xref: /illumos-gate/usr/src/cmd/zfs/zfs_main.c (revision bbf21555)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Copyright (c) 2011, 2016 by Delphix. All rights reserved.
25  * Copyright 2012 Milan Jurik. All rights reserved.
26  * Copyright 2019 Joyent, Inc.
27  * Copyright (c) 2011-2012 Pawel Jakub Dawidek. All rights reserved.
28  * Copyright (c) 2013 Steven Hartland.  All rights reserved.
29  * Copyright (c) 2014 Integros [integros.com]
30  * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>.
31  * Copyright 2016 Nexenta Systems, Inc.
32  * Copyright (c) 2018 Datto Inc.
33  * Copyright 2021 RackTop Systems, Inc.
34  */
35 
36 #include <assert.h>
37 #include <ctype.h>
38 #include <errno.h>
39 #include <getopt.h>
40 #include <libgen.h>
41 #include <libintl.h>
42 #include <libuutil.h>
43 #include <libnvpair.h>
44 #include <locale.h>
45 #include <stddef.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <strings.h>
49 #include <unistd.h>
50 #include <fcntl.h>
51 #include <zone.h>
52 #include <grp.h>
53 #include <pwd.h>
54 #include <signal.h>
55 #include <sys/debug.h>
56 #include <sys/list.h>
57 #include <sys/mkdev.h>
58 #include <sys/mntent.h>
59 #include <sys/mnttab.h>
60 #include <sys/mount.h>
61 #include <sys/stat.h>
62 #include <sys/fs/zfs.h>
63 #include <sys/types.h>
64 #include <time.h>
65 #include <sys/zfs_project.h>
66 #include <synch.h>
67 
68 #include <libzfs.h>
69 #include <libzfs_core.h>
70 #include <zfs_prop.h>
71 #include <zfs_deleg.h>
72 #include <libzutil.h>
73 #include <libuutil.h>
74 #include <aclutils.h>
75 #include <directory.h>
76 #include <idmap.h>
77 #include <libshare.h>
78 
79 #include "zfs_iter.h"
80 #include "zfs_util.h"
81 #include "zfs_comutil.h"
82 #include "zfs_projectutil.h"
83 
84 libzfs_handle_t *g_zfs;
85 
86 static FILE *mnttab_file;
87 static char history_str[HIS_MAX_RECORD_LEN];
88 static boolean_t log_history = B_TRUE;
89 
90 static int zfs_do_clone(int argc, char **argv);
91 static int zfs_do_create(int argc, char **argv);
92 static int zfs_do_destroy(int argc, char **argv);
93 static int zfs_do_get(int argc, char **argv);
94 static int zfs_do_inherit(int argc, char **argv);
95 static int zfs_do_list(int argc, char **argv);
96 static int zfs_do_mount(int argc, char **argv);
97 static int zfs_do_rename(int argc, char **argv);
98 static int zfs_do_rollback(int argc, char **argv);
99 static int zfs_do_set(int argc, char **argv);
100 static int zfs_do_upgrade(int argc, char **argv);
101 static int zfs_do_snapshot(int argc, char **argv);
102 static int zfs_do_unmount(int argc, char **argv);
103 static int zfs_do_share(int argc, char **argv);
104 static int zfs_do_unshare(int argc, char **argv);
105 static int zfs_do_send(int argc, char **argv);
106 static int zfs_do_receive(int argc, char **argv);
107 static int zfs_do_promote(int argc, char **argv);
108 static int zfs_do_userspace(int argc, char **argv);
109 static int zfs_do_allow(int argc, char **argv);
110 static int zfs_do_unallow(int argc, char **argv);
111 static int zfs_do_hold(int argc, char **argv);
112 static int zfs_do_holds(int argc, char **argv);
113 static int zfs_do_release(int argc, char **argv);
114 static int zfs_do_diff(int argc, char **argv);
115 static int zfs_do_bookmark(int argc, char **argv);
116 static int zfs_do_remap(int argc, char **argv);
117 static int zfs_do_channel_program(int argc, char **argv);
118 static int zfs_do_load_key(int argc, char **argv);
119 static int zfs_do_unload_key(int argc, char **argv);
120 static int zfs_do_change_key(int argc, char **argv);
121 static int zfs_do_project(int argc, char **argv);
122 
123 /*
124  * Enable a reasonable set of defaults for libumem debugging on DEBUG builds.
125  */
126 
127 #ifdef DEBUG
128 const char *
_umem_debug_init(void)129 _umem_debug_init(void)
130 {
131 	return ("default,verbose"); /* $UMEM_DEBUG setting */
132 }
133 
134 const char *
_umem_logging_init(void)135 _umem_logging_init(void)
136 {
137 	return ("fail,contents"); /* $UMEM_LOGGING setting */
138 }
139 #endif
140 
141 typedef enum {
142 	HELP_CLONE,
143 	HELP_CREATE,
144 	HELP_DESTROY,
145 	HELP_GET,
146 	HELP_INHERIT,
147 	HELP_UPGRADE,
148 	HELP_LIST,
149 	HELP_MOUNT,
150 	HELP_PROMOTE,
151 	HELP_RECEIVE,
152 	HELP_RENAME,
153 	HELP_ROLLBACK,
154 	HELP_SEND,
155 	HELP_SET,
156 	HELP_SHARE,
157 	HELP_SNAPSHOT,
158 	HELP_UNMOUNT,
159 	HELP_UNSHARE,
160 	HELP_ALLOW,
161 	HELP_UNALLOW,
162 	HELP_USERSPACE,
163 	HELP_GROUPSPACE,
164 	HELP_PROJECTSPACE,
165 	HELP_PROJECT,
166 	HELP_HOLD,
167 	HELP_HOLDS,
168 	HELP_RELEASE,
169 	HELP_DIFF,
170 	HELP_REMAP,
171 	HELP_BOOKMARK,
172 	HELP_CHANNEL_PROGRAM,
173 	HELP_LOAD_KEY,
174 	HELP_UNLOAD_KEY,
175 	HELP_CHANGE_KEY,
176 } zfs_help_t;
177 
178 typedef struct zfs_command {
179 	const char	*name;
180 	int		(*func)(int argc, char **argv);
181 	zfs_help_t	usage;
182 } zfs_command_t;
183 
184 /*
185  * Master command table.  Each ZFS command has a name, associated function, and
186  * usage message.  The usage messages need to be internationalized, so we have
187  * to have a function to return the usage message based on a command index.
188  *
189  * These commands are organized according to how they are displayed in the usage
190  * message.  An empty command (one with a NULL name) indicates an empty line in
191  * the generic usage message.
192  */
193 static zfs_command_t command_table[] = {
194 	{ "create",	zfs_do_create,		HELP_CREATE		},
195 	{ "destroy",	zfs_do_destroy,		HELP_DESTROY		},
196 	{ NULL },
197 	{ "snapshot",	zfs_do_snapshot,	HELP_SNAPSHOT		},
198 	{ "rollback",	zfs_do_rollback,	HELP_ROLLBACK		},
199 	{ "clone",	zfs_do_clone,		HELP_CLONE		},
200 	{ "promote",	zfs_do_promote,		HELP_PROMOTE		},
201 	{ "rename",	zfs_do_rename,		HELP_RENAME		},
202 	{ "bookmark",	zfs_do_bookmark,	HELP_BOOKMARK		},
203 	{ "program",    zfs_do_channel_program, HELP_CHANNEL_PROGRAM    },
204 	{ NULL },
205 	{ "list",	zfs_do_list,		HELP_LIST		},
206 	{ NULL },
207 	{ "set",	zfs_do_set,		HELP_SET		},
208 	{ "get",	zfs_do_get,		HELP_GET		},
209 	{ "inherit",	zfs_do_inherit,		HELP_INHERIT		},
210 	{ "upgrade",	zfs_do_upgrade,		HELP_UPGRADE		},
211 	{ NULL },
212 	{ "userspace",	zfs_do_userspace,	HELP_USERSPACE		},
213 	{ "groupspace",	zfs_do_userspace,	HELP_GROUPSPACE		},
214 	{ "projectspace", zfs_do_userspace,	HELP_PROJECTSPACE	},
215 	{ NULL },
216 	{ "project",	zfs_do_project,		HELP_PROJECT		},
217 	{ NULL },
218 	{ "mount",	zfs_do_mount,		HELP_MOUNT		},
219 	{ "unmount",	zfs_do_unmount,		HELP_UNMOUNT		},
220 	{ "share",	zfs_do_share,		HELP_SHARE		},
221 	{ "unshare",	zfs_do_unshare,		HELP_UNSHARE		},
222 	{ NULL },
223 	{ "send",	zfs_do_send,		HELP_SEND		},
224 	{ "receive",	zfs_do_receive,		HELP_RECEIVE		},
225 	{ NULL },
226 	{ "allow",	zfs_do_allow,		HELP_ALLOW		},
227 	{ NULL },
228 	{ "unallow",	zfs_do_unallow,		HELP_UNALLOW		},
229 	{ NULL },
230 	{ "hold",	zfs_do_hold,		HELP_HOLD		},
231 	{ "holds",	zfs_do_holds,		HELP_HOLDS		},
232 	{ "release",	zfs_do_release,		HELP_RELEASE		},
233 	{ "diff",	zfs_do_diff,		HELP_DIFF		},
234 	{ "remap",	zfs_do_remap,		HELP_REMAP		},
235 	{ "load-key",	zfs_do_load_key,	HELP_LOAD_KEY		},
236 	{ "unload-key",	zfs_do_unload_key,	HELP_UNLOAD_KEY		},
237 	{ "change-key",	zfs_do_change_key,	HELP_CHANGE_KEY		},
238 };
239 
240 #define	NCOMMAND	(sizeof (command_table) / sizeof (command_table[0]))
241 
242 zfs_command_t *current_command;
243 
244 static const char *
get_usage(zfs_help_t idx)245 get_usage(zfs_help_t idx)
246 {
247 	switch (idx) {
248 	case HELP_CLONE:
249 		return (gettext("\tclone [-p] [-o property=value] ... "
250 		    "<snapshot> <filesystem|volume>\n"));
251 	case HELP_CREATE:
252 		return (gettext("\tcreate [-p] [-o property=value] ... "
253 		    "<filesystem>\n"
254 		    "\tcreate [-ps] [-b blocksize] [-o property=value] ... "
255 		    "-V <size> <volume>\n"));
256 	case HELP_DESTROY:
257 		return (gettext("\tdestroy [-fnpRrv] <filesystem|volume>\n"
258 		    "\tdestroy [-dnpRrv] "
259 		    "<filesystem|volume>@<snap>[%<snap>][,...]\n"
260 		    "\tdestroy <filesystem|volume>#<bookmark>\n"));
261 	case HELP_GET:
262 		return (gettext("\tget [-rHp] [-d max] "
263 		    "[-o \"all\" | field[,...]]\n"
264 		    "\t    [-t type[,...]] [-s source[,...]]\n"
265 		    "\t    <\"all\" | property[,...]> "
266 		    "[filesystem|volume|snapshot|bookmark] ...\n"));
267 	case HELP_INHERIT:
268 		return (gettext("\tinherit [-rS] <property> "
269 		    "<filesystem|volume|snapshot> ...\n"));
270 	case HELP_UPGRADE:
271 		return (gettext("\tupgrade [-v]\n"
272 		    "\tupgrade [-r] [-V version] <-a | filesystem ...>\n"));
273 	case HELP_LIST:
274 		return (gettext("\tlist [-Hp] [-r|-d max] [-o property[,...]] "
275 		    "[-s property]...\n\t    [-S property]... [-t type[,...]] "
276 		    "[filesystem|volume|snapshot] ...\n"));
277 	case HELP_MOUNT:
278 		return (gettext("\tmount\n"
279 		    "\tmount [-lvO] [-o opts] <-a | filesystem>\n"));
280 	case HELP_PROMOTE:
281 		return (gettext("\tpromote <clone-filesystem>\n"));
282 	case HELP_RECEIVE:
283 		return (gettext("\treceive [-vnsFhu] "
284 		    "[-o <property>=<value>] ... [-x <property>] ...\n"
285 		    "\t    <filesystem|volume|snapshot>\n"
286 		    "\treceive [-vnsFhu] [-o <property>=<value>] ... "
287 		    "[-x <property>] ... \n"
288 		    "\t    [-d | -e] <filesystem>\n"
289 		    "\treceive -A <filesystem|volume>\n"));
290 	case HELP_RENAME:
291 		return (gettext("\trename [-f] <filesystem|volume|snapshot> "
292 		    "<filesystem|volume|snapshot>\n"
293 		    "\trename [-f] -p <filesystem|volume> <filesystem|volume>\n"
294 		    "\trename -r <snapshot> <snapshot>\n"));
295 	case HELP_ROLLBACK:
296 		return (gettext("\trollback [-rRf] <snapshot>\n"));
297 	case HELP_SEND:
298 		return (gettext("\tsend [-DnPpRvLecwhb] [-[iI] snapshot] "
299 		    "<snapshot>\n"
300 		    "\tsend [-nvPLecw] [-i snapshot|bookmark] "
301 		    "<filesystem|volume|snapshot>\n"
302 		    "\tsend [-nvPe] -t <receive_resume_token>\n"));
303 	case HELP_SET:
304 		return (gettext("\tset <property=value> ... "
305 		    "<filesystem|volume|snapshot> ...\n"));
306 	case HELP_SHARE:
307 		return (gettext("\tshare [-l] <-a | filesystem>\n"));
308 	case HELP_SNAPSHOT:
309 		return (gettext("\tsnapshot [-r] [-o property=value] ... "
310 		    "<filesystem|volume>@<snap> ...\n"));
311 	case HELP_UNMOUNT:
312 		return (gettext("\tunmount [-f] "
313 		    "<-a | filesystem|mountpoint>\n"));
314 	case HELP_UNSHARE:
315 		return (gettext("\tunshare "
316 		    "<-a | filesystem|mountpoint>\n"));
317 	case HELP_ALLOW:
318 		return (gettext("\tallow <filesystem|volume>\n"
319 		    "\tallow [-ldug] "
320 		    "<\"everyone\"|user|group>[,...] <perm|@setname>[,...]\n"
321 		    "\t    <filesystem|volume>\n"
322 		    "\tallow [-ld] -e <perm|@setname>[,...] "
323 		    "<filesystem|volume>\n"
324 		    "\tallow -c <perm|@setname>[,...] <filesystem|volume>\n"
325 		    "\tallow -s @setname <perm|@setname>[,...] "
326 		    "<filesystem|volume>\n"));
327 	case HELP_UNALLOW:
328 		return (gettext("\tunallow [-rldug] "
329 		    "<\"everyone\"|user|group>[,...]\n"
330 		    "\t    [<perm|@setname>[,...]] <filesystem|volume>\n"
331 		    "\tunallow [-rld] -e [<perm|@setname>[,...]] "
332 		    "<filesystem|volume>\n"
333 		    "\tunallow [-r] -c [<perm|@setname>[,...]] "
334 		    "<filesystem|volume>\n"
335 		    "\tunallow [-r] -s @setname [<perm|@setname>[,...]] "
336 		    "<filesystem|volume>\n"));
337 	case HELP_USERSPACE:
338 		return (gettext("\tuserspace [-Hinp] [-o field[,...]] "
339 		    "[-s field] ...\n"
340 		    "\t    [-S field] ... [-t type[,...]] "
341 		    "<filesystem|snapshot>\n"));
342 	case HELP_GROUPSPACE:
343 		return (gettext("\tgroupspace [-Hinp] [-o field[,...]] "
344 		    "[-s field] ...\n"
345 		    "\t    [-S field] ... [-t type[,...]] "
346 		    "<filesystem|snapshot>\n"));
347 	case HELP_PROJECTSPACE:
348 		return (gettext("\tprojectspace [-Hp] [-o field[,...]] "
349 		    "[-s field] ... \n"
350 		    "\t    [-S field] ... <filesystem|snapshot>\n"));
351 	case HELP_PROJECT:
352 		return (gettext("\tproject [-d|-r] <directory|file ...>\n"
353 		    "\tproject -c [-0] [-d|-r] [-p id] <directory|file ...>\n"
354 		    "\tproject -C [-k] [-r] <directory ...>\n"
355 		    "\tproject [-p id] [-r] [-s] <directory ...>\n"));
356 	case HELP_HOLD:
357 		return (gettext("\thold [-r] <tag> <snapshot> ...\n"));
358 	case HELP_HOLDS:
359 		return (gettext("\tholds [-r] <snapshot> ...\n"));
360 	case HELP_RELEASE:
361 		return (gettext("\trelease [-r] <tag> <snapshot> ...\n"));
362 	case HELP_DIFF:
363 		return (gettext("\tdiff [-FHt] <snapshot> "
364 		    "[snapshot|filesystem]\n"));
365 	case HELP_REMAP:
366 		return (gettext("\tremap <filesystem | volume>\n"));
367 	case HELP_BOOKMARK:
368 		return (gettext("\tbookmark <snapshot> <bookmark>\n"));
369 	case HELP_CHANNEL_PROGRAM:
370 		return (gettext("\tprogram [-jn] [-t <instruction limit>] "
371 		    "[-m <memory limit (b)>] <pool> <program file> "
372 		    "[lua args...]\n"));
373 	case HELP_LOAD_KEY:
374 		return (gettext("\tload-key [-rn] [-L <keylocation>] "
375 		    "<-a | filesystem|volume>\n"));
376 	case HELP_UNLOAD_KEY:
377 		return (gettext("\tunload-key [-r] "
378 		    "<-a | filesystem|volume>\n"));
379 	case HELP_CHANGE_KEY:
380 		return (gettext("\tchange-key [-l] [-o keyformat=<value>]\n"
381 		    "\t    [-o keylocation=<value>] [-o pbkfd2iters=<value>]\n"
382 		    "\t    <filesystem|volume>\n"
383 		    "\tchange-key -i [-l] <filesystem|volume>\n"));
384 	}
385 
386 	abort();
387 	/* NOTREACHED */
388 }
389 
390 void
nomem(void)391 nomem(void)
392 {
393 	(void) fprintf(stderr, gettext("internal error: out of memory\n"));
394 	exit(1);
395 }
396 
397 /*
398  * Utility function to guarantee malloc() success.
399  */
400 
401 void *
safe_malloc(size_t size)402 safe_malloc(size_t size)
403 {
404 	void *data;
405 
406 	if ((data = calloc(1, size)) == NULL)
407 		nomem();
408 
409 	return (data);
410 }
411 
412 void *
safe_realloc(void * data,size_t size)413 safe_realloc(void *data, size_t size)
414 {
415 	void *newp;
416 	if ((newp = realloc(data, size)) == NULL) {
417 		free(data);
418 		nomem();
419 	}
420 
421 	return (newp);
422 }
423 
424 static char *
safe_strdup(char * str)425 safe_strdup(char *str)
426 {
427 	char *dupstr = strdup(str);
428 
429 	if (dupstr == NULL)
430 		nomem();
431 
432 	return (dupstr);
433 }
434 
435 /*
436  * Callback routine that will print out information for each of
437  * the properties.
438  */
439 static int
usage_prop_cb(int prop,void * cb)440 usage_prop_cb(int prop, void *cb)
441 {
442 	FILE *fp = cb;
443 
444 	(void) fprintf(fp, "\t%-15s ", zfs_prop_to_name(prop));
445 
446 	if (zfs_prop_readonly(prop))
447 		(void) fprintf(fp, " NO    ");
448 	else
449 		(void) fprintf(fp, "YES    ");
450 
451 	if (zfs_prop_inheritable(prop))
452 		(void) fprintf(fp, "  YES   ");
453 	else
454 		(void) fprintf(fp, "   NO   ");
455 
456 	if (zfs_prop_values(prop) == NULL)
457 		(void) fprintf(fp, "-\n");
458 	else
459 		(void) fprintf(fp, "%s\n", zfs_prop_values(prop));
460 
461 	return (ZPROP_CONT);
462 }
463 
464 /*
465  * Display usage message.  If we're inside a command, display only the usage for
466  * that command.  Otherwise, iterate over the entire command table and display
467  * a complete usage message.
468  */
469 static void
usage(boolean_t requested)470 usage(boolean_t requested)
471 {
472 	int i;
473 	boolean_t show_properties = B_FALSE;
474 	FILE *fp = requested ? stdout : stderr;
475 
476 	if (current_command == NULL) {
477 
478 		(void) fprintf(fp, gettext("usage: zfs command args ...\n"));
479 		(void) fprintf(fp,
480 		    gettext("where 'command' is one of the following:\n\n"));
481 
482 		for (i = 0; i < NCOMMAND; i++) {
483 			if (command_table[i].name == NULL)
484 				(void) fprintf(fp, "\n");
485 			else
486 				(void) fprintf(fp, "%s",
487 				    get_usage(command_table[i].usage));
488 		}
489 
490 		(void) fprintf(fp, gettext("\nEach dataset is of the form: "
491 		    "pool/[dataset/]*dataset[@name]\n"));
492 	} else {
493 		(void) fprintf(fp, gettext("usage:\n"));
494 		(void) fprintf(fp, "%s", get_usage(current_command->usage));
495 	}
496 
497 	if (current_command != NULL &&
498 	    (strcmp(current_command->name, "set") == 0 ||
499 	    strcmp(current_command->name, "get") == 0 ||
500 	    strcmp(current_command->name, "inherit") == 0 ||
501 	    strcmp(current_command->name, "list") == 0))
502 		show_properties = B_TRUE;
503 
504 	if (show_properties) {
505 		(void) fprintf(fp,
506 		    gettext("\nThe following properties are supported:\n"));
507 
508 		(void) fprintf(fp, "\n\t%-14s %s  %s   %s\n\n",
509 		    "PROPERTY", "EDIT", "INHERIT", "VALUES");
510 
511 		/* Iterate over all properties */
512 		(void) zprop_iter(usage_prop_cb, fp, B_FALSE, B_TRUE,
513 		    ZFS_TYPE_DATASET);
514 
515 		(void) fprintf(fp, "\t%-15s ", "userused@...");
516 		(void) fprintf(fp, " NO       NO   <size>\n");
517 		(void) fprintf(fp, "\t%-15s ", "groupused@...");
518 		(void) fprintf(fp, " NO       NO   <size>\n");
519 		(void) fprintf(fp, "\t%-15s ", "projectused@...");
520 		(void) fprintf(fp, " NO       NO   <size>\n");
521 		(void) fprintf(fp, "\t%-15s ", "userobjused@...");
522 		(void) fprintf(fp, " NO       NO   <size>\n");
523 		(void) fprintf(fp, "\t%-15s ", "groupobjused@...");
524 		(void) fprintf(fp, " NO       NO   <size>\n");
525 		(void) fprintf(fp, "\t%-15s ", "projectobjused@...");
526 		(void) fprintf(fp, " NO       NO   <size>\n");
527 		(void) fprintf(fp, "\t%-15s ", "userquota@...");
528 		(void) fprintf(fp, "YES       NO   <size> | none\n");
529 		(void) fprintf(fp, "\t%-15s ", "groupquota@...");
530 		(void) fprintf(fp, "YES       NO   <size> | none\n");
531 		(void) fprintf(fp, "\t%-15s ", "projectquota@...");
532 		(void) fprintf(fp, "YES       NO   <size> | none\n");
533 		(void) fprintf(fp, "\t%-15s ", "userobjquota@...");
534 		(void) fprintf(fp, "YES       NO   <size> | none\n");
535 		(void) fprintf(fp, "\t%-15s ", "groupobjquota@...");
536 		(void) fprintf(fp, "YES       NO   <size> | none\n");
537 		(void) fprintf(fp, "\t%-15s ", "projectobjquota@...");
538 		(void) fprintf(fp, "YES       NO   <size> | none\n");
539 		(void) fprintf(fp, "\t%-15s ", "written@<snap>");
540 		(void) fprintf(fp, " NO       NO   <size>\n");
541 
542 		(void) fprintf(fp, gettext("\nSizes are specified in bytes "
543 		    "with standard units such as K, M, G, etc.\n"));
544 		(void) fprintf(fp, gettext("\nUser-defined properties can "
545 		    "be specified by using a name containing a colon (:).\n"));
546 		(void) fprintf(fp, gettext("\nThe {user|group|project}"
547 		    "[obj]{used|quota}@ properties must be appended with\n"
548 		    "a user|group|project specifier of one of these forms:\n"
549 		    "    POSIX name      (eg: \"matt\")\n"
550 		    "    POSIX id        (eg: \"126829\")\n"
551 		    "    SMB name@domain (eg: \"matt@sun\")\n"
552 		    "    SMB SID         (eg: \"S-1-234-567-89\")\n"));
553 	} else {
554 		(void) fprintf(fp,
555 		    gettext("\nFor the property list, run: %s\n"),
556 		    "zfs set|get");
557 		(void) fprintf(fp,
558 		    gettext("\nFor the delegated permission list, run: %s\n"),
559 		    "zfs allow|unallow");
560 	}
561 
562 	/*
563 	 * See comments at end of main().
564 	 */
565 	if (getenv("ZFS_ABORT") != NULL) {
566 		(void) printf("dumping core by request\n");
567 		abort();
568 	}
569 
570 	exit(requested ? 0 : 2);
571 }
572 
573 /*
574  * Take a property=value argument string and add it to the given nvlist.
575  * Modifies the argument inplace.
576  */
577 static boolean_t
parseprop(nvlist_t * props,char * propname)578 parseprop(nvlist_t *props, char *propname)
579 {
580 	char *propval;
581 
582 	if ((propval = strchr(propname, '=')) == NULL) {
583 		(void) fprintf(stderr, gettext("missing "
584 		    "'=' for property=value argument\n"));
585 		return (B_FALSE);
586 	}
587 	*propval = '\0';
588 	propval++;
589 	if (nvlist_exists(props, propname)) {
590 		(void) fprintf(stderr, gettext("property '%s' "
591 		    "specified multiple times\n"), propname);
592 		return (B_FALSE);
593 	}
594 	if (nvlist_add_string(props, propname, propval) != 0)
595 		nomem();
596 	return (B_TRUE);
597 }
598 
599 /*
600  * Take a property name argument and add it to the given nvlist.
601  * Modifies the argument inplace.
602  */
603 static boolean_t
parsepropname(nvlist_t * props,char * propname)604 parsepropname(nvlist_t *props, char *propname)
605 {
606 	if (strchr(propname, '=') != NULL) {
607 		(void) fprintf(stderr, gettext("invalid character "
608 		    "'=' in property argument\n"));
609 		return (B_FALSE);
610 	}
611 	if (nvlist_exists(props, propname)) {
612 		(void) fprintf(stderr, gettext("property '%s' "
613 		    "specified multiple times\n"), propname);
614 		return (B_FALSE);
615 	}
616 	if (nvlist_add_boolean(props, propname) != 0)
617 		nomem();
618 	return (B_TRUE);
619 }
620 
621 static int
parse_depth(char * opt,int * flags)622 parse_depth(char *opt, int *flags)
623 {
624 	char *tmp;
625 	int depth;
626 
627 	depth = (int)strtol(opt, &tmp, 0);
628 	if (*tmp) {
629 		(void) fprintf(stderr,
630 		    gettext("%s is not an integer\n"), optarg);
631 		usage(B_FALSE);
632 	}
633 	if (depth < 0) {
634 		(void) fprintf(stderr,
635 		    gettext("Depth can not be negative.\n"));
636 		usage(B_FALSE);
637 	}
638 	*flags |= (ZFS_ITER_DEPTH_LIMIT|ZFS_ITER_RECURSE);
639 	return (depth);
640 }
641 
642 #define	PROGRESS_DELAY 2		/* seconds */
643 
644 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";
645 static time_t pt_begin;
646 static char *pt_header = NULL;
647 static boolean_t pt_shown;
648 
649 static void
start_progress_timer(void)650 start_progress_timer(void)
651 {
652 	pt_begin = time(NULL) + PROGRESS_DELAY;
653 	pt_shown = B_FALSE;
654 }
655 
656 static void
set_progress_header(char * header)657 set_progress_header(char *header)
658 {
659 	assert(pt_header == NULL);
660 	pt_header = safe_strdup(header);
661 	if (pt_shown) {
662 		(void) printf("%s: ", header);
663 		(void) fflush(stdout);
664 	}
665 }
666 
667 static void
update_progress(char * update)668 update_progress(char *update)
669 {
670 	if (!pt_shown && time(NULL) > pt_begin) {
671 		int len = strlen(update);
672 
673 		(void) printf("%s: %s%*.*s", pt_header, update, len, len,
674 		    pt_reverse);
675 		(void) fflush(stdout);
676 		pt_shown = B_TRUE;
677 	} else if (pt_shown) {
678 		int len = strlen(update);
679 
680 		(void) printf("%s%*.*s", update, len, len, pt_reverse);
681 		(void) fflush(stdout);
682 	}
683 }
684 
685 static void
finish_progress(char * done)686 finish_progress(char *done)
687 {
688 	if (pt_shown) {
689 		(void) printf("%s\n", done);
690 		(void) fflush(stdout);
691 	}
692 	free(pt_header);
693 	pt_header = NULL;
694 }
695 
696 /*
697  * Check if the dataset is mountable and should be automatically mounted.
698  */
699 static boolean_t
should_auto_mount(zfs_handle_t * zhp)700 should_auto_mount(zfs_handle_t *zhp)
701 {
702 	if (!zfs_prop_valid_for_type(ZFS_PROP_CANMOUNT, zfs_get_type(zhp)))
703 		return (B_FALSE);
704 	return (zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT) == ZFS_CANMOUNT_ON);
705 }
706 
707 /*
708  * zfs clone [-p] [-o prop=value] ... <snap> <fs | vol>
709  *
710  * Given an existing dataset, create a writable copy whose initial contents
711  * are the same as the source.  The newly created dataset maintains a
712  * dependency on the original; the original cannot be destroyed so long as
713  * the clone exists.
714  *
715  * The '-p' flag creates all the non-existing ancestors of the target first.
716  */
717 static int
zfs_do_clone(int argc,char ** argv)718 zfs_do_clone(int argc, char **argv)
719 {
720 	zfs_handle_t *zhp = NULL;
721 	boolean_t parents = B_FALSE;
722 	nvlist_t *props;
723 	int ret = 0;
724 	int c;
725 
726 	if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0)
727 		nomem();
728 
729 	/* check options */
730 	while ((c = getopt(argc, argv, "o:p")) != -1) {
731 		switch (c) {
732 		case 'o':
733 			if (!parseprop(props, optarg)) {
734 				nvlist_free(props);
735 				return (1);
736 			}
737 			break;
738 		case 'p':
739 			parents = B_TRUE;
740 			break;
741 		case '?':
742 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
743 			    optopt);
744 			goto usage;
745 		}
746 	}
747 
748 	argc -= optind;
749 	argv += optind;
750 
751 	/* check number of arguments */
752 	if (argc < 1) {
753 		(void) fprintf(stderr, gettext("missing source dataset "
754 		    "argument\n"));
755 		goto usage;
756 	}
757 	if (argc < 2) {
758 		(void) fprintf(stderr, gettext("missing target dataset "
759 		    "argument\n"));
760 		goto usage;
761 	}
762 	if (argc > 2) {
763 		(void) fprintf(stderr, gettext("too many arguments\n"));
764 		goto usage;
765 	}
766 
767 	/* open the source dataset */
768 	if ((zhp = zfs_open(g_zfs, argv[0], ZFS_TYPE_SNAPSHOT)) == NULL)
769 		return (1);
770 
771 	if (parents && zfs_name_valid(argv[1], ZFS_TYPE_FILESYSTEM |
772 	    ZFS_TYPE_VOLUME)) {
773 		/*
774 		 * Now create the ancestors of the target dataset.  If the
775 		 * target already exists and '-p' option was used we should not
776 		 * complain.
777 		 */
778 		if (zfs_dataset_exists(g_zfs, argv[1], ZFS_TYPE_FILESYSTEM |
779 		    ZFS_TYPE_VOLUME))
780 			return (0);
781 		if (zfs_create_ancestors(g_zfs, argv[1]) != 0)
782 			return (1);
783 	}
784 
785 	/* pass to libzfs */
786 	ret = zfs_clone(zhp, argv[1], props);
787 
788 	/* create the mountpoint if necessary */
789 	if (ret == 0) {
790 		zfs_handle_t *clone;
791 
792 		clone = zfs_open(g_zfs, argv[1], ZFS_TYPE_DATASET);
793 		if (clone != NULL) {
794 			/*
795 			 * If the user doesn't want the dataset
796 			 * automatically mounted, then skip the mount/share
797 			 * step.
798 			 */
799 			if (should_auto_mount(clone)) {
800 				if ((ret = zfs_mount(clone, NULL, 0)) != 0) {
801 					(void) fprintf(stderr, gettext("clone "
802 					    "successfully created, "
803 					    "but not mounted\n"));
804 				} else if ((ret = zfs_share(clone)) != 0) {
805 					(void) fprintf(stderr, gettext("clone "
806 					    "successfully created, "
807 					    "but not shared\n"));
808 				}
809 			}
810 			zfs_close(clone);
811 		}
812 	}
813 
814 	zfs_close(zhp);
815 	nvlist_free(props);
816 
817 	return (!!ret);
818 
819 usage:
820 	if (zhp)
821 		zfs_close(zhp);
822 	nvlist_free(props);
823 	usage(B_FALSE);
824 	return (-1);
825 }
826 
827 /*
828  * zfs create [-p] [-o prop=value] ... fs
829  * zfs create [-ps] [-b blocksize] [-o prop=value] ... -V vol size
830  *
831  * Create a new dataset.  This command can be used to create filesystems
832  * and volumes.  Snapshot creation is handled by 'zfs snapshot'.
833  * For volumes, the user must specify a size to be used.
834  *
835  * The '-s' flag applies only to volumes, and indicates that we should not try
836  * to set the reservation for this volume.  By default we set a reservation
837  * equal to the size for any volume.  For pools with SPA_VERSION >=
838  * SPA_VERSION_REFRESERVATION, we set a refreservation instead.
839  *
840  * The '-p' flag creates all the non-existing ancestors of the target first.
841  */
842 static int
zfs_do_create(int argc,char ** argv)843 zfs_do_create(int argc, char **argv)
844 {
845 	zfs_type_t type = ZFS_TYPE_FILESYSTEM;
846 	zfs_handle_t *zhp = NULL;
847 	uint64_t volsize = 0;
848 	int c;
849 	boolean_t noreserve = B_FALSE;
850 	boolean_t bflag = B_FALSE;
851 	boolean_t parents = B_FALSE;
852 	int ret = 1;
853 	nvlist_t *props;
854 	uint64_t intval;
855 
856 	if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0)
857 		nomem();
858 
859 	/* check options */
860 	while ((c = getopt(argc, argv, ":V:b:so:p")) != -1) {
861 		switch (c) {
862 		case 'V':
863 			type = ZFS_TYPE_VOLUME;
864 			if (zfs_nicestrtonum(g_zfs, optarg, &intval) != 0) {
865 				(void) fprintf(stderr, gettext("bad volume "
866 				    "size '%s': %s\n"), optarg,
867 				    libzfs_error_description(g_zfs));
868 				goto error;
869 			}
870 
871 			if (nvlist_add_uint64(props,
872 			    zfs_prop_to_name(ZFS_PROP_VOLSIZE), intval) != 0)
873 				nomem();
874 			volsize = intval;
875 			break;
876 		case 'p':
877 			parents = B_TRUE;
878 			break;
879 		case 'b':
880 			bflag = B_TRUE;
881 			if (zfs_nicestrtonum(g_zfs, optarg, &intval) != 0) {
882 				(void) fprintf(stderr, gettext("bad volume "
883 				    "block size '%s': %s\n"), optarg,
884 				    libzfs_error_description(g_zfs));
885 				goto error;
886 			}
887 
888 			if (nvlist_add_uint64(props,
889 			    zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE),
890 			    intval) != 0)
891 				nomem();
892 			break;
893 		case 'o':
894 			if (!parseprop(props, optarg))
895 				goto error;
896 			break;
897 		case 's':
898 			noreserve = B_TRUE;
899 			break;
900 		case ':':
901 			(void) fprintf(stderr, gettext("missing size "
902 			    "argument\n"));
903 			goto badusage;
904 		case '?':
905 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
906 			    optopt);
907 			goto badusage;
908 		}
909 	}
910 
911 	if ((bflag || noreserve) && type != ZFS_TYPE_VOLUME) {
912 		(void) fprintf(stderr, gettext("'-s' and '-b' can only be "
913 		    "used when creating a volume\n"));
914 		goto badusage;
915 	}
916 
917 	argc -= optind;
918 	argv += optind;
919 
920 	/* check number of arguments */
921 	if (argc == 0) {
922 		(void) fprintf(stderr, gettext("missing %s argument\n"),
923 		    zfs_type_to_name(type));
924 		goto badusage;
925 	}
926 	if (argc > 1) {
927 		(void) fprintf(stderr, gettext("too many arguments\n"));
928 		goto badusage;
929 	}
930 
931 	if (type == ZFS_TYPE_VOLUME && !noreserve) {
932 		zpool_handle_t *zpool_handle;
933 		nvlist_t *real_props = NULL;
934 		uint64_t spa_version;
935 		char *p;
936 		zfs_prop_t resv_prop;
937 		char *strval;
938 		char msg[1024];
939 
940 		if ((p = strchr(argv[0], '/')) != NULL)
941 			*p = '\0';
942 		zpool_handle = zpool_open(g_zfs, argv[0]);
943 		if (p != NULL)
944 			*p = '/';
945 		if (zpool_handle == NULL)
946 			goto error;
947 		spa_version = zpool_get_prop_int(zpool_handle,
948 		    ZPOOL_PROP_VERSION, NULL);
949 		if (spa_version >= SPA_VERSION_REFRESERVATION)
950 			resv_prop = ZFS_PROP_REFRESERVATION;
951 		else
952 			resv_prop = ZFS_PROP_RESERVATION;
953 
954 		(void) snprintf(msg, sizeof (msg),
955 		    gettext("cannot create '%s'"), argv[0]);
956 		if (props && (real_props = zfs_valid_proplist(g_zfs, type,
957 		    props, 0, NULL, zpool_handle, B_TRUE, msg)) == NULL) {
958 			zpool_close(zpool_handle);
959 			goto error;
960 		}
961 
962 		volsize = zvol_volsize_to_reservation(zpool_handle, volsize,
963 		    real_props);
964 		nvlist_free(real_props);
965 		zpool_close(zpool_handle);
966 
967 		if (nvlist_lookup_string(props, zfs_prop_to_name(resv_prop),
968 		    &strval) != 0) {
969 			if (nvlist_add_uint64(props,
970 			    zfs_prop_to_name(resv_prop), volsize) != 0) {
971 				nvlist_free(props);
972 				nomem();
973 			}
974 		}
975 	}
976 
977 	if (parents && zfs_name_valid(argv[0], type)) {
978 		/*
979 		 * Now create the ancestors of target dataset.  If the target
980 		 * already exists and '-p' option was used we should not
981 		 * complain.
982 		 */
983 		if (zfs_dataset_exists(g_zfs, argv[0], type)) {
984 			ret = 0;
985 			goto error;
986 		}
987 		if (zfs_create_ancestors(g_zfs, argv[0]) != 0)
988 			goto error;
989 	}
990 
991 	/* pass to libzfs */
992 	if (zfs_create(g_zfs, argv[0], type, props) != 0)
993 		goto error;
994 
995 	if ((zhp = zfs_open(g_zfs, argv[0], ZFS_TYPE_DATASET)) == NULL)
996 		goto error;
997 
998 	ret = 0;
999 
1000 	/*
1001 	 * Mount and/or share the new filesystem as appropriate.  We provide a
1002 	 * verbose error message to let the user know that their filesystem was
1003 	 * in fact created, even if we failed to mount or share it.
1004 	 * If the user doesn't want the dataset automatically mounted,
1005 	 * then skip the mount/share step altogether.
1006 	 */
1007 	if (should_auto_mount(zhp)) {
1008 		if (zfs_mount(zhp, NULL, 0) != 0) {
1009 			(void) fprintf(stderr, gettext("filesystem "
1010 			    "successfully created, but not mounted\n"));
1011 			ret = 1;
1012 		} else if (zfs_share(zhp) != 0) {
1013 			(void) fprintf(stderr, gettext("filesystem "
1014 			    "successfully created, but not shared\n"));
1015 			ret = 1;
1016 		}
1017 	}
1018 
1019 error:
1020 	if (zhp)
1021 		zfs_close(zhp);
1022 	nvlist_free(props);
1023 	return (ret);
1024 badusage:
1025 	nvlist_free(props);
1026 	usage(B_FALSE);
1027 	return (2);
1028 }
1029 
1030 /*
1031  * zfs destroy [-rRf] <fs, vol>
1032  * zfs destroy [-rRd] <snap>
1033  *
1034  *	-r	Recursively destroy all children
1035  *	-R	Recursively destroy all dependents, including clones
1036  *	-f	Force unmounting of any dependents
1037  *	-d	If we can't destroy now, mark for deferred destruction
1038  *
1039  * Destroys the given dataset.  By default, it will unmount any filesystems,
1040  * and refuse to destroy a dataset that has any dependents.  A dependent can
1041  * either be a child, or a clone of a child.
1042  */
1043 typedef struct destroy_cbdata {
1044 	boolean_t	cb_first;
1045 	boolean_t	cb_force;
1046 	boolean_t	cb_recurse;
1047 	boolean_t	cb_error;
1048 	boolean_t	cb_doclones;
1049 	zfs_handle_t	*cb_target;
1050 	boolean_t	cb_defer_destroy;
1051 	boolean_t	cb_verbose;
1052 	boolean_t	cb_parsable;
1053 	boolean_t	cb_dryrun;
1054 	nvlist_t	*cb_nvl;
1055 	nvlist_t	*cb_batchedsnaps;
1056 
1057 	/* first snap in contiguous run */
1058 	char		*cb_firstsnap;
1059 	/* previous snap in contiguous run */
1060 	char		*cb_prevsnap;
1061 	int64_t		cb_snapused;
1062 	char		*cb_snapspec;
1063 	char		*cb_bookmark;
1064 } destroy_cbdata_t;
1065 
1066 /*
1067  * Check for any dependents based on the '-r' or '-R' flags.
1068  */
1069 static int
destroy_check_dependent(zfs_handle_t * zhp,void * data)1070 destroy_check_dependent(zfs_handle_t *zhp, void *data)
1071 {
1072 	destroy_cbdata_t *cbp = data;
1073 	const char *tname = zfs_get_name(cbp->cb_target);
1074 	const char *name = zfs_get_name(zhp);
1075 
1076 	if (strncmp(tname, name, strlen(tname)) == 0 &&
1077 	    (name[strlen(tname)] == '/' || name[strlen(tname)] == '@')) {
1078 		/*
1079 		 * This is a direct descendant, not a clone somewhere else in
1080 		 * the hierarchy.
1081 		 */
1082 		if (cbp->cb_recurse)
1083 			goto out;
1084 
1085 		if (cbp->cb_first) {
1086 			(void) fprintf(stderr, gettext("cannot destroy '%s': "
1087 			    "%s has children\n"),
1088 			    zfs_get_name(cbp->cb_target),
1089 			    zfs_type_to_name(zfs_get_type(cbp->cb_target)));
1090 			(void) fprintf(stderr, gettext("use '-r' to destroy "
1091 			    "the following datasets:\n"));
1092 			cbp->cb_first = B_FALSE;
1093 			cbp->cb_error = B_TRUE;
1094 		}
1095 
1096 		(void) fprintf(stderr, "%s\n", zfs_get_name(zhp));
1097 	} else {
1098 		/*
1099 		 * This is a clone.  We only want to report this if the '-r'
1100 		 * wasn't specified, or the target is a snapshot.
1101 		 */
1102 		if (!cbp->cb_recurse &&
1103 		    zfs_get_type(cbp->cb_target) != ZFS_TYPE_SNAPSHOT)
1104 			goto out;
1105 
1106 		if (cbp->cb_first) {
1107 			(void) fprintf(stderr, gettext("cannot destroy '%s': "
1108 			    "%s has dependent clones\n"),
1109 			    zfs_get_name(cbp->cb_target),
1110 			    zfs_type_to_name(zfs_get_type(cbp->cb_target)));
1111 			(void) fprintf(stderr, gettext("use '-R' to destroy "
1112 			    "the following datasets:\n"));
1113 			cbp->cb_first = B_FALSE;
1114 			cbp->cb_error = B_TRUE;
1115 			cbp->cb_dryrun = B_TRUE;
1116 		}
1117 
1118 		(void) fprintf(stderr, "%s\n", zfs_get_name(zhp));
1119 	}
1120 
1121 out:
1122 	zfs_close(zhp);
1123 	return (0);
1124 }
1125 
1126 static int
destroy_callback(zfs_handle_t * zhp,void * data)1127 destroy_callback(zfs_handle_t *zhp, void *data)
1128 {
1129 	destroy_cbdata_t *cb = data;
1130 	const char *name = zfs_get_name(zhp);
1131 
1132 	if (cb->cb_verbose) {
1133 		if (cb->cb_parsable) {
1134 			(void) printf("destroy\t%s\n", name);
1135 		} else if (cb->cb_dryrun) {
1136 			(void) printf(gettext("would destroy %s\n"),
1137 			    name);
1138 		} else {
1139 			(void) printf(gettext("will destroy %s\n"),
1140 			    name);
1141 		}
1142 	}
1143 
1144 	/*
1145 	 * Ignore pools (which we've already flagged as an error before getting
1146 	 * here).
1147 	 */
1148 	if (strchr(zfs_get_name(zhp), '/') == NULL &&
1149 	    zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) {
1150 		zfs_close(zhp);
1151 		return (0);
1152 	}
1153 	if (cb->cb_dryrun) {
1154 		zfs_close(zhp);
1155 		return (0);
1156 	}
1157 
1158 	/*
1159 	 * We batch up all contiguous snapshots (even of different
1160 	 * filesystems) and destroy them with one ioctl.  We can't
1161 	 * simply do all snap deletions and then all fs deletions,
1162 	 * because we must delete a clone before its origin.
1163 	 */
1164 	if (zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT) {
1165 		fnvlist_add_boolean(cb->cb_batchedsnaps, name);
1166 	} else {
1167 		int error = zfs_destroy_snaps_nvl(g_zfs,
1168 		    cb->cb_batchedsnaps, B_FALSE);
1169 		fnvlist_free(cb->cb_batchedsnaps);
1170 		cb->cb_batchedsnaps = fnvlist_alloc();
1171 
1172 		if (error != 0 ||
1173 		    zfs_unmount(zhp, NULL, cb->cb_force ? MS_FORCE : 0) != 0 ||
1174 		    zfs_destroy(zhp, cb->cb_defer_destroy) != 0) {
1175 			zfs_close(zhp);
1176 			return (-1);
1177 		}
1178 	}
1179 
1180 	zfs_close(zhp);
1181 	return (0);
1182 }
1183 
1184 static int
destroy_print_cb(zfs_handle_t * zhp,void * arg)1185 destroy_print_cb(zfs_handle_t *zhp, void *arg)
1186 {
1187 	destroy_cbdata_t *cb = arg;
1188 	const char *name = zfs_get_name(zhp);
1189 	int err = 0;
1190 
1191 	if (nvlist_exists(cb->cb_nvl, name)) {
1192 		if (cb->cb_firstsnap == NULL)
1193 			cb->cb_firstsnap = strdup(name);
1194 		if (cb->cb_prevsnap != NULL)
1195 			free(cb->cb_prevsnap);
1196 		/* this snap continues the current range */
1197 		cb->cb_prevsnap = strdup(name);
1198 		if (cb->cb_firstsnap == NULL || cb->cb_prevsnap == NULL)
1199 			nomem();
1200 		if (cb->cb_verbose) {
1201 			if (cb->cb_parsable) {
1202 				(void) printf("destroy\t%s\n", name);
1203 			} else if (cb->cb_dryrun) {
1204 				(void) printf(gettext("would destroy %s\n"),
1205 				    name);
1206 			} else {
1207 				(void) printf(gettext("will destroy %s\n"),
1208 				    name);
1209 			}
1210 		}
1211 	} else if (cb->cb_firstsnap != NULL) {
1212 		/* end of this range */
1213 		uint64_t used = 0;
1214 		err = lzc_snaprange_space(cb->cb_firstsnap,
1215 		    cb->cb_prevsnap, &used);
1216 		cb->cb_snapused += used;
1217 		free(cb->cb_firstsnap);
1218 		cb->cb_firstsnap = NULL;
1219 		free(cb->cb_prevsnap);
1220 		cb->cb_prevsnap = NULL;
1221 	}
1222 	zfs_close(zhp);
1223 	return (err);
1224 }
1225 
1226 static int
destroy_print_snapshots(zfs_handle_t * fs_zhp,destroy_cbdata_t * cb)1227 destroy_print_snapshots(zfs_handle_t *fs_zhp, destroy_cbdata_t *cb)
1228 {
1229 	int err = 0;
1230 	assert(cb->cb_firstsnap == NULL);
1231 	assert(cb->cb_prevsnap == NULL);
1232 	err = zfs_iter_snapshots_sorted(fs_zhp, destroy_print_cb, cb);
1233 	if (cb->cb_firstsnap != NULL) {
1234 		uint64_t used = 0;
1235 		if (err == 0) {
1236 			err = lzc_snaprange_space(cb->cb_firstsnap,
1237 			    cb->cb_prevsnap, &used);
1238 		}
1239 		cb->cb_snapused += used;
1240 		free(cb->cb_firstsnap);
1241 		cb->cb_firstsnap = NULL;
1242 		free(cb->cb_prevsnap);
1243 		cb->cb_prevsnap = NULL;
1244 	}
1245 	return (err);
1246 }
1247 
1248 static int
snapshot_to_nvl_cb(zfs_handle_t * zhp,void * arg)1249 snapshot_to_nvl_cb(zfs_handle_t *zhp, void *arg)
1250 {
1251 	destroy_cbdata_t *cb = arg;
1252 	int err = 0;
1253 
1254 	/* Check for clones. */
1255 	if (!cb->cb_doclones && !cb->cb_defer_destroy) {
1256 		cb->cb_target = zhp;
1257 		cb->cb_first = B_TRUE;
1258 		err = zfs_iter_dependents(zhp, B_TRUE,
1259 		    destroy_check_dependent, cb);
1260 	}
1261 
1262 	if (err == 0) {
1263 		if (nvlist_add_boolean(cb->cb_nvl, zfs_get_name(zhp)))
1264 			nomem();
1265 	}
1266 	zfs_close(zhp);
1267 	return (err);
1268 }
1269 
1270 static int
gather_snapshots(zfs_handle_t * zhp,void * arg)1271 gather_snapshots(zfs_handle_t *zhp, void *arg)
1272 {
1273 	destroy_cbdata_t *cb = arg;
1274 	int err = 0;
1275 
1276 	err = zfs_iter_snapspec(zhp, cb->cb_snapspec, snapshot_to_nvl_cb, cb);
1277 	if (err == ENOENT)
1278 		err = 0;
1279 	if (err != 0)
1280 		goto out;
1281 
1282 	if (cb->cb_verbose) {
1283 		err = destroy_print_snapshots(zhp, cb);
1284 		if (err != 0)
1285 			goto out;
1286 	}
1287 
1288 	if (cb->cb_recurse)
1289 		err = zfs_iter_filesystems(zhp, gather_snapshots, cb);
1290 
1291 out:
1292 	zfs_close(zhp);
1293 	return (err);
1294 }
1295 
1296 static int
destroy_clones(destroy_cbdata_t * cb)1297 destroy_clones(destroy_cbdata_t *cb)
1298 {
1299 	nvpair_t *pair;
1300 	for (pair = nvlist_next_nvpair(cb->cb_nvl, NULL);
1301 	    pair != NULL;
1302 	    pair = nvlist_next_nvpair(cb->cb_nvl, pair)) {
1303 		zfs_handle_t *zhp = zfs_open(g_zfs, nvpair_name(pair),
1304 		    ZFS_TYPE_SNAPSHOT);
1305 		if (zhp != NULL) {
1306 			boolean_t defer = cb->cb_defer_destroy;
1307 			int err = 0;
1308 
1309 			/*
1310 			 * We can't defer destroy non-snapshots, so set it to
1311 			 * false while destroying the clones.
1312 			 */
1313 			cb->cb_defer_destroy = B_FALSE;
1314 			err = zfs_iter_dependents(zhp, B_FALSE,
1315 			    destroy_callback, cb);
1316 			cb->cb_defer_destroy = defer;
1317 			zfs_close(zhp);
1318 			if (err != 0)
1319 				return (err);
1320 		}
1321 	}
1322 	return (0);
1323 }
1324 
1325 static int
zfs_do_destroy(int argc,char ** argv)1326 zfs_do_destroy(int argc, char **argv)
1327 {
1328 	destroy_cbdata_t cb = { 0 };
1329 	int rv = 0;
1330 	int err = 0;
1331 	int c;
1332 	zfs_handle_t *zhp = NULL;
1333 	char *at, *pound;
1334 	zfs_type_t type = ZFS_TYPE_DATASET;
1335 
1336 	/* check options */
1337 	while ((c = getopt(argc, argv, "vpndfrR")) != -1) {
1338 		switch (c) {
1339 		case 'v':
1340 			cb.cb_verbose = B_TRUE;
1341 			break;
1342 		case 'p':
1343 			cb.cb_verbose = B_TRUE;
1344 			cb.cb_parsable = B_TRUE;
1345 			break;
1346 		case 'n':
1347 			cb.cb_dryrun = B_TRUE;
1348 			break;
1349 		case 'd':
1350 			cb.cb_defer_destroy = B_TRUE;
1351 			type = ZFS_TYPE_SNAPSHOT;
1352 			break;
1353 		case 'f':
1354 			cb.cb_force = B_TRUE;
1355 			break;
1356 		case 'r':
1357 			cb.cb_recurse = B_TRUE;
1358 			break;
1359 		case 'R':
1360 			cb.cb_recurse = B_TRUE;
1361 			cb.cb_doclones = B_TRUE;
1362 			break;
1363 		case '?':
1364 		default:
1365 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1366 			    optopt);
1367 			usage(B_FALSE);
1368 		}
1369 	}
1370 
1371 	argc -= optind;
1372 	argv += optind;
1373 
1374 	/* check number of arguments */
1375 	if (argc == 0) {
1376 		(void) fprintf(stderr, gettext("missing dataset argument\n"));
1377 		usage(B_FALSE);
1378 	}
1379 	if (argc > 1) {
1380 		(void) fprintf(stderr, gettext("too many arguments\n"));
1381 		usage(B_FALSE);
1382 	}
1383 
1384 	at = strchr(argv[0], '@');
1385 	pound = strchr(argv[0], '#');
1386 	if (at != NULL) {
1387 
1388 		/* Build the list of snaps to destroy in cb_nvl. */
1389 		cb.cb_nvl = fnvlist_alloc();
1390 
1391 		*at = '\0';
1392 		zhp = zfs_open(g_zfs, argv[0],
1393 		    ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
1394 		if (zhp == NULL)
1395 			return (1);
1396 
1397 		cb.cb_snapspec = at + 1;
1398 		if (gather_snapshots(zfs_handle_dup(zhp), &cb) != 0 ||
1399 		    cb.cb_error) {
1400 			rv = 1;
1401 			goto out;
1402 		}
1403 
1404 		if (nvlist_empty(cb.cb_nvl)) {
1405 			(void) fprintf(stderr, gettext("could not find any "
1406 			    "snapshots to destroy; check snapshot names.\n"));
1407 			rv = 1;
1408 			goto out;
1409 		}
1410 
1411 		if (cb.cb_verbose) {
1412 			char buf[16];
1413 			zfs_nicenum(cb.cb_snapused, buf, sizeof (buf));
1414 			if (cb.cb_parsable) {
1415 				(void) printf("reclaim\t%llu\n",
1416 				    cb.cb_snapused);
1417 			} else if (cb.cb_dryrun) {
1418 				(void) printf(gettext("would reclaim %s\n"),
1419 				    buf);
1420 			} else {
1421 				(void) printf(gettext("will reclaim %s\n"),
1422 				    buf);
1423 			}
1424 		}
1425 
1426 		if (!cb.cb_dryrun) {
1427 			if (cb.cb_doclones) {
1428 				cb.cb_batchedsnaps = fnvlist_alloc();
1429 				err = destroy_clones(&cb);
1430 				if (err == 0) {
1431 					err = zfs_destroy_snaps_nvl(g_zfs,
1432 					    cb.cb_batchedsnaps, B_FALSE);
1433 				}
1434 				if (err != 0) {
1435 					rv = 1;
1436 					goto out;
1437 				}
1438 			}
1439 			if (err == 0) {
1440 				err = zfs_destroy_snaps_nvl(g_zfs, cb.cb_nvl,
1441 				    cb.cb_defer_destroy);
1442 			}
1443 		}
1444 
1445 		if (err != 0)
1446 			rv = 1;
1447 	} else if (pound != NULL) {
1448 		int err;
1449 		nvlist_t *nvl;
1450 
1451 		if (cb.cb_dryrun) {
1452 			(void) fprintf(stderr,
1453 			    "dryrun is not supported with bookmark\n");
1454 			return (-1);
1455 		}
1456 
1457 		if (cb.cb_defer_destroy) {
1458 			(void) fprintf(stderr,
1459 			    "defer destroy is not supported with bookmark\n");
1460 			return (-1);
1461 		}
1462 
1463 		if (cb.cb_recurse) {
1464 			(void) fprintf(stderr,
1465 			    "recursive is not supported with bookmark\n");
1466 			return (-1);
1467 		}
1468 
1469 		if (!zfs_bookmark_exists(argv[0])) {
1470 			(void) fprintf(stderr, gettext("bookmark '%s' "
1471 			    "does not exist.\n"), argv[0]);
1472 			return (1);
1473 		}
1474 
1475 		nvl = fnvlist_alloc();
1476 		fnvlist_add_boolean(nvl, argv[0]);
1477 
1478 		err = lzc_destroy_bookmarks(nvl, NULL);
1479 		if (err != 0) {
1480 			(void) zfs_standard_error(g_zfs, err,
1481 			    "cannot destroy bookmark");
1482 		}
1483 
1484 		nvlist_free(cb.cb_nvl);
1485 
1486 		return (err);
1487 	} else {
1488 		/* Open the given dataset */
1489 		if ((zhp = zfs_open(g_zfs, argv[0], type)) == NULL)
1490 			return (1);
1491 
1492 		cb.cb_target = zhp;
1493 
1494 		/*
1495 		 * Perform an explicit check for pools before going any further.
1496 		 */
1497 		if (!cb.cb_recurse && strchr(zfs_get_name(zhp), '/') == NULL &&
1498 		    zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) {
1499 			(void) fprintf(stderr, gettext("cannot destroy '%s': "
1500 			    "operation does not apply to pools\n"),
1501 			    zfs_get_name(zhp));
1502 			(void) fprintf(stderr, gettext("use 'zfs destroy -r "
1503 			    "%s' to destroy all datasets in the pool\n"),
1504 			    zfs_get_name(zhp));
1505 			(void) fprintf(stderr, gettext("use 'zpool destroy %s' "
1506 			    "to destroy the pool itself\n"), zfs_get_name(zhp));
1507 			rv = 1;
1508 			goto out;
1509 		}
1510 
1511 		/*
1512 		 * Check for any dependents and/or clones.
1513 		 */
1514 		cb.cb_first = B_TRUE;
1515 		if (!cb.cb_doclones &&
1516 		    zfs_iter_dependents(zhp, B_TRUE, destroy_check_dependent,
1517 		    &cb) != 0) {
1518 			rv = 1;
1519 			goto out;
1520 		}
1521 
1522 		if (cb.cb_error) {
1523 			rv = 1;
1524 			goto out;
1525 		}
1526 
1527 		cb.cb_batchedsnaps = fnvlist_alloc();
1528 		if (zfs_iter_dependents(zhp, B_FALSE, destroy_callback,
1529 		    &cb) != 0) {
1530 			rv = 1;
1531 			goto out;
1532 		}
1533 
1534 		/*
1535 		 * Do the real thing.  The callback will close the
1536 		 * handle regardless of whether it succeeds or not.
1537 		 */
1538 		err = destroy_callback(zhp, &cb);
1539 		zhp = NULL;
1540 		if (err == 0) {
1541 			err = zfs_destroy_snaps_nvl(g_zfs,
1542 			    cb.cb_batchedsnaps, cb.cb_defer_destroy);
1543 		}
1544 		if (err != 0)
1545 			rv = 1;
1546 	}
1547 
1548 out:
1549 	fnvlist_free(cb.cb_batchedsnaps);
1550 	fnvlist_free(cb.cb_nvl);
1551 	if (zhp != NULL)
1552 		zfs_close(zhp);
1553 	return (rv);
1554 }
1555 
1556 static boolean_t
is_recvd_column(zprop_get_cbdata_t * cbp)1557 is_recvd_column(zprop_get_cbdata_t *cbp)
1558 {
1559 	int i;
1560 	zfs_get_column_t col;
1561 
1562 	for (i = 0; i < ZFS_GET_NCOLS &&
1563 	    (col = cbp->cb_columns[i]) != GET_COL_NONE; i++)
1564 		if (col == GET_COL_RECVD)
1565 			return (B_TRUE);
1566 	return (B_FALSE);
1567 }
1568 
1569 /*
1570  * zfs get [-rHp] [-o all | field[,field]...] [-s source[,source]...]
1571  *	< all | property[,property]... > < fs | snap | vol > ...
1572  *
1573  *	-r	recurse over any child datasets
1574  *	-H	scripted mode.  Headers are stripped, and fields are separated
1575  *		by tabs instead of spaces.
1576  *	-o	Set of fields to display.  One of "name,property,value,
1577  *		received,source". Default is "name,property,value,source".
1578  *		"all" is an alias for all five.
1579  *	-s	Set of sources to allow.  One of
1580  *		"local,default,inherited,received,temporary,none".  Default is
1581  *		all six.
1582  *	-p	Display values in parsable (literal) format.
1583  *
1584  *  Prints properties for the given datasets.  The user can control which
1585  *  columns to display as well as which property types to allow.
1586  */
1587 
1588 /*
1589  * Invoked to display the properties for a single dataset.
1590  */
1591 static int
get_callback(zfs_handle_t * zhp,void * data)1592 get_callback(zfs_handle_t *zhp, void *data)
1593 {
1594 	char buf[ZFS_MAXPROPLEN];
1595 	char rbuf[ZFS_MAXPROPLEN];
1596 	zprop_source_t sourcetype;
1597 	char source[ZFS_MAX_DATASET_NAME_LEN];
1598 	zprop_get_cbdata_t *cbp = data;
1599 	nvlist_t *user_props = zfs_get_user_props(zhp);
1600 	zprop_list_t *pl = cbp->cb_proplist;
1601 	nvlist_t *propval;
1602 	char *strval;
1603 	char *sourceval;
1604 	boolean_t received = is_recvd_column(cbp);
1605 
1606 	for (; pl != NULL; pl = pl->pl_next) {
1607 		char *recvdval = NULL;
1608 		/*
1609 		 * Skip the special fake placeholder.  This will also skip over
1610 		 * the name property when 'all' is specified.
1611 		 */
1612 		if (pl->pl_prop == ZFS_PROP_NAME &&
1613 		    pl == cbp->cb_proplist)
1614 			continue;
1615 
1616 		if (pl->pl_prop != ZPROP_INVAL) {
1617 			if (zfs_prop_get(zhp, pl->pl_prop, buf,
1618 			    sizeof (buf), &sourcetype, source,
1619 			    sizeof (source),
1620 			    cbp->cb_literal) != 0) {
1621 				if (pl->pl_all)
1622 					continue;
1623 				if (!zfs_prop_valid_for_type(pl->pl_prop,
1624 				    ZFS_TYPE_DATASET)) {
1625 					(void) fprintf(stderr,
1626 					    gettext("No such property '%s'\n"),
1627 					    zfs_prop_to_name(pl->pl_prop));
1628 					continue;
1629 				}
1630 				sourcetype = ZPROP_SRC_NONE;
1631 				(void) strlcpy(buf, "-", sizeof (buf));
1632 			}
1633 
1634 			if (received && (zfs_prop_get_recvd(zhp,
1635 			    zfs_prop_to_name(pl->pl_prop), rbuf, sizeof (rbuf),
1636 			    cbp->cb_literal) == 0))
1637 				recvdval = rbuf;
1638 
1639 			zprop_print_one_property(zfs_get_name(zhp), cbp,
1640 			    zfs_prop_to_name(pl->pl_prop),
1641 			    buf, sourcetype, source, recvdval);
1642 		} else if (zfs_prop_userquota(pl->pl_user_prop)) {
1643 			sourcetype = ZPROP_SRC_LOCAL;
1644 
1645 			if (zfs_prop_get_userquota(zhp, pl->pl_user_prop,
1646 			    buf, sizeof (buf), cbp->cb_literal) != 0) {
1647 				sourcetype = ZPROP_SRC_NONE;
1648 				(void) strlcpy(buf, "-", sizeof (buf));
1649 			}
1650 
1651 			zprop_print_one_property(zfs_get_name(zhp), cbp,
1652 			    pl->pl_user_prop, buf, sourcetype, source, NULL);
1653 		} else if (zfs_prop_written(pl->pl_user_prop)) {
1654 			sourcetype = ZPROP_SRC_LOCAL;
1655 
1656 			if (zfs_prop_get_written(zhp, pl->pl_user_prop,
1657 			    buf, sizeof (buf), cbp->cb_literal) != 0) {
1658 				sourcetype = ZPROP_SRC_NONE;
1659 				(void) strlcpy(buf, "-", sizeof (buf));
1660 			}
1661 
1662 			zprop_print_one_property(zfs_get_name(zhp), cbp,
1663 			    pl->pl_user_prop, buf, sourcetype, source, NULL);
1664 		} else {
1665 			if (nvlist_lookup_nvlist(user_props,
1666 			    pl->pl_user_prop, &propval) != 0) {
1667 				if (pl->pl_all)
1668 					continue;
1669 				sourcetype = ZPROP_SRC_NONE;
1670 				strval = "-";
1671 			} else {
1672 				verify(nvlist_lookup_string(propval,
1673 				    ZPROP_VALUE, &strval) == 0);
1674 				verify(nvlist_lookup_string(propval,
1675 				    ZPROP_SOURCE, &sourceval) == 0);
1676 
1677 				if (strcmp(sourceval,
1678 				    zfs_get_name(zhp)) == 0) {
1679 					sourcetype = ZPROP_SRC_LOCAL;
1680 				} else if (strcmp(sourceval,
1681 				    ZPROP_SOURCE_VAL_RECVD) == 0) {
1682 					sourcetype = ZPROP_SRC_RECEIVED;
1683 				} else {
1684 					sourcetype = ZPROP_SRC_INHERITED;
1685 					(void) strlcpy(source,
1686 					    sourceval, sizeof (source));
1687 				}
1688 			}
1689 
1690 			if (received && (zfs_prop_get_recvd(zhp,
1691 			    pl->pl_user_prop, rbuf, sizeof (rbuf),
1692 			    cbp->cb_literal) == 0))
1693 				recvdval = rbuf;
1694 
1695 			zprop_print_one_property(zfs_get_name(zhp), cbp,
1696 			    pl->pl_user_prop, strval, sourcetype,
1697 			    source, recvdval);
1698 		}
1699 	}
1700 
1701 	return (0);
1702 }
1703 
1704 static int
zfs_do_get(int argc,char ** argv)1705 zfs_do_get(int argc, char **argv)
1706 {
1707 	zprop_get_cbdata_t cb = { 0 };
1708 	int i, c, flags = ZFS_ITER_ARGS_CAN_BE_PATHS;
1709 	int types = ZFS_TYPE_DATASET | ZFS_TYPE_BOOKMARK;
1710 	char *value, *fields;
1711 	int ret = 0;
1712 	int limit = 0;
1713 	zprop_list_t fake_name = { 0 };
1714 
1715 	/*
1716 	 * Set up default columns and sources.
1717 	 */
1718 	cb.cb_sources = ZPROP_SRC_ALL;
1719 	cb.cb_columns[0] = GET_COL_NAME;
1720 	cb.cb_columns[1] = GET_COL_PROPERTY;
1721 	cb.cb_columns[2] = GET_COL_VALUE;
1722 	cb.cb_columns[3] = GET_COL_SOURCE;
1723 	cb.cb_type = ZFS_TYPE_DATASET;
1724 
1725 	/* check options */
1726 	while ((c = getopt(argc, argv, ":d:o:s:rt:Hp")) != -1) {
1727 		switch (c) {
1728 		case 'p':
1729 			cb.cb_literal = B_TRUE;
1730 			break;
1731 		case 'd':
1732 			limit = parse_depth(optarg, &flags);
1733 			break;
1734 		case 'r':
1735 			flags |= ZFS_ITER_RECURSE;
1736 			break;
1737 		case 'H':
1738 			cb.cb_scripted = B_TRUE;
1739 			break;
1740 		case ':':
1741 			(void) fprintf(stderr, gettext("missing argument for "
1742 			    "'%c' option\n"), optopt);
1743 			usage(B_FALSE);
1744 			break;
1745 		case 'o':
1746 			/*
1747 			 * Process the set of columns to display.  We zero out
1748 			 * the structure to give us a blank slate.
1749 			 */
1750 			bzero(&cb.cb_columns, sizeof (cb.cb_columns));
1751 			i = 0;
1752 			while (*optarg != '\0') {
1753 				static char *col_subopts[] =
1754 				    { "name", "property", "value", "received",
1755 				    "source", "all", NULL };
1756 
1757 				if (i == ZFS_GET_NCOLS) {
1758 					(void) fprintf(stderr, gettext("too "
1759 					    "many fields given to -o "
1760 					    "option\n"));
1761 					usage(B_FALSE);
1762 				}
1763 
1764 				switch (getsubopt(&optarg, col_subopts,
1765 				    &value)) {
1766 				case 0:
1767 					cb.cb_columns[i++] = GET_COL_NAME;
1768 					break;
1769 				case 1:
1770 					cb.cb_columns[i++] = GET_COL_PROPERTY;
1771 					break;
1772 				case 2:
1773 					cb.cb_columns[i++] = GET_COL_VALUE;
1774 					break;
1775 				case 3:
1776 					cb.cb_columns[i++] = GET_COL_RECVD;
1777 					flags |= ZFS_ITER_RECVD_PROPS;
1778 					break;
1779 				case 4:
1780 					cb.cb_columns[i++] = GET_COL_SOURCE;
1781 					break;
1782 				case 5:
1783 					if (i > 0) {
1784 						(void) fprintf(stderr,
1785 						    gettext("\"all\" conflicts "
1786 						    "with specific fields "
1787 						    "given to -o option\n"));
1788 						usage(B_FALSE);
1789 					}
1790 					cb.cb_columns[0] = GET_COL_NAME;
1791 					cb.cb_columns[1] = GET_COL_PROPERTY;
1792 					cb.cb_columns[2] = GET_COL_VALUE;
1793 					cb.cb_columns[3] = GET_COL_RECVD;
1794 					cb.cb_columns[4] = GET_COL_SOURCE;
1795 					flags |= ZFS_ITER_RECVD_PROPS;
1796 					i = ZFS_GET_NCOLS;
1797 					break;
1798 				default:
1799 					(void) fprintf(stderr,
1800 					    gettext("invalid column name "
1801 					    "'%s'\n"), value);
1802 					usage(B_FALSE);
1803 				}
1804 			}
1805 			break;
1806 
1807 		case 's':
1808 			cb.cb_sources = 0;
1809 			while (*optarg != '\0') {
1810 				static char *source_subopts[] = {
1811 					"local", "default", "inherited",
1812 					"received", "temporary", "none",
1813 					NULL };
1814 
1815 				switch (getsubopt(&optarg, source_subopts,
1816 				    &value)) {
1817 				case 0:
1818 					cb.cb_sources |= ZPROP_SRC_LOCAL;
1819 					break;
1820 				case 1:
1821 					cb.cb_sources |= ZPROP_SRC_DEFAULT;
1822 					break;
1823 				case 2:
1824 					cb.cb_sources |= ZPROP_SRC_INHERITED;
1825 					break;
1826 				case 3:
1827 					cb.cb_sources |= ZPROP_SRC_RECEIVED;
1828 					break;
1829 				case 4:
1830 					cb.cb_sources |= ZPROP_SRC_TEMPORARY;
1831 					break;
1832 				case 5:
1833 					cb.cb_sources |= ZPROP_SRC_NONE;
1834 					break;
1835 				default:
1836 					(void) fprintf(stderr,
1837 					    gettext("invalid source "
1838 					    "'%s'\n"), value);
1839 					usage(B_FALSE);
1840 				}
1841 			}
1842 			break;
1843 
1844 		case 't':
1845 			types = 0;
1846 			flags &= ~ZFS_ITER_PROP_LISTSNAPS;
1847 			while (*optarg != '\0') {
1848 				static char *type_subopts[] = { "filesystem",
1849 				    "volume", "snapshot", "bookmark",
1850 				    "all", NULL };
1851 
1852 				switch (getsubopt(&optarg, type_subopts,
1853 				    &value)) {
1854 				case 0:
1855 					types |= ZFS_TYPE_FILESYSTEM;
1856 					break;
1857 				case 1:
1858 					types |= ZFS_TYPE_VOLUME;
1859 					break;
1860 				case 2:
1861 					types |= ZFS_TYPE_SNAPSHOT;
1862 					break;
1863 				case 3:
1864 					types |= ZFS_TYPE_BOOKMARK;
1865 					break;
1866 				case 4:
1867 					types = ZFS_TYPE_DATASET |
1868 					    ZFS_TYPE_BOOKMARK;
1869 					break;
1870 
1871 				default:
1872 					(void) fprintf(stderr,
1873 					    gettext("invalid type '%s'\n"),
1874 					    value);
1875 					usage(B_FALSE);
1876 				}
1877 			}
1878 			break;
1879 
1880 		case '?':
1881 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1882 			    optopt);
1883 			usage(B_FALSE);
1884 		}
1885 	}
1886 
1887 	argc -= optind;
1888 	argv += optind;
1889 
1890 	if (argc < 1) {
1891 		(void) fprintf(stderr, gettext("missing property "
1892 		    "argument\n"));
1893 		usage(B_FALSE);
1894 	}
1895 
1896 	fields = argv[0];
1897 
1898 	if (zprop_get_list(g_zfs, fields, &cb.cb_proplist, ZFS_TYPE_DATASET)
1899 	    != 0)
1900 		usage(B_FALSE);
1901 
1902 	argc--;
1903 	argv++;
1904 
1905 	/*
1906 	 * As part of zfs_expand_proplist(), we keep track of the maximum column
1907 	 * width for each property.  For the 'NAME' (and 'SOURCE') columns, we
1908 	 * need to know the maximum name length.  However, the user likely did
1909 	 * not specify 'name' as one of the properties to fetch, so we need to
1910 	 * make sure we always include at least this property for
1911 	 * print_get_headers() to work properly.
1912 	 */
1913 	if (cb.cb_proplist != NULL) {
1914 		fake_name.pl_prop = ZFS_PROP_NAME;
1915 		fake_name.pl_width = strlen(gettext("NAME"));
1916 		fake_name.pl_next = cb.cb_proplist;
1917 		cb.cb_proplist = &fake_name;
1918 	}
1919 
1920 	cb.cb_first = B_TRUE;
1921 
1922 	/* run for each object */
1923 	ret = zfs_for_each(argc, argv, flags, types, NULL,
1924 	    &cb.cb_proplist, limit, get_callback, &cb);
1925 
1926 	if (cb.cb_proplist == &fake_name)
1927 		zprop_free_list(fake_name.pl_next);
1928 	else
1929 		zprop_free_list(cb.cb_proplist);
1930 
1931 	return (ret);
1932 }
1933 
1934 /*
1935  * inherit [-rS] <property> <fs|vol> ...
1936  *
1937  *	-r	Recurse over all children
1938  *	-S	Revert to received value, if any
1939  *
1940  * For each dataset specified on the command line, inherit the given property
1941  * from its parent.  Inheriting a property at the pool level will cause it to
1942  * use the default value.  The '-r' flag will recurse over all children, and is
1943  * useful for setting a property on a hierarchy-wide basis, regardless of any
1944  * local modifications for each dataset.
1945  */
1946 
1947 typedef struct inherit_cbdata {
1948 	const char *cb_propname;
1949 	boolean_t cb_received;
1950 } inherit_cbdata_t;
1951 
1952 static int
inherit_recurse_cb(zfs_handle_t * zhp,void * data)1953 inherit_recurse_cb(zfs_handle_t *zhp, void *data)
1954 {
1955 	inherit_cbdata_t *cb = data;
1956 	zfs_prop_t prop = zfs_name_to_prop(cb->cb_propname);
1957 
1958 	/*
1959 	 * If we're doing it recursively, then ignore properties that
1960 	 * are not valid for this type of dataset.
1961 	 */
1962 	if (prop != ZPROP_INVAL &&
1963 	    !zfs_prop_valid_for_type(prop, zfs_get_type(zhp)))
1964 		return (0);
1965 
1966 	return (zfs_prop_inherit(zhp, cb->cb_propname, cb->cb_received) != 0);
1967 }
1968 
1969 static int
inherit_cb(zfs_handle_t * zhp,void * data)1970 inherit_cb(zfs_handle_t *zhp, void *data)
1971 {
1972 	inherit_cbdata_t *cb = data;
1973 
1974 	return (zfs_prop_inherit(zhp, cb->cb_propname, cb->cb_received) != 0);
1975 }
1976 
1977 static int
zfs_do_inherit(int argc,char ** argv)1978 zfs_do_inherit(int argc, char **argv)
1979 {
1980 	int c;
1981 	zfs_prop_t prop;
1982 	inherit_cbdata_t cb = { 0 };
1983 	char *propname;
1984 	int ret = 0;
1985 	int flags = 0;
1986 	boolean_t received = B_FALSE;
1987 
1988 	/* check options */
1989 	while ((c = getopt(argc, argv, "rS")) != -1) {
1990 		switch (c) {
1991 		case 'r':
1992 			flags |= ZFS_ITER_RECURSE;
1993 			break;
1994 		case 'S':
1995 			received = B_TRUE;
1996 			break;
1997 		case '?':
1998 		default:
1999 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2000 			    optopt);
2001 			usage(B_FALSE);
2002 		}
2003 	}
2004 
2005 	argc -= optind;
2006 	argv += optind;
2007 
2008 	/* check number of arguments */
2009 	if (argc < 1) {
2010 		(void) fprintf(stderr, gettext("missing property argument\n"));
2011 		usage(B_FALSE);
2012 	}
2013 	if (argc < 2) {
2014 		(void) fprintf(stderr, gettext("missing dataset argument\n"));
2015 		usage(B_FALSE);
2016 	}
2017 
2018 	propname = argv[0];
2019 	argc--;
2020 	argv++;
2021 
2022 	if ((prop = zfs_name_to_prop(propname)) != ZPROP_INVAL) {
2023 		if (zfs_prop_readonly(prop)) {
2024 			(void) fprintf(stderr, gettext(
2025 			    "%s property is read-only\n"),
2026 			    propname);
2027 			return (1);
2028 		}
2029 		if (!zfs_prop_inheritable(prop) && !received) {
2030 			(void) fprintf(stderr, gettext("'%s' property cannot "
2031 			    "be inherited\n"), propname);
2032 			if (prop == ZFS_PROP_QUOTA ||
2033 			    prop == ZFS_PROP_RESERVATION ||
2034 			    prop == ZFS_PROP_REFQUOTA ||
2035 			    prop == ZFS_PROP_REFRESERVATION) {
2036 				(void) fprintf(stderr, gettext("use 'zfs set "
2037 				    "%s=none' to clear\n"), propname);
2038 				(void) fprintf(stderr, gettext("use 'zfs "
2039 				    "inherit -S %s' to revert to received "
2040 				    "value\n"), propname);
2041 			}
2042 			return (1);
2043 		}
2044 		if (received && (prop == ZFS_PROP_VOLSIZE ||
2045 		    prop == ZFS_PROP_VERSION)) {
2046 			(void) fprintf(stderr, gettext("'%s' property cannot "
2047 			    "be reverted to a received value\n"), propname);
2048 			return (1);
2049 		}
2050 	} else if (!zfs_prop_user(propname)) {
2051 		(void) fprintf(stderr, gettext("invalid property '%s'\n"),
2052 		    propname);
2053 		usage(B_FALSE);
2054 	}
2055 
2056 	cb.cb_propname = propname;
2057 	cb.cb_received = received;
2058 
2059 	if (flags & ZFS_ITER_RECURSE) {
2060 		ret = zfs_for_each(argc, argv, flags, ZFS_TYPE_DATASET,
2061 		    NULL, NULL, 0, inherit_recurse_cb, &cb);
2062 	} else {
2063 		ret = zfs_for_each(argc, argv, flags, ZFS_TYPE_DATASET,
2064 		    NULL, NULL, 0, inherit_cb, &cb);
2065 	}
2066 
2067 	return (ret);
2068 }
2069 
2070 typedef struct upgrade_cbdata {
2071 	uint64_t cb_numupgraded;
2072 	uint64_t cb_numsamegraded;
2073 	uint64_t cb_numfailed;
2074 	uint64_t cb_version;
2075 	boolean_t cb_newer;
2076 	boolean_t cb_foundone;
2077 	char cb_lastfs[ZFS_MAX_DATASET_NAME_LEN];
2078 } upgrade_cbdata_t;
2079 
2080 static int
same_pool(zfs_handle_t * zhp,const char * name)2081 same_pool(zfs_handle_t *zhp, const char *name)
2082 {
2083 	int len1 = strcspn(name, "/@");
2084 	const char *zhname = zfs_get_name(zhp);
2085 	int len2 = strcspn(zhname, "/@");
2086 
2087 	if (len1 != len2)
2088 		return (B_FALSE);
2089 	return (strncmp(name, zhname, len1) == 0);
2090 }
2091 
2092 static int
upgrade_list_callback(zfs_handle_t * zhp,void * data)2093 upgrade_list_callback(zfs_handle_t *zhp, void *data)
2094 {
2095 	upgrade_cbdata_t *cb = data;
2096 	int version = zfs_prop_get_int(zhp, ZFS_PROP_VERSION);
2097 
2098 	/* list if it's old/new */
2099 	if ((!cb->cb_newer && version < ZPL_VERSION) ||
2100 	    (cb->cb_newer && version > ZPL_VERSION)) {
2101 		char *str;
2102 		if (cb->cb_newer) {
2103 			str = gettext("The following filesystems are "
2104 			    "formatted using a newer software version and\n"
2105 			    "cannot be accessed on the current system.\n\n");
2106 		} else {
2107 			str = gettext("The following filesystems are "
2108 			    "out of date, and can be upgraded.  After being\n"
2109 			    "upgraded, these filesystems (and any 'zfs send' "
2110 			    "streams generated from\n"
2111 			    "subsequent snapshots) will no longer be "
2112 			    "accessible by older software versions.\n\n");
2113 		}
2114 
2115 		if (!cb->cb_foundone) {
2116 			(void) puts(str);
2117 			(void) printf(gettext("VER  FILESYSTEM\n"));
2118 			(void) printf(gettext("---  ------------\n"));
2119 			cb->cb_foundone = B_TRUE;
2120 		}
2121 
2122 		(void) printf("%2u   %s\n", version, zfs_get_name(zhp));
2123 	}
2124 
2125 	return (0);
2126 }
2127 
2128 static int
upgrade_set_callback(zfs_handle_t * zhp,void * data)2129 upgrade_set_callback(zfs_handle_t *zhp, void *data)
2130 {
2131 	upgrade_cbdata_t *cb = data;
2132 	int version = zfs_prop_get_int(zhp, ZFS_PROP_VERSION);
2133 	int needed_spa_version;
2134 	int spa_version;
2135 
2136 	if (zfs_spa_version(zhp, &spa_version) < 0)
2137 		return (-1);
2138 
2139 	needed_spa_version = zfs_spa_version_map(cb->cb_version);
2140 
2141 	if (needed_spa_version < 0)
2142 		return (-1);
2143 
2144 	if (spa_version < needed_spa_version) {
2145 		/* can't upgrade */
2146 		(void) printf(gettext("%s: can not be "
2147 		    "upgraded; the pool version needs to first "
2148 		    "be upgraded\nto version %d\n\n"),
2149 		    zfs_get_name(zhp), needed_spa_version);
2150 		cb->cb_numfailed++;
2151 		return (0);
2152 	}
2153 
2154 	/* upgrade */
2155 	if (version < cb->cb_version) {
2156 		char verstr[16];
2157 		(void) snprintf(verstr, sizeof (verstr),
2158 		    "%llu", cb->cb_version);
2159 		if (cb->cb_lastfs[0] && !same_pool(zhp, cb->cb_lastfs)) {
2160 			/*
2161 			 * If they did "zfs upgrade -a", then we could
2162 			 * be doing ioctls to different pools.  We need
2163 			 * to log this history once to each pool, and bypass
2164 			 * the normal history logging that happens in main().
2165 			 */
2166 			(void) zpool_log_history(g_zfs, history_str);
2167 			log_history = B_FALSE;
2168 		}
2169 		if (zfs_prop_set(zhp, "version", verstr) == 0)
2170 			cb->cb_numupgraded++;
2171 		else
2172 			cb->cb_numfailed++;
2173 		(void) strcpy(cb->cb_lastfs, zfs_get_name(zhp));
2174 	} else if (version > cb->cb_version) {
2175 		/* can't downgrade */
2176 		(void) printf(gettext("%s: can not be downgraded; "
2177 		    "it is already at version %u\n"),
2178 		    zfs_get_name(zhp), version);
2179 		cb->cb_numfailed++;
2180 	} else {
2181 		cb->cb_numsamegraded++;
2182 	}
2183 	return (0);
2184 }
2185 
2186 /*
2187  * zfs upgrade
2188  * zfs upgrade -v
2189  * zfs upgrade [-r] [-V <version>] <-a | filesystem>
2190  */
2191 static int
zfs_do_upgrade(int argc,char ** argv)2192 zfs_do_upgrade(int argc, char **argv)
2193 {
2194 	boolean_t all = B_FALSE;
2195 	boolean_t showversions = B_FALSE;
2196 	int ret = 0;
2197 	upgrade_cbdata_t cb = { 0 };
2198 	char c;
2199 	int flags = ZFS_ITER_ARGS_CAN_BE_PATHS;
2200 
2201 	/* check options */
2202 	while ((c = getopt(argc, argv, "rvV:a")) != -1) {
2203 		switch (c) {
2204 		case 'r':
2205 			flags |= ZFS_ITER_RECURSE;
2206 			break;
2207 		case 'v':
2208 			showversions = B_TRUE;
2209 			break;
2210 		case 'V':
2211 			if (zfs_prop_string_to_index(ZFS_PROP_VERSION,
2212 			    optarg, &cb.cb_version) != 0) {
2213 				(void) fprintf(stderr,
2214 				    gettext("invalid version %s\n"), optarg);
2215 				usage(B_FALSE);
2216 			}
2217 			break;
2218 		case 'a':
2219 			all = B_TRUE;
2220 			break;
2221 		case '?':
2222 		default:
2223 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2224 			    optopt);
2225 			usage(B_FALSE);
2226 		}
2227 	}
2228 
2229 	argc -= optind;
2230 	argv += optind;
2231 
2232 	if ((!all && !argc) && ((flags & ZFS_ITER_RECURSE) | cb.cb_version))
2233 		usage(B_FALSE);
2234 	if (showversions && (flags & ZFS_ITER_RECURSE || all ||
2235 	    cb.cb_version || argc))
2236 		usage(B_FALSE);
2237 	if ((all || argc) && (showversions))
2238 		usage(B_FALSE);
2239 	if (all && argc)
2240 		usage(B_FALSE);
2241 
2242 	if (showversions) {
2243 		/* Show info on available versions. */
2244 		(void) printf(gettext("The following filesystem versions are "
2245 		    "supported:\n\n"));
2246 		(void) printf(gettext("VER  DESCRIPTION\n"));
2247 		(void) printf("---  -----------------------------------------"
2248 		    "---------------\n");
2249 		(void) printf(gettext(" 1   Initial ZFS filesystem version\n"));
2250 		(void) printf(gettext(" 2   Enhanced directory entries\n"));
2251 		(void) printf(gettext(" 3   Case insensitive and filesystem "
2252 		    "user identifier (FUID)\n"));
2253 		(void) printf(gettext(" 4   userquota, groupquota "
2254 		    "properties\n"));
2255 		(void) printf(gettext(" 5   System attributes\n"));
2256 		(void) printf(gettext("\nFor more information on a particular "
2257 		    "version, including supported releases,\n"));
2258 		(void) printf("see the ZFS Administration Guide.\n\n");
2259 		ret = 0;
2260 	} else if (argc || all) {
2261 		/* Upgrade filesystems */
2262 		if (cb.cb_version == 0)
2263 			cb.cb_version = ZPL_VERSION;
2264 		ret = zfs_for_each(argc, argv, flags, ZFS_TYPE_FILESYSTEM,
2265 		    NULL, NULL, 0, upgrade_set_callback, &cb);
2266 		(void) printf(gettext("%llu filesystems upgraded\n"),
2267 		    cb.cb_numupgraded);
2268 		if (cb.cb_numsamegraded) {
2269 			(void) printf(gettext("%llu filesystems already at "
2270 			    "this version\n"),
2271 			    cb.cb_numsamegraded);
2272 		}
2273 		if (cb.cb_numfailed != 0)
2274 			ret = 1;
2275 	} else {
2276 		/* List old-version filesystems */
2277 		boolean_t found;
2278 		(void) printf(gettext("This system is currently running "
2279 		    "ZFS filesystem version %llu.\n\n"), ZPL_VERSION);
2280 
2281 		flags |= ZFS_ITER_RECURSE;
2282 		ret = zfs_for_each(0, NULL, flags, ZFS_TYPE_FILESYSTEM,
2283 		    NULL, NULL, 0, upgrade_list_callback, &cb);
2284 
2285 		found = cb.cb_foundone;
2286 		cb.cb_foundone = B_FALSE;
2287 		cb.cb_newer = B_TRUE;
2288 
2289 		ret = zfs_for_each(0, NULL, flags, ZFS_TYPE_FILESYSTEM,
2290 		    NULL, NULL, 0, upgrade_list_callback, &cb);
2291 
2292 		if (!cb.cb_foundone && !found) {
2293 			(void) printf(gettext("All filesystems are "
2294 			    "formatted with the current version.\n"));
2295 		}
2296 	}
2297 
2298 	return (ret);
2299 }
2300 
2301 /*
2302  * zfs userspace [-Hinp] [-o field[,...]] [-s field [-s field]...]
2303  *               [-S field [-S field]...] [-t type[,...]] filesystem | snapshot
2304  * zfs groupspace [-Hinp] [-o field[,...]] [-s field [-s field]...]
2305  *                [-S field [-S field]...] [-t type[,...]] filesystem | snapshot
2306  * zfs projectspace [-Hp] [-o field[,...]] [-s field [-s field]...]
2307  *                [-S field [-S field]...] filesystem | snapshot
2308  *
2309  *	-H      Scripted mode; elide headers and separate columns by tabs.
2310  *	-i	Translate SID to POSIX ID.
2311  *	-n	Print numeric ID instead of user/group name.
2312  *	-o      Control which fields to display.
2313  *	-p	Use exact (parsable) numeric output.
2314  *	-s      Specify sort columns, descending order.
2315  *	-S      Specify sort columns, ascending order.
2316  *	-t      Control which object types to display.
2317  *
2318  *	Displays space consumed by, and quotas on, each user in the specified
2319  *	filesystem or snapshot.
2320  */
2321 
2322 /* us_field_types, us_field_hdr and us_field_names should be kept in sync */
2323 enum us_field_types {
2324 	USFIELD_TYPE,
2325 	USFIELD_NAME,
2326 	USFIELD_USED,
2327 	USFIELD_QUOTA,
2328 	USFIELD_OBJUSED,
2329 	USFIELD_OBJQUOTA
2330 };
2331 static char *us_field_hdr[] = { "TYPE", "NAME", "USED", "QUOTA",
2332 				    "OBJUSED", "OBJQUOTA" };
2333 static char *us_field_names[] = { "type", "name", "used", "quota",
2334 				    "objused", "objquota" };
2335 #define	USFIELD_LAST	(sizeof (us_field_names) / sizeof (char *))
2336 
2337 #define	USTYPE_PSX_GRP	(1 << 0)
2338 #define	USTYPE_PSX_USR	(1 << 1)
2339 #define	USTYPE_SMB_GRP	(1 << 2)
2340 #define	USTYPE_SMB_USR	(1 << 3)
2341 #define	USTYPE_PROJ	(1 << 4)
2342 #define	USTYPE_ALL	\
2343 	(USTYPE_PSX_GRP | USTYPE_PSX_USR | USTYPE_SMB_GRP | USTYPE_SMB_USR | \
2344 	    USTYPE_PROJ)
2345 
2346 static int us_type_bits[] = {
2347 	USTYPE_PSX_GRP,
2348 	USTYPE_PSX_USR,
2349 	USTYPE_SMB_GRP,
2350 	USTYPE_SMB_USR,
2351 	USTYPE_ALL
2352 };
2353 static char *us_type_names[] = { "posixgroup", "posixuser", "smbgroup",
2354 	"smbuser", "all" };
2355 
2356 typedef struct us_node {
2357 	nvlist_t	*usn_nvl;
2358 	uu_avl_node_t	usn_avlnode;
2359 	uu_list_node_t	usn_listnode;
2360 } us_node_t;
2361 
2362 typedef struct us_cbdata {
2363 	nvlist_t	**cb_nvlp;
2364 	uu_avl_pool_t	*cb_avl_pool;
2365 	uu_avl_t	*cb_avl;
2366 	boolean_t	cb_numname;
2367 	boolean_t	cb_nicenum;
2368 	boolean_t	cb_sid2posix;
2369 	zfs_userquota_prop_t cb_prop;
2370 	zfs_sort_column_t *cb_sortcol;
2371 	size_t		cb_width[USFIELD_LAST];
2372 } us_cbdata_t;
2373 
2374 static boolean_t us_populated = B_FALSE;
2375 
2376 typedef struct {
2377 	zfs_sort_column_t *si_sortcol;
2378 	boolean_t	si_numname;
2379 } us_sort_info_t;
2380 
2381 static int
us_field_index(char * field)2382 us_field_index(char *field)
2383 {
2384 	int i;
2385 
2386 	for (i = 0; i < USFIELD_LAST; i++) {
2387 		if (strcmp(field, us_field_names[i]) == 0)
2388 			return (i);
2389 	}
2390 
2391 	return (-1);
2392 }
2393 
2394 static int
us_compare(const void * larg,const void * rarg,void * unused)2395 us_compare(const void *larg, const void *rarg, void *unused)
2396 {
2397 	const us_node_t *l = larg;
2398 	const us_node_t *r = rarg;
2399 	us_sort_info_t *si = (us_sort_info_t *)unused;
2400 	zfs_sort_column_t *sortcol = si->si_sortcol;
2401 	boolean_t numname = si->si_numname;
2402 	nvlist_t *lnvl = l->usn_nvl;
2403 	nvlist_t *rnvl = r->usn_nvl;
2404 	int rc = 0;
2405 	boolean_t lvb, rvb;
2406 
2407 	for (; sortcol != NULL; sortcol = sortcol->sc_next) {
2408 		char *lvstr = "";
2409 		char *rvstr = "";
2410 		uint32_t lv32 = 0;
2411 		uint32_t rv32 = 0;
2412 		uint64_t lv64 = 0;
2413 		uint64_t rv64 = 0;
2414 		zfs_prop_t prop = sortcol->sc_prop;
2415 		const char *propname = NULL;
2416 		boolean_t reverse = sortcol->sc_reverse;
2417 
2418 		switch (prop) {
2419 		case ZFS_PROP_TYPE:
2420 			propname = "type";
2421 			(void) nvlist_lookup_uint32(lnvl, propname, &lv32);
2422 			(void) nvlist_lookup_uint32(rnvl, propname, &rv32);
2423 			if (rv32 != lv32)
2424 				rc = (rv32 < lv32) ? 1 : -1;
2425 			break;
2426 		case ZFS_PROP_NAME:
2427 			propname = "name";
2428 			if (numname) {
2429 				(void) nvlist_lookup_uint64(lnvl, propname,
2430 				    &lv64);
2431 				(void) nvlist_lookup_uint64(rnvl, propname,
2432 				    &rv64);
2433 				if (rv64 != lv64)
2434 					rc = (rv64 < lv64) ? 1 : -1;
2435 			} else {
2436 				(void) nvlist_lookup_string(lnvl, propname,
2437 				    &lvstr);
2438 				(void) nvlist_lookup_string(rnvl, propname,
2439 				    &rvstr);
2440 				rc = strcmp(lvstr, rvstr);
2441 			}
2442 			break;
2443 		case ZFS_PROP_USED:
2444 		case ZFS_PROP_QUOTA:
2445 			if (!us_populated)
2446 				break;
2447 			if (prop == ZFS_PROP_USED)
2448 				propname = "used";
2449 			else
2450 				propname = "quota";
2451 			(void) nvlist_lookup_uint64(lnvl, propname, &lv64);
2452 			(void) nvlist_lookup_uint64(rnvl, propname, &rv64);
2453 			if (rv64 != lv64)
2454 				rc = (rv64 < lv64) ? 1 : -1;
2455 			break;
2456 
2457 		default:
2458 			break;
2459 		}
2460 
2461 		if (rc != 0) {
2462 			if (rc < 0)
2463 				return (reverse ? 1 : -1);
2464 			else
2465 				return (reverse ? -1 : 1);
2466 		}
2467 	}
2468 
2469 	/*
2470 	 * If entries still seem to be the same, check if they are of the same
2471 	 * type (smbentity is added only if we are doing SID to POSIX ID
2472 	 * translation where we can have duplicate type/name combinations).
2473 	 */
2474 	if (nvlist_lookup_boolean_value(lnvl, "smbentity", &lvb) == 0 &&
2475 	    nvlist_lookup_boolean_value(rnvl, "smbentity", &rvb) == 0 &&
2476 	    lvb != rvb)
2477 		return (lvb < rvb ? -1 : 1);
2478 
2479 	return (0);
2480 }
2481 
2482 static boolean_t
zfs_prop_is_user(unsigned p)2483 zfs_prop_is_user(unsigned p)
2484 {
2485 	return (p == ZFS_PROP_USERUSED || p == ZFS_PROP_USERQUOTA ||
2486 	    p == ZFS_PROP_USEROBJUSED || p == ZFS_PROP_USEROBJQUOTA);
2487 }
2488 
2489 static boolean_t
zfs_prop_is_group(unsigned p)2490 zfs_prop_is_group(unsigned p)
2491 {
2492 	return (p == ZFS_PROP_GROUPUSED || p == ZFS_PROP_GROUPQUOTA ||
2493 	    p == ZFS_PROP_GROUPOBJUSED || p == ZFS_PROP_GROUPOBJQUOTA);
2494 }
2495 
2496 static boolean_t
zfs_prop_is_project(unsigned p)2497 zfs_prop_is_project(unsigned p)
2498 {
2499 	return (p == ZFS_PROP_PROJECTUSED || p == ZFS_PROP_PROJECTQUOTA ||
2500 	    p == ZFS_PROP_PROJECTOBJUSED || p == ZFS_PROP_PROJECTOBJQUOTA);
2501 }
2502 
2503 static inline const char *
us_type2str(unsigned field_type)2504 us_type2str(unsigned field_type)
2505 {
2506 	switch (field_type) {
2507 	case USTYPE_PSX_USR:
2508 		return ("POSIX User");
2509 	case USTYPE_PSX_GRP:
2510 		return ("POSIX Group");
2511 	case USTYPE_SMB_USR:
2512 		return ("SMB User");
2513 	case USTYPE_SMB_GRP:
2514 		return ("SMB Group");
2515 	case USTYPE_PROJ:
2516 		return ("Project");
2517 	default:
2518 		return ("Undefined");
2519 	}
2520 }
2521 
2522 static int
userspace_cb(void * arg,const char * domain,uid_t rid,uint64_t space)2523 userspace_cb(void *arg, const char *domain, uid_t rid, uint64_t space)
2524 {
2525 	us_cbdata_t *cb = (us_cbdata_t *)arg;
2526 	zfs_userquota_prop_t prop = cb->cb_prop;
2527 	char *name = NULL;
2528 	char *propname;
2529 	char sizebuf[32];
2530 	us_node_t *node;
2531 	uu_avl_pool_t *avl_pool = cb->cb_avl_pool;
2532 	uu_avl_t *avl = cb->cb_avl;
2533 	uu_avl_index_t idx;
2534 	nvlist_t *props;
2535 	us_node_t *n;
2536 	zfs_sort_column_t *sortcol = cb->cb_sortcol;
2537 	unsigned type = 0;
2538 	const char *typestr;
2539 	size_t namelen;
2540 	size_t typelen;
2541 	size_t sizelen;
2542 	int typeidx, nameidx, sizeidx;
2543 	us_sort_info_t sortinfo = { sortcol, cb->cb_numname };
2544 	boolean_t smbentity = B_FALSE;
2545 
2546 	if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0)
2547 		nomem();
2548 	node = safe_malloc(sizeof (us_node_t));
2549 	uu_avl_node_init(node, &node->usn_avlnode, avl_pool);
2550 	node->usn_nvl = props;
2551 
2552 	if (domain != NULL && domain[0] != '\0') {
2553 		/* SMB */
2554 		char sid[MAXNAMELEN + 32];
2555 		uid_t id;
2556 		int err;
2557 		int flag = IDMAP_REQ_FLG_USE_CACHE;
2558 
2559 		smbentity = B_TRUE;
2560 
2561 		(void) snprintf(sid, sizeof (sid), "%s-%u", domain, rid);
2562 
2563 		if (prop == ZFS_PROP_GROUPUSED || prop == ZFS_PROP_GROUPQUOTA) {
2564 			type = USTYPE_SMB_GRP;
2565 			err = sid_to_id(sid, B_FALSE, &id);
2566 		} else {
2567 			type = USTYPE_SMB_USR;
2568 			err = sid_to_id(sid, B_TRUE, &id);
2569 		}
2570 
2571 		if (err == 0) {
2572 			rid = id;
2573 			if (!cb->cb_sid2posix) {
2574 				if (type == USTYPE_SMB_USR) {
2575 					(void) idmap_getwinnamebyuid(rid, flag,
2576 					    &name, NULL);
2577 				} else {
2578 					(void) idmap_getwinnamebygid(rid, flag,
2579 					    &name, NULL);
2580 				}
2581 				if (name == NULL)
2582 					name = sid;
2583 			}
2584 		}
2585 	}
2586 
2587 	if (cb->cb_sid2posix || domain == NULL || domain[0] == '\0') {
2588 		/* POSIX or -i */
2589 		if (zfs_prop_is_group(prop)) {
2590 			type = USTYPE_PSX_GRP;
2591 			if (!cb->cb_numname) {
2592 				struct group *g;
2593 
2594 				if ((g = getgrgid(rid)) != NULL)
2595 					name = g->gr_name;
2596 			}
2597 		} else if (zfs_prop_is_user(prop)) {
2598 			type = USTYPE_PSX_USR;
2599 			if (!cb->cb_numname) {
2600 				struct passwd *p;
2601 
2602 				if ((p = getpwuid(rid)) != NULL)
2603 					name = p->pw_name;
2604 			}
2605 		} else {
2606 			type = USTYPE_PROJ;
2607 		}
2608 	}
2609 
2610 	/*
2611 	 * Make sure that the type/name combination is unique when doing
2612 	 * SID to POSIX ID translation (hence changing the type from SMB to
2613 	 * POSIX).
2614 	 */
2615 	if (cb->cb_sid2posix &&
2616 	    nvlist_add_boolean_value(props, "smbentity", smbentity) != 0)
2617 		nomem();
2618 
2619 	/* Calculate/update width of TYPE field */
2620 	typestr = us_type2str(type);
2621 	typelen = strlen(gettext(typestr));
2622 	typeidx = us_field_index("type");
2623 	if (typelen > cb->cb_width[typeidx])
2624 		cb->cb_width[typeidx] = typelen;
2625 	if (nvlist_add_uint32(props, "type", type) != 0)
2626 		nomem();
2627 
2628 	/* Calculate/update width of NAME field */
2629 	if ((cb->cb_numname && cb->cb_sid2posix) || name == NULL) {
2630 		if (nvlist_add_uint64(props, "name", rid) != 0)
2631 			nomem();
2632 		namelen = snprintf(NULL, 0, "%u", rid);
2633 	} else {
2634 		if (nvlist_add_string(props, "name", name) != 0)
2635 			nomem();
2636 		namelen = strlen(name);
2637 	}
2638 	nameidx = us_field_index("name");
2639 	if (namelen > cb->cb_width[nameidx])
2640 		cb->cb_width[nameidx] = namelen;
2641 
2642 	/*
2643 	 * Check if this type/name combination is in the list and update it;
2644 	 * otherwise add new node to the list.
2645 	 */
2646 	if ((n = uu_avl_find(avl, node, &sortinfo, &idx)) == NULL) {
2647 		uu_avl_insert(avl, node, idx);
2648 	} else {
2649 		nvlist_free(props);
2650 		free(node);
2651 		node = n;
2652 		props = node->usn_nvl;
2653 	}
2654 
2655 	/* Calculate/update width of USED/QUOTA fields */
2656 	if (cb->cb_nicenum) {
2657 		if (prop == ZFS_PROP_USERUSED || prop == ZFS_PROP_GROUPUSED ||
2658 		    prop == ZFS_PROP_USERQUOTA || prop == ZFS_PROP_GROUPQUOTA ||
2659 		    prop == ZFS_PROP_PROJECTUSED ||
2660 		    prop == ZFS_PROP_PROJECTQUOTA) {
2661 			zfs_nicenum(space, sizebuf, sizeof (sizebuf));
2662 		} else {
2663 			zfs_nicenum(space, sizebuf, sizeof (sizebuf));
2664 		}
2665 	} else {
2666 		(void) snprintf(sizebuf, sizeof (sizebuf), "%llu", space);
2667 	}
2668 	sizelen = strlen(sizebuf);
2669 	if (prop == ZFS_PROP_USERUSED || prop == ZFS_PROP_GROUPUSED ||
2670 	    prop == ZFS_PROP_PROJECTUSED) {
2671 		propname = "used";
2672 		if (!nvlist_exists(props, "quota"))
2673 			(void) nvlist_add_uint64(props, "quota", 0);
2674 	} else if (prop == ZFS_PROP_USERQUOTA || prop == ZFS_PROP_GROUPQUOTA ||
2675 	    prop == ZFS_PROP_PROJECTQUOTA) {
2676 		propname = "quota";
2677 		if (!nvlist_exists(props, "used"))
2678 			(void) nvlist_add_uint64(props, "used", 0);
2679 	} else if (prop == ZFS_PROP_USEROBJUSED ||
2680 	    prop == ZFS_PROP_GROUPOBJUSED || prop == ZFS_PROP_PROJECTOBJUSED) {
2681 		propname = "objused";
2682 		if (!nvlist_exists(props, "objquota"))
2683 			(void) nvlist_add_uint64(props, "objquota", 0);
2684 	} else if (prop == ZFS_PROP_USEROBJQUOTA ||
2685 	    prop == ZFS_PROP_GROUPOBJQUOTA ||
2686 	    prop == ZFS_PROP_PROJECTOBJQUOTA) {
2687 		propname = "objquota";
2688 		if (!nvlist_exists(props, "objused"))
2689 			(void) nvlist_add_uint64(props, "objused", 0);
2690 	} else {
2691 		return (-1);
2692 	}
2693 	sizeidx = us_field_index(propname);
2694 	if (sizelen > cb->cb_width[sizeidx])
2695 		cb->cb_width[sizeidx] = sizelen;
2696 
2697 	if (nvlist_add_uint64(props, propname, space) != 0)
2698 		nomem();
2699 
2700 	return (0);
2701 }
2702 
2703 static void
print_us_node(boolean_t scripted,boolean_t parsable,int * fields,int types,size_t * width,us_node_t * node)2704 print_us_node(boolean_t scripted, boolean_t parsable, int *fields, int types,
2705     size_t *width, us_node_t *node)
2706 {
2707 	nvlist_t *nvl = node->usn_nvl;
2708 	char valstr[MAXNAMELEN];
2709 	boolean_t first = B_TRUE;
2710 	int cfield = 0;
2711 	int field;
2712 	uint32_t ustype;
2713 
2714 	/* Check type */
2715 	(void) nvlist_lookup_uint32(nvl, "type", &ustype);
2716 	if (!(ustype & types))
2717 		return;
2718 
2719 	while ((field = fields[cfield]) != USFIELD_LAST) {
2720 		nvpair_t *nvp = NULL;
2721 		data_type_t type;
2722 		uint32_t val32;
2723 		uint64_t val64;
2724 		char *strval = "-";
2725 
2726 		while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
2727 			if (strcmp(nvpair_name(nvp),
2728 			    us_field_names[field]) == 0)
2729 				break;
2730 		}
2731 
2732 		type = nvp == NULL ? DATA_TYPE_UNKNOWN : nvpair_type(nvp);
2733 		switch (type) {
2734 		case DATA_TYPE_UINT32:
2735 			(void) nvpair_value_uint32(nvp, &val32);
2736 			break;
2737 		case DATA_TYPE_UINT64:
2738 			(void) nvpair_value_uint64(nvp, &val64);
2739 			break;
2740 		case DATA_TYPE_STRING:
2741 			(void) nvpair_value_string(nvp, &strval);
2742 			break;
2743 		case DATA_TYPE_UNKNOWN:
2744 			break;
2745 		default:
2746 			(void) fprintf(stderr, "invalid data type\n");
2747 		}
2748 
2749 		switch (field) {
2750 		case USFIELD_TYPE:
2751 			if (type == DATA_TYPE_UINT32)
2752 				strval = (char *)us_type2str(val32);
2753 			break;
2754 		case USFIELD_NAME:
2755 			if (type == DATA_TYPE_UINT64) {
2756 				(void) sprintf(valstr, "%llu", val64);
2757 				strval = valstr;
2758 			}
2759 			break;
2760 		case USFIELD_USED:
2761 		case USFIELD_QUOTA:
2762 		case USFIELD_OBJUSED:
2763 		case USFIELD_OBJQUOTA:
2764 			if (type == DATA_TYPE_UINT64) {
2765 				if (parsable) {
2766 					(void) sprintf(valstr, "%llu", val64);
2767 				} else {
2768 					zfs_nicenum(val64, valstr,
2769 					    sizeof (valstr));
2770 				}
2771 				if ((field == USFIELD_QUOTA ||
2772 				    field == USFIELD_OBJQUOTA) &&
2773 				    strcmp(valstr, "0") == 0)
2774 					strval = "none";
2775 				else
2776 					strval = valstr;
2777 			}
2778 			break;
2779 		}
2780 
2781 		if (!first) {
2782 			if (scripted)
2783 				(void) printf("\t");
2784 			else
2785 				(void) printf("  ");
2786 		}
2787 		if (scripted)
2788 			(void) printf("%s", strval);
2789 		else if (field == USFIELD_TYPE || field == USFIELD_NAME)
2790 			(void) printf("%-*s", width[field], strval);
2791 		else
2792 			(void) printf("%*s", width[field], strval);
2793 
2794 		first = B_FALSE;
2795 		cfield++;
2796 	}
2797 
2798 	(void) printf("\n");
2799 }
2800 
2801 static void
print_us(boolean_t scripted,boolean_t parsable,int * fields,int types,size_t * width,boolean_t rmnode,uu_avl_t * avl)2802 print_us(boolean_t scripted, boolean_t parsable, int *fields, int types,
2803     size_t *width, boolean_t rmnode, uu_avl_t *avl)
2804 {
2805 	us_node_t *node;
2806 	const char *col;
2807 	int cfield = 0;
2808 	int field;
2809 
2810 	if (!scripted) {
2811 		boolean_t first = B_TRUE;
2812 
2813 		while ((field = fields[cfield]) != USFIELD_LAST) {
2814 			col = gettext(us_field_hdr[field]);
2815 			if (field == USFIELD_TYPE || field == USFIELD_NAME) {
2816 				(void) printf(first ? "%-*s" : "  %-*s",
2817 				    width[field], col);
2818 			} else {
2819 				(void) printf(first ? "%*s" : "  %*s",
2820 				    width[field], col);
2821 			}
2822 			first = B_FALSE;
2823 			cfield++;
2824 		}
2825 		(void) printf("\n");
2826 	}
2827 
2828 	for (node = uu_avl_first(avl); node; node = uu_avl_next(avl, node)) {
2829 		print_us_node(scripted, parsable, fields, types, width, node);
2830 		if (rmnode)
2831 			nvlist_free(node->usn_nvl);
2832 	}
2833 }
2834 
2835 static int
zfs_do_userspace(int argc,char ** argv)2836 zfs_do_userspace(int argc, char **argv)
2837 {
2838 	zfs_handle_t *zhp;
2839 	zfs_userquota_prop_t p;
2840 	uu_avl_pool_t *avl_pool;
2841 	uu_avl_t *avl_tree;
2842 	uu_avl_walk_t *walk;
2843 	char *delim;
2844 	char deffields[] = "type,name,used,quota,objused,objquota";
2845 	char *ofield = NULL;
2846 	char *tfield = NULL;
2847 	int cfield = 0;
2848 	int fields[256];
2849 	int i;
2850 	boolean_t scripted = B_FALSE;
2851 	boolean_t prtnum = B_FALSE;
2852 	boolean_t parsable = B_FALSE;
2853 	boolean_t sid2posix = B_FALSE;
2854 	int ret = 0;
2855 	int c;
2856 	zfs_sort_column_t *sortcol = NULL;
2857 	int types = USTYPE_PSX_USR | USTYPE_SMB_USR;
2858 	us_cbdata_t cb;
2859 	us_node_t *node;
2860 	us_node_t *rmnode;
2861 	uu_list_pool_t *listpool;
2862 	uu_list_t *list;
2863 	uu_avl_index_t idx = 0;
2864 	uu_list_index_t idx2 = 0;
2865 
2866 	if (argc < 2)
2867 		usage(B_FALSE);
2868 
2869 	if (strcmp(argv[0], "groupspace") == 0) {
2870 		/* Toggle default group types */
2871 		types = USTYPE_PSX_GRP | USTYPE_SMB_GRP;
2872 	} else if (strcmp(argv[0], "projectspace") == 0) {
2873 		types = USTYPE_PROJ;
2874 		prtnum = B_TRUE;
2875 	}
2876 
2877 	while ((c = getopt(argc, argv, "nHpo:s:S:t:i")) != -1) {
2878 		switch (c) {
2879 		case 'n':
2880 			if (types == USTYPE_PROJ) {
2881 				(void) fprintf(stderr,
2882 				    gettext("invalid option 'n'\n"));
2883 				usage(B_FALSE);
2884 			}
2885 			prtnum = B_TRUE;
2886 			break;
2887 		case 'H':
2888 			scripted = B_TRUE;
2889 			break;
2890 		case 'p':
2891 			parsable = B_TRUE;
2892 			break;
2893 		case 'o':
2894 			ofield = optarg;
2895 			break;
2896 		case 's':
2897 		case 'S':
2898 			if (zfs_add_sort_column(&sortcol, optarg,
2899 			    c == 's' ? B_FALSE : B_TRUE) != 0) {
2900 				(void) fprintf(stderr,
2901 				    gettext("invalid field '%s'\n"), optarg);
2902 				usage(B_FALSE);
2903 			}
2904 			break;
2905 		case 't':
2906 			if (types == USTYPE_PROJ) {
2907 				(void) fprintf(stderr,
2908 				    gettext("invalid option 't'\n"));
2909 				usage(B_FALSE);
2910 			}
2911 			tfield = optarg;
2912 			break;
2913 		case 'i':
2914 			if (types == USTYPE_PROJ) {
2915 				(void) fprintf(stderr,
2916 				    gettext("invalid option 'i'\n"));
2917 				usage(B_FALSE);
2918 			}
2919 			sid2posix = B_TRUE;
2920 			break;
2921 		case ':':
2922 			(void) fprintf(stderr, gettext("missing argument for "
2923 			    "'%c' option\n"), optopt);
2924 			usage(B_FALSE);
2925 			break;
2926 		case '?':
2927 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2928 			    optopt);
2929 			usage(B_FALSE);
2930 		}
2931 	}
2932 
2933 	argc -= optind;
2934 	argv += optind;
2935 
2936 	if (argc < 1) {
2937 		(void) fprintf(stderr, gettext("missing dataset name\n"));
2938 		usage(B_FALSE);
2939 	}
2940 	if (argc > 1) {
2941 		(void) fprintf(stderr, gettext("too many arguments\n"));
2942 		usage(B_FALSE);
2943 	}
2944 
2945 	/* Use default output fields if not specified using -o */
2946 	if (ofield == NULL)
2947 		ofield = deffields;
2948 	do {
2949 		if ((delim = strchr(ofield, ',')) != NULL)
2950 			*delim = '\0';
2951 		if ((fields[cfield++] = us_field_index(ofield)) == -1) {
2952 			(void) fprintf(stderr, gettext("invalid type '%s' "
2953 			    "for -o option\n"), ofield);
2954 			return (-1);
2955 		}
2956 		if (delim != NULL)
2957 			ofield = delim + 1;
2958 	} while (delim != NULL);
2959 	fields[cfield] = USFIELD_LAST;
2960 
2961 	/* Override output types (-t option) */
2962 	if (tfield != NULL) {
2963 		types = 0;
2964 
2965 		do {
2966 			boolean_t found = B_FALSE;
2967 
2968 			if ((delim = strchr(tfield, ',')) != NULL)
2969 				*delim = '\0';
2970 			for (i = 0; i < sizeof (us_type_bits) / sizeof (int);
2971 			    i++) {
2972 				if (strcmp(tfield, us_type_names[i]) == 0) {
2973 					found = B_TRUE;
2974 					types |= us_type_bits[i];
2975 					break;
2976 				}
2977 			}
2978 			if (!found) {
2979 				(void) fprintf(stderr, gettext("invalid type "
2980 				    "'%s' for -t option\n"), tfield);
2981 				return (-1);
2982 			}
2983 			if (delim != NULL)
2984 				tfield = delim + 1;
2985 		} while (delim != NULL);
2986 	}
2987 
2988 	if ((zhp = zfs_open(g_zfs, argv[0], ZFS_TYPE_DATASET)) == NULL)
2989 		return (1);
2990 
2991 	if ((avl_pool = uu_avl_pool_create("us_avl_pool", sizeof (us_node_t),
2992 	    offsetof(us_node_t, usn_avlnode), us_compare, UU_DEFAULT)) == NULL)
2993 		nomem();
2994 	if ((avl_tree = uu_avl_create(avl_pool, NULL, UU_DEFAULT)) == NULL)
2995 		nomem();
2996 
2997 	/* Always add default sorting columns */
2998 	(void) zfs_add_sort_column(&sortcol, "type", B_FALSE);
2999 	(void) zfs_add_sort_column(&sortcol, "name", B_FALSE);
3000 
3001 	cb.cb_sortcol = sortcol;
3002 	cb.cb_numname = prtnum;
3003 	cb.cb_nicenum = !parsable;
3004 	cb.cb_avl_pool = avl_pool;
3005 	cb.cb_avl = avl_tree;
3006 	cb.cb_sid2posix = sid2posix;
3007 
3008 	for (i = 0; i < USFIELD_LAST; i++)
3009 		cb.cb_width[i] = strlen(gettext(us_field_hdr[i]));
3010 
3011 	for (p = 0; p < ZFS_NUM_USERQUOTA_PROPS; p++) {
3012 		if ((zfs_prop_is_user(p) &&
3013 		    !(types & (USTYPE_PSX_USR | USTYPE_SMB_USR))) ||
3014 		    (zfs_prop_is_group(p) &&
3015 		    !(types & (USTYPE_PSX_GRP | USTYPE_SMB_GRP))) ||
3016 		    (zfs_prop_is_project(p) && types != USTYPE_PROJ))
3017 			continue;
3018 
3019 		cb.cb_prop = p;
3020 		if ((ret = zfs_userspace(zhp, p, userspace_cb, &cb)) != 0)
3021 			return (ret);
3022 	}
3023 
3024 	/* Sort the list */
3025 	if ((node = uu_avl_first(avl_tree)) == NULL)
3026 		return (0);
3027 
3028 	us_populated = B_TRUE;
3029 
3030 	listpool = uu_list_pool_create("tmplist", sizeof (us_node_t),
3031 	    offsetof(us_node_t, usn_listnode), NULL, UU_DEFAULT);
3032 	list = uu_list_create(listpool, NULL, UU_DEFAULT);
3033 	uu_list_node_init(node, &node->usn_listnode, listpool);
3034 
3035 	while (node != NULL) {
3036 		rmnode = node;
3037 		node = uu_avl_next(avl_tree, node);
3038 		uu_avl_remove(avl_tree, rmnode);
3039 		if (uu_list_find(list, rmnode, NULL, &idx2) == NULL)
3040 			uu_list_insert(list, rmnode, idx2);
3041 	}
3042 
3043 	for (node = uu_list_first(list); node != NULL;
3044 	    node = uu_list_next(list, node)) {
3045 		us_sort_info_t sortinfo = { sortcol, cb.cb_numname };
3046 
3047 		if (uu_avl_find(avl_tree, node, &sortinfo, &idx) == NULL)
3048 			uu_avl_insert(avl_tree, node, idx);
3049 	}
3050 
3051 	uu_list_destroy(list);
3052 	uu_list_pool_destroy(listpool);
3053 
3054 	/* Print and free node nvlist memory */
3055 	print_us(scripted, parsable, fields, types, cb.cb_width, B_TRUE,
3056 	    cb.cb_avl);
3057 
3058 	zfs_free_sort_columns(sortcol);
3059 
3060 	/* Clean up the AVL tree */
3061 	if ((walk = uu_avl_walk_start(cb.cb_avl, UU_WALK_ROBUST)) == NULL)
3062 		nomem();
3063 
3064 	while ((node = uu_avl_walk_next(walk)) != NULL) {
3065 		uu_avl_remove(cb.cb_avl, node);
3066 		free(node);
3067 	}
3068 
3069 	uu_avl_walk_end(walk);
3070 	uu_avl_destroy(avl_tree);
3071 	uu_avl_pool_destroy(avl_pool);
3072 
3073 	return (ret);
3074 }
3075 
3076 /*
3077  * list [-Hp][-r|-d max] [-o property[,...]] [-s property] ... [-S property] ...
3078  *      [-t type[,...]] [filesystem|volume|snapshot] ...
3079  *
3080  *	-H	Scripted mode; elide headers and separate columns by tabs.
3081  *	-p	Display values in parsable (literal) format.
3082  *	-r	Recurse over all children.
3083  *	-d	Limit recursion by depth.
3084  *	-o	Control which fields to display.
3085  *	-s	Specify sort columns, descending order.
3086  *	-S	Specify sort columns, ascending order.
3087  *	-t	Control which object types to display.
3088  *
3089  * When given no arguments, list all filesystems in the system.
3090  * Otherwise, list the specified datasets, optionally recursing down them if
3091  * '-r' is specified.
3092  */
3093 typedef struct list_cbdata {
3094 	boolean_t	cb_first;
3095 	boolean_t	cb_literal;
3096 	boolean_t	cb_scripted;
3097 	zprop_list_t	*cb_proplist;
3098 } list_cbdata_t;
3099 
3100 /*
3101  * Given a list of columns to display, output appropriate headers for each one.
3102  */
3103 static void
print_header(list_cbdata_t * cb)3104 print_header(list_cbdata_t *cb)
3105 {
3106 	zprop_list_t *pl = cb->cb_proplist;
3107 	char headerbuf[ZFS_MAXPROPLEN];
3108 	const char *header;
3109 	int i;
3110 	boolean_t first = B_TRUE;
3111 	boolean_t right_justify;
3112 
3113 	for (; pl != NULL; pl = pl->pl_next) {
3114 		if (!first) {
3115 			(void) printf("  ");
3116 		} else {
3117 			first = B_FALSE;
3118 		}
3119 
3120 		right_justify = B_FALSE;
3121 		if (pl->pl_prop != ZPROP_INVAL) {
3122 			header = zfs_prop_column_name(pl->pl_prop);
3123 			right_justify = zfs_prop_align_right(pl->pl_prop);
3124 		} else {
3125 			for (i = 0; pl->pl_user_prop[i] != '\0'; i++)
3126 				headerbuf[i] = toupper(pl->pl_user_prop[i]);
3127 			headerbuf[i] = '\0';
3128 			header = headerbuf;
3129 		}
3130 
3131 		if (pl->pl_next == NULL && !right_justify)
3132 			(void) printf("%s", header);
3133 		else if (right_justify)
3134 			(void) printf("%*s", pl->pl_width, header);
3135 		else
3136 			(void) printf("%-*s", pl->pl_width, header);
3137 	}
3138 
3139 	(void) printf("\n");
3140 }
3141 
3142 /*
3143  * Given a dataset and a list of fields, print out all the properties according
3144  * to the described layout.
3145  */
3146 static void
print_dataset(zfs_handle_t * zhp,list_cbdata_t * cb)3147 print_dataset(zfs_handle_t *zhp, list_cbdata_t *cb)
3148 {
3149 	zprop_list_t *pl = cb->cb_proplist;
3150 	boolean_t first = B_TRUE;
3151 	char property[ZFS_MAXPROPLEN];
3152 	nvlist_t *userprops = zfs_get_user_props(zhp);
3153 	nvlist_t *propval;
3154 	char *propstr;
3155 	boolean_t right_justify;
3156 
3157 	for (; pl != NULL; pl = pl->pl_next) {
3158 		if (!first) {
3159 			if (cb->cb_scripted)
3160 				(void) printf("\t");
3161 			else
3162 				(void) printf("  ");
3163 		} else {
3164 			first = B_FALSE;
3165 		}
3166 
3167 		if (pl->pl_prop == ZFS_PROP_NAME) {
3168 			(void) strlcpy(property, zfs_get_name(zhp),
3169 			    sizeof (property));
3170 			propstr = property;
3171 			right_justify = zfs_prop_align_right(pl->pl_prop);
3172 		} else if (pl->pl_prop != ZPROP_INVAL) {
3173 			if (zfs_prop_get(zhp, pl->pl_prop, property,
3174 			    sizeof (property), NULL, NULL, 0,
3175 			    cb->cb_literal) != 0)
3176 				propstr = "-";
3177 			else
3178 				propstr = property;
3179 			right_justify = zfs_prop_align_right(pl->pl_prop);
3180 		} else if (zfs_prop_userquota(pl->pl_user_prop)) {
3181 			if (zfs_prop_get_userquota(zhp, pl->pl_user_prop,
3182 			    property, sizeof (property), cb->cb_literal) != 0)
3183 				propstr = "-";
3184 			else
3185 				propstr = property;
3186 			right_justify = B_TRUE;
3187 		} else if (zfs_prop_written(pl->pl_user_prop)) {
3188 			if (zfs_prop_get_written(zhp, pl->pl_user_prop,
3189 			    property, sizeof (property), cb->cb_literal) != 0)
3190 				propstr = "-";
3191 			else
3192 				propstr = property;
3193 			right_justify = B_TRUE;
3194 		} else {
3195 			if (nvlist_lookup_nvlist(userprops,
3196 			    pl->pl_user_prop, &propval) != 0)
3197 				propstr = "-";
3198 			else
3199 				verify(nvlist_lookup_string(propval,
3200 				    ZPROP_VALUE, &propstr) == 0);
3201 			right_justify = B_FALSE;
3202 		}
3203 
3204 		/*
3205 		 * If this is being called in scripted mode, or if this is the
3206 		 * last column and it is left-justified, don't include a width
3207 		 * format specifier.
3208 		 */
3209 		if (cb->cb_scripted || (pl->pl_next == NULL && !right_justify))
3210 			(void) printf("%s", propstr);
3211 		else if (right_justify)
3212 			(void) printf("%*s", pl->pl_width, propstr);
3213 		else
3214 			(void) printf("%-*s", pl->pl_width, propstr);
3215 	}
3216 
3217 	(void) printf("\n");
3218 }
3219 
3220 /*
3221  * Generic callback function to list a dataset or snapshot.
3222  */
3223 static int
list_callback(zfs_handle_t * zhp,void * data)3224 list_callback(zfs_handle_t *zhp, void *data)
3225 {
3226 	list_cbdata_t *cbp = data;
3227 
3228 	if (cbp->cb_first) {
3229 		if (!cbp->cb_scripted)
3230 			print_header(cbp);
3231 		cbp->cb_first = B_FALSE;
3232 	}
3233 
3234 	print_dataset(zhp, cbp);
3235 
3236 	return (0);
3237 }
3238 
3239 static int
zfs_do_list(int argc,char ** argv)3240 zfs_do_list(int argc, char **argv)
3241 {
3242 	int c;
3243 	static char default_fields[] =
3244 	    "name,used,available,referenced,mountpoint";
3245 	int types = ZFS_TYPE_DATASET;
3246 	boolean_t types_specified = B_FALSE;
3247 	char *fields = NULL;
3248 	list_cbdata_t cb = { 0 };
3249 	char *value;
3250 	int limit = 0;
3251 	int ret = 0;
3252 	zfs_sort_column_t *sortcol = NULL;
3253 	int flags = ZFS_ITER_PROP_LISTSNAPS | ZFS_ITER_ARGS_CAN_BE_PATHS;
3254 
3255 	/* check options */
3256 	while ((c = getopt(argc, argv, "HS:d:o:prs:t:")) != -1) {
3257 		switch (c) {
3258 		case 'o':
3259 			fields = optarg;
3260 			break;
3261 		case 'p':
3262 			cb.cb_literal = B_TRUE;
3263 			flags |= ZFS_ITER_LITERAL_PROPS;
3264 			break;
3265 		case 'd':
3266 			limit = parse_depth(optarg, &flags);
3267 			break;
3268 		case 'r':
3269 			flags |= ZFS_ITER_RECURSE;
3270 			break;
3271 		case 'H':
3272 			cb.cb_scripted = B_TRUE;
3273 			break;
3274 		case 's':
3275 			if (zfs_add_sort_column(&sortcol, optarg,
3276 			    B_FALSE) != 0) {
3277 				(void) fprintf(stderr,
3278 				    gettext("invalid property '%s'\n"), optarg);
3279 				usage(B_FALSE);
3280 			}
3281 			break;
3282 		case 'S':
3283 			if (zfs_add_sort_column(&sortcol, optarg,
3284 			    B_TRUE) != 0) {
3285 				(void) fprintf(stderr,
3286 				    gettext("invalid property '%s'\n"), optarg);
3287 				usage(B_FALSE);
3288 			}
3289 			break;
3290 		case 't':
3291 			types = 0;
3292 			types_specified = B_TRUE;
3293 			flags &= ~ZFS_ITER_PROP_LISTSNAPS;
3294 			while (*optarg != '\0') {
3295 				static char *type_subopts[] = { "filesystem",
3296 				    "volume", "snapshot", "snap", "bookmark",
3297 				    "all", NULL };
3298 
3299 				switch (getsubopt(&optarg, type_subopts,
3300 				    &value)) {
3301 				case 0:
3302 					types |= ZFS_TYPE_FILESYSTEM;
3303 					break;
3304 				case 1:
3305 					types |= ZFS_TYPE_VOLUME;
3306 					break;
3307 				case 2:
3308 				case 3:
3309 					types |= ZFS_TYPE_SNAPSHOT;
3310 					break;
3311 				case 4:
3312 					types |= ZFS_TYPE_BOOKMARK;
3313 					break;
3314 				case 5:
3315 					types = ZFS_TYPE_DATASET |
3316 					    ZFS_TYPE_BOOKMARK;
3317 					break;
3318 				default:
3319 					(void) fprintf(stderr,
3320 					    gettext("invalid type '%s'\n"),
3321 					    value);
3322 					usage(B_FALSE);
3323 				}
3324 			}
3325 			break;
3326 		case ':':
3327 			(void) fprintf(stderr, gettext("missing argument for "
3328 			    "'%c' option\n"), optopt);
3329 			usage(B_FALSE);
3330 			break;
3331 		case '?':
3332 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3333 			    optopt);
3334 			usage(B_FALSE);
3335 		}
3336 	}
3337 
3338 	argc -= optind;
3339 	argv += optind;
3340 
3341 	if (fields == NULL)
3342 		fields = default_fields;
3343 
3344 	/*
3345 	 * If we are only going to list snapshot names and sort by name,
3346 	 * then we can use faster version.
3347 	 */
3348 	if (strcmp(fields, "name") == 0 && zfs_sort_only_by_name(sortcol))
3349 		flags |= ZFS_ITER_SIMPLE;
3350 
3351 	/*
3352 	 * If "-o space" and no types were specified, don't display snapshots.
3353 	 */
3354 	if (strcmp(fields, "space") == 0 && types_specified == B_FALSE)
3355 		types &= ~ZFS_TYPE_SNAPSHOT;
3356 
3357 	/*
3358 	 * If the user specifies '-o all', the zprop_get_list() doesn't
3359 	 * normally include the name of the dataset.  For 'zfs list', we always
3360 	 * want this property to be first.
3361 	 */
3362 	if (zprop_get_list(g_zfs, fields, &cb.cb_proplist, ZFS_TYPE_DATASET)
3363 	    != 0)
3364 		usage(B_FALSE);
3365 
3366 	cb.cb_first = B_TRUE;
3367 
3368 	ret = zfs_for_each(argc, argv, flags, types, sortcol, &cb.cb_proplist,
3369 	    limit, list_callback, &cb);
3370 
3371 	zprop_free_list(cb.cb_proplist);
3372 	zfs_free_sort_columns(sortcol);
3373 
3374 	if (ret == 0 && cb.cb_first && !cb.cb_scripted)
3375 		(void) printf(gettext("no datasets available\n"));
3376 
3377 	return (ret);
3378 }
3379 
3380 /*
3381  * zfs rename [-f] <fs | snap | vol> <fs | snap | vol>
3382  * zfs rename [-f] -p <fs | vol> <fs | vol>
3383  * zfs rename -r <snap> <snap>
3384  *
3385  * Renames the given dataset to another of the same type.
3386  *
3387  * The '-p' flag creates all the non-existing ancestors of the target first.
3388  */
3389 /* ARGSUSED */
3390 static int
zfs_do_rename(int argc,char ** argv)3391 zfs_do_rename(int argc, char **argv)
3392 {
3393 	zfs_handle_t *zhp;
3394 	int c;
3395 	int ret = 0;
3396 	boolean_t recurse = B_FALSE;
3397 	boolean_t parents = B_FALSE;
3398 	boolean_t force_unmount = B_FALSE;
3399 
3400 	/* check options */
3401 	while ((c = getopt(argc, argv, "prf")) != -1) {
3402 		switch (c) {
3403 		case 'p':
3404 			parents = B_TRUE;
3405 			break;
3406 		case 'r':
3407 			recurse = B_TRUE;
3408 			break;
3409 		case 'f':
3410 			force_unmount = B_TRUE;
3411 			break;
3412 		case '?':
3413 		default:
3414 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3415 			    optopt);
3416 			usage(B_FALSE);
3417 		}
3418 	}
3419 
3420 	argc -= optind;
3421 	argv += optind;
3422 
3423 	/* check number of arguments */
3424 	if (argc < 1) {
3425 		(void) fprintf(stderr, gettext("missing source dataset "
3426 		    "argument\n"));
3427 		usage(B_FALSE);
3428 	}
3429 	if (argc < 2) {
3430 		(void) fprintf(stderr, gettext("missing target dataset "
3431 		    "argument\n"));
3432 		usage(B_FALSE);
3433 	}
3434 	if (argc > 2) {
3435 		(void) fprintf(stderr, gettext("too many arguments\n"));
3436 		usage(B_FALSE);
3437 	}
3438 
3439 	if (recurse && parents) {
3440 		(void) fprintf(stderr, gettext("-p and -r options are mutually "
3441 		    "exclusive\n"));
3442 		usage(B_FALSE);
3443 	}
3444 
3445 	if (recurse && strchr(argv[0], '@') == 0) {
3446 		(void) fprintf(stderr, gettext("source dataset for recursive "
3447 		    "rename must be a snapshot\n"));
3448 		usage(B_FALSE);
3449 	}
3450 
3451 	if ((zhp = zfs_open(g_zfs, argv[0], parents ? ZFS_TYPE_FILESYSTEM |
3452 	    ZFS_TYPE_VOLUME : ZFS_TYPE_DATASET)) == NULL)
3453 		return (1);
3454 
3455 	/* If we were asked and the name looks good, try to create ancestors. */
3456 	if (parents && zfs_name_valid(argv[1], zfs_get_type(zhp)) &&
3457 	    zfs_create_ancestors(g_zfs, argv[1]) != 0) {
3458 		zfs_close(zhp);
3459 		return (1);
3460 	}
3461 
3462 	ret = (zfs_rename(zhp, argv[1], recurse, force_unmount) != 0);
3463 
3464 	zfs_close(zhp);
3465 	return (ret);
3466 }
3467 
3468 /*
3469  * zfs promote <fs>
3470  *
3471  * Promotes the given clone fs to be the parent
3472  */
3473 /* ARGSUSED */
3474 static int
zfs_do_promote(int argc,char ** argv)3475 zfs_do_promote(int argc, char **argv)
3476 {
3477 	zfs_handle_t *zhp;
3478 	int ret = 0;
3479 
3480 	/* check options */
3481 	if (argc > 1 && argv[1][0] == '-') {
3482 		(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3483 		    argv[1][1]);
3484 		usage(B_FALSE);
3485 	}
3486 
3487 	/* check number of arguments */
3488 	if (argc < 2) {
3489 		(void) fprintf(stderr, gettext("missing clone filesystem"
3490 		    " argument\n"));
3491 		usage(B_FALSE);
3492 	}
3493 	if (argc > 2) {
3494 		(void) fprintf(stderr, gettext("too many arguments\n"));
3495 		usage(B_FALSE);
3496 	}
3497 
3498 	zhp = zfs_open(g_zfs, argv[1], ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
3499 	if (zhp == NULL)
3500 		return (1);
3501 
3502 	ret = (zfs_promote(zhp) != 0);
3503 
3504 
3505 	zfs_close(zhp);
3506 	return (ret);
3507 }
3508 
3509 /*
3510  * zfs rollback [-rRf] <snapshot>
3511  *
3512  *	-r	Delete any intervening snapshots before doing rollback
3513  *	-R	Delete any snapshots and their clones
3514  *	-f	ignored for backwards compatability
3515  *
3516  * Given a filesystem, rollback to a specific snapshot, discarding any changes
3517  * since then and making it the active dataset.  If more recent snapshots exist,
3518  * the command will complain unless the '-r' flag is given.
3519  */
3520 typedef struct rollback_cbdata {
3521 	uint64_t	cb_create;
3522 	boolean_t	cb_first;
3523 	int		cb_doclones;
3524 	char		*cb_target;
3525 	int		cb_error;
3526 	boolean_t	cb_recurse;
3527 } rollback_cbdata_t;
3528 
3529 static int
rollback_check_dependent(zfs_handle_t * zhp,void * data)3530 rollback_check_dependent(zfs_handle_t *zhp, void *data)
3531 {
3532 	rollback_cbdata_t *cbp = data;
3533 
3534 	if (cbp->cb_first && cbp->cb_recurse) {
3535 		(void) fprintf(stderr, gettext("cannot rollback to "
3536 		    "'%s': clones of previous snapshots exist\n"),
3537 		    cbp->cb_target);
3538 		(void) fprintf(