1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 /* 27 * System includes 28 */ 29 #include <assert.h> 30 #include <errno.h> 31 #include <libintl.h> 32 #include <libnvpair.h> 33 #include <libzfs.h> 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <string.h> 37 #include <sys/mntent.h> 38 #include <sys/mnttab.h> 39 #include <sys/mount.h> 40 #include <sys/stat.h> 41 #include <sys/types.h> 42 #include <sys/vfstab.h> 43 #include <unistd.h> 44 45 #include <libbe.h> 46 #include <libbe_priv.h> 47 48 typedef struct active_zone_root_data { 49 uuid_t parent_uuid; 50 char *zoneroot_ds; 51 } active_zone_root_data_t; 52 53 typedef struct mounted_zone_root_data { 54 char *zone_altroot; 55 char *zoneroot_ds; 56 } mounted_zone_root_data_t; 57 58 /* Private function prototypes */ 59 static int be_find_active_zone_root_callback(zfs_handle_t *, void *); 60 static int be_find_mounted_zone_root_callback(zfs_handle_t *, void *); 61 static boolean_t be_zone_get_active(zfs_handle_t *); 62 63 64 /* ******************************************************************** */ 65 /* Semi-Private Functions */ 66 /* ******************************************************************** */ 67 68 /* 69 * Function: be_make_zoneroot 70 * Description: Generate a string for a zone's zoneroot given the 71 * zone's zonepath. 72 * Parameters: 73 * zonepath - pointer to zonepath 74 * zoneroot - pointer to buffer to retrn zoneroot in. 75 * zoneroot_size - size of zoneroot 76 * Returns: 77 * None 78 * Scope: 79 * Semi-private (library wise use only) 80 */ 81 void 82 be_make_zoneroot(char *zonepath, char *zoneroot, int zoneroot_size) 83 { 84 (void) snprintf(zoneroot, zoneroot_size, "%s/root", zonepath); 85 } 86 87 /* 88 * Function: be_find_active_zone_root 89 * Description: This function will find the active zone root of a zone for 90 * a given global BE. It will iterate all of the zone roots 91 * under a zonepath, find the zone roots that belong to the 92 * specified global BE, and return the one that is active. 93 * Parameters: 94 * be_zhp - zfs handle to global BE root dataset. 95 * zonepath_ds - pointer to zone's zonepath dataset. 96 * zoneroot_ds - pointer to a buffer to store the dataset name of 97 * the zone's zoneroot that's currently active for this 98 * given global BE.. 99 * zoneroot-ds_size - size of zoneroot_ds. 100 * Returns: 101 * BE_SUCCESS - Success 102 * be_errno_t - Failure 103 * Scope: 104 * Semi-private (library wide use only) 105 */ 106 int 107 be_find_active_zone_root(zfs_handle_t *be_zhp, char *zonepath_ds, 108 char *zoneroot_ds, int zoneroot_ds_size) 109 { 110 active_zone_root_data_t azr_data = { 0 }; 111 zfs_handle_t *zhp; 112 char zone_container_ds[MAXPATHLEN]; 113 int ret = BE_SUCCESS; 114 115 /* Get the uuid of the parent global BE */ 116 if ((ret = be_get_uuid(zfs_get_name(be_zhp), &azr_data.parent_uuid)) 117 != BE_SUCCESS) { 118 be_print_err(gettext("be_find_active_zone_root: failed to " 119 "get uuid for BE root dataset %s\n"), zfs_get_name(be_zhp)); 120 return (ret); 121 } 122 123 /* Generate string for the root container dataset for this zone. */ 124 be_make_container_ds(zonepath_ds, zone_container_ds, 125 sizeof (zone_container_ds)); 126 127 /* Get handle to this zone's root container dataset */ 128 if ((zhp = zfs_open(g_zfs, zone_container_ds, ZFS_TYPE_FILESYSTEM)) 129 == NULL) { 130 be_print_err(gettext("be_find_active_zone_root: failed to " 131 "open zone root container dataset (%s): %s\n"), 132 zone_container_ds, libzfs_error_description(g_zfs)); 133 return (zfs_err_to_be_err(g_zfs)); 134 } 135 136 /* 137 * Iterate through all of this zone's BEs, looking for ones 138 * that belong to the parent global BE, and finding the one 139 * that is marked active. 140 */ 141 if ((ret = zfs_iter_filesystems(zhp, be_find_active_zone_root_callback, 142 &azr_data)) != 0) { 143 be_print_err(gettext("be_find_active_zone_root: failed to " 144 "find active zone root in zonepath dataset %s: %s\n"), 145 zonepath_ds, be_err_to_str(ret)); 146 goto done; 147 } 148 149 if (azr_data.zoneroot_ds != NULL) { 150 (void) strlcpy(zoneroot_ds, azr_data.zoneroot_ds, 151 zoneroot_ds_size); 152 free(azr_data.zoneroot_ds); 153 } else { 154 be_print_err(gettext("be_find_active_zone_root: failed to " 155 "find active zone root in zonepath dataset %s\n"), 156 zonepath_ds); 157 ret = BE_ERR_ZONE_NO_ACTIVE_ROOT; 158 } 159 160 done: 161 ZFS_CLOSE(zhp); 162 return (ret); 163 } 164 165 /* 166 * Function: be_find_mounted_zone_root 167 * Description: This function will find the dataset mounted as the zoneroot 168 * of a zone for a given mounted global BE. 169 * Parameters: 170 * zone_altroot - path of zoneroot wrt the mounted global BE. 171 * zonepath_ds - dataset of the zone's zonepath. 172 * zoneroot_ds - pointer to a buffer to store the dataset of 173 * the zoneroot that currently mounted for this zone 174 * in the mounted global BE. 175 * zoneroot_ds_size - size of zoneroot_ds 176 * Returns: 177 * BE_SUCCESS - Success 178 * be_errno_t - Failure 179 * Scope: 180 * Semi-private (library wide use only) 181 */ 182 int 183 be_find_mounted_zone_root(char *zone_altroot, char *zonepath_ds, 184 char *zoneroot_ds, int zoneroot_ds_size) 185 { 186 mounted_zone_root_data_t mzr_data = { 0 }; 187 zfs_handle_t *zhp = NULL; 188 char zone_container_ds[MAXPATHLEN]; 189 int ret = BE_SUCCESS; 190 int zret = 0; 191 192 /* Generate string for the root container dataset for this zone. */ 193 be_make_container_ds(zonepath_ds, zone_container_ds, 194 sizeof (zone_container_ds)); 195 196 /* Get handle to this zone's root container dataset. */ 197 if ((zhp = zfs_open(g_zfs, zone_container_ds, ZFS_TYPE_FILESYSTEM)) 198 == NULL) { 199 be_print_err(gettext("be_find_mounted_zone_root: failed to " 200 "open zone root container dataset (%s): %s\n"), 201 zone_container_ds, libzfs_error_description(g_zfs)); 202 return (zfs_err_to_be_err(g_zfs)); 203 } 204 205 mzr_data.zone_altroot = zone_altroot; 206 207 /* 208 * Iterate through all of the zone's BEs, looking for the one 209 * that is currently mounted at the zone altroot in the mounted 210 * global BE. 211 */ 212 if ((zret = zfs_iter_filesystems(zhp, 213 be_find_mounted_zone_root_callback, &mzr_data)) == 0) { 214 be_print_err(gettext("be_find_mounted_zone_root: did not " 215 "find mounted zone under altroot zonepath %s\n"), 216 zonepath_ds); 217 ret = BE_ERR_NO_MOUNTED_ZONE; 218 goto done; 219 } else if (zret < 0) { 220 be_print_err(gettext("be_find_mounted_zone_root: " 221 "zfs_iter_filesystems failed: %s\n"), 222 libzfs_error_description(g_zfs)); 223 ret = zfs_err_to_be_err(g_zfs); 224 goto done; 225 } 226 227 if (mzr_data.zoneroot_ds != NULL) { 228 (void) strlcpy(zoneroot_ds, mzr_data.zoneroot_ds, 229 zoneroot_ds_size); 230 free(mzr_data.zoneroot_ds); 231 } 232 233 done: 234 ZFS_CLOSE(zhp); 235 return (ret); 236 } 237 238 /* 239 * Function: be_zone_supported 240 * Description: This function will determine if a zone is supported 241 * based on its zonepath dataset. The zonepath dataset 242 * must: 243 * - not be under any global BE root dataset. 244 * - have a root container dataset underneath it. 245 * 246 * Parameters: 247 * zonepath_ds - name of dataset of the zonepath of the 248 * zone to check. 249 * Returns: 250 * B_TRUE - zone is supported 251 * B_FALSE - zone is not supported 252 * Scope: 253 * Semi-private (library wide use only) 254 */ 255 boolean_t 256 be_zone_supported(char *zonepath_ds) 257 { 258 char zone_container_ds[MAXPATHLEN]; 259 int ret = 0; 260 261 /* 262 * Make sure the dataset for the zonepath is not hierarchically 263 * under any reserved BE root container dataset of any pool. 264 */ 265 if ((ret = zpool_iter(g_zfs, be_check_be_roots_callback, 266 zonepath_ds)) > 0) { 267 be_print_err(gettext("be_zone_supported: " 268 "zonepath dataset %s not supported\n"), zonepath_ds); 269 return (B_FALSE); 270 } else if (ret < 0) { 271 be_print_err(gettext("be_zone_supported: " 272 "zpool_iter failed: %s\n"), 273 libzfs_error_description(g_zfs)); 274 return (B_FALSE); 275 } 276 277 /* 278 * Make sure the zonepath has a zone root container dataset 279 * underneath it. 280 */ 281 be_make_container_ds(zonepath_ds, zone_container_ds, 282 sizeof (zone_container_ds)); 283 284 if (!zfs_dataset_exists(g_zfs, zone_container_ds, 285 ZFS_TYPE_FILESYSTEM)) { 286 be_print_err(gettext("be_zone_supported: " 287 "zonepath dataset (%s) does not have a zone root container " 288 "dataset, zone is not supported, skipping ...\n"), 289 zonepath_ds); 290 return (B_FALSE); 291 } 292 293 return (B_TRUE); 294 } 295 296 /* 297 * Function: be_get_supported_brandlist 298 * Desciption: This functions retuns a list of supported brands in 299 * a zoneBrandList_t object. 300 * Parameters: 301 * None 302 * Returns: 303 * Failure - NULL if no supported brands found. 304 * Success - pointer to zoneBrandList structure. 305 * Scope: 306 * Semi-private (library wide use only) 307 */ 308 zoneBrandList_t * 309 be_get_supported_brandlist(void) 310 { 311 return (z_make_brand_list(BE_ZONE_SUPPORTED_BRANDS, 312 BE_ZONE_SUPPORTED_BRANDS_DELIM)); 313 } 314 315 /* 316 * Function: be_zone_get_parent_uuid 317 * Description: This function gets the parentbe property of a zone root 318 * dataset, parsed it into internal uuid format, and returns 319 * it in the uuid_t reference pointer passed in. 320 * Parameters: 321 * root_ds - dataset name of a zone root dataset 322 * uu - pointer to a uuid_t to return the parentbe uuid in 323 * Returns: 324 * BE_SUCCESS - Success 325 * be_errno_t - Failure 326 * Scope: 327 * Private 328 */ 329 int 330 be_zone_get_parent_uuid(const char *root_ds, uuid_t *uu) 331 { 332 zfs_handle_t *zhp = NULL; 333 nvlist_t *userprops = NULL; 334 nvlist_t *propname = NULL; 335 char *uu_string = NULL; 336 int ret = BE_SUCCESS; 337 338 /* Get handle to zone root dataset */ 339 if ((zhp = zfs_open(g_zfs, root_ds, ZFS_TYPE_FILESYSTEM)) == NULL) { 340 be_print_err(gettext("be_zone_get_parent_uuid: failed to " 341 "open zone root dataset (%s): %s\n"), root_ds, 342 libzfs_error_description(g_zfs)); 343 return (zfs_err_to_be_err(g_zfs)); 344 } 345 346 /* Get user properties for zone root dataset */ 347 if ((userprops = zfs_get_user_props(zhp)) == NULL) { 348 be_print_err(gettext("be_zone_get_parent_uuid: " 349 "failed to get user properties for zone root " 350 "dataset (%s): %s\n"), root_ds, 351 libzfs_error_description(g_zfs)); 352 ret = zfs_err_to_be_err(g_zfs); 353 goto done; 354 } 355 356 /* Get UUID string from zone's root dataset user properties */ 357 if (nvlist_lookup_nvlist(userprops, BE_ZONE_PARENTBE_PROPERTY, 358 &propname) != 0 || nvlist_lookup_string(propname, ZPROP_VALUE, 359 &uu_string) != 0) { 360 be_print_err(gettext("be_zone_get_parent_uuid: failed to " 361 "get parent uuid property from zone root dataset user " 362 "properties.\n")); 363 ret = BE_ERR_ZONE_NO_PARENTBE; 364 goto done; 365 } 366 367 /* Parse the uuid string into internal format */ 368 if (uuid_parse(uu_string, *uu) != 0 || uuid_is_null(*uu)) { 369 be_print_err(gettext("be_zone_get_parent_uuid: failed to " 370 "parse parentuuid\n")); 371 ret = BE_ERR_PARSE_UUID; 372 } 373 374 done: 375 ZFS_CLOSE(zhp); 376 return (ret); 377 } 378 379 /* ******************************************************************** */ 380 /* Private Functions */ 381 /* ******************************************************************** */ 382 383 /* 384 * Function: be_find_active_zone_root_callback 385 * Description: This function is used as a callback to iterate over all of 386 * a zone's root datasets, finding the one that is marked active 387 * for the parent BE specified in the data passed in. The name 388 * of the zone's active root dataset is returned in heap storage 389 * in the active_zone_root_data_t structure passed in, so the 390 * caller is responsible for freeing it. 391 * Parameters: 392 * zhp - zfs_handle_t pointer to current dataset being processed 393 * data - active_zone_root_data_t pointer 394 * Returns: 395 * 0 - Success 396 * >0 - Failure 397 * Scope: 398 * Private 399 */ 400 static int 401 be_find_active_zone_root_callback(zfs_handle_t *zhp, void *data) 402 { 403 active_zone_root_data_t *azr_data = data; 404 uuid_t parent_uuid = { 0 }; 405 int iret = 0; 406 int ret = 0; 407 408 if ((iret = be_zone_get_parent_uuid(zfs_get_name(zhp), &parent_uuid)) 409 != BE_SUCCESS) { 410 be_print_err(gettext("be_find_active_zone_root_callback: " 411 "skipping zone root dataset (%s): %s\n"), 412 zfs_get_name(zhp), be_err_to_str(iret)); 413 goto done; 414 } 415 416 if (uuid_compare(azr_data->parent_uuid, parent_uuid) == 0) { 417 /* 418 * Found a zone root dataset belonging to the right parent, 419 * check if its active. 420 */ 421 if (be_zone_get_active(zhp)) { 422 /* 423 * Found active zone root dataset, if its already 424 * set in the callback data, that means this 425 * is the second one we've found. Return error. 426 */ 427 if (azr_data->zoneroot_ds != NULL) { 428 ret = BE_ERR_ZONE_MULTIPLE_ACTIVE; 429 goto done; 430 } 431 432 azr_data->zoneroot_ds = strdup(zfs_get_name(zhp)); 433 if (azr_data->zoneroot_ds == NULL) { 434 ret = BE_ERR_NOMEM; 435 } 436 } 437 } 438 439 done: 440 ZFS_CLOSE(zhp); 441 return (ret); 442 } 443 444 /* 445 * Function: be_find_mounted_zone_root_callback 446 * Description: This function is used as a callback to iterate over all of 447 * a zone's root datasets, find the one that is currently 448 * mounted for the parent BE specified in the data passed in. 449 * The name of the zone's mounted root dataset is returned in 450 * heap storage the mounted_zone_data_t structure passed in, 451 * so the caller is responsible for freeing it. 452 * Parameters: 453 * zhp - zfs_handle_t pointer to the current dataset being 454 * processed 455 * data - mounted_zone_data_t pointer 456 * Returns: 457 * 0 - not mounted as zone's root 458 * 1 - this dataset is mounted as zone's root 459 * Scope: 460 * Private 461 */ 462 static int 463 be_find_mounted_zone_root_callback(zfs_handle_t *zhp, void *data) 464 { 465 mounted_zone_root_data_t *mzr_data = data; 466 char *mp = NULL; 467 468 if (zfs_is_mounted(zhp, &mp) && mp != NULL && 469 strcmp(mp, mzr_data->zone_altroot) == 0) { 470 mzr_data->zoneroot_ds = strdup(zfs_get_name(zhp)); 471 free(mp); 472 return (1); 473 } 474 475 free(mp); 476 return (0); 477 } 478 479 /* 480 * Function: be_zone_get_active 481 * Description: This function gets the active property of a zone root 482 * dataset, and returns true if active property is on. 483 * Parameters: 484 * zfs - zfs_handle_t pointer to zone root dataset to check 485 * Returns: 486 * B_TRUE - zone root dataset is active 487 * B_FALSE - zone root dataset is not active 488 * Scope: 489 * Private 490 */ 491 static boolean_t 492 be_zone_get_active(zfs_handle_t *zhp) 493 { 494 nvlist_t *userprops = NULL; 495 nvlist_t *propname = NULL; 496 char *active_str = NULL; 497 498 /* Get user properties for the zone root dataset */ 499 if ((userprops = zfs_get_user_props(zhp)) == NULL) { 500 be_print_err(gettext("be_zone_get_active: " 501 "failed to get user properties for zone root " 502 "dataset (%s): %s\n"), zfs_get_name(zhp), 503 libzfs_error_description(g_zfs)); 504 return (B_FALSE); 505 } 506 507 /* Get active property from the zone root dataset user properties */ 508 if (nvlist_lookup_nvlist(userprops, BE_ZONE_ACTIVE_PROPERTY, &propname) 509 != 0 || nvlist_lookup_string(propname, ZPROP_VALUE, &active_str) 510 != 0) { 511 return (B_FALSE); 512 } 513 514 if (strcmp(active_str, "on") == 0) 515 return (B_TRUE); 516 517 return (B_FALSE); 518 }