diff options
-rw-r--r-- | Makefile | 4 | ||||
-rw-r--r-- | README | 22 | ||||
-rw-r--r-- | config.def.h | 78 | ||||
-rw-r--r-- | poweroff.c | 15 | ||||
-rw-r--r-- | reboot.c | 15 | ||||
-rw-r--r-- | sinit.c | 119 |
6 files changed, 234 insertions, 19 deletions
@@ -1,9 +1,11 @@ include config.mk +CC = musl-gcc OBJ = sinit.o BIN = sinit +CFLAGS = $(shell pkg-config --cflags libevdev) -Os -all: $(BIN) +all: $(BIN) poweroff reboot $(BIN): $(OBJ) $(CC) $(LDFLAGS) -o $@ $(OBJ) $(LDLIBS) @@ -1,13 +1,22 @@ -sinit - suckless init -===================== +sinit - suckless init - nshp's fork +=================================== sinit is a simple init. It was initially based on Rich Felker's minimal init[1]. +What's different? +---------------- +My fork of sinit adds: + +* Service forking defined in config.h with very dumb dependency tracking +* A single user session defined in config.h +* Base system mounting defined in config.h +* Static reboot and poweroff binaries which just send the signals listed below + Why? ---- -I wanted to get rid of Busybox init on my toy distro[2]. +I wanted a fast, completely static init for my laptop. How? ---- @@ -17,10 +26,3 @@ There are 3 signals that sinit will act on. SIGUSR1: powers off the machine. SIGINT: reboots the machine (or alternatively via ctrl-alt-del). SIGCHLD: reap children - -To see how sinit integrates with the init scripts, then have -a look at [3]. - -[1] https://gist.github.com/rofl0r/6168719 -[2] http://git.2f30.org/morpheus/ -[3] http://git.2f30.org/ports/tree/fs/ diff --git a/config.def.h b/config.def.h index 6ab3920..9879dcb 100644 --- a/config.def.h +++ b/config.def.h @@ -1,5 +1,77 @@ /* See LICENSE file for copyright and license details. */ -static char *const rcinitcmd[] = { "/bin/rc.init", NULL }; -static char *const rcrebootcmd[] = { "/bin/rc.shutdown", "reboot", NULL }; -static char *const rcpoweroffcmd[] = { "/bin/rc.shutdown", "poweroff", NULL }; +/* user/group ID for user processes */ +#define HOSTNAME "what" +#define USERNAME "who" +#define HOMEDIR "/home/" USERNAME + +uid_t uid = 1000; +gid_t gid = 1000; + +/* Enable startup profiling with perf(1) */ +// #define PERF + +#ifdef PERF +static char *const perf[] = { + "/usr/bin/perf", "record", "-ag", "--output=/tmp/perf.data", + "--", "sleep", "3" }; +#endif + +/* constant groups to set for user session */ +static gid_t const groups[] = { + 5, /* tty */ + 10, /* wheel */ + 91, /* video */ + 92, /* audio */ +}; + +int wpa_started(void); +int udev_settled(void); + +static struct { + int (*dep)(); + char *argv[6]; +} init_procs[] = { + NULL, { "/usr/bin/agetty", "-p", "tty2", "linux", NULL, NULL }, + NULL, { "/usr/bin/spm", NULL, NULL, NULL, NULL, NULL }, + NULL, { "/usr/bin/udevd", "--daemon", NULL }, + NULL, { "/usr/bin/udevadm", "trigger", "-c", "add", NULL }, + NULL, { "/usr/bin/udevadm", "settle", NULL }, + NULL, { "/usr/bin/wpa_supplicant", "-iwlan0", "-c", "/etc/wpa_supplicant/wpa_supplicant.conf", NULL }, + NULL, { "/usr/bin/thermald", NULL }, + wpa_started, { "/usr/bin/wpa_cli", "-a", "/usr/local/bin/run_dhcpcd.sh", NULL }, + wpa_started, { "/usr/bin/dhcpcd", "wlan0", NULL }, + udev_settled, { "/usr/bin/illum-d", NULL }, +}; + +static struct { + char *source; + char *target; + char *type; + unsigned long flags; + char *data; +} static_mounts[] = { + { "tmpfs", "/tmp", "tmpfs", MS_NOSUID|MS_NODEV, "" }, + { "sysfs", "/sys", "sysfs", MS_NOSUID|MS_NODEV|MS_NOEXEC|MS_RELATIME, "rw" }, + { "proc", "/proc", "proc", MS_NOSUID|MS_NODEV|MS_NOEXEC|MS_RELATIME, "rw" }, + { "devpts", "/dev/pts", "devpts", MS_NOSUID|MS_NOEXEC|MS_RELATIME, "gid=5,mode=620,ptmxmode=000" }, + { "tmpfs", "/dev/shm", "tmpfs", MS_NOSUID|MS_NODEV, "mode=1777" }, + { "tmpfs", "/run", "tmpfs", MS_NOSUID|MS_NODEV, "mode=755" }, +}; + +static char *const user_env[] = { + "HOME=" HOMEDIR, + "PWD=" HOMEDIR, + "PATH=/usr/bin", + "DISPLAY=:0", + "LANG=en_US.UTF-8", + "SHELL=/bin/bash", + "USER=" USERNAME, + "LOGNAME=" USERNAME, + NULL +}; + +static char *const user_procs[][5] = { + { "/usr/bin/xinit", "/usr/bin/dwm", "--", "-quiet", NULL }, +}; + diff --git a/poweroff.c b/poweroff.c new file mode 100644 index 0000000..5379c4f --- /dev/null +++ b/poweroff.c @@ -0,0 +1,15 @@ +#include <sys/types.h> +#include <stdio.h> +#include <errno.h> +#include <signal.h> + +int +main(void) +{ + if (kill(1, SIGUSR1) == -1) { + perror("kill"); + return errno; + } + + return 0; +} diff --git a/reboot.c b/reboot.c new file mode 100644 index 0000000..d40e5c2 --- /dev/null +++ b/reboot.c @@ -0,0 +1,15 @@ +#include <sys/types.h> +#include <stdio.h> +#include <errno.h> +#include <signal.h> + +int +main(void) +{ + if (kill(1, SIGINT) == -1) { + perror("kill"); + return errno; + } + + return 0; +} @@ -1,18 +1,27 @@ /* See LICENSE file for copyright and license details. */ +#include <sys/reboot.h> #include <sys/types.h> #include <sys/wait.h> +#include <sys/mount.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <grp.h> +#include <err.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> +#include <time.h> #define LEN(x) (sizeof (x) / sizeof *(x)) static void sigpoweroff(void); static void sigreap(void); static void sigreboot(void); -static void spawn(char *const []); +static void spawn(int (*)(), char *const []); +static void spawn_as(uid_t, gid_t, char *const [], char *const []); +static void mounts(void); static struct { int sig; @@ -35,10 +44,24 @@ main(void) if (getpid() != 1) return 1; + +#ifdef PERF + spawn(NULL, perf); +#endif + chdir("/"); + sethostname(HOSTNAME, sizeof(HOSTNAME)-1); + mounts(); sigfillset(&set); sigprocmask(SIG_BLOCK, &set, NULL); - spawn(rcinitcmd); + ioctl(STDIN_FILENO, TIOCNOTTY, 0); + + for (i=0;i < LEN(init_procs);i++) { + spawn(init_procs[i].dep, init_procs[i].argv); + } + for (i=0;i < LEN(user_procs);i++) { + spawn_as(uid, gid, user_env, user_procs[i]); + } while (1) { sigwait(&set, &sig); for (i = 0; i < LEN(sigmap); i++) { @@ -53,9 +76,25 @@ main(void) } static void +kill_wait(void) +{ + int i; + + for (i=0;i < 4 && kill(-1, i>=3 ? SIGKILL:SIGTERM) == 0;i++) { + /* printf("killall %d\n", i); */ + sleep(1); + } +} + +static void sigpoweroff(void) { - spawn(rcpoweroffcmd); + sigprocmask(SIG_BLOCK, &set, NULL); + kill_wait(); + sync(); + reboot(RB_POWER_OFF); + /* only reachable on error */ + perror("poweroff"); } static void @@ -68,16 +107,31 @@ sigreap(void) static void sigreboot(void) { - spawn(rcrebootcmd); + sigprocmask(SIG_BLOCK, &set, NULL); + kill_wait(); + sync(); + reboot(RB_AUTOBOOT); + /* only reachable on error */ + perror("reboot"); } static void -spawn(char *const argv[]) +spawn(int (*dep)(), char *const argv[]) + { + struct timespec delay = { + .tv_nsec = 1000, + .tv_sec = 0, + }; + switch (fork()) { case 0: sigprocmask(SIG_UNBLOCK, &set, NULL); setsid(); + if (dep != NULL) { + while (!dep()) nanosleep(&delay, NULL); + } + /* printf("spawn: %s\n", argv[0]); */ execvp(argv[0], argv); perror("execvp"); _exit(1); @@ -85,3 +139,58 @@ spawn(char *const argv[]) perror("fork"); } } + +static void +spawn_as(uid_t uid, gid_t gid, char *const env[], char *const argv[]) +{ + /* printf("spawn_as %d,%d: %s\n", uid, gid, argv[0]); */ + switch (fork()) { + case 0: + chdir("/home/nick"); + sigprocmask(SIG_UNBLOCK, &set, NULL); + setsid(); + ioctl(STDIN_FILENO, TIOCSCTTY, 0); + setgid(gid); + setgroups(LEN(groups), groups); + setuid(uid); + execve(argv[0], argv, env); + perror("execve"); + _exit(1); + case -1: + perror("fork"); + } +} + +static void +mounts(void) +{ + int i; + mkdir("/dev/pts", 0755); + mkdir("/dev/shm", 0755); + for (i=0;i < LEN(static_mounts);i++) { + if (mount(static_mounts[i].source, + static_mounts[i].target, + static_mounts[i].type, + static_mounts[i].flags, + static_mounts[i].data) != 0) + { + warn("mount %s", static_mounts[i].target); + } + + } +} + +int +wpa_started(void) +{ + return ! access("/var/run/wpa_supplicant/wlan0", O_RDONLY); +} + +int +udev_settled(void) +{ + struct stat info; + if (stat("/dev/input/event4", &info)) + return 0; + return info.st_gid == 97; /* input group */ +} |