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