bug-hurd
[Top][All Lists]
Advanced

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

[PATCH 6/6] umount: add a umount utility


From: Justus Winter
Subject: [PATCH 6/6] umount: add a umount utility
Date: Thu, 4 Jul 2013 18:45:41 +0200

This adds a umount utility that implements most of the functions that
the Linux umount utility provides, especially that subset that is used
by the Debian package initscripts.

* utils/umount.c: New file.
---
 utils/Makefile |   10 +-
 utils/umount.c |  308 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 314 insertions(+), 4 deletions(-)
 create mode 100644 utils/umount.c

diff --git a/utils/Makefile b/utils/Makefile
index 207c904..4fe2dc2 100644
--- a/utils/Makefile
+++ b/utils/Makefile
@@ -21,7 +21,9 @@ makemode := utilities
 targets = shd ps settrans showtrans syncfs fsysopts \
        storeinfo login w uptime ids loginpr sush vmstat portinfo \
        devprobe vminfo addauth rmauth unsu setauth ftpcp ftpdir storecat \
-       storeread msgport rpctrace mount gcore fakeauth fakeroot remap
+       storeread msgport rpctrace mount gcore fakeauth fakeroot remap \
+       umount
+
 special-targets = loginpr sush uptime fakeroot remap
 SRCS = shd.c ps.c settrans.c syncfs.c showtrans.c addauth.c rmauth.c \
        fsysopts.c storeinfo.c login.c loginpr.sh sush.sh w.c \
@@ -29,7 +31,7 @@ SRCS = shd.c ps.c settrans.c syncfs.c showtrans.c addauth.c 
rmauth.c \
        parse.c frobauth.c frobauth-mod.c setauth.c pids.c nonsugid.c \
        unsu.c ftpcp.c ftpdir.c storeread.c storecat.c msgport.c \
        rpctrace.c mount.c gcore.c fakeauth.c fakeroot.sh remap.sh \
-       match-options.c
+       match-options.c umount.c
 
 OBJS = $(filter-out %.sh,$(SRCS:.c=.o))
 HURDLIBS = ps ihash store fshelp ports ftpconn shouldbeinlibc
@@ -58,7 +60,7 @@ ftpcp ftpdir: ../libftpconn/libftpconn.a
 settrans: ../libfshelp/libfshelp.a ../libports/libports.a
 ps w ids settrans syncfs showtrans fsysopts storeinfo login vmstat portinfo \
   devprobe vminfo addauth rmauth setauth unsu ftpcp ftpdir storeread \
-  storecat msgport mount: \
+  storecat msgport mount umount: \
        ../libshouldbeinlibc/libshouldbeinlibc.a
 
 $(filter-out $(special-targets), $(targets)): %: %.o
@@ -74,7 +76,7 @@ fakeauth-CPPFLAGS = -I$(srcdir)/../auth
 authServer-CPPFLAGS = -I$(srcdir)/../auth
 auth_requestUser-CPPFLAGS = -I$(srcdir)/../auth
 
-mount: ../sutils/fstab.o ../sutils/clookup.o match-options.o \
+mount umount: ../sutils/fstab.o ../sutils/clookup.o match-options.o \
        $(foreach L,fshelp ports,../lib$L/lib$L.a)
 ../sutils/fstab.o ../sutils/clookup.o: FORCE
        $(MAKE) -C $(@D) $(@F)
