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