xref: /onnv-gate/usr/src/cmd/zoneadm/zfs.c (revision 2199:712a788c2dfd)
11867Sgjelinek /*
21867Sgjelinek  * CDDL HEADER START
31867Sgjelinek  *
41867Sgjelinek  * The contents of this file are subject to the terms of the
51867Sgjelinek  * Common Development and Distribution License (the "License").
61867Sgjelinek  * You may not use this file except in compliance with the License.
71867Sgjelinek  *
81867Sgjelinek  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91867Sgjelinek  * or http://www.opensolaris.org/os/licensing.
101867Sgjelinek  * See the License for the specific language governing permissions
111867Sgjelinek  * and limitations under the License.
121867Sgjelinek  *
131867Sgjelinek  * When distributing Covered Code, include this CDDL HEADER in each
141867Sgjelinek  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151867Sgjelinek  * If applicable, add the following below this CDDL HEADER, with the
161867Sgjelinek  * fields enclosed by brackets "[]" replaced with your own identifying
171867Sgjelinek  * information: Portions Copyright [yyyy] [name of copyright owner]
181867Sgjelinek  *
191867Sgjelinek  * CDDL HEADER END
201867Sgjelinek  */
211867Sgjelinek 
221867Sgjelinek /*
231867Sgjelinek  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
241867Sgjelinek  * Use is subject to license terms.
251867Sgjelinek  */
261867Sgjelinek 
271867Sgjelinek #pragma ident	"%Z%%M%	%I%	%E% SMI"
281867Sgjelinek 
291867Sgjelinek /*
301867Sgjelinek  * This file contains the functions used to support the ZFS integration
311867Sgjelinek  * with zones.  This includes validation (e.g. zonecfg dataset), cloning,
321867Sgjelinek  * file system creation and destruction.
331867Sgjelinek  */
341867Sgjelinek 
351867Sgjelinek #include <stdio.h>
361867Sgjelinek #include <errno.h>
371867Sgjelinek #include <unistd.h>
381867Sgjelinek #include <string.h>
391867Sgjelinek #include <locale.h>
401867Sgjelinek #include <libintl.h>
411867Sgjelinek #include <sys/stat.h>
421867Sgjelinek #include <sys/statvfs.h>
431867Sgjelinek #include <libgen.h>
441867Sgjelinek #include <libzonecfg.h>
451867Sgjelinek #include <sys/mnttab.h>
461867Sgjelinek #include <libzfs.h>
471867Sgjelinek 
481867Sgjelinek #include "zoneadm.h"
491867Sgjelinek 
502082Seschrock libzfs_handle_t *g_zfs;
511867Sgjelinek 
521867Sgjelinek typedef struct zfs_mount_data {
531867Sgjelinek 	char		*match_name;
541867Sgjelinek 	zfs_handle_t	*match_handle;
551867Sgjelinek } zfs_mount_data_t;
561867Sgjelinek 
571867Sgjelinek typedef struct zfs_snapshot_data {
581867Sgjelinek 	char	*match_name;
591867Sgjelinek 	int	len;
601867Sgjelinek 	int	max;
611867Sgjelinek } zfs_snapshot_data_t;
621867Sgjelinek 
631867Sgjelinek /*
641867Sgjelinek  * A ZFS file system iterator call-back function which is used to validate
651867Sgjelinek  * datasets imported into the zone.
661867Sgjelinek  */
671867Sgjelinek /* ARGSUSED */
681867Sgjelinek static int
691867Sgjelinek check_zvol(zfs_handle_t *zhp, void *unused)
701867Sgjelinek {
711867Sgjelinek 	int ret;
721867Sgjelinek 
731867Sgjelinek 	if (zfs_get_type(zhp) == ZFS_TYPE_VOLUME) {
741867Sgjelinek 		/*
751867Sgjelinek 		 * TRANSLATION_NOTE
761867Sgjelinek 		 * zfs and dataset are literals that should not be translated.
771867Sgjelinek 		 */
781867Sgjelinek 		(void) fprintf(stderr, gettext("cannot verify zfs dataset %s: "
791867Sgjelinek 		    "volumes cannot be specified as a zone dataset resource\n"),
801867Sgjelinek 		    zfs_get_name(zhp));
811867Sgjelinek 		ret = -1;
821867Sgjelinek 	} else {
831867Sgjelinek 		ret = zfs_iter_children(zhp, check_zvol, NULL);
841867Sgjelinek 	}
851867Sgjelinek 
861867Sgjelinek 	zfs_close(zhp);
871867Sgjelinek 
881867Sgjelinek 	return (ret);
891867Sgjelinek }
901867Sgjelinek 
911867Sgjelinek /*
921867Sgjelinek  * A ZFS file system iterator call-back function which returns the
931867Sgjelinek  * zfs_handle_t for a ZFS file system on the specified mount point.
941867Sgjelinek  */
951867Sgjelinek static int
961867Sgjelinek match_mountpoint(zfs_handle_t *zhp, void *data)
971867Sgjelinek {
981867Sgjelinek 	int			res;
991867Sgjelinek 	zfs_mount_data_t	*cbp;
1001867Sgjelinek 	char			mp[ZFS_MAXPROPLEN];
1011867Sgjelinek 
1021867Sgjelinek 	if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) {
1031867Sgjelinek 		zfs_close(zhp);
1041867Sgjelinek 		return (0);
1051867Sgjelinek 	}
1061867Sgjelinek 
1071867Sgjelinek 	cbp = (zfs_mount_data_t *)data;
1081867Sgjelinek 	if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mp, sizeof (mp), NULL, NULL,
1092082Seschrock 	    0, B_FALSE) == 0 && strcmp(mp, cbp->match_name) == 0) {
1101867Sgjelinek 		cbp->match_handle = zhp;
1111867Sgjelinek 		return (1);
1121867Sgjelinek 	}
1131867Sgjelinek 
1141867Sgjelinek 	res = zfs_iter_filesystems(zhp, match_mountpoint, data);
1151867Sgjelinek 	zfs_close(zhp);
1161867Sgjelinek 	return (res);
1171867Sgjelinek }
1181867Sgjelinek 
1191867Sgjelinek /*
1201867Sgjelinek  * Get ZFS handle for the specified mount point.
1211867Sgjelinek  */
1221867Sgjelinek static zfs_handle_t *
1231867Sgjelinek mount2zhandle(char *mountpoint)
1241867Sgjelinek {
1251867Sgjelinek 	zfs_mount_data_t	cb;
1261867Sgjelinek 
1271867Sgjelinek 	cb.match_name = mountpoint;
1281867Sgjelinek 	cb.match_handle = NULL;
1292082Seschrock 	(void) zfs_iter_root(g_zfs, match_mountpoint, &cb);
1301867Sgjelinek 	return (cb.match_handle);
1311867Sgjelinek }
1321867Sgjelinek 
1331867Sgjelinek /*
1341867Sgjelinek  * Check if there is already a file system (zfs or any other type) mounted on
1351867Sgjelinek  * path.
1361867Sgjelinek  */
1371867Sgjelinek static boolean_t
1381867Sgjelinek is_mountpnt(char *path)
1391867Sgjelinek {
1401867Sgjelinek 	FILE		*fp;
1411867Sgjelinek 	struct mnttab	entry;
1421867Sgjelinek 
1431867Sgjelinek 	if ((fp = fopen("/etc/mnttab", "r")) == NULL)
1441867Sgjelinek 		return (B_FALSE);
1451867Sgjelinek 
1461867Sgjelinek 	while (getmntent(fp, &entry) == 0) {
1471867Sgjelinek 		if (strcmp(path, entry.mnt_mountp) == 0) {
1481867Sgjelinek 			(void) fclose(fp);
1491867Sgjelinek 			return (B_TRUE);
1501867Sgjelinek 		}
1511867Sgjelinek 	}
1521867Sgjelinek 
1531867Sgjelinek 	(void) fclose(fp);
1541867Sgjelinek 	return (B_FALSE);
1551867Sgjelinek }
1561867Sgjelinek 
1571867Sgjelinek /*
1581867Sgjelinek  * Perform any necessary housekeeping tasks we need to do before we take
1591867Sgjelinek  * a ZFS snapshot of the zone.  What this really entails is that we are
1601867Sgjelinek  * taking a sw inventory of the source zone, like we do when we detach,
1611867Sgjelinek  * so that there is the XML manifest in the snapshot.  We use that to
1621867Sgjelinek  * validate the snapshot if it is the source of a clone at some later time.
1631867Sgjelinek  */
1641867Sgjelinek static int
1651867Sgjelinek pre_snapshot(char *source_zone)
1661867Sgjelinek {
1671867Sgjelinek 	int err;
1681867Sgjelinek 	zone_dochandle_t handle;
1691867Sgjelinek 
1701867Sgjelinek 	if ((handle = zonecfg_init_handle()) == NULL) {
1711867Sgjelinek 		zperror(cmd_to_str(CMD_CLONE), B_TRUE);
1721867Sgjelinek 		return (Z_ERR);
1731867Sgjelinek 	}
1741867Sgjelinek 
1751867Sgjelinek 	if ((err = zonecfg_get_handle(source_zone, handle)) != Z_OK) {
1761867Sgjelinek 		errno = err;
1771867Sgjelinek 		zperror(cmd_to_str(CMD_CLONE), B_TRUE);
1781867Sgjelinek 		zonecfg_fini_handle(handle);
1791867Sgjelinek 		return (Z_ERR);
1801867Sgjelinek 	}
1811867Sgjelinek 
1821867Sgjelinek 	if ((err = zonecfg_get_detach_info(handle, B_TRUE)) != Z_OK) {
1831867Sgjelinek 		errno = err;
1841867Sgjelinek 		zperror(gettext("getting the software version information "
1851867Sgjelinek 		    "failed"), B_TRUE);
1861867Sgjelinek 		zonecfg_fini_handle(handle);
1871867Sgjelinek 		return (Z_ERR);
1881867Sgjelinek 	}
1891867Sgjelinek 
1902078Sgjelinek 	if ((err = zonecfg_detach_save(handle, 0)) != Z_OK) {
1911867Sgjelinek 		errno = err;
1921867Sgjelinek 		zperror(gettext("saving the software version manifest failed"),
1931867Sgjelinek 		    B_TRUE);
1941867Sgjelinek 		zonecfg_fini_handle(handle);
1951867Sgjelinek 		return (Z_ERR);
1961867Sgjelinek 	}
1971867Sgjelinek 
1981867Sgjelinek 	zonecfg_fini_handle(handle);
1991867Sgjelinek 	return (Z_OK);
2001867Sgjelinek }
2011867Sgjelinek 
2021867Sgjelinek /*
2031867Sgjelinek  * Perform any necessary housekeeping tasks we need to do after we take
2041867Sgjelinek  * a ZFS snapshot of the zone.  What this really entails is removing the
2051867Sgjelinek  * sw inventory XML file from the zone.  It is still in the snapshot where
2061867Sgjelinek  * we want it, but we don't want it in the source zone itself.
2071867Sgjelinek  */
2081867Sgjelinek static int
2091867Sgjelinek post_snapshot(char *source_zone)
2101867Sgjelinek {
2111867Sgjelinek 	int err;
2121867Sgjelinek 	zone_dochandle_t handle;
2131867Sgjelinek 
2141867Sgjelinek 	if ((handle = zonecfg_init_handle()) == NULL) {
2151867Sgjelinek 		zperror(cmd_to_str(CMD_CLONE), B_TRUE);
2161867Sgjelinek 		return (Z_ERR);
2171867Sgjelinek 	}
2181867Sgjelinek 
2191867Sgjelinek 	if ((err = zonecfg_get_handle(source_zone, handle)) != Z_OK) {
2201867Sgjelinek 		errno = err;
2211867Sgjelinek 		zperror(cmd_to_str(CMD_CLONE), B_TRUE);
2221867Sgjelinek 		zonecfg_fini_handle(handle);
2231867Sgjelinek 		return (Z_ERR);
2241867Sgjelinek 	}
2251867Sgjelinek 
2261867Sgjelinek 	zonecfg_rm_detached(handle, B_FALSE);
2271867Sgjelinek 	zonecfg_fini_handle(handle);
2281867Sgjelinek 
2291867Sgjelinek 	return (Z_OK);
2301867Sgjelinek }
2311867Sgjelinek 
2321867Sgjelinek /*
2331867Sgjelinek  * This is a ZFS snapshot iterator call-back function which returns the
2341867Sgjelinek  * highest number of SUNWzone snapshots that have been taken.
2351867Sgjelinek  */
2361867Sgjelinek static int
2371867Sgjelinek get_snap_max(zfs_handle_t *zhp, void *data)
2381867Sgjelinek {
2391867Sgjelinek 	int			res;
2401867Sgjelinek 	zfs_snapshot_data_t	*cbp;
2411867Sgjelinek 
2421867Sgjelinek 	if (zfs_get_type(zhp) != ZFS_TYPE_SNAPSHOT) {
2431867Sgjelinek 		zfs_close(zhp);
2441867Sgjelinek 		return (0);
2451867Sgjelinek 	}
2461867Sgjelinek 
2471867Sgjelinek 	cbp = (zfs_snapshot_data_t *)data;
2481867Sgjelinek 
2491867Sgjelinek 	if (strncmp(zfs_get_name(zhp), cbp->match_name, cbp->len) == 0) {
2501867Sgjelinek 		char	*nump;
2511867Sgjelinek 		int	num;
2521867Sgjelinek 
2531867Sgjelinek 		nump = (char *)(zfs_get_name(zhp) + cbp->len);
2541867Sgjelinek 		num = atoi(nump);
2551867Sgjelinek 		if (num > cbp->max)
2561867Sgjelinek 			cbp->max = num;
2571867Sgjelinek 	}
2581867Sgjelinek 
2591867Sgjelinek 	res = zfs_iter_snapshots(zhp, get_snap_max, data);
2601867Sgjelinek 	zfs_close(zhp);
2611867Sgjelinek 	return (res);
2621867Sgjelinek }
2631867Sgjelinek 
2641867Sgjelinek /*
2651867Sgjelinek  * Take a ZFS snapshot to be used for cloning the zone.
2661867Sgjelinek  */
2671867Sgjelinek static int
2681867Sgjelinek take_snapshot(char *source_zone, zfs_handle_t *zhp, char *snapshot_name,
2691867Sgjelinek     int snap_size)
2701867Sgjelinek {
2711867Sgjelinek 	int			res;
2721867Sgjelinek 	char			template[ZFS_MAXNAMELEN];
2731867Sgjelinek 	zfs_snapshot_data_t	cb;
2741867Sgjelinek 
2751867Sgjelinek 	/*
2761867Sgjelinek 	 * First we need to figure out the next available name for the
2771867Sgjelinek 	 * zone snapshot.  Look through the list of zones snapshots for
2781867Sgjelinek 	 * this file system to determine the maximum snapshot name.
2791867Sgjelinek 	 */
2801867Sgjelinek 	if (snprintf(template, sizeof (template), "%s@SUNWzone",
2811867Sgjelinek 	    zfs_get_name(zhp)) >=  sizeof (template))
2821867Sgjelinek 		return (Z_ERR);
2831867Sgjelinek 
2841867Sgjelinek 	cb.match_name = template;
2851867Sgjelinek 	cb.len = strlen(template);
2861867Sgjelinek 	cb.max = 0;
2871867Sgjelinek 
2881867Sgjelinek 	if (zfs_iter_snapshots(zhp, get_snap_max, &cb) != 0)
2891867Sgjelinek 		return (Z_ERR);
2901867Sgjelinek 
2911867Sgjelinek 	cb.max++;
2921867Sgjelinek 
2931867Sgjelinek 	if (snprintf(snapshot_name, snap_size, "%s@SUNWzone%d",
2941867Sgjelinek 	    zfs_get_name(zhp), cb.max) >= snap_size)
2951867Sgjelinek 		return (Z_ERR);
2961867Sgjelinek 
2971867Sgjelinek 	if (pre_snapshot(source_zone) != Z_OK)
2981867Sgjelinek 		return (Z_ERR);
299*2199Sahrens 	res = zfs_snapshot(g_zfs, snapshot_name, B_FALSE);
3001867Sgjelinek 	if (post_snapshot(source_zone) != Z_OK)
3011867Sgjelinek 		return (Z_ERR);
3021867Sgjelinek 
3031867Sgjelinek 	if (res != 0)
3041867Sgjelinek 		return (Z_ERR);
3051867Sgjelinek 	return (Z_OK);
3061867Sgjelinek }
3071867Sgjelinek 
3081867Sgjelinek /*
3091867Sgjelinek  * We are using an explicit snapshot from some earlier point in time so
3101867Sgjelinek  * we need to validate it.  This involves checking the sw inventory that
3111867Sgjelinek  * we took when we made the snapshot to verify that the current sw config
3121867Sgjelinek  * on the host is still valid to run a zone made from this snapshot.
3131867Sgjelinek  */
3141867Sgjelinek static int
3151867Sgjelinek validate_snapshot(char *snapshot_name, char *snap_path)
3161867Sgjelinek {
3171867Sgjelinek 	int err;
3181867Sgjelinek 	zone_dochandle_t handle;
3191867Sgjelinek 	zone_dochandle_t athandle = NULL;
3201867Sgjelinek 
3211867Sgjelinek 	if ((handle = zonecfg_init_handle()) == NULL) {
3221867Sgjelinek 		zperror(cmd_to_str(CMD_CLONE), B_TRUE);
3231867Sgjelinek 		return (Z_ERR);
3241867Sgjelinek 	}
3251867Sgjelinek 
3261867Sgjelinek 	if ((err = zonecfg_get_handle(target_zone, handle)) != Z_OK) {
3271867Sgjelinek 		errno = err;
3281867Sgjelinek 		zperror(cmd_to_str(CMD_CLONE), B_TRUE);
3291867Sgjelinek 		zonecfg_fini_handle(handle);
3301867Sgjelinek 		return (Z_ERR);
3311867Sgjelinek 	}
3321867Sgjelinek 
3331867Sgjelinek 	if ((athandle = zonecfg_init_handle()) == NULL) {
3341867Sgjelinek 		zperror(cmd_to_str(CMD_CLONE), B_TRUE);
3351867Sgjelinek 		goto done;
3361867Sgjelinek 	}
3371867Sgjelinek 
3381867Sgjelinek 	if ((err = zonecfg_get_attach_handle(snap_path, target_zone, B_TRUE,
3391867Sgjelinek 	    athandle)) != Z_OK) {
3401867Sgjelinek 		if (err == Z_NO_ZONE)
3411867Sgjelinek 			(void) fprintf(stderr, gettext("snapshot %s was not "
3421867Sgjelinek 			    "taken\n\tby a 'zoneadm clone' command.  It can "
3431867Sgjelinek 			    "not be used to clone zones.\n"), snapshot_name);
3441867Sgjelinek 		else
3451867Sgjelinek 			(void) fprintf(stderr, gettext("snapshot %s is "
3461867Sgjelinek 			    "out-dated\n\tIt can no longer be used to clone "
3471867Sgjelinek 			    "zones on this system.\n"), snapshot_name);
3481867Sgjelinek 		goto done;
3491867Sgjelinek 	}
3501867Sgjelinek 
3511867Sgjelinek 	/* Get the detach information for the locally defined zone. */
3521867Sgjelinek 	if ((err = zonecfg_get_detach_info(handle, B_FALSE)) != Z_OK) {
3531867Sgjelinek 		errno = err;
3541867Sgjelinek 		zperror(gettext("getting the attach information failed"),
3551867Sgjelinek 		    B_TRUE);
3561867Sgjelinek 		goto done;
3571867Sgjelinek 	}
3581867Sgjelinek 
3591867Sgjelinek 	if ((err = sw_cmp(handle, athandle, SW_CMP_SILENT)) != Z_OK)
3601867Sgjelinek 		(void) fprintf(stderr, gettext("snapshot %s is out-dated\n\t"
3611867Sgjelinek 		    "It can no longer be used to clone zones on this "
3621867Sgjelinek 		    "system.\n"), snapshot_name);
3631867Sgjelinek 
3641867Sgjelinek done:
3651867Sgjelinek 	zonecfg_fini_handle(handle);
3661867Sgjelinek 	if (athandle != NULL)
3671867Sgjelinek 		zonecfg_fini_handle(athandle);
3681867Sgjelinek 
3691867Sgjelinek 	return (err);
3701867Sgjelinek }
3711867Sgjelinek 
3721867Sgjelinek /*
3731867Sgjelinek  * Remove the sw inventory file from inside this zonepath that we picked up out
3741867Sgjelinek  * of the snapshot.
3751867Sgjelinek  */
3761867Sgjelinek static int
3771867Sgjelinek clean_out_clone()
3781867Sgjelinek {
3791867Sgjelinek 	int err;
3801867Sgjelinek 	zone_dochandle_t handle;
3811867Sgjelinek 
3821867Sgjelinek 	if ((handle = zonecfg_init_handle()) == NULL) {
3831867Sgjelinek 		zperror(cmd_to_str(CMD_CLONE), B_TRUE);
3841867Sgjelinek 		return (Z_ERR);
3851867Sgjelinek 	}
3861867Sgjelinek 
3871867Sgjelinek 	if ((err = zonecfg_get_handle(target_zone, handle)) != Z_OK) {
3881867Sgjelinek 		errno = err;
3891867Sgjelinek 		zperror(cmd_to_str(CMD_CLONE), B_TRUE);
3901867Sgjelinek 		zonecfg_fini_handle(handle);
3911867Sgjelinek 		return (Z_ERR);
3921867Sgjelinek 	}
3931867Sgjelinek 
3941867Sgjelinek 	zonecfg_rm_detached(handle, B_FALSE);
3951867Sgjelinek 	zonecfg_fini_handle(handle);
3961867Sgjelinek 
3971867Sgjelinek 	return (Z_OK);
3981867Sgjelinek }
3991867Sgjelinek 
4001867Sgjelinek /*
4011867Sgjelinek  * Make a ZFS clone on zonepath from snapshot_name.
4021867Sgjelinek  */
4031867Sgjelinek static int
4041867Sgjelinek clone_snap(char *snapshot_name, char *zonepath)
4051867Sgjelinek {
4061867Sgjelinek 	int		res = Z_OK;
4071867Sgjelinek 	int		err;
4081867Sgjelinek 	zfs_handle_t	*zhp;
4091867Sgjelinek 	zfs_handle_t	*clone;
4101867Sgjelinek 
4112082Seschrock 	if ((zhp = zfs_open(g_zfs, snapshot_name, ZFS_TYPE_SNAPSHOT)) == NULL)
4121867Sgjelinek 		return (Z_NO_ENTRY);
4131867Sgjelinek 
4141867Sgjelinek 	(void) printf(gettext("Cloning snapshot %s\n"), snapshot_name);
4151867Sgjelinek 
4161867Sgjelinek 	err = zfs_clone(zhp, zonepath);
4171867Sgjelinek 	zfs_close(zhp);
4181867Sgjelinek 	if (err != 0)
4191867Sgjelinek 		return (Z_ERR);
4201867Sgjelinek 
4211867Sgjelinek 	/* create the mountpoint if necessary */
4222082Seschrock 	if ((clone = zfs_open(g_zfs, zonepath, ZFS_TYPE_ANY)) == NULL)
4231867Sgjelinek 		return (Z_ERR);
4241867Sgjelinek 
4251867Sgjelinek 	/*
4261867Sgjelinek 	 * The clone has been created so we need to print a diagnostic
4271867Sgjelinek 	 * message if one of the following steps fails for some reason.
4281867Sgjelinek 	 */
4291867Sgjelinek 	if (zfs_mount(clone, NULL, 0) != 0) {
4301867Sgjelinek 		(void) fprintf(stderr, gettext("could not mount ZFS clone "
4311867Sgjelinek 		    "%s\n"), zfs_get_name(clone));
4321867Sgjelinek 		res = Z_ERR;
4331867Sgjelinek 
4341867Sgjelinek 	} else {
4351867Sgjelinek 		if (zfs_prop_set(clone, ZFS_PROP_SHARENFS, "off") != 0) {
4361867Sgjelinek 			/* we won't consider this a failure */
4371867Sgjelinek 			(void) fprintf(stderr, gettext("could not turn off the "
4381867Sgjelinek 			    "'sharenfs' property on ZFS clone %s\n"),
4391867Sgjelinek 			    zfs_get_name(clone));
4401867Sgjelinek 		}
4411867Sgjelinek 
4421867Sgjelinek 		if (clean_out_clone() != Z_OK) {
4431867Sgjelinek 			(void) fprintf(stderr, gettext("could not remove the "
4441867Sgjelinek 			    "software inventory from ZFS clone %s\n"),
4451867Sgjelinek 			    zfs_get_name(clone));
4461867Sgjelinek 			res = Z_ERR;
4471867Sgjelinek 		}
4481867Sgjelinek 	}
4491867Sgjelinek 
4501867Sgjelinek 	zfs_close(clone);
4511867Sgjelinek 	return (res);
4521867Sgjelinek }
4531867Sgjelinek 
4541867Sgjelinek /*
4551867Sgjelinek  * This function takes a zonepath and attempts to determine what the ZFS
4561867Sgjelinek  * file system name (not mountpoint) should be for that path.  We do not
4571867Sgjelinek  * assume that zonepath is an existing directory or ZFS fs since we use
4581867Sgjelinek  * this function as part of the process of creating a new ZFS fs or clone.
4591867Sgjelinek  *
4601867Sgjelinek  * The way this works is that we look at the parent directory of the zonepath
4611867Sgjelinek  * to see if it is a ZFS fs.  If it is, we get the name of that ZFS fs and
4621867Sgjelinek  * append the last component of the zonepath to generate the ZFS name for the
4631867Sgjelinek  * zonepath.  This matches the algorithm that ZFS uses for automatically
4641867Sgjelinek  * mounting a new fs after it is created.
4651867Sgjelinek  *
4661867Sgjelinek  * Although a ZFS fs can be mounted anywhere, we don't worry about handling
4671867Sgjelinek  * all of the complexity that a user could possibly configure with arbitrary
4681867Sgjelinek  * mounts since there is no way to generate a ZFS name from a random path in
4691867Sgjelinek  * the file system.  We only try to handle the automatic mounts that ZFS does
4701867Sgjelinek  * for each file system.  ZFS restricts this so that a new fs must be created
4711867Sgjelinek  * in an existing parent ZFS fs.  It then automatically mounts the new fs
4721867Sgjelinek  * directly under the mountpoint for the parent fs using the last component
4731867Sgjelinek  * of the name as the mountpoint directory.
4741867Sgjelinek  *
4751867Sgjelinek  * For example:
4761867Sgjelinek  *    Name			Mountpoint
4771867Sgjelinek  *    space/eng/dev/test/zone1	/project1/eng/dev/test/zone1
4781867Sgjelinek  *
4791867Sgjelinek  * Return Z_OK if the path mapped to a ZFS file system name, otherwise return
4801867Sgjelinek  * Z_ERR.
4811867Sgjelinek  */
4821867Sgjelinek static int
4831867Sgjelinek path2name(char *zonepath, char *zfs_name, int len)
4841867Sgjelinek {
4851867Sgjelinek 	int		res;
4861867Sgjelinek 	char		*p;
4871867Sgjelinek 	zfs_handle_t	*zhp;
4881867Sgjelinek 
4891867Sgjelinek 	if ((p = strrchr(zonepath, '/')) == NULL)
4901867Sgjelinek 		return (Z_ERR);
4911867Sgjelinek 
4921867Sgjelinek 	/*
4931867Sgjelinek 	 * If the parent directory is not its own ZFS fs, then we can't
4941867Sgjelinek 	 * automatically create a new ZFS fs at the 'zonepath' mountpoint
4951867Sgjelinek 	 * so return an error.
4961867Sgjelinek 	 */
4971867Sgjelinek 	*p = '\0';
4981867Sgjelinek 	zhp = mount2zhandle(zonepath);
4991867Sgjelinek 	*p = '/';
5001867Sgjelinek 	if (zhp == NULL)
5011867Sgjelinek 		return (Z_ERR);
5021867Sgjelinek 
5031867Sgjelinek 	res = snprintf(zfs_name, len, "%s/%s", zfs_get_name(zhp), p + 1);
5041867Sgjelinek 
5051867Sgjelinek 	zfs_close(zhp);
5061867Sgjelinek 	if (res >= len)
5071867Sgjelinek 		return (Z_ERR);
5081867Sgjelinek 
5091867Sgjelinek 	return (Z_OK);
5101867Sgjelinek }
5111867Sgjelinek 
5121867Sgjelinek /*
5131867Sgjelinek  * A ZFS file system iterator call-back function used to determine if the
5141867Sgjelinek  * file system has dependents (snapshots & clones).
5151867Sgjelinek  */
5161867Sgjelinek /* ARGSUSED */
5171867Sgjelinek static int
5181867Sgjelinek has_dependent(zfs_handle_t *zhp, void *data)
5191867Sgjelinek {
5201867Sgjelinek 	zfs_close(zhp);
5211867Sgjelinek 	return (1);
5221867Sgjelinek }
5231867Sgjelinek 
5241867Sgjelinek /*
5251867Sgjelinek  * Given a snapshot name, get the file system path where the snapshot lives.
5261867Sgjelinek  * A snapshot name is of the form fs_name@snap_name.  For example, snapshot
5271867Sgjelinek  * pl/zones/z1@SUNWzone1 would have a path of
5281867Sgjelinek  * /pl/zones/z1/.zfs/snapshot/SUNWzone1.
5291867Sgjelinek  */
5301867Sgjelinek static int
5311867Sgjelinek snap2path(char *snap_name, char *path, int len)
5321867Sgjelinek {
5331867Sgjelinek 	char		*p;
5341867Sgjelinek 	zfs_handle_t	*zhp;
5351867Sgjelinek 	char		mp[ZFS_MAXPROPLEN];
5361867Sgjelinek 
5371867Sgjelinek 	if ((p = strrchr(snap_name, '@')) == NULL)
5381867Sgjelinek 		return (Z_ERR);
5391867Sgjelinek 
5401867Sgjelinek 	/* Get the file system name from the snap_name. */
5411867Sgjelinek 	*p = '\0';
5422082Seschrock 	zhp = zfs_open(g_zfs, snap_name, ZFS_TYPE_ANY);
5431867Sgjelinek 	*p = '@';
5441867Sgjelinek 	if (zhp == NULL)
5451867Sgjelinek 		return (Z_ERR);
5461867Sgjelinek 
5471867Sgjelinek 	/* Get the file system mount point. */
5481867Sgjelinek 	if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mp, sizeof (mp), NULL, NULL,
5492082Seschrock 	    0, B_FALSE) != 0) {
5501867Sgjelinek 		zfs_close(zhp);
5511867Sgjelinek 		return (Z_ERR);
5521867Sgjelinek 	}
5531867Sgjelinek 	zfs_close(zhp);
5541867Sgjelinek 
5551867Sgjelinek 	p++;
5561867Sgjelinek 	if (snprintf(path, len, "%s/.zfs/snapshot/%s", mp, p) >= len)
5571867Sgjelinek 		return (Z_ERR);
5581867Sgjelinek 
5591867Sgjelinek 	return (Z_OK);
5601867Sgjelinek }
5611867Sgjelinek 
5621867Sgjelinek /*
5631867Sgjelinek  * Clone a pre-existing ZFS snapshot, either by making a direct ZFS clone, if
5641867Sgjelinek  * possible, or by copying the data from the snapshot to the zonepath.
5651867Sgjelinek  */
5661867Sgjelinek int
5671867Sgjelinek clone_snapshot_zfs(char *snap_name, char *zonepath)
5681867Sgjelinek {
5691867Sgjelinek 	int	err = Z_OK;
5701867Sgjelinek 	char	clone_name[MAXPATHLEN];
5711867Sgjelinek 	char	snap_path[MAXPATHLEN];
5721867Sgjelinek 
5731867Sgjelinek 	if (snap2path(snap_name, snap_path, sizeof (snap_path)) != Z_OK) {
5741867Sgjelinek 		(void) fprintf(stderr, gettext("unable to find path for %s.\n"),
5751867Sgjelinek 		    snap_name);
5761867Sgjelinek 		return (Z_ERR);
5771867Sgjelinek 	}
5781867Sgjelinek 
5791867Sgjelinek 	if (validate_snapshot(snap_name, snap_path) != Z_OK)
5801867Sgjelinek 		return (Z_NO_ENTRY);
5811867Sgjelinek 
5821867Sgjelinek 	/*
5831867Sgjelinek 	 * The zonepath cannot be ZFS cloned, try to copy the data from
5841867Sgjelinek 	 * within the snapshot to the zonepath.
5851867Sgjelinek 	 */
5861867Sgjelinek 	if (path2name(zonepath, clone_name, sizeof (clone_name)) != Z_OK) {
5871867Sgjelinek 		if ((err = clone_copy(snap_path, zonepath)) == Z_OK)
5881867Sgjelinek 			if (clean_out_clone() != Z_OK)
5891867Sgjelinek 				(void) fprintf(stderr,
5901867Sgjelinek 				    gettext("could not remove the "
5911867Sgjelinek 				    "software inventory from %s\n"), zonepath);
5921867Sgjelinek 
5931867Sgjelinek 		return (err);
5941867Sgjelinek 	}
5951867Sgjelinek 
5961867Sgjelinek 	if ((err = clone_snap(snap_name, clone_name)) != Z_OK) {
5971867Sgjelinek 		if (err != Z_NO_ENTRY) {
5981867Sgjelinek 			/*
5991867Sgjelinek 			 * Cloning the snapshot failed.  Fall back to trying
6001867Sgjelinek 			 * to install the zone by copying from the snapshot.
6011867Sgjelinek 			 */
6021867Sgjelinek 			if ((err = clone_copy(snap_path, zonepath)) == Z_OK)
6031867Sgjelinek 				if (clean_out_clone() != Z_OK)
6041867Sgjelinek 					(void) fprintf(stderr,
6051867Sgjelinek 					    gettext("could not remove the "
6061867Sgjelinek 					    "software inventory from %s\n"),
6071867Sgjelinek 					    zonepath);
6081867Sgjelinek 		} else {
6091867Sgjelinek 			/*
6101867Sgjelinek 			 * The snapshot is unusable for some reason so restore
6111867Sgjelinek 			 * the zone state to configured since we were unable to
6121867Sgjelinek 			 * actually do anything about getting the zone
6131867Sgjelinek 			 * installed.
6141867Sgjelinek 			 */
6151867Sgjelinek 			int tmp;
6161867Sgjelinek 
6171867Sgjelinek 			if ((tmp = zone_set_state(target_zone,
6181867Sgjelinek 			    ZONE_STATE_CONFIGURED)) != Z_OK) {
6191867Sgjelinek 				errno = tmp;
6201867Sgjelinek 				zperror2(target_zone,
6211867Sgjelinek 				    gettext("could not set state"));
6221867Sgjelinek 			}
6231867Sgjelinek 		}
6241867Sgjelinek 	}
6251867Sgjelinek 
6261867Sgjelinek 	return (err);
6271867Sgjelinek }
6281867Sgjelinek 
6291867Sgjelinek /*
6301867Sgjelinek  * Attempt to clone a source_zone to a target zonepath by using a ZFS clone.
6311867Sgjelinek  */
6321867Sgjelinek int
6331867Sgjelinek clone_zfs(char *source_zone, char *source_zonepath, char *zonepath)
6341867Sgjelinek {
6351867Sgjelinek 	zfs_handle_t	*zhp;
6361867Sgjelinek 	char		clone_name[MAXPATHLEN];
6371867Sgjelinek 	char		snap_name[MAXPATHLEN];
6381867Sgjelinek 
6391867Sgjelinek 	/*
6401867Sgjelinek 	 * Try to get a zfs handle for the source_zonepath.  If this fails
6411867Sgjelinek 	 * the source_zonepath is not ZFS so return an error.
6421867Sgjelinek 	 */
6431867Sgjelinek 	if ((zhp = mount2zhandle(source_zonepath)) == NULL)
6441867Sgjelinek 		return (Z_ERR);
6451867Sgjelinek 
6461867Sgjelinek 	/*
6471867Sgjelinek 	 * Check if there is a file system already mounted on zonepath.  If so,
6481867Sgjelinek 	 * we can't clone to the path so we should fall back to copying.
6491867Sgjelinek 	 */
6501867Sgjelinek 	if (is_mountpnt(zonepath)) {
6511867Sgjelinek 		zfs_close(zhp);
6521867Sgjelinek 		(void) fprintf(stderr,
6531867Sgjelinek 		    gettext("A file system is already mounted on %s,\n"
6541867Sgjelinek 		    "preventing use of a ZFS clone.\n"), zonepath);
6551867Sgjelinek 		return (Z_ERR);
6561867Sgjelinek 	}
6571867Sgjelinek 
6581867Sgjelinek 	/*
6591867Sgjelinek 	 * Instead of using path2name to get the clone name from the zonepath,
6601867Sgjelinek 	 * we could generate a name from the source zone ZFS name.  However,
6611867Sgjelinek 	 * this would mean we would create the clone under the ZFS fs of the
6621867Sgjelinek 	 * source instead of what the zonepath says.  For example,
6631867Sgjelinek 	 *
6641867Sgjelinek 	 * source_zonepath		zonepath
6651867Sgjelinek 	 * /pl/zones/dev/z1		/pl/zones/deploy/z2
6661867Sgjelinek 	 *
6671867Sgjelinek 	 * We don't want the clone to be under "dev", we want it under
6681867Sgjelinek 	 * "deploy", so that we can leverage the normal attribute inheritance
6691867Sgjelinek 	 * that ZFS provides in the fs hierarchy.
6701867Sgjelinek 	 */
6711867Sgjelinek 	if (path2name(zonepath, clone_name, sizeof (clone_name)) != Z_OK) {
6721867Sgjelinek 		zfs_close(zhp);
6731867Sgjelinek 		return (Z_ERR);
6741867Sgjelinek 	}
6751867Sgjelinek 
6761867Sgjelinek 	if (take_snapshot(source_zone, zhp, snap_name, sizeof (snap_name))
6771867Sgjelinek 	    != Z_OK) {
6781867Sgjelinek 		zfs_close(zhp);
6791867Sgjelinek 		return (Z_ERR);
6801867Sgjelinek 	}
6811867Sgjelinek 	zfs_close(zhp);
6821867Sgjelinek 
6831867Sgjelinek 	if (clone_snap(snap_name, clone_name) != Z_OK)
6841867Sgjelinek 		return (Z_ERR);
6851867Sgjelinek 
6861867Sgjelinek 	(void) printf(gettext("Instead of copying, a ZFS clone has been "
6871867Sgjelinek 	    "created for this zone.\n"));
6881867Sgjelinek 
6891867Sgjelinek 	return (Z_OK);
6901867Sgjelinek }
6911867Sgjelinek 
6921867Sgjelinek /*
6931867Sgjelinek  * Attempt to create a ZFS file system for the specified zonepath.
6941867Sgjelinek  * We either will successfully create a ZFS file system and get it mounted
6951867Sgjelinek  * on the zonepath or we don't.  The caller doesn't care since a regular
6961867Sgjelinek  * directory is used for the zonepath if no ZFS file system is mounted there.
6971867Sgjelinek  */
6981867Sgjelinek void
6991867Sgjelinek create_zfs_zonepath(char *zonepath)
7001867Sgjelinek {
7011867Sgjelinek 	zfs_handle_t	*zhp;
7021867Sgjelinek 	char		zfs_name[MAXPATHLEN];
7031867Sgjelinek 
7041867Sgjelinek 	if (path2name(zonepath, zfs_name, sizeof (zfs_name)) != Z_OK)
7051867Sgjelinek 		return;
7061867Sgjelinek 
7072082Seschrock 	if (zfs_create(g_zfs, zfs_name, ZFS_TYPE_FILESYSTEM, NULL, NULL) != 0 ||
7082082Seschrock 	    (zhp = zfs_open(g_zfs, zfs_name, ZFS_TYPE_ANY)) == NULL) {
7092082Seschrock 		(void) fprintf(stderr, gettext("cannot create ZFS dataset %s: "
7102082Seschrock 		    "%s\n"), zfs_name, libzfs_error_description(g_zfs));
7111867Sgjelinek 		return;
7121867Sgjelinek 	}
7131867Sgjelinek 
7141867Sgjelinek 	if (zfs_mount(zhp, NULL, 0) != 0) {
7152082Seschrock 		(void) fprintf(stderr, gettext("cannot mount ZFS dataset %s: "
7162082Seschrock 		    "%s\n"), zfs_name, libzfs_error_description(g_zfs));
7171867Sgjelinek 		(void) zfs_destroy(zhp);
7181867Sgjelinek 	} else if (zfs_prop_set(zhp, ZFS_PROP_SHARENFS, "off") != 0) {
7191867Sgjelinek 		(void) fprintf(stderr, gettext("file system %s successfully "
7201867Sgjelinek 		    "created,\nbut could not turn off the 'sharenfs' "
7211867Sgjelinek 		    "property\n"), zfs_name);
7221867Sgjelinek 	} else {
7231867Sgjelinek 		if (chmod(zonepath, S_IRWXU) != 0) {
7241867Sgjelinek 			(void) fprintf(stderr, gettext("file system %s "
7251867Sgjelinek 			    "successfully created, but chmod %o failed: %s\n"),
7261867Sgjelinek 			    zfs_name, S_IRWXU, strerror(errno));
7271867Sgjelinek 			(void) destroy_zfs(zonepath);
7281867Sgjelinek 		} else {
7291867Sgjelinek 			(void) printf(gettext("A ZFS file system has been "
7301867Sgjelinek 			    "created for this zone.\n"));
7311867Sgjelinek 		}
7321867Sgjelinek 	}
7331867Sgjelinek 
7341867Sgjelinek 	zfs_close(zhp);
7351867Sgjelinek }
7361867Sgjelinek 
7371867Sgjelinek /*
7381867Sgjelinek  * If the zonepath is a ZFS file system, attempt to destroy it.  We return Z_OK
7391867Sgjelinek  * if we were able to zfs_destroy the zonepath, otherwise we return Z_ERR
7401867Sgjelinek  * which means the caller should clean up the zonepath in the traditional
7411867Sgjelinek  * way.
7421867Sgjelinek  */
7431867Sgjelinek int
7441867Sgjelinek destroy_zfs(char *zonepath)
7451867Sgjelinek {
7461867Sgjelinek 	zfs_handle_t	*zhp;
7471867Sgjelinek 	boolean_t	is_clone = B_FALSE;
7481867Sgjelinek 	char		origin[ZFS_MAXPROPLEN];
7491867Sgjelinek 
7502082Seschrock 	if ((zhp = mount2zhandle(zonepath)) == NULL)
7511867Sgjelinek 		return (Z_ERR);
7521867Sgjelinek 
7531867Sgjelinek 	/*
7541867Sgjelinek 	 * We can't destroy the file system if it has dependents.
7551867Sgjelinek 	 */
7561867Sgjelinek 	if (zfs_iter_dependents(zhp, has_dependent, NULL) != 0 ||
7571867Sgjelinek 	    zfs_unmount(zhp, NULL, 0) != 0) {
7581867Sgjelinek 		zfs_close(zhp);
7591867Sgjelinek 		return (Z_ERR);
7601867Sgjelinek 	}
7611867Sgjelinek 
7621867Sgjelinek 	/*
7631867Sgjelinek 	 * This might be a clone.  Try to get the snapshot so we can attempt
7641867Sgjelinek 	 * to destroy that as well.
7651867Sgjelinek 	 */
7661867Sgjelinek 	if (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, origin, sizeof (origin), NULL,
7672082Seschrock 	    NULL, 0, B_FALSE) == 0)
7681867Sgjelinek 		is_clone = B_TRUE;
7691867Sgjelinek 
7701867Sgjelinek 	if (zfs_destroy(zhp) != 0) {
7711867Sgjelinek 		/*
7721867Sgjelinek 		 * If the destroy fails for some reason, try to remount
7731867Sgjelinek 		 * the file system so that we can use "rm -rf" to clean up
7741867Sgjelinek 		 * instead.
7751867Sgjelinek 		 */
7761867Sgjelinek 		(void) zfs_mount(zhp, NULL, 0);
7771867Sgjelinek 		zfs_close(zhp);
7781867Sgjelinek 		return (Z_ERR);
7791867Sgjelinek 	}
7801867Sgjelinek 
7811867Sgjelinek 	(void) printf(gettext("The ZFS file system for this zone has been "
7821867Sgjelinek 	    "destroyed.\n"));
7831867Sgjelinek 
7841867Sgjelinek 	if (is_clone) {
7851867Sgjelinek 		zfs_handle_t	*ohp;
7861867Sgjelinek 
7871867Sgjelinek 		/*
7881867Sgjelinek 		 * Try to clean up the snapshot that the clone was taken from.
7891867Sgjelinek 		 */
7902082Seschrock 		if ((ohp = zfs_open(g_zfs, origin,
7912082Seschrock 		    ZFS_TYPE_SNAPSHOT)) != NULL) {
7921867Sgjelinek 			if (zfs_iter_dependents(ohp, has_dependent, NULL)
7932082Seschrock 			    == 0 && zfs_unmount(ohp, NULL, 0) == 0)
7941867Sgjelinek 				(void) zfs_destroy(ohp);
7951867Sgjelinek 			zfs_close(ohp);
7961867Sgjelinek 		}
7971867Sgjelinek 	}
7981867Sgjelinek 
7991867Sgjelinek 	zfs_close(zhp);
8001867Sgjelinek 	return (Z_OK);
8011867Sgjelinek }
8021867Sgjelinek 
8031867Sgjelinek /*
8041867Sgjelinek  * Return true if the path is its own zfs file system.  We determine this
8051867Sgjelinek  * by stat-ing the path to see if it is zfs and stat-ing the parent to see
8061867Sgjelinek  * if it is a different fs.
8071867Sgjelinek  */
8081867Sgjelinek boolean_t
8091867Sgjelinek is_zonepath_zfs(char *zonepath)
8101867Sgjelinek {
8111867Sgjelinek 	int res;
8121867Sgjelinek 	char *path;
8131867Sgjelinek 	char *parent;
8141867Sgjelinek 	struct statvfs buf1, buf2;
8151867Sgjelinek 
8161867Sgjelinek 	if (statvfs(zonepath, &buf1) != 0)
8171867Sgjelinek 		return (B_FALSE);
8181867Sgjelinek 
8191867Sgjelinek 	if (strcmp(buf1.f_basetype, "zfs") != 0)
8201867Sgjelinek 		return (B_FALSE);
8211867Sgjelinek 
8221867Sgjelinek 	if ((path = strdup(zonepath)) == NULL)
8231867Sgjelinek 		return (B_FALSE);
8241867Sgjelinek 
8251867Sgjelinek 	parent = dirname(path);
8261867Sgjelinek 	res = statvfs(parent, &buf2);
8271867Sgjelinek 	free(path);
8281867Sgjelinek 
8291867Sgjelinek 	if (res != 0)
8301867Sgjelinek 		return (B_FALSE);
8311867Sgjelinek 
8321867Sgjelinek 	if (buf1.f_fsid == buf2.f_fsid)
8331867Sgjelinek 		return (B_FALSE);
8341867Sgjelinek 
8351867Sgjelinek 	return (B_TRUE);
8361867Sgjelinek }
8371867Sgjelinek 
8381867Sgjelinek /*
8391867Sgjelinek  * Implement the fast move of a ZFS file system by simply updating the
8401867Sgjelinek  * mountpoint.  Since it is file system already, we don't have the
8411867Sgjelinek  * issue of cross-file system copying.
8421867Sgjelinek  */
8431867Sgjelinek int
8441867Sgjelinek move_zfs(char *zonepath, char *new_zonepath)
8451867Sgjelinek {
8461867Sgjelinek 	int		ret = Z_ERR;
8471867Sgjelinek 	zfs_handle_t	*zhp;
8481867Sgjelinek 
8492082Seschrock 	if ((zhp = mount2zhandle(zonepath)) == NULL)
8501867Sgjelinek 		return (Z_ERR);
8511867Sgjelinek 
8521867Sgjelinek 	if (zfs_prop_set(zhp, ZFS_PROP_MOUNTPOINT, new_zonepath) == 0) {
8531867Sgjelinek 		/*
8541867Sgjelinek 		 * Clean up the old mount point.  We ignore any failure since
8551867Sgjelinek 		 * the zone is already successfully mounted on the new path.
8561867Sgjelinek 		 */
8571867Sgjelinek 		(void) rmdir(zonepath);
8581867Sgjelinek 		ret = Z_OK;
8591867Sgjelinek 	}
8601867Sgjelinek 
8611867Sgjelinek 	zfs_close(zhp);
8621867Sgjelinek 
8631867Sgjelinek 	return (ret);
8641867Sgjelinek }
8651867Sgjelinek 
8661867Sgjelinek /*
8671867Sgjelinek  * Validate that the given dataset exists on the system, and that neither it nor
8681867Sgjelinek  * its children are zvols.
8691867Sgjelinek  *
8701867Sgjelinek  * Note that we don't do anything with the 'zoned' property here.  All
8711867Sgjelinek  * management is done in zoneadmd when the zone is actually rebooted.  This
8721867Sgjelinek  * allows us to automatically set the zoned property even when a zone is
8731867Sgjelinek  * rebooted by the administrator.
8741867Sgjelinek  */
8751867Sgjelinek int
8761867Sgjelinek verify_datasets(zone_dochandle_t handle)
8771867Sgjelinek {
8781867Sgjelinek 	int return_code = Z_OK;
8791867Sgjelinek 	struct zone_dstab dstab;
8801867Sgjelinek 	zfs_handle_t *zhp;
8811867Sgjelinek 	char propbuf[ZFS_MAXPROPLEN];
8821867Sgjelinek 	char source[ZFS_MAXNAMELEN];
8831867Sgjelinek 	zfs_source_t srctype;
8841867Sgjelinek 
8851867Sgjelinek 	if (zonecfg_setdsent(handle) != Z_OK) {
8861867Sgjelinek 		/*
8871867Sgjelinek 		 * TRANSLATION_NOTE
8881867Sgjelinek 		 * zfs and dataset are literals that should not be translated.
8891867Sgjelinek 		 */
8901867Sgjelinek 		(void) fprintf(stderr, gettext("could not verify zfs datasets: "
8911867Sgjelinek 		    "unable to enumerate datasets\n"));
8921867Sgjelinek 		return (Z_ERR);
8931867Sgjelinek 	}
8941867Sgjelinek 
8951867Sgjelinek 	while (zonecfg_getdsent(handle, &dstab) == Z_OK) {
8961867Sgjelinek 
8972082Seschrock 		if ((zhp = zfs_open(g_zfs, dstab.zone_dataset_name,
8981867Sgjelinek 		    ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME)) == NULL) {
8992082Seschrock 			(void) fprintf(stderr, gettext("could not verify zfs "
9002082Seschrock 			    "dataset %s: %s\n"), dstab.zone_dataset_name,
9012082Seschrock 			    libzfs_error_description(g_zfs));
9021867Sgjelinek 			return_code = Z_ERR;
9031867Sgjelinek 			continue;
9041867Sgjelinek 		}
9051867Sgjelinek 
9061867Sgjelinek 		if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, propbuf,
9071867Sgjelinek 		    sizeof (propbuf), &srctype, source,
9081867Sgjelinek 		    sizeof (source), 0) == 0 &&
9091867Sgjelinek 		    (srctype == ZFS_SRC_INHERITED)) {
9101867Sgjelinek 			(void) fprintf(stderr, gettext("could not verify zfs "
9111867Sgjelinek 			    "dataset %s: mountpoint cannot be inherited\n"),
9121867Sgjelinek 			    dstab.zone_dataset_name);
9131867Sgjelinek 			return_code = Z_ERR;
9141867Sgjelinek 			zfs_close(zhp);
9151867Sgjelinek 			continue;
9161867Sgjelinek 		}
9171867Sgjelinek 
9181867Sgjelinek 		if (zfs_get_type(zhp) == ZFS_TYPE_VOLUME) {
9191867Sgjelinek 			(void) fprintf(stderr, gettext("cannot verify zfs "
9201867Sgjelinek 			    "dataset %s: volumes cannot be specified as a "
9211867Sgjelinek 			    "zone dataset resource\n"),
9221867Sgjelinek 			    dstab.zone_dataset_name);
9231867Sgjelinek 			return_code = Z_ERR;
9241867Sgjelinek 		}
9251867Sgjelinek 
9261867Sgjelinek 		if (zfs_iter_children(zhp, check_zvol, NULL) != 0)
9271867Sgjelinek 			return_code = Z_ERR;
9281867Sgjelinek 
9291867Sgjelinek 		zfs_close(zhp);
9301867Sgjelinek 	}
9311867Sgjelinek 	(void) zonecfg_enddsent(handle);
9321867Sgjelinek 
9331867Sgjelinek 	return (return_code);
9341867Sgjelinek }
9351867Sgjelinek 
9361867Sgjelinek /*
9371867Sgjelinek  * Verify that the ZFS dataset exists, and its mountpoint
9381867Sgjelinek  * property is set to "legacy".
9391867Sgjelinek  */
9401867Sgjelinek int
9411867Sgjelinek verify_fs_zfs(struct zone_fstab *fstab)
9421867Sgjelinek {
9431867Sgjelinek 	zfs_handle_t *zhp;
9441867Sgjelinek 	char propbuf[ZFS_MAXPROPLEN];
9451867Sgjelinek 
9462082Seschrock 	if ((zhp = zfs_open(g_zfs, fstab->zone_fs_special,
9472082Seschrock 	    ZFS_TYPE_ANY)) == NULL) {
9481867Sgjelinek 		(void) fprintf(stderr, gettext("could not verify fs %s: "
9491867Sgjelinek 		    "could not access zfs dataset '%s'\n"),
9501867Sgjelinek 		    fstab->zone_fs_dir, fstab->zone_fs_special);
9511867Sgjelinek 		return (Z_ERR);
9521867Sgjelinek 	}
9531867Sgjelinek 
9541867Sgjelinek 	if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) {
9551867Sgjelinek 		(void) fprintf(stderr, gettext("cannot verify fs %s: "
9561867Sgjelinek 		    "'%s' is not a file system\n"),
9571867Sgjelinek 		    fstab->zone_fs_dir, fstab->zone_fs_special);
9581867Sgjelinek 		zfs_close(zhp);
9591867Sgjelinek 		return (Z_ERR);
9601867Sgjelinek 	}
9611867Sgjelinek 
9621867Sgjelinek 	if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, propbuf, sizeof (propbuf),
9631867Sgjelinek 	    NULL, NULL, 0, 0) != 0 || strcmp(propbuf, "legacy") != 0) {
9641867Sgjelinek 		(void) fprintf(stderr, gettext("could not verify fs %s: "
9651867Sgjelinek 		    "zfs '%s' mountpoint is not \"legacy\"\n"),
9661867Sgjelinek 		    fstab->zone_fs_dir, fstab->zone_fs_special);
9671867Sgjelinek 		zfs_close(zhp);
9681867Sgjelinek 		return (Z_ERR);
9691867Sgjelinek 	}
9701867Sgjelinek 
9711867Sgjelinek 	zfs_close(zhp);
9721867Sgjelinek 	return (Z_OK);
9731867Sgjelinek }
9742082Seschrock 
9752082Seschrock int
9762082Seschrock init_zfs(void)
9772082Seschrock {
9782082Seschrock 	if ((g_zfs = libzfs_init()) == NULL) {
9792082Seschrock 		(void) fprintf(stderr, gettext("failed to initialize ZFS "
9802082Seschrock 		    "library\n"));
9812082Seschrock 		return (Z_ERR);
9822082Seschrock 	}
9832082Seschrock 
9842082Seschrock 	return (Z_OK);
9852082Seschrock }
986