xref: /titanic_41/usr/src/cmd/zoneadm/zfs.c (revision 4abb96737d15cd2d6530b0aa7b8404ec911ad940)
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 2006 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * This file contains the functions used to support the ZFS integration
31  * with zones.  This includes validation (e.g. zonecfg dataset), cloning,
32  * file system creation and destruction.
33  */
34 
35 #include <stdio.h>
36 #include <errno.h>
37 #include <unistd.h>
38 #include <string.h>
39 #include <locale.h>
40 #include <libintl.h>
41 #include <sys/stat.h>
42 #include <sys/statvfs.h>
43 #include <libgen.h>
44 #include <libzonecfg.h>
45 #include <sys/mnttab.h>
46 #include <libzfs.h>
47 
48 #include "zoneadm.h"
49 
50 static const char *current_dataset;
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;
59 	int	len;
60 	int	max;
61 } zfs_snapshot_data_t;
62 
63 /*
64  * ZFS error handler to do nothing - do not print the libzfs error messages.
65  */
66 /* ARGSUSED */
67 static void
68 noop_err_handler(const char *fmt, va_list ap)
69 {
70 }
71 
72 /*
73  * Custom error handler for errors incurred as part of verifying datasets.  We
74  * want to trim off the leading 'cannot open ...' to create a better error
75  * message.  The only other way this can fail is if we fail to set the 'zoned'
76  * property.  In this case we just pass the error on verbatim.
77  */
78 static void
79 err_handler(const char *fmt, va_list ap)
80 {
81 	char buf[1024];
82 
83 	(void) vsnprintf(buf, sizeof (buf), fmt, ap);
84 
85 	if (strncmp(gettext("cannot open "), buf,
86 	    strlen(gettext("cannot open "))) == 0)
87 		/*
88 		 * TRANSLATION_NOTE
89 		 * zfs and dataset are literals that should not be translated.
90 		 */
91 		(void) fprintf(stderr, gettext("could not verify zfs "
92 		    "dataset %s%s\n"), current_dataset, strchr(buf, ':'));
93 	else
94 		(void) fprintf(stderr, gettext("could not verify zfs dataset "
95 		    "%s: %s\n"), current_dataset, buf);
96 }
97 
98 /*
99  * A ZFS file system iterator call-back function which is used to validate
100  * datasets imported into the zone.
101  */
102 /* ARGSUSED */
103 static int
104 check_zvol(zfs_handle_t *zhp, void *unused)
105 {
106 	int ret;
107 
108 	if (zfs_get_type(zhp) == ZFS_TYPE_VOLUME) {
109 		/*
110 		 * TRANSLATION_NOTE
111 		 * zfs and dataset are literals that should not be translated.
112 		 */
113 		(void) fprintf(stderr, gettext("cannot verify zfs dataset %s: "
114 		    "volumes cannot be specified as a zone dataset resource\n"),
115 		    zfs_get_name(zhp));
116 		ret = -1;
117 	} else {
118 		ret = zfs_iter_children(zhp, check_zvol, NULL);
119 	}
120 
121 	zfs_close(zhp);
122 
123 	return (ret);
124 }
125 
126 /*
127  * A ZFS file system iterator call-back function which returns the
128  * zfs_handle_t for a ZFS file system on the specified mount point.
129  */
130 static int
131 match_mountpoint(zfs_handle_t *zhp, void *data)
132 {
133 	int			res;
134 	zfs_mount_data_t	*cbp;
135 	char			mp[ZFS_MAXPROPLEN];
136 
137 	if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) {
138 		zfs_close(zhp);
139 		return (0);
140 	}
141 
142 	cbp = (zfs_mount_data_t *)data;
143 	if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mp, sizeof (mp), NULL, NULL,
144 	    0, FALSE) == 0 && strcmp(mp, cbp->match_name) == 0) {
145 		cbp->match_handle = zhp;
146 		return (1);
147 	}
148 
149 	res = zfs_iter_filesystems(zhp, match_mountpoint, data);
150 	zfs_close(zhp);
151 	return (res);
152 }
153 
154 /*
155  * Get ZFS handle for the specified mount point.
156  */
157 static zfs_handle_t *
158 mount2zhandle(char *mountpoint)
159 {
160 	zfs_mount_data_t	cb;
161 
162 	cb.match_name = mountpoint;
163 	cb.match_handle = NULL;
164 	(void) zfs_iter_root(match_mountpoint, &cb);
165 	return (cb.match_handle);
166 }
167 
168 /*
169  * Check if there is already a file system (zfs or any other type) mounted on
170  * path.
171  */
172 static boolean_t
173 is_mountpnt(char *path)
174 {
175 	FILE		*fp;
176 	struct mnttab	entry;
177 
178 	if ((fp = fopen("/etc/mnttab", "r")) == NULL)
179 		return (B_FALSE);
180 
181 	while (getmntent(fp, &entry) == 0) {
182 		if (strcmp(path, entry.mnt_mountp) == 0) {
183 			(void) fclose(fp);
184 			return (B_TRUE);
185 		}
186 	}
187 
188 	(void) fclose(fp);
189 	return (B_FALSE);
190 }
191 
192 /*
193  * Perform any necessary housekeeping tasks we need to do before we take
194  * a ZFS snapshot of the zone.  What this really entails is that we are
195  * taking a sw inventory of the source zone, like we do when we detach,
196  * so that there is the XML manifest in the snapshot.  We use that to
197  * validate the snapshot if it is the source of a clone at some later time.
198  */
199 static int
200 pre_snapshot(char *source_zone)
201 {
202 	int err;
203 	zone_dochandle_t handle;
204 
205 	if ((handle = zonecfg_init_handle()) == NULL) {
206 		zperror(cmd_to_str(CMD_CLONE), B_TRUE);
207 		return (Z_ERR);
208 	}
209 
210 	if ((err = zonecfg_get_handle(source_zone, handle)) != Z_OK) {
211 		errno = err;
212 		zperror(cmd_to_str(CMD_CLONE), B_TRUE);
213 		zonecfg_fini_handle(handle);
214 		return (Z_ERR);
215 	}
216 
217 	if ((err = zonecfg_get_detach_info(handle, B_TRUE)) != Z_OK) {
218 		errno = err;
219 		zperror(gettext("getting the software version information "
220 		    "failed"), B_TRUE);
221 		zonecfg_fini_handle(handle);
222 		return (Z_ERR);
223 	}
224 
225 	if ((err = zonecfg_detach_save(handle)) != Z_OK) {
226 		errno = err;
227 		zperror(gettext("saving the software version manifest failed"),
228 		    B_TRUE);
229 		zonecfg_fini_handle(handle);
230 		return (Z_ERR);
231 	}
232 
233 	zonecfg_fini_handle(handle);
234 	return (Z_OK);
235 }
236 
237 /*
238  * Perform any necessary housekeeping tasks we need to do after we take
239  * a ZFS snapshot of the zone.  What this really entails is removing the
240  * sw inventory XML file from the zone.  It is still in the snapshot where
241  * we want it, but we don't want it in the source zone itself.
242  */
243 static int
244 post_snapshot(char *source_zone)
245 {
246 	int err;
247 	zone_dochandle_t handle;
248 
249 	if ((handle = zonecfg_init_handle()) == NULL) {
250 		zperror(cmd_to_str(CMD_CLONE), B_TRUE);
251 		return (Z_ERR);
252 	}
253 
254 	if ((err = zonecfg_get_handle(source_zone, handle)) != Z_OK) {
255 		errno = err;
256 		zperror(cmd_to_str(CMD_CLONE), B_TRUE);
257 		zonecfg_fini_handle(handle);
258 		return (Z_ERR);
259 	}
260 
261 	zonecfg_rm_detached(handle, B_FALSE);
262 	zonecfg_fini_handle(handle);
263 
264 	return (Z_OK);
265 }
266 
267 /*
268  * This is a ZFS snapshot iterator call-back function which returns the
269  * highest number of SUNWzone snapshots that have been taken.
270  */
271 static int
272 get_snap_max(zfs_handle_t *zhp, void *data)
273 {
274 	int			res;
275 	zfs_snapshot_data_t	*cbp;
276 
277 	if (zfs_get_type(zhp) != ZFS_TYPE_SNAPSHOT) {
278 		zfs_close(zhp);
279 		return (0);
280 	}
281 
282 	cbp = (zfs_snapshot_data_t *)data;
283 
284 	if (strncmp(zfs_get_name(zhp), cbp->match_name, cbp->len) == 0) {
285 		char	*nump;
286 		int	num;
287 
288 		nump = (char *)(zfs_get_name(zhp) + cbp->len);
289 		num = atoi(nump);
290 		if (num > cbp->max)
291 			cbp->max = num;
292 	}
293 
294 	res = zfs_iter_snapshots(zhp, get_snap_max, data);
295 	zfs_close(zhp);
296 	return (res);
297 }
298 
299 /*
300  * Take a ZFS snapshot to be used for cloning the zone.
301  */
302 static int
303 take_snapshot(char *source_zone, zfs_handle_t *zhp, char *snapshot_name,
304     int snap_size)
305 {
306 	int			res;
307 	char			template[ZFS_MAXNAMELEN];
308 	zfs_snapshot_data_t	cb;
309 
310 	/*
311 	 * First we need to figure out the next available name for the
312 	 * zone snapshot.  Look through the list of zones snapshots for
313 	 * this file system to determine the maximum snapshot name.
314 	 */
315 	if (snprintf(template, sizeof (template), "%s@SUNWzone",
316 	    zfs_get_name(zhp)) >=  sizeof (template))
317 		return (Z_ERR);
318 
319 	cb.match_name = template;
320 	cb.len = strlen(template);
321 	cb.max = 0;
322 
323 	if (zfs_iter_snapshots(zhp, get_snap_max, &cb) != 0)
324 		return (Z_ERR);
325 
326 	cb.max++;
327 
328 	if (snprintf(snapshot_name, snap_size, "%s@SUNWzone%d",
329 	    zfs_get_name(zhp), cb.max) >= snap_size)
330 		return (Z_ERR);
331 
332 	if (pre_snapshot(source_zone) != Z_OK)
333 		return (Z_ERR);
334 	res = zfs_snapshot(snapshot_name);
335 	if (post_snapshot(source_zone) != Z_OK)
336 		return (Z_ERR);
337 
338 	if (res != 0)
339 		return (Z_ERR);
340 	return (Z_OK);
341 }
342 
343 /*
344  * We are using an explicit snapshot from some earlier point in time so
345  * we need to validate it.  This involves checking the sw inventory that
346  * we took when we made the snapshot to verify that the current sw config
347  * on the host is still valid to run a zone made from this snapshot.
348  */
349 static int
350 validate_snapshot(char *snapshot_name, char *snap_path)
351 {
352 	int err;
353 	zone_dochandle_t handle;
354 	zone_dochandle_t athandle = NULL;
355 
356 	if ((handle = zonecfg_init_handle()) == NULL) {
357 		zperror(cmd_to_str(CMD_CLONE), B_TRUE);
358 		return (Z_ERR);
359 	}
360 
361 	if ((err = zonecfg_get_handle(target_zone, handle)) != Z_OK) {
362 		errno = err;
363 		zperror(cmd_to_str(CMD_CLONE), B_TRUE);
364 		zonecfg_fini_handle(handle);
365 		return (Z_ERR);
366 	}
367 
368 	if ((athandle = zonecfg_init_handle()) == NULL) {
369 		zperror(cmd_to_str(CMD_CLONE), B_TRUE);
370 		goto done;
371 	}
372 
373 	if ((err = zonecfg_get_attach_handle(snap_path, target_zone, B_TRUE,
374 	    athandle)) != Z_OK) {
375 		if (err == Z_NO_ZONE)
376 			(void) fprintf(stderr, gettext("snapshot %s was not "
377 			    "taken\n\tby a 'zoneadm clone' command.  It can "
378 			    "not be used to clone zones.\n"), snapshot_name);
379 		else
380 			(void) fprintf(stderr, gettext("snapshot %s is "
381 			    "out-dated\n\tIt can no longer be used to clone "
382 			    "zones on this system.\n"), snapshot_name);
383 		goto done;
384 	}
385 
386 	/* Get the detach information for the locally defined zone. */
387 	if ((err = zonecfg_get_detach_info(handle, B_FALSE)) != Z_OK) {
388 		errno = err;
389 		zperror(gettext("getting the attach information failed"),
390 		    B_TRUE);
391 		goto done;
392 	}
393 
394 	if ((err = sw_cmp(handle, athandle, SW_CMP_SILENT)) != Z_OK)
395 		(void) fprintf(stderr, gettext("snapshot %s is out-dated\n\t"
396 		    "It can no longer be used to clone zones on this "
397 		    "system.\n"), snapshot_name);
398 
399 done:
400 	zonecfg_fini_handle(handle);
401 	if (athandle != NULL)
402 		zonecfg_fini_handle(athandle);
403 
404 	return (err);
405 }
406 
407 /*
408  * Remove the sw inventory file from inside this zonepath that we picked up out
409  * of the snapshot.
410  */
411 static int
412 clean_out_clone()
413 {
414 	int err;
415 	zone_dochandle_t handle;
416 
417 	if ((handle = zonecfg_init_handle()) == NULL) {
418 		zperror(cmd_to_str(CMD_CLONE), B_TRUE);
419 		return (Z_ERR);
420 	}
421 
422 	if ((err = zonecfg_get_handle(target_zone, handle)) != Z_OK) {
423 		errno = err;
424 		zperror(cmd_to_str(CMD_CLONE), B_TRUE);
425 		zonecfg_fini_handle(handle);
426 		return (Z_ERR);
427 	}
428 
429 	zonecfg_rm_detached(handle, B_FALSE);
430 	zonecfg_fini_handle(handle);
431 
432 	return (Z_OK);
433 }
434 
435 /*
436  * Make a ZFS clone on zonepath from snapshot_name.
437  */
438 static int
439 clone_snap(char *snapshot_name, char *zonepath)
440 {
441 	int		res = Z_OK;
442 	int		err;
443 	zfs_handle_t	*zhp;
444 	zfs_handle_t	*clone;
445 
446 	if ((zhp = zfs_open(snapshot_name, ZFS_TYPE_SNAPSHOT)) == NULL)
447 		return (Z_NO_ENTRY);
448 
449 	(void) printf(gettext("Cloning snapshot %s\n"), snapshot_name);
450 
451 	err = zfs_clone(zhp, zonepath);
452 	zfs_close(zhp);
453 	if (err != 0)
454 		return (Z_ERR);
455 
456 	/* create the mountpoint if necessary */
457 	if ((clone = zfs_open(zonepath, ZFS_TYPE_ANY)) == NULL)
458 		return (Z_ERR);
459 
460 	/*
461 	 * The clone has been created so we need to print a diagnostic
462 	 * message if one of the following steps fails for some reason.
463 	 */
464 	if (zfs_mount(clone, NULL, 0) != 0) {
465 		(void) fprintf(stderr, gettext("could not mount ZFS clone "
466 		    "%s\n"), zfs_get_name(clone));
467 		res = Z_ERR;
468 
469 	} else {
470 		if (zfs_prop_set(clone, ZFS_PROP_SHARENFS, "off") != 0) {
471 			/* we won't consider this a failure */
472 			(void) fprintf(stderr, gettext("could not turn off the "
473 			    "'sharenfs' property on ZFS clone %s\n"),
474 			    zfs_get_name(clone));
475 		}
476 
477 		if (clean_out_clone() != Z_OK) {
478 			(void) fprintf(stderr, gettext("could not remove the "
479 			    "software inventory from ZFS clone %s\n"),
480 			    zfs_get_name(clone));
481 			res = Z_ERR;
482 		}
483 	}
484 
485 	zfs_close(clone);
486 	return (res);
487 }
488 
489 /*
490  * This function takes a zonepath and attempts to determine what the ZFS
491  * file system name (not mountpoint) should be for that path.  We do not
492  * assume that zonepath is an existing directory or ZFS fs since we use
493  * this function as part of the process of creating a new ZFS fs or clone.
494  *
495  * The way this works is that we look at the parent directory of the zonepath
496  * to see if it is a ZFS fs.  If it is, we get the name of that ZFS fs and
497  * append the last component of the zonepath to generate the ZFS name for the
498  * zonepath.  This matches the algorithm that ZFS uses for automatically
499  * mounting a new fs after it is created.
500  *
501  * Although a ZFS fs can be mounted anywhere, we don't worry about handling
502  * all of the complexity that a user could possibly configure with arbitrary
503  * mounts since there is no way to generate a ZFS name from a random path in
504  * the file system.  We only try to handle the automatic mounts that ZFS does
505  * for each file system.  ZFS restricts this so that a new fs must be created
506  * in an existing parent ZFS fs.  It then automatically mounts the new fs
507  * directly under the mountpoint for the parent fs using the last component
508  * of the name as the mountpoint directory.
509  *
510  * For example:
511  *    Name			Mountpoint
512  *    space/eng/dev/test/zone1	/project1/eng/dev/test/zone1
513  *
514  * Return Z_OK if the path mapped to a ZFS file system name, otherwise return
515  * Z_ERR.
516  */
517 static int
518 path2name(char *zonepath, char *zfs_name, int len)
519 {
520 	int		res;
521 	char		*p;
522 	zfs_handle_t	*zhp;
523 
524 	if ((p = strrchr(zonepath, '/')) == NULL)
525 		return (Z_ERR);
526 
527 	/*
528 	 * If the parent directory is not its own ZFS fs, then we can't
529 	 * automatically create a new ZFS fs at the 'zonepath' mountpoint
530 	 * so return an error.
531 	 */
532 	*p = '\0';
533 	zhp = mount2zhandle(zonepath);
534 	*p = '/';
535 	if (zhp == NULL)
536 		return (Z_ERR);
537 
538 	res = snprintf(zfs_name, len, "%s/%s", zfs_get_name(zhp), p + 1);
539 
540 	zfs_close(zhp);
541 	if (res >= len)
542 		return (Z_ERR);
543 
544 	return (Z_OK);
545 }
546 
547 /*
548  * A ZFS file system iterator call-back function used to determine if the
549  * file system has dependents (snapshots & clones).
550  */
551 /* ARGSUSED */
552 static int
553 has_dependent(zfs_handle_t *zhp, void *data)
554 {
555 	zfs_close(zhp);
556 	return (1);
557 }
558 
559 /*
560  * Given a snapshot name, get the file system path where the snapshot lives.
561  * A snapshot name is of the form fs_name@snap_name.  For example, snapshot
562  * pl/zones/z1@SUNWzone1 would have a path of
563  * /pl/zones/z1/.zfs/snapshot/SUNWzone1.
564  */
565 static int
566 snap2path(char *snap_name, char *path, int len)
567 {
568 	char		*p;
569 	zfs_handle_t	*zhp;
570 	char		mp[ZFS_MAXPROPLEN];
571 
572 	if ((p = strrchr(snap_name, '@')) == NULL)
573 		return (Z_ERR);
574 
575 	/* Get the file system name from the snap_name. */
576 	*p = '\0';
577 	zhp = zfs_open(snap_name, ZFS_TYPE_ANY);
578 	*p = '@';
579 	if (zhp == NULL)
580 		return (Z_ERR);
581 
582 	/* Get the file system mount point. */
583 	if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mp, sizeof (mp), NULL, NULL,
584 	    0, FALSE) != 0) {
585 		zfs_close(zhp);
586 		return (Z_ERR);
587 	}
588 	zfs_close(zhp);
589 
590 	p++;
591 	if (snprintf(path, len, "%s/.zfs/snapshot/%s", mp, p) >= len)
592 		return (Z_ERR);
593 
594 	return (Z_OK);
595 }
596 
597 /*
598  * Clone a pre-existing ZFS snapshot, either by making a direct ZFS clone, if
599  * possible, or by copying the data from the snapshot to the zonepath.
600  */
601 int
602 clone_snapshot_zfs(char *snap_name, char *zonepath)
603 {
604 	int	err = Z_OK;
605 	char	clone_name[MAXPATHLEN];
606 	char	snap_path[MAXPATHLEN];
607 
608 	if (snap2path(snap_name, snap_path, sizeof (snap_path)) != Z_OK) {
609 		(void) fprintf(stderr, gettext("unable to find path for %s.\n"),
610 		    snap_name);
611 		return (Z_ERR);
612 	}
613 
614 	if (validate_snapshot(snap_name, snap_path) != Z_OK)
615 		return (Z_NO_ENTRY);
616 
617 	/*
618 	 * The zonepath cannot be ZFS cloned, try to copy the data from
619 	 * within the snapshot to the zonepath.
620 	 */
621 	if (path2name(zonepath, clone_name, sizeof (clone_name)) != Z_OK) {
622 		if ((err = clone_copy(snap_path, zonepath)) == Z_OK)
623 			if (clean_out_clone() != Z_OK)
624 				(void) fprintf(stderr,
625 				    gettext("could not remove the "
626 				    "software inventory from %s\n"), zonepath);
627 
628 		return (err);
629 	}
630 
631 	if ((err = clone_snap(snap_name, clone_name)) != Z_OK) {
632 		if (err != Z_NO_ENTRY) {
633 			/*
634 			 * Cloning the snapshot failed.  Fall back to trying
635 			 * to install the zone by copying from the snapshot.
636 			 */
637 			if ((err = clone_copy(snap_path, zonepath)) == Z_OK)
638 				if (clean_out_clone() != Z_OK)
639 					(void) fprintf(stderr,
640 					    gettext("could not remove the "
641 					    "software inventory from %s\n"),
642 					    zonepath);
643 		} else {
644 			/*
645 			 * The snapshot is unusable for some reason so restore
646 			 * the zone state to configured since we were unable to
647 			 * actually do anything about getting the zone
648 			 * installed.
649 			 */
650 			int tmp;
651 
652 			if ((tmp = zone_set_state(target_zone,
653 			    ZONE_STATE_CONFIGURED)) != Z_OK) {
654 				errno = tmp;
655 				zperror2(target_zone,
656 				    gettext("could not set state"));
657 			}
658 		}
659 	}
660 
661 	return (err);
662 }
663 
664 /*
665  * Attempt to clone a source_zone to a target zonepath by using a ZFS clone.
666  */
667 int
668 clone_zfs(char *source_zone, char *source_zonepath, char *zonepath)
669 {
670 	zfs_handle_t	*zhp;
671 	char		clone_name[MAXPATHLEN];
672 	char		snap_name[MAXPATHLEN];
673 
674 	/*
675 	 * Try to get a zfs handle for the source_zonepath.  If this fails
676 	 * the source_zonepath is not ZFS so return an error.
677 	 */
678 	if ((zhp = mount2zhandle(source_zonepath)) == NULL)
679 		return (Z_ERR);
680 
681 	/*
682 	 * Check if there is a file system already mounted on zonepath.  If so,
683 	 * we can't clone to the path so we should fall back to copying.
684 	 */
685 	if (is_mountpnt(zonepath)) {
686 		zfs_close(zhp);
687 		(void) fprintf(stderr,
688 		    gettext("A file system is already mounted on %s,\n"
689 		    "preventing use of a ZFS clone.\n"), zonepath);
690 		return (Z_ERR);
691 	}
692 
693 	/*
694 	 * Instead of using path2name to get the clone name from the zonepath,
695 	 * we could generate a name from the source zone ZFS name.  However,
696 	 * this would mean we would create the clone under the ZFS fs of the
697 	 * source instead of what the zonepath says.  For example,
698 	 *
699 	 * source_zonepath		zonepath
700 	 * /pl/zones/dev/z1		/pl/zones/deploy/z2
701 	 *
702 	 * We don't want the clone to be under "dev", we want it under
703 	 * "deploy", so that we can leverage the normal attribute inheritance
704 	 * that ZFS provides in the fs hierarchy.
705 	 */
706 	if (path2name(zonepath, clone_name, sizeof (clone_name)) != Z_OK) {
707 		zfs_close(zhp);
708 		return (Z_ERR);
709 	}
710 
711 	if (take_snapshot(source_zone, zhp, snap_name, sizeof (snap_name))
712 	    != Z_OK) {
713 		zfs_close(zhp);
714 		return (Z_ERR);
715 	}
716 	zfs_close(zhp);
717 
718 	if (clone_snap(snap_name, clone_name) != Z_OK)
719 		return (Z_ERR);
720 
721 	(void) printf(gettext("Instead of copying, a ZFS clone has been "
722 	    "created for this zone.\n"));
723 
724 	return (Z_OK);
725 }
726 
727 /*
728  * Attempt to create a ZFS file system for the specified zonepath.
729  * We either will successfully create a ZFS file system and get it mounted
730  * on the zonepath or we don't.  The caller doesn't care since a regular
731  * directory is used for the zonepath if no ZFS file system is mounted there.
732  */
733 void
734 create_zfs_zonepath(char *zonepath)
735 {
736 	zfs_handle_t	*zhp;
737 	char		zfs_name[MAXPATHLEN];
738 
739 	if (path2name(zonepath, zfs_name, sizeof (zfs_name)) != Z_OK)
740 		return;
741 
742 	zfs_set_error_handler(noop_err_handler);
743 
744 	if (zfs_create(zfs_name, ZFS_TYPE_FILESYSTEM, NULL, NULL) != 0 ||
745 	    (zhp = zfs_open(zfs_name, ZFS_TYPE_ANY)) == NULL) {
746 		zfs_set_error_handler(NULL);
747 		return;
748 	}
749 
750 	if (zfs_mount(zhp, NULL, 0) != 0) {
751 		(void) zfs_destroy(zhp);
752 	} else if (zfs_prop_set(zhp, ZFS_PROP_SHARENFS, "off") != 0) {
753 		(void) fprintf(stderr, gettext("file system %s successfully "
754 		    "created,\nbut could not turn off the 'sharenfs' "
755 		    "property\n"), zfs_name);
756 	} else {
757 		if (chmod(zonepath, S_IRWXU) != 0) {
758 			(void) fprintf(stderr, gettext("file system %s "
759 			    "successfully created, but chmod %o failed: %s\n"),
760 			    zfs_name, S_IRWXU, strerror(errno));
761 			(void) destroy_zfs(zonepath);
762 		} else {
763 			(void) printf(gettext("A ZFS file system has been "
764 			    "created for this zone.\n"));
765 		}
766 	}
767 
768 	zfs_set_error_handler(NULL);
769 	zfs_close(zhp);
770 }
771 
772 /*
773  * If the zonepath is a ZFS file system, attempt to destroy it.  We return Z_OK
774  * if we were able to zfs_destroy the zonepath, otherwise we return Z_ERR
775  * which means the caller should clean up the zonepath in the traditional
776  * way.
777  */
778 int
779 destroy_zfs(char *zonepath)
780 {
781 	zfs_handle_t	*zhp;
782 	boolean_t	is_clone = B_FALSE;
783 	char		origin[ZFS_MAXPROPLEN];
784 
785 	zfs_set_error_handler(noop_err_handler);
786 
787 	if ((zhp = mount2zhandle(zonepath)) == NULL) {
788 		zfs_set_error_handler(NULL);
789 		return (Z_ERR);
790 	}
791 
792 	/*
793 	 * We can't destroy the file system if it has dependents.
794 	 */
795 	if (zfs_iter_dependents(zhp, has_dependent, NULL) != 0 ||
796 	    zfs_unmount(zhp, NULL, 0) != 0) {
797 		zfs_close(zhp);
798 		zfs_set_error_handler(NULL);
799 		return (Z_ERR);
800 	}
801 
802 	/*
803 	 * This might be a clone.  Try to get the snapshot so we can attempt
804 	 * to destroy that as well.
805 	 */
806 	if (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, origin, sizeof (origin), NULL,
807 	    NULL, 0, FALSE) == 0)
808 		is_clone = B_TRUE;
809 
810 	zfs_set_error_handler(NULL);
811 	if (zfs_destroy(zhp) != 0) {
812 		/*
813 		 * If the destroy fails for some reason, try to remount
814 		 * the file system so that we can use "rm -rf" to clean up
815 		 * instead.
816 		 */
817 		(void) zfs_mount(zhp, NULL, 0);
818 		zfs_close(zhp);
819 		return (Z_ERR);
820 	}
821 	zfs_set_error_handler(noop_err_handler);
822 
823 	(void) printf(gettext("The ZFS file system for this zone has been "
824 	    "destroyed.\n"));
825 
826 	if (is_clone) {
827 		zfs_handle_t	*ohp;
828 
829 		/*
830 		 * Try to clean up the snapshot that the clone was taken from.
831 		 */
832 		if ((ohp = zfs_open(origin, ZFS_TYPE_SNAPSHOT)) != NULL) {
833 			if (zfs_iter_dependents(ohp, has_dependent, NULL)
834 			    == 0 && zfs_unmount(ohp, NULL, 0) == 0) {
835 				(void) zfs_destroy(ohp);
836 			}
837 			zfs_close(ohp);
838 		}
839 	}
840 
841 	zfs_close(zhp);
842 	zfs_set_error_handler(NULL);
843 	return (Z_OK);
844 }
845 
846 /*
847  * Return true if the path is its own zfs file system.  We determine this
848  * by stat-ing the path to see if it is zfs and stat-ing the parent to see
849  * if it is a different fs.
850  */
851 boolean_t
852 is_zonepath_zfs(char *zonepath)
853 {
854 	int res;
855 	char *path;
856 	char *parent;
857 	struct statvfs buf1, buf2;
858 
859 	if (statvfs(zonepath, &buf1) != 0)
860 		return (B_FALSE);
861 
862 	if (strcmp(buf1.f_basetype, "zfs") != 0)
863 		return (B_FALSE);
864 
865 	if ((path = strdup(zonepath)) == NULL)
866 		return (B_FALSE);
867 
868 	parent = dirname(path);
869 	res = statvfs(parent, &buf2);
870 	free(path);
871 
872 	if (res != 0)
873 		return (B_FALSE);
874 
875 	if (buf1.f_fsid == buf2.f_fsid)
876 		return (B_FALSE);
877 
878 	return (B_TRUE);
879 }
880 
881 /*
882  * Implement the fast move of a ZFS file system by simply updating the
883  * mountpoint.  Since it is file system already, we don't have the
884  * issue of cross-file system copying.
885  */
886 int
887 move_zfs(char *zonepath, char *new_zonepath)
888 {
889 	int		ret = Z_ERR;
890 	zfs_handle_t	*zhp;
891 
892 	zfs_set_error_handler(noop_err_handler);
893 
894 	if ((zhp = mount2zhandle(zonepath)) == NULL) {
895 		zfs_set_error_handler(NULL);
896 		return (Z_ERR);
897 	}
898 
899 	if (zfs_prop_set(zhp, ZFS_PROP_MOUNTPOINT, new_zonepath) == 0) {
900 		/*
901 		 * Clean up the old mount point.  We ignore any failure since
902 		 * the zone is already successfully mounted on the new path.
903 		 */
904 		(void) rmdir(zonepath);
905 		ret = Z_OK;
906 	}
907 
908 	zfs_close(zhp);
909 	zfs_set_error_handler(NULL);
910 
911 	return (ret);
912 }
913 
914 /*
915  * Validate that the given dataset exists on the system, and that neither it nor
916  * its children are zvols.
917  *
918  * Note that we don't do anything with the 'zoned' property here.  All
919  * management is done in zoneadmd when the zone is actually rebooted.  This
920  * allows us to automatically set the zoned property even when a zone is
921  * rebooted by the administrator.
922  */
923 int
924 verify_datasets(zone_dochandle_t handle)
925 {
926 	int return_code = Z_OK;
927 	struct zone_dstab dstab;
928 	zfs_handle_t *zhp;
929 	char propbuf[ZFS_MAXPROPLEN];
930 	char source[ZFS_MAXNAMELEN];
931 	zfs_source_t srctype;
932 
933 	if (zonecfg_setdsent(handle) != Z_OK) {
934 		/*
935 		 * TRANSLATION_NOTE
936 		 * zfs and dataset are literals that should not be translated.
937 		 */
938 		(void) fprintf(stderr, gettext("could not verify zfs datasets: "
939 		    "unable to enumerate datasets\n"));
940 		return (Z_ERR);
941 	}
942 
943 	zfs_set_error_handler(err_handler);
944 
945 	while (zonecfg_getdsent(handle, &dstab) == Z_OK) {
946 
947 		current_dataset = dstab.zone_dataset_name;
948 
949 		if ((zhp = zfs_open(dstab.zone_dataset_name,
950 		    ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME)) == NULL) {
951 			return_code = Z_ERR;
952 			continue;
953 		}
954 
955 		if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, propbuf,
956 		    sizeof (propbuf), &srctype, source,
957 		    sizeof (source), 0) == 0 &&
958 		    (srctype == ZFS_SRC_INHERITED)) {
959 			(void) fprintf(stderr, gettext("could not verify zfs "
960 			    "dataset %s: mountpoint cannot be inherited\n"),
961 			    dstab.zone_dataset_name);
962 			return_code = Z_ERR;
963 			zfs_close(zhp);
964 			continue;
965 		}
966 
967 		if (zfs_get_type(zhp) == ZFS_TYPE_VOLUME) {
968 			(void) fprintf(stderr, gettext("cannot verify zfs "
969 			    "dataset %s: volumes cannot be specified as a "
970 			    "zone dataset resource\n"),
971 			    dstab.zone_dataset_name);
972 			return_code = Z_ERR;
973 		}
974 
975 		if (zfs_iter_children(zhp, check_zvol, NULL) != 0)
976 			return_code = Z_ERR;
977 
978 		zfs_close(zhp);
979 	}
980 	(void) zonecfg_enddsent(handle);
981 	zfs_set_error_handler(NULL);
982 
983 	return (return_code);
984 }
985 
986 /*
987  * Verify that the ZFS dataset exists, and its mountpoint
988  * property is set to "legacy".
989  */
990 int
991 verify_fs_zfs(struct zone_fstab *fstab)
992 {
993 	zfs_handle_t *zhp;
994 	char propbuf[ZFS_MAXPROPLEN];
995 
996 	zfs_set_error_handler(noop_err_handler);
997 
998 	if ((zhp = zfs_open(fstab->zone_fs_special, ZFS_TYPE_ANY)) == NULL) {
999 		(void) fprintf(stderr, gettext("could not verify fs %s: "
1000 		    "could not access zfs dataset '%s'\n"),
1001 		    fstab->zone_fs_dir, fstab->zone_fs_special);
1002 		zfs_set_error_handler(NULL);
1003 		return (Z_ERR);
1004 	}
1005 
1006 	if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) {
1007 		(void) fprintf(stderr, gettext("cannot verify fs %s: "
1008 		    "'%s' is not a file system\n"),
1009 		    fstab->zone_fs_dir, fstab->zone_fs_special);
1010 		zfs_close(zhp);
1011 		zfs_set_error_handler(NULL);
1012 		return (Z_ERR);
1013 	}
1014 
1015 	if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, propbuf, sizeof (propbuf),
1016 	    NULL, NULL, 0, 0) != 0 || strcmp(propbuf, "legacy") != 0) {
1017 		(void) fprintf(stderr, gettext("could not verify fs %s: "
1018 		    "zfs '%s' mountpoint is not \"legacy\"\n"),
1019 		    fstab->zone_fs_dir, fstab->zone_fs_special);
1020 		zfs_close(zhp);
1021 		zfs_set_error_handler(NULL);
1022 		return (Z_ERR);
1023 	}
1024 
1025 	zfs_close(zhp);
1026 	zfs_set_error_handler(NULL);
1027 	return (Z_OK);
1028 }
1029