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

« back to all changes in this revision

Viewing changes to src/shared/dbus-common.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 2010 Lennart Poettering
 
7
 
 
8
  systemd is free software; you can redistribute it and/or modify it
 
9
  under the terms of the GNU Lesser General Public License as published by
 
10
  the Free Software Foundation; either version 2.1 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
  Lesser General Public License for more details.
 
17
 
 
18
  You should have received a copy of the GNU Lesser General Public License
 
19
  along with systemd; If not, see <http://www.gnu.org/licenses/>.
 
20
***/
 
21
 
 
22
#include <assert.h>
 
23
#include <sys/socket.h>
 
24
#include <errno.h>
 
25
#include <unistd.h>
 
26
#include <stdio.h>
 
27
#include <stdlib.h>
 
28
#include <dbus/dbus.h>
 
29
#include <string.h>
 
30
#include <sys/epoll.h>
 
31
 
 
32
#include "log.h"
 
33
#include "dbus-common.h"
 
34
#include "util.h"
 
35
#include "missing.h"
 
36
#include "def.h"
 
37
#include "strv.h"
 
38
 
 
39
int bus_check_peercred(DBusConnection *c) {
 
40
        int fd;
 
41
        struct ucred ucred;
 
42
        socklen_t l;
 
43
 
 
44
        assert(c);
 
45
 
 
46
        assert_se(dbus_connection_get_unix_fd(c, &fd));
 
47
 
 
48
        l = sizeof(struct ucred);
 
49
        if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &l) < 0) {
 
50
                log_error("SO_PEERCRED failed: %m");
 
51
                return -errno;
 
52
        }
 
53
 
 
54
        if (l != sizeof(struct ucred)) {
 
55
                log_error("SO_PEERCRED returned wrong size.");
 
56
                return -E2BIG;
 
57
        }
 
58
 
 
59
        if (ucred.uid != 0 && ucred.uid != geteuid())
 
60
                return -EPERM;
 
61
 
 
62
        return 1;
 
63
}
 
64
 
 
65
static int sync_auth(DBusConnection *bus, DBusError *error) {
 
66
        usec_t begin, tstamp;
 
67
 
 
68
        assert(bus);
 
69
 
 
70
        /* This complexity should probably move into D-Bus itself:
 
71
         *
 
72
         * https://bugs.freedesktop.org/show_bug.cgi?id=35189 */
 
73
 
 
74
        begin = tstamp = now(CLOCK_MONOTONIC);
 
75
        for (;;) {
 
76
 
 
77
                if (tstamp > begin + DEFAULT_TIMEOUT_USEC)
 
78
                        break;
 
79
 
 
80
                if (dbus_connection_get_is_authenticated(bus))
 
81
                        break;
 
82
 
 
83
                if (!dbus_connection_read_write_dispatch(bus, ((begin + DEFAULT_TIMEOUT_USEC - tstamp) + USEC_PER_MSEC - 1) / USEC_PER_MSEC))
 
84
                        break;
 
85
 
 
86
                tstamp = now(CLOCK_MONOTONIC);
 
87
        }
 
88
 
 
89
        if (!dbus_connection_get_is_connected(bus)) {
 
90
                dbus_set_error_const(error, DBUS_ERROR_NO_SERVER, "Connection terminated during authentication.");
 
91
                return -ECONNREFUSED;
 
92
        }
 
93
 
 
94
        if (!dbus_connection_get_is_authenticated(bus)) {
 
95
                dbus_set_error_const(error, DBUS_ERROR_TIMEOUT, "Failed to authenticate in time.");
 
96
                return -EACCES;
 
97
        }
 
98
 
 
99
        return 0;
 
100
}
 
101
 
 
102
int bus_connect(DBusBusType t, DBusConnection **_bus, bool *_private, DBusError *error) {
 
103
        DBusConnection *bus = NULL;
 
104
        int r;
 
105
        bool private = true;
 
106
 
 
107
        assert(_bus);
 
108
 
 
109
        if (geteuid() == 0 && t == DBUS_BUS_SYSTEM) {
 
110
                /* If we are root, then let's talk directly to the
 
111
                 * system instance, instead of going via the bus */
 
112
 
 
113
                bus = dbus_connection_open_private("unix:path=/run/systemd/private", error);
 
114
                if (!bus)
 
115
                        return -EIO;
 
116
 
 
117
        } else {
 
118
                if (t == DBUS_BUS_SESSION) {
 
119
                        const char *e;
 
120
 
 
121
                        /* If we are supposed to talk to the instance,
 
122
                         * try via XDG_RUNTIME_DIR first, then
 
123
                         * fallback to normal bus access */
 
124
 
 
125
                        e = secure_getenv("XDG_RUNTIME_DIR");
 
126
                        if (e) {
 
127
                                char *p;
 
128
 
 
129
                                if (asprintf(&p, "unix:path=%s/systemd/private", e) < 0)
 
130
                                        return -ENOMEM;
 
131
 
 
132
                                bus = dbus_connection_open_private(p, NULL);
 
133
                                free(p);
 
134
                        }
 
135
                }
 
136
 
 
137
                if (!bus) {
 
138
                        bus = dbus_bus_get_private(t, error);
 
139
                        if (!bus)
 
140
                                return -EIO;
 
141
 
 
142
                        private = false;
 
143
                }
 
144
        }
 
145
 
 
146
        dbus_connection_set_exit_on_disconnect(bus, FALSE);
 
147
 
 
148
        if (private) {
 
149
                if (bus_check_peercred(bus) < 0) {
 
150
                        dbus_connection_close(bus);
 
151
                        dbus_connection_unref(bus);
 
152
 
 
153
                        dbus_set_error_const(error, DBUS_ERROR_ACCESS_DENIED, "Failed to verify owner of bus.");
 
154
                        return -EACCES;
 
155
                }
 
156
        }
 
157
 
 
158
        r = sync_auth(bus, error);
 
159
        if (r < 0) {
 
160
                dbus_connection_close(bus);
 
161
                dbus_connection_unref(bus);
 
162
                return r;
 
163
        }
 
164
 
 
165
        if (_private)
 
166
                *_private = private;
 
167
 
 
168
        *_bus = bus;
 
169
        return 0;
 
170
}
 
