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