xref: /onnv-gate/usr/src/cmd/zoneadm/zfs.c (revision 7089:0461a2d76570)
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 /*
23*7089Sgjelinek  * Copyright 2008 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 /*
158*7089Sgjelinek  * Run the brand's pre-snapshot hook before we take a ZFS snapshot of the zone.
1591867Sgjelinek  */
1601867Sgjelinek static int
161*7089Sgjelinek pre_snapshot(char *presnapbuf)
1621867Sgjelinek {
163*7089Sgjelinek 	int status;
1641867Sgjelinek 
165*7089Sgjelinek 	/* No brand-specific handler */
166*7089Sgjelinek 	if (presnapbuf[0] == '\0')
167*7089Sgjelinek 		return (Z_OK);
1681867Sgjelinek 
169*7089Sgjelinek 	/* Run the hook */
170*7089Sgjelinek 	status = do_subproc_interactive(presnapbuf);
171*7089Sgjelinek 	if ((status = subproc_status(gettext("brand-specific presnapshot"),
172*7089Sgjelinek 	    status, B_FALSE)) != ZONE_SUBPROC_OK)
1731867Sgjelinek 		return (Z_ERR);
1741867Sgjelinek 
1751867Sgjelinek 	return (Z_OK);
1761867Sgjelinek }
1771867Sgjelinek 
1781867Sgjelinek /*
179*7089Sgjelinek  * Run the brand's post-snapshot hook after we take a ZFS snapshot of the zone.
1801867Sgjelinek  */
1811867Sgjelinek static int
182*7089Sgjelinek post_snapshot(char *postsnapbuf)
1831867Sgjelinek {
184*7089Sgjelinek 	int status;
1851867Sgjelinek 
186*7089Sgjelinek 	/* No brand-specific handler */
187*7089Sgjelinek 	if (postsnapbuf[0] == '\0')
188*7089Sgjelinek 		return (Z_OK);
189*7089Sgjelinek 
190*7089Sgjelinek 	/* Run the hook */
191*7089Sgjelinek 	status = do_subproc_interactive(postsnapbuf);
192*7089Sgjelinek 	if ((status = subproc_status(gettext("brand-specific postsnapshot"),
193*7089Sgjelinek 	    status, B_FALSE)) != ZONE_SUBPROC_OK)
1941867Sgjelinek 		return (Z_ERR);
1951867Sgjelinek 
1961867Sgjelinek 	return (Z_OK);
1971867Sgjelinek }
1981867Sgjelinek 
1991867Sgjelinek /*
2001867Sgjelinek  * This is a ZFS snapshot iterator call-back function which returns the
2011867Sgjelinek  * highest number of SUNWzone snapshots that have been taken.
2021867Sgjelinek  */
2031867Sgjelinek static int
2041867Sgjelinek get_snap_max(zfs_handle_t *zhp, void *data)
2051867Sgjelinek {
2061867Sgjelinek 	int			res;
2071867Sgjelinek 	zfs_snapshot_data_t	*cbp;
2081867Sgjelinek 
2091867Sgjelinek 	if (zfs_get_type(zhp) != ZFS_TYPE_SNAPSHOT) {
2101867Sgjelinek 		zfs_close(zhp);
2111867Sgjelinek 		return (0);
2121867Sgjelinek 	}
2131867Sgjelinek 
2141867Sgjelinek 	cbp = (zfs_snapshot_data_t *)data;
2151867Sgjelinek 
2161867Sgjelinek 	if (strncmp(zfs_get_name(zhp), cbp->match_name, cbp->len) == 0) {
2171867Sgjelinek 		char	*nump;
2181867Sgjelinek 		int	num;
2191867Sgjelinek 
2201867Sgjelinek 		nump = (char *)(zfs_get_name(zhp) + cbp->len);
2211867Sgjelinek 		num = atoi(nump);
2221867Sgjelinek 		if (num > cbp->max)
2231867Sgjelinek 			cbp->max = num;
2241867Sgjelinek 	}
2251867Sgjelinek 
2261867Sgjelinek 	res = zfs_iter_snapshots(zhp, get_snap_max, data);
2271867Sgjelinek 	zfs_close(zhp);
2281867Sgjelinek 	return (res);
2291867Sgjelinek }
2301867Sgjelinek 
2311867Sgjelinek /*
2321867Sgjelinek  * Take a ZFS snapshot to be used for cloning the zone.
2331867Sgjelinek  */
2341867Sgjelinek static int
235*7089Sgjelinek take_snapshot(zfs_handle_t *zhp, char *snapshot_name, int snap_size,
236*7089Sgjelinek     char *presnapbuf, char *postsnapbuf)
2371867Sgjelinek {
2381867Sgjelinek 	int			res;
2391867Sgjelinek 	char			template[ZFS_MAXNAMELEN];
2401867Sgjelinek 	zfs_snapshot_data_t	cb;
2411867Sgjelinek 
2421867Sgjelinek 	/*
2431867Sgjelinek 	 * First we need to figure out the next available name for the
2441867Sgjelinek 	 * zone snapshot.  Look through the list of zones snapshots for
2451867Sgjelinek 	 * this file system to determine the maximum snapshot name.
2461867Sgjelinek 	 */
2471867Sgjelinek 	if (snprintf(template, sizeof (template), "%s@SUNWzone",
2481867Sgjelinek 	    zfs_get_name(zhp)) >=  sizeof (template))
2491867Sgjelinek 		return (Z_ERR);
2501867Sgjelinek 
2511867Sgjelinek 	cb.match_name = template;
2521867Sgjelinek 	cb.len = strlen(template);
2531867Sgjelinek 	cb.max = 0;
2541867Sgjelinek 
2551867Sgjelinek 	if (zfs_iter_snapshots(zhp, get_snap_max, &cb) != 0)
2561867Sgjelinek 		return (Z_ERR);
2571867Sgjelinek 
2581867Sgjelinek 	cb.max++;
2591867Sgjelinek 
2601867Sgjelinek 	if (snprintf(snapshot_name, snap_size, "%s@SUNWzone%d",
2611867Sgjelinek 	    zfs_get_name(zhp), cb.max) >= snap_size)
2621867Sgjelinek 		return (Z_ERR);
2631867Sgjelinek 
264*7089Sgjelinek 	if (pre_snapshot(presnapbuf) != Z_OK)
2651867Sgjelinek 		return (Z_ERR);
2662199Sahrens 	res = zfs_snapshot(g_zfs, snapshot_name, B_FALSE);
267*7089Sgjelinek 	if (post_snapshot(postsnapbuf) != Z_OK)
2681867Sgjelinek 		return (Z_ERR);
2691867Sgjelinek 
2701867Sgjelinek 	if (res != 0)
2711867Sgjelinek 		return (Z_ERR);
2721867Sgjelinek 	return (Z_OK);
2731867Sgjelinek }
2741867Sgjelinek 
2751867Sgjelinek /*
2761867Sgjelinek  * We are using an explicit snapshot from some earlier point in time so
277*7089Sgjelinek  * we need to validate it.  Run the brand specific hook.
2781867Sgjelinek  */
2791867Sgjelinek static int
280*7089Sgjelinek validate_snapshot(char *snapshot_name, char *snap_path, char *validsnapbuf)
2811867Sgjelinek {
282*7089Sgjelinek 	int status;
283*7089Sgjelinek 	char cmdbuf[MAXPATHLEN];
2841867Sgjelinek 
285*7089Sgjelinek 	/* No brand-specific handler */
286*7089Sgjelinek 	if (validsnapbuf[0] == '\0')
287*7089Sgjelinek 		return (Z_OK);
2881867Sgjelinek 
289*7089Sgjelinek 	/* pass args - snapshot_name & snap_path */
290*7089Sgjelinek 	if (snprintf(cmdbuf, sizeof (cmdbuf), "%s %s %s", validsnapbuf,
291*7089Sgjelinek 	    snapshot_name, snap_path) >= sizeof (cmdbuf)) {
292*7089Sgjelinek 		zerror("Command line too long");
2931867Sgjelinek 		return (Z_ERR);
2941867Sgjelinek 	}
2951867Sgjelinek 
296*7089Sgjelinek 	/* Run the hook */
297*7089Sgjelinek 	status = do_subproc_interactive(cmdbuf);
298*7089Sgjelinek 	if ((status = subproc_status(gettext("brand-specific validatesnapshot"),
299*7089Sgjelinek 	    status, B_FALSE)) != ZONE_SUBPROC_OK)
300*7089Sgjelinek 		return (Z_ERR);
3011867Sgjelinek 
302*7089Sgjelinek 	return (Z_OK);
3031867Sgjelinek }
3041867Sgjelinek 
3051867Sgjelinek /*
3061867Sgjelinek  * Remove the sw inventory file from inside this zonepath that we picked up out
3071867Sgjelinek  * of the snapshot.
3081867Sgjelinek  */
3091867Sgjelinek static int
3101867Sgjelinek clean_out_clone()
3111867Sgjelinek {
3121867Sgjelinek 	int err;
3131867Sgjelinek 	zone_dochandle_t handle;
3141867Sgjelinek 
3151867Sgjelinek 	if ((handle = zonecfg_init_handle()) == NULL) {
3161867Sgjelinek 		zperror(cmd_to_str(CMD_CLONE), B_TRUE);
3171867Sgjelinek 		return (Z_ERR);
3181867Sgjelinek 	}
3191867Sgjelinek 
3201867Sgjelinek 	if ((err = zonecfg_get_handle(target_zone, handle)) != Z_OK) {
3211867Sgjelinek 		errno = err;
3221867Sgjelinek 		zperror(cmd_to_str(CMD_CLONE), B_TRUE);
3231867Sgjelinek 		zonecfg_fini_handle(handle);
3241867Sgjelinek 		return (Z_ERR);
3251867Sgjelinek 	}
3261867Sgjelinek 
3271867Sgjelinek 	zonecfg_rm_detached(handle, B_FALSE);
3281867Sgjelinek 	zonecfg_fini_handle(handle);
3291867Sgjelinek 
3301867Sgjelinek 	return (Z_OK);
3311867Sgjelinek }
3321867Sgjelinek 
3331867Sgjelinek /*
3341867Sgjelinek  * Make a ZFS clone on zonepath from snapshot_name.
3351867Sgjelinek  */
3361867Sgjelinek static int
3371867Sgjelinek clone_snap(char *snapshot_name, char *zonepath)
3381867Sgjelinek {
3391867Sgjelinek 	int		res = Z_OK;
3401867Sgjelinek 	int		err;
3411867Sgjelinek 	zfs_handle_t	*zhp;
3421867Sgjelinek 	zfs_handle_t	*clone;
3432676Seschrock 	nvlist_t	*props = NULL;
3441867Sgjelinek 
3452082Seschrock 	if ((zhp = zfs_open(g_zfs, snapshot_name, ZFS_TYPE_SNAPSHOT)) == NULL)
3461867Sgjelinek 		return (Z_NO_ENTRY);
3471867Sgjelinek 
3481867Sgjelinek 	(void) printf(gettext("Cloning snapshot %s\n"), snapshot_name);
3491867Sgjelinek 
3502676Seschrock 	if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0 ||
3512744Snn35248 	    nvlist_add_string(props, zfs_prop_to_name(ZFS_PROP_SHARENFS),
3522744Snn35248 	    "off") != 0) {
3532744Snn35248 		if (props != NULL)
3542744Snn35248 			nvlist_free(props);
3552676Seschrock 		(void) fprintf(stderr, gettext("could not create ZFS clone "
3562676Seschrock 		    "%s: out of memory\n"), zonepath);
3572676Seschrock 		return (Z_ERR);
3582676Seschrock 	}
3592676Seschrock 
3602676Seschrock 	err = zfs_clone(zhp, zonepath, props);
3611867Sgjelinek 	zfs_close(zhp);
3622676Seschrock 
3632676Seschrock 	nvlist_free(props);
3642676Seschrock 
3651867Sgjelinek 	if (err != 0)
3661867Sgjelinek 		return (Z_ERR);
3671867Sgjelinek 
3681867Sgjelinek 	/* create the mountpoint if necessary */
3695094Slling 	if ((clone = zfs_open(g_zfs, zonepath, ZFS_TYPE_DATASET)) == NULL)
3701867Sgjelinek 		return (Z_ERR);
3711867Sgjelinek 
3721867Sgjelinek 	/*
3731867Sgjelinek 	 * The clone has been created so we need to print a diagnostic
3741867Sgjelinek 	 * message if one of the following steps fails for some reason.
3751867Sgjelinek 	 */
3761867Sgjelinek 	if (zfs_mount(clone, NULL, 0) != 0) {
3771867Sgjelinek 		(void) fprintf(stderr, gettext("could not mount ZFS clone "
3781867Sgjelinek 		    "%s\n"), zfs_get_name(clone));
3791867Sgjelinek 		res = Z_ERR;
3801867Sgjelinek 
3812676Seschrock 	} else if (clean_out_clone() != Z_OK) {
3822676Seschrock 		(void) fprintf(stderr, gettext("could not remove the "
3832676Seschrock 		    "software inventory from ZFS clone %s\n"),
3842676Seschrock 		    zfs_get_name(clone));
3852676Seschrock 		res = Z_ERR;
3861867Sgjelinek 	}
3871867Sgjelinek 
3881867Sgjelinek 	zfs_close(clone);
3891867Sgjelinek 	return (res);
3901867Sgjelinek }
3911867Sgjelinek 
3921867Sgjelinek /*
3931867Sgjelinek  * This function takes a zonepath and attempts to determine what the ZFS
3941867Sgjelinek  * file system name (not mountpoint) should be for that path.  We do not
3951867Sgjelinek  * assume that zonepath is an existing directory or ZFS fs since we use
3961867Sgjelinek  * this function as part of the process of creating a new ZFS fs or clone.
3971867Sgjelinek  *
3981867Sgjelinek  * The way this works is that we look at the parent directory of the zonepath
3991867Sgjelinek  * to see if it is a ZFS fs.  If it is, we get the name of that ZFS fs and
4001867Sgjelinek  * append the last component of the zonepath to generate the ZFS name for the
4011867Sgjelinek  * zonepath.  This matches the algorithm that ZFS uses for automatically
4021867Sgjelinek  * mounting a new fs after it is created.
4031867Sgjelinek  *
4041867Sgjelinek  * Although a ZFS fs can be mounted anywhere, we don't worry about handling
4051867Sgjelinek  * all of the complexity that a user could possibly configure with arbitrary
4061867Sgjelinek  * mounts since there is no way to generate a ZFS name from a random path in
4071867Sgjelinek  * the file system.  We only try to handle the automatic mounts that ZFS does
4081867Sgjelinek  * for each file system.  ZFS restricts this so that a new fs must be created
4091867Sgjelinek  * in an existing parent ZFS fs.  It then automatically mounts the new fs
4101867Sgjelinek  * directly under the mountpoint for the parent fs using the last component
4111867Sgjelinek  * of the name as the mountpoint directory.
4121867Sgjelinek  *
4131867Sgjelinek  * For example:
4141867Sgjelinek  *    Name			Mountpoint
4151867Sgjelinek  *    space/eng/dev/test/zone1	/project1/eng/dev/test/zone1
4161867Sgjelinek  *
4171867Sgjelinek  * Return Z_OK if the path mapped to a ZFS file system name, otherwise return
4181867Sgjelinek  * Z_ERR.
4191867Sgjelinek  */
4201867Sgjelinek static int
4211867Sgjelinek path2name(char *zonepath, char *zfs_name, int len)
4221867Sgjelinek {
4231867Sgjelinek 	int		res;
4241867Sgjelinek 	char		*p;
4251867Sgjelinek 	zfs_handle_t	*zhp;
4261867Sgjelinek 
4271867Sgjelinek 	if ((p = strrchr(zonepath, '/')) == NULL)
4281867Sgjelinek 		return (Z_ERR);
4291867Sgjelinek 
4301867Sgjelinek 	/*
4311867Sgjelinek 	 * If the parent directory is not its own ZFS fs, then we can't
4321867Sgjelinek 	 * automatically create a new ZFS fs at the 'zonepath' mountpoint
4331867Sgjelinek 	 * so return an error.
4341867Sgjelinek 	 */
4351867Sgjelinek 	*p = '\0';
4361867Sgjelinek 	zhp = mount2zhandle(zonepath);
4371867Sgjelinek 	*p = '/';
4381867Sgjelinek 	if (zhp == NULL)
4391867Sgjelinek 		return (Z_ERR);
4401867Sgjelinek 
4411867Sgjelinek 	res = snprintf(zfs_name, len, "%s/%s", zfs_get_name(zhp), p + 1);
4421867Sgjelinek 
4431867Sgjelinek 	zfs_close(zhp);
4441867Sgjelinek 	if (res >= len)
4451867Sgjelinek 		return (Z_ERR);
4461867Sgjelinek 
4471867Sgjelinek 	return (Z_OK);
4481867Sgjelinek }
4491867Sgjelinek 
4501867Sgjelinek /*
4511867Sgjelinek  * A ZFS file system iterator call-back function used to determine if the
4521867Sgjelinek  * file system has dependents (snapshots & clones).
4531867Sgjelinek  */
4541867Sgjelinek /* ARGSUSED */
4551867Sgjelinek static int
4561867Sgjelinek has_dependent(zfs_handle_t *zhp, void *data)
4571867Sgjelinek {
4581867Sgjelinek 	zfs_close(zhp);
4591867Sgjelinek 	return (1);
4601867Sgjelinek }
4611867Sgjelinek 
4621867Sgjelinek /*
4631867Sgjelinek  * Given a snapshot name, get the file system path where the snapshot lives.
4641867Sgjelinek  * A snapshot name is of the form fs_name@snap_name.  For example, snapshot
4651867Sgjelinek  * pl/zones/z1@SUNWzone1 would have a path of
4661867Sgjelinek  * /pl/zones/z1/.zfs/snapshot/SUNWzone1.
4671867Sgjelinek  */
4681867Sgjelinek static int
4691867Sgjelinek snap2path(char *snap_name, char *path, int len)
4701867Sgjelinek {
4711867Sgjelinek 	char		*p;
4721867Sgjelinek 	zfs_handle_t	*zhp;
4731867Sgjelinek 	char		mp[ZFS_MAXPROPLEN];
4741867Sgjelinek 
4751867Sgjelinek 	if ((p = strrchr(snap_name, '@')) == NULL)
4761867Sgjelinek 		return (Z_ERR);
4771867Sgjelinek 
4781867Sgjelinek 	/* Get the file system name from the snap_name. */
4791867Sgjelinek 	*p = '\0';
4805094Slling 	zhp = zfs_open(g_zfs, snap_name, ZFS_TYPE_DATASET);
4811867Sgjelinek 	*p = '@';
4821867Sgjelinek 	if (zhp == NULL)
4831867Sgjelinek 		return (Z_ERR);
4841867Sgjelinek 
4851867Sgjelinek 	/* Get the file system mount point. */
4861867Sgjelinek 	if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mp, sizeof (mp), NULL, NULL,
4872082Seschrock 	    0, B_FALSE) != 0) {
4881867Sgjelinek 		zfs_close(zhp);
4891867Sgjelinek 		return (Z_ERR);
4901867Sgjelinek 	}
4911867Sgjelinek 	zfs_close(zhp);
4921867Sgjelinek 
4931867Sgjelinek 	p++;
4941867Sgjelinek 	if (snprintf(path, len, "%s/.zfs/snapshot/%s", mp, p) >= len)
4951867Sgjelinek 		return (Z_ERR);
4961867Sgjelinek 
4971867Sgjelinek 	return (Z_OK);
4981867Sgjelinek }
4991867Sgjelinek 
5001867Sgjelinek /*
5011867Sgjelinek  * Clone a pre-existing ZFS snapshot, either by making a direct ZFS clone, if
5021867Sgjelinek  * possible, or by copying the data from the snapshot to the zonepath.
5031867Sgjelinek  */
5041867Sgjelinek int
505*7089Sgjelinek clone_snapshot_zfs(char *snap_name, char *zonepath, char *validatesnap)
5061867Sgjelinek {
5071867Sgjelinek 	int	err = Z_OK;
5081867Sgjelinek 	char	clone_name[MAXPATHLEN];
5091867Sgjelinek 	char	snap_path[MAXPATHLEN];
5101867Sgjelinek 
5111867Sgjelinek 	if (snap2path(snap_name, snap_path, sizeof (snap_path)) != Z_OK) {
5121867Sgjelinek 		(void) fprintf(stderr, gettext("unable to find path for %s.\n"),
5131867Sgjelinek 		    snap_name);
5141867Sgjelinek 		return (Z_ERR);
5151867Sgjelinek 	}
5161867Sgjelinek 
517*7089Sgjelinek 	if (validate_snapshot(snap_name, snap_path, validatesnap) != Z_OK)
5181867Sgjelinek 		return (Z_NO_ENTRY);
5191867Sgjelinek 
5201867Sgjelinek 	/*
5211867Sgjelinek 	 * The zonepath cannot be ZFS cloned, try to copy the data from
5221867Sgjelinek 	 * within the snapshot to the zonepath.
5231867Sgjelinek 	 */
5241867Sgjelinek 	if (path2name(zonepath, clone_name, sizeof (clone_name)) != Z_OK) {
5251867Sgjelinek 		if ((err = clone_copy(snap_path, zonepath)) == Z_OK)
5261867Sgjelinek 			if (clean_out_clone() != Z_OK)
5271867Sgjelinek 				(void) fprintf(stderr,
5281867Sgjelinek 				    gettext("could not remove the "
5291867Sgjelinek 				    "software inventory from %s\n"), zonepath);
5301867Sgjelinek 
5311867Sgjelinek 		return (err);
5321867Sgjelinek 	}
5331867Sgjelinek 
5341867Sgjelinek 	if ((err = clone_snap(snap_name, clone_name)) != Z_OK) {
5351867Sgjelinek 		if (err != Z_NO_ENTRY) {
5361867Sgjelinek 			/*
5371867Sgjelinek 			 * Cloning the snapshot failed.  Fall back to trying
5381867Sgjelinek 			 * to install the zone by copying from the snapshot.
5391867Sgjelinek 			 */
5401867Sgjelinek 			if ((err = clone_copy(snap_path, zonepath)) == Z_OK)
5411867Sgjelinek 				if (clean_out_clone() != Z_OK)
5421867Sgjelinek 					(void) fprintf(stderr,
5431867Sgjelinek 					    gettext("could not remove the "
5441867Sgjelinek 					    "software inventory from %s\n"),
5451867Sgjelinek 					    zonepath);
5461867Sgjelinek 		} else {
5471867Sgjelinek 			/*
5481867Sgjelinek 			 * The snapshot is unusable for some reason so restore
5491867Sgjelinek 			 * the zone state to configured since we were unable to
5501867Sgjelinek 			 * actually do anything about getting the zone
5511867Sgjelinek 			 * installed.
5521867Sgjelinek 			 */
5531867Sgjelinek 			int tmp;
5541867Sgjelinek 
5551867Sgjelinek 			if ((tmp = zone_set_state(target_zone,
5561867Sgjelinek 			    ZONE_STATE_CONFIGURED)) != Z_OK) {
5571867Sgjelinek 				errno = tmp;
5581867Sgjelinek 				zperror2(target_zone,
5591867Sgjelinek 				    gettext("could not set state"));
5601867Sgjelinek 			}
5611867Sgjelinek 		}
5621867Sgjelinek 	}
5631867Sgjelinek 
5641867Sgjelinek 	return (err);
5651867Sgjelinek }
5661867Sgjelinek 
5671867Sgjelinek /*
5681867Sgjelinek  * Attempt to clone a source_zone to a target zonepath by using a ZFS clone.
5691867Sgjelinek  */
5701867Sgjelinek int
571*7089Sgjelinek clone_zfs(char *source_zonepath, char *zonepath, char *presnapbuf,
572*7089Sgjelinek     char *postsnapbuf)
5731867Sgjelinek {
5741867Sgjelinek 	zfs_handle_t	*zhp;
5751867Sgjelinek 	char		clone_name[MAXPATHLEN];
5761867Sgjelinek 	char		snap_name[MAXPATHLEN];
5771867Sgjelinek 
5781867Sgjelinek 	/*
5791867Sgjelinek 	 * Try to get a zfs handle for the source_zonepath.  If this fails
5801867Sgjelinek 	 * the source_zonepath is not ZFS so return an error.
5811867Sgjelinek 	 */
5821867Sgjelinek 	if ((zhp = mount2zhandle(source_zonepath)) == NULL)
5831867Sgjelinek 		return (Z_ERR);
5841867Sgjelinek 
5851867Sgjelinek 	/*
5861867Sgjelinek 	 * Check if there is a file system already mounted on zonepath.  If so,
5871867Sgjelinek 	 * we can't clone to the path so we should fall back to copying.
5881867Sgjelinek 	 */
5891867Sgjelinek 	if (is_mountpnt(zonepath)) {
5901867Sgjelinek 		zfs_close(zhp);
5911867Sgjelinek 		(void) fprintf(stderr,
5921867Sgjelinek 		    gettext("A file system is already mounted on %s,\n"
5931867Sgjelinek 		    "preventing use of a ZFS clone.\n"), zonepath);
5941867Sgjelinek 		return (Z_ERR);
5951867Sgjelinek 	}
5961867Sgjelinek 
5971867Sgjelinek 	/*
5981867Sgjelinek 	 * Instead of using path2name to get the clone name from the zonepath,
5991867Sgjelinek 	 * we could generate a name from the source zone ZFS name.  However,
6001867Sgjelinek 	 * this would mean we would create the clone under the ZFS fs of the
6011867Sgjelinek 	 * source instead of what the zonepath says.  For example,
6021867Sgjelinek 	 *
6031867Sgjelinek 	 * source_zonepath		zonepath
6041867Sgjelinek 	 * /pl/zones/dev/z1		/pl/zones/deploy/z2
6051867Sgjelinek 	 *
6061867Sgjelinek 	 * We don't want the clone to be under "dev", we want it under
6071867Sgjelinek 	 * "deploy", so that we can leverage the normal attribute inheritance
6081867Sgjelinek 	 * that ZFS provides in the fs hierarchy.
6091867Sgjelinek 	 */
6101867Sgjelinek 	if (path2name(zonepath, clone_name, sizeof (clone_name)) != Z_OK) {
6111867Sgjelinek 		zfs_close(zhp);
6121867Sgjelinek 		return (Z_ERR);
6131867Sgjelinek 	}
6141867Sgjelinek 
615*7089Sgjelinek 	if (take_snapshot(zhp, snap_name, sizeof (snap_name), presnapbuf,
616*7089Sgjelinek 	    postsnapbuf) != Z_OK) {
6171867Sgjelinek 		zfs_close(zhp);
6181867Sgjelinek 		return (Z_ERR);
6191867Sgjelinek 	}
6201867Sgjelinek 	zfs_close(zhp);
6211867Sgjelinek 
6223686Sgjelinek 	if (clone_snap(snap_name, clone_name) != Z_OK) {
6233686Sgjelinek 		/* Clean up the snapshot we just took. */
6243686Sgjelinek 		if ((zhp = zfs_open(g_zfs, snap_name, ZFS_TYPE_SNAPSHOT))
6253686Sgjelinek 		    != NULL) {
6263686Sgjelinek 			if (zfs_unmount(zhp, NULL, 0) == 0)
6273686Sgjelinek 				(void) zfs_destroy(zhp);
6283686Sgjelinek 			zfs_close(zhp);
6293686Sgjelinek 		}
6303686Sgjelinek 
6311867Sgjelinek 		return (Z_ERR);
6323686Sgjelinek 	}
6331867Sgjelinek 
6341867Sgjelinek 	(void) printf(gettext("Instead of copying, a ZFS clone has been "
6351867Sgjelinek 	    "created for this zone.\n"));
6361867Sgjelinek 
6371867Sgjelinek 	return (Z_OK);
6381867Sgjelinek }
6391867Sgjelinek 
6401867Sgjelinek /*
6411867Sgjelinek  * Attempt to create a ZFS file system for the specified zonepath.
6421867Sgjelinek  * We either will successfully create a ZFS file system and get it mounted
6431867Sgjelinek  * on the zonepath or we don't.  The caller doesn't care since a regular
6441867Sgjelinek  * directory is used for the zonepath if no ZFS file system is mounted there.
6451867Sgjelinek  */
6461867Sgjelinek void
6471867Sgjelinek create_zfs_zonepath(char *zonepath)
6481867Sgjelinek {
6491867Sgjelinek 	zfs_handle_t	*zhp;
6501867Sgjelinek 	char		zfs_name[MAXPATHLEN];
6512676Seschrock 	nvlist_t	*props = NULL;
6521867Sgjelinek 
6531867Sgjelinek 	if (path2name(zonepath, zfs_name, sizeof (zfs_name)) != Z_OK)
6541867Sgjelinek 		return;
6551867Sgjelinek 
6562676Seschrock 	if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0 ||
6572744Snn35248 	    nvlist_add_string(props, zfs_prop_to_name(ZFS_PROP_SHARENFS),
6582744Snn35248 	    "off") != 0) {
6592744Snn35248 		if (props != NULL)
6602744Snn35248 			nvlist_free(props);
6612676Seschrock 		(void) fprintf(stderr, gettext("cannot create ZFS dataset %s: "
6622676Seschrock 		    "out of memory\n"), zfs_name);
6632676Seschrock 	}
6642676Seschrock 
6652676Seschrock 	if (zfs_create(g_zfs, zfs_name, ZFS_TYPE_FILESYSTEM, props) != 0 ||
6665094Slling 	    (zhp = zfs_open(g_zfs, zfs_name, ZFS_TYPE_DATASET)) == NULL) {
6672082Seschrock 		(void) fprintf(stderr, gettext("cannot create ZFS dataset %s: "
6682082Seschrock 		    "%s\n"), zfs_name, libzfs_error_description(g_zfs));
6692676Seschrock 		nvlist_free(props);
6701867Sgjelinek 		return;
6711867Sgjelinek 	}
6721867Sgjelinek 
6732676Seschrock 	nvlist_free(props);
6742676Seschrock 
6751867Sgjelinek 	if (zfs_mount(zhp, NULL, 0) != 0) {
6762082Seschrock 		(void) fprintf(stderr, gettext("cannot mount ZFS dataset %s: "
6772082Seschrock 		    "%s\n"), zfs_name, libzfs_error_description(g_zfs));
6781867Sgjelinek 		(void) zfs_destroy(zhp);
6791867Sgjelinek 	} else {
6801867Sgjelinek 		if (chmod(zonepath, S_IRWXU) != 0) {
6811867Sgjelinek 			(void) fprintf(stderr, gettext("file system %s "
6821867Sgjelinek 			    "successfully created, but chmod %o failed: %s\n"),
6831867Sgjelinek 			    zfs_name, S_IRWXU, strerror(errno));
6841867Sgjelinek 			(void) destroy_zfs(zonepath);
6851867Sgjelinek 		} else {
6861867Sgjelinek 			(void) printf(gettext("A ZFS file system has been "
6871867Sgjelinek 			    "created for this zone.\n"));
6881867Sgjelinek 		}
6891867Sgjelinek 	}
6901867Sgjelinek 
6911867Sgjelinek 	zfs_close(zhp);
6921867Sgjelinek }
6931867Sgjelinek 
6941867Sgjelinek /*
6951867Sgjelinek  * If the zonepath is a ZFS file system, attempt to destroy it.  We return Z_OK
6961867Sgjelinek  * if we were able to zfs_destroy the zonepath, otherwise we return Z_ERR
6971867Sgjelinek  * which means the caller should clean up the zonepath in the traditional
6981867Sgjelinek  * way.
6991867Sgjelinek  */
7001867Sgjelinek int
7011867Sgjelinek destroy_zfs(char *zonepath)
7021867Sgjelinek {
7031867Sgjelinek 	zfs_handle_t	*zhp;
7041867Sgjelinek 	boolean_t	is_clone = B_FALSE;
7051867Sgjelinek 	char		origin[ZFS_MAXPROPLEN];
7061867Sgjelinek 
7072082Seschrock 	if ((zhp = mount2zhandle(zonepath)) == NULL)
7081867Sgjelinek 		return (Z_ERR);
7091867Sgjelinek 
7101867Sgjelinek 	/*
7111867Sgjelinek 	 * We can't destroy the file system if it has dependents.
7121867Sgjelinek 	 */
7132474Seschrock 	if (zfs_iter_dependents(zhp, B_TRUE, has_dependent, NULL) != 0 ||
7141867Sgjelinek 	    zfs_unmount(zhp, NULL, 0) != 0) {
7151867Sgjelinek 		zfs_close(zhp);
7161867Sgjelinek 		return (Z_ERR);
7171867Sgjelinek 	}
7181867Sgjelinek 
7191867Sgjelinek 	/*
7201867Sgjelinek 	 * This might be a clone.  Try to get the snapshot so we can attempt
7211867Sgjelinek 	 * to destroy that as well.
7221867Sgjelinek 	 */
7231867Sgjelinek 	if (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, origin, sizeof (origin), NULL,
7242082Seschrock 	    NULL, 0, B_FALSE) == 0)
7251867Sgjelinek 		is_clone = B_TRUE;
7261867Sgjelinek 
7271867Sgjelinek 	if (zfs_destroy(zhp) != 0) {
7281867Sgjelinek 		/*
7291867Sgjelinek 		 * If the destroy fails for some reason, try to remount
7301867Sgjelinek 		 * the file system so that we can use "rm -rf" to clean up
7311867Sgjelinek 		 * instead.
7321867Sgjelinek 		 */
7331867Sgjelinek 		(void) zfs_mount(zhp, NULL, 0);
7341867Sgjelinek 		zfs_close(zhp);
7351867Sgjelinek 		return (Z_ERR);
7361867Sgjelinek 	}
7371867Sgjelinek 
7383686Sgjelinek 	/*
7393686Sgjelinek 	 * If the zone has ever been moved then the mountpoint dir will not be
7403686Sgjelinek 	 * cleaned up by the zfs_destroy().  To handle this case try to clean
7413686Sgjelinek 	 * it up now but don't worry if it fails, that will be normal.
7423686Sgjelinek 	 */
7433686Sgjelinek 	(void) rmdir(zonepath);
7443686Sgjelinek 
7451867Sgjelinek 	(void) printf(gettext("The ZFS file system for this zone has been "
7461867Sgjelinek 	    "destroyed.\n"));
7471867Sgjelinek 
7481867Sgjelinek 	if (is_clone) {
7491867Sgjelinek 		zfs_handle_t	*ohp;
7501867Sgjelinek 
7511867Sgjelinek 		/*
7521867Sgjelinek 		 * Try to clean up the snapshot that the clone was taken from.
7531867Sgjelinek 		 */
7542082Seschrock 		if ((ohp = zfs_open(g_zfs, origin,
7552082Seschrock 		    ZFS_TYPE_SNAPSHOT)) != NULL) {
7562474Seschrock 			if (zfs_iter_dependents(ohp, B_TRUE, has_dependent,
7572474Seschrock 			    NULL) == 0 && zfs_unmount(ohp, NULL, 0) == 0)
7581867Sgjelinek 				(void) zfs_destroy(ohp);
7591867Sgjelinek 			zfs_close(ohp);
7601867Sgjelinek 		}
7611867Sgjelinek 	}
7621867Sgjelinek 
7631867Sgjelinek 	zfs_close(zhp);
7641867Sgjelinek 	return (Z_OK);
7651867Sgjelinek }
7661867Sgjelinek 
7671867Sgjelinek /*
7681867Sgjelinek  * Return true if the path is its own zfs file system.  We determine this
7691867Sgjelinek  * by stat-ing the path to see if it is zfs and stat-ing the parent to see
7701867Sgjelinek  * if it is a different fs.
7711867Sgjelinek  */
7721867Sgjelinek boolean_t
7731867Sgjelinek is_zonepath_zfs(char *zonepath)
7741867Sgjelinek {
7751867Sgjelinek 	int res;
7761867Sgjelinek 	char *path;
7771867Sgjelinek 	char *parent;
7782267Sdp 	struct statvfs64 buf1, buf2;
7791867Sgjelinek 
7802267Sdp 	if (statvfs64(zonepath, &buf1) != 0)
7811867Sgjelinek 		return (B_FALSE);
7821867Sgjelinek 
7831867Sgjelinek 	if (strcmp(buf1.f_basetype, "zfs") != 0)
7841867Sgjelinek 		return (B_FALSE);
7851867Sgjelinek 
7861867Sgjelinek 	if ((path = strdup(zonepath)) == NULL)
7871867Sgjelinek 		return (B_FALSE);
7881867Sgjelinek 
7891867Sgjelinek 	parent = dirname(path);
7902267Sdp 	res = statvfs64(parent, &buf2);
7911867Sgjelinek 	free(path);
7921867Sgjelinek 
7931867Sgjelinek 	if (res != 0)
7941867Sgjelinek 		return (B_FALSE);
7951867Sgjelinek 
7961867Sgjelinek 	if (buf1.f_fsid == buf2.f_fsid)
7971867Sgjelinek 		return (B_FALSE);
7981867Sgjelinek 
7991867Sgjelinek 	return (B_TRUE);
8001867Sgjelinek }
8011867Sgjelinek 
8021867Sgjelinek /*
8031867Sgjelinek  * Implement the fast move of a ZFS file system by simply updating the
8041867Sgjelinek  * mountpoint.  Since it is file system already, we don't have the
8051867Sgjelinek  * issue of cross-file system copying.
8061867Sgjelinek  */
8071867Sgjelinek int
8081867Sgjelinek move_zfs(char *zonepath, char *new_zonepath)
8091867Sgjelinek {
8101867Sgjelinek 	int		ret = Z_ERR;
8111867Sgjelinek 	zfs_handle_t	*zhp;
8121867Sgjelinek 
8132082Seschrock 	if ((zhp = mount2zhandle(zonepath)) == NULL)
8141867Sgjelinek 		return (Z_ERR);
8151867Sgjelinek 
8162676Seschrock 	if (zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
8172676Seschrock 	    new_zonepath) == 0) {
8181867Sgjelinek 		/*
8191867Sgjelinek 		 * Clean up the old mount point.  We ignore any failure since
8201867Sgjelinek 		 * the zone is already successfully mounted on the new path.
8211867Sgjelinek 		 */
8221867Sgjelinek 		(void) rmdir(zonepath);
8231867Sgjelinek 		ret = Z_OK;
8241867Sgjelinek 	}
8251867Sgjelinek 
8261867Sgjelinek 	zfs_close(zhp);
8271867Sgjelinek 
8281867Sgjelinek 	return (ret);
8291867Sgjelinek }
8301867Sgjelinek 
8311867Sgjelinek /*
8321867Sgjelinek  * Validate that the given dataset exists on the system, and that neither it nor
8331867Sgjelinek  * its children are zvols.
8341867Sgjelinek  *
8351867Sgjelinek  * Note that we don't do anything with the 'zoned' property here.  All
8361867Sgjelinek  * management is done in zoneadmd when the zone is actually rebooted.  This
8371867Sgjelinek  * allows us to automatically set the zoned property even when a zone is
8381867Sgjelinek  * rebooted by the administrator.
8391867Sgjelinek  */
8401867Sgjelinek int
8411867Sgjelinek verify_datasets(zone_dochandle_t handle)
8421867Sgjelinek {
8431867Sgjelinek 	int return_code = Z_OK;
8441867Sgjelinek 	struct zone_dstab dstab;
8451867Sgjelinek 	zfs_handle_t *zhp;
8461867Sgjelinek 	char propbuf[ZFS_MAXPROPLEN];
8471867Sgjelinek 	char source[ZFS_MAXNAMELEN];
8485094Slling 	zprop_source_t srctype;
8491867Sgjelinek 
8501867Sgjelinek 	if (zonecfg_setdsent(handle) != Z_OK) {
8511867Sgjelinek 		/*
8521867Sgjelinek 		 * TRANSLATION_NOTE
8531867Sgjelinek 		 * zfs and dataset are literals that should not be translated.
8541867Sgjelinek 		 */
8551867Sgjelinek 		(void) fprintf(stderr, gettext("could not verify zfs datasets: "
8561867Sgjelinek 		    "unable to enumerate datasets\n"));
8571867Sgjelinek 		return (Z_ERR);
8581867Sgjelinek 	}
8591867Sgjelinek 
8601867Sgjelinek 	while (zonecfg_getdsent(handle, &dstab) == Z_OK) {
8611867Sgjelinek 
8622082Seschrock 		if ((zhp = zfs_open(g_zfs, dstab.zone_dataset_name,
8631867Sgjelinek 		    ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME)) == NULL) {
8642082Seschrock 			(void) fprintf(stderr, gettext("could not verify zfs "
8652082Seschrock 			    "dataset %s: %s\n"), dstab.zone_dataset_name,
8662082Seschrock 			    libzfs_error_description(g_zfs));
8671867Sgjelinek 			return_code = Z_ERR;
8681867Sgjelinek 			continue;
8691867Sgjelinek 		}
8701867Sgjelinek 
8711867Sgjelinek 		if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, propbuf,
8721867Sgjelinek 		    sizeof (propbuf), &srctype, source,
8731867Sgjelinek 		    sizeof (source), 0) == 0 &&
8745094Slling 		    (srctype == ZPROP_SRC_INHERITED)) {
8751867Sgjelinek 			(void) fprintf(stderr, gettext("could not verify zfs "
8761867Sgjelinek 			    "dataset %s: mountpoint cannot be inherited\n"),
8771867Sgjelinek 			    dstab.zone_dataset_name);
8781867Sgjelinek 			return_code = Z_ERR;
8791867Sgjelinek 			zfs_close(zhp);
8801867Sgjelinek 			continue;
8811867Sgjelinek 		}
8821867Sgjelinek 
8831867Sgjelinek 		if (zfs_get_type(zhp) == ZFS_TYPE_VOLUME) {
8841867Sgjelinek 			(void) fprintf(stderr, gettext("cannot verify zfs "
8851867Sgjelinek 			    "dataset %s: volumes cannot be specified as a "
8861867Sgjelinek 			    "zone dataset resource\n"),
8871867Sgjelinek 			    dstab.zone_dataset_name);
8881867Sgjelinek 			return_code = Z_ERR;
8891867Sgjelinek 		}
8901867Sgjelinek 
8911867Sgjelinek 		if (zfs_iter_children(zhp, check_zvol, NULL) != 0)
8921867Sgjelinek 			return_code = Z_ERR;
8931867Sgjelinek 
8941867Sgjelinek 		zfs_close(zhp);
8951867Sgjelinek 	}
8961867Sgjelinek 	(void) zonecfg_enddsent(handle);
8971867Sgjelinek 
8981867Sgjelinek 	return (return_code);
8991867Sgjelinek }
9001867Sgjelinek 
9011867Sgjelinek /*
9021867Sgjelinek  * Verify that the ZFS dataset exists, and its mountpoint
9031867Sgjelinek  * property is set to "legacy".
9041867Sgjelinek  */
9051867Sgjelinek int
9061867Sgjelinek verify_fs_zfs(struct zone_fstab *fstab)
9071867Sgjelinek {
9081867Sgjelinek 	zfs_handle_t *zhp;
9091867Sgjelinek 	char propbuf[ZFS_MAXPROPLEN];
9101867Sgjelinek 
9112082Seschrock 	if ((zhp = zfs_open(g_zfs, fstab->zone_fs_special,
9125094Slling 	    ZFS_TYPE_DATASET)) == NULL) {
9131867Sgjelinek 		(void) fprintf(stderr, gettext("could not verify fs %s: "
9141867Sgjelinek 		    "could not access zfs dataset '%s'\n"),
9151867Sgjelinek 		    fstab->zone_fs_dir, fstab->zone_fs_special);
9161867Sgjelinek 		return (Z_ERR);
9171867Sgjelinek 	}
9181867Sgjelinek 
9191867Sgjelinek 	if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) {
9201867Sgjelinek 		(void) fprintf(stderr, gettext("cannot verify fs %s: "
9211867Sgjelinek 		    "'%s' is not a file system\n"),
9221867Sgjelinek 		    fstab->zone_fs_dir, fstab->zone_fs_special);
9231867Sgjelinek 		zfs_close(zhp);
9241867Sgjelinek 		return (Z_ERR);
9251867Sgjelinek 	}
9261867Sgjelinek 
9271867Sgjelinek 	if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, propbuf, sizeof (propbuf),
9281867Sgjelinek 	    NULL, NULL, 0, 0) != 0 || strcmp(propbuf, "legacy") != 0) {
9291867Sgjelinek 		(void) fprintf(stderr, gettext("could not verify fs %s: "
9301867Sgjelinek 		    "zfs '%s' mountpoint is not \"legacy\"\n"),
9311867Sgjelinek 		    fstab->zone_fs_dir, fstab->zone_fs_special);
9321867Sgjelinek 		zfs_close(zhp);
9331867Sgjelinek 		return (Z_ERR);
9341867Sgjelinek 	}
9351867Sgjelinek 
9361867Sgjelinek 	zfs_close(zhp);
9371867Sgjelinek 	return (Z_OK);
9381867Sgjelinek }
9392082Seschrock 
9402082Seschrock int
9412082Seschrock init_zfs(void)
9422082Seschrock {
9432082Seschrock 	if ((g_zfs = libzfs_init()) == NULL) {
9442082Seschrock 		(void) fprintf(stderr, gettext("failed to initialize ZFS "
9452082Seschrock 		    "library\n"));
9462082Seschrock 		return (Z_ERR);
9472082Seschrock 	}
9482082Seschrock 
9492082Seschrock 	return (Z_OK);
9502082Seschrock }
951