summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrian Behlendorf <[email protected]>2010-12-08 16:40:11 -0800
committerBrian Behlendorf <[email protected]>2011-01-28 12:47:57 -0800
commit3b8cfee8af1d966eea75389e2a2e53a5a8dca600 (patch)
tree041d87026a2aee4540e81113df4bc8b254b5fc9a
parentb3259b6a2ba29595dc5f2df0f6def8c7fc6bcb98 (diff)
Enable mount.zfs helper
While not strictly required to mount a zfs filesystem using a mount helper has certain advantages. First, we need it if we want to honor the mount behavior as found on Solaris. As part of the mount we need to validate that the dataset has the legacy mount property set if we are using 'mount' instead of 'zfs mount'. Secondly, by using a mount helper we can automatically load the zpl kernel module. This way you can just issue a 'mount' or 'zfs mount' and it will just work. Finally, it gives us common hook in user space to add any zfs specific mount options we might want. At the moment we don't have any but now the infrastructure is at least in place.
-rw-r--r--cmd/zfs/zfs_main.c220
1 files changed, 188 insertions, 32 deletions
diff --git a/cmd/zfs/zfs_main.c b/cmd/zfs/zfs_main.c
index e2c39a856..2aa3e2ef1 100644
--- a/cmd/zfs/zfs_main.c
+++ b/cmd/zfs/zfs_main.c
@@ -3864,45 +3864,208 @@ zfs_do_python(int argc, char **argv)
return (-1);
}
+typedef struct option_map {
+ const char *name;
+ int mask;
+} option_map_t;
+
+static const option_map_t option_map[] = {
+ /* Canonicalized filesystem independent options from mount(8) */
+ { MNTOPT_NOAUTO, MS_COMMENT },
+ { MNTOPT_DEFAULTS, MS_COMMENT },
+ { MNTOPT_NODEVICES, MS_NODEV },
+ { MNTOPT_DIRSYNC, MS_DIRSYNC },
+ { MNTOPT_NOEXEC, MS_NOEXEC },
+ { MNTOPT_GROUP, MS_GROUP },
+ { MNTOPT_NETDEV, MS_COMMENT },
+ { MNTOPT_NOFAIL, MS_COMMENT },
+ { MNTOPT_NOSUID, MS_NOSUID },
+ { MNTOPT_OWNER, MS_OWNER },
+ { MNTOPT_REMOUNT, MS_REMOUNT },
+ { MNTOPT_RO, MS_RDONLY },
+ { MNTOPT_SYNC, MS_SYNCHRONOUS },
+ { MNTOPT_USER, MS_USERS },
+ { MNTOPT_USERS, MS_USERS },
+#ifdef MS_NOATIME
+ { MNTOPT_NOATIME, MS_NOATIME },
+#endif
+#ifdef MS_NODIRATIME
+ { MNTOPT_NODIRATIME, MS_NODIRATIME },
+#endif
+#ifdef MS_RELATIME
+ { MNTOPT_RELATIME, MS_RELATIME },
+#endif
+#ifdef MS_STRICTATIME
+ { MNTOPT_DFRATIME, MS_STRICTATIME },
+#endif
+#ifdef HAVE_SELINUX
+ { MNTOPT_CONTEXT, MS_COMMENT },
+ { MNTOPT_FSCONTEXT, MS_COMMENT },
+ { MNTOPT_DEFCONTEXT, MS_COMMENT },
+ { MNTOPT_ROOTCONTEXT, MS_COMMENT },
+#endif
+#ifdef MS_I_VERSION
+ { MNTOPT_IVERSION, MS_I_VERSION },
+#endif
+#ifdef MS_MANDLOCK
+ { MNTOPT_NBMAND, MS_MANDLOCK },
+#endif
+ /* Valid options not found in mount(8) */
+ { MNTOPT_BIND, MS_BIND },
+ { MNTOPT_RBIND, MS_BIND|MS_REC },
+ { MNTOPT_COMMENT, MS_COMMENT },
+ { MNTOPT_BOOTWAIT, MS_COMMENT },
+ { MNTOPT_NOBOOTWAIT, MS_COMMENT },
+ { MNTOPT_OPTIONAL, MS_COMMENT },
+ { MNTOPT_SHOWTHROUGH, MS_COMMENT },
+#ifdef MS_NOSUB
+ { MNTOPT_NOSUB, MS_NOSUB },
+#endif
+#ifdef MS_SILENT
+ { MNTOPT_QUIET, MS_SILENT },
+#endif
+ /* Custom zfs options */
+ { MNTOPT_NOXATTR, MS_COMMENT },
+ { NULL, 0 } };
+
/*
- * Called when invoked as /etc/fs/zfs/mount. Do the mount if the mountpoint is
- * 'legacy'. Otherwise, complain that use should be using 'zfs mount'.
+ * Break the mount option in to a name/value pair. The name is
+ * validated against the option map and mount flags set accordingly.
+ */
+static int
+parse_option(char *mntopt, unsigned long *mntflags, int sloppy)
+{
+ const option_map_t *opt;
+ char *ptr, *name, *value = NULL;
+ int rc;
+
+ name = strdup(mntopt);
+ if (name == NULL)
+ return (ENOMEM);
+
+ for (ptr = name; ptr && *ptr; ptr++) {
+ if (*ptr == '=') {
+ *ptr = '\0';
+ value = ptr+1;
+ break;
+ }
+ }
+
+ for (opt = option_map; opt->name != NULL; opt++) {
+ if (strncmp(name, opt->name, strlen(name)) == 0) {
+ *mntflags |= opt->mask;
+
+ /* MS_USERS implies default user options */
+ if (opt->mask & (MS_USERS))
+ *mntflags |= (MS_NOEXEC|MS_NOSUID|MS_NODEV);
+
+ /* MS_OWNER|MS_GROUP imply default owner options */
+ if (opt->mask & (MS_OWNER | MS_GROUP))
+ *mntflags |= (MS_NOSUID|MS_NODEV);
+
+ rc = 0;
+ goto out;
+ }
+ }
+
+ if (!sloppy)
+ rc = ENOENT;
+out:
+ /* If required further process on the value may be done here */
+ free(name);
+ return (rc);
+}
+
+/*
+ * Translate the mount option string in to MS_* mount flags for the
+ * kernel vfs. When sloppy is non-zero unknown options will be ignored
+ * otherwise they are considered fatal are copied in to badopt.
+ */
+static int
+parse_options(char *mntopts, unsigned long *mntflags, int sloppy, char *badopt)
+{
+ int rc = 0, quote = 0;
+ char *ptr, *opt, *opts;
+
+ opts = strdup(mntopts);
+ if (opts == NULL)
+ return (ENOMEM);
+
+ *mntflags = 0;
+ opt = NULL;
+
+ /*
+ * Scan through all mount options which must be comma delimited.
+ * We must be careful to notice regions which are double quoted
+ * and skip commas in these regions. Each option is then checked
+ * to determine if it is a known option.
+ */
+ for (ptr = opts; ptr && *ptr; ptr++) {
+ if (opt == NULL)
+ opt = ptr;
+
+ if (*ptr == '"')
+ quote = !quote;
+
+ if (quote)
+ continue;
+
+ if ((*ptr == ',') || (*ptr == '\0')) {
+ *ptr = '\0';
+ rc = parse_option(opt, mntflags, sloppy);
+ if (rc) {
+ strcpy(badopt, opt);
+ goto out;
+ }
+
+ opt = NULL;
+ }
+ }
+out:
+ free(opts);
+ return (rc);
+}
+
+/*
+ * Called when invoked as /sbin/mount.zfs, mount helper for mount(8).
*/
-#ifdef HAVE_ZPL
static int
manual_mount(int argc, char **argv)
{
zfs_handle_t *zhp;
- char mountpoint[ZFS_MAXPROPLEN];
+ char legacy[ZFS_MAXPROPLEN];
char mntopts[MNT_LINE_MAX] = { '\0' };
- int ret;
- int c;
- int flags = 0;
- char *dataset, *path;
+ char badopt[MNT_LINE_MAX] = { '\0' };
+ char *dataset, *mntpoint;
+ unsigned long mntflags;
+ int sloppy = 0, fake = 0, verbose = 0;
+ int rc, c;
/* check options */
- while ((c = getopt(argc, argv, ":mo:O")) != -1) {
+ while ((c = getopt(argc, argv, "sfnvo:h?")) != -1) {
switch (c) {
- case 'o':
- (void) strlcpy(mntopts, optarg, sizeof (mntopts));
+ case 's':
+ sloppy = 1;
break;
- case 'O':
- flags |= MS_OVERLAY;
+ case 'f':
+ fake = 1;
break;
- case 'm':
- flags |= MS_NOMNTTAB;
+ case 'n':
+ /* Ignored, handled by mount(8) */
break;
- case ':':
- (void) fprintf(stderr, gettext("missing argument for "
- "'%c' option\n"), optopt);
- usage(B_FALSE);
+ case 'v':
+ verbose++;
+ break;
+ case 'o':
+ (void) strlcpy(mntopts, optarg, sizeof (mntopts));
break;
+ case 'h':
case '?':
- (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+ (void) fprintf(stderr, gettext("Invalid option '%c'\n"),
optopt);
- (void) fprintf(stderr, gettext("usage: mount [-o opts] "
- "<path>\n"));
- return (2);
+ (void) fprintf(stderr, gettext("Usage: mount.zfs "
+ "[-sfnv] [-o options] <dataset> <mountpoint>\n"));
+ return (MOUNT_USAGE);
}
}
@@ -3999,7 +4162,6 @@ manual_unmount(int argc, char **argv)
return (unshare_unmount_path(OP_MOUNT, argv[0], flags, B_TRUE));
}
-#endif /* HAVE_ZPL */
static int
find_command_idx(char *command, int *idx)
@@ -4098,9 +4260,7 @@ main(int argc, char **argv)
{
int ret;
int i = 0;
-#ifdef HAVE_ZPL
char *progname;
-#endif
char *cmdname;
(void) setlocale(LC_ALL, "");
@@ -4114,20 +4274,16 @@ main(int argc, char **argv)
return (1);
}
-#ifdef HAVE_ZPL
/*
* This command also doubles as the /etc/fs mount and unmount program.
* Determine if we should take this behavior based on argv[0].
*/
progname = basename(argv[0]);
- if (strcmp(progname, "mount") == 0) {
+ if (strcmp(progname, "mount.zfs") == 0) {
ret = manual_mount(argc, argv);
- } else if (strcmp(progname, "umount") == 0) {
+ } else if (strcmp(progname, "umount.zfs") == 0) {
ret = manual_unmount(argc, argv);
} else {
-#else
- {
-#endif /* HAVE_ZPL */
/*
* Make sure the user has specified some command.
*/