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 /* 23*9023Sgerald.jelinek@sun.com * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 241867Sgjelinek * Use is subject to license terms. 251867Sgjelinek */ 261867Sgjelinek 271867Sgjelinek /* 281867Sgjelinek * This file contains the functions used to support the ZFS integration 291867Sgjelinek * with zones. This includes validation (e.g. zonecfg dataset), cloning, 301867Sgjelinek * file system creation and destruction. 311867Sgjelinek */ 321867Sgjelinek 331867Sgjelinek #include <stdio.h> 341867Sgjelinek #include <errno.h> 351867Sgjelinek #include <unistd.h> 361867Sgjelinek #include <string.h> 371867Sgjelinek #include <locale.h> 381867Sgjelinek #include <libintl.h> 391867Sgjelinek #include <sys/stat.h> 401867Sgjelinek #include <sys/statvfs.h> 411867Sgjelinek #include <libgen.h> 421867Sgjelinek #include <libzonecfg.h> 431867Sgjelinek #include <sys/mnttab.h> 441867Sgjelinek #include <libzfs.h> 457093Sgjelinek #include <sys/mntent.h> 461867Sgjelinek 471867Sgjelinek #include "zoneadm.h" 481867Sgjelinek 492082Seschrock libzfs_handle_t *g_zfs; 501867Sgjelinek 511867Sgjelinek typedef struct zfs_mount_data { 521867Sgjelinek char *match_name; 531867Sgjelinek zfs_handle_t *match_handle; 541867Sgjelinek } zfs_mount_data_t; 551867Sgjelinek 561867Sgjelinek typedef struct zfs_snapshot_data { 571867Sgjelinek char *match_name; 581867Sgjelinek int len; 591867Sgjelinek int max; 601867Sgjelinek } zfs_snapshot_data_t; 611867Sgjelinek 621867Sgjelinek /* 631867Sgjelinek * A ZFS file system iterator call-back function which is used to validate 641867Sgjelinek * datasets imported into the zone. 651867Sgjelinek */ 661867Sgjelinek /* ARGSUSED */ 671867Sgjelinek static int 681867Sgjelinek check_zvol(zfs_handle_t *zhp, void *unused) 691867Sgjelinek { 701867Sgjelinek int ret; 711867Sgjelinek 721867Sgjelinek if (zfs_get_type(zhp) == ZFS_TYPE_VOLUME) { 731867Sgjelinek /* 741867Sgjelinek * TRANSLATION_NOTE 751867Sgjelinek * zfs and dataset are literals that should not be translated. 761867Sgjelinek */ 771867Sgjelinek (void) fprintf(stderr, gettext("cannot verify zfs dataset %s: " 781867Sgjelinek "volumes cannot be specified as a zone dataset resource\n"), 791867Sgjelinek zfs_get_name(zhp)); 801867Sgjelinek ret = -1; 811867Sgjelinek } else { 821867Sgjelinek ret = zfs_iter_children(zhp, check_zvol, NULL); 831867Sgjelinek } 841867Sgjelinek 851867Sgjelinek zfs_close(zhp); 861867Sgjelinek 871867Sgjelinek return (ret); 881867Sgjelinek } 891867Sgjelinek 901867Sgjelinek /* 911867Sgjelinek * A ZFS file system iterator call-back function which returns the 921867Sgjelinek * zfs_handle_t for a ZFS file system on the specified mount point. 931867Sgjelinek */ 941867Sgjelinek static int 951867Sgjelinek match_mountpoint(zfs_handle_t *zhp, void *data) 961867Sgjelinek { 971867Sgjelinek int res; 981867Sgjelinek zfs_mount_data_t *cbp; 991867Sgjelinek char mp[ZFS_MAXPROPLEN]; 1001867Sgjelinek 1011867Sgjelinek if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) { 1021867Sgjelinek zfs_close(zhp); 1031867Sgjelinek return (0); 1041867Sgjelinek } 1051867Sgjelinek 1067093Sgjelinek /* First check if the dataset is mounted. */ 1077093Sgjelinek if (zfs_prop_get(zhp, ZFS_PROP_MOUNTED, mp, sizeof (mp), NULL, NULL, 1087093Sgjelinek 0, B_FALSE) != 0 || strcmp(mp, "no") == 0) { 1097093Sgjelinek zfs_close(zhp); 1107093Sgjelinek return (0); 1117093Sgjelinek } 1127093Sgjelinek 1137093Sgjelinek /* Now check mount point. */ 1141867Sgjelinek if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mp, sizeof (mp), NULL, NULL, 1157093Sgjelinek 0, B_FALSE) != 0) { 1167093Sgjelinek zfs_close(zhp); 1177093Sgjelinek return (0); 1187093Sgjelinek } 1197093Sgjelinek 1207093Sgjelinek cbp = (zfs_mount_data_t *)data; 1217093Sgjelinek 1227093Sgjelinek if (strcmp(mp, "legacy") == 0) { 1237093Sgjelinek /* If legacy, must look in mnttab for mountpoint. */ 1247093Sgjelinek FILE *fp; 1257093Sgjelinek struct mnttab entry; 1267093Sgjelinek const char *nm; 1277093Sgjelinek 1287093Sgjelinek nm = zfs_get_name(zhp); 1297093Sgjelinek if ((fp = fopen(MNTTAB, "r")) == NULL) { 1307093Sgjelinek zfs_close(zhp); 1317093Sgjelinek return (0); 1327093Sgjelinek } 1337093Sgjelinek 1347093Sgjelinek while (getmntent(fp, &entry) == 0) { 1357093Sgjelinek if (strcmp(nm, entry.mnt_special) == 0) { 1367093Sgjelinek if (strcmp(entry.mnt_mountp, cbp->match_name) 1377093Sgjelinek == 0) { 1387093Sgjelinek (void) fclose(fp); 1397093Sgjelinek cbp->match_handle = zhp; 1407093Sgjelinek return (1); 1417093Sgjelinek } 1427093Sgjelinek break; 1437093Sgjelinek } 1447093Sgjelinek } 1457093Sgjelinek (void) fclose(fp); 1467093Sgjelinek 1477093Sgjelinek } else if (strcmp(mp, cbp->match_name) == 0) { 1481867Sgjelinek cbp->match_handle = zhp; 1491867Sgjelinek return (1); 1501867Sgjelinek } 1511867Sgjelinek 1527093Sgjelinek /* Iterate over any nested datasets. */ 1531867Sgjelinek res = zfs_iter_filesystems(zhp, match_mountpoint, data); 1541867Sgjelinek zfs_close(zhp); 1551867Sgjelinek return (res); 1561867Sgjelinek } 1571867Sgjelinek 1581867Sgjelinek /* 1591867Sgjelinek * Get ZFS handle for the specified mount point. 1601867Sgjelinek */ 1611867Sgjelinek static zfs_handle_t * 1621867Sgjelinek mount2zhandle(char *mountpoint) 1631867Sgjelinek { 1641867Sgjelinek zfs_mount_data_t cb; 1651867Sgjelinek 1661867Sgjelinek cb.match_name = mountpoint; 1671867Sgjelinek cb.match_handle = NULL; 1682082Seschrock (void) zfs_iter_root(g_zfs, match_mountpoint, &cb); 1691867Sgjelinek return (cb.match_handle); 1701867Sgjelinek } 1711867Sgjelinek 1721867Sgjelinek /* 1731867Sgjelinek * Check if there is already a file system (zfs or any other type) mounted on 1741867Sgjelinek * path. 1751867Sgjelinek */ 1761867Sgjelinek static boolean_t 1771867Sgjelinek is_mountpnt(char *path) 1781867Sgjelinek { 1791867Sgjelinek FILE *fp; 1801867Sgjelinek struct mnttab entry; 1811867Sgjelinek 1827093Sgjelinek if ((fp = fopen(MNTTAB, "r")) == NULL) 1831867Sgjelinek return (B_FALSE); 1841867Sgjelinek 1851867Sgjelinek while (getmntent(fp, &entry) == 0) { 1861867Sgjelinek if (strcmp(path, entry.mnt_mountp) == 0) { 1871867Sgjelinek (void) fclose(fp); 1881867Sgjelinek return (B_TRUE); 1891867Sgjelinek } 1901867Sgjelinek } 1911867Sgjelinek 1921867Sgjelinek (void) fclose(fp); 1931867Sgjelinek return (B_FALSE); 1941867Sgjelinek } 1951867Sgjelinek 1961867Sgjelinek /* 1977089Sgjelinek * Run the brand's pre-snapshot hook before we take a ZFS snapshot of the zone. 1981867Sgjelinek */ 1991867Sgjelinek static int 2007089Sgjelinek pre_snapshot(char *presnapbuf) 2011867Sgjelinek { 2027089Sgjelinek int status; 2031867Sgjelinek 2047089Sgjelinek /* No brand-specific handler */ 2057089Sgjelinek if (presnapbuf[0] == '\0') 2067089Sgjelinek return (Z_OK); 2071867Sgjelinek 2087089Sgjelinek /* Run the hook */ 2097089Sgjelinek status = do_subproc_interactive(presnapbuf); 2107089Sgjelinek if ((status = subproc_status(gettext("brand-specific presnapshot"), 2117089Sgjelinek status, B_FALSE)) != ZONE_SUBPROC_OK) 2121867Sgjelinek return (Z_ERR); 2131867Sgjelinek 2141867Sgjelinek return (Z_OK); 2151867Sgjelinek } 2161867Sgjelinek 2171867Sgjelinek /* 2187089Sgjelinek * Run the brand's post-snapshot hook after we take a ZFS snapshot of the zone. 2191867Sgjelinek */ 2201867Sgjelinek static int 2217089Sgjelinek post_snapshot(char *postsnapbuf) 2221867Sgjelinek { 2237089Sgjelinek int status; 2241867Sgjelinek 2257089Sgjelinek /* No brand-specific handler */ 2267089Sgjelinek if (postsnapbuf[0] == '\0') 2277089Sgjelinek return (Z_OK); 2287089Sgjelinek 2297089Sgjelinek /* Run the hook */ 2307089Sgjelinek status = do_subproc_interactive(postsnapbuf); 2317089Sgjelinek if ((status = subproc_status(gettext("brand-specific postsnapshot"), 2327089Sgjelinek status, B_FALSE)) != ZONE_SUBPROC_OK) 2331867Sgjelinek return (Z_ERR); 2341867Sgjelinek 2351867Sgjelinek return (Z_OK); 2361867Sgjelinek } 2371867Sgjelinek 2381867Sgjelinek /* 2391867Sgjelinek * This is a ZFS snapshot iterator call-back function which returns the 2401867Sgjelinek * highest number of SUNWzone snapshots that have been taken. 2411867Sgjelinek */ 2421867Sgjelinek static int 2431867Sgjelinek get_snap_max(zfs_handle_t *zhp, void *data) 2441867Sgjelinek { 2451867Sgjelinek int res; 2461867Sgjelinek zfs_snapshot_data_t *cbp; 2471867Sgjelinek 2481867Sgjelinek if (zfs_get_type(zhp) != ZFS_TYPE_SNAPSHOT) { 2491867Sgjelinek zfs_close(zhp); 2501867Sgjelinek return (0); 2511867Sgjelinek } 2521867Sgjelinek 2531867Sgjelinek cbp = (zfs_snapshot_data_t *)data; 2541867Sgjelinek 2551867Sgjelinek if (strncmp(zfs_get_name(zhp), cbp->match_name, cbp->len) == 0) { 2561867Sgjelinek char *nump; 2571867Sgjelinek int num; 2581867Sgjelinek 2591867Sgjelinek nump = (char *)(zfs_get_name(zhp) + cbp->len); 2601867Sgjelinek num = atoi(nump); 2611867Sgjelinek if (num > cbp->max) 2621867Sgjelinek cbp->max = num; 2631867Sgjelinek } 2641867Sgjelinek 2651867Sgjelinek res = zfs_iter_snapshots(zhp, get_snap_max, data); 2661867Sgjelinek zfs_close(zhp); 2671867Sgjelinek return (res); 2681867Sgjelinek } 2691867Sgjelinek 2701867Sgjelinek /* 2711867Sgjelinek * Take a ZFS snapshot to be used for cloning the zone. 2721867Sgjelinek */ 2731867Sgjelinek static int 2747089Sgjelinek take_snapshot(zfs_handle_t *zhp, char *snapshot_name, int snap_size, 2757089Sgjelinek char *presnapbuf, char *postsnapbuf) 2761867Sgjelinek { 2771867Sgjelinek int res; 2781867Sgjelinek char template[ZFS_MAXNAMELEN]; 2791867Sgjelinek zfs_snapshot_data_t cb; 2801867Sgjelinek 2811867Sgjelinek /* 2821867Sgjelinek * First we need to figure out the next available name for the 2831867Sgjelinek * zone snapshot. Look through the list of zones snapshots for 2841867Sgjelinek * this file system to determine the maximum snapshot name. 2851867Sgjelinek */ 2861867Sgjelinek if (snprintf(template, sizeof (template), "%s@SUNWzone", 2871867Sgjelinek zfs_get_name(zhp)) >= sizeof (template)) 2881867Sgjelinek return (Z_ERR); 2891867Sgjelinek 2901867Sgjelinek cb.match_name = template; 2911867Sgjelinek cb.len = strlen(template); 2921867Sgjelinek cb.max = 0; 2931867Sgjelinek 2941867Sgjelinek if (zfs_iter_snapshots(zhp, get_snap_max, &cb) != 0) 2951867Sgjelinek return (Z_ERR); 2961867Sgjelinek 2971867Sgjelinek cb.max++; 2981867Sgjelinek 2991867Sgjelinek if (snprintf(snapshot_name, snap_size, "%s@SUNWzone%d", 3001867Sgjelinek zfs_get_name(zhp), cb.max) >= snap_size) 3011867Sgjelinek return (Z_ERR); 3021867Sgjelinek 3037089Sgjelinek if (pre_snapshot(presnapbuf) != Z_OK) 3041867Sgjelinek return (Z_ERR); 3057265Sahrens res = zfs_snapshot(g_zfs, snapshot_name, B_FALSE, NULL); 3067089Sgjelinek if (post_snapshot(postsnapbuf) != Z_OK) 3071867Sgjelinek return (Z_ERR); 3081867Sgjelinek 3091867Sgjelinek if (res != 0) 3101867Sgjelinek return (Z_ERR); 3111867Sgjelinek return (Z_OK); 3121867Sgjelinek } 3131867Sgjelinek 3141867Sgjelinek /* 3151867Sgjelinek * We are using an explicit snapshot from some earlier point in time so 3167089Sgjelinek * we need to validate it. Run the brand specific hook. 3171867Sgjelinek */ 3181867Sgjelinek static int 3197089Sgjelinek validate_snapshot(char *snapshot_name, char *snap_path, char *validsnapbuf) 3201867Sgjelinek { 3217089Sgjelinek int status; 3227089Sgjelinek char cmdbuf[MAXPATHLEN]; 3231867Sgjelinek 3247089Sgjelinek /* No brand-specific handler */ 3257089Sgjelinek if (validsnapbuf[0] == '\0') 3267089Sgjelinek return (Z_OK); 3271867Sgjelinek 3287089Sgjelinek /* pass args - snapshot_name & snap_path */ 3297089Sgjelinek if (snprintf(cmdbuf, sizeof (cmdbuf), "%s %s %s", validsnapbuf, 3307089Sgjelinek snapshot_name, snap_path) >= sizeof (cmdbuf)) { 3317089Sgjelinek zerror("Command line too long"); 3321867Sgjelinek return (Z_ERR); 3331867Sgjelinek } 3341867Sgjelinek 3357089Sgjelinek /* Run the hook */ 3367089Sgjelinek status = do_subproc_interactive(cmdbuf); 3377089Sgjelinek if ((status = subproc_status(gettext("brand-specific validatesnapshot"), 3387089Sgjelinek status, B_FALSE)) != ZONE_SUBPROC_OK) 3397089Sgjelinek return (Z_ERR); 3401867Sgjelinek 3417089Sgjelinek return (Z_OK); 3421867Sgjelinek } 3431867Sgjelinek 3441867Sgjelinek /* 3451867Sgjelinek * Remove the sw inventory file from inside this zonepath that we picked up out 3461867Sgjelinek * of the snapshot. 3471867Sgjelinek */ 3481867Sgjelinek static int 3491867Sgjelinek clean_out_clone() 3501867Sgjelinek { 3511867Sgjelinek int err; 3521867Sgjelinek zone_dochandle_t handle; 3531867Sgjelinek 3541867Sgjelinek if ((handle = zonecfg_init_handle()) == NULL) { 3551867Sgjelinek zperror(cmd_to_str(CMD_CLONE), B_TRUE); 3561867Sgjelinek return (Z_ERR); 3571867Sgjelinek } 3581867Sgjelinek 3591867Sgjelinek if ((err = zonecfg_get_handle(target_zone, handle)) != Z_OK) { 3601867Sgjelinek errno = err; 3611867Sgjelinek zperror(cmd_to_str(CMD_CLONE), B_TRUE); 3621867Sgjelinek zonecfg_fini_handle(handle); 3631867Sgjelinek return (Z_ERR); 3641867Sgjelinek } 3651867Sgjelinek 3661867Sgjelinek zonecfg_rm_detached(handle, B_FALSE); 3671867Sgjelinek zonecfg_fini_handle(handle); 3681867Sgjelinek 3691867Sgjelinek return (Z_OK); 3701867Sgjelinek } 3711867Sgjelinek 3721867Sgjelinek /* 3731867Sgjelinek * Make a ZFS clone on zonepath from snapshot_name. 3741867Sgjelinek */ 3751867Sgjelinek static int 3761867Sgjelinek clone_snap(char *snapshot_name, char *zonepath) 3771867Sgjelinek { 3781867Sgjelinek int res = Z_OK; 3791867Sgjelinek int err; 3801867Sgjelinek zfs_handle_t *zhp; 3811867Sgjelinek zfs_handle_t *clone; 3822676Seschrock nvlist_t *props = NULL; 3831867Sgjelinek 3842082Seschrock if ((zhp = zfs_open(g_zfs, snapshot_name, ZFS_TYPE_SNAPSHOT)) == NULL) 3851867Sgjelinek return (Z_NO_ENTRY); 3861867Sgjelinek 3871867Sgjelinek (void) printf(gettext("Cloning snapshot %s\n"), snapshot_name); 3881867Sgjelinek 3892676Seschrock if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0 || 3902744Snn35248 nvlist_add_string(props, zfs_prop_to_name(ZFS_PROP_SHARENFS), 3912744Snn35248 "off") != 0) { 3922744Snn35248 if (props != NULL) 3932744Snn35248 nvlist_free(props); 3942676Seschrock (void) fprintf(stderr, gettext("could not create ZFS clone " 3952676Seschrock "%s: out of memory\n"), zonepath); 3962676Seschrock return (Z_ERR); 3972676Seschrock } 3982676Seschrock 3992676Seschrock err = zfs_clone(zhp, zonepath, props); 4001867Sgjelinek zfs_close(zhp); 4012676Seschrock 4022676Seschrock nvlist_free(props); 4032676Seschrock 4041867Sgjelinek if (err != 0) 4051867Sgjelinek return (Z_ERR); 4061867Sgjelinek 4071867Sgjelinek /* create the mountpoint if necessary */ 4085094Slling if ((clone = zfs_open(g_zfs, zonepath, ZFS_TYPE_DATASET)) == NULL) 4091867Sgjelinek return (Z_ERR); 4101867Sgjelinek 4111867Sgjelinek /* 4121867Sgjelinek * The clone has been created so we need to print a diagnostic 4131867Sgjelinek * message if one of the following steps fails for some reason. 4141867Sgjelinek */ 4151867Sgjelinek if (zfs_mount(clone, NULL, 0) != 0) { 4161867Sgjelinek (void) fprintf(stderr, gettext("could not mount ZFS clone " 4171867Sgjelinek "%s\n"), zfs_get_name(clone)); 4181867Sgjelinek res = Z_ERR; 4191867Sgjelinek 4202676Seschrock } else if (clean_out_clone() != Z_OK) { 4212676Seschrock (void) fprintf(stderr, gettext("could not remove the " 4222676Seschrock "software inventory from ZFS clone %s\n"), 4232676Seschrock zfs_get_name(clone)); 4242676Seschrock res = Z_ERR; 4251867Sgjelinek } 4261867Sgjelinek 4271867Sgjelinek zfs_close(clone); 4281867Sgjelinek return (res); 4291867Sgjelinek } 4301867Sgjelinek 4311867Sgjelinek /* 4321867Sgjelinek * This function takes a zonepath and attempts to determine what the ZFS 4331867Sgjelinek * file system name (not mountpoint) should be for that path. We do not 4341867Sgjelinek * assume that zonepath is an existing directory or ZFS fs since we use 4351867Sgjelinek * this function as part of the process of creating a new ZFS fs or clone. 4361867Sgjelinek * 4371867Sgjelinek * The way this works is that we look at the parent directory of the zonepath 4381867Sgjelinek * to see if it is a ZFS fs. If it is, we get the name of that ZFS fs and 4391867Sgjelinek * append the last component of the zonepath to generate the ZFS name for the 4401867Sgjelinek * zonepath. This matches the algorithm that ZFS uses for automatically 4411867Sgjelinek * mounting a new fs after it is created. 4421867Sgjelinek * 4431867Sgjelinek * Although a ZFS fs can be mounted anywhere, we don't worry about handling 4441867Sgjelinek * all of the complexity that a user could possibly configure with arbitrary 4451867Sgjelinek * mounts since there is no way to generate a ZFS name from a random path in 4461867Sgjelinek * the file system. We only try to handle the automatic mounts that ZFS does 4471867Sgjelinek * for each file system. ZFS restricts this so that a new fs must be created 4481867Sgjelinek * in an existing parent ZFS fs. It then automatically mounts the new fs 4491867Sgjelinek * directly under the mountpoint for the parent fs using the last component 4501867Sgjelinek * of the name as the mountpoint directory. 4511867Sgjelinek * 4521867Sgjelinek * For example: 4531867Sgjelinek * Name Mountpoint 4541867Sgjelinek * space/eng/dev/test/zone1 /project1/eng/dev/test/zone1 4551867Sgjelinek * 4561867Sgjelinek * Return Z_OK if the path mapped to a ZFS file system name, otherwise return 4571867Sgjelinek * Z_ERR. 4581867Sgjelinek */ 4591867Sgjelinek static int 4601867Sgjelinek path2name(char *zonepath, char *zfs_name, int len) 4611867Sgjelinek { 4621867Sgjelinek int res; 4637093Sgjelinek char *bnm, *dnm, *dname, *bname; 4641867Sgjelinek zfs_handle_t *zhp; 4657093Sgjelinek struct stat stbuf; 4661867Sgjelinek 4677093Sgjelinek /* 4687093Sgjelinek * We need two tmp strings to handle paths directly in / (e.g. /foo) 4697093Sgjelinek * since dirname will overwrite the first char after "/" in this case. 4707093Sgjelinek */ 4717093Sgjelinek if ((bnm = strdup(zonepath)) == NULL) 4721867Sgjelinek return (Z_ERR); 4731867Sgjelinek 4747093Sgjelinek if ((dnm = strdup(zonepath)) == NULL) { 4757093Sgjelinek free(bnm); 4767093Sgjelinek return (Z_ERR); 4777093Sgjelinek } 4787093Sgjelinek 4797093Sgjelinek bname = basename(bnm); 4807093Sgjelinek dname = dirname(dnm); 4817093Sgjelinek 4821867Sgjelinek /* 4837093Sgjelinek * This is a quick test to save iterating over all of the zfs datasets 4847093Sgjelinek * on the system (which can be a lot). If the parent dir is not in a 4857093Sgjelinek * ZFS fs, then we're done. 4861867Sgjelinek */ 4877093Sgjelinek if (stat(dname, &stbuf) != 0 || !S_ISDIR(stbuf.st_mode) || 4887093Sgjelinek strcmp(stbuf.st_fstype, MNTTYPE_ZFS) != 0) { 4897093Sgjelinek free(bnm); 4907093Sgjelinek free(dnm); 4911867Sgjelinek return (Z_ERR); 4927093Sgjelinek } 4931867Sgjelinek 4947093Sgjelinek /* See if the parent directory is its own ZFS dataset. */ 4957093Sgjelinek if ((zhp = mount2zhandle(dname)) == NULL) { 4967093Sgjelinek /* 4977093Sgjelinek * The parent is not a ZFS dataset so we can't automatically 4987093Sgjelinek * create a dataset on the given path. 4997093Sgjelinek */ 5007093Sgjelinek free(bnm); 5017093Sgjelinek free(dnm); 5027093Sgjelinek return (Z_ERR); 5037093Sgjelinek } 5041867Sgjelinek 5057093Sgjelinek res = snprintf(zfs_name, len, "%s/%s", zfs_get_name(zhp), bname); 5067093Sgjelinek 5077093Sgjelinek free(bnm); 5087093Sgjelinek free(dnm); 5091867Sgjelinek zfs_close(zhp); 5101867Sgjelinek if (res >= len) 5111867Sgjelinek return (Z_ERR); 5121867Sgjelinek 5131867Sgjelinek return (Z_OK); 5141867Sgjelinek } 5151867Sgjelinek 5161867Sgjelinek /* 5171867Sgjelinek * A ZFS file system iterator call-back function used to determine if the 5181867Sgjelinek * file system has dependents (snapshots & clones). 5191867Sgjelinek */ 5201867Sgjelinek /* ARGSUSED */ 5211867Sgjelinek static int 5221867Sgjelinek has_dependent(zfs_handle_t *zhp, void *data) 5231867Sgjelinek { 5241867Sgjelinek zfs_close(zhp); 5251867Sgjelinek return (1); 5261867Sgjelinek } 5271867Sgjelinek 5281867Sgjelinek /* 5291867Sgjelinek * Given a snapshot name, get the file system path where the snapshot lives. 5301867Sgjelinek * A snapshot name is of the form fs_name@snap_name. For example, snapshot 5311867Sgjelinek * pl/zones/z1@SUNWzone1 would have a path of 5321867Sgjelinek * /pl/zones/z1/.zfs/snapshot/SUNWzone1. 5331867Sgjelinek */ 5341867Sgjelinek static int 5351867Sgjelinek snap2path(char *snap_name, char *path, int len) 5361867Sgjelinek { 5371867Sgjelinek char *p; 5381867Sgjelinek zfs_handle_t *zhp; 5391867Sgjelinek char mp[ZFS_MAXPROPLEN]; 5401867Sgjelinek 5411867Sgjelinek if ((p = strrchr(snap_name, '@')) == NULL) 5421867Sgjelinek return (Z_ERR); 5431867Sgjelinek 5441867Sgjelinek /* Get the file system name from the snap_name. */ 5451867Sgjelinek *p = '\0'; 5465094Slling zhp = zfs_open(g_zfs, snap_name, ZFS_TYPE_DATASET); 5471867Sgjelinek *p = '@'; 5481867Sgjelinek if (zhp == NULL) 5491867Sgjelinek return (Z_ERR); 5501867Sgjelinek 5511867Sgjelinek /* Get the file system mount point. */ 5521867Sgjelinek if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mp, sizeof (mp), NULL, NULL, 5532082Seschrock 0, B_FALSE) != 0) { 5541867Sgjelinek zfs_close(zhp); 5551867Sgjelinek return (Z_ERR); 5561867Sgjelinek } 5571867Sgjelinek zfs_close(zhp); 5581867Sgjelinek 5591867Sgjelinek p++; 5601867Sgjelinek if (snprintf(path, len, "%s/.zfs/snapshot/%s", mp, p) >= len) 5611867Sgjelinek return (Z_ERR); 5621867Sgjelinek 5631867Sgjelinek return (Z_OK); 5641867Sgjelinek } 5651867Sgjelinek 5661867Sgjelinek /* 5671867Sgjelinek * Clone a pre-existing ZFS snapshot, either by making a direct ZFS clone, if 5681867Sgjelinek * possible, or by copying the data from the snapshot to the zonepath. 5691867Sgjelinek */ 5701867Sgjelinek int 5717089Sgjelinek clone_snapshot_zfs(char *snap_name, char *zonepath, char *validatesnap) 5721867Sgjelinek { 5731867Sgjelinek int err = Z_OK; 5741867Sgjelinek char clone_name[MAXPATHLEN]; 5751867Sgjelinek char snap_path[MAXPATHLEN]; 5761867Sgjelinek 5771867Sgjelinek if (snap2path(snap_name, snap_path, sizeof (snap_path)) != Z_OK) { 5781867Sgjelinek (void) fprintf(stderr, gettext("unable to find path for %s.\n"), 5791867Sgjelinek snap_name); 5801867Sgjelinek return (Z_ERR); 5811867Sgjelinek } 5821867Sgjelinek 5837089Sgjelinek if (validate_snapshot(snap_name, snap_path, validatesnap) != Z_OK) 5841867Sgjelinek return (Z_NO_ENTRY); 5851867Sgjelinek 5861867Sgjelinek /* 5871867Sgjelinek * The zonepath cannot be ZFS cloned, try to copy the data from 5881867Sgjelinek * within the snapshot to the zonepath. 5891867Sgjelinek */ 5901867Sgjelinek if (path2name(zonepath, clone_name, sizeof (clone_name)) != Z_OK) { 5911867Sgjelinek if ((err = clone_copy(snap_path, zonepath)) == Z_OK) 5921867Sgjelinek if (clean_out_clone() != Z_OK) 5931867Sgjelinek (void) fprintf(stderr, 5941867Sgjelinek gettext("could not remove the " 5951867Sgjelinek "software inventory from %s\n"), zonepath); 5961867Sgjelinek 5971867Sgjelinek return (err); 5981867Sgjelinek } 5991867Sgjelinek 6001867Sgjelinek if ((err = clone_snap(snap_name, clone_name)) != Z_OK) { 6011867Sgjelinek if (err != Z_NO_ENTRY) { 6021867Sgjelinek /* 6031867Sgjelinek * Cloning the snapshot failed. Fall back to trying 6041867Sgjelinek * to install the zone by copying from the snapshot. 6051867Sgjelinek */ 6061867Sgjelinek if ((err = clone_copy(snap_path, zonepath)) == Z_OK) 6071867Sgjelinek if (clean_out_clone() != Z_OK) 6081867Sgjelinek (void) fprintf(stderr, 6091867Sgjelinek gettext("could not remove the " 6101867Sgjelinek "software inventory from %s\n"), 6111867Sgjelinek zonepath); 6121867Sgjelinek } else { 6131867Sgjelinek /* 6141867Sgjelinek * The snapshot is unusable for some reason so restore 6151867Sgjelinek * the zone state to configured since we were unable to 6161867Sgjelinek * actually do anything about getting the zone 6171867Sgjelinek * installed. 6181867Sgjelinek */ 6191867Sgjelinek int tmp; 6201867Sgjelinek 6211867Sgjelinek if ((tmp = zone_set_state(target_zone, 6221867Sgjelinek ZONE_STATE_CONFIGURED)) != Z_OK) { 6231867Sgjelinek errno = tmp; 6241867Sgjelinek zperror2(target_zone, 6251867Sgjelinek gettext("could not set state")); 6261867Sgjelinek } 6271867Sgjelinek } 6281867Sgjelinek } 6291867Sgjelinek 6301867Sgjelinek return (err); 6311867Sgjelinek } 6321867Sgjelinek 6331867Sgjelinek /* 6341867Sgjelinek * Attempt to clone a source_zone to a target zonepath by using a ZFS clone. 6351867Sgjelinek */ 6361867Sgjelinek int 6377089Sgjelinek clone_zfs(char *source_zonepath, char *zonepath, char *presnapbuf, 6387089Sgjelinek char *postsnapbuf) 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 6817089Sgjelinek if (take_snapshot(zhp, snap_name, sizeof (snap_name), presnapbuf, 6827089Sgjelinek postsnapbuf) != Z_OK) { 6831867Sgjelinek zfs_close(zhp); 6841867Sgjelinek return (Z_ERR); 6851867Sgjelinek } 6861867Sgjelinek zfs_close(zhp); 6871867Sgjelinek 6883686Sgjelinek if (clone_snap(snap_name, clone_name) != Z_OK) { 6893686Sgjelinek /* Clean up the snapshot we just took. */ 6903686Sgjelinek if ((zhp = zfs_open(g_zfs, snap_name, ZFS_TYPE_SNAPSHOT)) 6913686Sgjelinek != NULL) { 6923686Sgjelinek if (zfs_unmount(zhp, NULL, 0) == 0) 6933686Sgjelinek (void) zfs_destroy(zhp); 6943686Sgjelinek zfs_close(zhp); 6953686Sgjelinek } 6963686Sgjelinek 6971867Sgjelinek return (Z_ERR); 6983686Sgjelinek } 6991867Sgjelinek 7001867Sgjelinek (void) printf(gettext("Instead of copying, a ZFS clone has been " 7011867Sgjelinek "created for this zone.\n")); 7021867Sgjelinek 7031867Sgjelinek return (Z_OK); 7041867Sgjelinek } 7051867Sgjelinek 7061867Sgjelinek /* 7071867Sgjelinek * Attempt to create a ZFS file system for the specified zonepath. 7081867Sgjelinek * We either will successfully create a ZFS file system and get it mounted 7091867Sgjelinek * on the zonepath or we don't. The caller doesn't care since a regular 7101867Sgjelinek * directory is used for the zonepath if no ZFS file system is mounted there. 7111867Sgjelinek */ 7121867Sgjelinek void 7131867Sgjelinek create_zfs_zonepath(char *zonepath) 7141867Sgjelinek { 7151867Sgjelinek zfs_handle_t *zhp; 7161867Sgjelinek char zfs_name[MAXPATHLEN]; 7172676Seschrock nvlist_t *props = NULL; 7181867Sgjelinek 7191867Sgjelinek if (path2name(zonepath, zfs_name, sizeof (zfs_name)) != Z_OK) 7201867Sgjelinek return; 7211867Sgjelinek 722*9023Sgerald.jelinek@sun.com /* Check if the dataset already exists. */ 723*9023Sgerald.jelinek@sun.com if ((zhp = zfs_open(g_zfs, zfs_name, ZFS_TYPE_DATASET)) != NULL) { 724*9023Sgerald.jelinek@sun.com zfs_close(zhp); 725*9023Sgerald.jelinek@sun.com return; 726*9023Sgerald.jelinek@sun.com } 727*9023Sgerald.jelinek@sun.com 7282676Seschrock if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0 || 7292744Snn35248 nvlist_add_string(props, zfs_prop_to_name(ZFS_PROP_SHARENFS), 7302744Snn35248 "off") != 0) { 7312744Snn35248 if (props != NULL) 7322744Snn35248 nvlist_free(props); 7332676Seschrock (void) fprintf(stderr, gettext("cannot create ZFS dataset %s: " 7342676Seschrock "out of memory\n"), zfs_name); 7352676Seschrock } 7362676Seschrock 7372676Seschrock if (zfs_create(g_zfs, zfs_name, ZFS_TYPE_FILESYSTEM, props) != 0 || 7385094Slling (zhp = zfs_open(g_zfs, zfs_name, ZFS_TYPE_DATASET)) == NULL) { 7392082Seschrock (void) fprintf(stderr, gettext("cannot create ZFS dataset %s: " 7402082Seschrock "%s\n"), zfs_name, libzfs_error_description(g_zfs)); 7412676Seschrock nvlist_free(props); 7421867Sgjelinek return; 7431867Sgjelinek } 7441867Sgjelinek 7452676Seschrock nvlist_free(props); 7462676Seschrock 7471867Sgjelinek if (zfs_mount(zhp, NULL, 0) != 0) { 7482082Seschrock (void) fprintf(stderr, gettext("cannot mount ZFS dataset %s: " 7492082Seschrock "%s\n"), zfs_name, libzfs_error_description(g_zfs)); 7501867Sgjelinek (void) zfs_destroy(zhp); 7511867Sgjelinek } else { 7521867Sgjelinek if (chmod(zonepath, S_IRWXU) != 0) { 7531867Sgjelinek (void) fprintf(stderr, gettext("file system %s " 7541867Sgjelinek "successfully created, but chmod %o failed: %s\n"), 7551867Sgjelinek zfs_name, S_IRWXU, strerror(errno)); 7561867Sgjelinek (void) destroy_zfs(zonepath); 7571867Sgjelinek } else { 7581867Sgjelinek (void) printf(gettext("A ZFS file system has been " 7591867Sgjelinek "created for this zone.\n")); 7601867Sgjelinek } 7611867Sgjelinek } 7621867Sgjelinek 7631867Sgjelinek zfs_close(zhp); 7641867Sgjelinek } 7651867Sgjelinek 7661867Sgjelinek /* 7671867Sgjelinek * If the zonepath is a ZFS file system, attempt to destroy it. We return Z_OK 7681867Sgjelinek * if we were able to zfs_destroy the zonepath, otherwise we return Z_ERR 7691867Sgjelinek * which means the caller should clean up the zonepath in the traditional 7701867Sgjelinek * way. 7711867Sgjelinek */ 7721867Sgjelinek int 7731867Sgjelinek destroy_zfs(char *zonepath) 7741867Sgjelinek { 7751867Sgjelinek zfs_handle_t *zhp; 7761867Sgjelinek boolean_t is_clone = B_FALSE; 7771867Sgjelinek char origin[ZFS_MAXPROPLEN]; 7781867Sgjelinek 7792082Seschrock if ((zhp = mount2zhandle(zonepath)) == NULL) 7801867Sgjelinek return (Z_ERR); 7811867Sgjelinek 7821867Sgjelinek /* 7831867Sgjelinek * We can't destroy the file system if it has dependents. 7841867Sgjelinek */ 7852474Seschrock if (zfs_iter_dependents(zhp, B_TRUE, has_dependent, NULL) != 0 || 7861867Sgjelinek zfs_unmount(zhp, NULL, 0) != 0) { 7871867Sgjelinek zfs_close(zhp); 7881867Sgjelinek return (Z_ERR); 7891867Sgjelinek } 7901867Sgjelinek 7911867Sgjelinek /* 7921867Sgjelinek * This might be a clone. Try to get the snapshot so we can attempt 7931867Sgjelinek * to destroy that as well. 7941867Sgjelinek */ 7951867Sgjelinek if (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, origin, sizeof (origin), NULL, 7962082Seschrock NULL, 0, B_FALSE) == 0) 7971867Sgjelinek is_clone = B_TRUE; 7981867Sgjelinek 7991867Sgjelinek if (zfs_destroy(zhp) != 0) { 8001867Sgjelinek /* 8011867Sgjelinek * If the destroy fails for some reason, try to remount 8021867Sgjelinek * the file system so that we can use "rm -rf" to clean up 8031867Sgjelinek * instead. 8041867Sgjelinek */ 8051867Sgjelinek (void) zfs_mount(zhp, NULL, 0); 8061867Sgjelinek zfs_close(zhp); 8071867Sgjelinek return (Z_ERR); 8081867Sgjelinek } 8091867Sgjelinek 8103686Sgjelinek /* 8113686Sgjelinek * If the zone has ever been moved then the mountpoint dir will not be 8123686Sgjelinek * cleaned up by the zfs_destroy(). To handle this case try to clean 8133686Sgjelinek * it up now but don't worry if it fails, that will be normal. 8143686Sgjelinek */ 8153686Sgjelinek (void) rmdir(zonepath); 8163686Sgjelinek 8171867Sgjelinek (void) printf(gettext("The ZFS file system for this zone has been " 8181867Sgjelinek "destroyed.\n")); 8191867Sgjelinek 8201867Sgjelinek if (is_clone) { 8211867Sgjelinek zfs_handle_t *ohp; 8221867Sgjelinek 8231867Sgjelinek /* 8241867Sgjelinek * Try to clean up the snapshot that the clone was taken from. 8251867Sgjelinek */ 8262082Seschrock if ((ohp = zfs_open(g_zfs, origin, 8272082Seschrock ZFS_TYPE_SNAPSHOT)) != NULL) { 8282474Seschrock if (zfs_iter_dependents(ohp, B_TRUE, has_dependent, 8292474Seschrock NULL) == 0 && zfs_unmount(ohp, NULL, 0) == 0) 8301867Sgjelinek (void) zfs_destroy(ohp); 8311867Sgjelinek zfs_close(ohp); 8321867Sgjelinek } 8331867Sgjelinek } 8341867Sgjelinek 8351867Sgjelinek zfs_close(zhp); 8361867Sgjelinek return (Z_OK); 8371867Sgjelinek } 8381867Sgjelinek 8391867Sgjelinek /* 8401867Sgjelinek * Return true if the path is its own zfs file system. We determine this 8411867Sgjelinek * by stat-ing the path to see if it is zfs and stat-ing the parent to see 8421867Sgjelinek * if it is a different fs. 8431867Sgjelinek */ 8441867Sgjelinek boolean_t 8451867Sgjelinek is_zonepath_zfs(char *zonepath) 8461867Sgjelinek { 8471867Sgjelinek int res; 8481867Sgjelinek char *path; 8491867Sgjelinek char *parent; 8502267Sdp struct statvfs64 buf1, buf2; 8511867Sgjelinek 8522267Sdp if (statvfs64(zonepath, &buf1) != 0) 8531867Sgjelinek return (B_FALSE); 8541867Sgjelinek 8551867Sgjelinek if (strcmp(buf1.f_basetype, "zfs") != 0) 8561867Sgjelinek return (B_FALSE); 8571867Sgjelinek 8581867Sgjelinek if ((path = strdup(zonepath)) == NULL) 8591867Sgjelinek return (B_FALSE); 8601867Sgjelinek 8611867Sgjelinek parent = dirname(path); 8622267Sdp res = statvfs64(parent, &buf2); 8631867Sgjelinek free(path); 8641867Sgjelinek 8651867Sgjelinek if (res != 0) 8661867Sgjelinek return (B_FALSE); 8671867Sgjelinek 8681867Sgjelinek if (buf1.f_fsid == buf2.f_fsid) 8691867Sgjelinek return (B_FALSE); 8701867Sgjelinek 8711867Sgjelinek return (B_TRUE); 8721867Sgjelinek } 8731867Sgjelinek 8741867Sgjelinek /* 8751867Sgjelinek * Implement the fast move of a ZFS file system by simply updating the 8761867Sgjelinek * mountpoint. Since it is file system already, we don't have the 8771867Sgjelinek * issue of cross-file system copying. 8781867Sgjelinek */ 8791867Sgjelinek int 8801867Sgjelinek move_zfs(char *zonepath, char *new_zonepath) 8811867Sgjelinek { 8821867Sgjelinek int ret = Z_ERR; 8831867Sgjelinek zfs_handle_t *zhp; 8841867Sgjelinek 8852082Seschrock if ((zhp = mount2zhandle(zonepath)) == NULL) 8861867Sgjelinek return (Z_ERR); 8871867Sgjelinek 8882676Seschrock if (zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_MOUNTPOINT), 8892676Seschrock new_zonepath) == 0) { 8901867Sgjelinek /* 8911867Sgjelinek * Clean up the old mount point. We ignore any failure since 8921867Sgjelinek * the zone is already successfully mounted on the new path. 8931867Sgjelinek */ 8941867Sgjelinek (void) rmdir(zonepath); 8951867Sgjelinek ret = Z_OK; 8961867Sgjelinek } 8971867Sgjelinek 8981867Sgjelinek zfs_close(zhp); 8991867Sgjelinek 9001867Sgjelinek return (ret); 9011867Sgjelinek } 9021867Sgjelinek 9031867Sgjelinek /* 9041867Sgjelinek * Validate that the given dataset exists on the system, and that neither it nor 9051867Sgjelinek * its children are zvols. 9061867Sgjelinek * 9071867Sgjelinek * Note that we don't do anything with the 'zoned' property here. All 9081867Sgjelinek * management is done in zoneadmd when the zone is actually rebooted. This 9091867Sgjelinek * allows us to automatically set the zoned property even when a zone is 9101867Sgjelinek * rebooted by the administrator. 9111867Sgjelinek */ 9121867Sgjelinek int 9131867Sgjelinek verify_datasets(zone_dochandle_t handle) 9141867Sgjelinek { 9151867Sgjelinek int return_code = Z_OK; 9161867Sgjelinek struct zone_dstab dstab; 9171867Sgjelinek zfs_handle_t *zhp; 9181867Sgjelinek char propbuf[ZFS_MAXPROPLEN]; 9191867Sgjelinek char source[ZFS_MAXNAMELEN]; 9205094Slling zprop_source_t srctype; 9211867Sgjelinek 9221867Sgjelinek if (zonecfg_setdsent(handle) != Z_OK) { 9231867Sgjelinek /* 9241867Sgjelinek * TRANSLATION_NOTE 9251867Sgjelinek * zfs and dataset are literals that should not be translated. 9261867Sgjelinek */ 9271867Sgjelinek (void) fprintf(stderr, gettext("could not verify zfs datasets: " 9281867Sgjelinek "unable to enumerate datasets\n")); 9291867Sgjelinek return (Z_ERR); 9301867Sgjelinek } 9311867Sgjelinek 9321867Sgjelinek while (zonecfg_getdsent(handle, &dstab) == Z_OK) { 9331867Sgjelinek 9342082Seschrock if ((zhp = zfs_open(g_zfs, dstab.zone_dataset_name, 9351867Sgjelinek ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME)) == NULL) { 9362082Seschrock (void) fprintf(stderr, gettext("could not verify zfs " 9372082Seschrock "dataset %s: %s\n"), dstab.zone_dataset_name, 9382082Seschrock libzfs_error_description(g_zfs)); 9391867Sgjelinek return_code = Z_ERR; 9401867Sgjelinek continue; 9411867Sgjelinek } 9421867Sgjelinek 9431867Sgjelinek if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, propbuf, 9441867Sgjelinek sizeof (propbuf), &srctype, source, 9451867Sgjelinek sizeof (source), 0) == 0 && 9465094Slling (srctype == ZPROP_SRC_INHERITED)) { 9471867Sgjelinek (void) fprintf(stderr, gettext("could not verify zfs " 9481867Sgjelinek "dataset %s: mountpoint cannot be inherited\n"), 9491867Sgjelinek dstab.zone_dataset_name); 9501867Sgjelinek return_code = Z_ERR; 9511867Sgjelinek zfs_close(zhp); 9521867Sgjelinek continue; 9531867Sgjelinek } 9541867Sgjelinek 9551867Sgjelinek if (zfs_get_type(zhp) == ZFS_TYPE_VOLUME) { 9561867Sgjelinek (void) fprintf(stderr, gettext("cannot verify zfs " 9571867Sgjelinek "dataset %s: volumes cannot be specified as a " 9581867Sgjelinek "zone dataset resource\n"), 9591867Sgjelinek dstab.zone_dataset_name); 9601867Sgjelinek return_code = Z_ERR; 9611867Sgjelinek } 9621867Sgjelinek 9631867Sgjelinek if (zfs_iter_children(zhp, check_zvol, NULL) != 0) 9641867Sgjelinek return_code = Z_ERR; 9651867Sgjelinek 9661867Sgjelinek zfs_close(zhp); 9671867Sgjelinek } 9681867Sgjelinek (void) zonecfg_enddsent(handle); 9691867Sgjelinek 9701867Sgjelinek return (return_code); 9711867Sgjelinek } 9721867Sgjelinek 9731867Sgjelinek /* 9741867Sgjelinek * Verify that the ZFS dataset exists, and its mountpoint 9751867Sgjelinek * property is set to "legacy". 9761867Sgjelinek */ 9771867Sgjelinek int 9781867Sgjelinek verify_fs_zfs(struct zone_fstab *fstab) 9791867Sgjelinek { 9801867Sgjelinek zfs_handle_t *zhp; 9811867Sgjelinek char propbuf[ZFS_MAXPROPLEN]; 9821867Sgjelinek 9832082Seschrock if ((zhp = zfs_open(g_zfs, fstab->zone_fs_special, 9845094Slling ZFS_TYPE_DATASET)) == NULL) { 9851867Sgjelinek (void) fprintf(stderr, gettext("could not verify fs %s: " 9861867Sgjelinek "could not access zfs dataset '%s'\n"), 9871867Sgjelinek fstab->zone_fs_dir, fstab->zone_fs_special); 9881867Sgjelinek return (Z_ERR); 9891867Sgjelinek } 9901867Sgjelinek 9911867Sgjelinek if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) { 9921867Sgjelinek (void) fprintf(stderr, gettext("cannot verify fs %s: " 9931867Sgjelinek "'%s' is not a file system\n"), 9941867Sgjelinek fstab->zone_fs_dir, fstab->zone_fs_special); 9951867Sgjelinek zfs_close(zhp); 9961867Sgjelinek return (Z_ERR); 9971867Sgjelinek } 9981867Sgjelinek 9991867Sgjelinek if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, propbuf, sizeof (propbuf), 10001867Sgjelinek NULL, NULL, 0, 0) != 0 || strcmp(propbuf, "legacy") != 0) { 10011867Sgjelinek (void) fprintf(stderr, gettext("could not verify fs %s: " 10021867Sgjelinek "zfs '%s' mountpoint is not \"legacy\"\n"), 10031867Sgjelinek fstab->zone_fs_dir, fstab->zone_fs_special); 10041867Sgjelinek zfs_close(zhp); 10051867Sgjelinek return (Z_ERR); 10061867Sgjelinek } 10071867Sgjelinek 10081867Sgjelinek zfs_close(zhp); 10091867Sgjelinek return (Z_OK); 10101867Sgjelinek } 10112082Seschrock 10122082Seschrock int 10132082Seschrock init_zfs(void) 10142082Seschrock { 10152082Seschrock if ((g_zfs = libzfs_init()) == NULL) { 10162082Seschrock (void) fprintf(stderr, gettext("failed to initialize ZFS " 10172082Seschrock "library\n")); 10182082Seschrock return (Z_ERR); 10192082Seschrock } 10202082Seschrock 10212082Seschrock return (Z_OK); 10222082Seschrock } 1023