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 /* 237089Sgjelinek * Copyright 2008 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> 47*7093Sgjelinek #include <sys/mntent.h> 481867Sgjelinek 491867Sgjelinek #include "zoneadm.h" 501867Sgjelinek 512082Seschrock libzfs_handle_t *g_zfs; 521867Sgjelinek 531867Sgjelinek typedef struct zfs_mount_data { 541867Sgjelinek char *match_name; 551867Sgjelinek zfs_handle_t *match_handle; 561867Sgjelinek } zfs_mount_data_t; 571867Sgjelinek 581867Sgjelinek typedef struct zfs_snapshot_data { 591867Sgjelinek char *match_name; 601867Sgjelinek int len; 611867Sgjelinek int max; 621867Sgjelinek } zfs_snapshot_data_t; 631867Sgjelinek 641867Sgjelinek /* 651867Sgjelinek * A ZFS file system iterator call-back function which is used to validate 661867Sgjelinek * datasets imported into the zone. 671867Sgjelinek */ 681867Sgjelinek /* ARGSUSED */ 691867Sgjelinek static int 701867Sgjelinek check_zvol(zfs_handle_t *zhp, void *unused) 711867Sgjelinek { 721867Sgjelinek int ret; 731867Sgjelinek 741867Sgjelinek if (zfs_get_type(zhp) == ZFS_TYPE_VOLUME) { 751867Sgjelinek /* 761867Sgjelinek * TRANSLATION_NOTE 771867Sgjelinek * zfs and dataset are literals that should not be translated. 781867Sgjelinek */ 791867Sgjelinek (void) fprintf(stderr, gettext("cannot verify zfs dataset %s: " 801867Sgjelinek "volumes cannot be specified as a zone dataset resource\n"), 811867Sgjelinek zfs_get_name(zhp)); 821867Sgjelinek ret = -1; 831867Sgjelinek } else { 841867Sgjelinek ret = zfs_iter_children(zhp, check_zvol, NULL); 851867Sgjelinek } 861867Sgjelinek 871867Sgjelinek zfs_close(zhp); 881867Sgjelinek 891867Sgjelinek return (ret); 901867Sgjelinek } 911867Sgjelinek 921867Sgjelinek /* 931867Sgjelinek * A ZFS file system iterator call-back function which returns the 941867Sgjelinek * zfs_handle_t for a ZFS file system on the specified mount point. 951867Sgjelinek */ 961867Sgjelinek static int 971867Sgjelinek match_mountpoint(zfs_handle_t *zhp, void *data) 981867Sgjelinek { 991867Sgjelinek int res; 1001867Sgjelinek zfs_mount_data_t *cbp; 1011867Sgjelinek char mp[ZFS_MAXPROPLEN]; 1021867Sgjelinek 1031867Sgjelinek if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) { 1041867Sgjelinek zfs_close(zhp); 1051867Sgjelinek return (0); 1061867Sgjelinek } 1071867Sgjelinek 108*7093Sgjelinek /* First check if the dataset is mounted. */ 109*7093Sgjelinek if (zfs_prop_get(zhp, ZFS_PROP_MOUNTED, mp, sizeof (mp), NULL, NULL, 110*7093Sgjelinek 0, B_FALSE) != 0 || strcmp(mp, "no") == 0) { 111*7093Sgjelinek zfs_close(zhp); 112*7093Sgjelinek return (0); 113*7093Sgjelinek } 114*7093Sgjelinek 115*7093Sgjelinek /* Now check mount point. */ 1161867Sgjelinek if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mp, sizeof (mp), NULL, NULL, 117*7093Sgjelinek 0, B_FALSE) != 0) { 118*7093Sgjelinek zfs_close(zhp); 119*7093Sgjelinek return (0); 120*7093Sgjelinek } 121*7093Sgjelinek 122*7093Sgjelinek cbp = (zfs_mount_data_t *)data; 123*7093Sgjelinek 124*7093Sgjelinek if (strcmp(mp, "legacy") == 0) { 125*7093Sgjelinek /* If legacy, must look in mnttab for mountpoint. */ 126*7093Sgjelinek FILE *fp; 127*7093Sgjelinek struct mnttab entry; 128*7093Sgjelinek const char *nm; 129*7093Sgjelinek 130*7093Sgjelinek nm = zfs_get_name(zhp); 131*7093Sgjelinek if ((fp = fopen(MNTTAB, "r")) == NULL) { 132*7093Sgjelinek zfs_close(zhp); 133*7093Sgjelinek return (0); 134*7093Sgjelinek } 135*7093Sgjelinek 136*7093Sgjelinek while (getmntent(fp, &entry) == 0) { 137*7093Sgjelinek if (strcmp(nm, entry.mnt_special) == 0) { 138*7093Sgjelinek if (strcmp(entry.mnt_mountp, cbp->match_name) 139*7093Sgjelinek == 0) { 140*7093Sgjelinek (void) fclose(fp); 141*7093Sgjelinek cbp->match_handle = zhp; 142*7093Sgjelinek return (1); 143*7093Sgjelinek } 144*7093Sgjelinek break; 145*7093Sgjelinek } 146*7093Sgjelinek } 147*7093Sgjelinek (void) fclose(fp); 148*7093Sgjelinek 149*7093Sgjelinek } else if (strcmp(mp, cbp->match_name) == 0) { 1501867Sgjelinek cbp->match_handle = zhp; 1511867Sgjelinek return (1); 1521867Sgjelinek } 1531867Sgjelinek 154*7093Sgjelinek /* Iterate over any nested datasets. */ 1551867Sgjelinek res = zfs_iter_filesystems(zhp, match_mountpoint, data); 1561867Sgjelinek zfs_close(zhp); 1571867Sgjelinek return (res); 1581867Sgjelinek } 1591867Sgjelinek 1601867Sgjelinek /* 1611867Sgjelinek * Get ZFS handle for the specified mount point. 1621867Sgjelinek */ 1631867Sgjelinek static zfs_handle_t * 1641867Sgjelinek mount2zhandle(char *mountpoint) 1651867Sgjelinek { 1661867Sgjelinek zfs_mount_data_t cb; 1671867Sgjelinek 1681867Sgjelinek cb.match_name = mountpoint; 1691867Sgjelinek cb.match_handle = NULL; 1702082Seschrock (void) zfs_iter_root(g_zfs, match_mountpoint, &cb); 1711867Sgjelinek return (cb.match_handle); 1721867Sgjelinek } 1731867Sgjelinek 1741867Sgjelinek /* 1751867Sgjelinek * Check if there is already a file system (zfs or any other type) mounted on 1761867Sgjelinek * path. 1771867Sgjelinek */ 1781867Sgjelinek static boolean_t 1791867Sgjelinek is_mountpnt(char *path) 1801867Sgjelinek { 1811867Sgjelinek FILE *fp; 1821867Sgjelinek struct mnttab entry; 1831867Sgjelinek 184*7093Sgjelinek if ((fp = fopen(MNTTAB, "r")) == NULL) 1851867Sgjelinek return (B_FALSE); 1861867Sgjelinek 1871867Sgjelinek while (getmntent(fp, &entry) == 0) { 1881867Sgjelinek if (strcmp(path, entry.mnt_mountp) == 0) { 1891867Sgjelinek (void) fclose(fp); 1901867Sgjelinek return (B_TRUE); 1911867Sgjelinek } 1921867Sgjelinek } 1931867Sgjelinek 1941867Sgjelinek (void) fclose(fp); 1951867Sgjelinek return (B_FALSE); 1961867Sgjelinek } 1971867Sgjelinek 1981867Sgjelinek /* 1997089Sgjelinek * Run the brand's pre-snapshot hook before we take a ZFS snapshot of the zone. 2001867Sgjelinek */ 2011867Sgjelinek static int 2027089Sgjelinek pre_snapshot(char *presnapbuf) 2031867Sgjelinek { 2047089Sgjelinek int status; 2051867Sgjelinek 2067089Sgjelinek /* No brand-specific handler */ 2077089Sgjelinek if (presnapbuf[0] == '\0') 2087089Sgjelinek return (Z_OK); 2091867Sgjelinek 2107089Sgjelinek /* Run the hook */ 2117089Sgjelinek status = do_subproc_interactive(presnapbuf); 2127089Sgjelinek if ((status = subproc_status(gettext("brand-specific presnapshot"), 2137089Sgjelinek status, B_FALSE)) != ZONE_SUBPROC_OK) 2141867Sgjelinek return (Z_ERR); 2151867Sgjelinek 2161867Sgjelinek return (Z_OK); 2171867Sgjelinek } 2181867Sgjelinek 2191867Sgjelinek /* 2207089Sgjelinek * Run the brand's post-snapshot hook after we take a ZFS snapshot of the zone. 2211867Sgjelinek */ 2221867Sgjelinek static int 2237089Sgjelinek post_snapshot(char *postsnapbuf) 2241867Sgjelinek { 2257089Sgjelinek int status; 2261867Sgjelinek 2277089Sgjelinek /* No brand-specific handler */ 2287089Sgjelinek if (postsnapbuf[0] == '\0') 2297089Sgjelinek return (Z_OK); 2307089Sgjelinek 2317089Sgjelinek /* Run the hook */ 2327089Sgjelinek status = do_subproc_interactive(postsnapbuf); 2337089Sgjelinek if ((status = subproc_status(gettext("brand-specific postsnapshot"), 2347089Sgjelinek status, B_FALSE)) != ZONE_SUBPROC_OK) 2351867Sgjelinek return (Z_ERR); 2361867Sgjelinek 2371867Sgjelinek return (Z_OK); 2381867Sgjelinek } 2391867Sgjelinek 2401867Sgjelinek /* 2411867Sgjelinek * This is a ZFS snapshot iterator call-back function which returns the 2421867Sgjelinek * highest number of SUNWzone snapshots that have been taken. 2431867Sgjelinek */ 2441867Sgjelinek static int 2451867Sgjelinek get_snap_max(zfs_handle_t *zhp, void *data) 2461867Sgjelinek { 2471867Sgjelinek int res; 2481867Sgjelinek zfs_snapshot_data_t *cbp; 2491867Sgjelinek 2501867Sgjelinek if (zfs_get_type(zhp) != ZFS_TYPE_SNAPSHOT) { 2511867Sgjelinek zfs_close(zhp); 2521867Sgjelinek return (0); 2531867Sgjelinek } 2541867Sgjelinek 2551867Sgjelinek cbp = (zfs_snapshot_data_t *)data; 2561867Sgjelinek 2571867Sgjelinek if (strncmp(zfs_get_name(zhp), cbp->match_name, cbp->len) == 0) { 2581867Sgjelinek char *nump; 2591867Sgjelinek int num; 2601867Sgjelinek 2611867Sgjelinek nump = (char *)(zfs_get_name(zhp) + cbp->len); 2621867Sgjelinek num = atoi(nump); 2631867Sgjelinek if (num > cbp->max) 2641867Sgjelinek cbp->max = num; 2651867Sgjelinek } 2661867Sgjelinek 2671867Sgjelinek res = zfs_iter_snapshots(zhp, get_snap_max, data); 2681867Sgjelinek zfs_close(zhp); 2691867Sgjelinek return (res); 2701867Sgjelinek } 2711867Sgjelinek 2721867Sgjelinek /* 2731867Sgjelinek * Take a ZFS snapshot to be used for cloning the zone. 2741867Sgjelinek */ 2751867Sgjelinek static int 2767089Sgjelinek take_snapshot(zfs_handle_t *zhp, char *snapshot_name, int snap_size, 2777089Sgjelinek char *presnapbuf, char *postsnapbuf) 2781867Sgjelinek { 2791867Sgjelinek int res; 2801867Sgjelinek char template[ZFS_MAXNAMELEN]; 2811867Sgjelinek zfs_snapshot_data_t cb; 2821867Sgjelinek 2831867Sgjelinek /* 2841867Sgjelinek * First we need to figure out the next available name for the 2851867Sgjelinek * zone snapshot. Look through the list of zones snapshots for 2861867Sgjelinek * this file system to determine the maximum snapshot name. 2871867Sgjelinek */ 2881867Sgjelinek if (snprintf(template, sizeof (template), "%s@SUNWzone", 2891867Sgjelinek zfs_get_name(zhp)) >= sizeof (template)) 2901867Sgjelinek return (Z_ERR); 2911867Sgjelinek 2921867Sgjelinek cb.match_name = template; 2931867Sgjelinek cb.len = strlen(template); 2941867Sgjelinek cb.max = 0; 2951867Sgjelinek 2961867Sgjelinek if (zfs_iter_snapshots(zhp, get_snap_max, &cb) != 0) 2971867Sgjelinek return (Z_ERR); 2981867Sgjelinek 2991867Sgjelinek cb.max++; 3001867Sgjelinek 3011867Sgjelinek if (snprintf(snapshot_name, snap_size, "%s@SUNWzone%d", 3021867Sgjelinek zfs_get_name(zhp), cb.max) >= snap_size) 3031867Sgjelinek return (Z_ERR); 3041867Sgjelinek 3057089Sgjelinek if (pre_snapshot(presnapbuf) != Z_OK) 3061867Sgjelinek return (Z_ERR); 3072199Sahrens res = zfs_snapshot(g_zfs, snapshot_name, B_FALSE); 3087089Sgjelinek if (post_snapshot(postsnapbuf) != Z_OK) 3091867Sgjelinek return (Z_ERR); 3101867Sgjelinek 3111867Sgjelinek if (res != 0) 3121867Sgjelinek return (Z_ERR); 3131867Sgjelinek return (Z_OK); 3141867Sgjelinek } 3151867Sgjelinek 3161867Sgjelinek /* 3171867Sgjelinek * We are using an explicit snapshot from some earlier point in time so 3187089Sgjelinek * we need to validate it. Run the brand specific hook. 3191867Sgjelinek */ 3201867Sgjelinek static int 3217089Sgjelinek validate_snapshot(char *snapshot_name, char *snap_path, char *validsnapbuf) 3221867Sgjelinek { 3237089Sgjelinek int status; 3247089Sgjelinek char cmdbuf[MAXPATHLEN]; 3251867Sgjelinek 3267089Sgjelinek /* No brand-specific handler */ 3277089Sgjelinek if (validsnapbuf[0] == '\0') 3287089Sgjelinek return (Z_OK); 3291867Sgjelinek 3307089Sgjelinek /* pass args - snapshot_name & snap_path */ 3317089Sgjelinek if (snprintf(cmdbuf, sizeof (cmdbuf), "%s %s %s", validsnapbuf, 3327089Sgjelinek snapshot_name, snap_path) >= sizeof (cmdbuf)) { 3337089Sgjelinek zerror("Command line too long"); 3341867Sgjelinek return (Z_ERR); 3351867Sgjelinek } 3361867Sgjelinek 3377089Sgjelinek /* Run the hook */ 3387089Sgjelinek status = do_subproc_interactive(cmdbuf); 3397089Sgjelinek if ((status = subproc_status(gettext("brand-specific validatesnapshot"), 3407089Sgjelinek status, B_FALSE)) != ZONE_SUBPROC_OK) 3417089Sgjelinek return (Z_ERR); 3421867Sgjelinek 3437089Sgjelinek return (Z_OK); 3441867Sgjelinek } 3451867Sgjelinek 3461867Sgjelinek /* 3471867Sgjelinek * Remove the sw inventory file from inside this zonepath that we picked up out 3481867Sgjelinek * of the snapshot. 3491867Sgjelinek */ 3501867Sgjelinek static int 3511867Sgjelinek clean_out_clone() 3521867Sgjelinek { 3531867Sgjelinek int err; 3541867Sgjelinek zone_dochandle_t handle; 3551867Sgjelinek 3561867Sgjelinek if ((handle = zonecfg_init_handle()) == NULL) { 3571867Sgjelinek zperror(cmd_to_str(CMD_CLONE), B_TRUE); 3581867Sgjelinek return (Z_ERR); 3591867Sgjelinek } 3601867Sgjelinek 3611867Sgjelinek if ((err = zonecfg_get_handle(target_zone, handle)) != Z_OK) { 3621867Sgjelinek errno = err; 3631867Sgjelinek zperror(cmd_to_str(CMD_CLONE), B_TRUE); 3641867Sgjelinek zonecfg_fini_handle(handle); 3651867Sgjelinek return (Z_ERR); 3661867Sgjelinek } 3671867Sgjelinek 3681867Sgjelinek zonecfg_rm_detached(handle, B_FALSE); 3691867Sgjelinek zonecfg_fini_handle(handle); 3701867Sgjelinek 3711867Sgjelinek return (Z_OK); 3721867Sgjelinek } 3731867Sgjelinek 3741867Sgjelinek /* 3751867Sgjelinek * Make a ZFS clone on zonepath from snapshot_name. 3761867Sgjelinek */ 3771867Sgjelinek static int 3781867Sgjelinek clone_snap(char *snapshot_name, char *zonepath) 3791867Sgjelinek { 3801867Sgjelinek int res = Z_OK; 3811867Sgjelinek int err; 3821867Sgjelinek zfs_handle_t *zhp; 3831867Sgjelinek zfs_handle_t *clone; 3842676Seschrock nvlist_t *props = NULL; 3851867Sgjelinek 3862082Seschrock if ((zhp = zfs_open(g_zfs, snapshot_name, ZFS_TYPE_SNAPSHOT)) == NULL) 3871867Sgjelinek return (Z_NO_ENTRY); 3881867Sgjelinek 3891867Sgjelinek (void) printf(gettext("Cloning snapshot %s\n"), snapshot_name); 3901867Sgjelinek 3912676Seschrock if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0 || 3922744Snn35248 nvlist_add_string(props, zfs_prop_to_name(ZFS_PROP_SHARENFS), 3932744Snn35248 "off") != 0) { 3942744Snn35248 if (props != NULL) 3952744Snn35248 nvlist_free(props); 3962676Seschrock (void) fprintf(stderr, gettext("could not create ZFS clone " 3972676Seschrock "%s: out of memory\n"), zonepath); 3982676Seschrock return (Z_ERR); 3992676Seschrock } 4002676Seschrock 4012676Seschrock err = zfs_clone(zhp, zonepath, props); 4021867Sgjelinek zfs_close(zhp); 4032676Seschrock 4042676Seschrock nvlist_free(props); 4052676Seschrock 4061867Sgjelinek if (err != 0) 4071867Sgjelinek return (Z_ERR); 4081867Sgjelinek 4091867Sgjelinek /* create the mountpoint if necessary */ 4105094Slling if ((clone = zfs_open(g_zfs, zonepath, ZFS_TYPE_DATASET)) == NULL) 4111867Sgjelinek return (Z_ERR); 4121867Sgjelinek 4131867Sgjelinek /* 4141867Sgjelinek * The clone has been created so we need to print a diagnostic 4151867Sgjelinek * message if one of the following steps fails for some reason. 4161867Sgjelinek */ 4171867Sgjelinek if (zfs_mount(clone, NULL, 0) != 0) { 4181867Sgjelinek (void) fprintf(stderr, gettext("could not mount ZFS clone " 4191867Sgjelinek "%s\n"), zfs_get_name(clone)); 4201867Sgjelinek res = Z_ERR; 4211867Sgjelinek 4222676Seschrock } else if (clean_out_clone() != Z_OK) { 4232676Seschrock (void) fprintf(stderr, gettext("could not remove the " 4242676Seschrock "software inventory from ZFS clone %s\n"), 4252676Seschrock zfs_get_name(clone)); 4262676Seschrock res = Z_ERR; 4271867Sgjelinek } 4281867Sgjelinek 4291867Sgjelinek zfs_close(clone); 4301867Sgjelinek return (res); 4311867Sgjelinek } 4321867Sgjelinek 4331867Sgjelinek /* 4341867Sgjelinek * This function takes a zonepath and attempts to determine what the ZFS 4351867Sgjelinek * file system name (not mountpoint) should be for that path. We do not 4361867Sgjelinek * assume that zonepath is an existing directory or ZFS fs since we use 4371867Sgjelinek * this function as part of the process of creating a new ZFS fs or clone. 4381867Sgjelinek * 4391867Sgjelinek * The way this works is that we look at the parent directory of the zonepath 4401867Sgjelinek * to see if it is a ZFS fs. If it is, we get the name of that ZFS fs and 4411867Sgjelinek * append the last component of the zonepath to generate the ZFS name for the 4421867Sgjelinek * zonepath. This matches the algorithm that ZFS uses for automatically 4431867Sgjelinek * mounting a new fs after it is created. 4441867Sgjelinek * 4451867Sgjelinek * Although a ZFS fs can be mounted anywhere, we don't worry about handling 4461867Sgjelinek * all of the complexity that a user could possibly configure with arbitrary 4471867Sgjelinek * mounts since there is no way to generate a ZFS name from a random path in 4481867Sgjelinek * the file system. We only try to handle the automatic mounts that ZFS does 4491867Sgjelinek * for each file system. ZFS restricts this so that a new fs must be created 4501867Sgjelinek * in an existing parent ZFS fs. It then automatically mounts the new fs 4511867Sgjelinek * directly under the mountpoint for the parent fs using the last component 4521867Sgjelinek * of the name as the mountpoint directory. 4531867Sgjelinek * 4541867Sgjelinek * For example: 4551867Sgjelinek * Name Mountpoint 4561867Sgjelinek * space/eng/dev/test/zone1 /project1/eng/dev/test/zone1 4571867Sgjelinek * 4581867Sgjelinek * Return Z_OK if the path mapped to a ZFS file system name, otherwise return 4591867Sgjelinek * Z_ERR. 4601867Sgjelinek */ 4611867Sgjelinek static int 4621867Sgjelinek path2name(char *zonepath, char *zfs_name, int len) 4631867Sgjelinek { 4641867Sgjelinek int res; 465*7093Sgjelinek char *bnm, *dnm, *dname, *bname; 4661867Sgjelinek zfs_handle_t *zhp; 467*7093Sgjelinek struct stat stbuf; 4681867Sgjelinek 469*7093Sgjelinek /* 470*7093Sgjelinek * We need two tmp strings to handle paths directly in / (e.g. /foo) 471*7093Sgjelinek * since dirname will overwrite the first char after "/" in this case. 472*7093Sgjelinek */ 473*7093Sgjelinek if ((bnm = strdup(zonepath)) == NULL) 4741867Sgjelinek return (Z_ERR); 4751867Sgjelinek 476*7093Sgjelinek if ((dnm = strdup(zonepath)) == NULL) { 477*7093Sgjelinek free(bnm); 478*7093Sgjelinek return (Z_ERR); 479*7093Sgjelinek } 480*7093Sgjelinek 481*7093Sgjelinek bname = basename(bnm); 482*7093Sgjelinek dname = dirname(dnm); 483*7093Sgjelinek 4841867Sgjelinek /* 485*7093Sgjelinek * This is a quick test to save iterating over all of the zfs datasets 486*7093Sgjelinek * on the system (which can be a lot). If the parent dir is not in a 487*7093Sgjelinek * ZFS fs, then we're done. 4881867Sgjelinek */ 489*7093Sgjelinek if (stat(dname, &stbuf) != 0 || !S_ISDIR(stbuf.st_mode) || 490*7093Sgjelinek strcmp(stbuf.st_fstype, MNTTYPE_ZFS) != 0) { 491*7093Sgjelinek free(bnm); 492*7093Sgjelinek free(dnm); 4931867Sgjelinek return (Z_ERR); 494*7093Sgjelinek } 4951867Sgjelinek 496*7093Sgjelinek /* See if the parent directory is its own ZFS dataset. */ 497*7093Sgjelinek if ((zhp = mount2zhandle(dname)) == NULL) { 498*7093Sgjelinek /* 499*7093Sgjelinek * The parent is not a ZFS dataset so we can't automatically 500*7093Sgjelinek * create a dataset on the given path. 501*7093Sgjelinek */ 502*7093Sgjelinek free(bnm); 503*7093Sgjelinek free(dnm); 504*7093Sgjelinek return (Z_ERR); 505*7093Sgjelinek } 5061867Sgjelinek 507*7093Sgjelinek res = snprintf(zfs_name, len, "%s/%s", zfs_get_name(zhp), bname); 508*7093Sgjelinek 509*7093Sgjelinek free(bnm); 510*7093Sgjelinek free(dnm); 5111867Sgjelinek zfs_close(zhp); 5121867Sgjelinek if (res >= len) 5131867Sgjelinek return (Z_ERR); 5141867Sgjelinek 5151867Sgjelinek return (Z_OK); 5161867Sgjelinek } 5171867Sgjelinek 5181867Sgjelinek /* 5191867Sgjelinek * A ZFS file system iterator call-back function used to determine if the 5201867Sgjelinek * file system has dependents (snapshots & clones). 5211867Sgjelinek */ 5221867Sgjelinek /* ARGSUSED */ 5231867Sgjelinek static int 5241867Sgjelinek has_dependent(zfs_handle_t *zhp, void *data) 5251867Sgjelinek { 5261867Sgjelinek zfs_close(zhp); 5271867Sgjelinek return (1); 5281867Sgjelinek } 5291867Sgjelinek 5301867Sgjelinek /* 5311867Sgjelinek * Given a snapshot name, get the file system path where the snapshot lives. 5321867Sgjelinek * A snapshot name is of the form fs_name@snap_name. For example, snapshot 5331867Sgjelinek * pl/zones/z1@SUNWzone1 would have a path of 5341867Sgjelinek * /pl/zones/z1/.zfs/snapshot/SUNWzone1. 5351867Sgjelinek */ 5361867Sgjelinek static int 5371867Sgjelinek snap2path(char *snap_name, char *path, int len) 5381867Sgjelinek { 5391867Sgjelinek char *p; 5401867Sgjelinek zfs_handle_t *zhp; 5411867Sgjelinek char mp[ZFS_MAXPROPLEN]; 5421867Sgjelinek 5431867Sgjelinek if ((p = strrchr(snap_name, '@')) == NULL) 5441867Sgjelinek return (Z_ERR); 5451867Sgjelinek 5461867Sgjelinek /* Get the file system name from the snap_name. */ 5471867Sgjelinek *p = '\0'; 5485094Slling zhp = zfs_open(g_zfs, snap_name, ZFS_TYPE_DATASET); 5491867Sgjelinek *p = '@'; 5501867Sgjelinek if (zhp == NULL) 5511867Sgjelinek return (Z_ERR); 5521867Sgjelinek 5531867Sgjelinek /* Get the file system mount point. */ 5541867Sgjelinek if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mp, sizeof (mp), NULL, NULL, 5552082Seschrock 0, B_FALSE) != 0) { 5561867Sgjelinek zfs_close(zhp); 5571867Sgjelinek return (Z_ERR); 5581867Sgjelinek } 5591867Sgjelinek zfs_close(zhp); 5601867Sgjelinek 5611867Sgjelinek p++; 5621867Sgjelinek if (snprintf(path, len, "%s/.zfs/snapshot/%s", mp, p) >= len) 5631867Sgjelinek return (Z_ERR); 5641867Sgjelinek 5651867Sgjelinek return (Z_OK); 5661867Sgjelinek } 5671867Sgjelinek 5681867Sgjelinek /* 5691867Sgjelinek * Clone a pre-existing ZFS snapshot, either by making a direct ZFS clone, if 5701867Sgjelinek * possible, or by copying the data from the snapshot to the zonepath. 5711867Sgjelinek */ 5721867Sgjelinek int 5737089Sgjelinek clone_snapshot_zfs(char *snap_name, char *zonepath, char *validatesnap) 5741867Sgjelinek { 5751867Sgjelinek int err = Z_OK; 5761867Sgjelinek char clone_name[MAXPATHLEN]; 5771867Sgjelinek char snap_path[MAXPATHLEN]; 5781867Sgjelinek 5791867Sgjelinek if (snap2path(snap_name, snap_path, sizeof (snap_path)) != Z_OK) { 5801867Sgjelinek (void) fprintf(stderr, gettext("unable to find path for %s.\n"), 5811867Sgjelinek snap_name); 5821867Sgjelinek return (Z_ERR); 5831867Sgjelinek } 5841867Sgjelinek 5857089Sgjelinek if (validate_snapshot(snap_name, snap_path, validatesnap) != Z_OK) 5861867Sgjelinek return (Z_NO_ENTRY); 5871867Sgjelinek 5881867Sgjelinek /* 5891867Sgjelinek * The zonepath cannot be ZFS cloned, try to copy the data from 5901867Sgjelinek * within the snapshot to the zonepath. 5911867Sgjelinek */ 5921867Sgjelinek if (path2name(zonepath, clone_name, sizeof (clone_name)) != Z_OK) { 5931867Sgjelinek if ((err = clone_copy(snap_path, zonepath)) == Z_OK) 5941867Sgjelinek if (clean_out_clone() != Z_OK) 5951867Sgjelinek (void) fprintf(stderr, 5961867Sgjelinek gettext("could not remove the " 5971867Sgjelinek "software inventory from %s\n"), zonepath); 5981867Sgjelinek 5991867Sgjelinek return (err); 6001867Sgjelinek } 6011867Sgjelinek 6021867Sgjelinek if ((err = clone_snap(snap_name, clone_name)) != Z_OK) { 6031867Sgjelinek if (err != Z_NO_ENTRY) { 6041867Sgjelinek /* 6051867Sgjelinek * Cloning the snapshot failed. Fall back to trying 6061867Sgjelinek * to install the zone by copying from the snapshot. 6071867Sgjelinek */ 6081867Sgjelinek if ((err = clone_copy(snap_path, zonepath)) == Z_OK) 6091867Sgjelinek if (clean_out_clone() != Z_OK) 6101867Sgjelinek (void) fprintf(stderr, 6111867Sgjelinek gettext("could not remove the " 6121867Sgjelinek "software inventory from %s\n"), 6131867Sgjelinek zonepath); 6141867Sgjelinek } else { 6151867Sgjelinek /* 6161867Sgjelinek * The snapshot is unusable for some reason so restore 6171867Sgjelinek * the zone state to configured since we were unable to 6181867Sgjelinek * actually do anything about getting the zone 6191867Sgjelinek * installed. 6201867Sgjelinek */ 6211867Sgjelinek int tmp; 6221867Sgjelinek 6231867Sgjelinek if ((tmp = zone_set_state(target_zone, 6241867Sgjelinek ZONE_STATE_CONFIGURED)) != Z_OK) { 6251867Sgjelinek errno = tmp; 6261867Sgjelinek zperror2(target_zone, 6271867Sgjelinek gettext("could not set state")); 6281867Sgjelinek } 6291867Sgjelinek } 6301867Sgjelinek } 6311867Sgjelinek 6321867Sgjelinek return (err); 6331867Sgjelinek } 6341867Sgjelinek 6351867Sgjelinek /* 6361867Sgjelinek * Attempt to clone a source_zone to a target zonepath by using a ZFS clone. 6371867Sgjelinek */ 6381867Sgjelinek int 6397089Sgjelinek clone_zfs(char *source_zonepath, char *zonepath, char *presnapbuf, 6407089Sgjelinek char *postsnapbuf) 6411867Sgjelinek { 6421867Sgjelinek zfs_handle_t *zhp; 6431867Sgjelinek char clone_name[MAXPATHLEN]; 6441867Sgjelinek char snap_name[MAXPATHLEN]; 6451867Sgjelinek 6461867Sgjelinek /* 6471867Sgjelinek * Try to get a zfs handle for the source_zonepath. If this fails 6481867Sgjelinek * the source_zonepath is not ZFS so return an error. 6491867Sgjelinek */ 6501867Sgjelinek if ((zhp = mount2zhandle(source_zonepath)) == NULL) 6511867Sgjelinek return (Z_ERR); 6521867Sgjelinek 6531867Sgjelinek /* 6541867Sgjelinek * Check if there is a file system already mounted on zonepath. If so, 6551867Sgjelinek * we can't clone to the path so we should fall back to copying. 6561867Sgjelinek */ 6571867Sgjelinek if (is_mountpnt(zonepath)) { 6581867Sgjelinek zfs_close(zhp); 6591867Sgjelinek (void) fprintf(stderr, 6601867Sgjelinek gettext("A file system is already mounted on %s,\n" 6611867Sgjelinek "preventing use of a ZFS clone.\n"), zonepath); 6621867Sgjelinek return (Z_ERR); 6631867Sgjelinek } 6641867Sgjelinek 6651867Sgjelinek /* 6661867Sgjelinek * Instead of using path2name to get the clone name from the zonepath, 6671867Sgjelinek * we could generate a name from the source zone ZFS name. However, 6681867Sgjelinek * this would mean we would create the clone under the ZFS fs of the 6691867Sgjelinek * source instead of what the zonepath says. For example, 6701867Sgjelinek * 6711867Sgjelinek * source_zonepath zonepath 6721867Sgjelinek * /pl/zones/dev/z1 /pl/zones/deploy/z2 6731867Sgjelinek * 6741867Sgjelinek * We don't want the clone to be under "dev", we want it under 6751867Sgjelinek * "deploy", so that we can leverage the normal attribute inheritance 6761867Sgjelinek * that ZFS provides in the fs hierarchy. 6771867Sgjelinek */ 6781867Sgjelinek if (path2name(zonepath, clone_name, sizeof (clone_name)) != Z_OK) { 6791867Sgjelinek zfs_close(zhp); 6801867Sgjelinek return (Z_ERR); 6811867Sgjelinek } 6821867Sgjelinek 6837089Sgjelinek if (take_snapshot(zhp, snap_name, sizeof (snap_name), presnapbuf, 6847089Sgjelinek postsnapbuf) != Z_OK) { 6851867Sgjelinek zfs_close(zhp); 6861867Sgjelinek return (Z_ERR); 6871867Sgjelinek } 6881867Sgjelinek zfs_close(zhp); 6891867Sgjelinek 6903686Sgjelinek if (clone_snap(snap_name, clone_name) != Z_OK) { 6913686Sgjelinek /* Clean up the snapshot we just took. */ 6923686Sgjelinek if ((zhp = zfs_open(g_zfs, snap_name, ZFS_TYPE_SNAPSHOT)) 6933686Sgjelinek != NULL) { 6943686Sgjelinek if (zfs_unmount(zhp, NULL, 0) == 0) 6953686Sgjelinek (void) zfs_destroy(zhp); 6963686Sgjelinek zfs_close(zhp); 6973686Sgjelinek } 6983686Sgjelinek 6991867Sgjelinek return (Z_ERR); 7003686Sgjelinek } 7011867Sgjelinek 7021867Sgjelinek (void) printf(gettext("Instead of copying, a ZFS clone has been " 7031867Sgjelinek "created for this zone.\n")); 7041867Sgjelinek 7051867Sgjelinek return (Z_OK); 7061867Sgjelinek } 7071867Sgjelinek 7081867Sgjelinek /* 7091867Sgjelinek * Attempt to create a ZFS file system for the specified zonepath. 7101867Sgjelinek * We either will successfully create a ZFS file system and get it mounted 7111867Sgjelinek * on the zonepath or we don't. The caller doesn't care since a regular 7121867Sgjelinek * directory is used for the zonepath if no ZFS file system is mounted there. 7131867Sgjelinek */ 7141867Sgjelinek void 7151867Sgjelinek create_zfs_zonepath(char *zonepath) 7161867Sgjelinek { 7171867Sgjelinek zfs_handle_t *zhp; 7181867Sgjelinek char zfs_name[MAXPATHLEN]; 7192676Seschrock nvlist_t *props = NULL; 7201867Sgjelinek 7211867Sgjelinek if (path2name(zonepath, zfs_name, sizeof (zfs_name)) != Z_OK) 7221867Sgjelinek return; 7231867Sgjelinek 7242676Seschrock if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0 || 7252744Snn35248 nvlist_add_string(props, zfs_prop_to_name(ZFS_PROP_SHARENFS), 7262744Snn35248 "off") != 0) { 7272744Snn35248 if (props != NULL) 7282744Snn35248 nvlist_free(props); 7292676Seschrock (void) fprintf(stderr, gettext("cannot create ZFS dataset %s: " 7302676Seschrock "out of memory\n"), zfs_name); 7312676Seschrock } 7322676Seschrock 7332676Seschrock if (zfs_create(g_zfs, zfs_name, ZFS_TYPE_FILESYSTEM, props) != 0 || 7345094Slling (zhp = zfs_open(g_zfs, zfs_name, ZFS_TYPE_DATASET)) == NULL) { 7352082Seschrock (void) fprintf(stderr, gettext("cannot create ZFS dataset %s: " 7362082Seschrock "%s\n"), zfs_name, libzfs_error_description(g_zfs)); 7372676Seschrock nvlist_free(props); 7381867Sgjelinek return; 7391867Sgjelinek } 7401867Sgjelinek 7412676Seschrock nvlist_free(props); 7422676Seschrock 7431867Sgjelinek if (zfs_mount(zhp, NULL, 0) != 0) { 7442082Seschrock (void) fprintf(stderr, gettext("cannot mount ZFS dataset %s: " 7452082Seschrock "%s\n"), zfs_name, libzfs_error_description(g_zfs)); 7461867Sgjelinek (void) zfs_destroy(zhp); 7471867Sgjelinek } else { 7481867Sgjelinek if (chmod(zonepath, S_IRWXU) != 0) { 7491867Sgjelinek (void) fprintf(stderr, gettext("file system %s " 7501867Sgjelinek "successfully created, but chmod %o failed: %s\n"), 7511867Sgjelinek zfs_name, S_IRWXU, strerror(errno)); 7521867Sgjelinek (void) destroy_zfs(zonepath); 7531867Sgjelinek } else { 7541867Sgjelinek (void) printf(gettext("A ZFS file system has been " 7551867Sgjelinek "created for this zone.\n")); 7561867Sgjelinek } 7571867Sgjelinek } 7581867Sgjelinek 7591867Sgjelinek zfs_close(zhp); 7601867Sgjelinek } 7611867Sgjelinek 7621867Sgjelinek /* 7631867Sgjelinek * If the zonepath is a ZFS file system, attempt to destroy it. We return Z_OK 7641867Sgjelinek * if we were able to zfs_destroy the zonepath, otherwise we return Z_ERR 7651867Sgjelinek * which means the caller should clean up the zonepath in the traditional 7661867Sgjelinek * way. 7671867Sgjelinek */ 7681867Sgjelinek int 7691867Sgjelinek destroy_zfs(char *zonepath) 7701867Sgjelinek { 7711867Sgjelinek zfs_handle_t *zhp; 7721867Sgjelinek boolean_t is_clone = B_FALSE; 7731867Sgjelinek char origin[ZFS_MAXPROPLEN]; 7741867Sgjelinek 7752082Seschrock if ((zhp = mount2zhandle(zonepath)) == NULL) 7761867Sgjelinek return (Z_ERR); 7771867Sgjelinek 7781867Sgjelinek /* 7791867Sgjelinek * We can't destroy the file system if it has dependents. 7801867Sgjelinek */ 7812474Seschrock if (zfs_iter_dependents(zhp, B_TRUE, has_dependent, NULL) != 0 || 7821867Sgjelinek zfs_unmount(zhp, NULL, 0) != 0) { 7831867Sgjelinek zfs_close(zhp); 7841867Sgjelinek return (Z_ERR); 7851867Sgjelinek } 7861867Sgjelinek 7871867Sgjelinek /* 7881867Sgjelinek * This might be a clone. Try to get the snapshot so we can attempt 7891867Sgjelinek * to destroy that as well. 7901867Sgjelinek */ 7911867Sgjelinek if (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, origin, sizeof (origin), NULL, 7922082Seschrock NULL, 0, B_FALSE) == 0) 7931867Sgjelinek is_clone = B_TRUE; 7941867Sgjelinek 7951867Sgjelinek if (zfs_destroy(zhp) != 0) { 7961867Sgjelinek /* 7971867Sgjelinek * If the destroy fails for some reason, try to remount 7981867Sgjelinek * the file system so that we can use "rm -rf" to clean up 7991867Sgjelinek * instead. 8001867Sgjelinek */ 8011867Sgjelinek (void) zfs_mount(zhp, NULL, 0); 8021867Sgjelinek zfs_close(zhp); 8031867Sgjelinek return (Z_ERR); 8041867Sgjelinek } 8051867Sgjelinek 8063686Sgjelinek /* 8073686Sgjelinek * If the zone has ever been moved then the mountpoint dir will not be 8083686Sgjelinek * cleaned up by the zfs_destroy(). To handle this case try to clean 8093686Sgjelinek * it up now but don't worry if it fails, that will be normal. 8103686Sgjelinek */ 8113686Sgjelinek (void) rmdir(zonepath); 8123686Sgjelinek 8131867Sgjelinek (void) printf(gettext("The ZFS file system for this zone has been " 8141867Sgjelinek "destroyed.\n")); 8151867Sgjelinek 8161867Sgjelinek if (is_clone) { 8171867Sgjelinek zfs_handle_t *ohp; 8181867Sgjelinek 8191867Sgjelinek /* 8201867Sgjelinek * Try to clean up the snapshot that the clone was taken from. 8211867Sgjelinek */ 8222082Seschrock if ((ohp = zfs_open(g_zfs, origin, 8232082Seschrock ZFS_TYPE_SNAPSHOT)) != NULL) { 8242474Seschrock if (zfs_iter_dependents(ohp, B_TRUE, has_dependent, 8252474Seschrock NULL) == 0 && zfs_unmount(ohp, NULL, 0) == 0) 8261867Sgjelinek (void) zfs_destroy(ohp); 8271867Sgjelinek zfs_close(ohp); 8281867Sgjelinek } 8291867Sgjelinek } 8301867Sgjelinek 8311867Sgjelinek zfs_close(zhp); 8321867Sgjelinek return (Z_OK); 8331867Sgjelinek } 8341867Sgjelinek 8351867Sgjelinek /* 8361867Sgjelinek * Return true if the path is its own zfs file system. We determine this 8371867Sgjelinek * by stat-ing the path to see if it is zfs and stat-ing the parent to see 8381867Sgjelinek * if it is a different fs. 8391867Sgjelinek */ 8401867Sgjelinek boolean_t 8411867Sgjelinek is_zonepath_zfs(char *zonepath) 8421867Sgjelinek { 8431867Sgjelinek int res; 8441867Sgjelinek char *path; 8451867Sgjelinek char *parent; 8462267Sdp struct statvfs64 buf1, buf2; 8471867Sgjelinek 8482267Sdp if (statvfs64(zonepath, &buf1) != 0) 8491867Sgjelinek return (B_FALSE); 8501867Sgjelinek 8511867Sgjelinek if (strcmp(buf1.f_basetype, "zfs") != 0) 8521867Sgjelinek return (B_FALSE); 8531867Sgjelinek 8541867Sgjelinek if ((path = strdup(zonepath)) == NULL) 8551867Sgjelinek return (B_FALSE); 8561867Sgjelinek 8571867Sgjelinek parent = dirname(path); 8582267Sdp res = statvfs64(parent, &buf2); 8591867Sgjelinek free(path); 8601867Sgjelinek 8611867Sgjelinek if (res != 0) 8621867Sgjelinek return (B_FALSE); 8631867Sgjelinek 8641867Sgjelinek if (buf1.f_fsid == buf2.f_fsid) 8651867Sgjelinek return (B_FALSE); 8661867Sgjelinek 8671867Sgjelinek return (B_TRUE); 8681867Sgjelinek } 8691867Sgjelinek 8701867Sgjelinek /* 8711867Sgjelinek * Implement the fast move of a ZFS file system by simply updating the 8721867Sgjelinek * mountpoint. Since it is file system already, we don't have the 8731867Sgjelinek * issue of cross-file system copying. 8741867Sgjelinek */ 8751867Sgjelinek int 8761867Sgjelinek move_zfs(char *zonepath, char *new_zonepath) 8771867Sgjelinek { 8781867Sgjelinek int ret = Z_ERR; 8791867Sgjelinek zfs_handle_t *zhp; 8801867Sgjelinek 8812082Seschrock if ((zhp = mount2zhandle(zonepath)) == NULL) 8821867Sgjelinek return (Z_ERR); 8831867Sgjelinek 8842676Seschrock if (zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_MOUNTPOINT), 8852676Seschrock new_zonepath) == 0) { 8861867Sgjelinek /* 8871867Sgjelinek * Clean up the old mount point. We ignore any failure since 8881867Sgjelinek * the zone is already successfully mounted on the new path. 8891867Sgjelinek */ 8901867Sgjelinek (void) rmdir(zonepath); 8911867Sgjelinek ret = Z_OK; 8921867Sgjelinek } 8931867Sgjelinek 8941867Sgjelinek zfs_close(zhp); 8951867Sgjelinek 8961867Sgjelinek return (ret); 8971867Sgjelinek } 8981867Sgjelinek 8991867Sgjelinek /* 9001867Sgjelinek * Validate that the given dataset exists on the system, and that neither it nor 9011867Sgjelinek * its children are zvols. 9021867Sgjelinek * 9031867Sgjelinek * Note that we don't do anything with the 'zoned' property here. All 9041867Sgjelinek * management is done in zoneadmd when the zone is actually rebooted. This 9051867Sgjelinek * allows us to automatically set the zoned property even when a zone is 9061867Sgjelinek * rebooted by the administrator. 9071867Sgjelinek */ 9081867Sgjelinek int 9091867Sgjelinek verify_datasets(zone_dochandle_t handle) 9101867Sgjelinek { 9111867Sgjelinek int return_code = Z_OK; 9121867Sgjelinek struct zone_dstab dstab; 9131867Sgjelinek zfs_handle_t *zhp; 9141867Sgjelinek char propbuf[ZFS_MAXPROPLEN]; 9151867Sgjelinek char source[ZFS_MAXNAMELEN]; 9165094Slling zprop_source_t srctype; 9171867Sgjelinek 9181867Sgjelinek if (zonecfg_setdsent(handle) != Z_OK) { 9191867Sgjelinek /* 9201867Sgjelinek * TRANSLATION_NOTE 9211867Sgjelinek * zfs and dataset are literals that should not be translated. 9221867Sgjelinek */ 9231867Sgjelinek (void) fprintf(stderr, gettext("could not verify zfs datasets: " 9241867Sgjelinek "unable to enumerate datasets\n")); 9251867Sgjelinek return (Z_ERR); 9261867Sgjelinek } 9271867Sgjelinek 9281867Sgjelinek while (zonecfg_getdsent(handle, &dstab) == Z_OK) { 9291867Sgjelinek 9302082Seschrock if ((zhp = zfs_open(g_zfs, dstab.zone_dataset_name, 9311867Sgjelinek ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME)) == NULL) { 9322082Seschrock (void) fprintf(stderr, gettext("could not verify zfs " 9332082Seschrock "dataset %s: %s\n"), dstab.zone_dataset_name, 9342082Seschrock libzfs_error_description(g_zfs)); 9351867Sgjelinek return_code = Z_ERR; 9361867Sgjelinek continue; 9371867Sgjelinek } 9381867Sgjelinek 9391867Sgjelinek if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, propbuf, 9401867Sgjelinek sizeof (propbuf), &srctype, source, 9411867Sgjelinek sizeof (source), 0) == 0 && 9425094Slling (srctype == ZPROP_SRC_INHERITED)) { 9431867Sgjelinek (void) fprintf(stderr, gettext("could not verify zfs " 9441867Sgjelinek "dataset %s: mountpoint cannot be inherited\n"), 9451867Sgjelinek dstab.zone_dataset_name); 9461867Sgjelinek return_code = Z_ERR; 9471867Sgjelinek zfs_close(zhp); 9481867Sgjelinek continue; 9491867Sgjelinek } 9501867Sgjelinek 9511867Sgjelinek if (zfs_get_type(zhp) == ZFS_TYPE_VOLUME) { 9521867Sgjelinek (void) fprintf(stderr, gettext("cannot verify zfs " 9531867Sgjelinek "dataset %s: volumes cannot be specified as a " 9541867Sgjelinek "zone dataset resource\n"), 9551867Sgjelinek dstab.zone_dataset_name); 9561867Sgjelinek return_code = Z_ERR; 9571867Sgjelinek } 9581867Sgjelinek 9591867Sgjelinek if (zfs_iter_children(zhp, check_zvol, NULL) != 0) 9601867Sgjelinek return_code = Z_ERR; 9611867Sgjelinek 9621867Sgjelinek zfs_close(zhp); 9631867Sgjelinek } 9641867Sgjelinek (void) zonecfg_enddsent(handle); 9651867Sgjelinek 9661867Sgjelinek return (return_code); 9671867Sgjelinek } 9681867Sgjelinek 9691867Sgjelinek /* 9701867Sgjelinek * Verify that the ZFS dataset exists, and its mountpoint 9711867Sgjelinek * property is set to "legacy". 9721867Sgjelinek */ 9731867Sgjelinek int 9741867Sgjelinek verify_fs_zfs(struct zone_fstab *fstab) 9751867Sgjelinek { 9761867Sgjelinek zfs_handle_t *zhp; 9771867Sgjelinek char propbuf[ZFS_MAXPROPLEN]; 9781867Sgjelinek 9792082Seschrock if ((zhp = zfs_open(g_zfs, fstab->zone_fs_special, 9805094Slling ZFS_TYPE_DATASET)) == NULL) { 9811867Sgjelinek (void) fprintf(stderr, gettext("could not verify fs %s: " 9821867Sgjelinek "could not access zfs dataset '%s'\n"), 9831867Sgjelinek fstab->zone_fs_dir, fstab->zone_fs_special); 9841867Sgjelinek return (Z_ERR); 9851867Sgjelinek } 9861867Sgjelinek 9871867Sgjelinek if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) { 9881867Sgjelinek (void) fprintf(stderr, gettext("cannot verify fs %s: " 9891867Sgjelinek "'%s' is not a file system\n"), 9901867Sgjelinek fstab->zone_fs_dir, fstab->zone_fs_special); 9911867Sgjelinek zfs_close(zhp); 9921867Sgjelinek return (Z_ERR); 9931867Sgjelinek } 9941867Sgjelinek 9951867Sgjelinek if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, propbuf, sizeof (propbuf), 9961867Sgjelinek NULL, NULL, 0, 0) != 0 || strcmp(propbuf, "legacy") != 0) { 9971867Sgjelinek (void) fprintf(stderr, gettext("could not verify fs %s: " 9981867Sgjelinek "zfs '%s' mountpoint is not \"legacy\"\n"), 9991867Sgjelinek fstab->zone_fs_dir, fstab->zone_fs_special); 10001867Sgjelinek zfs_close(zhp); 10011867Sgjelinek return (Z_ERR); 10021867Sgjelinek } 10031867Sgjelinek 10041867Sgjelinek zfs_close(zhp); 10051867Sgjelinek return (Z_OK); 10061867Sgjelinek } 10072082Seschrock 10082082Seschrock int 10092082Seschrock init_zfs(void) 10102082Seschrock { 10112082Seschrock if ((g_zfs = libzfs_init()) == NULL) { 10122082Seschrock (void) fprintf(stderr, gettext("failed to initialize ZFS " 10132082Seschrock "library\n")); 10142082Seschrock return (Z_ERR); 10152082Seschrock } 10162082Seschrock 10172082Seschrock return (Z_OK); 10182082Seschrock } 1019