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