From c0356b5c7a62b7b493663a735c4487f57f053c10 Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Wed, 19 Sep 2012 17:44:35 +0200 Subject: [PATCH] Massive cleanup to be able to boot Debian 6.0 Update license and copyright information details in all files. Much cleanup by moving hard coded strings/data to #defines and using more common default values for each such #define. finit.c: o Make sdown[], startx[] allocated strings by default NULL o This fixes the issues where the shutdown handler segfaulted o Add ability to handle NULL input to build_cmd() by allocating space o Ignore kernel cmdline "quiet" if in debug mode o Add support for "network" stanza in finit.conf o Mount -n to skip removing /etc/mtab o Call swapon to enable swap if enabled in /etc/fstab o Cleanup /tmp, /var/run and /var/lock o Move sig_setup() *after* mount, sig_init() otoh runs early o Start initctl monitor before forking off startx/getty process o The startx process is now the console process. Only a getty is started when in debug mode. Otherwise only X is started if it is properly setup in /etc/finit.conf o NOTE: Currently X evdev does not work! o Support for /usr/sbin/services.sh has been replaced with finit now instead supporting builtin run-parts for /etc/finit.d/ helpers.c: o Bug fixes in run_parts() and also added chdir(oldpwd) at bottom. o New functions: - getuser() similar to getgroup() - cls() clear screen, only runs when not in debug mode - set_procname() used to set name "console" on console process - set_hostname() encapsulates /etc/hostname and sethostname() signal.c: o Split sig_setup() in two: sig_init() and sig_setup() The former to be called as soon as possible, while latter is supposed to run when the base filesystem is properly up. o Remove hard coded distribution specific progress bar write() o Add debug messages to do_shutdown() o Remove any lingering sync files in sig_setup() initctl.c: o Add debug messages and a new default: case to catch stray runlevels Signed-off-by: Joachim Nilsson --- LICENSE | 2 +- Makefile | 3 +- contrib/finit.conf | 3 + contrib/finit.d/services | 6 + finit.c | 238 +++++++++++++++++++++------------------ finit.h | 90 ++++++++------- helpers.c | 106 +++++++++++++++-- helpers.h | 44 +++++++- initctl.c | 64 +++++++---- signal.c | 140 +++++++++++++---------- 10 files changed, 451 insertions(+), 245 deletions(-) create mode 100644 contrib/finit.conf create mode 100755 contrib/finit.d/services diff --git a/LICENSE b/LICENSE index 6ee88f3f..c3a49545 100644 --- a/LICENSE +++ b/LICENSE @@ -1,5 +1,5 @@ Copyright (c) 2008-2010 Claudio Matsuoka -Copyright (c) 2009-2012 Joachim Nilsson +Copyright (c) 2008-2012 Joachim Nilsson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/Makefile b/Makefile index e8c92ff1..0f2de3b7 100644 --- a/Makefile +++ b/Makefile @@ -35,8 +35,7 @@ CFLAGS += -W -Wall -Werror -Os # Disable annoying gcc warning for "warn_unused_result", see GIT 37af997 CPPFLAGS += -U_FORTIFY_SOURCE CPPFLAGS += -I$(ROOTDIR)/$(CONFIG_LINUXDIR)/include/ -# Build for embedded systems, not notebook by default, see finit.h -CPPFLAGS += -DEMBEDDED_SYSTEM -DBUILTIN_RUNPARTS +CPPFLAGS += -DBUILTIN_RUNPARTS CPPFLAGS += -DVERSION=\"$(VERSION)\" -DWHOAMI=\"`whoami`@`hostname`\" CPPFLAGS += -D_XOPEN_SOURCE=600 -D_BSD_SOURCE -D_GNU_SOURCE diff --git a/contrib/finit.conf b/contrib/finit.conf new file mode 100644 index 00000000..0dbf32d8 --- /dev/null +++ b/contrib/finit.conf @@ -0,0 +1,3 @@ +# finit.conf +check /dev/vda1 + diff --git a/contrib/finit.d/services b/contrib/finit.d/services new file mode 100755 index 00000000..1d7bddd2 --- /dev/null +++ b/contrib/finit.d/services @@ -0,0 +1,6 @@ +#!/bin/sh +run-parts /etc/rcS.d --arg=start +run-parts /etc/rc2.d --arg=start +#service acpid start +#service networking start +#service ssh start diff --git a/finit.c b/finit.c index dd661dd3..f8c7c037 100644 --- a/finit.c +++ b/finit.c @@ -1,26 +1,26 @@ -/* - 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. -*/ +/* Improved fast init + * + * Copyright (c) 2008-2010 Claudio Matsuoka + * Copyright (c) 2008-2012 Joachim Nilsson + * + * 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 @@ -32,36 +32,44 @@ #include "finit.h" #include "helpers.h" -int debug = 0; -char sdown[CMD_SIZE] = ""; +int debug = 0; +char *sdown = NULL; +char *network = NULL; +char *startx = NULL; - -static void build_cmd(char *cmd, char *x, int len) +static char *build_cmd(char *cmd, char *line, int len) { int l; char *c; + /* Trim leading whitespace */ + while (*line && (*line == ' ' || *line == '\t')) + line++; + + if (!cmd) { + cmd = malloc (strlen(line) + 1); + if (!cmd) { + fprintf (stderr, "finit: No memory left for '%s'", line); + return NULL; + } + *cmd = 0; + } c = cmd + strlen(cmd); - - /* skip spaces */ - for (; *x && (*x == ' ' || *x == '\t'); x++); - - /* copy next arg */ - for (l = 0; *x && *x != '#' && *x != '\t' && l < len; l++) - *c++ = *x++; + for (l = 0; *line && *line != '#' && *line != '\t' && l < len; l++) + *c++ = *line++; *c = 0; _d("cmd = %s", cmd); + return cmd; } -int main(void) +int main(int UNUSED(args), char *argv[]) { - FILE *f; + FILE *fp; char line[LINE_SIZE]; char username[USERNAME_SIZE] = DEFUSER; char hostname[HOSTNAME_SIZE] = DEFHOST; char cmd[CMD_SIZE]; - char startx[CMD_SIZE] = "xinit"; #ifdef USE_ETC_RESOLVCONF_RUN DIR *dir; struct dirent *d; @@ -73,15 +81,16 @@ int main(void) int fd; #endif - /* Setup signals */ + /* + * Initial setup of signals, ignore all until we're up. + */ sig_init(); - chdir("/"); - umask(022); - /* * Mount base file system, kernel is assumed to run devtmpfs for /dev */ + chdir("/"); + umask(0); mount("none", "/proc", "proc", 0, NULL); mount("none", "/proc/bus/usb", "usbfs", 0, NULL); mount("none", "/sys", "sysfs", 0, NULL); @@ -89,44 +98,49 @@ int main(void) mkdir("/dev/shm", 0755); mount("none", "/dev/pts", "devpts", 0, "gid=5,mode=620"); mount("none", "/dev/shm", "tmpfs", 0, NULL); + umask(022); /* * Populate /dev and prepare for runtime events from kernel. */ -#ifdef MDEV - system("sysctl -w kernel.hotplug=" MDEV); - system(MDEV " -s"); +#if defined(USE_UDEV) + system("udevd --daemon"); +#elif defined (MDEV) + system(MDEV "-s"); #endif /* * Parse kernel parameters */ - if ((f = fopen("/proc/cmdline", "r")) != NULL) { - fgets(line, LINE_SIZE, f); + if ((fp = fopen("/proc/cmdline", "r")) != NULL) { + fgets(line, LINE_SIZE, fp); if (strstr(line, "finit_debug") || - strstr(line, "--verbose")) { + strstr(line, "--verbose") || + strstr(line, "--debug")) debug = 1; - } - if (strstr(line, "quiet")) { + if (!debug && strstr(line, "quiet")) { close(0); close(1); close(2); } - fclose(f); + fclose(fp); } + cls(); _d("finit " VERSION " (built " __DATE__ " " __TIME__ " by " WHOAMI ")"); /* * Parse configuration file */ - if ((f = fopen("/etc/finit.conf", "r")) != NULL) { + if ((fp = fopen(FINIT_CONF, "r")) != NULL) { char *x; - while (!feof(f)) { - if (!fgets(line, LINE_SIZE, f)) + + _d("Parse %s ...", FINIT_CONF); + while (!feof(fp)) { + if (!fgets(line, LINE_SIZE, fp)) continue; chomp(line); @@ -148,19 +162,14 @@ int main(void) build_cmd(username, x, USERNAME_SIZE); continue; } - if (MATCH_CMD(line, "startx ", x)) { - *startx = 0; - build_cmd(startx, x, CMD_SIZE); - continue; - } if (MATCH_CMD(line, "host ", x)) { *hostname = 0; build_cmd(hostname, x, HOSTNAME_SIZE); continue; } if (MATCH_CMD(line, "shutdown ", x)) { - *sdown = 0; - build_cmd(sdown, x, CMD_SIZE); + if (sdown) free(sdown); + sdown = build_cmd(NULL, x, CMD_SIZE); continue; } if (MATCH_CMD(line, "module ", x)) { @@ -175,14 +184,24 @@ int main(void) system(cmd); continue; } + if (MATCH_CMD(line, "network ", x)) { + if (network) free(network); + network = build_cmd(NULL, x, CMD_SIZE); + continue; + } + if (MATCH_CMD(line, "startx ", x)) { + if (startx) free(startx); + startx = build_cmd(NULL, x, CMD_SIZE); + continue; + } } - fclose(f); + fclose(fp); } /* * Mount filesystems */ - _d("mount filesystems"); + _d("Mount filesystems in /etc/fstab ..."); #ifdef REMOUNT_ROOTFS_RW system("/bin/mount -n -o remount,rw /"); @@ -191,15 +210,23 @@ int main(void) mount(SYSROOT, "/", NULL, MS_MOVE, NULL); #endif umask(0); - unlink("/etc/mtab"); - system("mount -a"); + system("mount -na"); + system("swapon -ea"); umask(0022); + /* Cleanup stale files, if any still linger on. */ + system("rm -rf /tmp/* /var/run/* /var/lock/*"); + + /* + * Base FS up, enable standard SysV init signals + */ + sig_setup(); + /* * Time adjustments */ - _d("adjust clock"); #ifndef NO_HCTOSYS + _d("Adjust system clock ..."); system("/sbin/hwclock --hctosys"); #endif @@ -229,11 +256,11 @@ int main(void) symlink("../../../etc/resolv.conf", "/var/run/resolvconf/resolv.conf"); #endif +#ifdef RUNLEVEL touch("/var/run/utmp"); chown("/var/run/utmp", 0, getgroup("utmp")); chmod("/var/run/utmp", 0664); -#ifdef RUNLEVEL memset(&entry, 0, sizeof(struct utmp)); entry.ut_type = RUN_LVL; entry.ut_pid = '0' + RUNLEVEL; @@ -259,15 +286,13 @@ int main(void) #endif /* Set initial hostname. */ - if ((f = fopen("/etc/hostname", "r")) != NULL) { - fgets(hostname, HOSTNAME_SIZE, f); - chomp(hostname); - fclose(f); - } - - sethostname(hostname, strlen(hostname)); + set_hostname(hostname); ifconfig("lo", "127.0.0.1", "255.0.0.0", 1); + if (network) { + _d("Starting networking: %s", network); + system(network); + } /* * Set random seed @@ -302,13 +327,14 @@ int main(void) mkdir("/tmp/.ICE-unix", 01777); umask(022); - /* Start console login. */ - system(GETTY "&"); +#ifdef LISTEN_INITCTL + listen_initctl(); +#endif - _d("forking"); if (!fork()) { /* child process */ int i; + char c; sigset_t nmask; struct sigaction sa; @@ -331,55 +357,53 @@ int main(void) for (i = 1; i < NSIG; i++) sigaction(i, &sa, NULL); - dup2(0, 0); - dup2(0, 1); - dup2(0, 2); + dup2(0, STDIN_FILENO); + dup2(0, STDOUT_FILENO); + dup2(0, STDERR_FILENO); -#ifdef USE_MESSAGE_BUS - _d("dbus"); - mkdir("/var/run/dbus", 0755); - mkdir("/var/lock/subsys/messagebus", 0755); - system("dbus-uuidgen --ensure;dbus-daemon --system"); -#endif - -#ifdef LISTEN_INITCTL - listen_initctl(); -#endif - - /* Prevents bash from running loadkeys */ - unsetenv("TERM"); + set_procname(argv, "console"); /* ConsoleKit needs this */ setenv("DISPLAY", ":0", 1); +#ifdef USE_MESSAGE_BUS + _d("Starting D-Bus ..."); + mkdir("/var/run/dbus", 0755); + mkdir("/var/lock/subsys/messagebus", 0755); + system("dbus-uuidgen --ensure"); + system("su -c \"dbus-daemon --system\" messagebus"); +#endif + + /* Run startup scripts in /etc/finit.d/, if any. */ + run_parts(FINIT_RCSD); + while (!fexist(SYNC_SHUTDOWN)) { if (fexist(SYNC_STOPPED)) { - sleep(2); + sleep(1); continue; } - _d("start X as %s\n", username); - if (debug) { - snprintf(line, LINE_SIZE, - "su -l %s -c \"%s\"", username, startx); + if (startx && !debug) { + snprintf(line, sizeof(line), "su -c \"%s\" -l %s", startx, username); system(line); - system("/bin/sh"); } else { - snprintf(line, LINE_SIZE, - "su -l %s -c \"%s\" &> /dev/null", - username, startx); - system(line); + static const char msg[] = "\nPlease press Enter to activate this console. "; + + i = write(STDERR_FILENO, msg, sizeof(msg) - 1); + while (read(STDIN_FILENO, &c, 1) == 1 && c != '\n') + continue; + + if (fexist(SYNC_STOPPED)) + continue; + + system(GETTY); } } exit(0); } - /* parent process */ - - /* sleep(1); */ - system("/usr/sbin/services.sh &>/dev/null&"); - + /* We're the grim reaper of innocent orphaned children ... */ while (1) { sigset_t nmask; diff --git a/finit.h b/finit.h index 7729492b..7bcc61f8 100644 --- a/finit.h +++ b/finit.h @@ -1,29 +1,29 @@ -/* - Improved fast init +/* Improved fast init + * + * Copyright (c) 2008-2010 Claudio Matsuoka + * Copyright (c) 2008-2012 Joachim Nilsson + * + * 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. + */ - 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. -*/ - -#ifndef FINIT_H__ -#define FINIT_H__ +#ifndef FINIT_H_ +#define FINIT_H_ #include #include @@ -45,6 +45,10 @@ #define DEBUG(fmt, args...) DO_LOG(LOG_DEBUG, fmt, ##args) #define ERROR(fmt, args...) DO_LOG(LOG_CRIT, fmt, ##args) +#define FINIT_FIFO "/dev/initctl" +#define FINIT_CONF "/etc/finit.conf" +#define FINIT_RCSD "/etc/finit.d" + /* Distribution configuration */ #if defined EMBEDDED_SYSTEM @@ -82,19 +86,20 @@ # define USE_ETC_RESOLVCONF_RUN #else /* Ubuntu */ # define RANDOMSEED "/var/lib/urandom/random-seed" -# define CONSOLE "/dev/console" -# define MDEV "\"/bin/busybox mdev\"" -# define GETTY "/usr/bin/openvt /sbin/getty 38400 tty2" +# define CONSOLE "/dev/tty1" +# define GETTY "/sbin/getty -8 38400 tty1" # define REMOUNT_ROOTFS_RW -# define TOUCH_ETC_NETWORK_RUN_IFSTATE +# define RUNLEVEL 2 # define LISTEN_INITCTL +# define USE_UDEV +# define USE_MESSAGE_BUS #endif #define SYNC_SHUTDOWN "/var/lock/finit.shutdown" #define SYNC_STOPPED "/var/lock/finit.stopped" #ifndef DEFUSER -# define DEFUSER "user" +# define DEFUSER "root" #endif #ifndef DEFHOST # define DEFHOST "noname" @@ -118,19 +123,28 @@ # define fexist(x) (access(x, F_OK) != -1) #endif +#ifndef UNUSED +#define UNUSED(x) UNUSED_ ## x __attribute__ ((unused)) +#endif + /* Match one command. */ -#define MATCH_CMD(l,c,x) \ - ((!strncmp((l), (c), strlen((c)))) && ((x) = (l) + strlen((c)))) +#define MATCH_CMD(l, c, x) \ + (!strncmp(l, c, strlen(c)) && (x = (l) + strlen(c))) -#define _d(fmt, args...) do { if (debug) { fprintf(stderr, "%s(): " fmt "\n", __func__, ##args); } } while (0) +#define _d(fmt, args...) do { if (debug) { fprintf(stderr, "finit:%s() - " fmt "\n", __func__, ##args); } } while (0) -extern int debug; +extern int debug; +extern char *sdown; -void do_shutdown(int sig); -void sig_init(void); -void listen_initctl(void); +/* signal.c */ +void do_shutdown (int sig); +void sig_init (void); +void sig_setup (void); -#endif /* FINIT_H__ */ +/* initctl.c */ +void listen_initctl (void); + +#endif /* FINIT_H_ */ /** * Local Variables: diff --git a/helpers.c b/helpers.c index bf3a1a0a..dcd3e464 100644 --- a/helpers.c +++ b/helpers.c @@ -1,3 +1,26 @@ +/* Misc. utility functions and C-library extensions to simplify finit system setup. + * + * Copyright (c) 2008-2010 Claudio Matsuoka + * Copyright (c) 2008-2012 Joachim Nilsson + * + * 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 @@ -7,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -19,7 +43,9 @@ #endif #include +#include +#include "finit.h" #include "helpers.h" /* @@ -115,16 +141,21 @@ int run_parts(char *dir, ...) DIR *d; struct dirent *e; struct stat st; + char *oldpwd = NULL; char *ent[NUM_SCRIPTS]; int i, num = 0, argnum = 1; char *args[NUM_ARGS]; va_list ap; - if (chdir(dir)) + oldpwd = getcwd (NULL, 0); + if (chdir(dir)) { + if (oldpwd) free(oldpwd); return -1; - - if ((d = opendir(dir)) == NULL) + } + if ((d = opendir(dir)) == NULL) { + if (oldpwd) free(oldpwd); return -1; + } va_start(ap, dir); while (argnum < NUM_ARGS && (args[argnum++] = va_arg(ap, char *))); @@ -132,6 +163,7 @@ int run_parts(char *dir, ...) while ((e = readdir(d))) { if (e->d_type == DT_REG && stat(e->d_name, &st) == 0) { + _d("Found %s/%s ...", dir, e->d_name); if (st.st_mode & S_IXUSR) { ent[num++] = strdup(e->d_name); if (num >= NUM_SCRIPTS) @@ -142,23 +174,46 @@ int run_parts(char *dir, ...) closedir(d); - if (num == 0) + if (num == 0) { + if (oldpwd) free(oldpwd); return 0; + } qsort(ent, num, sizeof(char *), cmp); for (i = 0; i < num; i++) { + pid_t pid = 0; + int status; + args[0] = ent[i]; - if (!fork()) { + args[1] = NULL; + + pid = fork(); + if (!pid) { + _d("Calling %s ...", ent[i]); execv(ent[i], args); exit(0); } - wait(NULL); + waitpid(pid, &status, 0); free(ent[i]); } + chdir(oldpwd); + free(oldpwd); + return 0; } +#endif /* BUILTIN_RUNPARTS */ + +int getuser(char *s) +{ + struct passwd *usr; + + if ((usr = getpwnam(s)) == NULL) + return -1; + + return usr->pw_uid; +} int getgroup(char *s) { @@ -174,6 +229,14 @@ int getgroup(char *s) * Other convenience functions */ +void cls(void) +{ + static const char cls[] = "\e[2J\e[1;1H"; + + if (!debug) + fprintf (stderr, "%s", cls); +} + void chomp(char *s) { char *x; @@ -182,4 +245,33 @@ void chomp(char *s) *x = 0; } -#endif +void set_procname(char *args[], char *name) +{ + size_t len = strlen(args[0]) + 1; /* Include terminating '\0' */ + + prctl(PR_SET_NAME, name, 0, 0, 0); + memset(args[0], 0, len); + strncpy(args[0], name, len); +} + +void set_hostname(char *hostname) +{ + FILE *fp; + + _d("Set hostname: %s", hostname); + if ((fp = fopen("/etc/hostname", "r")) != NULL) { + fgets(hostname, HOSTNAME_SIZE, fp); + chomp(hostname); + fclose(fp); + } + + sethostname(hostname, strlen(hostname)); +} + +/** + * Local Variables: + * version-control: t + * indent-tabs-mode: t + * c-file-style: "linux" + * End: + */ diff --git a/helpers.h b/helpers.h index 945aa528..466ff250 100644 --- a/helpers.h +++ b/helpers.h @@ -1,14 +1,50 @@ -#ifndef __FINIT_HELPERS_H -#define __FINIT_HELPERS_H +/* Misc. utility functions and C-library extensions to simplify finit system setup. + * + * Copyright (c) 2008-2010 Claudio Matsuoka + * Copyright (c) 2008-2012 Joachim Nilsson + * + * 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. + */ + +#ifndef FINIT_HELPERS_H_ +#define FINIT_HELPERS_H_ int makepath (char *); void ifconfig (char *, char *, char *, int); void copyfile (char *, char *, int); +void cls (void); void chomp (char *); +int getuser (char *); int getgroup (char *); +void set_procname (char *args[], char *name); +void set_hostname (char *hostname); #ifdef BUILTIN_RUNPARTS -int run_parts (char *, ...); +int run_parts (char *dir, ...); #endif -#endif +#endif /* FINIT_HELPERS_H_ */ + +/** + * Local Variables: + * version-control: t + * indent-tabs-mode: t + * c-file-style: "linux" + * End: + */ diff --git a/initctl.c b/initctl.c index 6d4005f9..2c82d5b9 100644 --- a/initctl.c +++ b/initctl.c @@ -1,26 +1,26 @@ -/* -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. -*/ +/* Optional /dev/initctl FIFO monitor + * + * Copyright (c) 2008-2010 Claudio Matsuoka + * Copyright (c) 2008-2012 Joachim Nilsson + * + * 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 @@ -50,32 +50,45 @@ struct init_request { */ void listen_initctl(void) { + _d("Forking %s watcher...", FINIT_FIFO); if (!fork()) { int ctl; fd_set fds; struct init_request request; - mkfifo("/dev/initctl", 0600); - ctl = open("/dev/initctl", O_RDONLY); + _d("Setting up %s", FINIT_FIFO); + mkfifo(FINIT_FIFO, 0600); + ctl = open(FINIT_FIFO, O_RDONLY); while (1) { FD_ZERO(&fds); FD_SET(ctl, &fds); + _d("Pending %s activity...", FINIT_FIFO); if (select(ctl + 1, &fds, NULL, NULL, NULL) <= 0) continue; + _d("Receiving request on %s...", FINIT_FIFO); read(ctl, &request, sizeof(request)); if (request.magic != INIT_MAGIC) continue; + _d("Magic OK..."); if (request.cmd == INIT_CMD_RUNLVL) { switch (request.runlevel) { case '0': + _d("Halting system (SIGUSR2)"); do_shutdown(SIGUSR2); break; + case '6': + _d("Rebooting system (SIGUSR1)"); do_shutdown(SIGUSR1); + break; + + default: + _d("Unsupported runlevel: %d", request.runlevel); + break; } } } @@ -87,6 +100,7 @@ void listen_initctl(void) /** * Local Variables: * version-control: t + * indent-tabs-mode: t * c-file-style: "linux" * End: */ diff --git a/signal.c b/signal.c index 55ce3ba7..c12ada7d 100644 --- a/signal.c +++ b/signal.c @@ -1,26 +1,42 @@ -/* - 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. -*/ +/* Signal management - Be conservative with what finit responds to! + * + * Copyright (c) 2008-2010 Claudio Matsuoka + * Copyright (c) 2008-2012 Joachim Nilsson + * + * 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. + * + * 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. + */ #include #include @@ -45,31 +61,32 @@ } while (0) static int stopped = 0; -extern char *sdown; void do_shutdown (int sig) { touch(SYNC_SHUTDOWN); - if (sdown[0] != 0) { + + if (sdown) { + _d("Calling shutdown hook: %s", sdown); system(sdown); } + _d("Sending SIGTERM to all processes."); 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"); + _d("Saving the system clock."); system("/sbin/hwclock --systohc"); - + _d("Sending SIGKILL to remaining processes."); kill(-1, SIGKILL); sync(); sync(); - system("/bin/umount -a;/bin/mount -n -o remount,ro /"); - //system("/sbin/unionctl.static / --remove / > /dev/null 2>&1"); + _d("Unmounting file systems, remounting / read-only."); + system("/bin/umount -fa 2>/dev/null"); + system("/bin/mount -n -o remount,ro / 2>/dev/null"); + _d("%s.", sig == SIGINT || sig == SIGUSR1 ? "Rebooting" : "Halting"); if (sig == SIGINT || sig == SIGUSR1) reboot(RB_AUTOBOOT); @@ -79,9 +96,9 @@ void do_shutdown (int sig) /* * Shut down on INT USR1 USR2 */ -static void shutdown_handler(int sig, siginfo_t *info, void *ctx __attribute__ ((unused))) +static void shutdown_handler(int sig, siginfo_t *info, void *UNUSED(ctx)) { - _d("finit: Rebooting on signal %d from pid %d with code %d", sig, info->si_pid, info->si_code); + _d("Rebooting on signal %d from pid %d with code %d", sig, info->si_pid, info->si_code); do_shutdown(sig); } @@ -89,11 +106,12 @@ static void shutdown_handler(int sig, siginfo_t *info, void *ctx __attribute__ ( /* * SIGCHLD: one of our children has died */ -static void chld_handler(int sig, siginfo_t *info, void *ctx __attribute__ ((unused))) +static void chld_handler(int sig, siginfo_t *info, void *UNUSED(ctx)) { int status; - _d("finit: Child died, harvesting... signal %d from pid %d with code %d", sig, info->si_pid, info->si_code); + /* XXX: Add (procname) to debug output, add get_procname(pid) to helpers.c */ + _d("Child died, harvesting. Signal %d from pid %d code %d", sig, info->si_pid, info->si_code); while (waitpid(-1, &status, WNOHANG) != 0) { if (errno == ECHILD) break; @@ -103,48 +121,47 @@ static void chld_handler(int sig, siginfo_t *info, void *ctx __attribute__ ((unu /* * SIGSTOP: Paused by user or netflash */ -static void sigstop_handler(int sig, siginfo_t *info, void *ctx __attribute__ ((unused))) +static void sigstop_handler(int sig, siginfo_t *info, void *UNUSED(ctx)) { - _d("finit: Received SIGSTOP(%d) from pid %d with code %d", sig, info->si_pid, info->si_code); + _d("Received SIGSTOP(%d) from pid %d 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))) +static void sigcont_handler(int sig, siginfo_t *info, void *UNUSED(ctx)) { - _d("finit: Received SIGCONT(%d) from pid %d with code %d", sig, info->si_pid, info->si_code); + _d("Received SIGCONT(%d) from pid %d 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. + * Inital signal setup - ignore everything until we're capable of responding */ 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 */ +/* + * Setup limited set of SysV compatible signals to respond to + */ +void sig_setup(void) +{ + sigset_t nmask; + struct sigaction sa; + + _d("Setup signals"); + + /* Cleanup any stale finit control files */ + remove(SYNC_SHUTDOWN); + remove(SYNC_STOPPED); + + /* Standard SysV init calls ctrl-alt-delete handler */ + SETSIG(sa, SIGINT, shutdown_handler, 0); SETSIG(sa, SIGPWR, shutdown_handler, 0); /* Ignore SIGUSR1/2 for now, only BusyBox init implements them as reboot+halt. */ @@ -171,7 +188,7 @@ void sig_init(void) sigaddset(&nmask, SIGCHLD); sigprocmask(SIG_BLOCK, &nmask, NULL); - /* Disable CTRL-ALT-DELETE from kernel, we handle shutdown gracefully with SIGINT */ + /* Disable CTRL-ALT-DELETE from kernel, we handle shutdown gracefully with SIGINT, above */ reboot(RB_DISABLE_CAD); setsid(); } @@ -179,6 +196,7 @@ void sig_init(void) /** * Local Variables: * version-control: t - * c-file-style: "ellemtel" + * indent-tabs-mode: t + * c-file-style: "linux" * End: */