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 /* 239023Sgerald.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> 46*9386Sgerald.jelinek@sun.com #include <values.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 { 58*9386Sgerald.jelinek@sun.com char *match_name; /* zonename@SUNWzone */ 59*9386Sgerald.jelinek@sun.com int len; /* strlen of match_name */ 60*9386Sgerald.jelinek@sun.com int max; /* highest digit appended to snap name */ 61*9386Sgerald.jelinek@sun.com int num; /* number of snapshots to rename */ 62*9386Sgerald.jelinek@sun.com int cntr; /* counter for renaming snapshots */ 631867Sgjelinek } zfs_snapshot_data_t; 641867Sgjelinek 65*9386Sgerald.jelinek@sun.com typedef struct clone_data { 66*9386Sgerald.jelinek@sun.com zfs_handle_t *clone_zhp; /* clone dataset to promote */ 67*9386Sgerald.jelinek@sun.com time_t origin_creation; /* snapshot creation time of clone */ 68*9386Sgerald.jelinek@sun.com const char *snapshot; /* snapshot of dataset being demoted */ 69*9386Sgerald.jelinek@sun.com } clone_data_t; 70*9386Sgerald.jelinek@sun.com 711867Sgjelinek /* 721867Sgjelinek * A ZFS file system iterator call-back function which is used to validate 731867Sgjelinek * datasets imported into the zone. 741867Sgjelinek */ 751867Sgjelinek /* ARGSUSED */ 761867Sgjelinek static int 771867Sgjelinek check_zvol(zfs_handle_t *zhp, void *unused) 781867Sgjelinek { 791867Sgjelinek int ret; 801867Sgjelinek 811867Sgjelinek if (zfs_get_type(zhp) == ZFS_TYPE_VOLUME) { 821867Sgjelinek /* 831867Sgjelinek * TRANSLATION_NOTE 841867Sgjelinek * zfs and dataset are literals that should not be translated. 851867Sgjelinek */ 861867Sgjelinek (void) fprintf(stderr, gettext("cannot verify zfs dataset %s: " 871867Sgjelinek "volumes cannot be specified as a zone dataset resource\n"), 881867Sgjelinek zfs_get_name(zhp)); 891867Sgjelinek ret = -1; 901867Sgjelinek } else { 911867Sgjelinek ret = zfs_iter_children(zhp, check_zvol, NULL); 921867Sgjelinek } 931867Sgjelinek 941867Sgjelinek zfs_close(zhp); 951867Sgjelinek 961867Sgjelinek return (ret); 971867Sgjelinek } 981867Sgjelinek 991867Sgjelinek /* 1001867Sgjelinek * A ZFS file system iterator call-back function which returns the 1011867Sgjelinek * zfs_handle_t for a ZFS file system on the specified mount point. 1021867Sgjelinek */ 1031867Sgjelinek static int 1041867Sgjelinek match_mountpoint(zfs_handle_t *zhp, void *data) 1051867Sgjelinek { 1061867Sgjelinek int res; 1071867Sgjelinek zfs_mount_data_t *cbp; 1081867Sgjelinek char mp[ZFS_MAXPROPLEN]; 1091867Sgjelinek 1101867Sgjelinek if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) { 1111867Sgjelinek zfs_close(zhp); 1121867Sgjelinek return (0); 1131867Sgjelinek } 1141867Sgjelinek 1157093Sgjelinek /* First check if the dataset is mounted. */ 1167093Sgjelinek if (zfs_prop_get(zhp, ZFS_PROP_MOUNTED, mp, sizeof (mp), NULL, NULL, 1177093Sgjelinek 0, B_FALSE) != 0 || strcmp(mp, "no") == 0) { 1187093Sgjelinek zfs_close(zhp); 1197093Sgjelinek return (0); 1207093Sgjelinek } 1217093Sgjelinek 1227093Sgjelinek /* Now check mount point. */ 1231867Sgjelinek if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mp, sizeof (mp), NULL, NULL, 1247093Sgjelinek 0, B_FALSE) != 0) { 1257093Sgjelinek zfs_close(zhp); 1267093Sgjelinek return (0); 1277093Sgjelinek } 1287093Sgjelinek 1297093Sgjelinek cbp = (zfs_mount_data_t *)data; 1307093Sgjelinek 1317093Sgjelinek if (strcmp(mp, "legacy") == 0) { 1327093Sgjelinek /* If legacy, must look in mnttab for mountpoint. */ 1337093Sgjelinek FILE *fp; 1347093Sgjelinek struct mnttab entry; 1357093Sgjelinek const char *nm; 1367093Sgjelinek 1377093Sgjelinek nm = zfs_get_name(zhp); 1387093Sgjelinek if ((fp = fopen(MNTTAB, "r")) == NULL) { 1397093Sgjelinek zfs_close(zhp); 1407093Sgjelinek return (0); 1417093Sgjelinek } 1427093Sgjelinek 1437093Sgjelinek while (getmntent(fp, &entry) == 0) { 1447093Sgjelinek if (strcmp(nm, entry.mnt_special) == 0) { 1457093Sgjelinek if (strcmp(entry.mnt_mountp, cbp->match_name) 1467093Sgjelinek == 0) { 1477093Sgjelinek (void) fclose(fp); 1487093Sgjelinek cbp->match_handle = zhp; 1497093Sgjelinek return (1); 1507093Sgjelinek } 1517093Sgjelinek break; 1527093Sgjelinek } 1537093Sgjelinek } 1547093Sgjelinek (void) fclose(fp); 1557093Sgjelinek 1567093Sgjelinek } else if (strcmp(mp, cbp->match_name) == 0) { 1571867Sgjelinek cbp->match_handle = zhp; 1581867Sgjelinek return (1); 1591867Sgjelinek } 1601867Sgjelinek 1617093Sgjelinek /* Iterate over any nested datasets. */ 1621867Sgjelinek res = zfs_iter_filesystems(zhp, match_mountpoint, data); 1631867Sgjelinek zfs_close(zhp); 1641867Sgjelinek return (res); 1651867Sgjelinek } 1661867Sgjelinek 1671867Sgjelinek /* 1681867Sgjelinek * Get ZFS handle for the specified mount point. 1691867Sgjelinek */ 1701867Sgjelinek static zfs_handle_t * 1711867Sgjelinek mount2zhandle(char *mountpoint) 1721867Sgjelinek { 1731867Sgjelinek zfs_mount_data_t cb; 1741867Sgjelinek 1751867Sgjelinek cb.match_name = mountpoint; 1761867Sgjelinek cb.match_handle = NULL; 1772082Seschrock (void) zfs_iter_root(g_zfs, match_mountpoint, &cb); 1781867Sgjelinek return (cb.match_handle); 1791867Sgjelinek } 1801867Sgjelinek 1811867Sgjelinek /* 1821867Sgjelinek * Check if there is already a file system (zfs or any other type) mounted on 1831867Sgjelinek * path. 1841867Sgjelinek */ 1851867Sgjelinek static boolean_t 1861867Sgjelinek is_mountpnt(char *path) 1871867Sgjelinek { 1881867Sgjelinek FILE *fp; 1891867Sgjelinek struct mnttab entry; 1901867Sgjelinek 1917093Sgjelinek if ((fp = fopen(MNTTAB, "r")) == NULL) 1921867Sgjelinek return (B_FALSE); 1931867Sgjelinek 1941867Sgjelinek while (getmntent(fp, &entry) == 0) { 1951867Sgjelinek if (strcmp(path, entry.mnt_mountp) == 0) { 1961867Sgjelinek (void) fclose(fp); 1971867Sgjelinek return (B_TRUE); 1981867Sgjelinek } 1991867Sgjelinek } 2001867Sgjelinek 2011867Sgjelinek (void) fclose(fp); 2021867Sgjelinek return (B_FALSE); 2031867Sgjelinek } 2041867Sgjelinek 2051867Sgjelinek /* 2067089Sgjelinek * Run the brand's pre-snapshot hook before we take a ZFS snapshot of the zone. 2071867Sgjelinek */ 2081867Sgjelinek static int 2097089Sgjelinek pre_snapshot(char *presnapbuf) 2101867Sgjelinek { 2117089Sgjelinek int status; 2121867Sgjelinek 2137089Sgjelinek /* No brand-specific handler */ 2147089Sgjelinek if (presnapbuf[0] == '\0') 2157089Sgjelinek return (Z_OK); 2161867Sgjelinek 2177089Sgjelinek /* Run the hook */ 2189310Sgerald.jelinek@sun.com status = do_subproc(presnapbuf); 2197089Sgjelinek if ((status = subproc_status(gettext("brand-specific presnapshot"), 2207089Sgjelinek status, B_FALSE)) != ZONE_SUBPROC_OK) 2211867Sgjelinek return (Z_ERR); 2221867Sgjelinek 2231867Sgjelinek return (Z_OK); 2241867Sgjelinek } 2251867Sgjelinek 2261867Sgjelinek /* 2277089Sgjelinek * Run the brand's post-snapshot hook after we take a ZFS snapshot of the zone. 2281867Sgjelinek */ 2291867Sgjelinek static int 2307089Sgjelinek post_snapshot(char *postsnapbuf) 2311867Sgjelinek { 2327089Sgjelinek int status; 2331867Sgjelinek 2347089Sgjelinek /* No brand-specific handler */ 2357089Sgjelinek if (postsnapbuf[0] == '\0') 2367089Sgjelinek return (Z_OK); 2377089Sgjelinek 2387089Sgjelinek /* Run the hook */ 2399310Sgerald.jelinek@sun.com status = do_subproc(postsnapbuf); 2407089Sgjelinek if ((status = subproc_status(gettext("brand-specific postsnapshot"), 2417089Sgjelinek status, B_FALSE)) != ZONE_SUBPROC_OK) 2421867Sgjelinek return (Z_ERR); 2431867Sgjelinek 2441867Sgjelinek return (Z_OK); 2451867Sgjelinek } 2461867Sgjelinek 2471867Sgjelinek /* 2481867Sgjelinek * This is a ZFS snapshot iterator call-back function which returns the 2491867Sgjelinek * highest number of SUNWzone snapshots that have been taken. 2501867Sgjelinek */ 2511867Sgjelinek static int 2521867Sgjelinek get_snap_max(zfs_handle_t *zhp, void *data) 2531867Sgjelinek { 2541867Sgjelinek int res; 2551867Sgjelinek zfs_snapshot_data_t *cbp; 2561867Sgjelinek 2571867Sgjelinek if (zfs_get_type(zhp) != ZFS_TYPE_SNAPSHOT) { 2581867Sgjelinek zfs_close(zhp); 2591867Sgjelinek return (0); 2601867Sgjelinek } 2611867Sgjelinek 2621867Sgjelinek cbp = (zfs_snapshot_data_t *)data; 2631867Sgjelinek 2641867Sgjelinek if (strncmp(zfs_get_name(zhp), cbp->match_name, cbp->len) == 0) { 2651867Sgjelinek char *nump; 2661867Sgjelinek int num; 2671867Sgjelinek 268*9386Sgerald.jelinek@sun.com cbp->num++; 2691867Sgjelinek nump = (char *)(zfs_get_name(zhp) + cbp->len); 2701867Sgjelinek num = atoi(nump); 2711867Sgjelinek if (num > cbp->max) 2721867Sgjelinek cbp->max = num; 2731867Sgjelinek } 2741867Sgjelinek 2751867Sgjelinek res = zfs_iter_snapshots(zhp, get_snap_max, data); 2761867Sgjelinek zfs_close(zhp); 2771867Sgjelinek return (res); 2781867Sgjelinek } 2791867Sgjelinek 2801867Sgjelinek /* 2811867Sgjelinek * Take a ZFS snapshot to be used for cloning the zone. 2821867Sgjelinek */ 2831867Sgjelinek static int 2847089Sgjelinek take_snapshot(zfs_handle_t *zhp, char *snapshot_name, int snap_size, 2857089Sgjelinek char *presnapbuf, char *postsnapbuf) 2861867Sgjelinek { 2871867Sgjelinek int res; 2881867Sgjelinek char template[ZFS_MAXNAMELEN]; 2891867Sgjelinek zfs_snapshot_data_t cb; 2901867Sgjelinek 2911867Sgjelinek /* 2921867Sgjelinek * First we need to figure out the next available name for the 2931867Sgjelinek * zone snapshot. Look through the list of zones snapshots for 2941867Sgjelinek * this file system to determine the maximum snapshot name. 2951867Sgjelinek */ 2961867Sgjelinek if (snprintf(template, sizeof (template), "%s@SUNWzone", 2971867Sgjelinek zfs_get_name(zhp)) >= sizeof (template)) 2981867Sgjelinek return (Z_ERR); 2991867Sgjelinek 3001867Sgjelinek cb.match_name = template; 3011867Sgjelinek cb.len = strlen(template); 3021867Sgjelinek cb.max = 0; 3031867Sgjelinek 3041867Sgjelinek if (zfs_iter_snapshots(zhp, get_snap_max, &cb) != 0) 3051867Sgjelinek return (Z_ERR); 3061867Sgjelinek 3071867Sgjelinek cb.max++; 3081867Sgjelinek 3091867Sgjelinek if (snprintf(snapshot_name, snap_size, "%s@SUNWzone%d", 3101867Sgjelinek zfs_get_name(zhp), cb.max) >= snap_size) 3111867Sgjelinek return (Z_ERR); 3121867Sgjelinek 3137089Sgjelinek if (pre_snapshot(presnapbuf) != Z_OK) 3141867Sgjelinek return (Z_ERR); 3157265Sahrens res = zfs_snapshot(g_zfs, snapshot_name, B_FALSE, NULL); 3167089Sgjelinek if (post_snapshot(postsnapbuf) != Z_OK) 3171867Sgjelinek return (Z_ERR); 3181867Sgjelinek 3191867Sgjelinek if (res != 0) 3201867Sgjelinek return (Z_ERR); 3211867Sgjelinek return (Z_OK); 3221867Sgjelinek } 3231867Sgjelinek 3241867Sgjelinek /* 3251867Sgjelinek * We are using an explicit snapshot from some earlier point in time so 3267089Sgjelinek * we need to validate it. Run the brand specific hook. 3271867Sgjelinek */ 3281867Sgjelinek static int 3297089Sgjelinek validate_snapshot(char *snapshot_name, char *snap_path, char *validsnapbuf) 3301867Sgjelinek { 3317089Sgjelinek int status; 3327089Sgjelinek char cmdbuf[MAXPATHLEN]; 3331867Sgjelinek 3347089Sgjelinek /* No brand-specific handler */ 3357089Sgjelinek if (validsnapbuf[0] == '\0') 3367089Sgjelinek return (Z_OK); 3371867Sgjelinek 3387089Sgjelinek /* pass args - snapshot_name & snap_path */ 3397089Sgjelinek if (snprintf(cmdbuf, sizeof (cmdbuf), "%s %s %s", validsnapbuf, 3407089Sgjelinek snapshot_name, snap_path) >= sizeof (cmdbuf)) { 3417089Sgjelinek zerror("Command line too long"); 3421867Sgjelinek return (Z_ERR); 3431867Sgjelinek } 3441867Sgjelinek 3457089Sgjelinek /* Run the hook */ 3469310Sgerald.jelinek@sun.com status = do_subproc(cmdbuf); 3477089Sgjelinek if ((status = subproc_status(gettext("brand-specific validatesnapshot"), 3487089Sgjelinek status, B_FALSE)) != ZONE_SUBPROC_OK) 3497089Sgjelinek return (Z_ERR); 3501867Sgjelinek 3517089Sgjelinek return (Z_OK); 3521867Sgjelinek } 3531867Sgjelinek 3541867Sgjelinek /* 3551867Sgjelinek * Remove the sw inventory file from inside this zonepath that we picked up out 3561867Sgjelinek * of the snapshot. 3571867Sgjelinek */ 3581867Sgjelinek static int 3591867Sgjelinek clean_out_clone() 3601867Sgjelinek { 3611867Sgjelinek int err; 3621867Sgjelinek zone_dochandle_t handle; 3631867Sgjelinek 3641867Sgjelinek if ((handle = zonecfg_init_handle()) == NULL) { 3651867Sgjelinek zperror(cmd_to_str(CMD_CLONE), B_TRUE); 3661867Sgjelinek return (Z_ERR); 3671867Sgjelinek } 3681867Sgjelinek 3691867Sgjelinek if ((err = zonecfg_get_handle(target_zone, handle)) != Z_OK) { 3701867Sgjelinek errno = err; 3711867Sgjelinek zperror(cmd_to_str(CMD_CLONE), B_TRUE); 3721867Sgjelinek zonecfg_fini_handle(handle); 3731867Sgjelinek return (Z_ERR); 3741867Sgjelinek } 3751867Sgjelinek 3761867Sgjelinek zonecfg_rm_detached(handle, B_FALSE); 3771867Sgjelinek zonecfg_fini_handle(handle); 3781867Sgjelinek 3791867Sgjelinek return (Z_OK); 3801867Sgjelinek } 3811867Sgjelinek 3821867Sgjelinek /* 3831867Sgjelinek * Make a ZFS clone on zonepath from snapshot_name. 3841867Sgjelinek */ 3851867Sgjelinek static int 3861867Sgjelinek clone_snap(char *snapshot_name, char *zonepath) 3871867Sgjelinek { 3881867Sgjelinek int res = Z_OK; 3891867Sgjelinek int err; 3901867Sgjelinek zfs_handle_t *zhp; 3911867Sgjelinek zfs_handle_t *clone; 3922676Seschrock nvlist_t *props = NULL; 3931867Sgjelinek 3942082Seschrock if ((zhp = zfs_open(g_zfs, snapshot_name, ZFS_TYPE_SNAPSHOT)) == NULL) 3951867Sgjelinek return (Z_NO_ENTRY); 3961867Sgjelinek 3971867Sgjelinek (void) printf(gettext("Cloning snapshot %s\n"), snapshot_name); 3981867Sgjelinek 3992676Seschrock if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0 || 4002744Snn35248 nvlist_add_string(props, zfs_prop_to_name(ZFS_PROP_SHARENFS), 4012744Snn35248 "off") != 0) { 4022744Snn35248 if (props != NULL) 4032744Snn35248 nvlist_free(props); 4042676Seschrock (void) fprintf(stderr, gettext("could not create ZFS clone " 4052676Seschrock "%s: out of memory\n"), zonepath); 4062676Seschrock return (Z_ERR); 4072676Seschrock } 4082676Seschrock 4092676Seschrock err = zfs_clone(zhp, zonepath, props); 4101867Sgjelinek zfs_close(zhp); 4112676Seschrock 4122676Seschrock nvlist_free(props); 4132676Seschrock 4141867Sgjelinek if (err != 0) 4151867Sgjelinek return (Z_ERR); 4161867Sgjelinek 4171867Sgjelinek /* create the mountpoint if necessary */ 4185094Slling if ((clone = zfs_open(g_zfs, zonepath, ZFS_TYPE_DATASET)) == NULL) 4191867Sgjelinek return (Z_ERR); 4201867Sgjelinek 4211867Sgjelinek /* 4221867Sgjelinek * The clone has been created so we need to print a diagnostic 4231867Sgjelinek * message if one of the following steps fails for some reason. 4241867Sgjelinek */ 4251867Sgjelinek if (zfs_mount(clone, NULL, 0) != 0) { 4261867Sgjelinek (void) fprintf(stderr, gettext("could not mount ZFS clone " 4271867Sgjelinek "%s\n"), zfs_get_name(clone)); 4281867Sgjelinek res = Z_ERR; 4291867Sgjelinek 4302676Seschrock } else if (clean_out_clone() != Z_OK) { 4312676Seschrock (void) fprintf(stderr, gettext("could not remove the " 4322676Seschrock "software inventory from ZFS clone %s\n"), 4332676Seschrock zfs_get_name(clone)); 4342676Seschrock res = Z_ERR; 4351867Sgjelinek } 4361867Sgjelinek 4371867Sgjelinek zfs_close(clone); 4381867Sgjelinek return (res); 4391867Sgjelinek } 4401867Sgjelinek 4411867Sgjelinek /* 4421867Sgjelinek * This function takes a zonepath and attempts to determine what the ZFS 4431867Sgjelinek * file system name (not mountpoint) should be for that path. We do not 4441867Sgjelinek * assume that zonepath is an existing directory or ZFS fs since we use 4451867Sgjelinek * this function as part of the process of creating a new ZFS fs or clone. 4461867Sgjelinek * 4471867Sgjelinek * The way this works is that we look at the parent directory of the zonepath 4481867Sgjelinek * to see if it is a ZFS fs. If it is, we get the name of that ZFS fs and 4491867Sgjelinek * append the last component of the zonepath to generate the ZFS name for the 4501867Sgjelinek * zonepath. This matches the algorithm that ZFS uses for automatically 4511867Sgjelinek * mounting a new fs after it is created. 4521867Sgjelinek * 4531867Sgjelinek * Although a ZFS fs can be mounted anywhere, we don't worry about handling 4541867Sgjelinek * all of the complexity that a user could possibly configure with arbitrary 4551867Sgjelinek * mounts since there is no way to generate a ZFS name from a random path in 4561867Sgjelinek * the file system. We only try to handle the automatic mounts that ZFS does 4571867Sgjelinek * for each file system. ZFS restricts this so that a new fs must be created 4581867Sgjelinek * in an existing parent ZFS fs. It then automatically mounts the new fs 4591867Sgjelinek * directly under the mountpoint for the parent fs using the last component 4601867Sgjelinek * of the name as the mountpoint directory. 4611867Sgjelinek * 4621867Sgjelinek * For example: 4631867Sgjelinek * Name Mountpoint 4641867Sgjelinek * space/eng/dev/test/zone1 /project1/eng/dev/test/zone1 4651867Sgjelinek * 4661867Sgjelinek * Return Z_OK if the path mapped to a ZFS file system name, otherwise return 4671867Sgjelinek * Z_ERR. 4681867Sgjelinek */ 4691867Sgjelinek static int 4701867Sgjelinek path2name(char *zonepath, char *zfs_name, int len) 4711867Sgjelinek { 4721867Sgjelinek int res; 4737093Sgjelinek char *bnm, *dnm, *dname, *bname; 4741867Sgjelinek zfs_handle_t *zhp; 4757093Sgjelinek struct stat stbuf; 4761867Sgjelinek 4777093Sgjelinek /* 4787093Sgjelinek * We need two tmp strings to handle paths directly in / (e.g. /foo) 4797093Sgjelinek * since dirname will overwrite the first char after "/" in this case. 4807093Sgjelinek */ 4817093Sgjelinek if ((bnm = strdup(zonepath)) == NULL) 4821867Sgjelinek return (Z_ERR); 4831867Sgjelinek 4847093Sgjelinek if ((dnm = strdup(zonepath)) == NULL) { 4857093Sgjelinek free(bnm); 4867093Sgjelinek return (Z_ERR); 4877093Sgjelinek } 4887093Sgjelinek 4897093Sgjelinek bname = basename(bnm); 4907093Sgjelinek dname = dirname(dnm); 4917093Sgjelinek 4921867Sgjelinek /* 4937093Sgjelinek * This is a quick test to save iterating over all of the zfs datasets 4947093Sgjelinek * on the system (which can be a lot). If the parent dir is not in a 4957093Sgjelinek * ZFS fs, then we're done. 4961867Sgjelinek */ 4977093Sgjelinek if (stat(dname, &stbuf) != 0 || !S_ISDIR(stbuf.st_mode) || 4987093Sgjelinek strcmp(stbuf.st_fstype, MNTTYPE_ZFS) != 0) { 4997093Sgjelinek free(bnm); 5007093Sgjelinek free(dnm); 5011867Sgjelinek return (Z_ERR); 5027093Sgjelinek } 5031867Sgjelinek 5047093Sgjelinek /* See if the parent directory is its own ZFS dataset. */ 5057093Sgjelinek if ((zhp = mount2zhandle(dname)) == NULL) { 5067093Sgjelinek /* 5077093Sgjelinek * The parent is not a ZFS dataset so we can't automatically 5087093Sgjelinek * create a dataset on the given path. 5097093Sgjelinek */ 5107093Sgjelinek free(bnm); 5117093Sgjelinek free(dnm); 5127093Sgjelinek return (Z_ERR); 5137093Sgjelinek } 5141867Sgjelinek 5157093Sgjelinek res = snprintf(zfs_name, len, "%s/%s", zfs_get_name(zhp), bname); 5167093Sgjelinek 5177093Sgjelinek free(bnm); 5187093Sgjelinek free(dnm); 5191867Sgjelinek zfs_close(zhp); 5201867Sgjelinek if (res >= len) 5211867Sgjelinek return (Z_ERR); 5221867Sgjelinek 5231867Sgjelinek return (Z_OK); 5241867Sgjelinek } 5251867Sgjelinek 5261867Sgjelinek /* 5271867Sgjelinek * A ZFS file system iterator call-back function used to determine if the 5281867Sgjelinek * file system has dependents (snapshots & clones). 5291867Sgjelinek */ 5301867Sgjelinek /* ARGSUSED */ 5311867Sgjelinek static int 5321867Sgjelinek has_dependent(zfs_handle_t *zhp, void *data) 5331867Sgjelinek { 5341867Sgjelinek zfs_close(zhp); 5351867Sgjelinek return (1); 5361867Sgjelinek } 5371867Sgjelinek 5381867Sgjelinek /* 5391867Sgjelinek * Given a snapshot name, get the file system path where the snapshot lives. 5401867Sgjelinek * A snapshot name is of the form fs_name@snap_name. For example, snapshot 5411867Sgjelinek * pl/zones/z1@SUNWzone1 would have a path of 5421867Sgjelinek * /pl/zones/z1/.zfs/snapshot/SUNWzone1. 5431867Sgjelinek */ 5441867Sgjelinek static int 5451867Sgjelinek snap2path(char *snap_name, char *path, int len) 5461867Sgjelinek { 5471867Sgjelinek char *p; 5481867Sgjelinek zfs_handle_t *zhp; 5491867Sgjelinek char mp[ZFS_MAXPROPLEN]; 5501867Sgjelinek 5511867Sgjelinek if ((p = strrchr(snap_name, '@')) == NULL) 5521867Sgjelinek return (Z_ERR); 5531867Sgjelinek 5541867Sgjelinek /* Get the file system name from the snap_name. */ 5551867Sgjelinek *p = '\0'; 5565094Slling zhp = zfs_open(g_zfs, snap_name, ZFS_TYPE_DATASET); 5571867Sgjelinek *p = '@'; 5581867Sgjelinek if (zhp == NULL) 5591867Sgjelinek return (Z_ERR); 5601867Sgjelinek 5611867Sgjelinek /* Get the file system mount point. */ 5621867Sgjelinek if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mp, sizeof (mp), NULL, NULL, 5632082Seschrock 0, B_FALSE) != 0) { 5641867Sgjelinek zfs_close(zhp); 5651867Sgjelinek return (Z_ERR); 5661867Sgjelinek } 5671867Sgjelinek zfs_close(zhp); 5681867Sgjelinek 5691867Sgjelinek p++; 5701867Sgjelinek if (snprintf(path, len, "%s/.zfs/snapshot/%s", mp, p) >= len) 5711867Sgjelinek return (Z_ERR); 5721867Sgjelinek 5731867Sgjelinek return (Z_OK); 5741867Sgjelinek } 5751867Sgjelinek 5761867Sgjelinek /* 577*9386Sgerald.jelinek@sun.com * This callback function is used to iterate through a snapshot's dependencies 578*9386Sgerald.jelinek@sun.com * to find a filesystem that is a direct clone of the snapshot being iterated. 579*9386Sgerald.jelinek@sun.com */ 580*9386Sgerald.jelinek@sun.com static int 581*9386Sgerald.jelinek@sun.com get_direct_clone(zfs_handle_t *zhp, void *data) 582*9386Sgerald.jelinek@sun.com { 583*9386Sgerald.jelinek@sun.com clone_data_t *cd = data; 584*9386Sgerald.jelinek@sun.com char origin[ZFS_MAXNAMELEN]; 585*9386Sgerald.jelinek@sun.com char ds_path[ZFS_MAXNAMELEN]; 586*9386Sgerald.jelinek@sun.com 587*9386Sgerald.jelinek@sun.com if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) { 588*9386Sgerald.jelinek@sun.com zfs_close(zhp); 589*9386Sgerald.jelinek@sun.com return (0); 590*9386Sgerald.jelinek@sun.com } 591*9386Sgerald.jelinek@sun.com 592*9386Sgerald.jelinek@sun.com (void) strlcpy(ds_path, zfs_get_name(zhp), sizeof (ds_path)); 593*9386Sgerald.jelinek@sun.com 594*9386Sgerald.jelinek@sun.com /* Make sure this is a direct clone of the snapshot we're iterating. */ 595*9386Sgerald.jelinek@sun.com if (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, origin, sizeof (origin), NULL, 596*9386Sgerald.jelinek@sun.com NULL, 0, B_FALSE) != 0 || strcmp(origin, cd->snapshot) != 0) { 597*9386Sgerald.jelinek@sun.com zfs_close(zhp); 598*9386Sgerald.jelinek@sun.com return (0); 599*9386Sgerald.jelinek@sun.com } 600*9386Sgerald.jelinek@sun.com 601*9386Sgerald.jelinek@sun.com if (cd->clone_zhp != NULL) 602*9386Sgerald.jelinek@sun.com zfs_close(cd->clone_zhp); 603*9386Sgerald.jelinek@sun.com 604*9386Sgerald.jelinek@sun.com cd->clone_zhp = zhp; 605*9386Sgerald.jelinek@sun.com return (1); 606*9386Sgerald.jelinek@sun.com } 607*9386Sgerald.jelinek@sun.com 608*9386Sgerald.jelinek@sun.com /* 609*9386Sgerald.jelinek@sun.com * A ZFS file system iterator call-back function used to determine the clone 610*9386Sgerald.jelinek@sun.com * to promote. This function finds the youngest (i.e. last one taken) snapshot 611*9386Sgerald.jelinek@sun.com * that has a clone. If found, it returns a reference to that clone in the 612*9386Sgerald.jelinek@sun.com * callback data. 613*9386Sgerald.jelinek@sun.com */ 614*9386Sgerald.jelinek@sun.com static int 615*9386Sgerald.jelinek@sun.com find_clone(zfs_handle_t *zhp, void *data) 616*9386Sgerald.jelinek@sun.com { 617*9386Sgerald.jelinek@sun.com clone_data_t *cd = data; 618*9386Sgerald.jelinek@sun.com time_t snap_creation; 619*9386Sgerald.jelinek@sun.com int zret = 0; 620*9386Sgerald.jelinek@sun.com 621*9386Sgerald.jelinek@sun.com /* If snapshot has no clones, skip it */ 622*9386Sgerald.jelinek@sun.com if (zfs_prop_get_int(zhp, ZFS_PROP_NUMCLONES) == 0) { 623*9386Sgerald.jelinek@sun.com zfs_close(zhp); 624*9386Sgerald.jelinek@sun.com return (0); 625*9386Sgerald.jelinek@sun.com } 626*9386Sgerald.jelinek@sun.com 627*9386Sgerald.jelinek@sun.com cd->snapshot = zfs_get_name(zhp); 628*9386Sgerald.jelinek@sun.com 629*9386Sgerald.jelinek@sun.com /* Get the creation time of this snapshot */ 630*9386Sgerald.jelinek@sun.com snap_creation = (time_t)zfs_prop_get_int(zhp, ZFS_PROP_CREATION); 631*9386Sgerald.jelinek@sun.com 632*9386Sgerald.jelinek@sun.com /* 633*9386Sgerald.jelinek@sun.com * If this snapshot's creation time is greater than (i.e. younger than) 634*9386Sgerald.jelinek@sun.com * the current youngest snapshot found, iterate this snapshot to 635*9386Sgerald.jelinek@sun.com * get the right clone. 636*9386Sgerald.jelinek@sun.com */ 637*9386Sgerald.jelinek@sun.com if (snap_creation >= cd->origin_creation) { 638*9386Sgerald.jelinek@sun.com /* 639*9386Sgerald.jelinek@sun.com * Iterate the dependents of this snapshot to find a clone 640*9386Sgerald.jelinek@sun.com * that's a direct dependent. 641*9386Sgerald.jelinek@sun.com */ 642*9386Sgerald.jelinek@sun.com if ((zret = zfs_iter_dependents(zhp, B_FALSE, get_direct_clone, 643*9386Sgerald.jelinek@sun.com cd)) == -1) { 644*9386Sgerald.jelinek@sun.com zfs_close(zhp); 645*9386Sgerald.jelinek@sun.com return (1); 646*9386Sgerald.jelinek@sun.com } else if (zret == 1) { 647*9386Sgerald.jelinek@sun.com /* 648*9386Sgerald.jelinek@sun.com * Found a clone, update the origin_creation time 649*9386Sgerald.jelinek@sun.com * in the callback data. 650*9386Sgerald.jelinek@sun.com */ 651*9386Sgerald.jelinek@sun.com cd->origin_creation = snap_creation; 652*9386Sgerald.jelinek@sun.com } 653*9386Sgerald.jelinek@sun.com } 654*9386Sgerald.jelinek@sun.com 655*9386Sgerald.jelinek@sun.com zfs_close(zhp); 656*9386Sgerald.jelinek@sun.com return (0); 657*9386Sgerald.jelinek@sun.com } 658*9386Sgerald.jelinek@sun.com 659*9386Sgerald.jelinek@sun.com /* 660*9386Sgerald.jelinek@sun.com * A ZFS file system iterator call-back function used to remove standalone 661*9386Sgerald.jelinek@sun.com * snapshots. 662*9386Sgerald.jelinek@sun.com */ 663*9386Sgerald.jelinek@sun.com /* ARGSUSED */ 664*9386Sgerald.jelinek@sun.com static int 665*9386Sgerald.jelinek@sun.com rm_snap(zfs_handle_t *zhp, void *data) 666*9386Sgerald.jelinek@sun.com { 667*9386Sgerald.jelinek@sun.com /* If snapshot has clones, something is wrong */ 668*9386Sgerald.jelinek@sun.com if (zfs_prop_get_int(zhp, ZFS_PROP_NUMCLONES) != 0) { 669*9386Sgerald.jelinek@sun.com zfs_close(zhp); 670*9386Sgerald.jelinek@sun.com return (1); 671*9386Sgerald.jelinek@sun.com } 672*9386Sgerald.jelinek@sun.com 673*9386Sgerald.jelinek@sun.com if (zfs_unmount(zhp, NULL, 0) == 0) { 674*9386Sgerald.jelinek@sun.com (void) zfs_destroy(zhp); 675*9386Sgerald.jelinek@sun.com } 676*9386Sgerald.jelinek@sun.com 677*9386Sgerald.jelinek@sun.com zfs_close(zhp); 678*9386Sgerald.jelinek@sun.com return (0); 679*9386Sgerald.jelinek@sun.com } 680*9386Sgerald.jelinek@sun.com 681*9386Sgerald.jelinek@sun.com /* 682*9386Sgerald.jelinek@sun.com * A ZFS snapshot iterator call-back function which renames snapshots. 683*9386Sgerald.jelinek@sun.com */ 684*9386Sgerald.jelinek@sun.com static int 685*9386Sgerald.jelinek@sun.com rename_snap(zfs_handle_t *zhp, void *data) 686*9386Sgerald.jelinek@sun.com { 687*9386Sgerald.jelinek@sun.com int res; 688*9386Sgerald.jelinek@sun.com zfs_snapshot_data_t *cbp; 689*9386Sgerald.jelinek@sun.com char template[ZFS_MAXNAMELEN]; 690*9386Sgerald.jelinek@sun.com 691*9386Sgerald.jelinek@sun.com cbp = (zfs_snapshot_data_t *)data; 692*9386Sgerald.jelinek@sun.com 693*9386Sgerald.jelinek@sun.com /* 694*9386Sgerald.jelinek@sun.com * When renaming snapshots with the iterator, the iterator can see 695*9386Sgerald.jelinek@sun.com * the same snapshot after we've renamed up in the namespace. To 696*9386Sgerald.jelinek@sun.com * prevent this we check the count for the number of snapshots we have 697*9386Sgerald.jelinek@sun.com * to rename and stop at that point. 698*9386Sgerald.jelinek@sun.com */ 699*9386Sgerald.jelinek@sun.com if (cbp->cntr >= cbp->num) { 700*9386Sgerald.jelinek@sun.com zfs_close(zhp); 701*9386Sgerald.jelinek@sun.com return (0); 702*9386Sgerald.jelinek@sun.com } 703*9386Sgerald.jelinek@sun.com 704*9386Sgerald.jelinek@sun.com if (zfs_get_type(zhp) != ZFS_TYPE_SNAPSHOT) { 705*9386Sgerald.jelinek@sun.com zfs_close(zhp); 706*9386Sgerald.jelinek@sun.com return (0); 707*9386Sgerald.jelinek@sun.com } 708*9386Sgerald.jelinek@sun.com 709*9386Sgerald.jelinek@sun.com /* Only rename the snapshots we automatically generate when we clone. */ 710*9386Sgerald.jelinek@sun.com if (strncmp(zfs_get_name(zhp), cbp->match_name, cbp->len) != 0) { 711*9386Sgerald.jelinek@sun.com zfs_close(zhp); 712*9386Sgerald.jelinek@sun.com return (0); 713*9386Sgerald.jelinek@sun.com } 714*9386Sgerald.jelinek@sun.com 715*9386Sgerald.jelinek@sun.com (void) snprintf(template, sizeof (template), "%s%d", cbp->match_name, 716*9386Sgerald.jelinek@sun.com cbp->max++); 717*9386Sgerald.jelinek@sun.com 718*9386Sgerald.jelinek@sun.com res = (zfs_rename(zhp, template, B_FALSE) != 0); 719*9386Sgerald.jelinek@sun.com if (res != 0) 720*9386Sgerald.jelinek@sun.com (void) fprintf(stderr, gettext("failed to rename snapshot %s " 721*9386Sgerald.jelinek@sun.com "to %s: %s\n"), zfs_get_name(zhp), template, 722*9386Sgerald.jelinek@sun.com libzfs_error_description(g_zfs)); 723*9386Sgerald.jelinek@sun.com 724*9386Sgerald.jelinek@sun.com cbp->cntr++; 725*9386Sgerald.jelinek@sun.com 726*9386Sgerald.jelinek@sun.com zfs_close(zhp); 727*9386Sgerald.jelinek@sun.com return (res); 728*9386Sgerald.jelinek@sun.com } 729*9386Sgerald.jelinek@sun.com 730*9386Sgerald.jelinek@sun.com /* 731*9386Sgerald.jelinek@sun.com * Rename the source dataset's snapshots that are automatically generated when 732*9386Sgerald.jelinek@sun.com * we clone a zone so that there won't be a name collision when we promote the 733*9386Sgerald.jelinek@sun.com * cloned dataset. Once the snapshots have been renamed, then promote the 734*9386Sgerald.jelinek@sun.com * clone. 735*9386Sgerald.jelinek@sun.com * 736*9386Sgerald.jelinek@sun.com * The snapshot rename process gets the highest number on the snapshot names 737*9386Sgerald.jelinek@sun.com * (the format is zonename@SUNWzoneXX where XX are digits) on both the source 738*9386Sgerald.jelinek@sun.com * and clone datasets, then renames the source dataset snapshots starting at 739*9386Sgerald.jelinek@sun.com * the next number. 740*9386Sgerald.jelinek@sun.com */ 741*9386Sgerald.jelinek@sun.com static int 742*9386Sgerald.jelinek@sun.com promote_clone(zfs_handle_t *src_zhp, zfs_handle_t *cln_zhp) 743*9386Sgerald.jelinek@sun.com { 744*9386Sgerald.jelinek@sun.com zfs_snapshot_data_t sd; 745*9386Sgerald.jelinek@sun.com char nm[ZFS_MAXNAMELEN]; 746*9386Sgerald.jelinek@sun.com char template[ZFS_MAXNAMELEN]; 747*9386Sgerald.jelinek@sun.com 748*9386Sgerald.jelinek@sun.com (void) strlcpy(nm, zfs_get_name(cln_zhp), sizeof (nm)); 749*9386Sgerald.jelinek@sun.com /* 750*9386Sgerald.jelinek@sun.com * Start by getting the clone's snapshot max which we use 751*9386Sgerald.jelinek@sun.com * during the rename of the original dataset's snapshots. 752*9386Sgerald.jelinek@sun.com */ 753*9386Sgerald.jelinek@sun.com (void) snprintf(template, sizeof (template), "%s@SUNWzone", nm); 754*9386Sgerald.jelinek@sun.com sd.match_name = template; 755*9386Sgerald.jelinek@sun.com sd.len = strlen(template); 756*9386Sgerald.jelinek@sun.com sd.max = 0; 757*9386Sgerald.jelinek@sun.com 758*9386Sgerald.jelinek@sun.com if (zfs_iter_snapshots(cln_zhp, get_snap_max, &sd) != 0) 759*9386Sgerald.jelinek@sun.com return (Z_ERR); 760*9386Sgerald.jelinek@sun.com 761*9386Sgerald.jelinek@sun.com /* 762*9386Sgerald.jelinek@sun.com * Now make sure the source's snapshot max is at least as high as 763*9386Sgerald.jelinek@sun.com * the clone's snapshot max. 764*9386Sgerald.jelinek@sun.com */ 765*9386Sgerald.jelinek@sun.com (void) snprintf(template, sizeof (template), "%s@SUNWzone", 766*9386Sgerald.jelinek@sun.com zfs_get_name(src_zhp)); 767*9386Sgerald.jelinek@sun.com sd.match_name = template; 768*9386Sgerald.jelinek@sun.com sd.len = strlen(template); 769*9386Sgerald.jelinek@sun.com sd.num = 0; 770*9386Sgerald.jelinek@sun.com 771*9386Sgerald.jelinek@sun.com if (zfs_iter_snapshots(src_zhp, get_snap_max, &sd) != 0) 772*9386Sgerald.jelinek@sun.com return (Z_ERR); 773*9386Sgerald.jelinek@sun.com 774*9386Sgerald.jelinek@sun.com /* 775*9386Sgerald.jelinek@sun.com * Now rename the source dataset's snapshots so there's no 776*9386Sgerald.jelinek@sun.com * conflict when we promote the clone. 777*9386Sgerald.jelinek@sun.com */ 778*9386Sgerald.jelinek@sun.com sd.max++; 779*9386Sgerald.jelinek@sun.com sd.cntr = 0; 780*9386Sgerald.jelinek@sun.com if (zfs_iter_snapshots(src_zhp, rename_snap, &sd) != 0) 781*9386Sgerald.jelinek@sun.com return (Z_ERR); 782*9386Sgerald.jelinek@sun.com 783*9386Sgerald.jelinek@sun.com /* close and reopen the clone dataset to get the latest info */ 784*9386Sgerald.jelinek@sun.com zfs_close(cln_zhp); 785*9386Sgerald.jelinek@sun.com if ((cln_zhp = zfs_open(g_zfs, nm, ZFS_TYPE_FILESYSTEM)) == NULL) 786*9386Sgerald.jelinek@sun.com return (Z_ERR); 787*9386Sgerald.jelinek@sun.com 788*9386Sgerald.jelinek@sun.com if (zfs_promote(cln_zhp) != 0) { 789*9386Sgerald.jelinek@sun.com (void) fprintf(stderr, gettext("failed to promote %s: %s\n"), 790*9386Sgerald.jelinek@sun.com nm, libzfs_error_description(g_zfs)); 791*9386Sgerald.jelinek@sun.com return (Z_ERR); 792*9386Sgerald.jelinek@sun.com } 793*9386Sgerald.jelinek@sun.com 794*9386Sgerald.jelinek@sun.com zfs_close(cln_zhp); 795*9386Sgerald.jelinek@sun.com return (Z_OK); 796*9386Sgerald.jelinek@sun.com } 797*9386Sgerald.jelinek@sun.com 798*9386Sgerald.jelinek@sun.com /* 799*9386Sgerald.jelinek@sun.com * Promote the youngest clone. That clone will then become the origin of all 800*9386Sgerald.jelinek@sun.com * of the other clones that were hanging off of the source dataset. 801*9386Sgerald.jelinek@sun.com */ 802*9386Sgerald.jelinek@sun.com int 803*9386Sgerald.jelinek@sun.com promote_all_clones(zfs_handle_t *zhp) 804*9386Sgerald.jelinek@sun.com { 805*9386Sgerald.jelinek@sun.com clone_data_t cd; 806*9386Sgerald.jelinek@sun.com char nm[ZFS_MAXNAMELEN]; 807*9386Sgerald.jelinek@sun.com 808*9386Sgerald.jelinek@sun.com cd.clone_zhp = NULL; 809*9386Sgerald.jelinek@sun.com cd.origin_creation = 0; 810*9386Sgerald.jelinek@sun.com cd.snapshot = NULL; 811*9386Sgerald.jelinek@sun.com 812*9386Sgerald.jelinek@sun.com if (zfs_iter_snapshots(zhp, find_clone, &cd) != 0) { 813*9386Sgerald.jelinek@sun.com zfs_close(zhp); 814*9386Sgerald.jelinek@sun.com return (Z_ERR); 815*9386Sgerald.jelinek@sun.com } 816*9386Sgerald.jelinek@sun.com 817*9386Sgerald.jelinek@sun.com /* Nothing to promote. */ 818*9386Sgerald.jelinek@sun.com if (cd.clone_zhp == NULL) 819*9386Sgerald.jelinek@sun.com return (Z_OK); 820*9386Sgerald.jelinek@sun.com 821*9386Sgerald.jelinek@sun.com /* Found the youngest clone to promote. Promote it. */ 822*9386Sgerald.jelinek@sun.com if (promote_clone(zhp, cd.clone_zhp) != 0) { 823*9386Sgerald.jelinek@sun.com zfs_close(cd.clone_zhp); 824*9386Sgerald.jelinek@sun.com zfs_close(zhp); 825*9386Sgerald.jelinek@sun.com return (Z_ERR); 826*9386Sgerald.jelinek@sun.com } 827*9386Sgerald.jelinek@sun.com 828*9386Sgerald.jelinek@sun.com /* close and reopen the main dataset to get the latest info */ 829*9386Sgerald.jelinek@sun.com (void) strlcpy(nm, zfs_get_name(zhp), sizeof (nm)); 830*9386Sgerald.jelinek@sun.com zfs_close(zhp); 831*9386Sgerald.jelinek@sun.com if ((zhp = zfs_open(g_zfs, nm, ZFS_TYPE_FILESYSTEM)) == NULL) 832*9386Sgerald.jelinek@sun.com return (Z_ERR); 833*9386Sgerald.jelinek@sun.com 834*9386Sgerald.jelinek@sun.com return (Z_OK); 835*9386Sgerald.jelinek@sun.com } 836*9386Sgerald.jelinek@sun.com 837*9386Sgerald.jelinek@sun.com /* 8381867Sgjelinek * Clone a pre-existing ZFS snapshot, either by making a direct ZFS clone, if 8391867Sgjelinek * possible, or by copying the data from the snapshot to the zonepath. 8401867Sgjelinek */ 8411867Sgjelinek int 8427089Sgjelinek clone_snapshot_zfs(char *snap_name, char *zonepath, char *validatesnap) 8431867Sgjelinek { 8441867Sgjelinek int err = Z_OK; 8451867Sgjelinek char clone_name[MAXPATHLEN]; 8461867Sgjelinek char snap_path[MAXPATHLEN]; 8471867Sgjelinek 8481867Sgjelinek if (snap2path(snap_name, snap_path, sizeof (snap_path)) != Z_OK) { 8491867Sgjelinek (void) fprintf(stderr, gettext("unable to find path for %s.\n"), 8501867Sgjelinek snap_name); 8511867Sgjelinek return (Z_ERR); 8521867Sgjelinek } 8531867Sgjelinek 8547089Sgjelinek if (validate_snapshot(snap_name, snap_path, validatesnap) != Z_OK) 8551867Sgjelinek return (Z_NO_ENTRY); 8561867Sgjelinek 8571867Sgjelinek /* 8581867Sgjelinek * The zonepath cannot be ZFS cloned, try to copy the data from 8591867Sgjelinek * within the snapshot to the zonepath. 8601867Sgjelinek */ 8611867Sgjelinek if (path2name(zonepath, clone_name, sizeof (clone_name)) != Z_OK) { 8621867Sgjelinek if ((err = clone_copy(snap_path, zonepath)) == Z_OK) 8631867Sgjelinek if (clean_out_clone() != Z_OK) 8641867Sgjelinek (void) fprintf(stderr, 8651867Sgjelinek gettext("could not remove the " 8661867Sgjelinek "software inventory from %s\n"), zonepath); 8671867Sgjelinek 8681867Sgjelinek return (err); 8691867Sgjelinek } 8701867Sgjelinek 8711867Sgjelinek if ((err = clone_snap(snap_name, clone_name)) != Z_OK) { 8721867Sgjelinek if (err != Z_NO_ENTRY) { 8731867Sgjelinek /* 8741867Sgjelinek * Cloning the snapshot failed. Fall back to trying 8751867Sgjelinek * to install the zone by copying from the snapshot. 8761867Sgjelinek */ 8771867Sgjelinek if ((err = clone_copy(snap_path, zonepath)) == Z_OK) 8781867Sgjelinek if (clean_out_clone() != Z_OK) 8791867Sgjelinek (void) fprintf(stderr, 8801867Sgjelinek gettext("could not remove the " 8811867Sgjelinek "software inventory from %s\n"), 8821867Sgjelinek zonepath); 8831867Sgjelinek } else { 8841867Sgjelinek /* 8851867Sgjelinek * The snapshot is unusable for some reason so restore 8861867Sgjelinek * the zone state to configured since we were unable to 8871867Sgjelinek * actually do anything about getting the zone 8881867Sgjelinek * installed. 8891867Sgjelinek */ 8901867Sgjelinek int tmp; 8911867Sgjelinek 8921867Sgjelinek if ((tmp = zone_set_state(target_zone, 8931867Sgjelinek ZONE_STATE_CONFIGURED)) != Z_OK) { 8941867Sgjelinek errno = tmp; 8951867Sgjelinek zperror2(target_zone, 8961867Sgjelinek gettext("could not set state")); 8971867Sgjelinek } 8981867Sgjelinek } 8991867Sgjelinek } 9001867Sgjelinek 9011867Sgjelinek return (err); 9021867Sgjelinek } 9031867Sgjelinek 9041867Sgjelinek /* 9051867Sgjelinek * Attempt to clone a source_zone to a target zonepath by using a ZFS clone. 9061867Sgjelinek */ 9071867Sgjelinek int 9087089Sgjelinek clone_zfs(char *source_zonepath, char *zonepath, char *presnapbuf, 9097089Sgjelinek char *postsnapbuf) 9101867Sgjelinek { 9111867Sgjelinek zfs_handle_t *zhp; 9121867Sgjelinek char clone_name[MAXPATHLEN]; 9131867Sgjelinek char snap_name[MAXPATHLEN]; 9141867Sgjelinek 9151867Sgjelinek /* 9161867Sgjelinek * Try to get a zfs handle for the source_zonepath. If this fails 9171867Sgjelinek * the source_zonepath is not ZFS so return an error. 9181867Sgjelinek */ 9191867Sgjelinek if ((zhp = mount2zhandle(source_zonepath)) == NULL) 9201867Sgjelinek return (Z_ERR); 9211867Sgjelinek 9221867Sgjelinek /* 9231867Sgjelinek * Check if there is a file system already mounted on zonepath. If so, 9241867Sgjelinek * we can't clone to the path so we should fall back to copying. 9251867Sgjelinek */ 9261867Sgjelinek if (is_mountpnt(zonepath)) { 9271867Sgjelinek zfs_close(zhp); 9281867Sgjelinek (void) fprintf(stderr, 9291867Sgjelinek gettext("A file system is already mounted on %s,\n" 9301867Sgjelinek "preventing use of a ZFS clone.\n"), zonepath); 9311867Sgjelinek return (Z_ERR); 9321867Sgjelinek } 9331867Sgjelinek 9341867Sgjelinek /* 9351867Sgjelinek * Instead of using path2name to get the clone name from the zonepath, 9361867Sgjelinek * we could generate a name from the source zone ZFS name. However, 9371867Sgjelinek * this would mean we would create the clone under the ZFS fs of the 9381867Sgjelinek * source instead of what the zonepath says. For example, 9391867Sgjelinek * 9401867Sgjelinek * source_zonepath zonepath 9411867Sgjelinek * /pl/zones/dev/z1 /pl/zones/deploy/z2 9421867Sgjelinek * 9431867Sgjelinek * We don't want the clone to be under "dev", we want it under 9441867Sgjelinek * "deploy", so that we can leverage the normal attribute inheritance 9451867Sgjelinek * that ZFS provides in the fs hierarchy. 9461867Sgjelinek */ 9471867Sgjelinek if (path2name(zonepath, clone_name, sizeof (clone_name)) != Z_OK) { 9481867Sgjelinek zfs_close(zhp); 9491867Sgjelinek return (Z_ERR); 9501867Sgjelinek } 9511867Sgjelinek 9527089Sgjelinek if (take_snapshot(zhp, snap_name, sizeof (snap_name), presnapbuf, 9537089Sgjelinek postsnapbuf) != Z_OK) { 9541867Sgjelinek zfs_close(zhp); 9551867Sgjelinek return (Z_ERR); 9561867Sgjelinek } 9571867Sgjelinek zfs_close(zhp); 9581867Sgjelinek 9593686Sgjelinek if (clone_snap(snap_name, clone_name) != Z_OK) { 9603686Sgjelinek /* Clean up the snapshot we just took. */ 9613686Sgjelinek if ((zhp = zfs_open(g_zfs, snap_name, ZFS_TYPE_SNAPSHOT)) 9623686Sgjelinek != NULL) { 9633686Sgjelinek if (zfs_unmount(zhp, NULL, 0) == 0) 9643686Sgjelinek (void) zfs_destroy(zhp); 9653686Sgjelinek zfs_close(zhp); 9663686Sgjelinek } 9673686Sgjelinek 9681867Sgjelinek return (Z_ERR); 9693686Sgjelinek } 9701867Sgjelinek 9711867Sgjelinek (void) printf(gettext("Instead of copying, a ZFS clone has been " 9721867Sgjelinek "created for this zone.\n")); 9731867Sgjelinek 9741867Sgjelinek return (Z_OK); 9751867Sgjelinek } 9761867Sgjelinek 9771867Sgjelinek /* 9781867Sgjelinek * Attempt to create a ZFS file system for the specified zonepath. 9791867Sgjelinek * We either will successfully create a ZFS file system and get it mounted 9801867Sgjelinek * on the zonepath or we don't. The caller doesn't care since a regular 9811867Sgjelinek * directory is used for the zonepath if no ZFS file system is mounted there. 9821867Sgjelinek */ 9831867Sgjelinek void 9841867Sgjelinek create_zfs_zonepath(char *zonepath) 9851867Sgjelinek { 9861867Sgjelinek zfs_handle_t *zhp; 9871867Sgjelinek char zfs_name[MAXPATHLEN]; 9882676Seschrock nvlist_t *props = NULL; 9891867Sgjelinek 9901867Sgjelinek if (path2name(zonepath, zfs_name, sizeof (zfs_name)) != Z_OK) 9911867Sgjelinek return; 9921867Sgjelinek 9939023Sgerald.jelinek@sun.com /* Check if the dataset already exists. */ 9949023Sgerald.jelinek@sun.com if ((zhp = zfs_open(g_zfs, zfs_name, ZFS_TYPE_DATASET)) != NULL) { 9959023Sgerald.jelinek@sun.com zfs_close(zhp); 9969023Sgerald.jelinek@sun.com return; 9979023Sgerald.jelinek@sun.com } 9989023Sgerald.jelinek@sun.com 9992676Seschrock if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0 || 10002744Snn35248 nvlist_add_string(props, zfs_prop_to_name(ZFS_PROP_SHARENFS), 10012744Snn35248 "off") != 0) { 10022744Snn35248 if (props != NULL) 10032744Snn35248 nvlist_free(props); 10042676Seschrock (void) fprintf(stderr, gettext("cannot create ZFS dataset %s: " 10052676Seschrock "out of memory\n"), zfs_name); 10062676Seschrock } 10072676Seschrock 10082676Seschrock if (zfs_create(g_zfs, zfs_name, ZFS_TYPE_FILESYSTEM, props) != 0 || 10095094Slling (zhp = zfs_open(g_zfs, zfs_name, ZFS_TYPE_DATASET)) == NULL) { 10102082Seschrock (void) fprintf(stderr, gettext("cannot create ZFS dataset %s: " 10112082Seschrock "%s\n"), zfs_name, libzfs_error_description(g_zfs)); 10122676Seschrock nvlist_free(props); 10131867Sgjelinek return; 10141867Sgjelinek } 10151867Sgjelinek 10162676Seschrock nvlist_free(props); 10172676Seschrock 10181867Sgjelinek if (zfs_mount(zhp, NULL, 0) != 0) { 10192082Seschrock (void) fprintf(stderr, gettext("cannot mount ZFS dataset %s: " 10202082Seschrock "%s\n"), zfs_name, libzfs_error_description(g_zfs)); 10211867Sgjelinek (void) zfs_destroy(zhp); 10221867Sgjelinek } else { 10231867Sgjelinek if (chmod(zonepath, S_IRWXU) != 0) { 10241867Sgjelinek (void) fprintf(stderr, gettext("file system %s " 10251867Sgjelinek "successfully created, but chmod %o failed: %s\n"), 10261867Sgjelinek zfs_name, S_IRWXU, strerror(errno)); 10271867Sgjelinek (void) destroy_zfs(zonepath); 10281867Sgjelinek } else { 10291867Sgjelinek (void) printf(gettext("A ZFS file system has been " 10301867Sgjelinek "created for this zone.\n")); 10311867Sgjelinek } 10321867Sgjelinek } 10331867Sgjelinek 10341867Sgjelinek zfs_close(zhp); 10351867Sgjelinek } 10361867Sgjelinek 10371867Sgjelinek /* 10381867Sgjelinek * If the zonepath is a ZFS file system, attempt to destroy it. We return Z_OK 10391867Sgjelinek * if we were able to zfs_destroy the zonepath, otherwise we return Z_ERR 10401867Sgjelinek * which means the caller should clean up the zonepath in the traditional 10411867Sgjelinek * way. 10421867Sgjelinek */ 10431867Sgjelinek int 10441867Sgjelinek destroy_zfs(char *zonepath) 10451867Sgjelinek { 10461867Sgjelinek zfs_handle_t *zhp; 10471867Sgjelinek boolean_t is_clone = B_FALSE; 10481867Sgjelinek char origin[ZFS_MAXPROPLEN]; 10491867Sgjelinek 10502082Seschrock if ((zhp = mount2zhandle(zonepath)) == NULL) 10511867Sgjelinek return (Z_ERR); 10521867Sgjelinek 1053*9386Sgerald.jelinek@sun.com if (promote_all_clones(zhp) != 0) 1054*9386Sgerald.jelinek@sun.com return (Z_ERR); 1055*9386Sgerald.jelinek@sun.com 1056*9386Sgerald.jelinek@sun.com /* Now cleanup any snapshots remaining. */ 1057*9386Sgerald.jelinek@sun.com if (zfs_iter_snapshots(zhp, rm_snap, NULL) != 0) { 1058*9386Sgerald.jelinek@sun.com zfs_close(zhp); 1059*9386Sgerald.jelinek@sun.com return (Z_ERR); 1060*9386Sgerald.jelinek@sun.com } 1061*9386Sgerald.jelinek@sun.com 10621867Sgjelinek /* 1063*9386Sgerald.jelinek@sun.com * We can't destroy the file system if it has still has dependents. 1064*9386Sgerald.jelinek@sun.com * There shouldn't be any at this point, but we'll double check. 10651867Sgjelinek */ 1066*9386Sgerald.jelinek@sun.com if (zfs_iter_dependents(zhp, B_TRUE, has_dependent, NULL) != 0) { 1067*9386Sgerald.jelinek@sun.com (void) fprintf(stderr, gettext("zfs destroy %s failed: the " 1068*9386Sgerald.jelinek@sun.com "dataset still has dependents\n"), zfs_get_name(zhp)); 10691867Sgjelinek zfs_close(zhp); 10701867Sgjelinek return (Z_ERR); 10711867Sgjelinek } 10721867Sgjelinek 10731867Sgjelinek /* 10741867Sgjelinek * This might be a clone. Try to get the snapshot so we can attempt 10751867Sgjelinek * to destroy that as well. 10761867Sgjelinek */ 10771867Sgjelinek if (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, origin, sizeof (origin), NULL, 10782082Seschrock NULL, 0, B_FALSE) == 0) 10791867Sgjelinek is_clone = B_TRUE; 10801867Sgjelinek 1081*9386Sgerald.jelinek@sun.com if (zfs_unmount(zhp, NULL, 0) != 0) { 1082*9386Sgerald.jelinek@sun.com (void) fprintf(stderr, gettext("zfs unmount %s failed: %s\n"), 1083*9386Sgerald.jelinek@sun.com zfs_get_name(zhp), libzfs_error_description(g_zfs)); 1084*9386Sgerald.jelinek@sun.com zfs_close(zhp); 1085*9386Sgerald.jelinek@sun.com return (Z_ERR); 1086*9386Sgerald.jelinek@sun.com } 1087*9386Sgerald.jelinek@sun.com 10881867Sgjelinek if (zfs_destroy(zhp) != 0) { 10891867Sgjelinek /* 10901867Sgjelinek * If the destroy fails for some reason, try to remount 10911867Sgjelinek * the file system so that we can use "rm -rf" to clean up 10921867Sgjelinek * instead. 10931867Sgjelinek */ 1094*9386Sgerald.jelinek@sun.com (void) fprintf(stderr, gettext("zfs destroy %s failed: %s\n"), 1095*9386Sgerald.jelinek@sun.com zfs_get_name(zhp), libzfs_error_description(g_zfs)); 10961867Sgjelinek (void) zfs_mount(zhp, NULL, 0); 10971867Sgjelinek zfs_close(zhp); 10981867Sgjelinek return (Z_ERR); 10991867Sgjelinek } 11001867Sgjelinek 11013686Sgjelinek /* 11023686Sgjelinek * If the zone has ever been moved then the mountpoint dir will not be 11033686Sgjelinek * cleaned up by the zfs_destroy(). To handle this case try to clean 11043686Sgjelinek * it up now but don't worry if it fails, that will be normal. 11053686Sgjelinek */ 11063686Sgjelinek (void) rmdir(zonepath); 11073686Sgjelinek 11081867Sgjelinek (void) printf(gettext("The ZFS file system for this zone has been " 11091867Sgjelinek "destroyed.\n")); 11101867Sgjelinek 11111867Sgjelinek if (is_clone) { 11121867Sgjelinek zfs_handle_t *ohp; 11131867Sgjelinek 11141867Sgjelinek /* 11151867Sgjelinek * Try to clean up the snapshot that the clone was taken from. 11161867Sgjelinek */ 11172082Seschrock if ((ohp = zfs_open(g_zfs, origin, 11182082Seschrock ZFS_TYPE_SNAPSHOT)) != NULL) { 11192474Seschrock if (zfs_iter_dependents(ohp, B_TRUE, has_dependent, 11202474Seschrock NULL) == 0 && zfs_unmount(ohp, NULL, 0) == 0) 11211867Sgjelinek (void) zfs_destroy(ohp); 11221867Sgjelinek zfs_close(ohp); 11231867Sgjelinek } 11241867Sgjelinek } 11251867Sgjelinek 11261867Sgjelinek zfs_close(zhp); 11271867Sgjelinek return (Z_OK); 11281867Sgjelinek } 11291867Sgjelinek 11301867Sgjelinek /* 11311867Sgjelinek * Return true if the path is its own zfs file system. We determine this 11321867Sgjelinek * by stat-ing the path to see if it is zfs and stat-ing the parent to see 11331867Sgjelinek * if it is a different fs. 11341867Sgjelinek */ 11351867Sgjelinek boolean_t 11361867Sgjelinek is_zonepath_zfs(char *zonepath) 11371867Sgjelinek { 11381867Sgjelinek int res; 11391867Sgjelinek char *path; 11401867Sgjelinek char *parent; 11412267Sdp struct statvfs64 buf1, buf2; 11421867Sgjelinek 11432267Sdp if (statvfs64(zonepath, &buf1) != 0) 11441867Sgjelinek return (B_FALSE); 11451867Sgjelinek 11461867Sgjelinek if (strcmp(buf1.f_basetype, "zfs") != 0) 11471867Sgjelinek return (B_FALSE); 11481867Sgjelinek 11491867Sgjelinek if ((path = strdup(zonepath)) == NULL) 11501867Sgjelinek return (B_FALSE); 11511867Sgjelinek 11521867Sgjelinek parent = dirname(path); 11532267Sdp res = statvfs64(parent, &buf2); 11541867Sgjelinek free(path); 11551867Sgjelinek 11561867Sgjelinek if (res != 0) 11571867Sgjelinek return (B_FALSE); 11581867Sgjelinek 11591867Sgjelinek if (buf1.f_fsid == buf2.f_fsid) 11601867Sgjelinek return (B_FALSE); 11611867Sgjelinek 11621867Sgjelinek return (B_TRUE); 11631867Sgjelinek } 11641867Sgjelinek 11651867Sgjelinek /* 11661867Sgjelinek * Implement the fast move of a ZFS file system by simply updating the 11671867Sgjelinek * mountpoint. Since it is file system already, we don't have the 11681867Sgjelinek * issue of cross-file system copying. 11691867Sgjelinek */ 11701867Sgjelinek int 11711867Sgjelinek move_zfs(char *zonepath, char *new_zonepath) 11721867Sgjelinek { 11731867Sgjelinek int ret = Z_ERR; 11741867Sgjelinek zfs_handle_t *zhp; 11751867Sgjelinek 11762082Seschrock if ((zhp = mount2zhandle(zonepath)) == NULL) 11771867Sgjelinek return (Z_ERR); 11781867Sgjelinek 11792676Seschrock if (zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_MOUNTPOINT), 11802676Seschrock new_zonepath) == 0) { 11811867Sgjelinek /* 11821867Sgjelinek * Clean up the old mount point. We ignore any failure since 11831867Sgjelinek * the zone is already successfully mounted on the new path. 11841867Sgjelinek */ 11851867Sgjelinek (void) rmdir(zonepath); 11861867Sgjelinek ret = Z_OK; 11871867Sgjelinek } 11881867Sgjelinek 11891867Sgjelinek zfs_close(zhp); 11901867Sgjelinek 11911867Sgjelinek return (ret); 11921867Sgjelinek } 11931867Sgjelinek 11941867Sgjelinek /* 11951867Sgjelinek * Validate that the given dataset exists on the system, and that neither it nor 11961867Sgjelinek * its children are zvols. 11971867Sgjelinek * 11981867Sgjelinek * Note that we don't do anything with the 'zoned' property here. All 11991867Sgjelinek * management is done in zoneadmd when the zone is actually rebooted. This 12001867Sgjelinek * allows us to automatically set the zoned property even when a zone is 12011867Sgjelinek * rebooted by the administrator. 12021867Sgjelinek */ 12031867Sgjelinek int 12041867Sgjelinek verify_datasets(zone_dochandle_t handle) 12051867Sgjelinek { 12061867Sgjelinek int return_code = Z_OK; 12071867Sgjelinek struct zone_dstab dstab; 12081867Sgjelinek zfs_handle_t *zhp; 12091867Sgjelinek char propbuf[ZFS_MAXPROPLEN]; 12101867Sgjelinek char source[ZFS_MAXNAMELEN]; 12115094Slling zprop_source_t srctype; 12121867Sgjelinek 12131867Sgjelinek if (zonecfg_setdsent(handle) != Z_OK) { 12141867Sgjelinek /* 12151867Sgjelinek * TRANSLATION_NOTE 12161867Sgjelinek * zfs and dataset are literals that should not be translated. 12171867Sgjelinek */ 12181867Sgjelinek (void) fprintf(stderr, gettext("could not verify zfs datasets: " 12191867Sgjelinek "unable to enumerate datasets\n")); 12201867Sgjelinek return (Z_ERR); 12211867Sgjelinek } 12221867Sgjelinek 12231867Sgjelinek while (zonecfg_getdsent(handle, &dstab) == Z_OK) { 12241867Sgjelinek 12252082Seschrock if ((zhp = zfs_open(g_zfs, dstab.zone_dataset_name, 12261867Sgjelinek ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME)) == NULL) { 12272082Seschrock (void) fprintf(stderr, gettext("could not verify zfs " 12282082Seschrock "dataset %s: %s\n"), dstab.zone_dataset_name, 12292082Seschrock libzfs_error_description(g_zfs)); 12301867Sgjelinek return_code = Z_ERR; 12311867Sgjelinek continue; 12321867Sgjelinek } 12331867Sgjelinek 12341867Sgjelinek if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, propbuf, 12351867Sgjelinek sizeof (propbuf), &srctype, source, 12361867Sgjelinek sizeof (source), 0) == 0 && 12375094Slling (srctype == ZPROP_SRC_INHERITED)) { 12381867Sgjelinek (void) fprintf(stderr, gettext("could not verify zfs " 12391867Sgjelinek "dataset %s: mountpoint cannot be inherited\n"), 12401867Sgjelinek dstab.zone_dataset_name); 12411867Sgjelinek return_code = Z_ERR; 12421867Sgjelinek zfs_close(zhp); 12431867Sgjelinek continue; 12441867Sgjelinek } 12451867Sgjelinek 12461867Sgjelinek if (zfs_get_type(zhp) == ZFS_TYPE_VOLUME) { 12471867Sgjelinek (void) fprintf(stderr, gettext("cannot verify zfs " 12481867Sgjelinek "dataset %s: volumes cannot be specified as a " 12491867Sgjelinek "zone dataset resource\n"), 12501867Sgjelinek dstab.zone_dataset_name); 12511867Sgjelinek return_code = Z_ERR; 12521867Sgjelinek } 12531867Sgjelinek 12541867Sgjelinek if (zfs_iter_children(zhp, check_zvol, NULL) != 0) 12551867Sgjelinek return_code = Z_ERR; 12561867Sgjelinek 12571867Sgjelinek zfs_close(zhp); 12581867Sgjelinek } 12591867Sgjelinek (void) zonecfg_enddsent(handle); 12601867Sgjelinek 12611867Sgjelinek return (return_code); 12621867Sgjelinek } 12631867Sgjelinek 12641867Sgjelinek /* 12651867Sgjelinek * Verify that the ZFS dataset exists, and its mountpoint 12661867Sgjelinek * property is set to "legacy". 12671867Sgjelinek */ 12681867Sgjelinek int 12691867Sgjelinek verify_fs_zfs(struct zone_fstab *fstab) 12701867Sgjelinek { 12711867Sgjelinek zfs_handle_t *zhp; 12721867Sgjelinek char propbuf[ZFS_MAXPROPLEN]; 12731867Sgjelinek 12742082Seschrock if ((zhp = zfs_open(g_zfs, fstab->zone_fs_special, 12755094Slling ZFS_TYPE_DATASET)) == NULL) { 12761867Sgjelinek (void) fprintf(stderr, gettext("could not verify fs %s: " 12771867Sgjelinek "could not access zfs dataset '%s'\n"), 12781867Sgjelinek fstab->zone_fs_dir, fstab->zone_fs_special); 12791867Sgjelinek return (Z_ERR); 12801867Sgjelinek } 12811867Sgjelinek 12821867Sgjelinek if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) { 12831867Sgjelinek (void) fprintf(stderr, gettext("cannot verify fs %s: " 12841867Sgjelinek "'%s' is not a file system\n"), 12851867Sgjelinek fstab->zone_fs_dir, fstab->zone_fs_special); 12861867Sgjelinek zfs_close(zhp); 12871867Sgjelinek return (Z_ERR); 12881867Sgjelinek } 12891867Sgjelinek 12901867Sgjelinek if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, propbuf, sizeof (propbuf), 12911867Sgjelinek NULL, NULL, 0, 0) != 0 || strcmp(propbuf, "legacy") != 0) { 12921867Sgjelinek (void) fprintf(stderr, gettext("could not verify fs %s: " 12931867Sgjelinek "zfs '%s' mountpoint is not \"legacy\"\n"), 12941867Sgjelinek fstab->zone_fs_dir, fstab->zone_fs_special); 12951867Sgjelinek zfs_close(zhp); 12961867Sgjelinek return (Z_ERR); 12971867Sgjelinek } 12981867Sgjelinek 12991867Sgjelinek zfs_close(zhp); 13001867Sgjelinek return (Z_OK); 13011867Sgjelinek } 13022082Seschrock 13032082Seschrock int 13042082Seschrock init_zfs(void) 13052082Seschrock { 13062082Seschrock if ((g_zfs = libzfs_init()) == NULL) { 13072082Seschrock (void) fprintf(stderr, gettext("failed to initialize ZFS " 13082082Seschrock "library\n")); 13092082Seschrock return (Z_ERR); 13102082Seschrock } 13112082Seschrock 13122082Seschrock return (Z_OK); 13132082Seschrock } 1314