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