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