From 5816c9cab90b4cff98f636573c138442d33391de Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Thu, 13 Sep 2012 19:15:41 +0200 Subject: [PATCH] Embedded finit for small embedded Linux systems and servers. o Make finit-alt.c the new finit.c, save old finit.c as finit-org.c o Keep original finit-alt.c for reference. o Update README and ChangeLog with direction of this fork o Correct ChangeLog date for v0.1 and set release date for the 0.6-pre release to 20100614, which is the last commit by the original author. o Add standard LICENSE file for MIT License o Add standard AUTHORS file to document history of project o Bump version to 1.0-pre to distance fork from original Signed-off-by: Joachim Nilsson --- AUTHORS | 6 + Changelog | 11 +- LICENSE | 19 ++ Makefile | 20 +- README | 55 +++-- contrib/Makefile.gdium | 20 +- finit-org.c | 282 ++++++++++++++++++++++ finit.c | 521 ++++++++++++++++++++++++++++++++++------- 8 files changed, 801 insertions(+), 133 deletions(-) create mode 100644 AUTHORS create mode 100644 LICENSE create mode 100644 finit-org.c diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 00000000..b55b07e9 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,6 @@ +Current Maintainer(s): + * Joachim Nilsson + +Original Author(s): + * Claudio Matsuoka + diff --git a/Changelog b/Changelog index 50563e50..aff738c3 100644 --- a/Changelog +++ b/Changelog @@ -1,4 +1,11 @@ -0.6 () +1.0 (UNRELEASED) + - New maintainer at GitHub http://github.com/troglobit/finit + - Make the unused finit.c finit-org.c for archival purposes + - Make finit-alt.c the new default finit.c + - Add standard LICENSE and AUTHORS files + - New focus: embedded systems and small headless servers + +0.6 (20100614) - don't start consolekit manually, dbus starts it (rtp) - unmount all filesystems before rebooting - disable USE_VAR_RUN_RESOLVCONF for Mandriva @@ -43,5 +50,5 @@ O.4 (20080516) - moved finit-mod and finit-alt helpers to helpers.c - replace system("echo;cat") to draw shutdown splash with C calls -0.1 (20081214) +0.1 (20080214) - initial release diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..b7297387 --- /dev/null +++ b/LICENSE @@ -0,0 +1,19 @@ +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. diff --git a/Makefile b/Makefile index 34243592..9e05060d 100644 --- a/Makefile +++ b/Makefile @@ -3,17 +3,17 @@ CFLAGS = -Os -Wall -DVERSION=\"$(VERSION)\" -DWHOAMI=\"`whoami`@`hostname`\" LD = gcc LDFLAGS = LIBS = -VERSION = 0.6-pre +VERSION = 1.0-pre PKG = finit-$(VERSION) -DFILES = Makefile README finit.c finit-mod.c finit-alt.c helpers.c helpers.h \ +DFILES = Makefile README finit.c finit-mod.c finit-org.c helpers.c helpers.h \ patches/*patch contrib/services.sh* contrib/Makefile.* -BINS = finit-mod finit-alt finit-mdv #finit-exb +BINS = finit finit-mod finit-mdv #finit-exb #### Configurable parameters -# Default user for finit-alt if not "user" +# Default user for finit if not "user" #DEFUSER = fred # Disable annoying gcc warning @@ -46,7 +46,7 @@ endif all: $(BINS) -finit: finit.o +finit-org: finit-org.o $(LD) $(LDFLAGS) -o $@ $+ $(LIBS) strip $@ @@ -54,7 +54,7 @@ finit-mod: finit-mod.o helpers.o $(LD) $(LDFLAGS) -o $@ $+ $(LIBS) strip $@ -finit-alt: finit-alt.o helpers.o +finit: finit.o helpers.o $(LD) $(LDFLAGS) -o $@ $+ $(LIBS) strip $@ @@ -62,15 +62,15 @@ finit-mdv: finit-mdv.o helpers.o $(LD) $(LDFLAGS) -o $@ $+ $(LIBS) strip $@ -finit-mdv.o: finit-alt.c Makefile - $(CC) -c $(CFLAGS) -DDIST_MDV -o $@ finit-alt.c +finit-mdv.o: finit.c Makefile + $(CC) -c $(CFLAGS) -DDIST_MDV -o $@ finit.c finit-exb: finit-exb.o helpers.o $(LD) $(LDFLAGS) -o $@ $+ $(LIBS) strip $@ -finit-exb.o: finit-alt.c Makefile - $(CC) -c $(CFLAGS) -DDIST_EEEXUBUNTU -o $@ finit-alt.c +finit-exb.o: finit.c Makefile + $(CC) -c $(CFLAGS) -DDIST_EEEXUBUNTU -o $@ finit.c clean: rm -f *.o core *~ $(BINS) diff --git a/README b/README index 856f894f..9bbbc9c2 100644 --- a/README +++ b/README @@ -1,36 +1,50 @@ +Finit -- A reimplementation of the EeePC SysV init replacement "fastinit" +========================================================================= -Finit is a reimplementation of the Eeepc "fastinit" program based on its +Finit is a reimplementation of the EeePC "fastinit" program based on its system calls with gaps filled with frog DNA. -Finit's purpose is to build upon the general workings of fastinit and -improve/optimize it for Xandros or alternative distributions running on -the Eeepc. Finit comes in three flavors: finit is a replica of the Asus -fastinit, finit-mod is an improved drop-in replacement for fastinit, -and finit-alt is a generic replacement for other systems. Finit-mod -and finit-alt were much improved with patches from Metalshark. +Finit's original purpose was to build upon the general workings of the +EeePC fastinit and improve/optimize it for Xandros or alternative +distributions running on the Eeepc. However, focus has now shifted to +small embedded Linux systems and headless miniature servers with a need +for extremely fast boot. -See more information at http://helllabs.org/finit/ +Nevertheless, finit comes in three flavors: + +o finit-org is a replica of the Asus fastinit, +o finit-mod is an improved drop-in replacement for fastinit, and +o finit is a generic replacement for other systems. + +Finit-mod and finit (previously finit-alt) were much improved with +patches from Metalshark. + +See the GitHub project's Wiki at https://github.com/troglobit/finit, or +the original author's home page at http://helllabs.org/finit/ for more +information. Usage scenarios --------------- -1. Replace the original Eeepc 702 fastinit (finit-mod) +1. Provide an extremely fine tuned and fast boot on embedded systems or + Linux distributions for the EeePC or other netbooks. (finit) -2. Allow fast booting in alternative Linux distributions running on the - Eeepc and other netbooks (finit-alt) +2. Replace the original Eeepc 702 fastinit (finit-mod) + +3. Provide a reverse engineered document of the original EeePC fastinit + implementation. (finit-org) + +Finit is distribution-specific. Currently it generates a finit-mdv +executable for Mandriva 2008/2008.1 systems. Smurfy ported it to +eeeXubuntu, and parts of his port have been merged to finit. -Finit-alt is distribution-specific. Currently it generates a finit-mdv -executable for Mandriva 2008/2008.1 systems. Smurfy ported it to -eeeXubuntu, and parts of his port have been merged to finit-alt. +Finit features +-------------- - -Finit-alt features ------------------- - -Finit-alt reads configuration information from /etc/finit.conf. See -the source code for available options. +Finit reads configuration information from /etc/finit.conf. See the +source code for available options. Rebooting and halting @@ -46,3 +60,4 @@ Debugging Add finit_debug to the kernel parameter line to enable trace messages and to run a shell after the X server. + diff --git a/contrib/Makefile.gdium b/contrib/Makefile.gdium index 328ed605..fc3ab9e9 100644 --- a/contrib/Makefile.gdium +++ b/contrib/Makefile.gdium @@ -3,17 +3,17 @@ CFLAGS = -Os -Wall -DVERSION=\"$(VERSION)\" -DWHOAMI=\"`whoami`@`hostname`\" LD = gcc LDFLAGS = LIBS = -VERSION = 0.6-pre +VERSION = 0.7-pre PKG = finit-$(VERSION) -DFILES = Makefile README finit.c finit-mod.c finit-alt.c helpers.c helpers.h \ +DFILES = Makefile README finit-org.c finit-mod.c finit.c helpers.c helpers.h \ patches/*patch contrib/services.sh* -BINS = finit-mod finit-alt finit-mdv #finit-exb +BINS = finit-mod finit finit-mdv #finit-exb #### Configurable parameters -# Default user for finit-alt if not "user" +# Default user for finit if not "user" #DEFUSER = fred # Use -march=pentium-m to build for Eeepc @@ -51,7 +51,7 @@ finit-mod: finit-mod.o helpers.o $(LD) $(LDFLAGS) -o $@ $+ $(LIBS) strip $@ -finit-alt: finit-alt.o helpers.o +finit: finit.o helpers.o $(LD) $(LDFLAGS) -o $@ $+ $(LIBS) strip $@ @@ -59,20 +59,20 @@ finit-mdv: finit-mdv.o helpers.o $(LD) $(LDFLAGS) -o $@ $+ $(LIBS) strip $@ -finit-mdv.o: finit-alt.c Makefile - $(CC) -c $(CFLAGS) -DDIST_MDV -o $@ finit-alt.c +finit-mdv.o: finit.c Makefile + $(CC) -c $(CFLAGS) -DDIST_MDV -o $@ finit.c finit-exb: finit-exb.o helpers.o $(LD) $(LDFLAGS) -o $@ $+ $(LIBS) strip $@ -finit-exb.o: finit-alt.c Makefile - $(CC) -c $(CFLAGS) -DDIST_EEEXUBUNTU -o $@ finit-alt.c +finit-exb.o: finit.c Makefile + $(CC) -c $(CFLAGS) -DDIST_EEEXUBUNTU -o $@ finit.c clean: rm -f *.o core *~ $(BINS) -finit.o: finit.c Makefile +finit.o: finit-org.c Makefile finit-mod.o: finit-mod.c Makefile diff --git a/finit-org.c b/finit-org.c new file mode 100644 index 00000000..8364d737 --- /dev/null +++ b/finit-org.c @@ -0,0 +1,282 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* 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) + +#define touch(x) close(open((x), O_CREAT|O_WRONLY|O_TRUNC, 0644)) + + +void shutdown(int); +void signal_handler(int); +void chld_handler(int); + + +int main() +{ + int i; + FILE *f; + char line[2096]; + int fd; + DIR *dir; + struct dirent *d; + char filename[1024]; + struct sigaction sa, act; + char hline[1024]; + char *x; + sigset_t nmask, nmask2; + + chdir("/"); + umask(022); + + /* + * Signal management + */ + for (i = 1; i < NSIG; i++) + SETSIG(sa, i, SIG_IGN, SA_RESTART); + + SETSIG(sa, SIGINT, shutdown, 0); + SETSIG(sa, SIGPWR, signal_handler, 0); + SETSIG(sa, SIGUSR1, shutdown, 0); + SETSIG(sa, SIGUSR2, shutdown, 0); + SETSIG(sa, SIGTERM, signal_handler, 0); + SETSIG(sa, SIGKILL, signal_handler, 0); + SETSIG(sa, SIGALRM, signal_handler, 0); + SETSIG(sa, SIGHUP, signal_handler, 0); + SETSIG(sa, SIGSTOP, signal_handler, SA_RESTART); + SETSIG(sa, SIGCONT, signal_handler, SA_RESTART); + SETSIG(sa, SIGCHLD, chld_handler, SA_RESTART); + + /* Block sigchild while forking */ + sigemptyset(&nmask); + sigaddset(&nmask, SIGCHLD); + sigprocmask(SIG_BLOCK, &nmask, NULL); + + reboot(RB_DISABLE_CAD); + + /* + * Parse kernel parameters + */ + if ((f = fopen("/proc/cmdline", "r")) != NULL) { + fgets(line, 2095, f); + if (strstr(line, "quiet")) { + close(0); + close(1); + close(2); + } + fclose(f); + } + + setsid(); + + /* + * Mount filesystems + */ + mount("proc", "/proc", "proc", 0, NULL); + mount("sysfs", "/sys", "sysfs", 0, NULL); + mount("devpts", "/dev/pts", "devpts", 0, "gid=5,mode=620"); + mount("tmpfs", "/dev/shm", "tmpfs", 0, NULL); + mount("tmpfs", "/tmp", "tmpfs", 0, "mode=1777,size=128m"); + mount("/mnt", "/", NULL, MS_MOVE, NULL); + + /* + * Time adjustments + */ + if ((fd = open("/etc/adjtime", O_CREAT|O_WRONLY|O_TRUNC, 0644)) >= 0) { + write(fd, "0.0 0 0.0\n", 10); + close(fd); + } + system("/sbin/hwclock --hctosys --localtime"); + + /* + * Network stuff + */ + system("mkdir -p /dev/shm/network"); + system("mkdir -p /dev/shm/resolvconf/interface"); + + if ((dir = opendir("/etc/resolvconf/run/interface")) != NULL) { + while ((d = readdir(dir)) != NULL) { + if (isalnum(d->d_name[0])) + continue; + sprintf(filename, "/etc/resolvconf/run/interface/%s", + d->d_name); + unlink(filename); + } + + closedir(dir); + } + + touch("/var/run/utmp"); + touch("/etc/resolvconf/run/enable-updates"); + + chdir("/etc/resolvconf/run/interface"); + system("/bin/run-parts --arg=-i /etc/resolvconf/update.d"); + chdir("/"); + + touch("/etc/network/run/ifstate"); + + if ((f = fopen("/etc/hostname", "r")) != NULL) { + fgets(hline, 1023, f); + if ((x = strchr(hline, 0x0a)) != NULL) + *x = 0; + + sethostname(hline, strlen(hline)); + fclose(f); + + } + + system("/sbin/ifconfig lo 127.0.0.1 netmask 255.0.0.0 up > /dev/null"); + + /* + * Set random seed + */ + /* Bug: the eeepc never sets its random seed from file */ + system("/bin/cat /var/lib/urandom/random-seed >/dev/urandom " + "> /dev/null 2>&1"); + unlink("/var/lib/urandom/random-seed"); + + umask(077); + system("/bin/dd if=/dev/urandom of=/var/lib/urandom/random-seed " + "bs=4096 count=1 >/dev/null 2>&1"); + + /* + * Misc setup + */ + /* not really needed, /tmp is a fresh mounted tmpfs */ + system("/bin/rm -rf /tmp/* /tmp/.* 2>/dev/null"); + + unlink("/var/run/.clean"); + unlink("/var/lock/.clean"); + umask(0); + mkdir("/tmp/.X11-unix", 01777); + mkdir("/tmp/.ICE-unix", 01777); + umask(022); + + if (!fork()) { + /* child process */ + + vhangup(); + + close(2); + close(1); + close(0); + + if (open("/dev/tty1", O_RDWR, 0)) + exit(1); + + sigemptyset(&act.sa_mask); + act.sa_handler = SIG_DFL; + + sigemptyset(&nmask2); + sigaddset(&nmask2, SIGCHLD); + sigprocmask(SIG_UNBLOCK, &nmask2, NULL); + + /* Bug: no signal 0 */ + for (i = 0; i < NSIG; i++) + sigaction(i, &sa, NULL); + + dup2(0, 0); + dup2(0, 1); + dup2(0, 2); + + touch("/tmp/nologin"); + + while (access("/tmp/shutdown", F_OK) < 0) + system("su -c startx -l user &> /dev/null"); + + exit(0); + } + + /* parent process */ + + system("/sbin/getty 38400 tty3 &"); + sleep(1); + system("/usr/sbin/services.sh &> /dev/null &"); + + while (1) { + sigemptyset(&nmask); + pselect(0, NULL, NULL, NULL, NULL, &nmask); + } +} + + +/* + * Shut down on INT USR1 USR2 + */ +void shutdown(int sig) +{ + int fd; + + system("/usr/bin/touch /tmp/shutdown"); + + kill(-1, SIGTERM); + + system("/bin/echo -e \"\033[?25l\033[30;40m\"; " + "/bin/cp /boot/shutdown.fb /dev/fb/0"); + sleep(1); + sleep(1); + + system("/usr/sbin/alsactl store > /dev/null 2>&1"); + system("/sbin/hwclock --systohc --localtime"); + + kill(-1, SIGKILL); + + sync(); + sync(); + system("/bin/mount -n -o remount,ro /"); + system("/sbin/unionctl.static / --remove / > /dev/null 2>&1"); + + if (sig == SIGINT || sig == SIGUSR1) + reboot(RB_AUTOBOOT); + + if ((fd = open("/proc/acpi/sleep", O_WRONLY)) >= 0) { + write(fd, "5", 1); + close(fd); + } +} + + +/* + * SIGCHLD: one of our children has died + */ +void chld_handler(int sig) +{ + int status; + + while (waitpid(-1, &status, WNOHANG) != 0) { + if (errno == ECHILD) + break; + } +} + + +/* + * We got a signal (PWR TERM ALRM HUP STOP CONT) + */ +void signal_handler(int sig) +{ + /* do nothing */ +} + diff --git a/finit.c b/finit.c index 8364d737..c6196daa 100644 --- a/finit.c +++ b/finit.c @@ -1,3 +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. +*/ #include #include @@ -14,6 +37,51 @@ #include #include #include +#include + +#include "helpers.h" + +#ifndef DEFUSER +#define DEFUSER "user" +#endif + +/* Distribution configuration */ + +#if defined DIST_MDV /* Mandriva */ +#define RANDOMSEED "/var/lib/random-seed" +#define SYSROOT "/sysroot" +#define GETTY "/usr/bin/openvt /sbin/mingetty tty2" +#define RUNPARTS "/usr/bin/run-parts" +#define REMOUNT_ROOTFS_RW +#define MAKE_DEVICES +#define MAKE_DEV_VCS +#define PAM_CONSOLE +#define LISTEN_INITCTL +#define RUNLEVEL 5 +#define USE_MESSAGE_BUS +#elif defined DIST_EEEXUBUNTU /* eeeXubuntu */ +#define RANDOMSEED "/var/lib/urandom/random-seed" +#define SYSROOT "/sysroot" +#define GETTY "/usr/bin/openvt /sbin/getty 38400 tty2" +#define RUNPARTS "/bin/run-parts" +#define REMOUNT_ROOTFS_RW +#define MAKE_DEVICES +#define TOUCH_ETC_NETWORK_RUN_IFSTATE +#define LISTEN_INITCTL +#else /* original Eeepc distribution */ +#define RANDOMSEED "/var/lib/urandom/random-seed" +#define SYSROOT "/mnt" +#define GETTY "/usr/bin/openvt /sbin/getty 38400 tty2" +#define RUNPARTS "/bin/run-parts" +#define TOUCH_ETC_NETWORK_RUN_IFSTATE +#define USE_ETC_RESOLVCONF_RUN +#endif + +#ifdef DIRECTISA +#define HWCLOCK_DIRECTISA " --directisa" +#else +#define HWCLOCK_DIRECTISA +#endif /* From sysvinit */ @@ -24,29 +92,124 @@ sa.sa_flags = flags; \ sigemptyset(&sa.sa_mask); \ sigaction(sig, &sa, NULL); \ - } while(0) + } while (0) -#define touch(x) close(open((x), O_CREAT|O_WRONLY|O_TRUNC, 0644)) +#ifdef LISTEN_INITCTL +#define INIT_MAGIC 0x03091969 +#define INIT_CMD_RUNLVL 1 + +struct init_request { + int magic; /* Magic number */ + int cmd; /* What kind of request */ + int runlevel; /* Runlevel to change to */ + int sleeptime; /* Time between TERM and KILL */ + char data[368]; +}; +#endif + +#define touch(x) mknod((x), S_IFREG|0644, 0) +#define chardev(x,m,maj,min) mknod((x), S_IFCHR|(m), makedev((maj),(min))) +#define blkdev(x,m,maj,min) mknod((x), S_IFBLK|(m), makedev((maj),(min))) + +#define MATCH_CMD(l,c,x) \ + ((!strncmp((l), (c), strlen((c)))) && ((x) = (l) + strlen((c)))) + +#define _d(x...) do { if (debug) { printf(x); printf("\n"); } } while (0) + +#define LINE_SIZE 1024 +#define CMD_SIZE 256 +#define USERNAME_SIZE 16 +#define HOSTNAME_SIZE 32 void shutdown(int); void signal_handler(int); void chld_handler(int); +static int debug = 0; +static char sdown[CMD_SIZE]; + +static void build_cmd(char *cmd, char *x, int len) +{ + int l; + char *c; + + 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++; + *c = 0; + + _d("cmd = %s", cmd); +} + + +#ifdef LISTEN_INITCTL + +/* Standard reboot/shutdown utilities talk to init using /dev/initctl. + * We should check if the fifo was recreated and reopen it. + */ +static void listen_initctl() +{ + if (!fork()) { + int ctl; + fd_set fds; + struct init_request request; + + mkfifo("/dev/initctl", 0600); + ctl = open("/dev/initctl", O_RDONLY); + + while (1) { + FD_ZERO(&fds); + FD_SET(ctl, &fds); + if (select(ctl + 1, &fds, NULL, NULL, NULL) <= 0) + continue; + + read(ctl, &request, sizeof(request)); + + if (request.magic != INIT_MAGIC) + continue; + + if (request.cmd == INIT_CMD_RUNLVL) { + switch (request.runlevel) { + case '0': + shutdown(SIGUSR2); + break; + case '6': + shutdown(SIGUSR1); + } + } + } + } +} +#endif + int main() { int i; FILE *f; - char line[2096]; - int fd; + char line[LINE_SIZE]; + struct sigaction sa, act; + sigset_t nmask, nmask2; + char username[USERNAME_SIZE] = DEFUSER; + char hostname[HOSTNAME_SIZE] = "eviltwin"; + char cmd[CMD_SIZE]; + char startx[CMD_SIZE] = "xinit"; +#ifdef USE_ETC_RESOLVCONF_RUN DIR *dir; struct dirent *d; - char filename[1024]; - struct sigaction sa, act; - char hline[1024]; - char *x; - sigset_t nmask, nmask2; +#endif +#ifdef RUNLEVEL + struct utmp entry; +#endif +#ifdef PAM_CONSOLE + int fd; +#endif chdir("/"); umask(022); @@ -57,17 +220,15 @@ int main() for (i = 1; i < NSIG; i++) SETSIG(sa, i, SIG_IGN, SA_RESTART); - SETSIG(sa, SIGINT, shutdown, 0); - SETSIG(sa, SIGPWR, signal_handler, 0); - SETSIG(sa, SIGUSR1, shutdown, 0); - SETSIG(sa, SIGUSR2, shutdown, 0); - SETSIG(sa, SIGTERM, signal_handler, 0); - SETSIG(sa, SIGKILL, signal_handler, 0); - SETSIG(sa, SIGALRM, signal_handler, 0); - SETSIG(sa, SIGHUP, signal_handler, 0); - SETSIG(sa, SIGSTOP, signal_handler, SA_RESTART); - SETSIG(sa, SIGCONT, signal_handler, SA_RESTART); - SETSIG(sa, SIGCHLD, chld_handler, SA_RESTART); + SETSIG(sa, SIGINT, shutdown, 0); + SETSIG(sa, SIGPWR, SIG_IGN, 0); + SETSIG(sa, SIGUSR1, shutdown, 0); + SETSIG(sa, SIGUSR2, shutdown, 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); @@ -76,11 +237,17 @@ int main() reboot(RB_DISABLE_CAD); + mount("none", "/proc", "proc", 0, NULL); + mount("none", "/sys", "sysfs", 0, NULL); + /* * Parse kernel parameters */ if ((f = fopen("/proc/cmdline", "r")) != NULL) { - fgets(line, 2095, f); + fgets(line, LINE_SIZE, f); + if ((strstr(line, "finit_debug"))) { + debug = 1; + } if (strstr(line, "quiet")) { close(0); close(1); @@ -89,91 +256,249 @@ int main() fclose(f); } + _d("finit " VERSION " (built " __DATE__ " " __TIME__ " by " WHOAMI ")"); + setsid(); + /* + * Parse configuration file + */ + if ((f = fopen("/etc/finit.conf", "r")) != NULL) { + char *x; + while (!feof(f)) { + fgets(line, LINE_SIZE, f); + chomp(line); + + _d("conf: %s", line); + + /* Do this before mounting / read-write */ + if (MATCH_CMD(line, "check ", x)) { + strcpy(cmd, "/sbin/fsck -C -a "); + build_cmd(cmd, x, CMD_SIZE); + system(cmd); + continue; + } + if (MATCH_CMD(line, "user ", x)) { + *username = 0; + 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); + continue; + } + if (MATCH_CMD(line, "module ", x)) { + strcpy(cmd, "/sbin/modprobe "); + build_cmd(cmd, x, CMD_SIZE); + system(cmd); + continue; + } +#ifdef MAKE_DEVICES + /* This is used if the system uses udev and doesn't + * mount /dev as tmpfs in the initrd, or if it doesn't + * use an initrd. Mount /dev as tmpfs and create basic + * device nodes. + */ + if (MATCH_CMD(line, "mountdev", x)) { + mount("none", "/dev", "tmpfs", 0, "mode=0755"); + chardev("/dev/null", 0666, 1, 3); + blkdev("/dev/sda1", 0660, 8, 1); + blkdev("/dev/sda2", 0660, 8, 2); + blkdev("/dev/sda3", 0660, 8, 3); + blkdev("/dev/sda4", 0660, 8, 4); + blkdev("/dev/sda5", 0660, 8, 5); + blkdev("/dev/sda6", 0660, 8, 6); +#ifdef MAKE_DEV_VCS + /* Caio reports that newer X.org needs these */ + blkdev("/dev/vcs1", 0660, 7, 1); + blkdev("/dev/vcs2", 0660, 7, 2); + blkdev("/dev/vcs3", 0660, 7, 3); + blkdev("/dev/vcs4", 0660, 7, 4); + blkdev("/dev/vcsa1", 0660, 7, 129); + blkdev("/dev/vcsa2", 0660, 7, 130); + blkdev("/dev/vcsa3", 0660, 7, 131); + blkdev("/dev/vcsa4", 0660, 7, 132); +#endif + continue; + } + /* This works only if /dev is tmpfs! If not, create + * devices statically on the filesystem + */ + if (MATCH_CMD(line, "mknod ", x)) { + strcpy(cmd, "/bin/mknod "); + build_cmd(cmd, x, CMD_SIZE); + system(cmd); + continue; + } +#endif + } + fclose(f); + } + /* * Mount filesystems */ - mount("proc", "/proc", "proc", 0, NULL); - mount("sysfs", "/sys", "sysfs", 0, NULL); - mount("devpts", "/dev/pts", "devpts", 0, "gid=5,mode=620"); - mount("tmpfs", "/dev/shm", "tmpfs", 0, NULL); - mount("tmpfs", "/tmp", "tmpfs", 0, "mode=1777,size=128m"); - mount("/mnt", "/", NULL, MS_MOVE, NULL); + _d("mount filesystems"); + +#ifdef REMOUNT_ROOTFS_RW + system("/bin/mount -n -o remount,rw /"); +#endif + umask(0); + +#ifdef MAKE_DEVICES + mkdir("/dev/shm", 0755); + mkdir("/dev/pts", 0755); +#endif + + mount("none", "/dev/pts", "devpts", 0, "gid=5,mode=620"); + mount("none", "/dev/shm", "tmpfs", 0, NULL); + mount("none", "/tmp", "tmpfs", 0, "mode=1777,size=128m"); + mount("none", "/var/run", "tmpfs", 0, "mode=0755"); + mount("none", "/var/lock", "tmpfs", 0, "mode=1777"); + mount("none", "/proc/bus/usb", "usbfs", 0, NULL); + mount(SYSROOT, "/", NULL, MS_MOVE, NULL); + + _d("make devices"); +#ifdef MAKE_DEVICES + mkdir("/dev/input", 0755); + chardev("/dev/urandom", 0666, 1, 9); + chardev("/dev/ptmx", 0666, 5, 2); + chardev("/dev/null", 0666, 1, 3); + chmod("/dev/null", 0666); + chardev("/dev/mem", 0640, 1, 1); + chardev("/dev/tty0", 0660, 4, 0); + chardev("/dev/tty1", 0660, 4, 1); + chardev("/dev/tty2", 0660, 4, 2); + chardev("/dev/tty3", 0660, 4, 3); + chardev("/dev/input/mice", 0660, 13, 63); + chardev("/dev/input/event0", 0660, 13, 64); + chardev("/dev/agpgart", 0660, 10, 175); + blkdev("/dev/loop0", 0600, 7, 0); +#endif + + unlink("/etc/mtab"); + system("mount -a"); + + umask(0022); /* * Time adjustments */ - if ((fd = open("/etc/adjtime", O_CREAT|O_WRONLY|O_TRUNC, 0644)) >= 0) { - write(fd, "0.0 0 0.0\n", 10); - close(fd); - } - system("/sbin/hwclock --hctosys --localtime"); + _d("adjust clock"); +#ifndef NO_HCTOSYS + system("/sbin/hwclock --hctosys" HWCLOCK_DIRECTISA); +#endif /* * Network stuff */ - system("mkdir -p /dev/shm/network"); - system("mkdir -p /dev/shm/resolvconf/interface"); + +#ifdef USE_ETC_RESOLVCONF_RUN + makepath("/dev/shm/network"); + makepath("/dev/shm/resolvconf/interface"); if ((dir = opendir("/etc/resolvconf/run/interface")) != NULL) { while ((d = readdir(dir)) != NULL) { if (isalnum(d->d_name[0])) continue; - sprintf(filename, "/etc/resolvconf/run/interface/%s", - d->d_name); - unlink(filename); + snprintf(line, LINE_SIZE, + "/etc/resolvconf/run/interface/%s", d->d_name); + unlink(line); } closedir(dir); } +#endif + +#ifdef USE_VAR_RUN_RESOLVCONF + makepath("/var/run/resolvconf/interface"); + symlink("../../../etc/resolv.conf", "/var/run/resolvconf/resolv.conf"); +#endif 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; + setutent(); + pututline(&entry); + endutent(); +#endif + +#ifdef USE_ETC_RESOLVCONF_RUN touch("/etc/resolvconf/run/enable-updates"); chdir("/etc/resolvconf/run/interface"); - system("/bin/run-parts --arg=-i /etc/resolvconf/update.d"); +#ifdef BUILTIN_RUNPARTS + run_parts("/etc/resolvconf/update.d", "-i", NULL); +#else + system(RUNPARTS " --arg=i /etc/resolvconf/update.d"); +#endif chdir("/"); +#endif +#ifdef TOUCH_ETC_NETWORK_RUN_IFSTATE touch("/etc/network/run/ifstate"); +#endif if ((f = fopen("/etc/hostname", "r")) != NULL) { - fgets(hline, 1023, f); - if ((x = strchr(hline, 0x0a)) != NULL) - *x = 0; - - sethostname(hline, strlen(hline)); + fgets(hostname, HOSTNAME_SIZE, f); + chomp(hostname); fclose(f); - } - system("/sbin/ifconfig lo 127.0.0.1 netmask 255.0.0.0 up > /dev/null"); + sethostname(hostname, strlen(hostname)); + + ifconfig("lo", "127.0.0.1", "255.0.0.0", 1); /* * Set random seed */ - /* Bug: the eeepc never sets its random seed from file */ - system("/bin/cat /var/lib/urandom/random-seed >/dev/urandom " - "> /dev/null 2>&1"); - unlink("/var/lib/urandom/random-seed"); - + copyfile(RANDOMSEED, "/dev/urandom", 0); + unlink(RANDOMSEED); umask(077); - system("/bin/dd if=/dev/urandom of=/var/lib/urandom/random-seed " - "bs=4096 count=1 >/dev/null 2>&1"); + copyfile("/dev/urandom", RANDOMSEED, 4096); + umask(0); + + /* + * Console setup (for X) + */ + makepath("/var/run/console"); + snprintf(line, LINE_SIZE, "/var/run/console/%s", username); + touch(line); + +#ifdef PAM_CONSOLE + if ((fd = open("/var/run/console/console.lock", O_CREAT|O_WRONLY|O_TRUNC, 0644)) >= 0) { + write(fd, username, strlen(username)); + close(fd); + system("/sbin/pam_console_apply"); + } +#endif /* * Misc setup */ - /* not really needed, /tmp is a fresh mounted tmpfs */ - system("/bin/rm -rf /tmp/* /tmp/.* 2>/dev/null"); - - unlink("/var/run/.clean"); - unlink("/var/lock/.clean"); - umask(0); mkdir("/tmp/.X11-unix", 01777); mkdir("/tmp/.ICE-unix", 01777); umask(022); + system(GETTY "&"); + + _d("forking"); if (!fork()) { /* child process */ @@ -183,7 +508,7 @@ int main() close(1); close(0); - if (open("/dev/tty1", O_RDWR, 0)) + if (open("/dev/tty1", O_RDWR) != 0) exit(1); sigemptyset(&act.sa_mask); @@ -193,27 +518,53 @@ int main() sigaddset(&nmask2, SIGCHLD); sigprocmask(SIG_UNBLOCK, &nmask2, NULL); - /* Bug: no signal 0 */ - for (i = 0; i < NSIG; i++) + for (i = 1; i < NSIG; i++) sigaction(i, &sa, NULL); dup2(0, 0); dup2(0, 1); dup2(0, 2); - touch("/tmp/nologin"); - - while (access("/tmp/shutdown", F_OK) < 0) - system("su -c startx -l user &> /dev/null"); +#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"); + + /* ConsoleKit needs this */ + setenv("DISPLAY", ":0", 1); + + while (access("/tmp/shutdown", F_OK) < 0) { + _d("start X as %s\n", username); + if (debug) { + snprintf(line, LINE_SIZE, + "su -l %s -c \"%s\"", username, startx); + system(line); + system("/bin/sh"); + } else { + snprintf(line, LINE_SIZE, + "su -l %s -c \"%s\" &> /dev/null", + username, startx); + system(line); + } + } exit(0); } /* parent process */ - system("/sbin/getty 38400 tty3 &"); - sleep(1); - system("/usr/sbin/services.sh &> /dev/null &"); + + /* sleep(1); */ + system("/usr/sbin/services.sh &>/dev/null&"); while (1) { sigemptyset(&nmask); @@ -227,34 +578,31 @@ int main() */ void shutdown(int sig) { - int fd; - - system("/usr/bin/touch /tmp/shutdown"); + touch("/tmp/shutdown"); + if (sdown) { + system(sdown); + } kill(-1, SIGTERM); - system("/bin/echo -e \"\033[?25l\033[30;40m\"; " - "/bin/cp /boot/shutdown.fb /dev/fb/0"); - sleep(1); - sleep(1); + 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 --localtime"); + system("/sbin/hwclock --systohc" HWCLOCK_DIRECTISA); kill(-1, SIGKILL); sync(); sync(); - system("/bin/mount -n -o remount,ro /"); - system("/sbin/unionctl.static / --remove / > /dev/null 2>&1"); + 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); - if ((fd = open("/proc/acpi/sleep", O_WRONLY)) >= 0) { - write(fd, "5", 1); - close(fd); - } + reboot(RB_POWER_OFF); } @@ -271,12 +619,3 @@ void chld_handler(int sig) } } - -/* - * We got a signal (PWR TERM ALRM HUP STOP CONT) - */ -void signal_handler(int sig) -{ - /* do nothing */ -} -