[systemd-devel] [PATCH 3/4] Adding halt binary to shutdown the system
Lennart Poettering
lennart at poettering.net
Tue Oct 5 13:47:04 PDT 2010
On Tue, 05.10.10 08:41, fidencio at profusion.mobi (fidencio at profusion.mobi) wrote:
> +
> +#define TIMEOUT_USEC 5000000
To make this more readable please write 5*USEC_PER_SEC here.
> +static bool ignore_proc(pid_t pid) {
> + if (pid == 1)
> + return true;
> +
> + return false;
> +}
> +
> +static unsigned int killall(DIR *dir, int sign) {
> + struct dirent *d;
> + pid_t pid;
> + unsigned int processes = 0;
> +
> + while ((d = readdir(dir))) {
> +
> + if ((pid = atoi(d->d_name)) == 0)
> + continue;
atoi() is evil... please use parse_pid() here!
> +
> + if (ignore_proc(pid))
> + continue;
> +
> + kill(pid, sign);
> + processes++;
We should increase the counter here only if the kill actually worked I believe.
> + }
> +
> + return processes;
> +}
> +
> +static unsigned int send_signal(DIR *dir, int sign) {
> + sigset_t mask;
> + usec_t until;
> + unsigned int processes;
> + struct timespec ts;
> +
> + sigemptyset(&mask);
> + sigaddset(&mask, SIGCHLD);
sigprocmask() is missing here? You need to make sure SIGCHLD is not
delivered via signal handlers here anymore.
> + processes = killall(dir, sign);
> +
> + until = now(CLOCK_REALTIME) + TIMEOUT_USEC;
> + for (;;) {
> + usec_t n;
> +
> + for (;;) {
> + n = now(CLOCK_REALTIME);
> + if (n >= until)
> + goto finish;
> +
> + if (waitpid(-1, NULL, WNOHANG) <= 0)
> + break;
> +
> + if (--processes == 0)
> + goto finish;
> + }
> +
> + timespec_store(&ts, until - n);
> + sigtimedwait(&mask, NULL, &ts);
Please handle errors here. Write a log message at least.
> + }
> +
> +finish:
> + return processes;
> +}
> +
> +int main(int argc, char *argv[]) {
> + DIR *dir;
> + int cmd;
> + const char *args[5] = {KEXEC_BINARY_PATH, "-e", "-x", "-f", NULL};
> +
> + if (getpid() != 1)
> + return EXIT_FAILURE;
> +
> + if (argc != 2)
> + return EXIT_FAILURE;
Please add explanatory log messages here.
> +
> + log_set_target(LOG_TARGET_SYSLOG_OR_KMSG);
> + log_parse_environment();
> + log_open();
> +
> + 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;
> +
> + /* lock us into memory */
> + mlockall(MCL_CURRENT|MCL_FUTURE);
> +
> + /* opening /proc to read all processes */
> + if ((dir = opendir("/proc")) == NULL)
> + return EXIT_FAILURE;
> +
> + /* sending SIGTERM and SIGKILL to all processes */
> + kill(-1, SIGSTOP);
> + log_info("Sending SIGTERM To Processes");
> + if ((send_signal(dir, SIGTERM)) > 0) {
> + log_info("Sending SIGKILL To Processes");
> + send_signal(dir, SIGKILL);
> + }
> + kill(-1, SIGCONT);
> +
> + /* preventing that we won't block umounts */
> + if (chdir("/") == -1)
> + return EXIT_FAILURE;
> +
> + /* umount all mountpoints, swaps, dm and loops */
> + log_info("Unmounting Filesystems");
> + umount_all();
> + log_info("Disabling Swaps");
> + swapoff_all();
> + /* FIXME:
> + * - undm_all()
> + * - unloop_all()
> + * - handling devicemapper
> + */
You need a loop here. i.e. a swap you drop might make it possible to
unmount another fs (because the swap was about a swap file, not a swap
device). And so on.
> +
> + sync();
> +
> + if (cmd == RB_AUTOBOOT)
> + execv(args[0], (char * const *) args);
Please add a proper verb above so that we can distuingish kexec and
normal reboots. (We probably want to have this all the way so that
there's a first klass kexec target and everything.
> +
> + return reboot(cmd);
> +}
reboot() returns -1 on failure, which is not suitable for retruning from main().
Otherwise looks good!
Lennart
--
Lennart Poettering - Red Hat, Inc.
More information about the systemd-devel
mailing list