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