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