mirror of
https://github.com/Dasharo/systemd.git
synced 2026-03-06 15:02:31 -08:00
Merge pull request #21838 from lnussel/logind-refactor
Logind shutdown refactor
This commit is contained in:
@@ -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"
|
||||
|
||||
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,
|
||||
};
|
||||
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) {
|
||||
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].target;
|
||||
}
|
||||
|
||||
const ActionTableItem* manager_item_for_handle(HandleAction handle) {
|
||||
assert(handle >= 0);
|
||||
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),
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
/* always try logind first */
|
||||
if (arg_when > 0)
|
||||
r = logind_schedule_shutdown();
|
||||
else {
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
1
test/TEST-69-SHUTDOWN/Makefile
Symbolic link
1
test/TEST-69-SHUTDOWN/Makefile
Symbolic link
@@ -0,0 +1 @@
|
||||
../TEST-01-BASIC/Makefile
|
||||
33
test/TEST-69-SHUTDOWN/test.sh
Executable file
33
test/TEST-69-SHUTDOWN/test.sh
Executable file
@@ -0,0 +1,33 @@
|
||||
#!/usr/bin/env bash
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
set -e
|
||||
|
||||
TEST_DESCRIPTION="shutdown testing"
|
||||
IMAGE_NAME="shutdown"
|
||||
TEST_NO_QEMU=1
|
||||
|
||||
# shellcheck source=test/test-functions
|
||||
. "${TEST_BASE_DIR:?}/test-functions"
|
||||
|
||||
_ORIG_NSPAWN="$SYSTEMD_NSPAWN"
|
||||
SYSTEMD_NSPAWN="$STATEDIR/run-nspawn"
|
||||
|
||||
setup_nspawn_root_hook() {
|
||||
cat > "$STATEDIR"/run-nspawn <<-EOF
|
||||
#!/bin/bash
|
||||
exec "$TEST_BASE_DIR"/test-shutdown.py -- "$_ORIG_NSPAWN" "\$@"
|
||||
exit 1
|
||||
EOF
|
||||
chmod 755 "$STATEDIR"/run-nspawn
|
||||
}
|
||||
|
||||
test_append_files() {
|
||||
# prevent shutdown in test suite, the expect script does that manually.
|
||||
rm "$1"/usr/lib/systemd/tests/testdata/units/end.service
|
||||
inst /usr/bin/screen
|
||||
echo "PS1='screen\$WINDOW # '" > "$1"/etc/bash.bashrc
|
||||
echo 'startup_message off' > "$1"/etc/screenrc
|
||||
echo 'bell_msg ""' >> "$1"/etc/screenrc
|
||||
}
|
||||
|
||||
do_test "$@"
|
||||
@@ -1896,6 +1896,8 @@ has_user_dbus_socket() {
|
||||
fi
|
||||
}
|
||||
|
||||
setup_nspawn_root_hook() { :;}
|
||||
|
||||
setup_nspawn_root() {
|
||||
if [ -z "${initdir}" ]; then
|
||||
dfatal "\$initdir not defined"
|
||||
@@ -1908,6 +1910,8 @@ setup_nspawn_root() {
|
||||
ddebug "cp -ar $initdir $TESTDIR/unprivileged-nspawn-root"
|
||||
cp -ar "$initdir" "$TESTDIR/unprivileged-nspawn-root"
|
||||
fi
|
||||
|
||||
setup_nspawn_root_hook
|
||||
}
|
||||
|
||||
setup_basic_dirs() {
|
||||
|
||||
114
test/test-shutdown.py
Executable file
114
test/test-shutdown.py
Executable file
@@ -0,0 +1,114 @@
|
||||
#!/usr/bin/python3
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
#
|
||||
|
||||
import argparse
|
||||
import logging
|
||||
import pexpect
|
||||
import sys
|
||||
|
||||
|
||||
def run(args):
|
||||
|
||||
ret = 1
|
||||
logger = logging.getLogger("test-shutdown")
|
||||
|
||||
logger.info("spawning test")
|
||||
console = pexpect.spawn(args.command, args.arg, env={
|
||||
"TERM": "linux",
|
||||
}, encoding='utf-8', timeout=30)
|
||||
|
||||
if args.verbose:
|
||||
console.logfile = sys.stdout
|
||||
|
||||
logger.debug("child pid %d" % console.pid)
|
||||
|
||||
try:
|
||||
logger.info("waiting for login prompt")
|
||||
console.expect('H login: ', 10)
|
||||
|
||||
logger.info("log in and start screen")
|
||||
console.sendline('root')
|
||||
console.expect('bash.*# ', 10)
|
||||
console.sendline('screen')
|
||||
console.expect('screen0 ', 10)
|
||||
console.sendcontrol('a')
|
||||
console.send('c')
|
||||
console.expect('screen1 ', 10)
|
||||
|
||||
# console.interact()
|
||||
|
||||
console.sendline('tty')
|
||||
console.expect(r'/dev/(pts/\d+)')
|
||||
pty = console.match.group(1)
|
||||
logger.info("window 1 at line %s", pty)
|
||||
|
||||
logger.info("schedule reboot")
|
||||
console.sendline('shutdown -r')
|
||||
console.expect("Reboot scheduled for (?P<date>.*), use 'shutdown -c' to cancel", 2)
|
||||
date = console.match.group('date')
|
||||
logger.info("reboot scheduled for %s", date)
|
||||
|
||||
console.sendcontrol('a')
|
||||
console.send('0')
|
||||
logger.info("verify broadcast message")
|
||||
console.expect('Broadcast message from root@H on %s' % pty, 2)
|
||||
console.expect('The system is going down for reboot at %s' % date, 2)
|
||||
|
||||
logger.info("check show output")
|
||||
console.sendline('shutdown --show')
|
||||
console.expect("Reboot scheduled for %s, use 'shutdown -c' to cancel" % date, 2)
|
||||
|
||||
logger.info("cancel shutdown")
|
||||
console.sendline('shutdown -c')
|
||||
console.sendcontrol('a')
|
||||
console.send('1')
|
||||
console.expect('The system shutdown has been cancelled', 2)
|
||||
|
||||
logger.info("call for reboot")
|
||||
console.sendline('sleep 10; shutdown -r now')
|
||||
console.sendcontrol('a')
|
||||
console.send('0')
|
||||
console.expect("The system is going down for reboot NOW!", 12)
|
||||
|
||||
logger.info("waiting for reboot")
|
||||
|
||||
console.expect('H login: ', 10)
|
||||
console.sendline('root')
|
||||
console.expect('bash.*# ', 10)
|
||||
|
||||
console.sendline('> /testok')
|
||||
|
||||
logger.info("power off")
|
||||
console.sendline('poweroff')
|
||||
|
||||
logger.info("expect termination now")
|
||||
console.expect(pexpect.EOF)
|
||||
|
||||
ret = 0
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
logger.info("killing child pid %d" % console.pid)
|
||||
console.terminate()
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(description='test logind shutdown feature')
|
||||
parser.add_argument("-v", "--verbose", action="store_true", help="verbose")
|
||||
parser.add_argument("command", help="command to run")
|
||||
parser.add_argument("arg", nargs='*', help="args for command")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.verbose:
|
||||
level = logging.DEBUG
|
||||
else:
|
||||
level = logging.INFO
|
||||
|
||||
logging.basicConfig(level=level)
|
||||
|
||||
sys.exit(run(args))
|
||||
|
||||
# vim: sw=4 et
|
||||
7
test/units/testsuite-69.service
Normal file
7
test/units/testsuite-69.service
Normal file
@@ -0,0 +1,7 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
[Unit]
|
||||
Description=TEST-69-SHUTDOWN
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh
|
||||
Reference in New Issue
Block a user