xref: /illumos-gate/usr/src/lib/libbe/common/be_mount.c (revision f169c0ea)
1*f169c0eaSGlenn Lagasse /*
2*f169c0eaSGlenn Lagasse  * CDDL HEADER START
3*f169c0eaSGlenn Lagasse  *
4*f169c0eaSGlenn Lagasse  * The contents of this file are subject to the terms of the
5*f169c0eaSGlenn Lagasse  * Common Development and Distribution License (the "License").
6*f169c0eaSGlenn Lagasse  * You may not use this file except in compliance with the License.
7*f169c0eaSGlenn Lagasse  *
8*f169c0eaSGlenn Lagasse  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*f169c0eaSGlenn Lagasse  * or http://www.opensolaris.org/os/licensing.
10*f169c0eaSGlenn Lagasse  * See the License for the specific language governing permissions
11*f169c0eaSGlenn Lagasse  * and limitations under the License.
12*f169c0eaSGlenn Lagasse  *
13*f169c0eaSGlenn Lagasse  * When distributing Covered Code, include this CDDL HEADER in each
14*f169c0eaSGlenn Lagasse  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*f169c0eaSGlenn Lagasse  * If applicable, add the following below this CDDL HEADER, with the
16*f169c0eaSGlenn Lagasse  * fields enclosed by brackets "[]" replaced with your own identifying
17*f169c0eaSGlenn Lagasse  * information: Portions Copyright [yyyy] [name of copyright owner]
18*f169c0eaSGlenn Lagasse  *
19*f169c0eaSGlenn Lagasse  * CDDL HEADER END
20*f169c0eaSGlenn Lagasse  */
21*f169c0eaSGlenn Lagasse 
22*f169c0eaSGlenn Lagasse /*
23*f169c0eaSGlenn Lagasse  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24*f169c0eaSGlenn Lagasse  */
25*f169c0eaSGlenn Lagasse 
26*f169c0eaSGlenn Lagasse /*
27*f169c0eaSGlenn Lagasse  * System includes
28*f169c0eaSGlenn Lagasse  */
29*f169c0eaSGlenn Lagasse #include <assert.h>
30*f169c0eaSGlenn Lagasse #include <errno.h>
31*f169c0eaSGlenn Lagasse #include <libintl.h>
32*f169c0eaSGlenn Lagasse #include <libnvpair.h>
33*f169c0eaSGlenn Lagasse #include <libzfs.h>
34*f169c0eaSGlenn Lagasse #include <stdio.h>
35*f169c0eaSGlenn Lagasse #include <stdlib.h>
36*f169c0eaSGlenn Lagasse #include <string.h>
37*f169c0eaSGlenn Lagasse #include <sys/mntent.h>
38*f169c0eaSGlenn Lagasse #include <sys/mnttab.h>
39*f169c0eaSGlenn Lagasse #include <sys/mount.h>
40*f169c0eaSGlenn Lagasse #include <sys/stat.h>
41*f169c0eaSGlenn Lagasse #include <sys/types.h>
42*f169c0eaSGlenn Lagasse #include <sys/vfstab.h>
43*f169c0eaSGlenn Lagasse #include <sys/zone.h>
44*f169c0eaSGlenn Lagasse #include <sys/mkdev.h>
45*f169c0eaSGlenn Lagasse #include <unistd.h>
46*f169c0eaSGlenn Lagasse 
47*f169c0eaSGlenn Lagasse #include <libbe.h>
48*f169c0eaSGlenn Lagasse #include <libbe_priv.h>
49*f169c0eaSGlenn Lagasse 
50*f169c0eaSGlenn Lagasse #define	BE_TMP_MNTPNT		"/tmp/.be.XXXXXX"
51*f169c0eaSGlenn Lagasse 
52*f169c0eaSGlenn Lagasse typedef struct dir_data {
53*f169c0eaSGlenn Lagasse 	char *dir;
54*f169c0eaSGlenn Lagasse 	char *ds;
55*f169c0eaSGlenn Lagasse } dir_data_t;
56*f169c0eaSGlenn Lagasse 
57*f169c0eaSGlenn Lagasse /* Private function prototypes */
58*f169c0eaSGlenn Lagasse static int be_mount_callback(zfs_handle_t *, void *);
59*f169c0eaSGlenn Lagasse static int be_unmount_callback(zfs_handle_t *, void *);
60*f169c0eaSGlenn Lagasse static int be_get_legacy_fs_callback(zfs_handle_t *, void *);
61*f169c0eaSGlenn Lagasse static int fix_mountpoint(zfs_handle_t *);
62*f169c0eaSGlenn Lagasse static int fix_mountpoint_callback(zfs_handle_t *, void *);
63*f169c0eaSGlenn Lagasse static int get_mountpoint_from_vfstab(char *, const char *, char *, size_t,
64*f169c0eaSGlenn Lagasse     boolean_t);
65*f169c0eaSGlenn Lagasse static int loopback_mount_shared_fs(zfs_handle_t *, be_mount_data_t *);
66*f169c0eaSGlenn Lagasse static int loopback_mount_zonepath(const char *, be_mount_data_t *);
67*f169c0eaSGlenn Lagasse static int iter_shared_fs_callback(zfs_handle_t *, void *);
68*f169c0eaSGlenn Lagasse static int zpool_shared_fs_callback(zpool_handle_t *, void *);
69*f169c0eaSGlenn Lagasse static int unmount_shared_fs(be_unmount_data_t *);
70*f169c0eaSGlenn Lagasse static int add_to_fs_list(be_fs_list_data_t *, const char *);
71*f169c0eaSGlenn Lagasse static int be_mount_root(zfs_handle_t *, char *);
72*f169c0eaSGlenn Lagasse static int be_unmount_root(zfs_handle_t *, be_unmount_data_t *);
73*f169c0eaSGlenn Lagasse static int be_mount_zones(zfs_handle_t *, be_mount_data_t *);
74*f169c0eaSGlenn Lagasse static int be_unmount_zones(be_unmount_data_t *);
75*f169c0eaSGlenn Lagasse static int be_mount_one_zone(zfs_handle_t *, be_mount_data_t *, char *, char *,
76*f169c0eaSGlenn Lagasse     char *);
77*f169c0eaSGlenn Lagasse static int be_unmount_one_zone(be_unmount_data_t *, char *, char *, char *);
78*f169c0eaSGlenn Lagasse static int be_get_ds_from_dir_callback(zfs_handle_t *, void *);
79*f169c0eaSGlenn Lagasse 
80*f169c0eaSGlenn Lagasse 
81*f169c0eaSGlenn Lagasse /* ********************************************************************	*/
82*f169c0eaSGlenn Lagasse /*			Public Functions				*/
83*f169c0eaSGlenn Lagasse /* ********************************************************************	*/
84*f169c0eaSGlenn Lagasse 
85*f169c0eaSGlenn Lagasse /*
86*f169c0eaSGlenn Lagasse  * Function:	be_mount
87*f169c0eaSGlenn Lagasse  * Description:	Mounts a BE and its subordinate datasets at a given mountpoint.
88*f169c0eaSGlenn Lagasse  * Parameters:
89*f169c0eaSGlenn Lagasse  *		be_attrs - pointer to nvlist_t of attributes being passed in.
90*f169c0eaSGlenn Lagasse  *			The following attributes are used by this function:
91*f169c0eaSGlenn Lagasse  *
92*f169c0eaSGlenn Lagasse  *			BE_ATTR_ORIG_BE_NAME		*required
93*f169c0eaSGlenn Lagasse  *			BE_ATTR_MOUNTPOINT		*required
94*f169c0eaSGlenn Lagasse  *			BE_ATTR_MOUNT_FLAGS		*optional
95*f169c0eaSGlenn Lagasse  * Return:
96*f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
97*f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
98*f169c0eaSGlenn Lagasse  * Scope:
99*f169c0eaSGlenn Lagasse  *		Public
100*f169c0eaSGlenn Lagasse  */
101*f169c0eaSGlenn Lagasse int
102*f169c0eaSGlenn Lagasse be_mount(nvlist_t *be_attrs)
103*f169c0eaSGlenn Lagasse {
104*f169c0eaSGlenn Lagasse 	char		*be_name = NULL;
105*f169c0eaSGlenn Lagasse 	char		*mountpoint = NULL;
106*f169c0eaSGlenn Lagasse 	uint16_t	flags = 0;
107*f169c0eaSGlenn Lagasse 	int		ret = BE_SUCCESS;
108*f169c0eaSGlenn Lagasse 
109*f169c0eaSGlenn Lagasse 	/* Initialize libzfs handle */
110*f169c0eaSGlenn Lagasse 	if (!be_zfs_init())
111*f169c0eaSGlenn Lagasse 		return (BE_ERR_INIT);
112*f169c0eaSGlenn Lagasse 
113*f169c0eaSGlenn Lagasse 	/* Get original BE name */
114*f169c0eaSGlenn Lagasse 	if (nvlist_lookup_string(be_attrs, BE_ATTR_ORIG_BE_NAME, &be_name)
115*f169c0eaSGlenn Lagasse 	    != 0) {
116*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_mount: failed to lookup "
117*f169c0eaSGlenn Lagasse 		    "BE_ATTR_ORIG_BE_NAME attribute\n"));
118*f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
119*f169c0eaSGlenn Lagasse 	}
120*f169c0eaSGlenn Lagasse 
121*f169c0eaSGlenn Lagasse 	/* Validate original BE name */
122*f169c0eaSGlenn Lagasse 	if (!be_valid_be_name(be_name)) {
123*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_mount: invalid BE name %s\n"),
124*f169c0eaSGlenn Lagasse 		    be_name);
125*f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
126*f169c0eaSGlenn Lagasse 	}
127*f169c0eaSGlenn Lagasse 
128*f169c0eaSGlenn Lagasse 	/* Get mountpoint */
129*f169c0eaSGlenn Lagasse 	if (nvlist_lookup_string(be_attrs, BE_ATTR_MOUNTPOINT, &mountpoint)
130*f169c0eaSGlenn Lagasse 	    != 0) {
131*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_mount: failed to lookup "
132*f169c0eaSGlenn Lagasse 		    "BE_ATTR_MOUNTPOINT attribute\n"));
133*f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
134*f169c0eaSGlenn Lagasse 	}
135*f169c0eaSGlenn Lagasse 
136*f169c0eaSGlenn Lagasse 	/* Get flags */
137*f169c0eaSGlenn Lagasse 	if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
138*f169c0eaSGlenn Lagasse 	    BE_ATTR_MOUNT_FLAGS, DATA_TYPE_UINT16, &flags, NULL) != 0) {
139*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_mount: failed to lookup "
140*f169c0eaSGlenn Lagasse 		    "BE_ATTR_MOUNT_FLAGS attribute\n"));
141*f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
142*f169c0eaSGlenn Lagasse 	}
143*f169c0eaSGlenn Lagasse 
144*f169c0eaSGlenn Lagasse 	ret = _be_mount(be_name, &mountpoint, flags);
145*f169c0eaSGlenn Lagasse 
146*f169c0eaSGlenn Lagasse 	be_zfs_fini();
147*f169c0eaSGlenn Lagasse 
148*f169c0eaSGlenn Lagasse 	return (ret);
149*f169c0eaSGlenn Lagasse }
150*f169c0eaSGlenn Lagasse 
151*f169c0eaSGlenn Lagasse /*
152*f169c0eaSGlenn Lagasse  * Function:	be_unmount
153*f169c0eaSGlenn Lagasse  * Description:	Unmounts a BE and its subordinate datasets.
154*f169c0eaSGlenn Lagasse  * Parameters:
155*f169c0eaSGlenn Lagasse  *		be_attrs - pointer to nvlist_t of attributes being passed in.
156*f169c0eaSGlenn Lagasse  *			The following attributes are used by this function:
157*f169c0eaSGlenn Lagasse  *
158*f169c0eaSGlenn Lagasse  *			BE_ATTR_ORIG_BE_NAME		*required
159*f169c0eaSGlenn Lagasse  *			BE_ATTR_UNMOUNT_FLAGS		*optional
160*f169c0eaSGlenn Lagasse  * Return:
161*f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
162*f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
163*f169c0eaSGlenn Lagasse  * Scope:
164*f169c0eaSGlenn Lagasse  *		Public
165*f169c0eaSGlenn Lagasse  */
166*f169c0eaSGlenn Lagasse int
167*f169c0eaSGlenn Lagasse be_unmount(nvlist_t *be_attrs)
168*f169c0eaSGlenn Lagasse {
169*f169c0eaSGlenn Lagasse 	char		*be_name = NULL;
170*f169c0eaSGlenn Lagasse 	uint16_t	flags = 0;
171*f169c0eaSGlenn Lagasse 	int		ret = BE_SUCCESS;
172*f169c0eaSGlenn Lagasse 
173*f169c0eaSGlenn Lagasse 	/* Initialize libzfs handle */
174*f169c0eaSGlenn Lagasse 	if (!be_zfs_init())
175*f169c0eaSGlenn Lagasse 		return (BE_ERR_INIT);
176*f169c0eaSGlenn Lagasse 
177*f169c0eaSGlenn Lagasse 	/* Get original BE name */
178*f169c0eaSGlenn Lagasse 	if (nvlist_lookup_string(be_attrs, BE_ATTR_ORIG_BE_NAME, &be_name)
179*f169c0eaSGlenn Lagasse 	    != 0) {
180*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_unmount: failed to lookup "
181*f169c0eaSGlenn Lagasse 		    "BE_ATTR_ORIG_BE_NAME attribute\n"));
182*f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
183*f169c0eaSGlenn Lagasse 	}
184*f169c0eaSGlenn Lagasse 
185*f169c0eaSGlenn Lagasse 	/* Validate original BE name */
186*f169c0eaSGlenn Lagasse 	if (!be_valid_be_name(be_name)) {
187*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_unmount: invalid BE name %s\n"),
188*f169c0eaSGlenn Lagasse 		    be_name);
189*f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
190*f169c0eaSGlenn Lagasse 	}
191*f169c0eaSGlenn Lagasse 
192*f169c0eaSGlenn Lagasse 	/* Get unmount flags */
193*f169c0eaSGlenn Lagasse 	if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
194*f169c0eaSGlenn Lagasse 	    BE_ATTR_UNMOUNT_FLAGS, DATA_TYPE_UINT16, &flags, NULL) != 0) {
195*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_unmount: failed to loookup "
196*f169c0eaSGlenn Lagasse 		    "BE_ATTR_UNMOUNT_FLAGS attribute\n"));
197*f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
198*f169c0eaSGlenn Lagasse 	}
199*f169c0eaSGlenn Lagasse 
200*f169c0eaSGlenn Lagasse 	ret = _be_unmount(be_name, flags);
201*f169c0eaSGlenn Lagasse 
202*f169c0eaSGlenn Lagasse 	be_zfs_fini();
203*f169c0eaSGlenn Lagasse 
204*f169c0eaSGlenn Lagasse 	return (ret);
205*f169c0eaSGlenn Lagasse }
206*f169c0eaSGlenn Lagasse 
207*f169c0eaSGlenn Lagasse /* ********************************************************************	*/
208*f169c0eaSGlenn Lagasse /*			Semi-Private Functions				*/
209*f169c0eaSGlenn Lagasse /* ******************************************************************** */
210*f169c0eaSGlenn Lagasse 
211*f169c0eaSGlenn Lagasse /*
212*f169c0eaSGlenn Lagasse  * Function:	_be_mount
213*f169c0eaSGlenn Lagasse  * Description:	Mounts a BE.  If the altroot is not provided, this function
214*f169c0eaSGlenn Lagasse  *		will generate a temporary mountpoint to mount the BE at.  It
215*f169c0eaSGlenn Lagasse  *		will return this temporary mountpoint to the caller via the
216*f169c0eaSGlenn Lagasse  *		altroot reference pointer passed in.  This returned value is
217*f169c0eaSGlenn Lagasse  *		allocated on heap storage and is the repsonsibility of the
218*f169c0eaSGlenn Lagasse  *		caller to free.
219*f169c0eaSGlenn Lagasse  * Parameters:
220*f169c0eaSGlenn Lagasse  *		be_name - pointer to name of BE to mount.
221*f169c0eaSGlenn Lagasse  *		altroot - reference pointer to altroot of where to mount BE.
222*f169c0eaSGlenn Lagasse  *		flags - flag indicating special handling for mounting the BE
223*f169c0eaSGlenn Lagasse  * Return:
224*f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
225*f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
226*f169c0eaSGlenn Lagasse  * Scope:
227*f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
228*f169c0eaSGlenn Lagasse  */
229*f169c0eaSGlenn Lagasse int
230*f169c0eaSGlenn Lagasse _be_mount(char *be_name, char **altroot, int flags)
231*f169c0eaSGlenn Lagasse {
232*f169c0eaSGlenn Lagasse 	be_transaction_data_t	bt = { 0 };
233*f169c0eaSGlenn Lagasse 	be_mount_data_t	md = { 0 };
234*f169c0eaSGlenn Lagasse 	zfs_handle_t	*zhp;
235*f169c0eaSGlenn Lagasse 	char		obe_root_ds[MAXPATHLEN];
236*f169c0eaSGlenn Lagasse 	char		*mp = NULL;
237*f169c0eaSGlenn Lagasse 	char		*tmp_altroot = NULL;
238*f169c0eaSGlenn Lagasse 	int		ret = BE_SUCCESS, err = 0;
239*f169c0eaSGlenn Lagasse 	uuid_t		uu = { 0 };
240*f169c0eaSGlenn Lagasse 	boolean_t	gen_tmp_altroot = B_FALSE;
241*f169c0eaSGlenn Lagasse 
242*f169c0eaSGlenn Lagasse 	if (be_name == NULL || altroot == NULL)
243*f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
244*f169c0eaSGlenn Lagasse 
245*f169c0eaSGlenn Lagasse 	/* Set be_name as obe_name in bt structure */
246*f169c0eaSGlenn Lagasse 	bt.obe_name = be_name;
247*f169c0eaSGlenn Lagasse 
248*f169c0eaSGlenn Lagasse 	/* Find which zpool obe_name lives in */
249*f169c0eaSGlenn Lagasse 	if ((err = zpool_iter(g_zfs, be_find_zpool_callback, &bt)) == 0) {
250*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_mount: failed to "
251*f169c0eaSGlenn Lagasse 		    "find zpool for BE (%s)\n"), bt.obe_name);
252*f169c0eaSGlenn Lagasse 		return (BE_ERR_BE_NOENT);
253*f169c0eaSGlenn Lagasse 	} else if (err < 0) {
254*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_mount: zpool_iter failed: %s\n"),
255*f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
256*f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
257*f169c0eaSGlenn Lagasse 	}
258*f169c0eaSGlenn Lagasse 
259*f169c0eaSGlenn Lagasse 	/* Generate string for obe_name's root dataset */
260*f169c0eaSGlenn Lagasse 	be_make_root_ds(bt.obe_zpool, bt.obe_name, obe_root_ds,
261*f169c0eaSGlenn Lagasse 	    sizeof (obe_root_ds));
262*f169c0eaSGlenn Lagasse 	bt.obe_root_ds = obe_root_ds;
263*f169c0eaSGlenn Lagasse 
264*f169c0eaSGlenn Lagasse 	/* Get handle to BE's root dataset */
265*f169c0eaSGlenn Lagasse 	if ((zhp = zfs_open(g_zfs, bt.obe_root_ds, ZFS_TYPE_FILESYSTEM)) ==
266*f169c0eaSGlenn Lagasse 	    NULL) {
267*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_mount: failed to "
268*f169c0eaSGlenn Lagasse 		    "open BE root dataset (%s): %s\n"), bt.obe_root_ds,
269*f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
270*f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
271*f169c0eaSGlenn Lagasse 	}
272*f169c0eaSGlenn Lagasse 
273*f169c0eaSGlenn Lagasse 	/* Make sure BE's root dataset isn't already mounted somewhere */
274*f169c0eaSGlenn Lagasse 	if (zfs_is_mounted(zhp, &mp)) {
275*f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
276*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_mount: %s is already mounted "
277*f169c0eaSGlenn Lagasse 		    "at %s\n"), bt.obe_name, mp != NULL ? mp : "");
278*f169c0eaSGlenn Lagasse 		free(mp);
279*f169c0eaSGlenn Lagasse 		return (BE_ERR_MOUNTED);
280*f169c0eaSGlenn Lagasse 	}
281*f169c0eaSGlenn Lagasse 
282*f169c0eaSGlenn Lagasse 	/*
283*f169c0eaSGlenn Lagasse 	 * Fix this BE's mountpoint if its root dataset isn't set to
284*f169c0eaSGlenn Lagasse 	 * either 'legacy' or '/'.
285*f169c0eaSGlenn Lagasse 	 */
286*f169c0eaSGlenn Lagasse 	if ((ret = fix_mountpoint(zhp)) != BE_SUCCESS) {
287*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_mount: mountpoint check "
288*f169c0eaSGlenn Lagasse 		    "failed for %s\n"), bt.obe_root_ds);
289*f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
290*f169c0eaSGlenn Lagasse 		return (ret);
291*f169c0eaSGlenn Lagasse 	}
292*f169c0eaSGlenn Lagasse 
293*f169c0eaSGlenn Lagasse 	/*
294*f169c0eaSGlenn Lagasse 	 * If altroot not provided, create a temporary alternate root
295*f169c0eaSGlenn Lagasse 	 * to mount on
296*f169c0eaSGlenn Lagasse 	 */
297*f169c0eaSGlenn Lagasse 	if (*altroot == NULL) {
298*f169c0eaSGlenn Lagasse 		if ((ret = be_make_tmp_mountpoint(&tmp_altroot))
299*f169c0eaSGlenn Lagasse 		    != BE_SUCCESS) {
300*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_mount: failed to "
301*f169c0eaSGlenn Lagasse 			    "make temporary mountpoint\n"));
302*f169c0eaSGlenn Lagasse 			ZFS_CLOSE(zhp);
303*f169c0eaSGlenn Lagasse 			return (ret);
304*f169c0eaSGlenn Lagasse 		}
305*f169c0eaSGlenn Lagasse 		gen_tmp_altroot = B_TRUE;
306*f169c0eaSGlenn Lagasse 	} else {
307*f169c0eaSGlenn Lagasse 		tmp_altroot = *altroot;
308*f169c0eaSGlenn Lagasse 	}
309*f169c0eaSGlenn Lagasse 
310*f169c0eaSGlenn Lagasse 	/* Mount the BE's root file system */
311*f169c0eaSGlenn Lagasse 	if ((ret = be_mount_root(zhp, tmp_altroot)) != BE_SUCCESS) {
312*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_mount: failed to "
313*f169c0eaSGlenn Lagasse 		    "mount BE root file system\n"));
314*f169c0eaSGlenn Lagasse 		if (gen_tmp_altroot)
315*f169c0eaSGlenn Lagasse 			free(tmp_altroot);
316*f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
317*f169c0eaSGlenn Lagasse 		return (ret);
318*f169c0eaSGlenn Lagasse 	}
319*f169c0eaSGlenn Lagasse 
320*f169c0eaSGlenn Lagasse 	/* Iterate through BE's children filesystems */
321*f169c0eaSGlenn Lagasse 	if ((err = zfs_iter_filesystems(zhp, be_mount_callback,
322*f169c0eaSGlenn Lagasse 	    tmp_altroot)) != 0) {
323*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_mount: failed to "
324*f169c0eaSGlenn Lagasse 		    "mount BE (%s) on %s\n"), bt.obe_name, tmp_altroot);
325*f169c0eaSGlenn Lagasse 		if (gen_tmp_altroot)
326*f169c0eaSGlenn Lagasse 			free(tmp_altroot);
327*f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
328*f169c0eaSGlenn Lagasse 		return (err);
329*f169c0eaSGlenn Lagasse 	}
330*f169c0eaSGlenn Lagasse 
331*f169c0eaSGlenn Lagasse 	md.altroot = tmp_altroot;
332*f169c0eaSGlenn Lagasse 	md.shared_fs = flags & BE_MOUNT_FLAG_SHARED_FS;
333*f169c0eaSGlenn Lagasse 	md.shared_rw = flags & BE_MOUNT_FLAG_SHARED_RW;
334*f169c0eaSGlenn Lagasse 
335*f169c0eaSGlenn Lagasse 	/*
336*f169c0eaSGlenn Lagasse 	 * Mount shared file systems if mount flag says so.
337*f169c0eaSGlenn Lagasse 	 */
338*f169c0eaSGlenn Lagasse 	if (md.shared_fs) {
339*f169c0eaSGlenn Lagasse 		/*
340*f169c0eaSGlenn Lagasse 		 * Mount all ZFS file systems not under the BE's root dataset
341*f169c0eaSGlenn Lagasse 		 */
342*f169c0eaSGlenn Lagasse 		(void) zpool_iter(g_zfs, zpool_shared_fs_callback, &md);
343*f169c0eaSGlenn Lagasse 
344*f169c0eaSGlenn Lagasse 		/* TODO: Mount all non-ZFS file systems - Not supported yet */
345*f169c0eaSGlenn Lagasse 	}
346*f169c0eaSGlenn Lagasse 
347*f169c0eaSGlenn Lagasse 	/*
348*f169c0eaSGlenn Lagasse 	 * If we're in the global zone and the global zone has a valid uuid,
349*f169c0eaSGlenn Lagasse 	 * mount all supported non-global zones.
350*f169c0eaSGlenn Lagasse 	 */
351*f169c0eaSGlenn Lagasse 	if (getzoneid() == GLOBAL_ZONEID &&
352*f169c0eaSGlenn Lagasse 	    !(flags & BE_MOUNT_FLAG_NO_ZONES) &&
353*f169c0eaSGlenn Lagasse 	    be_get_uuid(bt.obe_root_ds, &uu) == BE_SUCCESS) {
354*f169c0eaSGlenn Lagasse 		if ((ret = be_mount_zones(zhp, &md)) != BE_SUCCESS) {
355*f169c0eaSGlenn Lagasse 			(void) _be_unmount(bt.obe_name, 0);
356*f169c0eaSGlenn Lagasse 			if (gen_tmp_altroot)
357*f169c0eaSGlenn Lagasse 				free(tmp_altroot);
358*f169c0eaSGlenn Lagasse 			ZFS_CLOSE(zhp);
359*f169c0eaSGlenn Lagasse 			return (ret);
360*f169c0eaSGlenn Lagasse 		}
361*f169c0eaSGlenn Lagasse 	}
362*f169c0eaSGlenn Lagasse 
363*f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp);
364*f169c0eaSGlenn Lagasse 
365*f169c0eaSGlenn Lagasse 	/*
366*f169c0eaSGlenn Lagasse 	 * If a NULL altroot was passed in, pass the generated altroot
367*f169c0eaSGlenn Lagasse 	 * back to the caller in altroot.
368*f169c0eaSGlenn Lagasse 	 */
369*f169c0eaSGlenn Lagasse 	if (gen_tmp_altroot)
370*f169c0eaSGlenn Lagasse 		*altroot = tmp_altroot;
371*f169c0eaSGlenn Lagasse 
372*f169c0eaSGlenn Lagasse 	return (BE_SUCCESS);
373*f169c0eaSGlenn Lagasse }
374*f169c0eaSGlenn Lagasse 
375*f169c0eaSGlenn Lagasse /*
376*f169c0eaSGlenn Lagasse  * Function:	_be_unmount
377*f169c0eaSGlenn Lagasse  * Description:	Unmount a BE.
378*f169c0eaSGlenn Lagasse  * Parameters:
379*f169c0eaSGlenn Lagasse  *		be_name - pointer to name of BE to unmount.
380*f169c0eaSGlenn Lagasse  *		flags - flags for unmounting the BE.
381*f169c0eaSGlenn Lagasse  * Returns:
382*f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
383*f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
384*f169c0eaSGlenn Lagasse  * Scope:
385*f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
386*f169c0eaSGlenn Lagasse  */
387*f169c0eaSGlenn Lagasse int
388*f169c0eaSGlenn Lagasse _be_unmount(char *be_name, int flags)
389*f169c0eaSGlenn Lagasse {
390*f169c0eaSGlenn Lagasse 	be_transaction_data_t	bt = { 0 };
391*f169c0eaSGlenn Lagasse 	be_unmount_data_t	ud = { 0 };
392*f169c0eaSGlenn Lagasse 	zfs_handle_t	*zhp;
393*f169c0eaSGlenn Lagasse 	uuid_t		uu = { 0 };
394*f169c0eaSGlenn Lagasse 	char		obe_root_ds[MAXPATHLEN];
395*f169c0eaSGlenn Lagasse 	char		mountpoint[MAXPATHLEN];
396*f169c0eaSGlenn Lagasse 	char		*mp = NULL;
397*f169c0eaSGlenn Lagasse 	int		ret = BE_SUCCESS;
398*f169c0eaSGlenn Lagasse 	int		zret = 0;
399*f169c0eaSGlenn Lagasse 
400*f169c0eaSGlenn Lagasse 	if (be_name == NULL)
401*f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
402*f169c0eaSGlenn Lagasse 
403*f169c0eaSGlenn Lagasse 	/* Set be_name as obe_name in bt structure */
404*f169c0eaSGlenn Lagasse 	bt.obe_name = be_name;
405*f169c0eaSGlenn Lagasse 
406*f169c0eaSGlenn Lagasse 	/* Find which zpool obe_name lives in */
407*f169c0eaSGlenn Lagasse 	if ((zret = zpool_iter(g_zfs, be_find_zpool_callback, &bt)) == 0) {
408*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_unmount: failed to "
409*f169c0eaSGlenn Lagasse 		    "find zpool for BE (%s)\n"), bt.obe_name);
410*f169c0eaSGlenn Lagasse 		return (BE_ERR_BE_NOENT);
411*f169c0eaSGlenn Lagasse 	} else if (zret < 0) {
412*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_unmount: "
413*f169c0eaSGlenn Lagasse 		    "zpool_iter failed: %s\n"),
414*f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
415*f169c0eaSGlenn Lagasse 		ret = zfs_err_to_be_err(g_zfs);
416*f169c0eaSGlenn Lagasse 		return (ret);
417*f169c0eaSGlenn Lagasse 	}
418*f169c0eaSGlenn Lagasse 
419*f169c0eaSGlenn Lagasse 	/* Generate string for obe_name's root dataset */
420*f169c0eaSGlenn Lagasse 	be_make_root_ds(bt.obe_zpool, bt.obe_name, obe_root_ds,
421*f169c0eaSGlenn Lagasse 	    sizeof (obe_root_ds));
422*f169c0eaSGlenn Lagasse 	bt.obe_root_ds = obe_root_ds;
423*f169c0eaSGlenn Lagasse 
424*f169c0eaSGlenn Lagasse 	/* Get handle to BE's root dataset */
425*f169c0eaSGlenn Lagasse 	if ((zhp = zfs_open(g_zfs, bt.obe_root_ds, ZFS_TYPE_FILESYSTEM)) ==
426*f169c0eaSGlenn Lagasse 	    NULL) {
427*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_unmount: failed to "
428*f169c0eaSGlenn Lagasse 		    "open BE root dataset (%s): %s\n"), bt.obe_root_ds,
429*f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
430*f169c0eaSGlenn Lagasse 		ret = zfs_err_to_be_err(g_zfs);
431*f169c0eaSGlenn Lagasse 		return (ret);
432*f169c0eaSGlenn Lagasse 	}
433*f169c0eaSGlenn Lagasse 
434*f169c0eaSGlenn Lagasse 	/* Make sure BE's root dataset is mounted somewhere */
435*f169c0eaSGlenn Lagasse 	if (!zfs_is_mounted(zhp, &mp)) {
436*f169c0eaSGlenn Lagasse 
437*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_unmount: "
438*f169c0eaSGlenn Lagasse 		    "(%s) not mounted\n"), bt.obe_name);
439*f169c0eaSGlenn Lagasse 
440*f169c0eaSGlenn Lagasse 		/*
441*f169c0eaSGlenn Lagasse 		 * BE is not mounted, fix this BE's mountpoint if its root
442*f169c0eaSGlenn Lagasse 		 * dataset isn't set to either 'legacy' or '/'.
443*f169c0eaSGlenn Lagasse 		 */
444*f169c0eaSGlenn Lagasse 		if ((ret = fix_mountpoint(zhp)) != BE_SUCCESS) {
445*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_unmount: mountpoint check "
446*f169c0eaSGlenn Lagasse 			    "failed for %s\n"), bt.obe_root_ds);
447*f169c0eaSGlenn Lagasse 			ZFS_CLOSE(zhp);
448*f169c0eaSGlenn Lagasse 			return (ret);
449*f169c0eaSGlenn Lagasse 		}
450*f169c0eaSGlenn Lagasse 
451*f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
452*f169c0eaSGlenn Lagasse 		return (BE_SUCCESS);
453*f169c0eaSGlenn Lagasse 	}
454*f169c0eaSGlenn Lagasse 
455*f169c0eaSGlenn Lagasse 	/*
456*f169c0eaSGlenn Lagasse 	 * If we didn't get a mountpoint from the zfs_is_mounted call,
457*f169c0eaSGlenn Lagasse 	 * try and get it from its property.
458*f169c0eaSGlenn Lagasse 	 */
459*f169c0eaSGlenn Lagasse 	if (mp == NULL) {
460*f169c0eaSGlenn Lagasse 		if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint,
461*f169c0eaSGlenn Lagasse 		    sizeof (mountpoint), NULL, NULL, 0, B_FALSE) != 0) {
462*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_unmount: failed to "
463*f169c0eaSGlenn Lagasse 			    "get mountpoint of (%s)\n"), bt.obe_name);
464*f169c0eaSGlenn Lagasse 			ZFS_CLOSE(zhp);
465*f169c0eaSGlenn Lagasse 			return (BE_ERR_ZFS);
466*f169c0eaSGlenn Lagasse 		}
467*f169c0eaSGlenn Lagasse 	} else {
468*f169c0eaSGlenn Lagasse 		(void) strlcpy(mountpoint, mp, sizeof (mountpoint));
469*f169c0eaSGlenn Lagasse 		free(mp);
470*f169c0eaSGlenn Lagasse 	}
471*f169c0eaSGlenn Lagasse 
472*f169c0eaSGlenn Lagasse 	/* If BE mounted as current root, fail */
473*f169c0eaSGlenn Lagasse 	if (strcmp(mountpoint, "/") == 0) {
474*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_unmount: "
475*f169c0eaSGlenn Lagasse 		    "cannot unmount currently running BE\n"));
476*f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
477*f169c0eaSGlenn Lagasse 		return (BE_ERR_UMOUNT_CURR_BE);
478*f169c0eaSGlenn Lagasse 	}
479*f169c0eaSGlenn Lagasse 
480*f169c0eaSGlenn Lagasse 	ud.altroot = mountpoint;
481*f169c0eaSGlenn Lagasse 	ud.force = flags & BE_UNMOUNT_FLAG_FORCE;
482*f169c0eaSGlenn Lagasse 
483*f169c0eaSGlenn Lagasse 	/* Unmount all supported non-global zones if we're in the global zone */
484*f169c0eaSGlenn Lagasse 	if (getzoneid() == GLOBAL_ZONEID &&
485*f169c0eaSGlenn Lagasse 	    be_get_uuid(bt.obe_root_ds, &uu) == BE_SUCCESS) {
486*f169c0eaSGlenn Lagasse 		if ((ret = be_unmount_zones(&ud)) != BE_SUCCESS) {
487*f169c0eaSGlenn Lagasse 			ZFS_CLOSE(zhp);
488*f169c0eaSGlenn Lagasse 			return (ret);
489*f169c0eaSGlenn Lagasse 		}
490*f169c0eaSGlenn Lagasse 	}
491*f169c0eaSGlenn Lagasse 
492*f169c0eaSGlenn Lagasse 	/* TODO: Unmount all non-ZFS file systems - Not supported yet */
493*f169c0eaSGlenn Lagasse 
494*f169c0eaSGlenn Lagasse 	/* Unmount all ZFS file systems not under the BE root dataset */
495*f169c0eaSGlenn Lagasse 	if ((ret = unmount_shared_fs(&ud)) != BE_SUCCESS) {
496*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_unmount: failed to "
497*f169c0eaSGlenn Lagasse 		    "unmount shared file systems\n"));
498*f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
499*f169c0eaSGlenn Lagasse 		return (ret);
500*f169c0eaSGlenn Lagasse 	}
501*f169c0eaSGlenn Lagasse 
502*f169c0eaSGlenn Lagasse 	/* Unmount all children datasets under the BE's root dataset */
503*f169c0eaSGlenn Lagasse 	if ((zret = zfs_iter_filesystems(zhp, be_unmount_callback,
504*f169c0eaSGlenn Lagasse 	    &ud)) != 0) {
505*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_unmount: failed to "
506*f169c0eaSGlenn Lagasse 		    "unmount BE (%s)\n"), bt.obe_name);
507*f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
508*f169c0eaSGlenn Lagasse 		return (zret);
509*f169c0eaSGlenn Lagasse 	}
510*f169c0eaSGlenn Lagasse 
511*f169c0eaSGlenn Lagasse 	/* Unmount this BE's root filesystem */
512*f169c0eaSGlenn Lagasse 	if ((ret = be_unmount_root(zhp, &ud)) != BE_SUCCESS) {
513*f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
514*f169c0eaSGlenn Lagasse 		return (ret);
515*f169c0eaSGlenn Lagasse 	}
516*f169c0eaSGlenn Lagasse 
517*f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp);
518*f169c0eaSGlenn Lagasse 
519*f169c0eaSGlenn Lagasse 	return (BE_SUCCESS);
520*f169c0eaSGlenn Lagasse }
521*f169c0eaSGlenn Lagasse 
522*f169c0eaSGlenn Lagasse /*
523*f169c0eaSGlenn Lagasse  * Function:	be_mount_zone_root
524*f169c0eaSGlenn Lagasse  * Description:	Mounts the zone root dataset for a zone.
525*f169c0eaSGlenn Lagasse  * Parameters:
526*f169c0eaSGlenn Lagasse  *		zfs - zfs_handle_t pointer to zone root dataset
527*f169c0eaSGlenn Lagasse  *		md - be_mount_data_t pointer to data for zone to be mounted
528*f169c0eaSGlenn Lagasse  * Returns:
529*f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
530*f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
531*f169c0eaSGlenn Lagasse  * Scope:
532*f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
533*f169c0eaSGlenn Lagasse  */
534*f169c0eaSGlenn Lagasse int
535*f169c0eaSGlenn Lagasse be_mount_zone_root(zfs_handle_t *zhp, be_mount_data_t *md)
536*f169c0eaSGlenn Lagasse {
537*f169c0eaSGlenn Lagasse 	char	mountpoint[MAXPATHLEN];
538*f169c0eaSGlenn Lagasse 	int	err = 0;
539*f169c0eaSGlenn Lagasse 
540*f169c0eaSGlenn Lagasse 	/* Get mountpoint property of dataset */
541*f169c0eaSGlenn Lagasse 	if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint,
542*f169c0eaSGlenn Lagasse 	    sizeof (mountpoint), NULL, NULL, 0, B_FALSE) != 0) {
543*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_mount_zone_root: failed to "
544*f169c0eaSGlenn Lagasse 		    "get mountpoint property for %s: %s\n"), zfs_get_name(zhp),
545*f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
546*f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
547*f169c0eaSGlenn Lagasse 	}
548*f169c0eaSGlenn Lagasse 
549*f169c0eaSGlenn Lagasse 	/*
550*f169c0eaSGlenn Lagasse 	 * Make sure zone's root dataset is set to 'legacy'.  This is
551*f169c0eaSGlenn Lagasse 	 * currently a requirement in this implementation of zones
552*f169c0eaSGlenn Lagasse 	 * support.
553*f169c0eaSGlenn Lagasse 	 */
554*f169c0eaSGlenn Lagasse 	if (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0) {
555*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_mount_zone_root: "
556*f169c0eaSGlenn Lagasse 		    "zone root dataset mountpoint is not 'legacy'\n"));
557*f169c0eaSGlenn Lagasse 		return (BE_ERR_ZONE_ROOT_NOT_LEGACY);
558*f169c0eaSGlenn Lagasse 	}
559*f169c0eaSGlenn Lagasse 
560*f169c0eaSGlenn Lagasse 	/*
561*f169c0eaSGlenn Lagasse 	 * Legacy mount the zone root dataset.
562*f169c0eaSGlenn Lagasse 	 *
563*f169c0eaSGlenn Lagasse 	 * As a workaround for 6176743, we mount the zone's root with the
564*f169c0eaSGlenn Lagasse 	 * MS_OVERLAY option in case an alternate BE is mounted, and we're
565*f169c0eaSGlenn Lagasse 	 * mounting the root for the zone from the current BE here.  When an
566*f169c0eaSGlenn Lagasse 	 * alternate BE is mounted, it ties up the zone's zoneroot directory
567*f169c0eaSGlenn Lagasse 	 * for the current BE since the zone's zonepath is loopback mounted
568*f169c0eaSGlenn Lagasse 	 * from the current BE.
569*f169c0eaSGlenn Lagasse 	 *
570*f169c0eaSGlenn Lagasse 	 * TODO: The MS_OVERLAY option needs to be removed when 6176743
571*f169c0eaSGlenn Lagasse 	 * is fixed.
572*f169c0eaSGlenn Lagasse 	 */
573*f169c0eaSGlenn Lagasse 	if (mount(zfs_get_name(zhp), md->altroot, MS_OVERLAY, MNTTYPE_ZFS,
574*f169c0eaSGlenn Lagasse 	    NULL, 0, NULL, 0) != 0) {
575*f169c0eaSGlenn Lagasse 		err = errno;
576*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_mount_zone_root: failed to "
577*f169c0eaSGlenn Lagasse 		    "legacy mount zone root dataset (%s) at %s\n"),
578*f169c0eaSGlenn Lagasse 		    zfs_get_name(zhp), md->altroot);
579*f169c0eaSGlenn Lagasse 		return (errno_to_be_err(err));
580*f169c0eaSGlenn Lagasse 	}
581*f169c0eaSGlenn Lagasse 
582*f169c0eaSGlenn Lagasse 	return (BE_SUCCESS);
583*f169c0eaSGlenn Lagasse }
584*f169c0eaSGlenn Lagasse 
585*f169c0eaSGlenn Lagasse /*
586*f169c0eaSGlenn Lagasse  * Function:	be_unmount_zone_root
587*f169c0eaSGlenn Lagasse  * Description:	Unmounts the zone root dataset for a zone.
588*f169c0eaSGlenn Lagasse  * Parameters:
589*f169c0eaSGlenn Lagasse  *		zhp - zfs_handle_t pointer to zone root dataset
590*f169c0eaSGlenn Lagasse  *		ud - be_unmount_data_t pointer to data for zone to be unmounted
591*f169c0eaSGlenn Lagasse  * Returns:
592*f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
593*f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
594*f169c0eaSGlenn Lagasse  * Scope:
595*f169c0eaSGlenn Lagasse  *		Semi-private (library wise use only)
596*f169c0eaSGlenn Lagasse  */
597*f169c0eaSGlenn Lagasse int
598*f169c0eaSGlenn Lagasse be_unmount_zone_root(zfs_handle_t *zhp, be_unmount_data_t *ud)
599*f169c0eaSGlenn Lagasse {
600*f169c0eaSGlenn Lagasse 	char	mountpoint[MAXPATHLEN];
601*f169c0eaSGlenn Lagasse 
602*f169c0eaSGlenn Lagasse 	/* Unmount the dataset */
603*f169c0eaSGlenn Lagasse 	if (zfs_unmount(zhp, NULL, ud->force ? MS_FORCE : 0) != 0) {
604*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_unmount_zone_root: failed to "
605*f169c0eaSGlenn Lagasse 		    "unmount zone root dataset %s: %s\n"), zfs_get_name(zhp),
606*f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
607*f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
608*f169c0eaSGlenn Lagasse 	}
609*f169c0eaSGlenn Lagasse 
610*f169c0eaSGlenn Lagasse 	/* Get the current mountpoint property for the zone root dataset */
611*f169c0eaSGlenn Lagasse 	if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint,
612*f169c0eaSGlenn Lagasse 	    sizeof (mountpoint), NULL, NULL, 0, B_FALSE) != 0) {
613*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_unmount_zone_root: failed to "
614*f169c0eaSGlenn Lagasse 		    "get mountpoint property for zone root dataset (%s): %s\n"),
615*f169c0eaSGlenn Lagasse 		    zfs_get_name(zhp), libzfs_error_description(g_zfs));
616*f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
617*f169c0eaSGlenn Lagasse 	}
618*f169c0eaSGlenn Lagasse 
619*f169c0eaSGlenn Lagasse 	/* If mountpoint not already set to 'legacy', set it to 'legacy' */
620*f169c0eaSGlenn Lagasse 	if (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0) {
621*f169c0eaSGlenn Lagasse 		if (zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
622*f169c0eaSGlenn Lagasse 		    ZFS_MOUNTPOINT_LEGACY) != 0) {
623*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_unmount_zone_root: "
624*f169c0eaSGlenn Lagasse 			    "failed to set mountpoint of zone root dataset "
625*f169c0eaSGlenn Lagasse 			    "%s to 'legacy': %s\n"), zfs_get_name(zhp),
626*f169c0eaSGlenn Lagasse 			    libzfs_error_description(g_zfs));
627*f169c0eaSGlenn Lagasse 			return (zfs_err_to_be_err(g_zfs));
628*f169c0eaSGlenn Lagasse 		}
629*f169c0eaSGlenn Lagasse 	}
630*f169c0eaSGlenn Lagasse 
631*f169c0eaSGlenn Lagasse 	return (BE_SUCCESS);
632*f169c0eaSGlenn Lagasse }
633*f169c0eaSGlenn Lagasse 
634*f169c0eaSGlenn Lagasse /*
635*f169c0eaSGlenn Lagasse  * Function:	be_get_legacy_fs
636*f169c0eaSGlenn Lagasse  * Description:	This function iterates through all non-shared file systems
637*f169c0eaSGlenn Lagasse  *		of a BE and finds the ones with a legacy mountpoint.  For
638*f169c0eaSGlenn Lagasse  *		those file systems, it reads the BE's vfstab to get the
639*f169c0eaSGlenn Lagasse  *		mountpoint.  If found, it adds that file system to the
640*f169c0eaSGlenn Lagasse  *		be_fs_list_data_t passed in.
641*f169c0eaSGlenn Lagasse  *
642*f169c0eaSGlenn Lagasse  *		This function can be used to gather legacy mounted file systems
643*f169c0eaSGlenn Lagasse  *		for both global BEs and non-global zone BEs.  To get data for
644*f169c0eaSGlenn Lagasse  *		a non-global zone BE, the zoneroot_ds and zoneroot parameters
645*f169c0eaSGlenn Lagasse  *		will be specified, otherwise they should be set to NULL.
646*f169c0eaSGlenn Lagasse  * Parameters:
647*f169c0eaSGlenn Lagasse  *		be_name - global BE name from which to get legacy file
648*f169c0eaSGlenn Lagasse  *			system list.
649*f169c0eaSGlenn Lagasse  *		be_root_ds - root dataset of global BE.
650*f169c0eaSGlenn Lagasse  *		zoneroot_ds - root dataset of zone.
651*f169c0eaSGlenn Lagasse  *		zoneroot - zoneroot path of zone.
652*f169c0eaSGlenn Lagasse  *		fld - be_fs_list_data_t pointer.
653*f169c0eaSGlenn Lagasse  * Returns:
654*f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
655*f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
656*f169c0eaSGlenn Lagasse  * Scope:
657*f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
658*f169c0eaSGlenn Lagasse  */
659*f169c0eaSGlenn Lagasse int
660*f169c0eaSGlenn Lagasse be_get_legacy_fs(char *be_name, char *be_root_ds, char *zoneroot_ds,
661*f169c0eaSGlenn Lagasse     char *zoneroot, be_fs_list_data_t *fld)
662*f169c0eaSGlenn Lagasse {
663*f169c0eaSGlenn Lagasse 	zfs_handle_t		*zhp = NULL;
664*f169c0eaSGlenn Lagasse 	char			mountpoint[MAXPATHLEN];
665*f169c0eaSGlenn Lagasse 	boolean_t		mounted_here = B_FALSE;
666*f169c0eaSGlenn Lagasse 	boolean_t		zone_mounted_here = B_FALSE;
667*f169c0eaSGlenn Lagasse 	int			ret = BE_SUCCESS, err = 0;
668*f169c0eaSGlenn Lagasse 
669*f169c0eaSGlenn Lagasse 	if (be_name == NULL || be_root_ds == NULL || fld == NULL)
670*f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
671*f169c0eaSGlenn Lagasse 
672*f169c0eaSGlenn Lagasse 	/* Get handle to BE's root dataset */
673*f169c0eaSGlenn Lagasse 	if ((zhp = zfs_open(g_zfs, be_root_ds, ZFS_TYPE_FILESYSTEM))
674*f169c0eaSGlenn Lagasse 	    == NULL) {
675*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_get_legacy_fs: failed to "
676*f169c0eaSGlenn Lagasse 		    "open BE root dataset (%s): %s\n"), be_root_ds,
677*f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
678*f169c0eaSGlenn Lagasse 		ret = zfs_err_to_be_err(g_zfs);
679*f169c0eaSGlenn Lagasse 		return (ret);
680*f169c0eaSGlenn Lagasse 	}
681*f169c0eaSGlenn Lagasse 
682*f169c0eaSGlenn Lagasse 	/* If BE is not already mounted, mount it. */
683*f169c0eaSGlenn Lagasse 	if (!zfs_is_mounted(zhp, &fld->altroot)) {
684*f169c0eaSGlenn Lagasse 		if ((ret = _be_mount(be_name, &fld->altroot,
685*f169c0eaSGlenn Lagasse 		    zoneroot_ds ? BE_MOUNT_FLAG_NULL :
686*f169c0eaSGlenn Lagasse 		    BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
687*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_get_legacy_fs: "
688*f169c0eaSGlenn Lagasse 			    "failed to mount BE %s\n"), be_name);
689*f169c0eaSGlenn Lagasse 			goto cleanup;
690*f169c0eaSGlenn Lagasse 		}
691*f169c0eaSGlenn Lagasse 
692*f169c0eaSGlenn Lagasse 		mounted_here = B_TRUE;
693*f169c0eaSGlenn Lagasse 	} else if (fld->altroot == NULL) {
694*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_get_legacy_fs: failed to "
695*f169c0eaSGlenn Lagasse 		    "get altroot of mounted BE %s: %s\n"),
696*f169c0eaSGlenn Lagasse 		    be_name, libzfs_error_description(g_zfs));
697*f169c0eaSGlenn Lagasse 		ret = zfs_err_to_be_err(g_zfs);
698*f169c0eaSGlenn Lagasse 		goto cleanup;
699*f169c0eaSGlenn Lagasse 	}
700*f169c0eaSGlenn Lagasse 
701*f169c0eaSGlenn Lagasse 	/*
702*f169c0eaSGlenn Lagasse 	 * If a zone root dataset was passed in, we're wanting to get
703*f169c0eaSGlenn Lagasse 	 * legacy mounted file systems for that zone, not the global
704*f169c0eaSGlenn Lagasse 	 * BE.
705*f169c0eaSGlenn Lagasse 	 */
706*f169c0eaSGlenn Lagasse 	if (zoneroot_ds != NULL) {
707*f169c0eaSGlenn Lagasse 		be_mount_data_t		zone_md = { 0 };
708*f169c0eaSGlenn Lagasse 
709*f169c0eaSGlenn Lagasse 		/* Close off handle to global BE's root dataset */
710*f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
711*f169c0eaSGlenn Lagasse 
712*f169c0eaSGlenn Lagasse 		/* Get handle to zone's root dataset */
713*f169c0eaSGlenn Lagasse 		if ((zhp = zfs_open(g_zfs, zoneroot_ds,
714*f169c0eaSGlenn Lagasse 		    ZFS_TYPE_FILESYSTEM)) == NULL) {
715*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_get_legacy_fs: failed to "
716*f169c0eaSGlenn Lagasse 			    "open zone BE root dataset (%s): %s\n"),
717*f169c0eaSGlenn Lagasse 			    zoneroot_ds, libzfs_error_description(g_zfs));
718*f169c0eaSGlenn Lagasse 			ret = zfs_err_to_be_err(g_zfs);
719*f169c0eaSGlenn Lagasse 			goto cleanup;
720*f169c0eaSGlenn Lagasse 		}
721*f169c0eaSGlenn Lagasse 
722*f169c0eaSGlenn Lagasse 		/* Make sure the zone we're looking for is mounted */
723*f169c0eaSGlenn Lagasse 		if (!zfs_is_mounted(zhp, &zone_md.altroot)) {
724*f169c0eaSGlenn Lagasse 			char	zone_altroot[MAXPATHLEN];
725*f169c0eaSGlenn Lagasse 
726*f169c0eaSGlenn Lagasse 			/* Generate alternate root path for zone */
727*f169c0eaSGlenn Lagasse 			(void) snprintf(zone_altroot, sizeof (zone_altroot),
728*f169c0eaSGlenn Lagasse 			    "%s%s", fld->altroot, zoneroot);
729*f169c0eaSGlenn Lagasse 			if ((zone_md.altroot = strdup(zone_altroot)) == NULL) {
730*f169c0eaSGlenn Lagasse 				be_print_err(gettext("be_get_legacy_fs: "
731*f169c0eaSGlenn Lagasse 				    "memory allocation failed\n"));
732*f169c0eaSGlenn Lagasse 				ret = BE_ERR_NOMEM;
733*f169c0eaSGlenn Lagasse 				goto cleanup;
734*f169c0eaSGlenn Lagasse 			}
735*f169c0eaSGlenn Lagasse 
736*f169c0eaSGlenn Lagasse 			if ((ret = be_mount_zone_root(zhp, &zone_md))
737*f169c0eaSGlenn Lagasse 			    != BE_SUCCESS) {
738*f169c0eaSGlenn Lagasse 				be_print_err(gettext("be_get_legacy_fs: "
739*f169c0eaSGlenn Lagasse 				    "failed to mount zone root %s\n"),
740*f169c0eaSGlenn Lagasse 				    zoneroot_ds);
741*f169c0eaSGlenn Lagasse 				free(zone_md.altroot);
742*f169c0eaSGlenn Lagasse 				zone_md.altroot = NULL;
743*f169c0eaSGlenn Lagasse 				goto cleanup;
744*f169c0eaSGlenn Lagasse 			}
745*f169c0eaSGlenn Lagasse 			zone_mounted_here = B_TRUE;
746*f169c0eaSGlenn Lagasse 		}
747*f169c0eaSGlenn Lagasse 
748*f169c0eaSGlenn Lagasse 		free(fld->altroot);
749*f169c0eaSGlenn Lagasse 		fld->altroot = zone_md.altroot;
750*f169c0eaSGlenn Lagasse 	}
751*f169c0eaSGlenn Lagasse 
752*f169c0eaSGlenn Lagasse 	/*
753*f169c0eaSGlenn Lagasse 	 * If the root dataset is in the vfstab with a mountpoint of "/",
754*f169c0eaSGlenn Lagasse 	 * add it to the list
755*f169c0eaSGlenn Lagasse 	 */
756*f169c0eaSGlenn Lagasse 	if (get_mountpoint_from_vfstab(fld->altroot, zfs_get_name(zhp),
757*f169c0eaSGlenn Lagasse 	    mountpoint, sizeof (mountpoint), B_FALSE) == BE_SUCCESS) {
758*f169c0eaSGlenn Lagasse 		if (strcmp(mountpoint, "/") == 0) {
759*f169c0eaSGlenn Lagasse 			if (add_to_fs_list(fld, zfs_get_name(zhp))
760*f169c0eaSGlenn Lagasse 			    != BE_SUCCESS) {
761*f169c0eaSGlenn Lagasse 				be_print_err(gettext("be_get_legacy_fs: "
762*f169c0eaSGlenn Lagasse 				    "failed to add %s to fs list\n"),
763*f169c0eaSGlenn Lagasse 				    zfs_get_name(zhp));
764*f169c0eaSGlenn Lagasse 				ret = BE_ERR_INVAL;
765*f169c0eaSGlenn Lagasse 				goto cleanup;
766*f169c0eaSGlenn Lagasse 			}
767*f169c0eaSGlenn Lagasse 		}
768*f169c0eaSGlenn Lagasse 	}
769*f169c0eaSGlenn Lagasse 
770*f169c0eaSGlenn Lagasse 	/* Iterate subordinate file systems looking for legacy mounts */
771*f169c0eaSGlenn Lagasse 	if ((ret = zfs_iter_filesystems(zhp, be_get_legacy_fs_callback,
772*f169c0eaSGlenn Lagasse 	    fld)) != 0) {
773*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_get_legacy_fs: "
774*f169c0eaSGlenn Lagasse 		    "failed to iterate  %s to get legacy mounts\n"),
775*f169c0eaSGlenn Lagasse 		    zfs_get_name(zhp));
776*f169c0eaSGlenn Lagasse 	}
777*f169c0eaSGlenn Lagasse 
778*f169c0eaSGlenn Lagasse cleanup:
779*f169c0eaSGlenn Lagasse 	/* If we mounted the zone BE, unmount it */
780*f169c0eaSGlenn Lagasse 	if (zone_mounted_here) {
781*f169c0eaSGlenn Lagasse 		be_unmount_data_t	zone_ud = { 0 };
782*f169c0eaSGlenn Lagasse 
783*f169c0eaSGlenn Lagasse 		zone_ud.altroot = fld->altroot;
784*f169c0eaSGlenn Lagasse 		zone_ud.force = B_TRUE;
785*f169c0eaSGlenn Lagasse 		if ((err = be_unmount_zone_root(zhp, &zone_ud)) != BE_SUCCESS) {
786*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_get_legacy_fs: "
787*f169c0eaSGlenn Lagasse 			    "failed to unmount zone root %s\n"),
788*f169c0eaSGlenn Lagasse 			    zoneroot_ds);
789*f169c0eaSGlenn Lagasse 			if (ret == BE_SUCCESS)
790*f169c0eaSGlenn Lagasse 				ret = err;
791*f169c0eaSGlenn Lagasse 		}
792*f169c0eaSGlenn Lagasse 	}
793*f169c0eaSGlenn Lagasse 
794*f169c0eaSGlenn Lagasse 	/* If we mounted this BE, unmount it */
795*f169c0eaSGlenn Lagasse 	if (mounted_here) {
796*f169c0eaSGlenn Lagasse 		if ((err = _be_unmount(be_name, 0)) != BE_SUCCESS) {
797*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_get_legacy_fs: "
798*f169c0eaSGlenn Lagasse 			    "failed to unmount %s\n"), be_name);
799*f169c0eaSGlenn Lagasse 			if (ret == BE_SUCCESS)
800*f169c0eaSGlenn Lagasse 				ret = err;
801*f169c0eaSGlenn Lagasse 		}
802*f169c0eaSGlenn Lagasse 	}
803*f169c0eaSGlenn Lagasse 
804*f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp);
805*f169c0eaSGlenn Lagasse 
806*f169c0eaSGlenn Lagasse 	free(fld->altroot);
807*f169c0eaSGlenn Lagasse 	fld->altroot = NULL;
808*f169c0eaSGlenn Lagasse 
809*f169c0eaSGlenn Lagasse 	return (ret);
810*f169c0eaSGlenn Lagasse }
811*f169c0eaSGlenn Lagasse 
812*f169c0eaSGlenn Lagasse /*
813*f169c0eaSGlenn Lagasse  * Function:	be_free_fs_list
814*f169c0eaSGlenn Lagasse  * Description:	Function used to free the members of a be_fs_list_data_t
815*f169c0eaSGlenn Lagasse  *			structure.
816*f169c0eaSGlenn Lagasse  * Parameters:
817*f169c0eaSGlenn Lagasse  *		fld - be_fs_list_data_t pointer to free.
818*f169c0eaSGlenn Lagasse  * Returns:
819*f169c0eaSGlenn Lagasse  *		None
820*f169c0eaSGlenn Lagasse  * Scope:
821*f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
822*f169c0eaSGlenn Lagasse  */
823*f169c0eaSGlenn Lagasse void
824*f169c0eaSGlenn Lagasse be_free_fs_list(be_fs_list_data_t *fld)
825*f169c0eaSGlenn Lagasse {
826*f169c0eaSGlenn Lagasse 	int	i;
827*f169c0eaSGlenn Lagasse 
828*f169c0eaSGlenn Lagasse 	if (fld == NULL)
829*f169c0eaSGlenn Lagasse 		return;
830*f169c0eaSGlenn Lagasse 
831*f169c0eaSGlenn Lagasse 	free(fld->altroot);
832*f169c0eaSGlenn Lagasse 
833*f169c0eaSGlenn Lagasse 	if (fld->fs_list == NULL)
834*f169c0eaSGlenn Lagasse 		return;
835*f169c0eaSGlenn Lagasse 
836*f169c0eaSGlenn Lagasse 	for (i = 0; i < fld->fs_num; i++)
837*f169c0eaSGlenn Lagasse 		free(fld->fs_list[i]);
838*f169c0eaSGlenn Lagasse 
839*f169c0eaSGlenn Lagasse 	free(fld->fs_list);
840*f169c0eaSGlenn Lagasse }
841*f169c0eaSGlenn Lagasse 
842*f169c0eaSGlenn Lagasse /*
843*f169c0eaSGlenn Lagasse  * Function:	be_get_ds_from_dir(char *dir)
844*f169c0eaSGlenn Lagasse  * Description:	Given a directory path, find the underlying dataset mounted
845*f169c0eaSGlenn Lagasse  *		at that directory path if there is one.   The returned name
846*f169c0eaSGlenn Lagasse  *		is allocated in heap storage, so the caller is responsible
847*f169c0eaSGlenn Lagasse  *		for freeing it.
848*f169c0eaSGlenn Lagasse  * Parameters:
849*f169c0eaSGlenn Lagasse  *		dir - char pointer of directory to find.
850*f169c0eaSGlenn Lagasse  * Returns:
851*f169c0eaSGlenn Lagasse  *		NULL - if directory is not mounted from a dataset.
852*f169c0eaSGlenn Lagasse  *		name of dataset mounted at dir.
853*f169c0eaSGlenn Lagasse  * Scope:
854*f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
855*f169c0eaSGlenn Lagasse  */
856*f169c0eaSGlenn Lagasse char *
857*f169c0eaSGlenn Lagasse be_get_ds_from_dir(char *dir)
858*f169c0eaSGlenn Lagasse {
859*f169c0eaSGlenn Lagasse 	dir_data_t	dd = { 0 };
860*f169c0eaSGlenn Lagasse 	char		resolved_dir[MAXPATHLEN];
861*f169c0eaSGlenn Lagasse 
862*f169c0eaSGlenn Lagasse 	/* Make sure length of dir is within the max length */
863*f169c0eaSGlenn Lagasse 	if (dir == NULL || strlen(dir) >= MAXPATHLEN)
864*f169c0eaSGlenn Lagasse 		return (NULL);
865*f169c0eaSGlenn Lagasse 
866*f169c0eaSGlenn Lagasse 	/* Resolve dir in case its lofs mounted */
867*f169c0eaSGlenn Lagasse 	(void) strlcpy(resolved_dir, dir, sizeof (resolved_dir));
868*f169c0eaSGlenn Lagasse 	z_resolve_lofs(resolved_dir, sizeof (resolved_dir));
869*f169c0eaSGlenn Lagasse 
870*f169c0eaSGlenn Lagasse 	dd.dir = resolved_dir;
871*f169c0eaSGlenn Lagasse 
872*f169c0eaSGlenn Lagasse 	(void) zfs_iter_root(g_zfs, be_get_ds_from_dir_callback, &dd);
873*f169c0eaSGlenn Lagasse 
874*f169c0eaSGlenn Lagasse 	return (dd.ds);
875*f169c0eaSGlenn Lagasse }
876*f169c0eaSGlenn Lagasse 
877*f169c0eaSGlenn Lagasse /*
878*f169c0eaSGlenn Lagasse  * Function:	be_make_tmp_mountpoint
879*f169c0eaSGlenn Lagasse  * Description:	This function generates a random temporary mountpoint
880*f169c0eaSGlenn Lagasse  *		and creates that mountpoint directory.  It returns the
881*f169c0eaSGlenn Lagasse  *		mountpoint in heap storage, so the caller is responsible
882*f169c0eaSGlenn Lagasse  *		for freeing it.
883*f169c0eaSGlenn Lagasse  * Parameters:
884*f169c0eaSGlenn Lagasse  *		tmp_mp - reference to pointer of where to store generated
885*f169c0eaSGlenn Lagasse  *			temporary mountpoint.
886*f169c0eaSGlenn Lagasse  * Returns:
887*f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
888*f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
889*f169c0eaSGlenn Lagasse  * Scope:
890*f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
891*f169c0eaSGlenn Lagasse  */
892*f169c0eaSGlenn Lagasse int
893*f169c0eaSGlenn Lagasse be_make_tmp_mountpoint(char **tmp_mp)
894*f169c0eaSGlenn Lagasse {
895*f169c0eaSGlenn Lagasse 	int	err = 0;
896*f169c0eaSGlenn Lagasse 
897*f169c0eaSGlenn Lagasse 	if ((*tmp_mp = (char *)calloc(1, sizeof (BE_TMP_MNTPNT) + 1)) == NULL) {
898*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_make_tmp_mountpoint: "
899*f169c0eaSGlenn Lagasse 		    "malloc failed\n"));
900*f169c0eaSGlenn Lagasse 		return (BE_ERR_NOMEM);
901*f169c0eaSGlenn Lagasse 	}
902*f169c0eaSGlenn Lagasse 	(void) strlcpy(*tmp_mp, BE_TMP_MNTPNT, sizeof (BE_TMP_MNTPNT) + 1);
903*f169c0eaSGlenn Lagasse 	if (mkdtemp(*tmp_mp) == NULL) {
904*f169c0eaSGlenn Lagasse 		err = errno;
905*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_make_tmp_mountpoint: mkdtemp() failed "
906*f169c0eaSGlenn Lagasse 		    "for %s: %s\n"), *tmp_mp, strerror(err));
907*f169c0eaSGlenn Lagasse 		free(*tmp_mp);
908*f169c0eaSGlenn Lagasse 		*tmp_mp = NULL;
909*f169c0eaSGlenn Lagasse 		return (errno_to_be_err(err));
910*f169c0eaSGlenn Lagasse 	}
911*f169c0eaSGlenn Lagasse 
912*f169c0eaSGlenn Lagasse 	return (BE_SUCCESS);
913*f169c0eaSGlenn Lagasse }
914*f169c0eaSGlenn Lagasse 
915*f169c0eaSGlenn Lagasse /*
916*f169c0eaSGlenn Lagasse  * Function:	be_mount_pool
917*f169c0eaSGlenn Lagasse  * Description: This function determines if the pool's datase is mounted
918*f169c0eaSGlenn Lagasse  *		and if not it is used to mount the pool's dataset. The
919*f169c0eaSGlenn Lagasse  *		function returns the current mountpoint if we are able
920*f169c0eaSGlenn Lagasse  *		to mount the dataset.
921*f169c0eaSGlenn Lagasse  * Parameters:
922*f169c0eaSGlenn Lagasse  *		zhp - handle to the pool's dataset
923*f169c0eaSGlenn Lagasse  *		tmp_mntpnt - The temporary mountpoint that the pool's
924*f169c0eaSGlenn Lagasse  *			      dataset is mounted on. This is set only
925*f169c0eaSGlenn Lagasse  *			      if the attempt to mount the dataset at it's
926*f169c0eaSGlenn Lagasse  *			      set mountpoint fails, and we've used a
927*f169c0eaSGlenn Lagasse  *			      temporary mount point for this dataset. It
928*f169c0eaSGlenn Lagasse  *			      is expected that the caller will free this
929*f169c0eaSGlenn Lagasse  *			      memory.
930*f169c0eaSGlenn Lagasse  *		orig_mntpnt - The original mountpoint for the pool. If a
931*f169c0eaSGlenn Lagasse  *			      temporary mount point was needed this will
932*f169c0eaSGlenn Lagasse  *			      be used to reset the mountpoint property to
933*f169c0eaSGlenn Lagasse  *			      it's original mountpoint. It is expected that
934*f169c0eaSGlenn Lagasse  *			      the caller will free this memory.
935*f169c0eaSGlenn Lagasse  *		pool_mounted - This flag indicates that the pool was mounted
936*f169c0eaSGlenn Lagasse  *			       in this function.
937*f169c0eaSGlenn Lagasse  * Returns:
938*f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
939*f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
940*f169c0eaSGlenn Lagasse  * Scope:
941*f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
942*f169c0eaSGlenn Lagasse  */
943*f169c0eaSGlenn Lagasse int
944*f169c0eaSGlenn Lagasse be_mount_pool(
945*f169c0eaSGlenn Lagasse 	zfs_handle_t *zhp,
946*f169c0eaSGlenn Lagasse 	char **tmp_mntpnt,
947*f169c0eaSGlenn Lagasse 	char **orig_mntpnt,
948*f169c0eaSGlenn Lagasse 	boolean_t *pool_mounted)
949*f169c0eaSGlenn Lagasse {
950*f169c0eaSGlenn Lagasse 
951*f169c0eaSGlenn Lagasse 	char		mountpoint[MAXPATHLEN];
952*f169c0eaSGlenn Lagasse 	int		ret = 0;
953*f169c0eaSGlenn Lagasse 
954*f169c0eaSGlenn Lagasse 	*tmp_mntpnt = NULL;
955*f169c0eaSGlenn Lagasse 	*orig_mntpnt = NULL;
956*f169c0eaSGlenn Lagasse 	*pool_mounted = B_FALSE;
957*f169c0eaSGlenn Lagasse 
958*f169c0eaSGlenn Lagasse 	if (!zfs_is_mounted(zhp, NULL)) {
959*f169c0eaSGlenn Lagasse 		if (zfs_mount(zhp, NULL, 0) != 0) {
960*f169c0eaSGlenn Lagasse 			if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint,
961*f169c0eaSGlenn Lagasse 			    sizeof (mountpoint), NULL, NULL, 0, B_FALSE) != 0) {
962*f169c0eaSGlenn Lagasse 				be_print_err(gettext("be_mount_pool: failed to "
963*f169c0eaSGlenn Lagasse 				    "get mountpoint of (%s): %s\n"),
964*f169c0eaSGlenn Lagasse 				    zfs_get_name(zhp),
965*f169c0eaSGlenn Lagasse 				    libzfs_error_description(g_zfs));
966*f169c0eaSGlenn Lagasse 				return (zfs_err_to_be_err(g_zfs));
967*f169c0eaSGlenn Lagasse 			}
968*f169c0eaSGlenn Lagasse 			if ((*orig_mntpnt = strdup(mountpoint)) == NULL) {
969*f169c0eaSGlenn Lagasse 				be_print_err(gettext("be_mount_pool: memory "
970*f169c0eaSGlenn Lagasse 				    "allocation failed\n"));
971*f169c0eaSGlenn Lagasse 				return (BE_ERR_NOMEM);
972*f169c0eaSGlenn Lagasse 			}
973*f169c0eaSGlenn Lagasse 			/*
974*f169c0eaSGlenn Lagasse 			 * attempt to mount on a temp mountpoint
975*f169c0eaSGlenn Lagasse 			 */
976*f169c0eaSGlenn Lagasse 			if ((ret = be_make_tmp_mountpoint(tmp_mntpnt))
977*f169c0eaSGlenn Lagasse 			    != BE_SUCCESS) {
978*f169c0eaSGlenn Lagasse 				be_print_err(gettext("be_mount_pool: failed "
979*f169c0eaSGlenn Lagasse 				    "to make temporary mountpoint\n"));
980*f169c0eaSGlenn Lagasse 				free(*orig_mntpnt);
981*f169c0eaSGlenn Lagasse 				*orig_mntpnt = NULL;
982*f169c0eaSGlenn Lagasse 				return (ret);
983*f169c0eaSGlenn Lagasse 			}
984*f169c0eaSGlenn Lagasse 
985*f169c0eaSGlenn Lagasse 			if (zfs_prop_set(zhp,
986*f169c0eaSGlenn Lagasse 			    zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
987*f169c0eaSGlenn Lagasse 			    *tmp_mntpnt) != 0) {
988*f169c0eaSGlenn Lagasse 				be_print_err(gettext("be_mount_pool: failed "
989*f169c0eaSGlenn Lagasse 				    "to set mountpoint of pool dataset %s to "
990*f169c0eaSGlenn Lagasse 				    "%s: %s\n"), zfs_get_name(zhp),
991*f169c0eaSGlenn Lagasse 				    *orig_mntpnt,
992*f169c0eaSGlenn Lagasse 				    libzfs_error_description(g_zfs));
993*f169c0eaSGlenn Lagasse 				free(*tmp_mntpnt);
994*f169c0eaSGlenn Lagasse 				free(*orig_mntpnt);
995*f169c0eaSGlenn Lagasse 				*orig_mntpnt = NULL;
996*f169c0eaSGlenn Lagasse 				*tmp_mntpnt = NULL;
997*f169c0eaSGlenn Lagasse 				return (zfs_err_to_be_err(g_zfs));
998*f169c0eaSGlenn Lagasse 			}
999*f169c0eaSGlenn Lagasse 
1000*f169c0eaSGlenn Lagasse 			if (zfs_mount(zhp, NULL, 0) != 0) {
1001*f169c0eaSGlenn Lagasse 				be_print_err(gettext("be_mount_pool: failed "
1002*f169c0eaSGlenn Lagasse 				    "to mount dataset %s at %s: %s\n"),
1003*f169c0eaSGlenn Lagasse 				    zfs_get_name(zhp), *tmp_mntpnt,
1004*f169c0eaSGlenn Lagasse 				    libzfs_error_description(g_zfs));
1005*f169c0eaSGlenn Lagasse 				ret = zfs_err_to_be_err(g_zfs);
1006*f169c0eaSGlenn Lagasse 				if (zfs_prop_set(zhp,
1007*f169c0eaSGlenn Lagasse 				    zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
1008*f169c0eaSGlenn Lagasse 				    mountpoint) != 0) {
1009*f169c0eaSGlenn Lagasse 					be_print_err(gettext("be_mount_pool: "
1010*f169c0eaSGlenn Lagasse 					    "failed to set mountpoint of pool "
1011*f169c0eaSGlenn Lagasse 					    "dataset %s to %s: %s\n"),
1012*f169c0eaSGlenn Lagasse 					    zfs_get_name(zhp), *tmp_mntpnt,
1013*f169c0eaSGlenn Lagasse 					    libzfs_error_description(g_zfs));
1014*f169c0eaSGlenn Lagasse 				}
1015*f169c0eaSGlenn Lagasse 				free(*tmp_mntpnt);
1016*f169c0eaSGlenn Lagasse 				free(*orig_mntpnt);
1017*f169c0eaSGlenn Lagasse 				*orig_mntpnt = NULL;
1018*f169c0eaSGlenn Lagasse 				*tmp_mntpnt = NULL;
1019*f169c0eaSGlenn Lagasse 				return (ret);
1020*f169c0eaSGlenn Lagasse 			}
1021*f169c0eaSGlenn Lagasse 		}
1022*f169c0eaSGlenn Lagasse 		*pool_mounted = B_TRUE;
1023*f169c0eaSGlenn Lagasse 	}
1024*f169c0eaSGlenn Lagasse 
1025*f169c0eaSGlenn Lagasse 	return (BE_SUCCESS);
1026*f169c0eaSGlenn Lagasse }
1027*f169c0eaSGlenn Lagasse 
1028*f169c0eaSGlenn Lagasse /*
1029*f169c0eaSGlenn Lagasse  * Function:	be_unmount_pool
1030*f169c0eaSGlenn Lagasse  * Description: This function is used to unmount the pool's dataset if we
1031*f169c0eaSGlenn Lagasse  *		mounted it previously using be_mount_pool().
1032*f169c0eaSGlenn Lagasse  * Parameters:
1033*f169c0eaSGlenn Lagasse  *		zhp - handle to the pool's dataset
1034*f169c0eaSGlenn Lagasse  *		tmp_mntpnt - If a temprary mount point was used this will
1035*f169c0eaSGlenn Lagasse  *			     be set. Since this was created in be_mount_pool
1036*f169c0eaSGlenn Lagasse  *			     we will need to clean it up here.
1037*f169c0eaSGlenn Lagasse  *		orig_mntpnt - The original mountpoint for the pool. This is
1038*f169c0eaSGlenn Lagasse  *			      used to set the dataset mountpoint property
1039*f169c0eaSGlenn Lagasse  *			      back to it's original value in the case where a
1040*f169c0eaSGlenn Lagasse  *			      temporary mountpoint was used.
1041*f169c0eaSGlenn Lagasse  * Returns:
1042*f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
1043*f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
1044*f169c0eaSGlenn Lagasse  * Scope:
1045*f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
1046*f169c0eaSGlenn Lagasse  */
1047*f169c0eaSGlenn Lagasse int
1048*f169c0eaSGlenn Lagasse be_unmount_pool(
1049*f169c0eaSGlenn Lagasse 	zfs_handle_t *zhp,
1050*f169c0eaSGlenn Lagasse 	char *tmp_mntpnt,
1051*f169c0eaSGlenn Lagasse 	char *orig_mntpnt)
1052*f169c0eaSGlenn Lagasse {
1053*f169c0eaSGlenn Lagasse 	if (zfs_unmount(zhp, NULL, 0) != 0) {
1054*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_unmount_pool: failed to "
1055*f169c0eaSGlenn Lagasse 		    "unmount pool (%s): %s\n"), zfs_get_name(zhp),
1056*f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
1057*f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
1058*f169c0eaSGlenn Lagasse 	}
1059*f169c0eaSGlenn Lagasse 	if (orig_mntpnt != NULL) {
1060*f169c0eaSGlenn Lagasse 		if (tmp_mntpnt != NULL &&
1061*f169c0eaSGlenn Lagasse 		    strcmp(orig_mntpnt, tmp_mntpnt) != 0) {
1062*f169c0eaSGlenn Lagasse 			(void) rmdir(tmp_mntpnt);
1063*f169c0eaSGlenn Lagasse 		}
1064*f169c0eaSGlenn Lagasse 		if (zfs_prop_set(zhp,
1065*f169c0eaSGlenn Lagasse 		    zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
1066*f169c0eaSGlenn Lagasse 		    orig_mntpnt) != 0) {
1067*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_unmount_pool: failed "
1068*f169c0eaSGlenn Lagasse 			    "to set the mountpoint for dataset (%s) to "
1069*f169c0eaSGlenn Lagasse 			    "%s: %s\n"), zfs_get_name(zhp), orig_mntpnt,
1070*f169c0eaSGlenn Lagasse 			    libzfs_error_description(g_zfs));
1071*f169c0eaSGlenn Lagasse 			return (zfs_err_to_be_err(g_zfs));
1072*f169c0eaSGlenn Lagasse 		}
1073*f169c0eaSGlenn Lagasse 	}
1074*f169c0eaSGlenn Lagasse 
1075*f169c0eaSGlenn Lagasse 	return (BE_SUCCESS);
1076*f169c0eaSGlenn Lagasse }
1077*f169c0eaSGlenn Lagasse 
1078*f169c0eaSGlenn Lagasse /* ********************************************************************	*/
1079*f169c0eaSGlenn Lagasse /*			Private Functions				*/
1080*f169c0eaSGlenn Lagasse /* ********************************************************************	*/
1081*f169c0eaSGlenn Lagasse 
1082*f169c0eaSGlenn Lagasse /*
1083*f169c0eaSGlenn Lagasse  * Function:	be_mount_callback
1084*f169c0eaSGlenn Lagasse  * Description:	Callback function used to iterate through all of a BE's
1085*f169c0eaSGlenn Lagasse  *		subordinate file systems and to mount them accordingly.
1086*f169c0eaSGlenn Lagasse  * Parameters:
1087*f169c0eaSGlenn Lagasse  *		zhp - zfs_handle_t pointer to current file system being
1088*f169c0eaSGlenn Lagasse  *			processed.
1089*f169c0eaSGlenn Lagasse  *		data - pointer to the altroot of where to mount BE.
1090*f169c0eaSGlenn Lagasse  * Returns:
1091*f169c0eaSGlenn Lagasse  *		0 - Success
1092*f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
1093*f169c0eaSGlenn Lagasse  * Scope:
1094*f169c0eaSGlenn Lagasse  *		Private
1095*f169c0eaSGlenn Lagasse  */
1096*f169c0eaSGlenn Lagasse static int
1097*f169c0eaSGlenn Lagasse be_mount_callback(zfs_handle_t *zhp, void *data)
1098*f169c0eaSGlenn Lagasse {
1099*f169c0eaSGlenn Lagasse 	zprop_source_t	sourcetype;
1100*f169c0eaSGlenn Lagasse 	const char	*fs_name = zfs_get_name(zhp);
1101*f169c0eaSGlenn Lagasse 	char		source[ZFS_MAXNAMELEN];
1102*f169c0eaSGlenn Lagasse 	char		*altroot = data;
1103*f169c0eaSGlenn Lagasse 	char		zhp_mountpoint[MAXPATHLEN];
1104*f169c0eaSGlenn Lagasse 	char		mountpoint[MAXPATHLEN];
1105*f169c0eaSGlenn Lagasse 	int		ret = 0;
1106*f169c0eaSGlenn Lagasse 
1107*f169c0eaSGlenn Lagasse 	/* Get dataset's mountpoint and source values */
1108*f169c0eaSGlenn Lagasse 	if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, zhp_mountpoint,
1109*f169c0eaSGlenn Lagasse 	    sizeof (zhp_mountpoint), &sourcetype, source, sizeof (source),
1110*f169c0eaSGlenn Lagasse 	    B_FALSE) != 0) {
1111*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_mount_callback: failed to "
1112*f169c0eaSGlenn Lagasse 		    "get mountpoint and sourcetype for %s\n"),
1113*f169c0eaSGlenn Lagasse 		    fs_name);
1114*f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
1115*f169c0eaSGlenn Lagasse 		return (BE_ERR_ZFS);
1116*f169c0eaSGlenn Lagasse 	}
1117*f169c0eaSGlenn Lagasse 
1118*f169c0eaSGlenn Lagasse 	/*
1119*f169c0eaSGlenn Lagasse 	 * Set this filesystem's 'canmount' property to 'noauto' just incase
1120*f169c0eaSGlenn Lagasse 	 * it's been set 'on'.  We do this so that when we change its
1121*f169c0eaSGlenn Lagasse 	 * mountpoint zfs won't immediately try to mount it.
1122*f169c0eaSGlenn Lagasse 	 */
1123*f169c0eaSGlenn Lagasse 	if (zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_CANMOUNT), "noauto")) {
1124*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_mount_callback: failed to "
1125*f169c0eaSGlenn Lagasse 		    "set canmount to 'noauto' (%s)\n"), fs_name);
1126*f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
1127*f169c0eaSGlenn Lagasse 		return (BE_ERR_ZFS);
1128*f169c0eaSGlenn Lagasse 	}
1129*f169c0eaSGlenn Lagasse 
1130*f169c0eaSGlenn Lagasse 	/*
1131*f169c0eaSGlenn Lagasse 	 * If the mountpoint is none, there's nothing to do, goto next.
1132*f169c0eaSGlenn Lagasse 	 * If the mountpoint is legacy, legacy mount it with mount(2).
1133*f169c0eaSGlenn Lagasse 	 * If the mountpoint is inherited, its mountpoint should
1134*f169c0eaSGlenn Lagasse 	 * already be set.  If it's not, then explicitly fix-up
1135*f169c0eaSGlenn Lagasse 	 * the mountpoint now by appending its explicitly set
1136*f169c0eaSGlenn Lagasse 	 * mountpoint value to the BE mountpoint.
1137*f169c0eaSGlenn Lagasse 	 */
1138*f169c0eaSGlenn Lagasse 	if (strcmp(zhp_mountpoint, ZFS_MOUNTPOINT_NONE) == 0) {
1139*f169c0eaSGlenn Lagasse 		goto next;
1140*f169c0eaSGlenn Lagasse 	} else if (strcmp(zhp_mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0) {
1141*f169c0eaSGlenn Lagasse 		/*
1142*f169c0eaSGlenn Lagasse 		 * If the mountpoint is set to 'legacy', we need to
1143*f169c0eaSGlenn Lagasse 		 * dig into this BE's vfstab to figure out where to
1144*f169c0eaSGlenn Lagasse 		 * mount it, and just mount it via mount(2).
1145*f169c0eaSGlenn Lagasse 		 */
1146*f169c0eaSGlenn Lagasse 		if (get_mountpoint_from_vfstab(altroot, fs_name,
1147*f169c0eaSGlenn Lagasse 		    mountpoint, sizeof (mountpoint), B_TRUE) == BE_SUCCESS) {
1148*f169c0eaSGlenn Lagasse 
1149*f169c0eaSGlenn Lagasse 			/* Legacy mount the file system */
1150*f169c0eaSGlenn Lagasse 			if (mount(fs_name, mountpoint, MS_DATA,
1151*f169c0eaSGlenn Lagasse 			    MNTTYPE_ZFS, NULL, 0, NULL, 0) != 0) {
1152*f169c0eaSGlenn Lagasse 				be_print_err(
1153*f169c0eaSGlenn Lagasse 				    gettext("be_mount_callback: "
1154*f169c0eaSGlenn Lagasse 				    "failed to mount %s on %s\n"),
1155*f169c0eaSGlenn Lagasse 				    fs_name, mountpoint);
1156*f169c0eaSGlenn Lagasse 			}
1157*f169c0eaSGlenn Lagasse 		} else {
1158*f169c0eaSGlenn Lagasse 			be_print_err(
1159*f169c0eaSGlenn Lagasse 			    gettext("be_mount_callback: "
1160*f169c0eaSGlenn Lagasse 			    "no entry for %s in vfstab, "
1161*f169c0eaSGlenn Lagasse 			    "skipping ...\n"), fs_name);
1162*f169c0eaSGlenn Lagasse 		}
1163*f169c0eaSGlenn Lagasse 
1164*f169c0eaSGlenn Lagasse 		goto next;
1165*f169c0eaSGlenn Lagasse 
1166*f169c0eaSGlenn Lagasse 	} else if (sourcetype & ZPROP_SRC_INHERITED) {
1167*f169c0eaSGlenn Lagasse 		/*
1168*f169c0eaSGlenn Lagasse 		 * If the mountpoint is inherited, its parent should have
1169*f169c0eaSGlenn Lagasse 		 * already been processed so its current mountpoint value
1170*f169c0eaSGlenn Lagasse 		 * is what its mountpoint ought to be.
1171*f169c0eaSGlenn Lagasse 		 */
1172*f169c0eaSGlenn Lagasse 		(void) strlcpy(mountpoint, zhp_mountpoint, sizeof (mountpoint));
1173*f169c0eaSGlenn Lagasse 	} else if (sourcetype & ZPROP_SRC_LOCAL) {
1174*f169c0eaSGlenn Lagasse 		/*
1175*f169c0eaSGlenn Lagasse 		 * Else process dataset with explicitly set mountpoint.
1176*f169c0eaSGlenn Lagasse 		 */
1177*f169c0eaSGlenn Lagasse 		(void) snprintf(mountpoint, sizeof (mountpoint),
1178*f169c0eaSGlenn Lagasse 		    "%s%s", altroot, zhp_mountpoint);
1179*f169c0eaSGlenn Lagasse 
1180*f169c0eaSGlenn Lagasse 		/* Set the new mountpoint for the dataset */
1181*f169c0eaSGlenn Lagasse 		if (zfs_prop_set(zhp,
1182*f169c0eaSGlenn Lagasse 		    zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
1183*f169c0eaSGlenn Lagasse 		    mountpoint)) {
1184*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_mount_callback: "
1185*f169c0eaSGlenn Lagasse 			    "failed to set mountpoint for %s to "
1186*f169c0eaSGlenn Lagasse 			    "%s\n"), fs_name, mountpoint);
1187*f169c0eaSGlenn Lagasse 			ZFS_CLOSE(zhp);
1188*f169c0eaSGlenn Lagasse 			return (BE_ERR_ZFS);
1189*f169c0eaSGlenn Lagasse 		}
1190*f169c0eaSGlenn Lagasse 	} else {
1191*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_mount_callback: "
1192*f169c0eaSGlenn Lagasse 		    "mountpoint sourcetype of %s is %d, skipping ...\n"),
1193*f169c0eaSGlenn Lagasse 		    fs_name, sourcetype);
1194*f169c0eaSGlenn Lagasse 
1195*f169c0eaSGlenn Lagasse 		goto next;
1196*f169c0eaSGlenn Lagasse 	}
1197*f169c0eaSGlenn Lagasse 
1198*f169c0eaSGlenn Lagasse 	/* Mount this filesystem */
1199*f169c0eaSGlenn Lagasse 	if (zfs_mount(zhp, NULL, 0) != 0) {
1200*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_mount_callback: failed to "
1201*f169c0eaSGlenn Lagasse 		    "mount dataset %s at %s: %s\n"), fs_name, mountpoint,
1202*f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
1203*f169c0eaSGlenn Lagasse 		/*
1204*f169c0eaSGlenn Lagasse 		 * Set this filesystem's 'mountpoint' property back to what
1205*f169c0eaSGlenn Lagasse 		 * it was
1206*f169c0eaSGlenn Lagasse 		 */
1207*f169c0eaSGlenn Lagasse 		if (sourcetype & ZPROP_SRC_LOCAL &&
1208*f169c0eaSGlenn Lagasse 		    strcmp(zhp_mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0) {
1209*f169c0eaSGlenn Lagasse 			(void) zfs_prop_set(zhp,
1210*f169c0eaSGlenn Lagasse 			    zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
1211*f169c0eaSGlenn Lagasse 			    zhp_mountpoint);
1212*f169c0eaSGlenn Lagasse 		}
1213*f169c0eaSGlenn Lagasse 
1214*f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
1215*f169c0eaSGlenn Lagasse 		return (BE_ERR_MOUNT);
1216*f169c0eaSGlenn Lagasse 	}
1217*f169c0eaSGlenn Lagasse 
1218*f169c0eaSGlenn Lagasse next:
1219*f169c0eaSGlenn Lagasse 	/* Iterate through this dataset's children and mount them */
1220*f169c0eaSGlenn Lagasse 	if ((ret = zfs_iter_filesystems(zhp, be_mount_callback,
1221*f169c0eaSGlenn Lagasse 	    altroot)) != 0) {
1222*f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
1223*f169c0eaSGlenn Lagasse 		return (ret);
1224*f169c0eaSGlenn Lagasse 	}
1225*f169c0eaSGlenn Lagasse 
1226*f169c0eaSGlenn Lagasse 
1227*f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp);
1228*f169c0eaSGlenn Lagasse 	return (0);
1229*f169c0eaSGlenn Lagasse }
1230*f169c0eaSGlenn Lagasse 
1231*f169c0eaSGlenn Lagasse /*
1232*f169c0eaSGlenn Lagasse  * Function:	be_unmount_callback
1233*f169c0eaSGlenn Lagasse  * Description:	Callback function used to iterate through all of a BE's
1234*f169c0eaSGlenn Lagasse  *		subordinate file systems and to unmount them.
1235*f169c0eaSGlenn Lagasse  * Parameters:
1236*f169c0eaSGlenn Lagasse  *		zhp - zfs_handle_t pointer to current file system being
1237*f169c0eaSGlenn Lagasse  *			processed.
1238*f169c0eaSGlenn Lagasse  *		data - pointer to the mountpoint of where BE is mounted.
1239*f169c0eaSGlenn Lagasse  * Returns:
1240*f169c0eaSGlenn Lagasse  *		0 - Success
1241*f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
1242*f169c0eaSGlenn Lagasse  * Scope:
1243*f169c0eaSGlenn Lagasse  *		Private
1244*f169c0eaSGlenn Lagasse  */
1245*f169c0eaSGlenn Lagasse static int
1246*f169c0eaSGlenn Lagasse be_unmount_callback(zfs_handle_t *zhp, void *data)
1247*f169c0eaSGlenn Lagasse {
1248*f169c0eaSGlenn Lagasse 	be_unmount_data_t	*ud = data;
1249*f169c0eaSGlenn Lagasse 	zprop_source_t	sourcetype;
1250*f169c0eaSGlenn Lagasse 	const char	*fs_name = zfs_get_name(zhp);
1251*f169c0eaSGlenn Lagasse 	char		source[ZFS_MAXNAMELEN];
1252*f169c0eaSGlenn Lagasse 	char		mountpoint[MAXPATHLEN];
1253*f169c0eaSGlenn Lagasse 	char		*zhp_mountpoint;
1254*f169c0eaSGlenn Lagasse 	int		ret = 0;
1255*f169c0eaSGlenn Lagasse 
1256*f169c0eaSGlenn Lagasse 	/* Iterate down this dataset's children first */
1257*f169c0eaSGlenn Lagasse 	if (zfs_iter_filesystems(zhp, be_unmount_callback, ud)) {
1258*f169c0eaSGlenn Lagasse 		ret = BE_ERR_UMOUNT;
1259*f169c0eaSGlenn Lagasse 		goto done;
1260*f169c0eaSGlenn Lagasse 	}
1261*f169c0eaSGlenn Lagasse 
1262*f169c0eaSGlenn Lagasse 	/* Is dataset even mounted ? */
1263*f169c0eaSGlenn Lagasse 	if (!zfs_is_mounted(zhp, NULL))
1264*f169c0eaSGlenn Lagasse 		goto done;
1265*f169c0eaSGlenn Lagasse 
1266*f169c0eaSGlenn Lagasse 	/* Unmount this file system */
1267*f169c0eaSGlenn Lagasse 	if (zfs_unmount(zhp, NULL, ud->force ? MS_FORCE : 0) != 0) {
1268*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_unmount_callback: "
1269*f169c0eaSGlenn Lagasse 		    "failed to unmount %s: %s\n"), fs_name,
1270*f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
1271*f169c0eaSGlenn Lagasse 		ret = zfs_err_to_be_err(g_zfs);
1272*f169c0eaSGlenn Lagasse 		goto done;
1273*f169c0eaSGlenn Lagasse 	}
1274*f169c0eaSGlenn Lagasse 
1275*f169c0eaSGlenn Lagasse 	/* Get dataset's current mountpoint and source value */
1276*f169c0eaSGlenn Lagasse 	if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint,
1277*f169c0eaSGlenn Lagasse 	    sizeof (mountpoint), &sourcetype, source, sizeof (source),
1278*f169c0eaSGlenn Lagasse 	    B_FALSE) != 0) {
1279*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_unmount_callback: "
1280*f169c0eaSGlenn Lagasse 		    "failed to get mountpoint and sourcetype for %s: %s\n"),
1281*f169c0eaSGlenn Lagasse 		    fs_name, libzfs_error_description(g_zfs));
1282*f169c0eaSGlenn Lagasse 		ret = zfs_err_to_be_err(g_zfs);
1283*f169c0eaSGlenn Lagasse 		goto done;
1284*f169c0eaSGlenn Lagasse 	}
1285*f169c0eaSGlenn Lagasse 
1286*f169c0eaSGlenn Lagasse 	if (sourcetype & ZPROP_SRC_INHERITED) {
1287*f169c0eaSGlenn Lagasse 		/*
1288*f169c0eaSGlenn Lagasse 		 * If the mountpoint is inherited we don't need to
1289*f169c0eaSGlenn Lagasse 		 * do anything.  When its parent gets processed
1290*f169c0eaSGlenn Lagasse 		 * its mountpoint will be set accordingly.
1291*f169c0eaSGlenn Lagasse 		 */
1292*f169c0eaSGlenn Lagasse 		goto done;
1293*f169c0eaSGlenn Lagasse 	} else if (sourcetype & ZPROP_SRC_LOCAL) {
1294*f169c0eaSGlenn Lagasse 
1295*f169c0eaSGlenn Lagasse 		if (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0) {
1296*f169c0eaSGlenn Lagasse 			/*
1297*f169c0eaSGlenn Lagasse 			 * If the mountpoint is set to 'legacy', its already
1298*f169c0eaSGlenn Lagasse 			 * been unmounted (from above call to zfs_unmount), and
1299*f169c0eaSGlenn Lagasse 			 * we don't need to do anything else with it.
1300*f169c0eaSGlenn Lagasse 			 */
1301*f169c0eaSGlenn Lagasse 			goto done;
1302*f169c0eaSGlenn Lagasse 
1303*f169c0eaSGlenn Lagasse 		} else {
1304*f169c0eaSGlenn Lagasse 			/*
1305*f169c0eaSGlenn Lagasse 			 * Else process dataset with explicitly set mountpoint.
1306*f169c0eaSGlenn Lagasse 			 */
1307*f169c0eaSGlenn Lagasse 
1308*f169c0eaSGlenn Lagasse 			/*
1309*f169c0eaSGlenn Lagasse 			 * Get this dataset's mountpoint relative to
1310*f169c0eaSGlenn Lagasse 			 * the BE's mountpoint.
1311*f169c0eaSGlenn Lagasse 			 */
1312*f169c0eaSGlenn Lagasse 			if ((strncmp(mountpoint, ud->altroot,
1313*f169c0eaSGlenn Lagasse 			    strlen(ud->altroot)) == 0) &&
1314*f169c0eaSGlenn Lagasse 			    (mountpoint[strlen(ud->altroot)] == '/')) {
1315*f169c0eaSGlenn Lagasse 
1316*f169c0eaSGlenn Lagasse 				zhp_mountpoint = mountpoint +
1317*f169c0eaSGlenn Lagasse 				    strlen(ud->altroot);
1318*f169c0eaSGlenn Lagasse 
1319*f169c0eaSGlenn Lagasse 				/* Set this dataset's mountpoint value */
1320*f169c0eaSGlenn Lagasse 				if (zfs_prop_set(zhp,
1321*f169c0eaSGlenn Lagasse 				    zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
1322*f169c0eaSGlenn Lagasse 				    zhp_mountpoint)) {
1323*f169c0eaSGlenn Lagasse 					be_print_err(
1324*f169c0eaSGlenn Lagasse 					    gettext("be_unmount_callback: "
1325*f169c0eaSGlenn Lagasse 					    "failed to set mountpoint for "
1326*f169c0eaSGlenn Lagasse 					    "%s to %s: %s\n"), fs_name,
1327*f169c0eaSGlenn Lagasse 					    zhp_mountpoint,
1328*f169c0eaSGlenn Lagasse 					    libzfs_error_description(g_zfs));
1329*f169c0eaSGlenn Lagasse 					ret = zfs_err_to_be_err(g_zfs);
1330*f169c0eaSGlenn Lagasse 				}
1331*f169c0eaSGlenn Lagasse 			} else {
1332*f169c0eaSGlenn Lagasse 				be_print_err(
1333*f169c0eaSGlenn Lagasse 				    gettext("be_unmount_callback: "
1334*f169c0eaSGlenn Lagasse 				    "%s not mounted under BE's altroot %s, "
1335*f169c0eaSGlenn Lagasse 				    "skipping ...\n"), fs_name, ud->altroot);
1336*f169c0eaSGlenn Lagasse 				/*
1337*f169c0eaSGlenn Lagasse 				 * fs_name is mounted but not under the
1338*f169c0eaSGlenn Lagasse 				 * root for this BE.
1339*f169c0eaSGlenn Lagasse 				 */
1340*f169c0eaSGlenn Lagasse 				ret = BE_ERR_INVALMOUNTPOINT;
1341*f169c0eaSGlenn Lagasse 			}
1342*f169c0eaSGlenn Lagasse 		}
1343*f169c0eaSGlenn Lagasse 	} else {
1344*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_unmount_callback: "
1345*f169c0eaSGlenn Lagasse 		    "mountpoint sourcetype of %s is %d, skipping ...\n"),
1346*f169c0eaSGlenn Lagasse 		    fs_name, sourcetype);
1347*f169c0eaSGlenn Lagasse 		ret = BE_ERR_ZFS;
1348*f169c0eaSGlenn Lagasse 	}
1349*f169c0eaSGlenn Lagasse 
1350*f169c0eaSGlenn Lagasse done:
1351*f169c0eaSGlenn Lagasse 	/* Set this filesystem's 'canmount' property to 'noauto' */
1352*f169c0eaSGlenn Lagasse 	if (zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_CANMOUNT), "noauto")) {
1353*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_unmount_callback: "
1354*f169c0eaSGlenn Lagasse 		    "failed to set canmount to 'noauto' (%s)\n"), fs_name);
1355*f169c0eaSGlenn Lagasse 		if (ret == 0)
1356*f169c0eaSGlenn Lagasse 			ret = BE_ERR_ZFS;
1357*f169c0eaSGlenn Lagasse 	}
1358*f169c0eaSGlenn Lagasse 
1359*f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp);
1360*f169c0eaSGlenn Lagasse 	return (ret);
1361*f169c0eaSGlenn Lagasse }
1362*f169c0eaSGlenn Lagasse 
1363*f169c0eaSGlenn Lagasse /*
1364*f169c0eaSGlenn Lagasse  * Function:	be_get_legacy_fs_callback
1365*f169c0eaSGlenn Lagasse  * Description:	The callback function is used to iterate through all
1366*f169c0eaSGlenn Lagasse  *		non-shared file systems of a BE, finding ones that have
1367*f169c0eaSGlenn Lagasse  *		a legacy mountpoint and an entry in the BE's vfstab.
1368*f169c0eaSGlenn Lagasse  *		It adds these file systems to the callback data.
1369*f169c0eaSGlenn Lagasse  * Parameters:
1370*f169c0eaSGlenn Lagasse  *		zhp - zfs_handle_t pointer to current file system being
1371*f169c0eaSGlenn Lagasse  *			processed.
1372*f169c0eaSGlenn Lagasse  *		data - be_fs_list_data_t pointer
1373*f169c0eaSGlenn Lagasse  * Returns:
1374*f169c0eaSGlenn Lagasse  *		0 - Success
1375*f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
1376*f169c0eaSGlenn Lagasse  * Scope:
1377*f169c0eaSGlenn Lagasse  *		Private
1378*f169c0eaSGlenn Lagasse  */
1379*f169c0eaSGlenn Lagasse static int
1380*f169c0eaSGlenn Lagasse be_get_legacy_fs_callback(zfs_handle_t *zhp, void *data)
1381*f169c0eaSGlenn Lagasse {
1382*f169c0eaSGlenn Lagasse 	be_fs_list_data_t	*fld = data;
1383*f169c0eaSGlenn Lagasse 	const char		*fs_name = zfs_get_name(zhp);
1384*f169c0eaSGlenn Lagasse 	char			zhp_mountpoint[MAXPATHLEN];
1385*f169c0eaSGlenn Lagasse 	char			mountpoint[MAXPATHLEN];
1386*f169c0eaSGlenn Lagasse 	int			ret = 0;
1387*f169c0eaSGlenn Lagasse 
1388*f169c0eaSGlenn Lagasse 	/* Get this dataset's mountpoint property */
1389*f169c0eaSGlenn Lagasse 	if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, zhp_mountpoint,
1390*f169c0eaSGlenn Lagasse 	    sizeof (zhp_mountpoint), NULL, NULL, 0, B_FALSE) != 0) {
1391*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_get_legacy_fs_callback: "
1392*f169c0eaSGlenn Lagasse 		    "failed to get mountpoint for %s: %s\n"),
1393*f169c0eaSGlenn Lagasse 		    fs_name, libzfs_error_description(g_zfs));
1394*f169c0eaSGlenn Lagasse 		ret = zfs_err_to_be_err(g_zfs);
1395*f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
1396*f169c0eaSGlenn Lagasse 		return (ret);
1397*f169c0eaSGlenn Lagasse 	}
1398*f169c0eaSGlenn Lagasse 
1399*f169c0eaSGlenn Lagasse 	/*
1400*f169c0eaSGlenn Lagasse 	 * If mountpoint is legacy, try to get its mountpoint from this BE's
1401*f169c0eaSGlenn Lagasse 	 * vfstab.  If it exists in the vfstab, add this file system to the
1402*f169c0eaSGlenn Lagasse 	 * callback data.
1403*f169c0eaSGlenn Lagasse 	 */
1404*f169c0eaSGlenn Lagasse 	if (strcmp(zhp_mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0) {
1405*f169c0eaSGlenn Lagasse 		if (get_mountpoint_from_vfstab(fld->altroot, fs_name,
1406*f169c0eaSGlenn Lagasse 		    mountpoint, sizeof (mountpoint), B_FALSE) != BE_SUCCESS) {
1407*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_get_legacy_fs_callback: "
1408*f169c0eaSGlenn Lagasse 			    "no entry for %s in vfstab, "
1409*f169c0eaSGlenn Lagasse 			    "skipping ...\n"), fs_name);
1410*f169c0eaSGlenn Lagasse 
1411*f169c0eaSGlenn Lagasse 			goto next;
1412*f169c0eaSGlenn Lagasse 		}
1413*f169c0eaSGlenn Lagasse 
1414*f169c0eaSGlenn Lagasse 		/* Record file system into the callback data. */
1415*f169c0eaSGlenn Lagasse 		if (add_to_fs_list(fld, zfs_get_name(zhp)) != BE_SUCCESS) {
1416*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_get_legacy_fs_callback: "
1417*f169c0eaSGlenn Lagasse 			    "failed to add %s to fs list\n"), mountpoint);
1418*f169c0eaSGlenn Lagasse 			ZFS_CLOSE(zhp);
1419*f169c0eaSGlenn Lagasse 			return (BE_ERR_NOMEM);
1420*f169c0eaSGlenn Lagasse 		}
1421*f169c0eaSGlenn Lagasse 	}
1422*f169c0eaSGlenn Lagasse 
1423*f169c0eaSGlenn Lagasse next:
1424*f169c0eaSGlenn Lagasse 	/* Iterate through this dataset's children file systems */
1425*f169c0eaSGlenn Lagasse 	if ((ret = zfs_iter_filesystems(zhp, be_get_legacy_fs_callback,
1426*f169c0eaSGlenn Lagasse 	    fld)) != 0) {
1427*f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
1428*f169c0eaSGlenn Lagasse 		return (ret);
1429*f169c0eaSGlenn Lagasse 	}
1430*f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp);
1431*f169c0eaSGlenn Lagasse 	return (0);
1432*f169c0eaSGlenn Lagasse }
1433*f169c0eaSGlenn Lagasse 
1434*f169c0eaSGlenn Lagasse /*
1435*f169c0eaSGlenn Lagasse  * Function:	add_to_fs_list
1436*f169c0eaSGlenn Lagasse  * Description:	Function used to add a file system to the fs_list array in
1437*f169c0eaSGlenn Lagasse  *			a be_fs_list_data_t structure.
1438*f169c0eaSGlenn Lagasse  * Parameters:
1439*f169c0eaSGlenn Lagasse  *		fld - be_fs_list_data_t pointer
1440*f169c0eaSGlenn Lagasse  *		fs - file system to add
1441*f169c0eaSGlenn Lagasse  * Returns:
1442*f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
1443*f169c0eaSGlenn Lagasse  *		1 - Failure
1444*f169c0eaSGlenn Lagasse  * Scope:
1445*f169c0eaSGlenn Lagasse  *		Private
1446*f169c0eaSGlenn Lagasse  */
1447*f169c0eaSGlenn Lagasse static int
1448*f169c0eaSGlenn Lagasse add_to_fs_list(be_fs_list_data_t *fld, const char *fs)
1449*f169c0eaSGlenn Lagasse {
1450*f169c0eaSGlenn Lagasse 	if (fld == NULL || fs == NULL)
1451*f169c0eaSGlenn Lagasse 		return (1);
1452*f169c0eaSGlenn Lagasse 
1453*f169c0eaSGlenn Lagasse 	if ((fld->fs_list = (char **)realloc(fld->fs_list,
1454*f169c0eaSGlenn Lagasse 	    sizeof (char *)*(fld->fs_num + 1))) == NULL) {
1455*f169c0eaSGlenn Lagasse 		be_print_err(gettext("add_to_fs_list: "
1456*f169c0eaSGlenn Lagasse 		    "memory allocation failed\n"));
1457*f169c0eaSGlenn Lagasse 		return (1);
1458*f169c0eaSGlenn Lagasse 	}
1459*f169c0eaSGlenn Lagasse 
1460*f169c0eaSGlenn Lagasse 	if ((fld->fs_list[fld->fs_num++] = strdup(fs)) == NULL) {
1461*f169c0eaSGlenn Lagasse 		be_print_err(gettext("add_to_fs_list: "
1462*f169c0eaSGlenn Lagasse 		    "memory allocation failed\n"));
1463*f169c0eaSGlenn Lagasse 		return (1);
1464*f169c0eaSGlenn Lagasse 	}
1465*f169c0eaSGlenn Lagasse 
1466*f169c0eaSGlenn Lagasse 	return (BE_SUCCESS);
1467*f169c0eaSGlenn Lagasse }
1468*f169c0eaSGlenn Lagasse 
1469*f169c0eaSGlenn Lagasse /*
1470*f169c0eaSGlenn Lagasse  * Function:	zpool_shared_fs_callback
1471*f169c0eaSGlenn Lagasse  * Description:	Callback function used to iterate through all existing pools
1472*f169c0eaSGlenn Lagasse  *		to find and mount all shared filesystems.  This function
1473*f169c0eaSGlenn Lagasse  *		processes the pool's "pool data" dataset, then uses
1474*f169c0eaSGlenn Lagasse  *		iter_shared_fs_callback to iterate through the pool's
1475*f169c0eaSGlenn Lagasse  *		datasets.
1476*f169c0eaSGlenn Lagasse  * Parameters:
1477*f169c0eaSGlenn Lagasse  *		zlp - zpool_handle_t pointer to the current pool being
1478*f169c0eaSGlenn Lagasse  *			looked at.
1479*f169c0eaSGlenn Lagasse  *		data - be_mount_data_t pointer
1480*f169c0eaSGlenn Lagasse  * Returns:
1481*f169c0eaSGlenn Lagasse  *		0 - Success
1482*f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
1483*f169c0eaSGlenn Lagasse  * Scope:
1484*f169c0eaSGlenn Lagasse  *		Private
1485*f169c0eaSGlenn Lagasse  */
1486*f169c0eaSGlenn Lagasse static int
1487*f169c0eaSGlenn Lagasse zpool_shared_fs_callback(zpool_handle_t *zlp, void *data)
1488*f169c0eaSGlenn Lagasse {
1489*f169c0eaSGlenn Lagasse 	be_mount_data_t	*md = data;
1490*f169c0eaSGlenn Lagasse 	zfs_handle_t	*zhp = NULL;
1491*f169c0eaSGlenn Lagasse 	const char	*zpool = zpool_get_name(zlp);
1492*f169c0eaSGlenn Lagasse 	int		ret = 0;
1493*f169c0eaSGlenn Lagasse 
1494*f169c0eaSGlenn Lagasse 	/*
1495*f169c0eaSGlenn Lagasse 	 * Get handle to pool's "pool data" dataset
1496*f169c0eaSGlenn Lagasse 	 */
1497*f169c0eaSGlenn Lagasse 	if ((zhp = zfs_open(g_zfs, zpool, ZFS_TYPE_FILESYSTEM)) == NULL) {
1498*f169c0eaSGlenn Lagasse 		be_print_err(gettext("zpool_shared_fs: "
1499*f169c0eaSGlenn Lagasse 		    "failed to open pool dataset %s: %s\n"), zpool,
1500*f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
1501*f169c0eaSGlenn Lagasse 		ret = zfs_err_to_be_err(g_zfs);
1502*f169c0eaSGlenn Lagasse 		zpool_close(zlp);
1503*f169c0eaSGlenn Lagasse 		return (ret);
1504*f169c0eaSGlenn Lagasse 	}
1505*f169c0eaSGlenn Lagasse 
1506*f169c0eaSGlenn Lagasse 	/* Process this pool's "pool data" dataset */
1507*f169c0eaSGlenn Lagasse 	(void) loopback_mount_shared_fs(zhp, md);
1508*f169c0eaSGlenn Lagasse 
1509*f169c0eaSGlenn Lagasse 	/* Interate through this pool's children */
1510*f169c0eaSGlenn Lagasse 	(void) zfs_iter_filesystems(zhp, iter_shared_fs_callback, md);
1511*f169c0eaSGlenn Lagasse 
1512*f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp);
1513*f169c0eaSGlenn Lagasse 	zpool_close(zlp);
1514*f169c0eaSGlenn Lagasse 
1515*f169c0eaSGlenn Lagasse 	return (0);
1516*f169c0eaSGlenn Lagasse }
1517*f169c0eaSGlenn Lagasse 
1518*f169c0eaSGlenn Lagasse /*
1519*f169c0eaSGlenn Lagasse  * Function:	iter_shared_fs_callback
1520*f169c0eaSGlenn Lagasse  * Description:	Callback function used to iterate through a pool's datasets
1521*f169c0eaSGlenn Lagasse  *		to find and mount all shared filesystems.  It makes sure to
1522*f169c0eaSGlenn Lagasse  *		find the BE container dataset of the pool, if it exists, and
1523*f169c0eaSGlenn Lagasse  *		does not process and iterate down that path.
1524*f169c0eaSGlenn Lagasse  *
1525*f169c0eaSGlenn Lagasse  *		Note - This function iterates linearly down the
1526*f169c0eaSGlenn Lagasse  *		hierarchical dataset paths and mounts things as it goes
1527*f169c0eaSGlenn Lagasse  *		along.  It does not make sure that something deeper down
1528*f169c0eaSGlenn Lagasse  *		a dataset path has an interim mountpoint for something
1529*f169c0eaSGlenn Lagasse  *		processed earlier.
1530*f169c0eaSGlenn Lagasse  *
1531*f169c0eaSGlenn Lagasse  * Parameters:
1532*f169c0eaSGlenn Lagasse  *		zhp - zfs_handle_t pointer to the current dataset being
1533*f169c0eaSGlenn Lagasse  *			processed.
1534*f169c0eaSGlenn Lagasse  *		data - be_mount_data_t pointer
1535*f169c0eaSGlenn Lagasse  * Returns:
1536*f169c0eaSGlenn Lagasse  *		0 - Success
1537*f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
1538*f169c0eaSGlenn Lagasse  * Scope:
1539*f169c0eaSGlenn Lagasse  *		Private
1540*f169c0eaSGlenn Lagasse  */
1541*f169c0eaSGlenn Lagasse static int
1542*f169c0eaSGlenn Lagasse iter_shared_fs_callback(zfs_handle_t *zhp, void *data)
1543*f169c0eaSGlenn Lagasse {
1544*f169c0eaSGlenn Lagasse 	be_mount_data_t	*md = data;
1545*f169c0eaSGlenn Lagasse 	const char	*name = zfs_get_name(zhp);
1546*f169c0eaSGlenn Lagasse 	char		container_ds[MAXPATHLEN];
1547*f169c0eaSGlenn Lagasse 	char		tmp_name[MAXPATHLEN];
1548*f169c0eaSGlenn Lagasse 	char		*pool;
1549*f169c0eaSGlenn Lagasse 
1550*f169c0eaSGlenn Lagasse 	/* Get the pool's name */
1551*f169c0eaSGlenn Lagasse 	(void) strlcpy(tmp_name, name, sizeof (tmp_name));
1552*f169c0eaSGlenn Lagasse 	pool = strtok(tmp_name, "/");
1553*f169c0eaSGlenn Lagasse 
1554*f169c0eaSGlenn Lagasse 	if (pool) {
1555*f169c0eaSGlenn Lagasse 		/* Get the name of this pool's container dataset */
1556*f169c0eaSGlenn Lagasse 		be_make_container_ds(pool, container_ds,
1557*f169c0eaSGlenn Lagasse 		    sizeof (container_ds));
1558*f169c0eaSGlenn Lagasse 
1559*f169c0eaSGlenn Lagasse 		/*
1560*f169c0eaSGlenn Lagasse 		 * If what we're processing is this pool's BE container
1561*f169c0eaSGlenn Lagasse 		 * dataset, skip it.
1562*f169c0eaSGlenn Lagasse 		 */
1563*f169c0eaSGlenn Lagasse 		if (strcmp(name, container_ds) == 0) {
1564*f169c0eaSGlenn Lagasse 			ZFS_CLOSE(zhp);
1565*f169c0eaSGlenn Lagasse 			return (0);
1566*f169c0eaSGlenn Lagasse 		}
1567*f169c0eaSGlenn Lagasse 	} else {
1568*f169c0eaSGlenn Lagasse 		/* Getting the pool name failed, return error */
1569*f169c0eaSGlenn Lagasse 		be_print_err(gettext("iter_shared_fs_callback: "
1570*f169c0eaSGlenn Lagasse 		    "failed to get pool name from %s\n"), name);
1571*f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
1572*f169c0eaSGlenn Lagasse 		return (BE_ERR_POOL_NOENT);
1573*f169c0eaSGlenn Lagasse 	}
1574*f169c0eaSGlenn Lagasse 
1575*f169c0eaSGlenn Lagasse 	/* Mount this shared filesystem */
1576*f169c0eaSGlenn Lagasse 	(void) loopback_mount_shared_fs(zhp, md);
1577*f169c0eaSGlenn Lagasse 
1578*f169c0eaSGlenn Lagasse 	/* Iterate this dataset's children file systems */
1579*f169c0eaSGlenn Lagasse 	(void) zfs_iter_filesystems(zhp, iter_shared_fs_callback, md);
1580*f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp);
1581*f169c0eaSGlenn Lagasse 
1582*f169c0eaSGlenn Lagasse 	return (0);
1583*f169c0eaSGlenn Lagasse }
1584*f169c0eaSGlenn Lagasse 
1585*f169c0eaSGlenn Lagasse /*
1586*f169c0eaSGlenn Lagasse  * Function:	loopback_mount_shared_fs
1587*f169c0eaSGlenn Lagasse  * Description:	This function loopback mounts a file system into the altroot
1588*f169c0eaSGlenn Lagasse  *		area of the BE being mounted.  Since these are shared file
1589*f169c0eaSGlenn Lagasse  *		systems, they are expected to be already mounted for the
1590*f169c0eaSGlenn Lagasse  *		current BE, and this function just loopback mounts them into
1591*f169c0eaSGlenn Lagasse  *		the BE mountpoint.  If they are not mounted for the current
1592*f169c0eaSGlenn Lagasse  *		live system, they are skipped and not mounted into the BE
1593*f169c0eaSGlenn Lagasse  *		we're mounting.
1594*f169c0eaSGlenn Lagasse  * Parameters:
1595*f169c0eaSGlenn Lagasse  *		zhp - zfs_handle_t pointer to the dataset to loopback mount
1596*f169c0eaSGlenn Lagasse  *		md - be_mount_data_t pointer
1597*f169c0eaSGlenn Lagasse  * Returns:
1598*f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
1599*f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
1600*f169c0eaSGlenn Lagasse  * Scope:
1601*f169c0eaSGlenn Lagasse  *		Private
1602*f169c0eaSGlenn Lagasse  */
1603*f169c0eaSGlenn Lagasse static int
1604*f169c0eaSGlenn Lagasse loopback_mount_shared_fs(zfs_handle_t *zhp, be_mount_data_t *md)
1605*f169c0eaSGlenn Lagasse {
1606*f169c0eaSGlenn Lagasse 	char		zhp_mountpoint[MAXPATHLEN];
1607*f169c0eaSGlenn Lagasse 	char		mountpoint[MAXPATHLEN];
1608*f169c0eaSGlenn Lagasse 	char		*mp = NULL;
1609*f169c0eaSGlenn Lagasse 	char		optstr[MAX_MNTOPT_STR];
1610*f169c0eaSGlenn Lagasse 	int		mflag = MS_OPTIONSTR;
1611*f169c0eaSGlenn Lagasse 	int		err;
1612*f169c0eaSGlenn Lagasse 
1613*f169c0eaSGlenn Lagasse 	/*
1614*f169c0eaSGlenn Lagasse 	 * Check if file system is currently mounted and not delegated
1615*f169c0eaSGlenn Lagasse 	 * to a non-global zone (if we're in the global zone)
1616*f169c0eaSGlenn Lagasse 	 */
1617*f169c0eaSGlenn Lagasse 	if (zfs_is_mounted(zhp, &mp) && (getzoneid() != GLOBAL_ZONEID ||
1618*f169c0eaSGlenn Lagasse 	    !zfs_prop_get_int(zhp, ZFS_PROP_ZONED))) {
1619*f169c0eaSGlenn Lagasse 		/*
1620*f169c0eaSGlenn Lagasse 		 * If we didn't get a mountpoint from the zfs_is_mounted call,
1621*f169c0eaSGlenn Lagasse 		 * get it from the mountpoint property.
1622*f169c0eaSGlenn Lagasse 		 */
1623*f169c0eaSGlenn Lagasse 		if (mp == NULL) {
1624*f169c0eaSGlenn Lagasse 			if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT,
1625*f169c0eaSGlenn Lagasse 			    zhp_mountpoint, sizeof (zhp_mountpoint), NULL,
1626*f169c0eaSGlenn Lagasse 			    NULL, 0, B_FALSE) != 0) {
1627*f169c0eaSGlenn Lagasse 				be_print_err(
1628*f169c0eaSGlenn Lagasse 				    gettext("loopback_mount_shared_fs: "
1629*f169c0eaSGlenn Lagasse 				    "failed to get mountpoint property\n"));
1630*f169c0eaSGlenn Lagasse 				return (BE_ERR_ZFS);
1631*f169c0eaSGlenn Lagasse 			}
1632*f169c0eaSGlenn Lagasse 		} else {
1633*f169c0eaSGlenn Lagasse 			(void) strlcpy(zhp_mountpoint, mp,
1634*f169c0eaSGlenn Lagasse 			    sizeof (zhp_mountpoint));
1635*f169c0eaSGlenn Lagasse 			free(mp);
1636*f169c0eaSGlenn Lagasse 		}
1637*f169c0eaSGlenn Lagasse 
1638*f169c0eaSGlenn Lagasse 		(void) snprintf(mountpoint, sizeof (mountpoint), "%s%s",
1639*f169c0eaSGlenn Lagasse 		    md->altroot, zhp_mountpoint);
1640*f169c0eaSGlenn Lagasse 
1641*f169c0eaSGlenn Lagasse 		/* Mount it read-only if read-write was not requested */
1642*f169c0eaSGlenn Lagasse 		if (!md->shared_rw) {
1643*f169c0eaSGlenn Lagasse 			mflag |= MS_RDONLY;
1644*f169c0eaSGlenn Lagasse 		}
1645*f169c0eaSGlenn Lagasse 
1646*f169c0eaSGlenn Lagasse 		/* Add the "nosub" option to the mount options string */
1647*f169c0eaSGlenn Lagasse 		(void) strlcpy(optstr, MNTOPT_NOSUB, sizeof (optstr));
1648*f169c0eaSGlenn Lagasse 
1649*f169c0eaSGlenn Lagasse 		/* Loopback mount this dataset at the altroot */
1650*f169c0eaSGlenn Lagasse 		if (mount(zhp_mountpoint, mountpoint, mflag, MNTTYPE_LOFS,
1651*f169c0eaSGlenn Lagasse 		    NULL, 0, optstr, sizeof (optstr)) != 0) {
1652*f169c0eaSGlenn Lagasse 			err = errno;
1653*f169c0eaSGlenn Lagasse 			be_print_err(gettext("loopback_mount_shared_fs: "
1654*f169c0eaSGlenn Lagasse 			    "failed to loopback mount %s at %s: %s\n"),
1655*f169c0eaSGlenn Lagasse 			    zhp_mountpoint, mountpoint, strerror(err));
1656*f169c0eaSGlenn Lagasse 			return (BE_ERR_MOUNT);
1657*f169c0eaSGlenn Lagasse 		}
1658*f169c0eaSGlenn Lagasse 	}
1659*f169c0eaSGlenn Lagasse 
1660*f169c0eaSGlenn Lagasse 	return (BE_SUCCESS);
1661*f169c0eaSGlenn Lagasse }
1662*f169c0eaSGlenn Lagasse 
1663*f169c0eaSGlenn Lagasse /*
1664*f169c0eaSGlenn Lagasse  * Function:	loopback_mount_zonepath
1665*f169c0eaSGlenn Lagasse  * Description:	This function loopback mounts a zonepath into the altroot
1666*f169c0eaSGlenn Lagasse  *		area of the BE being mounted.  Since these are shared file
1667*f169c0eaSGlenn Lagasse  *		systems, they are expected to be already mounted for the
1668*f169c0eaSGlenn Lagasse  *		current BE, and this function just loopback mounts them into
1669*f169c0eaSGlenn Lagasse  *		the BE mountpoint.
1670*f169c0eaSGlenn Lagasse  * Parameters:
1671*f169c0eaSGlenn Lagasse  *		zonepath - pointer to zone path in the current BE
1672*f169c0eaSGlenn Lagasse  *		md - be_mount_data_t pointer
1673*f169c0eaSGlenn Lagasse  * Returns:
1674*f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
1675*f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
1676*f169c0eaSGlenn Lagasse  * Scope:
1677*f169c0eaSGlenn Lagasse  *		Private
1678*f169c0eaSGlenn Lagasse  */
1679*f169c0eaSGlenn Lagasse static int
1680*f169c0eaSGlenn Lagasse loopback_mount_zonepath(const char *zonepath, be_mount_data_t *md)
1681*f169c0eaSGlenn Lagasse {
1682*f169c0eaSGlenn Lagasse 	FILE		*fp = (FILE *)NULL;
1683*f169c0eaSGlenn Lagasse 	struct stat	st;
1684*f169c0eaSGlenn Lagasse 	char		*p;
1685*f169c0eaSGlenn Lagasse 	char		*p1;
1686*f169c0eaSGlenn Lagasse 	char		*parent_dir;
1687*f169c0eaSGlenn Lagasse 	struct extmnttab	extmtab;
1688*f169c0eaSGlenn Lagasse 	dev_t		dev = NODEV;
1689*f169c0eaSGlenn Lagasse 	char		*parentmnt;
1690*f169c0eaSGlenn Lagasse 	char		alt_parentmnt[MAXPATHLEN];
1691*f169c0eaSGlenn Lagasse 	struct mnttab	mntref;
1692*f169c0eaSGlenn Lagasse 	char		altzonepath[MAXPATHLEN];
1693*f169c0eaSGlenn Lagasse 	char		optstr[MAX_MNTOPT_STR];
1694*f169c0eaSGlenn Lagasse 	int		mflag = MS_OPTIONSTR;
1695*f169c0eaSGlenn Lagasse 	int		ret;
1696*f169c0eaSGlenn Lagasse 	int		err;
1697*f169c0eaSGlenn Lagasse 
1698*f169c0eaSGlenn Lagasse 	fp = fopen(MNTTAB, "r");
1699*f169c0eaSGlenn Lagasse 	if (fp == NULL) {
1700*f169c0eaSGlenn Lagasse 		err = errno;
1701*f169c0eaSGlenn Lagasse 		be_print_err(gettext("loopback_mount_zonepath: "
1702*f169c0eaSGlenn Lagasse 		    "failed to open /etc/mnttab\n"));
1703*f169c0eaSGlenn Lagasse 		return (errno_to_be_err(err));
1704*f169c0eaSGlenn Lagasse 	}
1705*f169c0eaSGlenn Lagasse 
1706*f169c0eaSGlenn Lagasse 	/*
1707*f169c0eaSGlenn Lagasse 	 * before attempting the loopback mount of zonepath under altroot,
1708*f169c0eaSGlenn Lagasse 	 * we need to make sure that all intermediate file systems in the
1709*f169c0eaSGlenn Lagasse 	 * zone path are also mounted under altroot
1710*f169c0eaSGlenn Lagasse 	 */
1711*f169c0eaSGlenn Lagasse 
1712*f169c0eaSGlenn Lagasse 	/* get the parent directory for zonepath */
1713*f169c0eaSGlenn Lagasse 	p = strrchr(zonepath, '/');
1714*f169c0eaSGlenn Lagasse 	if (p != NULL && p != zonepath) {
1715*f169c0eaSGlenn Lagasse 		if ((parent_dir = (char *)calloc(sizeof (char),
1716*f169c0eaSGlenn Lagasse 		    p - zonepath + 1)) == NULL) {
1717*f169c0eaSGlenn Lagasse 			ret = BE_ERR_NOMEM;
1718*f169c0eaSGlenn Lagasse 			goto done;
1719*f169c0eaSGlenn Lagasse 		}
1720*f169c0eaSGlenn Lagasse 		(void) strlcpy(parent_dir, zonepath, p - zonepath + 1);
1721*f169c0eaSGlenn Lagasse 		if (stat(parent_dir, &st) < 0) {
1722*f169c0eaSGlenn Lagasse 			ret = errno_to_be_err(errno);
1723*f169c0eaSGlenn Lagasse 			be_print_err(gettext("loopback_mount_zonepath: "
1724*f169c0eaSGlenn Lagasse 			    "failed to stat %s"),
1725*f169c0eaSGlenn Lagasse 			    parent_dir);
1726*f169c0eaSGlenn Lagasse 			free(parent_dir);
1727*f169c0eaSGlenn Lagasse 			goto done;
1728*f169c0eaSGlenn Lagasse 		}
1729*f169c0eaSGlenn Lagasse 		free(parent_dir);
1730*f169c0eaSGlenn Lagasse 
1731*f169c0eaSGlenn Lagasse 		/*
1732*f169c0eaSGlenn Lagasse 		 * After the above stat call, st.st_dev contains ID of the
1733*f169c0eaSGlenn Lagasse 		 * device over which parent dir resides.
1734*f169c0eaSGlenn Lagasse 		 * Now, search mnttab and find mount point of parent dir device.
1735*f169c0eaSGlenn Lagasse 		 */
1736*f169c0eaSGlenn Lagasse 
1737*f169c0eaSGlenn Lagasse 		resetmnttab(fp);
1738*f169c0eaSGlenn Lagasse 		while (getextmntent(fp, &extmtab, sizeof (extmtab)) == 0) {
1739*f169c0eaSGlenn Lagasse 			dev = makedev(extmtab.mnt_major, extmtab.mnt_minor);
1740*f169c0eaSGlenn Lagasse 			if (st.st_dev == dev && strcmp(extmtab.mnt_fstype,
1741*f169c0eaSGlenn Lagasse 			    MNTTYPE_ZFS) == 0) {
1742*f169c0eaSGlenn Lagasse 				p1 = strchr(extmtab.mnt_special, '/');
1743*f169c0eaSGlenn Lagasse 				if (p1 == NULL || strncmp(p1 + 1,
1744*f169c0eaSGlenn Lagasse 				    BE_CONTAINER_DS_NAME, 4) != 0 ||
1745*f169c0eaSGlenn Lagasse 				    (*(p1 + 5) != '/' && *(p1 + 5) != '\0')) {
1746*f169c0eaSGlenn Lagasse 					/*
1747*f169c0eaSGlenn Lagasse 					 * if parent dir is in a shared file
1748*f169c0eaSGlenn Lagasse 					 * system, check whether it is already
1749*f169c0eaSGlenn Lagasse 					 * loopback mounted under altroot or
1750*f169c0eaSGlenn Lagasse 					 * not.  It would have been mounted
1751*f169c0eaSGlenn Lagasse 					 * already under altroot if it is in
1752*f169c0eaSGlenn Lagasse 					 * a non-shared filesystem.
1753*f169c0eaSGlenn Lagasse 					 */
1754*f169c0eaSGlenn Lagasse 					parentmnt = strdup(extmtab.mnt_mountp);
1755*f169c0eaSGlenn Lagasse 					(void) snprintf(alt_parentmnt,
1756*f169c0eaSGlenn Lagasse 					    sizeof (alt_parentmnt), "%s%s",
1757*f169c0eaSGlenn Lagasse 					    md->altroot, parentmnt);
1758*f169c0eaSGlenn Lagasse 					mntref.mnt_mountp = alt_parentmnt;
1759*f169c0eaSGlenn Lagasse 					mntref.mnt_special = parentmnt;
1760*f169c0eaSGlenn Lagasse 					mntref.mnt_fstype = MNTTYPE_LOFS;
1761*f169c0eaSGlenn Lagasse 					mntref.mnt_mntopts = NULL;
1762*f169c0eaSGlenn Lagasse 					mntref.mnt_time = NULL;
1763*f169c0eaSGlenn Lagasse 					resetmnttab(fp);
1764*f169c0eaSGlenn Lagasse 					if (getmntany(fp, (struct mnttab *)
1765*f169c0eaSGlenn Lagasse 					    &extmtab, &mntref) != 0) {
1766*f169c0eaSGlenn Lagasse 						ret = loopback_mount_zonepath(
1767*f169c0eaSGlenn Lagasse 						    parentmnt, md);
1768*f169c0eaSGlenn Lagasse 						if (ret != BE_SUCCESS) {
1769*f169c0eaSGlenn Lagasse 							free(parentmnt);
1770*f169c0eaSGlenn Lagasse 							goto done;
1771*f169c0eaSGlenn Lagasse 						}
1772*f169c0eaSGlenn Lagasse 					}
1773*f169c0eaSGlenn Lagasse 					free(parentmnt);
1774*f169c0eaSGlenn Lagasse 				}
1775*f169c0eaSGlenn Lagasse 				break;
1776*f169c0eaSGlenn Lagasse 			}
1777*f169c0eaSGlenn Lagasse 		}
1778*f169c0eaSGlenn Lagasse 	}
1779*f169c0eaSGlenn Lagasse 
1780*f169c0eaSGlenn Lagasse 
1781*f169c0eaSGlenn Lagasse 	if (!md->shared_rw) {
1782*f169c0eaSGlenn Lagasse 		mflag |= MS_RDONLY;
1783*f169c0eaSGlenn Lagasse 	}
1784*f169c0eaSGlenn Lagasse 
1785*f169c0eaSGlenn Lagasse 	(void) snprintf(altzonepath, sizeof (altzonepath), "%s%s",
1786*f169c0eaSGlenn Lagasse 	    md->altroot, zonepath);
1787*f169c0eaSGlenn Lagasse 
1788*f169c0eaSGlenn Lagasse 	/* Add the "nosub" option to the mount options string */
1789*f169c0eaSGlenn Lagasse 	(void) strlcpy(optstr, MNTOPT_NOSUB, sizeof (optstr));
1790*f169c0eaSGlenn Lagasse 
1791*f169c0eaSGlenn Lagasse 	/* Loopback mount this dataset at the altroot */
1792*f169c0eaSGlenn Lagasse 	if (mount(zonepath, altzonepath, mflag, MNTTYPE_LOFS,
1793*f169c0eaSGlenn Lagasse 	    NULL, 0, optstr, sizeof (optstr)) != 0) {
1794*f169c0eaSGlenn Lagasse 		err = errno;
1795*f169c0eaSGlenn Lagasse 		be_print_err(gettext("loopback_mount_zonepath: "
1796*f169c0eaSGlenn Lagasse 		    "failed to loopback mount %s at %s: %s\n"),
1797*f169c0eaSGlenn Lagasse 		    zonepath, altzonepath, strerror(err));
1798*f169c0eaSGlenn Lagasse 		ret = BE_ERR_MOUNT;
1799*f169c0eaSGlenn Lagasse 		goto done;
1800*f169c0eaSGlenn Lagasse 	}
1801*f169c0eaSGlenn Lagasse 	ret = BE_SUCCESS;
1802*f169c0eaSGlenn Lagasse 
1803*f169c0eaSGlenn Lagasse done :
1804*f169c0eaSGlenn Lagasse 	(void) fclose(fp);
1805*f169c0eaSGlenn Lagasse 	return (ret);
1806*f169c0eaSGlenn Lagasse }
1807*f169c0eaSGlenn Lagasse 
1808*f169c0eaSGlenn Lagasse /*
1809*f169c0eaSGlenn Lagasse  * Function:	unmount_shared_fs
1810*f169c0eaSGlenn Lagasse  * Description:	This function iterates through the mnttab and finds all
1811*f169c0eaSGlenn Lagasse  *		loopback mount entries that reside within the altroot of
1812*f169c0eaSGlenn Lagasse  *		where the BE is mounted, and unmounts it.
1813*f169c0eaSGlenn Lagasse  * Parameters:
1814*f169c0eaSGlenn Lagasse  *		ud - be_unmount_data_t pointer
1815*f169c0eaSGlenn Lagasse  * Returns:
1816*f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
1817*f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
1818*f169c0eaSGlenn Lagasse  * Scope:
1819*f169c0eaSGlenn Lagasse  *		Private
1820*f169c0eaSGlenn Lagasse  */
1821*f169c0eaSGlenn Lagasse static int
1822*f169c0eaSGlenn Lagasse unmount_shared_fs(be_unmount_data_t *ud)
1823*f169c0eaSGlenn Lagasse {
1824*f169c0eaSGlenn Lagasse 	FILE		*fp = NULL;
1825*f169c0eaSGlenn Lagasse 	struct mnttab	*table = NULL;
1826*f169c0eaSGlenn Lagasse 	struct mnttab	ent;
1827*f169c0eaSGlenn Lagasse 	struct mnttab	*entp = NULL;
1828*f169c0eaSGlenn Lagasse 	size_t		size = 0;
1829*f169c0eaSGlenn Lagasse 	int		read_chunk = 32;
1830*f169c0eaSGlenn Lagasse 	int		i;
1831*f169c0eaSGlenn Lagasse 	int		altroot_len;
1832*f169c0eaSGlenn Lagasse 	int		err = 0;
1833*f169c0eaSGlenn Lagasse 
1834*f169c0eaSGlenn Lagasse 	errno = 0;
1835*f169c0eaSGlenn Lagasse 
1836*f169c0eaSGlenn Lagasse 	/* Read in the mnttab into a table */
1837*f169c0eaSGlenn Lagasse 	if ((fp = fopen(MNTTAB, "r")) == NULL) {
1838*f169c0eaSGlenn Lagasse 		err = errno;
1839*f169c0eaSGlenn Lagasse 		be_print_err(gettext("unmount_shared_fs: "
1840*f169c0eaSGlenn Lagasse 		    "failed to open mnttab\n"));
1841*f169c0eaSGlenn Lagasse 		return (errno_to_be_err(err));
1842*f169c0eaSGlenn Lagasse 	}
1843*f169c0eaSGlenn Lagasse 
1844*f169c0eaSGlenn Lagasse 	while (getmntent(fp, &ent) == 0) {
1845*f169c0eaSGlenn Lagasse 		if (size % read_chunk == 0) {
1846*f169c0eaSGlenn Lagasse 			table = (struct mnttab *)realloc(table,
1847*f169c0eaSGlenn Lagasse 			    (size + read_chunk) * sizeof (ent));
1848*f169c0eaSGlenn Lagasse 		}
1849*f169c0eaSGlenn Lagasse 		entp = &table[size++];
1850*f169c0eaSGlenn Lagasse 
1851*f169c0eaSGlenn Lagasse 		/*
1852*f169c0eaSGlenn Lagasse 		 * Copy over the current mnttab entry into our table,
1853*f169c0eaSGlenn Lagasse 		 * copying only the fields that we care about.
1854*f169c0eaSGlenn Lagasse 		 */
1855*f169c0eaSGlenn Lagasse 		(void) memset(entp, 0, sizeof (*entp));
1856*f169c0eaSGlenn Lagasse 		if ((entp->mnt_mountp = strdup(ent.mnt_mountp)) == NULL ||
1857*f169c0eaSGlenn Lagasse 		    (entp->mnt_fstype = strdup(ent.mnt_fstype)) == NULL) {
1858*f169c0eaSGlenn Lagasse 			be_print_err(gettext("unmount_shared_fs: "
1859*f169c0eaSGlenn Lagasse 			    "memory allocation failed\n"));
1860*f169c0eaSGlenn Lagasse 			return (BE_ERR_NOMEM);
1861*f169c0eaSGlenn Lagasse 		}
1862*f169c0eaSGlenn Lagasse 	}
1863*f169c0eaSGlenn Lagasse 	(void) fclose(fp);
1864*f169c0eaSGlenn Lagasse 
1865*f169c0eaSGlenn Lagasse 	/*
1866*f169c0eaSGlenn Lagasse 	 * Process the mnttab entries in reverse order, looking for
1867*f169c0eaSGlenn Lagasse 	 * loopback mount entries mounted under our altroot.
1868*f169c0eaSGlenn Lagasse 	 */
1869*f169c0eaSGlenn Lagasse 	altroot_len = strlen(ud->altroot);
1870*f169c0eaSGlenn Lagasse 	for (i = size; i > 0; i--) {
1871*f169c0eaSGlenn Lagasse 		entp = &table[i - 1];
1872*f169c0eaSGlenn Lagasse 
1873*f169c0eaSGlenn Lagasse 		/* If not of type lofs, skip */
1874*f169c0eaSGlenn Lagasse 		if (strcmp(entp->mnt_fstype, MNTTYPE_LOFS) != 0)
1875*f169c0eaSGlenn Lagasse 			continue;
1876*f169c0eaSGlenn Lagasse 
1877*f169c0eaSGlenn Lagasse 		/* If inside the altroot, unmount it */
1878*f169c0eaSGlenn Lagasse 		if (strncmp(entp->mnt_mountp, ud->altroot, altroot_len) == 0 &&
1879*f169c0eaSGlenn Lagasse 		    entp->mnt_mountp[altroot_len] == '/') {
1880*f169c0eaSGlenn Lagasse 			if (umount(entp->mnt_mountp) != 0) {
1881*f169c0eaSGlenn Lagasse 				err = errno;
1882*f169c0eaSGlenn Lagasse 				if (err == EBUSY) {
1883*f169c0eaSGlenn Lagasse 					(void) sleep(1);
1884*f169c0eaSGlenn Lagasse 					err = errno = 0;
1885*f169c0eaSGlenn Lagasse 					if (umount(entp->mnt_mountp) != 0)
1886*f169c0eaSGlenn Lagasse 						err = errno;
1887*f169c0eaSGlenn Lagasse 				}
1888*f169c0eaSGlenn Lagasse 				if (err != 0) {
1889*f169c0eaSGlenn Lagasse 					be_print_err(gettext(
1890*f169c0eaSGlenn Lagasse 					    "unmount_shared_fs: "
1891*f169c0eaSGlenn Lagasse 					    "failed to unmount shared file "
1892*f169c0eaSGlenn Lagasse 					    "system %s: %s\n"),
1893*f169c0eaSGlenn Lagasse 					    entp->mnt_mountp, strerror(err));
1894*f169c0eaSGlenn Lagasse 					return (errno_to_be_err(err));
1895*f169c0eaSGlenn Lagasse 				}
1896*f169c0eaSGlenn Lagasse 			}
1897*f169c0eaSGlenn Lagasse 		}
1898*f169c0eaSGlenn Lagasse 	}
1899*f169c0eaSGlenn Lagasse 
1900*f169c0eaSGlenn Lagasse 	return (BE_SUCCESS);
1901*f169c0eaSGlenn Lagasse }
1902*f169c0eaSGlenn Lagasse 
1903*f169c0eaSGlenn Lagasse /*
1904*f169c0eaSGlenn Lagasse  * Function:	get_mountpoint_from_vfstab
1905*f169c0eaSGlenn Lagasse  * Description:	This function digs into the vfstab in the given altroot,
1906*f169c0eaSGlenn Lagasse  *		and searches for an entry for the fs passed in.  If found,
1907*f169c0eaSGlenn Lagasse  *		it returns the mountpoint of that fs in the mountpoint
1908*f169c0eaSGlenn Lagasse  *		buffer passed in.  If the get_alt_mountpoint flag is set,
1909*f169c0eaSGlenn Lagasse  *		it returns the mountpoint with the altroot prepended.
1910*f169c0eaSGlenn Lagasse  * Parameters:
1911*f169c0eaSGlenn Lagasse  *		altroot - pointer to the alternate root location
1912*f169c0eaSGlenn Lagasse  *		fs - pointer to the file system name to look for in the
1913*f169c0eaSGlenn Lagasse  *			vfstab in altroot
1914*f169c0eaSGlenn Lagasse  *		mountpoint - pointer to buffer of where the mountpoint of
1915*f169c0eaSGlenn Lagasse  *			fs will be returned.
1916*f169c0eaSGlenn Lagasse  *		size_mp - size of mountpoint argument
1917*f169c0eaSGlenn Lagasse  *		get_alt_mountpoint - flag to indicate whether or not the
1918*f169c0eaSGlenn Lagasse  *			mountpoint should be populated with the altroot
1919*f169c0eaSGlenn Lagasse  *			prepended.
1920*f169c0eaSGlenn Lagasse  * Returns:
1921*f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
1922*f169c0eaSGlenn Lagasse  *		1 - Failure
1923*f169c0eaSGlenn Lagasse  * Scope:
1924*f169c0eaSGlenn Lagasse  *		Private
1925*f169c0eaSGlenn Lagasse  */
1926*f169c0eaSGlenn Lagasse static int
1927*f169c0eaSGlenn Lagasse get_mountpoint_from_vfstab(char *altroot, const char *fs, char *mountpoint,
1928*f169c0eaSGlenn Lagasse     size_t size_mp, boolean_t get_alt_mountpoint)
1929*f169c0eaSGlenn Lagasse {
1930*f169c0eaSGlenn Lagasse 	struct vfstab	vp;
1931*f169c0eaSGlenn Lagasse 	FILE		*fp = NULL;
1932*f169c0eaSGlenn Lagasse 	char		alt_vfstab[MAXPATHLEN];
1933*f169c0eaSGlenn Lagasse 
1934*f169c0eaSGlenn Lagasse 	/* Generate path to alternate root vfstab */
1935*f169c0eaSGlenn Lagasse 	(void) snprintf(alt_vfstab, sizeof (alt_vfstab), "%s/etc/vfstab",
1936*f169c0eaSGlenn Lagasse 	    altroot);
1937*f169c0eaSGlenn Lagasse 
1938*f169c0eaSGlenn Lagasse 	/* Open alternate root vfstab */
1939*f169c0eaSGlenn Lagasse 	if ((fp = fopen(alt_vfstab, "r")) == NULL) {
1940*f169c0eaSGlenn Lagasse 		be_print_err(gettext("get_mountpoint_from_vfstab: "
1941*f169c0eaSGlenn Lagasse 		    "failed to open vfstab (%s)\n"), alt_vfstab);
1942*f169c0eaSGlenn Lagasse 		return (1);
1943*f169c0eaSGlenn Lagasse 	}
1944*f169c0eaSGlenn Lagasse 
1945*f169c0eaSGlenn Lagasse 	if (getvfsspec(fp, &vp, (char *)fs) == 0) {
1946*f169c0eaSGlenn Lagasse 		/*
1947*f169c0eaSGlenn Lagasse 		 * Found entry for fs, grab its mountpoint.
1948*f169c0eaSGlenn Lagasse 		 * If the flag to prepend the altroot into the mountpoint
1949*f169c0eaSGlenn Lagasse 		 * is set, prepend it.  Otherwise, just return the mountpoint.
1950*f169c0eaSGlenn Lagasse 		 */
1951*f169c0eaSGlenn Lagasse 		if (get_alt_mountpoint) {
1952*f169c0eaSGlenn Lagasse 			(void) snprintf(mountpoint, size_mp, "%s%s", altroot,
1953*f169c0eaSGlenn Lagasse 			    vp.vfs_mountp);
1954*f169c0eaSGlenn Lagasse 		} else {
1955*f169c0eaSGlenn Lagasse 			(void) strlcpy(mountpoint, vp.vfs_mountp, size_mp);
1956*f169c0eaSGlenn Lagasse 		}
1957*f169c0eaSGlenn Lagasse 	} else {
1958*f169c0eaSGlenn Lagasse 		(void) fclose(fp);
1959*f169c0eaSGlenn Lagasse 		return (1);
1960*f169c0eaSGlenn Lagasse 	}
1961*f169c0eaSGlenn Lagasse 
1962*f169c0eaSGlenn Lagasse 	(void) fclose(fp);
1963*f169c0eaSGlenn Lagasse 
1964*f169c0eaSGlenn Lagasse 	return (BE_SUCCESS);
1965*f169c0eaSGlenn Lagasse }
1966*f169c0eaSGlenn Lagasse 
1967*f169c0eaSGlenn Lagasse /*
1968*f169c0eaSGlenn Lagasse  * Function:	fix_mountpoint_callback
1969*f169c0eaSGlenn Lagasse  * Description:	This callback function is used to iterate through a BE's
1970*f169c0eaSGlenn Lagasse  *		children filesystems to check if its mountpoint is currently
1971*f169c0eaSGlenn Lagasse  *		set to be mounted at some specified altroot.  If so, fix it by
1972*f169c0eaSGlenn Lagasse  *		removing altroot from the beginning of its mountpoint.
1973*f169c0eaSGlenn Lagasse  *
1974*f169c0eaSGlenn Lagasse  *		Note - There's no way to tell if a child filesystem's
1975*f169c0eaSGlenn Lagasse  *		mountpoint isn't broken, and just happens to begin with
1976*f169c0eaSGlenn Lagasse  *		the altroot we're looking for.  In this case, this function
1977*f169c0eaSGlenn Lagasse  *		will errantly remove the altroot portion from the beginning
1978*f169c0eaSGlenn Lagasse  *		of this filesystem's mountpoint.
1979*f169c0eaSGlenn Lagasse  *
1980*f169c0eaSGlenn Lagasse  * Parameters:
1981*f169c0eaSGlenn Lagasse  *		zhp - zfs_handle_t pointer to filesystem being processed.
1982*f169c0eaSGlenn Lagasse  *		data - altroot of where BE is to be mounted.
1983*f169c0eaSGlenn Lagasse  * Returns:
1984*f169c0eaSGlenn Lagasse  *		0 - Success
1985*f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
1986*f169c0eaSGlenn Lagasse  * Scope:
1987*f169c0eaSGlenn Lagasse  *		Private
1988*f169c0eaSGlenn Lagasse  */
1989*f169c0eaSGlenn Lagasse static int
1990*f169c0eaSGlenn Lagasse fix_mountpoint_callback(zfs_handle_t *zhp, void *data)
1991*f169c0eaSGlenn Lagasse {
1992*f169c0eaSGlenn Lagasse 	zprop_source_t	sourcetype;
1993*f169c0eaSGlenn Lagasse 	char		source[ZFS_MAXNAMELEN];
1994*f169c0eaSGlenn Lagasse 	char		mountpoint[MAXPATHLEN];
1995*f169c0eaSGlenn Lagasse 	char		*zhp_mountpoint = NULL;
1996*f169c0eaSGlenn Lagasse 	char		*altroot = data;
1997*f169c0eaSGlenn Lagasse 	int		ret = 0;
1998*f169c0eaSGlenn Lagasse 
1999*f169c0eaSGlenn Lagasse 	/* Get dataset's mountpoint and source values */
2000*f169c0eaSGlenn Lagasse 	if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint,
2001*f169c0eaSGlenn Lagasse 	    sizeof (mountpoint), &sourcetype, source, sizeof (source),
2002*f169c0eaSGlenn Lagasse 	    B_FALSE) != 0) {
2003*f169c0eaSGlenn Lagasse 		be_print_err(gettext("fix_mountpoint_callback: "
2004*f169c0eaSGlenn Lagasse 		    "failed to get mountpoint and sourcetype for %s\n"),
2005*f169c0eaSGlenn Lagasse 		    zfs_get_name(zhp));
2006*f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
2007*f169c0eaSGlenn Lagasse 		return (BE_ERR_ZFS);
2008*f169c0eaSGlenn Lagasse 	}
2009*f169c0eaSGlenn Lagasse 
2010*f169c0eaSGlenn Lagasse 	/*
2011*f169c0eaSGlenn Lagasse 	 * If the mountpoint is not inherited and the mountpoint is not
2012*f169c0eaSGlenn Lagasse 	 * 'legacy', this file system potentially needs its mountpoint
2013*f169c0eaSGlenn Lagasse 	 * fixed.
2014*f169c0eaSGlenn Lagasse 	 */
2015*f169c0eaSGlenn Lagasse 	if (!(sourcetype & ZPROP_SRC_INHERITED) &&
2016*f169c0eaSGlenn Lagasse 	    strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0) {
2017*f169c0eaSGlenn Lagasse 
2018*f169c0eaSGlenn Lagasse 		/*
2019*f169c0eaSGlenn Lagasse 		 * Check if this file system's current mountpoint is
2020*f169c0eaSGlenn Lagasse 		 * under the altroot we're fixing it against.
2021*f169c0eaSGlenn Lagasse 		 */
2022*f169c0eaSGlenn Lagasse 		if (strncmp(mountpoint, altroot, strlen(altroot)) == 0 &&
2023*f169c0eaSGlenn Lagasse 		    mountpoint[strlen(altroot)] == '/') {
2024*f169c0eaSGlenn Lagasse 
2025*f169c0eaSGlenn Lagasse 			/*
2026*f169c0eaSGlenn Lagasse 			 * Get this dataset's mountpoint relative to the
2027*f169c0eaSGlenn Lagasse 			 * altroot.
2028*f169c0eaSGlenn Lagasse 			 */
2029*f169c0eaSGlenn Lagasse 			zhp_mountpoint = mountpoint + strlen(altroot);
2030*f169c0eaSGlenn Lagasse 
2031*f169c0eaSGlenn Lagasse 			/* Fix this dataset's mountpoint value */
2032*f169c0eaSGlenn Lagasse 			if (zfs_prop_set(zhp,
2033*f169c0eaSGlenn Lagasse 			    zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
2034*f169c0eaSGlenn Lagasse 			    zhp_mountpoint)) {
2035*f169c0eaSGlenn Lagasse 				be_print_err(gettext("fix_mountpoint_callback: "
2036*f169c0eaSGlenn Lagasse 				    "failed to set mountpoint for %s to "
2037*f169c0eaSGlenn Lagasse 				    "%s: %s\n"), zfs_get_name(zhp),
2038*f169c0eaSGlenn Lagasse 				    zhp_mountpoint,
2039*f169c0eaSGlenn Lagasse 				    libzfs_error_description(g_zfs));
2040*f169c0eaSGlenn Lagasse 				ret = zfs_err_to_be_err(g_zfs);
2041*f169c0eaSGlenn Lagasse 				ZFS_CLOSE(zhp);
2042*f169c0eaSGlenn Lagasse 				return (ret);
2043*f169c0eaSGlenn Lagasse 			}
2044*f169c0eaSGlenn Lagasse 		}
2045*f169c0eaSGlenn Lagasse 	}
2046*f169c0eaSGlenn Lagasse 
2047*f169c0eaSGlenn Lagasse 	/* Iterate through this dataset's children and fix them */
2048*f169c0eaSGlenn Lagasse 	if ((ret = zfs_iter_filesystems(zhp, fix_mountpoint_callback,
2049*f169c0eaSGlenn Lagasse 	    altroot)) != 0) {
2050*f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
2051*f169c0eaSGlenn Lagasse 		return (ret);
2052*f169c0eaSGlenn Lagasse 	}
2053*f169c0eaSGlenn Lagasse 
2054*f169c0eaSGlenn Lagasse 
2055*f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp);
2056*f169c0eaSGlenn Lagasse 	return (0);
2057*f169c0eaSGlenn Lagasse }
2058*f169c0eaSGlenn Lagasse 
2059*f169c0eaSGlenn Lagasse /*
2060*f169c0eaSGlenn Lagasse  * Function:	be_mount_root
2061*f169c0eaSGlenn Lagasse  * Description:	This function mounts the root dataset of a BE at the
2062*f169c0eaSGlenn Lagasse  *		specified altroot.
2063*f169c0eaSGlenn Lagasse  * Parameters:
2064*f169c0eaSGlenn Lagasse  *		zhp - zfs_handle_t pointer to root dataset of a BE that is
2065*f169c0eaSGlenn Lagasse  *		to be mounted at altroot.
2066*f169c0eaSGlenn Lagasse  *		altroot - location of where to mount the BE root.
2067*f169c0eaSGlenn Lagasse  * Return:
2068*f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
2069*f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
2070*f169c0eaSGlenn Lagasse  * Scope:
2071*f169c0eaSGlenn Lagasse  *		Private
2072*f169c0eaSGlenn Lagasse  */
2073*f169c0eaSGlenn Lagasse static int
2074*f169c0eaSGlenn Lagasse be_mount_root(zfs_handle_t *zhp, char *altroot)
2075*f169c0eaSGlenn Lagasse {
2076*f169c0eaSGlenn Lagasse 	char		mountpoint[MAXPATHLEN];
2077*f169c0eaSGlenn Lagasse 
2078*f169c0eaSGlenn Lagasse 	/* Get mountpoint property of dataset */
2079*f169c0eaSGlenn Lagasse 	if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint,
2080*f169c0eaSGlenn Lagasse 	    sizeof (mountpoint), NULL, NULL, 0, B_FALSE) != 0) {
2081*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_mount_root: failed to "
2082*f169c0eaSGlenn Lagasse 		    "get mountpoint property for %s: %s\n"), zfs_get_name(zhp),
2083*f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
2084*f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
2085*f169c0eaSGlenn Lagasse 	}
2086*f169c0eaSGlenn Lagasse 
2087*f169c0eaSGlenn Lagasse 	/*
2088*f169c0eaSGlenn Lagasse 	 * Set the canmount property for the BE's root dataset to 'noauto' just
2089*f169c0eaSGlenn Lagasse 	 * in case it's been set to 'on'.  We do this so that when we change its
2090*f169c0eaSGlenn Lagasse 	 * mountpoint, zfs won't immediately try to mount it.
2091*f169c0eaSGlenn Lagasse 	 */
2092*f169c0eaSGlenn Lagasse 	if (zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_CANMOUNT), "noauto")
2093*f169c0eaSGlenn Lagasse 	    != 0) {
2094*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_mount_root: failed to "
2095*f169c0eaSGlenn Lagasse 		    "set canmount property to 'noauto' (%s): %s\n"),
2096*f169c0eaSGlenn Lagasse 		    zfs_get_name(zhp), libzfs_error_description(g_zfs));
2097*f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
2098*f169c0eaSGlenn Lagasse 	}
2099*f169c0eaSGlenn Lagasse 
2100*f169c0eaSGlenn Lagasse 	/* Set mountpoint for BE's root filesystem */
2101*f169c0eaSGlenn Lagasse 	if (zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_MOUNTPOINT), altroot)
2102*f169c0eaSGlenn Lagasse 	    != 0) {
2103*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_mount_root: failed to "
2104*f169c0eaSGlenn Lagasse 		    "set mountpoint of %s to %s: %s\n"),
2105*f169c0eaSGlenn Lagasse 		    zfs_get_name(zhp), altroot,
2106*f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
2107*f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
2108*f169c0eaSGlenn Lagasse 	}
2109*f169c0eaSGlenn Lagasse 
2110*f169c0eaSGlenn Lagasse 	/* Mount the BE's root filesystem */
2111*f169c0eaSGlenn Lagasse 	if (zfs_mount(zhp, NULL, 0) != 0) {
2112*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_mount_root: failed to "
2113*f169c0eaSGlenn Lagasse 		    "mount dataset %s at %s: %s\n"), zfs_get_name(zhp),
2114*f169c0eaSGlenn Lagasse 		    altroot, libzfs_error_description(g_zfs));
2115*f169c0eaSGlenn Lagasse 		/*
2116*f169c0eaSGlenn Lagasse 		 * Set this BE's root filesystem 'mountpoint' property
2117*f169c0eaSGlenn Lagasse 		 * back to what it was before.
2118*f169c0eaSGlenn Lagasse 		 */
2119*f169c0eaSGlenn Lagasse 		(void) zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
2120*f169c0eaSGlenn Lagasse 		    mountpoint);
2121*f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
2122*f169c0eaSGlenn Lagasse 	}
2123*f169c0eaSGlenn Lagasse 
2124*f169c0eaSGlenn Lagasse 	return (BE_SUCCESS);
2125*f169c0eaSGlenn Lagasse }
2126*f169c0eaSGlenn Lagasse 
2127*f169c0eaSGlenn Lagasse /*
2128*f169c0eaSGlenn Lagasse  * Function:	be_unmount_root
2129*f169c0eaSGlenn Lagasse  * Description:	This function unmounts the root dataset of a BE, but before
2130*f169c0eaSGlenn Lagasse  *		unmounting, it looks at the BE's vfstab to determine
2131*f169c0eaSGlenn Lagasse  *		if the root dataset mountpoint should be left as 'legacy'
2132*f169c0eaSGlenn Lagasse  *		or '/'.  If the vfstab contains an entry for this root
2133*f169c0eaSGlenn Lagasse  *		dataset with a mountpoint of '/', it sets the mountpoint
2134*f169c0eaSGlenn Lagasse  *		property to 'legacy'.
2135*f169c0eaSGlenn Lagasse  *
2136*f169c0eaSGlenn Lagasse  * Parameters:
2137*f169c0eaSGlenn Lagasse  *		zhp - zfs_handle_t pointer of the BE root dataset that
2138*f169c0eaSGlenn Lagasse  *		is currently mounted.
2139*f169c0eaSGlenn Lagasse  *		ud - be_unmount_data_t pointer providing unmount data
2140*f169c0eaSGlenn Lagasse  *		for the given BE root dataset.
2141*f169c0eaSGlenn Lagasse  * Returns:
2142*f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
2143*f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
2144*f169c0eaSGlenn Lagasse  * Scope:
2145*f169c0eaSGlenn Lagasse  *		Private
2146*f169c0eaSGlenn Lagasse  */
2147*f169c0eaSGlenn Lagasse static int
2148*f169c0eaSGlenn Lagasse be_unmount_root(zfs_handle_t *zhp, be_unmount_data_t *ud)
2149*f169c0eaSGlenn Lagasse {
2150*f169c0eaSGlenn Lagasse 	char		mountpoint[MAXPATHLEN];
2151*f169c0eaSGlenn Lagasse 	boolean_t	is_legacy = B_FALSE;
2152*f169c0eaSGlenn Lagasse 
2153*f169c0eaSGlenn Lagasse 	/* See if this is a legacy mounted root */
2154*f169c0eaSGlenn Lagasse 	if (get_mountpoint_from_vfstab(ud->altroot, zfs_get_name(zhp),
2155*f169c0eaSGlenn Lagasse 	    mountpoint, sizeof (mountpoint), B_FALSE) == BE_SUCCESS &&
2156*f169c0eaSGlenn Lagasse 	    strcmp(mountpoint, "/") == 0) {
2157*f169c0eaSGlenn Lagasse 		is_legacy = B_TRUE;
2158*f169c0eaSGlenn Lagasse 	}
2159*f169c0eaSGlenn Lagasse 
2160*f169c0eaSGlenn Lagasse 	/* Unmount the dataset */
2161*f169c0eaSGlenn Lagasse 	if (zfs_unmount(zhp, NULL, ud->force ? MS_FORCE : 0) != 0) {
2162*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_unmount_root: failed to "
2163*f169c0eaSGlenn Lagasse 		    "unmount BE root dataset %s: %s\n"), zfs_get_name(zhp),
2164*f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
2165*f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
2166*f169c0eaSGlenn Lagasse 	}
2167*f169c0eaSGlenn Lagasse 
2168*f169c0eaSGlenn Lagasse 	/* Set canmount property for this BE's root filesystem to noauto */
2169*f169c0eaSGlenn Lagasse 	if (zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_CANMOUNT), "noauto")
2170*f169c0eaSGlenn Lagasse 	    != 0) {
2171*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_unmount_root: failed to "
2172*f169c0eaSGlenn Lagasse 		    "set canmount property for %s to 'noauto': %s\n"),
2173*f169c0eaSGlenn Lagasse 		    zfs_get_name(zhp), libzfs_error_description(g_zfs));
2174*f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
2175*f169c0eaSGlenn Lagasse 	}
2176*f169c0eaSGlenn Lagasse 
2177*f169c0eaSGlenn Lagasse 	/*
2178*f169c0eaSGlenn Lagasse 	 * Set mountpoint for BE's root dataset back to '/', or 'legacy'
2179*f169c0eaSGlenn Lagasse 	 * if its a legacy mounted root.
2180*f169c0eaSGlenn Lagasse 	 */
2181*f169c0eaSGlenn Lagasse 	if (zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
2182*f169c0eaSGlenn Lagasse 	    is_legacy ? ZFS_MOUNTPOINT_LEGACY : "/") != 0) {
2183*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_unmount_root: failed to "
2184*f169c0eaSGlenn Lagasse 		    "set mountpoint of %s to %s\n"), zfs_get_name(zhp),
2185*f169c0eaSGlenn Lagasse 		    is_legacy ? ZFS_MOUNTPOINT_LEGACY : "/");
2186*f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
2187*f169c0eaSGlenn Lagasse 	}
2188*f169c0eaSGlenn Lagasse 
2189*f169c0eaSGlenn Lagasse 	return (BE_SUCCESS);
2190*f169c0eaSGlenn Lagasse }
2191*f169c0eaSGlenn Lagasse 
2192*f169c0eaSGlenn Lagasse /*
2193*f169c0eaSGlenn Lagasse  * Function:	fix_mountpoint
2194*f169c0eaSGlenn Lagasse  * Description:	This function checks the mountpoint of an unmounted BE to make
2195*f169c0eaSGlenn Lagasse  *		sure that it is set to either 'legacy' or '/'.  If it's not,
2196*f169c0eaSGlenn Lagasse  *		then we're in a situation where an unmounted BE has some random
2197*f169c0eaSGlenn Lagasse  *		mountpoint set for it.  (This could happen if the system was
2198*f169c0eaSGlenn Lagasse  *		rebooted while an inactive BE was mounted).  This function
2199*f169c0eaSGlenn Lagasse  *		attempts to fix its mountpoints.
2200*f169c0eaSGlenn Lagasse  * Parameters:
2201*f169c0eaSGlenn Lagasse  *		zhp - zfs_handle_t pointer to root dataset of the BE
2202*f169c0eaSGlenn Lagasse  *		whose mountpoint needs to be checked.
2203*f169c0eaSGlenn Lagasse  * Return:
2204*f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
2205*f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
2206*f169c0eaSGlenn Lagasse  * Scope:
2207*f169c0eaSGlenn Lagasse  *		Private
2208*f169c0eaSGlenn Lagasse  */
2209*f169c0eaSGlenn Lagasse static int
2210*f169c0eaSGlenn Lagasse fix_mountpoint(zfs_handle_t *zhp)
2211*f169c0eaSGlenn Lagasse {
2212*f169c0eaSGlenn Lagasse 	be_unmount_data_t	ud = { 0 };
2213*f169c0eaSGlenn Lagasse 	char	*altroot = NULL;
2214*f169c0eaSGlenn Lagasse 	char	mountpoint[MAXPATHLEN];
2215*f169c0eaSGlenn Lagasse 	int	ret = BE_SUCCESS;
2216*f169c0eaSGlenn Lagasse 
2217*f169c0eaSGlenn Lagasse 	/*
2218*f169c0eaSGlenn Lagasse 	 * Record what this BE's root dataset mountpoint property is currently
2219*f169c0eaSGlenn Lagasse 	 * set to.
2220*f169c0eaSGlenn Lagasse 	 */
2221*f169c0eaSGlenn Lagasse 	if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint,
2222*f169c0eaSGlenn Lagasse 	    sizeof (mountpoint), NULL, NULL, 0, B_FALSE) != 0) {
2223*f169c0eaSGlenn Lagasse 		be_print_err(gettext("fix_mountpoint: failed to get "
2224*f169c0eaSGlenn Lagasse 		    "mountpoint property of (%s): %s\n"), zfs_get_name(zhp),
2225*f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
2226*f169c0eaSGlenn Lagasse 		return (BE_ERR_ZFS);
2227*f169c0eaSGlenn Lagasse 	}
2228*f169c0eaSGlenn Lagasse 
2229*f169c0eaSGlenn Lagasse 	/*
2230*f169c0eaSGlenn Lagasse 	 * If the root dataset mountpoint is set to 'legacy' or '/', we're okay.
2231*f169c0eaSGlenn Lagasse 	 */
2232*f169c0eaSGlenn Lagasse 	if (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0 ||
2233*f169c0eaSGlenn Lagasse 	    strcmp(mountpoint, "/") == 0) {
2234*f169c0eaSGlenn Lagasse 		return (BE_SUCCESS);
2235*f169c0eaSGlenn Lagasse 	}
2236*f169c0eaSGlenn Lagasse 
2237*f169c0eaSGlenn Lagasse 	/*
2238*f169c0eaSGlenn Lagasse 	 * Iterate through this BE's children datasets and fix
2239*f169c0eaSGlenn Lagasse 	 * them if they need fixing.
2240*f169c0eaSGlenn Lagasse 	 */
2241*f169c0eaSGlenn Lagasse 	if (zfs_iter_filesystems(zhp, fix_mountpoint_callback, mountpoint)
2242*f169c0eaSGlenn Lagasse 	    != 0) {
2243*f169c0eaSGlenn Lagasse 		return (BE_ERR_ZFS);
2244*f169c0eaSGlenn Lagasse 	}
2245*f169c0eaSGlenn Lagasse 
2246*f169c0eaSGlenn Lagasse 	/*
2247*f169c0eaSGlenn Lagasse 	 * The process of mounting and unmounting the root file system
2248*f169c0eaSGlenn Lagasse 	 * will fix its mountpoint to correctly be either 'legacy' or '/'
2249*f169c0eaSGlenn Lagasse 	 * since be_unmount_root will do the right thing by looking at
2250*f169c0eaSGlenn Lagasse 	 * its vfstab.
2251*f169c0eaSGlenn Lagasse 	 */
2252*f169c0eaSGlenn Lagasse 
2253*f169c0eaSGlenn Lagasse 	/* Generate temporary altroot to mount the root file system */
2254*f169c0eaSGlenn Lagasse 	if ((ret = be_make_tmp_mountpoint(&altroot)) != BE_SUCCESS) {
2255*f169c0eaSGlenn Lagasse 		be_print_err(gettext("fix_mountpoint: failed to "
2256*f169c0eaSGlenn Lagasse 		    "make temporary mountpoint\n"));
2257*f169c0eaSGlenn Lagasse 		return (ret);
2258*f169c0eaSGlenn Lagasse 	}
2259*f169c0eaSGlenn Lagasse 
2260*f169c0eaSGlenn Lagasse 	/* Mount and unmount the root. */
2261*f169c0eaSGlenn Lagasse 	if ((ret = be_mount_root(zhp, altroot)) != BE_SUCCESS) {
2262*f169c0eaSGlenn Lagasse 		be_print_err(gettext("fix_mountpoint: failed to "
2263*f169c0eaSGlenn Lagasse 		    "mount BE root file system\n"));
2264*f169c0eaSGlenn Lagasse 		goto cleanup;
2265*f169c0eaSGlenn Lagasse 	}
2266*f169c0eaSGlenn Lagasse 	ud.altroot = altroot;
2267*f169c0eaSGlenn Lagasse 	if ((ret = be_unmount_root(zhp, &ud)) != BE_SUCCESS) {
2268*f169c0eaSGlenn Lagasse 		be_print_err(gettext("fix_mountpoint: failed to "
2269*f169c0eaSGlenn Lagasse 		    "unmount BE root file system\n"));
2270*f169c0eaSGlenn Lagasse 		goto cleanup;
2271*f169c0eaSGlenn Lagasse 	}
2272*f169c0eaSGlenn Lagasse 
2273*f169c0eaSGlenn Lagasse cleanup:
2274*f169c0eaSGlenn Lagasse 	free(altroot);
2275*f169c0eaSGlenn Lagasse 
2276*f169c0eaSGlenn Lagasse 	return (ret);
2277*f169c0eaSGlenn Lagasse }
2278*f169c0eaSGlenn Lagasse 
2279*f169c0eaSGlenn Lagasse /*
2280*f169c0eaSGlenn Lagasse  * Function:	be_mount_zones
2281*f169c0eaSGlenn Lagasse  * Description:	This function finds all supported non-global zones in the
2282*f169c0eaSGlenn Lagasse  *		given global BE and mounts them with respect to where the
2283*f169c0eaSGlenn Lagasse  *		global BE is currently mounted.  The global BE datasets
2284*f169c0eaSGlenn Lagasse  *		(including its shared datasets) are expected to already
2285*f169c0eaSGlenn Lagasse  *		be mounted.
2286*f169c0eaSGlenn Lagasse  * Parameters:
2287*f169c0eaSGlenn Lagasse  *		be_zhp - zfs_handle_t pointer to the root dataset of the
2288*f169c0eaSGlenn Lagasse  *			global BE.
2289*f169c0eaSGlenn Lagasse  *		md - be_mount_data_t pointer to data for global BE.
2290*f169c0eaSGlenn Lagasse  * Returns:
2291*f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
2292*f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
2293*f169c0eaSGlenn Lagasse  * Scope:
2294*f169c0eaSGlenn Lagasse  *		Private
2295*f169c0eaSGlenn Lagasse  */
2296*f169c0eaSGlenn Lagasse static int
2297*f169c0eaSGlenn Lagasse be_mount_zones(zfs_handle_t *be_zhp, be_mount_data_t *md)
2298*f169c0eaSGlenn Lagasse {
2299*f169c0eaSGlenn Lagasse 	zoneBrandList_t	*brands = NULL;
2300*f169c0eaSGlenn Lagasse 	zoneList_t	zlst = NULL;
2301*f169c0eaSGlenn Lagasse 	char		*zonename = NULL;
2302*f169c0eaSGlenn Lagasse 	char		*zonepath = NULL;
2303*f169c0eaSGlenn Lagasse 	char		*zonepath_ds = NULL;
2304*f169c0eaSGlenn Lagasse 	int		k;
2305*f169c0eaSGlenn Lagasse 	int		ret = BE_SUCCESS;
2306*f169c0eaSGlenn Lagasse 
2307*f169c0eaSGlenn Lagasse 	z_set_zone_root(md->altroot);
2308*f169c0eaSGlenn Lagasse 
2309*f169c0eaSGlenn Lagasse 	if ((brands = be_get_supported_brandlist()) == NULL) {
2310*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_mount_zones: "
2311*f169c0eaSGlenn Lagasse 		    "no supported brands\n"));
2312*f169c0eaSGlenn Lagasse 		return (BE_SUCCESS);
2313*f169c0eaSGlenn Lagasse 	}
2314*f169c0eaSGlenn Lagasse 
2315*f169c0eaSGlenn Lagasse 	zlst = z_get_nonglobal_zone_list_by_brand(brands);
2316*f169c0eaSGlenn Lagasse 	if (zlst == NULL) {
2317*f169c0eaSGlenn Lagasse 		z_free_brand_list(brands);
2318*f169c0eaSGlenn Lagasse 		return (BE_SUCCESS);
2319*f169c0eaSGlenn Lagasse 	}
2320*f169c0eaSGlenn Lagasse 
2321*f169c0eaSGlenn Lagasse 	for (k = 0; (zonename = z_zlist_get_zonename(zlst, k)) != NULL; k++) {
2322*f169c0eaSGlenn Lagasse 		if (z_zlist_get_current_state(zlst, k) ==
2323*f169c0eaSGlenn Lagasse 		    ZONE_STATE_INSTALLED) {
2324*f169c0eaSGlenn Lagasse 			zonepath = z_zlist_get_zonepath(zlst, k);
2325*f169c0eaSGlenn Lagasse 
2326*f169c0eaSGlenn Lagasse 			/*
2327*f169c0eaSGlenn Lagasse 			 * Get the dataset of this zonepath in current BE.
2328*f169c0eaSGlenn Lagasse 			 * If its not a dataset, skip it.
2329*f169c0eaSGlenn Lagasse 			 */
2330*f169c0eaSGlenn Lagasse 			if ((zonepath_ds = be_get_ds_from_dir(zonepath))
2331*f169c0eaSGlenn Lagasse 			    == NULL)
2332*f169c0eaSGlenn Lagasse 				continue;
2333*f169c0eaSGlenn Lagasse 
2334*f169c0eaSGlenn Lagasse 			/*
2335*f169c0eaSGlenn Lagasse 			 * Check if this zone is supported based on
2336*f169c0eaSGlenn Lagasse 			 * the dataset of its zonepath
2337*f169c0eaSGlenn Lagasse 			 */
2338*f169c0eaSGlenn Lagasse 			if (!be_zone_supported(zonepath_ds)) {
2339*f169c0eaSGlenn Lagasse 				free(zonepath_ds);
2340*f169c0eaSGlenn Lagasse 				zonepath_ds = NULL;
2341*f169c0eaSGlenn Lagasse 				continue;
2342*f169c0eaSGlenn Lagasse 			}
2343*f169c0eaSGlenn Lagasse 
2344*f169c0eaSGlenn Lagasse 			/*
2345*f169c0eaSGlenn Lagasse 			 * if BE's shared file systems are already mounted,
2346*f169c0eaSGlenn Lagasse 			 * zone path dataset would have already been lofs
2347*f169c0eaSGlenn Lagasse 			 * mounted under altroot. Otherwise, we need to do
2348*f169c0eaSGlenn Lagasse 			 * it here.
2349*f169c0eaSGlenn Lagasse 			 */
2350*f169c0eaSGlenn Lagasse 			if (!md->shared_fs) {
2351*f169c0eaSGlenn Lagasse 				ret = loopback_mount_zonepath(zonepath, md);
2352*f169c0eaSGlenn Lagasse 				if (ret != BE_SUCCESS)
2353*f169c0eaSGlenn Lagasse 					goto done;
2354*f169c0eaSGlenn Lagasse 			}
2355*f169c0eaSGlenn Lagasse 
2356*f169c0eaSGlenn Lagasse 
2357*f169c0eaSGlenn Lagasse 			/* Mount this zone */
2358*f169c0eaSGlenn Lagasse 			ret = be_mount_one_zone(be_zhp, md, zonename,
2359*f169c0eaSGlenn Lagasse 			    zonepath, zonepath_ds);
2360*f169c0eaSGlenn Lagasse 
2361*f169c0eaSGlenn Lagasse 			free(zonepath_ds);
2362*f169c0eaSGlenn Lagasse 			zonepath_ds = NULL;
2363*f169c0eaSGlenn Lagasse 
2364*f169c0eaSGlenn Lagasse 			if (ret != BE_SUCCESS) {
2365*f169c0eaSGlenn Lagasse 				be_print_err(gettext("be_mount_zones: "
2366*f169c0eaSGlenn Lagasse 				    "failed to mount zone %s under "
2367*f169c0eaSGlenn Lagasse 				    "altroot %s\n"), zonename, md->altroot);
2368*f169c0eaSGlenn Lagasse 				goto done;
2369*f169c0eaSGlenn Lagasse 			}
2370*f169c0eaSGlenn Lagasse 		}
2371*f169c0eaSGlenn Lagasse 	}
2372*f169c0eaSGlenn Lagasse 
2373*f169c0eaSGlenn Lagasse done:
2374*f169c0eaSGlenn Lagasse 	z_free_brand_list(brands);
2375*f169c0eaSGlenn Lagasse 	z_free_zone_list(zlst);
2376*f169c0eaSGlenn Lagasse 	/*
2377*f169c0eaSGlenn Lagasse 	 * libinstzones caches mnttab and uses cached version for resolving lofs
2378*f169c0eaSGlenn Lagasse 	 * mounts when we call z_resolve_lofs. It creates the cached version
2379*f169c0eaSGlenn Lagasse 	 * when the first call to z_resolve_lofs happens. So, library's cached
2380*f169c0eaSGlenn Lagasse 	 * mnttab doesn't contain entries for lofs mounts created in the above
2381*f169c0eaSGlenn Lagasse 	 * loop. Because of this, subsequent calls to z_resolve_lofs would fail
2382*f169c0eaSGlenn Lagasse 	 * to resolve these lofs mounts. So, here we destroy library's cached
2383*f169c0eaSGlenn Lagasse 	 * mnttab to force its recreation when the next call to z_resolve_lofs
2384*f169c0eaSGlenn Lagasse 	 * happens.
2385*f169c0eaSGlenn Lagasse 	 */
2386*f169c0eaSGlenn Lagasse 	z_destroyMountTable();
2387*f169c0eaSGlenn Lagasse 	return (ret);
2388*f169c0eaSGlenn Lagasse }
2389*f169c0eaSGlenn Lagasse 
2390*f169c0eaSGlenn Lagasse /*
2391*f169c0eaSGlenn Lagasse  * Function:	be_unmount_zones
2392*f169c0eaSGlenn Lagasse  * Description:	This function finds all supported non-global zones in the
2393*f169c0eaSGlenn Lagasse  *		given mounted global BE and unmounts them.
2394*f169c0eaSGlenn Lagasse  * Parameters:
2395*f169c0eaSGlenn Lagasse  *		ud - unmount_data_t pointer data for the global BE.
2396*f169c0eaSGlenn Lagasse  * Returns:
2397*f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
2398*f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
2399*f169c0eaSGlenn Lagasse  * Scope:
2400*f169c0eaSGlenn Lagasse  *		Private
2401*f169c0eaSGlenn Lagasse  */
2402*f169c0eaSGlenn Lagasse static int
2403*f169c0eaSGlenn Lagasse be_unmount_zones(be_unmount_data_t *ud)
2404*f169c0eaSGlenn Lagasse {
2405*f169c0eaSGlenn Lagasse 	zoneBrandList_t		*brands = NULL;
2406*f169c0eaSGlenn Lagasse 	zoneList_t		zlst = NULL;
2407*f169c0eaSGlenn Lagasse 	char			*zonename = NULL;
2408*f169c0eaSGlenn Lagasse 	char			*zonepath = NULL;
2409*f169c0eaSGlenn Lagasse 	char			alt_zonepath[MAXPATHLEN];
2410*f169c0eaSGlenn Lagasse 	char			*zonepath_ds = NULL;
2411*f169c0eaSGlenn Lagasse 	int			k;
2412*f169c0eaSGlenn Lagasse 	int			ret = BE_SUCCESS;
2413*f169c0eaSGlenn Lagasse 
2414*f169c0eaSGlenn Lagasse 	z_set_zone_root(ud->altroot);
2415*f169c0eaSGlenn Lagasse 
2416*f169c0eaSGlenn Lagasse 	if ((brands = be_get_supported_brandlist()) == NULL) {
2417*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_unmount_zones: "
2418*f169c0eaSGlenn Lagasse 		    "no supported brands\n"));
2419*f169c0eaSGlenn Lagasse 		return (BE_SUCCESS);
2420*f169c0eaSGlenn Lagasse 	}
2421*f169c0eaSGlenn Lagasse 
2422*f169c0eaSGlenn Lagasse 	zlst = z_get_nonglobal_zone_list_by_brand(brands);
2423*f169c0eaSGlenn Lagasse 	if (zlst == NULL) {
2424*f169c0eaSGlenn Lagasse 		z_free_brand_list(brands);
2425*f169c0eaSGlenn Lagasse 		return (BE_SUCCESS);
2426*f169c0eaSGlenn Lagasse 	}
2427*f169c0eaSGlenn Lagasse 
2428*f169c0eaSGlenn Lagasse 	for (k = 0; (zonename = z_zlist_get_zonename(zlst, k)) != NULL; k++) {
2429*f169c0eaSGlenn Lagasse 		if (z_zlist_get_current_state(zlst, k) ==
2430*f169c0eaSGlenn Lagasse 		    ZONE_STATE_INSTALLED) {
2431*f169c0eaSGlenn Lagasse 			zonepath = z_zlist_get_zonepath(zlst, k);
2432*f169c0eaSGlenn Lagasse 
2433*f169c0eaSGlenn Lagasse 			/* Build zone's zonepath wrt the global BE altroot */
2434*f169c0eaSGlenn Lagasse 			(void) snprintf(alt_zonepath, sizeof (alt_zonepath),
2435*f169c0eaSGlenn Lagasse 			    "%s%s", ud->altroot, zonepath);
2436*f169c0eaSGlenn Lagasse 
2437*f169c0eaSGlenn Lagasse 			/*
2438*f169c0eaSGlenn Lagasse 			 * Get the dataset of this zonepath.  If its not
2439*f169c0eaSGlenn Lagasse 			 * a dataset, skip it.
2440*f169c0eaSGlenn Lagasse 			 */
2441*f169c0eaSGlenn Lagasse 			if ((zonepath_ds = be_get_ds_from_dir(alt_zonepath))
2442*f169c0eaSGlenn Lagasse 			    == NULL)
2443*f169c0eaSGlenn Lagasse 				continue;
2444*f169c0eaSGlenn Lagasse 
2445*f169c0eaSGlenn Lagasse 			/*
2446*f169c0eaSGlenn Lagasse 			 * Check if this zone is supported based on the
2447*f169c0eaSGlenn Lagasse 			 * dataset of its zonepath.
2448*f169c0eaSGlenn Lagasse 			 */
2449*f169c0eaSGlenn Lagasse 			if (!be_zone_supported(zonepath_ds)) {
2450*f169c0eaSGlenn Lagasse 				free(zonepath_ds);
2451*f169c0eaSGlenn Lagasse 				zonepath_ds = NULL;
2452*f169c0eaSGlenn Lagasse 				continue;
2453*f169c0eaSGlenn Lagasse 			}
2454*f169c0eaSGlenn Lagasse 
2455*f169c0eaSGlenn Lagasse 			/* Unmount this zone */
2456*f169c0eaSGlenn Lagasse 			ret = be_unmount_one_zone(ud, zonename, zonepath,
2457*f169c0eaSGlenn Lagasse 			    zonepath_ds);
2458*f169c0eaSGlenn Lagasse 
2459*f169c0eaSGlenn Lagasse 			free(zonepath_ds);
2460*f169c0eaSGlenn Lagasse 			zonepath_ds = NULL;
2461*f169c0eaSGlenn Lagasse 
2462*f169c0eaSGlenn Lagasse 			if (ret != BE_SUCCESS) {
2463*f169c0eaSGlenn Lagasse 				be_print_err(gettext("be_unmount_zones:"
2464*f169c0eaSGlenn Lagasse 				    " failed to unmount zone %s from "
2465*f169c0eaSGlenn Lagasse 				    "altroot %s\n"), zonename, ud->altroot);
2466*f169c0eaSGlenn Lagasse 				goto done;
2467*f169c0eaSGlenn Lagasse 			}
2468*f169c0eaSGlenn Lagasse 		}
2469*f169c0eaSGlenn Lagasse 	}
2470*f169c0eaSGlenn Lagasse 
2471*f169c0eaSGlenn Lagasse done:
2472*f169c0eaSGlenn Lagasse 	z_free_brand_list(brands);
2473*f169c0eaSGlenn Lagasse 	z_free_zone_list(zlst);
2474*f169c0eaSGlenn Lagasse 	return (ret);
2475*f169c0eaSGlenn Lagasse }
2476*f169c0eaSGlenn Lagasse 
2477*f169c0eaSGlenn Lagasse /*
2478*f169c0eaSGlenn Lagasse  * Function:	be_mount_one_zone
2479*f169c0eaSGlenn Lagasse  * Description:	This function is called to mount one zone for a given
2480*f169c0eaSGlenn Lagasse  *		global BE.
2481*f169c0eaSGlenn Lagasse  * Parameters:
2482*f169c0eaSGlenn Lagasse  *		be_zhp - zfs_handle_t pointer to the root dataset of the
2483*f169c0eaSGlenn Lagasse  *			global BE
2484*f169c0eaSGlenn Lagasse  *		md - be_mount_data_t pointer to data for global BE
2485*f169c0eaSGlenn Lagasse  *		zonename - name of zone to mount
2486*f169c0eaSGlenn Lagasse  *		zonepath - zonepath of zone to mount
2487*f169c0eaSGlenn Lagasse  *		zonepath_ds - dataset for the zonepath
2488*f169c0eaSGlenn Lagasse  * Returns:
2489*f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
2490*f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
2491*f169c0eaSGlenn Lagasse  * Scope:
2492*f169c0eaSGlenn Lagasse  *		Private
2493*f169c0eaSGlenn Lagasse  */
2494*f169c0eaSGlenn Lagasse static int
2495*f169c0eaSGlenn Lagasse be_mount_one_zone(zfs_handle_t *be_zhp, be_mount_data_t *md, char *zonename,
2496*f169c0eaSGlenn Lagasse     char *zonepath, char *zonepath_ds)
2497*f169c0eaSGlenn Lagasse {
2498*f169c0eaSGlenn Lagasse 	be_mount_data_t	zone_md = { 0 };
2499*f169c0eaSGlenn Lagasse 	zfs_handle_t	*zone_zhp = NULL;
2500*f169c0eaSGlenn Lagasse 	char		zone_altroot[MAXPATHLEN];
2501*f169c0eaSGlenn Lagasse 	char		zoneroot[MAXPATHLEN];
2502*f169c0eaSGlenn Lagasse 	char		zoneroot_ds[MAXPATHLEN];
2503*f169c0eaSGlenn Lagasse 	int		ret = BE_SUCCESS;
2504*f169c0eaSGlenn Lagasse 
2505*f169c0eaSGlenn Lagasse 	/* Find the active zone root dataset for this zone for this BE */
2506*f169c0eaSGlenn Lagasse 	if ((ret = be_find_active_zone_root(be_zhp, zonepath_ds, zoneroot_ds,
2507*f169c0eaSGlenn Lagasse 	    sizeof (zoneroot_ds))) == BE_ERR_ZONE_NO_ACTIVE_ROOT) {
2508*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_mount_one_zone: did not "
2509*f169c0eaSGlenn Lagasse 		    "find active zone root for zone %s, skipping ...\n"),
2510*f169c0eaSGlenn Lagasse 		    zonename);
2511*f169c0eaSGlenn Lagasse 		return (BE_SUCCESS);
2512*f169c0eaSGlenn Lagasse 	} else if (ret != BE_SUCCESS) {
2513*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_mount_one_zone: failed to "
2514*f169c0eaSGlenn Lagasse 		    "find active zone root for zone %s\n"), zonename);
2515*f169c0eaSGlenn Lagasse 		return (ret);
2516*f169c0eaSGlenn Lagasse 	}
2517*f169c0eaSGlenn Lagasse 
2518*f169c0eaSGlenn Lagasse 	/* Get handle to active zoneroot dataset */
2519*f169c0eaSGlenn Lagasse 	if ((zone_zhp = zfs_open(g_zfs, zoneroot_ds, ZFS_TYPE_FILESYSTEM))
2520*f169c0eaSGlenn Lagasse 	    == NULL) {
2521*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_mount_one_zone: failed to "
2522*f169c0eaSGlenn Lagasse 		    "open zone root dataset (%s): %s\n"), zoneroot_ds,
2523*f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
2524*f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
2525*f169c0eaSGlenn Lagasse 	}
2526*f169c0eaSGlenn Lagasse 
2527*f169c0eaSGlenn Lagasse 	/* Generate string for zone's altroot path */
2528*f169c0eaSGlenn Lagasse 	be_make_zoneroot(zonepath, zoneroot, sizeof (zoneroot));
2529*f169c0eaSGlenn Lagasse 	(void) strlcpy(zone_altroot, md->altroot, sizeof (zone_altroot));
2530*f169c0eaSGlenn Lagasse 	(void) strlcat(zone_altroot, zoneroot, sizeof (zone_altroot));
2531*f169c0eaSGlenn Lagasse 
2532*f169c0eaSGlenn Lagasse 	/* Build mount_data for the zone */
2533*f169c0eaSGlenn Lagasse 	zone_md.altroot = zone_altroot;
2534*f169c0eaSGlenn Lagasse 	zone_md.shared_fs = md->shared_fs;
2535*f169c0eaSGlenn Lagasse 	zone_md.shared_rw = md->shared_rw;
2536*f169c0eaSGlenn Lagasse 
2537*f169c0eaSGlenn Lagasse 	/* Mount the zone's root file system */
2538*f169c0eaSGlenn Lagasse 	if ((ret = be_mount_zone_root(zone_zhp, &zone_md)) != BE_SUCCESS) {
2539*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_mount_one_zone: failed to "
2540*f169c0eaSGlenn Lagasse 		    "mount zone root file system at %s\n"), zone_altroot);
2541*f169c0eaSGlenn Lagasse 		goto done;
2542*f169c0eaSGlenn Lagasse 	}
2543*f169c0eaSGlenn Lagasse 
2544*f169c0eaSGlenn Lagasse 	/* Iterate through zone's children filesystems */
2545*f169c0eaSGlenn Lagasse 	if ((ret = zfs_iter_filesystems(zone_zhp, be_mount_callback,
2546*f169c0eaSGlenn Lagasse 	    zone_altroot)) != 0) {
2547*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_mount_one_zone: failed to "
2548*f169c0eaSGlenn Lagasse 		    "mount zone subordinate file systems at %s\n"),
2549*f169c0eaSGlenn Lagasse 		    zone_altroot);
2550*f169c0eaSGlenn Lagasse 		goto done;
2551*f169c0eaSGlenn Lagasse 	}
2552*f169c0eaSGlenn Lagasse 
2553*f169c0eaSGlenn Lagasse 	/* TODO: Mount all shared file systems for this zone */
2554*f169c0eaSGlenn Lagasse 
2555*f169c0eaSGlenn Lagasse done:
2556*f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zone_zhp);
2557*f169c0eaSGlenn Lagasse 	return (ret);
2558*f169c0eaSGlenn Lagasse }
2559*f169c0eaSGlenn Lagasse 
2560*f169c0eaSGlenn Lagasse /*
2561*f169c0eaSGlenn Lagasse  * Function:	be_unmount_one_zone
2562*f169c0eaSGlenn Lagasse  * Description:	This function unmount one zone for a give global BE.
2563*f169c0eaSGlenn Lagasse  * Parameters:
2564*f169c0eaSGlenn Lagasse  *		ud - be_unmount_data_t pointer to data for global BE
2565*f169c0eaSGlenn Lagasse  *		zonename - name of zone to unmount
2566*f169c0eaSGlenn Lagasse  *		zonepath - zonepath of the zone to unmount
2567*f169c0eaSGlenn Lagasse  *		zonepath_ds - dataset for the zonepath
2568*f169c0eaSGlenn Lagasse  * Returns:
2569*f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
2570*f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
2571*f169c0eaSGlenn Lagasse  * Scope:
2572*f169c0eaSGlenn Lagasse  *		Private
2573*f169c0eaSGlenn Lagasse  */
2574*f169c0eaSGlenn Lagasse static int
2575*f169c0eaSGlenn Lagasse be_unmount_one_zone(be_unmount_data_t *ud, char *zonename, char *zonepath,
2576*f169c0eaSGlenn Lagasse     char *zonepath_ds)
2577*f169c0eaSGlenn Lagasse {
2578*f169c0eaSGlenn Lagasse 	be_unmount_data_t	zone_ud = { 0 };
2579*f169c0eaSGlenn Lagasse 	zfs_handle_t	*zone_zhp = NULL;
2580*f169c0eaSGlenn Lagasse 	char		zone_altroot[MAXPATHLEN];
2581*f169c0eaSGlenn Lagasse 	char		zoneroot[MAXPATHLEN];
2582*f169c0eaSGlenn Lagasse 	char		zoneroot_ds[MAXPATHLEN];
2583*f169c0eaSGlenn Lagasse 	int		ret = BE_SUCCESS;
2584*f169c0eaSGlenn Lagasse 
2585*f169c0eaSGlenn Lagasse 	/* Generate string for zone's alternate root path */
2586*f169c0eaSGlenn Lagasse 	be_make_zoneroot(zonepath, zoneroot, sizeof (zoneroot));
2587*f169c0eaSGlenn Lagasse 	(void) strlcpy(zone_altroot, ud->altroot, sizeof (zone_altroot));
2588*f169c0eaSGlenn Lagasse 	(void) strlcat(zone_altroot, zoneroot, sizeof (zone_altroot));
2589*f169c0eaSGlenn Lagasse 
2590*f169c0eaSGlenn Lagasse 	/* Build be_unmount_data for zone */
2591*f169c0eaSGlenn Lagasse 	zone_ud.altroot = zone_altroot;
2592*f169c0eaSGlenn Lagasse 	zone_ud.force = ud->force;
2593*f169c0eaSGlenn Lagasse 
2594*f169c0eaSGlenn Lagasse 	/* Find the mounted zone root dataset for this zone for this BE */
2595*f169c0eaSGlenn Lagasse 	if ((ret = be_find_mounted_zone_root(zone_altroot, zonepath_ds,
2596*f169c0eaSGlenn Lagasse 	    zoneroot_ds, sizeof (zoneroot_ds))) == BE_ERR_NO_MOUNTED_ZONE) {
2597*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_unmount_one_zone: did not "
2598*f169c0eaSGlenn Lagasse 		    "find any zone root mounted for zone %s\n"), zonename);
2599*f169c0eaSGlenn Lagasse 		return (BE_SUCCESS);
2600*f169c0eaSGlenn Lagasse 	} else if (ret != BE_SUCCESS) {
2601*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_unmount_one_zone: failed to "
2602*f169c0eaSGlenn Lagasse 		    "find mounted zone root for zone %s\n"), zonename);
2603*f169c0eaSGlenn Lagasse 		return (ret);
2604*f169c0eaSGlenn Lagasse 	}
2605*f169c0eaSGlenn Lagasse 
2606*f169c0eaSGlenn Lagasse 	/* Get handle to zoneroot dataset mounted for this BE */
2607*f169c0eaSGlenn Lagasse 	if ((zone_zhp = zfs_open(g_zfs, zoneroot_ds, ZFS_TYPE_FILESYSTEM))
2608*f169c0eaSGlenn Lagasse 	    == NULL) {
2609*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_unmount_one_zone: failed to "
2610*f169c0eaSGlenn Lagasse 		    "open mounted zone root dataset (%s): %s\n"), zoneroot_ds,
2611*f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
2612*f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
2613*f169c0eaSGlenn Lagasse 	}
2614*f169c0eaSGlenn Lagasse 
2615*f169c0eaSGlenn Lagasse 	/* TODO: Unmount all shared file systems for this zone */
2616*f169c0eaSGlenn Lagasse 
2617*f169c0eaSGlenn Lagasse 	/* Iterate through zone's children filesystems and unmount them */
2618*f169c0eaSGlenn Lagasse 	if ((ret = zfs_iter_filesystems(zone_zhp, be_unmount_callback,
2619*f169c0eaSGlenn Lagasse 	    &zone_ud)) != 0) {
2620*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_unmount_one_zone: failed to "
2621*f169c0eaSGlenn Lagasse 		    "unmount zone subordinate file systems at %s\n"),
2622*f169c0eaSGlenn Lagasse 		    zone_altroot);
2623*f169c0eaSGlenn Lagasse 		goto done;
2624*f169c0eaSGlenn Lagasse 	}
2625*f169c0eaSGlenn Lagasse 
2626*f169c0eaSGlenn Lagasse 	/* Unmount the zone's root filesystem */
2627*f169c0eaSGlenn Lagasse 	if ((ret = be_unmount_zone_root(zone_zhp, &zone_ud)) != BE_SUCCESS) {
2628*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_unmount_one_zone: failed to "
2629*f169c0eaSGlenn Lagasse 		    "unmount zone root file system at %s\n"), zone_altroot);
2630*f169c0eaSGlenn Lagasse 		goto done;
2631*f169c0eaSGlenn Lagasse 	}
2632*f169c0eaSGlenn Lagasse 
2633*f169c0eaSGlenn Lagasse done:
2634*f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zone_zhp);
2635*f169c0eaSGlenn Lagasse 	return (ret);
2636*f169c0eaSGlenn Lagasse }
2637*f169c0eaSGlenn Lagasse 
2638*f169c0eaSGlenn Lagasse /*
2639*f169c0eaSGlenn Lagasse  * Function:	be_get_ds_from_dir_callback
2640*f169c0eaSGlenn Lagasse  * Description:	This is a callback function used to iterate all datasets
2641*f169c0eaSGlenn Lagasse  *		to find the one that is currently mounted at the directory
2642*f169c0eaSGlenn Lagasse  *		being searched for.  If matched, the name of the dataset is
2643*f169c0eaSGlenn Lagasse  *		returned in heap storage, so the caller is responsible for
2644*f169c0eaSGlenn Lagasse  *		freeing it.
2645*f169c0eaSGlenn Lagasse  * Parameters:
2646*f169c0eaSGlenn Lagasse  *		zhp - zfs_handle_t pointer to current dataset being processed.
2647*f169c0eaSGlenn Lagasse  *		data - dir_data_t pointer providing name of directory being
2648*f169c0eaSGlenn Lagasse  *			searched for.
2649*f169c0eaSGlenn Lagasse  * Returns:
2650*f169c0eaSGlenn Lagasse  *		1 - This dataset is mounted at directory being searched for.
2651*f169c0eaSGlenn Lagasse  *		0 - This dataset is not mounted at directory being searched for.
2652*f169c0eaSGlenn Lagasse  * Scope:
2653*f169c0eaSGlenn Lagasse  *		Private
2654*f169c0eaSGlenn Lagasse  */
2655*f169c0eaSGlenn Lagasse static int
2656*f169c0eaSGlenn Lagasse be_get_ds_from_dir_callback(zfs_handle_t *zhp, void *data)
2657*f169c0eaSGlenn Lagasse {
2658*f169c0eaSGlenn Lagasse 	dir_data_t	*dd = data;
2659*f169c0eaSGlenn Lagasse 	char		*mp = NULL;
2660*f169c0eaSGlenn Lagasse 	int		zret = 0;
2661*f169c0eaSGlenn Lagasse 
2662*f169c0eaSGlenn Lagasse 	if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) {
2663*f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
2664*f169c0eaSGlenn Lagasse 		return (0);
2665*f169c0eaSGlenn Lagasse 	}
2666*f169c0eaSGlenn Lagasse 
2667*f169c0eaSGlenn Lagasse 	if (zfs_is_mounted(zhp, &mp) && mp != NULL &&
2668*f169c0eaSGlenn Lagasse 	    strcmp(mp, dd->dir) == 0) {
2669*f169c0eaSGlenn Lagasse 		if ((dd->ds = strdup(zfs_get_name(zhp))) == NULL) {
2670*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_get_ds_from_dir_callback: "
2671*f169c0eaSGlenn Lagasse 			    "memory allocation failed\n"));
2672*f169c0eaSGlenn Lagasse 			ZFS_CLOSE(zhp);
2673*f169c0eaSGlenn Lagasse 			return (0);
2674*f169c0eaSGlenn Lagasse 		}
2675*f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
2676*f169c0eaSGlenn Lagasse 		return (1);
2677*f169c0eaSGlenn Lagasse 	}
2678*f169c0eaSGlenn Lagasse 
2679*f169c0eaSGlenn Lagasse 	zret = zfs_iter_filesystems(zhp, be_get_ds_from_dir_callback, dd);
2680*f169c0eaSGlenn Lagasse 
2681*f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp);
2682*f169c0eaSGlenn Lagasse 
2683*f169c0eaSGlenn Lagasse 	return (zret);
2684*f169c0eaSGlenn Lagasse }
2685