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