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