bug-hurd
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH 17/17] add mtab prototype


From: Justus Winter
Subject: [PATCH 17/17] add mtab prototype
Date: Fri, 19 Jul 2013 17:25:19 +0200

---
 trans/Makefile |    8 +-
 trans/mtab.c   |  682 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 687 insertions(+), 3 deletions(-)
 create mode 100644 trans/mtab.c

diff --git a/trans/Makefile b/trans/Makefile
index b3210b6..6eb51d0 100644
--- a/trans/Makefile
+++ b/trans/Makefile
@@ -20,14 +20,15 @@ dir := trans
 makemode := servers
 
 targets = symlink firmlink ifsock magic null fifo new-fifo fwd crash \
-         password hello hello-mt streamio fakeroot proxy-defpager remap
+         password hello hello-mt streamio fakeroot proxy-defpager remap \
+         mtab
 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
+       fakeroot.c proxy-defpager.c remap.c mtab.c
 OBJS = $(SRCS:.c=.o) fsysServer.o ifsockServer.o passwordServer.o \
        crashServer.o crash_replyUser.o msgServer.o \
        default_pagerServer.o default_pagerUser.o \
-       device_replyServer.o elfcore.o
+       device_replyServer.o elfcore.o fsysUser.o
 HURDLIBS = ports netfs trivfs iohelp fshelp pipe ihash shouldbeinlibc
 LDLIBS += -lpthread
 password-LDLIBS = $(LIBCRYPT)
@@ -51,6 +52,7 @@ magic: ../libiohelp/libiohelp.a
 hello: ../libtrivfs/libtrivfs.a ../libfshelp/libfshelp.a 
../libports/libports.a ../libihash/libihash.a
 fakeroot: ../libnetfs/libnetfs.a ../libfshelp/libfshelp.a 
../libiohelp/libiohelp.a ../libports/libports.a ../libihash/libihash.a
 remap: ../libtrivfs/libtrivfs.a ../libfshelp/libfshelp.a 
../libports/libports.a ../libihash/libihash.a
+mtab: ../libtrivfs/libtrivfs.a ../libfshelp/libfshelp.a ../libports/libports.a 
../libihash/libihash.a fsysUser.o
 $(targets): ../libshouldbeinlibc/libshouldbeinlibc.a
 
 $(targets): %: %.o
