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