171
 
 
172
int bus_connect_system_ssh(const char *user, const char *host, DBusConnection **_bus, DBusError *error) {
 
173
        DBusConnection *bus;
 
174
        char *p = NULL;
 
175
        int r;
 
176
 
 
177
        assert(_bus);
 
178
        assert(user || host);
 
179
 
 
180
        if (user && host)
 
181
                asprintf(&p, "unixexec:path=ssh,argv1=-xT,argv2=%s@%s,argv3=systemd-stdio-bridge", user, host);
 
182
        else if (user)
 
183
                asprintf(&p, "unixexec:path=ssh,argv1=-xT,argv2=%s@localhost,argv3=systemd-stdio-bridge", user);
 
184
        else if (host)
 
185
                asprintf(&p, "unixexec:path=ssh,argv1=-xT,argv2=%s,argv3=systemd-stdio-bridge", host);
 
186
 
 
187
        if (!p) {
 
188
                dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, NULL);
 
189
                return -ENOMEM;
 
190
        }
 
191
 
 
192
        bus = dbus_connection_open_private(p, error);
 
193
        free(p);
 
194
 
 
195
        if (!bus)
 
196
                return -EIO;
 
197
 
 
198
        dbus_connection_set_exit_on_disconnect(bus, FALSE);
 
199
 
 
200
        if ((r = sync_auth(bus, error)) < 0) {
 
201
                dbus_connection_close(bus);
 
202
                dbus_connection_unref(bus);
 
203
                return r;
 
204
        }
 
205
 
 
206
        if (!dbus_bus_register(bus, error)) {
 
207
                dbus_connection_close(bus);
 
208
                dbus_connection_unref(bus);
 
209
                return r;
 
210
        }
 
211
 
 
212
        *_bus = bus;
 
213
        return 0;
 
214
}
 
215
 
 
216
int bus_connect_system_polkit(DBusConnection **_bus, DBusError *error) {
 
217
        DBusConnection *bus;
 
218
        int r;
 
219
 
 
220
        assert(_bus);
 
221
 
 
222
        /* Don't bother with PolicyKit if we are root */
 
223
        if (geteuid() == 0)
 
224
                return bus_connect(DBUS_BUS_SYSTEM, _bus, NULL, error);
 
225
 
 
226
        bus = dbus_connection_open_private("unixexec:path=pkexec,argv1=" SYSTEMD_STDIO_BRIDGE_BINARY_PATH, error);
 
227
        if (!bus)
 
228
                return -EIO;
 
229
 
 
230
        dbus_connection_set_exit_on_disconnect(bus, FALSE);
 
231
 
 
232
        r = sync_auth(bus, error);
 
233
        if (r < 0) {
 
234
                dbus_connection_close(bus);
 
235
                dbus_connection_unref(bus);
 
236
                return r;
 
237
        }
 
238
 
 
239
        if (!dbus_bus_register(bus, error)) {
 
240
                dbus_connection_close(bus);
 
241
                dbus_connection_unref(bus);
 
242
                return r;
 
243
        }
 
244
 
 
245
        *_bus = bus;
 
246
        return 0;
 
247
}
 
248
 
 
249
const char *bus_error_message(const DBusError *error) {
 
250
        if (!error)
 
251
                return NULL;
 
252
 
 
253
        /* Sometimes the D-Bus server is a little bit too verbose with
 
254
         * its error messages, so let's override them here */
 
255
        if (dbus_error_has_name(error, DBUS_ERROR_ACCESS_DENIED))
 
256
                return "Access denied";
 
257
 
 
258
        return error->message;
 
259
}
 
260
 
 
261
const char *bus_error(const DBusError *error, int err) {
 
262
        if (error && dbus_error_is_set(error))
 
263
                return bus_error_message(error);
 
264
 
 
265
        return strerror(err < 0 ? -err : err);
 
266
}
 
267
 
 
268
DBusHandlerResult bus_default_message_handler(
 
269
                DBusConnection *c,
 
270
                DBusMessage *message,
 
271
                const char *introspection,
 
272
                const char *interfaces,
 
273
                const BusBoundProperties *bound_properties) {
 
274
 
 
275
        DBusError error;
 
276
        _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
 
277
        int r;
 
278
 
 
279
        assert(c);
 
280
        assert(message);
 
281
 
 
282
        dbus_error_init(&error);
 
283
 
 
284
        if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect") && introspection) {
 
285
 
 
286
                reply = dbus_message_new_method_return(message);
 
287
                if (!reply)
 
288
                        goto oom;
 
289
 
 
290
                if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID))
 
291
                        goto oom;
 
292
 
 
293
        } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "Get") && bound_properties) {
 
294
                const char *interface, *property;
 
295
                const BusBoundProperties *bp;
 
296
                const BusProperty *p;
 
297
                void *data;
 
298
                DBusMessageIter iter, sub;
 
299
 
 
300
                if (!dbus_message_get_args(
 
301
                            message,
 
302
                            &error,
 
303
                            DBUS_TYPE_STRING, &interface,
 
304
                            DBUS_TYPE_STRING, &property,
 
305
                            DBUS_TYPE_INVALID))
 
306
                        return bus_send_error_reply(c, message, &error, -EINVAL);
 
307
 
 
308
                for (bp = bound_properties; bp->interface; bp++) {
 
309
                        if (!streq(bp->interface, interface))
 
310
                                continue;
 
311
 
 
312
                        for (p = bp->properties; p->property; p++)
 
313
                                if (streq(p->property, property))
 
314
                                        goto get_prop;
 
315
                }
 
316
 
 
317
                /* no match */
 
318
                if (!nulstr_contains(interfaces, interface))
 
319
                        dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface");
 
320
                else
 
321
                        dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_PROPERTY, "Unknown property");
 
322
 
 
323
                return bus_send_error_reply(c, message, &error, -EINVAL);
 
324
 
 
325
get_prop:
 
326
                reply = dbus_message_new_method_return(message);
 
327
                if (!reply)
 
328
                        goto oom;
 
329
 
 
330
                dbus_message_iter_init_append(reply, &iter);
 
331
 
 
332
                if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, p->signature, &sub))
 
333
                        goto oom;
 
334
 
 
335
                data = (char*)bp->base + p->offset;
 
336
                if (p->indirect)
 
337
                        data = *(void**)data;
 
338
 
 
339
                r = p->append(&sub, property, data);
 
340
                if (r == -ENOMEM)
 
341
                        goto oom;
 
342
                if (r < 0)
 
343
                        return bus_send_error_reply(c, message, NULL, r);
 
344
 
 
345
                if (!dbus_message_iter_close_container(&iter, &sub))
 
346
                        goto oom;
 
