]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/dbus-manager.c
Add set_consume which always takes ownership
[thirdparty/systemd.git] / src / core / dbus-manager.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
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
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
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
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <errno.h>
23 #include <unistd.h>
24
25 #include "dbus.h"
26 #include "log.h"
27 #include "dbus-manager.h"
28 #include "strv.h"
29 #include "bus-errors.h"
30 #include "build.h"
31 #include "dbus-common.h"
32 #include "install.h"
33 #include "selinux-access.h"
34 #include "watchdog.h"
35 #include "hwclock.h"
36 #include "path-util.h"
37 #include "dbus-unit.h"
38 #include "virt.h"
39 #include "env-util.h"
40
41 #define BUS_MANAGER_INTERFACE_BEGIN \
42 " <interface name=\"org.freedesktop.systemd1.Manager\">\n"
43
44 #define BUS_MANAGER_INTERFACE_METHODS \
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" \
49 " <method name=\"GetUnitByPID\">\n" \
50 " <arg name=\"pid\" type=\"u\" direction=\"in\"/>\n" \
51 " <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n" \
52 " </method>\n" \
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" \
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" \
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" \
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" \
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" \
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" \
98 " <method name=\"KillUnit\">\n" \
99 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
100 " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
101 " <arg name=\"signal\" type=\"i\" direction=\"in\"/>\n" \
102 " </method>\n" \
103 " <method name=\"ResetFailedUnit\">\n" \
104 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
105 " </method>\n" \
106 " <method name=\"SetUnitControlGroup\">\n" \
107 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
108 " <arg name=\"group\" type=\"s\" direction=\"in\"/>\n" \
109 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
110 " </method>\n" \
111 " <method name=\"UnsetUnitControlGroup\">\n" \
112 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
113 " <arg name=\"group\" type=\"s\" direction=\"in\"/>\n" \
114 " <arg name=\"mode\" type=\"s\" direction=\"in\"\n/>" \
115 " </method>\n" \
116 " <method name=\"GetUnitControlGroupAttribute\">\n" \
117 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
118 " <arg name=\"attribute\" type=\"s\" direction=\"in\"/>\n" \
119 " <arg name=\"values\" type=\"as\" direction=\"out\"/>\n" \
120 " </method>\n" \
121 " <method name=\"SetUnitControlGroupAttribute\">\n" \
122 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
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/>" \
126 " </method>\n" \
127 " <method name=\"UnsetUnitControlGroupAttributes\">\n" \
128 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
129 " <arg name=\"attribute\" type=\"s\" direction=\"in\"/>\n" \
130 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
131 " </method>\n" \
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" \
136 " <method name=\"CancelJob\">\n" \
137 " <arg name=\"id\" type=\"u\" direction=\"in\"/>\n" \
138 " </method>\n" \
139 " <method name=\"ClearJobs\"/>\n" \
140 " <method name=\"ResetFailed\"/>\n" \
141 " <method name=\"ListUnits\">\n" \
142 " <arg name=\"units\" type=\"a(ssssssouso)\" direction=\"out\"/>\n" \
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" \
149 " <method name=\"Dump\">\n" \
150 " <arg name=\"dump\" type=\"s\" direction=\"out\"/>\n" \
151 " </method>\n" \
152 " <method name=\"CreateSnapshot\">\n" \
153 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
154 " <arg name=\"cleanup\" type=\"b\" direction=\"in\"/>\n" \
155 " <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n" \
156 " </method>\n" \
157 " <method name=\"RemoveSnapshot\">\n" \
158 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
159 " </method>\n" \
160 " <method name=\"Reload\"/>\n" \
161 " <method name=\"Reexecute\"/>\n" \
162 " <method name=\"Exit\"/>\n" \
163 " <method name=\"Reboot\"/>\n" \
164 " <method name=\"PowerOff\"/>\n" \
165 " <method name=\"Halt\"/>\n" \
166 " <method name=\"KExec\"/>\n" \
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" \
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" \
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" \
180 " </method>\n" \
181 " <method name=\"ListUnitFiles\">\n" \
182 " <arg name=\"files\" type=\"a(ss)\" direction=\"out\"/>\n" \
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" \
192 " <arg name=\"carries_install_info\" type=\"b\" direction=\"out\"/>\n" \
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" \
204 " <arg name=\"carries_install_info\" type=\"b\" direction=\"out\"/>\n" \
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" \
217 " <arg name=\"carries_install_info\" type=\"b\" direction=\"out\"/>\n" \
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" \
230 " </method>\n"
231
232 #define BUS_MANAGER_INTERFACE_SIGNALS \
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" \
244 " <arg name=\"unit\" type=\"s\"/>\n" \
245 " </signal>\n" \
246 " <signal name=\"JobRemoved\">\n" \
247 " <arg name=\"id\" type=\"u\"/>\n" \
248 " <arg name=\"job\" type=\"o\"/>\n" \
249 " <arg name=\"unit\" type=\"s\"/>\n" \
250 " <arg name=\"result\" type=\"s\"/>\n" \
251 " </signal>" \
252 " <signal name=\"StartupFinished\">\n" \
253 " <arg name=\"firmware\" type=\"t\"/>\n" \
254 " <arg name=\"loader\" type=\"t\"/>\n" \
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" \
259 " </signal>" \
260 " <signal name=\"UnitFilesChanged\"/>\n"
261
262 #define BUS_MANAGER_INTERFACE_PROPERTIES_GENERAL \
263 " <property name=\"Version\" type=\"s\" access=\"read\"/>\n" \
264 " <property name=\"Features\" type=\"s\" access=\"read\"/>\n" \
265 " <property name=\"Tainted\" type=\"s\" access=\"read\"/>\n" \
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" \
272 " <property name=\"InitRDTimestamp\" type=\"t\" access=\"read\"/>\n" \
273 " <property name=\"InitRDTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
274 " <property name=\"UserspaceTimestamp\" type=\"t\" access=\"read\"/>\n" \
275 " <property name=\"UserspaceTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
276 " <property name=\"FinishTimestamp\" type=\"t\" access=\"read\"/>\n" \
277 " <property name=\"FinishTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
278 " <property name=\"LogLevel\" type=\"s\" access=\"readwrite\"/>\n" \
279 " <property name=\"LogTarget\" type=\"s\" access=\"readwrite\"/>\n" \
280 " <property name=\"NNames\" type=\"u\" access=\"read\"/>\n" \
281 " <property name=\"NJobs\" type=\"u\" access=\"read\"/>\n" \
282 " <property name=\"NInstalledJobs\" type=\"u\" access=\"read\"/>\n" \
283 " <property name=\"NFailedJobs\" type=\"u\" access=\"read\"/>\n" \
284 " <property name=\"Progress\" type=\"d\" access=\"read\"/>\n" \
285 " <property name=\"Environment\" type=\"as\" access=\"read\"/>\n" \
286 " <property name=\"ConfirmSpawn\" type=\"b\" access=\"read\"/>\n" \
287 " <property name=\"ShowStatus\" type=\"b\" access=\"read\"/>\n" \
288 " <property name=\"UnitPath\" type=\"as\" access=\"read\"/>\n" \
289 " <property name=\"ControlGroupHierarchy\" type=\"s\" access=\"read\"/>\n" \
290 " <property name=\"DefaultControllers\" type=\"as\" access=\"read\"/>\n" \
291 " <property name=\"DefaultStandardOutput\" type=\"s\" access=\"read\"/>\n" \
292 " <property name=\"DefaultStandardError\" type=\"s\" access=\"read\"/>\n" \
293 " <property name=\"RuntimeWatchdogUSec\" type=\"t\" access=\"readwrite\"/>\n" \
294 " <property name=\"ShutdownWatchdogUSec\" type=\"t\" access=\"readwrite\"/>\n" \
295 " <property name=\"Virtualization\" type=\"s\" access=\"read\"/>\n"
296
297 #define BUS_MANAGER_INTERFACE_END \
298 " </interface>\n"
299
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 \
305 BUS_MANAGER_INTERFACE_END
306
307 #define INTROSPECTION_BEGIN \
308 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
309 "<node>\n" \
310 BUS_MANAGER_INTERFACE \
311 BUS_PROPERTIES_INTERFACE \
312 BUS_PEER_INTERFACE \
313 BUS_INTROSPECTABLE_INTERFACE
314
315 #define INTROSPECTION_END \
316 "</node>\n"
317
318 #define INTERFACES_LIST \
319 BUS_GENERIC_INTERFACES_LIST \
320 "org.freedesktop.systemd1.Manager\0"
321
322 const char bus_manager_interface[] _introspect_("Manager") = BUS_MANAGER_INTERFACE;
323
324 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_exec_output, exec_output, ExecOutput);
325
326 static int bus_manager_append_tainted(DBusMessageIter *i, const char *property, void *data) {
327 const char *t;
328 Manager *m = data;
329 char buf[LINE_MAX] = "", *e = buf, *p = NULL;
330
331 assert(i);
332 assert(property);
333 assert(m);
334
335 if (m->taint_usr)
336 e = stpcpy(e, "split-usr:");
337
338 if (readlink_malloc("/etc/mtab", &p) < 0)
339 e = stpcpy(e, "mtab-not-symlink:");
340 else
341 free(p);
342
343 if (access("/proc/cgroups", F_OK) < 0)
344 e = stpcpy(e, "cgroups-missing:");
345
346 if (hwclock_is_localtime() > 0)
347 e = stpcpy(e, "local-hwclock:");
348
349 /* remove the last ':' */
350 if (e != buf)
351 e[-1] = 0;
352
353 t = buf;
354
355 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
356 return -ENOMEM;
357
358 return 0;
359 }
360
361 static int bus_manager_append_log_target(DBusMessageIter *i, const char *property, void *data) {
362 const char *t;
363
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
375 static int bus_manager_set_log_target(DBusMessageIter *i, const char *property, void *data) {
376 const char *t;
377
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
386 static int bus_manager_append_log_level(DBusMessageIter *i, const char *property, void *data) {
387 char *t;
388 int r;
389
390 assert(i);
391 assert(property);
392
393 r = log_level_to_string_alloc(log_get_max_level(), &t);
394 if (r < 0)
395 return r;
396
397 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
398 r = -ENOMEM;
399
400 free(t);
401 return r;
402 }
403
404 static int bus_manager_set_log_level(DBusMessageIter *i, const char *property, void *data) {
405 const char *t;
406
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
415 static int bus_manager_append_n_names(DBusMessageIter *i, const char *property, void *data) {
416 Manager *m = data;
417 uint32_t u;
418
419 assert(i);
420 assert(property);
421 assert(m);
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
431 static int bus_manager_append_n_jobs(DBusMessageIter *i, const char *property, void *data) {
432 Manager *m = data;
433 uint32_t u;
434
435 assert(i);
436 assert(property);
437 assert(m);
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
447 static int bus_manager_append_progress(DBusMessageIter *i, const char *property, void *data) {
448 double d;
449 Manager *m = data;
450
451 assert(i);
452 assert(property);
453 assert(m);
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
466 static 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
482 static DBusMessage *message_from_file_changes(
483 DBusMessage *m,
484 UnitFileChange *changes,
485 unsigned n_changes,
486 int carries_install_info) {
487
488 DBusMessageIter iter, sub, sub2;
489 DBusMessage *reply;
490 unsigned i;
491
492 reply = dbus_message_new_method_return(m);
493 if (!reply)
494 return NULL;
495
496 dbus_message_iter_init_append(reply, &iter);
497
498 if (carries_install_info >= 0) {
499 dbus_bool_t b;
500
501 b = !!carries_install_info;
502 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b))
503 goto oom;
504 }
505
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) ||
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) ||
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
529 oom:
530 dbus_message_unref(reply);
531 return NULL;
532 }
533
534 static 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
548 static 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
559 static const char systemd_property_string[] =
560 PACKAGE_STRING "\0"
561 SYSTEMD_FEATURES;
562
563 static const BusProperty bus_systemd_properties[] = {
564 { "Version", bus_property_append_string, "s", 0 },
565 { "Features", bus_property_append_string, "s", sizeof(PACKAGE_STRING) },
566 { NULL, }
567 };
568
569 static const BusProperty bus_manager_properties[] = {
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, },
601 { NULL, }
602 };
603
604 static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, DBusMessage *message, void *data) {
605 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
606 _cleanup_free_ char * path = NULL;
607 Manager *m = data;
608 int r;
609 DBusError error;
610 JobType job_type = _JOB_TYPE_INVALID;
611 bool reload_if_possible = false;
612 const char *member;
613
614 assert(connection);
615 assert(message);
616 assert(m);
617
618 dbus_error_init(&error);
619
620 member = dbus_message_get_member(message);
621
622 if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnit")) {
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))
631 return bus_send_error_reply(connection, message, &error, -EINVAL);
632
633 u = manager_get_unit(m, name);
634 if (!u) {
635 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
636 return bus_send_error_reply(connection, message, &error, -ENOENT);
637 }
638
639 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status");
640
641 reply = dbus_message_new_method_return(message);
642 if (!reply)
643 goto oom;
644
645 path = unit_dbus_path(u);
646 if (!path)
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;
654 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnitByPID")) {
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))
663 return bus_send_error_reply(connection, message, &error, -EINVAL);
664
665 u = cgroup_unit_by_pid(m, (pid_t) pid);
666 if (!u) {
667 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "No unit for PID %lu is loaded.", (unsigned long) pid);
668 return bus_send_error_reply(connection, message, &error, -ENOENT);
669 }
670
671 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status");
672
673 reply = dbus_message_new_method_return(message);
674 if (!reply)
675 goto oom;
676
677 path = unit_dbus_path(u);
678 if (!path)
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 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "LoadUnit")) {
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))
695 return bus_send_error_reply(connection, message, &error, -EINVAL);
696
697 r = manager_load_unit(m, name, NULL, &error, &u);
698 if (r < 0)
699 return bus_send_error_reply(connection, message, &error, r);
700
701 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status");
702
703 reply = dbus_message_new_method_return(message);
704 if (!reply)
705 goto oom;
706
707 path = unit_dbus_path(u);
708 if (!path)
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
717 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnit"))
718 job_type = JOB_START;
719 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnitReplace"))
720 job_type = JOB_START;
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;
727 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "TryRestartUnit"))
728 job_type = JOB_TRY_RESTART;
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;
735 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "KillUnit")) {
736 const char *name, *swho;
737 int32_t signo;
738 Unit *u;
739 KillWho who;
740
741 if (!dbus_message_get_args(
742 message,
743 &error,
744 DBUS_TYPE_STRING, &name,
745 DBUS_TYPE_STRING, &swho,
746 DBUS_TYPE_INT32, &signo,
747 DBUS_TYPE_INVALID))
748 return bus_send_error_reply(connection, message, &error, -EINVAL);
749
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
758 if (signo <= 0 || signo >= _NSIG)
759 return bus_send_error_reply(connection, message, &error, -EINVAL);
760
761 u = manager_get_unit(m, name);
762 if (!u) {
763 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
764 return bus_send_error_reply(connection, message, &error, -ENOENT);
765 }
766
767 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "stop");
768
769 r = unit_kill(u, who, signo, &error);
770 if (r < 0)
771 return bus_send_error_reply(connection, message, &error, r);
772
773 reply = dbus_message_new_method_return(message);
774 if (!reply)
775 goto oom;
776
777 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetJob")) {
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))
786 return bus_send_error_reply(connection, message, &error, -EINVAL);
787
788 j = manager_get_job(m, id);
789 if (!j) {
790 dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "Job %u does not exist.", (unsigned) id);
791 return bus_send_error_reply(connection, message, &error, -ENOENT);
792 }
793
794 SELINUX_UNIT_ACCESS_CHECK(j->unit, connection, message, "status");
795
796 reply = dbus_message_new_method_return(message);
797 if (!reply)
798 goto oom;
799
800 path = job_dbus_path(j);
801 if (!path)
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
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
834 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ClearJobs")) {
835
836 SELINUX_ACCESS_CHECK(connection, message, "reboot");
837 manager_clear_jobs(m);
838
839 reply = dbus_message_new_method_return(message);
840 if (!reply)
841 goto oom;
842
843 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ResetFailed")) {
844
845 SELINUX_ACCESS_CHECK(connection, message, "reload");
846
847 manager_reset_failed(m);
848
849 reply = dbus_message_new_method_return(message);
850 if (!reply)
851 goto oom;
852
853 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ResetFailedUnit")) {
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))
862 return bus_send_error_reply(connection, message, &error, -EINVAL);
863
864 u = manager_get_unit(m, name);
865 if (!u) {
866 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
867 return bus_send_error_reply(connection, message, &error, -ENOENT);
868 }
869
870 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "reload");
871
872 unit_reset_failed(u);
873
874 reply = dbus_message_new_method_return(message);
875 if (!reply)
876 goto oom;
877
878 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetUnitControlGroup")) {
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
906 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetUnitControlGroup")) {
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
934 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetUnitControlGroupAttribute")) {
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");
953
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
962 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetUnitControlGroupAttribute")) {
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);
987 if (!reply)
988 goto oom;
989
990 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnitControlGroupAttribute")) {
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");
1010
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
1023 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnits")) {
1024 DBusMessageIter iter, sub;
1025 Iterator i;
1026 Unit *u;
1027 const char *k;
1028
1029 SELINUX_ACCESS_CHECK(connection, message, "status");
1030
1031 reply = dbus_message_new_method_return(message);
1032 if (!reply)
1033 goto oom;
1034
1035 dbus_message_iter_init_append(reply, &iter);
1036
1037 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssssouso)", &sub))
1038 goto oom;
1039
1040 HASHMAP_FOREACH_KEY(u, k, m->units, i) {
1041 char *u_path, *j_path;
1042 const char *description, *load_state, *active_state, *sub_state, *sjob_type, *following;
1043 DBusMessageIter sub2;
1044 uint32_t job_id;
1045 Unit *f;
1046
1047 if (k != u->id)
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);
1054 load_state = unit_load_state_to_string(u->load_state);
1055 active_state = unit_active_state_to_string(unit_active_state(u));
1056 sub_state = unit_sub_state_to_string(u);
1057
1058 f = unit_following(u);
1059 following = f ? f->id : "";
1060
1061 u_path = unit_dbus_path(u);
1062 if (!u_path)
1063 goto oom;
1064
1065 if (u->job) {
1066 job_id = (uint32_t) u->job->id;
1067
1068 if (!(j_path = job_dbus_path(u->job))) {
1069 free(u_path);
1070 goto oom;
1071 }
1072
1073 sjob_type = job_type_to_string(u->job->type);
1074 } else {
1075 job_id = 0;
1076 j_path = u_path;
1077 sjob_type = "";
1078 }
1079
1080 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &u->id) ||
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) ||
1084 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &sub_state) ||
1085 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &following) ||
1086 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &u_path) ||
1087 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &job_id) ||
1088 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &sjob_type) ||
1089 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &j_path)) {
1090 free(u_path);
1091 if (u->job)
1092 free(j_path);
1093 goto oom;
1094 }
1095
1096 free(u_path);
1097 if (u->job)
1098 free(j_path);
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
1107 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListJobs")) {
1108 DBusMessageIter iter, sub;
1109 Iterator i;
1110 Job *j;
1111
1112 SELINUX_ACCESS_CHECK(connection, message, "status");
1113
1114 reply = dbus_message_new_method_return(message);
1115 if (!reply)
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) {
1124 char *u_path, *j_path;
1125 const char *state, *type;
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;
1133 state = job_state_to_string(j->state);
1134 type = job_type_to_string(j->type);
1135
1136 j_path = job_dbus_path(j);
1137 if (!j_path)
1138 goto oom;
1139
1140 u_path = unit_dbus_path(j->unit);
1141 if (!u_path) {
1142 free(j_path);
1143 goto oom;
1144 }
1145
1146 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &id) ||
1147 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &j->unit->id) ||
1148 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &type) ||
1149 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &state) ||
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);
1154 goto oom;
1155 }
1156
1157 free(j_path);
1158 free(u_path);
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
1167 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Subscribe")) {
1168 char *client;
1169 Set *s;
1170
1171 SELINUX_ACCESS_CHECK(connection, message, "status");
1172
1173 s = BUS_CONNECTION_SUBSCRIBED(m, connection);
1174 if (!s) {
1175 s = set_new(string_hash_func, string_compare_func);
1176 if (!s)
1177 goto oom;
1178
1179 if (!dbus_connection_set_data(connection, m->subscribed_data_slot, s, NULL)) {
1180 set_free(s);
1181 goto oom;
1182 }
1183 }
1184
1185 client = strdup(bus_message_get_sender_with_fallback(message));
1186 if (!client)
1187 goto oom;
1188
1189 r = set_consume(s, client);
1190 if (r < 0)
1191 return bus_send_error_reply(connection, message, NULL, r);
1192
1193 reply = dbus_message_new_method_return(message);
1194 if (!reply)
1195 goto oom;
1196
1197 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Unsubscribe")) {
1198 char *client;
1199
1200 SELINUX_ACCESS_CHECK(connection, message, "status");
1201
1202 client = set_remove(BUS_CONNECTION_SUBSCRIBED(m, connection), (char*) bus_message_get_sender_with_fallback(message));
1203 if (!client) {
1204 dbus_set_error(&error, BUS_ERROR_NOT_SUBSCRIBED, "Client is not subscribed.");
1205 return bus_send_error_reply(connection, message, &error, -ENOENT);
1206 }
1207
1208 free(client);
1209
1210 reply = dbus_message_new_method_return(message);
1211 if (!reply)
1212 goto oom;
1213
1214 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Dump")) {
1215 FILE *f;
1216 char *dump = NULL;
1217 size_t size;
1218
1219 SELINUX_ACCESS_CHECK(connection, message, "status");
1220
1221 reply = dbus_message_new_method_return(message);
1222 if (!reply)
1223 goto oom;
1224
1225 f = open_memstream(&dump, &size);
1226 if (!f)
1227 goto oom;
1228
1229 manager_dump_units(m, f, NULL);
1230 manager_dump_jobs(m, f, NULL);
1231
1232 if (ferror(f)) {
1233 fclose(f);
1234 free(dump);
1235 goto oom;
1236 }
1237
1238 fclose(f);
1239
1240 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &dump, DBUS_TYPE_INVALID)) {
1241 free(dump);
1242 goto oom;
1243 }
1244
1245 free(dump);
1246 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "CreateSnapshot")) {
1247 const char *name;
1248 dbus_bool_t cleanup;
1249 Snapshot *s;
1250
1251 SELINUX_ACCESS_CHECK(connection, message, "start");
1252
1253 if (!dbus_message_get_args(
1254 message,
1255 &error,
1256 DBUS_TYPE_STRING, &name,
1257 DBUS_TYPE_BOOLEAN, &cleanup,
1258 DBUS_TYPE_INVALID))
1259 return bus_send_error_reply(connection, message, &error, -EINVAL);
1260
1261 if (isempty(name))
1262 name = NULL;
1263
1264 r = snapshot_create(m, name, cleanup, &error, &s);
1265 if (r < 0)
1266 return bus_send_error_reply(connection, message, &error, r);
1267
1268 reply = dbus_message_new_method_return(message);
1269 if (!reply)
1270 goto oom;
1271
1272 path = unit_dbus_path(UNIT(s));
1273 if (!path)
1274 goto oom;
1275
1276 if (!dbus_message_append_args(
1277 reply,
1278 DBUS_TYPE_OBJECT_PATH, &path,
1279 DBUS_TYPE_INVALID))
1280 goto oom;
1281
1282 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "RemoveSnapshot")) {
1283 const char *name;
1284 Unit *u;
1285
1286 if (!dbus_message_get_args(
1287 message,
1288 &error,
1289 DBUS_TYPE_STRING, &name,
1290 DBUS_TYPE_INVALID))
1291 return bus_send_error_reply(connection, message, &error, -EINVAL);
1292
1293 u = manager_get_unit(m, name);
1294 if (!u) {
1295 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s does not exist.", name);
1296 return bus_send_error_reply(connection, message, &error, -ENOENT);
1297 }
1298
1299 if (u->type != UNIT_SNAPSHOT) {
1300 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not a snapshot.", name);
1301 return bus_send_error_reply(connection, message, &error, -ENOENT);
1302 }
1303
1304 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "stop");
1305 snapshot_remove(SNAPSHOT(u));
1306
1307 reply = dbus_message_new_method_return(message);
1308 if (!reply)
1309 goto oom;
1310
1311 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
1312 char *introspection = NULL;
1313 FILE *f;
1314 Iterator i;
1315 Unit *u;
1316 Job *j;
1317 const char *k;
1318 size_t size;
1319
1320 SELINUX_ACCESS_CHECK(connection, message, "status");
1321
1322 reply = dbus_message_new_method_return(message);
1323 if (!reply)
1324 goto oom;
1325
1326 /* We roll our own introspection code here, instead of
1327 * relying on bus_default_message_handler() because we
1328 * need to generate our introspection string
1329 * dynamically. */
1330
1331 f = open_memstream(&introspection, &size);
1332 if (!f)
1333 goto oom;
1334
1335 fputs(INTROSPECTION_BEGIN, f);
1336
1337 HASHMAP_FOREACH_KEY(u, k, m->units, i) {
1338 char *p;
1339
1340 if (k != u->id)
1341 continue;
1342
1343 p = bus_path_escape(k);
1344 if (!p) {
1345 fclose(f);
1346 free(introspection);
1347 goto oom;
1348 }
1349
1350 fprintf(f, "<node name=\"unit/%s\"/>", p);
1351 free(p);
1352 }
1353
1354 HASHMAP_FOREACH(j, m->jobs, i)
1355 fprintf(f, "<node name=\"job/%lu\"/>", (unsigned long) j->id);
1356
1357 fputs(INTROSPECTION_END, f);
1358
1359 if (ferror(f)) {
1360 fclose(f);
1361 free(introspection);
1362 goto oom;
1363 }
1364
1365 fclose(f);
1366
1367 if (!introspection)
1368 goto oom;
1369
1370 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
1371 free(introspection);
1372 goto oom;
1373 }
1374
1375 free(introspection);
1376
1377 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reload")) {
1378
1379 SELINUX_ACCESS_CHECK(connection, message, "reload");
1380
1381 assert(!m->queued_message);
1382
1383 /* Instead of sending the reply back right away, we
1384 * just remember that we need to and then send it
1385 * after the reload is finished. That way the caller
1386 * knows when the reload finished. */
1387
1388 m->queued_message = dbus_message_new_method_return(message);
1389 if (!m->queued_message)
1390 goto oom;
1391
1392 m->queued_message_connection = connection;
1393 m->exit_code = MANAGER_RELOAD;
1394
1395 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reexecute")) {
1396
1397 SELINUX_ACCESS_CHECK(connection, message, "reload");
1398
1399 /* We don't send a reply back here, the client should
1400 * just wait for us disconnecting. */
1401
1402 m->exit_code = MANAGER_REEXECUTE;
1403
1404 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Exit")) {
1405
1406 SELINUX_ACCESS_CHECK(connection, message, "halt");
1407
1408 if (m->running_as == SYSTEMD_SYSTEM) {
1409 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Exit is only supported for user service managers.");
1410 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1411 }
1412
1413 reply = dbus_message_new_method_return(message);
1414 if (!reply)
1415 goto oom;
1416
1417 m->exit_code = MANAGER_EXIT;
1418
1419 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reboot")) {
1420
1421 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1422
1423 if (m->running_as != SYSTEMD_SYSTEM) {
1424 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Reboot is only supported for system managers.");
1425 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1426 }
1427
1428 reply = dbus_message_new_method_return(message);
1429 if (!reply)
1430 goto oom;
1431
1432 m->exit_code = MANAGER_REBOOT;
1433
1434 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "PowerOff")) {
1435
1436 SELINUX_ACCESS_CHECK(connection, message, "halt");
1437
1438 if (m->running_as != SYSTEMD_SYSTEM) {
1439 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Powering off is only supported for system managers.");
1440 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1441 }
1442
1443 reply = dbus_message_new_method_return(message);
1444 if (!reply)
1445 goto oom;
1446
1447 m->exit_code = MANAGER_POWEROFF;
1448
1449 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Halt")) {
1450
1451 SELINUX_ACCESS_CHECK(connection, message, "halt");
1452
1453 if (m->running_as != SYSTEMD_SYSTEM) {
1454 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Halting is only supported for system managers.");
1455 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1456 }
1457
1458 reply = dbus_message_new_method_return(message);
1459 if (!reply)
1460 goto oom;
1461
1462 m->exit_code = MANAGER_HALT;
1463
1464 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "KExec")) {
1465
1466 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1467
1468 if (m->running_as != SYSTEMD_SYSTEM) {
1469 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "kexec is only supported for system managers.");
1470 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1471 }
1472
1473 reply = dbus_message_new_method_return(message);
1474 if (!reply)
1475 goto oom;
1476
1477 m->exit_code = MANAGER_KEXEC;
1478
1479 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SwitchRoot")) {
1480 const char *switch_root, *switch_root_init;
1481 char *u, *v;
1482 bool good;
1483
1484 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1485
1486 if (!dbus_message_get_args(
1487 message,
1488 &error,
1489 DBUS_TYPE_STRING, &switch_root,
1490 DBUS_TYPE_STRING, &switch_root_init,
1491 DBUS_TYPE_INVALID))
1492 return bus_send_error_reply(connection, message, &error, -EINVAL);
1493
1494 if (path_equal(switch_root, "/") || !path_is_absolute(switch_root))
1495 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1496
1497 if (!isempty(switch_root_init) && !path_is_absolute(switch_root_init))
1498 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1499
1500 if (m->running_as != SYSTEMD_SYSTEM) {
1501 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Switching root is only supported for system managers.");
1502 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1503 }
1504
1505 /* Safety check */
1506 if (isempty(switch_root_init))
1507 good = path_is_os_tree(switch_root);
1508 else {
1509 _cleanup_free_ char *p = NULL;
1510
1511 p = strjoin(switch_root, "/", switch_root_init, NULL);
1512 if (!p)
1513 goto oom;
1514
1515 good = access(p, X_OK) >= 0;
1516 }
1517 if (!good)
1518 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1519
1520 u = strdup(switch_root);
1521 if (!u)
1522 goto oom;
1523
1524 if (!isempty(switch_root_init)) {
1525 v = strdup(switch_root_init);
1526 if (!v) {
1527 free(u);
1528 goto oom;
1529 }
1530 } else
1531 v = NULL;
1532
1533 free(m->switch_root);
1534 free(m->switch_root_init);
1535 m->switch_root = u;
1536 m->switch_root_init = v;
1537
1538 reply = dbus_message_new_method_return(message);
1539 if (!reply)
1540 goto oom;
1541
1542 m->exit_code = MANAGER_SWITCH_ROOT;
1543
1544 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetEnvironment")) {
1545 _cleanup_strv_free_ char **l = NULL;
1546 char **e = NULL;
1547
1548 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1549
1550 r = bus_parse_strv(message, &l);
1551 if (r == -ENOMEM)
1552 goto oom;
1553 if (r < 0)
1554 return bus_send_error_reply(connection, message, NULL, r);
1555 if (!strv_env_is_valid(l))
1556 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1557
1558 e = strv_env_merge(2, m->environment, l);
1559 if (!e)
1560 goto oom;
1561
1562 reply = dbus_message_new_method_return(message);
1563 if (!reply) {
1564 strv_free(e);
1565 goto oom;
1566 }
1567
1568 strv_free(m->environment);
1569 m->environment = e;
1570
1571 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetEnvironment")) {
1572 _cleanup_strv_free_ char **l = NULL;
1573 char **e = NULL;
1574
1575 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1576
1577 r = bus_parse_strv(message, &l);
1578 if (r == -ENOMEM)
1579 goto oom;
1580 if (r < 0)
1581 return bus_send_error_reply(connection, message, NULL, r);
1582 if (!strv_env_name_or_assignment_is_valid(l))
1583 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1584
1585 e = strv_env_delete(m->environment, 1, l);
1586 if (!e)
1587 goto oom;
1588
1589 reply = dbus_message_new_method_return(message);
1590 if (!reply) {
1591 strv_free(e);
1592 goto oom;
1593 }
1594
1595 strv_free(m->environment);
1596 m->environment = e;
1597
1598 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetAndSetEnvironment")) {
1599 _cleanup_strv_free_ char **l_set = NULL, **l_unset = NULL, **e = NULL;
1600 char **f = NULL;
1601 DBusMessageIter iter;
1602
1603 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1604
1605 if (!dbus_message_iter_init(message, &iter))
1606 goto oom;
1607
1608 r = bus_parse_strv_iter(&iter, &l_unset);
1609 if (r == -ENOMEM)
1610 goto oom;
1611 if (r < 0)
1612 return bus_send_error_reply(connection, message, NULL, r);
1613 if (!strv_env_name_or_assignment_is_valid(l_unset))
1614 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1615
1616 if (!dbus_message_iter_next(&iter))
1617 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1618
1619 r = bus_parse_strv_iter(&iter, &l_set);
1620 if (r == -ENOMEM)
1621 goto oom;
1622 if (r < 0)
1623 return bus_send_error_reply(connection, message, NULL, r);
1624 if (!strv_env_is_valid(l_set))
1625 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1626
1627 e = strv_env_delete(m->environment, 1, l_unset);
1628 if (!e)
1629 goto oom;
1630
1631 f = strv_env_merge(2, e, l_set);
1632 if (!f)
1633 goto oom;
1634
1635 reply = dbus_message_new_method_return(message);
1636 if (!reply) {
1637 strv_free(f);
1638 goto oom;
1639 }
1640
1641 strv_free(m->environment);
1642 m->environment = f;
1643 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnitFiles")) {
1644 DBusMessageIter iter, sub, sub2;
1645 Hashmap *h;
1646 Iterator i;
1647 UnitFileList *item;
1648
1649 SELINUX_ACCESS_CHECK(connection, message, "status");
1650
1651 reply = dbus_message_new_method_return(message);
1652 if (!reply)
1653 goto oom;
1654
1655 h = hashmap_new(string_hash_func, string_compare_func);
1656 if (!h)
1657 goto oom;
1658
1659 r = unit_file_get_list(m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, h);
1660 if (r < 0) {
1661 unit_file_list_free(h);
1662 return bus_send_error_reply(connection, message, NULL, r);
1663 }
1664
1665 dbus_message_iter_init_append(reply, &iter);
1666
1667 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ss)", &sub)) {
1668 unit_file_list_free(h);
1669 goto oom;
1670 }
1671
1672 HASHMAP_FOREACH(item, h, i) {
1673 const char *state;
1674
1675 state = unit_file_state_to_string(item->state);
1676 assert(state);
1677
1678 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
1679 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &item->path) ||
1680 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &state) ||
1681 !dbus_message_iter_close_container(&sub, &sub2)) {
1682 unit_file_list_free(h);
1683 goto oom;
1684 }
1685 }
1686
1687 unit_file_list_free(h);
1688
1689 if (!dbus_message_iter_close_container(&iter, &sub))
1690 goto oom;
1691
1692 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnitFileState")) {
1693 const char *name;
1694 UnitFileState state;
1695 const char *s;
1696
1697 SELINUX_ACCESS_CHECK(connection, message, "status");
1698
1699 if (!dbus_message_get_args(
1700 message,
1701 &error,
1702 DBUS_TYPE_STRING, &name,
1703 DBUS_TYPE_INVALID))
1704 return bus_send_error_reply(connection, message, &error, -EINVAL);
1705
1706 state = unit_file_get_state(m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, name);
1707 if (state < 0)
1708 return bus_send_error_reply(connection, message, NULL, state);
1709
1710 s = unit_file_state_to_string(state);
1711 assert(s);
1712
1713 reply = dbus_message_new_method_return(message);
1714 if (!reply)
1715 goto oom;
1716
1717 if (!dbus_message_append_args(
1718 reply,
1719 DBUS_TYPE_STRING, &s,
1720 DBUS_TYPE_INVALID))
1721 goto oom;
1722 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "EnableUnitFiles") ||
1723 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReenableUnitFiles") ||
1724 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "LinkUnitFiles") ||
1725 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "PresetUnitFiles") ||
1726 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "MaskUnitFiles")) {
1727
1728 char **l = NULL;
1729 DBusMessageIter iter;
1730 UnitFileScope scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
1731 UnitFileChange *changes = NULL;
1732 unsigned n_changes = 0;
1733 dbus_bool_t runtime, force;
1734 int carries_install_info = -1;
1735
1736 SELINUX_ACCESS_CHECK(connection, message, streq(member, "MaskUnitFiles") ? "disable" : "enable");
1737
1738 if (!dbus_message_iter_init(message, &iter))
1739 goto oom;
1740
1741 r = bus_parse_strv_iter(&iter, &l);
1742 if (r < 0) {
1743 if (r == -ENOMEM)
1744 goto oom;
1745
1746 return bus_send_error_reply(connection, message, NULL, r);
1747 }
1748
1749 if (!dbus_message_iter_next(&iter) ||
1750 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, true) < 0 ||
1751 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &force, false) < 0) {
1752 strv_free(l);
1753 return bus_send_error_reply(connection, message, NULL, -EIO);
1754 }
1755
1756 if (streq(member, "EnableUnitFiles")) {
1757 r = unit_file_enable(scope, runtime, NULL, l, force, &changes, &n_changes);
1758 carries_install_info = r;
1759 } else if (streq(member, "ReenableUnitFiles")) {
1760 r = unit_file_reenable(scope, runtime, NULL, l, force, &changes, &n_changes);
1761 carries_install_info = r;
1762 } else if (streq(member, "LinkUnitFiles"))
1763 r = unit_file_link(scope, runtime, NULL, l, force, &changes, &n_changes);
1764 else if (streq(member, "PresetUnitFiles")) {
1765 r = unit_file_preset(scope, runtime, NULL, l, force, &changes, &n_changes);
1766 carries_install_info = r;
1767 } else if (streq(member, "MaskUnitFiles"))
1768 r = unit_file_mask(scope, runtime, NULL, l, force, &changes, &n_changes);
1769 else
1770 assert_not_reached("Uh? Wrong method");
1771
1772 strv_free(l);
1773 bus_manager_send_unit_files_changed(m);
1774
1775 if (r < 0) {
1776 unit_file_changes_free(changes, n_changes);
1777 return bus_send_error_reply(connection, message, NULL, r);
1778 }
1779
1780 reply = message_from_file_changes(message, changes, n_changes, carries_install_info);
1781 unit_file_changes_free(changes, n_changes);
1782
1783 if (!reply)
1784 goto oom;
1785
1786 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "DisableUnitFiles") ||
1787 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnmaskUnitFiles")) {
1788
1789 char **l = NULL;
1790 DBusMessageIter iter;
1791 UnitFileScope scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
1792 UnitFileChange *changes = NULL;
1793 unsigned n_changes = 0;
1794 dbus_bool_t runtime;
1795
1796 SELINUX_ACCESS_CHECK(connection, message, streq(member, "UnmaskUnitFiles") ? "enable" : "disable");
1797
1798 if (!dbus_message_iter_init(message, &iter))
1799 goto oom;
1800
1801 r = bus_parse_strv_iter(&iter, &l);
1802 if (r < 0) {
1803 if (r == -ENOMEM)
1804 goto oom;
1805
1806 return bus_send_error_reply(connection, message, NULL, r);
1807 }
1808
1809 if (!dbus_message_iter_next(&iter) ||
1810 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, false) < 0) {
1811 strv_free(l);
1812 return bus_send_error_reply(connection, message, NULL, -EIO);
1813 }
1814
1815 if (streq(member, "DisableUnitFiles"))
1816 r = unit_file_disable(scope, runtime, NULL, l, &changes, &n_changes);
1817 else if (streq(member, "UnmaskUnitFiles"))
1818 r = unit_file_unmask(scope, runtime, NULL, l, &changes, &n_changes);
1819 else
1820 assert_not_reached("Uh? Wrong method");
1821
1822 strv_free(l);
1823 bus_manager_send_unit_files_changed(m);
1824
1825 if (r < 0) {
1826 unit_file_changes_free(changes, n_changes);
1827 return bus_send_error_reply(connection, message, NULL, r);
1828 }
1829
1830 reply = message_from_file_changes(message, changes, n_changes, -1);
1831 unit_file_changes_free(changes, n_changes);
1832
1833 if (!reply)
1834 goto oom;
1835
1836 } else {
1837 const BusBoundProperties bps[] = {
1838 { "org.freedesktop.systemd1.Manager", bus_systemd_properties, systemd_property_string },
1839 { "org.freedesktop.systemd1.Manager", bus_manager_properties, m },
1840 { NULL, }
1841 };
1842
1843 SELINUX_ACCESS_CHECK(connection, message, "status");
1844
1845 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
1846 }
1847
1848 if (job_type != _JOB_TYPE_INVALID) {
1849 const char *name, *smode, *old_name = NULL;
1850 JobMode mode;
1851 Unit *u;
1852 dbus_bool_t b;
1853
1854 if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnitReplace"))
1855 b = dbus_message_get_args(
1856 message,
1857 &error,
1858 DBUS_TYPE_STRING, &old_name,
1859 DBUS_TYPE_STRING, &name,
1860 DBUS_TYPE_STRING, &smode,
1861 DBUS_TYPE_INVALID);
1862 else
1863 b = dbus_message_get_args(
1864 message,
1865 &error,
1866 DBUS_TYPE_STRING, &name,
1867 DBUS_TYPE_STRING, &smode,
1868 DBUS_TYPE_INVALID);
1869 if (!b)
1870 return bus_send_error_reply(connection, message, &error, -EINVAL);
1871
1872 if (old_name) {
1873 u = manager_get_unit(m, old_name);
1874 if (!u || !u->job || u->job->type != JOB_START) {
1875 dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "No job queued for unit %s", old_name);
1876 return bus_send_error_reply(connection, message, &error, -ENOENT);
1877 }
1878 }
1879
1880 mode = job_mode_from_string(smode);
1881 if (mode < 0) {
1882 dbus_set_error(&error, BUS_ERROR_INVALID_JOB_MODE, "Job mode %s is invalid.", smode);
1883 return bus_send_error_reply(connection, message, &error, -EINVAL);
1884 }
1885
1886 r = manager_load_unit(m, name, NULL, &error, &u);
1887 if (r < 0)
1888 return bus_send_error_reply(connection, message, &error, r);
1889
1890 return bus_unit_queue_job(connection, message, u, job_type, mode, reload_if_possible);
1891 }
1892
1893 if (reply)
1894 if (!bus_maybe_send_reply(connection, message, reply))
1895 goto oom;
1896
1897 return DBUS_HANDLER_RESULT_HANDLED;
1898
1899 oom:
1900 dbus_error_free(&error);
1901
1902 return DBUS_HANDLER_RESULT_NEED_MEMORY;
1903 }
1904
1905 const DBusObjectPathVTable bus_manager_vtable = {
1906 .message_function = bus_manager_message_handler
1907 };