summaryrefslogtreecommitdiff
path: root/libfshelp
diff options
context:
space:
mode:
Diffstat (limited to 'libfshelp')
-rw-r--r--libfshelp/Makefile40
-rw-r--r--libfshelp/delegate.c64
-rw-r--r--libfshelp/drop-transbox.c28
-rw-r--r--libfshelp/exec-reauth.c152
-rw-r--r--libfshelp/fetch-control.c31
-rw-r--r--libfshelp/fetch-root.c195
-rw-r--r--libfshelp/fshelp.h308
-rw-r--r--libfshelp/get-identity.c92
-rw-r--r--libfshelp/lock-acquire.c131
-rw-r--r--libfshelp/lock-init.c32
-rw-r--r--libfshelp/locks.h28
-rw-r--r--libfshelp/perms-access.c43
-rw-r--r--libfshelp/perms-checkdirmod.c44
-rw-r--r--libfshelp/perms-iscontroller.c38
-rw-r--r--libfshelp/perms-isowner.c39
-rw-r--r--libfshelp/set-active.c62
-rw-r--r--libfshelp/set-options.c47
-rw-r--r--libfshelp/start-translator-long.c328
-rw-r--r--libfshelp/start-translator.c63
-rw-r--r--libfshelp/touch.c49
-rw-r--r--libfshelp/trans.h32
-rw-r--r--libfshelp/transbox-init.c34
-rw-r--r--libfshelp/translated.c28
-rw-r--r--libfshelp/translator-list.c202
24 files changed, 2110 insertions, 0 deletions
diff --git a/libfshelp/Makefile b/libfshelp/Makefile
new file mode 100644
index 00000000..6ba6a14f
--- /dev/null
+++ b/libfshelp/Makefile
@@ -0,0 +1,40 @@
+# Copyright (C) 1994, 95, 96, 98, 1999, 2006, 2012 Free Software Foundation,
+# Inc.
+#
+# 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, or (at
+# your option) any later version.
+#
+# This program 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.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+dir := libfshelp
+makemode := library
+
+libname = libfshelp
+SRCS = lock-acquire.c lock-init.c \
+ translator-list.c \
+ start-translator-long.c start-translator.c \
+ fetch-root.c transbox-init.c set-active.c fetch-control.c \
+ drop-transbox.c translated.c \
+ delegate.c \
+ exec-reauth.c \
+ set-options.c \
+ get-identity.c \
+ perms-isowner.c perms-iscontroller.c perms-access.c \
+ perms-checkdirmod.c \
+ touch.c
+installhdrs = fshelp.h
+
+HURDLIBS = shouldbeinlibc iohelp ports ihash
+LDLIBS += -lpthread
+OBJS = $(subst .c,.o,$(SRCS))
+
+include ../Makeconf
diff --git a/libfshelp/delegate.c b/libfshelp/delegate.c
new file mode 100644
index 00000000..a44310f0
--- /dev/null
+++ b/libfshelp/delegate.c
@@ -0,0 +1,64 @@
+/* fshelp_delegate_translation
+
+ Copyright (C) 1995,96,99,2000,02 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
+
+ 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, or (at
+ your option) any later version.
+
+ This program 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.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <errno.h>
+#include <string.h>
+#include <argz.h>
+#include <hurd.h>
+#include <hurd/fsys.h>
+#include <hurd/paths.h>
+
+/* Try to hand off responsibility from a translator to the server located on
+ the node SERVER_NAME. REQUESTOR is the translator's bootstrap port, and
+ ARGV is the command line. If SERVER_NAME is NULL, then a name is
+ concocted by appending ARGV[0] to _SERVERS. */
+error_t
+fshelp_delegate_translation (const char *server_name,
+ mach_port_t requestor, char **argv)
+{
+ error_t err;
+ file_t server;
+
+ if (! server_name)
+ {
+ char *buf = alloca (strlen (argv[0]) + sizeof (_SERVERS));
+ strcpy (buf, _SERVERS);
+ strcat (buf, argv[0]);
+ server_name = buf;
+ }
+
+ server = file_name_lookup (server_name, 0, 0);
+ if (server != MACH_PORT_NULL)
+ {
+ char *argz;
+ size_t argz_len;
+ err = argz_create (argv, &argz, &argz_len);
+ if (!err)
+ {
+ err = fsys_forward (server,
+ requestor, MACH_MSG_TYPE_COPY_SEND,
+ argz, argz_len);
+ free (argz);
+ }
+ }
+ else
+ err = errno;
+
+ return err;
+}
diff --git a/libfshelp/drop-transbox.c b/libfshelp/drop-transbox.c
new file mode 100644
index 00000000..d9087488
--- /dev/null
+++ b/libfshelp/drop-transbox.c
@@ -0,0 +1,28 @@
+/*
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Written by Michael I. Bushnell.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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, or (at
+ your option) any later version.
+
+ 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.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "fshelp.h"
+
+void
+fshelp_drop_transbox (struct transbox *box)
+{
+ if (box->active != MACH_PORT_NULL)
+ mach_port_deallocate (mach_task_self (), box->active);
+}
diff --git a/libfshelp/exec-reauth.c b/libfshelp/exec-reauth.c
new file mode 100644
index 00000000..d9a82974
--- /dev/null
+++ b/libfshelp/exec-reauth.c
@@ -0,0 +1,152 @@
+/* Setuid reauthentication for exec
+
+ Copyright (C) 1995,96,97,2002 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.org>,
+ from the original by Michael I. Bushnell p/BSG <mib@gnu.org>
+
+ 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, or (at
+ your option) any later version.
+
+ This program 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.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <hurd/io.h>
+#include <hurd/process.h>
+#include <hurd/auth.h>
+#include <idvec.h>
+
+#include "fshelp.h"
+
+extern error_t
+exec_reauth (auth_t auth, int secure, int must_reauth,
+ mach_port_t *ports, unsigned num_ports,
+ mach_port_t *fds, unsigned num_fds);
+
+/* If SUID or SGID is true, adds UID and/or GID respectively to the
+ authentication in PORTS[INIT_PORT_AUTH], and replaces it with the result.
+ All the other ports in PORTS and FDS are then reauthenticated, using any
+ privileges available through AUTH. If GET_FILE_IDS is non-NULL, and the
+ auth port in PORTS[INIT_PORT_AUTH] is bogus, it is called to get a list of
+ uids and gids from the file to use as a replacement. If SECURE is
+ non-NULL, whether not the added ids are new is returned in it. If either
+ the uid or gid case fails, then the other may still be applied. */
+error_t
+fshelp_exec_reauth (int suid, uid_t uid, int sgid, gid_t gid,
+ auth_t auth,
+ error_t
+ (*get_file_ids)(struct idvec *uids, struct idvec *gids),
+ mach_port_t *ports, mach_msg_type_number_t num_ports,
+ mach_port_t *fds, mach_msg_type_number_t num_fds,
+ int *secure)
+{
+ error_t err = 0;
+ int _secure = 0;
+
+ if (suid || sgid)
+ {
+ int already_root = 0;
+ auth_t newauth;
+ /* These variables describe the auth port that the user gave us. */
+ struct idvec *eff_uids = make_idvec (), *avail_uids = make_idvec ();
+ struct idvec *eff_gids = make_idvec (), *avail_gids = make_idvec ();
+
+ if (!eff_uids || !avail_uids || !eff_gids || !avail_gids)
+ goto abandon_suid; /* Allocation error; probably toast, but... */
+
+ /* STEP 0: Fetch the user's current id's. */
+ err = idvec_merge_auth (eff_uids, avail_uids, eff_gids, avail_gids,
+ ports[INIT_PORT_AUTH]);
+ if (err)
+ goto abandon_suid;
+
+ already_root =
+ idvec_contains (eff_uids, 0) || idvec_contains (avail_uids, 0);
+
+ /* If the user's auth port is fraudulent, then these values will be
+ wrong. No matter; we will repeat these checks using secure id sets
+ later if the port turns out to be bogus. */
+ if (suid)
+ err = idvec_setid (eff_uids, avail_uids, uid, &_secure);
+ if (sgid && !err)
+ err = idvec_setid (eff_gids, avail_gids, gid, &_secure);
+ if (err)
+ goto abandon_suid;
+
+ /* STEP 3: Attempt to create this new auth handle. */
+ err = auth_makeauth (auth, &ports[INIT_PORT_AUTH],
+ MACH_MSG_TYPE_COPY_SEND, 1,
+ eff_uids->ids, eff_uids->num,
+ avail_uids->ids, avail_uids->num,
+ eff_gids->ids, eff_gids->num,
+ avail_gids->ids, avail_gids->num,
+ &newauth);
+ if (err == EINVAL && get_file_ids)
+ /* The user's auth port was bogus. As we can't trust what the user
+ has told us about ids, we use the authentication on the file being
+ execed (which we know is good), as the effective ids, and assume
+ no aux ids. */
+ {
+ /* Get rid of all ids from the bogus auth port. */
+ idvec_clear (eff_uids);
+ idvec_clear (avail_uids);
+ idvec_clear (eff_gids);
+ idvec_clear (avail_gids);
+
+ /* Now add some from a source we trust. */
+ err = (*get_file_ids)(eff_uids, eff_gids);
+
+ already_root = idvec_contains (eff_uids, 0);
+ if (suid && !err)
+ err = idvec_setid (eff_uids, avail_uids, uid, &_secure);
+ if (sgid && !err)
+ err = idvec_setid (eff_gids, avail_gids, gid, &_secure);
+ if (err)
+ goto abandon_suid;
+
+ /* Trrrry again... */
+ err = auth_makeauth (auth, 0, MACH_MSG_TYPE_COPY_SEND, 1,
+ eff_uids->ids, eff_uids->num,
+ avail_uids->ids, avail_uids->num,
+ eff_gids->ids, eff_gids->num,
+ avail_gids->ids, avail_gids->num,
+ &newauth);
+ }
+
+ if (err)
+ goto abandon_suid;
+
+ if (already_root)
+ _secure = 0; /* executive privilege */
+
+ /* Re-authenticate the exec parameters. */
+ exec_reauth (newauth, _secure, 0, ports, num_ports, fds, num_fds);
+
+ proc_setowner (ports[INIT_PORT_PROC],
+ eff_uids->num > 0 ? eff_uids->ids[0] : 0,
+ !eff_uids->num);
+
+ abandon_suid:
+ if (eff_uids)
+ idvec_free (eff_uids);
+ if (avail_uids)
+ idvec_free (avail_uids);
+ if (eff_gids)
+ idvec_free (eff_gids);
+ if (avail_gids)
+ idvec_free (avail_gids);
+ }
+
+ if (secure)
+ *secure = _secure;
+
+ return err;
+}
diff --git a/libfshelp/fetch-control.c b/libfshelp/fetch-control.c
new file mode 100644
index 00000000..26c12d88
--- /dev/null
+++ b/libfshelp/fetch-control.c
@@ -0,0 +1,31 @@
+/*
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Written by Michael I. Bushnell.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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, or (at
+ your option) any later version.
+
+ 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.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "fshelp.h"
+
+error_t
+fshelp_fetch_control (struct transbox *box,
+ mach_port_t *control)
+{
+ *control = box->active;
+ if (*control != MACH_PORT_NULL)
+ mach_port_mod_refs (mach_task_self (), *control, MACH_PORT_RIGHT_SEND, 1);
+ return 0;
+}
diff --git a/libfshelp/fetch-root.c b/libfshelp/fetch-root.c
new file mode 100644
index 00000000..45c7dd09
--- /dev/null
+++ b/libfshelp/fetch-root.c
@@ -0,0 +1,195 @@
+/*
+ Copyright (C) 1995,96,99,2000,02 Free Software Foundation, Inc.
+ Written by Michael I. Bushnell.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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, or (at
+ your option) any later version.
+
+ 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.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "trans.h"
+#include <unistd.h>
+#include <assert.h>
+#include <string.h>
+#include <hurd/fsys.h>
+
+error_t
+fshelp_fetch_root (struct transbox *box, void *cookie,
+ file_t dotdot,
+ struct iouser *user,
+ int flags,
+ fshelp_fetch_root_callback1_t callback1,
+ fshelp_fetch_root_callback2_t callback2,
+ retry_type *retry, char *retryname,
+ file_t *root)
+{
+ error_t err;
+ mach_port_t control;
+ int cancel;
+ int i;
+
+ start_over:
+
+ if (box->active != MACH_PORT_NULL)
+ assert ((box->flags & TRANSBOX_STARTING) == 0);
+ else
+ {
+ uid_t uid, gid;
+ char *argz;
+ size_t argz_len;
+ error_t err;
+ mach_port_t ports[INIT_PORT_MAX];
+ int ints[INIT_INT_MAX];
+ mach_port_t fds[STDERR_FILENO + 1];
+ auth_t ourauth, newauth;
+
+ mach_port_t reauth (mach_port_t port) /* Consumes PORT. */
+ {
+ mach_port_t rend, ret;
+ error_t err;
+
+ if (port == MACH_PORT_NULL)
+ return port;
+
+ if (ourauth == MACH_PORT_NULL)
+ /* We have no auth server, so we aren't doing reauthentications.
+ Just pass on our own ports directly. */
+ return port;
+
+ rend = mach_reply_port ();
+
+ /* MAKE_SEND is safe here because we destroy REND ourselves. */
+ err = io_reauthenticate (port, rend,
+ MACH_MSG_TYPE_MAKE_SEND);
+ mach_port_deallocate (mach_task_self (), port);
+ if (! err)
+ err = auth_user_authenticate (newauth, rend,
+ MACH_MSG_TYPE_MAKE_SEND, &ret);
+ if (err)
+ ret = MACH_PORT_NULL;
+
+ mach_port_mod_refs (mach_task_self (), rend, MACH_PORT_RIGHT_RECEIVE, -1);
+
+ return ret;
+ }
+ error_t fetch_underlying (int flags, mach_port_t *underlying,
+ mach_msg_type_name_t *underlying_type,
+ task_t task, void *cookie)
+ {
+ return
+ (*callback2) (box->cookie, cookie, flags,
+ underlying, underlying_type);
+ }
+
+ if (box->flags & TRANSBOX_STARTING)
+ {
+ box->flags |= TRANSBOX_WANTED;
+ cancel = pthread_hurd_cond_wait_np (&box->wakeup, box->lock);
+ if (cancel)
+ return EINTR;
+ goto start_over;
+ }
+ box->flags |= TRANSBOX_STARTING;
+ pthread_mutex_unlock (box->lock);
+
+ err = (*callback1) (box->cookie, cookie, &uid, &gid, &argz, &argz_len);
+ if (err)
+ goto return_error;
+
+ ourauth = getauth ();
+ if (ourauth == MACH_PORT_NULL)
+ newauth = ourauth;
+ else
+ {
+ uid_t uidarray[2] = { uid, uid };
+ gid_t gidarray[2] = { gid, gid };
+ err = auth_makeauth (ourauth, 0, MACH_MSG_TYPE_COPY_SEND, 0,
+ uidarray, 1, uidarray, 2,
+ gidarray, 1, gidarray, 2, &newauth);
+ if (err)
+ goto return_error;
+ }
+
+ bzero (ports, INIT_PORT_MAX * sizeof (mach_port_t));
+ bzero (fds, (STDERR_FILENO + 1) * sizeof (mach_port_t));
+ bzero (ints, INIT_INT_MAX * sizeof (int));
+
+ ports[INIT_PORT_CWDIR] = dotdot;
+ ports[INIT_PORT_CRDIR] = reauth (getcrdir ());
+ ports[INIT_PORT_AUTH] = newauth;
+
+ fds[STDERR_FILENO] = reauth (getdport (STDERR_FILENO));
+
+ err = fshelp_start_translator_long (fetch_underlying, NULL,
+ argz, argz, argz_len,
+ fds, MACH_MSG_TYPE_COPY_SEND,
+ STDERR_FILENO + 1,
+ ports, MACH_MSG_TYPE_COPY_SEND,
+ INIT_PORT_MAX,
+ ints, INIT_INT_MAX,
+ uid,
+ 0, &control);
+ for (i = 0; i <= STDERR_FILENO; i++)
+ mach_port_deallocate (mach_task_self (), fds[i]);
+
+ for (i = 0; i < INIT_PORT_MAX; i++)
+ if (i != INIT_PORT_CWDIR)
+ mach_port_deallocate (mach_task_self (), ports[i]);
+
+ pthread_mutex_lock (box->lock);
+
+ free (argz);
+
+ return_error:
+
+ box->flags &= ~TRANSBOX_STARTING;
+ if (box->flags & TRANSBOX_WANTED)
+ {
+ box->flags &= ~TRANSBOX_WANTED;
+ pthread_cond_broadcast (&box->wakeup);
+ }
+
+ if (err)
+ return err;
+
+ if (! MACH_PORT_VALID (control))
+ /* The start translator succeeded, but it returned a bogus port. */
+ return EDIED;
+
+ box->active = control;
+ }
+
+ control = box->active;
+ mach_port_mod_refs (mach_task_self (), control,
+ MACH_PORT_RIGHT_SEND, 1);
+ pthread_mutex_unlock (box->lock);
+
+ /* Cancellation point XXX */
+ err = fsys_getroot (control, dotdot, MACH_MSG_TYPE_COPY_SEND,
+ user->uids->ids, user->uids->num,
+ user->gids->ids, user->gids->num,
+ flags, retry, retryname, root);
+
+ pthread_mutex_lock (box->lock);
+
+ if ((err == MACH_SEND_INVALID_DEST || err == MIG_SERVER_DIED)
+ && control == box->active)
+ fshelp_set_active (box, MACH_PORT_NULL, 0);
+ mach_port_deallocate (mach_task_self (), control);
+
+ if (err == MACH_SEND_INVALID_DEST || err == MIG_SERVER_DIED)
+ goto start_over;
+
+ return err;
+}
diff --git a/libfshelp/fshelp.h b/libfshelp/fshelp.h
new file mode 100644
index 00000000..5d3a0ceb
--- /dev/null
+++ b/libfshelp/fshelp.h
@@ -0,0 +1,308 @@
+/* FS helper library definitions
+ Copyright (C) 1994,95,96,97,98,99,2000,01,02,13,14
+ Free Software Foundation, Inc.
+
+ 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, or (at
+ your option) any later version.
+
+ This program 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.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef _HURD_FSHELP_
+#define _HURD_FSHELP_
+
+/* This library implements various things that are generic to
+ all or most implementors of the filesystem protocol. It
+ presumes that you are using the iohelp library as well. It
+ is divided into separate facilities which may be used independently. */
+
+#include <errno.h>
+#include <mach.h>
+#include <hurd/hurd_types.h>
+#include <pthread.h>
+#include <hurd/iohelp.h>
+#include <sys/stat.h>
+#include <maptime.h>
+
+
+/* Keeping track of active translators */
+/* These routines keep a list of active translators. They do not
+ require multi threading but depend on the ports library. */
+
+struct port_info;
+
+/* Record an active translator being bound to the given file name
+ NAME. ACTIVE is the control port of the translator. PI references
+ a receive port that is used to request dead name notifications,
+ typically the port for the underlying node passed to the
+ translator. */
+error_t
+fshelp_set_active_translator (struct port_info *pi,
+ const char *name,
+ mach_port_t active);
+
+/* Remove the active translator specified by its control port ACTIVE.
+ If there is no active translator with the given control port, this
+ does nothing. */
+error_t
+fshelp_remove_active_translator (mach_port_t active);
+
+/* This kind of function is used by fshelp_get_active_translators to
+ filter the list of translators to return. If a filter returns an
+ error for a given PATH, the translator bound to the PATH is not
+ included in the list. */
+typedef error_t (*fshelp_filter) (const char *path);
+
+/* Records the list of active translators into the argz vector
+ specified by TRANSLATORS filtered by FILTER. */
+error_t
+fshelp_get_active_translators (char **translators,
+ size_t *translators_len,
+ fshelp_filter filter);
+
+
+/* Passive translator linkage */
+/* These routines are self-contained and start passive translators,
+ returning the control port. They do not require multi threading
+ or the ports library. */
+
+/* A callback used by the translator starting functions, which should be a
+ function that given some open flags, opens the appropriate file, and
+ returns the node port. */
+typedef error_t (*fshelp_open_fn_t) (int flags,
+ file_t *node,
+ mach_msg_type_name_t *node_type,
+ task_t, void *cookie);
+
+/* Start a passive translator NAME with arguments ARGZ (length
+ ARGZ_LEN). Initialize the initports to PORTS (length PORTS_LEN),
+ the initints to INTS (length INTS_LEN), and the file descriptor
+ table to FDS (length FDS_LEN). Return the control port in
+ *CONTROL. If the translator doesn't respond or die in TIMEOUT
+ milliseconds (if TIMEOUT > 0), return an appropriate error. If the
+ translator dies before responding, return EDIED. Set the new
+ task's owner to OWNER_UID (or, if OWNER_UID is -1, then clear the
+ new task's owner. */
+error_t
+fshelp_start_translator_long (fshelp_open_fn_t underlying_open_fn, void *cookie,
+ char *name, char *argz, int argz_len,
+ mach_port_t *fds,
+ mach_msg_type_name_t fds_type, int fds_len,
+ mach_port_t *ports,
+ mach_msg_type_name_t ports_type, int ports_len,
+ int *ints, int ints_len,
+ uid_t owner_uid,
+ int timeout, fsys_t *control);
+
+
+/* Same as fshelp_start_translator_long, except the initports and ints
+ are copied from our own state, fd[2] is copied from our own stderr,
+ and the other fds are cleared. */
+error_t
+fshelp_start_translator (fshelp_open_fn_t underlying_open_fn, void *cookie,
+ char *name, char *argz, int argz_len,
+ int timeout, fsys_t *control);
+
+
+/* Active translator linkage */
+
+/* These routines implement the linkage to active translators needed
+ by any filesystem which supports them. They require pthreads and
+ use the passive translator routines above, but they don't require
+ the ports library at all. */
+
+struct transbox
+{
+ fsys_t active;
+ pthread_mutex_t *lock;
+ int flags;
+ pthread_cond_t wakeup;
+ void *cookie;
+};
+#define TRANSBOX_STARTING 1
+#define TRANSBOX_WANTED 2
+
+/* This interface is complex, because creating the ports and state
+ necessary for start_translator_long is expensive. The caller to
+ fshelp_fetch_root should not need to create them on every call, since
+ usually there will be an existing active translator. */
+
+/* This routine is called by fshelp_fetch_root to fetch more information.
+ Return the owner and group of the underlying translated file in *UID and
+ *GID; point *ARGZ at the entire passive translator spec for the file
+ (setting *ARGZ_LEN to the length.) If there is no passive translator,
+ then return ENOENT. COOKIE1 is the cookie passed in fshelp_transbox_init.
+ COOKIE2 is the cookie passed in the call to fshelp_fetch_root. */
+typedef error_t (*fshelp_fetch_root_callback1_t) (void *cookie1, void *cookie2,
+ uid_t *uid, gid_t *gid,
+ char **argz, size_t *argz_len);
+
+/* This routine is called by fshelp_fetch_root to fetch more information.
+ Return an unauthenticated node for the file itself in *UNDERLYING and
+ *UNDERLYING_TYPE (opened with FLAGS). COOKIE1 is the cookie passed in
+ fshelp_transbox_init. COOKIE2 is the cookie passed in the call to
+ fshelp_fetch_root. */
+typedef error_t (*fshelp_fetch_root_callback2_t) (void *cookie1, void *cookie2,
+ int flags,
+ mach_port_t *underlying,
+ mach_msg_type_name_t
+ *underlying_type);
+
+/* Fetch the root from TRANSBOX. DOTDOT is an unauthenticated port
+ for the directory in which we are looking; USER specifies the ids
+ of the user responsible for the call. FLAGS are as for dir_lookup
+ (but O_CREAT and O_EXCL are not meaningful and are ignored). The
+ transbox lock (as set by fshelp_transbox_init) must be held before
+ the call, and will be held upon return, but may be released during
+ the operation of the call. */
+error_t
+fshelp_fetch_root (struct transbox *transbox, void *cookie,
+ file_t dotdot,
+ struct iouser *user,
+ int flags,
+ fshelp_fetch_root_callback1_t callback1,
+ fshelp_fetch_root_callback2_t callback2,
+ retry_type *retry, char *retryname, mach_port_t *root);
+
+void
+fshelp_transbox_init (struct transbox *transbox,
+ pthread_mutex_t *lock,
+ void *cookie);
+
+/* Return true iff there is an active translator on this box */
+int fshelp_translated (struct transbox *box);
+
+/* Atomically replace the existing active translator port for this box
+ with NEWACTIVE. If EXCL is non-zero then don't frob an existing
+ active; return EBUSY instead. */
+error_t fshelp_set_active (struct transbox *box,
+ fsys_t newactive, int excl);
+
+/* Fetch the control port to make a request on it. It's a bad idea
+ to do fsys_getroot with the result; use fetch_root instead. */
+error_t fshelp_fetch_control (struct transbox *box,
+ mach_port_t *control);
+
+/* A transbox is being deallocated, clean associated state. */
+void fshelp_drop_transbox (struct transbox *box);
+
+
+
+/* Flock handling. */
+struct lock_box
+{
+ int type;
+ pthread_cond_t wait;
+ int waiting;
+ int shcount;
+};
+
+/* Call when a user makes a request to acquire an lock via file_lock.
+ There should be one lock box per object and one int per open; these
+ are passed as arguments BOX and USER respectively. FLAGS are as
+ per file_lock. MUT is a mutex which will be held whenever this
+ routine is called, to lock BOX->wait. */
+error_t fshelp_acquire_lock (struct lock_box *box, int *user,
+ pthread_mutex_t *mut, int flags);
+
+
+/* Initialize lock_box BOX. (The user int passed to fshelp_acquire_lock
+ should be initialized with LOCK_UN.). */
+void fshelp_lock_init (struct lock_box *box);
+
+
+
+struct port_bucket; /* shut up C compiler */
+/* Return an identity port in *PT for the node numbered FILENO,
+ suitable for returning from io_identity; exactly one send right
+ must be created from the returned value. FILENO should be the same
+ value returned as the `fileno' out-parameter in io_identity, and in
+ the enclosing directory (except for mount points), and in the
+ st_ino stat field. BUCKET should be a ports port bucket; fshelp
+ requires the caller to make sure port operations (for no-senders
+ notifications) are used.
+ */
+error_t fshelp_get_identity (struct port_bucket *bucket,
+ ino64_t fileno, mach_port_t *pt);
+
+
+
+/* Try to hand off responsibility from a translator to the server located on
+ the node SERVER_NAME. REQUESTOR is the translator's bootstrap port, and
+ ARGV is the command line. If SERVER_NAME is NULL, then a name is
+ concocted by appending ARGV[0] to _SERVERS. */
+error_t fshelp_delegate_translation (const char *server_name,
+ mach_port_t requestor, char **argv);
+
+struct idvec; /* Include <idvec.h> to get the real thing. */
+
+/* If SUID or SGID is true, adds UID and/or GID respectively to the
+ authentication in PORTS[INIT_PORT_AUTH], and replaces it with the result.
+ All the other ports in PORTS and FDS are then reauthenticated, using any
+ privileges available through AUTH. If GET_FILE_IDS is non-NULL, and the
+ auth port in PORTS[INIT_PORT_AUTH] is bogus, it is called to get a list of
+ uids and gids from the file to use as a replacement. If SECURE is
+ non-NULL, whether not the added ids are new is returned in it. If either
+ the uid or gid case fails, then the other may still be applied. */
+error_t
+fshelp_exec_reauth (int suid, uid_t uid, int sgid, gid_t gid,
+ auth_t auth,
+ error_t
+ (*get_file_ids)(struct idvec *uids, struct idvec *gids),
+ mach_port_t *ports, mach_msg_type_number_t num_ports,
+ mach_port_t *fds, mach_msg_type_number_t num_fds,
+ int *secure);
+
+struct argp; /* Include <argp.h> to get the real thing. */
+
+/* Invoke ARGP with data from DATA & LEN, in the standard way. */
+error_t fshelp_set_options (const struct argp *argp, int flags,
+ const char *argz, size_t argz_len, void *input);
+
+
+/* Standardized filesystem permission checking */
+
+/* Check to see whether USER should be considered the owner of the
+ file identified by ST. If so, return zero; otherwise return an
+ appropriate error code. */
+error_t fshelp_isowner (io_statbuf_t *st, struct iouser *user);
+
+/* Check to see whether USER should be considered a controller of the
+ filesystem. Which is to say, check to see if we should give USER the
+ control port. ST is the stat of the root node. USER is the user
+ asking for a send right to the control port. */
+error_t
+fshelp_iscontroller (io_statbuf_t *st, struct iouser *user);
+
+/* Check to see whether the user USER can operate on a file identified
+ by ST. OP is one of S_IREAD, S_IWRITE, and S_IEXEC. If the access
+ is permitted, return zero; otherwise return an appropriate error
+ code. */
+error_t fshelp_access (io_statbuf_t *st, int op, struct iouser *user);
+
+/* Check to see whether USER is allowed to modify DIR with respect to
+ existing file ST. (If there is no existing file, pass 0 for ST.)
+ If the access is permissible return 0; otherwise return an
+ appropriate error code. */
+error_t fshelp_checkdirmod (io_statbuf_t *dir, io_statbuf_t *st,
+ struct iouser *user);
+
+
+/* Timestamps to change. */
+#define TOUCH_ATIME 0x1
+#define TOUCH_MTIME 0x2
+#define TOUCH_CTIME 0x4
+
+/* Change the stat times of NODE as indicated by WHAT (from the set TOUCH_*)
+ to the current time. */
+void fshelp_touch (io_statbuf_t *st, unsigned what,
+ volatile struct mapped_time_value *maptime);
+#endif
diff --git a/libfshelp/get-identity.c b/libfshelp/get-identity.c
new file mode 100644
index 00000000..2dbd254c
--- /dev/null
+++ b/libfshelp/get-identity.c
@@ -0,0 +1,92 @@
+/* Helper function for io_identity
+ Copyright (C) 1996, 1999 Free Software Foundation, Inc.
+ Written by Michael I. Bushnell, p/BSG.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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, or (at
+ your option) any later version.
+
+ 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.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+
+#include <fshelp.h>
+#include <hurd/ports.h>
+#include <hurd/ihash.h>
+#include <stddef.h>
+#include <assert.h>
+
+static struct port_class *idclass = 0;
+static pthread_mutex_t idlock = PTHREAD_MUTEX_INITIALIZER;
+
+struct idspec
+{
+ struct port_info pi;
+ hurd_ihash_locp_t id_hashloc;
+};
+
+static struct hurd_ihash idhash
+ = HURD_IHASH_INITIALIZER (offsetof (struct idspec, id_hashloc));
+
+static void
+id_clean (void *cookie)
+{
+ struct idspec *i = cookie;
+ pthread_mutex_lock (&idlock);
+ hurd_ihash_locp_remove (&idhash, i->id_hashloc);
+ pthread_mutex_unlock (&idlock);
+}
+
+static void
+id_initialize ()
+{
+ assert (!idclass);
+ idclass = ports_create_class (id_clean, NULL);
+}
+
+error_t
+fshelp_get_identity (struct port_bucket *bucket,
+ ino_t fileno,
+ mach_port_t *pt)
+{
+ struct idspec *i;
+ error_t err = 0;
+
+ pthread_mutex_lock (&idlock);
+ if (!idclass)
+ id_initialize ();
+
+ i = hurd_ihash_find (&idhash, (hurd_ihash_key_t) fileno);
+ if (i == NULL)
+ {
+ err = ports_create_port (idclass, bucket, sizeof (struct idspec), &i);
+ if (err)
+ goto lose;
+ err = hurd_ihash_add (&idhash, (hurd_ihash_key_t) fileno, i);
+ if (err)
+ goto lose_port;
+
+ *pt = ports_get_right (i);
+ ports_port_deref (i);
+ }
+ else
+ *pt = ports_get_right (i);
+
+ /* Success! */
+ goto lose;
+
+ lose_port:
+ ports_destroy_right (i);
+ lose:
+ pthread_mutex_unlock (&idlock);
+ return err;
+}
diff --git a/libfshelp/lock-acquire.c b/libfshelp/lock-acquire.c
new file mode 100644
index 00000000..574bc5cb
--- /dev/null
+++ b/libfshelp/lock-acquire.c
@@ -0,0 +1,131 @@
+/*
+ Copyright (C) 1993, 1994, 1996 Free Software Foundation
+
+This file is part of the GNU Hurd.
+
+The GNU Hurd 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, or (at your option)
+any later version.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with the GNU Hurd; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Written by Michael I. Bushnell. */
+
+#include "locks.h"
+
+#define EWOULDBLOCK EAGAIN /* XXX */
+
+error_t
+fshelp_acquire_lock (struct lock_box *box, int *user, pthread_mutex_t *mut,
+ int flags)
+{
+ if (!(flags & (LOCK_UN | LOCK_EX | LOCK_SH)))
+ return 0;
+
+ if ((flags & LOCK_UN)
+ && (flags & (LOCK_SH | LOCK_EX)))
+ return EINVAL;
+
+ if (flags & LOCK_EX)
+ flags &= ~LOCK_SH;
+
+ /* flags now contains exactly one of LOCK_UN, LOCK_SH, or LOCK_EX. */
+
+ if (flags & LOCK_UN)
+ {
+ if (*user & LOCK_UN)
+ return 0;
+
+ assert (*user == box->type);
+ assert (*user == LOCK_SH || *user == LOCK_EX);
+
+ if (*user == LOCK_SH)
+ {
+ if (!--box->shcount)
+ box->type = LOCK_UN;
+ }
+ else if (*user == LOCK_EX)
+ box->type = LOCK_UN;
+
+ if (box->type == LOCK_UN && box->waiting)
+ {
+ box->waiting = 0;
+ pthread_cond_broadcast (&box->wait);
+ }
+ *user = LOCK_UN;
+ }
+ else
+ {
+ /* If we have an exclusive lock, release it. */
+ if (*user == LOCK_EX)
+ {
+ *user = LOCK_UN;
+ box->type = LOCK_UN;
+ if (box->waiting)
+ {
+ box->waiting = 0;
+ pthread_cond_broadcast (&box->wait);
+ }
+ }
+
+ /* If there is an exclusive lock, wait for it to end. */
+ while (box->type == LOCK_EX)
+ {
+ if (flags & LOCK_NB)
+ return EWOULDBLOCK;
+ box->waiting = 1;
+ if (pthread_hurd_cond_wait_np (&box->wait, mut))
+ return EINTR;
+ }
+
+ /* If we have a shared lock, release it. */
+ if (*user == LOCK_SH)
+ {
+ *user = LOCK_UN;
+ if (!--box->shcount)
+ {
+ box->type = LOCK_UN;
+ if (box->waiting)
+ {
+ box->waiting = 0;
+ pthread_cond_broadcast (&box->wait);
+ }
+ }
+ }
+
+ assert ((flags & LOCK_SH) || (flags & LOCK_EX));
+ if (flags & LOCK_SH)
+ {
+ assert (box->type != LOCK_EX);
+ *user = LOCK_SH;
+ box->type = LOCK_SH;
+ box->shcount++;
+ }
+ else if (flags & LOCK_EX)
+ {
+ /* Wait for any shared (and exclusive) locks to finish. */
+ while (box->type != LOCK_UN)
+ {
+ if (flags & LOCK_NB)
+ return EWOULDBLOCK;
+ else
+ {
+ box->waiting = 1;
+ if (pthread_hurd_cond_wait_np (&box->wait, mut))
+ return EINTR;
+ }
+ }
+ box->type = LOCK_EX;
+ *user = LOCK_EX;
+ }
+ }
+ return 0;
+}
diff --git a/libfshelp/lock-init.c b/libfshelp/lock-init.c
new file mode 100644
index 00000000..66046aaa
--- /dev/null
+++ b/libfshelp/lock-init.c
@@ -0,0 +1,32 @@
+/*
+ Copyright (C) 1993, 1994 Free Software Foundation
+
+This file is part of the GNU Hurd.
+
+The GNU Hurd 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, or (at your option)
+any later version.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with the GNU Hurd; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Written by Michael I. Bushnell. */
+
+#include "locks.h"
+
+/* Initialize a lock box. */
+void
+fshelp_lock_init (struct lock_box *box)
+{
+ box->type = LOCK_UN;
+ pthread_cond_init (&box->wait, NULL);
+ box->waiting = 0;
+ box->shcount = 0;
+}
diff --git a/libfshelp/locks.h b/libfshelp/locks.h
new file mode 100644
index 00000000..a950f610
--- /dev/null
+++ b/libfshelp/locks.h
@@ -0,0 +1,28 @@
+/*
+ Copyright (C) 1994 Free Software Foundation
+
+This file is part of the GNU Hurd.
+
+The GNU Hurd 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, or (at your option)
+any later version.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with the GNU Hurd; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Written by Michael I. Bushnell. */
+
+#include <mach.h>
+#include <hurd.h>
+#include <pthread.h>
+#include <hurd/ports.h>
+#include "fshelp.h"
+#include <sys/file.h>
+#include <assert.h>
diff --git a/libfshelp/perms-access.c b/libfshelp/perms-access.c
new file mode 100644
index 00000000..67e52812
--- /dev/null
+++ b/libfshelp/perms-access.c
@@ -0,0 +1,43 @@
+/*
+ Copyright (C) 1999 Free Software Foundation, Inc.
+ Written by Thomas Bushnell, BSG.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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, or (at
+ your option) any later version.
+
+ 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.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+
+#include "fshelp.h"
+
+/* Check to see whether the user USER can operate on a file identified
+ by ST. OP is one of S_IREAD, S_IWRITE, and S_IEXEC. If the access
+ is permitted, return zero; otherwise return an appropriate error
+ code. */
+error_t
+fshelp_access (struct stat *st, int op, struct iouser *user)
+{
+ int gotit;
+ if (idvec_contains (user->uids, 0))
+ gotit = (op != S_IEXEC) || !S_ISREG(st->st_mode) || (st->st_mode & (S_IXUSR | S_IXGRP | S_IXOTH));
+ else if (user->uids->num == 0 && (st->st_mode & S_IUSEUNK))
+ gotit = st->st_mode & (op << S_IUNKSHIFT);
+ else if (!fshelp_isowner (st, user))
+ gotit = st->st_mode & op;
+ else if (idvec_contains (user->gids, st->st_gid))
+ gotit = st->st_mode & (op >> 3);
+ else
+ gotit = st->st_mode & (op >> 6);
+ return gotit ? 0 : EACCES;
+}
diff --git a/libfshelp/perms-checkdirmod.c b/libfshelp/perms-checkdirmod.c
new file mode 100644
index 00000000..823c9f63
--- /dev/null
+++ b/libfshelp/perms-checkdirmod.c
@@ -0,0 +1,44 @@
+/*
+ Copyright (C) 1999 Free Software Foundation, Inc.
+ Written by Thomas Bushnell, BSG.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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, or (at
+ your option) any later version.
+
+ 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.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+
+#include "fshelp.h"
+
+/* Check to see whether USER is allowed to modify DIR with respect to
+ existing file ST. (If there is no existing file, pass 0 for ST.)
+ If the access is permissible return 0; otherwise return an
+ appropriate error code. */
+error_t
+fshelp_checkdirmod (struct stat *dir, struct stat *st, struct iouser *user)
+{
+ error_t err;
+
+ /* The user must be able to write the directory. */
+ err = fshelp_access (dir, S_IWRITE, user);
+ if (err)
+ return err;
+
+ /* If the directory is sticky, the user must own either it or the file. */
+ if ((dir->st_mode & S_ISVTX) && st
+ && fshelp_isowner (dir, user) && fshelp_isowner (st, user))
+ return EACCES;
+
+ return 0;
+}
diff --git a/libfshelp/perms-iscontroller.c b/libfshelp/perms-iscontroller.c
new file mode 100644
index 00000000..0adfdf22
--- /dev/null
+++ b/libfshelp/perms-iscontroller.c
@@ -0,0 +1,38 @@
+/* see whether a user should be considered a controller of the filesystem
+ Copyright (C) 2001, 2008 Free Software Foundation, Inc.
+ Written by Neal H Walfield <neal@cs.uml.edu>.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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, or (at
+ your option) any later version.
+
+ 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.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <unistd.h>
+#include "fshelp.h"
+
+/* Check to see whether USER should be considered a controller of the
+ filesystem. Which is to say, check to see if we should give USER the
+ control port. ST is the stat of the root node. USER is the user
+ asking for a send right to the control port. */
+error_t
+fshelp_iscontroller (struct stat *st, struct iouser *user)
+{
+ /* Permitted if USER has the superuser uid, the owner uid or if the
+ USER has authority over the process's effective id. */
+ if (idvec_contains (user->uids, 0)
+ || idvec_contains (user->uids, st->st_uid)
+ || idvec_contains (user->uids, geteuid ()))
+ return 0;
+ return EPERM;
+}
diff --git a/libfshelp/perms-isowner.c b/libfshelp/perms-isowner.c
new file mode 100644
index 00000000..d1975993
--- /dev/null
+++ b/libfshelp/perms-isowner.c
@@ -0,0 +1,39 @@
+/*
+ Copyright (C) 1999 Free Software Foundation, Inc.
+ Written by Thomas Bushnell, BSG.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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, or (at
+ your option) any later version.
+
+ 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.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include "fshelp.h"
+
+/* Check to see whether USER should be considered the owner of the
+ file identified by ST. If so, return zero; otherwise return an
+ appropriate error code. */
+error_t
+fshelp_isowner (struct stat *st, struct iouser *user)
+{
+ /* Permitted if the user has the owner UID, the superuser UID, or if
+ the user is in the group of the file and has the group ID as
+ their user ID. */
+ if (idvec_contains (user->uids, st->st_uid)
+ || idvec_contains (user->uids, 0)
+ || (idvec_contains (user->gids, st->st_gid)
+ && idvec_contains (user->uids, st->st_gid)))
+ return 0;
+ else
+ return EPERM;
+}
diff --git a/libfshelp/set-active.c b/libfshelp/set-active.c
new file mode 100644
index 00000000..00f2a186
--- /dev/null
+++ b/libfshelp/set-active.c
@@ -0,0 +1,62 @@
+/*
+ Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Written by Michael I. Bushnell.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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, or (at
+ your option) any later version.
+
+ 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.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "fshelp.h"
+#include <hurd/fsys.h>
+
+error_t
+fshelp_set_active (struct transbox *box,
+ mach_port_t active,
+ int excl)
+{
+ int cancel;
+
+ if (excl)
+ {
+ if (box->flags & TRANSBOX_STARTING)
+ return EBUSY;
+ if (box->active != MACH_PORT_NULL)
+ /* It looks like there's an existing translator, but make sure. */
+ {
+ mach_port_urefs_t dead_refs;
+ error_t err =
+ mach_port_get_refs (mach_task_self (),
+ box->active, MACH_PORT_RIGHT_DEAD_NAME,
+ &dead_refs);
+ if (!err && dead_refs == 0)
+ /* Still active, we lose. */
+ return EBUSY;
+ }
+ }
+
+ while (box->flags & TRANSBOX_STARTING)
+ {
+ box->flags |= TRANSBOX_WANTED;
+ cancel = pthread_hurd_cond_wait_np (&box->wakeup, box->lock);
+ if (cancel)
+ return EINTR;
+ }
+
+ if (box->active != MACH_PORT_NULL)
+ mach_port_deallocate (mach_task_self (), box->active);
+
+ box->active = active;
+ return 0;
+}
diff --git a/libfshelp/set-options.c b/libfshelp/set-options.c
new file mode 100644
index 00000000..a627b841
--- /dev/null
+++ b/libfshelp/set-options.c
@@ -0,0 +1,47 @@
+/* Standard filesystem runtime option parsing
+
+ Copyright (C) 1996, 1998, 1999 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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, or (at
+ your option) any later version.
+
+ 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.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <mach.h>
+#include <argp.h>
+#include <argz.h>
+#include <alloca.h>
+
+#include "fshelp.h"
+
+/* XXX this is not currently so useful, but the new fsys_set_options will
+ have more commonly used code that can be put here. */
+
+/* Invoke ARGP with data from DATA & LEN, in the standard way. */
+error_t
+fshelp_set_options (const struct argp *argp, int flags,
+ const char *argz, size_t argz_len, void *input)
+{
+ int argc = argz_count (argz, argz_len);
+ char **argv = alloca (sizeof (char *) * (argc + 1));
+
+ argz_extract ((char *) argz, argz_len, argv);
+
+ return
+ argp_parse (argp, argc, argv,
+ flags | ARGP_NO_ERRS | ARGP_NO_HELP | ARGP_PARSE_ARGV0,
+ 0, input);
+}
diff --git a/libfshelp/start-translator-long.c b/libfshelp/start-translator-long.c
new file mode 100644
index 00000000..64a20bed
--- /dev/null
+++ b/libfshelp/start-translator-long.c
@@ -0,0 +1,328 @@
+/*
+ Copyright (C) 1995,96,99,2000,02, 04 Free Software Foundation, Inc.
+ Written by Miles Bader and Michael I. Bushnell.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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, or (at
+ your option) any later version.
+
+ 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.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <hurd.h>
+#include <mach/notify.h>
+#include <mach.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <assert.h>
+#include "fshelp.h"
+
+
+/* The data passed in the various messages we're interested in. */
+struct fsys_startup_request
+{
+ mach_msg_header_t head;
+ mach_msg_type_t flagsType;
+ int flags;
+ mach_msg_type_t control_portType;
+ mach_port_t control_port;
+};
+
+struct fsys_startup_reply
+{
+ mach_msg_header_t head;
+ mach_msg_type_t RetCodeType;
+ kern_return_t RetCode;
+ mach_msg_type_t realnodeType;
+ mach_port_t realnode;
+};
+
+/* Wait around for an fsys_startup message on the port PORT from the
+ translator on NODE (timing out after TIMEOUT milliseconds), and return a
+ send right for the resulting fsys control port in CONTROL. If a no-senders
+ notification is received on PORT, then it will be assumed that the
+ translator died, and EDIED will be returned. If an error occurs, the
+ error code is returned, otherwise 0. */
+static error_t
+service_fsys_startup (fshelp_open_fn_t underlying_open_fn, void *cookie,
+ mach_port_t port, long timeout, fsys_t *control,
+ task_t task)
+{
+ /* These should be optimized away to pure integer constants. */
+ const mach_msg_type_t flagsCheck =
+ {
+ MACH_MSG_TYPE_INTEGER_32, /* msgt_name = */
+ 32, /* msgt_size = */
+ 1, /* msgt_number = */
+ TRUE, /* msgt_inline = */
+ FALSE, /* msgt_longform = */
+ FALSE, /* msgt_deallocate = */
+ 0 /* msgt_unused = */
+ };
+ const mach_msg_type_t control_portCheck =
+ {
+ MACH_MSG_TYPE_PORT_SEND, /* msgt_name = */
+ 32, /* msgt_size = */
+ 1, /* msgt_number = */
+ TRUE, /* msgt_inline = */
+ FALSE, /* msgt_longform = */
+ FALSE, /* msgt_deallocate = */
+ 0 /* msgt_unused = */
+ };
+ const mach_msg_type_t RetCodeType =
+ {
+ MACH_MSG_TYPE_INTEGER_32, /* msgt_name = */
+ 32, /* msgt_size = */
+ 1, /* msgt_number = */
+ TRUE, /* msgt_inline = */
+ FALSE, /* msgt_longform = */
+ FALSE, /* msgt_deallocate = */
+ 0 /* msgt_unused = */
+ };
+ const mach_msg_type_t realnodeType =
+ {
+ -1, /* msgt_name = */
+ 32, /* msgt_size = */
+ 1, /* msgt_number = */
+ TRUE, /* msgt_inline = */
+ FALSE, /* msgt_longform = */
+ FALSE, /* msgt_deallocate = */
+ 0 /* msgt_unused = */
+ };
+
+ /* Return true iff TYPE fails to match CHECK. */
+ inline int type_check (const mach_msg_type_t *type,
+ const mach_msg_type_t *check)
+ {
+ union
+ {
+ unsigned32_t word;
+ mach_msg_type_t type;
+ } t, c;
+ t.type = *type;
+ c.type = *check;
+ return t.word != c.word;
+ }
+
+ error_t err;
+ union
+ {
+ mach_msg_header_t head;
+ struct fsys_startup_request startup;
+ }
+ request;
+ struct fsys_startup_reply reply;
+
+ /* Wait for the fsys_startup message... */
+ err = mach_msg (&request.head, (MACH_RCV_MSG | MACH_RCV_INTERRUPT
+ | (timeout ? MACH_RCV_TIMEOUT : 0)),
+ 0, sizeof(request), port, timeout, MACH_PORT_NULL);
+ if (err)
+ return err;
+
+ /* Check whether we actually got a no-senders notification instead. */
+ if (request.head.msgh_id == MACH_NOTIFY_NO_SENDERS)
+ return EDIED;
+
+ /* Construct our reply to the fsys_startup rpc. */
+ reply.head.msgh_size = sizeof(reply);
+ reply.head.msgh_bits =
+ MACH_MSGH_BITS(MACH_MSGH_BITS_REMOTE(request.head.msgh_bits), 0);
+ reply.head.msgh_remote_port = request.head.msgh_remote_port;
+ reply.head.msgh_local_port = MACH_PORT_NULL;
+ reply.head.msgh_seqno = 0;
+ reply.head.msgh_id = request.head.msgh_id + 100;
+ reply.RetCodeType = RetCodeType;
+
+ if (request.head.msgh_id != 22000)
+ reply.RetCode = MIG_BAD_ID;
+ else if (type_check (&request.startup.control_portType, &control_portCheck)
+ || type_check (&request.startup.flagsType, &flagsCheck))
+ reply.RetCode = MIG_BAD_ARGUMENTS;
+ else
+ {
+ mach_msg_type_name_t realnode_type;
+
+ *control = request.startup.control_port;
+
+ reply.RetCode =
+ (*underlying_open_fn) (request.startup.flags,
+ &reply.realnode, &realnode_type, task,
+ cookie);
+
+ reply.realnodeType = realnodeType;
+ reply.realnodeType.msgt_name = realnode_type;
+
+ if (!reply.RetCode && reply.realnode != MACH_PORT_NULL)
+ /* The message can't be simple because of the port. */
+ reply.head.msgh_bits |= MACH_MSGH_BITS_COMPLEX;
+ }
+
+ err = mach_msg (&reply.head, MACH_SEND_MSG | MACH_SEND_INTERRUPT,
+ sizeof(reply), 0,
+ request.head.msgh_remote_port,
+ MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
+ if (err == MACH_SEND_INTERRUPTED
+ && reply.realnodeType.msgt_name == MACH_MSG_TYPE_MOVE_SEND)
+ /* For MACH_SEND_INTERRUPTED, we'll have pseudo-received the message
+ and might have to clean up a generated send right. */
+ mach_port_deallocate (mach_task_self (), reply.realnode);
+
+ if (reply.RetCode)
+ /* Make our error return be the earlier one. */
+ err = reply.RetCode;
+
+ return err;
+}
+
+
+error_t
+fshelp_start_translator_long (fshelp_open_fn_t underlying_open_fn,
+ void *cookie, char *name, char *argz,
+ int argz_len, mach_port_t *fds,
+ mach_msg_type_name_t fds_type, int fds_len,
+ mach_port_t *ports,
+ mach_msg_type_name_t ports_type, int ports_len,
+ int *ints, int ints_len,
+ uid_t owner_uid,
+ int timeout, fsys_t *control)
+{
+ error_t err;
+ file_t executable;
+ mach_port_t bootstrap = MACH_PORT_NULL;
+ mach_port_t task = MACH_PORT_NULL;
+ mach_port_t prev_notify, proc, saveport, childproc;
+ int ports_moved = 0;
+
+ /* Find the translator itself. Since argz has zero-separated elements, we
+ can use it as a normal string representing the first element. */
+ executable = file_name_lookup(name, O_EXEC, 0);
+ if (executable == MACH_PORT_NULL)
+ return errno;
+
+ /* Create a bootstrap port for the translator. */
+ err =
+ mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &bootstrap);
+ if (err)
+ goto lose;
+
+ /* Create the task for the translator. */
+ err = task_create (mach_task_self (),
+#ifdef KERN_INVALID_LEDGER
+ NULL, 0, /* OSF Mach */
+#endif
+ 0, &task);
+ if (err)
+ goto lose;
+
+ /* XXX 25 is BASEPRI_USER, which isn't exported by the kernel. Ideally,
+ nice values should be used, perhaps with a simple wrapper to convert
+ them to Mach priorities. */
+ err = task_priority(task, 25, FALSE);
+
+ if (err)
+ goto lose;
+
+ /* Designate TASK as our child and set it's owner accordingly. */
+ proc = getproc ();
+ proc_child (proc, task);
+ err = proc_task2proc (proc, task, &childproc);
+ mach_port_deallocate (mach_task_self (), proc);
+ if (err)
+ goto lose;
+ err = proc_setowner (childproc, owner_uid, owner_uid == (uid_t) -1);
+ mach_port_deallocate (mach_task_self (), childproc);
+ if (err)
+ goto lose;
+
+ assert (ports_len > INIT_PORT_BOOTSTRAP);
+ switch (ports_type)
+ {
+ case MACH_MSG_TYPE_MAKE_SEND:
+ case MACH_MSG_TYPE_MAKE_SEND_ONCE:
+ break;
+
+ case MACH_MSG_TYPE_MOVE_SEND:
+ if (ports[INIT_PORT_BOOTSTRAP] != MACH_PORT_NULL)
+ mach_port_deallocate (mach_task_self (), ports[INIT_PORT_BOOTSTRAP]);
+ mach_port_insert_right (mach_task_self (), bootstrap, bootstrap,
+ MACH_MSG_TYPE_MAKE_SEND);
+ break;
+
+ case MACH_MSG_TYPE_COPY_SEND:
+ mach_port_insert_right (mach_task_self (), bootstrap, bootstrap,
+ MACH_MSG_TYPE_MAKE_SEND);
+ break;
+
+ default:
+ abort ();
+ }
+
+ saveport = ports[INIT_PORT_BOOTSTRAP];
+ ports[INIT_PORT_BOOTSTRAP] = bootstrap;
+
+ /* Try and exec the translator in TASK... */
+ err = file_exec (executable, task, EXEC_DEFAULTS,
+ argz, argz_len, 0, 0,
+ fds, fds_type, fds_len,
+ ports, ports_type, ports_len,
+ ints, ints_len, 0, 0, 0, 0);
+ ports_moved = 1;
+
+ if (ports_type == MACH_MSG_TYPE_COPY_SEND)
+ mach_port_deallocate (mach_task_self (), bootstrap);
+ ports[INIT_PORT_BOOTSTRAP] = saveport;
+
+ if (err)
+ goto lose_task;
+
+ /* Ask to be told if TASK dies. */
+ err =
+ mach_port_request_notification(mach_task_self(),
+ bootstrap, MACH_NOTIFY_NO_SENDERS, 0,
+ bootstrap, MACH_MSG_TYPE_MAKE_SEND_ONCE,
+ &prev_notify);
+ if (err)
+ goto lose_task;
+
+ /* Ok, cool, we've got a running(?) program, now rendezvous with it if
+ possible using the startup protocol on the bootstrap port... */
+ err = service_fsys_startup(underlying_open_fn, cookie, bootstrap,
+ timeout, control, task);
+
+ lose_task:
+ if (err)
+ task_terminate (task);
+
+ lose:
+ if (!ports_moved)
+ {
+ int i;
+
+ if (fds_type == MACH_MSG_TYPE_MOVE_SEND)
+ for (i = 0; i < fds_len; i++)
+ mach_port_deallocate (mach_task_self (), fds[i]);
+ if (ports_type == MACH_MSG_TYPE_MOVE_SEND)
+ for (i = 0; i < ports_len; i++)
+ mach_port_deallocate (mach_task_self (), ports[i]);
+ }
+ if (bootstrap != MACH_PORT_NULL)
+ mach_port_destroy(mach_task_self(), bootstrap);
+ if (executable != MACH_PORT_NULL)
+ mach_port_deallocate(mach_task_self(), executable);
+ if (task != MACH_PORT_NULL)
+ mach_port_deallocate(mach_task_self(), task);
+
+ return err;
+}
diff --git a/libfshelp/start-translator.c b/libfshelp/start-translator.c
new file mode 100644
index 00000000..ba5418ec
--- /dev/null
+++ b/libfshelp/start-translator.c
@@ -0,0 +1,63 @@
+/*
+ Copyright (C) 1995, 1996, 1999 Free Software Foundation, Inc.
+ Written by Michael I. Bushnell.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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, or (at
+ your option) any later version.
+
+ 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.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "fshelp.h"
+#include <unistd.h>
+#include <string.h>
+#include <hurd.h>
+
+error_t
+fshelp_start_translator (fshelp_open_fn_t underlying_open_fn,
+ void *cookie, char *name, char *argz,
+ int argz_len, int timeout, fsys_t *control)
+{
+ mach_port_t ports[INIT_PORT_MAX];
+ mach_port_t fds[STDERR_FILENO + 1];
+ int ints[INIT_INT_MAX];
+ int i;
+ error_t err;
+
+ for (i = 0; i < INIT_PORT_MAX; i++)
+ ports[i] = MACH_PORT_NULL;
+ for (i = 0; i < STDERR_FILENO + 1; i++)
+ fds[i] = MACH_PORT_NULL;
+ bzero (ints, INIT_INT_MAX * sizeof (int));
+
+ ports[INIT_PORT_CWDIR] = getcwdir ();
+ ports[INIT_PORT_CRDIR] = getcrdir ();
+ ports[INIT_PORT_AUTH] = getauth ();
+ fds[STDERR_FILENO] = getdport (STDERR_FILENO);
+
+ err = fshelp_start_translator_long (underlying_open_fn, cookie,
+ name, argz, argz_len,
+ fds, MACH_MSG_TYPE_COPY_SEND,
+ STDERR_FILENO + 1,
+ ports, MACH_MSG_TYPE_COPY_SEND,
+ INIT_PORT_MAX,
+ ints, INIT_INT_MAX,
+ geteuid (),
+ timeout, control);
+ for (i = 0; i < INIT_PORT_MAX; i++)
+ mach_port_deallocate (mach_task_self (), ports[i]);
+ for (i = 0; i <= STDERR_FILENO; i++)
+ mach_port_deallocate (mach_task_self (), fds[i]);
+
+ return err;
+}
diff --git a/libfshelp/touch.c b/libfshelp/touch.c
new file mode 100644
index 00000000..00d90edd
--- /dev/null
+++ b/libfshelp/touch.c
@@ -0,0 +1,49 @@
+/*
+ Copyright (C) 1999, 2007 Free Software Foundation, Inc.
+
+ Written by Thomas Bushnell, BSG.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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, or (at
+ your option) any later version.
+
+ 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.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include "fshelp.h"
+
+/* Change the stat times of NODE as indicated by WHAT (from the set TOUCH_*)
+ to the current time. */
+void
+fshelp_touch (struct stat *st, unsigned what,
+ volatile struct mapped_time_value *maptime)
+{
+ struct timeval tv;
+
+ maptime_read (maptime, &tv);
+
+ if (what & TOUCH_ATIME)
+ {
+ st->st_atim.tv_sec = tv.tv_sec;
+ st->st_atim.tv_nsec = tv.tv_usec * 1000;
+ }
+ if (what & TOUCH_CTIME)
+ {
+ st->st_ctim.tv_sec = tv.tv_sec;
+ st->st_ctim.tv_nsec = tv.tv_usec * 1000;
+ }
+ if (what & TOUCH_MTIME)
+ {
+ st->st_mtim.tv_sec = tv.tv_sec;
+ st->st_mtim.tv_nsec = tv.tv_usec * 1000;
+ }
+}
diff --git a/libfshelp/trans.h b/libfshelp/trans.h
new file mode 100644
index 00000000..a9ea6487
--- /dev/null
+++ b/libfshelp/trans.h
@@ -0,0 +1,32 @@
+/*
+ Copyright (C) 1994 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
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program 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.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <mach.h>
+#include <hurd.h>
+#include <pthread.h>
+#include <hurd/ports.h>
+#include "fshelp.h"
+
+struct transboot
+{
+ struct port_info pi;
+ file_t node;
+ struct trans_link *link;
+};
+
+pthread_spinlock_t _fshelp_translistlock;
+struct trans_link *_fshelp_translist;
diff --git a/libfshelp/transbox-init.c b/libfshelp/transbox-init.c
new file mode 100644
index 00000000..11a1ab41
--- /dev/null
+++ b/libfshelp/transbox-init.c
@@ -0,0 +1,34 @@
+/*
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Written by Michael I. Bushnell.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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, or (at
+ your option) any later version.
+
+ 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.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "fshelp.h"
+#include <pthread.h>
+
+void
+fshelp_transbox_init (struct transbox *transbox,
+ pthread_mutex_t *lock,
+ void *cookie)
+{
+ transbox->active = MACH_PORT_NULL;
+ transbox->flags = 0;
+ transbox->lock = lock;
+ pthread_cond_init (&transbox->wakeup, NULL);
+ transbox->cookie = cookie;
+}
diff --git a/libfshelp/translated.c b/libfshelp/translated.c
new file mode 100644
index 00000000..2dc724b6
--- /dev/null
+++ b/libfshelp/translated.c
@@ -0,0 +1,28 @@
+/*
+ Copyright (C) 1999 Free Software Foundation, Inc.
+ Written by Thomas Bushnell, BSG.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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, or (at
+ your option) any later version.
+
+ 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.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include "fshelp.h"
+
+/* Return true iff there is an active translator on this box */
+int
+fshelp_translated (struct transbox *box)
+{
+ return (box->active != MACH_PORT_NULL);
+}
diff --git a/libfshelp/translator-list.c b/libfshelp/translator-list.c
new file mode 100644
index 00000000..3ece7112
--- /dev/null
+++ b/libfshelp/translator-list.c
@@ -0,0 +1,202 @@
+/* A list of active translators.
+
+ Copyright (C) 2013,14 Free Software Foundation, Inc.
+
+ Written by Justus Winter <4winter@informatik.uni-hamburg.de>
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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, or (at
+ your option) any later version.
+
+ 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.
+
+ You should have received a copy of the GNU General Public License
+ along with the GNU Hurd. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <argz.h>
+#include <hurd/fsys.h>
+#include <hurd/ihash.h>
+#include <hurd/ports.h>
+#include <mach.h>
+#include <mach/notify.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libgen.h>
+
+#include "fshelp.h"
+
+struct translator
+{
+ struct port_info *pi;
+ char *name;
+ mach_port_t active;
+};
+
+/* The list of active translators. */
+static struct hurd_ihash translator_ihash
+ = HURD_IHASH_INITIALIZER (HURD_IHASH_NO_LOCP);
+
+/* The lock protecting the translator_ihash. */
+static pthread_mutex_t translator_ihash_lock = PTHREAD_MUTEX_INITIALIZER;
+
+static void
+translator_ihash_cleanup (void *element, void *arg)
+{
+ struct translator *translator = element;
+
+ if (translator->pi)
+ ports_port_deref (translator->pi);
+ /* No need to deallocate translator->active, we only keep the name of
+ the port, not a reference. */
+ free (translator->name);
+ free (translator);
+}
+
+/* Record an active translator being bound to the given file name
+ NAME. ACTIVE is the control port of the translator. */
+error_t
+fshelp_set_active_translator (struct port_info *pi,
+ const char *name,
+ mach_port_t active)
+{
+ error_t err = 0;
+ pthread_mutex_lock (&translator_ihash_lock);
+
+ if (! translator_ihash.cleanup)
+ hurd_ihash_set_cleanup (&translator_ihash, translator_ihash_cleanup, NULL);
+
+ struct translator *t = NULL;
+ HURD_IHASH_ITERATE (&translator_ihash, value)
+ {
+ t = value;
+ if (strcmp (name, t->name) == 0)
+ goto update; /* Entry exists. */
+ }
+
+ t = malloc (sizeof (struct translator));
+ if (! t)
+ return ENOMEM;
+
+ t->active = MACH_PORT_NULL;
+ t->pi = NULL;
+ t->name = strdup (name);
+ if (! t->name)
+ {
+ err = errno;
+ free (t);
+ goto out;
+ }
+
+ err = hurd_ihash_add (&translator_ihash, (hurd_ihash_key_t) t, t);
+ if (err)
+ goto out;
+
+ update:
+ if (active)
+ {
+ if (t->pi != pi)
+ {
+ mach_port_t old;
+ err = mach_port_request_notification (mach_task_self (), active,
+ MACH_NOTIFY_DEAD_NAME, 0,
+ pi->port_right,
+ MACH_MSG_TYPE_MAKE_SEND_ONCE,
+ &old);
+ if (err)
+ return err;
+ if (old != MACH_PORT_NULL)
+ mach_port_deallocate (mach_task_self (), old);
+
+ if (t->pi)
+ ports_port_deref (t->pi);
+
+ ports_port_ref (pi);
+ t->pi = pi;
+ }
+
+ /* No need to increment the reference count, we only keep the
+ name, not a reference. */
+ t->active = active;
+ }
+ else
+ hurd_ihash_remove (&translator_ihash, (hurd_ihash_key_t) t);
+
+ out:
+ pthread_mutex_unlock (&translator_ihash_lock);
+ return err;
+}
+
+/* Remove the active translator specified by its control port ACTIVE.
+ If there is no active translator with the given control port, this
+ does nothing. */
+error_t
+fshelp_remove_active_translator (mach_port_t active)
+{
+ error_t err = 0;
+ pthread_mutex_lock (&translator_ihash_lock);
+
+ struct translator *t = NULL;
+ HURD_IHASH_ITERATE (&translator_ihash, value)
+ {
+ struct translator *v = value;
+ if (active == v->active)
+ {
+ t = v;
+ break;
+ }
+ }
+
+ if (t)
+ hurd_ihash_remove (&translator_ihash, (hurd_ihash_key_t) t);
+
+ pthread_mutex_unlock (&translator_ihash_lock);
+ return err;
+}
+
+/* Records the list of active translators into the argz vector
+ specified by TRANSLATORS filtered by FILTER. */
+error_t
+fshelp_get_active_translators (char **translators,
+ size_t *translators_len,
+ fshelp_filter filter)
+{
+ error_t err = 0;
+ pthread_mutex_lock (&translator_ihash_lock);
+
+ HURD_IHASH_ITERATE (&translator_ihash, value)
+ {
+ struct translator *t = value;
+ if (filter)
+ {
+ char *dir = strdup (t->name);
+ if (! dir)
+ {
+ err = ENOMEM;
+ break;
+ }
+
+ err = filter (dirname (dir));
+ free (dir);
+ if (err)
+ {
+ err = 0;
+ continue; /* Skip this entry. */
+ }
+ }
+
+ err = argz_add (translators, translators_len,
+ t->name);
+ if (err)
+ break;
+ }
+
+ pthread_mutex_unlock (&translator_ihash_lock);
+ return err;
+}