Home | History | Annotate | Download | only in zoneadm
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 /*
     23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 /*
     28  * This file contains the functions used to support the ZFS integration
     29  * with zones.  This includes validation (e.g. zonecfg dataset), cloning,
     30  * file system creation and destruction.
     31  */
     32 
     33 #include <stdio.h>
     34 #include <errno.h>
     35 #include <unistd.h>
     36 #include <string.h>
     37 #include <locale.h>
     38 #include <libintl.h>
     39 #include <sys/stat.h>
     40 #include <sys/statvfs.h>
     41 #include <libgen.h>
     42 #include <libzonecfg.h>
     43 #include <sys/mnttab.h>
     44 #include <libzfs.h>
     45 #include <sys/mntent.h>
     46 #include <values.h>
     47 
     48 #include "zoneadm.h"
     49 
     50 libzfs_handle_t *g_zfs;
     51 
     52 typedef struct zfs_mount_data {
     53 	char		*match_name;
     54 	zfs_handle_t	*match_handle;
     55 } zfs_mount_data_t;
     56 
     57 typedef struct zfs_snapshot_data {
     58 	char	*match_name;	/* zonename@SUNWzone */
     59 	int	len;		/* strlen of match_name */
     60 	int	max;		/* highest digit appended to snap name */
     61 	int	num;		/* number of snapshots to rename */
     62 	int	cntr;		/* counter for renaming snapshots */
     63 } zfs_snapshot_data_t;
     64 
     65 typedef struct clone_data {
     66 	zfs_handle_t	*clone_zhp;	/* clone dataset to promote */
     67 	time_t		origin_creation; /* snapshot creation time of clone */
     68 	const char	*snapshot;	/* snapshot of dataset being demoted */
     69 } clone_data_t;
     70 
     71 /*
     72  * A ZFS file system iterator call-back function which is used to validate
     73  * datasets imported into the zone.
     74  */
     75 /* ARGSUSED */
     76 static int
     77 check_zvol(zfs_handle_t *zhp, void *unused)
     78 {
     79 	int ret;
     80 
     81 	if (zfs_get_type(zhp) == ZFS_TYPE_VOLUME) {
     82 		/*
     83 		 * TRANSLATION_NOTE
     84 		 * zfs and dataset are literals that should not be translated.
     85 		 */
     86 		(void) fprintf(stderr, gettext("cannot verify zfs dataset %s: "
     87 		    "volumes cannot be specified as a zone dataset resource\n"),
     88 		    zfs_get_name(zhp));
     89 		ret = -1;
     90 	} else {
     91 		ret = zfs_iter_children(zhp, check_zvol, NULL);
     92 	}
     93 
     94 	zfs_close(zhp);
     95 
     96 	return (ret);
     97 }
     98 
     99 /*
    100  * A ZFS file system iterator call-back function which returns the
    101  * zfs_handle_t for a ZFS file system on the specified mount point.
    102  */
    103 static int
    104 match_mountpoint(zfs_handle_t *zhp, void *data)
    105 {
    106 	int			res;
    107 	zfs_mount_data_t	*cbp;
    108 	char			mp[ZFS_MAXPROPLEN];
    109 
    110 	if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) {
    111 		zfs_close(zhp);
    112 		return (0);
    113 	}
    114 
    115 	/* First check if the dataset is mounted. */
    116 	if (zfs_prop_get(zhp, ZFS_PROP_MOUNTED, mp, sizeof (mp), NULL, NULL,
    117 	    0, B_FALSE) != 0 || strcmp(mp, "no") == 0) {
    118 		zfs_close(zhp);
    119 		return (0);
    120 	}
    121 
    122 	/* Now check mount point. */
    123 	if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mp, sizeof (mp), NULL, NULL,
    124 	    0, B_FALSE) != 0) {
    125 		zfs_close(zhp);
    126 		return (0);
    127 	}
    128 
    129 	cbp = (zfs_mount_data_t *)data;
    130 
    131 	if (strcmp(mp, "legacy") == 0) {
    132 		/* If legacy, must look in mnttab for mountpoint. */
    133 		FILE		*fp;
    134 		struct mnttab	entry;
    135 		const char	*nm;
    136 
    137 		nm = zfs_get_name(zhp);
    138 		if ((fp = fopen(MNTTAB, "r")) == NULL) {
    139 			zfs_close(zhp);
    140 			return (0);
    141 		}
    142 
    143 		while (getmntent(fp, &entry) == 0) {
    144 			if (strcmp(nm, entry.mnt_special) == 0) {
    145 				if (strcmp(entry.mnt_mountp, cbp->match_name)
    146 				    == 0) {
    147 					(void) fclose(fp);
    148 					cbp->match_handle = zhp;
    149 					return (1);
    150 				}
    151 				break;
    152 			}
    153 		}
    154 		(void) fclose(fp);
    155 
    156 	} else if (strcmp(mp, cbp->match_name) == 0) {
    157 		cbp->match_handle = zhp;
    158 		return (1);
    159 	}
    160 
    161 	/* Iterate over any nested datasets. */
    162 	res = zfs_iter_filesystems(zhp, match_mountpoint, data);
    163 	zfs_close(zhp);
    164 	return (res);
    165 }
    166 
    167 /*
    168  * Get ZFS handle for the specified mount point.
    169  */
    170 static zfs_handle_t *
    171 mount2zhandle(char *mountpoint)
    172 {
    173 	zfs_mount_data_t	cb;
    174 
    175 	cb.match_name = mountpoint;
    176 	cb.match_handle = NULL;
    177 	(void) zfs_iter_root(g_zfs, match_mountpoint, &cb);
    178 	return (cb.match_handle);
    179 }
    180 
    181 /*
    182  * Check if there is already a file system (zfs or any other type) mounted on
    183  * path.
    184  */
    185 static boolean_t
    186 is_mountpnt(char *path)
    187 {
    188 	FILE		*fp;
    189 	struct mnttab	entry;
    190 
    191 	if ((fp = fopen(MNTTAB, "r")) == NULL)
    192 		return (B_FALSE);
    193 
    194 	while (getmntent(fp, &entry) == 0) {
    195 		if (strcmp(path, entry.mnt_mountp) == 0) {
    196 			(void) fclose(fp);
    197 			return (B_TRUE);
    198 		}
    199 	}
    200 
    201 	(void) fclose(fp);
    202 	return (B_FALSE);
    203 }
    204 
    205 /*
    206  * Run the brand's pre-snapshot hook before we take a ZFS snapshot of the zone.
    207  */
    208 static int
    209 pre_snapshot(char *presnapbuf)
    210 {
    211 	int status;
    212 
    213 	/* No brand-specific handler */
    214 	if (presnapbuf[0] == '\0')
    215 		return (Z_OK);
    216 
    217 	/* Run the hook */
    218 	status = do_subproc(presnapbuf);
    219 	if ((status = subproc_status(gettext("brand-specific presnapshot"),
    220 	    status, B_FALSE)) != ZONE_SUBPROC_OK)
    221 		return (Z_ERR);
    222 
    223 	return (Z_OK);
    224 }
    225 
    226 /*
    227  * Run the brand's post-snapshot hook after we take a ZFS snapshot of the zone.
    228  */
    229 static int
    230 post_snapshot(char *postsnapbuf)
    231 {
    232 	int status;
    233 
    234 	/* No brand-specific handler */
    235 	if (postsnapbuf[0] == '\0')
    236 		return (Z_OK);
    237 
    238 	/* Run the hook */
    239 	status = do_subproc(postsnapbuf);
    240 	if ((status = subproc_status(gettext("brand-specific postsnapshot"),
    241 	    status, B_FALSE)) != ZONE_SUBPROC_OK)
    242 		return (Z_ERR);
    243 
    244 	return (Z_OK);
    245 }
    246 
    247 /*
    248  * This is a ZFS snapshot iterator call-back function which returns the
    249  * highest number of SUNWzone snapshots that have been taken.
    250  */
    251 static int
    252 get_snap_max(zfs_handle_t *zhp, void *data)
    253 {
    254 	int			res;
    255 	zfs_snapshot_data_t	*cbp;
    256 
    257 	if (zfs_get_type(zhp) != ZFS_TYPE_SNAPSHOT) {
    258 		zfs_close(zhp);
    259 		return (0);
    260 	}
    261 
    262 	cbp = (zfs_snapshot_data_t *)data;
    263 
    264 	if (strncmp(zfs_get_name(zhp), cbp->match_name, cbp->len) == 0) {
    265 		char	*nump;
    266 		int	num;
    267 
    268 		cbp->num++;
    269 		nump = (char *)(zfs_get_name(zhp) + cbp->len);
    270 		num = atoi(nump);
    271 		if (num > cbp->max)
    272 			cbp->max = num;
    273 	}
    274 
    275 	res = zfs_iter_snapshots(zhp, get_snap_max, data);
    276 	zfs_close(zhp);
    277 	return (res);
    278 }
    279 
    280 /*
    281  * Take a ZFS snapshot to be used for cloning the zone.
    282  */
    283 static int
    284 take_snapshot(zfs_handle_t *zhp, char *snapshot_name, int snap_size,
    285     char *presnapbuf, char *postsnapbuf)
    286 {
    287 	int			res;
    288 	char			template[ZFS_MAXNAMELEN];
    289 	zfs_snapshot_data_t	cb;
    290 
    291 	/*
    292 	 * First we need to figure out the next available name for the
    293 	 * zone snapshot.  Look through the list of zones snapshots for
    294 	 * this file system to determine the maximum snapshot name.
    295 	 */
    296 	if (snprintf(template, sizeof (template), "%s@SUNWzone",
    297 	    zfs_get_name(zhp)) >=  sizeof (template))
    298 		return (Z_ERR);
    299 
    300 	cb.match_name = template;
    301 	cb.len = strlen(template);
    302 	cb.max = 0;
    303 
    304 	if (zfs_iter_snapshots(zhp, get_snap_max, &cb) != 0)
    305 		return (Z_ERR);
    306 
    307 	cb.max++;
    308 
    309 	if (snprintf(snapshot_name, snap_size, "%s@SUNWzone%d",
    310 	    zfs_get_name(zhp), cb.max) >= snap_size)
    311 		return (Z_ERR);
    312 
    313 	if (pre_snapshot(presnapbuf) != Z_OK)
    314 		return (Z_ERR);
    315 	res = zfs_snapshot(g_zfs, snapshot_name, B_FALSE, NULL);
    316 	if (post_snapshot(postsnapbuf) != Z_OK)
    317 		return (Z_ERR);
    318 
    319 	if (res != 0)
    320 		return (Z_ERR);
    321 	return (Z_OK);
    322 }
    323 
    324 /*
    325  * We are using an explicit snapshot from some earlier point in time so
    326  * we need to validate it.  Run the brand specific hook.
    327  */
    328 static int
    329 validate_snapshot(char *snapshot_name, char *snap_path, char *validsnapbuf)
    330 {
    331 	int status;
    332 	char cmdbuf[MAXPATHLEN];
    333 
    334 	/* No brand-specific handler */
    335 	if (validsnapbuf[0] == '\0')
    336 		return (Z_OK);
    337 
    338 	/* pass args - snapshot_name & snap_path */
    339 	if (snprintf(cmdbuf, sizeof (cmdbuf), "%s %s %s", validsnapbuf,
    340 	    snapshot_name, snap_path) >= sizeof (cmdbuf)) {
    341 		zerror("Command line too long");
    342 		return (Z_ERR);
    343 	}
    344 
    345 	/* Run the hook */
    346 	status = do_subproc(cmdbuf);
    347 	if ((status = subproc_status(gettext("brand-specific validatesnapshot"),
    348 	    status, B_FALSE)) != ZONE_SUBPROC_OK)
    349 		return (Z_ERR);
    350 
    351 	return (Z_OK);
    352 }
    353 
    354 /*
    355  * Remove the sw inventory file from inside this zonepath that we picked up out
    356  * of the snapshot.
    357  */
    358 static int
    359 clean_out_clone()
    360 {
    361 	int err;
    362 	zone_dochandle_t handle;
    363 
    364 	if ((handle = zonecfg_init_handle()) == NULL) {
    365 		zperror(cmd_to_str(CMD_CLONE), B_TRUE);
    366 		return (Z_ERR);
    367 	}
    368 
    369 	if ((err = zonecfg_get_handle(target_zone, handle)) != Z_OK) {
    370 		errno = err;
    371 		zperror(cmd_to_str(CMD_CLONE), B_TRUE);
    372 		zonecfg_fini_handle(handle);
    373 		return (Z_ERR);
    374 	}
    375 
    376 	zonecfg_rm_detached(handle, B_FALSE);
    377 	zonecfg_fini_handle(handle);
    378 
    379 	return (Z_OK);
    380 }
    381 
    382 /*
    383  * Make a ZFS clone on zonepath from snapshot_name.
    384  */
    385 static int
    386 clone_snap(char *snapshot_name, char *zonepath)
    387 {
    388 	int		res = Z_OK;
    389 	int		err;
    390 	zfs_handle_t	*zhp;
    391 	zfs_handle_t	*clone;
    392 	nvlist_t	*props = NULL;
    393 
    394 	if ((zhp = zfs_open(g_zfs, snapshot_name, ZFS_TYPE_SNAPSHOT)) == NULL)
    395 		return (Z_NO_ENTRY);
    396 
    397 	(void) printf(gettext("Cloning snapshot %s\n"), snapshot_name);
    398 
    399 	if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0 ||
    400 	    nvlist_add_string(props, zfs_prop_to_name(ZFS_PROP_SHARENFS),
    401 	    "off") != 0) {
    402 		if (props != NULL)
    403 			nvlist_free(props);
    404 		(void) fprintf(stderr, gettext("could not create ZFS clone "
    405 		    "%s: out of memory\n"), zonepath);
    406 		return (Z_ERR);
    407 	}
    408 
    409 	err = zfs_clone(zhp, zonepath, props);
    410 	zfs_close(zhp);
    411 
    412 	nvlist_free(props);
    413 
    414 	if (err != 0)
    415 		return (Z_ERR);
    416 
    417 	/* create the mountpoint if necessary */
    418 	if ((clone = zfs_open(g_zfs, zonepath, ZFS_TYPE_DATASET)) == NULL)
    419 		return (Z_ERR);
    420 
    421 	/*
    422 	 * The clone has been created so we need to print a diagnostic
    423 	 * message if one of the following steps fails for some reason.
    424 	 */
    425 	if (zfs_mount(clone, NULL, 0) != 0) {
    426 		(void) fprintf(stderr, gettext("could not mount ZFS clone "
    427 		    "%s\n"), zfs_get_name(clone));
    428 		res = Z_ERR;
    429 
    430 	} else if (clean_out_clone() != Z_OK) {
    431 		(void) fprintf(stderr, gettext("could not remove the "
    432 		    "software inventory from ZFS clone %s\n"),
    433 		    zfs_get_name(clone));
    434 		res = Z_ERR;
    435 	}
    436 
    437 	zfs_close(clone);
    438 	return (res);
    439 }
    440 
    441 /*
    442  * This function takes a zonepath and attempts to determine what the ZFS
    443  * file system name (not mountpoint) should be for that path.  We do not
    444  * assume that zonepath is an existing directory or ZFS fs since we use
    445  * this function as part of the process of creating a new ZFS fs or clone.
    446  *
    447  * The way this works is that we look at the parent directory of the zonepath
    448  * to see if it is a ZFS fs.  If it is, we get the name of that ZFS fs and
    449  * append the last component of the zonepath to generate the ZFS name for the
    450  * zonepath.  This matches the algorithm that ZFS uses for automatically
    451  * mounting a new fs after it is created.
    452  *
    453  * Although a ZFS fs can be mounted anywhere, we don't worry about handling
    454  * all of the complexity that a user could possibly configure with arbitrary
    455  * mounts since there is no way to generate a ZFS name from a random path in
    456  * the file system.  We only try to handle the automatic mounts that ZFS does
    457  * for each file system.  ZFS restricts this so that a new fs must be created
    458  * in an existing parent ZFS fs.  It then automatically mounts the new fs
    459  * directly under the mountpoint for the parent fs using the last component
    460  * of the name as the mountpoint directory.
    461  *
    462  * For example:
    463  *    Name			Mountpoint
    464  *    space/eng/dev/test/zone1	/project1/eng/dev/test/zone1
    465  *
    466  * Return Z_OK if the path mapped to a ZFS file system name, otherwise return
    467  * Z_ERR.
    468  */
    469 static int
    470 path2name(char *zonepath, char *zfs_name, int len)
    471 {
    472 	int		res;
    473 	char		*bnm, *dnm, *dname, *bname;
    474 	zfs_handle_t	*zhp;
    475 	struct stat	stbuf;
    476 
    477 	/*
    478 	 * We need two tmp strings to handle paths directly in / (e.g. /foo)
    479 	 * since dirname will overwrite the first char after "/" in this case.
    480 	 */
    481 	if ((bnm = strdup(zonepath)) == NULL)
    482 		return (Z_ERR);
    483 
    484 	if ((dnm = strdup(zonepath)) == NULL) {
    485 		free(bnm);
    486 		return (Z_ERR);
    487 	}
    488 
    489 	bname = basename(bnm);
    490 	dname = dirname(dnm);
    491 
    492 	/*
    493 	 * This is a quick test to save iterating over all of the zfs datasets
    494 	 * on the system (which can be a lot).  If the parent dir is not in a
    495 	 * ZFS fs, then we're done.
    496 	 */
    497 	if (stat(dname, &stbuf) != 0 || !S_ISDIR(stbuf.st_mode) ||
    498 	    strcmp(stbuf.st_fstype, MNTTYPE_ZFS) != 0) {
    499 		free(bnm);
    500 		free(dnm);
    501 		return (Z_ERR);
    502 	}
    503 
    504 	/* See if the parent directory is its own ZFS dataset. */
    505 	if ((zhp = mount2zhandle(dname)) == NULL) {
    506 		/*
    507 		 * The parent is not a ZFS dataset so we can't automatically
    508 		 * create a dataset on the given path.
    509 		 */
    510 		free(bnm);
    511 		free(dnm);
    512 		return (Z_ERR);
    513 	}
    514 
    515 	res = snprintf(zfs_name, len, "%s/%s", zfs_get_name(zhp), bname);
    516 
    517 	free(bnm);
    518 	free(dnm);
    519 	zfs_close(zhp);
    520 	if (res >= len)
    521 		return (Z_ERR);
    522 
    523 	return (Z_OK);
    524 }
    525 
    526 /*
    527  * A ZFS file system iterator call-back function used to determine if the
    528  * file system has dependents (snapshots & clones).
    529  */
    530 /* ARGSUSED */
    531 static int
    532 has_dependent(zfs_handle_t *zhp, void *data)
    533 {
    534 	zfs_close(zhp);
    535 	return (1);
    536 }
    537 
    538 /*
    539  * Given a snapshot name, get the file system path where the snapshot lives.
    540  * A snapshot name is of the form fs_name@snap_name.  For example, snapshot
    541  * pl/zones/z1@SUNWzone1 would have a path of
    542  * /pl/zones/z1/.zfs/snapshot/SUNWzone1.
    543  */
    544 static int
    545 snap2path(char *snap_name, char *path, int len)
    546 {
    547 	char		*p;
    548 	zfs_handle_t	*zhp;
    549 	char		mp[ZFS_MAXPROPLEN];
    550 
    551 	if ((p = strrchr(snap_name, '@')) == NULL)
    552 		return (Z_ERR);
    553 
    554 	/* Get the file system name from the snap_name. */
    555 	*p = '\0';
    556 	zhp = zfs_open(g_zfs, snap_name, ZFS_TYPE_DATASET);
    557 	*p = '@';
    558 	if (zhp == NULL)
    559 		return (Z_ERR);
    560 
    561 	/* Get the file system mount point. */
    562 	if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mp, sizeof (mp), NULL, NULL,
    563 	    0, B_FALSE) != 0) {
    564 		zfs_close(zhp);
    565 		return (Z_ERR);
    566 	}
    567 	zfs_close(zhp);
    568 
    569 	p++;
    570 	if (snprintf(path, len, "%s/.zfs/snapshot/%s", mp, p) >= len)
    571 		return (Z_ERR);
    572 
    573 	return (Z_OK);
    574 }
    575 
    576 /*
    577  * This callback function is used to iterate through a snapshot's dependencies
    578  * to find a filesystem that is a direct clone of the snapshot being iterated.
    579  */
    580 static int
    581 get_direct_clone(zfs_handle_t *zhp, void *data)
    582 {
    583 	clone_data_t	*cd = data;
    584 	char		origin[ZFS_MAXNAMELEN];
    585 	char		ds_path[ZFS_MAXNAMELEN];
    586 
    587 	if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) {
    588 		zfs_close(zhp);
    589 		return (0);
    590 	}
    591 
    592 	(void) strlcpy(ds_path, zfs_get_name(zhp), sizeof (ds_path));
    593 
    594 	/* Make sure this is a direct clone of the snapshot we're iterating. */
    595 	if (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, origin, sizeof (origin), NULL,
    596 	    NULL, 0, B_FALSE) != 0 || strcmp(origin, cd->snapshot) != 0) {
    597 		zfs_close(zhp);
    598 		return (0);
    599 	}
    600 
    601 	if (cd->clone_zhp != NULL)
    602 		zfs_close(cd->clone_zhp);
    603 
    604 	cd->clone_zhp = zhp;
    605 	return (1);
    606 }
    607 
    608 /*
    609  * A ZFS file system iterator call-back function used to determine the clone
    610  * to promote.  This function finds the youngest (i.e. last one taken) snapshot
    611  * that has a clone.  If found, it returns a reference to that clone in the
    612  * callback data.
    613  */
    614 static int
    615 find_clone(zfs_handle_t *zhp, void *data)
    616 {
    617 	clone_data_t	*cd = data;
    618 	time_t		snap_creation;
    619 	int		zret = 0;
    620 
    621 	/* If snapshot has no clones, skip it */
    622 	if (zfs_prop_get_int(zhp, ZFS_PROP_NUMCLONES) == 0) {
    623 		zfs_close(zhp);
    624 		return (0);
    625 	}
    626 
    627 	cd->snapshot = zfs_get_name(zhp);
    628 
    629 	/* Get the creation time of this snapshot */
    630 	snap_creation = (time_t)zfs_prop_get_int(zhp, ZFS_PROP_CREATION);
    631 
    632 	/*
    633 	 * If this snapshot's creation time is greater than (i.e. younger than)
    634 	 * the current youngest snapshot found, iterate this snapshot to
    635 	 * get the right clone.
    636 	 */
    637 	if (snap_creation >= cd->origin_creation) {
    638 		/*
    639 		 * Iterate the dependents of this snapshot to find a clone
    640 		 * that's a direct dependent.
    641 		 */
    642 		if ((zret = zfs_iter_dependents(zhp, B_FALSE, get_direct_clone,
    643 		    cd)) == -1) {
    644 			zfs_close(zhp);
    645 			return (1);
    646 		} else if (zret == 1) {
    647 			/*
    648 			 * Found a clone, update the origin_creation time
    649 			 * in the callback data.
    650 			 */
    651 			cd->origin_creation = snap_creation;
    652 		}
    653 	}
    654 
    655 	zfs_close(zhp);
    656 	return (0);
    657 }
    658 
    659 /*
    660  * A ZFS file system iterator call-back function used to remove standalone
    661  * snapshots.
    662  */
    663 /* ARGSUSED */
    664 static int
    665 rm_snap(zfs_handle_t *zhp, void *data)
    666 {
    667 	/* If snapshot has clones, something is wrong */
    668 	if (zfs_prop_get_int(zhp, ZFS_PROP_NUMCLONES) != 0) {
    669 		zfs_close(zhp);
    670 		return (1);
    671 	}
    672 
    673 	if (zfs_unmount(zhp, NULL, 0) == 0) {
    674 		(void) zfs_destroy(zhp, B_FALSE);
    675 	}
    676 
    677 	zfs_close(zhp);
    678 	return (0);
    679 }
    680 
    681 /*
    682  * A ZFS snapshot iterator call-back function which renames snapshots.
    683  */
    684 static int
    685 rename_snap(zfs_handle_t *zhp, void *data)
    686 {
    687 	int			res;
    688 	zfs_snapshot_data_t	*cbp;
    689 	char			template[ZFS_MAXNAMELEN];
    690 
    691 	cbp = (zfs_snapshot_data_t *)data;
    692 
    693 	/*
    694 	 * When renaming snapshots with the iterator, the iterator can see
    695 	 * the same snapshot after we've renamed up in the namespace.  To
    696 	 * prevent this we check the count for the number of snapshots we have
    697 	 * to rename and stop at that point.
    698 	 */
    699 	if (cbp->cntr >= cbp->num) {
    700 		zfs_close(zhp);
    701 		return (0);
    702 	}
    703 
    704 	if (zfs_get_type(zhp) != ZFS_TYPE_SNAPSHOT) {
    705 		zfs_close(zhp);
    706 		return (0);
    707 	}
    708 
    709 	/* Only rename the snapshots we automatically generate when we clone. */
    710 	if (strncmp(zfs_get_name(zhp), cbp->match_name, cbp->len) != 0) {
    711 		zfs_close(zhp);
    712 		return (0);
    713 	}
    714 
    715 	(void) snprintf(template, sizeof (template), "%s%d", cbp->match_name,
    716 	    cbp->max++);
    717 
    718 	res = (zfs_rename(zhp, template, B_FALSE) != 0);
    719 	if (res != 0)
    720 		(void) fprintf(stderr, gettext("failed to rename snapshot %s "
    721 		    "to %s: %s\n"), zfs_get_name(zhp), template,
    722 		    libzfs_error_description(g_zfs));
    723 
    724 	cbp->cntr++;
    725 
    726 	zfs_close(zhp);
    727 	return (res);
    728 }
    729 
    730 /*
    731  * Rename the source dataset's snapshots that are automatically generated when
    732  * we clone a zone so that there won't be a name collision when we promote the
    733  * cloned dataset.  Once the snapshots have been renamed, then promote the
    734  * clone.
    735  *
    736  * The snapshot rename process gets the highest number on the snapshot names
    737  * (the format is zonename@SUNWzoneXX where XX are digits) on both the source
    738  * and clone datasets, then renames the source dataset snapshots starting at
    739  * the next number.
    740  */
    741 static int
    742 promote_clone(zfs_handle_t *src_zhp, zfs_handle_t *cln_zhp)
    743 {
    744 	zfs_snapshot_data_t	sd;
    745 	char			nm[ZFS_MAXNAMELEN];
    746 	char			template[ZFS_MAXNAMELEN];
    747 
    748 	(void) strlcpy(nm, zfs_get_name(cln_zhp), sizeof (nm));
    749 	/*
    750 	 * Start by getting the clone's snapshot max which we use
    751 	 * during the rename of the original dataset's snapshots.
    752 	 */
    753 	(void) snprintf(template, sizeof (template), "%s@SUNWzone", nm);
    754 	sd.match_name = template;
    755 	sd.len = strlen(template);
    756 	sd.max = 0;
    757 
    758 	if (zfs_iter_snapshots(cln_zhp, get_snap_max, &sd) != 0)
    759 		return (Z_ERR);
    760 
    761 	/*
    762 	 * Now make sure the source's snapshot max is at least as high as
    763 	 * the clone's snapshot max.
    764 	 */
    765 	(void) snprintf(template, sizeof (template), "%s@SUNWzone",
    766 	    zfs_get_name(src_zhp));
    767 	sd.match_name = template;
    768 	sd.len = strlen(template);
    769 	sd.num = 0;
    770 
    771 	if (zfs_iter_snapshots(src_zhp, get_snap_max, &sd) != 0)
    772 		return (Z_ERR);
    773 
    774 	/*
    775 	 * Now rename the source dataset's snapshots so there's no
    776 	 * conflict when we promote the clone.
    777 	 */
    778 	sd.max++;
    779 	sd.cntr = 0;
    780 	if (zfs_iter_snapshots(src_zhp, rename_snap, &sd) != 0)
    781 		return (Z_ERR);
    782 
    783 	/* close and reopen the clone dataset to get the latest info */
    784 	zfs_close(cln_zhp);
    785 	if ((cln_zhp = zfs_open(g_zfs, nm, ZFS_TYPE_FILESYSTEM)) == NULL)
    786 		return (Z_ERR);
    787 
    788 	if (zfs_promote(cln_zhp) != 0) {
    789 		(void) fprintf(stderr, gettext("failed to promote %s: %s\n"),
    790 		    nm, libzfs_error_description(g_zfs));
    791 		return (Z_ERR);
    792 	}
    793 
    794 	zfs_close(cln_zhp);
    795 	return (Z_OK);
    796 }
    797 
    798 /*
    799  * Promote the youngest clone.  That clone will then become the origin of all
    800  * of the other clones that were hanging off of the source dataset.
    801  */
    802 int
    803 promote_all_clones(zfs_handle_t *zhp)
    804 {
    805 	clone_data_t	cd;
    806 	char		nm[ZFS_MAXNAMELEN];
    807 
    808 	cd.clone_zhp = NULL;
    809 	cd.origin_creation = 0;
    810 	cd.snapshot = NULL;
    811 
    812 	if (zfs_iter_snapshots(zhp, find_clone, &cd) != 0) {
    813 		zfs_close(zhp);
    814 		return (Z_ERR);
    815 	}
    816 
    817 	/* Nothing to promote. */
    818 	if (cd.clone_zhp == NULL)
    819 		return (Z_OK);
    820 
    821 	/* Found the youngest clone to promote.  Promote it. */
    822 	if (promote_clone(zhp, cd.clone_zhp) != 0) {
    823 		zfs_close(cd.clone_zhp);
    824 		zfs_close(zhp);
    825 		return (Z_ERR);
    826 	}
    827 
    828 	/* close and reopen the main dataset to get the latest info */
    829 	(void) strlcpy(nm, zfs_get_name(zhp), sizeof (nm));
    830 	zfs_close(zhp);
    831 	if ((zhp = zfs_open(g_zfs, nm, ZFS_TYPE_FILESYSTEM)) == NULL)
    832 		return (Z_ERR);
    833 
    834 	return (Z_OK);
    835 }
    836 
    837 /*
    838  * Clone a pre-existing ZFS snapshot, either by making a direct ZFS clone, if
    839  * possible, or by copying the data from the snapshot to the zonepath.
    840  */
    841 int
    842 clone_snapshot_zfs(char *snap_name, char *zonepath, char *validatesnap)
    843 {
    844 	int	err = Z_OK;
    845 	char	clone_name[MAXPATHLEN];
    846 	char	snap_path[MAXPATHLEN];
    847 
    848 	if (snap2path(snap_name, snap_path, sizeof (snap_path)) != Z_OK) {
    849 		(void) fprintf(stderr, gettext("unable to find path for %s.\n"),
    850 		    snap_name);
    851 		return (Z_ERR);
    852 	}
    853 
    854 	if (validate_snapshot(snap_name, snap_path, validatesnap) != Z_OK)
    855 		return (Z_NO_ENTRY);
    856 
    857 	/*
    858 	 * The zonepath cannot be ZFS cloned, try to copy the data from
    859 	 * within the snapshot to the zonepath.
    860 	 */
    861 	if (path2name(zonepath, clone_name, sizeof (clone_name)) != Z_OK) {
    862 		if ((err = clone_copy(snap_path, zonepath)) == Z_OK)
    863 			if (clean_out_clone() != Z_OK)
    864 				(void) fprintf(stderr,
    865 				    gettext("could not remove the "
    866 				    "software inventory from %s\n"), zonepath);
    867 
    868 		return (err);
    869 	}
    870 
    871 	if ((err = clone_snap(snap_name, clone_name)) != Z_OK) {
    872 		if (err != Z_NO_ENTRY) {
    873 			/*
    874 			 * Cloning the snapshot failed.  Fall back to trying
    875 			 * to install the zone by copying from the snapshot.
    876 			 */
    877 			if ((err = clone_copy(snap_path, zonepath)) == Z_OK)
    878 				if (clean_out_clone() != Z_OK)
    879 					(void) fprintf(stderr,
    880 					    gettext("could not remove the "
    881 					    "software inventory from %s\n"),
    882 					    zonepath);
    883 		} else {
    884 			/*
    885 			 * The snapshot is unusable for some reason so restore
    886 			 * the zone state to configured since we were unable to
    887 			 * actually do anything about getting the zone
    888 			 * installed.
    889 			 */
    890 			int tmp;
    891 
    892 			if ((tmp = zone_set_state(target_zone,
    893 			    ZONE_STATE_CONFIGURED)) != Z_OK) {
    894 				errno = tmp;
    895 				zperror2(target_zone,
    896 				    gettext("could not set state"));
    897 			}
    898 		}
    899 	}
    900 
    901 	return (err);
    902 }
    903 
    904 /*
    905  * Attempt to clone a source_zone to a target zonepath by using a ZFS clone.
    906  */
    907 int
    908 clone_zfs(char *source_zonepath, char *zonepath, char *presnapbuf,
    909     char *postsnapbuf)
    910 {
    911 	zfs_handle_t	*zhp;
    912 	char		clone_name[MAXPATHLEN];
    913 	char		snap_name[MAXPATHLEN];
    914 
    915 	/*
    916 	 * Try to get a zfs handle for the source_zonepath.  If this fails
    917 	 * the source_zonepath is not ZFS so return an error.
    918 	 */
    919 	if ((zhp = mount2zhandle(source_zonepath)) == NULL)
    920 		return (Z_ERR);
    921 
    922 	/*
    923 	 * Check if there is a file system already mounted on zonepath.  If so,
    924 	 * we can't clone to the path so we should fall back to copying.
    925 	 */
    926 	if (is_mountpnt(zonepath)) {
    927 		zfs_close(zhp);
    928 		(void) fprintf(stderr,
    929 		    gettext("A file system is already mounted on %s,\n"
    930 		    "preventing use of a ZFS clone.\n"), zonepath);
    931 		return (Z_ERR);
    932 	}
    933 
    934 	/*
    935 	 * Instead of using path2name to get the clone name from the zonepath,
    936 	 * we could generate a name from the source zone ZFS name.  However,
    937 	 * this would mean we would create the clone under the ZFS fs of the
    938 	 * source instead of what the zonepath says.  For example,
    939 	 *
    940 	 * source_zonepath		zonepath
    941 	 * /pl/zones/dev/z1		/pl/zones/deploy/z2
    942 	 *
    943 	 * We don't want the clone to be under "dev", we want it under
    944 	 * "deploy", so that we can leverage the normal attribute inheritance
    945 	 * that ZFS provides in the fs hierarchy.
    946 	 */
    947 	if (path2name(zonepath, clone_name, sizeof (clone_name)) != Z_OK) {
    948 		zfs_close(zhp);
    949 		return (Z_ERR);
    950 	}
    951 
    952 	if (take_snapshot(zhp, snap_name, sizeof (snap_name), presnapbuf,
    953 	    postsnapbuf) != Z_OK) {
    954 		zfs_close(zhp);
    955 		return (Z_ERR);
    956 	}
    957 	zfs_close(zhp);
    958 
    959 	if (clone_snap(snap_name, clone_name) != Z_OK) {
    960 		/* Clean up the snapshot we just took. */
    961 		if ((zhp = zfs_open(g_zfs, snap_name, ZFS_TYPE_SNAPSHOT))
    962 		    != NULL) {
    963 			if (zfs_unmount(zhp, NULL, 0) == 0)
    964 				(void) zfs_destroy(zhp, B_FALSE);
    965 			zfs_close(zhp);
    966 		}
    967 
    968 		return (Z_ERR);
    969 	}
    970 
    971 	(void) printf(gettext("Instead of copying, a ZFS clone has been "
    972 	    "created for this zone.\n"));
    973 
    974 	return (Z_OK);
    975 }
    976 
    977 /*
    978  * Attempt to create a ZFS file system for the specified zonepath.
    979  * We either will successfully create a ZFS file system and get it mounted
    980  * on the zonepath or we don't.  The caller doesn't care since a regular
    981  * directory is used for the zonepath if no ZFS file system is mounted there.
    982  */
    983 void
    984 create_zfs_zonepath(char *zonepath)
    985 {
    986 	zfs_handle_t	*zhp;
    987 	char		zfs_name[MAXPATHLEN];
    988 	nvlist_t	*props = NULL;
    989 
    990 	if (path2name(zonepath, zfs_name, sizeof (zfs_name)) != Z_OK)
    991 		return;
    992 
    993 	/* Check if the dataset already exists. */
    994 	if ((zhp = zfs_open(g_zfs, zfs_name, ZFS_TYPE_DATASET)) != NULL) {
    995 		zfs_close(zhp);
    996 		return;
    997 	}
    998 
    999 	if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0 ||
   1000 	    nvlist_add_string(props, zfs_prop_to_name(ZFS_PROP_SHARENFS),
   1001 	    "off") != 0) {
   1002 		if (props != NULL)
   1003 			nvlist_free(props);
   1004 		(void) fprintf(stderr, gettext("cannot create ZFS dataset %s: "
   1005 		    "out of memory\n"), zfs_name);
   1006 	}
   1007 
   1008 	if (zfs_create(g_zfs, zfs_name, ZFS_TYPE_FILESYSTEM, props) != 0 ||
   1009 	    (zhp = zfs_open(g_zfs, zfs_name, ZFS_TYPE_DATASET)) == NULL) {
   1010 		(void) fprintf(stderr, gettext("cannot create ZFS dataset %s: "
   1011 		    "%s\n"), zfs_name, libzfs_error_description(g_zfs));
   1012 		nvlist_free(props);
   1013 		return;
   1014 	}
   1015 
   1016 	nvlist_free(props);
   1017 
   1018 	if (zfs_mount(zhp, NULL, 0) != 0) {
   1019 		(void) fprintf(stderr, gettext("cannot mount ZFS dataset %s: "
   1020 		    "%s\n"), zfs_name, libzfs_error_description(g_zfs));
   1021 		(void) zfs_destroy(zhp, B_FALSE);
   1022 	} else {
   1023 		if (chmod(zonepath, S_IRWXU) != 0) {
   1024 			(void) fprintf(stderr, gettext("file system %s "
   1025 			    "successfully created, but chmod %o failed: %s\n"),
   1026 			    zfs_name, S_IRWXU, strerror(errno));
   1027 			(void) destroy_zfs(zonepath);
   1028 		} else {
   1029 			(void) printf(gettext("A ZFS file system has been "
   1030 			    "created for this zone.\n"));
   1031 		}
   1032 	}
   1033 
   1034 	zfs_close(zhp);
   1035 }
   1036 
   1037 /*
   1038  * If the zonepath is a ZFS file system, attempt to destroy it.  We return Z_OK
   1039  * if we were able to zfs_destroy the zonepath, otherwise we return Z_ERR
   1040  * which means the caller should clean up the zonepath in the traditional
   1041  * way.
   1042  */
   1043 int
   1044 destroy_zfs(char *zonepath)
   1045 {
   1046 	zfs_handle_t	*zhp;
   1047 	boolean_t	is_clone = B_FALSE;
   1048 	char		origin[ZFS_MAXPROPLEN];
   1049 
   1050 	if ((zhp = mount2zhandle(zonepath)) == NULL)
   1051 		return (Z_ERR);
   1052 
   1053 	if (promote_all_clones(zhp) != 0)
   1054 		return (Z_ERR);
   1055 
   1056 	/* Now cleanup any snapshots remaining. */
   1057 	if (zfs_iter_snapshots(zhp, rm_snap, NULL) != 0) {
   1058 		zfs_close(zhp);
   1059 		return (Z_ERR);
   1060 	}
   1061 
   1062 	/*
   1063 	 * We can't destroy the file system if it has still has dependents.
   1064 	 * There shouldn't be any at this point, but we'll double check.
   1065 	 */
   1066 	if (zfs_iter_dependents(zhp, B_TRUE, has_dependent, NULL) != 0) {
   1067 		(void) fprintf(stderr, gettext("zfs destroy %s failed: the "
   1068 		    "dataset still has dependents\n"), zfs_get_name(zhp));
   1069 		zfs_close(zhp);
   1070 		return (Z_ERR);
   1071 	}
   1072 
   1073 	/*
   1074 	 * This might be a clone.  Try to get the snapshot so we can attempt
   1075 	 * to destroy that as well.
   1076 	 */
   1077 	if (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, origin, sizeof (origin), NULL,
   1078 	    NULL, 0, B_FALSE) == 0)
   1079 		is_clone = B_TRUE;
   1080 
   1081 	if (zfs_unmount(zhp, NULL, 0) != 0) {
   1082 		(void) fprintf(stderr, gettext("zfs unmount %s failed: %s\n"),
   1083 		    zfs_get_name(zhp), libzfs_error_description(g_zfs));
   1084 		zfs_close(zhp);
   1085 		return (Z_ERR);
   1086 	}
   1087 
   1088 	if (zfs_destroy(zhp, B_FALSE) != 0) {
   1089 		/*
   1090 		 * If the destroy fails for some reason, try to remount
   1091 		 * the file system so that we can use "rm -rf" to clean up
   1092 		 * instead.
   1093 		 */
   1094 		(void) fprintf(stderr, gettext("zfs destroy %s failed: %s\n"),
   1095 		    zfs_get_name(zhp), libzfs_error_description(g_zfs));
   1096 		(void) zfs_mount(zhp, NULL, 0);
   1097 		zfs_close(zhp);
   1098 		return (Z_ERR);
   1099 	}
   1100 
   1101 	/*
   1102 	 * If the zone has ever been moved then the mountpoint dir will not be
   1103 	 * cleaned up by the zfs_destroy().  To handle this case try to clean
   1104 	 * it up now but don't worry if it fails, that will be normal.
   1105 	 */
   1106 	(void) rmdir(zonepath);
   1107 
   1108 	(void) printf(gettext("The ZFS file system for this zone has been "
   1109 	    "destroyed.\n"));
   1110 
   1111 	if (is_clone) {
   1112 		zfs_handle_t	*ohp;
   1113 
   1114 		/*
   1115 		 * Try to clean up the snapshot that the clone was taken from.
   1116 		 */
   1117 		if ((ohp = zfs_open(g_zfs, origin,
   1118 		    ZFS_TYPE_SNAPSHOT)) != NULL) {
   1119 			if (zfs_iter_dependents(ohp, B_TRUE, has_dependent,
   1120 			    NULL) == 0 && zfs_unmount(ohp, NULL, 0) == 0)
   1121 				(void) zfs_destroy(ohp, B_FALSE);
   1122 			zfs_close(ohp);
   1123 		}
   1124 	}
   1125 
   1126 	zfs_close(zhp);
   1127 	return (Z_OK);
   1128 }
   1129 
   1130 /*
   1131  * Return true if the path is its own zfs file system.  We determine this
   1132  * by stat-ing the path to see if it is zfs and stat-ing the parent to see
   1133  * if it is a different fs.
   1134  */
   1135 boolean_t
   1136 is_zonepath_zfs(char *zonepath)
   1137 {
   1138 	int res;
   1139 	char *path;
   1140 	char *parent;
   1141 	struct statvfs64 buf1, buf2;
   1142 
   1143 	if (statvfs64(zonepath, &buf1) != 0)
   1144 		return (B_FALSE);
   1145 
   1146 	if (strcmp(buf1.f_basetype, "zfs") != 0)
   1147 		return (B_FALSE);
   1148 
   1149 	if ((path = strdup(zonepath)) == NULL)
   1150 		return (B_FALSE);
   1151 
   1152 	parent = dirname(path);
   1153 	res = statvfs64(parent, &buf2);
   1154 	free(path);
   1155 
   1156 	if (res != 0)
   1157 		return (B_FALSE);
   1158 
   1159 	if (buf1.f_fsid == buf2.f_fsid)
   1160 		return (B_FALSE);
   1161 
   1162 	return (B_TRUE);
   1163 }
   1164 
   1165 /*
   1166  * Implement the fast move of a ZFS file system by simply updating the
   1167  * mountpoint.  Since it is file system already, we don't have the
   1168  * issue of cross-file system copying.
   1169  */
   1170 int
   1171 move_zfs(char *zonepath, char *new_zonepath)
   1172 {
   1173 	int		ret = Z_ERR;
   1174 	zfs_handle_t	*zhp;
   1175 
   1176 	if ((zhp = mount2zhandle(zonepath)) == NULL)
   1177 		return (Z_ERR);
   1178 
   1179 	if (zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
   1180 	    new_zonepath) == 0) {
   1181 		/*
   1182 		 * Clean up the old mount point.  We ignore any failure since
   1183 		 * the zone is already successfully mounted on the new path.
   1184 		 */
   1185 		(void) rmdir(zonepath);
   1186 		ret = Z_OK;
   1187 	}
   1188 
   1189 	zfs_close(zhp);
   1190 
   1191 	return (ret);
   1192 }
   1193 
   1194 /*
   1195  * Validate that the given dataset exists on the system, and that neither it nor
   1196  * its children are zvols.
   1197  *
   1198  * Note that we don't do anything with the 'zoned' property here.  All
   1199  * management is done in zoneadmd when the zone is actually rebooted.  This
   1200  * allows us to automatically set the zoned property even when a zone is
   1201  * rebooted by the administrator.
   1202  */
   1203 int
   1204 verify_datasets(zone_dochandle_t handle)
   1205 {
   1206 	int return_code = Z_OK;
   1207 	struct zone_dstab dstab;
   1208 	zfs_handle_t *zhp;
   1209 	char propbuf[ZFS_MAXPROPLEN];
   1210 	char source[ZFS_MAXNAMELEN];
   1211 	zprop_source_t srctype;
   1212 
   1213 	if (zonecfg_setdsent(handle) != Z_OK) {
   1214 		/*
   1215 		 * TRANSLATION_NOTE
   1216 		 * zfs and dataset are literals that should not be translated.
   1217 		 */
   1218 		(void) fprintf(stderr, gettext("could not verify zfs datasets: "
   1219 		    "unable to enumerate datasets\n"));
   1220 		return (Z_ERR);
   1221 	}
   1222 
   1223 	while (zonecfg_getdsent(handle, &dstab) == Z_OK) {
   1224 
   1225 		if ((zhp = zfs_open(g_zfs, dstab.zone_dataset_name,
   1226 		    ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME)) == NULL) {
   1227 			(void) fprintf(stderr, gettext("could not verify zfs "
   1228 			    "dataset %s: %s\n"), dstab.zone_dataset_name,
   1229 			    libzfs_error_description(g_zfs));
   1230 			return_code = Z_ERR;
   1231 			continue;
   1232 		}
   1233 
   1234 		if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, propbuf,
   1235 		    sizeof (propbuf), &srctype, source,
   1236 		    sizeof (source), 0) == 0 &&
   1237 		    (srctype == ZPROP_SRC_INHERITED)) {
   1238 			(void) fprintf(stderr, gettext("could not verify zfs "
   1239 			    "dataset %s: mountpoint cannot be inherited\n"),
   1240 			    dstab.zone_dataset_name);
   1241 			return_code = Z_ERR;
   1242 			zfs_close(zhp);
   1243 			continue;
   1244 		}
   1245 
   1246 		if (zfs_get_type(zhp) == ZFS_TYPE_VOLUME) {
   1247 			(void) fprintf(stderr, gettext("cannot verify zfs "
   1248 			    "dataset %s: volumes cannot be specified as a "
   1249 			    "zone dataset resource\n"),
   1250 			    dstab.zone_dataset_name);
   1251 			return_code = Z_ERR;
   1252 		}
   1253 
   1254 		if (zfs_iter_children(zhp, check_zvol, NULL) != 0)
   1255 			return_code = Z_ERR;
   1256 
   1257 		zfs_close(zhp);
   1258 	}
   1259 	(void) zonecfg_enddsent(handle);
   1260 
   1261 	return (return_code);
   1262 }
   1263 
   1264 /*
   1265  * Verify that the ZFS dataset exists, and its mountpoint
   1266  * property is set to "legacy".
   1267  */
   1268 int
   1269 verify_fs_zfs(struct zone_fstab *fstab)
   1270 {
   1271 	zfs_handle_t *zhp;
   1272 	char propbuf[ZFS_MAXPROPLEN];
   1273 
   1274 	if ((zhp = zfs_open(g_zfs, fstab->zone_fs_special,
   1275 	    ZFS_TYPE_DATASET)) == NULL) {
   1276 		(void) fprintf(stderr, gettext("could not verify fs %s: "
   1277 		    "could not access zfs dataset '%s'\n"),
   1278 		    fstab->zone_fs_dir, fstab->zone_fs_special);
   1279 		return (Z_ERR);
   1280 	}
   1281 
   1282 	if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) {
   1283 		(void) fprintf(stderr, gettext("cannot verify fs %s: "
   1284 		    "'%s' is not a file system\n"),
   1285 		    fstab->zone_fs_dir, fstab->zone_fs_special);
   1286 		zfs_close(zhp);
   1287 		return (Z_ERR);
   1288 	}
   1289 
   1290 	if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, propbuf, sizeof (propbuf),
   1291 	    NULL, NULL, 0, 0) != 0 || strcmp(propbuf, "legacy") != 0) {
   1292 		(void) fprintf(stderr, gettext("could not verify fs %s: "
   1293 		    "zfs '%s' mountpoint is not \"legacy\"\n"),
   1294 		    fstab->zone_fs_dir, fstab->zone_fs_special);
   1295 		zfs_close(zhp);
   1296 		return (Z_ERR);
   1297 	}
   1298 
   1299 	zfs_close(zhp);
   1300 	return (Z_OK);
   1301 }
   1302 
   1303 int
   1304 init_zfs(void)
   1305 {
   1306 	if ((g_zfs = libzfs_init()) == NULL) {
   1307 		(void) fprintf(stderr, gettext("failed to initialize ZFS "
   1308 		    "library\n"));
   1309 		return (Z_ERR);
   1310 	}
   1311 
   1312 	return (Z_OK);
   1313 }
   1314