]>
Commit | Line | Data |
---|---|---|
ea430986 LP |
1 | /*-*- Mode: C; c-basic-offset: 8 -*-*/ |
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" |
ea430986 | 28 | |
4288f619 LP |
29 | #define BUS_MANAGER_INTERFACE \ |
30 | " <interface name=\"org.freedesktop.systemd1.Manager\">\n" \ | |
31 | " <method name=\"GetUnit\">\n" \ | |
32 | " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \ | |
33 | " <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n" \ | |
34 | " </method>\n" \ | |
35 | " <method name=\"LoadUnit\">\n" \ | |
36 | " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \ | |
37 | " <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n" \ | |
38 | " </method>\n" \ | |
c87eba54 LP |
39 | " <method name=\"StartUnit\">\n" \ |
40 | " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \ | |
41 | " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \ | |
42 | " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \ | |
43 | " </method>\n" \ | |
44 | " <method name=\"StopUnit\">\n" \ | |
45 | " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \ | |
46 | " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \ | |
47 | " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \ | |
48 | " </method>\n" \ | |
49 | " <method name=\"ReloadUnit\">\n" \ | |
50 | " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \ | |
51 | " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \ | |
52 | " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \ | |
53 | " </method>\n" \ | |
54 | " <method name=\"RestartUnit\">\n" \ | |
55 | " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \ | |
56 | " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \ | |
57 | " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \ | |
58 | " </method>\n" \ | |
4288f619 LP |
59 | " <method name=\"GetJob\">\n" \ |
60 | " <arg name=\"id\" type=\"u\" direction=\"in\"/>\n" \ | |
61 | " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \ | |
62 | " </method>\n" \ | |
63 | " <method name=\"ClearJobs\"/>\n" \ | |
64 | " <method name=\"ListUnits\">\n" \ | |
65 | " <arg name=\"units\" type=\"a(sssssouso)\" direction=\"out\"/>\n" \ | |
66 | " </method>\n" \ | |
67 | " <method name=\"ListJobs\">\n" \ | |
68 | " <arg name=\"jobs\" type=\"a(usssoo)\" direction=\"out\"/>\n" \ | |
69 | " </method>\n" \ | |
70 | " <method name=\"Subscribe\"/>\n" \ | |
71 | " <method name=\"Unsubscribe\"/>\n" \ | |
72 | " <method name=\"Dump\"/>\n" \ | |
73 | " <method name=\"CreateSnapshot\">\n" \ | |
74 | " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \ | |
75 | " <arg nane=\"cleanup\" type=\"b\" direction=\"in\"/>\n" \ | |
76 | " <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n" \ | |
77 | " </method>\n" \ | |
78 | " <method name=\"Reload\"/>\n" \ | |
79 | " <method name=\"Reexecute\"/>\n" \ | |
80 | " <method name=\"Exit\"/>\n" \ | |
81 | " <method name=\"SetEnvironment\">\n" \ | |
82 | " <arg name=\"names\" type=\"as\" direction=\"in\"/>\n" \ | |
83 | " </method>\n" \ | |
84 | " <method name=\"UnsetEnvironment\">\n" \ | |
85 | " <arg name=\"names\" type=\"as\" direction=\"in\"/>\n" \ | |
86 | " </method>\n" \ | |
87 | " <signal name=\"UnitNew\">\n" \ | |
88 | " <arg name=\"id\" type=\"s\"/>\n" \ | |
89 | " <arg name=\"unit\" type=\"o\"/>\n" \ | |
90 | " </signal>\n" \ | |
91 | " <signal name=\"UnitRemoved\">\n" \ | |
92 | " <arg name=\"id\" type=\"s\"/>\n" \ | |
93 | " <arg name=\"unit\" type=\"o\"/>\n" \ | |
94 | " </signal>\n" \ | |
95 | " <signal name=\"JobNew\">\n" \ | |
96 | " <arg name=\"id\" type=\"u\"/>\n" \ | |
97 | " <arg name=\"job\" type=\"o\"/>\n" \ | |
98 | " </signal>\n" \ | |
99 | " <signal name=\"JobRemoved\">\n" \ | |
100 | " <arg name=\"id\" type=\"u\"/>\n" \ | |
101 | " <arg name=\"job\" type=\"o\"/>\n" \ | |
102 | " <arg name=\"success\" type=\"b\"/>\n" \ | |
103 | " </signal>" \ | |
104 | " <property name=\"Version\" type=\"s\" access=\"read\"/>\n" \ | |
105 | " <property name=\"RunningAs\" type=\"s\" access=\"read\"/>\n" \ | |
106 | " <property name=\"BootTimestamp\" type=\"t\" access=\"read\"/>\n" \ | |
107 | " <property name=\"LogLevel\" type=\"s\" access=\"read\"/>\n" \ | |
108 | " <property name=\"LogTarget\" type=\"s\" access=\"read\"/>\n" \ | |
109 | " <property name=\"NNames\" type=\"u\" access=\"read\"/>\n" \ | |
110 | " <property name=\"NJobs\" type=\"u\" access=\"read\"/>\n" \ | |
111 | " <property name=\"Environment\" type=\"as\" access=\"read\"/>\n" \ | |
112 | " </interface>\n" | |
113 | ||
ea430986 LP |
114 | #define INTROSPECTION_BEGIN \ |
115 | DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \ | |
4288f619 LP |
116 | "<node>\n" \ |
117 | BUS_MANAGER_INTERFACE \ | |
ea430986 LP |
118 | BUS_PROPERTIES_INTERFACE \ |
119 | BUS_INTROSPECTABLE_INTERFACE | |
120 | ||
121 | #define INTROSPECTION_END \ | |
4288f619 LP |
122 | "</node>\n" |
123 | ||
124 | const char bus_manager_interface[] = BUS_MANAGER_INTERFACE; | |
ea430986 | 125 | |
4139c1b2 | 126 | static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_running_as, manager_running_as, ManagerRunningAs); |
1adf1049 LP |
127 | |
128 | static int bus_manager_append_log_target(Manager *m, DBusMessageIter *i, const char *property, void *data) { | |
129 | const char *t; | |
130 | ||
131 | assert(m); | |
132 | assert(i); | |
133 | assert(property); | |
134 | ||
135 | t = log_target_to_string(log_get_target()); | |
136 | ||
137 | if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t)) | |
138 | return -ENOMEM; | |
139 | ||
140 | return 0; | |
141 | } | |
142 | ||
143 | static int bus_manager_append_log_level(Manager *m, DBusMessageIter *i, const char *property, void *data) { | |
144 | const char *t; | |
145 | ||
146 | assert(m); | |
147 | assert(i); | |
148 | assert(property); | |
149 | ||
150 | t = log_level_to_string(log_get_max_level()); | |
151 | ||
152 | if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t)) | |
153 | return -ENOMEM; | |
154 | ||
155 | return 0; | |
156 | } | |
157 | ||
4f0f902f LP |
158 | static int bus_manager_append_n_names(Manager *m, DBusMessageIter *i, const char *property, void *data) { |
159 | uint32_t u; | |
160 | ||
161 | assert(m); | |
162 | assert(i); | |
163 | assert(property); | |
164 | ||
165 | u = hashmap_size(m->units); | |
166 | ||
167 | if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, &u)) | |
168 | return -ENOMEM; | |
169 | ||
170 | return 0; | |
171 | } | |
172 | ||
173 | static int bus_manager_append_n_jobs(Manager *m, DBusMessageIter *i, const char *property, void *data) { | |
174 | uint32_t u; | |
175 | ||
176 | assert(m); | |
177 | assert(i); | |
178 | assert(property); | |
179 | ||
180 | u = hashmap_size(m->jobs); | |
181 | ||
182 | if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, &u)) | |
183 | return -ENOMEM; | |
184 | ||
185 | return 0; | |
186 | } | |
187 | ||
47be870b | 188 | static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, DBusMessage *message, void *data) { |
ea430986 | 189 | Manager *m = data; |
1adf1049 LP |
190 | |
191 | const BusProperty properties[] = { | |
4139c1b2 LP |
192 | { "org.freedesktop.systemd1.Manager", "Version", bus_property_append_string, "s", PACKAGE_STRING }, |
193 | { "org.freedesktop.systemd1.Manager", "RunningAs", bus_manager_append_running_as, "s", &m->running_as }, | |
871d7de4 | 194 | { "org.freedesktop.systemd1.Manager", "BootTimestamp", bus_property_append_uint64, "t", &m->startup_timestamp.realtime }, |
4139c1b2 LP |
195 | { "org.freedesktop.systemd1.Manager", "LogLevel", bus_manager_append_log_level, "s", NULL }, |
196 | { "org.freedesktop.systemd1.Manager", "LogTarget", bus_manager_append_log_target, "s", NULL }, | |
4f0f902f LP |
197 | { "org.freedesktop.systemd1.Manager", "NNames", bus_manager_append_n_names, "u", NULL }, |
198 | { "org.freedesktop.systemd1.Manager", "NJobs", bus_manager_append_n_jobs, "u", NULL }, | |
1137a57c | 199 | { "org.freedesktop.systemd1.Manager", "Environment", bus_property_append_strv, "as", m->environment }, |
1adf1049 LP |
200 | { NULL, NULL, NULL, NULL, NULL } |
201 | }; | |
202 | ||
203 | int r; | |
ea430986 LP |
204 | DBusError error; |
205 | DBusMessage *reply = NULL; | |
206 | char * path = NULL; | |
c87eba54 | 207 | JobType job_type = _JOB_TYPE_INVALID; |
ea430986 LP |
208 | |
209 | assert(connection); | |
210 | assert(message); | |
211 | assert(m); | |
212 | ||
213 | dbus_error_init(&error); | |
214 | ||
215 | log_debug("Got D-Bus request: %s.%s() on %s", | |
216 | dbus_message_get_interface(message), | |
217 | dbus_message_get_member(message), | |
218 | dbus_message_get_path(message)); | |
219 | ||
4139c1b2 | 220 | if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnit")) { |
ea430986 LP |
221 | const char *name; |
222 | Unit *u; | |
223 | ||
224 | if (!dbus_message_get_args( | |
225 | message, | |
226 | &error, | |
227 | DBUS_TYPE_STRING, &name, | |
228 | DBUS_TYPE_INVALID)) | |
229 | return bus_send_error_reply(m, message, &error, -EINVAL); | |
230 | ||
231 | if (!(u = manager_get_unit(m, name))) | |
232 | return bus_send_error_reply(m, message, NULL, -ENOENT); | |
233 | ||
234 | if (!(reply = dbus_message_new_method_return(message))) | |
235 | goto oom; | |
236 | ||
237 | if (!(path = unit_dbus_path(u))) | |
238 | goto oom; | |
239 | ||
240 | if (!dbus_message_append_args( | |
241 | reply, | |
242 | DBUS_TYPE_OBJECT_PATH, &path, | |
243 | DBUS_TYPE_INVALID)) | |
244 | goto oom; | |
245 | ||
4139c1b2 | 246 | } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "LoadUnit")) { |
ea430986 LP |
247 | const char *name; |
248 | Unit *u; | |
249 | ||
250 | if (!dbus_message_get_args( | |
251 | message, | |
252 | &error, | |
253 | DBUS_TYPE_STRING, &name, | |
254 | DBUS_TYPE_INVALID)) | |
255 | return bus_send_error_reply(m, message, &error, -EINVAL); | |
256 | ||
9e2f7c11 | 257 | if ((r = manager_load_unit(m, name, NULL, &u)) < 0) |
ea430986 LP |
258 | return bus_send_error_reply(m, message, NULL, r); |
259 | ||
260 | if (!(reply = dbus_message_new_method_return(message))) | |
261 | goto oom; | |
262 | ||
263 | if (!(path = unit_dbus_path(u))) | |
264 | goto oom; | |
265 | ||
266 | if (!dbus_message_append_args( | |
267 | reply, | |
268 | DBUS_TYPE_OBJECT_PATH, &path, | |
269 | DBUS_TYPE_INVALID)) | |
270 | goto oom; | |
271 | ||
c87eba54 LP |
272 | } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnit")) |
273 | job_type = JOB_START; | |
274 | else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StopUnit")) | |
275 | job_type = JOB_STOP; | |
276 | else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadUnit")) | |
277 | job_type = JOB_RELOAD; | |
278 | else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "RestartUnit")) | |
279 | job_type = JOB_RESTART; | |
280 | else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetJob")) { | |
ea430986 LP |
281 | uint32_t id; |
282 | Job *j; | |
283 | ||
284 | if (!dbus_message_get_args( | |
285 | message, | |
286 | &error, | |
287 | DBUS_TYPE_UINT32, &id, | |
288 | DBUS_TYPE_INVALID)) | |
289 | return bus_send_error_reply(m, message, &error, -EINVAL); | |
290 | ||
291 | if (!(j = manager_get_job(m, id))) | |
292 | return bus_send_error_reply(m, message, NULL, -ENOENT); | |
293 | ||
294 | if (!(reply = dbus_message_new_method_return(message))) | |
295 | goto oom; | |
296 | ||
297 | if (!(path = job_dbus_path(j))) | |
298 | goto oom; | |
299 | ||
300 | if (!dbus_message_append_args( | |
301 | reply, | |
302 | DBUS_TYPE_OBJECT_PATH, &path, | |
303 | DBUS_TYPE_INVALID)) | |
304 | goto oom; | |
305 | ||
4139c1b2 | 306 | } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ClearJobs")) { |
ea430986 LP |
307 | |
308 | manager_clear_jobs(m); | |
309 | ||
310 | if (!(reply = dbus_message_new_method_return(message))) | |
311 | goto oom; | |
312 | ||
4139c1b2 | 313 | } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnits")) { |
ea430986 LP |
314 | DBusMessageIter iter, sub; |
315 | Iterator i; | |
316 | Unit *u; | |
317 | const char *k; | |
318 | ||
319 | if (!(reply = dbus_message_new_method_return(message))) | |
320 | goto oom; | |
321 | ||
322 | dbus_message_iter_init_append(reply, &iter); | |
323 | ||
10a94420 | 324 | if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(sssssouso)", &sub)) |
ea430986 LP |
325 | goto oom; |
326 | ||
327 | HASHMAP_FOREACH_KEY(u, k, m->units, i) { | |
47be870b | 328 | char *u_path, *j_path; |
c87eba54 | 329 | const char *description, *load_state, *active_state, *sub_state, *sjob_type; |
ea430986 LP |
330 | DBusMessageIter sub2; |
331 | uint32_t job_id; | |
332 | ||
9e2f7c11 | 333 | if (k != u->meta.id) |
ea430986 LP |
334 | continue; |
335 | ||
336 | if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2)) | |
337 | goto oom; | |
338 | ||
339 | description = unit_description(u); | |
340 | load_state = unit_load_state_to_string(u->meta.load_state); | |
341 | active_state = unit_active_state_to_string(unit_active_state(u)); | |
10a94420 | 342 | sub_state = unit_sub_state_to_string(u); |
ea430986 | 343 | |
47be870b | 344 | if (!(u_path = unit_dbus_path(u))) |
ea430986 LP |
345 | goto oom; |
346 | ||
347 | if (u->meta.job) { | |
348 | job_id = (uint32_t) u->meta.job->id; | |
349 | ||
47be870b LP |
350 | if (!(j_path = job_dbus_path(u->meta.job))) { |
351 | free(u_path); | |
ea430986 LP |
352 | goto oom; |
353 | } | |
354 | ||
c87eba54 | 355 | sjob_type = job_type_to_string(u->meta.job->type); |
ea430986 LP |
356 | } else { |
357 | job_id = 0; | |
47be870b | 358 | j_path = u_path; |
c87eba54 | 359 | sjob_type = ""; |
ea430986 LP |
360 | } |
361 | ||
9e2f7c11 | 362 | if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &u->meta.id) || |
ea430986 LP |
363 | !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &description) || |
364 | !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &load_state) || | |
365 | !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &active_state) || | |
10a94420 | 366 | !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &sub_state) || |
47be870b | 367 | !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &u_path) || |
ea430986 | 368 | !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &job_id) || |
c87eba54 | 369 | !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &sjob_type) || |
47be870b LP |
370 | !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &j_path)) { |
371 | free(u_path); | |
ea430986 | 372 | if (u->meta.job) |
47be870b | 373 | free(j_path); |
ea430986 LP |
374 | goto oom; |
375 | } | |
376 | ||
47be870b | 377 | free(u_path); |
ea430986 | 378 | if (u->meta.job) |
47be870b | 379 | free(j_path); |
ea430986 LP |
380 | |
381 | if (!dbus_message_iter_close_container(&sub, &sub2)) | |
382 | goto oom; | |
383 | } | |
384 | ||
385 | if (!dbus_message_iter_close_container(&iter, &sub)) | |
386 | goto oom; | |
387 | ||
4139c1b2 | 388 | } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListJobs")) { |
ea430986 LP |
389 | DBusMessageIter iter, sub; |
390 | Iterator i; | |
391 | Job *j; | |
392 | ||
393 | if (!(reply = dbus_message_new_method_return(message))) | |
394 | goto oom; | |
395 | ||
396 | dbus_message_iter_init_append(reply, &iter); | |
397 | ||
398 | if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(usssoo)", &sub)) | |
399 | goto oom; | |
400 | ||
401 | HASHMAP_FOREACH(j, m->jobs, i) { | |
47be870b | 402 | char *u_path, *j_path; |
9e2f7c11 | 403 | const char *state, *type; |
ea430986 LP |
404 | uint32_t id; |
405 | DBusMessageIter sub2; | |
406 | ||
407 | if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2)) | |
408 | goto oom; | |
409 | ||
410 | id = (uint32_t) j->id; | |
ea430986 | 411 | state = job_state_to_string(j->state); |
2b53c70b | 412 | type = job_type_to_string(j->type); |
ea430986 | 413 | |
47be870b | 414 | if (!(j_path = job_dbus_path(j))) |
ea430986 LP |
415 | goto oom; |
416 | ||
47be870b LP |
417 | if (!(u_path = unit_dbus_path(j->unit))) { |
418 | free(j_path); | |
ea430986 LP |
419 | goto oom; |
420 | } | |
421 | ||
422 | if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &id) || | |
9e2f7c11 | 423 | !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &j->unit->meta.id) || |
ea430986 LP |
424 | !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &type) || |
425 | !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &state) || | |
47be870b LP |
426 | !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &j_path) || |
427 | !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &u_path)) { | |
428 | free(j_path); | |
429 | free(u_path); | |
ea430986 LP |
430 | goto oom; |
431 | } | |
432 | ||
47be870b LP |
433 | free(j_path); |
434 | free(u_path); | |
ea430986 LP |
435 | |
436 | if (!dbus_message_iter_close_container(&sub, &sub2)) | |
437 | goto oom; | |
438 | } | |
439 | ||
440 | if (!dbus_message_iter_close_container(&iter, &sub)) | |
441 | goto oom; | |
442 | ||
4139c1b2 | 443 | } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Subscribe")) { |
c1e1601e LP |
444 | char *client; |
445 | ||
446 | if (!(client = strdup(dbus_message_get_sender(message)))) | |
447 | goto oom; | |
448 | ||
449 | r = set_put(m->subscribed, client); | |
450 | ||
451 | if (r < 0) | |
452 | return bus_send_error_reply(m, message, NULL, r); | |
453 | ||
454 | if (!(reply = dbus_message_new_method_return(message))) | |
455 | goto oom; | |
456 | ||
4139c1b2 | 457 | } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Unsubscribe")) { |
c1e1601e LP |
458 | char *client; |
459 | ||
460 | if (!(client = set_remove(m->subscribed, (char*) dbus_message_get_sender(message)))) | |
461 | return bus_send_error_reply(m, message, NULL, -ENOENT); | |
462 | ||
463 | free(client); | |
464 | ||
465 | if (!(reply = dbus_message_new_method_return(message))) | |
466 | goto oom; | |
467 | ||
4139c1b2 | 468 | } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Dump")) { |
b152adec LP |
469 | FILE *f; |
470 | char *dump = NULL; | |
471 | size_t size; | |
472 | ||
473 | if (!(reply = dbus_message_new_method_return(message))) | |
474 | goto oom; | |
475 | ||
476 | if (!(f = open_memstream(&dump, &size))) | |
477 | goto oom; | |
478 | ||
479 | manager_dump_units(m, f, NULL); | |
480 | manager_dump_jobs(m, f, NULL); | |
481 | ||
482 | if (ferror(f)) { | |
483 | fclose(f); | |
484 | free(dump); | |
485 | goto oom; | |
486 | } | |
487 | ||
488 | fclose(f); | |
489 | ||
490 | if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &dump, DBUS_TYPE_INVALID)) { | |
491 | free(dump); | |
492 | goto oom; | |
493 | } | |
494 | ||
495 | free(dump); | |
4139c1b2 LP |
496 | } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "CreateSnapshot")) { |
497 | const char *name; | |
498 | dbus_bool_t cleanup; | |
499 | Snapshot *s; | |
500 | ||
501 | if (!dbus_message_get_args( | |
502 | message, | |
503 | &error, | |
504 | DBUS_TYPE_STRING, &name, | |
505 | DBUS_TYPE_BOOLEAN, &cleanup, | |
506 | DBUS_TYPE_INVALID)) | |
507 | return bus_send_error_reply(m, message, &error, -EINVAL); | |
508 | ||
509 | if (name && name[0] == 0) | |
510 | name = NULL; | |
511 | ||
512 | if ((r = snapshot_create(m, name, cleanup, &s)) < 0) | |
513 | return bus_send_error_reply(m, message, NULL, r); | |
514 | ||
515 | if (!(reply = dbus_message_new_method_return(message))) | |
516 | goto oom; | |
517 | ||
518 | if (!(path = unit_dbus_path(UNIT(s)))) | |
519 | goto oom; | |
520 | ||
521 | if (!dbus_message_append_args( | |
522 | reply, | |
523 | DBUS_TYPE_OBJECT_PATH, &path, | |
524 | DBUS_TYPE_INVALID)) | |
525 | goto oom; | |
b152adec | 526 | |
ea430986 LP |
527 | } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) { |
528 | char *introspection = NULL; | |
529 | FILE *f; | |
530 | Iterator i; | |
531 | Unit *u; | |
532 | Job *j; | |
533 | const char *k; | |
534 | size_t size; | |
535 | ||
536 | if (!(reply = dbus_message_new_method_return(message))) | |
537 | goto oom; | |
538 | ||
539 | /* We roll our own introspection code here, instead of | |
540 | * relying on bus_default_message_handler() because we | |
541 | * need to generate our introspection string | |
542 | * dynamically. */ | |
543 | ||
544 | if (!(f = open_memstream(&introspection, &size))) | |
545 | goto oom; | |
546 | ||
547 | fputs(INTROSPECTION_BEGIN, f); | |
548 | ||
549 | HASHMAP_FOREACH_KEY(u, k, m->units, i) { | |
550 | char *p; | |
551 | ||
9e2f7c11 | 552 | if (k != u->meta.id) |
ea430986 LP |
553 | continue; |
554 | ||
555 | if (!(p = bus_path_escape(k))) { | |
556 | fclose(f); | |
557 | free(introspection); | |
558 | goto oom; | |
559 | } | |
560 | ||
561 | fprintf(f, "<node name=\"unit/%s\"/>", p); | |
562 | free(p); | |
563 | } | |
564 | ||
565 | HASHMAP_FOREACH(j, m->jobs, i) | |
566 | fprintf(f, "<node name=\"job/%lu\"/>", (unsigned long) j->id); | |
567 | ||
568 | fputs(INTROSPECTION_END, f); | |
569 | ||
570 | if (ferror(f)) { | |
571 | fclose(f); | |
572 | free(introspection); | |
573 | goto oom; | |
574 | } | |
575 | ||
576 | fclose(f); | |
577 | ||
578 | if (!introspection) | |
579 | goto oom; | |
580 | ||
581 | if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) { | |
582 | free(introspection); | |
583 | goto oom; | |
584 | } | |
585 | ||
586 | free(introspection); | |
587 | ||
a16e1123 LP |
588 | } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reload")) { |
589 | ||
590 | assert(!m->queued_message); | |
591 | ||
592 | /* Instead of sending the reply back right away, we | |
593 | * just remember that we need to and then send it | |
594 | * after the reload is finished. That way the caller | |
595 | * knows when the reload finished. */ | |
596 | ||
597 | if (!(m->queued_message = dbus_message_new_method_return(message))) | |
598 | goto oom; | |
599 | ||
600 | m->exit_code = MANAGER_RELOAD; | |
601 | ||
602 | } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reexecute")) { | |
603 | ||
604 | if (!(reply = dbus_message_new_method_return(message))) | |
605 | goto oom; | |
606 | ||
607 | m->exit_code = MANAGER_REEXECUTE; | |
608 | ||
609 | } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Exit")) { | |
610 | ||
611 | if (m->running_as == MANAGER_INIT) | |
612 | return bus_send_error_reply(m, message, NULL, -ENOTSUP); | |
613 | ||
614 | if (!(reply = dbus_message_new_method_return(message))) | |
615 | goto oom; | |
616 | ||
617 | m->exit_code = MANAGER_EXIT; | |
618 | ||
1137a57c LP |
619 | } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetEnvironment")) { |
620 | char **l = NULL, **e = NULL; | |
621 | ||
622 | if ((r = bus_parse_strv(message, &l)) < 0) { | |
623 | if (r == -ENOMEM) | |
624 | goto oom; | |
625 | ||
626 | return bus_send_error_reply(m, message, NULL, r); | |
627 | } | |
628 | ||
5b6319dc | 629 | e = strv_env_merge(2, m->environment, l); |
1137a57c LP |
630 | strv_free(l); |
631 | ||
632 | if (!e) | |
633 | goto oom; | |
634 | ||
635 | if (!(reply = dbus_message_new_method_return(message))) { | |
636 | strv_free(e); | |
637 | goto oom; | |
638 | } | |
639 | ||
640 | strv_free(m->environment); | |
641 | m->environment = e; | |
642 | ||
643 | } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetEnvironment")) { | |
644 | char **l = NULL, **e = NULL; | |
645 | ||
646 | if ((r = bus_parse_strv(message, &l)) < 0) { | |
647 | if (r == -ENOMEM) | |
648 | goto oom; | |
649 | ||
650 | return bus_send_error_reply(m, message, NULL, r); | |
651 | } | |
652 | ||
5b6319dc | 653 | e = strv_env_delete(m->environment, 1, l); |
1137a57c LP |
654 | strv_free(l); |
655 | ||
656 | if (!e) | |
657 | goto oom; | |
658 | ||
659 | if (!(reply = dbus_message_new_method_return(message))) | |
660 | goto oom; | |
661 | ||
662 | strv_free(m->environment); | |
663 | m->environment = e; | |
664 | ||
ea430986 | 665 | } else |
1adf1049 | 666 | return bus_default_message_handler(m, message, NULL, properties); |
ea430986 | 667 | |
c87eba54 LP |
668 | |
669 | if (job_type != _JOB_TYPE_INVALID) { | |
670 | const char *name, *smode; | |
671 | JobMode mode; | |
672 | Job *j; | |
673 | Unit *u; | |
674 | ||
675 | if (!dbus_message_get_args( | |
676 | message, | |
677 | &error, | |
678 | DBUS_TYPE_STRING, &name, | |
679 | DBUS_TYPE_STRING, &smode, | |
680 | DBUS_TYPE_INVALID)) | |
681 | return bus_send_error_reply(m, message, &error, -EINVAL); | |
682 | ||
683 | if ((mode = job_mode_from_string(smode)) == _JOB_MODE_INVALID) | |
684 | return bus_send_error_reply(m, message, NULL, -EINVAL); | |
685 | ||
686 | if ((r = manager_load_unit(m, name, NULL, &u)) < 0) | |
687 | return bus_send_error_reply(m, message, NULL, r); | |
688 | ||
689 | if (job_type == JOB_START && u->meta.only_by_dependency) | |
690 | return bus_send_error_reply(m, message, NULL, -EPERM); | |
691 | ||
692 | if ((r = manager_add_job(m, job_type, u, mode, true, &j)) < 0) | |
693 | return bus_send_error_reply(m, message, NULL, r); | |
694 | ||
695 | if (!(reply = dbus_message_new_method_return(message))) | |
696 | goto oom; | |
697 | ||
698 | if (!(path = job_dbus_path(j))) | |
699 | goto oom; | |
700 | ||
701 | if (!dbus_message_append_args( | |
702 | reply, | |
703 | DBUS_TYPE_OBJECT_PATH, &path, | |
704 | DBUS_TYPE_INVALID)) | |
705 | goto oom; | |
706 | } | |
707 | ||
ea430986 LP |
708 | free(path); |
709 | ||
710 | if (reply) { | |
711 | if (!dbus_connection_send(connection, reply, NULL)) | |
712 | goto oom; | |
713 | ||
714 | dbus_message_unref(reply); | |
715 | } | |
716 | ||
717 | return DBUS_HANDLER_RESULT_HANDLED; | |
718 | ||
719 | oom: | |
720 | free(path); | |
721 | ||
722 | if (reply) | |
723 | dbus_message_unref(reply); | |
724 | ||
725 | dbus_error_free(&error); | |
726 | ||
727 | return DBUS_HANDLER_RESULT_NEED_MEMORY; | |
728 | } | |
729 | ||
730 | const DBusObjectPathVTable bus_manager_vtable = { | |
731 | .message_function = bus_manager_message_handler | |
732 | }; |