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