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