#include "sleep-config.h"
#include "special.h"
#include "serialize.h"
+#include "signal-util.h"
#include "stdio-util.h"
#include "strv.h"
#include "terminal-util.h"
#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,
return RET_GATHER(k, r);
}
+static int strdup_job(sd_bus_message *reply, char **ret) {
+ const char *j;
+ char *job;
+ int r;
+
+ assert(reply);
+ assert(ret);
+
+ r = sd_bus_message_read_basic(reply, 'o', &j);
+ if (r < 0)
+ return r;
+
+ job = strdup(j);
+ if (!job)
+ return -ENOMEM;
+
+ *ret = job;
+ return 0;
+}
+
static int execute_shutdown_or_sleep(
Manager *m,
const HandleActionData *a,
sd_bus_error *error) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
- const char *p;
int r;
assert(m);
&reply,
"ss", a->target, "replace-irreversibly");
if (r < 0)
- goto error;
+ goto fail;
- r = sd_bus_message_read(reply, "o", &p);
+ r = strdup_job(reply, &m->action_job);
if (r < 0)
- goto error;
-
- m->action_job = strdup(p);
- if (!m->action_job) {
- r = -ENOMEM;
- goto error;
- }
+ goto fail;
m->delayed_action = a;
return 0;
-error:
+fail:
/* Tell people that they now may take a lock again */
(void) send_prepare_for(m, a, false);
uint64_t usec,
void *userdata) {
- Manager *m = userdata;
+ Manager *m = ASSERT_PTR(userdata);
log_info("Creating /run/nologin, blocking further logins...");
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;
-
+static void reset_scheduled_shutdown(Manager *m) {
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_action = 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;
- }
+ m->scheduled_shutdown_timeout_source = sd_event_source_unref(m->scheduled_shutdown_timeout_source);
+ m->wall_message_timeout_source = sd_event_source_unref(m->wall_message_timeout_source);
+ m->nologin_timeout_source = sd_event_source_unref(m->nologin_timeout_source);
- 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);
- }
+ m->scheduled_shutdown_action = _HANDLE_ACTION_INVALID;
+ m->scheduled_shutdown_timeout = USEC_INFINITY;
+ m->scheduled_shutdown_uid = UID_INVALID;
+ m->scheduled_shutdown_tty = mfree(m->scheduled_shutdown_tty);
+ m->shutdown_dry_run = false;
- if (uid) {
- r = parse_uid(uid, &m->scheduled_shutdown_uid);
- if (r < 0)
- log_debug_errno(r, "Failed to parse wall uid: %s", uid);
+ if (m->unlink_nologin) {
+ (void) unlink_or_warn("/run/nologin");
+ m->unlink_nologin = false;
}
- 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;
+ (void) unlink(SHUTDOWN_SCHEDULE_FILE);
}
static int update_schedule_file(Manager *m) {
return log_error_errno(r, "Failed to write information about scheduled shutdowns: %m");
}
-static void reset_scheduled_shutdown(Manager *m) {
- assert(m);
-
- m->scheduled_shutdown_timeout_source = sd_event_source_unref(m->scheduled_shutdown_timeout_source);
- m->wall_message_timeout_source = sd_event_source_unref(m->wall_message_timeout_source);
- m->nologin_timeout_source = sd_event_source_unref(m->nologin_timeout_source);
-
- m->scheduled_shutdown_action = _HANDLE_ACTION_INVALID;
- m->scheduled_shutdown_timeout = USEC_INFINITY;
- m->scheduled_shutdown_uid = UID_INVALID;
- m->scheduled_shutdown_tty = mfree(m->scheduled_shutdown_tty);
- m->shutdown_dry_run = false;
-
- if (m->unlink_nologin) {
- (void) unlink_or_warn("/run/nologin");
- m->unlink_nologin = false;
- }
-
- (void) unlink(SHUTDOWN_SCHEDULE_FILE);
-}
-
static int manager_scheduled_shutdown_handler(
sd_event_source *s,
uint64_t usec,
return r;
}
+static int manager_setup_shutdown_timers(Manager* m) {
+ int r;
+
+ assert(m);
+
+ 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;
+}
+
+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_action = 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 method_schedule_shutdown(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = ASSERT_PTR(userdata);
HandleAction handle;
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 = ASSERT_PTR(userdata);
const HandleActionData *a;
l);
}
-static int strdup_job(sd_bus_message *reply, char **job) {
- const char *j;
- char *copy;
- int r;
-
- r = sd_bus_message_read(reply, "o", &j);
- if (r < 0)
- return r;
-
- copy = strdup(j);
- if (!copy)
- return -ENOMEM;
-
- *job = copy;
- return 1;
-}
-
int manager_start_scope(
Manager *manager,
const char *scope,
return strdup_job(reply, ret_job);
}
-int manager_start_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
+int manager_start_unit(Manager *manager, const char *unit, sd_bus_error *error, char **ret_job) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
int r;
assert(manager);
assert(unit);
- assert(job);
+ assert(ret_job);
r = bus_call_method(
manager->bus,
if (r < 0)
return r;
- return strdup_job(reply, job);
+ return strdup_job(reply, ret_job);
}
-int manager_stop_unit(Manager *manager, const char *unit, const char *job_mode, sd_bus_error *error, char **ret_job) {
+int manager_stop_unit(
+ Manager *manager,
+ const char *unit,
+ const char *job_mode,
+ sd_bus_error *ret_error,
+ char **ret_job) {
+
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
int r;
assert(manager);
manager->bus,
bus_systemd_mgr,
"StopUnit",
- error,
+ &error,
&reply,
"ss", unit, job_mode ?: "fail");
if (r < 0) {
- if (sd_bus_error_has_names(error, BUS_ERROR_NO_SUCH_UNIT,
- BUS_ERROR_LOAD_FAILED)) {
-
+ if (sd_bus_error_has_names(&error, BUS_ERROR_NO_SUCH_UNIT, BUS_ERROR_LOAD_FAILED)) {
*ret_job = NULL;
- sd_bus_error_free(error);
return 0;
}
+ sd_bus_error_move(ret_error, &error);
return r;
}
- return strdup_job(reply, ret_job);
+ r = strdup_job(reply, ret_job);
+ if (r < 0)
+ return r;
+
+ return 1;
}
int manager_abandon_scope(Manager *manager, const char *scope, sd_bus_error *ret_error) {
int manager_kill_unit(Manager *manager, const char *unit, KillWho who, int signo, sd_bus_error *error) {
assert(manager);
assert(unit);
+ assert(SIGNAL_VALID(signo));
return bus_call_method(
manager->bus,
"KillUnit",
error,
NULL,
- "ssi", unit, who == KILL_LEADER ? "main" : "all", signo);
+ "ssi",
+ unit,
+ who == KILL_LEADER ? "main" : "all",
+ signo);
}
int manager_unit_is_active(Manager *manager, const char *unit, sd_bus_error *ret_error) {