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