1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
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.
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.
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/>.
24 #include "selinux-access.h"
25 #include "cgroup-util.h"
27 #include "bus-common-errors.h"
29 #include "dbus-unit.h"
31 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_load_state, unit_load_state, UnitLoadState);
32 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_job_mode, job_mode, JobMode);
33 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_failure_action, failure_action, FailureAction);
35 static int property_get_names(
38 const char *interface,
40 sd_bus_message *reply,
42 sd_bus_error *error) {
53 r = sd_bus_message_open_container(reply, 'a', "s");
57 SET_FOREACH(t, u->names, i) {
58 r = sd_bus_message_append(reply, "s", t);
63 return sd_bus_message_close_container(reply);
66 static int property_get_following(
69 const char *interface,
71 sd_bus_message *reply,
73 sd_bus_error *error) {
75 Unit *u = userdata, *f;
81 f = unit_following(u);
82 return sd_bus_message_append(reply, "s", f ? f->id : "");
85 static int property_get_dependencies(
88 const char *interface,
90 sd_bus_message *reply,
92 sd_bus_error *error) {
94 Set *s = *(Set**) userdata;
102 r = sd_bus_message_open_container(reply, 'a', "s");
106 SET_FOREACH(u, s, j) {
107 r = sd_bus_message_append(reply, "s", u->id);
112 return sd_bus_message_close_container(reply);
115 static int property_get_description(
118 const char *interface,
119 const char *property,
120 sd_bus_message *reply,
122 sd_bus_error *error) {
130 return sd_bus_message_append(reply, "s", unit_description(u));
133 static int property_get_active_state(
136 const char *interface,
137 const char *property,
138 sd_bus_message *reply,
140 sd_bus_error *error) {
148 return sd_bus_message_append(reply, "s", unit_active_state_to_string(unit_active_state(u)));
151 static int property_get_sub_state(
154 const char *interface,
155 const char *property,
156 sd_bus_message *reply,
158 sd_bus_error *error) {
166 return sd_bus_message_append(reply, "s", unit_sub_state_to_string(u));
169 static int property_get_unit_file_preset(
172 const char *interface,
173 const char *property,
174 sd_bus_message *reply,
176 sd_bus_error *error) {
185 r = unit_get_unit_file_preset(u);
187 return sd_bus_message_append(reply, "s",
189 r > 0 ? "enabled" : "disabled");
192 static int property_get_unit_file_state(
195 const char *interface,
196 const char *property,
197 sd_bus_message *reply,
199 sd_bus_error *error) {
207 return sd_bus_message_append(reply, "s", unit_file_state_to_string(unit_get_unit_file_state(u)));
210 static int property_get_can_start(
213 const char *interface,
214 const char *property,
215 sd_bus_message *reply,
217 sd_bus_error *error) {
225 return sd_bus_message_append(reply, "b", unit_can_start(u) && !u->refuse_manual_start);
228 static int property_get_can_stop(
231 const char *interface,
232 const char *property,
233 sd_bus_message *reply,
235 sd_bus_error *error) {
243 /* On the lower levels we assume that every unit we can start
244 * we can also stop */
246 return sd_bus_message_append(reply, "b", unit_can_start(u) && !u->refuse_manual_stop);
249 static int property_get_can_reload(
252 const char *interface,
253 const char *property,
254 sd_bus_message *reply,
256 sd_bus_error *error) {
264 return sd_bus_message_append(reply, "b", unit_can_reload(u));
267 static int property_get_can_isolate(
270 const char *interface,
271 const char *property,
272 sd_bus_message *reply,
274 sd_bus_error *error) {
282 return sd_bus_message_append(reply, "b", unit_can_isolate(u) && !u->refuse_manual_start);
285 static int property_get_job(
288 const char *interface,
289 const char *property,
290 sd_bus_message *reply,
292 sd_bus_error *error) {
294 _cleanup_free_ char *p = NULL;
302 return sd_bus_message_append(reply, "(uo)", 0, "/");
304 p = job_dbus_path(u->job);
308 return sd_bus_message_append(reply, "(uo)", u->job->id, p);
311 static int property_get_need_daemon_reload(
314 const char *interface,
315 const char *property,
316 sd_bus_message *reply,
318 sd_bus_error *error) {
326 return sd_bus_message_append(reply, "b", unit_need_daemon_reload(u));
329 static int property_get_conditions(
332 const char *interface,
333 const char *property,
334 sd_bus_message *reply,
336 sd_bus_error *error) {
338 const char *(*to_string)(ConditionType type) = NULL;
339 Condition **list = userdata, *c;
346 to_string = streq(property, "Asserts") ? assert_type_to_string : condition_type_to_string;
348 r = sd_bus_message_open_container(reply, 'a', "(sbbsi)");
352 LIST_FOREACH(conditions, c, *list) {
356 c->result == CONDITION_UNTESTED ? 0 :
357 c->result == CONDITION_SUCCEEDED ? 1 : -1;
359 r = sd_bus_message_append(reply, "(sbbsi)",
361 c->trigger, c->negate,
362 c->parameter, tristate);
368 return sd_bus_message_close_container(reply);
371 static int property_get_load_error(
374 const char *interface,
375 const char *property,
376 sd_bus_message *reply,
378 sd_bus_error *error) {
380 _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL;
387 if (u->load_error != 0)
388 sd_bus_error_set_errno(&e, u->load_error);
390 return sd_bus_message_append(reply, "(ss)", e.name, e.message);
393 int bus_unit_method_start_generic(
395 sd_bus_message *message,
398 bool reload_if_possible,
399 sd_bus_error *error) {
408 assert(job_type >= 0 && job_type < _JOB_TYPE_MAX);
410 r = mac_selinux_unit_access_check(u, message, job_type == JOB_STOP ? "stop" : "start", error);
414 r = sd_bus_message_read(message, "s", &smode);
418 mode = job_mode_from_string(smode);
420 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Job mode %s invalid", smode);
422 r = bus_verify_manage_units_async(u->manager, message, error);
426 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
428 return bus_unit_queue_job(bus, message, u, job_type, mode, reload_if_possible, error);
431 static int method_start(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
432 return bus_unit_method_start_generic(bus, message, userdata, JOB_START, false, error);
435 static int method_stop(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
436 return bus_unit_method_start_generic(bus, message, userdata, JOB_STOP, false, error);
439 static int method_reload(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
440 return bus_unit_method_start_generic(bus, message, userdata, JOB_RELOAD, false, error);
443 static int method_restart(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
444 return bus_unit_method_start_generic(bus, message, userdata, JOB_RESTART, false, error);
447 static int method_try_restart(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
448 return bus_unit_method_start_generic(bus, message, userdata, JOB_TRY_RESTART, false, error);
451 static int method_reload_or_restart(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
452 return bus_unit_method_start_generic(bus, message, userdata, JOB_RESTART, true, error);
455 static int method_reload_or_try_restart(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
456 return bus_unit_method_start_generic(bus, message, userdata, JOB_TRY_RESTART, true, error);
459 int bus_unit_method_kill(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
470 r = mac_selinux_unit_access_check(u, message, "stop", error);
474 r = sd_bus_message_read(message, "si", &swho, &signo);
481 who = kill_who_from_string(swho);
483 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid who argument %s", swho);
486 if (signo <= 0 || signo >= _NSIG)
487 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Signal number out of range.");
489 r = bus_verify_manage_units_async_for_kill(u->manager, message, error);
493 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
495 r = unit_kill(u, who, signo, error);
499 return sd_bus_reply_method_return(message, NULL);
502 int bus_unit_method_reset_failed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
510 r = mac_selinux_unit_access_check(u, message, "reload", error);
514 r = bus_verify_manage_units_async(u->manager, message, error);
518 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
520 unit_reset_failed(u);
522 return sd_bus_reply_method_return(message, NULL);
525 int bus_unit_method_set_properties(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
533 r = mac_selinux_unit_access_check(u, message, "start", error);
537 r = sd_bus_message_read(message, "b", &runtime);
541 r = bus_verify_manage_units_async(u->manager, message, error);
545 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
547 r = bus_unit_set_properties(u, message, runtime ? UNIT_RUNTIME : UNIT_PERSISTENT, true, error);
551 return sd_bus_reply_method_return(message, NULL);
554 const sd_bus_vtable bus_unit_vtable[] = {
555 SD_BUS_VTABLE_START(0),
557 SD_BUS_PROPERTY("Id", "s", NULL, offsetof(Unit, id), SD_BUS_VTABLE_PROPERTY_CONST),
558 SD_BUS_PROPERTY("Names", "as", property_get_names, 0, SD_BUS_VTABLE_PROPERTY_CONST),
559 SD_BUS_PROPERTY("Following", "s", property_get_following, 0, 0),
560 SD_BUS_PROPERTY("Requires", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRES]), SD_BUS_VTABLE_PROPERTY_CONST),
561 SD_BUS_PROPERTY("RequiresOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRES_OVERRIDABLE]), SD_BUS_VTABLE_PROPERTY_CONST),
562 SD_BUS_PROPERTY("Requisite", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE]), SD_BUS_VTABLE_PROPERTY_CONST),
563 SD_BUS_PROPERTY("RequisiteOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE_OVERRIDABLE]), SD_BUS_VTABLE_PROPERTY_CONST),
564 SD_BUS_PROPERTY("Wants", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_WANTS]), SD_BUS_VTABLE_PROPERTY_CONST),
565 SD_BUS_PROPERTY("BindsTo", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BINDS_TO]), SD_BUS_VTABLE_PROPERTY_CONST),
566 SD_BUS_PROPERTY("PartOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_PART_OF]), SD_BUS_VTABLE_PROPERTY_CONST),
567 SD_BUS_PROPERTY("RequiredBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
568 SD_BUS_PROPERTY("RequiredByOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRED_BY_OVERRIDABLE]), SD_BUS_VTABLE_PROPERTY_CONST),
569 SD_BUS_PROPERTY("WantedBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_WANTED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
570 SD_BUS_PROPERTY("BoundBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BOUND_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
571 SD_BUS_PROPERTY("ConsistsOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONSISTS_OF]), SD_BUS_VTABLE_PROPERTY_CONST),
572 SD_BUS_PROPERTY("Conflicts", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONFLICTS]), SD_BUS_VTABLE_PROPERTY_CONST),
573 SD_BUS_PROPERTY("ConflictedBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONFLICTED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
574 SD_BUS_PROPERTY("Before", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BEFORE]), SD_BUS_VTABLE_PROPERTY_CONST),
575 SD_BUS_PROPERTY("After", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_AFTER]), SD_BUS_VTABLE_PROPERTY_CONST),
576 SD_BUS_PROPERTY("OnFailure", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_ON_FAILURE]), SD_BUS_VTABLE_PROPERTY_CONST),
577 SD_BUS_PROPERTY("Triggers", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_TRIGGERS]), SD_BUS_VTABLE_PROPERTY_CONST),
578 SD_BUS_PROPERTY("TriggeredBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_TRIGGERED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
579 SD_BUS_PROPERTY("PropagatesReloadTo", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_PROPAGATES_RELOAD_TO]), SD_BUS_VTABLE_PROPERTY_CONST),
580 SD_BUS_PROPERTY("ReloadPropagatedFrom", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_RELOAD_PROPAGATED_FROM]), SD_BUS_VTABLE_PROPERTY_CONST),
581 SD_BUS_PROPERTY("JoinsNamespaceOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_JOINS_NAMESPACE_OF]), SD_BUS_VTABLE_PROPERTY_CONST),
582 SD_BUS_PROPERTY("RequiresMountsFor", "as", NULL, offsetof(Unit, requires_mounts_for), SD_BUS_VTABLE_PROPERTY_CONST),
583 SD_BUS_PROPERTY("Documentation", "as", NULL, offsetof(Unit, documentation), SD_BUS_VTABLE_PROPERTY_CONST),
584 SD_BUS_PROPERTY("Description", "s", property_get_description, 0, SD_BUS_VTABLE_PROPERTY_CONST),
585 SD_BUS_PROPERTY("LoadState", "s", property_get_load_state, offsetof(Unit, load_state), SD_BUS_VTABLE_PROPERTY_CONST),
586 SD_BUS_PROPERTY("ActiveState", "s", property_get_active_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
587 SD_BUS_PROPERTY("SubState", "s", property_get_sub_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
588 SD_BUS_PROPERTY("FragmentPath", "s", NULL, offsetof(Unit, fragment_path), SD_BUS_VTABLE_PROPERTY_CONST),
589 SD_BUS_PROPERTY("SourcePath", "s", NULL, offsetof(Unit, source_path), SD_BUS_VTABLE_PROPERTY_CONST),
590 SD_BUS_PROPERTY("DropInPaths", "as", NULL, offsetof(Unit, dropin_paths), SD_BUS_VTABLE_PROPERTY_CONST),
591 SD_BUS_PROPERTY("UnitFileState", "s", property_get_unit_file_state, 0, 0),
592 SD_BUS_PROPERTY("UnitFilePreset", "s", property_get_unit_file_preset, 0, 0),
593 BUS_PROPERTY_DUAL_TIMESTAMP("InactiveExitTimestamp", offsetof(Unit, inactive_exit_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
594 BUS_PROPERTY_DUAL_TIMESTAMP("ActiveEnterTimestamp", offsetof(Unit, active_enter_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
595 BUS_PROPERTY_DUAL_TIMESTAMP("ActiveExitTimestamp", offsetof(Unit, active_exit_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
596 BUS_PROPERTY_DUAL_TIMESTAMP("InactiveEnterTimestamp", offsetof(Unit, inactive_enter_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
597 SD_BUS_PROPERTY("CanStart", "b", property_get_can_start, 0, SD_BUS_VTABLE_PROPERTY_CONST),
598 SD_BUS_PROPERTY("CanStop", "b", property_get_can_stop, 0, SD_BUS_VTABLE_PROPERTY_CONST),
599 SD_BUS_PROPERTY("CanReload", "b", property_get_can_reload, 0, SD_BUS_VTABLE_PROPERTY_CONST),
600 SD_BUS_PROPERTY("CanIsolate", "b", property_get_can_isolate, 0, SD_BUS_VTABLE_PROPERTY_CONST),
601 SD_BUS_PROPERTY("Job", "(uo)", property_get_job, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
602 SD_BUS_PROPERTY("StopWhenUnneeded", "b", bus_property_get_bool, offsetof(Unit, stop_when_unneeded), SD_BUS_VTABLE_PROPERTY_CONST),
603 SD_BUS_PROPERTY("RefuseManualStart", "b", bus_property_get_bool, offsetof(Unit, refuse_manual_start), SD_BUS_VTABLE_PROPERTY_CONST),
604 SD_BUS_PROPERTY("RefuseManualStop", "b", bus_property_get_bool, offsetof(Unit, refuse_manual_stop), SD_BUS_VTABLE_PROPERTY_CONST),
605 SD_BUS_PROPERTY("AllowIsolate", "b", bus_property_get_bool, offsetof(Unit, allow_isolate), SD_BUS_VTABLE_PROPERTY_CONST),
606 SD_BUS_PROPERTY("DefaultDependencies", "b", bus_property_get_bool, offsetof(Unit, default_dependencies), SD_BUS_VTABLE_PROPERTY_CONST),
607 SD_BUS_PROPERTY("OnFailureJobMode", "s", property_get_job_mode, offsetof(Unit, on_failure_job_mode), SD_BUS_VTABLE_PROPERTY_CONST),
608 SD_BUS_PROPERTY("IgnoreOnIsolate", "b", bus_property_get_bool, offsetof(Unit, ignore_on_isolate), SD_BUS_VTABLE_PROPERTY_CONST),
609 SD_BUS_PROPERTY("IgnoreOnSnapshot", "b", bus_property_get_bool, offsetof(Unit, ignore_on_snapshot), SD_BUS_VTABLE_PROPERTY_CONST),
610 SD_BUS_PROPERTY("NeedDaemonReload", "b", property_get_need_daemon_reload, 0, SD_BUS_VTABLE_PROPERTY_CONST),
611 SD_BUS_PROPERTY("JobTimeoutUSec", "t", bus_property_get_usec, offsetof(Unit, job_timeout), SD_BUS_VTABLE_PROPERTY_CONST),
612 SD_BUS_PROPERTY("JobTimeoutAction", "s", property_get_failure_action, offsetof(Unit, job_timeout_action), SD_BUS_VTABLE_PROPERTY_CONST),
613 SD_BUS_PROPERTY("JobTimeoutRebootArgument", "s", NULL, offsetof(Unit, job_timeout_reboot_arg), SD_BUS_VTABLE_PROPERTY_CONST),
614 SD_BUS_PROPERTY("ConditionResult", "b", bus_property_get_bool, offsetof(Unit, condition_result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
615 SD_BUS_PROPERTY("AssertResult", "b", bus_property_get_bool, offsetof(Unit, assert_result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
616 BUS_PROPERTY_DUAL_TIMESTAMP("ConditionTimestamp", offsetof(Unit, condition_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
617 BUS_PROPERTY_DUAL_TIMESTAMP("AssertTimestamp", offsetof(Unit, assert_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
618 SD_BUS_PROPERTY("Conditions", "a(sbbsi)", property_get_conditions, offsetof(Unit, conditions), 0),
619 SD_BUS_PROPERTY("Asserts", "a(sbbsi)", property_get_conditions, offsetof(Unit, asserts), 0),
620 SD_BUS_PROPERTY("LoadError", "(ss)", property_get_load_error, 0, SD_BUS_VTABLE_PROPERTY_CONST),
621 SD_BUS_PROPERTY("Transient", "b", bus_property_get_bool, offsetof(Unit, transient), SD_BUS_VTABLE_PROPERTY_CONST),
623 SD_BUS_METHOD("Start", "s", "o", method_start, SD_BUS_VTABLE_UNPRIVILEGED),
624 SD_BUS_METHOD("Stop", "s", "o", method_stop, SD_BUS_VTABLE_UNPRIVILEGED),
625 SD_BUS_METHOD("Reload", "s", "o", method_reload, SD_BUS_VTABLE_UNPRIVILEGED),
626 SD_BUS_METHOD("Restart", "s", "o", method_restart, SD_BUS_VTABLE_UNPRIVILEGED),
627 SD_BUS_METHOD("TryRestart", "s", "o", method_try_restart, SD_BUS_VTABLE_UNPRIVILEGED),
628 SD_BUS_METHOD("ReloadOrRestart", "s", "o", method_reload_or_restart, SD_BUS_VTABLE_UNPRIVILEGED),
629 SD_BUS_METHOD("ReloadOrTryRestart", "s", "o", method_reload_or_try_restart, SD_BUS_VTABLE_UNPRIVILEGED),
630 SD_BUS_METHOD("Kill", "si", NULL, bus_unit_method_kill, SD_BUS_VTABLE_UNPRIVILEGED),
631 SD_BUS_METHOD("ResetFailed", NULL, NULL, bus_unit_method_reset_failed, SD_BUS_VTABLE_UNPRIVILEGED),
632 SD_BUS_METHOD("SetProperties", "ba(sv)", NULL, bus_unit_method_set_properties, SD_BUS_VTABLE_UNPRIVILEGED),
637 static int property_get_slice(
640 const char *interface,
641 const char *property,
642 sd_bus_message *reply,
644 sd_bus_error *error) {
652 return sd_bus_message_append(reply, "s", unit_slice_name(u));
655 static int property_get_current_memory(
658 const char *interface,
659 const char *property,
660 sd_bus_message *reply,
662 sd_bus_error *error) {
664 uint64_t sz = (uint64_t) -1;
672 r = unit_get_memory_current(u, &sz);
673 if (r < 0 && r != -ENODATA)
674 log_unit_warning_errno(u->id, r, "Failed to get memory.usage_in_bytes attribute: %m");
676 return sd_bus_message_append(reply, "t", sz);
679 static int property_get_cpu_usage(
682 const char *interface,
683 const char *property,
684 sd_bus_message *reply,
686 sd_bus_error *error) {
688 nsec_t ns = (nsec_t) -1;
696 r = unit_get_cpu_usage(u, &ns);
697 if (r < 0 && r != -ENODATA)
698 log_unit_warning_errno(u->id, r, "Failed to get cpuacct.usage attribute: %m");
700 return sd_bus_message_append(reply, "t", ns);
703 const sd_bus_vtable bus_unit_cgroup_vtable[] = {
704 SD_BUS_VTABLE_START(0),
705 SD_BUS_PROPERTY("Slice", "s", property_get_slice, 0, 0),
706 SD_BUS_PROPERTY("ControlGroup", "s", NULL, offsetof(Unit, cgroup_path), 0),
707 SD_BUS_PROPERTY("MemoryCurrent", "t", property_get_current_memory, 0, 0),
708 SD_BUS_PROPERTY("CPUUsageNSec", "t", property_get_cpu_usage, 0, 0),
712 static int send_new_signal(sd_bus *bus, void *userdata) {
713 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
714 _cleanup_free_ char *p = NULL;
721 p = unit_dbus_path(u);
725 r = sd_bus_message_new_signal(
728 "/org/freedesktop/systemd1",
729 "org.freedesktop.systemd1.Manager",
734 r = sd_bus_message_append(m, "so", u->id, p);
738 return sd_bus_send(bus, m, NULL);
741 static int send_changed_signal(sd_bus *bus, void *userdata) {
742 _cleanup_free_ char *p = NULL;
749 p = unit_dbus_path(u);
753 /* Send a properties changed signal. First for the specific
754 * type, then for the generic unit. The clients may rely on
755 * this order to get atomic behavior if needed. */
757 r = sd_bus_emit_properties_changed_strv(
759 UNIT_VTABLE(u)->bus_interface,
764 return sd_bus_emit_properties_changed_strv(
766 "org.freedesktop.systemd1.Unit",
770 void bus_unit_send_change_signal(Unit *u) {
774 if (u->in_dbus_queue) {
775 LIST_REMOVE(dbus_queue, u->manager->dbus_unit_queue, u);
776 u->in_dbus_queue = false;
782 r = bus_foreach_bus(u->manager, NULL, u->sent_dbus_new_signal ? send_changed_signal : send_new_signal, u);
784 log_debug_errno(r, "Failed to send unit change signal for %s: %m", u->id);
786 u->sent_dbus_new_signal = true;
789 static int send_removed_signal(sd_bus *bus, void *userdata) {
790 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
791 _cleanup_free_ char *p = NULL;
798 p = unit_dbus_path(u);
802 r = sd_bus_message_new_signal(
805 "/org/freedesktop/systemd1",
806 "org.freedesktop.systemd1.Manager",
811 r = sd_bus_message_append(m, "so", u->id, p);
815 return sd_bus_send(bus, m, NULL);
818 void bus_unit_send_removed_signal(Unit *u) {
822 if (!u->sent_dbus_new_signal)
823 bus_unit_send_change_signal(u);
828 r = bus_foreach_bus(u->manager, NULL, send_removed_signal, u);
830 log_debug_errno(r, "Failed to send unit remove signal for %s: %m", u->id);
833 int bus_unit_queue_job(
835 sd_bus_message *message,
839 bool reload_if_possible,
840 sd_bus_error *error) {
842 _cleanup_free_ char *path = NULL;
849 assert(type >= 0 && type < _JOB_TYPE_MAX);
850 assert(mode >= 0 && mode < _JOB_MODE_MAX);
852 if (reload_if_possible && unit_can_reload(u)) {
853 if (type == JOB_RESTART)
854 type = JOB_RELOAD_OR_START;
855 else if (type == JOB_TRY_RESTART)
859 r = mac_selinux_unit_access_check(
861 (type == JOB_START || type == JOB_RESTART || type == JOB_TRY_RESTART) ? "start" :
862 type == JOB_STOP ? "stop" : "reload", error);
866 if (type == JOB_STOP &&
867 (u->load_state == UNIT_NOT_FOUND || u->load_state == UNIT_ERROR) &&
868 unit_active_state(u) == UNIT_INACTIVE)
869 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not loaded.", u->id);
871 if ((type == JOB_START && u->refuse_manual_start) ||
872 (type == JOB_STOP && u->refuse_manual_stop) ||
873 ((type == JOB_RESTART || type == JOB_TRY_RESTART) && (u->refuse_manual_start || u->refuse_manual_stop)))
874 return sd_bus_error_setf(error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, unit %s may be requested by dependency only.", u->id);
876 r = manager_add_job(u->manager, type, u, mode, true, error, &j);
880 if (bus == u->manager->api_bus) {
882 r = sd_bus_track_new(bus, &j->clients, NULL, NULL);
887 r = sd_bus_track_add_sender(j->clients, message);
892 path = job_dbus_path(j);
896 return sd_bus_reply_method_return(message, "o", path);
899 static int bus_unit_set_transient_property(
902 sd_bus_message *message,
903 UnitSetPropertiesMode mode,
904 sd_bus_error *error) {
912 if (streq(name, "Description")) {
915 r = sd_bus_message_read(message, "s", &d);
919 if (mode != UNIT_CHECK) {
920 r = unit_set_description(u, d);
924 unit_write_drop_in_format(u, mode, name, "[Unit]\nDescription=%s\n", d);
929 } else if (streq(name, "DefaultDependencies")) {
932 r = sd_bus_message_read(message, "b", &b);
936 if (mode != UNIT_CHECK) {
937 u->default_dependencies = b;
938 unit_write_drop_in_format(u, mode, name, "[Unit]\nDefaultDependencies=%s\n", yes_no(b));
943 } else if (streq(name, "Slice") && unit_get_cgroup_context(u)) {
946 r = sd_bus_message_read(message, "s", &s);
950 if (!unit_name_is_valid(s, TEMPLATE_INVALID) || !endswith(s, ".slice"))
951 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid slice name %s", s);
954 if (mode != UNIT_CHECK) {
955 unit_ref_unset(&u->slice);
956 unit_remove_drop_in(u, mode, name);
961 r = manager_load_unit(u->manager, s, NULL, error, &slice);
965 if (slice->type != UNIT_SLICE)
968 if (mode != UNIT_CHECK) {
969 unit_ref_set(&u->slice, slice);
970 unit_write_drop_in_private_format(u, mode, name, "Slice=%s\n", s);
975 } else if (STR_IN_SET(name,
976 "Requires", "RequiresOverridable",
977 "Requisite", "RequisiteOverridable",
983 "PropagatesReloadTo", "ReloadPropagatedFrom",
989 d = unit_dependency_from_string(name);
993 r = sd_bus_message_enter_container(message, 'a', "s");
997 while ((r = sd_bus_message_read(message, "s", &other)) > 0) {
998 if (!unit_name_is_valid(other, TEMPLATE_INVALID))
999 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit name %s", other);
1001 if (mode != UNIT_CHECK) {
1002 _cleanup_free_ char *label = NULL;
1004 r = unit_add_dependency_by_name(u, d, other, NULL, true);
1008 label = strjoin(name, "-", other, NULL);
1012 unit_write_drop_in_format(u, mode, label, "[Unit]\n%s=%s\n", name, other);
1019 r = sd_bus_message_exit_container(message);
1029 int bus_unit_set_properties(
1031 sd_bus_message *message,
1032 UnitSetPropertiesMode mode,
1034 sd_bus_error *error) {
1036 bool for_real = false;
1043 /* We iterate through the array twice. First run we just check
1044 * if all passed data is valid, second run actually applies
1045 * it. This is to implement transaction-like behaviour without
1046 * actually providing full transactions. */
1048 r = sd_bus_message_enter_container(message, 'a', "(sv)");
1055 r = sd_bus_message_enter_container(message, 'r', "sv");
1059 if (for_real || mode == UNIT_CHECK)
1062 /* Reached EOF. Let's try again, and this time for realz... */
1063 r = sd_bus_message_rewind(message, false);
1071 r = sd_bus_message_read(message, "s", &name);
1075 if (!UNIT_VTABLE(u)->bus_set_property)
1076 return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Objects of this type do not support setting properties.");
1078 r = sd_bus_message_enter_container(message, 'v', NULL);
1082 r = UNIT_VTABLE(u)->bus_set_property(u, name, message, for_real ? mode : UNIT_CHECK, error);
1083 if (r == 0 && u->transient && u->load_state == UNIT_STUB)
1084 r = bus_unit_set_transient_property(u, name, message, for_real ? mode : UNIT_CHECK, error);
1088 return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Cannot set property %s, or unknown property.", name);
1090 r = sd_bus_message_exit_container(message);
1094 r = sd_bus_message_exit_container(message);
1101 r = sd_bus_message_exit_container(message);
1105 if (commit && n > 0 && UNIT_VTABLE(u)->bus_commit_properties)
1106 UNIT_VTABLE(u)->bus_commit_properties(u);