diff options
-rw-r--r-- | init/Makefile | 12 | ||||
-rw-r--r-- | init/init.c | 203 | ||||
-rw-r--r-- | init/stubs.c | 106 |
3 files changed, 319 insertions, 2 deletions
diff --git a/init/Makefile b/init/Makefile index efa87c8c..0c020eb7 100644 --- a/init/Makefile +++ b/init/Makefile @@ -18,7 +18,9 @@ dir := init makemode := server -SRCS = init.c ttys.c +split-init=yes + +SRCS = init.c OBJS = $(SRCS:.c=.o) \ startupServer.o notifyServer.o startup_replyUser.o msgServer.o \ startup_notifyUser.o @@ -26,7 +28,13 @@ LCLHDRS = ttys.h target = init HURDLIBS=ports fshelp shouldbeinlibc -LDLIBS=-lutil +ifeq (yes,$(split-init)) +init-CPPFLAGS = -DSPLIT_INIT +SRCS += stubs.c +else +SRCS += ttys.c +LDLIBS = -lutil +endif include ../Makeconf diff --git a/init/init.c b/init/init.c index a5ac3c7b..1a3a15c7 100644 --- a/init/init.c +++ b/init/init.c @@ -1047,6 +1047,208 @@ frob_kernel_process (void) error (0, err, "proc_set_arg_locations for kernel task"); } +#ifdef SPLIT_INIT + +/** Running userland. **/ + +/* In the "split-init" setup, we just run a single program (usually + /libexec/runsystem) that is not expected to ever exit (or stop). + If it does exit (or can't be started), we go to an emergency single-user + shell as a fallback. */ + + +pid_t child_pid; /* PID of the child we run */ +task_t child_task; /* and its (original) task port */ + +error_t send_signal (mach_port_t msgport, int signal, mach_port_t refport); + +static void launch_something (const char *why); + + +/* SIGNO has arrived and has been validated. Do whatever work it + implies. */ +void +process_signal (int signo) +{ + if (signo == SIGCHLD) + { + /* 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. */ + + char *desc = 0; + + mach_port_deallocate (mach_task_self (), child_task); + child_task = MACH_PORT_NULL; + child_pid = -1; + + 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)); + + { + char buf[40]; + snprintf (buf, sizeof buf, "%d", status); + setenv ("STATUS", buf, 1); + } + + launch_something (desc); + } + } + } + else + { + /* Pass the signal on to the child. */ + task_t task; + error_t err; + + err = proc_pid2task (procserver, child_pid, &task); + if (err) + { + error (0, err, "proc_pid2task on %d", child_pid); + task = child_task; + } + else + { + mach_port_deallocate (mach_task_self (), child_task); + child_task = task; + } + + if (signo == SIGKILL) + { + err = task_terminate (task); + if (err != MACH_SEND_INVALID_DEST) + error (0, err, "task_terminate"); + } + else + { + mach_port_t msgport; + err = proc_getmsgport (procserver, child_pid, &msgport); + if (err) + error (0, err, "proc_getmsgport"); + else + { + err = send_signal (msgport, signo, task); /* Avoids blocking. */ + mach_port_deallocate (mach_task_self (), msgport); + if (err) + { + error (0, err, "cannot send %s to child %d", + strsignal (signo), child_pid); + err = task_terminate (task); + if (err != MACH_SEND_INVALID_DEST) + error (0, err, "task_terminate"); + } + } + } + } +} + +/* Start the child program PROG. It is run via /libexec/console-run, + and we pass it no arguments to pass on to PROG. */ +static int +start_child (const char *prog) +{ + file_t file; + error_t err; + char *args; + size_t arglen; + const char *argv[] = { "/libexec/console-run", prog, 0 }; + + err = argz_create ((char **) argv, &args, &arglen); + assert_perror (err); + + file = file_name_lookup (args, O_EXEC, 0); + if (!file) + { + error (0, errno, "%s", args); + free (args); + return -1; + } + + task_create (mach_task_self (), 0, &child_task); + proc_child (procserver, child_task); + proc_task2pid (procserver, child_task, &child_pid); + proc_task2proc (procserver, child_task, &default_ports[INIT_PORT_PROC]); + + if (bootstrap_args & RB_KDB) + { + printf ("Pausing for %s\n", args); + getchar (); + } + + err = file_exec (file, child_task, 0, + args, arglen, + startup_envz, startup_envz_len, + NULL, MACH_MSG_TYPE_COPY_SEND, 0, /* No fds. */ + default_ports, MACH_MSG_TYPE_COPY_SEND, INIT_PORT_MAX, + default_ints, INIT_INT_MAX, + NULL, 0, NULL, 0); + mach_port_deallocate (mach_task_self (), default_ports[INIT_PORT_PROC]); + mach_port_deallocate (mach_task_self (), file); + free (args); + if (err) + { + error (0, err, "Cannot execute %s", args); + free (args); + return -1; + } + + return 0; +} + +static void +launch_something (const char *why) +{ + static unsigned int try; + static const char *const tries[] = + { + "/libexec/runsystem", + _PATH_BSHELL, + "/bin/shd", /* XXX */ + }; + + if (why) + error (0, 0, "%s %s", tries[try - 1], why); + + while (try < sizeof tries / sizeof tries[0]) + if (start_child (tries[try++]) == 0) + return; + + crash_system (); +} + +void +launch_system (void) +{ + launch_something (0); +} + + +#else + /** Single and multi user transitions **/ /* Current state of the system. */ @@ -1353,6 +1555,7 @@ killing it and going to single user mode", } } +#endif /* SPLIT_INIT */ /** RPC servers **/ diff --git a/init/stubs.c b/init/stubs.c new file mode 100644 index 00000000..fd803f97 --- /dev/null +++ b/init/stubs.c @@ -0,0 +1,106 @@ +/* By-hand stubs for some RPC calls + Copyright (C) 1994, 1996, 1999 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, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include <stdlib.h> +#include <hurd/hurd_types.h> +#include <mach/message.h> +#include <string.h> + +/* From hurd/msg.defs: */ +#define RPCID_SIG_POST 23000 + + +/* Send signal SIGNO to MSGPORT with REFPORT as reference. Don't + block in any fashion. */ +error_t +send_signal (mach_port_t msgport, + int signal, + mach_port_t refport) +{ + error_t err; + + static struct + { + mach_msg_header_t head; + mach_msg_type_t signaltype; + int signal; + mach_msg_type_t sigcode_type; + natural_t sigcode; + mach_msg_type_t refporttype; + mach_port_t refport; + } + message = + { + { + /* Message header: */ + (MACH_MSGH_BITS_COMPLEX + | MACH_MSGH_BITS (MACH_MSG_TYPE_COPY_SEND, + MACH_MSG_TYPE_MAKE_SEND_ONCE)), /* msgh_bits */ + sizeof message, /* msgh_size */ + 0, /* msgh_remote_port */ + MACH_PORT_NULL, /* msgh_local_port */ + 0, /* msgh_seqno */ + RPCID_SIG_POST, /* msgh_id */ + }, + { + /* Type descriptor for signo */ + MACH_MSG_TYPE_INTEGER_32, /* msgt_name */ + 32, /* msgt_size */ + 1, /* msgt_number */ + 1, /* msgt_inline */ + 0, /* msgt_longform */ + 0, /* msgt_deallocate */ + 0, /* msgt_unused */ + }, + /* Signal number */ + 0, + /* Type descriptor for sigcode */ + { + MACH_MSG_TYPE_INTEGER_32, /* msgt_name */ + 32, /* msgt_size */ + 1, /* msgt_number */ + 1, /* msgt_inline */ + 0, /* msgt_longform */ + 0, /* msgt_deallocate */ + 0, /* msgt_unused */ + }, + /* Sigcode */ + 0, + { + /* Type descriptor for refport */ + MACH_MSG_TYPE_COPY_SEND, /* msgt_name */ + 32, /* msgt_size */ + 1, /* msgt_number */ + 1, /* msgt_inline */ + 0, /* msgt_longform */ + 0, /* msgt_deallocate */ + 0, /* msgt_unused */ + }, + /* Reference port */ + MACH_PORT_NULL, + }; + + message.head.msgh_remote_port = msgport; + message.signal = signal; + message.refport = refport; + + err = mach_msg((mach_msg_header_t *)&message, + MACH_SEND_MSG|MACH_SEND_TIMEOUT, sizeof message, 0, + MACH_PORT_NULL, 0, MACH_PORT_NULL); + + return err; +} |