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