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