347
 
 
348
        } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "GetAll") && bound_properties) {
 
349
                const char *interface;
 
350
                const BusBoundProperties *bp;
 
351
                const BusProperty *p;
 
352
                DBusMessageIter iter, sub, sub2, sub3;
 
353
 
 
354
                if (!dbus_message_get_args(
 
355
                            message,
 
356
                            &error,
 
357
                            DBUS_TYPE_STRING, &interface,
 
358
                            DBUS_TYPE_INVALID))
 
359
                        return bus_send_error_reply(c, message, &error, -EINVAL);
 
360
 
 
361
                if (interface[0] && !nulstr_contains(interfaces, interface)) {
 
362
                        dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface");
 
363
                        return bus_send_error_reply(c, message, &error, -EINVAL);
 
364
                }
 
365
 
 
366
                reply = dbus_message_new_method_return(message);
 
367
                if (!reply)
 
368
                        goto oom;
 
369
 
 
370
                dbus_message_iter_init_append(reply, &iter);
 
371
 
 
372
                if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub))
 
373
                        goto oom;
 
374
 
 
375
                for (bp = bound_properties; bp->interface; bp++) {
 
376
                        if (interface[0] && !streq(bp->interface, interface))
 
377
                                continue;
 
378
 
 
379
                        for (p = bp->properties; p->property; p++) {
 
380
                                void *data;
 
381
 
 
382
                                if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_DICT_ENTRY, NULL, &sub2) ||
 
383
                                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &p->property) ||
 
384
                                    !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, p->signature, &sub3))
 
385
                                        goto oom;
 
386
 
 
387
                                data = (char*)bp->base + p->offset;
 
388
                                if (p->indirect)
 
389
                                        data = *(void**)data;
 
390
                                r = p->append(&sub3, p->property, data);
 
391
                                if (r == -ENOMEM)
 
392
                                        goto oom;
 
393
                                if (r < 0)
 
394
                                        return bus_send_error_reply(c, message, NULL, r);
 
395
 
 
396
                                if (!dbus_message_iter_close_container(&sub2, &sub3) ||
 
397
                                    !dbus_message_iter_close_container(&sub, &sub2))
 
398
                                        goto oom;
 
399
                        }
 
400
                }
 
401
 
 
402
                if (!dbus_message_iter_close_container(&iter, &sub))
 
403
                        goto oom;
 
404
 
 
405
        } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "Set") && bound_properties) {
 
406
                const char *interface, *property;
 
407
                DBusMessageIter iter;
 
408
                const BusBoundProperties *bp;
 
409
                const BusProperty *p;
 
410
                DBusMessageIter sub;
 
411
                char *sig;
 
412
                void *data;
 
413
                DBusMessage *changed;
 
414
 
 
415
                if (!dbus_message_iter_init(message, &iter) ||
 
416
                    dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
 
417
                        return bus_send_error_reply(c, message, NULL, -EINVAL);
 
418
 
 
419
                dbus_message_iter_get_basic(&iter, &interface);
 
420
 
 
421
                if (!dbus_message_iter_next(&iter) ||
 
422
                    dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
 
423
                        return bus_send_error_reply(c, message, NULL, -EINVAL);
 
424
 
 
425
                dbus_message_iter_get_basic(&iter, &property);
 
426
 
 
427
                if (!dbus_message_iter_next(&iter) ||
 
428
                    dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT ||
 
429
                    dbus_message_iter_has_next(&iter))
 
430
                        return bus_send_error_reply(c, message, NULL, -EINVAL);
 
431
 
 
432
                for (bp = bound_properties; bp->interface; bp++) {
 
433
                        if (!streq(bp->interface, interface))
 
434
                                continue;
 
435
 
 
436
                        for (p = bp->properties; p->property; p++)
 
437
                                if (streq(p->property, property))
 
438
                                        goto set_prop;
 
439
                }
 
440
 
 
441
                /* no match */
 
442
                if (!nulstr_contains(interfaces, interface))
 
443
                        dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface");
 
444
                else
 
445
                        dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_PROPERTY, "Unknown property");
 
446
 
 
447
                return bus_send_error_reply(c, message, &error, -EINVAL);
 
448
 
 
449
set_prop:
 
450
                if (!p->set) {
 
451
                        dbus_set_error_const(&error, DBUS_ERROR_PROPERTY_READ_ONLY, "Property read-only");
 
452
                        return bus_send_error_reply(c, message, &error, -EINVAL);
 
453
                }
 
454
 
 
455
                dbus_message_iter_recurse(&iter, &sub);
 
456
 
 
457
                sig = dbus_message_iter_get_signature(&sub);
 
458
                if (!sig)
 
459
                        goto oom;
 
460
 
 
461
                if (!streq(sig, p->signature)) {
 
462
                        dbus_free(sig);
 
463
                        return bus_send_error_reply(c, message, NULL, -EINVAL);
 
464
                }
 
465
                dbus_free(sig);
 
466
 
 
467
                data = (uint8_t*) bp->base + p->offset;
 
468
                if (p->indirect)
 
469
                        data = *(void**)data;
 
470
 
 
471
                r = p->set(&sub, property, data);
 
472
                if (r == -ENOMEM)
 
473
                        goto oom;
 
474
                else if (r < 0)
 
475
                        return bus_send_error_reply(c, message, NULL, r);
 
476
 
 
477
                reply = dbus_message_new_method_return(message);
 
478
                if (!reply)
 
479
                        goto oom;
 
480
 
 
481
                /* Send out a signal about this, but it doesn't really
 
482
                 * matter if this fails, so eat all errors */
 
483
                changed = bus_properties_changed_one_new(
 
484
                                dbus_message_get_path(message),
 
485
                                interface,
 
486
                                property);
 
487
                if (changed) {
 
488
                        dbus_connection_send(c, changed, NULL);
 
489
                        dbus_message_unref(changed);
 
490
                }
 
491
 
 
492
 
 
493
        } else {
 
494
                const char *interface = dbus_message_get_interface(message);
 
495
 
 
496
                if (!interface || !nulstr_contains(interfaces, interface)) {
 
497
                        dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface");
 
498
                        return bus_send_error_reply(c, message, &error, -EINVAL);
 
499
                }
 
500
        }
 
501
 
 
502
        if (reply) {
 
503
                if (!bus_maybe_send_reply(c, message, reply))
 
504
                        goto oom;
 
505
 
 
506
                return DBUS_HANDLER_RESULT_HANDLED;
 
507
        }
 
508
 
 
509
        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 
510
 
 
511
oom:
 
512
        dbus_error_free(&error);
 
513
 
 
514
        return DBUS_HANDLER_RESULT_NEED_MEMORY;
 
515
}
 
516
 
 
517
int bus_property_append_string(DBusMessageIter *i, const char *property, void *data) {
 
518
        const char *t = data;
 
519
 
 
520
        assert(i);
 
521
        assert(property);
 
522
 
 
523
        if (!t)
 
524
                t = "";
 
525
 
 
526
        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
 
527
                return -ENOMEM;
 
528
 
 
529
        return 0;
 
530
}
 
