Exemple #1
0
int main(int argc, char *argv[]) {
        int cmd, r;
        unsigned retries;
        bool need_umount = true, need_swapoff = true, need_loop_detach = true, need_dm_detach = true;
        bool in_container, use_watchdog = false;
        char *arguments[3];

        log_parse_environment();
        log_set_target(LOG_TARGET_CONSOLE); /* syslog will die if not gone yet */
        log_open();

        umask(0022);

        if (getpid() != 1) {
                log_error("Not executed by init (pid 1).");
                r = -EPERM;
                goto error;
        }

        if (argc != 2) {
                log_error("Invalid number of arguments.");
                r = -EINVAL;
                goto error;
        }

        in_container = detect_container(NULL) > 0;

        if (streq(argv[1], "reboot"))
                cmd = RB_AUTOBOOT;
        else if (streq(argv[1], "poweroff"))
                cmd = RB_POWER_OFF;
        else if (streq(argv[1], "halt"))
                cmd = RB_HALT_SYSTEM;
        else if (streq(argv[1], "kexec"))
                cmd = LINUX_REBOOT_CMD_KEXEC;
        else {
                log_error("Unknown action '%s'.", argv[1]);
                r = -EINVAL;
                goto error;
        }

        use_watchdog = !!getenv("WATCHDOG_USEC");

        /* lock us into memory */
        mlockall(MCL_CURRENT|MCL_FUTURE);

        log_info("Sending SIGTERM to remaining processes...");
        broadcast_signal(SIGTERM, true);

        log_info("Sending SIGKILL to remaining processes...");
        broadcast_signal(SIGKILL, true);

        if (in_container) {
                need_swapoff = false;
                need_dm_detach = false;
                need_loop_detach = false;
        }

        /* Unmount all mountpoints, swaps, and loopback devices */
        for (retries = 0; retries < FINALIZE_ATTEMPTS; retries++) {
                bool changed = false;

                if (use_watchdog)
                        watchdog_ping();

                if (need_umount) {
                        log_info("Unmounting file systems.");
                        r = umount_all(&changed);
                        if (r == 0)
                                need_umount = false;
                        else if (r > 0)
                                log_info("Not all file systems unmounted, %d left.", r);
                        else
                                log_error("Failed to unmount file systems: %s", strerror(-r));
                }

                if (need_swapoff) {
                        log_info("Disabling swaps.");
                        r = swapoff_all(&changed);
                        if (r == 0)
                                need_swapoff = false;
                        else if (r > 0)
                                log_info("Not all swaps are turned off, %d left.", r);
                        else
                                log_error("Failed to turn off swaps: %s", strerror(-r));
                }

                if (need_loop_detach) {
                        log_info("Detaching loop devices.");
                        r = loopback_detach_all(&changed);
                        if (r == 0)
                                need_loop_detach = false;
                        else if (r > 0)
                                log_info("Not all loop devices detached, %d left.", r);
                        else
                                log_error("Failed to detach loop devices: %s", strerror(-r));
                }

                if (need_dm_detach) {
                        log_info("Detaching DM devices.");
                        r = dm_detach_all(&changed);
                        if (r == 0)
                                need_dm_detach = false;
                        else if (r > 0)
                                log_warning("Not all DM devices detached, %d left.", r);
                        else
                                log_error("Failed to detach DM devices: %s", strerror(-r));
                }

                if (!need_umount && !need_swapoff && !need_loop_detach && !need_dm_detach) {
                        if (retries > 0)
                                log_info("All filesystems, swaps, loop devices, DM devices detached.");
                        /* Yay, done */
                        break;
                }

                /* If in this iteration we didn't manage to
                 * unmount/deactivate anything, we simply give up */
                if (!changed) {
                        log_error("Cannot finalize remaining file systems and devices, giving up.");
                        break;
                }

                log_debug("Couldn't finalize remaining file systems and devices after %u retries, trying again.", retries+1);
        }

        if (retries >= FINALIZE_ATTEMPTS)
                log_error("Too many iterations, giving up.");

        arguments[0] = NULL;
        arguments[1] = argv[1];
        arguments[2] = NULL;
        execute_directory(SYSTEM_SHUTDOWN_PATH, NULL, arguments);

        if (!in_container &&
            access("/run/initramfs/shutdown", X_OK) == 0) {

                if (prepare_new_root() >= 0 &&
                    pivot_to_new_root() >= 0) {
                        execv("/shutdown", argv);
                        log_error("Failed to execute shutdown binary: %m");
                }
        }

        if (cmd == LINUX_REBOOT_CMD_KEXEC) {

                if (!in_container) {
                        /* We cheat and exec kexec to avoid doing all its work */
                        pid_t pid = fork();

                        if (pid < 0)
                                log_error("Could not fork: %m. Falling back to normal reboot.");
                        else if (pid > 0) {
                                wait_for_terminate_and_warn("kexec", pid);
                                log_warning("kexec failed. Falling back to normal reboot.");
                        } else {
                                /* Child */
                                const char *args[3] = { "/sbin/kexec", "-e", NULL };
                                execv(args[0], (char * const *) args);
                                return EXIT_FAILURE;
                        }
                }

                cmd = RB_AUTOBOOT;
        }

        reboot(cmd);

        if (errno == EPERM && in_container) {
                /* If we are in a container, and we lacked
                 * CAP_SYS_BOOT just exit, this will kill our
                 * container for good. */
                log_error("Exiting container.");
                exit(0);
        }

        log_error("Failed to invoke reboot(): %m");
        r = -errno;

  error:
        log_error("Critical error while doing system shutdown: %s", strerror(-r));

        freeze();
        return EXIT_FAILURE;
}
Exemple #2
0
int main(int argc, char *argv[]) {
        int cmd, r;
        unsigned retries;
        bool need_umount = true, need_swapoff = true, need_loop_detach = true, need_dm_detach = true;
        bool killed_everbody = false, in_container;

        log_parse_environment();
        log_set_target(LOG_TARGET_CONSOLE); /* syslog will die if not gone yet */
        log_open();

        if (getpid() != 1) {
                log_error("Not executed by init (pid 1).");
                r = -EPERM;
                goto error;
        }

        if (argc != 2) {
                log_error("Invalid number of arguments.");
                r = -EINVAL;
                goto error;
        }

        in_container = detect_container(NULL) > 0;

        if (streq(argv[1], "reboot"))
                cmd = RB_AUTOBOOT;
        else if (streq(argv[1], "poweroff"))
                cmd = RB_POWER_OFF;
        else if (streq(argv[1], "halt"))
                cmd = RB_HALT_SYSTEM;
        else if (streq(argv[1], "kexec"))
                cmd = LINUX_REBOOT_CMD_KEXEC;
        else {
                log_error("Unknown action '%s'.", argv[1]);
                r = -EINVAL;
                goto error;
        }

        /* lock us into memory */
        if (mlockall(MCL_CURRENT|MCL_FUTURE) != 0)
                log_warning("Cannot lock process memory: %m");

        log_info("Sending SIGTERM to remaining processes...");
        send_signal(SIGTERM);

        log_info("Sending SIGKILL to remaining processes...");
        send_signal(SIGKILL);

        if (in_container)
                need_swapoff = false;

        /* Unmount all mountpoints, swaps, and loopback devices */
        for (retries = 0; retries < FINALIZE_ATTEMPTS; retries++) {
                bool changed = false;

                if (need_umount) {
                        log_info("Unmounting file systems.");
                        r = umount_all(&changed);
                        if (r == 0)
                                need_umount = false;
                        else if (r > 0)
                                log_info("Not all file systems unmounted, %d left.", r);
                        else
                                log_error("Failed to unmount file systems: %s", strerror(-r));
                }

                if (need_swapoff) {
                        log_info("Disabling swaps.");
                        r = swapoff_all(&changed);
                        if (r == 0)
                                need_swapoff = false;
                        else if (r > 0)
                                log_info("Not all swaps are turned off, %d left.", r);
                        else
                                log_error("Failed to turn off swaps: %s", strerror(-r));
                }

                if (need_loop_detach) {
                        log_info("Detaching loop devices.");
                        r = loopback_detach_all(&changed);
                        if (r == 0)
                                need_loop_detach = false;
                        else if (r > 0)
                                log_info("Not all loop devices detached, %d left.", r);
                        else
                                log_error("Failed to detach loop devices: %s", strerror(-r));
                }

                if (need_dm_detach) {
                        log_info("Detaching DM devices.");
                        r = dm_detach_all(&changed);
                        if (r == 0)
                                need_dm_detach = false;
                        else if (r > 0)
                                log_warning("Not all DM devices detached, %d left.", r);
                        else
                                log_error("Failed to detach DM devices: %s", strerror(-r));
                }

                if (!need_umount && !need_swapoff && !need_loop_detach && !need_dm_detach)
                        /* Yay, done */
                        break;

                /* If in this iteration we didn't manage to
                 * unmount/deactivate anything, we either kill more
                 * processes, or simply give up */
                if (!changed) {

                        if (killed_everbody) {
                                /* Hmm, we already killed everybody,
                                 * let's just give up */
                                log_error("Cannot finalize remaining file systems and devices, giving up.");
                                break;
                        }

                        log_warning("Cannot finalize remaining file systems and devices, trying to kill remaining processes.");
                        ultimate_send_signal(SIGTERM);
                        ultimate_send_signal(SIGKILL);
                        killed_everbody = true;
                }

                log_debug("Couldn't finalize remaining file systems and devices after %u retries, trying again.", retries+1);
        }

        if (retries >= FINALIZE_ATTEMPTS)
                log_error("Too many iterations, giving up.");

        execute_directory(SYSTEM_SHUTDOWN_PATH, NULL, NULL);

        /* If we are in a container, just exit, this will kill our
         * container for good. */
        if (in_container) {
                log_error("Exiting container.");
                exit(0);
        }

        sync();

        if (cmd == LINUX_REBOOT_CMD_KEXEC) {
                /* We cheat and exec kexec to avoid doing all its work */
                pid_t pid = fork();

                if (pid < 0)
                        log_error("Could not fork: %m. Falling back to normal reboot.");
                else if (pid > 0) {
                        wait_for_terminate_and_warn("kexec", pid);
                        log_warning("kexec failed. Falling back to normal reboot.");
                } else {
                        /* Child */
                        const char *args[3] = { "/sbin/kexec", "-e", NULL };
                        execv(args[0], (char * const *) args);
                        return EXIT_FAILURE;
                }

                cmd = RB_AUTOBOOT;
        }

        reboot(cmd);
        log_error("Failed to invoke reboot(): %m");
        r = -errno;

  error:
        log_error("Critical error while doing system shutdown: %s", strerror(-r));

        freeze();
        return EXIT_FAILURE;
}
Exemple #3
0
int main(int argc, char *argv[]) {
        bool need_umount, need_swapoff, need_loop_detach, need_dm_detach;
        bool in_container, use_watchdog = false;
        _cleanup_free_ char *cgroup = NULL;
        char *arguments[3];
        unsigned retries;
        int cmd, r;

        log_parse_environment();
        r = parse_argv(argc, argv);
        if (r < 0)
                goto error;

        /* The log target defaults to console, but may
         * have been changed by command line options. */

        log_close_console(); /* force reopen of /dev/console */
        log_open();

        umask(0022);

        if (getpid() != 1) {
                log_error("Not executed by init (PID 1).");
                r = -EPERM;
                goto error;
        }

        if (streq(arg_verb, "reboot"))
                cmd = RB_AUTOBOOT;
        else if (streq(arg_verb, "poweroff"))
                cmd = RB_POWER_OFF;
        else if (streq(arg_verb, "halt"))
                cmd = RB_HALT_SYSTEM;
        else if (streq(arg_verb, "kexec"))
                cmd = LINUX_REBOOT_CMD_KEXEC;
        else {
                r = -EINVAL;
                log_error("Unknown action '%s'.", arg_verb);
                goto error;
        }

        cg_get_root_path(&cgroup);

        use_watchdog = !!getenv("WATCHDOG_USEC");

        /* lock us into memory */
        mlockall(MCL_CURRENT|MCL_FUTURE);

        log_info("Sending SIGTERM to remaining processes...");
        broadcast_signal(SIGTERM, true, true);

        log_info("Sending SIGKILL to remaining processes...");
        broadcast_signal(SIGKILL, true, false);

        in_container = detect_container(NULL) > 0;

        need_umount = true;
        need_swapoff = !in_container;
        need_loop_detach = !in_container;
        need_dm_detach = !in_container;

        /* Unmount all mountpoints, swaps, and loopback devices */
        for (retries = 0; retries < FINALIZE_ATTEMPTS; retries++) {
                bool changed = false;

                if (use_watchdog)
                        watchdog_ping();

                /* Let's trim the cgroup tree on each iteration so
                   that we leave an empty cgroup tree around, so that
                   container managers get a nice notify event when we
                   are down */
                if (cgroup)
                        cg_trim(SYSTEMD_CGROUP_CONTROLLER, cgroup, false);

                if (need_umount) {
                        log_info("Unmounting file systems.");
                        r = umount_all(&changed);
                        if (r == 0) {
                                need_umount = false;
                                log_info("All filesystems unmounted.");
                        } else if (r > 0)
                                log_info("Not all file systems unmounted, %d left.", r);
                        else
                                log_error("Failed to unmount file systems: %s", strerror(-r));
                }

                if (need_swapoff) {
                        log_info("Deactivating swaps.");
                        r = swapoff_all(&changed);
                        if (r == 0) {
                                need_swapoff = false;
                                log_info("All swaps deactivated.");
                        } else if (r > 0)
                                log_info("Not all swaps deactivated, %d left.", r);
                        else
                                log_error("Failed to deactivate swaps: %s", strerror(-r));
                }

                if (need_loop_detach) {
                        log_info("Detaching loop devices.");
                        r = loopback_detach_all(&changed);
                        if (r == 0) {
                                need_loop_detach = false;
                                log_info("All loop devices detached.");
                        } else if (r > 0)
                                log_info("Not all loop devices detached, %d left.", r);
                        else
                                log_error("Failed to detach loop devices: %s", strerror(-r));
                }

                if (need_dm_detach) {
                        log_info("Detaching DM devices.");
                        r = dm_detach_all(&changed);
                        if (r == 0) {
                                need_dm_detach = false;
                                log_info("All DM devices detached.");
                        } else if (r > 0)
                                log_info("Not all DM devices detached, %d left.", r);
                        else
                                log_error("Failed to detach DM devices: %s", strerror(-r));
                }

                if (!need_umount && !need_swapoff && !need_loop_detach && !need_dm_detach) {
                        if (retries > 0)
                                log_info("All filesystems, swaps, loop devices, DM devices detached.");
                        /* Yay, done */
                        goto initrd_jump;
                }

                /* If in this iteration we didn't manage to
                 * unmount/deactivate anything, we simply give up */
                if (!changed) {
                        log_info("Cannot finalize remaining%s%s%s%s continuing.",
                                 need_umount ? " file systems," : "",
                                 need_swapoff ? " swap devices," : "",
                                 need_loop_detach ? " loop devices," : "",
                                 need_dm_detach ? " DM devices," : "");
                        goto initrd_jump;
                }

                log_debug("After %u retries, couldn't finalize remaining %s%s%s%s trying again.",
                          retries + 1,
                          need_umount ? " file systems," : "",
                          need_swapoff ? " swap devices," : "",
                          need_loop_detach ? " loop devices," : "",
                          need_dm_detach ? " DM devices," : "");
        }

        log_error("Too many iterations, giving up.");

 initrd_jump:

        arguments[0] = NULL;
        arguments[1] = arg_verb;
        arguments[2] = NULL;
        execute_directory(SYSTEM_SHUTDOWN_PATH, NULL, DEFAULT_TIMEOUT_USEC, arguments);

        if (need_umount || need_swapoff || need_loop_detach || need_dm_detach)
                log_error("Failed to finalize %s%s%s%s ignoring",
                          need_umount ? " file systems," : "",
                          need_swapoff ? " swap devices," : "",
                          need_loop_detach ? " loop devices," : "",
                          need_dm_detach ? " DM devices," : "");

        /* The kernel will automaticall flush ATA disks and suchlike
         * on reboot(), but the file systems need to be synce'd
         * explicitly in advance. So let's do this here, but not
         * needlessly slow down containers. */
        if (!in_container)
                sync();

        switch (cmd) {

        case LINUX_REBOOT_CMD_KEXEC:

                if (!in_container) {
                        /* We cheat and exec kexec to avoid doing all its work */
                        pid_t pid;

                        log_info("Rebooting with kexec.");

                        pid = fork();
                        if (pid < 0)
                                log_error("Failed to fork: %m");
                        else if (pid == 0) {

                                const char * const args[] = {
                                        KEXEC, "-e", NULL
                                };

                                /* Child */

                                execv(args[0], (char * const *) args);
                                _exit(EXIT_FAILURE);
                        } else
                                wait_for_terminate_and_warn("kexec", pid);
                }

                cmd = RB_AUTOBOOT;
                /* Fall through */

        case RB_AUTOBOOT:

                if (!in_container) {
                        _cleanup_free_ char *param = NULL;

                        if (read_one_line_file(REBOOT_PARAM_FILE, &param) >= 0) {
                                log_info("Rebooting with argument '%s'.", param);
                                syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, param);
                        }
                }

                log_info("Rebooting.");
                break;

        case RB_POWER_OFF:
                log_info("Powering off.");
                break;

        case RB_HALT_SYSTEM:
                log_info("Halting system.");
                break;

        default:
                assert_not_reached("Unknown magic");
        }

        reboot(cmd);
        if (errno == EPERM && in_container) {
                /* If we are in a container, and we lacked
                 * CAP_SYS_BOOT just exit, this will kill our
                 * container for good. */
                log_info("Exiting container.");
                exit(0);
        }

        log_error("Failed to invoke reboot(): %m");
        r = -errno;

  error:
        log_error("Critical error while doing system shutdown: %s", strerror(-r));

        freeze();
}
Exemple #4
0
int main(int argc, char *argv[]) {
        const char *verb;
        char* arguments[4];
        int r;
        FILE *f;

        log_set_target(LOG_TARGET_AUTO);
        log_parse_environment();
        log_open();

        if (argc != 2) {
                log_error("Invalid number of arguments.");
                r = -EINVAL;
                goto finish;
        }

        if (streq(argv[1], "suspend"))
                verb = "mem";
        else if (streq(argv[1], "hibernate"))
                verb = "disk";
        else {
                log_error("Unknown action '%s'.", argv[1]);
                r = -EINVAL;
                goto finish;
        }

        f = fopen("/sys/power/state", "we");
        if (!f) {
                log_error("Failed to open /sys/power/state: %m");
                r = -errno;
                goto finish;
        }

        arguments[0] = NULL;
        arguments[1] = (char*) "pre";
        arguments[2] = argv[1];
        arguments[3] = NULL;
        execute_directory(SYSTEM_SLEEP_PATH, NULL, arguments);

        if (streq(argv[1], "suspend"))
                log_info("Suspending system...");
        else
                log_info("Hibernating system...");

        fputs(verb, f);
        fputc('\n', f);
        fflush(f);

        r = ferror(f) ? -errno : 0;

        if (streq(argv[1], "suspend"))
                log_info("System resumed.");
        else
                log_info("System thawed.");

        arguments[1] = (char*) "post";
        execute_directory(SYSTEM_SLEEP_PATH, NULL, arguments);

        fclose(f);

finish:

        return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;

}