aboutsummaryrefslogtreecommitdiff
path: root/libdiskfs/init-startup.c
diff options
context:
space:
mode:
Diffstat (limited to 'libdiskfs/init-startup.c')
-rw-r--r--libdiskfs/init-startup.c116
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");
}
-
-