531
 
 
532
int bus_property_append_strv(DBusMessageIter *i, const char *property, void *data) {
 
533
        char **t = data;
 
534
 
 
535
        assert(i);
 
536
        assert(property);
 
537
 
 
538
        return bus_append_strv_iter(i, t);
 
539
}
 
540
 
 
541
int bus_property_append_bool(DBusMessageIter *i, const char *property, void *data) {
 
542
        bool *b = data;
 
543
        dbus_bool_t db;
 
544
 
 
545
        assert(i);
 
546
        assert(property);
 
547
        assert(b);
 
548
 
 
549
        db = *b;
 
550
 
 
551
        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &db))
 
552
                return -ENOMEM;
 
553
 
 
554
        return 0;
 
555
}
 
556
 
 
557
int bus_property_append_tristate_false(DBusMessageIter *i, const char *property, void *data) {
 
558
        int *b = data;
 
559
        dbus_bool_t db;
 
560
 
 
561
        assert(i);
 
562
        assert(property);
 
563
        assert(b);
 
564
 
 
565
        db = *b > 0;
 
566
 
 
567
        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &db))
 
568
                return -ENOMEM;
 
569
 
 
570
        return 0;
 
571
}
 
572
 
 
573
int bus_property_append_uint64(DBusMessageIter *i, const char *property, void *data) {
 
574
        assert(i);
 
575
        assert(property);
 
576
        assert(data);
 
577
 
 
578
        /* Let's ensure that usec_t is actually 64bit, and hence this
 
579
         * function can be used for usec_t */
 
580
        assert_cc(sizeof(uint64_t) == sizeof(usec_t));
 
581
 
 
582
        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, data))
 
583
                return -ENOMEM;
 
584
 
 
585
        return 0;
 
586
}
 
587
 
 
588
int bus_property_append_uint32(DBusMessageIter *i, const char *property, void *data) {
 
589
        assert(i);
 
590
        assert(property);
 
591
        assert(data);
 
592
 
 
593
        /* Let's ensure that pid_t, mode_t, uid_t, gid_t are actually
 
594
         * 32bit, and hence this function can be used for
 
595
         * pid_t/mode_t/uid_t/gid_t */
 
596
        assert_cc(sizeof(uint32_t) == sizeof(pid_t));
 
597
        assert_cc(sizeof(uint32_t) == sizeof(mode_t));
 
598
        assert_cc(sizeof(uint32_t) == sizeof(unsigned));
 
599
        assert_cc(sizeof(uint32_t) == sizeof(uid_t));
 
600
        assert_cc(sizeof(uint32_t) == sizeof(gid_t));
 
601
 
 
602
        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, data))
 
603
                return -ENOMEM;
 
604
 
 
605
        return 0;
 
606
}
 
607
 
 
608
int bus_property_append_int32(DBusMessageIter *i, const char *property, void *data) {
 
609
        assert(i);
 
610
        assert(property);
 
611
        assert(data);
 
612
 
 
613
        assert_cc(sizeof(int32_t) == sizeof(int));
 
614
 
 
615
        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, data))
 
616
                return -ENOMEM;
 
617
 
 
618
        return 0;
 
619
}
 
620
 
 
621
int bus_property_append_size(DBusMessageIter *i, const char *property, void *data) {
 
622
        uint64_t u;
 
623
 
 
624
        assert(i);
 
625
        assert(property);
 
626
        assert(data);
 
627
 
 
628
        u = (uint64_t) *(size_t*) data;
 
629
 
 
630
        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
 
631
                return -ENOMEM;
 
632
 
 
633
        return 0;
 
634
}
 
635
 
 
636
int bus_property_append_ul(DBusMessageIter *i, const char *property, void *data) {
 
637
        uint64_t u;
 
638
 
 
639
        assert(i);
 
640
        assert(property);
 
641
        assert(data);
 
642
 
 
643
        u = (uint64_t) *(unsigned long*) data;
 
644
 
 
645
        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
 
646
                return -ENOMEM;
 
647
 
 
648
        return 0;
 
649
}
 
650
 
 
651
int bus_property_append_long(DBusMessageIter *i, const char *property, void *data) {
 
652
        int64_t l;
 
653
 
 
654
        assert(i);
 
655
        assert(property);
 
656
        assert(data);
 
657
 
 
658
        l = (int64_t) *(long*) data;
 
659
 
 
660
        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT64, &l))
 
661
                return -ENOMEM;
 
662
 
 
663
        return 0;
 
664
}
 
665
 
 
666
int bus_property_set_uint64(DBusMessageIter *i, const char *property, void *data) {
 
667
        uint64_t *t = data;
 
668
 
 
669
        assert(i);
 
670
        assert(property);
 
671
 
 
672
        dbus_message_iter_get_basic(i, t);
 
673
        return 0;
 
674
}
 
675
 
 
676
const char *bus_errno_to_dbus(int error) {
 
677
 
 
678
        switch(error) {
 
679
 
 
680
        case -EINVAL:
 
681
                return DBUS_ERROR_INVALID_ARGS;
 
682
 
 
683
        case -ENOMEM:
 
684
                return DBUS_ERROR_NO_MEMORY;
 
685
 
 
686
        case -EPERM:
 
687
        case -EACCES:
 
688
                return DBUS_ERROR_ACCESS_DENIED;
 
689
 
 
690
        case -ESRCH:
 
691
                return DBUS_ERROR_UNIX_PROCESS_ID_UNKNOWN;
 
692
 
 
693
        case -ENOENT:
 
694
                return DBUS_ERROR_FILE_NOT_FOUND;
 
695
 
 
696
        case -EEXIST:
 
697
                return DBUS_ERROR_FILE_EXISTS;
 
698
 
 
699
        case -ETIMEDOUT:
 
700
        case -ETIME:
 
701
                return DBUS_ERROR_TIMEOUT;
 
702
 
 
703
        case -EIO:
 
704
                return DBUS_ERROR_IO_ERROR;
 
705
 
 
706
        case -ENETRESET:
 
707
        case -ECONNABORTED:
 
708
        case -ECONNRESET:
 
709
                return DBUS_ERROR_DISCONNECTED;
 
710
        }
 
711
 
 
712
        return DBUS_ERROR_FAILED;
 
713
}
 
714
 
 
715
dbus_bool_t bus_maybe_send_reply (DBusConnection   *c,
 
716
                                  DBusMessage *message,
 
717
                                  DBusMessage *reply)
 
