diff options
-rw-r--r-- | Makefile | 1 | ||||
-rw-r--r-- | daemons/Makefile | 4 | ||||
-rw-r--r-- | daemons/rc.sh | 3 | ||||
-rw-r--r-- | daemons/runsystem.hurd | 155 | ||||
-rw-r--r-- | daemons/runsystem.sh | 80 | ||||
-rw-r--r-- | init/Makefile | 24 | ||||
-rw-r--r-- | init/init.c | 155 |
7 files changed, 364 insertions, 58 deletions
@@ -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; +} |