chiark / gitweb /
7d4703b88b04e4e0c2baa1036442885bad08745e
[elogind.git] / src / dbus-manager.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2010 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU General Public License as published by
10   the Free Software Foundation; either version 2 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <errno.h>
23
24 #include "dbus.h"
25 #include "log.h"
26 #include "dbus-manager.h"
27 #include "strv.h"
28 #include "bus-errors.h"
29 #include "build.h"
30
31 #define BUS_MANAGER_INTERFACE_BEGIN                                     \
32         " <interface name=\"org.freedesktop.systemd1.Manager\">\n"
33
34 #define BUS_MANAGER_INTERFACE_METHODS                                   \
35         "  <method name=\"GetUnit\">\n"                                 \
36         "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
37         "   <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n"        \
38         "  </method>\n"                                                 \
39         "  <method name=\"GetUnitByPID\">\n"                            \
40         "   <arg name=\"pid\" type=\"u\" direction=\"in\"/>\n"          \
41         "   <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n"        \
42         "  </method>\n"                                                 \
43         "  <method name=\"LoadUnit\">\n"                                \
44         "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
45         "   <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n"        \
46         "  </method>\n"                                                 \
47         "  <method name=\"StartUnit\">\n"                               \
48         "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
49         "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
50         "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
51         "  </method>\n"                                                 \
52         "  <method name=\"StartUnitReplace\">\n"                        \
53         "   <arg name=\"old_unit\" type=\"s\" direction=\"in\"/>\n"     \
54         "   <arg name=\"new_unit\" 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"                                                 \
58         "  <method name=\"StopUnit\">\n"                                \
59         "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
60         "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
61         "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
62         "  </method>\n"                                                 \
63         "  <method name=\"ReloadUnit\">\n"                              \
64         "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
65         "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
66         "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
67         "  </method>\n"                                                 \
68         "  <method name=\"RestartUnit\">\n"                             \
69         "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
70         "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
71         "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
72         "  </method>\n"                                                 \
73         "  <method name=\"TryRestartUnit\">\n"                          \
74         "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
75         "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
76         "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
77         "  </method>\n"                                                 \
78         "  <method name=\"ReloadOrRestartUnit\">\n"                     \
79         "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
80         "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
81         "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
82         "  </method>\n"                                                 \
83         "  <method name=\"ReloadOrTryRestartUnit\">\n"                  \
84         "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
85         "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
86         "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
87         "  </method>\n"                                                 \
88         "  <method name=\"KillUnit\">\n"                                \
89         "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
90         "   <arg name=\"who\" type=\"s\" direction=\"in\"/>\n"          \
91         "   <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"         \
92         "   <arg name=\"signal\" type=\"i\" direction=\"in\"/>\n"       \
93         "  </method>\n"                                                 \
94         "  <method name=\"ResetFailedUnit\">\n"                         \
95         "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
96         "  </method>\n"                                                 \
97         "  <method name=\"GetJob\">\n"                                  \
98         "   <arg name=\"id\" type=\"u\" direction=\"in\"/>\n"           \
99         "   <arg name=\"job\" type=\"o\" direction=\"out\"/>\n"         \
100         "  </method>\n"                                                 \
101         "  <method name=\"ClearJobs\"/>\n"                              \
102         "  <method name=\"ResetFailed\"/>\n"                            \
103         "  <method name=\"ListUnits\">\n"                               \
104         "   <arg name=\"units\" type=\"a(ssssssouso)\" direction=\"out\"/>\n" \
105         "  </method>\n"                                                 \
106         "  <method name=\"ListJobs\">\n"                                \
107         "   <arg name=\"jobs\" type=\"a(usssoo)\" direction=\"out\"/>\n" \
108         "  </method>\n"                                                 \
109         "  <method name=\"Subscribe\"/>\n"                              \
110         "  <method name=\"Unsubscribe\"/>\n"                            \
111         "  <method name=\"Dump\"/>\n"                                   \
112         "  <method name=\"CreateSnapshot\">\n"                          \
113         "   <arg name=\"name\" type=\"s\" direction=\"in\"/>\n"         \
114         "   <arg name=\"cleanup\" type=\"b\" direction=\"in\"/>\n"      \
115         "   <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n"        \
116         "  </method>\n"                                                 \
117         "  <method name=\"Reload\"/>\n"                                 \
118         "  <method name=\"Reexecute\"/>\n"                              \
119         "  <method name=\"Exit\"/>\n"                                   \
120         "  <method name=\"Reboot\"/>\n"                                 \
121         "  <method name=\"PowerOff\"/>\n"                               \
122         "  <method name=\"Halt\"/>\n"                                   \
123         "  <method name=\"KExec\"/>\n"                                  \
124         "  <method name=\"SetEnvironment\">\n"                          \
125         "   <arg name=\"names\" type=\"as\" direction=\"in\"/>\n"       \
126         "  </method>\n"                                                 \
127         "  <method name=\"UnsetEnvironment\">\n"                        \
128         "   <arg name=\"names\" type=\"as\" direction=\"in\"/>\n"       \
129         "  </method>\n"
130
131 #define BUS_MANAGER_INTERFACE_SIGNALS                                   \
132         "  <signal name=\"UnitNew\">\n"                                 \
133         "   <arg name=\"id\" type=\"s\"/>\n"                            \
134         "   <arg name=\"unit\" type=\"o\"/>\n"                          \
135         "  </signal>\n"                                                 \
136         "  <signal name=\"UnitRemoved\">\n"                             \
137         "   <arg name=\"id\" type=\"s\"/>\n"                            \
138         "   <arg name=\"unit\" type=\"o\"/>\n"                          \
139         "  </signal>\n"                                                 \
140         "  <signal name=\"JobNew\">\n"                                  \
141         "   <arg name=\"id\" type=\"u\"/>\n"                            \
142         "   <arg name=\"job\" type=\"o\"/>\n"                           \
143         "  </signal>\n"                                                 \
144         "  <signal name=\"JobRemoved\">\n"                              \
145         "   <arg name=\"id\" type=\"u\"/>\n"                            \
146         "   <arg name=\"job\" type=\"o\"/>\n"                           \
147         "   <arg name=\"result\" type=\"s\"/>\n"                        \
148         "  </signal>"
149
150 #define BUS_MANAGER_INTERFACE_PROPERTIES_GENERAL                        \
151         "  <property name=\"Version\" type=\"s\" access=\"read\"/>\n"   \
152         "  <property name=\"Distribution\" type=\"s\" access=\"read\"/>\n" \
153         "  <property name=\"Features\" type=\"s\" access=\"read\"/>\n"  \
154         "  <property name=\"Tainted\" type=\"s\" access=\"read\"/>\n"   \
155         "  <property name=\"RunningAs\" type=\"s\" access=\"read\"/>\n" \
156         "  <property name=\"InitRDTimestamp\" type=\"t\" access=\"read\"/>\n" \
157         "  <property name=\"StartupTimestamp\" type=\"t\" access=\"read\"/>\n" \
158         "  <property name=\"FinishTimestamp\" type=\"t\" access=\"read\"/>\n" \
159         "  <property name=\"LogLevel\" type=\"s\" access=\"readwrite\"/>\n"  \
160         "  <property name=\"LogTarget\" type=\"s\" access=\"readwrite\"/>\n" \
161         "  <property name=\"NNames\" type=\"u\" access=\"read\"/>\n"    \
162         "  <property name=\"NJobs\" type=\"u\" access=\"read\"/>\n"     \
163         "  <property name=\"NInstalledJobs\" type=\"u\" access=\"read\"/>\n" \
164         "  <property name=\"NFailedJobs\" type=\"u\" access=\"read\"/>\n" \
165         "  <property name=\"Progress\" type=\"d\" access=\"read\"/>\n"  \
166         "  <property name=\"Environment\" type=\"as\" access=\"read\"/>\n" \
167         "  <property name=\"ConfirmSpawn\" type=\"b\" access=\"read\"/>\n" \
168         "  <property name=\"ShowStatus\" type=\"b\" access=\"read\"/>\n" \
169         "  <property name=\"UnitPath\" type=\"as\" access=\"read\"/>\n" \
170         "  <property name=\"NotifySocket\" type=\"s\" access=\"read\"/>\n" \
171         "  <property name=\"ControlGroupHierarchy\" type=\"s\" access=\"read\"/>\n" \
172         "  <property name=\"MountAuto\" type=\"b\" access=\"read\"/>\n" \
173         "  <property name=\"SwapAuto\" type=\"b\" access=\"read\"/>\n"  \
174         "  <property name=\"DefaultControllers\" type=\"as\" access=\"read\"/>\n" \
175         "  <property name=\"DefaultStandardOutput\" type=\"s\" access=\"read\"/>\n" \
176         "  <property name=\"DefaultStandardError\" type=\"s\" access=\"read\"/>\n"
177
178 #ifdef HAVE_SYSV_COMPAT
179 #define BUS_MANAGER_INTERFACE_PROPERTIES_SYSV                           \
180         "  <property name=\"SysVConsole\" type=\"b\" access=\"read\"/>\n" \
181         "  <property name=\"SysVInitPath\" type=\"as\" access=\"read\"/>\n" \
182         "  <property name=\"SysVRcndPath\" type=\"as\" access=\"read\"/>\n"
183 #else
184 #define BUS_MANAGER_INTERFACE_PROPERTIES_SYSV
185 #endif
186
187 #define BUS_MANAGER_INTERFACE_END                                       \
188         " </interface>\n"
189
190 #define BUS_MANAGER_INTERFACE                                           \
191         BUS_MANAGER_INTERFACE_BEGIN                                     \
192         BUS_MANAGER_INTERFACE_METHODS                                   \
193         BUS_MANAGER_INTERFACE_SIGNALS                                   \
194         BUS_MANAGER_INTERFACE_PROPERTIES_GENERAL                        \
195         BUS_MANAGER_INTERFACE_PROPERTIES_SYSV                           \
196         BUS_MANAGER_INTERFACE_END
197
198 #define INTROSPECTION_BEGIN                                             \
199         DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE                       \
200         "<node>\n"                                                      \
201         BUS_MANAGER_INTERFACE                                           \
202         BUS_PROPERTIES_INTERFACE                                        \
203         BUS_PEER_INTERFACE                                              \
204         BUS_INTROSPECTABLE_INTERFACE
205
206 #define INTROSPECTION_END                                               \
207         "</node>\n"
208
209 const char bus_manager_interface[] _introspect_("Manager") = BUS_MANAGER_INTERFACE;
210
211 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_running_as, manager_running_as, ManagerRunningAs);
212 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_exec_output, exec_output, ExecOutput);
213
214 static int bus_manager_append_tainted(Manager *m, DBusMessageIter *i, const char *property, void *data) {
215         const char *t;
216         char buf[64] = "", *e = buf, *p = NULL;
217
218         assert(m);
219         assert(i);
220         assert(property);
221
222         if (path_is_mount_point("/usr") > 0 || dir_is_empty("/usr") > 0)
223                 e = stpcpy(e, "usr-separate-fs");
224
225         if (readlink_malloc("/etc/mtab", &p) < 0) {
226                 if (e != buf)
227                         e = stpcpy(e, " ");
228                 e = stpcpy(e, "etc-mtab-not-symlink");
229         } else
230                 free(p);
231
232         t = buf;
233
234         if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
235                 return -ENOMEM;
236
237         return 0;
238 }
239
240 static int bus_manager_append_log_target(Manager *m, DBusMessageIter *i, const char *property, void *data) {
241         const char *t;
242
243         assert(m);
244         assert(i);
245         assert(property);
246
247         t = log_target_to_string(log_get_target());
248
249         if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
250                 return -ENOMEM;
251
252         return 0;
253 }
254
255 static int bus_manager_set_log_target(Manager *m, DBusMessageIter *i, const char *property) {
256         const char *t;
257
258         assert(m);
259         assert(i);
260         assert(property);
261
262         dbus_message_iter_get_basic(i, &t);
263
264         return log_set_target_from_string(t);
265 }
266
267 static int bus_manager_append_log_level(Manager *m, DBusMessageIter *i, const char *property, void *data) {
268         const char *t;
269
270         assert(m);
271         assert(i);
272         assert(property);
273
274         t = log_level_to_string(log_get_max_level());
275
276         if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
277                 return -ENOMEM;
278
279         return 0;
280 }
281
282 static int bus_manager_set_log_level(Manager *m, DBusMessageIter *i, const char *property) {
283         const char *t;
284
285         assert(m);
286         assert(i);
287         assert(property);
288
289         dbus_message_iter_get_basic(i, &t);
290
291         return log_set_max_level_from_string(t);
292 }
293
294 static int bus_manager_append_n_names(Manager *m, DBusMessageIter *i, const char *property, void *data) {
295         uint32_t u;
296
297         assert(m);
298         assert(i);
299         assert(property);
300
301         u = hashmap_size(m->units);
302
303         if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, &u))
304                 return -ENOMEM;
305
306         return 0;
307 }
308
309 static int bus_manager_append_n_jobs(Manager *m, DBusMessageIter *i, const char *property, void *data) {
310         uint32_t u;
311
312         assert(m);
313         assert(i);
314         assert(property);
315
316         u = hashmap_size(m->jobs);
317
318         if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, &u))
319                 return -ENOMEM;
320
321         return 0;
322 }
323
324 static int bus_manager_append_progress(Manager *m, DBusMessageIter *i, const char *property, void *data) {
325         double d;
326
327         assert(m);
328         assert(i);
329         assert(property);
330
331         if (dual_timestamp_is_set(&m->finish_timestamp))
332                 d = 1.0;
333         else
334                 d = 1.0 - ((double) hashmap_size(m->jobs) / (double) m->n_installed_jobs);
335
336         if (!dbus_message_iter_append_basic(i, DBUS_TYPE_DOUBLE, &d))
337                 return -ENOMEM;
338
339         return 0;
340 }
341
342 static const char *message_get_sender_with_fallback(DBusMessage *m) {
343         const char *s;
344
345         assert(m);
346
347         if ((s = dbus_message_get_sender(m)))
348                 return s;
349
350         /* When the message came in from a direct connection the
351          * message will have no sender. We fix that here. */
352
353         return ":no-sender";
354 }
355
356 static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, DBusMessage *message, void *data) {
357         Manager *m = data;
358
359         const BusProperty properties[] = {
360                 { "org.freedesktop.systemd1.Manager", "Version",       bus_property_append_string,    "s",  PACKAGE_STRING     },
361                 { "org.freedesktop.systemd1.Manager", "Distribution",  bus_property_append_string,    "s",  DISTRIBUTION       },
362                 { "org.freedesktop.systemd1.Manager", "Features",      bus_property_append_string,    "s",  SYSTEMD_FEATURES   },
363                 { "org.freedesktop.systemd1.Manager", "RunningAs",     bus_manager_append_running_as, "s",  &m->running_as     },
364                 { "org.freedesktop.systemd1.Manager", "Tainted",       bus_manager_append_tainted,    "s",  m                  },
365                 { "org.freedesktop.systemd1.Manager", "InitRDTimestamp", bus_property_append_uint64,  "t",  &m->initrd_timestamp.realtime },
366                 { "org.freedesktop.systemd1.Manager", "StartupTimestamp", bus_property_append_uint64, "t",  &m->startup_timestamp.realtime },
367                 { "org.freedesktop.systemd1.Manager", "FinishTimestamp", bus_property_append_uint64,  "t",  &m->finish_timestamp.realtime },
368                 { "org.freedesktop.systemd1.Manager", "LogLevel",      bus_manager_append_log_level,  "s",  NULL,               bus_manager_set_log_level},
369                 { "org.freedesktop.systemd1.Manager", "LogTarget",     bus_manager_append_log_target, "s",  NULL,               bus_manager_set_log_target},
370                 { "org.freedesktop.systemd1.Manager", "NNames",        bus_manager_append_n_names,    "u",  NULL               },
371                 { "org.freedesktop.systemd1.Manager", "NJobs",         bus_manager_append_n_jobs,     "u",  NULL               },
372                 { "org.freedesktop.systemd1.Manager", "NInstalledJobs",bus_property_append_uint32,    "u",  &m->n_installed_jobs },
373                 { "org.freedesktop.systemd1.Manager", "NFailedJobs",   bus_property_append_uint32,    "u",  &m->n_failed_jobs  },
374                 { "org.freedesktop.systemd1.Manager", "Progress",      bus_manager_append_progress,   "d",  NULL               },
375                 { "org.freedesktop.systemd1.Manager", "Environment",   bus_property_append_strv,      "as", m->environment     },
376                 { "org.freedesktop.systemd1.Manager", "ConfirmSpawn",  bus_property_append_bool,      "b",  &m->confirm_spawn  },
377                 { "org.freedesktop.systemd1.Manager", "ShowStatus",    bus_property_append_bool,      "b",  &m->show_status    },
378                 { "org.freedesktop.systemd1.Manager", "UnitPath",      bus_property_append_strv,      "as", m->lookup_paths.unit_path },
379                 { "org.freedesktop.systemd1.Manager", "NotifySocket",  bus_property_append_string,    "s",  m->notify_socket   },
380                 { "org.freedesktop.systemd1.Manager", "ControlGroupHierarchy", bus_property_append_string, "s", m->cgroup_hierarchy },
381                 { "org.freedesktop.systemd1.Manager", "MountAuto",     bus_property_append_bool,      "b",  &m->mount_auto     },
382                 { "org.freedesktop.systemd1.Manager", "SwapAuto",      bus_property_append_bool,      "b",  &m->swap_auto      },
383                 { "org.freedesktop.systemd1.Manager", "DefaultControllers", bus_property_append_strv, "as", m->default_controllers },
384                 { "org.freedesktop.systemd1.Manager", "DefaultStandardOutput", bus_manager_append_exec_output, "s", &m->default_std_output },
385                 { "org.freedesktop.systemd1.Manager", "DefaultStandardError",  bus_manager_append_exec_output, "s", &m->default_std_error  },
386 #ifdef HAVE_SYSV_COMPAT
387                 { "org.freedesktop.systemd1.Manager", "SysVConsole",   bus_property_append_bool,      "b",  &m->sysv_console   },
388                 { "org.freedesktop.systemd1.Manager", "SysVInitPath",  bus_property_append_strv,      "as", m->lookup_paths.sysvinit_path },
389                 { "org.freedesktop.systemd1.Manager", "SysVRcndPath",  bus_property_append_strv,      "as", m->lookup_paths.sysvrcnd_path },
390 #endif
391                 { NULL, NULL, NULL, NULL, NULL }
392         };
393
394         int r;
395         DBusError error;
396         DBusMessage *reply = NULL;
397         char * path = NULL;
398         JobType job_type = _JOB_TYPE_INVALID;
399         bool reload_if_possible = false;
400
401         assert(connection);
402         assert(message);
403         assert(m);
404
405         dbus_error_init(&error);
406
407         if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnit")) {
408                 const char *name;
409                 Unit *u;
410
411                 if (!dbus_message_get_args(
412                                     message,
413                                     &error,
414                                     DBUS_TYPE_STRING, &name,
415                                     DBUS_TYPE_INVALID))
416                         return bus_send_error_reply(m, connection, message, &error, -EINVAL);
417
418                 if (!(u = manager_get_unit(m, name))) {
419                         dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
420                         return bus_send_error_reply(m, connection, message, &error, -ENOENT);
421                 }
422
423                 if (!(reply = dbus_message_new_method_return(message)))
424                         goto oom;
425
426                 if (!(path = unit_dbus_path(u)))
427                         goto oom;
428
429                 if (!dbus_message_append_args(
430                                     reply,
431                                     DBUS_TYPE_OBJECT_PATH, &path,
432                                     DBUS_TYPE_INVALID))
433                         goto oom;
434         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnitByPID")) {
435                 Unit *u;
436                 uint32_t pid;
437
438                 if (!dbus_message_get_args(
439                                     message,
440                                     &error,
441                                     DBUS_TYPE_UINT32, &pid,
442                                     DBUS_TYPE_INVALID))
443                         return bus_send_error_reply(m, connection, message, &error, -EINVAL);
444
445                 if (!(u = cgroup_unit_by_pid(m, (pid_t) pid))) {
446                         dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "No unit for PID %lu is loaded.", (unsigned long) pid);
447                         return bus_send_error_reply(m, connection, message, &error, -ENOENT);
448                 }
449
450                 if (!(reply = dbus_message_new_method_return(message)))
451                         goto oom;
452
453                 if (!(path = unit_dbus_path(u)))
454                         goto oom;
455
456                 if (!dbus_message_append_args(
457                                     reply,
458                                     DBUS_TYPE_OBJECT_PATH, &path,
459                                     DBUS_TYPE_INVALID))
460                         goto oom;
461         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "LoadUnit")) {
462                 const char *name;
463                 Unit *u;
464
465                 if (!dbus_message_get_args(
466                                     message,
467                                     &error,
468                                     DBUS_TYPE_STRING, &name,
469                                     DBUS_TYPE_INVALID))
470                         return bus_send_error_reply(m, connection, message, &error, -EINVAL);
471
472                 if ((r = manager_load_unit(m, name, NULL, &error, &u)) < 0)
473                         return bus_send_error_reply(m, connection, message, &error, r);
474
475                 if (!(reply = dbus_message_new_method_return(message)))
476                         goto oom;
477
478                 if (!(path = unit_dbus_path(u)))
479                         goto oom;
480
481                 if (!dbus_message_append_args(
482                                     reply,
483                                     DBUS_TYPE_OBJECT_PATH, &path,
484                                     DBUS_TYPE_INVALID))
485                         goto oom;
486
487         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnit"))
488                 job_type = JOB_START;
489         else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnitReplace"))
490                 job_type = JOB_START;
491         else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StopUnit"))
492                 job_type = JOB_STOP;
493         else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadUnit"))
494                 job_type = JOB_RELOAD;
495         else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "RestartUnit"))
496                 job_type = JOB_RESTART;
497         else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "TryRestartUnit"))
498                 job_type = JOB_TRY_RESTART;
499         else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadOrRestartUnit")) {
500                 reload_if_possible = true;
501                 job_type = JOB_RESTART;
502         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadOrTryRestartUnit")) {
503                 reload_if_possible = true;
504                 job_type = JOB_TRY_RESTART;
505         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "KillUnit")) {
506                 const char *name, *swho, *smode;
507                 int32_t signo;
508                 Unit *u;
509                 KillMode mode;
510                 KillWho who;
511
512                 if (!dbus_message_get_args(
513                                     message,
514                                     &error,
515                                     DBUS_TYPE_STRING, &name,
516                                     DBUS_TYPE_STRING, &swho,
517                                     DBUS_TYPE_STRING, &smode,
518                                     DBUS_TYPE_INT32, &signo,
519                                     DBUS_TYPE_INVALID))
520                         return bus_send_error_reply(m, connection, message, &error, -EINVAL);
521
522                 if ((mode = kill_mode_from_string(smode)) < 0 ||
523                     (who = kill_who_from_string(swho)) < 0 ||
524                     signo <= 0 ||
525                     signo >= _NSIG)
526                         return bus_send_error_reply(m, connection, message, &error, -EINVAL);
527
528                 if (!(u = manager_get_unit(m, name))) {
529                         dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
530                         return bus_send_error_reply(m, connection, message, &error, -ENOENT);
531                 }
532
533                 if ((r = unit_kill(u, who, mode, signo, &error)) < 0)
534                         return bus_send_error_reply(m, connection, message, &error, r);
535
536                 if (!(reply = dbus_message_new_method_return(message)))
537                         goto oom;
538
539         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetJob")) {
540                 uint32_t id;
541                 Job *j;
542
543                 if (!dbus_message_get_args(
544                                     message,
545                                     &error,
546                                     DBUS_TYPE_UINT32, &id,
547                                     DBUS_TYPE_INVALID))
548                         return bus_send_error_reply(m, connection, message, &error, -EINVAL);
549
550                 if (!(j = manager_get_job(m, id))) {
551                         dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "Job %u does not exist.", (unsigned) id);
552                         return bus_send_error_reply(m, connection, message, &error, -ENOENT);
553                 }
554
555                 if (!(reply = dbus_message_new_method_return(message)))
556                         goto oom;
557
558                 if (!(path = job_dbus_path(j)))
559                         goto oom;
560
561                 if (!dbus_message_append_args(
562                                     reply,
563                                     DBUS_TYPE_OBJECT_PATH, &path,
564                                     DBUS_TYPE_INVALID))
565                         goto oom;
566
567         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ClearJobs")) {
568
569                 manager_clear_jobs(m);
570
571                 if (!(reply = dbus_message_new_method_return(message)))
572                         goto oom;
573
574         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ResetFailed")) {
575
576                 manager_reset_failed(m);
577
578                 if (!(reply = dbus_message_new_method_return(message)))
579                         goto oom;
580
581         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ResetFailedUnit")) {
582                 const char *name;
583                 Unit *u;
584
585                 if (!dbus_message_get_args(
586                                     message,
587                                     &error,
588                                     DBUS_TYPE_STRING, &name,
589                                     DBUS_TYPE_INVALID))
590                         return bus_send_error_reply(m, connection, message, &error, -EINVAL);
591
592                 if (!(u = manager_get_unit(m, name))) {
593                         dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
594                         return bus_send_error_reply(m, connection, message, &error, -ENOENT);
595                 }
596
597                 unit_reset_failed(u);
598
599                 if (!(reply = dbus_message_new_method_return(message)))
600                         goto oom;
601
602         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnits")) {
603                 DBusMessageIter iter, sub;
604                 Iterator i;
605                 Unit *u;
606                 const char *k;
607
608                 if (!(reply = dbus_message_new_method_return(message)))
609                         goto oom;
610
611                 dbus_message_iter_init_append(reply, &iter);
612
613                 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssssouso)", &sub))
614                         goto oom;
615
616                 HASHMAP_FOREACH_KEY(u, k, m->units, i) {
617                         char *u_path, *j_path;
618                         const char *description, *load_state, *active_state, *sub_state, *sjob_type, *following;
619                         DBusMessageIter sub2;
620                         uint32_t job_id;
621                         Unit *f;
622
623                         if (k != u->meta.id)
624                                 continue;
625
626                         if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
627                                 goto oom;
628
629                         description = unit_description(u);
630                         load_state = unit_load_state_to_string(u->meta.load_state);
631                         active_state = unit_active_state_to_string(unit_active_state(u));
632                         sub_state = unit_sub_state_to_string(u);
633
634                         f = unit_following(u);
635                         following = f ? f->meta.id : "";
636
637                         if (!(u_path = unit_dbus_path(u)))
638                                 goto oom;
639
640                         if (u->meta.job) {
641                                 job_id = (uint32_t) u->meta.job->id;
642
643                                 if (!(j_path = job_dbus_path(u->meta.job))) {
644                                         free(u_path);
645                                         goto oom;
646                                 }
647
648                                 sjob_type = job_type_to_string(u->meta.job->type);
649                         } else {
650                                 job_id = 0;
651                                 j_path = u_path;
652                                 sjob_type = "";
653                         }
654
655                         if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &u->meta.id) ||
656                             !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &description) ||
657                             !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &load_state) ||
658                             !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &active_state) ||
659                             !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &sub_state) ||
660                             !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &following) ||
661                             !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &u_path) ||
662                             !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &job_id) ||
663                             !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &sjob_type) ||
664                             !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &j_path)) {
665                                 free(u_path);
666                                 if (u->meta.job)
667                                         free(j_path);
668                                 goto oom;
669                         }
670
671                         free(u_path);
672                         if (u->meta.job)
673                                 free(j_path);
674
675                         if (!dbus_message_iter_close_container(&sub, &sub2))
676                                 goto oom;
677                 }
678
679                 if (!dbus_message_iter_close_container(&iter, &sub))
680                         goto oom;
681
682         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListJobs")) {
683                 DBusMessageIter iter, sub;
684                 Iterator i;
685                 Job *j;
686
687                 if (!(reply = dbus_message_new_method_return(message)))
688                         goto oom;
689
690                 dbus_message_iter_init_append(reply, &iter);
691
692                 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(usssoo)", &sub))
693                         goto oom;
694
695                 HASHMAP_FOREACH(j, m->jobs, i) {
696                         char *u_path, *j_path;
697                         const char *state, *type;
698                         uint32_t id;
699                         DBusMessageIter sub2;
700
701                         if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
702                                 goto oom;
703
704                         id = (uint32_t) j->id;
705                         state = job_state_to_string(j->state);
706                         type = job_type_to_string(j->type);
707
708                         if (!(j_path = job_dbus_path(j)))
709                                 goto oom;
710
711                         if (!(u_path = unit_dbus_path(j->unit))) {
712                                 free(j_path);
713                                 goto oom;
714                         }
715
716                         if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &id) ||
717                             !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &j->unit->meta.id) ||
718                             !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &type) ||
719                             !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &state) ||
720                             !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &j_path) ||
721                             !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &u_path)) {
722                                 free(j_path);
723                                 free(u_path);
724                                 goto oom;
725                         }
726
727                         free(j_path);
728                         free(u_path);
729
730                         if (!dbus_message_iter_close_container(&sub, &sub2))
731                                 goto oom;
732                 }
733
734                 if (!dbus_message_iter_close_container(&iter, &sub))
735                         goto oom;
736
737         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Subscribe")) {
738                 char *client;
739                 Set *s;
740
741                 if (!(s = BUS_CONNECTION_SUBSCRIBED(m, connection))) {
742                         if (!(s = set_new(string_hash_func, string_compare_func)))
743                                 goto oom;
744
745                         if (!(dbus_connection_set_data(connection, m->subscribed_data_slot, s, NULL))) {
746                                 set_free(s);
747                                 goto oom;
748                         }
749                 }
750
751                 if (!(client = strdup(message_get_sender_with_fallback(message))))
752                         goto oom;
753
754                 if ((r = set_put(s, client)) < 0) {
755                         free(client);
756                         return bus_send_error_reply(m, connection, message, NULL, r);
757                 }
758
759                 if (!(reply = dbus_message_new_method_return(message)))
760                         goto oom;
761
762         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Unsubscribe")) {
763                 char *client;
764
765                 if (!(client = set_remove(BUS_CONNECTION_SUBSCRIBED(m, connection), (char*) message_get_sender_with_fallback(message)))) {
766                         dbus_set_error(&error, BUS_ERROR_NOT_SUBSCRIBED, "Client is not subscribed.");
767                         return bus_send_error_reply(m, connection, message, &error, -ENOENT);
768                 }
769
770                 free(client);
771
772                 if (!(reply = dbus_message_new_method_return(message)))
773                         goto oom;
774
775         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Dump")) {
776                 FILE *f;
777                 char *dump = NULL;
778                 size_t size;
779
780                 if (!(reply = dbus_message_new_method_return(message)))
781                         goto oom;
782
783                 if (!(f = open_memstream(&dump, &size)))
784                         goto oom;
785
786                 manager_dump_units(m, f, NULL);
787                 manager_dump_jobs(m, f, NULL);
788
789                 if (ferror(f)) {
790                         fclose(f);
791                         free(dump);
792                         goto oom;
793                 }
794
795                 fclose(f);
796
797                 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &dump, DBUS_TYPE_INVALID)) {
798                         free(dump);
799                         goto oom;
800                 }
801
802                 free(dump);
803         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "CreateSnapshot")) {
804                 const char *name;
805                 dbus_bool_t cleanup;
806                 Snapshot *s;
807
808                 if (!dbus_message_get_args(
809                                     message,
810                                     &error,
811                                     DBUS_TYPE_STRING, &name,
812                                     DBUS_TYPE_BOOLEAN, &cleanup,
813                                     DBUS_TYPE_INVALID))
814                         return bus_send_error_reply(m, connection, message, &error, -EINVAL);
815
816                 if (name && name[0] == 0)
817                         name = NULL;
818
819                 if ((r = snapshot_create(m, name, cleanup, &error, &s)) < 0)
820                         return bus_send_error_reply(m, connection, message, &error, r);
821
822                 if (!(reply = dbus_message_new_method_return(message)))
823                         goto oom;
824
825                 if (!(path = unit_dbus_path(UNIT(s))))
826                         goto oom;
827
828                 if (!dbus_message_append_args(
829                                     reply,
830                                     DBUS_TYPE_OBJECT_PATH, &path,
831                                     DBUS_TYPE_INVALID))
832                         goto oom;
833
834         } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
835                 char *introspection = NULL;
836                 FILE *f;
837                 Iterator i;
838                 Unit *u;
839                 Job *j;
840                 const char *k;
841                 size_t size;
842
843                 if (!(reply = dbus_message_new_method_return(message)))
844                         goto oom;
845
846                 /* We roll our own introspection code here, instead of
847                  * relying on bus_default_message_handler() because we
848                  * need to generate our introspection string
849                  * dynamically. */
850
851                 if (!(f = open_memstream(&introspection, &size)))
852                         goto oom;
853
854                 fputs(INTROSPECTION_BEGIN, f);
855
856                 HASHMAP_FOREACH_KEY(u, k, m->units, i) {
857                         char *p;
858
859                         if (k != u->meta.id)
860                                 continue;
861
862                         if (!(p = bus_path_escape(k))) {
863                                 fclose(f);
864                                 free(introspection);
865                                 goto oom;
866                         }
867
868                         fprintf(f, "<node name=\"unit/%s\"/>", p);
869                         free(p);
870                 }
871
872                 HASHMAP_FOREACH(j, m->jobs, i)
873                         fprintf(f, "<node name=\"job/%lu\"/>", (unsigned long) j->id);
874
875                 fputs(INTROSPECTION_END, f);
876
877                 if (ferror(f)) {
878                         fclose(f);
879                         free(introspection);
880                         goto oom;
881                 }
882
883                 fclose(f);
884
885                 if (!introspection)
886                         goto oom;
887
888                 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
889                         free(introspection);
890                         goto oom;
891                 }
892
893                 free(introspection);
894
895         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reload")) {
896
897                 assert(!m->queued_message);
898
899                 /* Instead of sending the reply back right away, we
900                  * just remember that we need to and then send it
901                  * after the reload is finished. That way the caller
902                  * knows when the reload finished. */
903
904                 if (!(m->queued_message = dbus_message_new_method_return(message)))
905                         goto oom;
906
907                 m->queued_message_connection = connection;
908                 m->exit_code = MANAGER_RELOAD;
909
910         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reexecute")) {
911
912                 if (!(reply = dbus_message_new_method_return(message)))
913                         goto oom;
914
915                 m->exit_code = MANAGER_REEXECUTE;
916
917         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Exit")) {
918
919                 if (m->running_as == MANAGER_SYSTEM) {
920                         dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Exit is only supported for user service managers.");
921                         return bus_send_error_reply(m, connection, message, &error, -ENOTSUP);
922                 }
923
924                 if (!(reply = dbus_message_new_method_return(message)))
925                         goto oom;
926
927                 m->exit_code = MANAGER_EXIT;
928
929         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reboot")) {
930
931                 if (m->running_as != MANAGER_SYSTEM) {
932                         dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Reboot is only supported for system managers.");
933                         return bus_send_error_reply(m, connection, message, &error, -ENOTSUP);
934                 }
935
936                 if (!(reply = dbus_message_new_method_return(message)))
937                         goto oom;
938
939                 m->exit_code = MANAGER_REBOOT;
940
941         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "PowerOff")) {
942
943                 if (m->running_as != MANAGER_SYSTEM) {
944                         dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Powering off is only supported for system managers.");
945                         return bus_send_error_reply(m, connection, message, &error, -ENOTSUP);
946                 }
947
948                 if (!(reply = dbus_message_new_method_return(message)))
949                         goto oom;
950
951                 m->exit_code = MANAGER_POWEROFF;
952
953         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Halt")) {
954
955                 if (m->running_as != MANAGER_SYSTEM) {
956                         dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Halting is only supported for system managers.");
957                         return bus_send_error_reply(m, connection, message, &error, -ENOTSUP);
958                 }
959
960                 if (!(reply = dbus_message_new_method_return(message)))
961                         goto oom;
962
963                 m->exit_code = MANAGER_HALT;
964
965         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "KExec")) {
966
967                 if (m->running_as != MANAGER_SYSTEM) {
968                         dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "kexec is only supported for system managers.");
969                         return bus_send_error_reply(m, connection, message, &error, -ENOTSUP);
970                 }
971
972                 if (!(reply = dbus_message_new_method_return(message)))
973                         goto oom;
974
975                 m->exit_code = MANAGER_KEXEC;
976
977         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetEnvironment")) {
978                 char **l = NULL, **e = NULL;
979
980                 if ((r = bus_parse_strv(message, &l)) < 0) {
981                         if (r == -ENOMEM)
982                                 goto oom;
983
984                         return bus_send_error_reply(m, connection, message, NULL, r);
985                 }
986
987                 e = strv_env_merge(2, m->environment, l);
988                 strv_free(l);
989
990                 if (!e)
991                         goto oom;
992
993                 if (!(reply = dbus_message_new_method_return(message))) {
994                         strv_free(e);
995                         goto oom;
996                 }
997
998                 strv_free(m->environment);
999                 m->environment = e;
1000
1001         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetEnvironment")) {
1002                 char **l = NULL, **e = NULL;
1003
1004                 if ((r = bus_parse_strv(message, &l)) < 0) {
1005                         if (r == -ENOMEM)
1006                                 goto oom;
1007
1008                         return bus_send_error_reply(m, connection, message, NULL, r);
1009                 }
1010
1011                 e = strv_env_delete(m->environment, 1, l);
1012                 strv_free(l);
1013
1014                 if (!e)
1015                         goto oom;
1016
1017                 if (!(reply = dbus_message_new_method_return(message)))
1018                         goto oom;
1019
1020                 strv_free(m->environment);
1021                 m->environment = e;
1022
1023         } else
1024                 return bus_default_message_handler(m, connection, message, NULL, properties);
1025
1026         if (job_type != _JOB_TYPE_INVALID) {
1027                 const char *name, *smode, *old_name = NULL;
1028                 JobMode mode;
1029                 Job *j;
1030                 Unit *u;
1031                 bool b;
1032
1033                 if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnitReplace"))
1034                         b = dbus_message_get_args(
1035                                         message,
1036                                         &error,
1037                                         DBUS_TYPE_STRING, &old_name,
1038                                         DBUS_TYPE_STRING, &name,
1039                                         DBUS_TYPE_STRING, &smode,
1040                                         DBUS_TYPE_INVALID);
1041                 else
1042                         b = dbus_message_get_args(
1043                                         message,
1044                                         &error,
1045                                         DBUS_TYPE_STRING, &name,
1046                                         DBUS_TYPE_STRING, &smode,
1047                                         DBUS_TYPE_INVALID);
1048
1049                 if (!b)
1050                         return bus_send_error_reply(m, connection, message, &error, -EINVAL);
1051
1052                 if (old_name)
1053                         if (!(u = manager_get_unit(m, old_name)) ||
1054                             !u->meta.job ||
1055                             u->meta.job->type != JOB_START) {
1056                                 dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "No job queued for unit %s", old_name);
1057                                 return bus_send_error_reply(m, connection, message, &error, -ENOENT);
1058                         }
1059
1060
1061                 if ((mode = job_mode_from_string(smode)) == _JOB_MODE_INVALID) {
1062                         dbus_set_error(&error, BUS_ERROR_INVALID_JOB_MODE, "Job mode %s is invalid.", smode);
1063                         return bus_send_error_reply(m, connection, message, &error, -EINVAL);
1064                 }
1065
1066                 if ((r = manager_load_unit(m, name, NULL, &error, &u)) < 0)
1067                         return bus_send_error_reply(m, connection, message, &error, r);
1068
1069                 if (reload_if_possible && unit_can_reload(u)) {
1070                         if (job_type == JOB_RESTART)
1071                                 job_type = JOB_RELOAD_OR_START;
1072                         else if (job_type == JOB_TRY_RESTART)
1073                                 job_type = JOB_RELOAD;
1074                 }
1075
1076                 if ((job_type == JOB_START && u->meta.refuse_manual_start) ||
1077                     (job_type == JOB_STOP && u->meta.refuse_manual_stop) ||
1078                     ((job_type == JOB_RESTART || job_type == JOB_TRY_RESTART) &&
1079                      (u->meta.refuse_manual_start || u->meta.refuse_manual_stop))) {
1080                         dbus_set_error(&error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, may be requested by dependency only.");
1081                         return bus_send_error_reply(m, connection, message, &error, -EPERM);
1082                 }
1083
1084                 if ((r = manager_add_job(m, job_type, u, mode, true, &error, &j)) < 0)
1085                         return bus_send_error_reply(m, connection, message, &error, r);
1086
1087                 if (!(j->bus_client = strdup(message_get_sender_with_fallback(message))))
1088                         goto oom;
1089
1090                 j->bus = connection;
1091
1092                 if (!(reply = dbus_message_new_method_return(message)))
1093                         goto oom;
1094
1095                 if (!(path = job_dbus_path(j)))
1096                         goto oom;
1097
1098                 if (!dbus_message_append_args(
1099                                     reply,
1100                                     DBUS_TYPE_OBJECT_PATH, &path,
1101                                     DBUS_TYPE_INVALID))
1102                         goto oom;
1103         }
1104
1105         free(path);
1106
1107         if (reply) {
1108                 if (!dbus_connection_send(connection, reply, NULL))
1109                         goto oom;
1110
1111                 dbus_message_unref(reply);
1112         }
1113
1114         return DBUS_HANDLER_RESULT_HANDLED;
1115
1116 oom:
1117         free(path);
1118
1119         if (reply)
1120                 dbus_message_unref(reply);
1121
1122         dbus_error_free(&error);
1123
1124         return DBUS_HANDLER_RESULT_NEED_MEMORY;
1125 }
1126
1127 const DBusObjectPathVTable bus_manager_vtable = {
1128         .message_function = bus_manager_message_handler
1129 };