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