]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/dbus-manager.c
core: correct dbus parameter direction
[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" \
459da00f 239 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
8e2af478
LP
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 278 " </signal>" \
71445ae7
LP
279 " <signal name=\"UnitFilesChanged\"/>\n" \
280 " <signal name=\"Reloading\">\n" \
281 " <arg name=\"active\" type=\"b\"/>\n" \
282 " </signal>"
07459bb6 283
07459bb6 284#define BUS_MANAGER_INTERFACE_PROPERTIES_GENERAL \
4288f619 285 " <property name=\"Version\" type=\"s\" access=\"read\"/>\n" \
c5d34390
LP
286 " <property name=\"Features\" type=\"s\" access=\"read\"/>\n" \
287 " <property name=\"Tainted\" type=\"s\" access=\"read\"/>\n" \
915b3753
LP
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" \
e9ddabc2 294 " <property name=\"InitRDTimestamp\" type=\"t\" access=\"read\"/>\n" \
b21a0ef8 295 " <property name=\"InitRDTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
915b3753
LP
296 " <property name=\"UserspaceTimestamp\" type=\"t\" access=\"read\"/>\n" \
297 " <property name=\"UserspaceTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
e9ddabc2 298 " <property name=\"FinishTimestamp\" type=\"t\" access=\"read\"/>\n" \
b21a0ef8 299 " <property name=\"FinishTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
518d10e9
UTL
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" \
d9acfb71
TA
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" \
c826cda4
AB
308 " <property name=\"LogLevel\" type=\"s\" access=\"readwrite\"/>\n" \
309 " <property name=\"LogTarget\" type=\"s\" access=\"readwrite\"/>\n" \
4288f619
LP
310 " <property name=\"NNames\" type=\"u\" access=\"read\"/>\n" \
311 " <property name=\"NJobs\" type=\"u\" access=\"read\"/>\n" \
e409f875 312 " <property name=\"NInstalledJobs\" type=\"u\" access=\"read\"/>\n" \
76bf48b7 313 " <property name=\"NFailedJobs\" type=\"u\" access=\"read\"/>\n" \
fa70128d 314 " <property name=\"Progress\" type=\"d\" access=\"read\"/>\n" \
4288f619 315 " <property name=\"Environment\" type=\"as\" access=\"read\"/>\n" \
f295f5c0 316 " <property name=\"ConfirmSpawn\" type=\"b\" access=\"read\"/>\n" \
9e58ff9c 317 " <property name=\"ShowStatus\" type=\"b\" access=\"read\"/>\n" \
f295f5c0 318 " <property name=\"UnitPath\" type=\"as\" access=\"read\"/>\n" \
0a494f1f
LP
319 " <property name=\"DefaultControllers\" type=\"as\" access=\"read\"/>\n" \
320 " <property name=\"DefaultStandardOutput\" type=\"s\" access=\"read\"/>\n" \
e96d6be7 321 " <property name=\"DefaultStandardError\" type=\"s\" access=\"read\"/>\n" \
d4b7fecb
RC
322 " <property name=\"RuntimeWatchdogUSec\" type=\"t\" access=\"readwrite\"/>\n" \
323 " <property name=\"ShutdownWatchdogUSec\" type=\"t\" access=\"readwrite\"/>\n" \
dfae3488 324 " <property name=\"Virtualization\" type=\"s\" access=\"read\"/>\n"
07459bb6 325
07459bb6 326#define BUS_MANAGER_INTERFACE_END \
4288f619
LP
327 " </interface>\n"
328
07459bb6
FF
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 \
07459bb6
FF
334 BUS_MANAGER_INTERFACE_END
335
ea430986
LP
336#define INTROSPECTION_BEGIN \
337 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
4288f619
LP
338 "<node>\n" \
339 BUS_MANAGER_INTERFACE \
ea430986 340 BUS_PROPERTIES_INTERFACE \
c4e2ceae 341 BUS_PEER_INTERFACE \
ea430986
LP
342 BUS_INTROSPECTABLE_INTERFACE
343
344#define INTROSPECTION_END \
4288f619
LP
345 "</node>\n"
346
05feefe0
LP
347#define INTERFACES_LIST \
348 BUS_GENERIC_INTERFACES_LIST \
349 "org.freedesktop.systemd1.Manager\0"
350
9a60da28 351const char bus_manager_interface[] _introspect_("Manager") = BUS_MANAGER_INTERFACE;
ea430986 352
0a494f1f 353static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_exec_output, exec_output, ExecOutput);
1adf1049 354
bfebab7f 355static int bus_manager_append_tainted(DBusMessageIter *i, const char *property, void *data) {
c5d34390 356 const char *t;
bfebab7f 357 Manager *m = data;
20c03b7b 358 char buf[LINE_MAX] = "", *e = buf, *p = NULL;
c5d34390 359
c5d34390
LP
360 assert(i);
361 assert(property);
bfebab7f 362 assert(m);
c5d34390 363
72bc8d00 364 if (m->taint_usr)
e677bf7e 365 e = stpcpy(e, "split-usr:");
c5d34390 366
871c44a7 367 if (readlink_malloc("/etc/mtab", &p) < 0)
e677bf7e 368 e = stpcpy(e, "mtab-not-symlink:");
871c44a7 369 else
c5d34390
LP
370 free(p);
371
871c44a7 372 if (access("/proc/cgroups", F_OK) < 0)
1ebf0cb7 373 e = stpcpy(e, "cgroups-missing:");
871c44a7 374
e677bf7e 375 if (hwclock_is_localtime() > 0)
1ebf0cb7 376 e = stpcpy(e, "local-hwclock:");
e677bf7e 377
1ebf0cb7
MS
378 /* remove the last ':' */
379 if (e != buf)
380 e[-1] = 0;
e677bf7e
LP
381
382 t = buf;
c5d34390
LP
383
384 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
385 return -ENOMEM;
386
387 return 0;
388}
389
bfebab7f 390static int bus_manager_append_log_target(DBusMessageIter *i, const char *property, void *data) {
1adf1049
LP
391 const char *t;
392
1adf1049
LP
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
9612f07c 404static int bus_manager_set_log_target(DBusMessageIter *i, const char *property, void *data) {
c826cda4
AB
405 const char *t;
406
c826cda4
AB
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
bfebab7f 415static int bus_manager_append_log_level(DBusMessageIter *i, const char *property, void *data) {
f8b69d1d
MS
416 char *t;
417 int r;
1adf1049 418
1adf1049
LP
419 assert(i);
420 assert(property);
421
f8b69d1d
MS
422 r = log_level_to_string_alloc(log_get_max_level(), &t);
423 if (r < 0)
424 return r;
1adf1049
LP
425
426 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
f8b69d1d 427 r = -ENOMEM;
1adf1049 428
f8b69d1d
MS
429 free(t);
430 return r;
1adf1049
LP
431}
432
9612f07c 433static int bus_manager_set_log_level(DBusMessageIter *i, const char *property, void *data) {
c826cda4
AB
434 const char *t;
435
c826cda4
AB
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
bfebab7f
LP
444static int bus_manager_append_n_names(DBusMessageIter *i, const char *property, void *data) {
445 Manager *m = data;
4f0f902f
LP
446 uint32_t u;
447
4f0f902f
LP
448 assert(i);
449 assert(property);
bfebab7f 450 assert(m);
4f0f902f
LP
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
bfebab7f
LP
460static int bus_manager_append_n_jobs(DBusMessageIter *i, const char *property, void *data) {
461 Manager *m = data;
4f0f902f
LP
462 uint32_t u;
463
4f0f902f
LP
464 assert(i);
465 assert(property);
bfebab7f 466 assert(m);
4f0f902f
LP
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
bfebab7f 476static int bus_manager_append_progress(DBusMessageIter *i, const char *property, void *data) {
05d6a3b6 477 double d;
bfebab7f 478 Manager *m = data;
05d6a3b6 479
05d6a3b6
LP
480 assert(i);
481 assert(property);
bfebab7f 482 assert(m);
05d6a3b6
LP
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
dfae3488
LP
495static 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
729e3769
LP
511static DBusMessage *message_from_file_changes(
512 DBusMessage *m,
513 UnitFileChange *changes,
514 unsigned n_changes,
515 int carries_install_info) {
516
c0576cd6
LP
517 DBusMessageIter iter, sub, sub2;
518 DBusMessage *reply;
519 unsigned i;
520
c0576cd6
LP
521 reply = dbus_message_new_method_return(m);
522 if (!reply)
523 return NULL;
524
525 dbus_message_iter_init_append(reply, &iter);
526
729e3769
LP
527 if (carries_install_info >= 0) {
528 dbus_bool_t b;
529
e191553d 530 b = !!carries_install_info;
729e3769
LP
531 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b))
532 goto oom;
533 }
534
c0576cd6
LP
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) ||
729e3769
LP
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) ||
c0576cd6
LP
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
558oom:
559 dbus_message_unref(reply);
560 return NULL;
561}
562
563static 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
c757a65b
LP
577static 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
e96d6be7
LP
588static const char systemd_property_string[] =
589 PACKAGE_STRING "\0"
e96d6be7 590 SYSTEMD_FEATURES;
d200735e
MS
591
592static const BusProperty bus_systemd_properties[] = {
bc270841
LP
593 { "Version", bus_property_append_string, "s", 0 },
594 { "Features", bus_property_append_string, "s", sizeof(PACKAGE_STRING) },
d200735e
MS
595 { NULL, }
596};
597
598static const BusProperty bus_manager_properties[] = {
dfae3488
LP
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) },
518d10e9
UTL
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) },
d9acfb71
TA
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) },
dfae3488
LP
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 },
dfae3488
LP
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, },
d200735e
MS
636 { NULL, }
637};
638
639static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, DBusMessage *message, void *data) {
cad45ba1
LP
640 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
641 _cleanup_free_ char * path = NULL;
d200735e 642 Manager *m = data;
1adf1049 643 int r;
ea430986 644 DBusError error;
c87eba54 645 JobType job_type = _JOB_TYPE_INVALID;
6f28c033 646 bool reload_if_possible = false;
c0576cd6 647 const char *member;
ea430986
LP
648
649 assert(connection);
650 assert(message);
651 assert(m);
652
653 dbus_error_init(&error);
654
c0576cd6
LP
655 member = dbus_message_get_member(message);
656
4139c1b2 657 if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnit")) {
ea430986
LP
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))
bfebab7f 666 return bus_send_error_reply(connection, message, &error, -EINVAL);
ea430986 667
cad45ba1
LP
668 u = manager_get_unit(m, name);
669 if (!u) {
398ef8ba 670 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
bfebab7f 671 return bus_send_error_reply(connection, message, &error, -ENOENT);
398ef8ba 672 }
ea430986 673
cad45ba1
LP
674 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status");
675
676 reply = dbus_message_new_method_return(message);
677 if (!reply)
ea430986
LP
678 goto oom;
679
cad45ba1
LP
680 path = unit_dbus_path(u);
681 if (!path)
ea430986
LP
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;
598b557b 689 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnitByPID")) {
598b557b
LP
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))
bfebab7f 698 return bus_send_error_reply(connection, message, &error, -EINVAL);
598b557b 699
4ad49000 700 u = manager_get_unit_by_pid(m, (pid_t) pid);
cad45ba1 701 if (!u) {
598b557b 702 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "No unit for PID %lu is loaded.", (unsigned long) pid);
bfebab7f 703 return bus_send_error_reply(connection, message, &error, -ENOENT);
598b557b
LP
704 }
705
cad45ba1
LP
706 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status");
707
708 reply = dbus_message_new_method_return(message);
709 if (!reply)
598b557b
LP
710 goto oom;
711
cad45ba1 712 path = unit_dbus_path(u);
b3c2cf3d 713 if (!path)
598b557b 714 goto oom;
ea430986 715
598b557b
LP
716 if (!dbus_message_append_args(
717 reply,
718 DBUS_TYPE_OBJECT_PATH, &path,
719 DBUS_TYPE_INVALID))
720 goto oom;
4139c1b2 721 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "LoadUnit")) {
ea430986
LP
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))
bfebab7f 730 return bus_send_error_reply(connection, message, &error, -EINVAL);
ea430986 731
cad45ba1
LP
732 r = manager_load_unit(m, name, NULL, &error, &u);
733 if (r < 0)
bfebab7f 734 return bus_send_error_reply(connection, message, &error, r);
ea430986 735
cad45ba1
LP
736 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status");
737
738 reply = dbus_message_new_method_return(message);
739 if (!reply)
ea430986
LP
740 goto oom;
741
cad45ba1
LP
742 path = unit_dbus_path(u);
743 if (!path)
ea430986
LP
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
c87eba54
LP
752 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnit"))
753 job_type = JOB_START;
90bb85e1
LP
754 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnitReplace"))
755 job_type = JOB_START;
c87eba54
LP
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;
9a1ac7b9
LP
762 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "TryRestartUnit"))
763 job_type = JOB_TRY_RESTART;
6f28c033
LP
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;
8a0867d6 770 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "KillUnit")) {
c74f17d9 771 const char *name, *swho;
8a0867d6
LP
772 int32_t signo;
773 Unit *u;
8a0867d6
LP
774 KillWho who;
775
776 if (!dbus_message_get_args(
777 message,
778 &error,
779 DBUS_TYPE_STRING, &name,
780 DBUS_TYPE_STRING, &swho,
8a0867d6
LP
781 DBUS_TYPE_INT32, &signo,
782 DBUS_TYPE_INVALID))
bfebab7f 783 return bus_send_error_reply(connection, message, &error, -EINVAL);
8a0867d6 784
0a524ba7
LP
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
0a524ba7 793 if (signo <= 0 || signo >= _NSIG)
bfebab7f 794 return bus_send_error_reply(connection, message, &error, -EINVAL);
8a0867d6 795
c74f17d9
LP
796 u = manager_get_unit(m, name);
797 if (!u) {
8a0867d6 798 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
bfebab7f 799 return bus_send_error_reply(connection, message, &error, -ENOENT);
8a0867d6
LP
800 }
801
cad45ba1
LP
802 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "stop");
803
c74f17d9
LP
804 r = unit_kill(u, who, signo, &error);
805 if (r < 0)
bfebab7f 806 return bus_send_error_reply(connection, message, &error, r);
8a0867d6 807
f72daa64
ZJS
808 reply = dbus_message_new_method_return(message);
809 if (!reply)
8a0867d6
LP
810 goto oom;
811
6f28c033 812 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetJob")) {
ea430986
LP
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))
bfebab7f 821 return bus_send_error_reply(connection, message, &error, -EINVAL);
ea430986 822
cad45ba1
LP
823 j = manager_get_job(m, id);
824 if (!j) {
398ef8ba 825 dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "Job %u does not exist.", (unsigned) id);
bfebab7f 826 return bus_send_error_reply(connection, message, &error, -ENOENT);
398ef8ba 827 }
ea430986 828
cad45ba1
LP
829 SELINUX_UNIT_ACCESS_CHECK(j->unit, connection, message, "status");
830
831 reply = dbus_message_new_method_return(message);
832 if (!reply)
ea430986
LP
833 goto oom;
834
cad45ba1
LP
835 path = job_dbus_path(j);
836 if (!path)
ea430986
LP
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
5dd9014f
LP
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
4139c1b2 869 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ClearJobs")) {
ea430986 870
ffc227c9 871 SELINUX_ACCESS_CHECK(connection, message, "reboot");
ea430986
LP
872 manager_clear_jobs(m);
873
cad45ba1
LP
874 reply = dbus_message_new_method_return(message);
875 if (!reply)
ea430986
LP
876 goto oom;
877
fdf20a31 878 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ResetFailed")) {
5632e374 879
ffc227c9 880 SELINUX_ACCESS_CHECK(connection, message, "reload");
cad45ba1 881
fdf20a31 882 manager_reset_failed(m);
5632e374 883
cad45ba1
LP
884 reply = dbus_message_new_method_return(message);
885 if (!reply)
5632e374
LP
886 goto oom;
887
fdf20a31 888 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ResetFailedUnit")) {
5632e374
LP
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))
bfebab7f 897 return bus_send_error_reply(connection, message, &error, -EINVAL);
5632e374 898
cad45ba1
LP
899 u = manager_get_unit(m, name);
900 if (!u) {
5632e374 901 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
bfebab7f 902 return bus_send_error_reply(connection, message, &error, -ENOENT);
5632e374
LP
903 }
904
cad45ba1
LP
905 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "reload");
906
fdf20a31 907 unit_reset_failed(u);
5632e374 908
cad45ba1 909 reply = dbus_message_new_method_return(message);
246aa6dd
LP
910 if (!reply)
911 goto oom;
912
4139c1b2 913 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnits")) {
ea430986
LP
914 DBusMessageIter iter, sub;
915 Iterator i;
916 Unit *u;
917 const char *k;
918
ffc227c9 919 SELINUX_ACCESS_CHECK(connection, message, "status");
cad45ba1
LP
920
921 reply = dbus_message_new_method_return(message);
922 if (!reply)
ea430986
LP
923 goto oom;
924
925 dbus_message_iter_init_append(reply, &iter);
926
8fe914ec 927 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssssouso)", &sub))
ea430986
LP
928 goto oom;
929
930 HASHMAP_FOREACH_KEY(u, k, m->units, i) {
47be870b 931 char *u_path, *j_path;
8fe914ec 932 const char *description, *load_state, *active_state, *sub_state, *sjob_type, *following;
ea430986
LP
933 DBusMessageIter sub2;
934 uint32_t job_id;
a7f241db 935 Unit *f;
ea430986 936
ac155bb8 937 if (k != u->id)
ea430986
LP
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);
ac155bb8 944 load_state = unit_load_state_to_string(u->load_state);
ea430986 945 active_state = unit_active_state_to_string(unit_active_state(u));
10a94420 946 sub_state = unit_sub_state_to_string(u);
a7f241db
LP
947
948 f = unit_following(u);
ac155bb8 949 following = f ? f->id : "";
ea430986 950
cad45ba1
LP
951 u_path = unit_dbus_path(u);
952 if (!u_path)
ea430986
LP
953 goto oom;
954
ac155bb8
MS
955 if (u->job) {
956 job_id = (uint32_t) u->job->id;
ea430986 957
ac155bb8 958 if (!(j_path = job_dbus_path(u->job))) {
47be870b 959 free(u_path);
ea430986
LP
960 goto oom;
961 }
962
ac155bb8 963 sjob_type = job_type_to_string(u->job->type);
ea430986
LP
964 } else {
965 job_id = 0;
47be870b 966 j_path = u_path;
c87eba54 967 sjob_type = "";
ea430986
LP
968 }
969
ac155bb8 970 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &u->id) ||
ea430986
LP
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) ||
10a94420 974 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &sub_state) ||
8fe914ec 975 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &following) ||
47be870b 976 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &u_path) ||
ea430986 977 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &job_id) ||
c87eba54 978 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &sjob_type) ||
47be870b
LP
979 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &j_path)) {
980 free(u_path);
ac155bb8 981 if (u->job)
47be870b 982 free(j_path);
ea430986
LP
983 goto oom;
984 }
985
47be870b 986 free(u_path);
ac155bb8 987 if (u->job)
47be870b 988 free(j_path);
ea430986
LP
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
4139c1b2 997 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListJobs")) {
ea430986
LP
998 DBusMessageIter iter, sub;
999 Iterator i;
1000 Job *j;
1001
ffc227c9 1002 SELINUX_ACCESS_CHECK(connection, message, "status");
cad45ba1
LP
1003
1004 reply = dbus_message_new_method_return(message);
1005 if (!reply)
ea430986
LP
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) {
47be870b 1014 char *u_path, *j_path;
9e2f7c11 1015 const char *state, *type;
ea430986
LP
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;
ea430986 1023 state = job_state_to_string(j->state);
2b53c70b 1024 type = job_type_to_string(j->type);
ea430986 1025
cad45ba1
LP
1026 j_path = job_dbus_path(j);
1027 if (!j_path)
ea430986
LP
1028 goto oom;
1029
cad45ba1
LP
1030 u_path = unit_dbus_path(j->unit);
1031 if (!u_path) {
47be870b 1032 free(j_path);
ea430986
LP
1033 goto oom;
1034 }
1035
1036 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &id) ||
ac155bb8 1037 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &j->unit->id) ||
ea430986
LP
1038 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &type) ||
1039 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &state) ||
47be870b
LP
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);
ea430986
LP
1044 goto oom;
1045 }
1046
47be870b
LP
1047 free(j_path);
1048 free(u_path);
ea430986
LP
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
4139c1b2 1057 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Subscribe")) {
c1e1601e 1058 char *client;
a567261a
LP
1059 Set *s;
1060
ffc227c9 1061 SELINUX_ACCESS_CHECK(connection, message, "status");
cad45ba1 1062
6fa48533
LP
1063 s = bus_acquire_subscribed(m, connection);
1064 if (!s)
1065 goto oom;
c1e1601e 1066
cad45ba1
LP
1067 client = strdup(bus_message_get_sender_with_fallback(message));
1068 if (!client)
c1e1601e
LP
1069 goto oom;
1070
ef42202a
ZJS
1071 r = set_consume(s, client);
1072 if (r < 0)
bfebab7f 1073 return bus_send_error_reply(connection, message, NULL, r);
c1e1601e 1074
cad45ba1
LP
1075 reply = dbus_message_new_method_return(message);
1076 if (!reply)
c1e1601e
LP
1077 goto oom;
1078
4139c1b2 1079 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Unsubscribe")) {
c1e1601e
LP
1080 char *client;
1081
ffc227c9 1082 SELINUX_ACCESS_CHECK(connection, message, "status");
cad45ba1
LP
1083
1084 client = set_remove(BUS_CONNECTION_SUBSCRIBED(m, connection), (char*) bus_message_get_sender_with_fallback(message));
1085 if (!client) {
398ef8ba 1086 dbus_set_error(&error, BUS_ERROR_NOT_SUBSCRIBED, "Client is not subscribed.");
bfebab7f 1087 return bus_send_error_reply(connection, message, &error, -ENOENT);
398ef8ba 1088 }
c1e1601e
LP
1089
1090 free(client);
1091
cad45ba1
LP
1092 reply = dbus_message_new_method_return(message);
1093 if (!reply)
c1e1601e
LP
1094 goto oom;
1095
4139c1b2 1096 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Dump")) {
b152adec
LP
1097 FILE *f;
1098 char *dump = NULL;
1099 size_t size;
1100
ffc227c9 1101 SELINUX_ACCESS_CHECK(connection, message, "status");
cad45ba1
LP
1102
1103 reply = dbus_message_new_method_return(message);
1104 if (!reply)
b152adec
LP
1105 goto oom;
1106
cad45ba1
LP
1107 f = open_memstream(&dump, &size);
1108 if (!f)
b152adec
LP
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);
4139c1b2
LP
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
ffc227c9 1133 SELINUX_ACCESS_CHECK(connection, message, "start");
cad45ba1 1134
4139c1b2
LP
1135 if (!dbus_message_get_args(
1136 message,
1137 &error,
1138 DBUS_TYPE_STRING, &name,
1139 DBUS_TYPE_BOOLEAN, &cleanup,
1140 DBUS_TYPE_INVALID))
bfebab7f 1141 return bus_send_error_reply(connection, message, &error, -EINVAL);
4139c1b2 1142
cad45ba1 1143 if (isempty(name))
4139c1b2
LP
1144 name = NULL;
1145
cad45ba1
LP
1146 r = snapshot_create(m, name, cleanup, &error, &s);
1147 if (r < 0)
bfebab7f 1148 return bus_send_error_reply(connection, message, &error, r);
4139c1b2 1149
cad45ba1
LP
1150 reply = dbus_message_new_method_return(message);
1151 if (!reply)
4139c1b2
LP
1152 goto oom;
1153
cad45ba1
LP
1154 path = unit_dbus_path(UNIT(s));
1155 if (!path)
4139c1b2
LP
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;
b152adec 1163
5dd9014f
LP
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
ea430986
LP
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
ffc227c9 1202 SELINUX_ACCESS_CHECK(connection, message, "status");
cad45ba1
LP
1203
1204 reply = dbus_message_new_method_return(message);
1205 if (!reply)
ea430986
LP
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
cad45ba1
LP
1213 f = open_memstream(&introspection, &size);
1214 if (!f)
ea430986
LP
1215 goto oom;
1216
1217 fputs(INTROSPECTION_BEGIN, f);
1218
1219 HASHMAP_FOREACH_KEY(u, k, m->units, i) {
1220 char *p;
1221
ac155bb8 1222 if (k != u->id)
ea430986
LP
1223 continue;
1224
cad45ba1
LP
1225 p = bus_path_escape(k);
1226 if (!p) {
ea430986
LP
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
a16e1123
LP
1259 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reload")) {
1260
ffc227c9 1261 SELINUX_ACCESS_CHECK(connection, message, "reload");
cad45ba1 1262
a16e1123
LP
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
cad45ba1
LP
1270 m->queued_message = dbus_message_new_method_return(message);
1271 if (!m->queued_message)
a16e1123
LP
1272 goto oom;
1273
7b97f477 1274 m->queued_message_connection = connection;
a16e1123
LP
1275 m->exit_code = MANAGER_RELOAD;
1276
1277 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reexecute")) {
1278
ffc227c9 1279 SELINUX_ACCESS_CHECK(connection, message, "reload");
cad45ba1 1280
b23de6af
LP
1281 /* We don't send a reply back here, the client should
1282 * just wait for us disconnecting. */
a16e1123
LP
1283
1284 m->exit_code = MANAGER_REEXECUTE;
1285
1286 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Exit")) {
1287
ffc227c9 1288 SELINUX_ACCESS_CHECK(connection, message, "halt");
cad45ba1 1289
67445f4e 1290 if (m->running_as == SYSTEMD_SYSTEM) {
af2d49f7 1291 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Exit is only supported for user service managers.");
bfebab7f 1292 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
398ef8ba 1293 }
a16e1123 1294
cad45ba1
LP
1295 reply = dbus_message_new_method_return(message);
1296 if (!reply)
a16e1123
LP
1297 goto oom;
1298
1299 m->exit_code = MANAGER_EXIT;
1300
6652a2b9
LP
1301 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reboot")) {
1302
ffc227c9 1303 SELINUX_ACCESS_CHECK(connection, message, "reboot");
cad45ba1 1304
67445f4e 1305 if (m->running_as != SYSTEMD_SYSTEM) {
6652a2b9 1306 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Reboot is only supported for system managers.");
bfebab7f 1307 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
6652a2b9
LP
1308 }
1309
cad45ba1
LP
1310 reply = dbus_message_new_method_return(message);
1311 if (!reply)
6652a2b9
LP
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
ffc227c9 1318 SELINUX_ACCESS_CHECK(connection, message, "halt");
cad45ba1 1319
67445f4e 1320 if (m->running_as != SYSTEMD_SYSTEM) {
6652a2b9 1321 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Powering off is only supported for system managers.");
bfebab7f 1322 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
6652a2b9
LP
1323 }
1324
cad45ba1
LP
1325 reply = dbus_message_new_method_return(message);
1326 if (!reply)
6652a2b9
LP
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
ffc227c9 1333 SELINUX_ACCESS_CHECK(connection, message, "halt");
cad45ba1 1334
67445f4e 1335 if (m->running_as != SYSTEMD_SYSTEM) {
6652a2b9 1336 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Halting is only supported for system managers.");
bfebab7f 1337 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
6652a2b9
LP
1338 }
1339
cad45ba1
LP
1340 reply = dbus_message_new_method_return(message);
1341 if (!reply)
6652a2b9
LP
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
ffc227c9 1348 SELINUX_ACCESS_CHECK(connection, message, "reboot");
cad45ba1 1349
67445f4e 1350 if (m->running_as != SYSTEMD_SYSTEM) {
6652a2b9 1351 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "kexec is only supported for system managers.");
bfebab7f 1352 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
6652a2b9
LP
1353 }
1354
cad45ba1
LP
1355 reply = dbus_message_new_method_return(message);
1356 if (!reply)
6652a2b9
LP
1357 goto oom;
1358
1359 m->exit_code = MANAGER_KEXEC;
1360
664f88a7
LP
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;
66060897 1364 bool good;
664f88a7 1365
ffc227c9 1366 SELINUX_ACCESS_CHECK(connection, message, "reboot");
cad45ba1 1367
664f88a7
LP
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
ee83acc4 1376 if (path_equal(switch_root, "/") || !path_is_absolute(switch_root))
664f88a7
LP
1377 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1378
ee83acc4 1379 if (!isempty(switch_root_init) && !path_is_absolute(switch_root_init))
664f88a7
LP
1380 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1381
67445f4e 1382 if (m->running_as != SYSTEMD_SYSTEM) {
664f88a7
LP
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
50913bc0 1387 /* Safety check */
17f5e457 1388 if (isempty(switch_root_init)) {
66060897 1389 good = path_is_os_tree(switch_root);
17f5e457
HH
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 }
50913bc0 1393 else {
66060897 1394 _cleanup_free_ char *p = NULL;
50913bc0 1395
b7def684 1396 p = strjoin(switch_root, "/", switch_root_init, NULL);
50913bc0
LP
1397 if (!p)
1398 goto oom;
1399
66060897 1400 good = access(p, X_OK) >= 0;
17f5e457
HH
1401 if (!good)
1402 log_error("Not switching root: cannot execute new init %s", p);
50913bc0 1403 }
66060897
LP
1404 if (!good)
1405 return bus_send_error_reply(connection, message, NULL, -EINVAL);
50913bc0 1406
664f88a7
LP
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
1137a57c 1431 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetEnvironment")) {
123b964a
LP
1432 _cleanup_strv_free_ char **l = NULL;
1433 char **e = NULL;
1137a57c 1434
ffc227c9 1435 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1137a57c 1436
cad45ba1
LP
1437 r = bus_parse_strv(message, &l);
1438 if (r == -ENOMEM)
1439 goto oom;
1440 if (r < 0)
bfebab7f 1441 return bus_send_error_reply(connection, message, NULL, r);
123b964a
LP
1442 if (!strv_env_is_valid(l))
1443 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1137a57c 1444
5b6319dc 1445 e = strv_env_merge(2, m->environment, l);
1137a57c
LP
1446 if (!e)
1447 goto oom;
1448
cad45ba1
LP
1449 reply = dbus_message_new_method_return(message);
1450 if (!reply) {
1137a57c
LP
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")) {
123b964a
LP
1459 _cleanup_strv_free_ char **l = NULL;
1460 char **e = NULL;
1137a57c 1461
ffc227c9 1462 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1137a57c 1463
cad45ba1
LP
1464 r = bus_parse_strv(message, &l);
1465 if (r == -ENOMEM)
1466 goto oom;
1467 if (r < 0)
bfebab7f 1468 return bus_send_error_reply(connection, message, NULL, r);
123b964a
LP
1469 if (!strv_env_name_or_assignment_is_valid(l))
1470 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1137a57c 1471
5b6319dc 1472 e = strv_env_delete(m->environment, 1, l);
1137a57c
LP
1473 if (!e)
1474 goto oom;
1475
f72daa64
ZJS
1476 reply = dbus_message_new_method_return(message);
1477 if (!reply) {
da19d5c1 1478 strv_free(e);
1137a57c 1479 goto oom;
da19d5c1 1480 }
1137a57c
LP
1481
1482 strv_free(m->environment);
1483 m->environment = e;
1484
8d0e38a2 1485 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetAndSetEnvironment")) {
123b964a
LP
1486 _cleanup_strv_free_ char **l_set = NULL, **l_unset = NULL, **e = NULL;
1487 char **f = NULL;
8d0e38a2
LP
1488 DBusMessageIter iter;
1489
ffc227c9 1490 SELINUX_ACCESS_CHECK(connection, message, "reboot");
cad45ba1 1491
8d0e38a2 1492 if (!dbus_message_iter_init(message, &iter))
c0576cd6 1493 goto oom;
8d0e38a2
LP
1494
1495 r = bus_parse_strv_iter(&iter, &l_unset);
cad45ba1
LP
1496 if (r == -ENOMEM)
1497 goto oom;
1498 if (r < 0)
8d0e38a2 1499 return bus_send_error_reply(connection, message, NULL, r);
123b964a
LP
1500 if (!strv_env_name_or_assignment_is_valid(l_unset))
1501 return bus_send_error_reply(connection, message, NULL, -EINVAL);
8d0e38a2 1502
123b964a 1503 if (!dbus_message_iter_next(&iter))
8d0e38a2 1504 return bus_send_error_reply(connection, message, NULL, -EINVAL);
8d0e38a2
LP
1505
1506 r = bus_parse_strv_iter(&iter, &l_set);
123b964a
LP
1507 if (r == -ENOMEM)
1508 goto oom;
1509 if (r < 0)
8d0e38a2 1510 return bus_send_error_reply(connection, message, NULL, r);
123b964a
LP
1511 if (!strv_env_is_valid(l_set))
1512 return bus_send_error_reply(connection, message, NULL, -EINVAL);
8d0e38a2
LP
1513
1514 e = strv_env_delete(m->environment, 1, l_unset);
123b964a 1515 if (!e)
8d0e38a2 1516 goto oom;
8d0e38a2
LP
1517
1518 f = strv_env_merge(2, e, l_set);
8d0e38a2
LP
1519 if (!f)
1520 goto oom;
1521
f72daa64
ZJS
1522 reply = dbus_message_new_method_return(message);
1523 if (!reply) {
8d0e38a2
LP
1524 strv_free(f);
1525 goto oom;
1526 }
1527
1528 strv_free(m->environment);
1529 m->environment = f;
c0576cd6
LP
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
ffc227c9 1536 SELINUX_ACCESS_CHECK(connection, message, "status");
cad45ba1 1537
c0576cd6
LP
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
67445f4e 1546 r = unit_file_get_list(m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, h);
c0576cd6
LP
1547 if (r < 0) {
1548 unit_file_list_free(h);
c0576cd6
LP
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
ffc227c9 1584 SELINUX_ACCESS_CHECK(connection, message, "status");
cad45ba1 1585
c0576cd6
LP
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
67445f4e 1593 state = unit_file_get_state(m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, name);
c0576cd6
LP
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") ||
99504dd4
VP
1613 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "MaskUnitFiles") ||
1614 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetDefaultTarget")) {
c0576cd6
LP
1615
1616 char **l = NULL;
1617 DBusMessageIter iter;
67445f4e 1618 UnitFileScope scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
c0576cd6
LP
1619 UnitFileChange *changes = NULL;
1620 unsigned n_changes = 0;
1621 dbus_bool_t runtime, force;
835680f5 1622 int carries_install_info = -1;
c0576cd6 1623
ffc227c9 1624 SELINUX_ACCESS_CHECK(connection, message, streq(member, "MaskUnitFiles") ? "disable" : "enable");
cad45ba1 1625
c0576cd6
LP
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
729e3769 1644 if (streq(member, "EnableUnitFiles")) {
c0576cd6 1645 r = unit_file_enable(scope, runtime, NULL, l, force, &changes, &n_changes);
729e3769
LP
1646 carries_install_info = r;
1647 } else if (streq(member, "ReenableUnitFiles")) {
c0576cd6 1648 r = unit_file_reenable(scope, runtime, NULL, l, force, &changes, &n_changes);
729e3769
LP
1649 carries_install_info = r;
1650 } else if (streq(member, "LinkUnitFiles"))
c0576cd6 1651 r = unit_file_link(scope, runtime, NULL, l, force, &changes, &n_changes);
729e3769 1652 else if (streq(member, "PresetUnitFiles")) {
c0576cd6 1653 r = unit_file_preset(scope, runtime, NULL, l, force, &changes, &n_changes);
729e3769
LP
1654 carries_install_info = r;
1655 } else if (streq(member, "MaskUnitFiles"))
c0576cd6 1656 r = unit_file_mask(scope, runtime, NULL, l, force, &changes, &n_changes);
99504dd4
VP
1657 else if (streq(member, "SetDefaultTarget"))
1658 r = unit_file_set_default(scope, NULL, l[0], &changes, &n_changes);
c0576cd6
LP
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
729e3769 1670 reply = message_from_file_changes(message, changes, n_changes, carries_install_info);
c0576cd6
LP
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;
67445f4e 1681 UnitFileScope scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
c0576cd6
LP
1682 UnitFileChange *changes = NULL;
1683 unsigned n_changes = 0;
1684 dbus_bool_t runtime;
1685
ffc227c9 1686 SELINUX_ACCESS_CHECK(connection, message, streq(member, "UnmaskUnitFiles") ? "enable" : "disable");
cad45ba1 1687
c0576cd6
LP
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
729e3769 1720 reply = message_from_file_changes(message, changes, n_changes, -1);
c0576cd6
LP
1721 unit_file_changes_free(changes, n_changes);
1722
1723 if (!reply)
1724 goto oom;
8d0e38a2 1725
99504dd4
VP
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);
99504dd4
VP
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 }
8e2af478
LP
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
c2756a68 1763 r = bus_unit_set_properties(u, &iter, runtime ? UNIT_RUNTIME : UNIT_PERSISTENT, true, &error);
8e2af478
LP
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
c2756a68
LP
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
d200735e
MS
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 };
cad45ba1 1837
ffc227c9 1838 SELINUX_ACCESS_CHECK(connection, message, "status");
cad45ba1 1839
d200735e
MS
1840 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
1841 }
ea430986 1842
c87eba54 1843 if (job_type != _JOB_TYPE_INVALID) {
90bb85e1 1844 const char *name, *smode, *old_name = NULL;
c87eba54 1845 JobMode mode;
c87eba54 1846 Unit *u;
cad45ba1 1847 dbus_bool_t b;
90bb85e1
LP
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);
90bb85e1 1864 if (!b)
bfebab7f 1865 return bus_send_error_reply(connection, message, &error, -EINVAL);
c87eba54 1866
cad45ba1
LP
1867 if (old_name) {
1868 u = manager_get_unit(m, old_name);
1869 if (!u || !u->job || u->job->type != JOB_START) {
90bb85e1 1870 dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "No job queued for unit %s", old_name);
bfebab7f 1871 return bus_send_error_reply(connection, message, &error, -ENOENT);
90bb85e1 1872 }
cad45ba1 1873 }
90bb85e1 1874
cad45ba1
LP
1875 mode = job_mode_from_string(smode);
1876 if (mode < 0) {
398ef8ba 1877 dbus_set_error(&error, BUS_ERROR_INVALID_JOB_MODE, "Job mode %s is invalid.", smode);
bfebab7f 1878 return bus_send_error_reply(connection, message, &error, -EINVAL);
398ef8ba 1879 }
c87eba54 1880
cad45ba1
LP
1881 r = manager_load_unit(m, name, NULL, &error, &u);
1882 if (r < 0)
bfebab7f 1883 return bus_send_error_reply(connection, message, &error, r);
c87eba54 1884
cad45ba1 1885 return bus_unit_queue_job(connection, message, u, job_type, mode, reload_if_possible);
c87eba54
LP
1886 }
1887
cad45ba1 1888 if (reply)
c6a818c8 1889 if (!bus_maybe_send_reply(connection, message, reply))
ea430986
LP
1890 goto oom;
1891
ea430986
LP
1892 return DBUS_HANDLER_RESULT_HANDLED;
1893
1894oom:
ea430986
LP
1895 dbus_error_free(&error);
1896
1897 return DBUS_HANDLER_RESULT_NEED_MEMORY;
1898}
1899
1900const DBusObjectPathVTable bus_manager_vtable = {
1901 .message_function = bus_manager_message_handler
1902};