mirror of
https://github.com/systemd/systemd.git
synced 2024-12-02 14:53:35 +08:00
logind: load scheduled shutdown on restart
Make sure logind doesn't forget about a scheduled shutdown, even if it gets restarted eg due to a package update.
This commit is contained in:
parent
9fa9c66dbd
commit
aa6123e85e
@ -22,8 +22,10 @@
|
||||
#include "dirent-util.h"
|
||||
#include "efi-loader.h"
|
||||
#include "efivars.h"
|
||||
#include "env-file.h"
|
||||
#include "env-util.h"
|
||||
#include "escape.h"
|
||||
#include "event-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio-label.h"
|
||||
#include "fileio.h"
|
||||
@ -45,6 +47,7 @@
|
||||
#include "selinux-util.h"
|
||||
#include "sleep-config.h"
|
||||
#include "special.h"
|
||||
#include "serialize.h"
|
||||
#include "stdio-util.h"
|
||||
#include "strv.h"
|
||||
#include "terminal-util.h"
|
||||
@ -63,7 +66,11 @@
|
||||
*/
|
||||
#define WALL_MESSAGE_MAX 4096
|
||||
|
||||
#define SHUTDOWN_SCHEDULE_FILE "/run/systemd/shutdown/scheduled"
|
||||
|
||||
static int update_schedule_file(Manager *m);
|
||||
static void reset_scheduled_shutdown(Manager *m);
|
||||
static int manager_setup_shutdown_timers(Manager* m);
|
||||
|
||||
static int get_sender_session(
|
||||
Manager *m,
|
||||
@ -2038,6 +2045,81 @@ static usec_t nologin_timeout_usec(usec_t elapse) {
|
||||
return LESS_BY(elapse, 5 * USEC_PER_MINUTE);
|
||||
}
|
||||
|
||||
void manager_load_scheduled_shutdown(Manager *m) {
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
_cleanup_free_ char *usec = NULL,
|
||||
*warn_wall = NULL,
|
||||
*mode = NULL,
|
||||
*wall_message = NULL,
|
||||
*uid = NULL,
|
||||
*tty = NULL;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
|
||||
r = parse_env_file(f, SHUTDOWN_SCHEDULE_FILE,
|
||||
"USEC", &usec,
|
||||
"WARN_WALL", &warn_wall,
|
||||
"MODE", &mode,
|
||||
"WALL_MESSAGE", &wall_message,
|
||||
"UID", &uid,
|
||||
"TTY", &tty);
|
||||
|
||||
/* reset will delete the file */
|
||||
reset_scheduled_shutdown(m);
|
||||
|
||||
if (r == -ENOENT)
|
||||
return;
|
||||
if (r < 0)
|
||||
return (void) log_debug_errno(r, "Failed to parse " SHUTDOWN_SCHEDULE_FILE ": %m");
|
||||
|
||||
HandleAction handle = handle_action_from_string(mode);
|
||||
if (handle < 0)
|
||||
return (void) log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse scheduled shutdown type: %s", mode);
|
||||
|
||||
if (!usec)
|
||||
return (void) log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "USEC is required");
|
||||
if (deserialize_usec(usec, &m->scheduled_shutdown_timeout) < 0)
|
||||
return;
|
||||
|
||||
/* assign parsed type only after we know usec is also valid */
|
||||
m->scheduled_shutdown_type = manager_item_for_handle(handle);
|
||||
|
||||
if (warn_wall) {
|
||||
r = parse_boolean(warn_wall);
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Failed to parse enabling wall messages");
|
||||
else
|
||||
m->enable_wall_messages = r;
|
||||
}
|
||||
|
||||
if (wall_message) {
|
||||
_cleanup_free_ char *unescaped = NULL;
|
||||
r = cunescape(wall_message, 0, &unescaped);
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Failed to parse wall message: %s", wall_message);
|
||||
else
|
||||
free_and_replace(m->wall_message, unescaped);
|
||||
}
|
||||
|
||||
if (uid) {
|
||||
r = parse_uid(uid, &m->scheduled_shutdown_uid);
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Failed to parse wall uid: %s", uid);
|
||||
}
|
||||
|
||||
free_and_replace(m->scheduled_shutdown_tty, tty);
|
||||
|
||||
r = manager_setup_shutdown_timers(m);
|
||||
if (r < 0)
|
||||
return reset_scheduled_shutdown(m);
|
||||
|
||||
(void) manager_setup_wall_message_timer(m);
|
||||
(void) update_schedule_file(m);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int update_schedule_file(Manager *m) {
|
||||
_cleanup_free_ char *temp_path = NULL;
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
@ -2046,41 +2128,35 @@ static int update_schedule_file(Manager *m) {
|
||||
assert(m);
|
||||
assert(m->scheduled_shutdown_type);
|
||||
|
||||
r = mkdir_safe_label("/run/systemd/shutdown", 0755, 0, 0, MKDIR_WARN_MODE);
|
||||
r = mkdir_parents_label(SHUTDOWN_SCHEDULE_FILE, 0755);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to create shutdown subdirectory: %m");
|
||||
|
||||
r = fopen_temporary("/run/systemd/shutdown/scheduled", &f, &temp_path);
|
||||
r = fopen_temporary(SHUTDOWN_SCHEDULE_FILE, &f, &temp_path);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to save information about scheduled shutdowns: %m");
|
||||
|
||||
(void) fchmod(fileno(f), 0644);
|
||||
|
||||
fprintf(f,
|
||||
"USEC="USEC_FMT"\n"
|
||||
"WARN_WALL=%s\n"
|
||||
"MODE=%s\n",
|
||||
m->scheduled_shutdown_timeout,
|
||||
one_zero(m->enable_wall_messages),
|
||||
handle_action_to_string(m->scheduled_shutdown_type->handle));
|
||||
serialize_usec(f, "USEC", m->scheduled_shutdown_timeout);
|
||||
serialize_item_format(f, "WARN_WALL", "%s", one_zero(m->enable_wall_messages));
|
||||
serialize_item_format(f, "MODE", "%s", handle_action_to_string(m->scheduled_shutdown_type->handle));
|
||||
serialize_item_format(f, "UID", UID_FMT, m->scheduled_shutdown_uid);
|
||||
|
||||
if (m->scheduled_shutdown_tty)
|
||||
serialize_item_format(f, "TTY", "%s", m->scheduled_shutdown_tty);
|
||||
|
||||
if (!isempty(m->wall_message)) {
|
||||
_cleanup_free_ char *t = NULL;
|
||||
|
||||
t = cescape(m->wall_message);
|
||||
if (!t) {
|
||||
r = -ENOMEM;
|
||||
r = serialize_item_escaped(f, "WALL_MESSAGE", m->wall_message);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
fprintf(f, "WALL_MESSAGE=%s\n", t);
|
||||
}
|
||||
|
||||
r = fflush_and_check(f);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
if (rename(temp_path, "/run/systemd/shutdown/scheduled") < 0) {
|
||||
if (rename(temp_path, SHUTDOWN_SCHEDULE_FILE) < 0) {
|
||||
r = -errno;
|
||||
goto fail;
|
||||
}
|
||||
@ -2089,7 +2165,7 @@ static int update_schedule_file(Manager *m) {
|
||||
|
||||
fail:
|
||||
(void) unlink(temp_path);
|
||||
(void) unlink("/run/systemd/shutdown/scheduled");
|
||||
(void) unlink(SHUTDOWN_SCHEDULE_FILE);
|
||||
|
||||
return log_error_errno(r, "Failed to write information about scheduled shutdowns: %m");
|
||||
}
|
||||
@ -2102,6 +2178,10 @@ static void reset_scheduled_shutdown(Manager *m) {
|
||||
m->nologin_timeout_source = sd_event_source_unref(m->nologin_timeout_source);
|
||||
|
||||
m->scheduled_shutdown_type = NULL;
|
||||
m->scheduled_shutdown_timeout = USEC_INFINITY;
|
||||
m->scheduled_shutdown_uid = UID_INVALID;
|
||||
freep(&m->scheduled_shutdown_tty);
|
||||
freep(&m->wall_message);
|
||||
m->shutdown_dry_run = false;
|
||||
|
||||
if (m->unlink_nologin) {
|
||||
@ -2109,7 +2189,7 @@ static void reset_scheduled_shutdown(Manager *m) {
|
||||
m->unlink_nologin = false;
|
||||
}
|
||||
|
||||
(void) unlink("/run/systemd/shutdown/scheduled");
|
||||
(void) unlink(SHUTDOWN_SCHEDULE_FILE);
|
||||
}
|
||||
|
||||
static int manager_scheduled_shutdown_handler(
|
||||
@ -2193,54 +2273,54 @@ static int method_schedule_shutdown(sd_bus_message *message, void *userdata, sd_
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
if (m->scheduled_shutdown_timeout_source) {
|
||||
r = sd_event_source_set_time(m->scheduled_shutdown_timeout_source, elapse);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "sd_event_source_set_time() failed: %m");
|
||||
|
||||
r = sd_event_source_set_enabled(m->scheduled_shutdown_timeout_source, SD_EVENT_ONESHOT);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "sd_event_source_set_enabled() failed: %m");
|
||||
} else {
|
||||
r = sd_event_add_time(m->event, &m->scheduled_shutdown_timeout_source,
|
||||
CLOCK_REALTIME, elapse, 0, manager_scheduled_shutdown_handler, m);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "sd_event_add_time() failed: %m");
|
||||
}
|
||||
|
||||
m->scheduled_shutdown_type = a;
|
||||
m->shutdown_dry_run = dry_run;
|
||||
|
||||
if (m->nologin_timeout_source) {
|
||||
r = sd_event_source_set_time(m->nologin_timeout_source, nologin_timeout_usec(elapse));
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "sd_event_source_set_time() failed: %m");
|
||||
|
||||
r = sd_event_source_set_enabled(m->nologin_timeout_source, SD_EVENT_ONESHOT);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "sd_event_source_set_enabled() failed: %m");
|
||||
} else {
|
||||
r = sd_event_add_time(m->event, &m->nologin_timeout_source,
|
||||
CLOCK_REALTIME, nologin_timeout_usec(elapse), 0, nologin_timeout_handler, m);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "sd_event_add_time() failed: %m");
|
||||
}
|
||||
|
||||
m->scheduled_shutdown_timeout = elapse;
|
||||
|
||||
r = setup_wall_message_timer(m, message);
|
||||
if (r < 0) {
|
||||
m->scheduled_shutdown_timeout_source = sd_event_source_unref(m->scheduled_shutdown_timeout_source);
|
||||
return r;
|
||||
}
|
||||
|
||||
r = update_schedule_file(m);
|
||||
r = manager_setup_shutdown_timers(m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = setup_wall_message_timer(m, message);
|
||||
if (r >= 0)
|
||||
r = update_schedule_file(m);
|
||||
|
||||
if (r < 0) {
|
||||
reset_scheduled_shutdown(m);
|
||||
return r;
|
||||
}
|
||||
|
||||
return sd_bus_reply_method_return(message, NULL);
|
||||
}
|
||||
|
||||
static int manager_setup_shutdown_timers(Manager* m) {
|
||||
int r;
|
||||
|
||||
r = event_reset_time(m->event, &m->scheduled_shutdown_timeout_source,
|
||||
CLOCK_REALTIME,
|
||||
m->scheduled_shutdown_timeout, 0,
|
||||
manager_scheduled_shutdown_handler, m,
|
||||
0, "scheduled-shutdown-timeout", true);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
r = event_reset_time(m->event, &m->nologin_timeout_source,
|
||||
CLOCK_REALTIME,
|
||||
nologin_timeout_usec(m->scheduled_shutdown_timeout), 0,
|
||||
nologin_timeout_handler, m,
|
||||
0, "nologin-timeout", true);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
m->scheduled_shutdown_timeout_source = sd_event_source_unref(m->scheduled_shutdown_timeout_source);
|
||||
m->nologin_timeout_source = sd_event_source_unref(m->nologin_timeout_source);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int method_cancel_scheduled_shutdown(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||
Manager *m = userdata;
|
||||
const ActionTableItem *a;
|
||||
|
@ -32,4 +32,6 @@ int manager_kill_unit(Manager *manager, const char *unit, KillWho who, int signo
|
||||
int manager_unit_is_active(Manager *manager, const char *unit, sd_bus_error *error);
|
||||
int manager_job_is_active(Manager *manager, const char *path, sd_bus_error *error);
|
||||
|
||||
void manager_load_scheduled_shutdown(Manager *m);
|
||||
|
||||
extern const BusObjectImplementation manager_object;
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "bus-common-errors.h"
|
||||
#include "bus-error.h"
|
||||
#include "bus-util.h"
|
||||
#include "event-util.h"
|
||||
#include "format-util.h"
|
||||
#include "logind.h"
|
||||
#include "path-util.h"
|
||||
@ -147,19 +148,15 @@ int manager_setup_wall_message_timer(Manager *m) {
|
||||
if (elapse == 0)
|
||||
return 0;
|
||||
|
||||
if (m->wall_message_timeout_source) {
|
||||
r = sd_event_source_set_time(m->wall_message_timeout_source, n + elapse);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "sd_event_source_set_time() failed. %m");
|
||||
r = event_reset_time(m->event, &m->wall_message_timeout_source,
|
||||
CLOCK_REALTIME,
|
||||
n + elapse, 0,
|
||||
wall_message_timeout_handler, m,
|
||||
0, "wall-message-timer", true);
|
||||
|
||||
r = sd_event_source_set_enabled(m->wall_message_timeout_source, SD_EVENT_ONESHOT);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "sd_event_source_set_enabled() failed. %m");
|
||||
} else {
|
||||
r = sd_event_add_time(m->event, &m->wall_message_timeout_source,
|
||||
CLOCK_REALTIME, n + elapse, 0, wall_message_timeout_handler, m);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "sd_event_add_time() failed. %m");
|
||||
if (r < 0) {
|
||||
m->wall_message_timeout_source = sd_event_source_unref(m->wall_message_timeout_source);
|
||||
return log_error_errno(r, "Failed to set up wall message timer: %m");
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -1090,6 +1090,8 @@ static int manager_startup(Manager *m) {
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Button enumeration failed: %m");
|
||||
|
||||
manager_load_scheduled_shutdown(m);
|
||||
|
||||
/* Remove stale objects before we start them */
|
||||
manager_gc(m, false);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user