718
{
 
719
        /* Some parts of systemd "reply" to signals, which of course
 
720
         * have the no-reply flag set.  We will be defensive here and
 
721
         * still send out a reply if we're passed a signal.
 
722
         */
 
723
        if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_METHOD_CALL &&
 
724
            dbus_message_get_no_reply(message))
 
725
                return TRUE;
 
726
        return dbus_connection_send(c, reply, NULL);
 
727
}
 
728
 
 
729
DBusHandlerResult bus_send_error_reply(DBusConnection *c, DBusMessage *message, DBusError *berror, int error) {
 
730
        _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
 
731
        const char *name, *text;
 
732
 
 
733
        if (berror && dbus_error_is_set(berror)) {
 
734
                name = berror->name;
 
735
                text = berror->message;
 
736
        } else {
 
737
                name = bus_errno_to_dbus(error);
 
738
                text = strerror(-error);
 
739
        }
 
740
 
 
741
        reply = dbus_message_new_error(message, name, text);
 
742
        if (!reply)
 
743
                goto oom;
 
744
 
 
745
        if (!bus_maybe_send_reply(c, message, reply))
 
746
                goto oom;
 
747
 
 
748
        if (berror)
 
749
                dbus_error_free(berror);
 
750
 
 
751
        return DBUS_HANDLER_RESULT_HANDLED;
 
752
 
 
753
oom:
 
754
        if (reply)
 
755
                dbus_message_unref(reply);
 
756
 
 
757
        if (berror)
 
758
                dbus_error_free(berror);
 
759
 
 
760
        return DBUS_HANDLER_RESULT_NEED_MEMORY;
 
761
}
 
762
 
 
763
DBusMessage* bus_properties_changed_new(const char *path, const char *interface, const char *properties) {
 
764
        DBusMessage *m;
 
765
        DBusMessageIter iter, sub;
 
766
        const char *i;
 
767
 
 
768
        assert(interface);
 
769
        assert(properties);
 
770
 
 
771
        m = dbus_message_new_signal(path, "org.freedesktop.DBus.Properties", "PropertiesChanged");
 
772
        if (!m)
 
773
                goto oom;
 
774
 
 
775
        dbus_message_iter_init_append(m, &iter);
 
776
 
 
777
        /* We won't send any property values, since they might be
 
778
         * large and sometimes not cheap to generated */
 
779
 
 
780
        if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &interface) ||
 
781
            !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub) ||
 
782
            !dbus_message_iter_close_container(&iter, &sub) ||
 
783
            !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub))
 
784
                goto oom;
 
785
 
 
786
        NULSTR_FOREACH(i, properties)
 
787
                if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &i))
 
788
                        goto oom;
 
789
 
 
790
        if (!dbus_message_iter_close_container(&iter, &sub))
 
791
                goto oom;
 
792
 
 
793
        return m;
 
794
 
 
795
oom:
 
796
        if (m)
 
797
                dbus_message_unref(m);
 
798
 
 
799
        return NULL;
 
800
}
 
801
 
 
802
DBusMessage* bus_properties_changed_one_new(const char *path, const char *interface, const char *property) {
 
803
        DBusMessage *m;
 
804
        DBusMessageIter iter, sub;
 
805
 
 
806
        assert(interface);
 
807
        assert(property);
 
808
 
 
809
        m = dbus_message_new_signal(path, "org.freedesktop.DBus.Properties", "PropertiesChanged");
 
810
        if (!m)
 
811
                goto oom;
 
812
 
 
813
        dbus_message_iter_init_append(m, &iter);
 
814
 
 
815
        /* We won't send any property values, since they might be
 
816
         * large and sometimes not cheap to generated */
 
817
 
 
818
        if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &interface) ||
 
819
            !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub) ||
 
820
            !dbus_message_iter_close_container(&iter, &sub) ||
 
821
            !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub))
 
822
                goto oom;
 
823
 
 
824
        if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &property))
 
825
                goto oom;
 
826
 
 
827
        if (!dbus_message_iter_close_container(&iter, &sub))
 
828
                goto oom;
 
829
 
 
830
        return m;
 
831
 
 
832
oom:
 
833
        if (m)
 
834
                dbus_message_unref(m);
 
835
 
 
836
        return NULL;
 
837
}
 
838
 
 
839
uint32_t bus_flags_to_events(DBusWatch *bus_watch) {
 
840
        unsigned flags;
 
841
        uint32_t events = 0;
 
842
 
 
843
        assert(bus_watch);
 
844
 
 
845
        /* no watch flags for disabled watches */
 
846
        if (!dbus_watch_get_enabled(bus_watch))
 
847
                return 0;
 
848
 
 
849
        flags = dbus_watch_get_flags(bus_watch);
 
850
 
 
851
        if (flags & DBUS_WATCH_READABLE)
 
852
                events |= EPOLLIN;
 
853
        if (flags & DBUS_WATCH_WRITABLE)
 
854
                events |= EPOLLOUT;
 
855
 
 
856
        return events | EPOLLHUP | EPOLLERR;
 
857
}
 
858
 
 
859
unsigned bus_events_to_flags(uint32_t events) {
 
860
        unsigned flags = 0;
 
861
 
 
862
        if (events & EPOLLIN)
 
863
                flags |= DBUS_WATCH_READABLE;
 
864
        if (events & EPOLLOUT)
 
865
                flags |= DBUS_WATCH_WRITABLE;
 
866
        if (events & EPOLLHUP)
 
867
                flags |= DBUS_WATCH_HANGUP;
 
868
        if (events & EPOLLERR)
 
869
                flags |= DBUS_WATCH_ERROR;
 
870
 
 
871
        return flags;
 
872
}
 
873
 
 
874
int bus_parse_strv(DBusMessage *m, char ***_l) {
 
875
        DBusMessageIter iter;
 
876
 
 
877
        assert(m);
 
878
        assert(_l);
 
879
 
 
880
        if (!dbus_message_iter_init(m, &iter))
 
881
                return -EINVAL;
 
882
 
 
883
        return bus_parse_strv_iter(&iter, _l);
 
884
}
 
885
 
 
886
int bus_parse_strv_iter(DBusMessageIter *iter, char ***_l) {
 
887
        DBusMessageIter sub;
 
888
        unsigned n = 0, i = 0;
 
889
        char **l;
 
890
 
 
891
        assert(iter);
 
892
        assert(_l);
 
893
 
 
894
        if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY ||
 
895
            dbus_message_iter_get_element_type(iter) != DBUS_TYPE_STRING)
 
896
            return -EINVAL;
 
897
 
 
898
        dbus_message_iter_recurse(iter, &sub);
 
