1*1867Sgjelinek /* 2*1867Sgjelinek * CDDL HEADER START 3*1867Sgjelinek * 4*1867Sgjelinek * The contents of this file are subject to the terms of the 5*1867Sgjelinek * Common Development and Distribution License (the "License"). 6*1867Sgjelinek * You may not use this file except in compliance with the License. 7*1867Sgjelinek * 8*1867Sgjelinek * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*1867Sgjelinek * or http://www.opensolaris.org/os/licensing. 10*1867Sgjelinek * See the License for the specific language governing permissions 11*1867Sgjelinek * and limitations under the License. 12*1867Sgjelinek * 13*1867Sgjelinek * When distributing Covered Code, include this CDDL HEADER in each 14*1867Sgjelinek * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*1867Sgjelinek * If applicable, add the following below this CDDL HEADER, with the 16*1867Sgjelinek * fields enclosed by brackets "[]" replaced with your own identifying 17*1867Sgjelinek * information: Portions Copyright [yyyy] [name of copyright owner] 18*1867Sgjelinek * 19*1867Sgjelinek * CDDL HEADER END 20*1867Sgjelinek */ 21*1867Sgjelinek 22*1867Sgjelinek /* 23*1867Sgjelinek * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24*1867Sgjelinek * Use is subject to license terms. 25*1867Sgjelinek */ 26*1867Sgjelinek 27*1867Sgjelinek #pragma ident "%Z%%M% %I% %E% SMI" 28*1867Sgjelinek 29*1867Sgjelinek /* 30*1867Sgjelinek * This file contains the functions used to support the ZFS integration 31*1867Sgjelinek * with zones. This includes validation (e.g. zonecfg dataset), cloning, 32*1867Sgjelinek * file system creation and destruction. 33*1867Sgjelinek */ 34*1867Sgjelinek 35*1867Sgjelinek #include <stdio.h> 36*1867Sgjelinek #include <errno.h> 37*1867Sgjelinek #include <unistd.h> 38*1867Sgjelinek #include <string.h> 39*1867Sgjelinek #include <locale.h> 40*1867Sgjelinek #include <libintl.h> 41*1867Sgjelinek #include <sys/stat.h> 42*1867Sgjelinek #include <sys/statvfs.h> 43*1867Sgjelinek #include <libgen.h> 44*1867Sgjelinek #include <libzonecfg.h> 45*1867Sgjelinek #include <sys/mnttab.h> 46*1867Sgjelinek #include <libzfs.h> 47*1867Sgjelinek 48*1867Sgjelinek #include "zoneadm.h" 49*1867Sgjelinek 50*1867Sgjelinek static const char *current_dataset; 51*1867Sgjelinek 52*1867Sgjelinek typedef struct zfs_mount_data { 53*1867Sgjelinek char *match_name; 54*1867Sgjelinek zfs_handle_t *match_handle; 55*1867Sgjelinek } zfs_mount_data_t; 56*1867Sgjelinek 57*1867Sgjelinek typedef struct zfs_snapshot_data { 58*1867Sgjelinek char *match_name; 59*1867Sgjelinek int len; 60*1867Sgjelinek int max; 61*1867Sgjelinek } zfs_snapshot_data_t; 62*1867Sgjelinek 63*1867Sgjelinek /* 64*1867Sgjelinek * ZFS error handler to do nothing - do not print the libzfs error messages. 65*1867Sgjelinek */ 66*1867Sgjelinek /* ARGSUSED */ 67*1867Sgjelinek static void 68*1867Sgjelinek noop_err_handler(const char *fmt, va_list ap) 69*1867Sgjelinek { 70*1867Sgjelinek } 71*1867Sgjelinek 72*1867Sgjelinek /* 73*1867Sgjelinek * Custom error handler for errors incurred as part of verifying datasets. We 74*1867Sgjelinek * want to trim off the leading 'cannot open ...' to create a better error 75*1867Sgjelinek * message. The only other way this can fail is if we fail to set the 'zoned' 76*1867Sgjelinek * property. In this case we just pass the error on verbatim. 77*1867Sgjelinek */ 78*1867Sgjelinek static void 79*1867Sgjelinek err_handler(const char *fmt, va_list ap) 80*1867Sgjelinek { 81*1867Sgjelinek char buf[1024]; 82*1867Sgjelinek 83*1867Sgjelinek (void) vsnprintf(buf, sizeof (buf), fmt, ap); 84*1867Sgjelinek 85*1867Sgjelinek if (strncmp(gettext("cannot open "), buf, 86*1867Sgjelinek strlen(gettext("cannot open "))) == 0) 87*1867Sgjelinek /* 88*1867Sgjelinek * TRANSLATION_NOTE 89*1867Sgjelinek * zfs and dataset are literals that should not be translated. 90*1867Sgjelinek */ 91*1867Sgjelinek (void) fprintf(stderr, gettext("could not verify zfs " 92*1867Sgjelinek "dataset %s%s\n"), current_dataset, strchr(buf, ':')); 93*1867Sgjelinek else 94*1867Sgjelinek (void) fprintf(stderr, gettext("could not verify zfs dataset " 95*1867Sgjelinek "%s: %s\n"), current_dataset, buf); 96*1867Sgjelinek } 97*1867Sgjelinek 98*1867Sgjelinek /* 99*1867Sgjelinek * A ZFS file system iterator call-back function which is used to validate 100*1867Sgjelinek * datasets imported into the zone. 101*1867Sgjelinek */ 102*1867Sgjelinek /* ARGSUSED */ 103*1867Sgjelinek static int 104*1867Sgjelinek check_zvol(zfs_handle_t *zhp, void *unused) 105*1867Sgjelinek { 106*1867Sgjelinek int ret; 107*1867Sgjelinek 108*1867Sgjelinek if (zfs_get_type(zhp) == ZFS_TYPE_VOLUME) { 109*1867Sgjelinek /* 110*1867Sgjelinek * TRANSLATION_NOTE 111*1867Sgjelinek * zfs and dataset are literals that should not be translated. 112*1867Sgjelinek */ 113*1867Sgjelinek (void) fprintf(stderr, gettext("cannot verify zfs dataset %s: " 114*1867Sgjelinek "volumes cannot be specified as a zone dataset resource\n"), 115*1867Sgjelinek zfs_get_name(zhp)); 116*1867Sgjelinek ret = -1; 117*1867Sgjelinek } else { 118*1867Sgjelinek ret = zfs_iter_children(zhp, check_zvol, NULL); 119*1867Sgjelinek } 120*1867Sgjelinek 121*1867Sgjelinek zfs_close(zhp); 122*1867Sgjelinek 123*1867Sgjelinek return (ret); 124*1867Sgjelinek } 125*1867Sgjelinek 126*1867Sgjelinek /* 127*1867Sgjelinek * A ZFS file system iterator call-back function which returns the 128*1867Sgjelinek * zfs_handle_t for a ZFS file system on the specified mount point. 129*1867Sgjelinek */ 130*1867Sgjelinek static int 131*1867Sgjelinek match_mountpoint(zfs_handle_t *zhp, void *data) 132*1867Sgjelinek { 133*1867Sgjelinek int res; 134*1867Sgjelinek zfs_mount_data_t *cbp; 135*1867Sgjelinek char mp[ZFS_MAXPROPLEN]; 136*1867Sgjelinek 137*1867Sgjelinek if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) { 138*1867Sgjelinek zfs_close(zhp); 139*1867Sgjelinek return (0); 140*1867Sgjelinek } 141*1867Sgjelinek 142*1867Sgjelinek cbp = (zfs_mount_data_t *)data; 143*1867Sgjelinek if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mp, sizeof (mp), NULL, NULL, 144*1867Sgjelinek 0, FALSE) == 0 && strcmp(mp, cbp->match_name) == 0) { 145*1867Sgjelinek cbp->match_handle = zhp; 146*1867Sgjelinek return (1); 147*1867Sgjelinek } 148*1867Sgjelinek 149*1867Sgjelinek res = zfs_iter_filesystems(zhp, match_mountpoint, data); 150*1867Sgjelinek zfs_close(zhp); 151*1867Sgjelinek return (res); 152*1867Sgjelinek } 153*1867Sgjelinek 154*1867Sgjelinek /* 155*1867Sgjelinek * Get ZFS handle for the specified mount point. 156*1867Sgjelinek */ 157*1867Sgjelinek static zfs_handle_t * 158*1867Sgjelinek mount2zhandle(char *mountpoint) 159*1867Sgjelinek { 160*1867Sgjelinek zfs_mount_data_t cb; 161*1867Sgjelinek 162*1867Sgjelinek cb.match_name = mountpoint; 163*1867Sgjelinek cb.match_handle = NULL; 164*1867Sgjelinek (void) zfs_iter_root(match_mountpoint, &cb); 165*1867Sgjelinek return (cb.match_handle); 166*1867Sgjelinek } 167*1867Sgjelinek 168*1867Sgjelinek /* 169*1867Sgjelinek * Check if there is already a file system (zfs or any other type) mounted on 170*1867Sgjelinek * path. 171*1867Sgjelinek */ 172*1867Sgjelinek static boolean_t 173*1867Sgjelinek is_mountpnt(char *path) 174*1867Sgjelinek { 175*1867Sgjelinek FILE *fp; 176*1867Sgjelinek struct mnttab entry; 177*1867Sgjelinek 178*1867Sgjelinek if ((fp = fopen("/etc/mnttab", "r")) == NULL) 179*1867Sgjelinek return (B_FALSE); 180*1867Sgjelinek 181*1867Sgjelinek while (getmntent(fp, &entry) == 0) { 182*1867Sgjelinek if (strcmp(path, entry.mnt_mountp) == 0) { 183*1867Sgjelinek (void) fclose(fp); 184*1867Sgjelinek return (B_TRUE); 185*1867Sgjelinek } 186*1867Sgjelinek } 187*1867Sgjelinek 188*1867Sgjelinek (void) fclose(fp); 189*1867Sgjelinek return (B_FALSE); 190*1867Sgjelinek } 191*1867Sgjelinek 192*1867Sgjelinek /* 193*1867Sgjelinek * Perform any necessary housekeeping tasks we need to do before we take 194*1867Sgjelinek * a ZFS snapshot of the zone. What this really entails is that we are 195*1867Sgjelinek * taking a sw inventory of the source zone, like we do when we detach, 196*1867Sgjelinek * so that there is the XML manifest in the snapshot. We use that to 197*1867Sgjelinek * validate the snapshot if it is the source of a clone at some later time. 198*1867Sgjelinek */ 199*1867Sgjelinek static int 200*1867Sgjelinek pre_snapshot(char *source_zone) 201*1867Sgjelinek { 202*1867Sgjelinek int err; 203*1867Sgjelinek zone_dochandle_t handle; 204*1867Sgjelinek 205*1867Sgjelinek if ((handle = zonecfg_init_handle()) == NULL) { 206*1867Sgjelinek zperror(cmd_to_str(CMD_CLONE), B_TRUE); 207*1867Sgjelinek return (Z_ERR); 208*1867Sgjelinek } 209*1867Sgjelinek 210*1867Sgjelinek if ((err = zonecfg_get_handle(source_zone, handle)) != Z_OK) { 211*1867Sgjelinek errno = err; 212*1867Sgjelinek zperror(cmd_to_str(CMD_CLONE), B_TRUE); 213*1867Sgjelinek zonecfg_fini_handle(handle); 214*1867Sgjelinek return (Z_ERR); 215*1867Sgjelinek } 216*1867Sgjelinek 217*1867Sgjelinek if ((err = zonecfg_get_detach_info(handle, B_TRUE)) != Z_OK) { 218*1867Sgjelinek errno = err; 219*1867Sgjelinek zperror(gettext("getting the software version information " 220*1867Sgjelinek "failed"), B_TRUE); 221*1867Sgjelinek zonecfg_fini_handle(handle); 222*1867Sgjelinek return (Z_ERR); 223*1867Sgjelinek } 224*1867Sgjelinek 225*1867Sgjelinek if ((err = zonecfg_detach_save(handle)) != Z_OK) { 226*1867Sgjelinek errno = err; 227*1867Sgjelinek zperror(gettext("saving the software version manifest failed"), 228*1867Sgjelinek B_TRUE); 229*1867Sgjelinek zonecfg_fini_handle(handle); 230*1867Sgjelinek return (Z_ERR); 231*1867Sgjelinek } 232*1867Sgjelinek 233*1867Sgjelinek zonecfg_fini_handle(handle); 234*1867Sgjelinek return (Z_OK); 235*1867Sgjelinek } 236*1867Sgjelinek 237*1867Sgjelinek /* 238*1867Sgjelinek * Perform any necessary housekeeping tasks we need to do after we take 239*1867Sgjelinek * a ZFS snapshot of the zone. What this really entails is removing the 240*1867Sgjelinek * sw inventory XML file from the zone. It is still in the snapshot where 241*1867Sgjelinek * we want it, but we don't want it in the source zone itself. 242*1867Sgjelinek */ 243*1867Sgjelinek static int 244*1867Sgjelinek post_snapshot(char *source_zone) 245*1867Sgjelinek { 246*1867Sgjelinek int err; 247*1867Sgjelinek zone_dochandle_t handle; 248*1867Sgjelinek 249*1867Sgjelinek if ((handle = zonecfg_init_handle()) == NULL) { 250*1867Sgjelinek zperror(cmd_to_str(CMD_CLONE), B_TRUE); 251*1867Sgjelinek return (Z_ERR); 252*1867Sgjelinek } 253*1867Sgjelinek 254*1867Sgjelinek if ((err = zonecfg_get_handle(source_zone, handle)) != Z_OK) { 255*1867Sgjelinek errno = err; 256*1867Sgjelinek zperror(cmd_to_str(CMD_CLONE), B_TRUE); 257*1867Sgjelinek zonecfg_fini_handle(handle); 258*1867Sgjelinek return (Z_ERR); 259*1867Sgjelinek } 260*1867Sgjelinek 261*1867Sgjelinek zonecfg_rm_detached(handle, B_FALSE); 262*1867Sgjelinek zonecfg_fini_handle(handle); 263*1867Sgjelinek 264*1867Sgjelinek return (Z_OK); 265*1867Sgjelinek } 266*1867Sgjelinek 267*1867Sgjelinek /* 268*1867Sgjelinek * This is a ZFS snapshot iterator call-back function which returns the 269*1867Sgjelinek * highest number of SUNWzone snapshots that have been taken. 270*1867Sgjelinek */ 271*1867Sgjelinek static int 272*1867Sgjelinek get_snap_max(zfs_handle_t *zhp, void *data) 273*1867Sgjelinek { 274*1867Sgjelinek int res; 275*1867Sgjelinek zfs_snapshot_data_t *cbp; 276*1867Sgjelinek 277*1867Sgjelinek if (zfs_get_type(zhp) != ZFS_TYPE_SNAPSHOT) { 278*1867Sgjelinek zfs_close(zhp); 279*1867Sgjelinek return (0); 280*1867Sgjelinek } 281*1867Sgjelinek 282*1867Sgjelinek cbp = (zfs_snapshot_data_t *)data; 283*1867Sgjelinek 284*1867Sgjelinek if (strncmp(zfs_get_name(zhp), cbp->match_name, cbp->len) == 0) { 285*1867Sgjelinek char *nump; 286*1867Sgjelinek int num; 287*1867Sgjelinek 288*1867Sgjelinek nump = (char *)(zfs_get_name(zhp) + cbp->len); 289*1867Sgjelinek num = atoi(nump); 290*1867Sgjelinek if (num > cbp->max) 291*1867Sgjelinek cbp->max = num; 292*1867Sgjelinek } 293*1867Sgjelinek 294*1867Sgjelinek res = zfs_iter_snapshots(zhp, get_snap_max, data); 295*1867Sgjelinek zfs_close(zhp); 296*1867Sgjelinek return (res); 297*1867Sgjelinek } 298*1867Sgjelinek 299*1867Sgjelinek /* 300*1867Sgjelinek * Take a ZFS snapshot to be used for cloning the zone. 301*1867Sgjelinek */ 302*1867Sgjelinek static int 303*1867Sgjelinek take_snapshot(char *source_zone, zfs_handle_t *zhp, char *snapshot_name, 304*1867Sgjelinek int snap_size) 305*1867Sgjelinek { 306*1867Sgjelinek int res; 307*1867Sgjelinek char template[ZFS_MAXNAMELEN]; 308*1867Sgjelinek zfs_snapshot_data_t cb; 309*1867Sgjelinek 310*1867Sgjelinek /* 311*1867Sgjelinek * First we need to figure out the next available name for the 312*1867Sgjelinek * zone snapshot. Look through the list of zones snapshots for 313*1867Sgjelinek * this file system to determine the maximum snapshot name. 314*1867Sgjelinek */ 315*1867Sgjelinek if (snprintf(template, sizeof (template), "%s@SUNWzone", 316*1867Sgjelinek zfs_get_name(zhp)) >= sizeof (template)) 317*1867Sgjelinek return (Z_ERR); 318*1867Sgjelinek 319*1867Sgjelinek cb.match_name = template; 320*1867Sgjelinek cb.len = strlen(template); 321*1867Sgjelinek cb.max = 0; 322*1867Sgjelinek 323*1867Sgjelinek if (zfs_iter_snapshots(zhp, get_snap_max, &cb) != 0) 324*1867Sgjelinek return (Z_ERR); 325*1867Sgjelinek 326*1867Sgjelinek cb.max++; 327*1867Sgjelinek 328*1867Sgjelinek if (snprintf(snapshot_name, snap_size, "%s@SUNWzone%d", 329*1867Sgjelinek zfs_get_name(zhp), cb.max) >= snap_size) 330*1867Sgjelinek return (Z_ERR); 331*1867Sgjelinek 332*1867Sgjelinek if (pre_snapshot(source_zone) != Z_OK) 333*1867Sgjelinek return (Z_ERR); 334*1867Sgjelinek res = zfs_snapshot(snapshot_name); 335*1867Sgjelinek if (post_snapshot(source_zone) != Z_OK) 336*1867Sgjelinek return (Z_ERR); 337*1867Sgjelinek 338*1867Sgjelinek if (res != 0) 339*1867Sgjelinek return (Z_ERR); 340*1867Sgjelinek return (Z_OK); 341*1867Sgjelinek } 342*1867Sgjelinek 343*1867Sgjelinek /* 344*1867Sgjelinek * We are using an explicit snapshot from some earlier point in time so 345*1867Sgjelinek * we need to validate it. This involves checking the sw inventory that 346*1867Sgjelinek * we took when we made the snapshot to verify that the current sw config 347*1867Sgjelinek * on the host is still valid to run a zone made from this snapshot. 348*1867Sgjelinek */ 349*1867Sgjelinek static int 350*1867Sgjelinek validate_snapshot(char *snapshot_name, char *snap_path) 351*1867Sgjelinek { 352*1867Sgjelinek int err; 353*1867Sgjelinek zone_dochandle_t handle; 354*1867Sgjelinek zone_dochandle_t athandle = NULL; 355*1867Sgjelinek 356*1867Sgjelinek if ((handle = zonecfg_init_handle()) == NULL) { 357*1867Sgjelinek zperror(cmd_to_str(CMD_CLONE), B_TRUE); 358*1867Sgjelinek return (Z_ERR); 359*1867Sgjelinek } 360*1867Sgjelinek 361*1867Sgjelinek if ((err = zonecfg_get_handle(target_zone, handle)) != Z_OK) { 362*1867Sgjelinek errno = err; 363*1867Sgjelinek zperror(cmd_to_str(CMD_CLONE), B_TRUE); 364*1867Sgjelinek zonecfg_fini_handle(handle); 365*1867Sgjelinek return (Z_ERR); 366*1867Sgjelinek } 367*1867Sgjelinek 368*1867Sgjelinek if ((athandle = zonecfg_init_handle()) == NULL) { 369*1867Sgjelinek zperror(cmd_to_str(CMD_CLONE), B_TRUE); 370*1867Sgjelinek goto done; 371*1867Sgjelinek } 372*1867Sgjelinek 373*1867Sgjelinek if ((err = zonecfg_get_attach_handle(snap_path, target_zone, B_TRUE, 374*1867Sgjelinek athandle)) != Z_OK) { 375*1867Sgjelinek if (err == Z_NO_ZONE) 376*1867Sgjelinek (void) fprintf(stderr, gettext("snapshot %s was not " 377*1867Sgjelinek "taken\n\tby a 'zoneadm clone' command. It can " 378*1867Sgjelinek "not be used to clone zones.\n"), snapshot_name); 379*1867Sgjelinek else 380*1867Sgjelinek (void) fprintf(stderr, gettext("snapshot %s is " 381*1867Sgjelinek "out-dated\n\tIt can no longer be used to clone " 382*1867Sgjelinek "zones on this system.\n"), snapshot_name); 383*1867Sgjelinek goto done; 384*1867Sgjelinek } 385*1867Sgjelinek 386*1867Sgjelinek /* Get the detach information for the locally defined zone. */ 387*1867Sgjelinek if ((err = zonecfg_get_detach_info(handle, B_FALSE)) != Z_OK) { 388*1867Sgjelinek errno = err; 389*1867Sgjelinek zperror(gettext("getting the attach information failed"), 390*1867Sgjelinek B_TRUE); 391*1867Sgjelinek goto done; 392*1867Sgjelinek } 393*1867Sgjelinek 394*1867Sgjelinek if ((err = sw_cmp(handle, athandle, SW_CMP_SILENT)) != Z_OK) 395*1867Sgjelinek (void) fprintf(stderr, gettext("snapshot %s is out-dated\n\t" 396*1867Sgjelinek "It can no longer be used to clone zones on this " 397*1867Sgjelinek "system.\n"), snapshot_name); 398*1867Sgjelinek 399*1867Sgjelinek done: 400*1867Sgjelinek zonecfg_fini_handle(handle); 401*1867Sgjelinek if (athandle != NULL) 402*1867Sgjelinek zonecfg_fini_handle(athandle); 403*1867Sgjelinek 404*1867Sgjelinek return (err); 405*1867Sgjelinek } 406*1867Sgjelinek 407*1867Sgjelinek /* 408*1867Sgjelinek * Remove the sw inventory file from inside this zonepath that we picked up out 409*1867Sgjelinek * of the snapshot. 410*1867Sgjelinek */ 411*1867Sgjelinek static int 412*1867Sgjelinek clean_out_clone() 413*1867Sgjelinek { 414*1867Sgjelinek int err; 415*1867Sgjelinek zone_dochandle_t handle; 416*1867Sgjelinek 417*1867Sgjelinek if ((handle = zonecfg_init_handle()) == NULL) { 418*1867Sgjelinek zperror(cmd_to_str(CMD_CLONE), B_TRUE); 419*1867Sgjelinek return (Z_ERR); 420*1867Sgjelinek } 421*1867Sgjelinek 422*1867Sgjelinek if ((err = zonecfg_get_handle(target_zone, handle)) != Z_OK) { 423*1867Sgjelinek errno = err; 424*1867Sgjelinek zperror(cmd_to_str(CMD_CLONE), B_TRUE); 425*1867Sgjelinek zonecfg_fini_handle(handle); 426*1867Sgjelinek return (Z_ERR); 427*1867Sgjelinek } 428*1867Sgjelinek 429*1867Sgjelinek zonecfg_rm_detached(handle, B_FALSE); 430*1867Sgjelinek zonecfg_fini_handle(handle); 431*1867Sgjelinek 432*1867Sgjelinek return (Z_OK); 433*1867Sgjelinek } 434*1867Sgjelinek 435*1867Sgjelinek /* 436*1867Sgjelinek * Make a ZFS clone on zonepath from snapshot_name. 437*1867Sgjelinek */ 438*1867Sgjelinek static int 439*1867Sgjelinek clone_snap(char *snapshot_name, char *zonepath) 440*1867Sgjelinek { 441*1867Sgjelinek int res = Z_OK; 442*1867Sgjelinek int err; 443*1867Sgjelinek zfs_handle_t *zhp; 444*1867Sgjelinek zfs_handle_t *clone; 445*1867Sgjelinek 446*1867Sgjelinek if ((zhp = zfs_open(snapshot_name, ZFS_TYPE_SNAPSHOT)) == NULL) 447*1867Sgjelinek return (Z_NO_ENTRY); 448*1867Sgjelinek 449*1867Sgjelinek (void) printf(gettext("Cloning snapshot %s\n"), snapshot_name); 450*1867Sgjelinek 451*1867Sgjelinek err = zfs_clone(zhp, zonepath); 452*1867Sgjelinek zfs_close(zhp); 453*1867Sgjelinek if (err != 0) 454*1867Sgjelinek return (Z_ERR); 455*1867Sgjelinek 456*1867Sgjelinek /* create the mountpoint if necessary */ 457*1867Sgjelinek if ((clone = zfs_open(zonepath, ZFS_TYPE_ANY)) == NULL) 458*1867Sgjelinek return (Z_ERR); 459*1867Sgjelinek 460*1867Sgjelinek /* 461*1867Sgjelinek * The clone has been created so we need to print a diagnostic 462*1867Sgjelinek * message if one of the following steps fails for some reason. 463*1867Sgjelinek */ 464*1867Sgjelinek if (zfs_mount(clone, NULL, 0) != 0) { 465*1867Sgjelinek (void) fprintf(stderr, gettext("could not mount ZFS clone " 466*1867Sgjelinek "%s\n"), zfs_get_name(clone)); 467*1867Sgjelinek res = Z_ERR; 468*1867Sgjelinek 469*1867Sgjelinek } else { 470*1867Sgjelinek if (zfs_prop_set(clone, ZFS_PROP_SHARENFS, "off") != 0) { 471*1867Sgjelinek /* we won't consider this a failure */ 472*1867Sgjelinek (void) fprintf(stderr, gettext("could not turn off the " 473*1867Sgjelinek "'sharenfs' property on ZFS clone %s\n"), 474*1867Sgjelinek zfs_get_name(clone)); 475*1867Sgjelinek } 476*1867Sgjelinek 477*1867Sgjelinek if (clean_out_clone() != Z_OK) { 478*1867Sgjelinek (void) fprintf(stderr, gettext("could not remove the " 479*1867Sgjelinek "software inventory from ZFS clone %s\n"), 480*1867Sgjelinek zfs_get_name(clone)); 481*1867Sgjelinek res = Z_ERR; 482*1867Sgjelinek } 483*1867Sgjelinek } 484*1867Sgjelinek 485*1867Sgjelinek zfs_close(clone); 486*1867Sgjelinek return (res); 487*1867Sgjelinek } 488*1867Sgjelinek 489*1867Sgjelinek /* 490*1867Sgjelinek * This function takes a zonepath and attempts to determine what the ZFS 491*1867Sgjelinek * file system name (not mountpoint) should be for that path. We do not 492*1867Sgjelinek * assume that zonepath is an existing directory or ZFS fs since we use 493*1867Sgjelinek * this function as part of the process of creating a new ZFS fs or clone. 494*1867Sgjelinek * 495*1867Sgjelinek * The way this works is that we look at the parent directory of the zonepath 496*1867Sgjelinek * to see if it is a ZFS fs. If it is, we get the name of that ZFS fs and 497*1867Sgjelinek * append the last component of the zonepath to generate the ZFS name for the 498*1867Sgjelinek * zonepath. This matches the algorithm that ZFS uses for automatically 499*1867Sgjelinek * mounting a new fs after it is created. 500*1867Sgjelinek * 501*1867Sgjelinek * Although a ZFS fs can be mounted anywhere, we don't worry about handling 502*1867Sgjelinek * all of the complexity that a user could possibly configure with arbitrary 503*1867Sgjelinek * mounts since there is no way to generate a ZFS name from a random path in 504*1867Sgjelinek * the file system. We only try to handle the automatic mounts that ZFS does 505*1867Sgjelinek * for each file system. ZFS restricts this so that a new fs must be created 506*1867Sgjelinek * in an existing parent ZFS fs. It then automatically mounts the new fs 507*1867Sgjelinek * directly under the mountpoint for the parent fs using the last component 508*1867Sgjelinek * of the name as the mountpoint directory. 509*1867Sgjelinek * 510*1867Sgjelinek * For example: 511*1867Sgjelinek * Name Mountpoint 512*1867Sgjelinek * space/eng/dev/test/zone1 /project1/eng/dev/test/zone1 513*1867Sgjelinek * 514*1867Sgjelinek * Return Z_OK if the path mapped to a ZFS file system name, otherwise return 515*1867Sgjelinek * Z_ERR. 516*1867Sgjelinek */ 517*1867Sgjelinek static int 518*1867Sgjelinek path2name(char *zonepath, char *zfs_name, int len) 519*1867Sgjelinek { 520*1867Sgjelinek int res; 521*1867Sgjelinek char *p; 522*1867Sgjelinek zfs_handle_t *zhp; 523*1867Sgjelinek 524*1867Sgjelinek if ((p = strrchr(zonepath, '/')) == NULL) 525*1867Sgjelinek return (Z_ERR); 526*1867Sgjelinek 527*1867Sgjelinek /* 528*1867Sgjelinek * If the parent directory is not its own ZFS fs, then we can't 529*1867Sgjelinek * automatically create a new ZFS fs at the 'zonepath' mountpoint 530*1867Sgjelinek * so return an error. 531*1867Sgjelinek */ 532*1867Sgjelinek *p = '\0'; 533*1867Sgjelinek zhp = mount2zhandle(zonepath); 534*1867Sgjelinek *p = '/'; 535*1867Sgjelinek if (zhp == NULL) 536*1867Sgjelinek return (Z_ERR); 537*1867Sgjelinek 538*1867Sgjelinek res = snprintf(zfs_name, len, "%s/%s", zfs_get_name(zhp), p + 1); 539*1867Sgjelinek 540*1867Sgjelinek zfs_close(zhp); 541*1867Sgjelinek if (res >= len) 542*1867Sgjelinek return (Z_ERR); 543*1867Sgjelinek 544*1867Sgjelinek return (Z_OK); 545*1867Sgjelinek } 546*1867Sgjelinek 547*1867Sgjelinek /* 548*1867Sgjelinek * A ZFS file system iterator call-back function used to determine if the 549*1867Sgjelinek * file system has dependents (snapshots & clones). 550*1867Sgjelinek */ 551*1867Sgjelinek /* ARGSUSED */ 552*1867Sgjelinek static int 553*1867Sgjelinek has_dependent(zfs_handle_t *zhp, void *data) 554*1867Sgjelinek { 555*1867Sgjelinek zfs_close(zhp); 556*1867Sgjelinek return (1); 557*1867Sgjelinek } 558*1867Sgjelinek 559*1867Sgjelinek /* 560*1867Sgjelinek * Given a snapshot name, get the file system path where the snapshot lives. 561*1867Sgjelinek * A snapshot name is of the form fs_name@snap_name. For example, snapshot 562*1867Sgjelinek * pl/zones/z1@SUNWzone1 would have a path of 563*1867Sgjelinek * /pl/zones/z1/.zfs/snapshot/SUNWzone1. 564*1867Sgjelinek */ 565*1867Sgjelinek static int 566*1867Sgjelinek snap2path(char *snap_name, char *path, int len) 567*1867Sgjelinek { 568*1867Sgjelinek char *p; 569*1867Sgjelinek zfs_handle_t *zhp; 570*1867Sgjelinek char mp[ZFS_MAXPROPLEN]; 571*1867Sgjelinek 572*1867Sgjelinek if ((p = strrchr(snap_name, '@')) == NULL) 573*1867Sgjelinek return (Z_ERR); 574*1867Sgjelinek 575*1867Sgjelinek /* Get the file system name from the snap_name. */ 576*1867Sgjelinek *p = '\0'; 577*1867Sgjelinek zhp = zfs_open(snap_name, ZFS_TYPE_ANY); 578*1867Sgjelinek *p = '@'; 579*1867Sgjelinek if (zhp == NULL) 580*1867Sgjelinek return (Z_ERR); 581*1867Sgjelinek 582*1867Sgjelinek /* Get the file system mount point. */ 583*1867Sgjelinek if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mp, sizeof (mp), NULL, NULL, 584*1867Sgjelinek 0, FALSE) != 0) { 585*1867Sgjelinek zfs_close(zhp); 586*1867Sgjelinek return (Z_ERR); 587*1867Sgjelinek } 588*1867Sgjelinek zfs_close(zhp); 589*1867Sgjelinek 590*1867Sgjelinek p++; 591*1867Sgjelinek if (snprintf(path, len, "%s/.zfs/snapshot/%s", mp, p) >= len) 592*1867Sgjelinek return (Z_ERR); 593*1867Sgjelinek 594*1867Sgjelinek return (Z_OK); 595*1867Sgjelinek } 596*1867Sgjelinek 597*1867Sgjelinek /* 598*1867Sgjelinek * Clone a pre-existing ZFS snapshot, either by making a direct ZFS clone, if 599*1867Sgjelinek * possible, or by copying the data from the snapshot to the zonepath. 600*1867Sgjelinek */ 601*1867Sgjelinek int 602*1867Sgjelinek clone_snapshot_zfs(char *snap_name, char *zonepath) 603*1867Sgjelinek { 604*1867Sgjelinek int err = Z_OK; 605*1867Sgjelinek char clone_name[MAXPATHLEN]; 606*1867Sgjelinek char snap_path[MAXPATHLEN]; 607*1867Sgjelinek 608*1867Sgjelinek if (snap2path(snap_name, snap_path, sizeof (snap_path)) != Z_OK) { 609*1867Sgjelinek (void) fprintf(stderr, gettext("unable to find path for %s.\n"), 610*1867Sgjelinek snap_name); 611*1867Sgjelinek return (Z_ERR); 612*1867Sgjelinek } 613*1867Sgjelinek 614*1867Sgjelinek if (validate_snapshot(snap_name, snap_path) != Z_OK) 615*1867Sgjelinek return (Z_NO_ENTRY); 616*1867Sgjelinek 617*1867Sgjelinek /* 618*1867Sgjelinek * The zonepath cannot be ZFS cloned, try to copy the data from 619*1867Sgjelinek * within the snapshot to the zonepath. 620*1867Sgjelinek */ 621*1867Sgjelinek if (path2name(zonepath, clone_name, sizeof (clone_name)) != Z_OK) { 622*1867Sgjelinek if ((err = clone_copy(snap_path, zonepath)) == Z_OK) 623*1867Sgjelinek if (clean_out_clone() != Z_OK) 624*1867Sgjelinek (void) fprintf(stderr, 625*1867Sgjelinek gettext("could not remove the " 626*1867Sgjelinek "software inventory from %s\n"), zonepath); 627*1867Sgjelinek 628*1867Sgjelinek return (err); 629*1867Sgjelinek } 630*1867Sgjelinek 631*1867Sgjelinek if ((err = clone_snap(snap_name, clone_name)) != Z_OK) { 632*1867Sgjelinek if (err != Z_NO_ENTRY) { 633*1867Sgjelinek /* 634*1867Sgjelinek * Cloning the snapshot failed. Fall back to trying 635*1867Sgjelinek * to install the zone by copying from the snapshot. 636*1867Sgjelinek */ 637*1867Sgjelinek if ((err = clone_copy(snap_path, zonepath)) == Z_OK) 638*1867Sgjelinek if (clean_out_clone() != Z_OK) 639*1867Sgjelinek (void) fprintf(stderr, 640*1867Sgjelinek gettext("could not remove the " 641*1867Sgjelinek "software inventory from %s\n"), 642*1867Sgjelinek zonepath); 643*1867Sgjelinek } else { 644*1867Sgjelinek /* 645*1867Sgjelinek * The snapshot is unusable for some reason so restore 646*1867Sgjelinek * the zone state to configured since we were unable to 647*1867Sgjelinek * actually do anything about getting the zone 648*1867Sgjelinek * installed. 649*1867Sgjelinek */ 650*1867Sgjelinek int tmp; 651*1867Sgjelinek 652*1867Sgjelinek if ((tmp = zone_set_state(target_zone, 653*1867Sgjelinek ZONE_STATE_CONFIGURED)) != Z_OK) { 654*1867Sgjelinek errno = tmp; 655*1867Sgjelinek zperror2(target_zone, 656*1867Sgjelinek gettext("could not set state")); 657*1867Sgjelinek } 658*1867Sgjelinek } 659*1867Sgjelinek } 660*1867Sgjelinek 661*1867Sgjelinek return (err); 662*1867Sgjelinek } 663*1867Sgjelinek 664*1867Sgjelinek /* 665*1867Sgjelinek * Attempt to clone a source_zone to a target zonepath by using a ZFS clone. 666*1867Sgjelinek */ 667*1867Sgjelinek int 668*1867Sgjelinek clone_zfs(char *source_zone, char *source_zonepath, char *zonepath) 669*1867Sgjelinek { 670*1867Sgjelinek zfs_handle_t *zhp; 671*1867Sgjelinek char clone_name[MAXPATHLEN]; 672*1867Sgjelinek char snap_name[MAXPATHLEN]; 673*1867Sgjelinek 674*1867Sgjelinek /* 675*1867Sgjelinek * Try to get a zfs handle for the source_zonepath. If this fails 676*1867Sgjelinek * the source_zonepath is not ZFS so return an error. 677*1867Sgjelinek */ 678*1867Sgjelinek if ((zhp = mount2zhandle(source_zonepath)) == NULL) 679*1867Sgjelinek return (Z_ERR); 680*1867Sgjelinek 681*1867Sgjelinek /* 682*1867Sgjelinek * Check if there is a file system already mounted on zonepath. If so, 683*1867Sgjelinek * we can't clone to the path so we should fall back to copying. 684*1867Sgjelinek */ 685*1867Sgjelinek if (is_mountpnt(zonepath)) { 686*1867Sgjelinek zfs_close(zhp); 687*1867Sgjelinek (void) fprintf(stderr, 688*1867Sgjelinek gettext("A file system is already mounted on %s,\n" 689*1867Sgjelinek "preventing use of a ZFS clone.\n"), zonepath); 690*1867Sgjelinek return (Z_ERR); 691*1867Sgjelinek } 692*1867Sgjelinek 693*1867Sgjelinek /* 694*1867Sgjelinek * Instead of using path2name to get the clone name from the zonepath, 695*1867Sgjelinek * we could generate a name from the source zone ZFS name. However, 696*1867Sgjelinek * this would mean we would create the clone under the ZFS fs of the 697*1867Sgjelinek * source instead of what the zonepath says. For example, 698*1867Sgjelinek * 699*1867Sgjelinek * source_zonepath zonepath 700*1867Sgjelinek * /pl/zones/dev/z1 /pl/zones/deploy/z2 701*1867Sgjelinek * 702*1867Sgjelinek * We don't want the clone to be under "dev", we want it under 703*1867Sgjelinek * "deploy", so that we can leverage the normal attribute inheritance 704*1867Sgjelinek * that ZFS provides in the fs hierarchy. 705*1867Sgjelinek */ 706*1867Sgjelinek if (path2name(zonepath, clone_name, sizeof (clone_name)) != Z_OK) { 707*1867Sgjelinek zfs_close(zhp); 708*1867Sgjelinek return (Z_ERR); 709*1867Sgjelinek } 710*1867Sgjelinek 711*1867Sgjelinek if (take_snapshot(source_zone, zhp, snap_name, sizeof (snap_name)) 712*1867Sgjelinek != Z_OK) { 713*1867Sgjelinek zfs_close(zhp); 714*1867Sgjelinek return (Z_ERR); 715*1867Sgjelinek } 716*1867Sgjelinek zfs_close(zhp); 717*1867Sgjelinek 718*1867Sgjelinek if (clone_snap(snap_name, clone_name) != Z_OK) 719*1867Sgjelinek return (Z_ERR); 720*1867Sgjelinek 721*1867Sgjelinek (void) printf(gettext("Instead of copying, a ZFS clone has been " 722*1867Sgjelinek "created for this zone.\n")); 723*1867Sgjelinek 724*1867Sgjelinek return (Z_OK); 725*1867Sgjelinek } 726*1867Sgjelinek 727*1867Sgjelinek /* 728*1867Sgjelinek * Attempt to create a ZFS file system for the specified zonepath. 729*1867Sgjelinek * We either will successfully create a ZFS file system and get it mounted 730*1867Sgjelinek * on the zonepath or we don't. The caller doesn't care since a regular 731*1867Sgjelinek * directory is used for the zonepath if no ZFS file system is mounted there. 732*1867Sgjelinek */ 733*1867Sgjelinek void 734*1867Sgjelinek create_zfs_zonepath(char *zonepath) 735*1867Sgjelinek { 736*1867Sgjelinek zfs_handle_t *zhp; 737*1867Sgjelinek char zfs_name[MAXPATHLEN]; 738*1867Sgjelinek 739*1867Sgjelinek if (path2name(zonepath, zfs_name, sizeof (zfs_name)) != Z_OK) 740*1867Sgjelinek return; 741*1867Sgjelinek 742*1867Sgjelinek zfs_set_error_handler(noop_err_handler); 743*1867Sgjelinek 744*1867Sgjelinek if (zfs_create(zfs_name, ZFS_TYPE_FILESYSTEM, NULL, NULL) != 0 || 745*1867Sgjelinek (zhp = zfs_open(zfs_name, ZFS_TYPE_ANY)) == NULL) { 746*1867Sgjelinek zfs_set_error_handler(NULL); 747*1867Sgjelinek return; 748*1867Sgjelinek } 749*1867Sgjelinek 750*1867Sgjelinek if (zfs_mount(zhp, NULL, 0) != 0) { 751*1867Sgjelinek (void) zfs_destroy(zhp); 752*1867Sgjelinek } else if (zfs_prop_set(zhp, ZFS_PROP_SHARENFS, "off") != 0) { 753*1867Sgjelinek (void) fprintf(stderr, gettext("file system %s successfully " 754*1867Sgjelinek "created,\nbut could not turn off the 'sharenfs' " 755*1867Sgjelinek "property\n"), zfs_name); 756*1867Sgjelinek } else { 757*1867Sgjelinek if (chmod(zonepath, S_IRWXU) != 0) { 758*1867Sgjelinek (void) fprintf(stderr, gettext("file system %s " 759*1867Sgjelinek "successfully created, but chmod %o failed: %s\n"), 760*1867Sgjelinek zfs_name, S_IRWXU, strerror(errno)); 761*1867Sgjelinek (void) destroy_zfs(zonepath); 762*1867Sgjelinek } else { 763*1867Sgjelinek (void) printf(gettext("A ZFS file system has been " 764*1867Sgjelinek "created for this zone.\n")); 765*1867Sgjelinek } 766*1867Sgjelinek } 767*1867Sgjelinek 768*1867Sgjelinek zfs_set_error_handler(NULL); 769*1867Sgjelinek zfs_close(zhp); 770*1867Sgjelinek } 771*1867Sgjelinek 772*1867Sgjelinek /* 773*1867Sgjelinek * If the zonepath is a ZFS file system, attempt to destroy it. We return Z_OK 774*1867Sgjelinek * if we were able to zfs_destroy the zonepath, otherwise we return Z_ERR 775*1867Sgjelinek * which means the caller should clean up the zonepath in the traditional 776*1867Sgjelinek * way. 777*1867Sgjelinek */ 778*1867Sgjelinek int 779*1867Sgjelinek destroy_zfs(char *zonepath) 780*1867Sgjelinek { 781*1867Sgjelinek zfs_handle_t *zhp; 782*1867Sgjelinek boolean_t is_clone = B_FALSE; 783*1867Sgjelinek char origin[ZFS_MAXPROPLEN]; 784*1867Sgjelinek 785*1867Sgjelinek zfs_set_error_handler(noop_err_handler); 786*1867Sgjelinek 787*1867Sgjelinek if ((zhp = mount2zhandle(zonepath)) == NULL) { 788*1867Sgjelinek zfs_set_error_handler(NULL); 789*1867Sgjelinek return (Z_ERR); 790*1867Sgjelinek } 791*1867Sgjelinek 792*1867Sgjelinek /* 793*1867Sgjelinek * We can't destroy the file system if it has dependents. 794*1867Sgjelinek */ 795*1867Sgjelinek if (zfs_iter_dependents(zhp, has_dependent, NULL) != 0 || 796*1867Sgjelinek zfs_unmount(zhp, NULL, 0) != 0) { 797*1867Sgjelinek zfs_close(zhp); 798*1867Sgjelinek zfs_set_error_handler(NULL); 799*1867Sgjelinek return (Z_ERR); 800*1867Sgjelinek } 801*1867Sgjelinek 802*1867Sgjelinek /* 803*1867Sgjelinek * This might be a clone. Try to get the snapshot so we can attempt 804*1867Sgjelinek * to destroy that as well. 805*1867Sgjelinek */ 806*1867Sgjelinek if (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, origin, sizeof (origin), NULL, 807*1867Sgjelinek NULL, 0, FALSE) == 0) 808*1867Sgjelinek is_clone = B_TRUE; 809*1867Sgjelinek 810*1867Sgjelinek zfs_set_error_handler(NULL); 811*1867Sgjelinek if (zfs_destroy(zhp) != 0) { 812*1867Sgjelinek /* 813*1867Sgjelinek * If the destroy fails for some reason, try to remount 814*1867Sgjelinek * the file system so that we can use "rm -rf" to clean up 815*1867Sgjelinek * instead. 816*1867Sgjelinek */ 817*1867Sgjelinek (void) zfs_mount(zhp, NULL, 0); 818*1867Sgjelinek zfs_close(zhp); 819*1867Sgjelinek return (Z_ERR); 820*1867Sgjelinek } 821*1867Sgjelinek zfs_set_error_handler(noop_err_handler); 822*1867Sgjelinek 823*1867Sgjelinek (void) printf(gettext("The ZFS file system for this zone has been " 824*1867Sgjelinek "destroyed.\n")); 825*1867Sgjelinek 826*1867Sgjelinek if (is_clone) { 827*1867Sgjelinek zfs_handle_t *ohp; 828*1867Sgjelinek 829*1867Sgjelinek /* 830*1867Sgjelinek * Try to clean up the snapshot that the clone was taken from. 831*1867Sgjelinek */ 832*1867Sgjelinek if ((ohp = zfs_open(origin, ZFS_TYPE_SNAPSHOT)) != NULL) { 833*1867Sgjelinek if (zfs_iter_dependents(ohp, has_dependent, NULL) 834*1867Sgjelinek == 0 && zfs_unmount(ohp, NULL, 0) == 0) { 835*1867Sgjelinek (void) zfs_destroy(ohp); 836*1867Sgjelinek } 837*1867Sgjelinek zfs_close(ohp); 838*1867Sgjelinek } 839*1867Sgjelinek } 840*1867Sgjelinek 841*1867Sgjelinek zfs_close(zhp); 842*1867Sgjelinek zfs_set_error_handler(NULL); 843*1867Sgjelinek return (Z_OK); 844*1867Sgjelinek } 845*1867Sgjelinek 846*1867Sgjelinek /* 847*1867Sgjelinek * Return true if the path is its own zfs file system. We determine this 848*1867Sgjelinek * by stat-ing the path to see if it is zfs and stat-ing the parent to see 849*1867Sgjelinek * if it is a different fs. 850*1867Sgjelinek */ 851*1867Sgjelinek boolean_t 852*1867Sgjelinek is_zonepath_zfs(char *zonepath) 853*1867Sgjelinek { 854*1867Sgjelinek int res; 855*1867Sgjelinek char *path; 856*1867Sgjelinek char *parent; 857*1867Sgjelinek struct statvfs buf1, buf2; 858*1867Sgjelinek 859*1867Sgjelinek if (statvfs(zonepath, &buf1) != 0) 860*1867Sgjelinek return (B_FALSE); 861*1867Sgjelinek 862*1867Sgjelinek if (strcmp(buf1.f_basetype, "zfs") != 0) 863*1867Sgjelinek return (B_FALSE); 864*1867Sgjelinek 865*1867Sgjelinek if ((path = strdup(zonepath)) == NULL) 866*1867Sgjelinek return (B_FALSE); 867*1867Sgjelinek 868*1867Sgjelinek parent = dirname(path); 869*1867Sgjelinek res = statvfs(parent, &buf2); 870*1867Sgjelinek free(path); 871*1867Sgjelinek 872*1867Sgjelinek if (res != 0) 873*1867Sgjelinek return (B_FALSE); 874*1867Sgjelinek 875*1867Sgjelinek if (buf1.f_fsid == buf2.f_fsid) 876*1867Sgjelinek return (B_FALSE); 877*1867Sgjelinek 878*1867Sgjelinek return (B_TRUE); 879*1867Sgjelinek } 880*1867Sgjelinek 881*1867Sgjelinek /* 882*1867Sgjelinek * Implement the fast move of a ZFS file system by simply updating the 883*1867Sgjelinek * mountpoint. Since it is file system already, we don't have the 884*1867Sgjelinek * issue of cross-file system copying. 885*1867Sgjelinek */ 886*1867Sgjelinek int 887*1867Sgjelinek move_zfs(char *zonepath, char *new_zonepath) 888*1867Sgjelinek { 889*1867Sgjelinek int ret = Z_ERR; 890*1867Sgjelinek zfs_handle_t *zhp; 891*1867Sgjelinek 892*1867Sgjelinek zfs_set_error_handler(noop_err_handler); 893*1867Sgjelinek 894*1867Sgjelinek if ((zhp = mount2zhandle(zonepath)) == NULL) { 895*1867Sgjelinek zfs_set_error_handler(NULL); 896*1867Sgjelinek return (Z_ERR); 897*1867Sgjelinek } 898*1867Sgjelinek 899*1867Sgjelinek if (zfs_prop_set(zhp, ZFS_PROP_MOUNTPOINT, new_zonepath) == 0) { 900*1867Sgjelinek /* 901*1867Sgjelinek * Clean up the old mount point. We ignore any failure since 902*1867Sgjelinek * the zone is already successfully mounted on the new path. 903*1867Sgjelinek */ 904*1867Sgjelinek (void) rmdir(zonepath); 905*1867Sgjelinek ret = Z_OK; 906*1867Sgjelinek } 907*1867Sgjelinek 908*1867Sgjelinek zfs_close(zhp); 909*1867Sgjelinek zfs_set_error_handler(NULL); 910*1867Sgjelinek 911*1867Sgjelinek return (ret); 912*1867Sgjelinek } 913*1867Sgjelinek 914*1867Sgjelinek /* 915*1867Sgjelinek * Validate that the given dataset exists on the system, and that neither it nor 916*1867Sgjelinek * its children are zvols. 917*1867Sgjelinek * 918*1867Sgjelinek * Note that we don't do anything with the 'zoned' property here. All 919*1867Sgjelinek * management is done in zoneadmd when the zone is actually rebooted. This 920*1867Sgjelinek * allows us to automatically set the zoned property even when a zone is 921*1867Sgjelinek * rebooted by the administrator. 922*1867Sgjelinek */ 923*1867Sgjelinek int 924*1867Sgjelinek verify_datasets(zone_dochandle_t handle) 925*1867Sgjelinek { 926*1867Sgjelinek int return_code = Z_OK; 927*1867Sgjelinek struct zone_dstab dstab; 928*1867Sgjelinek zfs_handle_t *zhp; 929*1867Sgjelinek char propbuf[ZFS_MAXPROPLEN]; 930*1867Sgjelinek char source[ZFS_MAXNAMELEN]; 931*1867Sgjelinek zfs_source_t srctype; 932*1867Sgjelinek 933*1867Sgjelinek if (zonecfg_setdsent(handle) != Z_OK) { 934*1867Sgjelinek /* 935*1867Sgjelinek * TRANSLATION_NOTE 936*1867Sgjelinek * zfs and dataset are literals that should not be translated. 937*1867Sgjelinek */ 938*1867Sgjelinek (void) fprintf(stderr, gettext("could not verify zfs datasets: " 939*1867Sgjelinek "unable to enumerate datasets\n")); 940*1867Sgjelinek return (Z_ERR); 941*1867Sgjelinek } 942*1867Sgjelinek 943*1867Sgjelinek zfs_set_error_handler(err_handler); 944*1867Sgjelinek 945*1867Sgjelinek while (zonecfg_getdsent(handle, &dstab) == Z_OK) { 946*1867Sgjelinek 947*1867Sgjelinek current_dataset = dstab.zone_dataset_name; 948*1867Sgjelinek 949*1867Sgjelinek if ((zhp = zfs_open(dstab.zone_dataset_name, 950*1867Sgjelinek ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME)) == NULL) { 951*1867Sgjelinek return_code = Z_ERR; 952*1867Sgjelinek continue; 953*1867Sgjelinek } 954*1867Sgjelinek 955*1867Sgjelinek if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, propbuf, 956*1867Sgjelinek sizeof (propbuf), &srctype, source, 957*1867Sgjelinek sizeof (source), 0) == 0 && 958*1867Sgjelinek (srctype == ZFS_SRC_INHERITED)) { 959*1867Sgjelinek (void) fprintf(stderr, gettext("could not verify zfs " 960*1867Sgjelinek "dataset %s: mountpoint cannot be inherited\n"), 961*1867Sgjelinek dstab.zone_dataset_name); 962*1867Sgjelinek return_code = Z_ERR; 963*1867Sgjelinek zfs_close(zhp); 964*1867Sgjelinek continue; 965*1867Sgjelinek } 966*1867Sgjelinek 967*1867Sgjelinek if (zfs_get_type(zhp) == ZFS_TYPE_VOLUME) { 968*1867Sgjelinek (void) fprintf(stderr, gettext("cannot verify zfs " 969*1867Sgjelinek "dataset %s: volumes cannot be specified as a " 970*1867Sgjelinek "zone dataset resource\n"), 971*1867Sgjelinek dstab.zone_dataset_name); 972*1867Sgjelinek return_code = Z_ERR; 973*1867Sgjelinek } 974*1867Sgjelinek 975*1867Sgjelinek if (zfs_iter_children(zhp, check_zvol, NULL) != 0) 976*1867Sgjelinek return_code = Z_ERR; 977*1867Sgjelinek 978*1867Sgjelinek zfs_close(zhp); 979*1867Sgjelinek } 980*1867Sgjelinek (void) zonecfg_enddsent(handle); 981*1867Sgjelinek zfs_set_error_handler(NULL); 982*1867Sgjelinek 983*1867Sgjelinek return (return_code); 984*1867Sgjelinek } 985*1867Sgjelinek 986*1867Sgjelinek /* 987*1867Sgjelinek * Verify that the ZFS dataset exists, and its mountpoint 988*1867Sgjelinek * property is set to "legacy". 989*1867Sgjelinek */ 990*1867Sgjelinek int 991*1867Sgjelinek verify_fs_zfs(struct zone_fstab *fstab) 992*1867Sgjelinek { 993*1867Sgjelinek zfs_handle_t *zhp; 994*1867Sgjelinek char propbuf[ZFS_MAXPROPLEN]; 995*1867Sgjelinek 996*1867Sgjelinek zfs_set_error_handler(noop_err_handler); 997*1867Sgjelinek 998*1867Sgjelinek if ((zhp = zfs_open(fstab->zone_fs_special, ZFS_TYPE_ANY)) == NULL) { 999*1867Sgjelinek (void) fprintf(stderr, gettext("could not verify fs %s: " 1000*1867Sgjelinek "could not access zfs dataset '%s'\n"), 1001*1867Sgjelinek fstab->zone_fs_dir, fstab->zone_fs_special); 1002*1867Sgjelinek zfs_set_error_handler(NULL); 1003*1867Sgjelinek return (Z_ERR); 1004*1867Sgjelinek } 1005*1867Sgjelinek 1006*1867Sgjelinek if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) { 1007*1867Sgjelinek (void) fprintf(stderr, gettext("cannot verify fs %s: " 1008*1867Sgjelinek "'%s' is not a file system\n"), 1009*1867Sgjelinek fstab->zone_fs_dir, fstab->zone_fs_special); 1010*1867Sgjelinek zfs_close(zhp); 1011*1867Sgjelinek zfs_set_error_handler(NULL); 1012*1867Sgjelinek return (Z_ERR); 1013*1867Sgjelinek } 1014*1867Sgjelinek 1015*1867Sgjelinek if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, propbuf, sizeof (propbuf), 1016*1867Sgjelinek NULL, NULL, 0, 0) != 0 || strcmp(propbuf, "legacy") != 0) { 1017*1867Sgjelinek (void) fprintf(stderr, gettext("could not verify fs %s: " 1018*1867Sgjelinek "zfs '%s' mountpoint is not \"legacy\"\n"), 1019*1867Sgjelinek fstab->zone_fs_dir, fstab->zone_fs_special); 1020*1867Sgjelinek zfs_close(zhp); 1021*1867Sgjelinek zfs_set_error_handler(NULL); 1022*1867Sgjelinek return (Z_ERR); 1023*1867Sgjelinek } 1024*1867Sgjelinek 1025*1867Sgjelinek zfs_close(zhp); 1026*1867Sgjelinek zfs_set_error_handler(NULL); 1027*1867Sgjelinek return (Z_OK); 1028*1867Sgjelinek } 1029