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