diff options
Diffstat (limited to 'libdiskfs/init-startup.c')
-rw-r--r-- | libdiskfs/init-startup.c | 116 |
1 files changed, 84 insertions, 32 deletions
diff --git a/libdiskfs/init-startup.c b/libdiskfs/init-startup.c index 885f7ccc..bf1acf29 100644 --- a/libdiskfs/init-startup.c +++ b/libdiskfs/init-startup.c @@ -1,5 +1,5 @@ /* diskfs_startup_diskfs -- advertise our fsys control port to our parent FS. - Copyright (C) 1994, 1995, 1996 Free Software Foundation + Copyright (C) 1994,95,96,98,99,2000,02 Free Software Foundation This file is part of the GNU Hurd. @@ -8,7 +8,7 @@ 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, +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. @@ -22,30 +22,84 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "priv.h" #include <stdio.h> #include <string.h> +#include <fcntl.h> +#include <error.h> #include <hurd/fsys.h> #include <hurd/startup.h> +char *_diskfs_chroot_directory; + mach_port_t diskfs_startup_diskfs (mach_port_t bootstrap, int flags) { - mach_port_t realnode; + error_t err; + mach_port_t realnode, right; struct port_info *newpi; - - if (bootstrap != MACH_PORT_NULL) + + if (_diskfs_chroot_directory != NULL) { - errno = ports_create_port (diskfs_control_class, diskfs_port_bucket, - sizeof (struct port_info), &newpi); - if (! errno) + /* The boot options requested we change to a subdirectory + and treat that as the root of the filesystem. */ + struct node *np, *old; + struct protid *rootpi; + struct peropen *rootpo; + + /* Skip leading slashes. */ + while (*_diskfs_chroot_directory == '/') + ++_diskfs_chroot_directory; + + mutex_lock (&diskfs_root_node->lock); + + /* Create a protid we can use in diskfs_lookup. */ + 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); + + /* Look up the directory name. */ + err = diskfs_lookup (diskfs_root_node, _diskfs_chroot_directory, + LOOKUP, &np, NULL, rootpi); + mutex_unlock (&diskfs_root_node->lock); + ports_port_deref (rootpi); + + if (err == EAGAIN) + error (1, 0, "`--virtual-root=%s' specifies the real root directory", + _diskfs_chroot_directory); + else if (err) + error (1, err, "`%s' not found", _diskfs_chroot_directory); + + if (!S_ISDIR (np->dn_stat.st_mode)) { - errno = fsys_startup (bootstrap, flags, ports_get_right (newpi), - MACH_MSG_TYPE_MAKE_SEND, &realnode); - ports_port_deref (newpi); + mutex_unlock (&np->lock); + error (1, ENOTDIR, "%s", _diskfs_chroot_directory); } - if (errno) + + /* Install this node as the new root, forgetting about the real root + node. The last essential piece that makes the virtual root work + is in fsys-getroot.c, which sets the first peropen's shadow_root + if _diskfs_chroot_directory is non-null. */ + old = diskfs_root_node; + diskfs_root_node = np; + mutex_unlock (&np->lock); + diskfs_nput (old); + } + + if (bootstrap != MACH_PORT_NULL) + { + err = ports_create_port (diskfs_control_class, diskfs_port_bucket, + sizeof (struct port_info), &newpi); + if (! err) { - perror ("Translator startup failure: fsys_startup"); - exit (1); + right = ports_get_send_right (newpi); + err = fsys_startup (bootstrap, flags, right, + MACH_MSG_TYPE_COPY_SEND, &realnode); + mach_port_deallocate (mach_task_self (), right); + ports_port_deref (newpi); } + if (err) + error (1, err, "Translator startup failure: fsys_startup"); + mach_port_deallocate (mach_task_self (), bootstrap); _diskfs_ncontrol_ports++; @@ -70,22 +124,22 @@ error_t diskfs_S_startup_dosync (mach_port_t handle) { error_t err = 0; - struct port_info *pi + struct port_info *pi = ports_lookup_port (diskfs_port_bucket, handle, diskfs_shutdown_notification_class); if (!pi) return EOPNOTSUPP; - + if (! diskfs_readonly) { /* First start a sync so that if something goes wrong we at least get this much done. */ diskfs_sync_everything (0); diskfs_set_hypermetadata (0, 0); - + rwlock_writer_lock (&diskfs_fsys_lock); - + /* Permit all the current RPC's to finish, and then suspend new ones */ err = ports_inhibit_class_rpcs (diskfs_protid_class); if (! err) @@ -107,7 +161,7 @@ diskfs_S_startup_dosync (mach_port_t handle) /* This is called when we have an ordinary environment, complete with proc and auth ports. */ -void +void _diskfs_init_completed () { startup_t init; @@ -117,12 +171,12 @@ _diskfs_init_completed () mach_port_t notify; char *name; - /* Contact the startup server and register our shutdown request. + /* Contact the startup server and register our shutdown request. If we get an error, print an informational message. */ proc = getproc (); assert (proc); - + err = ports_create_port (diskfs_shutdown_notification_class, diskfs_port_bucket, sizeof (struct port_info), &pi); @@ -133,23 +187,21 @@ _diskfs_init_completed () mach_port_deallocate (mach_task_self (), proc); if (err) goto errout; - - notify = ports_get_right (pi); + + notify = ports_get_send_right (pi); ports_port_deref (pi); - asprintf (&name, "%s %s", program_invocation_short_name, - diskfs_device_arg); - err = startup_request_notification (init, notify, - MACH_MSG_TYPE_MAKE_SEND, name); + asprintf (&name, + "%s %s", program_invocation_short_name, diskfs_disk_name ?: "-"); + err = startup_request_notification (init, notify, + MACH_MSG_TYPE_COPY_SEND, name); + mach_port_deallocate (mach_task_self (), notify); free (name); if (err) goto errout; - + mach_port_deallocate (mach_task_self (), init); return; errout: - fprintf (stderr, "Cannot request shutdown notification: %s\n", - strerror (err)); + error (0, err, "Cannot request shutdown notification"); } - - |