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); 299*2199Sahrens 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; 4101867Sgjelinek 4112082Seschrock if ((zhp = zfs_open(g_zfs, snapshot_name, ZFS_TYPE_SNAPSHOT)) == NULL) 4121867Sgjelinek return (Z_NO_ENTRY); 4131867Sgjelinek 4141867Sgjelinek (void) printf(gettext("Cloning snapshot %s\n"), snapshot_name); 4151867Sgjelinek 4161867Sgjelinek err = zfs_clone(zhp, zonepath); 4171867Sgjelinek zfs_close(zhp); 4181867Sgjelinek if (err != 0) 4191867Sgjelinek return (Z_ERR); 4201867Sgjelinek 4211867Sgjelinek /* create the mountpoint if necessary */ 4222082Seschrock if ((clone = zfs_open(g_zfs, zonepath, ZFS_TYPE_ANY)) == NULL) 4231867Sgjelinek return (Z_ERR); 4241867Sgjelinek 4251867Sgjelinek /* 4261867Sgjelinek * The clone has been created so we need to print a diagnostic 4271867Sgjelinek * message if one of the following steps fails for some reason. 4281867Sgjelinek */ 4291867Sgjelinek if (zfs_mount(clone, NULL, 0) != 0) { 4301867Sgjelinek (void) fprintf(stderr, gettext("could not mount ZFS clone " 4311867Sgjelinek "%s\n"), zfs_get_name(clone)); 4321867Sgjelinek res = Z_ERR; 4331867Sgjelinek 4341867Sgjelinek } else { 4351867Sgjelinek if (zfs_prop_set(clone, ZFS_PROP_SHARENFS, "off") != 0) { 4361867Sgjelinek /* we won't consider this a failure */ 4371867Sgjelinek (void) fprintf(stderr, gettext("could not turn off the " 4381867Sgjelinek "'sharenfs' property on ZFS clone %s\n"), 4391867Sgjelinek zfs_get_name(clone)); 4401867Sgjelinek } 4411867Sgjelinek 4421867Sgjelinek if (clean_out_clone() != Z_OK) { 4431867Sgjelinek (void) fprintf(stderr, gettext("could not remove the " 4441867Sgjelinek "software inventory from ZFS clone %s\n"), 4451867Sgjelinek zfs_get_name(clone)); 4461867Sgjelinek res = Z_ERR; 4471867Sgjelinek } 4481867Sgjelinek } 4491867Sgjelinek 4501867Sgjelinek zfs_close(clone); 4511867Sgjelinek return (res); 4521867Sgjelinek } 4531867Sgjelinek 4541867Sgjelinek /* 4551867Sgjelinek * This function takes a zonepath and attempts to determine what the ZFS 4561867Sgjelinek * file system name (not mountpoint) should be for that path. We do not 4571867Sgjelinek * assume that zonepath is an existing directory or ZFS fs since we use 4581867Sgjelinek * this function as part of the process of creating a new ZFS fs or clone. 4591867Sgjelinek * 4601867Sgjelinek * The way this works is that we look at the parent directory of the zonepath 4611867Sgjelinek * to see if it is a ZFS fs. If it is, we get the name of that ZFS fs and 4621867Sgjelinek * append the last component of the zonepath to generate the ZFS name for the 4631867Sgjelinek * zonepath. This matches the algorithm that ZFS uses for automatically 4641867Sgjelinek * mounting a new fs after it is created. 4651867Sgjelinek * 4661867Sgjelinek * Although a ZFS fs can be mounted anywhere, we don't worry about handling 4671867Sgjelinek * all of the complexity that a user could possibly configure with arbitrary 4681867Sgjelinek * mounts since there is no way to generate a ZFS name from a random path in 4691867Sgjelinek * the file system. We only try to handle the automatic mounts that ZFS does 4701867Sgjelinek * for each file system. ZFS restricts this so that a new fs must be created 4711867Sgjelinek * in an existing parent ZFS fs. It then automatically mounts the new fs 4721867Sgjelinek * directly under the mountpoint for the parent fs using the last component 4731867Sgjelinek * of the name as the mountpoint directory. 4741867Sgjelinek * 4751867Sgjelinek * For example: 4761867Sgjelinek * Name Mountpoint 4771867Sgjelinek * space/eng/dev/test/zone1 /project1/eng/dev/test/zone1 4781867Sgjelinek * 4791867Sgjelinek * Return Z_OK if the path mapped to a ZFS file system name, otherwise return 4801867Sgjelinek * Z_ERR. 4811867Sgjelinek */ 4821867Sgjelinek static int 4831867Sgjelinek path2name(char *zonepath, char *zfs_name, int len) 4841867Sgjelinek { 4851867Sgjelinek int res; 4861867Sgjelinek char *p; 4871867Sgjelinek zfs_handle_t *zhp; 4881867Sgjelinek 4891867Sgjelinek if ((p = strrchr(zonepath, '/')) == NULL) 4901867Sgjelinek return (Z_ERR); 4911867Sgjelinek 4921867Sgjelinek /* 4931867Sgjelinek * If the parent directory is not its own ZFS fs, then we can't 4941867Sgjelinek * automatically create a new ZFS fs at the 'zonepath' mountpoint 4951867Sgjelinek * so return an error. 4961867Sgjelinek */ 4971867Sgjelinek *p = '\0'; 4981867Sgjelinek zhp = mount2zhandle(zonepath); 4991867Sgjelinek *p = '/'; 5001867Sgjelinek if (zhp == NULL) 5011867Sgjelinek return (Z_ERR); 5021867Sgjelinek 5031867Sgjelinek res = snprintf(zfs_name, len, "%s/%s", zfs_get_name(zhp), p + 1); 5041867Sgjelinek 5051867Sgjelinek zfs_close(zhp); 5061867Sgjelinek if (res >= len) 5071867Sgjelinek return (Z_ERR); 5081867Sgjelinek 5091867Sgjelinek return (Z_OK); 5101867Sgjelinek } 5111867Sgjelinek 5121867Sgjelinek /* 5131867Sgjelinek * A ZFS file system iterator call-back function used to determine if the 5141867Sgjelinek * file system has dependents (snapshots & clones). 5151867Sgjelinek */ 5161867Sgjelinek /* ARGSUSED */ 5171867Sgjelinek static int 5181867Sgjelinek has_dependent(zfs_handle_t *zhp, void *data) 5191867Sgjelinek { 5201867Sgjelinek zfs_close(zhp); 5211867Sgjelinek return (1); 5221867Sgjelinek } 5231867Sgjelinek 5241867Sgjelinek /* 5251867Sgjelinek * Given a snapshot name, get the file system path where the snapshot lives. 5261867Sgjelinek * A snapshot name is of the form fs_name@snap_name. For example, snapshot 5271867Sgjelinek * pl/zones/z1@SUNWzone1 would have a path of 5281867Sgjelinek * /pl/zones/z1/.zfs/snapshot/SUNWzone1. 5291867Sgjelinek */ 5301867Sgjelinek static int 5311867Sgjelinek snap2path(char *snap_name, char *path, int len) 5321867Sgjelinek { 5331867Sgjelinek char *p; 5341867Sgjelinek zfs_handle_t *zhp; 5351867Sgjelinek char mp[ZFS_MAXPROPLEN]; 5361867Sgjelinek 5371867Sgjelinek if ((p = strrchr(snap_name, '@')) == NULL) 5381867Sgjelinek return (Z_ERR); 5391867Sgjelinek 5401867Sgjelinek /* Get the file system name from the snap_name. */ 5411867Sgjelinek *p = '\0'; 5422082Seschrock zhp = zfs_open(g_zfs, snap_name, ZFS_TYPE_ANY); 5431867Sgjelinek *p = '@'; 5441867Sgjelinek if (zhp == NULL) 5451867Sgjelinek return (Z_ERR); 5461867Sgjelinek 5471867Sgjelinek /* Get the file system mount point. */ 5481867Sgjelinek if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mp, sizeof (mp), NULL, NULL, 5492082Seschrock 0, B_FALSE) != 0) { 5501867Sgjelinek zfs_close(zhp); 5511867Sgjelinek return (Z_ERR); 5521867Sgjelinek } 5531867Sgjelinek zfs_close(zhp); 5541867Sgjelinek 5551867Sgjelinek p++; 5561867Sgjelinek if (snprintf(path, len, "%s/.zfs/snapshot/%s", mp, p) >= len) 5571867Sgjelinek return (Z_ERR); 5581867Sgjelinek 5591867Sgjelinek return (Z_OK); 5601867Sgjelinek } 5611867Sgjelinek 5621867Sgjelinek /* 5631867Sgjelinek * Clone a pre-existing ZFS snapshot, either by making a direct ZFS clone, if 5641867Sgjelinek * possible, or by copying the data from the snapshot to the zonepath. 5651867Sgjelinek */ 5661867Sgjelinek int 5671867Sgjelinek clone_snapshot_zfs(char *snap_name, char *zonepath) 5681867Sgjelinek { 5691867Sgjelinek int err = Z_OK; 5701867Sgjelinek char clone_name[MAXPATHLEN]; 5711867Sgjelinek char snap_path[MAXPATHLEN]; 5721867Sgjelinek 5731867Sgjelinek if (snap2path(snap_name, snap_path, sizeof (snap_path)) != Z_OK) { 5741867Sgjelinek (void) fprintf(stderr, gettext("unable to find path for %s.\n"), 5751867Sgjelinek snap_name); 5761867Sgjelinek return (Z_ERR); 5771867Sgjelinek } 5781867Sgjelinek 5791867Sgjelinek if (validate_snapshot(snap_name, snap_path) != Z_OK) 5801867Sgjelinek return (Z_NO_ENTRY); 5811867Sgjelinek 5821867Sgjelinek /* 5831867Sgjelinek * The zonepath cannot be ZFS cloned, try to copy the data from 5841867Sgjelinek * within the snapshot to the zonepath. 5851867Sgjelinek */ 5861867Sgjelinek if (path2name(zonepath, clone_name, sizeof (clone_name)) != Z_OK) { 5871867Sgjelinek if ((err = clone_copy(snap_path, zonepath)) == Z_OK) 5881867Sgjelinek if (clean_out_clone() != Z_OK) 5891867Sgjelinek (void) fprintf(stderr, 5901867Sgjelinek gettext("could not remove the " 5911867Sgjelinek "software inventory from %s\n"), zonepath); 5921867Sgjelinek 5931867Sgjelinek return (err); 5941867Sgjelinek } 5951867Sgjelinek 5961867Sgjelinek if ((err = clone_snap(snap_name, clone_name)) != Z_OK) { 5971867Sgjelinek if (err != Z_NO_ENTRY) { 5981867Sgjelinek /* 5991867Sgjelinek * Cloning the snapshot failed. Fall back to trying 6001867Sgjelinek * to install the zone by copying from the snapshot. 6011867Sgjelinek */ 6021867Sgjelinek if ((err = clone_copy(snap_path, zonepath)) == Z_OK) 6031867Sgjelinek if (clean_out_clone() != Z_OK) 6041867Sgjelinek (void) fprintf(stderr, 6051867Sgjelinek gettext("could not remove the " 6061867Sgjelinek "software inventory from %s\n"), 6071867Sgjelinek zonepath); 6081867Sgjelinek } else { 6091867Sgjelinek /* 6101867Sgjelinek * The snapshot is unusable for some reason so restore 6111867Sgjelinek * the zone state to configured since we were unable to 6121867Sgjelinek * actually do anything about getting the zone 6131867Sgjelinek * installed. 6141867Sgjelinek */ 6151867Sgjelinek int tmp; 6161867Sgjelinek 6171867Sgjelinek if ((tmp = zone_set_state(target_zone, 6181867Sgjelinek ZONE_STATE_CONFIGURED)) != Z_OK) { 6191867Sgjelinek errno = tmp; 6201867Sgjelinek zperror2(target_zone, 6211867Sgjelinek gettext("could not set state")); 6221867Sgjelinek } 6231867Sgjelinek } 6241867Sgjelinek } 6251867Sgjelinek 6261867Sgjelinek return (err); 6271867Sgjelinek } 6281867Sgjelinek 6291867Sgjelinek /* 6301867Sgjelinek * Attempt to clone a source_zone to a target zonepath by using a ZFS clone. 6311867Sgjelinek */ 6321867Sgjelinek int 6331867Sgjelinek clone_zfs(char *source_zone, char *source_zonepath, char *zonepath) 6341867Sgjelinek { 6351867Sgjelinek zfs_handle_t *zhp; 6361867Sgjelinek char clone_name[MAXPATHLEN]; 6371867Sgjelinek char snap_name[MAXPATHLEN]; 6381867Sgjelinek 6391867Sgjelinek /* 6401867Sgjelinek * Try to get a zfs handle for the source_zonepath. If this fails 6411867Sgjelinek * the source_zonepath is not ZFS so return an error. 6421867Sgjelinek */ 6431867Sgjelinek if ((zhp = mount2zhandle(source_zonepath)) == NULL) 6441867Sgjelinek return (Z_ERR); 6451867Sgjelinek 6461867Sgjelinek /* 6471867Sgjelinek * Check if there is a file system already mounted on zonepath. If so, 6481867Sgjelinek * we can't clone to the path so we should fall back to copying. 6491867Sgjelinek */ 6501867Sgjelinek if (is_mountpnt(zonepath)) { 6511867Sgjelinek zfs_close(zhp); 6521867Sgjelinek (void) fprintf(stderr, 6531867Sgjelinek gettext("A file system is already mounted on %s,\n" 6541867Sgjelinek "preventing use of a ZFS clone.\n"), zonepath); 6551867Sgjelinek return (Z_ERR); 6561867Sgjelinek } 6571867Sgjelinek 6581867Sgjelinek /* 6591867Sgjelinek * Instead of using path2name to get the clone name from the zonepath, 6601867Sgjelinek * we could generate a name from the source zone ZFS name. However, 6611867Sgjelinek * this would mean we would create the clone under the ZFS fs of the 6621867Sgjelinek * source instead of what the zonepath says. For example, 6631867Sgjelinek * 6641867Sgjelinek * source_zonepath zonepath 6651867Sgjelinek * /pl/zones/dev/z1 /pl/zones/deploy/z2 6661867Sgjelinek * 6671867Sgjelinek * We don't want the clone to be under "dev", we want it under 6681867Sgjelinek * "deploy", so that we can leverage the normal attribute inheritance 6691867Sgjelinek * that ZFS provides in the fs hierarchy. 6701867Sgjelinek */ 6711867Sgjelinek if (path2name(zonepath, clone_name, sizeof (clone_name)) != Z_OK) { 6721867Sgjelinek zfs_close(zhp); 6731867Sgjelinek return (Z_ERR); 6741867Sgjelinek } 6751867Sgjelinek 6761867Sgjelinek if (take_snapshot(source_zone, zhp, snap_name, sizeof (snap_name)) 6771867Sgjelinek != Z_OK) { 6781867Sgjelinek zfs_close(zhp); 6791867Sgjelinek return (Z_ERR); 6801867Sgjelinek } 6811867Sgjelinek zfs_close(zhp); 6821867Sgjelinek 6831867Sgjelinek if (clone_snap(snap_name, clone_name) != Z_OK) 6841867Sgjelinek return (Z_ERR); 6851867Sgjelinek 6861867Sgjelinek (void) printf(gettext("Instead of copying, a ZFS clone has been " 6871867Sgjelinek "created for this zone.\n")); 6881867Sgjelinek 6891867Sgjelinek return (Z_OK); 6901867Sgjelinek } 6911867Sgjelinek 6921867Sgjelinek /* 6931867Sgjelinek * Attempt to create a ZFS file system for the specified zonepath. 6941867Sgjelinek * We either will successfully create a ZFS file system and get it mounted 6951867Sgjelinek * on the zonepath or we don't. The caller doesn't care since a regular 6961867Sgjelinek * directory is used for the zonepath if no ZFS file system is mounted there. 6971867Sgjelinek */ 6981867Sgjelinek void 6991867Sgjelinek create_zfs_zonepath(char *zonepath) 7001867Sgjelinek { 7011867Sgjelinek zfs_handle_t *zhp; 7021867Sgjelinek char zfs_name[MAXPATHLEN]; 7031867Sgjelinek 7041867Sgjelinek if (path2name(zonepath, zfs_name, sizeof (zfs_name)) != Z_OK) 7051867Sgjelinek return; 7061867Sgjelinek 7072082Seschrock if (zfs_create(g_zfs, zfs_name, ZFS_TYPE_FILESYSTEM, NULL, NULL) != 0 || 7082082Seschrock (zhp = zfs_open(g_zfs, zfs_name, ZFS_TYPE_ANY)) == NULL) { 7092082Seschrock (void) fprintf(stderr, gettext("cannot create ZFS dataset %s: " 7102082Seschrock "%s\n"), zfs_name, libzfs_error_description(g_zfs)); 7111867Sgjelinek return; 7121867Sgjelinek } 7131867Sgjelinek 7141867Sgjelinek if (zfs_mount(zhp, NULL, 0) != 0) { 7152082Seschrock (void) fprintf(stderr, gettext("cannot mount ZFS dataset %s: " 7162082Seschrock "%s\n"), zfs_name, libzfs_error_description(g_zfs)); 7171867Sgjelinek (void) zfs_destroy(zhp); 7181867Sgjelinek } else if (zfs_prop_set(zhp, ZFS_PROP_SHARENFS, "off") != 0) { 7191867Sgjelinek (void) fprintf(stderr, gettext("file system %s successfully " 7201867Sgjelinek "created,\nbut could not turn off the 'sharenfs' " 7211867Sgjelinek "property\n"), zfs_name); 7221867Sgjelinek } else { 7231867Sgjelinek if (chmod(zonepath, S_IRWXU) != 0) { 7241867Sgjelinek (void) fprintf(stderr, gettext("file system %s " 7251867Sgjelinek "successfully created, but chmod %o failed: %s\n"), 7261867Sgjelinek zfs_name, S_IRWXU, strerror(errno)); 7271867Sgjelinek (void) destroy_zfs(zonepath); 7281867Sgjelinek } else { 7291867Sgjelinek (void) printf(gettext("A ZFS file system has been " 7301867Sgjelinek "created for this zone.\n")); 7311867Sgjelinek } 7321867Sgjelinek } 7331867Sgjelinek 7341867Sgjelinek zfs_close(zhp); 7351867Sgjelinek } 7361867Sgjelinek 7371867Sgjelinek /* 7381867Sgjelinek * If the zonepath is a ZFS file system, attempt to destroy it. We return Z_OK 7391867Sgjelinek * if we were able to zfs_destroy the zonepath, otherwise we return Z_ERR 7401867Sgjelinek * which means the caller should clean up the zonepath in the traditional 7411867Sgjelinek * way. 7421867Sgjelinek */ 7431867Sgjelinek int 7441867Sgjelinek destroy_zfs(char *zonepath) 7451867Sgjelinek { 7461867Sgjelinek zfs_handle_t *zhp; 7471867Sgjelinek boolean_t is_clone = B_FALSE; 7481867Sgjelinek char origin[ZFS_MAXPROPLEN]; 7491867Sgjelinek 7502082Seschrock if ((zhp = mount2zhandle(zonepath)) == NULL) 7511867Sgjelinek return (Z_ERR); 7521867Sgjelinek 7531867Sgjelinek /* 7541867Sgjelinek * We can't destroy the file system if it has dependents. 7551867Sgjelinek */ 7561867Sgjelinek if (zfs_iter_dependents(zhp, has_dependent, NULL) != 0 || 7571867Sgjelinek zfs_unmount(zhp, NULL, 0) != 0) { 7581867Sgjelinek zfs_close(zhp); 7591867Sgjelinek return (Z_ERR); 7601867Sgjelinek } 7611867Sgjelinek 7621867Sgjelinek /* 7631867Sgjelinek * This might be a clone. Try to get the snapshot so we can attempt 7641867Sgjelinek * to destroy that as well. 7651867Sgjelinek */ 7661867Sgjelinek if (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, origin, sizeof (origin), NULL, 7672082Seschrock NULL, 0, B_FALSE) == 0) 7681867Sgjelinek is_clone = B_TRUE; 7691867Sgjelinek 7701867Sgjelinek if (zfs_destroy(zhp) != 0) { 7711867Sgjelinek /* 7721867Sgjelinek * If the destroy fails for some reason, try to remount 7731867Sgjelinek * the file system so that we can use "rm -rf" to clean up 7741867Sgjelinek * instead. 7751867Sgjelinek */ 7761867Sgjelinek (void) zfs_mount(zhp, NULL, 0); 7771867Sgjelinek zfs_close(zhp); 7781867Sgjelinek return (Z_ERR); 7791867Sgjelinek } 7801867Sgjelinek 7811867Sgjelinek (void) printf(gettext("The ZFS file system for this zone has been " 7821867Sgjelinek "destroyed.\n")); 7831867Sgjelinek 7841867Sgjelinek if (is_clone) { 7851867Sgjelinek zfs_handle_t *ohp; 7861867Sgjelinek 7871867Sgjelinek /* 7881867Sgjelinek * Try to clean up the snapshot that the clone was taken from. 7891867Sgjelinek */ 7902082Seschrock if ((ohp = zfs_open(g_zfs, origin, 7912082Seschrock ZFS_TYPE_SNAPSHOT)) != NULL) { 7921867Sgjelinek if (zfs_iter_dependents(ohp, has_dependent, NULL) 7932082Seschrock == 0 && zfs_unmount(ohp, NULL, 0) == 0) 7941867Sgjelinek (void) zfs_destroy(ohp); 7951867Sgjelinek zfs_close(ohp); 7961867Sgjelinek } 7971867Sgjelinek } 7981867Sgjelinek 7991867Sgjelinek zfs_close(zhp); 8001867Sgjelinek return (Z_OK); 8011867Sgjelinek } 8021867Sgjelinek 8031867Sgjelinek /* 8041867Sgjelinek * Return true if the path is its own zfs file system. We determine this 8051867Sgjelinek * by stat-ing the path to see if it is zfs and stat-ing the parent to see 8061867Sgjelinek * if it is a different fs. 8071867Sgjelinek */ 8081867Sgjelinek boolean_t 8091867Sgjelinek is_zonepath_zfs(char *zonepath) 8101867Sgjelinek { 8111867Sgjelinek int res; 8121867Sgjelinek char *path; 8131867Sgjelinek char *parent; 8141867Sgjelinek struct statvfs buf1, buf2; 8151867Sgjelinek 8161867Sgjelinek if (statvfs(zonepath, &buf1) != 0) 8171867Sgjelinek return (B_FALSE); 8181867Sgjelinek 8191867Sgjelinek if (strcmp(buf1.f_basetype, "zfs") != 0) 8201867Sgjelinek return (B_FALSE); 8211867Sgjelinek 8221867Sgjelinek if ((path = strdup(zonepath)) == NULL) 8231867Sgjelinek return (B_FALSE); 8241867Sgjelinek 8251867Sgjelinek parent = dirname(path); 8261867Sgjelinek res = statvfs(parent, &buf2); 8271867Sgjelinek free(path); 8281867Sgjelinek 8291867Sgjelinek if (res != 0) 8301867Sgjelinek return (B_FALSE); 8311867Sgjelinek 8321867Sgjelinek if (buf1.f_fsid == buf2.f_fsid) 8331867Sgjelinek return (B_FALSE); 8341867Sgjelinek 8351867Sgjelinek return (B_TRUE); 8361867Sgjelinek } 8371867Sgjelinek 8381867Sgjelinek /* 8391867Sgjelinek * Implement the fast move of a ZFS file system by simply updating the 8401867Sgjelinek * mountpoint. Since it is file system already, we don't have the 8411867Sgjelinek * issue of cross-file system copying. 8421867Sgjelinek */ 8431867Sgjelinek int 8441867Sgjelinek move_zfs(char *zonepath, char *new_zonepath) 8451867Sgjelinek { 8461867Sgjelinek int ret = Z_ERR; 8471867Sgjelinek zfs_handle_t *zhp; 8481867Sgjelinek 8492082Seschrock if ((zhp = mount2zhandle(zonepath)) == NULL) 8501867Sgjelinek return (Z_ERR); 8511867Sgjelinek 8521867Sgjelinek if (zfs_prop_set(zhp, ZFS_PROP_MOUNTPOINT, new_zonepath) == 0) { 8531867Sgjelinek /* 8541867Sgjelinek * Clean up the old mount point. We ignore any failure since 8551867Sgjelinek * the zone is already successfully mounted on the new path. 8561867Sgjelinek */ 8571867Sgjelinek (void) rmdir(zonepath); 8581867Sgjelinek ret = Z_OK; 8591867Sgjelinek } 8601867Sgjelinek 8611867Sgjelinek zfs_close(zhp); 8621867Sgjelinek 8631867Sgjelinek return (ret); 8641867Sgjelinek } 8651867Sgjelinek 8661867Sgjelinek /* 8671867Sgjelinek * Validate that the given dataset exists on the system, and that neither it nor 8681867Sgjelinek * its children are zvols. 8691867Sgjelinek * 8701867Sgjelinek * Note that we don't do anything with the 'zoned' property here. All 8711867Sgjelinek * management is done in zoneadmd when the zone is actually rebooted. This 8721867Sgjelinek * allows us to automatically set the zoned property even when a zone is 8731867Sgjelinek * rebooted by the administrator. 8741867Sgjelinek */ 8751867Sgjelinek int 8761867Sgjelinek verify_datasets(zone_dochandle_t handle) 8771867Sgjelinek { 8781867Sgjelinek int return_code = Z_OK; 8791867Sgjelinek struct zone_dstab dstab; 8801867Sgjelinek zfs_handle_t *zhp; 8811867Sgjelinek char propbuf[ZFS_MAXPROPLEN]; 8821867Sgjelinek char source[ZFS_MAXNAMELEN]; 8831867Sgjelinek zfs_source_t srctype; 8841867Sgjelinek 8851867Sgjelinek if (zonecfg_setdsent(handle) != Z_OK) { 8861867Sgjelinek /* 8871867Sgjelinek * TRANSLATION_NOTE 8881867Sgjelinek * zfs and dataset are literals that should not be translated. 8891867Sgjelinek */ 8901867Sgjelinek (void) fprintf(stderr, gettext("could not verify zfs datasets: " 8911867Sgjelinek "unable to enumerate datasets\n")); 8921867Sgjelinek return (Z_ERR); 8931867Sgjelinek } 8941867Sgjelinek 8951867Sgjelinek while (zonecfg_getdsent(handle, &dstab) == Z_OK) { 8961867Sgjelinek 8972082Seschrock if ((zhp = zfs_open(g_zfs, dstab.zone_dataset_name, 8981867Sgjelinek ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME)) == NULL) { 8992082Seschrock (void) fprintf(stderr, gettext("could not verify zfs " 9002082Seschrock "dataset %s: %s\n"), dstab.zone_dataset_name, 9012082Seschrock libzfs_error_description(g_zfs)); 9021867Sgjelinek return_code = Z_ERR; 9031867Sgjelinek continue; 9041867Sgjelinek } 9051867Sgjelinek 9061867Sgjelinek if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, propbuf, 9071867Sgjelinek sizeof (propbuf), &srctype, source, 9081867Sgjelinek sizeof (source), 0) == 0 && 9091867Sgjelinek (srctype == ZFS_SRC_INHERITED)) { 9101867Sgjelinek (void) fprintf(stderr, gettext("could not verify zfs " 9111867Sgjelinek "dataset %s: mountpoint cannot be inherited\n"), 9121867Sgjelinek dstab.zone_dataset_name); 9131867Sgjelinek return_code = Z_ERR; 9141867Sgjelinek zfs_close(zhp); 9151867Sgjelinek continue; 9161867Sgjelinek } 9171867Sgjelinek 9181867Sgjelinek if (zfs_get_type(zhp) == ZFS_TYPE_VOLUME) { 9191867Sgjelinek (void) fprintf(stderr, gettext("cannot verify zfs " 9201867Sgjelinek "dataset %s: volumes cannot be specified as a " 9211867Sgjelinek "zone dataset resource\n"), 9221867Sgjelinek dstab.zone_dataset_name); 9231867Sgjelinek return_code = Z_ERR; 9241867Sgjelinek } 9251867Sgjelinek 9261867Sgjelinek if (zfs_iter_children(zhp, check_zvol, NULL) != 0) 9271867Sgjelinek return_code = Z_ERR; 9281867Sgjelinek 9291867Sgjelinek zfs_close(zhp); 9301867Sgjelinek } 9311867Sgjelinek (void) zonecfg_enddsent(handle); 9321867Sgjelinek 9331867Sgjelinek return (return_code); 9341867Sgjelinek } 9351867Sgjelinek 9361867Sgjelinek /* 9371867Sgjelinek * Verify that the ZFS dataset exists, and its mountpoint 9381867Sgjelinek * property is set to "legacy". 9391867Sgjelinek */ 9401867Sgjelinek int 9411867Sgjelinek verify_fs_zfs(struct zone_fstab *fstab) 9421867Sgjelinek { 9431867Sgjelinek zfs_handle_t *zhp; 9441867Sgjelinek char propbuf[ZFS_MAXPROPLEN]; 9451867Sgjelinek 9462082Seschrock if ((zhp = zfs_open(g_zfs, fstab->zone_fs_special, 9472082Seschrock ZFS_TYPE_ANY)) == NULL) { 9481867Sgjelinek (void) fprintf(stderr, gettext("could not verify fs %s: " 9491867Sgjelinek "could not access zfs dataset '%s'\n"), 9501867Sgjelinek fstab->zone_fs_dir, fstab->zone_fs_special); 9511867Sgjelinek return (Z_ERR); 9521867Sgjelinek } 9531867Sgjelinek 9541867Sgjelinek if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) { 9551867Sgjelinek (void) fprintf(stderr, gettext("cannot verify fs %s: " 9561867Sgjelinek "'%s' is not a file system\n"), 9571867Sgjelinek fstab->zone_fs_dir, fstab->zone_fs_special); 9581867Sgjelinek zfs_close(zhp); 9591867Sgjelinek return (Z_ERR); 9601867Sgjelinek } 9611867Sgjelinek 9621867Sgjelinek if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, propbuf, sizeof (propbuf), 9631867Sgjelinek NULL, NULL, 0, 0) != 0 || strcmp(propbuf, "legacy") != 0) { 9641867Sgjelinek (void) fprintf(stderr, gettext("could not verify fs %s: " 9651867Sgjelinek "zfs '%s' mountpoint is not \"legacy\"\n"), 9661867Sgjelinek fstab->zone_fs_dir, fstab->zone_fs_special); 9671867Sgjelinek zfs_close(zhp); 9681867Sgjelinek return (Z_ERR); 9691867Sgjelinek } 9701867Sgjelinek 9711867Sgjelinek zfs_close(zhp); 9721867Sgjelinek return (Z_OK); 9731867Sgjelinek } 9742082Seschrock 9752082Seschrock int 9762082Seschrock init_zfs(void) 9772082Seschrock { 9782082Seschrock if ((g_zfs = libzfs_init()) == NULL) { 9792082Seschrock (void) fprintf(stderr, gettext("failed to initialize ZFS " 9802082Seschrock "library\n")); 9812082Seschrock return (Z_ERR); 9822082Seschrock } 9832082Seschrock 9842082Seschrock return (Z_OK); 9852082Seschrock } 986