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