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