chiark / gitweb /
selinux: remove anything PID1-specific from selinux-access.[ch] so that we can reuse...
[elogind.git] / src / core / dbus-manager.c
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 <errno.h>
23 #include <unistd.h>
24
25 #include "dbus.h"
26 #include "log.h"
27 #include "dbus-manager.h"
28 #include "strv.h"
29 #include "bus-errors.h"
30 #include "build.h"
31 #include "dbus-common.h"
32 #include "install.h"
33 #include "selinux-access.h"
34 #include "watchdog.h"
35 #include "hwclock.h"
36 #include "path-util.h"
37 #include "dbus-unit.h"
38
39 #define BUS_MANAGER_INTERFACE_BEGIN                                     \
40         " <interface name=\"org.freedesktop.systemd1.Manager\">\n"
41
42 #define BUS_MANAGER_INTERFACE_METHODS                                   \
43         "  <method name=\"GetUnit\">\n"                                 \
44         "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
45         "   <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n"        \
46         "  </method>\n"                                                 \
47         "  <method name=\"GetUnitByPID\">\n"                            \
48         "   <arg name=\"pid\" type=\"u\" direction=\"in\"/>\n"          \
49         "   <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n"        \
50         "  </method>\n"                                                 \
51         "  <method name=\"LoadUnit\">\n"                                \
52         "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
53         "   <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n"        \
54         "  </method>\n"                                                 \
55         "  <method name=\"StartUnit\">\n"                               \
56         "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
57         "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
58         "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
59         "  </method>\n"                                                 \
60         "  <method name=\"StartUnitReplace\">\n"                        \
61         "   <arg name=\"old_unit\" type=\"s\" direction=\"in\"/>\n"     \
62         "   <arg name=\"new_unit\" type=\"s\" direction=\"in\"/>\n"     \
63         "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
64         "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
65         "  </method>\n"                                                 \
66         "  <method name=\"StopUnit\">\n"                                \
67         "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
68         "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
69         "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
70         "  </method>\n"                                                 \
71         "  <method name=\"ReloadUnit\">\n"                              \
72         "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
73         "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
74         "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
75         "  </method>\n"                                                 \
76         "  <method name=\"RestartUnit\">\n"                             \
77         "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
78         "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
79         "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
80         "  </method>\n"                                                 \
81         "  <method name=\"TryRestartUnit\">\n"                          \
82         "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
83         "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
84         "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
85         "  </method>\n"                                                 \
86         "  <method name=\"ReloadOrRestartUnit\">\n"                     \
87         "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
88         "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
89         "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
90         "  </method>\n"                                                 \
91         "  <method name=\"ReloadOrTryRestartUnit\">\n"                  \
92         "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
93         "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
94         "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
95         "  </method>\n"                                                 \
96         "  <method name=\"KillUnit\">\n"                                \
97         "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
98         "   <arg name=\"who\" type=\"s\" direction=\"in\"/>\n"          \
99         "   <arg name=\"signal\" type=\"i\" direction=\"in\"/>\n"       \
100         "  </method>\n"                                                 \
101         "  <method name=\"ResetFailedUnit\">\n"                         \
102         "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
103         "  </method>\n"                                                 \
104         "  <method name=\"GetJob\">\n"                                  \
105         "   <arg name=\"id\" type=\"u\" direction=\"in\"/>\n"           \
106         "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
107         "  </method>\n"                                                 \
108         "  <method name=\"ClearJobs\"/>\n"                              \
109         "  <method name=\"ResetFailed\"/>\n"                            \
110         "  <method name=\"ListUnits\">\n"                               \
111         "   <arg name=\"units\" type=\"a(ssssssouso)\" direction=\"out\"/>\n" \
112         "  </method>\n"                                                 \
113         "  <method name=\"ListJobs\">\n"                                \
114         "   <arg name=\"jobs\" type=\"a(usssoo)\" direction=\"out\"/>\n" \
115         "  </method>\n"                                                 \
116         "  <method name=\"Subscribe\"/>\n"                              \
117         "  <method name=\"Unsubscribe\"/>\n"                            \
118         "  <method name=\"Dump\">\n"                                    \
119         "   <arg name=\"dump\" type=\"s\" direction=\"out\"/>\n"        \
120         "  </method>\n"                                                 \
121         "  <method name=\"CreateSnapshot\">\n"                          \
122         "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
123         "   <arg name=\"cleanup\" type=\"b\" direction=\"in\"/>\n"      \
124         "   <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n"        \
125         "  </method>\n"                                                 \
126         "  <method name=\"Reload\"/>\n"                                 \
127         "  <method name=\"Reexecute\"/>\n"                              \
128         "  <method name=\"Exit\"/>\n"                                   \
129         "  <method name=\"Reboot\"/>\n"                                 \
130         "  <method name=\"PowerOff\"/>\n"                               \
131         "  <method name=\"Halt\"/>\n"                                   \
132         "  <method name=\"KExec\"/>\n"                                  \
133         "  <method name=\"SwitchRoot\">\n"                              \
134         "   <arg name=\"new_root\" type=\"s\" direction=\"in\"/>\n"     \
135         "   <arg name=\"init\" type=\"s\" direction=\"in\"/>\n"         \
136         "  </method>\n"                                                 \
137         "  <method name=\"SetEnvironment\">\n"                          \
138         "   <arg name=\"names\" type=\"as\" direction=\"in\"/>\n"       \
139         "  </method>\n"                                                 \
140         "  <method name=\"UnsetEnvironment\">\n"                        \
141         "   <arg name=\"names\" type=\"as\" direction=\"in\"/>\n"       \
142         "  </method>\n"                                                 \
143         "  <method name=\"UnsetAndSetEnvironment\">\n"                  \
144         "   <arg name=\"unset\" type=\"as\" direction=\"in\"/>\n"       \
145         "   <arg name=\"set\" type=\"as\" direction=\"in\"/>\n"         \
146         "  </method>\n"                                                 \
147         "  <method name=\"ListUnitFiles\">\n"                            \
148         "   <arg name=\"files\" type=\"a(ss)\" direction=\"out\"/>\n" \
149         "  </method>\n"                                                 \
150         "  <method name=\"GetUnitFileState\">\n"                        \
151         "   <arg name=\"file\" type=\"s\" direction=\"in\"/>\n"         \
152         "   <arg name=\"state\" type=\"s\" direction=\"out\"/>\n"       \
153         "  </method>\n"                                                 \
154         "  <method name=\"EnableUnitFiles\">\n"                         \
155         "   <arg name=\"files\" type=\"as\" direction=\"in\"/>\n"       \
156         "   <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n"      \
157         "   <arg name=\"force\" type=\"b\" direction=\"in\"/>\n"        \
158         "   <arg name=\"carries_install_info\" type=\"b\" direction=\"out\"/>\n" \
159         "   <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
160         "  </method>\n"                                                 \
161         "  <method name=\"DisableUnitFiles\">\n"                        \
162         "   <arg name=\"files\" type=\"as\" direction=\"in\"/>\n"       \
163         "   <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n"      \
164         "   <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
165         "  </method>\n"                                                 \
166         "  <method name=\"ReenableUnitFiles\">\n"                       \
167         "   <arg name=\"files\" type=\"as\" direction=\"in\"/>\n"       \
168         "   <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n"      \
169         "   <arg name=\"force\" type=\"b\" direction=\"in\"/>\n"        \
170         "   <arg name=\"carries_install_info\" type=\"b\" direction=\"out\"/>\n" \
171         "   <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
172         "  </method>\n"                                                 \
173         "  <method name=\"LinkUnitFiles\">\n"                           \
174         "   <arg name=\"files\" type=\"as\" direction=\"in\"/>\n"       \
175         "   <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n"      \
176         "   <arg name=\"force\" type=\"b\" direction=\"in\"/>\n"        \
177         "   <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
178         "  </method>\n"                                                 \
179         "  <method name=\"PresetUnitFiles\">\n"                         \
180         "   <arg name=\"files\" type=\"as\" direction=\"in\"/>\n"       \
181         "   <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n"      \
182         "   <arg name=\"force\" type=\"b\" direction=\"in\"/>\n"        \
183         "   <arg name=\"carries_install_info\" type=\"b\" direction=\"out\"/>\n" \
184         "   <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
185         "  </method>\n"                                                 \
186         "  <method name=\"MaskUnitFiles\">\n"                           \
187         "   <arg name=\"files\" type=\"as\" direction=\"in\"/>\n"       \
188         "   <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n"      \
189         "   <arg name=\"force\" type=\"b\" direction=\"in\"/>\n"        \
190         "   <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
191         "  </method>\n"                                                 \
192         "  <method name=\"UnmaskUnitFiles\">\n"                         \
193         "   <arg name=\"files\" type=\"as\" direction=\"in\"/>\n"       \
194         "   <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n"      \
195         "   <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
196         "  </method>\n"
197
198 #define BUS_MANAGER_INTERFACE_SIGNALS                                   \
199         "  <signal name=\"UnitNew\">\n"                                 \
200         "   <arg name=\"id\" type=\"s\"/>\n"                            \
201         "   <arg name=\"unit\" type=\"o\"/>\n"                          \
202         "  </signal>\n"                                                 \
203         "  <signal name=\"UnitRemoved\">\n"                             \
204         "   <arg name=\"id\" type=\"s\"/>\n"                            \
205         "   <arg name=\"unit\" type=\"o\"/>\n"                          \
206         "  </signal>\n"                                                 \
207         "  <signal name=\"JobNew\">\n"                                  \
208         "   <arg name=\"id\" type=\"u\"/>\n"                            \
209         "   <arg name=\"job\" type=\"o\"/>\n"                           \
210         "   <arg name=\"unit\" type=\"s\"/>\n"                          \
211         "  </signal>\n"                                                 \
212         "  <signal name=\"JobRemoved\">\n"                              \
213         "   <arg name=\"id\" type=\"u\"/>\n"                            \
214         "   <arg name=\"job\" type=\"o\"/>\n"                           \
215         "   <arg name=\"unit\" type=\"s\"/>\n"                          \
216         "   <arg name=\"result\" type=\"s\"/>\n"                        \
217         "  </signal>"                                                   \
218         "  <signal name=\"StartupFinished\">\n"                         \
219         "   <arg name=\"firmware\" type=\"t\"/>\n"                      \
220         "   <arg name=\"loader\" type=\"t\"/>\n"                        \
221         "   <arg name=\"kernel\" type=\"t\"/>\n"                        \
222         "   <arg name=\"initrd\" type=\"t\"/>\n"                        \
223         "   <arg name=\"userspace\" type=\"t\"/>\n"                     \
224         "   <arg name=\"total\" type=\"t\"/>\n"                         \
225         "  </signal>"                                                   \
226         "  <signal name=\"UnitFilesChanged\"/>\n"
227
228 #define BUS_MANAGER_INTERFACE_PROPERTIES_GENERAL                        \
229         "  <property name=\"Version\" type=\"s\" access=\"read\"/>\n"   \
230         "  <property name=\"Distribution\" type=\"s\" access=\"read\"/>\n" \
231         "  <property name=\"Features\" type=\"s\" access=\"read\"/>\n"  \
232         "  <property name=\"Tainted\" type=\"s\" access=\"read\"/>\n"   \
233         "  <property name=\"FirmwareTimestamp\" type=\"t\" access=\"read\"/>\n" \
234         "  <property name=\"FirmwareTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
235         "  <property name=\"LoaderTimestamp\" type=\"t\" access=\"read\"/>\n" \
236         "  <property name=\"LoaderTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
237         "  <property name=\"KernelTimestamp\" type=\"t\" access=\"read\"/>\n" \
238         "  <property name=\"KernelTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
239         "  <property name=\"InitRDTimestamp\" type=\"t\" access=\"read\"/>\n" \
240         "  <property name=\"InitRDTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
241         "  <property name=\"UserspaceTimestamp\" type=\"t\" access=\"read\"/>\n" \
242         "  <property name=\"UserspaceTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
243         "  <property name=\"FinishTimestamp\" type=\"t\" access=\"read\"/>\n" \
244         "  <property name=\"FinishTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
245         "  <property name=\"LogLevel\" type=\"s\" access=\"readwrite\"/>\n"  \
246         "  <property name=\"LogTarget\" type=\"s\" access=\"readwrite\"/>\n" \
247         "  <property name=\"NNames\" type=\"u\" access=\"read\"/>\n"    \
248         "  <property name=\"NJobs\" type=\"u\" access=\"read\"/>\n"     \
249         "  <property name=\"NInstalledJobs\" type=\"u\" access=\"read\"/>\n" \
250         "  <property name=\"NFailedJobs\" type=\"u\" access=\"read\"/>\n" \
251         "  <property name=\"Progress\" type=\"d\" access=\"read\"/>\n"  \
252         "  <property name=\"Environment\" type=\"as\" access=\"read\"/>\n" \
253         "  <property name=\"ConfirmSpawn\" type=\"b\" access=\"read\"/>\n" \
254         "  <property name=\"ShowStatus\" type=\"b\" access=\"read\"/>\n" \
255         "  <property name=\"UnitPath\" type=\"as\" access=\"read\"/>\n" \
256         "  <property name=\"ControlGroupHierarchy\" type=\"s\" access=\"read\"/>\n" \
257         "  <property name=\"DefaultControllers\" type=\"as\" access=\"read\"/>\n" \
258         "  <property name=\"DefaultStandardOutput\" type=\"s\" access=\"read\"/>\n" \
259         "  <property name=\"DefaultStandardError\" type=\"s\" access=\"read\"/>\n" \
260         "  <property name=\"RuntimeWatchdogUSec\" type=\"s\" access=\"readwrite\"/>\n" \
261         "  <property name=\"ShutdownWatchdogUSec\" type=\"s\" access=\"readwrite\"/>\n"
262
263 #define BUS_MANAGER_INTERFACE_END                                       \
264         " </interface>\n"
265
266 #define BUS_MANAGER_INTERFACE                                           \
267         BUS_MANAGER_INTERFACE_BEGIN                                     \
268         BUS_MANAGER_INTERFACE_METHODS                                   \
269         BUS_MANAGER_INTERFACE_SIGNALS                                   \
270         BUS_MANAGER_INTERFACE_PROPERTIES_GENERAL                        \
271         BUS_MANAGER_INTERFACE_END
272
273 #define INTROSPECTION_BEGIN                                             \
274         DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE                       \
275         "<node>\n"                                                      \
276         BUS_MANAGER_INTERFACE                                           \
277         BUS_PROPERTIES_INTERFACE                                        \
278         BUS_PEER_INTERFACE                                              \
279         BUS_INTROSPECTABLE_INTERFACE
280
281 #define INTROSPECTION_END                                               \
282         "</node>\n"
283
284 #define INTERFACES_LIST                              \
285         BUS_GENERIC_INTERFACES_LIST                  \
286         "org.freedesktop.systemd1.Manager\0"
287
288 const char bus_manager_interface[] _introspect_("Manager") = BUS_MANAGER_INTERFACE;
289
290 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_exec_output, exec_output, ExecOutput);
291
292 static int bus_manager_append_tainted(DBusMessageIter *i, const char *property, void *data) {
293         const char *t;
294         Manager *m = data;
295         char buf[LINE_MAX] = "", *e = buf, *p = NULL;
296
297         assert(i);
298         assert(property);
299         assert(m);
300
301         if (m->taint_usr)
302                 e = stpcpy(e, "split-usr:");
303
304         if (readlink_malloc("/etc/mtab", &p) < 0)
305                 e = stpcpy(e, "mtab-not-symlink:");
306         else
307                 free(p);
308
309         if (access("/proc/cgroups", F_OK) < 0)
310                 e = stpcpy(e, "cgroups-missing:");
311
312         if (hwclock_is_localtime() > 0)
313                 e = stpcpy(e, "local-hwclock:");
314
315         /* remove the last ':' */
316         if (e != buf)
317                 e[-1] = 0;
318
319         t = buf;
320
321         if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
322                 return -ENOMEM;
323
324         return 0;
325 }
326
327 static int bus_manager_append_log_target(DBusMessageIter *i, const char *property, void *data) {
328         const char *t;
329
330         assert(i);
331         assert(property);
332
333         t = log_target_to_string(log_get_target());
334
335         if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
336                 return -ENOMEM;
337
338         return 0;
339 }
340
341 static int bus_manager_set_log_target(DBusMessageIter *i, const char *property, void *data) {
342         const char *t;
343
344         assert(i);
345         assert(property);
346
347         dbus_message_iter_get_basic(i, &t);
348
349         return log_set_target_from_string(t);
350 }
351
352 static int bus_manager_append_log_level(DBusMessageIter *i, const char *property, void *data) {
353         const char *t;
354
355         assert(i);
356         assert(property);
357
358         t = log_level_to_string(log_get_max_level());
359
360         if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
361                 return -ENOMEM;
362
363         return 0;
364 }
365
366 static int bus_manager_set_log_level(DBusMessageIter *i, const char *property, void *data) {
367         const char *t;
368
369         assert(i);
370         assert(property);
371
372         dbus_message_iter_get_basic(i, &t);
373
374         return log_set_max_level_from_string(t);
375 }
376
377 static int bus_manager_append_n_names(DBusMessageIter *i, const char *property, void *data) {
378         Manager *m = data;
379         uint32_t u;
380
381         assert(i);
382         assert(property);
383         assert(m);
384
385         u = hashmap_size(m->units);
386
387         if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, &u))
388                 return -ENOMEM;
389
390         return 0;
391 }
392
393 static int bus_manager_append_n_jobs(DBusMessageIter *i, const char *property, void *data) {
394         Manager *m = data;
395         uint32_t u;
396
397         assert(i);
398         assert(property);
399         assert(m);
400
401         u = hashmap_size(m->jobs);
402
403         if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, &u))
404                 return -ENOMEM;
405
406         return 0;
407 }
408
409 static int bus_manager_append_progress(DBusMessageIter *i, const char *property, void *data) {
410         double d;
411         Manager *m = data;
412
413         assert(i);
414         assert(property);
415         assert(m);
416
417         if (dual_timestamp_is_set(&m->finish_timestamp))
418                 d = 1.0;
419         else
420                 d = 1.0 - ((double) hashmap_size(m->jobs) / (double) m->n_installed_jobs);
421
422         if (!dbus_message_iter_append_basic(i, DBUS_TYPE_DOUBLE, &d))
423                 return -ENOMEM;
424
425         return 0;
426 }
427
428 static DBusMessage *message_from_file_changes(
429                 DBusMessage *m,
430                 UnitFileChange *changes,
431                 unsigned n_changes,
432                 int carries_install_info) {
433
434         DBusMessageIter iter, sub, sub2;
435         DBusMessage *reply;
436         unsigned i;
437
438         reply = dbus_message_new_method_return(m);
439         if (!reply)
440                 return NULL;
441
442         dbus_message_iter_init_append(reply, &iter);
443
444         if (carries_install_info >= 0) {
445                 dbus_bool_t b;
446
447                 b = !!carries_install_info;
448                 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b))
449                         goto oom;
450         }
451
452         if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(sss)", &sub))
453                 goto oom;
454
455         for (i = 0; i < n_changes; i++) {
456                 const char *type, *path, *source;
457
458                 type = unit_file_change_type_to_string(changes[i].type);
459                 path = strempty(changes[i].path);
460                 source = strempty(changes[i].source);
461
462                 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
463                     !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &type) ||
464                     !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &path) ||
465                     !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &source) ||
466                     !dbus_message_iter_close_container(&sub, &sub2))
467                         goto oom;
468         }
469
470         if (!dbus_message_iter_close_container(&iter, &sub))
471                 goto oom;
472
473         return reply;
474
475 oom:
476         dbus_message_unref(reply);
477         return NULL;
478 }
479
480 static int bus_manager_send_unit_files_changed(Manager *m) {
481         DBusMessage *s;
482         int r;
483
484         s = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "UnitFilesChanged");
485         if (!s)
486                 return -ENOMEM;
487
488         r = bus_broadcast(m, s);
489         dbus_message_unref(s);
490
491         return r;
492 }
493
494 static int bus_manager_set_runtime_watchdog_usec(DBusMessageIter *i, const char *property, void *data) {
495         uint64_t *t = data;
496
497         assert(i);
498         assert(property);
499
500         dbus_message_iter_get_basic(i, t);
501
502         return watchdog_set_timeout(t);
503 }
504
505 static const char systemd_property_string[] =
506         PACKAGE_STRING "\0"
507         DISTRIBUTION "\0"
508         SYSTEMD_FEATURES;
509
510 static const BusProperty bus_systemd_properties[] = {
511         { "Version",       bus_property_append_string,    "s",  0                                             },
512         { "Distribution",  bus_property_append_string,    "s",  sizeof(PACKAGE_STRING)                        },
513         { "Features",      bus_property_append_string,    "s",  sizeof(PACKAGE_STRING) + sizeof(DISTRIBUTION) },
514         { NULL, }
515 };
516
517 static const BusProperty bus_manager_properties[] = {
518         { "Tainted",       bus_manager_append_tainted,             "s", 0                                              },
519         { "FirmwareTimestamp", bus_property_append_uint64,         "t", offsetof(Manager, firmware_timestamp.realtime) },
520         { "FirmwareTimestampMonotonic", bus_property_append_uint64,"t", offsetof(Manager, firmware_timestamp.monotonic)},
521         { "LoaderTimestamp", bus_property_append_uint64,           "t", offsetof(Manager, loader_timestamp.realtime)   },
522         { "LoaderTimestampMonotonic", bus_property_append_uint64,  "t", offsetof(Manager, loader_timestamp.monotonic)  },
523         { "KernelTimestamp", bus_property_append_uint64,           "t", offsetof(Manager, kernel_timestamp.realtime)   },
524         { "KernelTimestampMonotonic", bus_property_append_uint64,  "t", offsetof(Manager, kernel_timestamp.monotonic)  },
525         { "InitRDTimestamp", bus_property_append_uint64,           "t", offsetof(Manager, initrd_timestamp.realtime)   },
526         { "InitRDTimestampMonotonic", bus_property_append_uint64,  "t", offsetof(Manager, initrd_timestamp.monotonic)  },
527         { "UserspaceTimestamp", bus_property_append_uint64,        "t", offsetof(Manager, userspace_timestamp.realtime)},
528         { "UserspaceTimestampMonotonic", bus_property_append_uint64,"t",offsetof(Manager, userspace_timestamp.monotonic)},
529         { "FinishTimestamp", bus_property_append_uint64,           "t", offsetof(Manager, finish_timestamp.realtime)   },
530         { "FinishTimestampMonotonic", bus_property_append_uint64,  "t", offsetof(Manager, finish_timestamp.monotonic)  },
531         { "LogLevel",      bus_manager_append_log_level,           "s", 0,                                             false, bus_manager_set_log_level },
532         { "LogTarget",     bus_manager_append_log_target,          "s", 0,                                             false, bus_manager_set_log_target },
533         { "NNames",        bus_manager_append_n_names,             "u", 0                                              },
534         { "NJobs",         bus_manager_append_n_jobs,              "u", 0                                              },
535         { "NInstalledJobs",bus_property_append_uint32,             "u", offsetof(Manager, n_installed_jobs)            },
536         { "NFailedJobs",   bus_property_append_uint32,             "u", offsetof(Manager, n_failed_jobs)               },
537         { "Progress",      bus_manager_append_progress,            "d", 0                                              },
538         { "Environment",   bus_property_append_strv,              "as", offsetof(Manager, environment),                true },
539         { "ConfirmSpawn",  bus_property_append_bool,               "b", offsetof(Manager, confirm_spawn)               },
540         { "ShowStatus",    bus_property_append_bool,               "b", offsetof(Manager, show_status)                 },
541         { "UnitPath",      bus_property_append_strv,              "as", offsetof(Manager, lookup_paths.unit_path),     true },
542         { "ControlGroupHierarchy", bus_property_append_string,     "s", offsetof(Manager, cgroup_hierarchy),           true },
543         { "DefaultControllers", bus_property_append_strv,         "as", offsetof(Manager, default_controllers),        true },
544         { "DefaultStandardOutput", bus_manager_append_exec_output, "s", offsetof(Manager, default_std_output)          },
545         { "DefaultStandardError",  bus_manager_append_exec_output, "s", offsetof(Manager, default_std_error)           },
546         { "RuntimeWatchdogUSec", bus_property_append_usec,         "t", offsetof(Manager, runtime_watchdog),           false, bus_manager_set_runtime_watchdog_usec },
547         { "ShutdownWatchdogUSec", bus_property_append_usec,        "t", offsetof(Manager, shutdown_watchdog),          false, bus_property_set_usec },
548         { NULL, }
549 };
550
551 static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, DBusMessage *message, void *data) {
552         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
553         _cleanup_free_ char * path = NULL;
554         Manager *m = data;
555         int r;
556         DBusError error;
557         JobType job_type = _JOB_TYPE_INVALID;
558         bool reload_if_possible = false;
559         const char *member;
560
561         assert(connection);
562         assert(message);
563         assert(m);
564
565         dbus_error_init(&error);
566
567         member = dbus_message_get_member(message);
568
569         if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnit")) {
570                 const char *name;
571                 Unit *u;
572
573                 if (!dbus_message_get_args(
574                                     message,
575                                     &error,
576                                     DBUS_TYPE_STRING, &name,
577                                     DBUS_TYPE_INVALID))
578                         return bus_send_error_reply(connection, message, &error, -EINVAL);
579
580                 u = manager_get_unit(m, name);
581                 if (!u) {
582                         dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
583                         return bus_send_error_reply(connection, message, &error, -ENOENT);
584                 }
585
586                 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status");
587
588                 reply = dbus_message_new_method_return(message);
589                 if (!reply)
590                         goto oom;
591
592                 path = unit_dbus_path(u);
593                 if (!path)
594                         goto oom;
595
596                 if (!dbus_message_append_args(
597                                     reply,
598                                     DBUS_TYPE_OBJECT_PATH, &path,
599                                     DBUS_TYPE_INVALID))
600                         goto oom;
601         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnitByPID")) {
602                 Unit *u;
603                 uint32_t pid;
604
605                 if (!dbus_message_get_args(
606                                     message,
607                                     &error,
608                                     DBUS_TYPE_UINT32, &pid,
609                                     DBUS_TYPE_INVALID))
610                         return bus_send_error_reply(connection, message, &error, -EINVAL);
611
612                 u = cgroup_unit_by_pid(m, (pid_t) pid);
613                 if (!u) {
614                         dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "No unit for PID %lu is loaded.", (unsigned long) pid);
615                         return bus_send_error_reply(connection, message, &error, -ENOENT);
616                 }
617
618                 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status");
619
620                 reply = dbus_message_new_method_return(message);
621                 if (!reply)
622                         goto oom;
623
624                 path = unit_dbus_path(u);
625                 if (!reply)
626                         goto oom;
627
628                 if (!dbus_message_append_args(
629                                     reply,
630                                     DBUS_TYPE_OBJECT_PATH, &path,
631                                     DBUS_TYPE_INVALID))
632                         goto oom;
633         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "LoadUnit")) {
634                 const char *name;
635                 Unit *u;
636
637                 if (!dbus_message_get_args(
638                                     message,
639                                     &error,
640                                     DBUS_TYPE_STRING, &name,
641                                     DBUS_TYPE_INVALID))
642                         return bus_send_error_reply(connection, message, &error, -EINVAL);
643
644                 r = manager_load_unit(m, name, NULL, &error, &u);
645                 if (r < 0)
646                         return bus_send_error_reply(connection, message, &error, r);
647
648                 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status");
649
650                 reply = dbus_message_new_method_return(message);
651                 if (!reply)
652                         goto oom;
653
654                 path = unit_dbus_path(u);
655                 if (!path)
656                         goto oom;
657
658                 if (!dbus_message_append_args(
659                                     reply,
660                                     DBUS_TYPE_OBJECT_PATH, &path,
661                                     DBUS_TYPE_INVALID))
662                         goto oom;
663
664         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnit"))
665                 job_type = JOB_START;
666         else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnitReplace"))
667                 job_type = JOB_START;
668         else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StopUnit"))
669                 job_type = JOB_STOP;
670         else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadUnit"))
671                 job_type = JOB_RELOAD;
672         else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "RestartUnit"))
673                 job_type = JOB_RESTART;
674         else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "TryRestartUnit"))
675                 job_type = JOB_TRY_RESTART;
676         else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadOrRestartUnit")) {
677                 reload_if_possible = true;
678                 job_type = JOB_RESTART;
679         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadOrTryRestartUnit")) {
680                 reload_if_possible = true;
681                 job_type = JOB_TRY_RESTART;
682         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "KillUnit")) {
683                 const char *name, *swho;
684                 int32_t signo;
685                 Unit *u;
686                 KillWho who;
687
688                 if (!dbus_message_get_args(
689                                     message,
690                                     &error,
691                                     DBUS_TYPE_STRING, &name,
692                                     DBUS_TYPE_STRING, &swho,
693                                     DBUS_TYPE_INT32, &signo,
694                                     DBUS_TYPE_INVALID))
695                         return bus_send_error_reply(connection, message, &error, -EINVAL);
696
697                 if (isempty(swho))
698                         who = KILL_ALL;
699                 else {
700                         who = kill_who_from_string(swho);
701                         if (who < 0)
702                                 return bus_send_error_reply(connection, message, &error, -EINVAL);
703                 }
704
705                 if (signo <= 0 || signo >= _NSIG)
706                         return bus_send_error_reply(connection, message, &error, -EINVAL);
707
708                 u = manager_get_unit(m, name);
709                 if (!u) {
710                         dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
711                         return bus_send_error_reply(connection, message, &error, -ENOENT);
712                 }
713
714                 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "stop");
715
716                 r = unit_kill(u, who, signo, &error);
717                 if (r < 0)
718                         return bus_send_error_reply(connection, message, &error, r);
719
720                 if (!(reply = dbus_message_new_method_return(message)))
721                         goto oom;
722
723         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetJob")) {
724                 uint32_t id;
725                 Job *j;
726
727                 if (!dbus_message_get_args(
728                                     message,
729                                     &error,
730                                     DBUS_TYPE_UINT32, &id,
731                                     DBUS_TYPE_INVALID))
732                         return bus_send_error_reply(connection, message, &error, -EINVAL);
733
734                 j = manager_get_job(m, id);
735                 if (!j) {
736                         dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "Job %u does not exist.", (unsigned) id);
737                         return bus_send_error_reply(connection, message, &error, -ENOENT);
738                 }
739
740                 SELINUX_UNIT_ACCESS_CHECK(j->unit, connection, message, "status");
741
742                 reply = dbus_message_new_method_return(message);
743                 if (!reply)
744                         goto oom;
745
746                 path = job_dbus_path(j);
747                 if (!path)
748                         goto oom;
749
750                 if (!dbus_message_append_args(
751                                     reply,
752                                     DBUS_TYPE_OBJECT_PATH, &path,
753                                     DBUS_TYPE_INVALID))
754                         goto oom;
755
756         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ClearJobs")) {
757
758                 SELINUX_ACCESS_CHECK(connection, message, "reboot");
759
760                 manager_clear_jobs(m);
761
762                 reply = dbus_message_new_method_return(message);
763                 if (!reply)
764                         goto oom;
765
766         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ResetFailed")) {
767
768                 SELINUX_ACCESS_CHECK(connection, message, "reload");
769
770                 manager_reset_failed(m);
771
772                 reply = dbus_message_new_method_return(message);
773                 if (!reply)
774                         goto oom;
775
776         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ResetFailedUnit")) {
777                 const char *name;
778                 Unit *u;
779
780                 if (!dbus_message_get_args(
781                                     message,
782                                     &error,
783                                     DBUS_TYPE_STRING, &name,
784                                     DBUS_TYPE_INVALID))
785                         return bus_send_error_reply(connection, message, &error, -EINVAL);
786
787                 u = manager_get_unit(m, name);
788                 if (!u) {
789                         dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
790                         return bus_send_error_reply(connection, message, &error, -ENOENT);
791                 }
792
793                 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "reload");
794
795                 unit_reset_failed(u);
796
797                 reply = dbus_message_new_method_return(message);
798                 if (!reply)
799                         goto oom;
800
801         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnits")) {
802                 DBusMessageIter iter, sub;
803                 Iterator i;
804                 Unit *u;
805                 const char *k;
806
807                 SELINUX_ACCESS_CHECK(connection, message, "status");
808
809                 reply = dbus_message_new_method_return(message);
810                 if (!reply)
811                         goto oom;
812
813                 dbus_message_iter_init_append(reply, &iter);
814
815                 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssssouso)", &sub))
816                         goto oom;
817
818                 HASHMAP_FOREACH_KEY(u, k, m->units, i) {
819                         char *u_path, *j_path;
820                         const char *description, *load_state, *active_state, *sub_state, *sjob_type, *following;
821                         DBusMessageIter sub2;
822                         uint32_t job_id;
823                         Unit *f;
824
825                         if (k != u->id)
826                                 continue;
827
828                         if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
829                                 goto oom;
830
831                         description = unit_description(u);
832                         load_state = unit_load_state_to_string(u->load_state);
833                         active_state = unit_active_state_to_string(unit_active_state(u));
834                         sub_state = unit_sub_state_to_string(u);
835
836                         f = unit_following(u);
837                         following = f ? f->id : "";
838
839                         u_path = unit_dbus_path(u);
840                         if (!u_path)
841                                 goto oom;
842
843                         if (u->job) {
844                                 job_id = (uint32_t) u->job->id;
845
846                                 if (!(j_path = job_dbus_path(u->job))) {
847                                         free(u_path);
848                                         goto oom;
849                                 }
850
851                                 sjob_type = job_type_to_string(u->job->type);
852                         } else {
853                                 job_id = 0;
854                                 j_path = u_path;
855                                 sjob_type = "";
856                         }
857
858                         if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &u->id) ||
859                             !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &description) ||
860                             !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &load_state) ||
861                             !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &active_state) ||
862                             !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &sub_state) ||
863                             !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &following) ||
864                             !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &u_path) ||
865                             !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &job_id) ||
866                             !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &sjob_type) ||
867                             !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &j_path)) {
868                                 free(u_path);
869                                 if (u->job)
870                                         free(j_path);
871                                 goto oom;
872                         }
873
874                         free(u_path);
875                         if (u->job)
876                                 free(j_path);
877
878                         if (!dbus_message_iter_close_container(&sub, &sub2))
879                                 goto oom;
880                 }
881
882                 if (!dbus_message_iter_close_container(&iter, &sub))
883                         goto oom;
884
885         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListJobs")) {
886                 DBusMessageIter iter, sub;
887                 Iterator i;
888                 Job *j;
889
890                 SELINUX_ACCESS_CHECK(connection, message, "status");
891
892                 reply = dbus_message_new_method_return(message);
893                 if (!reply)
894                         goto oom;
895
896                 dbus_message_iter_init_append(reply, &iter);
897
898                 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(usssoo)", &sub))
899                         goto oom;
900
901                 HASHMAP_FOREACH(j, m->jobs, i) {
902                         char *u_path, *j_path;
903                         const char *state, *type;
904                         uint32_t id;
905                         DBusMessageIter sub2;
906
907                         if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
908                                 goto oom;
909
910                         id = (uint32_t) j->id;
911                         state = job_state_to_string(j->state);
912                         type = job_type_to_string(j->type);
913
914                         j_path = job_dbus_path(j);
915                         if (!j_path)
916                                 goto oom;
917
918                         u_path = unit_dbus_path(j->unit);
919                         if (!u_path) {
920                                 free(j_path);
921                                 goto oom;
922                         }
923
924                         if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &id) ||
925                             !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &j->unit->id) ||
926                             !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &type) ||
927                             !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &state) ||
928                             !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &j_path) ||
929                             !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &u_path)) {
930                                 free(j_path);
931                                 free(u_path);
932                                 goto oom;
933                         }
934
935                         free(j_path);
936                         free(u_path);
937
938                         if (!dbus_message_iter_close_container(&sub, &sub2))
939                                 goto oom;
940                 }
941
942                 if (!dbus_message_iter_close_container(&iter, &sub))
943                         goto oom;
944
945         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Subscribe")) {
946                 char *client;
947                 Set *s;
948
949                 SELINUX_ACCESS_CHECK(connection, message, "status");
950
951                 s = BUS_CONNECTION_SUBSCRIBED(m, connection);
952                 if (!s) {
953                         s = set_new(string_hash_func, string_compare_func);
954                         if (!s)
955                                 goto oom;
956
957                         if (!dbus_connection_set_data(connection, m->subscribed_data_slot, s, NULL)) {
958                                 set_free(s);
959                                 goto oom;
960                         }
961                 }
962
963                 client = strdup(bus_message_get_sender_with_fallback(message));
964                 if (!client)
965                         goto oom;
966
967                 r = set_put(s, client);
968                 if (r < 0) {
969                         free(client);
970                         return bus_send_error_reply(connection, message, NULL, r);
971                 }
972
973                 reply = dbus_message_new_method_return(message);
974                 if (!reply)
975                         goto oom;
976
977         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Unsubscribe")) {
978                 char *client;
979
980                 SELINUX_ACCESS_CHECK(connection, message, "status");
981
982                 client = set_remove(BUS_CONNECTION_SUBSCRIBED(m, connection), (char*) bus_message_get_sender_with_fallback(message));
983                 if (!client) {
984                         dbus_set_error(&error, BUS_ERROR_NOT_SUBSCRIBED, "Client is not subscribed.");
985                         return bus_send_error_reply(connection, message, &error, -ENOENT);
986                 }
987
988                 free(client);
989
990                 reply = dbus_message_new_method_return(message);
991                 if (!reply)
992                         goto oom;
993
994         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Dump")) {
995                 FILE *f;
996                 char *dump = NULL;
997                 size_t size;
998
999                 SELINUX_ACCESS_CHECK(connection, message, "status");
1000
1001                 reply = dbus_message_new_method_return(message);
1002                 if (!reply)
1003                         goto oom;
1004
1005                 f = open_memstream(&dump, &size);
1006                 if (!f)
1007                         goto oom;
1008
1009                 manager_dump_units(m, f, NULL);
1010                 manager_dump_jobs(m, f, NULL);
1011
1012                 if (ferror(f)) {
1013                         fclose(f);
1014                         free(dump);
1015                         goto oom;
1016                 }
1017
1018                 fclose(f);
1019
1020                 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &dump, DBUS_TYPE_INVALID)) {
1021                         free(dump);
1022                         goto oom;
1023                 }
1024
1025                 free(dump);
1026         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "CreateSnapshot")) {
1027                 const char *name;
1028                 dbus_bool_t cleanup;
1029                 Snapshot *s;
1030
1031                 SELINUX_ACCESS_CHECK(connection, message, "start");
1032
1033                 if (!dbus_message_get_args(
1034                                     message,
1035                                     &error,
1036                                     DBUS_TYPE_STRING, &name,
1037                                     DBUS_TYPE_BOOLEAN, &cleanup,
1038                                     DBUS_TYPE_INVALID))
1039                         return bus_send_error_reply(connection, message, &error, -EINVAL);
1040
1041                 if (isempty(name))
1042                         name = NULL;
1043
1044                 r = snapshot_create(m, name, cleanup, &error, &s);
1045                 if (r < 0)
1046                         return bus_send_error_reply(connection, message, &error, r);
1047
1048                 reply = dbus_message_new_method_return(message);
1049                 if (!reply)
1050                         goto oom;
1051
1052                 path = unit_dbus_path(UNIT(s));
1053                 if (!path)
1054                         goto oom;
1055
1056                 if (!dbus_message_append_args(
1057                                     reply,
1058                                     DBUS_TYPE_OBJECT_PATH, &path,
1059                                     DBUS_TYPE_INVALID))
1060                         goto oom;
1061
1062         } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
1063                 char *introspection = NULL;
1064                 FILE *f;
1065                 Iterator i;
1066                 Unit *u;
1067                 Job *j;
1068                 const char *k;
1069                 size_t size;
1070
1071                 SELINUX_ACCESS_CHECK(connection, message, "status");
1072
1073                 reply = dbus_message_new_method_return(message);
1074                 if (!reply)
1075                         goto oom;
1076
1077                 /* We roll our own introspection code here, instead of
1078                  * relying on bus_default_message_handler() because we
1079                  * need to generate our introspection string
1080                  * dynamically. */
1081
1082                 f = open_memstream(&introspection, &size);
1083                 if (!f)
1084                         goto oom;
1085
1086                 fputs(INTROSPECTION_BEGIN, f);
1087
1088                 HASHMAP_FOREACH_KEY(u, k, m->units, i) {
1089                         char *p;
1090
1091                         if (k != u->id)
1092                                 continue;
1093
1094                         p = bus_path_escape(k);
1095                         if (!p) {
1096                                 fclose(f);
1097                                 free(introspection);
1098                                 goto oom;
1099                         }
1100
1101                         fprintf(f, "<node name=\"unit/%s\"/>", p);
1102                         free(p);
1103                 }
1104
1105                 HASHMAP_FOREACH(j, m->jobs, i)
1106                         fprintf(f, "<node name=\"job/%lu\"/>", (unsigned long) j->id);
1107
1108                 fputs(INTROSPECTION_END, f);
1109
1110                 if (ferror(f)) {
1111                         fclose(f);
1112                         free(introspection);
1113                         goto oom;
1114                 }
1115
1116                 fclose(f);
1117
1118                 if (!introspection)
1119                         goto oom;
1120
1121                 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
1122                         free(introspection);
1123                         goto oom;
1124                 }
1125
1126                 free(introspection);
1127
1128         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reload")) {
1129
1130                 SELINUX_ACCESS_CHECK(connection, message, "reload");
1131
1132                 assert(!m->queued_message);
1133
1134                 /* Instead of sending the reply back right away, we
1135                  * just remember that we need to and then send it
1136                  * after the reload is finished. That way the caller
1137                  * knows when the reload finished. */
1138
1139                 m->queued_message = dbus_message_new_method_return(message);
1140                 if (!m->queued_message)
1141                         goto oom;
1142
1143                 m->queued_message_connection = connection;
1144                 m->exit_code = MANAGER_RELOAD;
1145
1146         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reexecute")) {
1147
1148                 SELINUX_ACCESS_CHECK(connection, message, "reload");
1149
1150                 /* We don't send a reply back here, the client should
1151                  * just wait for us disconnecting. */
1152
1153                 m->exit_code = MANAGER_REEXECUTE;
1154
1155         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Exit")) {
1156
1157                 SELINUX_ACCESS_CHECK(connection, message, "halt");
1158
1159                 if (m->running_as == SYSTEMD_SYSTEM) {
1160                         dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Exit is only supported for user service managers.");
1161                         return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1162                 }
1163
1164                 reply = dbus_message_new_method_return(message);
1165                 if (!reply)
1166                         goto oom;
1167
1168                 m->exit_code = MANAGER_EXIT;
1169
1170         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reboot")) {
1171
1172                 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1173
1174                 if (m->running_as != SYSTEMD_SYSTEM) {
1175                         dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Reboot is only supported for system managers.");
1176                         return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1177                 }
1178
1179                 reply = dbus_message_new_method_return(message);
1180                 if (!reply)
1181                         goto oom;
1182
1183                 m->exit_code = MANAGER_REBOOT;
1184
1185         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "PowerOff")) {
1186
1187                 SELINUX_ACCESS_CHECK(connection, message, "halt");
1188
1189                 if (m->running_as != SYSTEMD_SYSTEM) {
1190                         dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Powering off is only supported for system managers.");
1191                         return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1192                 }
1193
1194                 reply = dbus_message_new_method_return(message);
1195                 if (!reply)
1196                         goto oom;
1197
1198                 m->exit_code = MANAGER_POWEROFF;
1199
1200         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Halt")) {
1201
1202                 SELINUX_ACCESS_CHECK(connection, message, "halt");
1203
1204                 if (m->running_as != SYSTEMD_SYSTEM) {
1205                         dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Halting is only supported for system managers.");
1206                         return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1207                 }
1208
1209                 reply = dbus_message_new_method_return(message);
1210                 if (!reply)
1211                         goto oom;
1212
1213                 m->exit_code = MANAGER_HALT;
1214
1215         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "KExec")) {
1216
1217                 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1218
1219                 if (m->running_as != SYSTEMD_SYSTEM) {
1220                         dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "kexec is only supported for system managers.");
1221                         return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1222                 }
1223
1224                 reply = dbus_message_new_method_return(message);
1225                 if (!reply)
1226                         goto oom;
1227
1228                 m->exit_code = MANAGER_KEXEC;
1229
1230         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SwitchRoot")) {
1231                 const char *switch_root, *switch_root_init;
1232                 char *u, *v;
1233                 int k;
1234
1235                 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1236
1237                 if (!dbus_message_get_args(
1238                                     message,
1239                                     &error,
1240                                     DBUS_TYPE_STRING, &switch_root,
1241                                     DBUS_TYPE_STRING, &switch_root_init,
1242                                     DBUS_TYPE_INVALID))
1243                         return bus_send_error_reply(connection, message, &error, -EINVAL);
1244
1245                 if (path_equal(switch_root, "/") || !path_is_absolute(switch_root))
1246                         return bus_send_error_reply(connection, message, NULL, -EINVAL);
1247
1248                 if (!isempty(switch_root_init) && !path_is_absolute(switch_root_init))
1249                         return bus_send_error_reply(connection, message, NULL, -EINVAL);
1250
1251                 if (m->running_as != SYSTEMD_SYSTEM) {
1252                         dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Switching root is only supported for system managers.");
1253                         return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1254                 }
1255
1256                 /* Safety check */
1257                 if (isempty(switch_root_init))
1258                         k = access(switch_root, F_OK);
1259                 else {
1260                         char *p;
1261
1262                         p = strjoin(switch_root, "/", switch_root_init, NULL);
1263                         if (!p)
1264                                 goto oom;
1265
1266                         k = access(p, X_OK);
1267                         free(p);
1268                 }
1269                 if (k < 0)
1270                         return bus_send_error_reply(connection, message, NULL, -errno);
1271
1272                 u = strdup(switch_root);
1273                 if (!u)
1274                         goto oom;
1275
1276                 if (!isempty(switch_root_init)) {
1277                         v = strdup(switch_root_init);
1278                         if (!v) {
1279                                 free(u);
1280                                 goto oom;
1281                         }
1282                 } else
1283                         v = NULL;
1284
1285                 free(m->switch_root);
1286                 free(m->switch_root_init);
1287                 m->switch_root = u;
1288                 m->switch_root_init = v;
1289
1290                 reply = dbus_message_new_method_return(message);
1291                 if (!reply)
1292                         goto oom;
1293
1294                 m->exit_code = MANAGER_SWITCH_ROOT;
1295
1296         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetEnvironment")) {
1297                 char **l = NULL, **e = NULL;
1298
1299                 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1300
1301                 r = bus_parse_strv(message, &l);
1302                 if (r == -ENOMEM)
1303                         goto oom;
1304                 if (r < 0)
1305                         return bus_send_error_reply(connection, message, NULL, r);
1306
1307                 e = strv_env_merge(2, m->environment, l);
1308                 strv_free(l);
1309                 if (!e)
1310                         goto oom;
1311
1312                 reply = dbus_message_new_method_return(message);
1313                 if (!reply) {
1314                         strv_free(e);
1315                         goto oom;
1316                 }
1317
1318                 strv_free(m->environment);
1319                 m->environment = e;
1320
1321         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetEnvironment")) {
1322                 char **l = NULL, **e = NULL;
1323
1324                 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1325
1326                 r = bus_parse_strv(message, &l);
1327                 if (r == -ENOMEM)
1328                         goto oom;
1329                 if (r < 0)
1330                         return bus_send_error_reply(connection, message, NULL, r);
1331
1332                 e = strv_env_delete(m->environment, 1, l);
1333                 strv_free(l);
1334
1335                 if (!e)
1336                         goto oom;
1337
1338                 if (!(reply = dbus_message_new_method_return(message))) {
1339                         strv_free(e);
1340                         goto oom;
1341                 }
1342
1343                 strv_free(m->environment);
1344                 m->environment = e;
1345
1346         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetAndSetEnvironment")) {
1347                 char **l_set = NULL, **l_unset = NULL, **e = NULL, **f = NULL;
1348                 DBusMessageIter iter;
1349
1350                 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1351
1352                 if (!dbus_message_iter_init(message, &iter))
1353                         goto oom;
1354
1355                 r = bus_parse_strv_iter(&iter, &l_unset);
1356                 if (r == -ENOMEM)
1357                         goto oom;
1358                 if (r < 0)
1359                         return bus_send_error_reply(connection, message, NULL, r);
1360
1361                 if (!dbus_message_iter_next(&iter)) {
1362                         strv_free(l_unset);
1363                         return bus_send_error_reply(connection, message, NULL, -EINVAL);
1364                 }
1365
1366                 r = bus_parse_strv_iter(&iter, &l_set);
1367                 if (r < 0) {
1368                         strv_free(l_unset);
1369                         if (r == -ENOMEM)
1370                                 goto oom;
1371
1372                         return bus_send_error_reply(connection, message, NULL, r);
1373                 }
1374
1375                 e = strv_env_delete(m->environment, 1, l_unset);
1376                 strv_free(l_unset);
1377
1378                 if (!e) {
1379                         strv_free(l_set);
1380                         goto oom;
1381                 }
1382
1383                 f = strv_env_merge(2, e, l_set);
1384                 strv_free(l_set);
1385                 strv_free(e);
1386
1387                 if (!f)
1388                         goto oom;
1389
1390                 if (!(reply = dbus_message_new_method_return(message))) {
1391                         strv_free(f);
1392                         goto oom;
1393                 }
1394
1395                 strv_free(m->environment);
1396                 m->environment = f;
1397         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnitFiles")) {
1398                 DBusMessageIter iter, sub, sub2;
1399                 Hashmap *h;
1400                 Iterator i;
1401                 UnitFileList *item;
1402
1403                 SELINUX_ACCESS_CHECK(connection, message, "status");
1404
1405                 reply = dbus_message_new_method_return(message);
1406                 if (!reply)
1407                         goto oom;
1408
1409                 h = hashmap_new(string_hash_func, string_compare_func);
1410                 if (!h)
1411                         goto oom;
1412
1413                 r = unit_file_get_list(m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, h);
1414                 if (r < 0) {
1415                         unit_file_list_free(h);
1416                         dbus_message_unref(reply);
1417                         return bus_send_error_reply(connection, message, NULL, r);
1418                 }
1419
1420                 dbus_message_iter_init_append(reply, &iter);
1421
1422                 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ss)", &sub)) {
1423                         unit_file_list_free(h);
1424                         goto oom;
1425                 }
1426
1427                 HASHMAP_FOREACH(item, h, i) {
1428                         const char *state;
1429
1430                         state = unit_file_state_to_string(item->state);
1431                         assert(state);
1432
1433                         if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
1434                             !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &item->path) ||
1435                             !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &state) ||
1436                             !dbus_message_iter_close_container(&sub, &sub2)) {
1437                                 unit_file_list_free(h);
1438                                 goto oom;
1439                         }
1440                 }
1441
1442                 unit_file_list_free(h);
1443
1444                 if (!dbus_message_iter_close_container(&iter, &sub))
1445                         goto oom;
1446
1447         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnitFileState")) {
1448                 const char *name;
1449                 UnitFileState state;
1450                 const char *s;
1451
1452                 SELINUX_ACCESS_CHECK(connection, message, "status");
1453
1454                 if (!dbus_message_get_args(
1455                                     message,
1456                                     &error,
1457                                     DBUS_TYPE_STRING, &name,
1458                                     DBUS_TYPE_INVALID))
1459                         return bus_send_error_reply(connection, message, &error, -EINVAL);
1460
1461                 state = unit_file_get_state(m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, name);
1462                 if (state < 0)
1463                         return bus_send_error_reply(connection, message, NULL, state);
1464
1465                 s = unit_file_state_to_string(state);
1466                 assert(s);
1467
1468                 reply = dbus_message_new_method_return(message);
1469                 if (!reply)
1470                         goto oom;
1471
1472                 if (!dbus_message_append_args(
1473                                     reply,
1474                                     DBUS_TYPE_STRING, &s,
1475                                     DBUS_TYPE_INVALID))
1476                         goto oom;
1477         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "EnableUnitFiles") ||
1478                    dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReenableUnitFiles") ||
1479                    dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "LinkUnitFiles") ||
1480                    dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "PresetUnitFiles") ||
1481                    dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "MaskUnitFiles")) {
1482
1483                 char **l = NULL;
1484                 DBusMessageIter iter;
1485                 UnitFileScope scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
1486                 UnitFileChange *changes = NULL;
1487                 unsigned n_changes = 0;
1488                 dbus_bool_t runtime, force;
1489                 int carries_install_info = -1;
1490
1491                 SELINUX_ACCESS_CHECK(connection, message, streq(member, "MaskUnitFiles") ? "disable" : "enable");
1492
1493                 if (!dbus_message_iter_init(message, &iter))
1494                         goto oom;
1495
1496                 r = bus_parse_strv_iter(&iter, &l);
1497                 if (r < 0) {
1498                         if (r == -ENOMEM)
1499                                 goto oom;
1500
1501                         return bus_send_error_reply(connection, message, NULL, r);
1502                 }
1503
1504                 if (!dbus_message_iter_next(&iter) ||
1505                     bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, true) < 0 ||
1506                     bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &force, false) < 0) {
1507                         strv_free(l);
1508                         return bus_send_error_reply(connection, message, NULL, -EIO);
1509                 }
1510
1511                 if (streq(member, "EnableUnitFiles")) {
1512                         r = unit_file_enable(scope, runtime, NULL, l, force, &changes, &n_changes);
1513                         carries_install_info = r;
1514                 } else if (streq(member, "ReenableUnitFiles")) {
1515                         r = unit_file_reenable(scope, runtime, NULL, l, force, &changes, &n_changes);
1516                         carries_install_info = r;
1517                 } else if (streq(member, "LinkUnitFiles"))
1518                         r = unit_file_link(scope, runtime, NULL, l, force, &changes, &n_changes);
1519                 else if (streq(member, "PresetUnitFiles")) {
1520                         r = unit_file_preset(scope, runtime, NULL, l, force, &changes, &n_changes);
1521                         carries_install_info = r;
1522                 } else if (streq(member, "MaskUnitFiles"))
1523                         r = unit_file_mask(scope, runtime, NULL, l, force, &changes, &n_changes);
1524                 else
1525                         assert_not_reached("Uh? Wrong method");
1526
1527                 strv_free(l);
1528                 bus_manager_send_unit_files_changed(m);
1529
1530                 if (r < 0) {
1531                         unit_file_changes_free(changes, n_changes);
1532                         return bus_send_error_reply(connection, message, NULL, r);
1533                 }
1534
1535                 reply = message_from_file_changes(message, changes, n_changes, carries_install_info);
1536                 unit_file_changes_free(changes, n_changes);
1537
1538                 if (!reply)
1539                         goto oom;
1540
1541         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "DisableUnitFiles") ||
1542                    dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnmaskUnitFiles")) {
1543
1544                 char **l = NULL;
1545                 DBusMessageIter iter;
1546                 UnitFileScope scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
1547                 UnitFileChange *changes = NULL;
1548                 unsigned n_changes = 0;
1549                 dbus_bool_t runtime;
1550
1551                 SELINUX_ACCESS_CHECK(connection, message, streq(member, "UnmaskUnitFiles") ? "enable" : "disable");
1552
1553                 if (!dbus_message_iter_init(message, &iter))
1554                         goto oom;
1555
1556                 r = bus_parse_strv_iter(&iter, &l);
1557                 if (r < 0) {
1558                         if (r == -ENOMEM)
1559                                 goto oom;
1560
1561                         return bus_send_error_reply(connection, message, NULL, r);
1562                 }
1563
1564                 if (!dbus_message_iter_next(&iter) ||
1565                     bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, false) < 0) {
1566                         strv_free(l);
1567                         return bus_send_error_reply(connection, message, NULL, -EIO);
1568                 }
1569
1570                 if (streq(member, "DisableUnitFiles"))
1571                         r = unit_file_disable(scope, runtime, NULL, l, &changes, &n_changes);
1572                 else if (streq(member, "UnmaskUnitFiles"))
1573                         r = unit_file_unmask(scope, runtime, NULL, l, &changes, &n_changes);
1574                 else
1575                         assert_not_reached("Uh? Wrong method");
1576
1577                 strv_free(l);
1578                 bus_manager_send_unit_files_changed(m);
1579
1580                 if (r < 0) {
1581                         unit_file_changes_free(changes, n_changes);
1582                         return bus_send_error_reply(connection, message, NULL, r);
1583                 }
1584
1585                 reply = message_from_file_changes(message, changes, n_changes, -1);
1586                 unit_file_changes_free(changes, n_changes);
1587
1588                 if (!reply)
1589                         goto oom;
1590
1591         } else {
1592                 const BusBoundProperties bps[] = {
1593                         { "org.freedesktop.systemd1.Manager", bus_systemd_properties, systemd_property_string },
1594                         { "org.freedesktop.systemd1.Manager", bus_manager_properties, m },
1595                         { NULL, }
1596                 };
1597
1598                 SELINUX_ACCESS_CHECK(connection, message, "status");
1599
1600                 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
1601         }
1602
1603         if (job_type != _JOB_TYPE_INVALID) {
1604                 const char *name, *smode, *old_name = NULL;
1605                 JobMode mode;
1606                 Unit *u;
1607                 dbus_bool_t b;
1608
1609                 if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnitReplace"))
1610                         b = dbus_message_get_args(
1611                                         message,
1612                                         &error,
1613                                         DBUS_TYPE_STRING, &old_name,
1614                                         DBUS_TYPE_STRING, &name,
1615                                         DBUS_TYPE_STRING, &smode,
1616                                         DBUS_TYPE_INVALID);
1617                 else
1618                         b = dbus_message_get_args(
1619                                         message,
1620                                         &error,
1621                                         DBUS_TYPE_STRING, &name,
1622                                         DBUS_TYPE_STRING, &smode,
1623                                         DBUS_TYPE_INVALID);
1624                 if (!b)
1625                         return bus_send_error_reply(connection, message, &error, -EINVAL);
1626
1627                 if (old_name) {
1628                         u = manager_get_unit(m, old_name);
1629                         if (!u || !u->job || u->job->type != JOB_START) {
1630                                 dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "No job queued for unit %s", old_name);
1631                                 return bus_send_error_reply(connection, message, &error, -ENOENT);
1632                         }
1633                 }
1634
1635                 mode = job_mode_from_string(smode);
1636                 if (mode < 0) {
1637                         dbus_set_error(&error, BUS_ERROR_INVALID_JOB_MODE, "Job mode %s is invalid.", smode);
1638                         return bus_send_error_reply(connection, message, &error, -EINVAL);
1639                 }
1640
1641                 r = manager_load_unit(m, name, NULL, &error, &u);
1642                 if (r < 0)
1643                         return bus_send_error_reply(connection, message, &error, r);
1644
1645                 return bus_unit_queue_job(connection, message, u, job_type, mode, reload_if_possible);
1646         }
1647
1648         if (reply)
1649                 if (!dbus_connection_send(connection, reply, NULL))
1650                         goto oom;
1651
1652         return DBUS_HANDLER_RESULT_HANDLED;
1653
1654 oom:
1655         dbus_error_free(&error);
1656
1657         return DBUS_HANDLER_RESULT_NEED_MEMORY;
1658 }
1659
1660 const DBusObjectPathVTable bus_manager_vtable = {
1661         .message_function = bus_manager_message_handler
1662 };