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