zfs_main.c revision 240955
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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
25 * Copyright (c) 2012 by Delphix. All rights reserved.
26 * Copyright 2012 Milan Jurik. All rights reserved.
27 * Copyright (c) 2012, Joyent, Inc. All rights reserved.
28 * Copyright (c) 2011-2012 Pawel Jakub Dawidek <pawel@dawidek.net>.
29 * All rights reserved.
30 * Copyright (c) 2012 Martin Matuska <mm@FreeBSD.org>. All rights reserved.
31 */
32
33#include <assert.h>
34#include <ctype.h>
35#include <errno.h>
36#include <libgen.h>
37#include <libintl.h>
38#include <libuutil.h>
39#include <libnvpair.h>
40#include <locale.h>
41#include <stddef.h>
42#include <stdio.h>
43#include <stdlib.h>
44#include <strings.h>
45#include <unistd.h>
46#include <fcntl.h>
47#include <zone.h>
48#include <grp.h>
49#include <pwd.h>
50#include <signal.h>
51#include <sys/list.h>
52#include <sys/mntent.h>
53#include <sys/mnttab.h>
54#include <sys/mount.h>
55#include <sys/stat.h>
56#include <sys/fs/zfs.h>
57#include <sys/types.h>
58#include <time.h>
59
60#include <libzfs.h>
61#include <zfs_prop.h>
62#include <zfs_deleg.h>
63#include <libuutil.h>
64#ifdef sun
65#include <aclutils.h>
66#include <directory.h>
67#endif
68
69#include "zfs_iter.h"
70#include "zfs_util.h"
71#include "zfs_comutil.h"
72
73libzfs_handle_t *g_zfs;
74
75static FILE *mnttab_file;
76static char history_str[HIS_MAX_RECORD_LEN];
77
78static int zfs_do_clone(int argc, char **argv);
79static int zfs_do_create(int argc, char **argv);
80static int zfs_do_destroy(int argc, char **argv);
81static int zfs_do_get(int argc, char **argv);
82static int zfs_do_inherit(int argc, char **argv);
83static int zfs_do_list(int argc, char **argv);
84static int zfs_do_mount(int argc, char **argv);
85static int zfs_do_rename(int argc, char **argv);
86static int zfs_do_rollback(int argc, char **argv);
87static int zfs_do_set(int argc, char **argv);
88static int zfs_do_upgrade(int argc, char **argv);
89static int zfs_do_snapshot(int argc, char **argv);
90static int zfs_do_unmount(int argc, char **argv);
91static int zfs_do_share(int argc, char **argv);
92static int zfs_do_unshare(int argc, char **argv);
93static int zfs_do_send(int argc, char **argv);
94static int zfs_do_receive(int argc, char **argv);
95static int zfs_do_promote(int argc, char **argv);
96static int zfs_do_userspace(int argc, char **argv);
97static int zfs_do_allow(int argc, char **argv);
98static int zfs_do_unallow(int argc, char **argv);
99static int zfs_do_hold(int argc, char **argv);
100static int zfs_do_holds(int argc, char **argv);
101static int zfs_do_release(int argc, char **argv);
102static int zfs_do_diff(int argc, char **argv);
103static int zfs_do_jail(int argc, char **argv);
104static int zfs_do_unjail(int argc, char **argv);
105
106/*
107 * Enable a reasonable set of defaults for libumem debugging on DEBUG builds.
108 */
109
110#ifdef DEBUG
111const char *
112_umem_debug_init(void)
113{
114	return ("default,verbose"); /* $UMEM_DEBUG setting */
115}
116
117const char *
118_umem_logging_init(void)
119{
120	return ("fail,contents"); /* $UMEM_LOGGING setting */
121}
122#endif
123
124typedef enum {
125	HELP_CLONE,
126	HELP_CREATE,
127	HELP_DESTROY,
128	HELP_GET,
129	HELP_INHERIT,
130	HELP_UPGRADE,
131	HELP_JAIL,
132	HELP_UNJAIL,
133	HELP_LIST,
134	HELP_MOUNT,
135	HELP_PROMOTE,
136	HELP_RECEIVE,
137	HELP_RENAME,
138	HELP_ROLLBACK,
139	HELP_SEND,
140	HELP_SET,
141	HELP_SHARE,
142	HELP_SNAPSHOT,
143	HELP_UNMOUNT,
144	HELP_UNSHARE,
145	HELP_ALLOW,
146	HELP_UNALLOW,
147	HELP_USERSPACE,
148	HELP_GROUPSPACE,
149	HELP_HOLD,
150	HELP_HOLDS,
151	HELP_RELEASE,
152	HELP_DIFF,
153} zfs_help_t;
154
155typedef struct zfs_command {
156	const char	*name;
157	int		(*func)(int argc, char **argv);
158	zfs_help_t	usage;
159} zfs_command_t;
160
161/*
162 * Master command table.  Each ZFS command has a name, associated function, and
163 * usage message.  The usage messages need to be internationalized, so we have
164 * to have a function to return the usage message based on a command index.
165 *
166 * These commands are organized according to how they are displayed in the usage
167 * message.  An empty command (one with a NULL name) indicates an empty line in
168 * the generic usage message.
169 */
170static zfs_command_t command_table[] = {
171	{ "create",	zfs_do_create,		HELP_CREATE		},
172	{ "destroy",	zfs_do_destroy,		HELP_DESTROY		},
173	{ NULL },
174	{ "snapshot",	zfs_do_snapshot,	HELP_SNAPSHOT		},
175	{ "rollback",	zfs_do_rollback,	HELP_ROLLBACK		},
176	{ "clone",	zfs_do_clone,		HELP_CLONE		},
177	{ "promote",	zfs_do_promote,		HELP_PROMOTE		},
178	{ "rename",	zfs_do_rename,		HELP_RENAME		},
179	{ NULL },
180	{ "list",	zfs_do_list,		HELP_LIST		},
181	{ NULL },
182	{ "set",	zfs_do_set,		HELP_SET		},
183	{ "get",	zfs_do_get,		HELP_GET		},
184	{ "inherit",	zfs_do_inherit,		HELP_INHERIT		},
185	{ "upgrade",	zfs_do_upgrade,		HELP_UPGRADE		},
186	{ "userspace",	zfs_do_userspace,	HELP_USERSPACE		},
187	{ "groupspace",	zfs_do_userspace,	HELP_GROUPSPACE		},
188	{ NULL },
189	{ "mount",	zfs_do_mount,		HELP_MOUNT		},
190	{ "unmount",	zfs_do_unmount,		HELP_UNMOUNT		},
191	{ "share",	zfs_do_share,		HELP_SHARE		},
192	{ "unshare",	zfs_do_unshare,		HELP_UNSHARE		},
193	{ NULL },
194	{ "send",	zfs_do_send,		HELP_SEND		},
195	{ "receive",	zfs_do_receive,		HELP_RECEIVE		},
196	{ NULL },
197	{ "allow",	zfs_do_allow,		HELP_ALLOW		},
198	{ NULL },
199	{ "unallow",	zfs_do_unallow,		HELP_UNALLOW		},
200	{ NULL },
201	{ "hold",	zfs_do_hold,		HELP_HOLD		},
202	{ "holds",	zfs_do_holds,		HELP_HOLDS		},
203	{ "release",	zfs_do_release,		HELP_RELEASE		},
204	{ "diff",	zfs_do_diff,		HELP_DIFF		},
205	{ NULL },
206	{ "jail",	zfs_do_jail,		HELP_JAIL		},
207	{ "unjail",	zfs_do_unjail,		HELP_UNJAIL		},
208};
209
210#define	NCOMMAND	(sizeof (command_table) / sizeof (command_table[0]))
211
212zfs_command_t *current_command;
213
214static const char *
215get_usage(zfs_help_t idx)
216{
217	switch (idx) {
218	case HELP_CLONE:
219		return (gettext("\tclone [-p] [-o property=value] ... "
220		    "<snapshot> <filesystem|volume>\n"));
221	case HELP_CREATE:
222		return (gettext("\tcreate [-pu] [-o property=value] ... "
223		    "<filesystem>\n"
224		    "\tcreate [-ps] [-b blocksize] [-o property=value] ... "
225		    "-V <size> <volume>\n"));
226	case HELP_DESTROY:
227		return (gettext("\tdestroy [-fnpRrv] <filesystem|volume>\n"
228		    "\tdestroy [-dnpRrv] "
229		    "<snapshot>[%<snapname>][,...]\n"));
230	case HELP_GET:
231		return (gettext("\tget [-rHp] [-d max] "
232		    "[-o \"all\" | field[,...]] [-t type[,...]] "
233		    "[-s source[,...]]\n"
234		    "\t    <\"all\" | property[,...]> "
235		    "[filesystem|volume|snapshot] ...\n"));
236	case HELP_INHERIT:
237		return (gettext("\tinherit [-rS] <property> "
238		    "<filesystem|volume|snapshot> ...\n"));
239	case HELP_UPGRADE:
240		return (gettext("\tupgrade [-v]\n"
241		    "\tupgrade [-r] [-V version] <-a | filesystem ...>\n"));
242	case HELP_JAIL:
243		return (gettext("\tjail <jailid|jailname> <filesystem>\n"));
244	case HELP_UNJAIL:
245		return (gettext("\tunjail <jailid|jailname> <filesystem>\n"));
246	case HELP_LIST:
247		return (gettext("\tlist [-rH][-d max] "
248		    "[-o property[,...]] [-t type[,...]] [-s property] ...\n"
249		    "\t    [-S property] ... "
250		    "[filesystem|volume|snapshot] ...\n"));
251	case HELP_MOUNT:
252		return (gettext("\tmount\n"
253		    "\tmount [-vO] [-o opts] <-a | filesystem>\n"));
254	case HELP_PROMOTE:
255		return (gettext("\tpromote <clone-filesystem>\n"));
256	case HELP_RECEIVE:
257		return (gettext("\treceive [-vnFu] <filesystem|volume|"
258		"snapshot>\n"
259		"\treceive [-vnFu] [-d | -e] <filesystem>\n"));
260	case HELP_RENAME:
261		return (gettext("\trename [-f] <filesystem|volume|snapshot> "
262		    "<filesystem|volume|snapshot>\n"
263		    "\trename [-f] -p <filesystem|volume> "
264		    "<filesystem|volume>\n"
265		    "\trename -r <snapshot> <snapshot>\n"
266		    "\trename -u [-p] <filesystem> <filesystem>"));
267	case HELP_ROLLBACK:
268		return (gettext("\trollback [-rRf] <snapshot>\n"));
269	case HELP_SEND:
270		return (gettext("\tsend [-DnPpRv] "
271		    "[-i snapshot | -I snapshot] <snapshot>\n"));
272	case HELP_SET:
273		return (gettext("\tset <property=value> "
274		    "<filesystem|volume|snapshot> ...\n"));
275	case HELP_SHARE:
276		return (gettext("\tshare <-a | filesystem>\n"));
277	case HELP_SNAPSHOT:
278		return (gettext("\tsnapshot [-r] [-o property=value] ... "
279		    "<filesystem@snapname|volume@snapname>\n"));
280	case HELP_UNMOUNT:
281		return (gettext("\tunmount [-f] "
282		    "<-a | filesystem|mountpoint>\n"));
283	case HELP_UNSHARE:
284		return (gettext("\tunshare "
285		    "<-a | filesystem|mountpoint>\n"));
286	case HELP_ALLOW:
287		return (gettext("\tallow <filesystem|volume>\n"
288		    "\tallow [-ldug] "
289		    "<\"everyone\"|user|group>[,...] <perm|@setname>[,...]\n"
290		    "\t    <filesystem|volume>\n"
291		    "\tallow [-ld] -e <perm|@setname>[,...] "
292		    "<filesystem|volume>\n"
293		    "\tallow -c <perm|@setname>[,...] <filesystem|volume>\n"
294		    "\tallow -s @setname <perm|@setname>[,...] "
295		    "<filesystem|volume>\n"));
296	case HELP_UNALLOW:
297		return (gettext("\tunallow [-rldug] "
298		    "<\"everyone\"|user|group>[,...]\n"
299		    "\t    [<perm|@setname>[,...]] <filesystem|volume>\n"
300		    "\tunallow [-rld] -e [<perm|@setname>[,...]] "
301		    "<filesystem|volume>\n"
302		    "\tunallow [-r] -c [<perm|@setname>[,...]] "
303		    "<filesystem|volume>\n"
304		    "\tunallow [-r] -s @setname [<perm|@setname>[,...]] "
305		    "<filesystem|volume>\n"));
306	case HELP_USERSPACE:
307		return (gettext("\tuserspace [-Hinp] [-o field[,...]] "
308		    "[-s field] ...\n\t[-S field] ... "
309		    "[-t type[,...]] <filesystem|snapshot>\n"));
310	case HELP_GROUPSPACE:
311		return (gettext("\tgroupspace [-Hinp] [-o field[,...]] "
312		    "[-s field] ...\n\t[-S field] ... "
313		    "[-t type[,...]] <filesystem|snapshot>\n"));
314	case HELP_HOLD:
315		return (gettext("\thold [-r] <tag> <snapshot> ...\n"));
316	case HELP_HOLDS:
317		return (gettext("\tholds [-r] <snapshot> ...\n"));
318	case HELP_RELEASE:
319		return (gettext("\trelease [-r] <tag> <snapshot> ...\n"));
320	case HELP_DIFF:
321		return (gettext("\tdiff [-FHt] <snapshot> "
322		    "[snapshot|filesystem]\n"));
323	}
324
325	abort();
326	/* NOTREACHED */
327}
328
329void
330nomem(void)
331{
332	(void) fprintf(stderr, gettext("internal error: out of memory\n"));
333	exit(1);
334}
335
336/*
337 * Utility function to guarantee malloc() success.
338 */
339
340void *
341safe_malloc(size_t size)
342{
343	void *data;
344
345	if ((data = calloc(1, size)) == NULL)
346		nomem();
347
348	return (data);
349}
350
351static char *
352safe_strdup(char *str)
353{
354	char *dupstr = strdup(str);
355
356	if (dupstr == NULL)
357		nomem();
358
359	return (dupstr);
360}
361
362/*
363 * Callback routine that will print out information for each of
364 * the properties.
365 */
366static int
367usage_prop_cb(int prop, void *cb)
368{
369	FILE *fp = cb;
370
371	(void) fprintf(fp, "\t%-15s ", zfs_prop_to_name(prop));
372
373	if (zfs_prop_readonly(prop))
374		(void) fprintf(fp, " NO    ");
375	else
376		(void) fprintf(fp, "YES    ");
377
378	if (zfs_prop_inheritable(prop))
379		(void) fprintf(fp, "  YES   ");
380	else
381		(void) fprintf(fp, "   NO   ");
382
383	if (zfs_prop_values(prop) == NULL)
384		(void) fprintf(fp, "-\n");
385	else
386		(void) fprintf(fp, "%s\n", zfs_prop_values(prop));
387
388	return (ZPROP_CONT);
389}
390
391/*
392 * Display usage message.  If we're inside a command, display only the usage for
393 * that command.  Otherwise, iterate over the entire command table and display
394 * a complete usage message.
395 */
396static void
397usage(boolean_t requested)
398{
399	int i;
400	boolean_t show_properties = B_FALSE;
401	FILE *fp = requested ? stdout : stderr;
402
403	if (current_command == NULL) {
404
405		(void) fprintf(fp, gettext("usage: zfs command args ...\n"));
406		(void) fprintf(fp,
407		    gettext("where 'command' is one of the following:\n\n"));
408
409		for (i = 0; i < NCOMMAND; i++) {
410			if (command_table[i].name == NULL)
411				(void) fprintf(fp, "\n");
412			else
413				(void) fprintf(fp, "%s",
414				    get_usage(command_table[i].usage));
415		}
416
417		(void) fprintf(fp, gettext("\nEach dataset is of the form: "
418		    "pool/[dataset/]*dataset[@name]\n"));
419	} else {
420		(void) fprintf(fp, gettext("usage:\n"));
421		(void) fprintf(fp, "%s", get_usage(current_command->usage));
422	}
423
424	if (current_command != NULL &&
425	    (strcmp(current_command->name, "set") == 0 ||
426	    strcmp(current_command->name, "get") == 0 ||
427	    strcmp(current_command->name, "inherit") == 0 ||
428	    strcmp(current_command->name, "list") == 0))
429		show_properties = B_TRUE;
430
431	if (show_properties) {
432		(void) fprintf(fp,
433		    gettext("\nThe following properties are supported:\n"));
434
435		(void) fprintf(fp, "\n\t%-14s %s  %s   %s\n\n",
436		    "PROPERTY", "EDIT", "INHERIT", "VALUES");
437
438		/* Iterate over all properties */
439		(void) zprop_iter(usage_prop_cb, fp, B_FALSE, B_TRUE,
440		    ZFS_TYPE_DATASET);
441
442		(void) fprintf(fp, "\t%-15s ", "userused@...");
443		(void) fprintf(fp, " NO       NO   <size>\n");
444		(void) fprintf(fp, "\t%-15s ", "groupused@...");
445		(void) fprintf(fp, " NO       NO   <size>\n");
446		(void) fprintf(fp, "\t%-15s ", "userquota@...");
447		(void) fprintf(fp, "YES       NO   <size> | none\n");
448		(void) fprintf(fp, "\t%-15s ", "groupquota@...");
449		(void) fprintf(fp, "YES       NO   <size> | none\n");
450		(void) fprintf(fp, "\t%-15s ", "written@<snap>");
451		(void) fprintf(fp, " NO       NO   <size>\n");
452
453		(void) fprintf(fp, gettext("\nSizes are specified in bytes "
454		    "with standard units such as K, M, G, etc.\n"));
455		(void) fprintf(fp, gettext("\nUser-defined properties can "
456		    "be specified by using a name containing a colon (:).\n"));
457		(void) fprintf(fp, gettext("\nThe {user|group}{used|quota}@ "
458		    "properties must be appended with\n"
459		    "a user or group specifier of one of these forms:\n"
460		    "    POSIX name      (eg: \"matt\")\n"
461		    "    POSIX id        (eg: \"126829\")\n"
462		    "    SMB name@domain (eg: \"matt@sun\")\n"
463		    "    SMB SID         (eg: \"S-1-234-567-89\")\n"));
464	} else {
465		(void) fprintf(fp,
466		    gettext("\nFor the property list, run: %s\n"),
467		    "zfs set|get");
468		(void) fprintf(fp,
469		    gettext("\nFor the delegated permission list, run: %s\n"),
470		    "zfs allow|unallow");
471	}
472
473	/*
474	 * See comments at end of main().
475	 */
476	if (getenv("ZFS_ABORT") != NULL) {
477		(void) printf("dumping core by request\n");
478		abort();
479	}
480
481	exit(requested ? 0 : 2);
482}
483
484static int
485parseprop(nvlist_t *props)
486{
487	char *propname = optarg;
488	char *propval, *strval;
489
490	if ((propval = strchr(propname, '=')) == NULL) {
491		(void) fprintf(stderr, gettext("missing "
492		    "'=' for -o option\n"));
493		return (-1);
494	}
495	*propval = '\0';
496	propval++;
497	if (nvlist_lookup_string(props, propname, &strval) == 0) {
498		(void) fprintf(stderr, gettext("property '%s' "
499		    "specified multiple times\n"), propname);
500		return (-1);
501	}
502	if (nvlist_add_string(props, propname, propval) != 0)
503		nomem();
504	return (0);
505}
506
507static int
508parse_depth(char *opt, int *flags)
509{
510	char *tmp;
511	int depth;
512
513	depth = (int)strtol(opt, &tmp, 0);
514	if (*tmp) {
515		(void) fprintf(stderr,
516		    gettext("%s is not an integer\n"), optarg);
517		usage(B_FALSE);
518	}
519	if (depth < 0) {
520		(void) fprintf(stderr,
521		    gettext("Depth can not be negative.\n"));
522		usage(B_FALSE);
523	}
524	*flags |= (ZFS_ITER_DEPTH_LIMIT|ZFS_ITER_RECURSE);
525	return (depth);
526}
527
528#define	PROGRESS_DELAY 2		/* seconds */
529
530static char *pt_reverse = "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b";
531static time_t pt_begin;
532static char *pt_header = NULL;
533static boolean_t pt_shown;
534
535static void
536start_progress_timer(void)
537{
538	pt_begin = time(NULL) + PROGRESS_DELAY;
539	pt_shown = B_FALSE;
540}
541
542static void
543set_progress_header(char *header)
544{
545	assert(pt_header == NULL);
546	pt_header = safe_strdup(header);
547	if (pt_shown) {
548		(void) printf("%s: ", header);
549		(void) fflush(stdout);
550	}
551}
552
553static void
554update_progress(char *update)
555{
556	if (!pt_shown && time(NULL) > pt_begin) {
557		int len = strlen(update);
558
559		(void) printf("%s: %s%*.*s", pt_header, update, len, len,
560		    pt_reverse);
561		(void) fflush(stdout);
562		pt_shown = B_TRUE;
563	} else if (pt_shown) {
564		int len = strlen(update);
565
566		(void) printf("%s%*.*s", update, len, len, pt_reverse);
567		(void) fflush(stdout);
568	}
569}
570
571static void
572finish_progress(char *done)
573{
574	if (pt_shown) {
575		(void) printf("%s\n", done);
576		(void) fflush(stdout);
577	}
578	free(pt_header);
579	pt_header = NULL;
580}
581/*
582 * zfs clone [-p] [-o prop=value] ... <snap> <fs | vol>
583 *
584 * Given an existing dataset, create a writable copy whose initial contents
585 * are the same as the source.  The newly created dataset maintains a
586 * dependency on the original; the original cannot be destroyed so long as
587 * the clone exists.
588 *
589 * The '-p' flag creates all the non-existing ancestors of the target first.
590 */
591static int
592zfs_do_clone(int argc, char **argv)
593{
594	zfs_handle_t *zhp = NULL;
595	boolean_t parents = B_FALSE;
596	nvlist_t *props;
597	int ret = 0;
598	int c;
599
600	if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0)
601		nomem();
602
603	/* check options */
604	while ((c = getopt(argc, argv, "o:p")) != -1) {
605		switch (c) {
606		case 'o':
607			if (parseprop(props))
608				return (1);
609			break;
610		case 'p':
611			parents = B_TRUE;
612			break;
613		case '?':
614			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
615			    optopt);
616			goto usage;
617		}
618	}
619
620	argc -= optind;
621	argv += optind;
622
623	/* check number of arguments */
624	if (argc < 1) {
625		(void) fprintf(stderr, gettext("missing source dataset "
626		    "argument\n"));
627		goto usage;
628	}
629	if (argc < 2) {
630		(void) fprintf(stderr, gettext("missing target dataset "
631		    "argument\n"));
632		goto usage;
633	}
634	if (argc > 2) {
635		(void) fprintf(stderr, gettext("too many arguments\n"));
636		goto usage;
637	}
638
639	/* open the source dataset */
640	if ((zhp = zfs_open(g_zfs, argv[0], ZFS_TYPE_SNAPSHOT)) == NULL)
641		return (1);
642
643	if (parents && zfs_name_valid(argv[1], ZFS_TYPE_FILESYSTEM |
644	    ZFS_TYPE_VOLUME)) {
645		/*
646		 * Now create the ancestors of the target dataset.  If the
647		 * target already exists and '-p' option was used we should not
648		 * complain.
649		 */
650		if (zfs_dataset_exists(g_zfs, argv[1], ZFS_TYPE_FILESYSTEM |
651		    ZFS_TYPE_VOLUME))
652			return (0);
653		if (zfs_create_ancestors(g_zfs, argv[1]) != 0)
654			return (1);
655	}
656
657	/* pass to libzfs */
658	ret = zfs_clone(zhp, argv[1], props);
659
660	/* create the mountpoint if necessary */
661	if (ret == 0) {
662		zfs_handle_t *clone;
663
664		clone = zfs_open(g_zfs, argv[1], ZFS_TYPE_DATASET);
665		if (clone != NULL) {
666			if (zfs_get_type(clone) != ZFS_TYPE_VOLUME)
667				if ((ret = zfs_mount(clone, NULL, 0)) == 0)
668					ret = zfs_share(clone);
669			zfs_close(clone);
670		}
671	}
672
673	zfs_close(zhp);
674	nvlist_free(props);
675
676	return (!!ret);
677
678usage:
679	if (zhp)
680		zfs_close(zhp);
681	nvlist_free(props);
682	usage(B_FALSE);
683	return (-1);
684}
685
686/*
687 * zfs create [-pu] [-o prop=value] ... fs
688 * zfs create [-ps] [-b blocksize] [-o prop=value] ... -V vol size
689 *
690 * Create a new dataset.  This command can be used to create filesystems
691 * and volumes.  Snapshot creation is handled by 'zfs snapshot'.
692 * For volumes, the user must specify a size to be used.
693 *
694 * The '-s' flag applies only to volumes, and indicates that we should not try
695 * to set the reservation for this volume.  By default we set a reservation
696 * equal to the size for any volume.  For pools with SPA_VERSION >=
697 * SPA_VERSION_REFRESERVATION, we set a refreservation instead.
698 *
699 * The '-p' flag creates all the non-existing ancestors of the target first.
700 *
701 * The '-u' flag prevents mounting of newly created file system.
702 */
703static int
704zfs_do_create(int argc, char **argv)
705{
706	zfs_type_t type = ZFS_TYPE_FILESYSTEM;
707	zfs_handle_t *zhp = NULL;
708	uint64_t volsize;
709	int c;
710	boolean_t noreserve = B_FALSE;
711	boolean_t bflag = B_FALSE;
712	boolean_t parents = B_FALSE;
713	boolean_t nomount = B_FALSE;
714	int ret = 1;
715	nvlist_t *props;
716	uint64_t intval;
717	int canmount = ZFS_CANMOUNT_OFF;
718
719	if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0)
720		nomem();
721
722	/* check options */
723	while ((c = getopt(argc, argv, ":V:b:so:pu")) != -1) {
724		switch (c) {
725		case 'V':
726			type = ZFS_TYPE_VOLUME;
727			if (zfs_nicestrtonum(g_zfs, optarg, &intval) != 0) {
728				(void) fprintf(stderr, gettext("bad volume "
729				    "size '%s': %s\n"), optarg,
730				    libzfs_error_description(g_zfs));
731				goto error;
732			}
733
734			if (nvlist_add_uint64(props,
735			    zfs_prop_to_name(ZFS_PROP_VOLSIZE), intval) != 0)
736				nomem();
737			volsize = intval;
738			break;
739		case 'p':
740			parents = B_TRUE;
741			break;
742		case 'b':
743			bflag = B_TRUE;
744			if (zfs_nicestrtonum(g_zfs, optarg, &intval) != 0) {
745				(void) fprintf(stderr, gettext("bad volume "
746				    "block size '%s': %s\n"), optarg,
747				    libzfs_error_description(g_zfs));
748				goto error;
749			}
750
751			if (nvlist_add_uint64(props,
752			    zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE),
753			    intval) != 0)
754				nomem();
755			break;
756		case 'o':
757			if (parseprop(props))
758				goto error;
759			break;
760		case 's':
761			noreserve = B_TRUE;
762			break;
763		case 'u':
764			nomount = B_TRUE;
765			break;
766		case ':':
767			(void) fprintf(stderr, gettext("missing size "
768			    "argument\n"));
769			goto badusage;
770		case '?':
771			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
772			    optopt);
773			goto badusage;
774		}
775	}
776
777	if ((bflag || noreserve) && type != ZFS_TYPE_VOLUME) {
778		(void) fprintf(stderr, gettext("'-s' and '-b' can only be "
779		    "used when creating a volume\n"));
780		goto badusage;
781	}
782	if (nomount && type != ZFS_TYPE_FILESYSTEM) {
783		(void) fprintf(stderr, gettext("'-u' can only be "
784		    "used when creating a file system\n"));
785		goto badusage;
786	}
787
788	argc -= optind;
789	argv += optind;
790
791	/* check number of arguments */
792	if (argc == 0) {
793		(void) fprintf(stderr, gettext("missing %s argument\n"),
794		    zfs_type_to_name(type));
795		goto badusage;
796	}
797	if (argc > 1) {
798		(void) fprintf(stderr, gettext("too many arguments\n"));
799		goto badusage;
800	}
801
802	if (type == ZFS_TYPE_VOLUME && !noreserve) {
803		zpool_handle_t *zpool_handle;
804		uint64_t spa_version;
805		char *p;
806		zfs_prop_t resv_prop;
807		char *strval;
808
809		if (p = strchr(argv[0], '/'))
810			*p = '\0';
811		zpool_handle = zpool_open(g_zfs, argv[0]);
812		if (p != NULL)
813			*p = '/';
814		if (zpool_handle == NULL)
815			goto error;
816		spa_version = zpool_get_prop_int(zpool_handle,
817		    ZPOOL_PROP_VERSION, NULL);
818		zpool_close(zpool_handle);
819		if (spa_version >= SPA_VERSION_REFRESERVATION)
820			resv_prop = ZFS_PROP_REFRESERVATION;
821		else
822			resv_prop = ZFS_PROP_RESERVATION;
823		volsize = zvol_volsize_to_reservation(volsize, props);
824
825		if (nvlist_lookup_string(props, zfs_prop_to_name(resv_prop),
826		    &strval) != 0) {
827			if (nvlist_add_uint64(props,
828			    zfs_prop_to_name(resv_prop), volsize) != 0) {
829				nvlist_free(props);
830				nomem();
831			}
832		}
833	}
834
835	if (parents && zfs_name_valid(argv[0], type)) {
836		/*
837		 * Now create the ancestors of target dataset.  If the target
838		 * already exists and '-p' option was used we should not
839		 * complain.
840		 */
841		if (zfs_dataset_exists(g_zfs, argv[0], type)) {
842			ret = 0;
843			goto error;
844		}
845		if (zfs_create_ancestors(g_zfs, argv[0]) != 0)
846			goto error;
847	}
848
849	/* pass to libzfs */
850	if (zfs_create(g_zfs, argv[0], type, props) != 0)
851		goto error;
852
853	if ((zhp = zfs_open(g_zfs, argv[0], ZFS_TYPE_DATASET)) == NULL)
854		goto error;
855
856	ret = 0;
857	/*
858	 * if the user doesn't want the dataset automatically mounted,
859	 * then skip the mount/share step
860	 */
861	if (zfs_prop_valid_for_type(ZFS_PROP_CANMOUNT, type))
862		canmount = zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT);
863
864	/*
865	 * Mount and/or share the new filesystem as appropriate.  We provide a
866	 * verbose error message to let the user know that their filesystem was
867	 * in fact created, even if we failed to mount or share it.
868	 */
869	if (!nomount && canmount == ZFS_CANMOUNT_ON) {
870		if (zfs_mount(zhp, NULL, 0) != 0) {
871			(void) fprintf(stderr, gettext("filesystem "
872			    "successfully created, but not mounted\n"));
873			ret = 1;
874		} else if (zfs_share(zhp) != 0) {
875			(void) fprintf(stderr, gettext("filesystem "
876			    "successfully created, but not shared\n"));
877			ret = 1;
878		}
879	}
880
881error:
882	if (zhp)
883		zfs_close(zhp);
884	nvlist_free(props);
885	return (ret);
886badusage:
887	nvlist_free(props);
888	usage(B_FALSE);
889	return (2);
890}
891
892/*
893 * zfs destroy [-rRf] <fs, vol>
894 * zfs destroy [-rRd] <snap>
895 *
896 *	-r	Recursively destroy all children
897 *	-R	Recursively destroy all dependents, including clones
898 *	-f	Force unmounting of any dependents
899 *	-d	If we can't destroy now, mark for deferred destruction
900 *
901 * Destroys the given dataset.  By default, it will unmount any filesystems,
902 * and refuse to destroy a dataset that has any dependents.  A dependent can
903 * either be a child, or a clone of a child.
904 */
905typedef struct destroy_cbdata {
906	boolean_t	cb_first;
907	boolean_t	cb_force;
908	boolean_t	cb_recurse;
909	boolean_t	cb_error;
910	boolean_t	cb_doclones;
911	zfs_handle_t	*cb_target;
912	boolean_t	cb_defer_destroy;
913	boolean_t	cb_verbose;
914	boolean_t	cb_parsable;
915	boolean_t	cb_dryrun;
916	nvlist_t	*cb_nvl;
917
918	/* first snap in contiguous run */
919	zfs_handle_t	*cb_firstsnap;
920	/* previous snap in contiguous run */
921	zfs_handle_t	*cb_prevsnap;
922	int64_t		cb_snapused;
923	char		*cb_snapspec;
924} destroy_cbdata_t;
925
926/*
927 * Check for any dependents based on the '-r' or '-R' flags.
928 */
929static int
930destroy_check_dependent(zfs_handle_t *zhp, void *data)
931{
932	destroy_cbdata_t *cbp = data;
933	const char *tname = zfs_get_name(cbp->cb_target);
934	const char *name = zfs_get_name(zhp);
935
936	if (strncmp(tname, name, strlen(tname)) == 0 &&
937	    (name[strlen(tname)] == '/' || name[strlen(tname)] == '@')) {
938		/*
939		 * This is a direct descendant, not a clone somewhere else in
940		 * the hierarchy.
941		 */
942		if (cbp->cb_recurse)
943			goto out;
944
945		if (cbp->cb_first) {
946			(void) fprintf(stderr, gettext("cannot destroy '%s': "
947			    "%s has children\n"),
948			    zfs_get_name(cbp->cb_target),
949			    zfs_type_to_name(zfs_get_type(cbp->cb_target)));
950			(void) fprintf(stderr, gettext("use '-r' to destroy "
951			    "the following datasets:\n"));
952			cbp->cb_first = B_FALSE;
953			cbp->cb_error = B_TRUE;
954		}
955
956		(void) fprintf(stderr, "%s\n", zfs_get_name(zhp));
957	} else {
958		/*
959		 * This is a clone.  We only want to report this if the '-r'
960		 * wasn't specified, or the target is a snapshot.
961		 */
962		if (!cbp->cb_recurse &&
963		    zfs_get_type(cbp->cb_target) != ZFS_TYPE_SNAPSHOT)
964			goto out;
965
966		if (cbp->cb_first) {
967			(void) fprintf(stderr, gettext("cannot destroy '%s': "
968			    "%s has dependent clones\n"),
969			    zfs_get_name(cbp->cb_target),
970			    zfs_type_to_name(zfs_get_type(cbp->cb_target)));
971			(void) fprintf(stderr, gettext("use '-R' to destroy "
972			    "the following datasets:\n"));
973			cbp->cb_first = B_FALSE;
974			cbp->cb_error = B_TRUE;
975			cbp->cb_dryrun = B_TRUE;
976		}
977
978		(void) fprintf(stderr, "%s\n", zfs_get_name(zhp));
979	}
980
981out:
982	zfs_close(zhp);
983	return (0);
984}
985
986static int
987destroy_callback(zfs_handle_t *zhp, void *data)
988{
989	destroy_cbdata_t *cb = data;
990	const char *name = zfs_get_name(zhp);
991
992	if (cb->cb_verbose) {
993		if (cb->cb_parsable) {
994			(void) printf("destroy\t%s\n", name);
995		} else if (cb->cb_dryrun) {
996			(void) printf(gettext("would destroy %s\n"),
997			    name);
998		} else {
999			(void) printf(gettext("will destroy %s\n"),
1000			    name);
1001		}
1002	}
1003
1004	/*
1005	 * Ignore pools (which we've already flagged as an error before getting
1006	 * here).
1007	 */
1008	if (strchr(zfs_get_name(zhp), '/') == NULL &&
1009	    zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) {
1010		zfs_close(zhp);
1011		return (0);
1012	}
1013
1014	if (!cb->cb_dryrun) {
1015		if (zfs_unmount(zhp, NULL, cb->cb_force ? MS_FORCE : 0) != 0 ||
1016		    zfs_destroy(zhp, cb->cb_defer_destroy) != 0) {
1017			zfs_close(zhp);
1018			return (-1);
1019		}
1020	}
1021
1022	zfs_close(zhp);
1023	return (0);
1024}
1025
1026static int
1027destroy_print_cb(zfs_handle_t *zhp, void *arg)
1028{
1029	destroy_cbdata_t *cb = arg;
1030	const char *name = zfs_get_name(zhp);
1031	int err = 0;
1032
1033	if (nvlist_exists(cb->cb_nvl, name)) {
1034		if (cb->cb_firstsnap == NULL)
1035			cb->cb_firstsnap = zfs_handle_dup(zhp);
1036		if (cb->cb_prevsnap != NULL)
1037			zfs_close(cb->cb_prevsnap);
1038		/* this snap continues the current range */
1039		cb->cb_prevsnap = zfs_handle_dup(zhp);
1040		if (cb->cb_verbose) {
1041			if (cb->cb_parsable) {
1042				(void) printf("destroy\t%s\n", name);
1043			} else if (cb->cb_dryrun) {
1044				(void) printf(gettext("would destroy %s\n"),
1045				    name);
1046			} else {
1047				(void) printf(gettext("will destroy %s\n"),
1048				    name);
1049			}
1050		}
1051	} else if (cb->cb_firstsnap != NULL) {
1052		/* end of this range */
1053		uint64_t used = 0;
1054		err = zfs_get_snapused_int(cb->cb_firstsnap,
1055		    cb->cb_prevsnap, &used);
1056		cb->cb_snapused += used;
1057		zfs_close(cb->cb_firstsnap);
1058		cb->cb_firstsnap = NULL;
1059		zfs_close(cb->cb_prevsnap);
1060		cb->cb_prevsnap = NULL;
1061	}
1062	zfs_close(zhp);
1063	return (err);
1064}
1065
1066static int
1067destroy_print_snapshots(zfs_handle_t *fs_zhp, destroy_cbdata_t *cb)
1068{
1069	int err = 0;
1070	assert(cb->cb_firstsnap == NULL);
1071	assert(cb->cb_prevsnap == NULL);
1072	err = zfs_iter_snapshots_sorted(fs_zhp, destroy_print_cb, cb);
1073	if (cb->cb_firstsnap != NULL) {
1074		uint64_t used = 0;
1075		if (err == 0) {
1076			err = zfs_get_snapused_int(cb->cb_firstsnap,
1077			    cb->cb_prevsnap, &used);
1078		}
1079		cb->cb_snapused += used;
1080		zfs_close(cb->cb_firstsnap);
1081		cb->cb_firstsnap = NULL;
1082		zfs_close(cb->cb_prevsnap);
1083		cb->cb_prevsnap = NULL;
1084	}
1085	return (err);
1086}
1087
1088static int
1089snapshot_to_nvl_cb(zfs_handle_t *zhp, void *arg)
1090{
1091	destroy_cbdata_t *cb = arg;
1092	int err = 0;
1093
1094	/* Check for clones. */
1095	if (!cb->cb_doclones && !cb->cb_defer_destroy) {
1096		cb->cb_target = zhp;
1097		cb->cb_first = B_TRUE;
1098		err = zfs_iter_dependents(zhp, B_TRUE,
1099		    destroy_check_dependent, cb);
1100	}
1101
1102	if (err == 0) {
1103		if (nvlist_add_boolean(cb->cb_nvl, zfs_get_name(zhp)))
1104			nomem();
1105	}
1106	zfs_close(zhp);
1107	return (err);
1108}
1109
1110static int
1111gather_snapshots(zfs_handle_t *zhp, void *arg)
1112{
1113	destroy_cbdata_t *cb = arg;
1114	int err = 0;
1115
1116	err = zfs_iter_snapspec(zhp, cb->cb_snapspec, snapshot_to_nvl_cb, cb);
1117	if (err == ENOENT)
1118		err = 0;
1119	if (err != 0)
1120		goto out;
1121
1122	if (cb->cb_verbose) {
1123		err = destroy_print_snapshots(zhp, cb);
1124		if (err != 0)
1125			goto out;
1126	}
1127
1128	if (cb->cb_recurse)
1129		err = zfs_iter_filesystems(zhp, gather_snapshots, cb);
1130
1131out:
1132	zfs_close(zhp);
1133	return (err);
1134}
1135
1136static int
1137destroy_clones(destroy_cbdata_t *cb)
1138{
1139	nvpair_t *pair;
1140	for (pair = nvlist_next_nvpair(cb->cb_nvl, NULL);
1141	    pair != NULL;
1142	    pair = nvlist_next_nvpair(cb->cb_nvl, pair)) {
1143		zfs_handle_t *zhp = zfs_open(g_zfs, nvpair_name(pair),
1144		    ZFS_TYPE_SNAPSHOT);
1145		if (zhp != NULL) {
1146			boolean_t defer = cb->cb_defer_destroy;
1147			int err = 0;
1148
1149			/*
1150			 * We can't defer destroy non-snapshots, so set it to
1151			 * false while destroying the clones.
1152			 */
1153			cb->cb_defer_destroy = B_FALSE;
1154			err = zfs_iter_dependents(zhp, B_FALSE,
1155			    destroy_callback, cb);
1156			cb->cb_defer_destroy = defer;
1157			zfs_close(zhp);
1158			if (err != 0)
1159				return (err);
1160		}
1161	}
1162	return (0);
1163}
1164
1165static int
1166zfs_do_destroy(int argc, char **argv)
1167{
1168	destroy_cbdata_t cb = { 0 };
1169	int c;
1170	zfs_handle_t *zhp;
1171	char *at;
1172	zfs_type_t type = ZFS_TYPE_DATASET;
1173
1174	/* check options */
1175	while ((c = getopt(argc, argv, "vpndfrR")) != -1) {
1176		switch (c) {
1177		case 'v':
1178			cb.cb_verbose = B_TRUE;
1179			break;
1180		case 'p':
1181			cb.cb_verbose = B_TRUE;
1182			cb.cb_parsable = B_TRUE;
1183			break;
1184		case 'n':
1185			cb.cb_dryrun = B_TRUE;
1186			break;
1187		case 'd':
1188			cb.cb_defer_destroy = B_TRUE;
1189			type = ZFS_TYPE_SNAPSHOT;
1190			break;
1191		case 'f':
1192			cb.cb_force = B_TRUE;
1193			break;
1194		case 'r':
1195			cb.cb_recurse = B_TRUE;
1196			break;
1197		case 'R':
1198			cb.cb_recurse = B_TRUE;
1199			cb.cb_doclones = B_TRUE;
1200			break;
1201		case '?':
1202		default:
1203			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1204			    optopt);
1205			usage(B_FALSE);
1206		}
1207	}
1208
1209	argc -= optind;
1210	argv += optind;
1211
1212	/* check number of arguments */
1213	if (argc == 0) {
1214		(void) fprintf(stderr, gettext("missing dataset argument\n"));
1215		usage(B_FALSE);
1216	}
1217	if (argc > 1) {
1218		(void) fprintf(stderr, gettext("too many arguments\n"));
1219		usage(B_FALSE);
1220	}
1221
1222	at = strchr(argv[0], '@');
1223	if (at != NULL) {
1224		int err = 0;
1225
1226		/* Build the list of snaps to destroy in cb_nvl. */
1227		if (nvlist_alloc(&cb.cb_nvl, NV_UNIQUE_NAME, 0) != 0)
1228			nomem();
1229
1230		*at = '\0';
1231		zhp = zfs_open(g_zfs, argv[0],
1232		    ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
1233		if (zhp == NULL)
1234			return (1);
1235
1236		cb.cb_snapspec = at + 1;
1237		if (gather_snapshots(zfs_handle_dup(zhp), &cb) != 0 ||
1238		    cb.cb_error) {
1239			zfs_close(zhp);
1240			nvlist_free(cb.cb_nvl);
1241			return (1);
1242		}
1243
1244		if (nvlist_empty(cb.cb_nvl)) {
1245			(void) fprintf(stderr, gettext("could not find any "
1246			    "snapshots to destroy; check snapshot names.\n"));
1247			zfs_close(zhp);
1248			nvlist_free(cb.cb_nvl);
1249			return (1);
1250		}
1251
1252		if (cb.cb_verbose) {
1253			char buf[16];
1254			zfs_nicenum(cb.cb_snapused, buf, sizeof (buf));
1255			if (cb.cb_parsable) {
1256				(void) printf("reclaim\t%llu\n",
1257				    cb.cb_snapused);
1258			} else if (cb.cb_dryrun) {
1259				(void) printf(gettext("would reclaim %s\n"),
1260				    buf);
1261			} else {
1262				(void) printf(gettext("will reclaim %s\n"),
1263				    buf);
1264			}
1265		}
1266
1267		if (!cb.cb_dryrun) {
1268			if (cb.cb_doclones)
1269				err = destroy_clones(&cb);
1270			if (err == 0) {
1271				err = zfs_destroy_snaps_nvl(zhp, cb.cb_nvl,
1272				    cb.cb_defer_destroy);
1273			}
1274		}
1275
1276		zfs_close(zhp);
1277		nvlist_free(cb.cb_nvl);
1278		if (err != 0)
1279			return (1);
1280	} else {
1281		/* Open the given dataset */
1282		if ((zhp = zfs_open(g_zfs, argv[0], type)) == NULL)
1283			return (1);
1284
1285		cb.cb_target = zhp;
1286
1287		/*
1288		 * Perform an explicit check for pools before going any further.
1289		 */
1290		if (!cb.cb_recurse && strchr(zfs_get_name(zhp), '/') == NULL &&
1291		    zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) {
1292			(void) fprintf(stderr, gettext("cannot destroy '%s': "
1293			    "operation does not apply to pools\n"),
1294			    zfs_get_name(zhp));
1295			(void) fprintf(stderr, gettext("use 'zfs destroy -r "
1296			    "%s' to destroy all datasets in the pool\n"),
1297			    zfs_get_name(zhp));
1298			(void) fprintf(stderr, gettext("use 'zpool destroy %s' "
1299			    "to destroy the pool itself\n"), zfs_get_name(zhp));
1300			zfs_close(zhp);
1301			return (1);
1302		}
1303
1304		/*
1305		 * Check for any dependents and/or clones.
1306		 */
1307		cb.cb_first = B_TRUE;
1308		if (!cb.cb_doclones &&
1309		    zfs_iter_dependents(zhp, B_TRUE, destroy_check_dependent,
1310		    &cb) != 0) {
1311			zfs_close(zhp);
1312			return (1);
1313		}
1314
1315		if (cb.cb_error) {
1316			zfs_close(zhp);
1317			return (1);
1318		}
1319
1320		if (zfs_iter_dependents(zhp, B_FALSE, destroy_callback,
1321		    &cb) != 0) {
1322			zfs_close(zhp);
1323			return (1);
1324		}
1325
1326		/*
1327		 * Do the real thing.  The callback will close the
1328		 * handle regardless of whether it succeeds or not.
1329		 */
1330		if (destroy_callback(zhp, &cb) != 0)
1331			return (1);
1332	}
1333
1334	return (0);
1335}
1336
1337static boolean_t
1338is_recvd_column(zprop_get_cbdata_t *cbp)
1339{
1340	int i;
1341	zfs_get_column_t col;
1342
1343	for (i = 0; i < ZFS_GET_NCOLS &&
1344	    (col = cbp->cb_columns[i]) != GET_COL_NONE; i++)
1345		if (col == GET_COL_RECVD)
1346			return (B_TRUE);
1347	return (B_FALSE);
1348}
1349
1350/*
1351 * zfs get [-rHp] [-o all | field[,field]...] [-s source[,source]...]
1352 *	< all | property[,property]... > < fs | snap | vol > ...
1353 *
1354 *	-r	recurse over any child datasets
1355 *	-H	scripted mode.  Headers are stripped, and fields are separated
1356 *		by tabs instead of spaces.
1357 *	-o	Set of fields to display.  One of "name,property,value,
1358 *		received,source". Default is "name,property,value,source".
1359 *		"all" is an alias for all five.
1360 *	-s	Set of sources to allow.  One of
1361 *		"local,default,inherited,received,temporary,none".  Default is
1362 *		all six.
1363 *	-p	Display values in parsable (literal) format.
1364 *
1365 *  Prints properties for the given datasets.  The user can control which
1366 *  columns to display as well as which property types to allow.
1367 */
1368
1369/*
1370 * Invoked to display the properties for a single dataset.
1371 */
1372static int
1373get_callback(zfs_handle_t *zhp, void *data)
1374{
1375	char buf[ZFS_MAXPROPLEN];
1376	char rbuf[ZFS_MAXPROPLEN];
1377	zprop_source_t sourcetype;
1378	char source[ZFS_MAXNAMELEN];
1379	zprop_get_cbdata_t *cbp = data;
1380	nvlist_t *user_props = zfs_get_user_props(zhp);
1381	zprop_list_t *pl = cbp->cb_proplist;
1382	nvlist_t *propval;
1383	char *strval;
1384	char *sourceval;
1385	boolean_t received = is_recvd_column(cbp);
1386
1387	for (; pl != NULL; pl = pl->pl_next) {
1388		char *recvdval = NULL;
1389		/*
1390		 * Skip the special fake placeholder.  This will also skip over
1391		 * the name property when 'all' is specified.
1392		 */
1393		if (pl->pl_prop == ZFS_PROP_NAME &&
1394		    pl == cbp->cb_proplist)
1395			continue;
1396
1397		if (pl->pl_prop != ZPROP_INVAL) {
1398			if (zfs_prop_get(zhp, pl->pl_prop, buf,
1399			    sizeof (buf), &sourcetype, source,
1400			    sizeof (source),
1401			    cbp->cb_literal) != 0) {
1402				if (pl->pl_all)
1403					continue;
1404				if (!zfs_prop_valid_for_type(pl->pl_prop,
1405				    ZFS_TYPE_DATASET)) {
1406					(void) fprintf(stderr,
1407					    gettext("No such property '%s'\n"),
1408					    zfs_prop_to_name(pl->pl_prop));
1409					continue;
1410				}
1411				sourcetype = ZPROP_SRC_NONE;
1412				(void) strlcpy(buf, "-", sizeof (buf));
1413			}
1414
1415			if (received && (zfs_prop_get_recvd(zhp,
1416			    zfs_prop_to_name(pl->pl_prop), rbuf, sizeof (rbuf),
1417			    cbp->cb_literal) == 0))
1418				recvdval = rbuf;
1419
1420			zprop_print_one_property(zfs_get_name(zhp), cbp,
1421			    zfs_prop_to_name(pl->pl_prop),
1422			    buf, sourcetype, source, recvdval);
1423		} else if (zfs_prop_userquota(pl->pl_user_prop)) {
1424			sourcetype = ZPROP_SRC_LOCAL;
1425
1426			if (zfs_prop_get_userquota(zhp, pl->pl_user_prop,
1427			    buf, sizeof (buf), cbp->cb_literal) != 0) {
1428				sourcetype = ZPROP_SRC_NONE;
1429				(void) strlcpy(buf, "-", sizeof (buf));
1430			}
1431
1432			zprop_print_one_property(zfs_get_name(zhp), cbp,
1433			    pl->pl_user_prop, buf, sourcetype, source, NULL);
1434		} else if (zfs_prop_written(pl->pl_user_prop)) {
1435			sourcetype = ZPROP_SRC_LOCAL;
1436
1437			if (zfs_prop_get_written(zhp, pl->pl_user_prop,
1438			    buf, sizeof (buf), cbp->cb_literal) != 0) {
1439				sourcetype = ZPROP_SRC_NONE;
1440				(void) strlcpy(buf, "-", sizeof (buf));
1441			}
1442
1443			zprop_print_one_property(zfs_get_name(zhp), cbp,
1444			    pl->pl_user_prop, buf, sourcetype, source, NULL);
1445		} else {
1446			if (nvlist_lookup_nvlist(user_props,
1447			    pl->pl_user_prop, &propval) != 0) {
1448				if (pl->pl_all)
1449					continue;
1450				sourcetype = ZPROP_SRC_NONE;
1451				strval = "-";
1452			} else {
1453				verify(nvlist_lookup_string(propval,
1454				    ZPROP_VALUE, &strval) == 0);
1455				verify(nvlist_lookup_string(propval,
1456				    ZPROP_SOURCE, &sourceval) == 0);
1457
1458				if (strcmp(sourceval,
1459				    zfs_get_name(zhp)) == 0) {
1460					sourcetype = ZPROP_SRC_LOCAL;
1461				} else if (strcmp(sourceval,
1462				    ZPROP_SOURCE_VAL_RECVD) == 0) {
1463					sourcetype = ZPROP_SRC_RECEIVED;
1464				} else {
1465					sourcetype = ZPROP_SRC_INHERITED;
1466					(void) strlcpy(source,
1467					    sourceval, sizeof (source));
1468				}
1469			}
1470
1471			if (received && (zfs_prop_get_recvd(zhp,
1472			    pl->pl_user_prop, rbuf, sizeof (rbuf),
1473			    cbp->cb_literal) == 0))
1474				recvdval = rbuf;
1475
1476			zprop_print_one_property(zfs_get_name(zhp), cbp,
1477			    pl->pl_user_prop, strval, sourcetype,
1478			    source, recvdval);
1479		}
1480	}
1481
1482	return (0);
1483}
1484
1485static int
1486zfs_do_get(int argc, char **argv)
1487{
1488	zprop_get_cbdata_t cb = { 0 };
1489	int i, c, flags = ZFS_ITER_ARGS_CAN_BE_PATHS;
1490	int types = ZFS_TYPE_DATASET;
1491	char *value, *fields;
1492	int ret = 0;
1493	int limit = 0;
1494	zprop_list_t fake_name = { 0 };
1495
1496	/*
1497	 * Set up default columns and sources.
1498	 */
1499	cb.cb_sources = ZPROP_SRC_ALL;
1500	cb.cb_columns[0] = GET_COL_NAME;
1501	cb.cb_columns[1] = GET_COL_PROPERTY;
1502	cb.cb_columns[2] = GET_COL_VALUE;
1503	cb.cb_columns[3] = GET_COL_SOURCE;
1504	cb.cb_type = ZFS_TYPE_DATASET;
1505
1506	/* check options */
1507	while ((c = getopt(argc, argv, ":d:o:s:rt:Hp")) != -1) {
1508		switch (c) {
1509		case 'p':
1510			cb.cb_literal = B_TRUE;
1511			break;
1512		case 'd':
1513			limit = parse_depth(optarg, &flags);
1514			break;
1515		case 'r':
1516			flags |= ZFS_ITER_RECURSE;
1517			break;
1518		case 'H':
1519			cb.cb_scripted = B_TRUE;
1520			break;
1521		case ':':
1522			(void) fprintf(stderr, gettext("missing argument for "
1523			    "'%c' option\n"), optopt);
1524			usage(B_FALSE);
1525			break;
1526		case 'o':
1527			/*
1528			 * Process the set of columns to display.  We zero out
1529			 * the structure to give us a blank slate.
1530			 */
1531			bzero(&cb.cb_columns, sizeof (cb.cb_columns));
1532			i = 0;
1533			while (*optarg != '\0') {
1534				static char *col_subopts[] =
1535				    { "name", "property", "value", "received",
1536				    "source", "all", NULL };
1537
1538				if (i == ZFS_GET_NCOLS) {
1539					(void) fprintf(stderr, gettext("too "
1540					    "many fields given to -o "
1541					    "option\n"));
1542					usage(B_FALSE);
1543				}
1544
1545				switch (getsubopt(&optarg, col_subopts,
1546				    &value)) {
1547				case 0:
1548					cb.cb_columns[i++] = GET_COL_NAME;
1549					break;
1550				case 1:
1551					cb.cb_columns[i++] = GET_COL_PROPERTY;
1552					break;
1553				case 2:
1554					cb.cb_columns[i++] = GET_COL_VALUE;
1555					break;
1556				case 3:
1557					cb.cb_columns[i++] = GET_COL_RECVD;
1558					flags |= ZFS_ITER_RECVD_PROPS;
1559					break;
1560				case 4:
1561					cb.cb_columns[i++] = GET_COL_SOURCE;
1562					break;
1563				case 5:
1564					if (i > 0) {
1565						(void) fprintf(stderr,
1566						    gettext("\"all\" conflicts "
1567						    "with specific fields "
1568						    "given to -o option\n"));
1569						usage(B_FALSE);
1570					}
1571					cb.cb_columns[0] = GET_COL_NAME;
1572					cb.cb_columns[1] = GET_COL_PROPERTY;
1573					cb.cb_columns[2] = GET_COL_VALUE;
1574					cb.cb_columns[3] = GET_COL_RECVD;
1575					cb.cb_columns[4] = GET_COL_SOURCE;
1576					flags |= ZFS_ITER_RECVD_PROPS;
1577					i = ZFS_GET_NCOLS;
1578					break;
1579				default:
1580					(void) fprintf(stderr,
1581					    gettext("invalid column name "
1582					    "'%s'\n"), value);
1583					usage(B_FALSE);
1584				}
1585			}
1586			break;
1587
1588		case 's':
1589			cb.cb_sources = 0;
1590			while (*optarg != '\0') {
1591				static char *source_subopts[] = {
1592					"local", "default", "inherited",
1593					"received", "temporary", "none",
1594					NULL };
1595
1596				switch (getsubopt(&optarg, source_subopts,
1597				    &value)) {
1598				case 0:
1599					cb.cb_sources |= ZPROP_SRC_LOCAL;
1600					break;
1601				case 1:
1602					cb.cb_sources |= ZPROP_SRC_DEFAULT;
1603					break;
1604				case 2:
1605					cb.cb_sources |= ZPROP_SRC_INHERITED;
1606					break;
1607				case 3:
1608					cb.cb_sources |= ZPROP_SRC_RECEIVED;
1609					break;
1610				case 4:
1611					cb.cb_sources |= ZPROP_SRC_TEMPORARY;
1612					break;
1613				case 5:
1614					cb.cb_sources |= ZPROP_SRC_NONE;
1615					break;
1616				default:
1617					(void) fprintf(stderr,
1618					    gettext("invalid source "
1619					    "'%s'\n"), value);
1620					usage(B_FALSE);
1621				}
1622			}
1623			break;
1624
1625		case 't':
1626			types = 0;
1627			flags &= ~ZFS_ITER_PROP_LISTSNAPS;
1628			while (*optarg != '\0') {
1629				static char *type_subopts[] = { "filesystem",
1630				    "volume", "snapshot", "all", NULL };
1631
1632				switch (getsubopt(&optarg, type_subopts,
1633				    &value)) {
1634				case 0:
1635					types |= ZFS_TYPE_FILESYSTEM;
1636					break;
1637				case 1:
1638					types |= ZFS_TYPE_VOLUME;
1639					break;
1640				case 2:
1641					types |= ZFS_TYPE_SNAPSHOT;
1642					break;
1643				case 3:
1644					types = ZFS_TYPE_DATASET;
1645					break;
1646
1647				default:
1648					(void) fprintf(stderr,
1649					    gettext("invalid type '%s'\n"),
1650					    value);
1651					usage(B_FALSE);
1652				}
1653			}
1654			break;
1655
1656		case '?':
1657			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1658			    optopt);
1659			usage(B_FALSE);
1660		}
1661	}
1662
1663	argc -= optind;
1664	argv += optind;
1665
1666	if (argc < 1) {
1667		(void) fprintf(stderr, gettext("missing property "
1668		    "argument\n"));
1669		usage(B_FALSE);
1670	}
1671
1672	fields = argv[0];
1673
1674	if (zprop_get_list(g_zfs, fields, &cb.cb_proplist, ZFS_TYPE_DATASET)
1675	    != 0)
1676		usage(B_FALSE);
1677
1678	argc--;
1679	argv++;
1680
1681	/*
1682	 * As part of zfs_expand_proplist(), we keep track of the maximum column
1683	 * width for each property.  For the 'NAME' (and 'SOURCE') columns, we
1684	 * need to know the maximum name length.  However, the user likely did
1685	 * not specify 'name' as one of the properties to fetch, so we need to
1686	 * make sure we always include at least this property for
1687	 * print_get_headers() to work properly.
1688	 */
1689	if (cb.cb_proplist != NULL) {
1690		fake_name.pl_prop = ZFS_PROP_NAME;
1691		fake_name.pl_width = strlen(gettext("NAME"));
1692		fake_name.pl_next = cb.cb_proplist;
1693		cb.cb_proplist = &fake_name;
1694	}
1695
1696	cb.cb_first = B_TRUE;
1697
1698	/* run for each object */
1699	ret = zfs_for_each(argc, argv, flags, types, NULL,
1700	    &cb.cb_proplist, limit, get_callback, &cb);
1701
1702	if (cb.cb_proplist == &fake_name)
1703		zprop_free_list(fake_name.pl_next);
1704	else
1705		zprop_free_list(cb.cb_proplist);
1706
1707	return (ret);
1708}
1709
1710/*
1711 * inherit [-rS] <property> <fs|vol> ...
1712 *
1713 *	-r	Recurse over all children
1714 *	-S	Revert to received value, if any
1715 *
1716 * For each dataset specified on the command line, inherit the given property
1717 * from its parent.  Inheriting a property at the pool level will cause it to
1718 * use the default value.  The '-r' flag will recurse over all children, and is
1719 * useful for setting a property on a hierarchy-wide basis, regardless of any
1720 * local modifications for each dataset.
1721 */
1722
1723typedef struct inherit_cbdata {
1724	const char *cb_propname;
1725	boolean_t cb_received;
1726} inherit_cbdata_t;
1727
1728static int
1729inherit_recurse_cb(zfs_handle_t *zhp, void *data)
1730{
1731	inherit_cbdata_t *cb = data;
1732	zfs_prop_t prop = zfs_name_to_prop(cb->cb_propname);
1733
1734	/*
1735	 * If we're doing it recursively, then ignore properties that
1736	 * are not valid for this type of dataset.
1737	 */
1738	if (prop != ZPROP_INVAL &&
1739	    !zfs_prop_valid_for_type(prop, zfs_get_type(zhp)))
1740		return (0);
1741
1742	return (zfs_prop_inherit(zhp, cb->cb_propname, cb->cb_received) != 0);
1743}
1744
1745static int
1746inherit_cb(zfs_handle_t *zhp, void *data)
1747{
1748	inherit_cbdata_t *cb = data;
1749
1750	return (zfs_prop_inherit(zhp, cb->cb_propname, cb->cb_received) != 0);
1751}
1752
1753static int
1754zfs_do_inherit(int argc, char **argv)
1755{
1756	int c;
1757	zfs_prop_t prop;
1758	inherit_cbdata_t cb = { 0 };
1759	char *propname;
1760	int ret = 0;
1761	int flags = 0;
1762	boolean_t received = B_FALSE;
1763
1764	/* check options */
1765	while ((c = getopt(argc, argv, "rS")) != -1) {
1766		switch (c) {
1767		case 'r':
1768			flags |= ZFS_ITER_RECURSE;
1769			break;
1770		case 'S':
1771			received = B_TRUE;
1772			break;
1773		case '?':
1774		default:
1775			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1776			    optopt);
1777			usage(B_FALSE);
1778		}
1779	}
1780
1781	argc -= optind;
1782	argv += optind;
1783
1784	/* check number of arguments */
1785	if (argc < 1) {
1786		(void) fprintf(stderr, gettext("missing property argument\n"));
1787		usage(B_FALSE);
1788	}
1789	if (argc < 2) {
1790		(void) fprintf(stderr, gettext("missing dataset argument\n"));
1791		usage(B_FALSE);
1792	}
1793
1794	propname = argv[0];
1795	argc--;
1796	argv++;
1797
1798	if ((prop = zfs_name_to_prop(propname)) != ZPROP_INVAL) {
1799		if (zfs_prop_readonly(prop)) {
1800			(void) fprintf(stderr, gettext(
1801			    "%s property is read-only\n"),
1802			    propname);
1803			return (1);
1804		}
1805		if (!zfs_prop_inheritable(prop) && !received) {
1806			(void) fprintf(stderr, gettext("'%s' property cannot "
1807			    "be inherited\n"), propname);
1808			if (prop == ZFS_PROP_QUOTA ||
1809			    prop == ZFS_PROP_RESERVATION ||
1810			    prop == ZFS_PROP_REFQUOTA ||
1811			    prop == ZFS_PROP_REFRESERVATION)
1812				(void) fprintf(stderr, gettext("use 'zfs set "
1813				    "%s=none' to clear\n"), propname);
1814			return (1);
1815		}
1816		if (received && (prop == ZFS_PROP_VOLSIZE ||
1817		    prop == ZFS_PROP_VERSION)) {
1818			(void) fprintf(stderr, gettext("'%s' property cannot "
1819			    "be reverted to a received value\n"), propname);
1820			return (1);
1821		}
1822	} else if (!zfs_prop_user(propname)) {
1823		(void) fprintf(stderr, gettext("invalid property '%s'\n"),
1824		    propname);
1825		usage(B_FALSE);
1826	}
1827
1828	cb.cb_propname = propname;
1829	cb.cb_received = received;
1830
1831	if (flags & ZFS_ITER_RECURSE) {
1832		ret = zfs_for_each(argc, argv, flags, ZFS_TYPE_DATASET,
1833		    NULL, NULL, 0, inherit_recurse_cb, &cb);
1834	} else {
1835		ret = zfs_for_each(argc, argv, flags, ZFS_TYPE_DATASET,
1836		    NULL, NULL, 0, inherit_cb, &cb);
1837	}
1838
1839	return (ret);
1840}
1841
1842typedef struct upgrade_cbdata {
1843	uint64_t cb_numupgraded;
1844	uint64_t cb_numsamegraded;
1845	uint64_t cb_numfailed;
1846	uint64_t cb_version;
1847	boolean_t cb_newer;
1848	boolean_t cb_foundone;
1849	char cb_lastfs[ZFS_MAXNAMELEN];
1850} upgrade_cbdata_t;
1851
1852static int
1853same_pool(zfs_handle_t *zhp, const char *name)
1854{
1855	int len1 = strcspn(name, "/@");
1856	const char *zhname = zfs_get_name(zhp);
1857	int len2 = strcspn(zhname, "/@");
1858
1859	if (len1 != len2)
1860		return (B_FALSE);
1861	return (strncmp(name, zhname, len1) == 0);
1862}
1863
1864static int
1865upgrade_list_callback(zfs_handle_t *zhp, void *data)
1866{
1867	upgrade_cbdata_t *cb = data;
1868	int version = zfs_prop_get_int(zhp, ZFS_PROP_VERSION);
1869
1870	/* list if it's old/new */
1871	if ((!cb->cb_newer && version < ZPL_VERSION) ||
1872	    (cb->cb_newer && version > ZPL_VERSION)) {
1873		char *str;
1874		if (cb->cb_newer) {
1875			str = gettext("The following filesystems are "
1876			    "formatted using a newer software version and\n"
1877			    "cannot be accessed on the current system.\n\n");
1878		} else {
1879			str = gettext("The following filesystems are "
1880			    "out of date, and can be upgraded.  After being\n"
1881			    "upgraded, these filesystems (and any 'zfs send' "
1882			    "streams generated from\n"
1883			    "subsequent snapshots) will no longer be "
1884			    "accessible by older software versions.\n\n");
1885		}
1886
1887		if (!cb->cb_foundone) {
1888			(void) puts(str);
1889			(void) printf(gettext("VER  FILESYSTEM\n"));
1890			(void) printf(gettext("---  ------------\n"));
1891			cb->cb_foundone = B_TRUE;
1892		}
1893
1894		(void) printf("%2u   %s\n", version, zfs_get_name(zhp));
1895	}
1896
1897	return (0);
1898}
1899
1900static int
1901upgrade_set_callback(zfs_handle_t *zhp, void *data)
1902{
1903	upgrade_cbdata_t *cb = data;
1904	int version = zfs_prop_get_int(zhp, ZFS_PROP_VERSION);
1905	int needed_spa_version;
1906	int spa_version;
1907
1908	if (zfs_spa_version(zhp, &spa_version) < 0)
1909		return (-1);
1910
1911	needed_spa_version = zfs_spa_version_map(cb->cb_version);
1912
1913	if (needed_spa_version < 0)
1914		return (-1);
1915
1916	if (spa_version < needed_spa_version) {
1917		/* can't upgrade */
1918		(void) printf(gettext("%s: can not be "
1919		    "upgraded; the pool version needs to first "
1920		    "be upgraded\nto version %d\n\n"),
1921		    zfs_get_name(zhp), needed_spa_version);
1922		cb->cb_numfailed++;
1923		return (0);
1924	}
1925
1926	/* upgrade */
1927	if (version < cb->cb_version) {
1928		char verstr[16];
1929		(void) snprintf(verstr, sizeof (verstr),
1930		    "%llu", cb->cb_version);
1931		if (cb->cb_lastfs[0] && !same_pool(zhp, cb->cb_lastfs)) {
1932			/*
1933			 * If they did "zfs upgrade -a", then we could
1934			 * be doing ioctls to different pools.  We need
1935			 * to log this history once to each pool.
1936			 */
1937			verify(zpool_stage_history(g_zfs, history_str) == 0);
1938		}
1939		if (zfs_prop_set(zhp, "version", verstr) == 0)
1940			cb->cb_numupgraded++;
1941		else
1942			cb->cb_numfailed++;
1943		(void) strcpy(cb->cb_lastfs, zfs_get_name(zhp));
1944	} else if (version > cb->cb_version) {
1945		/* can't downgrade */
1946		(void) printf(gettext("%s: can not be downgraded; "
1947		    "it is already at version %u\n"),
1948		    zfs_get_name(zhp), version);
1949		cb->cb_numfailed++;
1950	} else {
1951		cb->cb_numsamegraded++;
1952	}
1953	return (0);
1954}
1955
1956/*
1957 * zfs upgrade
1958 * zfs upgrade -v
1959 * zfs upgrade [-r] [-V <version>] <-a | filesystem>
1960 */
1961static int
1962zfs_do_upgrade(int argc, char **argv)
1963{
1964	boolean_t all = B_FALSE;
1965	boolean_t showversions = B_FALSE;
1966	int ret = 0;
1967	upgrade_cbdata_t cb = { 0 };
1968	char c;
1969	int flags = ZFS_ITER_ARGS_CAN_BE_PATHS;
1970
1971	/* check options */
1972	while ((c = getopt(argc, argv, "rvV:a")) != -1) {
1973		switch (c) {
1974		case 'r':
1975			flags |= ZFS_ITER_RECURSE;
1976			break;
1977		case 'v':
1978			showversions = B_TRUE;
1979			break;
1980		case 'V':
1981			if (zfs_prop_string_to_index(ZFS_PROP_VERSION,
1982			    optarg, &cb.cb_version) != 0) {
1983				(void) fprintf(stderr,
1984				    gettext("invalid version %s\n"), optarg);
1985				usage(B_FALSE);
1986			}
1987			break;
1988		case 'a':
1989			all = B_TRUE;
1990			break;
1991		case '?':
1992		default:
1993			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1994			    optopt);
1995			usage(B_FALSE);
1996		}
1997	}
1998
1999	argc -= optind;
2000	argv += optind;
2001
2002	if ((!all && !argc) && ((flags & ZFS_ITER_RECURSE) | cb.cb_version))
2003		usage(B_FALSE);
2004	if (showversions && (flags & ZFS_ITER_RECURSE || all ||
2005	    cb.cb_version || argc))
2006		usage(B_FALSE);
2007	if ((all || argc) && (showversions))
2008		usage(B_FALSE);
2009	if (all && argc)
2010		usage(B_FALSE);
2011
2012	if (showversions) {
2013		/* Show info on available versions. */
2014		(void) printf(gettext("The following filesystem versions are "
2015		    "supported:\n\n"));
2016		(void) printf(gettext("VER  DESCRIPTION\n"));
2017		(void) printf("---  -----------------------------------------"
2018		    "---------------\n");
2019		(void) printf(gettext(" 1   Initial ZFS filesystem version\n"));
2020		(void) printf(gettext(" 2   Enhanced directory entries\n"));
2021		(void) printf(gettext(" 3   Case insensitive and filesystem "
2022		    "user identifier (FUID)\n"));
2023		(void) printf(gettext(" 4   userquota, groupquota "
2024		    "properties\n"));
2025		(void) printf(gettext(" 5   System attributes\n"));
2026		(void) printf(gettext("\nFor more information on a particular "
2027		    "version, including supported releases,\n"));
2028		(void) printf("see the ZFS Administration Guide.\n\n");
2029		ret = 0;
2030	} else if (argc || all) {
2031		/* Upgrade filesystems */
2032		if (cb.cb_version == 0)
2033			cb.cb_version = ZPL_VERSION;
2034		ret = zfs_for_each(argc, argv, flags, ZFS_TYPE_FILESYSTEM,
2035		    NULL, NULL, 0, upgrade_set_callback, &cb);
2036		(void) printf(gettext("%llu filesystems upgraded\n"),
2037		    cb.cb_numupgraded);
2038		if (cb.cb_numsamegraded) {
2039			(void) printf(gettext("%llu filesystems already at "
2040			    "this version\n"),
2041			    cb.cb_numsamegraded);
2042		}
2043		if (cb.cb_numfailed != 0)
2044			ret = 1;
2045	} else {
2046		/* List old-version filesytems */
2047		boolean_t found;
2048		(void) printf(gettext("This system is currently running "
2049		    "ZFS filesystem version %llu.\n\n"), ZPL_VERSION);
2050
2051		flags |= ZFS_ITER_RECURSE;
2052		ret = zfs_for_each(0, NULL, flags, ZFS_TYPE_FILESYSTEM,
2053		    NULL, NULL, 0, upgrade_list_callback, &cb);
2054
2055		found = cb.cb_foundone;
2056		cb.cb_foundone = B_FALSE;
2057		cb.cb_newer = B_TRUE;
2058
2059		ret = zfs_for_each(0, NULL, flags, ZFS_TYPE_FILESYSTEM,
2060		    NULL, NULL, 0, upgrade_list_callback, &cb);
2061
2062		if (!cb.cb_foundone && !found) {
2063			(void) printf(gettext("All filesystems are "
2064			    "formatted with the current version.\n"));
2065		}
2066	}
2067
2068	return (ret);
2069}
2070
2071/*
2072 * zfs userspace [-Hinp] [-o field[,...]] [-s field [-s field]...]
2073 *               [-S field [-S field]...] [-t type[,...]] filesystem | snapshot
2074 * zfs groupspace [-Hinp] [-o field[,...]] [-s field [-s field]...]
2075 *                [-S field [-S field]...] [-t type[,...]] filesystem | snapshot
2076 *
2077 *	-H      Scripted mode; elide headers and separate columns by tabs.
2078 *	-i	Translate SID to POSIX ID.
2079 *	-n	Print numeric ID instead of user/group name.
2080 *	-o      Control which fields to display.
2081 *	-p	Use exact (parseable) numeric output.
2082 *	-s      Specify sort columns, descending order.
2083 *	-S      Specify sort columns, ascending order.
2084 *	-t      Control which object types to display.
2085 *
2086 *	Displays space consumed by, and quotas on, each user in the specified
2087 *	filesystem or snapshot.
2088 */
2089
2090/* us_field_types, us_field_hdr and us_field_names should be kept in sync */
2091enum us_field_types {
2092	USFIELD_TYPE,
2093	USFIELD_NAME,
2094	USFIELD_USED,
2095	USFIELD_QUOTA
2096};
2097static char *us_field_hdr[] = { "TYPE", "NAME", "USED", "QUOTA" };
2098static char *us_field_names[] = { "type", "name", "used", "quota" };
2099#define	USFIELD_LAST	(sizeof (us_field_names) / sizeof (char *))
2100
2101#define	USTYPE_PSX_GRP	(1 << 0)
2102#define	USTYPE_PSX_USR	(1 << 1)
2103#define	USTYPE_SMB_GRP	(1 << 2)
2104#define	USTYPE_SMB_USR	(1 << 3)
2105#define	USTYPE_ALL	\
2106	(USTYPE_PSX_GRP | USTYPE_PSX_USR | USTYPE_SMB_GRP | USTYPE_SMB_USR)
2107
2108static int us_type_bits[] = {
2109	USTYPE_PSX_GRP,
2110	USTYPE_PSX_USR,
2111	USTYPE_SMB_GRP,
2112	USTYPE_SMB_USR,
2113	USTYPE_ALL
2114};
2115static char *us_type_names[] = { "posixgroup", "posxiuser", "smbgroup",
2116	"smbuser", "all" };
2117
2118typedef struct us_node {
2119	nvlist_t	*usn_nvl;
2120	uu_avl_node_t	usn_avlnode;
2121	uu_list_node_t	usn_listnode;
2122} us_node_t;
2123
2124typedef struct us_cbdata {
2125	nvlist_t	**cb_nvlp;
2126	uu_avl_pool_t	*cb_avl_pool;
2127	uu_avl_t	*cb_avl;
2128	boolean_t	cb_numname;
2129	boolean_t	cb_nicenum;
2130	boolean_t	cb_sid2posix;
2131	zfs_userquota_prop_t cb_prop;
2132	zfs_sort_column_t *cb_sortcol;
2133	size_t		cb_width[USFIELD_LAST];
2134} us_cbdata_t;
2135
2136static boolean_t us_populated = B_FALSE;
2137
2138typedef struct {
2139	zfs_sort_column_t *si_sortcol;
2140	boolean_t	si_numname;
2141} us_sort_info_t;
2142
2143static int
2144us_field_index(char *field)
2145{
2146	int i;
2147
2148	for (i = 0; i < USFIELD_LAST; i++) {
2149		if (strcmp(field, us_field_names[i]) == 0)
2150			return (i);
2151	}
2152
2153	return (-1);
2154}
2155
2156static int
2157us_compare(const void *larg, const void *rarg, void *unused)
2158{
2159	const us_node_t *l = larg;
2160	const us_node_t *r = rarg;
2161	us_sort_info_t *si = (us_sort_info_t *)unused;
2162	zfs_sort_column_t *sortcol = si->si_sortcol;
2163	boolean_t numname = si->si_numname;
2164	nvlist_t *lnvl = l->usn_nvl;
2165	nvlist_t *rnvl = r->usn_nvl;
2166	int rc = 0;
2167	boolean_t lvb, rvb;
2168
2169	for (; sortcol != NULL; sortcol = sortcol->sc_next) {
2170		char *lvstr = "";
2171		char *rvstr = "";
2172		uint32_t lv32 = 0;
2173		uint32_t rv32 = 0;
2174		uint64_t lv64 = 0;
2175		uint64_t rv64 = 0;
2176		zfs_prop_t prop = sortcol->sc_prop;
2177		const char *propname = NULL;
2178		boolean_t reverse = sortcol->sc_reverse;
2179
2180		switch (prop) {
2181		case ZFS_PROP_TYPE:
2182			propname = "type";
2183			(void) nvlist_lookup_uint32(lnvl, propname, &lv32);
2184			(void) nvlist_lookup_uint32(rnvl, propname, &rv32);
2185			if (rv32 != lv32)
2186				rc = (rv32 < lv32) ? 1 : -1;
2187			break;
2188		case ZFS_PROP_NAME:
2189			propname = "name";
2190			if (numname) {
2191				(void) nvlist_lookup_uint64(lnvl, propname,
2192				    &lv64);
2193				(void) nvlist_lookup_uint64(rnvl, propname,
2194				    &rv64);
2195				if (rv64 != lv64)
2196					rc = (rv64 < lv64) ? 1 : -1;
2197			} else {
2198				(void) nvlist_lookup_string(lnvl, propname,
2199				    &lvstr);
2200				(void) nvlist_lookup_string(rnvl, propname,
2201				    &rvstr);
2202				rc = strcmp(lvstr, rvstr);
2203			}
2204			break;
2205		case ZFS_PROP_USED:
2206		case ZFS_PROP_QUOTA:
2207			if (!us_populated)
2208				break;
2209			if (prop == ZFS_PROP_USED)
2210				propname = "used";
2211			else
2212				propname = "quota";
2213			(void) nvlist_lookup_uint64(lnvl, propname, &lv64);
2214			(void) nvlist_lookup_uint64(rnvl, propname, &rv64);
2215			if (rv64 != lv64)
2216				rc = (rv64 < lv64) ? 1 : -1;
2217			break;
2218		}
2219
2220		if (rc != 0) {
2221			if (rc < 0)
2222				return (reverse ? 1 : -1);
2223			else
2224				return (reverse ? -1 : 1);
2225		}
2226	}
2227
2228	/*
2229	 * If entries still seem to be the same, check if they are of the same
2230	 * type (smbentity is added only if we are doing SID to POSIX ID
2231	 * translation where we can have duplicate type/name combinations).
2232	 */
2233	if (nvlist_lookup_boolean_value(lnvl, "smbentity", &lvb) == 0 &&
2234	    nvlist_lookup_boolean_value(rnvl, "smbentity", &rvb) == 0 &&
2235	    lvb != rvb)
2236		return (lvb < rvb ? -1 : 1);
2237
2238	return (0);
2239}
2240
2241static inline const char *
2242us_type2str(unsigned field_type)
2243{
2244	switch (field_type) {
2245	case USTYPE_PSX_USR:
2246		return ("POSIX User");
2247	case USTYPE_PSX_GRP:
2248		return ("POSIX Group");
2249	case USTYPE_SMB_USR:
2250		return ("SMB User");
2251	case USTYPE_SMB_GRP:
2252		return ("SMB Group");
2253	default:
2254		return ("Undefined");
2255	}
2256}
2257
2258static int
2259userspace_cb(void *arg, const char *domain, uid_t rid, uint64_t space)
2260{
2261	us_cbdata_t *cb = (us_cbdata_t *)arg;
2262	zfs_userquota_prop_t prop = cb->cb_prop;
2263	char *name = NULL;
2264	char *propname;
2265	char sizebuf[32];
2266	us_node_t *node;
2267	uu_avl_pool_t *avl_pool = cb->cb_avl_pool;
2268	uu_avl_t *avl = cb->cb_avl;
2269	uu_avl_index_t idx;
2270	nvlist_t *props;
2271	us_node_t *n;
2272	zfs_sort_column_t *sortcol = cb->cb_sortcol;
2273	unsigned type;
2274	const char *typestr;
2275	size_t namelen;
2276	size_t typelen;
2277	size_t sizelen;
2278	int typeidx, nameidx, sizeidx;
2279	us_sort_info_t sortinfo = { sortcol, cb->cb_numname };
2280	boolean_t smbentity = B_FALSE;
2281
2282	if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0)
2283		nomem();
2284	node = safe_malloc(sizeof (us_node_t));
2285	uu_avl_node_init(node, &node->usn_avlnode, avl_pool);
2286	node->usn_nvl = props;
2287
2288	if (domain != NULL && domain[0] != '\0') {
2289		/* SMB */
2290		char sid[ZFS_MAXNAMELEN + 32];
2291		uid_t id;
2292		uint64_t classes;
2293#ifdef sun
2294		int err;
2295		directory_error_t e;
2296#endif
2297
2298		smbentity = B_TRUE;
2299
2300		(void) snprintf(sid, sizeof (sid), "%s-%u", domain, rid);
2301
2302		if (prop == ZFS_PROP_GROUPUSED || prop == ZFS_PROP_GROUPQUOTA) {
2303			type = USTYPE_SMB_GRP;
2304#ifdef sun
2305			err = sid_to_id(sid, B_FALSE, &id);
2306#endif
2307		} else {
2308			type = USTYPE_SMB_USR;
2309#ifdef sun
2310			err = sid_to_id(sid, B_TRUE, &id);
2311#endif
2312		}
2313
2314#ifdef sun
2315		if (err == 0) {
2316			rid = id;
2317			if (!cb->cb_sid2posix) {
2318				e = directory_name_from_sid(NULL, sid, &name,
2319				    &classes);
2320				if (e != NULL)
2321					directory_error_free(e);
2322				if (name == NULL)
2323					name = sid;
2324			}
2325		}
2326#endif
2327	}
2328
2329	if (cb->cb_sid2posix || domain == NULL || domain[0] == '\0') {
2330		/* POSIX or -i */
2331		if (prop == ZFS_PROP_GROUPUSED || prop == ZFS_PROP_GROUPQUOTA) {
2332			type = USTYPE_PSX_GRP;
2333			if (!cb->cb_numname) {
2334				struct group *g;
2335
2336				if ((g = getgrgid(rid)) != NULL)
2337					name = g->gr_name;
2338			}
2339		} else {
2340			type = USTYPE_PSX_USR;
2341			if (!cb->cb_numname) {
2342				struct passwd *p;
2343
2344				if ((p = getpwuid(rid)) != NULL)
2345					name = p->pw_name;
2346			}
2347		}
2348	}
2349
2350	/*
2351	 * Make sure that the type/name combination is unique when doing
2352	 * SID to POSIX ID translation (hence changing the type from SMB to
2353	 * POSIX).
2354	 */
2355	if (cb->cb_sid2posix &&
2356	    nvlist_add_boolean_value(props, "smbentity", smbentity) != 0)
2357		nomem();
2358
2359	/* Calculate/update width of TYPE field */
2360	typestr = us_type2str(type);
2361	typelen = strlen(gettext(typestr));
2362	typeidx = us_field_index("type");
2363	if (typelen > cb->cb_width[typeidx])
2364		cb->cb_width[typeidx] = typelen;
2365	if (nvlist_add_uint32(props, "type", type) != 0)
2366		nomem();
2367
2368	/* Calculate/update width of NAME field */
2369	if ((cb->cb_numname && cb->cb_sid2posix) || name == NULL) {
2370		if (nvlist_add_uint64(props, "name", rid) != 0)
2371			nomem();
2372		namelen = snprintf(NULL, 0, "%u", rid);
2373	} else {
2374		if (nvlist_add_string(props, "name", name) != 0)
2375			nomem();
2376		namelen = strlen(name);
2377	}
2378	nameidx = us_field_index("name");
2379	if (namelen > cb->cb_width[nameidx])
2380		cb->cb_width[nameidx] = namelen;
2381
2382	/*
2383	 * Check if this type/name combination is in the list and update it;
2384	 * otherwise add new node to the list.
2385	 */
2386	if ((n = uu_avl_find(avl, node, &sortinfo, &idx)) == NULL) {
2387		uu_avl_insert(avl, node, idx);
2388	} else {
2389		nvlist_free(props);
2390		free(node);
2391		node = n;
2392		props = node->usn_nvl;
2393	}
2394
2395	/* Calculate/update width of USED/QUOTA fields */
2396	if (cb->cb_nicenum)
2397		zfs_nicenum(space, sizebuf, sizeof (sizebuf));
2398	else
2399		(void) snprintf(sizebuf, sizeof (sizebuf), "%llu", space);
2400	sizelen = strlen(sizebuf);
2401	if (prop == ZFS_PROP_USERUSED || prop == ZFS_PROP_GROUPUSED) {
2402		propname = "used";
2403		if (!nvlist_exists(props, "quota"))
2404			(void) nvlist_add_uint64(props, "quota", 0);
2405	} else {
2406		propname = "quota";
2407		if (!nvlist_exists(props, "used"))
2408			(void) nvlist_add_uint64(props, "used", 0);
2409	}
2410	sizeidx = us_field_index(propname);
2411	if (sizelen > cb->cb_width[sizeidx])
2412		cb->cb_width[sizeidx] = sizelen;
2413
2414	if (nvlist_add_uint64(props, propname, space) != 0)
2415		nomem();
2416
2417	return (0);
2418}
2419
2420static void
2421print_us_node(boolean_t scripted, boolean_t parsable, int *fields, int types,
2422    size_t *width, us_node_t *node)
2423{
2424	nvlist_t *nvl = node->usn_nvl;
2425	char valstr[ZFS_MAXNAMELEN];
2426	boolean_t first = B_TRUE;
2427	int cfield = 0;
2428	int field;
2429	uint32_t ustype;
2430
2431	/* Check type */
2432	(void) nvlist_lookup_uint32(nvl, "type", &ustype);
2433	if (!(ustype & types))
2434		return;
2435
2436	while ((field = fields[cfield]) != USFIELD_LAST) {
2437		nvpair_t *nvp = NULL;
2438		data_type_t type;
2439		uint32_t val32;
2440		uint64_t val64;
2441		char *strval = NULL;
2442
2443		while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
2444			if (strcmp(nvpair_name(nvp),
2445			    us_field_names[field]) == 0)
2446				break;
2447		}
2448
2449		type = nvpair_type(nvp);
2450		switch (type) {
2451		case DATA_TYPE_UINT32:
2452			(void) nvpair_value_uint32(nvp, &val32);
2453			break;
2454		case DATA_TYPE_UINT64:
2455			(void) nvpair_value_uint64(nvp, &val64);
2456			break;
2457		case DATA_TYPE_STRING:
2458			(void) nvpair_value_string(nvp, &strval);
2459			break;
2460		default:
2461			(void) fprintf(stderr, "invalid data type\n");
2462		}
2463
2464		switch (field) {
2465		case USFIELD_TYPE:
2466			strval = (char *)us_type2str(val32);
2467			break;
2468		case USFIELD_NAME:
2469			if (type == DATA_TYPE_UINT64) {
2470				(void) sprintf(valstr, "%llu", val64);
2471				strval = valstr;
2472			}
2473			break;
2474		case USFIELD_USED:
2475		case USFIELD_QUOTA:
2476			if (type == DATA_TYPE_UINT64) {
2477				if (parsable) {
2478					(void) sprintf(valstr, "%llu", val64);
2479				} else {
2480					zfs_nicenum(val64, valstr,
2481					    sizeof (valstr));
2482				}
2483				if (field == USFIELD_QUOTA &&
2484				    strcmp(valstr, "0") == 0)
2485					strval = "none";
2486				else
2487					strval = valstr;
2488			}
2489			break;
2490		}
2491
2492		if (!first) {
2493			if (scripted)
2494				(void) printf("\t");
2495			else
2496				(void) printf("  ");
2497		}
2498		if (scripted)
2499			(void) printf("%s", strval);
2500		else if (field == USFIELD_TYPE || field == USFIELD_NAME)
2501			(void) printf("%-*s", width[field], strval);
2502		else
2503			(void) printf("%*s", width[field], strval);
2504
2505		first = B_FALSE;
2506		cfield++;
2507	}
2508
2509	(void) printf("\n");
2510}
2511
2512static void
2513print_us(boolean_t scripted, boolean_t parsable, int *fields, int types,
2514    size_t *width, boolean_t rmnode, uu_avl_t *avl)
2515{
2516	us_node_t *node;
2517	const char *col;
2518	int cfield = 0;
2519	int field;
2520
2521	if (!scripted) {
2522		boolean_t first = B_TRUE;
2523
2524		while ((field = fields[cfield]) != USFIELD_LAST) {
2525			col = gettext(us_field_hdr[field]);
2526			if (field == USFIELD_TYPE || field == USFIELD_NAME) {
2527				(void) printf(first ? "%-*s" : "  %-*s",
2528				    width[field], col);
2529			} else {
2530				(void) printf(first ? "%*s" : "  %*s",
2531				    width[field], col);
2532			}
2533			first = B_FALSE;
2534			cfield++;
2535		}
2536		(void) printf("\n");
2537	}
2538
2539	for (node = uu_avl_first(avl); node; node = uu_avl_next(avl, node)) {
2540		print_us_node(scripted, parsable, fields, types, width, node);
2541		if (rmnode)
2542			nvlist_free(node->usn_nvl);
2543	}
2544}
2545
2546static int
2547zfs_do_userspace(int argc, char **argv)
2548{
2549	zfs_handle_t *zhp;
2550	zfs_userquota_prop_t p;
2551
2552	uu_avl_pool_t *avl_pool;
2553	uu_avl_t *avl_tree;
2554	uu_avl_walk_t *walk;
2555	char *delim;
2556	char deffields[] = "type,name,used,quota";
2557	char *ofield = NULL;
2558	char *tfield = NULL;
2559	int cfield = 0;
2560	int fields[256];
2561	int i;
2562	boolean_t scripted = B_FALSE;
2563	boolean_t prtnum = B_FALSE;
2564	boolean_t parsable = B_FALSE;
2565	boolean_t sid2posix = B_FALSE;
2566	int ret = 0;
2567	int c;
2568	zfs_sort_column_t *sortcol = NULL;
2569	int types = USTYPE_PSX_USR | USTYPE_SMB_USR;
2570	us_cbdata_t cb;
2571	us_node_t *node;
2572	us_node_t *rmnode;
2573	uu_list_pool_t *listpool;
2574	uu_list_t *list;
2575	uu_avl_index_t idx = 0;
2576	uu_list_index_t idx2 = 0;
2577
2578	if (argc < 2)
2579		usage(B_FALSE);
2580
2581	if (strcmp(argv[0], "groupspace") == 0)
2582		/* Toggle default group types */
2583		types = USTYPE_PSX_GRP | USTYPE_SMB_GRP;
2584
2585	while ((c = getopt(argc, argv, "nHpo:s:S:t:i")) != -1) {
2586		switch (c) {
2587		case 'n':
2588			prtnum = B_TRUE;
2589			break;
2590		case 'H':
2591			scripted = B_TRUE;
2592			break;
2593		case 'p':
2594			parsable = B_TRUE;
2595			break;
2596		case 'o':
2597			ofield = optarg;
2598			break;
2599		case 's':
2600		case 'S':
2601			if (zfs_add_sort_column(&sortcol, optarg,
2602			    c == 's' ? B_FALSE : B_TRUE) != 0) {
2603				(void) fprintf(stderr,
2604				    gettext("invalid field '%s'\n"), optarg);
2605				usage(B_FALSE);
2606			}
2607			break;
2608		case 't':
2609			tfield = optarg;
2610			break;
2611		case 'i':
2612			sid2posix = B_TRUE;
2613			break;
2614		case ':':
2615			(void) fprintf(stderr, gettext("missing argument for "
2616			    "'%c' option\n"), optopt);
2617			usage(B_FALSE);
2618			break;
2619		case '?':
2620			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2621			    optopt);
2622			usage(B_FALSE);
2623		}
2624	}
2625
2626	argc -= optind;
2627	argv += optind;
2628
2629	if (argc < 1) {
2630		(void) fprintf(stderr, gettext("missing dataset name\n"));
2631		usage(B_FALSE);
2632	}
2633	if (argc > 1) {
2634		(void) fprintf(stderr, gettext("too many arguments\n"));
2635		usage(B_FALSE);
2636	}
2637
2638	/* Use default output fields if not specified using -o */
2639	if (ofield == NULL)
2640		ofield = deffields;
2641	do {
2642		if ((delim = strchr(ofield, ',')) != NULL)
2643			*delim = '\0';
2644		if ((fields[cfield++] = us_field_index(ofield)) == -1) {
2645			(void) fprintf(stderr, gettext("invalid type '%s' "
2646			    "for -o option\n"), ofield);
2647			return (-1);
2648		}
2649		if (delim != NULL)
2650			ofield = delim + 1;
2651	} while (delim != NULL);
2652	fields[cfield] = USFIELD_LAST;
2653
2654	/* Override output types (-t option) */
2655	if (tfield != NULL) {
2656		types = 0;
2657
2658		do {
2659			boolean_t found = B_FALSE;
2660
2661			if ((delim = strchr(tfield, ',')) != NULL)
2662				*delim = '\0';
2663			for (i = 0; i < sizeof (us_type_bits) / sizeof (int);
2664			    i++) {
2665				if (strcmp(tfield, us_type_names[i]) == 0) {
2666					found = B_TRUE;
2667					types |= us_type_bits[i];
2668					break;
2669				}
2670			}
2671			if (!found) {
2672				(void) fprintf(stderr, gettext("invalid type "
2673				    "'%s' for -t option\n"), tfield);
2674				return (-1);
2675			}
2676			if (delim != NULL)
2677				tfield = delim + 1;
2678		} while (delim != NULL);
2679	}
2680
2681	if ((zhp = zfs_open(g_zfs, argv[0], ZFS_TYPE_DATASET)) == NULL)
2682		return (1);
2683
2684	if ((avl_pool = uu_avl_pool_create("us_avl_pool", sizeof (us_node_t),
2685	    offsetof(us_node_t, usn_avlnode), us_compare, UU_DEFAULT)) == NULL)
2686		nomem();
2687	if ((avl_tree = uu_avl_create(avl_pool, NULL, UU_DEFAULT)) == NULL)
2688		nomem();
2689
2690	/* Always add default sorting columns */
2691	(void) zfs_add_sort_column(&sortcol, "type", B_FALSE);
2692	(void) zfs_add_sort_column(&sortcol, "name", B_FALSE);
2693
2694	cb.cb_sortcol = sortcol;
2695	cb.cb_numname = prtnum;
2696	cb.cb_nicenum = !parsable;
2697	cb.cb_avl_pool = avl_pool;
2698	cb.cb_avl = avl_tree;
2699	cb.cb_sid2posix = sid2posix;
2700
2701	for (i = 0; i < USFIELD_LAST; i++)
2702		cb.cb_width[i] = strlen(gettext(us_field_hdr[i]));
2703
2704	for (p = 0; p < ZFS_NUM_USERQUOTA_PROPS; p++) {
2705		if (((p == ZFS_PROP_USERUSED || p == ZFS_PROP_USERQUOTA) &&
2706		    !(types & (USTYPE_PSX_USR | USTYPE_SMB_USR))) ||
2707		    ((p == ZFS_PROP_GROUPUSED || p == ZFS_PROP_GROUPQUOTA) &&
2708		    !(types & (USTYPE_PSX_GRP | USTYPE_SMB_GRP))))
2709			continue;
2710		cb.cb_prop = p;
2711		if ((ret = zfs_userspace(zhp, p, userspace_cb, &cb)) != 0)
2712			return (ret);
2713	}
2714
2715	/* Sort the list */
2716	if ((node = uu_avl_first(avl_tree)) == NULL)
2717		return (0);
2718
2719	us_populated = B_TRUE;
2720
2721	listpool = uu_list_pool_create("tmplist", sizeof (us_node_t),
2722	    offsetof(us_node_t, usn_listnode), NULL, UU_DEFAULT);
2723	list = uu_list_create(listpool, NULL, UU_DEFAULT);
2724	uu_list_node_init(node, &node->usn_listnode, listpool);
2725
2726	while (node != NULL) {
2727		rmnode = node;
2728		node = uu_avl_next(avl_tree, node);
2729		uu_avl_remove(avl_tree, rmnode);
2730		if (uu_list_find(list, rmnode, NULL, &idx2) == NULL)
2731			uu_list_insert(list, rmnode, idx2);
2732	}
2733
2734	for (node = uu_list_first(list); node != NULL;
2735	    node = uu_list_next(list, node)) {
2736		us_sort_info_t sortinfo = { sortcol, cb.cb_numname };
2737
2738		if (uu_avl_find(avl_tree, node, &sortinfo, &idx) == NULL)
2739			uu_avl_insert(avl_tree, node, idx);
2740	}
2741
2742	uu_list_destroy(list);
2743	uu_list_pool_destroy(listpool);
2744
2745	/* Print and free node nvlist memory */
2746	print_us(scripted, parsable, fields, types, cb.cb_width, B_TRUE,
2747	    cb.cb_avl);
2748
2749	zfs_free_sort_columns(sortcol);
2750
2751	/* Clean up the AVL tree */
2752	if ((walk = uu_avl_walk_start(cb.cb_avl, UU_WALK_ROBUST)) == NULL)
2753		nomem();
2754
2755	while ((node = uu_avl_walk_next(walk)) != NULL) {
2756		uu_avl_remove(cb.cb_avl, node);
2757		free(node);
2758	}
2759
2760	uu_avl_walk_end(walk);
2761	uu_avl_destroy(avl_tree);
2762	uu_avl_pool_destroy(avl_pool);
2763
2764	return (ret);
2765}
2766
2767/*
2768 * list [-r][-d max] [-H] [-o property[,property]...] [-t type[,type]...]
2769 *      [-s property [-s property]...] [-S property [-S property]...]
2770 *      <dataset> ...
2771 *
2772 *	-r	Recurse over all children
2773 *	-d	Limit recursion by depth.
2774 *	-H	Scripted mode; elide headers and separate columns by tabs
2775 *	-o	Control which fields to display.
2776 *	-t	Control which object types to display.
2777 *	-s	Specify sort columns, descending order.
2778 *	-S	Specify sort columns, ascending order.
2779 *
2780 * When given no arguments, lists all filesystems in the system.
2781 * Otherwise, list the specified datasets, optionally recursing down them if
2782 * '-r' is specified.
2783 */
2784typedef struct list_cbdata {
2785	boolean_t	cb_first;
2786	boolean_t	cb_scripted;
2787	zprop_list_t	*cb_proplist;
2788} list_cbdata_t;
2789
2790/*
2791 * Given a list of columns to display, output appropriate headers for each one.
2792 */
2793static void
2794print_header(zprop_list_t *pl)
2795{
2796	char headerbuf[ZFS_MAXPROPLEN];
2797	const char *header;
2798	int i;
2799	boolean_t first = B_TRUE;
2800	boolean_t right_justify;
2801
2802	for (; pl != NULL; pl = pl->pl_next) {
2803		if (!first) {
2804			(void) printf("  ");
2805		} else {
2806			first = B_FALSE;
2807		}
2808
2809		right_justify = B_FALSE;
2810		if (pl->pl_prop != ZPROP_INVAL) {
2811			header = zfs_prop_column_name(pl->pl_prop);
2812			right_justify = zfs_prop_align_right(pl->pl_prop);
2813		} else {
2814			for (i = 0; pl->pl_user_prop[i] != '\0'; i++)
2815				headerbuf[i] = toupper(pl->pl_user_prop[i]);
2816			headerbuf[i] = '\0';
2817			header = headerbuf;
2818		}
2819
2820		if (pl->pl_next == NULL && !right_justify)
2821			(void) printf("%s", header);
2822		else if (right_justify)
2823			(void) printf("%*s", pl->pl_width, header);
2824		else
2825			(void) printf("%-*s", pl->pl_width, header);
2826	}
2827
2828	(void) printf("\n");
2829}
2830
2831/*
2832 * Given a dataset and a list of fields, print out all the properties according
2833 * to the described layout.
2834 */
2835static void
2836print_dataset(zfs_handle_t *zhp, zprop_list_t *pl, boolean_t scripted)
2837{
2838	boolean_t first = B_TRUE;
2839	char property[ZFS_MAXPROPLEN];
2840	nvlist_t *userprops = zfs_get_user_props(zhp);
2841	nvlist_t *propval;
2842	char *propstr;
2843	boolean_t right_justify;
2844	int width;
2845
2846	for (; pl != NULL; pl = pl->pl_next) {
2847		if (!first) {
2848			if (scripted)
2849				(void) printf("\t");
2850			else
2851				(void) printf("  ");
2852		} else {
2853			first = B_FALSE;
2854		}
2855
2856		if (pl->pl_prop == ZFS_PROP_NAME) {
2857			(void) strlcpy(property, zfs_get_name(zhp),
2858			    sizeof(property));
2859			propstr = property;
2860			right_justify = zfs_prop_align_right(pl->pl_prop);
2861		} else if (pl->pl_prop != ZPROP_INVAL) {
2862			if (zfs_prop_get(zhp, pl->pl_prop, property,
2863			    sizeof (property), NULL, NULL, 0, B_FALSE) != 0)
2864				propstr = "-";
2865			else
2866				propstr = property;
2867
2868			right_justify = zfs_prop_align_right(pl->pl_prop);
2869		} else if (zfs_prop_userquota(pl->pl_user_prop)) {
2870			if (zfs_prop_get_userquota(zhp, pl->pl_user_prop,
2871			    property, sizeof (property), B_FALSE) != 0)
2872				propstr = "-";
2873			else
2874				propstr = property;
2875			right_justify = B_TRUE;
2876		} else if (zfs_prop_written(pl->pl_user_prop)) {
2877			if (zfs_prop_get_written(zhp, pl->pl_user_prop,
2878			    property, sizeof (property), B_FALSE) != 0)
2879				propstr = "-";
2880			else
2881				propstr = property;
2882			right_justify = B_TRUE;
2883		} else {
2884			if (nvlist_lookup_nvlist(userprops,
2885			    pl->pl_user_prop, &propval) != 0)
2886				propstr = "-";
2887			else
2888				verify(nvlist_lookup_string(propval,
2889				    ZPROP_VALUE, &propstr) == 0);
2890			right_justify = B_FALSE;
2891		}
2892
2893		width = pl->pl_width;
2894
2895		/*
2896		 * If this is being called in scripted mode, or if this is the
2897		 * last column and it is left-justified, don't include a width
2898		 * format specifier.
2899		 */
2900		if (scripted || (pl->pl_next == NULL && !right_justify))
2901			(void) printf("%s", propstr);
2902		else if (right_justify)
2903			(void) printf("%*s", width, propstr);
2904		else
2905			(void) printf("%-*s", width, propstr);
2906	}
2907
2908	(void) printf("\n");
2909}
2910
2911/*
2912 * Generic callback function to list a dataset or snapshot.
2913 */
2914static int
2915list_callback(zfs_handle_t *zhp, void *data)
2916{
2917	list_cbdata_t *cbp = data;
2918
2919	if (cbp->cb_first) {
2920		if (!cbp->cb_scripted)
2921			print_header(cbp->cb_proplist);
2922		cbp->cb_first = B_FALSE;
2923	}
2924
2925	print_dataset(zhp, cbp->cb_proplist, cbp->cb_scripted);
2926
2927	return (0);
2928}
2929
2930static int
2931zfs_do_list(int argc, char **argv)
2932{
2933	int c;
2934	boolean_t scripted = B_FALSE;
2935	static char default_fields[] =
2936	    "name,used,available,referenced,mountpoint";
2937	int types = ZFS_TYPE_DATASET;
2938	boolean_t types_specified = B_FALSE;
2939	char *fields = NULL;
2940	list_cbdata_t cb = { 0 };
2941	char *value;
2942	int limit = 0;
2943	int ret = 0;
2944	zfs_sort_column_t *sortcol = NULL;
2945	int flags = ZFS_ITER_PROP_LISTSNAPS | ZFS_ITER_ARGS_CAN_BE_PATHS;
2946
2947	/* check options */
2948	while ((c = getopt(argc, argv, ":d:o:rt:Hs:S:")) != -1) {
2949		switch (c) {
2950		case 'o':
2951			fields = optarg;
2952			break;
2953		case 'd':
2954			limit = parse_depth(optarg, &flags);
2955			break;
2956		case 'r':
2957			flags |= ZFS_ITER_RECURSE;
2958			break;
2959		case 'H':
2960			scripted = B_TRUE;
2961			break;
2962		case 's':
2963			if (zfs_add_sort_column(&sortcol, optarg,
2964			    B_FALSE) != 0) {
2965				(void) fprintf(stderr,
2966				    gettext("invalid property '%s'\n"), optarg);
2967				usage(B_FALSE);
2968			}
2969			break;
2970		case 'S':
2971			if (zfs_add_sort_column(&sortcol, optarg,
2972			    B_TRUE) != 0) {
2973				(void) fprintf(stderr,
2974				    gettext("invalid property '%s'\n"), optarg);
2975				usage(B_FALSE);
2976			}
2977			break;
2978		case 't':
2979			types = 0;
2980			types_specified = B_TRUE;
2981			flags &= ~ZFS_ITER_PROP_LISTSNAPS;
2982			while (*optarg != '\0') {
2983				static char *type_subopts[] = { "filesystem",
2984				    "volume", "snapshot", "all", NULL };
2985
2986				switch (getsubopt(&optarg, type_subopts,
2987				    &value)) {
2988				case 0:
2989					types |= ZFS_TYPE_FILESYSTEM;
2990					break;
2991				case 1:
2992					types |= ZFS_TYPE_VOLUME;
2993					break;
2994				case 2:
2995					types |= ZFS_TYPE_SNAPSHOT;
2996					break;
2997				case 3:
2998					types = ZFS_TYPE_DATASET;
2999					break;
3000
3001				default:
3002					(void) fprintf(stderr,
3003					    gettext("invalid type '%s'\n"),
3004					    value);
3005					usage(B_FALSE);
3006				}
3007			}
3008			break;
3009		case ':':
3010			(void) fprintf(stderr, gettext("missing argument for "
3011			    "'%c' option\n"), optopt);
3012			usage(B_FALSE);
3013			break;
3014		case '?':
3015			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3016			    optopt);
3017			usage(B_FALSE);
3018		}
3019	}
3020
3021	argc -= optind;
3022	argv += optind;
3023
3024	if (fields == NULL)
3025		fields = default_fields;
3026
3027	/*
3028	 * If we are only going to list snapshot names and sort by name,
3029	 * then we can use faster version.
3030	 */
3031	if (strcmp(fields, "name") == 0 && zfs_sort_only_by_name(sortcol))
3032		flags |= ZFS_ITER_SIMPLE;
3033
3034	/*
3035	 * If "-o space" and no types were specified, don't display snapshots.
3036	 */
3037	if (strcmp(fields, "space") == 0 && types_specified == B_FALSE)
3038		types &= ~ZFS_TYPE_SNAPSHOT;
3039
3040	/*
3041	 * If the user specifies '-o all', the zprop_get_list() doesn't
3042	 * normally include the name of the dataset.  For 'zfs list', we always
3043	 * want this property to be first.
3044	 */
3045	if (zprop_get_list(g_zfs, fields, &cb.cb_proplist, ZFS_TYPE_DATASET)
3046	    != 0)
3047		usage(B_FALSE);
3048
3049	cb.cb_scripted = scripted;
3050	cb.cb_first = B_TRUE;
3051
3052	ret = zfs_for_each(argc, argv, flags, types, sortcol, &cb.cb_proplist,
3053	    limit, list_callback, &cb);
3054
3055	zprop_free_list(cb.cb_proplist);
3056	zfs_free_sort_columns(sortcol);
3057
3058	if (ret == 0 && cb.cb_first && !cb.cb_scripted)
3059		(void) printf(gettext("no datasets available\n"));
3060
3061	return (ret);
3062}
3063
3064/*
3065 * zfs rename [-f] <fs | snap | vol> <fs | snap | vol>
3066 * zfs rename [-f] -p <fs | vol> <fs | vol>
3067 * zfs rename -r <snap> <snap>
3068 * zfs rename -u [-p] <fs> <fs>
3069 *
3070 * Renames the given dataset to another of the same type.
3071 *
3072 * The '-p' flag creates all the non-existing ancestors of the target first.
3073 */
3074/* ARGSUSED */
3075static int
3076zfs_do_rename(int argc, char **argv)
3077{
3078	zfs_handle_t *zhp;
3079	renameflags_t flags = { 0 };
3080	int c;
3081	int ret = 0;
3082	int types;
3083	boolean_t parents = B_FALSE;
3084	char *snapshot = NULL;
3085
3086	/* check options */
3087	while ((c = getopt(argc, argv, "fpru")) != -1) {
3088		switch (c) {
3089		case 'p':
3090			parents = B_TRUE;
3091			break;
3092		case 'r':
3093			flags.recurse = B_TRUE;
3094			break;
3095		case 'u':
3096			flags.nounmount = B_TRUE;
3097			break;
3098		case 'f':
3099			flags.forceunmount = B_TRUE;
3100			break;
3101		case '?':
3102		default:
3103			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3104			    optopt);
3105			usage(B_FALSE);
3106		}
3107	}
3108
3109	argc -= optind;
3110	argv += optind;
3111
3112	/* check number of arguments */
3113	if (argc < 1) {
3114		(void) fprintf(stderr, gettext("missing source dataset "
3115		    "argument\n"));
3116		usage(B_FALSE);
3117	}
3118	if (argc < 2) {
3119		(void) fprintf(stderr, gettext("missing target dataset "
3120		    "argument\n"));
3121		usage(B_FALSE);
3122	}
3123	if (argc > 2) {
3124		(void) fprintf(stderr, gettext("too many arguments\n"));
3125		usage(B_FALSE);
3126	}
3127
3128	if (flags.recurse && parents) {
3129		(void) fprintf(stderr, gettext("-p and -r options are mutually "
3130		    "exclusive\n"));
3131		usage(B_FALSE);
3132	}
3133
3134	if (flags.recurse && strchr(argv[0], '@') == 0) {
3135		(void) fprintf(stderr, gettext("source dataset for recursive "
3136		    "rename must be a snapshot\n"));
3137		usage(B_FALSE);
3138	}
3139
3140	if (flags.nounmount && parents) {
3141		(void) fprintf(stderr, gettext("-u and -p options are mutually "
3142		    "exclusive\n"));
3143		usage(B_FALSE);
3144	}
3145
3146	if (flags.nounmount)
3147		types = ZFS_TYPE_FILESYSTEM;
3148	else if (parents)
3149		types = ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME;
3150	else
3151		types = ZFS_TYPE_DATASET;
3152
3153	if (flags.recurse) {
3154		/*
3155		 * When we do recursive rename we are fine when the given
3156		 * snapshot for the given dataset doesn't exist - it can
3157		 * still exists below.
3158		 */
3159
3160		snapshot = strchr(argv[0], '@');
3161		assert(snapshot != NULL);
3162		*snapshot = '\0';
3163		snapshot++;
3164	}
3165
3166	if ((zhp = zfs_open(g_zfs, argv[0], types)) == NULL)
3167		return (1);
3168
3169	/* If we were asked and the name looks good, try to create ancestors. */
3170	if (parents && zfs_name_valid(argv[1], zfs_get_type(zhp)) &&
3171	    zfs_create_ancestors(g_zfs, argv[1]) != 0) {
3172		zfs_close(zhp);
3173		return (1);
3174	}
3175
3176	ret = (zfs_rename(zhp, snapshot, argv[1], flags) != 0);
3177
3178	zfs_close(zhp);
3179	return (ret);
3180}
3181
3182/*
3183 * zfs promote <fs>
3184 *
3185 * Promotes the given clone fs to be the parent
3186 */
3187/* ARGSUSED */
3188static int
3189zfs_do_promote(int argc, char **argv)
3190{
3191	zfs_handle_t *zhp;
3192	int ret = 0;
3193
3194	/* check options */
3195	if (argc > 1 && argv[1][0] == '-') {
3196		(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3197		    argv[1][1]);
3198		usage(B_FALSE);
3199	}
3200
3201	/* check number of arguments */
3202	if (argc < 2) {
3203		(void) fprintf(stderr, gettext("missing clone filesystem"
3204		    " argument\n"));
3205		usage(B_FALSE);
3206	}
3207	if (argc > 2) {
3208		(void) fprintf(stderr, gettext("too many arguments\n"));
3209		usage(B_FALSE);
3210	}
3211
3212	zhp = zfs_open(g_zfs, argv[1], ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
3213	if (zhp == NULL)
3214		return (1);
3215
3216	ret = (zfs_promote(zhp) != 0);
3217
3218
3219	zfs_close(zhp);
3220	return (ret);
3221}
3222
3223/*
3224 * zfs rollback [-rRf] <snapshot>
3225 *
3226 *	-r	Delete any intervening snapshots before doing rollback
3227 *	-R	Delete any snapshots and their clones
3228 *	-f	ignored for backwards compatability
3229 *
3230 * Given a filesystem, rollback to a specific snapshot, discarding any changes
3231 * since then and making it the active dataset.  If more recent snapshots exist,
3232 * the command will complain unless the '-r' flag is given.
3233 */
3234typedef struct rollback_cbdata {
3235	uint64_t	cb_create;
3236	boolean_t	cb_first;
3237	int		cb_doclones;
3238	char		*cb_target;
3239	int		cb_error;
3240	boolean_t	cb_recurse;
3241	boolean_t	cb_dependent;
3242} rollback_cbdata_t;
3243
3244/*
3245 * Report any snapshots more recent than the one specified.  Used when '-r' is
3246 * not specified.  We reuse this same callback for the snapshot dependents - if
3247 * 'cb_dependent' is set, then this is a dependent and we should report it
3248 * without checking the transaction group.
3249 */
3250static int
3251rollback_check(zfs_handle_t *zhp, void *data)
3252{
3253	rollback_cbdata_t *cbp = data;
3254
3255	if (cbp->cb_doclones) {
3256		zfs_close(zhp);
3257		return (0);
3258	}
3259
3260	if (!cbp->cb_dependent) {
3261		if (strcmp(zfs_get_name(zhp), cbp->cb_target) != 0 &&
3262		    zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT &&
3263		    zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) >
3264		    cbp->cb_create) {
3265
3266			if (cbp->cb_first && !cbp->cb_recurse) {
3267				(void) fprintf(stderr, gettext("cannot "
3268				    "rollback to '%s': more recent snapshots "
3269				    "exist\n"),
3270				    cbp->cb_target);
3271				(void) fprintf(stderr, gettext("use '-r' to "
3272				    "force deletion of the following "
3273				    "snapshots:\n"));
3274				cbp->cb_first = 0;
3275				cbp->cb_error = 1;
3276			}
3277
3278			if (cbp->cb_recurse) {
3279				cbp->cb_dependent = B_TRUE;
3280				if (zfs_iter_dependents(zhp, B_TRUE,
3281				    rollback_check, cbp) != 0) {
3282					zfs_close(zhp);
3283					return (-1);
3284				}
3285				cbp->cb_dependent = B_FALSE;
3286			} else {
3287				(void) fprintf(stderr, "%s\n",
3288				    zfs_get_name(zhp));
3289			}
3290		}
3291	} else {
3292		if (cbp->cb_first && cbp->cb_recurse) {
3293			(void) fprintf(stderr, gettext("cannot rollback to "
3294			    "'%s': clones of previous snapshots exist\n"),
3295			    cbp->cb_target);
3296			(void) fprintf(stderr, gettext("use '-R' to "
3297			    "force deletion of the following clones and "
3298			    "dependents:\n"));
3299			cbp->cb_first = 0;
3300			cbp->cb_error = 1;
3301		}
3302
3303		(void) fprintf(stderr, "%s\n", zfs_get_name(zhp));
3304	}
3305
3306	zfs_close(zhp);
3307	return (0);
3308}
3309
3310static int
3311zfs_do_rollback(int argc, char **argv)
3312{
3313	int ret = 0;
3314	int c;
3315	boolean_t force = B_FALSE;
3316	rollback_cbdata_t cb = { 0 };
3317	zfs_handle_t *zhp, *snap;
3318	char parentname[ZFS_MAXNAMELEN];
3319	char *delim;
3320
3321	/* check options */
3322	while ((c = getopt(argc, argv, "rRf")) != -1) {
3323		switch (c) {
3324		case 'r':
3325			cb.cb_recurse = 1;
3326			break;
3327		case 'R':
3328			cb.cb_recurse = 1;
3329			cb.cb_doclones = 1;
3330			break;
3331		case 'f':
3332			force = B_TRUE;
3333			break;
3334		case '?':
3335			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3336			    optopt);
3337			usage(B_FALSE);
3338		}
3339	}
3340
3341	argc -= optind;
3342	argv += optind;
3343
3344	/* check number of arguments */
3345	if (argc < 1) {
3346		(void) fprintf(stderr, gettext("missing dataset argument\n"));
3347		usage(B_FALSE);
3348	}
3349	if (argc > 1) {
3350		(void) fprintf(stderr, gettext("too many arguments\n"));
3351		usage(B_FALSE);
3352	}
3353
3354	/* open the snapshot */
3355	if ((snap = zfs_open(g_zfs, argv[0], ZFS_TYPE_SNAPSHOT)) == NULL)
3356		return (1);
3357
3358	/* open the parent dataset */
3359	(void) strlcpy(parentname, argv[0], sizeof (parentname));
3360	verify((delim = strrchr(parentname, '@')) != NULL);
3361	*delim = '\0';
3362	if ((zhp = zfs_open(g_zfs, parentname, ZFS_TYPE_DATASET)) == NULL) {
3363		zfs_close(snap);
3364		return (1);
3365	}
3366
3367	/*
3368	 * Check for more recent snapshots and/or clones based on the presence
3369	 * of '-r' and '-R'.
3370	 */
3371	cb.cb_target = argv[0];
3372	cb.cb_create = zfs_prop_get_int(snap, ZFS_PROP_CREATETXG);
3373	cb.cb_first = B_TRUE;
3374	cb.cb_error = 0;
3375	if ((ret = zfs_iter_children(zhp, rollback_check, &cb)) != 0)
3376		goto out;
3377
3378	if ((ret = cb.cb_error) != 0)
3379		goto out;
3380
3381	/*
3382	 * Rollback parent to the given snapshot.
3383	 */
3384	ret = zfs_rollback(zhp, snap, force);
3385
3386out:
3387	zfs_close(snap);
3388	zfs_close(zhp);
3389
3390	if (ret == 0)
3391		return (0);
3392	else
3393		return (1);
3394}
3395
3396/*
3397 * zfs set property=value { fs | snap | vol } ...
3398 *
3399 * Sets the given property for all datasets specified on the command line.
3400 */
3401typedef struct set_cbdata {
3402	char		*cb_propname;
3403	char		*cb_value;
3404} set_cbdata_t;
3405
3406static int
3407set_callback(zfs_handle_t *zhp, void *data)
3408{
3409	set_cbdata_t *cbp = data;
3410
3411	if (zfs_prop_set(zhp, cbp->cb_propname, cbp->cb_value) != 0) {
3412		switch (libzfs_errno(g_zfs)) {
3413		case EZFS_MOUNTFAILED:
3414			(void) fprintf(stderr, gettext("property may be set "
3415			    "but unable to remount filesystem\n"));
3416			break;
3417		case EZFS_SHARENFSFAILED:
3418			(void) fprintf(stderr, gettext("property may be set "
3419			    "but unable to reshare filesystem\n"));
3420			break;
3421		}
3422		return (1);
3423	}
3424	return (0);
3425}
3426
3427static int
3428zfs_do_set(int argc, char **argv)
3429{
3430	set_cbdata_t cb;
3431	int ret = 0;
3432
3433	/* check for options */
3434	if (argc > 1 && argv[1][0] == '-') {
3435		(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3436		    argv[1][1]);
3437		usage(B_FALSE);
3438	}
3439
3440	/* check number of arguments */
3441	if (argc < 2) {
3442		(void) fprintf(stderr, gettext("missing property=value "
3443		    "argument\n"));
3444		usage(B_FALSE);
3445	}
3446	if (argc < 3) {
3447		(void) fprintf(stderr, gettext("missing dataset name\n"));
3448		usage(B_FALSE);
3449	}
3450
3451	/* validate property=value argument */
3452	cb.cb_propname = argv[1];
3453	if (((cb.cb_value = strchr(cb.cb_propname, '=')) == NULL) ||
3454	    (cb.cb_value[1] == '\0')) {
3455		(void) fprintf(stderr, gettext("missing value in "
3456		    "property=value argument\n"));
3457		usage(B_FALSE);
3458	}
3459
3460	*cb.cb_value = '\0';
3461	cb.cb_value++;
3462
3463	if (*cb.cb_propname == '\0') {
3464		(void) fprintf(stderr,
3465		    gettext("missing property in property=value argument\n"));
3466		usage(B_FALSE);
3467	}
3468
3469	ret = zfs_for_each(argc - 2, argv + 2, 0,
3470	    ZFS_TYPE_DATASET, NULL, NULL, 0, set_callback, &cb);
3471
3472	return (ret);
3473}
3474
3475/*
3476 * zfs snapshot [-r] [-o prop=value] ... <fs@snap>
3477 *
3478 * Creates a snapshot with the given name.  While functionally equivalent to
3479 * 'zfs create', it is a separate command to differentiate intent.
3480 */
3481static int
3482zfs_do_snapshot(int argc, char **argv)
3483{
3484	boolean_t recursive = B_FALSE;
3485	int ret = 0;
3486	char c;
3487	nvlist_t *props;
3488
3489	if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0)
3490		nomem();
3491
3492	/* check options */
3493	while ((c = getopt(argc, argv, "ro:")) != -1) {
3494		switch (c) {
3495		case 'o':
3496			if (parseprop(props))
3497				return (1);
3498			break;
3499		case 'r':
3500			recursive = B_TRUE;
3501			break;
3502		case '?':
3503			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3504			    optopt);
3505			goto usage;
3506		}
3507	}
3508
3509	argc -= optind;
3510	argv += optind;
3511
3512	/* check number of arguments */
3513	if (argc < 1) {
3514		(void) fprintf(stderr, gettext("missing snapshot argument\n"));
3515		goto usage;
3516	}
3517	if (argc > 1) {
3518		(void) fprintf(stderr, gettext("too many arguments\n"));
3519		goto usage;
3520	}
3521
3522	ret = zfs_snapshot(g_zfs, argv[0], recursive, props);
3523	nvlist_free(props);
3524	if (ret && recursive)
3525		(void) fprintf(stderr, gettext("no snapshots were created\n"));
3526	return (ret != 0);
3527
3528usage:
3529	nvlist_free(props);
3530	usage(B_FALSE);
3531	return (-1);
3532}
3533
3534/*
3535 * Send a backup stream to stdout.
3536 */
3537static int
3538zfs_do_send(int argc, char **argv)
3539{
3540	char *fromname = NULL;
3541	char *toname = NULL;
3542	char *cp;
3543	zfs_handle_t *zhp;
3544	sendflags_t flags = { 0 };
3545	int c, err;
3546	nvlist_t *dbgnv = NULL;
3547	boolean_t extraverbose = B_FALSE;
3548
3549	/* check options */
3550	while ((c = getopt(argc, argv, ":i:I:RDpvnP")) != -1) {
3551		switch (c) {
3552		case 'i':
3553			if (fromname)
3554				usage(B_FALSE);
3555			fromname = optarg;
3556			break;
3557		case 'I':
3558			if (fromname)
3559				usage(B_FALSE);
3560			fromname = optarg;
3561			flags.doall = B_TRUE;
3562			break;
3563		case 'R':
3564			flags.replicate = B_TRUE;
3565			break;
3566		case 'p':
3567			flags.props = B_TRUE;
3568			break;
3569		case 'P':
3570			flags.parsable = B_TRUE;
3571			flags.verbose = B_TRUE;
3572			break;
3573		case 'v':
3574			if (flags.verbose)
3575				extraverbose = B_TRUE;
3576			flags.verbose = B_TRUE;
3577			flags.progress = B_TRUE;
3578			break;
3579		case 'D':
3580			flags.dedup = B_TRUE;
3581			break;
3582		case 'n':
3583			flags.dryrun = B_TRUE;
3584			break;
3585		case ':':
3586			(void) fprintf(stderr, gettext("missing argument for "
3587			    "'%c' option\n"), optopt);
3588			usage(B_FALSE);
3589			break;
3590		case '?':
3591			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3592			    optopt);
3593			usage(B_FALSE);
3594		}
3595	}
3596
3597	argc -= optind;
3598	argv += optind;
3599
3600	/* check number of arguments */
3601	if (argc < 1) {
3602		(void) fprintf(stderr, gettext("missing snapshot argument\n"));
3603		usage(B_FALSE);
3604	}
3605	if (argc > 1) {
3606		(void) fprintf(stderr, gettext("too many arguments\n"));
3607		usage(B_FALSE);
3608	}
3609
3610	if (!flags.dryrun && isatty(STDOUT_FILENO)) {
3611		(void) fprintf(stderr,
3612		    gettext("Error: Stream can not be written to a terminal.\n"
3613		    "You must redirect standard output.\n"));
3614		return (1);
3615	}
3616
3617	cp = strchr(argv[0], '@');
3618	if (cp == NULL) {
3619		(void) fprintf(stderr,
3620		    gettext("argument must be a snapshot\n"));
3621		usage(B_FALSE);
3622	}
3623	*cp = '\0';
3624	toname = cp + 1;
3625	zhp = zfs_open(g_zfs, argv[0], ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
3626	if (zhp == NULL)
3627		return (1);
3628
3629	/*
3630	 * If they specified the full path to the snapshot, chop off
3631	 * everything except the short name of the snapshot, but special
3632	 * case if they specify the origin.
3633	 */
3634	if (fromname && (cp = strchr(fromname, '@')) != NULL) {
3635		char origin[ZFS_MAXNAMELEN];
3636		zprop_source_t src;
3637
3638		(void) zfs_prop_get(zhp, ZFS_PROP_ORIGIN,
3639		    origin, sizeof (origin), &src, NULL, 0, B_FALSE);
3640
3641		if (strcmp(origin, fromname) == 0) {
3642			fromname = NULL;
3643			flags.fromorigin = B_TRUE;
3644		} else {
3645			*cp = '\0';
3646			if (cp != fromname && strcmp(argv[0], fromname)) {
3647				(void) fprintf(stderr,
3648				    gettext("incremental source must be "
3649				    "in same filesystem\n"));
3650				usage(B_FALSE);
3651			}
3652			fromname = cp + 1;
3653			if (strchr(fromname, '@') || strchr(fromname, '/')) {
3654				(void) fprintf(stderr,
3655				    gettext("invalid incremental source\n"));
3656				usage(B_FALSE);
3657			}
3658		}
3659	}
3660
3661	if (flags.replicate && fromname == NULL)
3662		flags.doall = B_TRUE;
3663
3664	err = zfs_send(zhp, fromname, toname, &flags, STDOUT_FILENO, NULL, 0,
3665	    extraverbose ? &dbgnv : NULL);
3666
3667	if (extraverbose && dbgnv != NULL) {
3668		/*
3669		 * dump_nvlist prints to stdout, but that's been
3670		 * redirected to a file.  Make it print to stderr
3671		 * instead.
3672		 */
3673		(void) dup2(STDERR_FILENO, STDOUT_FILENO);
3674		dump_nvlist(dbgnv, 0);
3675		nvlist_free(dbgnv);
3676	}
3677	zfs_close(zhp);
3678
3679	return (err != 0);
3680}
3681
3682/*
3683 * zfs receive [-vnFu] [-d | -e] <fs@snap>
3684 *
3685 * Restore a backup stream from stdin.
3686 */
3687static int
3688zfs_do_receive(int argc, char **argv)
3689{
3690	int c, err;
3691	recvflags_t flags = { 0 };
3692
3693	/* check options */
3694	while ((c = getopt(argc, argv, ":denuvF")) != -1) {
3695		switch (c) {
3696		case 'd':
3697			flags.isprefix = B_TRUE;
3698			break;
3699		case 'e':
3700			flags.isprefix = B_TRUE;
3701			flags.istail = B_TRUE;
3702			break;
3703		case 'n':
3704			flags.dryrun = B_TRUE;
3705			break;
3706		case 'u':
3707			flags.nomount = B_TRUE;
3708			break;
3709		case 'v':
3710			flags.verbose = B_TRUE;
3711			break;
3712		case 'F':
3713			flags.force = B_TRUE;
3714			break;
3715		case ':':
3716			(void) fprintf(stderr, gettext("missing argument for "
3717			    "'%c' option\n"), optopt);
3718			usage(B_FALSE);
3719			break;
3720		case '?':
3721			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3722			    optopt);
3723			usage(B_FALSE);
3724		}
3725	}
3726
3727	argc -= optind;
3728	argv += optind;
3729
3730	/* check number of arguments */
3731	if (argc < 1) {
3732		(void) fprintf(stderr, gettext("missing snapshot argument\n"));
3733		usage(B_FALSE);
3734	}
3735	if (argc > 1) {
3736		(void) fprintf(stderr, gettext("too many arguments\n"));
3737		usage(B_FALSE);
3738	}
3739
3740	if (isatty(STDIN_FILENO)) {
3741		(void) fprintf(stderr,
3742		    gettext("Error: Backup stream can not be read "
3743		    "from a terminal.\n"
3744		    "You must redirect standard input.\n"));
3745		return (1);
3746	}
3747
3748	err = zfs_receive(g_zfs, argv[0], &flags, STDIN_FILENO, NULL);
3749
3750	return (err != 0);
3751}
3752
3753/*
3754 * allow/unallow stuff
3755 */
3756/* copied from zfs/sys/dsl_deleg.h */
3757#define	ZFS_DELEG_PERM_CREATE		"create"
3758#define	ZFS_DELEG_PERM_DESTROY		"destroy"
3759#define	ZFS_DELEG_PERM_SNAPSHOT		"snapshot"
3760#define	ZFS_DELEG_PERM_ROLLBACK		"rollback"
3761#define	ZFS_DELEG_PERM_CLONE		"clone"
3762#define	ZFS_DELEG_PERM_PROMOTE		"promote"
3763#define	ZFS_DELEG_PERM_RENAME		"rename"
3764#define	ZFS_DELEG_PERM_MOUNT		"mount"
3765#define	ZFS_DELEG_PERM_SHARE		"share"
3766#define	ZFS_DELEG_PERM_SEND		"send"
3767#define	ZFS_DELEG_PERM_RECEIVE		"receive"
3768#define	ZFS_DELEG_PERM_ALLOW		"allow"
3769#define	ZFS_DELEG_PERM_USERPROP		"userprop"
3770#define	ZFS_DELEG_PERM_VSCAN		"vscan" /* ??? */
3771#define	ZFS_DELEG_PERM_USERQUOTA	"userquota"
3772#define	ZFS_DELEG_PERM_GROUPQUOTA	"groupquota"
3773#define	ZFS_DELEG_PERM_USERUSED		"userused"
3774#define	ZFS_DELEG_PERM_GROUPUSED	"groupused"
3775#define	ZFS_DELEG_PERM_HOLD		"hold"
3776#define	ZFS_DELEG_PERM_RELEASE		"release"
3777#define	ZFS_DELEG_PERM_DIFF		"diff"
3778
3779#define	ZFS_NUM_DELEG_NOTES ZFS_DELEG_NOTE_NONE
3780
3781static zfs_deleg_perm_tab_t zfs_deleg_perm_tbl[] = {
3782	{ ZFS_DELEG_PERM_ALLOW, ZFS_DELEG_NOTE_ALLOW },
3783	{ ZFS_DELEG_PERM_CLONE, ZFS_DELEG_NOTE_CLONE },
3784	{ ZFS_DELEG_PERM_CREATE, ZFS_DELEG_NOTE_CREATE },
3785	{ ZFS_DELEG_PERM_DESTROY, ZFS_DELEG_NOTE_DESTROY },
3786	{ ZFS_DELEG_PERM_DIFF, ZFS_DELEG_NOTE_DIFF},
3787	{ ZFS_DELEG_PERM_HOLD, ZFS_DELEG_NOTE_HOLD },
3788	{ ZFS_DELEG_PERM_MOUNT, ZFS_DELEG_NOTE_MOUNT },
3789	{ ZFS_DELEG_PERM_PROMOTE, ZFS_DELEG_NOTE_PROMOTE },
3790	{ ZFS_DELEG_PERM_RECEIVE, ZFS_DELEG_NOTE_RECEIVE },
3791	{ ZFS_DELEG_PERM_RELEASE, ZFS_DELEG_NOTE_RELEASE },
3792	{ ZFS_DELEG_PERM_RENAME, ZFS_DELEG_NOTE_RENAME },
3793	{ ZFS_DELEG_PERM_ROLLBACK, ZFS_DELEG_NOTE_ROLLBACK },
3794	{ ZFS_DELEG_PERM_SEND, ZFS_DELEG_NOTE_SEND },
3795	{ ZFS_DELEG_PERM_SHARE, ZFS_DELEG_NOTE_SHARE },
3796	{ ZFS_DELEG_PERM_SNAPSHOT, ZFS_DELEG_NOTE_SNAPSHOT },
3797
3798	{ ZFS_DELEG_PERM_GROUPQUOTA, ZFS_DELEG_NOTE_GROUPQUOTA },
3799	{ ZFS_DELEG_PERM_GROUPUSED, ZFS_DELEG_NOTE_GROUPUSED },
3800	{ ZFS_DELEG_PERM_USERPROP, ZFS_DELEG_NOTE_USERPROP },
3801	{ ZFS_DELEG_PERM_USERQUOTA, ZFS_DELEG_NOTE_USERQUOTA },
3802	{ ZFS_DELEG_PERM_USERUSED, ZFS_DELEG_NOTE_USERUSED },
3803	{ NULL, ZFS_DELEG_NOTE_NONE }
3804};
3805
3806/* permission structure */
3807typedef struct deleg_perm {
3808	zfs_deleg_who_type_t	dp_who_type;
3809	const char		*dp_name;
3810	boolean_t		dp_local;
3811	boolean_t		dp_descend;
3812} deleg_perm_t;
3813
3814/* */
3815typedef struct deleg_perm_node {
3816	deleg_perm_t		dpn_perm;
3817
3818	uu_avl_node_t		dpn_avl_node;
3819} deleg_perm_node_t;
3820
3821typedef struct fs_perm fs_perm_t;
3822
3823/* permissions set */
3824typedef struct who_perm {
3825	zfs_deleg_who_type_t	who_type;
3826	const char		*who_name;		/* id */
3827	char			who_ug_name[256];	/* user/group name */
3828	fs_perm_t		*who_fsperm;		/* uplink */
3829
3830	uu_avl_t		*who_deleg_perm_avl;	/* permissions */
3831} who_perm_t;
3832
3833/* */
3834typedef struct who_perm_node {
3835	who_perm_t	who_perm;
3836	uu_avl_node_t	who_avl_node;
3837} who_perm_node_t;
3838
3839typedef struct fs_perm_set fs_perm_set_t;
3840/* fs permissions */
3841struct fs_perm {
3842	const char		*fsp_name;
3843
3844	uu_avl_t		*fsp_sc_avl;	/* sets,create */
3845	uu_avl_t		*fsp_uge_avl;	/* user,group,everyone */
3846
3847	fs_perm_set_t		*fsp_set;	/* uplink */
3848};
3849
3850/* */
3851typedef struct fs_perm_node {
3852	fs_perm_t	fspn_fsperm;
3853	uu_avl_t	*fspn_avl;
3854
3855	uu_list_node_t	fspn_list_node;
3856} fs_perm_node_t;
3857
3858/* top level structure */
3859struct fs_perm_set {
3860	uu_list_pool_t	*fsps_list_pool;
3861	uu_list_t	*fsps_list; /* list of fs_perms */
3862
3863	uu_avl_pool_t	*fsps_named_set_avl_pool;
3864	uu_avl_pool_t	*fsps_who_perm_avl_pool;
3865	uu_avl_pool_t	*fsps_deleg_perm_avl_pool;
3866};
3867
3868static inline const char *
3869deleg_perm_type(zfs_deleg_note_t note)
3870{
3871	/* subcommands */
3872	switch (note) {
3873		/* SUBCOMMANDS */
3874		/* OTHER */
3875	case ZFS_DELEG_NOTE_GROUPQUOTA:
3876	case ZFS_DELEG_NOTE_GROUPUSED:
3877	case ZFS_DELEG_NOTE_USERPROP:
3878	case ZFS_DELEG_NOTE_USERQUOTA:
3879	case ZFS_DELEG_NOTE_USERUSED:
3880		/* other */
3881		return (gettext("other"));
3882	default:
3883		return (gettext("subcommand"));
3884	}
3885}
3886
3887static int inline
3888who_type2weight(zfs_deleg_who_type_t who_type)
3889{
3890	int res;
3891	switch (who_type) {
3892		case ZFS_DELEG_NAMED_SET_SETS:
3893		case ZFS_DELEG_NAMED_SET:
3894			res = 0;
3895			break;
3896		case ZFS_DELEG_CREATE_SETS:
3897		case ZFS_DELEG_CREATE:
3898			res = 1;
3899			break;
3900		case ZFS_DELEG_USER_SETS:
3901		case ZFS_DELEG_USER:
3902			res = 2;
3903			break;
3904		case ZFS_DELEG_GROUP_SETS:
3905		case ZFS_DELEG_GROUP:
3906			res = 3;
3907			break;
3908		case ZFS_DELEG_EVERYONE_SETS:
3909		case ZFS_DELEG_EVERYONE:
3910			res = 4;
3911			break;
3912		default:
3913			res = -1;
3914	}
3915
3916	return (res);
3917}
3918
3919/* ARGSUSED */
3920static int
3921who_perm_compare(const void *larg, const void *rarg, void *unused)
3922{
3923	const who_perm_node_t *l = larg;
3924	const who_perm_node_t *r = rarg;
3925	zfs_deleg_who_type_t ltype = l->who_perm.who_type;
3926	zfs_deleg_who_type_t rtype = r->who_perm.who_type;
3927	int lweight = who_type2weight(ltype);
3928	int rweight = who_type2weight(rtype);
3929	int res = lweight - rweight;
3930	if (res == 0)
3931		res = strncmp(l->who_perm.who_name, r->who_perm.who_name,
3932		    ZFS_MAX_DELEG_NAME-1);
3933
3934	if (res == 0)
3935		return (0);
3936	if (res > 0)
3937		return (1);
3938	else
3939		return (-1);
3940}
3941
3942/* ARGSUSED */
3943static int
3944deleg_perm_compare(const void *larg, const void *rarg, void *unused)
3945{
3946	const deleg_perm_node_t *l = larg;
3947	const deleg_perm_node_t *r = rarg;
3948	int res =  strncmp(l->dpn_perm.dp_name, r->dpn_perm.dp_name,
3949	    ZFS_MAX_DELEG_NAME-1);
3950
3951	if (res == 0)
3952		return (0);
3953
3954	if (res > 0)
3955		return (1);
3956	else
3957		return (-1);
3958}
3959
3960static inline void
3961fs_perm_set_init(fs_perm_set_t *fspset)
3962{
3963	bzero(fspset, sizeof (fs_perm_set_t));
3964
3965	if ((fspset->fsps_list_pool = uu_list_pool_create("fsps_list_pool",
3966	    sizeof (fs_perm_node_t), offsetof(fs_perm_node_t, fspn_list_node),
3967	    NULL, UU_DEFAULT)) == NULL)
3968		nomem();
3969	if ((fspset->fsps_list = uu_list_create(fspset->fsps_list_pool, NULL,
3970	    UU_DEFAULT)) == NULL)
3971		nomem();
3972
3973	if ((fspset->fsps_named_set_avl_pool = uu_avl_pool_create(
3974	    "named_set_avl_pool", sizeof (who_perm_node_t), offsetof(
3975	    who_perm_node_t, who_avl_node), who_perm_compare,
3976	    UU_DEFAULT)) == NULL)
3977		nomem();
3978
3979	if ((fspset->fsps_who_perm_avl_pool = uu_avl_pool_create(
3980	    "who_perm_avl_pool", sizeof (who_perm_node_t), offsetof(
3981	    who_perm_node_t, who_avl_node), who_perm_compare,
3982	    UU_DEFAULT)) == NULL)
3983		nomem();
3984
3985	if ((fspset->fsps_deleg_perm_avl_pool = uu_avl_pool_create(
3986	    "deleg_perm_avl_pool", sizeof (deleg_perm_node_t), offsetof(
3987	    deleg_perm_node_t, dpn_avl_node), deleg_perm_compare, UU_DEFAULT))
3988	    == NULL)
3989		nomem();
3990}
3991
3992static inline void fs_perm_fini(fs_perm_t *);
3993static inline void who_perm_fini(who_perm_t *);
3994
3995static inline void
3996fs_perm_set_fini(fs_perm_set_t *fspset)
3997{
3998	fs_perm_node_t *node = uu_list_first(fspset->fsps_list);
3999
4000	while (node != NULL) {
4001		fs_perm_node_t *next_node =
4002		    uu_list_next(fspset->fsps_list, node);
4003		fs_perm_t *fsperm = &node->fspn_fsperm;
4004		fs_perm_fini(fsperm);
4005		uu_list_remove(fspset->fsps_list, node);
4006		free(node);
4007		node = next_node;
4008	}
4009
4010	uu_avl_pool_destroy(fspset->fsps_named_set_avl_pool);
4011	uu_avl_pool_destroy(fspset->fsps_who_perm_avl_pool);
4012	uu_avl_pool_destroy(fspset->fsps_deleg_perm_avl_pool);
4013}
4014
4015static inline void
4016deleg_perm_init(deleg_perm_t *deleg_perm, zfs_deleg_who_type_t type,
4017    const char *name)
4018{
4019	deleg_perm->dp_who_type = type;
4020	deleg_perm->dp_name = name;
4021}
4022
4023static inline void
4024who_perm_init(who_perm_t *who_perm, fs_perm_t *fsperm,
4025    zfs_deleg_who_type_t type, const char *name)
4026{
4027	uu_avl_pool_t	*pool;
4028	pool = fsperm->fsp_set->fsps_deleg_perm_avl_pool;
4029
4030	bzero(who_perm, sizeof (who_perm_t));
4031
4032	if ((who_perm->who_deleg_perm_avl = uu_avl_create(pool, NULL,
4033	    UU_DEFAULT)) == NULL)
4034		nomem();
4035
4036	who_perm->who_type = type;
4037	who_perm->who_name = name;
4038	who_perm->who_fsperm = fsperm;
4039}
4040
4041static inline void
4042who_perm_fini(who_perm_t *who_perm)
4043{
4044	deleg_perm_node_t *node = uu_avl_first(who_perm->who_deleg_perm_avl);
4045
4046	while (node != NULL) {
4047		deleg_perm_node_t *next_node =
4048		    uu_avl_next(who_perm->who_deleg_perm_avl, node);
4049
4050		uu_avl_remove(who_perm->who_deleg_perm_avl, node);
4051		free(node);
4052		node = next_node;
4053	}
4054
4055	uu_avl_destroy(who_perm->who_deleg_perm_avl);
4056}
4057
4058static inline void
4059fs_perm_init(fs_perm_t *fsperm, fs_perm_set_t *fspset, const char *fsname)
4060{
4061	uu_avl_pool_t	*nset_pool = fspset->fsps_named_set_avl_pool;
4062	uu_avl_pool_t	*who_pool = fspset->fsps_who_perm_avl_pool;
4063
4064	bzero(fsperm, sizeof (fs_perm_t));
4065
4066	if ((fsperm->fsp_sc_avl = uu_avl_create(nset_pool, NULL, UU_DEFAULT))
4067	    == NULL)
4068		nomem();
4069
4070	if ((fsperm->fsp_uge_avl = uu_avl_create(who_pool, NULL, UU_DEFAULT))
4071	    == NULL)
4072		nomem();
4073
4074	fsperm->fsp_set = fspset;
4075	fsperm->fsp_name = fsname;
4076}
4077
4078static inline void
4079fs_perm_fini(fs_perm_t *fsperm)
4080{
4081	who_perm_node_t *node = uu_avl_first(fsperm->fsp_sc_avl);
4082	while (node != NULL) {
4083		who_perm_node_t *next_node = uu_avl_next(fsperm->fsp_sc_avl,
4084		    node);
4085		who_perm_t *who_perm = &node->who_perm;
4086		who_perm_fini(who_perm);
4087		uu_avl_remove(fsperm->fsp_sc_avl, node);
4088		free(node);
4089		node = next_node;
4090	}
4091
4092	node = uu_avl_first(fsperm->fsp_uge_avl);
4093	while (node != NULL) {
4094		who_perm_node_t *next_node = uu_avl_next(fsperm->fsp_uge_avl,
4095		    node);
4096		who_perm_t *who_perm = &node->who_perm;
4097		who_perm_fini(who_perm);
4098		uu_avl_remove(fsperm->fsp_uge_avl, node);
4099		free(node);
4100		node = next_node;
4101	}
4102
4103	uu_avl_destroy(fsperm->fsp_sc_avl);
4104	uu_avl_destroy(fsperm->fsp_uge_avl);
4105}
4106
4107static void inline
4108set_deleg_perm_node(uu_avl_t *avl, deleg_perm_node_t *node,
4109    zfs_deleg_who_type_t who_type, const char *name, char locality)
4110{
4111	uu_avl_index_t idx = 0;
4112
4113	deleg_perm_node_t *found_node = NULL;
4114	deleg_perm_t	*deleg_perm = &node->dpn_perm;
4115
4116	deleg_perm_init(deleg_perm, who_type, name);
4117
4118	if ((found_node = uu_avl_find(avl, node, NULL, &idx))
4119	    == NULL)
4120		uu_avl_insert(avl, node, idx);
4121	else {
4122		node = found_node;
4123		deleg_perm = &node->dpn_perm;
4124	}
4125
4126
4127	switch (locality) {
4128	case ZFS_DELEG_LOCAL:
4129		deleg_perm->dp_local = B_TRUE;
4130		break;
4131	case ZFS_DELEG_DESCENDENT:
4132		deleg_perm->dp_descend = B_TRUE;
4133		break;
4134	case ZFS_DELEG_NA:
4135		break;
4136	default:
4137		assert(B_FALSE); /* invalid locality */
4138	}
4139}
4140
4141static inline int
4142parse_who_perm(who_perm_t *who_perm, nvlist_t *nvl, char locality)
4143{
4144	nvpair_t *nvp = NULL;
4145	fs_perm_set_t *fspset = who_perm->who_fsperm->fsp_set;
4146	uu_avl_t *avl = who_perm->who_deleg_perm_avl;
4147	zfs_deleg_who_type_t who_type = who_perm->who_type;
4148
4149	while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
4150		const char *name = nvpair_name(nvp);
4151		data_type_t type = nvpair_type(nvp);
4152		uu_avl_pool_t *avl_pool = fspset->fsps_deleg_perm_avl_pool;
4153		deleg_perm_node_t *node =
4154		    safe_malloc(sizeof (deleg_perm_node_t));
4155
4156		assert(type == DATA_TYPE_BOOLEAN);
4157
4158		uu_avl_node_init(node, &node->dpn_avl_node, avl_pool);
4159		set_deleg_perm_node(avl, node, who_type, name, locality);
4160	}
4161
4162	return (0);
4163}
4164
4165static inline int
4166parse_fs_perm(fs_perm_t *fsperm, nvlist_t *nvl)
4167{
4168	nvpair_t *nvp = NULL;
4169	fs_perm_set_t *fspset = fsperm->fsp_set;
4170
4171	while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
4172		nvlist_t *nvl2 = NULL;
4173		const char *name = nvpair_name(nvp);
4174		uu_avl_t *avl = NULL;
4175		uu_avl_pool_t *avl_pool;
4176		zfs_deleg_who_type_t perm_type = name[0];
4177		char perm_locality = name[1];
4178		const char *perm_name = name + 3;
4179		boolean_t is_set = B_TRUE;
4180		who_perm_t *who_perm = NULL;
4181
4182		assert('$' == name[2]);
4183
4184		if (nvpair_value_nvlist(nvp, &nvl2) != 0)
4185			return (-1);
4186
4187		switch (perm_type) {
4188		case ZFS_DELEG_CREATE:
4189		case ZFS_DELEG_CREATE_SETS:
4190		case ZFS_DELEG_NAMED_SET:
4191		case ZFS_DELEG_NAMED_SET_SETS:
4192			avl_pool = fspset->fsps_named_set_avl_pool;
4193			avl = fsperm->fsp_sc_avl;
4194			break;
4195		case ZFS_DELEG_USER:
4196		case ZFS_DELEG_USER_SETS:
4197		case ZFS_DELEG_GROUP:
4198		case ZFS_DELEG_GROUP_SETS:
4199		case ZFS_DELEG_EVERYONE:
4200		case ZFS_DELEG_EVERYONE_SETS:
4201			avl_pool = fspset->fsps_who_perm_avl_pool;
4202			avl = fsperm->fsp_uge_avl;
4203			break;
4204		}
4205
4206		if (is_set) {
4207			who_perm_node_t *found_node = NULL;
4208			who_perm_node_t *node = safe_malloc(
4209			    sizeof (who_perm_node_t));
4210			who_perm = &node->who_perm;
4211			uu_avl_index_t idx = 0;
4212
4213			uu_avl_node_init(node, &node->who_avl_node, avl_pool);
4214			who_perm_init(who_perm, fsperm, perm_type, perm_name);
4215
4216			if ((found_node = uu_avl_find(avl, node, NULL, &idx))
4217			    == NULL) {
4218				if (avl == fsperm->fsp_uge_avl) {
4219					uid_t rid = 0;
4220					struct passwd *p = NULL;
4221					struct group *g = NULL;
4222					const char *nice_name = NULL;
4223
4224					switch (perm_type) {
4225					case ZFS_DELEG_USER_SETS:
4226					case ZFS_DELEG_USER:
4227						rid = atoi(perm_name);
4228						p = getpwuid(rid);
4229						if (p)
4230							nice_name = p->pw_name;
4231						break;
4232					case ZFS_DELEG_GROUP_SETS:
4233					case ZFS_DELEG_GROUP:
4234						rid = atoi(perm_name);
4235						g = getgrgid(rid);
4236						if (g)
4237							nice_name = g->gr_name;
4238						break;
4239					}
4240
4241					if (nice_name != NULL)
4242						(void) strlcpy(
4243						    node->who_perm.who_ug_name,
4244						    nice_name, 256);
4245				}
4246
4247				uu_avl_insert(avl, node, idx);
4248			} else {
4249				node = found_node;
4250				who_perm = &node->who_perm;
4251			}
4252		}
4253
4254		(void) parse_who_perm(who_perm, nvl2, perm_locality);
4255	}
4256
4257	return (0);
4258}
4259
4260static inline int
4261parse_fs_perm_set(fs_perm_set_t *fspset, nvlist_t *nvl)
4262{
4263	nvpair_t *nvp = NULL;
4264	uu_avl_index_t idx = 0;
4265
4266	while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
4267		nvlist_t *nvl2 = NULL;
4268		const char *fsname = nvpair_name(nvp);
4269		data_type_t type = nvpair_type(nvp);
4270		fs_perm_t *fsperm = NULL;
4271		fs_perm_node_t *node = safe_malloc(sizeof (fs_perm_node_t));
4272		if (node == NULL)
4273			nomem();
4274
4275		fsperm = &node->fspn_fsperm;
4276
4277		assert(DATA_TYPE_NVLIST == type);
4278
4279		uu_list_node_init(node, &node->fspn_list_node,
4280		    fspset->fsps_list_pool);
4281
4282		idx = uu_list_numnodes(fspset->fsps_list);
4283		fs_perm_init(fsperm, fspset, fsname);
4284
4285		if (nvpair_value_nvlist(nvp, &nvl2) != 0)
4286			return (-1);
4287
4288		(void) parse_fs_perm(fsperm, nvl2);
4289
4290		uu_list_insert(fspset->fsps_list, node, idx);
4291	}
4292
4293	return (0);
4294}
4295
4296static inline const char *
4297deleg_perm_comment(zfs_deleg_note_t note)
4298{
4299	const char *str = "";
4300
4301	/* subcommands */
4302	switch (note) {
4303		/* SUBCOMMANDS */
4304	case ZFS_DELEG_NOTE_ALLOW:
4305		str = gettext("Must also have the permission that is being"
4306		    "\n\t\t\t\tallowed");
4307		break;
4308	case ZFS_DELEG_NOTE_CLONE:
4309		str = gettext("Must also have the 'create' ability and 'mount'"
4310		    "\n\t\t\t\tability in the origin file system");
4311		break;
4312	case ZFS_DELEG_NOTE_CREATE:
4313		str = gettext("Must also have the 'mount' ability");
4314		break;
4315	case ZFS_DELEG_NOTE_DESTROY:
4316		str = gettext("Must also have the 'mount' ability");
4317		break;
4318	case ZFS_DELEG_NOTE_DIFF:
4319		str = gettext("Allows lookup of paths within a dataset;"
4320		    "\n\t\t\t\tgiven an object number. Ordinary users need this"
4321		    "\n\t\t\t\tin order to use zfs diff");
4322		break;
4323	case ZFS_DELEG_NOTE_HOLD:
4324		str = gettext("Allows adding a user hold to a snapshot");
4325		break;
4326	case ZFS_DELEG_NOTE_MOUNT:
4327		str = gettext("Allows mount/umount of ZFS datasets");
4328		break;
4329	case ZFS_DELEG_NOTE_PROMOTE:
4330		str = gettext("Must also have the 'mount'\n\t\t\t\tand"
4331		    " 'promote' ability in the origin file system");
4332		break;
4333	case ZFS_DELEG_NOTE_RECEIVE:
4334		str = gettext("Must also have the 'mount' and 'create'"
4335		    " ability");
4336		break;
4337	case ZFS_DELEG_NOTE_RELEASE:
4338		str = gettext("Allows releasing a user hold which\n\t\t\t\t"
4339		    "might destroy the snapshot");
4340		break;
4341	case ZFS_DELEG_NOTE_RENAME:
4342		str = gettext("Must also have the 'mount' and 'create'"
4343		    "\n\t\t\t\tability in the new parent");
4344		break;
4345	case ZFS_DELEG_NOTE_ROLLBACK:
4346		str = gettext("");
4347		break;
4348	case ZFS_DELEG_NOTE_SEND:
4349		str = gettext("");
4350		break;
4351	case ZFS_DELEG_NOTE_SHARE:
4352		str = gettext("Allows sharing file systems over NFS or SMB"
4353		    "\n\t\t\t\tprotocols");
4354		break;
4355	case ZFS_DELEG_NOTE_SNAPSHOT:
4356		str = gettext("");
4357		break;
4358/*
4359 *	case ZFS_DELEG_NOTE_VSCAN:
4360 *		str = gettext("");
4361 *		break;
4362 */
4363		/* OTHER */
4364	case ZFS_DELEG_NOTE_GROUPQUOTA:
4365		str = gettext("Allows accessing any groupquota@... property");
4366		break;
4367	case ZFS_DELEG_NOTE_GROUPUSED:
4368		str = gettext("Allows reading any groupused@... property");
4369		break;
4370	case ZFS_DELEG_NOTE_USERPROP:
4371		str = gettext("Allows changing any user property");
4372		break;
4373	case ZFS_DELEG_NOTE_USERQUOTA:
4374		str = gettext("Allows accessing any userquota@... property");
4375		break;
4376	case ZFS_DELEG_NOTE_USERUSED:
4377		str = gettext("Allows reading any userused@... property");
4378		break;
4379		/* other */
4380	default:
4381		str = "";
4382	}
4383
4384	return (str);
4385}
4386
4387struct allow_opts {
4388	boolean_t local;
4389	boolean_t descend;
4390	boolean_t user;
4391	boolean_t group;
4392	boolean_t everyone;
4393	boolean_t create;
4394	boolean_t set;
4395	boolean_t recursive; /* unallow only */
4396	boolean_t prt_usage;
4397
4398	boolean_t prt_perms;
4399	char *who;
4400	char *perms;
4401	const char *dataset;
4402};
4403
4404static inline int
4405prop_cmp(const void *a, const void *b)
4406{
4407	const char *str1 = *(const char **)a;
4408	const char *str2 = *(const char **)b;
4409	return (strcmp(str1, str2));
4410}
4411
4412static void
4413allow_usage(boolean_t un, boolean_t requested, const char *msg)
4414{
4415	const char *opt_desc[] = {
4416		"-h", gettext("show this help message and exit"),
4417		"-l", gettext("set permission locally"),
4418		"-d", gettext("set permission for descents"),
4419		"-u", gettext("set permission for user"),
4420		"-g", gettext("set permission for group"),
4421		"-e", gettext("set permission for everyone"),
4422		"-c", gettext("set create time permission"),
4423		"-s", gettext("define permission set"),
4424		/* unallow only */
4425		"-r", gettext("remove permissions recursively"),
4426	};
4427	size_t unallow_size = sizeof (opt_desc) / sizeof (char *);
4428	size_t allow_size = unallow_size - 2;
4429	const char *props[ZFS_NUM_PROPS];
4430	int i;
4431	size_t count = 0;
4432	FILE *fp = requested ? stdout : stderr;
4433	zprop_desc_t *pdtbl = zfs_prop_get_table();
4434	const char *fmt = gettext("%-16s %-14s\t%s\n");
4435
4436	(void) fprintf(fp, gettext("Usage: %s\n"), get_usage(un ? HELP_UNALLOW :
4437	    HELP_ALLOW));
4438	(void) fprintf(fp, gettext("Options:\n"));
4439	for (i = 0; i < (un ? unallow_size : allow_size); i++) {
4440		const char *opt = opt_desc[i++];
4441		const char *optdsc = opt_desc[i];
4442		(void) fprintf(fp, gettext("  %-10s  %s\n"), opt, optdsc);
4443	}
4444
4445	(void) fprintf(fp, gettext("\nThe following permissions are "
4446	    "supported:\n\n"));
4447	(void) fprintf(fp, fmt, gettext("NAME"), gettext("TYPE"),
4448	    gettext("NOTES"));
4449	for (i = 0; i < ZFS_NUM_DELEG_NOTES; i++) {
4450		const char *perm_name = zfs_deleg_perm_tbl[i].z_perm;
4451		zfs_deleg_note_t perm_note = zfs_deleg_perm_tbl[i].z_note;
4452		const char *perm_type = deleg_perm_type(perm_note);
4453		const char *perm_comment = deleg_perm_comment(perm_note);
4454		(void) fprintf(fp, fmt, perm_name, perm_type, perm_comment);
4455	}
4456
4457	for (i = 0; i < ZFS_NUM_PROPS; i++) {
4458		zprop_desc_t *pd = &pdtbl[i];
4459		if (pd->pd_visible != B_TRUE)
4460			continue;
4461
4462		if (pd->pd_attr == PROP_READONLY)
4463			continue;
4464
4465		props[count++] = pd->pd_name;
4466	}
4467	props[count] = NULL;
4468
4469	qsort(props, count, sizeof (char *), prop_cmp);
4470
4471	for (i = 0; i < count; i++)
4472		(void) fprintf(fp, fmt, props[i], gettext("property"), "");
4473
4474	if (msg != NULL)
4475		(void) fprintf(fp, gettext("\nzfs: error: %s"), msg);
4476
4477	exit(requested ? 0 : 2);
4478}
4479
4480static inline const char *
4481munge_args(int argc, char **argv, boolean_t un, size_t expected_argc,
4482    char **permsp)
4483{
4484	if (un && argc == expected_argc - 1)
4485		*permsp = NULL;
4486	else if (argc == expected_argc)
4487		*permsp = argv[argc - 2];
4488	else
4489		allow_usage(un, B_FALSE,
4490		    gettext("wrong number of parameters\n"));
4491
4492	return (argv[argc - 1]);
4493}
4494
4495static void
4496parse_allow_args(int argc, char **argv, boolean_t un, struct allow_opts *opts)
4497{
4498	int uge_sum = opts->user + opts->group + opts->everyone;
4499	int csuge_sum = opts->create + opts->set + uge_sum;
4500	int ldcsuge_sum = csuge_sum + opts->local + opts->descend;
4501	int all_sum = un ? ldcsuge_sum + opts->recursive : ldcsuge_sum;
4502
4503	if (uge_sum > 1)
4504		allow_usage(un, B_FALSE,
4505		    gettext("-u, -g, and -e are mutually exclusive\n"));
4506
4507	if (opts->prt_usage)
4508		if (argc == 0 && all_sum == 0)
4509			allow_usage(un, B_TRUE, NULL);
4510		else
4511			usage(B_FALSE);
4512
4513	if (opts->set) {
4514		if (csuge_sum > 1)
4515			allow_usage(un, B_FALSE,
4516			    gettext("invalid options combined with -s\n"));
4517
4518		opts->dataset = munge_args(argc, argv, un, 3, &opts->perms);
4519		if (argv[0][0] != '@')
4520			allow_usage(un, B_FALSE,
4521			    gettext("invalid set name: missing '@' prefix\n"));
4522		opts->who = argv[0];
4523	} else if (opts->create) {
4524		if (ldcsuge_sum > 1)
4525			allow_usage(un, B_FALSE,
4526			    gettext("invalid options combined with -c\n"));
4527		opts->dataset = munge_args(argc, argv, un, 2, &opts->perms);
4528	} else if (opts->everyone) {
4529		if (csuge_sum > 1)
4530			allow_usage(un, B_FALSE,
4531			    gettext("invalid options combined with -e\n"));
4532		opts->dataset = munge_args(argc, argv, un, 2, &opts->perms);
4533	} else if (uge_sum == 0 && argc > 0 && strcmp(argv[0], "everyone")
4534	    == 0) {
4535		opts->everyone = B_TRUE;
4536		argc--;
4537		argv++;
4538		opts->dataset = munge_args(argc, argv, un, 2, &opts->perms);
4539	} else if (argc == 1 && !un) {
4540		opts->prt_perms = B_TRUE;
4541		opts->dataset = argv[argc-1];
4542	} else {
4543		opts->dataset = munge_args(argc, argv, un, 3, &opts->perms);
4544		opts->who = argv[0];
4545	}
4546
4547	if (!opts->local && !opts->descend) {
4548		opts->local = B_TRUE;
4549		opts->descend = B_TRUE;
4550	}
4551}
4552
4553static void
4554store_allow_perm(zfs_deleg_who_type_t type, boolean_t local, boolean_t descend,
4555    const char *who, char *perms, nvlist_t *top_nvl)
4556{
4557	int i;
4558	char ld[2] = { '\0', '\0' };
4559	char who_buf[ZFS_MAXNAMELEN+32];
4560	char base_type;
4561	char set_type;
4562	nvlist_t *base_nvl = NULL;
4563	nvlist_t *set_nvl = NULL;
4564	nvlist_t *nvl;
4565
4566	if (nvlist_alloc(&base_nvl, NV_UNIQUE_NAME, 0) != 0)
4567		nomem();
4568	if (nvlist_alloc(&set_nvl, NV_UNIQUE_NAME, 0) !=  0)
4569		nomem();
4570
4571	switch (type) {
4572	case ZFS_DELEG_NAMED_SET_SETS:
4573	case ZFS_DELEG_NAMED_SET:
4574		set_type = ZFS_DELEG_NAMED_SET_SETS;
4575		base_type = ZFS_DELEG_NAMED_SET;
4576		ld[0] = ZFS_DELEG_NA;
4577		break;
4578	case ZFS_DELEG_CREATE_SETS:
4579	case ZFS_DELEG_CREATE:
4580		set_type = ZFS_DELEG_CREATE_SETS;
4581		base_type = ZFS_DELEG_CREATE;
4582		ld[0] = ZFS_DELEG_NA;
4583		break;
4584	case ZFS_DELEG_USER_SETS:
4585	case ZFS_DELEG_USER:
4586		set_type = ZFS_DELEG_USER_SETS;
4587		base_type = ZFS_DELEG_USER;
4588		if (local)
4589			ld[0] = ZFS_DELEG_LOCAL;
4590		if (descend)
4591			ld[1] = ZFS_DELEG_DESCENDENT;
4592		break;
4593	case ZFS_DELEG_GROUP_SETS:
4594	case ZFS_DELEG_GROUP:
4595		set_type = ZFS_DELEG_GROUP_SETS;
4596		base_type = ZFS_DELEG_GROUP;
4597		if (local)
4598			ld[0] = ZFS_DELEG_LOCAL;
4599		if (descend)
4600			ld[1] = ZFS_DELEG_DESCENDENT;
4601		break;
4602	case ZFS_DELEG_EVERYONE_SETS:
4603	case ZFS_DELEG_EVERYONE:
4604		set_type = ZFS_DELEG_EVERYONE_SETS;
4605		base_type = ZFS_DELEG_EVERYONE;
4606		if (local)
4607			ld[0] = ZFS_DELEG_LOCAL;
4608		if (descend)
4609			ld[1] = ZFS_DELEG_DESCENDENT;
4610	}
4611
4612	if (perms != NULL) {
4613		char *curr = perms;
4614		char *end = curr + strlen(perms);
4615
4616		while (curr < end) {
4617			char *delim = strchr(curr, ',');
4618			if (delim == NULL)
4619				delim = end;
4620			else
4621				*delim = '\0';
4622
4623			if (curr[0] == '@')
4624				nvl = set_nvl;
4625			else
4626				nvl = base_nvl;
4627
4628			(void) nvlist_add_boolean(nvl, curr);
4629			if (delim != end)
4630				*delim = ',';
4631			curr = delim + 1;
4632		}
4633
4634		for (i = 0; i < 2; i++) {
4635			char locality = ld[i];
4636			if (locality == 0)
4637				continue;
4638
4639			if (!nvlist_empty(base_nvl)) {
4640				if (who != NULL)
4641					(void) snprintf(who_buf,
4642					    sizeof (who_buf), "%c%c$%s",
4643					    base_type, locality, who);
4644				else
4645					(void) snprintf(who_buf,
4646					    sizeof (who_buf), "%c%c$",
4647					    base_type, locality);
4648
4649				(void) nvlist_add_nvlist(top_nvl, who_buf,
4650				    base_nvl);
4651			}
4652
4653
4654			if (!nvlist_empty(set_nvl)) {
4655				if (who != NULL)
4656					(void) snprintf(who_buf,
4657					    sizeof (who_buf), "%c%c$%s",
4658					    set_type, locality, who);
4659				else
4660					(void) snprintf(who_buf,
4661					    sizeof (who_buf), "%c%c$",
4662					    set_type, locality);
4663
4664				(void) nvlist_add_nvlist(top_nvl, who_buf,
4665				    set_nvl);
4666			}
4667		}
4668	} else {
4669		for (i = 0; i < 2; i++) {
4670			char locality = ld[i];
4671			if (locality == 0)
4672				continue;
4673
4674			if (who != NULL)
4675				(void) snprintf(who_buf, sizeof (who_buf),
4676				    "%c%c$%s", base_type, locality, who);
4677			else
4678				(void) snprintf(who_buf, sizeof (who_buf),
4679				    "%c%c$", base_type, locality);
4680			(void) nvlist_add_boolean(top_nvl, who_buf);
4681
4682			if (who != NULL)
4683				(void) snprintf(who_buf, sizeof (who_buf),
4684				    "%c%c$%s", set_type, locality, who);
4685			else
4686				(void) snprintf(who_buf, sizeof (who_buf),
4687				    "%c%c$", set_type, locality);
4688			(void) nvlist_add_boolean(top_nvl, who_buf);
4689		}
4690	}
4691}
4692
4693static int
4694construct_fsacl_list(boolean_t un, struct allow_opts *opts, nvlist_t **nvlp)
4695{
4696	if (nvlist_alloc(nvlp, NV_UNIQUE_NAME, 0) != 0)
4697		nomem();
4698
4699	if (opts->set) {
4700		store_allow_perm(ZFS_DELEG_NAMED_SET, opts->local,
4701		    opts->descend, opts->who, opts->perms, *nvlp);
4702	} else if (opts->create) {
4703		store_allow_perm(ZFS_DELEG_CREATE, opts->local,
4704		    opts->descend, NULL, opts->perms, *nvlp);
4705	} else if (opts->everyone) {
4706		store_allow_perm(ZFS_DELEG_EVERYONE, opts->local,
4707		    opts->descend, NULL, opts->perms, *nvlp);
4708	} else {
4709		char *curr = opts->who;
4710		char *end = curr + strlen(curr);
4711
4712		while (curr < end) {
4713			const char *who;
4714			zfs_deleg_who_type_t who_type;
4715			char *endch;
4716			char *delim = strchr(curr, ',');
4717			char errbuf[256];
4718			char id[64];
4719			struct passwd *p = NULL;
4720			struct group *g = NULL;
4721
4722			uid_t rid;
4723			if (delim == NULL)
4724				delim = end;
4725			else
4726				*delim = '\0';
4727
4728			rid = (uid_t)strtol(curr, &endch, 0);
4729			if (opts->user) {
4730				who_type = ZFS_DELEG_USER;
4731				if (*endch != '\0')
4732					p = getpwnam(curr);
4733				else
4734					p = getpwuid(rid);
4735
4736				if (p != NULL)
4737					rid = p->pw_uid;
4738				else {
4739					(void) snprintf(errbuf, 256, gettext(
4740					    "invalid user %s"), curr);
4741					allow_usage(un, B_TRUE, errbuf);
4742				}
4743			} else if (opts->group) {
4744				who_type = ZFS_DELEG_GROUP;
4745				if (*endch != '\0')
4746					g = getgrnam(curr);
4747				else
4748					g = getgrgid(rid);
4749
4750				if (g != NULL)
4751					rid = g->gr_gid;
4752				else {
4753					(void) snprintf(errbuf, 256, gettext(
4754					    "invalid group %s"),  curr);
4755					allow_usage(un, B_TRUE, errbuf);
4756				}
4757			} else {
4758				if (*endch != '\0') {
4759					p = getpwnam(curr);
4760				} else {
4761					p = getpwuid(rid);
4762				}
4763
4764				if (p == NULL)
4765					if (*endch != '\0') {
4766						g = getgrnam(curr);
4767					} else {
4768						g = getgrgid(rid);
4769					}
4770
4771				if (p != NULL) {
4772					who_type = ZFS_DELEG_USER;
4773					rid = p->pw_uid;
4774				} else if (g != NULL) {
4775					who_type = ZFS_DELEG_GROUP;
4776					rid = g->gr_gid;
4777				} else {
4778					(void) snprintf(errbuf, 256, gettext(
4779					    "invalid user/group %s"), curr);
4780					allow_usage(un, B_TRUE, errbuf);
4781				}
4782			}
4783
4784			(void) sprintf(id, "%u", rid);
4785			who = id;
4786
4787			store_allow_perm(who_type, opts->local,
4788			    opts->descend, who, opts->perms, *nvlp);
4789			curr = delim + 1;
4790		}
4791	}
4792
4793	return (0);
4794}
4795
4796static void
4797print_set_creat_perms(uu_avl_t *who_avl)
4798{
4799	const char *sc_title[] = {
4800		gettext("Permission sets:\n"),
4801		gettext("Create time permissions:\n"),
4802		NULL
4803	};
4804	const char **title_ptr = sc_title;
4805	who_perm_node_t *who_node = NULL;
4806	int prev_weight = -1;
4807
4808	for (who_node = uu_avl_first(who_avl); who_node != NULL;
4809	    who_node = uu_avl_next(who_avl, who_node)) {
4810		uu_avl_t *avl = who_node->who_perm.who_deleg_perm_avl;
4811		zfs_deleg_who_type_t who_type = who_node->who_perm.who_type;
4812		const char *who_name = who_node->who_perm.who_name;
4813		int weight = who_type2weight(who_type);
4814		boolean_t first = B_TRUE;
4815		deleg_perm_node_t *deleg_node;
4816
4817		if (prev_weight != weight) {
4818			(void) printf(*title_ptr++);
4819			prev_weight = weight;
4820		}
4821
4822		if (who_name == NULL || strnlen(who_name, 1) == 0)
4823			(void) printf("\t");
4824		else
4825			(void) printf("\t%s ", who_name);
4826
4827		for (deleg_node = uu_avl_first(avl); deleg_node != NULL;
4828		    deleg_node = uu_avl_next(avl, deleg_node)) {
4829			if (first) {
4830				(void) printf("%s",
4831				    deleg_node->dpn_perm.dp_name);
4832				first = B_FALSE;
4833			} else
4834				(void) printf(",%s",
4835				    deleg_node->dpn_perm.dp_name);
4836		}
4837
4838		(void) printf("\n");
4839	}
4840}
4841
4842static void inline
4843print_uge_deleg_perms(uu_avl_t *who_avl, boolean_t local, boolean_t descend,
4844    const char *title)
4845{
4846	who_perm_node_t *who_node = NULL;
4847	boolean_t prt_title = B_TRUE;
4848	uu_avl_walk_t *walk;
4849
4850	if ((walk = uu_avl_walk_start(who_avl, UU_WALK_ROBUST)) == NULL)
4851		nomem();
4852
4853	while ((who_node = uu_avl_walk_next(walk)) != NULL) {
4854		const char *who_name = who_node->who_perm.who_name;
4855		const char *nice_who_name = who_node->who_perm.who_ug_name;
4856		uu_avl_t *avl = who_node->who_perm.who_deleg_perm_avl;
4857		zfs_deleg_who_type_t who_type = who_node->who_perm.who_type;
4858		char delim = ' ';
4859		deleg_perm_node_t *deleg_node;
4860		boolean_t prt_who = B_TRUE;
4861
4862		for (deleg_node = uu_avl_first(avl);
4863		    deleg_node != NULL;
4864		    deleg_node = uu_avl_next(avl, deleg_node)) {
4865			if (local != deleg_node->dpn_perm.dp_local ||
4866			    descend != deleg_node->dpn_perm.dp_descend)
4867				continue;
4868
4869			if (prt_who) {
4870				const char *who = NULL;
4871				if (prt_title) {
4872					prt_title = B_FALSE;
4873					(void) printf(title);
4874				}
4875
4876				switch (who_type) {
4877				case ZFS_DELEG_USER_SETS:
4878				case ZFS_DELEG_USER:
4879					who = gettext("user");
4880					if (nice_who_name)
4881						who_name  = nice_who_name;
4882					break;
4883				case ZFS_DELEG_GROUP_SETS:
4884				case ZFS_DELEG_GROUP:
4885					who = gettext("group");
4886					if (nice_who_name)
4887						who_name  = nice_who_name;
4888					break;
4889				case ZFS_DELEG_EVERYONE_SETS:
4890				case ZFS_DELEG_EVERYONE:
4891					who = gettext("everyone");
4892					who_name = NULL;
4893				}
4894
4895				prt_who = B_FALSE;
4896				if (who_name == NULL)
4897					(void) printf("\t%s", who);
4898				else
4899					(void) printf("\t%s %s", who, who_name);
4900			}
4901
4902			(void) printf("%c%s", delim,
4903			    deleg_node->dpn_perm.dp_name);
4904			delim = ',';
4905		}
4906
4907		if (!prt_who)
4908			(void) printf("\n");
4909	}
4910
4911	uu_avl_walk_end(walk);
4912}
4913
4914static void
4915print_fs_perms(fs_perm_set_t *fspset)
4916{
4917	fs_perm_node_t *node = NULL;
4918	char buf[ZFS_MAXNAMELEN+32];
4919	const char *dsname = buf;
4920
4921	for (node = uu_list_first(fspset->fsps_list); node != NULL;
4922	    node = uu_list_next(fspset->fsps_list, node)) {
4923		uu_avl_t *sc_avl = node->fspn_fsperm.fsp_sc_avl;
4924		uu_avl_t *uge_avl = node->fspn_fsperm.fsp_uge_avl;
4925		int left = 0;
4926
4927		(void) snprintf(buf, ZFS_MAXNAMELEN+32,
4928		    gettext("---- Permissions on %s "),
4929		    node->fspn_fsperm.fsp_name);
4930		(void) printf(dsname);
4931		left = 70 - strlen(buf);
4932		while (left-- > 0)
4933			(void) printf("-");
4934		(void) printf("\n");
4935
4936		print_set_creat_perms(sc_avl);
4937		print_uge_deleg_perms(uge_avl, B_TRUE, B_FALSE,
4938		    gettext("Local permissions:\n"));
4939		print_uge_deleg_perms(uge_avl, B_FALSE, B_TRUE,
4940		    gettext("Descendent permissions:\n"));
4941		print_uge_deleg_perms(uge_avl, B_TRUE, B_TRUE,
4942		    gettext("Local+Descendent permissions:\n"));
4943	}
4944}
4945
4946static fs_perm_set_t fs_perm_set = { NULL, NULL, NULL, NULL };
4947
4948struct deleg_perms {
4949	boolean_t un;
4950	nvlist_t *nvl;
4951};
4952
4953static int
4954set_deleg_perms(zfs_handle_t *zhp, void *data)
4955{
4956	struct deleg_perms *perms = (struct deleg_perms *)data;
4957	zfs_type_t zfs_type = zfs_get_type(zhp);
4958
4959	if (zfs_type != ZFS_TYPE_FILESYSTEM && zfs_type != ZFS_TYPE_VOLUME)
4960		return (0);
4961
4962	return (zfs_set_fsacl(zhp, perms->un, perms->nvl));
4963}
4964
4965static int
4966zfs_do_allow_unallow_impl(int argc, char **argv, boolean_t un)
4967{
4968	zfs_handle_t *zhp;
4969	nvlist_t *perm_nvl = NULL;
4970	nvlist_t *update_perm_nvl = NULL;
4971	int error = 1;
4972	int c;
4973	struct allow_opts opts = { 0 };
4974
4975	const char *optstr = un ? "ldugecsrh" : "ldugecsh";
4976
4977	/* check opts */
4978	while ((c = getopt(argc, argv, optstr)) != -1) {
4979		switch (c) {
4980		case 'l':
4981			opts.local = B_TRUE;
4982			break;
4983		case 'd':
4984			opts.descend = B_TRUE;
4985			break;
4986		case 'u':
4987			opts.user = B_TRUE;
4988			break;
4989		case 'g':
4990			opts.group = B_TRUE;
4991			break;
4992		case 'e':
4993			opts.everyone = B_TRUE;
4994			break;
4995		case 's':
4996			opts.set = B_TRUE;
4997			break;
4998		case 'c':
4999			opts.create = B_TRUE;
5000			break;
5001		case 'r':
5002			opts.recursive = B_TRUE;
5003			break;
5004		case ':':
5005			(void) fprintf(stderr, gettext("missing argument for "
5006			    "'%c' option\n"), optopt);
5007			usage(B_FALSE);
5008			break;
5009		case 'h':
5010			opts.prt_usage = B_TRUE;
5011			break;
5012		case '?':
5013			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
5014			    optopt);
5015			usage(B_FALSE);
5016		}
5017	}
5018
5019	argc -= optind;
5020	argv += optind;
5021
5022	/* check arguments */
5023	parse_allow_args(argc, argv, un, &opts);
5024
5025	/* try to open the dataset */
5026	if ((zhp = zfs_open(g_zfs, opts.dataset, ZFS_TYPE_FILESYSTEM |
5027	    ZFS_TYPE_VOLUME)) == NULL) {
5028		(void) fprintf(stderr, "Failed to open dataset: %s\n",
5029		    opts.dataset);
5030		return (-1);
5031	}
5032
5033	if (zfs_get_fsacl(zhp, &perm_nvl) != 0)
5034		goto cleanup2;
5035
5036	fs_perm_set_init(&fs_perm_set);
5037	if (parse_fs_perm_set(&fs_perm_set, perm_nvl) != 0) {
5038		(void) fprintf(stderr, "Failed to parse fsacl permissions\n");
5039		goto cleanup1;
5040	}
5041
5042	if (opts.prt_perms)
5043		print_fs_perms(&fs_perm_set);
5044	else {
5045		(void) construct_fsacl_list(un, &opts, &update_perm_nvl);
5046		if (zfs_set_fsacl(zhp, un, update_perm_nvl) != 0)
5047			goto cleanup0;
5048
5049		if (un && opts.recursive) {
5050			struct deleg_perms data = { un, update_perm_nvl };
5051			if (zfs_iter_filesystems(zhp, set_deleg_perms,
5052			    &data) != 0)
5053				goto cleanup0;
5054		}
5055	}
5056
5057	error = 0;
5058
5059cleanup0:
5060	nvlist_free(perm_nvl);
5061	if (update_perm_nvl != NULL)
5062		nvlist_free(update_perm_nvl);
5063cleanup1:
5064	fs_perm_set_fini(&fs_perm_set);
5065cleanup2:
5066	zfs_close(zhp);
5067
5068	return (error);
5069}
5070
5071/*
5072 * zfs allow [-r] [-t] <tag> <snap> ...
5073 *
5074 *	-r	Recursively hold
5075 *	-t	Temporary hold (hidden option)
5076 *
5077 * Apply a user-hold with the given tag to the list of snapshots.
5078 */
5079static int
5080zfs_do_allow(int argc, char **argv)
5081{
5082	return (zfs_do_allow_unallow_impl(argc, argv, B_FALSE));
5083}
5084
5085/*
5086 * zfs unallow [-r] [-t] <tag> <snap> ...
5087 *
5088 *	-r	Recursively hold
5089 *	-t	Temporary hold (hidden option)
5090 *
5091 * Apply a user-hold with the given tag to the list of snapshots.
5092 */
5093static int
5094zfs_do_unallow(int argc, char **argv)
5095{
5096	return (zfs_do_allow_unallow_impl(argc, argv, B_TRUE));
5097}
5098
5099static int
5100zfs_do_hold_rele_impl(int argc, char **argv, boolean_t holding)
5101{
5102	int errors = 0;
5103	int i;
5104	const char *tag;
5105	boolean_t recursive = B_FALSE;
5106	boolean_t temphold = B_FALSE;
5107	const char *opts = holding ? "rt" : "r";
5108	int c;
5109
5110	/* check options */
5111	while ((c = getopt(argc, argv, opts)) != -1) {
5112		switch (c) {
5113		case 'r':
5114			recursive = B_TRUE;
5115			break;
5116		case 't':
5117			temphold = B_TRUE;
5118			break;
5119		case '?':
5120			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
5121			    optopt);
5122			usage(B_FALSE);
5123		}
5124	}
5125
5126	argc -= optind;
5127	argv += optind;
5128
5129	/* check number of arguments */
5130	if (argc < 2)
5131		usage(B_FALSE);
5132
5133	tag = argv[0];
5134	--argc;
5135	++argv;
5136
5137	if (holding && tag[0] == '.') {
5138		/* tags starting with '.' are reserved for libzfs */
5139		(void) fprintf(stderr, gettext("tag may not start with '.'\n"));
5140		usage(B_FALSE);
5141	}
5142
5143	for (i = 0; i < argc; ++i) {
5144		zfs_handle_t *zhp;
5145		char parent[ZFS_MAXNAMELEN];
5146		const char *delim;
5147		char *path = argv[i];
5148
5149		delim = strchr(path, '@');
5150		if (delim == NULL) {
5151			(void) fprintf(stderr,
5152			    gettext("'%s' is not a snapshot\n"), path);
5153			++errors;
5154			continue;
5155		}
5156		(void) strncpy(parent, path, delim - path);
5157		parent[delim - path] = '\0';
5158
5159		zhp = zfs_open(g_zfs, parent,
5160		    ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
5161		if (zhp == NULL) {
5162			++errors;
5163			continue;
5164		}
5165		if (holding) {
5166			if (zfs_hold(zhp, delim+1, tag, recursive,
5167			    temphold, B_FALSE, -1, 0, 0) != 0)
5168				++errors;
5169		} else {
5170			if (zfs_release(zhp, delim+1, tag, recursive) != 0)
5171				++errors;
5172		}
5173		zfs_close(zhp);
5174	}
5175
5176	return (errors != 0);
5177}
5178
5179/*
5180 * zfs hold [-r] [-t] <tag> <snap> ...
5181 *
5182 *	-r	Recursively hold
5183 *	-t	Temporary hold (hidden option)
5184 *
5185 * Apply a user-hold with the given tag to the list of snapshots.
5186 */
5187static int
5188zfs_do_hold(int argc, char **argv)
5189{
5190	return (zfs_do_hold_rele_impl(argc, argv, B_TRUE));
5191}
5192
5193/*
5194 * zfs release [-r] <tag> <snap> ...
5195 *
5196 *	-r	Recursively release
5197 *
5198 * Release a user-hold with the given tag from the list of snapshots.
5199 */
5200static int
5201zfs_do_release(int argc, char **argv)
5202{
5203	return (zfs_do_hold_rele_impl(argc, argv, B_FALSE));
5204}
5205
5206typedef struct holds_cbdata {
5207	boolean_t	cb_recursive;
5208	const char	*cb_snapname;
5209	nvlist_t	**cb_nvlp;
5210	size_t		cb_max_namelen;
5211	size_t		cb_max_taglen;
5212} holds_cbdata_t;
5213
5214#define	STRFTIME_FMT_STR "%a %b %e %k:%M %Y"
5215#define	DATETIME_BUF_LEN (32)
5216/*
5217 *
5218 */
5219static void
5220print_holds(boolean_t scripted, size_t nwidth, size_t tagwidth, nvlist_t *nvl)
5221{
5222	int i;
5223	nvpair_t *nvp = NULL;
5224	char *hdr_cols[] = { "NAME", "TAG", "TIMESTAMP" };
5225	const char *col;
5226
5227	if (!scripted) {
5228		for (i = 0; i < 3; i++) {
5229			col = gettext(hdr_cols[i]);
5230			if (i < 2)
5231				(void) printf("%-*s  ", i ? tagwidth : nwidth,
5232				    col);
5233			else
5234				(void) printf("%s\n", col);
5235		}
5236	}
5237
5238	while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
5239		char *zname = nvpair_name(nvp);
5240		nvlist_t *nvl2;
5241		nvpair_t *nvp2 = NULL;
5242		(void) nvpair_value_nvlist(nvp, &nvl2);
5243		while ((nvp2 = nvlist_next_nvpair(nvl2, nvp2)) != NULL) {
5244			char tsbuf[DATETIME_BUF_LEN];
5245			char *tagname = nvpair_name(nvp2);
5246			uint64_t val = 0;
5247			time_t time;
5248			struct tm t;
5249			char sep = scripted ? '\t' : ' ';
5250			size_t sepnum = scripted ? 1 : 2;
5251
5252			(void) nvpair_value_uint64(nvp2, &val);
5253			time = (time_t)val;
5254			(void) localtime_r(&time, &t);
5255			(void) strftime(tsbuf, DATETIME_BUF_LEN,
5256			    gettext(STRFTIME_FMT_STR), &t);
5257
5258			(void) printf("%-*s%*c%-*s%*c%s\n", nwidth, zname,
5259			    sepnum, sep, tagwidth, tagname, sepnum, sep, tsbuf);
5260		}
5261	}
5262}
5263
5264/*
5265 * Generic callback function to list a dataset or snapshot.
5266 */
5267static int
5268holds_callback(zfs_handle_t *zhp, void *data)
5269{
5270	holds_cbdata_t *cbp = data;
5271	nvlist_t *top_nvl = *cbp->cb_nvlp;
5272	nvlist_t *nvl = NULL;
5273	nvpair_t *nvp = NULL;
5274	const char *zname = zfs_get_name(zhp);
5275	size_t znamelen = strnlen(zname, ZFS_MAXNAMELEN);
5276
5277	if (cbp->cb_recursive) {
5278		const char *snapname;
5279		char *delim  = strchr(zname, '@');
5280		if (delim == NULL)
5281			return (0);
5282
5283		snapname = delim + 1;
5284		if (strcmp(cbp->cb_snapname, snapname))
5285			return (0);
5286	}
5287
5288	if (zfs_get_holds(zhp, &nvl) != 0)
5289		return (-1);
5290
5291	if (znamelen > cbp->cb_max_namelen)
5292		cbp->cb_max_namelen  = znamelen;
5293
5294	while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
5295		const char *tag = nvpair_name(nvp);
5296		size_t taglen = strnlen(tag, MAXNAMELEN);
5297		if (taglen > cbp->cb_max_taglen)
5298			cbp->cb_max_taglen  = taglen;
5299	}
5300
5301	return (nvlist_add_nvlist(top_nvl, zname, nvl));
5302}
5303
5304/*
5305 * zfs holds [-r] <snap> ...
5306 *
5307 *	-r	Recursively hold
5308 */
5309static int
5310zfs_do_holds(int argc, char **argv)
5311{
5312	int errors = 0;
5313	int c;
5314	int i;
5315	boolean_t scripted = B_FALSE;
5316	boolean_t recursive = B_FALSE;
5317	const char *opts = "rH";
5318	nvlist_t *nvl;
5319
5320	int types = ZFS_TYPE_SNAPSHOT;
5321	holds_cbdata_t cb = { 0 };
5322
5323	int limit = 0;
5324	int ret = 0;
5325	int flags = 0;
5326
5327	/* check options */
5328	while ((c = getopt(argc, argv, opts)) != -1) {
5329		switch (c) {
5330		case 'r':
5331			recursive = B_TRUE;
5332			break;
5333		case 'H':
5334			scripted = B_TRUE;
5335			break;
5336		case '?':
5337			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
5338			    optopt);
5339			usage(B_FALSE);
5340		}
5341	}
5342
5343	if (recursive) {
5344		types |= ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME;
5345		flags |= ZFS_ITER_RECURSE;
5346	}
5347
5348	argc -= optind;
5349	argv += optind;
5350
5351	/* check number of arguments */
5352	if (argc < 1)
5353		usage(B_FALSE);
5354
5355	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
5356		nomem();
5357
5358	for (i = 0; i < argc; ++i) {
5359		char *snapshot = argv[i];
5360		const char *delim;
5361		const char *snapname;
5362
5363		delim = strchr(snapshot, '@');
5364		if (delim == NULL) {
5365			(void) fprintf(stderr,
5366			    gettext("'%s' is not a snapshot\n"), snapshot);
5367			++errors;
5368			continue;
5369		}
5370		snapname = delim + 1;
5371		if (recursive)
5372			snapshot[delim - snapshot] = '\0';
5373
5374		cb.cb_recursive = recursive;
5375		cb.cb_snapname = snapname;
5376		cb.cb_nvlp = &nvl;
5377
5378		/*
5379		 *  1. collect holds data, set format options
5380		 */
5381		ret = zfs_for_each(argc, argv, flags, types, NULL, NULL, limit,
5382		    holds_callback, &cb);
5383		if (ret != 0)
5384			++errors;
5385	}
5386
5387	/*
5388	 *  2. print holds data
5389	 */
5390	print_holds(scripted, cb.cb_max_namelen, cb.cb_max_taglen, nvl);
5391
5392	if (nvlist_empty(nvl))
5393		(void) printf(gettext("no datasets available\n"));
5394
5395	nvlist_free(nvl);
5396
5397	return (0 != errors);
5398}
5399
5400#define	CHECK_SPINNER 30
5401#define	SPINNER_TIME 3		/* seconds */
5402#define	MOUNT_TIME 5		/* seconds */
5403
5404static int
5405get_one_dataset(zfs_handle_t *zhp, void *data)
5406{
5407	static char *spin[] = { "-", "\\", "|", "/" };
5408	static int spinval = 0;
5409	static int spincheck = 0;
5410	static time_t last_spin_time = (time_t)0;
5411	get_all_cb_t *cbp = data;
5412	zfs_type_t type = zfs_get_type(zhp);
5413
5414	if (cbp->cb_verbose) {
5415		if (--spincheck < 0) {
5416			time_t now = time(NULL);
5417			if (last_spin_time + SPINNER_TIME < now) {
5418				update_progress(spin[spinval++ % 4]);
5419				last_spin_time = now;
5420			}
5421			spincheck = CHECK_SPINNER;
5422		}
5423	}
5424
5425	/*
5426	 * Interate over any nested datasets.
5427	 */
5428	if (zfs_iter_filesystems(zhp, get_one_dataset, data) != 0) {
5429		zfs_close(zhp);
5430		return (1);
5431	}
5432
5433	/*
5434	 * Skip any datasets whose type does not match.
5435	 */
5436	if ((type & ZFS_TYPE_FILESYSTEM) == 0) {
5437		zfs_close(zhp);
5438		return (0);
5439	}
5440	libzfs_add_handle(cbp, zhp);
5441	assert(cbp->cb_used <= cbp->cb_alloc);
5442
5443	return (0);
5444}
5445
5446static void
5447get_all_datasets(zfs_handle_t ***dslist, size_t *count, boolean_t verbose)
5448{
5449	get_all_cb_t cb = { 0 };
5450	cb.cb_verbose = verbose;
5451	cb.cb_getone = get_one_dataset;
5452
5453	if (verbose)
5454		set_progress_header(gettext("Reading ZFS config"));
5455	(void) zfs_iter_root(g_zfs, get_one_dataset, &cb);
5456
5457	*dslist = cb.cb_handles;
5458	*count = cb.cb_used;
5459
5460	if (verbose)
5461		finish_progress(gettext("done."));
5462}
5463
5464/*
5465 * Generic callback for sharing or mounting filesystems.  Because the code is so
5466 * similar, we have a common function with an extra parameter to determine which
5467 * mode we are using.
5468 */
5469#define	OP_SHARE	0x1
5470#define	OP_MOUNT	0x2
5471
5472/*
5473 * Share or mount a dataset.
5474 */
5475static int
5476share_mount_one(zfs_handle_t *zhp, int op, int flags, char *protocol,
5477    boolean_t explicit, const char *options)
5478{
5479	char mountpoint[ZFS_MAXPROPLEN];
5480	char shareopts[ZFS_MAXPROPLEN];
5481	char smbshareopts[ZFS_MAXPROPLEN];
5482	const char *cmdname = op == OP_SHARE ? "share" : "mount";
5483	struct mnttab mnt;
5484	uint64_t zoned, canmount;
5485	boolean_t shared_nfs, shared_smb;
5486
5487	assert(zfs_get_type(zhp) & ZFS_TYPE_FILESYSTEM);
5488
5489	/*
5490	 * Check to make sure we can mount/share this dataset.  If we
5491	 * are in the global zone and the filesystem is exported to a
5492	 * local zone, or if we are in a local zone and the
5493	 * filesystem is not exported, then it is an error.
5494	 */
5495	zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED);
5496
5497	if (zoned && getzoneid() == GLOBAL_ZONEID) {
5498		if (!explicit)
5499			return (0);
5500
5501		(void) fprintf(stderr, gettext("cannot %s '%s': "
5502		    "dataset is exported to a local zone\n"), cmdname,
5503		    zfs_get_name(zhp));
5504		return (1);
5505
5506	} else if (!zoned && getzoneid() != GLOBAL_ZONEID) {
5507		if (!explicit)
5508			return (0);
5509
5510		(void) fprintf(stderr, gettext("cannot %s '%s': "
5511		    "permission denied\n"), cmdname,
5512		    zfs_get_name(zhp));
5513		return (1);
5514	}
5515
5516	/*
5517	 * Ignore any filesystems which don't apply to us. This
5518	 * includes those with a legacy mountpoint, or those with
5519	 * legacy share options.
5520	 */
5521	verify(zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint,
5522	    sizeof (mountpoint), NULL, NULL, 0, B_FALSE) == 0);
5523	verify(zfs_prop_get(zhp, ZFS_PROP_SHARENFS, shareopts,
5524	    sizeof (shareopts), NULL, NULL, 0, B_FALSE) == 0);
5525	verify(zfs_prop_get(zhp, ZFS_PROP_SHARESMB, smbshareopts,
5526	    sizeof (smbshareopts), NULL, NULL, 0, B_FALSE) == 0);
5527
5528	if (op == OP_SHARE && strcmp(shareopts, "off") == 0 &&
5529	    strcmp(smbshareopts, "off") == 0) {
5530		if (!explicit)
5531			return (0);
5532
5533		(void) fprintf(stderr, gettext("cannot share '%s': "
5534		    "legacy share\n"), zfs_get_name(zhp));
5535		(void) fprintf(stderr, gettext("use share(1M) to "
5536		    "share this filesystem, or set "
5537		    "sharenfs property on\n"));
5538		return (1);
5539	}
5540
5541	/*
5542	 * We cannot share or mount legacy filesystems. If the
5543	 * shareopts is non-legacy but the mountpoint is legacy, we
5544	 * treat it as a legacy share.
5545	 */
5546	if (strcmp(mountpoint, "legacy") == 0) {
5547		if (!explicit)
5548			return (0);
5549
5550		(void) fprintf(stderr, gettext("cannot %s '%s': "
5551		    "legacy mountpoint\n"), cmdname, zfs_get_name(zhp));
5552		(void) fprintf(stderr, gettext("use %s(1M) to "
5553		    "%s this filesystem\n"), cmdname, cmdname);
5554		return (1);
5555	}
5556
5557	if (strcmp(mountpoint, "none") == 0) {
5558		if (!explicit)
5559			return (0);
5560
5561		(void) fprintf(stderr, gettext("cannot %s '%s': no "
5562		    "mountpoint set\n"), cmdname, zfs_get_name(zhp));
5563		return (1);
5564	}
5565
5566	/*
5567	 * canmount	explicit	outcome
5568	 * on		no		pass through
5569	 * on		yes		pass through
5570	 * off		no		return 0
5571	 * off		yes		display error, return 1
5572	 * noauto	no		return 0
5573	 * noauto	yes		pass through
5574	 */
5575	canmount = zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT);
5576	if (canmount == ZFS_CANMOUNT_OFF) {
5577		if (!explicit)
5578			return (0);
5579
5580		(void) fprintf(stderr, gettext("cannot %s '%s': "
5581		    "'canmount' property is set to 'off'\n"), cmdname,
5582		    zfs_get_name(zhp));
5583		return (1);
5584	} else if (canmount == ZFS_CANMOUNT_NOAUTO && !explicit) {
5585		return (0);
5586	}
5587
5588	/*
5589	 * At this point, we have verified that the mountpoint and/or
5590	 * shareopts are appropriate for auto management. If the
5591	 * filesystem is already mounted or shared, return (failing
5592	 * for explicit requests); otherwise mount or share the
5593	 * filesystem.
5594	 */
5595	switch (op) {
5596	case OP_SHARE:
5597
5598		shared_nfs = zfs_is_shared_nfs(zhp, NULL);
5599		shared_smb = zfs_is_shared_smb(zhp, NULL);
5600
5601		if (shared_nfs && shared_smb ||
5602		    (shared_nfs && strcmp(shareopts, "on") == 0 &&
5603		    strcmp(smbshareopts, "off") == 0) ||
5604		    (shared_smb && strcmp(smbshareopts, "on") == 0 &&
5605		    strcmp(shareopts, "off") == 0)) {
5606			if (!explicit)
5607				return (0);
5608
5609			(void) fprintf(stderr, gettext("cannot share "
5610			    "'%s': filesystem already shared\n"),
5611			    zfs_get_name(zhp));
5612			return (1);
5613		}
5614
5615		if (!zfs_is_mounted(zhp, NULL) &&
5616		    zfs_mount(zhp, NULL, 0) != 0)
5617			return (1);
5618
5619		if (protocol == NULL) {
5620			if (zfs_shareall(zhp) != 0)
5621				return (1);
5622		} else if (strcmp(protocol, "nfs") == 0) {
5623			if (zfs_share_nfs(zhp))
5624				return (1);
5625		} else if (strcmp(protocol, "smb") == 0) {
5626			if (zfs_share_smb(zhp))
5627				return (1);
5628		} else {
5629			(void) fprintf(stderr, gettext("cannot share "
5630			    "'%s': invalid share type '%s' "
5631			    "specified\n"),
5632			    zfs_get_name(zhp), protocol);
5633			return (1);
5634		}
5635
5636		break;
5637
5638	case OP_MOUNT:
5639		if (options == NULL)
5640			mnt.mnt_mntopts = "";
5641		else
5642			mnt.mnt_mntopts = (char *)options;
5643
5644		if (!hasmntopt(&mnt, MNTOPT_REMOUNT) &&
5645		    zfs_is_mounted(zhp, NULL)) {
5646			if (!explicit)
5647				return (0);
5648
5649			(void) fprintf(stderr, gettext("cannot mount "
5650			    "'%s': filesystem already mounted\n"),
5651			    zfs_get_name(zhp));
5652			return (1);
5653		}
5654
5655		if (zfs_mount(zhp, options, flags) != 0)
5656			return (1);
5657		break;
5658	}
5659
5660	return (0);
5661}
5662
5663/*
5664 * Reports progress in the form "(current/total)".  Not thread-safe.
5665 */
5666static void
5667report_mount_progress(int current, int total)
5668{
5669	static time_t last_progress_time = 0;
5670	time_t now = time(NULL);
5671	char info[32];
5672
5673	/* report 1..n instead of 0..n-1 */
5674	++current;
5675
5676	/* display header if we're here for the first time */
5677	if (current == 1) {
5678		set_progress_header(gettext("Mounting ZFS filesystems"));
5679	} else if (current != total && last_progress_time + MOUNT_TIME >= now) {
5680		/* too soon to report again */
5681		return;
5682	}
5683
5684	last_progress_time = now;
5685
5686	(void) sprintf(info, "(%d/%d)", current, total);
5687
5688	if (current == total)
5689		finish_progress(info);
5690	else
5691		update_progress(info);
5692}
5693
5694static void
5695append_options(char *mntopts, char *newopts)
5696{
5697	int len = strlen(mntopts);
5698
5699	/* original length plus new string to append plus 1 for the comma */
5700	if (len + 1 + strlen(newopts) >= MNT_LINE_MAX) {
5701		(void) fprintf(stderr, gettext("the opts argument for "
5702		    "'%c' option is too long (more than %d chars)\n"),
5703		    "-o", MNT_LINE_MAX);
5704		usage(B_FALSE);
5705	}
5706
5707	if (*mntopts)
5708		mntopts[len++] = ',';
5709
5710	(void) strcpy(&mntopts[len], newopts);
5711}
5712
5713static int
5714share_mount(int op, int argc, char **argv)
5715{
5716	int do_all = 0;
5717	boolean_t verbose = B_FALSE;
5718	int c, ret = 0;
5719	char *options = NULL;
5720	int flags = 0;
5721
5722	/* check options */
5723	while ((c = getopt(argc, argv, op == OP_MOUNT ? ":avo:O" : "a"))
5724	    != -1) {
5725		switch (c) {
5726		case 'a':
5727			do_all = 1;
5728			break;
5729		case 'v':
5730			verbose = B_TRUE;
5731			break;
5732		case 'o':
5733			if (*optarg == '\0') {
5734				(void) fprintf(stderr, gettext("empty mount "
5735				    "options (-o) specified\n"));
5736				usage(B_FALSE);
5737			}
5738
5739			if (options == NULL)
5740				options = safe_malloc(MNT_LINE_MAX + 1);
5741
5742			/* option validation is done later */
5743			append_options(options, optarg);
5744			break;
5745
5746		case 'O':
5747			warnx("no overlay mounts support on FreeBSD, ignoring");
5748			break;
5749		case ':':
5750			(void) fprintf(stderr, gettext("missing argument for "
5751			    "'%c' option\n"), optopt);
5752			usage(B_FALSE);
5753			break;
5754		case '?':
5755			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
5756			    optopt);
5757			usage(B_FALSE);
5758		}
5759	}
5760
5761	argc -= optind;
5762	argv += optind;
5763
5764	/* check number of arguments */
5765	if (do_all) {
5766		zfs_handle_t **dslist = NULL;
5767		size_t i, count = 0;
5768		char *protocol = NULL;
5769
5770		if (op == OP_SHARE && argc > 0) {
5771			if (strcmp(argv[0], "nfs") != 0 &&
5772			    strcmp(argv[0], "smb") != 0) {
5773				(void) fprintf(stderr, gettext("share type "
5774				    "must be 'nfs' or 'smb'\n"));
5775				usage(B_FALSE);
5776			}
5777			protocol = argv[0];
5778			argc--;
5779			argv++;
5780		}
5781
5782		if (argc != 0) {
5783			(void) fprintf(stderr, gettext("too many arguments\n"));
5784			usage(B_FALSE);
5785		}
5786
5787		start_progress_timer();
5788		get_all_datasets(&dslist, &count, verbose);
5789
5790		if (count == 0)
5791			return (0);
5792
5793		qsort(dslist, count, sizeof (void *), libzfs_dataset_cmp);
5794
5795		for (i = 0; i < count; i++) {
5796			if (verbose)
5797				report_mount_progress(i, count);
5798
5799			if (share_mount_one(dslist[i], op, flags, protocol,
5800			    B_FALSE, options) != 0)
5801				ret = 1;
5802			zfs_close(dslist[i]);
5803		}
5804
5805		free(dslist);
5806	} else if (argc == 0) {
5807		struct mnttab entry;
5808
5809		if ((op == OP_SHARE) || (options != NULL)) {
5810			(void) fprintf(stderr, gettext("missing filesystem "
5811			    "argument (specify -a for all)\n"));
5812			usage(B_FALSE);
5813		}
5814
5815		/*
5816		 * When mount is given no arguments, go through /etc/mnttab and
5817		 * display any active ZFS mounts.  We hide any snapshots, since
5818		 * they are controlled automatically.
5819		 */
5820		rewind(mnttab_file);
5821		while (getmntent(mnttab_file, &entry) == 0) {
5822			if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0 ||
5823			    strchr(entry.mnt_special, '@') != NULL)
5824				continue;
5825
5826			(void) printf("%-30s  %s\n", entry.mnt_special,
5827			    entry.mnt_mountp);
5828		}
5829
5830	} else {
5831		zfs_handle_t *zhp;
5832
5833		if (argc > 1) {
5834			(void) fprintf(stderr,
5835			    gettext("too many arguments\n"));
5836			usage(B_FALSE);
5837		}
5838
5839		if ((zhp = zfs_open(g_zfs, argv[0],
5840		    ZFS_TYPE_FILESYSTEM)) == NULL) {
5841			ret = 1;
5842		} else {
5843			ret = share_mount_one(zhp, op, flags, NULL, B_TRUE,
5844			    options);
5845			zfs_close(zhp);
5846		}
5847	}
5848
5849	return (ret);
5850}
5851
5852/*
5853 * zfs mount -a [nfs]
5854 * zfs mount filesystem
5855 *
5856 * Mount all filesystems, or mount the given filesystem.
5857 */
5858static int
5859zfs_do_mount(int argc, char **argv)
5860{
5861	return (share_mount(OP_MOUNT, argc, argv));
5862}
5863
5864/*
5865 * zfs share -a [nfs | smb]
5866 * zfs share filesystem
5867 *
5868 * Share all filesystems, or share the given filesystem.
5869 */
5870static int
5871zfs_do_share(int argc, char **argv)
5872{
5873	return (share_mount(OP_SHARE, argc, argv));
5874}
5875
5876typedef struct unshare_unmount_node {
5877	zfs_handle_t	*un_zhp;
5878	char		*un_mountp;
5879	uu_avl_node_t	un_avlnode;
5880} unshare_unmount_node_t;
5881
5882/* ARGSUSED */
5883static int
5884unshare_unmount_compare(const void *larg, const void *rarg, void *unused)
5885{
5886	const unshare_unmount_node_t *l = larg;
5887	const unshare_unmount_node_t *r = rarg;
5888
5889	return (strcmp(l->un_mountp, r->un_mountp));
5890}
5891
5892/*
5893 * Convenience routine used by zfs_do_umount() and manual_unmount().  Given an
5894 * absolute path, find the entry /etc/mnttab, verify that its a ZFS filesystem,
5895 * and unmount it appropriately.
5896 */
5897static int
5898unshare_unmount_path(int op, char *path, int flags, boolean_t is_manual)
5899{
5900	zfs_handle_t *zhp;
5901	int ret = 0;
5902	struct stat64 statbuf;
5903	struct extmnttab entry;
5904	const char *cmdname = (op == OP_SHARE) ? "unshare" : "unmount";
5905	ino_t path_inode;
5906
5907	/*
5908	 * Search for the path in /etc/mnttab.  Rather than looking for the
5909	 * specific path, which can be fooled by non-standard paths (i.e. ".."
5910	 * or "//"), we stat() the path and search for the corresponding
5911	 * (major,minor) device pair.
5912	 */
5913	if (stat64(path, &statbuf) != 0) {
5914		(void) fprintf(stderr, gettext("cannot %s '%s': %s\n"),
5915		    cmdname, path, strerror(errno));
5916		return (1);
5917	}
5918	path_inode = statbuf.st_ino;
5919
5920	/*
5921	 * Search for the given (major,minor) pair in the mount table.
5922	 */
5923#ifdef sun
5924	rewind(mnttab_file);
5925	while ((ret = getextmntent(mnttab_file, &entry, 0)) == 0) {
5926		if (entry.mnt_major == major(statbuf.st_dev) &&
5927		    entry.mnt_minor == minor(statbuf.st_dev))
5928			break;
5929	}
5930#else
5931	{
5932		struct statfs sfs;
5933
5934		if (statfs(path, &sfs) != 0) {
5935			(void) fprintf(stderr, "%s: %s\n", path,
5936			    strerror(errno));
5937			ret = -1;
5938		}
5939		statfs2mnttab(&sfs, &entry);
5940	}
5941#endif
5942	if (ret != 0) {
5943		if (op == OP_SHARE) {
5944			(void) fprintf(stderr, gettext("cannot %s '%s': not "
5945			    "currently mounted\n"), cmdname, path);
5946			return (1);
5947		}
5948		(void) fprintf(stderr, gettext("warning: %s not in mnttab\n"),
5949		    path);
5950		if ((ret = umount2(path, flags)) != 0)
5951			(void) fprintf(stderr, gettext("%s: %s\n"), path,
5952			    strerror(errno));
5953		return (ret != 0);
5954	}
5955
5956	if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0) {
5957		(void) fprintf(stderr, gettext("cannot %s '%s': not a ZFS "
5958		    "filesystem\n"), cmdname, path);
5959		return (1);
5960	}
5961
5962	if ((zhp = zfs_open(g_zfs, entry.mnt_special,
5963	    ZFS_TYPE_FILESYSTEM)) == NULL)
5964		return (1);
5965
5966	ret = 1;
5967	if (stat64(entry.mnt_mountp, &statbuf) != 0) {
5968		(void) fprintf(stderr, gettext("cannot %s '%s': %s\n"),
5969		    cmdname, path, strerror(errno));
5970		goto out;
5971	} else if (statbuf.st_ino != path_inode) {
5972		(void) fprintf(stderr, gettext("cannot "
5973		    "%s '%s': not a mountpoint\n"), cmdname, path);
5974		goto out;
5975	}
5976
5977	if (op == OP_SHARE) {
5978		char nfs_mnt_prop[ZFS_MAXPROPLEN];
5979		char smbshare_prop[ZFS_MAXPROPLEN];
5980
5981		verify(zfs_prop_get(zhp, ZFS_PROP_SHARENFS, nfs_mnt_prop,
5982		    sizeof (nfs_mnt_prop), NULL, NULL, 0, B_FALSE) == 0);
5983		verify(zfs_prop_get(zhp, ZFS_PROP_SHARESMB, smbshare_prop,
5984		    sizeof (smbshare_prop), NULL, NULL, 0, B_FALSE) == 0);
5985
5986		if (strcmp(nfs_mnt_prop, "off") == 0 &&
5987		    strcmp(smbshare_prop, "off") == 0) {
5988			(void) fprintf(stderr, gettext("cannot unshare "
5989			    "'%s': legacy share\n"), path);
5990			(void) fprintf(stderr, gettext("use "
5991			    "unshare(1M) to unshare this filesystem\n"));
5992		} else if (!zfs_is_shared(zhp)) {
5993			(void) fprintf(stderr, gettext("cannot unshare '%s': "
5994			    "not currently shared\n"), path);
5995		} else {
5996			ret = zfs_unshareall_bypath(zhp, path);
5997		}
5998	} else {
5999		char mtpt_prop[ZFS_MAXPROPLEN];
6000
6001		verify(zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mtpt_prop,
6002		    sizeof (mtpt_prop), NULL, NULL, 0, B_FALSE) == 0);
6003
6004		if (is_manual) {
6005			ret = zfs_unmount(zhp, NULL, flags);
6006		} else if (strcmp(mtpt_prop, "legacy") == 0) {
6007			(void) fprintf(stderr, gettext("cannot unmount "
6008			    "'%s': legacy mountpoint\n"),
6009			    zfs_get_name(zhp));
6010			(void) fprintf(stderr, gettext("use umount(1M) "
6011			    "to unmount this filesystem\n"));
6012		} else {
6013			ret = zfs_unmountall(zhp, flags);
6014		}
6015	}
6016
6017out:
6018	zfs_close(zhp);
6019
6020	return (ret != 0);
6021}
6022
6023/*
6024 * Generic callback for unsharing or unmounting a filesystem.
6025 */
6026static int
6027unshare_unmount(int op, int argc, char **argv)
6028{
6029	int do_all = 0;
6030	int flags = 0;
6031	int ret = 0;
6032	int c;
6033	zfs_handle_t *zhp;
6034	char nfs_mnt_prop[ZFS_MAXPROPLEN];
6035	char sharesmb[ZFS_MAXPROPLEN];
6036
6037	/* check options */
6038	while ((c = getopt(argc, argv, op == OP_SHARE ? "a" : "af")) != -1) {
6039		switch (c) {
6040		case 'a':
6041			do_all = 1;
6042			break;
6043		case 'f':
6044			flags = MS_FORCE;
6045			break;
6046		case '?':
6047			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
6048			    optopt);
6049			usage(B_FALSE);
6050		}
6051	}
6052
6053	argc -= optind;
6054	argv += optind;
6055
6056	if (do_all) {
6057		/*
6058		 * We could make use of zfs_for_each() to walk all datasets in
6059		 * the system, but this would be very inefficient, especially
6060		 * since we would have to linearly search /etc/mnttab for each
6061		 * one.  Instead, do one pass through /etc/mnttab looking for
6062		 * zfs entries and call zfs_unmount() for each one.
6063		 *
6064		 * Things get a little tricky if the administrator has created
6065		 * mountpoints beneath other ZFS filesystems.  In this case, we
6066		 * have to unmount the deepest filesystems first.  To accomplish
6067		 * this, we place all the mountpoints in an AVL tree sorted by
6068		 * the special type (dataset name), and walk the result in
6069		 * reverse to make sure to get any snapshots first.
6070		 */
6071		struct mnttab entry;
6072		uu_avl_pool_t *pool;
6073		uu_avl_t *tree;
6074		unshare_unmount_node_t *node;
6075		uu_avl_index_t idx;
6076		uu_avl_walk_t *walk;
6077
6078		if (argc != 0) {
6079			(void) fprintf(stderr, gettext("too many arguments\n"));
6080			usage(B_FALSE);
6081		}
6082
6083		if (((pool = uu_avl_pool_create("unmount_pool",
6084		    sizeof (unshare_unmount_node_t),
6085		    offsetof(unshare_unmount_node_t, un_avlnode),
6086		    unshare_unmount_compare, UU_DEFAULT)) == NULL) ||
6087		    ((tree = uu_avl_create(pool, NULL, UU_DEFAULT)) == NULL))
6088			nomem();
6089
6090		rewind(mnttab_file);
6091		while (getmntent(mnttab_file, &entry) == 0) {
6092
6093			/* ignore non-ZFS entries */
6094			if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0)
6095				continue;
6096
6097			/* ignore snapshots */
6098			if (strchr(entry.mnt_special, '@') != NULL)
6099				continue;
6100
6101			if ((zhp = zfs_open(g_zfs, entry.mnt_special,
6102			    ZFS_TYPE_FILESYSTEM)) == NULL) {
6103				ret = 1;
6104				continue;
6105			}
6106
6107			switch (op) {
6108			case OP_SHARE:
6109				verify(zfs_prop_get(zhp, ZFS_PROP_SHARENFS,
6110				    nfs_mnt_prop,
6111				    sizeof (nfs_mnt_prop),
6112				    NULL, NULL, 0, B_FALSE) == 0);
6113				if (strcmp(nfs_mnt_prop, "off") != 0)
6114					break;
6115				verify(zfs_prop_get(zhp, ZFS_PROP_SHARESMB,
6116				    nfs_mnt_prop,
6117				    sizeof (nfs_mnt_prop),
6118				    NULL, NULL, 0, B_FALSE) == 0);
6119				if (strcmp(nfs_mnt_prop, "off") == 0)
6120					continue;
6121				break;
6122			case OP_MOUNT:
6123				/* Ignore legacy mounts */
6124				verify(zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT,
6125				    nfs_mnt_prop,
6126				    sizeof (nfs_mnt_prop),
6127				    NULL, NULL, 0, B_FALSE) == 0);
6128				if (strcmp(nfs_mnt_prop, "legacy") == 0)
6129					continue;
6130				/* Ignore canmount=noauto mounts */
6131				if (zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT) ==
6132				    ZFS_CANMOUNT_NOAUTO)
6133					continue;
6134			default:
6135				break;
6136			}
6137
6138			node = safe_malloc(sizeof (unshare_unmount_node_t));
6139			node->un_zhp = zhp;
6140			node->un_mountp = safe_strdup(entry.mnt_mountp);
6141
6142			uu_avl_node_init(node, &node->un_avlnode, pool);
6143
6144			if (uu_avl_find(tree, node, NULL, &idx) == NULL) {
6145				uu_avl_insert(tree, node, idx);
6146			} else {
6147				zfs_close(node->un_zhp);
6148				free(node->un_mountp);
6149				free(node);
6150			}
6151		}
6152
6153		/*
6154		 * Walk the AVL tree in reverse, unmounting each filesystem and
6155		 * removing it from the AVL tree in the process.
6156		 */
6157		if ((walk = uu_avl_walk_start(tree,
6158		    UU_WALK_REVERSE | UU_WALK_ROBUST)) == NULL)
6159			nomem();
6160
6161		while ((node = uu_avl_walk_next(walk)) != NULL) {
6162			uu_avl_remove(tree, node);
6163
6164			switch (op) {
6165			case OP_SHARE:
6166				if (zfs_unshareall_bypath(node->un_zhp,
6167				    node->un_mountp) != 0)
6168					ret = 1;
6169				break;
6170
6171			case OP_MOUNT:
6172				if (zfs_unmount(node->un_zhp,
6173				    node->un_mountp, flags) != 0)
6174					ret = 1;
6175				break;
6176			}
6177
6178			zfs_close(node->un_zhp);
6179			free(node->un_mountp);
6180			free(node);
6181		}
6182
6183		uu_avl_walk_end(walk);
6184		uu_avl_destroy(tree);
6185		uu_avl_pool_destroy(pool);
6186
6187	} else {
6188		if (argc != 1) {
6189			if (argc == 0)
6190				(void) fprintf(stderr,
6191				    gettext("missing filesystem argument\n"));
6192			else
6193				(void) fprintf(stderr,
6194				    gettext("too many arguments\n"));
6195			usage(B_FALSE);
6196		}
6197
6198		/*
6199		 * We have an argument, but it may be a full path or a ZFS
6200		 * filesystem.  Pass full paths off to unmount_path() (shared by
6201		 * manual_unmount), otherwise open the filesystem and pass to
6202		 * zfs_unmount().
6203		 */
6204		if (argv[0][0] == '/')
6205			return (unshare_unmount_path(op, argv[0],
6206			    flags, B_FALSE));
6207
6208		if ((zhp = zfs_open(g_zfs, argv[0],
6209		    ZFS_TYPE_FILESYSTEM)) == NULL)
6210			return (1);
6211
6212		verify(zfs_prop_get(zhp, op == OP_SHARE ?
6213		    ZFS_PROP_SHARENFS : ZFS_PROP_MOUNTPOINT,
6214		    nfs_mnt_prop, sizeof (nfs_mnt_prop), NULL,
6215		    NULL, 0, B_FALSE) == 0);
6216
6217		switch (op) {
6218		case OP_SHARE:
6219			verify(zfs_prop_get(zhp, ZFS_PROP_SHARENFS,
6220			    nfs_mnt_prop,
6221			    sizeof (nfs_mnt_prop),
6222			    NULL, NULL, 0, B_FALSE) == 0);
6223			verify(zfs_prop_get(zhp, ZFS_PROP_SHARESMB,
6224			    sharesmb, sizeof (sharesmb), NULL, NULL,
6225			    0, B_FALSE) == 0);
6226
6227			if (strcmp(nfs_mnt_prop, "off") == 0 &&
6228			    strcmp(sharesmb, "off") == 0) {
6229				(void) fprintf(stderr, gettext("cannot "
6230				    "unshare '%s': legacy share\n"),
6231				    zfs_get_name(zhp));
6232				(void) fprintf(stderr, gettext("use "
6233				    "unshare(1M) to unshare this "
6234				    "filesystem\n"));
6235				ret = 1;
6236			} else if (!zfs_is_shared(zhp)) {
6237				(void) fprintf(stderr, gettext("cannot "
6238				    "unshare '%s': not currently "
6239				    "shared\n"), zfs_get_name(zhp));
6240				ret = 1;
6241			} else if (zfs_unshareall(zhp) != 0) {
6242				ret = 1;
6243			}
6244			break;
6245
6246		case OP_MOUNT:
6247			if (strcmp(nfs_mnt_prop, "legacy") == 0) {
6248				(void) fprintf(stderr, gettext("cannot "
6249				    "unmount '%s': legacy "
6250				    "mountpoint\n"), zfs_get_name(zhp));
6251				(void) fprintf(stderr, gettext("use "
6252				    "umount(1M) to unmount this "
6253				    "filesystem\n"));
6254				ret = 1;
6255			} else if (!zfs_is_mounted(zhp, NULL)) {
6256				(void) fprintf(stderr, gettext("cannot "
6257				    "unmount '%s': not currently "
6258				    "mounted\n"),
6259				    zfs_get_name(zhp));
6260				ret = 1;
6261			} else if (zfs_unmountall(zhp, flags) != 0) {
6262				ret = 1;
6263			}
6264			break;
6265		}
6266
6267		zfs_close(zhp);
6268	}
6269
6270	return (ret);
6271}
6272
6273/*
6274 * zfs unmount -a
6275 * zfs unmount filesystem
6276 *
6277 * Unmount all filesystems, or a specific ZFS filesystem.
6278 */
6279static int
6280zfs_do_unmount(int argc, char **argv)
6281{
6282	return (unshare_unmount(OP_MOUNT, argc, argv));
6283}
6284
6285/*
6286 * zfs unshare -a
6287 * zfs unshare filesystem
6288 *
6289 * Unshare all filesystems, or a specific ZFS filesystem.
6290 */
6291static int
6292zfs_do_unshare(int argc, char **argv)
6293{
6294	return (unshare_unmount(OP_SHARE, argc, argv));
6295}
6296
6297/*
6298 * Attach/detach the given dataset to/from the given jail
6299 */
6300/* ARGSUSED */
6301static int
6302do_jail(int argc, char **argv, int attach)
6303{
6304	zfs_handle_t *zhp;
6305	int jailid, ret;
6306
6307	/* check number of arguments */
6308	if (argc < 3) {
6309		(void) fprintf(stderr, gettext("missing argument(s)\n"));
6310		usage(B_FALSE);
6311	}
6312	if (argc > 3) {
6313		(void) fprintf(stderr, gettext("too many arguments\n"));
6314		usage(B_FALSE);
6315	}
6316
6317	jailid = jail_getid(argv[1]);
6318	if (jailid < 0) {
6319		(void) fprintf(stderr, gettext("invalid jail id or name\n"));
6320		usage(B_FALSE);
6321	}
6322
6323	zhp = zfs_open(g_zfs, argv[2], ZFS_TYPE_FILESYSTEM);
6324	if (zhp == NULL)
6325		return (1);
6326
6327	ret = (zfs_jail(zhp, jailid, attach) != 0);
6328
6329	zfs_close(zhp);
6330	return (ret);
6331}
6332
6333/*
6334 * zfs jail jailid filesystem
6335 *
6336 * Attach the given dataset to the given jail
6337 */
6338/* ARGSUSED */
6339static int
6340zfs_do_jail(int argc, char **argv)
6341{
6342
6343	return (do_jail(argc, argv, 1));
6344}
6345
6346/*
6347 * zfs unjail jailid filesystem
6348 *
6349 * Detach the given dataset from the given jail
6350 */
6351/* ARGSUSED */
6352static int
6353zfs_do_unjail(int argc, char **argv)
6354{
6355
6356	return (do_jail(argc, argv, 0));
6357}
6358
6359/*
6360 * Called when invoked as /etc/fs/zfs/mount.  Do the mount if the mountpoint is
6361 * 'legacy'.  Otherwise, complain that use should be using 'zfs mount'.
6362 */
6363static int
6364manual_mount(int argc, char **argv)
6365{
6366	zfs_handle_t *zhp;
6367	char mountpoint[ZFS_MAXPROPLEN];
6368	char mntopts[MNT_LINE_MAX] = { '\0' };
6369	int ret = 0;
6370	int c;
6371	int flags = 0;
6372	char *dataset, *path;
6373
6374	/* check options */
6375	while ((c = getopt(argc, argv, ":mo:O")) != -1) {
6376		switch (c) {
6377		case 'o':
6378			(void) strlcpy(mntopts, optarg, sizeof (mntopts));
6379			break;
6380		case 'O':
6381			flags |= MS_OVERLAY;
6382			break;
6383		case 'm':
6384			flags |= MS_NOMNTTAB;
6385			break;
6386		case ':':
6387			(void) fprintf(stderr, gettext("missing argument for "
6388			    "'%c' option\n"), optopt);
6389			usage(B_FALSE);
6390			break;
6391		case '?':
6392			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
6393			    optopt);
6394			(void) fprintf(stderr, gettext("usage: mount [-o opts] "
6395			    "<path>\n"));
6396			return (2);
6397		}
6398	}
6399
6400	argc -= optind;
6401	argv += optind;
6402
6403	/* check that we only have two arguments */
6404	if (argc != 2) {
6405		if (argc == 0)
6406			(void) fprintf(stderr, gettext("missing dataset "
6407			    "argument\n"));
6408		else if (argc == 1)
6409			(void) fprintf(stderr,
6410			    gettext("missing mountpoint argument\n"));
6411		else
6412			(void) fprintf(stderr, gettext("too many arguments\n"));
6413		(void) fprintf(stderr, "usage: mount <dataset> <mountpoint>\n");
6414		return (2);
6415	}
6416
6417	dataset = argv[0];
6418	path = argv[1];
6419
6420	/* try to open the dataset */
6421	if ((zhp = zfs_open(g_zfs, dataset, ZFS_TYPE_FILESYSTEM)) == NULL)
6422		return (1);
6423
6424	(void) zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint,
6425	    sizeof (mountpoint), NULL, NULL, 0, B_FALSE);
6426
6427	/* check for legacy mountpoint and complain appropriately */
6428	ret = 0;
6429	if (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0) {
6430		if (zmount(dataset, path, flags, MNTTYPE_ZFS,
6431		    NULL, 0, mntopts, sizeof (mntopts)) != 0) {
6432			(void) fprintf(stderr, gettext("mount failed: %s\n"),
6433			    strerror(errno));
6434			ret = 1;
6435		}
6436	} else {
6437		(void) fprintf(stderr, gettext("filesystem '%s' cannot be "
6438		    "mounted using 'mount -F zfs'\n"), dataset);
6439		(void) fprintf(stderr, gettext("Use 'zfs set mountpoint=%s' "
6440		    "instead.\n"), path);
6441		(void) fprintf(stderr, gettext("If you must use 'mount -F zfs' "
6442		    "or /etc/vfstab, use 'zfs set mountpoint=legacy'.\n"));
6443		(void) fprintf(stderr, gettext("See zfs(1M) for more "
6444		    "information.\n"));
6445		ret = 1;
6446	}
6447
6448	return (ret);
6449}
6450
6451/*
6452 * Called when invoked as /etc/fs/zfs/umount.  Unlike a manual mount, we allow
6453 * unmounts of non-legacy filesystems, as this is the dominant administrative
6454 * interface.
6455 */
6456static int
6457manual_unmount(int argc, char **argv)
6458{
6459	int flags = 0;
6460	int c;
6461
6462	/* check options */
6463	while ((c = getopt(argc, argv, "f")) != -1) {
6464		switch (c) {
6465		case 'f':
6466			flags = MS_FORCE;
6467			break;
6468		case '?':
6469			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
6470			    optopt);
6471			(void) fprintf(stderr, gettext("usage: unmount [-f] "
6472			    "<path>\n"));
6473			return (2);
6474		}
6475	}
6476
6477	argc -= optind;
6478	argv += optind;
6479
6480	/* check arguments */
6481	if (argc != 1) {
6482		if (argc == 0)
6483			(void) fprintf(stderr, gettext("missing path "
6484			    "argument\n"));
6485		else
6486			(void) fprintf(stderr, gettext("too many arguments\n"));
6487		(void) fprintf(stderr, gettext("usage: unmount [-f] <path>\n"));
6488		return (2);
6489	}
6490
6491	return (unshare_unmount_path(OP_MOUNT, argv[0], flags, B_TRUE));
6492}
6493
6494static int
6495find_command_idx(char *command, int *idx)
6496{
6497	int i;
6498
6499	for (i = 0; i < NCOMMAND; i++) {
6500		if (command_table[i].name == NULL)
6501			continue;
6502
6503		if (strcmp(command, command_table[i].name) == 0) {
6504			*idx = i;
6505			return (0);
6506		}
6507	}
6508	return (1);
6509}
6510
6511static int
6512zfs_do_diff(int argc, char **argv)
6513{
6514	zfs_handle_t *zhp;
6515	int flags = 0;
6516	char *tosnap = NULL;
6517	char *fromsnap = NULL;
6518	char *atp, *copy;
6519	int err = 0;
6520	int c;
6521
6522	while ((c = getopt(argc, argv, "FHt")) != -1) {
6523		switch (c) {
6524		case 'F':
6525			flags |= ZFS_DIFF_CLASSIFY;
6526			break;
6527		case 'H':
6528			flags |= ZFS_DIFF_PARSEABLE;
6529			break;
6530		case 't':
6531			flags |= ZFS_DIFF_TIMESTAMP;
6532			break;
6533		default:
6534			(void) fprintf(stderr,
6535			    gettext("invalid option '%c'\n"), optopt);
6536			usage(B_FALSE);
6537		}
6538	}
6539
6540	argc -= optind;
6541	argv += optind;
6542
6543	if (argc < 1) {
6544		(void) fprintf(stderr,
6545		gettext("must provide at least one snapshot name\n"));
6546		usage(B_FALSE);
6547	}
6548
6549	if (argc > 2) {
6550		(void) fprintf(stderr, gettext("too many arguments\n"));
6551		usage(B_FALSE);
6552	}
6553
6554	fromsnap = argv[0];
6555	tosnap = (argc == 2) ? argv[1] : NULL;
6556
6557	copy = NULL;
6558	if (*fromsnap != '@')
6559		copy = strdup(fromsnap);
6560	else if (tosnap)
6561		copy = strdup(tosnap);
6562	if (copy == NULL)
6563		usage(B_FALSE);
6564
6565	if (atp = strchr(copy, '@'))
6566		*atp = '\0';
6567
6568	if ((zhp = zfs_open(g_zfs, copy, ZFS_TYPE_FILESYSTEM)) == NULL)
6569		return (1);
6570
6571	free(copy);
6572
6573	/*
6574	 * Ignore SIGPIPE so that the library can give us
6575	 * information on any failure
6576	 */
6577	(void) sigignore(SIGPIPE);
6578
6579	err = zfs_show_diffs(zhp, STDOUT_FILENO, fromsnap, tosnap, flags);
6580
6581	zfs_close(zhp);
6582
6583	return (err != 0);
6584}
6585
6586int
6587main(int argc, char **argv)
6588{
6589	int ret = 0;
6590	int i;
6591	char *progname;
6592	char *cmdname;
6593
6594	(void) setlocale(LC_ALL, "");
6595	(void) textdomain(TEXT_DOMAIN);
6596
6597	opterr = 0;
6598
6599	if ((g_zfs = libzfs_init()) == NULL) {
6600		(void) fprintf(stderr, gettext("internal error: failed to "
6601		    "initialize ZFS library\n"));
6602		return (1);
6603	}
6604
6605	zpool_set_history_str("zfs", argc, argv, history_str);
6606	verify(zpool_stage_history(g_zfs, history_str) == 0);
6607
6608	libzfs_print_on_error(g_zfs, B_TRUE);
6609
6610	if ((mnttab_file = fopen(MNTTAB, "r")) == NULL) {
6611		(void) fprintf(stderr, gettext("internal error: unable to "
6612		    "open %s\n"), MNTTAB);
6613		return (1);
6614	}
6615
6616	/*
6617	 * This command also doubles as the /etc/fs mount and unmount program.
6618	 * Determine if we should take this behavior based on argv[0].
6619	 */
6620	progname = basename(argv[0]);
6621	if (strcmp(progname, "mount") == 0) {
6622		ret = manual_mount(argc, argv);
6623	} else if (strcmp(progname, "umount") == 0) {
6624		ret = manual_unmount(argc, argv);
6625	} else {
6626		/*
6627		 * Make sure the user has specified some command.
6628		 */
6629		if (argc < 2) {
6630			(void) fprintf(stderr, gettext("missing command\n"));
6631			usage(B_FALSE);
6632		}
6633
6634		cmdname = argv[1];
6635
6636		/*
6637		 * The 'umount' command is an alias for 'unmount'
6638		 */
6639		if (strcmp(cmdname, "umount") == 0)
6640			cmdname = "unmount";
6641
6642		/*
6643		 * The 'recv' command is an alias for 'receive'
6644		 */
6645		if (strcmp(cmdname, "recv") == 0)
6646			cmdname = "receive";
6647
6648		/*
6649		 * Special case '-?'
6650		 */
6651		if (strcmp(cmdname, "-?") == 0)
6652			usage(B_TRUE);
6653
6654		/*
6655		 * Run the appropriate command.
6656		 */
6657		libzfs_mnttab_cache(g_zfs, B_TRUE);
6658		if (find_command_idx(cmdname, &i) == 0) {
6659			current_command = &command_table[i];
6660			ret = command_table[i].func(argc - 1, argv + 1);
6661		} else if (strchr(cmdname, '=') != NULL) {
6662			verify(find_command_idx("set", &i) == 0);
6663			current_command = &command_table[i];
6664			ret = command_table[i].func(argc, argv);
6665		} else {
6666			(void) fprintf(stderr, gettext("unrecognized "
6667			    "command '%s'\n"), cmdname);
6668			usage(B_FALSE);
6669		}
6670		libzfs_mnttab_cache(g_zfs, B_FALSE);
6671	}
6672
6673	(void) fclose(mnttab_file);
6674
6675	libzfs_fini(g_zfs);
6676
6677	/*
6678	 * The 'ZFS_ABORT' environment variable causes us to dump core on exit
6679	 * for the purposes of running ::findleaks.
6680	 */
6681	if (getenv("ZFS_ABORT") != NULL) {
6682		(void) printf("dumping core by request\n");
6683		abort();
6684	}
6685
6686	return (ret);
6687}
6688