From 69c5f5e4421f231cc3ed94de8b19afc11cdec66f Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Thu, 15 Aug 2013 08:23:17 +0200 Subject: umount: add a umount utility 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 | 358 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 364 insertions(+), 4 deletions(-) create mode 100644 utils/umount.c (limited to 'utils') diff --git a/utils/Makefile b/utils/Makefile index 6975fb59..de33751a 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 @@ -57,7 +59,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 @@ -73,7 +75,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 00000000..b0d3877a --- /dev/null +++ b/utils/umount.c @@ -0,0 +1,358 @@ +/* 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, see . */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "match-options.h" +#include "../sutils/fstab.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 source_goaway; +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[] = +{ + {NULL, 'd', 0, 0, "Also ask the source translator to go away"}, + {"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 'd': + source_goaway = 1; + 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 -apg%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) + { + if (strcmp (fs->mntent.mnt_fsname, "") != 0 && + strcmp (fs->mntent.mnt_fsname, "none") != 0) + { + if (verbose) + printf ("settrans -ag%s%s %s\n", + goaway_flags & FSYS_GOAWAY_NOSYNC? "S": "", + goaway_flags & FSYS_GOAWAY_FORCE? "f": "", + fs->mntent.mnt_fsname); + + file_t source = file_name_lookup (fs->mntent.mnt_fsname, + O_NOTRANS, + 0666); + if (source == MACH_PORT_NULL) + { + error (0, errno, "%s", fs->mntent.mnt_fsname); + return errno; + } + + err = file_set_translator (source, + 0, active_flags, goaway_flags, + NULL, 0, + MACH_PORT_NULL, + MACH_MSG_TYPE_COPY_SEND); + if (err) + error (0, err, "%s", fs->mntent.mnt_fsname); + + mach_port_deallocate (mach_task_self (), source); + + } + } + else + { + 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); + } + } + } + + /* Deallocate the reference so that unmounting nested translators + works properly. */ + mach_port_deallocate (mach_task_self (), node); + return err; +} + +int +main (int argc, char **argv) +{ + error_t err; + + err = argp_parse (&argp, argc, argv, 0, 0, &fstab_params); + if (err) + error (3, err, "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); + + /* As last resort, just assume it is the mountpoint. */ + struct mntent m = + { + mnt_fsname: "", + mnt_dir: t, + mnt_type: "", + mnt_opts: 0, + mnt_freq: 0, + mnt_passno: 0, + }; + + err = fstab_add_mntent (fstab, &m, &fs); + if (err) + error (2, err, "%s", t); + } + } + + if (fs) + err |= do_umount (fs); + } + else + { + /* Sort entries in reverse lexicographical order so that the + longest mount points are unmounted first. This makes sure + that nested mounts are handled properly. */ + 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; +} -- cgit v1.2.3