Merge pull request #30055 from YHNdnzj/logind-handle-action

logind-action: several cleanups
This commit is contained in:
Luca Boccassi 2023-11-16 16:04:37 +00:00 committed by GitHub
commit 905dd9d6e6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 106 additions and 85 deletions

15
TODO
View file

@ -1454,21 +1454,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.

View file

@ -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));
@ -235,7 +172,8 @@ int manager_handle_action(
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;
@ -264,6 +202,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",

View file

@ -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);

View file

@ -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;

View file

@ -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);