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