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