1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2010 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
23 #include "alloc-util.h"
24 #include "bpf-firewall.h"
25 #include "bus-common-errors.h"
26 #include "cgroup-util.h"
28 #include "dbus-unit.h"
31 #include "locale-util.h"
33 #include "process-util.h"
34 #include "selinux-access.h"
35 #include "signal-util.h"
37 #include "string-util.h"
39 #include "user-util.h"
41 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_collect_mode
, collect_mode
, CollectMode
);
42 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_load_state
, unit_load_state
, UnitLoadState
);
43 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_job_mode
, job_mode
, JobMode
);
44 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_emergency_action
, emergency_action
, EmergencyAction
);
46 static int property_get_names(
49 const char *interface
,
51 sd_bus_message
*reply
,
53 sd_bus_error
*error
) {
64 r
= sd_bus_message_open_container(reply
, 'a', "s");
68 SET_FOREACH(t
, u
->names
, i
) {
69 r
= sd_bus_message_append(reply
, "s", t
);
74 return sd_bus_message_close_container(reply
);
77 static int property_get_following(
80 const char *interface
,
82 sd_bus_message
*reply
,
84 sd_bus_error
*error
) {
86 Unit
*u
= userdata
, *f
;
92 f
= unit_following(u
);
93 return sd_bus_message_append(reply
, "s", f
? f
->id
: "");
96 static int property_get_dependencies(
99 const char *interface
,
100 const char *property
,
101 sd_bus_message
*reply
,
103 sd_bus_error
*error
) {
105 Hashmap
*h
= *(Hashmap
**) userdata
;
114 r
= sd_bus_message_open_container(reply
, 'a', "s");
118 HASHMAP_FOREACH_KEY(v
, u
, h
, j
) {
119 r
= sd_bus_message_append(reply
, "s", u
->id
);
124 return sd_bus_message_close_container(reply
);
127 static int property_get_obsolete_dependencies(
130 const char *interface
,
131 const char *property
,
132 sd_bus_message
*reply
,
134 sd_bus_error
*error
) {
139 /* For dependency types we don't support anymore always return an empty array */
140 return sd_bus_message_append(reply
, "as", 0);
143 static int property_get_requires_mounts_for(
146 const char *interface
,
147 const char *property
,
148 sd_bus_message
*reply
,
150 sd_bus_error
*error
) {
152 Hashmap
*h
= *(Hashmap
**) userdata
;
161 r
= sd_bus_message_open_container(reply
, 'a', "s");
165 HASHMAP_FOREACH_KEY(v
, p
, h
, j
) {
166 r
= sd_bus_message_append(reply
, "s", p
);
171 return sd_bus_message_close_container(reply
);
174 static int property_get_description(
177 const char *interface
,
178 const char *property
,
179 sd_bus_message
*reply
,
181 sd_bus_error
*error
) {
189 return sd_bus_message_append(reply
, "s", unit_description(u
));
192 static int property_get_active_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_active_state_to_string(unit_active_state(u
)));
210 static int property_get_sub_state(
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
, "s", unit_sub_state_to_string(u
));
228 static int property_get_unit_file_preset(
231 const char *interface
,
232 const char *property
,
233 sd_bus_message
*reply
,
235 sd_bus_error
*error
) {
244 r
= unit_get_unit_file_preset(u
);
246 return sd_bus_message_append(reply
, "s",
248 r
> 0 ? "enabled" : "disabled");
251 static int property_get_unit_file_state(
254 const char *interface
,
255 const char *property
,
256 sd_bus_message
*reply
,
258 sd_bus_error
*error
) {
266 return sd_bus_message_append(reply
, "s", unit_file_state_to_string(unit_get_unit_file_state(u
)));
269 static int property_get_can_start(
272 const char *interface
,
273 const char *property
,
274 sd_bus_message
*reply
,
276 sd_bus_error
*error
) {
284 return sd_bus_message_append(reply
, "b", unit_can_start(u
) && !u
->refuse_manual_start
);
287 static int property_get_can_stop(
290 const char *interface
,
291 const char *property
,
292 sd_bus_message
*reply
,
294 sd_bus_error
*error
) {
302 return sd_bus_message_append(reply
, "b", unit_can_stop(u
) && !u
->refuse_manual_stop
);
305 static int property_get_can_reload(
308 const char *interface
,
309 const char *property
,
310 sd_bus_message
*reply
,
312 sd_bus_error
*error
) {
320 return sd_bus_message_append(reply
, "b", unit_can_reload(u
));
323 static int property_get_can_isolate(
326 const char *interface
,
327 const char *property
,
328 sd_bus_message
*reply
,
330 sd_bus_error
*error
) {
338 return sd_bus_message_append(reply
, "b", unit_can_isolate(u
) && !u
->refuse_manual_start
);
341 static int property_get_job(
344 const char *interface
,
345 const char *property
,
346 sd_bus_message
*reply
,
348 sd_bus_error
*error
) {
350 _cleanup_free_
char *p
= NULL
;
358 return sd_bus_message_append(reply
, "(uo)", 0, "/");
360 p
= job_dbus_path(u
->job
);
364 return sd_bus_message_append(reply
, "(uo)", u
->job
->id
, p
);
367 static int property_get_need_daemon_reload(
370 const char *interface
,
371 const char *property
,
372 sd_bus_message
*reply
,
374 sd_bus_error
*error
) {
382 return sd_bus_message_append(reply
, "b", unit_need_daemon_reload(u
));
385 static int property_get_conditions(
388 const char *interface
,
389 const char *property
,
390 sd_bus_message
*reply
,
392 sd_bus_error
*error
) {
394 const char *(*to_string
)(ConditionType type
) = NULL
;
395 Condition
**list
= userdata
, *c
;
402 to_string
= streq(property
, "Asserts") ? assert_type_to_string
: condition_type_to_string
;
404 r
= sd_bus_message_open_container(reply
, 'a', "(sbbsi)");
408 LIST_FOREACH(conditions
, c
, *list
) {
412 c
->result
== CONDITION_UNTESTED
? 0 :
413 c
->result
== CONDITION_SUCCEEDED
? 1 : -1;
415 r
= sd_bus_message_append(reply
, "(sbbsi)",
417 c
->trigger
, c
->negate
,
418 c
->parameter
, tristate
);
424 return sd_bus_message_close_container(reply
);
427 static int property_get_load_error(
430 const char *interface
,
431 const char *property
,
432 sd_bus_message
*reply
,
434 sd_bus_error
*error
) {
436 _cleanup_(sd_bus_error_free
) sd_bus_error e
= SD_BUS_ERROR_NULL
;
443 if (u
->load_error
!= 0)
444 sd_bus_error_set_errno(&e
, u
->load_error
);
446 return sd_bus_message_append(reply
, "(ss)", e
.name
, e
.message
);
449 static int bus_verify_manage_units_async_full(
453 const char *polkit_message
,
455 sd_bus_message
*call
,
456 sd_bus_error
*error
) {
458 const char *details
[9] = {
463 if (polkit_message
) {
464 details
[4] = "polkit.message";
465 details
[5] = polkit_message
;
466 details
[6] = "polkit.gettext_domain";
467 details
[7] = GETTEXT_PACKAGE
;
470 return bus_verify_polkit_async(
473 "org.freedesktop.systemd1.manage-units",
477 &u
->manager
->polkit_registry
,
481 int bus_unit_method_start_generic(
482 sd_bus_message
*message
,
485 bool reload_if_possible
,
486 sd_bus_error
*error
) {
490 _cleanup_free_
char *verb
= NULL
;
491 static const char *const polkit_message_for_job
[_JOB_TYPE_MAX
] = {
492 [JOB_START
] = N_("Authentication is required to start '$(unit)'."),
493 [JOB_STOP
] = N_("Authentication is required to stop '$(unit)'."),
494 [JOB_RELOAD
] = N_("Authentication is required to reload '$(unit)'."),
495 [JOB_RESTART
] = N_("Authentication is required to restart '$(unit)'."),
496 [JOB_TRY_RESTART
] = N_("Authentication is required to restart '$(unit)'."),
502 assert(job_type
>= 0 && job_type
< _JOB_TYPE_MAX
);
504 r
= mac_selinux_unit_access_check(
506 job_type_to_access_method(job_type
),
511 r
= sd_bus_message_read(message
, "s", &smode
);
515 mode
= job_mode_from_string(smode
);
517 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Job mode %s invalid", smode
);
519 if (reload_if_possible
)
520 verb
= strjoin("reload-or-", job_type_to_string(job_type
));
522 verb
= strdup(job_type_to_string(job_type
));
526 r
= bus_verify_manage_units_async_full(
530 job_type
< _JOB_TYPE_MAX
? polkit_message_for_job
[job_type
] : NULL
,
537 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
539 return bus_unit_queue_job(message
, u
, job_type
, mode
, reload_if_possible
, error
);
542 static int method_start(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
543 return bus_unit_method_start_generic(message
, userdata
, JOB_START
, false, error
);
546 static int method_stop(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
547 return bus_unit_method_start_generic(message
, userdata
, JOB_STOP
, false, error
);
550 static int method_reload(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
551 return bus_unit_method_start_generic(message
, userdata
, JOB_RELOAD
, false, error
);
554 static int method_restart(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
555 return bus_unit_method_start_generic(message
, userdata
, JOB_RESTART
, false, error
);
558 static int method_try_restart(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
559 return bus_unit_method_start_generic(message
, userdata
, JOB_TRY_RESTART
, false, error
);
562 static int method_reload_or_restart(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
563 return bus_unit_method_start_generic(message
, userdata
, JOB_RESTART
, true, error
);
566 static int method_reload_or_try_restart(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
567 return bus_unit_method_start_generic(message
, userdata
, JOB_TRY_RESTART
, true, error
);
570 int bus_unit_method_kill(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
580 r
= mac_selinux_unit_access_check(u
, message
, "stop", error
);
584 r
= sd_bus_message_read(message
, "si", &swho
, &signo
);
591 who
= kill_who_from_string(swho
);
593 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid who argument %s", swho
);
596 if (!SIGNAL_VALID(signo
))
597 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Signal number out of range.");
599 r
= bus_verify_manage_units_async_full(
603 N_("Authentication is required to kill '$(unit)'."),
610 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
612 r
= unit_kill(u
, who
, signo
, error
);
616 return sd_bus_reply_method_return(message
, NULL
);
619 int bus_unit_method_reset_failed(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
626 r
= mac_selinux_unit_access_check(u
, message
, "reload", error
);
630 r
= bus_verify_manage_units_async_full(
634 N_("Authentication is required to reset the \"failed\" state of '$(unit)'."),
641 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
643 unit_reset_failed(u
);
645 return sd_bus_reply_method_return(message
, NULL
);
648 int bus_unit_method_set_properties(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
655 r
= mac_selinux_unit_access_check(u
, message
, "start", error
);
659 r
= sd_bus_message_read(message
, "b", &runtime
);
663 r
= bus_verify_manage_units_async_full(
667 N_("Authentication is required to set properties on '$(unit)'."),
674 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
676 r
= bus_unit_set_properties(u
, message
, runtime
? UNIT_RUNTIME
: UNIT_PERSISTENT
, true, error
);
680 return sd_bus_reply_method_return(message
, NULL
);
683 int bus_unit_method_ref(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
690 r
= mac_selinux_unit_access_check(u
, message
, "start", error
);
694 r
= bus_verify_manage_units_async_full(
705 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
707 r
= bus_unit_track_add_sender(u
, message
);
711 return sd_bus_reply_method_return(message
, NULL
);
714 int bus_unit_method_unref(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
721 r
= bus_unit_track_remove_sender(u
, message
);
723 return sd_bus_error_setf(error
, BUS_ERROR_NOT_REFERENCED
, "Unit has not been referenced yet.");
727 return sd_bus_reply_method_return(message
, NULL
);
730 const sd_bus_vtable bus_unit_vtable
[] = {
731 SD_BUS_VTABLE_START(0),
733 SD_BUS_PROPERTY("Id", "s", NULL
, offsetof(Unit
, id
), SD_BUS_VTABLE_PROPERTY_CONST
),
734 SD_BUS_PROPERTY("Names", "as", property_get_names
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
735 SD_BUS_PROPERTY("Following", "s", property_get_following
, 0, 0),
736 SD_BUS_PROPERTY("Requires", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_REQUIRES
]), SD_BUS_VTABLE_PROPERTY_CONST
),
737 SD_BUS_PROPERTY("Requisite", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_REQUISITE
]), SD_BUS_VTABLE_PROPERTY_CONST
),
738 SD_BUS_PROPERTY("Wants", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_WANTS
]), SD_BUS_VTABLE_PROPERTY_CONST
),
739 SD_BUS_PROPERTY("BindsTo", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_BINDS_TO
]), SD_BUS_VTABLE_PROPERTY_CONST
),
740 SD_BUS_PROPERTY("PartOf", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_PART_OF
]), SD_BUS_VTABLE_PROPERTY_CONST
),
741 SD_BUS_PROPERTY("RequiredBy", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_REQUIRED_BY
]), SD_BUS_VTABLE_PROPERTY_CONST
),
742 SD_BUS_PROPERTY("RequisiteOf", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_REQUISITE_OF
]), SD_BUS_VTABLE_PROPERTY_CONST
),
743 SD_BUS_PROPERTY("WantedBy", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_WANTED_BY
]), SD_BUS_VTABLE_PROPERTY_CONST
),
744 SD_BUS_PROPERTY("BoundBy", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_BOUND_BY
]), SD_BUS_VTABLE_PROPERTY_CONST
),
745 SD_BUS_PROPERTY("ConsistsOf", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_CONSISTS_OF
]), SD_BUS_VTABLE_PROPERTY_CONST
),
746 SD_BUS_PROPERTY("Conflicts", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_CONFLICTS
]), SD_BUS_VTABLE_PROPERTY_CONST
),
747 SD_BUS_PROPERTY("ConflictedBy", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_CONFLICTED_BY
]), SD_BUS_VTABLE_PROPERTY_CONST
),
748 SD_BUS_PROPERTY("Before", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_BEFORE
]), SD_BUS_VTABLE_PROPERTY_CONST
),
749 SD_BUS_PROPERTY("After", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_AFTER
]), SD_BUS_VTABLE_PROPERTY_CONST
),
750 SD_BUS_PROPERTY("OnFailure", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_ON_FAILURE
]), SD_BUS_VTABLE_PROPERTY_CONST
),
751 SD_BUS_PROPERTY("Triggers", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_TRIGGERS
]), SD_BUS_VTABLE_PROPERTY_CONST
),
752 SD_BUS_PROPERTY("TriggeredBy", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_TRIGGERED_BY
]), SD_BUS_VTABLE_PROPERTY_CONST
),
753 SD_BUS_PROPERTY("PropagatesReloadTo", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_PROPAGATES_RELOAD_TO
]), SD_BUS_VTABLE_PROPERTY_CONST
),
754 SD_BUS_PROPERTY("ReloadPropagatedFrom", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_RELOAD_PROPAGATED_FROM
]), SD_BUS_VTABLE_PROPERTY_CONST
),
755 SD_BUS_PROPERTY("JoinsNamespaceOf", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_JOINS_NAMESPACE_OF
]), SD_BUS_VTABLE_PROPERTY_CONST
),
756 SD_BUS_PROPERTY("RequiresMountsFor", "as", property_get_requires_mounts_for
, offsetof(Unit
, requires_mounts_for
), SD_BUS_VTABLE_PROPERTY_CONST
),
757 SD_BUS_PROPERTY("Documentation", "as", NULL
, offsetof(Unit
, documentation
), SD_BUS_VTABLE_PROPERTY_CONST
),
758 SD_BUS_PROPERTY("Description", "s", property_get_description
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
759 SD_BUS_PROPERTY("LoadState", "s", property_get_load_state
, offsetof(Unit
, load_state
), SD_BUS_VTABLE_PROPERTY_CONST
),
760 SD_BUS_PROPERTY("ActiveState", "s", property_get_active_state
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
761 SD_BUS_PROPERTY("SubState", "s", property_get_sub_state
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
762 SD_BUS_PROPERTY("FragmentPath", "s", NULL
, offsetof(Unit
, fragment_path
), SD_BUS_VTABLE_PROPERTY_CONST
),
763 SD_BUS_PROPERTY("SourcePath", "s", NULL
, offsetof(Unit
, source_path
), SD_BUS_VTABLE_PROPERTY_CONST
),
764 SD_BUS_PROPERTY("DropInPaths", "as", NULL
, offsetof(Unit
, dropin_paths
), SD_BUS_VTABLE_PROPERTY_CONST
),
765 SD_BUS_PROPERTY("UnitFileState", "s", property_get_unit_file_state
, 0, 0),
766 SD_BUS_PROPERTY("UnitFilePreset", "s", property_get_unit_file_preset
, 0, 0),
767 BUS_PROPERTY_DUAL_TIMESTAMP("StateChangeTimestamp", offsetof(Unit
, state_change_timestamp
), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
768 BUS_PROPERTY_DUAL_TIMESTAMP("InactiveExitTimestamp", offsetof(Unit
, inactive_exit_timestamp
), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
769 BUS_PROPERTY_DUAL_TIMESTAMP("ActiveEnterTimestamp", offsetof(Unit
, active_enter_timestamp
), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
770 BUS_PROPERTY_DUAL_TIMESTAMP("ActiveExitTimestamp", offsetof(Unit
, active_exit_timestamp
), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
771 BUS_PROPERTY_DUAL_TIMESTAMP("InactiveEnterTimestamp", offsetof(Unit
, inactive_enter_timestamp
), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
772 SD_BUS_PROPERTY("CanStart", "b", property_get_can_start
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
773 SD_BUS_PROPERTY("CanStop", "b", property_get_can_stop
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
774 SD_BUS_PROPERTY("CanReload", "b", property_get_can_reload
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
775 SD_BUS_PROPERTY("CanIsolate", "b", property_get_can_isolate
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
776 SD_BUS_PROPERTY("Job", "(uo)", property_get_job
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
777 SD_BUS_PROPERTY("StopWhenUnneeded", "b", bus_property_get_bool
, offsetof(Unit
, stop_when_unneeded
), SD_BUS_VTABLE_PROPERTY_CONST
),
778 SD_BUS_PROPERTY("RefuseManualStart", "b", bus_property_get_bool
, offsetof(Unit
, refuse_manual_start
), SD_BUS_VTABLE_PROPERTY_CONST
),
779 SD_BUS_PROPERTY("RefuseManualStop", "b", bus_property_get_bool
, offsetof(Unit
, refuse_manual_stop
), SD_BUS_VTABLE_PROPERTY_CONST
),
780 SD_BUS_PROPERTY("AllowIsolate", "b", bus_property_get_bool
, offsetof(Unit
, allow_isolate
), SD_BUS_VTABLE_PROPERTY_CONST
),
781 SD_BUS_PROPERTY("DefaultDependencies", "b", bus_property_get_bool
, offsetof(Unit
, default_dependencies
), SD_BUS_VTABLE_PROPERTY_CONST
),
782 SD_BUS_PROPERTY("OnFailureJobMode", "s", property_get_job_mode
, offsetof(Unit
, on_failure_job_mode
), SD_BUS_VTABLE_PROPERTY_CONST
),
783 SD_BUS_PROPERTY("IgnoreOnIsolate", "b", bus_property_get_bool
, offsetof(Unit
, ignore_on_isolate
), SD_BUS_VTABLE_PROPERTY_CONST
),
784 SD_BUS_PROPERTY("NeedDaemonReload", "b", property_get_need_daemon_reload
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
785 SD_BUS_PROPERTY("JobTimeoutUSec", "t", bus_property_get_usec
, offsetof(Unit
, job_timeout
), SD_BUS_VTABLE_PROPERTY_CONST
),
786 SD_BUS_PROPERTY("JobRunningTimeoutUSec", "t", bus_property_get_usec
, offsetof(Unit
, job_running_timeout
), SD_BUS_VTABLE_PROPERTY_CONST
),
787 SD_BUS_PROPERTY("JobTimeoutAction", "s", property_get_emergency_action
, offsetof(Unit
, job_timeout_action
), SD_BUS_VTABLE_PROPERTY_CONST
),
788 SD_BUS_PROPERTY("JobTimeoutRebootArgument", "s", NULL
, offsetof(Unit
, job_timeout_reboot_arg
), SD_BUS_VTABLE_PROPERTY_CONST
),
789 SD_BUS_PROPERTY("ConditionResult", "b", bus_property_get_bool
, offsetof(Unit
, condition_result
), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
790 SD_BUS_PROPERTY("AssertResult", "b", bus_property_get_bool
, offsetof(Unit
, assert_result
), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
791 BUS_PROPERTY_DUAL_TIMESTAMP("ConditionTimestamp", offsetof(Unit
, condition_timestamp
), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
792 BUS_PROPERTY_DUAL_TIMESTAMP("AssertTimestamp", offsetof(Unit
, assert_timestamp
), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
793 SD_BUS_PROPERTY("Conditions", "a(sbbsi)", property_get_conditions
, offsetof(Unit
, conditions
), 0),
794 SD_BUS_PROPERTY("Asserts", "a(sbbsi)", property_get_conditions
, offsetof(Unit
, asserts
), 0),
795 SD_BUS_PROPERTY("LoadError", "(ss)", property_get_load_error
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
796 SD_BUS_PROPERTY("Transient", "b", bus_property_get_bool
, offsetof(Unit
, transient
), SD_BUS_VTABLE_PROPERTY_CONST
),
797 SD_BUS_PROPERTY("Perpetual", "b", bus_property_get_bool
, offsetof(Unit
, perpetual
), SD_BUS_VTABLE_PROPERTY_CONST
),
798 SD_BUS_PROPERTY("StartLimitIntervalSec", "t", bus_property_get_usec
, offsetof(Unit
, start_limit
.interval
), SD_BUS_VTABLE_PROPERTY_CONST
),
799 SD_BUS_PROPERTY("StartLimitBurst", "u", bus_property_get_unsigned
, offsetof(Unit
, start_limit
.burst
), SD_BUS_VTABLE_PROPERTY_CONST
),
800 SD_BUS_PROPERTY("StartLimitAction", "s", property_get_emergency_action
, offsetof(Unit
, start_limit_action
), SD_BUS_VTABLE_PROPERTY_CONST
),
801 SD_BUS_PROPERTY("FailureAction", "s", property_get_emergency_action
, offsetof(Unit
, failure_action
), SD_BUS_VTABLE_PROPERTY_CONST
),
802 SD_BUS_PROPERTY("SuccessAction", "s", property_get_emergency_action
, offsetof(Unit
, success_action
), SD_BUS_VTABLE_PROPERTY_CONST
),
803 SD_BUS_PROPERTY("RebootArgument", "s", NULL
, offsetof(Unit
, reboot_arg
), SD_BUS_VTABLE_PROPERTY_CONST
),
804 SD_BUS_PROPERTY("InvocationID", "ay", bus_property_get_id128
, offsetof(Unit
, invocation_id
), 0),
805 SD_BUS_PROPERTY("CollectMode", "s", property_get_collect_mode
, offsetof(Unit
, collect_mode
), 0),
807 SD_BUS_METHOD("Start", "s", "o", method_start
, SD_BUS_VTABLE_UNPRIVILEGED
),
808 SD_BUS_METHOD("Stop", "s", "o", method_stop
, SD_BUS_VTABLE_UNPRIVILEGED
),
809 SD_BUS_METHOD("Reload", "s", "o", method_reload
, SD_BUS_VTABLE_UNPRIVILEGED
),
810 SD_BUS_METHOD("Restart", "s", "o", method_restart
, SD_BUS_VTABLE_UNPRIVILEGED
),
811 SD_BUS_METHOD("TryRestart", "s", "o", method_try_restart
, SD_BUS_VTABLE_UNPRIVILEGED
),
812 SD_BUS_METHOD("ReloadOrRestart", "s", "o", method_reload_or_restart
, SD_BUS_VTABLE_UNPRIVILEGED
),
813 SD_BUS_METHOD("ReloadOrTryRestart", "s", "o", method_reload_or_try_restart
, SD_BUS_VTABLE_UNPRIVILEGED
),
814 SD_BUS_METHOD("Kill", "si", NULL
, bus_unit_method_kill
, SD_BUS_VTABLE_UNPRIVILEGED
),
815 SD_BUS_METHOD("ResetFailed", NULL
, NULL
, bus_unit_method_reset_failed
, SD_BUS_VTABLE_UNPRIVILEGED
),
816 SD_BUS_METHOD("SetProperties", "ba(sv)", NULL
, bus_unit_method_set_properties
, SD_BUS_VTABLE_UNPRIVILEGED
),
817 SD_BUS_METHOD("Ref", NULL
, NULL
, bus_unit_method_ref
, SD_BUS_VTABLE_UNPRIVILEGED
),
818 SD_BUS_METHOD("Unref", NULL
, NULL
, bus_unit_method_unref
, SD_BUS_VTABLE_UNPRIVILEGED
),
820 /* Obsolete properties or obsolete alias names */
821 SD_BUS_PROPERTY("RequiresOverridable", "as", property_get_obsolete_dependencies
, 0, SD_BUS_VTABLE_HIDDEN
),
822 SD_BUS_PROPERTY("RequisiteOverridable", "as", property_get_obsolete_dependencies
, 0, SD_BUS_VTABLE_HIDDEN
),
823 SD_BUS_PROPERTY("RequiredByOverridable", "as", property_get_obsolete_dependencies
, 0, SD_BUS_VTABLE_HIDDEN
),
824 SD_BUS_PROPERTY("RequisiteOfOverridable", "as", property_get_obsolete_dependencies
, 0, SD_BUS_VTABLE_HIDDEN
),
825 SD_BUS_PROPERTY("StartLimitInterval", "t", bus_property_get_usec
, offsetof(Unit
, start_limit
.interval
), SD_BUS_VTABLE_PROPERTY_CONST
|SD_BUS_VTABLE_HIDDEN
),
829 static int property_get_slice(
832 const char *interface
,
833 const char *property
,
834 sd_bus_message
*reply
,
836 sd_bus_error
*error
) {
844 return sd_bus_message_append(reply
, "s", unit_slice_name(u
));
847 static int property_get_current_memory(
850 const char *interface
,
851 const char *property
,
852 sd_bus_message
*reply
,
854 sd_bus_error
*error
) {
856 uint64_t sz
= (uint64_t) -1;
864 r
= unit_get_memory_current(u
, &sz
);
865 if (r
< 0 && r
!= -ENODATA
)
866 log_unit_warning_errno(u
, r
, "Failed to get memory.usage_in_bytes attribute: %m");
868 return sd_bus_message_append(reply
, "t", sz
);
871 static int property_get_current_tasks(
874 const char *interface
,
875 const char *property
,
876 sd_bus_message
*reply
,
878 sd_bus_error
*error
) {
880 uint64_t cn
= (uint64_t) -1;
888 r
= unit_get_tasks_current(u
, &cn
);
889 if (r
< 0 && r
!= -ENODATA
)
890 log_unit_warning_errno(u
, r
, "Failed to get pids.current attribute: %m");
892 return sd_bus_message_append(reply
, "t", cn
);
895 static int property_get_cpu_usage(
898 const char *interface
,
899 const char *property
,
900 sd_bus_message
*reply
,
902 sd_bus_error
*error
) {
904 nsec_t ns
= (nsec_t
) -1;
912 r
= unit_get_cpu_usage(u
, &ns
);
913 if (r
< 0 && r
!= -ENODATA
)
914 log_unit_warning_errno(u
, r
, "Failed to get cpuacct.usage attribute: %m");
916 return sd_bus_message_append(reply
, "t", ns
);
919 static int property_get_cgroup(
922 const char *interface
,
923 const char *property
,
924 sd_bus_message
*reply
,
926 sd_bus_error
*error
) {
935 /* Three cases: a) u->cgroup_path is NULL, in which case the
936 * unit has no control group, which we report as the empty
937 * string. b) u->cgroup_path is the empty string, which
938 * indicates the root cgroup, which we report as "/". c) all
939 * other cases we report as-is. */
942 t
= isempty(u
->cgroup_path
) ? "/" : u
->cgroup_path
;
946 return sd_bus_message_append(reply
, "s", t
);
949 static int append_process(sd_bus_message
*reply
, const char *p
, pid_t pid
, Set
*pids
) {
950 _cleanup_free_
char *buf
= NULL
, *cmdline
= NULL
;
956 r
= set_put(pids
, PID_TO_PTR(pid
));
957 if (IN_SET(r
, 0, -EEXIST
))
963 r
= cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER
, pid
, &buf
);
972 (void) get_process_cmdline(pid
, 0, true, &cmdline
);
974 return sd_bus_message_append(reply
,
981 static int append_cgroup(sd_bus_message
*reply
, const char *p
, Set
*pids
) {
982 _cleanup_closedir_
DIR *d
= NULL
;
983 _cleanup_fclose_
FILE *f
= NULL
;
989 r
= cg_enumerate_processes(SYSTEMD_CGROUP_CONTROLLER
, p
, &f
);
998 r
= cg_read_pid(f
, &pid
);
1004 if (is_kernel_thread(pid
) > 0)
1007 r
= append_process(reply
, p
, pid
, pids
);
1012 r
= cg_enumerate_subgroups(SYSTEMD_CGROUP_CONTROLLER
, p
, &d
);
1019 _cleanup_free_
char *g
= NULL
, *j
= NULL
;
1021 r
= cg_read_subgroup(d
, &g
);
1027 j
= strjoin(p
, "/", g
);
1031 r
= append_cgroup(reply
, j
, pids
);
1039 int bus_unit_method_get_processes(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1040 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
1041 _cleanup_(set_freep
) Set
*pids
= NULL
;
1048 r
= mac_selinux_unit_access_check(u
, message
, "status", error
);
1052 pids
= set_new(NULL
);
1056 r
= sd_bus_message_new_method_return(message
, &reply
);
1060 r
= sd_bus_message_open_container(reply
, 'a', "(sus)");
1064 if (u
->cgroup_path
) {
1065 r
= append_cgroup(reply
, u
->cgroup_path
, pids
);
1070 /* The main and control pids might live outside of the cgroup, hence fetch them separately */
1071 pid
= unit_main_pid(u
);
1073 r
= append_process(reply
, NULL
, pid
, pids
);
1078 pid
= unit_control_pid(u
);
1080 r
= append_process(reply
, NULL
, pid
, pids
);
1085 r
= sd_bus_message_close_container(reply
);
1089 return sd_bus_send(NULL
, reply
, NULL
);
1092 static int property_get_ip_counter(
1095 const char *interface
,
1096 const char *property
,
1097 sd_bus_message
*reply
,
1099 sd_bus_error
*error
) {
1101 CGroupIPAccountingMetric metric
;
1102 uint64_t value
= (uint64_t) -1;
1110 if (streq(property
, "IPIngressBytes"))
1111 metric
= CGROUP_IP_INGRESS_BYTES
;
1112 else if (streq(property
, "IPIngressPackets"))
1113 metric
= CGROUP_IP_INGRESS_PACKETS
;
1114 else if (streq(property
, "IPEgressBytes"))
1115 metric
= CGROUP_IP_EGRESS_BYTES
;
1117 assert(streq(property
, "IPEgressPackets"));
1118 metric
= CGROUP_IP_EGRESS_PACKETS
;
1121 (void) unit_get_ip_accounting(u
, metric
, &value
);
1122 return sd_bus_message_append(reply
, "t", value
);
1125 const sd_bus_vtable bus_unit_cgroup_vtable
[] = {
1126 SD_BUS_VTABLE_START(0),
1127 SD_BUS_PROPERTY("Slice", "s", property_get_slice
, 0, 0),
1128 SD_BUS_PROPERTY("ControlGroup", "s", property_get_cgroup
, 0, 0),
1129 SD_BUS_PROPERTY("MemoryCurrent", "t", property_get_current_memory
, 0, 0),
1130 SD_BUS_PROPERTY("CPUUsageNSec", "t", property_get_cpu_usage
, 0, 0),
1131 SD_BUS_PROPERTY("TasksCurrent", "t", property_get_current_tasks
, 0, 0),
1132 SD_BUS_PROPERTY("IPIngressBytes", "t", property_get_ip_counter
, 0, 0),
1133 SD_BUS_PROPERTY("IPIngressPackets", "t", property_get_ip_counter
, 0, 0),
1134 SD_BUS_PROPERTY("IPEgressBytes", "t", property_get_ip_counter
, 0, 0),
1135 SD_BUS_PROPERTY("IPEgressPackets", "t", property_get_ip_counter
, 0, 0),
1136 SD_BUS_METHOD("GetProcesses", NULL
, "a(sus)", bus_unit_method_get_processes
, SD_BUS_VTABLE_UNPRIVILEGED
),
1140 static int send_new_signal(sd_bus
*bus
, void *userdata
) {
1141 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
;
1142 _cleanup_free_
char *p
= NULL
;
1149 p
= unit_dbus_path(u
);
1153 r
= sd_bus_message_new_signal(
1156 "/org/freedesktop/systemd1",
1157 "org.freedesktop.systemd1.Manager",
1162 r
= sd_bus_message_append(m
, "so", u
->id
, p
);
1166 return sd_bus_send(bus
, m
, NULL
);
1169 static int send_changed_signal(sd_bus
*bus
, void *userdata
) {
1170 _cleanup_free_
char *p
= NULL
;
1177 p
= unit_dbus_path(u
);
1181 /* Send a properties changed signal. First for the specific
1182 * type, then for the generic unit. The clients may rely on
1183 * this order to get atomic behavior if needed. */
1185 r
= sd_bus_emit_properties_changed_strv(
1187 unit_dbus_interface_from_type(u
->type
),
1192 return sd_bus_emit_properties_changed_strv(
1194 "org.freedesktop.systemd1.Unit",
1198 void bus_unit_send_change_signal(Unit
*u
) {
1202 if (u
->in_dbus_queue
) {
1203 LIST_REMOVE(dbus_queue
, u
->manager
->dbus_unit_queue
, u
);
1204 u
->in_dbus_queue
= false;
1210 r
= bus_foreach_bus(u
->manager
, u
->bus_track
, u
->sent_dbus_new_signal
? send_changed_signal
: send_new_signal
, u
);
1212 log_unit_debug_errno(u
, r
, "Failed to send unit change signal for %s: %m", u
->id
);
1214 u
->sent_dbus_new_signal
= true;
1217 static int send_removed_signal(sd_bus
*bus
, void *userdata
) {
1218 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
;
1219 _cleanup_free_
char *p
= NULL
;
1226 p
= unit_dbus_path(u
);
1230 r
= sd_bus_message_new_signal(
1233 "/org/freedesktop/systemd1",
1234 "org.freedesktop.systemd1.Manager",
1239 r
= sd_bus_message_append(m
, "so", u
->id
, p
);
1243 return sd_bus_send(bus
, m
, NULL
);
1246 void bus_unit_send_removed_signal(Unit
*u
) {
1250 if (!u
->sent_dbus_new_signal
|| u
->in_dbus_queue
)
1251 bus_unit_send_change_signal(u
);
1256 r
= bus_foreach_bus(u
->manager
, u
->bus_track
, send_removed_signal
, u
);
1258 log_unit_debug_errno(u
, r
, "Failed to send unit remove signal for %s: %m", u
->id
);
1261 int bus_unit_queue_job(
1262 sd_bus_message
*message
,
1266 bool reload_if_possible
,
1267 sd_bus_error
*error
) {
1269 _cleanup_free_
char *path
= NULL
;
1275 assert(type
>= 0 && type
< _JOB_TYPE_MAX
);
1276 assert(mode
>= 0 && mode
< _JOB_MODE_MAX
);
1278 r
= mac_selinux_unit_access_check(
1280 job_type_to_access_method(type
),
1285 if (reload_if_possible
&& unit_can_reload(u
)) {
1286 if (type
== JOB_RESTART
)
1287 type
= JOB_RELOAD_OR_START
;
1288 else if (type
== JOB_TRY_RESTART
)
1289 type
= JOB_TRY_RELOAD
;
1292 if (type
== JOB_STOP
&&
1293 (IN_SET(u
->load_state
, UNIT_NOT_FOUND
, UNIT_ERROR
)) &&
1294 unit_active_state(u
) == UNIT_INACTIVE
)
1295 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_UNIT
, "Unit %s not loaded.", u
->id
);
1297 if ((type
== JOB_START
&& u
->refuse_manual_start
) ||
1298 (type
== JOB_STOP
&& u
->refuse_manual_stop
) ||
1299 (IN_SET(type
, JOB_RESTART
, JOB_TRY_RESTART
) && (u
->refuse_manual_start
|| u
->refuse_manual_stop
)) ||
1300 (type
== JOB_RELOAD_OR_START
&& job_type_collapse(type
, u
) == JOB_START
&& u
->refuse_manual_start
))
1301 return sd_bus_error_setf(error
, BUS_ERROR_ONLY_BY_DEPENDENCY
, "Operation refused, unit %s may be requested by dependency only (it is configured to refuse manual start/stop).", u
->id
);
1303 r
= manager_add_job(u
->manager
, type
, u
, mode
, error
, &j
);
1307 r
= bus_job_track_sender(j
, message
);
1311 path
= job_dbus_path(j
);
1315 return sd_bus_reply_method_return(message
, "o", path
);
1318 static int bus_unit_set_live_property(
1321 sd_bus_message
*message
,
1322 UnitWriteFlags flags
,
1323 sd_bus_error
*error
) {
1331 /* Handles setting properties both "live" (i.e. at any time during runtime), and during creation (for transient
1332 * units that are being created). */
1334 if (streq(name
, "Description")) {
1337 r
= sd_bus_message_read(message
, "s", &d
);
1341 if (!UNIT_WRITE_FLAGS_NOOP(flags
)) {
1342 r
= unit_set_description(u
, d
);
1346 unit_write_settingf(u
, flags
|UNIT_ESCAPE_SPECIFIERS
, name
, "Description=%s", d
);
1355 static int bus_unit_set_transient_property(
1358 sd_bus_message
*message
,
1359 UnitWriteFlags flags
,
1360 sd_bus_error
*error
) {
1368 /* Handles settings when transient units are created. This settings cannot be altered anymore after the unit
1369 * has been created. */
1371 if (streq(name
, "DefaultDependencies")) {
1374 r
= sd_bus_message_read(message
, "b", &b
);
1378 if (!UNIT_WRITE_FLAGS_NOOP(flags
)) {
1379 u
->default_dependencies
= b
;
1380 unit_write_settingf(u
, flags
, name
, "DefaultDependencies=%s", yes_no(b
));
1385 } else if (streq(name
, "CollectMode")) {
1389 r
= sd_bus_message_read(message
, "s", &s
);
1393 m
= collect_mode_from_string(s
);
1395 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Unknown garbage collection mode: %s", s
);
1397 if (!UNIT_WRITE_FLAGS_NOOP(flags
)) {
1398 u
->collect_mode
= m
;
1399 unit_write_settingf(u
, flags
, name
, "CollectMode=%s", collect_mode_to_string(m
));
1404 } else if (streq(name
, "Slice")) {
1408 if (!UNIT_HAS_CGROUP_CONTEXT(u
))
1409 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "The slice property is only available for units with control groups.");
1410 if (u
->type
== UNIT_SLICE
)
1411 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Slice may not be set for slice units.");
1412 if (unit_has_name(u
, SPECIAL_INIT_SCOPE
))
1413 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Cannot set slice for init.scope");
1415 r
= sd_bus_message_read(message
, "s", &s
);
1419 if (!unit_name_is_valid(s
, UNIT_NAME_PLAIN
))
1420 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid unit name '%s'", s
);
1422 /* Note that we do not dispatch the load queue here yet, as we don't want our own transient unit to be
1423 * loaded while we are still setting it up. Or in other words, we use manager_load_unit_prepare()
1424 * instead of manager_load_unit() on purpose, here. */
1425 r
= manager_load_unit_prepare(u
->manager
, s
, NULL
, error
, &slice
);
1429 if (slice
->type
!= UNIT_SLICE
)
1430 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Unit name '%s' is not a slice", s
);
1432 if (!UNIT_WRITE_FLAGS_NOOP(flags
)) {
1433 r
= unit_set_slice(u
, slice
);
1437 unit_write_settingf(u
, flags
|UNIT_PRIVATE
, name
, "Slice=%s", s
);
1442 } else if (STR_IN_SET(name
,
1443 "Requires", "RequiresOverridable",
1444 "Requisite", "RequisiteOverridable",
1450 "PropagatesReloadTo", "ReloadPropagatedFrom",
1456 if (streq(name
, "RequiresOverridable"))
1457 d
= UNIT_REQUIRES
; /* redirect for obsolete unit dependency type */
1458 else if (streq(name
, "RequisiteOverridable"))
1459 d
= UNIT_REQUISITE
; /* same here */
1461 d
= unit_dependency_from_string(name
);
1463 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid unit dependency: %s", name
);
1466 r
= sd_bus_message_enter_container(message
, 'a', "s");
1470 while ((r
= sd_bus_message_read(message
, "s", &other
)) > 0) {
1471 if (!unit_name_is_valid(other
, UNIT_NAME_PLAIN
|UNIT_NAME_INSTANCE
))
1472 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid unit name %s", other
);
1474 if (!UNIT_WRITE_FLAGS_NOOP(flags
)) {
1475 _cleanup_free_
char *label
= NULL
;
1477 r
= unit_add_dependency_by_name(u
, d
, other
, NULL
, true, UNIT_DEPENDENCY_FILE
);
1481 label
= strjoin(name
, "-", other
);
1485 unit_write_settingf(u
, flags
, label
, "%s=%s", name
, other
);
1492 r
= sd_bus_message_exit_container(message
);
1498 } else if (STR_IN_SET(name
, "FailureAction", "SuccessAction")) {
1499 EmergencyAction action
;
1502 r
= sd_bus_message_read(message
, "s", &s
);
1506 action
= emergency_action_from_string(s
);
1508 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid emergency action: %s", s
);
1510 if (!UNIT_WRITE_FLAGS_NOOP(flags
)) {
1512 if (streq(name
, "FailureAction"))
1513 u
->failure_action
= action
;
1515 u
->success_action
= action
;
1517 unit_write_settingf(u
, flags
, name
, "%s=%s", name
, emergency_action_to_string(action
));
1522 } else if (streq(name
, "AddRef")) {
1526 /* Why is this called "AddRef" rather than just "Ref", or "Reference"? There's already a "Ref()" method
1527 * on the Unit interface, and it's probably not a good idea to expose a property and a method on the
1528 * same interface (well, strictly speaking AddRef isn't exposed as full property, we just read it for
1529 * transient units, but still). And "References" and "ReferencedBy" is already used as unit reference
1530 * dependency type, hence let's not confuse things with that.
1532 * Note that we don't acually add the reference to the bus track. We do that only after the setup of
1533 * the transient unit is complete, so that setting this property multiple times in the same transient
1534 * unit creation call doesn't count as individual references. */
1536 r
= sd_bus_message_read(message
, "b", &b
);
1540 if (!UNIT_WRITE_FLAGS_NOOP(flags
))
1541 u
->bus_track_add
= b
;
1549 int bus_unit_set_properties(
1551 sd_bus_message
*message
,
1552 UnitWriteFlags flags
,
1554 sd_bus_error
*error
) {
1556 bool for_real
= false;
1563 /* We iterate through the array twice. First run we just check
1564 * if all passed data is valid, second run actually applies
1565 * it. This is to implement transaction-like behaviour without
1566 * actually providing full transactions. */
1568 r
= sd_bus_message_enter_container(message
, 'a', "(sv)");
1576 r
= sd_bus_message_enter_container(message
, 'r', "sv");
1580 if (for_real
|| UNIT_WRITE_FLAGS_NOOP(flags
))
1583 /* Reached EOF. Let's try again, and this time for realz... */
1584 r
= sd_bus_message_rewind(message
, false);
1592 r
= sd_bus_message_read(message
, "s", &name
);
1596 if (!UNIT_VTABLE(u
)->bus_set_property
)
1597 return sd_bus_error_setf(error
, SD_BUS_ERROR_PROPERTY_READ_ONLY
, "Objects of this type do not support setting properties.");
1599 r
= sd_bus_message_enter_container(message
, 'v', NULL
);
1603 /* If not for real, then mask out the two target flags */
1604 f
= for_real
? flags
: (flags
& ~(UNIT_RUNTIME
|UNIT_PERSISTENT
));
1606 r
= UNIT_VTABLE(u
)->bus_set_property(u
, name
, message
, f
, error
);
1607 if (r
== 0 && u
->transient
&& u
->load_state
== UNIT_STUB
)
1608 r
= bus_unit_set_transient_property(u
, name
, message
, f
, error
);
1610 r
= bus_unit_set_live_property(u
, name
, message
, f
, error
);
1615 return sd_bus_error_setf(error
, SD_BUS_ERROR_PROPERTY_READ_ONLY
, "Cannot set property %s, or unknown property.", name
);
1617 r
= sd_bus_message_exit_container(message
);
1621 r
= sd_bus_message_exit_container(message
);
1628 r
= sd_bus_message_exit_container(message
);
1632 if (commit
&& n
> 0 && UNIT_VTABLE(u
)->bus_commit_properties
)
1633 UNIT_VTABLE(u
)->bus_commit_properties(u
);
1638 int bus_unit_check_load_state(Unit
*u
, sd_bus_error
*error
) {
1641 if (u
->load_state
== UNIT_LOADED
)
1644 /* Give a better description of the unit error when
1645 * possible. Note that in the case of UNIT_MASKED, load_error
1647 if (u
->load_state
== UNIT_MASKED
)
1648 return sd_bus_error_setf(error
, BUS_ERROR_UNIT_MASKED
, "Unit %s is masked.", u
->id
);
1650 if (u
->load_state
== UNIT_NOT_FOUND
)
1651 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_UNIT
, "Unit %s not found.", u
->id
);
1653 return sd_bus_error_set_errnof(error
, u
->load_error
, "Unit %s is not loaded properly: %m.", u
->id
);
1656 static int bus_unit_track_handler(sd_bus_track
*t
, void *userdata
) {
1662 u
->bus_track
= sd_bus_track_unref(u
->bus_track
); /* make sure we aren't called again */
1664 unit_add_to_gc_queue(u
);
1668 static int bus_unit_allocate_bus_track(Unit
*u
) {
1676 r
= sd_bus_track_new(u
->manager
->api_bus
, &u
->bus_track
, bus_unit_track_handler
, u
);
1680 r
= sd_bus_track_set_recursive(u
->bus_track
, true);
1682 u
->bus_track
= sd_bus_track_unref(u
->bus_track
);
1689 int bus_unit_track_add_name(Unit
*u
, const char *name
) {
1694 r
= bus_unit_allocate_bus_track(u
);
1698 return sd_bus_track_add_name(u
->bus_track
, name
);
1701 int bus_unit_track_add_sender(Unit
*u
, sd_bus_message
*m
) {
1706 r
= bus_unit_allocate_bus_track(u
);
1710 return sd_bus_track_add_sender(u
->bus_track
, m
);
1713 int bus_unit_track_remove_sender(Unit
*u
, sd_bus_message
*m
) {
1716 /* If we haven't allocated the bus track object yet, then there's definitely no reference taken yet, return an
1721 return sd_bus_track_remove_sender(u
->bus_track
, m
);