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