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