]> Pileus Git - mkinit/commitdiff
Lots of work on mkinit
authorAndy Spencer <andy753421@gmail.com>
Thu, 15 Oct 2009 03:27:37 +0000 (03:27 +0000)
committerAndy Spencer <andy753421@gmail.com>
Thu, 15 Oct 2009 03:27:37 +0000 (03:27 +0000)
Interprocess communication, mkinit now reads from a fifo, which is written to
by initctld and (by default) tty0.

Initctld reads the old /dev/initctl fifo which is used by shutdown.

Adding a better concept of runlevels and -stop scripts for most services.

init.mk
mkfile
src/initctld.c [new file with mode: 0644]
src/mkinit
src/service

diff --git a/init.mk b/init.mk
index eeeda2152e2cbab28ad720e18817fd56e1dd16db..aebee30bb5e68209698f643ff4ae7395f3a88e2a 100644 (file)
--- a/init.mk
+++ b/init.mk
@@ -2,26 +2,36 @@
 # See COPYING for terms
 
 # Config
-PATH=/lib/mkinit/bin:/bin:/sbin:/usr/bin:/usr/sbin
 MKSHELL=/usr/lib/plan9/bin/rc
 NPROC=10
 
 # Example
-#start-test:VQPservice -u: start-foo
+#test-start:VQPservice -u: foo-start
 #      echo starting test
 #      service -U $target
 #
-#stop-test:VQPservice -d: /
+#test-stop:VQPservice -d: /
 #      echo stopping test
 #      service -D $target
 
 # Runlevels
-# Make getty wait (for bootchart)
+user   = alsa keymap polipo spam
+system = at cron hddtemp hostname hwclock i8k sshd swap syslog
+bare   = cpufreq fsclean getty localhost modules mounts uevents utmp
+
 default:V: user
 
