]>
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" | |
26 | ||
27 | #define INTROSPECTION_BEGIN \ | |
28 | DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \ | |
29 | "<node>" \ | |
30 | " <interface name=\"org.freedesktop.systemd1\">" \ | |
31 | " <method name=\"GetUnit\">" \ | |
32 | " <arg name=\"name\" type=\"s\" direction=\"in\"/>" \ | |
33 | " <arg name=\"unit\" type=\"o\" direction=\"out\"/>" \ | |
34 | " </method>" \ | |
35 | " <method name=\"LoadUnit\">" \ | |
36 | " <arg name=\"name\" type=\"s\" direction=\"in\"/>" \ | |
37 | " <arg name=\"unit\" type=\"o\" direction=\"out\"/>" \ | |
38 | " </method>" \ | |
39 | " <method name=\"GetJob\">" \ | |
40 | " <arg name=\"id\" type=\"u\" direction=\"in\"/>" \ | |
41 | " <arg name=\"unit\" type=\"o\" direction=\"out\"/>" \ | |
42 | " </method>" \ | |
43 | " <method name=\"ClearJobs\"/>" \ | |
44 | " <method name=\"ListUnits\">" \ | |
45 | " <arg name=\"units\" type=\"a(ssssouso)\" direction=\"out\"/>" \ | |
46 | " </method>" \ | |
47 | " <method name=\"ListJobs\">" \ | |
48 | " <arg name=\"jobs\" type=\"a(usssoo)\" direction=\"out\"/>" \ | |
49 | " </method>" \ | |
50 | " </interface>" \ | |
51 | BUS_PROPERTIES_INTERFACE \ | |
52 | BUS_INTROSPECTABLE_INTERFACE | |
53 | ||
54 | #define INTROSPECTION_END \ | |
55 | "</node>" | |
56 | ||
57 | DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, DBusMessage *message, void *data) { | |
58 | int r; | |
59 | Manager *m = data; | |
60 | DBusError error; | |
61 | DBusMessage *reply = NULL; | |
62 | char * path = NULL; | |
63 | ||
64 | assert(connection); | |
65 | assert(message); | |
66 | assert(m); | |
67 | ||
68 | dbus_error_init(&error); | |
69 | ||
70 | log_debug("Got D-Bus request: %s.%s() on %s", | |
71 | dbus_message_get_interface(message), | |
72 | dbus_message_get_member(message), | |
73 | dbus_message_get_path(message)); | |
74 | ||
75 | if (dbus_message_is_method_call(message, "org.freedesktop.systemd1", "GetUnit")) { | |
76 | const char *name; | |
77 | Unit *u; | |
78 | ||
79 | if (!dbus_message_get_args( | |
80 | message, | |
81 | &error, | |
82 | DBUS_TYPE_STRING, &name, | |
83 | DBUS_TYPE_INVALID)) | |
84 | return bus_send_error_reply(m, message, &error, -EINVAL); | |
85 | ||
86 | if (!(u = manager_get_unit(m, name))) | |
87 | return bus_send_error_reply(m, message, NULL, -ENOENT); | |
88 | ||
89 | if (!(reply = dbus_message_new_method_return(message))) | |
90 | goto oom; | |
91 | ||
92 | if (!(path = unit_dbus_path(u))) | |
93 | goto oom; | |
94 | ||
95 | if (!dbus_message_append_args( | |
96 | reply, | |
97 | DBUS_TYPE_OBJECT_PATH, &path, | |
98 | DBUS_TYPE_INVALID)) | |
99 | goto oom; | |
100 | ||
101 | } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1", "LoadUnit")) { | |
102 | const char *name; | |
103 | Unit *u; | |
104 | ||
105 | if (!dbus_message_get_args( | |
106 | message, | |
107 | &error, | |
108 | DBUS_TYPE_STRING, &name, | |
109 | DBUS_TYPE_INVALID)) | |
110 | return bus_send_error_reply(m, message, &error, -EINVAL); | |
111 | ||
112 | if ((r = manager_load_unit(m, name, &u)) < 0) | |
113 | return bus_send_error_reply(m, message, NULL, r); | |
114 | ||
115 | if (!(reply = dbus_message_new_method_return(message))) | |
116 | goto oom; | |
117 | ||
118 | if (!(path = unit_dbus_path(u))) | |
119 | goto oom; | |
120 | ||
121 | if (!dbus_message_append_args( | |
122 | reply, | |
123 | DBUS_TYPE_OBJECT_PATH, &path, | |
124 | DBUS_TYPE_INVALID)) | |
125 | goto oom; | |
126 | ||
127 | } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1", "GetJob")) { | |
128 | uint32_t id; | |
129 | Job *j; | |
130 | ||
131 | if (!dbus_message_get_args( | |
132 | message, | |
133 | &error, | |
134 | DBUS_TYPE_UINT32, &id, | |
135 | DBUS_TYPE_INVALID)) | |
136 | return bus_send_error_reply(m, message, &error, -EINVAL); | |
137 | ||
138 | if (!(j = manager_get_job(m, id))) | |
139 | return bus_send_error_reply(m, message, NULL, -ENOENT); | |
140 | ||
141 | if (!(reply = dbus_message_new_method_return(message))) | |
142 | goto oom; | |
143 | ||
144 | if (!(path = job_dbus_path(j))) | |
145 | goto oom; | |
146 | ||
147 | if (!dbus_message_append_args( | |
148 | reply, | |
149 | DBUS_TYPE_OBJECT_PATH, &path, | |
150 | DBUS_TYPE_INVALID)) | |
151 | goto oom; | |
152 | ||
153 | } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1", "ClearJobs")) { | |
154 | ||
155 | manager_clear_jobs(m); | |
156 | ||
157 | if (!(reply = dbus_message_new_method_return(message))) | |
158 | goto oom; | |
159 | ||
160 | } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1", "ListUnits")) { | |
161 | DBusMessageIter iter, sub; | |
162 | Iterator i; | |
163 | Unit *u; | |
164 | const char *k; | |
165 | ||
166 | if (!(reply = dbus_message_new_method_return(message))) | |
167 | goto oom; | |
168 | ||
169 | dbus_message_iter_init_append(reply, &iter); | |
170 | ||
171 | if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssouso)", &sub)) | |
172 | goto oom; | |
173 | ||
174 | HASHMAP_FOREACH_KEY(u, k, m->units, i) { | |
175 | char *unit_path, *job_path; | |
176 | const char *id, *description, *load_state, *active_state, *job_type; | |
177 | DBusMessageIter sub2; | |
178 | uint32_t job_id; | |
179 | ||
180 | id = unit_id(u); | |
181 | if (k != id) | |
182 | continue; | |
183 | ||
184 | if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2)) | |
185 | goto oom; | |
186 | ||
187 | description = unit_description(u); | |
188 | load_state = unit_load_state_to_string(u->meta.load_state); | |
189 | active_state = unit_active_state_to_string(unit_active_state(u)); | |
190 | ||
191 | if (!(unit_path = unit_dbus_path(u))) | |
192 | goto oom; | |
193 | ||
194 | if (u->meta.job) { | |
195 | job_id = (uint32_t) u->meta.job->id; | |
196 | ||
197 | if (!(job_path = job_dbus_path(u->meta.job))) { | |
198 | free(unit_path); | |
199 | goto oom; | |
200 | } | |
201 | ||
2b53c70b | 202 | job_type = job_type_to_string(u->meta.job->type); |
ea430986 LP |
203 | } else { |
204 | job_id = 0; | |
205 | job_path = unit_path; | |
206 | job_type = ""; | |
207 | } | |
208 | ||
209 | if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &id) || | |
210 | !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &description) || | |
211 | !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &load_state) || | |
212 | !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &active_state) || | |
213 | !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &unit_path) || | |
214 | !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &job_id) || | |
215 | !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &job_type) || | |
216 | !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &job_path)) { | |
217 | free(unit_path); | |
218 | if (u->meta.job) | |
219 | free(job_path); | |
220 | goto oom; | |
221 | } | |
222 | ||
223 | free(unit_path); | |
224 | if (u->meta.job) | |
225 | free(job_path); | |
226 | ||
227 | if (!dbus_message_iter_close_container(&sub, &sub2)) | |
228 | goto oom; | |
229 | } | |
230 | ||
231 | if (!dbus_message_iter_close_container(&iter, &sub)) | |
232 | goto oom; | |
233 | ||
234 | } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1", "ListJobs")) { | |
235 | DBusMessageIter iter, sub; | |
236 | Iterator i; | |
237 | Job *j; | |
238 | ||
239 | if (!(reply = dbus_message_new_method_return(message))) | |
240 | goto oom; | |
241 | ||
242 | dbus_message_iter_init_append(reply, &iter); | |
243 | ||
244 | if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(usssoo)", &sub)) | |
245 | goto oom; | |
246 | ||
247 | HASHMAP_FOREACH(j, m->jobs, i) { | |
248 | char *unit_path, *job_path; | |
249 | const char *unit, *state, *type; | |
250 | uint32_t id; | |
251 | DBusMessageIter sub2; | |
252 | ||
253 | if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2)) | |
254 | goto oom; | |
255 | ||
256 | id = (uint32_t) j->id; | |
257 | unit = unit_id(j->unit); | |
258 | state = job_state_to_string(j->state); | |
2b53c70b | 259 | type = job_type_to_string(j->type); |
ea430986 LP |
260 | |
261 | if (!(job_path = job_dbus_path(j))) | |
262 | goto oom; | |
263 | ||
264 | if (!(unit_path = unit_dbus_path(j->unit))) { | |
265 | free(job_path); | |
266 | goto oom; | |
267 | } | |
268 | ||
269 | if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &id) || | |
270 | !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &unit) || | |
271 | !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &type) || | |
272 | !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &state) || | |
273 | !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &job_path) || | |
274 | !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &unit_path)) { | |
275 | free(job_path); | |
276 | free(unit_path); | |
277 | goto oom; | |
278 | } | |
279 | ||
280 | free(job_path); | |
281 | free(unit_path); | |
282 | ||
283 | if (!dbus_message_iter_close_container(&sub, &sub2)) | |
284 | goto oom; | |
285 | } | |
286 | ||
287 | if (!dbus_message_iter_close_container(&iter, &sub)) | |
288 | goto oom; | |
289 | ||
290 | } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) { | |
291 | char *introspection = NULL; | |
292 | FILE *f; | |
293 | Iterator i; | |
294 | Unit *u; | |
295 | Job *j; | |
296 | const char *k; | |
297 | size_t size; | |
298 | ||
299 | if (!(reply = dbus_message_new_method_return(message))) | |
300 | goto oom; | |
301 | ||
302 | /* We roll our own introspection code here, instead of | |
303 | * relying on bus_default_message_handler() because we | |
304 | * need to generate our introspection string | |
305 | * dynamically. */ | |
306 | ||
307 | if (!(f = open_memstream(&introspection, &size))) | |
308 | goto oom; | |
309 | ||
310 | fputs(INTROSPECTION_BEGIN, f); | |
311 | ||
312 | HASHMAP_FOREACH_KEY(u, k, m->units, i) { | |
313 | char *p; | |
314 | ||
315 | if (k != unit_id(u)) | |
316 | continue; | |
317 | ||
318 | if (!(p = bus_path_escape(k))) { | |
319 | fclose(f); | |
320 | free(introspection); | |
321 | goto oom; | |
322 | } | |
323 | ||
324 | fprintf(f, "<node name=\"unit/%s\"/>", p); | |
325 | free(p); | |
326 | } | |
327 | ||
328 | HASHMAP_FOREACH(j, m->jobs, i) | |
329 | fprintf(f, "<node name=\"job/%lu\"/>", (unsigned long) j->id); | |
330 | ||
331 | fputs(INTROSPECTION_END, f); | |
332 | ||
333 | if (ferror(f)) { | |
334 | fclose(f); | |
335 | free(introspection); | |
336 | goto oom; | |
337 | } | |
338 | ||
339 | fclose(f); | |
340 | ||
341 | if (!introspection) | |
342 | goto oom; | |
343 | ||
344 | if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) { | |
345 | free(introspection); | |
346 | goto oom; | |
347 | } | |
348 | ||
349 | free(introspection); | |
350 | ||
351 | } else | |
352 | return bus_default_message_handler(m, message, NULL, NULL); | |
353 | ||
354 | free(path); | |
355 | ||
356 | if (reply) { | |
357 | if (!dbus_connection_send(connection, reply, NULL)) | |
358 | goto oom; | |
359 | ||
360 | dbus_message_unref(reply); | |
361 | } | |
362 | ||
363 | return DBUS_HANDLER_RESULT_HANDLED; | |
364 | ||
365 | oom: | |
366 | free(path); | |
367 | ||
368 | if (reply) | |
369 | dbus_message_unref(reply); | |
370 | ||
371 | dbus_error_free(&error); | |
372 | ||
373 | return DBUS_HANDLER_RESULT_NEED_MEMORY; | |
374 | } | |
375 | ||
376 | const DBusObjectPathVTable bus_manager_vtable = { | |
377 | .message_function = bus_manager_message_handler | |
378 | }; |