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