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