diff --git a/utils/umount.c b/utils/umount.c
new file mode 100644
index 0000000..707f058
--- /dev/null
+++ b/utils/umount.c
@@ -0,0 +1,308 @@
+/* Roughly Unix/Linux-compatible `umount' frontend for Hurd translators.
+
+   Copyright (C) 2013 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 this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include "../sutils/fstab.h"
+#include <argp.h>
+#include <argz.h>
+#include <blkid/blkid.h>
+#include <error.h>
+#include <fcntl.h>
+#include <hurd/fshelp.h>
+#include <hurd/fsys.h>
+#include <hurd/paths.h>
+#include <hurd/process.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "match-options.h"
+
+/* XXX fix libc */
+#undef _PATH_MOUNTED
+#define _PATH_MOUNTED "/etc/mtab"
+
+static char *targets;
+static size_t targets_len;
+static int readonly;
+static int verbose;
+static int passive_flags = FS_TRANS_SET;
+static int active_flags = FS_TRANS_SET;
+static int goaway_flags;
+static int fake;
+
+static struct fstab_argp_params fstab_params;
+
+#define FAKE_KEY 0x80 /* !isascii (FAKE_KEY), so no short option. */
+
+static const struct argp_option argp_opts[] =
+{
+  {"fake", FAKE_KEY, 0, 0, "Do not actually umount, just pretend"},
+  {"force", 'f', 0, 0, "Force umount by killing the translator"},
+  {"no-mtab", 'n', 0, 0, "Do not update /etc/mtab"},
+  {"read-only", 'r', 0, 0, "If unmounting fails, try to remount read-only"},
+  {"nosync", 'S', 0, 0, "Don't sync a translator before killing it"},
+  {"test-opts", 'O', "OPTIONS", 0,
+   "Only mount fstab entries matching the given set of options"},
+  {"verbose", 'v', 0, 0, "Give more detailed information"},
+  {},
+};
+
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+  struct fstab_argp_params *params = state->input;
+  error_t err;
+  switch (key)
+    {
+    case ARGP_KEY_INIT:
+      state->child_inputs[0] = params; /* pass down to fstab_argp parser */
+      break;
+
+    case FAKE_KEY:
+      fake = 1;
+      break;
+
+    case 'f':
+      goaway_flags |= FSYS_GOAWAY_FORCE;
+      break;
+
+    case 'n':
+      /* do nothing */
+      break;
+
+    case 'r':
+      readonly = 1;
+      break;
+
+    case 'S':
+      goaway_flags |= FSYS_GOAWAY_NOSYNC;
+      break;
+
+    case 'O':
+      err = argz_create_sep (arg, ',', &test_opts, &test_opts_len);
+      if (err)
+       argp_failure (state, 100, ENOMEM, "%s", arg);
+      break;
+
+    case 'v':
+      verbose += 1;
+      break;
+
+    case ARGP_KEY_ARG:
+      err = argz_add (&targets, &targets_len, arg);
+      if (err)
+       argp_failure (state, 100, ENOMEM, "%s", arg);
+      break;
+
+    case ARGP_KEY_NO_ARGS:
+      if (! params->do_all)
+       {
+         argp_error (state,
+                      "filesystem argument required if --all is not given");
+          return EINVAL;
+       }
+      break;
+
+    case ARGP_KEY_END:
+      if (params->do_all && targets)
+       {
+         argp_error (state, "filesystem argument not allowed with --all");
+         return EINVAL;
+       }
+      break;
+
+    default:
+      return ARGP_ERR_UNKNOWN;
+    }
+
+  return 0;
+}
+
+static const char doc[] = "Stop active and remove passive translators";
+static const char args_doc[] = "DEVICE|DIRECTORY [DEVICE|DIRECTORY ...]";
+
+static struct argp fstab_argp_mtab; /* Slightly modified version. */
+
+static const struct argp_child argp_kids[] =
+{
+  {&fstab_argp_mtab, 0,
+   "Filesystem selection (if no explicit filesystem arguments given):", 2},
+  {},
+};
+static struct argp argp = {
+  .options = argp_opts,
+  .parser = parse_opt,
+  .args_doc = args_doc,
+  .doc = doc,
+  .children = argp_kids,
+};
+
+/* This is a trimmed and slightly modified version of
+   fstab_argp.options which uses _PATH_MOUNTED instead of _PATH_MNTTAB
+   in the doc strings. */
+static const struct argp_option fstab_argp_mtab_opts[] =
+{
+  {"all",       'a', 0,      0, "Do all filesystems in " _PATH_MOUNTED},
+  {0,           'A', 0,      OPTION_ALIAS },
+  {"fstab",     'F', "FILE", 0, "File to use instead of " _PATH_MOUNTED},
+  {"fstype",    't', "TYPE", 0, "Do only filesystems of given type(s)"},
+  {"exclude-root",'R',0,      0,
+     "Exclude root (/) filesystem from " _PATH_MOUNTED " list"},
+  {"exclude",   'X', "PATTERN", 0, "Exclude directories matching PATTERN"},
+  {}
+};
+
+static error_t
+fstab_argp_mtab_parse_opt (int key, char *arg, struct argp_state *state)
+{
+  return fstab_argp.parser (key, arg, state);
+}
+
+static struct argp fstab_argp_mtab = {
+ .options = fstab_argp_mtab_opts,
+ .parser = fstab_argp_mtab_parse_opt,
+};
+
+/* Unmount one filesystem. */
+static error_t
+do_umount (struct fs *fs)
+{
+  error_t err = 0;
+
+  file_t node = file_name_lookup(fs->mntent.mnt_dir, O_NOTRANS, 0666);
+  if (node == MACH_PORT_NULL)
+    {
+      error(0, errno, "%s", fs->mntent.mnt_dir);
+      return errno;
+    }
+
+  if (verbose)
+    printf ("settrans -pg%s%s %s\n",
+            goaway_flags & FSYS_GOAWAY_NOSYNC? "S": "",
+            goaway_flags & FSYS_GOAWAY_FORCE? "f": "",
+            fs->mntent.mnt_dir);
+
+  if (! fake)
+    {
+      err = file_set_translator (node,
+                                 passive_flags, active_flags, goaway_flags,
+                                 NULL, 0,
+                                 MACH_PORT_NULL, MACH_MSG_TYPE_COPY_SEND);
+      if (err)
+        {
+          error (0, err, "%s", fs->mntent.mnt_dir);
+
+          /* Try remounting readonly instead if requested. */
+          if (readonly)
+            {
+              if (verbose)
+                printf ("fsysopts %s --readonly\n", fs->mntent.mnt_dir);
+
+              error_t e = fs_set_readonly (fs, TRUE);
+              if (e)
+                error (0, e, "%s", fs->mntent.mnt_dir);
+            }
+        }
+    }
+
+  mach_port_deallocate (mach_task_self (), node);
+  return err;
+}
+
+int
+main (int argc, char **argv)
+{
+  error_t err;
+
+  argp_parse (&argp, argc, argv, 0, 0, &fstab_params);
+
+  if (! targets && (fstab_params.types == 0
+                    || strncasecmp (fstab_params.types, "no", 2) == 0))
+    {
+      /* Always add the type "swap" to the list of types to exclude. */
+      err = argz_add (&fstab_params.types, &fstab_params.types_len,
+                     "no"MNTTYPE_SWAP);
+      if (err)
+       error (3, ENOMEM, "parsing arguments");
+    }
+
+  /* Read the mtab file by default. */
+  if (! fstab_params.fstab_path)
+    fstab_params.fstab_path = _PATH_MOUNTED;
+
+  struct fstab *fstab = fstab_argp_create (&fstab_params, NULL, 0);
+  if (! fstab)
+    error (3, ENOMEM, "fstab creation");
+
+  if (targets)
+    for (char *t = targets; t; t = argz_next (targets, targets_len, t))
+      {
+        /* Figure out if t is the device or the mountpoint. */
+        struct fs *fs = fstab_find_mount (fstab, t);
+        if (! fs)
+          {
+            fs = fstab_find_device (fstab, t);
+            if (! fs)
+              {
+                error (0, 0, "could not find entry for: %s", t);
+                err |= ENOENT;
+              }
+          }
+
+        if (fs)
+          err |= do_umount (fs);
+      }
+  else
+    {
+      /* Sort entries. */
+      size_t count = 0;
+      for (struct fs *fs = fstab->entries; fs; fs = fs->next)
+        count += 1;
+
+      char **entries = malloc (count * sizeof (char *));
+      if (! entries)
+        error (3, ENOMEM, "allocating entries array");
+
+      char **p = entries;
+      for (struct fs *fs = fstab->entries; fs; fs = fs->next)
+        *p++ = fs->mntent.mnt_dir;
+
+      /* Reverse lexicographical order. */
+      int compare_entries (const void *a, const void *b)
+        {
+          return -strcmp ((char *) a, (char *) b);
+        }
+
+      qsort (entries, count, sizeof (char *), compare_entries);
+
+      for (int i = 0; i < count; i++)
+        {
+          struct fs *fs = fstab_find_mount (fstab, entries[i]);
+          if (! fs)
+            error (4, 0, "could not find entry for: %s", entries[i]);
+
+          if (! match_options (&fs->mntent))
+            continue;
+
+          err |= do_umount (fs);
+        }
+    }
+  return err? EXIT_FAILURE: EXIT_SUCCESS;
+}
-- 
1.7.10.4




reply via email to

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