899
 
 
900
        while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
 
901
                n++;
 
902
                dbus_message_iter_next(&sub);
 
903
        }
 
904
 
 
905
        l = new(char*, n+1);
 
906
        if (!l)
 
907
                return -ENOMEM;
 
908
 
 
909
        dbus_message_iter_recurse(iter, &sub);
 
910
 
 
911
        while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
 
912
                const char *s;
 
913
 
 
914
                assert_se(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING);
 
915
                dbus_message_iter_get_basic(&sub, &s);
 
916
 
 
917
                if (!(l[i++] = strdup(s))) {
 
918
                        strv_free(l);
 
919
                        return -ENOMEM;
 
920
                }
 
921
 
 
922
                dbus_message_iter_next(&sub);
 
923
        }
 
924
 
 
925
        assert(i == n);
 
926
        l[i] = NULL;
 
927
 
 
928
        if (_l)
 
929
                *_l = l;
 
930
 
 
931
        return 0;
 
932
}
 
933
 
 
934
int bus_parse_strv_pairs_iter(DBusMessageIter *iter, char ***_l) {
 
935
        DBusMessageIter sub, sub2;
 
936
        unsigned n = 0, i = 0;
 
937
        char **l;
 
938
 
 
939
        assert(iter);
 
940
        assert(_l);
 
941
 
 
942
        if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY ||
 
943
            dbus_message_iter_get_element_type(iter) != DBUS_TYPE_STRUCT)
 
944
            return -EINVAL;
 
945
 
 
946
        dbus_message_iter_recurse(iter, &sub);
 
947
 
 
948
        while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
 
949
                n++;
 
950
                dbus_message_iter_next(&sub);
 
951
        }
 
952
 
 
953
        l = new(char*, n*2+1);
 
954
        if (!l)
 
955
                return -ENOMEM;
 
956
 
 
957
        dbus_message_iter_recurse(iter, &sub);
 
958
 
 
959
        while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
 
960
                const char *a, *b;
 
961
 
 
962
                assert_se(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT);
 
963
 
 
964
                dbus_message_iter_recurse(&sub, &sub2);
 
965
 
 
966
                if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &a, true) < 0 ||
 
967
                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &b, false) < 0)
 
968
                        return -EINVAL;
 
969
 
 
970
                l[i] = strdup(a);
 
971
                if (!l[i]) {
 
972
                        strv_free(l);
 
973
                        return -ENOMEM;
 
974
                }
 
975
 
 
976
                l[++i] = strdup(b);
 
977
                if (!l[i]) {
 
978
                        strv_free(l);
 
979
                        return -ENOMEM;
 
980
                }
 
981
 
 
982
                i++;
 
983
                dbus_message_iter_next(&sub);
 
984
        }
 
985
 
 
986
        assert(i == n*2);
 
987
        l[i] = NULL;
 
988
 
 
989
        if (_l)
 
990
                *_l = l;
 
991
 
 
992
        return 0;
 
993
}
 
994
 
 
995
int bus_parse_unit_info(DBusMessageIter *iter, struct unit_info *u) {
 
996
        DBusMessageIter sub;
 
997
 
 
998
        assert(iter);
 
999
        assert(u);
 
1000
 
 
1001
        if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRUCT)
 
1002
                return -EINVAL;
 
1003
 
 
1004
        dbus_message_iter_recurse(iter, &sub);
 
1005
 
 
1006
        if (bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &u->id, true) < 0 ||
 
1007
            bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &u->description, true) < 0 ||
 
1008
            bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &u->load_state, true) < 0 ||
 
1009
            bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &u->active_state, true) < 0 ||
 
1010
            bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &u->sub_state, true) < 0 ||
 
1011
            bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &u->following, true) < 0 ||
 
1012
            bus_iter_get_basic_and_next(&sub, DBUS_TYPE_OBJECT_PATH, &u->unit_path, true) < 0 ||
 
1013
            bus_iter_get_basic_and_next(&sub, DBUS_TYPE_UINT32, &u->job_id, true) < 0 ||
 
1014
            bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &u->job_type, true) < 0 ||
 
1015
            bus_iter_get_basic_and_next(&sub, DBUS_TYPE_OBJECT_PATH, &u->job_path, false) < 0) {
 
1016
                log_error("Failed to parse reply.");
 
1017
                return -EIO;
 
1018
        }
 
1019
 
 
1020
        return 0;
 
1021
}
 
1022
 
 
1023
int bus_append_strv_iter(DBusMessageIter *iter, char **l) {
 
1024
        DBusMessageIter sub;
 
1025
 
 
1026
        assert(iter);
 
1027
 
 
1028
        if (!dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "s", &sub))
 
1029
                return -ENOMEM;
 
1030
 
 
1031
        STRV_FOREACH(l, l)
 
1032
                if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, l))
 
1033
                        return -ENOMEM;
 
1034
 
 
1035
        if (!dbus_message_iter_close_container(iter, &sub))
 
1036
                return -ENOMEM;
 
1037
 
 
1038
        return 0;
 
1039
}
 
1040
 
 
1041
int bus_iter_get_basic_and_next(DBusMessageIter *iter, int type, void *data, bool next) {
 
1042
 
 
1043
        assert(iter);
 
1044
        assert(data);
 
1045
 
 
1046
        if (dbus_message_iter_get_arg_type(iter) != type)
 
1047
                return -EIO;
 
1048
 
 
1049
        dbus_message_iter_get_basic(iter, data);
 
1050
 
 
1051
        if (!dbus_message_iter_next(iter) != !next)
 
1052
                return -EIO;
 
1053
 
 
1054
        return 0;
 
1055
}
 
