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