From b0aec188bc843558d9512124236fe2f1fe5fb6c1 Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Mon, 17 Sep 2012 10:21:33 +0200 Subject: [PATCH] Further cleanup, move signal setup to a file of its own. finit.c: o Perform signal setup as soon as possible, no need to do any mounting of /proc or /sys beforehand o Move signal setup and callbacks to a file of its own o Use more #defines for hard coded strings o Use a more neutral default hostname signal.c: o New file, for setup and signal handlers o Add support for SIGSTOP/SIGSTP and SIGCONT. This pauses finit respawning of xinit/shell. Useful for, e.g., debugging o Document each ignored and handled signal better o Disable SIGUSR1 and SIGUSR2 for now, will be reenabled later Signed-off-by: Joachim Nilsson --- Makefile | 2 +- finit.c | 131 +++++--------------------------------- finit.h | 31 +++++---- initctl.c | 4 +- signal.c | 184 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 222 insertions(+), 130 deletions(-) create mode 100644 signal.c diff --git a/Makefile b/Makefile index 6a2e9d4e..39813475 100644 --- a/Makefile +++ b/Makefile @@ -28,7 +28,7 @@ ROOTDIR ?= $(shell pwd) VERSION = 1.0-pre PKG = finit-$(VERSION) EXEC = finit -OBJS = finit.o helpers.o initctl.o +OBJS = finit.o helpers.o initctl.o signal.o SRCS = $(OBJS:.o=.c) DEPS = $(addprefix .,$(SRCS:.c=.d)) CPPFLAGS += -DVERSION=\"$(VERSION)\" -DWHOAMI=\"`whoami`@`hostname`\" diff --git a/finit.c b/finit.c index 80fe3729..670d152b 100644 --- a/finit.c +++ b/finit.c @@ -22,31 +22,18 @@ THE SOFTWARE. */ -#include #include -#include #include #include -#include -#include -#include #include -#include -#include -#include -#include -#include #include #include #include "finit.h" #include "helpers.h" -static void chld_handler(int sig __attribute__ ((unused))); -static void sig_init(void); - -static int debug = 0; -static char sdown[CMD_SIZE] = ""; +int debug = 0; +char sdown[CMD_SIZE] = ""; static void build_cmd(char *cmd, char *x, int len) @@ -57,7 +44,7 @@ static void build_cmd(char *cmd, char *x, int len) c = cmd + strlen(cmd); /* skip spaces */ - for (; *x && (*x == ' ' || *x == '\t'); x++) ; + for (; *x && (*x == ' ' || *x == '\t'); x++); /* copy next arg */ for (l = 0; *x && *x != '#' && *x != '\t' && l < len; l++) @@ -72,7 +59,7 @@ int main(void) FILE *f; char line[LINE_SIZE]; char username[USERNAME_SIZE] = DEFUSER; - char hostname[HOSTNAME_SIZE] = "eviltwin"; + char hostname[HOSTNAME_SIZE] = DEFHOST; char cmd[CMD_SIZE]; char startx[CMD_SIZE] = "xinit"; #ifdef USE_ETC_RESOLVCONF_RUN @@ -86,15 +73,15 @@ int main(void) int fd; #endif + /* Setup signals */ + sig_init(); + chdir("/"); umask(022); mount("none", "/proc", "proc", 0, NULL); mount("none", "/sys", "sysfs", 0, NULL); - /* Setup signals */ - sig_init(); - /* * Parse kernel parameters */ @@ -119,7 +106,8 @@ int main(void) if ((f = fopen("/etc/finit.conf", "r")) != NULL) { char *x; while (!feof(f)) { - fgets(line, LINE_SIZE, f); + if (!fgets(line, LINE_SIZE, f)) + continue; chomp(line); _d("conf: %s", line); @@ -308,6 +296,7 @@ int main(void) touch("/etc/network/run/ifstate"); #endif + /* Set initial hostname. */ if ((f = fopen("/etc/hostname", "r")) != NULL) { fgets(hostname, HOSTNAME_SIZE, f); chomp(hostname); @@ -401,7 +390,12 @@ int main(void) /* ConsoleKit needs this */ setenv("DISPLAY", ":0", 1); - while (!fexist("/tmp/shutdown")) { + while (!fexist(SYNC_SHUTDOWN)) { + if (fexist(SYNC_STOPPED)) { + sleep(2); + continue; + } + _d("start X as %s\n", username); if (debug) { snprintf(line, LINE_SIZE, @@ -434,99 +428,6 @@ int main(void) return 0; } -/* - * Shut down on INT USR1 USR2 - */ -void shutdown_handler(int sig) -{ - touch("/tmp/shutdown"); - if (sdown[0] != 0) { - system(sdown); - } - - kill(-1, SIGTERM); - - write(1, "\033[?25l\033[30;40m", 14); - copyfile("/boot/shutdown.fb", "/dev/fb/0", 0); - sleep(2); - - system("/usr/sbin/alsactl store > /dev/null 2>&1"); - system("/sbin/hwclock --systohc"); - - kill(-1, SIGKILL); - - sync(); - sync(); - system("/bin/umount -a;/bin/mount -n -o remount,ro /"); - //system("/sbin/unionctl.static / --remove / > /dev/null 2>&1"); - - if (sig == SIGINT || sig == SIGUSR1) - reboot(RB_AUTOBOOT); - - reboot(RB_POWER_OFF); -} - -/* - * SIGCHLD: one of our children has died - */ -static void chld_handler(int sig __attribute__ ((unused))) -{ - int status; - - while (waitpid(-1, &status, WNOHANG) != 0) { - if (errno == ECHILD) - break; - } -} - -/* - * Signal management - Be conservative with what finit responds to! - * - * The standard SysV init only responds to the following signals: - * SIGHUP - * Has the same effect as telinit q. - * - * SIGUSR1 - * On receipt of this signals, init closes and re-opens its control - * fifo, /dev/initctl. Useful for bootscripts when /dev is remounted. - * - * SIGINT - * Normally the kernel sends this signal to init when CTRL-ALT-DEL is - * pressed. It activates the ctrlaltdel action. - * - * SIGWINCH - * The kernel sends this signal when the KeyboardSignal key is hit. - * It activates the kbrequest action. - */ -static void sig_init(void) -{ - int i; - sigset_t nmask; - struct sigaction sa; - - for (i = 1; i < NSIG; i++) - SETSIG(sa, i, SIG_IGN, SA_RESTART); - - SETSIG(sa, SIGINT, shutdown_handler, 0); - SETSIG(sa, SIGPWR, SIG_IGN, 0); - SETSIG(sa, SIGUSR1, shutdown_handler, 0); - SETSIG(sa, SIGUSR2, shutdown_handler, 0); - SETSIG(sa, SIGTERM, SIG_IGN, 0); - SETSIG(sa, SIGALRM, SIG_IGN, 0); - SETSIG(sa, SIGHUP, SIG_IGN, 0); - SETSIG(sa, SIGCONT, SIG_IGN, SA_RESTART); - SETSIG(sa, SIGCHLD, chld_handler, SA_RESTART); - - /* Block sigchild while forking */ - sigemptyset(&nmask); - sigaddset(&nmask, SIGCHLD); - sigprocmask(SIG_BLOCK, &nmask, NULL); - - /* Disable CTRL-ALT-DELETE from kernel, we handle shutdown gracefully with SIGINT */ - reboot(RB_DISABLE_CAD); - setsid(); -} - /** * Local Variables: * version-control: t diff --git a/finit.h b/finit.h index dc5a27f5..6595a07d 100644 --- a/finit.h +++ b/finit.h @@ -25,6 +25,15 @@ #ifndef FINIT_H__ #define FINIT_H__ +#include +#include +#include +#include +#include +#include +#include +#include + #include #define DO_LOG(level, fmt, args...) \ { \ @@ -71,26 +80,21 @@ #define USE_ETC_RESOLVCONF_RUN #endif +#define SYNC_SHUTDOWN "/var/lock/finit.shutdown" +#define SYNC_STOPPED "/var/lock/finit.stopped" + #ifndef DEFUSER #define DEFUSER "user" #endif +#ifndef DEFHOST +#define DEFHOST "noname" +#endif #define LINE_SIZE 1024 #define CMD_SIZE 256 #define USERNAME_SIZE 16 #define HOSTNAME_SIZE 32 -/* From sysvinit */ -/* Set a signal handler. */ -#define SETSIG(sa, sig, fun, flags) \ - do { \ - sa.sa_handler = fun; \ - sa.sa_flags = flags; \ - sigemptyset(&sa.sa_mask); \ - sigaction(sig, &sa, NULL); \ - } while (0) - - #ifndef touch #define touch(x) mknod((x), S_IFREG|0644, 0) #endif @@ -110,7 +114,10 @@ #define _d(fmt, args...) do { if (debug) { fprintf(stderr, "%s(): " fmt "\n", __func__, ##args); } } while (0) -void shutdown_handler(int sig); +extern int debug; + +void do_shutdown(int sig); +void sig_init(void); void listen_initctl(void); #endif /* FINIT_H__ */ diff --git a/initctl.c b/initctl.c index acc02093..0f004326 100644 --- a/initctl.c +++ b/initctl.c @@ -72,10 +72,10 @@ void listen_initctl(void) if (request.cmd == INIT_CMD_RUNLVL) { switch (request.runlevel) { case '0': - shutdown_handler(SIGUSR2); + do_shutdown(SIGUSR2); break; case '6': - shutdown_handler(SIGUSR1); + do_shutdown(SIGUSR1); } } } diff --git a/signal.c b/signal.c new file mode 100644 index 00000000..55ce3ba7 --- /dev/null +++ b/signal.c @@ -0,0 +1,184 @@ +/* + Improved fast init + + Copyright (c) 2008 Claudio Matsuoka + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#include +#include + +#include "finit.h" +#include "helpers.h" + +#define SETSIG(sa, sig, fun, flags) \ + do { \ + sa.sa_sigaction = fun; \ + sa.sa_flags = SA_SIGINFO | flags; \ + sigemptyset(&sa.sa_mask); \ + sigaction(sig, &sa, NULL); \ + } while (0) + +#define IGNSIG(sa, sig, flags) \ + do { \ + sa.sa_handler = SIG_IGN; \ + sa.sa_flags = flags; \ + sigemptyset(&sa.sa_mask); \ + sigaction(sig, &sa, NULL); \ + } while (0) + +static int stopped = 0; +extern char *sdown; + +void do_shutdown (int sig) +{ + touch(SYNC_SHUTDOWN); + if (sdown[0] != 0) { + system(sdown); + } + + kill(-1, SIGTERM); + + write(1, "\033[?25l\033[30;40m", 14); + copyfile("/boot/shutdown.fb", "/dev/fb/0", 0); + sleep(2); + + system("/usr/sbin/alsactl store > /dev/null 2>&1"); + system("/sbin/hwclock --systohc"); + + kill(-1, SIGKILL); + + sync(); + sync(); + system("/bin/umount -a;/bin/mount -n -o remount,ro /"); + //system("/sbin/unionctl.static / --remove / > /dev/null 2>&1"); + + if (sig == SIGINT || sig == SIGUSR1) + reboot(RB_AUTOBOOT); + + reboot(RB_POWER_OFF); +} + +/* + * Shut down on INT USR1 USR2 + */ +static void shutdown_handler(int sig, siginfo_t *info, void *ctx __attribute__ ((unused))) +{ + _d("finit: Rebooting on signal %d from pid %d with code %d", sig, info->si_pid, info->si_code); + + do_shutdown(sig); +} + +/* + * SIGCHLD: one of our children has died + */ +static void chld_handler(int sig, siginfo_t *info, void *ctx __attribute__ ((unused))) +{ + int status; + + _d("finit: Child died, harvesting... signal %d from pid %d with code %d", sig, info->si_pid, info->si_code); + while (waitpid(-1, &status, WNOHANG) != 0) { + if (errno == ECHILD) + break; + } +} + +/* + * SIGSTOP: Paused by user or netflash + */ +static void sigstop_handler(int sig, siginfo_t *info, void *ctx __attribute__ ((unused))) +{ + _d("finit: Received SIGSTOP(%d) from pid %d with code %d", sig, info->si_pid, info->si_code); + touch(SYNC_STOPPED); + stopped ++; +} +static void sigcont_handler(int sig, siginfo_t *info, void *ctx __attribute__ ((unused))) +{ + _d("finit: Received SIGCONT(%d) from pid %d with code %d", sig, info->si_pid, info->si_code); + stopped = 0; + remove(SYNC_STOPPED); +} + +/* + * Signal management - Be conservative with what finit responds to! + * + * The standard SysV init only responds to the following signals: + * SIGHUP + * Has the same effect as telinit q. + * + * SIGUSR1 + * On receipt of this signals, init closes and re-opens its control + * fifo, /dev/initctl. Useful for bootscripts when /dev is remounted. + * + * SIGINT + * Normally the kernel sends this signal to init when CTRL-ALT-DEL is + * pressed. It activates the ctrlaltdel action. + * + * SIGWINCH + * The kernel sends this signal when the KeyboardSignal key is hit. + * It activates the kbrequest action. + */ +void sig_init(void) +{ + int i; + sigset_t nmask; + struct sigaction sa; + + for (i = 1; i < NSIG; i++) + IGNSIG(sa, i, SA_RESTART); + + SETSIG(sa, SIGINT, shutdown_handler, 0); /* Standard SysV init calls ctrl-alt-delete handler */ + SETSIG(sa, SIGPWR, shutdown_handler, 0); + + /* Ignore SIGUSR1/2 for now, only BusyBox init implements them as reboot+halt. */ +// SETSIG2(sa, SIGUSR1, reopen_initctl, 0); +// SETSIG2(sa, SIGUSR2, pwrdwn_handler, 0); + + /* Init must ignore SIGTERM. May otherwise get false SIGTERM in forked children! */ + IGNSIG(sa, SIGTERM, 0); + + /* Some C APIs may need SIGALRM for implementing timers. */ + IGNSIG(sa, SIGALRM, 0); + + /* We don't have any /etc/inittab yet, reread finit.conf? */ + IGNSIG(sa, SIGHUP, 0); + + /* Stopping init is a bit tricky. */ + SETSIG(sa, SIGSTOP, sigstop_handler, 0); + SETSIG(sa, SIGTSTP, sigstop_handler, 0); + SETSIG(sa, SIGCONT, sigcont_handler, 0); + SETSIG(sa, SIGCHLD, chld_handler, SA_RESTART); + + /* Block SIGCHLD while forking */ + sigemptyset(&nmask); + sigaddset(&nmask, SIGCHLD); + sigprocmask(SIG_BLOCK, &nmask, NULL); + + /* Disable CTRL-ALT-DELETE from kernel, we handle shutdown gracefully with SIGINT */ + reboot(RB_DISABLE_CAD); + setsid(); +} + +/** + * Local Variables: + * version-control: t + * c-file-style: "ellemtel" + * End: + */