X-Git-Url: https://git.camperquake.de/gitweb.cgi?a=blobdiff_plain;f=cmd%2Fzfs%2Fzfs_main.c;h=b6dc6d49d3b7c47a0fa76f700dae812071e196b8;hb=e0f86c98620bbc085a7edddd8f6dbf82e4783a46;hp=e1cca2d91b99568dfb51b266cb89c46ec9aa500c;hpb=95c4cae39fd77b5b00810eb976c9a6462d86ccd4;p=zfs.git diff --git a/cmd/zfs/zfs_main.c b/cmd/zfs/zfs_main.c index e1cca2d..b6dc6d4 100644 --- a/cmd/zfs/zfs_main.c +++ b/cmd/zfs/zfs_main.c @@ -238,7 +238,7 @@ get_usage(zfs_help_t idx) case HELP_ROLLBACK: return (gettext("\trollback [-rRf] \n")); case HELP_SEND: - return (gettext("\tsend [-RDp] [-[iI] snapshot] \n")); + return (gettext("\tsend [-vRDp] [-[iI] snapshot] \n")); case HELP_SET: return (gettext("\tset " " ...\n")); @@ -318,7 +318,6 @@ safe_malloc(size_t size) return (data); } -#ifdef HAVE_ZPL static char * safe_strdup(char *str) { @@ -329,7 +328,6 @@ safe_strdup(char *str) return (dupstr); } -#endif /* HAVE_ZPL */ /* * Callback routine that will print out information for each of @@ -497,7 +495,6 @@ parse_depth(char *opt, int *flags) #define PROGRESS_DELAY 2 /* seconds */ -#ifdef HAVE_ZPL static char *pt_reverse = "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"; static time_t pt_begin; static char *pt_header = NULL; @@ -549,7 +546,6 @@ finish_progress(char *done) free(pt_header); pt_header = NULL; } -#endif /* HAVE_ZPL */ /* * zfs clone [-p] [-o prop=value] ... @@ -631,7 +627,6 @@ zfs_do_clone(int argc, char **argv) ret = zfs_clone(zhp, argv[1], props); /* create the mountpoint if necessary */ -#ifdef HAVE_ZPL if (ret == 0) { zfs_handle_t *clone; @@ -643,7 +638,6 @@ zfs_do_clone(int argc, char **argv) zfs_close(clone); } } -#endif /* HAVE_ZPL */ zfs_close(zhp); nvlist_free(props); @@ -831,7 +825,6 @@ zfs_do_create(int argc, char **argv) * verbose error message to let the user know that their filesystem was * in fact created, even if we failed to mount or share it. */ -#ifdef HAVE_ZPL if (canmount == ZFS_CANMOUNT_ON) { if (zfs_mount(zhp, NULL, 0) != 0) { (void) fprintf(stderr, gettext("filesystem " @@ -843,7 +836,6 @@ zfs_do_create(int argc, char **argv) ret = 1; } } -#endif /* HAVE_ZPL */ error: if (zhp) @@ -1887,16 +1879,6 @@ zfs_do_userspace(int argc, char **argv) zfs_userquota_prop_t p; int error; - /* - * Try the python version. If the execv fails, we'll continue - * and do a simplistic implementation. - */ - (void) execv(pypath, argv-1); - - (void) printf("internal error: %s not found\n" - "falling back on built-in implementation, " - "some features will not work\n", pypath); - if ((zhp = zfs_open(g_zfs, argv[argc-1], ZFS_TYPE_DATASET)) == NULL) return (1); @@ -2340,7 +2322,6 @@ typedef struct rollback_cbdata { * 'cb_dependent' is set, then this is a dependent and we should report it * without checking the transaction group. */ -#ifdef HAVE_ZPL static int rollback_check(zfs_handle_t *zhp, void *data) { @@ -2400,12 +2381,10 @@ rollback_check(zfs_handle_t *zhp, void *data) zfs_close(zhp); return (0); } -#endif /* HAVE_ZPL */ static int zfs_do_rollback(int argc, char **argv) { -#ifdef HAVE_ZPL int ret; int c; boolean_t force = B_FALSE; @@ -2487,9 +2466,6 @@ out: return (0); else return (1); -#else - return ENOSYS; -#endif /*HAVE_ZPL*/ } /* @@ -2955,7 +2931,6 @@ zfs_do_release(int argc, char **argv) #define SPINNER_TIME 3 /* seconds */ #define MOUNT_TIME 5 /* seconds */ -#ifdef HAVE_ZPL static int get_one_dataset(zfs_handle_t *zhp, void *data) { @@ -3275,7 +3250,7 @@ share_mount(int op, int argc, char **argv) int flags = 0; /* check options */ - while ((c = getopt(argc, argv, op == OP_MOUNT ? ":avo:O" : "a")) + while ((c = getopt(argc, argv, op == OP_MOUNT ? ":avo:" : "a")) != -1) { switch (c) { case 'a': @@ -3298,9 +3273,6 @@ share_mount(int op, int argc, char **argv) append_options(options, optarg); break; - case 'O': - flags |= MS_OVERLAY; - break; case ':': (void) fprintf(stderr, gettext("missing argument for " "'%c' option\n"), optopt); @@ -3368,7 +3340,7 @@ share_mount(int op, int argc, char **argv) } /* - * When mount is given no arguments, go through /etc/mnttab and + * When mount is given no arguments, go through /etc/mtab and * display any active ZFS mounts. We hide any snapshots, since * they are controlled automatically. */ @@ -3403,7 +3375,6 @@ share_mount(int op, int argc, char **argv) return (ret); } -#endif /* HAVE_ZPL */ /* * zfs mount -a [nfs] @@ -3414,11 +3385,7 @@ share_mount(int op, int argc, char **argv) static int zfs_do_mount(int argc, char **argv) { -#ifdef HAVE_ZPL return (share_mount(OP_MOUNT, argc, argv)); -#else - return ENOSYS; -#endif /* HAVE_ZPL */ } /* @@ -3430,14 +3397,9 @@ zfs_do_mount(int argc, char **argv) static int zfs_do_share(int argc, char **argv) { -#ifdef HAVE_ZPL return (share_mount(OP_SHARE, argc, argv)); -#else - return ENOSYS; -#endif /* HAVE_ZPL */ } -#ifdef HAVE_ZPL typedef struct unshare_unmount_node { zfs_handle_t *un_zhp; char *un_mountp; @@ -3456,7 +3418,7 @@ unshare_unmount_compare(const void *larg, const void *rarg, void *unused) /* * Convenience routine used by zfs_do_umount() and manual_unmount(). Given an - * absolute path, find the entry /etc/mnttab, verify that its a ZFS filesystem, + * absolute path, find the entry /etc/mtab, verify that its a ZFS filesystem, * and unmount it appropriately. */ static int @@ -3470,7 +3432,7 @@ unshare_unmount_path(int op, char *path, int flags, boolean_t is_manual) ino_t path_inode; /* - * Search for the path in /etc/mnttab. Rather than looking for the + * Search for the path in /etc/mtab. Rather than looking for the * specific path, which can be fooled by non-standard paths (i.e. ".." * or "//"), we stat() the path and search for the corresponding * (major,minor) device pair. @@ -3497,7 +3459,7 @@ unshare_unmount_path(int op, char *path, int flags, boolean_t is_manual) "currently mounted\n"), cmdname, path); return (1); } - (void) fprintf(stderr, gettext("warning: %s not in mnttab\n"), + (void) fprintf(stderr, gettext("warning: %s not in mtab\n"), path); if ((ret = umount2(path, flags)) != 0) (void) fprintf(stderr, gettext("%s: %s\n"), path, @@ -3539,8 +3501,8 @@ unshare_unmount_path(int op, char *path, int flags, boolean_t is_manual) strcmp(smbshare_prop, "off") == 0) { (void) fprintf(stderr, gettext("cannot unshare " "'%s': legacy share\n"), path); - (void) fprintf(stderr, gettext("use " - "unshare(1M) to unshare this filesystem\n")); + (void) fprintf(stderr, gettext("use exportfs(8) " + "or smbcontrol(1) to unshare this filesystem\n")); } else if (!zfs_is_shared(zhp)) { (void) fprintf(stderr, gettext("cannot unshare '%s': " "not currently shared\n"), path); @@ -3559,7 +3521,7 @@ unshare_unmount_path(int op, char *path, int flags, boolean_t is_manual) (void) fprintf(stderr, gettext("cannot unmount " "'%s': legacy mountpoint\n"), zfs_get_name(zhp)); - (void) fprintf(stderr, gettext("use umount(1M) " + (void) fprintf(stderr, gettext("use umount(8) " "to unmount this filesystem\n")); } else { ret = zfs_unmountall(zhp, flags); @@ -3609,8 +3571,8 @@ unshare_unmount(int op, int argc, char **argv) /* * We could make use of zfs_for_each() to walk all datasets in * the system, but this would be very inefficient, especially - * since we would have to linearly search /etc/mnttab for each - * one. Instead, do one pass through /etc/mnttab looking for + * since we would have to linearly search /etc/mtab for each + * one. Instead, do one pass through /etc/mtab looking for * zfs entries and call zfs_unmount() for each one. * * Things get a little tricky if the administrator has created @@ -3821,7 +3783,6 @@ unshare_unmount(int op, int argc, char **argv) return (ret); } -#endif /* HAVE_ZPL */ /* * zfs unmount -a @@ -3832,11 +3793,7 @@ unshare_unmount(int op, int argc, char **argv) static int zfs_do_unmount(int argc, char **argv) { -#ifdef HAVE_ZPL return (unshare_unmount(OP_MOUNT, argc, argv)); -#else - return ENOSYS; -#endif /* HAVE_ZPL */ } /* @@ -3848,11 +3805,7 @@ zfs_do_unmount(int argc, char **argv) static int zfs_do_unshare(int argc, char **argv) { -#ifdef HAVE_ZPL return (unshare_unmount(OP_SHARE, argc, argv)); -#else - return ENOSYS; -#endif /* HAVE_ZPL */ } /* ARGSUSED */ @@ -3864,369 +3817,6 @@ 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 } }; - -/* - * 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). - */ -static int -manual_mount(int argc, char **argv) -{ - zfs_handle_t *zhp; - char legacy[ZFS_MAXPROPLEN]; - char mntopts[MNT_LINE_MAX] = { '\0' }; - 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, "sfnvo:h?")) != -1) { - switch (c) { - case 's': - sloppy = 1; - break; - case 'f': - fake = 1; - break; - case 'n': - /* Ignored, handled by mount(8) */ - break; - case 'v': - verbose++; - break; - case 'o': - (void) strlcpy(mntopts, optarg, sizeof (mntopts)); - break; - case 'h': - case '?': - (void) fprintf(stderr, gettext("Invalid option '%c'\n"), - optopt); - (void) fprintf(stderr, gettext("Usage: mount.zfs " - "[-sfnv] [-o options] \n")); - return (MOUNT_USAGE); - } - } - - argc -= optind; - argv += optind; - - /* check that we only have two arguments */ - if (argc != 2) { - if (argc == 0) - (void) fprintf(stderr, gettext("missing dataset " - "argument\n")); - else if (argc == 1) - (void) fprintf(stderr, - gettext("missing mountpoint argument\n")); - else - (void) fprintf(stderr, gettext("too many arguments\n")); - (void) fprintf(stderr, "usage: mount \n"); - return (MOUNT_USAGE); - } - - dataset = argv[0]; - mntpoint = argv[1]; - - /* try to open the dataset to access the mount point */ - if ((zhp = zfs_open(g_zfs, dataset, ZFS_TYPE_FILESYSTEM)) == NULL) { - (void) fprintf(stderr, gettext("filesystem '%s' cannot be " - "mounted, unable to open the dataset\n"), dataset); - return (MOUNT_USAGE); - } - - (void) zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, legacy, - sizeof (legacy), NULL, NULL, 0, B_FALSE); - - zfs_close(zhp); - - /* check for legacy mountpoint or util mount option */ - if ((!strcmp(legacy, ZFS_MOUNTPOINT_LEGACY) == 0) && - (strstr(mntopts, MNTOPT_ZFSUTIL) == NULL)) { - (void) fprintf(stderr, gettext("filesystem '%s' cannot be " - "mounted using 'mount -a -t zfs'\n"), dataset); - (void) fprintf(stderr, gettext("Use 'zfs set mountpoint=%s' " - "instead.\n"), mntpoint); - (void) fprintf(stderr, gettext("If you must use 'mount -a -t " - "zfs' or /etc/fstab, use 'zfs set mountpoint=legacy'.\n")); - (void) fprintf(stderr, gettext("See zfs(8) for more " - "information.\n")); - return (MOUNT_USAGE); - } - - /* validate mount options and set mntflags */ - rc = parse_options(mntopts, &mntflags, sloppy, badopt); - if (rc) { - switch (rc) { - case ENOMEM: - (void) fprintf(stderr, gettext("filesystem '%s' " - "cannot be mounted due to a memory allocation " - "failure\n"), dataset); - return (MOUNT_SYSERR); - case EINVAL: - (void) fprintf(stderr, gettext("filesystem '%s' " - "cannot be mounted of due to the invalid option " - "'%s'\n"), dataset, badopt); - (void) fprintf(stderr, gettext("Use the '-s' option " - "to ignore the bad mount option.\n")); - return (MOUNT_USAGE); - default: - (void) fprintf(stderr, gettext("filesystem '%s' " - "cannot be mounted due to internal error %d\n"), - dataset, rc); - return (MOUNT_SOFTWARE); - } - } - - if (verbose > 2) - printf("mount.zfs: dataset: \"%s\", mountpoint: \"%s\" " - "mountflags: 0x%lx, mountopts: \"%s\"\n", dataset, - mntpoint, mntflags, mntopts); - - /* load the zfs posix layer module (zpl) */ - if (libzfs_load_module("zpl")) { - (void) fprintf(stderr, gettext("filesystem '%s' cannot be " - "mounted without the zpl kernel module\n"), dataset); - (void) fprintf(stderr, gettext("Use 'dmesg' to determine why " - "the module could not be loaded.\n")); - return (MOUNT_SYSERR); - } - - if (!fake) { - rc = mount(dataset, mntpoint, MNTTYPE_ZFS, mntflags, mntopts); - if (rc) { - (void) fprintf(stderr, gettext("filesystem '%s' can" - "not be mounted due to error %d\n"), dataset, rc); - return (MOUNT_USAGE); - } - } - - return (MOUNT_SUCCESS); -} - -#ifdef HAVE_UNMOUNT_HELPER -/* - * Called when invoked as /sbin/umount.zfs, mount helper for mount(8). - * Unlike a manual mount, we allow unmounts of non-legacy filesystems, - * as this is the dominant administrative interface. - */ -static int -manual_unmount(int argc, char **argv) -{ - int verbose = 0, flags = 0; - int c; - - /* check options */ - while ((c = getopt(argc, argv, "nlfvrh?")) != -1) { - switch (c) { - case 'n': - /* Ignored, handled by mount(8) */ - break; - case 'l': - flags = MS_DETACH; - break; - case 'f': - flags = MS_FORCE; - break; - case 'v': - verbose++; - break; - case 'r': - /* Remount read-only on umount failure, unsupported */ - (void) fprintf(stderr, gettext("Unsupported option " - "'%c'\n"), optopt); - return (MOUNT_USAGE); - case 'h': - case '?': - (void) fprintf(stderr, gettext("Invalid option '%c'\n"), - optopt); - (void) fprintf(stderr, gettext("Usage: umount.zfs " - "[-nlfvr] \n")); - return (MOUNT_USAGE); - } - } - - argc -= optind; - argv += optind; - - /* check that we only have one argument */ - if (argc != 1) { - if (argc == 0) - (void) fprintf(stderr, gettext("missing mountpoint " - "argument\n")); - else - (void) fprintf(stderr, gettext("too many arguments\n")); - - (void) fprintf(stderr, gettext("Usage: umount.zfs [-nlfvr] " - "\n")); - return (MOUNT_USAGE); - } - - return (unshare_unmount_path(OP_MOUNT, argv[0], flags, B_TRUE)); -} -#endif /* HAVE_UNMOUNT_HELPER */ - static int find_command_idx(char *command, int *idx) { @@ -4324,7 +3914,6 @@ main(int argc, char **argv) { int ret; int i = 0; - char *progname; char *cmdname; (void) setlocale(LC_ALL, ""); @@ -4339,78 +3928,64 @@ main(int argc, char **argv) } /* - * This command also doubles as the /etc/fs mount and unmount program. - * Determine if we should take this behavior based on argv[0]. + * Make sure the user has specified some command. */ - progname = basename(argv[0]); - if (strcmp(progname, "mount.zfs") == 0) { - ret = manual_mount(argc, argv); -#ifdef HAVE_UNMOUNT_HELPER - } else if (strcmp(progname, "umount.zfs") == 0) { - ret = manual_unmount(argc, argv); -#endif /* HAVE_UNMOUNT_HELPER */ - } else { - /* - * Make sure the user has specified some command. - */ - if (argc < 2) { - (void) fprintf(stderr, gettext("missing command\n")); - usage(B_FALSE); - } + if (argc < 2) { + (void) fprintf(stderr, gettext("missing command\n")); + usage(B_FALSE); + } - cmdname = argv[1]; + cmdname = argv[1]; - /* - * The 'umount' command is an alias for 'unmount' - */ - if (strcmp(cmdname, "umount") == 0) - cmdname = "unmount"; + /* + * The 'umount' command is an alias for 'unmount' + */ + if (strcmp(cmdname, "umount") == 0) + cmdname = "unmount"; - /* - * The 'recv' command is an alias for 'receive' - */ - if (strcmp(cmdname, "recv") == 0) - cmdname = "receive"; + /* + * The 'recv' command is an alias for 'receive' + */ + if (strcmp(cmdname, "recv") == 0) + cmdname = "receive"; - /* - * Special case '-?' - */ - if ((strcmp(cmdname, "-?") == 0) || - (strcmp(cmdname, "--help") == 0)) - usage(B_TRUE); + /* + * Special case '-?' + */ + if ((strcmp(cmdname, "-?") == 0) || + (strcmp(cmdname, "--help") == 0)) + usage(B_TRUE); - if ((g_zfs = libzfs_init()) == NULL) - return (1); + if ((g_zfs = libzfs_init()) == NULL) + return (1); - zpool_set_history_str("zfs", argc, argv, history_str); - verify(zpool_stage_history(g_zfs, history_str) == 0); + zpool_set_history_str("zfs", argc, argv, history_str); + verify(zpool_stage_history(g_zfs, history_str) == 0); - libzfs_print_on_error(g_zfs, B_TRUE); + libzfs_print_on_error(g_zfs, B_TRUE); - /* - * Run the appropriate command. - */ - libzfs_mnttab_cache(g_zfs, B_TRUE); - if (find_command_idx(cmdname, &i) == 0) { - current_command = &command_table[i]; - ret = command_table[i].func(argc - 1, argv + 1); - } else if (strchr(cmdname, '=') != NULL) { - verify(find_command_idx("set", &i) == 0); - current_command = &command_table[i]; - ret = command_table[i].func(argc, argv); - } else { - (void) fprintf(stderr, gettext("unrecognized " - "command '%s'\n"), cmdname); - usage(B_FALSE); - ret = 1; - } - libzfs_mnttab_cache(g_zfs, B_FALSE); + /* + * Run the appropriate command. + */ + libzfs_mnttab_cache(g_zfs, B_TRUE); + if (find_command_idx(cmdname, &i) == 0) { + current_command = &command_table[i]; + ret = command_table[i].func(argc - 1, argv + 1); + } else if (strchr(cmdname, '=') != NULL) { + verify(find_command_idx("set", &i) == 0); + current_command = &command_table[i]; + ret = command_table[i].func(argc, argv); + } else { + (void) fprintf(stderr, gettext("unrecognized " + "command '%s'\n"), cmdname); + usage(B_FALSE); + ret = 1; } + libzfs_mnttab_cache(g_zfs, B_FALSE); + libzfs_fini(g_zfs); (void) fclose(mnttab_file); - libzfs_fini(g_zfs); - /* * The 'ZFS_ABORT' environment variable causes us to dump core on exit * for the purposes of running ::findleaks.