aboutsummaryrefslogtreecommitdiff
path: root/init
diff options
context:
space:
mode:
Diffstat (limited to 'init')
-rw-r--r--init/ChangeLog491
-rw-r--r--init/Makefile18
-rw-r--r--init/init.c1355
-rw-r--r--init/stubs.c139
4 files changed, 697 insertions, 1306 deletions
diff --git a/init/ChangeLog b/init/ChangeLog
deleted file mode 100644
index 5e1d8a2b..00000000
--- a/init/ChangeLog
+++ /dev/null
@@ -1,491 +0,0 @@
-Tue Jul 16 11:55:09 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * init.c (process_signal): Set WUNTRACED in call to waitpid.
-
-Sun Jul 7 21:18:10 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * init.c (init_stdarrays): Don't use unsafe MOVE_SEND in call to
- interruptible proc_setexecdata.
- (open_console): Likewise, for file_set_translator.
-
-Wed Jul 3 14:46:41 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (init): Add libports (because libfshelp.so requires it,
- lose lose lose).
-
- * init.c (process_signal) [case SIGCHLD]: Correctly place `break'
- *outside* of for loop.
-
-Mon Jul 1 18:07:56 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * init.c (process_signal): On SIGCHLD, keep reaping children until
- we get an error; tolerate all errors silently.
-
-Mon Jun 24 16:29:24 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * init.c (kill_multi_user): Kill user tasks before doing
- notify_shutdown.
-
-Fri Jun 21 16:17:08 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * init.c (open_console): Pass correct length of argument vector
- when setting active translators.
- <maptime.h>: New include.
- (open_console): Print error messages for /dev/console failures.
- Reduce the scope of some variables.
-
-Thu Jun 20 14:51:14 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * init.c (mapped_time): New variable.
- (launch_multi_user): Initialize mapped_time.
-
- * init.c (_PATH_RUNCOM): Move to /libexec/rc.
-
-Wed Jun 19 14:49:08 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * init.c (run_for_real): Doc fix.
- (startup_terminal): Deal properly if one of the run_for_real's
- fails.
- (launch_single_user): If the shell can't be started, crash the
- system.
- (process_rc_script): Return non-zero if run_for_real fails.
- (process_signal) [SIGCHLD]: If process_rc_script fails, go back to
- single-user.
- (S_startup_essential_task): Likewise.
- (init_ttys): Return non-zero if we fail.
- (startup_terminal): Return non-zero if we don't actually start
- anything.
- (startup_ttys): Return non-zero if we fail.
- (launch_multi_user): If init_ttys fails, go back to single. If we
- go multi, actually set system_state accordingly. If startup_ttys
- fails, go back to single.
- (init_ttys, reread_ttys): Test return value of setttyent
- correctly.
-
-Mon Jun 17 14:05:33 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (libutil-libsubst): Define (as -lutil); and link
- against -lutil.
- * init.c: Include <ttyent.h>, <argz.h>, and <utmp.h>.
- (add_terminal, init_ttys, free_ttys, startup_terminal,
- startup_ttys, find_line, reread_ttys, restart_terminal): New functions.
- (launch_multi_user): Use new functions to do things right.
- (session_pid): Delete variable.
- (kill_multi_user): Call free_ttys.
- (process_signal) [SIGHUP]: Call reread_ttys.
- [SIGCHLD/MULTI]: Call restart_terminal.
-
- * init.c (run_for_real): New arg `setsid'; only do setsid if it's
- set. All callers changed. Return the pid of the new program,
- not the task port. All callers changed.
-
- * Makefile (dir): Now init.
-
- * init.c: Include "mung_msg_S.h" instead of "msg_S.h".
- (S_msg_sig_post, S_msg_sig_post_untraced): Include SIGCODE parm.
- * Makefile (mung_msg_S.h): New rule.
-
-Mon Jun 17 00:17:37 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * init.c (run_for_real, open_console, process_signal, reboot_mach,
- run_for_real, run, reboot_system): Use error instead of fprintf.
- (notify_shutdown): Always emit terminating newline.
-
-Fri Jun 14 11:07:30 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * init.c: Include <paths.h>, <error.h>, <sys/wait.h>, and
- <hurd/msg_reply.h>.
- (S_startup_essential_task): When all core servers have
- showed up, call launch_single_user only if RB_SINGLE; otherwise
- call process_rc_script. Call init_stdarrays here.
- (open_console): New function; massaged guts taken from
- launch_single_user. Be more verbose if we do something unusual.
- (launch_single_user): Call open_console. Don't call
- init_stdarrays here.
- (system_state, default_ints): New variables.
- (main): Initialize SYSTEM_STATE and DEFAULT_INTS.
- (run_for_real): Pass default_ints.
- (run): Likewise.
- (S_startup_essential_task): Delete var INITDONE; use SYSTEM_STATE
- instead.
- (launch_single_user): Set SYSTEM_STATE to SINGLE.
- (process_rc_script): New function.
- (launch_multi_user): New function.
- (kill_everyone): New function.
- (kill_multi_user): New function.
- (do_fastboot, rc_pid, session_pid): New variables.
- (process_signal): New function; guts from S_msg_sig_post_untraced.
- Handle state transitions here when programs exit. Process
- SIGTERM, and SIGHUP appropriately.
- (_PATH_RUNCOM, _PATH_LOGIN): New macros.
- (S_msg_sig_post_untraced): Only validate signal here; use
- process_signal to do the work, but reply first.
- (S_msg_sig_post): Likewise.
- (notify_shutdown): New function.
- (reboot_system): Use notify_shutdown.
-
-Wed Jun 12 16:01:17 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * init.c (S_startup_request_notification): Fill NT->name properly.
-
-Mon May 27 11:33:53 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * init.c (launch_single_user): Open TERM RDWR.
- Use openport to get FD from TERM.
- Print errno on assertion failure for FD.
-
-Fri May 24 12:29:20 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * init.c (reboot_mach): Insert a brief pause before actually
- rebooting the kernel so that the user has a chance to see any
- messages that may be displayed.
-
-Tue May 14 11:26:49 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * init.c (S_msg_get_exec_flags, S_msg_set_all_exec_flags,
- S_msg_set_some_exec_flags, S_msg_clear_some_exec_flags): Delete
- functions.
- (S_msg_describe_ports): New function.
-
- * init.c (reboot_system): Print prettier messages for shutdown
- notifications.
-
-Fri May 10 09:25:16 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * init.c: <hurd/startup_notify.h> -> "startup_notify_U.h".
- * Makefile (OBJS): Add startup_notifyUser.o.
-
-Thu May 9 19:03:24 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * init.c (struct ntfy_task): New member `name'.
- (S_startup_request_notification): Expect and record name.
- (S_msg_startup_dosync): Delete function.
- Include <hurd/startup_notify.h>.
- (reboot_system): Use new startup_dosync interface.
-
- * init.c (init_stdarrays): Use new authentication interface.
-
-Mon May 6 14:25:02 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * init.c (init_version): Upgrade to 0.0.
-
-Mon Apr 29 16:49:18 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * init.c (reboot_system): Not quite yet, though.
-
-Sun Apr 28 19:15:30 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
-
- * init.c (reboot_system): Use 1 minute timeout on reply to
- msg_startup_dosync.
-
-Wed Apr 17 17:06:30 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * init.c (launch_single_user): Set an active, not passive,
- translator on /tmp/console, so it works with / read-only.
- * Makefile (init): Depend on libfshelp.
-
-Mon Mar 25 16:55:22 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (init): Add explicit dependency so that
- libshouldbeinlibc is included.
- * init.c: Include <wire.h>.
- (main): Delete declarations of _etext _edata, and __data_start.
- (main): Use new wire_task_self function instead of doing it ourselves.
-
-Tue Dec 19 18:29:19 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * init.c (launch_core_servers, run_for_real): Call proc_mark_exec
- on child proc ports.
-
-Tue Dec 5 15:22:25 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * init.c (launch_single_user): Change initialization of TERMINAL
- to match new term driver arg syntax. Start terminal as ordinary
- passive translator instead of special weird kludge. Deleted
- variables foobiebletchcount, foobiebletch, and termtask.
-
-Sun Nov 5 02:03:33 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * init.c (reboot_system): Add flags, noise, & noise_len params to
- proc_getprocinfo. Deallocate NOISE if necessary.
- (S_msg_report_wait): New function.
-
-Tue Oct 24 16:49:08 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * init.c: Undo last change of 9Oct95.
-
-Mon Oct 9 04:29:39 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * init.c: Pass dealloc args in file_exec calls.
-
-Thu Jul 6 15:34:23 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * init.c (S_msg_sig_post, S_msg_sig_post_untraced): Reverse order
- of these definitions.
-
- * init.c: Include <hurd/msg_server.h>.
- (reboot_mach): Insert extra parens around assignment inside while
- test.
- (launch_core_servers): Remove assignment from inside if test.
-
- * Makefile: Removed dependencies that are now automatically
- generated.
-
-Thu Feb 9 17:18:21 1995 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * init.c (S_msg_sig_post_untraced): Omit obnoxious "random child
- died" messages.
-
-Sat Jan 28 15:00:37 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * init.c: Include "msg_S.h". Prepend `msg_' to msg.defs server
- functions. Add stubs for new msg.defs functions.
-
-Thu Jan 19 01:59:30 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * init.c: Prepend `msg_' to names of msg.defs RPCs.
-
-Mon Nov 28 15:00:42 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * init.c (run_for_real): Print error msg if file_exec fails.
- (shell_pid): New variable.
- (demuxer): Also try msg_server.
- (launch_single_user): Open terminal O_RDWR and dup to 0, 1, 2.
- Set shell_pid after starting shell.
- (S_sig_post): New function; grok SIGCHLD and restart shell if
- shell_pid dies.
- * Makefile (OBJS): Add msgServer.o.
- (init.o): Depend on msg_S.h.
-
-Fri Nov 11 14:06:43 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * init.c (fakeboot): New variable.
- (STANDALONE): Deleted macro.
- (main): Set FAKEBOOT if -f was passed.
- (reboot_mach): Use FAKEBOOT flag instead of STANDALONE macro.
- (launch_core_servers): Likewise.
- (reboot_system): Likewise. Also don't exit here; let
- reboot_mach exit.
-
-Tue Nov 1 04:13:49 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * init.c (main): Use &_start for start of text to wire.
- (main): Use assert_perror in place of `assert (!err)'.
- (launch_single_user): Use _PATH_CONSOLE and _PATH_BSHELL instead
- of hardcoded strings.
- Check for error from io_stat on console, print message.
- Add #if 0'd code to prompt for shell name.
-
-Tue Sep 6 13:09:40 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * init.c (launch_single_user): Don't run device or pipes
- servers by default. Run terminal server inside /tmp if
- /dev/console isn't set up properly.
-
-Wed Aug 31 01:03:51 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * init.c (launch_single_user): Test TERMTASK as port, not boolean;
- if null, properly initialize TERM to MACH_PORT_NULL as well.
-
-Tue Aug 30 17:07:07 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * init.c: Include <hurd/term.h>.
-
- * init.c (run): Use file_name_lookup instead of path_lookup.
- (launch_single_user): Likewise.
- (run_for_real): Likewise.
-
- * init.c (init_stdarrays): Use new authentication protocol.
-
-Mon Aug 22 16:44:11 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * init.c (run_for_real): If CTTY is set, then also put the process
- in its own login collection.
-
-Fri Aug 19 12:16:47 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * init.c (run_for_real): New arg `ctty'. All callers changed.
- If it's set, then set the new process's INIT_PORT_CTTYID
- accordingly, and change CTTY's owner to be the new process pgrp.
- (launch_single_user): Don't free TERM right away, only do it
- after we've passed it to run_for_real on the shell.
-
-Thu Aug 18 16:48:08 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * init.c (main): Print informative bootstrap messages.
- (launch_core_servers): Likewise.
- (launch_single_user): Likewise.
- (run): Don't print meaningless bootstrap clutter.
-
- * init.c (launch_single_user): Use task_info; it's less intrusive
- than task_suspend/task_resume.
-
- * init.c (launch_single_user): Run pipes before shell.
-
- * init.c (launch_single_user): Pause a bit to give term a chance
- to startup.
-
- * init.c (bootstrap_args): New variable.
- (main): Set `bootstrap_args' appropriately from argv[1].
- (prompt_for_servers): Deleted variable.
- (run): Use RB_INITNAME instead of prompt_for_servers.
- Only do `pausing' hack if RB_KDB is set.
- (run_for_real): Likewise.
-
- * init.c (main): Wire text and data segment soon after starting.
-
-Wed Aug 17 19:20:51 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * init.c (run_for_real): Call proc_setsid on new proc.
-
-Wed Aug 17 14:04:18 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * init.c (init_stdarrays): New function.
- (launch_single_user): Call init_stdarrays.
-
-Tue Aug 16 00:44:20 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * init.c (launch_single_user): Prompt whether to run term or dev.
-
- * init.c (main): Set default_ports[INIT_PORT_BOOTSTRAP] to STARTUP
- while running proc and auth, and then reset it to null.
-
-Mon Aug 15 23:16:24 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * init.c (launch_single_user): Use a volatile var to choose dev or
- term, so you can set it in gdb.
- (main): Set bootstrap port to MACH_PORT_NULL after fetching it.
- Don't set default_ports[INIT_PORT_BOOTSTRAP]; it should be nil.
-
-Mon Aug 15 11:40:34 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * init.c (launch_core_servers): Renamed from launch_system.
- Don't start dev, term, pipes, or shell here.
- (S_startup_procinit): Call launch_core_servers instead of
- launch_system.
- (S_startup_authinit): Likewise.
- (launch_single_user): New function.
- (S_startup_essential_task): Call launch_single_user once
- all the core servers have registered themselves here.
-
-Fri Aug 12 14:05:07 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * init.c (launch_system): Comment out use of dev for now.
-
-Thu Aug 11 12:25:32 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * init.c (launch_system): Run dev instead of term.
-
-Thu Jul 21 17:45:45 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * Makefile: Rewritten in accord with new scheme.
- * init.c: Include "startup_reply_U.h instead of "startup_reply.h".
- (demuxer): Remove S_ from references to startup_server.
-
-Tue Jul 19 20:36:30 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
-
- * init.c (run_for_real): Moved unused var BUF inside #if 0 where used.
- (launch_system): Call proc_set_arg_locations, not proc_setprocargs.
-
-Tue Jul 19 12:44:56 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * Makefile (init): Don't use variable $(link) anymore.
-
-Tue Jul 5 14:21:34 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * init.c (launch_system): After terminal driver is running,
- reopen stdin so that we always read through it. Don't do
- output, because that (for reliability) shouldn't depend
- on the terminal driver.
- (main): Open stdin separately from stdout/stderr.
-
- * Makefile (SRCS): New variable.
-
-Fri Jul 1 11:19:46 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * init.c (run_for_real): Return the task we created. All callers
- changed.
-
-Tue Jun 21 14:08:37 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * init.c (launch_system): Correct first arg to pipes.
-
-Mon Jun 20 15:06:19 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * init.c (launch_system): Look for pipes in /hurd/pipes, not
- /bin/pipes.
-
- * init.c (run_for_real): Comment out old code that prompts user;
- abandon attempt if we can't run something.
-
- * Makefile (install): Use $(INSTALL_BIN) instead of cp.
-
-Fri Jun 17 00:13:50 1994 Roland McGrath (roland@geech.gnu.ai.mit.edu)
-
- * init.c (demuxer): Use S_startup_server instead of startup_server.
-
-Wed Jun 15 18:14:59 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
-
- * init.c (launch_system): Start pipes server after starting shell.
-
- * init.c (run_for_real): New parms ARGS and ARGLEN. All callers
- changed.
-
-Tue May 24 02:20:55 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
-
- * init.c (launch_system): Start the shell before doing proc_setmsgport.
-
-Tue May 24 00:05:43 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * init.c (launch_system): Call proc_setmsgport before fsys_init.
-
-Mon May 16 14:43:47 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * init.c (reboot_system): Restore bits commented out on May 12;
- the proc bug responsible has been fixed.
-
-Fri May 13 14:59:12 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * init.c (launch_system): Make sure the auth server's proc state
- is correct *before* calling startup_authinit_reply.
-
-Thu May 12 15:13:10 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
-
- * init.c (reboot_system): Comment out bits checking to see
- if the procserver has died; they aren't quite right.
-
- * init.c (S_startup_essential_task): Don't take over the exception
- port of the task right now; this interferes with things too much.
-
-Thu May 12 02:22:08 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
-
- * init.c (launch_system): Don't call _hurd_proc_init; just call
- proc_setprocargs ourselves.
- (launch_system): Do proc_setmsgport last.
- (run, run_for_real): Pass argv[0] with name of program.
-
-Mon May 9 14:30:11 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
-
- * init.c (init_version): New variable.
- (launch_system): Call proc_register_version; don't call
- proc_setprocargs (which is done by _hurd_proc_init). Give
- correct argument to _hurd_proc_init.
-
- * init.c (S_startup_register_version, S_startup_uname): Deleted.
-
-Fri May 6 13:01:04 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
-
- * init.c (S_startup_register_version, S_startup_uname):
- New functions (temporary only).
-
-Thu May 5 19:15:39 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
-
- * init.c: Include <hurd/msg.h> for prototype of startup_dosync.
- Change return types of MiG stubs to be kern_return_t.
- (S_startup_essential_task): Expect new arg CREDENTIAL and
- validate it.
-
-Thu May 5 07:44:21 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
-
- * Makefile: Change uses of $(headers) to $(includedir).
-
diff --git a/init/Makefile b/init/Makefile
index 91e3e16b..ffb82ffd 100644
--- a/init/Makefile
+++ b/init/Makefile
@@ -1,5 +1,5 @@
-#
-# Copyright (C) 1994, 1995, 1996 Free Software Foundation
+#
+# Copyright (C) 1994,95,96,99,2001 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
@@ -18,16 +18,14 @@
dir := init
makemode := server
-SRCS = init.c
-OBJS = init.o startupServer.o notifyServer.o startup_replyUser.o msgServer.o \
- startup_notifyUser.o
+SRCS = init.c stubs.c
+OBJS = $(SRCS:.c=.o) \
+ startupServer.o notifyServer.o startup_replyUser.o msgServer.o \
+ startup_notifyUser.o
target = init
-libutil-libsubst = -lutil
+HURDLIBS = shouldbeinlibc
-init: $(OBJS) ../libports/libports.a ../libfshelp/libfshelp.a ../libshouldbeinlibc/libshouldbeinlibc.a -lutil
+include ../Makeconf
mung_msg_S.h: msg_S.h
sed 's/msg_server/mung_msg_server/' < $< > $@
-
-include ../Makeconf
-
diff --git a/init/init.c b/init/init.c
index 58a33410..d66bee0b 100644
--- a/init/init.c
+++ b/init/init.c
@@ -1,21 +1,22 @@
-/* Somewhat primitive version of init
- Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
+/* Start and maintain hurd core servers and system run state
-This file is part of the GNU Hurd.
+ Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+ 2005, 2008 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 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.
+ 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 GNU Hurd; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+ You should have received a copy of the GNU General Public License
+ along with the GNU Hurd; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Written by Michael I. Bushnell and Roland McGrath. */
@@ -38,17 +39,16 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <hurd/term.h>
#include <hurd/fshelp.h>
#include <paths.h>
-#include <sys/wait.h>
+#include <sys/mman.h>
#include <hurd/msg_server.h>
#include <wire.h>
-#include <paths.h>
#include <sys/wait.h>
#include <error.h>
#include <hurd/msg_reply.h>
-#include <ttyent.h>
#include <argz.h>
-#include <utmp.h>
#include <maptime.h>
+#include <version.h>
+#include <argp.h>
#include "startup_notify_U.h"
#include "startup_reply_U.h"
@@ -57,25 +57,29 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "mung_msg_S.h"
/* host_reboot flags for when we crash. */
-#define CRASH_FLAGS RB_AUTOBOOT
+static int crash_flags = RB_AUTOBOOT;
#define BOOT(flags) ((flags & RB_HALT) ? "halt" : "reboot")
-#define _PATH_RUNCOM "/libexec/rc"
-#define _PATH_LOGIN "/bin/login"
-
-/* How long to wait after starting window specs before starting getty */
-#define WINDOW_DELAY 3 /* seconds */
-
+
+const char *argp_program_version = STANDARD_HURD_VERSION (init);
-/* Current state of the system. */
-enum
+static struct argp_option
+options[] =
{
- INITIAL,
- SINGLE,
- RUNCOM,
- MULTI,
-} system_state;
+ {"single-user", 's', 0, 0, "Startup system in single-user mode"},
+ {"query", 'q', 0, 0, "Ask for the names of servers to start"},
+ {"init-name", 'n', 0, 0 },
+ {"crash-debug", 'H', 0, 0, "On system crash, go to kernel debugger"},
+ {"debug", 'd', 0, 0 },
+ {"fake-boot", 'f', 0, 0, "This hurd hasn't been booted on the raw machine"},
+ {0, 'x', 0, OPTION_HIDDEN},
+ {0}
+};
+
+static char doc[] = "Start and maintain hurd core servers and system run state";
+
+static int booted; /* Set when the core servers are up. */
/* This structure keeps track of each notified task. */
struct ntfy_task
@@ -94,78 +98,46 @@ struct ess_task
};
/* These are linked lists of all of the registered items. */
-struct ess_task *ess_tasks;
-struct ntfy_task *ntfy_tasks;
-
-/* Mapped time */
-volatile struct mapped_time_value *mapped_time;
-
-/* All the ttys in /etc/ttys. */
-struct terminal
-{
- /* argz list for getty */
- char *getty_argz;
- size_t getty_argz_len;
-
- /* argz list for window spec */
- char *window_argz;
- size_t window_argz_len;
-
- int on;
- int pid;
-
- char *name;
-};
-
-struct terminal *ttys;
-/* Number of live elements in ttys */
-int nttys;
-/* Total number of elements in ttys */
-int ttyslen;
+static struct ess_task *ess_tasks;
+static struct ntfy_task *ntfy_tasks;
/* Our receive right */
-mach_port_t startup;
+static mach_port_t startup;
/* Ports to the kernel */
-mach_port_t host_priv, device_master;
+static mach_port_t host_priv, device_master;
/* Args to bootstrap, expressed as flags */
-int bootstrap_args;
-
-/* Set if something determines we should no longer pass the `autoboot'
- flag to _PATH_RUNCOM. */
-int do_fastboot;
+static int bootstrap_args = 0;
/* Stored information for returning proc and auth startup messages. */
-mach_port_t procreply, authreply;
-mach_msg_type_name_t procreplytype, authreplytype;
+static mach_port_t procreply, authreply;
+static mach_msg_type_name_t procreplytype, authreplytype;
/* Our ports to auth and proc. */
-mach_port_t authserver;
-mach_port_t procserver;
+static mach_port_t authserver;
+static mach_port_t procserver;
/* Our bootstrap port, on which we call fsys_getpriv and fsys_init. */
-mach_port_t bootport;
+static mach_port_t bootport;
/* Set iff we are a `fake' bootstrap. */
-int fakeboot;
+static int fakeboot;
/* The tasks of auth and proc and the bootstrap filesystem. */
-task_t authtask, proctask, fstask;
-
-char *init_version = "0.0";
+static task_t authtask, proctask, fstask;
-mach_port_t default_ports[INIT_PORT_MAX];
-mach_port_t default_dtable[3];
-int default_ints[INIT_INT_MAX];
-
-char **global_argv;
-
-pid_t shell_pid; /* PID of single-user shell. */
-pid_t rc_pid; /* PID of rc script */
+static mach_port_t default_ports[INIT_PORT_MAX];
+static mach_port_t default_dtable[3];
+static int default_ints[INIT_INT_MAX];
+static char **global_argv;
+static char *startup_envz;
+static size_t startup_envz_len;
+void launch_system (void);
+void process_signal (int signo);
/** Utility functions **/
@@ -199,12 +171,13 @@ reboot_mach (int flags)
}
else
{
+ error_t err;
printf ("%s: %sing Mach (flags %#x)...\n",
program_invocation_short_name, BOOT (flags), flags);
fflush (stdout);
sleep (5);
- while ((errno = host_reboot (host_priv, flags)))
- error (0, errno, "reboot");
+ while ((err = host_reboot (host_priv, flags)))
+ error (0, err, "reboot");
for (;;);
}
}
@@ -213,19 +186,19 @@ reboot_mach (int flags)
void
crash_mach (void)
{
- reboot_mach (CRASH_FLAGS);
+ reboot_mach (crash_flags);
}
/* Notify all tasks that have requested shutdown notifications */
void
-notify_shutdown (char *msg)
+notify_shutdown (const char *msg)
{
struct ntfy_task *n;
for (n = ntfy_tasks; n != NULL; n = n->next)
{
error_t err;
- printf ("%s: notifying %s of %s...",
+ printf ("%s: notifying %s of %s...",
program_invocation_short_name, n->name, msg);
fflush (stdout);
err = startup_dosync (n->notify_port, 60000); /* 1 minute to reply */
@@ -237,7 +210,7 @@ notify_shutdown (char *msg)
puts ("done");
fflush (stdout);
}
-}
+}
/* Reboot the Hurd. */
void
@@ -248,7 +221,7 @@ reboot_system (int flags)
if (fakeboot)
{
pid_t *pp;
- u_int npids = 0;
+ size_t npids = 0;
error_t err;
int ind;
@@ -278,11 +251,13 @@ reboot_system (int flags)
if (task != mach_task_self () && task != proctask)
{
struct procinfo *pi = 0;
- u_int pisize = 0;
+ size_t pisize = 0;
char *noise;
- unsigned noise_len;
- err = proc_getprocinfo (procserver, pp[ind], 0,
- (int **)&pi, &pisize, &noise,&noise_len);
+ size_t noise_len = 0;
+ int flags;
+ err = proc_getprocinfo (procserver, pp[ind], &flags,
+ (int **)&pi, &pisize,
+ &noise, &noise_len);
if (err == MACH_SEND_INVALID_DEST)
goto procbad;
if (err)
@@ -298,8 +273,7 @@ reboot_system (int flags)
task_terminate (task);
}
if (noise_len > 0)
- vm_deallocate (mach_task_self (),
- (vm_address_t)noise, noise_len);
+ munmap (noise, noise_len);
}
}
printf ("%s: Killing proc server\n", program_invocation_short_name);
@@ -315,21 +289,64 @@ reboot_system (int flags)
void
crash_system (void)
{
- reboot_system (CRASH_FLAGS);
+ reboot_system (crash_flags);
}
+/* Request a dead-name notification sent to our port. */
+static void
+request_dead_name (mach_port_t name)
+{
+ mach_port_t prev;
+ mach_port_request_notification (mach_task_self (), name,
+ MACH_NOTIFY_DEAD_NAME, 1, startup,
+ MACH_MSG_TYPE_MAKE_SEND_ONCE, &prev);
+ if (prev != MACH_PORT_NULL)
+ mach_port_deallocate (mach_task_self (), prev);
+}
+
+/* Record an essential task in the list. */
+static error_t
+record_essential_task (const char *name, task_t task)
+{
+ struct ess_task *et;
+ /* Record this task as essential. */
+ et = malloc (sizeof (struct ess_task));
+ if (et == NULL)
+ return ENOMEM;
+ et->task_port = task;
+ et->name = strdup (name);
+ if (et->name == NULL)
+ {
+ free (et);
+ return ENOMEM;
+ }
+ et->next = ess_tasks;
+ ess_tasks = et;
+
+ /* Dead-name notification on the task port will tell us when it dies. */
+ request_dead_name (task);
+
+#if 0
+ /* Taking over the exception port will give us a better chance
+ if the task tries to get wedged on a fault. */
+ task_set_special_port (task, TASK_EXCEPTION_PORT, startup);
+#endif
+
+ return 0;
+}
+
/** Starting programs **/
/* Run SERVER, giving it INIT_PORT_MAX initial ports from PORTS.
Set TASK to be the task port of the new image. */
void
-run (char *server, mach_port_t *ports, task_t *task)
+run (const char *server, mach_port_t *ports, task_t *task)
{
char buf[BUFSIZ];
- char *prog = server;
+ const char *prog = server;
if (bootstrap_args & RB_INITNAME)
{
@@ -341,35 +358,34 @@ run (char *server, mach_port_t *ports, task_t *task)
while (1)
{
file_t file;
+ error_t err;
file = file_name_lookup (prog, O_EXEC, 0);
if (file == MACH_PORT_NULL)
error (0, errno, "%s", prog);
else
{
- char *progname;
- task_create (mach_task_self (), 0, task);
+ task_create (mach_task_self (),
+#ifdef KERN_INVALID_LEDGER
+ NULL, 0, /* OSF Mach */
+#endif
+ 0, task);
if (bootstrap_args & RB_KDB)
{
printf ("Pausing for %s\n", prog);
getchar ();
}
- progname = strrchr (prog, '/');
- if (progname)
- ++progname;
- else
- progname = prog;
- errno = file_exec (file, *task, 0,
- progname, strlen (progname) + 1, /* Args. */
- "", 1, /* No env. */
- default_dtable, MACH_MSG_TYPE_COPY_SEND, 3,
- ports, MACH_MSG_TYPE_COPY_SEND, INIT_PORT_MAX,
- default_ints, INIT_INT_MAX,
- NULL, 0, NULL, 0);
- if (!errno)
+ err = file_exec (file, *task, 0,
+ (char *)prog, strlen (prog) + 1, /* Args. */
+ startup_envz, startup_envz_len,
+ default_dtable, MACH_MSG_TYPE_COPY_SEND, 3,
+ ports, MACH_MSG_TYPE_COPY_SEND, INIT_PORT_MAX,
+ default_ints, INIT_INT_MAX,
+ NULL, 0, NULL, 0);
+ if (!err)
break;
- error (0, errno, "%s", prog);
+ error (0, err, "%s", prog);
}
printf ("File name for server %s (or nothing to reboot): ", server);
@@ -383,6 +399,10 @@ run (char *server, mach_port_t *ports, task_t *task)
printf ("started %s\n", prog);
fflush (stdout);
#endif
+
+ /* Dead-name notification on the task port will tell us when it dies,
+ so we can crash if we don't make it to a fully bootstrapped Hurd. */
+ request_dead_name (*task);
}
/* Run FILENAME as root with ARGS as its argv (length ARGLEN). Return
@@ -391,7 +411,7 @@ run (char *server, mach_port_t *ports, task_t *task)
collection. If SETSID is set, put it in a new session. Return
0 if the task was not created successfully. */
pid_t
-run_for_real (char *filename, char *args, int arglen, mach_port_t ctty,
+run_for_real (char *filename, char *args, int arglen, mach_port_t ctty,
int setsid)
{
file_t file;
@@ -408,20 +428,24 @@ run_for_real (char *filename, char *args, int arglen, mach_port_t ctty,
if (getstring (buf, sizeof (buf)) && *buf)
filename = buf;
file = file_name_lookup (filename, O_EXEC, 0);
- if (!file)
+ if (file == MACH_PORT_NULL)
error (0, errno, "%s", filename);
}
- while (!file);
+ while (file == MACH_PORT_NULL);
#else
file = file_name_lookup (filename, O_EXEC, 0);
- if (!file)
+ if (file == MACH_PORT_NULL)
{
error (0, errno, "%s", filename);
return 0;
}
#endif
- task_create (mach_task_self (), 0, &task);
+ task_create (mach_task_self (),
+#ifdef KERN_INVALID_LEDGER
+ NULL, 0, /* OSF Mach */
+#endif
+ 0, &task);
proc_child (procserver, task);
proc_task2pid (procserver, task, &pid);
proc_task2proc (procserver, task, &default_ports[INIT_PORT_PROC]);
@@ -446,7 +470,7 @@ run_for_real (char *filename, char *args, int arglen, mach_port_t ctty,
progname = filename;
err = file_exec (file, task, 0,
args, arglen,
- NULL, 0, /* No env. */
+ startup_envz, startup_envz_len,
default_dtable, MACH_MSG_TYPE_COPY_SEND, 3,
default_ports, MACH_MSG_TYPE_COPY_SEND,
INIT_PORT_MAX,
@@ -469,237 +493,9 @@ run_for_real (char *filename, char *args, int arglen, mach_port_t ctty,
return pid;
}
-
-
-
-/** /etc/ttys support **/
-
-
-/* Add a new terminal spec for TT and return it. */
-struct terminal *
-add_terminal (struct ttyent *tt)
-{
- struct terminal *t;
- char *line;
-
- if (nttys >= ttyslen)
- {
- ttys = realloc (ttys, (ttyslen * 2) * sizeof (struct ttyent));
- bzero (&ttys[nttys], ttyslen);
- ttyslen *= 2;
- }
-
- t = &ttys[nttys];
- nttys++;
-
- t->name = malloc (strlen (tt->ty_name) + 1);
- strcpy (t->name, tt->ty_name);
-
- if (t->getty_argz)
- free (t->getty_argz);
- if (t->window_argz)
- free (t->window_argz);
-
- if ((tt->ty_status & TTY_ON) && tt->ty_getty)
- {
- asprintf (&line, "%s %s", tt->ty_getty, tt->ty_name);
- argz_create_sep (line, ' ', &t->getty_argz, &t->getty_argz_len);
- if (tt->ty_window)
- argz_create_sep (tt->ty_window, ' ',
- &t->window_argz, &t->window_argz_len);
- else
- t->window_argz = 0;
- t->on = 1;
- }
- else
- {
- t->getty_argz = t->window_argz = 0;
- t->on = 0;
- }
- return t;
-}
-
-
-/* Read /etc/ttys and initialize ttys array. Return non-zero if we fail. */
-int
-init_ttys (void)
-{
- struct ttyent *tt;
-
- ttyslen = 10;
- nttys = 0;
-
- ttys = malloc (ttyslen * sizeof (struct ttyent));
- bzero (ttys, ttyslen * sizeof (struct ttyent));
-
- if (!setttyent ())
- {
- error (0, errno, "%s", _PATH_TTYS);
- return 1;
- }
- while ((tt = getttyent ()))
- {
- if (!tt->ty_name)
- continue;
-
- add_terminal (tt);
- }
-
- endttyent ();
- return 0;
-}
-
-/* Free everyting in the terminal array */
-void
-free_ttys (void)
-{
- int i;
-
- for (i = 0; i < nttys; i++)
- {
- if (ttys[i].getty_argz)
- free (ttys[i].getty_argz);
- if (ttys[i].window_argz)
- free (ttys[i].window_argz);
- free (ttys[i].name);
- }
- free (ttys);
-}
-
-/* Start line T. Return non-zero if we didn't actually start anything. */
-int
-startup_terminal (struct terminal *t)
-{
- pid_t pid;
- assert (t->on);
- assert (t->getty_argz);
-
- if (t->window_argz)
- {
- pid = run_for_real (t->window_argz, t->window_argz,
- t->window_argz_len, MACH_PORT_NULL, 1);
- if (!pid)
- goto error;
-
- sleep (WINDOW_DELAY);
- }
-
- pid = run_for_real (t->getty_argz, t->getty_argz,
- t->getty_argz_len, MACH_PORT_NULL, 0);
- if (pid == 0)
- {
- error:
- t->pid = 0;
- t->on = 0;
- return 1;
- }
- else
- {
- t->pid = pid;
- return 0;
- }
-}
-
-/* For each line in /etc/ttys, start up the specified program. Return
- non-zero if we fail. */
-int
-startup_ttys (void)
-{
- int i;
- int didone, fail;
-
- didone = 0;
-
- for (i = 0; i < nttys; i++)
- if (ttys[i].on)
- {
- fail = startup_terminal (&ttys[i]);
- if (!fail)
- didone = 1;
- }
- return !didone;
-}
-
-/* Find the terminal spec corresponding to line LINE. */
-struct terminal *
-find_line (char *line)
-{
- int i;
-
- for (i = 0; i < nttys; i++)
- if (!strcmp (ttys[i].name, line))
- return &ttys[i];
- return 0;
-}
-
-/* PID has just exited; restart the terminal it's on if necessary. */
-void
-restart_terminal (int pid)
-{
- int i;
-
- for (i = 0; i < nttys; i++)
- if (pid == ttys[i].pid)
- {
- if (logout (ttys[i].name))
- logwtmp (ttys[i].name, "", "");
- ttys[i].pid = 0;
- if (ttys[i].on)
- startup_terminal (&ttys[i]);
- }
-}
-
-/* Re-read /etc/ttys. If a line has turned off, kill what's there.
- If a line has turned on, start it. If an on line has changed,
- kill it, and then restart it. */
-void
-reread_ttys (void)
-{
- struct ttyent *tt;
- struct terminal *t;
- int on;
-
- if (!setttyent ())
- {
- error (0, errno, "%s", _PATH_TTYS);
- return;
- }
-
- while ((tt = getttyent ()))
- {
- if (!tt->ty_name)
- continue;
-
- t = find_line (tt->ty_name);
- on = tt->ty_getty && (tt->ty_status & TTY_ON);
-
- if (t)
- {
- if (t->on && !on)
- {
- t->on = 0;
- kill (t->pid, SIGHUP);
- }
- else if (!t->on && on)
- {
- t->on = 1;
- startup_terminal (t);
- }
- }
- else
- {
- t = add_terminal (tt);
- if (on)
- startup_terminal (t);
- }
- }
- endttyent ();
-}
-
/** Main program and setup **/
-
static int
demuxer (mach_msg_header_t *inp,
mach_msg_header_t *outp)
@@ -711,32 +507,46 @@ demuxer (mach_msg_header_t *inp,
startup_server (inp, outp));
}
+static int
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+ switch (key)
+ {
+ case 'q': bootstrap_args |= RB_ASKNAME; break;
+ case 's': bootstrap_args |= RB_SINGLE; break;
+ case 'd': bootstrap_args |= RB_KDB; break;
+ case 'n': bootstrap_args |= RB_INITNAME; break;
+ case 'f': fakeboot = 1; break;
+ case 'H': crash_flags = RB_DEBUGGER; break;
+ case 'x': /* NOP */ break;
+ default: return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+}
+
int
main (int argc, char **argv, char **envp)
{
volatile int err;
int i;
+ int flags;
mach_port_t consdev;
+ struct argp argp = { options, parse_opt, 0, doc };
- global_argv = argv;
+ /* Parse the arguments. We don't want the vector reordered, we
+ should pass on to our child the exact arguments we got and just
+ ignore any arguments that aren't flags for us. ARGP_NO_ERRS
+ suppresses --help and --version, so we only use that option if we
+ are booting. */
+ flags = ARGP_IN_ORDER;
+ if (getpid () == 0)
+ flags |= ARGP_NO_ERRS;
+ argp_parse (&argp, argc, argv, flags, 0, 0);
- system_state = INITIAL;
+ if (getpid () > 0)
+ error (2, 0, "can only be run by bootstrap filesystem");
- /* Parse the arguments */
- bootstrap_args = 0;
- if (argc >= 2)
- {
- if (index (argv[1], 'q'))
- bootstrap_args |= RB_ASKNAME;
- if (index (argv[1], 's'))
- bootstrap_args |= RB_SINGLE;
- if (index (argv[1], 'd'))
- bootstrap_args |= RB_KDB;
- if (index (argv[1], 'n'))
- bootstrap_args |= RB_INITNAME;
- if (index (argv[1], 'f'))
- fakeboot = 1;
- }
+ global_argv = argv;
/* Fetch a port to the bootstrap filesystem, the host priv and
master device ports, and the console. */
@@ -756,6 +566,9 @@ main (int argc, char **argv, char **envp)
crash_mach ();
setbuf (stdout, NULL);
+ err = argz_create (envp, &startup_envz, &startup_envz_len);
+ assert_perror (err);
+
/* At this point we can use assert to check for errors. */
err = mach_port_allocate (mach_task_self (),
MACH_PORT_RIGHT_RECEIVE, &startup);
@@ -764,6 +577,9 @@ main (int argc, char **argv, char **envp)
MACH_MSG_TYPE_MAKE_SEND);
assert_perror (err);
+ /* Crash if the boot filesystem task dies. */
+ request_dead_name (fstask);
+
/* Set up the set of ports we will pass to the programs we exec. */
for (i = 0; i < INIT_PORT_MAX; i++)
switch (i)
@@ -788,7 +604,7 @@ main (int argc, char **argv, char **envp)
not run under job control shells are protected. */
default_ints[INIT_SIGIGN] = (sigmask (SIGTSTP)
| sigmask (SIGTTIN)
- | sigmask (SIGTTOU));
+ | sigmask (SIGTTOU));
default_ports[INIT_PORT_BOOTSTRAP] = startup;
run ("/hurd/proc", default_ports, &proctask);
@@ -812,7 +628,8 @@ void
launch_core_servers (void)
{
mach_port_t old;
- mach_port_t authproc, fsproc;
+ mach_port_t authproc, fsproc, procproc;
+ error_t err;
/* Reply to the proc and auth servers. */
startup_procinit_reply (procreply, procreplytype, 0,
@@ -834,7 +651,8 @@ launch_core_servers (void)
proc_task2proc (procserver, authtask, &authproc);
proc_mark_exec (authproc);
startup_authinit_reply (authreply, authreplytype, 0, authproc,
- MACH_MSG_TYPE_MOVE_SEND);
+ MACH_MSG_TYPE_COPY_SEND);
+ mach_port_deallocate (mach_task_self (), authproc);
/* Give the library our auth and proc server ports. */
_hurd_port_set (&_hurd_ports[INIT_PORT_AUTH], authserver);
@@ -848,8 +666,16 @@ launch_core_servers (void)
default_ports[INIT_PORT_AUTH] = authserver;
- proc_register_version (procserver, host_priv, "init", HURD_RELEASE,
- init_version);
+ /* Declare that the proc server is our child. */
+ proc_child (procserver, proctask);
+ err = proc_task2proc (procserver, proctask, &procproc);
+ if (!err)
+ {
+ proc_mark_exec (procproc);
+ mach_port_deallocate (mach_task_self (), procproc);
+ }
+
+ proc_register_version (procserver, host_priv, "init", "", HURD_VERSION);
/* Get the bootstrap filesystem's proc server port.
We must do this before calling proc_setmsgport below. */
@@ -874,9 +700,10 @@ launch_core_servers (void)
mach_port_deallocate (mach_task_self (), old);
/* Give the bootstrap FS its proc and auth ports. */
- errno = fsys_init (bootport, fsproc, MACH_MSG_TYPE_MOVE_SEND, authserver);
- if (errno)
- error (0, errno, "fsys_init"); /* Not necessarily fatal. */
+ err = fsys_init (bootport, fsproc, MACH_MSG_TYPE_COPY_SEND, authserver);
+ mach_port_deallocate (mach_task_self (), fsproc);
+ if (err)
+ error (0, err, "fsys_init"); /* Not necessarily fatal. */
}
/* Set up the initial value of the standard exec data. */
@@ -899,6 +726,8 @@ init_stdarrays ()
__USEPORT (AUTH, auth_makeauth (port, 0, MACH_MSG_TYPE_COPY_SEND, 0,
0, 0, 0, 0, 0, 0, 0, 0, &nullauth));
+ /* MAKE_SEND is safe in these transactions because we destroy REF
+ ourselves each time. */
pt = getcwdir ();
ref = mach_reply_port ();
io_reauthenticate (pt, ref, MACH_MSG_TYPE_MAKE_SEND);
@@ -926,444 +755,359 @@ init_stdarrays ()
mach_port_deallocate (mach_task_self (), std_port_array[i]);
}
-/* Open /dev/console. If it isn't there, or it isn't a terminal, then
- create /tmp/console and put the terminal on it. If we get EROFS,
- in trying to create /tmp/console then as a last resort, put the
- console on /tmp itself.
-
- In any case, after the console has been opened, set it appropriately
- in default_dtable. Also return a port right for the terminal. */
-file_t
-open_console ()
+/* Frobnicate the kernel task and the proc server's idea of it (PID 2),
+ so the kernel command line can be read as for a normal Hurd process. */
+
+void
+frob_kernel_process (void)
{
-#define TERMINAL_FIRST_TRY "/hurd/term\0/tmp/console\0device\0console"
-#define TERMINAL_SECOND_TRY "/hurd/term\0/tmp\0device\0console"
- mach_port_t term;
- static char *termname;
- struct stat st;
- error_t err = 0;
-
- if (system_state != INITIAL)
+ error_t err;
+ int argc, i;
+ char *argz, *entry;
+ size_t argzlen;
+ size_t windowsz;
+ vm_address_t mine, his;
+ task_t task;
+ process_t proc, kbs;
+
+ err = proc_pid2task (procserver, 2, &task);
+ if (err)
{
- term = file_name_lookup (termname, O_RDWR, 0);
- return term;
+ error (0, err, "cannot get kernel task port");
+ return;
}
+ err = proc_task2proc (procserver, task, &proc);
+ if (err)
+ {
+ error (0, err, "cannot get kernel task's proc server port");
+ mach_port_deallocate (mach_task_self (), task);
+ return;
+ }
+
+ /* Mark the kernel task as an essential task so that we never
+ want to task_terminate it. */
+ err = record_essential_task ("kernel", task);
+ assert_perror (err);
- termname = _PATH_CONSOLE;
- term = file_name_lookup (termname, O_RDWR, 0);
- if (term != MACH_PORT_NULL)
- err = io_stat (term, &st);
+ err = task_get_bootstrap_port (task, &kbs);
+ assert_perror (err);
+ if (kbs == MACH_PORT_NULL)
+ {
+ /* The kernel task has no bootstrap port set, so we are presumably
+ the first Hurd to boot. Install the kernel task's proc port from
+ this Hurd's proc server as the task bootstrap port. Additional
+ Hurds will see this. */
+
+ err = task_set_bootstrap_port (task, proc);
+ if (err)
+ error (0, err, "cannot set kernel task's bootstrap port");
+
+ if (fakeboot)
+ error (0, 0, "warning: --fake-boot specified but I see no other Hurd");
+ }
else
- err = errno;
- if (err)
- error (0, err, "%s", termname);
- else if (st.st_fstype != FSTYPE_TERM)
- error (0, 0, "%s: Not a terminal", termname);
-
- if (term == MACH_PORT_NULL || err || st.st_fstype != FSTYPE_TERM)
- /* Start the terminal server ourselves. */
{
- size_t argz_len; /* Length of args passed to translator. */
- char *terminal; /* Name of term translator. */
- mach_port_t control; /* Control port for term translator. */
- int try = 1;
-
- error_t open_node (int flags,
- mach_port_t *underlying,
- mach_msg_type_name_t *underlying_type)
+ /* The kernel task has a bootstrap port set. Perhaps it is its proc
+ server port from another Hurd. If so, propagate the kernel
+ argument locations from that Hurd rather than diddling with the
+ kernel task ourselves. */
+
+ vm_address_t kargv, kenvp;
+ err = proc_get_arg_locations (kbs, &kargv, &kenvp);
+ mach_port_deallocate (mach_task_self (), kbs);
+ if (err)
+ error (0, err, "kernel task bootstrap port (ignoring)");
+ else
{
- term = file_name_lookup (termname, flags | O_CREAT|O_NOTRANS, 0666);
- if (term == MACH_PORT_NULL)
+ err = proc_set_arg_locations (proc, kargv, kenvp);
+ if (err)
+ error (0, err, "cannot propagate original kernel command line");
+ else
{
- error (0, errno, "%s", termname);
- return errno;
+ mach_port_deallocate (mach_task_self (), proc);
+ mach_port_deallocate (mach_task_self (), task);
+ if (! fakeboot)
+ error (0, 0, "warning: "
+ "I see another Hurd, but --fake-boot was not given");
+ return;
}
-
- *underlying = term;
- *underlying_type = MACH_MSG_TYPE_COPY_SEND;
-
- return 0;
}
+ }
- retry:
- bootstrap_args |= RB_SINGLE;
+ /* Our arguments make up the multiboot command line used to boot the
+ kernel. We'll write into the kernel task a page containing a
+ canonical argv array and argz of those words. */
- if (try == 1)
- {
- terminal = TERMINAL_FIRST_TRY;
- argz_len = sizeof TERMINAL_FIRST_TRY;
- try = 2;
- }
- else if (try == 2)
- {
- terminal = TERMINAL_SECOND_TRY;
- argz_len = sizeof TERMINAL_SECOND_TRY;
- try = 3;
- }
- else
- goto fail;
-
- termname = terminal + strlen (terminal) + 1; /* first arg is name */
-
- /* The callback to start_translator opens TERM as a side effect. */
- errno =
- fshelp_start_translator (open_node, terminal, terminal, argz_len, 3000,
- &control);
- if (errno)
- {
- error (0, errno, "%s", terminal);
- goto retry;
- }
-
- errno = file_set_translator (term, 0, FS_TRANS_SET, 0, 0, 0,
- control, MACH_MSG_TYPE_COPY_SEND);
- mach_port_deallocate (mach_task_self (), control);
- if (errno)
- {
- error (0, errno, "%s", termname);
- goto retry;
- }
- mach_port_deallocate (mach_task_self (), term);
-
- /* Now repeat the open. */
- term = file_name_lookup (termname, O_RDWR, 0);
- if (term == MACH_PORT_NULL)
- {
- error (0, errno, "%s", termname);
- goto retry;
- }
- errno = io_stat (term, &st);
- if (errno)
- {
- error (0, errno, "%s", termname);
- term = MACH_PORT_NULL;
- goto retry;
- }
- if (st.st_fstype != FSTYPE_TERM)
- {
- error (0, 0, "%s: Not a terminal", termname);
- term = MACH_PORT_NULL;
- goto retry;
- }
+ err = argz_create (&global_argv[1], &argz, &argzlen);
+ assert_perror (err);
+ argc = argz_count (argz, argzlen);
+
+ windowsz = round_page (((argc + 1) * sizeof (char *)) + argzlen);
- if (term)
- error (0, 0, "Using temporary console %s", termname);
+ mine = (vm_address_t) mmap (0, windowsz, PROT_READ|PROT_WRITE,
+ MAP_ANON, 0, 0);
+ assert (mine != -1);
+ err = vm_allocate (task, &his, windowsz, 1);
+ if (err)
+ {
+ error (0, err, "cannot allocate %Zu bytes in kernel task", windowsz);
+ free (argz);
+ mach_port_deallocate (mach_task_self (), proc);
+ mach_port_deallocate (mach_task_self (), task);
+ munmap ((caddr_t) mine, windowsz);
+ return;
}
- fail:
+ for (i = 0, entry = argz; entry != NULL;
+ ++i, entry = argz_next (argz, argzlen, entry))
+ ((char **) mine)[i] = ((char *) &((char **) his)[argc + 1]
+ + (entry - argz));
+ ((char **) mine)[argc] = NULL;
+ memcpy (&((char **) mine)[argc + 1], argz, argzlen);
- /* At this point either TERM is the console or it's null. If it's
- null, then don't do anything, and our fd's will be copied.
- Otherwise, open fd's 0, 1, and 2. */
- if (term != MACH_PORT_NULL)
+ free (argz);
+
+ /* We have the data all set up in our copy, now just write it over. */
+ err = vm_write (task, his, mine, windowsz);
+ mach_port_deallocate (mach_task_self (), task);
+ munmap ((caddr_t) mine, windowsz);
+ if (err)
{
- int fd = openport (term, O_RDWR);
- if (fd < 0)
- assert_perror (errno);
-
- dup2 (fd, 0);
- close (fd);
- dup2 (0, 1);
- dup2 (0, 2);
-
- fclose (stdin);
- stdin = fdopen (0, "r");
-
- /* Don't reopen our output channel for reliability's sake. */
-
- /* Set ports in init_dtable for programs we start. */
- mach_port_deallocate (mach_task_self (), default_dtable[0]);
- mach_port_deallocate (mach_task_self (), default_dtable[1]);
- mach_port_deallocate (mach_task_self (), default_dtable[2]);
- default_dtable[0] = getdport (0);
- default_dtable[1] = getdport (1);
- default_dtable[2] = getdport (2);
+ error (0, err, "cannot write command line into kernel task");
+ return;
}
- else
- error (0, 0, "Cannot open console");
- return term;
+ /* The argument vector is set up in the kernel task at address HIS.
+ Finally, we can inform the proc server where to find it. */
+ err = proc_set_arg_locations (proc, his, his + (argc * sizeof (char *)));
+ mach_port_deallocate (mach_task_self (), proc);
+ if (err)
+ error (0, err, "proc_set_arg_locations for kernel task");
}
-
-/** Single and multi user transitions **/
-
+/** Running userland. **/
-/* Start the single-user environment. This can only be done
- when the core servers have fully started. We know that
- startup_essential_task is the last thing they do before being
- ready to handle requests, so we start this once all the necessary
- servers have identified themselves that way. */
-void
-launch_single_user ()
-{
- char shell[1024];
- mach_port_t term;
+/* 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. */
- printf ("Single-user environment:");
- fflush (stdout);
- term = open_console ();
+static pid_t child_pid; /* PID of the child we run */
+static task_t child_task; /* and its (original) task port */
- system_state = SINGLE;
-
-#if 0
- printf ("Shell program [%s]: ", _PATH_BSHELL);
- if (! getstring (shell, sizeof shell))
-#endif
- strcpy (shell, _PATH_BSHELL);
-
- /* The shell needs a real controlling terminal, so set that up here. */
- shell_pid = run_for_real (shell, shell, strlen (shell) + 1, term, 1);
- mach_port_deallocate (mach_task_self (), term);
- if (shell_pid == 0)
- crash_system ();
- printf (" shell.\n");
- fflush (stdout);
-}
+error_t send_signal (mach_port_t msgport, int signal, mach_port_t refport,
+ mach_msg_timeout_t);
-/* Run /etc/rc as a shell script. Return non-zero if we fail. */
-int
-process_rc_script ()
-{
- char *rcargs;
- size_t rcargslen;
- mach_port_t term;
+static void launch_something (const char *why);
- if (do_fastboot)
- {
- rcargs = malloc (rcargslen = sizeof _PATH_RUNCOM);
- strcpy (rcargs, _PATH_RUNCOM);
- }
- else
- {
- rcargslen = asprintf (&rcargs, "%s%c%s", _PATH_RUNCOM, '\0', "autoboot");
- rcargslen++; /* final null */
- }
-
- term = open_console ();
-
- system_state = RUNCOM;
-
- rc_pid = run_for_real (rcargs, rcargs, rcargslen, term, 1);
- mach_port_deallocate (mach_task_self (), term);
- return ! rc_pid;
-}
-/* Start up multi-user state. */
+/* SIGNO has arrived and has been validated. Do whatever work it
+ implies. */
void
-launch_multi_user ()
+process_signal (int signo)
{
- int fail;
-
- if (!mapped_time)
- maptime_map (1, 0, &mapped_time);
-
- fail = init_ttys ();
- if (fail)
- launch_single_user ();
- else
+ if (signo == SIGCHLD)
{
- system_state = MULTI;
- fail = startup_ttys ();
- if (fail)
- launch_single_user ();
- }
-}
+ /* 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. */
-/* Kill all the outstanding processes with SIGNO. Return 1 if
- there were no tasks left to kill. */
-int
-kill_everyone (int signo)
-{
- pid_t pidbuf[100], *pids = pidbuf;
- mach_msg_type_number_t i, npids = 100;
- task_t tk;
- struct ess_task *es;
- mach_port_t msg;
- int didany;
- int nloops;
- error_t err;
+ /* 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);
+ }
- for (nloops = 10; nloops; nloops--)
+ launch_something (desc);
+ }
+ }
+ }
+ else
{
- if (nloops < 9)
- /* Give it a rest for folks to have a chance to die */
- sleep (1);
+ /* Pass the signal on to the child. */
+ task_t task;
+ error_t err;
- didany = 0;
- err = proc_getallpids (procserver, &pids, &npids);
- if (!err)
+ err = proc_pid2task (procserver, child_pid, &task);
+ if (err)
+ {
+ error (0, err, "proc_pid2task on %d", child_pid);
+ task = child_task;
+ }
+ else
{
- for (i = 0; i < npids; i++)
+ 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
{
- if (pids[i] == 1 /* us */
- || pids[i] == 2 /* kernel */
- || pids[i] == 3 /* default pager for now XXX */)
- continue;
-
- /* See if the task is essential */
- err = proc_pid2task (procserver, pids[i], &tk);
+ err = send_signal (msgport, signo, task,
+ 500); /* Block only half a second. */
+ mach_port_deallocate (mach_task_self (), msgport);
if (err)
- continue;
-
- for (es = ess_tasks; es; es = es->next)
- if (tk == es->task_port)
- {
- /* Skip this one */
- mach_port_deallocate (mach_task_self (), tk);
- continue;
- }
-
- /* Kill it */
- if (signo == SIGKILL)
- {
- task_terminate (tk);
- didany = 1;
- }
- else
{
- err = proc_getmsgport (procserver, pids[i], &msg);
- if (err)
- {
- mach_port_deallocate (mach_task_self (), tk);
- continue;
- }
-
- didany = 1;
- msg_sig_post (msg, signo, 0, tk);
- mach_port_deallocate (mach_task_self (), tk);
+ 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");
}
}
}
- if (pids != pidbuf)
- vm_deallocate (mach_task_self (), (vm_address_t) pids,
- npids * sizeof (pid_t));
- if (!didany)
- return 1;
}
- return 0;
}
-/* Kill outstanding multi-user sessions */
-void
-kill_multi_user ()
+/* Start the child program PROG. It is run via /libexec/console-run
+ with the given additional arguments. */
+static int
+start_child (const char *prog, char **progargs)
{
- int sigs[3] = {SIGHUP, SIGTERM, SIGKILL};
- int stage;
-
- free_ttys ();
-
- for (stage = 0; stage < 3; stage++)
- if (kill_everyone (sigs[stage]))
- break;
-
- /* Notify tasks that they are about to die. */
- notify_shutdown ("transition to single-user");
-
- if (stage == 3)
- error (0, 0, "warning: some processes wouldn't die; `ps -axlM' advised");
-}
+ file_t file;
+ error_t err;
+ char *args;
+ size_t arglen;
-/* SIGNO has arrived and has been validated. Do whatever work it
- implies. */
-void
-process_signal (int signo)
-{
- int fail;
-
- switch (signo)
+ if (progargs == 0)
{
- case SIGTERM:
- if (system_state == MULTI)
- {
- /* Drop back to single user. */
- kill_multi_user ();
- launch_single_user ();
- }
- break;
-
- case SIGHUP:
- if (system_state == MULTI)
- reread_ttys ();
- break;
-
- case SIGCHLD:
+ const char *argv[] = { "/libexec/console-run", prog, 0 };
+ err = argz_create ((char **) argv, &args, &arglen);
+ }
+ else
+ {
+ int argc = 0;
+ while (progargs[argc] != 0)
+ ++argc;
{
- /* A child died. Find its status. */
- int status;
- pid_t pid;
+ const char *argv[2 + argc + 1];
+ argv[0] = "/libexec/console-run";
+ argv[1] = prog;
+ argv[2 + argc] = 0;
+ while (argc-- > 0)
+ argv[2 + argc] = progargs[argc];
+ err = argz_create ((char **) argv, &args, &arglen);
+ }
+ }
+ assert_perror (err);
- for (;;)
- {
- pid = waitpid (WAIT_ANY, &status, WNOHANG | WUNTRACED);
- if (pid <= 0)
- return;
+ file = file_name_lookup (args, O_EXEC, 0);
+ if (file == MACH_PORT_NULL)
+ {
+ error (0, errno, "%s", args);
+ free (args);
+ return -1;
+ }
- if (pid == shell_pid && system_state == SINGLE)
- {
- if (WIFSIGNALED (status))
- {
- error (0, 0,
- "Single-user terminated abnormally (%s), restarting",
- strsignal (WTERMSIG (status)));
- launch_single_user ();
- }
- else if (WIFSTOPPED (status))
- {
- error (0, 0,
- "Single-user stopped (%s), killing and restarting",
- strsignal (WSTOPSIG (status)));
- kill (shell_pid, SIGKILL);
- launch_single_user ();
- }
- else
- {
- do_fastboot = 1;
- fail = process_rc_script ();
- if (fail)
- {
- do_fastboot = 0;
- launch_single_user ();
- }
- }
- }
- else if (pid == rc_pid && system_state == RUNCOM)
- {
- if (WIFSIGNALED (status))
- {
- error (0, 0,
- "%s terminated abnormally (%s), \
-going to single user mode",
- _PATH_RUNCOM, strsignal (WTERMSIG (status)));
- launch_single_user ();
- }
- else if (WIFSTOPPED (status))
- {
- error (0, 0,
- "%s stopped (%s), \
-killing it and going to single user mode",
- _PATH_RUNCOM, strsignal (WSTOPSIG (status)));
- kill (rc_pid, SIGKILL);
- launch_single_user ();
- }
- else if (WEXITSTATUS (status))
- launch_single_user ();
- else
- launch_multi_user ();
- }
- else if (system_state == MULTI)
- restart_terminal (pid);
- }
- break;
- }
- default:
- break;
+ task_create (mach_task_self (),
+#ifdef KERN_INVALID_LEDGER
+ NULL, 0, /* OSF Mach */
+#endif
+ 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);
+
+ if (try == 0 && start_child (tries[try++], &global_argv[1]) == 0)
+ return;
+
+ while (try < sizeof tries / sizeof tries[0])
+ if (start_child (tries[try++], NULL) == 0)
+ return;
+
+ crash_system ();
+}
+void
+launch_system (void)
+{
+ launch_something (0);
+}
/** RPC servers **/
@@ -1421,6 +1165,7 @@ S_startup_authinit (startup_t server,
return MIG_NO_REPLY;
}
+
kern_return_t
S_startup_essential_task (mach_port_t server,
mach_port_t reply,
@@ -1430,43 +1175,19 @@ S_startup_essential_task (mach_port_t server,
char *name,
mach_port_t credential)
{
- struct ess_task *et;
- mach_port_t prev;
static int authinit, procinit, execinit;
int fail;
if (credential != host_priv)
return EPERM;
- /* Record this task as essential. */
- et = malloc (sizeof (struct ess_task));
- if (et == NULL)
- return ENOMEM;
- et->task_port = task;
- et->name = strdup (name);
- if (et->name == NULL)
- {
- free (et);
- return ENOMEM;
- }
- et->next = ess_tasks;
- ess_tasks = et;
-
- /* Dead-name notification on the task port will tell us when it dies. */
- mach_port_request_notification (mach_task_self (), task,
- MACH_NOTIFY_DEAD_NAME, 1, startup,
- MACH_MSG_TYPE_MAKE_SEND_ONCE, &prev);
- if (prev)
- mach_port_deallocate (mach_task_self (), prev);
-#if 0
- /* Taking over the exception port will give us a better chance
- if the task tries to get wedged on a fault. */
- task_set_special_port (task, TASK_EXCEPTION_PORT, startup);
-#endif
+ fail = record_essential_task (name, task);
+ if (fail)
+ return fail;
mach_port_deallocate (mach_task_self (), credential);
- if (system_state == INITIAL)
+ if (!booted)
{
if (!strcmp (name, "auth"))
authinit = 1;
@@ -1482,15 +1203,12 @@ S_startup_essential_task (mach_port_t server,
startup_essential_task_reply (reply, replytype, 0);
init_stdarrays ();
+ frob_kernel_process ();
+
+ launch_system ();
+
+ booted = 1;
- if (bootstrap_args & RB_SINGLE)
- launch_single_user ();
- else
- {
- fail = process_rc_script ();
- if (fail)
- launch_single_user ();
- }
return MIG_NO_REPLY;
}
}
@@ -1504,15 +1222,10 @@ S_startup_request_notification (mach_port_t server,
char *name)
{
struct ntfy_task *nt;
- mach_port_t prev;
- mach_port_request_notification (mach_task_self (), notify,
- MACH_NOTIFY_DEAD_NAME, 1, startup,
- MACH_MSG_TYPE_MAKE_SEND_ONCE, &prev);
- if (prev != MACH_PORT_NULL)
- mach_port_deallocate (mach_task_self (), prev);
+ request_dead_name (notify);
- /* Note that the ntfy_tasks list is kept in inverse order of the
+ /* Note that the ntfy_tasks list is kept in inverse order of the
calls; this is important. We need later notification requests
to get executed first. */
nt = malloc (sizeof (struct ntfy_task));
@@ -1531,6 +1244,11 @@ do_mach_notify_dead_name (mach_port_t notify,
struct ntfy_task *nt, *pnt;
struct ess_task *et;
+ assert (notify == startup);
+
+ /* Deallocate the extra reference the notification carries. */
+ mach_port_deallocate (mach_task_self (), name);
+
for (et = ess_tasks; et != NULL; et = et->next)
if (et->task_port == name)
/* An essential task has died. */
@@ -1549,8 +1267,35 @@ do_mach_notify_dead_name (mach_port_t notify,
else
ntfy_tasks = nt->next;
free (nt);
+
return 0;
}
+
+ if (! booted)
+ {
+ /* The system has not come up yet, so essential tasks are not yet
+ registered. But the essential servers involved in the bootstrap
+ handshake might crash before completing it, so we have requested
+ dead-name notification on those tasks. */
+ static const struct { task_t *taskp; const char *name; } boots[] =
+ {
+ {&fstask, "bootstrap filesystem"},
+ {&authtask, "auth"},
+ {&proctask, "proc"},
+ };
+ size_t i;
+ for (i = 0; i < sizeof boots / sizeof boots[0]; ++i)
+ if (name == *boots[i].taskp)
+ {
+ error (0, 0, "Crashing system; %s server died during bootstrap",
+ boots[i].name);
+ crash_mach ();
+ }
+ error (0, 0, "BUG! Unexpected dead-name notification (name %#zx)",
+ name);
+ crash_mach ();
+ }
+
return 0;
}
@@ -1614,7 +1359,7 @@ S_msg_sig_post_untraced (mach_port_t msgport,
/* Reply immediately */
msg_sig_post_untraced_reply (reply, reply_type, 0);
-
+
process_signal (signo);
return MIG_NO_REPLY;
}
@@ -1627,10 +1372,10 @@ S_msg_sig_post (mach_port_t msgport,
if (refport != mach_task_self ())
return EPERM;
mach_port_deallocate (mach_task_self (), refport);
-
+
/* Reply immediately */
msg_sig_post_reply (reply, reply_type, 0);
-
+
process_signal (signo);
return MIG_NO_REPLY;
}
@@ -1803,13 +1548,13 @@ S_msg_describe_ports (mach_port_t process,
data_t *descriptions,
mach_msg_type_number_t *descriptionsCnt)
{
- return _S_msg_describe_ports (process, refport, names, namesCnt,
+ return _S_msg_describe_ports (process, refport, names, namesCnt,
descriptions, descriptionsCnt);
}
error_t
S_msg_report_wait (mach_port_t process, thread_t thread,
- string_t desc, int *rpc)
+ string_t desc, mach_msg_id_t *rpc)
{
*desc = 0;
*rpc = 0;
diff --git a/init/stubs.c b/init/stubs.c
new file mode 100644
index 00000000..5292ab68
--- /dev/null
+++ b/init/stubs.c
@@ -0,0 +1,139 @@
+/* By-hand stubs for some RPC calls
+ Copyright (C) 1994,96,99,2000 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.h>
+#include <string.h>
+#include <assert.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,
+ mach_msg_timeout_t timeout)
+{
+ error_t err;
+
+ /* This message buffer might be modified by mach_msg in some error cases,
+ so we cannot safely reuse a static buffer. */
+ 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 */
+ msgport, /* 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 */
+ signal,
+ /* 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 */
+ refport
+ };
+
+ err = mach_msg (&message.head,
+ MACH_SEND_MSG|MACH_SEND_TIMEOUT, sizeof message, 0,
+ MACH_PORT_NULL, timeout, MACH_PORT_NULL);
+
+ switch (err)
+ {
+ case MACH_SEND_TIMED_OUT:
+ /* The send could not complete in time. In this error case, the
+ kernel has modified the message buffer in a pseudo-receive
+ operation. That means our COPY_SEND refs might now be MOVE_SEND
+ refs, in which case each has gained user ref accordingly. To
+ avoid leaking those refs, we must clean up the buffer. We don't
+ use mach_msg_destroy because it assumes the local/remote ports in
+ the header have been reversed as from a real receive, while a
+ pseudo-receive leaves them as they were. */
+ if (MACH_MSGH_BITS_REMOTE (message.head.msgh_bits)
+ == MACH_MSG_TYPE_MOVE_SEND)
+ mach_port_deallocate (mach_task_self (),
+ message.head.msgh_remote_port);
+ if (message.refporttype.msgt_name == MACH_MSG_TYPE_MOVE_SEND)
+ mach_port_deallocate (mach_task_self (), message.refport);
+ break;
+
+ /* These are the other codes that mean a pseudo-receive modified
+ the message buffer and we might need to clean up the send rights.
+ None of them should be possible in our usage. */
+ case MACH_SEND_INTERRUPTED:
+ case MACH_SEND_INVALID_NOTIFY:
+ case MACH_SEND_NO_NOTIFY:
+ case MACH_SEND_NOTIFY_IN_PROGRESS:
+ assert_perror (err);
+ break;
+
+ default: /* Other errors are safe to ignore. */
+ break;
+ }
+
+ return err;
+}