1056
 
 
1057
int generic_print_property(const char *name, DBusMessageIter *iter, bool all) {
 
1058
        assert(name);
 
1059
        assert(iter);
 
1060
 
 
1061
        switch (dbus_message_iter_get_arg_type(iter)) {
 
1062
 
 
1063
        case DBUS_TYPE_STRING: {
 
1064
                const char *s;
 
1065
                dbus_message_iter_get_basic(iter, &s);
 
1066
 
 
1067
                if (all || !isempty(s))
 
1068
                        printf("%s=%s\n", name, s);
 
1069
 
 
1070
                return 1;
 
1071
        }
 
1072
 
 
1073
        case DBUS_TYPE_BOOLEAN: {
 
1074
                dbus_bool_t b;
 
1075
 
 
1076
                dbus_message_iter_get_basic(iter, &b);
 
1077
                printf("%s=%s\n", name, yes_no(b));
 
1078
 
 
1079
                return 1;
 
1080
        }
 
1081
 
 
1082
        case DBUS_TYPE_UINT64: {
 
1083
                uint64_t u;
 
1084
                dbus_message_iter_get_basic(iter, &u);
 
1085
 
 
1086
                /* Yes, heuristics! But we can change this check
 
1087
                 * should it turn out to not be sufficient */
 
1088
 
 
1089
                if (endswith(name, "Timestamp")) {
 
1090
                        char timestamp[FORMAT_TIMESTAMP_MAX], *t;
 
1091
 
 
1092
                        t = format_timestamp(timestamp, sizeof(timestamp), u);
 
1093
                        if (t || all)
 
1094
                                printf("%s=%s\n", name, strempty(t));
 
1095
 
 
1096
                } else if (strstr(name, "USec")) {
 
1097
                        char timespan[FORMAT_TIMESPAN_MAX];
 
1098
 
 
1099
                        printf("%s=%s\n", name, format_timespan(timespan, sizeof(timespan), u, 0));
 
1100
                } else
 
1101
                        printf("%s=%llu\n", name, (unsigned long long) u);
 
1102
 
 
1103
                return 1;
 
1104
        }
 
1105
 
 
1106
        case DBUS_TYPE_UINT32: {
 
1107
                uint32_t u;
 
1108
                dbus_message_iter_get_basic(iter, &u);
 
1109
 
 
1110
                if (strstr(name, "UMask") || strstr(name, "Mode"))
 
1111
                        printf("%s=%04o\n", name, u);
 
1112
                else
 
1113
                        printf("%s=%u\n", name, (unsigned) u);
 
1114
 
 
1115
                return 1;
 
1116
        }
 
1117
 
 
1118
        case DBUS_TYPE_INT32: {
 
1119
                int32_t i;
 
1120
                dbus_message_iter_get_basic(iter, &i);
 
1121
 
 
1122
                printf("%s=%i\n", name, (int) i);
 
1123
                return 1;
 
1124
        }
 
1125
 
 
1126
        case DBUS_TYPE_DOUBLE: {
 
1127
                double d;
 
1128
                dbus_message_iter_get_basic(iter, &d);
 
1129
 
 
1130
                printf("%s=%g\n", name, d);
 
1131
                return 1;
 
1132
        }
 
1133
 
 
1134
        case DBUS_TYPE_ARRAY:
 
1135
 
 
1136
                if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING) {
 
1137
                        DBusMessageIter sub;
 
1138
                        bool space = false;
 
1139
 
 
1140
                        dbus_message_iter_recurse(iter, &sub);
 
1141
                        if (all ||
 
1142
                            dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
 
1143
                                printf("%s=", name);
 
1144
 
 
1145
                                while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
 
1146
                                        const char *s;
 
1147
 
 
1148
                                        assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING);
 
1149
                                        dbus_message_iter_get_basic(&sub, &s);
 
1150
                                        printf("%s%s", space ? " " : "", s);
 
1151
 
 
1152
                                        space = true;
 
1153
                                        dbus_message_iter_next(&sub);
 
1154
                                }
 
1155
 
 
1156
                                puts("");
 
1157
                        }
 
1158
 
 
1159
                        return 1;
 
1160
 
 
1161
                } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_BYTE) {
 
1162
                        DBusMessageIter sub;
 
1163
 
 
1164
                        dbus_message_iter_recurse(iter, &sub);
 
1165
                        if (all ||
 
1166
                            dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
 
1167
                                printf("%s=", name);
 
1168
 
 
1169
                                while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
 
1170
                                        uint8_t u;
 
1171
 
 
1172
                                        assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_BYTE);
 
1173
                                        dbus_message_iter_get_basic(&sub, &u);
 
1174
                                        printf("%02x", u);
 
1175
 
 
1176
                                        dbus_message_iter_next(&sub);
 
1177
                                }
 
1178
 
 
1179
                                puts("");
 
1180
                        }
 
1181
 
 
1182
                        return 1;
 
1183
 
 
1184
                } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_UINT32) {
 
1185
                        DBusMessageIter sub;
 
1186
 
 
1187
                        dbus_message_iter_recurse(iter, &sub);
 
1188
                        if (all ||
 
1189
                            dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
 
1190
                                printf("%s=", name);
 
1191
 
 
1192
                                while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
 
1193
                                        uint32_t u;
 
1194
 
 
1195
                                        assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_UINT32);
 
1196
                                        dbus_message_iter_get_basic(&sub, &u);
 
1197
                                        printf("%08x", u);
 
1198
 
 
1199
                                        dbus_message_iter_next(&sub);
 
1200
                                }
 
1201
 
 
1202
                                puts("");
 
1203
                        }
 
1204
 
 
1205
                        return 1;
 
1206
                }
 
1207
 
 
1208
                break;
 
1209
        }
 
1210
 
 
1211
        return 0;
 
1212
}
 
1213
 
 
1214
static void release_name_pending_cb(DBusPendingCall *pending, void *userdata) {
 
1215
        DBusMessage *reply;
 
1216
        DBusConnection *bus = userdata;
 
1217
 
 
1218
        assert_se(reply = dbus_pending_call_steal_reply(pending));
 
1219
        dbus_message_unref(reply);
 
1220
 
 
1221
        dbus_connection_close(bus);
 
1222
}
 
1223
 
 
1224
void bus_async_unregister_and_exit(DBusConnection *bus, const char *name) {
 
1225
        _cleanup_dbus_message_unref_ DBusMessage *m = NULL;
 
1226
        DBusPendingCall *pending = NULL;
 
1227
 
 
1228
        assert(bus);
 
1229
 
 
1230
        /* We unregister the name here, but we continue to process
 
1231
         * requests, until we get the response for it, so that all
 
1232
         * requests are guaranteed to be processed. */
 
1233
 
 
1234
        m = dbus_message_new_method_call(
 
1235
                        DBUS_SERVICE_DBUS,
 
1236
                        DBUS_PATH_DBUS,
 
1237
                        DBUS_INTERFACE_DBUS,
 
1238
                        "ReleaseName");
 
1239
        if (!m)
 
1240
                goto oom;
 
1241
 
 
1242
        if (!dbus_message_append_args(
 
1243
                            m,
 
1244
                            DBUS_TYPE_STRING,
 
1245
                            &name,
 
1246
                            DBUS_TYPE_INVALID))
 
1247
                goto oom;
 
1248
 
 
1249
        if (!dbus_connection_send_with_reply(bus, m, &pending, -1))
 
1250
                goto oom;
 
1251
 
 
1252
        if (!dbus_pending_call_set_notify(pending, release_name_pending_cb, bus, NULL))
 
1253
                goto oom;
 
1254
 
 
1255
        dbus_pending_call_unref(pending);
 
1256
 
 
1257
        return;
 
1258
 
 
1259
oom:
 
1260
        log_oom();
 
1261
 
 
1262
        if (pending) {
 
1263
                dbus_pending_call_cancel(pending);
 
1264
                dbus_pending_call_unref(pending);
 
1265
        }
 
1266
}
 
