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