diff options
Diffstat (limited to 'init')
-rw-r--r-- | init/ChangeLog | 699 | ||||
-rw-r--r-- | init/Makefile | 47 | ||||
-rw-r--r-- | init/init.c | 2009 | ||||
-rw-r--r-- | init/stubs.c | 106 | ||||
-rw-r--r-- | init/ttys.c | 321 | ||||
-rw-r--r-- | init/ttys.h | 22 |
6 files changed, 3204 insertions, 0 deletions
diff --git a/init/ChangeLog b/init/ChangeLog new file mode 100644 index 00000000..941c6903 --- /dev/null +++ b/init/ChangeLog @@ -0,0 +1,699 @@ +1999-09-28 Thomas Bushnell, BSG <tb@mit.edu> + + * init.c (frob_kernel_process): Allocate the kernel's page in the + actual kernel task, not in our own. I wonder how this ever + worked. Also if we fail in that allocation, free the page we + allocated in our own space. + +1999-08-24 Roland McGrath <roland@baalperazim.frob.com> + + * init.c (notify_shutdown): Add const to argument type. + +1999-07-24 Roland McGrath <roland@baalperazim.frob.com> + + * Makefile (split-init): Set to `yes' by default. + +1999-07-10 Roland McGrath <roland@baalperazim.frob.com> + + * init.c: Add #include <sys/mman.h> for munmap decl. + +1999-07-09 Thomas Bushnell, BSG <tb@mit.edu> + + * init.c (frob_kernel_process): Use mmap instead of vm_allocate. + +1999-07-03 Thomas Bushnell, BSG <tb@mit.edu> + + * init.c (reboot_system): Use munmap instead of vm_deallocate. + (frob_kernel_process): Likewise. + (kill_everyone): Likewise. + +1999-06-19 Roland McGrath <roland@baalperazim.frob.com> + + * Makefile (HURDLIBS): Add ports and fshelp only if $(split-init)!=yes. + + * init.c (open_console): Put this function inside [! SPLIT_INIT]. + +1999-06-18 Roland McGrath <roland@baalperazim.frob.com> + + * init.c [SPLIT_INIT] (child_pid, child_task): New variables. + (process_signal, start_child, launch_something, launch_system): New + functions. + [! SPLIT_INIT] (system_state, shell_pid, rc_pid, launch_single_user, + process_rc_script, launch_multi_user, launch_system, kill_everyone, + kill_multi_user, process_signal): Variables and functions put inside + #ifndef SPLIT_INIT. + * stubs.c: New file, modified from ../proc/stubs.c. + * Makefile (SRCS): Remove ttys.c here. + [$(split-init) = yes] (SRCS): Add stubs.c + [$(split-init) = yes] (init-CPPFLAGS): New variable, -DSPLIT_INIT. + [$(split-init) = no] (SRCS): Add ttys.c only here. + [$(split-init) = no] (LDLIBS): Put defn (-lutil) under this test. + (split-init): New variable to turn on split-init, commented out. + +1999-06-15 Roland McGrath <roland@baalperazim.frob.com> + + * init.c (booted): New variable. + (open_console): Use that instead of system_state. + (S_startup_essential_task): Likewise. + (do_mach_notify_dead_name): Likewise. + (launch_system): New function. + (S_startup_essential_task): Call it. + + * init.c (global_argv): Make static. + + * init.c (startup_envz, startup_envz_len): New variables. + (run, run_for_real): Use those for child environment. + (main): Set them up from our ENVP argument. + +1999-06-14 Roland McGrath <roland@baalperazim.frob.com> + + * init.c (main): Barf if run in a normal Hurd environment (not boot). + + * init.c (record_essential_task): Add missing return. + + * ttys.c: Include "ttys.h". + +1999-06-13 Roland McGrath <roland@baalperazim.frob.com> + + * init.c (kill_multi_user): Suggest `ps -AlM' in error message. + + * init.c (record_essential_task): New function, broken out of + S_startup_essential_task. + (S_startup_essential_task): Call it. + (frob_kernel_process): Call it for kernel task port. + (kill_everyone): Remove special case for PID 2 (kernel task). + + * init.c (run): Add const to SERVER arg, PROG local. + Don't trim directory name from PROG for argument. + + * ttys.c (struct terminal): Use `pid_t' for `pid' member. + (ttys, nttys, ttyslen): Make variables static. + (setup_terminal, add_terminal, find_line, startup_terminal, + shutdown_terminal): Make all these functions static. + + Move all the /etc/ttys handling stuff into a separate source file. + * init.c (_PATH_LOGIN, WINDOW_DELAY, struct terminal, + nttys, ttyslen, setup_terminal, add_terminal, + init_ttys, free_ttys, startup_terminal, startup_ttys, + find_line, restart_terminal, shutdown_terminal, reread_ttys): Move to + * ttys.c: ... here, new file. + * ttys.h: New file, declare external functions in ttys.c. + * Makefile (SRCS): Add ttys.c. + (OBJS): Derive from $(SRCS). + (LCLHDRS): New variable, add ttys.h. + +1999-06-05 Roland McGrath <roland@baalperazim.frob.com> + + * init.c (request_dead_name): New function. + (S_startup_request_notification, S_startup_essential_task): Use it. + (run): Request dead-name notification for new task. + (main): Request dead-name notification for FSTASK. + (do_mach_notify_dead_name): If system_state is INITIAL, recognize + FSTASK, AUTHTASK, PROCTASK specifically and crash with appropriate msg. + +1999-06-04 Roland McGrath <roland@baalperazim.frob.com> + + * init.c (launch_core_servers): Use proc_child on the proc server task + to register it with itself as our child. Snarf its proc port and use + proc_mark_exec do remove that unsightly `f', as we do for the other + bootstrap processes. + +1999-06-02 Roland McGrath <roland@baalperazim.frob.com> + + * init.c (frob_kernel_process): If no --kernel-command-line option, + try `getenv ("MULTIBOOT_CMDLINE")' before defaulting to "(kernel)". + +1999-06-01 Roland McGrath <roland@baalperazim.frob.com> + + * init.c (CRASH_FLAGS): Macro removed. + (crash_flags): New variable replaces it. + (crash_mach, crash_system): Use crash_flags instead of CRASH_FLAGS. + (options, parse_opt): Add --crash-debug/-H, to set crash_flags to + RB_DEBUGGER. + + * init.c (kernel_command_line): New variable. + (frob_kernel_process): New function. + (S_startup_essential_task): Call it after init_stdarrays. + (options): Add --kernel-command-line/-K option. + (parse_opt): Grok -K, set kernel_command_line. + +Sat Mar 6 17:13:48 1999 Thomas Bushnell, BSG <tb@mit.edu> + + * init.c (do_mach_notify_dead_name): Deallocate the extra + reference to NAME that the notification carries. + +Tue Feb 16 18:54:33 1999 Thomas Bushnell, BSG <tb@mit.edu> + + * init.c (shutdown_terminal): Revoke access to the terminal from + existing programs. + +1998-10-24 Roland McGrath <roland@baalperazim.frob.com> + + * init.c (main): Don't bogusly clear bootstrap_args. + Reported by OKUJI Yoshinori <okuji@kuicr.kyoto-u.ac.jp>. + +Tue May 12 12:03:38 1998 Thomas Bushnell, n/BSG <tb@mit.edu> + + * init.c (setup_terminal): Free LINE after done using it. + (process_rc_script): Likewise free RCARGS. + Both reported by Katusya Tanaka (wyvern@pb3.so-net.ne.jp). + +1997-06-30 Miles Bader <miles@gnu.ai.mit.edu> + + * init.c (bootstrap_args): Initialize to 0. + (parse_opt): New function. + (options, doc): New variables. + (main): Parse args using argp. + Include <argp.h>. + +Thu Sep 12 16:32:31 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu> + + * Makefile (HURDLIBS): New variable. + (init): Delete special target. + + * Makefile (mung_msg_S.h): Put rule *after* inclusion of Makeconf. + +Thu Sep 5 11:12:32 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu> + + * init.c: Include <version.h>. + (init_version): Delete variable. + (launch_core_servers): Pass empty string as release; HURD_VERSION + as version. + +Tue Aug 13 17:51:38 1996 Miles Bader <miles@gnu.ai.mit.edu> + + * Makefile (init): Remove -lutil. + (libutil-libsubst): Variable removed. + (LDLIBS): New variable. + +Mon Aug 12 11:12:22 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu> + + * init.c (setup_terminal): Declare LINE. + (add_terminal): Don't declare LINE. + +Thu Aug 8 16:34:06 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu> + + * init.c (setup_terminal): New function. + (add_terminal): Use setup_terminal. + (reread_ttys): When turning an existent terminal spec on, call + setup_terminal before startup_terminal. + + * init.c (struct terminal): New member `read'. + (shutdown_terminal): New function. + (reread_ttys): Use shutdown_terminal instead of doing it by hand. + Keep track of which ttys we used to know about are no longer in + /etc/ttys, and treat them as now `off'. + + * init.c (kill_everyone): `continue' in the essential task case + didn't go back to the main loop; fix it up correctly. + +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 new file mode 100644 index 00000000..716aaa5a --- /dev/null +++ b/init/Makefile @@ -0,0 +1,47 @@ +# +# Copyright (C) 1994, 1995, 1996, 1999 Free Software Foundation +# +# 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. + +dir := init +makemode := server + +# Set this to something other than `yes' to get the old Hurd init +# that has BSD-style rc and ttys functionality rolled in. +# The option for this old style may go away at some point in the future; +# if you want BSD style, best to use runttys (in daemons) instead. +split-init = yes + +SRCS = init.c +OBJS = $(SRCS:.c=.o) \ + startupServer.o notifyServer.o startup_replyUser.o msgServer.o \ + startup_notifyUser.o +LCLHDRS = ttys.h +target = init +HURDLIBS = shouldbeinlibc + +ifeq (yes,$(split-init)) +init-CPPFLAGS = -DSPLIT_INIT +SRCS += stubs.c +else +SRCS += ttys.c +LDLIBS = -lutil +HURDLIBS += ports fshelp +endif + +include ../Makeconf + +mung_msg_S.h: msg_S.h + sed 's/msg_server/mung_msg_server/' < $< > $@ diff --git a/init/init.c b/init/init.c new file mode 100644 index 00000000..3ec1270b --- /dev/null +++ b/init/init.c @@ -0,0 +1,2009 @@ +/* Start and maintain hurd core servers and system run state + + Copyright (C) 1993,94,95,96,97,98,99 Free Software Foundation, Inc. + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + The GNU Hurd is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the 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. */ + +/* This is probably more include files than I've ever seen before for + one file. */ +#include <hurd.h> +#include <hurd/fs.h> +#include <hurd/fsys.h> +#include <device/device.h> +#include <stdio.h> +#include <assert.h> +#include <hurd/paths.h> +#include <sys/reboot.h> +#include <sys/file.h> +#include <unistd.h> +#include <string.h> +#include <mach/notify.h> +#include <stdlib.h> +#include <hurd/msg.h> +#include <hurd/term.h> +#include <hurd/fshelp.h> +#include <paths.h> +#include <sys/mman.h> +#include <hurd/msg_server.h> +#include <wire.h> +#include <sys/wait.h> +#include <error.h> +#include <hurd/msg_reply.h> +#include <argz.h> +#include <maptime.h> +#include <version.h> +#include <argp.h> + +#include "startup_notify_U.h" +#include "startup_reply_U.h" +#include "startup_S.h" +#include "notify_S.h" +#include "mung_msg_S.h" + +/* host_reboot flags for when we crash. */ +int crash_flags = RB_AUTOBOOT; + +#define BOOT(flags) ((flags & RB_HALT) ? "halt" : "reboot") + +#define _PATH_RUNCOM "/libexec/rc" + + +/* Multiboot command line used to start the kernel, + a single string of space-separated words. */ +char *kernel_command_line; + +const char *argp_program_version = STANDARD_HURD_VERSION (init); + +static struct argp_option +options[] = +{ + {"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"}, + {"kernel-command-line", + 'K', "COMMAND-LINE", 0, "Multiboot command line string"}, + {0, 'x', 0, OPTION_HIDDEN}, + {0} +}; + +char doc[] = "Start and maintain hurd core servers and system run state"; + +int booted; /* Set when the core servers are up. */ + +/* This structure keeps track of each notified task. */ +struct ntfy_task + { + mach_port_t notify_port; + struct ntfy_task *next; + char *name; + }; + +/* This structure keeps track of each registered essential task. */ +struct ess_task + { + struct ess_task *next; + task_t task_port; + char *name; + }; + +/* 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; + + +/* Our receive right */ +mach_port_t startup; + +/* Ports to the kernel */ +mach_port_t host_priv, device_master; + +/* Args to bootstrap, expressed as flags */ +int bootstrap_args = 0; + +/* Set if something determines we should no longer pass the `autoboot' + flag to _PATH_RUNCOM. */ +int do_fastboot; + +/* Stored information for returning proc and auth startup messages. */ +mach_port_t procreply, authreply; +mach_msg_type_name_t procreplytype, authreplytype; + +/* Our ports to auth and proc. */ +mach_port_t authserver; +mach_port_t procserver; + +/* Our bootstrap port, on which we call fsys_getpriv and fsys_init. */ +mach_port_t bootport; + +/* Set iff we are a `fake' bootstrap. */ +int fakeboot; + +/* The tasks of auth and proc and the bootstrap filesystem. */ +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]; + +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 **/ + +/* Read a string from stdin into BUF. */ +static int +getstring (char *buf, size_t bufsize) +{ + if (fgets (buf, bufsize, stdin) != NULL && buf[0] != '\0') + { + size_t len = strlen (buf); + if (buf[len - 1] == '\n' || buf[len - 1] == '\r') + buf[len - 1] = '\0'; + return 1; + } + return 0; +} + + +/** System shutdown **/ + +/* Reboot the microkernel. */ +void +reboot_mach (int flags) +{ + if (fakeboot) + { + printf ("%s: Would %s Mach with flags %#x\n", + program_invocation_short_name, BOOT (flags), flags); + fflush (stdout); + exit (1); + } + else + { + 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"); + for (;;); + } +} + +/* Reboot the microkernel, specifying that this is a crash. */ +void +crash_mach (void) +{ + reboot_mach (crash_flags); +} + +/* Notify all tasks that have requested shutdown notifications */ +void +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...", + program_invocation_short_name, n->name, msg); + fflush (stdout); + err = startup_dosync (n->notify_port, 60000); /* 1 minute to reply */ + if (err == MACH_SEND_INVALID_DEST) + puts ("(no longer present)"); + else if (err) + puts (strerror (err)); + else + puts ("done"); + fflush (stdout); + } +} + +/* Reboot the Hurd. */ +void +reboot_system (int flags) +{ + notify_shutdown ("shutdown"); + + if (fakeboot) + { + pid_t *pp; + u_int npids = 0; + error_t err; + int ind; + + err = proc_getallpids (procserver, &pp, &npids); + if (err == MACH_SEND_INVALID_DEST) + { + procbad: + /* The procserver must have died. Give up. */ + error (0, 0, "Can't simulate crash; proc has died"); + reboot_mach (flags); + } + for (ind = 0; ind < npids; ind++) + { + task_t task; + + err = proc_pid2task (procserver, pp[ind], &task); + if (err == MACH_SEND_INVALID_DEST) + goto procbad; + else if (err) + { + error (0, err, "Getting task for pid %d", pp[ind]); + continue; + } + + /* Postpone self so we can finish; postpone proc + so that we can finish. */ + if (task != mach_task_self () && task != proctask) + { + struct procinfo *pi = 0; + u_int pisize = 0; + char *noise; + unsigned noise_len; + err = proc_getprocinfo (procserver, pp[ind], 0, + (int **)&pi, &pisize, &noise,&noise_len); + if (err == MACH_SEND_INVALID_DEST) + goto procbad; + if (err) + { + error (0, err, "Getting procinfo for pid %d", pp[ind]); + continue; + } + if (!(pi->state & PI_NOPARENT)) + { + printf ("%s: Killing pid %d\n", + program_invocation_short_name, pp[ind]); + fflush (stdout); + task_terminate (task); + } + if (noise_len > 0) + munmap (noise, noise_len); + } + } + printf ("%s: Killing proc server\n", program_invocation_short_name); + fflush (stdout); + task_terminate (proctask); + printf ("%s: Exiting", program_invocation_short_name); + fflush (stdout); + } + reboot_mach (flags); +} + +/* Reboot the Hurd, specifying that this is a crash. */ +void +crash_system (void) +{ + 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 (const char *server, mach_port_t *ports, task_t *task) +{ + char buf[BUFSIZ]; + const char *prog = server; + + if (bootstrap_args & RB_INITNAME) + { + printf ("Server file name (default %s): ", server); + if (getstring (buf, sizeof (buf))) + prog = buf; + } + + while (1) + { + file_t file; + + file = file_name_lookup (prog, O_EXEC, 0); + if (file == MACH_PORT_NULL) + error (0, errno, "%s", prog); + else + { + task_create (mach_task_self (), 0, task); + if (bootstrap_args & RB_KDB) + { + printf ("Pausing for %s\n", prog); + getchar (); + } + errno = 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 (!errno) + break; + + error (0, errno, "%s", prog); + } + + printf ("File name for server %s (or nothing to reboot): ", server); + if (getstring (buf, sizeof (buf))) + prog = buf; + else + crash_system (); + } + +#if 0 + 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 + the task that we started. If CTTY is set, then make that the + controlling terminal of the new process and put it in its own login + 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, + int setsid) +{ + file_t file; + error_t err; + task_t task; + char *progname; + int pid; + +#if 0 + char buf[512]; + do + { + printf ("File name [%s]: ", filename); + if (getstring (buf, sizeof (buf)) && *buf) + filename = buf; + file = file_name_lookup (filename, O_EXEC, 0); + if (!file) + error (0, errno, "%s", filename); + } + while (!file); +#else + file = file_name_lookup (filename, O_EXEC, 0); + if (!file) + { + error (0, errno, "%s", filename); + return 0; + } +#endif + + task_create (mach_task_self (), 0, &task); + proc_child (procserver, task); + proc_task2pid (procserver, task, &pid); + proc_task2proc (procserver, task, &default_ports[INIT_PORT_PROC]); + proc_mark_exec (default_ports[INIT_PORT_PROC]); + if (setsid) + proc_setsid (default_ports[INIT_PORT_PROC]); + if (ctty != MACH_PORT_NULL) + { + term_getctty (ctty, &default_ports[INIT_PORT_CTTYID]); + io_mod_owner (ctty, -pid); + proc_make_login_coll (default_ports[INIT_PORT_PROC]); + } + if (bootstrap_args & RB_KDB) + { + printf ("Pausing for %s\n", filename); + getchar (); + } + progname = strrchr (filename, '/'); + if (progname) + ++progname; + else + progname = filename; + err = file_exec (file, task, 0, + args, arglen, + startup_envz, startup_envz_len, + default_dtable, MACH_MSG_TYPE_COPY_SEND, 3, + 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 (), task); + if (ctty != MACH_PORT_NULL) + { + mach_port_deallocate (mach_task_self (), + default_ports[INIT_PORT_CTTYID]); + default_ports[INIT_PORT_CTTYID] = MACH_PORT_NULL; + } + mach_port_deallocate (mach_task_self (), file); + if (err) + { + error (0, err, "Cannot execute %s", filename); + return 0; + } + return pid; +} + + +/** Main program and setup **/ + +static int +demuxer (mach_msg_header_t *inp, + mach_msg_header_t *outp) +{ + extern int notify_server (), startup_server (), msg_server (); + + return (notify_server (inp, outp) || + msg_server (inp, outp) || + 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; + + case 'K': + kernel_command_line = arg; + /* XXX When this is really in use, + this should do some magical parsing for options. */ + break; + } + return 0; +} + +int +main (int argc, char **argv, char **envp) +{ + volatile int err; + int i; + mach_port_t consdev; + struct argp argp = { options, parse_opt, 0, doc }; + + /* Parse the arguments */ + argp_parse (&argp, argc, argv, 0, 0, 0); + + if (getpid () > 0) + error (2, 0, "can only be run by bootstrap filesystem"); + + global_argv = argv; + + /* Fetch a port to the bootstrap filesystem, the host priv and + master device ports, and the console. */ + if (task_get_bootstrap_port (mach_task_self (), &bootport) + || fsys_getpriv (bootport, &host_priv, &device_master, &fstask) + || device_open (device_master, D_WRITE, "console", &consdev)) + crash_mach (); + + wire_task_self (); + + /* Clear our bootstrap port so our children don't inherit it. */ + task_set_bootstrap_port (mach_task_self (), MACH_PORT_NULL); + + stderr = stdout = mach_open_devstream (consdev, "w"); + stdin = mach_open_devstream (consdev, "r"); + if (stdout == NULL || stdin == NULL) + 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); + assert_perror (err); + err = mach_port_insert_right (mach_task_self (), startup, startup, + 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) + { + case INIT_PORT_CRDIR: + default_ports[i] = getcrdir (); + break; + case INIT_PORT_CWDIR: + default_ports[i] = getcwdir (); + break; + default: + default_ports[i] = MACH_PORT_NULL; + break; + } + + default_dtable[0] = getdport (0); + default_dtable[1] = getdport (1); + default_dtable[2] = getdport (2); + + /* All programs we start should ignore job control stop signals. + That way Posix.1 B.2.2.2 is satisfied where it says that programs + not run under job control shells are protected. */ + default_ints[INIT_SIGIGN] = (sigmask (SIGTSTP) + | sigmask (SIGTTIN) + | sigmask (SIGTTOU)); + + default_ports[INIT_PORT_BOOTSTRAP] = startup; + run ("/hurd/proc", default_ports, &proctask); + printf (" proc"); + fflush (stdout); + run ("/hurd/auth", default_ports, &authtask); + printf (" auth"); + fflush (stdout); + default_ports[INIT_PORT_BOOTSTRAP] = MACH_PORT_NULL; + + /* Wait for messages. When both auth and proc have started, we + run launch_system which does the rest of the boot. */ + while (1) + { + err = mach_msg_server (demuxer, 0, startup); + assert_perror (err); + } +} + +void +launch_core_servers (void) +{ + mach_port_t old; + mach_port_t authproc, fsproc, procproc; + error_t err; + + /* Reply to the proc and auth servers. */ + startup_procinit_reply (procreply, procreplytype, 0, + mach_task_self (), authserver, + host_priv, MACH_MSG_TYPE_COPY_SEND, + device_master, MACH_MSG_TYPE_COPY_SEND); + if (!fakeboot) + { + mach_port_deallocate (mach_task_self (), device_master); + device_master = 0; + } + + proc_mark_exec (procserver); + + /* Declare that the filesystem and auth are our children. */ + proc_child (procserver, fstask); + proc_child (procserver, authtask); + + proc_task2proc (procserver, authtask, &authproc); + proc_mark_exec (authproc); + startup_authinit_reply (authreply, authreplytype, 0, authproc, + MACH_MSG_TYPE_MOVE_SEND); + + /* Give the library our auth and proc server ports. */ + _hurd_port_set (&_hurd_ports[INIT_PORT_AUTH], authserver); + _hurd_port_set (&_hurd_ports[INIT_PORT_PROC], procserver); + + /* Do NOT run _hurd_proc_init! That will start signals, which we do not + want. We listen to our own message port. Tell the proc server where + our args and environment are. */ + proc_set_arg_locations (procserver, + (vm_address_t) global_argv, (vm_address_t) environ); + + default_ports[INIT_PORT_AUTH] = authserver; + + /* 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. */ + proc_task2proc (procserver, fstask, &fsproc); + proc_mark_exec (fsproc); + +#if 0 + printf ("Init has completed.\n"); + fflush (stdout); +#endif + printf (".\n"); + fflush (stdout); + + /* Tell the proc server our msgport. Be sure to do this after we are all + done making requests of proc. Once we have done this RPC, proc + assumes it can send us requests, so we cannot block on proc again + before accepting more RPC requests! However, we must do this before + calling fsys_init, because fsys_init blocks on exec_init, and + exec_init will block waiting on our message port. */ + proc_setmsgport (procserver, startup, &old); + if (old != MACH_PORT_NULL) + 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. */ +} + +/* Set up the initial value of the standard exec data. */ +void +init_stdarrays () +{ + auth_t nullauth; + mach_port_t pt; + mach_port_t ref; + mach_port_t *std_port_array; + int *std_int_array; + int i; + + std_port_array = alloca (sizeof (mach_port_t) * INIT_PORT_MAX); + std_int_array = alloca (sizeof (int) * INIT_INT_MAX); + + bzero (std_port_array, sizeof (mach_port_t) * INIT_PORT_MAX); + bzero (std_int_array, sizeof (int) * INIT_INT_MAX); + + __USEPORT (AUTH, auth_makeauth (port, 0, MACH_MSG_TYPE_COPY_SEND, 0, + 0, 0, 0, 0, 0, 0, 0, 0, &nullauth)); + + pt = getcwdir (); + ref = mach_reply_port (); + io_reauthenticate (pt, ref, MACH_MSG_TYPE_MAKE_SEND); + auth_user_authenticate (nullauth, ref, MACH_MSG_TYPE_MAKE_SEND, + &std_port_array[INIT_PORT_CWDIR]); + mach_port_destroy (mach_task_self (), ref); + mach_port_deallocate (mach_task_self (), pt); + + pt = getcrdir (); + ref = mach_reply_port (); + io_reauthenticate (pt, ref, MACH_MSG_TYPE_MAKE_SEND); + auth_user_authenticate (nullauth, ref, MACH_MSG_TYPE_MAKE_SEND, + &std_port_array[INIT_PORT_CRDIR]); + mach_port_destroy (mach_task_self (), ref); + mach_port_deallocate (mach_task_self (), pt); + + std_port_array[INIT_PORT_AUTH] = nullauth; + + std_int_array[INIT_UMASK] = CMASK; + + __USEPORT (PROC, proc_setexecdata (port, std_port_array, + MACH_MSG_TYPE_COPY_SEND, INIT_PORT_MAX, + std_int_array, INIT_INT_MAX)); + for (i = 0; i < INIT_PORT_MAX; i++) + mach_port_deallocate (mach_task_self (), std_port_array[i]); +} + +#ifndef SPLIT_INIT +/* 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 () +{ +#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 (booted) + { + term = file_name_lookup (termname, O_RDWR, 0); + return term; + } + + termname = _PATH_CONSOLE; + term = file_name_lookup (termname, O_RDWR, 0); + if (term != MACH_PORT_NULL) + err = io_stat (term, &st); + 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) + { + term = file_name_lookup (termname, flags | O_CREAT|O_NOTRANS, 0666); + if (term == MACH_PORT_NULL) + { + error (0, errno, "%s", termname); + return errno; + } + + *underlying = term; + *underlying_type = MACH_MSG_TYPE_COPY_SEND; + + return 0; + } + + retry: + bootstrap_args |= RB_SINGLE; + + 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; + } + + if (term) + error (0, 0, "Using temporary console %s", termname); + } + + fail: + + /* 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) + { + 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); + } + else + error (0, 0, "Cannot open console"); + + return term; +} +#endif + +/* 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) +{ + 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) + { + 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); + + 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 + { + /* 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 + { + err = proc_set_arg_locations (proc, kargv, kenvp); + if (err) + error (0, err, "cannot propagate original kernel command line"); + else + { + 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; + } + } + } + + if (!kernel_command_line) + kernel_command_line = getenv ("MULTIBOOT_CMDLINE") ?: "(kernel)"; + + + /* The variable `kernel_command_line' contains the multiboot command line + used to boot the kernel, a single string of space-separated words. + + We will slice that up into words, and then write into the kernel task + a page containing a canonical argv array and argz of those words. */ + + err = argz_create_sep (kernel_command_line, ' ', &argz, &argzlen); + assert_perror (err); + argc = argz_count (argz, argzlen); + + windowsz = round_page (((argc + 1) * sizeof (char *)) + argzlen); + + 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; + } + + 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); + + 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) + { + error (0, err, "cannot write command line into kernel task"); + return; + } + + /* 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"); +} + +#ifdef SPLIT_INIT + +/** Running userland. **/ + +/* In the "split-init" setup, we just run a single program (usually + /libexec/runsystem) that is not expected to ever exit (or stop). + If it does exit (or can't be started), we go to an emergency single-user + shell as a fallback. */ + + +pid_t child_pid; /* PID of the child we run */ +task_t child_task; /* and its (original) task port */ + +error_t send_signal (mach_port_t msgport, int signal, mach_port_t refport); + +static void launch_something (const char *why); + + +/* SIGNO has arrived and has been validated. Do whatever work it + implies. */ +void +process_signal (int signo) +{ + if (signo == SIGCHLD) + { + /* A child died. Find its status. */ + int status; + pid_t pid; + + while (1) + { + pid = waitpid (WAIT_ANY, &status, WNOHANG | WUNTRACED); + if (pid <= 0) + break; /* No more children. */ + + /* Since we are init, orphaned processes get reparented to us and + alas, all our adopted children eventually die. Woe is us. We + just need to reap the zombies to relieve the proc server of + its burden, and then we can forget about the little varmints. */ + + if (pid == child_pid) + { + /* The big magilla bit the dust. */ + + char *desc = 0; + + mach_port_deallocate (mach_task_self (), child_task); + child_task = MACH_PORT_NULL; + child_pid = -1; + + if (WIFSIGNALED (status)) + asprintf (&desc, "terminated abnormally (%s)", + strsignal (WTERMSIG (status))); + else if (WIFSTOPPED (status)) + asprintf (&desc, "stopped abnormally (%s)", + strsignal (WTERMSIG (status))); + else if (WEXITSTATUS (status) == 0) + desc = strdup ("finished"); + else + asprintf (&desc, "exited with status %d", + WEXITSTATUS (status)); + + { + char buf[40]; + snprintf (buf, sizeof buf, "%d", status); + setenv ("STATUS", buf, 1); + } + + launch_something (desc); + } + } + } + else + { + /* Pass the signal on to the child. */ + task_t task; + error_t err; + + err = proc_pid2task (procserver, child_pid, &task); + if (err) + { + error (0, err, "proc_pid2task on %d", child_pid); + task = child_task; + } + else + { + mach_port_deallocate (mach_task_self (), child_task); + child_task = task; + } + + if (signo == SIGKILL) + { + err = task_terminate (task); + if (err != MACH_SEND_INVALID_DEST) + error (0, err, "task_terminate"); + } + else + { + mach_port_t msgport; + err = proc_getmsgport (procserver, child_pid, &msgport); + if (err) + error (0, err, "proc_getmsgport"); + else + { + err = send_signal (msgport, signo, task); /* Avoids blocking. */ + mach_port_deallocate (mach_task_self (), msgport); + if (err) + { + error (0, err, "cannot send %s to child %d", + strsignal (signo), child_pid); + err = task_terminate (task); + if (err != MACH_SEND_INVALID_DEST) + error (0, err, "task_terminate"); + } + } + } + } +} + +/* Start the child program PROG. It is run via /libexec/console-run, + and we pass it no arguments to pass on to PROG. */ +static int +start_child (const char *prog) +{ + file_t file; + error_t err; + char *args; + size_t arglen; + const char *argv[] = { "/libexec/console-run", prog, 0 }; + + err = argz_create ((char **) argv, &args, &arglen); + assert_perror (err); + + file = file_name_lookup (args, O_EXEC, 0); + if (!file) + { + error (0, errno, "%s", args); + free (args); + return -1; + } + + task_create (mach_task_self (), 0, &child_task); + proc_child (procserver, child_task); + proc_task2pid (procserver, child_task, &child_pid); + proc_task2proc (procserver, child_task, &default_ports[INIT_PORT_PROC]); + + if (bootstrap_args & RB_KDB) + { + printf ("Pausing for %s\n", args); + getchar (); + } + + err = file_exec (file, child_task, 0, + args, arglen, + startup_envz, startup_envz_len, + NULL, MACH_MSG_TYPE_COPY_SEND, 0, /* No fds. */ + default_ports, MACH_MSG_TYPE_COPY_SEND, INIT_PORT_MAX, + default_ints, INIT_INT_MAX, + NULL, 0, NULL, 0); + mach_port_deallocate (mach_task_self (), default_ports[INIT_PORT_PROC]); + mach_port_deallocate (mach_task_self (), file); + free (args); + if (err) + { + error (0, err, "Cannot execute %s", args); + free (args); + return -1; + } + + return 0; +} + +static void +launch_something (const char *why) +{ + static unsigned int try; + static const char *const tries[] = + { + "/libexec/runsystem", + _PATH_BSHELL, + "/bin/shd", /* XXX */ + }; + + if (why) + error (0, 0, "%s %s", tries[try - 1], why); + + while (try < sizeof tries / sizeof tries[0]) + if (start_child (tries[try++]) == 0) + return; + + crash_system (); +} + +void +launch_system (void) +{ + launch_something (0); +} + + +#else + +/** Single and multi user transitions **/ + +/* Current state of the system. */ +enum +{ + INITIAL, + SINGLE, + RUNCOM, + MULTI, +} system_state; + +pid_t shell_pid; /* PID of single-user shell. */ +pid_t rc_pid; /* PID of rc script */ + + +#include "ttys.h" + + +/* 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; + + printf ("Single-user environment:"); + fflush (stdout); + + term = open_console (); + + 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); +} + +/* 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; + + 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); + free (rcargs); + mach_port_deallocate (mach_task_self (), term); + return ! rc_pid; +} + +/* Start up multi-user state. */ +void +launch_multi_user () +{ + int fail; + + if (!mapped_time) + maptime_map (1, 0, &mapped_time); + + fail = init_ttys (); + if (fail) + launch_single_user (); + else + { + system_state = MULTI; + fail = startup_ttys (); + if (fail) + launch_single_user (); + } +} + +void +launch_system () +{ + if (bootstrap_args & RB_SINGLE) + launch_single_user (); + else + { + if (process_rc_script ()) + launch_single_user (); + } +} + + +/* 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; + + for (nloops = 10; nloops; nloops--) + { + if (nloops < 9) + /* Give it a rest for folks to have a chance to die */ + sleep (1); + + didany = 0; + err = proc_getallpids (procserver, &pids, &npids); + if (!err) + { + for (i = 0; i < npids; i++) + { + if (pids[i] == 1 /* us */ + || pids[i] == 3 /* default pager for now XXX */) + continue; + + /* See if the task is essential */ + err = proc_pid2task (procserver, pids[i], &tk); + 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); + break; + } + if (es) + 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); + } + } + } + if (pids != pidbuf) + munmap (pids, npids * sizeof (pid_t)); + if (!didany) + return 1; + } + return 0; +} + +/* Kill outstanding multi-user sessions */ +void +kill_multi_user () +{ + 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 -AlM' advised"); +} + +/* SIGNO has arrived and has been validated. Do whatever work it + implies. */ +void +process_signal (int signo) +{ + int fail; + + switch (signo) + { + 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: + { + /* A child died. Find its status. */ + int status; + pid_t pid; + + for (;;) + { + pid = waitpid (WAIT_ANY, &status, WNOHANG | WUNTRACED); + if (pid <= 0) + return; + + 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; + } +} + +#endif /* SPLIT_INIT */ + +/** RPC servers **/ + +kern_return_t +S_startup_procinit (startup_t server, + mach_port_t reply, + mach_msg_type_name_t reply_porttype, + process_t proc, + mach_port_t *startuptask, + auth_t *auth, + mach_port_t *priv, + mach_msg_type_name_t *hostprivtype, + mach_port_t *dev, + mach_msg_type_name_t *devtype) +{ + if (procserver) + /* Only one proc server. */ + return EPERM; + + procserver = proc; + + procreply = reply; + procreplytype = reply_porttype; + + /* Save the reply port until we get startup_authinit. */ + if (authserver) + launch_core_servers (); + + return MIG_NO_REPLY; +} + +/* Called by the auth server when it starts up. */ + +kern_return_t +S_startup_authinit (startup_t server, + mach_port_t reply, + mach_msg_type_name_t reply_porttype, + mach_port_t auth, + mach_port_t *proc, + mach_msg_type_name_t *proctype) +{ + if (authserver) + /* Only one auth server. */ + return EPERM; + + authserver = auth; + + /* Save the reply port until we get startup_procinit. */ + authreply = reply; + authreplytype = reply_porttype; + + if (procserver) + launch_core_servers (); + + return MIG_NO_REPLY; +} + + +kern_return_t +S_startup_essential_task (mach_port_t server, + mach_port_t reply, + mach_msg_type_name_t replytype, + task_t task, + mach_port_t excpt, + char *name, + mach_port_t credential) +{ + static int authinit, procinit, execinit; + int fail; + + if (credential != host_priv) + return EPERM; + + fail = record_essential_task (name, task); + if (fail) + return fail; + + mach_port_deallocate (mach_task_self (), credential); + + if (!booted) + { + if (!strcmp (name, "auth")) + authinit = 1; + else if (!strcmp (name, "exec")) + execinit = 1; + else if (!strcmp (name, "proc")) + procinit = 1; + + if (authinit && execinit && procinit) + { + /* Reply to this RPC, after that everything + is ready for real startup to begin. */ + startup_essential_task_reply (reply, replytype, 0); + + init_stdarrays (); + frob_kernel_process (); + + launch_system (); + + booted = 1; + + return MIG_NO_REPLY; + } + } + + return 0; +} + +kern_return_t +S_startup_request_notification (mach_port_t server, + mach_port_t notify, + char *name) +{ + struct ntfy_task *nt; + + request_dead_name (notify); + + /* 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)); + nt->notify_port = notify; + nt->next = ntfy_tasks; + ntfy_tasks = nt; + nt->name = malloc (strlen (name) + 1); + strcpy (nt->name, name); + return 0; +} + +kern_return_t +do_mach_notify_dead_name (mach_port_t notify, + mach_port_t name) +{ + 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. */ + { + error (0, 0, "Crashing system; essential task %s died", et->name); + crash_system (); + } + + for (nt = ntfy_tasks, pnt = NULL; nt != NULL; pnt = nt, nt = nt->next) + if (nt->notify_port == name) + { + /* Someone who wanted to be notified is gone. */ + mach_port_deallocate (mach_task_self (), name); + if (pnt != NULL) + pnt->next = nt->next; + 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 %#x)", name); + crash_mach (); + } + + return 0; +} + +kern_return_t +S_startup_reboot (mach_port_t server, + mach_port_t refpt, + int code) +{ + if (refpt != host_priv) + return EPERM; + + reboot_system (code); + for (;;); +} + +/* Stubs for unused notification RPCs. */ + +kern_return_t +do_mach_notify_port_destroyed (mach_port_t notify, + mach_port_t rights) +{ + return EOPNOTSUPP; +} + +kern_return_t +do_mach_notify_send_once (mach_port_t notify) +{ + return EOPNOTSUPP; +} + +kern_return_t +do_mach_notify_no_senders (mach_port_t port, mach_port_mscount_t mscount) +{ + return EOPNOTSUPP; +} + +kern_return_t +do_mach_notify_port_deleted (mach_port_t notify, + mach_port_t name) +{ + return EOPNOTSUPP; +} + +kern_return_t +do_mach_notify_msg_accepted (mach_port_t notify, + mach_port_t name) +{ + return EOPNOTSUPP; +} + +/* msg server */ + +kern_return_t +S_msg_sig_post_untraced (mach_port_t msgport, + mach_port_t reply, mach_msg_type_name_t reply_type, + int signo, natural_t sigcode, mach_port_t refport) +{ + if (refport != mach_task_self ()) + return EPERM; + mach_port_deallocate (mach_task_self (), refport); + + /* Reply immediately */ + msg_sig_post_untraced_reply (reply, reply_type, 0); + + process_signal (signo); + return MIG_NO_REPLY; +} + +kern_return_t +S_msg_sig_post (mach_port_t msgport, + mach_port_t reply, mach_msg_type_name_t reply_type, + int signo, natural_t sigcode, mach_port_t refport) +{ + 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; +} + + +/* For the rest of the msg functions, just call the C library's + internal server stubs usually run in the signal thread. */ + +kern_return_t +S_msg_proc_newids (mach_port_t process, + mach_port_t task, + pid_t ppid, + pid_t pgrp, + int orphaned) +{ return _S_msg_proc_newids (process, task, ppid, pgrp, orphaned); } + + +kern_return_t +S_msg_add_auth (mach_port_t process, + auth_t auth) +{ return _S_msg_add_auth (process, auth); } + + +kern_return_t +S_msg_del_auth (mach_port_t process, + mach_port_t task, + intarray_t uids, + mach_msg_type_number_t uidsCnt, + intarray_t gids, + mach_msg_type_number_t gidsCnt) +{ return _S_msg_del_auth (process, task, uids, uidsCnt, gids, gidsCnt); } + + +kern_return_t +S_msg_get_init_port (mach_port_t process, + mach_port_t refport, + int which, + mach_port_t *port, + mach_msg_type_name_t *portPoly) +{ return _S_msg_get_init_port (process, refport, which, port, portPoly); } + + +kern_return_t +S_msg_set_init_port (mach_port_t process, + mach_port_t refport, + int which, + mach_port_t port) +{ return _S_msg_set_init_port (process, refport, which, port); } + + +kern_return_t +S_msg_get_init_ports (mach_port_t process, + mach_port_t refport, + portarray_t *ports, + mach_msg_type_name_t *portsPoly, + mach_msg_type_number_t *portsCnt) +{ return _S_msg_get_init_ports (process, refport, ports, portsPoly, portsCnt); } + + +kern_return_t +S_msg_set_init_ports (mach_port_t process, + mach_port_t refport, + portarray_t ports, + mach_msg_type_number_t portsCnt) +{ return _S_msg_set_init_ports (process, refport, ports, portsCnt); } + + +kern_return_t +S_msg_get_init_int (mach_port_t process, + mach_port_t refport, + int which, + int *value) +{ return _S_msg_get_init_int (process, refport, which, value); } + + +kern_return_t +S_msg_set_init_int (mach_port_t process, + mach_port_t refport, + int which, + int value) +{ return _S_msg_set_init_int (process, refport, which, value); } + + +kern_return_t +S_msg_get_init_ints (mach_port_t process, + mach_port_t refport, + intarray_t *values, + mach_msg_type_number_t *valuesCnt) +{ return _S_msg_get_init_ints (process, refport, values, valuesCnt); } + + +kern_return_t +S_msg_set_init_ints (mach_port_t process, + mach_port_t refport, + intarray_t values, + mach_msg_type_number_t valuesCnt) +{ return _S_msg_set_init_ints (process, refport, values, valuesCnt); } + + +kern_return_t +S_msg_get_dtable (mach_port_t process, + mach_port_t refport, + portarray_t *dtable, + mach_msg_type_name_t *dtablePoly, + mach_msg_type_number_t *dtableCnt) +{ return _S_msg_get_dtable (process, refport, dtable, dtablePoly, dtableCnt); } + + +kern_return_t +S_msg_set_dtable (mach_port_t process, + mach_port_t refport, + portarray_t dtable, + mach_msg_type_number_t dtableCnt) +{ return _S_msg_set_dtable (process, refport, dtable, dtableCnt); } + + +kern_return_t +S_msg_get_fd (mach_port_t process, + mach_port_t refport, + int fd, + mach_port_t *port, + mach_msg_type_name_t *portPoly) +{ return _S_msg_get_fd (process, refport, fd, port, portPoly); } + + +kern_return_t +S_msg_set_fd (mach_port_t process, + mach_port_t refport, + int fd, + mach_port_t port) +{ return _S_msg_set_fd (process, refport, fd, port); } + + +kern_return_t +S_msg_get_environment (mach_port_t process, + data_t *value, + mach_msg_type_number_t *valueCnt) +{ return _S_msg_get_environment (process, value, valueCnt); } + + +kern_return_t +S_msg_set_environment (mach_port_t process, + mach_port_t refport, + data_t value, + mach_msg_type_number_t valueCnt) +{ return _S_msg_set_environment (process, refport, value, valueCnt); } + + +kern_return_t +S_msg_get_env_variable (mach_port_t process, + string_t variable, + data_t *value, + mach_msg_type_number_t *valueCnt) +{ return _S_msg_get_env_variable (process, variable, value, valueCnt); } + + +kern_return_t +S_msg_set_env_variable (mach_port_t process, + mach_port_t refport, + string_t variable, + string_t value, + boolean_t replace) +{ return _S_msg_set_env_variable (process, refport, variable, value, replace); } + +error_t +S_msg_describe_ports (mach_port_t process, + mach_port_t refport, + mach_port_array_t names, + mach_msg_type_number_t namesCnt, + data_t *descriptions, + mach_msg_type_number_t *descriptionsCnt) +{ + 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) +{ + *desc = 0; + *rpc = 0; + return 0; +} diff --git a/init/stubs.c b/init/stubs.c new file mode 100644 index 00000000..fd803f97 --- /dev/null +++ b/init/stubs.c @@ -0,0 +1,106 @@ +/* By-hand stubs for some RPC calls + Copyright (C) 1994, 1996, 1999 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include <stdlib.h> +#include <hurd/hurd_types.h> +#include <mach/message.h> +#include <string.h> + +/* From hurd/msg.defs: */ +#define RPCID_SIG_POST 23000 + + +/* Send signal SIGNO to MSGPORT with REFPORT as reference. Don't + block in any fashion. */ +error_t +send_signal (mach_port_t msgport, + int signal, + mach_port_t refport) +{ + error_t err; + + static struct + { + mach_msg_header_t head; + mach_msg_type_t signaltype; + int signal; + mach_msg_type_t sigcode_type; + natural_t sigcode; + mach_msg_type_t refporttype; + mach_port_t refport; + } + message = + { + { + /* Message header: */ + (MACH_MSGH_BITS_COMPLEX + | MACH_MSGH_BITS (MACH_MSG_TYPE_COPY_SEND, + MACH_MSG_TYPE_MAKE_SEND_ONCE)), /* msgh_bits */ + sizeof message, /* msgh_size */ + 0, /* msgh_remote_port */ + MACH_PORT_NULL, /* msgh_local_port */ + 0, /* msgh_seqno */ + RPCID_SIG_POST, /* msgh_id */ + }, + { + /* Type descriptor for signo */ + MACH_MSG_TYPE_INTEGER_32, /* msgt_name */ + 32, /* msgt_size */ + 1, /* msgt_number */ + 1, /* msgt_inline */ + 0, /* msgt_longform */ + 0, /* msgt_deallocate */ + 0, /* msgt_unused */ + }, + /* Signal number */ + 0, + /* Type descriptor for sigcode */ + { + MACH_MSG_TYPE_INTEGER_32, /* msgt_name */ + 32, /* msgt_size */ + 1, /* msgt_number */ + 1, /* msgt_inline */ + 0, /* msgt_longform */ + 0, /* msgt_deallocate */ + 0, /* msgt_unused */ + }, + /* Sigcode */ + 0, + { + /* Type descriptor for refport */ + MACH_MSG_TYPE_COPY_SEND, /* msgt_name */ + 32, /* msgt_size */ + 1, /* msgt_number */ + 1, /* msgt_inline */ + 0, /* msgt_longform */ + 0, /* msgt_deallocate */ + 0, /* msgt_unused */ + }, + /* Reference port */ + MACH_PORT_NULL, + }; + + message.head.msgh_remote_port = msgport; + message.signal = signal; + message.refport = refport; + + err = mach_msg((mach_msg_header_t *)&message, + MACH_SEND_MSG|MACH_SEND_TIMEOUT, sizeof message, 0, + MACH_PORT_NULL, 0, MACH_PORT_NULL); + + return err; +} diff --git a/init/ttys.c b/init/ttys.c new file mode 100644 index 00000000..fa612e55 --- /dev/null +++ b/init/ttys.c @@ -0,0 +1,321 @@ +/* /etc/ttys support for Hurd init + Copyright (C) 1993,94,95,96,97,98,99 Free Software Foundation, Inc. + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + The GNU Hurd is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the GNU Hurd; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include <sys/types.h> +#include <errno.h> +#include <stdio.h> +#include <signal.h> +#include <unistd.h> +#include <string.h> +#include <argz.h> +#include <hurd.h> +#include <error.h> +#include <assert.h> +#include <ttyent.h> +#include <utmp.h> + +#include "ttys.h" + + +extern pid_t run_for_real (char *filename, char *args, int arglen, + mach_port_t ctty, int setsid); /* init.c */ + + +/* How long to wait after starting window specs before starting getty */ +#define WINDOW_DELAY 3 /* seconds */ + +#define _PATH_LOGIN "/bin/login" + + +/* 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; + pid_t pid; + int read; + + char *name; +}; + +static struct terminal *ttys; +/* Number of live elements in ttys */ +static int nttys; +/* Total number of elements in ttys */ +static int ttyslen; + + +/* Set up the getty and window fields of terminal spec T corresponding + to line TT. */ +static void +setup_terminal (struct terminal *t, struct ttyent *tt) +{ + char *line; + + 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); + free (line); + if (tt->ty_window) + argz_create_sep (tt->ty_window, ' ', + &t->window_argz, &t->window_argz_len); + else + t->window_argz = 0; + } + else + t->getty_argz = t->window_argz = 0; +} + + +/* Add a new terminal spec for TT and return it. */ +static struct terminal * +add_terminal (struct ttyent *tt) +{ + struct terminal *t; + + 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); + + setup_terminal (t, tt); + if (t->getty_argz) + t->on = 1; + + 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. */ +static 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. */ +static 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 (pid_t 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]); + } +} + +/* Shutdown the things running on terminal spec T. */ +static void +shutdown_terminal (struct terminal *t) +{ + kill (t->pid, SIGHUP); + revoke (t->name); +} + +/* Re-read /etc/ttys. If a line has turned off, kill what's there. + If a line has turned on, start it. */ +void +reread_ttys (void) +{ + struct ttyent *tt; + struct terminal *t; + int on; + int i; + + if (!setttyent ()) + { + error (0, errno, "%s", _PATH_TTYS); + return; + } + + /* Mark all the lines not yet read */ + for (i = 0; i < nttys; i++) + ttys[i].read = 0; + + 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; + shutdown_terminal (t); + } + else if (!t->on && on) + { + t->on = 1; + setup_terminal (t, tt); + startup_terminal (t); + } + } + else + { + t = add_terminal (tt); + if (on) + startup_terminal (t); + } + + t->read = 1; + } + endttyent (); + + /* Scan tty entries; any that were not found and were on, turn off. */ + for (i = 0; i < nttys; i++) + if (!ttys[i].read && ttys[i].on) + { + ttys[i].on = 0; + shutdown_terminal (&ttys[i]); + } +} diff --git a/init/ttys.h b/init/ttys.h new file mode 100644 index 00000000..db59f16d --- /dev/null +++ b/init/ttys.h @@ -0,0 +1,22 @@ +/* Declarations for /etc/ttys support for Hurd init + Copyright (C) 1999 Free Software Foundation, Inc. + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + The GNU Hurd is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the GNU Hurd; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +int init_ttys (), startup_ttys (); +void reread_ttys (), free_ttys (); + +void restart_terminal (pid_t pid); |