diff options
Diffstat (limited to 'src')
33 files changed, 543 insertions, 409 deletions
diff --git a/src/basic/filesystems-gperf.gperf b/src/basic/filesystems-gperf.gperf index 08c8c44510..e8c5357f91 100644 --- a/src/basic/filesystems-gperf.gperf +++ b/src/basic/filesystems-gperf.gperf @@ -40,7 +40,7 @@ ceph, {CEPH_SUPER_MAGIC} cgroup2, {CGROUP2_SUPER_MAGIC} # note that the cgroupfs magic got reassigned from cpuset cgroup, {CGROUP_SUPER_MAGIC} -cifs, {CIFS_MAGIC_NUMBER} +cifs, {CIFS_SUPER_MAGIC, SMB2_SUPER_MAGIC} coda, {CODA_SUPER_MAGIC} configfs, {CONFIGFS_MAGIC} cramfs, {CRAMFS_MAGIC} @@ -109,7 +109,7 @@ selinuxfs, {SELINUX_MAGIC} shiftfs, {SHIFTFS_MAGIC} smackfs, {SMACK_MAGIC} # smb3 is an alias for cifs -smb3, {CIFS_MAGIC_NUMBER} +smb3, {CIFS_SUPER_MAGIC} # smbfs was removed from the kernel in 2010, the magic remains smbfs, {SMB_SUPER_MAGIC} sockfs, {SOCKFS_MAGIC} diff --git a/src/basic/log.h b/src/basic/log.h index 1e2bec1646..0d927bfce9 100644 --- a/src/basic/log.h +++ b/src/basic/log.h @@ -273,9 +273,11 @@ int log_emergency_level(void); }) #if LOG_TRACE -# define log_trace(...) log_debug(__VA_ARGS__) +# define log_trace(...) log_debug(__VA_ARGS__) +# define log_trace_errno(...) log_debug_errno(__VA_ARGS__) #else -# define log_trace(...) do {} while (0) +# define log_trace(...) do {} while (0) +# define log_trace_errno(e, ...) (-ERRNO_VALUE(e)) #endif /* Structured logging */ diff --git a/src/basic/missing_magic.h b/src/basic/missing_magic.h index 7d9320bb6d..c104fcfba3 100644 --- a/src/basic/missing_magic.h +++ b/src/basic/missing_magic.h @@ -38,9 +38,14 @@ #define XFS_SB_MAGIC 0x58465342 #endif -/* Not exposed yet. Defined at fs/cifs/cifsglob.h */ -#ifndef CIFS_MAGIC_NUMBER -#define CIFS_MAGIC_NUMBER 0xFF534D42 +/* dea2903719283c156b53741126228c4a1b40440f (5.17) */ +#ifndef CIFS_SUPER_MAGIC +#define CIFS_SUPER_MAGIC 0xFF534D42 +#endif + +/* dea2903719283c156b53741126228c4a1b40440f (5.17) */ +#ifndef SMB2_SUPER_MAGIC +#define SMB2_SUPER_MAGIC 0xFE534D42 #endif /* 257f871993474e2bde6c497b54022c362cf398e1 (4.5) */ diff --git a/src/core/bpf-devices.c b/src/core/bpf-devices.c index e3100b862b..f62c6f1931 100644 --- a/src/core/bpf-devices.c +++ b/src/core/bpf-devices.c @@ -306,7 +306,7 @@ int bpf_devices_supported(void) { return supported = 0; } - r = bpf_program_new(BPF_PROG_TYPE_CGROUP_DEVICE, NULL, &program); + r = bpf_program_new(BPF_PROG_TYPE_CGROUP_DEVICE, "sd_devices", &program); if (r < 0) { log_debug_errno(r, "Can't allocate CGROUP DEVICE BPF program, BPF device control is not supported: %m"); return supported = 0; diff --git a/src/core/bpf-firewall.c b/src/core/bpf-firewall.c index 8158fafc8e..0297053add 100644 --- a/src/core/bpf-firewall.c +++ b/src/core/bpf-firewall.c @@ -145,6 +145,7 @@ static int add_instructions_for_ip_any( static int bpf_firewall_compile_bpf( Unit *u, + const char *prog_name, bool is_ingress, BPFProgram **ret, bool ip_allow_any, @@ -193,7 +194,6 @@ static int bpf_firewall_compile_bpf( }; _cleanup_(bpf_program_freep) BPFProgram *p = NULL; - const char *prog_name = is_ingress ? "sd_fw_ingress" : "sd_fw_egress"; int accounting_map_fd, r; bool access_enabled; @@ -527,9 +527,10 @@ static int bpf_firewall_prepare_accounting_maps(Unit *u, bool enabled, int *fd_i } int bpf_firewall_compile(Unit *u) { + const char *ingress_name = NULL, *egress_name = NULL; + bool ip_allow_any = false, ip_deny_any = false; CGroupContext *cc; int r, supported; - bool ip_allow_any = false, ip_deny_any = false; assert(u); @@ -552,6 +553,13 @@ int bpf_firewall_compile(Unit *u) { return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EOPNOTSUPP), "BPF_F_ALLOW_MULTI is not supported on this manager, not doing BPF firewall on slice units."); + /* If BPF_F_ALLOW_MULTI flag is supported program name is also supported (both were added to v4.15 + * kernel). */ + if (supported == BPF_FIREWALL_SUPPORTED_WITH_MULTI) { + ingress_name = "sd_fw_ingress"; + egress_name = "sd_fw_egress"; + } + /* Note that when we compile a new firewall we first flush out the access maps and the BPF programs themselves, * but we reuse the accounting maps. That way the firewall in effect always maps to the actual * configuration, but we don't flush out the accounting unnecessarily */ @@ -585,11 +593,11 @@ int bpf_firewall_compile(Unit *u) { if (r < 0) return log_unit_error_errno(u, r, "Preparation of eBPF accounting maps failed: %m"); - r = bpf_firewall_compile_bpf(u, true, &u->ip_bpf_ingress, ip_allow_any, ip_deny_any); + r = bpf_firewall_compile_bpf(u, ingress_name, true, &u->ip_bpf_ingress, ip_allow_any, ip_deny_any); if (r < 0) return log_unit_error_errno(u, r, "Compilation for ingress BPF program failed: %m"); - r = bpf_firewall_compile_bpf(u, false, &u->ip_bpf_egress, ip_allow_any, ip_deny_any); + r = bpf_firewall_compile_bpf(u, egress_name, false, &u->ip_bpf_egress, ip_allow_any, ip_deny_any); if (r < 0) return log_unit_error_errno(u, r, "Compilation for egress BPF program failed: %m"); @@ -826,6 +834,7 @@ int bpf_firewall_supported(void) { return supported = BPF_FIREWALL_UNSUPPORTED; } + /* prog_name is NULL since it is supported only starting from v4.15 kernel. */ r = bpf_program_new(BPF_PROG_TYPE_CGROUP_SKB, NULL, &program); if (r < 0) { bpf_firewall_unsupported_reason = @@ -883,7 +892,9 @@ int bpf_firewall_supported(void) { /* So now we know that the BPF program is generally available, let's see if BPF_F_ALLOW_MULTI is also supported * (which was added in kernel 4.15). We use a similar logic as before, but this time we use the BPF_PROG_ATTACH * bpf() call and the BPF_F_ALLOW_MULTI flags value. Since the flags are checked early in the system call we'll - * get EINVAL if it's not supported, and EBADF as before if it is available. */ + * get EINVAL if it's not supported, and EBADF as before if it is available. + * Use probe result as the indicator that program name is also supported since they both were + * added in kernel 4.15. */ zero(attr); attr.attach_type = BPF_CGROUP_INET_EGRESS; diff --git a/src/core/bpf/meson.build b/src/core/bpf/meson.build index c2465a845f..57a4c5393c 100644 --- a/src/core/bpf/meson.build +++ b/src/core/bpf/meson.build @@ -65,13 +65,23 @@ bpf_o_unstripped_cmd += [ '@OUTPUT@' ] -bpf_o_cmd = [ - llvm_strip, - '-g', - '@INPUT@', - '-o', - '@OUTPUT@' -] +if bpftool_strip + bpf_o_cmd = [ + bpftool, + 'g', + 'o', + '@OUTPUT@', + '@INPUT@' + ] +else + bpf_o_cmd = [ + llvm_strip, + '-g', + '@INPUT@', + '-o', + '@OUTPUT@' + ] +endif skel_h_cmd = [ bpftool, diff --git a/src/core/execute.c b/src/core/execute.c index acc59ef9db..d3266a9ab5 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -3373,7 +3373,7 @@ static int compile_symlinks( return r; } - if (!exec_directory_is_private(context, dt)) + if (!exec_directory_is_private(context, dt) || exec_context_with_rootfs(context)) continue; private_path = path_join(params->prefix[dt], "private", context->directories[dt].items[i].path); diff --git a/src/core/main.c b/src/core/main.c index 57aedb9b93..f347b74b11 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -2726,6 +2726,8 @@ int main(int argc, char *argv[]) { Manager *m = NULL; FDSet *fds = NULL; + assert_se(argc > 0 && !isempty(argv[0])); + /* SysV compatibility: redirect init → telinit */ redirect_telinit(argc, argv); diff --git a/src/core/namespace.c b/src/core/namespace.c index f3c6b58f86..e75e003e71 100644 --- a/src/core/namespace.c +++ b/src/core/namespace.c @@ -1482,7 +1482,7 @@ static int apply_one_mount( (void) mkdir_parents(mount_entry_path(m), 0755); q = make_mount_point_inode_from_path(what, mount_entry_path(m), 0755); - if (q < 0) + if (q < 0 && q != -EEXIST) log_error_errno(q, "Failed to create destination mount point node '%s': %m", mount_entry_path(m)); else @@ -1804,7 +1804,7 @@ static int apply_mounts( * exist, which means this will be a no-op. */ r = create_symlinks_from_tuples(root, exec_dir_symlinks); if (r < 0) - return r; + return log_debug_errno(r, "Failed to set up ExecDirectories symlinks inside mount namespace: %m"); /* Create a deny list we can pass to bind_mount_recursive() */ deny_list = new(char*, (*n_mounts)+1); diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c index 9b32383a76..ca9b045e85 100644 --- a/src/fstab-generator/fstab-generator.c +++ b/src/fstab-generator/fstab-generator.c @@ -721,7 +721,7 @@ static int sysroot_is_nfsroot(void) { if (!sep) return -EINVAL; - a = strndupa(arg_root_what + 1, sep - arg_root_what - 1); + a = strndupa_safe(arg_root_what + 1, sep - arg_root_what - 1); r = in_addr_from_string(AF_INET6, a, &u); if (r < 0) @@ -733,7 +733,7 @@ static int sysroot_is_nfsroot(void) { /* IPv4 address */ sep = strchr(arg_root_what, ':'); if (sep) { - a = strndupa(arg_root_what, sep - arg_root_what); + a = strndupa_safe(arg_root_what, sep - arg_root_what); if (in_addr_from_string(AF_INET, a, &u) >= 0) return true; diff --git a/src/libsystemd-network/fuzz-dhcp-client.c b/src/libsystemd-network/fuzz-dhcp-client.c new file mode 100644 index 0000000000..1812a61950 --- /dev/null +++ b/src/libsystemd-network/fuzz-dhcp-client.c @@ -0,0 +1,79 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include <errno.h> +#include <sys/socket.h> +#include <unistd.h> + +#include "alloc-util.h" +#include "fuzz.h" +#include "sd-event.h" + +#include "sd-dhcp-client.c" + +int dhcp_network_bind_raw_socket( + int ifindex, + union sockaddr_union *link, + uint32_t id, + const uint8_t *addr, size_t addr_len, + const uint8_t *bcaddr, size_t bcaddr_len, + uint16_t arp_type, uint16_t port) { + + int fd; + fd = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0); + if (fd < 0) + return -errno; + + return fd; +} + +int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link, const void *packet, size_t len) { + return len; +} + +int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port, int ip_service_type) { + int fd; + + fd = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0); + if (fd < 0) + return -errno; + + return fd; +} + +int dhcp_network_send_udp_socket(int s, be32_t address, uint16_t port, const void *packet, size_t len) { + return len; +} + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + uint8_t mac_addr[] = {'A', 'B', 'C', '1', '2', '3'}; + uint8_t bcast_addr[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + _cleanup_(sd_dhcp_client_unrefp) sd_dhcp_client *client = NULL; + _cleanup_(sd_event_unrefp) sd_event *e = NULL; + int res, r; + + if (!getenv("SYSTEMD_LOG_LEVEL")) + log_set_max_level(LOG_CRIT); + + r = sd_dhcp_client_new(&client, false); + assert_se(r >= 0); + assert_se(client); + + assert_se(sd_event_new(&e) >= 0); + + r = sd_dhcp_client_attach_event(client, e, 0); + assert_se(r >= 0); + + assert_se(sd_dhcp_client_set_ifindex(client, 42) >= 0); + assert_se(sd_dhcp_client_set_mac(client, mac_addr, bcast_addr, ETH_ALEN, ARPHRD_ETHER) >= 0); + dhcp_client_set_test_mode(client, true); + + res = sd_dhcp_client_start(client); + assert_se(IN_SET(res, 0, -EINPROGRESS)); + client->xid = 2; + + (void) client_handle_offer(client, (DHCPMessage*) data, size); + + assert_se(sd_dhcp_client_stop(client) >= 0); + + return 0; +} diff --git a/src/libsystemd-network/meson.build b/src/libsystemd-network/meson.build index 3f5e11e7f5..853401d5be 100644 --- a/src/libsystemd-network/meson.build +++ b/src/libsystemd-network/meson.build @@ -105,6 +105,10 @@ tests += [ ] fuzzers += [ + [files('fuzz-dhcp-client.c'), + [libshared, + libsystemd_network]], + [files('fuzz-dhcp6-client.c'), [libshared, libsystemd_network]], diff --git a/src/libsystemd-network/sd-dhcp-lease.c b/src/libsystemd-network/sd-dhcp-lease.c index ab131701fb..5a40eb94d3 100644 --- a/src/libsystemd-network/sd-dhcp-lease.c +++ b/src/libsystemd-network/sd-dhcp-lease.c @@ -492,10 +492,8 @@ static int lease_parse_routes( route->option = SD_DHCP_OPTION_STATIC_ROUTE; r = in4_addr_default_prefixlen((struct in_addr*) option, &route->dst_prefixlen); - if (r < 0) { - log_debug("Failed to determine destination prefix length from class based IP, ignoring"); - continue; - } + if (r < 0) + return -EINVAL; assert_se(lease_parse_be32(option, 4, &addr.s_addr) >= 0); route->dst_addr = inet_makeaddr(inet_netof(addr), 0); @@ -907,7 +905,7 @@ int dhcp_lease_parse_search_domains(const uint8_t *option, size_t len, char ***d pos = next_chunk; } - *domains = TAKE_PTR(names); + strv_free_and_replace(*domains, names); return cnt; } diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c index ec9202d02e..1d27d28959 100644 --- a/src/libsystemd-network/sd-dhcp-server.c +++ b/src/libsystemd-network/sd-dhcp-server.c @@ -319,6 +319,9 @@ static int dhcp_server_send_unicast_raw( memcpy(link.ll.sll_addr, chaddr, hlen); + if (len > UINT16_MAX) + return -EOVERFLOW; + dhcp_packet_append_ip_headers(packet, server->address, DHCP_PORT_SERVER, packet->dhcp.yiaddr, DHCP_PORT_CLIENT, len, -1); diff --git a/src/libsystemd/sd-device/sd-device.c b/src/libsystemd/sd-device/sd-device.c index 92a7ededf6..27c91ea724 100644 --- a/src/libsystemd/sd-device/sd-device.c +++ b/src/libsystemd/sd-device/sd-device.c @@ -188,8 +188,11 @@ int device_set_syspath(sd_device *device, const char *_syspath, bool verify) { path = strjoina(syspath, "/uevent"); if (access(path, F_OK) < 0) { if (errno == ENOENT) - /* this is not a valid device */ - return log_debug_errno(SYNTHETIC_ERRNO(ENODEV), + /* This is not a valid device. + * Note, this condition is quite often satisfied when + * enumerating devices or finding a parent device. + * Hence, use log_trace_errno() here. */ + return log_trace_errno(SYNTHETIC_ERRNO(ENODEV), "sd-device: the uevent file \"%s\" does not exist.", path); return log_debug_errno(errno, "sd-device: cannot access uevent file for %s: %m", syspath); diff --git a/src/login/logind-action.c b/src/login/logind-action.c index e172910948..45f77bc090 100644 --- a/src/login/logind-action.c +++ b/src/login/logind-action.c @@ -2,6 +2,8 @@ #include <unistd.h> +#include "sd-messages.h" + #include "alloc-util.h" #include "bus-error.h" #include "bus-util.h" @@ -11,29 +13,119 @@ #include "logind-dbus.h" #include "logind-session-dbus.h" #include "process-util.h" -#include "sleep-config.h" #include "special.h" #include "string-table.h" #include "terminal-util.h" #include "user-util.h" +static const ActionTableItem action_table[_HANDLE_ACTION_MAX] = { + [HANDLE_POWEROFF] = { + SPECIAL_POWEROFF_TARGET, + INHIBIT_SHUTDOWN, + "org.freedesktop.login1.power-off", + "org.freedesktop.login1.power-off-multiple-sessions", + "org.freedesktop.login1.power-off-ignore-inhibit", + _SLEEP_OPERATION_INVALID, + SD_MESSAGE_SHUTDOWN_STR, + "System is powering down", + "power-off", + }, + [HANDLE_REBOOT] = { + SPECIAL_REBOOT_TARGET, + INHIBIT_SHUTDOWN, + "org.freedesktop.login1.reboot", + "org.freedesktop.login1.reboot-multiple-sessions", + "org.freedesktop.login1.reboot-ignore-inhibit", + _SLEEP_OPERATION_INVALID, + SD_MESSAGE_SHUTDOWN_STR, + "System is rebooting", + "reboot", + }, + [HANDLE_HALT] = { + SPECIAL_HALT_TARGET, + INHIBIT_SHUTDOWN, + "org.freedesktop.login1.halt", + "org.freedesktop.login1.halt-multiple-sessions", + "org.freedesktop.login1.halt-ignore-inhibit", + _SLEEP_OPERATION_INVALID, + SD_MESSAGE_SHUTDOWN_STR, + "System is halting", + "halt", + }, + [HANDLE_KEXEC] = { + SPECIAL_KEXEC_TARGET, + INHIBIT_SHUTDOWN, + "org.freedesktop.login1.reboot", + "org.freedesktop.login1.reboot-multiple-sessions", + "org.freedesktop.login1.reboot-ignore-inhibit", + _SLEEP_OPERATION_INVALID, + SD_MESSAGE_SHUTDOWN_STR, + "System is rebooting with kexec", + "kexec", + }, + [HANDLE_SUSPEND] = { + SPECIAL_SUSPEND_TARGET, + INHIBIT_SLEEP, + "org.freedesktop.login1.suspend", + "org.freedesktop.login1.suspend-multiple-sessions", + "org.freedesktop.login1.suspend-ignore-inhibit", + SLEEP_SUSPEND, + }, + [HANDLE_HIBERNATE] = { + SPECIAL_HIBERNATE_TARGET, + INHIBIT_SLEEP, + "org.freedesktop.login1.hibernate", + "org.freedesktop.login1.hibernate-multiple-sessions", + "org.freedesktop.login1.hibernate-ignore-inhibit", + SLEEP_HIBERNATE, + }, + [HANDLE_HYBRID_SLEEP] = { + SPECIAL_HYBRID_SLEEP_TARGET, + INHIBIT_SLEEP, + "org.freedesktop.login1.hibernate", + "org.freedesktop.login1.hibernate-multiple-sessions", + "org.freedesktop.login1.hibernate-ignore-inhibit", + SLEEP_HYBRID_SLEEP, + }, + [HANDLE_SUSPEND_THEN_HIBERNATE] = { + SPECIAL_SUSPEND_THEN_HIBERNATE_TARGET, + INHIBIT_SLEEP, + "org.freedesktop.login1.hibernate", + "org.freedesktop.login1.hibernate-multiple-sessions", + "org.freedesktop.login1.hibernate-ignore-inhibit", + SLEEP_SUSPEND_THEN_HIBERNATE, + }, + [HANDLE_FACTORY_RESET] = { + SPECIAL_FACTORY_RESET_TARGET, + _INHIBIT_WHAT_INVALID, + NULL, + NULL, + NULL, + _SLEEP_OPERATION_INVALID, + SD_MESSAGE_FACTORY_RESET_STR, + "System is performing factory reset", + NULL + }, +}; + const char* manager_target_for_action(HandleAction handle) { - static const char * const target_table[_HANDLE_ACTION_MAX] = { - [HANDLE_POWEROFF] = SPECIAL_POWEROFF_TARGET, - [HANDLE_REBOOT] = SPECIAL_REBOOT_TARGET, - [HANDLE_HALT] = SPECIAL_HALT_TARGET, - [HANDLE_KEXEC] = SPECIAL_KEXEC_TARGET, - [HANDLE_SUSPEND] = SPECIAL_SUSPEND_TARGET, - [HANDLE_HIBERNATE] = SPECIAL_HIBERNATE_TARGET, - [HANDLE_HYBRID_SLEEP] = SPECIAL_HYBRID_SLEEP_TARGET, - [HANDLE_SUSPEND_THEN_HIBERNATE] = SPECIAL_SUSPEND_THEN_HIBERNATE_TARGET, - [HANDLE_FACTORY_RESET] = SPECIAL_FACTORY_RESET_TARGET, - }; + assert(handle >= 0); + assert(handle < (ssize_t) ELEMENTSOF(action_table)); + return action_table[handle].target; +} + +const ActionTableItem* manager_item_for_handle(HandleAction handle) { assert(handle >= 0); - if (handle < (ssize_t) ELEMENTSOF(target_table)) - return target_table[handle]; - return NULL; + assert(handle < (ssize_t) ELEMENTSOF(action_table)); + + return &action_table[handle]; +} + +HandleAction manager_handle_for_item(const ActionTableItem* a) { + if (a && a < action_table + ELEMENTSOF(action_table)) + return a - action_table; + return _HANDLE_ACTION_INVALID; } int manager_handle_action( @@ -59,7 +151,6 @@ int manager_handle_action( InhibitWhat inhibit_operation; Inhibitor *offending = NULL; bool supported; - const char *target; int r; assert(m); @@ -129,17 +220,13 @@ int manager_handle_action( return log_warning_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Requested %s operation not supported, ignoring.", handle_action_to_string(handle)); - if (m->action_what > 0) + if (m->delayed_action) return log_debug_errno(SYNTHETIC_ERRNO(EALREADY), "Action already in progress (%s), ignoring requested %s operation.", - inhibit_what_to_string(m->action_what), + inhibit_what_to_string(m->delayed_action->inhibit_what), handle_action_to_string(handle)); - assert_se(target = manager_target_for_action(handle)); - - inhibit_operation = IN_SET(handle, HANDLE_SUSPEND, HANDLE_HIBERNATE, - HANDLE_HYBRID_SLEEP, - HANDLE_SUSPEND_THEN_HIBERNATE) ? INHIBIT_SLEEP : INHIBIT_SHUTDOWN; + inhibit_operation = manager_item_for_handle(handle)->inhibit_what; /* If the actual operation is inhibited, warn and fail */ if (!ignore_inhibited && @@ -162,7 +249,7 @@ int manager_handle_action( log_info("%s", message_table[handle]); - r = bus_manager_shutdown_or_sleep_now_or_later(m, target, inhibit_operation, &error); + r = bus_manager_shutdown_or_sleep_now_or_later(m, manager_item_for_handle(handle), &error); if (r < 0) return log_error_errno(r, "Failed to execute %s operation: %s", handle_action_to_string(handle), diff --git a/src/login/logind-action.h b/src/login/logind-action.h index ec2fece2b7..e6d3047743 100644 --- a/src/login/logind-action.h +++ b/src/login/logind-action.h @@ -19,8 +19,26 @@ typedef enum HandleAction { _HANDLE_ACTION_INVALID = -EINVAL, } HandleAction; +typedef struct ActionTableItem ActionTableItem; + +#define handle_action_valid(x) (x && (x < _HANDLE_ACTION_MAX)) + #include "logind-inhibit.h" #include "logind.h" +#include "sleep-config.h" + +struct ActionTableItem { + const char *target; + InhibitWhat inhibit_what; + const char *polkit_action; + const char *polkit_action_multiple_sessions; + const char *polkit_action_ignore_inhibit; + SleepOperation sleep_operation; + const char* message_id; + const char* message; + const char* log_str; + +}; int manager_handle_action( Manager *m, @@ -33,5 +51,7 @@ const char* handle_action_to_string(HandleAction h) _const_; HandleAction handle_action_from_string(const char *s) _pure_; const char* manager_target_for_action(HandleAction handle); +const ActionTableItem* manager_item_for_handle(HandleAction handle); +HandleAction manager_handle_for_item(const ActionTableItem* a); CONFIG_PARSER_PROTOTYPE(config_parse_handle_action); diff --git a/src/login/logind-button.c b/src/login/logind-button.c index 7fb8114639..0f4e1f1b41 100644 --- a/src/login/logind-button.c +++ b/src/login/logind-button.c @@ -84,8 +84,7 @@ static void button_lid_switch_handle_action(Manager *manager, bool is_edge) { * differently */ if (manager_is_docked_or_external_displays(manager)) handle_action = manager->handle_lid_switch_docked; - else if (manager->handle_lid_switch_ep != _HANDLE_ACTION_INVALID && - manager_is_on_external_power()) + else if (!handle_action_valid(manager->handle_lid_switch_ep) && manager_is_on_external_power()) handle_action = manager->handle_lid_switch_ep; else handle_action = manager->handle_lid_switch; diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index f38f0629a8..5c4341df2b 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -29,6 +29,7 @@ #include "fileio.h" #include "format-util.h" #include "fs-util.h" +#include "logind-action.h" #include "logind-dbus.h" #include "logind-polkit.h" #include "logind-seat-dbus.h" @@ -53,6 +54,8 @@ #include "utmp-wtmp.h" #include "virt.h" +static void reset_scheduled_shutdown(Manager *m); + static int get_sender_session( Manager *m, sd_bus_message *message, @@ -309,16 +312,18 @@ static int property_get_preparing( sd_bus_error *error) { Manager *m = userdata; - bool b; + bool b = false; assert(bus); assert(reply); assert(m); - if (streq(property, "PreparingForShutdown")) - b = m->action_what & INHIBIT_SHUTDOWN; - else - b = m->action_what & INHIBIT_SLEEP; + if (m->delayed_action) { + if (streq(property, "PreparingForShutdown")) + b = m->delayed_action->inhibit_what & INHIBIT_SHUTDOWN; + else + b = m->delayed_action->inhibit_what & INHIBIT_SLEEP; + } return sd_bus_message_append(reply, "b", b); } @@ -343,7 +348,9 @@ static int property_get_scheduled_shutdown( if (r < 0) return r; - r = sd_bus_message_append(reply, "st", m->scheduled_shutdown_type, m->scheduled_shutdown_timeout); + r = sd_bus_message_append(reply, "st", + handle_action_to_string(manager_handle_for_item(m->scheduled_shutdown_type)), + m->scheduled_shutdown_timeout); if (r < 0) return r; @@ -1488,59 +1495,35 @@ static int have_multiple_sessions( return false; } -_printf_(2, 0) -static int log_with_wall_message(Manager *m, const char *d, const char *p, const char *q) { +static int bus_manager_log_shutdown( + Manager *m, + const ActionTableItem *a) { + + const char *message, *log_str; + assert(m); + assert(a); + + message = a->message; + log_str = a->log_str; + + if (message) + message = strjoina("MESSAGE=", message); + else + message = "MESSAGE=System is shutting down"; if (isempty(m->wall_message)) - p = strjoina(p, "."); + message = strjoina(message, "."); else - p = strjoina(p, " (", m->wall_message, ")."); + message = strjoina(message, " (", m->wall_message, ")."); - return log_struct(LOG_NOTICE, d, p, q); -} + if (log_str) + log_str = strjoina("SHUTDOWN=", log_str); -static int bus_manager_log_shutdown( - Manager *m, - const char *unit_name) { - - assert(m); - assert(unit_name); - - if (streq(unit_name, SPECIAL_POWEROFF_TARGET)) - return log_with_wall_message(m, - "MESSAGE_ID=" SD_MESSAGE_SHUTDOWN_STR, - "MESSAGE=System is powering down", - "SHUTDOWN=power-off"); - - if (streq(unit_name, SPECIAL_REBOOT_TARGET)) - return log_with_wall_message(m, - "MESSAGE_ID=" SD_MESSAGE_SHUTDOWN_STR, - "MESSAGE=System is rebooting", - "SHUTDOWN=reboot"); - - if (streq(unit_name, SPECIAL_HALT_TARGET)) - return log_with_wall_message(m, - "MESSAGE_ID=" SD_MESSAGE_SHUTDOWN_STR, - "MESSAGE=System is halting", - "SHUTDOWN=halt"); - - if (streq(unit_name, SPECIAL_KEXEC_TARGET)) - return log_with_wall_message(m, - "MESSAGE_ID=" SD_MESSAGE_SHUTDOWN_STR, - "MESSAGE=System is rebooting with kexec", - "SHUTDOWN=kexec"); - - if (streq(unit_name, SPECIAL_FACTORY_RESET_TARGET)) - return log_with_wall_message(m, - "MESSAGE_ID=" SD_MESSAGE_FACTORY_RESET_STR, - "MESSAGE=System is performing factory reset", - NULL); - - return log_with_wall_message(m, - "MESSAGE_ID=" SD_MESSAGE_SHUTDOWN_STR, - "MESSAGE=System is shutting down", - NULL); + return log_struct(LOG_NOTICE, + "MESSAGE_ID=%s", a->message_id ? a->message_id : SD_MESSAGE_SHUTDOWN_STR, + message, + log_str); } static int lid_switch_ignore_handler(sd_event_source *e, uint64_t usec, void *userdata) { @@ -1604,8 +1587,7 @@ static int send_prepare_for(Manager *m, InhibitWhat w, bool _active) { static int execute_shutdown_or_sleep( Manager *m, - InhibitWhat w, - const char *unit_name, + const ActionTableItem *a, sd_bus_error *error) { _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; @@ -1613,12 +1595,10 @@ static int execute_shutdown_or_sleep( int r; assert(m); - assert(w > 0); - assert(w < _INHIBIT_WHAT_MAX); - assert(unit_name); + assert(a); - if (w == INHIBIT_SHUTDOWN) - bus_manager_log_shutdown(m, unit_name); + if (a->inhibit_what == INHIBIT_SHUTDOWN) + bus_manager_log_shutdown(m, a); r = bus_call_method( m->bus, @@ -1626,7 +1606,7 @@ static int execute_shutdown_or_sleep( "StartUnit", error, &reply, - "ss", unit_name, "replace-irreversibly"); + "ss", a->target, "replace-irreversibly"); if (r < 0) goto error; @@ -1638,8 +1618,7 @@ static int execute_shutdown_or_sleep( if (r < 0) goto error; - m->action_unit = unit_name; - m->action_what = w; + m->delayed_action = a; /* Make sure the lid switch is ignored for a while */ manager_set_lid_switch_ignore(m, usec_add(now(CLOCK_MONOTONIC), m->holdoff_timeout_usec)); @@ -1648,7 +1627,7 @@ static int execute_shutdown_or_sleep( error: /* Tell people that they now may take a lock again */ - (void) send_prepare_for(m, w, false); + (void) send_prepare_for(m, a->inhibit_what, false); return r; } @@ -1660,10 +1639,10 @@ int manager_dispatch_delayed(Manager *manager, bool timeout) { assert(manager); - if (manager->action_what == 0 || manager->action_job) + if (!manager->delayed_action || manager->action_job) return 0; - if (manager_is_inhibited(manager, manager->action_what, INHIBIT_DELAY, NULL, false, false, 0, &offending)) { + if (manager_is_inhibited(manager, manager->delayed_action->inhibit_what, INHIBIT_DELAY, NULL, false, false, 0, &offending)) { _cleanup_free_ char *comm = NULL, *u = NULL; if (!timeout) @@ -1678,13 +1657,12 @@ int manager_dispatch_delayed(Manager *manager, bool timeout) { } /* Actually do the operation */ - r = execute_shutdown_or_sleep(manager, manager->action_what, manager->action_unit, &error); + r = execute_shutdown_or_sleep(manager, manager->delayed_action, &error); if (r < 0) { log_warning("Error during inhibitor-delayed operation (already returned success to client): %s", bus_error_message(&error, r)); - manager->action_unit = NULL; - manager->action_what = 0; + manager->delayed_action = NULL; } return 1; /* We did some work. */ @@ -1705,15 +1683,12 @@ static int manager_inhibit_timeout_handler( static int delay_shutdown_or_sleep( Manager *m, - InhibitWhat w, - const char *unit_name) { + const ActionTableItem *a) { int r; assert(m); - assert(w >= 0); - assert(w < _INHIBIT_WHAT_MAX); - assert(unit_name); + assert(a); if (m->inhibit_timeout_source) { r = sd_event_source_set_time_relative(m->inhibit_timeout_source, m->inhibit_delay_max); @@ -1733,16 +1708,14 @@ static int delay_shutdown_or_sleep( return r; } - m->action_unit = unit_name; - m->action_what = w; + m->delayed_action = a; return 0; } int bus_manager_shutdown_or_sleep_now_or_later( Manager *m, - const char *unit_name, - InhibitWhat w, + const ActionTableItem *a, sd_bus_error *error) { _cleanup_free_ char *load_state = NULL; @@ -1750,35 +1723,33 @@ int bus_manager_shutdown_or_sleep_now_or_later( int r; assert(m); - assert(unit_name); - assert(w > 0); - assert(w < _INHIBIT_WHAT_MAX); + assert(a); assert(!m->action_job); - r = unit_load_state(m->bus, unit_name, &load_state); + r = unit_load_state(m->bus, a->target, &load_state); if (r < 0) return r; if (!streq(load_state, "loaded")) return log_notice_errno(SYNTHETIC_ERRNO(EACCES), "Unit %s is %s, refusing operation.", - unit_name, load_state); + a->target, load_state); /* Tell everybody to prepare for shutdown/sleep */ - (void) send_prepare_for(m, w, true); + (void) send_prepare_for(m, a->inhibit_what, true); delayed = m->inhibit_delay_max > 0 && - manager_is_inhibited(m, w, INHIBIT_DELAY, NULL, false, false, 0, NULL); + manager_is_inhibited(m, a->inhibit_what, INHIBIT_DELAY, NULL, false, false, 0, NULL); if (delayed) /* Shutdown is delayed, keep in mind what we * want to do, and start a timeout */ - r = delay_shutdown_or_sleep(m, w, unit_name); + r = delay_shutdown_or_sleep(m, a); else /* Shutdown is not delayed, execute it * immediately */ - r = execute_shutdown_or_sleep(m, w, unit_name, error); + r = execute_shutdown_or_sleep(m, a, error); return r; } @@ -1786,10 +1757,7 @@ int bus_manager_shutdown_or_sleep_now_or_later( static int verify_shutdown_creds( Manager *m, sd_bus_message *message, - InhibitWhat w, - const char *action, - const char *action_multiple_sessions, - const char *action_ignore_inhibit, + const ActionTableItem *a, uint64_t flags, sd_bus_error *error) { @@ -1799,12 +1767,8 @@ static int verify_shutdown_creds( int r; assert(m); + assert(a); assert(message); - assert(w >= 0); - assert(w <= _INHIBIT_WHAT_MAX); - assert(action); - assert(action_multiple_sessions); - assert(action_ignore_inhibit); r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds); if (r < 0) @@ -1819,11 +1783,19 @@ static int verify_shutdown_creds( return r; multiple_sessions = r > 0; - blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, uid, NULL); + blocked = manager_is_inhibited(m, a->inhibit_what, INHIBIT_BLOCK, NULL, false, true, uid, NULL); interactive = flags & SD_LOGIND_INTERACTIVE; if (multiple_sessions) { - r = bus_verify_polkit_async(message, CAP_SYS_BOOT, action_multiple_sessions, NULL, interactive, UID_INVALID, &m->polkit_registry, error); + r = bus_verify_polkit_async( + message, + CAP_SYS_BOOT, + a->polkit_action_multiple_sessions, + NULL, + interactive, + UID_INVALID, + &m->polkit_registry, + error); if (r < 0) return r; if (r == 0) @@ -1836,7 +1808,14 @@ static int verify_shutdown_creds( return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Access denied to root due to active block inhibitor"); - r = bus_verify_polkit_async(message, CAP_SYS_BOOT, action_ignore_inhibit, NULL, interactive, UID_INVALID, &m->polkit_registry, error); + r = bus_verify_polkit_async(message, + CAP_SYS_BOOT, + a->polkit_action_ignore_inhibit, + NULL, + interactive, + UID_INVALID, + &m->polkit_registry, + error); if (r < 0) return r; if (r == 0) @@ -1844,7 +1823,14 @@ static int verify_shutdown_creds( } if (!multiple_sessions && !blocked) { - r = bus_verify_polkit_async(message, CAP_SYS_BOOT, action, NULL, interactive, UID_INVALID, &m->polkit_registry, error); + r = bus_verify_polkit_async(message, + CAP_SYS_BOOT, + a->polkit_action, + NULL, + interactive, + UID_INVALID, + &m->polkit_registry, + error); if (r < 0) return r; if (r == 0) @@ -1854,15 +1840,33 @@ static int verify_shutdown_creds( return 0; } +static int setup_wall_message_timer(Manager *m, sd_bus_message* message) { + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; + int r; + + r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_AUGMENT|SD_BUS_CREDS_TTY|SD_BUS_CREDS_UID, &creds); + if (r >= 0) { + const char *tty = NULL; + + (void) sd_bus_creds_get_uid(creds, &m->scheduled_shutdown_uid); + (void) sd_bus_creds_get_tty(creds, &tty); + + r = free_and_strdup(&m->scheduled_shutdown_tty, tty); + if (r < 0) + return log_oom(); + } + + r = manager_setup_wall_message_timer(m); + if (r < 0) + return r; + + return 0; +} + static int method_do_shutdown_or_sleep( Manager *m, sd_bus_message *message, - const char *unit_name, - InhibitWhat w, - const char *action, - const char *action_multiple_sessions, - const char *action_ignore_inhibit, - SleepOperation sleep_operation, + const ActionTableItem *a, bool with_flags, sd_bus_error *error) { @@ -1871,9 +1875,7 @@ static int method_do_shutdown_or_sleep( assert(m); assert(message); - assert(unit_name); - assert(w >= 0); - assert(w <= _INHIBIT_WHAT_MAX); + assert(a); if (with_flags) { /* New style method: with flags parameter (and interactive bool in the bus message header) */ @@ -1882,7 +1884,7 @@ static int method_do_shutdown_or_sleep( return r; if ((flags & ~SD_LOGIND_SHUTDOWN_AND_SLEEP_FLAGS_PUBLIC) != 0) return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid flags parameter"); - if (!streq(unit_name, SPECIAL_REBOOT_TARGET) && (flags & SD_LOGIND_REBOOT_VIA_KEXEC)) + if (manager_handle_for_item(a) != HANDLE_REBOOT && (flags & SD_LOGIND_REBOOT_VIA_KEXEC)) return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Reboot via kexec is only applicable with reboot operations"); } else { /* Old style method: no flags parameter, but interactive bool passed as boolean in @@ -1898,31 +1900,39 @@ static int method_do_shutdown_or_sleep( } if ((flags & SD_LOGIND_REBOOT_VIA_KEXEC) && kexec_loaded()) - unit_name = SPECIAL_KEXEC_TARGET; + a = manager_item_for_handle(HANDLE_KEXEC); /* Don't allow multiple jobs being executed at the same time */ - if (m->action_what > 0) + if (m->delayed_action) return sd_bus_error_setf(error, BUS_ERROR_OPERATION_IN_PROGRESS, "There's already a shutdown or sleep operation in progress"); - if (sleep_operation >= 0) { - r = can_sleep(sleep_operation); + if (a->sleep_operation >= 0) { + r = can_sleep(a->sleep_operation); if (r == -ENOSPC) return sd_bus_error_set(error, BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED, "Not enough swap space for hibernation"); if (r == 0) return sd_bus_error_setf(error, BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED, - "Sleep verb \"%s\" not supported", sleep_operation_to_string(sleep_operation)); + "Sleep verb \"%s\" not supported", sleep_operation_to_string(a->sleep_operation)); if (r < 0) return r; } - r = verify_shutdown_creds(m, message, w, action, action_multiple_sessions, - action_ignore_inhibit, flags, error); + r = verify_shutdown_creds(m, message, a, flags, error); if (r != 0) return r; - r = bus_manager_shutdown_or_sleep_now_or_later(m, unit_name, w, error); + /* reset case we're shorting a scheduled shutdown */ + m->unlink_nologin = false; + reset_scheduled_shutdown(m); + + m->scheduled_shutdown_timeout = 0; + m->scheduled_shutdown_type = a; + + (void) setup_wall_message_timer(m, message); + + r = bus_manager_shutdown_or_sleep_now_or_later(m, a, error); if (r < 0) return r; @@ -1934,12 +1944,7 @@ static int method_poweroff(sd_bus_message *message, void *userdata, sd_bus_error return method_do_shutdown_or_sleep( m, message, - SPECIAL_POWEROFF_TARGET, - INHIBIT_SHUTDOWN, - "org.freedesktop.login1.power-off", - "org.freedesktop.login1.power-off-multiple-sessions", - "org.freedesktop.login1.power-off-ignore-inhibit", - _SLEEP_OPERATION_INVALID, + manager_item_for_handle(HANDLE_POWEROFF), sd_bus_message_is_method_call(message, NULL, "PowerOffWithFlags"), error); } @@ -1949,12 +1954,7 @@ static int method_reboot(sd_bus_message *message, void *userdata, sd_bus_error * return method_do_shutdown_or_sleep( m, message, - SPECIAL_REBOOT_TARGET, - INHIBIT_SHUTDOWN, - "org.freedesktop.login1.reboot", - "org.freedesktop.login1.reboot-multiple-sessions", - "org.freedesktop.login1.reboot-ignore-inhibit", - _SLEEP_OPERATION_INVALID, + manager_item_for_handle(HANDLE_REBOOT), sd_bus_message_is_method_call(message, NULL, "RebootWithFlags"), error); } @@ -1964,12 +1964,7 @@ static int method_halt(sd_bus_message *message, void *userdata, sd_bus_error *er return method_do_shutdown_or_sleep( m, message, - SPECIAL_HALT_TARGET, - INHIBIT_SHUTDOWN, - "org.freedesktop.login1.halt", - "org.freedesktop.login1.halt-multiple-sessions", - "org.freedesktop.login1.halt-ignore-inhibit", - _SLEEP_OPERATION_INVALID, + manager_item_for_handle(HANDLE_HALT), sd_bus_message_is_method_call(message, NULL, "HaltWithFlags"), error); } @@ -1979,12 +1974,7 @@ static int method_suspend(sd_bus_message *message, void *userdata, sd_bus_error return method_do_shutdown_or_sleep( m, message, - SPECIAL_SUSPEND_TARGET, - INHIBIT_SLEEP, - "org.freedesktop.login1.suspend", - "org.freedesktop.login1.suspend-multiple-sessions", - "org.freedesktop.login1.suspend-ignore-inhibit", - SLEEP_SUSPEND, + manager_item_for_handle(HANDLE_SUSPEND), sd_bus_message_is_method_call(message, NULL, "SuspendWithFlags"), error); } @@ -1994,12 +1984,7 @@ static int method_hibernate(sd_bus_message *message, void *userdata, sd_bus_erro return method_do_shutdown_or_sleep( m, message, - SPECIAL_HIBERNATE_TARGET, - INHIBIT_SLEEP, - "org.freedesktop.login1.hibernate", - "org.freedesktop.login1.hibernate-multiple-sessions", - "org.freedesktop.login1.hibernate-ignore-inhibit", - SLEEP_HIBERNATE, + manager_item_for_handle(HANDLE_HIBERNATE), sd_bus_message_is_method_call(message, NULL, "HibernateWithFlags"), error); } @@ -2009,12 +1994,7 @@ static int method_hybrid_sleep(sd_bus_message *message, void *userdata, sd_bus_e return method_do_shutdown_or_sleep( m, message, - SPECIAL_HYBRID_SLEEP_TARGET, - INHIBIT_SLEEP, - "org.freedesktop.login1.hibernate", - "org.freedesktop.login1.hibernate-multiple-sessions", - "org.freedesktop.login1.hibernate-ignore-inhibit", - SLEEP_HYBRID_SLEEP, + manager_item_for_handle(HANDLE_HYBRID_SLEEP), sd_bus_message_is_method_call(message, NULL, "HybridSleepWithFlags"), error); } @@ -2024,12 +2004,7 @@ static int method_suspend_then_hibernate(sd_bus_message *message, void *userdata return method_do_shutdown_or_sleep( m, message, - SPECIAL_SUSPEND_THEN_HIBERNATE_TARGET, - INHIBIT_SLEEP, - "org.freedesktop.login1.hibernate", - "org.freedesktop.login1.hibernate-multiple-sessions", - "org.freedesktop.login1.hibernate-ignore-inhibit", - SLEEP_SUSPEND_THEN_HIBERNATE, + manager_item_for_handle(HANDLE_SUSPEND_THEN_HIBERNATE), sd_bus_message_is_method_call(message, NULL, "SuspendThenHibernateWithFlags"), error); } @@ -2077,7 +2052,7 @@ static int update_schedule_file(Manager *m) { "MODE=%s\n", m->scheduled_shutdown_timeout, m->enable_wall_messages, - m->scheduled_shutdown_type); + handle_action_to_string(manager_handle_for_item(m->scheduled_shutdown_type))); if (!isempty(m->wall_message)) { _cleanup_free_ char *t = NULL; @@ -2116,8 +2091,7 @@ static void reset_scheduled_shutdown(Manager *m) { m->wall_message_timeout_source = sd_event_source_unref(m->wall_message_timeout_source); m->nologin_timeout_source = sd_event_source_unref(m->nologin_timeout_source); - m->scheduled_shutdown_type = mfree(m->scheduled_shutdown_type); - m->scheduled_shutdown_timeout = 0; + m->scheduled_shutdown_type = NULL; m->shutdown_dry_run = false; if (m->unlink_nologin) { @@ -2133,31 +2107,20 @@ static int manager_scheduled_shutdown_handler( uint64_t usec, void *userdata) { + const ActionTableItem *a = NULL; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; Manager *m = userdata; - const char *target; int r; assert(m); - if (isempty(m->scheduled_shutdown_type)) - return 0; - - if (streq(m->scheduled_shutdown_type, "poweroff")) - target = SPECIAL_POWEROFF_TARGET; - else if (streq(m->scheduled_shutdown_type, "reboot")) - target = SPECIAL_REBOOT_TARGET; - else if (streq(m->scheduled_shutdown_type, "kexec")) - target = SPECIAL_KEXEC_TARGET; - else if (streq(m->scheduled_shutdown_type, "halt")) - target = SPECIAL_HALT_TARGET; - else - assert_not_reached(); + a = m->scheduled_shutdown_type; + assert(a); /* Don't allow multiple jobs being executed at the same time */ - if (m->action_what > 0) { + if (m->delayed_action) { r = -EALREADY; - log_error("Scheduled shutdown to %s failed: shutdown or sleep operation already in progress", target); + log_error("Scheduled shutdown to %s failed: shutdown or sleep operation already in progress", a->target); goto error; } @@ -2167,16 +2130,16 @@ static int manager_scheduled_shutdown_handler( * above) for some seconds after our admin has seen the final * wall message. */ - bus_manager_log_shutdown(m, target); + bus_manager_log_shutdown(m, a); log_info("Running in dry run, suppressing action."); reset_scheduled_shutdown(m); return 0; } - r = bus_manager_shutdown_or_sleep_now_or_later(m, target, INHIBIT_SHUTDOWN, &error); + r = bus_manager_shutdown_or_sleep_now_or_later(m, m->scheduled_shutdown_type, &error); if (r < 0) { - log_error_errno(r, "Scheduled shutdown to %s failed: %m", target); + log_error_errno(r, "Scheduled shutdown to %s failed: %m", a->target); goto error; } @@ -2189,10 +2152,8 @@ error: static int method_schedule_shutdown(sd_bus_message *message, void *userdata, sd_bus_error *error) { Manager *m = userdata; - _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; - const char *action_multiple_sessions = NULL; - const char *action_ignore_inhibit = NULL; - const char *action = NULL; + HandleAction handle; + const ActionTableItem *a; uint64_t elapse; char *type; int r; @@ -2210,23 +2171,15 @@ static int method_schedule_shutdown(sd_bus_message *message, void *userdata, sd_ dry_run = true; } - if (streq(type, "poweroff")) { - action = "org.freedesktop.login1.power-off"; - action_multiple_sessions = "org.freedesktop.login1.power-off-multiple-sessions"; - action_ignore_inhibit = "org.freedesktop.login1.power-off-ignore-inhibit"; - } else if (STR_IN_SET(type, "reboot", "kexec")) { - action = "org.freedesktop.login1.reboot"; - action_multiple_sessions = "org.freedesktop.login1.reboot-multiple-sessions"; - action_ignore_inhibit = "org.freedesktop.login1.reboot-ignore-inhibit"; - } else if (streq(type, "halt")) { - action = "org.freedesktop.login1.halt"; - action_multiple_sessions = "org.freedesktop.login1.halt-multiple-sessions"; - action_ignore_inhibit = "org.freedesktop.login1.halt-ignore-inhibit"; - } else + handle = handle_action_from_string(type); + if (!IN_SET(handle, HANDLE_POWEROFF, HANDLE_REBOOT, HANDLE_HALT, HANDLE_KEXEC)) return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Unsupported shutdown type"); - r = verify_shutdown_creds(m, message, INHIBIT_SHUTDOWN, action, action_multiple_sessions, - action_ignore_inhibit, 0, error); + a = manager_item_for_handle(handle); + assert(a); + assert(a->polkit_action); + + r = verify_shutdown_creds(m, message, a, 0, error); if (r != 0) return r; @@ -2245,12 +2198,7 @@ static int method_schedule_shutdown(sd_bus_message *message, void *userdata, sd_ return log_error_errno(r, "sd_event_add_time() failed: %m"); } - r = free_and_strdup(&m->scheduled_shutdown_type, type); - if (r < 0) { - m->scheduled_shutdown_timeout_source = sd_event_source_unref(m->scheduled_shutdown_timeout_source); - return log_oom(); - } - + m->scheduled_shutdown_type = a; m->shutdown_dry_run = dry_run; if (m->nologin_timeout_source) { @@ -2270,23 +2218,11 @@ static int method_schedule_shutdown(sd_bus_message *message, void *userdata, sd_ m->scheduled_shutdown_timeout = elapse; - r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_AUGMENT|SD_BUS_CREDS_TTY|SD_BUS_CREDS_UID, &creds); - if (r >= 0) { - const char *tty = NULL; - - (void) sd_bus_creds_get_uid(creds, &m->scheduled_shutdown_uid); - (void) sd_bus_creds_get_tty(creds, &tty); - - r = free_and_strdup(&m->scheduled_shutdown_tty, tty); - if (r < 0) { - m->scheduled_shutdown_timeout_source = sd_event_source_unref(m->scheduled_shutdown_timeout_source); - return log_oom(); - } - } - - r = manager_setup_wall_message_timer(m); - if (r < 0) + r = setup_wall_message_timer(m, message); + if (r < 0) { + m->scheduled_shutdown_timeout_source = sd_event_source_unref(m->scheduled_shutdown_timeout_source); return r; + } r = update_schedule_file(m); if (r < 0) @@ -2297,20 +2233,42 @@ static int method_schedule_shutdown(sd_bus_message *message, void *userdata, sd_ static int method_cancel_scheduled_shutdown(sd_bus_message *message, void *userdata, sd_bus_error *error) { Manager *m = userdata; + const ActionTableItem *a; bool cancelled; + int r; assert(m); assert(message); - cancelled = m->scheduled_shutdown_type != NULL; + cancelled = !IN_SET(manager_handle_for_item(m->scheduled_shutdown_type), HANDLE_IGNORE, _HANDLE_ACTION_INVALID); + if (!cancelled) + goto done; + + a = m->scheduled_shutdown_type; + if (!a->polkit_action) + return sd_bus_error_set(error, SD_BUS_ERROR_AUTH_FAILED, "Unsupported shutdown type"); + + r = bus_verify_polkit_async( + message, + CAP_SYS_BOOT, + a->polkit_action, + NULL, + false, + UID_INVALID, + &m->polkit_registry, + error); + if (r < 0) + return r; + if (r == 0) + return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ + reset_scheduled_shutdown(m); - if (cancelled && m->enable_wall_messages) { + if (m->enable_wall_messages) { _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; _cleanup_free_ char *username = NULL; const char *tty = NULL; uid_t uid = 0; - int r; r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_AUGMENT|SD_BUS_CREDS_TTY|SD_BUS_CREDS_UID, &creds); if (r >= 0) { @@ -2323,21 +2281,17 @@ static int method_cancel_scheduled_shutdown(sd_bus_message *message, void *userd username, tty, logind_wall_tty_filter, m); } +done: return sd_bus_reply_method_return(message, "b", cancelled); } static int method_can_shutdown_or_sleep( Manager *m, sd_bus_message *message, - InhibitWhat w, - const char *action, - const char *action_multiple_sessions, - const char *action_ignore_inhibit, - SleepOperation sleep_operation, + const ActionTableItem *a, sd_bus_error *error) { _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; - HandleAction handle; bool multiple_sessions, challenge, blocked; const char *result = NULL; uid_t uid; @@ -2345,14 +2299,10 @@ static int method_can_shutdown_or_sleep( assert(m); assert(message); - assert(w >= 0); - assert(w <= _INHIBIT_WHAT_MAX); - assert(action); - assert(action_multiple_sessions); - assert(action_ignore_inhibit); - - if (sleep_operation >= 0) { - r = can_sleep(sleep_operation); + assert(a); + + if (a->sleep_operation >= 0) { + r = can_sleep(a->sleep_operation); if (IN_SET(r, 0, -ENOSPC)) return sd_bus_reply_method_return(message, "s", "na"); if (r < 0) @@ -2372,9 +2322,9 @@ static int method_can_shutdown_or_sleep( return r; multiple_sessions = r > 0; - blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, uid, NULL); + blocked = manager_is_inhibited(m, a->inhibit_what, INHIBIT_BLOCK, NULL, false, true, uid, NULL); - handle = handle_action_from_string(sleep_operation_to_string(sleep_operation)); + HandleAction handle = handle_action_from_string(sleep_operation_to_string(a->sleep_operation)); if (handle >= 0) { const char *target; @@ -2394,7 +2344,7 @@ static int method_can_shutdown_or_sleep( } if (multiple_sessions) { - r = bus_test_polkit(message, CAP_SYS_BOOT, action_multiple_sessions, NULL, UID_INVALID, &challenge, error); + r = bus_test_polkit(message, CAP_SYS_BOOT, a->polkit_action_multiple_sessions, NULL, UID_INVALID, &challenge, error); if (r < 0) return r; @@ -2407,7 +2357,7 @@ static int method_can_shutdown_or_sleep( } if (blocked) { - r = bus_test_polkit(message, CAP_SYS_BOOT, action_ignore_inhibit, NULL, UID_INVALID, &challenge, error); + r = bus_test_polkit(message, CAP_SYS_BOOT, a->polkit_action_ignore_inhibit, NULL, UID_INVALID, &challenge, error); if (r < 0) return r; @@ -2425,7 +2375,7 @@ static int method_can_shutdown_or_sleep( /* If neither inhibit nor multiple sessions * apply then just check the normal policy */ - r = bus_test_polkit(message, CAP_SYS_BOOT, action, NULL, UID_INVALID, &challenge, error); + r = bus_test_polkit(message, CAP_SYS_BOOT, a->polkit_action, NULL, UID_INVALID, &challenge, error); if (r < 0) return r; @@ -2445,12 +2395,7 @@ static int method_can_poweroff(sd_bus_message *message, void *userdata, sd_bus_e Manager *m = userdata; return method_can_shutdown_or_sleep( - m, message, - INHIBIT_SHUTDOWN, - "org.freedesktop.login1.power-off", - "org.freedesktop.login1.power-off-multiple-sessions", - "org.freedesktop.login1.power-off-ignore-inhibit", - _SLEEP_OPERATION_INVALID, + m, message, manager_item_for_handle(HANDLE_POWEROFF), error); } @@ -2458,12 +2403,7 @@ static int method_can_reboot(sd_bus_message *message, void *userdata, sd_bus_err Manager *m = userdata; return method_can_shutdown_or_sleep( - m, message, - INHIBIT_SHUTDOWN, - "org.freedesktop.login1.reboot", - "org.freedesktop.login1.reboot-multiple-sessions", - "org.freedesktop.login1.reboot-ignore-inhibit", - _SLEEP_OPERATION_INVALID, + m, message, manager_item_for_handle(HANDLE_REBOOT), error); } @@ -2471,12 +2411,7 @@ static int method_can_halt(sd_bus_message *message, void *userdata, sd_bus_error Manager *m = userdata; return method_can_shutdown_or_sleep( - m, message, - INHIBIT_SHUTDOWN, - "org.freedesktop.login1.halt", - "org.freedesktop.login1.halt-multiple-sessions", - "org.freedesktop.login1.halt-ignore-inhibit", - _SLEEP_OPERATION_INVALID, + m, message, manager_item_for_handle(HANDLE_HALT), error); } @@ -2484,12 +2419,7 @@ static int method_can_suspend(sd_bus_message *message, void *userdata, sd_bus_er Manager *m = userdata; return method_can_shutdown_or_sleep( - m, message, - INHIBIT_SLEEP, - "org.freedesktop.login1.suspend", - "org.freedesktop.login1.suspend-multiple-sessions", - "org.freedesktop.login1.suspend-ignore-inhibit", - SLEEP_SUSPEND, + m, message, manager_item_for_handle(HANDLE_SUSPEND), error); } @@ -2497,12 +2427,7 @@ static int method_can_hibernate(sd_bus_message *message, void *userdata, sd_bus_ Manager *m = userdata; return method_can_shutdown_or_sleep( - m, message, - INHIBIT_SLEEP, - "org.freedesktop.login1.hibernate", - "org.freedesktop.login1.hibernate-multiple-sessions", - "org.freedesktop.login1.hibernate-ignore-inhibit", - SLEEP_HIBERNATE, + m, message, manager_item_for_handle(HANDLE_HIBERNATE), error); } @@ -2510,12 +2435,7 @@ static int method_can_hybrid_sleep(sd_bus_message *message, void *userdata, sd_b Manager *m = userdata; return method_can_shutdown_or_sleep( - m, message, - INHIBIT_SLEEP, - "org.freedesktop.login1.hibernate", - "org.freedesktop.login1.hibernate-multiple-sessions", - "org.freedesktop.login1.hibernate-ignore-inhibit", - SLEEP_HYBRID_SLEEP, + m, message, manager_item_for_handle(HANDLE_HYBRID_SLEEP), error); } @@ -2523,12 +2443,7 @@ static int method_can_suspend_then_hibernate(sd_bus_message *message, void *user Manager *m = userdata; return method_can_shutdown_or_sleep( - m, message, - INHIBIT_SLEEP, - "org.freedesktop.login1.hibernate", - "org.freedesktop.login1.hibernate-multiple-sessions", - "org.freedesktop.login1.hibernate-ignore-inhibit", - SLEEP_SUSPEND_THEN_HIBERNATE, + m, message, manager_item_for_handle(HANDLE_SUSPEND_THEN_HIBERNATE), error); } @@ -3200,6 +3115,15 @@ static int method_set_wall_message( if (r < 0) return r; + /* sysvinit has a 252 (256-(strlen(" \r\n")+1)) character + * limit for the wall message. There is no real technical + * need for that but doesn't make sense to store arbitrary + * armounts either. + * https://git.savannah.nongnu.org/cgit/sysvinit.git/tree/src/shutdown.c#n72) + */ + if (strlen(wall_message) > 252) + return -EMSGSIZE; + /* Short-circuit the operation if the desired state is already in place, to * avoid an unnecessary polkit permission check. */ if (streq_ptr(m->wall_message, empty_to_null(wall_message)) && @@ -3267,7 +3191,7 @@ static int method_inhibit(sd_bus_message *message, void *userdata, sd_bus_error * executing the operation. We shouldn't create the impression * that the lock was successful if the machine is about to go * down/suspend any moment. */ - if (m->action_what & w) + if (m->delayed_action && m->delayed_action->inhibit_what & w) return sd_bus_error_setf(error, BUS_ERROR_OPERATION_IN_PROGRESS, "The operation inhibition has been requested for is already running"); @@ -3774,14 +3698,14 @@ int match_job_removed(sd_bus_message *message, void *userdata, sd_bus_error *err } if (m->action_job && streq(m->action_job, path)) { - log_info("Operation '%s' finished.", inhibit_what_to_string(m->action_what)); + assert(m->delayed_action); + log_info("Operation '%s' finished.", inhibit_what_to_string(m->delayed_action->inhibit_what)); /* Tell people that they now may take a lock again */ - (void) send_prepare_for(m, m->action_what, false); + (void) send_prepare_for(m, m->delayed_action->inhibit_what, false); m->action_job = mfree(m->action_job); - m->action_unit = NULL; - m->action_what = 0; + m->delayed_action = NULL; return 0; } diff --git a/src/login/logind-dbus.h b/src/login/logind-dbus.h index 6b5d3abcd6..13aff11bba 100644 --- a/src/login/logind-dbus.h +++ b/src/login/logind-dbus.h @@ -4,6 +4,7 @@ #include "sd-bus.h" #include "bus-object.h" +#include "logind-action.h" #include "logind-session.h" #include "logind-user.h" #include "logind.h" @@ -14,7 +15,7 @@ int manager_get_seat_from_creds(Manager *m, sd_bus_message *message, const char int manager_dispatch_delayed(Manager *manager, bool timeout); -int bus_manager_shutdown_or_sleep_now_or_later(Manager *m, const char *unit_name, InhibitWhat w, sd_bus_error *error); +int bus_manager_shutdown_or_sleep_now_or_later(Manager *m, const ActionTableItem *a, sd_bus_error *error); int match_job_removed(sd_bus_message *message, void *userdata, sd_bus_error *error); int match_unit_removed(sd_bus_message *message, void *userdata, sd_bus_error *error); diff --git a/src/login/logind-utmp.c b/src/login/logind-utmp.c index 5533836473..03817f9c1a 100644 --- a/src/login/logind-utmp.c +++ b/src/login/logind-utmp.c @@ -72,7 +72,7 @@ static int warn_wall(Manager *m, usec_t n) { r = asprintf(&l, "%s%sThe system is going down for %s %s%s!", strempty(m->wall_message), isempty(m->wall_message) ? "" : "\n", - m->scheduled_shutdown_type, + handle_action_to_string(manager_handle_for_item(m->scheduled_shutdown_type)), left ? "at " : "NOW", left ? FORMAT_TIMESTAMP(m->scheduled_shutdown_timeout) : ""); if (r < 0) { @@ -130,16 +130,14 @@ int manager_setup_wall_message_timer(Manager *m) { /* wall message handling */ - if (isempty(m->scheduled_shutdown_type)) { - warn_wall(m, n); + if (!m->scheduled_shutdown_type) return 0; - } - if (elapse < n) + if (elapse > 0 && elapse < n) return 0; /* Warn immediately if less than 15 minutes are left */ - if (elapse - n < 15 * USEC_PER_MINUTE) { + if (elapse == 0 || elapse - n < 15 * USEC_PER_MINUTE) { r = warn_wall(m, n); if (r == 0) return 0; diff --git a/src/login/logind.c b/src/login/logind.c index 52b1d95034..c561b75951 100644 --- a/src/login/logind.c +++ b/src/login/logind.c @@ -54,6 +54,7 @@ static int manager_new(Manager **ret) { *m = (Manager) { .console_active_fd = -1, .reserve_vt_fd = -1, + .enable_wall_messages = true, .idle_action_not_before_usec = now(CLOCK_MONOTONIC), }; @@ -167,7 +168,6 @@ static Manager* manager_unref(Manager *m) { strv_free(m->kill_only_users); strv_free(m->kill_exclude_users); - free(m->scheduled_shutdown_type); free(m->scheduled_shutdown_tty); free(m->wall_message); free(m->action_job); diff --git a/src/login/logind.h b/src/login/logind.h index 730c14a46a..5647e5069c 100644 --- a/src/login/logind.h +++ b/src/login/logind.h @@ -68,21 +68,17 @@ struct Manager { usec_t inhibit_delay_max; usec_t user_stop_delay; - /* If an action is currently being executed or is delayed, - * this is != 0 and encodes what is being done */ - InhibitWhat action_what; - /* If a shutdown/suspend was delayed due to an inhibitor this - contains the unit name we are supposed to start after the + contains the action we are supposed to start after the delay is over */ - const char *action_unit; + const ActionTableItem *delayed_action; /* If a shutdown/suspend is currently executed, then this is * the job of it */ char *action_job; sd_event_source *inhibit_timeout_source; - char *scheduled_shutdown_type; + const ActionTableItem *scheduled_shutdown_type; usec_t scheduled_shutdown_timeout; sd_event_source *scheduled_shutdown_timeout_source; uid_t scheduled_shutdown_uid; diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 1f5f4bd41a..ab4f321b00 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -1026,8 +1026,7 @@ static Link *link_drop(Link *link) { hashmap_remove(link->manager->links_by_name, link->ifname); /* bonding master and its slaves have the same hardware address. */ - if (hashmap_get(link->manager->links_by_hw_addr, &link->hw_addr) == link) - hashmap_remove(link->manager->links_by_hw_addr, &link->hw_addr); + hashmap_remove_value(link->manager->links_by_hw_addr, &link->hw_addr, link); /* The following must be called at last. */ assert_se(hashmap_remove(link->manager->links_by_index, INT_TO_PTR(link->ifindex)) == link); @@ -1775,7 +1774,7 @@ static int link_admin_state_up(Link *link) { return 0; if (link->activated && link->network->activation_policy == ACTIVATION_POLICY_ALWAYS_DOWN) { - log_link_info(link, "ActivationPolicy is \"always-off\", forcing link down."); + log_link_info(link, "Activation policy is \"always-down\", forcing link down."); return link_request_to_bring_up_or_down(link, /* up = */ false); } @@ -1795,7 +1794,7 @@ static int link_admin_state_down(Link *link) { return 0; if (link->activated && link->network->activation_policy == ACTIVATION_POLICY_ALWAYS_UP) { - log_link_info(link, "ActivationPolicy is \"always-on\", forcing link up."); + log_link_info(link, "Activation policy is \"always-up\", forcing link up."); return link_request_to_bring_up_or_down(link, /* up = */ true); } @@ -2148,8 +2147,7 @@ static int link_update_hardware_address(Link *link, sd_netlink_message *message) log_link_debug(link, "Hardware address is changed: %s → %s", HW_ADDR_TO_STR(&link->hw_addr), HW_ADDR_TO_STR(&addr)); - if (hashmap_get(link->manager->links_by_hw_addr, &link->hw_addr) == link) - hashmap_remove(link->manager->links_by_hw_addr, &link->hw_addr); + hashmap_remove_value(link->manager->links_by_hw_addr, &link->hw_addr, link); } link->hw_addr = addr; diff --git a/src/resolve/test-resolved-stream.c b/src/resolve/test-resolved-stream.c index 8a01460a0e..f9428989f0 100644 --- a/src/resolve/test-resolved-stream.c +++ b/src/resolve/test-resolved-stream.c @@ -130,7 +130,7 @@ static void *tls_dns_server(void *p) { assert_se(in_addr_to_string(SERVER_ADDRESS.sin_family, &(union in_addr_union){.in = SERVER_ADDRESS.sin_addr}, &ip_str) >= 0); - asprintf(&bind_str, "%s:%d", ip_str, be16toh(SERVER_ADDRESS.sin_port)); + assert_se(asprintf(&bind_str, "%s:%d", ip_str, be16toh(SERVER_ADDRESS.sin_port)) >= 0); /* We will hook one of the socketpair ends to OpenSSL's TLS server * stdin/stdout, so we will be able to read and write plaintext diff --git a/src/shared/copy.c b/src/shared/copy.c index a92cfc0f61..0941706356 100644 --- a/src/shared/copy.c +++ b/src/shared/copy.c @@ -119,9 +119,11 @@ static int create_hole(int fd, off_t size) { if (end < 0) return -errno; - /* If we're not at the end of the target file, punch a hole in the existing space using fallocate(). */ + /* If we're not at the end of the target file, try to punch a hole in the existing space using fallocate(). */ - if (offset < end && fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, offset, MIN(size, end - offset)) < 0) + if (offset < end && + fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, offset, MIN(size, end - offset)) < 0 && + !ERRNO_IS_NOT_SUPPORTED(errno)) return -errno; if (end - offset >= size) { diff --git a/src/shared/main-func.h b/src/shared/main-func.h index 05cdffeec0..81a5c1813c 100644 --- a/src/shared/main-func.h +++ b/src/shared/main-func.h @@ -15,6 +15,7 @@ #define _DEFINE_MAIN_FUNCTION(intro, impl, ret) \ int main(int argc, char *argv[]) { \ int r; \ + assert_se(argc > 0 && !isempty(argv[0])); \ save_argc_argv(argc, argv); \ intro; \ r = impl; \ diff --git a/src/shared/selinux-util.c b/src/shared/selinux-util.c index a1359a5bfd..67ea858142 100644 --- a/src/shared/selinux-util.c +++ b/src/shared/selinux-util.c @@ -346,7 +346,7 @@ int mac_selinux_apply_fd(int fd, const char *path, const char *label) { assert(label); - if (fsetfilecon(fd, label) < 0) + if (setfilecon(FORMAT_PROC_FD_PATH(fd), label) < 0) return log_enforcing_errno(errno, "Failed to set SELinux security context %s on path %s: %m", label, strna(path)); #endif return 0; diff --git a/src/shared/smack-util.c b/src/shared/smack-util.c index b8434b068c..0df1778cb2 100644 --- a/src/shared/smack-util.c +++ b/src/shared/smack-util.c @@ -95,9 +95,9 @@ int mac_smack_apply_fd(int fd, SmackAttr attr, const char *label) { return 0; if (label) - r = fsetxattr(fd, smack_attr_to_string(attr), label, strlen(label), 0); + r = setxattr(FORMAT_PROC_FD_PATH(fd), smack_attr_to_string(attr), label, strlen(label), 0); else - r = fremovexattr(fd, smack_attr_to_string(attr)); + r = removexattr(FORMAT_PROC_FD_PATH(fd), smack_attr_to_string(attr)); if (r < 0) return -errno; diff --git a/src/systemctl/systemctl-compat-halt.c b/src/systemctl/systemctl-compat-halt.c index 760758322f..a7d3ffadf4 100644 --- a/src/systemctl/systemctl-compat-halt.c +++ b/src/systemctl/systemctl-compat-halt.c @@ -144,35 +144,23 @@ int halt_parse_argv(int argc, char *argv[]) { int halt_main(void) { int r; - r = logind_check_inhibitors(arg_action); - if (r < 0) - return r; - - /* Delayed shutdown requested, and was successful */ - if (arg_when > 0 && logind_schedule_shutdown() == 0) - return 0; - - /* No delay, or logind failed or is not at all available */ - if (geteuid() != 0) { - if (arg_dry_run || arg_force > 0) { - (void) must_be_root(); - return -EPERM; - } + /* always try logind first */ + if (arg_when > 0) + r = logind_schedule_shutdown(); + else { + r = logind_check_inhibitors(arg_action); + if (r < 0) + return r; - /* Try logind if we are a normal user and no special mode applies. Maybe polkit allows us to - * shutdown the machine. */ - if (IN_SET(arg_action, ACTION_POWEROFF, ACTION_REBOOT, ACTION_KEXEC, ACTION_HALT)) { - r = logind_reboot(arg_action); - if (r >= 0) - return r; - if (IN_SET(r, -EOPNOTSUPP, -EINPROGRESS)) - /* Requested operation is not supported on the local system or already in - * progress */ - return r; - - /* on all other errors, try low-level operation */ - } + r = logind_reboot(arg_action); } + if (r >= 0) + return r; + if (IN_SET(r, -EACCES, -EOPNOTSUPP, -EINPROGRESS)) + /* Requested operation requires auth, is not supported on the local system or already in + * progress */ + return r; + /* on all other errors, try low-level operation */ /* In order to minimize the difference between operation with and without logind, we explicitly * enable non-blocking mode for this, as logind's shutdown operations are always non-blocking. */ @@ -181,7 +169,10 @@ int halt_main(void) { if (!arg_dry_run && !arg_force) return start_with_fallback(); - assert(geteuid() == 0); + if (geteuid() != 0) { + (void) must_be_root(); + return -EPERM; + } if (!arg_no_wtmp) { if (sd_booted() > 0) diff --git a/src/systemctl/systemctl-logind.c b/src/systemctl/systemctl-logind.c index 9eae59ca31..9bf24ed554 100644 --- a/src/systemctl/systemctl-logind.c +++ b/src/systemctl/systemctl-logind.c @@ -330,7 +330,7 @@ int logind_schedule_shutdown(void) { r = bus_call_method(bus, bus_login_mgr, "ScheduleShutdown", &error, NULL, "st", action, arg_when); if (r < 0) - return log_warning_errno(r, "Failed to call ScheduleShutdown in logind, proceeding with immediate shutdown: %s", bus_error_message(&error, r)); + return log_warning_errno(r, "Failed to schedule shutdown: %s", bus_error_message(&error, r)); if (!arg_quiet) logind_show_shutdown(); diff --git a/src/systemctl/systemctl-start-special.c b/src/systemctl/systemctl-start-special.c index 6ece700a9b..08eefc473e 100644 --- a/src/systemctl/systemctl-start-special.c +++ b/src/systemctl/systemctl-start-special.c @@ -213,8 +213,8 @@ int start_special(int argc, char *argv[], void *userdata) { r = logind_reboot(a); if (r >= 0) return r; - if (IN_SET(r, -EOPNOTSUPP, -EINPROGRESS)) - /* Requested operation is not supported or already in progress */ + if (IN_SET(r, -EACCES, -EOPNOTSUPP, -EINPROGRESS)) + /* Requested operation requires auth, is not supported or already in progress */ return r; /* On all other errors, try low-level operation. In order to minimize the difference diff --git a/src/test/test-load-fragment.c b/src/test/test-load-fragment.c index 68172be43e..9e5ae85597 100644 --- a/src/test/test-load-fragment.c +++ b/src/test/test-load-fragment.c @@ -803,7 +803,7 @@ TEST(config_parse_unit_env_file) { "EnvironmentFile", 0, "not-absolute", &files, u); assert_se(r == 0); - assert_se(strv_length(files) == 0); + assert_se(strv_isempty(files)); r = config_parse_unit_env_file(u->id, "fake", 1, "section", 1, "EnvironmentFile", 0, "/absolute1", |