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