]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/dbus-manager.c
sd-journal: do not require path to be absolute
[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" \
c757a65b 293 " <property name=\"RuntimeWatchdogUSec\" type=\"s\" access=\"readwrite\"/>\n" \
dfae3488
LP
294 " <property name=\"ShutdownWatchdogUSec\" type=\"s\" access=\"readwrite\"/>\n" \
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
cad45ba1
LP
1189 r = set_put(s, client);
1190 if (r < 0) {
a567261a 1191 free(client);
bfebab7f 1192 return bus_send_error_reply(connection, message, NULL, r);
a567261a 1193 }
c1e1601e 1194
cad45ba1
LP
1195 reply = dbus_message_new_method_return(message);
1196 if (!reply)
c1e1601e
LP
1197 goto oom;
1198
4139c1b2 1199 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Unsubscribe")) {
c1e1601e
LP
1200 char *client;
1201
ffc227c9 1202 SELINUX_ACCESS_CHECK(connection, message, "status");
cad45ba1
LP
1203
1204 client = set_remove(BUS_CONNECTION_SUBSCRIBED(m, connection), (char*) bus_message_get_sender_with_fallback(message));
1205 if (!client) {
398ef8ba 1206 dbus_set_error(&error, BUS_ERROR_NOT_SUBSCRIBED, "Client is not subscribed.");
bfebab7f 1207 return bus_send_error_reply(connection, message, &error, -ENOENT);
398ef8ba 1208 }
c1e1601e
LP
1209
1210 free(client);
1211
cad45ba1
LP
1212 reply = dbus_message_new_method_return(message);
1213 if (!reply)
c1e1601e
LP
1214 goto oom;
1215
4139c1b2 1216 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Dump")) {
b152adec
LP
1217 FILE *f;
1218 char *dump = NULL;
1219 size_t size;
1220
ffc227c9 1221 SELINUX_ACCESS_CHECK(connection, message, "status");
cad45ba1
LP
1222
1223 reply = dbus_message_new_method_return(message);
1224 if (!reply)
b152adec
LP
1225 goto oom;
1226
cad45ba1
LP
1227 f = open_memstream(&dump, &size);
1228 if (!f)
b152adec
LP
1229 goto oom;
1230
1231 manager_dump_units(m, f, NULL);
1232 manager_dump_jobs(m, f, NULL);
1233
1234 if (ferror(f)) {
1235 fclose(f);
1236 free(dump);
1237 goto oom;
1238 }
1239
1240 fclose(f);
1241
1242 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &dump, DBUS_TYPE_INVALID)) {
1243 free(dump);
1244 goto oom;
1245 }
1246
1247 free(dump);
4139c1b2
LP
1248 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "CreateSnapshot")) {
1249 const char *name;
1250 dbus_bool_t cleanup;
1251 Snapshot *s;
1252
ffc227c9 1253 SELINUX_ACCESS_CHECK(connection, message, "start");
cad45ba1 1254
4139c1b2
LP
1255 if (!dbus_message_get_args(
1256 message,
1257 &error,
1258 DBUS_TYPE_STRING, &name,
1259 DBUS_TYPE_BOOLEAN, &cleanup,
1260 DBUS_TYPE_INVALID))
bfebab7f 1261 return bus_send_error_reply(connection, message, &error, -EINVAL);
4139c1b2 1262
cad45ba1 1263 if (isempty(name))
4139c1b2
LP
1264 name = NULL;
1265
cad45ba1
LP
1266 r = snapshot_create(m, name, cleanup, &error, &s);
1267 if (r < 0)
bfebab7f 1268 return bus_send_error_reply(connection, message, &error, r);
4139c1b2 1269
cad45ba1
LP
1270 reply = dbus_message_new_method_return(message);
1271 if (!reply)
4139c1b2
LP
1272 goto oom;
1273
cad45ba1
LP
1274 path = unit_dbus_path(UNIT(s));
1275 if (!path)
4139c1b2
LP
1276 goto oom;
1277
1278 if (!dbus_message_append_args(
1279 reply,
1280 DBUS_TYPE_OBJECT_PATH, &path,
1281 DBUS_TYPE_INVALID))
1282 goto oom;
b152adec 1283
5dd9014f
LP
1284 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "RemoveSnapshot")) {
1285 const char *name;
1286 Unit *u;
1287
1288 if (!dbus_message_get_args(
1289 message,
1290 &error,
1291 DBUS_TYPE_STRING, &name,
1292 DBUS_TYPE_INVALID))
1293 return bus_send_error_reply(connection, message, &error, -EINVAL);
1294
1295 u = manager_get_unit(m, name);
1296 if (!u) {
1297 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s does not exist.", name);
1298 return bus_send_error_reply(connection, message, &error, -ENOENT);
1299 }
1300
1301 if (u->type != UNIT_SNAPSHOT) {
1302 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not a snapshot.", name);
1303 return bus_send_error_reply(connection, message, &error, -ENOENT);
1304 }
1305
1306 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "stop");
1307 snapshot_remove(SNAPSHOT(u));
1308
1309 reply = dbus_message_new_method_return(message);
1310 if (!reply)
1311 goto oom;
1312
ea430986
LP
1313 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
1314 char *introspection = NULL;
1315 FILE *f;
1316 Iterator i;
1317 Unit *u;
1318 Job *j;
1319 const char *k;
1320 size_t size;
1321
ffc227c9 1322 SELINUX_ACCESS_CHECK(connection, message, "status");
cad45ba1
LP
1323
1324 reply = dbus_message_new_method_return(message);
1325 if (!reply)
ea430986
LP
1326 goto oom;
1327
1328 /* We roll our own introspection code here, instead of
1329 * relying on bus_default_message_handler() because we
1330 * need to generate our introspection string
1331 * dynamically. */
1332
cad45ba1
LP
1333 f = open_memstream(&introspection, &size);
1334 if (!f)
ea430986
LP
1335 goto oom;
1336
1337 fputs(INTROSPECTION_BEGIN, f);
1338
1339 HASHMAP_FOREACH_KEY(u, k, m->units, i) {
1340 char *p;
1341
ac155bb8 1342 if (k != u->id)
ea430986
LP
1343 continue;
1344
cad45ba1
LP
1345 p = bus_path_escape(k);
1346 if (!p) {
ea430986
LP
1347 fclose(f);
1348 free(introspection);
1349 goto oom;
1350 }
1351
1352 fprintf(f, "<node name=\"unit/%s\"/>", p);
1353 free(p);
1354 }
1355
1356 HASHMAP_FOREACH(j, m->jobs, i)
1357 fprintf(f, "<node name=\"job/%lu\"/>", (unsigned long) j->id);
1358
1359 fputs(INTROSPECTION_END, f);
1360
1361 if (ferror(f)) {
1362 fclose(f);
1363 free(introspection);
1364 goto oom;
1365 }
1366
1367 fclose(f);
1368
1369 if (!introspection)
1370 goto oom;
1371
1372 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
1373 free(introspection);
1374 goto oom;
1375 }
1376
1377 free(introspection);
1378
a16e1123
LP
1379 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reload")) {
1380
ffc227c9 1381 SELINUX_ACCESS_CHECK(connection, message, "reload");
cad45ba1 1382
a16e1123
LP
1383 assert(!m->queued_message);
1384
1385 /* Instead of sending the reply back right away, we
1386 * just remember that we need to and then send it
1387 * after the reload is finished. That way the caller
1388 * knows when the reload finished. */
1389
cad45ba1
LP
1390 m->queued_message = dbus_message_new_method_return(message);
1391 if (!m->queued_message)
a16e1123
LP
1392 goto oom;
1393
7b97f477 1394 m->queued_message_connection = connection;
a16e1123
LP
1395 m->exit_code = MANAGER_RELOAD;
1396
1397 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reexecute")) {
1398
ffc227c9 1399 SELINUX_ACCESS_CHECK(connection, message, "reload");
cad45ba1 1400
b23de6af
LP
1401 /* We don't send a reply back here, the client should
1402 * just wait for us disconnecting. */
a16e1123
LP
1403
1404 m->exit_code = MANAGER_REEXECUTE;
1405
1406 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Exit")) {
1407
ffc227c9 1408 SELINUX_ACCESS_CHECK(connection, message, "halt");
cad45ba1 1409
67445f4e 1410 if (m->running_as == SYSTEMD_SYSTEM) {
af2d49f7 1411 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Exit is only supported for user service managers.");
bfebab7f 1412 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
398ef8ba 1413 }
a16e1123 1414
cad45ba1
LP
1415 reply = dbus_message_new_method_return(message);
1416 if (!reply)
a16e1123
LP
1417 goto oom;
1418
1419 m->exit_code = MANAGER_EXIT;
1420
6652a2b9
LP
1421 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reboot")) {
1422
ffc227c9 1423 SELINUX_ACCESS_CHECK(connection, message, "reboot");
cad45ba1 1424
67445f4e 1425 if (m->running_as != SYSTEMD_SYSTEM) {
6652a2b9 1426 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Reboot is only supported for system managers.");
bfebab7f 1427 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
6652a2b9
LP
1428 }
1429
cad45ba1
LP
1430 reply = dbus_message_new_method_return(message);
1431 if (!reply)
6652a2b9
LP
1432 goto oom;
1433
1434 m->exit_code = MANAGER_REBOOT;
1435
1436 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "PowerOff")) {
1437
ffc227c9 1438 SELINUX_ACCESS_CHECK(connection, message, "halt");
cad45ba1 1439
67445f4e 1440 if (m->running_as != SYSTEMD_SYSTEM) {
6652a2b9 1441 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Powering off is only supported for system managers.");
bfebab7f 1442 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
6652a2b9
LP
1443 }
1444
cad45ba1
LP
1445 reply = dbus_message_new_method_return(message);
1446 if (!reply)
6652a2b9
LP
1447 goto oom;
1448
1449 m->exit_code = MANAGER_POWEROFF;
1450
1451 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Halt")) {
1452
ffc227c9 1453 SELINUX_ACCESS_CHECK(connection, message, "halt");
cad45ba1 1454
67445f4e 1455 if (m->running_as != SYSTEMD_SYSTEM) {
6652a2b9 1456 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Halting is only supported for system managers.");
bfebab7f 1457 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
6652a2b9
LP
1458 }
1459
cad45ba1
LP
1460 reply = dbus_message_new_method_return(message);
1461 if (!reply)
6652a2b9
LP
1462 goto oom;
1463
1464 m->exit_code = MANAGER_HALT;
1465
1466 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "KExec")) {
1467
ffc227c9 1468 SELINUX_ACCESS_CHECK(connection, message, "reboot");
cad45ba1 1469
67445f4e 1470 if (m->running_as != SYSTEMD_SYSTEM) {
6652a2b9 1471 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "kexec is only supported for system managers.");
bfebab7f 1472 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
6652a2b9
LP
1473 }
1474
cad45ba1
LP
1475 reply = dbus_message_new_method_return(message);
1476 if (!reply)
6652a2b9
LP
1477 goto oom;
1478
1479 m->exit_code = MANAGER_KEXEC;
1480
664f88a7
LP
1481 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SwitchRoot")) {
1482 const char *switch_root, *switch_root_init;
1483 char *u, *v;
50913bc0 1484 int k;
664f88a7 1485
ffc227c9 1486 SELINUX_ACCESS_CHECK(connection, message, "reboot");
cad45ba1 1487
664f88a7
LP
1488 if (!dbus_message_get_args(
1489 message,
1490 &error,
1491 DBUS_TYPE_STRING, &switch_root,
1492 DBUS_TYPE_STRING, &switch_root_init,
1493 DBUS_TYPE_INVALID))
1494 return bus_send_error_reply(connection, message, &error, -EINVAL);
1495
ee83acc4 1496 if (path_equal(switch_root, "/") || !path_is_absolute(switch_root))
664f88a7
LP
1497 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1498
ee83acc4 1499 if (!isempty(switch_root_init) && !path_is_absolute(switch_root_init))
664f88a7
LP
1500 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1501
67445f4e 1502 if (m->running_as != SYSTEMD_SYSTEM) {
664f88a7
LP
1503 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Switching root is only supported for system managers.");
1504 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1505 }
1506
50913bc0
LP
1507 /* Safety check */
1508 if (isempty(switch_root_init))
1509 k = access(switch_root, F_OK);
1510 else {
1511 char *p;
1512
b7def684 1513 p = strjoin(switch_root, "/", switch_root_init, NULL);
50913bc0
LP
1514 if (!p)
1515 goto oom;
1516
1517 k = access(p, X_OK);
1518 free(p);
1519 }
1520 if (k < 0)
1521 return bus_send_error_reply(connection, message, NULL, -errno);
1522
664f88a7
LP
1523 u = strdup(switch_root);
1524 if (!u)
1525 goto oom;
1526
1527 if (!isempty(switch_root_init)) {
1528 v = strdup(switch_root_init);
1529 if (!v) {
1530 free(u);
1531 goto oom;
1532 }
1533 } else
1534 v = NULL;
1535
1536 free(m->switch_root);
1537 free(m->switch_root_init);
1538 m->switch_root = u;
1539 m->switch_root_init = v;
1540
1541 reply = dbus_message_new_method_return(message);
1542 if (!reply)
1543 goto oom;
1544
1545 m->exit_code = MANAGER_SWITCH_ROOT;
1546
1137a57c 1547 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetEnvironment")) {
123b964a
LP
1548 _cleanup_strv_free_ char **l = NULL;
1549 char **e = NULL;
1137a57c 1550
ffc227c9 1551 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1137a57c 1552
cad45ba1
LP
1553 r = bus_parse_strv(message, &l);
1554 if (r == -ENOMEM)
1555 goto oom;
1556 if (r < 0)
bfebab7f 1557 return bus_send_error_reply(connection, message, NULL, r);
123b964a
LP
1558 if (!strv_env_is_valid(l))
1559 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1137a57c 1560
5b6319dc 1561 e = strv_env_merge(2, m->environment, l);
1137a57c
LP
1562 if (!e)
1563 goto oom;
1564
cad45ba1
LP
1565 reply = dbus_message_new_method_return(message);
1566 if (!reply) {
1137a57c
LP
1567 strv_free(e);
1568 goto oom;
1569 }
1570
1571 strv_free(m->environment);
1572 m->environment = e;
1573
1574 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetEnvironment")) {
123b964a
LP
1575 _cleanup_strv_free_ char **l = NULL;
1576 char **e = NULL;
1137a57c 1577
ffc227c9 1578 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1137a57c 1579
cad45ba1
LP
1580 r = bus_parse_strv(message, &l);
1581 if (r == -ENOMEM)
1582 goto oom;
1583 if (r < 0)
bfebab7f 1584 return bus_send_error_reply(connection, message, NULL, r);
123b964a
LP
1585 if (!strv_env_name_or_assignment_is_valid(l))
1586 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1137a57c 1587
5b6319dc 1588 e = strv_env_delete(m->environment, 1, l);
1137a57c
LP
1589 if (!e)
1590 goto oom;
1591
f72daa64
ZJS
1592 reply = dbus_message_new_method_return(message);
1593 if (!reply) {
da19d5c1 1594 strv_free(e);
1137a57c 1595 goto oom;
da19d5c1 1596 }
1137a57c
LP
1597
1598 strv_free(m->environment);
1599 m->environment = e;
1600
8d0e38a2 1601 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetAndSetEnvironment")) {
123b964a
LP
1602 _cleanup_strv_free_ char **l_set = NULL, **l_unset = NULL, **e = NULL;
1603 char **f = NULL;
8d0e38a2
LP
1604 DBusMessageIter iter;
1605
ffc227c9 1606 SELINUX_ACCESS_CHECK(connection, message, "reboot");
cad45ba1 1607
8d0e38a2 1608 if (!dbus_message_iter_init(message, &iter))
c0576cd6 1609 goto oom;
8d0e38a2
LP
1610
1611 r = bus_parse_strv_iter(&iter, &l_unset);
cad45ba1
LP
1612 if (r == -ENOMEM)
1613 goto oom;
1614 if (r < 0)
8d0e38a2 1615 return bus_send_error_reply(connection, message, NULL, r);
123b964a
LP
1616 if (!strv_env_name_or_assignment_is_valid(l_unset))
1617 return bus_send_error_reply(connection, message, NULL, -EINVAL);
8d0e38a2 1618
123b964a 1619 if (!dbus_message_iter_next(&iter))
8d0e38a2 1620 return bus_send_error_reply(connection, message, NULL, -EINVAL);
8d0e38a2
LP
1621
1622 r = bus_parse_strv_iter(&iter, &l_set);
123b964a
LP
1623 if (r == -ENOMEM)
1624 goto oom;
1625 if (r < 0)
8d0e38a2 1626 return bus_send_error_reply(connection, message, NULL, r);
123b964a
LP
1627 if (!strv_env_is_valid(l_set))
1628 return bus_send_error_reply(connection, message, NULL, -EINVAL);
8d0e38a2
LP
1629
1630 e = strv_env_delete(m->environment, 1, l_unset);
123b964a 1631 if (!e)
8d0e38a2 1632 goto oom;
8d0e38a2
LP
1633
1634 f = strv_env_merge(2, e, l_set);
8d0e38a2
LP
1635 if (!f)
1636 goto oom;
1637
f72daa64
ZJS
1638 reply = dbus_message_new_method_return(message);
1639 if (!reply) {
8d0e38a2
LP
1640 strv_free(f);
1641 goto oom;
1642 }
1643
1644 strv_free(m->environment);
1645 m->environment = f;
c0576cd6
LP
1646 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnitFiles")) {
1647 DBusMessageIter iter, sub, sub2;
1648 Hashmap *h;
1649 Iterator i;
1650 UnitFileList *item;
1651
ffc227c9 1652 SELINUX_ACCESS_CHECK(connection, message, "status");
cad45ba1 1653
c0576cd6
LP
1654 reply = dbus_message_new_method_return(message);
1655 if (!reply)
1656 goto oom;
1657
1658 h = hashmap_new(string_hash_func, string_compare_func);
1659 if (!h)
1660 goto oom;
1661
67445f4e 1662 r = unit_file_get_list(m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, h);
c0576cd6
LP
1663 if (r < 0) {
1664 unit_file_list_free(h);
c0576cd6
LP
1665 return bus_send_error_reply(connection, message, NULL, r);
1666 }
1667
1668 dbus_message_iter_init_append(reply, &iter);
1669
1670 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ss)", &sub)) {
1671 unit_file_list_free(h);
1672 goto oom;
1673 }
1674
1675 HASHMAP_FOREACH(item, h, i) {
1676 const char *state;
1677
1678 state = unit_file_state_to_string(item->state);
1679 assert(state);
1680
1681 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
1682 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &item->path) ||
1683 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &state) ||
1684 !dbus_message_iter_close_container(&sub, &sub2)) {
1685 unit_file_list_free(h);
1686 goto oom;
1687 }
1688 }
1689
1690 unit_file_list_free(h);
1691
1692 if (!dbus_message_iter_close_container(&iter, &sub))
1693 goto oom;
1694
1695 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnitFileState")) {
1696 const char *name;
1697 UnitFileState state;
1698 const char *s;
1699
ffc227c9 1700 SELINUX_ACCESS_CHECK(connection, message, "status");
cad45ba1 1701
c0576cd6
LP
1702 if (!dbus_message_get_args(
1703 message,
1704 &error,
1705 DBUS_TYPE_STRING, &name,
1706 DBUS_TYPE_INVALID))
1707 return bus_send_error_reply(connection, message, &error, -EINVAL);
1708
67445f4e 1709 state = unit_file_get_state(m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, name);
c0576cd6
LP
1710 if (state < 0)
1711 return bus_send_error_reply(connection, message, NULL, state);
1712
1713 s = unit_file_state_to_string(state);
1714 assert(s);
1715
1716 reply = dbus_message_new_method_return(message);
1717 if (!reply)
1718 goto oom;
1719
1720 if (!dbus_message_append_args(
1721 reply,
1722 DBUS_TYPE_STRING, &s,
1723 DBUS_TYPE_INVALID))
1724 goto oom;
1725 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "EnableUnitFiles") ||
1726 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReenableUnitFiles") ||
1727 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "LinkUnitFiles") ||
1728 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "PresetUnitFiles") ||
1729 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "MaskUnitFiles")) {
1730
1731 char **l = NULL;
1732 DBusMessageIter iter;
67445f4e 1733 UnitFileScope scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
c0576cd6
LP
1734 UnitFileChange *changes = NULL;
1735 unsigned n_changes = 0;
1736 dbus_bool_t runtime, force;
835680f5 1737 int carries_install_info = -1;
c0576cd6 1738
ffc227c9 1739 SELINUX_ACCESS_CHECK(connection, message, streq(member, "MaskUnitFiles") ? "disable" : "enable");
cad45ba1 1740
c0576cd6
LP
1741 if (!dbus_message_iter_init(message, &iter))
1742 goto oom;
1743
1744 r = bus_parse_strv_iter(&iter, &l);
1745 if (r < 0) {
1746 if (r == -ENOMEM)
1747 goto oom;
1748
1749 return bus_send_error_reply(connection, message, NULL, r);
1750 }
1751
1752 if (!dbus_message_iter_next(&iter) ||
1753 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, true) < 0 ||
1754 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &force, false) < 0) {
1755 strv_free(l);
1756 return bus_send_error_reply(connection, message, NULL, -EIO);
1757 }
1758
729e3769 1759 if (streq(member, "EnableUnitFiles")) {
c0576cd6 1760 r = unit_file_enable(scope, runtime, NULL, l, force, &changes, &n_changes);
729e3769
LP
1761 carries_install_info = r;
1762 } else if (streq(member, "ReenableUnitFiles")) {
c0576cd6 1763 r = unit_file_reenable(scope, runtime, NULL, l, force, &changes, &n_changes);
729e3769
LP
1764 carries_install_info = r;
1765 } else if (streq(member, "LinkUnitFiles"))
c0576cd6 1766 r = unit_file_link(scope, runtime, NULL, l, force, &changes, &n_changes);
729e3769 1767 else if (streq(member, "PresetUnitFiles")) {
c0576cd6 1768 r = unit_file_preset(scope, runtime, NULL, l, force, &changes, &n_changes);
729e3769
LP
1769 carries_install_info = r;
1770 } else if (streq(member, "MaskUnitFiles"))
c0576cd6
LP
1771 r = unit_file_mask(scope, runtime, NULL, l, force, &changes, &n_changes);
1772 else
1773 assert_not_reached("Uh? Wrong method");
1774
1775 strv_free(l);
1776 bus_manager_send_unit_files_changed(m);
1777
1778 if (r < 0) {
1779 unit_file_changes_free(changes, n_changes);
1780 return bus_send_error_reply(connection, message, NULL, r);
1781 }
1782
729e3769 1783 reply = message_from_file_changes(message, changes, n_changes, carries_install_info);
c0576cd6
LP
1784 unit_file_changes_free(changes, n_changes);
1785
1786 if (!reply)
1787 goto oom;
1788
1789 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "DisableUnitFiles") ||
1790 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnmaskUnitFiles")) {
1791
1792 char **l = NULL;
1793 DBusMessageIter iter;
67445f4e 1794 UnitFileScope scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
c0576cd6
LP
1795 UnitFileChange *changes = NULL;
1796 unsigned n_changes = 0;
1797 dbus_bool_t runtime;
1798
ffc227c9 1799 SELINUX_ACCESS_CHECK(connection, message, streq(member, "UnmaskUnitFiles") ? "enable" : "disable");
cad45ba1 1800
c0576cd6
LP
1801 if (!dbus_message_iter_init(message, &iter))
1802 goto oom;
1803
1804 r = bus_parse_strv_iter(&iter, &l);
1805 if (r < 0) {
1806 if (r == -ENOMEM)
1807 goto oom;
1808
1809 return bus_send_error_reply(connection, message, NULL, r);
1810 }
1811
1812 if (!dbus_message_iter_next(&iter) ||
1813 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, false) < 0) {
1814 strv_free(l);
1815 return bus_send_error_reply(connection, message, NULL, -EIO);
1816 }
1817
1818 if (streq(member, "DisableUnitFiles"))
1819 r = unit_file_disable(scope, runtime, NULL, l, &changes, &n_changes);
1820 else if (streq(member, "UnmaskUnitFiles"))
1821 r = unit_file_unmask(scope, runtime, NULL, l, &changes, &n_changes);
1822 else
1823 assert_not_reached("Uh? Wrong method");
1824
1825 strv_free(l);
1826 bus_manager_send_unit_files_changed(m);
1827
1828 if (r < 0) {
1829 unit_file_changes_free(changes, n_changes);
1830 return bus_send_error_reply(connection, message, NULL, r);
1831 }
1832
729e3769 1833 reply = message_from_file_changes(message, changes, n_changes, -1);
c0576cd6
LP
1834 unit_file_changes_free(changes, n_changes);
1835
1836 if (!reply)
1837 goto oom;
8d0e38a2 1838
d200735e
MS
1839 } else {
1840 const BusBoundProperties bps[] = {
1841 { "org.freedesktop.systemd1.Manager", bus_systemd_properties, systemd_property_string },
1842 { "org.freedesktop.systemd1.Manager", bus_manager_properties, m },
1843 { NULL, }
1844 };
cad45ba1 1845
ffc227c9 1846 SELINUX_ACCESS_CHECK(connection, message, "status");
cad45ba1 1847
d200735e
MS
1848 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
1849 }
ea430986 1850
c87eba54 1851 if (job_type != _JOB_TYPE_INVALID) {
90bb85e1 1852 const char *name, *smode, *old_name = NULL;
c87eba54 1853 JobMode mode;
c87eba54 1854 Unit *u;
cad45ba1 1855 dbus_bool_t b;
90bb85e1
LP
1856
1857 if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnitReplace"))
1858 b = dbus_message_get_args(
1859 message,
1860 &error,
1861 DBUS_TYPE_STRING, &old_name,
1862 DBUS_TYPE_STRING, &name,
1863 DBUS_TYPE_STRING, &smode,
1864 DBUS_TYPE_INVALID);
1865 else
1866 b = dbus_message_get_args(
1867 message,
1868 &error,
1869 DBUS_TYPE_STRING, &name,
1870 DBUS_TYPE_STRING, &smode,
1871 DBUS_TYPE_INVALID);
90bb85e1 1872 if (!b)
bfebab7f 1873 return bus_send_error_reply(connection, message, &error, -EINVAL);
c87eba54 1874
cad45ba1
LP
1875 if (old_name) {
1876 u = manager_get_unit(m, old_name);
1877 if (!u || !u->job || u->job->type != JOB_START) {
90bb85e1 1878 dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "No job queued for unit %s", old_name);
bfebab7f 1879 return bus_send_error_reply(connection, message, &error, -ENOENT);
90bb85e1 1880 }
cad45ba1 1881 }
90bb85e1 1882
cad45ba1
LP
1883 mode = job_mode_from_string(smode);
1884 if (mode < 0) {
398ef8ba 1885 dbus_set_error(&error, BUS_ERROR_INVALID_JOB_MODE, "Job mode %s is invalid.", smode);
bfebab7f 1886 return bus_send_error_reply(connection, message, &error, -EINVAL);
398ef8ba 1887 }
c87eba54 1888
cad45ba1
LP
1889 r = manager_load_unit(m, name, NULL, &error, &u);
1890 if (r < 0)
bfebab7f 1891 return bus_send_error_reply(connection, message, &error, r);
c87eba54 1892
cad45ba1 1893 return bus_unit_queue_job(connection, message, u, job_type, mode, reload_if_possible);
c87eba54
LP
1894 }
1895
cad45ba1 1896 if (reply)
ea430986
LP
1897 if (!dbus_connection_send(connection, reply, NULL))
1898 goto oom;
1899
ea430986
LP
1900 return DBUS_HANDLER_RESULT_HANDLED;
1901
1902oom:
ea430986
LP
1903 dbus_error_free(&error);
1904
1905 return DBUS_HANDLER_RESULT_NEED_MEMORY;
1906}
1907
1908const DBusObjectPathVTable bus_manager_vtable = {
1909 .message_function = bus_manager_message_handler
1910};