diff options
Diffstat (limited to 'libfshelp')
-rw-r--r-- | libfshelp/Makefile | 40 | ||||
-rw-r--r-- | libfshelp/delegate.c | 64 | ||||
-rw-r--r-- | libfshelp/drop-transbox.c | 28 | ||||
-rw-r--r-- | libfshelp/exec-reauth.c | 152 | ||||
-rw-r--r-- | libfshelp/fetch-control.c | 31 | ||||
-rw-r--r-- | libfshelp/fetch-root.c | 195 | ||||
-rw-r--r-- | libfshelp/fshelp.h | 308 | ||||
-rw-r--r-- | libfshelp/get-identity.c | 92 | ||||
-rw-r--r-- | libfshelp/lock-acquire.c | 131 | ||||
-rw-r--r-- | libfshelp/lock-init.c | 32 | ||||
-rw-r--r-- | libfshelp/locks.h | 28 | ||||
-rw-r--r-- | libfshelp/perms-access.c | 43 | ||||
-rw-r--r-- | libfshelp/perms-checkdirmod.c | 44 | ||||
-rw-r--r-- | libfshelp/perms-iscontroller.c | 38 | ||||
-rw-r--r-- | libfshelp/perms-isowner.c | 39 | ||||
-rw-r--r-- | libfshelp/set-active.c | 62 | ||||
-rw-r--r-- | libfshelp/set-options.c | 47 | ||||
-rw-r--r-- | libfshelp/start-translator-long.c | 328 | ||||
-rw-r--r-- | libfshelp/start-translator.c | 63 | ||||
-rw-r--r-- | libfshelp/touch.c | 49 | ||||
-rw-r--r-- | libfshelp/trans.h | 32 | ||||
-rw-r--r-- | libfshelp/transbox-init.c | 34 | ||||
-rw-r--r-- | libfshelp/translated.c | 28 | ||||
-rw-r--r-- | libfshelp/translator-list.c | 202 |
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; +} |