From f8e9c21bc6f36840b308da7bb1c2d1be79386830 Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Sat, 24 Oct 1998 07:31:10 +0000 Subject: 1998-04-04 Roland McGrath Add support for a "virtual root directory" specified at startup. * priv.h (_diskfs_chroot_directory): Declare new variable. * opts-std-startup.c (startup_options, parse_startup_opt): New string-valued option -C/--directory/--virtual-root/--chroot sets _diskfs_chroot_directory. * init-startup.c (_diskfs_chroot_directory): New variable. (diskfs_startup_diskfs): If that's set, look up the name and warp us to that as a virtual root directory. * fsys-getroot.c (diskfs_S_fsys_getroot): Initialize new peropen's shadow_root_parent to null, and shadow_root to either null or, if _diskfs_chroot_directory is set, to diskfs_root_node. --- libdiskfs/fsys-getroot.c | 39 +++++++++++++---------- libdiskfs/init-startup.c | 75 +++++++++++++++++++++++++++++++++++--------- libdiskfs/opts-std-startup.c | 7 ++++- libdiskfs/priv.h | 5 ++- 4 files changed, 92 insertions(+), 34 deletions(-) (limited to 'libdiskfs') diff --git a/libdiskfs/fsys-getroot.c b/libdiskfs/fsys-getroot.c index 2a18810c..4e44395d 100644 --- a/libdiskfs/fsys-getroot.c +++ b/libdiskfs/fsys-getroot.c @@ -1,5 +1,5 @@ /* - Copyright (C) 1993, 1994, 1995, 1996, 1997 Free Software Foundation + Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998 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. @@ -40,13 +40,18 @@ diskfs_S_fsys_getroot (fsys_t controlport, file_t *returned_port, mach_msg_type_name_t *returned_port_poly) { - struct port_info *pt = ports_lookup_port (diskfs_port_bucket, controlport, + struct port_info *pt = ports_lookup_port (diskfs_port_bucket, controlport, diskfs_control_class); error_t error = 0; mode_t type; struct protid *newpi; struct iouser user; - struct peropen peropen_context = { root_parent: dotdot }; + struct peropen peropen_context = + { + root_parent: dotdot, + shadow_root_parent: MACH_PORT_NULL, + shadow_root: _diskfs_chroot_directory ? diskfs_root_node : NULL /* XXX */ + }; if (!pt) return EOPNOTSUPP; @@ -61,7 +66,7 @@ diskfs_S_fsys_getroot (fsys_t controlport, rwlock_reader_lock (&diskfs_fsys_lock); mutex_lock (&diskfs_root_node->lock); - + /* This code is similar (but not the same as) the code in dir-pathtrans.c that does the same thing. Perhaps a way should be found to share the logic. */ @@ -73,7 +78,7 @@ diskfs_S_fsys_getroot (fsys_t controlport, && !(flags & O_NOTRANS)) { error = fshelp_fetch_root (&diskfs_root_node->transbox, - &peropen_context, dotdot, &user, flags, + &peropen_context, dotdot, &user, flags, _diskfs_translator_callback1, _diskfs_translator_callback2, retry, retryname, returned_port); @@ -86,17 +91,17 @@ diskfs_S_fsys_getroot (fsys_t controlport, *returned_port_poly = MACH_MSG_TYPE_MOVE_SEND; return error; } - + /* ENOENT means the translator was removed in the interim. */ error = 0; } - + if (type == S_IFLNK && !(flags & (O_NOLINK | O_NOTRANS))) { /* Handle symlink interpretation */ char pathbuf[diskfs_root_node->dn_stat.st_size + 1]; int amt; - + if (diskfs_read_symlink_hook) error = (*diskfs_read_symlink_hook) (diskfs_root_node, pathbuf); if (!diskfs_read_symlink_hook || error == EINVAL) @@ -112,7 +117,7 @@ diskfs_S_fsys_getroot (fsys_t controlport, drop_idvec (); return error; } - + if (pathbuf[0] == '/') { *retry = FS_RETRY_MAGICAL; @@ -134,24 +139,24 @@ diskfs_S_fsys_getroot (fsys_t controlport, } } - if ((type == S_IFSOCK || type == S_IFBLK + if ((type == S_IFSOCK || type == S_IFBLK || type == S_IFCHR || type == S_IFIFO) && (flags & (O_READ|O_WRITE|O_EXEC))) error = EOPNOTSUPP; - + if (!error && (flags & O_READ)) error = fshelp_access (&diskfs_root_node->dn_stat, S_IREAD, &user); - + if (!error && (flags & O_EXEC)) error = fshelp_access (&diskfs_root_node->dn_stat, S_IEXEC, &user); - + if (!error && (flags & (O_WRITE))) { if (type == S_IFDIR) error = EISDIR; else if (diskfs_check_readonly ()) error = EROFS; - else + else error = fshelp_access (&diskfs_root_node->dn_stat, S_IWRITE, &user); } @@ -163,7 +168,7 @@ diskfs_S_fsys_getroot (fsys_t controlport, drop_idvec (); return error; } - + if ((flags & O_NOATIME) && (fshelp_isowner (&diskfs_root_node->dn_stat, &user) == EPERM)) @@ -186,7 +191,7 @@ diskfs_S_fsys_getroot (fsys_t controlport, *returned_port_poly = MACH_MSG_TYPE_MAKE_SEND; ports_port_deref (newpi); } - + mutex_unlock (&diskfs_root_node->lock); rwlock_reader_unlock (&diskfs_fsys_lock); diff --git a/libdiskfs/init-startup.c b/libdiskfs/init-startup.c index d2802db5..3573f8ff 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, 1995, 1996, 1998 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,15 +22,62 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "priv.h" #include #include +#include +#include #include #include +const char *_diskfs_chroot_directory; + mach_port_t diskfs_startup_diskfs (mach_port_t bootstrap, int flags) { mach_port_t realnode; struct port_info *newpi; - + + if (_diskfs_chroot_directory != NULL) + { + /* The boot options requested we change to a subdirectory + and treat that as the root of the filesystem. */ + error_t err; + struct node *np, *old; + struct protid *rootpi; + + mutex_lock (&diskfs_root_node->lock); + + /* Create a protid we can use in diskfs_lookup. */ + err = diskfs_create_protid (diskfs_make_peropen (diskfs_root_node, + O_READ|O_EXEC, 0), + 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)) + { + mutex_unlock (&np->lock); + error (1, ENOTDIR, "%s", _diskfs_chroot_directory); + } + + /* 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; + ports_port_deref (old); + } + if (bootstrap != MACH_PORT_NULL) { errno = ports_create_port (diskfs_control_class, diskfs_port_bucket, @@ -70,22 +117,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 +154,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 +164,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,17 +180,17 @@ _diskfs_init_completed () mach_port_deallocate (mach_task_self (), proc); if (err) goto errout; - + notify = ports_get_right (pi); ports_port_deref (pi); asprintf (&name, "%s %s", program_invocation_short_name, diskfs_disk_name ?: "-"); - err = startup_request_notification (init, notify, + err = startup_request_notification (init, notify, MACH_MSG_TYPE_MAKE_SEND, name); free (name); if (err) goto errout; - + mach_port_deallocate (mach_task_self (), init); return; @@ -151,5 +198,3 @@ _diskfs_init_completed () fprintf (stderr, "Cannot request shutdown notification: %s\n", strerror (err)); } - - diff --git a/libdiskfs/opts-std-startup.c b/libdiskfs/opts-std-startup.c index 13cf8e65..14760ed7 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 Free Software Foundation, Inc. + Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc. Written by Miles Bader @@ -46,6 +46,9 @@ startup_options[] = {"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} }; @@ -84,6 +87,8 @@ parse_startup_opt (int opt, char *arg, struct argp_state *state) diskfs_exec_server_task = atoi (arg); break; case OPT_BOOTFLAGS: diskfs_boot_flags = arg; break; + case 'C': + _diskfs_chroot_directory = arg; break; case ARGP_KEY_END: diskfs_argv = state->argv; break; diff --git a/libdiskfs/priv.h b/libdiskfs/priv.h index c03d93dc..5a90c2b8 100644 --- a/libdiskfs/priv.h +++ b/libdiskfs/priv.h @@ -1,5 +1,5 @@ /* Private declarations for fileserver library - Copyright (C) 1994, 1995, 1996, 1997 Free Software Foundation + Copyright (C) 1994, 1995, 1996, 1997, 1998 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 @@ -30,6 +30,9 @@ /* These inhibit setuid or exec. */ extern int _diskfs_nosuid, _diskfs_noexec; +/* This is the -C argument value. */ +extern const char *_diskfs_chroot_directory; + volatile struct mapped_time_value *_diskfs_mtime; extern struct argp_option diskfs_common_options[]; -- cgit v1.2.3