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