summaryrefslogtreecommitdiff
path: root/debian/patches/gpg0001-trans-add-identity-translator.patch
diff options
context:
space:
mode:
authorJustus Winter <justus@gnupg.org>2016-04-18 22:38:48 +0200
committerJustus Winter <justus@gnupg.org>2016-04-18 22:38:48 +0200
commit138c3d1bfb236529b102514dd05a4678e430e11c (patch)
treedb5ea601d682d2ea5e1b8d2c921819641ca8b414 /debian/patches/gpg0001-trans-add-identity-translator.patch
parentdb77785f901694a15c0d62c82f7cb742105b9088 (diff)
add patch series
Diffstat (limited to 'debian/patches/gpg0001-trans-add-identity-translator.patch')
-rw-r--r--debian/patches/gpg0001-trans-add-identity-translator.patch941
1 files changed, 941 insertions, 0 deletions
diff --git a/debian/patches/gpg0001-trans-add-identity-translator.patch b/debian/patches/gpg0001-trans-add-identity-translator.patch
new file mode 100644
index 00000000..6e1b3187
--- /dev/null
+++ b/debian/patches/gpg0001-trans-add-identity-translator.patch
@@ -0,0 +1,941 @@
+From 7e72e8a337c58e6cb6badff8be4381dc180d8277 Mon Sep 17 00:00:00 2001
+From: Justus Winter <4winter@informatik.uni-hamburg.de>
+Date: Sat, 23 Jan 2016 00:14:56 +0100
+Subject: [PATCH hurd 1/4] trans: add identity translator
+
+The 'identity' translator is the simplest possible translator. It
+computes the identity function of Hurdish RPC translations.
+
+* trans/Makefile: Add new files.
+* trans/chroot.c: New file.
+* trans/chroot.h: Likewise.
+* trans/identity.c: Likewise.
+---
+ trans/Makefile | 7 +-
+ trans/chroot.c | 724 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ trans/chroot.h | 34 +++
+ trans/identity.c | 113 +++++++++
+ 4 files changed, 875 insertions(+), 3 deletions(-)
+ create mode 100644 trans/chroot.c
+ create mode 100644 trans/chroot.h
+ create mode 100644 trans/identity.c
+
+diff --git a/trans/Makefile b/trans/Makefile
+index 65b51d1..e4eba0a 100644
+--- a/trans/Makefile
++++ b/trans/Makefile
+@@ -21,10 +21,10 @@ makemode := servers
+
+ targets = symlink firmlink ifsock magic null fifo new-fifo fwd crash \
+ password hello hello-mt streamio fakeroot proxy-defpager remap \
+- mtab
++ mtab identity
+ SRCS = ifsock.c symlink.c magic.c null.c fifo.c new-fifo.c fwd.c \
+ crash.c firmlink.c password.c hello.c hello-mt.c streamio.c \
+- fakeroot.c proxy-defpager.c remap.c mtab.c
++ fakeroot.c proxy-defpager.c remap.c mtab.c chroot.c identity.c
+ OBJS = $(SRCS:.c=.o) fsysServer.o ifsockServer.o passwordServer.o \
+ crashServer.o crash_replyUser.o msgServer.o \
+ default_pagerServer.o default_pagerUser.o \
+@@ -65,7 +65,8 @@ proxy-defpager: default_pagerServer.o default_pagerUser.o
+ streamio: device_replyServer.o
+ symlink: fsysServer.o
+
+-fakeroot: ../libnetfs/libnetfs.a
++identity: chroot.o
++fakeroot identity: ../libnetfs/libnetfs.a
+ fifo new-fifo: ../libpipe/libpipe.a
+ crash fifo firmlink hello hello-mt ifsock magic mtab new-fifo null password proxy-defpager remap streamio: ../libtrivfs/libtrivfs.a
+ $(targets): ../libfshelp/libfshelp.a \
+diff --git a/trans/chroot.c b/trans/chroot.c
+new file mode 100644
+index 0000000..0055d6c
+--- /dev/null
++++ b/trans/chroot.c
+@@ -0,0 +1,724 @@
++/* chroot.c -- support for writing chrooting translators
++ Copyright (C) 2002, 2003, 2008, 2013, 2016 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
++
++#include <argz.h>
++#include <argp.h>
++#include <dirent.h>
++#include <error.h>
++#include <hurd/netfs.h>
++#include <stddef.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <fcntl.h>
++#include <sys/mman.h>
++#include <sys/stat.h>
++#include <pthread.h>
++#include <hurd/ihash.h>
++#include <hurd/paths.h>
++#include <sys/types.h>
++#include <sys/wait.h>
++#include <unistd.h>
++
++#include <version.h>
++
++#include "chroot.h"
++
++#include "libnetfs/fs_S.h"
++#include "libnetfs/io_S.h"
++#include "libnetfs/fsys_S.h"
++#include "libports/notify_S.h"
++#include "libports/interrupt_S.h"
++
++/* Make a new virtual node. Always consumes the ports. If
++ successful, NP will be locked. */
++error_t __attribute__ ((weak))
++chroot_new_node (file_t file, size_t size, struct node **np)
++{
++ error_t err;
++ struct netnode *nn;
++
++ *np = netfs_make_node_alloc (sizeof *nn + size);
++ if (*np == NULL)
++ {
++ mach_port_deallocate (mach_task_self (), file);
++ return ENOMEM;
++ }
++ nn = netfs_node_netnode (*np);
++ nn->file = file;
++ return 0;
++}
++
++/* Node NP has no more references; free all its associated storage. */
++void
++netfs_node_norefs (struct node *np)
++{
++ pthread_mutex_unlock (&np->lock);
++
++ chroot_node_norefs (np);
++ mach_port_deallocate (mach_task_self (), netfs_node_netnode (np)->file);
++ free (np);
++}
++
++/* This is the cleanup function we install in netfs_protid_class. If
++ the associated nodes reference count would also drop to zero, and
++ the node has no faked attributes, we destroy it as well. */
++static void
++chroot_netfs_release_protid (void *cookie)
++{
++ netfs_release_protid (cookie);
++
++ int cports = ports_count_class (netfs_control_class);
++ int nports = ports_count_class (netfs_protid_class);
++ ports_enable_class (netfs_control_class);
++ ports_enable_class (netfs_protid_class);
++ if (cports == 0 && nports == 0)
++ {
++ /* The last client is gone. Our job is done. */
++ error_t err = netfs_shutdown (0);
++ if (! err)
++ exit (EXIT_SUCCESS);
++
++ /* If netfs_shutdown returns EBUSY, we lost a race against
++ fsys_goaway. Hence we ignore this error. */
++ if (err != EBUSY)
++ error (1, err, "netfs_shutdown");
++ }
++}
++
++error_t __attribute__ ((weak))
++chroot_init (void)
++{
++ /* Install our own clean routine. */
++ netfs_protid_class->clean_routine = chroot_netfs_release_protid;
++ return 0;
++}
++
++/* This is called by netfs_S_fsys_getroot. */
++error_t __attribute__ ((weak))
++netfs_check_open_permissions (struct iouser *user, struct node *np,
++ int flags, int newnode)
++{
++ return 0; /* XXX */
++}
++
++error_t __attribute__ ((weak))
++netfs_S_dir_lookup (struct protid *diruser,
++ char *filename,
++ int flags,
++ mode_t mode,
++ retry_type *do_retry,
++ char *retry_name,
++ mach_port_t *retry_port,
++ mach_msg_type_name_t *retry_port_type)
++{
++ struct node *dnp, *np;
++ error_t err;
++ struct protid *newpi;
++ struct iouser *user;
++ file_t file;
++ file_t dir;
++
++ if (!diruser)
++ return EOPNOTSUPP;
++
++ dnp = diruser->po->np;
++
++ //error (0, 0, "dir_lookup (#uids: %d, %s, flags %x, ...)", diruser->user->uids->num, filename, flags);
++
++ dir = netfs_node_netnode (dnp)->file;
++ err = dir_lookup (dir, filename, flags, mode, do_retry, retry_name, &file);
++ if (err)
++ return err;
++
++ switch (*do_retry)
++ {
++ case FS_RETRY_NORMAL:
++ break;
++
++ case FS_RETRY_REAUTH:
++ /* Fallthrough. */
++
++ case FS_RETRY_MAGICAL:
++ *retry_port = file;
++ *retry_port_type = MACH_MSG_TYPE_MOVE_SEND;
++ return 0;
++
++ default:
++ /* Invalid response to our dir_lookup request. */
++ if (MACH_PORT_VALID (file))
++ mach_port_deallocate (mach_task_self (), file);
++ *retry_port = MACH_PORT_NULL;
++ *retry_port_type = MACH_MSG_TYPE_COPY_SEND;
++ return EOPNOTSUPP;
++ }
++
++ /* We have a new port to an underlying node.
++ Find or make our corresponding virtual node. */
++
++ np = 0;
++
++ err = chroot_new_node (file, 0, &np);
++ if (!err)
++ err = netfs_validate_stat (np, diruser->user);
++ if (err)
++ goto lose;
++
++ assert (*do_retry == FS_RETRY_NORMAL);
++ flags &= ~(O_CREAT|O_EXCL|O_NOLINK|O_NOTRANS|O_NONBLOCK);
++
++ err = iohelp_dup_iouser (&user, diruser->user);
++ if (!err)
++ {
++ newpi = netfs_make_protid (netfs_make_peropen (np, flags, diruser->po),
++ user);
++ if (! newpi)
++ {
++ iohelp_free_iouser (user);
++ err = errno;
++ }
++ else
++ {
++ *retry_port = ports_get_right (newpi);
++ *retry_port_type = MACH_MSG_TYPE_MAKE_SEND;
++ ports_port_deref (newpi);
++ }
++ }
++
++ lose:
++ if (dir != netfs_node_netnode (dnp)->file)
++ mach_port_deallocate (mach_task_self (), dir);
++ if (np != NULL)
++ netfs_nput (np);
++ return err;
++}
++
++/* The user may define this function. Attempt to set the passive
++ translator record for FILE to ARGZ (of length ARGZLEN) for user
++ CRED. */
++error_t __attribute__ ((weak))
++netfs_set_translator (struct iouser *cred, struct node *np,
++ char *argz, size_t argzlen)
++{
++ return file_set_translator (netfs_node_netnode (np)->file,
++ FS_TRANS_EXCL|FS_TRANS_SET,
++ 0, 0,
++ argz, argzlen,
++ MACH_PORT_NULL, MACH_MSG_TYPE_COPY_SEND);
++}
++
++/* These callbacks are used only by the standard netfs_S_dir_lookup,
++ which we do not use. But the shared library requires us to define them. */
++error_t __attribute__ ((weak))
++netfs_attempt_lookup (struct iouser *user, struct node *dir,
++ char *name, struct node **np)
++{
++ assert (! "should not be here");
++ return EIEIO;
++}
++
++error_t __attribute__ ((weak))
++netfs_attempt_create_file (struct iouser *user, struct node *dir,
++ char *name, mode_t mode, struct node **np)
++{
++ assert (! "should not be here");
++ return EIEIO;
++}
++
++/* Make sure that NP->nn_stat is filled with the most current information.
++ CRED identifies the user responsible for the operation. NP is locked. */
++error_t __attribute__ ((weak))
++netfs_validate_stat (struct node *np, struct iouser *cred)
++{
++ struct stat st;
++ error_t err = io_stat (netfs_node_netnode (np)->file, &st);
++ if (err)
++ return err;
++
++ np->nn_stat = st;
++ /* XXX */
++ np->nn_translated = S_ISLNK (st.st_mode) ? S_IFLNK : 0;
++
++ return 0;
++}
++
++error_t __attribute__ ((weak))
++netfs_attempt_chown (struct iouser *cred, struct node *np,
++ uid_t uid, uid_t gid)
++{
++ if (! cred)
++ return EOPNOTSUPP;
++ return file_chown (netfs_node_netnode (np)->file, uid, gid);
++}
++
++error_t __attribute__ ((weak))
++netfs_attempt_chauthor (struct iouser *cred, struct node *np, uid_t author)
++{
++ if (! cred)
++ return EOPNOTSUPP;
++ return file_chauthor (netfs_node_netnode (np)->file, author);
++}
++
++/* This should attempt a chmod call for the user specified by CRED on
++ locked node NODE, to change the mode to MODE. Unlike the normal Unix
++ and Hurd meaning of chmod, this function is also used to attempt to
++ change files into other types. If such a transition is attempted which
++ is impossible, then return EOPNOTSUPP. */
++error_t __attribute__ ((weak))
++netfs_attempt_chmod (struct iouser *cred, struct node *np, mode_t mode)
++{
++ if (! cred)
++ return EOPNOTSUPP;
++ return file_chmod (netfs_node_netnode (np)->file, mode);
++}
++
++/* The user must define this function. Attempt to turn locked node NP
++ (user CRED) into a symlink with target NAME. */
++error_t __attribute__ ((weak))
++netfs_attempt_mksymlink (struct iouser *cred, struct node *np, char *name)
++{
++ int namelen = strlen (name) + 1;
++ char trans[sizeof _HURD_SYMLINK + namelen];
++ memcpy (trans, _HURD_SYMLINK, sizeof _HURD_SYMLINK);
++ memcpy (&trans[sizeof _HURD_SYMLINK], name, namelen);
++ return file_set_translator (netfs_node_netnode (np)->file,
++ FS_TRANS_EXCL|FS_TRANS_SET,
++ FS_TRANS_EXCL|FS_TRANS_SET, 0,
++ trans, sizeof trans,
++ MACH_PORT_NULL, MACH_MSG_TYPE_COPY_SEND);
++}
++
++error_t __attribute__ ((weak))
++netfs_attempt_mkdev (struct iouser *cred, struct node *np,
++ mode_t type, dev_t indexes)
++{
++ char *trans = 0;
++ int translen = asprintf (&trans, "%s%c%d%c%d",
++ S_ISCHR (type) ? _HURD_CHRDEV : _HURD_BLKDEV,
++ '\0', major (indexes), '\0', minor (indexes));
++ if (trans == 0)
++ return ENOMEM;
++ else
++ {
++ error_t err = file_set_translator (netfs_node_netnode (np)->file,
++ FS_TRANS_EXCL|FS_TRANS_SET,
++ FS_TRANS_EXCL|FS_TRANS_SET, 0,
++ trans, translen + 1,
++ MACH_PORT_NULL,
++ MACH_MSG_TYPE_COPY_SEND);
++ free (trans);
++ return err;
++ }
++}
++
++error_t __attribute__ ((weak))
++netfs_attempt_chflags (struct iouser *cred, struct node *np, int flags)
++{
++ return file_chflags (netfs_node_netnode (np)->file, flags);
++}
++
++error_t __attribute__ ((weak))
++netfs_attempt_utimes (struct iouser *cred, struct node *np,
++ struct timespec *atime, struct timespec *mtime)
++{
++ union tv
++ {
++ struct timeval tv;
++ time_value_t tvt;
++ };
++ union tv a, m;
++ if (atime)
++ {
++ TIMESPEC_TO_TIMEVAL (&a.tv, atime);
++ }
++ else
++ a.tv.tv_sec = a.tv.tv_usec = -1;
++ if (mtime)
++ {
++ TIMESPEC_TO_TIMEVAL (&m.tv, mtime);
++ }
++ else
++ m.tv.tv_sec = m.tv.tv_usec = -1;
++
++ return file_utimes (netfs_node_netnode (np)->file, a.tvt, m.tvt);
++}
++
++error_t __attribute__ ((weak))
++netfs_attempt_set_size (struct iouser *cred, struct node *np, off_t size)
++{
++ return file_set_size (netfs_node_netnode (np)->file, size);
++}
++
++error_t __attribute__ ((weak))
++netfs_attempt_statfs (struct iouser *cred, struct node *np, struct statfs *st)
++{
++ return file_statfs (netfs_node_netnode (np)->file, st);
++}
++
++error_t __attribute__ ((weak))
++netfs_attempt_sync (struct iouser *cred, struct node *np, int wait)
++{
++ return file_sync (netfs_node_netnode (np)->file, wait, 0);
++}
++
++error_t __attribute__ ((weak))
++netfs_attempt_syncfs (struct iouser *cred, int wait)
++{
++ return 0;
++}
++
++error_t __attribute__ ((weak))
++netfs_attempt_mkdir (struct iouser *user, struct node *dir,
++ char *name, mode_t mode)
++{
++ return dir_mkdir (netfs_node_netnode (dir)->file, name, mode | S_IRWXU);
++}
++
++
++/* XXX
++ Removing a node should mark the netnode so that it is GC'd when
++ it has no hard refs.
++ */
++
++error_t __attribute__ ((weak))
++netfs_attempt_unlink (struct iouser *user, struct node *dir, char *name)
++{
++ return dir_unlink (netfs_node_netnode (dir)->file, name);
++}
++
++error_t __attribute__ ((weak))
++netfs_attempt_rename (struct iouser *user, struct node *fromdir,
++ char *fromname, struct node *todir,
++ char *toname, int excl)
++{
++ return dir_rename (netfs_node_netnode (fromdir)->file, fromname,
++ netfs_node_netnode (todir)->file, toname, excl);
++}
++
++error_t __attribute__ ((weak))
++netfs_attempt_rmdir (struct iouser *user,
++ struct node *dir, char *name)
++{
++ return dir_rmdir (netfs_node_netnode (dir)->file, name);
++}
++
++error_t __attribute__ ((weak))
++netfs_attempt_link (struct iouser *user, struct node *dir,
++ struct node *file, char *name, int excl)
++{
++ return dir_link (netfs_node_netnode (dir)->file,
++ netfs_node_netnode (file)->file, name, excl);
++}
++
++error_t __attribute__ ((weak))
++netfs_attempt_mkfile (struct iouser *user, struct node *dir,
++ mode_t mode, struct node **np)
++{
++ file_t newfile;
++ error_t err = dir_mkfile (netfs_node_netnode (dir)->file, O_RDWR|O_EXEC,
++ mode, &newfile);
++ pthread_mutex_unlock (&dir->lock);
++ if (err)
++ return err;
++
++ err = chroot_new_node (newfile, 0, np);
++ if (err)
++ return err;
++
++ pthread_mutex_unlock (&(*np)->lock);
++ return err;
++}
++
++error_t __attribute__ ((weak))
++netfs_attempt_readlink (struct iouser *user, struct node *np, char *buf)
++{
++ char transbuf[sizeof _HURD_SYMLINK + np->nn_stat.st_size + 1];
++ char *trans = transbuf;
++ size_t translen = sizeof transbuf;
++ error_t err = file_get_translator (netfs_node_netnode (np)->file,
++ &trans, &translen);
++ if (err == 0)
++ {
++ if (translen < sizeof _HURD_SYMLINK
++ || memcmp (trans, _HURD_SYMLINK, sizeof _HURD_SYMLINK) != 0)
++ err = EINVAL;
++ else
++ {
++ assert (translen <= sizeof _HURD_SYMLINK + np->nn_stat.st_size + 1);
++ memcpy (buf, &trans[sizeof _HURD_SYMLINK],
++ translen - sizeof _HURD_SYMLINK);
++ }
++ if (trans != transbuf)
++ munmap (trans, translen);
++ }
++ return err;
++}
++
++error_t __attribute__ ((weak))
++netfs_get_dirents (struct iouser *cred, struct node *dir,
++ int entry, int nentries, char **data,
++ mach_msg_type_number_t *datacnt,
++ vm_size_t bufsize, int *amt)
++{
++ error_t err;
++ err = dir_readdir (netfs_node_netnode (dir)->file, data, datacnt,
++ entry, nentries, bufsize, amt);
++ return err;
++}
++
++error_t __attribute__ ((weak))
++netfs_attempt_read (struct iouser *cred, struct node *np,
++ off_t offset, size_t *len, void *data)
++{
++ char *buf = data;
++ error_t err = io_read (netfs_node_netnode (np)->file,
++ &buf, len, offset, *len);
++ if (err == 0 && buf != data)
++ {
++ memcpy (data, buf, *len);
++ munmap (buf, *len);
++ }
++ return err;
++}
++
++error_t __attribute__ ((weak))
++netfs_attempt_write (struct iouser *cred, struct node *np,
++ off_t offset, size_t *len, void *data)
++{
++ return io_write (netfs_node_netnode (np)->file, data, *len, offset, len);
++}
++
++error_t __attribute__ ((weak))
++netfs_report_access (struct iouser *cred, struct node *np, int *types)
++{
++ return file_check_access (netfs_node_netnode (np)->file, types);
++}
++
++error_t __attribute__ ((weak))
++netfs_file_get_storage_info (struct iouser *cred,
++ struct node *np,
++ mach_port_t **ports,
++ mach_msg_type_name_t *ports_type,
++ mach_msg_type_number_t *num_ports,
++ int **ints,
++ mach_msg_type_number_t *num_ints,
++ off_t **offsets,
++ mach_msg_type_number_t *num_offsets,
++ char **data,
++ mach_msg_type_number_t *data_len)
++{
++ *ports_type = MACH_MSG_TYPE_MOVE_SEND;
++ return file_get_storage_info (netfs_node_netnode (np)->file,
++ ports, num_ports,
++ ints, num_ints,
++ offsets, num_offsets,
++ data, data_len);
++}
++
++error_t __attribute__ ((weak))
++netfs_S_file_exec (struct protid *user,
++ task_t task,
++ int flags,
++ char *argv,
++ size_t argvlen,
++ char *envp,
++ size_t envplen,
++ mach_port_t *fds,
++ size_t fdslen,
++ mach_port_t *portarray,
++ size_t portarraylen,
++ int *intarray,
++ size_t intarraylen,
++ mach_port_t *deallocnames,
++ size_t deallocnameslen,
++ mach_port_t *destroynames,
++ size_t destroynameslen)
++{
++ error_t err;
++ file_t file;
++
++ if (!user)
++ return EOPNOTSUPP;
++
++ file = netfs_node_netnode (user->po->np)->file;
++ err = mach_port_mod_refs (mach_task_self (),
++ file, MACH_PORT_RIGHT_SEND, 1);
++
++ if (!err)
++ {
++ /* We cannot use MACH_MSG_TYPE_MOVE_SEND because we might need to
++ retry an interrupted call that would have consumed the rights. */
++ err = file_exec (file, task, flags, argv, argvlen,
++ envp, envplen, fds, MACH_MSG_TYPE_COPY_SEND, fdslen,
++ portarray, MACH_MSG_TYPE_COPY_SEND, portarraylen,
++ intarray, intarraylen, deallocnames, deallocnameslen,
++ destroynames, destroynameslen);
++ mach_port_deallocate (mach_task_self (), file);
++ }
++
++ if (err == 0)
++ {
++ size_t i;
++ mach_port_deallocate (mach_task_self (), task);
++ for (i = 0; i < fdslen; ++i)
++ mach_port_deallocate (mach_task_self (), fds[i]);
++ for (i = 0; i < portarraylen; ++i)
++ mach_port_deallocate (mach_task_self (), portarray[i]);
++ }
++ return err;
++}
++
++error_t __attribute__ ((weak))
++netfs_S_io_map (struct protid *user,
++ mach_port_t *rdobj, mach_msg_type_name_t *rdobjtype,
++ mach_port_t *wrobj, mach_msg_type_name_t *wrobjtype)
++{
++ if (!user)
++ return EOPNOTSUPP;
++ *rdobjtype = *wrobjtype = MACH_MSG_TYPE_MOVE_SEND;
++
++ return io_map (netfs_node_netnode (user->po->np)->file, rdobj, wrobj);
++}
++
++error_t __attribute__ ((weak))
++netfs_S_io_map_cntl (struct protid *user,
++ mach_port_t *obj,
++ mach_msg_type_name_t *objtype)
++{
++ if (!user)
++ return EOPNOTSUPP;
++ *objtype = MACH_MSG_TYPE_MOVE_SEND;
++
++ return io_map_cntl (netfs_node_netnode (user->po->np)->file, obj);
++}
++
++error_t __attribute__ ((weak))
++netfs_S_io_identity (struct protid *user,
++ mach_port_t *id,
++ mach_msg_type_name_t *idtype,
++ mach_port_t *fsys,
++ mach_msg_type_name_t *fsystype,
++ ino_t *fileno)
++{
++ if (!user)
++ return EOPNOTSUPP;
++
++ *idtype = *fsystype = MACH_MSG_TYPE_MOVE_SEND;
++
++ return io_identity (netfs_node_netnode (user->po->np)->file,
++ id, fsys, fileno);
++}
++
++#define NETFS_S_SIMPLE(name) \
++error_t __attribute__ ((weak)) \
++netfs_S_##name (struct protid *user) \
++{ \
++ if (!user) \
++ return EOPNOTSUPP; \
++ \
++ return name (netfs_node_netnode (user->po->np)->file); \
++}
++
++NETFS_S_SIMPLE (io_get_conch)
++NETFS_S_SIMPLE (io_release_conch)
++NETFS_S_SIMPLE (io_eofnotify)
++NETFS_S_SIMPLE (io_readnotify)
++NETFS_S_SIMPLE (io_readsleep)
++NETFS_S_SIMPLE (io_sigio)
++
++error_t __attribute__ ((weak))
++netfs_S_io_prenotify (struct protid *user,
++ vm_offset_t start, vm_offset_t stop)
++{
++ if (!user)
++ return EOPNOTSUPP;
++
++ return io_prenotify (netfs_node_netnode (user->po->np)->file, start, stop);
++}
++
++error_t __attribute__ ((weak))
++netfs_S_io_postnotify (struct protid *user,
++ vm_offset_t start, vm_offset_t stop)
++{
++ if (!user)
++ return EOPNOTSUPP;
++
++ return io_postnotify (netfs_node_netnode (user->po->np)->file, start, stop);
++}
++
++/* This overrides the library's definition. */
++int __attribute__ ((weak))
++netfs_demuxer (mach_msg_header_t *inp,
++ mach_msg_header_t *outp)
++{
++ mig_routine_t routine;
++ if ((routine = netfs_io_server_routine (inp)) ||
++ (routine = netfs_fs_server_routine (inp)) ||
++ (routine = ports_notify_server_routine (inp)) ||
++ (routine = netfs_fsys_server_routine (inp)) ||
++ /* XXX we should intercept interrupt_operation and do
++ the ports_S_interrupt_operation work as well as
++ sending an interrupt_operation to the underlying file.
++ */
++ (routine = ports_interrupt_server_routine (inp)))
++ {
++ (*routine) (inp, outp);
++ return TRUE;
++ }
++ else
++ {
++ /* We didn't recognize the message ID, so pass the message through
++ unchanged to the underlying file. */
++ struct protid *cred;
++ if (MACH_MSGH_BITS_LOCAL (inp->msgh_bits) ==
++ MACH_MSG_TYPE_PROTECTED_PAYLOAD)
++ cred = ports_lookup_payload (netfs_port_bucket,
++ inp->msgh_protected_payload,
++ netfs_protid_class);
++ else
++ cred = ports_lookup_port (netfs_port_bucket,
++ inp->msgh_local_port,
++ netfs_protid_class);
++ if (cred == 0)
++ /* This must be an unknown message on our fsys control port. */
++ return 0;
++ else
++ {
++ error_t err;
++ assert (MACH_MSGH_BITS_LOCAL (inp->msgh_bits)
++ == MACH_MSG_TYPE_MOVE_SEND
++ || MACH_MSGH_BITS_LOCAL (inp->msgh_bits)
++ == MACH_MSG_TYPE_PROTECTED_PAYLOAD);
++ inp->msgh_bits = (inp->msgh_bits & MACH_MSGH_BITS_COMPLEX)
++ | MACH_MSGH_BITS (MACH_MSG_TYPE_COPY_SEND,
++ MACH_MSGH_BITS_REMOTE (inp->msgh_bits));
++ inp->msgh_local_port = inp->msgh_remote_port; /* reply port */
++ inp->msgh_remote_port = netfs_node_netnode (cred->po->np)->file;
++ err = mach_msg (inp, MACH_SEND_MSG, inp->msgh_size, 0,
++ MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE,
++ MACH_PORT_NULL);
++ if (err)
++ ((mig_reply_header_t *) outp)->RetCode = err;
++ else
++ /* We already sent the message, so the server loop
++ shouldn't do it again. */
++ ((mig_reply_header_t *) outp)->RetCode = MIG_NO_REPLY;
++ ports_port_deref (cred);
++ return 1;
++ }
++ }
++}
+diff --git a/trans/chroot.h b/trans/chroot.h
+new file mode 100644
+index 0000000..057a251
+--- /dev/null
++++ b/trans/chroot.h
+@@ -0,0 +1,34 @@
++#ifndef __HURD_CHROOT_H__
++#define __HURD_CHROOT_H__
++
++struct netnode
++{
++ file_t file; /* port on real file */
++};
++
++struct chroot_node;
++
++error_t chroot_init (void);
++
++/* Make a new virtual node. Always consumes the ports. If
++ successful, NP will be locked. */
++error_t chroot_new_node (file_t file, size_t size, struct node **np);
++
++/* Users must implement this. */
++void chroot_node_norefs (struct node *np);
++
++/* Return the address of the chroot_node for NODE. NODE must have been
++ allocated using chroot_new_node. */
++static inline struct chroot_node *
++chroot_node (struct node *node)
++{
++ return (struct chroot_node *) ((char *) netfs_node_netnode (node)
++ + sizeof (struct netnode));
++}
++
++// XXX
++pthread_mutex_t idport_ihash_lock;
++struct hurd_ihash idport_ihash;
++
++
++#endif /* __HURD_CHROOT_H__ */
+diff --git a/trans/identity.c b/trans/identity.c
+new file mode 100644
+index 0000000..875fc4f
+--- /dev/null
++++ b/trans/identity.c
+@@ -0,0 +1,113 @@
++/* identity -- a translator interposing file RPCs.
++ Copyright (C) 2016 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
++
++#include <argp.h>
++#include <error.h>
++#include <fcntl.h>
++#include <hurd/netfs.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <unistd.h>
++
++#include <version.h>
++
++#include "chroot.h"
++
++const char *argp_program_version = STANDARD_HURD_VERSION (identity);
++
++char *netfs_server_name = "identity";
++char *netfs_server_version = HURD_VERSION;
++int netfs_maxsymlinks = 16; /* arbitrary */
++
++struct chroot_node
++{
++};
++
++void
++chroot_node_norefs (struct node *np)
++{
++}
++
++
++static struct argp_option options[] =
++{
++ {0}
++};
++
++static char *args_doc = "";
++static char *doc =
++ "The identity translator relays file RPCs without changing them."
++ "\v"
++ "It can be used in conjunction with settrans --chroot to implement "
++ "a hurdish chroot utility.";
++
++static error_t
++parse_opt (int key, char *arg, struct argp_state *state)
++{
++ switch (key)
++ {
++ default:
++ return ARGP_ERR_UNKNOWN;
++ }
++ return 0;
++}
++
++int
++main (int argc, char **argv)
++{
++ error_t err;
++ mach_port_t bootstrap;
++
++ struct argp argp =
++ {
++ .options = options,
++ .parser = parse_opt,
++ .args_doc = args_doc,
++ .doc = doc,
++ };
++
++ /* Parse our command line arguments (all none of them). */
++ argp_parse (&argp, argc, argv, 0, 0, 0);
++
++ task_get_bootstrap_port (mach_task_self (), &bootstrap);
++ if (! MACH_PORT_VALID (bootstrap))
++ error (1, 0, "Must be started as a translator");
++
++ netfs_init ();
++ chroot_init ();
++
++ /* Get our underlying node (we presume it's a directory) and use
++ that to make the root node of the filesystem. */
++ err = chroot_new_node (netfs_startup (bootstrap, O_READ),
++ sizeof (struct chroot_node), &netfs_root_node);
++ if (err)
++ error (5, err, "Cannot create root node");
++
++ err = netfs_validate_stat (netfs_root_node, 0);
++ if (err)
++ error (6, err, "Cannot stat underlying node");
++
++ netfs_root_node->nn_stat.st_mode &= ~(S_IPTRANS | S_IATRANS);
++ netfs_root_node->nn_stat.st_mode |= S_IROOT;
++ pthread_mutex_unlock (&netfs_root_node->lock);
++
++ netfs_server_loop (); /* Never returns. */
++
++ /*NOTREACHED*/
++ return 0;
++}
+--
+2.1.4
+