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