]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/dbus-unit.c
bus: let's simplify things by getting rid of unnecessary bus parameters
[thirdparty/systemd.git] / src / core / dbus-unit.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include "sd-bus.h"
23 #include "log.h"
24 #include "selinux-access.h"
25 #include "cgroup-util.h"
26 #include "strv.h"
27 #include "path-util.h"
28 #include "fileio.h"
29 #include "dbus-unit.h"
30 #include "dbus-manager.h"
31 #include "bus-errors.h"
32 #include "dbus-client-track.h"
33
34 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_load_state, unit_load_state, UnitLoadState);
35
36 static int property_get_names(
37 sd_bus *bus,
38 const char *path,
39 const char *interface,
40 const char *property,
41 sd_bus_message *reply,
42 sd_bus_error *error,
43 void *userdata) {
44
45 Unit *u = userdata;
46 Iterator i;
47 const char *t;
48 int r;
49
50 assert(bus);
51 assert(reply);
52 assert(u);
53
54 r = sd_bus_message_open_container(reply, 'a', "s");
55 if (r < 0)
56 return r;
57
58 SET_FOREACH(t, u->names, i) {
59 r = sd_bus_message_append(reply, "s", t);
60 if (r < 0)
61 return r;
62 }
63
64 return sd_bus_message_close_container(reply);
65 }
66
67 static int property_get_following(
68 sd_bus *bus,
69 const char *path,
70 const char *interface,
71 const char *property,
72 sd_bus_message *reply,
73 sd_bus_error *error,
74 void *userdata) {
75
76 Unit *u = userdata, *f;
77
78 assert(bus);
79 assert(reply);
80 assert(u);
81
82 f = unit_following(u);
83 return sd_bus_message_append(reply, "s", f ? f->id : "");
84 }
85
86 static int property_get_dependencies(
87 sd_bus *bus,
88 const char *path,
89 const char *interface,
90 const char *property,
91 sd_bus_message *reply,
92 sd_bus_error *error,
93 void *userdata) {
94
95 Set *s = *(Set**) userdata;
96 Iterator j;
97 Unit *u;
98 int r;
99
100 assert(bus);
101 assert(reply);
102
103 r = sd_bus_message_open_container(reply, 'a', "s");
104 if (r < 0)
105 return r;
106
107 SET_FOREACH(u, s, j) {
108 r = sd_bus_message_append(reply, "s", u->id);
109 if (r < 0)
110 return r;
111 }
112
113 return sd_bus_message_close_container(reply);
114 }
115
116 static int property_get_description(
117 sd_bus *bus,
118 const char *path,
119 const char *interface,
120 const char *property,
121 sd_bus_message *reply,
122 sd_bus_error *error,
123 void *userdata) {
124
125 Unit *u = userdata;
126
127 assert(bus);
128 assert(reply);
129 assert(u);
130
131 return sd_bus_message_append(reply, "s", unit_description(u));
132 }
133
134 static int property_get_active_state(
135 sd_bus *bus,
136 const char *path,
137 const char *interface,
138 const char *property,
139 sd_bus_message *reply,
140 sd_bus_error *error,
141 void *userdata) {
142
143 Unit *u = userdata;
144
145 assert(bus);
146 assert(reply);
147 assert(u);
148
149 return sd_bus_message_append(reply, "s", unit_active_state_to_string(unit_active_state(u)));
150 }
151
152 static int property_get_sub_state(
153 sd_bus *bus,
154 const char *path,
155 const char *interface,
156 const char *property,
157 sd_bus_message *reply,
158 sd_bus_error *error,
159 void *userdata) {
160
161 Unit *u = userdata;
162
163 assert(bus);
164 assert(reply);
165 assert(u);
166
167 return sd_bus_message_append(reply, "s", unit_sub_state_to_string(u));
168 }
169
170 static int property_get_unit_file_state(
171 sd_bus *bus,
172 const char *path,
173 const char *interface,
174 const char *property,
175 sd_bus_message *reply,
176 sd_bus_error *error,
177 void *userdata) {
178
179 Unit *u = userdata;
180
181 assert(bus);
182 assert(reply);
183 assert(u);
184
185 return sd_bus_message_append(reply, "s", unit_file_state_to_string(unit_get_unit_file_state(u)));
186 }
187
188 static int property_get_can_start(
189 sd_bus *bus,
190 const char *path,
191 const char *interface,
192 const char *property,
193 sd_bus_message *reply,
194 sd_bus_error *error,
195 void *userdata) {
196
197 Unit *u = userdata;
198
199 assert(bus);
200 assert(reply);
201 assert(u);
202
203 return sd_bus_message_append(reply, "b", unit_can_start(u) && !u->refuse_manual_start);
204 }
205
206 static int property_get_can_stop(
207 sd_bus *bus,
208 const char *path,
209 const char *interface,
210 const char *property,
211 sd_bus_message *reply,
212 sd_bus_error *error,
213 void *userdata) {
214
215 Unit *u = userdata;
216
217 assert(bus);
218 assert(reply);
219 assert(u);
220
221 /* On the lower levels we assume that every unit we can start
222 * we can also stop */
223
224 return sd_bus_message_append(reply, "b", unit_can_start(u) && !u->refuse_manual_stop);
225 }
226
227 static int property_get_can_reload(
228 sd_bus *bus,
229 const char *path,
230 const char *interface,
231 const char *property,
232 sd_bus_message *reply,
233 sd_bus_error *error,
234 void *userdata) {
235
236 Unit *u = userdata;
237
238 assert(bus);
239 assert(reply);
240 assert(u);
241
242 return sd_bus_message_append(reply, "b", unit_can_reload(u));
243 }
244
245 static int property_get_can_isolate(
246 sd_bus *bus,
247 const char *path,
248 const char *interface,
249 const char *property,
250 sd_bus_message *reply,
251 sd_bus_error *error,
252 void *userdata) {
253
254 Unit *u = userdata;
255
256 assert(bus);
257 assert(reply);
258 assert(u);
259
260 return sd_bus_message_append(reply, "b", unit_can_isolate(u) && !u->refuse_manual_start);
261 }
262
263 static int property_get_job(
264 sd_bus *bus,
265 const char *path,
266 const char *interface,
267 const char *property,
268 sd_bus_message *reply,
269 sd_bus_error *error,
270 void *userdata) {
271
272 _cleanup_free_ char *p = NULL;
273 Unit *u = userdata;
274
275 assert(bus);
276 assert(reply);
277 assert(u);
278
279 if (!u->job)
280 return sd_bus_message_append(reply, "(uo)", 0, "/");
281
282 p = job_dbus_path(u->job);
283 if (!p)
284 return -ENOMEM;
285
286 return sd_bus_message_append(reply, "(uo)", u->job->id, p);
287 }
288
289 static int property_get_need_daemon_reload(
290 sd_bus *bus,
291 const char *path,
292 const char *interface,
293 const char *property,
294 sd_bus_message *reply,
295 sd_bus_error *error,
296 void *userdata) {
297
298 Unit *u = userdata;
299
300 assert(bus);
301 assert(reply);
302 assert(u);
303
304 return sd_bus_message_append(reply, "b", unit_need_daemon_reload(u));
305 }
306
307 static int property_get_conditions(
308 sd_bus *bus,
309 const char *path,
310 const char *interface,
311 const char *property,
312 sd_bus_message *reply,
313 sd_bus_error *error,
314 void *userdata) {
315
316 Unit *u = userdata;
317 Condition *c;
318 int r;
319
320 assert(bus);
321 assert(reply);
322 assert(u);
323
324 r = sd_bus_message_open_container(reply, 'a', "(sbbsi)");
325 if (r < 0)
326 return r;
327
328 LIST_FOREACH(conditions, c, u->conditions) {
329 r = sd_bus_message_append(reply, "sbbsi", condition_type_to_string(c->type), c->trigger, c->negate, c->parameter, c->state);
330 if (r < 0)
331 return r;
332
333 }
334
335 return sd_bus_message_close_container(reply);
336 }
337
338 static int property_get_load_error(
339 sd_bus *bus,
340 const char *path,
341 const char *interface,
342 const char *property,
343 sd_bus_message *reply,
344 sd_bus_error *error,
345 void *userdata) {
346
347 _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL;
348 Unit *u = userdata;
349
350 assert(bus);
351 assert(reply);
352 assert(u);
353
354 if (u->load_error != 0)
355 sd_bus_error_set_errno(&e, u->load_error);
356
357 return sd_bus_message_append(reply, "(ss)", e.name, e.message);
358 }
359
360 int bus_unit_method_start_generic(sd_bus *bus, sd_bus_message *message, Unit *u, JobType job_type, bool reload_if_possible) {
361 const char *smode;
362 JobMode mode;
363 int r;
364
365 assert(bus);
366 assert(message);
367 assert(u);
368 assert(job_type >= 0 && job_type < _JOB_TYPE_MAX);
369
370 r = sd_bus_message_read(message, "s", &smode);
371 if (r < 0)
372 return sd_bus_reply_method_errno(message, r, NULL);
373
374 mode = job_mode_from_string(smode);
375 if (mode < 0)
376 return sd_bus_reply_method_errorf(message, SD_BUS_ERROR_INVALID_ARGS, "Job mode %s invalid", smode);
377
378 return bus_unit_queue_job(bus, message, u, job_type, mode, reload_if_possible);
379 }
380
381 static int method_start(sd_bus *bus, sd_bus_message *message, void *userdata) {
382 return bus_unit_method_start_generic(bus, message, userdata, JOB_START, false);
383 }
384
385 static int method_stop(sd_bus *bus, sd_bus_message *message, void *userdata) {
386 return bus_unit_method_start_generic(bus, message, userdata, JOB_STOP, false);
387 }
388
389 static int method_reload(sd_bus *bus, sd_bus_message *message, void *userdata) {
390 return bus_unit_method_start_generic(bus, message, userdata, JOB_RELOAD, false);
391 }
392
393 static int method_restart(sd_bus *bus, sd_bus_message *message, void *userdata) {
394 return bus_unit_method_start_generic(bus, message, userdata, JOB_RESTART, false);
395 }
396
397 static int method_try_restart(sd_bus *bus, sd_bus_message *message, void *userdata) {
398 return bus_unit_method_start_generic(bus, message, userdata, JOB_TRY_RESTART, false);
399 }
400
401 static int method_reload_or_restart(sd_bus *bus, sd_bus_message *message, void *userdata) {
402 return bus_unit_method_start_generic(bus, message, userdata, JOB_RESTART, true);
403 }
404
405 static int method_reload_or_try_restart(sd_bus *bus, sd_bus_message *message, void *userdata) {
406 return bus_unit_method_start_generic(bus, message, userdata, JOB_TRY_RESTART, true);
407 }
408
409 int bus_unit_method_kill(sd_bus *bus, sd_bus_message *message, void *userdata) {
410 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
411 Unit *u = userdata;
412 const char *swho;
413 int32_t signo;
414 KillWho who;
415 int r;
416
417 assert(bus);
418 assert(message);
419 assert(u);
420
421 r = sd_bus_message_read(message, "si", &swho, &signo);
422 if (r < 0)
423 return sd_bus_reply_method_errno(message, r, NULL);
424
425 if (isempty(swho))
426 who = KILL_ALL;
427 else {
428 who = kill_who_from_string(swho);
429 if (who < 0)
430 return sd_bus_reply_method_errorf(message, SD_BUS_ERROR_INVALID_ARGS, "Invalid who argument %s", swho);
431 }
432
433 if (signo <= 0 || signo >= _NSIG)
434 return sd_bus_reply_method_errorf(message, SD_BUS_ERROR_INVALID_ARGS, "Signal number out of range.");
435
436 SELINUX_UNIT_ACCESS_CHECK(u, bus, message, "stop");
437
438 r = unit_kill(u, who, signo, &error);
439 if (r < 0)
440 return sd_bus_reply_method_errno(message, r, &error);
441
442 return sd_bus_reply_method_return(message, NULL);
443 }
444
445 int bus_unit_method_reset_failed(sd_bus *bus, sd_bus_message *message, void *userdata) {
446 Unit *u = userdata;
447
448 assert(bus);
449 assert(message);
450 assert(u);
451
452 SELINUX_UNIT_ACCESS_CHECK(u, bus, message, "reload");
453
454 unit_reset_failed(u);
455
456 return sd_bus_reply_method_return(message, NULL);
457 }
458
459 int bus_unit_method_set_properties(sd_bus *bus, sd_bus_message *message, void *userdata) {
460 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
461 Unit *u = userdata;
462 int runtime, r;
463
464 assert(bus);
465 assert(message);
466 assert(u);
467
468 r = sd_bus_message_read(message, "b", &runtime);
469 if (r < 0)
470 return sd_bus_reply_method_errno(message, r, NULL);
471
472 SELINUX_UNIT_ACCESS_CHECK(u, bus, message, "start");
473
474 r = sd_bus_message_enter_container(message, 'a', "(sv)");
475 if (r < 0)
476 return sd_bus_reply_method_errno(message, r, NULL);
477
478 r = bus_unit_set_properties(u, message, runtime ? UNIT_RUNTIME : UNIT_PERSISTENT, true, &error);
479 if (r < 0)
480 return sd_bus_reply_method_errno(message, r, &error);
481
482 r = sd_bus_message_exit_container(message);
483 if (r < 0)
484 return sd_bus_reply_method_errno(message, r, NULL);
485
486 return sd_bus_reply_method_return(message, NULL);
487 }
488
489 const sd_bus_vtable bus_unit_vtable[] = {
490 SD_BUS_VTABLE_START(0),
491
492 SD_BUS_PROPERTY("Id", "s", NULL, offsetof(Unit, id), 0),
493 SD_BUS_PROPERTY("Names", "as", property_get_names, 0, 0),
494 SD_BUS_PROPERTY("Following", "s", property_get_following, 0, 0),
495 SD_BUS_PROPERTY("Requires", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRES]), 0),
496 SD_BUS_PROPERTY("RequiresOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRES_OVERRIDABLE]), 0),
497 SD_BUS_PROPERTY("Requisite", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE]), 0),
498 SD_BUS_PROPERTY("RequisiteOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE_OVERRIDABLE]), 0),
499 SD_BUS_PROPERTY("Wants", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_WANTS]), 0),
500 SD_BUS_PROPERTY("BindsTo", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BINDS_TO]), 0),
501 SD_BUS_PROPERTY("PartOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_PART_OF]), 0),
502 SD_BUS_PROPERTY("RequiredBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRED_BY]), 0),
503 SD_BUS_PROPERTY("RequiredByOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRED_BY_OVERRIDABLE]), 0),
504 SD_BUS_PROPERTY("WantedBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_WANTED_BY]), 0),
505 SD_BUS_PROPERTY("BoundBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BOUND_BY]), 0),
506 SD_BUS_PROPERTY("ConsistsOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONSISTS_OF]), 0),
507 SD_BUS_PROPERTY("Conflicts", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONFLICTS]), 0),
508 SD_BUS_PROPERTY("ConflictedBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONFLICTED_BY]), 0),
509 SD_BUS_PROPERTY("Before", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BEFORE]), 0),
510 SD_BUS_PROPERTY("After", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_AFTER]), 0),
511 SD_BUS_PROPERTY("OnFailure", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_ON_FAILURE]), 0),
512 SD_BUS_PROPERTY("Triggers", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_TRIGGERS]), 0),
513 SD_BUS_PROPERTY("TriggeredBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_TRIGGERED_BY]), 0),
514 SD_BUS_PROPERTY("PropagatesReloadTo", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_PROPAGATES_RELOAD_TO]), 0),
515 SD_BUS_PROPERTY("ReloadPropagatedFrom", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_RELOAD_PROPAGATED_FROM]), 0),
516 SD_BUS_PROPERTY("RequiresMountsFor", "as", NULL, offsetof(Unit, requires_mounts_for), 0),
517 SD_BUS_PROPERTY("Documentation", "as", NULL, offsetof(Unit, documentation), 0),
518 SD_BUS_PROPERTY("Description", "s", property_get_description, 0, 0),
519 SD_BUS_PROPERTY("LoadState", "s", property_get_load_state, offsetof(Unit, load_state), 0),
520 SD_BUS_PROPERTY("ActiveState", "s", property_get_active_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
521 SD_BUS_PROPERTY("SubState", "s", property_get_sub_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
522 SD_BUS_PROPERTY("FragmentPath", "s", NULL, offsetof(Unit, fragment_path), 0),
523 SD_BUS_PROPERTY("SourcePath", "s", NULL, offsetof(Unit, source_path), 0),
524 SD_BUS_PROPERTY("DropInPaths", "as", NULL, offsetof(Unit, dropin_paths), 0),
525 SD_BUS_PROPERTY("UnitFileState", "s", property_get_unit_file_state, 0, 0),
526 BUS_PROPERTY_DUAL_TIMESTAMP("InactiveExitTimestamp", offsetof(Unit, inactive_exit_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
527 BUS_PROPERTY_DUAL_TIMESTAMP("ActiveEnterTimestamp", offsetof(Unit, active_enter_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
528 BUS_PROPERTY_DUAL_TIMESTAMP("ActiveExitTimestamp", offsetof(Unit, active_exit_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
529 BUS_PROPERTY_DUAL_TIMESTAMP("InactiveEnterTimestamp", offsetof(Unit, inactive_enter_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
530 SD_BUS_PROPERTY("CanStart", "b", property_get_can_start, 0, 0),
531 SD_BUS_PROPERTY("CanStop", "b", property_get_can_stop, 0, 0),
532 SD_BUS_PROPERTY("CanReload", "b", property_get_can_reload, 0, 0),
533 SD_BUS_PROPERTY("CanIsolate", "b", property_get_can_isolate, 0, 0),
534 SD_BUS_PROPERTY("Job", "(uo)", property_get_job, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
535 SD_BUS_PROPERTY("StopWhenUnneeded", "b", bus_property_get_bool, offsetof(Unit, stop_when_unneeded), 0),
536 SD_BUS_PROPERTY("RefuseManualStart", "b", bus_property_get_bool, offsetof(Unit, refuse_manual_start), 0),
537 SD_BUS_PROPERTY("RefuseManualStop", "b", bus_property_get_bool, offsetof(Unit, refuse_manual_stop), 0),
538 SD_BUS_PROPERTY("AllowIsolate", "b", bus_property_get_bool, offsetof(Unit, allow_isolate), 0),
539 SD_BUS_PROPERTY("DefaultDependencies", "b", bus_property_get_bool, offsetof(Unit, default_dependencies), 0),
540 SD_BUS_PROPERTY("OnFailureIsolate", "b", bus_property_get_bool, offsetof(Unit, on_failure_isolate), 0),
541 SD_BUS_PROPERTY("IgnoreOnIsolate", "b", bus_property_get_bool, offsetof(Unit, ignore_on_isolate), 0),
542 SD_BUS_PROPERTY("IgnoreOnSnapshot", "b", bus_property_get_bool, offsetof(Unit, ignore_on_snapshot), 0),
543 SD_BUS_PROPERTY("NeedDaemonReload", "b", property_get_need_daemon_reload, 0, 0),
544 SD_BUS_PROPERTY("JobTimeoutUSec", "t", bus_property_get_usec, offsetof(Unit, job_timeout), 0),
545 SD_BUS_PROPERTY("ConditionResult", "b", bus_property_get_bool, offsetof(Unit, condition_result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
546 BUS_PROPERTY_DUAL_TIMESTAMP("ConditionTimestamp", offsetof(Unit, condition_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
547 SD_BUS_PROPERTY("Conditions", "a(sbbsi)", property_get_conditions, 0, 0),
548 SD_BUS_PROPERTY("LoadError", "(ss)", property_get_load_error, 0, 0),
549 SD_BUS_PROPERTY("Transient", "b", bus_property_get_bool, offsetof(Unit, transient), 0),
550
551 SD_BUS_METHOD("Start", "s", "o", method_start, 0),
552 SD_BUS_METHOD("Stop", "s", "o", method_stop, 0),
553 SD_BUS_METHOD("Reload", "s", "o", method_reload, 0),
554 SD_BUS_METHOD("Restart", "s", "o", method_restart, 0),
555 SD_BUS_METHOD("TryRestart", "s", "o", method_try_restart, 0),
556 SD_BUS_METHOD("ReloadOrRestart", "s", "o", method_reload_or_restart, 0),
557 SD_BUS_METHOD("ReloadOrTryRestart", "s", "o", method_reload_or_try_restart, 0),
558 SD_BUS_METHOD("Kill", "si", NULL, bus_unit_method_kill, 0),
559 SD_BUS_METHOD("ResetFailed", NULL, NULL, bus_unit_method_reset_failed, 0),
560 SD_BUS_METHOD("SetProperties", "ba(sv)", NULL, bus_unit_method_set_properties, 0),
561
562 SD_BUS_VTABLE_END
563 };
564
565 static int property_get_slice(
566 sd_bus *bus,
567 const char *path,
568 const char *interface,
569 const char *property,
570 sd_bus_message *reply,
571 sd_bus_error *error,
572 void *userdata) {
573
574 Unit *u = userdata;
575
576 assert(bus);
577 assert(reply);
578 assert(u);
579
580 return sd_bus_message_append(reply, "s", unit_slice_name(u));
581 }
582
583 const sd_bus_vtable bus_unit_cgroup_vtable[] = {
584 SD_BUS_VTABLE_START(0),
585 SD_BUS_PROPERTY("Slice", "s", property_get_slice, 0, 0),
586 SD_BUS_PROPERTY("ControlGroup", "s", NULL, offsetof(Unit, cgroup_path), 0),
587 SD_BUS_VTABLE_END
588 };
589
590 static int send_new_signal(sd_bus *bus, const char *destination, void *userdata) {
591 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
592 _cleanup_free_ char *p = NULL;
593 Unit *u = userdata;
594 int r;
595
596 assert(bus);
597 assert(u);
598
599 p = unit_dbus_path(u);
600 if (!u)
601 return -ENOMEM;
602
603 r = sd_bus_message_new_signal(
604 bus,
605 "/org/freedesktop/systemd1",
606 "org.freedesktop.systemd1.Manager",
607 "UnitNew",
608 &m);
609 if (r < 0)
610 return r;
611
612 r = sd_bus_message_append(m, "so", u->id, p);
613 if (r < 0)
614 return r;
615
616 return sd_bus_send_to(bus, m, destination, NULL);
617 }
618
619 static int send_changed_signal(sd_bus *bus, const char *destination, void *userdata) {
620 _cleanup_free_ char *p = NULL;
621 Unit *u = userdata;
622 int r;
623
624 assert(bus);
625 assert(u);
626
627 p = unit_dbus_path(u);
628 if (!u)
629 return -ENOMEM;
630
631 /* Send a properties changed signal. First for the specific
632 * type, then for the generic unit. The clients may rely on
633 * this order to get atomic behavior if needed. */
634
635 if (UNIT_VTABLE(u)->bus_changing_properties) {
636
637 r = sd_bus_emit_properties_changed_strv(
638 bus, p,
639 UNIT_VTABLE(u)->bus_interface,
640 (char**) UNIT_VTABLE(u)->bus_changing_properties);
641 if (r < 0)
642 return r;
643 }
644
645 return sd_bus_emit_properties_changed(
646 bus, p,
647 "org.freedesktop.systemd1.Unit",
648 "ActiveState",
649 "SubState",
650 "InactiveExitTimestamp",
651 "ActiveEnterTimestamp",
652 "ActiveExitTimestamp",
653 "InactiveEnterTimestamp",
654 "Job",
655 "ConditionResult",
656 "ConditionTimestamp",
657 NULL);
658 }
659
660 void bus_unit_send_change_signal(Unit *u) {
661 int r;
662
663 assert(u);
664
665 if (u->in_dbus_queue) {
666 LIST_REMOVE(dbus_queue, u->manager->dbus_unit_queue, u);
667 u->in_dbus_queue = false;
668 }
669
670 if (!u->id)
671 return;
672
673 r = bus_manager_foreach_client(u->manager, u->sent_dbus_new_signal ? send_changed_signal : send_new_signal, u);
674 if (r < 0)
675 log_warning("Failed to send unit change signal for %s: %s", u->id, strerror(-r));
676
677 u->sent_dbus_new_signal = true;
678 }
679
680 static int send_removed_signal(sd_bus *bus, const char *destination, void *userdata) {
681 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
682 _cleanup_free_ char *p = NULL;
683 Unit *u = userdata;
684 int r;
685
686 assert(bus);
687 assert(u);
688
689 p = unit_dbus_path(u);
690 if (!u)
691 return -ENOMEM;
692
693 r = sd_bus_message_new_signal(
694 bus,
695 "/org/freedesktop/systemd1",
696 "org.freedesktop.systemd1.Manager",
697 "UnitRemoved",
698 &m);
699 if (r < 0)
700 return r;
701
702 r = sd_bus_message_append(m, "so", u->id, p);
703 if (r < 0)
704 return r;
705
706 return sd_bus_send_to(bus, m, destination, NULL);
707 }
708
709 void bus_unit_send_removed_signal(Unit *u) {
710 int r;
711
712 assert(u);
713
714 if (!u->sent_dbus_new_signal)
715 bus_unit_send_change_signal(u);
716
717 if (!u->id)
718 return;
719
720 r = bus_manager_foreach_client(u->manager, send_removed_signal, u);
721 if (r < 0)
722 log_warning("Failed to send unit change signal for %s: %s", u->id, strerror(-r));
723 }
724
725 int bus_unit_queue_job(
726 sd_bus *bus,
727 sd_bus_message *message,
728 Unit *u,
729 JobType type,
730 JobMode mode,
731 bool reload_if_possible) {
732
733 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
734 _cleanup_free_ char *path = NULL;
735 Job *j;
736 int r;
737
738 assert(bus);
739 assert(message);
740 assert(u);
741 assert(type >= 0 && type < _JOB_TYPE_MAX);
742 assert(mode >= 0 && mode < _JOB_MODE_MAX);
743
744 if (reload_if_possible && unit_can_reload(u)) {
745 if (type == JOB_RESTART)
746 type = JOB_RELOAD_OR_START;
747 else if (type == JOB_TRY_RESTART)
748 type = JOB_RELOAD;
749 }
750
751 SELINUX_UNIT_ACCESS_CHECK(u, bus, message,
752 (type == JOB_START || type == JOB_RESTART || type == JOB_TRY_RESTART) ? "start" :
753 type == JOB_STOP ? "stop" : "reload");
754
755 if (type == JOB_STOP &&
756 (u->load_state == UNIT_NOT_FOUND || u->load_state == UNIT_ERROR) &&
757 unit_active_state(u) == UNIT_INACTIVE)
758 return sd_bus_reply_method_errorf(message, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not loaded.", u->id);
759
760 if ((type == JOB_START && u->refuse_manual_start) ||
761 (type == JOB_STOP && u->refuse_manual_stop) ||
762 ((type == JOB_RESTART || type == JOB_TRY_RESTART) && (u->refuse_manual_start || u->refuse_manual_stop)))
763 return sd_bus_reply_method_errorf(message, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, unit %s may be requested by dependency only.", u->id);
764
765 r = manager_add_job(u->manager, type, u, mode, true, &error, &j);
766 if (r < 0)
767 return sd_bus_reply_method_errno(message, r, &error);
768
769 r = bus_client_track(&j->subscribed, bus, sd_bus_message_get_sender(message));
770 if (r < 0)
771 return sd_bus_reply_method_errno(message, r, NULL);
772
773 path = job_dbus_path(j);
774 if (!path)
775 return sd_bus_reply_method_errno(message, r, NULL);
776
777 return sd_bus_reply_method_return(message, "o", path);
778 }
779
780 static int bus_unit_set_transient_property(
781 Unit *u,
782 const char *name,
783 sd_bus_message *message,
784 UnitSetPropertiesMode mode,
785 sd_bus_error *error) {
786
787 int r;
788
789 assert(u);
790 assert(name);
791 assert(message);
792
793 if (streq(name, "Description")) {
794 const char *d;
795
796 r = sd_bus_message_read(message, "s", &d);
797 if (r < 0)
798 return r;
799
800 if (mode != UNIT_CHECK) {
801 r = unit_set_description(u, d);
802 if (r < 0)
803 return r;
804
805 unit_write_drop_in_format(u, mode, name, "[Unit]\nDescription=%s\n", d);
806 }
807
808 return 1;
809
810 } else if (streq(name, "Slice") && unit_get_cgroup_context(u)) {
811 const char *s;
812
813 r = sd_bus_message_read(message, "s", &s);
814 if (r < 0)
815 return r;
816
817 if (!unit_name_is_valid(s, false) || !endswith(s, ".slice"))
818 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid slice name %s", s);
819
820 if (isempty(s)) {
821 if (mode != UNIT_CHECK) {
822 unit_ref_unset(&u->slice);
823 unit_remove_drop_in(u, mode, name);
824 }
825 } else {
826 Unit *slice;
827
828 r = manager_load_unit(u->manager, s, NULL, error, &slice);
829 if (r < 0)
830 return r;
831
832 if (slice->type != UNIT_SLICE)
833 return -EINVAL;
834
835 if (mode != UNIT_CHECK) {
836 unit_ref_set(&u->slice, slice);
837 unit_write_drop_in_private_format(u, mode, name, "Slice=%s\n", s);
838 }
839 }
840
841 return 1;
842
843 } else if (streq(name, "Requires") ||
844 streq(name, "RequiresOverridable") ||
845 streq(name, "Requisite") ||
846 streq(name, "RequisiteOverridable") ||
847 streq(name, "Wants") ||
848 streq(name, "BindsTo") ||
849 streq(name, "Conflicts") ||
850 streq(name, "Before") ||
851 streq(name, "After") ||
852 streq(name, "OnFailure") ||
853 streq(name, "PropagatesReloadTo") ||
854 streq(name, "ReloadPropagatedFrom") ||
855 streq(name, "PartOf")) {
856
857 UnitDependency d;
858 const char *other;
859
860 d = unit_dependency_from_string(name);
861 if (d < 0)
862 return -EINVAL;
863
864 r = sd_bus_message_enter_container(message, 'a', "s");
865 if (r < 0)
866 return r;
867
868 while ((r = sd_bus_message_read(message, "s", &other)) > 0) {
869 if (!unit_name_is_valid(other, false))
870 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit name %s", other);
871
872 if (mode != UNIT_CHECK) {
873 _cleanup_free_ char *label = NULL;
874
875 r = unit_add_dependency_by_name(u, d, other, NULL, true);
876 if (r < 0)
877 return r;
878
879 label = strjoin(name, "-", other, NULL);
880 if (!label)
881 return -ENOMEM;
882
883 unit_write_drop_in_format(u, mode, label, "[Unit]\n%s=%s\n", name, other);
884 }
885
886 }
887 if (r < 0)
888 return r;
889
890 return 1;
891 }
892
893 return 0;
894 }
895
896 int bus_unit_set_properties(
897 Unit *u,
898 sd_bus_message *message,
899 UnitSetPropertiesMode mode,
900 bool commit,
901 sd_bus_error *error) {
902
903 bool for_real = false;
904 unsigned n = 0;
905 int r;
906
907 assert(u);
908 assert(message);
909
910 if (u->transient)
911 mode &= UNIT_RUNTIME;
912
913 /* We iterate through the array twice. First run we just check
914 * if all passed data is valid, second run actually applies
915 * it. This is to implement transaction-like behaviour without
916 * actually providing full transactions. */
917
918 r = sd_bus_message_enter_container(message, 'a', "(sv)");
919 if (r < 0)
920 return r;
921
922 for (;;) {
923 const char *name;
924
925 r = sd_bus_message_enter_container(message, 'r', "sv");
926 if (r < 0)
927 return r;
928 if (r == 0) {
929 if (for_real || mode == UNIT_CHECK)
930 break;
931
932 /* Reached EOF. Let's try again, and this time for realz... */
933 r = sd_bus_message_rewind(message, false);
934 if (r < 0)
935 return r;
936 for_real = true;
937 continue;
938 }
939
940 r = sd_bus_message_read(message, "s", &name);
941 if (r < 0)
942 return r;
943
944 if (!UNIT_VTABLE(u)->bus_set_property)
945 return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Objects of this type do not support setting properties.");
946
947 r = sd_bus_message_enter_container(message, 'v', NULL);
948 if (r < 0)
949 return r;
950
951 r = UNIT_VTABLE(u)->bus_set_property(u, name, message, for_real ? mode : UNIT_CHECK, error);
952 if (r == 0 && u->transient && u->load_state == UNIT_STUB)
953 r = bus_unit_set_transient_property(u, name, message, for_real ? mode : UNIT_CHECK, error);
954 if (r < 0)
955 return r;
956 if (r == 0)
957 return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Cannot set property %s, or unknown property.", name);
958
959 r = sd_bus_message_exit_container(message);
960 if (r < 0)
961 return r;
962
963 r = sd_bus_message_exit_container(message);
964 if (r < 0)
965 return r;
966
967 n += for_real;
968 }
969
970 if (commit && n > 0 && UNIT_VTABLE(u)->bus_commit_properties)
971 UNIT_VTABLE(u)->bus_commit_properties(u);
972
973 return n;
974 }