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) {
665 uint64_t sz = (uint64_t) -1;
672 if (u->cgroup_path &&
673 (u->cgroup_realized_mask & CGROUP_MEMORY)) {
674 _cleanup_free_ char *v = NULL;
676 r = cg_get_attribute("memory", u->cgroup_path, "memory.usage_in_bytes", &v);
677 if (r < 0 && r != -ENOENT)
678 log_unit_warning_errno(u->id, r, "Couldn't read memory.usage_in_bytes attribute: %m");
681 r = safe_atou64(v, &sz);
683 log_unit_warning_errno(u->id, r, "Failed to parse memory.usage_in_bytes attribute: %m");
687 return sd_bus_message_append(reply, "t", sz);
690 const sd_bus_vtable bus_unit_cgroup_vtable[] = {
691 SD_BUS_VTABLE_START(0),
692 SD_BUS_PROPERTY("Slice", "s", property_get_slice, 0, 0),
693 SD_BUS_PROPERTY("ControlGroup", "s", NULL, offsetof(Unit, cgroup_path), 0),
694 SD_BUS_PROPERTY("MemoryCurrent", "t", property_get_current_memory, 0, 0),
698 static int send_new_signal(sd_bus *bus, void *userdata) {
699 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
700 _cleanup_free_ char *p = NULL;
707 p = unit_dbus_path(u);
711 r = sd_bus_message_new_signal(
714 "/org/freedesktop/systemd1",
715 "org.freedesktop.systemd1.Manager",
720 r = sd_bus_message_append(m, "so", u->id, p);
724 return sd_bus_send(bus, m, NULL);
727 static int send_changed_signal(sd_bus *bus, void *userdata) {
728 _cleanup_free_ char *p = NULL;
735 p = unit_dbus_path(u);
739 /* Send a properties changed signal. First for the specific
740 * type, then for the generic unit. The clients may rely on
741 * this order to get atomic behavior if needed. */
743 r = sd_bus_emit_properties_changed_strv(
745 UNIT_VTABLE(u)->bus_interface,
750 return sd_bus_emit_properties_changed_strv(
752 "org.freedesktop.systemd1.Unit",
756 void bus_unit_send_change_signal(Unit *u) {
760 if (u->in_dbus_queue) {
761 LIST_REMOVE(dbus_queue, u->manager->dbus_unit_queue, u);
762 u->in_dbus_queue = false;
768 r = bus_foreach_bus(u->manager, NULL, u->sent_dbus_new_signal ? send_changed_signal : send_new_signal, u);
770 log_debug_errno(r, "Failed to send unit change signal for %s: %m", u->id);
772 u->sent_dbus_new_signal = true;
775 static int send_removed_signal(sd_bus *bus, void *userdata) {
776 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
777 _cleanup_free_ char *p = NULL;
784 p = unit_dbus_path(u);
788 r = sd_bus_message_new_signal(
791 "/org/freedesktop/systemd1",
792 "org.freedesktop.systemd1.Manager",
797 r = sd_bus_message_append(m, "so", u->id, p);
801 return sd_bus_send(bus, m, NULL);
804 void bus_unit_send_removed_signal(Unit *u) {
808 if (!u->sent_dbus_new_signal)
809 bus_unit_send_change_signal(u);
814 r = bus_foreach_bus(u->manager, NULL, send_removed_signal, u);
816 log_debug_errno(r, "Failed to send unit remove signal for %s: %m", u->id);
819 int bus_unit_queue_job(
821 sd_bus_message *message,
825 bool reload_if_possible,
826 sd_bus_error *error) {
828 _cleanup_free_ char *path = NULL;
835 assert(type >= 0 && type < _JOB_TYPE_MAX);
836 assert(mode >= 0 && mode < _JOB_MODE_MAX);
838 if (reload_if_possible && unit_can_reload(u)) {
839 if (type == JOB_RESTART)
840 type = JOB_RELOAD_OR_START;
841 else if (type == JOB_TRY_RESTART)
845 r = mac_selinux_unit_access_check(
847 (type == JOB_START || type == JOB_RESTART || type == JOB_TRY_RESTART) ? "start" :
848 type == JOB_STOP ? "stop" : "reload", error);
852 if (type == JOB_STOP &&
853 (u->load_state == UNIT_NOT_FOUND || u->load_state == UNIT_ERROR) &&
854 unit_active_state(u) == UNIT_INACTIVE)
855 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not loaded.", u->id);
857 if ((type == JOB_START && u->refuse_manual_start) ||
858 (type == JOB_STOP && u->refuse_manual_stop) ||
859 ((type == JOB_RESTART || type == JOB_TRY_RESTART) && (u->refuse_manual_start || u->refuse_manual_stop)))
860 return sd_bus_error_setf(error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, unit %s may be requested by dependency only.", u->id);
862 r = manager_add_job(u->manager, type, u, mode, true, error, &j);
866 if (bus == u->manager->api_bus) {
868 r = sd_bus_track_new(bus, &j->clients, NULL, NULL);
873 r = sd_bus_track_add_sender(j->clients, message);
878 path = job_dbus_path(j);
882 return sd_bus_reply_method_return(message, "o", path);
885 static int bus_unit_set_transient_property(
888 sd_bus_message *message,
889 UnitSetPropertiesMode mode,
890 sd_bus_error *error) {
898 if (streq(name, "Description")) {
901 r = sd_bus_message_read(message, "s", &d);
905 if (mode != UNIT_CHECK) {
906 r = unit_set_description(u, d);
910 unit_write_drop_in_format(u, mode, name, "[Unit]\nDescription=%s\n", d);
915 } else if (streq(name, "DefaultDependencies")) {
918 r = sd_bus_message_read(message, "b", &b);
922 if (mode != UNIT_CHECK) {
923 u->default_dependencies = b;
924 unit_write_drop_in_format(u, mode, name, "[Unit]\nDefaultDependencies=%s\n", yes_no(b));
929 } else if (streq(name, "Slice") && unit_get_cgroup_context(u)) {
932 r = sd_bus_message_read(message, "s", &s);
936 if (!unit_name_is_valid(s, TEMPLATE_INVALID) || !endswith(s, ".slice"))
937 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid slice name %s", s);
940 if (mode != UNIT_CHECK) {
941 unit_ref_unset(&u->slice);
942 unit_remove_drop_in(u, mode, name);
947 r = manager_load_unit(u->manager, s, NULL, error, &slice);
951 if (slice->type != UNIT_SLICE)
954 if (mode != UNIT_CHECK) {
955 unit_ref_set(&u->slice, slice);
956 unit_write_drop_in_private_format(u, mode, name, "Slice=%s\n", s);
961 } else if (STR_IN_SET(name,
962 "Requires", "RequiresOverridable",
963 "Requisite", "RequisiteOverridable",
969 "PropagatesReloadTo", "ReloadPropagatedFrom",
975 d = unit_dependency_from_string(name);
979 r = sd_bus_message_enter_container(message, 'a', "s");
983 while ((r = sd_bus_message_read(message, "s", &other)) > 0) {
984 if (!unit_name_is_valid(other, TEMPLATE_INVALID))
985 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit name %s", other);
987 if (mode != UNIT_CHECK) {
988 _cleanup_free_ char *label = NULL;
990 r = unit_add_dependency_by_name(u, d, other, NULL, true);
994 label = strjoin(name, "-", other, NULL);
998 unit_write_drop_in_format(u, mode, label, "[Unit]\n%s=%s\n", name, other);
1005 r = sd_bus_message_exit_container(message);
1015 int bus_unit_set_properties(
1017 sd_bus_message *message,
1018 UnitSetPropertiesMode mode,
1020 sd_bus_error *error) {
1022 bool for_real = false;
1029 /* We iterate through the array twice. First run we just check
1030 * if all passed data is valid, second run actually applies
1031 * it. This is to implement transaction-like behaviour without
1032 * actually providing full transactions. */
1034 r = sd_bus_message_enter_container(message, 'a', "(sv)");
1041 r = sd_bus_message_enter_container(message, 'r', "sv");
1045 if (for_real || mode == UNIT_CHECK)
1048 /* Reached EOF. Let's try again, and this time for realz... */
1049 r = sd_bus_message_rewind(message, false);
1057 r = sd_bus_message_read(message, "s", &name);
1061 if (!UNIT_VTABLE(u)->bus_set_property)
1062 return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Objects of this type do not support setting properties.");
1064 r = sd_bus_message_enter_container(message, 'v', NULL);
1068 r = UNIT_VTABLE(u)->bus_set_property(u, name, message, for_real ? mode : UNIT_CHECK, error);
1069 if (r == 0 && u->transient && u->load_state == UNIT_STUB)
1070 r = bus_unit_set_transient_property(u, name, message, for_real ? mode : UNIT_CHECK, error);
1074 return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Cannot set property %s, or unknown property.", name);
1076 r = sd_bus_message_exit_container(message);
1080 r = sd_bus_message_exit_container(message);
1087 r = sd_bus_message_exit_container(message);
1091 if (commit && n > 0 && UNIT_VTABLE(u)->bus_commit_properties)
1092 UNIT_VTABLE(u)->bus_commit_properties(u);