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