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