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