chiark / gitweb /
logind: add support for /run/nologin and /run/systemd/shutdown/scheduled
authorDaniel Mack <daniel@zonque.org>
Thu, 23 Apr 2015 15:11:28 +0000 (17:11 +0200)
committerSven Eden <yamakuzure@gmx.net>
Tue, 14 Mar 2017 07:12:03 +0000 (08:12 +0100)
Port over more code from shutdownd and teach logind to write /run/nologin at
least 5 minutes before the system is going down, and
/run/systemd/shutdown/scheduled when a shutdown is scheduled.

src/login/logind-dbus.c
src/login/logind.c
src/login/logind.h

index 80514f3d2c0eb9fe4bdab4784cfe53571cc14f1b..1eda3c2c8342fce7f6874c6949fe74bc5c932999 100644 (file)
@@ -1770,6 +1770,71 @@ static int method_suspend(sd_bus *bus, sd_bus_message *message, void *userdata,
                         error);
 }
 
+static int nologin_timeout_handler(
+                        sd_event_source *s,
+                        uint64_t usec,
+                        void *userdata) {
+
+        Manager *m = userdata;
+        int r;
+
+        log_info("Creating /run/nologin, blocking further logins...");
+
+        r = write_string_file_atomic("/run/nologin", "System is going down.");
+        if (r < 0)
+                log_error_errno(r, "Failed to create /run/nologin: %m");
+        else
+                m->unlink_nologin = true;
+
+        return 0;
+}
+
+static int update_schedule_file(Manager *m) {
+
+        int r;
+        _cleanup_fclose_ FILE *f = NULL;
+        _cleanup_free_ char *t = NULL, *temp_path = NULL;
+
+        assert(m);
+
+        r = mkdir_safe_label("/run/systemd/shutdown", 0755, 0, 0);
+        if (r < 0)
+                return log_error_errno(r, "Failed to create shutdown subdirectory: %m");
+
+        t = cescape(m->wall_message);
+        if (!t)
+                return log_oom();
+
+        r = fopen_temporary("/run/systemd/shutdown/scheduled", &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=%i\n"
+                "MODE=%s\n",
+                m->scheduled_shutdown_timeout,
+                m->enable_wall_messages,
+                m->scheduled_shutdown_type);
+
+        if (!isempty(m->wall_message))
+                fprintf(f, "WALL_MESSAGE=%s\n", t);
+
+        (void) fflush_and_check(f);
+
+        if (ferror(f) || rename(temp_path, "/run/systemd/shutdown/scheduled") < 0) {
+                log_error_errno(errno, "Failed to write information about scheduled shutdowns: %m");
+                r = -errno;
+
+                (void) unlink(temp_path);
+                (void) unlink("/run/systemd/shutdown/scheduled");
+        }
+
+        return r;
+}
+
 static int manager_scheduled_shutdown_handler(
                         sd_event_source *s,
                         uint64_t usec,
@@ -1857,6 +1922,21 @@ static int method_schedule_shutdown(sd_bus *bus, sd_bus_message *message, void *
                 return log_oom();
         }
 
+        if (m->nologin_timeout_source) {
+                r = sd_event_source_set_time(m->nologin_timeout_source, elapse);
+                if (r < 0)
+                        return log_error_errno(r, "sd_event_source_set_time() failed: %m\n");
+
+                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\n");
+        } else {
+                r = sd_event_add_time(m->event, &m->nologin_timeout_source,
+                                      CLOCK_REALTIME, elapse - 5 * USEC_PER_MINUTE, 0, nologin_timeout_handler, m);
+                if (r < 0)
+                        return log_error_errno(r, "sd_event_add_time() failed: %m\n");
+        }
+
         m->scheduled_shutdown_timeout = elapse;
 
         r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_AUGMENT|SD_BUS_CREDS_TTY|SD_BUS_CREDS_UID, &creds);
@@ -1877,6 +1957,13 @@ static int method_schedule_shutdown(sd_bus *bus, sd_bus_message *message, void *
         if (r < 0)
                 return r;
 
+        if (!isempty(type)) {
+                r = update_schedule_file(m);
+                if (r < 0)
+                        return r;
+        } else
+                (void) unlink("/run/systemd/shutdown/scheduled");
+
         return sd_bus_reply_method_return(message, NULL);
 }
 
@@ -1891,6 +1978,7 @@ static int method_cancel_scheduled_shutdown(sd_bus *bus, sd_bus_message *message
 
         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);
         free(m->scheduled_shutdown_type);
         m->scheduled_shutdown_type = NULL;
         m->scheduled_shutdown_timeout = 0;
index 0d96bbdaa93e4656129252ed32503abdedbbfdf0..7520f1345b7ccd3a4d81f3ea1fb6ee98daf32fa9 100644 (file)
@@ -145,6 +145,7 @@ static void manager_free(Manager *m) {
         sd_event_source_unref(m->idle_action_event_source);
         sd_event_source_unref(m->inhibit_timeout_source);
         sd_event_source_unref(m->scheduled_shutdown_timeout_source);
+        sd_event_source_unref(m->nologin_timeout_source);
         sd_event_source_unref(m->wall_message_timeout_source);
 
         sd_event_source_unref(m->console_active_event_source);
@@ -168,6 +169,9 @@ static void manager_free(Manager *m) {
         if (m->udev)
                 udev_unref(m->udev);
 
+        if (m->unlink_nologin)
+                unlink("/run/nologin");
+
         bus_verify_polkit_async_registry_free(m->polkit_registry);
 
         sd_bus_unref(m->bus);
index 906c8ba4082659f3628d777175924f5a1e109c6d..ca9b5ce8650ebfa72494260d443326f1754714a4 100644 (file)
@@ -97,6 +97,8 @@ struct Manager {
         sd_event_source *scheduled_shutdown_timeout_source;
         uid_t scheduled_shutdown_uid;
         char *scheduled_shutdown_tty;
+        sd_event_source *nologin_timeout_source;
+        bool unlink_nologin;
 
         char *wall_message;
         unsigned enable_wall_messages;