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