diff options
author | Roland McGrath <roland@gnu.org> | 1999-11-19 05:10:37 +0000 |
---|---|---|
committer | Roland McGrath <roland@gnu.org> | 1999-11-19 05:10:37 +0000 |
commit | daa03eecddd230fe6af0fbdadf66f05f5097beb6 (patch) | |
tree | 6af5bf9dbec505b4fdc0400ea25069f9e6b6ef7c | |
parent | 99d3db0311f353fdbfa0eac8c862ba1afd7fab67 (diff) |
1999-11-19 Roland McGrath <roland@baalperazim.frob.com>
* mount.c: New file.
* mount.sh: File removed.
* Makefile (special-targets): Remove mount.
(SRCS): mount.sh -> mount.c
(mount): Add deps on ../sutils/fstab.o, ../sutils/clookup.o,
libfshelp and libports.
(../sutils/fstab.o ../sutils/clookup.o): Rule to build in ../sutils.
-rw-r--r-- | utils/Makefile | 18 | ||||
-rw-r--r-- | utils/mount.c | 575 |
2 files changed, 587 insertions, 6 deletions
diff --git a/utils/Makefile b/utils/Makefile index 184c1574..fd8035be 100644 --- a/utils/Makefile +++ b/utils/Makefile @@ -18,17 +18,17 @@ dir := utils makemode := utilities -targets = shd ps settrans showtrans syncfs su mount fsysopts \ +targets = shd ps settrans showtrans syncfs su fsysopts \ storeinfo login w uptime ids loginpr sush vmstat portinfo \ devprobe vminfo addauth rmauth unsu setauth ftpcp ftpdir storecat \ - storeread ping msgport rpctrace -special-targets = mount loginpr sush uptime + storeread ping msgport rpctrace mount +special-targets = loginpr sush uptime SRCS = shd.c ps.c su.c settrans.c syncfs.c showtrans.c addauth.c rmauth.c \ - mount.sh fsysopts.c storeinfo.c login.c loginpr.sh sush.sh w.c \ + fsysopts.c storeinfo.c login.c loginpr.sh sush.sh w.c \ uptime.sh psout.c ids.c vmstat.c portinfo.c devprobe.c vminfo.c \ parse.c frobauth.c frobauth-mod.c setauth.c pids.c nonsugid.c \ unsu.c ftpcp.c ftpdir.c storeread.c storecat.c ping.c msgport.c \ - rpctrace.c + rpctrace.c mount.c LCLHDRS = psout.h parse.h pids.h frobauth.h OBJS = $(filter-out %.sh,$(SRCS:.c=.o)) @@ -66,9 +66,15 @@ ping: ../libthreads/libthreads.a settrans: ../libfshelp/libfshelp.a ../libports/libports.a ../libthreads/libthreads.a ps w ids settrans syncfs showtrans fsysopts storeinfo login vmstat portinfo \ devprobe vminfo addauth freeauth rmauth setauth su unsu ftpcp ftpdir storeread \ - storecat msgport: \ + storecat msgport mount: \ ../libshouldbeinlibc/libshouldbeinlibc.a $(filter-out $(special-targets), $(targets)): %: %.o rpctrace: ../libports/libports.a ../libihash/libihash.a ../libthreads/libthreads.a + +mount: ../sutils/fstab.o ../sutils/clookup.o \ + $(foreach L,fshelp ports,../lib$L/lib$L.a) +../sutils/fstab.o ../sutils/clookup.o: FORCE + $(MAKE) -C $(@D) $(@F) +FORCE: diff --git a/utils/mount.c b/utils/mount.c new file mode 100644 index 00000000..75610bc6 --- /dev/null +++ b/utils/mount.c @@ -0,0 +1,575 @@ +/* Roughly Unix/Linux-compatible `mount' frontend for Hurd translators. + + Copyright (C) 1999 Free Software Foundation, Inc. + + 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 <error.h> +#include <stdlib.h> +#include <fcntl.h> +#include <hurd/fsys.h> +#include <hurd/fshelp.h> +#include <hurd/paths.h> + +#define SEARCH_FMTS _HURD "%sfs\0" _HURD "%s" +#define DEFAULT_FSTYPE "ext2" + +static char *fstype = DEFAULT_FSTYPE; +static char *device, *mountpoint; +static int verbose; +static char *options; +static size_t options_len; +static mach_msg_timeout_t timeout; + +static enum { mount, query } mode; +static enum { qf_standard, qf_fstab, qf_translator } query_format; +static struct fstab_argp_params fstab_params; + + +static const struct argp_option argp_opts[] = +{ + {"timeout", 'T', "MILLISECONDS", 0, "Timeout for translator startup"}, + {"format", 'p', "mount|fstab|translator", OPTION_ARG_OPTIONAL, + "Output format for query (no filesystem arguments)"}, + {0, 0} +}; + +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; + +#define ARGZ(call) \ + err = argz_##call; \ + if (err) \ + argp_failure (state, 100, ENOMEM, "%s", arg); \ + break + case 'r': ARGZ (add (&options, &options_len, "ro")); + case 'w': ARGZ (add (&options, &options_len, "rw")); + case 'u': ARGZ (add (&options, &options_len, "remount")); + case 'o': ARGZ (add_sep (&options, &options_len, arg, ',')); + case 'v': ++verbose; break; +#undef ARGZ + + case 'T': + { + char *end; + unsigned long int ms = strtoul (arg, &end, 10); + if (end && *end == '\0') + timeout = ms; + else + { + argp_error (state, + "--timeout needs a numeric argument (milliseconds)"); + return EINVAL; + } + } + break; + + case 'p': + if (arg == 0 || !strcasecmp (arg, "fstab")) + query_format = qf_fstab; + else if (!strcasecmp (arg, "mount")) + query_format = qf_standard; + else if (!strcasecmp (arg, "translator") + || !strcasecmp (arg, "showtrans")) + query_format = qf_translator; + else + { + argp_error (state, "invalid argument to --format"); + return EINVAL; + } + break; + + case ARGP_KEY_ARG: + if (mountpoint == 0) /* One arg: mountpoint */ + mountpoint = arg; + else if (device == 0) /* Two args: device, mountpoint */ + { + device = mountpoint; + mountpoint = arg; + } + else /* More than two args. */ + { + argp_error (state, "too many arguments"); + return EINVAL; + } + break; + + case ARGP_KEY_NO_ARGS: + if (! params->do_all) + { + params->do_all = 1; + mode = query; + } + break; + + case ARGP_KEY_END: + if (params->do_all && mountpoint) + { + argp_error (state, "filesystem argument not allowed with --all"); + return EINVAL; + } + if (mode == query && options_len != 0) + { + argp_error (state, + "mount options not allowed without filesystem argument"); + return EINVAL; + } + if (mountpoint) + switch (argz_count (params->types, params->types_len)) + { + default: + argp_error (state, + "multiple types not allowed with filesystem argument"); + return EINVAL; + case 1: + fstype = params->types; + params->types = 0; + params->types_len = 0; + break; + case 0: + break; + } + break; + + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + +static const char doc[] = "Start active filesystem translators"; +static const char args_doc[] = "\ +DEVICE\t(in " _PATH_MNTTAB ")\n\ +DIRECTORY\t(in " _PATH_MNTTAB ")\n\ +[-t TYPE] DEVICE DIRECTORY\n\ +-a"; +static const struct argp_child argp_kids[] = +{ { &fstab_argp, 0, + "Filesystem selection (if no explicit filesystem arguments given):", 2 }, + { 0 } }; +static struct argp argp = { argp_opts, parse_opt, args_doc, doc, argp_kids }; + +/* Mount one filesystem. */ +static error_t +do_mount (struct fs *fs, int remount) +{ + error_t err; + char *fsopts, *o; + size_t fsopts_len; + char *mntopts; + size_t mntopts_len; + fsys_t mounted; + + inline void explain (const char *command) + { + if (verbose) + { + const char *o; + printf ("%s %s", command, fs->mntent.mnt_dir); + for (o = fsopts; o; o = argz_next (fsopts, fsopts_len, o)) + printf (" %s", o); + putchar ('\n'); + } + } + + err = fs_fsys (fs, &mounted); + if (err) + { + error (0, err, "cannot determine if %s is already mounted", + fs->mntent.mnt_fsname); + return err; + } + + + /* Produce an argz of translator option arguments from the + given FS's options and the command-line options. */ + +#define ARGZ(call) \ + err = argz_##call; \ + if (err) \ + error (3, ENOMEM, "collecting mount options"); \ + + if (fs->mntent.mnt_opts) + { + /* Append the fstab options to any specified on the command line. */ + ARGZ (create_sep (fs->mntent.mnt_opts, ',', &mntopts, &mntopts_len)); + + /* Remove the `noauto' option, since it's for us not the filesystem. */ + for (o = mntopts; o; o = argz_next (mntopts, mntopts_len, o)) + if (!strcmp (o, MNTOPT_NOAUTO)) + break; + if (o) + argz_delete (&mntopts, &mntopts_len, o); + + ARGZ (append (&mntopts, &mntopts_len, options, options_len)); + } + else + { + mntopts = options; + mntopts_len = options_len; + } + + /* Convert the list of options into a list of switch arguments. */ + fsopts = 0; + fsopts_len = 0; + for (o = mntopts; o; o = argz_next (mntopts, mntopts_len, o)) + if (*o == '-') /* Allow letter opts `-o -r,-E', BSD style. */ + { + ARGZ (add (&fsopts, &fsopts_len, o)); + } + else + { + /* Prepend `--' to the option to make a long option switch, + e.g. `--ro' or `--rsize=1024'. */ + char arg[2 + strlen (o) + 1]; + arg[0] = arg[1] = '-'; + memcpy (&arg[2], o, sizeof arg - 2); + ARGZ (add (&fsopts, &fsopts_len, arg)); + } + + if (mntopts != options) + free (mntopts); +#undef ARGZ + + if (remount) + { + if (mounted == MACH_PORT_NULL) + { + error (0, 0, "%s not already mounted", fs->mntent.mnt_fsname); + return EBUSY; + } + + /* Send an RPC to request the new options, including --update. */ + explain ("fsysopts"); + err = fsys_set_options (mounted, fsopts, fsopts_len, 0); + if (err) + error (0, err, "cannot remount %s", fs->mntent.mnt_fsname); + return err; + } + else + { + /* Error during file lookup; we use this to avoid duplicating error + messages. */ + error_t open_err = 0; + /* The control port for any active translator we start up. */ + fsys_t active_control; + file_t node; /* Port to the underlying node. */ + struct fstype *type; + + /* The callback to start_translator opens NODE as a side effect. */ + error_t open_node (int flags, + mach_port_t *underlying, + mach_msg_type_name_t *underlying_type) + { + node = file_name_lookup (fs->mntent.mnt_dir, + flags | O_NOTRANS, 0666); + if (node == MACH_PORT_NULL) + { + open_err = errno; + return open_err; + } + + *underlying = node; + *underlying_type = MACH_MSG_TYPE_COPY_SEND; + + return 0; + } + + if (mounted != MACH_PORT_NULL) + { + error (0, 0, "%s already mounted", fs->mntent.mnt_fsname); + return EBUSY; + } + + err = fs_type (fs, &type); + if (err) + { + error (0, err, "%s: cannot determine filesystem type", + fs->mntent.mnt_fsname); + return err; + } + if (type->program == 0) + { + error (0, 0, "%s: filesystem type `%s' unknown", + fs->mntent.mnt_fsname, type->name); + return EFTYPE; + } + + /* Stick the translator program name in front of the option switches. */ + err = argz_insert (&fsopts, &fsopts_len, fsopts, type->program); + /* Now stick the device name on the end as the last argument. */ + if (!err) + err = argz_add (&fsopts, &fsopts_len, fs->mntent.mnt_fsname); + if (err) + error (3, ENOMEM, "collecting mount options"); + + /* Now we have a translator command line argz in FSOPTS. */ + + explain ("settrans -a"); + err = fshelp_start_translator (open_node, fsopts, + fsopts, fsopts_len, timeout, + &active_control); + /* If ERR is due to a problem opening the translated node, we print + that name, otherwise, the name of the translator. */ + if (open_err) + error (0, open_err, "cannot mount on %s", fs->mntent.mnt_dir); + else if (err) + error (0, err, "cannot start translator %s", fsopts); + else + { + err = file_set_translator (node, 0, FS_TRANS_SET|FS_TRANS_EXCL, 0, + 0, 0, + active_control, MACH_MSG_TYPE_COPY_SEND); + if (err == EBUSY) + error (0, 0, "%s already mounted on", fs->mntent.mnt_dir); + else if (err) + error (0, err, "cannot set translator on %s", fs->mntent.mnt_dir); + if (err) + fsys_goaway (active_control, FSYS_GOAWAY_FORCE); + mach_port_deallocate (mach_task_self (), active_control); + } + + return err; + } +} + +/* Report the state of one filesystem to stdout. */ +static error_t +do_query (struct fs *fs) +{ + error_t err; + fsys_t fsys; + char _opts[200], *opts = _opts; + size_t opts_len = sizeof opts; + size_t nopts; + + err = fs_fsys (fs, &fsys); + if (err) + return err; + + if (fsys == MACH_PORT_NULL) + /* This filesystem is not mounted. Nothing to report. */ + return 0; + + err = fsys_get_options (fsys, &opts, &opts_len); + if (err) + { + error (0, err, "%s: cannot get filesystem options", + fs->mntent.mnt_fsname); + return err; + } + + nopts = argz_count (opts, opts_len); + if (nopts == 0) + { + error (0, 0, "%s: fsys_get_options returned empty string", + fs->mntent.mnt_dir); + return EGRATUITOUS; + } + + if (query_format == qf_translator) + { + argz_stringify (opts, opts_len, ' '); + printf ("%s: %s\n", fs->mntent.mnt_dir, opts); + } + else + { + char *argv[nopts]; + const char *prog, *device; + + inline const char *fsopt_string (const char *opt) /* canonicalize */ + { + if (opt[0] == '-' && opt[1] == '-') + { + opt += 2; + if (!strcmp (opt, "readonly")) + return "ro"; + if (!strcmp (opt, "writable")) + return "rw"; + } + else + { + if (!strcmp (opt, "-r")) + return "ro"; + if (!strcmp (opt, "-w")) + return "rw"; + } + return opt; + } + inline void print_prog (const char *sfx) + { + if (!strncmp (_HURD, prog, sizeof _HURD - 1)) + { + const char *type = &prog[sizeof _HURD - 1]; + size_t len = strlen (type); + if (!strcmp (&type[len - 2], "fs")) + printf ("%.*s%s", (int) (len - 2), type, sfx); + else + printf ("%s%s", type, sfx); + } + else + printf ("%s%s", prog, sfx); + } + inline int print_opts (char sep) + { + char *opt = argz_next (opts, opts_len, prog); + if (opt == 0) + return 0; + fputs (fsopt_string (opt), stdout); + while ((opt = argz_next (opts, opts_len, opt)) != 0) + printf ("%c%s", sep, fsopt_string (opt)); + return 1; + } + + argz_extract (opts, opts_len, argv); + prog = argv[0]; + + if (nopts < 2) + device = fs->mntent.mnt_fsname; + else + { + static const char type_opt[] = "--store-type="; + device = argv[--nopts]; + opts_len -= strlen (device) + 1; + if (!strncmp (type_opt, argv[nopts - 1], sizeof type_opt - 1)) + { + asprintf ((char **) &device, "%s:%s", + &argv[nopts - 1][sizeof type_opt - 1], device); + opts_len -= strlen (argv[nopts - 1]) + 1; + } + } + + switch (query_format) + { + case qf_standard: + printf ("%s on %s type ", device, fs->mntent.mnt_dir); + print_prog (" ("); + if (print_opts (',')) + puts (")"); + else + puts ("defaults)"); + break; + + case qf_fstab: + printf ("%s\t%s\t", device, fs->mntent.mnt_dir); + print_prog ("\t"); + printf ("%s\t%d %d\n", + print_opts (',') ? "" : "defaults", + fs->mntent.mnt_freq, fs->mntent.mnt_passno); + break; + + case qf_translator: /* impossible */ + break; + } + } + + return 0; +} + +int +main (int argc, char **argv) +{ + unsigned int remount; + struct fstab *fstab; + struct fs *fs; + error_t err; + + argp_parse (&argp, argc, argv, 0, 0, &fstab_params); + + if (!mountpoint && (fstab_params.types == 0 + + || !strncasecmp (fstab_params.types, "no", 2))) + { + /* 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"); + } + + fstab = fstab_argp_create (&fstab_params, SEARCH_FMTS, sizeof SEARCH_FMTS); + + if (device) /* two-argument form */ + { + struct mntent m = + { + mnt_fsname: device, + mnt_dir: mountpoint, + mnt_type: fstype, + mnt_opts: 0, + mnt_freq: 0, mnt_passno: 0 + }; + struct fstype *fst; + + err = fstypes_get (fstab->types, fstype, &fst); + if (err) + error (106, err, "cannot initialize type %s", fstype); + if (fst->program == 0) + error (2, 0, "filesystem type %s not recognized", fstype); + + err = fstab_add_mntent (fstab, &m, &fs); + if (err) + error (2, err, "%s", mountpoint); + } + else if (mountpoint) /* one-argument form */ + { + fs = fstab_find (fstab, mountpoint); + if (!fs) + error (2, 0, "%s: Unknown device or filesystem", mountpoint); + } + else + fs = 0; + + /* This is a convenient way of checking for any `remount' options. */ + remount = 0; + err = argz_replace (&options, &options_len, "remount", "update", &remount); + if (err) + error (3, ENOMEM, "collecting mount options"); + + if (fs != 0) + err = do_mount (fs, remount); + else + switch (mode) + { + case mount: + for (fs = fstab->entries; fs; fs = fs->next) + { + if (fstab_params.do_all && hasmntopt (&fs->mntent, MNTOPT_NOAUTO)) + continue; + err |= do_mount (fs, remount); + } + break; + + case query: + for (fs = fstab->entries; fs; fs = fs->next) + err |= do_query (fs); + break; + } + + return err ? 1 : 0; +} |