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