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