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 2008 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 (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 { 2628 BAM_DPRINTF((D_IS_UNKNOWN_KERNEL, fcn, arg)); 2629 bam_error(UNKNOWN_KERNEL_LINE, linenum); 2630 return (BAM_ERROR); 2631 } 2632 2633 return (BAM_SUCCESS); 2634 } 2635 2636 static error_t 2637 module_parser(entry_t *entry, char *cmd, char *arg, int linenum) 2638 { 2639 const char *fcn = "module_parser()"; 2640 2641 assert(entry); 2642 assert(cmd); 2643 assert(arg); 2644 2645 if (strcmp(cmd, menu_cmds[MODULE_CMD]) != 0 && 2646 strcmp(cmd, menu_cmds[MODULE_DOLLAR_CMD]) != 0) { 2647 BAM_DPRINTF((D_NOT_MODULE_CMD, fcn, cmd)); 2648 return (BAM_ERROR); 2649 } 2650 2651 if (strcmp(arg, DIRECT_BOOT_ARCHIVE) == 0 || 2652 strcmp(arg, DIRECT_BOOT_ARCHIVE_32) == 0 || 2653 strcmp(arg, DIRECT_BOOT_ARCHIVE_64) == 0 || 2654 strcmp(arg, MULTIBOOT_ARCHIVE) == 0 || 2655 strcmp(arg, FAILSAFE_ARCHIVE) == 0 || 2656 strcmp(arg, FAILSAFE_ARCHIVE_32) == 0 || 2657 strcmp(arg, FAILSAFE_ARCHIVE_64) == 0 || 2658 strcmp(arg, XEN_KERNEL_MODULE_LINE) == 0 || 2659 strcmp(arg, XEN_KERNEL_MODULE_LINE_ZFS) == 0) { 2660 BAM_DPRINTF((D_BOOTADM_LU_MODULE, fcn, arg)); 2661 return (BAM_SUCCESS); 2662 } else if (!(entry->flags & BAM_ENTRY_BOOTADM) && 2663 !(entry->flags & BAM_ENTRY_LU)) { 2664 /* don't emit warning for hand entries */ 2665 BAM_DPRINTF((D_IS_HAND_MODULE, fcn, arg)); 2666 return (BAM_ERROR); 2667 } else { 2668 BAM_DPRINTF((D_IS_UNKNOWN_MODULE, fcn, arg)); 2669 bam_error(UNKNOWN_MODULE_LINE, linenum); 2670 return (BAM_ERROR); 2671 } 2672 } 2673 2674 /* 2675 * A line in menu.lst looks like 2676 * [ ]*<cmd>[ \t=]*<arg>* 2677 */ 2678 static void 2679 line_parser(menu_t *mp, char *str, int *lineNum, int *entryNum) 2680 { 2681 /* 2682 * save state across calls. This is so that 2683 * header gets the right entry# after title has 2684 * been processed 2685 */ 2686 static line_t *prev = NULL; 2687 static entry_t *curr_ent = NULL; 2688 static int in_liveupgrade = 0; 2689 2690 line_t *lp; 2691 char *cmd, *sep, *arg; 2692 char save, *cp, *line; 2693 menu_flag_t flag = BAM_INVALID; 2694 const char *fcn = "line_parser()"; 2695 2696 if (str == NULL) { 2697 return; 2698 } 2699 2700 /* 2701 * First save a copy of the entire line. 2702 * We use this later to set the line field. 2703 */ 2704 line = s_strdup(str); 2705 2706 /* Eat up leading whitespace */ 2707 while (*str == ' ' || *str == '\t') 2708 str++; 2709 2710 if (*str == '#') { /* comment */ 2711 cmd = s_strdup("#"); 2712 sep = NULL; 2713 arg = s_strdup(str + 1); 2714 flag = BAM_COMMENT; 2715 if (strstr(arg, BAM_LU_HDR) != NULL) { 2716 in_liveupgrade = 1; 2717 } else if (strstr(arg, BAM_LU_FTR) != NULL) { 2718 in_liveupgrade = 0; 2719 } 2720 } else if (*str == '\0') { /* blank line */ 2721 cmd = sep = arg = NULL; 2722 flag = BAM_EMPTY; 2723 } else { 2724 /* 2725 * '=' is not a documented separator in grub syntax. 2726 * However various development bits use '=' as a 2727 * separator. In addition, external users also 2728 * use = as a separator. So we will allow that usage. 2729 */ 2730 cp = str; 2731 while (*str != ' ' && *str != '\t' && *str != '=') { 2732 if (*str == '\0') { 2733 cmd = s_strdup(cp); 2734 sep = arg = NULL; 2735 break; 2736 } 2737 str++; 2738 } 2739 2740 if (*str != '\0') { 2741 save = *str; 2742 *str = '\0'; 2743 cmd = s_strdup(cp); 2744 *str = save; 2745 2746 str++; 2747 save = *str; 2748 *str = '\0'; 2749 sep = s_strdup(str - 1); 2750 *str = save; 2751 2752 while (*str == ' ' || *str == '\t') 2753 str++; 2754 if (*str == '\0') 2755 arg = NULL; 2756 else 2757 arg = s_strdup(str); 2758 } 2759 } 2760 2761 lp = s_calloc(1, sizeof (line_t)); 2762 2763 lp->cmd = cmd; 2764 lp->sep = sep; 2765 lp->arg = arg; 2766 lp->line = line; 2767 lp->lineNum = ++(*lineNum); 2768 if (cmd && strcmp(cmd, menu_cmds[TITLE_CMD]) == 0) { 2769 lp->entryNum = ++(*entryNum); 2770 lp->flags = BAM_TITLE; 2771 if (prev && prev->flags == BAM_COMMENT && 2772 prev->arg && strcmp(prev->arg, BAM_BOOTADM_HDR) == 0) { 2773 prev->entryNum = lp->entryNum; 2774 curr_ent = boot_entry_new(mp, prev, lp); 2775 curr_ent->flags |= BAM_ENTRY_BOOTADM; 2776 BAM_DPRINTF((D_IS_BOOTADM_ENTRY, fcn, arg)); 2777 } else { 2778 curr_ent = boot_entry_new(mp, lp, lp); 2779 if (in_liveupgrade) { 2780 curr_ent->flags |= BAM_ENTRY_LU; 2781 BAM_DPRINTF((D_IS_LU_ENTRY, fcn, arg)); 2782 } 2783 } 2784 curr_ent->entryNum = *entryNum; 2785 } else if (flag != BAM_INVALID) { 2786 /* 2787 * For header comments, the entry# is "fixed up" 2788 * by the subsequent title 2789 */ 2790 lp->entryNum = *entryNum; 2791 lp->flags = flag; 2792 } else { 2793 lp->entryNum = *entryNum; 2794 2795 if (*entryNum == ENTRY_INIT) { 2796 lp->flags = BAM_GLOBAL; 2797 } else { 2798 lp->flags = BAM_ENTRY; 2799 2800 if (cmd && arg) { 2801 if (strcmp(cmd, menu_cmds[ROOT_CMD]) == 0) { 2802 BAM_DPRINTF((D_IS_ROOT_CMD, fcn, arg)); 2803 curr_ent->flags |= BAM_ENTRY_ROOT; 2804 } else if (strcmp(cmd, menu_cmds[FINDROOT_CMD]) 2805 == 0) { 2806 BAM_DPRINTF((D_IS_FINDROOT_CMD, fcn, 2807 arg)); 2808 curr_ent->flags |= BAM_ENTRY_FINDROOT; 2809 } else if (strcmp(cmd, 2810 menu_cmds[CHAINLOADER_CMD]) == 0) { 2811 BAM_DPRINTF((D_IS_CHAINLOADER_CMD, fcn, 2812 arg)); 2813 curr_ent->flags |= 2814 BAM_ENTRY_CHAINLOADER; 2815 } else if (kernel_parser(curr_ent, cmd, arg, 2816 lp->lineNum) != BAM_SUCCESS) { 2817 (void) module_parser(curr_ent, cmd, 2818 arg, lp->lineNum); 2819 } 2820 } 2821 } 2822 } 2823 2824 /* record default, old default, and entry line ranges */ 2825 if (lp->flags == BAM_GLOBAL && 2826 strcmp(lp->cmd, menu_cmds[DEFAULT_CMD]) == 0) { 2827 mp->curdefault = lp; 2828 } else if (lp->flags == BAM_COMMENT && 2829 strncmp(lp->arg, BAM_OLDDEF, strlen(BAM_OLDDEF)) == 0) { 2830 mp->olddefault = lp; 2831 } else if (lp->flags == BAM_COMMENT && 2832 strncmp(lp->arg, BAM_OLD_RC_DEF, strlen(BAM_OLD_RC_DEF)) == 0) { 2833 mp->old_rc_default = lp; 2834 } else if (lp->flags == BAM_ENTRY || 2835 (lp->flags == BAM_COMMENT && 2836 strcmp(lp->arg, BAM_BOOTADM_FTR) == 0)) { 2837 boot_entry_addline(curr_ent, lp); 2838 } 2839 append_line(mp, lp); 2840 2841 prev = lp; 2842 } 2843 2844 void 2845 update_numbering(menu_t *mp) 2846 { 2847 int lineNum; 2848 int entryNum; 2849 int old_default_value; 2850 line_t *lp, *prev, *default_lp, *default_entry; 2851 char buf[PATH_MAX]; 2852 2853 if (mp->start == NULL) { 2854 return; 2855 } 2856 2857 lineNum = LINE_INIT; 2858 entryNum = ENTRY_INIT; 2859 old_default_value = ENTRY_INIT; 2860 lp = default_lp = default_entry = NULL; 2861 2862 prev = NULL; 2863 for (lp = mp->start; lp; prev = lp, lp = lp->next) { 2864 lp->lineNum = ++lineNum; 2865 2866 /* 2867 * Get the value of the default command 2868 */ 2869 if (lp->entryNum == ENTRY_INIT && lp->cmd && 2870 strcmp(lp->cmd, menu_cmds[DEFAULT_CMD]) == 0 && 2871 lp->arg) { 2872 old_default_value = atoi(lp->arg); 2873 default_lp = lp; 2874 } 2875 2876 /* 2877 * If not a booting entry, nothing else to fix for this 2878 * entry 2879 */ 2880 if (lp->entryNum == ENTRY_INIT) 2881 continue; 2882 2883 /* 2884 * Record the position of the default entry. 2885 * The following works because global 2886 * commands like default and timeout should precede 2887 * actual boot entries, so old_default_value 2888 * is already known (or default cmd is missing). 2889 */ 2890 if (default_entry == NULL && 2891 old_default_value != ENTRY_INIT && 2892 lp->entryNum == old_default_value) { 2893 default_entry = lp; 2894 } 2895 2896 /* 2897 * Now fixup the entry number 2898 */ 2899 if (lp->cmd && strcmp(lp->cmd, menu_cmds[TITLE_CMD]) == 0) { 2900 lp->entryNum = ++entryNum; 2901 /* fixup the bootadm header */ 2902 if (prev && prev->flags == BAM_COMMENT && 2903 prev->arg && 2904 strcmp(prev->arg, BAM_BOOTADM_HDR) == 0) { 2905 prev->entryNum = lp->entryNum; 2906 } 2907 } else { 2908 lp->entryNum = entryNum; 2909 } 2910 } 2911 2912 /* 2913 * No default command in menu, simply return 2914 */ 2915 if (default_lp == NULL) { 2916 return; 2917 } 2918 2919 free(default_lp->arg); 2920 free(default_lp->line); 2921 2922 if (default_entry == NULL) { 2923 default_lp->arg = s_strdup("0"); 2924 } else { 2925 (void) snprintf(buf, sizeof (buf), "%d", 2926 default_entry->entryNum); 2927 default_lp->arg = s_strdup(buf); 2928 } 2929 2930 /* 2931 * The following is required since only the line field gets 2932 * written back to menu.lst 2933 */ 2934 (void) snprintf(buf, sizeof (buf), "%s%s%s", 2935 menu_cmds[DEFAULT_CMD], menu_cmds[SEP_CMD], default_lp->arg); 2936 default_lp->line = s_strdup(buf); 2937 } 2938 2939 2940 static menu_t * 2941 menu_read(char *menu_path) 2942 { 2943 FILE *fp; 2944 char buf[BAM_MAXLINE], *cp; 2945 menu_t *mp; 2946 int line, entry, len, n; 2947 2948 mp = s_calloc(1, sizeof (menu_t)); 2949 2950 fp = fopen(menu_path, "r"); 2951 if (fp == NULL) { /* Let the caller handle this error */ 2952 return (mp); 2953 } 2954 2955 2956 /* Note: GRUB boot entry number starts with 0 */ 2957 line = LINE_INIT; 2958 entry = ENTRY_INIT; 2959 cp = buf; 2960 len = sizeof (buf); 2961 while (s_fgets(cp, len, fp) != NULL) { 2962 n = strlen(cp); 2963 if (cp[n - 1] == '\\') { 2964 len -= n - 1; 2965 assert(len >= 2); 2966 cp += n - 1; 2967 continue; 2968 } 2969 line_parser(mp, buf, &line, &entry); 2970 cp = buf; 2971 len = sizeof (buf); 2972 } 2973 2974 if (fclose(fp) == EOF) { 2975 bam_error(CLOSE_FAIL, menu_path, strerror(errno)); 2976 } 2977 2978 return (mp); 2979 } 2980 2981 static error_t 2982 selector(menu_t *mp, char *opt, int *entry, char **title) 2983 { 2984 char *eq; 2985 char *opt_dup; 2986 int entryNum; 2987 2988 assert(mp); 2989 assert(mp->start); 2990 assert(opt); 2991 2992 opt_dup = s_strdup(opt); 2993 2994 if (entry) 2995 *entry = ENTRY_INIT; 2996 if (title) 2997 *title = NULL; 2998 2999 eq = strchr(opt_dup, '='); 3000 if (eq == NULL) { 3001 bam_error(INVALID_OPT, opt); 3002 free(opt_dup); 3003 return (BAM_ERROR); 3004 } 3005 3006 *eq = '\0'; 3007 if (entry && strcmp(opt_dup, OPT_ENTRY_NUM) == 0) { 3008 assert(mp->end); 3009 entryNum = s_strtol(eq + 1); 3010 if (entryNum < 0 || entryNum > mp->end->entryNum) { 3011 bam_error(INVALID_ENTRY, eq + 1); 3012 free(opt_dup); 3013 return (BAM_ERROR); 3014 } 3015 *entry = entryNum; 3016 } else if (title && strcmp(opt_dup, menu_cmds[TITLE_CMD]) == 0) { 3017 *title = opt + (eq - opt_dup) + 1; 3018 } else { 3019 bam_error(INVALID_OPT, opt); 3020 free(opt_dup); 3021 return (BAM_ERROR); 3022 } 3023 3024 free(opt_dup); 3025 return (BAM_SUCCESS); 3026 } 3027 3028 /* 3029 * If invoked with no titles/entries (opt == NULL) 3030 * only title lines in file are printed. 3031 * 3032 * If invoked with a title or entry #, all 3033 * lines in *every* matching entry are listed 3034 */ 3035 static error_t 3036 list_entry(menu_t *mp, char *menu_path, char *opt) 3037 { 3038 line_t *lp; 3039 int entry = ENTRY_INIT; 3040 int found; 3041 char *title = NULL; 3042 3043 assert(mp); 3044 assert(menu_path); 3045 3046 /* opt is optional */ 3047 BAM_DPRINTF((D_FUNC_ENTRY2, "list_entry", menu_path, 3048 opt ? opt : "<NULL>")); 3049 3050 if (mp->start == NULL) { 3051 bam_error(NO_MENU, menu_path); 3052 return (BAM_ERROR); 3053 } 3054 3055 if (opt != NULL) { 3056 if (selector(mp, opt, &entry, &title) != BAM_SUCCESS) { 3057 return (BAM_ERROR); 3058 } 3059 assert((entry != ENTRY_INIT) ^ (title != NULL)); 3060 } else { 3061 (void) read_globals(mp, menu_path, menu_cmds[DEFAULT_CMD], 0); 3062 (void) read_globals(mp, menu_path, menu_cmds[TIMEOUT_CMD], 0); 3063 } 3064 3065 found = 0; 3066 for (lp = mp->start; lp; lp = lp->next) { 3067 if (lp->flags == BAM_COMMENT || lp->flags == BAM_EMPTY) 3068 continue; 3069 if (opt == NULL && lp->flags == BAM_TITLE) { 3070 bam_print(PRINT_TITLE, lp->entryNum, 3071 lp->arg); 3072 found = 1; 3073 continue; 3074 } 3075 if (entry != ENTRY_INIT && lp->entryNum == entry) { 3076 bam_print(PRINT, lp->line); 3077 found = 1; 3078 continue; 3079 } 3080 3081 /* 3082 * We set the entry value here so that all lines 3083 * in entry get printed. If we subsequently match 3084 * title in other entries, all lines in those 3085 * entries get printed as well. 3086 */ 3087 if (title && lp->flags == BAM_TITLE && lp->arg && 3088 strncmp(title, lp->arg, strlen(title)) == 0) { 3089 bam_print(PRINT, lp->line); 3090 entry = lp->entryNum; 3091 found = 1; 3092 continue; 3093 } 3094 } 3095 3096 if (!found) { 3097 bam_error(NO_MATCH_ENTRY); 3098 return (BAM_ERROR); 3099 } 3100 3101 return (BAM_SUCCESS); 3102 } 3103 3104 int 3105 add_boot_entry(menu_t *mp, 3106 char *title, 3107 char *findroot, 3108 char *kernel, 3109 char *mod_kernel, 3110 char *module) 3111 { 3112 int lineNum; 3113 int entryNum; 3114 char linebuf[BAM_MAXLINE]; 3115 menu_cmd_t k_cmd; 3116 menu_cmd_t m_cmd; 3117 const char *fcn = "add_boot_entry()"; 3118 3119 assert(mp); 3120 3121 INJECT_ERROR1("ADD_BOOT_ENTRY_FINDROOT_NULL", findroot = NULL); 3122 if (findroot == NULL) { 3123 bam_error(NULL_FINDROOT); 3124 return (BAM_ERROR); 3125 } 3126 3127 if (title == NULL) { 3128 title = "Solaris"; /* default to Solaris */ 3129 } 3130 if (kernel == NULL) { 3131 bam_error(SUBOPT_MISS, menu_cmds[KERNEL_CMD]); 3132 return (BAM_ERROR); 3133 } 3134 if (module == NULL) { 3135 if (bam_direct != BAM_DIRECT_DBOOT) { 3136 bam_error(SUBOPT_MISS, menu_cmds[MODULE_CMD]); 3137 return (BAM_ERROR); 3138 } 3139 3140 /* Figure the commands out from the kernel line */ 3141 if (strstr(kernel, "$ISADIR") != NULL) { 3142 module = DIRECT_BOOT_ARCHIVE; 3143 k_cmd = KERNEL_DOLLAR_CMD; 3144 m_cmd = MODULE_DOLLAR_CMD; 3145 } else if (strstr(kernel, "amd64") != NULL) { 3146 module = DIRECT_BOOT_ARCHIVE_64; 3147 k_cmd = KERNEL_CMD; 3148 m_cmd = MODULE_CMD; 3149 } else { 3150 module = DIRECT_BOOT_ARCHIVE_32; 3151 k_cmd = KERNEL_CMD; 3152 m_cmd = MODULE_CMD; 3153 } 3154 } else if ((bam_direct == BAM_DIRECT_DBOOT) && 3155 (strstr(kernel, "$ISADIR") != NULL)) { 3156 /* 3157 * If it's a non-failsafe dboot kernel, use the "kernel$" 3158 * command. Otherwise, use "kernel". 3159 */ 3160 k_cmd = KERNEL_DOLLAR_CMD; 3161 m_cmd = MODULE_DOLLAR_CMD; 3162 } else { 3163 k_cmd = KERNEL_CMD; 3164 m_cmd = MODULE_CMD; 3165 } 3166 3167 if (mp->start) { 3168 lineNum = mp->end->lineNum; 3169 entryNum = mp->end->entryNum; 3170 } else { 3171 lineNum = LINE_INIT; 3172 entryNum = ENTRY_INIT; 3173 } 3174 3175 /* 3176 * No separator for comment (HDR/FTR) commands 3177 * The syntax for comments is #<comment> 3178 */ 3179 (void) snprintf(linebuf, sizeof (linebuf), "%s%s", 3180 menu_cmds[COMMENT_CMD], BAM_BOOTADM_HDR); 3181 line_parser(mp, linebuf, &lineNum, &entryNum); 3182 3183 (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s", 3184 menu_cmds[TITLE_CMD], menu_cmds[SEP_CMD], title); 3185 line_parser(mp, linebuf, &lineNum, &entryNum); 3186 3187 (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s", 3188 menu_cmds[FINDROOT_CMD], menu_cmds[SEP_CMD], findroot); 3189 line_parser(mp, linebuf, &lineNum, &entryNum); 3190 BAM_DPRINTF((D_ADD_FINDROOT_NUM, fcn, lineNum, entryNum)); 3191 3192 (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s", 3193 menu_cmds[k_cmd], menu_cmds[SEP_CMD], kernel); 3194 line_parser(mp, linebuf, &lineNum, &entryNum); 3195 3196 if (mod_kernel != NULL) { 3197 (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s", 3198 menu_cmds[m_cmd], menu_cmds[SEP_CMD], mod_kernel); 3199 line_parser(mp, linebuf, &lineNum, &entryNum); 3200 } 3201 3202 (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s", 3203 menu_cmds[m_cmd], menu_cmds[SEP_CMD], module); 3204 line_parser(mp, linebuf, &lineNum, &entryNum); 3205 3206 (void) snprintf(linebuf, sizeof (linebuf), "%s%s", 3207 menu_cmds[COMMENT_CMD], BAM_BOOTADM_FTR); 3208 line_parser(mp, linebuf, &lineNum, &entryNum); 3209 3210 return (entryNum); 3211 } 3212 3213 static error_t 3214 do_delete(menu_t *mp, int entryNum) 3215 { 3216 line_t *lp; 3217 line_t *freed; 3218 entry_t *ent; 3219 entry_t *tmp; 3220 int deleted; 3221 const char *fcn = "do_delete()"; 3222 3223 assert(entryNum != ENTRY_INIT); 3224 3225 tmp = NULL; 3226 3227 ent = mp->entries; 3228 while (ent) { 3229 lp = ent->start; 3230 /* check entry number and make sure it's a bootadm entry */ 3231 if (lp->flags != BAM_COMMENT || 3232 strcmp(lp->arg, BAM_BOOTADM_HDR) != 0 || 3233 (entryNum != ALL_ENTRIES && lp->entryNum != entryNum)) { 3234 ent = ent->next; 3235 continue; 3236 } 3237 3238 /* free the entry content */ 3239 do { 3240 freed = lp; 3241 lp = lp->next; /* prev stays the same */ 3242 BAM_DPRINTF((D_FREEING_LINE, fcn, freed->lineNum)); 3243 unlink_line(mp, freed); 3244 line_free(freed); 3245 } while (freed != ent->end); 3246 3247 /* free the entry_t structure */ 3248 assert(tmp == NULL); 3249 tmp = ent; 3250 ent = ent->next; 3251 if (tmp->prev) 3252 tmp->prev->next = ent; 3253 else 3254 mp->entries = ent; 3255 if (ent) 3256 ent->prev = tmp->prev; 3257 BAM_DPRINTF((D_FREEING_ENTRY, fcn, tmp->entryNum)); 3258 free(tmp); 3259 tmp = NULL; 3260 deleted = 1; 3261 } 3262 3263 assert(tmp == NULL); 3264 3265 if (!deleted && entryNum != ALL_ENTRIES) { 3266 bam_error(NO_BOOTADM_MATCH); 3267 return (BAM_ERROR); 3268 } 3269 3270 /* 3271 * Now that we have deleted an entry, update 3272 * the entry numbering and the default cmd. 3273 */ 3274 update_numbering(mp); 3275 3276 return (BAM_SUCCESS); 3277 } 3278 3279 static error_t 3280 delete_all_entries(menu_t *mp, char *dummy, char *opt) 3281 { 3282 assert(mp); 3283 assert(dummy == NULL); 3284 assert(opt == NULL); 3285 3286 BAM_DPRINTF((D_FUNC_ENTRY0, "delete_all_entries")); 3287 3288 if (mp->start == NULL) { 3289 bam_print(EMPTY_MENU); 3290 return (BAM_SUCCESS); 3291 } 3292 3293 if (do_delete(mp, ALL_ENTRIES) != BAM_SUCCESS) { 3294 return (BAM_ERROR); 3295 } 3296 3297 return (BAM_WRITE); 3298 } 3299 3300 static FILE * 3301 create_diskmap(char *osroot) 3302 { 3303 FILE *fp; 3304 char cmd[PATH_MAX]; 3305 const char *fcn = "create_diskmap()"; 3306 3307 /* make sure we have a map file */ 3308 fp = fopen(GRUBDISK_MAP, "r"); 3309 if (fp == NULL) { 3310 (void) snprintf(cmd, sizeof (cmd), 3311 "%s/%s > /dev/null", osroot, CREATE_DISKMAP); 3312 if (exec_cmd(cmd, NULL) != 0) 3313 return (NULL); 3314 fp = fopen(GRUBDISK_MAP, "r"); 3315 INJECT_ERROR1("DISKMAP_CREATE_FAIL", fp = NULL); 3316 if (fp) { 3317 BAM_DPRINTF((D_CREATED_DISKMAP, fcn, GRUBDISK_MAP)); 3318 } else { 3319 BAM_DPRINTF((D_CREATE_DISKMAP_FAIL, fcn, GRUBDISK_MAP)); 3320 } 3321 } 3322 return (fp); 3323 } 3324 3325 #define SECTOR_SIZE 512 3326 3327 static int 3328 get_partition(char *device) 3329 { 3330 int i, fd, is_pcfs, partno = -1; 3331 struct mboot *mboot; 3332 char boot_sect[SECTOR_SIZE]; 3333 char *wholedisk, *slice; 3334 3335 /* form whole disk (p0) */ 3336 slice = device + strlen(device) - 2; 3337 is_pcfs = (*slice != 's'); 3338 if (!is_pcfs) 3339 *slice = '\0'; 3340 wholedisk = s_calloc(1, strlen(device) + 3); 3341 (void) snprintf(wholedisk, strlen(device) + 3, "%sp0", device); 3342 if (!is_pcfs) 3343 *slice = 's'; 3344 3345 /* read boot sector */ 3346 fd = open(wholedisk, O_RDONLY); 3347 free(wholedisk); 3348 if (fd == -1 || read(fd, boot_sect, SECTOR_SIZE) != SECTOR_SIZE) { 3349 return (partno); 3350 } 3351 (void) close(fd); 3352 3353 /* parse fdisk table */ 3354 mboot = (struct mboot *)((void *)boot_sect); 3355 for (i = 0; i < FD_NUMPART; i++) { 3356 struct ipart *part = 3357 (struct ipart *)(uintptr_t)mboot->parts + i; 3358 if (is_pcfs) { /* looking for solaris boot part */ 3359 if (part->systid == 0xbe) { 3360 partno = i; 3361 break; 3362 } 3363 } else { /* look for solaris partition, old and new */ 3364 if (part->systid == SUNIXOS || 3365 part->systid == SUNIXOS2) { 3366 partno = i; 3367 break; 3368 } 3369 } 3370 } 3371 return (partno); 3372 } 3373 3374 char * 3375 get_grubroot(char *osroot, char *osdev, char *menu_root) 3376 { 3377 char *grubroot; /* (hd#,#,#) */ 3378 char *slice; 3379 char *grubhd; 3380 int fdiskpart; 3381 int found = 0; 3382 char *devname; 3383 char *ctdname = strstr(osdev, "dsk/"); 3384 char linebuf[PATH_MAX]; 3385 FILE *fp; 3386 const char *fcn = "get_grubroot()"; 3387 3388 INJECT_ERROR1("GRUBROOT_INVALID_OSDEV", ctdname = NULL); 3389 if (ctdname == NULL) { 3390 bam_error(INVALID_DEV_DSK, osdev); 3391 return (NULL); 3392 } 3393 3394 if (menu_root && !menu_on_bootdisk(osroot, menu_root)) { 3395 /* menu bears no resemblance to our reality */ 3396 bam_error(CANNOT_GRUBROOT_BOOTDISK, fcn, osdev); 3397 return (NULL); 3398 } 3399 3400 ctdname += strlen("dsk/"); 3401 slice = strrchr(ctdname, 's'); 3402 if (slice) 3403 *slice = '\0'; 3404 3405 fp = create_diskmap(osroot); 3406 if (fp == NULL) { 3407 bam_error(DISKMAP_FAIL, osroot); 3408 return (NULL); 3409 } 3410 3411 rewind(fp); 3412 while (s_fgets(linebuf, sizeof (linebuf), fp) != NULL) { 3413 grubhd = strtok(linebuf, " \t\n"); 3414 if (grubhd) 3415 devname = strtok(NULL, " \t\n"); 3416 else 3417 devname = NULL; 3418 if (devname && strcmp(devname, ctdname) == 0) { 3419 found = 1; 3420 break; 3421 } 3422 } 3423 3424 if (slice) 3425 *slice = 's'; 3426 3427 (void) fclose(fp); 3428 fp = NULL; 3429 3430 INJECT_ERROR1("GRUBROOT_BIOSDEV_FAIL", found = 0); 3431 if (found == 0) { 3432 bam_error(BIOSDEV_FAIL, osdev); 3433 return (NULL); 3434 } 3435 3436 fdiskpart = get_partition(osdev); 3437 INJECT_ERROR1("GRUBROOT_FDISK_FAIL", fdiskpart = -1); 3438 if (fdiskpart == -1) { 3439 bam_error(FDISKPART_FAIL, osdev); 3440 return (NULL); 3441 } 3442 3443 grubroot = s_calloc(1, 10); 3444 if (slice) { 3445 (void) snprintf(grubroot, 10, "(hd%s,%d,%c)", 3446 grubhd, fdiskpart, slice[1] + 'a' - '0'); 3447 } else 3448 (void) snprintf(grubroot, 10, "(hd%s,%d)", 3449 grubhd, fdiskpart); 3450 3451 assert(fp == NULL); 3452 assert(strncmp(grubroot, "(hd", strlen("(hd")) == 0); 3453 return (grubroot); 3454 } 3455 3456 static char * 3457 find_primary_common(char *mntpt, char *fstype) 3458 { 3459 char signdir[PATH_MAX]; 3460 char tmpsign[MAXNAMELEN + 1]; 3461 char *lu; 3462 char *ufs; 3463 char *zfs; 3464 DIR *dirp = NULL; 3465 struct dirent *entp; 3466 struct stat sb; 3467 const char *fcn = "find_primary_common()"; 3468 3469 (void) snprintf(signdir, sizeof (signdir), "%s/%s", 3470 mntpt, GRUBSIGN_DIR); 3471 3472 if (stat(signdir, &sb) == -1) { 3473 BAM_DPRINTF((D_NO_SIGNDIR, fcn, signdir)); 3474 return (NULL); 3475 } 3476 3477 dirp = opendir(signdir); 3478 INJECT_ERROR1("SIGNDIR_OPENDIR_FAIL", dirp = NULL); 3479 if (dirp == NULL) { 3480 bam_error(OPENDIR_FAILED, signdir, strerror(errno)); 3481 return (NULL); 3482 } 3483 3484 ufs = zfs = lu = NULL; 3485 3486 while (entp = readdir(dirp)) { 3487 if (strcmp(entp->d_name, ".") == 0 || 3488 strcmp(entp->d_name, "..") == 0) 3489 continue; 3490 3491 (void) snprintf(tmpsign, sizeof (tmpsign), "%s", entp->d_name); 3492 3493 if (lu == NULL && 3494 strncmp(tmpsign, GRUBSIGN_LU_PREFIX, 3495 strlen(GRUBSIGN_LU_PREFIX)) == 0) { 3496 lu = s_strdup(tmpsign); 3497 } 3498 3499 if (ufs == NULL && 3500 strncmp(tmpsign, GRUBSIGN_UFS_PREFIX, 3501 strlen(GRUBSIGN_UFS_PREFIX)) == 0) { 3502 ufs = s_strdup(tmpsign); 3503 } 3504 3505 if (zfs == NULL && 3506 strncmp(tmpsign, GRUBSIGN_ZFS_PREFIX, 3507 strlen(GRUBSIGN_ZFS_PREFIX)) == 0) { 3508 zfs = s_strdup(tmpsign); 3509 } 3510 } 3511 3512 BAM_DPRINTF((D_EXIST_PRIMARY_SIGNS, fcn, 3513 zfs ? zfs : "NULL", 3514 ufs ? ufs : "NULL", 3515 lu ? lu : "NULL")); 3516 3517 if (dirp) { 3518 (void) closedir(dirp); 3519 dirp = NULL; 3520 } 3521 3522 if (strcmp(fstype, "ufs") == 0 && zfs) { 3523 bam_error(SIGN_FSTYPE_MISMATCH, zfs, "ufs"); 3524 free(zfs); 3525 zfs = NULL; 3526 } else if (strcmp(fstype, "zfs") == 0 && ufs) { 3527 bam_error(SIGN_FSTYPE_MISMATCH, ufs, "zfs"); 3528 free(ufs); 3529 ufs = NULL; 3530 } 3531 3532 assert(dirp == NULL); 3533 3534 /* For now, we let Live Upgrade take care of its signature itself */ 3535 if (lu) { 3536 BAM_DPRINTF((D_FREEING_LU_SIGNS, fcn, lu)); 3537 free(lu); 3538 lu = NULL; 3539 } 3540 3541 return (zfs ? zfs : ufs); 3542 } 3543 3544 static char * 3545 find_backup_common(char *mntpt, char *fstype) 3546 { 3547 FILE *bfp = NULL; 3548 char tmpsign[MAXNAMELEN + 1]; 3549 char backup[PATH_MAX]; 3550 char *ufs; 3551 char *zfs; 3552 char *lu; 3553 int error; 3554 const char *fcn = "find_backup_common()"; 3555 3556 /* 3557 * We didn't find it in the primary directory. 3558 * Look at the backup 3559 */ 3560 (void) snprintf(backup, sizeof (backup), "%s%s", 3561 mntpt, GRUBSIGN_BACKUP); 3562 3563 bfp = fopen(backup, "r"); 3564 if (bfp == NULL) { 3565 error = errno; 3566 if (bam_verbose) { 3567 bam_error(OPEN_FAIL, backup, strerror(error)); 3568 } 3569 BAM_DPRINTF((D_OPEN_FAIL, fcn, backup, strerror(error))); 3570 return (NULL); 3571 } 3572 3573 ufs = zfs = lu = NULL; 3574 3575 while (s_fgets(tmpsign, sizeof (tmpsign), bfp) != NULL) { 3576 3577 if (lu == NULL && 3578 strncmp(tmpsign, GRUBSIGN_LU_PREFIX, 3579 strlen(GRUBSIGN_LU_PREFIX)) == 0) { 3580 lu = s_strdup(tmpsign); 3581 } 3582 3583 if (ufs == NULL && 3584 strncmp(tmpsign, GRUBSIGN_UFS_PREFIX, 3585 strlen(GRUBSIGN_UFS_PREFIX)) == 0) { 3586 ufs = s_strdup(tmpsign); 3587 } 3588 3589 if (zfs == NULL && 3590 strncmp(tmpsign, GRUBSIGN_ZFS_PREFIX, 3591 strlen(GRUBSIGN_ZFS_PREFIX)) == 0) { 3592 zfs = s_strdup(tmpsign); 3593 } 3594 } 3595 3596 BAM_DPRINTF((D_EXIST_BACKUP_SIGNS, fcn, 3597 zfs ? zfs : "NULL", 3598 ufs ? ufs : "NULL", 3599 lu ? lu : "NULL")); 3600 3601 if (bfp) { 3602 (void) fclose(bfp); 3603 bfp = NULL; 3604 } 3605 3606 if (strcmp(fstype, "ufs") == 0 && zfs) { 3607 bam_error(SIGN_FSTYPE_MISMATCH, zfs, "ufs"); 3608 free(zfs); 3609 zfs = NULL; 3610 } else if (strcmp(fstype, "zfs") == 0 && ufs) { 3611 bam_error(SIGN_FSTYPE_MISMATCH, ufs, "zfs"); 3612 free(ufs); 3613 ufs = NULL; 3614 } 3615 3616 assert(bfp == NULL); 3617 3618 /* For now, we let Live Upgrade take care of its signature itself */ 3619 if (lu) { 3620 BAM_DPRINTF((D_FREEING_LU_SIGNS, fcn, lu)); 3621 free(lu); 3622 lu = NULL; 3623 } 3624 3625 return (zfs ? zfs : ufs); 3626 } 3627 3628 static char * 3629 find_ufs_existing(char *osroot) 3630 { 3631 char *sign; 3632 const char *fcn = "find_ufs_existing()"; 3633 3634 sign = find_primary_common(osroot, "ufs"); 3635 if (sign == NULL) { 3636 sign = find_backup_common(osroot, "ufs"); 3637 BAM_DPRINTF((D_EXIST_BACKUP_SIGN, fcn, sign ? sign : "NULL")); 3638 } else { 3639 BAM_DPRINTF((D_EXIST_PRIMARY_SIGN, fcn, sign)); 3640 } 3641 3642 return (sign); 3643 } 3644 3645 char * 3646 get_mountpoint(char *special, char *fstype) 3647 { 3648 FILE *mntfp; 3649 struct mnttab mp = {0}; 3650 struct mnttab mpref = {0}; 3651 int error; 3652 int ret; 3653 const char *fcn = "get_mountpoint()"; 3654 3655 BAM_DPRINTF((D_FUNC_ENTRY2, fcn, special, fstype)); 3656 3657 mntfp = fopen(MNTTAB, "r"); 3658 error = errno; 3659 INJECT_ERROR1("MNTTAB_ERR_GET_MNTPT", mntfp = NULL); 3660 if (mntfp == NULL) { 3661 bam_error(OPEN_FAIL, MNTTAB, strerror(error)); 3662 return (NULL); 3663 } 3664 3665 mpref.mnt_special = special; 3666 mpref.mnt_fstype = fstype; 3667 3668 ret = getmntany(mntfp, &mp, &mpref); 3669 INJECT_ERROR1("GET_MOUNTPOINT_MNTANY", ret = 1); 3670 if (ret != 0) { 3671 (void) fclose(mntfp); 3672 BAM_DPRINTF((D_NO_MNTPT, fcn, special, fstype)); 3673 return (NULL); 3674 } 3675 (void) fclose(mntfp); 3676 3677 assert(mp.mnt_mountp); 3678 3679 BAM_DPRINTF((D_GET_MOUNTPOINT_RET, fcn, special, mp.mnt_mountp)); 3680 3681 return (s_strdup(mp.mnt_mountp)); 3682 } 3683 3684 /* 3685 * Mounts a "legacy" top dataset (if needed) 3686 * Returns: The mountpoint of the legacy top dataset or NULL on error 3687 * mnted returns one of the above values defined for zfs_mnted_t 3688 */ 3689 static char * 3690 mount_legacy_dataset(char *pool, zfs_mnted_t *mnted) 3691 { 3692 char cmd[PATH_MAX]; 3693 char tmpmnt[PATH_MAX]; 3694 filelist_t flist = {0}; 3695 char *is_mounted; 3696 struct stat sb; 3697 int ret; 3698 const char *fcn = "mount_legacy_dataset()"; 3699 3700 BAM_DPRINTF((D_FUNC_ENTRY1, fcn, pool)); 3701 3702 *mnted = ZFS_MNT_ERROR; 3703 3704 (void) snprintf(cmd, sizeof (cmd), 3705 "/sbin/zfs get -Ho value mounted %s", 3706 pool); 3707 3708 ret = exec_cmd(cmd, &flist); 3709 INJECT_ERROR1("Z_MOUNT_LEG_GET_MOUNTED_CMD", ret = 1); 3710 if (ret != 0) { 3711 bam_error(ZFS_MNTED_FAILED, pool); 3712 return (NULL); 3713 } 3714 3715 INJECT_ERROR1("Z_MOUNT_LEG_GET_MOUNTED_OUT", flist.head = NULL); 3716 if ((flist.head == NULL) || (flist.head != flist.tail)) { 3717 bam_error(BAD_ZFS_MNTED, pool); 3718 filelist_free(&flist); 3719 return (NULL); 3720 } 3721 3722 is_mounted = strtok(flist.head->line, " \t\n"); 3723 INJECT_ERROR1("Z_MOUNT_LEG_GET_MOUNTED_STRTOK_YES", is_mounted = "yes"); 3724 INJECT_ERROR1("Z_MOUNT_LEG_GET_MOUNTED_STRTOK_NO", is_mounted = "no"); 3725 if (strcmp(is_mounted, "no") != 0) { 3726 filelist_free(&flist); 3727 *mnted = LEGACY_ALREADY; 3728 /* get_mountpoint returns a strdup'ed string */ 3729 BAM_DPRINTF((D_Z_MOUNT_TOP_LEG_ALREADY, fcn, pool)); 3730 return (get_mountpoint(pool, "zfs")); 3731 } 3732 3733 filelist_free(&flist); 3734 3735 /* 3736 * legacy top dataset is not mounted. Mount it now 3737 * First create a mountpoint. 3738 */ 3739 (void) snprintf(tmpmnt, sizeof (tmpmnt), "%s.%d", 3740 ZFS_LEGACY_MNTPT, getpid()); 3741 3742 ret = stat(tmpmnt, &sb); 3743 if (ret == -1) { 3744 BAM_DPRINTF((D_Z_MOUNT_TOP_LEG_MNTPT_ABS, fcn, pool, tmpmnt)); 3745 ret = mkdirp(tmpmnt, 0755); 3746 INJECT_ERROR1("Z_MOUNT_TOP_LEG_MNTPT_MKDIRP", ret = -1); 3747 if (ret == -1) { 3748 bam_error(MKDIR_FAILED, tmpmnt, strerror(errno)); 3749 return (NULL); 3750 } 3751 } else { 3752 BAM_DPRINTF((D_Z_MOUNT_TOP_LEG_MNTPT_PRES, fcn, pool, tmpmnt)); 3753 } 3754 3755 (void) snprintf(cmd, sizeof (cmd), 3756 "/sbin/mount -F zfs %s %s", 3757 pool, tmpmnt); 3758 3759 ret = exec_cmd(cmd, NULL); 3760 INJECT_ERROR1("Z_MOUNT_TOP_LEG_MOUNT_CMD", ret = 1); 3761 if (ret != 0) { 3762 bam_error(ZFS_MOUNT_FAILED, pool); 3763 (void) rmdir(tmpmnt); 3764 return (NULL); 3765 } 3766 3767 *mnted = LEGACY_MOUNTED; 3768 BAM_DPRINTF((D_Z_MOUNT_TOP_LEG_MOUNTED, fcn, pool, tmpmnt)); 3769 return (s_strdup(tmpmnt)); 3770 } 3771 3772 /* 3773 * Mounts the top dataset (if needed) 3774 * Returns: The mountpoint of the top dataset or NULL on error 3775 * mnted returns one of the above values defined for zfs_mnted_t 3776 */ 3777 static char * 3778 mount_top_dataset(char *pool, zfs_mnted_t *mnted) 3779 { 3780 char cmd[PATH_MAX]; 3781 filelist_t flist = {0}; 3782 char *is_mounted; 3783 char *mntpt; 3784 char *zmntpt; 3785 int ret; 3786 const char *fcn = "mount_top_dataset()"; 3787 3788 *mnted = ZFS_MNT_ERROR; 3789 3790 BAM_DPRINTF((D_FUNC_ENTRY1, fcn, pool)); 3791 3792 /* 3793 * First check if the top dataset is a "legacy" dataset 3794 */ 3795 (void) snprintf(cmd, sizeof (cmd), 3796 "/sbin/zfs get -Ho value mountpoint %s", 3797 pool); 3798 ret = exec_cmd(cmd, &flist); 3799 INJECT_ERROR1("Z_MOUNT_TOP_GET_MNTPT", ret = 1); 3800 if (ret != 0) { 3801 bam_error(ZFS_MNTPT_FAILED, pool); 3802 return (NULL); 3803 } 3804 3805 if (flist.head && (flist.head == flist.tail)) { 3806 char *legacy = strtok(flist.head->line, " \t\n"); 3807 if (legacy && strcmp(legacy, "legacy") == 0) { 3808 filelist_free(&flist); 3809 BAM_DPRINTF((D_Z_IS_LEGACY, fcn, pool)); 3810 return (mount_legacy_dataset(pool, mnted)); 3811 } 3812 } 3813 3814 filelist_free(&flist); 3815 3816 BAM_DPRINTF((D_Z_IS_NOT_LEGACY, fcn, pool)); 3817 3818 (void) snprintf(cmd, sizeof (cmd), 3819 "/sbin/zfs get -Ho value mounted %s", 3820 pool); 3821 3822 ret = exec_cmd(cmd, &flist); 3823 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MOUNTED", ret = 1); 3824 if (ret != 0) { 3825 bam_error(ZFS_MNTED_FAILED, pool); 3826 return (NULL); 3827 } 3828 3829 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MOUNTED_VAL", flist.head = NULL); 3830 if ((flist.head == NULL) || (flist.head != flist.tail)) { 3831 bam_error(BAD_ZFS_MNTED, pool); 3832 filelist_free(&flist); 3833 return (NULL); 3834 } 3835 3836 is_mounted = strtok(flist.head->line, " \t\n"); 3837 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MOUNTED_YES", is_mounted = "yes"); 3838 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MOUNTED_NO", is_mounted = "no"); 3839 if (strcmp(is_mounted, "no") != 0) { 3840 filelist_free(&flist); 3841 *mnted = ZFS_ALREADY; 3842 BAM_DPRINTF((D_Z_MOUNT_TOP_NONLEG_MOUNTED_ALREADY, fcn, pool)); 3843 goto mounted; 3844 } 3845 3846 filelist_free(&flist); 3847 BAM_DPRINTF((D_Z_MOUNT_TOP_NONLEG_MOUNTED_NOT_ALREADY, fcn, pool)); 3848 3849 /* top dataset is not mounted. Mount it now */ 3850 (void) snprintf(cmd, sizeof (cmd), 3851 "/sbin/zfs mount %s", pool); 3852 ret = exec_cmd(cmd, NULL); 3853 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_MOUNT_CMD", ret = 1); 3854 if (ret != 0) { 3855 bam_error(ZFS_MOUNT_FAILED, pool); 3856 return (NULL); 3857 } 3858 *mnted = ZFS_MOUNTED; 3859 BAM_DPRINTF((D_Z_MOUNT_TOP_NONLEG_MOUNTED_NOW, fcn, pool)); 3860 /*FALLTHRU*/ 3861 mounted: 3862 /* 3863 * Now get the mountpoint 3864 */ 3865 (void) snprintf(cmd, sizeof (cmd), 3866 "/sbin/zfs get -Ho value mountpoint %s", 3867 pool); 3868 3869 ret = exec_cmd(cmd, &flist); 3870 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MNTPT_CMD", ret = 1); 3871 if (ret != 0) { 3872 bam_error(ZFS_MNTPT_FAILED, pool); 3873 goto error; 3874 } 3875 3876 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MNTPT_OUT", flist.head = NULL); 3877 if ((flist.head == NULL) || (flist.head != flist.tail)) { 3878 bam_error(NULL_ZFS_MNTPT, pool); 3879 goto error; 3880 } 3881 3882 mntpt = strtok(flist.head->line, " \t\n"); 3883 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MNTPT_STRTOK", mntpt = "foo"); 3884 if (*mntpt != '/') { 3885 bam_error(BAD_ZFS_MNTPT, pool, mntpt); 3886 goto error; 3887 } 3888 zmntpt = s_strdup(mntpt); 3889 3890 filelist_free(&flist); 3891 3892 BAM_DPRINTF((D_Z_MOUNT_TOP_NONLEG_MNTPT, fcn, pool, zmntpt)); 3893 3894 return (zmntpt); 3895 3896 error: 3897 filelist_free(&flist); 3898 (void) umount_top_dataset(pool, *mnted, NULL); 3899 BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 3900 return (NULL); 3901 } 3902 3903 static int 3904 umount_top_dataset(char *pool, zfs_mnted_t mnted, char *mntpt) 3905 { 3906 char cmd[PATH_MAX]; 3907 int ret; 3908 const char *fcn = "umount_top_dataset()"; 3909 3910 INJECT_ERROR1("Z_UMOUNT_TOP_INVALID_STATE", mnted = ZFS_MNT_ERROR); 3911 switch (mnted) { 3912 case LEGACY_ALREADY: 3913 case ZFS_ALREADY: 3914 /* nothing to do */ 3915 BAM_DPRINTF((D_Z_UMOUNT_TOP_ALREADY_NOP, fcn, pool, 3916 mntpt ? mntpt : "NULL")); 3917 free(mntpt); 3918 return (BAM_SUCCESS); 3919 case LEGACY_MOUNTED: 3920 (void) snprintf(cmd, sizeof (cmd), 3921 "/sbin/umount %s", pool); 3922 ret = exec_cmd(cmd, NULL); 3923 INJECT_ERROR1("Z_UMOUNT_TOP_LEGACY_UMOUNT_FAIL", ret = 1); 3924 if (ret != 0) { 3925 bam_error(UMOUNT_FAILED, pool); 3926 free(mntpt); 3927 return (BAM_ERROR); 3928 } 3929 if (mntpt) 3930 (void) rmdir(mntpt); 3931 free(mntpt); 3932 BAM_DPRINTF((D_Z_UMOUNT_TOP_LEGACY, fcn, pool)); 3933 return (BAM_SUCCESS); 3934 case ZFS_MOUNTED: 3935 free(mntpt); 3936 (void) snprintf(cmd, sizeof (cmd), 3937 "/sbin/zfs unmount %s", pool); 3938 ret = exec_cmd(cmd, NULL); 3939 INJECT_ERROR1("Z_UMOUNT_TOP_NONLEG_UMOUNT_FAIL", ret = 1); 3940 if (ret != 0) { 3941 bam_error(UMOUNT_FAILED, pool); 3942 return (BAM_ERROR); 3943 } 3944 BAM_DPRINTF((D_Z_UMOUNT_TOP_NONLEG, fcn, pool)); 3945 return (BAM_SUCCESS); 3946 default: 3947 bam_error(INT_BAD_MNTSTATE, pool); 3948 return (BAM_ERROR); 3949 } 3950 /*NOTREACHED*/ 3951 } 3952 3953 /* 3954 * For ZFS, osdev can be one of two forms 3955 * It can be a "special" file as seen in mnttab: rpool/ROOT/szboot_0402 3956 * It can be a /dev/[r]dsk special file. We handle both instances 3957 */ 3958 static char * 3959 get_pool(char *osdev) 3960 { 3961 char cmd[PATH_MAX]; 3962 char buf[PATH_MAX]; 3963 filelist_t flist = {0}; 3964 char *pool; 3965 char *cp; 3966 char *slash; 3967 int ret; 3968 const char *fcn = "get_pool()"; 3969 3970 INJECT_ERROR1("GET_POOL_OSDEV", osdev = NULL); 3971 if (osdev == NULL) { 3972 bam_error(GET_POOL_OSDEV_NULL); 3973 return (NULL); 3974 } 3975 3976 BAM_DPRINTF((D_GET_POOL_OSDEV, fcn, osdev)); 3977 3978 if (osdev[0] != '/') { 3979 (void) strlcpy(buf, osdev, sizeof (buf)); 3980 slash = strchr(buf, '/'); 3981 if (slash) 3982 *slash = '\0'; 3983 pool = s_strdup(buf); 3984 BAM_DPRINTF((D_GET_POOL_RET, fcn, pool)); 3985 return (pool); 3986 } else if (strncmp(osdev, "/dev/dsk/", strlen("/dev/dsk/")) != 0 && 3987 strncmp(osdev, "/dev/rdsk/", strlen("/dev/rdsk/")) != 0) { 3988 bam_error(GET_POOL_BAD_OSDEV, osdev); 3989 return (NULL); 3990 } 3991 3992 (void) snprintf(cmd, sizeof (cmd), 3993 "/usr/sbin/fstyp -a %s 2>/dev/null | /bin/grep '^name:'", 3994 osdev); 3995 3996 ret = exec_cmd(cmd, &flist); 3997 INJECT_ERROR1("GET_POOL_FSTYP", ret = 1); 3998 if (ret != 0) { 3999 bam_error(FSTYP_A_FAILED, osdev); 4000 return (NULL); 4001 } 4002 4003 INJECT_ERROR1("GET_POOL_FSTYP_OUT", flist.head = NULL); 4004 if ((flist.head == NULL) || (flist.head != flist.tail)) { 4005 bam_error(NULL_FSTYP_A, osdev); 4006 filelist_free(&flist); 4007 return (NULL); 4008 } 4009 4010 (void) strtok(flist.head->line, "'"); 4011 cp = strtok(NULL, "'"); 4012 INJECT_ERROR1("GET_POOL_FSTYP_STRTOK", cp = NULL); 4013 if (cp == NULL) { 4014 bam_error(BAD_FSTYP_A, osdev); 4015 filelist_free(&flist); 4016 return (NULL); 4017 } 4018 4019 pool = s_strdup(cp); 4020 4021 filelist_free(&flist); 4022 4023 BAM_DPRINTF((D_GET_POOL_RET, fcn, pool)); 4024 4025 return (pool); 4026 } 4027 4028 static char * 4029 find_zfs_existing(char *osdev) 4030 { 4031 char *pool; 4032 zfs_mnted_t mnted; 4033 char *mntpt; 4034 char *sign; 4035 const char *fcn = "find_zfs_existing()"; 4036 4037 pool = get_pool(osdev); 4038 INJECT_ERROR1("ZFS_FIND_EXIST_POOL", pool = NULL); 4039 if (pool == NULL) { 4040 bam_error(ZFS_GET_POOL_FAILED, osdev); 4041 return (NULL); 4042 } 4043 4044 mntpt = mount_top_dataset(pool, &mnted); 4045 INJECT_ERROR1("ZFS_FIND_EXIST_MOUNT_TOP", mntpt = NULL); 4046 if (mntpt == NULL) { 4047 bam_error(ZFS_MOUNT_TOP_DATASET_FAILED, pool); 4048 free(pool); 4049 return (NULL); 4050 } 4051 4052 sign = find_primary_common(mntpt, "zfs"); 4053 if (sign == NULL) { 4054 sign = find_backup_common(mntpt, "zfs"); 4055 BAM_DPRINTF((D_EXIST_BACKUP_SIGN, fcn, sign ? sign : "NULL")); 4056 } else { 4057 BAM_DPRINTF((D_EXIST_PRIMARY_SIGN, fcn, sign)); 4058 } 4059 4060 (void) umount_top_dataset(pool, mnted, mntpt); 4061 4062 free(pool); 4063 4064 return (sign); 4065 } 4066 4067 static char * 4068 find_existing_sign(char *osroot, char *osdev, char *fstype) 4069 { 4070 const char *fcn = "find_existing_sign()"; 4071 4072 INJECT_ERROR1("FIND_EXIST_NOTSUP_FS", fstype = "foofs"); 4073 if (strcmp(fstype, "ufs") == 0) { 4074 BAM_DPRINTF((D_CHECK_UFS_EXIST_SIGN, fcn)); 4075 return (find_ufs_existing(osroot)); 4076 } else if (strcmp(fstype, "zfs") == 0) { 4077 BAM_DPRINTF((D_CHECK_ZFS_EXIST_SIGN, fcn)); 4078 return (find_zfs_existing(osdev)); 4079 } else { 4080 bam_error(GRUBSIGN_NOTSUP, fstype); 4081 return (NULL); 4082 } 4083 } 4084 4085 #define MH_HASH_SZ 16 4086 4087 typedef enum { 4088 MH_ERROR = -1, 4089 MH_NOMATCH, 4090 MH_MATCH 4091 } mh_search_t; 4092 4093 typedef struct mcache { 4094 char *mc_special; 4095 char *mc_mntpt; 4096 char *mc_fstype; 4097 struct mcache *mc_next; 4098 } mcache_t; 4099 4100 typedef struct mhash { 4101 mcache_t *mh_hash[MH_HASH_SZ]; 4102 } mhash_t; 4103 4104 static int 4105 mhash_fcn(char *key) 4106 { 4107 int i; 4108 uint64_t sum = 0; 4109 4110 for (i = 0; key[i] != '\0'; i++) { 4111 sum += (uchar_t)key[i]; 4112 } 4113 4114 sum %= MH_HASH_SZ; 4115 4116 assert(sum < MH_HASH_SZ); 4117 4118 return (sum); 4119 } 4120 4121 static mhash_t * 4122 cache_mnttab(void) 4123 { 4124 FILE *mfp; 4125 struct extmnttab mnt; 4126 mcache_t *mcp; 4127 mhash_t *mhp; 4128 char *ctds; 4129 int idx; 4130 int error; 4131 char *special_dup; 4132 const char *fcn = "cache_mnttab()"; 4133 4134 mfp = fopen(MNTTAB, "r"); 4135 error = errno; 4136 INJECT_ERROR1("CACHE_MNTTAB_MNTTAB_ERR", mfp = NULL); 4137 if (mfp == NULL) { 4138 bam_error(OPEN_FAIL, MNTTAB, strerror(error)); 4139 return (NULL); 4140 } 4141 4142 mhp = s_calloc(1, sizeof (mhash_t)); 4143 4144 resetmnttab(mfp); 4145 4146 while (getextmntent(mfp, &mnt, sizeof (mnt)) == 0) { 4147 /* only cache ufs */ 4148 if (strcmp(mnt.mnt_fstype, "ufs") != 0) 4149 continue; 4150 4151 /* basename() modifies its arg, so dup it */ 4152 special_dup = s_strdup(mnt.mnt_special); 4153 ctds = basename(special_dup); 4154 4155 mcp = s_calloc(1, sizeof (mcache_t)); 4156 mcp->mc_special = s_strdup(ctds); 4157 mcp->mc_mntpt = s_strdup(mnt.mnt_mountp); 4158 mcp->mc_fstype = s_strdup(mnt.mnt_fstype); 4159 BAM_DPRINTF((D_CACHE_MNTS, fcn, ctds, 4160 mnt.mnt_mountp, mnt.mnt_fstype)); 4161 idx = mhash_fcn(ctds); 4162 mcp->mc_next = mhp->mh_hash[idx]; 4163 mhp->mh_hash[idx] = mcp; 4164 free(special_dup); 4165 } 4166 4167 (void) fclose(mfp); 4168 4169 return (mhp); 4170 } 4171 4172 static void 4173 free_mnttab(mhash_t *mhp) 4174 { 4175 mcache_t *mcp; 4176 int i; 4177 4178 for (i = 0; i < MH_HASH_SZ; i++) { 4179 /*LINTED*/ 4180 while (mcp = mhp->mh_hash[i]) { 4181 mhp->mh_hash[i] = mcp->mc_next; 4182 free(mcp->mc_special); 4183 free(mcp->mc_mntpt); 4184 free(mcp->mc_fstype); 4185 free(mcp); 4186 } 4187 } 4188 4189 for (i = 0; i < MH_HASH_SZ; i++) { 4190 assert(mhp->mh_hash[i] == NULL); 4191 } 4192 free(mhp); 4193 } 4194 4195 static mh_search_t 4196 search_hash(mhash_t *mhp, char *special, char **mntpt) 4197 { 4198 int idx; 4199 mcache_t *mcp; 4200 const char *fcn = "search_hash()"; 4201 4202 assert(mntpt); 4203 4204 *mntpt = NULL; 4205 4206 INJECT_ERROR1("SEARCH_HASH_FULL_PATH", special = "/foo"); 4207 if (strchr(special, '/')) { 4208 bam_error(INVALID_MHASH_KEY, special); 4209 return (MH_ERROR); 4210 } 4211 4212 idx = mhash_fcn(special); 4213 4214 for (mcp = mhp->mh_hash[idx]; mcp; mcp = mcp->mc_next) { 4215 if (strcmp(mcp->mc_special, special) == 0) 4216 break; 4217 } 4218 4219 if (mcp == NULL) { 4220 BAM_DPRINTF((D_MNTTAB_HASH_NOMATCH, fcn, special)); 4221 return (MH_NOMATCH); 4222 } 4223 4224 assert(strcmp(mcp->mc_fstype, "ufs") == 0); 4225 *mntpt = mcp->mc_mntpt; 4226 BAM_DPRINTF((D_MNTTAB_HASH_MATCH, fcn, special)); 4227 return (MH_MATCH); 4228 } 4229 4230 static int 4231 check_add_ufs_sign_to_list(FILE *tfp, char *mntpt) 4232 { 4233 char *sign; 4234 char *signline; 4235 char signbuf[MAXNAMELEN]; 4236 int len; 4237 int error; 4238 const char *fcn = "check_add_ufs_sign_to_list()"; 4239 4240 /* safe to specify NULL as "osdev" arg for UFS */ 4241 sign = find_existing_sign(mntpt, NULL, "ufs"); 4242 if (sign == NULL) { 4243 /* No existing signature, nothing to add to list */ 4244 BAM_DPRINTF((D_NO_SIGN_TO_LIST, fcn, mntpt)); 4245 return (0); 4246 } 4247 4248 (void) snprintf(signbuf, sizeof (signbuf), "%s\n", sign); 4249 signline = signbuf; 4250 4251 INJECT_ERROR1("UFS_MNTPT_SIGN_NOTUFS", signline = "pool_rpool10\n"); 4252 if (strncmp(signline, GRUBSIGN_UFS_PREFIX, 4253 strlen(GRUBSIGN_UFS_PREFIX))) { 4254 bam_error(INVALID_UFS_SIGNATURE, sign); 4255 free(sign); 4256 /* ignore invalid signatures */ 4257 return (0); 4258 } 4259 4260 len = fputs(signline, tfp); 4261 error = errno; 4262 INJECT_ERROR1("SIGN_LIST_PUTS_ERROR", len = 0); 4263 if (len != strlen(signline)) { 4264 bam_error(SIGN_LIST_FPUTS_ERR, sign, strerror(error)); 4265 free(sign); 4266 return (-1); 4267 } 4268 4269 free(sign); 4270 4271 BAM_DPRINTF((D_SIGN_LIST_PUTS_DONE, fcn, mntpt)); 4272 return (0); 4273 } 4274 4275 /* 4276 * slice is a basename not a full pathname 4277 */ 4278 static int 4279 process_slice_common(char *slice, FILE *tfp, mhash_t *mhp, char *tmpmnt) 4280 { 4281 int ret; 4282 char cmd[PATH_MAX]; 4283 char path[PATH_MAX]; 4284 struct stat sbuf; 4285 char *mntpt; 4286 filelist_t flist = {0}; 4287 char *fstype; 4288 char blkslice[PATH_MAX]; 4289 const char *fcn = "process_slice_common()"; 4290 4291 4292 ret = search_hash(mhp, slice, &mntpt); 4293 switch (ret) { 4294 case MH_MATCH: 4295 if (check_add_ufs_sign_to_list(tfp, mntpt) == -1) 4296 return (-1); 4297 else 4298 return (0); 4299 case MH_NOMATCH: 4300 break; 4301 case MH_ERROR: 4302 default: 4303 return (-1); 4304 } 4305 4306 (void) snprintf(path, sizeof (path), "/dev/rdsk/%s", slice); 4307 if (stat(path, &sbuf) == -1) { 4308 BAM_DPRINTF((D_SLICE_ENOENT, fcn, path)); 4309 return (0); 4310 } 4311 4312 /* Check if ufs */ 4313 (void) snprintf(cmd, sizeof (cmd), 4314 "/usr/sbin/fstyp /dev/rdsk/%s 2>/dev/null", 4315 slice); 4316 4317 if (exec_cmd(cmd, &flist) != 0) { 4318 if (bam_verbose) 4319 bam_print(FSTYP_FAILED, slice); 4320 return (0); 4321 } 4322 4323 if ((flist.head == NULL) || (flist.head != flist.tail)) { 4324 if (bam_verbose) 4325 bam_print(FSTYP_BAD, slice); 4326 filelist_free(&flist); 4327 return (0); 4328 } 4329 4330 fstype = strtok(flist.head->line, " \t\n"); 4331 if (fstype == NULL || strcmp(fstype, "ufs") != 0) { 4332 if (bam_verbose) 4333 bam_print(NOT_UFS_SLICE, slice, fstype); 4334 filelist_free(&flist); 4335 return (0); 4336 } 4337 4338 filelist_free(&flist); 4339 4340 /* 4341 * Since we are mounting the filesystem read-only, the 4342 * the last mount field of the superblock is unchanged 4343 * and does not need to be fixed up post-mount; 4344 */ 4345 4346 (void) snprintf(blkslice, sizeof (blkslice), "/dev/dsk/%s", 4347 slice); 4348 4349 (void) snprintf(cmd, sizeof (cmd), 4350 "/usr/sbin/mount -F ufs -o ro %s %s " 4351 "> /dev/null 2>&1", blkslice, tmpmnt); 4352 4353 if (exec_cmd(cmd, NULL) != 0) { 4354 if (bam_verbose) 4355 bam_print(MOUNT_FAILED, blkslice, "ufs"); 4356 return (0); 4357 } 4358 4359 ret = check_add_ufs_sign_to_list(tfp, tmpmnt); 4360 4361 (void) snprintf(cmd, sizeof (cmd), 4362 "/usr/sbin/umount -f %s > /dev/null 2>&1", 4363 tmpmnt); 4364 4365 if (exec_cmd(cmd, NULL) != 0) { 4366 bam_print(UMOUNT_FAILED, slice); 4367 return (0); 4368 } 4369 4370 return (ret); 4371 } 4372 4373 static int 4374 process_vtoc_slices( 4375 char *s0, 4376 struct vtoc *vtoc, 4377 FILE *tfp, 4378 mhash_t *mhp, 4379 char *tmpmnt) 4380 { 4381 int idx; 4382 char slice[PATH_MAX]; 4383 size_t len; 4384 char *cp; 4385 const char *fcn = "process_vtoc_slices()"; 4386 4387 len = strlen(s0); 4388 4389 assert(s0[len - 2] == 's' && s0[len - 1] == '0'); 4390 4391 s0[len - 1] = '\0'; 4392 4393 (void) strlcpy(slice, s0, sizeof (slice)); 4394 4395 s0[len - 1] = '0'; 4396 4397 cp = slice + len - 1; 4398 4399 for (idx = 0; idx < vtoc->v_nparts; idx++) { 4400 4401 (void) snprintf(cp, sizeof (slice) - (len - 1), "%u", idx); 4402 4403 if (vtoc->v_part[idx].p_size == 0) { 4404 BAM_DPRINTF((D_VTOC_SIZE_ZERO, fcn, slice)); 4405 continue; 4406 } 4407 4408 /* Skip "SWAP", "USR", "BACKUP", "VAR", "HOME", "ALTSCTR" */ 4409 switch (vtoc->v_part[idx].p_tag) { 4410 case V_SWAP: 4411 case V_USR: 4412 case V_BACKUP: 4413 case V_VAR: 4414 case V_HOME: 4415 case V_ALTSCTR: 4416 BAM_DPRINTF((D_VTOC_NOT_ROOT_TAG, fcn, slice)); 4417 continue; 4418 default: 4419 BAM_DPRINTF((D_VTOC_ROOT_TAG, fcn, slice)); 4420 break; 4421 } 4422 4423 /* skip unmountable and readonly slices */ 4424 switch (vtoc->v_part[idx].p_flag) { 4425 case V_UNMNT: 4426 case V_RONLY: 4427 BAM_DPRINTF((D_VTOC_NOT_RDWR_FLAG, fcn, slice)); 4428 continue; 4429 default: 4430 BAM_DPRINTF((D_VTOC_RDWR_FLAG, fcn, slice)); 4431 break; 4432 } 4433 4434 if (process_slice_common(slice, tfp, mhp, tmpmnt) == -1) { 4435 return (-1); 4436 } 4437 } 4438 4439 return (0); 4440 } 4441 4442 static int 4443 process_efi_slices( 4444 char *s0, 4445 struct dk_gpt *efi, 4446 FILE *tfp, 4447 mhash_t *mhp, 4448 char *tmpmnt) 4449 { 4450 int idx; 4451 char slice[PATH_MAX]; 4452 size_t len; 4453 char *cp; 4454 const char *fcn = "process_efi_slices()"; 4455 4456 len = strlen(s0); 4457 4458 assert(s0[len - 2] == 's' && s0[len - 1] == '0'); 4459 4460 s0[len - 1] = '\0'; 4461 4462 (void) strlcpy(slice, s0, sizeof (slice)); 4463 4464 s0[len - 1] = '0'; 4465 4466 cp = slice + len - 1; 4467 4468 for (idx = 0; idx < efi->efi_nparts; idx++) { 4469 4470 (void) snprintf(cp, sizeof (slice) - (len - 1), "%u", idx); 4471 4472 if (efi->efi_parts[idx].p_size == 0) { 4473 BAM_DPRINTF((D_EFI_SIZE_ZERO, fcn, slice)); 4474 continue; 4475 } 4476 4477 /* Skip "SWAP", "USR", "BACKUP", "VAR", "HOME", "ALTSCTR" */ 4478 switch (efi->efi_parts[idx].p_tag) { 4479 case V_SWAP: 4480 case V_USR: 4481 case V_BACKUP: 4482 case V_VAR: 4483 case V_HOME: 4484 case V_ALTSCTR: 4485 BAM_DPRINTF((D_EFI_NOT_ROOT_TAG, fcn, slice)); 4486 continue; 4487 default: 4488 BAM_DPRINTF((D_EFI_ROOT_TAG, fcn, slice)); 4489 break; 4490 } 4491 4492 /* skip unmountable and readonly slices */ 4493 switch (efi->efi_parts[idx].p_flag) { 4494 case V_UNMNT: 4495 case V_RONLY: 4496 BAM_DPRINTF((D_EFI_NOT_RDWR_FLAG, fcn, slice)); 4497 continue; 4498 default: 4499 BAM_DPRINTF((D_EFI_RDWR_FLAG, fcn, slice)); 4500 break; 4501 } 4502 4503 if (process_slice_common(slice, tfp, mhp, tmpmnt) == -1) { 4504 return (-1); 4505 } 4506 } 4507 4508 return (0); 4509 } 4510 4511 /* 4512 * s0 is a basename not a full path 4513 */ 4514 static int 4515 process_slice0(char *s0, FILE *tfp, mhash_t *mhp, char *tmpmnt) 4516 { 4517 struct vtoc vtoc; 4518 struct dk_gpt *efi; 4519 char s0path[PATH_MAX]; 4520 struct stat sbuf; 4521 int e_flag; 4522 int v_flag; 4523 int retval; 4524 int err; 4525 int fd; 4526 const char *fcn = "process_slice0()"; 4527 4528 (void) snprintf(s0path, sizeof (s0path), "/dev/rdsk/%s", s0); 4529 4530 if (stat(s0path, &sbuf) == -1) { 4531 BAM_DPRINTF((D_SLICE0_ENOENT, fcn, s0path)); 4532 return (0); 4533 } 4534 4535 fd = open(s0path, O_NONBLOCK|O_RDONLY); 4536 if (fd == -1) { 4537 bam_error(OPEN_FAIL, s0path, strerror(errno)); 4538 return (0); 4539 } 4540 4541 e_flag = v_flag = 0; 4542 retval = ((err = read_vtoc(fd, &vtoc)) >= 0) ? 0 : err; 4543 switch (retval) { 4544 case VT_EIO: 4545 BAM_DPRINTF((D_VTOC_READ_FAIL, fcn, s0path)); 4546 break; 4547 case VT_EINVAL: 4548 BAM_DPRINTF((D_VTOC_INVALID, fcn, s0path)); 4549 break; 4550 case VT_ERROR: 4551 BAM_DPRINTF((D_VTOC_UNKNOWN_ERR, fcn, s0path)); 4552 break; 4553 case VT_ENOTSUP: 4554 e_flag = 1; 4555 BAM_DPRINTF((D_VTOC_NOTSUP, fcn, s0path)); 4556 break; 4557 case 0: 4558 v_flag = 1; 4559 BAM_DPRINTF((D_VTOC_READ_SUCCESS, fcn, s0path)); 4560 break; 4561 default: 4562 BAM_DPRINTF((D_VTOC_UNKNOWN_RETCODE, fcn, s0path)); 4563 break; 4564 } 4565 4566 4567 if (e_flag) { 4568 e_flag = 0; 4569 retval = ((err = efi_alloc_and_read(fd, &efi)) >= 0) ? 0 : err; 4570 switch (retval) { 4571 case VT_EIO: 4572 BAM_DPRINTF((D_EFI_READ_FAIL, fcn, s0path)); 4573 break; 4574 case VT_EINVAL: 4575 BAM_DPRINTF((D_EFI_INVALID, fcn, s0path)); 4576 break; 4577 case VT_ERROR: 4578 BAM_DPRINTF((D_EFI_UNKNOWN_ERR, fcn, s0path)); 4579 break; 4580 case VT_ENOTSUP: 4581 BAM_DPRINTF((D_EFI_NOTSUP, fcn, s0path)); 4582 break; 4583 case 0: 4584 e_flag = 1; 4585 BAM_DPRINTF((D_EFI_READ_SUCCESS, fcn, s0path)); 4586 break; 4587 default: 4588 BAM_DPRINTF((D_EFI_UNKNOWN_RETCODE, fcn, s0path)); 4589 break; 4590 } 4591 } 4592 4593 (void) close(fd); 4594 4595 if (v_flag) { 4596 retval = process_vtoc_slices(s0, 4597 &vtoc, tfp, mhp, tmpmnt); 4598 } else if (e_flag) { 4599 retval = process_efi_slices(s0, 4600 efi, tfp, mhp, tmpmnt); 4601 } else { 4602 BAM_DPRINTF((D_NOT_VTOC_OR_EFI, fcn, s0path)); 4603 return (0); 4604 } 4605 4606 return (retval); 4607 } 4608 4609 /* 4610 * Find and create a list of all existing UFS boot signatures 4611 */ 4612 static int 4613 FindAllUfsSignatures(void) 4614 { 4615 mhash_t *mnttab_hash; 4616 DIR *dirp = NULL; 4617 struct dirent *dp; 4618 char tmpmnt[PATH_MAX]; 4619 char cmd[PATH_MAX]; 4620 struct stat sb; 4621 int fd; 4622 FILE *tfp; 4623 size_t len; 4624 int ret; 4625 int error; 4626 const char *fcn = "FindAllUfsSignatures()"; 4627 4628 if (stat(UFS_SIGNATURE_LIST, &sb) != -1) { 4629 bam_print(SIGNATURE_LIST_EXISTS, UFS_SIGNATURE_LIST); 4630 return (0); 4631 } 4632 4633 fd = open(UFS_SIGNATURE_LIST".tmp", 4634 O_RDWR|O_CREAT|O_TRUNC, 0644); 4635 error = errno; 4636 INJECT_ERROR1("SIGN_LIST_TMP_TRUNC", fd = -1); 4637 if (fd == -1) { 4638 bam_error(OPEN_FAIL, UFS_SIGNATURE_LIST".tmp", strerror(error)); 4639 return (-1); 4640 } 4641 4642 ret = close(fd); 4643 error = errno; 4644 INJECT_ERROR1("SIGN_LIST_TMP_CLOSE", ret = -1); 4645 if (ret == -1) { 4646 bam_error(CLOSE_FAIL, UFS_SIGNATURE_LIST".tmp", 4647 strerror(error)); 4648 (void) unlink(UFS_SIGNATURE_LIST".tmp"); 4649 return (-1); 4650 } 4651 4652 tfp = fopen(UFS_SIGNATURE_LIST".tmp", "a"); 4653 error = errno; 4654 INJECT_ERROR1("SIGN_LIST_APPEND_FOPEN", tfp = NULL); 4655 if (tfp == NULL) { 4656 bam_error(OPEN_FAIL, UFS_SIGNATURE_LIST".tmp", strerror(error)); 4657 (void) unlink(UFS_SIGNATURE_LIST".tmp"); 4658 return (-1); 4659 } 4660 4661 mnttab_hash = cache_mnttab(); 4662 INJECT_ERROR1("CACHE_MNTTAB_ERROR", mnttab_hash = NULL); 4663 if (mnttab_hash == NULL) { 4664 (void) fclose(tfp); 4665 (void) unlink(UFS_SIGNATURE_LIST".tmp"); 4666 bam_error(CACHE_MNTTAB_FAIL, fcn); 4667 return (-1); 4668 } 4669 4670 (void) snprintf(tmpmnt, sizeof (tmpmnt), 4671 "/tmp/bootadm_ufs_sign_mnt.%d", getpid()); 4672 (void) unlink(tmpmnt); 4673 4674 ret = mkdirp(tmpmnt, 0755); 4675 error = errno; 4676 INJECT_ERROR1("MKDIRP_SIGN_MNT", ret = -1); 4677 if (ret == -1) { 4678 bam_error(MKDIR_FAILED, tmpmnt, strerror(error)); 4679 free_mnttab(mnttab_hash); 4680 (void) fclose(tfp); 4681 (void) unlink(UFS_SIGNATURE_LIST".tmp"); 4682 return (-1); 4683 } 4684 4685 dirp = opendir("/dev/rdsk"); 4686 error = errno; 4687 INJECT_ERROR1("OPENDIR_DEV_RDSK", dirp = NULL); 4688 if (dirp == NULL) { 4689 bam_error(OPENDIR_FAILED, "/dev/rdsk", strerror(error)); 4690 goto fail; 4691 } 4692 4693 while (dp = readdir(dirp)) { 4694 if (strcmp(dp->d_name, ".") == 0 || 4695 strcmp(dp->d_name, "..") == 0) 4696 continue; 4697 4698 /* 4699 * we only look for the s0 slice. This is guranteed to 4700 * have 's' at len - 2. 4701 */ 4702 len = strlen(dp->d_name); 4703 if (dp->d_name[len - 2 ] != 's' || dp->d_name[len - 1] != '0') { 4704 BAM_DPRINTF((D_SKIP_SLICE_NOTZERO, fcn, dp->d_name)); 4705 continue; 4706 } 4707 4708 ret = process_slice0(dp->d_name, tfp, mnttab_hash, tmpmnt); 4709 INJECT_ERROR1("PROCESS_S0_FAIL", ret = -1); 4710 if (ret == -1) 4711 goto fail; 4712 } 4713 4714 (void) closedir(dirp); 4715 free_mnttab(mnttab_hash); 4716 (void) rmdir(tmpmnt); 4717 4718 ret = fclose(tfp); 4719 error = errno; 4720 INJECT_ERROR1("FCLOSE_SIGNLIST_TMP", ret = EOF); 4721 if (ret == EOF) { 4722 bam_error(CLOSE_FAIL, UFS_SIGNATURE_LIST".tmp", 4723 strerror(error)); 4724 (void) unlink(UFS_SIGNATURE_LIST".tmp"); 4725 return (-1); 4726 } 4727 4728 /* We have a list of existing GRUB signatures. Sort it first */ 4729 (void) snprintf(cmd, sizeof (cmd), 4730 "/usr/bin/sort -u %s.tmp > %s.sorted", 4731 UFS_SIGNATURE_LIST, UFS_SIGNATURE_LIST); 4732 4733 ret = exec_cmd(cmd, NULL); 4734 INJECT_ERROR1("SORT_SIGN_LIST", ret = 1); 4735 if (ret != 0) { 4736 bam_error(GRUBSIGN_SORT_FAILED); 4737 (void) unlink(UFS_SIGNATURE_LIST".sorted"); 4738 (void) unlink(UFS_SIGNATURE_LIST".tmp"); 4739 return (-1); 4740 } 4741 4742 (void) unlink(UFS_SIGNATURE_LIST".tmp"); 4743 4744 ret = rename(UFS_SIGNATURE_LIST".sorted", UFS_SIGNATURE_LIST); 4745 error = errno; 4746 INJECT_ERROR1("RENAME_TMP_SIGNLIST", ret = -1); 4747 if (ret == -1) { 4748 bam_error(RENAME_FAIL, UFS_SIGNATURE_LIST, strerror(error)); 4749 (void) unlink(UFS_SIGNATURE_LIST".sorted"); 4750 return (-1); 4751 } 4752 4753 if (stat(UFS_SIGNATURE_LIST, &sb) == 0 && sb.st_size == 0) { 4754 BAM_DPRINTF((D_ZERO_LEN_SIGNLIST, fcn, UFS_SIGNATURE_LIST)); 4755 } 4756 4757 BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 4758 return (0); 4759 4760 fail: 4761 if (dirp) 4762 (void) closedir(dirp); 4763 free_mnttab(mnttab_hash); 4764 (void) rmdir(tmpmnt); 4765 (void) fclose(tfp); 4766 (void) unlink(UFS_SIGNATURE_LIST".tmp"); 4767 BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 4768 return (-1); 4769 } 4770 4771 static char * 4772 create_ufs_sign(void) 4773 { 4774 struct stat sb; 4775 int signnum = -1; 4776 char tmpsign[MAXNAMELEN + 1]; 4777 char *numstr; 4778 int i; 4779 FILE *tfp; 4780 int ret; 4781 int error; 4782 const char *fcn = "create_ufs_sign()"; 4783 4784 bam_print(SEARCHING_UFS_SIGN); 4785 4786 ret = FindAllUfsSignatures(); 4787 INJECT_ERROR1("FIND_ALL_UFS", ret = -1); 4788 if (ret == -1) { 4789 bam_error(ERR_FIND_UFS_SIGN); 4790 return (NULL); 4791 } 4792 4793 /* Make sure the list exists and is owned by root */ 4794 INJECT_ERROR1("SIGNLIST_NOT_CREATED", 4795 (void) unlink(UFS_SIGNATURE_LIST)); 4796 if (stat(UFS_SIGNATURE_LIST, &sb) == -1 || sb.st_uid != 0) { 4797 (void) unlink(UFS_SIGNATURE_LIST); 4798 bam_error(UFS_SIGNATURE_LIST_MISS, UFS_SIGNATURE_LIST); 4799 return (NULL); 4800 } 4801 4802 if (sb.st_size == 0) { 4803 bam_print(GRUBSIGN_UFS_NONE); 4804 i = 0; 4805 goto found; 4806 } 4807 4808 /* The signature list was sorted when it was created */ 4809 tfp = fopen(UFS_SIGNATURE_LIST, "r"); 4810 error = errno; 4811 INJECT_ERROR1("FOPEN_SIGN_LIST", tfp = NULL); 4812 if (tfp == NULL) { 4813 bam_error(UFS_SIGNATURE_LIST_OPENERR, 4814 UFS_SIGNATURE_LIST, strerror(error)); 4815 (void) unlink(UFS_SIGNATURE_LIST); 4816 return (NULL); 4817 } 4818 4819 for (i = 0; s_fgets(tmpsign, sizeof (tmpsign), tfp); i++) { 4820 4821 if (strncmp(tmpsign, GRUBSIGN_UFS_PREFIX, 4822 strlen(GRUBSIGN_UFS_PREFIX)) != 0) { 4823 (void) fclose(tfp); 4824 (void) unlink(UFS_SIGNATURE_LIST); 4825 bam_error(UFS_BADSIGN, tmpsign); 4826 return (NULL); 4827 } 4828 numstr = tmpsign + strlen(GRUBSIGN_UFS_PREFIX); 4829 4830 if (numstr[0] == '\0' || !isdigit(numstr[0])) { 4831 (void) fclose(tfp); 4832 (void) unlink(UFS_SIGNATURE_LIST); 4833 bam_error(UFS_BADSIGN, tmpsign); 4834 return (NULL); 4835 } 4836 4837 signnum = atoi(numstr); 4838 INJECT_ERROR1("NEGATIVE_SIGN", signnum = -1); 4839 if (signnum < 0) { 4840 (void) fclose(tfp); 4841 (void) unlink(UFS_SIGNATURE_LIST); 4842 bam_error(UFS_BADSIGN, tmpsign); 4843 return (NULL); 4844 } 4845 4846 if (i != signnum) { 4847 BAM_DPRINTF((D_FOUND_HOLE_SIGNLIST, fcn, i)); 4848 break; 4849 } 4850 } 4851 4852 (void) fclose(tfp); 4853 4854 found: 4855 (void) snprintf(tmpsign, sizeof (tmpsign), "rootfs%d", i); 4856 4857 /* add the ufs signature to the /var/run list of signatures */ 4858 ret = ufs_add_to_sign_list(tmpsign); 4859 INJECT_ERROR1("UFS_ADD_TO_SIGN_LIST", ret = -1); 4860 if (ret == -1) { 4861 (void) unlink(UFS_SIGNATURE_LIST); 4862 bam_error(FAILED_ADD_SIGNLIST, tmpsign); 4863 return (NULL); 4864 } 4865 4866 BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 4867 4868 return (s_strdup(tmpsign)); 4869 } 4870 4871 static char * 4872 get_fstype(char *osroot) 4873 { 4874 FILE *mntfp; 4875 struct mnttab mp = {0}; 4876 struct mnttab mpref = {0}; 4877 int error; 4878 int ret; 4879 const char *fcn = "get_fstype()"; 4880 4881 INJECT_ERROR1("GET_FSTYPE_OSROOT", osroot = NULL); 4882 if (osroot == NULL) { 4883 bam_error(GET_FSTYPE_ARGS); 4884 return (NULL); 4885 } 4886 4887 mntfp = fopen(MNTTAB, "r"); 4888 error = errno; 4889 INJECT_ERROR1("GET_FSTYPE_FOPEN", mntfp = NULL); 4890 if (mntfp == NULL) { 4891 bam_error(OPEN_FAIL, MNTTAB, strerror(error)); 4892 return (NULL); 4893 } 4894 4895 if (*osroot == '\0') 4896 mpref.mnt_mountp = "/"; 4897 else 4898 mpref.mnt_mountp = osroot; 4899 4900 ret = getmntany(mntfp, &mp, &mpref); 4901 INJECT_ERROR1("GET_FSTYPE_GETMNTANY", ret = 1); 4902 if (ret != 0) { 4903 bam_error(MNTTAB_MNTPT_NOT_FOUND, osroot, MNTTAB); 4904 (void) fclose(mntfp); 4905 return (NULL); 4906 } 4907 (void) fclose(mntfp); 4908 4909 INJECT_ERROR1("GET_FSTYPE_NULL", mp.mnt_fstype = NULL); 4910 if (mp.mnt_fstype == NULL) { 4911 bam_error(MNTTAB_FSTYPE_NULL, osroot); 4912 return (NULL); 4913 } 4914 4915 BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 4916 4917 return (s_strdup(mp.mnt_fstype)); 4918 } 4919 4920 static char * 4921 create_zfs_sign(char *osdev) 4922 { 4923 char tmpsign[PATH_MAX]; 4924 char *pool; 4925 const char *fcn = "create_zfs_sign()"; 4926 4927 BAM_DPRINTF((D_FUNC_ENTRY1, fcn, osdev)); 4928 4929 /* 4930 * First find the pool name 4931 */ 4932 pool = get_pool(osdev); 4933 INJECT_ERROR1("CREATE_ZFS_SIGN_GET_POOL", pool = NULL); 4934 if (pool == NULL) { 4935 bam_error(GET_POOL_FAILED, osdev); 4936 return (NULL); 4937 } 4938 4939 (void) snprintf(tmpsign, sizeof (tmpsign), "pool_%s", pool); 4940 4941 BAM_DPRINTF((D_CREATED_ZFS_SIGN, fcn, tmpsign)); 4942 4943 free(pool); 4944 4945 BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 4946 4947 return (s_strdup(tmpsign)); 4948 } 4949 4950 static char * 4951 create_new_sign(char *osdev, char *fstype) 4952 { 4953 char *sign; 4954 const char *fcn = "create_new_sign()"; 4955 4956 INJECT_ERROR1("NEW_SIGN_FSTYPE", fstype = "foofs"); 4957 4958 if (strcmp(fstype, "zfs") == 0) { 4959 BAM_DPRINTF((D_CREATE_NEW_ZFS, fcn)); 4960 sign = create_zfs_sign(osdev); 4961 } else if (strcmp(fstype, "ufs") == 0) { 4962 BAM_DPRINTF((D_CREATE_NEW_UFS, fcn)); 4963 sign = create_ufs_sign(); 4964 } else { 4965 bam_error(GRUBSIGN_NOTSUP, fstype); 4966 sign = NULL; 4967 } 4968 4969 BAM_DPRINTF((D_CREATED_NEW_SIGN, fcn, sign ? sign : "<NULL>")); 4970 return (sign); 4971 } 4972 4973 static int 4974 set_backup_common(char *mntpt, char *sign) 4975 { 4976 FILE *bfp; 4977 char backup[PATH_MAX]; 4978 char tmpsign[PATH_MAX]; 4979 int error; 4980 char *bdir; 4981 char *backup_dup; 4982 struct stat sb; 4983 int ret; 4984 const char *fcn = "set_backup_common()"; 4985 4986 (void) snprintf(backup, sizeof (backup), "%s%s", 4987 mntpt, GRUBSIGN_BACKUP); 4988 4989 /* First read the backup */ 4990 bfp = fopen(backup, "r"); 4991 if (bfp != NULL) { 4992 while (s_fgets(tmpsign, sizeof (tmpsign), bfp)) { 4993 if (strcmp(tmpsign, sign) == 0) { 4994 BAM_DPRINTF((D_FOUND_IN_BACKUP, fcn, sign)); 4995 (void) fclose(bfp); 4996 return (0); 4997 } 4998 } 4999 (void) fclose(bfp); 5000 BAM_DPRINTF((D_NOT_FOUND_IN_EXIST_BACKUP, fcn, sign)); 5001 } else { 5002 BAM_DPRINTF((D_BACKUP_NOT_EXIST, fcn, backup)); 5003 } 5004 5005 /* 5006 * Didn't find the correct signature. First create 5007 * the directory if necessary. 5008 */ 5009 5010 /* dirname() modifies its argument so dup it */ 5011 backup_dup = s_strdup(backup); 5012 bdir = dirname(backup_dup); 5013 assert(bdir); 5014 5015 ret = stat(bdir, &sb); 5016 INJECT_ERROR1("SET_BACKUP_STAT", ret = -1); 5017 if (ret == -1) { 5018 BAM_DPRINTF((D_BACKUP_DIR_NOEXIST, fcn, bdir)); 5019 ret = mkdirp(bdir, 0755); 5020 error = errno; 5021 INJECT_ERROR1("SET_BACKUP_MKDIRP", ret = -1); 5022 if (ret == -1) { 5023 bam_error(GRUBSIGN_BACKUP_MKDIRERR, 5024 GRUBSIGN_BACKUP, strerror(error)); 5025 free(backup_dup); 5026 return (-1); 5027 } 5028 } 5029 free(backup_dup); 5030 5031 /* 5032 * Open the backup in append mode to add the correct 5033 * signature; 5034 */ 5035 bfp = fopen(backup, "a"); 5036 error = errno; 5037 INJECT_ERROR1("SET_BACKUP_FOPEN_A", bfp = NULL); 5038 if (bfp == NULL) { 5039 bam_error(GRUBSIGN_BACKUP_OPENERR, 5040 GRUBSIGN_BACKUP, strerror(error)); 5041 return (-1); 5042 } 5043 5044 (void) snprintf(tmpsign, sizeof (tmpsign), "%s\n", sign); 5045 5046 ret = fputs(tmpsign, bfp); 5047 error = errno; 5048 INJECT_ERROR1("SET_BACKUP_FPUTS", ret = 0); 5049 if (ret != strlen(tmpsign)) { 5050 bam_error(GRUBSIGN_BACKUP_WRITEERR, 5051 GRUBSIGN_BACKUP, strerror(error)); 5052 (void) fclose(bfp); 5053 return (-1); 5054 } 5055 5056 (void) fclose(bfp); 5057 5058 if (bam_verbose) 5059 bam_print(GRUBSIGN_BACKUP_UPDATED, GRUBSIGN_BACKUP); 5060 5061 BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 5062 5063 return (0); 5064 } 5065 5066 static int 5067 set_backup_ufs(char *osroot, char *sign) 5068 { 5069 const char *fcn = "set_backup_ufs()"; 5070 5071 BAM_DPRINTF((D_FUNC_ENTRY2, fcn, osroot, sign)); 5072 return (set_backup_common(osroot, sign)); 5073 } 5074 5075 static int 5076 set_backup_zfs(char *osdev, char *sign) 5077 { 5078 char *pool; 5079 char *mntpt; 5080 zfs_mnted_t mnted; 5081 int ret; 5082 const char *fcn = "set_backup_zfs()"; 5083 5084 BAM_DPRINTF((D_FUNC_ENTRY2, fcn, osdev, sign)); 5085 5086 pool = get_pool(osdev); 5087 INJECT_ERROR1("SET_BACKUP_GET_POOL", pool = NULL); 5088 if (pool == NULL) { 5089 bam_error(GET_POOL_FAILED, osdev); 5090 return (-1); 5091 } 5092 5093 mntpt = mount_top_dataset(pool, &mnted); 5094 INJECT_ERROR1("SET_BACKUP_MOUNT_DATASET", mntpt = NULL); 5095 if (mntpt == NULL) { 5096 bam_error(FAIL_MNT_TOP_DATASET, pool); 5097 free(pool); 5098 return (-1); 5099 } 5100 5101 ret = set_backup_common(mntpt, sign); 5102 5103 (void) umount_top_dataset(pool, mnted, mntpt); 5104 5105 free(pool); 5106 5107 INJECT_ERROR1("SET_BACKUP_ZFS_FAIL", ret = 1); 5108 if (ret == 0) { 5109 BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 5110 } else { 5111 BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 5112 } 5113 5114 return (ret); 5115 } 5116 5117 static int 5118 set_backup(char *osroot, char *osdev, char *sign, char *fstype) 5119 { 5120 const char *fcn = "set_backup()"; 5121 int ret; 5122 5123 INJECT_ERROR1("SET_BACKUP_FSTYPE", fstype = "foofs"); 5124 5125 if (strcmp(fstype, "ufs") == 0) { 5126 BAM_DPRINTF((D_SET_BACKUP_UFS, fcn)); 5127 ret = set_backup_ufs(osroot, sign); 5128 } else if (strcmp(fstype, "zfs") == 0) { 5129 BAM_DPRINTF((D_SET_BACKUP_ZFS, fcn)); 5130 ret = set_backup_zfs(osdev, sign); 5131 } else { 5132 bam_error(GRUBSIGN_NOTSUP, fstype); 5133 ret = -1; 5134 } 5135 5136 if (ret == 0) { 5137 BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 5138 } else { 5139 BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 5140 } 5141 5142 return (ret); 5143 } 5144 5145 static int 5146 set_primary_common(char *mntpt, char *sign) 5147 { 5148 char signfile[PATH_MAX]; 5149 char signdir[PATH_MAX]; 5150 struct stat sb; 5151 int fd; 5152 int error; 5153 int ret; 5154 const char *fcn = "set_primary_common()"; 5155 5156 (void) snprintf(signfile, sizeof (signfile), "%s/%s/%s", 5157 mntpt, GRUBSIGN_DIR, sign); 5158 5159 if (stat(signfile, &sb) != -1) { 5160 if (bam_verbose) 5161 bam_print(PRIMARY_SIGN_EXISTS, sign); 5162 return (0); 5163 } else { 5164 BAM_DPRINTF((D_PRIMARY_NOT_EXIST, fcn, signfile)); 5165 } 5166 5167 (void) snprintf(signdir, sizeof (signdir), "%s/%s", 5168 mntpt, GRUBSIGN_DIR); 5169 5170 if (stat(signdir, &sb) == -1) { 5171 BAM_DPRINTF((D_PRIMARY_DIR_NOEXIST, fcn, signdir)); 5172 ret = mkdirp(signdir, 0755); 5173 error = errno; 5174 INJECT_ERROR1("SET_PRIMARY_MKDIRP", ret = -1); 5175 if (ret == -1) { 5176 bam_error(GRUBSIGN_MKDIR_ERR, signdir, strerror(errno)); 5177 return (-1); 5178 } 5179 } 5180 5181 fd = open(signfile, O_RDWR|O_CREAT|O_TRUNC, 0444); 5182 error = errno; 5183 INJECT_ERROR1("PRIMARY_SIGN_CREAT", fd = -1); 5184 if (fd == -1) { 5185 bam_error(GRUBSIGN_PRIMARY_CREATERR, signfile, strerror(error)); 5186 return (-1); 5187 } 5188 5189 ret = fsync(fd); 5190 error = errno; 5191 INJECT_ERROR1("PRIMARY_FSYNC", ret = -1); 5192 if (ret != 0) { 5193 bam_error(GRUBSIGN_PRIMARY_SYNCERR, signfile, strerror(error)); 5194 } 5195 5196 (void) close(fd); 5197 5198 if (bam_verbose) 5199 bam_print(GRUBSIGN_CREATED_PRIMARY, signfile); 5200 5201 BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 5202 5203 return (0); 5204 } 5205 5206 static int 5207 set_primary_ufs(char *osroot, char *sign) 5208 { 5209 const char *fcn = "set_primary_ufs()"; 5210 5211 BAM_DPRINTF((D_FUNC_ENTRY2, fcn, osroot, sign)); 5212 return (set_primary_common(osroot, sign)); 5213 } 5214 5215 static int 5216 set_primary_zfs(char *osdev, char *sign) 5217 { 5218 char *pool; 5219 char *mntpt; 5220 zfs_mnted_t mnted; 5221 int ret; 5222 const char *fcn = "set_primary_zfs()"; 5223 5224 BAM_DPRINTF((D_FUNC_ENTRY2, fcn, osdev, sign)); 5225 5226 pool = get_pool(osdev); 5227 INJECT_ERROR1("SET_PRIMARY_ZFS_GET_POOL", pool = NULL); 5228 if (pool == NULL) { 5229 bam_error(GET_POOL_FAILED, osdev); 5230 return (-1); 5231 } 5232 5233 /* Pool name must exist in the sign */ 5234 ret = (strstr(sign, pool) != NULL); 5235 INJECT_ERROR1("SET_PRIMARY_ZFS_POOL_SIGN_INCOMPAT", ret = 0); 5236 if (ret == 0) { 5237 bam_error(POOL_SIGN_INCOMPAT, pool, sign); 5238 free(pool); 5239 return (-1); 5240 } 5241 5242 mntpt = mount_top_dataset(pool, &mnted); 5243 INJECT_ERROR1("SET_PRIMARY_ZFS_MOUNT_DATASET", mntpt = NULL); 5244 if (mntpt == NULL) { 5245 bam_error(FAIL_MNT_TOP_DATASET, pool); 5246 free(pool); 5247 return (-1); 5248 } 5249 5250 ret = set_primary_common(mntpt, sign); 5251 5252 (void) umount_top_dataset(pool, mnted, mntpt); 5253 5254 free(pool); 5255 5256 INJECT_ERROR1("SET_PRIMARY_ZFS_FAIL", ret = 1); 5257 if (ret == 0) { 5258 BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 5259 } else { 5260 BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 5261 } 5262 5263 return (ret); 5264 } 5265 5266 static int 5267 set_primary(char *osroot, char *osdev, char *sign, char *fstype) 5268 { 5269 const char *fcn = "set_primary()"; 5270 int ret; 5271 5272 INJECT_ERROR1("SET_PRIMARY_FSTYPE", fstype = "foofs"); 5273 if (strcmp(fstype, "ufs") == 0) { 5274 BAM_DPRINTF((D_SET_PRIMARY_UFS, fcn)); 5275 ret = set_primary_ufs(osroot, sign); 5276 } else if (strcmp(fstype, "zfs") == 0) { 5277 BAM_DPRINTF((D_SET_PRIMARY_ZFS, fcn)); 5278 ret = set_primary_zfs(osdev, sign); 5279 } else { 5280 bam_error(GRUBSIGN_NOTSUP, fstype); 5281 ret = -1; 5282 } 5283 5284 if (ret == 0) { 5285 BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 5286 } else { 5287 BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 5288 } 5289 5290 return (ret); 5291 } 5292 5293 static int 5294 ufs_add_to_sign_list(char *sign) 5295 { 5296 FILE *tfp; 5297 char signline[MAXNAMELEN]; 5298 char cmd[PATH_MAX]; 5299 int ret; 5300 int error; 5301 const char *fcn = "ufs_add_to_sign_list()"; 5302 5303 INJECT_ERROR1("ADD_TO_SIGN_LIST_NOT_UFS", sign = "pool_rpool5"); 5304 if (strncmp(sign, GRUBSIGN_UFS_PREFIX, 5305 strlen(GRUBSIGN_UFS_PREFIX)) != 0) { 5306 bam_error(INVALID_UFS_SIGN, sign); 5307 (void) unlink(UFS_SIGNATURE_LIST); 5308 return (-1); 5309 } 5310 5311 /* 5312 * most failures in this routine are not a fatal error 5313 * We simply unlink the /var/run file and continue 5314 */ 5315 5316 ret = rename(UFS_SIGNATURE_LIST, UFS_SIGNATURE_LIST".tmp"); 5317 error = errno; 5318 INJECT_ERROR1("ADD_TO_SIGN_LIST_RENAME", ret = -1); 5319 if (ret == -1) { 5320 bam_error(RENAME_FAIL, UFS_SIGNATURE_LIST".tmp", 5321 strerror(error)); 5322 (void) unlink(UFS_SIGNATURE_LIST); 5323 return (0); 5324 } 5325 5326 tfp = fopen(UFS_SIGNATURE_LIST".tmp", "a"); 5327 error = errno; 5328 INJECT_ERROR1("ADD_TO_SIGN_LIST_FOPEN", tfp = NULL); 5329 if (tfp == NULL) { 5330 bam_error(OPEN_FAIL, UFS_SIGNATURE_LIST".tmp", strerror(error)); 5331 (void) unlink(UFS_SIGNATURE_LIST".tmp"); 5332 return (0); 5333 } 5334 5335 (void) snprintf(signline, sizeof (signline), "%s\n", sign); 5336 5337 ret = fputs(signline, tfp); 5338 error = errno; 5339 INJECT_ERROR1("ADD_TO_SIGN_LIST_FPUTS", ret = 0); 5340 if (ret != strlen(signline)) { 5341 bam_error(SIGN_LIST_FPUTS_ERR, sign, strerror(error)); 5342 (void) fclose(tfp); 5343 (void) unlink(UFS_SIGNATURE_LIST".tmp"); 5344 return (0); 5345 } 5346 5347 ret = fclose(tfp); 5348 error = errno; 5349 INJECT_ERROR1("ADD_TO_SIGN_LIST_FCLOSE", ret = EOF); 5350 if (ret == EOF) { 5351 bam_error(CLOSE_FAIL, UFS_SIGNATURE_LIST".tmp", 5352 strerror(error)); 5353 (void) unlink(UFS_SIGNATURE_LIST".tmp"); 5354 return (0); 5355 } 5356 5357 /* Sort the list again */ 5358 (void) snprintf(cmd, sizeof (cmd), 5359 "/usr/bin/sort -u %s.tmp > %s.sorted", 5360 UFS_SIGNATURE_LIST, UFS_SIGNATURE_LIST); 5361 5362 ret = exec_cmd(cmd, NULL); 5363 INJECT_ERROR1("ADD_TO_SIGN_LIST_SORT", ret = 1); 5364 if (ret != 0) { 5365 bam_error(GRUBSIGN_SORT_FAILED); 5366 (void) unlink(UFS_SIGNATURE_LIST".sorted"); 5367 (void) unlink(UFS_SIGNATURE_LIST".tmp"); 5368 return (0); 5369 } 5370 5371 (void) unlink(UFS_SIGNATURE_LIST".tmp"); 5372 5373 ret = rename(UFS_SIGNATURE_LIST".sorted", UFS_SIGNATURE_LIST); 5374 error = errno; 5375 INJECT_ERROR1("ADD_TO_SIGN_LIST_RENAME2", ret = -1); 5376 if (ret == -1) { 5377 bam_error(RENAME_FAIL, UFS_SIGNATURE_LIST, strerror(error)); 5378 (void) unlink(UFS_SIGNATURE_LIST".sorted"); 5379 return (0); 5380 } 5381 5382 BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 5383 5384 return (0); 5385 } 5386 5387 static int 5388 set_signature(char *osroot, char *osdev, char *sign, char *fstype) 5389 { 5390 int ret; 5391 const char *fcn = "set_signature()"; 5392 5393 BAM_DPRINTF((D_FUNC_ENTRY4, fcn, osroot, osdev, sign, fstype)); 5394 5395 ret = set_backup(osroot, osdev, sign, fstype); 5396 INJECT_ERROR1("SET_SIGNATURE_BACKUP", ret = -1); 5397 if (ret == -1) { 5398 BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 5399 bam_error(SET_BACKUP_FAILED, sign, osroot, osdev); 5400 return (-1); 5401 } 5402 5403 ret = set_primary(osroot, osdev, sign, fstype); 5404 INJECT_ERROR1("SET_SIGNATURE_PRIMARY", ret = -1); 5405 5406 if (ret == 0) { 5407 BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 5408 } else { 5409 BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 5410 bam_error(SET_PRIMARY_FAILED, sign, osroot, osdev); 5411 5412 } 5413 return (ret); 5414 } 5415 5416 char * 5417 get_grubsign(char *osroot, char *osdev) 5418 { 5419 char *grubsign; /* (<sign>,#,#) */ 5420 char *slice; 5421 int fdiskpart; 5422 char *sign; 5423 char *fstype; 5424 int ret; 5425 const char *fcn = "get_grubsign()"; 5426 5427 BAM_DPRINTF((D_FUNC_ENTRY2, fcn, osroot, osdev)); 5428 5429 fstype = get_fstype(osroot); 5430 INJECT_ERROR1("GET_GRUBSIGN_FSTYPE", fstype = NULL); 5431 if (fstype == NULL) { 5432 bam_error(GET_FSTYPE_FAILED, osroot); 5433 return (NULL); 5434 } 5435 5436 sign = find_existing_sign(osroot, osdev, fstype); 5437 INJECT_ERROR1("FIND_EXISTING_SIGN", sign = NULL); 5438 if (sign == NULL) { 5439 BAM_DPRINTF((D_GET_GRUBSIGN_NO_EXISTING, fcn, osroot, osdev)); 5440 sign = create_new_sign(osdev, fstype); 5441 INJECT_ERROR1("CREATE_NEW_SIGN", sign = NULL); 5442 if (sign == NULL) { 5443 bam_error(GRUBSIGN_CREATE_FAIL, osdev); 5444 free(fstype); 5445 return (NULL); 5446 } 5447 } 5448 5449 ret = set_signature(osroot, osdev, sign, fstype); 5450 INJECT_ERROR1("SET_SIGNATURE_FAIL", ret = -1); 5451 if (ret == -1) { 5452 bam_error(GRUBSIGN_WRITE_FAIL, osdev); 5453 free(sign); 5454 free(fstype); 5455 (void) unlink(UFS_SIGNATURE_LIST); 5456 return (NULL); 5457 } 5458 5459 free(fstype); 5460 5461 if (bam_verbose) 5462 bam_print(GRUBSIGN_FOUND_OR_CREATED, sign, osdev); 5463 5464 fdiskpart = get_partition(osdev); 5465 INJECT_ERROR1("GET_GRUBSIGN_FDISK", fdiskpart = -1); 5466 if (fdiskpart == -1) { 5467 bam_error(FDISKPART_FAIL, osdev); 5468 free(sign); 5469 return (NULL); 5470 } 5471 5472 slice = strrchr(osdev, 's'); 5473 5474 grubsign = s_calloc(1, MAXNAMELEN + 10); 5475 if (slice) { 5476 (void) snprintf(grubsign, MAXNAMELEN + 10, "(%s,%d,%c)", 5477 sign, fdiskpart, slice[1] + 'a' - '0'); 5478 } else 5479 (void) snprintf(grubsign, MAXNAMELEN + 10, "(%s,%d)", 5480 sign, fdiskpart); 5481 5482 free(sign); 5483 5484 BAM_DPRINTF((D_GET_GRUBSIGN_SUCCESS, fcn, grubsign)); 5485 5486 return (grubsign); 5487 } 5488 5489 static char * 5490 get_title(char *rootdir) 5491 { 5492 static char title[80]; 5493 char *cp = NULL; 5494 char release[PATH_MAX]; 5495 FILE *fp; 5496 const char *fcn = "get_title()"; 5497 5498 /* open the /etc/release file */ 5499 (void) snprintf(release, sizeof (release), "%s/etc/release", rootdir); 5500 5501 fp = fopen(release, "r"); 5502 if (fp == NULL) { 5503 bam_error(OPEN_FAIL, release, strerror(errno)); 5504 cp = NULL; 5505 goto out; 5506 } 5507 5508 while (s_fgets(title, sizeof (title), fp) != NULL) { 5509 cp = strstr(title, "Solaris"); 5510 if (cp) 5511 break; 5512 } 5513 (void) fclose(fp); 5514 5515 out: 5516 cp = cp ? cp : "Solaris"; 5517 5518 BAM_DPRINTF((D_GET_TITLE, fcn, cp)); 5519 5520 return (cp); 5521 } 5522 5523 char * 5524 get_special(char *mountp) 5525 { 5526 FILE *mntfp; 5527 struct mnttab mp = {0}; 5528 struct mnttab mpref = {0}; 5529 int error; 5530 int ret; 5531 const char *fcn = "get_special()"; 5532 5533 INJECT_ERROR1("GET_SPECIAL_MNTPT", mountp = NULL); 5534 if (mountp == NULL) { 5535 bam_error(GET_SPECIAL_NULL_MNTPT); 5536 return (NULL); 5537 } 5538 5539 mntfp = fopen(MNTTAB, "r"); 5540 error = errno; 5541 INJECT_ERROR1("GET_SPECIAL_MNTTAB_OPEN", mntfp = NULL); 5542 if (mntfp == NULL) { 5543 bam_error(OPEN_FAIL, MNTTAB, strerror(error)); 5544 return (NULL); 5545 } 5546 5547 if (*mountp == '\0') 5548 mpref.mnt_mountp = "/"; 5549 else 5550 mpref.mnt_mountp = mountp; 5551 5552 ret = getmntany(mntfp, &mp, &mpref); 5553 INJECT_ERROR1("GET_SPECIAL_MNTTAB_SEARCH", ret = 1); 5554 if (ret != 0) { 5555 (void) fclose(mntfp); 5556 BAM_DPRINTF((D_GET_SPECIAL_NOT_IN_MNTTAB, fcn, mountp)); 5557 return (NULL); 5558 } 5559 (void) fclose(mntfp); 5560 5561 BAM_DPRINTF((D_GET_SPECIAL, fcn, mp.mnt_special)); 5562 5563 return (s_strdup(mp.mnt_special)); 5564 } 5565 5566 static void 5567 free_physarray(char **physarray, int n) 5568 { 5569 int i; 5570 const char *fcn = "free_physarray()"; 5571 5572 assert(physarray); 5573 assert(n); 5574 5575 BAM_DPRINTF((D_FUNC_ENTRY_N1, fcn, n)); 5576 5577 for (i = 0; i < n; i++) { 5578 free(physarray[i]); 5579 } 5580 free(physarray); 5581 5582 BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 5583 } 5584 5585 static int 5586 zfs_get_physical(char *special, char ***physarray, int *n) 5587 { 5588 char sdup[PATH_MAX]; 5589 char cmd[PATH_MAX]; 5590 char dsk[PATH_MAX]; 5591 char *pool; 5592 filelist_t flist = {0}; 5593 line_t *lp; 5594 line_t *startlp; 5595 char *comp1; 5596 int i; 5597 int ret; 5598 const char *fcn = "zfs_get_physical()"; 5599 5600 assert(special); 5601 5602 BAM_DPRINTF((D_FUNC_ENTRY1, fcn, special)); 5603 5604 INJECT_ERROR1("INVALID_ZFS_SPECIAL", special = "/foo"); 5605 if (special[0] == '/') { 5606 bam_error(INVALID_ZFS_SPECIAL, special); 5607 return (-1); 5608 } 5609 5610 (void) strlcpy(sdup, special, sizeof (sdup)); 5611 5612 pool = strtok(sdup, "/"); 5613 INJECT_ERROR1("ZFS_GET_PHYS_POOL", pool = NULL); 5614 if (pool == NULL) { 5615 bam_error(CANT_FIND_POOL_FROM_SPECIAL, special); 5616 return (-1); 5617 } 5618 5619 (void) snprintf(cmd, sizeof (cmd), "/sbin/zpool status %s", pool); 5620 5621 ret = exec_cmd(cmd, &flist); 5622 INJECT_ERROR1("ZFS_GET_PHYS_STATUS", ret = 1); 5623 if (ret != 0) { 5624 bam_error(ZFS_GET_POOL_STATUS, pool); 5625 return (-1); 5626 } 5627 5628 INJECT_ERROR1("ZFS_GET_PHYS_STATUS_OUT", flist.head = NULL); 5629 if (flist.head == NULL) { 5630 bam_error(BAD_ZPOOL_STATUS, pool); 5631 filelist_free(&flist); 5632 return (-1); 5633 } 5634 5635 for (lp = flist.head; lp; lp = lp->next) { 5636 BAM_DPRINTF((D_STRTOK_ZPOOL_STATUS, fcn, lp->line)); 5637 comp1 = strtok(lp->line, " \t"); 5638 if (comp1 == NULL) { 5639 free(lp->line); 5640 lp->line = NULL; 5641 } else { 5642 comp1 = s_strdup(comp1); 5643 free(lp->line); 5644 lp->line = comp1; 5645 } 5646 } 5647 5648 for (lp = flist.head; lp; lp = lp->next) { 5649 if (lp->line == NULL) 5650 continue; 5651 if (strcmp(lp->line, pool) == 0) { 5652 BAM_DPRINTF((D_FOUND_POOL_IN_ZPOOL_STATUS, fcn, pool)); 5653 break; 5654 } 5655 } 5656 5657 if (lp == NULL) { 5658 bam_error(NO_POOL_IN_ZPOOL_STATUS, pool); 5659 filelist_free(&flist); 5660 return (-1); 5661 } 5662 5663 startlp = lp->next; 5664 for (i = 0, lp = startlp; lp; lp = lp->next) { 5665 if (lp->line == NULL) 5666 continue; 5667 if (strcmp(lp->line, "mirror") == 0) 5668 continue; 5669 if (lp->line[0] == '\0' || strcmp(lp->line, "errors:") == 0) 5670 break; 5671 i++; 5672 BAM_DPRINTF((D_COUNTING_ZFS_PHYS, fcn, i)); 5673 } 5674 5675 if (i == 0) { 5676 bam_error(NO_PHYS_IN_ZPOOL_STATUS, pool); 5677 filelist_free(&flist); 5678 return (-1); 5679 } 5680 5681 *n = i; 5682 *physarray = s_calloc(*n, sizeof (char *)); 5683 for (i = 0, lp = startlp; lp; lp = lp->next) { 5684 if (lp->line == NULL) 5685 continue; 5686 if (strcmp(lp->line, "mirror") == 0) 5687 continue; 5688 if (strcmp(lp->line, "errors:") == 0) 5689 break; 5690 if (strncmp(lp->line, "/dev/dsk/", strlen("/dev/dsk/")) != 0 && 5691 strncmp(lp->line, "/dev/rdsk/", 5692 strlen("/dev/rdsk/")) != 0) { 5693 (void) snprintf(dsk, sizeof (dsk), "/dev/dsk/%s", 5694 lp->line); 5695 } else { 5696 (void) strlcpy(dsk, lp->line, sizeof (dsk)); 5697 } 5698 BAM_DPRINTF((D_ADDING_ZFS_PHYS, fcn, dsk, pool)); 5699 (*physarray)[i++] = s_strdup(dsk); 5700 } 5701 5702 assert(i == *n); 5703 5704 filelist_free(&flist); 5705 5706 BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 5707 return (0); 5708 } 5709 5710 /* 5711 * Certain services needed to run metastat successfully may not 5712 * be enabled. Enable them now. 5713 */ 5714 /* 5715 * Checks if the specified service is online 5716 * Returns: 1 if the service is online 5717 * 0 if the service is not online 5718 * -1 on error 5719 */ 5720 static int 5721 is_svc_online(char *svc) 5722 { 5723 char *state; 5724 const char *fcn = "is_svc_online()"; 5725 5726 BAM_DPRINTF((D_FUNC_ENTRY1, fcn, svc)); 5727 5728 state = smf_get_state(svc); 5729 INJECT_ERROR2("GET_SVC_STATE", free(state), state = NULL); 5730 if (state == NULL) { 5731 bam_error(GET_SVC_STATE_ERR, svc); 5732 return (-1); 5733 } 5734 BAM_DPRINTF((D_GOT_SVC_STATUS, fcn, svc)); 5735 5736 if (strcmp(state, SCF_STATE_STRING_ONLINE) == 0) { 5737 BAM_DPRINTF((D_SVC_ONLINE, fcn, svc)); 5738 free(state); 5739 return (1); 5740 } 5741 5742 BAM_DPRINTF((D_SVC_NOT_ONLINE, fcn, state, svc)); 5743 5744 free(state); 5745 5746 return (0); 5747 } 5748 5749 static int 5750 enable_svc(char *svc) 5751 { 5752 int ret; 5753 int sleeptime; 5754 const char *fcn = "enable_svc()"; 5755 5756 ret = is_svc_online(svc); 5757 if (ret == -1) { 5758 bam_error(SVC_IS_ONLINE_FAILED, svc); 5759 return (-1); 5760 } else if (ret == 1) { 5761 BAM_DPRINTF((D_SVC_ALREADY_ONLINE, fcn, svc)); 5762 return (0); 5763 } 5764 5765 /* Service is not enabled. Enable it now. */ 5766 ret = smf_enable_instance(svc, 0); 5767 INJECT_ERROR1("ENABLE_SVC_FAILED", ret = -1); 5768 if (ret != 0) { 5769 bam_error(ENABLE_SVC_FAILED, svc); 5770 return (-1); 5771 } 5772 5773 BAM_DPRINTF((D_SVC_ONLINE_INITIATED, fcn, svc)); 5774 5775 sleeptime = 0; 5776 do { 5777 ret = is_svc_online(svc); 5778 INJECT_ERROR1("SVC_ONLINE_SUCCESS", ret = 1); 5779 INJECT_ERROR1("SVC_ONLINE_FAILURE", ret = -1); 5780 INJECT_ERROR1("SVC_ONLINE_NOTYET", ret = 0); 5781 if (ret == -1) { 5782 bam_error(ERR_SVC_GET_ONLINE, svc); 5783 return (-1); 5784 } else if (ret == 1) { 5785 BAM_DPRINTF((D_SVC_NOW_ONLINE, fcn, svc)); 5786 return (1); 5787 } 5788 (void) sleep(1); 5789 } while (sleeptime < 60); 5790 5791 bam_error(TIMEOUT_ENABLE_SVC, svc); 5792 5793 return (-1); 5794 } 5795 5796 static int 5797 ufs_get_physical(char *special, char ***physarray, int *n) 5798 { 5799 char cmd[PATH_MAX]; 5800 char *shortname; 5801 filelist_t flist = {0}; 5802 char *meta; 5803 char *type; 5804 char *comp1; 5805 char *comp2; 5806 char *comp3; 5807 char *comp4; 5808 int i; 5809 line_t *lp; 5810 int ret; 5811 char *svc; 5812 const char *fcn = "ufs_get_physical()"; 5813 5814 assert(special); 5815 5816 BAM_DPRINTF((D_FUNC_ENTRY1, fcn, special)); 5817 5818 if (strncmp(special, "/dev/md/", strlen("/dev/md/")) != 0) { 5819 bam_error(UFS_GET_PHYS_NOT_SVM, special); 5820 return (-1); 5821 } 5822 5823 if (strncmp(special, "/dev/md/dsk/", strlen("/dev/md/dsk/")) == 0) { 5824 shortname = special + strlen("/dev/md/dsk/"); 5825 } else if (strncmp(special, "/dev/md/rdsk/", 5826 strlen("/dev/md/rdsk/")) == 0) { 5827 shortname = special + strlen("/dev/md/rdsk"); 5828 } else { 5829 bam_error(UFS_GET_PHYS_INVALID_SVM, special); 5830 return (-1); 5831 } 5832 5833 BAM_DPRINTF((D_UFS_SVM_SHORT, fcn, special, shortname)); 5834 5835 svc = "network/rpc/meta:default"; 5836 if (enable_svc(svc) == -1) { 5837 bam_error(UFS_SVM_METASTAT_SVC_ERR, svc); 5838 } 5839 5840 (void) snprintf(cmd, sizeof (cmd), "/sbin/metastat -p %s", shortname); 5841 5842 ret = exec_cmd(cmd, &flist); 5843 INJECT_ERROR1("UFS_SVM_METASTAT", ret = 1); 5844 if (ret != 0) { 5845 bam_error(UFS_SVM_METASTAT_ERR, shortname); 5846 return (-1); 5847 } 5848 5849 INJECT_ERROR1("UFS_SVM_METASTAT_OUT", flist.head = NULL); 5850 if (flist.head == NULL) { 5851 bam_error(BAD_UFS_SVM_METASTAT, shortname); 5852 filelist_free(&flist); 5853 return (-1); 5854 } 5855 5856 /* 5857 * Check if not a mirror. We only parse a single metadevice 5858 * if not a mirror 5859 */ 5860 meta = strtok(flist.head->line, " \t"); 5861 type = strtok(NULL, " \t"); 5862 if (meta == NULL || type == NULL) { 5863 bam_error(ERROR_PARSE_UFS_SVM_METASTAT, shortname); 5864 filelist_free(&flist); 5865 return (-1); 5866 } 5867 if (strcmp(type, "-m") != 0) { 5868 comp1 = strtok(NULL, " \t"); 5869 comp2 = strtok(NULL, " \t"); 5870 if (comp1 == NULL || comp2 != NULL) { 5871 bam_error(INVALID_UFS_SVM_METASTAT, shortname); 5872 filelist_free(&flist); 5873 return (-1); 5874 } 5875 BAM_DPRINTF((D_UFS_SVM_ONE_COMP, fcn, comp1, shortname)); 5876 *physarray = s_calloc(1, sizeof (char *)); 5877 (*physarray)[0] = s_strdup(comp1); 5878 *n = 1; 5879 filelist_free(&flist); 5880 return (0); 5881 } 5882 5883 /* 5884 * Okay we have a mirror. Everything after the first line 5885 * is a submirror 5886 */ 5887 for (i = 0, lp = flist.head->next; lp; lp = lp->next) { 5888 if (strstr(lp->line, "/dev/dsk/") == NULL && 5889 strstr(lp->line, "/dev/rdsk/") == NULL) { 5890 bam_error(CANNOT_PARSE_UFS_SVM_METASTAT, shortname); 5891 filelist_free(&flist); 5892 return (-1); 5893 } 5894 i++; 5895 } 5896 5897 *physarray = s_calloc(i, sizeof (char *)); 5898 *n = i; 5899 5900 for (i = 0, lp = flist.head->next; lp; lp = lp->next) { 5901 comp1 = strtok(lp->line, " \t"); 5902 comp2 = strtok(NULL, " \t"); 5903 comp3 = strtok(NULL, " \t"); 5904 comp4 = strtok(NULL, " \t"); 5905 5906 if (comp3 == NULL || comp4 == NULL || 5907 (strncmp(comp4, "/dev/dsk/", strlen("/dev/dsk/")) != 0 && 5908 strncmp(comp4, "/dev/rdsk/", strlen("/dev/rdsk/")) != 0)) { 5909 bam_error(CANNOT_PARSE_UFS_SVM_SUBMIRROR, shortname); 5910 filelist_free(&flist); 5911 free_physarray(*physarray, *n); 5912 return (-1); 5913 } 5914 5915 (*physarray)[i++] = s_strdup(comp4); 5916 } 5917 5918 assert(i == *n); 5919 5920 filelist_free(&flist); 5921 5922 BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 5923 return (0); 5924 } 5925 5926 static int 5927 get_physical(char *menu_root, char ***physarray, int *n) 5928 { 5929 char *special; 5930 int ret; 5931 const char *fcn = "get_physical()"; 5932 5933 assert(menu_root); 5934 assert(physarray); 5935 assert(n); 5936 5937 *physarray = NULL; 5938 *n = 0; 5939 5940 BAM_DPRINTF((D_FUNC_ENTRY1, fcn, menu_root)); 5941 5942 /* First get the device special file from /etc/mnttab */ 5943 special = get_special(menu_root); 5944 INJECT_ERROR1("GET_PHYSICAL_SPECIAL", special = NULL); 5945 if (special == NULL) { 5946 bam_error(GET_SPECIAL_NULL, menu_root); 5947 return (-1); 5948 } 5949 5950 /* If already a physical device nothing to do */ 5951 if (strncmp(special, "/dev/dsk/", strlen("/dev/dsk/")) == 0 || 5952 strncmp(special, "/dev/rdsk/", strlen("/dev/rdsk/")) == 0) { 5953 BAM_DPRINTF((D_GET_PHYSICAL_ALREADY, fcn, menu_root, special)); 5954 BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 5955 *physarray = s_calloc(1, sizeof (char *)); 5956 (*physarray)[0] = special; 5957 *n = 1; 5958 return (0); 5959 } 5960 5961 if (is_zfs(menu_root)) { 5962 ret = zfs_get_physical(special, physarray, n); 5963 } else if (is_ufs(menu_root)) { 5964 ret = ufs_get_physical(special, physarray, n); 5965 } else { 5966 bam_error(GET_PHYSICAL_NOTSUP_FSTYPE, menu_root, special); 5967 ret = -1; 5968 } 5969 5970 free(special); 5971 5972 INJECT_ERROR1("GET_PHYSICAL_RET", ret = -1); 5973 if (ret == -1) { 5974 BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 5975 } else { 5976 int i; 5977 assert (*n > 0); 5978 for (i = 0; i < *n; i++) { 5979 BAM_DPRINTF((D_GET_PHYSICAL_RET, fcn, (*physarray)[i])); 5980 } 5981 } 5982 5983 return (ret); 5984 } 5985 5986 static int 5987 is_bootdisk(char *osroot, char *physical) 5988 { 5989 int ret; 5990 char *grubroot; 5991 char *bootp; 5992 const char *fcn = "is_bootdisk()"; 5993 5994 assert(osroot); 5995 assert(physical); 5996 5997 BAM_DPRINTF((D_FUNC_ENTRY2, fcn, osroot, physical)); 5998 5999 bootp = strstr(physical, "p0:boot"); 6000 if (bootp) 6001 *bootp = '\0'; 6002 /* 6003 * We just want the BIOS mapping for menu disk. 6004 * Don't pass menu_root to get_grubroot() as the 6005 * check that it is used for is not relevant here. 6006 * The osroot is immaterial as well - it is only used to 6007 * to find create_diskmap script. Everything hinges on 6008 * "physical" 6009 */ 6010 grubroot = get_grubroot(osroot, physical, NULL); 6011 6012 INJECT_ERROR1("IS_BOOTDISK_GRUBROOT", grubroot = NULL); 6013 if (grubroot == NULL) { 6014 bam_error(NO_GRUBROOT_FOR_DISK, fcn, physical); 6015 return (0); 6016 } 6017 ret = grubroot[3] == '0'; 6018 free(grubroot); 6019 6020 BAM_DPRINTF((D_RETURN_RET, fcn, ret)); 6021 6022 return (ret); 6023 } 6024 6025 /* 6026 * Check if menu is on the boot device 6027 * Return 0 (false) on error 6028 */ 6029 static int 6030 menu_on_bootdisk(char *osroot, char *menu_root) 6031 { 6032 char **physarray; 6033 int ret; 6034 int n; 6035 int i; 6036 int on_bootdisk; 6037 const char *fcn = "menu_on_bootdisk()"; 6038 6039 BAM_DPRINTF((D_FUNC_ENTRY2, fcn, osroot, menu_root)); 6040 6041 ret = get_physical(menu_root, &physarray, &n); 6042 INJECT_ERROR1("MENU_ON_BOOTDISK_PHYSICAL", ret = -1); 6043 if (ret != 0) { 6044 bam_error(GET_PHYSICAL_MENU_NULL, menu_root); 6045 return (0); 6046 } 6047 6048 assert(physarray); 6049 assert(n > 0); 6050 6051 on_bootdisk = 0; 6052 for (i = 0; i < n; i++) { 6053 assert(strncmp(physarray[i], "/dev/dsk/", 6054 strlen("/dev/dsk/")) == 0 || 6055 strncmp(physarray[i], "/dev/rdsk/", 6056 strlen("/dev/rdsk/")) == 0); 6057 6058 BAM_DPRINTF((D_CHECK_ON_BOOTDISK, fcn, physarray[i])); 6059 if (is_bootdisk(osroot, physarray[i])) { 6060 on_bootdisk = 1; 6061 BAM_DPRINTF((D_IS_ON_BOOTDISK, fcn, physarray[i])); 6062 } 6063 } 6064 6065 free_physarray(physarray, n); 6066 6067 INJECT_ERROR1("ON_BOOTDISK_YES", on_bootdisk = 1); 6068 INJECT_ERROR1("ON_BOOTDISK_NO", on_bootdisk = 0); 6069 if (on_bootdisk) { 6070 BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 6071 } else { 6072 BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 6073 } 6074 6075 return (on_bootdisk); 6076 } 6077 6078 void 6079 bam_add_line(menu_t *mp, entry_t *entry, line_t *prev, line_t *lp) 6080 { 6081 const char *fcn = "bam_add_line()"; 6082 6083 assert(mp); 6084 assert(entry); 6085 assert(prev); 6086 assert(lp); 6087 6088 lp->next = prev->next; 6089 if (prev->next) { 6090 BAM_DPRINTF((D_ADD_LINE_PREV_NEXT, fcn)); 6091 prev->next->prev = lp; 6092 } else { 6093 BAM_DPRINTF((D_ADD_LINE_NOT_PREV_NEXT, fcn)); 6094 } 6095 prev->next = lp; 6096 lp->prev = prev; 6097 6098 if (entry->end == prev) { 6099 BAM_DPRINTF((D_ADD_LINE_LAST_LINE_IN_ENTRY, fcn)); 6100 entry->end = lp; 6101 } 6102 if (mp->end == prev) { 6103 assert(lp->next == NULL); 6104 mp->end = lp; 6105 BAM_DPRINTF((D_ADD_LINE_LAST_LINE_IN_MENU, fcn)); 6106 } 6107 } 6108 6109 /* 6110 * look for matching bootadm entry with specified parameters 6111 * Here are the rules (based on existing usage): 6112 * - If title is specified, match on title only 6113 * - Else, match on root/findroot, kernel, and module. 6114 * Note that, if root_opt is non-zero, the absence of 6115 * root line is considered a match. 6116 */ 6117 static entry_t * 6118 find_boot_entry( 6119 menu_t *mp, 6120 char *title, 6121 char *kernel, 6122 char *findroot, 6123 char *root, 6124 char *module, 6125 int root_opt, 6126 int *entry_num) 6127 { 6128 int i; 6129 line_t *lp; 6130 entry_t *ent; 6131 const char *fcn = "find_boot_entry()"; 6132 6133 if (entry_num) 6134 *entry_num = BAM_ERROR; 6135 6136 /* find matching entry */ 6137 for (i = 0, ent = mp->entries; ent; i++, ent = ent->next) { 6138 lp = ent->start; 6139 6140 /* first line of entry must be bootadm comment */ 6141 lp = ent->start; 6142 if (lp->flags != BAM_COMMENT || 6143 strcmp(lp->arg, BAM_BOOTADM_HDR) != 0) { 6144 continue; 6145 } 6146 6147 /* advance to title line */ 6148 lp = lp->next; 6149 if (title) { 6150 if (lp->flags == BAM_TITLE && lp->arg && 6151 strcmp(lp->arg, title) == 0) { 6152 BAM_DPRINTF((D_MATCHED_TITLE, fcn, title)); 6153 break; 6154 } 6155 BAM_DPRINTF((D_NOMATCH_TITLE, fcn, title, lp->arg)); 6156 continue; /* check title only */ 6157 } 6158 6159 lp = lp->next; /* advance to root line */ 6160 if (lp == NULL) { 6161 continue; 6162 } else if (strcmp(lp->cmd, menu_cmds[FINDROOT_CMD]) == 0) { 6163 INJECT_ERROR1("FIND_BOOT_ENTRY_NULL_FINDROOT", 6164 findroot = NULL); 6165 if (findroot == NULL) { 6166 BAM_DPRINTF((D_NOMATCH_FINDROOT_NULL, 6167 fcn, lp->arg)); 6168 continue; 6169 } 6170 /* findroot command found, try match */ 6171 if (strcmp(lp->arg, findroot) != 0) { 6172 BAM_DPRINTF((D_NOMATCH_FINDROOT, 6173 fcn, findroot, lp->arg)); 6174 continue; 6175 } 6176 BAM_DPRINTF((D_MATCHED_FINDROOT, fcn, findroot)); 6177 lp = lp->next; /* advance to kernel line */ 6178 } else if (strcmp(lp->cmd, menu_cmds[ROOT_CMD]) == 0) { 6179 INJECT_ERROR1("FIND_BOOT_ENTRY_NULL_ROOT", root = NULL); 6180 if (root == NULL) { 6181 BAM_DPRINTF((D_NOMATCH_ROOT_NULL, 6182 fcn, lp->arg)); 6183 continue; 6184 } 6185 /* root cmd found, try match */ 6186 if (strcmp(lp->arg, root) != 0) { 6187 BAM_DPRINTF((D_NOMATCH_ROOT, 6188 fcn, root, lp->arg)); 6189 continue; 6190 } 6191 BAM_DPRINTF((D_MATCHED_ROOT, fcn, root)); 6192 lp = lp->next; /* advance to kernel line */ 6193 } else { 6194 INJECT_ERROR1("FIND_BOOT_ENTRY_ROOT_OPT_NO", 6195 root_opt = 0); 6196 INJECT_ERROR1("FIND_BOOT_ENTRY_ROOT_OPT_YES", 6197 root_opt = 1); 6198 /* no root command, see if root is optional */ 6199 if (root_opt == 0) { 6200 BAM_DPRINTF((D_NO_ROOT_OPT, fcn)); 6201 continue; 6202 } 6203 BAM_DPRINTF((D_ROOT_OPT, fcn)); 6204 } 6205 6206 if (lp == NULL || lp->next == NULL) { 6207 continue; 6208 } 6209 6210 if (kernel && 6211 (!check_cmd(lp->cmd, KERNEL_CMD, lp->arg, kernel))) { 6212 if (!(ent->flags & BAM_ENTRY_FAILSAFE) || 6213 !(ent->flags & BAM_ENTRY_DBOOT) || 6214 strcmp(kernel, DIRECT_BOOT_FAILSAFE_LINE) != 0) 6215 continue; 6216 6217 ent->flags |= BAM_ENTRY_UPGFSKERNEL; 6218 6219 } 6220 BAM_DPRINTF((D_KERNEL_MATCH, fcn, kernel, lp->arg)); 6221 6222 /* 6223 * Check for matching module entry (failsafe or normal). 6224 * If it fails to match, we go around the loop again. 6225 * For xpv entries, there are two module lines, so we 6226 * do the check twice. 6227 */ 6228 lp = lp->next; /* advance to module line */ 6229 if (check_cmd(lp->cmd, MODULE_CMD, lp->arg, module) || 6230 (((lp = lp->next) != NULL) && 6231 check_cmd(lp->cmd, MODULE_CMD, lp->arg, module))) { 6232 /* match found */ 6233 BAM_DPRINTF((D_MODULE_MATCH, fcn, module, lp->arg)); 6234 break; 6235 } 6236 6237 if (strcmp(module, FAILSAFE_ARCHIVE) == 0 && 6238 (strcmp(lp->prev->arg, FAILSAFE_ARCHIVE_32) == 0 || 6239 strcmp(lp->prev->arg, FAILSAFE_ARCHIVE_64) == 0)) { 6240 ent->flags |= BAM_ENTRY_UPGFSMODULE; 6241 break; 6242 } 6243 6244 } 6245 6246 if (ent && entry_num) { 6247 *entry_num = i; 6248 } 6249 6250 if (ent) { 6251 BAM_DPRINTF((D_RETURN_RET, fcn, i)); 6252 } else { 6253 BAM_DPRINTF((D_RETURN_RET, fcn, BAM_ERROR)); 6254 } 6255 return (ent); 6256 } 6257 6258 static int 6259 update_boot_entry(menu_t *mp, char *title, char *findroot, char *root, 6260 char *kernel, char *mod_kernel, char *module, int root_opt) 6261 { 6262 int i; 6263 int change_kernel = 0; 6264 entry_t *ent; 6265 line_t *lp; 6266 line_t *tlp; 6267 char linebuf[BAM_MAXLINE]; 6268 const char *fcn = "update_boot_entry()"; 6269 6270 /* note: don't match on title, it's updated on upgrade */ 6271 ent = find_boot_entry(mp, NULL, kernel, findroot, root, module, 6272 root_opt, &i); 6273 if ((ent == NULL) && (bam_direct == BAM_DIRECT_DBOOT)) { 6274 /* 6275 * We may be upgrading a kernel from multiboot to 6276 * directboot. Look for a multiboot entry. A multiboot 6277 * entry will not have a findroot line. 6278 */ 6279 ent = find_boot_entry(mp, NULL, "multiboot", NULL, root, 6280 MULTIBOOT_ARCHIVE, root_opt, &i); 6281 if (ent != NULL) { 6282 BAM_DPRINTF((D_UPGRADE_FROM_MULTIBOOT, fcn, root)); 6283 change_kernel = 1; 6284 } 6285 } else if (ent) { 6286 BAM_DPRINTF((D_FOUND_FINDROOT, fcn, findroot)); 6287 } 6288 6289 if (ent == NULL) { 6290 BAM_DPRINTF((D_ENTRY_NOT_FOUND_CREATING, fcn, findroot)); 6291 return (add_boot_entry(mp, title, findroot, 6292 kernel, mod_kernel, module)); 6293 } 6294 6295 /* replace title of existing entry and update findroot line */ 6296 lp = ent->start; 6297 lp = lp->next; /* title line */ 6298 (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s", 6299 menu_cmds[TITLE_CMD], menu_cmds[SEP_CMD], title); 6300 free(lp->arg); 6301 free(lp->line); 6302 lp->arg = s_strdup(title); 6303 lp->line = s_strdup(linebuf); 6304 BAM_DPRINTF((D_CHANGING_TITLE, fcn, title)); 6305 6306 tlp = lp; /* title line */ 6307 lp = lp->next; /* root line */ 6308 6309 /* if no root or findroot command, create a new line_t */ 6310 if (strcmp(lp->cmd, menu_cmds[ROOT_CMD]) != 0 && 6311 strcmp(lp->cmd, menu_cmds[FINDROOT_CMD]) != 0) { 6312 lp = s_calloc(1, sizeof (line_t)); 6313 bam_add_line(mp, ent, tlp, lp); 6314 } else { 6315 free(lp->cmd); 6316 free(lp->sep); 6317 free(lp->arg); 6318 free(lp->line); 6319 } 6320 6321 lp->cmd = s_strdup(menu_cmds[FINDROOT_CMD]); 6322 lp->sep = s_strdup(menu_cmds[SEP_CMD]); 6323 lp->arg = s_strdup(findroot); 6324 (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s", 6325 menu_cmds[FINDROOT_CMD], menu_cmds[SEP_CMD], findroot); 6326 lp->line = s_strdup(linebuf); 6327 BAM_DPRINTF((D_ADDING_FINDROOT_LINE, fcn, findroot)); 6328 6329 /* kernel line */ 6330 lp = lp->next; 6331 6332 if (ent->flags & BAM_ENTRY_UPGFSKERNEL) { 6333 char *params = NULL; 6334 6335 params = strstr(lp->line, "-s"); 6336 if (params != NULL) 6337 (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s%s", 6338 menu_cmds[KERNEL_DOLLAR_CMD], menu_cmds[SEP_CMD], 6339 kernel, params+2); 6340 else 6341 (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s", 6342 menu_cmds[KERNEL_DOLLAR_CMD], menu_cmds[SEP_CMD], 6343 kernel); 6344 6345 free(lp->cmd); 6346 free(lp->arg); 6347 free(lp->line); 6348 lp->cmd = s_strdup(menu_cmds[KERNEL_DOLLAR_CMD]); 6349 lp->arg = s_strdup(strstr(linebuf, "/")); 6350 lp->line = s_strdup(linebuf); 6351 ent->flags &= ~BAM_ENTRY_UPGFSKERNEL; 6352 BAM_DPRINTF((D_ADDING_KERNEL_DOLLAR, fcn, lp->prev->cmd)); 6353 } 6354 6355 if (change_kernel) { 6356 /* 6357 * We're upgrading from multiboot to directboot. 6358 */ 6359 if (strcmp(lp->cmd, menu_cmds[KERNEL_CMD]) == 0) { 6360 (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s", 6361 menu_cmds[KERNEL_DOLLAR_CMD], menu_cmds[SEP_CMD], 6362 kernel); 6363 free(lp->cmd); 6364 free(lp->arg); 6365 free(lp->line); 6366 lp->cmd = s_strdup(menu_cmds[KERNEL_DOLLAR_CMD]); 6367 lp->arg = s_strdup(kernel); 6368 lp->line = s_strdup(linebuf); 6369 lp = lp->next; 6370 BAM_DPRINTF((D_ADDING_KERNEL_DOLLAR, fcn, kernel)); 6371 } 6372 if (strcmp(lp->cmd, menu_cmds[MODULE_CMD]) == 0) { 6373 (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s", 6374 menu_cmds[MODULE_DOLLAR_CMD], menu_cmds[SEP_CMD], 6375 module); 6376 free(lp->cmd); 6377 free(lp->arg); 6378 free(lp->line); 6379 lp->cmd = s_strdup(menu_cmds[MODULE_DOLLAR_CMD]); 6380 lp->arg = s_strdup(module); 6381 lp->line = s_strdup(linebuf); 6382 lp = lp->next; 6383 BAM_DPRINTF((D_ADDING_MODULE_DOLLAR, fcn, module)); 6384 } 6385 } 6386 6387 /* module line */ 6388 lp = lp->next; 6389 6390 if (ent->flags & BAM_ENTRY_UPGFSMODULE) { 6391 if (strcmp(lp->cmd, menu_cmds[MODULE_CMD]) == 0) { 6392 (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s", 6393 menu_cmds[MODULE_DOLLAR_CMD], menu_cmds[SEP_CMD], 6394 module); 6395 free(lp->cmd); 6396 free(lp->arg); 6397 free(lp->line); 6398 lp->cmd = s_strdup(menu_cmds[MODULE_DOLLAR_CMD]); 6399 lp->arg = s_strdup(module); 6400 lp->line = s_strdup(linebuf); 6401 lp = lp->next; 6402 ent->flags &= ~BAM_ENTRY_UPGFSMODULE; 6403 BAM_DPRINTF((D_ADDING_MODULE_DOLLAR, fcn, module)); 6404 } 6405 } 6406 6407 BAM_DPRINTF((D_RETURN_RET, fcn, i)); 6408 return (i); 6409 } 6410 6411 int 6412 root_optional(char *osroot, char *menu_root) 6413 { 6414 char *ospecial; 6415 char *mspecial; 6416 char *slash; 6417 int root_opt; 6418 int ret1; 6419 int ret2; 6420 const char *fcn = "root_optional()"; 6421 6422 BAM_DPRINTF((D_FUNC_ENTRY2, fcn, osroot, menu_root)); 6423 6424 /* 6425 * For all filesystems except ZFS, a straight compare of osroot 6426 * and menu_root will tell us if root is optional. 6427 * For ZFS, the situation is complicated by the fact that 6428 * menu_root and osroot are always different 6429 */ 6430 ret1 = is_zfs(osroot); 6431 ret2 = is_zfs(menu_root); 6432 INJECT_ERROR1("ROOT_OPT_NOT_ZFS", ret1 = 0); 6433 if (!ret1 || !ret2) { 6434 BAM_DPRINTF((D_ROOT_OPT_NOT_ZFS, fcn, osroot, menu_root)); 6435 root_opt = (strcmp(osroot, menu_root) == 0); 6436 goto out; 6437 } 6438 6439 ospecial = get_special(osroot); 6440 INJECT_ERROR1("ROOT_OPTIONAL_OSPECIAL", ospecial = NULL); 6441 if (ospecial == NULL) { 6442 bam_error(GET_OSROOT_SPECIAL_ERR, osroot); 6443 return (0); 6444 } 6445 BAM_DPRINTF((D_ROOT_OPTIONAL_OSPECIAL, fcn, ospecial, osroot)); 6446 6447 mspecial = get_special(menu_root); 6448 INJECT_ERROR1("ROOT_OPTIONAL_MSPECIAL", mspecial = NULL); 6449 if (mspecial == NULL) { 6450 bam_error(GET_MENU_ROOT_SPECIAL_ERR, menu_root); 6451 free(ospecial); 6452 return (0); 6453 } 6454 BAM_DPRINTF((D_ROOT_OPTIONAL_MSPECIAL, fcn, mspecial, menu_root)); 6455 6456 slash = strchr(ospecial, '/'); 6457 if (slash) 6458 *slash = '\0'; 6459 BAM_DPRINTF((D_ROOT_OPTIONAL_FIXED_OSPECIAL, fcn, ospecial, osroot)); 6460 6461 root_opt = (strcmp(ospecial, mspecial) == 0); 6462 6463 free(ospecial); 6464 free(mspecial); 6465 6466 out: 6467 INJECT_ERROR1("ROOT_OPTIONAL_NO", root_opt = 0); 6468 INJECT_ERROR1("ROOT_OPTIONAL_YES", root_opt = 1); 6469 if (root_opt) { 6470 BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 6471 } else { 6472 BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 6473 } 6474 6475 return (root_opt); 6476 } 6477 6478 /*ARGSUSED*/ 6479 static error_t 6480 update_entry(menu_t *mp, char *menu_root, char *osdev) 6481 { 6482 int entry; 6483 char *grubsign; 6484 char *grubroot; 6485 char *title; 6486 char osroot[PATH_MAX]; 6487 char *failsafe_kernel = NULL; 6488 struct stat sbuf; 6489 char failsafe[256]; 6490 char failsafe_64[256]; 6491 int ret; 6492 const char *fcn = "update_entry()"; 6493 6494 assert(mp); 6495 assert(menu_root); 6496 assert(osdev); 6497 assert(bam_root); 6498 6499 BAM_DPRINTF((D_FUNC_ENTRY3, fcn, menu_root, osdev, bam_root)); 6500 6501 (void) strlcpy(osroot, bam_root, sizeof (osroot)); 6502 6503 title = get_title(osroot); 6504 assert(title); 6505 6506 grubsign = get_grubsign(osroot, osdev); 6507 INJECT_ERROR1("GET_GRUBSIGN_FAIL", grubsign = NULL); 6508 if (grubsign == NULL) { 6509 bam_error(GET_GRUBSIGN_ERROR, osroot, osdev); 6510 return (BAM_ERROR); 6511 } 6512 6513 /* 6514 * It is not a fatal error if get_grubroot() fails 6515 * We no longer rely on biosdev to populate the 6516 * menu 6517 */ 6518 grubroot = get_grubroot(osroot, osdev, menu_root); 6519 INJECT_ERROR1("GET_GRUBROOT_FAIL", grubroot = NULL); 6520 if (grubroot) { 6521 BAM_DPRINTF((D_GET_GRUBROOT_SUCCESS, 6522 fcn, osroot, osdev, menu_root)); 6523 } else { 6524 BAM_DPRINTF((D_GET_GRUBROOT_FAILURE, 6525 fcn, osroot, osdev, menu_root)); 6526 } 6527 6528 /* add the entry for normal Solaris */ 6529 INJECT_ERROR1("UPDATE_ENTRY_MULTIBOOT", 6530 bam_direct = BAM_DIRECT_MULTIBOOT); 6531 if (bam_direct == BAM_DIRECT_DBOOT) { 6532 entry = update_boot_entry(mp, title, grubsign, grubroot, 6533 (bam_zfs ? DIRECT_BOOT_KERNEL_ZFS : DIRECT_BOOT_KERNEL), 6534 NULL, DIRECT_BOOT_ARCHIVE, 6535 root_optional(osroot, menu_root)); 6536 BAM_DPRINTF((D_UPDATED_BOOT_ENTRY, fcn, bam_zfs, grubsign)); 6537 if ((entry != BAM_ERROR) && (bam_is_hv == BAM_HV_PRESENT)) { 6538 (void) update_boot_entry(mp, NEW_HV_ENTRY, grubsign, 6539 grubroot, XEN_MENU, bam_zfs ? 6540 XEN_KERNEL_MODULE_LINE_ZFS : XEN_KERNEL_MODULE_LINE, 6541 DIRECT_BOOT_ARCHIVE, 6542 root_optional(osroot, menu_root)); 6543 BAM_DPRINTF((D_UPDATED_HV_ENTRY, 6544 fcn, bam_zfs, grubsign)); 6545 } 6546 } else { 6547 entry = update_boot_entry(mp, title, grubsign, grubroot, 6548 MULTI_BOOT, NULL, MULTIBOOT_ARCHIVE, 6549 root_optional(osroot, menu_root)); 6550 6551 BAM_DPRINTF((D_UPDATED_MULTIBOOT_ENTRY, fcn, grubsign)); 6552 } 6553 6554 /* 6555 * Add the entry for failsafe archive. On a bfu'd system, the 6556 * failsafe may be different than the installed kernel. 6557 */ 6558 (void) snprintf(failsafe, sizeof (failsafe), "%s%s", 6559 osroot, FAILSAFE_ARCHIVE_32); 6560 (void) snprintf(failsafe_64, sizeof (failsafe_64), "%s%s", 6561 osroot, FAILSAFE_ARCHIVE_64); 6562 6563 /* 6564 * Check if at least one of the two archives exists 6565 * Using $ISADIR as the default line, we have an entry which works 6566 * for both the cases. 6567 */ 6568 6569 if (stat(failsafe, &sbuf) == 0 || stat(failsafe_64, &sbuf) == 0) { 6570 6571 /* Figure out where the kernel line should point */ 6572 (void) snprintf(failsafe, sizeof (failsafe), "%s%s", osroot, 6573 DIRECT_BOOT_FAILSAFE_32); 6574 (void) snprintf(failsafe_64, sizeof (failsafe_64), "%s%s", 6575 osroot, DIRECT_BOOT_FAILSAFE_64); 6576 if (stat(failsafe, &sbuf) == 0 || 6577 stat(failsafe_64, &sbuf) == 0) { 6578 failsafe_kernel = DIRECT_BOOT_FAILSAFE_LINE; 6579 } else { 6580 (void) snprintf(failsafe, sizeof (failsafe), "%s%s", 6581 osroot, MULTI_BOOT_FAILSAFE); 6582 if (stat(failsafe, &sbuf) == 0) { 6583 failsafe_kernel = MULTI_BOOT_FAILSAFE_LINE; 6584 } 6585 } 6586 if (failsafe_kernel != NULL) { 6587 (void) update_boot_entry(mp, FAILSAFE_TITLE, grubsign, 6588 grubroot, failsafe_kernel, NULL, FAILSAFE_ARCHIVE, 6589 root_optional(osroot, menu_root)); 6590 BAM_DPRINTF((D_UPDATED_FAILSAFE_ENTRY, fcn, 6591 failsafe_kernel)); 6592 } 6593 } 6594 free(grubroot); 6595 6596 INJECT_ERROR1("UPDATE_ENTRY_ERROR", entry = BAM_ERROR); 6597 if (entry == BAM_ERROR) { 6598 bam_error(FAILED_TO_ADD_BOOT_ENTRY, title, grubsign); 6599 free(grubsign); 6600 return (BAM_ERROR); 6601 } 6602 free(grubsign); 6603 6604 update_numbering(mp); 6605 ret = set_global(mp, menu_cmds[DEFAULT_CMD], entry); 6606 INJECT_ERROR1("SET_DEFAULT_ERROR", ret = BAM_ERROR); 6607 if (ret == BAM_ERROR) { 6608 bam_error(SET_DEFAULT_FAILED, entry); 6609 } 6610 BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 6611 return (BAM_WRITE); 6612 } 6613 6614 static void 6615 save_default_entry(menu_t *mp, const char *which) 6616 { 6617 int lineNum; 6618 int entryNum; 6619 int entry = 0; /* default is 0 */ 6620 char linebuf[BAM_MAXLINE]; 6621 line_t *lp = mp->curdefault; 6622 const char *fcn = "save_default_entry()"; 6623 6624 if (mp->start) { 6625 lineNum = mp->end->lineNum; 6626 entryNum = mp->end->entryNum; 6627 } else { 6628 lineNum = LINE_INIT; 6629 entryNum = ENTRY_INIT; 6630 } 6631 6632 if (lp) 6633 entry = s_strtol(lp->arg); 6634 6635 (void) snprintf(linebuf, sizeof (linebuf), "#%s%d", which, entry); 6636 BAM_DPRINTF((D_SAVING_DEFAULT_TO, fcn, linebuf)); 6637 line_parser(mp, linebuf, &lineNum, &entryNum); 6638 BAM_DPRINTF((D_SAVED_DEFAULT_TO, fcn, lineNum, entryNum)); 6639 } 6640 6641 static void 6642 restore_default_entry(menu_t *mp, const char *which, line_t *lp) 6643 { 6644 int entry; 6645 char *str; 6646 const char *fcn = "restore_default_entry()"; 6647 6648 if (lp == NULL) { 6649 BAM_DPRINTF((D_RESTORE_DEFAULT_NULL, fcn)); 6650 return; /* nothing to restore */ 6651 } 6652 6653 BAM_DPRINTF((D_RESTORE_DEFAULT_STR, fcn, which)); 6654 6655 str = lp->arg + strlen(which); 6656 entry = s_strtol(str); 6657 (void) set_global(mp, menu_cmds[DEFAULT_CMD], entry); 6658 6659 BAM_DPRINTF((D_RESTORED_DEFAULT_TO, fcn, entry)); 6660 6661 /* delete saved old default line */ 6662 unlink_line(mp, lp); 6663 line_free(lp); 6664 } 6665 6666 /* 6667 * This function is for supporting reboot with args. 6668 * The opt value can be: 6669 * NULL delete temp entry, if present 6670 * entry=<n> switches default entry to <n> 6671 * else treated as boot-args and setup a temperary menu entry 6672 * and make it the default 6673 * Note that we are always rebooting the current OS instance 6674 * so osroot == / always. 6675 */ 6676 #define REBOOT_TITLE "Solaris_reboot_transient" 6677 6678 /*ARGSUSED*/ 6679 static error_t 6680 update_temp(menu_t *mp, char *dummy, char *opt) 6681 { 6682 int entry; 6683 char *osdev; 6684 char *fstype; 6685 char *sign; 6686 char *opt_ptr; 6687 char *path; 6688 char kernbuf[BUFSIZ]; 6689 char args_buf[BUFSIZ]; 6690 char signbuf[PATH_MAX]; 6691 int ret; 6692 const char *fcn = "update_temp()"; 6693 6694 assert(mp); 6695 assert(dummy == NULL); 6696 6697 /* opt can be NULL */ 6698 BAM_DPRINTF((D_FUNC_ENTRY1, fcn, opt ? opt : "<NULL>")); 6699 BAM_DPRINTF((D_BAM_ROOT, fcn, bam_alt_root, bam_root)); 6700 6701 if (bam_alt_root || bam_rootlen != 1 || 6702 strcmp(bam_root, "/") != 0 || 6703 strcmp(rootbuf, "/") != 0) { 6704 bam_error(ALT_ROOT_INVALID, bam_root); 6705 return (BAM_ERROR); 6706 } 6707 6708 /* If no option, delete exiting reboot menu entry */ 6709 if (opt == NULL) { 6710 entry_t *ent; 6711 BAM_DPRINTF((D_OPT_NULL, fcn)); 6712 ent = find_boot_entry(mp, REBOOT_TITLE, NULL, NULL, 6713 NULL, NULL, 0, &entry); 6714 if (ent == NULL) { /* not found is ok */ 6715 BAM_DPRINTF((D_TRANSIENT_NOTFOUND, fcn)); 6716 return (BAM_SUCCESS); 6717 } 6718 (void) do_delete(mp, entry); 6719 restore_default_entry(mp, BAM_OLDDEF, mp->olddefault); 6720 mp->olddefault = NULL; 6721 BAM_DPRINTF((D_RESTORED_DEFAULT, fcn)); 6722 BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 6723 return (BAM_WRITE); 6724 } 6725 6726 /* if entry= is specified, set the default entry */ 6727 if (strncmp(opt, "entry=", strlen("entry=")) == 0) { 6728 int entryNum = s_strtol(opt + strlen("entry=")); 6729 BAM_DPRINTF((D_ENTRY_EQUALS, fcn, opt)); 6730 if (selector(mp, opt, &entry, NULL) == BAM_SUCCESS) { 6731 /* this is entry=# option */ 6732 ret = set_global(mp, menu_cmds[DEFAULT_CMD], entry); 6733 BAM_DPRINTF((D_ENTRY_SET_IS, fcn, entry, ret)); 6734 return (ret); 6735 } else { 6736 bam_error(SET_DEFAULT_FAILED, entryNum); 6737 return (BAM_ERROR); 6738 } 6739 } 6740 6741 /* 6742 * add a new menu entry based on opt and make it the default 6743 */ 6744 6745 fstype = get_fstype("/"); 6746 INJECT_ERROR1("REBOOT_FSTYPE_NULL", fstype = NULL); 6747 if (fstype == NULL) { 6748 bam_error(REBOOT_FSTYPE_FAILED); 6749 return (BAM_ERROR); 6750 } 6751 6752 osdev = get_special("/"); 6753 INJECT_ERROR1("REBOOT_SPECIAL_NULL", osdev = NULL); 6754 if (osdev == NULL) { 6755 free(fstype); 6756 bam_error(REBOOT_SPECIAL_FAILED); 6757 return (BAM_ERROR); 6758 } 6759 6760 sign = find_existing_sign("/", osdev, fstype); 6761 INJECT_ERROR1("REBOOT_SIGN_NULL", sign = NULL); 6762 if (sign == NULL) { 6763 free(fstype); 6764 free(osdev); 6765 bam_error(REBOOT_SIGN_FAILED); 6766 return (BAM_ERROR); 6767 } 6768 6769 free(fstype); 6770 free(osdev); 6771 (void) strlcpy(signbuf, sign, sizeof (signbuf)); 6772 free(sign); 6773 6774 assert(strchr(signbuf, '(') == NULL && strchr(signbuf, ',') == NULL && 6775 strchr(signbuf, ')') == NULL); 6776 6777 /* 6778 * There is no alternate root while doing reboot with args 6779 * This version of bootadm is only delivered with a DBOOT 6780 * version of Solaris. 6781 */ 6782 INJECT_ERROR1("REBOOT_NOT_DBOOT", bam_direct = BAM_DIRECT_MULTIBOOT); 6783 if (bam_direct != BAM_DIRECT_DBOOT) { 6784 bam_error(REBOOT_DIRECT_FAILED); 6785 return (BAM_ERROR); 6786 } 6787 6788 /* add an entry for Solaris reboot */ 6789 if (opt[0] == '-') { 6790 /* It's an option - first see if boot-file is set */ 6791 ret = get_kernel(mp, KERNEL_CMD, kernbuf, sizeof (kernbuf)); 6792 INJECT_ERROR1("REBOOT_GET_KERNEL", ret = BAM_ERROR); 6793 if (ret != BAM_SUCCESS) { 6794 bam_error(REBOOT_GET_KERNEL_FAILED); 6795 return (BAM_ERROR); 6796 } 6797 if (kernbuf[0] == '\0') 6798 (void) strlcpy(kernbuf, DIRECT_BOOT_KERNEL, 6799 sizeof (kernbuf)); 6800 (void) strlcat(kernbuf, " ", sizeof (kernbuf)); 6801 (void) strlcat(kernbuf, opt, sizeof (kernbuf)); 6802 BAM_DPRINTF((D_REBOOT_OPTION, fcn, kernbuf)); 6803 } else if (opt[0] == '/') { 6804 /* It's a full path, so write it out. */ 6805 (void) strlcpy(kernbuf, opt, sizeof (kernbuf)); 6806 6807 /* 6808 * If someone runs: 6809 * 6810 * # eeprom boot-args='-kd' 6811 * # reboot /platform/i86pc/kernel/unix 6812 * 6813 * we want to use the boot-args as part of the boot 6814 * line. On the other hand, if someone runs: 6815 * 6816 * # reboot "/platform/i86pc/kernel/unix -kd" 6817 * 6818 * we don't need to mess with boot-args. If there's 6819 * no space in the options string, assume we're in the 6820 * first case. 6821 */ 6822 if (strchr(opt, ' ') == NULL) { 6823 ret = get_kernel(mp, ARGS_CMD, args_buf, 6824 sizeof (args_buf)); 6825 INJECT_ERROR1("REBOOT_GET_ARGS", ret = BAM_ERROR); 6826 if (ret != BAM_SUCCESS) { 6827 bam_error(REBOOT_GET_ARGS_FAILED); 6828 return (BAM_ERROR); 6829 } 6830 6831 if (args_buf[0] != '\0') { 6832 (void) strlcat(kernbuf, " ", sizeof (kernbuf)); 6833 (void) strlcat(kernbuf, args_buf, 6834 sizeof (kernbuf)); 6835 } 6836 } 6837 BAM_DPRINTF((D_REBOOT_ABSPATH, fcn, kernbuf)); 6838 } else { 6839 /* 6840 * It may be a partial path, or it may be a partial 6841 * path followed by options. Assume that only options 6842 * follow a space. If someone sends us a kernel path 6843 * that includes a space, they deserve to be broken. 6844 */ 6845 opt_ptr = strchr(opt, ' '); 6846 if (opt_ptr != NULL) { 6847 *opt_ptr = '\0'; 6848 } 6849 6850 path = expand_path(opt); 6851 if (path != NULL) { 6852 (void) strlcpy(kernbuf, path, sizeof (kernbuf)); 6853 free(path); 6854 6855 /* 6856 * If there were options given, use those. 6857 * Otherwise, copy over the default options. 6858 */ 6859 if (opt_ptr != NULL) { 6860 /* Restore the space in opt string */ 6861 *opt_ptr = ' '; 6862 (void) strlcat(kernbuf, opt_ptr, 6863 sizeof (kernbuf)); 6864 } else { 6865 ret = get_kernel(mp, ARGS_CMD, args_buf, 6866 sizeof (args_buf)); 6867 INJECT_ERROR1("UPDATE_TEMP_PARTIAL_ARGS", 6868 ret = BAM_ERROR); 6869 if (ret != BAM_SUCCESS) { 6870 bam_error(REBOOT_GET_ARGS_FAILED); 6871 return (BAM_ERROR); 6872 } 6873 6874 if (args_buf[0] != '\0') { 6875 (void) strlcat(kernbuf, " ", 6876 sizeof (kernbuf)); 6877 (void) strlcat(kernbuf, 6878 args_buf, sizeof (kernbuf)); 6879 } 6880 } 6881 BAM_DPRINTF((D_REBOOT_RESOLVED_PARTIAL, fcn, kernbuf)); 6882 } else { 6883 bam_error(UNKNOWN_KERNEL, opt); 6884 bam_print_stderr(UNKNOWN_KERNEL_REBOOT); 6885 return (BAM_ERROR); 6886 } 6887 } 6888 entry = add_boot_entry(mp, REBOOT_TITLE, signbuf, kernbuf, 6889 NULL, NULL); 6890 INJECT_ERROR1("REBOOT_ADD_BOOT_ENTRY", entry = BAM_ERROR); 6891 if (entry == BAM_ERROR) { 6892 bam_error(REBOOT_WITH_ARGS_ADD_ENTRY_FAILED); 6893 return (BAM_ERROR); 6894 } 6895 6896 save_default_entry(mp, BAM_OLDDEF); 6897 ret = set_global(mp, menu_cmds[DEFAULT_CMD], entry); 6898 INJECT_ERROR1("REBOOT_SET_GLOBAL", ret = BAM_ERROR); 6899 if (ret == BAM_ERROR) { 6900 bam_error(REBOOT_SET_DEFAULT_FAILED, entry); 6901 } 6902 BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 6903 return (BAM_WRITE); 6904 } 6905 6906 static error_t 6907 set_global(menu_t *mp, char *globalcmd, int val) 6908 { 6909 line_t *lp; 6910 line_t *found; 6911 line_t *last; 6912 char *cp; 6913 char *str; 6914 char prefix[BAM_MAXLINE]; 6915 size_t len; 6916 const char *fcn = "set_global()"; 6917 6918 assert(mp); 6919 assert(globalcmd); 6920 6921 if (strcmp(globalcmd, menu_cmds[DEFAULT_CMD]) == 0) { 6922 INJECT_ERROR1("SET_GLOBAL_VAL_NEG", val = -1); 6923 INJECT_ERROR1("SET_GLOBAL_MENU_EMPTY", mp->end = NULL); 6924 INJECT_ERROR1("SET_GLOBAL_VAL_TOO_BIG", val = 100); 6925 if (val < 0 || mp->end == NULL || val > mp->end->entryNum) { 6926 (void) snprintf(prefix, sizeof (prefix), "%d", val); 6927 bam_error(INVALID_ENTRY, prefix); 6928 return (BAM_ERROR); 6929 } 6930 } 6931 6932 found = last = NULL; 6933 for (lp = mp->start; lp; lp = lp->next) { 6934 if (lp->flags != BAM_GLOBAL) 6935 continue; 6936 6937 last = lp; /* track the last global found */ 6938 6939 INJECT_ERROR1("SET_GLOBAL_NULL_CMD", lp->cmd = NULL); 6940 if (lp->cmd == NULL) { 6941 bam_error(NO_CMD, lp->lineNum); 6942 continue; 6943 } 6944 if (strcmp(globalcmd, lp->cmd) != 0) 6945 continue; 6946 6947 BAM_DPRINTF((D_FOUND_GLOBAL, fcn, globalcmd)); 6948 6949 if (found) { 6950 bam_error(DUP_CMD, globalcmd, lp->lineNum, bam_root); 6951 } 6952 found = lp; 6953 } 6954 6955 if (found == NULL) { 6956 lp = s_calloc(1, sizeof (line_t)); 6957 if (last == NULL) { 6958 lp->next = mp->start; 6959 mp->start = lp; 6960 mp->end = (mp->end) ? mp->end : lp; 6961 } else { 6962 lp->next = last->next; 6963 last->next = lp; 6964 if (lp->next == NULL) 6965 mp->end = lp; 6966 } 6967 lp->flags = BAM_GLOBAL; /* other fields not needed for writes */ 6968 len = strlen(globalcmd) + strlen(menu_cmds[SEP_CMD]); 6969 len += 10; /* val < 10 digits */ 6970 lp->line = s_calloc(1, len); 6971 (void) snprintf(lp->line, len, "%s%s%d", 6972 globalcmd, menu_cmds[SEP_CMD], val); 6973 BAM_DPRINTF((D_SET_GLOBAL_WROTE_NEW, fcn, lp->line)); 6974 BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 6975 return (BAM_WRITE); 6976 } 6977 6978 /* 6979 * We are changing an existing entry. Retain any prefix whitespace, 6980 * but overwrite everything else. This preserves tabs added for 6981 * readability. 6982 */ 6983 str = found->line; 6984 cp = prefix; 6985 while (*str == ' ' || *str == '\t') 6986 *(cp++) = *(str++); 6987 *cp = '\0'; /* Terminate prefix */ 6988 len = strlen(prefix) + strlen(globalcmd); 6989 len += strlen(menu_cmds[SEP_CMD]) + 10; 6990 6991 free(found->line); 6992 found->line = s_calloc(1, len); 6993 (void) snprintf(found->line, len, 6994 "%s%s%s%d", prefix, globalcmd, menu_cmds[SEP_CMD], val); 6995 6996 BAM_DPRINTF((D_SET_GLOBAL_REPLACED, fcn, found->line)); 6997 BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 6998 return (BAM_WRITE); /* need a write to menu */ 6999 } 7000 7001 /* 7002 * partial_path may be anything like "kernel/unix" or "kmdb". Try to 7003 * expand it to a full unix path. The calling function is expected to 7004 * output a message if an error occurs and NULL is returned. 7005 */ 7006 static char * 7007 expand_path(const char *partial_path) 7008 { 7009 int new_path_len; 7010 char *new_path; 7011 char new_path2[PATH_MAX]; 7012 struct stat sb; 7013 const char *fcn = "expand_path()"; 7014 7015 new_path_len = strlen(partial_path) + 64; 7016 new_path = s_calloc(1, new_path_len); 7017 7018 /* First, try the simplest case - something like "kernel/unix" */ 7019 (void) snprintf(new_path, new_path_len, "/platform/i86pc/%s", 7020 partial_path); 7021 if (stat(new_path, &sb) == 0) { 7022 BAM_DPRINTF((D_EXPAND_PATH, fcn, new_path)); 7023 return (new_path); 7024 } 7025 7026 if (strcmp(partial_path, "kmdb") == 0) { 7027 (void) snprintf(new_path, new_path_len, "%s -k", 7028 DIRECT_BOOT_KERNEL); 7029 BAM_DPRINTF((D_EXPAND_PATH, fcn, new_path)); 7030 return (new_path); 7031 } 7032 7033 /* 7034 * We've quickly reached unsupported usage. Try once more to 7035 * see if we were just given a glom name. 7036 */ 7037 (void) snprintf(new_path, new_path_len, "/platform/i86pc/%s/unix", 7038 partial_path); 7039 (void) snprintf(new_path2, PATH_MAX, "/platform/i86pc/%s/amd64/unix", 7040 partial_path); 7041 if (stat(new_path, &sb) == 0) { 7042 if (stat(new_path2, &sb) == 0) { 7043 /* 7044 * We matched both, so we actually 7045 * want to write the $ISADIR version. 7046 */ 7047 (void) snprintf(new_path, new_path_len, 7048 "/platform/i86pc/kernel/%s/$ISADIR/unix", 7049 partial_path); 7050 } 7051 BAM_DPRINTF((D_EXPAND_PATH, fcn, new_path)); 7052 return (new_path); 7053 } 7054 7055 free(new_path); 7056 BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 7057 return (NULL); 7058 } 7059 7060 /* 7061 * The kernel cmd and arg have been changed, so 7062 * check whether the archive line needs to change. 7063 */ 7064 static void 7065 set_archive_line(entry_t *entryp, line_t *kernelp) 7066 { 7067 line_t *lp = entryp->start; 7068 char *new_archive; 7069 menu_cmd_t m_cmd; 7070 const char *fcn = "set_archive_line()"; 7071 7072 for (; lp != NULL; lp = lp->next) { 7073 if (strncmp(lp->cmd, menu_cmds[MODULE_CMD], 7074 sizeof (menu_cmds[MODULE_CMD]) - 1) == 0) { 7075 break; 7076 } 7077 7078 INJECT_ERROR1("SET_ARCHIVE_LINE_END_ENTRY", lp = entryp->end); 7079 if (lp == entryp->end) { 7080 BAM_DPRINTF((D_ARCHIVE_LINE_NONE, fcn, 7081 entryp->entryNum)); 7082 return; 7083 } 7084 } 7085 INJECT_ERROR1("SET_ARCHIVE_LINE_END_MENU", lp = NULL); 7086 if (lp == NULL) { 7087 BAM_DPRINTF((D_ARCHIVE_LINE_NONE, fcn, entryp->entryNum)); 7088 return; 7089 } 7090 7091 if (strstr(kernelp->arg, "$ISADIR") != NULL) { 7092 new_archive = DIRECT_BOOT_ARCHIVE; 7093 m_cmd = MODULE_DOLLAR_CMD; 7094 } else if (strstr(kernelp->arg, "amd64") != NULL) { 7095 new_archive = DIRECT_BOOT_ARCHIVE_64; 7096 m_cmd = MODULE_CMD; 7097 } else { 7098 new_archive = DIRECT_BOOT_ARCHIVE_32; 7099 m_cmd = MODULE_CMD; 7100 } 7101 7102 if (strcmp(lp->arg, new_archive) == 0) { 7103 BAM_DPRINTF((D_ARCHIVE_LINE_NOCHANGE, fcn, lp->arg)); 7104 return; 7105 } 7106 7107 if (strcmp(lp->cmd, menu_cmds[m_cmd]) != 0) { 7108 free(lp->cmd); 7109 lp->cmd = s_strdup(menu_cmds[m_cmd]); 7110 } 7111 7112 free(lp->arg); 7113 lp->arg = s_strdup(new_archive); 7114 update_line(lp); 7115 BAM_DPRINTF((D_ARCHIVE_LINE_REPLACED, fcn, lp->line)); 7116 } 7117 7118 /* 7119 * Title for an entry to set properties that once went in bootenv.rc. 7120 */ 7121 #define BOOTENV_RC_TITLE "Solaris bootenv rc" 7122 7123 /* 7124 * If path is NULL, return the kernel (optnum == KERNEL_CMD) or arguments 7125 * (optnum == ARGS_CMD) in the argument buf. If path is a zero-length 7126 * string, reset the value to the default. If path is a non-zero-length 7127 * string, set the kernel or arguments. 7128 */ 7129 static error_t 7130 get_set_kernel( 7131 menu_t *mp, 7132 menu_cmd_t optnum, 7133 char *path, 7134 char *buf, 7135 size_t bufsize) 7136 { 7137 int entryNum; 7138 int rv = BAM_SUCCESS; 7139 int free_new_path = 0; 7140 entry_t *entryp; 7141 line_t *ptr; 7142 line_t *kernelp; 7143 char *new_arg; 7144 char *old_args; 7145 char *space; 7146 char *new_path; 7147 char old_space; 7148 size_t old_kernel_len; 7149 size_t new_str_len; 7150 char *fstype; 7151 char *osdev; 7152 char *sign; 7153 char signbuf[PATH_MAX]; 7154 int ret; 7155 const char *fcn = "get_set_kernel()"; 7156 7157 assert(bufsize > 0); 7158 7159 ptr = kernelp = NULL; 7160 new_arg = old_args = space = NULL; 7161 new_path = NULL; 7162 buf[0] = '\0'; 7163 7164 INJECT_ERROR1("GET_SET_KERNEL_NOT_DBOOT", 7165 bam_direct = BAM_DIRECT_MULTIBOOT); 7166 if (bam_direct != BAM_DIRECT_DBOOT) { 7167 bam_error(NOT_DBOOT, optnum == KERNEL_CMD ? "kernel" : "args"); 7168 return (BAM_ERROR); 7169 } 7170 7171 /* 7172 * If a user changed the default entry to a non-bootadm controlled 7173 * one, we don't want to mess with it. Just print an error and 7174 * return. 7175 */ 7176 if (mp->curdefault) { 7177 entryNum = s_strtol(mp->curdefault->arg); 7178 for (entryp = mp->entries; entryp; entryp = entryp->next) { 7179 if (entryp->entryNum == entryNum) 7180 break; 7181 } 7182 if ((entryp != NULL) && 7183 ((entryp->flags & (BAM_ENTRY_BOOTADM|BAM_ENTRY_LU)) == 0)) { 7184 bam_error(DEFAULT_NOT_BAM); 7185 return (BAM_ERROR); 7186 } 7187 } 7188 7189 entryp = find_boot_entry(mp, BOOTENV_RC_TITLE, NULL, NULL, NULL, NULL, 7190 0, &entryNum); 7191 7192 if (entryp != NULL) { 7193 for (ptr = entryp->start; ptr && ptr != entryp->end; 7194 ptr = ptr->next) { 7195 if (strncmp(ptr->cmd, menu_cmds[KERNEL_CMD], 7196 sizeof (menu_cmds[KERNEL_CMD]) - 1) == 0) { 7197 kernelp = ptr; 7198 break; 7199 } 7200 } 7201 if (kernelp == NULL) { 7202 bam_error(NO_KERNEL, entryNum); 7203 return (BAM_ERROR); 7204 } 7205 7206 old_kernel_len = strcspn(kernelp->arg, " \t"); 7207 space = old_args = kernelp->arg + old_kernel_len; 7208 while ((*old_args == ' ') || (*old_args == '\t')) 7209 old_args++; 7210 } 7211 7212 if (path == NULL) { 7213 if (entryp == NULL) { 7214 BAM_DPRINTF((D_GET_SET_KERNEL_NO_RC, fcn)); 7215 BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 7216 return (BAM_SUCCESS); 7217 } 7218 assert(kernelp); 7219 if (optnum == ARGS_CMD) { 7220 if (old_args[0] != '\0') { 7221 (void) strlcpy(buf, old_args, bufsize); 7222 BAM_DPRINTF((D_GET_SET_KERNEL_ARGS, fcn, buf)); 7223 } 7224 } else { 7225 /* 7226 * We need to print the kernel, so we just turn the 7227 * first space into a '\0' and print the beginning. 7228 * We don't print anything if it's the default kernel. 7229 */ 7230 old_space = *space; 7231 *space = '\0'; 7232 if (strcmp(kernelp->arg, DIRECT_BOOT_KERNEL) != 0) { 7233 (void) strlcpy(buf, kernelp->arg, bufsize); 7234 BAM_DPRINTF((D_GET_SET_KERNEL_KERN, fcn, buf)); 7235 } 7236 *space = old_space; 7237 } 7238 BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 7239 return (BAM_SUCCESS); 7240 } 7241 7242 /* 7243 * First, check if we're resetting an entry to the default. 7244 */ 7245 if ((path[0] == '\0') || 7246 ((optnum == KERNEL_CMD) && 7247 (strcmp(path, DIRECT_BOOT_KERNEL) == 0))) { 7248 if ((entryp == NULL) || (kernelp == NULL)) { 7249 /* No previous entry, it's already the default */ 7250 BAM_DPRINTF((D_GET_SET_KERNEL_ALREADY, fcn)); 7251 return (BAM_SUCCESS); 7252 } 7253 7254 /* 7255 * Check if we can delete the entry. If we're resetting the 7256 * kernel command, and the args is already empty, or if we're 7257 * resetting the args command, and the kernel is already the 7258 * default, we can restore the old default and delete the entry. 7259 */ 7260 if (((optnum == KERNEL_CMD) && 7261 ((old_args == NULL) || (old_args[0] == '\0'))) || 7262 ((optnum == ARGS_CMD) && 7263 (strncmp(kernelp->arg, DIRECT_BOOT_KERNEL, 7264 sizeof (DIRECT_BOOT_KERNEL) - 1) == 0))) { 7265 kernelp = NULL; 7266 (void) do_delete(mp, entryNum); 7267 restore_default_entry(mp, BAM_OLD_RC_DEF, 7268 mp->old_rc_default); 7269 mp->old_rc_default = NULL; 7270 rv = BAM_WRITE; 7271 BAM_DPRINTF((D_GET_SET_KERNEL_RESTORE_DEFAULT, fcn)); 7272 goto done; 7273 } 7274 7275 if (optnum == KERNEL_CMD) { 7276 /* 7277 * At this point, we've already checked that old_args 7278 * and entryp are valid pointers. The "+ 2" is for 7279 * a space a the string termination character. 7280 */ 7281 new_str_len = (sizeof (DIRECT_BOOT_KERNEL) - 1) + 7282 strlen(old_args) + 2; 7283 new_arg = s_calloc(1, new_str_len); 7284 (void) snprintf(new_arg, new_str_len, "%s %s", 7285 DIRECT_BOOT_KERNEL, old_args); 7286 free(kernelp->arg); 7287 kernelp->arg = new_arg; 7288 7289 /* 7290 * We have changed the kernel line, so we may need 7291 * to update the archive line as well. 7292 */ 7293 set_archive_line(entryp, kernelp); 7294 BAM_DPRINTF((D_GET_SET_KERNEL_RESET_KERNEL_SET_ARG, 7295 fcn, kernelp->arg)); 7296 } else { 7297 /* 7298 * We're resetting the boot args to nothing, so 7299 * we only need to copy the kernel. We've already 7300 * checked that the kernel is not the default. 7301 */ 7302 new_arg = s_calloc(1, old_kernel_len + 1); 7303 (void) snprintf(new_arg, old_kernel_len + 1, "%s", 7304 kernelp->arg); 7305 free(kernelp->arg); 7306 kernelp->arg = new_arg; 7307 BAM_DPRINTF((D_GET_SET_KERNEL_RESET_ARG_SET_KERNEL, 7308 fcn, kernelp->arg)); 7309 } 7310 rv = BAM_WRITE; 7311 goto done; 7312 } 7313 7314 /* 7315 * Expand the kernel file to a full path, if necessary 7316 */ 7317 if ((optnum == KERNEL_CMD) && (path[0] != '/')) { 7318 new_path = expand_path(path); 7319 if (new_path == NULL) { 7320 bam_error(UNKNOWN_KERNEL, path); 7321 BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 7322 return (BAM_ERROR); 7323 } 7324 free_new_path = 1; 7325 } else { 7326 new_path = path; 7327 free_new_path = 0; 7328 } 7329 7330 /* 7331 * At this point, we know we're setting a new value. First, take care 7332 * of the case where there was no previous entry. 7333 */ 7334 if (entryp == NULL) { 7335 7336 /* Similar to code in update_temp */ 7337 fstype = get_fstype("/"); 7338 INJECT_ERROR1("GET_SET_KERNEL_FSTYPE", fstype = NULL); 7339 if (fstype == NULL) { 7340 bam_error(BOOTENV_FSTYPE_FAILED); 7341 rv = BAM_ERROR; 7342 goto done; 7343 } 7344 7345 osdev = get_special("/"); 7346 INJECT_ERROR1("GET_SET_KERNEL_SPECIAL", osdev = NULL); 7347 if (osdev == NULL) { 7348 free(fstype); 7349 bam_error(BOOTENV_SPECIAL_FAILED); 7350 rv = BAM_ERROR; 7351 goto done; 7352 } 7353 7354 sign = find_existing_sign("/", osdev, fstype); 7355 INJECT_ERROR1("GET_SET_KERNEL_SIGN", sign = NULL); 7356 if (sign == NULL) { 7357 free(fstype); 7358 free(osdev); 7359 bam_error(BOOTENV_SIGN_FAILED); 7360 rv = BAM_ERROR; 7361 goto done; 7362 } 7363 7364 free(fstype); 7365 free(osdev); 7366 (void) strlcpy(signbuf, sign, sizeof (signbuf)); 7367 free(sign); 7368 assert(strchr(signbuf, '(') == NULL && 7369 strchr(signbuf, ',') == NULL && 7370 strchr(signbuf, ')') == NULL); 7371 7372 if (optnum == KERNEL_CMD) { 7373 BAM_DPRINTF((D_GET_SET_KERNEL_NEW_KERN, fcn, new_path)); 7374 entryNum = add_boot_entry(mp, BOOTENV_RC_TITLE, 7375 signbuf, new_path, NULL, NULL); 7376 } else { 7377 new_str_len = strlen(DIRECT_BOOT_KERNEL) + 7378 strlen(path) + 8; 7379 new_arg = s_calloc(1, new_str_len); 7380 7381 (void) snprintf(new_arg, new_str_len, "%s %s", 7382 DIRECT_BOOT_KERNEL, path); 7383 BAM_DPRINTF((D_GET_SET_KERNEL_NEW_ARG, fcn, new_arg)); 7384 entryNum = add_boot_entry(mp, BOOTENV_RC_TITLE, 7385 signbuf, new_arg, NULL, DIRECT_BOOT_ARCHIVE); 7386 free(new_arg); 7387 } 7388 INJECT_ERROR1("GET_SET_KERNEL_ADD_BOOT_ENTRY", 7389 entryNum = BAM_ERROR); 7390 if (entryNum == BAM_ERROR) { 7391 bam_error(GET_SET_KERNEL_ADD_BOOT_ENTRY, 7392 BOOTENV_RC_TITLE); 7393 rv = BAM_ERROR; 7394 goto done; 7395 } 7396 save_default_entry(mp, BAM_OLD_RC_DEF); 7397 ret = set_global(mp, menu_cmds[DEFAULT_CMD], entryNum); 7398 INJECT_ERROR1("GET_SET_KERNEL_SET_GLOBAL", ret = BAM_ERROR); 7399 if (ret == BAM_ERROR) { 7400 bam_error(GET_SET_KERNEL_SET_GLOBAL, entryNum); 7401 } 7402 rv = BAM_WRITE; 7403 goto done; 7404 } 7405 7406 /* 7407 * There was already an bootenv entry which we need to edit. 7408 */ 7409 if (optnum == KERNEL_CMD) { 7410 new_str_len = strlen(new_path) + strlen(old_args) + 2; 7411 new_arg = s_calloc(1, new_str_len); 7412 (void) snprintf(new_arg, new_str_len, "%s %s", new_path, 7413 old_args); 7414 free(kernelp->arg); 7415 kernelp->arg = new_arg; 7416 7417 /* 7418 * If we have changed the kernel line, we may need to update 7419 * the archive line as well. 7420 */ 7421 set_archive_line(entryp, kernelp); 7422 BAM_DPRINTF((D_GET_SET_KERNEL_REPLACED_KERNEL_SAME_ARG, fcn, 7423 kernelp->arg)); 7424 } else { 7425 new_str_len = old_kernel_len + strlen(path) + 8; 7426 new_arg = s_calloc(1, new_str_len); 7427 (void) strncpy(new_arg, kernelp->arg, old_kernel_len); 7428 (void) strlcat(new_arg, " ", new_str_len); 7429 (void) strlcat(new_arg, path, new_str_len); 7430 free(kernelp->arg); 7431 kernelp->arg = new_arg; 7432 BAM_DPRINTF((D_GET_SET_KERNEL_SAME_KERNEL_REPLACED_ARG, fcn, 7433 kernelp->arg)); 7434 } 7435 rv = BAM_WRITE; 7436 7437 done: 7438 if ((rv == BAM_WRITE) && kernelp) 7439 update_line(kernelp); 7440 if (free_new_path) 7441 free(new_path); 7442 if (rv == BAM_WRITE) { 7443 BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 7444 } else { 7445 BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 7446 } 7447 return (rv); 7448 } 7449 7450 static error_t 7451 get_kernel(menu_t *mp, menu_cmd_t optnum, char *buf, size_t bufsize) 7452 { 7453 const char *fcn = "get_kernel()"; 7454 BAM_DPRINTF((D_FUNC_ENTRY1, fcn, menu_cmds[optnum])); 7455 return (get_set_kernel(mp, optnum, NULL, buf, bufsize)); 7456 } 7457 7458 static error_t 7459 set_kernel(menu_t *mp, menu_cmd_t optnum, char *path, char *buf, size_t bufsize) 7460 { 7461 const char *fcn = "set_kernel()"; 7462 assert(path != NULL); 7463 BAM_DPRINTF((D_FUNC_ENTRY2, fcn, menu_cmds[optnum], path)); 7464 return (get_set_kernel(mp, optnum, path, buf, bufsize)); 7465 } 7466 7467 /*ARGSUSED*/ 7468 static error_t 7469 set_option(menu_t *mp, char *dummy, char *opt) 7470 { 7471 int optnum; 7472 int optval; 7473 char *val; 7474 char buf[BUFSIZ] = ""; 7475 error_t rv; 7476 const char *fcn = "set_option()"; 7477 7478 assert(mp); 7479 assert(opt); 7480 assert(dummy == NULL); 7481 7482 /* opt is set from bam_argv[0] and is always non-NULL */ 7483 BAM_DPRINTF((D_FUNC_ENTRY1, fcn, opt)); 7484 7485 val = strchr(opt, '='); 7486 if (val != NULL) { 7487 *val = '\0'; 7488 } 7489 7490 if (strcmp(opt, "default") == 0) { 7491 optnum = DEFAULT_CMD; 7492 } else if (strcmp(opt, "timeout") == 0) { 7493 optnum = TIMEOUT_CMD; 7494 } else if (strcmp(opt, menu_cmds[KERNEL_CMD]) == 0) { 7495 optnum = KERNEL_CMD; 7496 } else if (strcmp(opt, menu_cmds[ARGS_CMD]) == 0) { 7497 optnum = ARGS_CMD; 7498 } else { 7499 bam_error(INVALID_OPTION, opt); 7500 return (BAM_ERROR); 7501 } 7502 7503 /* 7504 * kernel and args are allowed without "=new_value" strings. All 7505 * others cause errors 7506 */ 7507 if ((val == NULL) && (optnum != KERNEL_CMD) && (optnum != ARGS_CMD)) { 7508 bam_error(NO_OPTION_ARG, opt); 7509 return (BAM_ERROR); 7510 } else if (val != NULL) { 7511 *val = '='; 7512 } 7513 7514 if ((optnum == KERNEL_CMD) || (optnum == ARGS_CMD)) { 7515 BAM_DPRINTF((D_SET_OPTION, fcn, menu_cmds[optnum], 7516 val ? val + 1 : "NULL")); 7517 7518 if (val) 7519 rv = set_kernel(mp, optnum, val + 1, buf, sizeof (buf)); 7520 else 7521 rv = get_kernel(mp, optnum, buf, sizeof (buf)); 7522 if ((rv == BAM_SUCCESS) && (buf[0] != '\0')) 7523 (void) printf("%s\n", buf); 7524 } else { 7525 optval = s_strtol(val + 1); 7526 BAM_DPRINTF((D_SET_OPTION, fcn, menu_cmds[optnum], val + 1)); 7527 rv = set_global(mp, menu_cmds[optnum], optval); 7528 } 7529 7530 if (rv == BAM_WRITE || rv == BAM_SUCCESS) { 7531 BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 7532 } else { 7533 BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 7534 } 7535 7536 return (rv); 7537 } 7538 7539 /* 7540 * The quiet argument suppresses messages. This is used 7541 * when invoked in the context of other commands (e.g. list_entry) 7542 */ 7543 static error_t 7544 read_globals(menu_t *mp, char *menu_path, char *globalcmd, int quiet) 7545 { 7546 line_t *lp; 7547 char *arg; 7548 int done, ret = BAM_SUCCESS; 7549 7550 assert(mp); 7551 assert(menu_path); 7552 assert(globalcmd); 7553 7554 if (mp->start == NULL) { 7555 if (!quiet) 7556 bam_error(NO_MENU, menu_path); 7557 return (BAM_ERROR); 7558 } 7559 7560 done = 0; 7561 for (lp = mp->start; lp; lp = lp->next) { 7562 if (lp->flags != BAM_GLOBAL) 7563 continue; 7564 7565 if (lp->cmd == NULL) { 7566 if (!quiet) 7567 bam_error(NO_CMD, lp->lineNum); 7568 continue; 7569 } 7570 7571 if (strcmp(globalcmd, lp->cmd) != 0) 7572 continue; 7573 7574 /* Found global. Check for duplicates */ 7575 if (done && !quiet) { 7576 bam_error(DUP_CMD, globalcmd, lp->lineNum, bam_root); 7577 ret = BAM_ERROR; 7578 } 7579 7580 arg = lp->arg ? lp->arg : ""; 7581 bam_print(GLOBAL_CMD, globalcmd, arg); 7582 done = 1; 7583 } 7584 7585 if (!done && bam_verbose) 7586 bam_print(NO_ENTRY, globalcmd); 7587 7588 return (ret); 7589 } 7590 7591 static error_t 7592 menu_write(char *root, menu_t *mp) 7593 { 7594 const char *fcn = "menu_write()"; 7595 7596 BAM_DPRINTF((D_MENU_WRITE_ENTER, fcn, root)); 7597 return (list2file(root, MENU_TMP, GRUB_MENU, mp->start)); 7598 } 7599 7600 void 7601 line_free(line_t *lp) 7602 { 7603 if (lp == NULL) 7604 return; 7605 7606 if (lp->cmd) 7607 free(lp->cmd); 7608 if (lp->sep) 7609 free(lp->sep); 7610 if (lp->arg) 7611 free(lp->arg); 7612 if (lp->line) 7613 free(lp->line); 7614 free(lp); 7615 } 7616 7617 static void 7618 linelist_free(line_t *start) 7619 { 7620 line_t *lp; 7621 7622 while (start) { 7623 lp = start; 7624 start = start->next; 7625 line_free(lp); 7626 } 7627 } 7628 7629 static void 7630 filelist_free(filelist_t *flistp) 7631 { 7632 linelist_free(flistp->head); 7633 flistp->head = NULL; 7634 flistp->tail = NULL; 7635 } 7636 7637 static void 7638 menu_free(menu_t *mp) 7639 { 7640 entry_t *ent, *tmp; 7641 assert(mp); 7642 7643 if (mp->start) 7644 linelist_free(mp->start); 7645 ent = mp->entries; 7646 while (ent) { 7647 tmp = ent; 7648 ent = tmp->next; 7649 free(tmp); 7650 } 7651 7652 free(mp); 7653 } 7654 7655 /* 7656 * Utility routines 7657 */ 7658 7659 7660 /* 7661 * Returns 0 on success 7662 * Any other value indicates an error 7663 */ 7664 static int 7665 exec_cmd(char *cmdline, filelist_t *flistp) 7666 { 7667 char buf[BUFSIZ]; 7668 int ret; 7669 FILE *ptr; 7670 sigset_t set; 7671 void (*disp)(int); 7672 7673 /* 7674 * For security 7675 * - only absolute paths are allowed 7676 * - set IFS to space and tab 7677 */ 7678 if (*cmdline != '/') { 7679 bam_error(ABS_PATH_REQ, cmdline); 7680 return (-1); 7681 } 7682 (void) putenv("IFS= \t"); 7683 7684 /* 7685 * We may have been exec'ed with SIGCHLD blocked 7686 * unblock it here 7687 */ 7688 (void) sigemptyset(&set); 7689 (void) sigaddset(&set, SIGCHLD); 7690 if (sigprocmask(SIG_UNBLOCK, &set, NULL) != 0) { 7691 bam_error(CANT_UNBLOCK_SIGCHLD, strerror(errno)); 7692 return (-1); 7693 } 7694 7695 /* 7696 * Set SIGCHLD disposition to SIG_DFL for popen/pclose 7697 */ 7698 disp = sigset(SIGCHLD, SIG_DFL); 7699 if (disp == SIG_ERR) { 7700 bam_error(FAILED_SIG, strerror(errno)); 7701 return (-1); 7702 } 7703 if (disp == SIG_HOLD) { 7704 bam_error(BLOCKED_SIG, cmdline); 7705 return (-1); 7706 } 7707 7708 ptr = popen(cmdline, "r"); 7709 if (ptr == NULL) { 7710 bam_error(POPEN_FAIL, cmdline, strerror(errno)); 7711 return (-1); 7712 } 7713 7714 /* 7715 * If we simply do a pclose() following a popen(), pclose() 7716 * will close the reader end of the pipe immediately even 7717 * if the child process has not started/exited. pclose() 7718 * does wait for cmd to terminate before returning though. 7719 * When the executed command writes its output to the pipe 7720 * there is no reader process and the command dies with 7721 * SIGPIPE. To avoid this we read repeatedly until read 7722 * terminates with EOF. This indicates that the command 7723 * (writer) has closed the pipe and we can safely do a 7724 * pclose(). 7725 * 7726 * Since pclose() does wait for the command to exit, 7727 * we can safely reap the exit status of the command 7728 * from the value returned by pclose() 7729 */ 7730 while (s_fgets(buf, sizeof (buf), ptr) != NULL) { 7731 if (flistp == NULL) { 7732 /* s_fgets strips newlines, so insert them at the end */ 7733 bam_print(PRINT, buf); 7734 } else { 7735 append_to_flist(flistp, buf); 7736 } 7737 } 7738 7739 ret = pclose(ptr); 7740 if (ret == -1) { 7741 bam_error(PCLOSE_FAIL, cmdline, strerror(errno)); 7742 return (-1); 7743 } 7744 7745 if (WIFEXITED(ret)) { 7746 return (WEXITSTATUS(ret)); 7747 } else { 7748 bam_error(EXEC_FAIL, cmdline, ret); 7749 return (-1); 7750 } 7751 } 7752 7753 /* 7754 * Since this function returns -1 on error 7755 * it cannot be used to convert -1. However, 7756 * that is sufficient for what we need. 7757 */ 7758 static long 7759 s_strtol(char *str) 7760 { 7761 long l; 7762 char *res = NULL; 7763 7764 if (str == NULL) { 7765 return (-1); 7766 } 7767 7768 errno = 0; 7769 l = strtol(str, &res, 10); 7770 if (errno || *res != '\0') { 7771 return (-1); 7772 } 7773 7774 return (l); 7775 } 7776 7777 /* 7778 * Wrapper around fputs, that adds a newline (since fputs doesn't) 7779 */ 7780 static int 7781 s_fputs(char *str, FILE *fp) 7782 { 7783 char linebuf[BAM_MAXLINE]; 7784 7785 (void) snprintf(linebuf, sizeof (linebuf), "%s\n", str); 7786 return (fputs(linebuf, fp)); 7787 } 7788 7789 /* 7790 * Wrapper around fgets, that strips newlines returned by fgets 7791 */ 7792 char * 7793 s_fgets(char *buf, int buflen, FILE *fp) 7794 { 7795 int n; 7796 7797 buf = fgets(buf, buflen, fp); 7798 if (buf) { 7799 n = strlen(buf); 7800 if (n == buflen - 1 && buf[n-1] != '\n') 7801 bam_error(TOO_LONG, buflen - 1, buf); 7802 buf[n-1] = (buf[n-1] == '\n') ? '\0' : buf[n-1]; 7803 } 7804 7805 return (buf); 7806 } 7807 7808 void * 7809 s_calloc(size_t nelem, size_t sz) 7810 { 7811 void *ptr; 7812 7813 ptr = calloc(nelem, sz); 7814 if (ptr == NULL) { 7815 bam_error(NO_MEM, nelem*sz); 7816 bam_exit(1); 7817 } 7818 return (ptr); 7819 } 7820 7821 void * 7822 s_realloc(void *ptr, size_t sz) 7823 { 7824 ptr = realloc(ptr, sz); 7825 if (ptr == NULL) { 7826 bam_error(NO_MEM, sz); 7827 bam_exit(1); 7828 } 7829 return (ptr); 7830 } 7831 7832 char * 7833 s_strdup(char *str) 7834 { 7835 char *ptr; 7836 7837 if (str == NULL) 7838 return (NULL); 7839 7840 ptr = strdup(str); 7841 if (ptr == NULL) { 7842 bam_error(NO_MEM, strlen(str) + 1); 7843 bam_exit(1); 7844 } 7845 return (ptr); 7846 } 7847 7848 /* 7849 * Returns 1 if amd64 (or sparc, for syncing x86 diskless clients) 7850 * Returns 0 otherwise 7851 */ 7852 static int 7853 is_amd64(void) 7854 { 7855 static int amd64 = -1; 7856 char isabuf[257]; /* from sysinfo(2) manpage */ 7857 7858 if (amd64 != -1) 7859 return (amd64); 7860 7861 if (bam_alt_platform) { 7862 if (strcmp(bam_platform, "i86pc") == 0) { 7863 amd64 = 1; /* diskless server */ 7864 } 7865 } else { 7866 if (sysinfo(SI_ISALIST, isabuf, sizeof (isabuf)) > 0 && 7867 strncmp(isabuf, "amd64 ", strlen("amd64 ")) == 0) { 7868 amd64 = 1; 7869 } else if (strstr(isabuf, "i386") == NULL) { 7870 amd64 = 1; /* diskless server */ 7871 } 7872 } 7873 if (amd64 == -1) 7874 amd64 = 0; 7875 7876 return (amd64); 7877 } 7878 7879 static char * 7880 get_machine(void) 7881 { 7882 static int cached = -1; 7883 static char mbuf[257]; /* from sysinfo(2) manpage */ 7884 7885 if (cached == 0) 7886 return (mbuf); 7887 7888 if (bam_alt_platform) { 7889 return (bam_platform); 7890 } else { 7891 if (sysinfo(SI_MACHINE, mbuf, sizeof (mbuf)) > 0) { 7892 cached = 1; 7893 } 7894 } 7895 if (cached == -1) { 7896 mbuf[0] = '\0'; 7897 cached = 0; 7898 } 7899 7900 return (mbuf); 7901 } 7902 7903 int 7904 is_sparc(void) 7905 { 7906 static int issparc = -1; 7907 char mbuf[257]; /* from sysinfo(2) manpage */ 7908 7909 if (issparc != -1) 7910 return (issparc); 7911 7912 if (bam_alt_platform) { 7913 if (strncmp(bam_platform, "sun4", 4) == 0) { 7914 issparc = 1; 7915 } 7916 } else { 7917 if (sysinfo(SI_ARCHITECTURE, mbuf, sizeof (mbuf)) > 0 && 7918 strcmp(mbuf, "sparc") == 0) { 7919 issparc = 1; 7920 } 7921 } 7922 if (issparc == -1) 7923 issparc = 0; 7924 7925 return (issparc); 7926 } 7927 7928 static void 7929 append_to_flist(filelist_t *flistp, char *s) 7930 { 7931 line_t *lp; 7932 7933 lp = s_calloc(1, sizeof (line_t)); 7934 lp->line = s_strdup(s); 7935 if (flistp->head == NULL) 7936 flistp->head = lp; 7937 else 7938 flistp->tail->next = lp; 7939 flistp->tail = lp; 7940 } 7941 7942 #if !defined(_OPB) 7943 7944 UCODE_VENDORS; 7945 7946 /*ARGSUSED*/ 7947 static void 7948 ucode_install(char *root) 7949 { 7950 int i; 7951 7952 for (i = 0; ucode_vendors[i].filestr != NULL; i++) { 7953 int cmd_len = PATH_MAX + 256; 7954 char cmd[PATH_MAX + 256]; 7955 char file[PATH_MAX]; 7956 char timestamp[PATH_MAX]; 7957 struct stat fstatus, tstatus; 7958 struct utimbuf u_times; 7959 7960 (void) snprintf(file, PATH_MAX, "%s/%s/%s-ucode.%s", 7961 bam_root, UCODE_INSTALL_PATH, ucode_vendors[i].filestr, 7962 ucode_vendors[i].extstr); 7963 7964 if (stat(file, &fstatus) != 0 || !(S_ISREG(fstatus.st_mode))) 7965 continue; 7966 7967 (void) snprintf(timestamp, PATH_MAX, "%s.ts", file); 7968 7969 if (stat(timestamp, &tstatus) == 0 && 7970 fstatus.st_mtime <= tstatus.st_mtime) 7971 continue; 7972 7973 (void) snprintf(cmd, cmd_len, "/usr/sbin/ucodeadm -i -R " 7974 "%s/%s/%s %s > /dev/null 2>&1", bam_root, 7975 UCODE_INSTALL_PATH, ucode_vendors[i].vendorstr, file); 7976 if (system(cmd) != 0) 7977 return; 7978 7979 if (creat(timestamp, S_IRUSR | S_IWUSR) == -1) 7980 return; 7981 7982 u_times.actime = fstatus.st_atime; 7983 u_times.modtime = fstatus.st_mtime; 7984 (void) utime(timestamp, &u_times); 7985 } 7986 } 7987 #endif 7988