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