diff options
author | Roland McGrath <roland@gnu.org> | 1998-12-27 08:41:15 +0000 |
---|---|---|
committer | Roland McGrath <roland@gnu.org> | 1998-12-27 08:41:15 +0000 |
commit | acb030991c07ad33a8d55ff19e493cc26a3ea6a6 (patch) | |
tree | 68312059ccd49b5c42927d19825bba3d90e48fd9 | |
parent | 2c026d41553528d0fdb0fe795b99ddd6c5e68b74 (diff) |
1998-12-27 Roland McGrath <roland@baalperazim.frob.com>
* opts-std-startup.c (startup_options): Move -C above "Boot options:",
give it a docstring. Docstrings for --bootflags, --boot-command.
(_diskfs_boot_command): New variable.
(startup_options, parse_startup_opt): New option --boot-command,
consumes remaining args to set _diskfs_boot_command.
* priv.h: Declare _diskfs_boot_command.
* boot-start.c (diskfs_start_bootstrap): If diskfs_exec_server_task is
null, assume we are running as the boot command and have a root with
/servers/exec.
If _diskfs_boot_command is set, start that command in place of init.
If can't lookup initname, print error msg and loop to prompt.
Put a newline before "Init name" prompt.
After starting exec server, try to set active trans on /servers/exec.
(diskfs_boot_getpriv): New function: if _hurd_host_priv
is null, use fsys_getpriv on our bootstrap port.
(parent_task): New static variable, set there with fsys_getpriv call.
(diskfs_S_fsys_init): If diskfs_exec_server_task is null, don't do
anything with it; instead register parent_task as our child
and send an fsys_init to our parent on our bootstrap port.
* console.c (diskfs_console_stdio): Call diskfs_boot_privports before
get_privileged_ports if diskfs_boot_flags is set.
-rw-r--r-- | libdiskfs/boot-start.c | 310 | ||||
-rw-r--r-- | libdiskfs/console.c | 6 | ||||
-rw-r--r-- | libdiskfs/opts-std-startup.c | 29 | ||||
-rw-r--r-- | libdiskfs/priv.h | 3 |
4 files changed, 262 insertions, 86 deletions
diff --git a/libdiskfs/boot-start.c b/libdiskfs/boot-start.c index 8a956b30..725addaa 100644 --- a/libdiskfs/boot-start.c +++ b/libdiskfs/boot-start.c @@ -30,12 +30,15 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <device/device.h> #include <sys/reboot.h> #include <string.h> +#include <argz.h> +#include <error.h> #include "fsys_S.h" #include "fsys_reply_U.h" -mach_port_t diskfs_exec_ctl; -mach_port_t diskfs_exec; +static mach_port_t diskfs_exec_ctl; +mach_port_t diskfs_exec = MACH_PORT_NULL; extern task_t diskfs_exec_server_task; +static task_t parent_task = MACH_PORT_NULL; static struct mutex execstartlock; static struct condition execstarted; @@ -62,6 +65,25 @@ get_console () return console; } +/* Make sure we have the privileged ports. */ +void +diskfs_boot_privports (void) +{ + assert (diskfs_boot_flags); + if (_hurd_host_priv == MACH_PORT_NULL) + { + /* We are the boot command run by the real bootstrap filesystem. + We get the privileged ports from it as init would. */ + mach_port_t bootstrap; + error_t err = task_get_bootstrap_port (mach_task_self (), &bootstrap); + assert_perror (err); + err = fsys_getpriv (bootstrap, &_hurd_host_priv, &_hurd_device_master, + &parent_task); + mach_port_deallocate (mach_task_self (), bootstrap); + assert_perror (err); + } +} + /* Once diskfs_root_node is set, call this if we are a bootstrap filesystem. */ void @@ -71,29 +93,15 @@ diskfs_start_bootstrap () retry_type retry; char pathbuf[1024]; string_t retry_name; - uid_t idlist[] = {0, 0, 0}; mach_port_t portarray[INIT_PORT_MAX]; mach_port_t fdarray[3]; /* XXX */ task_t newt; error_t err; - char *initname, *initnamebuf; - char *exec_argv; - int exec_argvlen; + char *exec_argv, *initname; + size_t exec_argvlen; struct port_info *bootinfo; struct protid *rootpi; - printf ("Hurd server bootstrap: %s", program_invocation_short_name); - fflush (stdout); - - /* Get the execserver going and wait for its fsys_startup */ - mutex_init (&execstartlock); - condition_init (&execstarted); - mutex_lock (&execstartlock); - start_execserver (); - condition_wait (&execstarted, &execstartlock); - mutex_unlock (&execstartlock); - assert (diskfs_exec_ctl); - /* Create the port for current and root directory. */ err = diskfs_create_protid (diskfs_make_peropen (diskfs_root_node, O_READ | O_EXEC, 0), @@ -107,49 +115,144 @@ diskfs_start_bootstrap () ports_port_deref (rootpi); - /* Contact the exec server. */ - err = fsys_getroot (diskfs_exec_ctl, root_pt, MACH_MSG_TYPE_COPY_SEND, - idlist, 3, idlist, 3, 0, - &retry, retry_name, &diskfs_exec); - assert_perror (err); - assert (retry == FS_RETRY_NORMAL); - assert (retry_name[0] == '\0'); - assert (diskfs_exec); - + if (diskfs_exec_server_task == MACH_PORT_NULL) + { + /* We are the boot command run by the real bootstrap filesystem. + Our parent (the real bootstrap filesystem) provides us a root + directory where we look up /servers/exec like any non-bootstrap + filesystem would. */ + assert (_hurd_ports); + assert (_hurd_ports[INIT_PORT_CRDIR].port != MACH_PORT_NULL); + diskfs_exec = file_name_lookup (_SERVERS_EXEC, 0, 0); + if (diskfs_exec == MACH_PORT_NULL) + error (1, errno, "%s", _SERVERS_EXEC); + else + { +#ifndef NDEBUG + /* Make sure this is really a port to another server. */ + struct port_info *pi = ports_lookup_port (diskfs_port_bucket, + diskfs_exec, 0); + assert (!pi); +#endif + } - /* Execute the startup server. */ - initnamebuf = NULL; - initname = default_init; - if (index (diskfs_boot_flags, 'i')) + /* Here we assume the parent has already printed: + Hurd server bootstrap: bootfs exec ourfs + */ + printf ("[re-bootstrap]:"); + fflush (stdout); + } + else { - size_t bufsz; - ssize_t len; - printf ("Init name [%s]: ", default_init); - bufsz = 0; - switch (len = getline (&initnamebuf, &bufsz, stdin)) + uid_t idlist[] = {0, 0, 0}; + file_t execnode; + + printf ("Hurd server bootstrap: %s", program_invocation_short_name); + fflush (stdout); + + /* Get the execserver going and wait for its fsys_startup */ + mutex_init (&execstartlock); + condition_init (&execstarted); + mutex_lock (&execstartlock); + start_execserver (); + condition_wait (&execstarted, &execstartlock); + mutex_unlock (&execstartlock); + assert (diskfs_exec_ctl != MACH_PORT_NULL); + + /* Contact the exec server. */ + err = fsys_getroot (diskfs_exec_ctl, root_pt, MACH_MSG_TYPE_COPY_SEND, + idlist, 3, idlist, 3, 0, + &retry, retry_name, &diskfs_exec); + assert_perror (err); + assert (retry == FS_RETRY_NORMAL); + assert (retry_name[0] == '\0'); + assert (diskfs_exec != MACH_PORT_NULL); + + /* Attempt to set the active translator for the exec server so that + filesystems other than the bootstrap can find it. */ + err = dir_lookup (root_pt, _SERVERS_EXEC, O_NOTRANS, 0, + &retry, pathbuf, &execnode); + if (err) { - case -1: - perror ("getline"); - printf ("Using default of `%s'.\n", initname); - case 0: /* Hmm. */ - case 1: /* Empty line, just a newline. */ - /* Use default. */ - break; - default: - initnamebuf[len - 1] = '\0'; /* Remove the newline. */ - initname = initnamebuf; - while (*initname == '/') - initname++; - break; + error (0, err, "cannot set translator on %s", _SERVERS_EXEC); + mach_port_deallocate (mach_task_self (), diskfs_exec_ctl); } + else + { + assert (retry == FS_RETRY_NORMAL); + assert (retry_name[0] == '\0'); + assert (execnode != MACH_PORT_NULL); + err = file_set_translator (execnode, 0, FS_TRANS_SET, 0, 0, 0, + diskfs_exec_ctl, MACH_MSG_TYPE_MOVE_SEND); + mach_port_deallocate (mach_task_self (), execnode); + assert_perror (err); + } + diskfs_exec_ctl = MACH_PORT_NULL; /* Not used after this. */ + } + + if (_diskfs_boot_command) + { + /* We have a boot command line to run instead of init. */ + err = argz_create (_diskfs_boot_command, &exec_argv, &exec_argvlen); + assert_perror (err); + initname = exec_argv; + while (*initname == '/') + initname++; } else - initname = default_init; + { + /* Choose the name of the startup server to execute. */ + char *initnamebuf; + if (index (diskfs_boot_flags, 'i')) + { + size_t bufsz; + ssize_t len; + initname = default_init; + prompt: + initnamebuf = NULL; + printf ("\nInit name [%s]: ", initname); + fflush (stdout); + bufsz = 0; + switch (len = getline (&initnamebuf, &bufsz, stdin)) + { + case -1: + perror ("getline"); + printf ("Using default of `%s'.\n", initname); + case 0: /* Hmm. */ + case 1: /* Empty line, just a newline. */ + /* Use default. */ + break; + default: + initnamebuf[len - 1] = '\0'; /* Remove the newline. */ + initname = initnamebuf; + while (*initname == '/') + initname++; + break; + } + } + else + { + initname = default_init; + initnamebuf = NULL; + } + + exec_argvlen = asprintf (&exec_argv, "/%s%c%s%c", + initname, '\0', diskfs_boot_flags, '\0'); + if (initname != default_init) + free (initnamebuf); + initname = exec_argv + 1; + } err = dir_lookup (root_pt, initname, O_READ, 0, &retry, pathbuf, &startup_pt); - - assert_perror (err); + if (err) + { + printf ("\nCannot find startup program `%s': %s\n", + initname, strerror (err)); + fflush (stdout); + free (exec_argv); + goto prompt; + } assert (retry == FS_RETRY_NORMAL); assert (pathbuf[0] == '\0'); @@ -170,17 +273,14 @@ diskfs_start_bootstrap () fdarray[0] = fdarray[1] = fdarray[2] = get_console (); /* XXX */ - exec_argvlen = - asprintf (&exec_argv, "%s%c%s%c", initname, '\0', diskfs_boot_flags, '\0'); - err = task_create (mach_task_self (), 0, &newt); assert_perror (err); if (index (diskfs_boot_flags, 'd')) { - printf ("pausing for init...\n"); + printf ("pausing for %s...\n", exec_argv); getc (stdin); } - printf (" init"); + printf (" %s", basename (exec_argv)); fflush (stdout); err = exec_exec (diskfs_exec, startup_pt, MACH_MSG_TYPE_COPY_SEND, newt, 0, exec_argv, exec_argvlen, 0, 0, @@ -193,8 +293,6 @@ diskfs_start_bootstrap () mach_port_deallocate (mach_task_self (), root_pt); mach_port_deallocate (mach_task_self (), startup_pt); mach_port_deallocate (mach_task_self (), bootpt); - if (initnamebuf != default_init) - free (initnamebuf); assert_perror (err); } @@ -362,7 +460,6 @@ diskfs_S_fsys_init (mach_port_t port, { struct port_infe *pt; static int initdone = 0; - process_t execprocess; mach_port_t host, startup; error_t err; mach_port_t root_pt; @@ -380,9 +477,12 @@ diskfs_S_fsys_init (mach_port_t port, anything which might attempt to send an RPC to init. */ fsys_init_reply (reply, replytype, 0); - /* Allocate our reference here; _hurd_init will consume a reference + /* Allocate our references here; _hurd_init will consume a reference for the library itself. */ err = mach_port_mod_refs (mach_task_self (), + procserver, MACH_PORT_RIGHT_SEND, +1); + assert_perror (err); + err = mach_port_mod_refs (mach_task_self (), authhandle, MACH_PORT_RIGHT_SEND, +1); assert_perror (err); @@ -390,22 +490,74 @@ diskfs_S_fsys_init (mach_port_t port, mach_port_deallocate (mach_task_self (), diskfs_auth_server_port); diskfs_auth_server_port = authhandle; - assert (diskfs_exec_server_task != MACH_PORT_NULL); - err = proc_task2proc (procserver, diskfs_exec_server_task, &execprocess); - assert_perror (err); - - /* Declare that the exec server is our child. */ - proc_child (procserver, diskfs_exec_server_task); - proc_mark_exec (execprocess); - - /* Don't start this until now so that exec is fully authenticated - with proc. */ - exec_init (diskfs_exec, authhandle, execprocess, MACH_MSG_TYPE_COPY_SEND); - mach_port_deallocate (mach_task_self (), execprocess); - - /* We don't need this anymore. */ - mach_port_deallocate (mach_task_self (), diskfs_exec_server_task); - diskfs_exec_server_task = MACH_PORT_NULL; + if (diskfs_exec_server_task != MACH_PORT_NULL) + { + process_t execprocess; + err = proc_task2proc (procserver, diskfs_exec_server_task, &execprocess); + assert_perror (err); + + /* Declare that the exec server is our child. */ + proc_child (procserver, diskfs_exec_server_task); + proc_mark_exec (execprocess); + + /* Don't start this until now so that exec is fully authenticated + with proc. */ + exec_init (diskfs_exec, authhandle, + execprocess, MACH_MSG_TYPE_COPY_SEND); + mach_port_deallocate (mach_task_self (), execprocess); + + /* We don't need this anymore. */ + mach_port_deallocate (mach_task_self (), diskfs_exec_server_task); + diskfs_exec_server_task = MACH_PORT_NULL; + } + else + { + mach_port_t bootstrap; + process_t parent_proc; + + assert (parent_task != MACH_PORT_NULL); + + /* Tell the proc server that our parent task is our child. This + makes the process hierarchy fail to represent the real order of + who created whom, but it sets the owner and authentication ids to + root. It doesn't really matter that the parent fs task be + authenticated, but the exec server needs to be authenticated to + complete the boot handshakes with init. The exec server gets its + privilege by the parent fs doing proc_child (code above) after + we send it fsys_init (below). */ + + err = proc_child (procserver, parent_task); + assert_perror (err); + + /* Get the parent's proc server port so we can send it in the fsys_init + RPC just as init would. */ + err = proc_task2proc (procserver, parent_task, &parent_proc); + assert_perror (err); + { + pid_t pid; + err = proc_task2pid (procserver, parent_task, &pid); + assert_perror (err); + printf("BOOT parent pid %d\n",pid); + err = proc_task2pid (procserver, mach_task_self(), &pid); + assert_perror (err); + printf("BOOT our pid %d\n",pid); + } + + /* We don't need this anymore. */ + mach_port_deallocate (mach_task_self (), parent_task); + parent_task = MACH_PORT_NULL; + + proc_mark_exec (parent_proc); + + /* Give our parent (the real bootstrap filesystem) an fsys_init + RPC of its own, as init would have sent it. */ + err = task_get_bootstrap_port (mach_task_self (), &bootstrap); + assert_perror (err); + err = fsys_init (bootstrap, parent_proc, MACH_MSG_TYPE_MOVE_SEND, + authhandle); + mach_port_deallocate (mach_task_self (), bootstrap); + assert_perror (err); + } /* Get a port to the root directory to put in the library's data structures. */ @@ -458,7 +610,7 @@ diskfs_S_fsys_init (mach_port_t port, if (err) return err; - proc_register_version (procserver, host, diskfs_server_name, "", + proc_register_version (procserver, host, diskfs_server_name, "", diskfs_server_version); err = proc_getmsgport (procserver, 1, &startup); @@ -470,6 +622,7 @@ diskfs_S_fsys_init (mach_port_t port, } mach_port_deallocate (mach_task_self (), host); + mach_port_deallocate (mach_task_self (), procserver); _diskfs_init_completed (); @@ -507,4 +660,3 @@ start_execserver (void) printf (" exec"); fflush (stdout); } - diff --git a/libdiskfs/console.c b/libdiskfs/console.c index 885f527e..8271b799 100644 --- a/libdiskfs/console.c +++ b/libdiskfs/console.c @@ -1,6 +1,6 @@ /* Redirect stdio to the console if possible - Copyright (C) 1995, 1996 Free Software Foundation, Inc. + Copyright (C) 1995, 96, 98 Free Software Foundation, Inc. Written by Miles Bader <miles@gnu.ai.mit.edu> @@ -31,6 +31,8 @@ #include <device/device.h> #include <hurd.h> +#include "priv.h" + /* Make errors go somewhere reasonable. */ void diskfs_console_stdio () @@ -49,6 +51,8 @@ diskfs_console_stdio () { mach_port_t dev, cons; error_t err; + if (diskfs_boot_flags) + diskfs_boot_privports (); err = get_privileged_ports (NULL, &dev); assert_perror (err); err = device_open (dev, D_READ|D_WRITE, "console", &cons); diff --git a/libdiskfs/opts-std-startup.c b/libdiskfs/opts-std-startup.c index 14760ed7..e03c2722 100644 --- a/libdiskfs/opts-std-startup.c +++ b/libdiskfs/opts-std-startup.c @@ -1,6 +1,6 @@ /* Standard startup-time command line parser - Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc. + Copyright (C) 1995, 96, 97, 98 Free Software Foundation, Inc. Written by Miles Bader <miles@gnu.ai.mit.edu> @@ -25,7 +25,8 @@ #include <hurd/store.h> #include "priv.h" -char *diskfs_boot_flags = 0; +char *diskfs_boot_flags; +char **_diskfs_boot_command; extern char **diskfs_argv; @@ -37,18 +38,26 @@ mach_port_t diskfs_exec_server_task = MACH_PORT_NULL; #define OPT_DEVICE_MASTER_PORT (-2) #define OPT_EXEC_SERVER_TASK (-3) #define OPT_BOOTFLAGS (-4) +#define OPT_BOOT_COMMAND (-5) static const struct argp_option startup_options[] = { + {"directory", 'C', "DIRECTORY", 0, + "Use DIRECTORY as the root of the filesystem"}, + {"virtual-root", 0, 0, OPTION_ALIAS}, + {"chroot", 0, 0, OPTION_ALIAS}, + {0,0,0,0, "Boot options:", -2}, + {"bootflags", OPT_BOOTFLAGS, "FLAGS", 0, + "Required for bootstrap filesystem, the FLAGS" + " argument is passed on to init"}, + {"boot-command", OPT_BOOT_COMMAND, 0, 0, + "Remaining arguments form command line to run" + " at bootstrap instead of init"}, {"host-priv-port", OPT_HOST_PRIV_PORT, "PORT"}, {"device-master-port", OPT_DEVICE_MASTER_PORT, "PORT"}, {"exec-server-task", OPT_EXEC_SERVER_TASK, "PORT"}, - {"bootflags", OPT_BOOTFLAGS, "FLAGS"}, - {"directory", 'C', "DIRECTORY"}, - {"virtual-root", 0, 0, OPTION_ALIAS | OPTION_HIDDEN}, - {"chroot", 0, 0, OPTION_ALIAS | OPTION_HIDDEN}, {0} }; @@ -90,6 +99,14 @@ parse_startup_opt (int opt, char *arg, struct argp_state *state) case 'C': _diskfs_chroot_directory = arg; break; + case OPT_BOOT_COMMAND: + if (state->next == state->argc) + argp_error (state, "Command line must follow --boot-command option"); + _diskfs_boot_command = state->argv + state->next; + state->next = state->argc; /* stop parsing */ + {char **p; for (p = _diskfs_boot_command; *p; ++p) printf("BC %s\n",*p);} + break; + case ARGP_KEY_END: diskfs_argv = state->argv; break; diff --git a/libdiskfs/priv.h b/libdiskfs/priv.h index 5a90c2b8..b5c9b98d 100644 --- a/libdiskfs/priv.h +++ b/libdiskfs/priv.h @@ -33,6 +33,9 @@ extern int _diskfs_nosuid, _diskfs_noexec; /* This is the -C argument value. */ extern const char *_diskfs_chroot_directory; +/* If --boot-command is given, this points to the program and args. */ +extern char **_diskfs_boot_command; + volatile struct mapped_time_value *_diskfs_mtime; extern struct argp_option diskfs_common_options[]; |