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-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);
37 static int property_get_names(
40 const char *interface,
42 sd_bus_message *reply,
44 sd_bus_error *error) {
55 r = sd_bus_message_open_container(reply, 'a', "s");
59 SET_FOREACH(t, u->names, i) {
60 r = sd_bus_message_append(reply, "s", t);
65 return sd_bus_message_close_container(reply);
68 static int property_get_following(
71 const char *interface,
73 sd_bus_message *reply,
75 sd_bus_error *error) {
77 Unit *u = userdata, *f;
83 f = unit_following(u);
84 return sd_bus_message_append(reply, "s", f ? f->id : "");
87 static int property_get_dependencies(
90 const char *interface,
92 sd_bus_message *reply,
94 sd_bus_error *error) {
96 Set *s = *(Set**) userdata;
104 r = sd_bus_message_open_container(reply, 'a', "s");
108 SET_FOREACH(u, s, j) {
109 r = sd_bus_message_append(reply, "s", u->id);
114 return sd_bus_message_close_container(reply);
117 static int property_get_description(
120 const char *interface,
121 const char *property,
122 sd_bus_message *reply,
124 sd_bus_error *error) {
132 return sd_bus_message_append(reply, "s", unit_description(u));
135 static int property_get_active_state(
138 const char *interface,
139 const char *property,
140 sd_bus_message *reply,
142 sd_bus_error *error) {
150 return sd_bus_message_append(reply, "s", unit_active_state_to_string(unit_active_state(u)));
153 static int property_get_sub_state(
156 const char *interface,
157 const char *property,
158 sd_bus_message *reply,
160 sd_bus_error *error) {
168 return sd_bus_message_append(reply, "s", unit_sub_state_to_string(u));
171 static int property_get_unit_file_state(
174 const char *interface,
175 const char *property,
176 sd_bus_message *reply,
178 sd_bus_error *error) {
186 return sd_bus_message_append(reply, "s", unit_file_state_to_string(unit_get_unit_file_state(u)));
189 static int property_get_can_start(
192 const char *interface,
193 const char *property,
194 sd_bus_message *reply,
196 sd_bus_error *error) {
204 return sd_bus_message_append(reply, "b", unit_can_start(u) && !u->refuse_manual_start);
207 static int property_get_can_stop(
210 const char *interface,
211 const char *property,
212 sd_bus_message *reply,
214 sd_bus_error *error) {
222 /* On the lower levels we assume that every unit we can start
223 * we can also stop */
225 return sd_bus_message_append(reply, "b", unit_can_start(u) && !u->refuse_manual_stop);
228 static int property_get_can_reload(
231 const char *interface,
232 const char *property,
233 sd_bus_message *reply,
235 sd_bus_error *error) {
243 return sd_bus_message_append(reply, "b", unit_can_reload(u));
246 static int property_get_can_isolate(
249 const char *interface,
250 const char *property,
251 sd_bus_message *reply,
253 sd_bus_error *error) {
261 return sd_bus_message_append(reply, "b", unit_can_isolate(u) && !u->refuse_manual_start);
264 static int property_get_job(
267 const char *interface,
268 const char *property,
269 sd_bus_message *reply,
271 sd_bus_error *error) {
273 _cleanup_free_ char *p = NULL;
281 return sd_bus_message_append(reply, "(uo)", 0, "/");
283 p = job_dbus_path(u->job);
287 return sd_bus_message_append(reply, "(uo)", u->job->id, p);
290 static int property_get_need_daemon_reload(
293 const char *interface,
294 const char *property,
295 sd_bus_message *reply,
297 sd_bus_error *error) {
305 return sd_bus_message_append(reply, "b", unit_need_daemon_reload(u));
308 static int property_get_conditions(
311 const char *interface,
312 const char *property,
313 sd_bus_message *reply,
315 sd_bus_error *error) {
325 r = sd_bus_message_open_container(reply, 'a', "(sbbsi)");
329 LIST_FOREACH(conditions, c, u->conditions) {
330 r = sd_bus_message_append(reply, "(sbbsi)",
331 condition_type_to_string(c->type),
332 c->trigger, c->negate,
333 c->parameter, c->state);
339 return sd_bus_message_close_container(reply);
342 static int property_get_load_error(
345 const char *interface,
346 const char *property,
347 sd_bus_message *reply,
349 sd_bus_error *error) {
351 _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL;
358 if (u->load_error != 0)
359 sd_bus_error_set_errno(&e, u->load_error);
361 return sd_bus_message_append(reply, "(ss)", e.name, e.message);
364 int bus_unit_method_start_generic(sd_bus *bus, sd_bus_message *message, Unit *u, JobType job_type, bool reload_if_possible, sd_bus_error *error) {
372 assert(job_type >= 0 && job_type < _JOB_TYPE_MAX);
374 r = sd_bus_message_read(message, "s", &smode);
378 mode = job_mode_from_string(smode);
380 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Job mode %s invalid", smode);
382 return bus_unit_queue_job(bus, message, u, job_type, mode, reload_if_possible, error);
385 static int method_start(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
386 return bus_unit_method_start_generic(bus, message, userdata, JOB_START, false, error);
389 static int method_stop(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
390 return bus_unit_method_start_generic(bus, message, userdata, JOB_STOP, false, error);
393 static int method_reload(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
394 return bus_unit_method_start_generic(bus, message, userdata, JOB_RELOAD, false, error);
397 static int method_restart(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
398 return bus_unit_method_start_generic(bus, message, userdata, JOB_RESTART, false, error);
401 static int method_try_restart(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
402 return bus_unit_method_start_generic(bus, message, userdata, JOB_TRY_RESTART, false, error);
405 static int method_reload_or_restart(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
406 return bus_unit_method_start_generic(bus, message, userdata, JOB_RESTART, true, error);
409 static int method_reload_or_try_restart(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
410 return bus_unit_method_start_generic(bus, message, userdata, JOB_TRY_RESTART, true, error);
413 int bus_unit_method_kill(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
424 r = bus_verify_manage_unit_async_for_kill(u->manager, message, error);
428 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
430 r = sd_bus_message_read(message, "si", &swho, &signo);
437 who = kill_who_from_string(swho);
439 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid who argument %s", swho);
442 if (signo <= 0 || signo >= _NSIG)
443 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Signal number out of range.");
445 r = selinux_unit_access_check(u, message, "stop", error);
449 r = unit_kill(u, who, signo, error);
453 return sd_bus_reply_method_return(message, NULL);
456 int bus_unit_method_reset_failed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
464 r = bus_verify_manage_unit_async(u->manager, message, error);
468 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
470 r = selinux_unit_access_check(u, message, "reload", error);
474 unit_reset_failed(u);
476 return sd_bus_reply_method_return(message, NULL);
479 int bus_unit_method_set_properties(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
487 r = bus_verify_manage_unit_async(u->manager, message, error);
491 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
493 r = sd_bus_message_read(message, "b", &runtime);
497 r = selinux_unit_access_check(u, message, "start", error);
501 r = bus_unit_set_properties(u, message, runtime ? UNIT_RUNTIME : UNIT_PERSISTENT, true, error);
505 return sd_bus_reply_method_return(message, NULL);
508 const sd_bus_vtable bus_unit_vtable[] = {
509 SD_BUS_VTABLE_START(0),
511 SD_BUS_PROPERTY("Id", "s", NULL, offsetof(Unit, id), SD_BUS_VTABLE_PROPERTY_CONST),
512 SD_BUS_PROPERTY("Names", "as", property_get_names, 0, SD_BUS_VTABLE_PROPERTY_CONST),
513 SD_BUS_PROPERTY("Following", "s", property_get_following, 0, 0),
514 SD_BUS_PROPERTY("Requires", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRES]), SD_BUS_VTABLE_PROPERTY_CONST),
515 SD_BUS_PROPERTY("RequiresOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRES_OVERRIDABLE]), SD_BUS_VTABLE_PROPERTY_CONST),
516 SD_BUS_PROPERTY("Requisite", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE]), SD_BUS_VTABLE_PROPERTY_CONST),
517 SD_BUS_PROPERTY("RequisiteOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE_OVERRIDABLE]), SD_BUS_VTABLE_PROPERTY_CONST),
518 SD_BUS_PROPERTY("Wants", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_WANTS]), SD_BUS_VTABLE_PROPERTY_CONST),
519 SD_BUS_PROPERTY("BindsTo", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BINDS_TO]), SD_BUS_VTABLE_PROPERTY_CONST),
520 SD_BUS_PROPERTY("PartOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_PART_OF]), SD_BUS_VTABLE_PROPERTY_CONST),
521 SD_BUS_PROPERTY("RequiredBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
522 SD_BUS_PROPERTY("RequiredByOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRED_BY_OVERRIDABLE]), SD_BUS_VTABLE_PROPERTY_CONST),
523 SD_BUS_PROPERTY("WantedBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_WANTED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
524 SD_BUS_PROPERTY("BoundBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BOUND_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
525 SD_BUS_PROPERTY("ConsistsOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONSISTS_OF]), SD_BUS_VTABLE_PROPERTY_CONST),
526 SD_BUS_PROPERTY("Conflicts", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONFLICTS]), SD_BUS_VTABLE_PROPERTY_CONST),
527 SD_BUS_PROPERTY("ConflictedBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONFLICTED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
528 SD_BUS_PROPERTY("Before", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BEFORE]), SD_BUS_VTABLE_PROPERTY_CONST),
529 SD_BUS_PROPERTY("After", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_AFTER]), SD_BUS_VTABLE_PROPERTY_CONST),
530 SD_BUS_PROPERTY("OnFailure", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_ON_FAILURE]), SD_BUS_VTABLE_PROPERTY_CONST),
531 SD_BUS_PROPERTY("Triggers", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_TRIGGERS]), SD_BUS_VTABLE_PROPERTY_CONST),
532 SD_BUS_PROPERTY("TriggeredBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_TRIGGERED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
533 SD_BUS_PROPERTY("PropagatesReloadTo", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_PROPAGATES_RELOAD_TO]), SD_BUS_VTABLE_PROPERTY_CONST),
534 SD_BUS_PROPERTY("ReloadPropagatedFrom", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_RELOAD_PROPAGATED_FROM]), SD_BUS_VTABLE_PROPERTY_CONST),
535 SD_BUS_PROPERTY("JoinsNamespaceOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_JOINS_NAMESPACE_OF]), SD_BUS_VTABLE_PROPERTY_CONST),
536 SD_BUS_PROPERTY("RequiresMountsFor", "as", NULL, offsetof(Unit, requires_mounts_for), SD_BUS_VTABLE_PROPERTY_CONST),
537 SD_BUS_PROPERTY("Documentation", "as", NULL, offsetof(Unit, documentation), SD_BUS_VTABLE_PROPERTY_CONST),
538 SD_BUS_PROPERTY("Description", "s", property_get_description, 0, SD_BUS_VTABLE_PROPERTY_CONST),
539 SD_BUS_PROPERTY("LoadState", "s", property_get_load_state, offsetof(Unit, load_state), SD_BUS_VTABLE_PROPERTY_CONST),
540 SD_BUS_PROPERTY("ActiveState", "s", property_get_active_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
541 SD_BUS_PROPERTY("SubState", "s", property_get_sub_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
542 SD_BUS_PROPERTY("FragmentPath", "s", NULL, offsetof(Unit, fragment_path), SD_BUS_VTABLE_PROPERTY_CONST),
543 SD_BUS_PROPERTY("SourcePath", "s", NULL, offsetof(Unit, source_path), SD_BUS_VTABLE_PROPERTY_CONST),
544 SD_BUS_PROPERTY("DropInPaths", "as", NULL, offsetof(Unit, dropin_paths), SD_BUS_VTABLE_PROPERTY_CONST),
545 SD_BUS_PROPERTY("UnitFileState", "s", property_get_unit_file_state, 0, 0),
546 BUS_PROPERTY_DUAL_TIMESTAMP("InactiveExitTimestamp", offsetof(Unit, inactive_exit_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
547 BUS_PROPERTY_DUAL_TIMESTAMP("ActiveEnterTimestamp", offsetof(Unit, active_enter_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
548 BUS_PROPERTY_DUAL_TIMESTAMP("ActiveExitTimestamp", offsetof(Unit, active_exit_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
549 BUS_PROPERTY_DUAL_TIMESTAMP("InactiveEnterTimestamp", offsetof(Unit, inactive_enter_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
550 SD_BUS_PROPERTY("CanStart", "b", property_get_can_start, 0, SD_BUS_VTABLE_PROPERTY_CONST),
551 SD_BUS_PROPERTY("CanStop", "b", property_get_can_stop, 0, SD_BUS_VTABLE_PROPERTY_CONST),
552 SD_BUS_PROPERTY("CanReload", "b", property_get_can_reload, 0, SD_BUS_VTABLE_PROPERTY_CONST),
553 SD_BUS_PROPERTY("CanIsolate", "b", property_get_can_isolate, 0, SD_BUS_VTABLE_PROPERTY_CONST),
554 SD_BUS_PROPERTY("Job", "(uo)", property_get_job, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
555 SD_BUS_PROPERTY("StopWhenUnneeded", "b", bus_property_get_bool, offsetof(Unit, stop_when_unneeded), SD_BUS_VTABLE_PROPERTY_CONST),
556 SD_BUS_PROPERTY("RefuseManualStart", "b", bus_property_get_bool, offsetof(Unit, refuse_manual_start), SD_BUS_VTABLE_PROPERTY_CONST),
557 SD_BUS_PROPERTY("RefuseManualStop", "b", bus_property_get_bool, offsetof(Unit, refuse_manual_stop), SD_BUS_VTABLE_PROPERTY_CONST),
558 SD_BUS_PROPERTY("AllowIsolate", "b", bus_property_get_bool, offsetof(Unit, allow_isolate), SD_BUS_VTABLE_PROPERTY_CONST),
559 SD_BUS_PROPERTY("DefaultDependencies", "b", bus_property_get_bool, offsetof(Unit, default_dependencies), SD_BUS_VTABLE_PROPERTY_CONST),
560 SD_BUS_PROPERTY("OnFailureJobMode", "s", property_get_job_mode, offsetof(Unit, on_failure_job_mode), SD_BUS_VTABLE_PROPERTY_CONST),
561 SD_BUS_PROPERTY("IgnoreOnIsolate", "b", bus_property_get_bool, offsetof(Unit, ignore_on_isolate), SD_BUS_VTABLE_PROPERTY_CONST),
562 SD_BUS_PROPERTY("IgnoreOnSnapshot", "b", bus_property_get_bool, offsetof(Unit, ignore_on_snapshot), SD_BUS_VTABLE_PROPERTY_CONST),
563 SD_BUS_PROPERTY("NeedDaemonReload", "b", property_get_need_daemon_reload, 0, SD_BUS_VTABLE_PROPERTY_CONST),
564 SD_BUS_PROPERTY("JobTimeoutUSec", "t", bus_property_get_usec, offsetof(Unit, job_timeout), SD_BUS_VTABLE_PROPERTY_CONST),
565 SD_BUS_PROPERTY("ConditionResult", "b", bus_property_get_bool, offsetof(Unit, condition_result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
566 BUS_PROPERTY_DUAL_TIMESTAMP("ConditionTimestamp", offsetof(Unit, condition_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
567 SD_BUS_PROPERTY("Conditions", "a(sbbsi)", property_get_conditions, 0, 0),
568 SD_BUS_PROPERTY("LoadError", "(ss)", property_get_load_error, 0, SD_BUS_VTABLE_PROPERTY_CONST),
569 SD_BUS_PROPERTY("Transient", "b", bus_property_get_bool, offsetof(Unit, transient), SD_BUS_VTABLE_PROPERTY_CONST),
571 SD_BUS_METHOD("Start", "s", "o", method_start, 0),
572 SD_BUS_METHOD("Stop", "s", "o", method_stop, 0),
573 SD_BUS_METHOD("Reload", "s", "o", method_reload, 0),
574 SD_BUS_METHOD("Restart", "s", "o", method_restart, 0),
575 SD_BUS_METHOD("TryRestart", "s", "o", method_try_restart, 0),
576 SD_BUS_METHOD("ReloadOrRestart", "s", "o", method_reload_or_restart, 0),
577 SD_BUS_METHOD("ReloadOrTryRestart", "s", "o", method_reload_or_try_restart, 0),
578 SD_BUS_METHOD("Kill", "si", NULL, bus_unit_method_kill, 0),
579 SD_BUS_METHOD("ResetFailed", NULL, NULL, bus_unit_method_reset_failed, 0),
580 SD_BUS_METHOD("SetProperties", "ba(sv)", NULL, bus_unit_method_set_properties, 0),
585 static int property_get_slice(
588 const char *interface,
589 const char *property,
590 sd_bus_message *reply,
592 sd_bus_error *error) {
600 return sd_bus_message_append(reply, "s", unit_slice_name(u));
603 const sd_bus_vtable bus_unit_cgroup_vtable[] = {
604 SD_BUS_VTABLE_START(0),
605 SD_BUS_PROPERTY("Slice", "s", property_get_slice, 0, 0),
606 SD_BUS_PROPERTY("ControlGroup", "s", NULL, offsetof(Unit, cgroup_path), 0),
610 static int send_new_signal(sd_bus *bus, void *userdata) {
611 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
612 _cleanup_free_ char *p = NULL;
619 p = unit_dbus_path(u);
623 r = sd_bus_message_new_signal(
626 "/org/freedesktop/systemd1",
627 "org.freedesktop.systemd1.Manager",
632 r = sd_bus_message_append(m, "so", u->id, p);
636 return sd_bus_send(bus, m, NULL);
639 static int send_changed_signal(sd_bus *bus, void *userdata) {
640 _cleanup_free_ char *p = NULL;
647 p = unit_dbus_path(u);
651 /* Send a properties changed signal. First for the specific
652 * type, then for the generic unit. The clients may rely on
653 * this order to get atomic behavior if needed. */
655 r = sd_bus_emit_properties_changed_strv(
657 UNIT_VTABLE(u)->bus_interface,
662 return sd_bus_emit_properties_changed_strv(
664 "org.freedesktop.systemd1.Unit",
668 void bus_unit_send_change_signal(Unit *u) {
672 if (u->in_dbus_queue) {
673 LIST_REMOVE(dbus_queue, u->manager->dbus_unit_queue, u);
674 u->in_dbus_queue = false;
680 r = bus_foreach_bus(u->manager, NULL, u->sent_dbus_new_signal ? send_changed_signal : send_new_signal, u);
682 log_debug("Failed to send unit change signal for %s: %s", u->id, strerror(-r));
684 u->sent_dbus_new_signal = true;
687 static int send_removed_signal(sd_bus *bus, void *userdata) {
688 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
689 _cleanup_free_ char *p = NULL;
696 p = unit_dbus_path(u);
700 r = sd_bus_message_new_signal(
703 "/org/freedesktop/systemd1",
704 "org.freedesktop.systemd1.Manager",
709 r = sd_bus_message_append(m, "so", u->id, p);
713 return sd_bus_send(bus, m, NULL);
716 void bus_unit_send_removed_signal(Unit *u) {
720 if (!u->sent_dbus_new_signal)
721 bus_unit_send_change_signal(u);
726 r = bus_foreach_bus(u->manager, NULL, send_removed_signal, u);
728 log_debug("Failed to send unit remove signal for %s: %s", u->id, strerror(-r));
731 int bus_unit_queue_job(
733 sd_bus_message *message,
737 bool reload_if_possible,
738 sd_bus_error *error) {
740 _cleanup_free_ char *path = NULL;
747 assert(type >= 0 && type < _JOB_TYPE_MAX);
748 assert(mode >= 0 && mode < _JOB_MODE_MAX);
750 if (reload_if_possible && unit_can_reload(u)) {
751 if (type == JOB_RESTART)
752 type = JOB_RELOAD_OR_START;
753 else if (type == JOB_TRY_RESTART)
757 r = selinux_unit_access_check(
759 (type == JOB_START || type == JOB_RESTART || type == JOB_TRY_RESTART) ? "start" :
760 type == JOB_STOP ? "stop" : "reload", error);
764 if (type == JOB_STOP &&
765 (u->load_state == UNIT_NOT_FOUND || u->load_state == UNIT_ERROR) &&
766 unit_active_state(u) == UNIT_INACTIVE)
767 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not loaded.", u->id);
769 if ((type == JOB_START && u->refuse_manual_start) ||
770 (type == JOB_STOP && u->refuse_manual_stop) ||
771 ((type == JOB_RESTART || type == JOB_TRY_RESTART) && (u->refuse_manual_start || u->refuse_manual_stop)))
772 return sd_bus_error_setf(error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, unit %s may be requested by dependency only.", u->id);
774 r = manager_add_job(u->manager, type, u, mode, true, error, &j);
778 if (bus == u->manager->api_bus) {
780 r = sd_bus_track_new(bus, &j->clients, NULL, NULL);
785 r = sd_bus_track_add_sender(j->clients, message);
790 path = job_dbus_path(j);
794 return sd_bus_reply_method_return(message, "o", path);
797 static int bus_unit_set_transient_property(
800 sd_bus_message *message,
801 UnitSetPropertiesMode mode,
802 sd_bus_error *error) {
810 if (streq(name, "Description")) {
813 r = sd_bus_message_read(message, "s", &d);
817 if (mode != UNIT_CHECK) {
818 r = unit_set_description(u, d);
822 unit_write_drop_in_format(u, mode, name, "[Unit]\nDescription=%s\n", d);
827 } else if (streq(name, "Slice") && unit_get_cgroup_context(u)) {
830 r = sd_bus_message_read(message, "s", &s);
834 if (!unit_name_is_valid(s, TEMPLATE_INVALID) || !endswith(s, ".slice"))
835 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid slice name %s", s);
838 if (mode != UNIT_CHECK) {
839 unit_ref_unset(&u->slice);
840 unit_remove_drop_in(u, mode, name);
845 r = manager_load_unit(u->manager, s, NULL, error, &slice);
849 if (slice->type != UNIT_SLICE)
852 if (mode != UNIT_CHECK) {
853 unit_ref_set(&u->slice, slice);
854 unit_write_drop_in_private_format(u, mode, name, "Slice=%s\n", s);
860 } else if (streq(name, "Requires") ||
861 streq(name, "RequiresOverridable") ||
862 streq(name, "Requisite") ||
863 streq(name, "RequisiteOverridable") ||
864 streq(name, "Wants") ||
865 streq(name, "BindsTo") ||
866 streq(name, "Conflicts") ||
867 streq(name, "Before") ||
868 streq(name, "After") ||
869 streq(name, "OnFailure") ||
870 streq(name, "PropagatesReloadTo") ||
871 streq(name, "ReloadPropagatedFrom") ||
872 streq(name, "PartOf")) {
877 d = unit_dependency_from_string(name);
881 r = sd_bus_message_enter_container(message, 'a', "s");
885 while ((r = sd_bus_message_read(message, "s", &other)) > 0) {
886 if (!unit_name_is_valid(other, TEMPLATE_INVALID))
887 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit name %s", other);
889 if (mode != UNIT_CHECK) {
890 _cleanup_free_ char *label = NULL;
892 r = unit_add_dependency_by_name(u, d, other, NULL, true);
896 label = strjoin(name, "-", other, NULL);
900 unit_write_drop_in_format(u, mode, label, "[Unit]\n%s=%s\n", name, other);
907 r = sd_bus_message_exit_container(message);
917 int bus_unit_set_properties(
919 sd_bus_message *message,
920 UnitSetPropertiesMode mode,
922 sd_bus_error *error) {
924 bool for_real = false;
931 /* We iterate through the array twice. First run we just check
932 * if all passed data is valid, second run actually applies
933 * it. This is to implement transaction-like behaviour without
934 * actually providing full transactions. */
936 r = sd_bus_message_enter_container(message, 'a', "(sv)");
943 r = sd_bus_message_enter_container(message, 'r', "sv");
947 if (for_real || mode == UNIT_CHECK)
950 /* Reached EOF. Let's try again, and this time for realz... */
951 r = sd_bus_message_rewind(message, false);
959 r = sd_bus_message_read(message, "s", &name);
963 if (!UNIT_VTABLE(u)->bus_set_property)
964 return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Objects of this type do not support setting properties.");
966 r = sd_bus_message_enter_container(message, 'v', NULL);
970 r = UNIT_VTABLE(u)->bus_set_property(u, name, message, for_real ? mode : UNIT_CHECK, error);
971 if (r == 0 && u->transient && u->load_state == UNIT_STUB)
972 r = bus_unit_set_transient_property(u, name, message, for_real ? mode : UNIT_CHECK, error);
976 return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Cannot set property %s, or unknown property.", name);
978 r = sd_bus_message_exit_container(message);
982 r = sd_bus_message_exit_container(message);
989 r = sd_bus_message_exit_container(message);
993 if (commit && n > 0 && UNIT_VTABLE(u)->bus_commit_properties)
994 UNIT_VTABLE(u)->bus_commit_properties(u);