11867Sgjelinek /* 21867Sgjelinek * CDDL HEADER START 31867Sgjelinek * 41867Sgjelinek * The contents of this file are subject to the terms of the 51867Sgjelinek * Common Development and Distribution License (the "License"). 61867Sgjelinek * You may not use this file except in compliance with the License. 71867Sgjelinek * 81867Sgjelinek * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 91867Sgjelinek * or http://www.opensolaris.org/os/licensing. 101867Sgjelinek * See the License for the specific language governing permissions 111867Sgjelinek * and limitations under the License. 121867Sgjelinek * 131867Sgjelinek * When distributing Covered Code, include this CDDL HEADER in each 141867Sgjelinek * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 151867Sgjelinek * If applicable, add the following below this CDDL HEADER, with the 161867Sgjelinek * fields enclosed by brackets "[]" replaced with your own identifying 171867Sgjelinek * information: Portions Copyright [yyyy] [name of copyright owner] 181867Sgjelinek * 191867Sgjelinek * CDDL HEADER END 201867Sgjelinek */ 211867Sgjelinek 221867Sgjelinek /* 231867Sgjelinek * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 241867Sgjelinek * Use is subject to license terms. 251867Sgjelinek */ 261867Sgjelinek 271867Sgjelinek #pragma ident "%Z%%M% %I% %E% SMI" 281867Sgjelinek 291867Sgjelinek /* 301867Sgjelinek * This file contains the functions used to support the ZFS integration 311867Sgjelinek * with zones. This includes validation (e.g. zonecfg dataset), cloning, 321867Sgjelinek * file system creation and destruction. 331867Sgjelinek */ 341867Sgjelinek 351867Sgjelinek #include <stdio.h> 361867Sgjelinek #include <errno.h> 371867Sgjelinek #include <unistd.h> 381867Sgjelinek #include <string.h> 391867Sgjelinek #include <locale.h> 401867Sgjelinek #include <libintl.h> 411867Sgjelinek #include <sys/stat.h> 421867Sgjelinek #include <sys/statvfs.h> 431867Sgjelinek #include <libgen.h> 441867Sgjelinek #include <libzonecfg.h> 451867Sgjelinek #include <sys/mnttab.h> 461867Sgjelinek #include <libzfs.h> 471867Sgjelinek 481867Sgjelinek #include "zoneadm.h" 491867Sgjelinek 502082Seschrock libzfs_handle_t *g_zfs; 511867Sgjelinek 521867Sgjelinek typedef struct zfs_mount_data { 531867Sgjelinek char *match_name; 541867Sgjelinek zfs_handle_t *match_handle; 551867Sgjelinek } zfs_mount_data_t; 561867Sgjelinek 571867Sgjelinek typedef struct zfs_snapshot_data { 581867Sgjelinek char *match_name; 591867Sgjelinek int len; 601867Sgjelinek int max; 611867Sgjelinek } zfs_snapshot_data_t; 621867Sgjelinek 631867Sgjelinek /* 641867Sgjelinek * A ZFS file system iterator call-back function which is used to validate 651867Sgjelinek * datasets imported into the zone. 661867Sgjelinek */ 671867Sgjelinek /* ARGSUSED */ 681867Sgjelinek static int 691867Sgjelinek check_zvol(zfs_handle_t *zhp, void *unused) 701867Sgjelinek { 711867Sgjelinek int ret; 721867Sgjelinek 731867Sgjelinek if (zfs_get_type(zhp) == ZFS_TYPE_VOLUME) { 741867Sgjelinek /* 751867Sgjelinek * TRANSLATION_NOTE 761867Sgjelinek * zfs and dataset are literals that should not be translated. 771867Sgjelinek */ 781867Sgjelinek (void) fprintf(stderr, gettext("cannot verify zfs dataset %s: " 791867Sgjelinek "volumes cannot be specified as a zone dataset resource\n"), 801867Sgjelinek zfs_get_name(zhp)); 811867Sgjelinek ret = -1; 821867Sgjelinek } else { 831867Sgjelinek ret = zfs_iter_children(zhp, check_zvol, NULL); 841867Sgjelinek } 851867Sgjelinek 861867Sgjelinek zfs_close(zhp); 871867Sgjelinek 881867Sgjelinek return (ret); 891867Sgjelinek } 901867Sgjelinek 911867Sgjelinek /* 921867Sgjelinek * A ZFS file system iterator call-back function which returns the 931867Sgjelinek * zfs_handle_t for a ZFS file system on the specified mount point. 941867Sgjelinek */ 951867Sgjelinek static int 961867Sgjelinek match_mountpoint(zfs_handle_t *zhp, void *data) 971867Sgjelinek { 981867Sgjelinek int res; 991867Sgjelinek zfs_mount_data_t *cbp; 1001867Sgjelinek char mp[ZFS_MAXPROPLEN]; 1011867Sgjelinek 1021867Sgjelinek if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) { 1031867Sgjelinek zfs_close(zhp); 1041867Sgjelinek return (0); 1051867Sgjelinek } 1061867Sgjelinek 1071867Sgjelinek cbp = (zfs_mount_data_t *)data; 1081867Sgjelinek if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mp, sizeof (mp), NULL, NULL, 1092082Seschrock 0, B_FALSE) == 0 && strcmp(mp, cbp->match_name) == 0) { 1101867Sgjelinek cbp->match_handle = zhp; 1111867Sgjelinek return (1); 1121867Sgjelinek } 1131867Sgjelinek 1141867Sgjelinek res = zfs_iter_filesystems(zhp, match_mountpoint, data); 1151867Sgjelinek zfs_close(zhp); 1161867Sgjelinek return (res); 1171867Sgjelinek } 1181867Sgjelinek 1191867Sgjelinek /* 1201867Sgjelinek * Get ZFS handle for the specified mount point. 1211867Sgjelinek */ 1221867Sgjelinek static zfs_handle_t * 1231867Sgjelinek mount2zhandle(char *mountpoint) 1241867Sgjelinek { 1251867Sgjelinek zfs_mount_data_t cb; 1261867Sgjelinek 1271867Sgjelinek cb.match_name = mountpoint; 1281867Sgjelinek cb.match_handle = NULL; 1292082Seschrock (void) zfs_iter_root(g_zfs, match_mountpoint, &cb); 1301867Sgjelinek return (cb.match_handle); 1311867Sgjelinek } 1321867Sgjelinek 1331867Sgjelinek /* 1341867Sgjelinek * Check if there is already a file system (zfs or any other type) mounted on 1351867Sgjelinek * path. 1361867Sgjelinek */ 1371867Sgjelinek static boolean_t 1381867Sgjelinek is_mountpnt(char *path) 1391867Sgjelinek { 1401867Sgjelinek FILE *fp; 1411867Sgjelinek struct mnttab entry; 1421867Sgjelinek 1431867Sgjelinek if ((fp = fopen("/etc/mnttab", "r")) == NULL) 1441867Sgjelinek return (B_FALSE); 1451867Sgjelinek 1461867Sgjelinek while (getmntent(fp, &entry) == 0) { 1471867Sgjelinek if (strcmp(path, entry.mnt_mountp) == 0) { 1481867Sgjelinek (void) fclose(fp); 1491867Sgjelinek return (B_TRUE); 1501867Sgjelinek } 1511867Sgjelinek } 1521867Sgjelinek 1531867Sgjelinek (void) fclose(fp); 1541867Sgjelinek return (B_FALSE); 1551867Sgjelinek } 1561867Sgjelinek 1571867Sgjelinek /* 1581867Sgjelinek * Perform any necessary housekeeping tasks we need to do before we take 1591867Sgjelinek * a ZFS snapshot of the zone. What this really entails is that we are 1601867Sgjelinek * taking a sw inventory of the source zone, like we do when we detach, 1611867Sgjelinek * so that there is the XML manifest in the snapshot. We use that to 1621867Sgjelinek * validate the snapshot if it is the source of a clone at some later time. 1631867Sgjelinek */ 1641867Sgjelinek static int 1651867Sgjelinek pre_snapshot(char *source_zone) 1661867Sgjelinek { 1671867Sgjelinek int err; 1681867Sgjelinek zone_dochandle_t handle; 1691867Sgjelinek 1701867Sgjelinek if ((handle = zonecfg_init_handle()) == NULL) { 1711867Sgjelinek zperror(cmd_to_str(CMD_CLONE), B_TRUE); 1721867Sgjelinek return (Z_ERR); 1731867Sgjelinek } 1741867Sgjelinek 1751867Sgjelinek if ((err = zonecfg_get_handle(source_zone, handle)) != Z_OK) { 1761867Sgjelinek errno = err; 1771867Sgjelinek zperror(cmd_to_str(CMD_CLONE), B_TRUE); 1781867Sgjelinek zonecfg_fini_handle(handle); 1791867Sgjelinek return (Z_ERR); 1801867Sgjelinek } 1811867Sgjelinek 1821867Sgjelinek if ((err = zonecfg_get_detach_info(handle, B_TRUE)) != Z_OK) { 1831867Sgjelinek errno = err; 1841867Sgjelinek zperror(gettext("getting the software version information " 1851867Sgjelinek "failed"), B_TRUE); 1861867Sgjelinek zonecfg_fini_handle(handle); 1871867Sgjelinek return (Z_ERR); 1881867Sgjelinek } 1891867Sgjelinek 1902078Sgjelinek if ((err = zonecfg_detach_save(handle, 0)) != Z_OK) { 1911867Sgjelinek errno = err; 1921867Sgjelinek zperror(gettext("saving the software version manifest failed"), 1931867Sgjelinek B_TRUE); 1941867Sgjelinek zonecfg_fini_handle(handle); 1951867Sgjelinek return (Z_ERR); 1961867Sgjelinek } 1971867Sgjelinek 1981867Sgjelinek zonecfg_fini_handle(handle); 1991867Sgjelinek return (Z_OK); 2001867Sgjelinek } 2011867Sgjelinek 2021867Sgjelinek /* 2031867Sgjelinek * Perform any necessary housekeeping tasks we need to do after we take 2041867Sgjelinek * a ZFS snapshot of the zone. What this really entails is removing the 2051867Sgjelinek * sw inventory XML file from the zone. It is still in the snapshot where 2061867Sgjelinek * we want it, but we don't want it in the source zone itself. 2071867Sgjelinek */ 2081867Sgjelinek static int 2091867Sgjelinek post_snapshot(char *source_zone) 2101867Sgjelinek { 2111867Sgjelinek int err; 2121867Sgjelinek zone_dochandle_t handle; 2131867Sgjelinek 2141867Sgjelinek if ((handle = zonecfg_init_handle()) == NULL) { 2151867Sgjelinek zperror(cmd_to_str(CMD_CLONE), B_TRUE); 2161867Sgjelinek return (Z_ERR); 2171867Sgjelinek } 2181867Sgjelinek 2191867Sgjelinek if ((err = zonecfg_get_handle(source_zone, handle)) != Z_OK) { 2201867Sgjelinek errno = err; 2211867Sgjelinek zperror(cmd_to_str(CMD_CLONE), B_TRUE); 2221867Sgjelinek zonecfg_fini_handle(handle); 2231867Sgjelinek return (Z_ERR); 2241867Sgjelinek } 2251867Sgjelinek 2261867Sgjelinek zonecfg_rm_detached(handle, B_FALSE); 2271867Sgjelinek zonecfg_fini_handle(handle); 2281867Sgjelinek 2291867Sgjelinek return (Z_OK); 2301867Sgjelinek } 2311867Sgjelinek 2321867Sgjelinek /* 2331867Sgjelinek * This is a ZFS snapshot iterator call-back function which returns the 2341867Sgjelinek * highest number of SUNWzone snapshots that have been taken. 2351867Sgjelinek */ 2361867Sgjelinek static int 2371867Sgjelinek get_snap_max(zfs_handle_t *zhp, void *data) 2381867Sgjelinek { 2391867Sgjelinek int res; 2401867Sgjelinek zfs_snapshot_data_t *cbp; 2411867Sgjelinek 2421867Sgjelinek if (zfs_get_type(zhp) != ZFS_TYPE_SNAPSHOT) { 2431867Sgjelinek zfs_close(zhp); 2441867Sgjelinek return (0); 2451867Sgjelinek } 2461867Sgjelinek 2471867Sgjelinek cbp = (zfs_snapshot_data_t *)data; 2481867Sgjelinek 2491867Sgjelinek if (strncmp(zfs_get_name(zhp), cbp->match_name, cbp->len) == 0) { 2501867Sgjelinek char *nump; 2511867Sgjelinek int num; 2521867Sgjelinek 2531867Sgjelinek nump = (char *)(zfs_get_name(zhp) + cbp->len); 2541867Sgjelinek num = atoi(nump); 2551867Sgjelinek if (num > cbp->max) 2561867Sgjelinek cbp->max = num; 2571867Sgjelinek } 2581867Sgjelinek 2591867Sgjelinek res = zfs_iter_snapshots(zhp, get_snap_max, data); 2601867Sgjelinek zfs_close(zhp); 2611867Sgjelinek return (res); 2621867Sgjelinek } 2631867Sgjelinek 2641867Sgjelinek /* 2651867Sgjelinek * Take a ZFS snapshot to be used for cloning the zone. 2661867Sgjelinek */ 2671867Sgjelinek static int 2681867Sgjelinek take_snapshot(char *source_zone, zfs_handle_t *zhp, char *snapshot_name, 2691867Sgjelinek int snap_size) 2701867Sgjelinek { 2711867Sgjelinek int res; 2721867Sgjelinek char template[ZFS_MAXNAMELEN]; 2731867Sgjelinek zfs_snapshot_data_t cb; 2741867Sgjelinek 2751867Sgjelinek /* 2761867Sgjelinek * First we need to figure out the next available name for the 2771867Sgjelinek * zone snapshot. Look through the list of zones snapshots for 2781867Sgjelinek * this file system to determine the maximum snapshot name. 2791867Sgjelinek */ 2801867Sgjelinek if (snprintf(template, sizeof (template), "%s@SUNWzone", 2811867Sgjelinek zfs_get_name(zhp)) >= sizeof (template)) 2821867Sgjelinek return (Z_ERR); 2831867Sgjelinek 2841867Sgjelinek cb.match_name = template; 2851867Sgjelinek cb.len = strlen(template); 2861867Sgjelinek cb.max = 0; 2871867Sgjelinek 2881867Sgjelinek if (zfs_iter_snapshots(zhp, get_snap_max, &cb) != 0) 2891867Sgjelinek return (Z_ERR); 2901867Sgjelinek 2911867Sgjelinek cb.max++; 2921867Sgjelinek 2931867Sgjelinek if (snprintf(snapshot_name, snap_size, "%s@SUNWzone%d", 2941867Sgjelinek zfs_get_name(zhp), cb.max) >= snap_size) 2951867Sgjelinek return (Z_ERR); 2961867Sgjelinek 2971867Sgjelinek if (pre_snapshot(source_zone) != Z_OK) 2981867Sgjelinek return (Z_ERR); 2992199Sahrens res = zfs_snapshot(g_zfs, snapshot_name, B_FALSE); 3001867Sgjelinek if (post_snapshot(source_zone) != Z_OK) 3011867Sgjelinek return (Z_ERR); 3021867Sgjelinek 3031867Sgjelinek if (res != 0) 3041867Sgjelinek return (Z_ERR); 3051867Sgjelinek return (Z_OK); 3061867Sgjelinek } 3071867Sgjelinek 3081867Sgjelinek /* 3091867Sgjelinek * We are using an explicit snapshot from some earlier point in time so 3101867Sgjelinek * we need to validate it. This involves checking the sw inventory that 3111867Sgjelinek * we took when we made the snapshot to verify that the current sw config 3121867Sgjelinek * on the host is still valid to run a zone made from this snapshot. 3131867Sgjelinek */ 3141867Sgjelinek static int 3151867Sgjelinek validate_snapshot(char *snapshot_name, char *snap_path) 3161867Sgjelinek { 3171867Sgjelinek int err; 3181867Sgjelinek zone_dochandle_t handle; 3191867Sgjelinek zone_dochandle_t athandle = NULL; 3201867Sgjelinek 3211867Sgjelinek if ((handle = zonecfg_init_handle()) == NULL) { 3221867Sgjelinek zperror(cmd_to_str(CMD_CLONE), B_TRUE); 3231867Sgjelinek return (Z_ERR); 3241867Sgjelinek } 3251867Sgjelinek 3261867Sgjelinek if ((err = zonecfg_get_handle(target_zone, handle)) != Z_OK) { 3271867Sgjelinek errno = err; 3281867Sgjelinek zperror(cmd_to_str(CMD_CLONE), B_TRUE); 3291867Sgjelinek zonecfg_fini_handle(handle); 3301867Sgjelinek return (Z_ERR); 3311867Sgjelinek } 3321867Sgjelinek 3331867Sgjelinek if ((athandle = zonecfg_init_handle()) == NULL) { 3341867Sgjelinek zperror(cmd_to_str(CMD_CLONE), B_TRUE); 3351867Sgjelinek goto done; 3361867Sgjelinek } 3371867Sgjelinek 3381867Sgjelinek if ((err = zonecfg_get_attach_handle(snap_path, target_zone, B_TRUE, 3391867Sgjelinek athandle)) != Z_OK) { 3401867Sgjelinek if (err == Z_NO_ZONE) 3411867Sgjelinek (void) fprintf(stderr, gettext("snapshot %s was not " 3421867Sgjelinek "taken\n\tby a 'zoneadm clone' command. It can " 3431867Sgjelinek "not be used to clone zones.\n"), snapshot_name); 3441867Sgjelinek else 3451867Sgjelinek (void) fprintf(stderr, gettext("snapshot %s is " 3461867Sgjelinek "out-dated\n\tIt can no longer be used to clone " 3471867Sgjelinek "zones on this system.\n"), snapshot_name); 3481867Sgjelinek goto done; 3491867Sgjelinek } 3501867Sgjelinek 3511867Sgjelinek /* Get the detach information for the locally defined zone. */ 3521867Sgjelinek if ((err = zonecfg_get_detach_info(handle, B_FALSE)) != Z_OK) { 3531867Sgjelinek errno = err; 3541867Sgjelinek zperror(gettext("getting the attach information failed"), 3551867Sgjelinek B_TRUE); 3561867Sgjelinek goto done; 3571867Sgjelinek } 3581867Sgjelinek 3591867Sgjelinek if ((err = sw_cmp(handle, athandle, SW_CMP_SILENT)) != Z_OK) 3601867Sgjelinek (void) fprintf(stderr, gettext("snapshot %s is out-dated\n\t" 3611867Sgjelinek "It can no longer be used to clone zones on this " 3621867Sgjelinek "system.\n"), snapshot_name); 3631867Sgjelinek 3641867Sgjelinek done: 3651867Sgjelinek zonecfg_fini_handle(handle); 3661867Sgjelinek if (athandle != NULL) 3671867Sgjelinek zonecfg_fini_handle(athandle); 3681867Sgjelinek 3691867Sgjelinek return (err); 3701867Sgjelinek } 3711867Sgjelinek 3721867Sgjelinek /* 3731867Sgjelinek * Remove the sw inventory file from inside this zonepath that we picked up out 3741867Sgjelinek * of the snapshot. 3751867Sgjelinek */ 3761867Sgjelinek static int 3771867Sgjelinek clean_out_clone() 3781867Sgjelinek { 3791867Sgjelinek int err; 3801867Sgjelinek zone_dochandle_t handle; 3811867Sgjelinek 3821867Sgjelinek if ((handle = zonecfg_init_handle()) == NULL) { 3831867Sgjelinek zperror(cmd_to_str(CMD_CLONE), B_TRUE); 3841867Sgjelinek return (Z_ERR); 3851867Sgjelinek } 3861867Sgjelinek 3871867Sgjelinek if ((err = zonecfg_get_handle(target_zone, handle)) != Z_OK) { 3881867Sgjelinek errno = err; 3891867Sgjelinek zperror(cmd_to_str(CMD_CLONE), B_TRUE); 3901867Sgjelinek zonecfg_fini_handle(handle); 3911867Sgjelinek return (Z_ERR); 3921867Sgjelinek } 3931867Sgjelinek 3941867Sgjelinek zonecfg_rm_detached(handle, B_FALSE); 3951867Sgjelinek zonecfg_fini_handle(handle); 3961867Sgjelinek 3971867Sgjelinek return (Z_OK); 3981867Sgjelinek } 3991867Sgjelinek 4001867Sgjelinek /* 4011867Sgjelinek * Make a ZFS clone on zonepath from snapshot_name. 4021867Sgjelinek */ 4031867Sgjelinek static int 4041867Sgjelinek clone_snap(char *snapshot_name, char *zonepath) 4051867Sgjelinek { 4061867Sgjelinek int res = Z_OK; 4071867Sgjelinek int err; 4081867Sgjelinek zfs_handle_t *zhp; 4091867Sgjelinek zfs_handle_t *clone; 4102676Seschrock nvlist_t *props = NULL; 4111867Sgjelinek 4122082Seschrock if ((zhp = zfs_open(g_zfs, snapshot_name, ZFS_TYPE_SNAPSHOT)) == NULL) 4131867Sgjelinek return (Z_NO_ENTRY); 4141867Sgjelinek 4151867Sgjelinek (void) printf(gettext("Cloning snapshot %s\n"), snapshot_name); 4161867Sgjelinek 4172676Seschrock if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0 || 418*2744Snn35248 nvlist_add_string(props, zfs_prop_to_name(ZFS_PROP_SHARENFS), 419*2744Snn35248 "off") != 0) { 420*2744Snn35248 if (props != NULL) 421*2744Snn35248 nvlist_free(props); 4222676Seschrock (void) fprintf(stderr, gettext("could not create ZFS clone " 4232676Seschrock "%s: out of memory\n"), zonepath); 4242676Seschrock return (Z_ERR); 4252676Seschrock } 4262676Seschrock 4272676Seschrock err = zfs_clone(zhp, zonepath, props); 4281867Sgjelinek zfs_close(zhp); 4292676Seschrock 4302676Seschrock nvlist_free(props); 4312676Seschrock 4321867Sgjelinek if (err != 0) 4331867Sgjelinek return (Z_ERR); 4341867Sgjelinek 4351867Sgjelinek /* create the mountpoint if necessary */ 4362082Seschrock if ((clone = zfs_open(g_zfs, zonepath, ZFS_TYPE_ANY)) == NULL) 4371867Sgjelinek return (Z_ERR); 4381867Sgjelinek 4391867Sgjelinek /* 4401867Sgjelinek * The clone has been created so we need to print a diagnostic 4411867Sgjelinek * message if one of the following steps fails for some reason. 4421867Sgjelinek */ 4431867Sgjelinek if (zfs_mount(clone, NULL, 0) != 0) { 4441867Sgjelinek (void) fprintf(stderr, gettext("could not mount ZFS clone " 4451867Sgjelinek "%s\n"), zfs_get_name(clone)); 4461867Sgjelinek res = Z_ERR; 4471867Sgjelinek 4482676Seschrock } else if (clean_out_clone() != Z_OK) { 4492676Seschrock (void) fprintf(stderr, gettext("could not remove the " 4502676Seschrock "software inventory from ZFS clone %s\n"), 4512676Seschrock zfs_get_name(clone)); 4522676Seschrock res = Z_ERR; 4531867Sgjelinek } 4541867Sgjelinek 4551867Sgjelinek zfs_close(clone); 4561867Sgjelinek return (res); 4571867Sgjelinek } 4581867Sgjelinek 4591867Sgjelinek /* 4601867Sgjelinek * This function takes a zonepath and attempts to determine what the ZFS 4611867Sgjelinek * file system name (not mountpoint) should be for that path. We do not 4621867Sgjelinek * assume that zonepath is an existing directory or ZFS fs since we use 4631867Sgjelinek * this function as part of the process of creating a new ZFS fs or clone. 4641867Sgjelinek * 4651867Sgjelinek * The way this works is that we look at the parent directory of the zonepath 4661867Sgjelinek * to see if it is a ZFS fs. If it is, we get the name of that ZFS fs and 4671867Sgjelinek * append the last component of the zonepath to generate the ZFS name for the 4681867Sgjelinek * zonepath. This matches the algorithm that ZFS uses for automatically 4691867Sgjelinek * mounting a new fs after it is created. 4701867Sgjelinek * 4711867Sgjelinek * Although a ZFS fs can be mounted anywhere, we don't worry about handling 4721867Sgjelinek * all of the complexity that a user could possibly configure with arbitrary 4731867Sgjelinek * mounts since there is no way to generate a ZFS name from a random path in 4741867Sgjelinek * the file system. We only try to handle the automatic mounts that ZFS does 4751867Sgjelinek * for each file system. ZFS restricts this so that a new fs must be created 4761867Sgjelinek * in an existing parent ZFS fs. It then automatically mounts the new fs 4771867Sgjelinek * directly under the mountpoint for the parent fs using the last component 4781867Sgjelinek * of the name as the mountpoint directory. 4791867Sgjelinek * 4801867Sgjelinek * For example: 4811867Sgjelinek * Name Mountpoint 4821867Sgjelinek * space/eng/dev/test/zone1 /project1/eng/dev/test/zone1 4831867Sgjelinek * 4841867Sgjelinek * Return Z_OK if the path mapped to a ZFS file system name, otherwise return 4851867Sgjelinek * Z_ERR. 4861867Sgjelinek */ 4871867Sgjelinek static int 4881867Sgjelinek path2name(char *zonepath, char *zfs_name, int len) 4891867Sgjelinek { 4901867Sgjelinek int res; 4911867Sgjelinek char *p; 4921867Sgjelinek zfs_handle_t *zhp; 4931867Sgjelinek 4941867Sgjelinek if ((p = strrchr(zonepath, '/')) == NULL) 4951867Sgjelinek return (Z_ERR); 4961867Sgjelinek 4971867Sgjelinek /* 4981867Sgjelinek * If the parent directory is not its own ZFS fs, then we can't 4991867Sgjelinek * automatically create a new ZFS fs at the 'zonepath' mountpoint 5001867Sgjelinek * so return an error. 5011867Sgjelinek */ 5021867Sgjelinek *p = '\0'; 5031867Sgjelinek zhp = mount2zhandle(zonepath); 5041867Sgjelinek *p = '/'; 5051867Sgjelinek if (zhp == NULL) 5061867Sgjelinek return (Z_ERR); 5071867Sgjelinek 5081867Sgjelinek res = snprintf(zfs_name, len, "%s/%s", zfs_get_name(zhp), p + 1); 5091867Sgjelinek 5101867Sgjelinek zfs_close(zhp); 5111867Sgjelinek if (res >= len) 5121867Sgjelinek return (Z_ERR); 5131867Sgjelinek 5141867Sgjelinek return (Z_OK); 5151867Sgjelinek } 5161867Sgjelinek 5171867Sgjelinek /* 5181867Sgjelinek * A ZFS file system iterator call-back function used to determine if the 5191867Sgjelinek * file system has dependents (snapshots & clones). 5201867Sgjelinek */ 5211867Sgjelinek /* ARGSUSED */ 5221867Sgjelinek static int 5231867Sgjelinek has_dependent(zfs_handle_t *zhp, void *data) 5241867Sgjelinek { 5251867Sgjelinek zfs_close(zhp); 5261867Sgjelinek return (1); 5271867Sgjelinek } 5281867Sgjelinek 5291867Sgjelinek /* 5301867Sgjelinek * Given a snapshot name, get the file system path where the snapshot lives. 5311867Sgjelinek * A snapshot name is of the form fs_name@snap_name. For example, snapshot 5321867Sgjelinek * pl/zones/z1@SUNWzone1 would have a path of 5331867Sgjelinek * /pl/zones/z1/.zfs/snapshot/SUNWzone1. 5341867Sgjelinek */ 5351867Sgjelinek static int 5361867Sgjelinek snap2path(char *snap_name, char *path, int len) 5371867Sgjelinek { 5381867Sgjelinek char *p; 5391867Sgjelinek zfs_handle_t *zhp; 5401867Sgjelinek char mp[ZFS_MAXPROPLEN]; 5411867Sgjelinek 5421867Sgjelinek if ((p = strrchr(snap_name, '@')) == NULL) 5431867Sgjelinek return (Z_ERR); 5441867Sgjelinek 5451867Sgjelinek /* Get the file system name from the snap_name. */ 5461867Sgjelinek *p = '\0'; 5472082Seschrock zhp = zfs_open(g_zfs, snap_name, ZFS_TYPE_ANY); 5481867Sgjelinek *p = '@'; 5491867Sgjelinek if (zhp == NULL) 5501867Sgjelinek return (Z_ERR); 5511867Sgjelinek 5521867Sgjelinek /* Get the file system mount point. */ 5531867Sgjelinek if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mp, sizeof (mp), NULL, NULL, 5542082Seschrock 0, B_FALSE) != 0) { 5551867Sgjelinek zfs_close(zhp); 5561867Sgjelinek return (Z_ERR); 5571867Sgjelinek } 5581867Sgjelinek zfs_close(zhp); 5591867Sgjelinek 5601867Sgjelinek p++; 5611867Sgjelinek if (snprintf(path, len, "%s/.zfs/snapshot/%s", mp, p) >= len) 5621867Sgjelinek return (Z_ERR); 5631867Sgjelinek 5641867Sgjelinek return (Z_OK); 5651867Sgjelinek } 5661867Sgjelinek 5671867Sgjelinek /* 5681867Sgjelinek * Clone a pre-existing ZFS snapshot, either by making a direct ZFS clone, if 5691867Sgjelinek * possible, or by copying the data from the snapshot to the zonepath. 5701867Sgjelinek */ 5711867Sgjelinek int 5721867Sgjelinek clone_snapshot_zfs(char *snap_name, char *zonepath) 5731867Sgjelinek { 5741867Sgjelinek int err = Z_OK; 5751867Sgjelinek char clone_name[MAXPATHLEN]; 5761867Sgjelinek char snap_path[MAXPATHLEN]; 5771867Sgjelinek 5781867Sgjelinek if (snap2path(snap_name, snap_path, sizeof (snap_path)) != Z_OK) { 5791867Sgjelinek (void) fprintf(stderr, gettext("unable to find path for %s.\n"), 5801867Sgjelinek snap_name); 5811867Sgjelinek return (Z_ERR); 5821867Sgjelinek } 5831867Sgjelinek 5841867Sgjelinek if (validate_snapshot(snap_name, snap_path) != Z_OK) 5851867Sgjelinek return (Z_NO_ENTRY); 5861867Sgjelinek 5871867Sgjelinek /* 5881867Sgjelinek * The zonepath cannot be ZFS cloned, try to copy the data from 5891867Sgjelinek * within the snapshot to the zonepath. 5901867Sgjelinek */ 5911867Sgjelinek if (path2name(zonepath, clone_name, sizeof (clone_name)) != Z_OK) { 5921867Sgjelinek if ((err = clone_copy(snap_path, zonepath)) == Z_OK) 5931867Sgjelinek if (clean_out_clone() != Z_OK) 5941867Sgjelinek (void) fprintf(stderr, 5951867Sgjelinek gettext("could not remove the " 5961867Sgjelinek "software inventory from %s\n"), zonepath); 5971867Sgjelinek 5981867Sgjelinek return (err); 5991867Sgjelinek } 6001867Sgjelinek 6011867Sgjelinek if ((err = clone_snap(snap_name, clone_name)) != Z_OK) { 6021867Sgjelinek if (err != Z_NO_ENTRY) { 6031867Sgjelinek /* 6041867Sgjelinek * Cloning the snapshot failed. Fall back to trying 6051867Sgjelinek * to install the zone by copying from the snapshot. 6061867Sgjelinek */ 6071867Sgjelinek if ((err = clone_copy(snap_path, zonepath)) == Z_OK) 6081867Sgjelinek if (clean_out_clone() != Z_OK) 6091867Sgjelinek (void) fprintf(stderr, 6101867Sgjelinek gettext("could not remove the " 6111867Sgjelinek "software inventory from %s\n"), 6121867Sgjelinek zonepath); 6131867Sgjelinek } else { 6141867Sgjelinek /* 6151867Sgjelinek * The snapshot is unusable for some reason so restore 6161867Sgjelinek * the zone state to configured since we were unable to 6171867Sgjelinek * actually do anything about getting the zone 6181867Sgjelinek * installed. 6191867Sgjelinek */ 6201867Sgjelinek int tmp; 6211867Sgjelinek 6221867Sgjelinek if ((tmp = zone_set_state(target_zone, 6231867Sgjelinek ZONE_STATE_CONFIGURED)) != Z_OK) { 6241867Sgjelinek errno = tmp; 6251867Sgjelinek zperror2(target_zone, 6261867Sgjelinek gettext("could not set state")); 6271867Sgjelinek } 6281867Sgjelinek } 6291867Sgjelinek } 6301867Sgjelinek 6311867Sgjelinek return (err); 6321867Sgjelinek } 6331867Sgjelinek 6341867Sgjelinek /* 6351867Sgjelinek * Attempt to clone a source_zone to a target zonepath by using a ZFS clone. 6361867Sgjelinek */ 6371867Sgjelinek int 6381867Sgjelinek clone_zfs(char *source_zone, char *source_zonepath, char *zonepath) 6391867Sgjelinek { 6401867Sgjelinek zfs_handle_t *zhp; 6411867Sgjelinek char clone_name[MAXPATHLEN]; 6421867Sgjelinek char snap_name[MAXPATHLEN]; 6431867Sgjelinek 6441867Sgjelinek /* 6451867Sgjelinek * Try to get a zfs handle for the source_zonepath. If this fails 6461867Sgjelinek * the source_zonepath is not ZFS so return an error. 6471867Sgjelinek */ 6481867Sgjelinek if ((zhp = mount2zhandle(source_zonepath)) == NULL) 6491867Sgjelinek return (Z_ERR); 6501867Sgjelinek 6511867Sgjelinek /* 6521867Sgjelinek * Check if there is a file system already mounted on zonepath. If so, 6531867Sgjelinek * we can't clone to the path so we should fall back to copying. 6541867Sgjelinek */ 6551867Sgjelinek if (is_mountpnt(zonepath)) { 6561867Sgjelinek zfs_close(zhp); 6571867Sgjelinek (void) fprintf(stderr, 6581867Sgjelinek gettext("A file system is already mounted on %s,\n" 6591867Sgjelinek "preventing use of a ZFS clone.\n"), zonepath); 6601867Sgjelinek return (Z_ERR); 6611867Sgjelinek } 6621867Sgjelinek 6631867Sgjelinek /* 6641867Sgjelinek * Instead of using path2name to get the clone name from the zonepath, 6651867Sgjelinek * we could generate a name from the source zone ZFS name. However, 6661867Sgjelinek * this would mean we would create the clone under the ZFS fs of the 6671867Sgjelinek * source instead of what the zonepath says. For example, 6681867Sgjelinek * 6691867Sgjelinek * source_zonepath zonepath 6701867Sgjelinek * /pl/zones/dev/z1 /pl/zones/deploy/z2 6711867Sgjelinek * 6721867Sgjelinek * We don't want the clone to be under "dev", we want it under 6731867Sgjelinek * "deploy", so that we can leverage the normal attribute inheritance 6741867Sgjelinek * that ZFS provides in the fs hierarchy. 6751867Sgjelinek */ 6761867Sgjelinek if (path2name(zonepath, clone_name, sizeof (clone_name)) != Z_OK) { 6771867Sgjelinek zfs_close(zhp); 6781867Sgjelinek return (Z_ERR); 6791867Sgjelinek } 6801867Sgjelinek 6811867Sgjelinek if (take_snapshot(source_zone, zhp, snap_name, sizeof (snap_name)) 6821867Sgjelinek != Z_OK) { 6831867Sgjelinek zfs_close(zhp); 6841867Sgjelinek return (Z_ERR); 6851867Sgjelinek } 6861867Sgjelinek zfs_close(zhp); 6871867Sgjelinek 6881867Sgjelinek if (clone_snap(snap_name, clone_name) != Z_OK) 6891867Sgjelinek return (Z_ERR); 6901867Sgjelinek 6911867Sgjelinek (void) printf(gettext("Instead of copying, a ZFS clone has been " 6921867Sgjelinek "created for this zone.\n")); 6931867Sgjelinek 6941867Sgjelinek return (Z_OK); 6951867Sgjelinek } 6961867Sgjelinek 6971867Sgjelinek /* 6981867Sgjelinek * Attempt to create a ZFS file system for the specified zonepath. 6991867Sgjelinek * We either will successfully create a ZFS file system and get it mounted 7001867Sgjelinek * on the zonepath or we don't. The caller doesn't care since a regular 7011867Sgjelinek * directory is used for the zonepath if no ZFS file system is mounted there. 7021867Sgjelinek */ 7031867Sgjelinek void 7041867Sgjelinek create_zfs_zonepath(char *zonepath) 7051867Sgjelinek { 7061867Sgjelinek zfs_handle_t *zhp; 7071867Sgjelinek char zfs_name[MAXPATHLEN]; 7082676Seschrock nvlist_t *props = NULL; 7091867Sgjelinek 7101867Sgjelinek if (path2name(zonepath, zfs_name, sizeof (zfs_name)) != Z_OK) 7111867Sgjelinek return; 7121867Sgjelinek 7132676Seschrock if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0 || 714*2744Snn35248 nvlist_add_string(props, zfs_prop_to_name(ZFS_PROP_SHARENFS), 715*2744Snn35248 "off") != 0) { 716*2744Snn35248 if (props != NULL) 717*2744Snn35248 nvlist_free(props); 7182676Seschrock (void) fprintf(stderr, gettext("cannot create ZFS dataset %s: " 7192676Seschrock "out of memory\n"), zfs_name); 7202676Seschrock } 7212676Seschrock 7222676Seschrock if (zfs_create(g_zfs, zfs_name, ZFS_TYPE_FILESYSTEM, props) != 0 || 7232082Seschrock (zhp = zfs_open(g_zfs, zfs_name, ZFS_TYPE_ANY)) == NULL) { 7242082Seschrock (void) fprintf(stderr, gettext("cannot create ZFS dataset %s: " 7252082Seschrock "%s\n"), zfs_name, libzfs_error_description(g_zfs)); 7262676Seschrock nvlist_free(props); 7271867Sgjelinek return; 7281867Sgjelinek } 7291867Sgjelinek 7302676Seschrock nvlist_free(props); 7312676Seschrock 7321867Sgjelinek if (zfs_mount(zhp, NULL, 0) != 0) { 7332082Seschrock (void) fprintf(stderr, gettext("cannot mount ZFS dataset %s: " 7342082Seschrock "%s\n"), zfs_name, libzfs_error_description(g_zfs)); 7351867Sgjelinek (void) zfs_destroy(zhp); 7361867Sgjelinek } else { 7371867Sgjelinek if (chmod(zonepath, S_IRWXU) != 0) { 7381867Sgjelinek (void) fprintf(stderr, gettext("file system %s " 7391867Sgjelinek "successfully created, but chmod %o failed: %s\n"), 7401867Sgjelinek zfs_name, S_IRWXU, strerror(errno)); 7411867Sgjelinek (void) destroy_zfs(zonepath); 7421867Sgjelinek } else { 7431867Sgjelinek (void) printf(gettext("A ZFS file system has been " 7441867Sgjelinek "created for this zone.\n")); 7451867Sgjelinek } 7461867Sgjelinek } 7471867Sgjelinek 7481867Sgjelinek zfs_close(zhp); 7491867Sgjelinek } 7501867Sgjelinek 7511867Sgjelinek /* 7521867Sgjelinek * If the zonepath is a ZFS file system, attempt to destroy it. We return Z_OK 7531867Sgjelinek * if we were able to zfs_destroy the zonepath, otherwise we return Z_ERR 7541867Sgjelinek * which means the caller should clean up the zonepath in the traditional 7551867Sgjelinek * way. 7561867Sgjelinek */ 7571867Sgjelinek int 7581867Sgjelinek destroy_zfs(char *zonepath) 7591867Sgjelinek { 7601867Sgjelinek zfs_handle_t *zhp; 7611867Sgjelinek boolean_t is_clone = B_FALSE; 7621867Sgjelinek char origin[ZFS_MAXPROPLEN]; 7631867Sgjelinek 7642082Seschrock if ((zhp = mount2zhandle(zonepath)) == NULL) 7651867Sgjelinek return (Z_ERR); 7661867Sgjelinek 7671867Sgjelinek /* 7681867Sgjelinek * We can't destroy the file system if it has dependents. 7691867Sgjelinek */ 7702474Seschrock if (zfs_iter_dependents(zhp, B_TRUE, has_dependent, NULL) != 0 || 7711867Sgjelinek zfs_unmount(zhp, NULL, 0) != 0) { 7721867Sgjelinek zfs_close(zhp); 7731867Sgjelinek return (Z_ERR); 7741867Sgjelinek } 7751867Sgjelinek 7761867Sgjelinek /* 7771867Sgjelinek * This might be a clone. Try to get the snapshot so we can attempt 7781867Sgjelinek * to destroy that as well. 7791867Sgjelinek */ 7801867Sgjelinek if (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, origin, sizeof (origin), NULL, 7812082Seschrock NULL, 0, B_FALSE) == 0) 7821867Sgjelinek is_clone = B_TRUE; 7831867Sgjelinek 7841867Sgjelinek if (zfs_destroy(zhp) != 0) { 7851867Sgjelinek /* 7861867Sgjelinek * If the destroy fails for some reason, try to remount 7871867Sgjelinek * the file system so that we can use "rm -rf" to clean up 7881867Sgjelinek * instead. 7891867Sgjelinek */ 7901867Sgjelinek (void) zfs_mount(zhp, NULL, 0); 7911867Sgjelinek zfs_close(zhp); 7921867Sgjelinek return (Z_ERR); 7931867Sgjelinek } 7941867Sgjelinek 7951867Sgjelinek (void) printf(gettext("The ZFS file system for this zone has been " 7961867Sgjelinek "destroyed.\n")); 7971867Sgjelinek 7981867Sgjelinek if (is_clone) { 7991867Sgjelinek zfs_handle_t *ohp; 8001867Sgjelinek 8011867Sgjelinek /* 8021867Sgjelinek * Try to clean up the snapshot that the clone was taken from. 8031867Sgjelinek */ 8042082Seschrock if ((ohp = zfs_open(g_zfs, origin, 8052082Seschrock ZFS_TYPE_SNAPSHOT)) != NULL) { 8062474Seschrock if (zfs_iter_dependents(ohp, B_TRUE, has_dependent, 8072474Seschrock NULL) == 0 && zfs_unmount(ohp, NULL, 0) == 0) 8081867Sgjelinek (void) zfs_destroy(ohp); 8091867Sgjelinek zfs_close(ohp); 8101867Sgjelinek } 8111867Sgjelinek } 8121867Sgjelinek 8131867Sgjelinek zfs_close(zhp); 8141867Sgjelinek return (Z_OK); 8151867Sgjelinek } 8161867Sgjelinek 8171867Sgjelinek /* 8181867Sgjelinek * Return true if the path is its own zfs file system. We determine this 8191867Sgjelinek * by stat-ing the path to see if it is zfs and stat-ing the parent to see 8201867Sgjelinek * if it is a different fs. 8211867Sgjelinek */ 8221867Sgjelinek boolean_t 8231867Sgjelinek is_zonepath_zfs(char *zonepath) 8241867Sgjelinek { 8251867Sgjelinek int res; 8261867Sgjelinek char *path; 8271867Sgjelinek char *parent; 8282267Sdp struct statvfs64 buf1, buf2; 8291867Sgjelinek 8302267Sdp if (statvfs64(zonepath, &buf1) != 0) 8311867Sgjelinek return (B_FALSE); 8321867Sgjelinek 8331867Sgjelinek if (strcmp(buf1.f_basetype, "zfs") != 0) 8341867Sgjelinek return (B_FALSE); 8351867Sgjelinek 8361867Sgjelinek if ((path = strdup(zonepath)) == NULL) 8371867Sgjelinek return (B_FALSE); 8381867Sgjelinek 8391867Sgjelinek parent = dirname(path); 8402267Sdp res = statvfs64(parent, &buf2); 8411867Sgjelinek free(path); 8421867Sgjelinek 8431867Sgjelinek if (res != 0) 8441867Sgjelinek return (B_FALSE); 8451867Sgjelinek 8461867Sgjelinek if (buf1.f_fsid == buf2.f_fsid) 8471867Sgjelinek return (B_FALSE); 8481867Sgjelinek 8491867Sgjelinek return (B_TRUE); 8501867Sgjelinek } 8511867Sgjelinek 8521867Sgjelinek /* 8531867Sgjelinek * Implement the fast move of a ZFS file system by simply updating the 8541867Sgjelinek * mountpoint. Since it is file system already, we don't have the 8551867Sgjelinek * issue of cross-file system copying. 8561867Sgjelinek */ 8571867Sgjelinek int 8581867Sgjelinek move_zfs(char *zonepath, char *new_zonepath) 8591867Sgjelinek { 8601867Sgjelinek int ret = Z_ERR; 8611867Sgjelinek zfs_handle_t *zhp; 8621867Sgjelinek 8632082Seschrock if ((zhp = mount2zhandle(zonepath)) == NULL) 8641867Sgjelinek return (Z_ERR); 8651867Sgjelinek 8662676Seschrock if (zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_MOUNTPOINT), 8672676Seschrock new_zonepath) == 0) { 8681867Sgjelinek /* 8691867Sgjelinek * Clean up the old mount point. We ignore any failure since 8701867Sgjelinek * the zone is already successfully mounted on the new path. 8711867Sgjelinek */ 8721867Sgjelinek (void) rmdir(zonepath); 8731867Sgjelinek ret = Z_OK; 8741867Sgjelinek } 8751867Sgjelinek 8761867Sgjelinek zfs_close(zhp); 8771867Sgjelinek 8781867Sgjelinek return (ret); 8791867Sgjelinek } 8801867Sgjelinek 8811867Sgjelinek /* 8821867Sgjelinek * Validate that the given dataset exists on the system, and that neither it nor 8831867Sgjelinek * its children are zvols. 8841867Sgjelinek * 8851867Sgjelinek * Note that we don't do anything with the 'zoned' property here. All 8861867Sgjelinek * management is done in zoneadmd when the zone is actually rebooted. This 8871867Sgjelinek * allows us to automatically set the zoned property even when a zone is 8881867Sgjelinek * rebooted by the administrator. 8891867Sgjelinek */ 8901867Sgjelinek int 8911867Sgjelinek verify_datasets(zone_dochandle_t handle) 8921867Sgjelinek { 8931867Sgjelinek int return_code = Z_OK; 8941867Sgjelinek struct zone_dstab dstab; 8951867Sgjelinek zfs_handle_t *zhp; 8961867Sgjelinek char propbuf[ZFS_MAXPROPLEN]; 8971867Sgjelinek char source[ZFS_MAXNAMELEN]; 8981867Sgjelinek zfs_source_t srctype; 8991867Sgjelinek 9001867Sgjelinek if (zonecfg_setdsent(handle) != Z_OK) { 9011867Sgjelinek /* 9021867Sgjelinek * TRANSLATION_NOTE 9031867Sgjelinek * zfs and dataset are literals that should not be translated. 9041867Sgjelinek */ 9051867Sgjelinek (void) fprintf(stderr, gettext("could not verify zfs datasets: " 9061867Sgjelinek "unable to enumerate datasets\n")); 9071867Sgjelinek return (Z_ERR); 9081867Sgjelinek } 9091867Sgjelinek 9101867Sgjelinek while (zonecfg_getdsent(handle, &dstab) == Z_OK) { 9111867Sgjelinek 9122082Seschrock if ((zhp = zfs_open(g_zfs, dstab.zone_dataset_name, 9131867Sgjelinek ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME)) == NULL) { 9142082Seschrock (void) fprintf(stderr, gettext("could not verify zfs " 9152082Seschrock "dataset %s: %s\n"), dstab.zone_dataset_name, 9162082Seschrock libzfs_error_description(g_zfs)); 9171867Sgjelinek return_code = Z_ERR; 9181867Sgjelinek continue; 9191867Sgjelinek } 9201867Sgjelinek 9211867Sgjelinek if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, propbuf, 9221867Sgjelinek sizeof (propbuf), &srctype, source, 9231867Sgjelinek sizeof (source), 0) == 0 && 9241867Sgjelinek (srctype == ZFS_SRC_INHERITED)) { 9251867Sgjelinek (void) fprintf(stderr, gettext("could not verify zfs " 9261867Sgjelinek "dataset %s: mountpoint cannot be inherited\n"), 9271867Sgjelinek dstab.zone_dataset_name); 9281867Sgjelinek return_code = Z_ERR; 9291867Sgjelinek zfs_close(zhp); 9301867Sgjelinek continue; 9311867Sgjelinek } 9321867Sgjelinek 9331867Sgjelinek if (zfs_get_type(zhp) == ZFS_TYPE_VOLUME) { 9341867Sgjelinek (void) fprintf(stderr, gettext("cannot verify zfs " 9351867Sgjelinek "dataset %s: volumes cannot be specified as a " 9361867Sgjelinek "zone dataset resource\n"), 9371867Sgjelinek dstab.zone_dataset_name); 9381867Sgjelinek return_code = Z_ERR; 9391867Sgjelinek } 9401867Sgjelinek 9411867Sgjelinek if (zfs_iter_children(zhp, check_zvol, NULL) != 0) 9421867Sgjelinek return_code = Z_ERR; 9431867Sgjelinek 9441867Sgjelinek zfs_close(zhp); 9451867Sgjelinek } 9461867Sgjelinek (void) zonecfg_enddsent(handle); 9471867Sgjelinek 9481867Sgjelinek return (return_code); 9491867Sgjelinek } 9501867Sgjelinek 9511867Sgjelinek /* 9521867Sgjelinek * Verify that the ZFS dataset exists, and its mountpoint 9531867Sgjelinek * property is set to "legacy". 9541867Sgjelinek */ 9551867Sgjelinek int 9561867Sgjelinek verify_fs_zfs(struct zone_fstab *fstab) 9571867Sgjelinek { 9581867Sgjelinek zfs_handle_t *zhp; 9591867Sgjelinek char propbuf[ZFS_MAXPROPLEN]; 9601867Sgjelinek 9612082Seschrock if ((zhp = zfs_open(g_zfs, fstab->zone_fs_special, 9622082Seschrock ZFS_TYPE_ANY)) == NULL) { 9631867Sgjelinek (void) fprintf(stderr, gettext("could not verify fs %s: " 9641867Sgjelinek "could not access zfs dataset '%s'\n"), 9651867Sgjelinek fstab->zone_fs_dir, fstab->zone_fs_special); 9661867Sgjelinek return (Z_ERR); 9671867Sgjelinek } 9681867Sgjelinek 9691867Sgjelinek if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) { 9701867Sgjelinek (void) fprintf(stderr, gettext("cannot verify fs %s: " 9711867Sgjelinek "'%s' is not a file system\n"), 9721867Sgjelinek fstab->zone_fs_dir, fstab->zone_fs_special); 9731867Sgjelinek zfs_close(zhp); 9741867Sgjelinek return (Z_ERR); 9751867Sgjelinek } 9761867Sgjelinek 9771867Sgjelinek if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, propbuf, sizeof (propbuf), 9781867Sgjelinek NULL, NULL, 0, 0) != 0 || strcmp(propbuf, "legacy") != 0) { 9791867Sgjelinek (void) fprintf(stderr, gettext("could not verify fs %s: " 9801867Sgjelinek "zfs '%s' mountpoint is not \"legacy\"\n"), 9811867Sgjelinek fstab->zone_fs_dir, fstab->zone_fs_special); 9821867Sgjelinek zfs_close(zhp); 9831867Sgjelinek return (Z_ERR); 9841867Sgjelinek } 9851867Sgjelinek 9861867Sgjelinek zfs_close(zhp); 9871867Sgjelinek return (Z_OK); 9881867Sgjelinek } 9892082Seschrock 9902082Seschrock int 9912082Seschrock init_zfs(void) 9922082Seschrock { 9932082Seschrock if ((g_zfs = libzfs_init()) == NULL) { 9942082Seschrock (void) fprintf(stderr, gettext("failed to initialize ZFS " 9952082Seschrock "library\n")); 9962082Seschrock return (Z_ERR); 9972082Seschrock } 9982082Seschrock 9992082Seschrock return (Z_OK); 10002082Seschrock } 1001