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