-user:V:   system `{echo start-^(alsa keymap polipo spam)}
-system:V: bare   `{echo start-^(at cron hddtemp hostname hwclock i8k sshd swap syslog)}
-bare:V:          `{echo start-^(cpufreq fsclean getty localhost modules mounts uevents)}
+user:V:   `{echo $user^-start $system^-start $bare^-start}
+system:V: `{echo $user^-stop  $system^-start $bare^-start}
+bare:V:   `{echo $user^-stop  $system^-stop  $bare^-start}
+single:V: `{echo $user^-stop  $system^-stop  $bare^-stop }
+
+poweroff:V: halt 
+       $P poweroff -ndf
+reboot:V: halt
+       $P reboot -ndf
+kexec:V: halt
+       $P reboot -ndfk
 
 # Initial setup/shutdown for mkinit
 boot:QVEPservice -u: /
@@ -33,7 +43,7 @@ boot:QVEPservice -u: /
        service -U $target
 
 # Kill all process, then remount and sync
-halt:QVE: stop-utmp stop-hwclock stop-alsa
+halt:QVE: utmp-stop hwclock-stop alsa-stop
        echo Stopping init
        rm -f /lib/mkinit/state/*
        
@@ -50,8 +60,10 @@ halt:QVE: stop-utmp stop-hwclock stop-alsa
        $P mount -o remount,ro /
        $P sync
 
+# Bare
+# ----
 # Proc, mtab, udev, fstab
-start-mounts:QVPservice -u: boot
+mounts-start:QVPservice -u: boot
        echo Starting mounts
        $P cat /proc/mounts > /etc/mtab
        $P udevd --daemon
@@ -59,42 +71,44 @@ start-mounts:QVPservice -u: boot
        service -U $target
 
 # Load kernel modules
-start-modules:QVEPservice -u: boot
+modules-start:QVEPservice -u: boot
        echo Starting modules
        $P modprobe uvesafb
        service -U $target
 
 # Trigger udev uevents
-start-uevents:QVEPservice -u:  start-mounts
+uevents-start:QVEPservice -u:  mounts-start
        echo Starting uevents
        $P udevadm trigger
        $P udevadm settle '--timeout=10'
        service -U $target
 
 # Clean out /tmp and /var/run directories
-start-fsclean:QVPservice -u: boot
+fsclean-start:QVPservice -u: boot
        echo Starting fsclean
        $P rm -rf /tmp/* 
        $P rm -rf /var/run/*
        service -U $target
 
 # Spawn gettys for tty[456]
-start-getty:QVPservice -u: start-hostname start-utmp
+getty-start:QVPservice -u: hostname-start utmp-start
        echo Starting getty
        $P respawn /sbin/agetty 38400 tty4 linux &
        $P respawn /sbin/agetty 38400 tty5 linux &
        $P respawn /sbin/agetty 38400 tty6 linux &
        service -U $target
+getty-stop_cmd=pkill agetty
 
 # Spawn qingys for tty[23]
-start-qingy:QVPservice -u: start-hostname start-utmp start-modules start-uevents
+qingy-start:QVPservice -u: hostname-start utmp-start modules-start uevents-start
        echo Starting qingy
        $P respawn /sbin/qingy tty2 &
        $P respawn /sbin/qingy tty3 &
        service -U $target
+getty-stop_cmd=pkill qingy
 
 # Login records
-start-utmp:QVPservice -u: start-fsclean
+utmp-start:QVPservice -u: fsclean-start
        echo Starting utmp
        for (i in /var/run/utmp /var/log/wtmp) {
                echo -n > $i
@@ -102,81 +116,94 @@ start-utmp:QVPservice -u: start-fsclean
                chmod 0664 $i
        }
        service -U $target
-utmp_stop_cmd=halt -w
+utmp-stop_cmd=halt -w
 
 # CPU freq
-start-cpufreq:QVPservice -u: start-uevents
+cpufreq-start:QVPservice -u: uevents-start
        echo Starting cpufreq
        cpufreq-set -g ondemand
        service -U $target
 
 # Keymap (us-cc = us with ctrl-capslock switched)
-keymap_start_cmd=loadkeys -u us-cc
+keymap-start_cmd=loadkeys -u us-cc
 
 # Localhost
-localhost_start_cmd=ifconfig lo 127.0.0.1
-localhost_stop_cmd=ifconfig lo down
+localhost-start_cmd=ifconfig lo 127.0.0.1
+localhost-stop_cmd=ifconfig lo down
 
 # Set hostname
-hostname_start_cmd=hostname b
+hostname-start_cmd=hostname b
 
 # Kernel parameters
-sysctl_start_cmd=sysctl -p
+sysctl-start_cmd=sysctl -p
 
 
 # Console
 # -------
-at_start_cmd=atd
-cron_start_cmd=cron
-hwclock_start_cmd=hwclock --hctosys --utc
-hwclock_stop_cmd=hwclock --systohc --utc
-swap_start_cmd=swapon -a
-swap_stop_cmd=swapoff -a
-start-syslog:QVPservice -u: start-mounts
+at-start_cmd=atd
+at-stop_cmd=pkill atd
+
+cron-start_cmd=cron
+cron-stop_cmd=pkill cron
+
+hwclock-start_cmd=hwclock --hctosys --utc
+hwclock-stop_cmd=hwclock --systohc --utc
+
+swap-start_cmd=swapon -a
+swap-stop_cmd=swapoff -a
+
+syslog-start:QVPservice -u: mounts-start
        echo Starting syslog;
        $P syslog-ng
        service -U $target
-start-hddtemp:QVPservice -u: start-localhost
+syslog-stop_cmd=pkill syslog
+
+hddtemp-start:QVPservice -u: localhost-start
        echo Starting hddtemp
        $P hddtemp -d -l 127.0.0.1 /dev/sda
        service -U $target
-hddtemp_stop_cmd=pkill hddtemp
+hddtemp-stop_cmd=pkill hddtemp
 
 
 # Desktop
 # -------
-alsa_start_cmd=alsactl restore
-alsa_stop_cmd=alsactl store
-sshd_start_cmd=/usr/sbin/sshd
-start-spam:QVPservice -u: start-localhost
+alsa-start_cmd=alsactl restore
+alsa-stop_cmd=alsactl store
+
+sshd-start_cmd=/usr/sbin/sshd
+sshd-stop_cmd=pkill sshd
+
+spam-start:QVPservice -u: localhost-start
        echo Starting spam
        $P spamd -d
        service -U $target
-start-polipo:QVPservice -u: start-localhost
+spam-stop_cmd=pkill spamd
+
+polipo-start:QVPservice -u: localhost-start
        echo Starting poliop
        $P polipo
        service -U $target
-polipo_stop_cmd=pkill polipo
+polipo-stop_cmd=pkill polipo
 
 
 # Library 
 # -------
-start-%:QVPservice -u: boot
-       if (~ $#($stem^_start_cmd) 0)
+%-start:QVPservice -u: boot
+       if (~ $#($stem^-start_cmd) 0)
                exit 0
        echo Starting $stem
-       $P $($stem^_start_cmd)
+       $P $($stem^-start_cmd)
        service -U $target
 
-stop-%:QVPservice -d: /
-       if (~ $#($stem^_stop_cmd) 0)
+%-stop:QVPservice -d: /
+       if (~ $#($stem^-stop_cmd) 0)
                exit 0
        echo Stopping $stem
-       $P $($stem^_stop_cmd)
+       $P $($stem^-stop_cmd)
        service -D $target
 
-zap-%:QVPservice -d: /
+%-zap:QVPservice -d: /
        service -D $target
 
-status-%:QV:
+%-status:QV:
        service -q $target
diff --git a/mkfile b/mkfile
index e762874ae1d69b860d061a234a2d7c8edada0c67..8a60b60fb48a1e4667a059840eb1c668164d883e 100644 (file)
--- a/mkfile
+++ b/mkfile
@@ -1,14 +1,19 @@
 # Copyright (C) 2009 Andy Spencer
 # See COPYING for terms
 
-install:V:
+PROGS=src/initctld
+CLEAN=src/*.o
+
+default:V: all
+
+install:V: all
        install -d \
                $DESTDIR/etc \
                $DESTDIR/sbin \
                $DESTDIR/lib/mkinit/bin \
                $DESTDIR/lib/mkinit/state
        install -t $DESTDIR/lib/mkinit/bin \
-               ./src/{mkinit,service,respawn}
+               ./src/{mkinit,service,respawn,initctld}
        install -t $DESTDIR/etc  ./init.mk       
        ln -sf $DESTDIR/lib/mkinit/bin/mkinit $DESTDIR/sbin
 
@@ -18,3 +23,7 @@ uninstall:VE:
        rm /sbin/mkinit
        rmdir /lib/mkinit/state/
        rmdir /lib/mkinit/
+
+<../mkcommon
+
+# vim: ft=mk
diff --git a/src/initctld.c b/src/initctld.c
new file mode 100644 (file)
index 0000000..892a25e
--- /dev/null
@@ -0,0 +1,177 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <err.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#define INIT_MAGIC            0x03091969
+#define INIT_CMD_START        0
+#define INIT_CMD_RUNLVL       1
+#define INIT_CMD_POWERFAIL    2
+#define INIT_CMD_POWERFAILNOW 3
+#define INIT_CMD_POWEROK      4
+#define INIT_CMD_BSD          5
+#define INIT_CMD_SETENV       6
+#define INIT_CMD_UNSETENV     7
+#define INIT_CMD_CHANGECONS   12345
+#define INITRQ_HLEN           64
+
+/**
+ * tellinit
+ *   0   shutdown
+ *   1   single
+ *   2   nonetwork
+ *   3   default
+ *   4   default
+ *   5   gui
+ *   6   reboot
+ *   abc ignored (inittab)
+ *   sS  single user
+ *   qQ  reload
+ *   uU  reload
+ * 
+ * shutdown
+ *   -r, reboot        runlevel 6 5, setenv INIT_HALT
+ *   -h, default halt  runlevel 0 5, setenv INIT_HALT
+ *   -P, poweroff      runlevel S 5, setenv INIT_HALT=POWERDOWN
+ *   -H, just halt     runlevel S 5, setenv INIT_HALT=HALT
+ *   -f, skip fsck     runlevel S 5, setenv INIT_HALT
+ *   -F, force fskc    runlevel S 5, setenv INIT_HALT
+ */
+
+/**
+ * This is what BSD 4.4 uses when talking to init.
+ * Linux doesn't use this right now.
+ */
+struct init_request_bsd {
+        char gen_id[8];         /* Beats me.. telnetd uses "fe" */
+        char tty_id[16];        /* Tty name minus /dev/tty      */
+        char host[INITRQ_HLEN]; /* Hostname                     */
+        char term_type[16];     /* Terminal type                */
+        int  signal;            /* Signal to send               */
+        int  pid;               /* Process to send to           */
+        char exec_name[128];    /* Program to execute           */
+        char reserved[128];     /* For future expansion.        */
+};
+
+/**
+ * Because of legacy interfaces, "runlevel" and "sleeptime" aren't in a
+ * seperate struct in the union.
+ *
+ * The weird sizes are because init expects the whole struct to be 384 bytes.
+ */
+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 */
+        union {
+                struct init_request_bsd bsd;
+                char  data[368];
+        } i;
+};
+
+const char *telinit_map[0x100] = {
+       /* not sure if these are mapped correctly */
+       ['0'] "runlevel poweroff",
+       ['1'] "runlevel single",
+       ['2'] "runlevel bare",
+       ['3'] "runlevel system",
+       ['5'] "runlevel user",
+       ['6'] "runlevel reboot",
+       ['s'] "runlevel single",
+       ['S'] "runlevel single",
+       ['q'] "reload",
+       ['Q'] "reload",
+       ['u'] "reload",
+       ['U'] "reload",
+};
+
+int open_initctl(char *init_fifo)
+{
+       /* First, try to create /dev/initctl if not present. */
+       struct stat st, st2;
+       if (stat(init_fifo, &st2) < 0 && errno == ENOENT)
+               mkfifo(init_fifo, 0600);
+
+       /* Now finally try to open /dev/initctl */
+       int pipe_fd = open(init_fifo, O_RDWR);
+       if (pipe_fd < 0)
+               err(errno, "error opening %s", init_fifo);
+
+       /* Make sure it's a fifo */
+       fstat(pipe_fd, &st);
+       if (!S_ISFIFO(st.st_mode)) {
+               errno = EINVAL;
+               err(errno, "%s is not a fifo", init_fifo);
+       }
+
+       return pipe_fd;
+}
+
+void process_request(struct init_request *request)
+{
+       if (request->sleeptime)
+               printf("eval SLEEP_TIME=%d\n", request->sleeptime);
+
+       switch (request->cmd) {
+       case INIT_CMD_RUNLVL:
+               if (telinit_map[request->runlevel])
+                       printf("%s\n", telinit_map[request->runlevel]);
+               break;
+       case INIT_CMD_POWERFAIL:
+               printf("powerfail\n");
+               break;
+       case INIT_CMD_POWERFAILNOW:
+               printf("powerfailnow\n");
+               break;
+       case INIT_CMD_POWEROK:
+               printf("powerok\n");
+               break;
+       case INIT_CMD_SETENV:
+               printf("eval export %.*s\n",
+                               sizeof(request->i.data),
+                               request->i.data);
+               break;
+       case INIT_CMD_CHANGECONS:
+               printf("changeconsole %.*s\n",
+                               sizeof(request->i.bsd.reserved),
+                               request->i.bsd.reserved);
+               break;
+       default:
+               fprintf(stderr, "got unimplemented initrequest");
+               break;
+       }
+       fflush(stdout);
+}
+
+int main(int argc, char **argv)
+{
+       if (argc != 2) {
+               printf("usage: %s <initctl>\n", argv[0]);
+               return -EINVAL;
+       }
+       char *init_fifo = argv[1];
+       int pipe_fd = open_initctl(init_fifo);
+
+       /* Main loop, process data and reopen pipe when necessasairy */
+       while (1) {
+               /* Read the data, return on EINTR. */
+               struct init_request request;
+               int n = read(pipe_fd, &request, sizeof(request));
+               if (n == 0)
+                       pipe_fd = open_initctl(init_fifo);
+               else if (n <= 0)
+                     warn("error reading request");
+               else if (n != sizeof(request))
+                     warn("short read");
+               else if (request.magic != INIT_MAGIC)
+                     warn("got bogus request");
+               else
+                     process_request(&request);
+       }
+
+       return 0;
+}
index 581e66214606e6395daeb3ca93bb0062be7239a3..05424314e5a4a2c57d72ecb95d500ed623addb04 100755 (executable)
@@ -1,8 +1,15 @@
-#!/bin/sh
+#!/bin/bash
 
 # Copyright (C) 2009 Andy Spencer
 # See ../COPYING for terms
 
+# GLobals
+CMD=/lib/mkinit/cmd
+INITCTL=/dev/initctl
+PATH=/lib/mkinit/bin:/bin:/sbin:/usr/bin:/usr/sbin
+export PATH
+
+# Functions 
 function usage {
 cat - <<EOF
 usage: $0 [options] [command]
@@ -30,82 +37,103 @@ function runamk {
                -i -k "$@"
 }
 
-# Handle arguments
-TEMP=`getopt -n "$0" \
-       --options     th \
-       --longoptions test,help \
-       -- "$@"`
-[ $? != 0 ] && usage
-eval set -- "$TEMP"
-while true; do
-       [ "$TEST" ] && echo "\$1=$1"
-       case "$1" in
-       -h|--help   ) usage ;;
-       -t|--test   ) TEST=true; shift ;;
-       --          ) shift; cmd="$1";
-                     shift; args="$@";
-                     break ;;
-       *           ) ;;
-       esac
-done
-if [ "$TEST" ]; then
-       echo "Options"
-       echo "  test=$TEST"
-       echo "  cmd=$cmd"
-       echo "  args=$args"
-fi
-
-# Main loop
-while true; do
+function process {
+       cmd="$1"
+       shift
+       args="$@"
        case "$cmd" in
        boot )
                echo
                echo "mkinit -- booting"
-               if runamk -a "$args" && ! [ "$TEST" ]; then
-                       # booted successuflly, redirect input
-                       echo "skipping redirect"
-                       #pipe=/lib/mkinit/cmd
-                       #[ -p pipe ] || mkfifo $pipe
-                       #exec 0< $pipe
-               fi
-               ;;
-       halt|reboot|poweroff )
-               echo "mkinit -- ${cmd}ing"
-               runamk "halt"
-               if [ "$args" -o "$cmd" = reboot -o "$cmd" = poweroff ]; then
-                       # mk handles syncing and logging message
-                       ${TEST:+echo} $cmd -ndf $args
-               fi
+               runamk -a "$args"
                ;;
        restart )
                if [ "$args" ]; then
                        echo "mkinit -- restarting $args"
-                       runamk "stop-$args"
-                       runamk "start-$args"
+                       runamk "$args-stop"
+                       runamk "$args-start"
                fi
                ;;
        start|stop|zap|status )
                if [ "$args" ]; then
                        echo "mkinit -- ${cmd}ing $args"
-                       runamk "${cmd}-$args"
+                       runamk "$args-$cmd"
                fi
                ;;
-       mk )
+       mk|runlevel )
                if [ "$args" ]; then
-                       echo "mkinit -- running mk cmd [$args]"
+                       [ "$cmd" = mk ] &&
+                               echo "mkinit -- running mk cmd [$args]"
+                       [ "$cmd" = runlevel ] &&
+                               echo "mkinit -- entering runlevel $args"
                        runamk "$args"
                fi
                ;;
        reload )
-               exec /sbin/mkinit ${TEST:+"-t"}
+               echo "mkinit -- ${cmd}ing"
+               exec $0 -r ${TEST:+"-t"}
                ;;
        eval )
-               $args
+               eval $args
                ;;
        ?* )
-               echo "unknown command [$cmd $args]"
+               echo "mkinit -- unknown command [$cmd $args]"
                ;;
        esac
-       read -e -p "mkinit> " cmd args
-       history -s $cmd $args
+}
+
+# Handle arguments
+TEMP=`getopt -n "$0" \
+       --options     hrt \
+       --longoptions help,reload,test \
+       -- "$@"`
+[ $? != 0 ] && usage
+eval set -- "$TEMP"
+while true; do
+       [ "$TEST" ] && echo "\$1=$1"
+       case "$1" in
+       -h|--help   ) usage ;;
+       -r|--reload ) RELOAD=true; shift ;;
+       -t|--test   ) TEST=true; shift ;;
+       --          ) shift; cmd="$1";
+                     shift; args="$@";
+                     break ;;
+       *           ) ;;
+       esac
+done
+
+# Initial boot-up
+process $cmd $args
+
+if [ "$TEST" ]; then
+       CMD=/tmp/pipe
+       echo "Options"
+       echo "  test=$TEST"
+       echo "  reload=$RELOAD"
+       echo "  cmd=$cmd"
+       echo "  args=$args"
+fi
+
+if [ ! "$RELOAD" ]; then
+       # Fork /dev/initctl listener
+       initctld $INITCTL |
+       while read line; do
+               echo $line > $CMD
+       done &
+
+       # Fork console listener
+       while read -e -p "mkinit> " line; do
+               echo $line > $CMD
+               history -s $line
+       done <&0 &
+fi
+
+# Kill listeners on exit
+trap "pkill -HUP -P $$ initctld" EXIT
+
+# Main loop
+while true; do
+while line=$(line); do
+       process $line
+done < $CMD
 done
index 034df51ec3000f80528fd9c495cf98965a5b31fb..d4b7a7d612789bea7827cab801190993e1377818 100755 (executable)
@@ -20,7 +20,7 @@ exit
 STATE=/lib/mkinit/state
 
 action="$1"
-service="${2/*-}"
+service="${2/-*}"
 
 [ "$action" -a "$service" ] || usage