xref: /titanic_54/usr/src/cmd/zoneadm/zfs.c (revision 0094b373ead542a342e4250eaf37854ccd3e50c0)
10b5de56dSgjelinek /*
20b5de56dSgjelinek  * CDDL HEADER START
30b5de56dSgjelinek  *
40b5de56dSgjelinek  * The contents of this file are subject to the terms of the
50b5de56dSgjelinek  * Common Development and Distribution License (the "License").
60b5de56dSgjelinek  * You may not use this file except in compliance with the License.
70b5de56dSgjelinek  *
80b5de56dSgjelinek  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90b5de56dSgjelinek  * or http://www.opensolaris.org/os/licensing.
100b5de56dSgjelinek  * See the License for the specific language governing permissions
110b5de56dSgjelinek  * and limitations under the License.
120b5de56dSgjelinek  *
130b5de56dSgjelinek  * When distributing Covered Code, include this CDDL HEADER in each
140b5de56dSgjelinek  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150b5de56dSgjelinek  * If applicable, add the following below this CDDL HEADER, with the
160b5de56dSgjelinek  * fields enclosed by brackets "[]" replaced with your own identifying
170b5de56dSgjelinek  * information: Portions Copyright [yyyy] [name of copyright owner]
180b5de56dSgjelinek  *
190b5de56dSgjelinek  * CDDL HEADER END
200b5de56dSgjelinek  */
210b5de56dSgjelinek 
220b5de56dSgjelinek /*
23d1f855d7S  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
240b5de56dSgjelinek  * Use is subject to license terms.
250b5de56dSgjelinek  */
260b5de56dSgjelinek 
270b5de56dSgjelinek /*
280b5de56dSgjelinek  * This file contains the functions used to support the ZFS integration
290b5de56dSgjelinek  * with zones.  This includes validation (e.g. zonecfg dataset), cloning,
300b5de56dSgjelinek  * file system creation and destruction.
310b5de56dSgjelinek  */
320b5de56dSgjelinek 
330b5de56dSgjelinek #include <stdio.h>
340b5de56dSgjelinek #include <errno.h>
350b5de56dSgjelinek #include <unistd.h>
360b5de56dSgjelinek #include <string.h>
370b5de56dSgjelinek #include <locale.h>
380b5de56dSgjelinek #include <libintl.h>
390b5de56dSgjelinek #include <sys/stat.h>
400b5de56dSgjelinek #include <sys/statvfs.h>
410b5de56dSgjelinek #include <libgen.h>
420b5de56dSgjelinek #include <libzonecfg.h>
430b5de56dSgjelinek #include <sys/mnttab.h>
440b5de56dSgjelinek #include <libzfs.h>
4511506c41Sgjelinek #include <sys/mntent.h>
46286822ddS #include <values.h>
47*0094b373Sjv227347 #include <strings.h>
48*0094b373Sjv227347 #include <assert.h>
490b5de56dSgjelinek 
500b5de56dSgjelinek #include "zoneadm.h"
510b5de56dSgjelinek 
5299653d4eSeschrock libzfs_handle_t *g_zfs;
530b5de56dSgjelinek 
540b5de56dSgjelinek typedef struct zfs_mount_data {
550b5de56dSgjelinek 	char		*match_name;
560b5de56dSgjelinek 	zfs_handle_t	*match_handle;
570b5de56dSgjelinek } zfs_mount_data_t;
580b5de56dSgjelinek 
590b5de56dSgjelinek typedef struct zfs_snapshot_data {
60286822ddS 	char	*match_name;	/* zonename@SUNWzone */
61286822ddS 	int	len;		/* strlen of match_name */
62286822ddS 	int	max;		/* highest digit appended to snap name */
63286822ddS 	int	num;		/* number of snapshots to rename */
64286822ddS 	int	cntr;		/* counter for renaming snapshots */
650b5de56dSgjelinek } zfs_snapshot_data_t;
660b5de56dSgjelinek 
67286822ddS typedef struct clone_data {
68286822ddS 	zfs_handle_t	*clone_zhp;	/* clone dataset to promote */
69286822ddS 	time_t		origin_creation; /* snapshot creation time of clone */
70286822ddS 	const char	*snapshot;	/* snapshot of dataset being demoted */
71286822ddS } clone_data_t;
72286822ddS 
730b5de56dSgjelinek /*
740b5de56dSgjelinek  * A ZFS file system iterator call-back function which is used to validate
750b5de56dSgjelinek  * datasets imported into the zone.
760b5de56dSgjelinek  */
770b5de56dSgjelinek /* ARGSUSED */
780b5de56dSgjelinek static int
790b5de56dSgjelinek check_zvol(zfs_handle_t *zhp, void *unused)
800b5de56dSgjelinek {
810b5de56dSgjelinek 	int ret;
820b5de56dSgjelinek 
830b5de56dSgjelinek 	if (zfs_get_type(zhp) == ZFS_TYPE_VOLUME) {
840b5de56dSgjelinek 		/*
850b5de56dSgjelinek 		 * TRANSLATION_NOTE
860b5de56dSgjelinek 		 * zfs and dataset are literals that should not be translated.
870b5de56dSgjelinek 		 */
880b5de56dSgjelinek 		(void) fprintf(stderr, gettext("cannot verify zfs dataset %s: "
890b5de56dSgjelinek 		    "volumes cannot be specified as a zone dataset resource\n"),
900b5de56dSgjelinek 		    zfs_get_name(zhp));
910b5de56dSgjelinek 		ret = -1;
920b5de56dSgjelinek 	} else {
930b5de56dSgjelinek 		ret = zfs_iter_children(zhp, check_zvol, NULL);
940b5de56dSgjelinek 	}
950b5de56dSgjelinek 
960b5de56dSgjelinek 	zfs_close(zhp);
970b5de56dSgjelinek 
980b5de56dSgjelinek 	return (ret);
990b5de56dSgjelinek }
1000b5de56dSgjelinek 
1010b5de56dSgjelinek /*
1020b5de56dSgjelinek  * A ZFS file system iterator call-back function which returns the
1030b5de56dSgjelinek  * zfs_handle_t for a ZFS file system on the specified mount point.
1040b5de56dSgjelinek  */
1050b5de56dSgjelinek static int
1060b5de56dSgjelinek match_mountpoint(zfs_handle_t *zhp, void *data)
1070b5de56dSgjelinek {
1080b5de56dSgjelinek 	int			res;
1090b5de56dSgjelinek 	zfs_mount_data_t	*cbp;
1100b5de56dSgjelinek 	char			mp[ZFS_MAXPROPLEN];
1110b5de56dSgjelinek 
1120b5de56dSgjelinek 	if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) {
1130b5de56dSgjelinek 		zfs_close(zhp);
1140b5de56dSgjelinek 		return (0);
1150b5de56dSgjelinek 	}
1160b5de56dSgjelinek 
11711506c41Sgjelinek 	/* First check if the dataset is mounted. */
11811506c41Sgjelinek 	if (zfs_prop_get(zhp, ZFS_PROP_MOUNTED, mp, sizeof (mp), NULL, NULL,
11911506c41Sgjelinek 	    0, B_FALSE) != 0 || strcmp(mp, "no") == 0) {
12011506c41Sgjelinek 		zfs_close(zhp);
12111506c41Sgjelinek 		return (0);
12211506c41Sgjelinek 	}
12311506c41Sgjelinek 
12411506c41Sgjelinek 	/* Now check mount point. */
1250b5de56dSgjelinek 	if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mp, sizeof (mp), NULL, NULL,
12611506c41Sgjelinek 	    0, B_FALSE) != 0) {
12711506c41Sgjelinek 		zfs_close(zhp);
12811506c41Sgjelinek 		return (0);
12911506c41Sgjelinek 	}
13011506c41Sgjelinek 
13111506c41Sgjelinek 	cbp = (zfs_mount_data_t *)data;
13211506c41Sgjelinek 
13311506c41Sgjelinek 	if (strcmp(mp, "legacy") == 0) {
13411506c41Sgjelinek 		/* If legacy, must look in mnttab for mountpoint. */
13511506c41Sgjelinek 		FILE		*fp;
13611506c41Sgjelinek 		struct mnttab	entry;
13711506c41Sgjelinek 		const char	*nm;
13811506c41Sgjelinek 
13911506c41Sgjelinek 		nm = zfs_get_name(zhp);
14011506c41Sgjelinek 		if ((fp = fopen(MNTTAB, "r")) == NULL) {
14111506c41Sgjelinek 			zfs_close(zhp);
14211506c41Sgjelinek 			return (0);
14311506c41Sgjelinek 		}
14411506c41Sgjelinek 
14511506c41Sgjelinek 		while (getmntent(fp, &entry) == 0) {
14611506c41Sgjelinek 			if (strcmp(nm, entry.mnt_special) == 0) {
14711506c41Sgjelinek 				if (strcmp(entry.mnt_mountp, cbp->match_name)
14811506c41Sgjelinek 				    == 0) {
14911506c41Sgjelinek 					(void) fclose(fp);
15011506c41Sgjelinek 					cbp->match_handle = zhp;
15111506c41Sgjelinek 					return (1);
15211506c41Sgjelinek 				}
15311506c41Sgjelinek 				break;
15411506c41Sgjelinek 			}
15511506c41Sgjelinek 		}
15611506c41Sgjelinek 		(void) fclose(fp);
15711506c41Sgjelinek 
15811506c41Sgjelinek 	} else if (strcmp(mp, cbp->match_name) == 0) {
1590b5de56dSgjelinek 		cbp->match_handle = zhp;
1600b5de56dSgjelinek 		return (1);
1610b5de56dSgjelinek 	}
1620b5de56dSgjelinek 
16311506c41Sgjelinek 	/* Iterate over any nested datasets. */
1640b5de56dSgjelinek 	res = zfs_iter_filesystems(zhp, match_mountpoint, data);
1650b5de56dSgjelinek 	zfs_close(zhp);
1660b5de56dSgjelinek 	return (res);
1670b5de56dSgjelinek }
1680b5de56dSgjelinek 
1690b5de56dSgjelinek /*
1700b5de56dSgjelinek  * Get ZFS handle for the specified mount point.
1710b5de56dSgjelinek  */
1720b5de56dSgjelinek static zfs_handle_t *
1730b5de56dSgjelinek mount2zhandle(char *mountpoint)
1740b5de56dSgjelinek {
1750b5de56dSgjelinek 	zfs_mount_data_t	cb;
1760b5de56dSgjelinek 
1770b5de56dSgjelinek 	cb.match_name = mountpoint;
1780b5de56dSgjelinek 	cb.match_handle = NULL;
17999653d4eSeschrock 	(void) zfs_iter_root(g_zfs, match_mountpoint, &cb);
1800b5de56dSgjelinek 	return (cb.match_handle);
1810b5de56dSgjelinek }
1820b5de56dSgjelinek 
1830b5de56dSgjelinek /*
1840b5de56dSgjelinek  * Check if there is already a file system (zfs or any other type) mounted on
1850b5de56dSgjelinek  * path.
1860b5de56dSgjelinek  */
1870b5de56dSgjelinek static boolean_t
1880b5de56dSgjelinek is_mountpnt(char *path)
1890b5de56dSgjelinek {
1900b5de56dSgjelinek 	FILE		*fp;
1910b5de56dSgjelinek 	struct mnttab	entry;
1920b5de56dSgjelinek 
19311506c41Sgjelinek 	if ((fp = fopen(MNTTAB, "r")) == NULL)
1940b5de56dSgjelinek 		return (B_FALSE);
1950b5de56dSgjelinek 
1960b5de56dSgjelinek 	while (getmntent(fp, &entry) == 0) {
1970b5de56dSgjelinek 		if (strcmp(path, entry.mnt_mountp) == 0) {
1980b5de56dSgjelinek 			(void) fclose(fp);
1990b5de56dSgjelinek 			return (B_TRUE);
2000b5de56dSgjelinek 		}
2010b5de56dSgjelinek 	}
2020b5de56dSgjelinek 
2030b5de56dSgjelinek 	(void) fclose(fp);
2040b5de56dSgjelinek 	return (B_FALSE);
2050b5de56dSgjelinek }
2060b5de56dSgjelinek 
2070b5de56dSgjelinek /*
208ff17c8bfSgjelinek  * Run the brand's pre-snapshot hook before we take a ZFS snapshot of the zone.
2090b5de56dSgjelinek  */
2100b5de56dSgjelinek static int
211ff17c8bfSgjelinek pre_snapshot(char *presnapbuf)
2120b5de56dSgjelinek {
213ff17c8bfSgjelinek 	int status;
2140b5de56dSgjelinek 
215ff17c8bfSgjelinek 	/* No brand-specific handler */
216ff17c8bfSgjelinek 	if (presnapbuf[0] == '\0')
217ff17c8bfSgjelinek 		return (Z_OK);
218ff17c8bfSgjelinek 
219ff17c8bfSgjelinek 	/* Run the hook */
220c75cc341S 	status = do_subproc(presnapbuf);
221ff17c8bfSgjelinek 	if ((status = subproc_status(gettext("brand-specific presnapshot"),
222ff17c8bfSgjelinek 	    status, B_FALSE)) != ZONE_SUBPROC_OK)
2230b5de56dSgjelinek 		return (Z_ERR);
2240b5de56dSgjelinek 
2250b5de56dSgjelinek 	return (Z_OK);
2260b5de56dSgjelinek }
2270b5de56dSgjelinek 
2280b5de56dSgjelinek /*
229ff17c8bfSgjelinek  * Run the brand's post-snapshot hook after we take a ZFS snapshot of the zone.
2300b5de56dSgjelinek  */
2310b5de56dSgjelinek static int
232ff17c8bfSgjelinek post_snapshot(char *postsnapbuf)
2330b5de56dSgjelinek {
234ff17c8bfSgjelinek 	int status;
2350b5de56dSgjelinek 
236ff17c8bfSgjelinek 	/* No brand-specific handler */
237ff17c8bfSgjelinek 	if (postsnapbuf[0] == '\0')
238ff17c8bfSgjelinek 		return (Z_OK);
239ff17c8bfSgjelinek 
240ff17c8bfSgjelinek 	/* Run the hook */
241c75cc341S 	status = do_subproc(postsnapbuf);
242ff17c8bfSgjelinek 	if ((status = subproc_status(gettext("brand-specific postsnapshot"),
243ff17c8bfSgjelinek 	    status, B_FALSE)) != ZONE_SUBPROC_OK)
2440b5de56dSgjelinek 		return (Z_ERR);
2450b5de56dSgjelinek 
2460b5de56dSgjelinek 	return (Z_OK);
2470b5de56dSgjelinek }
2480b5de56dSgjelinek 
2490b5de56dSgjelinek /*
2500b5de56dSgjelinek  * This is a ZFS snapshot iterator call-back function which returns the
2510b5de56dSgjelinek  * highest number of SUNWzone snapshots that have been taken.
2520b5de56dSgjelinek  */
2530b5de56dSgjelinek static int
2540b5de56dSgjelinek get_snap_max(zfs_handle_t *zhp, void *data)
2550b5de56dSgjelinek {
2560b5de56dSgjelinek 	int			res;
2570b5de56dSgjelinek 	zfs_snapshot_data_t	*cbp;
2580b5de56dSgjelinek 
2590b5de56dSgjelinek 	if (zfs_get_type(zhp) != ZFS_TYPE_SNAPSHOT) {
2600b5de56dSgjelinek 		zfs_close(zhp);
2610b5de56dSgjelinek 		return (0);
2620b5de56dSgjelinek 	}
2630b5de56dSgjelinek 
2640b5de56dSgjelinek 	cbp = (zfs_snapshot_data_t *)data;
2650b5de56dSgjelinek 
2660b5de56dSgjelinek 	if (strncmp(zfs_get_name(zhp), cbp->match_name, cbp->len) == 0) {
2670b5de56dSgjelinek 		char	*nump;
2680b5de56dSgjelinek 		int	num;
2690b5de56dSgjelinek 
270286822ddS 		cbp->num++;
2710b5de56dSgjelinek 		nump = (char *)(zfs_get_name(zhp) + cbp->len);
2720b5de56dSgjelinek 		num = atoi(nump);
2730b5de56dSgjelinek 		if (num > cbp->max)
2740b5de56dSgjelinek 			cbp->max = num;
2750b5de56dSgjelinek 	}
2760b5de56dSgjelinek 
2770b5de56dSgjelinek 	res = zfs_iter_snapshots(zhp, get_snap_max, data);
2780b5de56dSgjelinek 	zfs_close(zhp);
2790b5de56dSgjelinek 	return (res);
2800b5de56dSgjelinek }
2810b5de56dSgjelinek 
2820b5de56dSgjelinek /*
2830b5de56dSgjelinek  * Take a ZFS snapshot to be used for cloning the zone.
2840b5de56dSgjelinek  */
2850b5de56dSgjelinek static int
286ff17c8bfSgjelinek take_snapshot(zfs_handle_t *zhp, char *snapshot_name, int snap_size,
287ff17c8bfSgjelinek     char *presnapbuf, char *postsnapbuf)
2880b5de56dSgjelinek {
2890b5de56dSgjelinek 	int			res;
2900b5de56dSgjelinek 	char			template[ZFS_MAXNAMELEN];
2910b5de56dSgjelinek 	zfs_snapshot_data_t	cb;
2920b5de56dSgjelinek 
2930b5de56dSgjelinek 	/*
2940b5de56dSgjelinek 	 * First we need to figure out the next available name for the
2950b5de56dSgjelinek 	 * zone snapshot.  Look through the list of zones snapshots for
2960b5de56dSgjelinek 	 * this file system to determine the maximum snapshot name.
2970b5de56dSgjelinek 	 */
2980b5de56dSgjelinek 	if (snprintf(template, sizeof (template), "%s@SUNWzone",
2990b5de56dSgjelinek 	    zfs_get_name(zhp)) >=  sizeof (template))
3000b5de56dSgjelinek 		return (Z_ERR);
3010b5de56dSgjelinek 
3020b5de56dSgjelinek 	cb.match_name = template;
3030b5de56dSgjelinek 	cb.len = strlen(template);
3040b5de56dSgjelinek 	cb.max = 0;
3050b5de56dSgjelinek 
3060b5de56dSgjelinek 	if (zfs_iter_snapshots(zhp, get_snap_max, &cb) != 0)
3070b5de56dSgjelinek 		return (Z_ERR);
3080b5de56dSgjelinek 
3090b5de56dSgjelinek 	cb.max++;
3100b5de56dSgjelinek 
3110b5de56dSgjelinek 	if (snprintf(snapshot_name, snap_size, "%s@SUNWzone%d",
3120b5de56dSgjelinek 	    zfs_get_name(zhp), cb.max) >= snap_size)
3130b5de56dSgjelinek 		return (Z_ERR);
3140b5de56dSgjelinek 
315ff17c8bfSgjelinek 	if (pre_snapshot(presnapbuf) != Z_OK)
3160b5de56dSgjelinek 		return (Z_ERR);
317bb0ade09Sahrens 	res = zfs_snapshot(g_zfs, snapshot_name, B_FALSE, NULL);
318ff17c8bfSgjelinek 	if (post_snapshot(postsnapbuf) != Z_OK)
3190b5de56dSgjelinek 		return (Z_ERR);
3200b5de56dSgjelinek 
3210b5de56dSgjelinek 	if (res != 0)
3220b5de56dSgjelinek 		return (Z_ERR);
3230b5de56dSgjelinek 	return (Z_OK);
3240b5de56dSgjelinek }
3250b5de56dSgjelinek 
3260b5de56dSgjelinek /*
3270b5de56dSgjelinek  * We are using an explicit snapshot from some earlier point in time so
328ff17c8bfSgjelinek  * we need to validate it.  Run the brand specific hook.
3290b5de56dSgjelinek  */
3300b5de56dSgjelinek static int
331ff17c8bfSgjelinek validate_snapshot(char *snapshot_name, char *snap_path, char *validsnapbuf)
3320b5de56dSgjelinek {
333ff17c8bfSgjelinek 	int status;
334ff17c8bfSgjelinek 	char cmdbuf[MAXPATHLEN];
3350b5de56dSgjelinek 
336ff17c8bfSgjelinek 	/* No brand-specific handler */
337ff17c8bfSgjelinek 	if (validsnapbuf[0] == '\0')
338ff17c8bfSgjelinek 		return (Z_OK);
339ff17c8bfSgjelinek 
340ff17c8bfSgjelinek 	/* pass args - snapshot_name & snap_path */
341ff17c8bfSgjelinek 	if (snprintf(cmdbuf, sizeof (cmdbuf), "%s %s %s", validsnapbuf,
342ff17c8bfSgjelinek 	    snapshot_name, snap_path) >= sizeof (cmdbuf)) {
343ff17c8bfSgjelinek 		zerror("Command line too long");
3440b5de56dSgjelinek 		return (Z_ERR);
3450b5de56dSgjelinek 	}
3460b5de56dSgjelinek 
347ff17c8bfSgjelinek 	/* Run the hook */
348c75cc341S 	status = do_subproc(cmdbuf);
349ff17c8bfSgjelinek 	if ((status = subproc_status(gettext("brand-specific validatesnapshot"),
350ff17c8bfSgjelinek 	    status, B_FALSE)) != ZONE_SUBPROC_OK)
3510b5de56dSgjelinek 		return (Z_ERR);
3520b5de56dSgjelinek 
353ff17c8bfSgjelinek 	return (Z_OK);
3540b5de56dSgjelinek }
3550b5de56dSgjelinek 
3560b5de56dSgjelinek /*
3570b5de56dSgjelinek  * Remove the sw inventory file from inside this zonepath that we picked up out
3580b5de56dSgjelinek  * of the snapshot.
3590b5de56dSgjelinek  */
3600b5de56dSgjelinek static int
3610b5de56dSgjelinek clean_out_clone()
3620b5de56dSgjelinek {
3630b5de56dSgjelinek 	int err;
3640b5de56dSgjelinek 	zone_dochandle_t handle;
3650b5de56dSgjelinek 
3660b5de56dSgjelinek 	if ((handle = zonecfg_init_handle()) == NULL) {
3670b5de56dSgjelinek 		zperror(cmd_to_str(CMD_CLONE), B_TRUE);
3680b5de56dSgjelinek 		return (Z_ERR);
3690b5de56dSgjelinek 	}
3700b5de56dSgjelinek 
3710b5de56dSgjelinek 	if ((err = zonecfg_get_handle(target_zone, handle)) != Z_OK) {
3720b5de56dSgjelinek 		errno = err;
3730b5de56dSgjelinek 		zperror(cmd_to_str(CMD_CLONE), B_TRUE);
3740b5de56dSgjelinek 		zonecfg_fini_handle(handle);
3750b5de56dSgjelinek 		return (Z_ERR);
3760b5de56dSgjelinek 	}
3770b5de56dSgjelinek 
3780b5de56dSgjelinek 	zonecfg_rm_detached(handle, B_FALSE);
3790b5de56dSgjelinek 	zonecfg_fini_handle(handle);
3800b5de56dSgjelinek 
3810b5de56dSgjelinek 	return (Z_OK);
3820b5de56dSgjelinek }
3830b5de56dSgjelinek 
3840b5de56dSgjelinek /*
3850b5de56dSgjelinek  * Make a ZFS clone on zonepath from snapshot_name.
3860b5de56dSgjelinek  */
3870b5de56dSgjelinek static int
3880b5de56dSgjelinek clone_snap(char *snapshot_name, char *zonepath)
3890b5de56dSgjelinek {
3900b5de56dSgjelinek 	int		res = Z_OK;
3910b5de56dSgjelinek 	int		err;
3920b5de56dSgjelinek 	zfs_handle_t	*zhp;
3930b5de56dSgjelinek 	zfs_handle_t	*clone;
394e9dbad6fSeschrock 	nvlist_t	*props = NULL;
3950b5de56dSgjelinek 
39699653d4eSeschrock 	if ((zhp = zfs_open(g_zfs, snapshot_name, ZFS_TYPE_SNAPSHOT)) == NULL)
3970b5de56dSgjelinek 		return (Z_NO_ENTRY);
3980b5de56dSgjelinek 
3990b5de56dSgjelinek 	(void) printf(gettext("Cloning snapshot %s\n"), snapshot_name);
4000b5de56dSgjelinek 
401e9dbad6fSeschrock 	if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0 ||
4025f8e1617Snn35248 	    nvlist_add_string(props, zfs_prop_to_name(ZFS_PROP_SHARENFS),
4035f8e1617Snn35248 	    "off") != 0) {
4045f8e1617Snn35248 		if (props != NULL)
405e9dbad6fSeschrock 			nvlist_free(props);
406e9dbad6fSeschrock 		(void) fprintf(stderr, gettext("could not create ZFS clone "
407e9dbad6fSeschrock 		    "%s: out of memory\n"), zonepath);
408e9dbad6fSeschrock 		return (Z_ERR);
409e9dbad6fSeschrock 	}
410e9dbad6fSeschrock 
411e9dbad6fSeschrock 	err = zfs_clone(zhp, zonepath, props);
4120b5de56dSgjelinek 	zfs_close(zhp);
413e9dbad6fSeschrock 
414e9dbad6fSeschrock 	nvlist_free(props);
415e9dbad6fSeschrock 
4160b5de56dSgjelinek 	if (err != 0)
4170b5de56dSgjelinek 		return (Z_ERR);
4180b5de56dSgjelinek 
4190b5de56dSgjelinek 	/* create the mountpoint if necessary */
420990b4856Slling 	if ((clone = zfs_open(g_zfs, zonepath, ZFS_TYPE_DATASET)) == NULL)
4210b5de56dSgjelinek 		return (Z_ERR);
4220b5de56dSgjelinek 
4230b5de56dSgjelinek 	/*
4240b5de56dSgjelinek 	 * The clone has been created so we need to print a diagnostic
4250b5de56dSgjelinek 	 * message if one of the following steps fails for some reason.
4260b5de56dSgjelinek 	 */
4270b5de56dSgjelinek 	if (zfs_mount(clone, NULL, 0) != 0) {
4280b5de56dSgjelinek 		(void) fprintf(stderr, gettext("could not mount ZFS clone "
4290b5de56dSgjelinek 		    "%s\n"), zfs_get_name(clone));
4300b5de56dSgjelinek 		res = Z_ERR;
4310b5de56dSgjelinek 
432e9dbad6fSeschrock 	} else if (clean_out_clone() != Z_OK) {
4330b5de56dSgjelinek 		(void) fprintf(stderr, gettext("could not remove the "
4340b5de56dSgjelinek 		    "software inventory from ZFS clone %s\n"),
4350b5de56dSgjelinek 		    zfs_get_name(clone));
4360b5de56dSgjelinek 		res = Z_ERR;
4370b5de56dSgjelinek 	}
4380b5de56dSgjelinek 
4390b5de56dSgjelinek 	zfs_close(clone);
4400b5de56dSgjelinek 	return (res);
4410b5de56dSgjelinek }
4420b5de56dSgjelinek 
4430b5de56dSgjelinek /*
4440b5de56dSgjelinek  * This function takes a zonepath and attempts to determine what the ZFS
4450b5de56dSgjelinek  * file system name (not mountpoint) should be for that path.  We do not
4460b5de56dSgjelinek  * assume that zonepath is an existing directory or ZFS fs since we use
4470b5de56dSgjelinek  * this function as part of the process of creating a new ZFS fs or clone.
4480b5de56dSgjelinek  *
4490b5de56dSgjelinek  * The way this works is that we look at the parent directory of the zonepath
4500b5de56dSgjelinek  * to see if it is a ZFS fs.  If it is, we get the name of that ZFS fs and
4510b5de56dSgjelinek  * append the last component of the zonepath to generate the ZFS name for the
4520b5de56dSgjelinek  * zonepath.  This matches the algorithm that ZFS uses for automatically
4530b5de56dSgjelinek  * mounting a new fs after it is created.
4540b5de56dSgjelinek  *
4550b5de56dSgjelinek  * Although a ZFS fs can be mounted anywhere, we don't worry about handling
4560b5de56dSgjelinek  * all of the complexity that a user could possibly configure with arbitrary
4570b5de56dSgjelinek  * mounts since there is no way to generate a ZFS name from a random path in
4580b5de56dSgjelinek  * the file system.  We only try to handle the automatic mounts that ZFS does
4590b5de56dSgjelinek  * for each file system.  ZFS restricts this so that a new fs must be created
4600b5de56dSgjelinek  * in an existing parent ZFS fs.  It then automatically mounts the new fs
4610b5de56dSgjelinek  * directly under the mountpoint for the parent fs using the last component
4620b5de56dSgjelinek  * of the name as the mountpoint directory.
4630b5de56dSgjelinek  *
4640b5de56dSgjelinek  * For example:
4650b5de56dSgjelinek  *    Name			Mountpoint
4660b5de56dSgjelinek  *    space/eng/dev/test/zone1	/project1/eng/dev/test/zone1
4670b5de56dSgjelinek  *
4680b5de56dSgjelinek  * Return Z_OK if the path mapped to a ZFS file system name, otherwise return
4690b5de56dSgjelinek  * Z_ERR.
4700b5de56dSgjelinek  */
4710b5de56dSgjelinek static int
4720b5de56dSgjelinek path2name(char *zonepath, char *zfs_name, int len)
4730b5de56dSgjelinek {
4740b5de56dSgjelinek 	int		res;
47511506c41Sgjelinek 	char		*bnm, *dnm, *dname, *bname;
4760b5de56dSgjelinek 	zfs_handle_t	*zhp;
47711506c41Sgjelinek 	struct stat	stbuf;
4780b5de56dSgjelinek 
4790b5de56dSgjelinek 	/*
48011506c41Sgjelinek 	 * We need two tmp strings to handle paths directly in / (e.g. /foo)
48111506c41Sgjelinek 	 * since dirname will overwrite the first char after "/" in this case.
4820b5de56dSgjelinek 	 */
48311506c41Sgjelinek 	if ((bnm = strdup(zonepath)) == NULL)
4840b5de56dSgjelinek 		return (Z_ERR);
4850b5de56dSgjelinek 
48611506c41Sgjelinek 	if ((dnm = strdup(zonepath)) == NULL) {
48711506c41Sgjelinek 		free(bnm);
48811506c41Sgjelinek 		return (Z_ERR);
48911506c41Sgjelinek 	}
4900b5de56dSgjelinek 
49111506c41Sgjelinek 	bname = basename(bnm);
49211506c41Sgjelinek 	dname = dirname(dnm);
49311506c41Sgjelinek 
49411506c41Sgjelinek 	/*
49511506c41Sgjelinek 	 * This is a quick test to save iterating over all of the zfs datasets
49611506c41Sgjelinek 	 * on the system (which can be a lot).  If the parent dir is not in a
49711506c41Sgjelinek 	 * ZFS fs, then we're done.
49811506c41Sgjelinek 	 */
49911506c41Sgjelinek 	if (stat(dname, &stbuf) != 0 || !S_ISDIR(stbuf.st_mode) ||
50011506c41Sgjelinek 	    strcmp(stbuf.st_fstype, MNTTYPE_ZFS) != 0) {
50111506c41Sgjelinek 		free(bnm);
50211506c41Sgjelinek 		free(dnm);
50311506c41Sgjelinek 		return (Z_ERR);
50411506c41Sgjelinek 	}
50511506c41Sgjelinek 
50611506c41Sgjelinek 	/* See if the parent directory is its own ZFS dataset. */
50711506c41Sgjelinek 	if ((zhp = mount2zhandle(dname)) == NULL) {
50811506c41Sgjelinek 		/*
50911506c41Sgjelinek 		 * The parent is not a ZFS dataset so we can't automatically
51011506c41Sgjelinek 		 * create a dataset on the given path.
51111506c41Sgjelinek 		 */
51211506c41Sgjelinek 		free(bnm);
51311506c41Sgjelinek 		free(dnm);
51411506c41Sgjelinek 		return (Z_ERR);
51511506c41Sgjelinek 	}
51611506c41Sgjelinek 
51711506c41Sgjelinek 	res = snprintf(zfs_name, len, "%s/%s", zfs_get_name(zhp), bname);
51811506c41Sgjelinek 
51911506c41Sgjelinek 	free(bnm);
52011506c41Sgjelinek 	free(dnm);
5210b5de56dSgjelinek 	zfs_close(zhp);
5220b5de56dSgjelinek 	if (res >= len)
5230b5de56dSgjelinek 		return (Z_ERR);
5240b5de56dSgjelinek 
5250b5de56dSgjelinek 	return (Z_OK);
5260b5de56dSgjelinek }
5270b5de56dSgjelinek 
5280b5de56dSgjelinek /*
5290b5de56dSgjelinek  * A ZFS file system iterator call-back function used to determine if the
5300b5de56dSgjelinek  * file system has dependents (snapshots & clones).
5310b5de56dSgjelinek  */
5320b5de56dSgjelinek /* ARGSUSED */
5330b5de56dSgjelinek static int
5340b5de56dSgjelinek has_dependent(zfs_handle_t *zhp, void *data)
5350b5de56dSgjelinek {
5360b5de56dSgjelinek 	zfs_close(zhp);
5370b5de56dSgjelinek 	return (1);
5380b5de56dSgjelinek }
5390b5de56dSgjelinek 
5400b5de56dSgjelinek /*
5410b5de56dSgjelinek  * Given a snapshot name, get the file system path where the snapshot lives.
5420b5de56dSgjelinek  * A snapshot name is of the form fs_name@snap_name.  For example, snapshot
5430b5de56dSgjelinek  * pl/zones/z1@SUNWzone1 would have a path of
5440b5de56dSgjelinek  * /pl/zones/z1/.zfs/snapshot/SUNWzone1.
5450b5de56dSgjelinek  */
5460b5de56dSgjelinek static int
5470b5de56dSgjelinek snap2path(char *snap_name, char *path, int len)
5480b5de56dSgjelinek {
5490b5de56dSgjelinek 	char		*p;
5500b5de56dSgjelinek 	zfs_handle_t	*zhp;
5510b5de56dSgjelinek 	char		mp[ZFS_MAXPROPLEN];
5520b5de56dSgjelinek 
5530b5de56dSgjelinek 	if ((p = strrchr(snap_name, '@')) == NULL)
5540b5de56dSgjelinek 		return (Z_ERR);
5550b5de56dSgjelinek 
5560b5de56dSgjelinek 	/* Get the file system name from the snap_name. */
5570b5de56dSgjelinek 	*p = '\0';
558990b4856Slling 	zhp = zfs_open(g_zfs, snap_name, ZFS_TYPE_DATASET);
5590b5de56dSgjelinek 	*p = '@';
5600b5de56dSgjelinek 	if (zhp == NULL)
5610b5de56dSgjelinek 		return (Z_ERR);
5620b5de56dSgjelinek 
5630b5de56dSgjelinek 	/* Get the file system mount point. */
5640b5de56dSgjelinek 	if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mp, sizeof (mp), NULL, NULL,
56599653d4eSeschrock 	    0, B_FALSE) != 0) {
5660b5de56dSgjelinek 		zfs_close(zhp);
5670b5de56dSgjelinek 		return (Z_ERR);
5680b5de56dSgjelinek 	}
5690b5de56dSgjelinek 	zfs_close(zhp);
5700b5de56dSgjelinek 
5710b5de56dSgjelinek 	p++;
5720b5de56dSgjelinek 	if (snprintf(path, len, "%s/.zfs/snapshot/%s", mp, p) >= len)
5730b5de56dSgjelinek 		return (Z_ERR);
5740b5de56dSgjelinek 
5750b5de56dSgjelinek 	return (Z_OK);
5760b5de56dSgjelinek }
5770b5de56dSgjelinek 
5780b5de56dSgjelinek /*
579286822ddS  * This callback function is used to iterate through a snapshot's dependencies
580286822ddS  * to find a filesystem that is a direct clone of the snapshot being iterated.
581286822ddS  */
582286822ddS static int
583286822ddS get_direct_clone(zfs_handle_t *zhp, void *data)
584286822ddS {
585286822ddS 	clone_data_t	*cd = data;
586286822ddS 	char		origin[ZFS_MAXNAMELEN];
587286822ddS 	char		ds_path[ZFS_MAXNAMELEN];
588286822ddS 
589286822ddS 	if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) {
590286822ddS 		zfs_close(zhp);
591286822ddS 		return (0);
592286822ddS 	}
593286822ddS 
594286822ddS 	(void) strlcpy(ds_path, zfs_get_name(zhp), sizeof (ds_path));
595286822ddS 
596286822ddS 	/* Make sure this is a direct clone of the snapshot we're iterating. */
597286822ddS 	if (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, origin, sizeof (origin), NULL,
598286822ddS 	    NULL, 0, B_FALSE) != 0 || strcmp(origin, cd->snapshot) != 0) {
599286822ddS 		zfs_close(zhp);
600286822ddS 		return (0);
601286822ddS 	}
602286822ddS 
603286822ddS 	if (cd->clone_zhp != NULL)
604286822ddS 		zfs_close(cd->clone_zhp);
605286822ddS 
606286822ddS 	cd->clone_zhp = zhp;
607286822ddS 	return (1);
608286822ddS }
609286822ddS 
610286822ddS /*
611286822ddS  * A ZFS file system iterator call-back function used to determine the clone
612286822ddS  * to promote.  This function finds the youngest (i.e. last one taken) snapshot
613286822ddS  * that has a clone.  If found, it returns a reference to that clone in the
614286822ddS  * callback data.
615286822ddS  */
616286822ddS static int
617286822ddS find_clone(zfs_handle_t *zhp, void *data)
618286822ddS {
619286822ddS 	clone_data_t	*cd = data;
620286822ddS 	time_t		snap_creation;
621286822ddS 	int		zret = 0;
622286822ddS 
623286822ddS 	/* If snapshot has no clones, skip it */
624286822ddS 	if (zfs_prop_get_int(zhp, ZFS_PROP_NUMCLONES) == 0) {
625286822ddS 		zfs_close(zhp);
626286822ddS 		return (0);
627286822ddS 	}
628286822ddS 
629286822ddS 	cd->snapshot = zfs_get_name(zhp);
630286822ddS 
631286822ddS 	/* Get the creation time of this snapshot */
632286822ddS 	snap_creation = (time_t)zfs_prop_get_int(zhp, ZFS_PROP_CREATION);
633286822ddS 
634286822ddS 	/*
635286822ddS 	 * If this snapshot's creation time is greater than (i.e. younger than)
636286822ddS 	 * the current youngest snapshot found, iterate this snapshot to
637286822ddS 	 * get the right clone.
638286822ddS 	 */
639286822ddS 	if (snap_creation >= cd->origin_creation) {
640286822ddS 		/*
641286822ddS 		 * Iterate the dependents of this snapshot to find a clone
642286822ddS 		 * that's a direct dependent.
643286822ddS 		 */
644286822ddS 		if ((zret = zfs_iter_dependents(zhp, B_FALSE, get_direct_clone,
645286822ddS 		    cd)) == -1) {
646286822ddS 			zfs_close(zhp);
647286822ddS 			return (1);
648286822ddS 		} else if (zret == 1) {
649286822ddS 			/*
650286822ddS 			 * Found a clone, update the origin_creation time
651286822ddS 			 * in the callback data.
652286822ddS 			 */
653286822ddS 			cd->origin_creation = snap_creation;
654286822ddS 		}
655286822ddS 	}
656286822ddS 
657286822ddS 	zfs_close(zhp);
658286822ddS 	return (0);
659286822ddS }
660286822ddS 
661286822ddS /*
662286822ddS  * A ZFS file system iterator call-back function used to remove standalone
663286822ddS  * snapshots.
664286822ddS  */
665286822ddS /* ARGSUSED */
666286822ddS static int
667286822ddS rm_snap(zfs_handle_t *zhp, void *data)
668286822ddS {
669286822ddS 	/* If snapshot has clones, something is wrong */
670286822ddS 	if (zfs_prop_get_int(zhp, ZFS_PROP_NUMCLONES) != 0) {
671286822ddS 		zfs_close(zhp);
672286822ddS 		return (1);
673286822ddS 	}
674286822ddS 
675286822ddS 	if (zfs_unmount(zhp, NULL, 0) == 0) {
676842727c2SChris Kirby 		(void) zfs_destroy(zhp, B_FALSE);
677286822ddS 	}
678286822ddS 
679286822ddS 	zfs_close(zhp);
680286822ddS 	return (0);
681286822ddS }
682286822ddS 
683286822ddS /*
684286822ddS  * A ZFS snapshot iterator call-back function which renames snapshots.
685286822ddS  */
686286822ddS static int
687286822ddS rename_snap(zfs_handle_t *zhp, void *data)
688286822ddS {
689286822ddS 	int			res;
690286822ddS 	zfs_snapshot_data_t	*cbp;
691286822ddS 	char			template[ZFS_MAXNAMELEN];
692286822ddS 
693286822ddS 	cbp = (zfs_snapshot_data_t *)data;
694286822ddS 
695286822ddS 	/*
696286822ddS 	 * When renaming snapshots with the iterator, the iterator can see
697286822ddS 	 * the same snapshot after we've renamed up in the namespace.  To
698286822ddS 	 * prevent this we check the count for the number of snapshots we have
699286822ddS 	 * to rename and stop at that point.
700286822ddS 	 */
701286822ddS 	if (cbp->cntr >= cbp->num) {
702286822ddS 		zfs_close(zhp);
703286822ddS 		return (0);
704286822ddS 	}
705286822ddS 
706286822ddS 	if (zfs_get_type(zhp) != ZFS_TYPE_SNAPSHOT) {
707286822ddS 		zfs_close(zhp);
708286822ddS 		return (0);
709286822ddS 	}
710286822ddS 
711286822ddS 	/* Only rename the snapshots we automatically generate when we clone. */
712286822ddS 	if (strncmp(zfs_get_name(zhp), cbp->match_name, cbp->len) != 0) {
713286822ddS 		zfs_close(zhp);
714286822ddS 		return (0);
715286822ddS 	}
716286822ddS 
717286822ddS 	(void) snprintf(template, sizeof (template), "%s%d", cbp->match_name,
718286822ddS 	    cbp->max++);
719286822ddS 
720286822ddS 	res = (zfs_rename(zhp, template, B_FALSE) != 0);
721286822ddS 	if (res != 0)
722286822ddS 		(void) fprintf(stderr, gettext("failed to rename snapshot %s "
723286822ddS 		    "to %s: %s\n"), zfs_get_name(zhp), template,
724286822ddS 		    libzfs_error_description(g_zfs));
725286822ddS 
726286822ddS 	cbp->cntr++;
727286822ddS 
728286822ddS 	zfs_close(zhp);
729286822ddS 	return (res);
730286822ddS }
731286822ddS 
732286822ddS /*
733286822ddS  * Rename the source dataset's snapshots that are automatically generated when
734286822ddS  * we clone a zone so that there won't be a name collision when we promote the
735286822ddS  * cloned dataset.  Once the snapshots have been renamed, then promote the
736286822ddS  * clone.
737286822ddS  *
738286822ddS  * The snapshot rename process gets the highest number on the snapshot names
739286822ddS  * (the format is zonename@SUNWzoneXX where XX are digits) on both the source
740286822ddS  * and clone datasets, then renames the source dataset snapshots starting at
741286822ddS  * the next number.
742286822ddS  */
743286822ddS static int
744286822ddS promote_clone(zfs_handle_t *src_zhp, zfs_handle_t *cln_zhp)
745286822ddS {
746286822ddS 	zfs_snapshot_data_t	sd;
747286822ddS 	char			nm[ZFS_MAXNAMELEN];
748286822ddS 	char			template[ZFS_MAXNAMELEN];
749286822ddS 
750286822ddS 	(void) strlcpy(nm, zfs_get_name(cln_zhp), sizeof (nm));
751286822ddS 	/*
752286822ddS 	 * Start by getting the clone's snapshot max which we use
753286822ddS 	 * during the rename of the original dataset's snapshots.
754286822ddS 	 */
755286822ddS 	(void) snprintf(template, sizeof (template), "%s@SUNWzone", nm);
756286822ddS 	sd.match_name = template;
757286822ddS 	sd.len = strlen(template);
758286822ddS 	sd.max = 0;
759286822ddS 
760286822ddS 	if (zfs_iter_snapshots(cln_zhp, get_snap_max, &sd) != 0)
761286822ddS 		return (Z_ERR);
762286822ddS 
763286822ddS 	/*
764286822ddS 	 * Now make sure the source's snapshot max is at least as high as
765286822ddS 	 * the clone's snapshot max.
766286822ddS 	 */
767286822ddS 	(void) snprintf(template, sizeof (template), "%s@SUNWzone",
768286822ddS 	    zfs_get_name(src_zhp));
769286822ddS 	sd.match_name = template;
770286822ddS 	sd.len = strlen(template);
771286822ddS 	sd.num = 0;
772286822ddS 
773286822ddS 	if (zfs_iter_snapshots(src_zhp, get_snap_max, &sd) != 0)
774286822ddS 		return (Z_ERR);
775286822ddS 
776286822ddS 	/*
777286822ddS 	 * Now rename the source dataset's snapshots so there's no
778286822ddS 	 * conflict when we promote the clone.
779286822ddS 	 */
780286822ddS 	sd.max++;
781286822ddS 	sd.cntr = 0;
782286822ddS 	if (zfs_iter_snapshots(src_zhp, rename_snap, &sd) != 0)
783286822ddS 		return (Z_ERR);
784286822ddS 
785286822ddS 	/* close and reopen the clone dataset to get the latest info */
786286822ddS 	zfs_close(cln_zhp);
787286822ddS 	if ((cln_zhp = zfs_open(g_zfs, nm, ZFS_TYPE_FILESYSTEM)) == NULL)
788286822ddS 		return (Z_ERR);
789286822ddS 
790286822ddS 	if (zfs_promote(cln_zhp) != 0) {
791286822ddS 		(void) fprintf(stderr, gettext("failed to promote %s: %s\n"),
792286822ddS 		    nm, libzfs_error_description(g_zfs));
793286822ddS 		return (Z_ERR);
794286822ddS 	}
795286822ddS 
796286822ddS 	zfs_close(cln_zhp);
797286822ddS 	return (Z_OK);
798286822ddS }
799286822ddS 
800286822ddS /*
801286822ddS  * Promote the youngest clone.  That clone will then become the origin of all
802286822ddS  * of the other clones that were hanging off of the source dataset.
803286822ddS  */
804286822ddS int
805286822ddS promote_all_clones(zfs_handle_t *zhp)
806286822ddS {
807286822ddS 	clone_data_t	cd;
808286822ddS 	char		nm[ZFS_MAXNAMELEN];
809286822ddS 
810286822ddS 	cd.clone_zhp = NULL;
811286822ddS 	cd.origin_creation = 0;
812286822ddS 	cd.snapshot = NULL;
813286822ddS 
814286822ddS 	if (zfs_iter_snapshots(zhp, find_clone, &cd) != 0) {
815286822ddS 		zfs_close(zhp);
816286822ddS 		return (Z_ERR);
817286822ddS 	}
818286822ddS 
819286822ddS 	/* Nothing to promote. */
820286822ddS 	if (cd.clone_zhp == NULL)
821286822ddS 		return (Z_OK);
822286822ddS 
823286822ddS 	/* Found the youngest clone to promote.  Promote it. */
824286822ddS 	if (promote_clone(zhp, cd.clone_zhp) != 0) {
825286822ddS 		zfs_close(cd.clone_zhp);
826286822ddS 		zfs_close(zhp);
827286822ddS 		return (Z_ERR);
828286822ddS 	}
829286822ddS 
830286822ddS 	/* close and reopen the main dataset to get the latest info */
831286822ddS 	(void) strlcpy(nm, zfs_get_name(zhp), sizeof (nm));
832286822ddS 	zfs_close(zhp);
833286822ddS 	if ((zhp = zfs_open(g_zfs, nm, ZFS_TYPE_FILESYSTEM)) == NULL)
834286822ddS 		return (Z_ERR);
835286822ddS 
836286822ddS 	return (Z_OK);
837286822ddS }
838286822ddS 
839286822ddS /*
8400b5de56dSgjelinek  * Clone a pre-existing ZFS snapshot, either by making a direct ZFS clone, if
8410b5de56dSgjelinek  * possible, or by copying the data from the snapshot to the zonepath.
8420b5de56dSgjelinek  */
8430b5de56dSgjelinek int
844ff17c8bfSgjelinek clone_snapshot_zfs(char *snap_name, char *zonepath, char *validatesnap)
8450b5de56dSgjelinek {
8460b5de56dSgjelinek 	int	err = Z_OK;
8470b5de56dSgjelinek 	char	clone_name[MAXPATHLEN];
8480b5de56dSgjelinek 	char	snap_path[MAXPATHLEN];
8490b5de56dSgjelinek 
8500b5de56dSgjelinek 	if (snap2path(snap_name, snap_path, sizeof (snap_path)) != Z_OK) {
8510b5de56dSgjelinek 		(void) fprintf(stderr, gettext("unable to find path for %s.\n"),
8520b5de56dSgjelinek 		    snap_name);
8530b5de56dSgjelinek 		return (Z_ERR);
8540b5de56dSgjelinek 	}
8550b5de56dSgjelinek 
856ff17c8bfSgjelinek 	if (validate_snapshot(snap_name, snap_path, validatesnap) != Z_OK)
8570b5de56dSgjelinek 		return (Z_NO_ENTRY);
8580b5de56dSgjelinek 
8590b5de56dSgjelinek 	/*
8600b5de56dSgjelinek 	 * The zonepath cannot be ZFS cloned, try to copy the data from
8610b5de56dSgjelinek 	 * within the snapshot to the zonepath.
8620b5de56dSgjelinek 	 */
8630b5de56dSgjelinek 	if (path2name(zonepath, clone_name, sizeof (clone_name)) != Z_OK) {
8640b5de56dSgjelinek 		if ((err = clone_copy(snap_path, zonepath)) == Z_OK)
8650b5de56dSgjelinek 			if (clean_out_clone() != Z_OK)
8660b5de56dSgjelinek 				(void) fprintf(stderr,
8670b5de56dSgjelinek 				    gettext("could not remove the "
8680b5de56dSgjelinek 				    "software inventory from %s\n"), zonepath);
8690b5de56dSgjelinek 
8700b5de56dSgjelinek 		return (err);
8710b5de56dSgjelinek 	}
8720b5de56dSgjelinek 
8730b5de56dSgjelinek 	if ((err = clone_snap(snap_name, clone_name)) != Z_OK) {
8740b5de56dSgjelinek 		if (err != Z_NO_ENTRY) {
8750b5de56dSgjelinek 			/*
8760b5de56dSgjelinek 			 * Cloning the snapshot failed.  Fall back to trying
8770b5de56dSgjelinek 			 * to install the zone by copying from the snapshot.
8780b5de56dSgjelinek 			 */
8790b5de56dSgjelinek 			if ((err = clone_copy(snap_path, zonepath)) == Z_OK)
8800b5de56dSgjelinek 				if (clean_out_clone() != Z_OK)
8810b5de56dSgjelinek 					(void) fprintf(stderr,
8820b5de56dSgjelinek 					    gettext("could not remove the "
8830b5de56dSgjelinek 					    "software inventory from %s\n"),
8840b5de56dSgjelinek 					    zonepath);
8850b5de56dSgjelinek 		} else {
8860b5de56dSgjelinek 			/*
8870b5de56dSgjelinek 			 * The snapshot is unusable for some reason so restore
8880b5de56dSgjelinek 			 * the zone state to configured since we were unable to
8890b5de56dSgjelinek 			 * actually do anything about getting the zone
8900b5de56dSgjelinek 			 * installed.
8910b5de56dSgjelinek 			 */
8920b5de56dSgjelinek 			int tmp;
8930b5de56dSgjelinek 
8940b5de56dSgjelinek 			if ((tmp = zone_set_state(target_zone,
8950b5de56dSgjelinek 			    ZONE_STATE_CONFIGURED)) != Z_OK) {
8960b5de56dSgjelinek 				errno = tmp;
8970b5de56dSgjelinek 				zperror2(target_zone,
8980b5de56dSgjelinek 				    gettext("could not set state"));
8990b5de56dSgjelinek 			}
9000b5de56dSgjelinek 		}
9010b5de56dSgjelinek 	}
9020b5de56dSgjelinek 
9030b5de56dSgjelinek 	return (err);
9040b5de56dSgjelinek }
9050b5de56dSgjelinek 
9060b5de56dSgjelinek /*
9070b5de56dSgjelinek  * Attempt to clone a source_zone to a target zonepath by using a ZFS clone.
9080b5de56dSgjelinek  */
9090b5de56dSgjelinek int
910ff17c8bfSgjelinek clone_zfs(char *source_zonepath, char *zonepath, char *presnapbuf,
911ff17c8bfSgjelinek     char *postsnapbuf)
9120b5de56dSgjelinek {
9130b5de56dSgjelinek 	zfs_handle_t	*zhp;
9140b5de56dSgjelinek 	char		clone_name[MAXPATHLEN];
9150b5de56dSgjelinek 	char		snap_name[MAXPATHLEN];
9160b5de56dSgjelinek 
9170b5de56dSgjelinek 	/*
9180b5de56dSgjelinek 	 * Try to get a zfs handle for the source_zonepath.  If this fails
9190b5de56dSgjelinek 	 * the source_zonepath is not ZFS so return an error.
9200b5de56dSgjelinek 	 */
9210b5de56dSgjelinek 	if ((zhp = mount2zhandle(source_zonepath)) == NULL)
9220b5de56dSgjelinek 		return (Z_ERR);
9230b5de56dSgjelinek 
9240b5de56dSgjelinek 	/*
9250b5de56dSgjelinek 	 * Check if there is a file system already mounted on zonepath.  If so,
9260b5de56dSgjelinek 	 * we can't clone to the path so we should fall back to copying.
9270b5de56dSgjelinek 	 */
9280b5de56dSgjelinek 	if (is_mountpnt(zonepath)) {
9290b5de56dSgjelinek 		zfs_close(zhp);
9300b5de56dSgjelinek 		(void) fprintf(stderr,
9310b5de56dSgjelinek 		    gettext("A file system is already mounted on %s,\n"
9320b5de56dSgjelinek 		    "preventing use of a ZFS clone.\n"), zonepath);
9330b5de56dSgjelinek 		return (Z_ERR);
9340b5de56dSgjelinek 	}
9350b5de56dSgjelinek 
9360b5de56dSgjelinek 	/*
9370b5de56dSgjelinek 	 * Instead of using path2name to get the clone name from the zonepath,
9380b5de56dSgjelinek 	 * we could generate a name from the source zone ZFS name.  However,
9390b5de56dSgjelinek 	 * this would mean we would create the clone under the ZFS fs of the
9400b5de56dSgjelinek 	 * source instead of what the zonepath says.  For example,
9410b5de56dSgjelinek 	 *
9420b5de56dSgjelinek 	 * source_zonepath		zonepath
9430b5de56dSgjelinek 	 * /pl/zones/dev/z1		/pl/zones/deploy/z2
9440b5de56dSgjelinek 	 *
9450b5de56dSgjelinek 	 * We don't want the clone to be under "dev", we want it under
9460b5de56dSgjelinek 	 * "deploy", so that we can leverage the normal attribute inheritance
9470b5de56dSgjelinek 	 * that ZFS provides in the fs hierarchy.
9480b5de56dSgjelinek 	 */
9490b5de56dSgjelinek 	if (path2name(zonepath, clone_name, sizeof (clone_name)) != Z_OK) {
9500b5de56dSgjelinek 		zfs_close(zhp);
9510b5de56dSgjelinek 		return (Z_ERR);
9520b5de56dSgjelinek 	}
9530b5de56dSgjelinek 
954ff17c8bfSgjelinek 	if (take_snapshot(zhp, snap_name, sizeof (snap_name), presnapbuf,
955ff17c8bfSgjelinek 	    postsnapbuf) != Z_OK) {
9560b5de56dSgjelinek 		zfs_close(zhp);
9570b5de56dSgjelinek 		return (Z_ERR);
9580b5de56dSgjelinek 	}
9590b5de56dSgjelinek 	zfs_close(zhp);
9600b5de56dSgjelinek 
961d9e728a2Sgjelinek 	if (clone_snap(snap_name, clone_name) != Z_OK) {
962d9e728a2Sgjelinek 		/* Clean up the snapshot we just took. */
963d9e728a2Sgjelinek 		if ((zhp = zfs_open(g_zfs, snap_name, ZFS_TYPE_SNAPSHOT))
964d9e728a2Sgjelinek 		    != NULL) {
965d9e728a2Sgjelinek 			if (zfs_unmount(zhp, NULL, 0) == 0)
966842727c2SChris Kirby 				(void) zfs_destroy(zhp, B_FALSE);
967d9e728a2Sgjelinek 			zfs_close(zhp);
968d9e728a2Sgjelinek 		}
969d9e728a2Sgjelinek 
9700b5de56dSgjelinek 		return (Z_ERR);
971d9e728a2Sgjelinek 	}
9720b5de56dSgjelinek 
9730b5de56dSgjelinek 	(void) printf(gettext("Instead of copying, a ZFS clone has been "
9740b5de56dSgjelinek 	    "created for this zone.\n"));
9750b5de56dSgjelinek 
9760b5de56dSgjelinek 	return (Z_OK);
9770b5de56dSgjelinek }
9780b5de56dSgjelinek 
9790b5de56dSgjelinek /*
9800b5de56dSgjelinek  * Attempt to create a ZFS file system for the specified zonepath.
9810b5de56dSgjelinek  * We either will successfully create a ZFS file system and get it mounted
9820b5de56dSgjelinek  * on the zonepath or we don't.  The caller doesn't care since a regular
9830b5de56dSgjelinek  * directory is used for the zonepath if no ZFS file system is mounted there.
9840b5de56dSgjelinek  */
9850b5de56dSgjelinek void
9860b5de56dSgjelinek create_zfs_zonepath(char *zonepath)
9870b5de56dSgjelinek {
9880b5de56dSgjelinek 	zfs_handle_t	*zhp;
9890b5de56dSgjelinek 	char		zfs_name[MAXPATHLEN];
990e9dbad6fSeschrock 	nvlist_t	*props = NULL;
9910b5de56dSgjelinek 
9920b5de56dSgjelinek 	if (path2name(zonepath, zfs_name, sizeof (zfs_name)) != Z_OK)
9930b5de56dSgjelinek 		return;
9940b5de56dSgjelinek 
995d1f855d7S 	/* Check if the dataset already exists. */
996d1f855d7S 	if ((zhp = zfs_open(g_zfs, zfs_name, ZFS_TYPE_DATASET)) != NULL) {
997d1f855d7S 		zfs_close(zhp);
998d1f855d7S 		return;
999d1f855d7S 	}
1000d1f855d7S 
1001e9dbad6fSeschrock 	if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0 ||
10025f8e1617Snn35248 	    nvlist_add_string(props, zfs_prop_to_name(ZFS_PROP_SHARENFS),
10035f8e1617Snn35248 	    "off") != 0) {
10045f8e1617Snn35248 		if (props != NULL)
1005e9dbad6fSeschrock 			nvlist_free(props);
1006e9dbad6fSeschrock 		(void) fprintf(stderr, gettext("cannot create ZFS dataset %s: "
1007e9dbad6fSeschrock 		    "out of memory\n"), zfs_name);
1008e9dbad6fSeschrock 	}
1009e9dbad6fSeschrock 
1010e9dbad6fSeschrock 	if (zfs_create(g_zfs, zfs_name, ZFS_TYPE_FILESYSTEM, props) != 0 ||
1011990b4856Slling 	    (zhp = zfs_open(g_zfs, zfs_name, ZFS_TYPE_DATASET)) == NULL) {
101299653d4eSeschrock 		(void) fprintf(stderr, gettext("cannot create ZFS dataset %s: "
101399653d4eSeschrock 		    "%s\n"), zfs_name, libzfs_error_description(g_zfs));
1014e9dbad6fSeschrock 		nvlist_free(props);
10150b5de56dSgjelinek 		return;
10160b5de56dSgjelinek 	}
10170b5de56dSgjelinek 
1018e9dbad6fSeschrock 	nvlist_free(props);
1019e9dbad6fSeschrock 
10200b5de56dSgjelinek 	if (zfs_mount(zhp, NULL, 0) != 0) {
102199653d4eSeschrock 		(void) fprintf(stderr, gettext("cannot mount ZFS dataset %s: "
102299653d4eSeschrock 		    "%s\n"), zfs_name, libzfs_error_description(g_zfs));
1023842727c2SChris Kirby 		(void) zfs_destroy(zhp, B_FALSE);
10240b5de56dSgjelinek 	} else {
10250b5de56dSgjelinek 		if (chmod(zonepath, S_IRWXU) != 0) {
10260b5de56dSgjelinek 			(void) fprintf(stderr, gettext("file system %s "
10270b5de56dSgjelinek 			    "successfully created, but chmod %o failed: %s\n"),
10280b5de56dSgjelinek 			    zfs_name, S_IRWXU, strerror(errno));
10290b5de56dSgjelinek 			(void) destroy_zfs(zonepath);
10300b5de56dSgjelinek 		} else {
10310b5de56dSgjelinek 			(void) printf(gettext("A ZFS file system has been "
10320b5de56dSgjelinek 			    "created for this zone.\n"));
10330b5de56dSgjelinek 		}
10340b5de56dSgjelinek 	}
10350b5de56dSgjelinek 
10360b5de56dSgjelinek 	zfs_close(zhp);
10370b5de56dSgjelinek }
10380b5de56dSgjelinek 
10390b5de56dSgjelinek /*
10400b5de56dSgjelinek  * If the zonepath is a ZFS file system, attempt to destroy it.  We return Z_OK
10410b5de56dSgjelinek  * if we were able to zfs_destroy the zonepath, otherwise we return Z_ERR
10420b5de56dSgjelinek  * which means the caller should clean up the zonepath in the traditional
10430b5de56dSgjelinek  * way.
10440b5de56dSgjelinek  */
10450b5de56dSgjelinek int
10460b5de56dSgjelinek destroy_zfs(char *zonepath)
10470b5de56dSgjelinek {
10480b5de56dSgjelinek 	zfs_handle_t	*zhp;
10490b5de56dSgjelinek 	boolean_t	is_clone = B_FALSE;
10500b5de56dSgjelinek 	char		origin[ZFS_MAXPROPLEN];
10510b5de56dSgjelinek 
105299653d4eSeschrock 	if ((zhp = mount2zhandle(zonepath)) == NULL)
10530b5de56dSgjelinek 		return (Z_ERR);
10540b5de56dSgjelinek 
1055286822ddS 	if (promote_all_clones(zhp) != 0)
1056286822ddS 		return (Z_ERR);
1057286822ddS 
1058286822ddS 	/* Now cleanup any snapshots remaining. */
1059286822ddS 	if (zfs_iter_snapshots(zhp, rm_snap, NULL) != 0) {
1060286822ddS 		zfs_close(zhp);
1061286822ddS 		return (Z_ERR);
1062286822ddS 	}
1063286822ddS 
10640b5de56dSgjelinek 	/*
1065286822ddS 	 * We can't destroy the file system if it has still has dependents.
1066286822ddS 	 * There shouldn't be any at this point, but we'll double check.
10670b5de56dSgjelinek 	 */
1068286822ddS 	if (zfs_iter_dependents(zhp, B_TRUE, has_dependent, NULL) != 0) {
1069286822ddS 		(void) fprintf(stderr, gettext("zfs destroy %s failed: the "
1070286822ddS 		    "dataset still has dependents\n"), zfs_get_name(zhp));
10710b5de56dSgjelinek 		zfs_close(zhp);
10720b5de56dSgjelinek 		return (Z_ERR);
10730b5de56dSgjelinek 	}
10740b5de56dSgjelinek 
10750b5de56dSgjelinek 	/*
10760b5de56dSgjelinek 	 * This might be a clone.  Try to get the snapshot so we can attempt
10770b5de56dSgjelinek 	 * to destroy that as well.
10780b5de56dSgjelinek 	 */
10790b5de56dSgjelinek 	if (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, origin, sizeof (origin), NULL,
108099653d4eSeschrock 	    NULL, 0, B_FALSE) == 0)
10810b5de56dSgjelinek 		is_clone = B_TRUE;
10820b5de56dSgjelinek 
1083286822ddS 	if (zfs_unmount(zhp, NULL, 0) != 0) {
1084286822ddS 		(void) fprintf(stderr, gettext("zfs unmount %s failed: %s\n"),
1085286822ddS 		    zfs_get_name(zhp), libzfs_error_description(g_zfs));
1086286822ddS 		zfs_close(zhp);
1087286822ddS 		return (Z_ERR);
1088286822ddS 	}
1089286822ddS 
1090842727c2SChris Kirby 	if (zfs_destroy(zhp, B_FALSE) != 0) {
10910b5de56dSgjelinek 		/*
10920b5de56dSgjelinek 		 * If the destroy fails for some reason, try to remount
10930b5de56dSgjelinek 		 * the file system so that we can use "rm -rf" to clean up
10940b5de56dSgjelinek 		 * instead.
10950b5de56dSgjelinek 		 */
1096286822ddS 		(void) fprintf(stderr, gettext("zfs destroy %s failed: %s\n"),
1097286822ddS 		    zfs_get_name(zhp), libzfs_error_description(g_zfs));
10980b5de56dSgjelinek 		(void) zfs_mount(zhp, NULL, 0);
10990b5de56dSgjelinek 		zfs_close(zhp);
11000b5de56dSgjelinek 		return (Z_ERR);
11010b5de56dSgjelinek 	}
11020b5de56dSgjelinek 
1103d9e728a2Sgjelinek 	/*
1104d9e728a2Sgjelinek 	 * If the zone has ever been moved then the mountpoint dir will not be
1105d9e728a2Sgjelinek 	 * cleaned up by the zfs_destroy().  To handle this case try to clean
1106d9e728a2Sgjelinek 	 * it up now but don't worry if it fails, that will be normal.
1107d9e728a2Sgjelinek 	 */
1108d9e728a2Sgjelinek 	(void) rmdir(zonepath);
1109d9e728a2Sgjelinek 
11100b5de56dSgjelinek 	(void) printf(gettext("The ZFS file system for this zone has been "
11110b5de56dSgjelinek 	    "destroyed.\n"));
11120b5de56dSgjelinek 
11130b5de56dSgjelinek 	if (is_clone) {
11140b5de56dSgjelinek 		zfs_handle_t	*ohp;
11150b5de56dSgjelinek 
11160b5de56dSgjelinek 		/*
11170b5de56dSgjelinek 		 * Try to clean up the snapshot that the clone was taken from.
11180b5de56dSgjelinek 		 */
111999653d4eSeschrock 		if ((ohp = zfs_open(g_zfs, origin,
112099653d4eSeschrock 		    ZFS_TYPE_SNAPSHOT)) != NULL) {
11213bb79becSeschrock 			if (zfs_iter_dependents(ohp, B_TRUE, has_dependent,
11223bb79becSeschrock 			    NULL) == 0 && zfs_unmount(ohp, NULL, 0) == 0)
1123842727c2SChris Kirby 				(void) zfs_destroy(ohp, B_FALSE);
11240b5de56dSgjelinek 			zfs_close(ohp);
11250b5de56dSgjelinek 		}
11260b5de56dSgjelinek 	}
11270b5de56dSgjelinek 
11280b5de56dSgjelinek 	zfs_close(zhp);
11290b5de56dSgjelinek 	return (Z_OK);
11300b5de56dSgjelinek }
11310b5de56dSgjelinek 
11320b5de56dSgjelinek /*
11330b5de56dSgjelinek  * Return true if the path is its own zfs file system.  We determine this
11340b5de56dSgjelinek  * by stat-ing the path to see if it is zfs and stat-ing the parent to see
11350b5de56dSgjelinek  * if it is a different fs.
11360b5de56dSgjelinek  */
11370b5de56dSgjelinek boolean_t
11380b5de56dSgjelinek is_zonepath_zfs(char *zonepath)
11390b5de56dSgjelinek {
11400b5de56dSgjelinek 	int res;
11410b5de56dSgjelinek 	char *path;
11420b5de56dSgjelinek 	char *parent;
11433f2f09c1Sdp 	struct statvfs64 buf1, buf2;
11440b5de56dSgjelinek 
11453f2f09c1Sdp 	if (statvfs64(zonepath, &buf1) != 0)
11460b5de56dSgjelinek 		return (B_FALSE);
11470b5de56dSgjelinek 
11480b5de56dSgjelinek 	if (strcmp(buf1.f_basetype, "zfs") != 0)
11490b5de56dSgjelinek 		return (B_FALSE);
11500b5de56dSgjelinek 
11510b5de56dSgjelinek 	if ((path = strdup(zonepath)) == NULL)
11520b5de56dSgjelinek 		return (B_FALSE);
11530b5de56dSgjelinek 
11540b5de56dSgjelinek 	parent = dirname(path);
11553f2f09c1Sdp 	res = statvfs64(parent, &buf2);
11560b5de56dSgjelinek 	free(path);
11570b5de56dSgjelinek 
11580b5de56dSgjelinek 	if (res != 0)
11590b5de56dSgjelinek 		return (B_FALSE);
11600b5de56dSgjelinek 
11610b5de56dSgjelinek 	if (buf1.f_fsid == buf2.f_fsid)
11620b5de56dSgjelinek 		return (B_FALSE);
11630b5de56dSgjelinek 
11640b5de56dSgjelinek 	return (B_TRUE);
11650b5de56dSgjelinek }
11660b5de56dSgjelinek 
11670b5de56dSgjelinek /*
11680b5de56dSgjelinek  * Implement the fast move of a ZFS file system by simply updating the
11690b5de56dSgjelinek  * mountpoint.  Since it is file system already, we don't have the
11700b5de56dSgjelinek  * issue of cross-file system copying.
11710b5de56dSgjelinek  */
11720b5de56dSgjelinek int
11730b5de56dSgjelinek move_zfs(char *zonepath, char *new_zonepath)
11740b5de56dSgjelinek {
11750b5de56dSgjelinek 	int		ret = Z_ERR;
11760b5de56dSgjelinek 	zfs_handle_t	*zhp;
11770b5de56dSgjelinek 
117899653d4eSeschrock 	if ((zhp = mount2zhandle(zonepath)) == NULL)
11790b5de56dSgjelinek 		return (Z_ERR);
11800b5de56dSgjelinek 
1181e9dbad6fSeschrock 	if (zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
1182e9dbad6fSeschrock 	    new_zonepath) == 0) {
11830b5de56dSgjelinek 		/*
11840b5de56dSgjelinek 		 * Clean up the old mount point.  We ignore any failure since
11850b5de56dSgjelinek 		 * the zone is already successfully mounted on the new path.
11860b5de56dSgjelinek 		 */
11870b5de56dSgjelinek 		(void) rmdir(zonepath);
11880b5de56dSgjelinek 		ret = Z_OK;
11890b5de56dSgjelinek 	}
11900b5de56dSgjelinek 
11910b5de56dSgjelinek 	zfs_close(zhp);
11920b5de56dSgjelinek 
11930b5de56dSgjelinek 	return (ret);
11940b5de56dSgjelinek }
11950b5de56dSgjelinek 
11960b5de56dSgjelinek /*
11970b5de56dSgjelinek  * Validate that the given dataset exists on the system, and that neither it nor
11980b5de56dSgjelinek  * its children are zvols.
11990b5de56dSgjelinek  *
12000b5de56dSgjelinek  * Note that we don't do anything with the 'zoned' property here.  All
12010b5de56dSgjelinek  * management is done in zoneadmd when the zone is actually rebooted.  This
12020b5de56dSgjelinek  * allows us to automatically set the zoned property even when a zone is
12030b5de56dSgjelinek  * rebooted by the administrator.
12040b5de56dSgjelinek  */
12050b5de56dSgjelinek int
12060b5de56dSgjelinek verify_datasets(zone_dochandle_t handle)
12070b5de56dSgjelinek {
12080b5de56dSgjelinek 	int return_code = Z_OK;
12090b5de56dSgjelinek 	struct zone_dstab dstab;
12100b5de56dSgjelinek 	zfs_handle_t *zhp;
12110b5de56dSgjelinek 	char propbuf[ZFS_MAXPROPLEN];
12120b5de56dSgjelinek 	char source[ZFS_MAXNAMELEN];
1213990b4856Slling 	zprop_source_t srctype;
12140b5de56dSgjelinek 
12150b5de56dSgjelinek 	if (zonecfg_setdsent(handle) != Z_OK) {
12160b5de56dSgjelinek 		/*
12170b5de56dSgjelinek 		 * TRANSLATION_NOTE
12180b5de56dSgjelinek 		 * zfs and dataset are literals that should not be translated.
12190b5de56dSgjelinek 		 */
12200b5de56dSgjelinek 		(void) fprintf(stderr, gettext("could not verify zfs datasets: "
12210b5de56dSgjelinek 		    "unable to enumerate datasets\n"));
12220b5de56dSgjelinek 		return (Z_ERR);
12230b5de56dSgjelinek 	}
12240b5de56dSgjelinek 
12250b5de56dSgjelinek 	while (zonecfg_getdsent(handle, &dstab) == Z_OK) {
12260b5de56dSgjelinek 
122799653d4eSeschrock 		if ((zhp = zfs_open(g_zfs, dstab.zone_dataset_name,
12280b5de56dSgjelinek 		    ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME)) == NULL) {
122999653d4eSeschrock 			(void) fprintf(stderr, gettext("could not verify zfs "
123099653d4eSeschrock 			    "dataset %s: %s\n"), dstab.zone_dataset_name,
123199653d4eSeschrock 			    libzfs_error_description(g_zfs));
12320b5de56dSgjelinek 			return_code = Z_ERR;
12330b5de56dSgjelinek 			continue;
12340b5de56dSgjelinek 		}
12350b5de56dSgjelinek 
12360b5de56dSgjelinek 		if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, propbuf,
12370b5de56dSgjelinek 		    sizeof (propbuf), &srctype, source,
12380b5de56dSgjelinek 		    sizeof (source), 0) == 0 &&
1239990b4856Slling 		    (srctype == ZPROP_SRC_INHERITED)) {
12400b5de56dSgjelinek 			(void) fprintf(stderr, gettext("could not verify zfs "
12410b5de56dSgjelinek 			    "dataset %s: mountpoint cannot be inherited\n"),
12420b5de56dSgjelinek 			    dstab.zone_dataset_name);
12430b5de56dSgjelinek 			return_code = Z_ERR;
12440b5de56dSgjelinek 			zfs_close(zhp);
12450b5de56dSgjelinek 			continue;
12460b5de56dSgjelinek 		}
12470b5de56dSgjelinek 
12480b5de56dSgjelinek 		if (zfs_get_type(zhp) == ZFS_TYPE_VOLUME) {
12490b5de56dSgjelinek 			(void) fprintf(stderr, gettext("cannot verify zfs "
12500b5de56dSgjelinek 			    "dataset %s: volumes cannot be specified as a "
12510b5de56dSgjelinek 			    "zone dataset resource\n"),
12520b5de56dSgjelinek 			    dstab.zone_dataset_name);
12530b5de56dSgjelinek 			return_code = Z_ERR;
12540b5de56dSgjelinek 		}
12550b5de56dSgjelinek 
12560b5de56dSgjelinek 		if (zfs_iter_children(zhp, check_zvol, NULL) != 0)
12570b5de56dSgjelinek 			return_code = Z_ERR;
12580b5de56dSgjelinek 
12590b5de56dSgjelinek 		zfs_close(zhp);
12600b5de56dSgjelinek 	}
12610b5de56dSgjelinek 	(void) zonecfg_enddsent(handle);
12620b5de56dSgjelinek 
12630b5de56dSgjelinek 	return (return_code);
12640b5de56dSgjelinek }
12650b5de56dSgjelinek 
12660b5de56dSgjelinek /*
12670b5de56dSgjelinek  * Verify that the ZFS dataset exists, and its mountpoint
12680b5de56dSgjelinek  * property is set to "legacy".
12690b5de56dSgjelinek  */
12700b5de56dSgjelinek int
12710b5de56dSgjelinek verify_fs_zfs(struct zone_fstab *fstab)
12720b5de56dSgjelinek {
12730b5de56dSgjelinek 	zfs_handle_t *zhp;
12740b5de56dSgjelinek 	char propbuf[ZFS_MAXPROPLEN];
12750b5de56dSgjelinek 
127699653d4eSeschrock 	if ((zhp = zfs_open(g_zfs, fstab->zone_fs_special,
1277990b4856Slling 	    ZFS_TYPE_DATASET)) == NULL) {
12780b5de56dSgjelinek 		(void) fprintf(stderr, gettext("could not verify fs %s: "
12790b5de56dSgjelinek 		    "could not access zfs dataset '%s'\n"),
12800b5de56dSgjelinek 		    fstab->zone_fs_dir, fstab->zone_fs_special);
12810b5de56dSgjelinek 		return (Z_ERR);
12820b5de56dSgjelinek 	}
12830b5de56dSgjelinek 
12840b5de56dSgjelinek 	if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) {
12850b5de56dSgjelinek 		(void) fprintf(stderr, gettext("cannot verify fs %s: "
12860b5de56dSgjelinek 		    "'%s' is not a file system\n"),
12870b5de56dSgjelinek 		    fstab->zone_fs_dir, fstab->zone_fs_special);
12880b5de56dSgjelinek 		zfs_close(zhp);
12890b5de56dSgjelinek 		return (Z_ERR);
12900b5de56dSgjelinek 	}
12910b5de56dSgjelinek 
12920b5de56dSgjelinek 	if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, propbuf, sizeof (propbuf),
12930b5de56dSgjelinek 	    NULL, NULL, 0, 0) != 0 || strcmp(propbuf, "legacy") != 0) {
12940b5de56dSgjelinek 		(void) fprintf(stderr, gettext("could not verify fs %s: "
12950b5de56dSgjelinek 		    "zfs '%s' mountpoint is not \"legacy\"\n"),
12960b5de56dSgjelinek 		    fstab->zone_fs_dir, fstab->zone_fs_special);
12970b5de56dSgjelinek 		zfs_close(zhp);
12980b5de56dSgjelinek 		return (Z_ERR);
12990b5de56dSgjelinek 	}
13000b5de56dSgjelinek 
13010b5de56dSgjelinek 	zfs_close(zhp);
130299653d4eSeschrock 	return (Z_OK);
130399653d4eSeschrock }
130499653d4eSeschrock 
1305*0094b373Sjv227347 /*
1306*0094b373Sjv227347  * Destroy the specified mnttab structure that was created by mnttab_dup().
1307*0094b373Sjv227347  * NOTE: The structure's mnt_time field isn't freed.
1308*0094b373Sjv227347  */
1309*0094b373Sjv227347 static void
1310*0094b373Sjv227347 mnttab_destroy(struct mnttab *tabp)
1311*0094b373Sjv227347 {
1312*0094b373Sjv227347 	assert(tabp != NULL);
1313*0094b373Sjv227347 
1314*0094b373Sjv227347 	free(tabp->mnt_mountp);
1315*0094b373Sjv227347 	free(tabp->mnt_special);
1316*0094b373Sjv227347 	free(tabp->mnt_fstype);
1317*0094b373Sjv227347 	free(tabp->mnt_mntopts);
1318*0094b373Sjv227347 	free(tabp);
1319*0094b373Sjv227347 }
1320*0094b373Sjv227347 
1321*0094b373Sjv227347 /*
1322*0094b373Sjv227347  * Duplicate the specified mnttab structure.  The mnt_mountp and mnt_time
1323*0094b373Sjv227347  * fields aren't duplicated.  This function returns a pointer to the new mnttab
1324*0094b373Sjv227347  * structure or NULL if an error occurred.  If an error occurs, then this
1325*0094b373Sjv227347  * function sets errno to reflect the error.  mnttab structures created by
1326*0094b373Sjv227347  * this function should be destroyed via mnttab_destroy().
1327*0094b373Sjv227347  */
1328*0094b373Sjv227347 static struct mnttab *
1329*0094b373Sjv227347 mnttab_dup(const struct mnttab *srcp)
1330*0094b373Sjv227347 {
1331*0094b373Sjv227347 	struct mnttab *retval;
1332*0094b373Sjv227347 
1333*0094b373Sjv227347 	assert(srcp != NULL);
1334*0094b373Sjv227347 
1335*0094b373Sjv227347 	retval = (struct mnttab *)calloc(1, sizeof (*retval));
1336*0094b373Sjv227347 	if (retval == NULL) {
1337*0094b373Sjv227347 		errno = ENOMEM;
1338*0094b373Sjv227347 		return (NULL);
1339*0094b373Sjv227347 	}
1340*0094b373Sjv227347 	if (srcp->mnt_special != NULL) {
1341*0094b373Sjv227347 		retval->mnt_special = strdup(srcp->mnt_special);
1342*0094b373Sjv227347 		if (retval->mnt_special == NULL)
1343*0094b373Sjv227347 			goto err;
1344*0094b373Sjv227347 	}
1345*0094b373Sjv227347 	if (srcp->mnt_fstype != NULL) {
1346*0094b373Sjv227347 		retval->mnt_fstype = strdup(srcp->mnt_fstype);
1347*0094b373Sjv227347 		if (retval->mnt_fstype == NULL)
1348*0094b373Sjv227347 			goto err;
1349*0094b373Sjv227347 	}
1350*0094b373Sjv227347 	retval->mnt_mntopts = (char *)malloc(MAX_MNTOPT_STR * sizeof (char));
1351*0094b373Sjv227347 	if (retval->mnt_mntopts == NULL)
1352*0094b373Sjv227347 		goto err;
1353*0094b373Sjv227347 	if (srcp->mnt_mntopts != NULL) {
1354*0094b373Sjv227347 		if (strlcpy(retval->mnt_mntopts, srcp->mnt_mntopts,
1355*0094b373Sjv227347 		    MAX_MNTOPT_STR * sizeof (char)) >= MAX_MNTOPT_STR *
1356*0094b373Sjv227347 		    sizeof (char)) {
1357*0094b373Sjv227347 			mnttab_destroy(retval);
1358*0094b373Sjv227347 			errno = EOVERFLOW; /* similar to mount(2) behavior */
1359*0094b373Sjv227347 			return (NULL);
1360*0094b373Sjv227347 		}
1361*0094b373Sjv227347 	} else {
1362*0094b373Sjv227347 		retval->mnt_mntopts[0] = '\0';
1363*0094b373Sjv227347 	}
1364*0094b373Sjv227347 	return (retval);
1365*0094b373Sjv227347 
1366*0094b373Sjv227347 err:
1367*0094b373Sjv227347 	mnttab_destroy(retval);
1368*0094b373Sjv227347 	errno = ENOMEM;
1369*0094b373Sjv227347 	return (NULL);
1370*0094b373Sjv227347 }
1371*0094b373Sjv227347 
1372*0094b373Sjv227347 /*
1373*0094b373Sjv227347  * Determine whether the specified ZFS dataset's mountpoint property is set
1374*0094b373Sjv227347  * to "legacy".  If the specified dataset does not have a legacy mountpoint,
1375*0094b373Sjv227347  * then the string pointer to which the mountpoint argument points is assigned
1376*0094b373Sjv227347  * a dynamically-allocated string containing the dataset's mountpoint
1377*0094b373Sjv227347  * property.  If the dataset's mountpoint property is "legacy" or a libzfs
1378*0094b373Sjv227347  * error occurs, then the string pointer to which the mountpoint argument
1379*0094b373Sjv227347  * points isn't modified.
1380*0094b373Sjv227347  *
1381*0094b373Sjv227347  * This function returns B_TRUE if it doesn't encounter any fatal errors.
1382*0094b373Sjv227347  * It returns B_FALSE if it encounters a fatal error and sets errno to the
1383*0094b373Sjv227347  * appropriate error code.
1384*0094b373Sjv227347  */
1385*0094b373Sjv227347 static boolean_t
1386*0094b373Sjv227347 get_zfs_non_legacy_mountpoint(const char *dataset_name, char **mountpoint)
1387*0094b373Sjv227347 {
1388*0094b373Sjv227347 	zfs_handle_t *zhp;
1389*0094b373Sjv227347 	char propbuf[ZFS_MAXPROPLEN];
1390*0094b373Sjv227347 
1391*0094b373Sjv227347 	assert(dataset_name != NULL);
1392*0094b373Sjv227347 	assert(mountpoint != NULL);
1393*0094b373Sjv227347 
1394*0094b373Sjv227347 	if ((zhp = zfs_open(g_zfs, dataset_name, ZFS_TYPE_DATASET)) == NULL) {
1395*0094b373Sjv227347 		errno = EINVAL;
1396*0094b373Sjv227347 		return (B_FALSE);
1397*0094b373Sjv227347 	}
1398*0094b373Sjv227347 	if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, propbuf, sizeof (propbuf),
1399*0094b373Sjv227347 	    NULL, NULL, 0, 0) != 0) {
1400*0094b373Sjv227347 		zfs_close(zhp);
1401*0094b373Sjv227347 		errno = EINVAL;
1402*0094b373Sjv227347 		return (B_FALSE);
1403*0094b373Sjv227347 	}
1404*0094b373Sjv227347 	zfs_close(zhp);
1405*0094b373Sjv227347 	if (strcmp(propbuf, "legacy") != 0) {
1406*0094b373Sjv227347 		if ((*mountpoint = strdup(propbuf)) == NULL) {
1407*0094b373Sjv227347 			errno = ENOMEM;
1408*0094b373Sjv227347 			return (B_FALSE);
1409*0094b373Sjv227347 		}
1410*0094b373Sjv227347 	}
1411*0094b373Sjv227347 	return (B_TRUE);
1412*0094b373Sjv227347 }
1413*0094b373Sjv227347 
1414*0094b373Sjv227347 
1415*0094b373Sjv227347 /*
1416*0094b373Sjv227347  * This zonecfg_find_mounts() callback records information about mounts of
1417*0094b373Sjv227347  * interest in a zonepath.  It also tallies the number of zone
1418*0094b373Sjv227347  * root overlay mounts and the number of unexpected mounts found.
1419*0094b373Sjv227347  * This function outputs errors using zerror() if it finds unexpected
1420*0094b373Sjv227347  * mounts.  cookiep should point to an initialized zone_mounts_t structure.
1421*0094b373Sjv227347  *
1422*0094b373Sjv227347  * This function returns zero on success and a nonzero value on failure.
1423*0094b373Sjv227347  */
1424*0094b373Sjv227347 static int
1425*0094b373Sjv227347 zone_mounts_cb(const struct mnttab *mountp, void *cookiep)
1426*0094b373Sjv227347 {
1427*0094b373Sjv227347 	zone_mounts_t *mounts;
1428*0094b373Sjv227347 	const char *zone_mount_dir;
1429*0094b373Sjv227347 
1430*0094b373Sjv227347 	assert(mountp != NULL);
1431*0094b373Sjv227347 	assert(cookiep != NULL);
1432*0094b373Sjv227347 
1433*0094b373Sjv227347 	mounts = (zone_mounts_t *)cookiep;
1434*0094b373Sjv227347 	zone_mount_dir = mountp->mnt_mountp + mounts->zonepath_len;
1435*0094b373Sjv227347 	if (strcmp(zone_mount_dir, "/root") == 0) {
1436*0094b373Sjv227347 		/*
1437*0094b373Sjv227347 		 * Check for an overlay mount.  If we already detected a /root
1438*0094b373Sjv227347 		 * mount, then the current mount must be an overlay mount.
1439*0094b373Sjv227347 		 */
1440*0094b373Sjv227347 		if (mounts->root_mnttab != NULL) {
1441*0094b373Sjv227347 			mounts->num_root_overlay_mounts++;
1442*0094b373Sjv227347 			return (0);
1443*0094b373Sjv227347 		}
1444*0094b373Sjv227347 
1445*0094b373Sjv227347 		/*
1446*0094b373Sjv227347 		 * Store the root mount's mnttab information in the
1447*0094b373Sjv227347 		 * zone_mounts_t structure for future use.
1448*0094b373Sjv227347 		 */
1449*0094b373Sjv227347 		if ((mounts->root_mnttab = mnttab_dup(mountp)) == NULL) {
1450*0094b373Sjv227347 			zperror(cmd_to_str(CMD_MOVE), B_FALSE);
1451*0094b373Sjv227347 			return (-1);
1452*0094b373Sjv227347 		}
1453*0094b373Sjv227347 
1454*0094b373Sjv227347 		/*
1455*0094b373Sjv227347 		 * Determine if the filesystem is a ZFS filesystem with a
1456*0094b373Sjv227347 		 * non-legacy mountpoint.  If it is, then set the root
1457*0094b373Sjv227347 		 * filesystem's mnttab's mnt_mountp field to a non-NULL
1458*0094b373Sjv227347 		 * value, which will serve as a flag to indicate this special
1459*0094b373Sjv227347 		 * condition.
1460*0094b373Sjv227347 		 */
1461*0094b373Sjv227347 		if (strcmp(mountp->mnt_fstype, MNTTYPE_ZFS) == 0 &&
1462*0094b373Sjv227347 		    get_zfs_non_legacy_mountpoint(mountp->mnt_special,
1463*0094b373Sjv227347 		    &mounts->root_mnttab->mnt_mountp) != B_TRUE) {
1464*0094b373Sjv227347 			zperror(cmd_to_str(CMD_MOVE), B_FALSE);
1465*0094b373Sjv227347 			return (-1);
1466*0094b373Sjv227347 		}
1467*0094b373Sjv227347 	} else {
1468*0094b373Sjv227347 		/*
1469*0094b373Sjv227347 		 * An unexpected mount was found.  Notify the user.
1470*0094b373Sjv227347 		 */
1471*0094b373Sjv227347 		if (mounts->num_unexpected_mounts == 0)
1472*0094b373Sjv227347 			zerror(gettext("These file systems are mounted on "
1473*0094b373Sjv227347 			    "subdirectories of %s.\n"), mounts->zonepath);
1474*0094b373Sjv227347 		mounts->num_unexpected_mounts++;
1475*0094b373Sjv227347 		(void) zfm_print(mountp, NULL);
1476*0094b373Sjv227347 	}
1477*0094b373Sjv227347 	return (0);
1478*0094b373Sjv227347 }
1479*0094b373Sjv227347 
1480*0094b373Sjv227347 /*
1481*0094b373Sjv227347  * Initialize the specified zone_mounts_t structure for the given zonepath.
1482*0094b373Sjv227347  * If this function succeeds, it returns zero and the specified zone_mounts_t
1483*0094b373Sjv227347  * structure contains information about mounts in the specified zonepath.
1484*0094b373Sjv227347  * The function returns a nonzero value if it fails.  The zone_mounts_t
1485*0094b373Sjv227347  * structure doesn't need be destroyed via zone_mounts_destroy() if this
1486*0094b373Sjv227347  * function fails.
1487*0094b373Sjv227347  */
1488*0094b373Sjv227347 int
1489*0094b373Sjv227347 zone_mounts_init(zone_mounts_t *mounts, const char *zonepath)
1490*0094b373Sjv227347 {
1491*0094b373Sjv227347 	assert(mounts != NULL);
1492*0094b373Sjv227347 	assert(zonepath != NULL);
1493*0094b373Sjv227347 
1494*0094b373Sjv227347 	bzero(mounts, sizeof (*mounts));
1495*0094b373Sjv227347 	if ((mounts->zonepath = strdup(zonepath)) == NULL) {
1496*0094b373Sjv227347 		zerror(gettext("the process ran out of memory while checking "
1497*0094b373Sjv227347 		    "for mounts in zonepath %s."), zonepath);
1498*0094b373Sjv227347 		return (-1);
1499*0094b373Sjv227347 	}
1500*0094b373Sjv227347 	mounts->zonepath_len = strlen(zonepath);
1501*0094b373Sjv227347 	if (zonecfg_find_mounts((char *)zonepath, zone_mounts_cb, mounts) ==
1502*0094b373Sjv227347 	    -1) {
1503*0094b373Sjv227347 		zerror(gettext("an error occurred while checking for mounts "
1504*0094b373Sjv227347 		    "in zonepath %s."), zonepath);
1505*0094b373Sjv227347 		zone_mounts_destroy(mounts);
1506*0094b373Sjv227347 		return (-1);
1507*0094b373Sjv227347 	}
1508*0094b373Sjv227347 	return (0);
1509*0094b373Sjv227347 }
1510*0094b373Sjv227347 
1511*0094b373Sjv227347 /*
1512*0094b373Sjv227347  * Destroy the memory used by the specified zone_mounts_t structure's fields.
1513*0094b373Sjv227347  * This function doesn't free the memory occupied by the structure itself
1514*0094b373Sjv227347  * (i.e., it doesn't free the parameter).
1515*0094b373Sjv227347  */
1516*0094b373Sjv227347 void
1517*0094b373Sjv227347 zone_mounts_destroy(zone_mounts_t *mounts)
1518*0094b373Sjv227347 {
1519*0094b373Sjv227347 	assert(mounts != NULL);
1520*0094b373Sjv227347 
1521*0094b373Sjv227347 	free(mounts->zonepath);
1522*0094b373Sjv227347 	if (mounts->root_mnttab != NULL)
1523*0094b373Sjv227347 		mnttab_destroy(mounts->root_mnttab);
1524*0094b373Sjv227347 }
1525*0094b373Sjv227347 
1526*0094b373Sjv227347 /*
1527*0094b373Sjv227347  * Mount a moving zone's root filesystem (if it had a root filesystem mount
1528*0094b373Sjv227347  * prior to the move) using the specified zonepath.  mounts should refer to
1529*0094b373Sjv227347  * the zone_mounts_t structure describing the zone's mount information.
1530*0094b373Sjv227347  *
1531*0094b373Sjv227347  * This function returns zero if the mount succeeds and a nonzero value
1532*0094b373Sjv227347  * if it doesn't.
1533*0094b373Sjv227347  */
1534*0094b373Sjv227347 int
1535*0094b373Sjv227347 zone_mount_rootfs(zone_mounts_t *mounts, const char *zonepath)
1536*0094b373Sjv227347 {
1537*0094b373Sjv227347 	char zoneroot[MAXPATHLEN];
1538*0094b373Sjv227347 	struct mnttab *mtab;
1539*0094b373Sjv227347 	int flags;
1540*0094b373Sjv227347 
1541*0094b373Sjv227347 	assert(mounts != NULL);
1542*0094b373Sjv227347 	assert(zonepath != NULL);
1543*0094b373Sjv227347 
1544*0094b373Sjv227347 	/*
1545*0094b373Sjv227347 	 * If there isn't a root filesystem, then don't do anything.
1546*0094b373Sjv227347 	 */
1547*0094b373Sjv227347 	mtab = mounts->root_mnttab;
1548*0094b373Sjv227347 	if (mtab == NULL)
1549*0094b373Sjv227347 		return (0);
1550*0094b373Sjv227347 
1551*0094b373Sjv227347 	/*
1552*0094b373Sjv227347 	 * Determine the root filesystem's new mountpoint.
1553*0094b373Sjv227347 	 */
1554*0094b373Sjv227347 	if (snprintf(zoneroot, sizeof (zoneroot), "%s/root", zonepath) >=
1555*0094b373Sjv227347 	    sizeof (zoneroot)) {
1556*0094b373Sjv227347 		zerror(gettext("Zonepath %s is too long.\n"), zonepath);
1557*0094b373Sjv227347 		return (-1);
1558*0094b373Sjv227347 	}
1559*0094b373Sjv227347 
1560*0094b373Sjv227347 	/*
1561*0094b373Sjv227347 	 * If the root filesystem is a non-legacy ZFS filesystem (i.e., if it's
1562*0094b373Sjv227347 	 * mnt_mountp field is non-NULL), then make the filesystem's new
1563*0094b373Sjv227347 	 * mount point its mountpoint property and mount the filesystem.
1564*0094b373Sjv227347 	 */
1565*0094b373Sjv227347 	if (mtab->mnt_mountp != NULL) {
1566*0094b373Sjv227347 		zfs_handle_t *zhp;
1567*0094b373Sjv227347 
1568*0094b373Sjv227347 		if ((zhp = zfs_open(g_zfs, mtab->mnt_special,
1569*0094b373Sjv227347 		    ZFS_TYPE_DATASET)) == NULL) {
1570*0094b373Sjv227347 			zerror(gettext("could not get ZFS handle for the zone's"
1571*0094b373Sjv227347 			    " root filesystem"));
1572*0094b373Sjv227347 			return (-1);
1573*0094b373Sjv227347 		}
1574*0094b373Sjv227347 		if (zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
1575*0094b373Sjv227347 		    zoneroot) != 0) {
1576*0094b373Sjv227347 			zerror(gettext("could not modify zone's root "
1577*0094b373Sjv227347 			    "filesystem's mountpoint property"));
1578*0094b373Sjv227347 			zfs_close(zhp);
1579*0094b373Sjv227347 			return (-1);
1580*0094b373Sjv227347 		}
1581*0094b373Sjv227347 		if (zfs_mount(zhp, mtab->mnt_mntopts, 0) != 0) {
1582*0094b373Sjv227347 			zerror(gettext("unable to mount zone root %s: %s"),
1583*0094b373Sjv227347 			    zoneroot, libzfs_error_description(g_zfs));
1584*0094b373Sjv227347 			if (zfs_prop_set(zhp,
1585*0094b373Sjv227347 			    zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
1586*0094b373Sjv227347 			    mtab->mnt_mountp) != 0)
1587*0094b373Sjv227347 				zerror(gettext("unable to restore zone's root "
1588*0094b373Sjv227347 				    "filesystem's mountpoint property"));
1589*0094b373Sjv227347 			zfs_close(zhp);
1590*0094b373Sjv227347 			return (-1);
1591*0094b373Sjv227347 		}
1592*0094b373Sjv227347 		zfs_close(zhp);
1593*0094b373Sjv227347 		return (0);
1594*0094b373Sjv227347 	}
1595*0094b373Sjv227347 
1596*0094b373Sjv227347 	/*
1597*0094b373Sjv227347 	 * The root filesystem is either a legacy-mounted ZFS filesystem or
1598*0094b373Sjv227347 	 * a non-ZFS filesystem.  Use mount(2) to mount the root filesystem.
1599*0094b373Sjv227347 	 */
1600*0094b373Sjv227347 	if (mtab->mnt_mntopts != NULL)
1601*0094b373Sjv227347 		flags = MS_OPTIONSTR;
1602*0094b373Sjv227347 	else
1603*0094b373Sjv227347 		flags = 0;
1604*0094b373Sjv227347 	if (mount(mtab->mnt_special, zoneroot, flags, mtab->mnt_fstype, NULL, 0,
1605*0094b373Sjv227347 	    mtab->mnt_mntopts, MAX_MNTOPT_STR * sizeof (char)) != 0) {
1606*0094b373Sjv227347 		flags = errno;
1607*0094b373Sjv227347 		zerror(gettext("unable to mount zone root %s: %s"), zoneroot,
1608*0094b373Sjv227347 		    strerror(flags));
1609*0094b373Sjv227347 		return (-1);
1610*0094b373Sjv227347 	}
1611*0094b373Sjv227347 	return (0);
1612*0094b373Sjv227347 }
1613*0094b373Sjv227347 
1614*0094b373Sjv227347 /*
1615*0094b373Sjv227347  * Unmount a moving zone's root filesystem (if such a mount exists) using the
1616*0094b373Sjv227347  * specified zonepath.  mounts should refer to the zone_mounts_t structure
1617*0094b373Sjv227347  * describing the zone's mount information.  If force is B_TRUE, then if the
1618*0094b373Sjv227347  * unmount fails, then the function will try to forcibly unmount the zone's root
1619*0094b373Sjv227347  * filesystem.
1620*0094b373Sjv227347  *
1621*0094b373Sjv227347  * This function returns zero if the unmount (forced or otherwise) succeeds;
1622*0094b373Sjv227347  * otherwise, it returns a nonzero value.
1623*0094b373Sjv227347  */
1624*0094b373Sjv227347 int
1625*0094b373Sjv227347 zone_unmount_rootfs(zone_mounts_t *mounts, const char *zonepath,
1626*0094b373Sjv227347     boolean_t force)
1627*0094b373Sjv227347 {
1628*0094b373Sjv227347 	char zoneroot[MAXPATHLEN];
1629*0094b373Sjv227347 	struct mnttab *mtab;
1630*0094b373Sjv227347 	int err;
1631*0094b373Sjv227347 
1632*0094b373Sjv227347 	assert(mounts != NULL);
1633*0094b373Sjv227347 	assert(zonepath != NULL);
1634*0094b373Sjv227347 
1635*0094b373Sjv227347 	/*
1636*0094b373Sjv227347 	 * If there isn't a root filesystem, then don't do anything.
1637*0094b373Sjv227347 	 */
1638*0094b373Sjv227347 	mtab = mounts->root_mnttab;
1639*0094b373Sjv227347 	if (mtab == NULL)
1640*0094b373Sjv227347 		return (0);
1641*0094b373Sjv227347 
1642*0094b373Sjv227347 	/*
1643*0094b373Sjv227347 	 * Determine the root filesystem's mountpoint.
1644*0094b373Sjv227347 	 */
1645*0094b373Sjv227347 	if (snprintf(zoneroot, sizeof (zoneroot), "%s/root", zonepath) >=
1646*0094b373Sjv227347 	    sizeof (zoneroot)) {
1647*0094b373Sjv227347 		zerror(gettext("Zonepath %s is too long.\n"), zonepath);
1648*0094b373Sjv227347 		return (-1);
1649*0094b373Sjv227347 	}
1650*0094b373Sjv227347 
1651*0094b373Sjv227347 	/*
1652*0094b373Sjv227347 	 * If the root filesystem is a non-legacy ZFS fileystem, then unmount
1653*0094b373Sjv227347 	 * the filesystem via libzfs.
1654*0094b373Sjv227347 	 */
1655*0094b373Sjv227347 	if (mtab->mnt_mountp != NULL) {
1656*0094b373Sjv227347 		zfs_handle_t *zhp;
1657*0094b373Sjv227347 
1658*0094b373Sjv227347 		if ((zhp = zfs_open(g_zfs, mtab->mnt_special,
1659*0094b373Sjv227347 		    ZFS_TYPE_DATASET)) == NULL) {
1660*0094b373Sjv227347 			zerror(gettext("could not get ZFS handle for the zone's"
1661*0094b373Sjv227347 			    " root filesystem"));
1662*0094b373Sjv227347 			return (-1);
1663*0094b373Sjv227347 		}
1664*0094b373Sjv227347 		if (zfs_unmount(zhp, zoneroot, 0) != 0) {
1665*0094b373Sjv227347 			if (force && zfs_unmount(zhp, zoneroot, MS_FORCE) ==
1666*0094b373Sjv227347 			    0) {
1667*0094b373Sjv227347 				zfs_close(zhp);
1668*0094b373Sjv227347 				return (0);
1669*0094b373Sjv227347 			}
1670*0094b373Sjv227347 			zerror(gettext("unable to unmount zone root %s: %s"),
1671*0094b373Sjv227347 			    zoneroot, libzfs_error_description(g_zfs));
1672*0094b373Sjv227347 			zfs_close(zhp);
1673*0094b373Sjv227347 			return (-1);
1674*0094b373Sjv227347 		}
1675*0094b373Sjv227347 		zfs_close(zhp);
1676*0094b373Sjv227347 		return (0);
1677*0094b373Sjv227347 	}
1678*0094b373Sjv227347 
1679*0094b373Sjv227347 	/*
1680*0094b373Sjv227347 	 * Use umount(2) to unmount the root filesystem.  If this fails, then
1681*0094b373Sjv227347 	 * forcibly unmount it if the force flag is set.
1682*0094b373Sjv227347 	 */
1683*0094b373Sjv227347 	if (umount(zoneroot) != 0) {
1684*0094b373Sjv227347 		if (force && umount2(zoneroot, MS_FORCE) == 0)
1685*0094b373Sjv227347 			return (0);
1686*0094b373Sjv227347 		err = errno;
1687*0094b373Sjv227347 		zerror(gettext("unable to unmount zone root %s: %s"), zoneroot,
1688*0094b373Sjv227347 		    strerror(err));
1689*0094b373Sjv227347 		return (-1);
1690*0094b373Sjv227347 	}
1691*0094b373Sjv227347 	return (0);
1692*0094b373Sjv227347 }
1693*0094b373Sjv227347 
169499653d4eSeschrock int
169599653d4eSeschrock init_zfs(void)
169699653d4eSeschrock {
169799653d4eSeschrock 	if ((g_zfs = libzfs_init()) == NULL) {
169899653d4eSeschrock 		(void) fprintf(stderr, gettext("failed to initialize ZFS "
169999653d4eSeschrock 		    "library\n"));
170099653d4eSeschrock 		return (Z_ERR);
170199653d4eSeschrock 	}
170299653d4eSeschrock 
17030b5de56dSgjelinek 	return (Z_OK);
17040b5de56dSgjelinek }
1705