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