From 15b5bb626256ed7ed32f537e06f6150bef0fe462 Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Fri, 3 Nov 2023 20:43:18 +0800 Subject: [PATCH 1/5] TODO: remove an already implemented entry Follow-up for #23640 --- TODO | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/TODO b/TODO index 4e216a2cf4a..6882a1b2215 100644 --- a/TODO +++ b/TODO @@ -1442,21 +1442,6 @@ Features: * teach parse_timestamp() timezones like the calendar spec already knows it -* beef up s2h to implement a battery watch loop: instead of entering - hibernation unconditionally after coming back from resume make a decision - based on the battery load level: if battery level is above a specific - threshold, go to suspend again, only hibernate if below it. This means we'd - stick to suspend usually, but fall back to hibernation only when battery runs - empty (well, subject to our sampling interval). Related to this, check if we - can make ACPI _BTP (i.e. /sys/class/power_supply/*/alarm) work for us too, - i.e. see if it can wake up machines from suspend, so that we could resume - automatically when the system is low on power and move automatically to - hibernation mode. (see - https://uefi.org/sites/default/files/resources/ACPI%206_2_A_Sept29.pdf - section 10.2.2.8 and - https://docs.microsoft.com/en-us/windows-hardware/design/device-experiences/modern-standby-wake-sources - at the end). - * We should probably replace /etc/rc.d/README with a symlink to doc content. After all it is constant vendor data. From 51eeeb7bde2db84d2892eef4a8bf93896feeb985 Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Tue, 31 Oct 2023 21:08:19 +0800 Subject: [PATCH 2/5] logind: return "no" if sleep operation is disabled According to org.freedesktop.login1: > If "na" is returned, the operation is not available because > hardware, kernel, or drivers do not support it. If "yes" is > returned, the operation is supported and the user may execute > the operation without further authentication. If "no" is returned, > the operation is available but the user is not allowed to execute > the operation. Therefore, we should return "no" if sleep is explicitly disabled, otherwise we return "na". --- src/login/logind-dbus.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index 6ad6ef912db..ec88c55a089 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -2543,11 +2543,13 @@ static int method_can_shutdown_or_sleep( assert(a); if (a->sleep_operation >= 0) { - r = sleep_supported(a->sleep_operation); + SleepSupport support; + + r = sleep_supported_full(a->sleep_operation, &support); if (r < 0) return r; if (r == 0) - return sd_bus_reply_method_return(message, "s", "na"); + return sd_bus_reply_method_return(message, "s", support == SLEEP_DISABLED ? "no" : "na"); } r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds); From ddd0c2be81c5f432ef6923871089d09192c50476 Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Thu, 2 Nov 2023 18:23:21 +0800 Subject: [PATCH 3/5] logind-action: split out logic for handle_action_sleep Preparation for #29853 --- src/login/logind-action.c | 158 ++++++++++++++++++++++---------------- 1 file changed, 93 insertions(+), 65 deletions(-) diff --git a/src/login/logind-action.c b/src/login/logind-action.c index d4d53bddd70..c1d60af7591 100644 --- a/src/login/logind-action.c +++ b/src/login/logind-action.c @@ -133,9 +133,8 @@ const HandleActionData* handle_action_lookup(HandleAction action) { return &handle_action_data_table[action]; } -int manager_handle_action( +static int handle_action_execute( Manager *m, - InhibitWhat inhibit_key, HandleAction handle, bool ignore_inhibited, bool is_edge) { @@ -156,73 +155,11 @@ int manager_handle_action( _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; InhibitWhat inhibit_operation; Inhibitor *offending = NULL; - bool supported; int r; assert(m); - /* If the key handling is turned off, don't do anything */ - if (handle == HANDLE_IGNORE) { - log_debug("Handling of %s (%s) is disabled, taking no action.", - inhibit_key == 0 ? "idle timeout" : inhibit_what_to_string(inhibit_key), - is_edge ? "edge" : "level"); - return 0; - } - - if (inhibit_key == INHIBIT_HANDLE_LID_SWITCH) { - /* If the last system suspend or startup is too close, - * let's not suspend for now, to give USB docking - * stations some time to settle so that we can - * properly watch its displays. */ - if (m->lid_switch_ignore_event_source) { - log_debug("Ignoring lid switch request, system startup or resume too close."); - return 0; - } - } - - /* If the key handling is inhibited, don't do anything */ - if (inhibit_key > 0) { - if (manager_is_inhibited(m, inhibit_key, INHIBIT_BLOCK, NULL, true, false, 0, NULL)) { - log_debug("Refusing %s operation, %s is inhibited.", - handle_action_to_string(handle), - inhibit_what_to_string(inhibit_key)); - return 0; - } - } - - /* Locking is handled differently from the rest. */ - if (handle == HANDLE_LOCK) { - if (!is_edge) - return 0; - - log_info("Locking sessions..."); - session_send_lock_all(m, true); - return 1; - } - - if (handle == HANDLE_SUSPEND) - supported = sleep_supported(SLEEP_SUSPEND) > 0; - else if (handle == HANDLE_HIBERNATE) - supported = sleep_supported(SLEEP_HIBERNATE) > 0; - else if (handle == HANDLE_HYBRID_SLEEP) - supported = sleep_supported(SLEEP_HYBRID_SLEEP) > 0; - else if (handle == HANDLE_SUSPEND_THEN_HIBERNATE) - supported = sleep_supported(SLEEP_SUSPEND_THEN_HIBERNATE) > 0; - else if (handle == HANDLE_KEXEC) - supported = access(KEXEC, X_OK) >= 0; - else - supported = true; - - if (!supported && HANDLE_ACTION_IS_SLEEP(handle) && handle != HANDLE_SUSPEND) { - supported = sleep_supported(SLEEP_SUSPEND) > 0; - if (supported) { - log_notice("Requested %s operation is not supported, using regular suspend instead.", - handle_action_to_string(handle)); - handle = HANDLE_SUSPEND; - } - } - - if (!supported) + if (handle == HANDLE_KEXEC && access(KEXEC, X_OK) < 0) return log_warning_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Requested %s operation not supported, ignoring.", handle_action_to_string(handle)); @@ -264,6 +201,97 @@ int manager_handle_action( return 1; } +static int handle_action_sleep_execute( + Manager *m, + HandleAction handle, + bool ignore_inhibited, + bool is_edge) { + + bool supported; + + assert(m); + assert(HANDLE_ACTION_IS_SLEEP(handle)); + + if (handle == HANDLE_SUSPEND) + supported = sleep_supported(SLEEP_SUSPEND) > 0; + else if (handle == HANDLE_HIBERNATE) + supported = sleep_supported(SLEEP_HIBERNATE) > 0; + else if (handle == HANDLE_HYBRID_SLEEP) + supported = sleep_supported(SLEEP_HYBRID_SLEEP) > 0; + else if (handle == HANDLE_SUSPEND_THEN_HIBERNATE) + supported = sleep_supported(SLEEP_SUSPEND_THEN_HIBERNATE) > 0; + else + assert_not_reached(); + + if (!supported && handle != HANDLE_SUSPEND) { + supported = sleep_supported(SLEEP_SUSPEND) > 0; + if (supported) { + log_notice("Requested %s operation is not supported, using regular suspend instead.", + handle_action_to_string(handle)); + handle = HANDLE_SUSPEND; + } + } + + if (!supported) + return log_warning_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), + "Requested %s operation not supported, ignoring.", handle_action_to_string(handle)); + + return handle_action_execute(m, handle, ignore_inhibited, is_edge); +} + +int manager_handle_action( + Manager *m, + InhibitWhat inhibit_key, + HandleAction handle, + bool ignore_inhibited, + bool is_edge) { + + assert(m); + assert(handle_action_valid(handle)); + + /* If the key handling is turned off, don't do anything */ + if (handle == HANDLE_IGNORE) { + log_debug("Handling of %s (%s) is disabled, taking no action.", + inhibit_key == 0 ? "idle timeout" : inhibit_what_to_string(inhibit_key), + is_edge ? "edge" : "level"); + return 0; + } + + if (inhibit_key == INHIBIT_HANDLE_LID_SWITCH) { + /* If the last system suspend or startup is too close, let's not suspend for now, to give + * USB docking stations some time to settle so that we can properly watch its displays. */ + if (m->lid_switch_ignore_event_source) { + log_debug("Ignoring lid switch request, system startup or resume too close."); + return 0; + } + } + + /* If the key handling is inhibited, don't do anything */ + if (inhibit_key > 0) { + if (manager_is_inhibited(m, inhibit_key, INHIBIT_BLOCK, NULL, true, false, 0, NULL)) { + log_debug("Refusing %s operation, %s is inhibited.", + handle_action_to_string(handle), + inhibit_what_to_string(inhibit_key)); + return 0; + } + } + + /* Locking is handled differently from the rest. */ + if (handle == HANDLE_LOCK) { + if (!is_edge) + return 0; + + log_info("Locking sessions..."); + session_send_lock_all(m, true); + return 1; + } + + if (HANDLE_ACTION_IS_SLEEP(handle)) + return handle_action_sleep_execute(m, handle, ignore_inhibited, is_edge); + + return handle_action_execute(m, handle, ignore_inhibited, is_edge); +} + static const char* const handle_action_verb_table[_HANDLE_ACTION_MAX] = { [HANDLE_IGNORE] = "do nothing", [HANDLE_POWEROFF] = "power off", From febe81313e828f9ca3df14f43eeef4dfe709589c Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Thu, 16 Nov 2023 17:46:56 +0800 Subject: [PATCH 4/5] logind-inhibit: introduce inhibit_what_is_valid --- src/login/logind-inhibit.c | 5 +++-- src/login/logind-inhibit.h | 4 ++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/login/logind-inhibit.c b/src/login/logind-inhibit.c index af7879f5616..1566dab0b6c 100644 --- a/src/login/logind-inhibit.c +++ b/src/login/logind-inhibit.c @@ -411,7 +411,8 @@ bool manager_is_inhibited( bool inhibited = false; assert(m); - assert(w > 0 && w < _INHIBIT_WHAT_MAX); + assert(w > 0); + assert(w < _INHIBIT_WHAT_MAX); HASHMAP_FOREACH(i, m->inhibitors) { if (!i->started) @@ -457,7 +458,7 @@ const char *inhibit_what_to_string(InhibitWhat w) { "handle-reboot-key")+1]; char *p; - if (w < 0 || w >= _INHIBIT_WHAT_MAX) + if (!inhibit_what_is_valid(w)) return NULL; p = buffer; diff --git a/src/login/logind-inhibit.h b/src/login/logind-inhibit.h index 6435d41f819..c34c2256768 100644 --- a/src/login/logind-inhibit.h +++ b/src/login/logind-inhibit.h @@ -68,6 +68,10 @@ bool inhibitor_is_orphan(Inhibitor *i); InhibitWhat manager_inhibit_what(Manager *m, InhibitMode mm); bool manager_is_inhibited(Manager *m, InhibitWhat w, InhibitMode mm, dual_timestamp *since, bool ignore_inactive, bool ignore_uid, uid_t uid, Inhibitor **offending); +static inline bool inhibit_what_is_valid(InhibitWhat w) { + return w > 0 && w < _INHIBIT_WHAT_MAX; +} + const char *inhibit_what_to_string(InhibitWhat k); int inhibit_what_from_string(const char *s); From 99416b6d4e14163993f2578e1d1579972332c5d5 Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Thu, 16 Nov 2023 17:47:47 +0800 Subject: [PATCH 5/5] logind-action: check if inhibit_what is valid Fixes #30037 --- src/login/logind-action.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/login/logind-action.c b/src/login/logind-action.c index c1d60af7591..e678edd66fb 100644 --- a/src/login/logind-action.c +++ b/src/login/logind-action.c @@ -172,7 +172,8 @@ static int handle_action_execute( inhibit_operation = handle_action_lookup(handle)->inhibit_what; /* If the actual operation is inhibited, warn and fail */ - if (!ignore_inhibited && + if (inhibit_what_is_valid(inhibit_operation) && + !ignore_inhibited && manager_is_inhibited(m, inhibit_operation, INHIBIT_BLOCK, NULL, false, false, 0, &offending)) { _cleanup_free_ char *comm = NULL, *u = NULL;