1267
 
 
1268
DBusHandlerResult bus_exit_idle_filter(DBusConnection *bus, DBusMessage *m, void *userdata) {
 
1269
        usec_t *remain_until = userdata;
 
1270
 
 
1271
        assert(bus);
 
1272
        assert(m);
 
1273
        assert(remain_until);
 
1274
 
 
1275
        /* Every time we get a new message we reset out timeout */
 
1276
        *remain_until = now(CLOCK_MONOTONIC) + DEFAULT_EXIT_USEC;
 
1277
 
 
1278
        if (dbus_message_is_signal(m, DBUS_INTERFACE_LOCAL, "Disconnected"))
 
1279
                dbus_connection_close(bus);
 
1280
 
 
1281
        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 
1282
}
 
1283
 
 
1284
/* This mimics dbus_bus_get_unix_user() */
 
1285
pid_t bus_get_unix_process_id(
 
1286
                DBusConnection *connection,
 
1287
                const char *name,
 
1288
                DBusError *error) {
 
1289
 
 
1290
        _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
 
1291
        uint32_t pid = 0;
 
1292
 
 
1293
        m = dbus_message_new_method_call(
 
1294
                        DBUS_SERVICE_DBUS,
 
1295
                        DBUS_PATH_DBUS,
 
1296
                        DBUS_INTERFACE_DBUS,
 
1297
                        "GetConnectionUnixProcessID");
 
1298
        if (!m) {
 
1299
                dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, NULL);
 
1300
                return 0;
 
1301
        }
 
1302
 
 
1303
        if (!dbus_message_append_args(
 
1304
                            m,
 
1305
                            DBUS_TYPE_STRING, &name,
 
1306
                            DBUS_TYPE_INVALID)) {
 
1307
                dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, NULL);
 
1308
                return 0;
 
1309
        }
 
1310
 
 
1311
        reply = dbus_connection_send_with_reply_and_block(connection, m, -1, error);
 
1312
        if (!reply)
 
1313
                return 0;
 
1314
 
 
1315
        if (dbus_set_error_from_message(error, reply))
 
1316
                return 0;
 
1317
 
 
1318
        if (!dbus_message_get_args(
 
1319
                            reply, error,
 
1320
                            DBUS_TYPE_UINT32, &pid,
 
1321
                            DBUS_TYPE_INVALID))
 
1322
                return 0;
 
1323
 
 
1324
        return (pid_t) pid;
 
1325
}
 
1326
 
 
1327
bool bus_error_is_no_service(const DBusError *error) {
 
1328
        assert(error);
 
1329
 
 
1330
        if (!dbus_error_is_set(error))
 
1331
                return false;
 
1332
 
 
1333
        if (dbus_error_has_name(error, DBUS_ERROR_NAME_HAS_NO_OWNER))
 
1334
                return true;
 
1335
 
 
1336
        if (dbus_error_has_name(error, DBUS_ERROR_SERVICE_UNKNOWN))
 
1337
                return true;
 
1338
 
 
1339
        return startswith(error->name, "org.freedesktop.DBus.Error.Spawn.");
 
1340
}
 
1341
 
 
1342
int bus_method_call_with_reply(
 
1343
                DBusConnection *bus,
 
1344
                const char *destination,
 
1345
                const char *path,
 
1346
                const char *interface,
 
1347
                const char *method,
 
1348
                DBusMessage **return_reply,
 
1349
                DBusError *return_error,
 
1350
                int first_arg_type, ...) {
 
1351
 
 
1352
        DBusError error;
 
1353
        _cleanup_dbus_message_unref_ DBusMessage *m = NULL;
 
1354
        DBusMessage *reply;
 
1355
        va_list ap;
 
1356
        int r = 0;
 
1357
 
 
1358
        dbus_error_init(&error);
 
1359
        assert(bus);
 
1360
 
 
1361
        m = dbus_message_new_method_call(destination, path, interface, method);
 
1362
        if (!m) {
 
1363
                r = log_oom();
 
1364
                goto finish;
 
1365
        }
 
1366
 
 
1367
        va_start(ap, first_arg_type);
 
1368
        if (!dbus_message_append_args_valist(m, first_arg_type, ap)) {
 
1369
                va_end(ap);
 
1370
                r = log_oom();
 
1371
                goto finish;
 
1372
        }
 
1373
        va_end(ap);
 
1374
 
 
1375
        reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
 
1376
        if (!reply) {
 
1377
                if (!return_error)
 
1378
                        log_error("Failed to issue method call: %s", bus_error_message(&error));
 
1379
 
 
1380
                if (bus_error_is_no_service(&error))
 
1381
                        r = -ENOENT;
 
1382
                else if (dbus_error_has_name(&error, DBUS_ERROR_ACCESS_DENIED))
 
1383
                        r = -EACCES;
 
1384
                else if (dbus_error_has_name(&error, DBUS_ERROR_NO_REPLY))
 
1385
                        r = -ETIMEDOUT;
 
1386
                else
 
1387
                        r = -EIO;
 
1388
                goto finish;
 
1389
        }
 
1390
 
 
1391
        if (return_reply)
 
1392
                *return_reply = reply;
 
1393
        else
 
1394
                dbus_message_unref(reply);
 
1395
 
 
1396
finish:
 
1397
        if (return_error)
 
1398
                *return_error = error;
 
1399
        else
 
1400
                dbus_error_free(&error);
 
1401
 
 
1402
        return r;
 
1403
}
 
1404
 
 
1405
void bus_message_unrefp(DBusMessage **reply) {
 
1406
        if (!reply)
 
1407
                return;
 
1408
 
 
1409
        if (!*reply)
 
1410
                return;
 
1411
 
 
1412
        dbus_message_unref(*reply);
 
1413
}
 
1414
 
 
1415
const char *bus_message_get_sender_with_fallback(DBusMessage *m) {
 
1416
        const char *s;
 
1417
 
 
1418
        assert(m);
 
1419
 
 
1420
        s = dbus_message_get_sender(m);
 
1421
        if (s)
 
1422
                return s;
 
1423
 
 
1424
        /* When the message came in from a direct connection the
 
1425
         * message will have no sender. We fix that here. */
 
1426
 
 
1427
        return ":no-sender";
 
1428
}