~ubuntu-branches/ubuntu/trusty/systemd/trusty

« back to all changes in this revision

Viewing changes to src/dbus-loop.c

  • Committer: Package Import Robot
  • Author(s): Michael Biebl, Michael Biebl, Michael Stapelberg, Daniel Schaal, Ondrej Balaz
  • Date: 2013-09-12 00:13:11 UTC
  • mfrom: (1.1.11) (9.1.2 experimental)
  • mto: This revision was merged to the branch mainline in revision 53.
  • Revision ID: package-import@ubuntu.com-20130912001311-dz35it34wr2lbday
Tags: 204-3
[ Michael Biebl ]
* Upload to unstable.
* Use /bin/bash in debug-shell.service as Debian doesn't have /sbin/sushell.
* Only import net.ifaces cmdline property for network devices.
* Generate strict dependencies between the binary packages using a
  shlibs.local file and add an explicit versioned dependency on
  libsystemd-login0 to systemd to ensure packages are upgraded in sync.
  Closes: #719444
* Drop obsolete Replaces: libudev0 from udev package.
* Use correct paths for various binaries, like /sbin/quotaon, which are
  installed in / and not /usr in Debian.  Closes: #721347
* Don't install kernel-install(8) man page since we don't install the
  corresponding binary either.  Closes: #722180
* Cherry-pick upstream fixes to make switching runlevels and starting
  reboot via ctrl-alt-del more robust.
* Cherry-pick upstream fix to properly apply ACLs to Journal files.

[ Michael Stapelberg ]
* Make systemctl enable|disable call update-rc.d for SysV init scripts.
  Closes: #709780
* Don't mount /tmp as tmpfs by default and make it possible to enable this
  feature via "systemctl enable tmp.mount".

[ Daniel Schaal ]
* Add bug-script to systemd and udev.  Closes: #711245

[ Ondrej Balaz ]
* Recognize discard option in /etc/crypttab.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
 
 
3
 
/***
4
 
  This file is part of systemd.
5
 
 
6
 
  Copyright 2011 Lennart Poettering
7
 
 
8
 
  systemd is free software; you can redistribute it and/or modify it
9
 
  under the terms of the GNU General Public License as published by
10
 
  the Free Software Foundation; either version 2 of the License, or
11
 
  (at your option) any later version.
12
 
 
13
 
  systemd is distributed in the hope that it will be useful, but
14
 
  WITHOUT ANY WARRANTY; without even the implied warranty of
15
 
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
 
  General Public License for more details.
17
 
 
18
 
  You should have received a copy of the GNU General Public License
19
 
  along with systemd; If not, see <http://www.gnu.org/licenses/>.
20
 
***/
21
 
 
22
 
#include <stdbool.h>
23
 
#include <assert.h>
24
 
#include <sys/epoll.h>
25
 
#include <string.h>
26
 
#include <errno.h>
27
 
#include <sys/timerfd.h>
28
 
#include <unistd.h>
29
 
 
30
 
#include "dbus-loop.h"
31
 
#include "dbus-common.h"
32
 
#include "util.h"
33
 
 
34
 
/* Minimal implementation of the dbus loop which integrates all dbus
35
 
 * events into a single epoll fd which we can triviall integrate with
36
 
 * other loops. Note that this is not used in the main systemd daemon
37
 
 * since we run a more elaborate mainloop there. */
38
 
 
39
 
typedef struct EpollData {
40
 
        int fd;
41
 
        void *object;
42
 
        bool is_timeout:1;
43
 
        bool fd_is_dupped:1;
44
 
} EpollData;
45
 
 
46
 
