diff options
Diffstat (limited to 'init')
-rw-r--r-- | init/ChangeLog | 491 | ||||
-rw-r--r-- | init/Makefile | 18 | ||||
-rw-r--r-- | init/init.c | 1355 | ||||
-rw-r--r-- | init/stubs.c | 139 |
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; +} |