logind-action.c revision 15411c0cb1192799b37ec8f25d6f30e8d7292fc6
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster/***
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster This file is part of systemd.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster Copyright 2012 Lennart Poettering
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster systemd is free software; you can redistribute it and/or modify it
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster under the terms of the GNU Lesser General Public License as published by
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster the Free Software Foundation; either version 2.1 of the License, or
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster (at your option) any later version.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster systemd is distributed in the hope that it will be useful, but
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster WITHOUT ANY WARRANTY; without even the implied warranty of
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster Lesser General Public License for more details.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster You should have received a copy of the GNU Lesser General Public License
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster along with systemd; If not, see <http://www.gnu.org/licenses/>.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster***/
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster#include <unistd.h>
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster#include "conf-parser.h"
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster#include "special.h"
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster#include "sleep-config.h"
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster#include "bus-util.h"
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster#include "bus-error.h"
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster#include "logind-action.h"
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Fosterint manager_handle_action(
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster Manager *m,
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster InhibitWhat inhibit_key,
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster HandleAction handle,
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster bool ignore_inhibited,
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster bool is_edge) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster static const char * const message_table[_HANDLE_ACTION_MAX] = {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster [HANDLE_POWEROFF] = "Powering Off...",
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster [HANDLE_REBOOT] = "Rebooting...",
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster [HANDLE_HALT] = "Halting...",
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster [HANDLE_KEXEC] = "Rebooting via kexec...",
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster [HANDLE_SUSPEND] = "Suspending...",
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster [HANDLE_HIBERNATE] = "Hibernating...",
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster [HANDLE_HYBRID_SLEEP] = "Hibernating and suspending..."
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster };
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster static const char * const target_table[_HANDLE_ACTION_MAX] = {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster [HANDLE_POWEROFF] = SPECIAL_POWEROFF_TARGET,
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster [HANDLE_REBOOT] = SPECIAL_REBOOT_TARGET,
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster [HANDLE_HALT] = SPECIAL_HALT_TARGET,
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster [HANDLE_KEXEC] = SPECIAL_KEXEC_TARGET,
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster [HANDLE_SUSPEND] = SPECIAL_SUSPEND_TARGET,
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster [HANDLE_HIBERNATE] = SPECIAL_HIBERNATE_TARGET,
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster [HANDLE_HYBRID_SLEEP] = SPECIAL_HYBRID_SLEEP_TARGET
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster };
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster InhibitWhat inhibit_operation;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster Inhibitor *offending = NULL;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster bool supported;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster int r;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster assert(m);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster /* If the key handling is turned off, don't do anything */
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if (handle == HANDLE_IGNORE) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster log_debug("Refusing operation, as it is turned off.");
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster return 0;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if (inhibit_key == INHIBIT_HANDLE_LID_SWITCH) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster /* If the last system suspend or startup is too close,
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * let's not suspend for now, to give USB docking
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * stations some time to settle so that we can
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * properly watch its displays. */
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if (m->lid_switch_ignore_event_source) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster log_debug("Ignoring lid switch request, system startup or resume too close.");
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster return 0;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster /* If the key handling is inhibited, don't do anything */
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if (inhibit_key > 0) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if (manager_is_inhibited(m, inhibit_key, INHIBIT_BLOCK, NULL, true, false, 0, NULL)) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster log_debug("Refusing operation, %s is inhibited.", inhibit_what_to_string(inhibit_key));
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster return 0;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster /* Locking is handled differently from the rest. */
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if (handle == HANDLE_LOCK) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if (!is_edge)
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster return 0;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster log_info("Locking sessions...");
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster session_send_lock_all(m, true);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster return 1;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if (handle == HANDLE_SUSPEND)
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster supported = can_sleep("suspend") > 0;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster else if (handle == HANDLE_HIBERNATE)
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster supported = can_sleep("hibernate") > 0;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster else if (handle == HANDLE_HYBRID_SLEEP)
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster supported = can_sleep("hybrid-sleep") > 0;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster else if (handle == HANDLE_KEXEC)
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster supported = access(KEXEC, X_OK) >= 0;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster else
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster supported = true;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if (!supported) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster log_warning("Requested operation not supported, ignoring.");
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster return -EOPNOTSUPP;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if (m->action_what) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster log_debug("Action already in progress, ignoring.");
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster return -EALREADY;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster inhibit_operation = handle == HANDLE_SUSPEND || handle == HANDLE_HIBERNATE || handle == HANDLE_HYBRID_SLEEP ? INHIBIT_SLEEP : INHIBIT_SHUTDOWN;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster /* If the actual operation is inhibited, warn and fail */
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if (!ignore_inhibited &&
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster manager_is_inhibited(m, inhibit_operation, INHIBIT_BLOCK, NULL, false, false, 0, &offending)) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster _cleanup_free_ char *comm = NULL, *u = NULL;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster get_process_comm(offending->pid, &comm);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster u = uid_to_name(offending->uid);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
/* If this is just a recheck of the lid switch then don't warn about anything */
if (!is_edge) {
log_debug("Refusing operation, %s is inhibited by UID "UID_FMT"/%s, PID "PID_FMT"/%s.",
inhibit_what_to_string(inhibit_operation),
offending->uid, strna(u),
offending->pid, strna(comm));
return 0;
}
log_error("Refusing operation, %s is inhibited by UID "UID_FMT"/%s, PID "PID_FMT"/%s.",
inhibit_what_to_string(inhibit_operation),
offending->uid, strna(u),
offending->pid, strna(comm));
warn_melody();
return -EPERM;
}
log_info("%s", message_table[handle]);
r = bus_manager_shutdown_or_sleep_now_or_later(m, target_table[handle], inhibit_operation, &error);
if (r < 0) {
log_error("Failed to execute operation: %s", bus_error_message(&error, r));
return r;
}
return 1;
}
static const char* const handle_action_table[_HANDLE_ACTION_MAX] = {
[HANDLE_IGNORE] = "ignore",
[HANDLE_POWEROFF] = "poweroff",
[HANDLE_REBOOT] = "reboot",
[HANDLE_HALT] = "halt",
[HANDLE_KEXEC] = "kexec",
[HANDLE_SUSPEND] = "suspend",
[HANDLE_HIBERNATE] = "hibernate",
[HANDLE_HYBRID_SLEEP] = "hybrid-sleep",
[HANDLE_LOCK] = "lock"
};
DEFINE_STRING_TABLE_LOOKUP(handle_action, HandleAction);
DEFINE_CONFIG_PARSE_ENUM(config_parse_handle_action, handle_action, HandleAction, "Failed to parse handle action setting");