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