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