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