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