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