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