1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 #include <sys/reboot.h>
9 #include "bus-common-errors.h"
10 #include "bus-locator.h"
11 #include "bus-map-properties.h"
12 #include "bus-unit-util.h"
15 #include "exit-status.h"
17 #include "glob-util.h"
19 #include "path-util.h"
20 #include "reboot-util.h"
22 #include "spawn-ask-password-agent.h"
23 #include "spawn-polkit-agent.h"
24 #include "stat-util.h"
25 #include "systemctl-util.h"
26 #include "systemctl.h"
27 #include "terminal-util.h"
30 static sd_bus
*buses
[_BUS_FOCUS_MAX
] = {};
32 int acquire_bus(BusFocus focus
, sd_bus
**ret
) {
35 assert(focus
< _BUS_FOCUS_MAX
);
38 /* We only go directly to the manager, if we are using a local transport */
39 if (arg_transport
!= BUS_TRANSPORT_LOCAL
)
42 if (getenv_bool("SYSTEMCTL_FORCE_BUS") > 0)
48 user
= arg_scope
!= UNIT_FILE_SYSTEM
;
50 if (focus
== BUS_MANAGER
)
51 r
= bus_connect_transport_systemd(arg_transport
, arg_host
, user
, &buses
[focus
]);
53 r
= bus_connect_transport(arg_transport
, arg_host
, user
, &buses
[focus
]);
55 return bus_log_connect_error(r
);
57 (void) sd_bus_set_allow_interactive_authorization(buses
[focus
], arg_ask_password
);
64 void release_busses(void) {
67 for (w
= 0; w
< _BUS_FOCUS_MAX
; w
++)
68 buses
[w
] = sd_bus_flush_close_unref(buses
[w
]);
71 void ask_password_agent_open_maybe(void) {
72 /* Open the password agent as a child process if necessary */
77 if (arg_scope
!= UNIT_FILE_SYSTEM
)
80 ask_password_agent_open_if_enabled(arg_transport
, arg_ask_password
);
83 void polkit_agent_open_maybe(void) {
84 /* Open the polkit agent as a child process if necessary */
86 if (arg_scope
!= UNIT_FILE_SYSTEM
)
89 polkit_agent_open_if_enabled(arg_transport
, arg_ask_password
);
92 int translate_bus_error_to_exit_status(int r
, const sd_bus_error
*error
) {
95 if (!sd_bus_error_is_set(error
))
98 if (sd_bus_error_has_names(error
, SD_BUS_ERROR_ACCESS_DENIED
,
99 BUS_ERROR_ONLY_BY_DEPENDENCY
,
100 BUS_ERROR_NO_ISOLATION
,
101 BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE
))
102 return EXIT_NOPERMISSION
;
104 if (sd_bus_error_has_name(error
, BUS_ERROR_NO_SUCH_UNIT
))
105 return EXIT_NOTINSTALLED
;
107 if (sd_bus_error_has_names(error
, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE
,
108 SD_BUS_ERROR_NOT_SUPPORTED
))
109 return EXIT_NOTIMPLEMENTED
;
111 if (sd_bus_error_has_name(error
, BUS_ERROR_LOAD_FAILED
))
112 return EXIT_NOTCONFIGURED
;
120 int get_state_one_unit(sd_bus
*bus
, const char *unit
, UnitActiveState
*ret_active_state
) {
121 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
122 _cleanup_free_
char *buf
= NULL
, *dbus_path
= NULL
;
123 UnitActiveState state
;
127 assert(ret_active_state
);
129 dbus_path
= unit_dbus_path_from_name(unit
);
133 r
= sd_bus_get_property_string(
135 "org.freedesktop.systemd1",
137 "org.freedesktop.systemd1.Unit",
142 return log_error_errno(r
, "Failed to retrieve unit state: %s", bus_error_message(&error
, r
));
144 state
= unit_active_state_from_string(buf
);
146 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Invalid unit state '%s' for: %s", buf
, unit
);
148 *ret_active_state
= state
;
156 UnitInfo
**unit_infos
,
158 sd_bus_message
**ret_reply
) {
160 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
;
161 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
162 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
165 bool fallback
= false;
171 r
= bus_message_new_method_call(bus
, &m
, bus_systemd_mgr
, "ListUnitsByPatterns");
173 return bus_log_create_error(r
);
175 r
= sd_bus_message_append_strv(m
, arg_states
);
177 return bus_log_create_error(r
);
179 r
= sd_bus_message_append_strv(m
, patterns
);
181 return bus_log_create_error(r
);
183 r
= sd_bus_call(bus
, m
, 0, &error
, &reply
);
184 if (r
< 0 && (sd_bus_error_has_names(&error
, SD_BUS_ERROR_UNKNOWN_METHOD
,
185 SD_BUS_ERROR_ACCESS_DENIED
))) {
186 /* Fallback to legacy ListUnitsFiltered method */
188 log_debug_errno(r
, "Failed to list units: %s Falling back to ListUnitsFiltered method.", bus_error_message(&error
, r
));
189 m
= sd_bus_message_unref(m
);
190 sd_bus_error_free(&error
);
192 r
= bus_message_new_method_call(bus
, &m
, bus_systemd_mgr
, "ListUnitsFiltered");
194 return bus_log_create_error(r
);
196 r
= sd_bus_message_append_strv(m
, arg_states
);
198 return bus_log_create_error(r
);
200 r
= sd_bus_call(bus
, m
, 0, &error
, &reply
);
203 return log_error_errno(r
, "Failed to list units: %s", bus_error_message(&error
, r
));
205 r
= sd_bus_message_enter_container(reply
, SD_BUS_TYPE_ARRAY
, "(ssssssouso)");
207 return bus_log_parse_error(r
);
212 r
= bus_parse_unit_info(reply
, &u
);
214 return bus_log_parse_error(r
);
220 if (!output_show_unit(&u
, fallback
? patterns
: NULL
))
223 if (!GREEDY_REALLOC(*unit_infos
, size
, c
+1))
226 (*unit_infos
)[c
++] = u
;
229 r
= sd_bus_message_exit_container(reply
);
231 return bus_log_parse_error(r
);
233 *ret_reply
= TAKE_PTR(reply
);
237 int expand_unit_names(sd_bus
*bus
, char **names
, const char* suffix
, char ***ret
, bool *ret_expanded
) {
238 _cleanup_strv_free_
char **mangled
= NULL
, **globs
= NULL
;
245 STRV_FOREACH(name
, names
) {
246 UnitNameMangle options
= UNIT_NAME_MANGLE_GLOB
| (arg_quiet
? 0 : UNIT_NAME_MANGLE_WARN
);
249 r
= unit_name_mangle_with_suffix(*name
, NULL
, options
, suffix
?: ".service", &t
);
251 return log_error_errno(r
, "Failed to mangle name: %m");
253 if (string_is_glob(t
))
254 r
= strv_consume(&globs
, t
);
256 r
= strv_consume(&mangled
, t
);
261 /* Query the manager only if any of the names are a glob, since this is fairly expensive */
262 bool expanded
= !strv_isempty(globs
);
264 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
265 _cleanup_free_ UnitInfo
*unit_infos
= NULL
;
268 r
= get_unit_list(bus
, NULL
, globs
, &unit_infos
, 0, &reply
);
272 n
= strv_length(mangled
);
275 for (i
= 0; i
< r
; i
++) {
276 if (!GREEDY_REALLOC(mangled
, allocated
, n
+2))
279 mangled
[n
] = strdup(unit_infos
[i
].id
);
288 *ret_expanded
= expanded
;
290 *ret
= TAKE_PTR(mangled
);
294 int check_triggering_units(sd_bus
*bus
, const char *unit
) {
295 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
296 _cleanup_free_
char *n
= NULL
, *dbus_path
= NULL
, *load_state
= NULL
;
297 _cleanup_strv_free_
char **triggered_by
= NULL
;
298 bool print_warning_label
= true;
299 UnitActiveState active_state
;
303 r
= unit_name_mangle(unit
, 0, &n
);
305 return log_error_errno(r
, "Failed to mangle unit name: %m");
307 r
= unit_load_state(bus
, n
, &load_state
);
311 if (streq(load_state
, "masked"))
314 dbus_path
= unit_dbus_path_from_name(n
);
318 r
= sd_bus_get_property_strv(
320 "org.freedesktop.systemd1",
322 "org.freedesktop.systemd1.Unit",
327 return log_error_errno(r
, "Failed to get triggered by array of %s: %s", n
, bus_error_message(&error
, r
));
329 STRV_FOREACH(i
, triggered_by
) {
330 r
= get_state_one_unit(bus
, *i
, &active_state
);
334 if (!IN_SET(active_state
, UNIT_ACTIVE
, UNIT_RELOADING
))
337 if (print_warning_label
) {
338 log_warning("Warning: Stopping %s, but it can still be activated by:", n
);
339 print_warning_label
= false;
342 log_warning(" %s", *i
);
348 int need_daemon_reload(sd_bus
*bus
, const char *unit
) {
349 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
353 /* We ignore all errors here, since this is used to show a
356 /* We don't use unit_dbus_path_from_name() directly since we
357 * don't want to load the unit if it isn't loaded. */
359 r
= bus_call_method(bus
, bus_systemd_mgr
, "GetUnit", NULL
, &reply
, "s", unit
);
363 r
= sd_bus_message_read(reply
, "o", &path
);
367 r
= sd_bus_get_property_trivial(
369 "org.freedesktop.systemd1",
371 "org.freedesktop.systemd1.Unit",
381 void warn_unit_file_changed(const char *unit
) {
384 log_warning("%sWarning:%s The unit file, source configuration file or drop-ins of %s changed on disk. Run 'systemctl%s daemon-reload' to reload units.",
385 ansi_highlight_red(),
388 arg_scope
== UNIT_FILE_SYSTEM
? "" : " --user");
391 int unit_file_find_path(LookupPaths
*lp
, const char *unit_name
, char **ret_unit_path
) {
397 STRV_FOREACH(p
, lp
->search_path
) {
398 _cleanup_free_
char *path
= NULL
, *lpath
= NULL
;
401 path
= path_join(*p
, unit_name
);
405 r
= chase_symlinks(path
, arg_root
, 0, &lpath
, NULL
);
411 return log_error_errno(r
, "Failed to access path \"%s\": %m", path
);
414 *ret_unit_path
= TAKE_PTR(lpath
);
420 *ret_unit_path
= NULL
;
427 const char *unit_name
,
429 bool force_client_side
,
430 Hashmap
**cached_name_map
,
431 Hashmap
**cached_id_map
,
432 char **ret_fragment_path
,
433 char ***ret_dropin_paths
) {
435 _cleanup_strv_free_
char **dropins
= NULL
;
436 _cleanup_free_
char *path
= NULL
;
440 * Finds where the unit is defined on disk. Returns 0 if the unit is not found. Returns 1 if it is
442 * - the path to the unit in *ret_frament_path, if it exists on disk,
443 * - and a strv of existing drop-ins in *ret_dropin_paths, if the arg is not NULL and any dropins
446 * Returns -ERFKILL if the unit is masked, and -EKEYREJECTED if the unit file could not be loaded for
447 * some reason (the latter only applies if we are going through the service manager).
451 assert(ret_fragment_path
);
454 /* Go via the bus to acquire the path, unless we are explicitly told not to, or when the unit name is a template */
455 if (!force_client_side
&&
456 !install_client_side() &&
457 !unit_name_is_valid(unit_name
, UNIT_NAME_TEMPLATE
)) {
458 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
459 _cleanup_free_
char *load_state
= NULL
, *dbus_path
= NULL
;
461 dbus_path
= unit_dbus_path_from_name(unit_name
);
465 r
= sd_bus_get_property_string(
467 "org.freedesktop.systemd1",
469 "org.freedesktop.systemd1.Unit",
474 return log_error_errno(r
, "Failed to get LoadState: %s", bus_error_message(&error
, r
));
476 if (streq(load_state
, "masked"))
478 if (streq(load_state
, "not-found")) {
482 if (!STR_IN_SET(load_state
, "loaded", "bad-setting"))
483 return -EKEYREJECTED
;
485 r
= sd_bus_get_property_string(
487 "org.freedesktop.systemd1",
489 "org.freedesktop.systemd1.Unit",
494 return log_error_errno(r
, "Failed to get FragmentPath: %s", bus_error_message(&error
, r
));
496 if (ret_dropin_paths
) {
497 r
= sd_bus_get_property_strv(
499 "org.freedesktop.systemd1",
501 "org.freedesktop.systemd1.Unit",
506 return log_error_errno(r
, "Failed to get DropInPaths: %s", bus_error_message(&error
, r
));
510 _cleanup_set_free_free_ Set
*names
= NULL
;
512 if (!*cached_name_map
) {
513 r
= unit_file_build_name_map(lp
, NULL
, cached_id_map
, cached_name_map
, NULL
);
518 r
= unit_file_find_fragment(*cached_id_map
, *cached_name_map
, unit_name
, &_path
, &names
);
523 path
= strdup(_path
);
528 if (ret_dropin_paths
) {
529 r
= unit_file_find_dropin_paths(arg_root
, lp
->search_path
, NULL
,
531 NULL
, names
, &dropins
);
538 *ret_fragment_path
= NULL
;
541 *ret_fragment_path
= TAKE_PTR(path
);
545 if (ret_dropin_paths
) {
546 if (!strv_isempty(dropins
)) {
547 *ret_dropin_paths
= TAKE_PTR(dropins
);
550 *ret_dropin_paths
= NULL
;
554 if (r
== 0 && !arg_force
)
555 log_error("No files found for %s.", unit_name
);
560 static int unit_find_template_path(
561 const char *unit_name
,
563 char **ret_fragment_path
,
564 char **ret_template
) {
566 _cleanup_free_
char *t
= NULL
, *f
= NULL
;
569 /* Returns 1 if a fragment was found, 0 if not found, negative on error. */
571 r
= unit_file_find_path(lp
, unit_name
, &f
);
575 if (ret_fragment_path
)
576 *ret_fragment_path
= TAKE_PTR(f
);
578 *ret_template
= NULL
;
579 return r
; /* found a real unit */
582 r
= unit_name_template(unit_name
, &t
);
584 if (ret_fragment_path
)
585 *ret_fragment_path
= NULL
;
587 *ret_template
= NULL
;
589 return 0; /* not a template, does not exist */
592 return log_error_errno(r
, "Failed to determine template name: %m");
594 r
= unit_file_find_path(lp
, t
, ret_fragment_path
);
599 *ret_template
= r
> 0 ? TAKE_PTR(t
) : NULL
;
604 int unit_is_masked(sd_bus
*bus
, LookupPaths
*lp
, const char *name
) {
605 _cleanup_free_
char *load_state
= NULL
;
608 if (unit_name_is_valid(name
, UNIT_NAME_TEMPLATE
)) {
609 _cleanup_free_
char *path
= NULL
;
611 /* A template cannot be loaded, but it can be still masked, so
612 * we need to use a different method. */
614 r
= unit_file_find_path(lp
, name
, &path
);
619 return null_or_empty_path(path
);
622 r
= unit_load_state(bus
, name
, &load_state
);
626 return streq(load_state
, "masked");
629 int unit_exists(LookupPaths
*lp
, const char *unit
) {
630 typedef struct UnitStateInfo
{
631 const char *load_state
;
632 const char *active_state
;
635 static const struct bus_properties_map property_map
[] = {
636 { "LoadState", "s", NULL
, offsetof(UnitStateInfo
, load_state
) },
637 { "ActiveState", "s", NULL
, offsetof(UnitStateInfo
, active_state
) },
641 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
642 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
;
643 _cleanup_free_
char *path
= NULL
;
644 UnitStateInfo info
= {};
648 if (unit_name_is_valid(unit
, UNIT_NAME_TEMPLATE
))
649 return unit_find_template_path(unit
, lp
, NULL
, NULL
);
651 path
= unit_dbus_path_from_name(unit
);
655 r
= acquire_bus(BUS_MANAGER
, &bus
);
659 r
= bus_map_all_properties(bus
, "org.freedesktop.systemd1", path
, property_map
, 0, &error
, &m
, &info
);
661 return log_error_errno(r
, "Failed to get properties: %s", bus_error_message(&error
, r
));
663 return !streq_ptr(info
.load_state
, "not-found") || !streq_ptr(info
.active_state
, "inactive");
667 int append_unit_dependencies(sd_bus
*bus
, char **names
, char ***ret
) {
668 _cleanup_strv_free_
char **with_deps
= NULL
;
674 STRV_FOREACH(name
, names
) {
675 _cleanup_strv_free_
char **deps
= NULL
;
677 if (strv_extend(&with_deps
, *name
) < 0)
680 (void) unit_get_dependencies(bus
, *name
, &deps
);
682 if (strv_extend_strv(&with_deps
, deps
, true) < 0)
686 *ret
= TAKE_PTR(with_deps
);
691 int maybe_extend_with_unit_dependencies(sd_bus
*bus
, char ***list
) {
692 _cleanup_strv_free_
char **list_with_deps
= NULL
;
698 if (!arg_with_dependencies
)
701 r
= append_unit_dependencies(bus
, *list
, &list_with_deps
);
703 return log_error_errno(r
, "Failed to append unit dependencies: %m");
706 *list
= TAKE_PTR(list_with_deps
);
710 int unit_get_dependencies(sd_bus
*bus
, const char *name
, char ***ret
) {
711 _cleanup_strv_free_
char **deps
= NULL
;
713 static const struct bus_properties_map map
[_DEPENDENCY_MAX
][6] = {
714 [DEPENDENCY_FORWARD
] = {
715 { "Requires", "as", NULL
, 0 },
716 { "Requisite", "as", NULL
, 0 },
717 { "Wants", "as", NULL
, 0 },
718 { "ConsistsOf", "as", NULL
, 0 },
719 { "BindsTo", "as", NULL
, 0 },
722 [DEPENDENCY_REVERSE
] = {
723 { "RequiredBy", "as", NULL
, 0 },
724 { "RequisiteOf", "as", NULL
, 0 },
725 { "WantedBy", "as", NULL
, 0 },
726 { "PartOf", "as", NULL
, 0 },
727 { "BoundBy", "as", NULL
, 0 },
730 [DEPENDENCY_AFTER
] = {
731 { "After", "as", NULL
, 0 },
734 [DEPENDENCY_BEFORE
] = {
735 { "Before", "as", NULL
, 0 },
740 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
741 _cleanup_free_
char *dbus_path
= NULL
;
748 dbus_path
= unit_dbus_path_from_name(name
);
752 r
= bus_map_all_properties(bus
,
753 "org.freedesktop.systemd1",
761 return log_error_errno(r
, "Failed to get properties of %s: %s", name
, bus_error_message(&error
, r
));
763 strv_uniq(deps
); /* Sometimes a unit might have multiple deps on the other unit,
764 * but we still want to show it just once. */
765 *ret
= TAKE_PTR(deps
);
770 const char* unit_type_suffix(const char *unit
) {
773 dot
= strrchr(unit
, '.');
780 bool output_show_unit(const UnitInfo
*u
, char **patterns
) {
783 if (!strv_fnmatch_or_empty(patterns
, u
->id
, FNM_NOESCAPE
))
786 if (arg_types
&& !strv_find(arg_types
, unit_type_suffix(u
->id
)))
792 /* Note that '--all' is not purely a state filter, but also a filter that hides units that "follow"
793 * other units (which is used for device units that appear under different names). */
794 if (!isempty(u
->following
))
797 if (!strv_isempty(arg_states
))
800 /* By default show all units except the ones in inactive state and with no pending job */
804 if (streq(u
->active_state
, "inactive"))
810 bool install_client_side(void) {
811 /* Decides when to execute enable/disable/... operations client-side rather than server-side. */
813 if (running_in_chroot_or_offline())
816 if (sd_booted() <= 0)
819 if (!isempty(arg_root
))
822 if (arg_scope
== UNIT_FILE_GLOBAL
)
825 /* Unsupported environment variable, mostly for debugging purposes */
826 if (getenv_bool("SYSTEMCTL_INSTALL_CLIENT_SIDE") > 0)
832 int output_table(Table
*table
) {
837 if (OUTPUT_MODE_IS_JSON(arg_output
))
838 r
= table_print_json(table
, NULL
, output_mode_to_json_format_flags(arg_output
) | JSON_FORMAT_COLOR_AUTO
);
840 r
= table_print(table
, NULL
);
842 return table_log_print_error(r
);
847 bool show_preset_for_state(UnitFileState state
) {
848 /* Don't show preset state in those unit file states, it'll only confuse users. */
849 return !IN_SET(state
,
853 UNIT_FILE_TRANSIENT
);
856 UnitFileFlags
unit_file_flags_from_args(void) {
857 return (arg_runtime
? UNIT_FILE_RUNTIME
: 0) |
858 (arg_force
? UNIT_FILE_FORCE
: 0);
861 int mangle_names(const char *operation
, char **original_names
, char ***ret_mangled_names
) {
862 _cleanup_strv_free_
char **l
= NULL
;
866 assert(ret_mangled_names
);
868 l
= i
= new(char*, strv_length(original_names
) + 1);
872 STRV_FOREACH(name
, original_names
) {
874 /* When enabling units qualified path names are OK, too, hence allow them explicitly. */
876 if (is_path(*name
)) {
881 r
= unit_name_mangle_with_suffix(*name
, operation
,
882 arg_quiet
? 0 : UNIT_NAME_MANGLE_WARN
,
886 return log_error_errno(r
, "Failed to mangle unit name: %m");
894 *ret_mangled_names
= TAKE_PTR(l
);
899 int halt_now(enum action a
) {
900 /* The kernel will automatically flush ATA disks and suchlike on reboot(), but the file systems need
901 * to be synced explicitly in advance. */
902 if (!arg_no_sync
&& !arg_dry_run
)
905 /* Make sure C-A-D is handled by the kernel from this point on... */
907 (void) reboot(RB_ENABLE_CAD
);
913 log_info("Halting.");
916 (void) reboot(RB_HALT_SYSTEM
);
919 case ACTION_POWEROFF
:
921 log_info("Powering off.");
924 (void) reboot(RB_POWER_OFF
);
929 return reboot_with_parameter(REBOOT_FALLBACK
|
930 (arg_quiet
? 0 : REBOOT_LOG
) |
931 (arg_dry_run
? REBOOT_DRY_RUN
: 0));
934 assert_not_reached("Unknown action.");