summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile1
-rw-r--r--daemons/Makefile4
-rw-r--r--daemons/rc.sh3
-rw-r--r--daemons/runsystem.hurd155
-rw-r--r--daemons/runsystem.sh80
-rw-r--r--init/Makefile24
-rw-r--r--init/init.c155
7 files changed, 364 insertions, 58 deletions
diff --git a/Makefile b/Makefile
index 455df67f..31787408 100644
--- a/Makefile
+++ b/Makefile
@@ -41,6 +41,7 @@ prog-subdirs = auth proc exec term \
random \
procfs \
startup \
+ init \
ifeq ($(HAVE_SUN_RPC),yes)
prog-subdirs += nfs nfsd
diff --git a/daemons/Makefile b/daemons/Makefile
index d16680ec..db1acc77 100644
--- a/daemons/Makefile
+++ b/daemons/Makefile
@@ -22,7 +22,9 @@ makemode := utilities
targets = rc getty mail.local console-run runttys runsystem
special-targets = rc runsystem
-SRCS = rc.sh runsystem.sh getty.c lmail.c console-run.c runttys.c
+SRCS = rc.sh runsystem.sh getty.c lmail.c console-run.c runttys.c \
+ runsystem.hurd \
+
installationdir = $(libexecdir)
HURDLIBS = fshelp ports shouldbeinlibc
diff --git a/daemons/rc.sh b/daemons/rc.sh
index 5cf44fa6..12408830 100644
--- a/daemons/rc.sh
+++ b/daemons/rc.sh
@@ -2,9 +2,6 @@
PATH=/bin:/sbin
-# Start the default pager. It will bail if there is already one running.
-/hurd/mach-defpager
-
# Set up swap space. This will complain if no default pager is functioning.
swapon -a
diff --git a/daemons/runsystem.hurd b/daemons/runsystem.hurd
new file mode 100644
index 00000000..f4f27711
--- /dev/null
+++ b/daemons/runsystem.hurd
@@ -0,0 +1,155 @@
+#!/bin/bash
+#
+# This program is run by /hurd/init at boot time after the essential
+# servers are up, and is responsible for running the "userland" parts of a
+# normal system. This includes running the single-user shell as well as a
+# multi-user system. This program is expected never to exit.
+#
+
+
+###
+### Where to find programs, etc.
+###
+
+PATH=/bin:/sbin
+export PATH
+
+umask 022
+
+# If we lose badly, try to exec each of these in turn.
+fallback_shells='/bin/sh /bin/bash /bin/csh /bin/ash /bin/shd'
+
+# Shell used for normal single-user startup.
+SHELL=/bin/sh
+
+# Programs that do multi-user startup.
+RUNCOM=/libexec/rc
+RUNTTYS=/libexec/runttys
+# Signals that we should pass down to runttys.
+runttys_sigs='TERM INT HUP TSTP'
+
+###
+
+
+# If we get a SIGLOST, attempt to reopen the console in case
+# our console ports were revoked. This lets us print messages.
+function reopen_console ()
+{
+ exec 1>/dev/console 2>&1 || exit 3
+}
+trap 'reopen_console' SIGLOST
+
+
+# Call this when we are losing badly enough that we want to punt normal
+# startup entirely. We exec a single-user shell, so we will not come back
+# here. The only way to get to multi-user from that shell will be
+# explicitly exec this script or something like that.
+function singleuser ()
+{
+ test $# -eq 0 || echo "$0: $*"
+ for try in ${fallback_shells}; do
+ SHELL=${try}
+ exec ${SHELL}
+ done
+ exit 127
+}
+
+
+# See whether pflocal is set up already, and do so if not (install case)
+#
+# Normally this should be the case, but we better make sure since
+# without the pflocal server, pipe(2) does not work.
+if ! test -e /servers/socket/1 ; then
+ # The root filesystem should be read-only at this point.
+ if fsysopts / --update --writable ; then
+ settrans -c /servers/socket/1 /hurd/pflocal
+ else
+ singleuser "Failed to create /servers/socket/1."
+ fi
+fi
+
+# We expect to be started by console-run, which gives us no arguments and
+# puts FALLBACK_CONSOLE=file-name in the environment if our console is
+# other than a normal /dev/console.
+
+if [ "${FALLBACK_CONSOLE+set}" = set ]; then
+ singleuser "Running on fallback console ${FALLBACK_CONSOLE}"
+fi
+
+
+###
+### Normal startup procedures
+###
+
+# Parse the multiboot command line. We only pay attention to -s and -f.
+# The first argument is the kernel file name; skip that.
+shift
+flags=
+while [ $# -gt 0 ]; do
+ arg="$1"
+ shift
+ case "$arg" in
+ --*) ;;
+ *=*) ;;
+ -*)
+ flags="${flags}${arg#-}"
+ ;;
+ 'single'|'emergency') # Linux compat
+ flags="${flags}s"
+ ;;
+ 'fastboot')
+ flags="${flags}f"
+ ;;
+ esac
+done
+
+# Check boot flags.
+case "$flags" in
+*s*)
+ rc=false # force single-user
+ ;;
+*f*)
+ rc="${RUNCOM}" # fastboot
+ ;;
+*)
+ rc="${RUNCOM} autoboot" # multi-user default
+ ;;
+esac
+
+# Large infinite loop. If this script ever exits, init considers that
+# a serious bogosity and punts to a fallback single-user shell.
+# We handle here the normal transitions between single-user and multi-user.
+while : ; do
+
+ # Run the rc script. As long as it exits nonzero, punt to single-user.
+ # After the single-user shell exits, we will start over attempting to
+ # run rc; but later invocations strip the `autoboot' argument.
+ until $rc; do
+ rc=${RUNCOM}
+
+ # Run single-user shell and repeat as long as it dies with a signal.
+ until ${SHELL} || test $? -lt 128; do
+ :
+ done
+ done
+
+ # Now we are officially ready for normal multi-user operation.
+
+ # Trap certain signals and send them on to runttys. For this to work, we
+ # must run it asynchronously and wait for it with the `wait' built-in.
+ runttys_pid=0
+ for sig in $runttys_sigs; do
+ trap "kill -$sig \${runttys_pid}" $sig
+ done
+
+ # This program reads /etc/ttys and starts the programs it says to.
+ ${RUNTTYS} &
+ runttys_pid=$!
+
+ # Wait for runttys to die, meanwhile handling trapped signals.
+ wait
+
+ # Go back to the top of the infinite loop, as if booting single-user.
+ rc=false
+
+done
diff --git a/daemons/runsystem.sh b/daemons/runsystem.sh
index f4f27711..ae25a7d6 100644
--- a/daemons/runsystem.sh
+++ b/daemons/runsystem.sh
@@ -1,9 +1,9 @@
#!/bin/bash
#
# This program is run by /hurd/init at boot time after the essential
-# servers are up, and is responsible for running the "userland" parts of a
-# normal system. This includes running the single-user shell as well as a
-# multi-user system. This program is expected never to exit.
+# servers are up. It does some initialization of its own and then
+# execs /hurd/init or any other roughly SysV init-compatible program
+# to bring up the "userland" parts of a normal system.
#
@@ -22,11 +22,10 @@ fallback_shells='/bin/sh /bin/bash /bin/csh /bin/ash /bin/shd'
# Shell used for normal single-user startup.
SHELL=/bin/sh
-# Programs that do multi-user startup.
-RUNCOM=/libexec/rc
-RUNTTYS=/libexec/runttys
-# Signals that we should pass down to runttys.
-runttys_sigs='TERM INT HUP TSTP'
+# The init program to call.
+#
+# Can be overridden using init=something in the kernel command line.
+init=/hurd/init
###
@@ -44,7 +43,7 @@ trap 'reopen_console' SIGLOST
# startup entirely. We exec a single-user shell, so we will not come back
# here. The only way to get to multi-user from that shell will be
# explicitly exec this script or something like that.
-function singleuser ()
+function singleuser()
{
test $# -eq 0 || echo "$0: $*"
for try in ${fallback_shells}; do
@@ -54,6 +53,8 @@ function singleuser ()
exit 127
}
+# Print a newline.
+echo
# See whether pflocal is set up already, and do so if not (install case)
#
@@ -85,20 +86,23 @@ fi
# The first argument is the kernel file name; skip that.
shift
flags=
+single=
while [ $# -gt 0 ]; do
arg="$1"
shift
case "$arg" in
--*) ;;
+ init=*)
+ eval "${arg}"
+ ;;
*=*) ;;
-*)
flags="${flags}${arg#-}"
;;
- 'single'|'emergency') # Linux compat
- flags="${flags}s"
+ 'single')
+ single="-s"
;;
- 'fastboot')
- flags="${flags}f"
+ 'fastboot'|'emergency')
;;
esac
done
@@ -106,50 +110,18 @@ done
# Check boot flags.
case "$flags" in
*s*)
- rc=false # force single-user
- ;;
-*f*)
- rc="${RUNCOM}" # fastboot
- ;;
-*)
- rc="${RUNCOM} autoboot" # multi-user default
+ single="-s" # force single-user
;;
esac
-# Large infinite loop. If this script ever exits, init considers that
-# a serious bogosity and punts to a fallback single-user shell.
-# We handle here the normal transitions between single-user and multi-user.
-while : ; do
-
- # Run the rc script. As long as it exits nonzero, punt to single-user.
- # After the single-user shell exits, we will start over attempting to
- # run rc; but later invocations strip the `autoboot' argument.
- until $rc; do
- rc=${RUNCOM}
-
- # Run single-user shell and repeat as long as it dies with a signal.
- until ${SHELL} || test $? -lt 128; do
- :
- done
- done
-
- # Now we are officially ready for normal multi-user operation.
-
- # Trap certain signals and send them on to runttys. For this to work, we
- # must run it asynchronously and wait for it with the `wait' built-in.
- runttys_pid=0
- for sig in $runttys_sigs; do
- trap "kill -$sig \${runttys_pid}" $sig
- done
+# Start the default pager. It will bail if there is already one running.
+/hurd/mach-defpager
- # This program reads /etc/ttys and starts the programs it says to.
- ${RUNTTYS} &
- runttys_pid=$!
+# This is necessary to make stat / return the correct device ids.
+# Work around a race condition (probably in the root translator).
+for i in `seq 1 100000` ; do : ; done # XXX
- # Wait for runttys to die, meanwhile handling trapped signals.
- wait
+fsysopts / --update --readonly
- # Go back to the top of the infinite loop, as if booting single-user.
- rc=false
-
-done
+# Finally, start the actual init.
+exec ${init} ${single} -a
diff --git a/init/Makefile b/init/Makefile
new file mode 100644
index 00000000..07b80261
--- /dev/null
+++ b/init/Makefile
@@ -0,0 +1,24 @@
+#
+# Copyright (C) 2013 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2, or (at
+# your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+dir := init
+makemode := server
+
+SRCS = init.c
+OBJS = $(SRCS:.c=.o)
+target = init
+
+include ../Makeconf
diff --git a/init/init.c b/init/init.c
new file mode 100644
index 00000000..b3d33018
--- /dev/null
+++ b/init/init.c
@@ -0,0 +1,155 @@
+/* A minimalist init for the Hurd
+
+ Copyright (C) 2013,14 Free Software Foundation, Inc.
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the Hurd. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <argp.h>
+#include <error.h>
+#include <hurd.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <version.h>
+
+const char *argp_program_version = STANDARD_HURD_VERSION (init);
+static pid_t child_pid;
+static int single;
+
+static struct argp_option
+options[] =
+{
+ /* XXX: Currently, -s does nothing. */
+ {"single-user", 's', NULL, 0, "Startup system in single-user mode", 0},
+ {NULL, 'a', NULL, 0, "Ignored for compatibility with sysvinit", 0},
+ {0}
+};
+
+static char doc[] = "A minimalist init for the Hurd";
+
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+ switch (key)
+ {
+ case 's':
+ single = 1;
+ break;
+
+ case 'a':
+ /* Ignored. */
+ break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+
+ return 0;
+}
+
+void
+sigchld_handler(int signal)
+{
+ /* A child died. Find its status. */
+ int status;
+ pid_t pid;
+
+ while (1)
+ {
+ pid = waitpid (WAIT_ANY, &status, WNOHANG | WUNTRACED);
+ if (pid <= 0)
+ break; /* No more children. */
+
+ /* Since we are init, orphaned processes get reparented to us and
+ alas, all our adopted children eventually die. Woe is us. We
+ just need to reap the zombies to relieve the proc server of
+ its burden, and then we can forget about the little varmints. */
+
+ if (pid == child_pid)
+ {
+ /* The big magilla bit the dust. */
+ child_pid = -1;
+
+ char *desc = NULL;
+ if (WIFSIGNALED (status))
+ asprintf (&desc, "terminated abnormally (%s)",
+ strsignal (WTERMSIG (status)));
+ else if (WIFSTOPPED (status))
+ asprintf (&desc, "stopped abnormally (%s)",
+ strsignal (WTERMSIG (status)));
+ else if (WEXITSTATUS (status) == 0)
+ desc = strdup ("finished");
+ else
+ asprintf (&desc, "exited with status %d",
+ WEXITSTATUS (status));
+
+ error (0, 0, "child %s", desc);
+ free (desc);
+
+ /* XXX: launch emergency shell. */
+ error (23, 0, "panic!!");
+ }
+ }
+}
+
+int
+main (int argc, char **argv)
+{
+ struct argp argp =
+ {
+ .options = options,
+ .parser = parse_opt,
+ .doc = doc,
+ };
+ argp_parse (&argp, argc, argv, 0, 0, 0);
+
+ if (getpid () != 1)
+ error (1, 0, "can only be run as PID 1");
+
+ struct sigaction sa;
+ sa.sa_handler = SIG_IGN;
+ sa.sa_flags = 0;
+ sigemptyset (&sa.sa_mask);
+
+ sigaction (SIGHUP, &sa, NULL);
+ sigaction (SIGINT, &sa, NULL);
+ sigaction (SIGQUIT, &sa, NULL);
+ sigaction (SIGTERM, &sa, NULL);
+ sigaction (SIGUSR1, &sa, NULL);
+ sigaction (SIGUSR2, &sa, NULL);
+ sigaction (SIGTSTP, &sa, NULL);
+
+ sa.sa_handler = sigchld_handler;
+ sa.sa_flags |= SA_RESTART;
+ sigaction (SIGCHLD, &sa, NULL);
+
+ char *args[] = { "/etc/hurd/runsystem.hurd", NULL };
+
+ switch (child_pid = fork ())
+ {
+ case -1:
+ error (1, errno, "failed to fork");
+ case 0:
+ execv (args[0], args);
+ error (2, errno, "failed to execv child");
+ }
+
+ select (0, NULL, NULL, NULL, NULL);
+ /* Not reached. */
+ return 0;
+}