aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile4
-rw-r--r--README22
-rw-r--r--config.def.h78
-rw-r--r--poweroff.c15
-rw-r--r--reboot.c15
-rw-r--r--sinit.c119
6 files changed, 234 insertions, 19 deletions
diff --git a/Makefile b/Makefile
index 7e2fde5..4d4ee77 100644
--- a/Makefile
+++ b/Makefile
@@ -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)
diff --git a/README b/README
index 13642b8..a9e9dda 100644
--- a/README
+++ b/README
@@ -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;
+}
diff --git a/sinit.c b/sinit.c
index 93f9925..6e3c5d8 100644
--- a/sinit.c
+++ b/sinit.c
@@ -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 */
+}