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 * Copyright 2013 Nexenta Systems, Inc. All rights reserved. 25 * Copyright (c) 2015 by Delphix. All rights reserved. 26 */ 27 28 29 /* 30 * System includes 31 */ 32 #include <assert.h> 33 #include <errno.h> 34 #include <libgen.h> 35 #include <libintl.h> 36 #include <libnvpair.h> 37 #include <libzfs.h> 38 #include <libgen.h> 39 #include <stdio.h> 40 #include <stdlib.h> 41 #include <string.h> 42 #include <sys/stat.h> 43 #include <sys/types.h> 44 #include <sys/vfstab.h> 45 #include <sys/param.h> 46 #include <sys/systeminfo.h> 47 #include <ctype.h> 48 #include <time.h> 49 #include <unistd.h> 50 #include <fcntl.h> 51 #include <deflt.h> 52 #include <wait.h> 53 #include <libdevinfo.h> 54 #include <libgen.h> 55 56 #include <libbe.h> 57 #include <libbe_priv.h> 58 59 /* Private function prototypes */ 60 static int update_dataset(char *, int, char *, char *, char *); 61 static int _update_vfstab(char *, char *, char *, char *, be_fs_list_data_t *); 62 static int be_open_menu(char *, char *, FILE **, char *, boolean_t); 63 static int be_create_menu(char *, char *, FILE **, char *); 64 static char *be_get_auto_name(char *, char *, boolean_t); 65 66 /* 67 * Global error printing 68 */ 69 boolean_t do_print = B_FALSE; 70 71 /* 72 * Private datatypes 73 */ 74 typedef struct zone_be_name_cb_data { 75 char *base_be_name; 76 int num; 77 } zone_be_name_cb_data_t; 78 79 /* ******************************************************************** */ 80 /* Public Functions */ 81 /* ******************************************************************** */ 82 83 /* 84 * Function: be_max_avail 85 * Description: Returns the available size for the zfs dataset passed in. 86 * Parameters: 87 * dataset - The dataset we want to get the available space for. 88 * ret - The available size will be returned in this. 89 * Returns: 90 * The error returned by the zfs get property function. 91 * Scope: 92 * Public 93 */ 94 int 95 be_max_avail(char *dataset, uint64_t *ret) 96 { 97 zfs_handle_t *zhp; 98 int err = 0; 99 100 /* Initialize libzfs handle */ 101 if (!be_zfs_init()) 102 return (BE_ERR_INIT); 103 104 zhp = zfs_open(g_zfs, dataset, ZFS_TYPE_DATASET); 105 if (zhp == NULL) { 106 /* 107 * The zfs_open failed return an error 108 */ 109 err = zfs_err_to_be_err(g_zfs); 110 } else { 111 err = be_maxsize_avail(zhp, ret); 112 } 113 ZFS_CLOSE(zhp); 114 be_zfs_fini(); 115 return (err); 116 } 117 118 /* 119 * Function: libbe_print_errors 120 * Description: Turns on/off error output for the library. 121 * Parameter: 122 * set_do_print - Boolean that turns library error 123 * printing on or off. 124 * Returns: 125 * None 126 * Scope: 127 * Public; 128 */ 129 void 130 libbe_print_errors(boolean_t set_do_print) 131 { 132 do_print = set_do_print; 133 } 134 135 /* ******************************************************************** */ 136 /* Semi-Private Functions */ 137 /* ******************************************************************** */ 138 139 /* 140 * Function: be_zfs_init 141 * Description: Initializes the libary global libzfs handle. 142 * Parameters: 143 * None 144 * Returns: 145 * B_TRUE - Success 146 * B_FALSE - Failure 147 * Scope: 148 * Semi-private (library wide use only) 149 */ 150 boolean_t 151 be_zfs_init(void) 152 { 153 be_zfs_fini(); 154 155 if ((g_zfs = libzfs_init()) == NULL) { 156 be_print_err(gettext("be_zfs_init: failed to initialize ZFS " 157 "library\n")); 158 return (B_FALSE); 159 } 160 161 return (B_TRUE); 162 } 163 164 /* 165 * Function: be_zfs_fini 166 * Description: Closes the library global libzfs handle if it currently open. 167 * Parameter: 168 * None 169 * Returns: 170 * None 171 * Scope: 172 * Semi-private (library wide use only) 173 */ 174 void 175 be_zfs_fini(void) 176 { 177 if (g_zfs) 178 libzfs_fini(g_zfs); 179 180 g_zfs = NULL; 181 } 182 183 /* 184 * Function: be_get_defaults 185 * Description: Open defaults and gets be default paramets 186 * Parameters: 187 * defaults - be defaults struct 188 * Returns: 189 * None 190 * Scope: 191 * Semi-private (library wide use only) 192 */ 193 void 194 be_get_defaults(struct be_defaults *defaults) 195 { 196 void *defp; 197 198 defaults->be_deflt_rpool_container = B_FALSE; 199 defaults->be_deflt_bename_starts_with[0] = '\0'; 200 201 if ((defp = defopen_r(BE_DEFAULTS)) != NULL) { 202 const char *res = defread_r(BE_DFLT_BENAME_STARTS, defp); 203 if (res != NULL && res[0] != NULL) { 204 (void) strlcpy(defaults->be_deflt_bename_starts_with, 205 res, ZFS_MAX_DATASET_NAME_LEN); 206 defaults->be_deflt_rpool_container = B_TRUE; 207 } 208 defclose_r(defp); 209 } 210 } 211 212 /* 213 * Function: be_make_root_ds 214 * Description: Generate string for BE's root dataset given the pool 215 * it lives in and the BE name. 216 * Parameters: 217 * zpool - pointer zpool name. 218 * be_name - pointer to BE name. 219 * be_root_ds - pointer to buffer to return BE root dataset in. 220 * be_root_ds_size - size of be_root_ds 221 * Returns: 222 * None 223 * Scope: 224 * Semi-private (library wide use only) 225 */ 226 void 227 be_make_root_ds(const char *zpool, const char *be_name, char *be_root_ds, 228 int be_root_ds_size) 229 { 230 struct be_defaults be_defaults; 231 be_get_defaults(&be_defaults); 232 char *root_ds = NULL; 233 234 if (getzoneid() == GLOBAL_ZONEID) { 235 if (be_defaults.be_deflt_rpool_container) { 236 (void) snprintf(be_root_ds, be_root_ds_size, 237 "%s/%s", zpool, be_name); 238 } else { 239 (void) snprintf(be_root_ds, be_root_ds_size, 240 "%s/%s/%s", zpool, BE_CONTAINER_DS_NAME, be_name); 241 } 242 } else { 243 /* 244 * In non-global zone we can use path from mounted root dataset 245 * to generate BE's root dataset string. 246 */ 247 if ((root_ds = be_get_ds_from_dir("/")) != NULL) { 248 (void) snprintf(be_root_ds, be_root_ds_size, "%s/%s", 249 dirname(root_ds), be_name); 250 } else { 251 be_print_err(gettext("be_make_root_ds: zone root " 252 "dataset is not mounted\n")); 253 return; 254 } 255 } 256 } 257 258 /* 259 * Function: be_make_container_ds 260 * Description: Generate string for the BE container dataset given a pool name. 261 * Parameters: 262 * zpool - pointer zpool name. 263 * container_ds - pointer to buffer to return BE container 264 * dataset in. 265 * container_ds_size - size of container_ds 266 * Returns: 267 * None 268 * Scope: 269 * Semi-private (library wide use only) 270 */ 271 void 272 be_make_container_ds(const char *zpool, char *container_ds, 273 int container_ds_size) 274 { 275 struct be_defaults be_defaults; 276 be_get_defaults(&be_defaults); 277 char *root_ds = NULL; 278 279 if (getzoneid() == GLOBAL_ZONEID) { 280 if (be_defaults.be_deflt_rpool_container) { 281 (void) snprintf(container_ds, container_ds_size, 282 "%s", zpool); 283 } else { 284 (void) snprintf(container_ds, container_ds_size, 285 "%s/%s", zpool, BE_CONTAINER_DS_NAME); 286 } 287 } else { 288 if ((root_ds = be_get_ds_from_dir("/")) != NULL) { 289 (void) strlcpy(container_ds, dirname(root_ds), 290 container_ds_size); 291 } else { 292 be_print_err(gettext("be_make_container_ds: zone root " 293 "dataset is not mounted\n")); 294 return; 295 } 296 } 297 } 298 299 /* 300 * Function: be_make_name_from_ds 301 * Description: This function takes a dataset name and strips off the 302 * BE container dataset portion from the beginning. The 303 * returned name is allocated in heap storage, so the caller 304 * is responsible for freeing it. 305 * Parameters: 306 * dataset - dataset to get name from. 307 * rc_loc - dataset underwhich the root container dataset lives. 308 * Returns: 309 * name of dataset relative to BE container dataset. 310 * NULL if dataset is not under a BE root dataset. 311 * Scope: 312 * Semi-primate (library wide use only) 313 */ 314 char * 315 be_make_name_from_ds(const char *dataset, char *rc_loc) 316 { 317 char ds[ZFS_MAX_DATASET_NAME_LEN]; 318 char *tok = NULL; 319 char *name = NULL; 320 struct be_defaults be_defaults; 321 int rlen = strlen(rc_loc); 322 323 be_get_defaults(&be_defaults); 324 325 /* 326 * First token is the location of where the root container dataset 327 * lives; it must match rc_loc. 328 */ 329 if (strncmp(dataset, rc_loc, rlen) == 0 && dataset[rlen] == '/') 330 (void) strlcpy(ds, dataset + rlen + 1, sizeof (ds)); 331 else 332 return (NULL); 333 334 if (be_defaults.be_deflt_rpool_container) { 335 if ((name = strdup(ds)) == NULL) { 336 be_print_err(gettext("be_make_name_from_ds: " 337 "memory allocation failed\n")); 338 return (NULL); 339 } 340 } else { 341 /* Second token must be BE container dataset name */ 342 if ((tok = strtok(ds, "/")) == NULL || 343 strcmp(tok, BE_CONTAINER_DS_NAME) != 0) 344 return (NULL); 345 346 /* Return the remaining token if one exists */ 347 if ((tok = strtok(NULL, "")) == NULL) 348 return (NULL); 349 350 if ((name = strdup(tok)) == NULL) { 351 be_print_err(gettext("be_make_name_from_ds: " 352 "memory allocation failed\n")); 353 return (NULL); 354 } 355 } 356 357 return (name); 358 } 359 360 /* 361 * Function: be_maxsize_avail 362 * Description: Returns the available size for the zfs handle passed in. 363 * Parameters: 364 * zhp - A pointer to the open zfs handle. 365 * ret - The available size will be returned in this. 366 * Returns: 367 * The error returned by the zfs get property function. 368 * Scope: 369 * Semi-private (library wide use only) 370 */ 371 int 372 be_maxsize_avail(zfs_handle_t *zhp, uint64_t *ret) 373 { 374 return ((*ret = zfs_prop_get_int(zhp, ZFS_PROP_AVAILABLE))); 375 } 376 377 /* 378 * Function: be_append_menu 379 * Description: Appends an entry for a BE into the menu.lst. 380 * Parameters: 381 * be_name - pointer to name of BE to add boot menu entry for. 382 * be_root_pool - pointer to name of pool BE lives in. 383 * boot_pool - Used if the pool containing the grub menu is 384 * different than the one contaiing the BE. This 385 * will normally be NULL. 386 * be_orig_root_ds - The root dataset for the BE. This is 387 * used to check to see if an entry already exists 388 * for this BE. 389 * description - pointer to description of BE to be added in 390 * the title line for this BEs entry. 391 * Returns: 392 * BE_SUCCESS - Success 393 * be_errno_t - Failure 394 * Scope: 395 * Semi-private (library wide use only) 396 */ 397 int 398 be_append_menu(char *be_name, char *be_root_pool, char *boot_pool, 399 char *be_orig_root_ds, char *description) 400 { 401 zfs_handle_t *zhp = NULL; 402 char menu_file[MAXPATHLEN]; 403 char be_root_ds[MAXPATHLEN]; 404 char line[BUFSIZ]; 405 char temp_line[BUFSIZ]; 406 char title[MAXPATHLEN]; 407 char *entries[BUFSIZ]; 408 char *tmp_entries[BUFSIZ]; 409 char *pool_mntpnt = NULL; 410 char *ptmp_mntpnt = NULL; 411 char *orig_mntpnt = NULL; 412 boolean_t found_be = B_FALSE; 413 boolean_t found_orig_be = B_FALSE; 414 boolean_t found_title = B_FALSE; 415 boolean_t pool_mounted = B_FALSE; 416 boolean_t collect_lines = B_FALSE; 417 FILE *menu_fp = NULL; 418 int err = 0, ret = BE_SUCCESS; 419 int i, num_tmp_lines = 0, num_lines = 0; 420 421 if (be_name == NULL || be_root_pool == NULL) 422 return (BE_ERR_INVAL); 423 424 if (boot_pool == NULL) 425 boot_pool = be_root_pool; 426 427 if ((zhp = zfs_open(g_zfs, be_root_pool, ZFS_TYPE_DATASET)) == NULL) { 428 be_print_err(gettext("be_append_menu: failed to open " 429 "pool dataset for %s: %s\n"), be_root_pool, 430 libzfs_error_description(g_zfs)); 431 return (zfs_err_to_be_err(g_zfs)); 432 } 433 434 /* 435 * Check to see if the pool's dataset is mounted. If it isn't we'll 436 * attempt to mount it. 437 */ 438 if ((ret = be_mount_pool(zhp, &ptmp_mntpnt, &orig_mntpnt, 439 &pool_mounted)) != BE_SUCCESS) { 440 be_print_err(gettext("be_append_menu: pool dataset " 441 "(%s) could not be mounted\n"), be_root_pool); 442 ZFS_CLOSE(zhp); 443 return (ret); 444 } 445 446 /* 447 * Get the mountpoint for the root pool dataset. 448 */ 449 if (!zfs_is_mounted(zhp, &pool_mntpnt)) { 450 be_print_err(gettext("be_append_menu: pool " 451 "dataset (%s) is not mounted. Can't set " 452 "the default BE in the grub menu.\n"), be_root_pool); 453 ret = BE_ERR_NO_MENU; 454 goto cleanup; 455 } 456 457 /* 458 * Check to see if this system supports grub 459 */ 460 if (be_has_grub()) { 461 (void) snprintf(menu_file, sizeof (menu_file), 462 "%s%s", pool_mntpnt, BE_GRUB_MENU); 463 } else { 464 (void) snprintf(menu_file, sizeof (menu_file), 465 "%s%s", pool_mntpnt, BE_SPARC_MENU); 466 } 467 468 be_make_root_ds(be_root_pool, be_name, be_root_ds, sizeof (be_root_ds)); 469 470 /* 471 * Iterate through menu first to make sure the BE doesn't already 472 * have an entry in the menu. 473 * 474 * Additionally while iterating through the menu, if we have an 475 * original root dataset for a BE we're cloning from, we need to keep 476 * track of that BE's menu entry. We will then use the lines from 477 * that entry to create the entry for the new BE. 478 */ 479 if ((ret = be_open_menu(be_root_pool, menu_file, 480 &menu_fp, "r", B_TRUE)) != BE_SUCCESS) { 481 goto cleanup; 482 } else if (menu_fp == NULL) { 483 ret = BE_ERR_NO_MENU; 484 goto cleanup; 485 } 486 487 free(pool_mntpnt); 488 pool_mntpnt = NULL; 489 490 while (fgets(line, BUFSIZ, menu_fp)) { 491 char *tok = NULL; 492 493 (void) strlcpy(temp_line, line, BUFSIZ); 494 tok = strtok(line, BE_WHITE_SPACE); 495 496 if (tok == NULL || tok[0] == '#') { 497 continue; 498 } else if (strcmp(tok, "title") == 0) { 499 collect_lines = B_FALSE; 500 if ((tok = strtok(NULL, "\n")) == NULL) 501 (void) strlcpy(title, "", sizeof (title)); 502 else 503 (void) strlcpy(title, tok, sizeof (title)); 504 found_title = B_TRUE; 505 506 if (num_tmp_lines != 0) { 507 for (i = 0; i < num_tmp_lines; i++) { 508 free(tmp_entries[i]); 509 tmp_entries[i] = NULL; 510 } 511 num_tmp_lines = 0; 512 } 513 } else if (strcmp(tok, "bootfs") == 0) { 514 char *bootfs = strtok(NULL, BE_WHITE_SPACE); 515 found_title = B_FALSE; 516 if (bootfs == NULL) 517 continue; 518 519 if (strcmp(bootfs, be_root_ds) == 0) { 520 found_be = B_TRUE; 521 break; 522 } 523 524 if (be_orig_root_ds != NULL && 525 strcmp(bootfs, be_orig_root_ds) == 0 && 526 !found_orig_be) { 527 char str[BUFSIZ]; 528 found_orig_be = B_TRUE; 529 num_lines = 0; 530 /* 531 * Store the new title line 532 */ 533 (void) snprintf(str, BUFSIZ, "title %s\n", 534 description ? description : be_name); 535 entries[num_lines] = strdup(str); 536 num_lines++; 537 /* 538 * If there are any lines between the title 539 * and the bootfs line store these. Also 540 * free the temporary lines. 541 */ 542 for (i = 0; i < num_tmp_lines; i++) { 543 entries[num_lines] = tmp_entries[i]; 544 tmp_entries[i] = NULL; 545 num_lines++; 546 } 547 num_tmp_lines = 0; 548 /* 549 * Store the new bootfs line. 550 */ 551 (void) snprintf(str, BUFSIZ, "bootfs %s\n", 552 be_root_ds); 553 entries[num_lines] = strdup(str); 554 num_lines++; 555 collect_lines = B_TRUE; 556 } 557 } else if (found_orig_be && collect_lines) { 558 /* 559 * get the rest of the lines for the original BE and 560 * store them. 561 */ 562 if (strstr(line, BE_GRUB_COMMENT) != NULL || 563 strstr(line, "BOOTADM") != NULL) 564 continue; 565 if (strcmp(tok, "splashimage") == 0) { 566 entries[num_lines] = 567 strdup("splashimage " 568 "/boot/splashimage.xpm\n"); 569 } else { 570 entries[num_lines] = strdup(temp_line); 571 } 572 num_lines++; 573 } else if (found_title && !found_orig_be) { 574 tmp_entries[num_tmp_lines] = strdup(temp_line); 575 num_tmp_lines++; 576 } 577 } 578 579 (void) fclose(menu_fp); 580 581 if (found_be) { 582 /* 583 * If an entry for this BE was already in the menu, then if 584 * that entry's title matches what we would have put in 585 * return success. Otherwise return failure. 586 */ 587 char *new_title = description ? description : be_name; 588 589 if (strcmp(title, new_title) == 0) { 590 ret = BE_SUCCESS; 591 goto cleanup; 592 } else { 593 if (be_remove_menu(be_name, be_root_pool, 594 boot_pool) != BE_SUCCESS) { 595 be_print_err(gettext("be_append_menu: " 596 "Failed to remove existing unusable " 597 "entry '%s' in boot menu.\n"), be_name); 598 ret = BE_ERR_BE_EXISTS; 599 goto cleanup; 600 } 601 } 602 } 603 604 /* Append BE entry to the end of the file */ 605 menu_fp = fopen(menu_file, "a+"); 606 err = errno; 607 if (menu_fp == NULL) { 608 be_print_err(gettext("be_append_menu: failed " 609 "to open menu.lst file %s\n"), menu_file); 610 ret = errno_to_be_err(err); 611 goto cleanup; 612 } 613 614 if (found_orig_be) { 615 /* 616 * write out all the stored lines 617 */ 618 for (i = 0; i < num_lines; i++) { 619 (void) fprintf(menu_fp, "%s", entries[i]); 620 free(entries[i]); 621 } 622 num_lines = 0; 623 624 /* 625 * Check to see if this system supports grub 626 */ 627 if (be_has_grub()) 628 (void) fprintf(menu_fp, "%s\n", BE_GRUB_COMMENT); 629 ret = BE_SUCCESS; 630 } else { 631 (void) fprintf(menu_fp, "title %s\n", 632 description ? description : be_name); 633 (void) fprintf(menu_fp, "bootfs %s\n", be_root_ds); 634 635 /* 636 * Check to see if this system supports grub 637 */ 638 if (be_has_grub()) { 639 (void) fprintf(menu_fp, "kernel$ " 640 "/platform/i86pc/kernel/$ISADIR/unix -B " 641 "$ZFS-BOOTFS\n"); 642 (void) fprintf(menu_fp, "module$ " 643 "/platform/i86pc/$ISADIR/boot_archive\n"); 644 (void) fprintf(menu_fp, "%s\n", BE_GRUB_COMMENT); 645 } 646 ret = BE_SUCCESS; 647 } 648 (void) fclose(menu_fp); 649 cleanup: 650 if (pool_mounted) { 651 int err = BE_SUCCESS; 652 err = be_unmount_pool(zhp, ptmp_mntpnt, orig_mntpnt); 653 if (ret == BE_SUCCESS) 654 ret = err; 655 free(orig_mntpnt); 656 free(ptmp_mntpnt); 657 } 658 ZFS_CLOSE(zhp); 659 if (num_tmp_lines > 0) { 660 for (i = 0; i < num_tmp_lines; i++) { 661 free(tmp_entries[i]); 662 tmp_entries[i] = NULL; 663 } 664 } 665 if (num_lines > 0) { 666 for (i = 0; i < num_lines; i++) { 667 free(entries[i]); 668 entries[i] = NULL; 669 } 670 } 671 return (ret); 672 } 673 674 /* 675 * Function: be_remove_menu 676 * Description: Removes a BE's entry from a menu.lst file. 677 * Parameters: 678 * be_name - the name of BE whose entry is to be removed from 679 * the menu.lst file. 680 * be_root_pool - the pool that be_name lives in. 681 * boot_pool - the pool where the BE is, if different than 682 * the pool containing the boot menu. If this is 683 * NULL it will be set to be_root_pool. 684 * Returns: 685 * BE_SUCCESS - Success 686 * be_errno_t - Failure 687 * Scope: 688 * Semi-private (library wide use only) 689 */ 690 int 691 be_remove_menu(char *be_name, char *be_root_pool, char *boot_pool) 692 { 693 zfs_handle_t *zhp = NULL; 694 char be_root_ds[MAXPATHLEN]; 695 char **buffer = NULL; 696 char menu_buf[BUFSIZ]; 697 char menu[MAXPATHLEN]; 698 char *pool_mntpnt = NULL; 699 char *ptmp_mntpnt = NULL; 700 char *orig_mntpnt = NULL; 701 char *tmp_menu = NULL; 702 FILE *menu_fp = NULL; 703 FILE *tmp_menu_fp = NULL; 704 struct stat sb; 705 int ret = BE_SUCCESS; 706 int i; 707 int fd; 708 int err = 0; 709 int nlines = 0; 710 int default_entry = 0; 711 int entry_cnt = 0; 712 int entry_del = 0; 713 int num_entry_del = 0; 714 int tmp_menu_len = 0; 715 boolean_t write = B_TRUE; 716 boolean_t do_buffer = B_FALSE; 717 boolean_t pool_mounted = B_FALSE; 718 719 if (boot_pool == NULL) 720 boot_pool = be_root_pool; 721 722 /* Get name of BE's root dataset */ 723 be_make_root_ds(be_root_pool, be_name, be_root_ds, sizeof (be_root_ds)); 724 725 /* Get handle to pool dataset */ 726 if ((zhp = zfs_open(g_zfs, be_root_pool, ZFS_TYPE_DATASET)) == NULL) { 727 be_print_err(gettext("be_remove_menu: " 728 "failed to open pool dataset for %s: %s"), 729 be_root_pool, libzfs_error_description(g_zfs)); 730 return (zfs_err_to_be_err(g_zfs)); 731 } 732 733 /* 734 * Check to see if the pool's dataset is mounted. If it isn't we'll 735 * attempt to mount it. 736 */ 737 if ((ret = be_mount_pool(zhp, &ptmp_mntpnt, &orig_mntpnt, 738 &pool_mounted)) != BE_SUCCESS) { 739 be_print_err(gettext("be_remove_menu: pool dataset " 740 "(%s) could not be mounted\n"), be_root_pool); 741 ZFS_CLOSE(zhp); 742 return (ret); 743 } 744 745 /* 746 * Get the mountpoint for the root pool dataset. 747 */ 748 if (!zfs_is_mounted(zhp, &pool_mntpnt)) { 749 be_print_err(gettext("be_remove_menu: pool " 750 "dataset (%s) is not mounted. Can't set " 751 "the default BE in the grub menu.\n"), be_root_pool); 752 ret = BE_ERR_NO_MENU; 753 goto cleanup; 754 } 755 756 /* Get path to boot menu */ 757 (void) strlcpy(menu, pool_mntpnt, sizeof (menu)); 758 759 /* 760 * Check to see if this system supports grub 761 */ 762 if (be_has_grub()) 763 (void) strlcat(menu, BE_GRUB_MENU, sizeof (menu)); 764 else 765 (void) strlcat(menu, BE_SPARC_MENU, sizeof (menu)); 766 767 /* Get handle to boot menu file */ 768 if ((ret = be_open_menu(be_root_pool, menu, &menu_fp, "r", 769 B_TRUE)) != BE_SUCCESS) { 770 goto cleanup; 771 } else if (menu_fp == NULL) { 772 ret = BE_ERR_NO_MENU; 773 goto cleanup; 774 } 775 776 free(pool_mntpnt); 777 pool_mntpnt = NULL; 778 779 /* Grab the stats of the original menu file */ 780 if (stat(menu, &sb) != 0) { 781 err = errno; 782 be_print_err(gettext("be_remove_menu: " 783 "failed to stat file %s: %s\n"), menu, strerror(err)); 784 ret = errno_to_be_err(err); 785 goto cleanup; 786 } 787 788 /* Create a tmp file for the modified menu.lst */ 789 tmp_menu_len = strlen(menu) + 7; 790 if ((tmp_menu = (char *)malloc(tmp_menu_len)) == NULL) { 791 be_print_err(gettext("be_remove_menu: malloc failed\n")); 792 ret = BE_ERR_NOMEM; 793 goto cleanup; 794 } 795 (void) memset(tmp_menu, 0, tmp_menu_len); 796 (void) strlcpy(tmp_menu, menu, tmp_menu_len); 797 (void) strlcat(tmp_menu, "XXXXXX", tmp_menu_len); 798 if ((fd = mkstemp(tmp_menu)) == -1) { 799 err = errno; 800 be_print_err(gettext("be_remove_menu: mkstemp failed\n")); 801 ret = errno_to_be_err(err); 802 free(tmp_menu); 803 tmp_menu = NULL; 804 goto cleanup; 805 } 806 if ((tmp_menu_fp = fdopen(fd, "w")) == NULL) { 807 err = errno; 808 be_print_err(gettext("be_remove_menu: " 809 "could not open tmp file for write: %s\n"), strerror(err)); 810 (void) close(fd); 811 ret = errno_to_be_err(err); 812 goto cleanup; 813 } 814 815 while (fgets(menu_buf, BUFSIZ, menu_fp)) { 816 char tline [BUFSIZ]; 817 char *tok = NULL; 818 819 (void) strlcpy(tline, menu_buf, sizeof (tline)); 820 821 /* Tokenize line */ 822 tok = strtok(tline, BE_WHITE_SPACE); 823 824 if (tok == NULL || tok[0] == '#') { 825 /* Found empty line or comment line */ 826 if (do_buffer) { 827 /* Buffer this line */ 828 if ((buffer = (char **)realloc(buffer, 829 sizeof (char *)*(nlines + 1))) == NULL) { 830 ret = BE_ERR_NOMEM; 831 goto cleanup; 832 } 833 if ((buffer[nlines++] = strdup(menu_buf)) 834 == NULL) { 835 ret = BE_ERR_NOMEM; 836 goto cleanup; 837 } 838 839 } else if (write || strncmp(menu_buf, BE_GRUB_COMMENT, 840 strlen(BE_GRUB_COMMENT)) != 0) { 841 /* Write this line out */ 842 (void) fputs(menu_buf, tmp_menu_fp); 843 } 844 } else if (strcmp(tok, "default") == 0) { 845 /* 846 * Record what 'default' is set to because we might 847 * need to adjust this upon deleting an entry. 848 */ 849 tok = strtok(NULL, BE_WHITE_SPACE); 850 851 if (tok != NULL) { 852 default_entry = atoi(tok); 853 } 854 855 (void) fputs(menu_buf, tmp_menu_fp); 856 } else if (strcmp(tok, "title") == 0) { 857 /* 858 * If we've reached a 'title' line and do_buffer is 859 * is true, that means we've just buffered an entire 860 * entry without finding a 'bootfs' directive. We 861 * need to write that entry out and keep searching. 862 */ 863 if (do_buffer) { 864 for (i = 0; i < nlines; i++) { 865 (void) fputs(buffer[i], tmp_menu_fp); 866 free(buffer[i]); 867 } 868 free(buffer); 869 buffer = NULL; 870 nlines = 0; 871 } 872 873 /* 874 * Turn writing off and buffering on, and increment 875 * our entry counter. 876 */ 877 write = B_FALSE; 878 do_buffer = B_TRUE; 879 entry_cnt++; 880 881 /* Buffer this 'title' line */ 882 if ((buffer = (char **)realloc(buffer, 883 sizeof (char *)*(nlines + 1))) == NULL) { 884 ret = BE_ERR_NOMEM; 885 goto cleanup; 886 } 887 if ((buffer[nlines++] = strdup(menu_buf)) == NULL) { 888 ret = BE_ERR_NOMEM; 889 goto cleanup; 890 } 891 892 } else if (strcmp(tok, "bootfs") == 0) { 893 char *bootfs = NULL; 894 895 /* 896 * Found a 'bootfs' line. See if it matches the 897 * BE we're looking for. 898 */ 899 if ((bootfs = strtok(NULL, BE_WHITE_SPACE)) == NULL || 900 strcmp(bootfs, be_root_ds) != 0) { 901 /* 902 * Either there's nothing after the 'bootfs' 903 * or this is not the BE we're looking for, 904 * write out the line(s) we've buffered since 905 * finding the title. 906 */ 907 for (i = 0; i < nlines; i++) { 908 (void) fputs(buffer[i], tmp_menu_fp); 909 free(buffer[i]); 910 } 911 free(buffer); 912 buffer = NULL; 913 nlines = 0; 914 915 /* 916 * Turn writing back on, and turn off buffering 917 * since this isn't the entry we're looking 918 * for. 919 */ 920 write = B_TRUE; 921 do_buffer = B_FALSE; 922 923 /* Write this 'bootfs' line out. */ 924 (void) fputs(menu_buf, tmp_menu_fp); 925 } else { 926 /* 927 * Found the entry we're looking for. 928 * Record its entry number, increment the 929 * number of entries we've deleted, and turn 930 * writing off. Also, throw away the lines 931 * we've buffered for this entry so far, we 932 * don't need them. 933 */ 934 entry_del = entry_cnt - 1; 935 num_entry_del++; 936 write = B_FALSE; 937 do_buffer = B_FALSE; 938 939 for (i = 0; i < nlines; i++) { 940 free(buffer[i]); 941 } 942 free(buffer); 943 buffer = NULL; 944 nlines = 0; 945 } 946 } else { 947 if (do_buffer) { 948 /* Buffer this line */ 949 if ((buffer = (char **)realloc(buffer, 950 sizeof (char *)*(nlines + 1))) == NULL) { 951 ret = BE_ERR_NOMEM; 952 goto cleanup; 953 } 954 if ((buffer[nlines++] = strdup(menu_buf)) 955 == NULL) { 956 ret = BE_ERR_NOMEM; 957 goto cleanup; 958 } 959 } else if (write) { 960 /* Write this line out */ 961 (void) fputs(menu_buf, tmp_menu_fp); 962 } 963 } 964 } 965 966 (void) fclose(menu_fp); 967 menu_fp = NULL; 968 (void) fclose(tmp_menu_fp); 969 tmp_menu_fp = NULL; 970 971 /* Copy the modified menu.lst into place */ 972 if (rename(tmp_menu, menu) != 0) { 973 err = errno; 974 be_print_err(gettext("be_remove_menu: " 975 "failed to rename file %s to %s: %s\n"), 976 tmp_menu, menu, strerror(err)); 977 ret = errno_to_be_err(err); 978 goto cleanup; 979 } 980 free(tmp_menu); 981 tmp_menu = NULL; 982 983 /* 984 * If we've removed an entry, see if we need to 985 * adjust the default value in the menu.lst. If the 986 * entry we've deleted comes before the default entry 987 * we need to adjust the default value accordingly. 988 * 989 * be_has_grub is used here to check to see if this system 990 * supports grub. 991 */ 992 if (be_has_grub() && num_entry_del > 0) { 993 if (entry_del <= default_entry) { 994 default_entry = default_entry - num_entry_del; 995 if (default_entry < 0) 996 default_entry = 0; 997 998 /* 999 * Adjust the default value by rewriting the 1000 * menu.lst file. This may be overkill, but to 1001 * preserve the location of the 'default' entry 1002 * in the file, we need to do this. 1003 */ 1004 1005 /* Get handle to boot menu file */ 1006 if ((menu_fp = fopen(menu, "r")) == NULL) { 1007 err = errno; 1008 be_print_err(gettext("be_remove_menu: " 1009 "failed to open menu.lst (%s): %s\n"), 1010 menu, strerror(err)); 1011 ret = errno_to_be_err(err); 1012 goto cleanup; 1013 } 1014 1015 /* Create a tmp file for the modified menu.lst */ 1016 tmp_menu_len = strlen(menu) + 7; 1017 if ((tmp_menu = (char *)malloc(tmp_menu_len)) 1018 == NULL) { 1019 be_print_err(gettext("be_remove_menu: " 1020 "malloc failed\n")); 1021 ret = BE_ERR_NOMEM; 1022 goto cleanup; 1023 } 1024 (void) memset(tmp_menu, 0, tmp_menu_len); 1025 (void) strlcpy(tmp_menu, menu, tmp_menu_len); 1026 (void) strlcat(tmp_menu, "XXXXXX", tmp_menu_len); 1027 if ((fd = mkstemp(tmp_menu)) == -1) { 1028 err = errno; 1029 be_print_err(gettext("be_remove_menu: " 1030 "mkstemp failed: %s\n"), strerror(err)); 1031 ret = errno_to_be_err(err); 1032 free(tmp_menu); 1033 tmp_menu = NULL; 1034 goto cleanup; 1035 } 1036 if ((tmp_menu_fp = fdopen(fd, "w")) == NULL) { 1037 err = errno; 1038 be_print_err(gettext("be_remove_menu: " 1039 "could not open tmp file for write: %s\n"), 1040 strerror(err)); 1041 (void) close(fd); 1042 ret = errno_to_be_err(err); 1043 goto cleanup; 1044 } 1045 1046 while (fgets(menu_buf, BUFSIZ, menu_fp)) { 1047 char tline [BUFSIZ]; 1048 char *tok = NULL; 1049 1050 (void) strlcpy(tline, menu_buf, sizeof (tline)); 1051 1052 /* Tokenize line */ 1053 tok = strtok(tline, BE_WHITE_SPACE); 1054 1055 if (tok == NULL) { 1056 /* Found empty line, write it out */ 1057 (void) fputs(menu_buf, tmp_menu_fp); 1058 } else if (strcmp(tok, "default") == 0) { 1059 /* Found the default line, adjust it */ 1060 (void) snprintf(tline, sizeof (tline), 1061 "default %d\n", default_entry); 1062 1063 (void) fputs(tline, tmp_menu_fp); 1064 } else { 1065 /* Pass through all other lines */ 1066 (void) fputs(menu_buf, tmp_menu_fp); 1067 } 1068 } 1069 1070 (void) fclose(menu_fp); 1071 menu_fp = NULL; 1072 (void) fclose(tmp_menu_fp); 1073 tmp_menu_fp = NULL; 1074 1075 /* Copy the modified menu.lst into place */ 1076 if (rename(tmp_menu, menu) != 0) { 1077 err = errno; 1078 be_print_err(gettext("be_remove_menu: " 1079 "failed to rename file %s to %s: %s\n"), 1080 tmp_menu, menu, strerror(err)); 1081 ret = errno_to_be_err(err); 1082 goto cleanup; 1083 } 1084 1085 free(tmp_menu); 1086 tmp_menu = NULL; 1087 } 1088 } 1089 1090 /* Set the perms and ownership of the updated file */ 1091 if (chmod(menu, sb.st_mode) != 0) { 1092 err = errno; 1093 be_print_err(gettext("be_remove_menu: " 1094 "failed to chmod %s: %s\n"), menu, strerror(err)); 1095 ret = errno_to_be_err(err); 1096 goto cleanup; 1097 } 1098 if (chown(menu, sb.st_uid, sb.st_gid) != 0) { 1099 err = errno; 1100 be_print_err(gettext("be_remove_menu: " 1101 "failed to chown %s: %s\n"), menu, strerror(err)); 1102 ret = errno_to_be_err(err); 1103 goto cleanup; 1104 } 1105 1106 cleanup: 1107 if (pool_mounted) { 1108 int err = BE_SUCCESS; 1109 err = be_unmount_pool(zhp, ptmp_mntpnt, orig_mntpnt); 1110 if (ret == BE_SUCCESS) 1111 ret = err; 1112 free(orig_mntpnt); 1113 free(ptmp_mntpnt); 1114 } 1115 ZFS_CLOSE(zhp); 1116 1117 free(buffer); 1118 if (menu_fp != NULL) 1119 (void) fclose(menu_fp); 1120 if (tmp_menu_fp != NULL) 1121 (void) fclose(tmp_menu_fp); 1122 if (tmp_menu != NULL) { 1123 (void) unlink(tmp_menu); 1124 free(tmp_menu); 1125 } 1126 1127 return (ret); 1128 } 1129 1130 /* 1131 * Function: be_default_grub_bootfs 1132 * Description: This function returns the dataset in the default entry of 1133 * the grub menu. If no default entry is found with a valid bootfs 1134 * entry NULL is returned. 1135 * Parameters: 1136 * be_root_pool - This is the name of the root pool where the 1137 * grub menu can be found. 1138 * def_bootfs - This is used to pass back the bootfs string. On 1139 * error NULL is returned here. 1140 * Returns: 1141 * Success - BE_SUCCESS is returned. 1142 * Failure - a be_errno_t is returned. 1143 * Scope: 1144 * Semi-private (library wide use only) 1145 */ 1146 int 1147 be_default_grub_bootfs(const char *be_root_pool, char **def_bootfs) 1148 { 1149 zfs_handle_t *zhp = NULL; 1150 char grub_file[MAXPATHLEN]; 1151 FILE *menu_fp; 1152 char line[BUFSIZ]; 1153 char *pool_mntpnt = NULL; 1154 char *ptmp_mntpnt = NULL; 1155 char *orig_mntpnt = NULL; 1156 int default_entry = 0, entries = 0; 1157 int found_default = 0; 1158 int ret = BE_SUCCESS; 1159 boolean_t pool_mounted = B_FALSE; 1160 1161 errno = 0; 1162 1163 /* 1164 * Check to see if this system supports grub 1165 */ 1166 if (!be_has_grub()) { 1167 be_print_err(gettext("be_default_grub_bootfs: operation " 1168 "not supported on this architecture\n")); 1169 return (BE_ERR_NOTSUP); 1170 } 1171 1172 *def_bootfs = NULL; 1173 1174 /* Get handle to pool dataset */ 1175 if ((zhp = zfs_open(g_zfs, be_root_pool, ZFS_TYPE_DATASET)) == NULL) { 1176 be_print_err(gettext("be_default_grub_bootfs: " 1177 "failed to open pool dataset for %s: %s"), 1178 be_root_pool, libzfs_error_description(g_zfs)); 1179 return (zfs_err_to_be_err(g_zfs)); 1180 } 1181 1182 /* 1183 * Check to see if the pool's dataset is mounted. If it isn't we'll 1184 * attempt to mount it. 1185 */ 1186 if ((ret = be_mount_pool(zhp, &ptmp_mntpnt, &orig_mntpnt, 1187 &pool_mounted)) != BE_SUCCESS) { 1188 be_print_err(gettext("be_default_grub_bootfs: pool dataset " 1189 "(%s) could not be mounted\n"), be_root_pool); 1190 ZFS_CLOSE(zhp); 1191 return (ret); 1192 } 1193 1194 /* 1195 * Get the mountpoint for the root pool dataset. 1196 */ 1197 if (!zfs_is_mounted(zhp, &pool_mntpnt)) { 1198 be_print_err(gettext("be_default_grub_bootfs: failed " 1199 "to get mount point for the root pool. Can't set " 1200 "the default BE in the grub menu.\n")); 1201 ret = BE_ERR_NO_MENU; 1202 goto cleanup; 1203 } 1204 1205 (void) snprintf(grub_file, MAXPATHLEN, "%s%s", 1206 pool_mntpnt, BE_GRUB_MENU); 1207 1208 if ((ret = be_open_menu((char *)be_root_pool, grub_file, 1209 &menu_fp, "r", B_FALSE)) != BE_SUCCESS) { 1210 goto cleanup; 1211 } else if (menu_fp == NULL) { 1212 ret = BE_ERR_NO_MENU; 1213 goto cleanup; 1214 } 1215 1216 free(pool_mntpnt); 1217 pool_mntpnt = NULL; 1218 1219 while (fgets(line, BUFSIZ, menu_fp)) { 1220 char *tok = strtok(line, BE_WHITE_SPACE); 1221 1222 if (tok != NULL && tok[0] != '#') { 1223 if (!found_default) { 1224 if (strcmp(tok, "default") == 0) { 1225 tok = strtok(NULL, BE_WHITE_SPACE); 1226 if (tok != NULL) { 1227 default_entry = atoi(tok); 1228 rewind(menu_fp); 1229 found_default = 1; 1230 } 1231 } 1232 continue; 1233 } 1234 if (strcmp(tok, "title") == 0) { 1235 entries++; 1236 } else if (default_entry == entries - 1) { 1237 if (strcmp(tok, "bootfs") == 0) { 1238 tok = strtok(NULL, BE_WHITE_SPACE); 1239 (void) fclose(menu_fp); 1240 1241 if (tok == NULL) { 1242 ret = BE_SUCCESS; 1243 goto cleanup; 1244 } 1245 1246 if ((*def_bootfs = strdup(tok)) != 1247 NULL) { 1248 ret = BE_SUCCESS; 1249 goto cleanup; 1250 } 1251 be_print_err(gettext( 1252 "be_default_grub_bootfs: " 1253 "memory allocation failed\n")); 1254 ret = BE_ERR_NOMEM; 1255 goto cleanup; 1256 } 1257 } else if (default_entry < entries - 1) { 1258 /* 1259 * no bootfs entry for the default entry. 1260 */ 1261 break; 1262 } 1263 } 1264 } 1265 (void) fclose(menu_fp); 1266 1267 cleanup: 1268 if (pool_mounted) { 1269 int err = BE_SUCCESS; 1270 err = be_unmount_pool(zhp, ptmp_mntpnt, orig_mntpnt); 1271 if (ret == BE_SUCCESS) 1272 ret = err; 1273 free(orig_mntpnt); 1274 free(ptmp_mntpnt); 1275 } 1276 ZFS_CLOSE(zhp); 1277 return (ret); 1278 } 1279 1280 /* 1281 * Function: be_change_grub_default 1282 * Description: This function takes two parameters. These are the name of 1283 * the BE we want to have as the default booted in the grub 1284 * menu and the root pool where the path to the grub menu exists. 1285 * The code takes this and finds the BE's entry in the grub menu 1286 * and changes the default entry to point to that entry in the 1287 * list. 1288 * Parameters: 1289 * be_name - This is the name of the BE wanted as the default 1290 * for the next boot. 1291 * be_root_pool - This is the name of the root pool where the 1292 * grub menu can be found. 1293 * Returns: 1294 * BE_SUCCESS - Success 1295 * be_errno_t - Failure 1296 * Scope: 1297 * Semi-private (library wide use only) 1298 */ 1299 int 1300 be_change_grub_default(char *be_name, char *be_root_pool) 1301 { 1302 zfs_handle_t *zhp = NULL; 1303 char grub_file[MAXPATHLEN]; 1304 char *temp_grub; 1305 char *pool_mntpnt = NULL; 1306 char *ptmp_mntpnt = NULL; 1307 char *orig_mntpnt = NULL; 1308 char line[BUFSIZ]; 1309 char temp_line[BUFSIZ]; 1310 char be_root_ds[MAXPATHLEN]; 1311 FILE *grub_fp = NULL; 1312 FILE *temp_fp = NULL; 1313 struct stat sb; 1314 int temp_grub_len = 0; 1315 int fd, entries = 0; 1316 int err = 0; 1317 int ret = BE_SUCCESS; 1318 boolean_t found_default = B_FALSE; 1319 boolean_t pool_mounted = B_FALSE; 1320 1321 errno = 0; 1322 1323 /* 1324 * Check to see if this system supports grub 1325 */ 1326 if (!be_has_grub()) { 1327 be_print_err(gettext("be_change_grub_default: operation " 1328 "not supported on this architecture\n")); 1329 return (BE_ERR_NOTSUP); 1330 } 1331 1332 /* Generate string for BE's root dataset */ 1333 be_make_root_ds(be_root_pool, be_name, be_root_ds, sizeof (be_root_ds)); 1334 1335 /* Get handle to pool dataset */ 1336 if ((zhp = zfs_open(g_zfs, be_root_pool, ZFS_TYPE_DATASET)) == NULL) { 1337 be_print_err(gettext("be_change_grub_default: " 1338 "failed to open pool dataset for %s: %s"), 1339 be_root_pool, libzfs_error_description(g_zfs)); 1340 return (zfs_err_to_be_err(g_zfs)); 1341 } 1342 1343 /* 1344 * Check to see if the pool's dataset is mounted. If it isn't we'll 1345 * attempt to mount it. 1346 */ 1347 if ((ret = be_mount_pool(zhp, &ptmp_mntpnt, &orig_mntpnt, 1348 &pool_mounted)) != BE_SUCCESS) { 1349 be_print_err(gettext("be_change_grub_default: pool dataset " 1350 "(%s) could not be mounted\n"), be_root_pool); 1351 ZFS_CLOSE(zhp); 1352 return (ret); 1353 } 1354 1355 /* 1356 * Get the mountpoint for the root pool dataset. 1357 */ 1358 if (!zfs_is_mounted(zhp, &pool_mntpnt)) { 1359 be_print_err(gettext("be_change_grub_default: pool " 1360 "dataset (%s) is not mounted. Can't set " 1361 "the default BE in the grub menu.\n"), be_root_pool); 1362 ret = BE_ERR_NO_MENU; 1363 goto cleanup; 1364 } 1365 1366 (void) snprintf(grub_file, MAXPATHLEN, "%s%s", 1367 pool_mntpnt, BE_GRUB_MENU); 1368 1369 if ((ret = be_open_menu(be_root_pool, grub_file, 1370 &grub_fp, "r+", B_TRUE)) != BE_SUCCESS) { 1371 goto cleanup; 1372 } else if (grub_fp == NULL) { 1373 ret = BE_ERR_NO_MENU; 1374 goto cleanup; 1375 } 1376 1377 free(pool_mntpnt); 1378 pool_mntpnt = NULL; 1379 1380 /* Grab the stats of the original menu file */ 1381 if (stat(grub_file, &sb) != 0) { 1382 err = errno; 1383 be_print_err(gettext("be_change_grub_default: " 1384 "failed to stat file %s: %s\n"), grub_file, strerror(err)); 1385 ret = errno_to_be_err(err); 1386 goto cleanup; 1387 } 1388 1389 /* Create a tmp file for the modified menu.lst */ 1390 temp_grub_len = strlen(grub_file) + 7; 1391 if ((temp_grub = (char *)malloc(temp_grub_len)) == NULL) { 1392 be_print_err(gettext("be_change_grub_default: " 1393 "malloc failed\n")); 1394 ret = BE_ERR_NOMEM; 1395 goto cleanup; 1396 } 1397 (void) memset(temp_grub, 0, temp_grub_len); 1398 (void) strlcpy(temp_grub, grub_file, temp_grub_len); 1399 (void) strlcat(temp_grub, "XXXXXX", temp_grub_len); 1400 if ((fd = mkstemp(temp_grub)) == -1) { 1401 err = errno; 1402 be_print_err(gettext("be_change_grub_default: " 1403 "mkstemp failed: %s\n"), strerror(err)); 1404 ret = errno_to_be_err(err); 1405 free(temp_grub); 1406 temp_grub = NULL; 1407 goto cleanup; 1408 } 1409 if ((temp_fp = fdopen(fd, "w")) == NULL) { 1410 err = errno; 1411 be_print_err(gettext("be_change_grub_default: " 1412 "failed to open %s file: %s\n"), 1413 temp_grub, strerror(err)); 1414 (void) close(fd); 1415 ret = errno_to_be_err(err); 1416 goto cleanup; 1417 } 1418 1419 while (fgets(line, BUFSIZ, grub_fp)) { 1420 char *tok = strtok(line, BE_WHITE_SPACE); 1421 1422 if (tok == NULL || tok[0] == '#') { 1423 continue; 1424 } else if (strcmp(tok, "title") == 0) { 1425 entries++; 1426 continue; 1427 } else if (strcmp(tok, "bootfs") == 0) { 1428 char *bootfs = strtok(NULL, BE_WHITE_SPACE); 1429 if (bootfs == NULL) 1430 continue; 1431 1432 if (strcmp(bootfs, be_root_ds) == 0) { 1433 found_default = B_TRUE; 1434 break; 1435 } 1436 } 1437 } 1438 1439 if (!found_default) { 1440 be_print_err(gettext("be_change_grub_default: failed " 1441 "to find entry for %s in the grub menu\n"), 1442 be_name); 1443 ret = BE_ERR_BE_NOENT; 1444 goto cleanup; 1445 } 1446 1447 rewind(grub_fp); 1448 1449 while (fgets(line, BUFSIZ, grub_fp)) { 1450 char *tok = NULL; 1451 1452 (void) strncpy(temp_line, line, BUFSIZ); 1453 1454 if ((tok = strtok(temp_line, BE_WHITE_SPACE)) != NULL && 1455 strcmp(tok, "default") == 0) { 1456 (void) snprintf(temp_line, BUFSIZ, "default %d\n", 1457 entries - 1 >= 0 ? entries - 1 : 0); 1458 (void) fputs(temp_line, temp_fp); 1459 } else { 1460 (void) fputs(line, temp_fp); 1461 } 1462 } 1463 1464 (void) fclose(grub_fp); 1465 grub_fp = NULL; 1466 (void) fclose(temp_fp); 1467 temp_fp = NULL; 1468 1469 if (rename(temp_grub, grub_file) != 0) { 1470 err = errno; 1471 be_print_err(gettext("be_change_grub_default: " 1472 "failed to rename file %s to %s: %s\n"), 1473 temp_grub, grub_file, strerror(err)); 1474 ret = errno_to_be_err(err); 1475 goto cleanup; 1476 } 1477 free(temp_grub); 1478 temp_grub = NULL; 1479 1480 /* Set the perms and ownership of the updated file */ 1481 if (chmod(grub_file, sb.st_mode) != 0) { 1482 err = errno; 1483 be_print_err(gettext("be_change_grub_default: " 1484 "failed to chmod %s: %s\n"), grub_file, strerror(err)); 1485 ret = errno_to_be_err(err); 1486 goto cleanup; 1487 } 1488 if (chown(grub_file, sb.st_uid, sb.st_gid) != 0) { 1489 err = errno; 1490 be_print_err(gettext("be_change_grub_default: " 1491 "failed to chown %s: %s\n"), grub_file, strerror(err)); 1492 ret = errno_to_be_err(err); 1493 } 1494 1495 cleanup: 1496 if (pool_mounted) { 1497 int err = BE_SUCCESS; 1498 err = be_unmount_pool(zhp, ptmp_mntpnt, orig_mntpnt); 1499 if (ret == BE_SUCCESS) 1500 ret = err; 1501 free(orig_mntpnt); 1502 free(ptmp_mntpnt); 1503 } 1504 ZFS_CLOSE(zhp); 1505 if (grub_fp != NULL) 1506 (void) fclose(grub_fp); 1507 if (temp_fp != NULL) 1508 (void) fclose(temp_fp); 1509 if (temp_grub != NULL) { 1510 (void) unlink(temp_grub); 1511 free(temp_grub); 1512 } 1513 1514 return (ret); 1515 } 1516 1517 /* 1518 * Function: be_update_menu 1519 * Description: This function is used by be_rename to change the BE name in 1520 * an existing entry in the grub menu to the new name of the BE. 1521 * Parameters: 1522 * be_orig_name - the original name of the BE 1523 * be_new_name - the new name the BE is being renameed to. 1524 * be_root_pool - The pool which contains the grub menu 1525 * boot_pool - the pool where the BE is, if different than 1526 * the pool containing the boot menu. If this is 1527 * NULL it will be set to be_root_pool. 1528 * Returns: 1529 * BE_SUCCESS - Success 1530 * be_errno_t - Failure 1531 * Scope: 1532 * Semi-private (library wide use only) 1533 */ 1534 int 1535 be_update_menu(char *be_orig_name, char *be_new_name, char *be_root_pool, 1536 char *boot_pool) 1537 { 1538 zfs_handle_t *zhp = NULL; 1539 char menu_file[MAXPATHLEN]; 1540 char be_root_ds[MAXPATHLEN]; 1541 char be_new_root_ds[MAXPATHLEN]; 1542 char line[BUFSIZ]; 1543 char *pool_mntpnt = NULL; 1544 char *ptmp_mntpnt = NULL; 1545 char *orig_mntpnt = NULL; 1546 char *temp_menu = NULL; 1547 FILE *menu_fp = NULL; 1548 FILE *new_fp = NULL; 1549 struct stat sb; 1550 int temp_menu_len = 0; 1551 int tmp_fd; 1552 int ret = BE_SUCCESS; 1553 int err = 0; 1554 boolean_t pool_mounted = B_FALSE; 1555 1556 errno = 0; 1557 1558 if (boot_pool == NULL) 1559 boot_pool = be_root_pool; 1560 1561 if ((zhp = zfs_open(g_zfs, be_root_pool, ZFS_TYPE_DATASET)) == NULL) { 1562 be_print_err(gettext("be_update_menu: failed to open " 1563 "pool dataset for %s: %s\n"), be_root_pool, 1564 libzfs_error_description(g_zfs)); 1565 return (zfs_err_to_be_err(g_zfs)); 1566 } 1567 1568 /* 1569 * Check to see if the pool's dataset is mounted. If it isn't we'll 1570 * attempt to mount it. 1571 */ 1572 if ((ret = be_mount_pool(zhp, &ptmp_mntpnt, &orig_mntpnt, 1573 &pool_mounted)) != BE_SUCCESS) { 1574 be_print_err(gettext("be_update_menu: pool dataset " 1575 "(%s) could not be mounted\n"), be_root_pool); 1576 ZFS_CLOSE(zhp); 1577 return (ret); 1578 } 1579 1580 /* 1581 * Get the mountpoint for the root pool dataset. 1582 */ 1583 if (!zfs_is_mounted(zhp, &pool_mntpnt)) { 1584 be_print_err(gettext("be_update_menu: failed " 1585 "to get mount point for the root pool. Can't set " 1586 "the default BE in the grub menu.\n")); 1587 ret = BE_ERR_NO_MENU; 1588 goto cleanup; 1589 } 1590 1591 /* 1592 * Check to see if this system supports grub 1593 */ 1594 if (be_has_grub()) { 1595 (void) snprintf(menu_file, sizeof (menu_file), 1596 "%s%s", pool_mntpnt, BE_GRUB_MENU); 1597 } else { 1598 (void) snprintf(menu_file, sizeof (menu_file), 1599 "%s%s", pool_mntpnt, BE_SPARC_MENU); 1600 } 1601 1602 be_make_root_ds(be_root_pool, be_orig_name, be_root_ds, 1603 sizeof (be_root_ds)); 1604 be_make_root_ds(be_root_pool, be_new_name, be_new_root_ds, 1605 sizeof (be_new_root_ds)); 1606 1607 if ((ret = be_open_menu(be_root_pool, menu_file, 1608 &menu_fp, "r", B_TRUE)) != BE_SUCCESS) { 1609 goto cleanup; 1610 } else if (menu_fp == NULL) { 1611 ret = BE_ERR_NO_MENU; 1612 goto cleanup; 1613 } 1614 1615 free(pool_mntpnt); 1616 pool_mntpnt = NULL; 1617 1618 /* Grab the stat of the original menu file */ 1619 if (stat(menu_file, &sb) != 0) { 1620 err = errno; 1621 be_print_err(gettext("be_update_menu: " 1622 "failed to stat file %s: %s\n"), menu_file, strerror(err)); 1623 (void) fclose(menu_fp); 1624 ret = errno_to_be_err(err); 1625 goto cleanup; 1626 } 1627 1628 /* Create tmp file for modified menu.lst */ 1629 temp_menu_len = strlen(menu_file) + 7; 1630 if ((temp_menu = (char *)malloc(temp_menu_len)) 1631 == NULL) { 1632 be_print_err(gettext("be_update_menu: " 1633 "malloc failed\n")); 1634 (void) fclose(menu_fp); 1635 ret = BE_ERR_NOMEM; 1636 goto cleanup; 1637 } 1638 (void) memset(temp_menu, 0, temp_menu_len); 1639 (void) strlcpy(temp_menu, menu_file, temp_menu_len); 1640 (void) strlcat(temp_menu, "XXXXXX", temp_menu_len); 1641 if ((tmp_fd = mkstemp(temp_menu)) == -1) { 1642 err = errno; 1643 be_print_err(gettext("be_update_menu: " 1644 "mkstemp failed: %s\n"), strerror(err)); 1645 (void) fclose(menu_fp); 1646 free(temp_menu); 1647 ret = errno_to_be_err(err); 1648 goto cleanup; 1649 } 1650 if ((new_fp = fdopen(tmp_fd, "w")) == NULL) { 1651 err = errno; 1652 be_print_err(gettext("be_update_menu: " 1653 "fdopen failed: %s\n"), strerror(err)); 1654 (void) close(tmp_fd); 1655 (void) fclose(menu_fp); 1656 free(temp_menu); 1657 ret = errno_to_be_err(err); 1658 goto cleanup; 1659 } 1660 1661 while (fgets(line, BUFSIZ, menu_fp)) { 1662 char tline[BUFSIZ]; 1663 char new_line[BUFSIZ]; 1664 char *c = NULL; 1665 1666 (void) strlcpy(tline, line, sizeof (tline)); 1667 1668 /* Tokenize line */ 1669 c = strtok(tline, BE_WHITE_SPACE); 1670 1671 if (c == NULL) { 1672 /* Found empty line, write it out. */ 1673 (void) fputs(line, new_fp); 1674 } else if (c[0] == '#') { 1675 /* Found a comment line, write it out. */ 1676 (void) fputs(line, new_fp); 1677 } else if (strcmp(c, "title") == 0) { 1678 char *name = NULL; 1679 char *desc = NULL; 1680 1681 /* 1682 * Found a 'title' line, parse out BE name or 1683 * the description. 1684 */ 1685 name = strtok(NULL, BE_WHITE_SPACE); 1686 1687 if (name == NULL) { 1688 /* 1689 * Nothing after 'title', just push 1690 * this line through 1691 */ 1692 (void) fputs(line, new_fp); 1693 } else { 1694 /* 1695 * Grab the remainder of the title which 1696 * could be a multi worded description 1697 */ 1698 desc = strtok(NULL, "\n"); 1699 1700 if (strcmp(name, be_orig_name) == 0) { 1701 /* 1702 * The first token of the title is 1703 * the old BE name, replace it with 1704 * the new one, and write it out 1705 * along with the remainder of 1706 * description if there is one. 1707 */ 1708 if (desc) { 1709 (void) snprintf(new_line, 1710 sizeof (new_line), 1711 "title %s %s\n", 1712 be_new_name, desc); 1713 } else { 1714 (void) snprintf(new_line, 1715 sizeof (new_line), 1716 "title %s\n", be_new_name); 1717 } 1718 1719 (void) fputs(new_line, new_fp); 1720 } else { 1721 (void) fputs(line, new_fp); 1722 } 1723 } 1724 } else if (strcmp(c, "bootfs") == 0) { 1725 /* 1726 * Found a 'bootfs' line, parse out the BE root 1727 * dataset value. 1728 */ 1729 char *root_ds = strtok(NULL, BE_WHITE_SPACE); 1730 1731 if (root_ds == NULL) { 1732 /* 1733 * Nothing after 'bootfs', just push 1734 * this line through 1735 */ 1736 (void) fputs(line, new_fp); 1737 } else { 1738 /* 1739 * If this bootfs is the one we're renaming, 1740 * write out the new root dataset value 1741 */ 1742 if (strcmp(root_ds, be_root_ds) == 0) { 1743 (void) snprintf(new_line, 1744 sizeof (new_line), "bootfs %s\n", 1745 be_new_root_ds); 1746 1747 (void) fputs(new_line, new_fp); 1748 } else { 1749 (void) fputs(line, new_fp); 1750 } 1751 } 1752 } else { 1753 /* 1754 * Found some other line we don't care 1755 * about, write it out. 1756 */ 1757 (void) fputs(line, new_fp); 1758 } 1759 } 1760 1761 (void) fclose(menu_fp); 1762 (void) fclose(new_fp); 1763 (void) close(tmp_fd); 1764 1765 if (rename(temp_menu, menu_file) != 0) { 1766 err = errno; 1767 be_print_err(gettext("be_update_menu: " 1768 "failed to rename file %s to %s: %s\n"), 1769 temp_menu, menu_file, strerror(err)); 1770 ret = errno_to_be_err(err); 1771 } 1772 free(temp_menu); 1773 1774 /* Set the perms and ownership of the updated file */ 1775 if (chmod(menu_file, sb.st_mode) != 0) { 1776 err = errno; 1777 be_print_err(gettext("be_update_menu: " 1778 "failed to chmod %s: %s\n"), menu_file, strerror(err)); 1779 ret = errno_to_be_err(err); 1780 goto cleanup; 1781 } 1782 if (chown(menu_file, sb.st_uid, sb.st_gid) != 0) { 1783 err = errno; 1784 be_print_err(gettext("be_update_menu: " 1785 "failed to chown %s: %s\n"), menu_file, strerror(err)); 1786 ret = errno_to_be_err(err); 1787 } 1788 1789 cleanup: 1790 if (pool_mounted) { 1791 int err = BE_SUCCESS; 1792 err = be_unmount_pool(zhp, ptmp_mntpnt, orig_mntpnt); 1793 if (ret == BE_SUCCESS) 1794 ret = err; 1795 free(orig_mntpnt); 1796 free(ptmp_mntpnt); 1797 } 1798 ZFS_CLOSE(zhp); 1799 return (ret); 1800 } 1801 1802 /* 1803 * Function: be_has_menu_entry 1804 * Description: Checks to see if the BEs root dataset has an entry in the grub 1805 * menu. 1806 * Parameters: 1807 * be_dataset - The root dataset of the BE 1808 * be_root_pool - The pool which contains the boot menu 1809 * entry - A pointer the the entry number of the BE if found. 1810 * Returns: 1811 * B_TRUE - Success 1812 * B_FALSE - Failure 1813 * Scope: 1814 * Semi-private (library wide use only) 1815 */ 1816 boolean_t 1817 be_has_menu_entry(char *be_dataset, char *be_root_pool, int *entry) 1818 { 1819 zfs_handle_t *zhp = NULL; 1820 char menu_file[MAXPATHLEN]; 1821 FILE *menu_fp; 1822 char line[BUFSIZ]; 1823 char *last; 1824 char *rpool_mntpnt = NULL; 1825 char *ptmp_mntpnt = NULL; 1826 char *orig_mntpnt = NULL; 1827 int ent_num = 0; 1828 boolean_t ret = 0; 1829 boolean_t pool_mounted = B_FALSE; 1830 1831 1832 /* 1833 * Check to see if this system supports grub 1834 */ 1835 if ((zhp = zfs_open(g_zfs, be_root_pool, ZFS_TYPE_DATASET)) == NULL) { 1836 be_print_err(gettext("be_has_menu_entry: failed to open " 1837 "pool dataset for %s: %s\n"), be_root_pool, 1838 libzfs_error_description(g_zfs)); 1839 return (B_FALSE); 1840 } 1841 1842 /* 1843 * Check to see if the pool's dataset is mounted. If it isn't we'll 1844 * attempt to mount it. 1845 */ 1846 if (be_mount_pool(zhp, &ptmp_mntpnt, &orig_mntpnt, 1847 &pool_mounted) != 0) { 1848 be_print_err(gettext("be_has_menu_entry: pool dataset " 1849 "(%s) could not be mounted\n"), be_root_pool); 1850 ZFS_CLOSE(zhp); 1851 return (B_FALSE); 1852 } 1853 1854 /* 1855 * Get the mountpoint for the root pool dataset. 1856 */ 1857 if (!zfs_is_mounted(zhp, &rpool_mntpnt)) { 1858 be_print_err(gettext("be_has_menu_entry: pool " 1859 "dataset (%s) is not mounted. Can't set " 1860 "the default BE in the grub menu.\n"), be_root_pool); 1861 ret = B_FALSE; 1862 goto cleanup; 1863 } 1864 1865 if (be_has_grub()) { 1866 (void) snprintf(menu_file, MAXPATHLEN, "/%s%s", 1867 rpool_mntpnt, BE_GRUB_MENU); 1868 } else { 1869 (void) snprintf(menu_file, MAXPATHLEN, "/%s%s", 1870 rpool_mntpnt, BE_SPARC_MENU); 1871 } 1872 1873 if (be_open_menu(be_root_pool, menu_file, &menu_fp, "r", 1874 B_FALSE) != 0) { 1875 ret = B_FALSE; 1876 goto cleanup; 1877 } else if (menu_fp == NULL) { 1878 ret = B_FALSE; 1879 goto cleanup; 1880 } 1881 1882 free(rpool_mntpnt); 1883 rpool_mntpnt = NULL; 1884 1885 while (fgets(line, BUFSIZ, menu_fp)) { 1886 char *tok = strtok_r(line, BE_WHITE_SPACE, &last); 1887 1888 if (tok != NULL && tok[0] != '#') { 1889 if (strcmp(tok, "bootfs") == 0) { 1890 tok = strtok_r(last, BE_WHITE_SPACE, &last); 1891 if (tok != NULL && strcmp(tok, 1892 be_dataset) == 0) { 1893 (void) fclose(menu_fp); 1894 /* 1895 * The entry number needs to be 1896 * decremented here because the title 1897 * will always be the first line for 1898 * an entry. Because of this we'll 1899 * always be off by one entry when we 1900 * check for bootfs. 1901 */ 1902 *entry = ent_num - 1; 1903 ret = B_TRUE; 1904 goto cleanup; 1905 } 1906 } else if (strcmp(tok, "title") == 0) 1907 ent_num++; 1908 } 1909 } 1910 1911 cleanup: 1912 if (pool_mounted) { 1913 (void) be_unmount_pool(zhp, ptmp_mntpnt, orig_mntpnt); 1914 free(orig_mntpnt); 1915 free(ptmp_mntpnt); 1916 } 1917 ZFS_CLOSE(zhp); 1918 (void) fclose(menu_fp); 1919 return (ret); 1920 } 1921 1922 /* 1923 * Function: be_update_vfstab 1924 * Description: This function digs into a BE's vfstab and updates all 1925 * entries with file systems listed in be_fs_list_data_t. 1926 * The entry's root container dataset and be_name will be 1927 * updated with the parameters passed in. 1928 * Parameters: 1929 * be_name - name of BE to update 1930 * old_rc_loc - dataset under which the root container dataset 1931 * of the old BE resides in. 1932 * new_rc_loc - dataset under which the root container dataset 1933 * of the new BE resides in. 1934 * fld - be_fs_list_data_t pointer providing the list of 1935 * file systems to look for in vfstab. 1936 * mountpoint - directory of where BE is currently mounted. 1937 * If NULL, then BE is not currently mounted. 1938 * Returns: 1939 * BE_SUCCESS - Success 1940 * be_errno_t - Failure 1941 * Scope: 1942 * Semi-private (library wide use only) 1943 */ 1944 int 1945 be_update_vfstab(char *be_name, char *old_rc_loc, char *new_rc_loc, 1946 be_fs_list_data_t *fld, char *mountpoint) 1947 { 1948 char *tmp_mountpoint = NULL; 1949 char alt_vfstab[MAXPATHLEN]; 1950 int ret = BE_SUCCESS, err = BE_SUCCESS; 1951 1952 if (fld == NULL || fld->fs_list == NULL || fld->fs_num == 0) 1953 return (BE_SUCCESS); 1954 1955 /* If BE not already mounted, mount the BE */ 1956 if (mountpoint == NULL) { 1957 if ((ret = _be_mount(be_name, &tmp_mountpoint, 1958 BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) { 1959 be_print_err(gettext("be_update_vfstab: " 1960 "failed to mount BE (%s)\n"), be_name); 1961 return (ret); 1962 } 1963 } else { 1964 tmp_mountpoint = mountpoint; 1965 } 1966 1967 /* Get string for vfstab in the mounted BE. */ 1968 (void) snprintf(alt_vfstab, sizeof (alt_vfstab), "%s/etc/vfstab", 1969 tmp_mountpoint); 1970 1971 /* Update the vfstab */ 1972 ret = _update_vfstab(alt_vfstab, be_name, old_rc_loc, new_rc_loc, 1973 fld); 1974 1975 /* Unmount BE if we mounted it */ 1976 if (mountpoint == NULL) { 1977 if ((err = _be_unmount(be_name, 0)) == BE_SUCCESS) { 1978 /* Remove temporary mountpoint */ 1979 (void) rmdir(tmp_mountpoint); 1980 } else { 1981 be_print_err(gettext("be_update_vfstab: " 1982 "failed to unmount BE %s mounted at %s\n"), 1983 be_name, tmp_mountpoint); 1984 if (ret == BE_SUCCESS) 1985 ret = err; 1986 } 1987 1988 free(tmp_mountpoint); 1989 } 1990 1991 return (ret); 1992 } 1993 1994 /* 1995 * Function: be_update_zone_vfstab 1996 * Description: This function digs into a zone BE's vfstab and updates all 1997 * entries with file systems listed in be_fs_list_data_t. 1998 * The entry's root container dataset and be_name will be 1999 * updated with the parameters passed in. 2000 * Parameters: 2001 * zhp - zfs_handle_t pointer to zone root dataset. 2002 * be_name - name of zone BE to update 2003 * old_rc_loc - dataset under which the root container dataset 2004 * of the old zone BE resides in. 2005 * new_rc_loc - dataset under which the root container dataset 2006 * of the new zone BE resides in. 2007 * fld - be_fs_list_data_t pointer providing the list of 2008 * file systems to look for in vfstab. 2009 * Returns: 2010 * BE_SUCCESS - Success 2011 * be_errno_t - Failure 2012 * Scope: 2013 * Semi-private (library wide use only) 2014 */ 2015 int 2016 be_update_zone_vfstab(zfs_handle_t *zhp, char *be_name, char *old_rc_loc, 2017 char *new_rc_loc, be_fs_list_data_t *fld) 2018 { 2019 be_mount_data_t md = { 0 }; 2020 be_unmount_data_t ud = { 0 }; 2021 char alt_vfstab[MAXPATHLEN]; 2022 boolean_t mounted_here = B_FALSE; 2023 int ret = BE_SUCCESS; 2024 2025 /* 2026 * If zone root not already mounted, mount it at a 2027 * temporary location. 2028 */ 2029 if (!zfs_is_mounted(zhp, &md.altroot)) { 2030 /* Generate temporary mountpoint to mount zone root */ 2031 if ((ret = be_make_tmp_mountpoint(&md.altroot)) != BE_SUCCESS) { 2032 be_print_err(gettext("be_update_zone_vfstab: " 2033 "failed to make temporary mountpoint to " 2034 "mount zone root\n")); 2035 return (ret); 2036 } 2037 2038 if (be_mount_zone_root(zhp, &md) != BE_SUCCESS) { 2039 be_print_err(gettext("be_update_zone_vfstab: " 2040 "failed to mount zone root %s\n"), 2041 zfs_get_name(zhp)); 2042 free(md.altroot); 2043 return (BE_ERR_MOUNT_ZONEROOT); 2044 } 2045 mounted_here = B_TRUE; 2046 } 2047 2048 /* Get string from vfstab in the mounted zone BE */ 2049 (void) snprintf(alt_vfstab, sizeof (alt_vfstab), "%s/etc/vfstab", 2050 md.altroot); 2051 2052 /* Update the vfstab */ 2053 ret = _update_vfstab(alt_vfstab, be_name, old_rc_loc, new_rc_loc, 2054 fld); 2055 2056 /* Unmount zone root if we mounted it */ 2057 if (mounted_here) { 2058 ud.force = B_TRUE; 2059 2060 if (be_unmount_zone_root(zhp, &ud) == BE_SUCCESS) { 2061 /* Remove the temporary mountpoint */ 2062 (void) rmdir(md.altroot); 2063 } else { 2064 be_print_err(gettext("be_update_zone_vfstab: " 2065 "failed to unmount zone root %s from %s\n"), 2066 zfs_get_name(zhp), md.altroot); 2067 if (ret == 0) 2068 ret = BE_ERR_UMOUNT_ZONEROOT; 2069 } 2070 } 2071 2072 free(md.altroot); 2073 return (ret); 2074 } 2075 2076 /* 2077 * Function: be_auto_snap_name 2078 * Description: Generate an auto snapshot name constructed based on the 2079 * current date and time. The auto snapshot name is of the form: 2080 * 2081 * <date>-<time> 2082 * 2083 * where <date> is in ISO standard format, so the resultant name 2084 * is of the form: 2085 * 2086 * %Y-%m-%d-%H:%M:%S 2087 * 2088 * Parameters: 2089 * None 2090 * Returns: 2091 * Success - pointer to auto generated snapshot name. The name 2092 * is allocated in heap storage so the caller is 2093 * responsible for free'ing the name. 2094 * Failure - NULL 2095 * Scope: 2096 * Semi-private (library wide use only) 2097 */ 2098 char * 2099 be_auto_snap_name(void) 2100 { 2101 time_t utc_tm = NULL; 2102 struct tm *gmt_tm = NULL; 2103 char gmt_time_str[64]; 2104 char *auto_snap_name = NULL; 2105 2106 if (time(&utc_tm) == -1) { 2107 be_print_err(gettext("be_auto_snap_name: time() failed\n")); 2108 return (NULL); 2109 } 2110 2111 if ((gmt_tm = gmtime(&utc_tm)) == NULL) { 2112 be_print_err(gettext("be_auto_snap_name: gmtime() failed\n")); 2113 return (NULL); 2114 } 2115 2116 (void) strftime(gmt_time_str, sizeof (gmt_time_str), "%F-%T", gmt_tm); 2117 2118 if ((auto_snap_name = strdup(gmt_time_str)) == NULL) { 2119 be_print_err(gettext("be_auto_snap_name: " 2120 "memory allocation failed\n")); 2121 return (NULL); 2122 } 2123 2124 return (auto_snap_name); 2125 } 2126 2127 /* 2128 * Function: be_auto_be_name 2129 * Description: Generate an auto BE name constructed based on the BE name 2130 * of the original BE being cloned. 2131 * Parameters: 2132 * obe_name - name of the original BE being cloned. 2133 * Returns: 2134 * Success - pointer to auto generated BE name. The name 2135 * is allocated in heap storage so the caller is 2136 * responsible for free'ing the name. 2137 * Failure - NULL 2138 * Scope: 2139 * Semi-private (library wide use only) 2140 */ 2141 char * 2142 be_auto_be_name(char *obe_name) 2143 { 2144 return (be_get_auto_name(obe_name, NULL, B_FALSE)); 2145 } 2146 2147 /* 2148 * Function: be_auto_zone_be_name 2149 * Description: Generate an auto BE name for a zone constructed based on 2150 * the BE name of the original zone BE being cloned. 2151 * Parameters: 2152 * container_ds - container dataset for the zone. 2153 * zbe_name - name of the original zone BE being cloned. 2154 * Returns: 2155 * Success - pointer to auto generated BE name. The name 2156 * is allocated in heap storage so the caller is 2157 * responsible for free'ing the name. 2158 * Failure - NULL 2159 * Scope: 2160 * Semi-private (library wide use only) 2161 */ 2162 char * 2163 be_auto_zone_be_name(char *container_ds, char *zbe_name) 2164 { 2165 return (be_get_auto_name(zbe_name, container_ds, B_TRUE)); 2166 } 2167 2168 /* 2169 * Function: be_valid_be_name 2170 * Description: Validates a BE name. 2171 * Parameters: 2172 * be_name - name of BE to validate 2173 * Returns: 2174 * B_TRUE - be_name is valid 2175 * B_FALSE - be_name is invalid 2176 * Scope: 2177 * Semi-private (library wide use only) 2178 */ 2179 2180 boolean_t 2181 be_valid_be_name(const char *be_name) 2182 { 2183 const char *c = NULL; 2184 struct be_defaults be_defaults; 2185 2186 if (be_name == NULL) 2187 return (B_FALSE); 2188 2189 be_get_defaults(&be_defaults); 2190 2191 /* 2192 * A BE name must not be a multi-level dataset name. We also check 2193 * that it does not contain the ' ' and '%' characters. The ' ' is 2194 * a valid character for datasets, however we don't allow that in a 2195 * BE name. The '%' is invalid, but zfs_name_valid() allows it for 2196 * internal reasons, so we explicitly check for it here. 2197 */ 2198 c = be_name; 2199 while (*c != '\0' && *c != '/' && *c != ' ' && *c != '%') 2200 c++; 2201 2202 if (*c != '\0') 2203 return (B_FALSE); 2204 2205 /* 2206 * The BE name must comply with a zfs dataset filesystem. We also 2207 * verify its length to be < BE_NAME_MAX_LEN. 2208 */ 2209 if (!zfs_name_valid(be_name, ZFS_TYPE_FILESYSTEM) || 2210 strlen(be_name) > BE_NAME_MAX_LEN) 2211 return (B_FALSE); 2212 2213 if (be_defaults.be_deflt_bename_starts_with[0] != '\0' && 2214 strstr(be_name, be_defaults.be_deflt_bename_starts_with) == NULL) { 2215 return (B_FALSE); 2216 } 2217 2218 return (B_TRUE); 2219 } 2220 2221 /* 2222 * Function: be_valid_auto_snap_name 2223 * Description: This function checks that a snapshot name is a valid auto 2224 * generated snapshot name. A valid auto generated snapshot 2225 * name is of the form: 2226 * 2227 * %Y-%m-%d-%H:%M:%S 2228 * 2229 * An older form of the auto generated snapshot name also 2230 * included the snapshot's BE cleanup policy and a reserved 2231 * field. Those names will also be verified by this function. 2232 * 2233 * Examples of valid auto snapshot names are: 2234 * 2235 * 2008-03-31-18:41:30 2236 * 2008-03-31-22:17:24 2237 * <policy>:-:2008:04-05-09:12:55 2238 * <policy>:-:2008:04-06-15:34:12 2239 * 2240 * Parameters: 2241 * name - name of the snapshot to be validated. 2242 * Returns: 2243 * B_TRUE - the name is a valid auto snapshot name. 2244 * B_FALSE - the name is not a valid auto snapshot name. 2245 * Scope: 2246 * Semi-private (library wide use only) 2247 */ 2248 boolean_t 2249 be_valid_auto_snap_name(char *name) 2250 { 2251 struct tm gmt_tm; 2252 2253 char *policy = NULL; 2254 char *reserved = NULL; 2255 char *date = NULL; 2256 char *c = NULL; 2257 2258 /* Validate the snapshot name by converting it into utc time */ 2259 if (strptime(name, "%Y-%m-%d-%T", &gmt_tm) != NULL && 2260 (mktime(&gmt_tm) != -1)) { 2261 return (B_TRUE); 2262 } 2263 2264 /* 2265 * Validate the snapshot name against the older form of an 2266 * auto generated snapshot name. 2267 */ 2268 policy = strdup(name); 2269 2270 /* 2271 * Get the first field from the snapshot name, 2272 * which is the BE policy 2273 */ 2274 c = strchr(policy, ':'); 2275 if (c == NULL) { 2276 free(policy); 2277 return (B_FALSE); 2278 } 2279 c[0] = '\0'; 2280 2281 /* Validate the policy name */ 2282 if (!valid_be_policy(policy)) { 2283 free(policy); 2284 return (B_FALSE); 2285 } 2286 2287 /* Get the next field, which is the reserved field. */ 2288 if (c[1] == NULL || c[1] == '\0') { 2289 free(policy); 2290 return (B_FALSE); 2291 } 2292 reserved = c+1; 2293 c = strchr(reserved, ':'); 2294 if (c == NULL) { 2295 free(policy); 2296 return (B_FALSE); 2297 } 2298 c[0] = '\0'; 2299 2300 /* Validate the reserved field */ 2301 if (strcmp(reserved, "-") != 0) { 2302 free(policy); 2303 return (B_FALSE); 2304 } 2305 2306 /* The remaining string should be the date field */ 2307 if (c[1] == NULL || c[1] == '\0') { 2308 free(policy); 2309 return (B_FALSE); 2310 } 2311 date = c+1; 2312 2313 /* Validate the date string by converting it into utc time */ 2314 if (strptime(date, "%Y-%m-%d-%T", &gmt_tm) == NULL || 2315 (mktime(&gmt_tm) == -1)) { 2316 be_print_err(gettext("be_valid_auto_snap_name: " 2317 "invalid auto snapshot name\n")); 2318 free(policy); 2319 return (B_FALSE); 2320 } 2321 2322 free(policy); 2323 return (B_TRUE); 2324 } 2325 2326 /* 2327 * Function: be_default_policy 2328 * Description: Temporary hardcoded policy support. This function returns 2329 * the default policy type to be used to create a BE or a BE 2330 * snapshot. 2331 * Parameters: 2332 * None 2333 * Returns: 2334 * Name of default BE policy. 2335 * Scope: 2336 * Semi-private (library wide use only) 2337 */ 2338 char * 2339 be_default_policy(void) 2340 { 2341 return (BE_PLCY_STATIC); 2342 } 2343 2344 /* 2345 * Function: valid_be_policy 2346 * Description: Temporary hardcoded policy support. This function valids 2347 * whether a policy is a valid known policy or not. 2348 * Paramters: 2349 * policy - name of policy to validate. 2350 * Returns: 2351 * B_TRUE - policy is a valid. 2352 * B_FALSE - policy is invalid. 2353 * Scope: 2354 * Semi-private (library wide use only) 2355 */ 2356 boolean_t 2357 valid_be_policy(char *policy) 2358 { 2359 if (policy == NULL) 2360 return (B_FALSE); 2361 2362 if (strcmp(policy, BE_PLCY_STATIC) == 0 || 2363 strcmp(policy, BE_PLCY_VOLATILE) == 0) { 2364 return (B_TRUE); 2365 } 2366 2367 return (B_FALSE); 2368 } 2369 2370 /* 2371 * Function: be_print_err 2372 * Description: This function prints out error messages if do_print is 2373 * set to B_TRUE or if the BE_PRINT_ERR environment variable 2374 * is set to true. 2375 * Paramters: 2376 * prnt_str - the string we wish to print and any arguments 2377 * for the format of that string. 2378 * Returns: 2379 * void 2380 * Scope: 2381 * Semi-private (library wide use only) 2382 */ 2383 void 2384 be_print_err(char *prnt_str, ...) 2385 { 2386 va_list ap; 2387 char buf[BUFSIZ]; 2388 char *env_buf; 2389 static boolean_t env_checked = B_FALSE; 2390 2391 if (!env_checked) { 2392 if ((env_buf = getenv("BE_PRINT_ERR")) != NULL) { 2393 if (strcasecmp(env_buf, "true") == 0) { 2394 do_print = B_TRUE; 2395 } 2396 } 2397 env_checked = B_TRUE; 2398 } 2399 2400 if (do_print) { 2401 va_start(ap, prnt_str); 2402 /* LINTED variable format specifier */ 2403 (void) vsnprintf(buf, BUFSIZ, prnt_str, ap); 2404 (void) fputs(buf, stderr); 2405 va_end(ap); 2406 } 2407 } 2408 2409 /* 2410 * Function: be_find_current_be 2411 * Description: Find the currently "active" BE. Fill in the 2412 * passed in be_transaction_data_t reference with the 2413 * active BE's data. 2414 * Paramters: 2415 * none 2416 * Returns: 2417 * BE_SUCCESS - Success 2418 * be_errnot_t - Failure 2419 * Scope: 2420 * Semi-private (library wide use only) 2421 * Notes: 2422 * The caller is responsible for initializing the libzfs handle 2423 * and freeing the memory used by the active be_name. 2424 */ 2425 int 2426 be_find_current_be(be_transaction_data_t *bt) 2427 { 2428 int zret; 2429 2430 if ((zret = zpool_iter(g_zfs, be_zpool_find_current_be_callback, 2431 bt)) == 0) { 2432 be_print_err(gettext("be_find_current_be: failed to " 2433 "find current BE name\n")); 2434 return (BE_ERR_BE_NOENT); 2435 } else if (zret < 0) { 2436 be_print_err(gettext("be_find_current_be: " 2437 "zpool_iter failed: %s\n"), 2438 libzfs_error_description(g_zfs)); 2439 return (zfs_err_to_be_err(g_zfs)); 2440 } 2441 2442 return (BE_SUCCESS); 2443 } 2444 2445 /* 2446 * Function: be_zpool_find_current_be_callback 2447 * Description: Callback function used to iterate through all existing pools 2448 * to find the BE that is the currently booted BE. 2449 * Parameters: 2450 * zlp - zpool_handle_t pointer to the current pool being 2451 * looked at. 2452 * data - be_transaction_data_t pointer. 2453 * Upon successfully finding the current BE, the 2454 * obe_zpool member of this parameter is set to the 2455 * pool it is found in. 2456 * Return: 2457 * 1 - Found current BE in this pool. 2458 * 0 - Did not find current BE in this pool. 2459 * Scope: 2460 * Semi-private (library wide use only) 2461 */ 2462 int 2463 be_zpool_find_current_be_callback(zpool_handle_t *zlp, void *data) 2464 { 2465 be_transaction_data_t *bt = data; 2466 zfs_handle_t *zhp = NULL; 2467 const char *zpool = zpool_get_name(zlp); 2468 char be_container_ds[MAXPATHLEN]; 2469 char *zpath = NULL; 2470 2471 /* 2472 * Generate string for BE container dataset 2473 */ 2474 if (getzoneid() != GLOBAL_ZONEID) { 2475 if ((zpath = be_get_ds_from_dir("/")) != NULL) { 2476 (void) strlcpy(be_container_ds, dirname(zpath), 2477 sizeof (be_container_ds)); 2478 } else { 2479 be_print_err(gettext( 2480 "be_zpool_find_current_be_callback: " 2481 "zone root dataset is not mounted\n")); 2482 return (0); 2483 } 2484 } else { 2485 be_make_container_ds(zpool, be_container_ds, 2486 sizeof (be_container_ds)); 2487 } 2488 2489 /* 2490 * Check if a BE container dataset exists in this pool. 2491 */ 2492 if (!zfs_dataset_exists(g_zfs, be_container_ds, ZFS_TYPE_FILESYSTEM)) { 2493 zpool_close(zlp); 2494 return (0); 2495 } 2496 2497 /* 2498 * Get handle to this zpool's BE container dataset. 2499 */ 2500 if ((zhp = zfs_open(g_zfs, be_container_ds, ZFS_TYPE_FILESYSTEM)) == 2501 NULL) { 2502 be_print_err(gettext("be_zpool_find_current_be_callback: " 2503 "failed to open BE container dataset (%s)\n"), 2504 be_container_ds); 2505 zpool_close(zlp); 2506 return (0); 2507 } 2508 2509 /* 2510 * Iterate through all potential BEs in this zpool 2511 */ 2512 if (zfs_iter_filesystems(zhp, be_zfs_find_current_be_callback, bt)) { 2513 /* 2514 * Found current BE dataset; set obe_zpool 2515 */ 2516 if ((bt->obe_zpool = strdup(zpool)) == NULL) { 2517 be_print_err(gettext( 2518 "be_zpool_find_current_be_callback: " 2519 "memory allocation failed\n")); 2520 ZFS_CLOSE(zhp); 2521 zpool_close(zlp); 2522 return (0); 2523 } 2524 2525 ZFS_CLOSE(zhp); 2526 zpool_close(zlp); 2527 return (1); 2528 } 2529 2530 ZFS_CLOSE(zhp); 2531 zpool_close(zlp); 2532 2533 return (0); 2534 } 2535 2536 /* 2537 * Function: be_zfs_find_current_be_callback 2538 * Description: Callback function used to iterate through all BEs in a 2539 * pool to find the BE that is the currently booted BE. 2540 * Parameters: 2541 * zhp - zfs_handle_t pointer to current filesystem being checked. 2542 * data - be_transaction-data_t pointer 2543 * Upon successfully finding the current BE, the 2544 * obe_name and obe_root_ds members of this parameter 2545 * are set to the BE name and BE's root dataset 2546 * respectively. 2547 * Return: 2548 * 1 - Found current BE. 2549 * 0 - Did not find current BE. 2550 * Scope: 2551 * Semi-private (library wide use only) 2552 */ 2553 int 2554 be_zfs_find_current_be_callback(zfs_handle_t *zhp, void *data) 2555 { 2556 be_transaction_data_t *bt = data; 2557 char *mp = NULL; 2558 2559 /* 2560 * Check if dataset is mounted, and if so where. 2561 */ 2562 if (zfs_is_mounted(zhp, &mp)) { 2563 /* 2564 * If mounted at root, set obe_root_ds and obe_name 2565 */ 2566 if (mp != NULL && strcmp(mp, "/") == 0) { 2567 free(mp); 2568 2569 if ((bt->obe_root_ds = strdup(zfs_get_name(zhp))) 2570 == NULL) { 2571 be_print_err(gettext( 2572 "be_zfs_find_current_be_callback: " 2573 "memory allocation failed\n")); 2574 ZFS_CLOSE(zhp); 2575 return (0); 2576 } 2577 2578 if ((bt->obe_name = strdup(basename(bt->obe_root_ds))) 2579 == NULL) { 2580 be_print_err(gettext( 2581 "be_zfs_find_current_be_callback: " 2582 "memory allocation failed\n")); 2583 ZFS_CLOSE(zhp); 2584 return (0); 2585 } 2586 2587 ZFS_CLOSE(zhp); 2588 return (1); 2589 } 2590 2591 free(mp); 2592 } 2593 ZFS_CLOSE(zhp); 2594 2595 return (0); 2596 } 2597 2598 /* 2599 * Function: be_check_be_roots_callback 2600 * Description: This function checks whether or not the dataset name passed 2601 * is hierachically located under the BE root container dataset 2602 * for this pool. 2603 * Parameters: 2604 * zlp - zpool_handle_t pointer to current pool being processed. 2605 * data - name of dataset to check 2606 * Returns: 2607 * 0 - dataset is not in this pool's BE root container dataset 2608 * 1 - dataset is in this pool's BE root container dataset 2609 * Scope: 2610 * Semi-private (library wide use only) 2611 */ 2612 int 2613 be_check_be_roots_callback(zpool_handle_t *zlp, void *data) 2614 { 2615 const char *zpool = zpool_get_name(zlp); 2616 char *ds = data; 2617 char be_container_ds[MAXPATHLEN]; 2618 2619 /* Generate string for this pool's BE root container dataset */ 2620 be_make_container_ds(zpool, be_container_ds, sizeof (be_container_ds)); 2621 2622 /* 2623 * If dataset lives under the BE root container dataset 2624 * of this pool, return failure. 2625 */ 2626 if (strncmp(be_container_ds, ds, strlen(be_container_ds)) == 0 && 2627 ds[strlen(be_container_ds)] == '/') { 2628 zpool_close(zlp); 2629 return (1); 2630 } 2631 2632 zpool_close(zlp); 2633 return (0); 2634 } 2635 2636 /* 2637 * Function: zfs_err_to_be_err 2638 * Description: This function takes the error stored in the libzfs handle 2639 * and maps it to an be_errno_t. If there are no matching 2640 * be_errno_t's then BE_ERR_ZFS is returned. 2641 * Paramters: 2642 * zfsh - The libzfs handle containing the error we're looking up. 2643 * Returns: 2644 * be_errno_t 2645 * Scope: 2646 * Semi-private (library wide use only) 2647 */ 2648 int 2649 zfs_err_to_be_err(libzfs_handle_t *zfsh) 2650 { 2651 int err = libzfs_errno(zfsh); 2652 2653 switch (err) { 2654 case 0: 2655 return (BE_SUCCESS); 2656 case EZFS_PERM: 2657 return (BE_ERR_PERM); 2658 case EZFS_INTR: 2659 return (BE_ERR_INTR); 2660 case EZFS_NOENT: 2661 return (BE_ERR_NOENT); 2662 case EZFS_NOSPC: 2663 return (BE_ERR_NOSPC); 2664 case EZFS_MOUNTFAILED: 2665 return (BE_ERR_MOUNT); 2666 case EZFS_UMOUNTFAILED: 2667 return (BE_ERR_UMOUNT); 2668 case EZFS_EXISTS: 2669 return (BE_ERR_BE_EXISTS); 2670 case EZFS_BUSY: 2671 return (BE_ERR_DEV_BUSY); 2672 case EZFS_POOLREADONLY: 2673 return (BE_ERR_ROFS); 2674 case EZFS_NAMETOOLONG: 2675 return (BE_ERR_NAMETOOLONG); 2676 case EZFS_NODEVICE: 2677 return (BE_ERR_NODEV); 2678 case EZFS_POOL_INVALARG: 2679 return (BE_ERR_INVAL); 2680 case EZFS_PROPTYPE: 2681 return (BE_ERR_INVALPROP); 2682 case EZFS_BADTYPE: 2683 return (BE_ERR_DSTYPE); 2684 case EZFS_PROPNONINHERIT: 2685 return (BE_ERR_NONINHERIT); 2686 case EZFS_PROPREADONLY: 2687 return (BE_ERR_READONLYPROP); 2688 case EZFS_RESILVERING: 2689 case EZFS_POOLUNAVAIL: 2690 return (BE_ERR_UNAVAIL); 2691 case EZFS_DSREADONLY: 2692 return (BE_ERR_READONLYDS); 2693 default: 2694 return (BE_ERR_ZFS); 2695 } 2696 } 2697 2698 /* 2699 * Function: errno_to_be_err 2700 * Description: This function takes an errno and maps it to an be_errno_t. 2701 * If there are no matching be_errno_t's then BE_ERR_UNKNOWN is 2702 * returned. 2703 * Paramters: 2704 * err - The errno we're compairing against. 2705 * Returns: 2706 * be_errno_t 2707 * Scope: 2708 * Semi-private (library wide use only) 2709 */ 2710 int 2711 errno_to_be_err(int err) 2712 { 2713 switch (err) { 2714 case EPERM: 2715 return (BE_ERR_PERM); 2716 case EACCES: 2717 return (BE_ERR_ACCESS); 2718 case ECANCELED: 2719 return (BE_ERR_CANCELED); 2720 case EINTR: 2721 return (BE_ERR_INTR); 2722 case ENOENT: 2723 return (BE_ERR_NOENT); 2724 case ENOSPC: 2725 case EDQUOT: 2726 return (BE_ERR_NOSPC); 2727 case EEXIST: 2728 return (BE_ERR_BE_EXISTS); 2729 case EBUSY: 2730 return (BE_ERR_BUSY); 2731 case EROFS: 2732 return (BE_ERR_ROFS); 2733 case ENAMETOOLONG: 2734 return (BE_ERR_NAMETOOLONG); 2735 case ENXIO: 2736 return (BE_ERR_NXIO); 2737 case EINVAL: 2738 return (BE_ERR_INVAL); 2739 case EFAULT: 2740 return (BE_ERR_FAULT); 2741 default: 2742 return (BE_ERR_UNKNOWN); 2743 } 2744 } 2745 2746 /* 2747 * Function: be_err_to_str 2748 * Description: This function takes a be_errno_t and maps it to a message. 2749 * If there are no matching be_errno_t's then NULL is returned. 2750 * Paramters: 2751 * be_errno_t - The be_errno_t we're mapping. 2752 * Returns: 2753 * string or NULL if the error code is not known. 2754 * Scope: 2755 * Semi-private (library wide use only) 2756 */ 2757 char * 2758 be_err_to_str(int err) 2759 { 2760 switch (err) { 2761 case BE_ERR_ACCESS: 2762 return (gettext("Permission denied.")); 2763 case BE_ERR_ACTIVATE_CURR: 2764 return (gettext("Activation of current BE failed.")); 2765 case BE_ERR_AUTONAME: 2766 return (gettext("Auto naming failed.")); 2767 case BE_ERR_BE_NOENT: 2768 return (gettext("No such BE.")); 2769 case BE_ERR_BUSY: 2770 return (gettext("Mount busy.")); 2771 case BE_ERR_DEV_BUSY: 2772 return (gettext("Device busy.")); 2773 case BE_ERR_CANCELED: 2774 return (gettext("Operation canceled.")); 2775 case BE_ERR_CLONE: 2776 return (gettext("BE clone failed.")); 2777 case BE_ERR_COPY: 2778 return (gettext("BE copy failed.")); 2779 case BE_ERR_CREATDS: 2780 return (gettext("Dataset creation failed.")); 2781 case BE_ERR_CURR_BE_NOT_FOUND: 2782 return (gettext("Can't find current BE.")); 2783 case BE_ERR_DESTROY: 2784 return (gettext("Failed to destroy BE or snapshot.")); 2785 case BE_ERR_DESTROY_CURR_BE: 2786 return (gettext("Cannot destroy current BE.")); 2787 case BE_ERR_DEMOTE: 2788 return (gettext("BE demotion failed.")); 2789 case BE_ERR_DSTYPE: 2790 return (gettext("Invalid dataset type.")); 2791 case BE_ERR_BE_EXISTS: 2792 return (gettext("BE exists.")); 2793 case BE_ERR_INIT: 2794 return (gettext("be_zfs_init failed.")); 2795 case BE_ERR_INTR: 2796 return (gettext("Interupted system call.")); 2797 case BE_ERR_INVAL: 2798 return (gettext("Invalid argument.")); 2799 case BE_ERR_INVALPROP: 2800 return (gettext("Invalid property for dataset.")); 2801 case BE_ERR_INVALMOUNTPOINT: 2802 return (gettext("Unexpected mountpoint.")); 2803 case BE_ERR_MOUNT: 2804 return (gettext("Mount failed.")); 2805 case BE_ERR_MOUNTED: 2806 return (gettext("Already mounted.")); 2807 case BE_ERR_NAMETOOLONG: 2808 return (gettext("name > BUFSIZ.")); 2809 case BE_ERR_NOENT: 2810 return (gettext("Doesn't exist.")); 2811 case BE_ERR_POOL_NOENT: 2812 return (gettext("No such pool.")); 2813 case BE_ERR_NODEV: 2814 return (gettext("No such device.")); 2815 case BE_ERR_NOTMOUNTED: 2816 return (gettext("File system not mounted.")); 2817 case BE_ERR_NOMEM: 2818 return (gettext("Not enough memory.")); 2819 case BE_ERR_NONINHERIT: 2820 return (gettext( 2821 "Property is not inheritable for the BE dataset.")); 2822 case BE_ERR_NXIO: 2823 return (gettext("No such device or address.")); 2824 case BE_ERR_NOSPC: 2825 return (gettext("No space on device.")); 2826 case BE_ERR_NOTSUP: 2827 return (gettext("Operation not supported.")); 2828 case BE_ERR_OPEN: 2829 return (gettext("Open failed.")); 2830 case BE_ERR_PERM: 2831 return (gettext("Not owner.")); 2832 case BE_ERR_UNAVAIL: 2833 return (gettext("The BE is currently unavailable.")); 2834 case BE_ERR_PROMOTE: 2835 return (gettext("BE promotion failed.")); 2836 case BE_ERR_ROFS: 2837 return (gettext("Read only file system.")); 2838 case BE_ERR_READONLYDS: 2839 return (gettext("Read only dataset.")); 2840 case BE_ERR_READONLYPROP: 2841 return (gettext("Read only property.")); 2842 case BE_ERR_RENAME_ACTIVE: 2843 return (gettext("Renaming the active BE is not supported.")); 2844 case BE_ERR_SS_EXISTS: 2845 return (gettext("Snapshot exists.")); 2846 case BE_ERR_SS_NOENT: 2847 return (gettext("No such snapshot.")); 2848 case BE_ERR_UMOUNT: 2849 return (gettext("Unmount failed.")); 2850 case BE_ERR_UMOUNT_CURR_BE: 2851 return (gettext("Can't unmount the current BE.")); 2852 case BE_ERR_UMOUNT_SHARED: 2853 return (gettext("Unmount of a shared File System failed.")); 2854 case BE_ERR_FAULT: 2855 return (gettext("Bad address.")); 2856 case BE_ERR_UNKNOWN: 2857 return (gettext("Unknown error.")); 2858 case BE_ERR_ZFS: 2859 return (gettext("ZFS returned an error.")); 2860 case BE_ERR_GEN_UUID: 2861 return (gettext("Failed to generate uuid.")); 2862 case BE_ERR_PARSE_UUID: 2863 return (gettext("Failed to parse uuid.")); 2864 case BE_ERR_NO_UUID: 2865 return (gettext("No uuid")); 2866 case BE_ERR_ZONE_NO_PARENTBE: 2867 return (gettext("No parent uuid")); 2868 case BE_ERR_ZONE_MULTIPLE_ACTIVE: 2869 return (gettext("Multiple active zone roots")); 2870 case BE_ERR_ZONE_NO_ACTIVE_ROOT: 2871 return (gettext("No active zone root")); 2872 case BE_ERR_ZONE_ROOT_NOT_LEGACY: 2873 return (gettext("Zone root not legacy")); 2874 case BE_ERR_MOUNT_ZONEROOT: 2875 return (gettext("Failed to mount a zone root.")); 2876 case BE_ERR_UMOUNT_ZONEROOT: 2877 return (gettext("Failed to unmount a zone root.")); 2878 case BE_ERR_NO_MOUNTED_ZONE: 2879 return (gettext("Zone is not mounted")); 2880 case BE_ERR_ZONES_UNMOUNT: 2881 return (gettext("Unable to unmount a zone BE.")); 2882 case BE_ERR_NO_MENU: 2883 return (gettext("Missing boot menu file.")); 2884 case BE_ERR_BAD_MENU_PATH: 2885 return (gettext("Invalid path for menu.lst file")); 2886 case BE_ERR_ZONE_SS_EXISTS: 2887 return (gettext("Zone snapshot exists.")); 2888 case BE_ERR_BOOTFILE_INST: 2889 return (gettext("Error installing boot files.")); 2890 case BE_ERR_EXTCMD: 2891 return (gettext("Error running an external command.")); 2892 default: 2893 return (NULL); 2894 } 2895 } 2896 2897 /* 2898 * Function: be_has_grub 2899 * Description: Boolean function indicating whether the current system 2900 * uses grub. 2901 * Return: B_FALSE - the system does not have grub 2902 * B_TRUE - the system does have grub. 2903 * Scope: 2904 * Semi-private (library wide use only) 2905 */ 2906 boolean_t 2907 be_has_grub(void) 2908 { 2909 /* 2910 * TODO: This will need to be expanded to check for the existence of 2911 * grub if and when there is grub support for SPARC. 2912 */ 2913 return (be_is_isa("i386")); 2914 } 2915 2916 /* 2917 * Function: be_is_isa 2918 * Description: Boolean function indicating whether the instruction set 2919 * architecture of the executing system matches the name provided. 2920 * The string must match a system defined architecture (e.g. 2921 * "i386", "sparc") and is case sensitive. 2922 * Parameters: name - string representing the name of instruction set 2923 * architecture being tested 2924 * Returns: B_FALSE - the system instruction set architecture is different 2925 * from the one specified 2926 * B_TRUE - the system instruction set architecture is the same 2927 * as the one specified 2928 * Scope: 2929 * Semi-private (library wide use only) 2930 */ 2931 boolean_t 2932 be_is_isa(char *name) 2933 { 2934 return ((strcmp((char *)be_get_default_isa(), name) == 0)); 2935 } 2936 2937 /* 2938 * Function: be_get_default_isa 2939 * Description: 2940 * Returns the default instruction set architecture of the 2941 * machine it is executed on. (eg. sparc, i386, ...) 2942 * NOTE: SYS_INST environment variable may override default 2943 * return value 2944 * Parameters: 2945 * none 2946 * Returns: 2947 * NULL - the architecture returned by sysinfo() was too 2948 * long for local variables 2949 * char * - pointer to a string containing the default 2950 * implementation 2951 * Scope: 2952 * Semi-private (library wide use only) 2953 */ 2954 char * 2955 be_get_default_isa(void) 2956 { 2957 int i; 2958 char *envp; 2959 static char default_inst[ARCH_LENGTH] = ""; 2960 2961 if (default_inst[0] == '\0') { 2962 if ((envp = getenv("SYS_INST")) != NULL) { 2963 if ((int)strlen(envp) >= ARCH_LENGTH) 2964 return (NULL); 2965 else 2966 (void) strcpy(default_inst, envp); 2967 } else { 2968 i = sysinfo(SI_ARCHITECTURE, default_inst, ARCH_LENGTH); 2969 if (i < 0 || i > ARCH_LENGTH) 2970 return (NULL); 2971 } 2972 } 2973 return (default_inst); 2974 } 2975 2976 /* 2977 * Function: be_run_cmd 2978 * Description: 2979 * Runs a command in a separate subprocess. Splits out stdout from stderr 2980 * and sends each to its own buffer. Buffers must be pre-allocated and 2981 * passed in as arguments. Buffer sizes are also passed in as arguments. 2982 * 2983 * Notes / caveats: 2984 * - Command being run is assumed to not have any stdout or stderr 2985 * redirection. 2986 * - Commands which emit total stderr output of greater than PIPE_BUF 2987 * bytes can hang. For such commands, a different implementation 2988 * which uses poll(2) must be used. 2989 * - stdout_buf can be NULL. In this case, stdout_bufsize is ignored, and 2990 * the stream which would have gone to it is sent to the bit 2991 * bucket. 2992 * - stderr_buf cannot be NULL. 2993 * - Only subprocess errors are appended to the stderr_buf. Errors 2994 * running the command are reported through be_print_err(). 2995 * - Data which would overflow its respective buffer is sent to the bit 2996 * bucket. 2997 * 2998 * Parameters: 2999 * command: command to run. Assumed not to have embedded stdout 3000 * or stderr redirection. May have stdin redirection, 3001 * however. 3002 * stderr_buf: buffer returning subprocess stderr data. Errors 3003 * reported by this function are reported through 3004 * be_print_err(). 3005 * stderr_bufsize: size of stderr_buf 3006 * stdout_buf: buffer returning subprocess stdout data. 3007 * stdout_bufsize: size of stdout_buf 3008 * Returns: 3009 * BE_SUCCESS - The command ran successfully without returning 3010 * errors. 3011 * BE_ERR_EXTCMD 3012 * - The command could not be run. 3013 * - The command terminated with error status. 3014 * - There were errors extracting or returning subprocess 3015 * data. 3016 * BE_ERR_NOMEM - The command exceeds the command buffer size. 3017 * BE_ERR_INVAL - An invalid argument was specified. 3018 * Scope: 3019 * Semi-private (library wide use only) 3020 */ 3021 int 3022 be_run_cmd(char *command, char *stderr_buf, int stderr_bufsize, 3023 char *stdout_buf, int stdout_bufsize) 3024 { 3025 char *temp_filename = strdup(tmpnam(NULL)); 3026 FILE *stdout_str = NULL; 3027 FILE *stderr_str = NULL; 3028 char cmdline[BUFSIZ]; 3029 char oneline[BUFSIZ]; 3030 int exit_status; 3031 int rval = BE_SUCCESS; 3032 3033 if ((command == NULL) || (stderr_buf == NULL) || 3034 (stderr_bufsize <= 0) || (stdout_bufsize < 0) || 3035 ((stdout_buf != NULL) ^ (stdout_bufsize != 0))) { 3036 return (BE_ERR_INVAL); 3037 } 3038 3039 /* Set up command so popen returns stderr, not stdout */ 3040 if (snprintf(cmdline, BUFSIZ, "%s 2> %s", command, 3041 temp_filename) >= BUFSIZ) { 3042 rval = BE_ERR_NOMEM; 3043 goto cleanup; 3044 } 3045 3046 /* Set up the fifo that will make stderr available. */ 3047 if (mkfifo(temp_filename, 0600) != 0) { 3048 (void) be_print_err(gettext("be_run_cmd: mkfifo: %s\n"), 3049 strerror(errno)); 3050 rval = BE_ERR_EXTCMD; 3051 goto cleanup; 3052 } 3053 3054 if ((stdout_str = popen(cmdline, "r")) == NULL) { 3055 (void) be_print_err(gettext("be_run_cmd: popen: %s\n"), 3056 strerror(errno)); 3057 rval = BE_ERR_EXTCMD; 3058 goto cleanup; 3059 } 3060 3061 if ((stderr_str = fopen(temp_filename, "r")) == NULL) { 3062 (void) be_print_err(gettext("be_run_cmd: fopen: %s\n"), 3063 strerror(errno)); 3064 (void) pclose(stdout_str); 3065 rval = BE_ERR_EXTCMD; 3066 goto cleanup; 3067 } 3068 3069 /* Read stdout first, as it usually outputs more than stderr. */ 3070 oneline[BUFSIZ-1] = '\0'; 3071 while (fgets(oneline, BUFSIZ-1, stdout_str) != NULL) { 3072 if (stdout_str != NULL) { 3073 (void) strlcat(stdout_buf, oneline, stdout_bufsize); 3074 } 3075 } 3076 3077 while (fgets(oneline, BUFSIZ-1, stderr_str) != NULL) { 3078 (void) strlcat(stderr_buf, oneline, stderr_bufsize); 3079 } 3080 3081 /* Close pipe, get exit status. */ 3082 if ((exit_status = pclose(stdout_str)) == -1) { 3083 (void) be_print_err(gettext("be_run_cmd: pclose: %s\n"), 3084 strerror(errno)); 3085 rval = BE_ERR_EXTCMD; 3086 } else if (WIFEXITED(exit_status)) { 3087 exit_status = (int)((char)WEXITSTATUS(exit_status)); 3088 if (exit_status != 0) { 3089 (void) snprintf(oneline, BUFSIZ, gettext("be_run_cmd: " 3090 "command terminated with error status: %d\n"), 3091 exit_status); 3092 (void) strlcat(stderr_buf, oneline, stderr_bufsize); 3093 rval = BE_ERR_EXTCMD; 3094 } 3095 } else { 3096 (void) snprintf(oneline, BUFSIZ, gettext("be_run_cmd: command " 3097 "terminated on signal: %s\n"), 3098 strsignal(WTERMSIG(exit_status))); 3099 (void) strlcat(stderr_buf, oneline, stderr_bufsize); 3100 rval = BE_ERR_EXTCMD; 3101 } 3102 3103 cleanup: 3104 (void) unlink(temp_filename); 3105 (void) free(temp_filename); 3106 3107 return (rval); 3108 } 3109 3110 /* ******************************************************************** */ 3111 /* Private Functions */ 3112 /* ******************************************************************** */ 3113 3114 /* 3115 * Function: update_dataset 3116 * Description: This function takes a dataset name and replaces the zpool 3117 * and be_name components of the dataset with the new be_name 3118 * zpool passed in. 3119 * Parameters: 3120 * dataset - name of dataset 3121 * dataset_len - lenth of buffer in which dataset is passed in. 3122 * be_name - name of new BE name to update to. 3123 * old_rc_loc - dataset under which the root container dataset 3124 * for the old BE lives. 3125 * new_rc_loc - dataset under which the root container dataset 3126 * for the new BE lives. 3127 * Returns: 3128 * BE_SUCCESS - Success 3129 * be_errno_t - Failure 3130 * Scope: 3131 * Private 3132 */ 3133 static int 3134 update_dataset(char *dataset, int dataset_len, char *be_name, 3135 char *old_rc_loc, char *new_rc_loc) 3136 { 3137 char *ds = NULL; 3138 char *sub_ds = NULL; 3139 3140 /* Tear off the BE container dataset */ 3141 if ((ds = be_make_name_from_ds(dataset, old_rc_loc)) == NULL) { 3142 return (BE_ERR_INVAL); 3143 } 3144 3145 /* Get dataset name relative to BE root, if there is one */ 3146 sub_ds = strchr(ds, '/'); 3147 3148 /* Generate the BE root dataset name */ 3149 be_make_root_ds(new_rc_loc, be_name, dataset, dataset_len); 3150 3151 /* If a subordinate dataset name was found, append it */ 3152 if (sub_ds != NULL) 3153 (void) strlcat(dataset, sub_ds, dataset_len); 3154 3155 free(ds); 3156 return (BE_SUCCESS); 3157 } 3158 3159 /* 3160 * Function: _update_vfstab 3161 * Description: This function updates a vfstab file to reflect the new 3162 * root container dataset location and be_name for all 3163 * entries listed in the be_fs_list_data_t structure passed in. 3164 * Parameters: 3165 * vfstab - vfstab file to modify 3166 * be_name - name of BE to update. 3167 * old_rc_loc - dataset under which the root container dataset 3168 * of the old BE resides in. 3169 * new_rc_loc - dataset under which the root container dataset 3170 * of the new BE resides in. 3171 * fld - be_fs_list_data_t pointer providing the list of 3172 * file systems to look for in vfstab. 3173 * Returns: 3174 * BE_SUCCESS - Success 3175 * be_errno_t - Failure 3176 * Scope: 3177 * Private 3178 */ 3179 static int 3180 _update_vfstab(char *vfstab, char *be_name, char *old_rc_loc, 3181 char *new_rc_loc, be_fs_list_data_t *fld) 3182 { 3183 struct vfstab vp; 3184 char *tmp_vfstab = NULL; 3185 char comments_buf[BUFSIZ]; 3186 FILE *comments = NULL; 3187 FILE *vfs_ents = NULL; 3188 FILE *tfile = NULL; 3189 struct stat sb; 3190 char dev[MAXPATHLEN]; 3191 char *c; 3192 int fd; 3193 int ret = BE_SUCCESS, err = 0; 3194 int i; 3195 int tmp_vfstab_len = 0; 3196 3197 errno = 0; 3198 3199 /* 3200 * Open vfstab for reading twice. First is for comments, 3201 * second is for actual entries. 3202 */ 3203 if ((comments = fopen(vfstab, "r")) == NULL || 3204 (vfs_ents = fopen(vfstab, "r")) == NULL) { 3205 err = errno; 3206 be_print_err(gettext("_update_vfstab: " 3207 "failed to open vfstab (%s): %s\n"), vfstab, 3208 strerror(err)); 3209 ret = errno_to_be_err(err); 3210 goto cleanup; 3211 } 3212 3213 /* Grab the stats of the original vfstab file */ 3214 if (stat(vfstab, &sb) != 0) { 3215 err = errno; 3216 be_print_err(gettext("_update_vfstab: " 3217 "failed to stat file %s: %s\n"), vfstab, 3218 strerror(err)); 3219 ret = errno_to_be_err(err); 3220 goto cleanup; 3221 } 3222 3223 /* Create tmp file for modified vfstab */ 3224 if ((tmp_vfstab = (char *)malloc(strlen(vfstab) + 7)) 3225 == NULL) { 3226 be_print_err(gettext("_update_vfstab: " 3227 "malloc failed\n")); 3228 ret = BE_ERR_NOMEM; 3229 goto cleanup; 3230 } 3231 tmp_vfstab_len = strlen(vfstab) + 7; 3232 (void) memset(tmp_vfstab, 0, tmp_vfstab_len); 3233 (void) strlcpy(tmp_vfstab, vfstab, tmp_vfstab_len); 3234 (void) strlcat(tmp_vfstab, "XXXXXX", tmp_vfstab_len); 3235 if ((fd = mkstemp(tmp_vfstab)) == -1) { 3236 err = errno; 3237 be_print_err(gettext("_update_vfstab: " 3238 "mkstemp failed: %s\n"), strerror(err)); 3239 ret = errno_to_be_err(err); 3240 goto cleanup; 3241 } 3242 if ((tfile = fdopen(fd, "w")) == NULL) { 3243 err = errno; 3244 be_print_err(gettext("_update_vfstab: " 3245 "could not open file for write\n")); 3246 (void) close(fd); 3247 ret = errno_to_be_err(err); 3248 goto cleanup; 3249 } 3250 3251 while (fgets(comments_buf, BUFSIZ, comments)) { 3252 for (c = comments_buf; *c != '\0' && isspace(*c); c++) 3253 ; 3254 if (*c == '\0') { 3255 continue; 3256 } else if (*c == '#') { 3257 /* 3258 * If line is a comment line, just put 3259 * it through to the tmp vfstab. 3260 */ 3261 (void) fputs(comments_buf, tfile); 3262 } else { 3263 /* 3264 * Else line is a vfstab entry, grab it 3265 * into a vfstab struct. 3266 */ 3267 if (getvfsent(vfs_ents, &vp) != 0) { 3268 err = errno; 3269 be_print_err(gettext("_update_vfstab: " 3270 "getvfsent failed: %s\n"), strerror(err)); 3271 ret = errno_to_be_err(err); 3272 goto cleanup; 3273 } 3274 3275 if (vp.vfs_special == NULL || vp.vfs_mountp == NULL) { 3276 (void) putvfsent(tfile, &vp); 3277 continue; 3278 } 3279 3280 /* 3281 * If the entry is one of the entries in the list 3282 * of file systems to update, modify it's device 3283 * field to be correct for this BE. 3284 */ 3285 for (i = 0; i < fld->fs_num; i++) { 3286 if (strcmp(vp.vfs_special, fld->fs_list[i]) 3287 == 0) { 3288 /* 3289 * Found entry that needs an update. 3290 * Replace the root container dataset 3291 * location and be_name in the 3292 * entry's device. 3293 */ 3294 (void) strlcpy(dev, vp.vfs_special, 3295 sizeof (dev)); 3296 3297 if ((ret = update_dataset(dev, 3298 sizeof (dev), be_name, old_rc_loc, 3299 new_rc_loc)) != 0) { 3300 be_print_err( 3301 gettext("_update_vfstab: " 3302 "Failed to update device " 3303 "field for vfstab entry " 3304 "%s\n"), fld->fs_list[i]); 3305 goto cleanup; 3306 } 3307 3308 vp.vfs_special = dev; 3309 break; 3310 } 3311 } 3312 3313 /* Put entry through to tmp vfstab */ 3314 (void) putvfsent(tfile, &vp); 3315 } 3316 } 3317 3318 (void) fclose(comments); 3319 comments = NULL; 3320 (void) fclose(vfs_ents); 3321 vfs_ents = NULL; 3322 (void) fclose(tfile); 3323 tfile = NULL; 3324 3325 /* Copy tmp vfstab into place */ 3326 if (rename(tmp_vfstab, vfstab) != 0) { 3327 err = errno; 3328 be_print_err(gettext("_update_vfstab: " 3329 "failed to rename file %s to %s: %s\n"), tmp_vfstab, 3330 vfstab, strerror(err)); 3331 ret = errno_to_be_err(err); 3332 goto cleanup; 3333 } 3334 3335 /* Set the perms and ownership of the updated file */ 3336 if (chmod(vfstab, sb.st_mode) != 0) { 3337 err = errno; 3338 be_print_err(gettext("_update_vfstab: " 3339 "failed to chmod %s: %s\n"), vfstab, strerror(err)); 3340 ret = errno_to_be_err(err); 3341 goto cleanup; 3342 } 3343 if (chown(vfstab, sb.st_uid, sb.st_gid) != 0) { 3344 err = errno; 3345 be_print_err(gettext("_update_vfstab: " 3346 "failed to chown %s: %s\n"), vfstab, strerror(err)); 3347 ret = errno_to_be_err(err); 3348 goto cleanup; 3349 } 3350 3351 cleanup: 3352 if (comments != NULL) 3353 (void) fclose(comments); 3354 if (vfs_ents != NULL) 3355 (void) fclose(vfs_ents); 3356 (void) unlink(tmp_vfstab); 3357 (void) free(tmp_vfstab); 3358 if (tfile != NULL) 3359 (void) fclose(tfile); 3360 3361 return (ret); 3362 } 3363 3364 3365 /* 3366 * Function: be_get_auto_name 3367 * Description: Generate an auto name constructed based on the BE name 3368 * of the original BE or zone BE being cloned. 3369 * Parameters: 3370 * obe_name - name of the original BE or zone BE being cloned. 3371 * container_ds - container dataset for the zone. 3372 * Note: if zone_be is false this should be 3373 * NULL. 3374 * zone_be - flag that indicates if we are operating on a zone BE. 3375 * Returns: 3376 * Success - pointer to auto generated BE name. The name 3377 * is allocated in heap storage so the caller is 3378 * responsible for free'ing the name. 3379 * Failure - NULL 3380 * Scope: 3381 * Private 3382 */ 3383 static char * 3384 be_get_auto_name(char *obe_name, char *be_container_ds, boolean_t zone_be) 3385 { 3386 be_node_list_t *be_nodes = NULL; 3387 be_node_list_t *cur_be = NULL; 3388 char auto_be_name[MAXPATHLEN]; 3389 char base_be_name[MAXPATHLEN]; 3390 char cur_be_name[MAXPATHLEN]; 3391 char *num_str = NULL; 3392 char *c = NULL; 3393 int num = 0; 3394 int cur_num = 0; 3395 3396 errno = 0; 3397 3398 /* 3399 * Check if obe_name is already in an auto BE name format. 3400 * If it is, then strip off the increment number to get the 3401 * base name. 3402 */ 3403 (void) strlcpy(base_be_name, obe_name, sizeof (base_be_name)); 3404 3405 if ((num_str = strrchr(base_be_name, BE_AUTO_NAME_DELIM)) 3406 != NULL) { 3407 /* Make sure remaining string is all digits */ 3408 c = num_str + 1; 3409 while (c[0] != '\0' && isdigit(c[0])) 3410 c++; 3411 /* 3412 * If we're now at the end of the string strip off the 3413 * increment number. 3414 */ 3415 if (c[0] == '\0') 3416 num_str[0] = '\0'; 3417 } 3418 3419 if (zone_be) { 3420 if (be_container_ds == NULL) 3421 return (NULL); 3422 if (be_get_zone_be_list(obe_name, be_container_ds, 3423 &be_nodes) != BE_SUCCESS) { 3424 be_print_err(gettext("be_get_auto_name: " 3425 "be_get_zone_be_list failed\n")); 3426 return (NULL); 3427 } 3428 } else if (_be_list(NULL, &be_nodes) != BE_SUCCESS) { 3429 be_print_err(gettext("be_get_auto_name: be_list failed\n")); 3430 return (NULL); 3431 } 3432 3433 for (cur_be = be_nodes; cur_be != NULL; cur_be = cur_be->be_next_node) { 3434 (void) strlcpy(cur_be_name, cur_be->be_node_name, 3435 sizeof (cur_be_name)); 3436 3437 /* If cur_be_name doesn't match at least base be name, skip. */ 3438 if (strncmp(cur_be_name, base_be_name, strlen(base_be_name)) 3439 != 0) 3440 continue; 3441 3442 /* Get the string following the base be name */ 3443 num_str = cur_be_name + strlen(base_be_name); 3444 3445 /* 3446 * If nothing follows the base be name, this cur_be_name 3447 * is the BE named with the base be name, skip. 3448 */ 3449 if (num_str == NULL || num_str[0] == '\0') 3450 continue; 3451 3452 /* 3453 * Remove the name delimiter. If its not there, 3454 * cur_be_name isn't part of this BE name stream, skip. 3455 */ 3456 if (num_str[0] == BE_AUTO_NAME_DELIM) 3457 num_str++; 3458 else 3459 continue; 3460 3461 /* Make sure remaining string is all digits */ 3462 c = num_str; 3463 while (c[0] != '\0' && isdigit(c[0])) 3464 c++; 3465 if (c[0] != '\0') 3466 continue; 3467 3468 /* Convert the number string to an int */ 3469 cur_num = atoi(num_str); 3470 3471 /* 3472 * If failed to convert the string, skip it. If its too 3473 * long to be converted to an int, we wouldn't auto generate 3474 * this number anyway so there couldn't be a conflict. 3475 * We treat it as a manually created BE name. 3476 */ 3477 if (cur_num == 0 && errno == EINVAL) 3478 continue; 3479 3480 /* 3481 * Compare current number to current max number, 3482 * take higher of the two. 3483 */ 3484 if (cur_num > num) 3485 num = cur_num; 3486 } 3487 3488 /* 3489 * Store off a copy of 'num' incase we need it later. If incrementing 3490 * 'num' causes it to roll over, this means 'num' is the largest 3491 * positive int possible; we'll need it later in the loop to determine 3492 * if we've exhausted all possible increment numbers. We store it in 3493 * 'cur_num'. 3494 */ 3495 cur_num = num; 3496 3497 /* Increment 'num' to get new auto BE name number */ 3498 if (++num <= 0) { 3499 int ret = 0; 3500 3501 /* 3502 * Since incrementing 'num' caused it to rollover, start 3503 * over at 0 and find the first available number. 3504 */ 3505 for (num = 0; num < cur_num; num++) { 3506 3507 (void) snprintf(cur_be_name, sizeof (cur_be_name), 3508 "%s%c%d", base_be_name, BE_AUTO_NAME_DELIM, num); 3509 3510 ret = zpool_iter(g_zfs, be_exists_callback, 3511 cur_be_name); 3512 3513 if (ret == 0) { 3514 /* 3515 * BE name doesn't exist, break out 3516 * to use 'num'. 3517 */ 3518 break; 3519 } else if (ret == 1) { 3520 /* BE name exists, continue looking */ 3521 continue; 3522 } else { 3523 be_print_err(gettext("be_get_auto_name: " 3524 "zpool_iter failed: %s\n"), 3525 libzfs_error_description(g_zfs)); 3526 be_free_list(be_nodes); 3527 return (NULL); 3528 } 3529 } 3530 3531 /* 3532 * If 'num' equals 'cur_num', we've exhausted all possible 3533 * auto BE names for this base BE name. 3534 */ 3535 if (num == cur_num) { 3536 be_print_err(gettext("be_get_auto_name: " 3537 "No more available auto BE names for base " 3538 "BE name %s\n"), base_be_name); 3539 be_free_list(be_nodes); 3540 return (NULL); 3541 } 3542 } 3543 3544 be_free_list(be_nodes); 3545 3546 /* 3547 * Generate string for auto BE name. 3548 */ 3549 (void) snprintf(auto_be_name, sizeof (auto_be_name), "%s%c%d", 3550 base_be_name, BE_AUTO_NAME_DELIM, num); 3551 3552 if ((c = strdup(auto_be_name)) == NULL) { 3553 be_print_err(gettext("be_get_auto_name: " 3554 "memory allocation failed\n")); 3555 return (NULL); 3556 } 3557 3558 return (c); 3559 } 3560 3561 /* 3562 * Function: be_get_console_prop 3563 * Description: Determine console device. 3564 * Returns: 3565 * Success - pointer to console setting. 3566 * Failure - NULL 3567 * Scope: 3568 * Private 3569 */ 3570 static char * 3571 be_get_console_prop(void) 3572 { 3573 di_node_t dn; 3574 char *console = NULL; 3575 3576 if ((dn = di_init("/", DINFOPROP)) == DI_NODE_NIL) { 3577 be_print_err(gettext("be_get_console_prop: " 3578 "di_init() failed\n")); 3579 return (NULL); 3580 } 3581 3582 if (di_prop_lookup_strings(DDI_DEV_T_ANY, dn, 3583 "console", &console) != -1) { 3584 di_fini(dn); 3585 return (console); 3586 } 3587 3588 if (console == NULL) { 3589 if (di_prop_lookup_strings(DDI_DEV_T_ANY, dn, 3590 "output-device", &console) != -1) { 3591 di_fini(dn); 3592 if (strncmp(console, "screen", strlen("screen")) == 0) 3593 console = BE_DEFAULT_CONSOLE; 3594 } 3595 } 3596 3597 /* 3598 * Default console to text 3599 */ 3600 if (console == NULL) { 3601 console = BE_DEFAULT_CONSOLE; 3602 } 3603 3604 return (console); 3605 } 3606 3607 /* 3608 * Function: be_create_menu 3609 * Description: 3610 * This function is used if no menu.lst file exists. In 3611 * this case a new file is created and if needed default 3612 * lines are added to the file. 3613 * Parameters: 3614 * pool - The name of the pool the menu.lst file is on 3615 * menu_file - The name of the file we're creating. 3616 * menu_fp - A pointer to the file pointer of the file we 3617 * created. This is also used to pass back the file 3618 * pointer to the newly created file. 3619 * mode - the original mode used for the failed attempt to 3620 * non-existent file. 3621 * Returns: 3622 * BE_SUCCESS - Success 3623 * be_errno_t - Failure 3624 * Scope: 3625 * Private 3626 */ 3627 static int 3628 be_create_menu( 3629 char *pool, 3630 char *menu_file, 3631 FILE **menu_fp, 3632 char *mode) 3633 { 3634 be_node_list_t *be_nodes = NULL; 3635 char *menu_path = NULL; 3636 char *be_rpool = NULL; 3637 char *be_name = NULL; 3638 char *console = NULL; 3639 errno = 0; 3640 3641 if (menu_file == NULL || menu_fp == NULL || mode == NULL) 3642 return (BE_ERR_INVAL); 3643 3644 menu_path = strdup(menu_file); 3645 if (menu_path == NULL) 3646 return (BE_ERR_NOMEM); 3647 3648 (void) dirname(menu_path); 3649 if (*menu_path == '.') { 3650 free(menu_path); 3651 return (BE_ERR_BAD_MENU_PATH); 3652 } 3653 if (mkdirp(menu_path, 3654 S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == -1 && 3655 errno != EEXIST) { 3656 free(menu_path); 3657 be_print_err(gettext("be_create_menu: Failed to create the %s " 3658 "directory: %s\n"), menu_path, strerror(errno)); 3659 return (errno_to_be_err(errno)); 3660 } 3661 free(menu_path); 3662 3663 /* 3664 * Check to see if this system supports grub 3665 */ 3666 if (be_has_grub()) { 3667 /* 3668 * The grub menu is missing so we need to create it 3669 * and fill in the first few lines. 3670 */ 3671 FILE *temp_fp = fopen(menu_file, "a+"); 3672 if (temp_fp == NULL) { 3673 *menu_fp = NULL; 3674 return (errno_to_be_err(errno)); 3675 } 3676 3677 if ((console = be_get_console_prop()) != NULL) { 3678 3679 /* 3680 * If console is redirected to serial line, 3681 * GRUB splash screen will not be enabled. 3682 */ 3683 if (strncmp(console, "text", strlen("text")) == 0 || 3684 strncmp(console, "graphics", 3685 strlen("graphics")) == 0) { 3686 3687 (void) fprintf(temp_fp, "%s\n", BE_GRUB_SPLASH); 3688 (void) fprintf(temp_fp, "%s\n", 3689 BE_GRUB_FOREGROUND); 3690 (void) fprintf(temp_fp, "%s\n", 3691 BE_GRUB_BACKGROUND); 3692 (void) fprintf(temp_fp, "%s\n", 3693 BE_GRUB_DEFAULT); 3694 } else { 3695 be_print_err(gettext("be_create_menu: " 3696 "console on serial line, " 3697 "GRUB splash image will be disabled\n")); 3698 } 3699 } 3700 3701 (void) fprintf(temp_fp, "timeout 30\n"); 3702 (void) fclose(temp_fp); 3703 3704 } else { 3705 /* 3706 * The menu file doesn't exist so we need to create a 3707 * blank file. 3708 */ 3709 FILE *temp_fp = fopen(menu_file, "w+"); 3710 if (temp_fp == NULL) { 3711 *menu_fp = NULL; 3712 return (errno_to_be_err(errno)); 3713 } 3714 (void) fclose(temp_fp); 3715 } 3716 3717 /* 3718 * Now we need to add all the BE's back into the the file. 3719 */ 3720 if (_be_list(NULL, &be_nodes) == BE_SUCCESS) { 3721 while (be_nodes != NULL) { 3722 if (strcmp(pool, be_nodes->be_rpool) == 0) { 3723 (void) be_append_menu(be_nodes->be_node_name, 3724 be_nodes->be_rpool, NULL, NULL, NULL); 3725 } 3726 if (be_nodes->be_active_on_boot) { 3727 be_rpool = strdup(be_nodes->be_rpool); 3728 be_name = strdup(be_nodes->be_node_name); 3729 } 3730 3731 be_nodes = be_nodes->be_next_node; 3732 } 3733 } 3734 be_free_list(be_nodes); 3735 3736 /* 3737 * Check to see if this system supports grub 3738 */ 3739 if (be_has_grub()) { 3740 int err = be_change_grub_default(be_name, be_rpool); 3741 if (err != BE_SUCCESS) 3742 return (err); 3743 } 3744 *menu_fp = fopen(menu_file, mode); 3745 if (*menu_fp == NULL) 3746 return (errno_to_be_err(errno)); 3747 3748 return (BE_SUCCESS); 3749 } 3750 3751 /* 3752 * Function: be_open_menu 3753 * Description: 3754 * This function is used it open the menu.lst file. If this 3755 * file does not exist be_create_menu is called to create it 3756 * and the open file pointer is returned. If the file does 3757 * exist it is simply opened using the mode passed in. 3758 * Parameters: 3759 * pool - The name of the pool the menu.lst file is on 3760 * menu_file - The name of the file we're opening. 3761 * menu_fp - A pointer to the file pointer of the file we're 3762 * opening. This is also used to pass back the file 3763 * pointer. 3764 * mode - the original mode to be used for opening the menu.lst 3765 * file. 3766 * create_menu - If this is true and the menu.lst file does not 3767 * exist we will attempt to re-create it. However 3768 * if it's false the error returned from the fopen 3769 * will be returned. 3770 * Returns: 3771 * BE_SUCCESS - Success 3772 * be_errno_t - Failure 3773 * Scope: 3774 * Private 3775 */ 3776 static int 3777 be_open_menu( 3778 char *pool, 3779 char *menu_file, 3780 FILE **menu_fp, 3781 char *mode, 3782 boolean_t create_menu) 3783 { 3784 int err = 0; 3785 boolean_t set_print = B_FALSE; 3786 3787 *menu_fp = fopen(menu_file, mode); 3788 err = errno; 3789 if (*menu_fp == NULL) { 3790 if (err == ENOENT && create_menu) { 3791 be_print_err(gettext("be_open_menu: menu.lst " 3792 "file %s does not exist,\n"), menu_file); 3793 if (!do_print) { 3794 set_print = B_TRUE; 3795 do_print = B_TRUE; 3796 } 3797 be_print_err(gettext("WARNING: menu.lst " 3798 "file %s does not exist,\n generating " 3799 "a new menu.lst file\n"), menu_file); 3800 if (set_print) 3801 do_print = B_FALSE; 3802 err = 0; 3803 if ((err = be_create_menu(pool, menu_file, 3804 menu_fp, mode)) == ENOENT) 3805 return (BE_ERR_NO_MENU); 3806 else if (err != BE_SUCCESS) 3807 return (err); 3808 else if (*menu_fp == NULL) 3809 return (BE_ERR_NO_MENU); 3810 } else { 3811 be_print_err(gettext("be_open_menu: failed " 3812 "to open menu.lst file %s\n"), menu_file); 3813 if (err == ENOENT) 3814 return (BE_ERR_NO_MENU); 3815 else 3816 return (errno_to_be_err(err)); 3817 } 3818 } 3819 return (BE_SUCCESS); 3820 } 3821