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