1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#include <assert.h>
28#include <ctype.h>
29#include <errno.h>
30#include <libgen.h>
31#include <libintl.h>
32#include <libuutil.h>
33#include <libnvpair.h>
34#include <locale.h>
35#include <stddef.h>
36#include <stdio.h>
37#include <stdlib.h>
38#include <strings.h>
39#include <unistd.h>
40#include <fcntl.h>
41#include <zone.h>
42#include <grp.h>
43#include <pwd.h>
44#include <sys/mkdev.h>
45#include <sys/mntent.h>
46#include <sys/mnttab.h>
47#include <sys/mount.h>
48#include <sys/stat.h>
49#include <sys/fs/zfs.h>
50
51#include <libzfs.h>
52#include <libuutil.h>
53
54#include "zfs_iter.h"
55#include "zfs_util.h"
56
57libzfs_handle_t *g_zfs;
58
59static FILE *mnttab_file;
60static char history_str[HIS_MAX_RECORD_LEN];
61const char *pypath = "/usr/lib/zfs/pyzfs.py";
62
63static int zfs_do_clone(int argc, char **argv);
64static int zfs_do_create(int argc, char **argv);
65static int zfs_do_destroy(int argc, char **argv);
66static int zfs_do_get(int argc, char **argv);
67static int zfs_do_inherit(int argc, char **argv);
68static int zfs_do_list(int argc, char **argv);
69static int zfs_do_mount(int argc, char **argv);
70static int zfs_do_rename(int argc, char **argv);
71static int zfs_do_rollback(int argc, char **argv);
72static int zfs_do_set(int argc, char **argv);
73static int zfs_do_upgrade(int argc, char **argv);
74static int zfs_do_snapshot(int argc, char **argv);
75static int zfs_do_unmount(int argc, char **argv);
76static int zfs_do_share(int argc, char **argv);
77static int zfs_do_unshare(int argc, char **argv);
78static int zfs_do_send(int argc, char **argv);
79static int zfs_do_receive(int argc, char **argv);
80static int zfs_do_promote(int argc, char **argv);
81static int zfs_do_userspace(int argc, char **argv);
82static int zfs_do_python(int argc, char **argv);
83static int zfs_do_hold(int argc, char **argv);
84static int zfs_do_release(int argc, char **argv);
85
86/*
87 * Enable a reasonable set of defaults for libumem debugging on DEBUG builds.
88 */
89
90#ifdef DEBUG
91const char *
92_umem_debug_init(void)
93{
94	return ("default,verbose"); /* $UMEM_DEBUG setting */
95}
96
97const char *
98_umem_logging_init(void)
99{
100	return ("fail,contents"); /* $UMEM_LOGGING setting */
101}
102#endif
103
104typedef enum {
105	HELP_CLONE,
106	HELP_CREATE,
107	HELP_DESTROY,
108	HELP_GET,
109	HELP_INHERIT,
110	HELP_UPGRADE,
111	HELP_LIST,
112	HELP_MOUNT,
113	HELP_PROMOTE,
114	HELP_RECEIVE,
115	HELP_RENAME,
116	HELP_ROLLBACK,
117	HELP_SEND,
118	HELP_SET,
119	HELP_SHARE,
120	HELP_SNAPSHOT,
121	HELP_UNMOUNT,
122	HELP_UNSHARE,
123	HELP_ALLOW,
124	HELP_UNALLOW,
125	HELP_USERSPACE,
126	HELP_GROUPSPACE,
127	HELP_HOLD,
128	HELP_HOLDS,
129	HELP_RELEASE
130} zfs_help_t;
131
132typedef struct zfs_command {
133	const char	*name;
134	int		(*func)(int argc, char **argv);
135	zfs_help_t	usage;
136} zfs_command_t;
137
138/*
139 * Master command table.  Each ZFS command has a name, associated function, and
140 * usage message.  The usage messages need to be internationalized, so we have
141 * to have a function to return the usage message based on a command index.
142 *
143 * These commands are organized according to how they are displayed in the usage
144 * message.  An empty command (one with a NULL name) indicates an empty line in
145 * the generic usage message.
146 */
147static zfs_command_t command_table[] = {
148	{ "create",	zfs_do_create,		HELP_CREATE		},
149	{ "destroy",	zfs_do_destroy,		HELP_DESTROY		},
150	{ NULL },
151	{ "snapshot",	zfs_do_snapshot,	HELP_SNAPSHOT		},
152	{ "rollback",	zfs_do_rollback,	HELP_ROLLBACK		},
153	{ "clone",	zfs_do_clone,		HELP_CLONE		},
154	{ "promote",	zfs_do_promote,		HELP_PROMOTE		},
155	{ "rename",	zfs_do_rename,		HELP_RENAME		},
156	{ NULL },
157	{ "list",	zfs_do_list,		HELP_LIST		},
158	{ NULL },
159	{ "set",	zfs_do_set,		HELP_SET		},
160	{ "get",	zfs_do_get,		HELP_GET		},
161	{ "inherit",	zfs_do_inherit,		HELP_INHERIT		},
162	{ "upgrade",	zfs_do_upgrade,		HELP_UPGRADE		},
163	{ "userspace",	zfs_do_userspace,	HELP_USERSPACE		},
164	{ "groupspace",	zfs_do_userspace,	HELP_GROUPSPACE		},
165	{ NULL },
166	{ "mount",	zfs_do_mount,		HELP_MOUNT		},
167	{ "unmount",	zfs_do_unmount,		HELP_UNMOUNT		},
168	{ "share",	zfs_do_share,		HELP_SHARE		},
169	{ "unshare",	zfs_do_unshare,		HELP_UNSHARE		},
170	{ NULL },
171	{ "send",	zfs_do_send,		HELP_SEND		},
172	{ "receive",	zfs_do_receive,		HELP_RECEIVE		},
173	{ NULL },
174	{ "allow",	zfs_do_python,		HELP_ALLOW		},
175	{ NULL },
176	{ "unallow",	zfs_do_python,		HELP_UNALLOW		},
177	{ NULL },
178	{ "hold",	zfs_do_hold,		HELP_HOLD		},
179	{ "holds",	zfs_do_python,		HELP_HOLDS		},
180	{ "release",	zfs_do_release,		HELP_RELEASE		},
181};
182
183#define	NCOMMAND	(sizeof (command_table) / sizeof (command_table[0]))
184
185zfs_command_t *current_command;
186
187static const char *
188get_usage(zfs_help_t idx)
189{
190	switch (idx) {
191	case HELP_CLONE:
192		return (gettext("\tclone [-p] [-o property=value] ... "
193		    "<snapshot> <filesystem|volume>\n"));
194	case HELP_CREATE:
195		return (gettext("\tcreate [-p] [-o property=value] ... "
196		    "<filesystem>\n"
197		    "\tcreate [-ps] [-b blocksize] [-o property=value] ... "
198		    "-V <size> <volume>\n"));
199	case HELP_DESTROY:
200		return (gettext("\tdestroy [-rRf] <filesystem|volume>\n"
201		    "\tdestroy [-rRd] <snapshot>\n"));
202	case HELP_GET:
203		return (gettext("\tget [-rHp] [-d max] "
204		    "[-o \"all\" | field[,...]] [-s source[,...]]\n"
205		    "\t    <\"all\" | property[,...]> "
206		    "[filesystem|volume|snapshot] ...\n"));
207	case HELP_INHERIT:
208		return (gettext("\tinherit [-rS] <property> "
209		    "<filesystem|volume|snapshot> ...\n"));
210	case HELP_UPGRADE:
211		return (gettext("\tupgrade [-v]\n"
212		    "\tupgrade [-r] [-V version] <-a | filesystem ...>\n"));
213	case HELP_LIST:
214		return (gettext("\tlist [-rH][-d max] "
215		    "[-o property[,...]] [-t type[,...]] [-s property] ...\n"
216		    "\t    [-S property] ... "
217		    "[filesystem|volume|snapshot] ...\n"));
218	case HELP_MOUNT:
219		return (gettext("\tmount\n"
220		    "\tmount [-vO] [-o opts] <-a | filesystem>\n"));
221	case HELP_PROMOTE:
222		return (gettext("\tpromote <clone-filesystem>\n"));
223	case HELP_RECEIVE:
224		return (gettext("\treceive [-vnF] <filesystem|volume|"
225		"snapshot>\n"
226		"\treceive [-vnF] -d <filesystem>\n"));
227	case HELP_RENAME:
228		return (gettext("\trename <filesystem|volume|snapshot> "
229		    "<filesystem|volume|snapshot>\n"
230		    "\trename -p <filesystem|volume> <filesystem|volume>\n"
231		    "\trename -r <snapshot> <snapshot>"));
232	case HELP_ROLLBACK:
233		return (gettext("\trollback [-rRf] <snapshot>\n"));
234	case HELP_SEND:
235		return (gettext("\tsend [-RDp] [-[iI] snapshot] <snapshot>\n"));
236	case HELP_SET:
237		return (gettext("\tset <property=value> "
238		    "<filesystem|volume|snapshot> ...\n"));
239	case HELP_SHARE:
240		return (gettext("\tshare <-a | filesystem>\n"));
241	case HELP_SNAPSHOT:
242		return (gettext("\tsnapshot [-r] [-o property=value] ... "
243		    "<filesystem@snapname|volume@snapname>\n"));
244	case HELP_UNMOUNT:
245		return (gettext("\tunmount [-f] "
246		    "<-a | filesystem|mountpoint>\n"));
247	case HELP_UNSHARE:
248		return (gettext("\tunshare "
249		    "<-a | filesystem|mountpoint>\n"));
250	case HELP_ALLOW:
251		return (gettext("\tallow <filesystem|volume>\n"
252		    "\tallow [-ldug] "
253		    "<\"everyone\"|user|group>[,...] <perm|@setname>[,...]\n"
254		    "\t    <filesystem|volume>\n"
255		    "\tallow [-ld] -e <perm|@setname>[,...] "
256		    "<filesystem|volume>\n"
257		    "\tallow -c <perm|@setname>[,...] <filesystem|volume>\n"
258		    "\tallow -s @setname <perm|@setname>[,...] "
259		    "<filesystem|volume>\n"));
260	case HELP_UNALLOW:
261		return (gettext("\tunallow [-rldug] "
262		    "<\"everyone\"|user|group>[,...]\n"
263		    "\t    [<perm|@setname>[,...]] <filesystem|volume>\n"
264		    "\tunallow [-rld] -e [<perm|@setname>[,...]] "
265		    "<filesystem|volume>\n"
266		    "\tunallow [-r] -c [<perm|@setname>[,...]] "
267		    "<filesystem|volume>\n"
268		    "\tunallow [-r] -s @setname [<perm|@setname>[,...]] "
269		    "<filesystem|volume>\n"));
270	case HELP_USERSPACE:
271		return (gettext("\tuserspace [-hniHp] [-o field[,...]] "
272		    "[-sS field] ... [-t type[,...]]\n"
273		    "\t    <filesystem|snapshot>\n"));
274	case HELP_GROUPSPACE:
275		return (gettext("\tgroupspace [-hniHpU] [-o field[,...]] "
276		    "[-sS field] ... [-t type[,...]]\n"
277		    "\t    <filesystem|snapshot>\n"));
278	case HELP_HOLD:
279		return (gettext("\thold [-r] <tag> <snapshot> ...\n"));
280	case HELP_HOLDS:
281		return (gettext("\tholds [-r] <snapshot> ...\n"));
282	case HELP_RELEASE:
283		return (gettext("\trelease [-r] <tag> <snapshot> ...\n"));
284	}
285
286	abort();
287	/* NOTREACHED */
288}
289
290/*
291 * Utility function to guarantee malloc() success.
292 */
293void *
294safe_malloc(size_t size)
295{
296	void *data;
297
298	if ((data = calloc(1, size)) == NULL) {
299		(void) fprintf(stderr, "internal error: out of memory\n");
300		exit(1);
301	}
302
303	return (data);
304}
305
306/*
307 * Callback routine that will print out information for each of
308 * the properties.
309 */
310static int
311usage_prop_cb(int prop, void *cb)
312{
313	FILE *fp = cb;
314
315	(void) fprintf(fp, "\t%-15s ", zfs_prop_to_name(prop));
316
317	if (zfs_prop_readonly(prop))
318		(void) fprintf(fp, " NO    ");
319	else
320		(void) fprintf(fp, "YES    ");
321
322	if (zfs_prop_inheritable(prop))
323		(void) fprintf(fp, "  YES   ");
324	else
325		(void) fprintf(fp, "   NO   ");
326
327	if (zfs_prop_values(prop) == NULL)
328		(void) fprintf(fp, "-\n");
329	else
330		(void) fprintf(fp, "%s\n", zfs_prop_values(prop));
331
332	return (ZPROP_CONT);
333}
334
335/*
336 * Display usage message.  If we're inside a command, display only the usage for
337 * that command.  Otherwise, iterate over the entire command table and display
338 * a complete usage message.
339 */
340static void
341usage(boolean_t requested)
342{
343	int i;
344	boolean_t show_properties = B_FALSE;
345	FILE *fp = requested ? stdout : stderr;
346
347	if (current_command == NULL) {
348
349		(void) fprintf(fp, gettext("usage: zfs command args ...\n"));
350		(void) fprintf(fp,
351		    gettext("where 'command' is one of the following:\n\n"));
352
353		for (i = 0; i < NCOMMAND; i++) {
354			if (command_table[i].name == NULL)
355				(void) fprintf(fp, "\n");
356			else
357				(void) fprintf(fp, "%s",
358				    get_usage(command_table[i].usage));
359		}
360
361		(void) fprintf(fp, gettext("\nEach dataset is of the form: "
362		    "pool/[dataset/]*dataset[@name]\n"));
363	} else {
364		(void) fprintf(fp, gettext("usage:\n"));
365		(void) fprintf(fp, "%s", get_usage(current_command->usage));
366	}
367
368	if (current_command != NULL &&
369	    (strcmp(current_command->name, "set") == 0 ||
370	    strcmp(current_command->name, "get") == 0 ||
371	    strcmp(current_command->name, "inherit") == 0 ||
372	    strcmp(current_command->name, "list") == 0))
373		show_properties = B_TRUE;
374
375	if (show_properties) {
376		(void) fprintf(fp,
377		    gettext("\nThe following properties are supported:\n"));
378
379		(void) fprintf(fp, "\n\t%-14s %s  %s   %s\n\n",
380		    "PROPERTY", "EDIT", "INHERIT", "VALUES");
381
382		/* Iterate over all properties */
383		(void) zprop_iter(usage_prop_cb, fp, B_FALSE, B_TRUE,
384		    ZFS_TYPE_DATASET);
385
386		(void) fprintf(fp, "\t%-15s ", "userused@...");
387		(void) fprintf(fp, " NO       NO   <size>\n");
388		(void) fprintf(fp, "\t%-15s ", "groupused@...");
389		(void) fprintf(fp, " NO       NO   <size>\n");
390		(void) fprintf(fp, "\t%-15s ", "userquota@...");
391		(void) fprintf(fp, "YES       NO   <size> | none\n");
392		(void) fprintf(fp, "\t%-15s ", "groupquota@...");
393		(void) fprintf(fp, "YES       NO   <size> | none\n");
394
395		(void) fprintf(fp, gettext("\nSizes are specified in bytes "
396		    "with standard units such as K, M, G, etc.\n"));
397		(void) fprintf(fp, gettext("\nUser-defined properties can "
398		    "be specified by using a name containing a colon (:).\n"));
399		(void) fprintf(fp, gettext("\nThe {user|group}{used|quota}@ "
400		    "properties must be appended with\n"
401		    "a user or group specifier of one of these forms:\n"
402		    "    POSIX name      (eg: \"matt\")\n"
403		    "    POSIX id        (eg: \"126829\")\n"
404		    "    SMB name@domain (eg: \"matt@sun\")\n"
405		    "    SMB SID         (eg: \"S-1-234-567-89\")\n"));
406	} else {
407		(void) fprintf(fp,
408		    gettext("\nFor the property list, run: %s\n"),
409		    "zfs set|get");
410		(void) fprintf(fp,
411		    gettext("\nFor the delegated permission list, run: %s\n"),
412		    "zfs allow|unallow");
413	}
414
415	/*
416	 * See comments at end of main().
417	 */
418	if (getenv("ZFS_ABORT") != NULL) {
419		(void) printf("dumping core by request\n");
420		abort();
421	}
422
423	exit(requested ? 0 : 2);
424}
425
426static int
427parseprop(nvlist_t *props)
428{
429	char *propname = optarg;
430	char *propval, *strval;
431
432	if ((propval = strchr(propname, '=')) == NULL) {
433		(void) fprintf(stderr, gettext("missing "
434		    "'=' for -o option\n"));
435		return (-1);
436	}
437	*propval = '\0';
438	propval++;
439	if (nvlist_lookup_string(props, propname, &strval) == 0) {
440		(void) fprintf(stderr, gettext("property '%s' "
441		    "specified multiple times\n"), propname);
442		return (-1);
443	}
444	if (nvlist_add_string(props, propname, propval) != 0) {
445		(void) fprintf(stderr, gettext("internal "
446		    "error: out of memory\n"));
447		return (-1);
448	}
449	return (0);
450}
451
452static int
453parse_depth(char *opt, int *flags)
454{
455	char *tmp;
456	int depth;
457
458	depth = (int)strtol(opt, &tmp, 0);
459	if (*tmp) {
460		(void) fprintf(stderr,
461		    gettext("%s is not an integer\n"), optarg);
462		usage(B_FALSE);
463	}
464	if (depth < 0) {
465		(void) fprintf(stderr,
466		    gettext("Depth can not be negative.\n"));
467		usage(B_FALSE);
468	}
469	*flags |= (ZFS_ITER_DEPTH_LIMIT|ZFS_ITER_RECURSE);
470	return (depth);
471}
472
473/*
474 * zfs clone [-p] [-o prop=value] ... <snap> <fs | vol>
475 *
476 * Given an existing dataset, create a writable copy whose initial contents
477 * are the same as the source.  The newly created dataset maintains a
478 * dependency on the original; the original cannot be destroyed so long as
479 * the clone exists.
480 *
481 * The '-p' flag creates all the non-existing ancestors of the target first.
482 */
483static int
484zfs_do_clone(int argc, char **argv)
485{
486	zfs_handle_t *zhp = NULL;
487	boolean_t parents = B_FALSE;
488	nvlist_t *props;
489	int ret;
490	int c;
491
492	if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) {
493		(void) fprintf(stderr, gettext("internal error: "
494		    "out of memory\n"));
495		return (1);
496	}
497
498	/* check options */
499	while ((c = getopt(argc, argv, "o:p")) != -1) {
500		switch (c) {
501		case 'o':
502			if (parseprop(props))
503				return (1);
504			break;
505		case 'p':
506			parents = B_TRUE;
507			break;
508		case '?':
509			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
510			    optopt);
511			goto usage;
512		}
513	}
514
515	argc -= optind;
516	argv += optind;
517
518	/* check number of arguments */
519	if (argc < 1) {
520		(void) fprintf(stderr, gettext("missing source dataset "
521		    "argument\n"));
522		goto usage;
523	}
524	if (argc < 2) {
525		(void) fprintf(stderr, gettext("missing target dataset "
526		    "argument\n"));
527		goto usage;
528	}
529	if (argc > 2) {
530		(void) fprintf(stderr, gettext("too many arguments\n"));
531		goto usage;
532	}
533
534	/* open the source dataset */
535	if ((zhp = zfs_open(g_zfs, argv[0], ZFS_TYPE_SNAPSHOT)) == NULL)
536		return (1);
537
538	if (parents && zfs_name_valid(argv[1], ZFS_TYPE_FILESYSTEM |
539	    ZFS_TYPE_VOLUME)) {
540		/*
541		 * Now create the ancestors of the target dataset.  If the
542		 * target already exists and '-p' option was used we should not
543		 * complain.
544		 */
545		if (zfs_dataset_exists(g_zfs, argv[1], ZFS_TYPE_FILESYSTEM |
546		    ZFS_TYPE_VOLUME))
547			return (0);
548		if (zfs_create_ancestors(g_zfs, argv[1]) != 0)
549			return (1);
550	}
551
552	/* pass to libzfs */
553	ret = zfs_clone(zhp, argv[1], props);
554
555	/* create the mountpoint if necessary */
556	if (ret == 0) {
557		zfs_handle_t *clone;
558
559		clone = zfs_open(g_zfs, argv[1], ZFS_TYPE_DATASET);
560		if (clone != NULL) {
561			if ((ret = zfs_mount(clone, NULL, 0)) == 0)
562				ret = zfs_share(clone);
563			zfs_close(clone);
564		}
565	}
566
567	zfs_close(zhp);
568	nvlist_free(props);
569
570	return (!!ret);
571
572usage:
573	if (zhp)
574		zfs_close(zhp);
575	nvlist_free(props);
576	usage(B_FALSE);
577	return (-1);
578}
579
580/*
581 * zfs create [-p] [-o prop=value] ... fs
582 * zfs create [-ps] [-b blocksize] [-o prop=value] ... -V vol size
583 *
584 * Create a new dataset.  This command can be used to create filesystems
585 * and volumes.  Snapshot creation is handled by 'zfs snapshot'.
586 * For volumes, the user must specify a size to be used.
587 *
588 * The '-s' flag applies only to volumes, and indicates that we should not try
589 * to set the reservation for this volume.  By default we set a reservation
590 * equal to the size for any volume.  For pools with SPA_VERSION >=
591 * SPA_VERSION_REFRESERVATION, we set a refreservation instead.
592 *
593 * The '-p' flag creates all the non-existing ancestors of the target first.
594 */
595static int
596zfs_do_create(int argc, char **argv)
597{
598	zfs_type_t type = ZFS_TYPE_FILESYSTEM;
599	zfs_handle_t *zhp = NULL;
600	uint64_t volsize;
601	int c;
602	boolean_t noreserve = B_FALSE;
603	boolean_t bflag = B_FALSE;
604	boolean_t parents = B_FALSE;
605	int ret = 1;
606	nvlist_t *props;
607	uint64_t intval;
608	int canmount;
609
610	if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) {
611		(void) fprintf(stderr, gettext("internal error: "
612		    "out of memory\n"));
613		return (1);
614	}
615
616	/* check options */
617	while ((c = getopt(argc, argv, ":V:b:so:p")) != -1) {
618		switch (c) {
619		case 'V':
620			type = ZFS_TYPE_VOLUME;
621			if (zfs_nicestrtonum(g_zfs, optarg, &intval) != 0) {
622				(void) fprintf(stderr, gettext("bad volume "
623				    "size '%s': %s\n"), optarg,
624				    libzfs_error_description(g_zfs));
625				goto error;
626			}
627
628			if (nvlist_add_uint64(props,
629			    zfs_prop_to_name(ZFS_PROP_VOLSIZE),
630			    intval) != 0) {
631				(void) fprintf(stderr, gettext("internal "
632				    "error: out of memory\n"));
633				goto error;
634			}
635			volsize = intval;
636			break;
637		case 'p':
638			parents = B_TRUE;
639			break;
640		case 'b':
641			bflag = B_TRUE;
642			if (zfs_nicestrtonum(g_zfs, optarg, &intval) != 0) {
643				(void) fprintf(stderr, gettext("bad volume "
644				    "block size '%s': %s\n"), optarg,
645				    libzfs_error_description(g_zfs));
646				goto error;
647			}
648
649			if (nvlist_add_uint64(props,
650			    zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE),
651			    intval) != 0) {
652				(void) fprintf(stderr, gettext("internal "
653				    "error: out of memory\n"));
654				goto error;
655			}
656			break;
657		case 'o':
658			if (parseprop(props))
659				goto error;
660			break;
661		case 's':
662			noreserve = B_TRUE;
663			break;
664		case ':':
665			(void) fprintf(stderr, gettext("missing size "
666			    "argument\n"));
667			goto badusage;
668			break;
669		case '?':
670			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
671			    optopt);
672			goto badusage;
673		}
674	}
675
676	if ((bflag || noreserve) && type != ZFS_TYPE_VOLUME) {
677		(void) fprintf(stderr, gettext("'-s' and '-b' can only be "
678		    "used when creating a volume\n"));
679		goto badusage;
680	}
681
682	argc -= optind;
683	argv += optind;
684
685	/* check number of arguments */
686	if (argc == 0) {
687		(void) fprintf(stderr, gettext("missing %s argument\n"),
688		    zfs_type_to_name(type));
689		goto badusage;
690	}
691	if (argc > 1) {
692		(void) fprintf(stderr, gettext("too many arguments\n"));
693		goto badusage;
694	}
695
696	if (type == ZFS_TYPE_VOLUME && !noreserve) {
697		zpool_handle_t *zpool_handle;
698		uint64_t spa_version;
699		char *p;
700		zfs_prop_t resv_prop;
701		char *strval;
702
703		if (p = strchr(argv[0], '/'))
704			*p = '\0';
705		zpool_handle = zpool_open(g_zfs, argv[0]);
706		if (p != NULL)
707			*p = '/';
708		if (zpool_handle == NULL)
709			goto error;
710		spa_version = zpool_get_prop_int(zpool_handle,
711		    ZPOOL_PROP_VERSION, NULL);
712		zpool_close(zpool_handle);
713		if (spa_version >= SPA_VERSION_REFRESERVATION)
714			resv_prop = ZFS_PROP_REFRESERVATION;
715		else
716			resv_prop = ZFS_PROP_RESERVATION;
717		volsize = zvol_volsize_to_reservation(volsize, props);
718
719		if (nvlist_lookup_string(props, zfs_prop_to_name(resv_prop),
720		    &strval) != 0) {
721			if (nvlist_add_uint64(props,
722			    zfs_prop_to_name(resv_prop), volsize) != 0) {
723				(void) fprintf(stderr, gettext("internal "
724				    "error: out of memory\n"));
725				nvlist_free(props);
726				return (1);
727			}
728		}
729	}
730
731	if (parents && zfs_name_valid(argv[0], type)) {
732		/*
733		 * Now create the ancestors of target dataset.  If the target
734		 * already exists and '-p' option was used we should not
735		 * complain.
736		 */
737		if (zfs_dataset_exists(g_zfs, argv[0], type)) {
738			ret = 0;
739			goto error;
740		}
741		if (zfs_create_ancestors(g_zfs, argv[0]) != 0)
742			goto error;
743	}
744
745	/* pass to libzfs */
746	if (zfs_create(g_zfs, argv[0], type, props) != 0)
747		goto error;
748
749	if ((zhp = zfs_open(g_zfs, argv[0], ZFS_TYPE_DATASET)) == NULL)
750		goto error;
751	/*
752	 * if the user doesn't want the dataset automatically mounted,
753	 * then skip the mount/share step
754	 */
755
756	canmount = zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT);
757
758	/*
759	 * Mount and/or share the new filesystem as appropriate.  We provide a
760	 * verbose error message to let the user know that their filesystem was
761	 * in fact created, even if we failed to mount or share it.
762	 */
763	ret = 0;
764	if (canmount == ZFS_CANMOUNT_ON) {
765		if (zfs_mount(zhp, NULL, 0) != 0) {
766			(void) fprintf(stderr, gettext("filesystem "
767			    "successfully created, but not mounted\n"));
768			ret = 1;
769		} else if (zfs_share(zhp) != 0) {
770			(void) fprintf(stderr, gettext("filesystem "
771			    "successfully created, but not shared\n"));
772			ret = 1;
773		}
774	}
775
776error:
777	if (zhp)
778		zfs_close(zhp);
779	nvlist_free(props);
780	return (ret);
781badusage:
782	nvlist_free(props);
783	usage(B_FALSE);
784	return (2);
785}
786
787/*
788 * zfs destroy [-rRf] <fs, vol>
789 * zfs destroy [-rRd] <snap>
790 *
791 *	-r	Recursively destroy all children
792 *	-R	Recursively destroy all dependents, including clones
793 *	-f	Force unmounting of any dependents
794 *	-d	If we can't destroy now, mark for deferred destruction
795 *
796 * Destroys the given dataset.  By default, it will unmount any filesystems,
797 * and refuse to destroy a dataset that has any dependents.  A dependent can
798 * either be a child, or a clone of a child.
799 */
800typedef struct destroy_cbdata {
801	boolean_t	cb_first;
802	int		cb_force;
803	int		cb_recurse;
804	int		cb_error;
805	int		cb_needforce;
806	int		cb_doclones;
807	boolean_t	cb_closezhp;
808	zfs_handle_t	*cb_target;
809	char		*cb_snapname;
810	boolean_t	cb_defer_destroy;
811} destroy_cbdata_t;
812
813/*
814 * Check for any dependents based on the '-r' or '-R' flags.
815 */
816static int
817destroy_check_dependent(zfs_handle_t *zhp, void *data)
818{
819	destroy_cbdata_t *cbp = data;
820	const char *tname = zfs_get_name(cbp->cb_target);
821	const char *name = zfs_get_name(zhp);
822
823	if (strncmp(tname, name, strlen(tname)) == 0 &&
824	    (name[strlen(tname)] == '/' || name[strlen(tname)] == '@')) {
825		/*
826		 * This is a direct descendant, not a clone somewhere else in
827		 * the hierarchy.
828		 */
829		if (cbp->cb_recurse)
830			goto out;
831
832		if (cbp->cb_first) {
833			(void) fprintf(stderr, gettext("cannot destroy '%s': "
834			    "%s has children\n"),
835			    zfs_get_name(cbp->cb_target),
836			    zfs_type_to_name(zfs_get_type(cbp->cb_target)));
837			(void) fprintf(stderr, gettext("use '-r' to destroy "
838			    "the following datasets:\n"));
839			cbp->cb_first = B_FALSE;
840			cbp->cb_error = 1;
841		}
842
843		(void) fprintf(stderr, "%s\n", zfs_get_name(zhp));
844	} else {
845		/*
846		 * This is a clone.  We only want to report this if the '-r'
847		 * wasn't specified, or the target is a snapshot.
848		 */
849		if (!cbp->cb_recurse &&
850		    zfs_get_type(cbp->cb_target) != ZFS_TYPE_SNAPSHOT)
851			goto out;
852
853		if (cbp->cb_first) {
854			(void) fprintf(stderr, gettext("cannot destroy '%s': "
855			    "%s has dependent clones\n"),
856			    zfs_get_name(cbp->cb_target),
857			    zfs_type_to_name(zfs_get_type(cbp->cb_target)));
858			(void) fprintf(stderr, gettext("use '-R' to destroy "
859			    "the following datasets:\n"));
860			cbp->cb_first = B_FALSE;
861			cbp->cb_error = 1;
862		}
863
864		(void) fprintf(stderr, "%s\n", zfs_get_name(zhp));
865	}
866
867out:
868	zfs_close(zhp);
869	return (0);
870}
871
872static int
873destroy_callback(zfs_handle_t *zhp, void *data)
874{
875	destroy_cbdata_t *cbp = data;
876
877	/*
878	 * Ignore pools (which we've already flagged as an error before getting
879	 * here).
880	 */
881	if (strchr(zfs_get_name(zhp), '/') == NULL &&
882	    zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) {
883		zfs_close(zhp);
884		return (0);
885	}
886
887	/*
888	 * Bail out on the first error.
889	 */
890	if (zfs_unmount(zhp, NULL, cbp->cb_force ? MS_FORCE : 0) != 0 ||
891	    zfs_destroy(zhp, cbp->cb_defer_destroy) != 0) {
892		zfs_close(zhp);
893		return (-1);
894	}
895
896	zfs_close(zhp);
897	return (0);
898}
899
900static int
901destroy_snap_clones(zfs_handle_t *zhp, void *arg)
902{
903	destroy_cbdata_t *cbp = arg;
904	char thissnap[MAXPATHLEN];
905	zfs_handle_t *szhp;
906	boolean_t closezhp = cbp->cb_closezhp;
907	int rv;
908
909	(void) snprintf(thissnap, sizeof (thissnap),
910	    "%s@%s", zfs_get_name(zhp), cbp->cb_snapname);
911
912	libzfs_print_on_error(g_zfs, B_FALSE);
913	szhp = zfs_open(g_zfs, thissnap, ZFS_TYPE_SNAPSHOT);
914	libzfs_print_on_error(g_zfs, B_TRUE);
915	if (szhp) {
916		/*
917		 * Destroy any clones of this snapshot
918		 */
919		if (zfs_iter_dependents(szhp, B_FALSE, destroy_callback,
920		    cbp) != 0) {
921			zfs_close(szhp);
922			if (closezhp)
923				zfs_close(zhp);
924			return (-1);
925		}
926		zfs_close(szhp);
927	}
928
929	cbp->cb_closezhp = B_TRUE;
930	rv = zfs_iter_filesystems(zhp, destroy_snap_clones, arg);
931	if (closezhp)
932		zfs_close(zhp);
933	return (rv);
934}
935
936static int
937zfs_do_destroy(int argc, char **argv)
938{
939	destroy_cbdata_t cb = { 0 };
940	int c;
941	zfs_handle_t *zhp;
942	char *cp;
943	zfs_type_t type = ZFS_TYPE_DATASET;
944
945	/* check options */
946	while ((c = getopt(argc, argv, "dfrR")) != -1) {
947		switch (c) {
948		case 'd':
949			cb.cb_defer_destroy = B_TRUE;
950			type = ZFS_TYPE_SNAPSHOT;
951			break;
952		case 'f':
953			cb.cb_force = 1;
954			break;
955		case 'r':
956			cb.cb_recurse = 1;
957			break;
958		case 'R':
959			cb.cb_recurse = 1;
960			cb.cb_doclones = 1;
961			break;
962		case '?':
963		default:
964			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
965			    optopt);
966			usage(B_FALSE);
967		}
968	}
969
970	argc -= optind;
971	argv += optind;
972
973	/* check number of arguments */
974	if (argc == 0) {
975		(void) fprintf(stderr, gettext("missing path argument\n"));
976		usage(B_FALSE);
977	}
978	if (argc > 1) {
979		(void) fprintf(stderr, gettext("too many arguments\n"));
980		usage(B_FALSE);
981	}
982
983	/*
984	 * If we are doing recursive destroy of a snapshot, then the
985	 * named snapshot may not exist.  Go straight to libzfs.
986	 */
987	if (cb.cb_recurse && (cp = strchr(argv[0], '@'))) {
988		int ret;
989
990		*cp = '\0';
991		if ((zhp = zfs_open(g_zfs, argv[0], ZFS_TYPE_DATASET)) == NULL)
992			return (1);
993		*cp = '@';
994		cp++;
995
996		if (cb.cb_doclones) {
997			boolean_t defer = cb.cb_defer_destroy;
998
999			/*
1000			 * Temporarily ignore the defer_destroy setting since
1001			 * it's not supported for clones.
1002			 */
1003			cb.cb_defer_destroy = B_FALSE;
1004			cb.cb_snapname = cp;
1005			if (destroy_snap_clones(zhp, &cb) != 0) {
1006				zfs_close(zhp);
1007				return (1);
1008			}
1009			cb.cb_defer_destroy = defer;
1010		}
1011
1012		ret = zfs_destroy_snaps(zhp, cp, cb.cb_defer_destroy);
1013		zfs_close(zhp);
1014		if (ret) {
1015			(void) fprintf(stderr,
1016			    gettext("no snapshots destroyed\n"));
1017		}
1018		return (ret != 0);
1019	}
1020
1021	/* Open the given dataset */
1022	if ((zhp = zfs_open(g_zfs, argv[0], type)) == NULL)
1023		return (1);
1024
1025	cb.cb_target = zhp;
1026
1027	/*
1028	 * Perform an explicit check for pools before going any further.
1029	 */
1030	if (!cb.cb_recurse && strchr(zfs_get_name(zhp), '/') == NULL &&
1031	    zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) {
1032		(void) fprintf(stderr, gettext("cannot destroy '%s': "
1033		    "operation does not apply to pools\n"),
1034		    zfs_get_name(zhp));
1035		(void) fprintf(stderr, gettext("use 'zfs destroy -r "
1036		    "%s' to destroy all datasets in the pool\n"),
1037		    zfs_get_name(zhp));
1038		(void) fprintf(stderr, gettext("use 'zpool destroy %s' "
1039		    "to destroy the pool itself\n"), zfs_get_name(zhp));
1040		zfs_close(zhp);
1041		return (1);
1042	}
1043
1044	/*
1045	 * Check for any dependents and/or clones.
1046	 */
1047	cb.cb_first = B_TRUE;
1048	if (!cb.cb_doclones && !cb.cb_defer_destroy &&
1049	    zfs_iter_dependents(zhp, B_TRUE, destroy_check_dependent,
1050	    &cb) != 0) {
1051		zfs_close(zhp);
1052		return (1);
1053	}
1054
1055	if (cb.cb_error || (!cb.cb_defer_destroy &&
1056	    (zfs_iter_dependents(zhp, B_FALSE, destroy_callback, &cb) != 0))) {
1057		zfs_close(zhp);
1058		return (1);
1059	}
1060
1061	/*
1062	 * Do the real thing.  The callback will close the handle regardless of
1063	 * whether it succeeds or not.
1064	 */
1065
1066	if (destroy_callback(zhp, &cb) != 0)
1067		return (1);
1068
1069	return (0);
1070}
1071
1072static boolean_t
1073is_recvd_column(zprop_get_cbdata_t *cbp)
1074{
1075	int i;
1076	zfs_get_column_t col;
1077
1078	for (i = 0; i < ZFS_GET_NCOLS &&
1079	    (col = cbp->cb_columns[i]) != GET_COL_NONE; i++)
1080		if (col == GET_COL_RECVD)
1081			return (B_TRUE);
1082	return (B_FALSE);
1083}
1084
1085/*
1086 * zfs get [-rHp] [-o all | field[,field]...] [-s source[,source]...]
1087 *	< all | property[,property]... > < fs | snap | vol > ...
1088 *
1089 *	-r	recurse over any child datasets
1090 *	-H	scripted mode.  Headers are stripped, and fields are separated
1091 *		by tabs instead of spaces.
1092 *	-o	Set of fields to display.  One of "name,property,value,
1093 *		received,source". Default is "name,property,value,source".
1094 *		"all" is an alias for all five.
1095 *	-s	Set of sources to allow.  One of
1096 *		"local,default,inherited,received,temporary,none".  Default is
1097 *		all six.
1098 *	-p	Display values in parsable (literal) format.
1099 *
1100 *  Prints properties for the given datasets.  The user can control which
1101 *  columns to display as well as which property types to allow.
1102 */
1103
1104/*
1105 * Invoked to display the properties for a single dataset.
1106 */
1107static int
1108get_callback(zfs_handle_t *zhp, void *data)
1109{
1110	char buf[ZFS_MAXPROPLEN];
1111	char rbuf[ZFS_MAXPROPLEN];
1112	zprop_source_t sourcetype;
1113	char source[ZFS_MAXNAMELEN];
1114	zprop_get_cbdata_t *cbp = data;
1115	nvlist_t *user_props = zfs_get_user_props(zhp);
1116	zprop_list_t *pl = cbp->cb_proplist;
1117	nvlist_t *propval;
1118	char *strval;
1119	char *sourceval;
1120	boolean_t received = is_recvd_column(cbp);
1121
1122	for (; pl != NULL; pl = pl->pl_next) {
1123		char *recvdval = NULL;
1124		/*
1125		 * Skip the special fake placeholder.  This will also skip over
1126		 * the name property when 'all' is specified.
1127		 */
1128		if (pl->pl_prop == ZFS_PROP_NAME &&
1129		    pl == cbp->cb_proplist)
1130			continue;
1131
1132		if (pl->pl_prop != ZPROP_INVAL) {
1133			if (zfs_prop_get(zhp, pl->pl_prop, buf,
1134			    sizeof (buf), &sourcetype, source,
1135			    sizeof (source),
1136			    cbp->cb_literal) != 0) {
1137				if (pl->pl_all)
1138					continue;
1139				if (!zfs_prop_valid_for_type(pl->pl_prop,
1140				    ZFS_TYPE_DATASET)) {
1141					(void) fprintf(stderr,
1142					    gettext("No such property '%s'\n"),
1143					    zfs_prop_to_name(pl->pl_prop));
1144					continue;
1145				}
1146				sourcetype = ZPROP_SRC_NONE;
1147				(void) strlcpy(buf, "-", sizeof (buf));
1148			}
1149
1150			if (received && (zfs_prop_get_recvd(zhp,
1151			    zfs_prop_to_name(pl->pl_prop), rbuf, sizeof (rbuf),
1152			    cbp->cb_literal) == 0))
1153				recvdval = rbuf;
1154
1155			zprop_print_one_property(zfs_get_name(zhp), cbp,
1156			    zfs_prop_to_name(pl->pl_prop),
1157			    buf, sourcetype, source, recvdval);
1158		} else if (zfs_prop_userquota(pl->pl_user_prop)) {
1159			sourcetype = ZPROP_SRC_LOCAL;
1160
1161			if (zfs_prop_get_userquota(zhp, pl->pl_user_prop,
1162			    buf, sizeof (buf), cbp->cb_literal) != 0) {
1163				sourcetype = ZPROP_SRC_NONE;
1164				(void) strlcpy(buf, "-", sizeof (buf));
1165			}
1166
1167			zprop_print_one_property(zfs_get_name(zhp), cbp,
1168			    pl->pl_user_prop, buf, sourcetype, source, NULL);
1169		} else {
1170			if (nvlist_lookup_nvlist(user_props,
1171			    pl->pl_user_prop, &propval) != 0) {
1172				if (pl->pl_all)
1173					continue;
1174				sourcetype = ZPROP_SRC_NONE;
1175				strval = "-";
1176			} else {
1177				verify(nvlist_lookup_string(propval,
1178				    ZPROP_VALUE, &strval) == 0);
1179				verify(nvlist_lookup_string(propval,
1180				    ZPROP_SOURCE, &sourceval) == 0);
1181
1182				if (strcmp(sourceval,
1183				    zfs_get_name(zhp)) == 0) {
1184					sourcetype = ZPROP_SRC_LOCAL;
1185				} else if (strcmp(sourceval,
1186				    ZPROP_SOURCE_VAL_RECVD) == 0) {
1187					sourcetype = ZPROP_SRC_RECEIVED;
1188				} else {
1189					sourcetype = ZPROP_SRC_INHERITED;
1190					(void) strlcpy(source,
1191					    sourceval, sizeof (source));
1192				}
1193			}
1194
1195			if (received && (zfs_prop_get_recvd(zhp,
1196			    pl->pl_user_prop, rbuf, sizeof (rbuf),
1197			    cbp->cb_literal) == 0))
1198				recvdval = rbuf;
1199
1200			zprop_print_one_property(zfs_get_name(zhp), cbp,
1201			    pl->pl_user_prop, strval, sourcetype,
1202			    source, recvdval);
1203		}
1204	}
1205
1206	return (0);
1207}
1208
1209static int
1210zfs_do_get(int argc, char **argv)
1211{
1212	zprop_get_cbdata_t cb = { 0 };
1213	int i, c, flags = 0;
1214	char *value, *fields;
1215	int ret;
1216	int limit = 0;
1217	zprop_list_t fake_name = { 0 };
1218
1219	/*
1220	 * Set up default columns and sources.
1221	 */
1222	cb.cb_sources = ZPROP_SRC_ALL;
1223	cb.cb_columns[0] = GET_COL_NAME;
1224	cb.cb_columns[1] = GET_COL_PROPERTY;
1225	cb.cb_columns[2] = GET_COL_VALUE;
1226	cb.cb_columns[3] = GET_COL_SOURCE;
1227	cb.cb_type = ZFS_TYPE_DATASET;
1228
1229	/* check options */
1230	while ((c = getopt(argc, argv, ":d:o:s:rHp")) != -1) {
1231		switch (c) {
1232		case 'p':
1233			cb.cb_literal = B_TRUE;
1234			break;
1235		case 'd':
1236			limit = parse_depth(optarg, &flags);
1237			break;
1238		case 'r':
1239			flags |= ZFS_ITER_RECURSE;
1240			break;
1241		case 'H':
1242			cb.cb_scripted = B_TRUE;
1243			break;
1244		case ':':
1245			(void) fprintf(stderr, gettext("missing argument for "
1246			    "'%c' option\n"), optopt);
1247			usage(B_FALSE);
1248			break;
1249		case 'o':
1250			/*
1251			 * Process the set of columns to display.  We zero out
1252			 * the structure to give us a blank slate.
1253			 */
1254			bzero(&cb.cb_columns, sizeof (cb.cb_columns));
1255			i = 0;
1256			while (*optarg != '\0') {
1257				static char *col_subopts[] =
1258				    { "name", "property", "value", "received",
1259				    "source", "all", NULL };
1260
1261				if (i == ZFS_GET_NCOLS) {
1262					(void) fprintf(stderr, gettext("too "
1263					    "many fields given to -o "
1264					    "option\n"));
1265					usage(B_FALSE);
1266				}
1267
1268				switch (getsubopt(&optarg, col_subopts,
1269				    &value)) {
1270				case 0:
1271					cb.cb_columns[i++] = GET_COL_NAME;
1272					break;
1273				case 1:
1274					cb.cb_columns[i++] = GET_COL_PROPERTY;
1275					break;
1276				case 2:
1277					cb.cb_columns[i++] = GET_COL_VALUE;
1278					break;
1279				case 3:
1280					cb.cb_columns[i++] = GET_COL_RECVD;
1281					flags |= ZFS_ITER_RECVD_PROPS;
1282					break;
1283				case 4:
1284					cb.cb_columns[i++] = GET_COL_SOURCE;
1285					break;
1286				case 5:
1287					if (i > 0) {
1288						(void) fprintf(stderr,
1289						    gettext("\"all\" conflicts "
1290						    "with specific fields "
1291						    "given to -o option\n"));
1292						usage(B_FALSE);
1293					}
1294					cb.cb_columns[0] = GET_COL_NAME;
1295					cb.cb_columns[1] = GET_COL_PROPERTY;
1296					cb.cb_columns[2] = GET_COL_VALUE;
1297					cb.cb_columns[3] = GET_COL_RECVD;
1298					cb.cb_columns[4] = GET_COL_SOURCE;
1299					flags |= ZFS_ITER_RECVD_PROPS;
1300					i = ZFS_GET_NCOLS;
1301					break;
1302				default:
1303					(void) fprintf(stderr,
1304					    gettext("invalid column name "
1305					    "'%s'\n"), value);
1306					usage(B_FALSE);
1307				}
1308			}
1309			break;
1310
1311		case 's':
1312			cb.cb_sources = 0;
1313			while (*optarg != '\0') {
1314				static char *source_subopts[] = {
1315					"local", "default", "inherited",
1316					"received", "temporary", "none",
1317					NULL };
1318
1319				switch (getsubopt(&optarg, source_subopts,
1320				    &value)) {
1321				case 0:
1322					cb.cb_sources |= ZPROP_SRC_LOCAL;
1323					break;
1324				case 1:
1325					cb.cb_sources |= ZPROP_SRC_DEFAULT;
1326					break;
1327				case 2:
1328					cb.cb_sources |= ZPROP_SRC_INHERITED;
1329					break;
1330				case 3:
1331					cb.cb_sources |= ZPROP_SRC_RECEIVED;
1332					break;
1333				case 4:
1334					cb.cb_sources |= ZPROP_SRC_TEMPORARY;
1335					break;
1336				case 5:
1337					cb.cb_sources |= ZPROP_SRC_NONE;
1338					break;
1339				default:
1340					(void) fprintf(stderr,
1341					    gettext("invalid source "
1342					    "'%s'\n"), value);
1343					usage(B_FALSE);
1344				}
1345			}
1346			break;
1347
1348		case '?':
1349			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1350			    optopt);
1351			usage(B_FALSE);
1352		}
1353	}
1354
1355	argc -= optind;
1356	argv += optind;
1357
1358	if (argc < 1) {
1359		(void) fprintf(stderr, gettext("missing property "
1360		    "argument\n"));
1361		usage(B_FALSE);
1362	}
1363
1364	fields = argv[0];
1365
1366	if (zprop_get_list(g_zfs, fields, &cb.cb_proplist, ZFS_TYPE_DATASET)
1367	    != 0)
1368		usage(B_FALSE);
1369
1370	argc--;
1371	argv++;
1372
1373	/*
1374	 * As part of zfs_expand_proplist(), we keep track of the maximum column
1375	 * width for each property.  For the 'NAME' (and 'SOURCE') columns, we
1376	 * need to know the maximum name length.  However, the user likely did
1377	 * not specify 'name' as one of the properties to fetch, so we need to
1378	 * make sure we always include at least this property for
1379	 * print_get_headers() to work properly.
1380	 */
1381	if (cb.cb_proplist != NULL) {
1382		fake_name.pl_prop = ZFS_PROP_NAME;
1383		fake_name.pl_width = strlen(gettext("NAME"));
1384		fake_name.pl_next = cb.cb_proplist;
1385		cb.cb_proplist = &fake_name;
1386	}
1387
1388	cb.cb_first = B_TRUE;
1389
1390	/* run for each object */
1391	ret = zfs_for_each(argc, argv, flags, ZFS_TYPE_DATASET, NULL,
1392	    &cb.cb_proplist, limit, get_callback, &cb);
1393
1394	if (cb.cb_proplist == &fake_name)
1395		zprop_free_list(fake_name.pl_next);
1396	else
1397		zprop_free_list(cb.cb_proplist);
1398
1399	return (ret);
1400}
1401
1402/*
1403 * inherit [-rS] <property> <fs|vol> ...
1404 *
1405 *	-r	Recurse over all children
1406 *	-S	Revert to received value, if any
1407 *
1408 * For each dataset specified on the command line, inherit the given property
1409 * from its parent.  Inheriting a property at the pool level will cause it to
1410 * use the default value.  The '-r' flag will recurse over all children, and is
1411 * useful for setting a property on a hierarchy-wide basis, regardless of any
1412 * local modifications for each dataset.
1413 */
1414
1415typedef struct inherit_cbdata {
1416	const char *cb_propname;
1417	boolean_t cb_received;
1418} inherit_cbdata_t;
1419
1420static int
1421inherit_recurse_cb(zfs_handle_t *zhp, void *data)
1422{
1423	inherit_cbdata_t *cb = data;
1424	zfs_prop_t prop = zfs_name_to_prop(cb->cb_propname);
1425
1426	/*
1427	 * If we're doing it recursively, then ignore properties that
1428	 * are not valid for this type of dataset.
1429	 */
1430	if (prop != ZPROP_INVAL &&
1431	    !zfs_prop_valid_for_type(prop, zfs_get_type(zhp)))
1432		return (0);
1433
1434	return (zfs_prop_inherit(zhp, cb->cb_propname, cb->cb_received) != 0);
1435}
1436
1437static int
1438inherit_cb(zfs_handle_t *zhp, void *data)
1439{
1440	inherit_cbdata_t *cb = data;
1441
1442	return (zfs_prop_inherit(zhp, cb->cb_propname, cb->cb_received) != 0);
1443}
1444
1445static int
1446zfs_do_inherit(int argc, char **argv)
1447{
1448	int c;
1449	zfs_prop_t prop;
1450	inherit_cbdata_t cb = { 0 };
1451	char *propname;
1452	int ret;
1453	int flags = 0;
1454	boolean_t received = B_FALSE;
1455
1456	/* check options */
1457	while ((c = getopt(argc, argv, "rS")) != -1) {
1458		switch (c) {
1459		case 'r':
1460			flags |= ZFS_ITER_RECURSE;
1461			break;
1462		case 'S':
1463			received = B_TRUE;
1464			break;
1465		case '?':
1466		default:
1467			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1468			    optopt);
1469			usage(B_FALSE);
1470		}
1471	}
1472
1473	argc -= optind;
1474	argv += optind;
1475
1476	/* check number of arguments */
1477	if (argc < 1) {
1478		(void) fprintf(stderr, gettext("missing property argument\n"));
1479		usage(B_FALSE);
1480	}
1481	if (argc < 2) {
1482		(void) fprintf(stderr, gettext("missing dataset argument\n"));
1483		usage(B_FALSE);
1484	}
1485
1486	propname = argv[0];
1487	argc--;
1488	argv++;
1489
1490	if ((prop = zfs_name_to_prop(propname)) != ZPROP_INVAL) {
1491		if (zfs_prop_readonly(prop)) {
1492			(void) fprintf(stderr, gettext(
1493			    "%s property is read-only\n"),
1494			    propname);
1495			return (1);
1496		}
1497		if (!zfs_prop_inheritable(prop) && !received) {
1498			(void) fprintf(stderr, gettext("'%s' property cannot "
1499			    "be inherited\n"), propname);
1500			if (prop == ZFS_PROP_QUOTA ||
1501			    prop == ZFS_PROP_RESERVATION ||
1502			    prop == ZFS_PROP_REFQUOTA ||
1503			    prop == ZFS_PROP_REFRESERVATION)
1504				(void) fprintf(stderr, gettext("use 'zfs set "
1505				    "%s=none' to clear\n"), propname);
1506			return (1);
1507		}
1508		if (received && (prop == ZFS_PROP_VOLSIZE ||
1509		    prop == ZFS_PROP_VERSION)) {
1510			(void) fprintf(stderr, gettext("'%s' property cannot "
1511			    "be reverted to a received value\n"), propname);
1512			return (1);
1513		}
1514	} else if (!zfs_prop_user(propname)) {
1515		(void) fprintf(stderr, gettext("invalid property '%s'\n"),
1516		    propname);
1517		usage(B_FALSE);
1518	}
1519
1520	cb.cb_propname = propname;
1521	cb.cb_received = received;
1522
1523	if (flags & ZFS_ITER_RECURSE) {
1524		ret = zfs_for_each(argc, argv, flags, ZFS_TYPE_DATASET,
1525		    NULL, NULL, 0, inherit_recurse_cb, &cb);
1526	} else {
1527		ret = zfs_for_each(argc, argv, flags, ZFS_TYPE_DATASET,
1528		    NULL, NULL, 0, inherit_cb, &cb);
1529	}
1530
1531	return (ret);
1532}
1533
1534typedef struct upgrade_cbdata {
1535	uint64_t cb_numupgraded;
1536	uint64_t cb_numsamegraded;
1537	uint64_t cb_numfailed;
1538	uint64_t cb_version;
1539	boolean_t cb_newer;
1540	boolean_t cb_foundone;
1541	char cb_lastfs[ZFS_MAXNAMELEN];
1542} upgrade_cbdata_t;
1543
1544static int
1545same_pool(zfs_handle_t *zhp, const char *name)
1546{
1547	int len1 = strcspn(name, "/@");
1548	const char *zhname = zfs_get_name(zhp);
1549	int len2 = strcspn(zhname, "/@");
1550
1551	if (len1 != len2)
1552		return (B_FALSE);
1553	return (strncmp(name, zhname, len1) == 0);
1554}
1555
1556static int
1557upgrade_list_callback(zfs_handle_t *zhp, void *data)
1558{
1559	upgrade_cbdata_t *cb = data;
1560	int version = zfs_prop_get_int(zhp, ZFS_PROP_VERSION);
1561
1562	/* list if it's old/new */
1563	if ((!cb->cb_newer && version < ZPL_VERSION) ||
1564	    (cb->cb_newer && version > ZPL_VERSION)) {
1565		char *str;
1566		if (cb->cb_newer) {
1567			str = gettext("The following filesystems are "
1568			    "formatted using a newer software version and\n"
1569			    "cannot be accessed on the current system.\n\n");
1570		} else {
1571			str = gettext("The following filesystems are "
1572			    "out of date, and can be upgraded.  After being\n"
1573			    "upgraded, these filesystems (and any 'zfs send' "
1574			    "streams generated from\n"
1575			    "subsequent snapshots) will no longer be "
1576			    "accessible by older software versions.\n\n");
1577		}
1578
1579		if (!cb->cb_foundone) {
1580			(void) puts(str);
1581			(void) printf(gettext("VER  FILESYSTEM\n"));
1582			(void) printf(gettext("---  ------------\n"));
1583			cb->cb_foundone = B_TRUE;
1584		}
1585
1586		(void) printf("%2u   %s\n", version, zfs_get_name(zhp));
1587	}
1588
1589	return (0);
1590}
1591
1592static int
1593upgrade_set_callback(zfs_handle_t *zhp, void *data)
1594{
1595	upgrade_cbdata_t *cb = data;
1596	int version = zfs_prop_get_int(zhp, ZFS_PROP_VERSION);
1597	int i;
1598	static struct { int zplver; int spaver; } table[] = {
1599		{ZPL_VERSION_FUID, SPA_VERSION_FUID},
1600		{ZPL_VERSION_USERSPACE, SPA_VERSION_USERSPACE},
1601		{0, 0}
1602	};
1603
1604
1605	for (i = 0; table[i].zplver; i++) {
1606		if (cb->cb_version >= table[i].zplver) {
1607			int spa_version;
1608
1609			if (zfs_spa_version(zhp, &spa_version) < 0)
1610				return (-1);
1611
1612			if (spa_version < table[i].spaver) {
1613				/* can't upgrade */
1614				(void) printf(gettext("%s: can not be "
1615				    "upgraded; the pool version needs to first "
1616				    "be upgraded\nto version %d\n\n"),
1617				    zfs_get_name(zhp), table[i].spaver);
1618				cb->cb_numfailed++;
1619				return (0);
1620			}
1621		}
1622	}
1623
1624	/* upgrade */
1625	if (version < cb->cb_version) {
1626		char verstr[16];
1627		(void) snprintf(verstr, sizeof (verstr),
1628		    "%llu", cb->cb_version);
1629		if (cb->cb_lastfs[0] && !same_pool(zhp, cb->cb_lastfs)) {
1630			/*
1631			 * If they did "zfs upgrade -a", then we could
1632			 * be doing ioctls to different pools.  We need
1633			 * to log this history once to each pool.
1634			 */
1635			verify(zpool_stage_history(g_zfs, history_str) == 0);
1636		}
1637		if (zfs_prop_set(zhp, "version", verstr) == 0)
1638			cb->cb_numupgraded++;
1639		else
1640			cb->cb_numfailed++;
1641		(void) strcpy(cb->cb_lastfs, zfs_get_name(zhp));
1642	} else if (version > cb->cb_version) {
1643		/* can't downgrade */
1644		(void) printf(gettext("%s: can not be downgraded; "
1645		    "it is already at version %u\n"),
1646		    zfs_get_name(zhp), version);
1647		cb->cb_numfailed++;
1648	} else {
1649		cb->cb_numsamegraded++;
1650	}
1651	return (0);
1652}
1653
1654/*
1655 * zfs upgrade
1656 * zfs upgrade -v
1657 * zfs upgrade [-r] [-V <version>] <-a | filesystem>
1658 */
1659static int
1660zfs_do_upgrade(int argc, char **argv)
1661{
1662	boolean_t all = B_FALSE;
1663	boolean_t showversions = B_FALSE;
1664	int ret;
1665	upgrade_cbdata_t cb = { 0 };
1666	char c;
1667	int flags = ZFS_ITER_ARGS_CAN_BE_PATHS;
1668
1669	/* check options */
1670	while ((c = getopt(argc, argv, "rvV:a")) != -1) {
1671		switch (c) {
1672		case 'r':
1673			flags |= ZFS_ITER_RECURSE;
1674			break;
1675		case 'v':
1676			showversions = B_TRUE;
1677			break;
1678		case 'V':
1679			if (zfs_prop_string_to_index(ZFS_PROP_VERSION,
1680			    optarg, &cb.cb_version) != 0) {
1681				(void) fprintf(stderr,
1682				    gettext("invalid version %s\n"), optarg);
1683				usage(B_FALSE);
1684			}
1685			break;
1686		case 'a':
1687			all = B_TRUE;
1688			break;
1689		case '?':
1690		default:
1691			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1692			    optopt);
1693			usage(B_FALSE);
1694		}
1695	}
1696
1697	argc -= optind;
1698	argv += optind;
1699
1700	if ((!all && !argc) && ((flags & ZFS_ITER_RECURSE) | cb.cb_version))
1701		usage(B_FALSE);
1702	if (showversions && (flags & ZFS_ITER_RECURSE || all ||
1703	    cb.cb_version || argc))
1704		usage(B_FALSE);
1705	if ((all || argc) && (showversions))
1706		usage(B_FALSE);
1707	if (all && argc)
1708		usage(B_FALSE);
1709
1710	if (showversions) {
1711		/* Show info on available versions. */
1712		(void) printf(gettext("The following filesystem versions are "
1713		    "supported:\n\n"));
1714		(void) printf(gettext("VER  DESCRIPTION\n"));
1715		(void) printf("---  -----------------------------------------"
1716		    "---------------\n");
1717		(void) printf(gettext(" 1   Initial ZFS filesystem version\n"));
1718		(void) printf(gettext(" 2   Enhanced directory entries\n"));
1719		(void) printf(gettext(" 3   Case insensitive and File system "
1720		    "unique identifier (FUID)\n"));
1721		(void) printf(gettext(" 4   userquota, groupquota "
1722		    "properties\n"));
1723		(void) printf(gettext("\nFor more information on a particular "
1724		    "version, including supported releases, see:\n\n"));
1725		(void) printf("http://www.opensolaris.org/os/community/zfs/"
1726		    "version/zpl/N\n\n");
1727		(void) printf(gettext("Where 'N' is the version number.\n"));
1728		ret = 0;
1729	} else if (argc || all) {
1730		/* Upgrade filesystems */
1731		if (cb.cb_version == 0)
1732			cb.cb_version = ZPL_VERSION;
1733		ret = zfs_for_each(argc, argv, flags, ZFS_TYPE_FILESYSTEM,
1734		    NULL, NULL, 0, upgrade_set_callback, &cb);
1735		(void) printf(gettext("%llu filesystems upgraded\n"),
1736		    cb.cb_numupgraded);
1737		if (cb.cb_numsamegraded) {
1738			(void) printf(gettext("%llu filesystems already at "
1739			    "this version\n"),
1740			    cb.cb_numsamegraded);
1741		}
1742		if (cb.cb_numfailed != 0)
1743			ret = 1;
1744	} else {
1745		/* List old-version filesytems */
1746		boolean_t found;
1747		(void) printf(gettext("This system is currently running "
1748		    "ZFS filesystem version %llu.\n\n"), ZPL_VERSION);
1749
1750		flags |= ZFS_ITER_RECURSE;
1751		ret = zfs_for_each(0, NULL, flags, ZFS_TYPE_FILESYSTEM,
1752		    NULL, NULL, 0, upgrade_list_callback, &cb);
1753
1754		found = cb.cb_foundone;
1755		cb.cb_foundone = B_FALSE;
1756		cb.cb_newer = B_TRUE;
1757
1758		ret = zfs_for_each(0, NULL, flags, ZFS_TYPE_FILESYSTEM,
1759		    NULL, NULL, 0, upgrade_list_callback, &cb);
1760
1761		if (!cb.cb_foundone && !found) {
1762			(void) printf(gettext("All filesystems are "
1763			    "formatted with the current version.\n"));
1764		}
1765	}
1766
1767	return (ret);
1768}
1769
1770/*
1771 * zfs userspace
1772 */
1773static int
1774userspace_cb(void *arg, const char *domain, uid_t rid, uint64_t space)
1775{
1776	zfs_userquota_prop_t *typep = arg;
1777	zfs_userquota_prop_t p = *typep;
1778	char *name = NULL;
1779	char *ug, *propname;
1780	char namebuf[32];
1781	char sizebuf[32];
1782
1783	if (domain == NULL || domain[0] == '\0') {
1784		if (p == ZFS_PROP_GROUPUSED || p == ZFS_PROP_GROUPQUOTA) {
1785			struct group *g = getgrgid(rid);
1786			if (g)
1787				name = g->gr_name;
1788		} else {
1789			struct passwd *p = getpwuid(rid);
1790			if (p)
1791				name = p->pw_name;
1792		}
1793	}
1794
1795	if (p == ZFS_PROP_GROUPUSED || p == ZFS_PROP_GROUPQUOTA)
1796		ug = "group";
1797	else
1798		ug = "user";
1799
1800	if (p == ZFS_PROP_USERUSED || p == ZFS_PROP_GROUPUSED)
1801		propname = "used";
1802	else
1803		propname = "quota";
1804
1805	if (name == NULL) {
1806		(void) snprintf(namebuf, sizeof (namebuf),
1807		    "%llu", (longlong_t)rid);
1808		name = namebuf;
1809	}
1810	zfs_nicenum(space, sizebuf, sizeof (sizebuf));
1811
1812	(void) printf("%s %s %s%c%s %s\n", propname, ug, domain,
1813	    domain[0] ? '-' : ' ', name, sizebuf);
1814
1815	return (0);
1816}
1817
1818static int
1819zfs_do_userspace(int argc, char **argv)
1820{
1821	zfs_handle_t *zhp;
1822	zfs_userquota_prop_t p;
1823	int error;
1824
1825	/*
1826	 * Try the python version.  If the execv fails, we'll continue
1827	 * and do a simplistic implementation.
1828	 */
1829	(void) execv(pypath, argv-1);
1830
1831	(void) printf("internal error: %s not found\n"
1832	    "falling back on built-in implementation, "
1833	    "some features will not work\n", pypath);
1834
1835	if ((zhp = zfs_open(g_zfs, argv[argc-1], ZFS_TYPE_DATASET)) == NULL)
1836		return (1);
1837
1838	(void) printf("PROP TYPE NAME VALUE\n");
1839
1840	for (p = 0; p < ZFS_NUM_USERQUOTA_PROPS; p++) {
1841		error = zfs_userspace(zhp, p, userspace_cb, &p);
1842		if (error)
1843			break;
1844	}
1845	return (error);
1846}
1847
1848/*
1849 * list [-r][-d max] [-H] [-o property[,property]...] [-t type[,type]...]
1850 *      [-s property [-s property]...] [-S property [-S property]...]
1851 *      <dataset> ...
1852 *
1853 *	-r	Recurse over all children
1854 *	-d	Limit recursion by depth.
1855 *	-H	Scripted mode; elide headers and separate columns by tabs
1856 *	-o	Control which fields to display.
1857 *	-t	Control which object types to display.
1858 *	-s	Specify sort columns, descending order.
1859 *	-S	Specify sort columns, ascending order.
1860 *
1861 * When given no arguments, lists all filesystems in the system.
1862 * Otherwise, list the specified datasets, optionally recursing down them if
1863 * '-r' is specified.
1864 */
1865typedef struct list_cbdata {
1866	boolean_t	cb_first;
1867	boolean_t	cb_scripted;
1868	zprop_list_t	*cb_proplist;
1869} list_cbdata_t;
1870
1871/*
1872 * Given a list of columns to display, output appropriate headers for each one.
1873 */
1874static void
1875print_header(zprop_list_t *pl)
1876{
1877	char headerbuf[ZFS_MAXPROPLEN];
1878	const char *header;
1879	int i;
1880	boolean_t first = B_TRUE;
1881	boolean_t right_justify;
1882
1883	for (; pl != NULL; pl = pl->pl_next) {
1884		if (!first) {
1885			(void) printf("  ");
1886		} else {
1887			first = B_FALSE;
1888		}
1889
1890		right_justify = B_FALSE;
1891		if (pl->pl_prop != ZPROP_INVAL) {
1892			header = zfs_prop_column_name(pl->pl_prop);
1893			right_justify = zfs_prop_align_right(pl->pl_prop);
1894		} else {
1895			for (i = 0; pl->pl_user_prop[i] != '\0'; i++)
1896				headerbuf[i] = toupper(pl->pl_user_prop[i]);
1897			headerbuf[i] = '\0';
1898			header = headerbuf;
1899		}
1900
1901		if (pl->pl_next == NULL && !right_justify)
1902			(void) printf("%s", header);
1903		else if (right_justify)
1904			(void) printf("%*s", pl->pl_width, header);
1905		else
1906			(void) printf("%-*s", pl->pl_width, header);
1907	}
1908
1909	(void) printf("\n");
1910}
1911
1912/*
1913 * Given a dataset and a list of fields, print out all the properties according
1914 * to the described layout.
1915 */
1916static void
1917print_dataset(zfs_handle_t *zhp, zprop_list_t *pl, boolean_t scripted)
1918{
1919	boolean_t first = B_TRUE;
1920	char property[ZFS_MAXPROPLEN];
1921	nvlist_t *userprops = zfs_get_user_props(zhp);
1922	nvlist_t *propval;
1923	char *propstr;
1924	boolean_t right_justify;
1925	int width;
1926
1927	for (; pl != NULL; pl = pl->pl_next) {
1928		if (!first) {
1929			if (scripted)
1930				(void) printf("\t");
1931			else
1932				(void) printf("  ");
1933		} else {
1934			first = B_FALSE;
1935		}
1936
1937		if (pl->pl_prop != ZPROP_INVAL) {
1938			if (zfs_prop_get(zhp, pl->pl_prop, property,
1939			    sizeof (property), NULL, NULL, 0, B_FALSE) != 0)
1940				propstr = "-";
1941			else
1942				propstr = property;
1943
1944			right_justify = zfs_prop_align_right(pl->pl_prop);
1945		} else if (zfs_prop_userquota(pl->pl_user_prop)) {
1946			if (zfs_prop_get_userquota(zhp, pl->pl_user_prop,
1947			    property, sizeof (property), B_FALSE) != 0)
1948				propstr = "-";
1949			else
1950				propstr = property;
1951			right_justify = B_TRUE;
1952		} else {
1953			if (nvlist_lookup_nvlist(userprops,
1954			    pl->pl_user_prop, &propval) != 0)
1955				propstr = "-";
1956			else
1957				verify(nvlist_lookup_string(propval,
1958				    ZPROP_VALUE, &propstr) == 0);
1959			right_justify = B_FALSE;
1960		}
1961
1962		width = pl->pl_width;
1963
1964		/*
1965		 * If this is being called in scripted mode, or if this is the
1966		 * last column and it is left-justified, don't include a width
1967		 * format specifier.
1968		 */
1969		if (scripted || (pl->pl_next == NULL && !right_justify))
1970			(void) printf("%s", propstr);
1971		else if (right_justify)
1972			(void) printf("%*s", width, propstr);
1973		else
1974			(void) printf("%-*s", width, propstr);
1975	}
1976
1977	(void) printf("\n");
1978}
1979
1980/*
1981 * Generic callback function to list a dataset or snapshot.
1982 */
1983static int
1984list_callback(zfs_handle_t *zhp, void *data)
1985{
1986	list_cbdata_t *cbp = data;
1987
1988	if (cbp->cb_first) {
1989		if (!cbp->cb_scripted)
1990			print_header(cbp->cb_proplist);
1991		cbp->cb_first = B_FALSE;
1992	}
1993
1994	print_dataset(zhp, cbp->cb_proplist, cbp->cb_scripted);
1995
1996	return (0);
1997}
1998
1999static int
2000zfs_do_list(int argc, char **argv)
2001{
2002	int c;
2003	boolean_t scripted = B_FALSE;
2004	static char default_fields[] =
2005	    "name,used,available,referenced,mountpoint";
2006	int types = ZFS_TYPE_DATASET;
2007	boolean_t types_specified = B_FALSE;
2008	char *fields = NULL;
2009	list_cbdata_t cb = { 0 };
2010	char *value;
2011	int limit = 0;
2012	int ret;
2013	zfs_sort_column_t *sortcol = NULL;
2014	int flags = ZFS_ITER_PROP_LISTSNAPS | ZFS_ITER_ARGS_CAN_BE_PATHS;
2015
2016	/* check options */
2017	while ((c = getopt(argc, argv, ":d:o:rt:Hs:S:")) != -1) {
2018		switch (c) {
2019		case 'o':
2020			fields = optarg;
2021			break;
2022		case 'd':
2023			limit = parse_depth(optarg, &flags);
2024			break;
2025		case 'r':
2026			flags |= ZFS_ITER_RECURSE;
2027			break;
2028		case 'H':
2029			scripted = B_TRUE;
2030			break;
2031		case 's':
2032			if (zfs_add_sort_column(&sortcol, optarg,
2033			    B_FALSE) != 0) {
2034				(void) fprintf(stderr,
2035				    gettext("invalid property '%s'\n"), optarg);
2036				usage(B_FALSE);
2037			}
2038			break;
2039		case 'S':
2040			if (zfs_add_sort_column(&sortcol, optarg,
2041			    B_TRUE) != 0) {
2042				(void) fprintf(stderr,
2043				    gettext("invalid property '%s'\n"), optarg);
2044				usage(B_FALSE);
2045			}
2046			break;
2047		case 't':
2048			types = 0;
2049			types_specified = B_TRUE;
2050			flags &= ~ZFS_ITER_PROP_LISTSNAPS;
2051			while (*optarg != '\0') {
2052				static char *type_subopts[] = { "filesystem",
2053				    "volume", "snapshot", "all", NULL };
2054
2055				switch (getsubopt(&optarg, type_subopts,
2056				    &value)) {
2057				case 0:
2058					types |= ZFS_TYPE_FILESYSTEM;
2059					break;
2060				case 1:
2061					types |= ZFS_TYPE_VOLUME;
2062					break;
2063				case 2:
2064					types |= ZFS_TYPE_SNAPSHOT;
2065					break;
2066				case 3:
2067					types = ZFS_TYPE_DATASET;
2068					break;
2069
2070				default:
2071					(void) fprintf(stderr,
2072					    gettext("invalid type '%s'\n"),
2073					    value);
2074					usage(B_FALSE);
2075				}
2076			}
2077			break;
2078		case ':':
2079			(void) fprintf(stderr, gettext("missing argument for "
2080			    "'%c' option\n"), optopt);
2081			usage(B_FALSE);
2082			break;
2083		case '?':
2084			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2085			    optopt);
2086			usage(B_FALSE);
2087		}
2088	}
2089
2090	argc -= optind;
2091	argv += optind;
2092
2093	if (fields == NULL)
2094		fields = default_fields;
2095
2096	/*
2097	 * If "-o space" and no types were specified, don't display snapshots.
2098	 */
2099	if (strcmp(fields, "space") == 0 && types_specified == B_FALSE)
2100		types &= ~ZFS_TYPE_SNAPSHOT;
2101
2102	/*
2103	 * If the user specifies '-o all', the zprop_get_list() doesn't
2104	 * normally include the name of the dataset.  For 'zfs list', we always
2105	 * want this property to be first.
2106	 */
2107	if (zprop_get_list(g_zfs, fields, &cb.cb_proplist, ZFS_TYPE_DATASET)
2108	    != 0)
2109		usage(B_FALSE);
2110
2111	cb.cb_scripted = scripted;
2112	cb.cb_first = B_TRUE;
2113
2114	ret = zfs_for_each(argc, argv, flags, types, sortcol, &cb.cb_proplist,
2115	    limit, list_callback, &cb);
2116
2117	zprop_free_list(cb.cb_proplist);
2118	zfs_free_sort_columns(sortcol);
2119
2120	if (ret == 0 && cb.cb_first && !cb.cb_scripted)
2121		(void) printf(gettext("no datasets available\n"));
2122
2123	return (ret);
2124}
2125
2126/*
2127 * zfs rename <fs | snap | vol> <fs | snap | vol>
2128 * zfs rename -p <fs | vol> <fs | vol>
2129 * zfs rename -r <snap> <snap>
2130 *
2131 * Renames the given dataset to another of the same type.
2132 *
2133 * The '-p' flag creates all the non-existing ancestors of the target first.
2134 */
2135/* ARGSUSED */
2136static int
2137zfs_do_rename(int argc, char **argv)
2138{
2139	zfs_handle_t *zhp;
2140	int c;
2141	int ret;
2142	boolean_t recurse = B_FALSE;
2143	boolean_t parents = B_FALSE;
2144
2145	/* check options */
2146	while ((c = getopt(argc, argv, "pr")) != -1) {
2147		switch (c) {
2148		case 'p':
2149			parents = B_TRUE;
2150			break;
2151		case 'r':
2152			recurse = B_TRUE;
2153			break;
2154		case '?':
2155		default:
2156			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2157			    optopt);
2158			usage(B_FALSE);
2159		}
2160	}
2161
2162	argc -= optind;
2163	argv += optind;
2164
2165	/* check number of arguments */
2166	if (argc < 1) {
2167		(void) fprintf(stderr, gettext("missing source dataset "
2168		    "argument\n"));
2169		usage(B_FALSE);
2170	}
2171	if (argc < 2) {
2172		(void) fprintf(stderr, gettext("missing target dataset "
2173		    "argument\n"));
2174		usage(B_FALSE);
2175	}
2176	if (argc > 2) {
2177		(void) fprintf(stderr, gettext("too many arguments\n"));
2178		usage(B_FALSE);
2179	}
2180
2181	if (recurse && parents) {
2182		(void) fprintf(stderr, gettext("-p and -r options are mutually "
2183		    "exclusive\n"));
2184		usage(B_FALSE);
2185	}
2186
2187	if (recurse && strchr(argv[0], '@') == 0) {
2188		(void) fprintf(stderr, gettext("source dataset for recursive "
2189		    "rename must be a snapshot\n"));
2190		usage(B_FALSE);
2191	}
2192
2193	if ((zhp = zfs_open(g_zfs, argv[0], parents ? ZFS_TYPE_FILESYSTEM |
2194	    ZFS_TYPE_VOLUME : ZFS_TYPE_DATASET)) == NULL)
2195		return (1);
2196
2197	/* If we were asked and the name looks good, try to create ancestors. */
2198	if (parents && zfs_name_valid(argv[1], zfs_get_type(zhp)) &&
2199	    zfs_create_ancestors(g_zfs, argv[1]) != 0) {
2200		zfs_close(zhp);
2201		return (1);
2202	}
2203
2204	ret = (zfs_rename(zhp, argv[1], recurse) != 0);
2205
2206	zfs_close(zhp);
2207	return (ret);
2208}
2209
2210/*
2211 * zfs promote <fs>
2212 *
2213 * Promotes the given clone fs to be the parent
2214 */
2215/* ARGSUSED */
2216static int
2217zfs_do_promote(int argc, char **argv)
2218{
2219	zfs_handle_t *zhp;
2220	int ret;
2221
2222	/* check options */
2223	if (argc > 1 && argv[1][0] == '-') {
2224		(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2225		    argv[1][1]);
2226		usage(B_FALSE);
2227	}
2228
2229	/* check number of arguments */
2230	if (argc < 2) {
2231		(void) fprintf(stderr, gettext("missing clone filesystem"
2232		    " argument\n"));
2233		usage(B_FALSE);
2234	}
2235	if (argc > 2) {
2236		(void) fprintf(stderr, gettext("too many arguments\n"));
2237		usage(B_FALSE);
2238	}
2239
2240	zhp = zfs_open(g_zfs, argv[1], ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
2241	if (zhp == NULL)
2242		return (1);
2243
2244	ret = (zfs_promote(zhp) != 0);
2245
2246
2247	zfs_close(zhp);
2248	return (ret);
2249}
2250
2251/*
2252 * zfs rollback [-rRf] <snapshot>
2253 *
2254 *	-r	Delete any intervening snapshots before doing rollback
2255 *	-R	Delete any snapshots and their clones
2256 *	-f	ignored for backwards compatability
2257 *
2258 * Given a filesystem, rollback to a specific snapshot, discarding any changes
2259 * since then and making it the active dataset.  If more recent snapshots exist,
2260 * the command will complain unless the '-r' flag is given.
2261 */
2262typedef struct rollback_cbdata {
2263	uint64_t	cb_create;
2264	boolean_t	cb_first;
2265	int		cb_doclones;
2266	char		*cb_target;
2267	int		cb_error;
2268	boolean_t	cb_recurse;
2269	boolean_t	cb_dependent;
2270} rollback_cbdata_t;
2271
2272/*
2273 * Report any snapshots more recent than the one specified.  Used when '-r' is
2274 * not specified.  We reuse this same callback for the snapshot dependents - if
2275 * 'cb_dependent' is set, then this is a dependent and we should report it
2276 * without checking the transaction group.
2277 */
2278static int
2279rollback_check(zfs_handle_t *zhp, void *data)
2280{
2281	rollback_cbdata_t *cbp = data;
2282
2283	if (cbp->cb_doclones) {
2284		zfs_close(zhp);
2285		return (0);
2286	}
2287
2288	if (!cbp->cb_dependent) {
2289		if (strcmp(zfs_get_name(zhp), cbp->cb_target) != 0 &&
2290		    zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT &&
2291		    zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) >
2292		    cbp->cb_create) {
2293
2294			if (cbp->cb_first && !cbp->cb_recurse) {
2295				(void) fprintf(stderr, gettext("cannot "
2296				    "rollback to '%s': more recent snapshots "
2297				    "exist\n"),
2298				    cbp->cb_target);
2299				(void) fprintf(stderr, gettext("use '-r' to "
2300				    "force deletion of the following "
2301				    "snapshots:\n"));
2302				cbp->cb_first = 0;
2303				cbp->cb_error = 1;
2304			}
2305
2306			if (cbp->cb_recurse) {
2307				cbp->cb_dependent = B_TRUE;
2308				if (zfs_iter_dependents(zhp, B_TRUE,
2309				    rollback_check, cbp) != 0) {
2310					zfs_close(zhp);
2311					return (-1);
2312				}
2313				cbp->cb_dependent = B_FALSE;
2314			} else {
2315				(void) fprintf(stderr, "%s\n",
2316				    zfs_get_name(zhp));
2317			}
2318		}
2319	} else {
2320		if (cbp->cb_first && cbp->cb_recurse) {
2321			(void) fprintf(stderr, gettext("cannot rollback to "
2322			    "'%s': clones of previous snapshots exist\n"),
2323			    cbp->cb_target);
2324			(void) fprintf(stderr, gettext("use '-R' to "
2325			    "force deletion of the following clones and "
2326			    "dependents:\n"));
2327			cbp->cb_first = 0;
2328			cbp->cb_error = 1;
2329		}
2330
2331		(void) fprintf(stderr, "%s\n", zfs_get_name(zhp));
2332	}
2333
2334	zfs_close(zhp);
2335	return (0);
2336}
2337
2338static int
2339zfs_do_rollback(int argc, char **argv)
2340{
2341	int ret;
2342	int c;
2343	boolean_t force = B_FALSE;
2344	rollback_cbdata_t cb = { 0 };
2345	zfs_handle_t *zhp, *snap;
2346	char parentname[ZFS_MAXNAMELEN];
2347	char *delim;
2348
2349	/* check options */
2350	while ((c = getopt(argc, argv, "rRf")) != -1) {
2351		switch (c) {
2352		case 'r':
2353			cb.cb_recurse = 1;
2354			break;
2355		case 'R':
2356			cb.cb_recurse = 1;
2357			cb.cb_doclones = 1;
2358			break;
2359		case 'f':
2360			force = B_TRUE;
2361			break;
2362		case '?':
2363			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2364			    optopt);
2365			usage(B_FALSE);
2366		}
2367	}
2368
2369	argc -= optind;
2370	argv += optind;
2371
2372	/* check number of arguments */
2373	if (argc < 1) {
2374		(void) fprintf(stderr, gettext("missing dataset argument\n"));
2375		usage(B_FALSE);
2376	}
2377	if (argc > 1) {
2378		(void) fprintf(stderr, gettext("too many arguments\n"));
2379		usage(B_FALSE);
2380	}
2381
2382	/* open the snapshot */
2383	if ((snap = zfs_open(g_zfs, argv[0], ZFS_TYPE_SNAPSHOT)) == NULL)
2384		return (1);
2385
2386	/* open the parent dataset */
2387	(void) strlcpy(parentname, argv[0], sizeof (parentname));
2388	verify((delim = strrchr(parentname, '@')) != NULL);
2389	*delim = '\0';
2390	if ((zhp = zfs_open(g_zfs, parentname, ZFS_TYPE_DATASET)) == NULL) {
2391		zfs_close(snap);
2392		return (1);
2393	}
2394
2395	/*
2396	 * Check for more recent snapshots and/or clones based on the presence
2397	 * of '-r' and '-R'.
2398	 */
2399	cb.cb_target = argv[0];
2400	cb.cb_create = zfs_prop_get_int(snap, ZFS_PROP_CREATETXG);
2401	cb.cb_first = B_TRUE;
2402	cb.cb_error = 0;
2403	if ((ret = zfs_iter_children(zhp, rollback_check, &cb)) != 0)
2404		goto out;
2405
2406	if ((ret = cb.cb_error) != 0)
2407		goto out;
2408
2409	/*
2410	 * Rollback parent to the given snapshot.
2411	 */
2412	ret = zfs_rollback(zhp, snap, force);
2413
2414out:
2415	zfs_close(snap);
2416	zfs_close(zhp);
2417
2418	if (ret == 0)
2419		return (0);
2420	else
2421		return (1);
2422}
2423
2424/*
2425 * zfs set property=value { fs | snap | vol } ...
2426 *
2427 * Sets the given property for all datasets specified on the command line.
2428 */
2429typedef struct set_cbdata {
2430	char		*cb_propname;
2431	char		*cb_value;
2432} set_cbdata_t;
2433
2434static int
2435set_callback(zfs_handle_t *zhp, void *data)
2436{
2437	set_cbdata_t *cbp = data;
2438
2439	if (zfs_prop_set(zhp, cbp->cb_propname, cbp->cb_value) != 0) {
2440		switch (libzfs_errno(g_zfs)) {
2441		case EZFS_MOUNTFAILED:
2442			(void) fprintf(stderr, gettext("property may be set "
2443			    "but unable to remount filesystem\n"));
2444			break;
2445		case EZFS_SHARENFSFAILED:
2446			(void) fprintf(stderr, gettext("property may be set "
2447			    "but unable to reshare filesystem\n"));
2448			break;
2449		}
2450		return (1);
2451	}
2452	return (0);
2453}
2454
2455static int
2456zfs_do_set(int argc, char **argv)
2457{
2458	set_cbdata_t cb;
2459	int ret;
2460
2461	/* check for options */
2462	if (argc > 1 && argv[1][0] == '-') {
2463		(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2464		    argv[1][1]);
2465		usage(B_FALSE);
2466	}
2467
2468	/* check number of arguments */
2469	if (argc < 2) {
2470		(void) fprintf(stderr, gettext("missing property=value "
2471		    "argument\n"));
2472		usage(B_FALSE);
2473	}
2474	if (argc < 3) {
2475		(void) fprintf(stderr, gettext("missing dataset name\n"));
2476		usage(B_FALSE);
2477	}
2478
2479	/* validate property=value argument */
2480	cb.cb_propname = argv[1];
2481	if (((cb.cb_value = strchr(cb.cb_propname, '=')) == NULL) ||
2482	    (cb.cb_value[1] == '\0')) {
2483		(void) fprintf(stderr, gettext("missing value in "
2484		    "property=value argument\n"));
2485		usage(B_FALSE);
2486	}
2487
2488	*cb.cb_value = '\0';
2489	cb.cb_value++;
2490
2491	if (*cb.cb_propname == '\0') {
2492		(void) fprintf(stderr,
2493		    gettext("missing property in property=value argument\n"));
2494		usage(B_FALSE);
2495	}
2496
2497	ret = zfs_for_each(argc - 2, argv + 2, NULL,
2498	    ZFS_TYPE_DATASET, NULL, NULL, 0, set_callback, &cb);
2499
2500	return (ret);
2501}
2502
2503/*
2504 * zfs snapshot [-r] [-o prop=value] ... <fs@snap>
2505 *
2506 * Creates a snapshot with the given name.  While functionally equivalent to
2507 * 'zfs create', it is a separate command to differentiate intent.
2508 */
2509static int
2510zfs_do_snapshot(int argc, char **argv)
2511{
2512	boolean_t recursive = B_FALSE;
2513	int ret;
2514	char c;
2515	nvlist_t *props;
2516
2517	if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) {
2518		(void) fprintf(stderr, gettext("internal error: "
2519		    "out of memory\n"));
2520		return (1);
2521	}
2522
2523	/* check options */
2524	while ((c = getopt(argc, argv, "ro:")) != -1) {
2525		switch (c) {
2526		case 'o':
2527			if (parseprop(props))
2528				return (1);
2529			break;
2530		case 'r':
2531			recursive = B_TRUE;
2532			break;
2533		case '?':
2534			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2535			    optopt);
2536			goto usage;
2537		}
2538	}
2539
2540	argc -= optind;
2541	argv += optind;
2542
2543	/* check number of arguments */
2544	if (argc < 1) {
2545		(void) fprintf(stderr, gettext("missing snapshot argument\n"));
2546		goto usage;
2547	}
2548	if (argc > 1) {
2549		(void) fprintf(stderr, gettext("too many arguments\n"));
2550		goto usage;
2551	}
2552
2553	ret = zfs_snapshot(g_zfs, argv[0], recursive, props);
2554	nvlist_free(props);
2555	if (ret && recursive)
2556		(void) fprintf(stderr, gettext("no snapshots were created\n"));
2557	return (ret != 0);
2558
2559usage:
2560	nvlist_free(props);
2561	usage(B_FALSE);
2562	return (-1);
2563}
2564
2565/*
2566 * zfs send [-vDp] -R [-i|-I <@snap>] <fs@snap>
2567 * zfs send [-vDp] [-i|-I <@snap>] <fs@snap>
2568 *
2569 * Send a backup stream to stdout.
2570 */
2571static int
2572zfs_do_send(int argc, char **argv)
2573{
2574	char *fromname = NULL;
2575	char *toname = NULL;
2576	char *cp;
2577	zfs_handle_t *zhp;
2578	sendflags_t flags = { 0 };
2579	int c, err;
2580
2581	/* check options */
2582	while ((c = getopt(argc, argv, ":i:I:RDpv")) != -1) {
2583		switch (c) {
2584		case 'i':
2585			if (fromname)
2586				usage(B_FALSE);
2587			fromname = optarg;
2588			break;
2589		case 'I':
2590			if (fromname)
2591				usage(B_FALSE);
2592			fromname = optarg;
2593			flags.doall = B_TRUE;
2594			break;
2595		case 'R':
2596			flags.replicate = B_TRUE;
2597			break;
2598		case 'p':
2599			flags.props = B_TRUE;
2600			break;
2601		case 'v':
2602			flags.verbose = B_TRUE;
2603			break;
2604		case 'D':
2605			flags.dedup = B_TRUE;
2606			break;
2607		case ':':
2608			(void) fprintf(stderr, gettext("missing argument for "
2609			    "'%c' option\n"), optopt);
2610			usage(B_FALSE);
2611			break;
2612		case '?':
2613			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2614			    optopt);
2615			usage(B_FALSE);
2616		}
2617	}
2618
2619	argc -= optind;
2620	argv += optind;
2621
2622	/* check number of arguments */
2623	if (argc < 1) {
2624		(void) fprintf(stderr, gettext("missing snapshot argument\n"));
2625		usage(B_FALSE);
2626	}
2627	if (argc > 1) {
2628		(void) fprintf(stderr, gettext("too many arguments\n"));
2629		usage(B_FALSE);
2630	}
2631
2632	if (isatty(STDOUT_FILENO)) {
2633		(void) fprintf(stderr,
2634		    gettext("Error: Stream can not be written to a terminal.\n"
2635		    "You must redirect standard output.\n"));
2636		return (1);
2637	}
2638
2639	cp = strchr(argv[0], '@');
2640	if (cp == NULL) {
2641		(void) fprintf(stderr,
2642		    gettext("argument must be a snapshot\n"));
2643		usage(B_FALSE);
2644	}
2645	*cp = '\0';
2646	toname = cp + 1;
2647	zhp = zfs_open(g_zfs, argv[0], ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
2648	if (zhp == NULL)
2649		return (1);
2650
2651	/*
2652	 * If they specified the full path to the snapshot, chop off
2653	 * everything except the short name of the snapshot, but special
2654	 * case if they specify the origin.
2655	 */
2656	if (fromname && (cp = strchr(fromname, '@')) != NULL) {
2657		char origin[ZFS_MAXNAMELEN];
2658		zprop_source_t src;
2659
2660		(void) zfs_prop_get(zhp, ZFS_PROP_ORIGIN,
2661		    origin, sizeof (origin), &src, NULL, 0, B_FALSE);
2662
2663		if (strcmp(origin, fromname) == 0) {
2664			fromname = NULL;
2665			flags.fromorigin = B_TRUE;
2666		} else {
2667			*cp = '\0';
2668			if (cp != fromname && strcmp(argv[0], fromname)) {
2669				(void) fprintf(stderr,
2670				    gettext("incremental source must be "
2671				    "in same filesystem\n"));
2672				usage(B_FALSE);
2673			}
2674			fromname = cp + 1;
2675			if (strchr(fromname, '@') || strchr(fromname, '/')) {
2676				(void) fprintf(stderr,
2677				    gettext("invalid incremental source\n"));
2678				usage(B_FALSE);
2679			}
2680		}
2681	}
2682
2683	if (flags.replicate && fromname == NULL)
2684		flags.doall = B_TRUE;
2685
2686	err = zfs_send(zhp, fromname, toname, flags, STDOUT_FILENO, NULL, 0);
2687	zfs_close(zhp);
2688
2689	return (err != 0);
2690}
2691
2692/*
2693 * zfs receive [-denvF] <fs@snap>
2694 *
2695 * Restore a backup stream from stdin.
2696 */
2697static int
2698zfs_do_receive(int argc, char **argv)
2699{
2700	int c, err;
2701	recvflags_t flags = { 0 };
2702
2703	/* check options */
2704	while ((c = getopt(argc, argv, ":denuvF")) != -1) {
2705		switch (c) {
2706		case 'd':
2707			flags.isprefix = B_TRUE;
2708			break;
2709		case 'e':
2710			flags.isprefix = B_TRUE;
2711			flags.istail = B_TRUE;
2712			break;
2713		case 'n':
2714			flags.dryrun = B_TRUE;
2715			break;
2716		case 'u':
2717			flags.nomount = B_TRUE;
2718			break;
2719		case 'v':
2720			flags.verbose = B_TRUE;
2721			break;
2722		case 'F':
2723			flags.force = B_TRUE;
2724			break;
2725		case ':':
2726			(void) fprintf(stderr, gettext("missing argument for "
2727			    "'%c' option\n"), optopt);
2728			usage(B_FALSE);
2729			break;
2730		case '?':
2731			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2732			    optopt);
2733			usage(B_FALSE);
2734		}
2735	}
2736
2737	argc -= optind;
2738	argv += optind;
2739
2740	/* check number of arguments */
2741	if (argc < 1) {
2742		(void) fprintf(stderr, gettext("missing snapshot argument\n"));
2743		usage(B_FALSE);
2744	}
2745	if (argc > 1) {
2746		(void) fprintf(stderr, gettext("too many arguments\n"));
2747		usage(B_FALSE);
2748	}
2749
2750	if (isatty(STDIN_FILENO)) {
2751		(void) fprintf(stderr,
2752		    gettext("Error: Backup stream can not be read "
2753		    "from a terminal.\n"
2754		    "You must redirect standard input.\n"));
2755		return (1);
2756	}
2757
2758	err = zfs_receive(g_zfs, argv[0], flags, STDIN_FILENO, NULL);
2759
2760	return (err != 0);
2761}
2762
2763static int
2764zfs_do_hold_rele_impl(int argc, char **argv, boolean_t holding)
2765{
2766	int errors = 0;
2767	int i;
2768	const char *tag;
2769	boolean_t recursive = B_FALSE;
2770	boolean_t temphold = B_FALSE;
2771	const char *opts = holding ? "rt" : "r";
2772	int c;
2773
2774	/* check options */
2775	while ((c = getopt(argc, argv, opts)) != -1) {
2776		switch (c) {
2777		case 'r':
2778			recursive = B_TRUE;
2779			break;
2780		case 't':
2781			temphold = B_TRUE;
2782			break;
2783		case '?':
2784			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2785			    optopt);
2786			usage(B_FALSE);
2787		}
2788	}
2789
2790	argc -= optind;
2791	argv += optind;
2792
2793	/* check number of arguments */
2794	if (argc < 2)
2795		usage(B_FALSE);
2796
2797	tag = argv[0];
2798	--argc;
2799	++argv;
2800
2801	if (holding && tag[0] == '.') {
2802		/* tags starting with '.' are reserved for libzfs */
2803		(void) fprintf(stderr, gettext("tag may not start with '.'\n"));
2804		usage(B_FALSE);
2805	}
2806
2807	for (i = 0; i < argc; ++i) {
2808		zfs_handle_t *zhp;
2809		char parent[ZFS_MAXNAMELEN];
2810		const char *delim;
2811		char *path = argv[i];
2812
2813		delim = strchr(path, '@');
2814		if (delim == NULL) {
2815			(void) fprintf(stderr,
2816			    gettext("'%s' is not a snapshot\n"), path);
2817			++errors;
2818			continue;
2819		}
2820		(void) strncpy(parent, path, delim - path);
2821		parent[delim - path] = '\0';
2822
2823		zhp = zfs_open(g_zfs, parent,
2824		    ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
2825		if (zhp == NULL) {
2826			++errors;
2827			continue;
2828		}
2829		if (holding) {
2830			if (zfs_hold(zhp, delim+1, tag, recursive,
2831			    temphold, B_FALSE) != 0)
2832				++errors;
2833		} else {
2834			if (zfs_release(zhp, delim+1, tag, recursive) != 0)
2835				++errors;
2836		}
2837		zfs_close(zhp);
2838	}
2839
2840	return (errors != 0);
2841}
2842
2843/*
2844 * zfs hold [-r] [-t] <tag> <snap> ...
2845 *
2846 *	-r	Recursively hold
2847 *	-t	Temporary hold (hidden option)
2848 *
2849 * Apply a user-hold with the given tag to the list of snapshots.
2850 */
2851static int
2852zfs_do_hold(int argc, char **argv)
2853{
2854	return (zfs_do_hold_rele_impl(argc, argv, B_TRUE));
2855}
2856
2857/*
2858 * zfs release [-r] <tag> <snap> ...
2859 *
2860 *	-r	Recursively release
2861 *
2862 * Release a user-hold with the given tag from the list of snapshots.
2863 */
2864static int
2865zfs_do_release(int argc, char **argv)
2866{
2867	return (zfs_do_hold_rele_impl(argc, argv, B_FALSE));
2868}
2869
2870typedef struct get_all_cbdata {
2871	zfs_handle_t	**cb_handles;
2872	size_t		cb_alloc;
2873	size_t		cb_used;
2874	uint_t		cb_types;
2875	boolean_t	cb_verbose;
2876} get_all_cbdata_t;
2877
2878#define	CHECK_SPINNER 30
2879#define	SPINNER_TIME 3		/* seconds */
2880#define	MOUNT_TIME 5		/* seconds */
2881
2882static int
2883get_one_dataset(zfs_handle_t *zhp, void *data)
2884{
2885	static char spin[] = { '-', '\\', '|', '/' };
2886	static int spinval = 0;
2887	static int spincheck = 0;
2888	static time_t last_spin_time = (time_t)0;
2889	get_all_cbdata_t *cbp = data;
2890	zfs_type_t type = zfs_get_type(zhp);
2891
2892	if (cbp->cb_verbose) {
2893		if (--spincheck < 0) {
2894			time_t now = time(NULL);
2895			if (last_spin_time + SPINNER_TIME < now) {
2896				(void) printf("\b%c", spin[spinval++ % 4]);
2897				(void) fflush(stdout);
2898				last_spin_time = now;
2899			}
2900			spincheck = CHECK_SPINNER;
2901		}
2902	}
2903
2904	/*
2905	 * Interate over any nested datasets.
2906	 */
2907	if (type == ZFS_TYPE_FILESYSTEM &&
2908	    zfs_iter_filesystems(zhp, get_one_dataset, data) != 0) {
2909		zfs_close(zhp);
2910		return (1);
2911	}
2912
2913	/*
2914	 * Skip any datasets whose type does not match.
2915	 */
2916	if ((type & cbp->cb_types) == 0) {
2917		zfs_close(zhp);
2918		return (0);
2919	}
2920
2921	if (cbp->cb_alloc == cbp->cb_used) {
2922		zfs_handle_t **handles;
2923
2924		if (cbp->cb_alloc == 0)
2925			cbp->cb_alloc = 64;
2926		else
2927			cbp->cb_alloc *= 2;
2928
2929		handles = safe_malloc(cbp->cb_alloc * sizeof (void *));
2930
2931		if (cbp->cb_handles) {
2932			bcopy(cbp->cb_handles, handles,
2933			    cbp->cb_used * sizeof (void *));
2934			free(cbp->cb_handles);
2935		}
2936
2937		cbp->cb_handles = handles;
2938	}
2939
2940	cbp->cb_handles[cbp->cb_used++] = zhp;
2941
2942	return (0);
2943}
2944
2945static void
2946get_all_datasets(uint_t types, zfs_handle_t ***dslist, size_t *count,
2947    boolean_t verbose)
2948{
2949	get_all_cbdata_t cb = { 0 };
2950	cb.cb_types = types;
2951	cb.cb_verbose = verbose;
2952
2953	if (verbose) {
2954		(void) printf("%s: *", gettext("Reading ZFS config"));
2955		(void) fflush(stdout);
2956	}
2957
2958	(void) zfs_iter_root(g_zfs, get_one_dataset, &cb);
2959
2960	*dslist = cb.cb_handles;
2961	*count = cb.cb_used;
2962
2963	if (verbose) {
2964		(void) printf("\b%s\n", gettext("done."));
2965	}
2966}
2967
2968static int
2969dataset_cmp(const void *a, const void *b)
2970{
2971	zfs_handle_t **za = (zfs_handle_t **)a;
2972	zfs_handle_t **zb = (zfs_handle_t **)b;
2973	char mounta[MAXPATHLEN];
2974	char mountb[MAXPATHLEN];
2975	boolean_t gota, gotb;
2976
2977	if ((gota = (zfs_get_type(*za) == ZFS_TYPE_FILESYSTEM)) != 0)
2978		verify(zfs_prop_get(*za, ZFS_PROP_MOUNTPOINT, mounta,
2979		    sizeof (mounta), NULL, NULL, 0, B_FALSE) == 0);
2980	if ((gotb = (zfs_get_type(*zb) == ZFS_TYPE_FILESYSTEM)) != 0)
2981		verify(zfs_prop_get(*zb, ZFS_PROP_MOUNTPOINT, mountb,
2982		    sizeof (mountb), NULL, NULL, 0, B_FALSE) == 0);
2983
2984	if (gota && gotb)
2985		return (strcmp(mounta, mountb));
2986
2987	if (gota)
2988		return (-1);
2989	if (gotb)
2990		return (1);
2991
2992	return (strcmp(zfs_get_name(a), zfs_get_name(b)));
2993}
2994
2995/*
2996 * Generic callback for sharing or mounting filesystems.  Because the code is so
2997 * similar, we have a common function with an extra parameter to determine which
2998 * mode we are using.
2999 */
3000#define	OP_SHARE	0x1
3001#define	OP_MOUNT	0x2
3002
3003/*
3004 * Share or mount a dataset.
3005 */
3006static int
3007share_mount_one(zfs_handle_t *zhp, int op, int flags, char *protocol,
3008    boolean_t explicit, const char *options)
3009{
3010	char mountpoint[ZFS_MAXPROPLEN];
3011	char shareopts[ZFS_MAXPROPLEN];
3012	char smbshareopts[ZFS_MAXPROPLEN];
3013	const char *cmdname = op == OP_SHARE ? "share" : "mount";
3014	struct mnttab mnt;
3015	uint64_t zoned, canmount;
3016	zfs_type_t type = zfs_get_type(zhp);
3017	boolean_t shared_nfs, shared_smb;
3018
3019	assert(type & (ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME));
3020
3021	if (type == ZFS_TYPE_FILESYSTEM) {
3022		/*
3023		 * Check to make sure we can mount/share this dataset.  If we
3024		 * are in the global zone and the filesystem is exported to a
3025		 * local zone, or if we are in a local zone and the
3026		 * filesystem is not exported, then it is an error.
3027		 */
3028		zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED);
3029
3030		if (zoned && getzoneid() == GLOBAL_ZONEID) {
3031			if (!explicit)
3032				return (0);
3033
3034			(void) fprintf(stderr, gettext("cannot %s '%s': "
3035			    "dataset is exported to a local zone\n"), cmdname,
3036			    zfs_get_name(zhp));
3037			return (1);
3038
3039		} else if (!zoned && getzoneid() != GLOBAL_ZONEID) {
3040			if (!explicit)
3041				return (0);
3042
3043			(void) fprintf(stderr, gettext("cannot %s '%s': "
3044			    "permission denied\n"), cmdname,
3045			    zfs_get_name(zhp));
3046			return (1);
3047		}
3048
3049		/*
3050		 * Ignore any filesystems which don't apply to us. This
3051		 * includes those with a legacy mountpoint, or those with
3052		 * legacy share options.
3053		 */
3054		verify(zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint,
3055		    sizeof (mountpoint), NULL, NULL, 0, B_FALSE) == 0);
3056		verify(zfs_prop_get(zhp, ZFS_PROP_SHARENFS, shareopts,
3057		    sizeof (shareopts), NULL, NULL, 0, B_FALSE) == 0);
3058		verify(zfs_prop_get(zhp, ZFS_PROP_SHARESMB, smbshareopts,
3059		    sizeof (smbshareopts), NULL, NULL, 0, B_FALSE) == 0);
3060
3061		if (op == OP_SHARE && strcmp(shareopts, "off") == 0 &&
3062		    strcmp(smbshareopts, "off") == 0) {
3063			if (!explicit)
3064				return (0);
3065
3066			(void) fprintf(stderr, gettext("cannot share '%s': "
3067			    "legacy share\n"), zfs_get_name(zhp));
3068			(void) fprintf(stderr, gettext("use share(1M) to "
3069			    "share this filesystem, or set "
3070			    "sharenfs property on\n"));
3071			return (1);
3072		}
3073
3074		/*
3075		 * We cannot share or mount legacy filesystems. If the
3076		 * shareopts is non-legacy but the mountpoint is legacy, we
3077		 * treat it as a legacy share.
3078		 */
3079		if (strcmp(mountpoint, "legacy") == 0) {
3080			if (!explicit)
3081				return (0);
3082
3083			(void) fprintf(stderr, gettext("cannot %s '%s': "
3084			    "legacy mountpoint\n"), cmdname, zfs_get_name(zhp));
3085			(void) fprintf(stderr, gettext("use %s(1M) to "
3086			    "%s this filesystem\n"), cmdname, cmdname);
3087			return (1);
3088		}
3089
3090		if (strcmp(mountpoint, "none") == 0) {
3091			if (!explicit)
3092				return (0);
3093
3094			(void) fprintf(stderr, gettext("cannot %s '%s': no "
3095			    "mountpoint set\n"), cmdname, zfs_get_name(zhp));
3096			return (1);
3097		}
3098
3099		/*
3100		 * canmount	explicit	outcome
3101		 * on		no		pass through
3102		 * on		yes		pass through
3103		 * off		no		return 0
3104		 * off		yes		display error, return 1
3105		 * noauto	no		return 0
3106		 * noauto	yes		pass through
3107		 */
3108		canmount = zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT);
3109		if (canmount == ZFS_CANMOUNT_OFF) {
3110			if (!explicit)
3111				return (0);
3112
3113			(void) fprintf(stderr, gettext("cannot %s '%s': "
3114			    "'canmount' property is set to 'off'\n"), cmdname,
3115			    zfs_get_name(zhp));
3116			return (1);
3117		} else if (canmount == ZFS_CANMOUNT_NOAUTO && !explicit) {
3118			return (0);
3119		}
3120
3121		/*
3122		 * At this point, we have verified that the mountpoint and/or
3123		 * shareopts are appropriate for auto management. If the
3124		 * filesystem is already mounted or shared, return (failing
3125		 * for explicit requests); otherwise mount or share the
3126		 * filesystem.
3127		 */
3128		switch (op) {
3129		case OP_SHARE:
3130
3131			shared_nfs = zfs_is_shared_nfs(zhp, NULL);
3132			shared_smb = zfs_is_shared_smb(zhp, NULL);
3133
3134			if (shared_nfs && shared_smb ||
3135			    (shared_nfs && strcmp(shareopts, "on") == 0 &&
3136			    strcmp(smbshareopts, "off") == 0) ||
3137			    (shared_smb && strcmp(smbshareopts, "on") == 0 &&
3138			    strcmp(shareopts, "off") == 0)) {
3139				if (!explicit)
3140					return (0);
3141
3142				(void) fprintf(stderr, gettext("cannot share "
3143				    "'%s': filesystem already shared\n"),
3144				    zfs_get_name(zhp));
3145				return (1);
3146			}
3147
3148			if (!zfs_is_mounted(zhp, NULL) &&
3149			    zfs_mount(zhp, NULL, 0) != 0)
3150				return (1);
3151
3152			if (protocol == NULL) {
3153				if (zfs_shareall(zhp) != 0)
3154					return (1);
3155			} else if (strcmp(protocol, "nfs") == 0) {
3156				if (zfs_share_nfs(zhp))
3157					return (1);
3158			} else if (strcmp(protocol, "smb") == 0) {
3159				if (zfs_share_smb(zhp))
3160					return (1);
3161			} else {
3162				(void) fprintf(stderr, gettext("cannot share "
3163				    "'%s': invalid share type '%s' "
3164				    "specified\n"),
3165				    zfs_get_name(zhp), protocol);
3166				return (1);
3167			}
3168
3169			break;
3170
3171		case OP_MOUNT:
3172			if (options == NULL)
3173				mnt.mnt_mntopts = "";
3174			else
3175				mnt.mnt_mntopts = (char *)options;
3176
3177			if (!hasmntopt(&mnt, MNTOPT_REMOUNT) &&
3178			    zfs_is_mounted(zhp, NULL)) {
3179				if (!explicit)
3180					return (0);
3181
3182				(void) fprintf(stderr, gettext("cannot mount "
3183				    "'%s': filesystem already mounted\n"),
3184				    zfs_get_name(zhp));
3185				return (1);
3186			}
3187
3188			if (zfs_mount(zhp, options, flags) != 0)
3189				return (1);
3190			break;
3191		}
3192	} else {
3193		assert(op == OP_SHARE);
3194
3195		/*
3196		 * Ignore any volumes that aren't shared.
3197		 */
3198		verify(zfs_prop_get(zhp, ZFS_PROP_SHAREISCSI, shareopts,
3199		    sizeof (shareopts), NULL, NULL, 0, B_FALSE) == 0);
3200
3201		if (strcmp(shareopts, "off") == 0) {
3202			if (!explicit)
3203				return (0);
3204
3205			(void) fprintf(stderr, gettext("cannot share '%s': "
3206			    "'shareiscsi' property not set\n"),
3207			    zfs_get_name(zhp));
3208			(void) fprintf(stderr, gettext("set 'shareiscsi' "
3209			    "property or use iscsitadm(1M) to share this "
3210			    "volume\n"));
3211			return (1);
3212		}
3213
3214		if (zfs_is_shared_iscsi(zhp)) {
3215			if (!explicit)
3216				return (0);
3217
3218			(void) fprintf(stderr, gettext("cannot share "
3219			    "'%s': volume already shared\n"),
3220			    zfs_get_name(zhp));
3221			return (1);
3222		}
3223
3224		if (zfs_share_iscsi(zhp) != 0)
3225			return (1);
3226	}
3227
3228	return (0);
3229}
3230
3231/*
3232 * Reports progress in the form "(current/total)".  Not thread-safe.
3233 */
3234static void
3235report_mount_progress(int current, int total)
3236{
3237	static int len;
3238	static char *reverse = "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"
3239	    "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b";
3240	static time_t last_progress_time;
3241	time_t now = time(NULL);
3242
3243	/* report 1..n instead of 0..n-1 */
3244	++current;
3245
3246	/* display header if we're here for the first time */
3247	if (current == 1) {
3248		(void) printf(gettext("Mounting ZFS filesystems: "));
3249		len = 0;
3250	} else if (current != total && last_progress_time + MOUNT_TIME >= now) {
3251		/* too soon to report again */
3252		return;
3253	}
3254
3255	last_progress_time = now;
3256
3257	/* back up to prepare for overwriting */
3258	if (len)
3259		(void) printf("%*.*s", len, len, reverse);
3260
3261	/* We put a newline at the end if this is the last one.  */
3262	len = printf("(%d/%d)%s", current, total, current == total ? "\n" : "");
3263	(void) fflush(stdout);
3264}
3265
3266static void
3267append_options(char *mntopts, char *newopts)
3268{
3269	int len = strlen(mntopts);
3270
3271	/* original length plus new string to append plus 1 for the comma */
3272	if (len + 1 + strlen(newopts) >= MNT_LINE_MAX) {
3273		(void) fprintf(stderr, gettext("the opts argument for "
3274		    "'%c' option is too long (more than %d chars)\n"),
3275		    "-o", MNT_LINE_MAX);
3276		usage(B_FALSE);
3277	}
3278
3279	if (*mntopts)
3280		mntopts[len++] = ',';
3281
3282	(void) strcpy(&mntopts[len], newopts);
3283}
3284
3285static int
3286share_mount(int op, int argc, char **argv)
3287{
3288	int do_all = 0;
3289	boolean_t verbose = B_FALSE;
3290	int c, ret = 0;
3291	char *options = NULL;
3292	int types, flags = 0;
3293
3294	/* check options */
3295	while ((c = getopt(argc, argv, op == OP_MOUNT ? ":avo:O" : "a"))
3296	    != -1) {
3297		switch (c) {
3298		case 'a':
3299			do_all = 1;
3300			break;
3301		case 'v':
3302			verbose = B_TRUE;
3303			break;
3304		case 'o':
3305			if (*optarg == '\0') {
3306				(void) fprintf(stderr, gettext("empty mount "
3307				    "options (-o) specified\n"));
3308				usage(B_FALSE);
3309			}
3310
3311			if (options == NULL)
3312				options = safe_malloc(MNT_LINE_MAX + 1);
3313
3314			/* option validation is done later */
3315			append_options(options, optarg);
3316			break;
3317
3318		case 'O':
3319			flags |= MS_OVERLAY;
3320			break;
3321		case ':':
3322			(void) fprintf(stderr, gettext("missing argument for "
3323			    "'%c' option\n"), optopt);
3324			usage(B_FALSE);
3325			break;
3326		case '?':
3327			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3328			    optopt);
3329			usage(B_FALSE);
3330		}
3331	}
3332
3333	argc -= optind;
3334	argv += optind;
3335
3336	/* check number of arguments */
3337	if (do_all) {
3338		zfs_handle_t **dslist = NULL;
3339		size_t i, count = 0;
3340		char *protocol = NULL;
3341
3342		if (op == OP_MOUNT) {
3343			types = ZFS_TYPE_FILESYSTEM;
3344		} else if (argc > 0) {
3345			if (strcmp(argv[0], "nfs") == 0 ||
3346			    strcmp(argv[0], "smb") == 0) {
3347				types = ZFS_TYPE_FILESYSTEM;
3348			} else if (strcmp(argv[0], "iscsi") == 0) {
3349				types = ZFS_TYPE_VOLUME;
3350			} else {
3351				(void) fprintf(stderr, gettext("share type "
3352				    "must be 'nfs', 'smb' or 'iscsi'\n"));
3353				usage(B_FALSE);
3354			}
3355			protocol = argv[0];
3356			argc--;
3357			argv++;
3358		} else {
3359			types = ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME;
3360		}
3361
3362		if (argc != 0) {
3363			(void) fprintf(stderr, gettext("too many arguments\n"));
3364			usage(B_FALSE);
3365		}
3366
3367		get_all_datasets(types, &dslist, &count, verbose);
3368
3369		if (count == 0)
3370			return (0);
3371
3372		qsort(dslist, count, sizeof (void *), dataset_cmp);
3373
3374		for (i = 0; i < count; i++) {
3375			if (verbose)
3376				report_mount_progress(i, count);
3377
3378			if (share_mount_one(dslist[i], op, flags, protocol,
3379			    B_FALSE, options) != 0)
3380				ret = 1;
3381			zfs_close(dslist[i]);
3382		}
3383
3384		free(dslist);
3385	} else if (argc == 0) {
3386		struct statvfs *sfs;
3387		int i, n;
3388
3389		if ((op == OP_SHARE) || (options != NULL)) {
3390			(void) fprintf(stderr, gettext("missing filesystem "
3391			    "argument (specify -a for all)\n"));
3392			usage(B_FALSE);
3393		}
3394
3395		/*
3396		 * When mount is given no arguments, go through /etc/mnttab and
3397		 * display any active ZFS mounts.  We hide any snapshots, since
3398		 * they are controlled automatically.
3399		 */
3400                if ((n = getmntinfo(&sfs, MNT_WAIT)) == 0) {
3401			fprintf(stderr, "getmntinfo(): %s\n", strerror(errno));
3402                        return (0);
3403		}
3404		for (i = 0; i < n; i++) {
3405			if (strcmp(sfs[i].f_fstypename, MNTTYPE_ZFS) != 0 ||
3406			    strchr(sfs[i].f_mntfromname, '@') != NULL)
3407				continue;
3408
3409			(void) printf("%-30s  %s\n", sfs[i].f_mntfromname,
3410			    sfs[i].f_mntonname);
3411		}
3412
3413	} else {
3414		zfs_handle_t *zhp;
3415
3416		types = ZFS_TYPE_FILESYSTEM;
3417		if (op == OP_SHARE)
3418			types |= ZFS_TYPE_VOLUME;
3419
3420		if (argc > 1) {
3421			(void) fprintf(stderr,
3422			    gettext("too many arguments\n"));
3423			usage(B_FALSE);
3424		}
3425
3426		if ((zhp = zfs_open(g_zfs, argv[0], types)) == NULL) {
3427			ret = 1;
3428		} else {
3429			ret = share_mount_one(zhp, op, flags, NULL, B_TRUE,
3430			    options);
3431			zfs_close(zhp);
3432		}
3433	}
3434
3435	return (ret);
3436}
3437
3438/*
3439 * zfs mount -a [nfs | iscsi]
3440 * zfs mount filesystem
3441 *
3442 * Mount all filesystems, or mount the given filesystem.
3443 */
3444static int
3445zfs_do_mount(int argc, char **argv)
3446{
3447	return (share_mount(OP_MOUNT, argc, argv));
3448}
3449
3450/*
3451 * zfs share -a [nfs | iscsi | smb]
3452 * zfs share filesystem
3453 *
3454 * Share all filesystems, or share the given filesystem.
3455 */
3456static int
3457zfs_do_share(int argc, char **argv)
3458{
3459	return (share_mount(OP_SHARE, argc, argv));
3460}
3461
3462typedef struct unshare_unmount_node {
3463	zfs_handle_t	*un_zhp;
3464	char		*un_mountp;
3465	uu_avl_node_t	un_avlnode;
3466} unshare_unmount_node_t;
3467
3468/* ARGSUSED */
3469static int
3470unshare_unmount_compare(const void *larg, const void *rarg, void *unused)
3471{
3472	const unshare_unmount_node_t *l = larg;
3473	const unshare_unmount_node_t *r = rarg;
3474
3475	return (strcmp(l->un_mountp, r->un_mountp));
3476}
3477
3478/*
3479 * Convenience routine used by zfs_do_umount() and manual_unmount().  Given an
3480 * absolute path, find the entry /etc/mnttab, verify that its a ZFS filesystem,
3481 * and unmount it appropriately.
3482 */
3483static int
3484unshare_unmount_path(int op, char *path, int flags, boolean_t is_manual)
3485{
3486	zfs_handle_t *zhp;
3487	int ret;
3488	struct stat64 statbuf;
3489	struct mnttab entry, search = { 0 };
3490	const char *cmdname = (op == OP_SHARE) ? "unshare" : "unmount";
3491	ino_t path_inode;
3492
3493	/*
3494	 * Search for the path in /etc/mnttab.  Rather than looking for the
3495	 * specific path, which can be fooled by non-standard paths (i.e. ".."
3496	 * or "//"), we stat() the path and search for the corresponding
3497	 * (major,minor) device pair.
3498	 */
3499	if (stat64(path, &statbuf) != 0) {
3500		(void) fprintf(stderr, gettext("cannot %s '%s': %s\n"),
3501		    cmdname, path, strerror(errno));
3502		return (1);
3503	}
3504	path_inode = statbuf.st_ino;
3505
3506	/*
3507	 * Search for the given (major,minor) pair in the mount table.
3508	 */
3509	rewind(mnttab_file);
3510	search.mnt_mountp = path;
3511	if ((ret = getmntany(mnttab_file, &entry, &search)) == 0) {
3512		if (op == OP_SHARE) {
3513			(void) fprintf(stderr, gettext("cannot %s '%s': not "
3514			    "currently mounted\n"), cmdname, path);
3515			return (1);
3516		}
3517		(void) fprintf(stderr, gettext("warning: %s not in mnttab\n"),
3518		    path);
3519		if ((ret = umount2(path, flags)) != 0)
3520			(void) fprintf(stderr, gettext("%s: %s\n"), path,
3521			    strerror(errno));
3522		return (ret != 0);
3523	}
3524
3525	if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0) {
3526		(void) fprintf(stderr, gettext("cannot %s '%s': not a ZFS "
3527		    "filesystem\n"), cmdname, path);
3528		return (1);
3529	}
3530
3531	if ((zhp = zfs_open(g_zfs, entry.mnt_special,
3532	    ZFS_TYPE_FILESYSTEM)) == NULL)
3533		return (1);
3534
3535	ret = 1;
3536	if (stat64(entry.mnt_mountp, &statbuf) != 0) {
3537		(void) fprintf(stderr, gettext("cannot %s '%s': %s\n"),
3538		    cmdname, path, strerror(errno));
3539		goto out;
3540	} else if (statbuf.st_ino != path_inode) {
3541		(void) fprintf(stderr, gettext("cannot "
3542		    "%s '%s': not a mountpoint\n"), cmdname, path);
3543		goto out;
3544	}
3545
3546	if (op == OP_SHARE) {
3547		char nfs_mnt_prop[ZFS_MAXPROPLEN];
3548		char smbshare_prop[ZFS_MAXPROPLEN];
3549
3550		verify(zfs_prop_get(zhp, ZFS_PROP_SHARENFS, nfs_mnt_prop,
3551		    sizeof (nfs_mnt_prop), NULL, NULL, 0, B_FALSE) == 0);
3552		verify(zfs_prop_get(zhp, ZFS_PROP_SHARESMB, smbshare_prop,
3553		    sizeof (smbshare_prop), NULL, NULL, 0, B_FALSE) == 0);
3554
3555		if (strcmp(nfs_mnt_prop, "off") == 0 &&
3556		    strcmp(smbshare_prop, "off") == 0) {
3557			(void) fprintf(stderr, gettext("cannot unshare "
3558			    "'%s': legacy share\n"), path);
3559			(void) fprintf(stderr, gettext("use "
3560			    "unshare(1M) to unshare this filesystem\n"));
3561		} else if (!zfs_is_shared(zhp)) {
3562			(void) fprintf(stderr, gettext("cannot unshare '%s': "
3563			    "not currently shared\n"), path);
3564		} else {
3565			ret = zfs_unshareall_bypath(zhp, path);
3566		}
3567	} else {
3568		char mtpt_prop[ZFS_MAXPROPLEN];
3569
3570		verify(zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mtpt_prop,
3571		    sizeof (mtpt_prop), NULL, NULL, 0, B_FALSE) == 0);
3572
3573		if (is_manual) {
3574			ret = zfs_unmount(zhp, NULL, flags);
3575		} else if (strcmp(mtpt_prop, "legacy") == 0) {
3576			(void) fprintf(stderr, gettext("cannot unmount "
3577			    "'%s': legacy mountpoint\n"),
3578			    zfs_get_name(zhp));
3579			(void) fprintf(stderr, gettext("use umount(1M) "
3580			    "to unmount this filesystem\n"));
3581		} else {
3582			ret = zfs_unmountall(zhp, flags);
3583		}
3584	}
3585
3586out:
3587	zfs_close(zhp);
3588
3589	return (ret != 0);
3590}
3591
3592/*
3593 * Generic callback for unsharing or unmounting a filesystem.
3594 */
3595static int
3596unshare_unmount(int op, int argc, char **argv)
3597{
3598	int do_all = 0;
3599	int flags = 0;
3600	int ret = 0;
3601	int types, c;
3602	zfs_handle_t *zhp;
3603	char nfsiscsi_mnt_prop[ZFS_MAXPROPLEN];
3604	char sharesmb[ZFS_MAXPROPLEN];
3605
3606	/* check options */
3607	while ((c = getopt(argc, argv, op == OP_SHARE ? "a" : "af")) != -1) {
3608		switch (c) {
3609		case 'a':
3610			do_all = 1;
3611			break;
3612		case 'f':
3613			flags = MS_FORCE;
3614			break;
3615		case '?':
3616			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3617			    optopt);
3618			usage(B_FALSE);
3619		}
3620	}
3621
3622	argc -= optind;
3623	argv += optind;
3624
3625	if (do_all) {
3626		/*
3627		 * We could make use of zfs_for_each() to walk all datasets in
3628		 * the system, but this would be very inefficient, especially
3629		 * since we would have to linearly search /etc/mnttab for each
3630		 * one.  Instead, do one pass through /etc/mnttab looking for
3631		 * zfs entries and call zfs_unmount() for each one.
3632		 *
3633		 * Things get a little tricky if the administrator has created
3634		 * mountpoints beneath other ZFS filesystems.  In this case, we
3635		 * have to unmount the deepest filesystems first.  To accomplish
3636		 * this, we place all the mountpoints in an AVL tree sorted by
3637		 * the special type (dataset name), and walk the result in
3638		 * reverse to make sure to get any snapshots first.
3639		 */
3640		struct statvfs *sfs;
3641		int i, n;
3642		uu_avl_pool_t *pool;
3643		uu_avl_t *tree;
3644		unshare_unmount_node_t *node;
3645		uu_avl_index_t idx;
3646		uu_avl_walk_t *walk;
3647
3648		if (argc != 0) {
3649			(void) fprintf(stderr, gettext("too many arguments\n"));
3650			usage(B_FALSE);
3651		}
3652
3653		if ((pool = uu_avl_pool_create("unmount_pool",
3654		    sizeof (unshare_unmount_node_t),
3655		    offsetof(unshare_unmount_node_t, un_avlnode),
3656		    unshare_unmount_compare,
3657		    UU_DEFAULT)) == NULL) {
3658			(void) fprintf(stderr, gettext("internal error: "
3659			    "out of memory\n"));
3660			exit(1);
3661		}
3662
3663		if ((tree = uu_avl_create(pool, NULL, UU_DEFAULT)) == NULL) {
3664			(void) fprintf(stderr, gettext("internal error: "
3665			    "out of memory\n"));
3666			exit(1);
3667		}
3668
3669		rewind(mnttab_file);
3670		if ((n = getmntinfo(&sfs, MNT_WAIT)) == 0) {
3671			(void) fprintf(stderr, gettext("internal error: "
3672			    "getmntinfo() failed\n"));
3673			exit(1);
3674		}
3675                for (i = 0; i < n; i++) {
3676
3677			/* ignore non-ZFS entries */
3678			if (strcmp(sfs[i].f_fstypename, MNTTYPE_ZFS) != 0)
3679				continue;
3680
3681			/* ignore snapshots */
3682			if (strchr(sfs[i].f_mntfromname, '@') != NULL)
3683				continue;
3684
3685			if ((zhp = zfs_open(g_zfs, sfs[i].f_mntfromname,
3686			    ZFS_TYPE_FILESYSTEM)) == NULL) {
3687				ret = 1;
3688				continue;
3689			}
3690
3691			switch (op) {
3692			case OP_SHARE:
3693				verify(zfs_prop_get(zhp, ZFS_PROP_SHARENFS,
3694				    nfsiscsi_mnt_prop,
3695				    sizeof (nfsiscsi_mnt_prop),
3696				    NULL, NULL, 0, B_FALSE) == 0);
3697				if (strcmp(nfsiscsi_mnt_prop, "off") != 0)
3698					break;
3699				verify(zfs_prop_get(zhp, ZFS_PROP_SHARESMB,
3700				    nfsiscsi_mnt_prop,
3701				    sizeof (nfsiscsi_mnt_prop),
3702				    NULL, NULL, 0, B_FALSE) == 0);
3703				if (strcmp(nfsiscsi_mnt_prop, "off") == 0)
3704					continue;
3705				break;
3706			case OP_MOUNT:
3707				/* Ignore legacy mounts */
3708				verify(zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT,
3709				    nfsiscsi_mnt_prop,
3710				    sizeof (nfsiscsi_mnt_prop),
3711				    NULL, NULL, 0, B_FALSE) == 0);
3712				if (strcmp(nfsiscsi_mnt_prop, "legacy") == 0)
3713					continue;
3714				/* Ignore canmount=noauto mounts */
3715				if (zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT) ==
3716				    ZFS_CANMOUNT_NOAUTO)
3717					continue;
3718			default:
3719				break;
3720			}
3721
3722			node = safe_malloc(sizeof (unshare_unmount_node_t));
3723			node->un_zhp = zhp;
3724
3725			if ((node->un_mountp = strdup(sfs[i].f_mntonname)) ==
3726			    NULL) {
3727				(void) fprintf(stderr, gettext("internal error:"
3728				    " out of memory\n"));
3729				exit(1);
3730			}
3731
3732			uu_avl_node_init(node, &node->un_avlnode, pool);
3733
3734			if (uu_avl_find(tree, node, NULL, &idx) == NULL) {
3735				uu_avl_insert(tree, node, idx);
3736			} else {
3737				zfs_close(node->un_zhp);
3738				free(node->un_mountp);
3739				free(node);
3740			}
3741		}
3742
3743		/*
3744		 * Walk the AVL tree in reverse, unmounting each filesystem and
3745		 * removing it from the AVL tree in the process.
3746		 */
3747		if ((walk = uu_avl_walk_start(tree,
3748		    UU_WALK_REVERSE | UU_WALK_ROBUST)) == NULL) {
3749			(void) fprintf(stderr,
3750			    gettext("internal error: out of memory"));
3751			exit(1);
3752		}
3753
3754		while ((node = uu_avl_walk_next(walk)) != NULL) {
3755			uu_avl_remove(tree, node);
3756
3757			switch (op) {
3758			case OP_SHARE:
3759				if (zfs_unshareall_bypath(node->un_zhp,
3760				    node->un_mountp) != 0)
3761					ret = 1;
3762				break;
3763
3764			case OP_MOUNT:
3765				if (zfs_unmount(node->un_zhp,
3766				    node->un_mountp, flags) != 0)
3767					ret = 1;
3768				break;
3769			}
3770
3771			zfs_close(node->un_zhp);
3772			free(node->un_mountp);
3773			free(node);
3774		}
3775
3776		uu_avl_walk_end(walk);
3777		uu_avl_destroy(tree);
3778		uu_avl_pool_destroy(pool);
3779
3780		if (op == OP_SHARE) {
3781			/*
3782			 * Finally, unshare any volumes shared via iSCSI.
3783			 */
3784			zfs_handle_t **dslist = NULL;
3785			size_t i, count = 0;
3786
3787			get_all_datasets(ZFS_TYPE_VOLUME, &dslist, &count,
3788			    B_FALSE);
3789
3790			if (count != 0) {
3791				qsort(dslist, count, sizeof (void *),
3792				    dataset_cmp);
3793
3794				for (i = 0; i < count; i++) {
3795					if (zfs_unshare_iscsi(dslist[i]) != 0)
3796						ret = 1;
3797					zfs_close(dslist[i]);
3798				}
3799
3800				free(dslist);
3801			}
3802		}
3803	} else {
3804		if (argc != 1) {
3805			if (argc == 0)
3806				(void) fprintf(stderr,
3807				    gettext("missing filesystem argument\n"));
3808			else
3809				(void) fprintf(stderr,
3810				    gettext("too many arguments\n"));
3811			usage(B_FALSE);
3812		}
3813
3814		/*
3815		 * We have an argument, but it may be a full path or a ZFS
3816		 * filesystem.  Pass full paths off to unmount_path() (shared by
3817		 * manual_unmount), otherwise open the filesystem and pass to
3818		 * zfs_unmount().
3819		 */
3820		if (argv[0][0] == '/')
3821			return (unshare_unmount_path(op, argv[0],
3822			    flags, B_FALSE));
3823
3824		types = ZFS_TYPE_FILESYSTEM;
3825		if (op == OP_SHARE)
3826			types |= ZFS_TYPE_VOLUME;
3827
3828		if ((zhp = zfs_open(g_zfs, argv[0], types)) == NULL)
3829			return (1);
3830
3831		if (zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) {
3832			verify(zfs_prop_get(zhp, op == OP_SHARE ?
3833			    ZFS_PROP_SHARENFS : ZFS_PROP_MOUNTPOINT,
3834			    nfsiscsi_mnt_prop, sizeof (nfsiscsi_mnt_prop), NULL,
3835			    NULL, 0, B_FALSE) == 0);
3836
3837			switch (op) {
3838			case OP_SHARE:
3839				verify(zfs_prop_get(zhp, ZFS_PROP_SHARENFS,
3840				    nfsiscsi_mnt_prop,
3841				    sizeof (nfsiscsi_mnt_prop),
3842				    NULL, NULL, 0, B_FALSE) == 0);
3843				verify(zfs_prop_get(zhp, ZFS_PROP_SHARESMB,
3844				    sharesmb, sizeof (sharesmb), NULL, NULL,
3845				    0, B_FALSE) == 0);
3846
3847				if (strcmp(nfsiscsi_mnt_prop, "off") == 0 &&
3848				    strcmp(sharesmb, "off") == 0) {
3849					(void) fprintf(stderr, gettext("cannot "
3850					    "unshare '%s': legacy share\n"),
3851					    zfs_get_name(zhp));
3852					(void) fprintf(stderr, gettext("use "
3853					    "unshare(1M) to unshare this "
3854					    "filesystem\n"));
3855					ret = 1;
3856				} else if (!zfs_is_shared(zhp)) {
3857					(void) fprintf(stderr, gettext("cannot "
3858					    "unshare '%s': not currently "
3859					    "shared\n"), zfs_get_name(zhp));
3860					ret = 1;
3861				} else if (zfs_unshareall(zhp) != 0) {
3862					ret = 1;
3863				}
3864				break;
3865
3866			case OP_MOUNT:
3867				if (strcmp(nfsiscsi_mnt_prop, "legacy") == 0) {
3868					(void) fprintf(stderr, gettext("cannot "
3869					    "unmount '%s': legacy "
3870					    "mountpoint\n"), zfs_get_name(zhp));
3871					(void) fprintf(stderr, gettext("use "
3872					    "umount(1M) to unmount this "
3873					    "filesystem\n"));
3874					ret = 1;
3875				} else if (!zfs_is_mounted(zhp, NULL)) {
3876					(void) fprintf(stderr, gettext("cannot "
3877					    "unmount '%s': not currently "
3878					    "mounted\n"),
3879					    zfs_get_name(zhp));
3880					ret = 1;
3881				} else if (zfs_unmountall(zhp, flags) != 0) {
3882					ret = 1;
3883				}
3884				break;
3885			}
3886		} else {
3887			assert(op == OP_SHARE);
3888
3889			verify(zfs_prop_get(zhp, ZFS_PROP_SHAREISCSI,
3890			    nfsiscsi_mnt_prop, sizeof (nfsiscsi_mnt_prop),
3891			    NULL, NULL, 0, B_FALSE) == 0);
3892
3893			if (strcmp(nfsiscsi_mnt_prop, "off") == 0) {
3894				(void) fprintf(stderr, gettext("cannot unshare "
3895				    "'%s': 'shareiscsi' property not set\n"),
3896				    zfs_get_name(zhp));
3897				(void) fprintf(stderr, gettext("set "
3898				    "'shareiscsi' property or use "
3899				    "iscsitadm(1M) to share this volume\n"));
3900				ret = 1;
3901			} else if (!zfs_is_shared_iscsi(zhp)) {
3902				(void) fprintf(stderr, gettext("cannot "
3903				    "unshare '%s': not currently shared\n"),
3904				    zfs_get_name(zhp));
3905				ret = 1;
3906			} else if (zfs_unshare_iscsi(zhp) != 0) {
3907				ret = 1;
3908			}
3909		}
3910
3911		zfs_close(zhp);
3912	}
3913
3914	return (ret);
3915}
3916
3917/*
3918 * zfs unmount -a
3919 * zfs unmount filesystem
3920 *
3921 * Unmount all filesystems, or a specific ZFS filesystem.
3922 */
3923static int
3924zfs_do_unmount(int argc, char **argv)
3925{
3926	return (unshare_unmount(OP_MOUNT, argc, argv));
3927}
3928
3929/*
3930 * zfs unshare -a
3931 * zfs unshare filesystem
3932 *
3933 * Unshare all filesystems, or a specific ZFS filesystem.
3934 */
3935static int
3936zfs_do_unshare(int argc, char **argv)
3937{
3938	return (unshare_unmount(OP_SHARE, argc, argv));
3939}
3940
3941/* ARGSUSED */
3942static int
3943zfs_do_python(int argc, char **argv)
3944{
3945	(void) execv(pypath, argv-1);
3946	(void) printf("internal error: %s not found\n", pypath);
3947	return (-1);
3948}
3949
3950/*
3951 * Called when invoked as /etc/fs/zfs/mount.  Do the mount if the mountpoint is
3952 * 'legacy'.  Otherwise, complain that use should be using 'zfs mount'.
3953 */
3954static int
3955manual_mount(int argc, char **argv)
3956{
3957	zfs_handle_t *zhp;
3958	char mountpoint[ZFS_MAXPROPLEN];
3959	char mntopts[MNT_LINE_MAX] = { '\0' };
3960	int ret;
3961	int c;
3962	int flags = 0;
3963	char *dataset, *path;
3964
3965	/* check options */
3966	while ((c = getopt(argc, argv, ":mo:O")) != -1) {
3967		switch (c) {
3968		case 'o':
3969			(void) strlcpy(mntopts, optarg, sizeof (mntopts));
3970			break;
3971		case 'O':
3972			flags |= MS_OVERLAY;
3973			break;
3974		case 'm':
3975			flags |= MS_NOMNTTAB;
3976			break;
3977		case ':':
3978			(void) fprintf(stderr, gettext("missing argument for "
3979			    "'%c' option\n"), optopt);
3980			usage(B_FALSE);
3981			break;
3982		case '?':
3983			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3984			    optopt);
3985			(void) fprintf(stderr, gettext("usage: mount [-o opts] "
3986			    "<path>\n"));
3987			return (2);
3988		}
3989	}
3990
3991	argc -= optind;
3992	argv += optind;
3993
3994	/* check that we only have two arguments */
3995	if (argc != 2) {
3996		if (argc == 0)
3997			(void) fprintf(stderr, gettext("missing dataset "
3998			    "argument\n"));
3999		else if (argc == 1)
4000			(void) fprintf(stderr,
4001			    gettext("missing mountpoint argument\n"));
4002		else
4003			(void) fprintf(stderr, gettext("too many arguments\n"));
4004		(void) fprintf(stderr, "usage: mount <dataset> <mountpoint>\n");
4005		return (2);
4006	}
4007
4008	dataset = argv[0];
4009	path = argv[1];
4010
4011	/* try to open the dataset */
4012	if ((zhp = zfs_open(g_zfs, dataset, ZFS_TYPE_FILESYSTEM)) == NULL)
4013		return (1);
4014
4015	(void) zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint,
4016	    sizeof (mountpoint), NULL, NULL, 0, B_FALSE);
4017
4018	/* check for legacy mountpoint and complain appropriately */
4019	ret = 0;
4020	if (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0) {
4021		if (mount(dataset, path, MS_OPTIONSTR | flags, MNTTYPE_ZFS,
4022		    NULL, 0, mntopts, sizeof (mntopts)) != 0) {
4023			(void) fprintf(stderr, gettext("mount failed: %s\n"),
4024			    strerror(errno));
4025			ret = 1;
4026		}
4027	} else {
4028		(void) fprintf(stderr, gettext("filesystem '%s' cannot be "
4029		    "mounted using 'mount -F zfs'\n"), dataset);
4030		(void) fprintf(stderr, gettext("Use 'zfs set mountpoint=%s' "
4031		    "instead.\n"), path);
4032		(void) fprintf(stderr, gettext("If you must use 'mount -F zfs' "
4033		    "or /etc/vfstab, use 'zfs set mountpoint=legacy'.\n"));
4034		(void) fprintf(stderr, gettext("See zfs(1M) for more "
4035		    "information.\n"));
4036		ret = 1;
4037	}
4038
4039	return (ret);
4040}
4041
4042/*
4043 * Called when invoked as /etc/fs/zfs/umount.  Unlike a manual mount, we allow
4044 * unmounts of non-legacy filesystems, as this is the dominant administrative
4045 * interface.
4046 */
4047static int
4048manual_unmount(int argc, char **argv)
4049{
4050	int flags = 0;
4051	int c;
4052
4053	/* check options */
4054	while ((c = getopt(argc, argv, "f")) != -1) {
4055		switch (c) {
4056		case 'f':
4057			flags = MS_FORCE;
4058			break;
4059		case '?':
4060			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
4061			    optopt);
4062			(void) fprintf(stderr, gettext("usage: unmount [-f] "
4063			    "<path>\n"));
4064			return (2);
4065		}
4066	}
4067
4068	argc -= optind;
4069	argv += optind;
4070
4071	/* check arguments */
4072	if (argc != 1) {
4073		if (argc == 0)
4074			(void) fprintf(stderr, gettext("missing path "
4075			    "argument\n"));
4076		else
4077			(void) fprintf(stderr, gettext("too many arguments\n"));
4078		(void) fprintf(stderr, gettext("usage: unmount [-f] <path>\n"));
4079		return (2);
4080	}
4081
4082	return (unshare_unmount_path(OP_MOUNT, argv[0], flags, B_TRUE));
4083}
4084
4085static int
4086find_command_idx(char *command, int *idx)
4087{
4088	int i;
4089
4090	for (i = 0; i < NCOMMAND; i++) {
4091		if (command_table[i].name == NULL)
4092			continue;
4093
4094		if (strcmp(command, command_table[i].name) == 0) {
4095			*idx = i;
4096			return (0);
4097		}
4098	}
4099	return (1);
4100}
4101
4102int
4103main(int argc, char **argv)
4104{
4105	int ret;
4106	int i;
4107	char *progname;
4108	char *cmdname;
4109
4110	(void) setlocale(LC_ALL, "");
4111	(void) textdomain(TEXT_DOMAIN);
4112
4113	opterr = 0;
4114
4115	if ((g_zfs = libzfs_init()) == NULL) {
4116		(void) fprintf(stderr, gettext("internal error: failed to "
4117		    "initialize ZFS library\n"));
4118		return (1);
4119	}
4120
4121	zpool_set_history_str("zfs", argc, argv, history_str);
4122	verify(zpool_stage_history(g_zfs, history_str) == 0);
4123
4124	libzfs_print_on_error(g_zfs, B_TRUE);
4125
4126	if ((mnttab_file = fopen(MNTTAB, "r")) == NULL) {
4127		(void) fprintf(stderr, gettext("internal error: unable to "
4128		    "open %s\n"), MNTTAB);
4129		return (1);
4130	}
4131
4132	/*
4133	 * This command also doubles as the /etc/fs mount and unmount program.
4134	 * Determine if we should take this behavior based on argv[0].
4135	 */
4136	progname = basename(argv[0]);
4137	if (strcmp(progname, "mount") == 0) {
4138		ret = manual_mount(argc, argv);
4139	} else if (strcmp(progname, "umount") == 0) {
4140		ret = manual_unmount(argc, argv);
4141	} else {
4142		/*
4143		 * Make sure the user has specified some command.
4144		 */
4145		if (argc < 2) {
4146			(void) fprintf(stderr, gettext("missing command\n"));
4147			usage(B_FALSE);
4148		}
4149
4150		cmdname = argv[1];
4151
4152		/*
4153		 * The 'umount' command is an alias for 'unmount'
4154		 */
4155		if (strcmp(cmdname, "umount") == 0)
4156			cmdname = "unmount";
4157
4158		/*
4159		 * The 'recv' command is an alias for 'receive'
4160		 */
4161		if (strcmp(cmdname, "recv") == 0)
4162			cmdname = "receive";
4163
4164		/*
4165		 * Special case '-?'
4166		 */
4167		if (strcmp(cmdname, "-?") == 0)
4168			usage(B_TRUE);
4169
4170		/*
4171		 * Run the appropriate command.
4172		 */
4173		libzfs_mnttab_cache(g_zfs, B_TRUE);
4174		if (find_command_idx(cmdname, &i) == 0) {
4175			current_command = &command_table[i];
4176			ret = command_table[i].func(argc - 1, argv + 1);
4177		} else if (strchr(cmdname, '=') != NULL) {
4178			verify(find_command_idx("set", &i) == 0);
4179			current_command = &command_table[i];
4180			ret = command_table[i].func(argc, argv);
4181		} else {
4182			(void) fprintf(stderr, gettext("unrecognized "
4183			    "command '%s'\n"), cmdname);
4184			usage(B_FALSE);
4185		}
4186		libzfs_mnttab_cache(g_zfs, B_FALSE);
4187	}
4188
4189	(void) fclose(mnttab_file);
4190
4191	libzfs_fini(g_zfs);
4192
4193	/*
4194	 * The 'ZFS_ABORT' environment variable causes us to dump core on exit
4195	 * for the purposes of running ::findleaks.
4196	 */
4197	if (getenv("ZFS_ABORT") != NULL) {
4198		(void) printf("dumping core by request\n");
4199		abort();
4200	}
4201
4202	return (ret);
4203}
4204