Exemplo n.º 1
0
static int wall_message_timeout_handler(
                        sd_event_source *s,
                        uint64_t usec,
                        void *userdata) {

        Manager *m = userdata;
        usec_t n, next;
        int r;

        assert(m);
        assert(s == m->wall_message_timeout_source);

        n = now(CLOCK_REALTIME);

        r = warn_wall(m, n);
        if (r == 0)
                return 0;

        next = when_wall(n, m->scheduled_shutdown_timeout);
        if (next > 0) {
                r = sd_event_source_set_time(s, n + next);
                if (r < 0)
                        return log_error_errno(r, "sd_event_source_set_time() failed. %m");

                r = sd_event_source_set_enabled(s, SD_EVENT_ONESHOT);
                if (r < 0)
                        return log_error_errno(r, "sd_event_source_set_enabled() failed. %m");
        }

        return 0;
}
Exemplo n.º 2
0
int manager_setup_wall_message_timer(Manager *m) {

        usec_t n, elapse;
        int r;

        assert(m);

        n = now(CLOCK_REALTIME);
        elapse = m->scheduled_shutdown_timeout;

        /* wall message handling */

        if (isempty(m->scheduled_shutdown_type)) {
                warn_wall(m, n);
                return 0;
        }

        if (elapse < n)
                return 0;

        /* Warn immediately if less than 15 minutes are left */
        if (elapse - n < 15 * USEC_PER_MINUTE) {
                r = warn_wall(m, n);
                if (r == 0)
                        return 0;
        }

        elapse = when_wall(n, elapse);
        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 = 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");
        }

        return 0;
}
Exemplo n.º 3
0
int main(int argc, char *argv[]) {
        enum {
                FD_SOCKET,
                FD_WALL_TIMER,
                FD_NOLOGIN_TIMER,
                FD_SHUTDOWN_TIMER,
                _FD_MAX
        };

        int r = EXIT_FAILURE, n_fds;
        int one = 1;
        struct shutdownd_command c;
        struct pollfd pollfd[_FD_MAX];
        bool exec_shutdown = false, unlink_nologin = false, failed = false;
        unsigned i;

        if (getppid() != 1) {
                log_error("This program should be invoked by init only.");
                return EXIT_FAILURE;
        }

        if (argc > 1) {
                log_error("This program does not take arguments.");
                return EXIT_FAILURE;
        }

        log_set_target(LOG_TARGET_SYSLOG_OR_KMSG);
        log_parse_environment();
        log_open();

        if ((n_fds = sd_listen_fds(true)) < 0) {
                log_error("Failed to read listening file descriptors from environment: %s", strerror(-r));
                return EXIT_FAILURE;
        }

        if (n_fds != 1) {
                log_error("Need exactly one file descriptor.");
                return EXIT_FAILURE;
        }

        if (setsockopt(SD_LISTEN_FDS_START, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)) < 0) {
                log_error("SO_PASSCRED failed: %m");
                return EXIT_FAILURE;
        }

        zero(c);
        zero(pollfd);

        pollfd[FD_SOCKET].fd = SD_LISTEN_FDS_START;
        pollfd[FD_SOCKET].events = POLLIN;

        for (i = 0; i < _FD_MAX; i++) {

                if (i == FD_SOCKET)
                        continue;

                pollfd[i].events = POLLIN;

                if ((pollfd[i].fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK|TFD_CLOEXEC)) < 0) {
                        log_error("timerfd_create(): %m");
                        failed = true;
                }
        }

        if (failed)
                goto finish;

        log_debug("systemd-shutdownd running as pid %lu", (unsigned long) getpid());

        sd_notify(false,
                  "READY=1\n"
                  "STATUS=Processing requests...");

        do {
                int k;
                usec_t n;

                if (poll(pollfd, _FD_MAX, -1) < 0) {

                        if (errno == EAGAIN || errno == EINTR)
                                continue;

                        log_error("poll(): %m");
                        goto finish;
                }

                n = now(CLOCK_REALTIME);

                if (pollfd[FD_SOCKET].revents) {

                        if ((k = read_packet(pollfd[FD_SOCKET].fd, &c)) < 0)
                                goto finish;
                        else if (k > 0 && c.elapse > 0) {
                                struct itimerspec its;
                                char date[FORMAT_TIMESTAMP_MAX];

                                if (c.warn_wall) {
                                        /* Send wall messages every so often */
                                        zero(its);
                                        timespec_store(&its.it_value, when_wall(n, c.elapse));
                                        if (timerfd_settime(pollfd[FD_WALL_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
                                                log_error("timerfd_settime(): %m");
                                                goto finish;
                                        }

                                        /* Warn immediately if less than 15 minutes are left */
                                        if (n < c.elapse &&
                                            n + 15*USEC_PER_MINUTE >= c.elapse)
                                                warn_wall(n, &c);
                                }

                                /* Disallow logins 5 minutes prior to shutdown */
                                zero(its);
                                timespec_store(&its.it_value, when_nologin(c.elapse));
                                if (timerfd_settime(pollfd[FD_NOLOGIN_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
                                        log_error("timerfd_settime(): %m");
                                        goto finish;
                                }

                                /* Shutdown after the specified time is reached */
                                zero(its);
                                timespec_store(&its.it_value, c.elapse);
                                if (timerfd_settime(pollfd[FD_SHUTDOWN_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
                                        log_error("timerfd_settime(): %m");
                                        goto finish;
                                }

                                sd_notifyf(false,
                                           "STATUS=Shutting down at %s...",
                                           format_timestamp(date, sizeof(date), c.elapse));
                        }
                }

                if (pollfd[FD_WALL_TIMER].revents) {
                        struct itimerspec its;

                        warn_wall(n, &c);
                        flush_fd(pollfd[FD_WALL_TIMER].fd);

                        /* Restart timer */
                        zero(its);
                        timespec_store(&its.it_value, when_wall(n, c.elapse));
                        if (timerfd_settime(pollfd[FD_WALL_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
                                log_error("timerfd_settime(): %m");
                                goto finish;
                        }
                }

                if (pollfd[FD_NOLOGIN_TIMER].revents) {
                        int e;

                        log_info("Creating /run/nologin, blocking further logins...");

                        if ((e = write_one_line_file("/run/nologin", "System is going down.")) < 0)
                                log_error("Failed to create /run/nologin: %s", strerror(-e));
                        else
                                unlink_nologin = true;

                        flush_fd(pollfd[FD_NOLOGIN_TIMER].fd);
                }

                if (pollfd[FD_SHUTDOWN_TIMER].revents) {
                        exec_shutdown = true;
                        goto finish;
                }

        } while (c.elapse > 0);

        r = EXIT_SUCCESS;

        log_debug("systemd-shutdownd stopped as pid %lu", (unsigned long) getpid());

finish:

        for (i = 0; i < _FD_MAX; i++)
                if (pollfd[i].fd >= 0)
                        close_nointr_nofail(pollfd[i].fd);

        if (unlink_nologin)
                unlink("/run/nologin");

        if (exec_shutdown) {
                char sw[3];

                sw[0] = '-';
                sw[1] = c.mode;
                sw[2] = 0;

                execl(SYSTEMCTL_BINARY_PATH,
                      "shutdown",
                      sw,
                      "now",
                      (c.warn_wall && c.wall_message[0]) ? c.wall_message :
                      (c.warn_wall ? NULL : "--no-wall"),
                      NULL);

                log_error("Failed to execute /sbin/shutdown: %m");
        }

        sd_notify(false,
                  "STATUS=Exiting...");

        return r;
}