zfs_main.c revision 1294:87b43e5de5ee
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, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22/*
23 * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#pragma ident	"%Z%%M%	%I%	%E% SMI"
28
29#include <assert.h>
30#include <errno.h>
31#include <libgen.h>
32#include <libintl.h>
33#include <libuutil.h>
34#include <locale.h>
35#include <stddef.h>
36#include <stdio.h>
37#include <stdlib.h>
38#include <strings.h>
39#include <unistd.h>
40#include <fcntl.h>
41#include <zone.h>
42#include <sys/mkdev.h>
43#include <sys/mntent.h>
44#include <sys/mnttab.h>
45#include <sys/mount.h>
46#include <sys/stat.h>
47
48#include <libzfs.h>
49
50#include "zfs_iter.h"
51
52static FILE *mnttab_file;
53
54static int zfs_do_clone(int argc, char **argv);
55static int zfs_do_create(int argc, char **argv);
56static int zfs_do_destroy(int argc, char **argv);
57static int zfs_do_get(int argc, char **argv);
58static int zfs_do_inherit(int argc, char **argv);
59static int zfs_do_list(int argc, char **argv);
60static int zfs_do_mount(int argc, char **argv);
61static int zfs_do_rename(int argc, char **argv);
62static int zfs_do_rollback(int argc, char **argv);
63static int zfs_do_set(int argc, char **argv);
64static int zfs_do_snapshot(int argc, char **argv);
65static int zfs_do_unmount(int argc, char **argv);
66static int zfs_do_share(int argc, char **argv);
67static int zfs_do_unshare(int argc, char **argv);
68static int zfs_do_backup(int argc, char **argv);
69static int zfs_do_restore(int argc, char **argv);
70
71/*
72 * These libumem hooks provide a reasonable set of defaults for the allocator's
73 * debugging facilities.
74 */
75const char *
76_umem_debug_init()
77{
78	return ("default,verbose"); /* $UMEM_DEBUG setting */
79}
80
81const char *
82_umem_logging_init(void)
83{
84	return ("fail,contents"); /* $UMEM_LOGGING setting */
85}
86
87typedef struct zfs_command {
88	const char	*name;
89	int		(*func)(int argc, char **argv);
90	const char	*usage;
91} zfs_command_t;
92
93/*
94 * Master command table.  Each ZFS command has a name, associated function, and
95 * usage message.  These commands are organized according to how they are
96 * displayed in the usage message.  An empty command (one with a NULL name)
97 * indicates an empty line in the generic usage message.  A command with a NULL
98 * usage message indicates an alias for an existing command, and is not
99 * displayed in the general usage message.
100 */
101static zfs_command_t command_table[] = {
102	{ "create",	zfs_do_create,
103	    "\tcreate <filesystem>\n"
104	    "\tcreate [-s] [-b blocksize] -V <size> <volume>\n"		},
105	{ "destroy",	zfs_do_destroy,
106	    "\tdestroy [-rRf] <filesystem|volume|snapshot>\n"		},
107	{ NULL },
108	{ "snapshot",	zfs_do_snapshot,
109	    "\tsnapshot <filesystem@name|volume@name>\n"		},
110	{ "rollback",	zfs_do_rollback,
111	    "\trollback [-rRf] <snapshot>\n"				},
112	{ "clone",	zfs_do_clone,
113	    "\tclone <snapshot> <filesystem|volume>\n"			},
114	{ "rename",	zfs_do_rename,
115	    "\trename <filesystem|volume|snapshot> "
116	    "<filesystem|volume|snapshot>\n"				},
117	{ NULL },
118	{ "list",	zfs_do_list,
119	    "\tlist [-rH] [-o property[,property]...] [-t type[,type]...]\n"
120	    "\t    [filesystem|volume|snapshot] ...\n"			},
121	{ NULL },
122	{ "set",	zfs_do_set,
123	    "\tset <property=value> <filesystem|volume> ...\n"		},
124	{ "get", 	zfs_do_get,
125	    "\tget [-rHp] [-o field[,field]...] [-s source[,source]...]\n"
126	    "\t    <all | property[,property]...> "
127	    "<filesystem|volume|snapshot> ...\n"			},
128	{ "inherit",	zfs_do_inherit,
129	    "\tinherit [-r] <property> <filesystem|volume> ...\n"	},
130	{ NULL },
131	{ "mount",	zfs_do_mount,
132	    "\tmount\n"
133	    "\tmount [-o opts] [-O] -a\n"
134	    "\tmount [-o opts] [-O] <filesystem>\n"			},
135	{ NULL },
136	{ "unmount",	zfs_do_unmount,
137	    "\tunmount [-f] -a\n"
138	    "\tunmount [-f] <filesystem|mountpoint>\n"			},
139	{ NULL },
140	{ "share",	zfs_do_share,
141	    "\tshare -a\n"
142	    "\tshare <filesystem>\n"					},
143	{ NULL },
144	{ "unshare",	zfs_do_unshare,
145	    "\tunshare [-f] -a\n"
146	    "\tunshare [-f] <filesystem|mountpoint>\n"			},
147	{ NULL },
148	{ "backup",	zfs_do_backup,
149	    "\tbackup [-i <snapshot>] <snapshot>\n"			},
150	{ "restore",	zfs_do_restore,
151	    "\trestore [-vn] <filesystem|volume|snapshot>\n"
152	    "\trestore [-vn] -d <filesystem>\n"				},
153};
154
155#define	NCOMMAND	(sizeof (command_table) / sizeof (command_table[0]))
156
157zfs_command_t *current_command;
158
159/*
160 * Utility function to guarantee malloc() success.
161 */
162void *
163safe_malloc(size_t size)
164{
165	void *data;
166
167	if ((data = calloc(1, size)) == NULL) {
168		(void) fprintf(stderr, "internal error: out of memory\n");
169		exit(1);
170	}
171
172	return (data);
173}
174
175/*
176 * Display usage message.  If we're inside a command, display only the usage for
177 * that command.  Otherwise, iterate over the entire command table and display
178 * a complete usage message.
179 */
180static void
181usage(int requested)
182{
183	int i;
184	int show_properties = FALSE;
185	FILE *fp = requested ? stdout : stderr;
186
187	if (current_command == NULL) {
188
189		(void) fprintf(fp, gettext("usage: zfs command args ...\n"));
190		(void) fprintf(fp,
191		    gettext("where 'command' is one of the following:\n\n"));
192
193		for (i = 0; i < NCOMMAND; i++) {
194			if (command_table[i].name == NULL)
195				(void) fprintf(fp, "\n");
196			else
197				(void) fprintf(fp, "%s",
198				    command_table[i].usage);
199		}
200
201		(void) fprintf(fp, gettext("\nEach dataset is of the form: "
202		    "pool/[dataset/]*dataset[@name]\n"));
203	} else {
204		(void) fprintf(fp, gettext("usage:\n"));
205		(void) fprintf(fp, current_command->usage);
206	}
207
208	if (current_command == NULL ||
209	    strcmp(current_command->name, "set") == 0 ||
210	    strcmp(current_command->name, "get") == 0 ||
211	    strcmp(current_command->name, "inherit") == 0 ||
212	    strcmp(current_command->name, "list") == 0)
213		show_properties = TRUE;
214
215	if (show_properties) {
216
217		(void) fprintf(fp,
218		    gettext("\nThe following properties are supported:\n"));
219
220		(void) fprintf(fp, "\n\t%-13s  %s  %s   %s\n\n",
221		    "PROPERTY", "EDIT", "INHERIT", "VALUES");
222
223		for (i = 0; i < ZFS_NPROP_VISIBLE; i++) {
224			(void) fprintf(fp, "\t%-13s  ", zfs_prop_to_name(i));
225
226			if (zfs_prop_readonly(i))
227				(void) fprintf(fp, "  NO    ");
228			else
229				(void) fprintf(fp, " YES    ");
230
231			if (zfs_prop_inheritable(i))
232				(void) fprintf(fp, "  YES   ");
233			else
234				(void) fprintf(fp, "   NO   ");
235
236			if (zfs_prop_values(i) == NULL)
237				(void) fprintf(fp, "-\n");
238			else
239				(void) fprintf(fp, "%s\n", zfs_prop_values(i));
240		}
241		(void) fprintf(fp, gettext("\nSizes are specified in bytes "
242		    "with standard units such as K, M, G, etc.\n"));
243	}
244
245	exit(requested ? 0 : 2);
246}
247
248/*
249 * zfs clone <fs, snap, vol> fs
250 *
251 * Given an existing dataset, create a writable copy whose initial contents
252 * are the same as the source.  The newly created dataset maintains a
253 * dependency on the original; the original cannot be destroyed so long as
254 * the clone exists.
255 */
256static int
257zfs_do_clone(int argc, char **argv)
258{
259	zfs_handle_t *zhp;
260	int ret;
261
262	/* check options */
263	if (argc > 1 && argv[1][0] == '-') {
264		(void) fprintf(stderr, gettext("invalid option '%c'\n"),
265		    argv[1][1]);
266		usage(FALSE);
267	}
268
269	/* check number of arguments */
270	if (argc < 2) {
271		(void) fprintf(stderr, gettext("missing source dataset "
272		    "argument\n"));
273		usage(FALSE);
274	}
275	if (argc < 3) {
276		(void) fprintf(stderr, gettext("missing target dataset "
277		    "argument\n"));
278		usage(FALSE);
279	}
280	if (argc > 3) {
281		(void) fprintf(stderr, gettext("too many arguments\n"));
282		usage(FALSE);
283	}
284
285	/* open the source dataset */
286	if ((zhp = zfs_open(argv[1], ZFS_TYPE_SNAPSHOT)) == NULL)
287		return (1);
288
289	/* pass to libzfs */
290	ret = zfs_clone(zhp, argv[2]);
291
292	/* create the mountpoint if necessary */
293	if (ret == 0) {
294		zfs_handle_t *clone = zfs_open(argv[2], ZFS_TYPE_ANY);
295		if (clone != NULL) {
296			if ((ret = zfs_mount(clone, NULL, 0)) == 0)
297				ret = zfs_share(clone);
298			zfs_close(clone);
299		}
300	}
301
302	zfs_close(zhp);
303
304	return (ret == 0 ? 0 : 1);
305}
306
307/*
308 * zfs create fs
309 * zfs create [-s] -V vol size
310 *
311 * Create a new dataset.  This command can be used to create filesystems
312 * and volumes.  Snapshot creation is handled by 'zfs snapshot'.
313 * For volumes, the user must specify a size to be used.
314 *
315 * The '-s' flag applies only to volumes, and indicates that we should not try
316 * to set the reservation for this volume.  By default we set a reservation
317 * equal to the size for any volume.
318 */
319static int
320zfs_do_create(int argc, char **argv)
321{
322	zfs_type_t type = ZFS_TYPE_FILESYSTEM;
323	zfs_handle_t *zhp;
324	char *size = NULL;
325	char *blocksize = NULL;
326	int c;
327	int noreserve = FALSE;
328	int ret;
329
330	/* check options */
331	while ((c = getopt(argc, argv, ":V:b:s")) != -1) {
332		switch (c) {
333		case 'V':
334			type = ZFS_TYPE_VOLUME;
335			size = optarg;
336			break;
337		case 'b':
338			blocksize = optarg;
339			break;
340		case 's':
341			noreserve = TRUE;
342			break;
343		case ':':
344			(void) fprintf(stderr, gettext("missing size "
345			    "argument\n"));
346			usage(FALSE);
347			break;
348		case '?':
349			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
350			    optopt);
351			usage(FALSE);
352		}
353	}
354
355	if (noreserve && type != ZFS_TYPE_VOLUME) {
356		(void) fprintf(stderr, gettext("'-s' can only be used when "
357		    "creating a volume\n"));
358		usage(FALSE);
359	}
360
361	argc -= optind;
362	argv += optind;
363
364	/* check number of arguments */
365	if (argc == 0) {
366		(void) fprintf(stderr, gettext("missing %s argument\n"),
367		    zfs_type_to_name(type));
368		usage(FALSE);
369	}
370	if (argc > 1) {
371		(void) fprintf(stderr, gettext("too many arguments\n"));
372		usage(FALSE);
373	}
374
375	/* pass to libzfs */
376	if (zfs_create(argv[0], type, size, blocksize) != 0)
377		return (1);
378
379	if ((zhp = zfs_open(argv[0], ZFS_TYPE_ANY)) == NULL)
380		return (1);
381
382	/*
383	 * Volume handling.  By default, we try to create a reservation of equal
384	 * size for the volume.  If we can't do this, then destroy the dataset
385	 * and report an error.
386	 */
387	if (type == ZFS_TYPE_VOLUME && !noreserve) {
388		if (zfs_prop_set(zhp, ZFS_PROP_RESERVATION, size) != 0) {
389			(void) fprintf(stderr, gettext("use '-s' to create a "
390			    "volume without a matching reservation\n"));
391			(void) zfs_destroy(zhp);
392			return (1);
393		}
394	}
395
396	/*
397	 * Mount and/or share the new filesystem as appropriate.  We provide a
398	 * verbose error message to let the user know that their filesystem was
399	 * in fact created, even if we failed to mount or share it.
400	 */
401	if (zfs_mount(zhp, NULL, 0) != 0) {
402		(void) fprintf(stderr, gettext("filesystem successfully "
403		    "created, but not mounted\n"));
404		ret = 1;
405	} else if (zfs_share(zhp) != 0) {
406		(void) fprintf(stderr, gettext("filesystem successfully "
407		    "created, but not shared\n"));
408		ret = 1;
409	} else {
410		ret = 0;
411	}
412
413	zfs_close(zhp);
414	return (ret);
415}
416
417/*
418 * zfs destroy [-rf] <fs, snap, vol>
419 *
420 * 	-r	Recursively destroy all children
421 * 	-R	Recursively destroy all dependents, including clones
422 * 	-f	Force unmounting of any dependents
423 *
424 * Destroys the given dataset.  By default, it will unmount any filesystems,
425 * and refuse to destroy a dataset that has any dependents.  A dependent can
426 * either be a child, or a clone of a child.
427 */
428typedef struct destroy_cbdata {
429	int		cb_first;
430	int		cb_force;
431	int		cb_recurse;
432	int		cb_error;
433	int		cb_needforce;
434	int		cb_doclones;
435	zfs_handle_t	*cb_target;
436} destroy_cbdata_t;
437
438/*
439 * Check for any dependents based on the '-r' or '-R' flags.
440 */
441static int
442destroy_check_dependent(zfs_handle_t *zhp, void *data)
443{
444	destroy_cbdata_t *cbp = data;
445	const char *tname = zfs_get_name(cbp->cb_target);
446	const char *name = zfs_get_name(zhp);
447
448	if (strncmp(tname, name, strlen(tname)) == 0 &&
449	    (name[strlen(tname)] == '/' || name[strlen(tname)] == '@')) {
450		/*
451		 * This is a direct descendant, not a clone somewhere else in
452		 * the hierarchy.
453		 */
454		if (cbp->cb_recurse)
455			goto out;
456
457		if (cbp->cb_first) {
458			(void) fprintf(stderr, gettext("cannot destroy '%s': "
459			    "%s has children\n"),
460			    zfs_get_name(cbp->cb_target),
461			    zfs_type_to_name(zfs_get_type(cbp->cb_target)));
462			(void) fprintf(stderr, gettext("use '-r' to destroy "
463			    "the following datasets:\n"));
464			cbp->cb_first = 0;
465			cbp->cb_error = 1;
466		}
467
468		(void) fprintf(stderr, "%s\n", zfs_get_name(zhp));
469	} else {
470		/*
471		 * This is a clone.  We only want to report this if the '-r'
472		 * wasn't specified, or the target is a snapshot.
473		 */
474		if (!cbp->cb_recurse &&
475		    zfs_get_type(cbp->cb_target) != ZFS_TYPE_SNAPSHOT)
476			goto out;
477
478		if (cbp->cb_first) {
479			(void) fprintf(stderr, gettext("cannot destroy '%s': "
480			    "%s has dependent clones\n"),
481			    zfs_get_name(cbp->cb_target),
482			    zfs_type_to_name(zfs_get_type(cbp->cb_target)));
483			(void) fprintf(stderr, gettext("use '-R' to destroy "
484			    "the following datasets:\n"));
485			cbp->cb_first = 0;
486			cbp->cb_error = 1;
487		}
488
489		(void) fprintf(stderr, "%s\n", zfs_get_name(zhp));
490	}
491
492out:
493	zfs_close(zhp);
494	return (0);
495}
496
497static int
498destroy_callback(zfs_handle_t *zhp, void *data)
499{
500	destroy_cbdata_t *cbp = data;
501
502	/*
503	 * Ignore pools (which we've already flagged as an error before getting
504	 * here.
505	 */
506	if (strchr(zfs_get_name(zhp), '/') == NULL &&
507	    zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) {
508		zfs_close(zhp);
509		return (0);
510	}
511
512	/*
513	 * Bail out on the first error.
514	 */
515	if (zfs_unmount(zhp, NULL, cbp->cb_force ? MS_FORCE : 0) != 0 ||
516	    zfs_destroy(zhp) != 0) {
517		zfs_close(zhp);
518		return (-1);
519	}
520
521	zfs_close(zhp);
522	return (0);
523}
524
525
526static int
527zfs_do_destroy(int argc, char **argv)
528{
529	destroy_cbdata_t cb = { 0 };
530	int c;
531	zfs_handle_t *zhp;
532
533	/* check options */
534	while ((c = getopt(argc, argv, "frR")) != -1) {
535		switch (c) {
536		case 'f':
537			cb.cb_force = 1;
538			break;
539		case 'r':
540			cb.cb_recurse = 1;
541			break;
542		case 'R':
543			cb.cb_recurse = 1;
544			cb.cb_doclones = 1;
545			break;
546		case '?':
547		default:
548			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
549			    optopt);
550			usage(FALSE);
551		}
552	}
553
554	argc -= optind;
555	argv += optind;
556
557	/* check number of arguments */
558	if (argc == 0) {
559		(void) fprintf(stderr, gettext("missing path argument\n"));
560		usage(FALSE);
561	}
562	if (argc > 1) {
563		(void) fprintf(stderr, gettext("too many arguments\n"));
564		usage(FALSE);
565	}
566
567	/* Open the given dataset */
568	if ((zhp = zfs_open(argv[0], ZFS_TYPE_ANY)) == NULL)
569		return (1);
570
571	cb.cb_target = zhp;
572
573	/*
574	 * Perform an explicit check for pools before going any further.
575	 */
576	if (!cb.cb_recurse && strchr(zfs_get_name(zhp), '/') == NULL &&
577	    zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) {
578		(void) fprintf(stderr, gettext("cannot destroy '%s': "
579		    "operation does not apply to pools\n"),
580		    zfs_get_name(zhp));
581		(void) fprintf(stderr, gettext("use 'zfs destroy -r "
582		    "%s' to destroy all datasets in the pool\n"),
583		    zfs_get_name(zhp));
584		(void) fprintf(stderr, gettext("use 'zpool destroy %s' "
585		    "to destroy the pool itself\n"), zfs_get_name(zhp));
586		zfs_close(zhp);
587		return (1);
588	}
589
590
591	/*
592	 * Check for any dependents and/or clones.
593	 */
594	cb.cb_first = 1;
595	if (!cb.cb_doclones)
596		(void) zfs_iter_dependents(zhp, destroy_check_dependent, &cb);
597
598	if (cb.cb_error) {
599		zfs_close(zhp);
600		return (1);
601	}
602
603	/*
604	 * Do the real thing.
605	 */
606	if (zfs_iter_dependents(zhp, destroy_callback, &cb) == 0 &&
607	    destroy_callback(zhp, &cb) == 0)
608		return (0);
609
610	return (1);
611}
612
613/*
614 * zfs get [-rHp] [-o field[,field]...] [-s source[,source]...]
615 * 	< all | property[,property]... > < fs | snap | vol > ...
616 *
617 *	-r	recurse over any child datasets
618 *	-H	scripted mode.  Headers are stripped, and fields are separated
619 *		by tabs instead of spaces.
620 *	-o	Set of fields to display.  One of "name,property,value,source".
621 *		Default is all four.
622 *	-s	Set of sources to allow.  One of
623 *		"local,default,inherited,temporary,none".  Default is all
624 *		five.
625 *	-p	Display values in parsable (literal) format.
626 *
627 *  Prints properties for the given datasets.  The user can control which
628 *  columns to display as well as which property types to allow.
629 */
630typedef struct get_cbdata {
631	int cb_scripted;
632	int cb_sources;
633	int cb_literal;
634	int cb_columns[4];
635	zfs_prop_t cb_prop[ZFS_NPROP_ALL];
636	int cb_nprop;
637	int cb_isall;
638} get_cbdata_t;
639
640#define	GET_COL_NAME		1
641#define	GET_COL_PROPERTY	2
642#define	GET_COL_VALUE		3
643#define	GET_COL_SOURCE		4
644
645/*
646 * Display a single line of output, according to the settings in the callback
647 * structure.
648 */
649static void
650print_one_property(zfs_handle_t *zhp, get_cbdata_t *cbp, zfs_prop_t prop,
651    const char *value, zfs_source_t sourcetype, const char *source)
652{
653	int i;
654	int width;
655	const char *str;
656	char buf[128];
657
658	/*
659	 * Ignore those source types that the user has chosen to ignore.
660	 */
661	if ((sourcetype & cbp->cb_sources) == 0)
662		return;
663
664	for (i = 0; i < 4; i++) {
665		switch (cbp->cb_columns[i]) {
666		case GET_COL_NAME:
667			width = 15;
668			str = zfs_get_name(zhp);
669			break;
670
671		case GET_COL_PROPERTY:
672			width = 13;
673			str = zfs_prop_to_name(prop);
674			break;
675
676		case GET_COL_VALUE:
677			width = 25;
678			str = value;
679			break;
680
681		case GET_COL_SOURCE:
682			width = 15;
683			switch (sourcetype) {
684			case ZFS_SRC_NONE:
685				str = "-";
686				break;
687
688			case ZFS_SRC_DEFAULT:
689				str = "default";
690				break;
691
692			case ZFS_SRC_LOCAL:
693				str = "local";
694				break;
695
696			case ZFS_SRC_TEMPORARY:
697				str = "temporary";
698				break;
699
700			case ZFS_SRC_INHERITED:
701				(void) snprintf(buf, sizeof (buf),
702				    "inherited from %s", source);
703				str = buf;
704				break;
705			}
706			break;
707
708		default:
709			continue;
710		}
711
712		if (cbp->cb_columns[i + 1] == 0)
713			(void) printf("%s", str);
714		else if (cbp->cb_scripted)
715			(void) printf("%s\t", str);
716		else
717			(void) printf("%-*s  ", width, str);
718
719	}
720
721	(void) printf("\n");
722}
723
724/*
725 * Invoked to display the properties for a single dataset.
726 */
727static int
728get_callback(zfs_handle_t *zhp, void *data)
729{
730	char buf[ZFS_MAXPROPLEN];
731	zfs_source_t sourcetype;
732	char source[ZFS_MAXNAMELEN];
733	get_cbdata_t *cbp = data;
734	int i;
735
736	for (i = 0; i < cbp->cb_nprop; i++) {
737		if (zfs_prop_get(zhp, cbp->cb_prop[i], buf,
738		    sizeof (buf), &sourcetype, source, sizeof (source),
739		    cbp->cb_literal) != 0) {
740			if (cbp->cb_isall)
741				continue;
742			(void) strlcpy(buf, "-", sizeof (buf));
743			sourcetype = ZFS_SRC_NONE;
744		}
745
746		print_one_property(zhp, cbp, cbp->cb_prop[i],
747		    buf, sourcetype, source);
748	}
749
750	return (0);
751}
752
753static int
754zfs_do_get(int argc, char **argv)
755{
756	get_cbdata_t cb = { 0 };
757	int recurse = 0;
758	int c;
759	char *value, *fields, *badopt;
760	int i;
761	int ret;
762
763	/*
764	 * Set up default columns and sources.
765	 */
766	cb.cb_sources = ZFS_SRC_ALL;
767	cb.cb_columns[0] = GET_COL_NAME;
768	cb.cb_columns[1] = GET_COL_PROPERTY;
769	cb.cb_columns[2] = GET_COL_VALUE;
770	cb.cb_columns[3] = GET_COL_SOURCE;
771
772	/* check options */
773	while ((c = getopt(argc, argv, ":o:s:rHp")) != -1) {
774		switch (c) {
775		case 'p':
776			cb.cb_literal = TRUE;
777			break;
778		case 'r':
779			recurse = TRUE;
780			break;
781		case 'H':
782			cb.cb_scripted = TRUE;
783			break;
784		case ':':
785			(void) fprintf(stderr, gettext("missing argument for "
786			    "'%c' option\n"), optopt);
787			usage(FALSE);
788			break;
789		case 'o':
790			/*
791			 * Process the set of columns to display.  We zero out
792			 * the structure to give us a blank slate.
793			 */
794			bzero(&cb.cb_columns, sizeof (cb.cb_columns));
795			i = 0;
796			while (*optarg != '\0') {
797				static char *col_subopts[] =
798				    { "name", "property", "value", "source",
799				    NULL };
800
801				if (i == 4) {
802					(void) fprintf(stderr, gettext("too "
803					    "many fields given to -o "
804					    "option\n"));
805					usage(FALSE);
806				}
807
808				switch (getsubopt(&optarg, col_subopts,
809				    &value)) {
810				case 0:
811					cb.cb_columns[i++] = GET_COL_NAME;
812					break;
813				case 1:
814					cb.cb_columns[i++] = GET_COL_PROPERTY;
815					break;
816				case 2:
817					cb.cb_columns[i++] = GET_COL_VALUE;
818					break;
819				case 3:
820					cb.cb_columns[i++] = GET_COL_SOURCE;
821					break;
822				default:
823					(void) fprintf(stderr,
824					    gettext("invalid column name "
825					    "'%s'\n"), value);
826					    usage(FALSE);
827				}
828			}
829			break;
830
831		case 's':
832			cb.cb_sources = 0;
833			while (*optarg != '\0') {
834				static char *source_subopts[] = {
835					"local", "default", "inherited",
836					"temporary", "none", NULL };
837
838				switch (getsubopt(&optarg, source_subopts,
839				    &value)) {
840				case 0:
841					cb.cb_sources |= ZFS_SRC_LOCAL;
842					break;
843				case 1:
844					cb.cb_sources |= ZFS_SRC_DEFAULT;
845					break;
846				case 2:
847					cb.cb_sources |= ZFS_SRC_INHERITED;
848					break;
849				case 3:
850					cb.cb_sources |= ZFS_SRC_TEMPORARY;
851					break;
852				case 4:
853					cb.cb_sources |= ZFS_SRC_NONE;
854					break;
855				default:
856					(void) fprintf(stderr,
857					    gettext("invalid source "
858					    "'%s'\n"), value);
859					    usage(FALSE);
860				}
861			}
862			break;
863
864		case '?':
865			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
866			    optopt);
867			usage(FALSE);
868		}
869	}
870
871	argc -= optind;
872	argv += optind;
873
874	if (argc < 1) {
875		(void) fprintf(stderr, gettext("missing property "
876		    "argument\n"));
877		usage(FALSE);
878	}
879
880	fields = argv[0];
881
882	/*
883	 * If the user specifies 'all', the behavior of 'zfs get' is slightly
884	 * different, because we don't show properties which don't apply to the
885	 * given dataset.
886	 */
887	if (strcmp(fields, "all") == 0)
888		cb.cb_isall = TRUE;
889
890	if ((ret = zfs_get_proplist(fields, cb.cb_prop, ZFS_NPROP_ALL,
891	    &cb.cb_nprop, &badopt)) != 0) {
892		if (ret == EINVAL)
893			(void) fprintf(stderr, gettext("invalid property "
894			    "'%s'\n"), badopt);
895		else
896			(void) fprintf(stderr, gettext("too many properties "
897			    "specified\n"));
898		usage(FALSE);
899	}
900
901	argc--;
902	argv++;
903
904	/* check for at least one dataset name */
905	if (argc < 1) {
906		(void) fprintf(stderr, gettext("missing dataset argument\n"));
907		usage(FALSE);
908	}
909
910	/*
911	 * Print out any headers
912	 */
913	if (!cb.cb_scripted) {
914		int i;
915		for (i = 0; i < 4; i++) {
916			switch (cb.cb_columns[i]) {
917			case GET_COL_NAME:
918				(void) printf("%-15s  ", "NAME");
919				break;
920			case GET_COL_PROPERTY:
921				(void) printf("%-13s  ", "PROPERTY");
922				break;
923			case GET_COL_VALUE:
924				(void) printf("%-25s  ", "VALUE");
925				break;
926			case GET_COL_SOURCE:
927				(void) printf("%s", "SOURCE");
928				break;
929			}
930		}
931		(void) printf("\n");
932	}
933
934	/* run for each object */
935	return (zfs_for_each(argc, argv, recurse, ZFS_TYPE_ANY,
936	    get_callback, &cb));
937}
938
939/*
940 * inherit [-r] <property> <fs|vol> ...
941 *
942 * 	-r	Recurse over all children
943 *
944 * For each dataset specified on the command line, inherit the given property
945 * from its parent.  Inheriting a property at the pool level will cause it to
946 * use the default value.  The '-r' flag will recurse over all children, and is
947 * useful for setting a property on a hierarchy-wide basis, regardless of any
948 * local modifications for each dataset.
949 */
950static int
951inherit_callback(zfs_handle_t *zhp, void *data)
952{
953	zfs_prop_t prop = (zfs_prop_t)data;
954
955	return (zfs_prop_inherit(zhp, prop) != 0);
956}
957
958static int
959zfs_do_inherit(int argc, char **argv)
960{
961	int recurse = 0;
962	int c;
963	zfs_prop_t prop;
964	char *propname;
965
966	/* check options */
967	while ((c = getopt(argc, argv, "r")) != -1) {
968		switch (c) {
969		case 'r':
970			recurse = TRUE;
971			break;
972		case '?':
973		default:
974			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
975			    optopt);
976			usage(FALSE);
977		}
978	}
979
980	argc -= optind;
981	argv += optind;
982
983	/* check number of arguments */
984	if (argc < 1) {
985		(void) fprintf(stderr, gettext("missing property argument\n"));
986		usage(FALSE);
987	}
988	if (argc < 2) {
989		(void) fprintf(stderr, gettext("missing dataset argument\n"));
990		usage(FALSE);
991	}
992
993	propname = argv[0];
994
995	/*
996	 * Get and validate the property before iterating over the datasets.  We
997	 * do this now so as to avoid printing out an error message for each and
998	 * every dataset.
999	 */
1000	if ((prop = zfs_name_to_prop(propname)) == ZFS_PROP_INVAL) {
1001		(void) fprintf(stderr, gettext("invalid property '%s'\n"),
1002		    propname);
1003		usage(FALSE);
1004	}
1005	if (zfs_prop_readonly(prop)) {
1006		(void) fprintf(stderr, gettext("%s property is read-only\n"),
1007		    propname);
1008		return (1);
1009	}
1010	if (!zfs_prop_inheritable(prop)) {
1011		(void) fprintf(stderr, gettext("%s property cannot be "
1012		    "inherited\n"), propname);
1013		(void) fprintf(stderr, gettext("use 'zfs set %s=none' to "
1014		    "clear\n"), propname);
1015		return (1);
1016	}
1017
1018	return (zfs_for_each(argc - 1, argv + 1, recurse,
1019	    ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
1020	    inherit_callback, (void *)prop));
1021}
1022
1023/*
1024 * list [-rH] [-o property[,property]...] [-t type[,type]...] <dataset> ...
1025 *
1026 * 	-r	Recurse over all children
1027 * 	-H	Scripted mode; elide headers and separate colums by tabs
1028 * 	-o	Control which fields to display.
1029 * 	-t	Control which object types to display.
1030 *
1031 * When given no arguments, lists all filesystems in the system.
1032 * Otherwise, list the specified datasets, optionally recursing down them if
1033 * '-r' is specified.
1034 */
1035typedef struct list_cbdata {
1036	int		cb_first;
1037	int		cb_scripted;
1038	zfs_prop_t	cb_fields[ZFS_NPROP_ALL];
1039	int		cb_fieldcount;
1040} list_cbdata_t;
1041
1042/*
1043 * Given a list of columns to display, output appropriate headers for each one.
1044 */
1045static void
1046print_header(zfs_prop_t *fields, size_t count)
1047{
1048	int i;
1049
1050	for (i = 0; i < count; i++) {
1051		if (i != 0)
1052			(void) printf("  ");
1053		if (i == count - 1)
1054			(void) printf("%s", zfs_prop_column_name(fields[i]));
1055		else	/* LINTED - format specifier */
1056			(void) printf(zfs_prop_column_format(fields[i]),
1057			    zfs_prop_column_name(fields[i]));
1058	}
1059
1060	(void) printf("\n");
1061}
1062
1063/*
1064 * Given a dataset and a list of fields, print out all the properties according
1065 * to the described layout.
1066 */
1067static void
1068print_dataset(zfs_handle_t *zhp, zfs_prop_t *fields, size_t count, int scripted)
1069{
1070	int i;
1071	char property[ZFS_MAXPROPLEN];
1072
1073	for (i = 0; i < count; i++) {
1074		if (i != 0) {
1075			if (scripted)
1076				(void) printf("\t");
1077			else
1078				(void) printf("  ");
1079		}
1080
1081		if (zfs_prop_get(zhp, fields[i], property,
1082		    sizeof (property), NULL, NULL, 0, FALSE) != 0)
1083			(void) strlcpy(property, "-", sizeof (property));
1084
1085		/*
1086		 * If this is being called in scripted mode, or if this is the
1087		 * last column and it is left-justified, don't include a width
1088		 * format specifier.
1089		 */
1090		if (scripted || (i == count - 1 &&
1091		    strchr(zfs_prop_column_format(fields[i]), '-') != NULL))
1092			(void) printf("%s", property);
1093		else	/* LINTED - format specifier */
1094			(void) printf(zfs_prop_column_format(fields[i]),
1095			    property);
1096	}
1097
1098	(void) printf("\n");
1099}
1100
1101/*
1102 * Generic callback function to list a dataset or snapshot.
1103 */
1104static int
1105list_callback(zfs_handle_t *zhp, void *data)
1106{
1107	list_cbdata_t *cbp = data;
1108
1109	if (cbp->cb_first) {
1110		if (!cbp->cb_scripted)
1111			print_header(cbp->cb_fields, cbp->cb_fieldcount);
1112		cbp->cb_first = FALSE;
1113	}
1114
1115	print_dataset(zhp, cbp->cb_fields, cbp->cb_fieldcount,
1116	    cbp->cb_scripted);
1117
1118	return (0);
1119}
1120
1121static int
1122zfs_do_list(int argc, char **argv)
1123{
1124	int c;
1125	int recurse = 0;
1126	int scripted = FALSE;
1127	static char default_fields[] =
1128	    "name,used,available,referenced,mountpoint";
1129	int types = ZFS_TYPE_ANY;
1130	char *fields = NULL;
1131	char *basic_fields = default_fields;
1132	list_cbdata_t cb = { 0 };
1133	char *value;
1134	int ret;
1135	char *type_subopts[] = { "filesystem", "volume", "snapshot", NULL };
1136	char *badopt;
1137	int alloffset;
1138
1139	/* check options */
1140	while ((c = getopt(argc, argv, ":o:rt:H")) != -1) {
1141		switch (c) {
1142		case 'o':
1143			fields = optarg;
1144			break;
1145		case 'r':
1146			recurse = TRUE;
1147			break;
1148		case 'H':
1149			scripted = TRUE;
1150			break;
1151		case 't':
1152			types = 0;
1153			while (*optarg != '\0') {
1154				switch (getsubopt(&optarg, type_subopts,
1155				    &value)) {
1156				case 0:
1157					types |= ZFS_TYPE_FILESYSTEM;
1158					break;
1159				case 1:
1160					types |= ZFS_TYPE_VOLUME;
1161					break;
1162				case 2:
1163					types |= ZFS_TYPE_SNAPSHOT;
1164					break;
1165				default:
1166					(void) fprintf(stderr,
1167					    gettext("invalid type '%s'\n"),
1168					    value);
1169					usage(FALSE);
1170				}
1171			}
1172			break;
1173		case ':':
1174			(void) fprintf(stderr, gettext("missing argument for "
1175			    "'%c' option\n"), optopt);
1176			usage(FALSE);
1177			break;
1178		case '?':
1179			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1180			    optopt);
1181			usage(FALSE);
1182		}
1183	}
1184
1185	argc -= optind;
1186	argv += optind;
1187
1188	if (fields == NULL)
1189		fields = basic_fields;
1190
1191	/*
1192	 * If the user specifies '-o all', the zfs_get_proplist() doesn't
1193	 * normally include the name of the dataset.  For 'zfs list', we always
1194	 * want this property to be first.
1195	 */
1196	if (strcmp(fields, "all") == 0) {
1197		cb.cb_fields[0] = ZFS_PROP_NAME;
1198		alloffset = 1;
1199	} else {
1200		alloffset = 0;
1201	}
1202
1203	if ((ret = zfs_get_proplist(fields, cb.cb_fields + alloffset,
1204	    ZFS_NPROP_ALL - alloffset, &cb.cb_fieldcount, &badopt)) != 0) {
1205		if (ret == EINVAL)
1206			(void) fprintf(stderr, gettext("invalid property "
1207			    "'%s'\n"), badopt);
1208		else
1209			(void) fprintf(stderr, gettext("too many properties "
1210			    "specified\n"));
1211		usage(FALSE);
1212	}
1213
1214	cb.cb_fieldcount += alloffset;
1215	cb.cb_scripted = scripted;
1216	cb.cb_first = TRUE;
1217
1218	ret = zfs_for_each(argc, argv, recurse, types, list_callback, &cb);
1219
1220	if (ret == 0 && cb.cb_first == TRUE)
1221		(void) printf(gettext("no datasets available\n"));
1222
1223	return (ret);
1224}
1225
1226/*
1227 * zfs rename <fs | snap | vol> <fs | snap | vol>
1228 *
1229 * Renames the given dataset to another of the same type.
1230 */
1231/* ARGSUSED */
1232static int
1233zfs_do_rename(int argc, char **argv)
1234{
1235	zfs_handle_t *zhp;
1236	int ret = 1;
1237
1238	/* check options */
1239	if (argc > 1 && argv[1][0] == '-') {
1240		(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1241		    argv[1][1]);
1242		usage(FALSE);
1243	}
1244
1245	/* check number of arguments */
1246	if (argc < 2) {
1247		(void) fprintf(stderr, gettext("missing source dataset "
1248		    "argument\n"));
1249		usage(FALSE);
1250	}
1251	if (argc < 3) {
1252		(void) fprintf(stderr, gettext("missing target dataset "
1253		    "argument\n"));
1254		usage(FALSE);
1255	}
1256	if (argc > 3) {
1257		(void) fprintf(stderr, gettext("too many arguments\n"));
1258		usage(FALSE);
1259	}
1260
1261	if ((zhp = zfs_open(argv[1], ZFS_TYPE_ANY)) == NULL)
1262		return (1);
1263
1264	if (zfs_rename(zhp, argv[2]) != 0)
1265		goto error;
1266
1267	ret = 0;
1268error:
1269	zfs_close(zhp);
1270	return (ret);
1271}
1272
1273/*
1274 * zfs rollback [-rfR] <snapshot>
1275 *
1276 * 	-r	Delete any intervening snapshots before doing rollback
1277 * 	-R	Delete any snapshots and their clones
1278 * 	-f	Force unmount filesystems, even if they are in use.
1279 *
1280 * Given a filesystem, rollback to a specific snapshot, discarding any changes
1281 * since then and making it the active dataset.  If more recent snapshots exist,
1282 * the command will complain unless the '-r' flag is given.
1283 */
1284typedef struct rollback_cbdata {
1285	uint64_t	cb_create;
1286	int		cb_first;
1287	int		cb_doclones;
1288	char		*cb_target;
1289	int		cb_error;
1290	int		cb_recurse;
1291	int		cb_dependent;
1292} rollback_cbdata_t;
1293
1294/*
1295 * Report any snapshots more recent than the one specified.  Used when '-r' is
1296 * not specified.  We reuse this same callback for the snapshot dependents - if
1297 * 'cb_dependent' is set, then this is a dependent and we should report it
1298 * without checking the transaction group.
1299 */
1300static int
1301rollback_check(zfs_handle_t *zhp, void *data)
1302{
1303	rollback_cbdata_t *cbp = data;
1304
1305	if (cbp->cb_doclones)
1306		return (0);
1307
1308	if (!cbp->cb_dependent) {
1309		if (strcmp(zfs_get_name(zhp), cbp->cb_target) != 0 &&
1310		    zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT &&
1311		    zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) >
1312		    cbp->cb_create) {
1313
1314			if (cbp->cb_first && !cbp->cb_recurse) {
1315				(void) fprintf(stderr, gettext("cannot "
1316				    "rollback to '%s': more recent snapshots "
1317				    "exist\n"),
1318				    cbp->cb_target);
1319				(void) fprintf(stderr, gettext("use '-r' to "
1320				    "force deletion of the following "
1321				    "snapshots:\n"));
1322				cbp->cb_first = 0;
1323				cbp->cb_error = 1;
1324			}
1325
1326			if (cbp->cb_recurse) {
1327				cbp->cb_dependent = TRUE;
1328				(void) zfs_iter_dependents(zhp, rollback_check,
1329				    cbp);
1330				cbp->cb_dependent = FALSE;
1331			} else {
1332				(void) fprintf(stderr, "%s\n",
1333				    zfs_get_name(zhp));
1334			}
1335		}
1336	} else {
1337		if (cbp->cb_first && cbp->cb_recurse) {
1338			(void) fprintf(stderr, gettext("cannot rollback to "
1339			    "'%s': clones of previous snapshots exist\n"),
1340			    cbp->cb_target);
1341			(void) fprintf(stderr, gettext("use '-R' to "
1342			    "force deletion of the following clones and "
1343			    "dependents:\n"));
1344			cbp->cb_first = 0;
1345			cbp->cb_error = 1;
1346		}
1347
1348		(void) fprintf(stderr, "%s\n", zfs_get_name(zhp));
1349	}
1350
1351	zfs_close(zhp);
1352	return (0);
1353}
1354
1355static int
1356zfs_do_rollback(int argc, char **argv)
1357{
1358	int ret;
1359	int c;
1360	rollback_cbdata_t cb = { 0 };
1361	zfs_handle_t *zhp, *snap;
1362	char parentname[ZFS_MAXNAMELEN];
1363	char *delim;
1364	int force = 0;
1365
1366	/* check options */
1367	while ((c = getopt(argc, argv, "rfR")) != -1) {
1368		switch (c) {
1369		case 'f':
1370			force = 1;
1371			break;
1372		case 'r':
1373			cb.cb_recurse = 1;
1374			break;
1375		case 'R':
1376			cb.cb_recurse = 1;
1377			cb.cb_doclones = 1;
1378			break;
1379		case '?':
1380			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1381			    optopt);
1382			usage(FALSE);
1383		}
1384	}
1385
1386	argc -= optind;
1387	argv += optind;
1388
1389	/* check number of arguments */
1390	if (argc < 1) {
1391		(void) fprintf(stderr, gettext("missing dataset argument\n"));
1392		usage(FALSE);
1393	}
1394	if (argc > 1) {
1395		(void) fprintf(stderr, gettext("too many arguments\n"));
1396		usage(FALSE);
1397	}
1398
1399	/* open the snapshot */
1400	if ((snap = zfs_open(argv[0], ZFS_TYPE_SNAPSHOT)) == NULL)
1401		return (1);
1402
1403	/* open the parent dataset */
1404	(void) strlcpy(parentname, argv[0], sizeof (parentname));
1405	verify((delim = strrchr(parentname, '@')) != NULL);
1406	*delim = '\0';
1407	if ((zhp = zfs_open(parentname, ZFS_TYPE_ANY)) == NULL) {
1408		zfs_close(snap);
1409		return (1);
1410	}
1411
1412	/*
1413	 * Check for more recent snapshots and/or clones based on the presence
1414	 * of '-r' and '-R'.
1415	 */
1416	cb.cb_target = argv[0];
1417	cb.cb_create = zfs_prop_get_int(snap, ZFS_PROP_CREATETXG);
1418	cb.cb_first = 1;
1419	cb.cb_error = 0;
1420	(void) zfs_iter_children(zhp, rollback_check, &cb);
1421
1422	if ((ret = cb.cb_error) != 0)
1423		goto out;
1424
1425	/*
1426	 * Rollback parent to the given snapshot.
1427	 */
1428	ret = zfs_rollback(zhp, snap, force);
1429
1430out:
1431	zfs_close(snap);
1432	zfs_close(zhp);
1433
1434	if (ret == 0)
1435		return (0);
1436	else
1437		return (1);
1438}
1439
1440/*
1441 * zfs set property=value { fs | snap | vol } ...
1442 *
1443 * Sets the given property for all datasets specified on the command line.
1444 */
1445typedef struct set_cbdata {
1446	char		*cb_propname;
1447	char		*cb_value;
1448	zfs_prop_t	cb_prop;
1449} set_cbdata_t;
1450
1451static int
1452set_callback(zfs_handle_t *zhp, void *data)
1453{
1454	set_cbdata_t *cbp = data;
1455	int ret = 1;
1456
1457	/* don't allow setting of properties for snapshots */
1458	if (zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT) {
1459		(void) fprintf(stderr, gettext("cannot set %s property for "
1460		    "'%s': snapshot properties cannot be modified\n"),
1461		    cbp->cb_propname, zfs_get_name(zhp));
1462		return (1);
1463	}
1464
1465	/*
1466	 * If we're changing the volsize, make sure the value is appropriate,
1467	 * and set the reservation if this is a non-sparse volume.
1468	 */
1469	if (cbp->cb_prop == ZFS_PROP_VOLSIZE &&
1470	    zfs_get_type(zhp) == ZFS_TYPE_VOLUME) {
1471		uint64_t volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE);
1472		uint64_t avail = zfs_prop_get_int(zhp, ZFS_PROP_AVAILABLE);
1473		uint64_t reservation = zfs_prop_get_int(zhp,
1474		    ZFS_PROP_RESERVATION);
1475		uint64_t blocksize = zfs_prop_get_int(zhp,
1476		    ZFS_PROP_VOLBLOCKSIZE);
1477		uint64_t value;
1478
1479		verify(zfs_nicestrtonum(cbp->cb_value, &value) == 0);
1480
1481		if (value % blocksize != 0) {
1482			char buf[64];
1483
1484			zfs_nicenum(blocksize, buf, sizeof (buf));
1485			(void) fprintf(stderr, gettext("cannot set %s for "
1486			    "'%s': must be a multiple of volume block size "
1487			    "(%s)\n"), cbp->cb_propname, zfs_get_name(zhp),
1488			    buf);
1489			return (1);
1490		}
1491
1492		if (value == 0) {
1493			(void) fprintf(stderr, gettext("cannot set %s for "
1494			    "'%s': cannot be zero\n"), cbp->cb_propname,
1495			    zfs_get_name(zhp));
1496			return (1);
1497		}
1498
1499		if (volsize == reservation) {
1500			if (value > volsize && (value - volsize) > avail) {
1501				(void) fprintf(stderr, gettext("cannot set "
1502				    "%s property for '%s': volume size exceeds "
1503				    "amount of available space\n"),
1504				    cbp->cb_propname, zfs_get_name(zhp));
1505				return (1);
1506			}
1507
1508			if (zfs_prop_set(zhp, ZFS_PROP_RESERVATION,
1509			    cbp->cb_value) != 0) {
1510				(void) fprintf(stderr, gettext("volsize and "
1511				    "reservation must remain equal\n"));
1512				return (1);
1513			}
1514		}
1515	}
1516
1517	/*
1518	 * Do not allow the reservation to be set above the volume size. We do
1519	 * this here instead of inside libzfs because libzfs violates this rule
1520	 * internally.
1521	 */
1522	if (cbp->cb_prop == ZFS_PROP_RESERVATION &&
1523	    zfs_get_type(zhp) == ZFS_TYPE_VOLUME) {
1524		uint64_t value;
1525		uint64_t volsize;
1526
1527		volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE);
1528		if (strcmp(cbp->cb_value, "none") == 0)
1529			value = 0;
1530		else
1531			verify(zfs_nicestrtonum(cbp->cb_value, &value) == 0);
1532
1533		if (value > volsize) {
1534			(void) fprintf(stderr, gettext("cannot set %s "
1535			    "for '%s': size is greater than current "
1536			    "volume size\n"), cbp->cb_propname,
1537			    zfs_get_name(zhp));
1538			return (-1);
1539		}
1540	}
1541
1542	if (zfs_prop_set(zhp, cbp->cb_prop, cbp->cb_value) != 0)
1543		return (1);
1544
1545	ret = 0;
1546error:
1547	return (ret);
1548}
1549
1550static int
1551zfs_do_set(int argc, char **argv)
1552{
1553	set_cbdata_t cb;
1554
1555	/* check for options */
1556	if (argc > 1 && argv[1][0] == '-') {
1557		(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1558		    argv[1][1]);
1559		usage(FALSE);
1560	}
1561
1562	/* check number of arguments */
1563	if (argc < 2) {
1564		(void) fprintf(stderr, gettext("missing property=value "
1565		    "argument\n"));
1566		usage(FALSE);
1567	}
1568	if (argc < 3) {
1569		(void) fprintf(stderr, gettext("missing dataset name\n"));
1570		usage(FALSE);
1571	}
1572
1573	/* validate property=value argument */
1574	cb.cb_propname = argv[1];
1575	if ((cb.cb_value = strchr(cb.cb_propname, '=')) == NULL) {
1576		(void) fprintf(stderr, gettext("missing value in "
1577		    "property=value argument\n"));
1578		usage(FALSE);
1579	}
1580
1581	*cb.cb_value = '\0';
1582	cb.cb_value++;
1583
1584	if (*cb.cb_propname == '\0') {
1585		(void) fprintf(stderr,
1586		    gettext("missing property in property=value argument\n"));
1587		usage(FALSE);
1588	}
1589	if (*cb.cb_value == '\0') {
1590		(void) fprintf(stderr,
1591		    gettext("missing value in property=value argument\n"));
1592		usage(FALSE);
1593	}
1594
1595	/* get the property type */
1596	if ((cb.cb_prop = zfs_name_to_prop(cb.cb_propname)) ==
1597	    ZFS_PROP_INVAL) {
1598		(void) fprintf(stderr,
1599		    gettext("invalid property '%s'\n"), cb.cb_propname);
1600		usage(FALSE);
1601	}
1602
1603	/*
1604	 * Validate that the value is appropriate for this property.  We do this
1605	 * once now so we don't generate multiple errors each time we try to
1606	 * apply it to a dataset.
1607	 */
1608	if (zfs_prop_validate(cb.cb_prop, cb.cb_value, NULL) != 0)
1609		return (1);
1610
1611	return (zfs_for_each(argc - 2, argv + 2, FALSE,
1612	    ZFS_TYPE_ANY, set_callback, &cb));
1613}
1614
1615/*
1616 * zfs snapshot <fs@snap>
1617 *
1618 * Creates a snapshot with the given name.  While functionally equivalent to
1619 * 'zfs create', it is a separate command to diffferentiate intent.
1620 */
1621static int
1622zfs_do_snapshot(int argc, char **argv)
1623{
1624	/* check options */
1625	if (argc > 1 && argv[1][0] == '-') {
1626		(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1627		    argv[1][1]);
1628		usage(FALSE);
1629	}
1630
1631	/* check number of arguments */
1632	if (argc < 2) {
1633		(void) fprintf(stderr, gettext("missing snapshot argument\n"));
1634		usage(FALSE);
1635	}
1636	if (argc > 2) {
1637		(void) fprintf(stderr, gettext("too many arguments\n"));
1638		usage(FALSE);
1639	}
1640
1641	return (zfs_snapshot(argv[1]) != 0);
1642}
1643
1644/*
1645 * zfs backup [-i <fs@snap>] <fs@snap>
1646 *
1647 * Send a backup stream to stdout.
1648 */
1649static int
1650zfs_do_backup(int argc, char **argv)
1651{
1652	char *fromname = NULL;
1653	zfs_handle_t *zhp_from = NULL, *zhp_to;
1654	int c, err;
1655
1656	/* check options */
1657	while ((c = getopt(argc, argv, ":i:")) != -1) {
1658		switch (c) {
1659		case 'i':
1660			fromname = optarg;
1661			break;
1662		case ':':
1663			(void) fprintf(stderr, gettext("missing argument for "
1664			    "'%c' option\n"), optopt);
1665			usage(FALSE);
1666			break;
1667		case '?':
1668			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1669			    optopt);
1670			usage(FALSE);
1671		}
1672	}
1673
1674	argc -= optind;
1675	argv += optind;
1676
1677	/* check number of arguments */
1678	if (argc < 1) {
1679		(void) fprintf(stderr, gettext("missing snapshot argument\n"));
1680		usage(FALSE);
1681	}
1682	if (argc > 1) {
1683		(void) fprintf(stderr, gettext("too many arguments\n"));
1684		usage(FALSE);
1685	}
1686
1687	if (isatty(STDOUT_FILENO)) {
1688		(void) fprintf(stderr,
1689		    gettext("Error: Backup stream can not be written "
1690			    "to a terminal.\n"
1691			    "You must redirect standard output.\n"));
1692		return (1);
1693	}
1694
1695	if (fromname) {
1696		if ((zhp_from = zfs_open(fromname, ZFS_TYPE_SNAPSHOT)) == NULL)
1697			return (1);
1698	}
1699	if ((zhp_to = zfs_open(argv[0], ZFS_TYPE_SNAPSHOT)) == NULL)
1700		return (1);
1701
1702	err = zfs_backup(zhp_to, zhp_from);
1703
1704	if (zhp_from)
1705		zfs_close(zhp_from);
1706	zfs_close(zhp_to);
1707
1708	return (err != 0);
1709}
1710
1711/*
1712 * zfs restore <fs@snap>
1713 *
1714 * Restore a backup stream from stdin.
1715 */
1716static int
1717zfs_do_restore(int argc, char **argv)
1718{
1719	int c, err;
1720	int isprefix = FALSE;
1721	int dryrun = FALSE;
1722	int verbose = FALSE;
1723
1724	/* check options */
1725	while ((c = getopt(argc, argv, ":dnv")) != -1) {
1726		switch (c) {
1727		case 'd':
1728			isprefix = TRUE;
1729			break;
1730		case 'n':
1731			dryrun = TRUE;
1732			break;
1733		case 'v':
1734			verbose = TRUE;
1735			break;
1736		case ':':
1737			(void) fprintf(stderr, gettext("missing argument for "
1738			    "'%c' option\n"), optopt);
1739			usage(FALSE);
1740			break;
1741		case '?':
1742			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1743			    optopt);
1744			usage(FALSE);
1745		}
1746	}
1747
1748	argc -= optind;
1749	argv += optind;
1750
1751	/* check number of arguments */
1752	if (argc < 1) {
1753		(void) fprintf(stderr, gettext("missing snapshot argument\n"));
1754		usage(FALSE);
1755	}
1756	if (argc > 1) {
1757		(void) fprintf(stderr, gettext("too many arguments\n"));
1758		usage(FALSE);
1759	}
1760
1761	if (isatty(STDIN_FILENO)) {
1762		(void) fprintf(stderr,
1763		    gettext("Error: Backup stream can not be read "
1764			    "from a terminal.\n"
1765			    "You must redirect standard input.\n"));
1766		return (1);
1767	}
1768
1769	err = zfs_restore(argv[0], isprefix, verbose, dryrun);
1770	return (err != 0);
1771}
1772
1773
1774/*
1775 * Generic callback for sharing or mounting filesystems.  Because the code is so
1776 * similar, we have a common function with an extra parameter to determine which
1777 * mode we are using.
1778 */
1779#define	OP_SHARE	0x1
1780#define	OP_MOUNT	0x2
1781
1782typedef struct share_mount_cbdata {
1783	int	cb_type;
1784	int	cb_explicit;
1785	int	cb_flags;
1786	const char *cb_options;
1787} share_mount_cbdata_t;
1788
1789/*
1790 * Share or mount the filesystem.
1791 */
1792static int
1793share_mount_callback(zfs_handle_t *zhp, void *data)
1794{
1795	char mountpoint[ZFS_MAXPROPLEN];
1796	char shareopts[ZFS_MAXPROPLEN];
1797	share_mount_cbdata_t *cbp = data;
1798	const char *cmdname = cbp->cb_type == OP_SHARE ? "share" : "mount";
1799	struct mnttab mnt;
1800	uint64_t zoned;
1801
1802	if (cbp->cb_options == NULL)
1803		mnt.mnt_mntopts = "";
1804	else
1805		mnt.mnt_mntopts = (char *)cbp->cb_options;
1806
1807	/*
1808	 * Check to make sure we can mount/share this dataset.  If we are in the
1809	 * global zone and the filesystem is exported to a local zone, or if we
1810	 * are in a local zone and the filesystem is not exported, then it is an
1811	 * error.
1812	 */
1813	zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED);
1814
1815	if (zoned && getzoneid() == GLOBAL_ZONEID) {
1816		if (!cbp->cb_explicit)
1817			return (0);
1818
1819		(void) fprintf(stderr, gettext("cannot %s '%s': dataset is "
1820		    "exported to a local zone\n"), cmdname, zfs_get_name(zhp));
1821		return (1);
1822
1823	} else if (!zoned && getzoneid() != GLOBAL_ZONEID) {
1824		if (!cbp->cb_explicit)
1825			return (0);
1826
1827		(void) fprintf(stderr, gettext("cannot %s '%s': permission "
1828		    "denied\n"), cmdname, zfs_get_name(zhp));
1829		return (1);
1830	}
1831
1832	/*
1833	 * Inore any filesystems which don't apply to us.  This includes those
1834	 * with a legacy mountpoint, or those with legacy share options.
1835	 */
1836	verify(zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint,
1837	    sizeof (mountpoint), NULL, NULL, 0, FALSE) == 0);
1838	verify(zfs_prop_get(zhp, ZFS_PROP_SHARENFS, shareopts,
1839	    sizeof (shareopts), NULL, NULL, 0, FALSE) == 0);
1840
1841	if (cbp->cb_type == OP_SHARE) {
1842		if (strcmp(shareopts, "off") == 0) {
1843			if (!cbp->cb_explicit)
1844				return (0);
1845
1846			(void) fprintf(stderr, gettext("cannot share '%s': "
1847			    "legacy share\n"), zfs_get_name(zhp));
1848			(void) fprintf(stderr, gettext("use share(1M) to "
1849			    "share this filesystem\n"));
1850			return (1);
1851		}
1852	}
1853
1854	/*
1855	 * We cannot share or mount legacy filesystems.  If the shareopts is
1856	 * non-legacy but the mountpoint is legacy, we treat it as a legacy
1857	 * share.
1858	 */
1859	if (strcmp(mountpoint, "legacy") == 0) {
1860		if (!cbp->cb_explicit)
1861			return (0);
1862
1863		(void) fprintf(stderr, gettext("cannot %s '%s': "
1864		    "legacy mountpoint\n"), cmdname, zfs_get_name(zhp));
1865		(void) fprintf(stderr, gettext("use %s to "
1866		    "%s this filesystem\n"), cbp->cb_type == OP_SHARE ?
1867		    "share(1M)" : "mount(1M)", cmdname);
1868		return (1);
1869	}
1870
1871	if (strcmp(mountpoint, "none") == 0) {
1872		if (!cbp->cb_explicit)
1873			return (0);
1874
1875		(void) fprintf(stderr, gettext("cannot %s '%s': no "
1876		    "mountpoint set\n"), cmdname, zfs_get_name(zhp));
1877		return (1);
1878	}
1879
1880	/*
1881	 * At this point, we have verified that the mountpoint and/or shareopts
1882	 * are appropriate for auto management.  Determine if the filesystem is
1883	 * currently mounted or shared, and abort if this is an explicit
1884	 * request.
1885	 */
1886	switch (cbp->cb_type) {
1887	case OP_SHARE:
1888		if (zfs_is_shared(zhp, NULL)) {
1889			if (cbp->cb_explicit) {
1890				(void) fprintf(stderr, gettext("cannot share "
1891				    "'%s': filesystem already shared\n"),
1892				    zfs_get_name(zhp));
1893				return (1);
1894			} else {
1895				return (0);
1896			}
1897		}
1898		break;
1899
1900	case OP_MOUNT:
1901		if (!hasmntopt(&mnt, MNTOPT_REMOUNT) &&
1902		    zfs_is_mounted(zhp, NULL)) {
1903			if (cbp->cb_explicit) {
1904				(void) fprintf(stderr, gettext("cannot mount "
1905				    "'%s': filesystem already mounted\n"),
1906				    zfs_get_name(zhp));
1907				return (1);
1908			} else {
1909				return (0);
1910			}
1911		}
1912		break;
1913	}
1914
1915	/*
1916	 * Mount and optionally share the filesystem.
1917	 */
1918	switch (cbp->cb_type) {
1919	case OP_SHARE:
1920		{
1921			if (!zfs_is_mounted(zhp, NULL) &&
1922			    zfs_mount(zhp, NULL, 0) != 0)
1923				return (1);
1924
1925			if (zfs_share(zhp) != 0)
1926				return (1);
1927		}
1928		break;
1929
1930	case OP_MOUNT:
1931		if (zfs_mount(zhp, cbp->cb_options, cbp->cb_flags) != 0)
1932			return (1);
1933		break;
1934	}
1935
1936	return (0);
1937}
1938
1939static int
1940share_or_mount(int type, int argc, char **argv)
1941{
1942	int do_all = 0;
1943	int c, ret;
1944	share_mount_cbdata_t cb = { 0 };
1945
1946	cb.cb_type = type;
1947
1948	/* check options */
1949	while ((c = getopt(argc, argv, type == OP_MOUNT ? ":ao:O" : "a"))
1950	    != -1) {
1951		switch (c) {
1952		case 'a':
1953			do_all = 1;
1954			break;
1955		case 'o':
1956			cb.cb_options = optarg;
1957			break;
1958		case 'O':
1959			cb.cb_flags |= MS_OVERLAY;
1960			break;
1961		case ':':
1962			(void) fprintf(stderr, gettext("missing argument for "
1963			    "'%c' option\n"), optopt);
1964			usage(FALSE);
1965			break;
1966		case '?':
1967			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1968			    optopt);
1969			usage(FALSE);
1970		}
1971	}
1972
1973	argc -= optind;
1974	argv += optind;
1975
1976	/* check number of arguments */
1977	if (do_all) {
1978		if (argc != 0) {
1979			(void) fprintf(stderr, gettext("too many arguments\n"));
1980			usage(FALSE);
1981		}
1982
1983		ret = zfs_for_each(argc, argv, TRUE,
1984		    ZFS_TYPE_FILESYSTEM, share_mount_callback, &cb);
1985	} else if (argc == 0) {
1986		struct mnttab entry;
1987
1988		if (type == OP_SHARE) {
1989			(void) fprintf(stderr, gettext("missing filesystem "
1990			    "argument\n"));
1991			usage(FALSE);
1992		}
1993
1994		/*
1995		 * When mount is given no arguments, go through /etc/mnttab and
1996		 * display any active ZFS mounts.  We hide any snapshots, since
1997		 * they are controlled automatically.
1998		 */
1999		rewind(mnttab_file);
2000		while (getmntent(mnttab_file, &entry) == 0) {
2001			if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0 ||
2002			    strchr(entry.mnt_special, '@') != NULL)
2003				continue;
2004
2005			(void) printf("%-30s  %s\n", entry.mnt_special,
2006			    entry.mnt_mountp);
2007		}
2008
2009		ret = 0;
2010	} else {
2011		zfs_handle_t *zhp;
2012
2013		if (argc > 1) {
2014			(void) fprintf(stderr,
2015			    gettext("too many arguments\n"));
2016			usage(FALSE);
2017		}
2018
2019		if ((zhp = zfs_open(argv[0], ZFS_TYPE_FILESYSTEM)) == NULL)
2020			ret = 1;
2021		else {
2022			cb.cb_explicit = TRUE;
2023			ret = share_mount_callback(zhp, &cb);
2024			zfs_close(zhp);
2025		}
2026	}
2027
2028	return (ret);
2029}
2030
2031/*
2032 * zfs mount -a
2033 * zfs mount filesystem
2034 *
2035 * Mount all filesystems, or mount the given filesystem.
2036 */
2037static int
2038zfs_do_mount(int argc, char **argv)
2039{
2040	return (share_or_mount(OP_MOUNT, argc, argv));
2041}
2042
2043/*
2044 * zfs share -a
2045 * zfs share filesystem
2046 *
2047 * Share all filesystems, or share the given filesystem.
2048 */
2049static int
2050zfs_do_share(int argc, char **argv)
2051{
2052	return (share_or_mount(OP_SHARE, argc, argv));
2053}
2054
2055typedef struct unshare_unmount_node {
2056	zfs_handle_t	*un_zhp;
2057	char		*un_mountp;
2058	uu_avl_node_t	un_avlnode;
2059} unshare_unmount_node_t;
2060
2061/* ARGSUSED */
2062static int
2063unshare_unmount_compare(const void *larg, const void *rarg, void *unused)
2064{
2065	const unshare_unmount_node_t *l = larg;
2066	const unshare_unmount_node_t *r = rarg;
2067
2068	return (strcmp(l->un_mountp, r->un_mountp));
2069}
2070
2071/*
2072 * Convenience routine used by zfs_do_umount() and manual_unmount().  Given an
2073 * absolute path, find the entry /etc/mnttab, verify that its a ZFS filesystem,
2074 * and unmount it appropriately.
2075 */
2076static int
2077unshare_unmount_path(int type, char *path, int flags, int is_manual)
2078{
2079	zfs_handle_t *zhp;
2080	int ret;
2081	struct stat64 statbuf;
2082	struct extmnttab entry;
2083	const char *cmdname = (type == OP_SHARE) ? "unshare" : "unmount";
2084	char property[ZFS_MAXPROPLEN];
2085
2086	/*
2087	 * Search for the path in /etc/mnttab.  Rather than looking for the
2088	 * specific path, which can be fooled by non-standard paths (i.e. ".."
2089	 * or "//"), we stat() the path and search for the corresponding
2090	 * (major,minor) device pair.
2091	 */
2092	if (stat64(path, &statbuf) != 0) {
2093		(void) fprintf(stderr, gettext("cannot %s '%s': %s\n"),
2094		    cmdname, path, strerror(errno));
2095		return (1);
2096	}
2097
2098	/*
2099	 * Search for the given (major,minor) pair in the mount table.
2100	 */
2101	rewind(mnttab_file);
2102	while ((ret = getextmntent(mnttab_file, &entry, 0)) == 0) {
2103		if (entry.mnt_major == major(statbuf.st_dev) &&
2104		    entry.mnt_minor == minor(statbuf.st_dev))
2105			break;
2106	}
2107	if (ret != 0) {
2108		(void) fprintf(stderr, gettext("cannot %s '%s': not "
2109		    "currently mounted\n"), cmdname, path);
2110		return (1);
2111	}
2112
2113	if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0) {
2114		(void) fprintf(stderr, gettext("cannot %s '%s': not a ZFS "
2115		    "filesystem\n"), cmdname, path);
2116		return (1);
2117	}
2118
2119	if ((zhp = zfs_open(entry.mnt_special, ZFS_TYPE_FILESYSTEM)) == NULL)
2120		return (1);
2121
2122	verify(zfs_prop_get(zhp, type == OP_SHARE ?
2123		ZFS_PROP_SHARENFS : ZFS_PROP_MOUNTPOINT, property,
2124		sizeof (property), NULL, NULL, 0, FALSE) == 0);
2125
2126	if (type == OP_SHARE) {
2127		if (strcmp(property, "off") == 0) {
2128			(void) fprintf(stderr, gettext("cannot unshare "
2129			    "'%s': legacy share\n"), path);
2130			(void) fprintf(stderr, gettext("use "
2131			    "unshare(1M) to unshare this filesystem\n"));
2132			ret = 1;
2133		} else if (!zfs_is_shared(zhp, NULL)) {
2134			(void) fprintf(stderr, gettext("cannot unshare '%s': "
2135			    "not currently shared\n"), path);
2136			ret = 1;
2137		} else {
2138			ret = zfs_unshareall(zhp);
2139		}
2140	} else {
2141		if (is_manual) {
2142			ret = zfs_unmount(zhp, NULL, flags);
2143		} else if (strcmp(property, "legacy") == 0) {
2144			(void) fprintf(stderr, gettext("cannot unmount "
2145			    "'%s': legacy mountpoint\n"),
2146			    zfs_get_name(zhp));
2147			(void) fprintf(stderr, gettext("use umount(1M) "
2148			    "to unmount this filesystem\n"));
2149			ret = 1;
2150		} else {
2151			ret = zfs_unmountall(zhp, flags);
2152		}
2153	}
2154
2155	zfs_close(zhp);
2156
2157	return (ret != 0);
2158}
2159
2160/*
2161 * Generic callback for unsharing or unmounting a filesystem.
2162 */
2163static int
2164unshare_unmount(int type, int argc, char **argv)
2165{
2166	int do_all = 0;
2167	int flags = 0;
2168	int ret = 0;
2169	int c;
2170	zfs_handle_t *zhp;
2171	char property[ZFS_MAXPROPLEN];
2172
2173	/* check options */
2174	while ((c = getopt(argc, argv, type == OP_SHARE ? "a" : "af")) != -1) {
2175		switch (c) {
2176		case 'a':
2177			do_all = 1;
2178			break;
2179		case 'f':
2180			flags = MS_FORCE;
2181			break;
2182		case '?':
2183			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2184			    optopt);
2185			usage(FALSE);
2186		}
2187	}
2188
2189	argc -= optind;
2190	argv += optind;
2191
2192	/* ensure correct number of arguments */
2193	if (do_all) {
2194		if (argc != 0) {
2195			(void) fprintf(stderr, gettext("too many arguments\n"));
2196			usage(FALSE);
2197		}
2198	} else if (argc != 1) {
2199		if (argc == 0)
2200			(void) fprintf(stderr,
2201			    gettext("missing filesystem argument\n"));
2202		else
2203			(void) fprintf(stderr,
2204			    gettext("too many arguments\n"));
2205		usage(FALSE);
2206	}
2207
2208	if (do_all) {
2209		/*
2210		 * We could make use of zfs_for_each() to walk all datasets in
2211		 * the system, but this would be very inefficient, especially
2212		 * since we would have to linearly search /etc/mnttab for each
2213		 * one.  Instead, do one pass through /etc/mnttab looking for
2214		 * zfs entries and call zfs_unmount() for each one.
2215		 *
2216		 * Things get a little tricky if the administrator has created
2217		 * mountpoints beneath other ZFS filesystems.  In this case, we
2218		 * have to unmount the deepest filesystems first.  To accomplish
2219		 * this, we place all the mountpoints in an AVL tree sorted by
2220		 * the special type (dataset name), and walk the result in
2221		 * reverse to make sure to get any snapshots first.
2222		 */
2223		struct mnttab entry;
2224		uu_avl_pool_t *pool;
2225		uu_avl_t *tree;
2226		unshare_unmount_node_t *node;
2227		uu_avl_index_t idx;
2228		uu_avl_walk_t *walk;
2229
2230		if ((pool = uu_avl_pool_create("unmount_pool",
2231		    sizeof (unshare_unmount_node_t),
2232		    offsetof(unshare_unmount_node_t, un_avlnode),
2233		    unshare_unmount_compare,
2234		    UU_DEFAULT)) == NULL) {
2235			(void) fprintf(stderr, gettext("internal error: "
2236			    "out of memory\n"));
2237			exit(1);
2238		}
2239
2240		if ((tree = uu_avl_create(pool, NULL, UU_DEFAULT)) == NULL) {
2241			(void) fprintf(stderr, gettext("internal error: "
2242			    "out of memory\n"));
2243			exit(1);
2244		}
2245
2246		rewind(mnttab_file);
2247		while (getmntent(mnttab_file, &entry) == 0) {
2248
2249			/* ignore non-ZFS entries */
2250			if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0)
2251				continue;
2252
2253			/* ignore snapshots */
2254			if (strchr(entry.mnt_special, '@') != NULL)
2255				continue;
2256
2257			if ((zhp = zfs_open(entry.mnt_special,
2258			    ZFS_TYPE_FILESYSTEM)) == NULL) {
2259				ret = 1;
2260				continue;
2261			}
2262
2263			verify(zfs_prop_get(zhp, type == OP_SHARE ?
2264			    ZFS_PROP_SHARENFS : ZFS_PROP_MOUNTPOINT,
2265			    property, sizeof (property), NULL, NULL,
2266			    0, FALSE) == 0);
2267
2268			/* Ignore legacy mounts and shares */
2269			if ((type == OP_SHARE &&
2270			    strcmp(property, "off") == 0) ||
2271			    (type == OP_MOUNT &&
2272			    strcmp(property, "legacy") == 0)) {
2273				zfs_close(zhp);
2274				continue;
2275			}
2276
2277			node = safe_malloc(sizeof (unshare_unmount_node_t));
2278			node->un_zhp = zhp;
2279
2280			if ((node->un_mountp = strdup(entry.mnt_mountp)) ==
2281			    NULL) {
2282				(void) fprintf(stderr, gettext("internal error:"
2283				    " out of memory\n"));
2284				exit(1);
2285			}
2286
2287			uu_avl_node_init(node, &node->un_avlnode, pool);
2288
2289			if (uu_avl_find(tree, node, NULL, &idx) == NULL) {
2290				uu_avl_insert(tree, node, idx);
2291			} else {
2292				zfs_close(node->un_zhp);
2293				free(node->un_mountp);
2294				free(node);
2295			}
2296		}
2297
2298		/*
2299		 * Walk the AVL tree in reverse, unmounting each filesystem and
2300		 * removing it from the AVL tree in the process.
2301		 */
2302		if ((walk = uu_avl_walk_start(tree,
2303		    UU_WALK_REVERSE | UU_WALK_ROBUST)) == NULL) {
2304			(void) fprintf(stderr,
2305			    gettext("internal error: out of memory"));
2306			exit(1);
2307		}
2308
2309		while ((node = uu_avl_walk_next(walk)) != NULL) {
2310			uu_avl_remove(tree, node);
2311
2312			switch (type) {
2313			case OP_SHARE:
2314				if (zfs_unshare(node->un_zhp,
2315				    node->un_mountp) != 0)
2316					ret = 1;
2317				break;
2318
2319			case OP_MOUNT:
2320				if (zfs_unmount(node->un_zhp,
2321				    node->un_mountp, flags) != 0)
2322					ret = 1;
2323				break;
2324			}
2325
2326			zfs_close(node->un_zhp);
2327			free(node->un_mountp);
2328			free(node);
2329		}
2330
2331		uu_avl_walk_end(walk);
2332		uu_avl_destroy(tree);
2333		uu_avl_pool_destroy(pool);
2334	} else {
2335		/*
2336		 * We have an argument, but it may be a full path or a ZFS
2337		 * filesystem.  Pass full paths off to unmount_path() (shared by
2338		 * manual_unmount), otherwise open the filesystem and pass to
2339		 * zfs_unmount().
2340		 */
2341		if (argv[0][0] == '/')
2342			return (unshare_unmount_path(type, argv[0],
2343				flags, FALSE));
2344
2345		if ((zhp = zfs_open(argv[0], ZFS_TYPE_FILESYSTEM)) == NULL)
2346			return (1);
2347
2348		verify(zfs_prop_get(zhp, type == OP_SHARE ?
2349		    ZFS_PROP_SHARENFS : ZFS_PROP_MOUNTPOINT, property,
2350		    sizeof (property), NULL, NULL, 0, FALSE) == 0);
2351
2352		switch (type) {
2353		case OP_SHARE:
2354			if (strcmp(property, "off") == 0) {
2355				(void) fprintf(stderr, gettext("cannot unshare "
2356				    "'%s': legacy share\n"), zfs_get_name(zhp));
2357				(void) fprintf(stderr, gettext("use unshare(1M)"
2358				    " to unshare this filesystem\n"));
2359				ret = 1;
2360			} else if (!zfs_is_shared(zhp, NULL)) {
2361				(void) fprintf(stderr, gettext("cannot unshare "
2362				    "'%s': not currently shared\n"),
2363				    zfs_get_name(zhp));
2364				ret = 1;
2365			} else if (zfs_unshareall(zhp) != 0) {
2366				ret = 1;
2367			}
2368			break;
2369
2370		case OP_MOUNT:
2371			if (strcmp(property, "legacy") == 0) {
2372				(void) fprintf(stderr, gettext("cannot unmount "
2373				    "'%s': legacy mountpoint\n"),
2374				    zfs_get_name(zhp));
2375				(void) fprintf(stderr, gettext("use umount(1M) "
2376				    "to unmount this filesystem\n"));
2377				ret = 1;
2378			} else if (!zfs_is_mounted(zhp, NULL)) {
2379				(void) fprintf(stderr, gettext("cannot unmount "
2380				    "'%s': not currently mounted\n"),
2381				    zfs_get_name(zhp));
2382				ret = 1;
2383			} else if (zfs_unmountall(zhp, flags) != 0) {
2384				ret = 1;
2385			}
2386		}
2387
2388		zfs_close(zhp);
2389	}
2390
2391	return (ret);
2392}
2393
2394/*
2395 * zfs unmount -a
2396 * zfs unmount filesystem
2397 *
2398 * Unmount all filesystems, or a specific ZFS filesystem.
2399 */
2400static int
2401zfs_do_unmount(int argc, char **argv)
2402{
2403	return (unshare_unmount(OP_MOUNT, argc, argv));
2404}
2405
2406/*
2407 * zfs unshare -a
2408 * zfs unshare filesystem
2409 *
2410 * Unshare all filesystems, or a specific ZFS filesystem.
2411 */
2412static int
2413zfs_do_unshare(int argc, char **argv)
2414{
2415	return (unshare_unmount(OP_SHARE, argc, argv));
2416}
2417
2418/*
2419 * Called when invoked as /etc/fs/zfs/mount.  Do the mount if the mountpoint is
2420 * 'legacy'.  Otherwise, complain that use should be using 'zfs mount'.
2421 */
2422static int
2423manual_mount(int argc, char **argv)
2424{
2425	zfs_handle_t *zhp;
2426	char mountpoint[ZFS_MAXPROPLEN];
2427	char mntopts[MNT_LINE_MAX] = { '\0' };
2428	int ret;
2429	int c;
2430	int flags = 0;
2431	char *dataset, *path;
2432
2433	/* check options */
2434	while ((c = getopt(argc, argv, ":o:O")) != -1) {
2435		switch (c) {
2436		case 'o':
2437			(void) strlcpy(mntopts, optarg, sizeof (mntopts));
2438			break;
2439		case 'O':
2440			flags |= MS_OVERLAY;
2441			break;
2442		case ':':
2443			(void) fprintf(stderr, gettext("missing argument for "
2444			    "'%c' option\n"), optopt);
2445			usage(FALSE);
2446			break;
2447		case '?':
2448			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2449			    optopt);
2450			(void) fprintf(stderr, gettext("usage: mount [-o opts] "
2451			    "<path>\n"));
2452			return (2);
2453		}
2454	}
2455
2456	argc -= optind;
2457	argv += optind;
2458
2459	/* check that we only have two arguments */
2460	if (argc != 2) {
2461		if (argc == 0)
2462			(void) fprintf(stderr, gettext("missing dataset "
2463			    "argument\n"));
2464		else if (argc == 1)
2465			(void) fprintf(stderr,
2466			    gettext("missing mountpoint argument\n"));
2467		else
2468			(void) fprintf(stderr, gettext("too many arguments\n"));
2469		(void) fprintf(stderr, "usage: mount <dataset> <mountpoint>\n");
2470		return (2);
2471	}
2472
2473	dataset = argv[0];
2474	path = argv[1];
2475
2476	/* try to open the dataset */
2477	if ((zhp = zfs_open(dataset, ZFS_TYPE_FILESYSTEM)) == NULL)
2478		return (1);
2479
2480	(void) zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint,
2481	    sizeof (mountpoint), NULL, NULL, 0, FALSE);
2482
2483	/* check for legacy mountpoint and complain appropriately */
2484	ret = 0;
2485	if (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0) {
2486		if (mount(dataset, path, MS_OPTIONSTR | flags, MNTTYPE_ZFS,
2487		    NULL, 0, mntopts, sizeof (mntopts)) != 0) {
2488			(void) fprintf(stderr, gettext("mount failed: %s\n"),
2489			    strerror(errno));
2490			ret = 1;
2491		}
2492	} else {
2493		(void) fprintf(stderr, gettext("filesystem '%s' cannot be "
2494		    "mounted using 'mount -F zfs'\n"), dataset);
2495		(void) fprintf(stderr, gettext("Use 'zfs set mountpoint=%s' "
2496		    "instead.\n"), path);
2497		(void) fprintf(stderr, gettext("If you must use 'mount -F zfs' "
2498		    "or /etc/vfstab, use 'zfs set mountpoint=legacy'.\n"));
2499		(void) fprintf(stderr, gettext("See zfs(1M) for more "
2500		    "information.\n"));
2501		ret = 1;
2502	}
2503
2504	return (ret);
2505}
2506
2507/*
2508 * Called when invoked as /etc/fs/zfs/umount.  Unlike a manual mount, we allow
2509 * unmounts of non-legacy filesystems, as this is the dominant administrative
2510 * interface.
2511 */
2512static int
2513manual_unmount(int argc, char **argv)
2514{
2515	int flags = 0;
2516	int c;
2517
2518	/* check options */
2519	while ((c = getopt(argc, argv, "f")) != -1) {
2520		switch (c) {
2521		case 'f':
2522			flags = MS_FORCE;
2523			break;
2524		case '?':
2525			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2526			    optopt);
2527			(void) fprintf(stderr, gettext("usage: unmount [-f] "
2528			    "<path>\n"));
2529			return (2);
2530		}
2531	}
2532
2533	argc -= optind;
2534	argv += optind;
2535
2536	/* check arguments */
2537	if (argc != 1) {
2538		if (argc == 0)
2539			(void) fprintf(stderr, gettext("missing path "
2540			    "argument\n"));
2541		else
2542			(void) fprintf(stderr, gettext("too many arguments\n"));
2543		(void) fprintf(stderr, gettext("usage: unmount [-f] <path>\n"));
2544		return (2);
2545	}
2546
2547	return (unshare_unmount_path(OP_MOUNT, argv[0], flags, TRUE));
2548}
2549
2550static int
2551volcheck(zpool_handle_t *zhp, void *data)
2552{
2553	int isinit = (int)data;
2554
2555	if (isinit)
2556		return (zpool_create_zvol_links(zhp));
2557	else
2558		return (zpool_remove_zvol_links(zhp));
2559}
2560
2561/*
2562 * Iterate over all pools in the system and either create or destroy /dev/zvol
2563 * links, depending on the value of 'isinit'.
2564 */
2565static int
2566do_volcheck(int isinit)
2567{
2568	return (zpool_iter(volcheck, (void *)isinit) ? 1 : 0);
2569}
2570
2571int
2572main(int argc, char **argv)
2573{
2574	int ret;
2575	int i;
2576	char *progname;
2577	char *cmdname;
2578
2579	(void) setlocale(LC_ALL, "");
2580	(void) textdomain(TEXT_DOMAIN);
2581
2582	opterr = 0;
2583
2584	if ((mnttab_file = fopen(MNTTAB, "r")) == NULL) {
2585		(void) fprintf(stderr, gettext("internal error: unable to "
2586		    "open %s\n"), MNTTAB);
2587		return (1);
2588	}
2589
2590	/*
2591	 * This command also doubles as the /etc/fs mount and unmount program.
2592	 * Determine if we should take this behavior based on argv[0].
2593	 */
2594	progname = basename(argv[0]);
2595	if (strcmp(progname, "mount") == 0) {
2596		ret = manual_mount(argc, argv);
2597	} else if (strcmp(progname, "umount") == 0) {
2598		ret = manual_unmount(argc, argv);
2599	} else {
2600		/*
2601		 * Make sure the user has specified some command.
2602		 */
2603		if (argc < 2) {
2604			(void) fprintf(stderr, gettext("missing command\n"));
2605			usage(FALSE);
2606		}
2607
2608		cmdname = argv[1];
2609
2610		/*
2611		 * The 'umount' command is an alias for 'unmount'
2612		 */
2613		if (strcmp(cmdname, "umount") == 0)
2614			cmdname = "unmount";
2615
2616		/*
2617		 * Special case '-?'
2618		 */
2619		if (strcmp(cmdname, "-?") == 0)
2620			usage(TRUE);
2621
2622		/*
2623		 * 'volinit' and 'volfini' do not appear in the usage message,
2624		 * so we have to special case them here.
2625		 */
2626		if (strcmp(cmdname, "volinit") == 0)
2627			return (do_volcheck(TRUE));
2628		else if (strcmp(cmdname, "volfini") == 0)
2629			return (do_volcheck(FALSE));
2630
2631		/*
2632		 * Run the appropriate command.
2633		 */
2634		for (i = 0; i < NCOMMAND; i++) {
2635			if (command_table[i].name == NULL)
2636				continue;
2637
2638			if (strcmp(cmdname, command_table[i].name) == 0) {
2639				current_command = &command_table[i];
2640				ret = command_table[i].func(argc - 1, argv + 1);
2641				break;
2642			}
2643		}
2644
2645		if (i == NCOMMAND) {
2646			(void) fprintf(stderr, gettext("unrecognized "
2647			    "command '%s'\n"), cmdname);
2648			usage(FALSE);
2649		}
2650	}
2651
2652	(void) fclose(mnttab_file);
2653
2654	/*
2655	 * The 'ZFS_ABORT' environment variable causes us to dump core on exit
2656	 * for the purposes of running ::findleaks.
2657	 */
2658	if (getenv("ZFS_ABORT") != NULL) {
2659		(void) printf("dumping core by request\n");
2660		abort();
2661	}
2662
2663	return (ret);
2664}
2665