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