]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/dbus-unit.c
core: add support for the "pids" cgroup controller
[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 static int bus_verify_manage_units_async_full(
395 Unit *u,
396 const char *verb,
397 int capability,
398 const char *polkit_message,
399 sd_bus_message *call,
400 sd_bus_error *error) {
401
402 const char *details[9] = {
403 "unit", u->id,
404 "verb", verb,
405 };
406
407 if (polkit_message) {
408 details[4] = "polkit.message";
409 details[5] = polkit_message;
410 details[6] = "polkit.gettext_domain";
411 details[7] = GETTEXT_PACKAGE;
412 }
413
414 return bus_verify_polkit_async(call, capability, "org.freedesktop.systemd1.manage-units", details, false, UID_INVALID, &u->manager->polkit_registry, error);
415 }
416
417 int bus_unit_method_start_generic(
418 sd_bus_message *message,
419 Unit *u,
420 JobType job_type,
421 bool reload_if_possible,
422 sd_bus_error *error) {
423
424 const char *smode;
425 JobMode mode;
426 _cleanup_free_ char *verb = NULL;
427 static const char *const polkit_message_for_job[_JOB_TYPE_MAX] = {
428 [JOB_START] = N_("Authentication is required to start '$(unit)'."),
429 [JOB_STOP] = N_("Authentication is required to stop '$(unit)'."),
430 [JOB_RELOAD] = N_("Authentication is required to reload '$(unit)'."),
431 [JOB_RESTART] = N_("Authentication is required to restart '$(unit)'."),
432 [JOB_TRY_RESTART] = N_("Authentication is required to restart '$(unit)'."),
433 };
434 int r;
435
436 assert(message);
437 assert(u);
438 assert(job_type >= 0 && job_type < _JOB_TYPE_MAX);
439
440 r = mac_selinux_unit_access_check(u, message, job_type == JOB_STOP ? "stop" : "start", error);
441 if (r < 0)
442 return r;
443
444 r = sd_bus_message_read(message, "s", &smode);
445 if (r < 0)
446 return r;
447
448 mode = job_mode_from_string(smode);
449 if (mode < 0)
450 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Job mode %s invalid", smode);
451
452 if (reload_if_possible)
453 verb = strjoin("reload-or-", job_type_to_string(job_type), NULL);
454 else
455 verb = strdup(job_type_to_string(job_type));
456 if (!verb)
457 return -ENOMEM;
458
459 r = bus_verify_manage_units_async_full(
460 u,
461 verb,
462 CAP_SYS_ADMIN,
463 job_type < _JOB_TYPE_MAX ? polkit_message_for_job[job_type] : NULL,
464 message,
465 error);
466 if (r < 0)
467 return r;
468 if (r == 0)
469 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
470
471 return bus_unit_queue_job(message, u, job_type, mode, reload_if_possible, error);
472 }
473
474 static int method_start(sd_bus_message *message, void *userdata, sd_bus_error *error) {
475 return bus_unit_method_start_generic(message, userdata, JOB_START, false, error);
476 }
477
478 static int method_stop(sd_bus_message *message, void *userdata, sd_bus_error *error) {
479 return bus_unit_method_start_generic(message, userdata, JOB_STOP, false, error);
480 }
481
482 static int method_reload(sd_bus_message *message, void *userdata, sd_bus_error *error) {
483 return bus_unit_method_start_generic(message, userdata, JOB_RELOAD, false, error);
484 }
485
486 static int method_restart(sd_bus_message *message, void *userdata, sd_bus_error *error) {
487 return bus_unit_method_start_generic(message, userdata, JOB_RESTART, false, error);
488 }
489
490 static int method_try_restart(sd_bus_message *message, void *userdata, sd_bus_error *error) {
491 return bus_unit_method_start_generic(message, userdata, JOB_TRY_RESTART, false, error);
492 }
493
494 static int method_reload_or_restart(sd_bus_message *message, void *userdata, sd_bus_error *error) {
495 return bus_unit_method_start_generic(message, userdata, JOB_RESTART, true, error);
496 }
497
498 static int method_reload_or_try_restart(sd_bus_message *message, void *userdata, sd_bus_error *error) {
499 return bus_unit_method_start_generic(message, userdata, JOB_TRY_RESTART, true, error);
500 }
501
502 int bus_unit_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *error) {
503 Unit *u = userdata;
504 const char *swho;
505 int32_t signo;
506 KillWho who;
507 int r;
508
509 assert(message);
510 assert(u);
511
512 r = mac_selinux_unit_access_check(u, message, "stop", error);
513 if (r < 0)
514 return r;
515
516 r = sd_bus_message_read(message, "si", &swho, &signo);
517 if (r < 0)
518 return r;
519
520 if (isempty(swho))
521 who = KILL_ALL;
522 else {
523 who = kill_who_from_string(swho);
524 if (who < 0)
525 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid who argument %s", swho);
526 }
527
528 if (signo <= 0 || signo >= _NSIG)
529 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Signal number out of range.");
530
531 r = bus_verify_manage_units_async_full(
532 u,
533 "kill",
534 CAP_KILL,
535 N_("Authentication is required to kill '$(unit)'."),
536 message,
537 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 = unit_kill(u, who, signo, error);
544 if (r < 0)
545 return r;
546
547 return sd_bus_reply_method_return(message, NULL);
548 }
549
550 int bus_unit_method_reset_failed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
551 Unit *u = userdata;
552 int r;
553
554 assert(message);
555 assert(u);
556
557 r = mac_selinux_unit_access_check(u, message, "reload", error);
558 if (r < 0)
559 return r;
560
561 r = bus_verify_manage_units_async_full(
562 u,
563 "reset-failed",
564 CAP_SYS_ADMIN,
565 N_("Authentication is required to reset the \"failed\" state of '$(unit)'."),
566 message,
567 error);
568 if (r < 0)
569 return r;
570 if (r == 0)
571 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
572
573 unit_reset_failed(u);
574
575 return sd_bus_reply_method_return(message, NULL);
576 }
577
578 int bus_unit_method_set_properties(sd_bus_message *message, void *userdata, sd_bus_error *error) {
579 Unit *u = userdata;
580 int runtime, r;
581
582 assert(message);
583 assert(u);
584
585 r = mac_selinux_unit_access_check(u, message, "start", error);
586 if (r < 0)
587 return r;
588
589 r = sd_bus_message_read(message, "b", &runtime);
590 if (r < 0)
591 return r;
592
593 r = bus_verify_manage_units_async_full(
594 u,
595 "set-property",
596 CAP_SYS_ADMIN,
597 N_("Authentication is required to set properties on '$(unit)'."),
598 message,
599 error);
600 if (r < 0)
601 return r;
602 if (r == 0)
603 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
604
605 r = bus_unit_set_properties(u, message, runtime ? UNIT_RUNTIME : UNIT_PERSISTENT, true, error);
606 if (r < 0)
607 return r;
608
609 return sd_bus_reply_method_return(message, NULL);
610 }
611
612 const sd_bus_vtable bus_unit_vtable[] = {
613 SD_BUS_VTABLE_START(0),
614
615 SD_BUS_PROPERTY("Id", "s", NULL, offsetof(Unit, id), SD_BUS_VTABLE_PROPERTY_CONST),
616 SD_BUS_PROPERTY("Names", "as", property_get_names, 0, SD_BUS_VTABLE_PROPERTY_CONST),
617 SD_BUS_PROPERTY("Following", "s", property_get_following, 0, 0),
618 SD_BUS_PROPERTY("Requires", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRES]), SD_BUS_VTABLE_PROPERTY_CONST),
619 SD_BUS_PROPERTY("RequiresOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRES_OVERRIDABLE]), SD_BUS_VTABLE_PROPERTY_CONST),
620 SD_BUS_PROPERTY("Requisite", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE]), SD_BUS_VTABLE_PROPERTY_CONST),
621 SD_BUS_PROPERTY("RequisiteOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE_OVERRIDABLE]), SD_BUS_VTABLE_PROPERTY_CONST),
622 SD_BUS_PROPERTY("Wants", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_WANTS]), SD_BUS_VTABLE_PROPERTY_CONST),
623 SD_BUS_PROPERTY("BindsTo", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BINDS_TO]), SD_BUS_VTABLE_PROPERTY_CONST),
624 SD_BUS_PROPERTY("PartOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_PART_OF]), SD_BUS_VTABLE_PROPERTY_CONST),
625 SD_BUS_PROPERTY("RequiredBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
626 SD_BUS_PROPERTY("RequiredByOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRED_BY_OVERRIDABLE]), SD_BUS_VTABLE_PROPERTY_CONST),
627 SD_BUS_PROPERTY("RequisiteOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE_OF]), SD_BUS_VTABLE_PROPERTY_CONST),
628 SD_BUS_PROPERTY("RequisiteOfOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE_OF_OVERRIDABLE]), SD_BUS_VTABLE_PROPERTY_CONST),
629 SD_BUS_PROPERTY("WantedBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_WANTED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
630 SD_BUS_PROPERTY("BoundBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BOUND_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
631 SD_BUS_PROPERTY("ConsistsOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONSISTS_OF]), SD_BUS_VTABLE_PROPERTY_CONST),
632 SD_BUS_PROPERTY("Conflicts", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONFLICTS]), SD_BUS_VTABLE_PROPERTY_CONST),
633 SD_BUS_PROPERTY("ConflictedBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONFLICTED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
634 SD_BUS_PROPERTY("Before", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BEFORE]), SD_BUS_VTABLE_PROPERTY_CONST),
635 SD_BUS_PROPERTY("After", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_AFTER]), SD_BUS_VTABLE_PROPERTY_CONST),
636 SD_BUS_PROPERTY("OnFailure", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_ON_FAILURE]), SD_BUS_VTABLE_PROPERTY_CONST),
637 SD_BUS_PROPERTY("Triggers", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_TRIGGERS]), SD_BUS_VTABLE_PROPERTY_CONST),
638 SD_BUS_PROPERTY("TriggeredBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_TRIGGERED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
639 SD_BUS_PROPERTY("PropagatesReloadTo", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_PROPAGATES_RELOAD_TO]), SD_BUS_VTABLE_PROPERTY_CONST),
640 SD_BUS_PROPERTY("ReloadPropagatedFrom", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_RELOAD_PROPAGATED_FROM]), SD_BUS_VTABLE_PROPERTY_CONST),
641 SD_BUS_PROPERTY("JoinsNamespaceOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_JOINS_NAMESPACE_OF]), SD_BUS_VTABLE_PROPERTY_CONST),
642 SD_BUS_PROPERTY("RequiresMountsFor", "as", NULL, offsetof(Unit, requires_mounts_for), SD_BUS_VTABLE_PROPERTY_CONST),
643 SD_BUS_PROPERTY("Documentation", "as", NULL, offsetof(Unit, documentation), SD_BUS_VTABLE_PROPERTY_CONST),
644 SD_BUS_PROPERTY("Description", "s", property_get_description, 0, SD_BUS_VTABLE_PROPERTY_CONST),
645 SD_BUS_PROPERTY("LoadState", "s", property_get_load_state, offsetof(Unit, load_state), SD_BUS_VTABLE_PROPERTY_CONST),
646 SD_BUS_PROPERTY("ActiveState", "s", property_get_active_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
647 SD_BUS_PROPERTY("SubState", "s", property_get_sub_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
648 SD_BUS_PROPERTY("FragmentPath", "s", NULL, offsetof(Unit, fragment_path), SD_BUS_VTABLE_PROPERTY_CONST),
649 SD_BUS_PROPERTY("SourcePath", "s", NULL, offsetof(Unit, source_path), SD_BUS_VTABLE_PROPERTY_CONST),
650 SD_BUS_PROPERTY("DropInPaths", "as", NULL, offsetof(Unit, dropin_paths), SD_BUS_VTABLE_PROPERTY_CONST),
651 SD_BUS_PROPERTY("UnitFileState", "s", property_get_unit_file_state, 0, 0),
652 SD_BUS_PROPERTY("UnitFilePreset", "s", property_get_unit_file_preset, 0, 0),
653 BUS_PROPERTY_DUAL_TIMESTAMP("InactiveExitTimestamp", offsetof(Unit, inactive_exit_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
654 BUS_PROPERTY_DUAL_TIMESTAMP("ActiveEnterTimestamp", offsetof(Unit, active_enter_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
655 BUS_PROPERTY_DUAL_TIMESTAMP("ActiveExitTimestamp", offsetof(Unit, active_exit_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
656 BUS_PROPERTY_DUAL_TIMESTAMP("InactiveEnterTimestamp", offsetof(Unit, inactive_enter_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
657 SD_BUS_PROPERTY("CanStart", "b", property_get_can_start, 0, SD_BUS_VTABLE_PROPERTY_CONST),
658 SD_BUS_PROPERTY("CanStop", "b", property_get_can_stop, 0, SD_BUS_VTABLE_PROPERTY_CONST),
659 SD_BUS_PROPERTY("CanReload", "b", property_get_can_reload, 0, SD_BUS_VTABLE_PROPERTY_CONST),
660 SD_BUS_PROPERTY("CanIsolate", "b", property_get_can_isolate, 0, SD_BUS_VTABLE_PROPERTY_CONST),
661 SD_BUS_PROPERTY("Job", "(uo)", property_get_job, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
662 SD_BUS_PROPERTY("StopWhenUnneeded", "b", bus_property_get_bool, offsetof(Unit, stop_when_unneeded), SD_BUS_VTABLE_PROPERTY_CONST),
663 SD_BUS_PROPERTY("RefuseManualStart", "b", bus_property_get_bool, offsetof(Unit, refuse_manual_start), SD_BUS_VTABLE_PROPERTY_CONST),
664 SD_BUS_PROPERTY("RefuseManualStop", "b", bus_property_get_bool, offsetof(Unit, refuse_manual_stop), SD_BUS_VTABLE_PROPERTY_CONST),
665 SD_BUS_PROPERTY("AllowIsolate", "b", bus_property_get_bool, offsetof(Unit, allow_isolate), SD_BUS_VTABLE_PROPERTY_CONST),
666 SD_BUS_PROPERTY("DefaultDependencies", "b", bus_property_get_bool, offsetof(Unit, default_dependencies), SD_BUS_VTABLE_PROPERTY_CONST),
667 SD_BUS_PROPERTY("OnFailureJobMode", "s", property_get_job_mode, offsetof(Unit, on_failure_job_mode), SD_BUS_VTABLE_PROPERTY_CONST),
668 SD_BUS_PROPERTY("IgnoreOnIsolate", "b", bus_property_get_bool, offsetof(Unit, ignore_on_isolate), SD_BUS_VTABLE_PROPERTY_CONST),
669 SD_BUS_PROPERTY("IgnoreOnSnapshot", "b", bus_property_get_bool, offsetof(Unit, ignore_on_snapshot), SD_BUS_VTABLE_PROPERTY_CONST),
670 SD_BUS_PROPERTY("NeedDaemonReload", "b", property_get_need_daemon_reload, 0, SD_BUS_VTABLE_PROPERTY_CONST),
671 SD_BUS_PROPERTY("JobTimeoutUSec", "t", bus_property_get_usec, offsetof(Unit, job_timeout), SD_BUS_VTABLE_PROPERTY_CONST),
672 SD_BUS_PROPERTY("JobTimeoutAction", "s", property_get_failure_action, offsetof(Unit, job_timeout_action), SD_BUS_VTABLE_PROPERTY_CONST),
673 SD_BUS_PROPERTY("JobTimeoutRebootArgument", "s", NULL, offsetof(Unit, job_timeout_reboot_arg), SD_BUS_VTABLE_PROPERTY_CONST),
674 SD_BUS_PROPERTY("ConditionResult", "b", bus_property_get_bool, offsetof(Unit, condition_result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
675 SD_BUS_PROPERTY("AssertResult", "b", bus_property_get_bool, offsetof(Unit, assert_result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
676 BUS_PROPERTY_DUAL_TIMESTAMP("ConditionTimestamp", offsetof(Unit, condition_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
677 BUS_PROPERTY_DUAL_TIMESTAMP("AssertTimestamp", offsetof(Unit, assert_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
678 SD_BUS_PROPERTY("Conditions", "a(sbbsi)", property_get_conditions, offsetof(Unit, conditions), 0),
679 SD_BUS_PROPERTY("Asserts", "a(sbbsi)", property_get_conditions, offsetof(Unit, asserts), 0),
680 SD_BUS_PROPERTY("LoadError", "(ss)", property_get_load_error, 0, SD_BUS_VTABLE_PROPERTY_CONST),
681 SD_BUS_PROPERTY("Transient", "b", bus_property_get_bool, offsetof(Unit, transient), SD_BUS_VTABLE_PROPERTY_CONST),
682
683 SD_BUS_METHOD("Start", "s", "o", method_start, SD_BUS_VTABLE_UNPRIVILEGED),
684 SD_BUS_METHOD("Stop", "s", "o", method_stop, SD_BUS_VTABLE_UNPRIVILEGED),
685 SD_BUS_METHOD("Reload", "s", "o", method_reload, SD_BUS_VTABLE_UNPRIVILEGED),
686 SD_BUS_METHOD("Restart", "s", "o", method_restart, SD_BUS_VTABLE_UNPRIVILEGED),
687 SD_BUS_METHOD("TryRestart", "s", "o", method_try_restart, SD_BUS_VTABLE_UNPRIVILEGED),
688 SD_BUS_METHOD("ReloadOrRestart", "s", "o", method_reload_or_restart, SD_BUS_VTABLE_UNPRIVILEGED),
689 SD_BUS_METHOD("ReloadOrTryRestart", "s", "o", method_reload_or_try_restart, SD_BUS_VTABLE_UNPRIVILEGED),
690 SD_BUS_METHOD("Kill", "si", NULL, bus_unit_method_kill, SD_BUS_VTABLE_UNPRIVILEGED),
691 SD_BUS_METHOD("ResetFailed", NULL, NULL, bus_unit_method_reset_failed, SD_BUS_VTABLE_UNPRIVILEGED),
692 SD_BUS_METHOD("SetProperties", "ba(sv)", NULL, bus_unit_method_set_properties, SD_BUS_VTABLE_UNPRIVILEGED),
693
694 SD_BUS_VTABLE_END
695 };
696
697 static int property_get_slice(
698 sd_bus *bus,
699 const char *path,
700 const char *interface,
701 const char *property,
702 sd_bus_message *reply,
703 void *userdata,
704 sd_bus_error *error) {
705
706 Unit *u = userdata;
707
708 assert(bus);
709 assert(reply);
710 assert(u);
711
712 return sd_bus_message_append(reply, "s", unit_slice_name(u));
713 }
714
715 static int property_get_current_memory(
716 sd_bus *bus,
717 const char *path,
718 const char *interface,
719 const char *property,
720 sd_bus_message *reply,
721 void *userdata,
722 sd_bus_error *error) {
723
724 uint64_t sz = (uint64_t) -1;
725 Unit *u = userdata;
726 int r;
727
728 assert(bus);
729 assert(reply);
730 assert(u);
731
732 r = unit_get_memory_current(u, &sz);
733 if (r < 0 && r != -ENODATA)
734 log_unit_warning_errno(u, r, "Failed to get memory.usage_in_bytes attribute: %m");
735
736 return sd_bus_message_append(reply, "t", sz);
737 }
738
739 static int property_get_current_tasks(
740 sd_bus *bus,
741 const char *path,
742 const char *interface,
743 const char *property,
744 sd_bus_message *reply,
745 void *userdata,
746 sd_bus_error *error) {
747
748 uint64_t cn = (uint64_t) -1;
749 Unit *u = userdata;
750 int r;
751
752 assert(bus);
753 assert(reply);
754 assert(u);
755
756 r = unit_get_tasks_current(u, &cn);
757 if (r < 0 && r != -ENODATA)
758 log_unit_warning_errno(u, r, "Failed to get pids.current attribute: %m");
759
760 return sd_bus_message_append(reply, "t", cn);
761 }
762
763 static int property_get_cpu_usage(
764 sd_bus *bus,
765 const char *path,
766 const char *interface,
767 const char *property,
768 sd_bus_message *reply,
769 void *userdata,
770 sd_bus_error *error) {
771
772 nsec_t ns = (nsec_t) -1;
773 Unit *u = userdata;
774 int r;
775
776 assert(bus);
777 assert(reply);
778 assert(u);
779
780 r = unit_get_cpu_usage(u, &ns);
781 if (r < 0 && r != -ENODATA)
782 log_unit_warning_errno(u, r, "Failed to get cpuacct.usage attribute: %m");
783
784 return sd_bus_message_append(reply, "t", ns);
785 }
786
787 static int property_get_cgroup(
788 sd_bus *bus,
789 const char *path,
790 const char *interface,
791 const char *property,
792 sd_bus_message *reply,
793 void *userdata,
794 sd_bus_error *error) {
795
796 Unit *u = userdata;
797 const char *t;
798
799 assert(bus);
800 assert(reply);
801 assert(u);
802
803 /* Three cases: a) u->cgroup_path is NULL, in which case the
804 * unit has no control group, which we report as the empty
805 * string. b) u->cgroup_path is the empty string, which
806 * indicates the root cgroup, which we report as "/". c) all
807 * other cases we report as-is. */
808
809 if (u->cgroup_path)
810 t = isempty(u->cgroup_path) ? "/" : u->cgroup_path;
811 else
812 t = "";
813
814 return sd_bus_message_append(reply, "s", t);
815 }
816
817 const sd_bus_vtable bus_unit_cgroup_vtable[] = {
818 SD_BUS_VTABLE_START(0),
819 SD_BUS_PROPERTY("Slice", "s", property_get_slice, 0, 0),
820 SD_BUS_PROPERTY("ControlGroup", "s", property_get_cgroup, 0, 0),
821 SD_BUS_PROPERTY("MemoryCurrent", "t", property_get_current_memory, 0, 0),
822 SD_BUS_PROPERTY("CPUUsageNSec", "t", property_get_cpu_usage, 0, 0),
823 SD_BUS_PROPERTY("TasksCurrent", "t", property_get_current_tasks, 0, 0),
824 SD_BUS_VTABLE_END
825 };
826
827 static int send_new_signal(sd_bus *bus, void *userdata) {
828 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
829 _cleanup_free_ char *p = NULL;
830 Unit *u = userdata;
831 int r;
832
833 assert(bus);
834 assert(u);
835
836 p = unit_dbus_path(u);
837 if (!p)
838 return -ENOMEM;
839
840 r = sd_bus_message_new_signal(
841 bus,
842 &m,
843 "/org/freedesktop/systemd1",
844 "org.freedesktop.systemd1.Manager",
845 "UnitNew");
846 if (r < 0)
847 return r;
848
849 r = sd_bus_message_append(m, "so", u->id, p);
850 if (r < 0)
851 return r;
852
853 return sd_bus_send(bus, m, NULL);
854 }
855
856 static int send_changed_signal(sd_bus *bus, void *userdata) {
857 _cleanup_free_ char *p = NULL;
858 Unit *u = userdata;
859 int r;
860
861 assert(bus);
862 assert(u);
863
864 p = unit_dbus_path(u);
865 if (!p)
866 return -ENOMEM;
867
868 /* Send a properties changed signal. First for the specific
869 * type, then for the generic unit. The clients may rely on
870 * this order to get atomic behavior if needed. */
871
872 r = sd_bus_emit_properties_changed_strv(
873 bus, p,
874 unit_dbus_interface_from_type(u->type),
875 NULL);
876 if (r < 0)
877 return r;
878
879 return sd_bus_emit_properties_changed_strv(
880 bus, p,
881 "org.freedesktop.systemd1.Unit",
882 NULL);
883 }
884
885 void bus_unit_send_change_signal(Unit *u) {
886 int r;
887 assert(u);
888
889 if (u->in_dbus_queue) {
890 LIST_REMOVE(dbus_queue, u->manager->dbus_unit_queue, u);
891 u->in_dbus_queue = false;
892 }
893
894 if (!u->id)
895 return;
896
897 r = bus_foreach_bus(u->manager, NULL, u->sent_dbus_new_signal ? send_changed_signal : send_new_signal, u);
898 if (r < 0)
899 log_unit_debug_errno(u, r, "Failed to send unit change signal for %s: %m", u->id);
900
901 u->sent_dbus_new_signal = true;
902 }
903
904 static int send_removed_signal(sd_bus *bus, void *userdata) {
905 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
906 _cleanup_free_ char *p = NULL;
907 Unit *u = userdata;
908 int r;
909
910 assert(bus);
911 assert(u);
912
913 p = unit_dbus_path(u);
914 if (!p)
915 return -ENOMEM;
916
917 r = sd_bus_message_new_signal(
918 bus,
919 &m,
920 "/org/freedesktop/systemd1",
921 "org.freedesktop.systemd1.Manager",
922 "UnitRemoved");
923 if (r < 0)
924 return r;
925
926 r = sd_bus_message_append(m, "so", u->id, p);
927 if (r < 0)
928 return r;
929
930 return sd_bus_send(bus, m, NULL);
931 }
932
933 void bus_unit_send_removed_signal(Unit *u) {
934 int r;
935 assert(u);
936
937 if (!u->sent_dbus_new_signal)
938 bus_unit_send_change_signal(u);
939
940 if (!u->id)
941 return;
942
943 r = bus_foreach_bus(u->manager, NULL, send_removed_signal, u);
944 if (r < 0)
945 log_unit_debug_errno(u, r, "Failed to send unit remove signal for %s: %m", u->id);
946 }
947
948 int bus_unit_queue_job(
949 sd_bus_message *message,
950 Unit *u,
951 JobType type,
952 JobMode mode,
953 bool reload_if_possible,
954 sd_bus_error *error) {
955
956 _cleanup_free_ char *path = NULL;
957 Job *j;
958 int r;
959
960 assert(message);
961 assert(u);
962 assert(type >= 0 && type < _JOB_TYPE_MAX);
963 assert(mode >= 0 && mode < _JOB_MODE_MAX);
964
965 if (reload_if_possible && unit_can_reload(u)) {
966 if (type == JOB_RESTART)
967 type = JOB_RELOAD_OR_START;
968 else if (type == JOB_TRY_RESTART)
969 type = JOB_RELOAD;
970 }
971
972 r = mac_selinux_unit_access_check(
973 u, message,
974 (type == JOB_START || type == JOB_RESTART || type == JOB_TRY_RESTART) ? "start" :
975 type == JOB_STOP ? "stop" : "reload", error);
976 if (r < 0)
977 return r;
978
979 if (type == JOB_STOP &&
980 (u->load_state == UNIT_NOT_FOUND || u->load_state == UNIT_ERROR) &&
981 unit_active_state(u) == UNIT_INACTIVE)
982 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not loaded.", u->id);
983
984 if ((type == JOB_START && u->refuse_manual_start) ||
985 (type == JOB_STOP && u->refuse_manual_stop) ||
986 ((type == JOB_RESTART || type == JOB_TRY_RESTART) && (u->refuse_manual_start || u->refuse_manual_stop)))
987 return sd_bus_error_setf(error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, unit %s may be requested by dependency only.", u->id);
988
989 r = manager_add_job(u->manager, type, u, mode, true, error, &j);
990 if (r < 0)
991 return r;
992
993 if (sd_bus_message_get_bus(message) == u->manager->api_bus) {
994 if (!j->clients) {
995 r = sd_bus_track_new(sd_bus_message_get_bus(message), &j->clients, NULL, NULL);
996 if (r < 0)
997 return r;
998 }
999
1000 r = sd_bus_track_add_sender(j->clients, message);
1001 if (r < 0)
1002 return r;
1003 }
1004
1005 path = job_dbus_path(j);
1006 if (!path)
1007 return -ENOMEM;
1008
1009 return sd_bus_reply_method_return(message, "o", path);
1010 }
1011
1012 static int bus_unit_set_transient_property(
1013 Unit *u,
1014 const char *name,
1015 sd_bus_message *message,
1016 UnitSetPropertiesMode mode,
1017 sd_bus_error *error) {
1018
1019 int r;
1020
1021 assert(u);
1022 assert(name);
1023 assert(message);
1024
1025 if (streq(name, "Description")) {
1026 const char *d;
1027
1028 r = sd_bus_message_read(message, "s", &d);
1029 if (r < 0)
1030 return r;
1031
1032 if (mode != UNIT_CHECK) {
1033 r = unit_set_description(u, d);
1034 if (r < 0)
1035 return r;
1036
1037 unit_write_drop_in_format(u, mode, name, "[Unit]\nDescription=%s\n", d);
1038 }
1039
1040 return 1;
1041
1042 } else if (streq(name, "DefaultDependencies")) {
1043 int b;
1044
1045 r = sd_bus_message_read(message, "b", &b);
1046 if (r < 0)
1047 return r;
1048
1049 if (mode != UNIT_CHECK) {
1050 u->default_dependencies = b;
1051 unit_write_drop_in_format(u, mode, name, "[Unit]\nDefaultDependencies=%s\n", yes_no(b));
1052 }
1053
1054 return 1;
1055
1056 } else if (streq(name, "Slice")) {
1057 Unit *slice;
1058 const char *s;
1059
1060 if (!UNIT_HAS_CGROUP_CONTEXT(u))
1061 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "The slice property is only available for units with control groups.");
1062 if (u->type == UNIT_SLICE)
1063 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Slice may not be set for slice units.");
1064 if (unit_has_name(u, SPECIAL_INIT_SCOPE))
1065 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Cannot set slice for init.scope");
1066
1067 r = sd_bus_message_read(message, "s", &s);
1068 if (r < 0)
1069 return r;
1070
1071 if (!unit_name_is_valid(s, UNIT_NAME_PLAIN))
1072 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit name '%s'", s);
1073
1074 r = manager_load_unit(u->manager, s, NULL, error, &slice);
1075 if (r < 0)
1076 return r;
1077
1078 if (slice->type != UNIT_SLICE)
1079 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unit name '%s' is not a slice", s);
1080
1081 if (mode != UNIT_CHECK) {
1082 r = unit_set_slice(u, slice);
1083 if (r < 0)
1084 return r;
1085
1086 unit_write_drop_in_private_format(u, mode, name, "Slice=%s\n", s);
1087 }
1088
1089 return 1;
1090
1091 } else if (STR_IN_SET(name,
1092 "Requires", "RequiresOverridable",
1093 "Requisite", "RequisiteOverridable",
1094 "Wants",
1095 "BindsTo",
1096 "Conflicts",
1097 "Before", "After",
1098 "OnFailure",
1099 "PropagatesReloadTo", "ReloadPropagatedFrom",
1100 "PartOf")) {
1101
1102 UnitDependency d;
1103 const char *other;
1104
1105 d = unit_dependency_from_string(name);
1106 if (d < 0)
1107 return -EINVAL;
1108
1109 r = sd_bus_message_enter_container(message, 'a', "s");
1110 if (r < 0)
1111 return r;
1112
1113 while ((r = sd_bus_message_read(message, "s", &other)) > 0) {
1114 if (!unit_name_is_valid(other, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE))
1115 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit name %s", other);
1116
1117 if (mode != UNIT_CHECK) {
1118 _cleanup_free_ char *label = NULL;
1119
1120 r = unit_add_dependency_by_name(u, d, other, NULL, true);
1121 if (r < 0)
1122 return r;
1123
1124 label = strjoin(name, "-", other, NULL);
1125 if (!label)
1126 return -ENOMEM;
1127
1128 unit_write_drop_in_format(u, mode, label, "[Unit]\n%s=%s\n", name, other);
1129 }
1130
1131 }
1132 if (r < 0)
1133 return r;
1134
1135 r = sd_bus_message_exit_container(message);
1136 if (r < 0)
1137 return r;
1138
1139 return 1;
1140 }
1141
1142 return 0;
1143 }
1144
1145 int bus_unit_set_properties(
1146 Unit *u,
1147 sd_bus_message *message,
1148 UnitSetPropertiesMode mode,
1149 bool commit,
1150 sd_bus_error *error) {
1151
1152 bool for_real = false;
1153 unsigned n = 0;
1154 int r;
1155
1156 assert(u);
1157 assert(message);
1158
1159 /* We iterate through the array twice. First run we just check
1160 * if all passed data is valid, second run actually applies
1161 * it. This is to implement transaction-like behaviour without
1162 * actually providing full transactions. */
1163
1164 r = sd_bus_message_enter_container(message, 'a', "(sv)");
1165 if (r < 0)
1166 return r;
1167
1168 for (;;) {
1169 const char *name;
1170
1171 r = sd_bus_message_enter_container(message, 'r', "sv");
1172 if (r < 0)
1173 return r;
1174 if (r == 0) {
1175 if (for_real || mode == UNIT_CHECK)
1176 break;
1177
1178 /* Reached EOF. Let's try again, and this time for realz... */
1179 r = sd_bus_message_rewind(message, false);
1180 if (r < 0)
1181 return r;
1182
1183 for_real = true;
1184 continue;
1185 }
1186
1187 r = sd_bus_message_read(message, "s", &name);
1188 if (r < 0)
1189 return r;
1190
1191 if (!UNIT_VTABLE(u)->bus_set_property)
1192 return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Objects of this type do not support setting properties.");
1193
1194 r = sd_bus_message_enter_container(message, 'v', NULL);
1195 if (r < 0)
1196 return r;
1197
1198 r = UNIT_VTABLE(u)->bus_set_property(u, name, message, for_real ? mode : UNIT_CHECK, error);
1199 if (r == 0 && u->transient && u->load_state == UNIT_STUB)
1200 r = bus_unit_set_transient_property(u, name, message, for_real ? mode : UNIT_CHECK, error);
1201 if (r < 0)
1202 return r;
1203 if (r == 0)
1204 return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Cannot set property %s, or unknown property.", name);
1205
1206 r = sd_bus_message_exit_container(message);
1207 if (r < 0)
1208 return r;
1209
1210 r = sd_bus_message_exit_container(message);
1211 if (r < 0)
1212 return r;
1213
1214 n += for_real;
1215 }
1216
1217 r = sd_bus_message_exit_container(message);
1218 if (r < 0)
1219 return r;
1220
1221 if (commit && n > 0 && UNIT_VTABLE(u)->bus_commit_properties)
1222 UNIT_VTABLE(u)->bus_commit_properties(u);
1223
1224 return n;
1225 }