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 "path-util.h"
29 #include "bus-common-errors.h"
31 #include "dbus-manager.h"
32 #include "dbus-unit.h"
34 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_load_state, unit_load_state, UnitLoadState);
35 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_job_mode, job_mode, JobMode);
36 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_failure_action, failure_action, FailureAction);
38 static int property_get_names(
41 const char *interface,
43 sd_bus_message *reply,
45 sd_bus_error *error) {
56 r = sd_bus_message_open_container(reply, 'a', "s");
60 SET_FOREACH(t, u->names, i) {
61 r = sd_bus_message_append(reply, "s", t);
66 return sd_bus_message_close_container(reply);
69 static int property_get_following(
72 const char *interface,
74 sd_bus_message *reply,
76 sd_bus_error *error) {
78 Unit *u = userdata, *f;
84 f = unit_following(u);
85 return sd_bus_message_append(reply, "s", f ? f->id : "");
88 static int property_get_dependencies(
91 const char *interface,
93 sd_bus_message *reply,
95 sd_bus_error *error) {
97 Set *s = *(Set**) userdata;
105 r = sd_bus_message_open_container(reply, 'a', "s");
109 SET_FOREACH(u, s, j) {
110 r = sd_bus_message_append(reply, "s", u->id);
115 return sd_bus_message_close_container(reply);
118 static int property_get_description(
121 const char *interface,
122 const char *property,
123 sd_bus_message *reply,
125 sd_bus_error *error) {
133 return sd_bus_message_append(reply, "s", unit_description(u));
136 static int property_get_active_state(
139 const char *interface,
140 const char *property,
141 sd_bus_message *reply,
143 sd_bus_error *error) {
151 return sd_bus_message_append(reply, "s", unit_active_state_to_string(unit_active_state(u)));
154 static int property_get_sub_state(
157 const char *interface,
158 const char *property,
159 sd_bus_message *reply,
161 sd_bus_error *error) {
169 return sd_bus_message_append(reply, "s", unit_sub_state_to_string(u));
172 static int property_get_unit_file_preset(
175 const char *interface,
176 const char *property,
177 sd_bus_message *reply,
179 sd_bus_error *error) {
188 r = unit_get_unit_file_preset(u);
190 return sd_bus_message_append(reply, "s",
192 r > 0 ? "enabled" : "disabled");
195 static int property_get_unit_file_state(
198 const char *interface,
199 const char *property,
200 sd_bus_message *reply,
202 sd_bus_error *error) {
210 return sd_bus_message_append(reply, "s", unit_file_state_to_string(unit_get_unit_file_state(u)));
213 static int property_get_can_start(
216 const char *interface,
217 const char *property,
218 sd_bus_message *reply,
220 sd_bus_error *error) {
228 return sd_bus_message_append(reply, "b", unit_can_start(u) && !u->refuse_manual_start);
231 static int property_get_can_stop(
234 const char *interface,
235 const char *property,
236 sd_bus_message *reply,
238 sd_bus_error *error) {
246 /* On the lower levels we assume that every unit we can start
247 * we can also stop */
249 return sd_bus_message_append(reply, "b", unit_can_start(u) && !u->refuse_manual_stop);
252 static int property_get_can_reload(
255 const char *interface,
256 const char *property,
257 sd_bus_message *reply,
259 sd_bus_error *error) {
267 return sd_bus_message_append(reply, "b", unit_can_reload(u));
270 static int property_get_can_isolate(
273 const char *interface,
274 const char *property,
275 sd_bus_message *reply,
277 sd_bus_error *error) {
285 return sd_bus_message_append(reply, "b", unit_can_isolate(u) && !u->refuse_manual_start);
288 static int property_get_job(
291 const char *interface,
292 const char *property,
293 sd_bus_message *reply,
295 sd_bus_error *error) {
297 _cleanup_free_ char *p = NULL;
305 return sd_bus_message_append(reply, "(uo)", 0, "/");
307 p = job_dbus_path(u->job);
311 return sd_bus_message_append(reply, "(uo)", u->job->id, p);
314 static int property_get_need_daemon_reload(
317 const char *interface,
318 const char *property,
319 sd_bus_message *reply,
321 sd_bus_error *error) {
329 return sd_bus_message_append(reply, "b", unit_need_daemon_reload(u));
332 static int property_get_conditions(
335 const char *interface,
336 const char *property,
337 sd_bus_message *reply,
339 sd_bus_error *error) {
341 const char *(*to_string)(ConditionType type) = NULL;
342 Condition **list = userdata, *c;
349 to_string = streq(property, "Asserts") ? assert_type_to_string : condition_type_to_string;
351 r = sd_bus_message_open_container(reply, 'a', "(sbbsi)");
355 LIST_FOREACH(conditions, c, *list) {
359 c->result == CONDITION_UNTESTED ? 0 :
360 c->result == CONDITION_SUCCEEDED ? 1 : -1;
362 r = sd_bus_message_append(reply, "(sbbsi)",
364 c->trigger, c->negate,
365 c->parameter, tristate);
371 return sd_bus_message_close_container(reply);
374 static int property_get_load_error(
377 const char *interface,
378 const char *property,
379 sd_bus_message *reply,
381 sd_bus_error *error) {
383 _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL;
390 if (u->load_error != 0)
391 sd_bus_error_set_errno(&e, u->load_error);
393 return sd_bus_message_append(reply, "(ss)", e.name, e.message);
396 int bus_unit_method_start_generic(
398 sd_bus_message *message,
401 bool reload_if_possible,
402 sd_bus_error *error) {
411 assert(job_type >= 0 && job_type < _JOB_TYPE_MAX);
413 r = mac_selinux_unit_access_check(u, message, job_type == JOB_STOP ? "stop" : "start", error);
417 r = sd_bus_message_read(message, "s", &smode);
421 mode = job_mode_from_string(smode);
423 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Job mode %s invalid", smode);
425 r = bus_verify_manage_units_async(u->manager, message, error);
429 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
431 return bus_unit_queue_job(bus, message, u, job_type, mode, reload_if_possible, error);
434 static int method_start(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
435 return bus_unit_method_start_generic(bus, message, userdata, JOB_START, false, error);
438 static int method_stop(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
439 return bus_unit_method_start_generic(bus, message, userdata, JOB_STOP, false, error);
442 static int method_reload(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
443 return bus_unit_method_start_generic(bus, message, userdata, JOB_RELOAD, false, error);
446 static int method_restart(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
447 return bus_unit_method_start_generic(bus, message, userdata, JOB_RESTART, false, error);
450 static int method_try_restart(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
451 return bus_unit_method_start_generic(bus, message, userdata, JOB_TRY_RESTART, false, error);
454 static int method_reload_or_restart(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
455 return bus_unit_method_start_generic(bus, message, userdata, JOB_RESTART, true, error);
458 static int method_reload_or_try_restart(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
459 return bus_unit_method_start_generic(bus, message, userdata, JOB_TRY_RESTART, true, error);
462 int bus_unit_method_kill(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
473 r = mac_selinux_unit_access_check(u, message, "stop", error);
477 r = sd_bus_message_read(message, "si", &swho, &signo);
484 who = kill_who_from_string(swho);
486 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid who argument %s", swho);
489 if (signo <= 0 || signo >= _NSIG)
490 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Signal number out of range.");
492 r = bus_verify_manage_units_async_for_kill(u->manager, message, error);
496 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
498 r = unit_kill(u, who, signo, error);
502 return sd_bus_reply_method_return(message, NULL);
505 int bus_unit_method_reset_failed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
513 r = mac_selinux_unit_access_check(u, message, "reload", error);
517 r = bus_verify_manage_units_async(u->manager, message, error);
521 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
523 unit_reset_failed(u);
525 return sd_bus_reply_method_return(message, NULL);
528 int bus_unit_method_set_properties(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
536 r = mac_selinux_unit_access_check(u, message, "start", error);
540 r = sd_bus_message_read(message, "b", &runtime);
544 r = bus_verify_manage_units_async(u->manager, message, error);
548 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
550 r = bus_unit_set_properties(u, message, runtime ? UNIT_RUNTIME : UNIT_PERSISTENT, true, error);
554 return sd_bus_reply_method_return(message, NULL);
557 const sd_bus_vtable bus_unit_vtable[] = {
558 SD_BUS_VTABLE_START(0),
560 SD_BUS_PROPERTY("Id", "s", NULL, offsetof(Unit, id), SD_BUS_VTABLE_PROPERTY_CONST),
561 SD_BUS_PROPERTY("Names", "as", property_get_names, 0, SD_BUS_VTABLE_PROPERTY_CONST),
562 SD_BUS_PROPERTY("Following", "s", property_get_following, 0, 0),
563 SD_BUS_PROPERTY("Requires", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRES]), SD_BUS_VTABLE_PROPERTY_CONST),
564 SD_BUS_PROPERTY("RequiresOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRES_OVERRIDABLE]), SD_BUS_VTABLE_PROPERTY_CONST),
565 SD_BUS_PROPERTY("Requisite", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE]), SD_BUS_VTABLE_PROPERTY_CONST),
566 SD_BUS_PROPERTY("RequisiteOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE_OVERRIDABLE]), SD_BUS_VTABLE_PROPERTY_CONST),
567 SD_BUS_PROPERTY("Wants", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_WANTS]), SD_BUS_VTABLE_PROPERTY_CONST),
568 SD_BUS_PROPERTY("BindsTo", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BINDS_TO]), SD_BUS_VTABLE_PROPERTY_CONST),
569 SD_BUS_PROPERTY("PartOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_PART_OF]), SD_BUS_VTABLE_PROPERTY_CONST),
570 SD_BUS_PROPERTY("RequiredBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
571 SD_BUS_PROPERTY("RequiredByOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRED_BY_OVERRIDABLE]), SD_BUS_VTABLE_PROPERTY_CONST),
572 SD_BUS_PROPERTY("WantedBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_WANTED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
573 SD_BUS_PROPERTY("BoundBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BOUND_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
574 SD_BUS_PROPERTY("ConsistsOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONSISTS_OF]), SD_BUS_VTABLE_PROPERTY_CONST),
575 SD_BUS_PROPERTY("Conflicts", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONFLICTS]), SD_BUS_VTABLE_PROPERTY_CONST),
576 SD_BUS_PROPERTY("ConflictedBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONFLICTED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
577 SD_BUS_PROPERTY("Before", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BEFORE]), SD_BUS_VTABLE_PROPERTY_CONST),
578 SD_BUS_PROPERTY("After", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_AFTER]), SD_BUS_VTABLE_PROPERTY_CONST),
579 SD_BUS_PROPERTY("OnFailure", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_ON_FAILURE]), SD_BUS_VTABLE_PROPERTY_CONST),
580 SD_BUS_PROPERTY("Triggers", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_TRIGGERS]), SD_BUS_VTABLE_PROPERTY_CONST),
581 SD_BUS_PROPERTY("TriggeredBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_TRIGGERED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
582 SD_BUS_PROPERTY("PropagatesReloadTo", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_PROPAGATES_RELOAD_TO]), SD_BUS_VTABLE_PROPERTY_CONST),
583 SD_BUS_PROPERTY("ReloadPropagatedFrom", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_RELOAD_PROPAGATED_FROM]), SD_BUS_VTABLE_PROPERTY_CONST),
584 SD_BUS_PROPERTY("JoinsNamespaceOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_JOINS_NAMESPACE_OF]), SD_BUS_VTABLE_PROPERTY_CONST),
585 SD_BUS_PROPERTY("RequiresMountsFor", "as", NULL, offsetof(Unit, requires_mounts_for), SD_BUS_VTABLE_PROPERTY_CONST),
586 SD_BUS_PROPERTY("Documentation", "as", NULL, offsetof(Unit, documentation), SD_BUS_VTABLE_PROPERTY_CONST),
587 SD_BUS_PROPERTY("Description", "s", property_get_description, 0, SD_BUS_VTABLE_PROPERTY_CONST),
588 SD_BUS_PROPERTY("LoadState", "s", property_get_load_state, offsetof(Unit, load_state), SD_BUS_VTABLE_PROPERTY_CONST),
589 SD_BUS_PROPERTY("ActiveState", "s", property_get_active_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
590 SD_BUS_PROPERTY("SubState", "s", property_get_sub_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
591 SD_BUS_PROPERTY("FragmentPath", "s", NULL, offsetof(Unit, fragment_path), SD_BUS_VTABLE_PROPERTY_CONST),
592 SD_BUS_PROPERTY("SourcePath", "s", NULL, offsetof(Unit, source_path), SD_BUS_VTABLE_PROPERTY_CONST),
593 SD_BUS_PROPERTY("DropInPaths", "as", NULL, offsetof(Unit, dropin_paths), SD_BUS_VTABLE_PROPERTY_CONST),
594 SD_BUS_PROPERTY("UnitFileState", "s", property_get_unit_file_state, 0, 0),
595 SD_BUS_PROPERTY("UnitFilePreset", "s", property_get_unit_file_preset, 0, 0),
596 BUS_PROPERTY_DUAL_TIMESTAMP("InactiveExitTimestamp", offsetof(Unit, inactive_exit_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
597 BUS_PROPERTY_DUAL_TIMESTAMP("ActiveEnterTimestamp", offsetof(Unit, active_enter_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
598 BUS_PROPERTY_DUAL_TIMESTAMP("ActiveExitTimestamp", offsetof(Unit, active_exit_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
599 BUS_PROPERTY_DUAL_TIMESTAMP("InactiveEnterTimestamp", offsetof(Unit, inactive_enter_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
600 SD_BUS_PROPERTY("CanStart", "b", property_get_can_start, 0, SD_BUS_VTABLE_PROPERTY_CONST),
601 SD_BUS_PROPERTY("CanStop", "b", property_get_can_stop, 0, SD_BUS_VTABLE_PROPERTY_CONST),
602 SD_BUS_PROPERTY("CanReload", "b", property_get_can_reload, 0, SD_BUS_VTABLE_PROPERTY_CONST),
603 SD_BUS_PROPERTY("CanIsolate", "b", property_get_can_isolate, 0, SD_BUS_VTABLE_PROPERTY_CONST),
604 SD_BUS_PROPERTY("Job", "(uo)", property_get_job, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
605 SD_BUS_PROPERTY("StopWhenUnneeded", "b", bus_property_get_bool, offsetof(Unit, stop_when_unneeded), SD_BUS_VTABLE_PROPERTY_CONST),
606 SD_BUS_PROPERTY("RefuseManualStart", "b", bus_property_get_bool, offsetof(Unit, refuse_manual_start), SD_BUS_VTABLE_PROPERTY_CONST),
607 SD_BUS_PROPERTY("RefuseManualStop", "b", bus_property_get_bool, offsetof(Unit, refuse_manual_stop), SD_BUS_VTABLE_PROPERTY_CONST),
608 SD_BUS_PROPERTY("AllowIsolate", "b", bus_property_get_bool, offsetof(Unit, allow_isolate), SD_BUS_VTABLE_PROPERTY_CONST),
609 SD_BUS_PROPERTY("DefaultDependencies", "b", bus_property_get_bool, offsetof(Unit, default_dependencies), SD_BUS_VTABLE_PROPERTY_CONST),
610 SD_BUS_PROPERTY("OnFailureJobMode", "s", property_get_job_mode, offsetof(Unit, on_failure_job_mode), SD_BUS_VTABLE_PROPERTY_CONST),
611 SD_BUS_PROPERTY("IgnoreOnIsolate", "b", bus_property_get_bool, offsetof(Unit, ignore_on_isolate), SD_BUS_VTABLE_PROPERTY_CONST),
612 SD_BUS_PROPERTY("IgnoreOnSnapshot", "b", bus_property_get_bool, offsetof(Unit, ignore_on_snapshot), SD_BUS_VTABLE_PROPERTY_CONST),
613 SD_BUS_PROPERTY("NeedDaemonReload", "b", property_get_need_daemon_reload, 0, SD_BUS_VTABLE_PROPERTY_CONST),
614 SD_BUS_PROPERTY("JobTimeoutUSec", "t", bus_property_get_usec, offsetof(Unit, job_timeout), SD_BUS_VTABLE_PROPERTY_CONST),
615 SD_BUS_PROPERTY("JobTimeoutAction", "s", property_get_failure_action, offsetof(Unit, job_timeout_action), SD_BUS_VTABLE_PROPERTY_CONST),
616 SD_BUS_PROPERTY("JobTimeoutRebootArgument", "s", NULL, offsetof(Unit, job_timeout_reboot_arg), SD_BUS_VTABLE_PROPERTY_CONST),
617 SD_BUS_PROPERTY("ConditionResult", "b", bus_property_get_bool, offsetof(Unit, condition_result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
618 SD_BUS_PROPERTY("AssertResult", "b", bus_property_get_bool, offsetof(Unit, assert_result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
619 BUS_PROPERTY_DUAL_TIMESTAMP("ConditionTimestamp", offsetof(Unit, condition_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
620 BUS_PROPERTY_DUAL_TIMESTAMP("AssertTimestamp", offsetof(Unit, assert_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
621 SD_BUS_PROPERTY("Conditions", "a(sbbsi)", property_get_conditions, offsetof(Unit, conditions), 0),
622 SD_BUS_PROPERTY("Asserts", "a(sbbsi)", property_get_conditions, offsetof(Unit, asserts), 0),
623 SD_BUS_PROPERTY("LoadError", "(ss)", property_get_load_error, 0, SD_BUS_VTABLE_PROPERTY_CONST),
624 SD_BUS_PROPERTY("Transient", "b", bus_property_get_bool, offsetof(Unit, transient), SD_BUS_VTABLE_PROPERTY_CONST),
626 SD_BUS_METHOD("Start", "s", "o", method_start, SD_BUS_VTABLE_UNPRIVILEGED),
627 SD_BUS_METHOD("Stop", "s", "o", method_stop, SD_BUS_VTABLE_UNPRIVILEGED),
628 SD_BUS_METHOD("Reload", "s", "o", method_reload, SD_BUS_VTABLE_UNPRIVILEGED),
629 SD_BUS_METHOD("Restart", "s", "o", method_restart, SD_BUS_VTABLE_UNPRIVILEGED),
630 SD_BUS_METHOD("TryRestart", "s", "o", method_try_restart, SD_BUS_VTABLE_UNPRIVILEGED),
631 SD_BUS_METHOD("ReloadOrRestart", "s", "o", method_reload_or_restart, SD_BUS_VTABLE_UNPRIVILEGED),
632 SD_BUS_METHOD("ReloadOrTryRestart", "s", "o", method_reload_or_try_restart, SD_BUS_VTABLE_UNPRIVILEGED),
633 SD_BUS_METHOD("Kill", "si", NULL, bus_unit_method_kill, SD_BUS_VTABLE_UNPRIVILEGED),
634 SD_BUS_METHOD("ResetFailed", NULL, NULL, bus_unit_method_reset_failed, SD_BUS_VTABLE_UNPRIVILEGED),
635 SD_BUS_METHOD("SetProperties", "ba(sv)", NULL, bus_unit_method_set_properties, SD_BUS_VTABLE_UNPRIVILEGED),
640 static int property_get_slice(
643 const char *interface,
644 const char *property,
645 sd_bus_message *reply,
647 sd_bus_error *error) {
655 return sd_bus_message_append(reply, "s", unit_slice_name(u));
658 static int property_get_current_memory(
661 const char *interface,
662 const char *property,
663 sd_bus_message *reply,
665 sd_bus_error *error) {
668 uint64_t sz = (uint64_t) -1;
675 if (u->cgroup_path &&
676 (u->cgroup_realized_mask & CGROUP_MEMORY)) {
677 _cleanup_free_ char *v = NULL;
679 r = cg_get_attribute("memory", u->cgroup_path, "memory.usage_in_bytes", &v);
680 if (r < 0 && r != -ENOENT)
681 log_unit_warning_errno(u->id, r, "Couldn't read memory.usage_in_bytes attribute: %m");
684 r = safe_atou64(v, &sz);
686 log_unit_warning_errno(u->id, r, "Failed to parse memory.usage_in_bytes attribute: %m");
690 return sd_bus_message_append(reply, "t", sz);
693 const sd_bus_vtable bus_unit_cgroup_vtable[] = {
694 SD_BUS_VTABLE_START(0),
695 SD_BUS_PROPERTY("Slice", "s", property_get_slice, 0, 0),
696 SD_BUS_PROPERTY("ControlGroup", "s", NULL, offsetof(Unit, cgroup_path), 0),
697 SD_BUS_PROPERTY("MemoryCurrent", "t", property_get_current_memory, 0, 0),
701 static int send_new_signal(sd_bus *bus, void *userdata) {
702 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
703 _cleanup_free_ char *p = NULL;
710 p = unit_dbus_path(u);
714 r = sd_bus_message_new_signal(
717 "/org/freedesktop/systemd1",
718 "org.freedesktop.systemd1.Manager",
723 r = sd_bus_message_append(m, "so", u->id, p);
727 return sd_bus_send(bus, m, NULL);
730 static int send_changed_signal(sd_bus *bus, void *userdata) {
731 _cleanup_free_ char *p = NULL;
738 p = unit_dbus_path(u);
742 /* Send a properties changed signal. First for the specific
743 * type, then for the generic unit. The clients may rely on
744 * this order to get atomic behavior if needed. */
746 r = sd_bus_emit_properties_changed_strv(
748 UNIT_VTABLE(u)->bus_interface,
753 return sd_bus_emit_properties_changed_strv(
755 "org.freedesktop.systemd1.Unit",
759 void bus_unit_send_change_signal(Unit *u) {
763 if (u->in_dbus_queue) {
764 LIST_REMOVE(dbus_queue, u->manager->dbus_unit_queue, u);
765 u->in_dbus_queue = false;
771 r = bus_foreach_bus(u->manager, NULL, u->sent_dbus_new_signal ? send_changed_signal : send_new_signal, u);
773 log_debug_errno(r, "Failed to send unit change signal for %s: %m", u->id);
775 u->sent_dbus_new_signal = true;
778 static int send_removed_signal(sd_bus *bus, void *userdata) {
779 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
780 _cleanup_free_ char *p = NULL;
787 p = unit_dbus_path(u);
791 r = sd_bus_message_new_signal(
794 "/org/freedesktop/systemd1",
795 "org.freedesktop.systemd1.Manager",
800 r = sd_bus_message_append(m, "so", u->id, p);
804 return sd_bus_send(bus, m, NULL);
807 void bus_unit_send_removed_signal(Unit *u) {
811 if (!u->sent_dbus_new_signal)
812 bus_unit_send_change_signal(u);
817 r = bus_foreach_bus(u->manager, NULL, send_removed_signal, u);
819 log_debug_errno(r, "Failed to send unit remove signal for %s: %m", u->id);
822 int bus_unit_queue_job(
824 sd_bus_message *message,
828 bool reload_if_possible,
829 sd_bus_error *error) {
831 _cleanup_free_ char *path = NULL;
838 assert(type >= 0 && type < _JOB_TYPE_MAX);
839 assert(mode >= 0 && mode < _JOB_MODE_MAX);
841 if (reload_if_possible && unit_can_reload(u)) {
842 if (type == JOB_RESTART)
843 type = JOB_RELOAD_OR_START;
844 else if (type == JOB_TRY_RESTART)
848 r = mac_selinux_unit_access_check(
850 (type == JOB_START || type == JOB_RESTART || type == JOB_TRY_RESTART) ? "start" :
851 type == JOB_STOP ? "stop" : "reload", error);
855 if (type == JOB_STOP &&
856 (u->load_state == UNIT_NOT_FOUND || u->load_state == UNIT_ERROR) &&
857 unit_active_state(u) == UNIT_INACTIVE)
858 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not loaded.", u->id);
860 if ((type == JOB_START && u->refuse_manual_start) ||
861 (type == JOB_STOP && u->refuse_manual_stop) ||
862 ((type == JOB_RESTART || type == JOB_TRY_RESTART) && (u->refuse_manual_start || u->refuse_manual_stop)))
863 return sd_bus_error_setf(error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, unit %s may be requested by dependency only.", u->id);
865 r = manager_add_job(u->manager, type, u, mode, true, error, &j);
869 if (bus == u->manager->api_bus) {
871 r = sd_bus_track_new(bus, &j->clients, NULL, NULL);
876 r = sd_bus_track_add_sender(j->clients, message);
881 path = job_dbus_path(j);
885 return sd_bus_reply_method_return(message, "o", path);
888 static int bus_unit_set_transient_property(
891 sd_bus_message *message,
892 UnitSetPropertiesMode mode,
893 sd_bus_error *error) {
901 if (streq(name, "Description")) {
904 r = sd_bus_message_read(message, "s", &d);
908 if (mode != UNIT_CHECK) {
909 r = unit_set_description(u, d);
913 unit_write_drop_in_format(u, mode, name, "[Unit]\nDescription=%s\n", d);
918 } else if (streq(name, "DefaultDependencies")) {
921 r = sd_bus_message_read(message, "b", &b);
925 if (mode != UNIT_CHECK) {
926 u->default_dependencies = b;
927 unit_write_drop_in_format(u, mode, name, "[Unit]\nDefaultDependencies=%s\n", yes_no(b));
932 } else if (streq(name, "Slice") && unit_get_cgroup_context(u)) {
935 r = sd_bus_message_read(message, "s", &s);
939 if (!unit_name_is_valid(s, TEMPLATE_INVALID) || !endswith(s, ".slice"))
940 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid slice name %s", s);
943 if (mode != UNIT_CHECK) {
944 unit_ref_unset(&u->slice);
945 unit_remove_drop_in(u, mode, name);
950 r = manager_load_unit(u->manager, s, NULL, error, &slice);
954 if (slice->type != UNIT_SLICE)
957 if (mode != UNIT_CHECK) {
958 unit_ref_set(&u->slice, slice);
959 unit_write_drop_in_private_format(u, mode, name, "Slice=%s\n", s);
964 } else if (STR_IN_SET(name,
965 "Requires", "RequiresOverridable",
966 "Requisite", "RequisiteOverridable",
972 "PropagatesReloadTo", "ReloadPropagatedFrom",
978 d = unit_dependency_from_string(name);
982 r = sd_bus_message_enter_container(message, 'a', "s");
986 while ((r = sd_bus_message_read(message, "s", &other)) > 0) {
987 if (!unit_name_is_valid(other, TEMPLATE_INVALID))
988 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit name %s", other);
990 if (mode != UNIT_CHECK) {
991 _cleanup_free_ char *label = NULL;
993 r = unit_add_dependency_by_name(u, d, other, NULL, true);
997 label = strjoin(name, "-", other, NULL);
1001 unit_write_drop_in_format(u, mode, label, "[Unit]\n%s=%s\n", name, other);
1008 r = sd_bus_message_exit_container(message);
1018 int bus_unit_set_properties(
1020 sd_bus_message *message,
1021 UnitSetPropertiesMode mode,
1023 sd_bus_error *error) {
1025 bool for_real = false;
1032 /* We iterate through the array twice. First run we just check
1033 * if all passed data is valid, second run actually applies
1034 * it. This is to implement transaction-like behaviour without
1035 * actually providing full transactions. */
1037 r = sd_bus_message_enter_container(message, 'a', "(sv)");
1044 r = sd_bus_message_enter_container(message, 'r', "sv");
1048 if (for_real || mode == UNIT_CHECK)
1051 /* Reached EOF. Let's try again, and this time for realz... */
1052 r = sd_bus_message_rewind(message, false);
1060 r = sd_bus_message_read(message, "s", &name);
1064 if (!UNIT_VTABLE(u)->bus_set_property)
1065 return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Objects of this type do not support setting properties.");
1067 r = sd_bus_message_enter_container(message, 'v', NULL);
1071 r = UNIT_VTABLE(u)->bus_set_property(u, name, message, for_real ? mode : UNIT_CHECK, error);
1072 if (r == 0 && u->transient && u->load_state == UNIT_STUB)
1073 r = bus_unit_set_transient_property(u, name, message, for_real ? mode : UNIT_CHECK, error);
1077 return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Cannot set property %s, or unknown property.", name);
1079 r = sd_bus_message_exit_container(message);
1083 r = sd_bus_message_exit_container(message);
1090 r = sd_bus_message_exit_container(message);
1094 if (commit && n > 0 && UNIT_VTABLE(u)->bus_commit_properties)
1095 UNIT_VTABLE(u)->bus_commit_properties(u);