diff options
Diffstat (limited to 'libdiskfs/boot-start.c')
-rw-r--r-- | libdiskfs/boot-start.c | 384 |
1 files changed, 260 insertions, 124 deletions
diff --git a/libdiskfs/boot-start.c b/libdiskfs/boot-start.c index 9c0e0f79..15563bdb 100644 --- a/libdiskfs/boot-start.c +++ b/libdiskfs/boot-start.c @@ -1,5 +1,6 @@ /* - Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation + Copyright (C) 1993,94,95,96,97,98,99,2000,01,02,10,11 + Free Software Foundation, Inc. This file is part of the GNU Hurd. @@ -30,17 +31,19 @@ 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; extern task_t diskfs_exec_server_task; +static task_t parent_task = MACH_PORT_NULL; static struct mutex execstartlock; static struct condition execstarted; -static char *default_init = "hurd/init"; +const char *diskfs_boot_init_program = _HURD_INIT; static void start_execserver (); @@ -62,6 +65,25 @@ get_console () return console; } +/* Make sure we have the privileged ports. */ +void +_diskfs_boot_privports (void) +{ + assert (diskfs_boot_filesystem ()); + 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,95 +93,164 @@ 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, *exec_env; + const char *initname; + size_t exec_argvlen, exec_envlen; 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); + struct peropen *rootpo; + mach_port_t diskfs_exec; + unsigned int init_lookups = 0; /* Create the port for current and root directory. */ - err = diskfs_create_protid (diskfs_make_peropen (diskfs_root_node, - O_READ | O_EXEC, - MACH_PORT_NULL), - 0,0,0,0, &rootpi); + err = diskfs_make_peropen (diskfs_root_node, O_READ | O_EXEC, 0, + &rootpo); assert_perror (err); - root_pt = ports_get_right (rootpi); - /* Get us a send right to copy around. */ - mach_port_insert_right (mach_task_self (), root_pt, root_pt, - MACH_MSG_TYPE_MAKE_SEND); + err = diskfs_create_protid (rootpo, 0, &rootpi); + assert_perror (err); + /* Get us a send right to copy around. */ + root_pt = ports_get_send_right (rootpi); 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[bootdev] exec ourfs + */ + printf ("\nContinuing on new root filesystem %s:", diskfs_disk_name); + 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[%s]", + program_invocation_short_name, diskfs_disk_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_COPY_SEND); + mach_port_deallocate (mach_task_self (), diskfs_exec_ctl); + mach_port_deallocate (mach_task_self (), execnode); + assert_perror (err); + } + diskfs_exec_ctl = MACH_PORT_NULL; /* Not used after this. */ + } + + /* Cache the exec server port for file_exec to use. */ + _hurd_port_set (&_diskfs_exec_portcell, diskfs_exec); + + 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. */ + initname = diskfs_boot_init_program; + while (*initname == '/') + initname++; + + exec_argvlen = asprintf (&exec_argv, "/%s%c", initname, '\0'); + assert (exec_argvlen != -1); + err = argz_add_sep (&exec_argv, &exec_argvlen, + diskfs_boot_command_line, ' '); + assert_perror (err); + + initname = exec_argv + 1; + } + lookup_init: err = dir_lookup (root_pt, initname, O_READ, 0, &retry, pathbuf, &startup_pt); + init_lookups++; + if (err) + { + printf ("\nCannot find startup program `%s': %s\n", + initname, strerror (err)); + fflush (stdout); + free (exec_argv); + assert_perror (err); /* XXX this won't reboot properly */ + } + else if (retry == FS_RETRY_MAGICAL && pathbuf[0] == '/') + { + assert (init_lookups < SYMLOOP_MAX); + + /* INITNAME is a symlink with an absolute target, so try again. */ + initname = strdupa (pathbuf); + goto lookup_init; + } - assert_perror (err); assert (retry == FS_RETRY_NORMAL); assert (pathbuf[0] == '\0'); err = ports_create_port (diskfs_initboot_class, diskfs_port_bucket, sizeof (struct port_info), &bootinfo); assert_perror (err); - bootpt = ports_get_right (bootinfo); - mach_port_insert_right (mach_task_self (), bootpt, bootpt, - MACH_MSG_TYPE_MAKE_SEND); + bootpt = ports_get_send_right (bootinfo); ports_port_deref (bootinfo); portarray[INIT_PORT_CRDIR] = root_pt; @@ -171,31 +262,34 @@ 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 = argz_create (environ, &exec_env, &exec_envlen); + assert_perror (err); - err = task_create (mach_task_self (), 0, &newt); + err = task_create (mach_task_self (), +#ifdef KERN_INVALID_LEDGER + NULL, 0, /* OSF Mach */ +#endif + 0, &newt); assert_perror (err); - if (index (diskfs_boot_flags, 'd')) + if (_diskfs_boot_pause) { - 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, + newt, 0, exec_argv, exec_argvlen, exec_env, exec_envlen, fdarray, MACH_MSG_TYPE_COPY_SEND, 3, portarray, MACH_MSG_TYPE_COPY_SEND, INIT_PORT_MAX, /* Supply no intarray, since we have no info for it. With none supplied, it will use the defaults. */ NULL, 0, 0, 0, 0, 0); free (exec_argv); + free (exec_env); 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); } @@ -228,6 +322,7 @@ diskfs_S_exec_startup_get_info (mach_port_t port, mach_port_t rootport; struct ufsport *upt; struct protid *rootpi; + struct peropen *rootpo; if (!(upt = ports_lookup_port (diskfs_port_bucket, port, diskfs_execboot_class))) @@ -243,14 +338,14 @@ diskfs_S_exec_startup_get_info (mach_port_t port, *flags = EXEC_STACK_ARGS; if (*portarraylen < INIT_PORT_MAX) - vm_allocate (mach_task_self (), (vm_address_t *) portarrayP, - (INIT_PORT_MAX * sizeof (mach_port_t)), 1); + *portarrayP = mmap (0, INIT_PORT_MAX * sizeof (mach_port_t), + PROT_READ|PROT_WRITE, MAP_ANON, 0, 0); portarray = *portarrayP; *portarraylen = INIT_PORT_MAX; if (*dtablelen < 3) - vm_allocate (mach_task_self (), (vm_address_t *) dtableP, - (3 * sizeof (mach_port_t)), 1); + *dtableP = mmap (0, 3 * sizeof (mach_port_t), PROT_READ|PROT_WRITE, + MAP_ANON, 0, 0); dtable = *dtableP; *dtablelen = 3; dtable[0] = dtable[1] = dtable[2] = get_console (); /* XXX */ @@ -258,11 +353,12 @@ diskfs_S_exec_startup_get_info (mach_port_t port, *intarrayP = NULL; *intarraylen = 0; - err = diskfs_create_protid (diskfs_make_peropen (diskfs_root_node, - O_READ | O_EXEC, - MACH_PORT_NULL), - 0,0,0,0, &rootpi); + err = diskfs_make_peropen (diskfs_root_node, O_READ | O_EXEC, 0, &rootpo); + assert_perror (err); + + err = diskfs_create_protid (rootpo, 0, &rootpi); assert_perror (err); + rootport = ports_get_right (rootpi); ports_port_deref (rootpi); portarray[INIT_PORT_CWDIR] = rootport; @@ -293,19 +389,18 @@ diskfs_execboot_fsys_startup (mach_port_t port, int flags, enum retry_type retry; struct port_info *pt; struct protid *rootpi; + struct peropen *rootpo; mach_port_t rootport; if (!(pt = ports_lookup_port (diskfs_port_bucket, port, diskfs_execboot_class))) return EOPNOTSUPP; - err = diskfs_create_protid (diskfs_make_peropen (diskfs_root_node, flags, - MACH_PORT_NULL), - 0,0,0,0, &rootpi); + err = diskfs_make_peropen (diskfs_root_node, flags, 0, &rootpo); assert_perror (err); - rootport = ports_get_right (rootpi); - mach_port_insert_right (mach_task_self (), rootport, rootport, - MACH_MSG_TYPE_MAKE_SEND); + err = diskfs_create_protid (rootpo, 0, &rootpi); + assert_perror (err); + rootport = ports_get_send_right (rootpi); ports_port_deref (rootpi); err = dir_lookup (rootport, _SERVERS_EXEC, flags|O_NOTRANS, 0, @@ -365,12 +460,11 @@ diskfs_S_fsys_init (mach_port_t port, { struct port_infe *pt; static int initdone = 0; - process_t execprocess; - string_t version; mach_port_t host, startup; error_t err; mach_port_t root_pt; struct protid *rootpi; + struct peropen *rootpo; pt = ports_lookup_port (diskfs_port_bucket, port, diskfs_initboot_class); if (!pt) @@ -384,9 +478,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); @@ -394,36 +491,78 @@ 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. */ + HURD_PORT_USE (&_diskfs_exec_portcell, + exec_init (port, 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); + + /* 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_COPY_SEND, + authhandle); + mach_port_deallocate (mach_task_self (), parent_proc); + 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. */ - err = diskfs_create_protid (diskfs_make_peropen (diskfs_root_node, - O_READ|O_EXEC, - MACH_PORT_NULL), - 0,0,0,0, &rootpi); + err = diskfs_make_peropen (diskfs_root_node, O_READ|O_EXEC, 0, &rootpo); + assert_perror (err); + err = diskfs_create_protid (rootpo, 0, &rootpi); assert_perror (err); - root_pt = ports_get_right (rootpi); + root_pt = ports_get_send_right (rootpi); ports_port_deref (rootpi); /* We need two send rights, for the crdir and cwdir slots. */ - mach_port_insert_right (mach_task_self (), root_pt, root_pt, - MACH_MSG_TYPE_MAKE_SEND); mach_port_mod_refs (mach_task_self (), root_pt, MACH_PORT_RIGHT_SEND, +1); @@ -437,7 +576,7 @@ diskfs_S_fsys_init (mach_port_t port, _hurd_port_set (&_hurd_ports[INIT_PORT_AUTH], authhandle); /* Consume. */ _hurd_port_set (&_hurd_ports[INIT_PORT_CRDIR], root_pt); /* Consume. */ _hurd_port_set (&_hurd_ports[INIT_PORT_CWDIR], root_pt); /* Consume. */ - _hurd_proc_init (diskfs_argv); + _hurd_proc_init (diskfs_argv, NULL, 0); } else { @@ -447,8 +586,8 @@ diskfs_S_fsys_init (mach_port_t port, and call _hurd_init. */ mach_port_t *portarray; unsigned int i; - __vm_allocate (__mach_task_self (), (vm_address_t *) &portarray, - INIT_PORT_MAX * sizeof *portarray, 1); + portarray = mmap (0, INIT_PORT_MAX * sizeof *portarray, + PROT_READ|PROT_WRITE, MAP_ANON, 0, 0); if (MACH_PORT_NULL != (mach_port_t) 0) for (i = 0; i < INIT_PORT_MAX; ++i) portarray[i] = MACH_PORT_NULL; @@ -463,9 +602,8 @@ diskfs_S_fsys_init (mach_port_t port, if (err) return err; - sprintf (version, "%d.%d", diskfs_major_version, diskfs_minor_version); - proc_register_version (procserver, host, - diskfs_server_name, HURD_RELEASE, version); + proc_register_version (procserver, host, diskfs_server_name, "", + diskfs_server_version); err = proc_getmsgport (procserver, 1, &startup); if (!err) @@ -476,6 +614,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 (); @@ -496,14 +635,12 @@ start_execserver (void) err = ports_create_port (diskfs_execboot_class, diskfs_port_bucket, sizeof (struct port_info), &execboot_info); assert_perror (err); - right = ports_get_right (execboot_info); - mach_port_insert_right (mach_task_self (), right, - right, MACH_MSG_TYPE_MAKE_SEND); + right = ports_get_send_right (execboot_info); ports_port_deref (execboot_info); task_set_special_port (diskfs_exec_server_task, TASK_BOOTSTRAP_PORT, right); mach_port_deallocate (mach_task_self (), right); - if (index (diskfs_boot_flags, 'd')) + if (_diskfs_boot_pause) { printf ("pausing for exec\n"); getc (stdin); @@ -513,4 +650,3 @@ start_execserver (void) printf (" exec"); fflush (stdout); } - |