]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/dbus-unit.c
systemctl: use format_timespan() where applicable
[thirdparty/systemd.git] / src / dbus-unit.c
CommitLineData
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-unit.h"
ea430986 27
4288f619
LP
28const char bus_unit_interface[] = BUS_UNIT_INTERFACE;
29
4139c1b2
LP
30int bus_unit_append_names(Manager *m, DBusMessageIter *i, const char *property, void *data) {
31 char *t;
32 Iterator j;
33 DBusMessageIter sub;
34 Unit *u = data;
35
36 if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "s", &sub))
37 return -ENOMEM;
38
39 SET_FOREACH(t, u->meta.names, j)
40 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &t))
41 return -ENOMEM;
42
43 if (!dbus_message_iter_close_container(i, &sub))
44 return -ENOMEM;
45
46 return 0;
47}
48
5301be81
LP
49int bus_unit_append_dependencies(Manager *m, DBusMessageIter *i, const char *property, void *data) {
50 Unit *u;
51 Iterator j;
52 DBusMessageIter sub;
53 Set *s = data;
54
55 if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "s", &sub))
56 return -ENOMEM;
57
58 SET_FOREACH(u, s, j)
59 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &u->meta.id))
60 return -ENOMEM;
61
62 if (!dbus_message_iter_close_container(i, &sub))
63 return -ENOMEM;
64
65 return 0;
66}
67
4139c1b2 68int bus_unit_append_description(Manager *m, DBusMessageIter *i, const char *property, void *data) {
ea430986
LP
69 Unit *u = data;
70 const char *d;
71
72 assert(m);
73 assert(i);
74 assert(property);
75 assert(u);
76
77 d = unit_description(u);
78
79 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &d))
80 return -ENOMEM;
81
82 return 0;
83}
84
6f4706b7 85DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_unit_append_load_state, unit_load_state, UnitLoadState);
ea430986 86
4139c1b2 87int bus_unit_append_active_state(Manager *m, DBusMessageIter *i, const char *property, void *data) {
ea430986
LP
88 Unit *u = data;
89 const char *state;
90
91 assert(m);
92 assert(i);
93 assert(property);
94 assert(u);
95
96 state = unit_active_state_to_string(unit_active_state(u));
97
98 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &state))
99 return -ENOMEM;
100
101 return 0;
102}
103
4139c1b2 104int bus_unit_append_sub_state(Manager *m, DBusMessageIter *i, const char *property, void *data) {
10a94420
LP
105 Unit *u = data;
106 const char *state;
107
108 assert(m);
109 assert(i);
110 assert(property);
111 assert(u);
112
113 state = unit_sub_state_to_string(u);
114
115 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &state))
116 return -ENOMEM;
117
118 return 0;
119}
120
4139c1b2 121int bus_unit_append_can_start(Manager *m, DBusMessageIter *i, const char *property, void *data) {
38131695
LP
122 Unit *u = data;
123 dbus_bool_t b;
124
125 assert(m);
126 assert(i);
127 assert(property);
128 assert(u);
129
4139c1b2 130 b = unit_can_start(u);
38131695
LP
131
132 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
133 return -ENOMEM;
134
135 return 0;
136}
137
4139c1b2 138int bus_unit_append_can_reload(Manager *m, DBusMessageIter *i, const char *property, void *data) {
38131695
LP
139 Unit *u = data;
140 dbus_bool_t b;
141
142 assert(m);
143 assert(i);
144 assert(property);
145 assert(u);
146
4139c1b2 147 b = unit_can_reload(u);
38131695
LP
148
149 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
150 return -ENOMEM;
151
152 return 0;
153}
154
4139c1b2 155int bus_unit_append_job(Manager *m, DBusMessageIter *i, const char *property, void *data) {
38131695
LP
156 Unit *u = data;
157 DBusMessageIter sub;
158 char *p;
159
160 assert(m);
161 assert(i);
162 assert(property);
163 assert(u);
164
165 if (!dbus_message_iter_open_container(i, DBUS_TYPE_STRUCT, NULL, &sub))
166 return -ENOMEM;
167
168 if (u->meta.job) {
169
170 if (!(p = job_dbus_path(u->meta.job)))
171 return -ENOMEM;
172
173 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_UINT32, &u->meta.job->id) ||
86ad3bc1 174 !dbus_message_iter_append_basic(&sub, DBUS_TYPE_OBJECT_PATH, &p)) {
38131695
LP
175 free(p);
176 return -ENOMEM;
177 }
178 } else {
179 uint32_t id = 0;
180
181 /* No job, so let's fill in some placeholder
182 * data. Since we need to fill in a valid path we
183 * simple point to ourselves. */
184
185 if (!(p = unit_dbus_path(u)))
186 return -ENOMEM;
187
188 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_UINT32, &id) ||
86ad3bc1 189 !dbus_message_iter_append_basic(&sub, DBUS_TYPE_OBJECT_PATH, &p)) {
38131695
LP
190 free(p);
191 return -ENOMEM;
192 }
193 }
194
195 free(p);
196
197 if (!dbus_message_iter_close_container(i, &sub))
198 return -ENOMEM;
199
200 return 0;
201}
202
4139c1b2
LP
203int bus_unit_append_default_cgroup(Manager *m, DBusMessageIter *i, const char *property, void *data) {
204 Unit *u = data;
205 char *t;
206 CGroupBonding *cgb;
207 bool success;
ea430986 208
4139c1b2
LP
209 assert(m);
210 assert(i);
211 assert(property);
212 assert(u);
213
214 if ((cgb = unit_get_default_cgroup(u))) {
215 if (!(t = cgroup_bonding_to_string(cgb)))
216 return -ENOMEM;
217 } else
218 t = (char*) "";
ea430986 219
4139c1b2
LP
220 success = dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t);
221
222 if (cgb)
223 free(t);
224
225 return success ? 0 : -ENOMEM;
226}
227
228int bus_unit_append_cgroups(Manager *m, DBusMessageIter *i, const char *property, void *data) {
229 Unit *u = data;
230 CGroupBonding *cgb;
231 DBusMessageIter sub;
232
233 if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "s", &sub))
234 return -ENOMEM;
235
236 LIST_FOREACH(by_unit, cgb, u->meta.cgroup_bondings) {
237 char *t;
238 bool success;
239
240 if (!(t = cgroup_bonding_to_string(cgb)))
241 return -ENOMEM;
242
243 success = dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &t);
244 free(t);
245
246 if (!success)
247 return -ENOMEM;
248 }
249
250 if (!dbus_message_iter_close_container(i, &sub))
251 return -ENOMEM;
252
253 return 0;
254}
255
256DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_unit_append_kill_mode, kill_mode, KillMode);
257
5e8d1c9a 258static DBusHandlerResult bus_unit_message_dispatch(Unit *u, DBusConnection *connection, DBusMessage *message) {
b548631a
LP
259 DBusMessage *reply = NULL;
260 Manager *m = u->meta.manager;
261 DBusError error;
262 JobType job_type = _JOB_TYPE_INVALID;
c87eba54 263 char *path = NULL;
b548631a
LP
264
265 dbus_error_init(&error);
266
267 if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "Start"))
268 job_type = JOB_START;
269 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "Stop"))
270 job_type = JOB_STOP;
271 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "Reload"))
272 job_type = JOB_RELOAD;
273 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "Restart"))
274 job_type = JOB_RESTART;
4139c1b2 275 else if (UNIT_VTABLE(u)->bus_message_handler)
5e8d1c9a 276 return UNIT_VTABLE(u)->bus_message_handler(u, connection, message);
b548631a 277 else
4139c1b2 278 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
b548631a
LP
279
280 if (job_type != _JOB_TYPE_INVALID) {
281 const char *smode;
282 JobMode mode;
283 Job *j;
284 int r;
b548631a 285
bc0f8771 286 if (job_type == JOB_START && u->meta.only_by_dependency)
5e8d1c9a 287 return bus_send_error_reply(m, connection, message, NULL, -EPERM);
bc0f8771 288
b548631a
LP
289 if (!dbus_message_get_args(
290 message,
291 &error,
292 DBUS_TYPE_STRING, &smode,
293 DBUS_TYPE_INVALID))
5e8d1c9a 294 return bus_send_error_reply(m, connection, message, &error, -EINVAL);
b548631a
LP
295
296 if ((mode = job_mode_from_string(smode)) == _JOB_MODE_INVALID)
5e8d1c9a 297 return bus_send_error_reply(m, connection, message, NULL, -EINVAL);
b548631a
LP
298
299 if ((r = manager_add_job(m, job_type, u, mode, true, &j)) < 0)
5e8d1c9a 300 return bus_send_error_reply(m, connection, message, NULL, r);
b548631a
LP
301
302 if (!(reply = dbus_message_new_method_return(message)))
303 goto oom;
304
305 if (!(path = job_dbus_path(j)))
306 goto oom;
307
308 if (!dbus_message_append_args(
309 reply,
310 DBUS_TYPE_OBJECT_PATH, &path,
311 DBUS_TYPE_INVALID))
312 goto oom;
313 }
314
c87eba54
LP
315 free(path);
316
b548631a 317 if (reply) {
5e8d1c9a 318 if (!dbus_connection_send(connection, reply, NULL))
b548631a
LP
319 goto oom;
320
321 dbus_message_unref(reply);
322 }
323
324 return DBUS_HANDLER_RESULT_HANDLED;
325
326oom:
c87eba54
LP
327 free(path);
328
b548631a
LP
329 if (reply)
330 dbus_message_unref(reply);
331
332 dbus_error_free(&error);
333
334 return DBUS_HANDLER_RESULT_NEED_MEMORY;
ea430986
LP
335}
336
5e8d1c9a 337static DBusHandlerResult bus_unit_message_handler(DBusConnection *connection, DBusMessage *message, void *data) {
ea430986
LP
338 Manager *m = data;
339 Unit *u;
340 int r;
341
342 assert(connection);
343 assert(message);
344 assert(m);
345
346 log_debug("Got D-Bus request: %s.%s() on %s",
347 dbus_message_get_interface(message),
348 dbus_message_get_member(message),
349 dbus_message_get_path(message));
350
351 if ((r = manager_get_unit_from_dbus_path(m, dbus_message_get_path(message), &u)) < 0) {
352
353 if (r == -ENOMEM)
354 return DBUS_HANDLER_RESULT_NEED_MEMORY;
355
356 if (r == -ENOENT)
357 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
358
5e8d1c9a 359 return bus_send_error_reply(m, connection, message, NULL, r);
ea430986
LP
360 }
361
5e8d1c9a 362 return bus_unit_message_dispatch(u, connection, message);
ea430986
LP
363}
364
365const DBusObjectPathVTable bus_unit_vtable = {
366 .message_function = bus_unit_message_handler
367};
c1e1601e
LP
368
369void bus_unit_send_change_signal(Unit *u) {
370 char *p = NULL;
371 DBusMessage *m = NULL;
372
373 assert(u);
374 assert(u->meta.in_dbus_queue);
375
376 LIST_REMOVE(Meta, dbus_queue, u->meta.manager->dbus_unit_queue, &u->meta);
377 u->meta.in_dbus_queue = false;
378
94b6dfa2
LP
379 if (set_isempty(u->meta.manager->subscribed)) {
380 u->meta.sent_dbus_new_signal = true;
c1e1601e 381 return;
94b6dfa2 382 }
c1e1601e
LP
383
384 if (!(p = unit_dbus_path(u)))
385 goto oom;
386
387 if (u->meta.sent_dbus_new_signal) {
388 /* Send a change signal */
389
390 if (!(m = dbus_message_new_signal(p, "org.freedesktop.systemd1.Unit", "Changed")))
391 goto oom;
392 } else {
c1e1601e
LP
393 /* Send a new signal */
394
701cc384 395 if (!(m = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "UnitNew")))
c1e1601e
LP
396 goto oom;
397
c1e1601e 398 if (!dbus_message_append_args(m,
9e2f7c11 399 DBUS_TYPE_STRING, &u->meta.id,
c1e1601e
LP
400 DBUS_TYPE_OBJECT_PATH, &p,
401 DBUS_TYPE_INVALID))
402 goto oom;
403 }
404
5e8d1c9a 405 if (bus_broadcast(u->meta.manager, m) < 0)
c1e1601e
LP
406 goto oom;
407
408 free(p);
409 dbus_message_unref(m);
410
411 u->meta.sent_dbus_new_signal = true;
412
413 return;
414
415oom:
416 free(p);
417
418 if (m)
419 dbus_message_unref(m);
420
421 log_error("Failed to allocate unit change/new signal.");
422}
423
424void bus_unit_send_removed_signal(Unit *u) {
425 char *p = NULL;
426 DBusMessage *m = NULL;
c1e1601e
LP
427
428 assert(u);
429
7535cc78 430 if (set_isempty(u->meta.manager->subscribed))
c1e1601e
LP
431 return;
432
7535cc78
LP
433 if (!u->meta.sent_dbus_new_signal)
434 bus_unit_send_change_signal(u);
435
c1e1601e
LP
436 if (!(p = unit_dbus_path(u)))
437 goto oom;
438
701cc384 439 if (!(m = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "UnitRemoved")))
c1e1601e
LP
440 goto oom;
441
c1e1601e 442 if (!dbus_message_append_args(m,
9e2f7c11 443 DBUS_TYPE_STRING, &u->meta.id,
c1e1601e
LP
444 DBUS_TYPE_OBJECT_PATH, &p,
445 DBUS_TYPE_INVALID))
446 goto oom;
447
5e8d1c9a 448 if (bus_broadcast(u->meta.manager, m) < 0)
c1e1601e
LP
449 goto oom;
450
451 free(p);
452 dbus_message_unref(m);
453
454 return;
455
456oom:
457 free(p);
458
459 if (m)
460 dbus_message_unref(m);
461
462 log_error("Failed to allocate unit remove signal.");
463}