static dbus_bool_t add_watch(DBusWatch *watch, void *data) {
47
 
        EpollData *e;
48
 
        struct epoll_event ev;
49
 
 
50
 
        assert(watch);
51
 
 
52
 
        e = new0(EpollData, 1);
53
 
        if (!e)
54
 
                return FALSE;
55
 
 
56
 
        e->fd = dbus_watch_get_unix_fd(watch);
57
 
        e->object = watch;
58
 
        e->is_timeout = false;
59
 
 
60
 
        zero(ev);
61
 
        ev.events = bus_flags_to_events(watch);
62
 
        ev.data.ptr = e;
63
 
 
64
 
        if (epoll_ctl(PTR_TO_INT(data), EPOLL_CTL_ADD, e->fd, &ev) < 0) {
65
 
 
66
 
                if (errno != EEXIST) {
67
 
                        free(e);
68
 
                        return FALSE;
69
 
                }
70
 
 
71
 
                /* Hmm, bloody D-Bus creates multiple watches on the
72
 
                 * same fd. epoll() does not like that. As a dirty
73
 
                 * hack we simply dup() the fd and hence get a second
74
 
                 * one we can safely add to the epoll(). */
75
 
 
76
 
                e->fd = dup(e->fd);
77
 
                if (e->fd < 0) {
78
 
                        free(e);
79
 
                        return FALSE;
80
 
                }
81
 
 
82
 
                if (epoll_ctl(PTR_TO_INT(data), EPOLL_CTL_ADD, e->fd, &ev) < 0) {
83
 
                        close_nointr_nofail(e->fd);
84
 
                        free(e);
85
 
                        return FALSE;
86
 
                }
87
 
 
88
 
                e->fd_is_dupped = true;
89
 
        }
90
 
 
91
 
        dbus_watch_set_data(watch, e, NULL);
92
 
 
93
 
        return TRUE;
94
 
}
95
 
 
96
 
static void remove_watch(DBusWatch *watch, void *data) {
97
 
        EpollData *e;
98
 
 
99
 
        assert(watch);
100
 
 
101
 
        e = dbus_watch_get_data(watch);
102
 
        if (!e)
103
 
                return;
104
 
 
105
 
        assert_se(epoll_ctl(PTR_TO_INT(data), EPOLL_CTL_DEL, e->fd, NULL) >= 0);
106
 
 
107
 
        if (e->fd_is_dupped)
108
 
                close_nointr_nofail(e->fd);
109
 
 
110
 
        free(e);
111
 
}
112
 
 
113
 
static void toggle_watch(DBusWatch *watch, void *data) {
114
 
        EpollData *e;
115
 
        struct epoll_event ev;
116
 
 
117
 
        assert(watch);
118
 
 
119
 
        e = dbus_watch_get_data(watch);
120
 
        if (!e)
121
 
                return;
122
 
 
123
 
        zero(ev);
124
 
        ev.events = bus_flags_to_events(watch);
125
 
        ev.data.ptr = e;
126
 
 
127
 
        assert_se(epoll_ctl(PTR_TO_INT(data), EPOLL_CTL_MOD, e->fd, &ev) == 0);
128
 
}
129
 
 
130
 
static int timeout_arm(EpollData *e) {
131
 
        struct itimerspec its;
132
 
 
133
 
        assert(e);
134
 
        assert(e->is_timeout);
135
 
 
136
 
        zero(its);
137
 
 
138
 
        if (dbus_timeout_get_enabled(e->object)) {
139
 
                timespec_store(&its.it_value, dbus_timeout_get_interval(e->object) * USEC_PER_MSEC);
140
 
                its.it_interval = its.it_value;
141
 
        }
142
 
 
143
 
        if (timerfd_settime(e->fd, 0, &its, NULL) < 0)
144
 
                return -errno;
145
 
 
146
 
        return 0;
147
 
}
148
 
 
149
 
static dbus_bool_t add_timeout(DBusTimeout *timeout, void *data) {
150
 
        EpollData *e;
151
 
        struct epoll_event ev;
152
 
 
153
 
        assert(timeout);
154
 
 
155
 
        e = new0(EpollData, 1);
156
 
        if (!e)
157
 
                return FALSE;
158
 
 
159
 
        e->fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC);
