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