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 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * bootadm(1M) is a new utility for managing bootability of 28 * Solaris *Newboot* environments. It has two primary tasks: 29 * - Allow end users to manage bootability of Newboot Solaris instances 30 * - Provide services to other subsystems in Solaris (primarily Install) 31 */ 32 33 /* Headers */ 34 #include <stdio.h> 35 #include <errno.h> 36 #include <stdlib.h> 37 #include <string.h> 38 #include <unistd.h> 39 #include <sys/types.h> 40 #include <sys/stat.h> 41 #include <stdarg.h> 42 #include <limits.h> 43 #include <signal.h> 44 #include <sys/wait.h> 45 #include <sys/mnttab.h> 46 #include <sys/mntent.h> 47 #include <sys/statvfs.h> 48 #include <libnvpair.h> 49 #include <ftw.h> 50 #include <fcntl.h> 51 #include <strings.h> 52 #include <utime.h> 53 #include <sys/systeminfo.h> 54 #include <sys/dktp/fdisk.h> 55 #include <sys/param.h> 56 #include <dirent.h> 57 #include <ctype.h> 58 #include <libgen.h> 59 #include <sys/sysmacros.h> 60 #include <libscf.h> 61 62 #if !defined(_OPB) 63 #include <sys/ucode.h> 64 #endif 65 66 #include <pwd.h> 67 #include <grp.h> 68 #include <device_info.h> 69 #include <sys/vtoc.h> 70 #include <sys/efi_partition.h> 71 72 #include <locale.h> 73 74 #include "message.h" 75 #include "bootadm.h" 76 77 #ifndef TEXT_DOMAIN 78 #define TEXT_DOMAIN "SUNW_OST_OSCMD" 79 #endif /* TEXT_DOMAIN */ 80 81 /* Type definitions */ 82 83 /* Primary subcmds */ 84 typedef enum { 85 BAM_MENU = 3, 86 BAM_ARCHIVE 87 } subcmd_t; 88 89 typedef enum { 90 OPT_ABSENT = 0, /* No option */ 91 OPT_REQ, /* option required */ 92 OPT_OPTIONAL /* option may or may not be present */ 93 } option_t; 94 95 typedef struct { 96 char *subcmd; 97 option_t option; 98 error_t (*handler)(); 99 int unpriv; /* is this an unprivileged command */ 100 } subcmd_defn_t; 101 102 #define LINE_INIT 0 /* lineNum initial value */ 103 #define ENTRY_INIT -1 /* entryNum initial value */ 104 #define ALL_ENTRIES -2 /* selects all boot entries */ 105 106 #define GRUB_DIR "/boot/grub" 107 #define GRUB_STAGE2 GRUB_DIR "/stage2" 108 #define GRUB_MENU "/boot/grub/menu.lst" 109 #define MENU_TMP "/boot/grub/menu.lst.tmp" 110 #define GRUB_BACKUP_MENU "/etc/lu/GRUB_backup_menu" 111 #define RAMDISK_SPECIAL "/ramdisk" 112 #define STUBBOOT "/stubboot" 113 #define MULTIBOOT "/platform/i86pc/multiboot" 114 #define GRUBSIGN_DIR "/boot/grub/bootsign" 115 #define GRUBSIGN_BACKUP "/etc/bootsign" 116 #define GRUBSIGN_UFS_PREFIX "rootfs" 117 #define GRUBSIGN_ZFS_PREFIX "pool_" 118 #define GRUBSIGN_LU_PREFIX "BE_" 119 #define UFS_SIGNATURE_LIST "/var/run/grub_ufs_signatures" 120 #define ZFS_LEGACY_MNTPT "/tmp/bootadm_mnt_zfs_legacy" 121 122 #define BOOTADM_RDONLY_TEST "BOOTADM_RDONLY_TEST" 123 124 /* lock related */ 125 #define BAM_LOCK_FILE "/var/run/bootadm.lock" 126 #define LOCK_FILE_PERMS (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) 127 128 #define CREATE_RAMDISK "boot/solaris/bin/create_ramdisk" 129 #define CREATE_DISKMAP "boot/solaris/bin/create_diskmap" 130 #define EXTRACT_BOOT_FILELIST "boot/solaris/bin/extract_boot_filelist" 131 #define GRUBDISK_MAP "/var/run/solaris_grubdisk.map" 132 133 #define GRUB_slice "/etc/lu/GRUB_slice" 134 #define GRUB_root "/etc/lu/GRUB_root" 135 #define GRUB_fdisk "/etc/lu/GRUB_fdisk" 136 #define GRUB_fdisk_target "/etc/lu/GRUB_fdisk_target" 137 #define FINDROOT_INSTALLGRUB "/etc/lu/installgrub.findroot" 138 #define LULIB "/usr/lib/lu/lulib" 139 #define LULIB_PROPAGATE_FILE "lulib_propagate_file" 140 #define CKSUM "/usr/bin/cksum" 141 #define LU_MENU_CKSUM "/etc/lu/menu.cksum" 142 #define BOOTADM "/sbin/bootadm" 143 144 #define INSTALLGRUB "/sbin/installgrub" 145 #define STAGE1 "/boot/grub/stage1" 146 #define STAGE2 "/boot/grub/stage2" 147 148 typedef enum zfs_mnted { 149 ZFS_MNT_ERROR = -1, 150 LEGACY_MOUNTED = 1, 151 LEGACY_ALREADY, 152 ZFS_MOUNTED, 153 ZFS_ALREADY 154 } zfs_mnted_t; 155 156 157 158 159 /* 160 * The following two defines are used to detect and create the correct 161 * boot archive when safemode patching is underway. LOFS_PATCH_FILE is a 162 * contracted private interface between bootadm and the install 163 * consolidation. It is set by pdo.c when a patch with SUNW_PATCH_SAFEMODE 164 * is applied. 165 */ 166 167 #define LOFS_PATCH_FILE "/var/run/.patch_loopback_mode" 168 #define LOFS_PATCH_MNT "/var/run/.patch_root_loopbackmnt" 169 170 /* 171 * Default file attributes 172 */ 173 #define DEFAULT_DEV_MODE 0644 /* default permissions */ 174 #define DEFAULT_DEV_UID 0 /* user root */ 175 #define DEFAULT_DEV_GID 3 /* group sys */ 176 177 /* 178 * Menu related 179 * menu_cmd_t and menu_cmds must be kept in sync 180 */ 181 char *menu_cmds[] = { 182 "default", /* DEFAULT_CMD */ 183 "timeout", /* TIMEOUT_CMD */ 184 "title", /* TITLE_CMD */ 185 "root", /* ROOT_CMD */ 186 "kernel", /* KERNEL_CMD */ 187 "kernel$", /* KERNEL_DOLLAR_CMD */ 188 "module", /* MODULE_CMD */ 189 "module$", /* MODULE_DOLLAR_CMD */ 190 " ", /* SEP_CMD */ 191 "#", /* COMMENT_CMD */ 192 "chainloader", /* CHAINLOADER_CMD */ 193 "args", /* ARGS_CMD */ 194 "findroot", /* FINDROOT_CMD */ 195 NULL 196 }; 197 198 #define OPT_ENTRY_NUM "entry" 199 200 /* 201 * exec_cmd related 202 */ 203 typedef struct { 204 line_t *head; 205 line_t *tail; 206 } filelist_t; 207 208 #define BOOT_FILE_LIST "boot/solaris/filelist.ramdisk" 209 #define ETC_FILE_LIST "etc/boot/solaris/filelist.ramdisk" 210 211 #define FILE_STAT "boot/solaris/filestat.ramdisk" 212 #define FILE_STAT_TMP "boot/solaris/filestat.ramdisk.tmp" 213 #define DIR_PERMS (S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) 214 #define FILE_STAT_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) 215 216 /* Globals */ 217 int bam_verbose; 218 int bam_force; 219 int bam_debug; 220 static char *prog; 221 static subcmd_t bam_cmd; 222 static char *bam_root; 223 static int bam_rootlen; 224 static int bam_root_readonly; 225 static int bam_alt_root; 226 static char *bam_subcmd; 227 static char *bam_opt; 228 static char **bam_argv; 229 static int bam_argc; 230 static int bam_check; 231 static int bam_smf_check; 232 static int bam_lock_fd = -1; 233 static int bam_zfs; 234 static char rootbuf[PATH_MAX] = "/"; 235 static int bam_update_all; 236 static int bam_alt_platform; 237 static char *bam_platform; 238 239 /* function prototypes */ 240 static void parse_args_internal(int, char *[]); 241 static void parse_args(int, char *argv[]); 242 static error_t bam_menu(char *, char *, int, char *[]); 243 static error_t bam_archive(char *, char *); 244 245 static void bam_exit(int); 246 static void bam_lock(void); 247 static void bam_unlock(void); 248 249 static int exec_cmd(char *, filelist_t *); 250 static error_t read_globals(menu_t *, char *, char *, int); 251 static int menu_on_bootdisk(char *os_root, char *menu_root); 252 static menu_t *menu_read(char *); 253 static error_t menu_write(char *, menu_t *); 254 static void linelist_free(line_t *); 255 static void menu_free(menu_t *); 256 static void filelist_free(filelist_t *); 257 static error_t list2file(char *, char *, char *, line_t *); 258 static error_t list_entry(menu_t *, char *, char *); 259 static error_t delete_all_entries(menu_t *, char *, char *); 260 static error_t update_entry(menu_t *mp, char *menu_root, char *opt); 261 static error_t update_temp(menu_t *mp, char *dummy, char *opt); 262 263 static error_t update_archive(char *, char *); 264 static error_t list_archive(char *, char *); 265 static error_t update_all(char *, char *); 266 static error_t read_list(char *, filelist_t *); 267 static error_t set_global(menu_t *, char *, int); 268 static error_t set_option(menu_t *, char *, char *); 269 static error_t set_kernel(menu_t *, menu_cmd_t, char *, char *, size_t); 270 static error_t get_kernel(menu_t *, menu_cmd_t, char *, size_t); 271 static char *expand_path(const char *); 272 273 static long s_strtol(char *); 274 static int s_fputs(char *, FILE *); 275 276 static int is_zfs(char *root); 277 static int is_ufs(char *root); 278 static int is_pcfs(char *root); 279 static int is_amd64(void); 280 static char *get_machine(void); 281 static void append_to_flist(filelist_t *, char *); 282 static char *mount_top_dataset(char *pool, zfs_mnted_t *mnted); 283 static int umount_top_dataset(char *pool, zfs_mnted_t mnted, char *mntpt); 284 static int ufs_add_to_sign_list(char *sign); 285 static error_t synchronize_BE_menu(void); 286 287 #if !defined(_OPB) 288 static void ucode_install(); 289 #endif 290 291 /* Menu related sub commands */ 292 static subcmd_defn_t menu_subcmds[] = { 293 "set_option", OPT_ABSENT, set_option, 0, /* PUB */ 294 "list_entry", OPT_OPTIONAL, list_entry, 1, /* PUB */ 295 "delete_all_entries", OPT_ABSENT, delete_all_entries, 0, /* PVT */ 296 "update_entry", OPT_REQ, update_entry, 0, /* menu */ 297 "update_temp", OPT_OPTIONAL, update_temp, 0, /* reboot */ 298 "upgrade", OPT_ABSENT, upgrade_menu, 0, /* menu */ 299 NULL, 0, NULL, 0 /* must be last */ 300 }; 301 302 /* Archive related sub commands */ 303 static subcmd_defn_t arch_subcmds[] = { 304 "update", OPT_ABSENT, update_archive, 0, /* PUB */ 305 "update_all", OPT_ABSENT, update_all, 0, /* PVT */ 306 "list", OPT_OPTIONAL, list_archive, 1, /* PUB */ 307 NULL, 0, NULL, 0 /* must be last */ 308 }; 309 310 static struct { 311 nvlist_t *new_nvlp; 312 nvlist_t *old_nvlp; 313 int need_update; 314 } walk_arg; 315 316 317 struct safefile { 318 char *name; 319 struct safefile *next; 320 }; 321 322 static struct safefile *safefiles = NULL; 323 #define NEED_UPDATE_FILE "/etc/svc/volatile/boot_archive_needs_update" 324 325 static int sync_menu = 1; /* whether we need to sync the BE menus */ 326 327 static void 328 usage(void) 329 { 330 (void) fprintf(stderr, "USAGE:\n"); 331 332 333 /* archive usage */ 334 (void) fprintf(stderr, 335 "\t%s update-archive [-vn] [-R altroot [-p platform>]]\n", prog); 336 (void) fprintf(stderr, 337 "\t%s list-archive [-R altroot [-p platform>]]\n", prog); 338 #if !defined(_OPB) 339 /* x86 only */ 340 (void) fprintf(stderr, "\t%s set-menu [-R altroot] key=value\n", prog); 341 (void) fprintf(stderr, "\t%s list-menu [-R altroot]\n", prog); 342 #endif 343 } 344 345 int 346 main(int argc, char *argv[]) 347 { 348 error_t ret; 349 350 (void) setlocale(LC_ALL, ""); 351 (void) textdomain(TEXT_DOMAIN); 352 353 if ((prog = strrchr(argv[0], '/')) == NULL) { 354 prog = argv[0]; 355 } else { 356 prog++; 357 } 358 359 INJECT_ERROR1("ASSERT_ON", assert(0)) 360 361 /* 362 * Don't depend on caller's umask 363 */ 364 (void) umask(0022); 365 366 parse_args(argc, argv); 367 368 switch (bam_cmd) { 369 case BAM_MENU: 370 ret = bam_menu(bam_subcmd, bam_opt, bam_argc, bam_argv); 371 break; 372 case BAM_ARCHIVE: 373 ret = bam_archive(bam_subcmd, bam_opt); 374 break; 375 default: 376 usage(); 377 bam_exit(1); 378 } 379 380 if (ret != BAM_SUCCESS) 381 bam_exit(1); 382 383 bam_unlock(); 384 return (0); 385 } 386 387 /* 388 * Equivalence of public and internal commands: 389 * update-archive -- -a update 390 * list-archive -- -a list 391 * set-menu -- -m set_option 392 * list-menu -- -m list_entry 393 * update-menu -- -m update_entry 394 */ 395 static struct cmd_map { 396 char *bam_cmdname; 397 int bam_cmd; 398 char *bam_subcmd; 399 } cmd_map[] = { 400 { "update-archive", BAM_ARCHIVE, "update"}, 401 { "list-archive", BAM_ARCHIVE, "list"}, 402 { "set-menu", BAM_MENU, "set_option"}, 403 { "list-menu", BAM_MENU, "list_entry"}, 404 { "update-menu", BAM_MENU, "update_entry"}, 405 { NULL, 0, NULL} 406 }; 407 408 /* 409 * Commands syntax published in bootadm(1M) are parsed here 410 */ 411 static void 412 parse_args(int argc, char *argv[]) 413 { 414 struct cmd_map *cmp = cmd_map; 415 416 /* command conforming to the final spec */ 417 if (argc > 1 && argv[1][0] != '-') { 418 /* 419 * Map commands to internal table. 420 */ 421 while (cmp->bam_cmdname) { 422 if (strcmp(argv[1], cmp->bam_cmdname) == 0) { 423 bam_cmd = cmp->bam_cmd; 424 bam_subcmd = cmp->bam_subcmd; 425 break; 426 } 427 cmp++; 428 } 429 if (cmp->bam_cmdname == NULL) { 430 usage(); 431 bam_exit(1); 432 } 433 argc--; 434 argv++; 435 } 436 437 parse_args_internal(argc, argv); 438 } 439 440 /* 441 * A combination of public and private commands are parsed here. 442 * The internal syntax and the corresponding functionality are: 443 * -a update -- update-archive 444 * -a list -- list-archive 445 * -a update-all -- (reboot to sync all mounted OS archive) 446 * -m update_entry -- update-menu 447 * -m list_entry -- list-menu 448 * -m update_temp -- (reboot -- [boot-args]) 449 * -m delete_all_entries -- (called from install) 450 */ 451 static void 452 parse_args_internal(int argc, char *argv[]) 453 { 454 int c, error; 455 extern char *optarg; 456 extern int optind, opterr; 457 458 /* Suppress error message from getopt */ 459 opterr = 0; 460 461 error = 0; 462 while ((c = getopt(argc, argv, "a:d:fm:no:vCR:p:Z")) != -1) { 463 switch (c) { 464 case 'a': 465 if (bam_cmd) { 466 error = 1; 467 bam_error(MULT_CMDS, c); 468 } 469 bam_cmd = BAM_ARCHIVE; 470 bam_subcmd = optarg; 471 break; 472 case 'd': 473 if (bam_debug) { 474 error = 1; 475 bam_error(DUP_OPT, c); 476 } 477 bam_debug = s_strtol(optarg); 478 break; 479 case 'f': 480 if (bam_force) { 481 error = 1; 482 bam_error(DUP_OPT, c); 483 } 484 bam_force = 1; 485 break; 486 case 'm': 487 if (bam_cmd) { 488 error = 1; 489 bam_error(MULT_CMDS, c); 490 } 491 bam_cmd = BAM_MENU; 492 bam_subcmd = optarg; 493 break; 494 case 'n': 495 if (bam_check) { 496 error = 1; 497 bam_error(DUP_OPT, c); 498 } 499 bam_check = 1; 500 break; 501 case 'o': 502 if (bam_opt) { 503 error = 1; 504 bam_error(DUP_OPT, c); 505 } 506 bam_opt = optarg; 507 break; 508 case 'v': 509 if (bam_verbose) { 510 error = 1; 511 bam_error(DUP_OPT, c); 512 } 513 bam_verbose = 1; 514 break; 515 case 'C': 516 bam_smf_check = 1; 517 break; 518 case 'R': 519 if (bam_root) { 520 error = 1; 521 bam_error(DUP_OPT, c); 522 break; 523 } else if (realpath(optarg, rootbuf) == NULL) { 524 error = 1; 525 bam_error(CANT_RESOLVE, optarg, 526 strerror(errno)); 527 break; 528 } 529 bam_alt_root = 1; 530 bam_root = rootbuf; 531 bam_rootlen = strlen(rootbuf); 532 break; 533 case 'p': 534 bam_alt_platform = 1; 535 bam_platform = optarg; 536 if ((strcmp(bam_platform, "i86pc") != 0) && 537 (strcmp(bam_platform, "sun4u") != 0) && 538 (strcmp(bam_platform, "sun4v") != 0)) { 539 error = 1; 540 bam_error(INVALID_PLAT, bam_platform); 541 } 542 break; 543 case 'Z': 544 bam_zfs = 1; 545 break; 546 case '?': 547 error = 1; 548 bam_error(BAD_OPT, optopt); 549 break; 550 default : 551 error = 1; 552 bam_error(BAD_OPT, c); 553 break; 554 } 555 } 556 557 /* 558 * An alternate platform requires an alternate root 559 */ 560 if (bam_alt_platform && bam_alt_root == 0) { 561 usage(); 562 bam_exit(0); 563 } 564 565 /* 566 * A command option must be specfied 567 */ 568 if (!bam_cmd) { 569 if (bam_opt && strcmp(bam_opt, "all") == 0) { 570 usage(); 571 bam_exit(0); 572 } 573 bam_error(NEED_CMD); 574 error = 1; 575 } 576 577 if (error) { 578 usage(); 579 bam_exit(1); 580 } 581 582 if (optind > argc) { 583 bam_error(INT_ERROR, "parse_args"); 584 bam_exit(1); 585 } else if (optind < argc) { 586 bam_argv = &argv[optind]; 587 bam_argc = argc - optind; 588 } 589 590 /* 591 * -n implies verbose mode 592 */ 593 if (bam_check) 594 bam_verbose = 1; 595 } 596 597 static error_t 598 check_subcmd_and_options( 599 char *subcmd, 600 char *opt, 601 subcmd_defn_t *table, 602 error_t (**fp)()) 603 { 604 int i; 605 606 if (subcmd == NULL) { 607 bam_error(NEED_SUBCMD); 608 return (BAM_ERROR); 609 } 610 611 if (strcmp(subcmd, "set_option") == 0) { 612 if (bam_argc == 0 || bam_argv == NULL || bam_argv[0] == NULL) { 613 bam_error(MISSING_ARG); 614 usage(); 615 return (BAM_ERROR); 616 } else if (bam_argc > 1 || bam_argv[1] != NULL) { 617 bam_error(TRAILING_ARGS); 618 usage(); 619 return (BAM_ERROR); 620 } 621 } else if (strcmp(subcmd, "update_all") == 0) { 622 /* 623 * The only option we accept for the "update_all" 624 * subcmd is "fastboot". 625 */ 626 if (bam_argc > 1 || (bam_argc == 1 && 627 strcmp(bam_argv[0], "fastboot") != 0)) { 628 bam_error(TRAILING_ARGS); 629 usage(); 630 return (BAM_ERROR); 631 } 632 if (bam_argc == 1) 633 sync_menu = 0; 634 } else if (bam_argc || bam_argv) { 635 bam_error(TRAILING_ARGS); 636 usage(); 637 return (BAM_ERROR); 638 } 639 640 if (bam_root == NULL) { 641 bam_root = rootbuf; 642 bam_rootlen = 1; 643 } 644 645 /* verify that subcmd is valid */ 646 for (i = 0; table[i].subcmd != NULL; i++) { 647 if (strcmp(table[i].subcmd, subcmd) == 0) 648 break; 649 } 650 651 if (table[i].subcmd == NULL) { 652 bam_error(INVALID_SUBCMD, subcmd); 653 return (BAM_ERROR); 654 } 655 656 if (table[i].unpriv == 0 && geteuid() != 0) { 657 bam_error(MUST_BE_ROOT); 658 return (BAM_ERROR); 659 } 660 661 /* 662 * Currently only privileged commands need a lock 663 */ 664 if (table[i].unpriv == 0) 665 bam_lock(); 666 667 /* subcmd verifies that opt is appropriate */ 668 if (table[i].option != OPT_OPTIONAL) { 669 if ((table[i].option == OPT_REQ) ^ (opt != NULL)) { 670 if (opt) 671 bam_error(NO_OPT_REQ, subcmd); 672 else 673 bam_error(MISS_OPT, subcmd); 674 return (BAM_ERROR); 675 } 676 } 677 678 *fp = table[i].handler; 679 680 return (BAM_SUCCESS); 681 } 682 683 /* 684 * NOTE: A single "/" is also considered a trailing slash and will 685 * be deleted. 686 */ 687 static void 688 elide_trailing_slash(const char *src, char *dst, size_t dstsize) 689 { 690 size_t dstlen; 691 692 assert(src); 693 assert(dst); 694 695 (void) strlcpy(dst, src, dstsize); 696 697 dstlen = strlen(dst); 698 if (dst[dstlen - 1] == '/') { 699 dst[dstlen - 1] = '\0'; 700 } 701 } 702 703 static error_t 704 bam_menu(char *subcmd, char *opt, int largc, char *largv[]) 705 { 706 error_t ret; 707 char menu_path[PATH_MAX]; 708 char clean_menu_root[PATH_MAX]; 709 char path[PATH_MAX]; 710 menu_t *menu; 711 char menu_root[PATH_MAX]; 712 struct stat sb; 713 error_t (*f)(menu_t *mp, char *menu_path, char *opt); 714 char *special; 715 char *pool = NULL; 716 zfs_mnted_t zmnted; 717 char *zmntpt; 718 char *osdev; 719 char *osroot; 720 const char *fcn = "bam_menu()"; 721 722 /* 723 * Menu sub-command only applies to GRUB (i.e. x86) 724 */ 725 if (!is_grub(bam_alt_root ? bam_root : "/")) { 726 bam_error(NOT_GRUB_BOOT); 727 return (BAM_ERROR); 728 } 729 730 /* 731 * Check arguments 732 */ 733 ret = check_subcmd_and_options(subcmd, opt, menu_subcmds, &f); 734 if (ret == BAM_ERROR) { 735 return (BAM_ERROR); 736 } 737 738 assert(bam_root); 739 740 (void) strlcpy(menu_root, bam_root, sizeof (menu_root)); 741 osdev = osroot = NULL; 742 743 if (strcmp(subcmd, "update_entry") == 0) { 744 assert(opt); 745 746 osdev = strtok(opt, ","); 747 assert(osdev); 748 osroot = strtok(NULL, ","); 749 if (osroot) { 750 /* fixup bam_root so that it points at osroot */ 751 if (realpath(osroot, rootbuf) == NULL) { 752 bam_error(CANT_RESOLVE, osroot, 753 strerror(errno)); 754 return (BAM_ERROR); 755 } 756 bam_alt_root = 1; 757 bam_root = rootbuf; 758 bam_rootlen = strlen(rootbuf); 759 } 760 } 761 762 /* 763 * We support menu on PCFS (under certain conditions), but 764 * not the OS root 765 */ 766 if (is_pcfs(bam_root)) { 767 bam_error(PCFS_ROOT_NOTSUP, bam_root); 768 return (BAM_ERROR); 769 } 770 771 if (stat(menu_root, &sb) == -1) { 772 bam_error(CANNOT_LOCATE_GRUB_MENU); 773 return (BAM_ERROR); 774 } 775 776 BAM_DPRINTF((D_MENU_ROOT, fcn, menu_root)); 777 778 /* 779 * We no longer use the GRUB slice file. If it exists, then 780 * the user is doing something that is unsupported (such as 781 * standard upgrading an old Live Upgrade BE). If that 782 * happens, mimic existing behavior i.e. pretend that it is 783 * not a BE. Emit a warning though. 784 */ 785 if (bam_alt_root) { 786 (void) snprintf(path, sizeof (path), "%s%s", bam_root, 787 GRUB_slice); 788 } else { 789 (void) snprintf(path, sizeof (path), "%s", GRUB_slice); 790 } 791 792 if (bam_verbose && stat(path, &sb) == 0) 793 bam_error(GRUB_SLICE_FILE_EXISTS, path); 794 795 if (is_zfs(menu_root)) { 796 assert(strcmp(menu_root, bam_root) == 0); 797 special = get_special(menu_root); 798 INJECT_ERROR1("Z_MENU_GET_SPECIAL", special = NULL); 799 if (special == NULL) { 800 bam_error(CANT_FIND_SPECIAL, menu_root); 801 return (BAM_ERROR); 802 } 803 pool = strtok(special, "/"); 804 INJECT_ERROR1("Z_MENU_GET_POOL", pool = NULL); 805 if (pool == NULL) { 806 free(special); 807 bam_error(CANT_FIND_POOL, menu_root); 808 return (BAM_ERROR); 809 } 810 BAM_DPRINTF((D_Z_MENU_GET_POOL_FROM_SPECIAL, fcn, pool)); 811 812 zmntpt = mount_top_dataset(pool, &zmnted); 813 INJECT_ERROR1("Z_MENU_MOUNT_TOP_DATASET", zmntpt = NULL); 814 if (zmntpt == NULL) { 815 bam_error(CANT_MOUNT_POOL_DATASET, pool); 816 free(special); 817 return (BAM_ERROR); 818 } 819 BAM_DPRINTF((D_Z_GET_MENU_MOUNT_TOP_DATASET, fcn, zmntpt)); 820 821 (void) strlcpy(menu_root, zmntpt, sizeof (menu_root)); 822 BAM_DPRINTF((D_Z_GET_MENU_MENU_ROOT, fcn, menu_root)); 823 } 824 825 elide_trailing_slash(menu_root, clean_menu_root, 826 sizeof (clean_menu_root)); 827 828 BAM_DPRINTF((D_CLEAN_MENU_ROOT, fcn, clean_menu_root)); 829 830 (void) strlcpy(menu_path, clean_menu_root, sizeof (menu_path)); 831 (void) strlcat(menu_path, GRUB_MENU, sizeof (menu_path)); 832 833 BAM_DPRINTF((D_MENU_PATH, fcn, menu_path)); 834 835 /* 836 * If listing the menu, display the menu location 837 */ 838 if (strcmp(subcmd, "list_entry") == 0) { 839 bam_print(GRUB_MENU_PATH, menu_path); 840 } 841 842 843 menu = menu_read(menu_path); 844 assert(menu); 845 846 /* 847 * We already checked the following case in 848 * check_subcmd_and_suboptions() above. Complete the 849 * final step now. 850 */ 851 if (strcmp(subcmd, "set_option") == 0) { 852 assert(largc == 1 && largv[0] && largv[1] == NULL); 853 opt = largv[0]; 854 } else { 855 assert(largc == 0 && largv == NULL); 856 } 857 858 ret = get_boot_cap(bam_root); 859 if (ret != BAM_SUCCESS) { 860 BAM_DPRINTF((D_BOOT_GET_CAP_FAILED, fcn)); 861 goto out; 862 } 863 864 /* 865 * Once the sub-cmd handler has run 866 * only the line field is guaranteed to have valid values 867 */ 868 if (strcmp(subcmd, "update_entry") == 0) 869 ret = f(menu, menu_root, osdev); 870 else if (strcmp(subcmd, "upgrade") == 0) 871 ret = f(menu, bam_root, menu_root); 872 else if (strcmp(subcmd, "list_entry") == 0) 873 ret = f(menu, menu_path, opt); 874 else 875 ret = f(menu, NULL, opt); 876 877 if (ret == BAM_WRITE) { 878 BAM_DPRINTF((D_WRITING_MENU_ROOT, fcn, clean_menu_root)); 879 ret = menu_write(clean_menu_root, menu); 880 } 881 882 out: 883 INJECT_ERROR1("POOL_SET", pool = "/pooldata"); 884 assert((is_zfs(menu_root)) ^ (pool == NULL)); 885 if (pool) { 886 (void) umount_top_dataset(pool, zmnted, zmntpt); 887 free(special); 888 } 889 menu_free(menu); 890 return (ret); 891 } 892 893 894 static error_t 895 bam_archive( 896 char *subcmd, 897 char *opt) 898 { 899 error_t ret; 900 error_t (*f)(char *root, char *opt); 901 const char *fcn = "bam_archive()"; 902 903 /* 904 * Add trailing / for archive subcommands 905 */ 906 if (rootbuf[strlen(rootbuf) - 1] != '/') 907 (void) strcat(rootbuf, "/"); 908 bam_rootlen = strlen(rootbuf); 909 910 /* 911 * Check arguments 912 */ 913 ret = check_subcmd_and_options(subcmd, opt, arch_subcmds, &f); 914 if (ret != BAM_SUCCESS) { 915 return (BAM_ERROR); 916 } 917 918 ret = get_boot_cap(rootbuf); 919 if (ret != BAM_SUCCESS) { 920 BAM_DPRINTF((D_BOOT_GET_CAP_FAILED, fcn)); 921 return (ret); 922 } 923 924 /* 925 * Check archive not supported with update_all 926 * since it is awkward to display out-of-sync 927 * information for each BE. 928 */ 929 if (bam_check && strcmp(subcmd, "update_all") == 0) { 930 bam_error(CHECK_NOT_SUPPORTED, subcmd); 931 return (BAM_ERROR); 932 } 933 934 if (strcmp(subcmd, "update_all") == 0) 935 bam_update_all = 1; 936 937 #if !defined(_OPB) 938 ucode_install(bam_root); 939 #endif 940 941 ret = f(bam_root, opt); 942 943 bam_update_all = 0; 944 945 return (ret); 946 } 947 948 /*PRINTFLIKE1*/ 949 void 950 bam_error(char *format, ...) 951 { 952 va_list ap; 953 954 va_start(ap, format); 955 (void) fprintf(stderr, "%s: ", prog); 956 (void) vfprintf(stderr, format, ap); 957 va_end(ap); 958 } 959 960 /*PRINTFLIKE1*/ 961 void 962 bam_derror(char *format, ...) 963 { 964 va_list ap; 965 966 assert(bam_debug); 967 968 va_start(ap, format); 969 (void) fprintf(stderr, "DEBUG: "); 970 (void) vfprintf(stderr, format, ap); 971 va_end(ap); 972 } 973 974 /*PRINTFLIKE1*/ 975 void 976 bam_print(char *format, ...) 977 { 978 va_list ap; 979 980 va_start(ap, format); 981 (void) vfprintf(stdout, format, ap); 982 va_end(ap); 983 } 984 985 /*PRINTFLIKE1*/ 986 void 987 bam_print_stderr(char *format, ...) 988 { 989 va_list ap; 990 991 va_start(ap, format); 992 (void) vfprintf(stderr, format, ap); 993 va_end(ap); 994 } 995 996 static void 997 bam_exit(int excode) 998 { 999 bam_unlock(); 1000 exit(excode); 1001 } 1002 1003 static void 1004 bam_lock(void) 1005 { 1006 struct flock lock; 1007 pid_t pid; 1008 1009 bam_lock_fd = open(BAM_LOCK_FILE, O_CREAT|O_RDWR, LOCK_FILE_PERMS); 1010 if (bam_lock_fd < 0) { 1011 /* 1012 * We may be invoked early in boot for archive verification. 1013 * In this case, root is readonly and /var/run may not exist. 1014 * Proceed without the lock 1015 */ 1016 if (errno == EROFS || errno == ENOENT) { 1017 bam_root_readonly = 1; 1018 return; 1019 } 1020 1021 bam_error(OPEN_FAIL, BAM_LOCK_FILE, strerror(errno)); 1022 bam_exit(1); 1023 } 1024 1025 lock.l_type = F_WRLCK; 1026 lock.l_whence = SEEK_SET; 1027 lock.l_start = 0; 1028 lock.l_len = 0; 1029 1030 if (fcntl(bam_lock_fd, F_SETLK, &lock) == -1) { 1031 if (errno != EACCES && errno != EAGAIN) { 1032 bam_error(LOCK_FAIL, BAM_LOCK_FILE, strerror(errno)); 1033 (void) close(bam_lock_fd); 1034 bam_lock_fd = -1; 1035 bam_exit(1); 1036 } 1037 pid = 0; 1038 (void) pread(bam_lock_fd, &pid, sizeof (pid_t), 0); 1039 bam_print(FILE_LOCKED, pid); 1040 1041 lock.l_type = F_WRLCK; 1042 lock.l_whence = SEEK_SET; 1043 lock.l_start = 0; 1044 lock.l_len = 0; 1045 if (fcntl(bam_lock_fd, F_SETLKW, &lock) == -1) { 1046 bam_error(LOCK_FAIL, BAM_LOCK_FILE, strerror(errno)); 1047 (void) close(bam_lock_fd); 1048 bam_lock_fd = -1; 1049 bam_exit(1); 1050 } 1051 } 1052 1053 /* We own the lock now */ 1054 pid = getpid(); 1055 (void) write(bam_lock_fd, &pid, sizeof (pid)); 1056 } 1057 1058 static void 1059 bam_unlock(void) 1060 { 1061 struct flock unlock; 1062 1063 /* 1064 * NOP if we don't hold the lock 1065 */ 1066 if (bam_lock_fd < 0) { 1067 return; 1068 } 1069 1070 unlock.l_type = F_UNLCK; 1071 unlock.l_whence = SEEK_SET; 1072 unlock.l_start = 0; 1073 unlock.l_len = 0; 1074 1075 if (fcntl(bam_lock_fd, F_SETLK, &unlock) == -1) { 1076 bam_error(UNLOCK_FAIL, BAM_LOCK_FILE, strerror(errno)); 1077 } 1078 1079 if (close(bam_lock_fd) == -1) { 1080 bam_error(CLOSE_FAIL, BAM_LOCK_FILE, strerror(errno)); 1081 } 1082 bam_lock_fd = -1; 1083 } 1084 1085 static error_t 1086 list_archive(char *root, char *opt) 1087 { 1088 filelist_t flist; 1089 filelist_t *flistp = &flist; 1090 line_t *lp; 1091 1092 assert(root); 1093 assert(opt == NULL); 1094 1095 flistp->head = flistp->tail = NULL; 1096 if (read_list(root, flistp) != BAM_SUCCESS) { 1097 return (BAM_ERROR); 1098 } 1099 assert(flistp->head && flistp->tail); 1100 1101 for (lp = flistp->head; lp; lp = lp->next) { 1102 bam_print(PRINT, lp->line); 1103 } 1104 1105 filelist_free(flistp); 1106 1107 return (BAM_SUCCESS); 1108 } 1109 1110 /* 1111 * This routine writes a list of lines to a file. 1112 * The list is *not* freed 1113 */ 1114 static error_t 1115 list2file(char *root, char *tmp, char *final, line_t *start) 1116 { 1117 char tmpfile[PATH_MAX]; 1118 char path[PATH_MAX]; 1119 FILE *fp; 1120 int ret; 1121 struct stat sb; 1122 mode_t mode; 1123 uid_t root_uid; 1124 gid_t sys_gid; 1125 struct passwd *pw; 1126 struct group *gp; 1127 const char *fcn = "list2file()"; 1128 1129 (void) snprintf(path, sizeof (path), "%s%s", root, final); 1130 1131 if (start == NULL) { 1132 /* Empty GRUB menu */ 1133 if (stat(path, &sb) != -1) { 1134 bam_print(UNLINK_EMPTY, path); 1135 if (unlink(path) != 0) { 1136 bam_error(UNLINK_FAIL, path, strerror(errno)); 1137 return (BAM_ERROR); 1138 } else { 1139 return (BAM_SUCCESS); 1140 } 1141 } 1142 return (BAM_SUCCESS); 1143 } 1144 1145 /* 1146 * Preserve attributes of existing file if possible, 1147 * otherwise ask the system for uid/gid of root/sys. 1148 * If all fails, fall back on hard-coded defaults. 1149 */ 1150 if (stat(path, &sb) != -1) { 1151 mode = sb.st_mode; 1152 root_uid = sb.st_uid; 1153 sys_gid = sb.st_gid; 1154 } else { 1155 mode = DEFAULT_DEV_MODE; 1156 if ((pw = getpwnam(DEFAULT_DEV_USER)) != NULL) { 1157 root_uid = pw->pw_uid; 1158 } else { 1159 bam_error(CANT_FIND_USER, 1160 DEFAULT_DEV_USER, DEFAULT_DEV_UID); 1161 root_uid = (uid_t)DEFAULT_DEV_UID; 1162 } 1163 if ((gp = getgrnam(DEFAULT_DEV_GROUP)) != NULL) { 1164 sys_gid = gp->gr_gid; 1165 } else { 1166 bam_error(CANT_FIND_GROUP, 1167 DEFAULT_DEV_GROUP, DEFAULT_DEV_GID); 1168 sys_gid = (gid_t)DEFAULT_DEV_GID; 1169 } 1170 } 1171 1172 (void) snprintf(tmpfile, sizeof (tmpfile), "%s%s", root, tmp); 1173 1174 /* Truncate tmpfile first */ 1175 fp = fopen(tmpfile, "w"); 1176 if (fp == NULL) { 1177 bam_error(OPEN_FAIL, tmpfile, strerror(errno)); 1178 return (BAM_ERROR); 1179 } 1180 ret = fclose(fp); 1181 INJECT_ERROR1("LIST2FILE_TRUNC_FCLOSE", ret = EOF); 1182 if (ret == EOF) { 1183 bam_error(CLOSE_FAIL, tmpfile, strerror(errno)); 1184 return (BAM_ERROR); 1185 } 1186 1187 /* Now open it in append mode */ 1188 fp = fopen(tmpfile, "a"); 1189 if (fp == NULL) { 1190 bam_error(OPEN_FAIL, tmpfile, strerror(errno)); 1191 return (BAM_ERROR); 1192 } 1193 1194 for (; start; start = start->next) { 1195 ret = s_fputs(start->line, fp); 1196 INJECT_ERROR1("LIST2FILE_FPUTS", ret = EOF); 1197 if (ret == EOF) { 1198 bam_error(WRITE_FAIL, tmpfile, strerror(errno)); 1199 (void) fclose(fp); 1200 return (BAM_ERROR); 1201 } 1202 } 1203 1204 ret = fclose(fp); 1205 INJECT_ERROR1("LIST2FILE_APPEND_FCLOSE", ret = EOF); 1206 if (ret == EOF) { 1207 bam_error(CLOSE_FAIL, tmpfile, strerror(errno)); 1208 return (BAM_ERROR); 1209 } 1210 1211 /* 1212 * Set up desired attributes. Ignore failures on filesystems 1213 * not supporting these operations - pcfs reports unsupported 1214 * operations as EINVAL. 1215 */ 1216 ret = chmod(tmpfile, mode); 1217 if (ret == -1 && 1218 errno != EINVAL && errno != ENOTSUP) { 1219 bam_error(CHMOD_FAIL, tmpfile, strerror(errno)); 1220 return (BAM_ERROR); 1221 } 1222 1223 ret = chown(tmpfile, root_uid, sys_gid); 1224 if (ret == -1 && 1225 errno != EINVAL && errno != ENOTSUP) { 1226 bam_error(CHOWN_FAIL, tmpfile, strerror(errno)); 1227 return (BAM_ERROR); 1228 } 1229 1230 1231 /* 1232 * Do an atomic rename 1233 */ 1234 ret = rename(tmpfile, path); 1235 INJECT_ERROR1("LIST2FILE_RENAME", ret = -1); 1236 if (ret != 0) { 1237 bam_error(RENAME_FAIL, path, strerror(errno)); 1238 return (BAM_ERROR); 1239 } 1240 1241 BAM_DPRINTF((D_WROTE_FILE, fcn, path)); 1242 return (BAM_SUCCESS); 1243 } 1244 1245 /* 1246 * This function should always return 0 - since we want 1247 * to create stat data for *all* files in the list. 1248 */ 1249 /*ARGSUSED*/ 1250 static int 1251 cmpstat( 1252 const char *file, 1253 const struct stat *stat, 1254 int flags, 1255 struct FTW *ftw) 1256 { 1257 uint_t sz; 1258 uint64_t *value; 1259 uint64_t filestat[2]; 1260 int error; 1261 1262 struct safefile *safefilep; 1263 FILE *fp; 1264 1265 /* 1266 * We only want regular files 1267 */ 1268 if (!S_ISREG(stat->st_mode)) 1269 return (0); 1270 1271 /* 1272 * new_nvlp may be NULL if there were errors earlier 1273 * but this is not fatal to update determination. 1274 */ 1275 if (walk_arg.new_nvlp) { 1276 filestat[0] = stat->st_size; 1277 filestat[1] = stat->st_mtime; 1278 error = nvlist_add_uint64_array(walk_arg.new_nvlp, 1279 file + bam_rootlen, filestat, 2); 1280 if (error) 1281 bam_error(NVADD_FAIL, file, strerror(error)); 1282 } 1283 1284 /* 1285 * The remaining steps are only required if we haven't made a 1286 * decision about update or if we are checking (-n) 1287 */ 1288 if (walk_arg.need_update && !bam_check) 1289 return (0); 1290 1291 /* 1292 * If we are invoked as part of system/filesystem/boot-archive, then 1293 * there are a number of things we should not worry about 1294 */ 1295 if (bam_smf_check) { 1296 /* ignore amd64 modules unless we are booted amd64. */ 1297 if (!is_amd64() && strstr(file, "/amd64/") != 0) 1298 return (0); 1299 1300 /* read in list of safe files */ 1301 if (safefiles == NULL) 1302 if (fp = fopen("/boot/solaris/filelist.safe", "r")) { 1303 safefiles = s_calloc(1, 1304 sizeof (struct safefile)); 1305 safefilep = safefiles; 1306 safefilep->name = s_calloc(1, MAXPATHLEN + 1307 MAXNAMELEN); 1308 safefilep->next = NULL; 1309 while (s_fgets(safefilep->name, MAXPATHLEN + 1310 MAXNAMELEN, fp) != NULL) { 1311 safefilep->next = s_calloc(1, 1312 sizeof (struct safefile)); 1313 safefilep = safefilep->next; 1314 safefilep->name = s_calloc(1, 1315 MAXPATHLEN + MAXNAMELEN); 1316 safefilep->next = NULL; 1317 } 1318 (void) fclose(fp); 1319 } 1320 } 1321 1322 /* 1323 * We need an update if file doesn't exist in old archive 1324 */ 1325 if (walk_arg.old_nvlp == NULL || 1326 nvlist_lookup_uint64_array(walk_arg.old_nvlp, 1327 file + bam_rootlen, &value, &sz) != 0) { 1328 if (bam_smf_check) /* ignore new during smf check */ 1329 return (0); 1330 walk_arg.need_update = 1; 1331 if (bam_verbose) 1332 bam_print(PARSEABLE_NEW_FILE, file); 1333 return (0); 1334 } 1335 1336 /* 1337 * File exists in old archive. Check if file has changed 1338 */ 1339 assert(sz == 2); 1340 bcopy(value, filestat, sizeof (filestat)); 1341 1342 if (filestat[0] != stat->st_size || 1343 filestat[1] != stat->st_mtime) { 1344 if (bam_smf_check) { 1345 safefilep = safefiles; 1346 while (safefilep != NULL) { 1347 if (strcmp(file + bam_rootlen, 1348 safefilep->name) == 0) { 1349 (void) creat(NEED_UPDATE_FILE, 0644); 1350 return (0); 1351 } 1352 safefilep = safefilep->next; 1353 } 1354 } 1355 walk_arg.need_update = 1; 1356 if (bam_verbose) 1357 if (bam_smf_check) 1358 bam_print(" %s\n", file); 1359 else 1360 bam_print(PARSEABLE_OUT_DATE, file); 1361 } 1362 1363 return (0); 1364 } 1365 1366 /* 1367 * Check flags and presence of required files. 1368 * The force flag and/or absence of files should 1369 * trigger an update. 1370 * Suppress stdout output if check (-n) option is set 1371 * (as -n should only produce parseable output.) 1372 */ 1373 static void 1374 check_flags_and_files(char *root) 1375 { 1376 char path[PATH_MAX]; 1377 struct stat sb; 1378 1379 /* 1380 * if force, create archive unconditionally 1381 */ 1382 if (bam_force) { 1383 walk_arg.need_update = 1; 1384 if (bam_verbose && !bam_check) 1385 bam_print(UPDATE_FORCE); 1386 return; 1387 } 1388 1389 /* 1390 * If archive is missing, create archive 1391 */ 1392 if (is_sparc()) { 1393 (void) snprintf(path, sizeof (path), "%s%s%s%s", root, 1394 ARCHIVE_PREFIX, get_machine(), ARCHIVE_SUFFIX); 1395 } else { 1396 if (bam_direct == BAM_DIRECT_DBOOT) { 1397 (void) snprintf(path, sizeof (path), "%s%s", root, 1398 DIRECT_BOOT_ARCHIVE_64); 1399 if (stat(path, &sb) != 0) { 1400 if (bam_verbose && !bam_check) 1401 bam_print(UPDATE_ARCH_MISS, path); 1402 walk_arg.need_update = 1; 1403 return; 1404 } 1405 } 1406 (void) snprintf(path, sizeof (path), "%s%s", root, 1407 DIRECT_BOOT_ARCHIVE_32); 1408 } 1409 1410 if (stat(path, &sb) != 0) { 1411 if (bam_verbose && !bam_check) 1412 bam_print(UPDATE_ARCH_MISS, path); 1413 walk_arg.need_update = 1; 1414 return; 1415 } 1416 } 1417 1418 static error_t 1419 read_one_list(char *root, filelist_t *flistp, char *filelist) 1420 { 1421 char path[PATH_MAX]; 1422 FILE *fp; 1423 char buf[BAM_MAXLINE]; 1424 const char *fcn = "read_one_list()"; 1425 1426 (void) snprintf(path, sizeof (path), "%s%s", root, filelist); 1427 1428 fp = fopen(path, "r"); 1429 if (fp == NULL) { 1430 BAM_DPRINTF((D_FLIST_FAIL, fcn, path, strerror(errno))); 1431 return (BAM_ERROR); 1432 } 1433 while (s_fgets(buf, sizeof (buf), fp) != NULL) { 1434 /* skip blank lines */ 1435 if (strspn(buf, " \t") == strlen(buf)) 1436 continue; 1437 append_to_flist(flistp, buf); 1438 } 1439 if (fclose(fp) != 0) { 1440 bam_error(CLOSE_FAIL, path, strerror(errno)); 1441 return (BAM_ERROR); 1442 } 1443 return (BAM_SUCCESS); 1444 } 1445 1446 static error_t 1447 read_list(char *root, filelist_t *flistp) 1448 { 1449 char path[PATH_MAX]; 1450 char cmd[PATH_MAX]; 1451 struct stat sb; 1452 int n, rval; 1453 const char *fcn = "read_list()"; 1454 1455 flistp->head = flistp->tail = NULL; 1456 1457 /* 1458 * build and check path to extract_boot_filelist.ksh 1459 */ 1460 n = snprintf(path, sizeof (path), "%s%s", root, EXTRACT_BOOT_FILELIST); 1461 if (n >= sizeof (path)) { 1462 bam_error(NO_FLIST); 1463 return (BAM_ERROR); 1464 } 1465 1466 /* 1467 * If extract_boot_filelist is present, exec it, otherwise read 1468 * the filelists directly, for compatibility with older images. 1469 */ 1470 if (stat(path, &sb) == 0) { 1471 /* 1472 * build arguments to exec extract_boot_filelist.ksh 1473 */ 1474 char *rootarg, *platarg; 1475 int platarglen = 1, rootarglen = 1; 1476 if (strlen(root) > 1) 1477 rootarglen += strlen(root) + strlen("-R "); 1478 if (bam_alt_platform) 1479 platarglen += strlen(bam_platform) + strlen("-p "); 1480 platarg = s_calloc(1, platarglen); 1481 rootarg = s_calloc(1, rootarglen); 1482 *platarg = 0; 1483 *rootarg = 0; 1484 1485 if (strlen(root) > 1) { 1486 (void) snprintf(rootarg, rootarglen, 1487 "-R %s", root); 1488 } 1489 if (bam_alt_platform) { 1490 (void) snprintf(platarg, platarglen, 1491 "-p %s", bam_platform); 1492 } 1493 n = snprintf(cmd, sizeof (cmd), "%s %s %s /%s /%s", 1494 path, rootarg, platarg, BOOT_FILE_LIST, ETC_FILE_LIST); 1495 free(platarg); 1496 free(rootarg); 1497 if (n >= sizeof (cmd)) { 1498 bam_error(NO_FLIST); 1499 return (BAM_ERROR); 1500 } 1501 if (exec_cmd(cmd, flistp) != 0) { 1502 BAM_DPRINTF((D_FLIST_FAIL, fcn, path, strerror(errno))); 1503 return (BAM_ERROR); 1504 } 1505 } else { 1506 /* 1507 * Read current lists of files - only the first is mandatory 1508 */ 1509 rval = read_one_list(root, flistp, BOOT_FILE_LIST); 1510 if (rval != BAM_SUCCESS) 1511 return (rval); 1512 (void) read_one_list(root, flistp, ETC_FILE_LIST); 1513 } 1514 1515 if (flistp->head == NULL) { 1516 bam_error(NO_FLIST); 1517 return (BAM_ERROR); 1518 } 1519 1520 return (BAM_SUCCESS); 1521 } 1522 1523 static void 1524 getoldstat(char *root) 1525 { 1526 char path[PATH_MAX]; 1527 int fd, error; 1528 struct stat sb; 1529 char *ostat; 1530 1531 (void) snprintf(path, sizeof (path), "%s%s", root, FILE_STAT); 1532 fd = open(path, O_RDONLY); 1533 if (fd == -1) { 1534 if (bam_verbose) 1535 bam_print(OPEN_FAIL, path, strerror(errno)); 1536 walk_arg.need_update = 1; 1537 return; 1538 } 1539 1540 if (fstat(fd, &sb) != 0) { 1541 bam_error(STAT_FAIL, path, strerror(errno)); 1542 (void) close(fd); 1543 walk_arg.need_update = 1; 1544 return; 1545 } 1546 1547 ostat = s_calloc(1, sb.st_size); 1548 1549 if (read(fd, ostat, sb.st_size) != sb.st_size) { 1550 bam_error(READ_FAIL, path, strerror(errno)); 1551 (void) close(fd); 1552 free(ostat); 1553 walk_arg.need_update = 1; 1554 return; 1555 } 1556 1557 (void) close(fd); 1558 1559 walk_arg.old_nvlp = NULL; 1560 error = nvlist_unpack(ostat, sb.st_size, &walk_arg.old_nvlp, 0); 1561 1562 free(ostat); 1563 1564 if (error) { 1565 bam_error(UNPACK_FAIL, path, strerror(error)); 1566 walk_arg.old_nvlp = NULL; 1567 walk_arg.need_update = 1; 1568 return; 1569 } 1570 } 1571 1572 /* 1573 * Checks if a file in the current (old) archive has 1574 * been deleted from the root filesystem. This is needed for 1575 * software like Trusted Extensions (TX) that switch early 1576 * in boot based on presence/absence of a kernel module. 1577 */ 1578 static void 1579 check4stale(char *root) 1580 { 1581 nvpair_t *nvp; 1582 nvlist_t *nvlp; 1583 char *file; 1584 char path[PATH_MAX]; 1585 struct stat sb; 1586 1587 /* 1588 * Skip stale file check during smf check 1589 */ 1590 if (bam_smf_check) 1591 return; 1592 1593 /* Nothing to do if no old stats */ 1594 if ((nvlp = walk_arg.old_nvlp) == NULL) 1595 return; 1596 1597 for (nvp = nvlist_next_nvpair(nvlp, NULL); nvp; 1598 nvp = nvlist_next_nvpair(nvlp, nvp)) { 1599 file = nvpair_name(nvp); 1600 if (file == NULL) 1601 continue; 1602 (void) snprintf(path, sizeof (path), "%s/%s", 1603 root, file); 1604 if (stat(path, &sb) == -1) { 1605 walk_arg.need_update = 1; 1606 if (bam_verbose) 1607 bam_print(PARSEABLE_STALE_FILE, path); 1608 } 1609 } 1610 } 1611 1612 static void 1613 create_newstat(void) 1614 { 1615 int error; 1616 1617 error = nvlist_alloc(&walk_arg.new_nvlp, NV_UNIQUE_NAME, 0); 1618 if (error) { 1619 /* 1620 * Not fatal - we can still create archive 1621 */ 1622 walk_arg.new_nvlp = NULL; 1623 bam_error(NVALLOC_FAIL, strerror(error)); 1624 } 1625 } 1626 1627 static void 1628 walk_list(char *root, filelist_t *flistp) 1629 { 1630 char path[PATH_MAX]; 1631 line_t *lp; 1632 1633 for (lp = flistp->head; lp; lp = lp->next) { 1634 /* 1635 * Don't follow symlinks. A symlink must refer to 1636 * a file that would appear in the archive through 1637 * a direct reference. This matches the archive 1638 * construction behavior. 1639 */ 1640 (void) snprintf(path, sizeof (path), "%s%s", root, lp->line); 1641 if (nftw(path, cmpstat, 20, FTW_PHYS) == -1) { 1642 /* 1643 * Some files may not exist. 1644 * For example: etc/rtc_config on a x86 diskless system 1645 * Emit verbose message only 1646 */ 1647 if (bam_verbose) 1648 bam_print(NFTW_FAIL, path, strerror(errno)); 1649 } 1650 } 1651 } 1652 1653 static void 1654 savenew(char *root) 1655 { 1656 char path[PATH_MAX]; 1657 char path2[PATH_MAX]; 1658 size_t sz; 1659 char *nstat; 1660 int fd, wrote, error; 1661 1662 nstat = NULL; 1663 sz = 0; 1664 error = nvlist_pack(walk_arg.new_nvlp, &nstat, &sz, 1665 NV_ENCODE_XDR, 0); 1666 if (error) { 1667 bam_error(PACK_FAIL, strerror(error)); 1668 return; 1669 } 1670 1671 (void) snprintf(path, sizeof (path), "%s%s", root, FILE_STAT_TMP); 1672 fd = open(path, O_RDWR|O_CREAT|O_TRUNC, FILE_STAT_MODE); 1673 if (fd == -1) { 1674 bam_error(OPEN_FAIL, path, strerror(errno)); 1675 free(nstat); 1676 return; 1677 } 1678 wrote = write(fd, nstat, sz); 1679 if (wrote != sz) { 1680 bam_error(WRITE_FAIL, path, strerror(errno)); 1681 (void) close(fd); 1682 free(nstat); 1683 return; 1684 } 1685 (void) close(fd); 1686 free(nstat); 1687 1688 (void) snprintf(path2, sizeof (path2), "%s%s", root, FILE_STAT); 1689 if (rename(path, path2) != 0) { 1690 bam_error(RENAME_FAIL, path2, strerror(errno)); 1691 } 1692 } 1693 1694 static void 1695 clear_walk_args(void) 1696 { 1697 if (walk_arg.old_nvlp) 1698 nvlist_free(walk_arg.old_nvlp); 1699 if (walk_arg.new_nvlp) 1700 nvlist_free(walk_arg.new_nvlp); 1701 walk_arg.need_update = 0; 1702 walk_arg.old_nvlp = NULL; 1703 walk_arg.new_nvlp = NULL; 1704 } 1705 1706 /* 1707 * Returns: 1708 * 0 - no update necessary 1709 * 1 - update required. 1710 * BAM_ERROR (-1) - An error occurred 1711 * 1712 * Special handling for check (-n): 1713 * ================================ 1714 * The check (-n) option produces parseable output. 1715 * To do this, we suppress all stdout messages unrelated 1716 * to out of sync files. 1717 * All stderr messages are still printed though. 1718 * 1719 */ 1720 static int 1721 update_required(char *root) 1722 { 1723 struct stat sb; 1724 char path[PATH_MAX]; 1725 filelist_t flist; 1726 filelist_t *flistp = &flist; 1727 int need_update; 1728 1729 flistp->head = flistp->tail = NULL; 1730 1731 walk_arg.need_update = 0; 1732 1733 /* 1734 * Without consulting stat data, check if we need update 1735 */ 1736 check_flags_and_files(root); 1737 1738 /* 1739 * In certain deployment scenarios, filestat may not 1740 * exist. Ignore it during boot-archive SMF check. 1741 */ 1742 if (bam_smf_check) { 1743 (void) snprintf(path, sizeof (path), "%s%s", root, FILE_STAT); 1744 if (stat(path, &sb) != 0) 1745 return (0); 1746 } 1747 1748 /* 1749 * consult stat data only if we haven't made a decision 1750 * about update. If checking (-n) however, we always 1751 * need stat data (since we want to compare old and new) 1752 */ 1753 if (!walk_arg.need_update || bam_check) 1754 getoldstat(root); 1755 1756 /* 1757 * Check if the archive contains files that are no longer 1758 * present on the root filesystem. 1759 */ 1760 if (!walk_arg.need_update || bam_check) 1761 check4stale(root); 1762 1763 /* 1764 * read list of files 1765 */ 1766 if (read_list(root, flistp) != BAM_SUCCESS) { 1767 clear_walk_args(); 1768 return (BAM_ERROR); 1769 } 1770 1771 assert(flistp->head && flistp->tail); 1772 1773 /* 1774 * At this point either the update is required 1775 * or the decision is pending. In either case 1776 * we need to create new stat nvlist 1777 */ 1778 create_newstat(); 1779 1780 /* 1781 * This walk does 2 things: 1782 * - gets new stat data for every file 1783 * - (optional) compare old and new stat data 1784 */ 1785 walk_list(root, &flist); 1786 1787 /* done with the file list */ 1788 filelist_free(flistp); 1789 1790 /* 1791 * if we didn't succeed in creating new stat data above 1792 * just return result of update check so that archive is built. 1793 */ 1794 if (walk_arg.new_nvlp == NULL) { 1795 bam_error(NO_NEW_STAT); 1796 need_update = walk_arg.need_update; 1797 clear_walk_args(); 1798 return (need_update ? 1 : 0); 1799 } 1800 1801 1802 /* 1803 * If no update required, discard newstat 1804 */ 1805 if (!walk_arg.need_update) { 1806 clear_walk_args(); 1807 return (0); 1808 } 1809 1810 return (1); 1811 } 1812 1813 static error_t 1814 create_ramdisk(char *root) 1815 { 1816 char *cmdline, path[PATH_MAX]; 1817 size_t len; 1818 struct stat sb; 1819 1820 /* 1821 * Setup command args for create_ramdisk.ksh 1822 */ 1823 (void) snprintf(path, sizeof (path), "%s/%s", root, CREATE_RAMDISK); 1824 if (stat(path, &sb) != 0) { 1825 bam_error(ARCH_EXEC_MISS, path, strerror(errno)); 1826 return (BAM_ERROR); 1827 } 1828 1829 len = strlen(path) + strlen(root) + 10; /* room for space + -R */ 1830 if (bam_alt_platform) 1831 len += strlen(bam_platform) + strlen("-p "); 1832 cmdline = s_calloc(1, len); 1833 1834 if (bam_alt_platform) { 1835 assert(strlen(root) > 1); 1836 (void) snprintf(cmdline, len, "%s -p %s -R %s", 1837 path, bam_platform, root); 1838 /* chop off / at the end */ 1839 cmdline[strlen(cmdline) - 1] = '\0'; 1840 } else if (strlen(root) > 1) { 1841 (void) snprintf(cmdline, len, "%s -R %s", path, root); 1842 /* chop off / at the end */ 1843 cmdline[strlen(cmdline) - 1] = '\0'; 1844 } else 1845 (void) snprintf(cmdline, len, "%s", path); 1846 1847 if (exec_cmd(cmdline, NULL) != 0) { 1848 bam_error(ARCHIVE_FAIL, cmdline); 1849 free(cmdline); 1850 return (BAM_ERROR); 1851 } 1852 free(cmdline); 1853 1854 /* 1855 * The existence of the expected archives used to be 1856 * verified here. This check is done in create_ramdisk as 1857 * it needs to be in sync with the altroot operated upon. 1858 */ 1859 1860 return (BAM_SUCCESS); 1861 } 1862 1863 /* 1864 * Checks if target filesystem is on a ramdisk 1865 * 1 - is miniroot 1866 * 0 - is not 1867 * When in doubt assume it is not a ramdisk. 1868 */ 1869 static int 1870 is_ramdisk(char *root) 1871 { 1872 struct extmnttab mnt; 1873 FILE *fp; 1874 int found; 1875 char mntpt[PATH_MAX]; 1876 char *cp; 1877 1878 /* 1879 * There are 3 situations where creating archive is 1880 * of dubious value: 1881 * - create boot_archive on a lofi-mounted boot_archive 1882 * - create it on a ramdisk which is the root filesystem 1883 * - create it on a ramdisk mounted somewhere else 1884 * The first is not easy to detect and checking for it is not 1885 * worth it. 1886 * The other two conditions are handled here 1887 */ 1888 1889 fp = fopen(MNTTAB, "r"); 1890 if (fp == NULL) { 1891 bam_error(OPEN_FAIL, MNTTAB, strerror(errno)); 1892 return (0); 1893 } 1894 1895 resetmnttab(fp); 1896 1897 /* 1898 * Remove any trailing / from the mount point 1899 */ 1900 (void) strlcpy(mntpt, root, sizeof (mntpt)); 1901 if (strcmp(root, "/") != 0) { 1902 cp = mntpt + strlen(mntpt) - 1; 1903 if (*cp == '/') 1904 *cp = '\0'; 1905 } 1906 found = 0; 1907 while (getextmntent(fp, &mnt, sizeof (mnt)) == 0) { 1908 if (strcmp(mnt.mnt_mountp, mntpt) == 0) { 1909 found = 1; 1910 break; 1911 } 1912 } 1913 1914 if (!found) { 1915 if (bam_verbose) 1916 bam_error(NOT_IN_MNTTAB, mntpt); 1917 (void) fclose(fp); 1918 return (0); 1919 } 1920 1921 if (strstr(mnt.mnt_special, RAMDISK_SPECIAL) != NULL) { 1922 if (bam_verbose) 1923 bam_error(IS_RAMDISK, bam_root); 1924 (void) fclose(fp); 1925 return (1); 1926 } 1927 1928 (void) fclose(fp); 1929 1930 return (0); 1931 } 1932 1933 static int 1934 is_boot_archive(char *root) 1935 { 1936 char path[PATH_MAX]; 1937 struct stat sb; 1938 int error; 1939 const char *fcn = "is_boot_archive()"; 1940 1941 /* 1942 * We can't create an archive without the create_ramdisk script 1943 */ 1944 (void) snprintf(path, sizeof (path), "%s/%s", root, CREATE_RAMDISK); 1945 error = stat(path, &sb); 1946 INJECT_ERROR1("NOT_ARCHIVE_BASED", error = -1); 1947 if (error == -1) { 1948 if (bam_verbose) 1949 bam_print(FILE_MISS, path); 1950 BAM_DPRINTF((D_NOT_ARCHIVE_BOOT, fcn, root)); 1951 return (0); 1952 } 1953 1954 BAM_DPRINTF((D_IS_ARCHIVE_BOOT, fcn, root)); 1955 return (1); 1956 } 1957 1958 /* 1959 * Need to call this for anything that operates on the GRUB menu 1960 * In the x86 live upgrade case the directory /boot/grub may be present 1961 * even on pre-newboot BEs. The authoritative way to check for a GRUB target 1962 * is to check for the presence of the stage2 binary which is present 1963 * only on GRUB targets (even on x86 boot partitions). Checking for the 1964 * presence of the multiboot binary is not correct as it is not present 1965 * on x86 boot partitions. 1966 */ 1967 int 1968 is_grub(const char *root) 1969 { 1970 char path[PATH_MAX]; 1971 struct stat sb; 1972 const char *fcn = "is_grub()"; 1973 1974 (void) snprintf(path, sizeof (path), "%s%s", root, GRUB_STAGE2); 1975 if (stat(path, &sb) == -1) { 1976 BAM_DPRINTF((D_NO_GRUB_DIR, fcn, path)); 1977 return (0); 1978 } 1979 1980 return (1); 1981 } 1982 1983 static int 1984 is_zfs(char *root) 1985 { 1986 struct statvfs vfs; 1987 int ret; 1988 const char *fcn = "is_zfs()"; 1989 1990 ret = statvfs(root, &vfs); 1991 INJECT_ERROR1("STATVFS_ZFS", ret = 1); 1992 if (ret != 0) { 1993 bam_error(STATVFS_FAIL, root, strerror(errno)); 1994 return (0); 1995 } 1996 1997 if (strncmp(vfs.f_basetype, "zfs", strlen("zfs")) == 0) { 1998 BAM_DPRINTF((D_IS_ZFS, fcn, root)); 1999 return (1); 2000 } else { 2001 BAM_DPRINTF((D_IS_NOT_ZFS, fcn, root)); 2002 return (0); 2003 } 2004 } 2005 2006 static int 2007 is_ufs(char *root) 2008 { 2009 struct statvfs vfs; 2010 int ret; 2011 const char *fcn = "is_ufs()"; 2012 2013 ret = statvfs(root, &vfs); 2014 INJECT_ERROR1("STATVFS_UFS", ret = 1); 2015 if (ret != 0) { 2016 bam_error(STATVFS_FAIL, root, strerror(errno)); 2017 return (0); 2018 } 2019 2020 if (strncmp(vfs.f_basetype, "ufs", strlen("ufs")) == 0) { 2021 BAM_DPRINTF((D_IS_UFS, fcn, root)); 2022 return (1); 2023 } else { 2024 BAM_DPRINTF((D_IS_NOT_UFS, fcn, root)); 2025 return (0); 2026 } 2027 } 2028 2029 static int 2030 is_pcfs(char *root) 2031 { 2032 struct statvfs vfs; 2033 int ret; 2034 const char *fcn = "is_pcfs()"; 2035 2036 ret = statvfs(root, &vfs); 2037 INJECT_ERROR1("STATVFS_PCFS", ret = 1); 2038 if (ret != 0) { 2039 bam_error(STATVFS_FAIL, root, strerror(errno)); 2040 return (0); 2041 } 2042 2043 if (strncmp(vfs.f_basetype, "pcfs", strlen("pcfs")) == 0) { 2044 BAM_DPRINTF((D_IS_PCFS, fcn, root)); 2045 return (1); 2046 } else { 2047 BAM_DPRINTF((D_IS_NOT_PCFS, fcn, root)); 2048 return (0); 2049 } 2050 } 2051 2052 static int 2053 is_readonly(char *root) 2054 { 2055 int fd; 2056 int error; 2057 char testfile[PATH_MAX]; 2058 const char *fcn = "is_readonly()"; 2059 2060 /* 2061 * Using statvfs() to check for a read-only filesystem is not 2062 * reliable. The only way to reliably test is to attempt to 2063 * create a file 2064 */ 2065 (void) snprintf(testfile, sizeof (testfile), "%s/%s.%d", 2066 root, BOOTADM_RDONLY_TEST, getpid()); 2067 2068 (void) unlink(testfile); 2069 2070 errno = 0; 2071 fd = open(testfile, O_RDWR|O_CREAT|O_EXCL, 0644); 2072 error = errno; 2073 INJECT_ERROR2("RDONLY_TEST_ERROR", fd = -1, error = EACCES); 2074 if (fd == -1 && error == EROFS) { 2075 BAM_DPRINTF((D_RDONLY_FS, fcn, root)); 2076 return (1); 2077 } else if (fd == -1) { 2078 bam_error(RDONLY_TEST_ERROR, root, strerror(error)); 2079 } 2080 2081 (void) close(fd); 2082 (void) unlink(testfile); 2083 2084 BAM_DPRINTF((D_RDWR_FS, fcn, root)); 2085 return (0); 2086 } 2087 2088 static error_t 2089 update_archive(char *root, char *opt) 2090 { 2091 error_t ret; 2092 2093 assert(root); 2094 assert(opt == NULL); 2095 2096 /* 2097 * root must belong to a boot archive based OS, 2098 */ 2099 if (!is_boot_archive(root)) { 2100 /* 2101 * Emit message only if not in context of update_all. 2102 * If in update_all, emit only if verbose flag is set. 2103 */ 2104 if (!bam_update_all || bam_verbose) 2105 bam_print(NOT_ARCHIVE_BOOT, root); 2106 return (BAM_SUCCESS); 2107 } 2108 2109 /* 2110 * If smf check is requested when / is writable (can happen 2111 * on first reboot following an upgrade because service 2112 * dependency is messed up), skip the check. 2113 */ 2114 if (bam_smf_check && !bam_root_readonly) 2115 return (BAM_SUCCESS); 2116 2117 /* 2118 * root must be writable. This check applies to alternate 2119 * root (-R option); bam_root_readonly applies to '/' only. 2120 */ 2121 if (!bam_smf_check && !bam_check && is_readonly(root)) { 2122 if (bam_verbose) 2123 bam_print(RDONLY_FS, root); 2124 return (BAM_SUCCESS); 2125 } 2126 2127 /* 2128 * Don't generate archive on ramdisk 2129 */ 2130 if (is_ramdisk(root)) { 2131 if (bam_verbose) 2132 bam_print(SKIP_RAMDISK); 2133 return (BAM_SUCCESS); 2134 } 2135 2136 /* 2137 * Now check if updated is really needed 2138 */ 2139 ret = update_required(root); 2140 2141 /* 2142 * The check command (-n) is *not* a dry run 2143 * It only checks if the archive is in sync. 2144 */ 2145 if (bam_check) { 2146 bam_exit((ret != 0) ? 1 : 0); 2147 } 2148 2149 if (ret == 1) { 2150 /* create the ramdisk */ 2151 ret = create_ramdisk(root); 2152 } 2153 2154 /* if the archive is updated, save the new stat data */ 2155 if (ret == 0 && walk_arg.new_nvlp != NULL) { 2156 savenew(root); 2157 } 2158 2159 clear_walk_args(); 2160 2161 return (ret); 2162 } 2163 2164 static error_t 2165 synchronize_BE_menu(void) 2166 { 2167 struct stat sb; 2168 char cmdline[PATH_MAX]; 2169 char cksum_line[PATH_MAX]; 2170 filelist_t flist = {0}; 2171 char *old_cksum_str; 2172 char *old_size_str; 2173 char *old_file; 2174 char *curr_cksum_str; 2175 char *curr_size_str; 2176 char *curr_file; 2177 FILE *cfp; 2178 int found; 2179 int ret; 2180 const char *fcn = "synchronize_BE_menu()"; 2181 2182 BAM_DPRINTF((D_FUNC_ENTRY0, fcn)); 2183 2184 /* Check if findroot enabled LU BE */ 2185 if (stat(FINDROOT_INSTALLGRUB, &sb) != 0) { 2186 BAM_DPRINTF((D_NOT_LU_BE, fcn)); 2187 return (BAM_SUCCESS); 2188 } 2189 2190 if (stat(LU_MENU_CKSUM, &sb) != 0) { 2191 BAM_DPRINTF((D_NO_CKSUM_FILE, fcn, LU_MENU_CKSUM)); 2192 goto menu_sync; 2193 } 2194 2195 cfp = fopen(LU_MENU_CKSUM, "r"); 2196 INJECT_ERROR1("CKSUM_FILE_MISSING", cfp = NULL); 2197 if (cfp == NULL) { 2198 bam_error(CANNOT_READ_LU_CKSUM, LU_MENU_CKSUM); 2199 goto menu_sync; 2200 } 2201 BAM_DPRINTF((D_CKSUM_FILE_OPENED, fcn, LU_MENU_CKSUM)); 2202 2203 found = 0; 2204 while (s_fgets(cksum_line, sizeof (cksum_line), cfp) != NULL) { 2205 INJECT_ERROR1("MULTIPLE_CKSUM", found = 1); 2206 if (found) { 2207 bam_error(MULTIPLE_LU_CKSUM, LU_MENU_CKSUM); 2208 (void) fclose(cfp); 2209 goto menu_sync; 2210 } 2211 found = 1; 2212 } 2213 BAM_DPRINTF((D_CKSUM_FILE_READ, fcn, LU_MENU_CKSUM)); 2214 2215 2216 old_cksum_str = strtok(cksum_line, " \t"); 2217 old_size_str = strtok(NULL, " \t"); 2218 old_file = strtok(NULL, " \t"); 2219 2220 INJECT_ERROR1("OLD_CKSUM_NULL", old_cksum_str = NULL); 2221 INJECT_ERROR1("OLD_SIZE_NULL", old_size_str = NULL); 2222 INJECT_ERROR1("OLD_FILE_NULL", old_file = NULL); 2223 if (old_cksum_str == NULL || old_size_str == NULL || old_file == NULL) { 2224 bam_error(CANNOT_PARSE_LU_CKSUM, LU_MENU_CKSUM); 2225 goto menu_sync; 2226 } 2227 BAM_DPRINTF((D_CKSUM_FILE_PARSED, fcn, LU_MENU_CKSUM)); 2228 2229 /* Get checksum of current menu */ 2230 (void) snprintf(cmdline, sizeof (cmdline), "%s %s", 2231 CKSUM, GRUB_MENU); 2232 ret = exec_cmd(cmdline, &flist); 2233 INJECT_ERROR1("GET_CURR_CKSUM", ret = 1); 2234 if (ret != 0) { 2235 bam_error(MENU_CKSUM_FAIL); 2236 return (BAM_ERROR); 2237 } 2238 BAM_DPRINTF((D_CKSUM_GEN_SUCCESS, fcn)); 2239 2240 INJECT_ERROR1("GET_CURR_CKSUM_OUTPUT", flist.head = NULL); 2241 if ((flist.head == NULL) || (flist.head != flist.tail)) { 2242 bam_error(BAD_CKSUM); 2243 filelist_free(&flist); 2244 return (BAM_ERROR); 2245 } 2246 BAM_DPRINTF((D_CKSUM_GEN_OUTPUT_VALID, fcn)); 2247 2248 curr_cksum_str = strtok(flist.head->line, " \t"); 2249 curr_size_str = strtok(NULL, " \t"); 2250 curr_file = strtok(NULL, " \t"); 2251 2252 INJECT_ERROR1("CURR_CKSUM_NULL", curr_cksum_str = NULL); 2253 INJECT_ERROR1("CURR_SIZE_NULL", curr_size_str = NULL); 2254 INJECT_ERROR1("CURR_FILE_NULL", curr_file = NULL); 2255 if (curr_cksum_str == NULL || curr_size_str == NULL || 2256 curr_file == NULL) { 2257 bam_error(BAD_CKSUM_PARSE); 2258 filelist_free(&flist); 2259 return (BAM_ERROR); 2260 } 2261 BAM_DPRINTF((D_CKSUM_GEN_PARSED, fcn)); 2262 2263 if (strcmp(old_cksum_str, curr_cksum_str) == 0 && 2264 strcmp(old_size_str, curr_size_str) == 0 && 2265 strcmp(old_file, curr_file) == 0) { 2266 filelist_free(&flist); 2267 BAM_DPRINTF((D_CKSUM_NO_CHANGE, fcn)); 2268 return (BAM_SUCCESS); 2269 } 2270 2271 filelist_free(&flist); 2272 2273 /* cksum doesn't match - the menu has changed */ 2274 BAM_DPRINTF((D_CKSUM_HAS_CHANGED, fcn)); 2275 2276 menu_sync: 2277 bam_print(PROP_GRUB_MENU); 2278 2279 (void) snprintf(cmdline, sizeof (cmdline), 2280 "/bin/sh -c '. %s > /dev/null; %s %s yes > /dev/null'", 2281 LULIB, LULIB_PROPAGATE_FILE, GRUB_MENU); 2282 ret = exec_cmd(cmdline, NULL); 2283 INJECT_ERROR1("PROPAGATE_MENU", ret = 1); 2284 if (ret != 0) { 2285 bam_error(MENU_PROP_FAIL); 2286 return (BAM_ERROR); 2287 } 2288 BAM_DPRINTF((D_PROPAGATED_MENU, fcn)); 2289 2290 (void) snprintf(cmdline, sizeof (cmdline), "/bin/cp %s %s > /dev/null", 2291 GRUB_MENU, GRUB_BACKUP_MENU); 2292 ret = exec_cmd(cmdline, NULL); 2293 INJECT_ERROR1("CREATE_BACKUP", ret = 1); 2294 if (ret != 0) { 2295 bam_error(MENU_BACKUP_FAIL, GRUB_BACKUP_MENU); 2296 return (BAM_ERROR); 2297 } 2298 BAM_DPRINTF((D_CREATED_BACKUP, fcn, GRUB_BACKUP_MENU)); 2299 2300 (void) snprintf(cmdline, sizeof (cmdline), 2301 "/bin/sh -c '. %s > /dev/null; %s %s no > /dev/null'", 2302 LULIB, LULIB_PROPAGATE_FILE, GRUB_BACKUP_MENU); 2303 ret = exec_cmd(cmdline, NULL); 2304 INJECT_ERROR1("PROPAGATE_BACKUP", ret = 1); 2305 if (ret != 0) { 2306 bam_error(BACKUP_PROP_FAIL, GRUB_BACKUP_MENU); 2307 return (BAM_ERROR); 2308 } 2309 BAM_DPRINTF((D_PROPAGATED_BACKUP, fcn, GRUB_BACKUP_MENU)); 2310 2311 (void) snprintf(cmdline, sizeof (cmdline), "%s %s > %s", 2312 CKSUM, GRUB_MENU, LU_MENU_CKSUM); 2313 ret = exec_cmd(cmdline, NULL); 2314 INJECT_ERROR1("CREATE_CKSUM_FILE", ret = 1); 2315 if (ret != 0) { 2316 bam_error(MENU_CKSUM_WRITE_FAIL, LU_MENU_CKSUM); 2317 return (BAM_ERROR); 2318 } 2319 BAM_DPRINTF((D_CREATED_CKSUM_FILE, fcn, LU_MENU_CKSUM)); 2320 2321 (void) snprintf(cmdline, sizeof (cmdline), 2322 "/bin/sh -c '. %s > /dev/null; %s %s no > /dev/null'", 2323 LULIB, LULIB_PROPAGATE_FILE, LU_MENU_CKSUM); 2324 ret = exec_cmd(cmdline, NULL); 2325 INJECT_ERROR1("PROPAGATE_MENU_CKSUM_FILE", ret = 1); 2326 if (ret != 0) { 2327 bam_error(MENU_CKSUM_PROP_FAIL, LU_MENU_CKSUM); 2328 return (BAM_ERROR); 2329 } 2330 BAM_DPRINTF((D_PROPAGATED_CKSUM_FILE, fcn, LU_MENU_CKSUM)); 2331 2332 (void) snprintf(cmdline, sizeof (cmdline), 2333 "/bin/sh -c '. %s > /dev/null; %s %s no > /dev/null'", 2334 LULIB, LULIB_PROPAGATE_FILE, BOOTADM); 2335 ret = exec_cmd(cmdline, NULL); 2336 INJECT_ERROR1("PROPAGATE_BOOTADM_FILE", ret = 1); 2337 if (ret != 0) { 2338 bam_error(BOOTADM_PROP_FAIL, BOOTADM); 2339 return (BAM_ERROR); 2340 } 2341 BAM_DPRINTF((D_PROPAGATED_BOOTADM, fcn, BOOTADM)); 2342 2343 return (BAM_SUCCESS); 2344 } 2345 2346 static error_t 2347 update_all(char *root, char *opt) 2348 { 2349 struct extmnttab mnt; 2350 struct stat sb; 2351 FILE *fp; 2352 char multibt[PATH_MAX]; 2353 char creatram[PATH_MAX]; 2354 error_t ret = BAM_SUCCESS; 2355 2356 assert(root); 2357 assert(opt == NULL); 2358 2359 if (bam_rootlen != 1 || *root != '/') { 2360 elide_trailing_slash(root, multibt, sizeof (multibt)); 2361 bam_error(ALT_ROOT_INVALID, multibt); 2362 return (BAM_ERROR); 2363 } 2364 2365 /* 2366 * Check to see if we are in the midst of safemode patching 2367 * If so skip building the archive for /. Instead build it 2368 * against the latest bits obtained by creating a fresh lofs 2369 * mount of root. 2370 */ 2371 if (stat(LOFS_PATCH_FILE, &sb) == 0) { 2372 if (mkdir(LOFS_PATCH_MNT, 0755) == -1 && 2373 errno != EEXIST) { 2374 bam_error(MKDIR_FAILED, "%s", LOFS_PATCH_MNT, 2375 strerror(errno)); 2376 ret = BAM_ERROR; 2377 goto out; 2378 } 2379 (void) snprintf(multibt, sizeof (multibt), 2380 "/sbin/mount -F lofs -o nosub / %s", LOFS_PATCH_MNT); 2381 if (exec_cmd(multibt, NULL) != 0) { 2382 bam_error(MOUNT_FAILED, LOFS_PATCH_MNT, "lofs"); 2383 ret = BAM_ERROR; 2384 } 2385 if (ret != BAM_ERROR) { 2386 (void) snprintf(rootbuf, sizeof (rootbuf), "%s/", 2387 LOFS_PATCH_MNT); 2388 bam_rootlen = strlen(rootbuf); 2389 if (update_archive(rootbuf, opt) != BAM_SUCCESS) 2390 ret = BAM_ERROR; 2391 /* 2392 * unmount the lofs mount since there could be 2393 * multiple invocations of bootadm -a update_all 2394 */ 2395 (void) snprintf(multibt, sizeof (multibt), 2396 "/sbin/umount %s", LOFS_PATCH_MNT); 2397 if (exec_cmd(multibt, NULL) != 0) { 2398 bam_error(UMOUNT_FAILED, LOFS_PATCH_MNT); 2399 ret = BAM_ERROR; 2400 } 2401 } 2402 } else { 2403 /* 2404 * First update archive for current root 2405 */ 2406 if (update_archive(root, opt) != BAM_SUCCESS) 2407 ret = BAM_ERROR; 2408 } 2409 2410 if (ret == BAM_ERROR) 2411 goto out; 2412 2413 /* 2414 * Now walk the mount table, performing archive update 2415 * for all mounted Newboot root filesystems 2416 */ 2417 fp = fopen(MNTTAB, "r"); 2418 if (fp == NULL) { 2419 bam_error(OPEN_FAIL, MNTTAB, strerror(errno)); 2420 ret = BAM_ERROR; 2421 goto out; 2422 } 2423 2424 resetmnttab(fp); 2425 2426 while (getextmntent(fp, &mnt, sizeof (mnt)) == 0) { 2427 if (mnt.mnt_special == NULL) 2428 continue; 2429 if ((strcmp(mnt.mnt_fstype, MNTTYPE_ZFS) != 0) && 2430 (strncmp(mnt.mnt_special, "/dev/", strlen("/dev/")) != 0)) 2431 continue; 2432 if (strcmp(mnt.mnt_mountp, "/") == 0) 2433 continue; 2434 2435 (void) snprintf(creatram, sizeof (creatram), "%s/%s", 2436 mnt.mnt_mountp, CREATE_RAMDISK); 2437 2438 if (stat(creatram, &sb) == -1) 2439 continue; 2440 2441 /* 2442 * We put a trailing slash to be consistent with root = "/" 2443 * case, such that we don't have to print // in some cases. 2444 */ 2445 (void) snprintf(rootbuf, sizeof (rootbuf), "%s/", 2446 mnt.mnt_mountp); 2447 bam_rootlen = strlen(rootbuf); 2448 2449 /* 2450 * It's possible that other mounts may be an alternate boot 2451 * architecture, so check it again. 2452 */ 2453 if ((get_boot_cap(rootbuf) != BAM_SUCCESS) || 2454 (update_archive(rootbuf, opt) != BAM_SUCCESS)) 2455 ret = BAM_ERROR; 2456 } 2457 2458 (void) fclose(fp); 2459 2460 out: 2461 /* 2462 * We no longer use biosdev for Live Upgrade. Hence 2463 * there is no need to defer (to shutdown time) any fdisk 2464 * updates 2465 */ 2466 if (stat(GRUB_fdisk, &sb) == 0 || stat(GRUB_fdisk_target, &sb) == 0) { 2467 bam_error(FDISK_FILES_FOUND, GRUB_fdisk, GRUB_fdisk_target); 2468 } 2469 2470 /* 2471 * If user has updated menu in current BE, propagate the 2472 * updates to all BEs. 2473 */ 2474 if (sync_menu && synchronize_BE_menu() != BAM_SUCCESS) 2475 ret = BAM_ERROR; 2476 2477 return (ret); 2478 } 2479 2480 static void 2481 append_line(menu_t *mp, line_t *lp) 2482 { 2483 if (mp->start == NULL) { 2484 mp->start = lp; 2485 } else { 2486 mp->end->next = lp; 2487 lp->prev = mp->end; 2488 } 2489 mp->end = lp; 2490 } 2491 2492 void 2493 unlink_line(menu_t *mp, line_t *lp) 2494 { 2495 /* unlink from list */ 2496 if (lp->prev) 2497 lp->prev->next = lp->next; 2498 else 2499 mp->start = lp->next; 2500 if (lp->next) 2501 lp->next->prev = lp->prev; 2502 else 2503 mp->end = lp->prev; 2504 } 2505 2506 static entry_t * 2507 boot_entry_new(menu_t *mp, line_t *start, line_t *end) 2508 { 2509 entry_t *ent, *prev; 2510 const char *fcn = "boot_entry_new()"; 2511 2512 assert(mp); 2513 assert(start); 2514 assert(end); 2515 2516 ent = s_calloc(1, sizeof (entry_t)); 2517 BAM_DPRINTF((D_ENTRY_NEW, fcn)); 2518 ent->start = start; 2519 ent->end = end; 2520 2521 if (mp->entries == NULL) { 2522 mp->entries = ent; 2523 BAM_DPRINTF((D_ENTRY_NEW_FIRST, fcn)); 2524 return (ent); 2525 } 2526 2527 prev = mp->entries; 2528 while (prev->next) 2529 prev = prev->next; 2530 prev->next = ent; 2531 ent->prev = prev; 2532 BAM_DPRINTF((D_ENTRY_NEW_LINKED, fcn)); 2533 return (ent); 2534 } 2535 2536 static void 2537 boot_entry_addline(entry_t *ent, line_t *lp) 2538 { 2539 if (ent) 2540 ent->end = lp; 2541 } 2542 2543 /* 2544 * Check whether cmd matches the one indexed by which, and whether arg matches 2545 * str. which must be either KERNEL_CMD or MODULE_CMD, and a match to the 2546 * respective *_DOLLAR_CMD is also acceptable. The arg is searched using 2547 * strstr(), so it can be a partial match. 2548 */ 2549 static int 2550 check_cmd(const char *cmd, const int which, const char *arg, const char *str) 2551 { 2552 int ret; 2553 const char *fcn = "check_cmd()"; 2554 2555 BAM_DPRINTF((D_FUNC_ENTRY2, fcn, arg, str)); 2556 2557 if ((strcmp(cmd, menu_cmds[which]) != 0) && 2558 (strcmp(cmd, menu_cmds[which + 1]) != 0)) { 2559 BAM_DPRINTF((D_CHECK_CMD_CMD_NOMATCH, 2560 fcn, cmd, menu_cmds[which])); 2561 return (0); 2562 } 2563 ret = (strstr(arg, str) != NULL); 2564 2565 if (ret) { 2566 BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 2567 } else { 2568 BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 2569 } 2570 2571 return (ret); 2572 } 2573 2574 static error_t 2575 kernel_parser(entry_t *entry, char *cmd, char *arg, int linenum) 2576 { 2577 const char *fcn = "kernel_parser()"; 2578 2579 assert(entry); 2580 assert(cmd); 2581 assert(arg); 2582 2583 if (strcmp(cmd, menu_cmds[KERNEL_CMD]) != 0 && 2584 strcmp(cmd, menu_cmds[KERNEL_DOLLAR_CMD]) != 0) { 2585 BAM_DPRINTF((D_NOT_KERNEL_CMD, fcn, cmd)); 2586 return (BAM_ERROR); 2587 } 2588 2589 if (strncmp(arg, DIRECT_BOOT_32, sizeof (DIRECT_BOOT_32) - 1) == 0) { 2590 BAM_DPRINTF((D_SET_DBOOT_32, fcn, arg)); 2591 entry->flags |= BAM_ENTRY_DBOOT | BAM_ENTRY_32BIT; 2592 } else if (strncmp(arg, DIRECT_BOOT_KERNEL, 2593 sizeof (DIRECT_BOOT_KERNEL) - 1) == 0) { 2594 BAM_DPRINTF((D_SET_DBOOT, fcn, arg)); 2595 entry->flags |= BAM_ENTRY_DBOOT; 2596 } else if (strncmp(arg, DIRECT_BOOT_64, 2597 sizeof (DIRECT_BOOT_64) - 1) == 0) { 2598 BAM_DPRINTF((D_SET_DBOOT_64, fcn, arg)); 2599 entry->flags |= BAM_ENTRY_DBOOT | BAM_ENTRY_64BIT; 2600 } else if (strncmp(arg, DIRECT_BOOT_FAILSAFE_KERNEL, 2601 sizeof (DIRECT_BOOT_FAILSAFE_KERNEL) - 1) == 0) { 2602 BAM_DPRINTF((D_SET_DBOOT_FAILSAFE, fcn, arg)); 2603 entry->flags |= BAM_ENTRY_DBOOT | BAM_ENTRY_FAILSAFE; 2604 } else if (strncmp(arg, DIRECT_BOOT_FAILSAFE_32, 2605 sizeof (DIRECT_BOOT_FAILSAFE_32) - 1) == 0) { 2606 BAM_DPRINTF((D_SET_DBOOT_FAILSAFE_32, fcn, arg)); 2607 entry->flags |= BAM_ENTRY_DBOOT | BAM_ENTRY_FAILSAFE 2608 | BAM_ENTRY_32BIT; 2609 } else if (strncmp(arg, DIRECT_BOOT_FAILSAFE_64, 2610 sizeof (DIRECT_BOOT_FAILSAFE_64) - 1) == 0) { 2611 BAM_DPRINTF((D_SET_DBOOT_FAILSAFE_64, fcn, arg)); 2612 entry->flags |= BAM_ENTRY_DBOOT | BAM_ENTRY_FAILSAFE 2613 | BAM_ENTRY_64BIT; 2614 } else if (strncmp(arg, MULTI_BOOT, sizeof (MULTI_BOOT) - 1) == 0) { 2615 BAM_DPRINTF((D_SET_MULTIBOOT, fcn, arg)); 2616 entry->flags |= BAM_ENTRY_MULTIBOOT; 2617 } else if (strncmp(arg, MULTI_BOOT_FAILSAFE, 2618 sizeof (MULTI_BOOT_FAILSAFE) - 1) == 0) { 2619 BAM_DPRINTF((D_SET_MULTIBOOT_FAILSAFE, fcn, arg)); 2620 entry->flags |= BAM_ENTRY_MULTIBOOT | BAM_ENTRY_FAILSAFE; 2621 } else if (strstr(arg, XEN_KERNEL_SUBSTR)) { 2622 BAM_DPRINTF((D_SET_HV, fcn, arg)); 2623 entry->flags |= BAM_ENTRY_HV; 2624 } else if (!(entry->flags & (BAM_ENTRY_BOOTADM|BAM_ENTRY_LU))) { 2625 BAM_DPRINTF((D_SET_HAND_KERNEL, fcn, arg)); 2626 return (BAM_ERROR); 2627 } else if (strncmp(arg, KERNEL_PREFIX, strlen(KERNEL_PREFIX)) == 0 && 2628 strstr(arg, UNIX_SPACE)) { 2629 entry->flags |= BAM_ENTRY_DBOOT | BAM_ENTRY_32BIT; 2630 } else if (strncmp(arg, KERNEL_PREFIX, strlen(KERNEL_PREFIX)) == 0 && 2631 strstr(arg, AMD_UNIX_SPACE)) { 2632 entry->flags |= BAM_ENTRY_DBOOT | BAM_ENTRY_64BIT; 2633 } else { 2634 BAM_DPRINTF((D_IS_UNKNOWN_KERNEL, fcn, arg)); 2635 bam_error(UNKNOWN_KERNEL_LINE, linenum); 2636 return (BAM_ERROR); 2637 } 2638 2639 return (BAM_SUCCESS); 2640 } 2641 2642 static error_t 2643 module_parser(entry_t *entry, char *cmd, char *arg, int linenum) 2644 { 2645 const char *fcn = "module_parser()"; 2646 2647 assert(entry); 2648 assert(cmd); 2649 assert(arg); 2650 2651 if (strcmp(cmd, menu_cmds[MODULE_CMD]) != 0 && 2652 strcmp(cmd, menu_cmds[MODULE_DOLLAR_CMD]) != 0) { 2653 BAM_DPRINTF((D_NOT_MODULE_CMD, fcn, cmd)); 2654 return (BAM_ERROR); 2655 } 2656 2657 if (strcmp(arg, DIRECT_BOOT_ARCHIVE) == 0 || 2658 strcmp(arg, DIRECT_BOOT_ARCHIVE_32) == 0 || 2659 strcmp(arg, DIRECT_BOOT_ARCHIVE_64) == 0 || 2660 strcmp(arg, MULTIBOOT_ARCHIVE) == 0 || 2661 strcmp(arg, FAILSAFE_ARCHIVE) == 0 || 2662 strcmp(arg, FAILSAFE_ARCHIVE_32) == 0 || 2663 strcmp(arg, FAILSAFE_ARCHIVE_64) == 0 || 2664 strcmp(arg, XEN_KERNEL_MODULE_LINE) == 0 || 2665 strcmp(arg, XEN_KERNEL_MODULE_LINE_ZFS) == 0) { 2666 BAM_DPRINTF((D_BOOTADM_LU_MODULE, fcn, arg)); 2667 return (BAM_SUCCESS); 2668 } else if (!(entry->flags & BAM_ENTRY_BOOTADM) && 2669 !(entry->flags & BAM_ENTRY_LU)) { 2670 /* don't emit warning for hand entries */ 2671 BAM_DPRINTF((D_IS_HAND_MODULE, fcn, arg)); 2672 return (BAM_ERROR); 2673 } else { 2674 BAM_DPRINTF((D_IS_UNKNOWN_MODULE, fcn, arg)); 2675 bam_error(UNKNOWN_MODULE_LINE, linenum); 2676 return (BAM_ERROR); 2677 } 2678 } 2679 2680 /* 2681 * A line in menu.lst looks like 2682 * [ ]*<cmd>[ \t=]*<arg>* 2683 */ 2684 static void 2685 line_parser(menu_t *mp, char *str, int *lineNum, int *entryNum) 2686 { 2687 /* 2688 * save state across calls. This is so that 2689 * header gets the right entry# after title has 2690 * been processed 2691 */ 2692 static line_t *prev = NULL; 2693 static entry_t *curr_ent = NULL; 2694 static int in_liveupgrade = 0; 2695 2696 line_t *lp; 2697 char *cmd, *sep, *arg; 2698 char save, *cp, *line; 2699 menu_flag_t flag = BAM_INVALID; 2700 const char *fcn = "line_parser()"; 2701 2702 if (str == NULL) { 2703 return; 2704 } 2705 2706 /* 2707 * First save a copy of the entire line. 2708 * We use this later to set the line field. 2709 */ 2710 line = s_strdup(str); 2711 2712 /* Eat up leading whitespace */ 2713 while (*str == ' ' || *str == '\t') 2714 str++; 2715 2716 if (*str == '#') { /* comment */ 2717 cmd = s_strdup("#"); 2718 sep = NULL; 2719 arg = s_strdup(str + 1); 2720 flag = BAM_COMMENT; 2721 if (strstr(arg, BAM_LU_HDR) != NULL) { 2722 in_liveupgrade = 1; 2723 } else if (strstr(arg, BAM_LU_FTR) != NULL) { 2724 in_liveupgrade = 0; 2725 } 2726 } else if (*str == '\0') { /* blank line */ 2727 cmd = sep = arg = NULL; 2728 flag = BAM_EMPTY; 2729 } else { 2730 /* 2731 * '=' is not a documented separator in grub syntax. 2732 * However various development bits use '=' as a 2733 * separator. In addition, external users also 2734 * use = as a separator. So we will allow that usage. 2735 */ 2736 cp = str; 2737 while (*str != ' ' && *str != '\t' && *str != '=') { 2738 if (*str == '\0') { 2739 cmd = s_strdup(cp); 2740 sep = arg = NULL; 2741 break; 2742 } 2743 str++; 2744 } 2745 2746 if (*str != '\0') { 2747 save = *str; 2748 *str = '\0'; 2749 cmd = s_strdup(cp); 2750 *str = save; 2751 2752 str++; 2753 save = *str; 2754 *str = '\0'; 2755 sep = s_strdup(str - 1); 2756 *str = save; 2757 2758 while (*str == ' ' || *str == '\t') 2759 str++; 2760 if (*str == '\0') 2761 arg = NULL; 2762 else 2763 arg = s_strdup(str); 2764 } 2765 } 2766 2767 lp = s_calloc(1, sizeof (line_t)); 2768 2769 lp->cmd = cmd; 2770 lp->sep = sep; 2771 lp->arg = arg; 2772 lp->line = line; 2773 lp->lineNum = ++(*lineNum); 2774 if (cmd && strcmp(cmd, menu_cmds[TITLE_CMD]) == 0) { 2775 lp->entryNum = ++(*entryNum); 2776 lp->flags = BAM_TITLE; 2777 if (prev && prev->flags == BAM_COMMENT && 2778 prev->arg && strcmp(prev->arg, BAM_BOOTADM_HDR) == 0) { 2779 prev->entryNum = lp->entryNum; 2780 curr_ent = boot_entry_new(mp, prev, lp); 2781 curr_ent->flags |= BAM_ENTRY_BOOTADM; 2782 BAM_DPRINTF((D_IS_BOOTADM_ENTRY, fcn, arg)); 2783 } else { 2784 curr_ent = boot_entry_new(mp, lp, lp); 2785 if (in_liveupgrade) { 2786 curr_ent->flags |= BAM_ENTRY_LU; 2787 BAM_DPRINTF((D_IS_LU_ENTRY, fcn, arg)); 2788 } 2789 } 2790 curr_ent->entryNum = *entryNum; 2791 } else if (flag != BAM_INVALID) { 2792 /* 2793 * For header comments, the entry# is "fixed up" 2794 * by the subsequent title 2795 */ 2796 lp->entryNum = *entryNum; 2797 lp->flags = flag; 2798 } else { 2799 lp->entryNum = *entryNum; 2800 2801 if (*entryNum == ENTRY_INIT) { 2802 lp->flags = BAM_GLOBAL; 2803 } else { 2804 lp->flags = BAM_ENTRY; 2805 2806 if (cmd && arg) { 2807 if (strcmp(cmd, menu_cmds[ROOT_CMD]) == 0) { 2808 BAM_DPRINTF((D_IS_ROOT_CMD, fcn, arg)); 2809 curr_ent->flags |= BAM_ENTRY_ROOT; 2810 } else if (strcmp(cmd, menu_cmds[FINDROOT_CMD]) 2811 == 0) { 2812 BAM_DPRINTF((D_IS_FINDROOT_CMD, fcn, 2813 arg)); 2814 curr_ent->flags |= BAM_ENTRY_FINDROOT; 2815 } else if (strcmp(cmd, 2816 menu_cmds[CHAINLOADER_CMD]) == 0) { 2817 BAM_DPRINTF((D_IS_CHAINLOADER_CMD, fcn, 2818 arg)); 2819 curr_ent->flags |= 2820 BAM_ENTRY_CHAINLOADER; 2821 } else if (kernel_parser(curr_ent, cmd, arg, 2822 lp->lineNum) != BAM_SUCCESS) { 2823 (void) module_parser(curr_ent, cmd, 2824 arg, lp->lineNum); 2825 } 2826 } 2827 } 2828 } 2829 2830 /* record default, old default, and entry line ranges */ 2831 if (lp->flags == BAM_GLOBAL && 2832 strcmp(lp->cmd, menu_cmds[DEFAULT_CMD]) == 0) { 2833 mp->curdefault = lp; 2834 } else if (lp->flags == BAM_COMMENT && 2835 strncmp(lp->arg, BAM_OLDDEF, strlen(BAM_OLDDEF)) == 0) { 2836 mp->olddefault = lp; 2837 } else if (lp->flags == BAM_COMMENT && 2838 strncmp(lp->arg, BAM_OLD_RC_DEF, strlen(BAM_OLD_RC_DEF)) == 0) { 2839 mp->old_rc_default = lp; 2840 } else if (lp->flags == BAM_ENTRY || 2841 (lp->flags == BAM_COMMENT && 2842 strcmp(lp->arg, BAM_BOOTADM_FTR) == 0)) { 2843 boot_entry_addline(curr_ent, lp); 2844 } 2845 append_line(mp, lp); 2846 2847 prev = lp; 2848 } 2849 2850 void 2851 update_numbering(menu_t *mp) 2852 { 2853 int lineNum; 2854 int entryNum; 2855 int old_default_value; 2856 line_t *lp, *prev, *default_lp, *default_entry; 2857 char buf[PATH_MAX]; 2858 2859 if (mp->start == NULL) { 2860 return; 2861 } 2862 2863 lineNum = LINE_INIT; 2864 entryNum = ENTRY_INIT; 2865 old_default_value = ENTRY_INIT; 2866 lp = default_lp = default_entry = NULL; 2867 2868 prev = NULL; 2869 for (lp = mp->start; lp; prev = lp, lp = lp->next) { 2870 lp->lineNum = ++lineNum; 2871 2872 /* 2873 * Get the value of the default command 2874 */ 2875 if (lp->entryNum == ENTRY_INIT && lp->cmd && 2876 strcmp(lp->cmd, menu_cmds[DEFAULT_CMD]) == 0 && 2877 lp->arg) { 2878 old_default_value = atoi(lp->arg); 2879 default_lp = lp; 2880 } 2881 2882 /* 2883 * If not a booting entry, nothing else to fix for this 2884 * entry 2885 */ 2886 if (lp->entryNum == ENTRY_INIT) 2887 continue; 2888 2889 /* 2890 * Record the position of the default entry. 2891 * The following works because global 2892 * commands like default and timeout should precede 2893 * actual boot entries, so old_default_value 2894 * is already known (or default cmd is missing). 2895 */ 2896 if (default_entry == NULL && 2897 old_default_value != ENTRY_INIT && 2898 lp->entryNum == old_default_value) { 2899 default_entry = lp; 2900 } 2901 2902 /* 2903 * Now fixup the entry number 2904 */ 2905 if (lp->cmd && strcmp(lp->cmd, menu_cmds[TITLE_CMD]) == 0) { 2906 lp->entryNum = ++entryNum; 2907 /* fixup the bootadm header */ 2908 if (prev && prev->flags == BAM_COMMENT && 2909 prev->arg && 2910 strcmp(prev->arg, BAM_BOOTADM_HDR) == 0) { 2911 prev->entryNum = lp->entryNum; 2912 } 2913 } else { 2914 lp->entryNum = entryNum; 2915 } 2916 } 2917 2918 /* 2919 * No default command in menu, simply return 2920 */ 2921 if (default_lp == NULL) { 2922 return; 2923 } 2924 2925 free(default_lp->arg); 2926 free(default_lp->line); 2927 2928 if (default_entry == NULL) { 2929 default_lp->arg = s_strdup("0"); 2930 } else { 2931 (void) snprintf(buf, sizeof (buf), "%d", 2932 default_entry->entryNum); 2933 default_lp->arg = s_strdup(buf); 2934 } 2935 2936 /* 2937 * The following is required since only the line field gets 2938 * written back to menu.lst 2939 */ 2940 (void) snprintf(buf, sizeof (buf), "%s%s%s", 2941 menu_cmds[DEFAULT_CMD], menu_cmds[SEP_CMD], default_lp->arg); 2942 default_lp->line = s_strdup(buf); 2943 } 2944 2945 2946 static menu_t * 2947 menu_read(char *menu_path) 2948 { 2949 FILE *fp; 2950 char buf[BAM_MAXLINE], *cp; 2951 menu_t *mp; 2952 int line, entry, len, n; 2953 2954 mp = s_calloc(1, sizeof (menu_t)); 2955 2956 fp = fopen(menu_path, "r"); 2957 if (fp == NULL) { /* Let the caller handle this error */ 2958 return (mp); 2959 } 2960 2961 2962 /* Note: GRUB boot entry number starts with 0 */ 2963 line = LINE_INIT; 2964 entry = ENTRY_INIT; 2965 cp = buf; 2966 len = sizeof (buf); 2967 while (s_fgets(cp, len, fp) != NULL) { 2968 n = strlen(cp); 2969 if (cp[n - 1] == '\\') { 2970 len -= n - 1; 2971 assert(len >= 2); 2972 cp += n - 1; 2973 continue; 2974 } 2975 line_parser(mp, buf, &line, &entry); 2976 cp = buf; 2977 len = sizeof (buf); 2978 } 2979 2980 if (fclose(fp) == EOF) { 2981 bam_error(CLOSE_FAIL, menu_path, strerror(errno)); 2982 } 2983 2984 return (mp); 2985 } 2986 2987 static error_t 2988 selector(menu_t *mp, char *opt, int *entry, char **title) 2989 { 2990 char *eq; 2991 char *opt_dup; 2992 int entryNum; 2993 2994 assert(mp); 2995 assert(mp->start); 2996 assert(opt); 2997 2998 opt_dup = s_strdup(opt); 2999 3000 if (entry) 3001 *entry = ENTRY_INIT; 3002 if (title) 3003 *title = NULL; 3004 3005 eq = strchr(opt_dup, '='); 3006 if (eq == NULL) { 3007 bam_error(INVALID_OPT, opt); 3008 free(opt_dup); 3009 return (BAM_ERROR); 3010 } 3011 3012 *eq = '\0'; 3013 if (entry && strcmp(opt_dup, OPT_ENTRY_NUM) == 0) { 3014 assert(mp->end); 3015 entryNum = s_strtol(eq + 1); 3016 if (entryNum < 0 || entryNum > mp->end->entryNum) { 3017 bam_error(INVALID_ENTRY, eq + 1); 3018 free(opt_dup); 3019 return (BAM_ERROR); 3020 } 3021 *entry = entryNum; 3022 } else if (title && strcmp(opt_dup, menu_cmds[TITLE_CMD]) == 0) { 3023 *title = opt + (eq - opt_dup) + 1; 3024 } else { 3025 bam_error(INVALID_OPT, opt); 3026 free(opt_dup); 3027 return (BAM_ERROR); 3028 } 3029 3030 free(opt_dup); 3031 return (BAM_SUCCESS); 3032 } 3033 3034 /* 3035 * If invoked with no titles/entries (opt == NULL) 3036 * only title lines in file are printed. 3037 * 3038 * If invoked with a title or entry #, all 3039 * lines in *every* matching entry are listed 3040 */ 3041 static error_t 3042 list_entry(menu_t *mp, char *menu_path, char *opt) 3043 { 3044 line_t *lp; 3045 int entry = ENTRY_INIT; 3046 int found; 3047 char *title = NULL; 3048 3049 assert(mp); 3050 assert(menu_path); 3051 3052 /* opt is optional */ 3053 BAM_DPRINTF((D_FUNC_ENTRY2, "list_entry", menu_path, 3054 opt ? opt : "<NULL>")); 3055 3056 if (mp->start == NULL) { 3057 bam_error(NO_MENU, menu_path); 3058 return (BAM_ERROR); 3059 } 3060 3061 if (opt != NULL) { 3062 if (selector(mp, opt, &entry, &title) != BAM_SUCCESS) { 3063 return (BAM_ERROR); 3064 } 3065 assert((entry != ENTRY_INIT) ^ (title != NULL)); 3066 } else { 3067 (void) read_globals(mp, menu_path, menu_cmds[DEFAULT_CMD], 0); 3068 (void) read_globals(mp, menu_path, menu_cmds[TIMEOUT_CMD], 0); 3069 } 3070 3071 found = 0; 3072 for (lp = mp->start; lp; lp = lp->next) { 3073 if (lp->flags == BAM_COMMENT || lp->flags == BAM_EMPTY) 3074 continue; 3075 if (opt == NULL && lp->flags == BAM_TITLE) { 3076 bam_print(PRINT_TITLE, lp->entryNum, 3077 lp->arg); 3078 found = 1; 3079 continue; 3080 } 3081 if (entry != ENTRY_INIT && lp->entryNum == entry) { 3082 bam_print(PRINT, lp->line); 3083 found = 1; 3084 continue; 3085 } 3086 3087 /* 3088 * We set the entry value here so that all lines 3089 * in entry get printed. If we subsequently match 3090 * title in other entries, all lines in those 3091 * entries get printed as well. 3092 */ 3093 if (title && lp->flags == BAM_TITLE && lp->arg && 3094 strncmp(title, lp->arg, strlen(title)) == 0) { 3095 bam_print(PRINT, lp->line); 3096 entry = lp->entryNum; 3097 found = 1; 3098 continue; 3099 } 3100 } 3101 3102 if (!found) { 3103 bam_error(NO_MATCH_ENTRY); 3104 return (BAM_ERROR); 3105 } 3106 3107 return (BAM_SUCCESS); 3108 } 3109 3110 int 3111 add_boot_entry(menu_t *mp, 3112 char *title, 3113 char *findroot, 3114 char *kernel, 3115 char *mod_kernel, 3116 char *module) 3117 { 3118 int lineNum; 3119 int entryNum; 3120 char linebuf[BAM_MAXLINE]; 3121 menu_cmd_t k_cmd; 3122 menu_cmd_t m_cmd; 3123 const char *fcn = "add_boot_entry()"; 3124 3125 assert(mp); 3126 3127 INJECT_ERROR1("ADD_BOOT_ENTRY_FINDROOT_NULL", findroot = NULL); 3128 if (findroot == NULL) { 3129 bam_error(NULL_FINDROOT); 3130 return (BAM_ERROR); 3131 } 3132 3133 if (title == NULL) { 3134 title = "Solaris"; /* default to Solaris */ 3135 } 3136 if (kernel == NULL) { 3137 bam_error(SUBOPT_MISS, menu_cmds[KERNEL_CMD]); 3138 return (BAM_ERROR); 3139 } 3140 if (module == NULL) { 3141 if (bam_direct != BAM_DIRECT_DBOOT) { 3142 bam_error(SUBOPT_MISS, menu_cmds[MODULE_CMD]); 3143 return (BAM_ERROR); 3144 } 3145 3146 /* Figure the commands out from the kernel line */ 3147 if (strstr(kernel, "$ISADIR") != NULL) { 3148 module = DIRECT_BOOT_ARCHIVE; 3149 k_cmd = KERNEL_DOLLAR_CMD; 3150 m_cmd = MODULE_DOLLAR_CMD; 3151 } else if (strstr(kernel, "amd64") != NULL) { 3152 module = DIRECT_BOOT_ARCHIVE_64; 3153 k_cmd = KERNEL_CMD; 3154 m_cmd = MODULE_CMD; 3155 } else { 3156 module = DIRECT_BOOT_ARCHIVE_32; 3157 k_cmd = KERNEL_CMD; 3158 m_cmd = MODULE_CMD; 3159 } 3160 } else if ((bam_direct == BAM_DIRECT_DBOOT) && 3161 (strstr(kernel, "$ISADIR") != NULL)) { 3162 /* 3163 * If it's a non-failsafe dboot kernel, use the "kernel$" 3164 * command. Otherwise, use "kernel". 3165 */ 3166 k_cmd = KERNEL_DOLLAR_CMD; 3167 m_cmd = MODULE_DOLLAR_CMD; 3168 } else { 3169 k_cmd = KERNEL_CMD; 3170 m_cmd = MODULE_CMD; 3171 } 3172 3173 if (mp->start) { 3174 lineNum = mp->end->lineNum; 3175 entryNum = mp->end->entryNum; 3176 } else { 3177 lineNum = LINE_INIT; 3178 entryNum = ENTRY_INIT; 3179 } 3180 3181 /* 3182 * No separator for comment (HDR/FTR) commands 3183 * The syntax for comments is #<comment> 3184 */ 3185 (void) snprintf(linebuf, sizeof (linebuf), "%s%s", 3186 menu_cmds[COMMENT_CMD], BAM_BOOTADM_HDR); 3187 line_parser(mp, linebuf, &lineNum, &entryNum); 3188 3189 (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s", 3190 menu_cmds[TITLE_CMD], menu_cmds[SEP_CMD], title); 3191 line_parser(mp, linebuf, &lineNum, &entryNum); 3192 3193 (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s", 3194 menu_cmds[FINDROOT_CMD], menu_cmds[SEP_CMD], findroot); 3195 line_parser(mp, linebuf, &lineNum, &entryNum); 3196 BAM_DPRINTF((D_ADD_FINDROOT_NUM, fcn, lineNum, entryNum)); 3197 3198 (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s", 3199 menu_cmds[k_cmd], menu_cmds[SEP_CMD], kernel); 3200 line_parser(mp, linebuf, &lineNum, &entryNum); 3201 3202 if (mod_kernel != NULL) { 3203 (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s", 3204 menu_cmds[m_cmd], menu_cmds[SEP_CMD], mod_kernel); 3205 line_parser(mp, linebuf, &lineNum, &entryNum); 3206 } 3207 3208 (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s", 3209 menu_cmds[m_cmd], menu_cmds[SEP_CMD], module); 3210 line_parser(mp, linebuf, &lineNum, &entryNum); 3211 3212 (void) snprintf(linebuf, sizeof (linebuf), "%s%s", 3213 menu_cmds[COMMENT_CMD], BAM_BOOTADM_FTR); 3214 line_parser(mp, linebuf, &lineNum, &entryNum); 3215 3216 return (entryNum); 3217 } 3218 3219 static error_t 3220 do_delete(menu_t *mp, int entryNum) 3221 { 3222 line_t *lp; 3223 line_t *freed; 3224 entry_t *ent; 3225 entry_t *tmp; 3226 int deleted; 3227 const char *fcn = "do_delete()"; 3228 3229 assert(entryNum != ENTRY_INIT); 3230 3231 tmp = NULL; 3232 3233 ent = mp->entries; 3234 while (ent) { 3235 lp = ent->start; 3236 /* check entry number and make sure it's a bootadm entry */ 3237 if (lp->flags != BAM_COMMENT || 3238 strcmp(lp->arg, BAM_BOOTADM_HDR) != 0 || 3239 (entryNum != ALL_ENTRIES && lp->entryNum != entryNum)) { 3240 ent = ent->next; 3241 continue; 3242 } 3243 3244 /* free the entry content */ 3245 do { 3246 freed = lp; 3247 lp = lp->next; /* prev stays the same */ 3248 BAM_DPRINTF((D_FREEING_LINE, fcn, freed->lineNum)); 3249 unlink_line(mp, freed); 3250 line_free(freed); 3251 } while (freed != ent->end); 3252 3253 /* free the entry_t structure */ 3254 assert(tmp == NULL); 3255 tmp = ent; 3256 ent = ent->next; 3257 if (tmp->prev) 3258 tmp->prev->next = ent; 3259 else 3260 mp->entries = ent; 3261 if (ent) 3262 ent->prev = tmp->prev; 3263 BAM_DPRINTF((D_FREEING_ENTRY, fcn, tmp->entryNum)); 3264 free(tmp); 3265 tmp = NULL; 3266 deleted = 1; 3267 } 3268 3269 assert(tmp == NULL); 3270 3271 if (!deleted && entryNum != ALL_ENTRIES) { 3272 bam_error(NO_BOOTADM_MATCH); 3273 return (BAM_ERROR); 3274 } 3275 3276 /* 3277 * Now that we have deleted an entry, update 3278 * the entry numbering and the default cmd. 3279 */ 3280 update_numbering(mp); 3281 3282 return (BAM_SUCCESS); 3283 } 3284 3285 static error_t 3286 delete_all_entries(menu_t *mp, char *dummy, char *opt) 3287 { 3288 assert(mp); 3289 assert(dummy == NULL); 3290 assert(opt == NULL); 3291 3292 BAM_DPRINTF((D_FUNC_ENTRY0, "delete_all_entries")); 3293 3294 if (mp->start == NULL) { 3295 bam_print(EMPTY_MENU); 3296 return (BAM_SUCCESS); 3297 } 3298 3299 if (do_delete(mp, ALL_ENTRIES) != BAM_SUCCESS) { 3300 return (BAM_ERROR); 3301 } 3302 3303 return (BAM_WRITE); 3304 } 3305 3306 static FILE * 3307 create_diskmap(char *osroot) 3308 { 3309 FILE *fp; 3310 char cmd[PATH_MAX]; 3311 const char *fcn = "create_diskmap()"; 3312 3313 /* make sure we have a map file */ 3314 fp = fopen(GRUBDISK_MAP, "r"); 3315 if (fp == NULL) { 3316 (void) snprintf(cmd, sizeof (cmd), 3317 "%s/%s > /dev/null", osroot, CREATE_DISKMAP); 3318 if (exec_cmd(cmd, NULL) != 0) 3319 return (NULL); 3320 fp = fopen(GRUBDISK_MAP, "r"); 3321 INJECT_ERROR1("DISKMAP_CREATE_FAIL", fp = NULL); 3322 if (fp) { 3323 BAM_DPRINTF((D_CREATED_DISKMAP, fcn, GRUBDISK_MAP)); 3324 } else { 3325 BAM_DPRINTF((D_CREATE_DISKMAP_FAIL, fcn, GRUBDISK_MAP)); 3326 } 3327 } 3328 return (fp); 3329 } 3330 3331 #define SECTOR_SIZE 512 3332 3333 static int 3334 get_partition(char *device) 3335 { 3336 int i, fd, is_pcfs, partno = -1; 3337 struct mboot *mboot; 3338 char boot_sect[SECTOR_SIZE]; 3339 char *wholedisk, *slice; 3340 3341 /* form whole disk (p0) */ 3342 slice = device + strlen(device) - 2; 3343 is_pcfs = (*slice != 's'); 3344 if (!is_pcfs) 3345 *slice = '\0'; 3346 wholedisk = s_calloc(1, strlen(device) + 3); 3347 (void) snprintf(wholedisk, strlen(device) + 3, "%sp0", device); 3348 if (!is_pcfs) 3349 *slice = 's'; 3350 3351 /* read boot sector */ 3352 fd = open(wholedisk, O_RDONLY); 3353 free(wholedisk); 3354 if (fd == -1 || read(fd, boot_sect, SECTOR_SIZE) != SECTOR_SIZE) { 3355 return (partno); 3356 } 3357 (void) close(fd); 3358 3359 /* parse fdisk table */ 3360 mboot = (struct mboot *)((void *)boot_sect); 3361 for (i = 0; i < FD_NUMPART; i++) { 3362 struct ipart *part = 3363 (struct ipart *)(uintptr_t)mboot->parts + i; 3364 if (is_pcfs) { /* looking for solaris boot part */ 3365 if (part->systid == 0xbe) { 3366 partno = i; 3367 break; 3368 } 3369 } else { /* look for solaris partition, old and new */ 3370 if (part->systid == SUNIXOS || 3371 part->systid == SUNIXOS2) { 3372 partno = i; 3373 break; 3374 } 3375 } 3376 } 3377 return (partno); 3378 } 3379 3380 char * 3381 get_grubroot(char *osroot, char *osdev, char *menu_root) 3382 { 3383 char *grubroot; /* (hd#,#,#) */ 3384 char *slice; 3385 char *grubhd; 3386 int fdiskpart; 3387 int found = 0; 3388 char *devname; 3389 char *ctdname = strstr(osdev, "dsk/"); 3390 char linebuf[PATH_MAX]; 3391 FILE *fp; 3392 3393 INJECT_ERROR1("GRUBROOT_INVALID_OSDEV", ctdname = NULL); 3394 if (ctdname == NULL) { 3395 bam_error(INVALID_DEV_DSK, osdev); 3396 return (NULL); 3397 } 3398 3399 if (menu_root && !menu_on_bootdisk(osroot, menu_root)) { 3400 /* menu bears no resemblance to our reality */ 3401 bam_error(CANNOT_GRUBROOT_BOOTDISK, osdev); 3402 return (NULL); 3403 } 3404 3405 ctdname += strlen("dsk/"); 3406 slice = strrchr(ctdname, 's'); 3407 if (slice) 3408 *slice = '\0'; 3409 3410 fp = create_diskmap(osroot); 3411 if (fp == NULL) { 3412 bam_error(DISKMAP_FAIL, osroot); 3413 return (NULL); 3414 } 3415 3416 rewind(fp); 3417 while (s_fgets(linebuf, sizeof (linebuf), fp) != NULL) { 3418 grubhd = strtok(linebuf, " \t\n"); 3419 if (grubhd) 3420 devname = strtok(NULL, " \t\n"); 3421 else 3422 devname = NULL; 3423 if (devname && strcmp(devname, ctdname) == 0) { 3424 found = 1; 3425 break; 3426 } 3427 } 3428 3429 if (slice) 3430 *slice = 's'; 3431 3432 (void) fclose(fp); 3433 fp = NULL; 3434 3435 INJECT_ERROR1("GRUBROOT_BIOSDEV_FAIL", found = 0); 3436 if (found == 0) { 3437 bam_error(BIOSDEV_SKIP, osdev); 3438 return (NULL); 3439 } 3440 3441 fdiskpart = get_partition(osdev); 3442 INJECT_ERROR1("GRUBROOT_FDISK_FAIL", fdiskpart = -1); 3443 if (fdiskpart == -1) { 3444 bam_error(FDISKPART_FAIL, osdev); 3445 return (NULL); 3446 } 3447 3448 grubroot = s_calloc(1, 10); 3449 if (slice) { 3450 (void) snprintf(grubroot, 10, "(hd%s,%d,%c)", 3451 grubhd, fdiskpart, slice[1] + 'a' - '0'); 3452 } else 3453 (void) snprintf(grubroot, 10, "(hd%s,%d)", 3454 grubhd, fdiskpart); 3455 3456 assert(fp == NULL); 3457 assert(strncmp(grubroot, "(hd", strlen("(hd")) == 0); 3458 return (grubroot); 3459 } 3460 3461 static char * 3462 find_primary_common(char *mntpt, char *fstype) 3463 { 3464 char signdir[PATH_MAX]; 3465 char tmpsign[MAXNAMELEN + 1]; 3466 char *lu; 3467 char *ufs; 3468 char *zfs; 3469 DIR *dirp = NULL; 3470 struct dirent *entp; 3471 struct stat sb; 3472 const char *fcn = "find_primary_common()"; 3473 3474 (void) snprintf(signdir, sizeof (signdir), "%s/%s", 3475 mntpt, GRUBSIGN_DIR); 3476 3477 if (stat(signdir, &sb) == -1) { 3478 BAM_DPRINTF((D_NO_SIGNDIR, fcn, signdir)); 3479 return (NULL); 3480 } 3481 3482 dirp = opendir(signdir); 3483 INJECT_ERROR1("SIGNDIR_OPENDIR_FAIL", dirp = NULL); 3484 if (dirp == NULL) { 3485 bam_error(OPENDIR_FAILED, signdir, strerror(errno)); 3486 return (NULL); 3487 } 3488 3489 ufs = zfs = lu = NULL; 3490 3491 while (entp = readdir(dirp)) { 3492 if (strcmp(entp->d_name, ".") == 0 || 3493 strcmp(entp->d_name, "..") == 0) 3494 continue; 3495 3496 (void) snprintf(tmpsign, sizeof (tmpsign), "%s", entp->d_name); 3497 3498 if (lu == NULL && 3499 strncmp(tmpsign, GRUBSIGN_LU_PREFIX, 3500 strlen(GRUBSIGN_LU_PREFIX)) == 0) { 3501 lu = s_strdup(tmpsign); 3502 } 3503 3504 if (ufs == NULL && 3505 strncmp(tmpsign, GRUBSIGN_UFS_PREFIX, 3506 strlen(GRUBSIGN_UFS_PREFIX)) == 0) { 3507 ufs = s_strdup(tmpsign); 3508 } 3509 3510 if (zfs == NULL && 3511 strncmp(tmpsign, GRUBSIGN_ZFS_PREFIX, 3512 strlen(GRUBSIGN_ZFS_PREFIX)) == 0) { 3513 zfs = s_strdup(tmpsign); 3514 } 3515 } 3516 3517 BAM_DPRINTF((D_EXIST_PRIMARY_SIGNS, fcn, 3518 zfs ? zfs : "NULL", 3519 ufs ? ufs : "NULL", 3520 lu ? lu : "NULL")); 3521 3522 if (dirp) { 3523 (void) closedir(dirp); 3524 dirp = NULL; 3525 } 3526 3527 if (strcmp(fstype, "ufs") == 0 && zfs) { 3528 bam_error(SIGN_FSTYPE_MISMATCH, zfs, "ufs"); 3529 free(zfs); 3530 zfs = NULL; 3531 } else if (strcmp(fstype, "zfs") == 0 && ufs) { 3532 bam_error(SIGN_FSTYPE_MISMATCH, ufs, "zfs"); 3533 free(ufs); 3534 ufs = NULL; 3535 } 3536 3537 assert(dirp == NULL); 3538 3539 /* For now, we let Live Upgrade take care of its signature itself */ 3540 if (lu) { 3541 BAM_DPRINTF((D_FREEING_LU_SIGNS, fcn, lu)); 3542 free(lu); 3543 lu = NULL; 3544 } 3545 3546 return (zfs ? zfs : ufs); 3547 } 3548 3549 static char * 3550 find_backup_common(char *mntpt, char *fstype) 3551 { 3552 FILE *bfp = NULL; 3553 char tmpsign[MAXNAMELEN + 1]; 3554 char backup[PATH_MAX]; 3555 char *ufs; 3556 char *zfs; 3557 char *lu; 3558 int error; 3559 const char *fcn = "find_backup_common()"; 3560 3561 /* 3562 * We didn't find it in the primary directory. 3563 * Look at the backup 3564 */ 3565 (void) snprintf(backup, sizeof (backup), "%s%s", 3566 mntpt, GRUBSIGN_BACKUP); 3567 3568 bfp = fopen(backup, "r"); 3569 if (bfp == NULL) { 3570 error = errno; 3571 if (bam_verbose) { 3572 bam_error(OPEN_FAIL, backup, strerror(error)); 3573 } 3574 BAM_DPRINTF((D_OPEN_FAIL, fcn, backup, strerror(error))); 3575 return (NULL); 3576 } 3577 3578 ufs = zfs = lu = NULL; 3579 3580 while (s_fgets(tmpsign, sizeof (tmpsign), bfp) != NULL) { 3581 3582 if (lu == NULL && 3583 strncmp(tmpsign, GRUBSIGN_LU_PREFIX, 3584 strlen(GRUBSIGN_LU_PREFIX)) == 0) { 3585 lu = s_strdup(tmpsign); 3586 } 3587 3588 if (ufs == NULL && 3589 strncmp(tmpsign, GRUBSIGN_UFS_PREFIX, 3590 strlen(GRUBSIGN_UFS_PREFIX)) == 0) { 3591 ufs = s_strdup(tmpsign); 3592 } 3593 3594 if (zfs == NULL && 3595 strncmp(tmpsign, GRUBSIGN_ZFS_PREFIX, 3596 strlen(GRUBSIGN_ZFS_PREFIX)) == 0) { 3597 zfs = s_strdup(tmpsign); 3598 } 3599 } 3600 3601 BAM_DPRINTF((D_EXIST_BACKUP_SIGNS, fcn, 3602 zfs ? zfs : "NULL", 3603 ufs ? ufs : "NULL", 3604 lu ? lu : "NULL")); 3605 3606 if (bfp) { 3607 (void) fclose(bfp); 3608 bfp = NULL; 3609 } 3610 3611 if (strcmp(fstype, "ufs") == 0 && zfs) { 3612 bam_error(SIGN_FSTYPE_MISMATCH, zfs, "ufs"); 3613 free(zfs); 3614 zfs = NULL; 3615 } else if (strcmp(fstype, "zfs") == 0 && ufs) { 3616 bam_error(SIGN_FSTYPE_MISMATCH, ufs, "zfs"); 3617 free(ufs); 3618 ufs = NULL; 3619 } 3620 3621 assert(bfp == NULL); 3622 3623 /* For now, we let Live Upgrade take care of its signature itself */ 3624 if (lu) { 3625 BAM_DPRINTF((D_FREEING_LU_SIGNS, fcn, lu)); 3626 free(lu); 3627 lu = NULL; 3628 } 3629 3630 return (zfs ? zfs : ufs); 3631 } 3632 3633 static char * 3634 find_ufs_existing(char *osroot) 3635 { 3636 char *sign; 3637 const char *fcn = "find_ufs_existing()"; 3638 3639 sign = find_primary_common(osroot, "ufs"); 3640 if (sign == NULL) { 3641 sign = find_backup_common(osroot, "ufs"); 3642 BAM_DPRINTF((D_EXIST_BACKUP_SIGN, fcn, sign ? sign : "NULL")); 3643 } else { 3644 BAM_DPRINTF((D_EXIST_PRIMARY_SIGN, fcn, sign)); 3645 } 3646 3647 return (sign); 3648 } 3649 3650 char * 3651 get_mountpoint(char *special, char *fstype) 3652 { 3653 FILE *mntfp; 3654 struct mnttab mp = {0}; 3655 struct mnttab mpref = {0}; 3656 int error; 3657 int ret; 3658 const char *fcn = "get_mountpoint()"; 3659 3660 BAM_DPRINTF((D_FUNC_ENTRY2, fcn, special, fstype)); 3661 3662 mntfp = fopen(MNTTAB, "r"); 3663 error = errno; 3664 INJECT_ERROR1("MNTTAB_ERR_GET_MNTPT", mntfp = NULL); 3665 if (mntfp == NULL) { 3666 bam_error(OPEN_FAIL, MNTTAB, strerror(error)); 3667 return (NULL); 3668 } 3669 3670 mpref.mnt_special = special; 3671 mpref.mnt_fstype = fstype; 3672 3673 ret = getmntany(mntfp, &mp, &mpref); 3674 INJECT_ERROR1("GET_MOUNTPOINT_MNTANY", ret = 1); 3675 if (ret != 0) { 3676 (void) fclose(mntfp); 3677 BAM_DPRINTF((D_NO_MNTPT, fcn, special, fstype)); 3678 return (NULL); 3679 } 3680 (void) fclose(mntfp); 3681 3682 assert(mp.mnt_mountp); 3683 3684 BAM_DPRINTF((D_GET_MOUNTPOINT_RET, fcn, special, mp.mnt_mountp)); 3685 3686 return (s_strdup(mp.mnt_mountp)); 3687 } 3688 3689 /* 3690 * Mounts a "legacy" top dataset (if needed) 3691 * Returns: The mountpoint of the legacy top dataset or NULL on error 3692 * mnted returns one of the above values defined for zfs_mnted_t 3693 */ 3694 static char * 3695 mount_legacy_dataset(char *pool, zfs_mnted_t *mnted) 3696 { 3697 char cmd[PATH_MAX]; 3698 char tmpmnt[PATH_MAX]; 3699 filelist_t flist = {0}; 3700 char *is_mounted; 3701 struct stat sb; 3702 int ret; 3703 const char *fcn = "mount_legacy_dataset()"; 3704 3705 BAM_DPRINTF((D_FUNC_ENTRY1, fcn, pool)); 3706 3707 *mnted = ZFS_MNT_ERROR; 3708 3709 (void) snprintf(cmd, sizeof (cmd), 3710 "/sbin/zfs get -Ho value mounted %s", 3711 pool); 3712 3713 ret = exec_cmd(cmd, &flist); 3714 INJECT_ERROR1("Z_MOUNT_LEG_GET_MOUNTED_CMD", ret = 1); 3715 if (ret != 0) { 3716 bam_error(ZFS_MNTED_FAILED, pool); 3717 return (NULL); 3718 } 3719 3720 INJECT_ERROR1("Z_MOUNT_LEG_GET_MOUNTED_OUT", flist.head = NULL); 3721 if ((flist.head == NULL) || (flist.head != flist.tail)) { 3722 bam_error(BAD_ZFS_MNTED, pool); 3723 filelist_free(&flist); 3724 return (NULL); 3725 } 3726 3727 is_mounted = strtok(flist.head->line, " \t\n"); 3728 INJECT_ERROR1("Z_MOUNT_LEG_GET_MOUNTED_STRTOK_YES", is_mounted = "yes"); 3729 INJECT_ERROR1("Z_MOUNT_LEG_GET_MOUNTED_STRTOK_NO", is_mounted = "no"); 3730 if (strcmp(is_mounted, "no") != 0) { 3731 filelist_free(&flist); 3732 *mnted = LEGACY_ALREADY; 3733 /* get_mountpoint returns a strdup'ed string */ 3734 BAM_DPRINTF((D_Z_MOUNT_TOP_LEG_ALREADY, fcn, pool)); 3735 return (get_mountpoint(pool, "zfs")); 3736 } 3737 3738 filelist_free(&flist); 3739 3740 /* 3741 * legacy top dataset is not mounted. Mount it now 3742 * First create a mountpoint. 3743 */ 3744 (void) snprintf(tmpmnt, sizeof (tmpmnt), "%s.%d", 3745 ZFS_LEGACY_MNTPT, getpid()); 3746 3747 ret = stat(tmpmnt, &sb); 3748 if (ret == -1) { 3749 BAM_DPRINTF((D_Z_MOUNT_TOP_LEG_MNTPT_ABS, fcn, pool, tmpmnt)); 3750 ret = mkdirp(tmpmnt, 0755); 3751 INJECT_ERROR1("Z_MOUNT_TOP_LEG_MNTPT_MKDIRP", ret = -1); 3752 if (ret == -1) { 3753 bam_error(MKDIR_FAILED, tmpmnt, strerror(errno)); 3754 return (NULL); 3755 } 3756 } else { 3757 BAM_DPRINTF((D_Z_MOUNT_TOP_LEG_MNTPT_PRES, fcn, pool, tmpmnt)); 3758 } 3759 3760 (void) snprintf(cmd, sizeof (cmd), 3761 "/sbin/mount -F zfs %s %s", 3762 pool, tmpmnt); 3763 3764 ret = exec_cmd(cmd, NULL); 3765 INJECT_ERROR1("Z_MOUNT_TOP_LEG_MOUNT_CMD", ret = 1); 3766 if (ret != 0) { 3767 bam_error(ZFS_MOUNT_FAILED, pool); 3768 (void) rmdir(tmpmnt); 3769 return (NULL); 3770 } 3771 3772 *mnted = LEGACY_MOUNTED; 3773 BAM_DPRINTF((D_Z_MOUNT_TOP_LEG_MOUNTED, fcn, pool, tmpmnt)); 3774 return (s_strdup(tmpmnt)); 3775 } 3776 3777 /* 3778 * Mounts the top dataset (if needed) 3779 * Returns: The mountpoint of the top dataset or NULL on error 3780 * mnted returns one of the above values defined for zfs_mnted_t 3781 */ 3782 static char * 3783 mount_top_dataset(char *pool, zfs_mnted_t *mnted) 3784 { 3785 char cmd[PATH_MAX]; 3786 filelist_t flist = {0}; 3787 char *is_mounted; 3788 char *mntpt; 3789 char *zmntpt; 3790 int ret; 3791 const char *fcn = "mount_top_dataset()"; 3792 3793 *mnted = ZFS_MNT_ERROR; 3794 3795 BAM_DPRINTF((D_FUNC_ENTRY1, fcn, pool)); 3796 3797 /* 3798 * First check if the top dataset is a "legacy" dataset 3799 */ 3800 (void) snprintf(cmd, sizeof (cmd), 3801 "/sbin/zfs get -Ho value mountpoint %s", 3802 pool); 3803 ret = exec_cmd(cmd, &flist); 3804 INJECT_ERROR1("Z_MOUNT_TOP_GET_MNTPT", ret = 1); 3805 if (ret != 0) { 3806 bam_error(ZFS_MNTPT_FAILED, pool); 3807 return (NULL); 3808 } 3809 3810 if (flist.head && (flist.head == flist.tail)) { 3811 char *legacy = strtok(flist.head->line, " \t\n"); 3812 if (legacy && strcmp(legacy, "legacy") == 0) { 3813 filelist_free(&flist); 3814 BAM_DPRINTF((D_Z_IS_LEGACY, fcn, pool)); 3815 return (mount_legacy_dataset(pool, mnted)); 3816 } 3817 } 3818 3819 filelist_free(&flist); 3820 3821 BAM_DPRINTF((D_Z_IS_NOT_LEGACY, fcn, pool)); 3822 3823 (void) snprintf(cmd, sizeof (cmd), 3824 "/sbin/zfs get -Ho value mounted %s", 3825 pool); 3826 3827 ret = exec_cmd(cmd, &flist); 3828 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MOUNTED", ret = 1); 3829 if (ret != 0) { 3830 bam_error(ZFS_MNTED_FAILED, pool); 3831 return (NULL); 3832 } 3833 3834 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MOUNTED_VAL", flist.head = NULL); 3835 if ((flist.head == NULL) || (flist.head != flist.tail)) { 3836 bam_error(BAD_ZFS_MNTED, pool); 3837 filelist_free(&flist); 3838 return (NULL); 3839 } 3840 3841 is_mounted = strtok(flist.head->line, " \t\n"); 3842 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MOUNTED_YES", is_mounted = "yes"); 3843 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MOUNTED_NO", is_mounted = "no"); 3844 if (strcmp(is_mounted, "no") != 0) { 3845 filelist_free(&flist); 3846 *mnted = ZFS_ALREADY; 3847 BAM_DPRINTF((D_Z_MOUNT_TOP_NONLEG_MOUNTED_ALREADY, fcn, pool)); 3848 goto mounted; 3849 } 3850 3851 filelist_free(&flist); 3852 BAM_DPRINTF((D_Z_MOUNT_TOP_NONLEG_MOUNTED_NOT_ALREADY, fcn, pool)); 3853 3854 /* top dataset is not mounted. Mount it now */ 3855 (void) snprintf(cmd, sizeof (cmd), 3856 "/sbin/zfs mount %s", pool); 3857 ret = exec_cmd(cmd, NULL); 3858 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_MOUNT_CMD", ret = 1); 3859 if (ret != 0) { 3860 bam_error(ZFS_MOUNT_FAILED, pool); 3861 return (NULL); 3862 } 3863 *mnted = ZFS_MOUNTED; 3864 BAM_DPRINTF((D_Z_MOUNT_TOP_NONLEG_MOUNTED_NOW, fcn, pool)); 3865 /*FALLTHRU*/ 3866 mounted: 3867 /* 3868 * Now get the mountpoint 3869 */ 3870 (void) snprintf(cmd, sizeof (cmd), 3871 "/sbin/zfs get -Ho value mountpoint %s", 3872 pool); 3873 3874 ret = exec_cmd(cmd, &flist); 3875 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MNTPT_CMD", ret = 1); 3876 if (ret != 0) { 3877 bam_error(ZFS_MNTPT_FAILED, pool); 3878 goto error; 3879 } 3880 3881 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MNTPT_OUT", flist.head = NULL); 3882 if ((flist.head == NULL) || (flist.head != flist.tail)) { 3883 bam_error(NULL_ZFS_MNTPT, pool); 3884 goto error; 3885 } 3886 3887 mntpt = strtok(flist.head->line, " \t\n"); 3888 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MNTPT_STRTOK", mntpt = "foo"); 3889 if (*mntpt != '/') { 3890 bam_error(BAD_ZFS_MNTPT, pool, mntpt); 3891 goto error; 3892 } 3893 zmntpt = s_strdup(mntpt); 3894 3895 filelist_free(&flist); 3896 3897 BAM_DPRINTF((D_Z_MOUNT_TOP_NONLEG_MNTPT, fcn, pool, zmntpt)); 3898 3899 return (zmntpt); 3900 3901 error: 3902 filelist_free(&flist); 3903 (void) umount_top_dataset(pool, *mnted, NULL); 3904 BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 3905 return (NULL); 3906 } 3907 3908 static int 3909 umount_top_dataset(char *pool, zfs_mnted_t mnted, char *mntpt) 3910 { 3911 char cmd[PATH_MAX]; 3912 int ret; 3913 const char *fcn = "umount_top_dataset()"; 3914 3915 INJECT_ERROR1("Z_UMOUNT_TOP_INVALID_STATE", mnted = ZFS_MNT_ERROR); 3916 switch (mnted) { 3917 case LEGACY_ALREADY: 3918 case ZFS_ALREADY: 3919 /* nothing to do */ 3920 BAM_DPRINTF((D_Z_UMOUNT_TOP_ALREADY_NOP, fcn, pool, 3921 mntpt ? mntpt : "NULL")); 3922 free(mntpt); 3923 return (BAM_SUCCESS); 3924 case LEGACY_MOUNTED: 3925 (void) snprintf(cmd, sizeof (cmd), 3926 "/sbin/umount %s", pool); 3927 ret = exec_cmd(cmd, NULL); 3928 INJECT_ERROR1("Z_UMOUNT_TOP_LEGACY_UMOUNT_FAIL", ret = 1); 3929 if (ret != 0) { 3930 bam_error(UMOUNT_FAILED, pool); 3931 free(mntpt); 3932 return (BAM_ERROR); 3933 } 3934 if (mntpt) 3935 (void) rmdir(mntpt); 3936 free(mntpt); 3937 BAM_DPRINTF((D_Z_UMOUNT_TOP_LEGACY, fcn, pool)); 3938 return (BAM_SUCCESS); 3939 case ZFS_MOUNTED: 3940 free(mntpt); 3941 (void) snprintf(cmd, sizeof (cmd), 3942 "/sbin/zfs unmount %s", pool); 3943 ret = exec_cmd(cmd, NULL); 3944 INJECT_ERROR1("Z_UMOUNT_TOP_NONLEG_UMOUNT_FAIL", ret = 1); 3945 if (ret != 0) { 3946 bam_error(UMOUNT_FAILED, pool); 3947 return (BAM_ERROR); 3948 } 3949 BAM_DPRINTF((D_Z_UMOUNT_TOP_NONLEG, fcn, pool)); 3950 return (BAM_SUCCESS); 3951 default: 3952 bam_error(INT_BAD_MNTSTATE, pool); 3953 return (BAM_ERROR); 3954 } 3955 /*NOTREACHED*/ 3956 } 3957 3958 /* 3959 * For ZFS, osdev can be one of two forms 3960 * It can be a "special" file as seen in mnttab: rpool/ROOT/szboot_0402 3961 * It can be a /dev/[r]dsk special file. We handle both instances 3962 */ 3963 static char * 3964 get_pool(char *osdev) 3965 { 3966 char cmd[PATH_MAX]; 3967 char buf[PATH_MAX]; 3968 filelist_t flist = {0}; 3969 char *pool; 3970 char *cp; 3971 char *slash; 3972 int ret; 3973 const char *fcn = "get_pool()"; 3974 3975 INJECT_ERROR1("GET_POOL_OSDEV", osdev = NULL); 3976 if (osdev == NULL) { 3977 bam_error(GET_POOL_OSDEV_NULL); 3978 return (NULL); 3979 } 3980 3981 BAM_DPRINTF((D_GET_POOL_OSDEV, fcn, osdev)); 3982 3983 if (osdev[0] != '/') { 3984 (void) strlcpy(buf, osdev, sizeof (buf)); 3985 slash = strchr(buf, '/'); 3986 if (slash) 3987 *slash = '\0'; 3988 pool = s_strdup(buf); 3989 BAM_DPRINTF((D_GET_POOL_RET, fcn, pool)); 3990 return (pool); 3991 } else if (strncmp(osdev, "/dev/dsk/", strlen("/dev/dsk/")) != 0 && 3992 strncmp(osdev, "/dev/rdsk/", strlen("/dev/rdsk/")) != 0) { 3993 bam_error(GET_POOL_BAD_OSDEV, osdev); 3994 return (NULL); 3995 } 3996 3997 (void) snprintf(cmd, sizeof (cmd), 3998 "/usr/sbin/fstyp -a %s 2>/dev/null | /bin/grep '^name:'", 3999 osdev); 4000 4001 ret = exec_cmd(cmd, &flist); 4002 INJECT_ERROR1("GET_POOL_FSTYP", ret = 1); 4003 if (ret != 0) { 4004 bam_error(FSTYP_A_FAILED, osdev); 4005 return (NULL); 4006 } 4007 4008 INJECT_ERROR1("GET_POOL_FSTYP_OUT", flist.head = NULL); 4009 if ((flist.head == NULL) || (flist.head != flist.tail)) { 4010 bam_error(NULL_FSTYP_A, osdev); 4011 filelist_free(&flist); 4012 return (NULL); 4013 } 4014 4015 (void) strtok(flist.head->line, "'"); 4016 cp = strtok(NULL, "'"); 4017 INJECT_ERROR1("GET_POOL_FSTYP_STRTOK", cp = NULL); 4018 if (cp == NULL) { 4019 bam_error(BAD_FSTYP_A, osdev); 4020 filelist_free(&flist); 4021 return (NULL); 4022 } 4023 4024 pool = s_strdup(cp); 4025 4026 filelist_free(&flist); 4027 4028 BAM_DPRINTF((D_GET_POOL_RET, fcn, pool)); 4029 4030 return (pool); 4031 } 4032 4033 static char * 4034 find_zfs_existing(char *osdev) 4035 { 4036 char *pool; 4037 zfs_mnted_t mnted; 4038 char *mntpt; 4039 char *sign; 4040 const char *fcn = "find_zfs_existing()"; 4041 4042 pool = get_pool(osdev); 4043 INJECT_ERROR1("ZFS_FIND_EXIST_POOL", pool = NULL); 4044 if (pool == NULL) { 4045 bam_error(ZFS_GET_POOL_FAILED, osdev); 4046 return (NULL); 4047 } 4048 4049 mntpt = mount_top_dataset(pool, &mnted); 4050 INJECT_ERROR1("ZFS_FIND_EXIST_MOUNT_TOP", mntpt = NULL); 4051 if (mntpt == NULL) { 4052 bam_error(ZFS_MOUNT_TOP_DATASET_FAILED, pool); 4053 free(pool); 4054 return (NULL); 4055 } 4056 4057 sign = find_primary_common(mntpt, "zfs"); 4058 if (sign == NULL) { 4059 sign = find_backup_common(mntpt, "zfs"); 4060 BAM_DPRINTF((D_EXIST_BACKUP_SIGN, fcn, sign ? sign : "NULL")); 4061 } else { 4062 BAM_DPRINTF((D_EXIST_PRIMARY_SIGN, fcn, sign)); 4063 } 4064 4065 (void) umount_top_dataset(pool, mnted, mntpt); 4066 4067 free(pool); 4068 4069 return (sign); 4070 } 4071 4072 static char * 4073 find_existing_sign(char *osroot, char *osdev, char *fstype) 4074 { 4075 const char *fcn = "find_existing_sign()"; 4076 4077 INJECT_ERROR1("FIND_EXIST_NOTSUP_FS", fstype = "foofs"); 4078 if (strcmp(fstype, "ufs") == 0) { 4079 BAM_DPRINTF((D_CHECK_UFS_EXIST_SIGN, fcn)); 4080 return (find_ufs_existing(osroot)); 4081 } else if (strcmp(fstype, "zfs") == 0) { 4082 BAM_DPRINTF((D_CHECK_ZFS_EXIST_SIGN, fcn)); 4083 return (find_zfs_existing(osdev)); 4084 } else { 4085 bam_error(GRUBSIGN_NOTSUP, fstype); 4086 return (NULL); 4087 } 4088 } 4089 4090 #define MH_HASH_SZ 16 4091 4092 typedef enum { 4093 MH_ERROR = -1, 4094 MH_NOMATCH, 4095 MH_MATCH 4096 } mh_search_t; 4097 4098 typedef struct mcache { 4099 char *mc_special; 4100 char *mc_mntpt; 4101 char *mc_fstype; 4102 struct mcache *mc_next; 4103 } mcache_t; 4104 4105 typedef struct mhash { 4106 mcache_t *mh_hash[MH_HASH_SZ]; 4107 } mhash_t; 4108 4109 static int 4110 mhash_fcn(char *key) 4111 { 4112 int i; 4113 uint64_t sum = 0; 4114 4115 for (i = 0; key[i] != '\0'; i++) { 4116 sum += (uchar_t)key[i]; 4117 } 4118 4119 sum %= MH_HASH_SZ; 4120 4121 assert(sum < MH_HASH_SZ); 4122 4123 return (sum); 4124 } 4125 4126 static mhash_t * 4127 cache_mnttab(void) 4128 { 4129 FILE *mfp; 4130 struct extmnttab mnt; 4131 mcache_t *mcp; 4132 mhash_t *mhp; 4133 char *ctds; 4134 int idx; 4135 int error; 4136 char *special_dup; 4137 const char *fcn = "cache_mnttab()"; 4138 4139 mfp = fopen(MNTTAB, "r"); 4140 error = errno; 4141 INJECT_ERROR1("CACHE_MNTTAB_MNTTAB_ERR", mfp = NULL); 4142 if (mfp == NULL) { 4143 bam_error(OPEN_FAIL, MNTTAB, strerror(error)); 4144 return (NULL); 4145 } 4146 4147 mhp = s_calloc(1, sizeof (mhash_t)); 4148 4149 resetmnttab(mfp); 4150 4151 while (getextmntent(mfp, &mnt, sizeof (mnt)) == 0) { 4152 /* only cache ufs */ 4153 if (strcmp(mnt.mnt_fstype, "ufs") != 0) 4154 continue; 4155 4156 /* basename() modifies its arg, so dup it */ 4157 special_dup = s_strdup(mnt.mnt_special); 4158 ctds = basename(special_dup); 4159 4160 mcp = s_calloc(1, sizeof (mcache_t)); 4161 mcp->mc_special = s_strdup(ctds); 4162 mcp->mc_mntpt = s_strdup(mnt.mnt_mountp); 4163 mcp->mc_fstype = s_strdup(mnt.mnt_fstype); 4164 BAM_DPRINTF((D_CACHE_MNTS, fcn, ctds, 4165 mnt.mnt_mountp, mnt.mnt_fstype)); 4166 idx = mhash_fcn(ctds); 4167 mcp->mc_next = mhp->mh_hash[idx]; 4168 mhp->mh_hash[idx] = mcp; 4169 free(special_dup); 4170 } 4171 4172 (void) fclose(mfp); 4173 4174 return (mhp); 4175 } 4176 4177 static void 4178 free_mnttab(mhash_t *mhp) 4179 { 4180 mcache_t *mcp; 4181 int i; 4182 4183 for (i = 0; i < MH_HASH_SZ; i++) { 4184 /*LINTED*/ 4185 while (mcp = mhp->mh_hash[i]) { 4186 mhp->mh_hash[i] = mcp->mc_next; 4187 free(mcp->mc_special); 4188 free(mcp->mc_mntpt); 4189 free(mcp->mc_fstype); 4190 free(mcp); 4191 } 4192 } 4193 4194 for (i = 0; i < MH_HASH_SZ; i++) { 4195 assert(mhp->mh_hash[i] == NULL); 4196 } 4197 free(mhp); 4198 } 4199 4200 static mh_search_t 4201 search_hash(mhash_t *mhp, char *special, char **mntpt) 4202 { 4203 int idx; 4204 mcache_t *mcp; 4205 const char *fcn = "search_hash()"; 4206 4207 assert(mntpt); 4208 4209 *mntpt = NULL; 4210 4211 INJECT_ERROR1("SEARCH_HASH_FULL_PATH", special = "/foo"); 4212 if (strchr(special, '/')) { 4213 bam_error(INVALID_MHASH_KEY, special); 4214 return (MH_ERROR); 4215 } 4216 4217 idx = mhash_fcn(special); 4218 4219 for (mcp = mhp->mh_hash[idx]; mcp; mcp = mcp->mc_next) { 4220 if (strcmp(mcp->mc_special, special) == 0) 4221 break; 4222 } 4223 4224 if (mcp == NULL) { 4225 BAM_DPRINTF((D_MNTTAB_HASH_NOMATCH, fcn, special)); 4226 return (MH_NOMATCH); 4227 } 4228 4229 assert(strcmp(mcp->mc_fstype, "ufs") == 0); 4230 *mntpt = mcp->mc_mntpt; 4231 BAM_DPRINTF((D_MNTTAB_HASH_MATCH, fcn, special)); 4232 return (MH_MATCH); 4233 } 4234 4235 static int 4236 check_add_ufs_sign_to_list(FILE *tfp, char *mntpt) 4237 { 4238 char *sign; 4239 char *signline; 4240 char signbuf[MAXNAMELEN]; 4241 int len; 4242 int error; 4243 const char *fcn = "check_add_ufs_sign_to_list()"; 4244 4245 /* safe to specify NULL as "osdev" arg for UFS */ 4246 sign = find_existing_sign(mntpt, NULL, "ufs"); 4247 if (sign == NULL) { 4248 /* No existing signature, nothing to add to list */ 4249 BAM_DPRINTF((D_NO_SIGN_TO_LIST, fcn, mntpt)); 4250 return (0); 4251 } 4252 4253 (void) snprintf(signbuf, sizeof (signbuf), "%s\n", sign); 4254 signline = signbuf; 4255 4256 INJECT_ERROR1("UFS_MNTPT_SIGN_NOTUFS", signline = "pool_rpool10\n"); 4257 if (strncmp(signline, GRUBSIGN_UFS_PREFIX, 4258 strlen(GRUBSIGN_UFS_PREFIX))) { 4259 bam_error(INVALID_UFS_SIGNATURE, sign); 4260 free(sign); 4261 /* ignore invalid signatures */ 4262 return (0); 4263 } 4264 4265 len = fputs(signline, tfp); 4266 error = errno; 4267 INJECT_ERROR1("SIGN_LIST_PUTS_ERROR", len = 0); 4268 if (len != strlen(signline)) { 4269 bam_error(SIGN_LIST_FPUTS_ERR, sign, strerror(error)); 4270 free(sign); 4271 return (-1); 4272 } 4273 4274 free(sign); 4275 4276 BAM_DPRINTF((D_SIGN_LIST_PUTS_DONE, fcn, mntpt)); 4277 return (0); 4278 } 4279 4280 /* 4281 * slice is a basename not a full pathname 4282 */ 4283 static int 4284 process_slice_common(char *slice, FILE *tfp, mhash_t *mhp, char *tmpmnt) 4285 { 4286 int ret; 4287 char cmd[PATH_MAX]; 4288 char path[PATH_MAX]; 4289 struct stat sbuf; 4290 char *mntpt; 4291 filelist_t flist = {0}; 4292 char *fstype; 4293 char blkslice[PATH_MAX]; 4294 const char *fcn = "process_slice_common()"; 4295 4296 4297 ret = search_hash(mhp, slice, &mntpt); 4298 switch (ret) { 4299 case MH_MATCH: 4300 if (check_add_ufs_sign_to_list(tfp, mntpt) == -1) 4301 return (-1); 4302 else 4303 return (0); 4304 case MH_NOMATCH: 4305 break; 4306 case MH_ERROR: 4307 default: 4308 return (-1); 4309 } 4310 4311 (void) snprintf(path, sizeof (path), "/dev/rdsk/%s", slice); 4312 if (stat(path, &sbuf) == -1) { 4313 BAM_DPRINTF((D_SLICE_ENOENT, fcn, path)); 4314 return (0); 4315 } 4316 4317 /* Check if ufs */ 4318 (void) snprintf(cmd, sizeof (cmd), 4319 "/usr/sbin/fstyp /dev/rdsk/%s 2>/dev/null", 4320 slice); 4321 4322 if (exec_cmd(cmd, &flist) != 0) { 4323 if (bam_verbose) 4324 bam_print(FSTYP_FAILED, slice); 4325 return (0); 4326 } 4327 4328 if ((flist.head == NULL) || (flist.head != flist.tail)) { 4329 if (bam_verbose) 4330 bam_print(FSTYP_BAD, slice); 4331 filelist_free(&flist); 4332 return (0); 4333 } 4334 4335 fstype = strtok(flist.head->line, " \t\n"); 4336 if (fstype == NULL || strcmp(fstype, "ufs") != 0) { 4337 if (bam_verbose) 4338 bam_print(NOT_UFS_SLICE, slice, fstype); 4339 filelist_free(&flist); 4340 return (0); 4341 } 4342 4343 filelist_free(&flist); 4344 4345 /* 4346 * Since we are mounting the filesystem read-only, the 4347 * the last mount field of the superblock is unchanged 4348 * and does not need to be fixed up post-mount; 4349 */ 4350 4351 (void) snprintf(blkslice, sizeof (blkslice), "/dev/dsk/%s", 4352 slice); 4353 4354 (void) snprintf(cmd, sizeof (cmd), 4355 "/usr/sbin/mount -F ufs -o ro %s %s " 4356 "> /dev/null 2>&1", blkslice, tmpmnt); 4357 4358 if (exec_cmd(cmd, NULL) != 0) { 4359 if (bam_verbose) 4360 bam_print(MOUNT_FAILED, blkslice, "ufs"); 4361 return (0); 4362 } 4363 4364 ret = check_add_ufs_sign_to_list(tfp, tmpmnt); 4365 4366 (void) snprintf(cmd, sizeof (cmd), 4367 "/usr/sbin/umount -f %s > /dev/null 2>&1", 4368 tmpmnt); 4369 4370 if (exec_cmd(cmd, NULL) != 0) { 4371 bam_print(UMOUNT_FAILED, slice); 4372 return (0); 4373 } 4374 4375 return (ret); 4376 } 4377 4378 static int 4379 process_vtoc_slices( 4380 char *s0, 4381 struct vtoc *vtoc, 4382 FILE *tfp, 4383 mhash_t *mhp, 4384 char *tmpmnt) 4385 { 4386 int idx; 4387 char slice[PATH_MAX]; 4388 size_t len; 4389 char *cp; 4390 const char *fcn = "process_vtoc_slices()"; 4391 4392 len = strlen(s0); 4393 4394 assert(s0[len - 2] == 's' && s0[len - 1] == '0'); 4395 4396 s0[len - 1] = '\0'; 4397 4398 (void) strlcpy(slice, s0, sizeof (slice)); 4399 4400 s0[len - 1] = '0'; 4401 4402 cp = slice + len - 1; 4403 4404 for (idx = 0; idx < vtoc->v_nparts; idx++) { 4405 4406 (void) snprintf(cp, sizeof (slice) - (len - 1), "%u", idx); 4407 4408 if (vtoc->v_part[idx].p_size == 0) { 4409 BAM_DPRINTF((D_VTOC_SIZE_ZERO, fcn, slice)); 4410 continue; 4411 } 4412 4413 /* Skip "SWAP", "USR", "BACKUP", "VAR", "HOME", "ALTSCTR" */ 4414 switch (vtoc->v_part[idx].p_tag) { 4415 case V_SWAP: 4416 case V_USR: 4417 case V_BACKUP: 4418 case V_VAR: 4419 case V_HOME: 4420 case V_ALTSCTR: 4421 BAM_DPRINTF((D_VTOC_NOT_ROOT_TAG, fcn, slice)); 4422 continue; 4423 default: 4424 BAM_DPRINTF((D_VTOC_ROOT_TAG, fcn, slice)); 4425 break; 4426 } 4427 4428 /* skip unmountable and readonly slices */ 4429 switch (vtoc->v_part[idx].p_flag) { 4430 case V_UNMNT: 4431 case V_RONLY: 4432 BAM_DPRINTF((D_VTOC_NOT_RDWR_FLAG, fcn, slice)); 4433 continue; 4434 default: 4435 BAM_DPRINTF((D_VTOC_RDWR_FLAG, fcn, slice)); 4436 break; 4437 } 4438 4439 if (process_slice_common(slice, tfp, mhp, tmpmnt) == -1) { 4440 return (-1); 4441 } 4442 } 4443 4444 return (0); 4445 } 4446 4447 static int 4448 process_efi_slices( 4449 char *s0, 4450 struct dk_gpt *efi, 4451 FILE *tfp, 4452 mhash_t *mhp, 4453 char *tmpmnt) 4454 { 4455 int idx; 4456 char slice[PATH_MAX]; 4457 size_t len; 4458 char *cp; 4459 const char *fcn = "process_efi_slices()"; 4460 4461 len = strlen(s0); 4462 4463 assert(s0[len - 2] == 's' && s0[len - 1] == '0'); 4464 4465 s0[len - 1] = '\0'; 4466 4467 (void) strlcpy(slice, s0, sizeof (slice)); 4468 4469 s0[len - 1] = '0'; 4470 4471 cp = slice + len - 1; 4472 4473 for (idx = 0; idx < efi->efi_nparts; idx++) { 4474 4475 (void) snprintf(cp, sizeof (slice) - (len - 1), "%u", idx); 4476 4477 if (efi->efi_parts[idx].p_size == 0) { 4478 BAM_DPRINTF((D_EFI_SIZE_ZERO, fcn, slice)); 4479 continue; 4480 } 4481 4482 /* Skip "SWAP", "USR", "BACKUP", "VAR", "HOME", "ALTSCTR" */ 4483 switch (efi->efi_parts[idx].p_tag) { 4484 case V_SWAP: 4485 case V_USR: 4486 case V_BACKUP: 4487 case V_VAR: 4488 case V_HOME: 4489 case V_ALTSCTR: 4490 BAM_DPRINTF((D_EFI_NOT_ROOT_TAG, fcn, slice)); 4491 continue; 4492 default: 4493 BAM_DPRINTF((D_EFI_ROOT_TAG, fcn, slice)); 4494 break; 4495 } 4496 4497 /* skip unmountable and readonly slices */ 4498 switch (efi->efi_parts[idx].p_flag) { 4499 case V_UNMNT: 4500 case V_RONLY: 4501 BAM_DPRINTF((D_EFI_NOT_RDWR_FLAG, fcn, slice)); 4502 continue; 4503 default: 4504 BAM_DPRINTF((D_EFI_RDWR_FLAG, fcn, slice)); 4505 break; 4506 } 4507 4508 if (process_slice_common(slice, tfp, mhp, tmpmnt) == -1) { 4509 return (-1); 4510 } 4511 } 4512 4513 return (0); 4514 } 4515 4516 /* 4517 * s0 is a basename not a full path 4518 */ 4519 static int 4520 process_slice0(char *s0, FILE *tfp, mhash_t *mhp, char *tmpmnt) 4521 { 4522 struct vtoc vtoc; 4523 struct dk_gpt *efi; 4524 char s0path[PATH_MAX]; 4525 struct stat sbuf; 4526 int e_flag; 4527 int v_flag; 4528 int retval; 4529 int err; 4530 int fd; 4531 const char *fcn = "process_slice0()"; 4532 4533 (void) snprintf(s0path, sizeof (s0path), "/dev/rdsk/%s", s0); 4534 4535 if (stat(s0path, &sbuf) == -1) { 4536 BAM_DPRINTF((D_SLICE0_ENOENT, fcn, s0path)); 4537 return (0); 4538 } 4539 4540 fd = open(s0path, O_NONBLOCK|O_RDONLY); 4541 if (fd == -1) { 4542 bam_error(OPEN_FAIL, s0path, strerror(errno)); 4543 return (0); 4544 } 4545 4546 e_flag = v_flag = 0; 4547 retval = ((err = read_vtoc(fd, &vtoc)) >= 0) ? 0 : err; 4548 switch (retval) { 4549 case VT_EIO: 4550 BAM_DPRINTF((D_VTOC_READ_FAIL, fcn, s0path)); 4551 break; 4552 case VT_EINVAL: 4553 BAM_DPRINTF((D_VTOC_INVALID, fcn, s0path)); 4554 break; 4555 case VT_ERROR: 4556 BAM_DPRINTF((D_VTOC_UNKNOWN_ERR, fcn, s0path)); 4557 break; 4558 case VT_ENOTSUP: 4559 e_flag = 1; 4560 BAM_DPRINTF((D_VTOC_NOTSUP, fcn, s0path)); 4561 break; 4562 case 0: 4563 v_flag = 1; 4564 BAM_DPRINTF((D_VTOC_READ_SUCCESS, fcn, s0path)); 4565 break; 4566 default: 4567 BAM_DPRINTF((D_VTOC_UNKNOWN_RETCODE, fcn, s0path)); 4568 break; 4569 } 4570 4571 4572 if (e_flag) { 4573 e_flag = 0; 4574 retval = ((err = efi_alloc_and_read(fd, &efi)) >= 0) ? 0 : err; 4575 switch (retval) { 4576 case VT_EIO: 4577 BAM_DPRINTF((D_EFI_READ_FAIL, fcn, s0path)); 4578 break; 4579 case VT_EINVAL: 4580 BAM_DPRINTF((D_EFI_INVALID, fcn, s0path)); 4581 break; 4582 case VT_ERROR: 4583 BAM_DPRINTF((D_EFI_UNKNOWN_ERR, fcn, s0path)); 4584 break; 4585 case VT_ENOTSUP: 4586 BAM_DPRINTF((D_EFI_NOTSUP, fcn, s0path)); 4587 break; 4588 case 0: 4589 e_flag = 1; 4590 BAM_DPRINTF((D_EFI_READ_SUCCESS, fcn, s0path)); 4591 break; 4592 default: 4593 BAM_DPRINTF((D_EFI_UNKNOWN_RETCODE, fcn, s0path)); 4594 break; 4595 } 4596 } 4597 4598 (void) close(fd); 4599 4600 if (v_flag) { 4601 retval = process_vtoc_slices(s0, 4602 &vtoc, tfp, mhp, tmpmnt); 4603 } else if (e_flag) { 4604 retval = process_efi_slices(s0, 4605 efi, tfp, mhp, tmpmnt); 4606 } else { 4607 BAM_DPRINTF((D_NOT_VTOC_OR_EFI, fcn, s0path)); 4608 return (0); 4609 } 4610 4611 return (retval); 4612 } 4613 4614 /* 4615 * Find and create a list of all existing UFS boot signatures 4616 */ 4617 static int 4618 FindAllUfsSignatures(void) 4619 { 4620 mhash_t *mnttab_hash; 4621 DIR *dirp = NULL; 4622 struct dirent *dp; 4623 char tmpmnt[PATH_MAX]; 4624 char cmd[PATH_MAX]; 4625 struct stat sb; 4626 int fd; 4627 FILE *tfp; 4628 size_t len; 4629 int ret; 4630 int error; 4631 const char *fcn = "FindAllUfsSignatures()"; 4632 4633 if (stat(UFS_SIGNATURE_LIST, &sb) != -1) { 4634 bam_print(SIGNATURE_LIST_EXISTS, UFS_SIGNATURE_LIST); 4635 return (0); 4636 } 4637 4638 fd = open(UFS_SIGNATURE_LIST".tmp", 4639 O_RDWR|O_CREAT|O_TRUNC, 0644); 4640 error = errno; 4641 INJECT_ERROR1("SIGN_LIST_TMP_TRUNC", fd = -1); 4642 if (fd == -1) { 4643 bam_error(OPEN_FAIL, UFS_SIGNATURE_LIST".tmp", strerror(error)); 4644 return (-1); 4645 } 4646 4647 ret = close(fd); 4648 error = errno; 4649 INJECT_ERROR1("SIGN_LIST_TMP_CLOSE", ret = -1); 4650 if (ret == -1) { 4651 bam_error(CLOSE_FAIL, UFS_SIGNATURE_LIST".tmp", 4652 strerror(error)); 4653 (void) unlink(UFS_SIGNATURE_LIST".tmp"); 4654 return (-1); 4655 } 4656 4657 tfp = fopen(UFS_SIGNATURE_LIST".tmp", "a"); 4658 error = errno; 4659 INJECT_ERROR1("SIGN_LIST_APPEND_FOPEN", tfp = NULL); 4660 if (tfp == NULL) { 4661 bam_error(OPEN_FAIL, UFS_SIGNATURE_LIST".tmp", strerror(error)); 4662 (void) unlink(UFS_SIGNATURE_LIST".tmp"); 4663 return (-1); 4664 } 4665 4666 mnttab_hash = cache_mnttab(); 4667 INJECT_ERROR1("CACHE_MNTTAB_ERROR", mnttab_hash = NULL); 4668 if (mnttab_hash == NULL) { 4669 (void) fclose(tfp); 4670 (void) unlink(UFS_SIGNATURE_LIST".tmp"); 4671 bam_error(CACHE_MNTTAB_FAIL, fcn); 4672 return (-1); 4673 } 4674 4675 (void) snprintf(tmpmnt, sizeof (tmpmnt), 4676 "/tmp/bootadm_ufs_sign_mnt.%d", getpid()); 4677 (void) unlink(tmpmnt); 4678 4679 ret = mkdirp(tmpmnt, 0755); 4680 error = errno; 4681 INJECT_ERROR1("MKDIRP_SIGN_MNT", ret = -1); 4682 if (ret == -1) { 4683 bam_error(MKDIR_FAILED, tmpmnt, strerror(error)); 4684 free_mnttab(mnttab_hash); 4685 (void) fclose(tfp); 4686 (void) unlink(UFS_SIGNATURE_LIST".tmp"); 4687 return (-1); 4688 } 4689 4690 dirp = opendir("/dev/rdsk"); 4691 error = errno; 4692 INJECT_ERROR1("OPENDIR_DEV_RDSK", dirp = NULL); 4693 if (dirp == NULL) { 4694 bam_error(OPENDIR_FAILED, "/dev/rdsk", strerror(error)); 4695 goto fail; 4696 } 4697 4698 while (dp = readdir(dirp)) { 4699 if (strcmp(dp->d_name, ".") == 0 || 4700 strcmp(dp->d_name, "..") == 0) 4701 continue; 4702 4703 /* 4704 * we only look for the s0 slice. This is guranteed to 4705 * have 's' at len - 2. 4706 */ 4707 len = strlen(dp->d_name); 4708 if (dp->d_name[len - 2 ] != 's' || dp->d_name[len - 1] != '0') { 4709 BAM_DPRINTF((D_SKIP_SLICE_NOTZERO, fcn, dp->d_name)); 4710 continue; 4711 } 4712 4713 ret = process_slice0(dp->d_name, tfp, mnttab_hash, tmpmnt); 4714 INJECT_ERROR1("PROCESS_S0_FAIL", ret = -1); 4715 if (ret == -1) 4716 goto fail; 4717 } 4718 4719 (void) closedir(dirp); 4720 free_mnttab(mnttab_hash); 4721 (void) rmdir(tmpmnt); 4722 4723 ret = fclose(tfp); 4724 error = errno; 4725 INJECT_ERROR1("FCLOSE_SIGNLIST_TMP", ret = EOF); 4726 if (ret == EOF) { 4727 bam_error(CLOSE_FAIL, UFS_SIGNATURE_LIST".tmp", 4728 strerror(error)); 4729 (void) unlink(UFS_SIGNATURE_LIST".tmp"); 4730 return (-1); 4731 } 4732 4733 /* We have a list of existing GRUB signatures. Sort it first */ 4734 (void) snprintf(cmd, sizeof (cmd), 4735 "/usr/bin/sort -u %s.tmp > %s.sorted", 4736 UFS_SIGNATURE_LIST, UFS_SIGNATURE_LIST); 4737 4738 ret = exec_cmd(cmd, NULL); 4739 INJECT_ERROR1("SORT_SIGN_LIST", ret = 1); 4740 if (ret != 0) { 4741 bam_error(GRUBSIGN_SORT_FAILED); 4742 (void) unlink(UFS_SIGNATURE_LIST".sorted"); 4743 (void) unlink(UFS_SIGNATURE_LIST".tmp"); 4744 return (-1); 4745 } 4746 4747 (void) unlink(UFS_SIGNATURE_LIST".tmp"); 4748 4749 ret = rename(UFS_SIGNATURE_LIST".sorted", UFS_SIGNATURE_LIST); 4750 error = errno; 4751 INJECT_ERROR1("RENAME_TMP_SIGNLIST", ret = -1); 4752 if (ret == -1) { 4753 bam_error(RENAME_FAIL, UFS_SIGNATURE_LIST, strerror(error)); 4754 (void) unlink(UFS_SIGNATURE_LIST".sorted"); 4755 return (-1); 4756 } 4757 4758 if (stat(UFS_SIGNATURE_LIST, &sb) == 0 && sb.st_size == 0) { 4759 BAM_DPRINTF((D_ZERO_LEN_SIGNLIST, fcn, UFS_SIGNATURE_LIST)); 4760 } 4761 4762 BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 4763 return (0); 4764 4765 fail: 4766 if (dirp) 4767 (void) closedir(dirp); 4768 free_mnttab(mnttab_hash); 4769 (void) rmdir(tmpmnt); 4770 (void) fclose(tfp); 4771 (void) unlink(UFS_SIGNATURE_LIST".tmp"); 4772 BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 4773 return (-1); 4774 } 4775 4776 static char * 4777 create_ufs_sign(void) 4778 { 4779 struct stat sb; 4780 int signnum = -1; 4781 char tmpsign[MAXNAMELEN + 1]; 4782 char *numstr; 4783 int i; 4784 FILE *tfp; 4785 int ret; 4786 int error; 4787 const char *fcn = "create_ufs_sign()"; 4788 4789 bam_print(SEARCHING_UFS_SIGN); 4790 4791 ret = FindAllUfsSignatures(); 4792 INJECT_ERROR1("FIND_ALL_UFS", ret = -1); 4793 if (ret == -1) { 4794 bam_error(ERR_FIND_UFS_SIGN); 4795 return (NULL); 4796 } 4797 4798 /* Make sure the list exists and is owned by root */ 4799 INJECT_ERROR1("SIGNLIST_NOT_CREATED", 4800 (void) unlink(UFS_SIGNATURE_LIST)); 4801 if (stat(UFS_SIGNATURE_LIST, &sb) == -1 || sb.st_uid != 0) { 4802 (void) unlink(UFS_SIGNATURE_LIST); 4803 bam_error(UFS_SIGNATURE_LIST_MISS, UFS_SIGNATURE_LIST); 4804 return (NULL); 4805 } 4806 4807 if (sb.st_size == 0) { 4808 bam_print(GRUBSIGN_UFS_NONE); 4809 i = 0; 4810 goto found; 4811 } 4812 4813 /* The signature list was sorted when it was created */ 4814 tfp = fopen(UFS_SIGNATURE_LIST, "r"); 4815 error = errno; 4816 INJECT_ERROR1("FOPEN_SIGN_LIST", tfp = NULL); 4817 if (tfp == NULL) { 4818 bam_error(UFS_SIGNATURE_LIST_OPENERR, 4819 UFS_SIGNATURE_LIST, strerror(error)); 4820 (void) unlink(UFS_SIGNATURE_LIST); 4821 return (NULL); 4822 } 4823 4824 for (i = 0; s_fgets(tmpsign, sizeof (tmpsign), tfp); i++) { 4825 4826 if (strncmp(tmpsign, GRUBSIGN_UFS_PREFIX, 4827 strlen(GRUBSIGN_UFS_PREFIX)) != 0) { 4828 (void) fclose(tfp); 4829 (void) unlink(UFS_SIGNATURE_LIST); 4830 bam_error(UFS_BADSIGN, tmpsign); 4831 return (NULL); 4832 } 4833 numstr = tmpsign + strlen(GRUBSIGN_UFS_PREFIX); 4834 4835 if (numstr[0] == '\0' || !isdigit(numstr[0])) { 4836 (void) fclose(tfp); 4837 (void) unlink(UFS_SIGNATURE_LIST); 4838 bam_error(UFS_BADSIGN, tmpsign); 4839 return (NULL); 4840 } 4841 4842 signnum = atoi(numstr); 4843 INJECT_ERROR1("NEGATIVE_SIGN", signnum = -1); 4844 if (signnum < 0) { 4845 (void) fclose(tfp); 4846 (void) unlink(UFS_SIGNATURE_LIST); 4847 bam_error(UFS_BADSIGN, tmpsign); 4848 return (NULL); 4849 } 4850 4851 if (i != signnum) { 4852 BAM_DPRINTF((D_FOUND_HOLE_SIGNLIST, fcn, i)); 4853 break; 4854 } 4855 } 4856 4857 (void) fclose(tfp); 4858 4859 found: 4860 (void) snprintf(tmpsign, sizeof (tmpsign), "rootfs%d", i); 4861 4862 /* add the ufs signature to the /var/run list of signatures */ 4863 ret = ufs_add_to_sign_list(tmpsign); 4864 INJECT_ERROR1("UFS_ADD_TO_SIGN_LIST", ret = -1); 4865 if (ret == -1) { 4866 (void) unlink(UFS_SIGNATURE_LIST); 4867 bam_error(FAILED_ADD_SIGNLIST, tmpsign); 4868 return (NULL); 4869 } 4870 4871 BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 4872 4873 return (s_strdup(tmpsign)); 4874 } 4875 4876 static char * 4877 get_fstype(char *osroot) 4878 { 4879 FILE *mntfp; 4880 struct mnttab mp = {0}; 4881 struct mnttab mpref = {0}; 4882 int error; 4883 int ret; 4884 const char *fcn = "get_fstype()"; 4885 4886 INJECT_ERROR1("GET_FSTYPE_OSROOT", osroot = NULL); 4887 if (osroot == NULL) { 4888 bam_error(GET_FSTYPE_ARGS); 4889 return (NULL); 4890 } 4891 4892 mntfp = fopen(MNTTAB, "r"); 4893 error = errno; 4894 INJECT_ERROR1("GET_FSTYPE_FOPEN", mntfp = NULL); 4895 if (mntfp == NULL) { 4896 bam_error(OPEN_FAIL, MNTTAB, strerror(error)); 4897 return (NULL); 4898 } 4899 4900 if (*osroot == '\0') 4901 mpref.mnt_mountp = "/"; 4902 else 4903 mpref.mnt_mountp = osroot; 4904 4905 ret = getmntany(mntfp, &mp, &mpref); 4906 INJECT_ERROR1("GET_FSTYPE_GETMNTANY", ret = 1); 4907 if (ret != 0) { 4908 bam_error(MNTTAB_MNTPT_NOT_FOUND, osroot, MNTTAB); 4909 (void) fclose(mntfp); 4910 return (NULL); 4911 } 4912 (void) fclose(mntfp); 4913 4914 INJECT_ERROR1("GET_FSTYPE_NULL", mp.mnt_fstype = NULL); 4915 if (mp.mnt_fstype == NULL) { 4916 bam_error(MNTTAB_FSTYPE_NULL, osroot); 4917 return (NULL); 4918 } 4919 4920 BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 4921 4922 return (s_strdup(mp.mnt_fstype)); 4923 } 4924 4925 static char * 4926 create_zfs_sign(char *osdev) 4927 { 4928 char tmpsign[PATH_MAX]; 4929 char *pool; 4930 const char *fcn = "create_zfs_sign()"; 4931 4932 BAM_DPRINTF((D_FUNC_ENTRY1, fcn, osdev)); 4933 4934 /* 4935 * First find the pool name 4936 */ 4937 pool = get_pool(osdev); 4938 INJECT_ERROR1("CREATE_ZFS_SIGN_GET_POOL", pool = NULL); 4939 if (pool == NULL) { 4940 bam_error(GET_POOL_FAILED, osdev); 4941 return (NULL); 4942 } 4943 4944 (void) snprintf(tmpsign, sizeof (tmpsign), "pool_%s", pool); 4945 4946 BAM_DPRINTF((D_CREATED_ZFS_SIGN, fcn, tmpsign)); 4947 4948 free(pool); 4949 4950 BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 4951 4952 return (s_strdup(tmpsign)); 4953 } 4954 4955 static char * 4956 create_new_sign(char *osdev, char *fstype) 4957 { 4958 char *sign; 4959 const char *fcn = "create_new_sign()"; 4960 4961 INJECT_ERROR1("NEW_SIGN_FSTYPE", fstype = "foofs"); 4962 4963 if (strcmp(fstype, "zfs") == 0) { 4964 BAM_DPRINTF((D_CREATE_NEW_ZFS, fcn)); 4965 sign = create_zfs_sign(osdev); 4966 } else if (strcmp(fstype, "ufs") == 0) { 4967 BAM_DPRINTF((D_CREATE_NEW_UFS, fcn)); 4968 sign = create_ufs_sign(); 4969 } else { 4970 bam_error(GRUBSIGN_NOTSUP, fstype); 4971 sign = NULL; 4972 } 4973 4974 BAM_DPRINTF((D_CREATED_NEW_SIGN, fcn, sign ? sign : "<NULL>")); 4975 return (sign); 4976 } 4977 4978 static int 4979 set_backup_common(char *mntpt, char *sign) 4980 { 4981 FILE *bfp; 4982 char backup[PATH_MAX]; 4983 char tmpsign[PATH_MAX]; 4984 int error; 4985 char *bdir; 4986 char *backup_dup; 4987 struct stat sb; 4988 int ret; 4989 const char *fcn = "set_backup_common()"; 4990 4991 (void) snprintf(backup, sizeof (backup), "%s%s", 4992 mntpt, GRUBSIGN_BACKUP); 4993 4994 /* First read the backup */ 4995 bfp = fopen(backup, "r"); 4996 if (bfp != NULL) { 4997 while (s_fgets(tmpsign, sizeof (tmpsign), bfp)) { 4998 if (strcmp(tmpsign, sign) == 0) { 4999 BAM_DPRINTF((D_FOUND_IN_BACKUP, fcn, sign)); 5000 (void) fclose(bfp); 5001 return (0); 5002 } 5003 } 5004 (void) fclose(bfp); 5005 BAM_DPRINTF((D_NOT_FOUND_IN_EXIST_BACKUP, fcn, sign)); 5006 } else { 5007 BAM_DPRINTF((D_BACKUP_NOT_EXIST, fcn, backup)); 5008 } 5009 5010 /* 5011 * Didn't find the correct signature. First create 5012 * the directory if necessary. 5013 */ 5014 5015 /* dirname() modifies its argument so dup it */ 5016 backup_dup = s_strdup(backup); 5017 bdir = dirname(backup_dup); 5018 assert(bdir); 5019 5020 ret = stat(bdir, &sb); 5021 INJECT_ERROR1("SET_BACKUP_STAT", ret = -1); 5022 if (ret == -1) { 5023 BAM_DPRINTF((D_BACKUP_DIR_NOEXIST, fcn, bdir)); 5024 ret = mkdirp(bdir, 0755); 5025 error = errno; 5026 INJECT_ERROR1("SET_BACKUP_MKDIRP", ret = -1); 5027 if (ret == -1) { 5028 bam_error(GRUBSIGN_BACKUP_MKDIRERR, 5029 GRUBSIGN_BACKUP, strerror(error)); 5030 free(backup_dup); 5031 return (-1); 5032 } 5033 } 5034 free(backup_dup); 5035 5036 /* 5037 * Open the backup in append mode to add the correct 5038 * signature; 5039 */ 5040 bfp = fopen(backup, "a"); 5041 error = errno; 5042 INJECT_ERROR1("SET_BACKUP_FOPEN_A", bfp = NULL); 5043 if (bfp == NULL) { 5044 bam_error(GRUBSIGN_BACKUP_OPENERR, 5045 GRUBSIGN_BACKUP, strerror(error)); 5046 return (-1); 5047 } 5048 5049 (void) snprintf(tmpsign, sizeof (tmpsign), "%s\n", sign); 5050 5051 ret = fputs(tmpsign, bfp); 5052 error = errno; 5053 INJECT_ERROR1("SET_BACKUP_FPUTS", ret = 0); 5054 if (ret != strlen(tmpsign)) { 5055 bam_error(GRUBSIGN_BACKUP_WRITEERR, 5056 GRUBSIGN_BACKUP, strerror(error)); 5057 (void) fclose(bfp); 5058 return (-1); 5059 } 5060 5061 (void) fclose(bfp); 5062 5063 if (bam_verbose) 5064 bam_print(GRUBSIGN_BACKUP_UPDATED, GRUBSIGN_BACKUP); 5065 5066 BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 5067 5068 return (0); 5069 } 5070 5071 static int 5072 set_backup_ufs(char *osroot, char *sign) 5073 { 5074 const char *fcn = "set_backup_ufs()"; 5075 5076 BAM_DPRINTF((D_FUNC_ENTRY2, fcn, osroot, sign)); 5077 return (set_backup_common(osroot, sign)); 5078 } 5079 5080 static int 5081 set_backup_zfs(char *osdev, char *sign) 5082 { 5083 char *pool; 5084 char *mntpt; 5085 zfs_mnted_t mnted; 5086 int ret; 5087 const char *fcn = "set_backup_zfs()"; 5088 5089 BAM_DPRINTF((D_FUNC_ENTRY2, fcn, osdev, sign)); 5090 5091 pool = get_pool(osdev); 5092 INJECT_ERROR1("SET_BACKUP_GET_POOL", pool = NULL); 5093 if (pool == NULL) { 5094 bam_error(GET_POOL_FAILED, osdev); 5095 return (-1); 5096 } 5097 5098 mntpt = mount_top_dataset(pool, &mnted); 5099 INJECT_ERROR1("SET_BACKUP_MOUNT_DATASET", mntpt = NULL); 5100 if (mntpt == NULL) { 5101 bam_error(FAIL_MNT_TOP_DATASET, pool); 5102 free(pool); 5103 return (-1); 5104 } 5105 5106 ret = set_backup_common(mntpt, sign); 5107 5108 (void) umount_top_dataset(pool, mnted, mntpt); 5109 5110 free(pool); 5111 5112 INJECT_ERROR1("SET_BACKUP_ZFS_FAIL", ret = 1); 5113 if (ret == 0) { 5114 BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 5115 } else { 5116 BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 5117 } 5118 5119 return (ret); 5120 } 5121 5122 static int 5123 set_backup(char *osroot, char *osdev, char *sign, char *fstype) 5124 { 5125 const char *fcn = "set_backup()"; 5126 int ret; 5127 5128 INJECT_ERROR1("SET_BACKUP_FSTYPE", fstype = "foofs"); 5129 5130 if (strcmp(fstype, "ufs") == 0) { 5131 BAM_DPRINTF((D_SET_BACKUP_UFS, fcn)); 5132 ret = set_backup_ufs(osroot, sign); 5133 } else if (strcmp(fstype, "zfs") == 0) { 5134 BAM_DPRINTF((D_SET_BACKUP_ZFS, fcn)); 5135 ret = set_backup_zfs(osdev, sign); 5136 } else { 5137 bam_error(GRUBSIGN_NOTSUP, fstype); 5138 ret = -1; 5139 } 5140 5141 if (ret == 0) { 5142 BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 5143 } else { 5144 BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 5145 } 5146 5147 return (ret); 5148 } 5149 5150 static int 5151 set_primary_common(char *mntpt, char *sign) 5152 { 5153 char signfile[PATH_MAX]; 5154 char signdir[PATH_MAX]; 5155 struct stat sb; 5156 int fd; 5157 int error; 5158 int ret; 5159 const char *fcn = "set_primary_common()"; 5160 5161 (void) snprintf(signfile, sizeof (signfile), "%s/%s/%s", 5162 mntpt, GRUBSIGN_DIR, sign); 5163 5164 if (stat(signfile, &sb) != -1) { 5165 if (bam_verbose) 5166 bam_print(PRIMARY_SIGN_EXISTS, sign); 5167 return (0); 5168 } else { 5169 BAM_DPRINTF((D_PRIMARY_NOT_EXIST, fcn, signfile)); 5170 } 5171 5172 (void) snprintf(signdir, sizeof (signdir), "%s/%s", 5173 mntpt, GRUBSIGN_DIR); 5174 5175 if (stat(signdir, &sb) == -1) { 5176 BAM_DPRINTF((D_PRIMARY_DIR_NOEXIST, fcn, signdir)); 5177 ret = mkdirp(signdir, 0755); 5178 error = errno; 5179 INJECT_ERROR1("SET_PRIMARY_MKDIRP", ret = -1); 5180 if (ret == -1) { 5181 bam_error(GRUBSIGN_MKDIR_ERR, signdir, strerror(errno)); 5182 return (-1); 5183 } 5184 } 5185 5186 fd = open(signfile, O_RDWR|O_CREAT|O_TRUNC, 0444); 5187 error = errno; 5188 INJECT_ERROR1("PRIMARY_SIGN_CREAT", fd = -1); 5189 if (fd == -1) { 5190 bam_error(GRUBSIGN_PRIMARY_CREATERR, signfile, strerror(error)); 5191 return (-1); 5192 } 5193 5194 ret = fsync(fd); 5195 error = errno; 5196 INJECT_ERROR1("PRIMARY_FSYNC", ret = -1); 5197 if (ret != 0) { 5198 bam_error(GRUBSIGN_PRIMARY_SYNCERR, signfile, strerror(error)); 5199 } 5200 5201 (void) close(fd); 5202 5203 if (bam_verbose) 5204 bam_print(GRUBSIGN_CREATED_PRIMARY, signfile); 5205 5206 BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 5207 5208 return (0); 5209 } 5210 5211 static int 5212 set_primary_ufs(char *osroot, char *sign) 5213 { 5214 const char *fcn = "set_primary_ufs()"; 5215 5216 BAM_DPRINTF((D_FUNC_ENTRY2, fcn, osroot, sign)); 5217 return (set_primary_common(osroot, sign)); 5218 } 5219 5220 static int 5221 set_primary_zfs(char *osdev, char *sign) 5222 { 5223 char *pool; 5224 char *mntpt; 5225 zfs_mnted_t mnted; 5226 int ret; 5227 const char *fcn = "set_primary_zfs()"; 5228 5229 BAM_DPRINTF((D_FUNC_ENTRY2, fcn, osdev, sign)); 5230 5231 pool = get_pool(osdev); 5232 INJECT_ERROR1("SET_PRIMARY_ZFS_GET_POOL", pool = NULL); 5233 if (pool == NULL) { 5234 bam_error(GET_POOL_FAILED, osdev); 5235 return (-1); 5236 } 5237 5238 /* Pool name must exist in the sign */ 5239 ret = (strstr(sign, pool) != NULL); 5240 INJECT_ERROR1("SET_PRIMARY_ZFS_POOL_SIGN_INCOMPAT", ret = 0); 5241 if (ret == 0) { 5242 bam_error(POOL_SIGN_INCOMPAT, pool, sign); 5243 free(pool); 5244 return (-1); 5245 } 5246 5247 mntpt = mount_top_dataset(pool, &mnted); 5248 INJECT_ERROR1("SET_PRIMARY_ZFS_MOUNT_DATASET", mntpt = NULL); 5249 if (mntpt == NULL) { 5250 bam_error(FAIL_MNT_TOP_DATASET, pool); 5251 free(pool); 5252 return (-1); 5253 } 5254 5255 ret = set_primary_common(mntpt, sign); 5256 5257 (void) umount_top_dataset(pool, mnted, mntpt); 5258 5259 free(pool); 5260 5261 INJECT_ERROR1("SET_PRIMARY_ZFS_FAIL", ret = 1); 5262 if (ret == 0) { 5263 BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 5264 } else { 5265 BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 5266 } 5267 5268 return (ret); 5269 } 5270 5271 static int 5272 set_primary(char *osroot, char *osdev, char *sign, char *fstype) 5273 { 5274 const char *fcn = "set_primary()"; 5275 int ret; 5276 5277 INJECT_ERROR1("SET_PRIMARY_FSTYPE", fstype = "foofs"); 5278 if (strcmp(fstype, "ufs") == 0) { 5279 BAM_DPRINTF((D_SET_PRIMARY_UFS, fcn)); 5280 ret = set_primary_ufs(osroot, sign); 5281 } else if (strcmp(fstype, "zfs") == 0) { 5282 BAM_DPRINTF((D_SET_PRIMARY_ZFS, fcn)); 5283 ret = set_primary_zfs(osdev, sign); 5284 } else { 5285 bam_error(GRUBSIGN_NOTSUP, fstype); 5286 ret = -1; 5287 } 5288 5289 if (ret == 0) { 5290 BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 5291 } else { 5292 BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 5293 } 5294 5295 return (ret); 5296 } 5297 5298 static int 5299 ufs_add_to_sign_list(char *sign) 5300 { 5301 FILE *tfp; 5302 char signline[MAXNAMELEN]; 5303 char cmd[PATH_MAX]; 5304 int ret; 5305 int error; 5306 const char *fcn = "ufs_add_to_sign_list()"; 5307 5308 INJECT_ERROR1("ADD_TO_SIGN_LIST_NOT_UFS", sign = "pool_rpool5"); 5309 if (strncmp(sign, GRUBSIGN_UFS_PREFIX, 5310 strlen(GRUBSIGN_UFS_PREFIX)) != 0) { 5311 bam_error(INVALID_UFS_SIGN, sign); 5312 (void) unlink(UFS_SIGNATURE_LIST); 5313 return (-1); 5314 } 5315 5316 /* 5317 * most failures in this routine are not a fatal error 5318 * We simply unlink the /var/run file and continue 5319 */ 5320 5321 ret = rename(UFS_SIGNATURE_LIST, UFS_SIGNATURE_LIST".tmp"); 5322 error = errno; 5323 INJECT_ERROR1("ADD_TO_SIGN_LIST_RENAME", ret = -1); 5324 if (ret == -1) { 5325 bam_error(RENAME_FAIL, UFS_SIGNATURE_LIST".tmp", 5326 strerror(error)); 5327 (void) unlink(UFS_SIGNATURE_LIST); 5328 return (0); 5329 } 5330 5331 tfp = fopen(UFS_SIGNATURE_LIST".tmp", "a"); 5332 error = errno; 5333 INJECT_ERROR1("ADD_TO_SIGN_LIST_FOPEN", tfp = NULL); 5334 if (tfp == NULL) { 5335 bam_error(OPEN_FAIL, UFS_SIGNATURE_LIST".tmp", strerror(error)); 5336 (void) unlink(UFS_SIGNATURE_LIST".tmp"); 5337 return (0); 5338 } 5339 5340 (void) snprintf(signline, sizeof (signline), "%s\n", sign); 5341 5342 ret = fputs(signline, tfp); 5343 error = errno; 5344 INJECT_ERROR1("ADD_TO_SIGN_LIST_FPUTS", ret = 0); 5345 if (ret != strlen(signline)) { 5346 bam_error(SIGN_LIST_FPUTS_ERR, sign, strerror(error)); 5347 (void) fclose(tfp); 5348 (void) unlink(UFS_SIGNATURE_LIST".tmp"); 5349 return (0); 5350 } 5351 5352 ret = fclose(tfp); 5353 error = errno; 5354 INJECT_ERROR1("ADD_TO_SIGN_LIST_FCLOSE", ret = EOF); 5355 if (ret == EOF) { 5356 bam_error(CLOSE_FAIL, UFS_SIGNATURE_LIST".tmp", 5357 strerror(error)); 5358 (void) unlink(UFS_SIGNATURE_LIST".tmp"); 5359 return (0); 5360 } 5361 5362 /* Sort the list again */ 5363 (void) snprintf(cmd, sizeof (cmd), 5364 "/usr/bin/sort -u %s.tmp > %s.sorted", 5365 UFS_SIGNATURE_LIST, UFS_SIGNATURE_LIST); 5366 5367 ret = exec_cmd(cmd, NULL); 5368 INJECT_ERROR1("ADD_TO_SIGN_LIST_SORT", ret = 1); 5369 if (ret != 0) { 5370 bam_error(GRUBSIGN_SORT_FAILED); 5371 (void) unlink(UFS_SIGNATURE_LIST".sorted"); 5372 (void) unlink(UFS_SIGNATURE_LIST".tmp"); 5373 return (0); 5374 } 5375 5376 (void) unlink(UFS_SIGNATURE_LIST".tmp"); 5377 5378 ret = rename(UFS_SIGNATURE_LIST".sorted", UFS_SIGNATURE_LIST); 5379 error = errno; 5380 INJECT_ERROR1("ADD_TO_SIGN_LIST_RENAME2", ret = -1); 5381 if (ret == -1) { 5382 bam_error(RENAME_FAIL, UFS_SIGNATURE_LIST, strerror(error)); 5383 (void) unlink(UFS_SIGNATURE_LIST".sorted"); 5384 return (0); 5385 } 5386 5387 BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 5388 5389 return (0); 5390 } 5391 5392 static int 5393 set_signature(char *osroot, char *osdev, char *sign, char *fstype) 5394 { 5395 int ret; 5396 const char *fcn = "set_signature()"; 5397 5398 BAM_DPRINTF((D_FUNC_ENTRY4, fcn, osroot, osdev, sign, fstype)); 5399 5400 ret = set_backup(osroot, osdev, sign, fstype); 5401 INJECT_ERROR1("SET_SIGNATURE_BACKUP", ret = -1); 5402 if (ret == -1) { 5403 BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 5404 bam_error(SET_BACKUP_FAILED, sign, osroot, osdev); 5405 return (-1); 5406 } 5407 5408 ret = set_primary(osroot, osdev, sign, fstype); 5409 INJECT_ERROR1("SET_SIGNATURE_PRIMARY", ret = -1); 5410 5411 if (ret == 0) { 5412 BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 5413 } else { 5414 BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 5415 bam_error(SET_PRIMARY_FAILED, sign, osroot, osdev); 5416 5417 } 5418 return (ret); 5419 } 5420 5421 char * 5422 get_grubsign(char *osroot, char *osdev) 5423 { 5424 char *grubsign; /* (<sign>,#,#) */ 5425 char *slice; 5426 int fdiskpart; 5427 char *sign; 5428 char *fstype; 5429 int ret; 5430 const char *fcn = "get_grubsign()"; 5431 5432 BAM_DPRINTF((D_FUNC_ENTRY2, fcn, osroot, osdev)); 5433 5434 fstype = get_fstype(osroot); 5435 INJECT_ERROR1("GET_GRUBSIGN_FSTYPE", fstype = NULL); 5436 if (fstype == NULL) { 5437 bam_error(GET_FSTYPE_FAILED, osroot); 5438 return (NULL); 5439 } 5440 5441 sign = find_existing_sign(osroot, osdev, fstype); 5442 INJECT_ERROR1("FIND_EXISTING_SIGN", sign = NULL); 5443 if (sign == NULL) { 5444 BAM_DPRINTF((D_GET_GRUBSIGN_NO_EXISTING, fcn, osroot, osdev)); 5445 sign = create_new_sign(osdev, fstype); 5446 INJECT_ERROR1("CREATE_NEW_SIGN", sign = NULL); 5447 if (sign == NULL) { 5448 bam_error(GRUBSIGN_CREATE_FAIL, osdev); 5449 free(fstype); 5450 return (NULL); 5451 } 5452 } 5453 5454 ret = set_signature(osroot, osdev, sign, fstype); 5455 INJECT_ERROR1("SET_SIGNATURE_FAIL", ret = -1); 5456 if (ret == -1) { 5457 bam_error(GRUBSIGN_WRITE_FAIL, osdev); 5458 free(sign); 5459 free(fstype); 5460 (void) unlink(UFS_SIGNATURE_LIST); 5461 return (NULL); 5462 } 5463 5464 free(fstype); 5465 5466 if (bam_verbose) 5467 bam_print(GRUBSIGN_FOUND_OR_CREATED, sign, osdev); 5468 5469 fdiskpart = get_partition(osdev); 5470 INJECT_ERROR1("GET_GRUBSIGN_FDISK", fdiskpart = -1); 5471 if (fdiskpart == -1) { 5472 bam_error(FDISKPART_FAIL, osdev); 5473 free(sign); 5474 return (NULL); 5475 } 5476 5477 slice = strrchr(osdev, 's'); 5478 5479 grubsign = s_calloc(1, MAXNAMELEN + 10); 5480 if (slice) { 5481 (void) snprintf(grubsign, MAXNAMELEN + 10, "(%s,%d,%c)", 5482 sign, fdiskpart, slice[1] + 'a' - '0'); 5483 } else 5484 (void) snprintf(grubsign, MAXNAMELEN + 10, "(%s,%d)", 5485 sign, fdiskpart); 5486 5487 free(sign); 5488 5489 BAM_DPRINTF((D_GET_GRUBSIGN_SUCCESS, fcn, grubsign)); 5490 5491 return (grubsign); 5492 } 5493 5494 static char * 5495 get_title(char *rootdir) 5496 { 5497 static char title[80]; 5498 char *cp = NULL; 5499 char release[PATH_MAX]; 5500 FILE *fp; 5501 const char *fcn = "get_title()"; 5502 5503 /* open the /etc/release file */ 5504 (void) snprintf(release, sizeof (release), "%s/etc/release", rootdir); 5505 5506 fp = fopen(release, "r"); 5507 if (fp == NULL) { 5508 bam_error(OPEN_FAIL, release, strerror(errno)); 5509 cp = NULL; 5510 goto out; 5511 } 5512 5513 while (s_fgets(title, sizeof (title), fp) != NULL) { 5514 cp = strstr(title, "Solaris"); 5515 if (cp) 5516 break; 5517 } 5518 (void) fclose(fp); 5519 5520 out: 5521 cp = cp ? cp : "Solaris"; 5522 5523 BAM_DPRINTF((D_GET_TITLE, fcn, cp)); 5524 5525 return (cp); 5526 } 5527 5528 char * 5529 get_special(char *mountp) 5530 { 5531 FILE *mntfp; 5532 struct mnttab mp = {0}; 5533 struct mnttab mpref = {0}; 5534 int error; 5535 int ret; 5536 const char *fcn = "get_special()"; 5537 5538 INJECT_ERROR1("GET_SPECIAL_MNTPT", mountp = NULL); 5539 if (mountp == NULL) { 5540 bam_error(GET_SPECIAL_NULL_MNTPT); 5541 return (NULL); 5542 } 5543 5544 mntfp = fopen(MNTTAB, "r"); 5545 error = errno; 5546 INJECT_ERROR1("GET_SPECIAL_MNTTAB_OPEN", mntfp = NULL); 5547 if (mntfp == NULL) { 5548 bam_error(OPEN_FAIL, MNTTAB, strerror(error)); 5549 return (NULL); 5550 } 5551 5552 if (*mountp == '\0') 5553 mpref.mnt_mountp = "/"; 5554 else 5555 mpref.mnt_mountp = mountp; 5556 5557 ret = getmntany(mntfp, &mp, &mpref); 5558 INJECT_ERROR1("GET_SPECIAL_MNTTAB_SEARCH", ret = 1); 5559 if (ret != 0) { 5560 (void) fclose(mntfp); 5561 BAM_DPRINTF((D_GET_SPECIAL_NOT_IN_MNTTAB, fcn, mountp)); 5562 return (NULL); 5563 } 5564 (void) fclose(mntfp); 5565 5566 BAM_DPRINTF((D_GET_SPECIAL, fcn, mp.mnt_special)); 5567 5568 return (s_strdup(mp.mnt_special)); 5569 } 5570 5571 static void 5572 free_physarray(char **physarray, int n) 5573 { 5574 int i; 5575 const char *fcn = "free_physarray()"; 5576 5577 assert(physarray); 5578 assert(n); 5579 5580 BAM_DPRINTF((D_FUNC_ENTRY_N1, fcn, n)); 5581 5582 for (i = 0; i < n; i++) { 5583 free(physarray[i]); 5584 } 5585 free(physarray); 5586 5587 BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 5588 } 5589 5590 static int 5591 zfs_get_physical(char *special, char ***physarray, int *n) 5592 { 5593 char sdup[PATH_MAX]; 5594 char cmd[PATH_MAX]; 5595 char dsk[PATH_MAX]; 5596 char *pool; 5597 filelist_t flist = {0}; 5598 line_t *lp; 5599 line_t *startlp; 5600 char *comp1; 5601 int i; 5602 int ret; 5603 const char *fcn = "zfs_get_physical()"; 5604 5605 assert(special); 5606 5607 BAM_DPRINTF((D_FUNC_ENTRY1, fcn, special)); 5608 5609 INJECT_ERROR1("INVALID_ZFS_SPECIAL", special = "/foo"); 5610 if (special[0] == '/') { 5611 bam_error(INVALID_ZFS_SPECIAL, special); 5612 return (-1); 5613 } 5614 5615 (void) strlcpy(sdup, special, sizeof (sdup)); 5616 5617 pool = strtok(sdup, "/"); 5618 INJECT_ERROR1("ZFS_GET_PHYS_POOL", pool = NULL); 5619 if (pool == NULL) { 5620 bam_error(CANT_FIND_POOL_FROM_SPECIAL, special); 5621 return (-1); 5622 } 5623 5624 (void) snprintf(cmd, sizeof (cmd), "/sbin/zpool status %s", pool); 5625 5626 ret = exec_cmd(cmd, &flist); 5627 INJECT_ERROR1("ZFS_GET_PHYS_STATUS", ret = 1); 5628 if (ret != 0) { 5629 bam_error(ZFS_GET_POOL_STATUS, pool); 5630 return (-1); 5631 } 5632 5633 INJECT_ERROR1("ZFS_GET_PHYS_STATUS_OUT", flist.head = NULL); 5634 if (flist.head == NULL) { 5635 bam_error(BAD_ZPOOL_STATUS, pool); 5636 filelist_free(&flist); 5637 return (-1); 5638 } 5639 5640 for (lp = flist.head; lp; lp = lp->next) { 5641 BAM_DPRINTF((D_STRTOK_ZPOOL_STATUS, fcn, lp->line)); 5642 comp1 = strtok(lp->line, " \t"); 5643 if (comp1 == NULL) { 5644 free(lp->line); 5645 lp->line = NULL; 5646 } else { 5647 comp1 = s_strdup(comp1); 5648 free(lp->line); 5649 lp->line = comp1; 5650 } 5651 } 5652 5653 for (lp = flist.head; lp; lp = lp->next) { 5654 if (lp->line == NULL) 5655 continue; 5656 if (strcmp(lp->line, pool) == 0) { 5657 BAM_DPRINTF((D_FOUND_POOL_IN_ZPOOL_STATUS, fcn, pool)); 5658 break; 5659 } 5660 } 5661 5662 if (lp == NULL) { 5663 bam_error(NO_POOL_IN_ZPOOL_STATUS, pool); 5664 filelist_free(&flist); 5665 return (-1); 5666 } 5667 5668 startlp = lp->next; 5669 for (i = 0, lp = startlp; lp; lp = lp->next) { 5670 if (lp->line == NULL) 5671 continue; 5672 if (strcmp(lp->line, "mirror") == 0) 5673 continue; 5674 if (lp->line[0] == '\0' || strcmp(lp->line, "errors:") == 0) 5675 break; 5676 i++; 5677 BAM_DPRINTF((D_COUNTING_ZFS_PHYS, fcn, i)); 5678 } 5679 5680 if (i == 0) { 5681 bam_error(NO_PHYS_IN_ZPOOL_STATUS, pool); 5682 filelist_free(&flist); 5683 return (-1); 5684 } 5685 5686 *n = i; 5687 *physarray = s_calloc(*n, sizeof (char *)); 5688 for (i = 0, lp = startlp; lp; lp = lp->next) { 5689 if (lp->line == NULL) 5690 continue; 5691 if (strcmp(lp->line, "mirror") == 0) 5692 continue; 5693 if (strcmp(lp->line, "errors:") == 0) 5694 break; 5695 if (strncmp(lp->line, "/dev/dsk/", strlen("/dev/dsk/")) != 0 && 5696 strncmp(lp->line, "/dev/rdsk/", 5697 strlen("/dev/rdsk/")) != 0) { 5698 (void) snprintf(dsk, sizeof (dsk), "/dev/dsk/%s", 5699 lp->line); 5700 } else { 5701 (void) strlcpy(dsk, lp->line, sizeof (dsk)); 5702 } 5703 BAM_DPRINTF((D_ADDING_ZFS_PHYS, fcn, dsk, pool)); 5704 (*physarray)[i++] = s_strdup(dsk); 5705 } 5706 5707 assert(i == *n); 5708 5709 filelist_free(&flist); 5710 5711 BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 5712 return (0); 5713 } 5714 5715 /* 5716 * Certain services needed to run metastat successfully may not 5717 * be enabled. Enable them now. 5718 */ 5719 /* 5720 * Checks if the specified service is online 5721 * Returns: 1 if the service is online 5722 * 0 if the service is not online 5723 * -1 on error 5724 */ 5725 static int 5726 is_svc_online(char *svc) 5727 { 5728 char *state; 5729 const char *fcn = "is_svc_online()"; 5730 5731 BAM_DPRINTF((D_FUNC_ENTRY1, fcn, svc)); 5732 5733 state = smf_get_state(svc); 5734 INJECT_ERROR2("GET_SVC_STATE", free(state), state = NULL); 5735 if (state == NULL) { 5736 bam_error(GET_SVC_STATE_ERR, svc); 5737 return (-1); 5738 } 5739 BAM_DPRINTF((D_GOT_SVC_STATUS, fcn, svc)); 5740 5741 if (strcmp(state, SCF_STATE_STRING_ONLINE) == 0) { 5742 BAM_DPRINTF((D_SVC_ONLINE, fcn, svc)); 5743 free(state); 5744 return (1); 5745 } 5746 5747 BAM_DPRINTF((D_SVC_NOT_ONLINE, fcn, state, svc)); 5748 5749 free(state); 5750 5751 return (0); 5752 } 5753 5754 static int 5755 enable_svc(char *svc) 5756 { 5757 int ret; 5758 int sleeptime; 5759 const char *fcn = "enable_svc()"; 5760 5761 ret = is_svc_online(svc); 5762 if (ret == -1) { 5763 bam_error(SVC_IS_ONLINE_FAILED, svc); 5764 return (-1); 5765 } else if (ret == 1) { 5766 BAM_DPRINTF((D_SVC_ALREADY_ONLINE, fcn, svc)); 5767 return (0); 5768 } 5769 5770 /* Service is not enabled. Enable it now. */ 5771 ret = smf_enable_instance(svc, 0); 5772 INJECT_ERROR1("ENABLE_SVC_FAILED", ret = -1); 5773 if (ret != 0) { 5774 bam_error(ENABLE_SVC_FAILED, svc); 5775 return (-1); 5776 } 5777 5778 BAM_DPRINTF((D_SVC_ONLINE_INITIATED, fcn, svc)); 5779 5780 sleeptime = 0; 5781 do { 5782 ret = is_svc_online(svc); 5783 INJECT_ERROR1("SVC_ONLINE_SUCCESS", ret = 1); 5784 INJECT_ERROR1("SVC_ONLINE_FAILURE", ret = -1); 5785 INJECT_ERROR1("SVC_ONLINE_NOTYET", ret = 0); 5786 if (ret == -1) { 5787 bam_error(ERR_SVC_GET_ONLINE, svc); 5788 return (-1); 5789 } else if (ret == 1) { 5790 BAM_DPRINTF((D_SVC_NOW_ONLINE, fcn, svc)); 5791 return (1); 5792 } 5793 (void) sleep(1); 5794 } while (sleeptime < 60); 5795 5796 bam_error(TIMEOUT_ENABLE_SVC, svc); 5797 5798 return (-1); 5799 } 5800 5801 static int 5802 ufs_get_physical(char *special, char ***physarray, int *n) 5803 { 5804 char cmd[PATH_MAX]; 5805 char *shortname; 5806 filelist_t flist = {0}; 5807 char *meta; 5808 char *type; 5809 char *comp1; 5810 char *comp2; 5811 char *comp3; 5812 char *comp4; 5813 int i; 5814 line_t *lp; 5815 int ret; 5816 char *svc; 5817 const char *fcn = "ufs_get_physical()"; 5818 5819 assert(special); 5820 5821 BAM_DPRINTF((D_FUNC_ENTRY1, fcn, special)); 5822 5823 if (strncmp(special, "/dev/md/", strlen("/dev/md/")) != 0) { 5824 bam_error(UFS_GET_PHYS_NOT_SVM, special); 5825 return (-1); 5826 } 5827 5828 if (strncmp(special, "/dev/md/dsk/", strlen("/dev/md/dsk/")) == 0) { 5829 shortname = special + strlen("/dev/md/dsk/"); 5830 } else if (strncmp(special, "/dev/md/rdsk/", 5831 strlen("/dev/md/rdsk/")) == 0) { 5832 shortname = special + strlen("/dev/md/rdsk"); 5833 } else { 5834 bam_error(UFS_GET_PHYS_INVALID_SVM, special); 5835 return (-1); 5836 } 5837 5838 BAM_DPRINTF((D_UFS_SVM_SHORT, fcn, special, shortname)); 5839 5840 svc = "network/rpc/meta:default"; 5841 if (enable_svc(svc) == -1) { 5842 bam_error(UFS_SVM_METASTAT_SVC_ERR, svc); 5843 } 5844 5845 (void) snprintf(cmd, sizeof (cmd), "/sbin/metastat -p %s", shortname); 5846 5847 ret = exec_cmd(cmd, &flist); 5848 INJECT_ERROR1("UFS_SVM_METASTAT", ret = 1); 5849 if (ret != 0) { 5850 bam_error(UFS_SVM_METASTAT_ERR, shortname); 5851 return (-1); 5852 } 5853 5854 INJECT_ERROR1("UFS_SVM_METASTAT_OUT", flist.head = NULL); 5855 if (flist.head == NULL) { 5856 bam_error(BAD_UFS_SVM_METASTAT, shortname); 5857 filelist_free(&flist); 5858 return (-1); 5859 } 5860 5861 /* 5862 * Check if not a mirror. We only parse a single metadevice 5863 * if not a mirror 5864 */ 5865 meta = strtok(flist.head->line, " \t"); 5866 type = strtok(NULL, " \t"); 5867 if (meta == NULL || type == NULL) { 5868 bam_error(ERROR_PARSE_UFS_SVM_METASTAT, shortname); 5869 filelist_free(&flist); 5870 return (-1); 5871 } 5872 if (strcmp(type, "-m") != 0) { 5873 comp1 = strtok(NULL, " \t"); 5874 comp2 = strtok(NULL, " \t"); 5875 if (comp1 == NULL || comp2 != NULL) { 5876 bam_error(INVALID_UFS_SVM_METASTAT, shortname); 5877 filelist_free(&flist); 5878 return (-1); 5879 } 5880 BAM_DPRINTF((D_UFS_SVM_ONE_COMP, fcn, comp1, shortname)); 5881 *physarray = s_calloc(1, sizeof (char *)); 5882 (*physarray)[0] = s_strdup(comp1); 5883 *n = 1; 5884 filelist_free(&flist); 5885 return (0); 5886 } 5887 5888 /* 5889 * Okay we have a mirror. Everything after the first line 5890 * is a submirror 5891 */ 5892 for (i = 0, lp = flist.head->next; lp; lp = lp->next) { 5893 if (strstr(lp->line, "/dev/dsk/") == NULL && 5894 strstr(lp->line, "/dev/rdsk/") == NULL) { 5895 bam_error(CANNOT_PARSE_UFS_SVM_METASTAT, shortname); 5896 filelist_free(&flist); 5897 return (-1); 5898 } 5899 i++; 5900 } 5901 5902 *physarray = s_calloc(i, sizeof (char *)); 5903 *n = i; 5904 5905 for (i = 0, lp = flist.head->next; lp; lp = lp->next) { 5906 comp1 = strtok(lp->line, " \t"); 5907 comp2 = strtok(NULL, " \t"); 5908 comp3 = strtok(NULL, " \t"); 5909 comp4 = strtok(NULL, " \t"); 5910 5911 if (comp3 == NULL || comp4 == NULL || 5912 (strncmp(comp4, "/dev/dsk/", strlen("/dev/dsk/")) != 0 && 5913 strncmp(comp4, "/dev/rdsk/", strlen("/dev/rdsk/")) != 0)) { 5914 bam_error(CANNOT_PARSE_UFS_SVM_SUBMIRROR, shortname); 5915 filelist_free(&flist); 5916 free_physarray(*physarray, *n); 5917 return (-1); 5918 } 5919 5920 (*physarray)[i++] = s_strdup(comp4); 5921 } 5922 5923 assert(i == *n); 5924 5925 filelist_free(&flist); 5926 5927 BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 5928 return (0); 5929 } 5930 5931 static int 5932 get_physical(char *menu_root, char ***physarray, int *n) 5933 { 5934 char *special; 5935 int ret; 5936 const char *fcn = "get_physical()"; 5937 5938 assert(menu_root); 5939 assert(physarray); 5940 assert(n); 5941 5942 *physarray = NULL; 5943 *n = 0; 5944 5945 BAM_DPRINTF((D_FUNC_ENTRY1, fcn, menu_root)); 5946 5947 /* First get the device special file from /etc/mnttab */ 5948 special = get_special(menu_root); 5949 INJECT_ERROR1("GET_PHYSICAL_SPECIAL", special = NULL); 5950 if (special == NULL) { 5951 bam_error(GET_SPECIAL_NULL, menu_root); 5952 return (-1); 5953 } 5954 5955 /* If already a physical device nothing to do */ 5956 if (strncmp(special, "/dev/dsk/", strlen("/dev/dsk/")) == 0 || 5957 strncmp(special, "/dev/rdsk/", strlen("/dev/rdsk/")) == 0) { 5958 BAM_DPRINTF((D_GET_PHYSICAL_ALREADY, fcn, menu_root, special)); 5959 BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 5960 *physarray = s_calloc(1, sizeof (char *)); 5961 (*physarray)[0] = special; 5962 *n = 1; 5963 return (0); 5964 } 5965 5966 if (is_zfs(menu_root)) { 5967 ret = zfs_get_physical(special, physarray, n); 5968 } else if (is_ufs(menu_root)) { 5969 ret = ufs_get_physical(special, physarray, n); 5970 } else { 5971 bam_error(GET_PHYSICAL_NOTSUP_FSTYPE, menu_root, special); 5972 ret = -1; 5973 } 5974 5975 free(special); 5976 5977 INJECT_ERROR1("GET_PHYSICAL_RET", ret = -1); 5978 if (ret == -1) { 5979 BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 5980 } else { 5981 int i; 5982 assert (*n > 0); 5983 for (i = 0; i < *n; i++) { 5984 BAM_DPRINTF((D_GET_PHYSICAL_RET, fcn, (*physarray)[i])); 5985 } 5986 } 5987 5988 return (ret); 5989 } 5990 5991 static int 5992 is_bootdisk(char *osroot, char *physical) 5993 { 5994 int ret; 5995 char *grubroot; 5996 char *bootp; 5997 const char *fcn = "is_bootdisk()"; 5998 5999 assert(osroot); 6000 assert(physical); 6001 6002 BAM_DPRINTF((D_FUNC_ENTRY2, fcn, osroot, physical)); 6003 6004 bootp = strstr(physical, "p0:boot"); 6005 if (bootp) 6006 *bootp = '\0'; 6007 /* 6008 * We just want the BIOS mapping for menu disk. 6009 * Don't pass menu_root to get_grubroot() as the 6010 * check that it is used for is not relevant here. 6011 * The osroot is immaterial as well - it is only used to 6012 * to find create_diskmap script. Everything hinges on 6013 * "physical" 6014 */ 6015 grubroot = get_grubroot(osroot, physical, NULL); 6016 6017 INJECT_ERROR1("IS_BOOTDISK_GRUBROOT", grubroot = NULL); 6018 if (grubroot == NULL) { 6019 if (bam_verbose) 6020 bam_error(NO_GRUBROOT_FOR_DISK, physical); 6021 return (0); 6022 } 6023 ret = grubroot[3] == '0'; 6024 free(grubroot); 6025 6026 BAM_DPRINTF((D_RETURN_RET, fcn, ret)); 6027 6028 return (ret); 6029 } 6030 6031 /* 6032 * Check if menu is on the boot device 6033 * Return 0 (false) on error 6034 */ 6035 static int 6036 menu_on_bootdisk(char *osroot, char *menu_root) 6037 { 6038 char **physarray; 6039 int ret; 6040 int n; 6041 int i; 6042 int on_bootdisk; 6043 const char *fcn = "menu_on_bootdisk()"; 6044 6045 BAM_DPRINTF((D_FUNC_ENTRY2, fcn, osroot, menu_root)); 6046 6047 ret = get_physical(menu_root, &physarray, &n); 6048 INJECT_ERROR1("MENU_ON_BOOTDISK_PHYSICAL", ret = -1); 6049 if (ret != 0) { 6050 bam_error(GET_PHYSICAL_MENU_NULL, menu_root); 6051 return (0); 6052 } 6053 6054 assert(physarray); 6055 assert(n > 0); 6056 6057 on_bootdisk = 0; 6058 for (i = 0; i < n; i++) { 6059 assert(strncmp(physarray[i], "/dev/dsk/", 6060 strlen("/dev/dsk/")) == 0 || 6061 strncmp(physarray[i], "/dev/rdsk/", 6062 strlen("/dev/rdsk/")) == 0); 6063 6064 BAM_DPRINTF((D_CHECK_ON_BOOTDISK, fcn, physarray[i])); 6065 if (is_bootdisk(osroot, physarray[i])) { 6066 on_bootdisk = 1; 6067 BAM_DPRINTF((D_IS_ON_BOOTDISK, fcn, physarray[i])); 6068 } 6069 } 6070 6071 free_physarray(physarray, n); 6072 6073 INJECT_ERROR1("ON_BOOTDISK_YES", on_bootdisk = 1); 6074 INJECT_ERROR1("ON_BOOTDISK_NO", on_bootdisk = 0); 6075 if (on_bootdisk) { 6076 BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 6077 } else { 6078 BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 6079 } 6080 6081 return (on_bootdisk); 6082 } 6083 6084 void 6085 bam_add_line(menu_t *mp, entry_t *entry, line_t *prev, line_t *lp) 6086 { 6087 const char *fcn = "bam_add_line()"; 6088 6089 assert(mp); 6090 assert(entry); 6091 assert(prev); 6092 assert(lp); 6093 6094 lp->next = prev->next; 6095 if (prev->next) { 6096 BAM_DPRINTF((D_ADD_LINE_PREV_NEXT, fcn)); 6097 prev->next->prev = lp; 6098 } else { 6099 BAM_DPRINTF((D_ADD_LINE_NOT_PREV_NEXT, fcn)); 6100 } 6101 prev->next = lp; 6102 lp->prev = prev; 6103 6104 if (entry->end == prev) { 6105 BAM_DPRINTF((D_ADD_LINE_LAST_LINE_IN_ENTRY, fcn)); 6106 entry->end = lp; 6107 } 6108 if (mp->end == prev) { 6109 assert(lp->next == NULL); 6110 mp->end = lp; 6111 BAM_DPRINTF((D_ADD_LINE_LAST_LINE_IN_MENU, fcn)); 6112 } 6113 } 6114 6115 /* 6116 * look for matching bootadm entry with specified parameters 6117 * Here are the rules (based on existing usage): 6118 * - If title is specified, match on title only 6119 * - Else, match on root/findroot, kernel, and module. 6120 * Note that, if root_opt is non-zero, the absence of 6121 * root line is considered a match. 6122 */ 6123 static entry_t * 6124 find_boot_entry( 6125 menu_t *mp, 6126 char *title, 6127 char *kernel, 6128 char *findroot, 6129 char *root, 6130 char *module, 6131 int root_opt, 6132 int *entry_num) 6133 { 6134 int i; 6135 line_t *lp; 6136 entry_t *ent; 6137 const char *fcn = "find_boot_entry()"; 6138 6139 if (entry_num) 6140 *entry_num = BAM_ERROR; 6141 6142 /* find matching entry */ 6143 for (i = 0, ent = mp->entries; ent; i++, ent = ent->next) { 6144 lp = ent->start; 6145 6146 /* first line of entry must be bootadm comment */ 6147 lp = ent->start; 6148 if (lp->flags != BAM_COMMENT || 6149 strcmp(lp->arg, BAM_BOOTADM_HDR) != 0) { 6150 continue; 6151 } 6152 6153 /* advance to title line */ 6154 lp = lp->next; 6155 if (title) { 6156 if (lp->flags == BAM_TITLE && lp->arg && 6157 strcmp(lp->arg, title) == 0) { 6158 BAM_DPRINTF((D_MATCHED_TITLE, fcn, title)); 6159 break; 6160 } 6161 BAM_DPRINTF((D_NOMATCH_TITLE, fcn, title, lp->arg)); 6162 continue; /* check title only */ 6163 } 6164 6165 lp = lp->next; /* advance to root line */ 6166 if (lp == NULL) { 6167 continue; 6168 } else if (strcmp(lp->cmd, menu_cmds[FINDROOT_CMD]) == 0) { 6169 INJECT_ERROR1("FIND_BOOT_ENTRY_NULL_FINDROOT", 6170 findroot = NULL); 6171 if (findroot == NULL) { 6172 BAM_DPRINTF((D_NOMATCH_FINDROOT_NULL, 6173 fcn, lp->arg)); 6174 continue; 6175 } 6176 /* findroot command found, try match */ 6177 if (strcmp(lp->arg, findroot) != 0) { 6178 BAM_DPRINTF((D_NOMATCH_FINDROOT, 6179 fcn, findroot, lp->arg)); 6180 continue; 6181 } 6182 BAM_DPRINTF((D_MATCHED_FINDROOT, fcn, findroot)); 6183 lp = lp->next; /* advance to kernel line */ 6184 } else if (strcmp(lp->cmd, menu_cmds[ROOT_CMD]) == 0) { 6185 INJECT_ERROR1("FIND_BOOT_ENTRY_NULL_ROOT", root = NULL); 6186 if (root == NULL) { 6187 BAM_DPRINTF((D_NOMATCH_ROOT_NULL, 6188 fcn, lp->arg)); 6189 continue; 6190 } 6191 /* root cmd found, try match */ 6192 if (strcmp(lp->arg, root) != 0) { 6193 BAM_DPRINTF((D_NOMATCH_ROOT, 6194 fcn, root, lp->arg)); 6195 continue; 6196 } 6197 BAM_DPRINTF((D_MATCHED_ROOT, fcn, root)); 6198 lp = lp->next; /* advance to kernel line */ 6199 } else { 6200 INJECT_ERROR1("FIND_BOOT_ENTRY_ROOT_OPT_NO", 6201 root_opt = 0); 6202 INJECT_ERROR1("FIND_BOOT_ENTRY_ROOT_OPT_YES", 6203 root_opt = 1); 6204 /* no root command, see if root is optional */ 6205 if (root_opt == 0) { 6206 BAM_DPRINTF((D_NO_ROOT_OPT, fcn)); 6207 continue; 6208 } 6209 BAM_DPRINTF((D_ROOT_OPT, fcn)); 6210 } 6211 6212 if (lp == NULL || lp->next == NULL) { 6213 continue; 6214 } 6215 6216 if (kernel && 6217 (!check_cmd(lp->cmd, KERNEL_CMD, lp->arg, kernel))) { 6218 if (!(ent->flags & BAM_ENTRY_FAILSAFE) || 6219 !(ent->flags & BAM_ENTRY_DBOOT) || 6220 strcmp(kernel, DIRECT_BOOT_FAILSAFE_LINE) != 0) 6221 continue; 6222 6223 ent->flags |= BAM_ENTRY_UPGFSKERNEL; 6224 6225 } 6226 BAM_DPRINTF((D_KERNEL_MATCH, fcn, kernel, lp->arg)); 6227 6228 /* 6229 * Check for matching module entry (failsafe or normal). 6230 * If it fails to match, we go around the loop again. 6231 * For xpv entries, there are two module lines, so we 6232 * do the check twice. 6233 */ 6234 lp = lp->next; /* advance to module line */ 6235 if (check_cmd(lp->cmd, MODULE_CMD, lp->arg, module) || 6236 (((lp = lp->next) != NULL) && 6237 check_cmd(lp->cmd, MODULE_CMD, lp->arg, module))) { 6238 /* match found */ 6239 BAM_DPRINTF((D_MODULE_MATCH, fcn, module, lp->arg)); 6240 break; 6241 } 6242 6243 if (strcmp(module, FAILSAFE_ARCHIVE) == 0 && 6244 (strcmp(lp->prev->arg, FAILSAFE_ARCHIVE_32) == 0 || 6245 strcmp(lp->prev->arg, FAILSAFE_ARCHIVE_64) == 0)) { 6246 ent->flags |= BAM_ENTRY_UPGFSMODULE; 6247 break; 6248 } 6249 6250 } 6251 6252 if (ent && entry_num) { 6253 *entry_num = i; 6254 } 6255 6256 if (ent) { 6257 BAM_DPRINTF((D_RETURN_RET, fcn, i)); 6258 } else { 6259 BAM_DPRINTF((D_RETURN_RET, fcn, BAM_ERROR)); 6260 } 6261 return (ent); 6262 } 6263 6264 static int 6265 update_boot_entry(menu_t *mp, char *title, char *findroot, char *root, 6266 char *kernel, char *mod_kernel, char *module, int root_opt) 6267 { 6268 int i; 6269 int change_kernel = 0; 6270 entry_t *ent; 6271 line_t *lp; 6272 line_t *tlp; 6273 char linebuf[BAM_MAXLINE]; 6274 const char *fcn = "update_boot_entry()"; 6275 6276 /* note: don't match on title, it's updated on upgrade */ 6277 ent = find_boot_entry(mp, NULL, kernel, findroot, root, module, 6278 root_opt, &i); 6279 if ((ent == NULL) && (bam_direct == BAM_DIRECT_DBOOT)) { 6280 /* 6281 * We may be upgrading a kernel from multiboot to 6282 * directboot. Look for a multiboot entry. A multiboot 6283 * entry will not have a findroot line. 6284 */ 6285 ent = find_boot_entry(mp, NULL, "multiboot", NULL, root, 6286 MULTIBOOT_ARCHIVE, root_opt, &i); 6287 if (ent != NULL) { 6288 BAM_DPRINTF((D_UPGRADE_FROM_MULTIBOOT, fcn, root)); 6289 change_kernel = 1; 6290 } 6291 } else if (ent) { 6292 BAM_DPRINTF((D_FOUND_FINDROOT, fcn, findroot)); 6293 } 6294 6295 if (ent == NULL) { 6296 BAM_DPRINTF((D_ENTRY_NOT_FOUND_CREATING, fcn, findroot)); 6297 return (add_boot_entry(mp, title, findroot, 6298 kernel, mod_kernel, module)); 6299 } 6300 6301 /* replace title of existing entry and update findroot line */ 6302 lp = ent->start; 6303 lp = lp->next; /* title line */ 6304 (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s", 6305 menu_cmds[TITLE_CMD], menu_cmds[SEP_CMD], title); 6306 free(lp->arg); 6307 free(lp->line); 6308 lp->arg = s_strdup(title); 6309 lp->line = s_strdup(linebuf); 6310 BAM_DPRINTF((D_CHANGING_TITLE, fcn, title)); 6311 6312 tlp = lp; /* title line */ 6313 lp = lp->next; /* root line */ 6314 6315 /* if no root or findroot command, create a new line_t */ 6316 if (strcmp(lp->cmd, menu_cmds[ROOT_CMD]) != 0 && 6317 strcmp(lp->cmd, menu_cmds[FINDROOT_CMD]) != 0) { 6318 lp = s_calloc(1, sizeof (line_t)); 6319 bam_add_line(mp, ent, tlp, lp); 6320 } else { 6321 free(lp->cmd); 6322 free(lp->sep); 6323 free(lp->arg); 6324 free(lp->line); 6325 } 6326 6327 lp->cmd = s_strdup(menu_cmds[FINDROOT_CMD]); 6328 lp->sep = s_strdup(menu_cmds[SEP_CMD]); 6329 lp->arg = s_strdup(findroot); 6330 (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s", 6331 menu_cmds[FINDROOT_CMD], menu_cmds[SEP_CMD], findroot); 6332 lp->line = s_strdup(linebuf); 6333 BAM_DPRINTF((D_ADDING_FINDROOT_LINE, fcn, findroot)); 6334 6335 /* kernel line */ 6336 lp = lp->next; 6337 6338 if (ent->flags & BAM_ENTRY_UPGFSKERNEL) { 6339 char *params = NULL; 6340 6341 params = strstr(lp->line, "-s"); 6342 if (params != NULL) 6343 (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s%s", 6344 menu_cmds[KERNEL_DOLLAR_CMD], menu_cmds[SEP_CMD], 6345 kernel, params+2); 6346 else 6347 (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s", 6348 menu_cmds[KERNEL_DOLLAR_CMD], menu_cmds[SEP_CMD], 6349 kernel); 6350 6351 free(lp->cmd); 6352 free(lp->arg); 6353 free(lp->line); 6354 lp->cmd = s_strdup(menu_cmds[KERNEL_DOLLAR_CMD]); 6355 lp->arg = s_strdup(strstr(linebuf, "/")); 6356 lp->line = s_strdup(linebuf); 6357 ent->flags &= ~BAM_ENTRY_UPGFSKERNEL; 6358 BAM_DPRINTF((D_ADDING_KERNEL_DOLLAR, fcn, lp->prev->cmd)); 6359 } 6360 6361 if (change_kernel) { 6362 /* 6363 * We're upgrading from multiboot to directboot. 6364 */ 6365 if (strcmp(lp->cmd, menu_cmds[KERNEL_CMD]) == 0) { 6366 (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s", 6367 menu_cmds[KERNEL_DOLLAR_CMD], menu_cmds[SEP_CMD], 6368 kernel); 6369 free(lp->cmd); 6370 free(lp->arg); 6371 free(lp->line); 6372 lp->cmd = s_strdup(menu_cmds[KERNEL_DOLLAR_CMD]); 6373 lp->arg = s_strdup(kernel); 6374 lp->line = s_strdup(linebuf); 6375 lp = lp->next; 6376 BAM_DPRINTF((D_ADDING_KERNEL_DOLLAR, fcn, kernel)); 6377 } 6378 if (strcmp(lp->cmd, menu_cmds[MODULE_CMD]) == 0) { 6379 (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s", 6380 menu_cmds[MODULE_DOLLAR_CMD], menu_cmds[SEP_CMD], 6381 module); 6382 free(lp->cmd); 6383 free(lp->arg); 6384 free(lp->line); 6385 lp->cmd = s_strdup(menu_cmds[MODULE_DOLLAR_CMD]); 6386 lp->arg = s_strdup(module); 6387 lp->line = s_strdup(linebuf); 6388 lp = lp->next; 6389 BAM_DPRINTF((D_ADDING_MODULE_DOLLAR, fcn, module)); 6390 } 6391 } 6392 6393 /* module line */ 6394 lp = lp->next; 6395 6396 if (ent->flags & BAM_ENTRY_UPGFSMODULE) { 6397 if (strcmp(lp->cmd, menu_cmds[MODULE_CMD]) == 0) { 6398 (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s", 6399 menu_cmds[MODULE_DOLLAR_CMD], menu_cmds[SEP_CMD], 6400 module); 6401 free(lp->cmd); 6402 free(lp->arg); 6403 free(lp->line); 6404 lp->cmd = s_strdup(menu_cmds[MODULE_DOLLAR_CMD]); 6405 lp->arg = s_strdup(module); 6406 lp->line = s_strdup(linebuf); 6407 lp = lp->next; 6408 ent->flags &= ~BAM_ENTRY_UPGFSMODULE; 6409 BAM_DPRINTF((D_ADDING_MODULE_DOLLAR, fcn, module)); 6410 } 6411 } 6412 6413 BAM_DPRINTF((D_RETURN_RET, fcn, i)); 6414 return (i); 6415 } 6416 6417 int 6418 root_optional(char *osroot, char *menu_root) 6419 { 6420 char *ospecial; 6421 char *mspecial; 6422 char *slash; 6423 int root_opt; 6424 int ret1; 6425 int ret2; 6426 const char *fcn = "root_optional()"; 6427 6428 BAM_DPRINTF((D_FUNC_ENTRY2, fcn, osroot, menu_root)); 6429 6430 /* 6431 * For all filesystems except ZFS, a straight compare of osroot 6432 * and menu_root will tell us if root is optional. 6433 * For ZFS, the situation is complicated by the fact that 6434 * menu_root and osroot are always different 6435 */ 6436 ret1 = is_zfs(osroot); 6437 ret2 = is_zfs(menu_root); 6438 INJECT_ERROR1("ROOT_OPT_NOT_ZFS", ret1 = 0); 6439 if (!ret1 || !ret2) { 6440 BAM_DPRINTF((D_ROOT_OPT_NOT_ZFS, fcn, osroot, menu_root)); 6441 root_opt = (strcmp(osroot, menu_root) == 0); 6442 goto out; 6443 } 6444 6445 ospecial = get_special(osroot); 6446 INJECT_ERROR1("ROOT_OPTIONAL_OSPECIAL", ospecial = NULL); 6447 if (ospecial == NULL) { 6448 bam_error(GET_OSROOT_SPECIAL_ERR, osroot); 6449 return (0); 6450 } 6451 BAM_DPRINTF((D_ROOT_OPTIONAL_OSPECIAL, fcn, ospecial, osroot)); 6452 6453 mspecial = get_special(menu_root); 6454 INJECT_ERROR1("ROOT_OPTIONAL_MSPECIAL", mspecial = NULL); 6455 if (mspecial == NULL) { 6456 bam_error(GET_MENU_ROOT_SPECIAL_ERR, menu_root); 6457 free(ospecial); 6458 return (0); 6459 } 6460 BAM_DPRINTF((D_ROOT_OPTIONAL_MSPECIAL, fcn, mspecial, menu_root)); 6461 6462 slash = strchr(ospecial, '/'); 6463 if (slash) 6464 *slash = '\0'; 6465 BAM_DPRINTF((D_ROOT_OPTIONAL_FIXED_OSPECIAL, fcn, ospecial, osroot)); 6466 6467 root_opt = (strcmp(ospecial, mspecial) == 0); 6468 6469 free(ospecial); 6470 free(mspecial); 6471 6472 out: 6473 INJECT_ERROR1("ROOT_OPTIONAL_NO", root_opt = 0); 6474 INJECT_ERROR1("ROOT_OPTIONAL_YES", root_opt = 1); 6475 if (root_opt) { 6476 BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 6477 } else { 6478 BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 6479 } 6480 6481 return (root_opt); 6482 } 6483 6484 /*ARGSUSED*/ 6485 static error_t 6486 update_entry(menu_t *mp, char *menu_root, char *osdev) 6487 { 6488 int entry; 6489 char *grubsign; 6490 char *grubroot; 6491 char *title; 6492 char osroot[PATH_MAX]; 6493 char *failsafe_kernel = NULL; 6494 struct stat sbuf; 6495 char failsafe[256]; 6496 char failsafe_64[256]; 6497 int ret; 6498 const char *fcn = "update_entry()"; 6499 6500 assert(mp); 6501 assert(menu_root); 6502 assert(osdev); 6503 assert(bam_root); 6504 6505 BAM_DPRINTF((D_FUNC_ENTRY3, fcn, menu_root, osdev, bam_root)); 6506 6507 (void) strlcpy(osroot, bam_root, sizeof (osroot)); 6508 6509 title = get_title(osroot); 6510 assert(title); 6511 6512 grubsign = get_grubsign(osroot, osdev); 6513 INJECT_ERROR1("GET_GRUBSIGN_FAIL", grubsign = NULL); 6514 if (grubsign == NULL) { 6515 bam_error(GET_GRUBSIGN_ERROR, osroot, osdev); 6516 return (BAM_ERROR); 6517 } 6518 6519 /* 6520 * It is not a fatal error if get_grubroot() fails 6521 * We no longer rely on biosdev to populate the 6522 * menu 6523 */ 6524 grubroot = get_grubroot(osroot, osdev, menu_root); 6525 INJECT_ERROR1("GET_GRUBROOT_FAIL", grubroot = NULL); 6526 if (grubroot) { 6527 BAM_DPRINTF((D_GET_GRUBROOT_SUCCESS, 6528 fcn, osroot, osdev, menu_root)); 6529 } else { 6530 BAM_DPRINTF((D_GET_GRUBROOT_FAILURE, 6531 fcn, osroot, osdev, menu_root)); 6532 } 6533 6534 /* add the entry for normal Solaris */ 6535 INJECT_ERROR1("UPDATE_ENTRY_MULTIBOOT", 6536 bam_direct = BAM_DIRECT_MULTIBOOT); 6537 if (bam_direct == BAM_DIRECT_DBOOT) { 6538 entry = update_boot_entry(mp, title, grubsign, grubroot, 6539 (bam_zfs ? DIRECT_BOOT_KERNEL_ZFS : DIRECT_BOOT_KERNEL), 6540 NULL, DIRECT_BOOT_ARCHIVE, 6541 root_optional(osroot, menu_root)); 6542 BAM_DPRINTF((D_UPDATED_BOOT_ENTRY, fcn, bam_zfs, grubsign)); 6543 if ((entry != BAM_ERROR) && (bam_is_hv == BAM_HV_PRESENT)) { 6544 (void) update_boot_entry(mp, NEW_HV_ENTRY, grubsign, 6545 grubroot, XEN_MENU, bam_zfs ? 6546 XEN_KERNEL_MODULE_LINE_ZFS : XEN_KERNEL_MODULE_LINE, 6547 DIRECT_BOOT_ARCHIVE, 6548 root_optional(osroot, menu_root)); 6549 BAM_DPRINTF((D_UPDATED_HV_ENTRY, 6550 fcn, bam_zfs, grubsign)); 6551 } 6552 } else { 6553 entry = update_boot_entry(mp, title, grubsign, grubroot, 6554 MULTI_BOOT, NULL, MULTIBOOT_ARCHIVE, 6555 root_optional(osroot, menu_root)); 6556 6557 BAM_DPRINTF((D_UPDATED_MULTIBOOT_ENTRY, fcn, grubsign)); 6558 } 6559 6560 /* 6561 * Add the entry for failsafe archive. On a bfu'd system, the 6562 * failsafe may be different than the installed kernel. 6563 */ 6564 (void) snprintf(failsafe, sizeof (failsafe), "%s%s", 6565 osroot, FAILSAFE_ARCHIVE_32); 6566 (void) snprintf(failsafe_64, sizeof (failsafe_64), "%s%s", 6567 osroot, FAILSAFE_ARCHIVE_64); 6568 6569 /* 6570 * Check if at least one of the two archives exists 6571 * Using $ISADIR as the default line, we have an entry which works 6572 * for both the cases. 6573 */ 6574 6575 if (stat(failsafe, &sbuf) == 0 || stat(failsafe_64, &sbuf) == 0) { 6576 6577 /* Figure out where the kernel line should point */ 6578 (void) snprintf(failsafe, sizeof (failsafe), "%s%s", osroot, 6579 DIRECT_BOOT_FAILSAFE_32); 6580 (void) snprintf(failsafe_64, sizeof (failsafe_64), "%s%s", 6581 osroot, DIRECT_BOOT_FAILSAFE_64); 6582 if (stat(failsafe, &sbuf) == 0 || 6583 stat(failsafe_64, &sbuf) == 0) { 6584 failsafe_kernel = DIRECT_BOOT_FAILSAFE_LINE; 6585 } else { 6586 (void) snprintf(failsafe, sizeof (failsafe), "%s%s", 6587 osroot, MULTI_BOOT_FAILSAFE); 6588 if (stat(failsafe, &sbuf) == 0) { 6589 failsafe_kernel = MULTI_BOOT_FAILSAFE_LINE; 6590 } 6591 } 6592 if (failsafe_kernel != NULL) { 6593 (void) update_boot_entry(mp, FAILSAFE_TITLE, grubsign, 6594 grubroot, failsafe_kernel, NULL, FAILSAFE_ARCHIVE, 6595 root_optional(osroot, menu_root)); 6596 BAM_DPRINTF((D_UPDATED_FAILSAFE_ENTRY, fcn, 6597 failsafe_kernel)); 6598 } 6599 } 6600 free(grubroot); 6601 6602 INJECT_ERROR1("UPDATE_ENTRY_ERROR", entry = BAM_ERROR); 6603 if (entry == BAM_ERROR) { 6604 bam_error(FAILED_TO_ADD_BOOT_ENTRY, title, grubsign); 6605 free(grubsign); 6606 return (BAM_ERROR); 6607 } 6608 free(grubsign); 6609 6610 update_numbering(mp); 6611 ret = set_global(mp, menu_cmds[DEFAULT_CMD], entry); 6612 INJECT_ERROR1("SET_DEFAULT_ERROR", ret = BAM_ERROR); 6613 if (ret == BAM_ERROR) { 6614 bam_error(SET_DEFAULT_FAILED, entry); 6615 } 6616 BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 6617 return (BAM_WRITE); 6618 } 6619 6620 static void 6621 save_default_entry(menu_t *mp, const char *which) 6622 { 6623 int lineNum; 6624 int entryNum; 6625 int entry = 0; /* default is 0 */ 6626 char linebuf[BAM_MAXLINE]; 6627 line_t *lp = mp->curdefault; 6628 const char *fcn = "save_default_entry()"; 6629 6630 if (mp->start) { 6631 lineNum = mp->end->lineNum; 6632 entryNum = mp->end->entryNum; 6633 } else { 6634 lineNum = LINE_INIT; 6635 entryNum = ENTRY_INIT; 6636 } 6637 6638 if (lp) 6639 entry = s_strtol(lp->arg); 6640 6641 (void) snprintf(linebuf, sizeof (linebuf), "#%s%d", which, entry); 6642 BAM_DPRINTF((D_SAVING_DEFAULT_TO, fcn, linebuf)); 6643 line_parser(mp, linebuf, &lineNum, &entryNum); 6644 BAM_DPRINTF((D_SAVED_DEFAULT_TO, fcn, lineNum, entryNum)); 6645 } 6646 6647 static void 6648 restore_default_entry(menu_t *mp, const char *which, line_t *lp) 6649 { 6650 int entry; 6651 char *str; 6652 const char *fcn = "restore_default_entry()"; 6653 6654 if (lp == NULL) { 6655 BAM_DPRINTF((D_RESTORE_DEFAULT_NULL, fcn)); 6656 return; /* nothing to restore */ 6657 } 6658 6659 BAM_DPRINTF((D_RESTORE_DEFAULT_STR, fcn, which)); 6660 6661 str = lp->arg + strlen(which); 6662 entry = s_strtol(str); 6663 (void) set_global(mp, menu_cmds[DEFAULT_CMD], entry); 6664 6665 BAM_DPRINTF((D_RESTORED_DEFAULT_TO, fcn, entry)); 6666 6667 /* delete saved old default line */ 6668 unlink_line(mp, lp); 6669 line_free(lp); 6670 } 6671 6672 /* 6673 * This function is for supporting reboot with args. 6674 * The opt value can be: 6675 * NULL delete temp entry, if present 6676 * entry=<n> switches default entry to <n> 6677 * else treated as boot-args and setup a temperary menu entry 6678 * and make it the default 6679 * Note that we are always rebooting the current OS instance 6680 * so osroot == / always. 6681 */ 6682 #define REBOOT_TITLE "Solaris_reboot_transient" 6683 6684 /*ARGSUSED*/ 6685 static error_t 6686 update_temp(menu_t *mp, char *dummy, char *opt) 6687 { 6688 int entry; 6689 char *osdev; 6690 char *fstype; 6691 char *sign; 6692 char *opt_ptr; 6693 char *path; 6694 char kernbuf[BUFSIZ]; 6695 char args_buf[BUFSIZ]; 6696 char signbuf[PATH_MAX]; 6697 int ret; 6698 const char *fcn = "update_temp()"; 6699 6700 assert(mp); 6701 assert(dummy == NULL); 6702 6703 /* opt can be NULL */ 6704 BAM_DPRINTF((D_FUNC_ENTRY1, fcn, opt ? opt : "<NULL>")); 6705 BAM_DPRINTF((D_BAM_ROOT, fcn, bam_alt_root, bam_root)); 6706 6707 if (bam_alt_root || bam_rootlen != 1 || 6708 strcmp(bam_root, "/") != 0 || 6709 strcmp(rootbuf, "/") != 0) { 6710 bam_error(ALT_ROOT_INVALID, bam_root); 6711 return (BAM_ERROR); 6712 } 6713 6714 /* If no option, delete exiting reboot menu entry */ 6715 if (opt == NULL) { 6716 entry_t *ent; 6717 BAM_DPRINTF((D_OPT_NULL, fcn)); 6718 ent = find_boot_entry(mp, REBOOT_TITLE, NULL, NULL, 6719 NULL, NULL, 0, &entry); 6720 if (ent == NULL) { /* not found is ok */ 6721 BAM_DPRINTF((D_TRANSIENT_NOTFOUND, fcn)); 6722 return (BAM_SUCCESS); 6723 } 6724 (void) do_delete(mp, entry); 6725 restore_default_entry(mp, BAM_OLDDEF, mp->olddefault); 6726 mp->olddefault = NULL; 6727 BAM_DPRINTF((D_RESTORED_DEFAULT, fcn)); 6728 BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 6729 return (BAM_WRITE); 6730 } 6731 6732 /* if entry= is specified, set the default entry */ 6733 if (strncmp(opt, "entry=", strlen("entry=")) == 0) { 6734 int entryNum = s_strtol(opt + strlen("entry=")); 6735 BAM_DPRINTF((D_ENTRY_EQUALS, fcn, opt)); 6736 if (selector(mp, opt, &entry, NULL) == BAM_SUCCESS) { 6737 /* this is entry=# option */ 6738 ret = set_global(mp, menu_cmds[DEFAULT_CMD], entry); 6739 BAM_DPRINTF((D_ENTRY_SET_IS, fcn, entry, ret)); 6740 return (ret); 6741 } else { 6742 bam_error(SET_DEFAULT_FAILED, entryNum); 6743 return (BAM_ERROR); 6744 } 6745 } 6746 6747 /* 6748 * add a new menu entry based on opt and make it the default 6749 */ 6750 6751 fstype = get_fstype("/"); 6752 INJECT_ERROR1("REBOOT_FSTYPE_NULL", fstype = NULL); 6753 if (fstype == NULL) { 6754 bam_error(REBOOT_FSTYPE_FAILED); 6755 return (BAM_ERROR); 6756 } 6757 6758 osdev = get_special("/"); 6759 INJECT_ERROR1("REBOOT_SPECIAL_NULL", osdev = NULL); 6760 if (osdev == NULL) { 6761 free(fstype); 6762 bam_error(REBOOT_SPECIAL_FAILED); 6763 return (BAM_ERROR); 6764 } 6765 6766 sign = find_existing_sign("/", osdev, fstype); 6767 INJECT_ERROR1("REBOOT_SIGN_NULL", sign = NULL); 6768 if (sign == NULL) { 6769 free(fstype); 6770 free(osdev); 6771 bam_error(REBOOT_SIGN_FAILED); 6772 return (BAM_ERROR); 6773 } 6774 6775 free(fstype); 6776 free(osdev); 6777 (void) strlcpy(signbuf, sign, sizeof (signbuf)); 6778 free(sign); 6779 6780 assert(strchr(signbuf, '(') == NULL && strchr(signbuf, ',') == NULL && 6781 strchr(signbuf, ')') == NULL); 6782 6783 /* 6784 * There is no alternate root while doing reboot with args 6785 * This version of bootadm is only delivered with a DBOOT 6786 * version of Solaris. 6787 */ 6788 INJECT_ERROR1("REBOOT_NOT_DBOOT", bam_direct = BAM_DIRECT_MULTIBOOT); 6789 if (bam_direct != BAM_DIRECT_DBOOT) { 6790 bam_error(REBOOT_DIRECT_FAILED); 6791 return (BAM_ERROR); 6792 } 6793 6794 /* add an entry for Solaris reboot */ 6795 if (opt[0] == '-') { 6796 /* It's an option - first see if boot-file is set */ 6797 ret = get_kernel(mp, KERNEL_CMD, kernbuf, sizeof (kernbuf)); 6798 INJECT_ERROR1("REBOOT_GET_KERNEL", ret = BAM_ERROR); 6799 if (ret != BAM_SUCCESS) { 6800 bam_error(REBOOT_GET_KERNEL_FAILED); 6801 return (BAM_ERROR); 6802 } 6803 if (kernbuf[0] == '\0') 6804 (void) strlcpy(kernbuf, DIRECT_BOOT_KERNEL, 6805 sizeof (kernbuf)); 6806 (void) strlcat(kernbuf, " ", sizeof (kernbuf)); 6807 (void) strlcat(kernbuf, opt, sizeof (kernbuf)); 6808 BAM_DPRINTF((D_REBOOT_OPTION, fcn, kernbuf)); 6809 } else if (opt[0] == '/') { 6810 /* It's a full path, so write it out. */ 6811 (void) strlcpy(kernbuf, opt, sizeof (kernbuf)); 6812 6813 /* 6814 * If someone runs: 6815 * 6816 * # eeprom boot-args='-kd' 6817 * # reboot /platform/i86pc/kernel/unix 6818 * 6819 * we want to use the boot-args as part of the boot 6820 * line. On the other hand, if someone runs: 6821 * 6822 * # reboot "/platform/i86pc/kernel/unix -kd" 6823 * 6824 * we don't need to mess with boot-args. If there's 6825 * no space in the options string, assume we're in the 6826 * first case. 6827 */ 6828 if (strchr(opt, ' ') == NULL) { 6829 ret = get_kernel(mp, ARGS_CMD, args_buf, 6830 sizeof (args_buf)); 6831 INJECT_ERROR1("REBOOT_GET_ARGS", ret = BAM_ERROR); 6832 if (ret != BAM_SUCCESS) { 6833 bam_error(REBOOT_GET_ARGS_FAILED); 6834 return (BAM_ERROR); 6835 } 6836 6837 if (args_buf[0] != '\0') { 6838 (void) strlcat(kernbuf, " ", sizeof (kernbuf)); 6839 (void) strlcat(kernbuf, args_buf, 6840 sizeof (kernbuf)); 6841 } 6842 } 6843 BAM_DPRINTF((D_REBOOT_ABSPATH, fcn, kernbuf)); 6844 } else { 6845 /* 6846 * It may be a partial path, or it may be a partial 6847 * path followed by options. Assume that only options 6848 * follow a space. If someone sends us a kernel path 6849 * that includes a space, they deserve to be broken. 6850 */ 6851 opt_ptr = strchr(opt, ' '); 6852 if (opt_ptr != NULL) { 6853 *opt_ptr = '\0'; 6854 } 6855 6856 path = expand_path(opt); 6857 if (path != NULL) { 6858 (void) strlcpy(kernbuf, path, sizeof (kernbuf)); 6859 free(path); 6860 6861 /* 6862 * If there were options given, use those. 6863 * Otherwise, copy over the default options. 6864 */ 6865 if (opt_ptr != NULL) { 6866 /* Restore the space in opt string */ 6867 *opt_ptr = ' '; 6868 (void) strlcat(kernbuf, opt_ptr, 6869 sizeof (kernbuf)); 6870 } else { 6871 ret = get_kernel(mp, ARGS_CMD, args_buf, 6872 sizeof (args_buf)); 6873 INJECT_ERROR1("UPDATE_TEMP_PARTIAL_ARGS", 6874 ret = BAM_ERROR); 6875 if (ret != BAM_SUCCESS) { 6876 bam_error(REBOOT_GET_ARGS_FAILED); 6877 return (BAM_ERROR); 6878 } 6879 6880 if (args_buf[0] != '\0') { 6881 (void) strlcat(kernbuf, " ", 6882 sizeof (kernbuf)); 6883 (void) strlcat(kernbuf, 6884 args_buf, sizeof (kernbuf)); 6885 } 6886 } 6887 BAM_DPRINTF((D_REBOOT_RESOLVED_PARTIAL, fcn, kernbuf)); 6888 } else { 6889 bam_error(UNKNOWN_KERNEL, opt); 6890 bam_print_stderr(UNKNOWN_KERNEL_REBOOT); 6891 return (BAM_ERROR); 6892 } 6893 } 6894 entry = add_boot_entry(mp, REBOOT_TITLE, signbuf, kernbuf, 6895 NULL, NULL); 6896 INJECT_ERROR1("REBOOT_ADD_BOOT_ENTRY", entry = BAM_ERROR); 6897 if (entry == BAM_ERROR) { 6898 bam_error(REBOOT_WITH_ARGS_ADD_ENTRY_FAILED); 6899 return (BAM_ERROR); 6900 } 6901 6902 save_default_entry(mp, BAM_OLDDEF); 6903 ret = set_global(mp, menu_cmds[DEFAULT_CMD], entry); 6904 INJECT_ERROR1("REBOOT_SET_GLOBAL", ret = BAM_ERROR); 6905 if (ret == BAM_ERROR) { 6906 bam_error(REBOOT_SET_DEFAULT_FAILED, entry); 6907 } 6908 BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 6909 return (BAM_WRITE); 6910 } 6911 6912 static error_t 6913 set_global(menu_t *mp, char *globalcmd, int val) 6914 { 6915 line_t *lp; 6916 line_t *found; 6917 line_t *last; 6918 char *cp; 6919 char *str; 6920 char prefix[BAM_MAXLINE]; 6921 size_t len; 6922 const char *fcn = "set_global()"; 6923 6924 assert(mp); 6925 assert(globalcmd); 6926 6927 if (strcmp(globalcmd, menu_cmds[DEFAULT_CMD]) == 0) { 6928 INJECT_ERROR1("SET_GLOBAL_VAL_NEG", val = -1); 6929 INJECT_ERROR1("SET_GLOBAL_MENU_EMPTY", mp->end = NULL); 6930 INJECT_ERROR1("SET_GLOBAL_VAL_TOO_BIG", val = 100); 6931 if (val < 0 || mp->end == NULL || val > mp->end->entryNum) { 6932 (void) snprintf(prefix, sizeof (prefix), "%d", val); 6933 bam_error(INVALID_ENTRY, prefix); 6934 return (BAM_ERROR); 6935 } 6936 } 6937 6938 found = last = NULL; 6939 for (lp = mp->start; lp; lp = lp->next) { 6940 if (lp->flags != BAM_GLOBAL) 6941 continue; 6942 6943 last = lp; /* track the last global found */ 6944 6945 INJECT_ERROR1("SET_GLOBAL_NULL_CMD", lp->cmd = NULL); 6946 if (lp->cmd == NULL) { 6947 bam_error(NO_CMD, lp->lineNum); 6948 continue; 6949 } 6950 if (strcmp(globalcmd, lp->cmd) != 0) 6951 continue; 6952 6953 BAM_DPRINTF((D_FOUND_GLOBAL, fcn, globalcmd)); 6954 6955 if (found) { 6956 bam_error(DUP_CMD, globalcmd, lp->lineNum, bam_root); 6957 } 6958 found = lp; 6959 } 6960 6961 if (found == NULL) { 6962 lp = s_calloc(1, sizeof (line_t)); 6963 if (last == NULL) { 6964 lp->next = mp->start; 6965 mp->start = lp; 6966 mp->end = (mp->end) ? mp->end : lp; 6967 } else { 6968 lp->next = last->next; 6969 last->next = lp; 6970 if (lp->next == NULL) 6971 mp->end = lp; 6972 } 6973 lp->flags = BAM_GLOBAL; /* other fields not needed for writes */ 6974 len = strlen(globalcmd) + strlen(menu_cmds[SEP_CMD]); 6975 len += 10; /* val < 10 digits */ 6976 lp->line = s_calloc(1, len); 6977 (void) snprintf(lp->line, len, "%s%s%d", 6978 globalcmd, menu_cmds[SEP_CMD], val); 6979 BAM_DPRINTF((D_SET_GLOBAL_WROTE_NEW, fcn, lp->line)); 6980 BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 6981 return (BAM_WRITE); 6982 } 6983 6984 /* 6985 * We are changing an existing entry. Retain any prefix whitespace, 6986 * but overwrite everything else. This preserves tabs added for 6987 * readability. 6988 */ 6989 str = found->line; 6990 cp = prefix; 6991 while (*str == ' ' || *str == '\t') 6992 *(cp++) = *(str++); 6993 *cp = '\0'; /* Terminate prefix */ 6994 len = strlen(prefix) + strlen(globalcmd); 6995 len += strlen(menu_cmds[SEP_CMD]) + 10; 6996 6997 free(found->line); 6998 found->line = s_calloc(1, len); 6999 (void) snprintf(found->line, len, 7000 "%s%s%s%d", prefix, globalcmd, menu_cmds[SEP_CMD], val); 7001 7002 BAM_DPRINTF((D_SET_GLOBAL_REPLACED, fcn, found->line)); 7003 BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 7004 return (BAM_WRITE); /* need a write to menu */ 7005 } 7006 7007 /* 7008 * partial_path may be anything like "kernel/unix" or "kmdb". Try to 7009 * expand it to a full unix path. The calling function is expected to 7010 * output a message if an error occurs and NULL is returned. 7011 */ 7012 static char * 7013 expand_path(const char *partial_path) 7014 { 7015 int new_path_len; 7016 char *new_path; 7017 char new_path2[PATH_MAX]; 7018 struct stat sb; 7019 const char *fcn = "expand_path()"; 7020 7021 new_path_len = strlen(partial_path) + 64; 7022 new_path = s_calloc(1, new_path_len); 7023 7024 /* First, try the simplest case - something like "kernel/unix" */ 7025 (void) snprintf(new_path, new_path_len, "/platform/i86pc/%s", 7026 partial_path); 7027 if (stat(new_path, &sb) == 0) { 7028 BAM_DPRINTF((D_EXPAND_PATH, fcn, new_path)); 7029 return (new_path); 7030 } 7031 7032 if (strcmp(partial_path, "kmdb") == 0) { 7033 (void) snprintf(new_path, new_path_len, "%s -k", 7034 DIRECT_BOOT_KERNEL); 7035 BAM_DPRINTF((D_EXPAND_PATH, fcn, new_path)); 7036 return (new_path); 7037 } 7038 7039 /* 7040 * We've quickly reached unsupported usage. Try once more to 7041 * see if we were just given a glom name. 7042 */ 7043 (void) snprintf(new_path, new_path_len, "/platform/i86pc/%s/unix", 7044 partial_path); 7045 (void) snprintf(new_path2, PATH_MAX, "/platform/i86pc/%s/amd64/unix", 7046 partial_path); 7047 if (stat(new_path, &sb) == 0) { 7048 if (stat(new_path2, &sb) == 0) { 7049 /* 7050 * We matched both, so we actually 7051 * want to write the $ISADIR version. 7052 */ 7053 (void) snprintf(new_path, new_path_len, 7054 "/platform/i86pc/kernel/%s/$ISADIR/unix", 7055 partial_path); 7056 } 7057 BAM_DPRINTF((D_EXPAND_PATH, fcn, new_path)); 7058 return (new_path); 7059 } 7060 7061 free(new_path); 7062 BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 7063 return (NULL); 7064 } 7065 7066 /* 7067 * The kernel cmd and arg have been changed, so 7068 * check whether the archive line needs to change. 7069 */ 7070 static void 7071 set_archive_line(entry_t *entryp, line_t *kernelp) 7072 { 7073 line_t *lp = entryp->start; 7074 char *new_archive; 7075 menu_cmd_t m_cmd; 7076 const char *fcn = "set_archive_line()"; 7077 7078 for (; lp != NULL; lp = lp->next) { 7079 if (strncmp(lp->cmd, menu_cmds[MODULE_CMD], 7080 sizeof (menu_cmds[MODULE_CMD]) - 1) == 0) { 7081 break; 7082 } 7083 7084 INJECT_ERROR1("SET_ARCHIVE_LINE_END_ENTRY", lp = entryp->end); 7085 if (lp == entryp->end) { 7086 BAM_DPRINTF((D_ARCHIVE_LINE_NONE, fcn, 7087 entryp->entryNum)); 7088 return; 7089 } 7090 } 7091 INJECT_ERROR1("SET_ARCHIVE_LINE_END_MENU", lp = NULL); 7092 if (lp == NULL) { 7093 BAM_DPRINTF((D_ARCHIVE_LINE_NONE, fcn, entryp->entryNum)); 7094 return; 7095 } 7096 7097 if (strstr(kernelp->arg, "$ISADIR") != NULL) { 7098 new_archive = DIRECT_BOOT_ARCHIVE; 7099 m_cmd = MODULE_DOLLAR_CMD; 7100 } else if (strstr(kernelp->arg, "amd64") != NULL) { 7101 new_archive = DIRECT_BOOT_ARCHIVE_64; 7102 m_cmd = MODULE_CMD; 7103 } else { 7104 new_archive = DIRECT_BOOT_ARCHIVE_32; 7105 m_cmd = MODULE_CMD; 7106 } 7107 7108 if (strcmp(lp->arg, new_archive) == 0) { 7109 BAM_DPRINTF((D_ARCHIVE_LINE_NOCHANGE, fcn, lp->arg)); 7110 return; 7111 } 7112 7113 if (strcmp(lp->cmd, menu_cmds[m_cmd]) != 0) { 7114 free(lp->cmd); 7115 lp->cmd = s_strdup(menu_cmds[m_cmd]); 7116 } 7117 7118 free(lp->arg); 7119 lp->arg = s_strdup(new_archive); 7120 update_line(lp); 7121 BAM_DPRINTF((D_ARCHIVE_LINE_REPLACED, fcn, lp->line)); 7122 } 7123 7124 /* 7125 * Title for an entry to set properties that once went in bootenv.rc. 7126 */ 7127 #define BOOTENV_RC_TITLE "Solaris bootenv rc" 7128 7129 /* 7130 * If path is NULL, return the kernel (optnum == KERNEL_CMD) or arguments 7131 * (optnum == ARGS_CMD) in the argument buf. If path is a zero-length 7132 * string, reset the value to the default. If path is a non-zero-length 7133 * string, set the kernel or arguments. 7134 */ 7135 static error_t 7136 get_set_kernel( 7137 menu_t *mp, 7138 menu_cmd_t optnum, 7139 char *path, 7140 char *buf, 7141 size_t bufsize) 7142 { 7143 int entryNum; 7144 int rv = BAM_SUCCESS; 7145 int free_new_path = 0; 7146 entry_t *entryp; 7147 line_t *ptr; 7148 line_t *kernelp; 7149 char *new_arg; 7150 char *old_args; 7151 char *space; 7152 char *new_path; 7153 char old_space; 7154 size_t old_kernel_len; 7155 size_t new_str_len; 7156 char *fstype; 7157 char *osdev; 7158 char *sign; 7159 char signbuf[PATH_MAX]; 7160 int ret; 7161 const char *fcn = "get_set_kernel()"; 7162 7163 assert(bufsize > 0); 7164 7165 ptr = kernelp = NULL; 7166 new_arg = old_args = space = NULL; 7167 new_path = NULL; 7168 buf[0] = '\0'; 7169 7170 INJECT_ERROR1("GET_SET_KERNEL_NOT_DBOOT", 7171 bam_direct = BAM_DIRECT_MULTIBOOT); 7172 if (bam_direct != BAM_DIRECT_DBOOT) { 7173 bam_error(NOT_DBOOT, optnum == KERNEL_CMD ? "kernel" : "args"); 7174 return (BAM_ERROR); 7175 } 7176 7177 /* 7178 * If a user changed the default entry to a non-bootadm controlled 7179 * one, we don't want to mess with it. Just print an error and 7180 * return. 7181 */ 7182 if (mp->curdefault) { 7183 entryNum = s_strtol(mp->curdefault->arg); 7184 for (entryp = mp->entries; entryp; entryp = entryp->next) { 7185 if (entryp->entryNum == entryNum) 7186 break; 7187 } 7188 if ((entryp != NULL) && 7189 ((entryp->flags & (BAM_ENTRY_BOOTADM|BAM_ENTRY_LU)) == 0)) { 7190 bam_error(DEFAULT_NOT_BAM); 7191 return (BAM_ERROR); 7192 } 7193 } 7194 7195 entryp = find_boot_entry(mp, BOOTENV_RC_TITLE, NULL, NULL, NULL, NULL, 7196 0, &entryNum); 7197 7198 if (entryp != NULL) { 7199 for (ptr = entryp->start; ptr && ptr != entryp->end; 7200 ptr = ptr->next) { 7201 if (strncmp(ptr->cmd, menu_cmds[KERNEL_CMD], 7202 sizeof (menu_cmds[KERNEL_CMD]) - 1) == 0) { 7203 kernelp = ptr; 7204 break; 7205 } 7206 } 7207 if (kernelp == NULL) { 7208 bam_error(NO_KERNEL, entryNum); 7209 return (BAM_ERROR); 7210 } 7211 7212 old_kernel_len = strcspn(kernelp->arg, " \t"); 7213 space = old_args = kernelp->arg + old_kernel_len; 7214 while ((*old_args == ' ') || (*old_args == '\t')) 7215 old_args++; 7216 } 7217 7218 if (path == NULL) { 7219 if (entryp == NULL) { 7220 BAM_DPRINTF((D_GET_SET_KERNEL_NO_RC, fcn)); 7221 BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 7222 return (BAM_SUCCESS); 7223 } 7224 assert(kernelp); 7225 if (optnum == ARGS_CMD) { 7226 if (old_args[0] != '\0') { 7227 (void) strlcpy(buf, old_args, bufsize); 7228 BAM_DPRINTF((D_GET_SET_KERNEL_ARGS, fcn, buf)); 7229 } 7230 } else { 7231 /* 7232 * We need to print the kernel, so we just turn the 7233 * first space into a '\0' and print the beginning. 7234 * We don't print anything if it's the default kernel. 7235 */ 7236 old_space = *space; 7237 *space = '\0'; 7238 if (strcmp(kernelp->arg, DIRECT_BOOT_KERNEL) != 0) { 7239 (void) strlcpy(buf, kernelp->arg, bufsize); 7240 BAM_DPRINTF((D_GET_SET_KERNEL_KERN, fcn, buf)); 7241 } 7242 *space = old_space; 7243 } 7244 BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 7245 return (BAM_SUCCESS); 7246 } 7247 7248 /* 7249 * First, check if we're resetting an entry to the default. 7250 */ 7251 if ((path[0] == '\0') || 7252 ((optnum == KERNEL_CMD) && 7253 (strcmp(path, DIRECT_BOOT_KERNEL) == 0))) { 7254 if ((entryp == NULL) || (kernelp == NULL)) { 7255 /* No previous entry, it's already the default */ 7256 BAM_DPRINTF((D_GET_SET_KERNEL_ALREADY, fcn)); 7257 return (BAM_SUCCESS); 7258 } 7259 7260 /* 7261 * Check if we can delete the entry. If we're resetting the 7262 * kernel command, and the args is already empty, or if we're 7263 * resetting the args command, and the kernel is already the 7264 * default, we can restore the old default and delete the entry. 7265 */ 7266 if (((optnum == KERNEL_CMD) && 7267 ((old_args == NULL) || (old_args[0] == '\0'))) || 7268 ((optnum == ARGS_CMD) && 7269 (strncmp(kernelp->arg, DIRECT_BOOT_KERNEL, 7270 sizeof (DIRECT_BOOT_KERNEL) - 1) == 0))) { 7271 kernelp = NULL; 7272 (void) do_delete(mp, entryNum); 7273 restore_default_entry(mp, BAM_OLD_RC_DEF, 7274 mp->old_rc_default); 7275 mp->old_rc_default = NULL; 7276 rv = BAM_WRITE; 7277 BAM_DPRINTF((D_GET_SET_KERNEL_RESTORE_DEFAULT, fcn)); 7278 goto done; 7279 } 7280 7281 if (optnum == KERNEL_CMD) { 7282 /* 7283 * At this point, we've already checked that old_args 7284 * and entryp are valid pointers. The "+ 2" is for 7285 * a space a the string termination character. 7286 */ 7287 new_str_len = (sizeof (DIRECT_BOOT_KERNEL) - 1) + 7288 strlen(old_args) + 2; 7289 new_arg = s_calloc(1, new_str_len); 7290 (void) snprintf(new_arg, new_str_len, "%s %s", 7291 DIRECT_BOOT_KERNEL, old_args); 7292 free(kernelp->arg); 7293 kernelp->arg = new_arg; 7294 7295 /* 7296 * We have changed the kernel line, so we may need 7297 * to update the archive line as well. 7298 */ 7299 set_archive_line(entryp, kernelp); 7300 BAM_DPRINTF((D_GET_SET_KERNEL_RESET_KERNEL_SET_ARG, 7301 fcn, kernelp->arg)); 7302 } else { 7303 /* 7304 * We're resetting the boot args to nothing, so 7305 * we only need to copy the kernel. We've already 7306 * checked that the kernel is not the default. 7307 */ 7308 new_arg = s_calloc(1, old_kernel_len + 1); 7309 (void) snprintf(new_arg, old_kernel_len + 1, "%s", 7310 kernelp->arg); 7311 free(kernelp->arg); 7312 kernelp->arg = new_arg; 7313 BAM_DPRINTF((D_GET_SET_KERNEL_RESET_ARG_SET_KERNEL, 7314 fcn, kernelp->arg)); 7315 } 7316 rv = BAM_WRITE; 7317 goto done; 7318 } 7319 7320 /* 7321 * Expand the kernel file to a full path, if necessary 7322 */ 7323 if ((optnum == KERNEL_CMD) && (path[0] != '/')) { 7324 new_path = expand_path(path); 7325 if (new_path == NULL) { 7326 bam_error(UNKNOWN_KERNEL, path); 7327 BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 7328 return (BAM_ERROR); 7329 } 7330 free_new_path = 1; 7331 } else { 7332 new_path = path; 7333 free_new_path = 0; 7334 } 7335 7336 /* 7337 * At this point, we know we're setting a new value. First, take care 7338 * of the case where there was no previous entry. 7339 */ 7340 if (entryp == NULL) { 7341 7342 /* Similar to code in update_temp */ 7343 fstype = get_fstype("/"); 7344 INJECT_ERROR1("GET_SET_KERNEL_FSTYPE", fstype = NULL); 7345 if (fstype == NULL) { 7346 bam_error(BOOTENV_FSTYPE_FAILED); 7347 rv = BAM_ERROR; 7348 goto done; 7349 } 7350 7351 osdev = get_special("/"); 7352 INJECT_ERROR1("GET_SET_KERNEL_SPECIAL", osdev = NULL); 7353 if (osdev == NULL) { 7354 free(fstype); 7355 bam_error(BOOTENV_SPECIAL_FAILED); 7356 rv = BAM_ERROR; 7357 goto done; 7358 } 7359 7360 sign = find_existing_sign("/", osdev, fstype); 7361 INJECT_ERROR1("GET_SET_KERNEL_SIGN", sign = NULL); 7362 if (sign == NULL) { 7363 free(fstype); 7364 free(osdev); 7365 bam_error(BOOTENV_SIGN_FAILED); 7366 rv = BAM_ERROR; 7367 goto done; 7368 } 7369 7370 free(fstype); 7371 free(osdev); 7372 (void) strlcpy(signbuf, sign, sizeof (signbuf)); 7373 free(sign); 7374 assert(strchr(signbuf, '(') == NULL && 7375 strchr(signbuf, ',') == NULL && 7376 strchr(signbuf, ')') == NULL); 7377 7378 if (optnum == KERNEL_CMD) { 7379 BAM_DPRINTF((D_GET_SET_KERNEL_NEW_KERN, fcn, new_path)); 7380 entryNum = add_boot_entry(mp, BOOTENV_RC_TITLE, 7381 signbuf, new_path, NULL, NULL); 7382 } else { 7383 new_str_len = strlen(DIRECT_BOOT_KERNEL) + 7384 strlen(path) + 8; 7385 new_arg = s_calloc(1, new_str_len); 7386 7387 (void) snprintf(new_arg, new_str_len, "%s %s", 7388 DIRECT_BOOT_KERNEL, path); 7389 BAM_DPRINTF((D_GET_SET_KERNEL_NEW_ARG, fcn, new_arg)); 7390 entryNum = add_boot_entry(mp, BOOTENV_RC_TITLE, 7391 signbuf, new_arg, NULL, DIRECT_BOOT_ARCHIVE); 7392 free(new_arg); 7393 } 7394 INJECT_ERROR1("GET_SET_KERNEL_ADD_BOOT_ENTRY", 7395 entryNum = BAM_ERROR); 7396 if (entryNum == BAM_ERROR) { 7397 bam_error(GET_SET_KERNEL_ADD_BOOT_ENTRY, 7398 BOOTENV_RC_TITLE); 7399 rv = BAM_ERROR; 7400 goto done; 7401 } 7402 save_default_entry(mp, BAM_OLD_RC_DEF); 7403 ret = set_global(mp, menu_cmds[DEFAULT_CMD], entryNum); 7404 INJECT_ERROR1("GET_SET_KERNEL_SET_GLOBAL", ret = BAM_ERROR); 7405 if (ret == BAM_ERROR) { 7406 bam_error(GET_SET_KERNEL_SET_GLOBAL, entryNum); 7407 } 7408 rv = BAM_WRITE; 7409 goto done; 7410 } 7411 7412 /* 7413 * There was already an bootenv entry which we need to edit. 7414 */ 7415 if (optnum == KERNEL_CMD) { 7416 new_str_len = strlen(new_path) + strlen(old_args) + 2; 7417 new_arg = s_calloc(1, new_str_len); 7418 (void) snprintf(new_arg, new_str_len, "%s %s", new_path, 7419 old_args); 7420 free(kernelp->arg); 7421 kernelp->arg = new_arg; 7422 7423 /* 7424 * If we have changed the kernel line, we may need to update 7425 * the archive line as well. 7426 */ 7427 set_archive_line(entryp, kernelp); 7428 BAM_DPRINTF((D_GET_SET_KERNEL_REPLACED_KERNEL_SAME_ARG, fcn, 7429 kernelp->arg)); 7430 } else { 7431 new_str_len = old_kernel_len + strlen(path) + 8; 7432 new_arg = s_calloc(1, new_str_len); 7433 (void) strncpy(new_arg, kernelp->arg, old_kernel_len); 7434 (void) strlcat(new_arg, " ", new_str_len); 7435 (void) strlcat(new_arg, path, new_str_len); 7436 free(kernelp->arg); 7437 kernelp->arg = new_arg; 7438 BAM_DPRINTF((D_GET_SET_KERNEL_SAME_KERNEL_REPLACED_ARG, fcn, 7439 kernelp->arg)); 7440 } 7441 rv = BAM_WRITE; 7442 7443 done: 7444 if ((rv == BAM_WRITE) && kernelp) 7445 update_line(kernelp); 7446 if (free_new_path) 7447 free(new_path); 7448 if (rv == BAM_WRITE) { 7449 BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 7450 } else { 7451 BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 7452 } 7453 return (rv); 7454 } 7455 7456 static error_t 7457 get_kernel(menu_t *mp, menu_cmd_t optnum, char *buf, size_t bufsize) 7458 { 7459 const char *fcn = "get_kernel()"; 7460 BAM_DPRINTF((D_FUNC_ENTRY1, fcn, menu_cmds[optnum])); 7461 return (get_set_kernel(mp, optnum, NULL, buf, bufsize)); 7462 } 7463 7464 static error_t 7465 set_kernel(menu_t *mp, menu_cmd_t optnum, char *path, char *buf, size_t bufsize) 7466 { 7467 const char *fcn = "set_kernel()"; 7468 assert(path != NULL); 7469 BAM_DPRINTF((D_FUNC_ENTRY2, fcn, menu_cmds[optnum], path)); 7470 return (get_set_kernel(mp, optnum, path, buf, bufsize)); 7471 } 7472 7473 /*ARGSUSED*/ 7474 static error_t 7475 set_option(menu_t *mp, char *dummy, char *opt) 7476 { 7477 int optnum; 7478 int optval; 7479 char *val; 7480 char buf[BUFSIZ] = ""; 7481 error_t rv; 7482 const char *fcn = "set_option()"; 7483 7484 assert(mp); 7485 assert(opt); 7486 assert(dummy == NULL); 7487 7488 /* opt is set from bam_argv[0] and is always non-NULL */ 7489 BAM_DPRINTF((D_FUNC_ENTRY1, fcn, opt)); 7490 7491 val = strchr(opt, '='); 7492 if (val != NULL) { 7493 *val = '\0'; 7494 } 7495 7496 if (strcmp(opt, "default") == 0) { 7497 optnum = DEFAULT_CMD; 7498 } else if (strcmp(opt, "timeout") == 0) { 7499 optnum = TIMEOUT_CMD; 7500 } else if (strcmp(opt, menu_cmds[KERNEL_CMD]) == 0) { 7501 optnum = KERNEL_CMD; 7502 } else if (strcmp(opt, menu_cmds[ARGS_CMD]) == 0) { 7503 optnum = ARGS_CMD; 7504 } else { 7505 bam_error(INVALID_OPTION, opt); 7506 return (BAM_ERROR); 7507 } 7508 7509 /* 7510 * kernel and args are allowed without "=new_value" strings. All 7511 * others cause errors 7512 */ 7513 if ((val == NULL) && (optnum != KERNEL_CMD) && (optnum != ARGS_CMD)) { 7514 bam_error(NO_OPTION_ARG, opt); 7515 return (BAM_ERROR); 7516 } else if (val != NULL) { 7517 *val = '='; 7518 } 7519 7520 if ((optnum == KERNEL_CMD) || (optnum == ARGS_CMD)) { 7521 BAM_DPRINTF((D_SET_OPTION, fcn, menu_cmds[optnum], 7522 val ? val + 1 : "NULL")); 7523 7524 if (val) 7525 rv = set_kernel(mp, optnum, val + 1, buf, sizeof (buf)); 7526 else 7527 rv = get_kernel(mp, optnum, buf, sizeof (buf)); 7528 if ((rv == BAM_SUCCESS) && (buf[0] != '\0')) 7529 (void) printf("%s\n", buf); 7530 } else { 7531 optval = s_strtol(val + 1); 7532 BAM_DPRINTF((D_SET_OPTION, fcn, menu_cmds[optnum], val + 1)); 7533 rv = set_global(mp, menu_cmds[optnum], optval); 7534 } 7535 7536 if (rv == BAM_WRITE || rv == BAM_SUCCESS) { 7537 BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 7538 } else { 7539 BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 7540 } 7541 7542 return (rv); 7543 } 7544 7545 /* 7546 * The quiet argument suppresses messages. This is used 7547 * when invoked in the context of other commands (e.g. list_entry) 7548 */ 7549 static error_t 7550 read_globals(menu_t *mp, char *menu_path, char *globalcmd, int quiet) 7551 { 7552 line_t *lp; 7553 char *arg; 7554 int done, ret = BAM_SUCCESS; 7555 7556 assert(mp); 7557 assert(menu_path); 7558 assert(globalcmd); 7559 7560 if (mp->start == NULL) { 7561 if (!quiet) 7562 bam_error(NO_MENU, menu_path); 7563 return (BAM_ERROR); 7564 } 7565 7566 done = 0; 7567 for (lp = mp->start; lp; lp = lp->next) { 7568 if (lp->flags != BAM_GLOBAL) 7569 continue; 7570 7571 if (lp->cmd == NULL) { 7572 if (!quiet) 7573 bam_error(NO_CMD, lp->lineNum); 7574 continue; 7575 } 7576 7577 if (strcmp(globalcmd, lp->cmd) != 0) 7578 continue; 7579 7580 /* Found global. Check for duplicates */ 7581 if (done && !quiet) { 7582 bam_error(DUP_CMD, globalcmd, lp->lineNum, bam_root); 7583 ret = BAM_ERROR; 7584 } 7585 7586 arg = lp->arg ? lp->arg : ""; 7587 bam_print(GLOBAL_CMD, globalcmd, arg); 7588 done = 1; 7589 } 7590 7591 if (!done && bam_verbose) 7592 bam_print(NO_ENTRY, globalcmd); 7593 7594 return (ret); 7595 } 7596 7597 static error_t 7598 menu_write(char *root, menu_t *mp) 7599 { 7600 const char *fcn = "menu_write()"; 7601 7602 BAM_DPRINTF((D_MENU_WRITE_ENTER, fcn, root)); 7603 return (list2file(root, MENU_TMP, GRUB_MENU, mp->start)); 7604 } 7605 7606 void 7607 line_free(line_t *lp) 7608 { 7609 if (lp == NULL) 7610 return; 7611 7612 if (lp->cmd) 7613 free(lp->cmd); 7614 if (lp->sep) 7615 free(lp->sep); 7616 if (lp->arg) 7617 free(lp->arg); 7618 if (lp->line) 7619 free(lp->line); 7620 free(lp); 7621 } 7622 7623 static void 7624 linelist_free(line_t *start) 7625 { 7626 line_t *lp; 7627 7628 while (start) { 7629 lp = start; 7630 start = start->next; 7631 line_free(lp); 7632 } 7633 } 7634 7635 static void 7636 filelist_free(filelist_t *flistp) 7637 { 7638 linelist_free(flistp->head); 7639 flistp->head = NULL; 7640 flistp->tail = NULL; 7641 } 7642 7643 static void 7644 menu_free(menu_t *mp) 7645 { 7646 entry_t *ent, *tmp; 7647 assert(mp); 7648 7649 if (mp->start) 7650 linelist_free(mp->start); 7651 ent = mp->entries; 7652 while (ent) { 7653 tmp = ent; 7654 ent = tmp->next; 7655 free(tmp); 7656 } 7657 7658 free(mp); 7659 } 7660 7661 /* 7662 * Utility routines 7663 */ 7664 7665 7666 /* 7667 * Returns 0 on success 7668 * Any other value indicates an error 7669 */ 7670 static int 7671 exec_cmd(char *cmdline, filelist_t *flistp) 7672 { 7673 char buf[BUFSIZ]; 7674 int ret; 7675 FILE *ptr; 7676 sigset_t set; 7677 void (*disp)(int); 7678 7679 /* 7680 * For security 7681 * - only absolute paths are allowed 7682 * - set IFS to space and tab 7683 */ 7684 if (*cmdline != '/') { 7685 bam_error(ABS_PATH_REQ, cmdline); 7686 return (-1); 7687 } 7688 (void) putenv("IFS= \t"); 7689 7690 /* 7691 * We may have been exec'ed with SIGCHLD blocked 7692 * unblock it here 7693 */ 7694 (void) sigemptyset(&set); 7695 (void) sigaddset(&set, SIGCHLD); 7696 if (sigprocmask(SIG_UNBLOCK, &set, NULL) != 0) { 7697 bam_error(CANT_UNBLOCK_SIGCHLD, strerror(errno)); 7698 return (-1); 7699 } 7700 7701 /* 7702 * Set SIGCHLD disposition to SIG_DFL for popen/pclose 7703 */ 7704 disp = sigset(SIGCHLD, SIG_DFL); 7705 if (disp == SIG_ERR) { 7706 bam_error(FAILED_SIG, strerror(errno)); 7707 return (-1); 7708 } 7709 if (disp == SIG_HOLD) { 7710 bam_error(BLOCKED_SIG, cmdline); 7711 return (-1); 7712 } 7713 7714 ptr = popen(cmdline, "r"); 7715 if (ptr == NULL) { 7716 bam_error(POPEN_FAIL, cmdline, strerror(errno)); 7717 return (-1); 7718 } 7719 7720 /* 7721 * If we simply do a pclose() following a popen(), pclose() 7722 * will close the reader end of the pipe immediately even 7723 * if the child process has not started/exited. pclose() 7724 * does wait for cmd to terminate before returning though. 7725 * When the executed command writes its output to the pipe 7726 * there is no reader process and the command dies with 7727 * SIGPIPE. To avoid this we read repeatedly until read 7728 * terminates with EOF. This indicates that the command 7729 * (writer) has closed the pipe and we can safely do a 7730 * pclose(). 7731 * 7732 * Since pclose() does wait for the command to exit, 7733 * we can safely reap the exit status of the command 7734 * from the value returned by pclose() 7735 */ 7736 while (s_fgets(buf, sizeof (buf), ptr) != NULL) { 7737 if (flistp == NULL) { 7738 /* s_fgets strips newlines, so insert them at the end */ 7739 bam_print(PRINT, buf); 7740 } else { 7741 append_to_flist(flistp, buf); 7742 } 7743 } 7744 7745 ret = pclose(ptr); 7746 if (ret == -1) { 7747 bam_error(PCLOSE_FAIL, cmdline, strerror(errno)); 7748 return (-1); 7749 } 7750 7751 if (WIFEXITED(ret)) { 7752 return (WEXITSTATUS(ret)); 7753 } else { 7754 bam_error(EXEC_FAIL, cmdline, ret); 7755 return (-1); 7756 } 7757 } 7758 7759 /* 7760 * Since this function returns -1 on error 7761 * it cannot be used to convert -1. However, 7762 * that is sufficient for what we need. 7763 */ 7764 static long 7765 s_strtol(char *str) 7766 { 7767 long l; 7768 char *res = NULL; 7769 7770 if (str == NULL) { 7771 return (-1); 7772 } 7773 7774 errno = 0; 7775 l = strtol(str, &res, 10); 7776 if (errno || *res != '\0') { 7777 return (-1); 7778 } 7779 7780 return (l); 7781 } 7782 7783 /* 7784 * Wrapper around fputs, that adds a newline (since fputs doesn't) 7785 */ 7786 static int 7787 s_fputs(char *str, FILE *fp) 7788 { 7789 char linebuf[BAM_MAXLINE]; 7790 7791 (void) snprintf(linebuf, sizeof (linebuf), "%s\n", str); 7792 return (fputs(linebuf, fp)); 7793 } 7794 7795 /* 7796 * Wrapper around fgets, that strips newlines returned by fgets 7797 */ 7798 char * 7799 s_fgets(char *buf, int buflen, FILE *fp) 7800 { 7801 int n; 7802 7803 buf = fgets(buf, buflen, fp); 7804 if (buf) { 7805 n = strlen(buf); 7806 if (n == buflen - 1 && buf[n-1] != '\n') 7807 bam_error(TOO_LONG, buflen - 1, buf); 7808 buf[n-1] = (buf[n-1] == '\n') ? '\0' : buf[n-1]; 7809 } 7810 7811 return (buf); 7812 } 7813 7814 void * 7815 s_calloc(size_t nelem, size_t sz) 7816 { 7817 void *ptr; 7818 7819 ptr = calloc(nelem, sz); 7820 if (ptr == NULL) { 7821 bam_error(NO_MEM, nelem*sz); 7822 bam_exit(1); 7823 } 7824 return (ptr); 7825 } 7826 7827 void * 7828 s_realloc(void *ptr, size_t sz) 7829 { 7830 ptr = realloc(ptr, sz); 7831 if (ptr == NULL) { 7832 bam_error(NO_MEM, sz); 7833 bam_exit(1); 7834 } 7835 return (ptr); 7836 } 7837 7838 char * 7839 s_strdup(char *str) 7840 { 7841 char *ptr; 7842 7843 if (str == NULL) 7844 return (NULL); 7845 7846 ptr = strdup(str); 7847 if (ptr == NULL) { 7848 bam_error(NO_MEM, strlen(str) + 1); 7849 bam_exit(1); 7850 } 7851 return (ptr); 7852 } 7853 7854 /* 7855 * Returns 1 if amd64 (or sparc, for syncing x86 diskless clients) 7856 * Returns 0 otherwise 7857 */ 7858 static int 7859 is_amd64(void) 7860 { 7861 static int amd64 = -1; 7862 char isabuf[257]; /* from sysinfo(2) manpage */ 7863 7864 if (amd64 != -1) 7865 return (amd64); 7866 7867 if (bam_alt_platform) { 7868 if (strcmp(bam_platform, "i86pc") == 0) { 7869 amd64 = 1; /* diskless server */ 7870 } 7871 } else { 7872 if (sysinfo(SI_ISALIST, isabuf, sizeof (isabuf)) > 0 && 7873 strncmp(isabuf, "amd64 ", strlen("amd64 ")) == 0) { 7874 amd64 = 1; 7875 } else if (strstr(isabuf, "i386") == NULL) { 7876 amd64 = 1; /* diskless server */ 7877 } 7878 } 7879 if (amd64 == -1) 7880 amd64 = 0; 7881 7882 return (amd64); 7883 } 7884 7885 static char * 7886 get_machine(void) 7887 { 7888 static int cached = -1; 7889 static char mbuf[257]; /* from sysinfo(2) manpage */ 7890 7891 if (cached == 0) 7892 return (mbuf); 7893 7894 if (bam_alt_platform) { 7895 return (bam_platform); 7896 } else { 7897 if (sysinfo(SI_MACHINE, mbuf, sizeof (mbuf)) > 0) { 7898 cached = 1; 7899 } 7900 } 7901 if (cached == -1) { 7902 mbuf[0] = '\0'; 7903 cached = 0; 7904 } 7905 7906 return (mbuf); 7907 } 7908 7909 int 7910 is_sparc(void) 7911 { 7912 static int issparc = -1; 7913 char mbuf[257]; /* from sysinfo(2) manpage */ 7914 7915 if (issparc != -1) 7916 return (issparc); 7917 7918 if (bam_alt_platform) { 7919 if (strncmp(bam_platform, "sun4", 4) == 0) { 7920 issparc = 1; 7921 } 7922 } else { 7923 if (sysinfo(SI_ARCHITECTURE, mbuf, sizeof (mbuf)) > 0 && 7924 strcmp(mbuf, "sparc") == 0) { 7925 issparc = 1; 7926 } 7927 } 7928 if (issparc == -1) 7929 issparc = 0; 7930 7931 return (issparc); 7932 } 7933 7934 static void 7935 append_to_flist(filelist_t *flistp, char *s) 7936 { 7937 line_t *lp; 7938 7939 lp = s_calloc(1, sizeof (line_t)); 7940 lp->line = s_strdup(s); 7941 if (flistp->head == NULL) 7942 flistp->head = lp; 7943 else 7944 flistp->tail->next = lp; 7945 flistp->tail = lp; 7946 } 7947 7948 #if !defined(_OPB) 7949 7950 UCODE_VENDORS; 7951 7952 /*ARGSUSED*/ 7953 static void 7954 ucode_install(char *root) 7955 { 7956 int i; 7957 7958 for (i = 0; ucode_vendors[i].filestr != NULL; i++) { 7959 int cmd_len = PATH_MAX + 256; 7960 char cmd[PATH_MAX + 256]; 7961 char file[PATH_MAX]; 7962 char timestamp[PATH_MAX]; 7963 struct stat fstatus, tstatus; 7964 struct utimbuf u_times; 7965 7966 (void) snprintf(file, PATH_MAX, "%s/%s/%s-ucode.%s", 7967 bam_root, UCODE_INSTALL_PATH, ucode_vendors[i].filestr, 7968 ucode_vendors[i].extstr); 7969 7970 if (stat(file, &fstatus) != 0 || !(S_ISREG(fstatus.st_mode))) 7971 continue; 7972 7973 (void) snprintf(timestamp, PATH_MAX, "%s.ts", file); 7974 7975 if (stat(timestamp, &tstatus) == 0 && 7976 fstatus.st_mtime <= tstatus.st_mtime) 7977 continue; 7978 7979 (void) snprintf(cmd, cmd_len, "/usr/sbin/ucodeadm -i -R " 7980 "%s/%s/%s %s > /dev/null 2>&1", bam_root, 7981 UCODE_INSTALL_PATH, ucode_vendors[i].vendorstr, file); 7982 if (system(cmd) != 0) 7983 return; 7984 7985 if (creat(timestamp, S_IRUSR | S_IWUSR) == -1) 7986 return; 7987 7988 u_times.actime = fstatus.st_atime; 7989 u_times.modtime = fstatus.st_mtime; 7990 (void) utime(timestamp, &u_times); 7991 } 7992 } 7993 #endif 7994