160
 
        if (e->fd < 0)
161
 
                goto fail;
162
 
 
163
 
        e->object = timeout;
164
 
        e->is_timeout = true;
165
 
 
166
 
        if (timeout_arm(e) < 0)
167
 
                goto fail;
168
 
 
169
 
        zero(ev);
170
 
        ev.events = EPOLLIN;
171
 
        ev.data.ptr = e;
172
 
 
173
 
        if (epoll_ctl(PTR_TO_INT(data), EPOLL_CTL_ADD, e->fd, &ev) < 0)
174
 
                goto fail;
175
 
 
176
 
        dbus_timeout_set_data(timeout, e, NULL);
177
 
 
178
 
        return TRUE;
179
 
 
180
 
fail:
181
 
        if (e->fd >= 0)
182
 
                close_nointr_nofail(e->fd);
183
 
 
184
 
        free(e);
185
 
        return FALSE;
186
 
}
187
 
 
188
 
static void remove_timeout(DBusTimeout *timeout, void *data) {
189
 
        EpollData *e;
190
 
 
191
 
        assert(timeout);
192
 
 
193
 
        e = dbus_timeout_get_data(timeout);
194
 
        if (!e)
195
 
                return;
196
 
 
197
 
        assert_se(epoll_ctl(PTR_TO_INT(data), EPOLL_CTL_DEL, e->fd, NULL) >= 0);
198
 
        close_nointr_nofail(e->fd);
199
 
        free(e);
200
 
}
201
 
 
202
 
static void toggle_timeout(DBusTimeout *timeout, void *data) {
203
 
        EpollData *e;
204
 
        int r;
205
 
 
206
 
        assert(timeout);
207
 
 
208
 
        e = dbus_timeout_get_data(timeout);
209
 
        if (!e)
210
 
                return;
211
 
 
212
 
        r = timeout_arm(e);
213
 
        if (r < 0)
214
 
                log_error("Failed to rearm timer: %s", strerror(-r));
215
 
}
216
 
 
217
 
int bus_loop_open(DBusConnection *c) {
218
 
        int fd;
219
 
 
220
 
        assert(c);
221
 
 
222
 
        fd = epoll_create1(EPOLL_CLOEXEC);
223
 
        if (fd < 0)
224
 
                return -errno;
225
 
 
226
 
        if (!dbus_connection_set_watch_functions(c, add_watch, remove_watch, toggle_watch, INT_TO_PTR(fd), NULL) ||
227
 
            !dbus_connection_set_timeout_functions(c, add_timeout, remove_timeout, toggle_timeout, INT_TO_PTR(fd), NULL)) {
228
 
                close_nointr_nofail(fd);
229
 
                return -ENOMEM;
230
 
        }
231
 
 
232
 
        return fd;
233
 
}
234
 
 
235
 
int bus_loop_dispatch(int fd) {
236
 
        int n;
237
 
        struct epoll_event event;
238
 
        EpollData *d;
239
 
 
240
 
        assert(fd >= 0);
241
 
 
242
 
        zero(event);
243
 
 
244
 
        n = epoll_wait(fd, &event, 1, 0);
245
 
        if (n < 0)
246
 
                return errno == EAGAIN || errno == EINTR ? 0 : -errno;
247
 
 
248
 
        assert_se(d = event.data.ptr);
249
 
 
250
 
        if (d->is_timeout) {
251
 
                DBusTimeout *t = d->object;
252
 
 
253
 
                if (dbus_timeout_get_enabled(t))
254
 
                        dbus_timeout_handle(t);
255
 
        } else {
256
 
                DBusWatch *w = d->object;
257
 
 
258
 
                if (dbus_watch_get_enabled(w))
259
 
                        dbus_watch_handle(w, bus_events_to_flags(event.events));
260
 
        }
261
 
 
262
 
        return 0;
263
 
}