>From 236bcec849c5775a4567c7d8fbceb75beb29dc48 Mon Sep 17 00:00:00 2001 From: Sergiu Ivanov <unlimitedscol...@gmail.com> Date: Sun, 5 Jul 2009 23:08:44 +0300 Subject: [PATCH] Start the mountee in a lazy fashion.
* mount.c (unionmount_proxy): New variable. (mountee_port): Likewise. (mountee_started): Likewise. (setup_unionmount): New function. (start_mountee): New function (based on node_set_translator in nsmux). * mount.h (unionmount_proxy): New variable. (mountee_port): Likewise. (mountee_started): Likewise. (setup_unionmount): New function. (start_mountee): New function. (setup_unionmount): New function. * netfs.c (netfs_validate_stat): Start the mountee at the first invocation. --- mount.c | 179 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ mount.h | 23 ++++++++ netfs.c | 14 +++++- 3 files changed, 215 insertions(+), 1 deletions(-) diff --git a/mount.c b/mount.c index 7bc1fb8..f05fe7c 100644 --- a/mount.c +++ b/mount.c @@ -22,8 +22,187 @@ #define _GNU_SOURCE +#include <hurd/fsys.h> +#include <fcntl.h> + #include "mount.h" +#include "lib.h" /* The command line for starting the mountee. */ char * mountee_argz; size_t mountee_argz_len; + +/* The node the mountee is sitting on. */ +node_t * unionmount_proxy; + +mach_port_t mountee_port; + +int mountee_started = 0; + +/* Starts the mountee (given by `argz` and `argz_len`), sets it on + node `np` and opens a port `port` to with `flags`. */ +error_t +start_mountee (node_t * np, char * argz, size_t argz_len, int flags, + mach_port_t * port) +{ + error_t err; + mach_port_t underlying_port; + + /* The intermediate container for the port to the root of the + mountee. */ + mach_port_t res_port; + + /* An unauthenticated port to the root of the translator, which + plays the role of the directory containing the underlying node of + the mountee. This one is used in fsys_getroot as the dotdot + parameter, so it is not really important what we put here because + the dotdot parameter is used mostly with symlinks. */ + mach_port_t unauth_dir; + + /* The control port of the mountee. */ + mach_port_t control; + + /* The user which has created this process. */ + struct iouser * user; + + /* The user who has no priveleges at all. */ + struct iouser * nobody; + + /* A protid which will be created from the supplied node. */ + struct protid * newpi; + + /* Identity information about the current process (for + fsys_getroot). */ + uid_t * uids; + size_t nuids; + + gid_t * gids; + size_t ngids; + + /* The retry information returned by fsys_getroot. */ + string_t retry_name; + mach_port_t retry_port; + + /* Fetch the effective UIDs of this process. */ + nuids = geteuids (0, 0); + if (nuids < 0) + return EPERM; + uids = alloca (nuids * sizeof (uid_t)); + + nuids = geteuids (nuids, uids); + assert (nuids > 0); + + /* Fetch the effective GIDs of this process. */ + ngids = getgroups (0, 0); + if (ngids < 0) + return EPERM; + gids = alloca (ngids * sizeof (gid_t)); + + ngids = getgroups (ngids, gids); + assert (ngids > 0); + + /* Create an iouser instance basing on the obtained authority + information. */ + err = iohelp_create_complex_iouser (&user, uids, nuids, gids, ngids); + if (err) + return err; + + /* Opens the port on which to set the mountee. */ + error_t + open_port (int flags, mach_port_t * underlying, + mach_msg_type_name_t * underlying_type, task_t task, + void *cookie) + { + err = 0; + + /* Create a port to `np`. */ + newpi = netfs_make_protid + (netfs_make_peropen (np, flags, NULL), user); + if (!newpi) + { + iohelp_free_iouser (user); + return errno; + } + + *underlying = underlying_port = ports_get_send_right (newpi); + *underlying_type = MACH_MSG_TYPE_COPY_SEND; + + ports_port_deref (newpi); + + return err; + } /*open_port */ + + /* Create a completely unprivileged user. */ + err = iohelp_create_iouser(&nobody, NULL, NULL); + + /* Create a port to `np` for the unprivileged user. */ + newpi = netfs_make_protid + (netfs_make_peropen (np, flags, NULL), nobody); + if (!newpi) + { + iohelp_free_iouser (nobody); + err = errno; + return err; + } + + unauth_dir = ports_get_send_right (newpi); + ports_port_deref (newpi); + + /* Start the translator. The value 60000 for the timeout is the one + found in settrans. */ + err = fshelp_start_translator (open_port, NULL, argz, argz, argz_len, + 60000, &control); + if (err) + return err; + + /* Attempt to attach the mountee to the port opened in the previous + call. */ + err = file_set_translator (underlying_port, 0, FS_TRANS_SET, 0, argz, + argz_len, control, MACH_MSG_TYPE_COPY_SEND); + port_dealloc (underlying_port); + if (err) + return err; + + /* Obtain the port to the root of the newly-set translator. */ + err = fsys_getroot (control, unauth_dir, MACH_MSG_TYPE_COPY_SEND, + uids, nuids, gids, ngids, flags, &retry_port, + retry_name, &res_port); + if (err) + return err; + + *port = res_port; + + return 0; +} /* start_mountee */ + +/* Sets up a proxy node, sets the translator on it, and registers the + filesystem published by the translator in the list of merged + filesystems. */ +error_t +setup_unionmount (void) +{ + error_t err = 0; + + /* The proxy node on which the mountee will be sitting must be able + to forward some of the RPCs coming from the mountee to the + underlying filesystem. That is why we create this proxy node as + a clone of the root node: the mountee will feel as if there is no + unionfs under itself. */ + unionmount_proxy = netfs_make_node (netfs_root_node->nn); + if (!unionmount_proxy) + return ENOMEM; + + /* Set the mountee on the proxy node. + Note that the O_READ flag does not actually limit access to the + mountee's filesystem considerably. Whenever a client looks up a + node which is not a directory, unionfs will give off a port to + the node itself, withouth proxying it. Proxying happens only for + directory nodes. */ + err = start_mountee (unionmount_proxy, mountee_argz, + mountee_argz_len, O_READ, &mountee_port); + + mountee_started = 1; + + return err; +} /* setup_unionmount */ + diff --git a/mount.h b/mount.h index a7dd933..181608c 100644 --- a/mount.h +++ b/mount.h @@ -23,10 +23,33 @@ #ifndef INCLUDED_MOUNT_H #define INCLUDED_MOUNT_H +#include <error.h> #include <unistd.h> +#include <hurd/hurd_types.h> + +#include "node.h" /* The command line for starting the mountee. */ extern char * mountee_argz; extern size_t mountee_argz_len; +/* The node the mountee is sitting on. */ +extern node_t * unionmount_proxy; + +extern mach_port_t mountee_port; + +extern int mountee_started; + +/* Starts the mountee (given by `argz` and `argz_len`), sets it on + node `np` and opens a port `port` to with `flags`. */ +error_t +start_mountee (node_t * np, char * argz, size_t argz_len, int flags, + mach_port_t * port); + +/* Sets up a proxy node, sets the translator on it, and registers the + filesystem published by the translator in the list of merged + filesystems. */ +error_t +setup_unionmount (void); + #endif /* not INCLUDED_MOUNT_H */ diff --git a/netfs.c b/netfs.c index 89d1bf6..01e8ae9 100644 --- a/netfs.c +++ b/netfs.c @@ -1,7 +1,11 @@ /* Hurd unionfs - Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc. + Copyright (C) 2001, 2002, 2003, 2005, 2009 + Free Software Foundation, Inc. + Written by Moritz Schulte <mor...@duesseldorf.ccc.de>. + Adapted for unionmount by Sergiu Ivanov <unlimitedscol...@gmail.com>. + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the @@ -36,6 +40,7 @@ #include "lib.h" #include "ncache.h" #include "options.h" +#include "mount.h" /* Return an argz string describing the current options. Fill *ARGZ with a pointer to newly malloced storage holding the list and *LEN @@ -165,6 +170,13 @@ netfs_validate_stat (struct node *np, struct iouser *cred) } else { + if (!mountee_started) + { + err = setup_unionmount (); + if (err) + error (EXIT_FAILURE, err, "failed to setup the mountee"); + } + _get_node_size (np, &np->nn_stat.st_size); } -- 1.5.2.4