diff --git a/trans/mtab.c b/trans/mtab.c
new file mode 100644
index 0000000..729b9b8
--- /dev/null
+++ b/trans/mtab.c
@@ -0,0 +1,682 @@
+/* This is an mtab translator.
+
+   Copyright (C) 2013 Free Software Foundation, Inc.
+
+   Written by Justus Winter <4winter@informatik.uni-hamburg.de>
+
+   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 <argp.h>
+#include <argz.h>
+#include <error.h>
+#include <fcntl.h>
+#include <hurd.h>
+#include <hurd/trivfs.h>
+#include <inttypes.h>
+#include <mntent.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <version.h>
+
+#include "fsys_U.h"
+
+static char *path = NULL;
+static int insecure = 0;
+
+/* Our control port.  */
+struct trivfs_control *control;
+
+/* XXX */
+struct mtab
+{
+  char *contents;
+  size_t contents_len;
+  off_t offs;
+};
+
+const char *argp_program_version = STANDARD_HURD_VERSION (mtab);
+
+static const struct argp_option options[] =
+{
+  {"insecure", 'I', 0, 0, "Follow translators not started by root"},
+  {}
+};
+
+/* Parse a command line option.  */
+error_t parse_opt (int key, char *arg, struct argp_state *state)
+{
+  switch (key)
+    {
+    case 'I':
+      insecure = 1;
+      break;
+
+    case ARGP_KEY_ARG:
+      path = realpath (arg, NULL);
+      if (! path)
+        argp_error (state, "Error while canonicalizing path");
+      break;
+
+    case ARGP_KEY_NO_ARGS:
+      argp_usage (state);
+      return EINVAL;
+
+    default:
+      return ARGP_ERR_UNKNOWN;
+    }
+  return 0;
+}
+
+static struct argp argp =
+  {
+    options,
+    parse_opt,
+    "TARGET",
+    "A translator providing mtab compatible information about active "
+    "and passive translators below TARGET.",
+  };
+
+/* This will be called from libtrivfs to help construct the answer
+   to an fsys_get_options RPC.  */
+error_t
+trivfs_append_args (struct trivfs_control *fsys,
+                   char **argz, size_t *argz_len)
+{
+  error_t err;
+
+  if (insecure)
+    {
+      err = argz_add (argz, argz_len, path);
+      if (err)
+        return err;
+    }
+
+  err = argz_add (argz, argz_len, path);
+  return err;
+}
+
+/* Setting this variable makes libtrivfs use our argp to
+   parse options passed in an fsys_set_options RPC.  */
+struct argp *trivfs_runtime_argp = &argp;
+
+error_t
+mtab_populate (struct mtab *mtab, const char *path, int insecure);
+
+error_t
+argz_add_device (char **options, size_t *options_len, const char *device);
+
+error_t
+map_device_to_path (const char *device, char **path);
+
+int
+main (int argc, char *argv[])
+{
+  error_t err;
+
+  err = argp_parse (&argp, argc, argv, ARGP_IN_ORDER, 0, 0);
+  if (err)
+    error (1, err, "argument parsing");
+
+  mach_port_t bootstrap;
+  task_get_bootstrap_port (mach_task_self (), &bootstrap);
+  if (bootstrap != MACH_PORT_NULL)
+    {
+      /* Started as a translator.  */
+
+      /* Reply to our parent.  */
+      err = trivfs_startup (bootstrap, 0, 0, 0, 0, 0, &control);
+      mach_port_deallocate (mach_task_self (), bootstrap);
+      if (err)
+        error (3, err, "trivfs_startup");
+
+      /* Launch.  */
+      ports_manage_port_operations_one_thread (control->pi.bucket,
+                                               trivfs_demuxer,
+                                               0);
+    }
+  else
+    {
+      /* One-shot mode.  */
+      struct mtab mtab = { NULL, 0, 0 };
+      err = mtab_populate (&mtab, path, insecure);
+      if (err)
+        error (5, err, "%s", path);
+
+      if (mtab.contents)
+        printf ("%s", mtab.contents);
+    }
+
+  return 0;
+}
+
+error_t
+mtab_add_entry (struct mtab *mtab, const char *entry, size_t length)
+{
+  char *p = realloc (mtab->contents, mtab->contents_len + length + 1);
+  if (! p)
+    return ENOMEM;
+
+  memcpy (&p[mtab->contents_len], entry, length);
+
+  mtab->contents = p;
+  mtab->contents_len += length;
+
+  /* Zero-terminate contents so that we can also interpret it as
+     string.  */
+  mtab->contents[mtab->contents_len] = '\0';
+
+  return 0;
+}
+
+/* XXX */
+/* XXX split up */
+error_t
+mtab_populate (struct mtab *mtab, const char *path, int insecure)
+{
+  error_t err = 0;
+
+  /* These resources are freed in the epilogue.  */
+  file_t node = MACH_PORT_NULL;
+  fsys_t fsys = MACH_PORT_NULL;
+  char *argz = NULL;
+  size_t argz_len = 0;
+  char **argv = NULL;
+  char *type = NULL;
+  char *options = NULL;
+  size_t options_len = 0;
+  char *src = NULL;
+  char *entry = NULL;
+  size_t entry_len = 0;
+  char *children = NULL;
+  size_t children_len = 0;
+
+  if (! insecure)
+    {
+      /* XXX check who owns the translator */
+    }
+
+  /* Get the underlying node.  */
+  node = file_name_lookup (path, O_NOTRANS, 0666);
+  if (node == MACH_PORT_NULL)
+    {
+      err = errno;
+      goto errout;
+    }
+
+  err = file_get_translator_cntl (node, &fsys);
+  if (err == EPERM)
+    /* If we do not have permission to do that, it cannot be a node
+       bound to our control port, so ignore this error.  */
+    err = 0;
+
+  if (err == ENXIO && strcmp (path, "/") == 0)
+    /* The root translator fails differently, but this can't be bound
+       to our control port either, so ignore this error.  */
+    err = 0;
+
+  if (err)
+    return err;
+
+  if (control && control->pi.port_right == fsys)
+    /* This node is bound to our control port, ignore it.  */
+    goto errout;
+
+  /* Re-do the lookup without O_NOTRANS to get the root node.  */
+  mach_port_deallocate (mach_task_self (), node);
+  node = file_name_lookup (path, 0, 0666);
+  if (node == MACH_PORT_NULL)
+    {
+      err = errno;
+      goto errout;
+    }
+
+  /* Query its options.  */
+  err = file_get_fs_options (node, &argz, &argz_len);
+  if (err)
+    {
+      if (err == EOPNOTSUPP)
+        err = 0; /* There's not much we could do then.  */
+
+      goto errout;
+    }
+
+  size_t count = argz_count (argz, argz_len);
+  argv = malloc ((count + 1) * sizeof (char *));
+  if (! argv)
+    {
+      err = ENOMEM;
+      goto errout;
+    }
+
+  argz_extract (argz, argz_len, argv);
+
+  type = strdup (argv[0]);
+  if (! type)
+    {
+      err = ENOMEM;
+      goto errout;
+    }
+
+  for (int i = 1; i < count - 1; i++)
+    {
+      char *v = argv[i];
+
+      if (*v == '-')
+        v++;
+      if (*v == '-')
+        v++;
+
+      err = argz_add (&options, &options_len, v);
+      if (err)
+        goto errout;
+    }
+
+  err = argz_add_device (&options, &options_len, argv[count - 1]);
+  if (err)
+    goto errout;
+
+  argz_stringify (options, options_len, ',');
+
+  string_t source;
+  err = fsys_get_source (node, source);
+  if (err)
+    {
+      if (err == EOPNOTSUPP)
+        {
+          /* Guess based on the last argument.  */
+          err = map_device_to_path (argv[count - 1], &src);
+          if (err)
+            goto errout;
+        }
+      else
+        goto errout;
+    }
+  else
+    src = source;
+
+  entry_len = asprintf (&entry, "%s %s %s %s 0 0\n", src, path, type,
+                        options? options: MNTOPT_DEFAULTS);
+  if (! entry)
+    {
+      err = ENOMEM;
+      goto errout;
+    }
+
+  err = mtab_add_entry (mtab, entry, entry_len);
+  if (err)
+    goto errout;
+
+  /* path has an active translator, query its children.  */
+  err = fsys_get_children (node, &children, &children_len);
+  if (err == EOPNOTSUPP)
+    {
+      err = 0;
+      children_len = 0;
+    }
+
+  if (err)
+    goto errout;
+
+  if (children_len)
+    for (char *c = children; c; c = argz_next (children, children_len, c))
+      {
+        char *p = NULL;
+        asprintf (&p, "%s%s%s",
+                  path,
+                  path[strlen (path) - 1] == '/'? "": "/",
+                  c);
+        if (! p)
+          {
+            err = ENOMEM;
+            goto errout;
+          }
+
+        err = mtab_populate (mtab, p, insecure);
+        if (err)
+          {
+            /* There is really not much we can do about errors here.  */
+            error (0, err, "%s", p);
+            err = 0;
+          }
+
+        free (p);
+      }
+
+ errout:
+  if (node != MACH_PORT_NULL)
+    mach_port_deallocate (mach_task_self (), node);
+
+  if (fsys != MACH_PORT_NULL)
+    mach_port_deallocate (mach_task_self (), fsys);
+
+  if (argz)
+    vm_deallocate (mach_task_self (), (vm_address_t) argz, argz_len);
+
+  free (argv);
+  free (type);
+  free (options);
+
+  if (src != source)
+    free (src);
+
+  free (entry);
+
+  if (children)
+    vm_deallocate (mach_task_self (), (vm_address_t) children, children_len);
+
+  return err;
+}
+
+/* XXX */
+error_t
+argz_add_device (char **options, size_t *options_len, const char *device)
+{
+  error_t err;
+  char *end = NULL;
+  intmax_t size = strtoimax (device, &end, 0);
+  if (end == NULL || end == device)
+    return 0;
+
+  if (size < 0)
+    return 0;
+
+  switch (*end)
+    {
+      case 'g':
+      case 'G':
+      case 'm':
+      case 'M':
+      case 'k':
+      case 'K':
+        break;
+    default:
+      return 0;
+    }
+
+  /* device is a size */
+  char *arg = NULL;
+  asprintf (&arg, "size=%s", device);
+  if (! arg)
+    return ENOMEM;
+
+  err = argz_add (options, options_len, arg);
+
+  free (arg);
+  return err;
+}
+
+/* Map a device string to a file name referencing the appropriate
+   device file.  */
+error_t
+map_device_to_path (const char *device, char **path)
+{
+  if (strncmp (device, "device:", 7) == 0)
+    asprintf (path, "/dev/%s", &device[7]);
+  else if (strncmp (device, "/dev/", 5) == 0)
+    *path = strdup (device);
+  else
+    *path = strdup ("none");
+
+  if (! *path)
+    return ENOMEM;
+
+  return 0;
+}
+
+/* Trivfs hooks.  */
+int trivfs_fstype = FSTYPE_MISC;
+int trivfs_fsid = 0;
+
+int trivfs_allow_open = O_READ;
+
+int trivfs_support_read = 1;
+int trivfs_support_write = 0;
+int trivfs_support_exec = 0;
+
+void
+trivfs_modify_stat (struct trivfs_protid *cred, struct stat *st)
+{
+  /* Mark the node as a read-only plain file.  */
+  st->st_mode &= ~(S_IFMT | ALLPERMS);
+  st->st_mode |= (S_IFREG | S_IRUSR | S_IRGRP | S_IROTH);
+  st->st_size = ((struct mtab *) cred->po->hook)->contents_len;
+}
+
+error_t
+trivfs_goaway (struct trivfs_control *cntl, int flags)
+{
+  exit (EXIT_SUCCESS);
+}
+
+static error_t
+open_hook (struct trivfs_peropen *peropen)
+{
+  struct mtab *mtab = malloc (sizeof (struct mtab));
+  if (mtab == NULL)
+    return ENOMEM;
+
+  /* Hook! */
+  peropen->hook = mtab;
+
+  /* Initialize the fields.  */
+  mtab->offs = 0;
+  mtab->contents = NULL;
+  mtab->contents_len = 0;
+
+  return mtab_populate (mtab, path, insecure);
+}
+
+static void
+close_hook (struct trivfs_peropen *peropen)
+{
+  free (((struct mtab *) peropen->hook)->contents);
+  free (peropen->hook);
+}
+
+/* Read data from an IO object.  If offset is -1, read from the object
+   maintained file pointer.  If the object is not seekable, offset is
+   ignored.  The amount desired to be read is in AMOUNT.  */
+error_t
+trivfs_S_io_read (struct trivfs_protid *cred,
+                 mach_port_t reply, mach_msg_type_name_t reply_type,
+                 char **data, mach_msg_type_number_t *data_len,
+                 loff_t offs, mach_msg_type_number_t amount)
+{
+  struct mtab *op;
+
+  /* Deny access if they have bad credentials.  */
+  if (! cred)
+    return EOPNOTSUPP;
+
+  if (! (cred->po->openmodes & O_READ))
+    return EBADF;
+
+  /* Get the offset.  */
+  op = cred->po->hook;
+  if (offs == -1)
+    offs = op->offs;
+
+  /* Prune the amount they want to read.  */
+  if (offs > op->contents_len)
+    offs = op->contents_len;
+  if (offs + amount > op->contents_len)
+    amount = op->contents_len - offs;
+
+  if (amount > 0)
+    {
+      /* Possibly allocate a new buffer.  */
+      if (*data_len < amount)
+       {
+         *data = mmap (0, amount, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+         if (*data == MAP_FAILED)
+           return ENOMEM;
+       }
+
+      /* Copy the constant data into the buffer.  */
+      memcpy ((char *) *data, op->contents + offs, amount);
+
+      /* Update the saved offset.  */
+      op->offs += amount;
+    }
+
+  *data_len = amount;
+  return 0;
+}
+
+
+/* Change current read/write offset */
+error_t
+trivfs_S_io_seek (struct trivfs_protid *cred,
+                 mach_port_t reply, mach_msg_type_name_t reply_type,
+                 off_t offs, int whence, off_t *new_offs)
+{
+  if (! cred)
+    return EOPNOTSUPP;
+
+  struct mtab *op = cred->po->hook;
+
+  switch (whence)
+    {
+    case SEEK_CUR:
+      offs += op->offs;
+      goto check;
+    case SEEK_END:
+      offs += op->contents_len;
+    case SEEK_SET:
+    check:
+      if (offs >= 0)
+       {
+         *new_offs = op->offs = offs;
+         break;
+       }
+    default:
+      return EINVAL;
+    }
+
+  return 0;
+}
+
+/* If this variable is set, it is called every time a new peropen
+   structure is created and initialized.  */
+error_t (*trivfs_peropen_create_hook)(struct trivfs_peropen *) = open_hook;
+
+/* If this variable is set, it is called every time a peropen structure
+   is about to be destroyed.  */
+void (*trivfs_peropen_destroy_hook) (struct trivfs_peropen *) = close_hook;
+
+/* Tell how much data can be read from the object without blocking for
+   a "long time" (this should be the same meaning of "long time" used
+   by the nonblocking flag.  */
+kern_return_t
+trivfs_S_io_readable (struct trivfs_protid *cred,
+                     mach_port_t reply, mach_msg_type_name_t replytype,
+                     mach_msg_type_number_t *amount)
+{
+  if (!cred)
+    return EOPNOTSUPP;
+
+  if (!(cred->po->openmodes & O_READ))
+    return EINVAL;
+
+  *amount = 0;
+  return 0;
+}
+
+/* SELECT_TYPE is the bitwise OR of SELECT_READ, SELECT_WRITE, and SELECT_URG.
+   Block until one of the indicated types of i/o can be done "quickly", and
+   return the types that are then available.  ID_TAG is returned as passed; it
+   is just for the convenience of the user in matching up reply messages with
+   specific requests sent.  */
+kern_return_t
+trivfs_S_io_select (struct trivfs_protid *cred,
+                   mach_port_t reply, mach_msg_type_name_t replytype,
+                   int *type)
+{
+  if (!cred)
+    return EOPNOTSUPP;
+
+  if (((*type & SELECT_READ) && !(cred->po->openmodes & O_READ))
+      || ((*type & SELECT_WRITE) && !(cred->po->openmodes & O_WRITE)))
+    return EBADF;
+
+  *type &= ~SELECT_URG;
+  return 0;
+}
+
+kern_return_t
+trivfs_S_io_select_timeout (struct trivfs_protid *cred,
+                           mach_port_t reply, mach_msg_type_name_t replytype,
+                           struct timespec ts,
+                           int *type)
+{
+  return trivfs_S_io_select (cred, reply, replytype, type);
+}
+
+/* These four routines modify the O_APPEND, O_ASYNC, O_FSYNC, and
+   O_NONBLOCK bits for the IO object. In addition, io_get_openmodes
+   will tell you which of O_READ, O_WRITE, and O_EXEC the object can
+   be used for.  The O_ASYNC bit affects icky async I/O; good async
+   I/O is done through io_async which is orthogonal to these calls. */
+
+kern_return_t
+trivfs_S_io_get_openmodes (struct trivfs_protid *cred,
+                          mach_port_t reply, mach_msg_type_name_t replytype,
+                          int *bits)
+{
+  if (!cred)
+    return EOPNOTSUPP;
+
+  *bits = cred->po->openmodes;
+  return 0;
+}
+
+error_t
+trivfs_S_io_set_all_openmodes(struct trivfs_protid *cred,
+                             mach_port_t reply,
+                             mach_msg_type_name_t replytype,
+                             int mode)
+{
+  if (!cred)
+    return EOPNOTSUPP;
+
+  return 0;
+}
+
+kern_return_t
+trivfs_S_io_set_some_openmodes (struct trivfs_protid *cred,
+                               mach_port_t reply,
+                               mach_msg_type_name_t replytype,
+                               int bits)
+{
+  if (!cred)
+    return EOPNOTSUPP;
+
+  return 0;
+}
+
+kern_return_t
+trivfs_S_io_clear_some_openmodes (struct trivfs_protid *cred,
+                                 mach_port_t reply,
+                                 mach_msg_type_name_t replytype,
+                                 int bits)
+{
+  if (!cred)
+    return EOPNOTSUPP;
+
+  return 0;
+}
-- 
1.7.10.4




reply via email to

[Prev in Thread] Current Thread [Next in Thread]