17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5fbac2b2bSvikram * Common Development and Distribution License (the "License"). 6fbac2b2bSvikram * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22d876c67dSjg * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate /* 277c478bd9Sstevel@tonic-gate * bootadm(1M) is a new utility for managing bootability of 287c478bd9Sstevel@tonic-gate * Solaris *Newboot* environments. It has two primary tasks: 297c478bd9Sstevel@tonic-gate * - Allow end users to manage bootability of Newboot Solaris instances 307c478bd9Sstevel@tonic-gate * - Provide services to other subsystems in Solaris (primarily Install) 317c478bd9Sstevel@tonic-gate */ 327c478bd9Sstevel@tonic-gate 337c478bd9Sstevel@tonic-gate /* Headers */ 347c478bd9Sstevel@tonic-gate #include <stdio.h> 357c478bd9Sstevel@tonic-gate #include <errno.h> 367c478bd9Sstevel@tonic-gate #include <stdlib.h> 377c478bd9Sstevel@tonic-gate #include <string.h> 387c478bd9Sstevel@tonic-gate #include <unistd.h> 397c478bd9Sstevel@tonic-gate #include <sys/types.h> 407c478bd9Sstevel@tonic-gate #include <sys/stat.h> 417c478bd9Sstevel@tonic-gate #include <stdarg.h> 427c478bd9Sstevel@tonic-gate #include <limits.h> 437c478bd9Sstevel@tonic-gate #include <signal.h> 447c478bd9Sstevel@tonic-gate #include <sys/wait.h> 457c478bd9Sstevel@tonic-gate #include <sys/mnttab.h> 46f904d32dSJerry Gilliam #include <sys/mntent.h> 477c478bd9Sstevel@tonic-gate #include <sys/statvfs.h> 487c478bd9Sstevel@tonic-gate #include <libnvpair.h> 497c478bd9Sstevel@tonic-gate #include <ftw.h> 507c478bd9Sstevel@tonic-gate #include <fcntl.h> 517c478bd9Sstevel@tonic-gate #include <strings.h> 522449e17fSsherrym #include <utime.h> 537c478bd9Sstevel@tonic-gate #include <sys/systeminfo.h> 547c478bd9Sstevel@tonic-gate #include <sys/dktp/fdisk.h> 5558091fd8Ssetje #include <sys/param.h> 56eb2bd662Svikram #include <dirent.h> 57eb2bd662Svikram #include <ctype.h> 58eb2bd662Svikram #include <libgen.h> 59e7cbe64fSgw25295 #include <sys/sysmacros.h> 60963390b4Svikram #include <libscf.h> 61986fd29aSsetje 62986fd29aSsetje #if !defined(_OPB) 632449e17fSsherrym #include <sys/ucode.h> 642449e17fSsherrym #endif 657c478bd9Sstevel@tonic-gate 667c478bd9Sstevel@tonic-gate #include <pwd.h> 677c478bd9Sstevel@tonic-gate #include <grp.h> 687c478bd9Sstevel@tonic-gate #include <device_info.h> 69eb2bd662Svikram #include <sys/vtoc.h> 70eb2bd662Svikram #include <sys/efi_partition.h> 71eb2bd662Svikram 727c478bd9Sstevel@tonic-gate #include <locale.h> 737c478bd9Sstevel@tonic-gate 747c478bd9Sstevel@tonic-gate #include "message.h" 75ae115bc7Smrj #include "bootadm.h" 767c478bd9Sstevel@tonic-gate 777c478bd9Sstevel@tonic-gate #ifndef TEXT_DOMAIN 787c478bd9Sstevel@tonic-gate #define TEXT_DOMAIN "SUNW_OST_OSCMD" 797c478bd9Sstevel@tonic-gate #endif /* TEXT_DOMAIN */ 807c478bd9Sstevel@tonic-gate 817c478bd9Sstevel@tonic-gate /* Type definitions */ 827c478bd9Sstevel@tonic-gate 837c478bd9Sstevel@tonic-gate /* Primary subcmds */ 847c478bd9Sstevel@tonic-gate typedef enum { 857c478bd9Sstevel@tonic-gate BAM_MENU = 3, 867c478bd9Sstevel@tonic-gate BAM_ARCHIVE 877c478bd9Sstevel@tonic-gate } subcmd_t; 887c478bd9Sstevel@tonic-gate 897c478bd9Sstevel@tonic-gate typedef enum { 907c478bd9Sstevel@tonic-gate OPT_ABSENT = 0, /* No option */ 917c478bd9Sstevel@tonic-gate OPT_REQ, /* option required */ 927c478bd9Sstevel@tonic-gate OPT_OPTIONAL /* option may or may not be present */ 937c478bd9Sstevel@tonic-gate } option_t; 947c478bd9Sstevel@tonic-gate 957c478bd9Sstevel@tonic-gate typedef struct { 967c478bd9Sstevel@tonic-gate char *subcmd; 977c478bd9Sstevel@tonic-gate option_t option; 987c478bd9Sstevel@tonic-gate error_t (*handler)(); 991a97e40eSvikram int unpriv; /* is this an unprivileged command */ 1007c478bd9Sstevel@tonic-gate } subcmd_defn_t; 1017c478bd9Sstevel@tonic-gate 1027c478bd9Sstevel@tonic-gate #define LINE_INIT 0 /* lineNum initial value */ 1037c478bd9Sstevel@tonic-gate #define ENTRY_INIT -1 /* entryNum initial value */ 1047c478bd9Sstevel@tonic-gate #define ALL_ENTRIES -2 /* selects all boot entries */ 1057c478bd9Sstevel@tonic-gate 1067c478bd9Sstevel@tonic-gate #define GRUB_DIR "/boot/grub" 107963390b4Svikram #define GRUB_STAGE2 GRUB_DIR "/stage2" 1087c478bd9Sstevel@tonic-gate #define GRUB_MENU "/boot/grub/menu.lst" 1097c478bd9Sstevel@tonic-gate #define MENU_TMP "/boot/grub/menu.lst.tmp" 110963390b4Svikram #define GRUB_BACKUP_MENU "/etc/lu/GRUB_backup_menu" 1117c478bd9Sstevel@tonic-gate #define RAMDISK_SPECIAL "/ramdisk" 11240541d5dSvikram #define STUBBOOT "/stubboot" 113eb2bd662Svikram #define MULTIBOOT "/platform/i86pc/multiboot" 114eb2bd662Svikram #define GRUBSIGN_DIR "/boot/grub/bootsign" 115eb2bd662Svikram #define GRUBSIGN_BACKUP "/etc/bootsign" 116eb2bd662Svikram #define GRUBSIGN_UFS_PREFIX "rootfs" 117eb2bd662Svikram #define GRUBSIGN_ZFS_PREFIX "pool_" 118eb2bd662Svikram #define GRUBSIGN_LU_PREFIX "BE_" 119eb2bd662Svikram #define UFS_SIGNATURE_LIST "/var/run/grub_ufs_signatures" 120eb2bd662Svikram #define ZFS_LEGACY_MNTPT "/tmp/bootadm_mnt_zfs_legacy" 121eb2bd662Svikram 122eb2bd662Svikram #define BOOTADM_RDONLY_TEST "BOOTADM_RDONLY_TEST" 1237c478bd9Sstevel@tonic-gate 1247c478bd9Sstevel@tonic-gate /* lock related */ 1257c478bd9Sstevel@tonic-gate #define BAM_LOCK_FILE "/var/run/bootadm.lock" 1267c478bd9Sstevel@tonic-gate #define LOCK_FILE_PERMS (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) 1277c478bd9Sstevel@tonic-gate 128986fd29aSsetje #define CREATE_RAMDISK "boot/solaris/bin/create_ramdisk" 129986fd29aSsetje #define CREATE_DISKMAP "boot/solaris/bin/create_diskmap" 130986fd29aSsetje #define EXTRACT_BOOT_FILELIST "boot/solaris/bin/extract_boot_filelist" 1317c478bd9Sstevel@tonic-gate #define GRUBDISK_MAP "/var/run/solaris_grubdisk.map" 1327c478bd9Sstevel@tonic-gate 133b610f78eSvikram #define GRUB_slice "/etc/lu/GRUB_slice" 134b610f78eSvikram #define GRUB_root "/etc/lu/GRUB_root" 135fbac2b2bSvikram #define GRUB_fdisk "/etc/lu/GRUB_fdisk" 136fbac2b2bSvikram #define GRUB_fdisk_target "/etc/lu/GRUB_fdisk_target" 137963390b4Svikram #define FINDROOT_INSTALLGRUB "/etc/lu/installgrub.findroot" 138963390b4Svikram #define LULIB "/usr/lib/lu/lulib" 139963390b4Svikram #define LULIB_PROPAGATE_FILE "lulib_propagate_file" 140963390b4Svikram #define CKSUM "/usr/bin/cksum" 141963390b4Svikram #define LU_MENU_CKSUM "/etc/lu/menu.cksum" 142963390b4Svikram #define BOOTADM "/sbin/bootadm" 143b610f78eSvikram 144b610f78eSvikram #define INSTALLGRUB "/sbin/installgrub" 145b610f78eSvikram #define STAGE1 "/boot/grub/stage1" 146b610f78eSvikram #define STAGE2 "/boot/grub/stage2" 147b610f78eSvikram 148eb2bd662Svikram typedef enum zfs_mnted { 149eb2bd662Svikram ZFS_MNT_ERROR = -1, 150eb2bd662Svikram LEGACY_MOUNTED = 1, 151eb2bd662Svikram LEGACY_ALREADY, 152eb2bd662Svikram ZFS_MOUNTED, 153eb2bd662Svikram ZFS_ALREADY 154eb2bd662Svikram } zfs_mnted_t; 155eb2bd662Svikram 156eb2bd662Svikram 157eb2bd662Svikram 158eb2bd662Svikram 1597c478bd9Sstevel@tonic-gate /* 16098892a30Snadkarni * The following two defines are used to detect and create the correct 16198892a30Snadkarni * boot archive when safemode patching is underway. LOFS_PATCH_FILE is a 16298892a30Snadkarni * contracted private interface between bootadm and the install 16398892a30Snadkarni * consolidation. It is set by pdo.c when a patch with SUNW_PATCH_SAFEMODE 16498892a30Snadkarni * is applied. 16598892a30Snadkarni */ 16698892a30Snadkarni 16798892a30Snadkarni #define LOFS_PATCH_FILE "/var/run/.patch_loopback_mode" 16898892a30Snadkarni #define LOFS_PATCH_MNT "/var/run/.patch_root_loopbackmnt" 16998892a30Snadkarni 17098892a30Snadkarni /* 1717c478bd9Sstevel@tonic-gate * Default file attributes 1727c478bd9Sstevel@tonic-gate */ 1737c478bd9Sstevel@tonic-gate #define DEFAULT_DEV_MODE 0644 /* default permissions */ 1747c478bd9Sstevel@tonic-gate #define DEFAULT_DEV_UID 0 /* user root */ 1757c478bd9Sstevel@tonic-gate #define DEFAULT_DEV_GID 3 /* group sys */ 1767c478bd9Sstevel@tonic-gate 1777c478bd9Sstevel@tonic-gate /* 1787c478bd9Sstevel@tonic-gate * Menu related 1797c478bd9Sstevel@tonic-gate * menu_cmd_t and menu_cmds must be kept in sync 1807c478bd9Sstevel@tonic-gate */ 181ae115bc7Smrj char *menu_cmds[] = { 1827c478bd9Sstevel@tonic-gate "default", /* DEFAULT_CMD */ 1837c478bd9Sstevel@tonic-gate "timeout", /* TIMEOUT_CMD */ 1847c478bd9Sstevel@tonic-gate "title", /* TITLE_CMD */ 1857c478bd9Sstevel@tonic-gate "root", /* ROOT_CMD */ 1867c478bd9Sstevel@tonic-gate "kernel", /* KERNEL_CMD */ 187ae115bc7Smrj "kernel$", /* KERNEL_DOLLAR_CMD */ 1887c478bd9Sstevel@tonic-gate "module", /* MODULE_CMD */ 189ae115bc7Smrj "module$", /* MODULE_DOLLAR_CMD */ 1907c478bd9Sstevel@tonic-gate " ", /* SEP_CMD */ 1917c478bd9Sstevel@tonic-gate "#", /* COMMENT_CMD */ 192ae115bc7Smrj "chainloader", /* CHAINLOADER_CMD */ 193ae115bc7Smrj "args", /* ARGS_CMD */ 194eb2bd662Svikram "findroot", /* FINDROOT_CMD */ 1957c478bd9Sstevel@tonic-gate NULL 1967c478bd9Sstevel@tonic-gate }; 1977c478bd9Sstevel@tonic-gate 1987c478bd9Sstevel@tonic-gate #define OPT_ENTRY_NUM "entry" 1997c478bd9Sstevel@tonic-gate 2007c478bd9Sstevel@tonic-gate /* 201eb2bd662Svikram * exec_cmd related 2027c478bd9Sstevel@tonic-gate */ 2037c478bd9Sstevel@tonic-gate typedef struct { 2047c478bd9Sstevel@tonic-gate line_t *head; 2057c478bd9Sstevel@tonic-gate line_t *tail; 2067c478bd9Sstevel@tonic-gate } filelist_t; 2077c478bd9Sstevel@tonic-gate 2087c478bd9Sstevel@tonic-gate #define BOOT_FILE_LIST "boot/solaris/filelist.ramdisk" 2097c478bd9Sstevel@tonic-gate #define ETC_FILE_LIST "etc/boot/solaris/filelist.ramdisk" 2107c478bd9Sstevel@tonic-gate 2117c478bd9Sstevel@tonic-gate #define FILE_STAT "boot/solaris/filestat.ramdisk" 2127c478bd9Sstevel@tonic-gate #define FILE_STAT_TMP "boot/solaris/filestat.ramdisk.tmp" 2137c478bd9Sstevel@tonic-gate #define DIR_PERMS (S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) 2147c478bd9Sstevel@tonic-gate #define FILE_STAT_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) 2157c478bd9Sstevel@tonic-gate 2167c478bd9Sstevel@tonic-gate /* Globals */ 217ae115bc7Smrj int bam_verbose; 218ae115bc7Smrj int bam_force; 219eb2bd662Svikram int bam_debug; 2207c478bd9Sstevel@tonic-gate static char *prog; 2217c478bd9Sstevel@tonic-gate static subcmd_t bam_cmd; 2227c478bd9Sstevel@tonic-gate static char *bam_root; 2237c478bd9Sstevel@tonic-gate static int bam_rootlen; 2247c478bd9Sstevel@tonic-gate static int bam_root_readonly; 22540541d5dSvikram static int bam_alt_root; 2267c478bd9Sstevel@tonic-gate static char *bam_subcmd; 2277c478bd9Sstevel@tonic-gate static char *bam_opt; 2287c478bd9Sstevel@tonic-gate static char **bam_argv; 2297c478bd9Sstevel@tonic-gate static int bam_argc; 2307c478bd9Sstevel@tonic-gate static int bam_check; 2317c478bd9Sstevel@tonic-gate static int bam_smf_check; 2327c478bd9Sstevel@tonic-gate static int bam_lock_fd = -1; 233e7cbe64fSgw25295 static int bam_zfs; 2347c478bd9Sstevel@tonic-gate static char rootbuf[PATH_MAX] = "/"; 235b610f78eSvikram static int bam_update_all; 236d876c67dSjg static int bam_alt_platform; 237d876c67dSjg static char *bam_platform; 2387c478bd9Sstevel@tonic-gate 2397c478bd9Sstevel@tonic-gate /* function prototypes */ 240986fd29aSsetje static void parse_args_internal(int, char *[]); 241986fd29aSsetje static void parse_args(int, char *argv[]); 242986fd29aSsetje static error_t bam_menu(char *, char *, int, char *[]); 243986fd29aSsetje static error_t bam_archive(char *, char *); 2447c478bd9Sstevel@tonic-gate 245986fd29aSsetje static void bam_exit(int); 2467c478bd9Sstevel@tonic-gate static void bam_lock(void); 2477c478bd9Sstevel@tonic-gate static void bam_unlock(void); 2487c478bd9Sstevel@tonic-gate 249986fd29aSsetje static int exec_cmd(char *, filelist_t *); 250986fd29aSsetje static error_t read_globals(menu_t *, char *, char *, int); 251eb2bd662Svikram static int menu_on_bootdisk(char *os_root, char *menu_root); 252986fd29aSsetje static menu_t *menu_read(char *); 253986fd29aSsetje static error_t menu_write(char *, menu_t *); 254986fd29aSsetje static void linelist_free(line_t *); 255986fd29aSsetje static void menu_free(menu_t *); 256986fd29aSsetje static void filelist_free(filelist_t *); 257986fd29aSsetje static error_t list2file(char *, char *, char *, line_t *); 258986fd29aSsetje static error_t list_entry(menu_t *, char *, char *); 259986fd29aSsetje static error_t delete_all_entries(menu_t *, char *, char *); 260eb2bd662Svikram static error_t update_entry(menu_t *mp, char *menu_root, char *opt); 261eb2bd662Svikram static error_t update_temp(menu_t *mp, char *dummy, char *opt); 2627c478bd9Sstevel@tonic-gate 263986fd29aSsetje static error_t update_archive(char *, char *); 264986fd29aSsetje static error_t list_archive(char *, char *); 265986fd29aSsetje static error_t update_all(char *, char *); 266986fd29aSsetje static error_t read_list(char *, filelist_t *); 267986fd29aSsetje static error_t set_global(menu_t *, char *, int); 268986fd29aSsetje static error_t set_option(menu_t *, char *, char *); 269986fd29aSsetje static error_t set_kernel(menu_t *, menu_cmd_t, char *, char *, size_t); 270eb2bd662Svikram static error_t get_kernel(menu_t *, menu_cmd_t, char *, size_t); 271986fd29aSsetje static char *expand_path(const char *); 2727c478bd9Sstevel@tonic-gate 273986fd29aSsetje static long s_strtol(char *); 274986fd29aSsetje static int s_fputs(char *, FILE *); 2757c478bd9Sstevel@tonic-gate 276eb2bd662Svikram static int is_zfs(char *root); 277eb2bd662Svikram static int is_ufs(char *root); 278eb2bd662Svikram static int is_pcfs(char *root); 2797c478bd9Sstevel@tonic-gate static int is_amd64(void); 28079755401Ssetje static char *get_machine(void); 2817c478bd9Sstevel@tonic-gate static void append_to_flist(filelist_t *, char *); 282eb2bd662Svikram static char *mount_top_dataset(char *pool, zfs_mnted_t *mnted); 283eb2bd662Svikram static int umount_top_dataset(char *pool, zfs_mnted_t mnted, char *mntpt); 284eb2bd662Svikram static int ufs_add_to_sign_list(char *sign); 285963390b4Svikram static error_t synchronize_BE_menu(void); 2867c478bd9Sstevel@tonic-gate 287986fd29aSsetje #if !defined(_OPB) 2882449e17fSsherrym static void ucode_install(); 2892449e17fSsherrym #endif 2902449e17fSsherrym 2917c478bd9Sstevel@tonic-gate /* Menu related sub commands */ 2927c478bd9Sstevel@tonic-gate static subcmd_defn_t menu_subcmds[] = { 293eb2bd662Svikram "set_option", OPT_ABSENT, set_option, 0, /* PUB */ 2941a97e40eSvikram "list_entry", OPT_OPTIONAL, list_entry, 1, /* PUB */ 2951a97e40eSvikram "delete_all_entries", OPT_ABSENT, delete_all_entries, 0, /* PVT */ 2961a97e40eSvikram "update_entry", OPT_REQ, update_entry, 0, /* menu */ 2971a97e40eSvikram "update_temp", OPT_OPTIONAL, update_temp, 0, /* reboot */ 298ae115bc7Smrj "upgrade", OPT_ABSENT, upgrade_menu, 0, /* menu */ 2991a97e40eSvikram NULL, 0, NULL, 0 /* must be last */ 3007c478bd9Sstevel@tonic-gate }; 3017c478bd9Sstevel@tonic-gate 3027c478bd9Sstevel@tonic-gate /* Archive related sub commands */ 3037c478bd9Sstevel@tonic-gate static subcmd_defn_t arch_subcmds[] = { 3041a97e40eSvikram "update", OPT_ABSENT, update_archive, 0, /* PUB */ 3051a97e40eSvikram "update_all", OPT_ABSENT, update_all, 0, /* PVT */ 3061a97e40eSvikram "list", OPT_OPTIONAL, list_archive, 1, /* PUB */ 3071a97e40eSvikram NULL, 0, NULL, 0 /* must be last */ 3087c478bd9Sstevel@tonic-gate }; 3097c478bd9Sstevel@tonic-gate 3107c478bd9Sstevel@tonic-gate static struct { 3117c478bd9Sstevel@tonic-gate nvlist_t *new_nvlp; 3127c478bd9Sstevel@tonic-gate nvlist_t *old_nvlp; 3137c478bd9Sstevel@tonic-gate int need_update; 3147c478bd9Sstevel@tonic-gate } walk_arg; 3157c478bd9Sstevel@tonic-gate 31658091fd8Ssetje 3179632cfadSsetje struct safefile { 31858091fd8Ssetje char *name; 31958091fd8Ssetje struct safefile *next; 32058091fd8Ssetje }; 32158091fd8Ssetje 322ae115bc7Smrj static struct safefile *safefiles = NULL; 32358091fd8Ssetje #define NEED_UPDATE_FILE "/etc/svc/volatile/boot_archive_needs_update" 32458091fd8Ssetje 325*19397407SSherry Moore static int sync_menu = 1; /* whether we need to sync the BE menus */ 326*19397407SSherry Moore 3277c478bd9Sstevel@tonic-gate static void 3287c478bd9Sstevel@tonic-gate usage(void) 3297c478bd9Sstevel@tonic-gate { 3307c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "USAGE:\n"); 3317c478bd9Sstevel@tonic-gate 3327c478bd9Sstevel@tonic-gate 3337c478bd9Sstevel@tonic-gate /* archive usage */ 334d876c67dSjg (void) fprintf(stderr, 335d876c67dSjg "\t%s update-archive [-vn] [-R altroot [-p platform>]]\n", prog); 336d876c67dSjg (void) fprintf(stderr, 337d876c67dSjg "\t%s list-archive [-R altroot [-p platform>]]\n", prog); 338986fd29aSsetje #if !defined(_OPB) 3397c478bd9Sstevel@tonic-gate /* x86 only */ 3407c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "\t%s set-menu [-R altroot] key=value\n", prog); 3417c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "\t%s list-menu [-R altroot]\n", prog); 3427c478bd9Sstevel@tonic-gate #endif 3437c478bd9Sstevel@tonic-gate } 3447c478bd9Sstevel@tonic-gate 3457c478bd9Sstevel@tonic-gate int 3467c478bd9Sstevel@tonic-gate main(int argc, char *argv[]) 3477c478bd9Sstevel@tonic-gate { 3487c478bd9Sstevel@tonic-gate error_t ret; 3497c478bd9Sstevel@tonic-gate 3507c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 3517c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 3527c478bd9Sstevel@tonic-gate 3537c478bd9Sstevel@tonic-gate if ((prog = strrchr(argv[0], '/')) == NULL) { 3547c478bd9Sstevel@tonic-gate prog = argv[0]; 3557c478bd9Sstevel@tonic-gate } else { 3567c478bd9Sstevel@tonic-gate prog++; 3577c478bd9Sstevel@tonic-gate } 3587c478bd9Sstevel@tonic-gate 359eb2bd662Svikram INJECT_ERROR1("ASSERT_ON", assert(0)) 3607c478bd9Sstevel@tonic-gate 3617c478bd9Sstevel@tonic-gate /* 3627c478bd9Sstevel@tonic-gate * Don't depend on caller's umask 3637c478bd9Sstevel@tonic-gate */ 3647c478bd9Sstevel@tonic-gate (void) umask(0022); 3657c478bd9Sstevel@tonic-gate 3667c478bd9Sstevel@tonic-gate parse_args(argc, argv); 3677c478bd9Sstevel@tonic-gate 3687c478bd9Sstevel@tonic-gate switch (bam_cmd) { 3697c478bd9Sstevel@tonic-gate case BAM_MENU: 3707c478bd9Sstevel@tonic-gate ret = bam_menu(bam_subcmd, bam_opt, bam_argc, bam_argv); 3717c478bd9Sstevel@tonic-gate break; 3727c478bd9Sstevel@tonic-gate case BAM_ARCHIVE: 3737c478bd9Sstevel@tonic-gate ret = bam_archive(bam_subcmd, bam_opt); 3747c478bd9Sstevel@tonic-gate break; 3757c478bd9Sstevel@tonic-gate default: 3767c478bd9Sstevel@tonic-gate usage(); 3777c478bd9Sstevel@tonic-gate bam_exit(1); 3787c478bd9Sstevel@tonic-gate } 3797c478bd9Sstevel@tonic-gate 3807c478bd9Sstevel@tonic-gate if (ret != BAM_SUCCESS) 3817c478bd9Sstevel@tonic-gate bam_exit(1); 3827c478bd9Sstevel@tonic-gate 3837c478bd9Sstevel@tonic-gate bam_unlock(); 3847c478bd9Sstevel@tonic-gate return (0); 3857c478bd9Sstevel@tonic-gate } 3867c478bd9Sstevel@tonic-gate 3877c478bd9Sstevel@tonic-gate /* 3887c478bd9Sstevel@tonic-gate * Equivalence of public and internal commands: 3897c478bd9Sstevel@tonic-gate * update-archive -- -a update 3907c478bd9Sstevel@tonic-gate * list-archive -- -a list 3917c478bd9Sstevel@tonic-gate * set-menu -- -m set_option 3927c478bd9Sstevel@tonic-gate * list-menu -- -m list_entry 3937c478bd9Sstevel@tonic-gate * update-menu -- -m update_entry 3947c478bd9Sstevel@tonic-gate */ 3957c478bd9Sstevel@tonic-gate static struct cmd_map { 3967c478bd9Sstevel@tonic-gate char *bam_cmdname; 3977c478bd9Sstevel@tonic-gate int bam_cmd; 3987c478bd9Sstevel@tonic-gate char *bam_subcmd; 3997c478bd9Sstevel@tonic-gate } cmd_map[] = { 4007c478bd9Sstevel@tonic-gate { "update-archive", BAM_ARCHIVE, "update"}, 4017c478bd9Sstevel@tonic-gate { "list-archive", BAM_ARCHIVE, "list"}, 4027c478bd9Sstevel@tonic-gate { "set-menu", BAM_MENU, "set_option"}, 4037c478bd9Sstevel@tonic-gate { "list-menu", BAM_MENU, "list_entry"}, 4047c478bd9Sstevel@tonic-gate { "update-menu", BAM_MENU, "update_entry"}, 4057c478bd9Sstevel@tonic-gate { NULL, 0, NULL} 4067c478bd9Sstevel@tonic-gate }; 4077c478bd9Sstevel@tonic-gate 4087c478bd9Sstevel@tonic-gate /* 4097c478bd9Sstevel@tonic-gate * Commands syntax published in bootadm(1M) are parsed here 4107c478bd9Sstevel@tonic-gate */ 4117c478bd9Sstevel@tonic-gate static void 4127c478bd9Sstevel@tonic-gate parse_args(int argc, char *argv[]) 4137c478bd9Sstevel@tonic-gate { 4147c478bd9Sstevel@tonic-gate struct cmd_map *cmp = cmd_map; 4157c478bd9Sstevel@tonic-gate 4167c478bd9Sstevel@tonic-gate /* command conforming to the final spec */ 4177c478bd9Sstevel@tonic-gate if (argc > 1 && argv[1][0] != '-') { 4187c478bd9Sstevel@tonic-gate /* 4197c478bd9Sstevel@tonic-gate * Map commands to internal table. 4207c478bd9Sstevel@tonic-gate */ 4217c478bd9Sstevel@tonic-gate while (cmp->bam_cmdname) { 4227c478bd9Sstevel@tonic-gate if (strcmp(argv[1], cmp->bam_cmdname) == 0) { 4237c478bd9Sstevel@tonic-gate bam_cmd = cmp->bam_cmd; 4247c478bd9Sstevel@tonic-gate bam_subcmd = cmp->bam_subcmd; 4257c478bd9Sstevel@tonic-gate break; 4267c478bd9Sstevel@tonic-gate } 4277c478bd9Sstevel@tonic-gate cmp++; 4287c478bd9Sstevel@tonic-gate } 4297c478bd9Sstevel@tonic-gate if (cmp->bam_cmdname == NULL) { 4307c478bd9Sstevel@tonic-gate usage(); 4317c478bd9Sstevel@tonic-gate bam_exit(1); 4327c478bd9Sstevel@tonic-gate } 4337c478bd9Sstevel@tonic-gate argc--; 4347c478bd9Sstevel@tonic-gate argv++; 4357c478bd9Sstevel@tonic-gate } 4367c478bd9Sstevel@tonic-gate 4377c478bd9Sstevel@tonic-gate parse_args_internal(argc, argv); 4387c478bd9Sstevel@tonic-gate } 4397c478bd9Sstevel@tonic-gate 4407c478bd9Sstevel@tonic-gate /* 4417c478bd9Sstevel@tonic-gate * A combination of public and private commands are parsed here. 4427c478bd9Sstevel@tonic-gate * The internal syntax and the corresponding functionality are: 4437c478bd9Sstevel@tonic-gate * -a update -- update-archive 4447c478bd9Sstevel@tonic-gate * -a list -- list-archive 4457c478bd9Sstevel@tonic-gate * -a update-all -- (reboot to sync all mounted OS archive) 4467c478bd9Sstevel@tonic-gate * -m update_entry -- update-menu 4477c478bd9Sstevel@tonic-gate * -m list_entry -- list-menu 4487c478bd9Sstevel@tonic-gate * -m update_temp -- (reboot -- [boot-args]) 4497c478bd9Sstevel@tonic-gate * -m delete_all_entries -- (called from install) 4507c478bd9Sstevel@tonic-gate */ 4517c478bd9Sstevel@tonic-gate static void 4527c478bd9Sstevel@tonic-gate parse_args_internal(int argc, char *argv[]) 4537c478bd9Sstevel@tonic-gate { 4547c478bd9Sstevel@tonic-gate int c, error; 4557c478bd9Sstevel@tonic-gate extern char *optarg; 4567c478bd9Sstevel@tonic-gate extern int optind, opterr; 4577c478bd9Sstevel@tonic-gate 4587c478bd9Sstevel@tonic-gate /* Suppress error message from getopt */ 4597c478bd9Sstevel@tonic-gate opterr = 0; 4607c478bd9Sstevel@tonic-gate 4617c478bd9Sstevel@tonic-gate error = 0; 462e7cbe64fSgw25295 while ((c = getopt(argc, argv, "a:d:fm:no:vCR:p:Z")) != -1) { 4637c478bd9Sstevel@tonic-gate switch (c) { 4647c478bd9Sstevel@tonic-gate case 'a': 4657c478bd9Sstevel@tonic-gate if (bam_cmd) { 4667c478bd9Sstevel@tonic-gate error = 1; 4677c478bd9Sstevel@tonic-gate bam_error(MULT_CMDS, c); 4687c478bd9Sstevel@tonic-gate } 4697c478bd9Sstevel@tonic-gate bam_cmd = BAM_ARCHIVE; 4707c478bd9Sstevel@tonic-gate bam_subcmd = optarg; 4717c478bd9Sstevel@tonic-gate break; 4727c478bd9Sstevel@tonic-gate case 'd': 4737c478bd9Sstevel@tonic-gate if (bam_debug) { 4747c478bd9Sstevel@tonic-gate error = 1; 4757c478bd9Sstevel@tonic-gate bam_error(DUP_OPT, c); 4767c478bd9Sstevel@tonic-gate } 4777c478bd9Sstevel@tonic-gate bam_debug = s_strtol(optarg); 4787c478bd9Sstevel@tonic-gate break; 4797c478bd9Sstevel@tonic-gate case 'f': 4807c478bd9Sstevel@tonic-gate if (bam_force) { 4817c478bd9Sstevel@tonic-gate error = 1; 4827c478bd9Sstevel@tonic-gate bam_error(DUP_OPT, c); 4837c478bd9Sstevel@tonic-gate } 4847c478bd9Sstevel@tonic-gate bam_force = 1; 4857c478bd9Sstevel@tonic-gate break; 4867c478bd9Sstevel@tonic-gate case 'm': 4877c478bd9Sstevel@tonic-gate if (bam_cmd) { 4887c478bd9Sstevel@tonic-gate error = 1; 4897c478bd9Sstevel@tonic-gate bam_error(MULT_CMDS, c); 4907c478bd9Sstevel@tonic-gate } 4917c478bd9Sstevel@tonic-gate bam_cmd = BAM_MENU; 4927c478bd9Sstevel@tonic-gate bam_subcmd = optarg; 4937c478bd9Sstevel@tonic-gate break; 4947c478bd9Sstevel@tonic-gate case 'n': 4957c478bd9Sstevel@tonic-gate if (bam_check) { 4967c478bd9Sstevel@tonic-gate error = 1; 4977c478bd9Sstevel@tonic-gate bam_error(DUP_OPT, c); 4987c478bd9Sstevel@tonic-gate } 4997c478bd9Sstevel@tonic-gate bam_check = 1; 5007c478bd9Sstevel@tonic-gate break; 5017c478bd9Sstevel@tonic-gate case 'o': 5027c478bd9Sstevel@tonic-gate if (bam_opt) { 5037c478bd9Sstevel@tonic-gate error = 1; 5047c478bd9Sstevel@tonic-gate bam_error(DUP_OPT, c); 5057c478bd9Sstevel@tonic-gate } 5067c478bd9Sstevel@tonic-gate bam_opt = optarg; 5077c478bd9Sstevel@tonic-gate break; 5087c478bd9Sstevel@tonic-gate case 'v': 5097c478bd9Sstevel@tonic-gate if (bam_verbose) { 5107c478bd9Sstevel@tonic-gate error = 1; 5117c478bd9Sstevel@tonic-gate bam_error(DUP_OPT, c); 5127c478bd9Sstevel@tonic-gate } 5137c478bd9Sstevel@tonic-gate bam_verbose = 1; 5147c478bd9Sstevel@tonic-gate break; 5158c1b6884Sszhou case 'C': 5168c1b6884Sszhou bam_smf_check = 1; 5178c1b6884Sszhou break; 5187c478bd9Sstevel@tonic-gate case 'R': 5197c478bd9Sstevel@tonic-gate if (bam_root) { 5207c478bd9Sstevel@tonic-gate error = 1; 5217c478bd9Sstevel@tonic-gate bam_error(DUP_OPT, c); 5227c478bd9Sstevel@tonic-gate break; 5237c478bd9Sstevel@tonic-gate } else if (realpath(optarg, rootbuf) == NULL) { 5247c478bd9Sstevel@tonic-gate error = 1; 5257c478bd9Sstevel@tonic-gate bam_error(CANT_RESOLVE, optarg, 5267c478bd9Sstevel@tonic-gate strerror(errno)); 5277c478bd9Sstevel@tonic-gate break; 5287c478bd9Sstevel@tonic-gate } 52940541d5dSvikram bam_alt_root = 1; 5307c478bd9Sstevel@tonic-gate bam_root = rootbuf; 5317c478bd9Sstevel@tonic-gate bam_rootlen = strlen(rootbuf); 5327c478bd9Sstevel@tonic-gate break; 533d876c67dSjg case 'p': 534d876c67dSjg bam_alt_platform = 1; 535d876c67dSjg bam_platform = optarg; 536d876c67dSjg if ((strcmp(bam_platform, "i86pc") != 0) && 537d876c67dSjg (strcmp(bam_platform, "sun4u") != 0) && 538d876c67dSjg (strcmp(bam_platform, "sun4v") != 0)) { 539d876c67dSjg error = 1; 540d876c67dSjg bam_error(INVALID_PLAT, bam_platform); 541d876c67dSjg } 542d876c67dSjg break; 543e7cbe64fSgw25295 case 'Z': 544e7cbe64fSgw25295 bam_zfs = 1; 545e7cbe64fSgw25295 break; 5467c478bd9Sstevel@tonic-gate case '?': 5477c478bd9Sstevel@tonic-gate error = 1; 5487c478bd9Sstevel@tonic-gate bam_error(BAD_OPT, optopt); 5497c478bd9Sstevel@tonic-gate break; 5507c478bd9Sstevel@tonic-gate default : 5517c478bd9Sstevel@tonic-gate error = 1; 5527c478bd9Sstevel@tonic-gate bam_error(BAD_OPT, c); 5537c478bd9Sstevel@tonic-gate break; 5547c478bd9Sstevel@tonic-gate } 5557c478bd9Sstevel@tonic-gate } 5567c478bd9Sstevel@tonic-gate 5577c478bd9Sstevel@tonic-gate /* 558d876c67dSjg * An alternate platform requires an alternate root 559d876c67dSjg */ 560d876c67dSjg if (bam_alt_platform && bam_alt_root == 0) { 561d876c67dSjg usage(); 562d876c67dSjg bam_exit(0); 563d876c67dSjg } 564d876c67dSjg 565d876c67dSjg /* 5667c478bd9Sstevel@tonic-gate * A command option must be specfied 5677c478bd9Sstevel@tonic-gate */ 5687c478bd9Sstevel@tonic-gate if (!bam_cmd) { 5697c478bd9Sstevel@tonic-gate if (bam_opt && strcmp(bam_opt, "all") == 0) { 5707c478bd9Sstevel@tonic-gate usage(); 5717c478bd9Sstevel@tonic-gate bam_exit(0); 5727c478bd9Sstevel@tonic-gate } 5737c478bd9Sstevel@tonic-gate bam_error(NEED_CMD); 5747c478bd9Sstevel@tonic-gate error = 1; 5757c478bd9Sstevel@tonic-gate } 5767c478bd9Sstevel@tonic-gate 5777c478bd9Sstevel@tonic-gate if (error) { 5787c478bd9Sstevel@tonic-gate usage(); 5797c478bd9Sstevel@tonic-gate bam_exit(1); 5807c478bd9Sstevel@tonic-gate } 5817c478bd9Sstevel@tonic-gate 5827c478bd9Sstevel@tonic-gate if (optind > argc) { 5837c478bd9Sstevel@tonic-gate bam_error(INT_ERROR, "parse_args"); 5847c478bd9Sstevel@tonic-gate bam_exit(1); 5857c478bd9Sstevel@tonic-gate } else if (optind < argc) { 5867c478bd9Sstevel@tonic-gate bam_argv = &argv[optind]; 5877c478bd9Sstevel@tonic-gate bam_argc = argc - optind; 5887c478bd9Sstevel@tonic-gate } 5897c478bd9Sstevel@tonic-gate 5907c478bd9Sstevel@tonic-gate /* 5917c478bd9Sstevel@tonic-gate * -n implies verbose mode 5927c478bd9Sstevel@tonic-gate */ 5937c478bd9Sstevel@tonic-gate if (bam_check) 5947c478bd9Sstevel@tonic-gate bam_verbose = 1; 5957c478bd9Sstevel@tonic-gate } 5967c478bd9Sstevel@tonic-gate 5977c478bd9Sstevel@tonic-gate static error_t 5987c478bd9Sstevel@tonic-gate check_subcmd_and_options( 5997c478bd9Sstevel@tonic-gate char *subcmd, 6007c478bd9Sstevel@tonic-gate char *opt, 6017c478bd9Sstevel@tonic-gate subcmd_defn_t *table, 6027c478bd9Sstevel@tonic-gate error_t (**fp)()) 6037c478bd9Sstevel@tonic-gate { 6047c478bd9Sstevel@tonic-gate int i; 6057c478bd9Sstevel@tonic-gate 6067c478bd9Sstevel@tonic-gate if (subcmd == NULL) { 6077c478bd9Sstevel@tonic-gate bam_error(NEED_SUBCMD); 6087c478bd9Sstevel@tonic-gate return (BAM_ERROR); 6097c478bd9Sstevel@tonic-gate } 6107c478bd9Sstevel@tonic-gate 611eb2bd662Svikram if (strcmp(subcmd, "set_option") == 0) { 612eb2bd662Svikram if (bam_argc == 0 || bam_argv == NULL || bam_argv[0] == NULL) { 613eb2bd662Svikram bam_error(MISSING_ARG); 614eb2bd662Svikram usage(); 615eb2bd662Svikram return (BAM_ERROR); 616eb2bd662Svikram } else if (bam_argc > 1 || bam_argv[1] != NULL) { 6171a97e40eSvikram bam_error(TRAILING_ARGS); 6181a97e40eSvikram usage(); 6191a97e40eSvikram return (BAM_ERROR); 6201a97e40eSvikram } 621*19397407SSherry Moore } else if (strcmp(subcmd, "update_all") == 0) { 622*19397407SSherry Moore /* 623*19397407SSherry Moore * The only option we accept for the "update_all" 624*19397407SSherry Moore * subcmd is "fastboot". 625*19397407SSherry Moore */ 626*19397407SSherry Moore if (bam_argc > 1 || (bam_argc == 1 && 627*19397407SSherry Moore strcmp(bam_argv[0], "fastboot") != 0)) { 628*19397407SSherry Moore bam_error(TRAILING_ARGS); 629*19397407SSherry Moore usage(); 630*19397407SSherry Moore return (BAM_ERROR); 631*19397407SSherry Moore } 632*19397407SSherry Moore if (bam_argc == 1) 633*19397407SSherry Moore sync_menu = 0; 634eb2bd662Svikram } else if (bam_argc || bam_argv) { 635eb2bd662Svikram bam_error(TRAILING_ARGS); 636eb2bd662Svikram usage(); 637eb2bd662Svikram return (BAM_ERROR); 6381a97e40eSvikram } 6391a97e40eSvikram 6407c478bd9Sstevel@tonic-gate if (bam_root == NULL) { 6417c478bd9Sstevel@tonic-gate bam_root = rootbuf; 6427c478bd9Sstevel@tonic-gate bam_rootlen = 1; 6437c478bd9Sstevel@tonic-gate } 6447c478bd9Sstevel@tonic-gate 6457c478bd9Sstevel@tonic-gate /* verify that subcmd is valid */ 6467c478bd9Sstevel@tonic-gate for (i = 0; table[i].subcmd != NULL; i++) { 6477c478bd9Sstevel@tonic-gate if (strcmp(table[i].subcmd, subcmd) == 0) 6487c478bd9Sstevel@tonic-gate break; 6497c478bd9Sstevel@tonic-gate } 6507c478bd9Sstevel@tonic-gate 6517c478bd9Sstevel@tonic-gate if (table[i].subcmd == NULL) { 6527c478bd9Sstevel@tonic-gate bam_error(INVALID_SUBCMD, subcmd); 6537c478bd9Sstevel@tonic-gate return (BAM_ERROR); 6547c478bd9Sstevel@tonic-gate } 6557c478bd9Sstevel@tonic-gate 6561a97e40eSvikram if (table[i].unpriv == 0 && geteuid() != 0) { 6571a97e40eSvikram bam_error(MUST_BE_ROOT); 6581a97e40eSvikram return (BAM_ERROR); 6591a97e40eSvikram } 6601a97e40eSvikram 6611a97e40eSvikram /* 6621a97e40eSvikram * Currently only privileged commands need a lock 6631a97e40eSvikram */ 6641a97e40eSvikram if (table[i].unpriv == 0) 6651a97e40eSvikram bam_lock(); 6661a97e40eSvikram 6677c478bd9Sstevel@tonic-gate /* subcmd verifies that opt is appropriate */ 6687c478bd9Sstevel@tonic-gate if (table[i].option != OPT_OPTIONAL) { 6697c478bd9Sstevel@tonic-gate if ((table[i].option == OPT_REQ) ^ (opt != NULL)) { 6707c478bd9Sstevel@tonic-gate if (opt) 6717c478bd9Sstevel@tonic-gate bam_error(NO_OPT_REQ, subcmd); 6727c478bd9Sstevel@tonic-gate else 6737c478bd9Sstevel@tonic-gate bam_error(MISS_OPT, subcmd); 6747c478bd9Sstevel@tonic-gate return (BAM_ERROR); 6757c478bd9Sstevel@tonic-gate } 6767c478bd9Sstevel@tonic-gate } 6777c478bd9Sstevel@tonic-gate 6787c478bd9Sstevel@tonic-gate *fp = table[i].handler; 6797c478bd9Sstevel@tonic-gate 6807c478bd9Sstevel@tonic-gate return (BAM_SUCCESS); 6817c478bd9Sstevel@tonic-gate } 6827c478bd9Sstevel@tonic-gate 68340541d5dSvikram /* 68440541d5dSvikram * NOTE: A single "/" is also considered a trailing slash and will 68540541d5dSvikram * be deleted. 68640541d5dSvikram */ 68740541d5dSvikram static void 68840541d5dSvikram elide_trailing_slash(const char *src, char *dst, size_t dstsize) 68940541d5dSvikram { 69040541d5dSvikram size_t dstlen; 69140541d5dSvikram 69240541d5dSvikram assert(src); 69340541d5dSvikram assert(dst); 69440541d5dSvikram 69540541d5dSvikram (void) strlcpy(dst, src, dstsize); 69640541d5dSvikram 69740541d5dSvikram dstlen = strlen(dst); 69840541d5dSvikram if (dst[dstlen - 1] == '/') { 69940541d5dSvikram dst[dstlen - 1] = '\0'; 70040541d5dSvikram } 70140541d5dSvikram } 70240541d5dSvikram 7037c478bd9Sstevel@tonic-gate static error_t 7047c478bd9Sstevel@tonic-gate bam_menu(char *subcmd, char *opt, int largc, char *largv[]) 7057c478bd9Sstevel@tonic-gate { 7067c478bd9Sstevel@tonic-gate error_t ret; 7077c478bd9Sstevel@tonic-gate char menu_path[PATH_MAX]; 708eb2bd662Svikram char clean_menu_root[PATH_MAX]; 709ae115bc7Smrj char path[PATH_MAX]; 7107c478bd9Sstevel@tonic-gate menu_t *menu; 711eb2bd662Svikram char menu_root[PATH_MAX]; 712b610f78eSvikram struct stat sb; 7137c478bd9Sstevel@tonic-gate error_t (*f)(menu_t *mp, char *menu_path, char *opt); 714eb2bd662Svikram char *special; 715eb2bd662Svikram char *pool = NULL; 716eb2bd662Svikram zfs_mnted_t zmnted; 717eb2bd662Svikram char *zmntpt; 718eb2bd662Svikram char *osdev; 719eb2bd662Svikram char *osroot; 720eb2bd662Svikram const char *fcn = "bam_menu()"; 721986fd29aSsetje 722986fd29aSsetje /* 723986fd29aSsetje * Menu sub-command only applies to GRUB (i.e. x86) 724986fd29aSsetje */ 725eb2bd662Svikram if (!is_grub(bam_alt_root ? bam_root : "/")) { 726eb2bd662Svikram bam_error(NOT_GRUB_BOOT); 727986fd29aSsetje return (BAM_ERROR); 728986fd29aSsetje } 7297c478bd9Sstevel@tonic-gate 7307c478bd9Sstevel@tonic-gate /* 7317c478bd9Sstevel@tonic-gate * Check arguments 7327c478bd9Sstevel@tonic-gate */ 7337c478bd9Sstevel@tonic-gate ret = check_subcmd_and_options(subcmd, opt, menu_subcmds, &f); 7347c478bd9Sstevel@tonic-gate if (ret == BAM_ERROR) { 7357c478bd9Sstevel@tonic-gate return (BAM_ERROR); 7367c478bd9Sstevel@tonic-gate } 7377c478bd9Sstevel@tonic-gate 738eb2bd662Svikram assert(bam_root); 739eb2bd662Svikram 740eb2bd662Svikram (void) strlcpy(menu_root, bam_root, sizeof (menu_root)); 741eb2bd662Svikram osdev = osroot = NULL; 742eb2bd662Svikram 743eb2bd662Svikram if (strcmp(subcmd, "update_entry") == 0) { 744eb2bd662Svikram assert(opt); 745eb2bd662Svikram 746eb2bd662Svikram osdev = strtok(opt, ","); 747eb2bd662Svikram assert(osdev); 748eb2bd662Svikram osroot = strtok(NULL, ","); 749eb2bd662Svikram if (osroot) { 750eb2bd662Svikram /* fixup bam_root so that it points at osroot */ 751eb2bd662Svikram if (realpath(osroot, rootbuf) == NULL) { 752eb2bd662Svikram bam_error(CANT_RESOLVE, osroot, 753eb2bd662Svikram strerror(errno)); 754eb2bd662Svikram return (BAM_ERROR); 755eb2bd662Svikram } 756eb2bd662Svikram bam_alt_root = 1; 757eb2bd662Svikram bam_root = rootbuf; 758eb2bd662Svikram bam_rootlen = strlen(rootbuf); 759eb2bd662Svikram } 760eb2bd662Svikram } 76140541d5dSvikram 76240541d5dSvikram /* 763eb2bd662Svikram * We support menu on PCFS (under certain conditions), but 764eb2bd662Svikram * not the OS root 76540541d5dSvikram */ 766eb2bd662Svikram if (is_pcfs(bam_root)) { 767eb2bd662Svikram bam_error(PCFS_ROOT_NOTSUP, bam_root); 768eb2bd662Svikram return (BAM_ERROR); 769ae115bc7Smrj } 770ae115bc7Smrj 771eb2bd662Svikram if (stat(menu_root, &sb) == -1) { 77240541d5dSvikram bam_error(CANNOT_LOCATE_GRUB_MENU); 77340541d5dSvikram return (BAM_ERROR); 77440541d5dSvikram } 77540541d5dSvikram 776eb2bd662Svikram BAM_DPRINTF((D_MENU_ROOT, fcn, menu_root)); 777e7cbe64fSgw25295 778eb2bd662Svikram /* 779eb2bd662Svikram * We no longer use the GRUB slice file. If it exists, then 780eb2bd662Svikram * the user is doing something that is unsupported (such as 781eb2bd662Svikram * standard upgrading an old Live Upgrade BE). If that 782eb2bd662Svikram * happens, mimic existing behavior i.e. pretend that it is 783eb2bd662Svikram * not a BE. Emit a warning though. 784eb2bd662Svikram */ 785eb2bd662Svikram if (bam_alt_root) { 786eb2bd662Svikram (void) snprintf(path, sizeof (path), "%s%s", bam_root, 787eb2bd662Svikram GRUB_slice); 788eb2bd662Svikram } else { 789eb2bd662Svikram (void) snprintf(path, sizeof (path), "%s", GRUB_slice); 790e7cbe64fSgw25295 } 791e7cbe64fSgw25295 792eb2bd662Svikram if (stat(path, &sb) == 0) 793eb2bd662Svikram bam_error(GRUB_SLICE_FILE_EXISTS, path); 794eb2bd662Svikram 795eb2bd662Svikram if (is_zfs(menu_root)) { 796eb2bd662Svikram assert(strcmp(menu_root, bam_root) == 0); 797eb2bd662Svikram special = get_special(menu_root); 798eb2bd662Svikram INJECT_ERROR1("Z_MENU_GET_SPECIAL", special = NULL); 799eb2bd662Svikram if (special == NULL) { 800eb2bd662Svikram bam_error(CANT_FIND_SPECIAL, menu_root); 801eb2bd662Svikram return (BAM_ERROR); 802eb2bd662Svikram } 803eb2bd662Svikram pool = strtok(special, "/"); 804eb2bd662Svikram INJECT_ERROR1("Z_MENU_GET_POOL", pool = NULL); 805eb2bd662Svikram if (pool == NULL) { 806eb2bd662Svikram free(special); 807eb2bd662Svikram bam_error(CANT_FIND_POOL, menu_root); 808eb2bd662Svikram return (BAM_ERROR); 809eb2bd662Svikram } 810eb2bd662Svikram BAM_DPRINTF((D_Z_MENU_GET_POOL_FROM_SPECIAL, fcn, pool)); 811eb2bd662Svikram 812eb2bd662Svikram zmntpt = mount_top_dataset(pool, &zmnted); 813eb2bd662Svikram INJECT_ERROR1("Z_MENU_MOUNT_TOP_DATASET", zmntpt = NULL); 814eb2bd662Svikram if (zmntpt == NULL) { 815eb2bd662Svikram bam_error(CANT_MOUNT_POOL_DATASET, pool); 816eb2bd662Svikram free(special); 817eb2bd662Svikram return (BAM_ERROR); 818eb2bd662Svikram } 819eb2bd662Svikram BAM_DPRINTF((D_Z_GET_MENU_MOUNT_TOP_DATASET, fcn, zmntpt)); 820eb2bd662Svikram 821eb2bd662Svikram (void) strlcpy(menu_root, zmntpt, sizeof (menu_root)); 822eb2bd662Svikram BAM_DPRINTF((D_Z_GET_MENU_MENU_ROOT, fcn, menu_root)); 823eb2bd662Svikram } 824eb2bd662Svikram 825eb2bd662Svikram elide_trailing_slash(menu_root, clean_menu_root, 826eb2bd662Svikram sizeof (clean_menu_root)); 827eb2bd662Svikram 828eb2bd662Svikram BAM_DPRINTF((D_CLEAN_MENU_ROOT, fcn, clean_menu_root)); 829eb2bd662Svikram 830eb2bd662Svikram (void) strlcpy(menu_path, clean_menu_root, sizeof (menu_path)); 83140541d5dSvikram (void) strlcat(menu_path, GRUB_MENU, sizeof (menu_path)); 83240541d5dSvikram 833eb2bd662Svikram BAM_DPRINTF((D_MENU_PATH, fcn, menu_path)); 834eb2bd662Svikram 83540541d5dSvikram /* 836eb2bd662Svikram * If listing the menu, display the menu location 83740541d5dSvikram */ 83840541d5dSvikram if (strcmp(subcmd, "list_entry") == 0) { 839eb2bd662Svikram bam_print(GRUB_MENU_PATH, menu_path); 84040541d5dSvikram } 8417c478bd9Sstevel@tonic-gate 842eb2bd662Svikram 8437c478bd9Sstevel@tonic-gate menu = menu_read(menu_path); 8447c478bd9Sstevel@tonic-gate assert(menu); 8457c478bd9Sstevel@tonic-gate 8467c478bd9Sstevel@tonic-gate /* 847eb2bd662Svikram * We already checked the following case in 848eb2bd662Svikram * check_subcmd_and_suboptions() above. Complete the 849eb2bd662Svikram * final step now. 8507c478bd9Sstevel@tonic-gate */ 8517c478bd9Sstevel@tonic-gate if (strcmp(subcmd, "set_option") == 0) { 852eb2bd662Svikram assert(largc == 1 && largv[0] && largv[1] == NULL); 8537c478bd9Sstevel@tonic-gate opt = largv[0]; 854eb2bd662Svikram } else { 855eb2bd662Svikram assert(largc == 0 && largv == NULL); 8567c478bd9Sstevel@tonic-gate } 8577c478bd9Sstevel@tonic-gate 858eb2bd662Svikram ret = get_boot_cap(bam_root); 859eb2bd662Svikram if (ret != BAM_SUCCESS) { 860eb2bd662Svikram BAM_DPRINTF((D_BOOT_GET_CAP_FAILED, fcn)); 861eb2bd662Svikram goto out; 862eb2bd662Svikram } 863ae115bc7Smrj 8647c478bd9Sstevel@tonic-gate /* 8657c478bd9Sstevel@tonic-gate * Once the sub-cmd handler has run 8667c478bd9Sstevel@tonic-gate * only the line field is guaranteed to have valid values 8677c478bd9Sstevel@tonic-gate */ 868eb2bd662Svikram if (strcmp(subcmd, "update_entry") == 0) 869eb2bd662Svikram ret = f(menu, menu_root, osdev); 870eb2bd662Svikram else if (strcmp(subcmd, "upgrade") == 0) 871eb2bd662Svikram ret = f(menu, bam_root, menu_root); 872eb2bd662Svikram else if (strcmp(subcmd, "list_entry") == 0) 8737c478bd9Sstevel@tonic-gate ret = f(menu, menu_path, opt); 874eb2bd662Svikram else 875eb2bd662Svikram ret = f(menu, NULL, opt); 876eb2bd662Svikram 8777c478bd9Sstevel@tonic-gate if (ret == BAM_WRITE) { 878eb2bd662Svikram BAM_DPRINTF((D_WRITING_MENU_ROOT, fcn, clean_menu_root)); 879eb2bd662Svikram ret = menu_write(clean_menu_root, menu); 8807c478bd9Sstevel@tonic-gate } 8817c478bd9Sstevel@tonic-gate 882eb2bd662Svikram out: 883eb2bd662Svikram INJECT_ERROR1("POOL_SET", pool = "/pooldata"); 884eb2bd662Svikram assert((is_zfs(menu_root)) ^ (pool == NULL)); 885eb2bd662Svikram if (pool) { 886eb2bd662Svikram (void) umount_top_dataset(pool, zmnted, zmntpt); 887eb2bd662Svikram free(special); 888eb2bd662Svikram } 8897c478bd9Sstevel@tonic-gate menu_free(menu); 8907c478bd9Sstevel@tonic-gate return (ret); 8917c478bd9Sstevel@tonic-gate } 8927c478bd9Sstevel@tonic-gate 8937c478bd9Sstevel@tonic-gate 8947c478bd9Sstevel@tonic-gate static error_t 8957c478bd9Sstevel@tonic-gate bam_archive( 8967c478bd9Sstevel@tonic-gate char *subcmd, 8977c478bd9Sstevel@tonic-gate char *opt) 8987c478bd9Sstevel@tonic-gate { 8997c478bd9Sstevel@tonic-gate error_t ret; 9007c478bd9Sstevel@tonic-gate error_t (*f)(char *root, char *opt); 901eb2bd662Svikram const char *fcn = "bam_archive()"; 9027c478bd9Sstevel@tonic-gate 9037c478bd9Sstevel@tonic-gate /* 9048c1b6884Sszhou * Add trailing / for archive subcommands 9058c1b6884Sszhou */ 9068c1b6884Sszhou if (rootbuf[strlen(rootbuf) - 1] != '/') 9078c1b6884Sszhou (void) strcat(rootbuf, "/"); 9088c1b6884Sszhou bam_rootlen = strlen(rootbuf); 9098c1b6884Sszhou 9108c1b6884Sszhou /* 9117c478bd9Sstevel@tonic-gate * Check arguments 9127c478bd9Sstevel@tonic-gate */ 9137c478bd9Sstevel@tonic-gate ret = check_subcmd_and_options(subcmd, opt, arch_subcmds, &f); 9147c478bd9Sstevel@tonic-gate if (ret != BAM_SUCCESS) { 9157c478bd9Sstevel@tonic-gate return (BAM_ERROR); 9167c478bd9Sstevel@tonic-gate } 9177c478bd9Sstevel@tonic-gate 918eb2bd662Svikram ret = get_boot_cap(rootbuf); 919eb2bd662Svikram if (ret != BAM_SUCCESS) { 920eb2bd662Svikram BAM_DPRINTF((D_BOOT_GET_CAP_FAILED, fcn)); 921ae115bc7Smrj return (ret); 922eb2bd662Svikram } 923ae115bc7Smrj 9247c478bd9Sstevel@tonic-gate /* 9257c478bd9Sstevel@tonic-gate * Check archive not supported with update_all 9267c478bd9Sstevel@tonic-gate * since it is awkward to display out-of-sync 9277c478bd9Sstevel@tonic-gate * information for each BE. 9287c478bd9Sstevel@tonic-gate */ 9297c478bd9Sstevel@tonic-gate if (bam_check && strcmp(subcmd, "update_all") == 0) { 9307c478bd9Sstevel@tonic-gate bam_error(CHECK_NOT_SUPPORTED, subcmd); 9317c478bd9Sstevel@tonic-gate return (BAM_ERROR); 9327c478bd9Sstevel@tonic-gate } 9337c478bd9Sstevel@tonic-gate 934b610f78eSvikram if (strcmp(subcmd, "update_all") == 0) 935b610f78eSvikram bam_update_all = 1; 936b610f78eSvikram 937986fd29aSsetje #if !defined(_OPB) 9382449e17fSsherrym ucode_install(bam_root); 9392449e17fSsherrym #endif 9402449e17fSsherrym 941b610f78eSvikram ret = f(bam_root, opt); 942b610f78eSvikram 943b610f78eSvikram bam_update_all = 0; 944b610f78eSvikram 945b610f78eSvikram return (ret); 9467c478bd9Sstevel@tonic-gate } 9477c478bd9Sstevel@tonic-gate 9487c478bd9Sstevel@tonic-gate /*PRINTFLIKE1*/ 949ae115bc7Smrj void 9507c478bd9Sstevel@tonic-gate bam_error(char *format, ...) 9517c478bd9Sstevel@tonic-gate { 9527c478bd9Sstevel@tonic-gate va_list ap; 9537c478bd9Sstevel@tonic-gate 9547c478bd9Sstevel@tonic-gate va_start(ap, format); 9557c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: ", prog); 9567c478bd9Sstevel@tonic-gate (void) vfprintf(stderr, format, ap); 9577c478bd9Sstevel@tonic-gate va_end(ap); 9587c478bd9Sstevel@tonic-gate } 9597c478bd9Sstevel@tonic-gate 9607c478bd9Sstevel@tonic-gate /*PRINTFLIKE1*/ 961eb2bd662Svikram void 962eb2bd662Svikram bam_derror(char *format, ...) 963eb2bd662Svikram { 964eb2bd662Svikram va_list ap; 965eb2bd662Svikram 966eb2bd662Svikram assert(bam_debug); 967eb2bd662Svikram 968eb2bd662Svikram va_start(ap, format); 969eb2bd662Svikram (void) fprintf(stderr, "DEBUG: "); 970eb2bd662Svikram (void) vfprintf(stderr, format, ap); 971eb2bd662Svikram va_end(ap); 972eb2bd662Svikram } 973eb2bd662Svikram 974eb2bd662Svikram /*PRINTFLIKE1*/ 975eb2bd662Svikram void 9767c478bd9Sstevel@tonic-gate bam_print(char *format, ...) 9777c478bd9Sstevel@tonic-gate { 9787c478bd9Sstevel@tonic-gate va_list ap; 9797c478bd9Sstevel@tonic-gate 9807c478bd9Sstevel@tonic-gate va_start(ap, format); 9817c478bd9Sstevel@tonic-gate (void) vfprintf(stdout, format, ap); 9827c478bd9Sstevel@tonic-gate va_end(ap); 9837c478bd9Sstevel@tonic-gate } 9847c478bd9Sstevel@tonic-gate 985ae115bc7Smrj /*PRINTFLIKE1*/ 986ae115bc7Smrj void 987ae115bc7Smrj bam_print_stderr(char *format, ...) 988ae115bc7Smrj { 989ae115bc7Smrj va_list ap; 990ae115bc7Smrj 991ae115bc7Smrj va_start(ap, format); 992ae115bc7Smrj (void) vfprintf(stderr, format, ap); 993ae115bc7Smrj va_end(ap); 994ae115bc7Smrj } 995ae115bc7Smrj 9967c478bd9Sstevel@tonic-gate static void 9977c478bd9Sstevel@tonic-gate bam_exit(int excode) 9987c478bd9Sstevel@tonic-gate { 9997c478bd9Sstevel@tonic-gate bam_unlock(); 10007c478bd9Sstevel@tonic-gate exit(excode); 10017c478bd9Sstevel@tonic-gate } 10027c478bd9Sstevel@tonic-gate 10037c478bd9Sstevel@tonic-gate static void 10047c478bd9Sstevel@tonic-gate bam_lock(void) 10057c478bd9Sstevel@tonic-gate { 10067c478bd9Sstevel@tonic-gate struct flock lock; 10077c478bd9Sstevel@tonic-gate pid_t pid; 10087c478bd9Sstevel@tonic-gate 10097c478bd9Sstevel@tonic-gate bam_lock_fd = open(BAM_LOCK_FILE, O_CREAT|O_RDWR, LOCK_FILE_PERMS); 10107c478bd9Sstevel@tonic-gate if (bam_lock_fd < 0) { 10117c478bd9Sstevel@tonic-gate /* 10127c478bd9Sstevel@tonic-gate * We may be invoked early in boot for archive verification. 10137c478bd9Sstevel@tonic-gate * In this case, root is readonly and /var/run may not exist. 10147c478bd9Sstevel@tonic-gate * Proceed without the lock 10157c478bd9Sstevel@tonic-gate */ 10167c478bd9Sstevel@tonic-gate if (errno == EROFS || errno == ENOENT) { 10177c478bd9Sstevel@tonic-gate bam_root_readonly = 1; 10187c478bd9Sstevel@tonic-gate return; 10197c478bd9Sstevel@tonic-gate } 10207c478bd9Sstevel@tonic-gate 10217c478bd9Sstevel@tonic-gate bam_error(OPEN_FAIL, BAM_LOCK_FILE, strerror(errno)); 10227c478bd9Sstevel@tonic-gate bam_exit(1); 10237c478bd9Sstevel@tonic-gate } 10247c478bd9Sstevel@tonic-gate 10257c478bd9Sstevel@tonic-gate lock.l_type = F_WRLCK; 10267c478bd9Sstevel@tonic-gate lock.l_whence = SEEK_SET; 10277c478bd9Sstevel@tonic-gate lock.l_start = 0; 10287c478bd9Sstevel@tonic-gate lock.l_len = 0; 10297c478bd9Sstevel@tonic-gate 10307c478bd9Sstevel@tonic-gate if (fcntl(bam_lock_fd, F_SETLK, &lock) == -1) { 10317c478bd9Sstevel@tonic-gate if (errno != EACCES && errno != EAGAIN) { 10327c478bd9Sstevel@tonic-gate bam_error(LOCK_FAIL, BAM_LOCK_FILE, strerror(errno)); 10337c478bd9Sstevel@tonic-gate (void) close(bam_lock_fd); 10347c478bd9Sstevel@tonic-gate bam_lock_fd = -1; 10357c478bd9Sstevel@tonic-gate bam_exit(1); 10367c478bd9Sstevel@tonic-gate } 10377c478bd9Sstevel@tonic-gate pid = 0; 10387c478bd9Sstevel@tonic-gate (void) pread(bam_lock_fd, &pid, sizeof (pid_t), 0); 10397c478bd9Sstevel@tonic-gate bam_print(FILE_LOCKED, pid); 10407c478bd9Sstevel@tonic-gate 10417c478bd9Sstevel@tonic-gate lock.l_type = F_WRLCK; 10427c478bd9Sstevel@tonic-gate lock.l_whence = SEEK_SET; 10437c478bd9Sstevel@tonic-gate lock.l_start = 0; 10447c478bd9Sstevel@tonic-gate lock.l_len = 0; 10457c478bd9Sstevel@tonic-gate if (fcntl(bam_lock_fd, F_SETLKW, &lock) == -1) { 10467c478bd9Sstevel@tonic-gate bam_error(LOCK_FAIL, BAM_LOCK_FILE, strerror(errno)); 10477c478bd9Sstevel@tonic-gate (void) close(bam_lock_fd); 10487c478bd9Sstevel@tonic-gate bam_lock_fd = -1; 10497c478bd9Sstevel@tonic-gate bam_exit(1); 10507c478bd9Sstevel@tonic-gate } 10517c478bd9Sstevel@tonic-gate } 10527c478bd9Sstevel@tonic-gate 10537c478bd9Sstevel@tonic-gate /* We own the lock now */ 10547c478bd9Sstevel@tonic-gate pid = getpid(); 10557c478bd9Sstevel@tonic-gate (void) write(bam_lock_fd, &pid, sizeof (pid)); 10567c478bd9Sstevel@tonic-gate } 10577c478bd9Sstevel@tonic-gate 10587c478bd9Sstevel@tonic-gate static void 10597c478bd9Sstevel@tonic-gate bam_unlock(void) 10607c478bd9Sstevel@tonic-gate { 10617c478bd9Sstevel@tonic-gate struct flock unlock; 10627c478bd9Sstevel@tonic-gate 10637c478bd9Sstevel@tonic-gate /* 10647c478bd9Sstevel@tonic-gate * NOP if we don't hold the lock 10657c478bd9Sstevel@tonic-gate */ 10667c478bd9Sstevel@tonic-gate if (bam_lock_fd < 0) { 10677c478bd9Sstevel@tonic-gate return; 10687c478bd9Sstevel@tonic-gate } 10697c478bd9Sstevel@tonic-gate 10707c478bd9Sstevel@tonic-gate unlock.l_type = F_UNLCK; 10717c478bd9Sstevel@tonic-gate unlock.l_whence = SEEK_SET; 10727c478bd9Sstevel@tonic-gate unlock.l_start = 0; 10737c478bd9Sstevel@tonic-gate unlock.l_len = 0; 10747c478bd9Sstevel@tonic-gate 10757c478bd9Sstevel@tonic-gate if (fcntl(bam_lock_fd, F_SETLK, &unlock) == -1) { 10767c478bd9Sstevel@tonic-gate bam_error(UNLOCK_FAIL, BAM_LOCK_FILE, strerror(errno)); 10777c478bd9Sstevel@tonic-gate } 10787c478bd9Sstevel@tonic-gate 10797c478bd9Sstevel@tonic-gate if (close(bam_lock_fd) == -1) { 10807c478bd9Sstevel@tonic-gate bam_error(CLOSE_FAIL, BAM_LOCK_FILE, strerror(errno)); 10817c478bd9Sstevel@tonic-gate } 10827c478bd9Sstevel@tonic-gate bam_lock_fd = -1; 10837c478bd9Sstevel@tonic-gate } 10847c478bd9Sstevel@tonic-gate 10857c478bd9Sstevel@tonic-gate static error_t 10867c478bd9Sstevel@tonic-gate list_archive(char *root, char *opt) 10877c478bd9Sstevel@tonic-gate { 10887c478bd9Sstevel@tonic-gate filelist_t flist; 10897c478bd9Sstevel@tonic-gate filelist_t *flistp = &flist; 10907c478bd9Sstevel@tonic-gate line_t *lp; 10917c478bd9Sstevel@tonic-gate 10927c478bd9Sstevel@tonic-gate assert(root); 10937c478bd9Sstevel@tonic-gate assert(opt == NULL); 10947c478bd9Sstevel@tonic-gate 10957c478bd9Sstevel@tonic-gate flistp->head = flistp->tail = NULL; 10967c478bd9Sstevel@tonic-gate if (read_list(root, flistp) != BAM_SUCCESS) { 10977c478bd9Sstevel@tonic-gate return (BAM_ERROR); 10987c478bd9Sstevel@tonic-gate } 10997c478bd9Sstevel@tonic-gate assert(flistp->head && flistp->tail); 11007c478bd9Sstevel@tonic-gate 11017c478bd9Sstevel@tonic-gate for (lp = flistp->head; lp; lp = lp->next) { 11027c478bd9Sstevel@tonic-gate bam_print(PRINT, lp->line); 11037c478bd9Sstevel@tonic-gate } 11047c478bd9Sstevel@tonic-gate 11057c478bd9Sstevel@tonic-gate filelist_free(flistp); 11067c478bd9Sstevel@tonic-gate 11077c478bd9Sstevel@tonic-gate return (BAM_SUCCESS); 11087c478bd9Sstevel@tonic-gate } 11097c478bd9Sstevel@tonic-gate 11107c478bd9Sstevel@tonic-gate /* 11117c478bd9Sstevel@tonic-gate * This routine writes a list of lines to a file. 11127c478bd9Sstevel@tonic-gate * The list is *not* freed 11137c478bd9Sstevel@tonic-gate */ 11147c478bd9Sstevel@tonic-gate static error_t 11157c478bd9Sstevel@tonic-gate list2file(char *root, char *tmp, char *final, line_t *start) 11167c478bd9Sstevel@tonic-gate { 11177c478bd9Sstevel@tonic-gate char tmpfile[PATH_MAX]; 11187c478bd9Sstevel@tonic-gate char path[PATH_MAX]; 11197c478bd9Sstevel@tonic-gate FILE *fp; 11207c478bd9Sstevel@tonic-gate int ret; 11217c478bd9Sstevel@tonic-gate struct stat sb; 11227c478bd9Sstevel@tonic-gate mode_t mode; 11237c478bd9Sstevel@tonic-gate uid_t root_uid; 11247c478bd9Sstevel@tonic-gate gid_t sys_gid; 11257c478bd9Sstevel@tonic-gate struct passwd *pw; 11267c478bd9Sstevel@tonic-gate struct group *gp; 1127eb2bd662Svikram const char *fcn = "list2file()"; 11287c478bd9Sstevel@tonic-gate 11297c478bd9Sstevel@tonic-gate (void) snprintf(path, sizeof (path), "%s%s", root, final); 11307c478bd9Sstevel@tonic-gate 11317c478bd9Sstevel@tonic-gate if (start == NULL) { 1132eb2bd662Svikram /* Empty GRUB menu */ 11337c478bd9Sstevel@tonic-gate if (stat(path, &sb) != -1) { 11347c478bd9Sstevel@tonic-gate bam_print(UNLINK_EMPTY, path); 11357c478bd9Sstevel@tonic-gate if (unlink(path) != 0) { 11367c478bd9Sstevel@tonic-gate bam_error(UNLINK_FAIL, path, strerror(errno)); 11377c478bd9Sstevel@tonic-gate return (BAM_ERROR); 11387c478bd9Sstevel@tonic-gate } else { 11397c478bd9Sstevel@tonic-gate return (BAM_SUCCESS); 11407c478bd9Sstevel@tonic-gate } 11417c478bd9Sstevel@tonic-gate } 1142eb2bd662Svikram return (BAM_SUCCESS); 11437c478bd9Sstevel@tonic-gate } 11447c478bd9Sstevel@tonic-gate 11457c478bd9Sstevel@tonic-gate /* 11467c478bd9Sstevel@tonic-gate * Preserve attributes of existing file if possible, 11477c478bd9Sstevel@tonic-gate * otherwise ask the system for uid/gid of root/sys. 11487c478bd9Sstevel@tonic-gate * If all fails, fall back on hard-coded defaults. 11497c478bd9Sstevel@tonic-gate */ 11507c478bd9Sstevel@tonic-gate if (stat(path, &sb) != -1) { 11517c478bd9Sstevel@tonic-gate mode = sb.st_mode; 11527c478bd9Sstevel@tonic-gate root_uid = sb.st_uid; 11537c478bd9Sstevel@tonic-gate sys_gid = sb.st_gid; 11547c478bd9Sstevel@tonic-gate } else { 11557c478bd9Sstevel@tonic-gate mode = DEFAULT_DEV_MODE; 11567c478bd9Sstevel@tonic-gate if ((pw = getpwnam(DEFAULT_DEV_USER)) != NULL) { 11577c478bd9Sstevel@tonic-gate root_uid = pw->pw_uid; 11587c478bd9Sstevel@tonic-gate } else { 11597c478bd9Sstevel@tonic-gate bam_error(CANT_FIND_USER, 11607c478bd9Sstevel@tonic-gate DEFAULT_DEV_USER, DEFAULT_DEV_UID); 11617c478bd9Sstevel@tonic-gate root_uid = (uid_t)DEFAULT_DEV_UID; 11627c478bd9Sstevel@tonic-gate } 11637c478bd9Sstevel@tonic-gate if ((gp = getgrnam(DEFAULT_DEV_GROUP)) != NULL) { 11647c478bd9Sstevel@tonic-gate sys_gid = gp->gr_gid; 11657c478bd9Sstevel@tonic-gate } else { 11667c478bd9Sstevel@tonic-gate bam_error(CANT_FIND_GROUP, 11677c478bd9Sstevel@tonic-gate DEFAULT_DEV_GROUP, DEFAULT_DEV_GID); 11687c478bd9Sstevel@tonic-gate sys_gid = (gid_t)DEFAULT_DEV_GID; 11697c478bd9Sstevel@tonic-gate } 11707c478bd9Sstevel@tonic-gate } 11717c478bd9Sstevel@tonic-gate 11727c478bd9Sstevel@tonic-gate (void) snprintf(tmpfile, sizeof (tmpfile), "%s%s", root, tmp); 11737c478bd9Sstevel@tonic-gate 11747c478bd9Sstevel@tonic-gate /* Truncate tmpfile first */ 11757c478bd9Sstevel@tonic-gate fp = fopen(tmpfile, "w"); 11767c478bd9Sstevel@tonic-gate if (fp == NULL) { 11777c478bd9Sstevel@tonic-gate bam_error(OPEN_FAIL, tmpfile, strerror(errno)); 11787c478bd9Sstevel@tonic-gate return (BAM_ERROR); 11797c478bd9Sstevel@tonic-gate } 1180963390b4Svikram ret = fclose(fp); 1181963390b4Svikram INJECT_ERROR1("LIST2FILE_TRUNC_FCLOSE", ret = EOF); 1182963390b4Svikram if (ret == EOF) { 11837c478bd9Sstevel@tonic-gate bam_error(CLOSE_FAIL, tmpfile, strerror(errno)); 11847c478bd9Sstevel@tonic-gate return (BAM_ERROR); 11857c478bd9Sstevel@tonic-gate } 11867c478bd9Sstevel@tonic-gate 11877c478bd9Sstevel@tonic-gate /* Now open it in append mode */ 11887c478bd9Sstevel@tonic-gate fp = fopen(tmpfile, "a"); 11897c478bd9Sstevel@tonic-gate if (fp == NULL) { 11907c478bd9Sstevel@tonic-gate bam_error(OPEN_FAIL, tmpfile, strerror(errno)); 11917c478bd9Sstevel@tonic-gate return (BAM_ERROR); 11927c478bd9Sstevel@tonic-gate } 11937c478bd9Sstevel@tonic-gate 11947c478bd9Sstevel@tonic-gate for (; start; start = start->next) { 1195963390b4Svikram ret = s_fputs(start->line, fp); 1196963390b4Svikram INJECT_ERROR1("LIST2FILE_FPUTS", ret = EOF); 1197963390b4Svikram if (ret == EOF) { 11987c478bd9Sstevel@tonic-gate bam_error(WRITE_FAIL, tmpfile, strerror(errno)); 11997c478bd9Sstevel@tonic-gate (void) fclose(fp); 12007c478bd9Sstevel@tonic-gate return (BAM_ERROR); 12017c478bd9Sstevel@tonic-gate } 12027c478bd9Sstevel@tonic-gate } 12037c478bd9Sstevel@tonic-gate 1204963390b4Svikram ret = fclose(fp); 1205963390b4Svikram INJECT_ERROR1("LIST2FILE_APPEND_FCLOSE", ret = EOF); 1206963390b4Svikram if (ret == EOF) { 12077c478bd9Sstevel@tonic-gate bam_error(CLOSE_FAIL, tmpfile, strerror(errno)); 12087c478bd9Sstevel@tonic-gate return (BAM_ERROR); 12097c478bd9Sstevel@tonic-gate } 12107c478bd9Sstevel@tonic-gate 12117c478bd9Sstevel@tonic-gate /* 1212de531be4Sjg * Set up desired attributes. Ignore failures on filesystems 1213de531be4Sjg * not supporting these operations - pcfs reports unsupported 1214de531be4Sjg * operations as EINVAL. 12157c478bd9Sstevel@tonic-gate */ 12167c478bd9Sstevel@tonic-gate ret = chmod(tmpfile, mode); 1217de531be4Sjg if (ret == -1 && 1218de531be4Sjg errno != EINVAL && errno != ENOTSUP) { 12197c478bd9Sstevel@tonic-gate bam_error(CHMOD_FAIL, tmpfile, strerror(errno)); 12207c478bd9Sstevel@tonic-gate return (BAM_ERROR); 12217c478bd9Sstevel@tonic-gate } 12227c478bd9Sstevel@tonic-gate 12237c478bd9Sstevel@tonic-gate ret = chown(tmpfile, root_uid, sys_gid); 1224de531be4Sjg if (ret == -1 && 1225de531be4Sjg errno != EINVAL && errno != ENOTSUP) { 12267c478bd9Sstevel@tonic-gate bam_error(CHOWN_FAIL, tmpfile, strerror(errno)); 12277c478bd9Sstevel@tonic-gate return (BAM_ERROR); 12287c478bd9Sstevel@tonic-gate } 12297c478bd9Sstevel@tonic-gate 12307c478bd9Sstevel@tonic-gate 12317c478bd9Sstevel@tonic-gate /* 12327c478bd9Sstevel@tonic-gate * Do an atomic rename 12337c478bd9Sstevel@tonic-gate */ 12347c478bd9Sstevel@tonic-gate ret = rename(tmpfile, path); 1235963390b4Svikram INJECT_ERROR1("LIST2FILE_RENAME", ret = -1); 12367c478bd9Sstevel@tonic-gate if (ret != 0) { 12377c478bd9Sstevel@tonic-gate bam_error(RENAME_FAIL, path, strerror(errno)); 12387c478bd9Sstevel@tonic-gate return (BAM_ERROR); 12397c478bd9Sstevel@tonic-gate } 12407c478bd9Sstevel@tonic-gate 1241eb2bd662Svikram BAM_DPRINTF((D_WROTE_FILE, fcn, path)); 12427c478bd9Sstevel@tonic-gate return (BAM_SUCCESS); 12437c478bd9Sstevel@tonic-gate } 12447c478bd9Sstevel@tonic-gate 12457c478bd9Sstevel@tonic-gate /* 12467c478bd9Sstevel@tonic-gate * This function should always return 0 - since we want 12477c478bd9Sstevel@tonic-gate * to create stat data for *all* files in the list. 12487c478bd9Sstevel@tonic-gate */ 12497c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 12507c478bd9Sstevel@tonic-gate static int 12517c478bd9Sstevel@tonic-gate cmpstat( 12527c478bd9Sstevel@tonic-gate const char *file, 12537c478bd9Sstevel@tonic-gate const struct stat *stat, 12547c478bd9Sstevel@tonic-gate int flags, 12557c478bd9Sstevel@tonic-gate struct FTW *ftw) 12567c478bd9Sstevel@tonic-gate { 12577c478bd9Sstevel@tonic-gate uint_t sz; 12587c478bd9Sstevel@tonic-gate uint64_t *value; 12597c478bd9Sstevel@tonic-gate uint64_t filestat[2]; 12607c478bd9Sstevel@tonic-gate int error; 12617c478bd9Sstevel@tonic-gate 126258091fd8Ssetje struct safefile *safefilep; 126358091fd8Ssetje FILE *fp; 126458091fd8Ssetje 12657c478bd9Sstevel@tonic-gate /* 12667c478bd9Sstevel@tonic-gate * We only want regular files 12677c478bd9Sstevel@tonic-gate */ 12687c478bd9Sstevel@tonic-gate if (!S_ISREG(stat->st_mode)) 12697c478bd9Sstevel@tonic-gate return (0); 12707c478bd9Sstevel@tonic-gate 12717c478bd9Sstevel@tonic-gate /* 12727c478bd9Sstevel@tonic-gate * new_nvlp may be NULL if there were errors earlier 12737c478bd9Sstevel@tonic-gate * but this is not fatal to update determination. 12747c478bd9Sstevel@tonic-gate */ 12757c478bd9Sstevel@tonic-gate if (walk_arg.new_nvlp) { 12767c478bd9Sstevel@tonic-gate filestat[0] = stat->st_size; 12777c478bd9Sstevel@tonic-gate filestat[1] = stat->st_mtime; 12787c478bd9Sstevel@tonic-gate error = nvlist_add_uint64_array(walk_arg.new_nvlp, 12797c478bd9Sstevel@tonic-gate file + bam_rootlen, filestat, 2); 12807c478bd9Sstevel@tonic-gate if (error) 12817c478bd9Sstevel@tonic-gate bam_error(NVADD_FAIL, file, strerror(error)); 12827c478bd9Sstevel@tonic-gate } 12837c478bd9Sstevel@tonic-gate 12847c478bd9Sstevel@tonic-gate /* 12857c478bd9Sstevel@tonic-gate * The remaining steps are only required if we haven't made a 12867c478bd9Sstevel@tonic-gate * decision about update or if we are checking (-n) 12877c478bd9Sstevel@tonic-gate */ 12887c478bd9Sstevel@tonic-gate if (walk_arg.need_update && !bam_check) 12897c478bd9Sstevel@tonic-gate return (0); 12907c478bd9Sstevel@tonic-gate 12917c478bd9Sstevel@tonic-gate /* 1292d876c67dSjg * If we are invoked as part of system/filesystem/boot-archive, then 129358091fd8Ssetje * there are a number of things we should not worry about 12947c478bd9Sstevel@tonic-gate */ 129558091fd8Ssetje if (bam_smf_check) { 129658091fd8Ssetje /* ignore amd64 modules unless we are booted amd64. */ 129758091fd8Ssetje if (!is_amd64() && strstr(file, "/amd64/") != 0) 12987c478bd9Sstevel@tonic-gate return (0); 12997c478bd9Sstevel@tonic-gate 130058091fd8Ssetje /* read in list of safe files */ 130158091fd8Ssetje if (safefiles == NULL) 130258091fd8Ssetje if (fp = fopen("/boot/solaris/filelist.safe", "r")) { 130358091fd8Ssetje safefiles = s_calloc(1, 130458091fd8Ssetje sizeof (struct safefile)); 130558091fd8Ssetje safefilep = safefiles; 130658091fd8Ssetje safefilep->name = s_calloc(1, MAXPATHLEN + 130758091fd8Ssetje MAXNAMELEN); 130858091fd8Ssetje safefilep->next = NULL; 130958091fd8Ssetje while (s_fgets(safefilep->name, MAXPATHLEN + 131058091fd8Ssetje MAXNAMELEN, fp) != NULL) { 131158091fd8Ssetje safefilep->next = s_calloc(1, 131258091fd8Ssetje sizeof (struct safefile)); 131358091fd8Ssetje safefilep = safefilep->next; 131458091fd8Ssetje safefilep->name = s_calloc(1, 131558091fd8Ssetje MAXPATHLEN + MAXNAMELEN); 131658091fd8Ssetje safefilep->next = NULL; 131758091fd8Ssetje } 131858091fd8Ssetje (void) fclose(fp); 131958091fd8Ssetje } 132058091fd8Ssetje } 132158091fd8Ssetje 13227c478bd9Sstevel@tonic-gate /* 13237c478bd9Sstevel@tonic-gate * We need an update if file doesn't exist in old archive 13247c478bd9Sstevel@tonic-gate */ 13257c478bd9Sstevel@tonic-gate if (walk_arg.old_nvlp == NULL || 13267c478bd9Sstevel@tonic-gate nvlist_lookup_uint64_array(walk_arg.old_nvlp, 13277c478bd9Sstevel@tonic-gate file + bam_rootlen, &value, &sz) != 0) { 13287c478bd9Sstevel@tonic-gate if (bam_smf_check) /* ignore new during smf check */ 13297c478bd9Sstevel@tonic-gate return (0); 13307c478bd9Sstevel@tonic-gate walk_arg.need_update = 1; 13317c478bd9Sstevel@tonic-gate if (bam_verbose) 13327c478bd9Sstevel@tonic-gate bam_print(PARSEABLE_NEW_FILE, file); 13337c478bd9Sstevel@tonic-gate return (0); 13347c478bd9Sstevel@tonic-gate } 13357c478bd9Sstevel@tonic-gate 13367c478bd9Sstevel@tonic-gate /* 13377c478bd9Sstevel@tonic-gate * File exists in old archive. Check if file has changed 13387c478bd9Sstevel@tonic-gate */ 13397c478bd9Sstevel@tonic-gate assert(sz == 2); 13407c478bd9Sstevel@tonic-gate bcopy(value, filestat, sizeof (filestat)); 13417c478bd9Sstevel@tonic-gate 13427c478bd9Sstevel@tonic-gate if (filestat[0] != stat->st_size || 13437c478bd9Sstevel@tonic-gate filestat[1] != stat->st_mtime) { 13447c609327Ssetje if (bam_smf_check) { 13457c609327Ssetje safefilep = safefiles; 13467c609327Ssetje while (safefilep != NULL) { 13477c609327Ssetje if (strcmp(file + bam_rootlen, 13487c609327Ssetje safefilep->name) == 0) { 13497c609327Ssetje (void) creat(NEED_UPDATE_FILE, 0644); 13507c609327Ssetje return (0); 13517c609327Ssetje } 13527c609327Ssetje safefilep = safefilep->next; 13537c609327Ssetje } 13547c609327Ssetje } 13557c478bd9Sstevel@tonic-gate walk_arg.need_update = 1; 13567c478bd9Sstevel@tonic-gate if (bam_verbose) 13577c478bd9Sstevel@tonic-gate if (bam_smf_check) 13587c478bd9Sstevel@tonic-gate bam_print(" %s\n", file); 13597c478bd9Sstevel@tonic-gate else 13607c478bd9Sstevel@tonic-gate bam_print(PARSEABLE_OUT_DATE, file); 13617c478bd9Sstevel@tonic-gate } 13627c478bd9Sstevel@tonic-gate 13637c478bd9Sstevel@tonic-gate return (0); 13647c478bd9Sstevel@tonic-gate } 13657c478bd9Sstevel@tonic-gate 13667c478bd9Sstevel@tonic-gate /* 13677c478bd9Sstevel@tonic-gate * Check flags and presence of required files. 13687c478bd9Sstevel@tonic-gate * The force flag and/or absence of files should 13697c478bd9Sstevel@tonic-gate * trigger an update. 13707c478bd9Sstevel@tonic-gate * Suppress stdout output if check (-n) option is set 13717c478bd9Sstevel@tonic-gate * (as -n should only produce parseable output.) 13727c478bd9Sstevel@tonic-gate */ 13737c478bd9Sstevel@tonic-gate static void 13747c478bd9Sstevel@tonic-gate check_flags_and_files(char *root) 13757c478bd9Sstevel@tonic-gate { 13767c478bd9Sstevel@tonic-gate char path[PATH_MAX]; 13777c478bd9Sstevel@tonic-gate struct stat sb; 13787c478bd9Sstevel@tonic-gate 13797c478bd9Sstevel@tonic-gate /* 13807c478bd9Sstevel@tonic-gate * if force, create archive unconditionally 13817c478bd9Sstevel@tonic-gate */ 13827c478bd9Sstevel@tonic-gate if (bam_force) { 13837c478bd9Sstevel@tonic-gate walk_arg.need_update = 1; 13847c478bd9Sstevel@tonic-gate if (bam_verbose && !bam_check) 13857c478bd9Sstevel@tonic-gate bam_print(UPDATE_FORCE); 13867c478bd9Sstevel@tonic-gate return; 13877c478bd9Sstevel@tonic-gate } 13887c478bd9Sstevel@tonic-gate 13897c478bd9Sstevel@tonic-gate /* 13907c478bd9Sstevel@tonic-gate * If archive is missing, create archive 13917c478bd9Sstevel@tonic-gate */ 139279755401Ssetje if (is_sparc()) { 139379755401Ssetje (void) snprintf(path, sizeof (path), "%s%s%s%s", root, 139479755401Ssetje ARCHIVE_PREFIX, get_machine(), ARCHIVE_SUFFIX); 1395d876c67dSjg } else { 1396ae115bc7Smrj if (bam_direct == BAM_DIRECT_DBOOT) { 1397ae115bc7Smrj (void) snprintf(path, sizeof (path), "%s%s", root, 1398ae115bc7Smrj DIRECT_BOOT_ARCHIVE_64); 1399ae115bc7Smrj if (stat(path, &sb) != 0) { 1400ae115bc7Smrj if (bam_verbose && !bam_check) 1401ae115bc7Smrj bam_print(UPDATE_ARCH_MISS, path); 1402ae115bc7Smrj walk_arg.need_update = 1; 1403ae115bc7Smrj return; 1404ae115bc7Smrj } 1405ae115bc7Smrj } 1406986fd29aSsetje (void) snprintf(path, sizeof (path), "%s%s", root, 1407986fd29aSsetje DIRECT_BOOT_ARCHIVE_32); 1408986fd29aSsetje } 1409986fd29aSsetje 1410986fd29aSsetje if (stat(path, &sb) != 0) { 1411986fd29aSsetje if (bam_verbose && !bam_check) 1412986fd29aSsetje bam_print(UPDATE_ARCH_MISS, path); 1413986fd29aSsetje walk_arg.need_update = 1; 1414986fd29aSsetje return; 1415986fd29aSsetje } 14167c478bd9Sstevel@tonic-gate } 14177c478bd9Sstevel@tonic-gate 14187c478bd9Sstevel@tonic-gate static error_t 14197c478bd9Sstevel@tonic-gate read_one_list(char *root, filelist_t *flistp, char *filelist) 14207c478bd9Sstevel@tonic-gate { 14217c478bd9Sstevel@tonic-gate char path[PATH_MAX]; 14227c478bd9Sstevel@tonic-gate FILE *fp; 14237c478bd9Sstevel@tonic-gate char buf[BAM_MAXLINE]; 1424eb2bd662Svikram const char *fcn = "read_one_list()"; 14257c478bd9Sstevel@tonic-gate 14267c478bd9Sstevel@tonic-gate (void) snprintf(path, sizeof (path), "%s%s", root, filelist); 14277c478bd9Sstevel@tonic-gate 14287c478bd9Sstevel@tonic-gate fp = fopen(path, "r"); 14297c478bd9Sstevel@tonic-gate if (fp == NULL) { 1430eb2bd662Svikram BAM_DPRINTF((D_FLIST_FAIL, fcn, path, strerror(errno))); 14317c478bd9Sstevel@tonic-gate return (BAM_ERROR); 14327c478bd9Sstevel@tonic-gate } 14337c478bd9Sstevel@tonic-gate while (s_fgets(buf, sizeof (buf), fp) != NULL) { 1434b610f78eSvikram /* skip blank lines */ 1435b610f78eSvikram if (strspn(buf, " \t") == strlen(buf)) 1436b610f78eSvikram continue; 14377c478bd9Sstevel@tonic-gate append_to_flist(flistp, buf); 14387c478bd9Sstevel@tonic-gate } 14397c478bd9Sstevel@tonic-gate if (fclose(fp) != 0) { 14407c478bd9Sstevel@tonic-gate bam_error(CLOSE_FAIL, path, strerror(errno)); 14417c478bd9Sstevel@tonic-gate return (BAM_ERROR); 14427c478bd9Sstevel@tonic-gate } 14437c478bd9Sstevel@tonic-gate return (BAM_SUCCESS); 14447c478bd9Sstevel@tonic-gate } 14457c478bd9Sstevel@tonic-gate 14467c478bd9Sstevel@tonic-gate static error_t 14477c478bd9Sstevel@tonic-gate read_list(char *root, filelist_t *flistp) 14487c478bd9Sstevel@tonic-gate { 1449986fd29aSsetje char path[PATH_MAX]; 1450986fd29aSsetje char cmd[PATH_MAX]; 1451986fd29aSsetje struct stat sb; 1452986fd29aSsetje int n, rval; 1453eb2bd662Svikram const char *fcn = "read_list()"; 14547c478bd9Sstevel@tonic-gate 14557c478bd9Sstevel@tonic-gate flistp->head = flistp->tail = NULL; 14567c478bd9Sstevel@tonic-gate 14577c478bd9Sstevel@tonic-gate /* 1458986fd29aSsetje * build and check path to extract_boot_filelist.ksh 1459986fd29aSsetje */ 1460986fd29aSsetje n = snprintf(path, sizeof (path), "%s%s", root, EXTRACT_BOOT_FILELIST); 1461986fd29aSsetje if (n >= sizeof (path)) { 1462986fd29aSsetje bam_error(NO_FLIST); 1463986fd29aSsetje return (BAM_ERROR); 1464986fd29aSsetje } 1465986fd29aSsetje 1466986fd29aSsetje /* 1467986fd29aSsetje * If extract_boot_filelist is present, exec it, otherwise read 1468986fd29aSsetje * the filelists directly, for compatibility with older images. 1469986fd29aSsetje */ 1470986fd29aSsetje if (stat(path, &sb) == 0) { 1471986fd29aSsetje /* 1472986fd29aSsetje * build arguments to exec extract_boot_filelist.ksh 1473986fd29aSsetje */ 1474d876c67dSjg char *rootarg, *platarg; 1475d876c67dSjg int platarglen = 1, rootarglen = 1; 1476d876c67dSjg if (strlen(root) > 1) 1477d876c67dSjg rootarglen += strlen(root) + strlen("-R "); 1478d876c67dSjg if (bam_alt_platform) 1479d876c67dSjg platarglen += strlen(bam_platform) + strlen("-p "); 1480d876c67dSjg platarg = s_calloc(1, platarglen); 1481d876c67dSjg rootarg = s_calloc(1, rootarglen); 1482d876c67dSjg *platarg = 0; 1483d876c67dSjg *rootarg = 0; 1484d876c67dSjg 1485986fd29aSsetje if (strlen(root) > 1) { 1486d876c67dSjg (void) snprintf(rootarg, rootarglen, 1487d876c67dSjg "-R %s", root); 1488986fd29aSsetje } 1489d876c67dSjg if (bam_alt_platform) { 1490d876c67dSjg (void) snprintf(platarg, platarglen, 1491d876c67dSjg "-p %s", bam_platform); 1492d876c67dSjg } 1493d876c67dSjg n = snprintf(cmd, sizeof (cmd), "%s %s %s /%s /%s", 1494d876c67dSjg path, rootarg, platarg, BOOT_FILE_LIST, ETC_FILE_LIST); 1495d876c67dSjg free(platarg); 1496d876c67dSjg free(rootarg); 1497986fd29aSsetje if (n >= sizeof (cmd)) { 1498986fd29aSsetje bam_error(NO_FLIST); 1499986fd29aSsetje return (BAM_ERROR); 1500986fd29aSsetje } 1501986fd29aSsetje if (exec_cmd(cmd, flistp) != 0) { 1502eb2bd662Svikram BAM_DPRINTF((D_FLIST_FAIL, fcn, path, strerror(errno))); 1503986fd29aSsetje return (BAM_ERROR); 1504986fd29aSsetje } 1505986fd29aSsetje } else { 1506986fd29aSsetje /* 15077c478bd9Sstevel@tonic-gate * Read current lists of files - only the first is mandatory 15087c478bd9Sstevel@tonic-gate */ 15097c478bd9Sstevel@tonic-gate rval = read_one_list(root, flistp, BOOT_FILE_LIST); 15107c478bd9Sstevel@tonic-gate if (rval != BAM_SUCCESS) 15117c478bd9Sstevel@tonic-gate return (rval); 15127c478bd9Sstevel@tonic-gate (void) read_one_list(root, flistp, ETC_FILE_LIST); 1513986fd29aSsetje } 15147c478bd9Sstevel@tonic-gate 15157c478bd9Sstevel@tonic-gate if (flistp->head == NULL) { 15167c478bd9Sstevel@tonic-gate bam_error(NO_FLIST); 15177c478bd9Sstevel@tonic-gate return (BAM_ERROR); 15187c478bd9Sstevel@tonic-gate } 15197c478bd9Sstevel@tonic-gate 15207c478bd9Sstevel@tonic-gate return (BAM_SUCCESS); 15217c478bd9Sstevel@tonic-gate } 15227c478bd9Sstevel@tonic-gate 15237c478bd9Sstevel@tonic-gate static void 15247c478bd9Sstevel@tonic-gate getoldstat(char *root) 15257c478bd9Sstevel@tonic-gate { 15267c478bd9Sstevel@tonic-gate char path[PATH_MAX]; 15277c478bd9Sstevel@tonic-gate int fd, error; 15287c478bd9Sstevel@tonic-gate struct stat sb; 15297c478bd9Sstevel@tonic-gate char *ostat; 15307c478bd9Sstevel@tonic-gate 15317c478bd9Sstevel@tonic-gate (void) snprintf(path, sizeof (path), "%s%s", root, FILE_STAT); 15327c478bd9Sstevel@tonic-gate fd = open(path, O_RDONLY); 15337c478bd9Sstevel@tonic-gate if (fd == -1) { 15347c478bd9Sstevel@tonic-gate if (bam_verbose) 15357c478bd9Sstevel@tonic-gate bam_print(OPEN_FAIL, path, strerror(errno)); 15367c478bd9Sstevel@tonic-gate walk_arg.need_update = 1; 15377c478bd9Sstevel@tonic-gate return; 15387c478bd9Sstevel@tonic-gate } 15397c478bd9Sstevel@tonic-gate 15407c478bd9Sstevel@tonic-gate if (fstat(fd, &sb) != 0) { 15417c478bd9Sstevel@tonic-gate bam_error(STAT_FAIL, path, strerror(errno)); 15427c478bd9Sstevel@tonic-gate (void) close(fd); 15437c478bd9Sstevel@tonic-gate walk_arg.need_update = 1; 15447c478bd9Sstevel@tonic-gate return; 15457c478bd9Sstevel@tonic-gate } 15467c478bd9Sstevel@tonic-gate 15477c478bd9Sstevel@tonic-gate ostat = s_calloc(1, sb.st_size); 15487c478bd9Sstevel@tonic-gate 15497c478bd9Sstevel@tonic-gate if (read(fd, ostat, sb.st_size) != sb.st_size) { 15507c478bd9Sstevel@tonic-gate bam_error(READ_FAIL, path, strerror(errno)); 15517c478bd9Sstevel@tonic-gate (void) close(fd); 15527c478bd9Sstevel@tonic-gate free(ostat); 15537c478bd9Sstevel@tonic-gate walk_arg.need_update = 1; 15547c478bd9Sstevel@tonic-gate return; 15557c478bd9Sstevel@tonic-gate } 15567c478bd9Sstevel@tonic-gate 15577c478bd9Sstevel@tonic-gate (void) close(fd); 15587c478bd9Sstevel@tonic-gate 15597c478bd9Sstevel@tonic-gate walk_arg.old_nvlp = NULL; 15607c478bd9Sstevel@tonic-gate error = nvlist_unpack(ostat, sb.st_size, &walk_arg.old_nvlp, 0); 15617c478bd9Sstevel@tonic-gate 15627c478bd9Sstevel@tonic-gate free(ostat); 15637c478bd9Sstevel@tonic-gate 15647c478bd9Sstevel@tonic-gate if (error) { 15657c478bd9Sstevel@tonic-gate bam_error(UNPACK_FAIL, path, strerror(error)); 15667c478bd9Sstevel@tonic-gate walk_arg.old_nvlp = NULL; 15677c478bd9Sstevel@tonic-gate walk_arg.need_update = 1; 15687c478bd9Sstevel@tonic-gate return; 15697c478bd9Sstevel@tonic-gate } 15707c478bd9Sstevel@tonic-gate } 15717c478bd9Sstevel@tonic-gate 1572a28d77b8Svikram /* 1573a28d77b8Svikram * Checks if a file in the current (old) archive has 1574a28d77b8Svikram * been deleted from the root filesystem. This is needed for 1575a28d77b8Svikram * software like Trusted Extensions (TX) that switch early 1576a28d77b8Svikram * in boot based on presence/absence of a kernel module. 1577a28d77b8Svikram */ 1578a28d77b8Svikram static void 1579a28d77b8Svikram check4stale(char *root) 1580a28d77b8Svikram { 1581a28d77b8Svikram nvpair_t *nvp; 1582a28d77b8Svikram nvlist_t *nvlp; 1583a28d77b8Svikram char *file; 1584a28d77b8Svikram char path[PATH_MAX]; 1585a28d77b8Svikram struct stat sb; 1586a28d77b8Svikram 1587a28d77b8Svikram /* 1588a28d77b8Svikram * Skip stale file check during smf check 1589a28d77b8Svikram */ 1590a28d77b8Svikram if (bam_smf_check) 1591a28d77b8Svikram return; 1592a28d77b8Svikram 1593a28d77b8Svikram /* Nothing to do if no old stats */ 1594a28d77b8Svikram if ((nvlp = walk_arg.old_nvlp) == NULL) 1595a28d77b8Svikram return; 1596a28d77b8Svikram 1597a28d77b8Svikram for (nvp = nvlist_next_nvpair(nvlp, NULL); nvp; 1598a28d77b8Svikram nvp = nvlist_next_nvpair(nvlp, nvp)) { 1599a28d77b8Svikram file = nvpair_name(nvp); 1600a28d77b8Svikram if (file == NULL) 1601a28d77b8Svikram continue; 1602a28d77b8Svikram (void) snprintf(path, sizeof (path), "%s/%s", 1603a28d77b8Svikram root, file); 1604a28d77b8Svikram if (stat(path, &sb) == -1) { 1605a28d77b8Svikram walk_arg.need_update = 1; 1606a28d77b8Svikram if (bam_verbose) 1607a28d77b8Svikram bam_print(PARSEABLE_STALE_FILE, path); 1608a28d77b8Svikram } 1609a28d77b8Svikram } 1610a28d77b8Svikram } 1611a28d77b8Svikram 16127c478bd9Sstevel@tonic-gate static void 16137c478bd9Sstevel@tonic-gate create_newstat(void) 16147c478bd9Sstevel@tonic-gate { 16157c478bd9Sstevel@tonic-gate int error; 16167c478bd9Sstevel@tonic-gate 16177c478bd9Sstevel@tonic-gate error = nvlist_alloc(&walk_arg.new_nvlp, NV_UNIQUE_NAME, 0); 16187c478bd9Sstevel@tonic-gate if (error) { 16197c478bd9Sstevel@tonic-gate /* 16207c478bd9Sstevel@tonic-gate * Not fatal - we can still create archive 16217c478bd9Sstevel@tonic-gate */ 16227c478bd9Sstevel@tonic-gate walk_arg.new_nvlp = NULL; 16237c478bd9Sstevel@tonic-gate bam_error(NVALLOC_FAIL, strerror(error)); 16247c478bd9Sstevel@tonic-gate } 16257c478bd9Sstevel@tonic-gate } 16267c478bd9Sstevel@tonic-gate 16277c478bd9Sstevel@tonic-gate static void 16287c478bd9Sstevel@tonic-gate walk_list(char *root, filelist_t *flistp) 16297c478bd9Sstevel@tonic-gate { 16307c478bd9Sstevel@tonic-gate char path[PATH_MAX]; 16317c478bd9Sstevel@tonic-gate line_t *lp; 16327c478bd9Sstevel@tonic-gate 16337c478bd9Sstevel@tonic-gate for (lp = flistp->head; lp; lp = lp->next) { 1634986fd29aSsetje /* 1635986fd29aSsetje * Don't follow symlinks. A symlink must refer to 1636986fd29aSsetje * a file that would appear in the archive through 1637986fd29aSsetje * a direct reference. This matches the archive 1638986fd29aSsetje * construction behavior. 1639986fd29aSsetje */ 16407c478bd9Sstevel@tonic-gate (void) snprintf(path, sizeof (path), "%s%s", root, lp->line); 1641986fd29aSsetje if (nftw(path, cmpstat, 20, FTW_PHYS) == -1) { 16427c478bd9Sstevel@tonic-gate /* 16437c478bd9Sstevel@tonic-gate * Some files may not exist. 16447c478bd9Sstevel@tonic-gate * For example: etc/rtc_config on a x86 diskless system 16457c478bd9Sstevel@tonic-gate * Emit verbose message only 16467c478bd9Sstevel@tonic-gate */ 16477c478bd9Sstevel@tonic-gate if (bam_verbose) 16487c478bd9Sstevel@tonic-gate bam_print(NFTW_FAIL, path, strerror(errno)); 16497c478bd9Sstevel@tonic-gate } 16507c478bd9Sstevel@tonic-gate } 16517c478bd9Sstevel@tonic-gate } 16527c478bd9Sstevel@tonic-gate 16537c478bd9Sstevel@tonic-gate static void 16547c478bd9Sstevel@tonic-gate savenew(char *root) 16557c478bd9Sstevel@tonic-gate { 16567c478bd9Sstevel@tonic-gate char path[PATH_MAX]; 16577c478bd9Sstevel@tonic-gate char path2[PATH_MAX]; 16587c478bd9Sstevel@tonic-gate size_t sz; 16597c478bd9Sstevel@tonic-gate char *nstat; 16607c478bd9Sstevel@tonic-gate int fd, wrote, error; 16617c478bd9Sstevel@tonic-gate 16627c478bd9Sstevel@tonic-gate nstat = NULL; 16637c478bd9Sstevel@tonic-gate sz = 0; 16647c478bd9Sstevel@tonic-gate error = nvlist_pack(walk_arg.new_nvlp, &nstat, &sz, 16657c478bd9Sstevel@tonic-gate NV_ENCODE_XDR, 0); 16667c478bd9Sstevel@tonic-gate if (error) { 16677c478bd9Sstevel@tonic-gate bam_error(PACK_FAIL, strerror(error)); 16687c478bd9Sstevel@tonic-gate return; 16697c478bd9Sstevel@tonic-gate } 16707c478bd9Sstevel@tonic-gate 16717c478bd9Sstevel@tonic-gate (void) snprintf(path, sizeof (path), "%s%s", root, FILE_STAT_TMP); 16727c478bd9Sstevel@tonic-gate fd = open(path, O_RDWR|O_CREAT|O_TRUNC, FILE_STAT_MODE); 16737c478bd9Sstevel@tonic-gate if (fd == -1) { 16747c478bd9Sstevel@tonic-gate bam_error(OPEN_FAIL, path, strerror(errno)); 16757c478bd9Sstevel@tonic-gate free(nstat); 16767c478bd9Sstevel@tonic-gate return; 16777c478bd9Sstevel@tonic-gate } 16787c478bd9Sstevel@tonic-gate wrote = write(fd, nstat, sz); 16797c478bd9Sstevel@tonic-gate if (wrote != sz) { 16807c478bd9Sstevel@tonic-gate bam_error(WRITE_FAIL, path, strerror(errno)); 16817c478bd9Sstevel@tonic-gate (void) close(fd); 16827c478bd9Sstevel@tonic-gate free(nstat); 16837c478bd9Sstevel@tonic-gate return; 16847c478bd9Sstevel@tonic-gate } 16857c478bd9Sstevel@tonic-gate (void) close(fd); 16867c478bd9Sstevel@tonic-gate free(nstat); 16877c478bd9Sstevel@tonic-gate 16887c478bd9Sstevel@tonic-gate (void) snprintf(path2, sizeof (path2), "%s%s", root, FILE_STAT); 16897c478bd9Sstevel@tonic-gate if (rename(path, path2) != 0) { 16907c478bd9Sstevel@tonic-gate bam_error(RENAME_FAIL, path2, strerror(errno)); 16917c478bd9Sstevel@tonic-gate } 16927c478bd9Sstevel@tonic-gate } 16937c478bd9Sstevel@tonic-gate 16947c478bd9Sstevel@tonic-gate static void 16957c478bd9Sstevel@tonic-gate clear_walk_args(void) 16967c478bd9Sstevel@tonic-gate { 16977c478bd9Sstevel@tonic-gate if (walk_arg.old_nvlp) 16987c478bd9Sstevel@tonic-gate nvlist_free(walk_arg.old_nvlp); 16997c478bd9Sstevel@tonic-gate if (walk_arg.new_nvlp) 17007c478bd9Sstevel@tonic-gate nvlist_free(walk_arg.new_nvlp); 17017c478bd9Sstevel@tonic-gate walk_arg.need_update = 0; 17027c478bd9Sstevel@tonic-gate walk_arg.old_nvlp = NULL; 17037c478bd9Sstevel@tonic-gate walk_arg.new_nvlp = NULL; 17047c478bd9Sstevel@tonic-gate } 17057c478bd9Sstevel@tonic-gate 17067c478bd9Sstevel@tonic-gate /* 17077c478bd9Sstevel@tonic-gate * Returns: 17087c478bd9Sstevel@tonic-gate * 0 - no update necessary 17097c478bd9Sstevel@tonic-gate * 1 - update required. 17107c478bd9Sstevel@tonic-gate * BAM_ERROR (-1) - An error occurred 17117c478bd9Sstevel@tonic-gate * 17127c478bd9Sstevel@tonic-gate * Special handling for check (-n): 17137c478bd9Sstevel@tonic-gate * ================================ 17147c478bd9Sstevel@tonic-gate * The check (-n) option produces parseable output. 17157c478bd9Sstevel@tonic-gate * To do this, we suppress all stdout messages unrelated 17167c478bd9Sstevel@tonic-gate * to out of sync files. 17177c478bd9Sstevel@tonic-gate * All stderr messages are still printed though. 17187c478bd9Sstevel@tonic-gate * 17197c478bd9Sstevel@tonic-gate */ 17207c478bd9Sstevel@tonic-gate static int 17217c478bd9Sstevel@tonic-gate update_required(char *root) 17227c478bd9Sstevel@tonic-gate { 17237c478bd9Sstevel@tonic-gate struct stat sb; 17247c478bd9Sstevel@tonic-gate char path[PATH_MAX]; 17257c478bd9Sstevel@tonic-gate filelist_t flist; 17267c478bd9Sstevel@tonic-gate filelist_t *flistp = &flist; 17277c478bd9Sstevel@tonic-gate int need_update; 17287c478bd9Sstevel@tonic-gate 17297c478bd9Sstevel@tonic-gate flistp->head = flistp->tail = NULL; 17307c478bd9Sstevel@tonic-gate 17317c478bd9Sstevel@tonic-gate walk_arg.need_update = 0; 17327c478bd9Sstevel@tonic-gate 17337c478bd9Sstevel@tonic-gate /* 17347c478bd9Sstevel@tonic-gate * Without consulting stat data, check if we need update 17357c478bd9Sstevel@tonic-gate */ 17367c478bd9Sstevel@tonic-gate check_flags_and_files(root); 17377c478bd9Sstevel@tonic-gate 17387c478bd9Sstevel@tonic-gate /* 17397c478bd9Sstevel@tonic-gate * In certain deployment scenarios, filestat may not 17407c478bd9Sstevel@tonic-gate * exist. Ignore it during boot-archive SMF check. 17417c478bd9Sstevel@tonic-gate */ 17427c478bd9Sstevel@tonic-gate if (bam_smf_check) { 17437c478bd9Sstevel@tonic-gate (void) snprintf(path, sizeof (path), "%s%s", root, FILE_STAT); 17447c478bd9Sstevel@tonic-gate if (stat(path, &sb) != 0) 17457c478bd9Sstevel@tonic-gate return (0); 17467c478bd9Sstevel@tonic-gate } 17477c478bd9Sstevel@tonic-gate 17487c478bd9Sstevel@tonic-gate /* 17497c478bd9Sstevel@tonic-gate * consult stat data only if we haven't made a decision 17507c478bd9Sstevel@tonic-gate * about update. If checking (-n) however, we always 17517c478bd9Sstevel@tonic-gate * need stat data (since we want to compare old and new) 17527c478bd9Sstevel@tonic-gate */ 17537c478bd9Sstevel@tonic-gate if (!walk_arg.need_update || bam_check) 17547c478bd9Sstevel@tonic-gate getoldstat(root); 17557c478bd9Sstevel@tonic-gate 17567c478bd9Sstevel@tonic-gate /* 1757a28d77b8Svikram * Check if the archive contains files that are no longer 1758a28d77b8Svikram * present on the root filesystem. 1759a28d77b8Svikram */ 1760a28d77b8Svikram if (!walk_arg.need_update || bam_check) 1761a28d77b8Svikram check4stale(root); 1762a28d77b8Svikram 1763a28d77b8Svikram /* 17647c478bd9Sstevel@tonic-gate * read list of files 17657c478bd9Sstevel@tonic-gate */ 17667c478bd9Sstevel@tonic-gate if (read_list(root, flistp) != BAM_SUCCESS) { 17677c478bd9Sstevel@tonic-gate clear_walk_args(); 17687c478bd9Sstevel@tonic-gate return (BAM_ERROR); 17697c478bd9Sstevel@tonic-gate } 17707c478bd9Sstevel@tonic-gate 17717c478bd9Sstevel@tonic-gate assert(flistp->head && flistp->tail); 17727c478bd9Sstevel@tonic-gate 17737c478bd9Sstevel@tonic-gate /* 17747c478bd9Sstevel@tonic-gate * At this point either the update is required 17757c478bd9Sstevel@tonic-gate * or the decision is pending. In either case 17767c478bd9Sstevel@tonic-gate * we need to create new stat nvlist 17777c478bd9Sstevel@tonic-gate */ 17787c478bd9Sstevel@tonic-gate create_newstat(); 17797c478bd9Sstevel@tonic-gate 17807c478bd9Sstevel@tonic-gate /* 17817c478bd9Sstevel@tonic-gate * This walk does 2 things: 17827c478bd9Sstevel@tonic-gate * - gets new stat data for every file 17837c478bd9Sstevel@tonic-gate * - (optional) compare old and new stat data 17847c478bd9Sstevel@tonic-gate */ 17857c478bd9Sstevel@tonic-gate walk_list(root, &flist); 17867c478bd9Sstevel@tonic-gate 17877c478bd9Sstevel@tonic-gate /* done with the file list */ 17887c478bd9Sstevel@tonic-gate filelist_free(flistp); 17897c478bd9Sstevel@tonic-gate 17907c478bd9Sstevel@tonic-gate /* 17917c478bd9Sstevel@tonic-gate * if we didn't succeed in creating new stat data above 17927c478bd9Sstevel@tonic-gate * just return result of update check so that archive is built. 17937c478bd9Sstevel@tonic-gate */ 17947c478bd9Sstevel@tonic-gate if (walk_arg.new_nvlp == NULL) { 17957c478bd9Sstevel@tonic-gate bam_error(NO_NEW_STAT); 17967c478bd9Sstevel@tonic-gate need_update = walk_arg.need_update; 17977c478bd9Sstevel@tonic-gate clear_walk_args(); 17987c478bd9Sstevel@tonic-gate return (need_update ? 1 : 0); 17997c478bd9Sstevel@tonic-gate } 18007c478bd9Sstevel@tonic-gate 18017c478bd9Sstevel@tonic-gate 18027c478bd9Sstevel@tonic-gate /* 18037c478bd9Sstevel@tonic-gate * If no update required, discard newstat 18047c478bd9Sstevel@tonic-gate */ 18057c478bd9Sstevel@tonic-gate if (!walk_arg.need_update) { 18067c478bd9Sstevel@tonic-gate clear_walk_args(); 18077c478bd9Sstevel@tonic-gate return (0); 18087c478bd9Sstevel@tonic-gate } 18097c478bd9Sstevel@tonic-gate 18107c478bd9Sstevel@tonic-gate return (1); 18117c478bd9Sstevel@tonic-gate } 18127c478bd9Sstevel@tonic-gate 18137c478bd9Sstevel@tonic-gate static error_t 18147c478bd9Sstevel@tonic-gate create_ramdisk(char *root) 18157c478bd9Sstevel@tonic-gate { 18167c478bd9Sstevel@tonic-gate char *cmdline, path[PATH_MAX]; 18177c478bd9Sstevel@tonic-gate size_t len; 18187c478bd9Sstevel@tonic-gate struct stat sb; 18197c478bd9Sstevel@tonic-gate 18207c478bd9Sstevel@tonic-gate /* 18217c478bd9Sstevel@tonic-gate * Setup command args for create_ramdisk.ksh 18227c478bd9Sstevel@tonic-gate */ 1823986fd29aSsetje (void) snprintf(path, sizeof (path), "%s/%s", root, CREATE_RAMDISK); 18247c478bd9Sstevel@tonic-gate if (stat(path, &sb) != 0) { 18257c478bd9Sstevel@tonic-gate bam_error(ARCH_EXEC_MISS, path, strerror(errno)); 18267c478bd9Sstevel@tonic-gate return (BAM_ERROR); 18277c478bd9Sstevel@tonic-gate } 18287c478bd9Sstevel@tonic-gate 18297c478bd9Sstevel@tonic-gate len = strlen(path) + strlen(root) + 10; /* room for space + -R */ 1830d876c67dSjg if (bam_alt_platform) 1831d876c67dSjg len += strlen(bam_platform) + strlen("-p "); 18327c478bd9Sstevel@tonic-gate cmdline = s_calloc(1, len); 18337c478bd9Sstevel@tonic-gate 1834d876c67dSjg if (bam_alt_platform) { 1835d876c67dSjg assert(strlen(root) > 1); 1836d876c67dSjg (void) snprintf(cmdline, len, "%s -p %s -R %s", 1837d876c67dSjg path, bam_platform, root); 1838d876c67dSjg /* chop off / at the end */ 1839d876c67dSjg cmdline[strlen(cmdline) - 1] = '\0'; 1840d876c67dSjg } else if (strlen(root) > 1) { 18417c478bd9Sstevel@tonic-gate (void) snprintf(cmdline, len, "%s -R %s", path, root); 18427c478bd9Sstevel@tonic-gate /* chop off / at the end */ 18437c478bd9Sstevel@tonic-gate cmdline[strlen(cmdline) - 1] = '\0'; 18447c478bd9Sstevel@tonic-gate } else 18457c478bd9Sstevel@tonic-gate (void) snprintf(cmdline, len, "%s", path); 18467c478bd9Sstevel@tonic-gate 1847986fd29aSsetje if (exec_cmd(cmdline, NULL) != 0) { 18487c478bd9Sstevel@tonic-gate bam_error(ARCHIVE_FAIL, cmdline); 18497c478bd9Sstevel@tonic-gate free(cmdline); 18507c478bd9Sstevel@tonic-gate return (BAM_ERROR); 18517c478bd9Sstevel@tonic-gate } 18527c478bd9Sstevel@tonic-gate free(cmdline); 18537c478bd9Sstevel@tonic-gate 18547c478bd9Sstevel@tonic-gate /* 1855986fd29aSsetje * The existence of the expected archives used to be 1856986fd29aSsetje * verified here. This check is done in create_ramdisk as 1857986fd29aSsetje * it needs to be in sync with the altroot operated upon. 18587c478bd9Sstevel@tonic-gate */ 18597c478bd9Sstevel@tonic-gate 18607c478bd9Sstevel@tonic-gate return (BAM_SUCCESS); 18617c478bd9Sstevel@tonic-gate } 18627c478bd9Sstevel@tonic-gate 18637c478bd9Sstevel@tonic-gate /* 18647c478bd9Sstevel@tonic-gate * Checks if target filesystem is on a ramdisk 18657c478bd9Sstevel@tonic-gate * 1 - is miniroot 18667c478bd9Sstevel@tonic-gate * 0 - is not 18677c478bd9Sstevel@tonic-gate * When in doubt assume it is not a ramdisk. 18687c478bd9Sstevel@tonic-gate */ 18697c478bd9Sstevel@tonic-gate static int 18707c478bd9Sstevel@tonic-gate is_ramdisk(char *root) 18717c478bd9Sstevel@tonic-gate { 18727c478bd9Sstevel@tonic-gate struct extmnttab mnt; 18737c478bd9Sstevel@tonic-gate FILE *fp; 18747c478bd9Sstevel@tonic-gate int found; 1875b610f78eSvikram char mntpt[PATH_MAX]; 1876b610f78eSvikram char *cp; 18777c478bd9Sstevel@tonic-gate 18787c478bd9Sstevel@tonic-gate /* 18797c478bd9Sstevel@tonic-gate * There are 3 situations where creating archive is 18807c478bd9Sstevel@tonic-gate * of dubious value: 1881b610f78eSvikram * - create boot_archive on a lofi-mounted boot_archive 18827c478bd9Sstevel@tonic-gate * - create it on a ramdisk which is the root filesystem 18837c478bd9Sstevel@tonic-gate * - create it on a ramdisk mounted somewhere else 18847c478bd9Sstevel@tonic-gate * The first is not easy to detect and checking for it is not 18857c478bd9Sstevel@tonic-gate * worth it. 18867c478bd9Sstevel@tonic-gate * The other two conditions are handled here 18877c478bd9Sstevel@tonic-gate */ 18887c478bd9Sstevel@tonic-gate 18897c478bd9Sstevel@tonic-gate fp = fopen(MNTTAB, "r"); 18907c478bd9Sstevel@tonic-gate if (fp == NULL) { 18917c478bd9Sstevel@tonic-gate bam_error(OPEN_FAIL, MNTTAB, strerror(errno)); 18927c478bd9Sstevel@tonic-gate return (0); 18937c478bd9Sstevel@tonic-gate } 18947c478bd9Sstevel@tonic-gate 18957c478bd9Sstevel@tonic-gate resetmnttab(fp); 18967c478bd9Sstevel@tonic-gate 1897b610f78eSvikram /* 1898b610f78eSvikram * Remove any trailing / from the mount point 1899b610f78eSvikram */ 1900b610f78eSvikram (void) strlcpy(mntpt, root, sizeof (mntpt)); 1901b610f78eSvikram if (strcmp(root, "/") != 0) { 1902b610f78eSvikram cp = mntpt + strlen(mntpt) - 1; 1903b610f78eSvikram if (*cp == '/') 1904b610f78eSvikram *cp = '\0'; 1905b610f78eSvikram } 19067c478bd9Sstevel@tonic-gate found = 0; 19077c478bd9Sstevel@tonic-gate while (getextmntent(fp, &mnt, sizeof (mnt)) == 0) { 1908b610f78eSvikram if (strcmp(mnt.mnt_mountp, mntpt) == 0) { 19097c478bd9Sstevel@tonic-gate found = 1; 19107c478bd9Sstevel@tonic-gate break; 19117c478bd9Sstevel@tonic-gate } 19127c478bd9Sstevel@tonic-gate } 19137c478bd9Sstevel@tonic-gate 19147c478bd9Sstevel@tonic-gate if (!found) { 19157c478bd9Sstevel@tonic-gate if (bam_verbose) 1916b610f78eSvikram bam_error(NOT_IN_MNTTAB, mntpt); 19177c478bd9Sstevel@tonic-gate (void) fclose(fp); 19187c478bd9Sstevel@tonic-gate return (0); 19197c478bd9Sstevel@tonic-gate } 19207c478bd9Sstevel@tonic-gate 19217c478bd9Sstevel@tonic-gate if (strstr(mnt.mnt_special, RAMDISK_SPECIAL) != NULL) { 19227c478bd9Sstevel@tonic-gate if (bam_verbose) 19237c478bd9Sstevel@tonic-gate bam_error(IS_RAMDISK, bam_root); 19247c478bd9Sstevel@tonic-gate (void) fclose(fp); 19257c478bd9Sstevel@tonic-gate return (1); 19267c478bd9Sstevel@tonic-gate } 19277c478bd9Sstevel@tonic-gate 19287c478bd9Sstevel@tonic-gate (void) fclose(fp); 19297c478bd9Sstevel@tonic-gate 19307c478bd9Sstevel@tonic-gate return (0); 19317c478bd9Sstevel@tonic-gate } 19327c478bd9Sstevel@tonic-gate 19337c478bd9Sstevel@tonic-gate static int 1934986fd29aSsetje is_boot_archive(char *root) 19357c478bd9Sstevel@tonic-gate { 19367c478bd9Sstevel@tonic-gate char path[PATH_MAX]; 19377c478bd9Sstevel@tonic-gate struct stat sb; 1938eb2bd662Svikram int error; 1939eb2bd662Svikram const char *fcn = "is_boot_archive()"; 19407c478bd9Sstevel@tonic-gate 19417c478bd9Sstevel@tonic-gate /* 1942986fd29aSsetje * We can't create an archive without the create_ramdisk script 19437c478bd9Sstevel@tonic-gate */ 1944986fd29aSsetje (void) snprintf(path, sizeof (path), "%s/%s", root, CREATE_RAMDISK); 1945eb2bd662Svikram error = stat(path, &sb); 1946eb2bd662Svikram INJECT_ERROR1("NOT_ARCHIVE_BASED", error = -1); 1947eb2bd662Svikram if (error == -1) { 19487c478bd9Sstevel@tonic-gate if (bam_verbose) 19497c478bd9Sstevel@tonic-gate bam_print(FILE_MISS, path); 1950eb2bd662Svikram BAM_DPRINTF((D_NOT_ARCHIVE_BOOT, fcn, root)); 19517c478bd9Sstevel@tonic-gate return (0); 19527c478bd9Sstevel@tonic-gate } 19537c478bd9Sstevel@tonic-gate 1954eb2bd662Svikram BAM_DPRINTF((D_IS_ARCHIVE_BOOT, fcn, root)); 1955986fd29aSsetje return (1); 1956986fd29aSsetje } 1957986fd29aSsetje 19587c478bd9Sstevel@tonic-gate /* 1959986fd29aSsetje * Need to call this for anything that operates on the GRUB menu 1960963390b4Svikram * In the x86 live upgrade case the directory /boot/grub may be present 1961963390b4Svikram * even on pre-newboot BEs. The authoritative way to check for a GRUB target 1962963390b4Svikram * is to check for the presence of the stage2 binary which is present 1963963390b4Svikram * only on GRUB targets (even on x86 boot partitions). Checking for the 1964963390b4Svikram * presence of the multiboot binary is not correct as it is not present 1965963390b4Svikram * on x86 boot partitions. 1966986fd29aSsetje */ 1967986fd29aSsetje int 1968986fd29aSsetje is_grub(const char *root) 1969986fd29aSsetje { 1970986fd29aSsetje char path[PATH_MAX]; 1971986fd29aSsetje struct stat sb; 1972eb2bd662Svikram const char *fcn = "is_grub()"; 1973986fd29aSsetje 1974963390b4Svikram (void) snprintf(path, sizeof (path), "%s%s", root, GRUB_STAGE2); 19757c478bd9Sstevel@tonic-gate if (stat(path, &sb) == -1) { 1976eb2bd662Svikram BAM_DPRINTF((D_NO_GRUB_DIR, fcn, path)); 19777c478bd9Sstevel@tonic-gate return (0); 19787c478bd9Sstevel@tonic-gate } 19797c478bd9Sstevel@tonic-gate 19807c478bd9Sstevel@tonic-gate return (1); 19817c478bd9Sstevel@tonic-gate } 19827c478bd9Sstevel@tonic-gate 19837c478bd9Sstevel@tonic-gate static int 1984eb2bd662Svikram is_zfs(char *root) 1985eb2bd662Svikram { 1986eb2bd662Svikram struct statvfs vfs; 1987eb2bd662Svikram int ret; 1988eb2bd662Svikram const char *fcn = "is_zfs()"; 1989eb2bd662Svikram 1990eb2bd662Svikram ret = statvfs(root, &vfs); 1991eb2bd662Svikram INJECT_ERROR1("STATVFS_ZFS", ret = 1); 1992eb2bd662Svikram if (ret != 0) { 1993eb2bd662Svikram bam_error(STATVFS_FAIL, root, strerror(errno)); 1994eb2bd662Svikram return (0); 1995eb2bd662Svikram } 1996eb2bd662Svikram 1997eb2bd662Svikram if (strncmp(vfs.f_basetype, "zfs", strlen("zfs")) == 0) { 1998eb2bd662Svikram BAM_DPRINTF((D_IS_ZFS, fcn, root)); 1999eb2bd662Svikram return (1); 2000eb2bd662Svikram } else { 2001eb2bd662Svikram BAM_DPRINTF((D_IS_NOT_ZFS, fcn, root)); 2002eb2bd662Svikram return (0); 2003eb2bd662Svikram } 2004eb2bd662Svikram } 2005eb2bd662Svikram 2006eb2bd662Svikram static int 2007eb2bd662Svikram is_ufs(char *root) 2008eb2bd662Svikram { 2009eb2bd662Svikram struct statvfs vfs; 2010eb2bd662Svikram int ret; 2011eb2bd662Svikram const char *fcn = "is_ufs()"; 2012eb2bd662Svikram 2013eb2bd662Svikram ret = statvfs(root, &vfs); 2014eb2bd662Svikram INJECT_ERROR1("STATVFS_UFS", ret = 1); 2015eb2bd662Svikram if (ret != 0) { 2016eb2bd662Svikram bam_error(STATVFS_FAIL, root, strerror(errno)); 2017eb2bd662Svikram return (0); 2018eb2bd662Svikram } 2019eb2bd662Svikram 2020eb2bd662Svikram if (strncmp(vfs.f_basetype, "ufs", strlen("ufs")) == 0) { 2021eb2bd662Svikram BAM_DPRINTF((D_IS_UFS, fcn, root)); 2022eb2bd662Svikram return (1); 2023eb2bd662Svikram } else { 2024eb2bd662Svikram BAM_DPRINTF((D_IS_NOT_UFS, fcn, root)); 2025eb2bd662Svikram return (0); 2026eb2bd662Svikram } 2027eb2bd662Svikram } 2028eb2bd662Svikram 2029eb2bd662Svikram static int 2030eb2bd662Svikram is_pcfs(char *root) 2031eb2bd662Svikram { 2032eb2bd662Svikram struct statvfs vfs; 2033eb2bd662Svikram int ret; 2034eb2bd662Svikram const char *fcn = "is_pcfs()"; 2035eb2bd662Svikram 2036eb2bd662Svikram ret = statvfs(root, &vfs); 2037eb2bd662Svikram INJECT_ERROR1("STATVFS_PCFS", ret = 1); 2038eb2bd662Svikram if (ret != 0) { 2039eb2bd662Svikram bam_error(STATVFS_FAIL, root, strerror(errno)); 2040eb2bd662Svikram return (0); 2041eb2bd662Svikram } 2042eb2bd662Svikram 2043eb2bd662Svikram if (strncmp(vfs.f_basetype, "pcfs", strlen("pcfs")) == 0) { 2044eb2bd662Svikram BAM_DPRINTF((D_IS_PCFS, fcn, root)); 2045eb2bd662Svikram return (1); 2046eb2bd662Svikram } else { 2047eb2bd662Svikram BAM_DPRINTF((D_IS_NOT_PCFS, fcn, root)); 2048eb2bd662Svikram return (0); 2049eb2bd662Svikram } 2050eb2bd662Svikram } 2051eb2bd662Svikram 2052eb2bd662Svikram static int 20537c478bd9Sstevel@tonic-gate is_readonly(char *root) 20547c478bd9Sstevel@tonic-gate { 2055eb2bd662Svikram int fd; 2056eb2bd662Svikram int error; 2057eb2bd662Svikram char testfile[PATH_MAX]; 2058eb2bd662Svikram const char *fcn = "is_readonly()"; 20597c478bd9Sstevel@tonic-gate 20607c478bd9Sstevel@tonic-gate /* 2061eb2bd662Svikram * Using statvfs() to check for a read-only filesystem is not 2062eb2bd662Svikram * reliable. The only way to reliably test is to attempt to 2063eb2bd662Svikram * create a file 20647c478bd9Sstevel@tonic-gate */ 2065eb2bd662Svikram (void) snprintf(testfile, sizeof (testfile), "%s/%s.%d", 2066eb2bd662Svikram root, BOOTADM_RDONLY_TEST, getpid()); 20677c478bd9Sstevel@tonic-gate 2068eb2bd662Svikram (void) unlink(testfile); 2069eb2bd662Svikram 2070eb2bd662Svikram errno = 0; 2071eb2bd662Svikram fd = open(testfile, O_RDWR|O_CREAT|O_EXCL, 0644); 2072eb2bd662Svikram error = errno; 2073eb2bd662Svikram INJECT_ERROR2("RDONLY_TEST_ERROR", fd = -1, error = EACCES); 2074eb2bd662Svikram if (fd == -1 && error == EROFS) { 2075eb2bd662Svikram BAM_DPRINTF((D_RDONLY_FS, fcn, root)); 20767c478bd9Sstevel@tonic-gate return (1); 2077eb2bd662Svikram } else if (fd == -1) { 2078eb2bd662Svikram bam_error(RDONLY_TEST_ERROR, root, strerror(error)); 20797c478bd9Sstevel@tonic-gate } 20807c478bd9Sstevel@tonic-gate 2081eb2bd662Svikram (void) close(fd); 2082eb2bd662Svikram (void) unlink(testfile); 20837c478bd9Sstevel@tonic-gate 2084eb2bd662Svikram BAM_DPRINTF((D_RDWR_FS, fcn, root)); 2085e7cbe64fSgw25295 return (0); 2086e7cbe64fSgw25295 } 2087e7cbe64fSgw25295 20887c478bd9Sstevel@tonic-gate static error_t 20897c478bd9Sstevel@tonic-gate update_archive(char *root, char *opt) 20907c478bd9Sstevel@tonic-gate { 20917c478bd9Sstevel@tonic-gate error_t ret; 20927c478bd9Sstevel@tonic-gate 20937c478bd9Sstevel@tonic-gate assert(root); 20947c478bd9Sstevel@tonic-gate assert(opt == NULL); 20957c478bd9Sstevel@tonic-gate 20967c478bd9Sstevel@tonic-gate /* 2097986fd29aSsetje * root must belong to a boot archive based OS, 20987c478bd9Sstevel@tonic-gate */ 2099986fd29aSsetje if (!is_boot_archive(root)) { 2100b610f78eSvikram /* 2101b610f78eSvikram * Emit message only if not in context of update_all. 2102b610f78eSvikram * If in update_all, emit only if verbose flag is set. 2103b610f78eSvikram */ 2104b610f78eSvikram if (!bam_update_all || bam_verbose) 2105eb2bd662Svikram bam_print(NOT_ARCHIVE_BOOT, root); 21067c478bd9Sstevel@tonic-gate return (BAM_SUCCESS); 21077c478bd9Sstevel@tonic-gate } 21087c478bd9Sstevel@tonic-gate 21097c478bd9Sstevel@tonic-gate /* 21108c1b6884Sszhou * If smf check is requested when / is writable (can happen 21118c1b6884Sszhou * on first reboot following an upgrade because service 21128c1b6884Sszhou * dependency is messed up), skip the check. 21138c1b6884Sszhou */ 21148c1b6884Sszhou if (bam_smf_check && !bam_root_readonly) 21158c1b6884Sszhou return (BAM_SUCCESS); 21168c1b6884Sszhou 21178c1b6884Sszhou /* 21188c1b6884Sszhou * root must be writable. This check applies to alternate 21198c1b6884Sszhou * root (-R option); bam_root_readonly applies to '/' only. 21207c478bd9Sstevel@tonic-gate */ 212161cb17bdSsetje if (!bam_smf_check && !bam_check && is_readonly(root)) { 21228c1b6884Sszhou if (bam_verbose) 21237c478bd9Sstevel@tonic-gate bam_print(RDONLY_FS, root); 21247c478bd9Sstevel@tonic-gate return (BAM_SUCCESS); 21257c478bd9Sstevel@tonic-gate } 21267c478bd9Sstevel@tonic-gate 21277c478bd9Sstevel@tonic-gate /* 21287c478bd9Sstevel@tonic-gate * Don't generate archive on ramdisk 21297c478bd9Sstevel@tonic-gate */ 21307c478bd9Sstevel@tonic-gate if (is_ramdisk(root)) { 21317c478bd9Sstevel@tonic-gate if (bam_verbose) 21327c478bd9Sstevel@tonic-gate bam_print(SKIP_RAMDISK); 21337c478bd9Sstevel@tonic-gate return (BAM_SUCCESS); 21347c478bd9Sstevel@tonic-gate } 21357c478bd9Sstevel@tonic-gate 21367c478bd9Sstevel@tonic-gate /* 21377c478bd9Sstevel@tonic-gate * Now check if updated is really needed 21387c478bd9Sstevel@tonic-gate */ 21397c478bd9Sstevel@tonic-gate ret = update_required(root); 21407c478bd9Sstevel@tonic-gate 21417c478bd9Sstevel@tonic-gate /* 21427c478bd9Sstevel@tonic-gate * The check command (-n) is *not* a dry run 21437c478bd9Sstevel@tonic-gate * It only checks if the archive is in sync. 21447c478bd9Sstevel@tonic-gate */ 21457c478bd9Sstevel@tonic-gate if (bam_check) { 21467c478bd9Sstevel@tonic-gate bam_exit((ret != 0) ? 1 : 0); 21477c478bd9Sstevel@tonic-gate } 21487c478bd9Sstevel@tonic-gate 21497c478bd9Sstevel@tonic-gate if (ret == 1) { 21507c478bd9Sstevel@tonic-gate /* create the ramdisk */ 21517c478bd9Sstevel@tonic-gate ret = create_ramdisk(root); 21527c478bd9Sstevel@tonic-gate } 2153986fd29aSsetje 2154986fd29aSsetje /* if the archive is updated, save the new stat data */ 2155986fd29aSsetje if (ret == 0 && walk_arg.new_nvlp != NULL) { 2156986fd29aSsetje savenew(root); 2157986fd29aSsetje } 2158986fd29aSsetje 2159986fd29aSsetje clear_walk_args(); 2160986fd29aSsetje 21617c478bd9Sstevel@tonic-gate return (ret); 21627c478bd9Sstevel@tonic-gate } 21637c478bd9Sstevel@tonic-gate 2164963390b4Svikram static error_t 2165963390b4Svikram synchronize_BE_menu(void) 2166fbac2b2bSvikram { 2167fbac2b2bSvikram struct stat sb; 2168963390b4Svikram char cmdline[PATH_MAX]; 2169963390b4Svikram char cksum_line[PATH_MAX]; 2170963390b4Svikram filelist_t flist = {0}; 2171963390b4Svikram char *old_cksum_str; 2172963390b4Svikram char *old_size_str; 2173963390b4Svikram char *old_file; 2174963390b4Svikram char *curr_cksum_str; 2175963390b4Svikram char *curr_size_str; 2176963390b4Svikram char *curr_file; 2177963390b4Svikram FILE *cfp; 2178963390b4Svikram int found; 2179963390b4Svikram int ret; 2180963390b4Svikram const char *fcn = "synchronize_BE_menu()"; 2181fbac2b2bSvikram 2182963390b4Svikram BAM_DPRINTF((D_FUNC_ENTRY0, fcn)); 2183fbac2b2bSvikram 2184963390b4Svikram /* Check if findroot enabled LU BE */ 2185963390b4Svikram if (stat(FINDROOT_INSTALLGRUB, &sb) != 0) { 2186963390b4Svikram BAM_DPRINTF((D_NOT_LU_BE, fcn)); 2187963390b4Svikram return (BAM_SUCCESS); 2188fbac2b2bSvikram } 2189fbac2b2bSvikram 2190963390b4Svikram if (stat(LU_MENU_CKSUM, &sb) != 0) { 2191963390b4Svikram BAM_DPRINTF((D_NO_CKSUM_FILE, fcn, LU_MENU_CKSUM)); 2192963390b4Svikram goto menu_sync; 2193fbac2b2bSvikram } 2194963390b4Svikram 2195963390b4Svikram cfp = fopen(LU_MENU_CKSUM, "r"); 2196963390b4Svikram INJECT_ERROR1("CKSUM_FILE_MISSING", cfp = NULL); 2197963390b4Svikram if (cfp == NULL) { 2198963390b4Svikram bam_error(CANNOT_READ_LU_CKSUM, LU_MENU_CKSUM); 2199963390b4Svikram goto menu_sync; 2200963390b4Svikram } 2201963390b4Svikram BAM_DPRINTF((D_CKSUM_FILE_OPENED, fcn, LU_MENU_CKSUM)); 2202963390b4Svikram 2203963390b4Svikram found = 0; 2204963390b4Svikram while (s_fgets(cksum_line, sizeof (cksum_line), cfp) != NULL) { 2205963390b4Svikram INJECT_ERROR1("MULTIPLE_CKSUM", found = 1); 2206963390b4Svikram if (found) { 2207963390b4Svikram bam_error(MULTIPLE_LU_CKSUM, LU_MENU_CKSUM); 2208963390b4Svikram (void) fclose(cfp); 2209963390b4Svikram goto menu_sync; 2210963390b4Svikram } 2211963390b4Svikram found = 1; 2212963390b4Svikram } 2213963390b4Svikram BAM_DPRINTF((D_CKSUM_FILE_READ, fcn, LU_MENU_CKSUM)); 2214963390b4Svikram 2215963390b4Svikram 2216963390b4Svikram old_cksum_str = strtok(cksum_line, " \t"); 2217963390b4Svikram old_size_str = strtok(NULL, " \t"); 2218963390b4Svikram old_file = strtok(NULL, " \t"); 2219963390b4Svikram 2220963390b4Svikram INJECT_ERROR1("OLD_CKSUM_NULL", old_cksum_str = NULL); 2221963390b4Svikram INJECT_ERROR1("OLD_SIZE_NULL", old_size_str = NULL); 2222963390b4Svikram INJECT_ERROR1("OLD_FILE_NULL", old_file = NULL); 2223963390b4Svikram if (old_cksum_str == NULL || old_size_str == NULL || old_file == NULL) { 2224963390b4Svikram bam_error(CANNOT_PARSE_LU_CKSUM, LU_MENU_CKSUM); 2225963390b4Svikram goto menu_sync; 2226963390b4Svikram } 2227963390b4Svikram BAM_DPRINTF((D_CKSUM_FILE_PARSED, fcn, LU_MENU_CKSUM)); 2228963390b4Svikram 2229963390b4Svikram /* Get checksum of current menu */ 2230963390b4Svikram (void) snprintf(cmdline, sizeof (cmdline), "%s %s", 2231963390b4Svikram CKSUM, GRUB_MENU); 2232963390b4Svikram ret = exec_cmd(cmdline, &flist); 2233963390b4Svikram INJECT_ERROR1("GET_CURR_CKSUM", ret = 1); 2234963390b4Svikram if (ret != 0) { 2235963390b4Svikram bam_error(MENU_CKSUM_FAIL); 2236963390b4Svikram return (BAM_ERROR); 2237963390b4Svikram } 2238963390b4Svikram BAM_DPRINTF((D_CKSUM_GEN_SUCCESS, fcn)); 2239963390b4Svikram 2240963390b4Svikram INJECT_ERROR1("GET_CURR_CKSUM_OUTPUT", flist.head = NULL); 2241963390b4Svikram if ((flist.head == NULL) || (flist.head != flist.tail)) { 2242963390b4Svikram bam_error(BAD_CKSUM); 2243963390b4Svikram filelist_free(&flist); 2244963390b4Svikram return (BAM_ERROR); 2245963390b4Svikram } 2246963390b4Svikram BAM_DPRINTF((D_CKSUM_GEN_OUTPUT_VALID, fcn)); 2247963390b4Svikram 2248963390b4Svikram curr_cksum_str = strtok(flist.head->line, " \t"); 2249963390b4Svikram curr_size_str = strtok(NULL, " \t"); 2250963390b4Svikram curr_file = strtok(NULL, " \t"); 2251963390b4Svikram 2252963390b4Svikram INJECT_ERROR1("CURR_CKSUM_NULL", curr_cksum_str = NULL); 2253963390b4Svikram INJECT_ERROR1("CURR_SIZE_NULL", curr_size_str = NULL); 2254963390b4Svikram INJECT_ERROR1("CURR_FILE_NULL", curr_file = NULL); 2255963390b4Svikram if (curr_cksum_str == NULL || curr_size_str == NULL || 2256963390b4Svikram curr_file == NULL) { 2257963390b4Svikram bam_error(BAD_CKSUM_PARSE); 2258963390b4Svikram filelist_free(&flist); 2259963390b4Svikram return (BAM_ERROR); 2260963390b4Svikram } 2261963390b4Svikram BAM_DPRINTF((D_CKSUM_GEN_PARSED, fcn)); 2262963390b4Svikram 2263963390b4Svikram if (strcmp(old_cksum_str, curr_cksum_str) == 0 && 2264963390b4Svikram strcmp(old_size_str, curr_size_str) == 0 && 2265963390b4Svikram strcmp(old_file, curr_file) == 0) { 2266963390b4Svikram filelist_free(&flist); 2267963390b4Svikram BAM_DPRINTF((D_CKSUM_NO_CHANGE, fcn)); 2268963390b4Svikram return (BAM_SUCCESS); 2269963390b4Svikram } 2270963390b4Svikram 2271963390b4Svikram filelist_free(&flist); 2272963390b4Svikram 2273963390b4Svikram /* cksum doesn't match - the menu has changed */ 2274963390b4Svikram BAM_DPRINTF((D_CKSUM_HAS_CHANGED, fcn)); 2275963390b4Svikram 2276963390b4Svikram menu_sync: 2277963390b4Svikram bam_print(PROP_GRUB_MENU); 2278963390b4Svikram 2279963390b4Svikram (void) snprintf(cmdline, sizeof (cmdline), 2280a6968364Svikram "/bin/sh -c '. %s > /dev/null; %s %s yes > /dev/null'", 2281963390b4Svikram LULIB, LULIB_PROPAGATE_FILE, GRUB_MENU); 2282963390b4Svikram ret = exec_cmd(cmdline, NULL); 2283963390b4Svikram INJECT_ERROR1("PROPAGATE_MENU", ret = 1); 2284963390b4Svikram if (ret != 0) { 2285963390b4Svikram bam_error(MENU_PROP_FAIL); 2286963390b4Svikram return (BAM_ERROR); 2287963390b4Svikram } 2288963390b4Svikram BAM_DPRINTF((D_PROPAGATED_MENU, fcn)); 2289963390b4Svikram 2290a6968364Svikram (void) snprintf(cmdline, sizeof (cmdline), "/bin/cp %s %s > /dev/null", 2291963390b4Svikram GRUB_MENU, GRUB_BACKUP_MENU); 2292963390b4Svikram ret = exec_cmd(cmdline, NULL); 2293963390b4Svikram INJECT_ERROR1("CREATE_BACKUP", ret = 1); 2294963390b4Svikram if (ret != 0) { 2295963390b4Svikram bam_error(MENU_BACKUP_FAIL, GRUB_BACKUP_MENU); 2296963390b4Svikram return (BAM_ERROR); 2297963390b4Svikram } 2298963390b4Svikram BAM_DPRINTF((D_CREATED_BACKUP, fcn, GRUB_BACKUP_MENU)); 2299963390b4Svikram 2300963390b4Svikram (void) snprintf(cmdline, sizeof (cmdline), 2301a6968364Svikram "/bin/sh -c '. %s > /dev/null; %s %s no > /dev/null'", 2302963390b4Svikram LULIB, LULIB_PROPAGATE_FILE, GRUB_BACKUP_MENU); 2303963390b4Svikram ret = exec_cmd(cmdline, NULL); 2304963390b4Svikram INJECT_ERROR1("PROPAGATE_BACKUP", ret = 1); 2305963390b4Svikram if (ret != 0) { 2306963390b4Svikram bam_error(BACKUP_PROP_FAIL, GRUB_BACKUP_MENU); 2307963390b4Svikram return (BAM_ERROR); 2308963390b4Svikram } 2309963390b4Svikram BAM_DPRINTF((D_PROPAGATED_BACKUP, fcn, GRUB_BACKUP_MENU)); 2310963390b4Svikram 2311963390b4Svikram (void) snprintf(cmdline, sizeof (cmdline), "%s %s > %s", 2312963390b4Svikram CKSUM, GRUB_MENU, LU_MENU_CKSUM); 2313963390b4Svikram ret = exec_cmd(cmdline, NULL); 2314963390b4Svikram INJECT_ERROR1("CREATE_CKSUM_FILE", ret = 1); 2315963390b4Svikram if (ret != 0) { 2316963390b4Svikram bam_error(MENU_CKSUM_WRITE_FAIL, LU_MENU_CKSUM); 2317963390b4Svikram return (BAM_ERROR); 2318963390b4Svikram } 2319963390b4Svikram BAM_DPRINTF((D_CREATED_CKSUM_FILE, fcn, LU_MENU_CKSUM)); 2320963390b4Svikram 2321963390b4Svikram (void) snprintf(cmdline, sizeof (cmdline), 2322a6968364Svikram "/bin/sh -c '. %s > /dev/null; %s %s no > /dev/null'", 2323963390b4Svikram LULIB, LULIB_PROPAGATE_FILE, LU_MENU_CKSUM); 2324963390b4Svikram ret = exec_cmd(cmdline, NULL); 2325963390b4Svikram INJECT_ERROR1("PROPAGATE_MENU_CKSUM_FILE", ret = 1); 2326963390b4Svikram if (ret != 0) { 2327963390b4Svikram bam_error(MENU_CKSUM_PROP_FAIL, LU_MENU_CKSUM); 2328963390b4Svikram return (BAM_ERROR); 2329963390b4Svikram } 2330963390b4Svikram BAM_DPRINTF((D_PROPAGATED_CKSUM_FILE, fcn, LU_MENU_CKSUM)); 2331963390b4Svikram 2332963390b4Svikram (void) snprintf(cmdline, sizeof (cmdline), 2333a6968364Svikram "/bin/sh -c '. %s > /dev/null; %s %s no > /dev/null'", 2334963390b4Svikram LULIB, LULIB_PROPAGATE_FILE, BOOTADM); 2335963390b4Svikram ret = exec_cmd(cmdline, NULL); 2336963390b4Svikram INJECT_ERROR1("PROPAGATE_BOOTADM_FILE", ret = 1); 2337963390b4Svikram if (ret != 0) { 2338963390b4Svikram bam_error(BOOTADM_PROP_FAIL, BOOTADM); 2339963390b4Svikram return (BAM_ERROR); 2340963390b4Svikram } 2341963390b4Svikram BAM_DPRINTF((D_PROPAGATED_BOOTADM, fcn, BOOTADM)); 2342963390b4Svikram 2343963390b4Svikram return (BAM_SUCCESS); 2344fbac2b2bSvikram } 2345fbac2b2bSvikram 23467c478bd9Sstevel@tonic-gate static error_t 23477c478bd9Sstevel@tonic-gate update_all(char *root, char *opt) 23487c478bd9Sstevel@tonic-gate { 23497c478bd9Sstevel@tonic-gate struct extmnttab mnt; 23507c478bd9Sstevel@tonic-gate struct stat sb; 23517c478bd9Sstevel@tonic-gate FILE *fp; 23527c478bd9Sstevel@tonic-gate char multibt[PATH_MAX]; 2353986fd29aSsetje char creatram[PATH_MAX]; 23547c478bd9Sstevel@tonic-gate error_t ret = BAM_SUCCESS; 23557c478bd9Sstevel@tonic-gate 235640541d5dSvikram assert(root); 23577c478bd9Sstevel@tonic-gate assert(opt == NULL); 23587c478bd9Sstevel@tonic-gate 235940541d5dSvikram if (bam_rootlen != 1 || *root != '/') { 236040541d5dSvikram elide_trailing_slash(root, multibt, sizeof (multibt)); 236140541d5dSvikram bam_error(ALT_ROOT_INVALID, multibt); 236240541d5dSvikram return (BAM_ERROR); 236340541d5dSvikram } 236440541d5dSvikram 23657c478bd9Sstevel@tonic-gate /* 236698892a30Snadkarni * Check to see if we are in the midst of safemode patching 236798892a30Snadkarni * If so skip building the archive for /. Instead build it 236898892a30Snadkarni * against the latest bits obtained by creating a fresh lofs 236998892a30Snadkarni * mount of root. 237098892a30Snadkarni */ 237198892a30Snadkarni if (stat(LOFS_PATCH_FILE, &sb) == 0) { 237298892a30Snadkarni if (mkdir(LOFS_PATCH_MNT, 0755) == -1 && 237398892a30Snadkarni errno != EEXIST) { 237498892a30Snadkarni bam_error(MKDIR_FAILED, "%s", LOFS_PATCH_MNT, 237598892a30Snadkarni strerror(errno)); 237698892a30Snadkarni ret = BAM_ERROR; 237798892a30Snadkarni goto out; 237898892a30Snadkarni } 237998892a30Snadkarni (void) snprintf(multibt, sizeof (multibt), 238098892a30Snadkarni "/sbin/mount -F lofs -o nosub / %s", LOFS_PATCH_MNT); 2381986fd29aSsetje if (exec_cmd(multibt, NULL) != 0) { 238298892a30Snadkarni bam_error(MOUNT_FAILED, LOFS_PATCH_MNT, "lofs"); 238398892a30Snadkarni ret = BAM_ERROR; 238498892a30Snadkarni } 238598892a30Snadkarni if (ret != BAM_ERROR) { 238698892a30Snadkarni (void) snprintf(rootbuf, sizeof (rootbuf), "%s/", 238798892a30Snadkarni LOFS_PATCH_MNT); 238898892a30Snadkarni bam_rootlen = strlen(rootbuf); 238998892a30Snadkarni if (update_archive(rootbuf, opt) != BAM_SUCCESS) 239098892a30Snadkarni ret = BAM_ERROR; 239195b1e0e9Snadkarni /* 239295b1e0e9Snadkarni * unmount the lofs mount since there could be 239395b1e0e9Snadkarni * multiple invocations of bootadm -a update_all 239495b1e0e9Snadkarni */ 239595b1e0e9Snadkarni (void) snprintf(multibt, sizeof (multibt), 239695b1e0e9Snadkarni "/sbin/umount %s", LOFS_PATCH_MNT); 2397986fd29aSsetje if (exec_cmd(multibt, NULL) != 0) { 239895b1e0e9Snadkarni bam_error(UMOUNT_FAILED, LOFS_PATCH_MNT); 239995b1e0e9Snadkarni ret = BAM_ERROR; 240095b1e0e9Snadkarni } 240198892a30Snadkarni } 240298892a30Snadkarni } else { 240398892a30Snadkarni /* 24047c478bd9Sstevel@tonic-gate * First update archive for current root 24057c478bd9Sstevel@tonic-gate */ 24067c478bd9Sstevel@tonic-gate if (update_archive(root, opt) != BAM_SUCCESS) 24077c478bd9Sstevel@tonic-gate ret = BAM_ERROR; 240898892a30Snadkarni } 240998892a30Snadkarni 241098892a30Snadkarni if (ret == BAM_ERROR) 241198892a30Snadkarni goto out; 24127c478bd9Sstevel@tonic-gate 24137c478bd9Sstevel@tonic-gate /* 24147c478bd9Sstevel@tonic-gate * Now walk the mount table, performing archive update 24157c478bd9Sstevel@tonic-gate * for all mounted Newboot root filesystems 24167c478bd9Sstevel@tonic-gate */ 24177c478bd9Sstevel@tonic-gate fp = fopen(MNTTAB, "r"); 24187c478bd9Sstevel@tonic-gate if (fp == NULL) { 24197c478bd9Sstevel@tonic-gate bam_error(OPEN_FAIL, MNTTAB, strerror(errno)); 2420b610f78eSvikram ret = BAM_ERROR; 2421b610f78eSvikram goto out; 24227c478bd9Sstevel@tonic-gate } 24237c478bd9Sstevel@tonic-gate 24247c478bd9Sstevel@tonic-gate resetmnttab(fp); 24257c478bd9Sstevel@tonic-gate 24267c478bd9Sstevel@tonic-gate while (getextmntent(fp, &mnt, sizeof (mnt)) == 0) { 24277c478bd9Sstevel@tonic-gate if (mnt.mnt_special == NULL) 24287c478bd9Sstevel@tonic-gate continue; 2429f904d32dSJerry Gilliam if ((strcmp(mnt.mnt_fstype, MNTTYPE_ZFS) != 0) && 2430f904d32dSJerry Gilliam (strncmp(mnt.mnt_special, "/dev/", strlen("/dev/")) != 0)) 24317c478bd9Sstevel@tonic-gate continue; 24327c478bd9Sstevel@tonic-gate if (strcmp(mnt.mnt_mountp, "/") == 0) 24337c478bd9Sstevel@tonic-gate continue; 24347c478bd9Sstevel@tonic-gate 2435986fd29aSsetje (void) snprintf(creatram, sizeof (creatram), "%s/%s", 2436986fd29aSsetje mnt.mnt_mountp, CREATE_RAMDISK); 24377c478bd9Sstevel@tonic-gate 2438986fd29aSsetje if (stat(creatram, &sb) == -1) 24397c478bd9Sstevel@tonic-gate continue; 24407c478bd9Sstevel@tonic-gate 24417c478bd9Sstevel@tonic-gate /* 24427c478bd9Sstevel@tonic-gate * We put a trailing slash to be consistent with root = "/" 24437c478bd9Sstevel@tonic-gate * case, such that we don't have to print // in some cases. 24447c478bd9Sstevel@tonic-gate */ 24457c478bd9Sstevel@tonic-gate (void) snprintf(rootbuf, sizeof (rootbuf), "%s/", 24467c478bd9Sstevel@tonic-gate mnt.mnt_mountp); 24477c478bd9Sstevel@tonic-gate bam_rootlen = strlen(rootbuf); 2448ae115bc7Smrj 2449ae115bc7Smrj /* 2450ae115bc7Smrj * It's possible that other mounts may be an alternate boot 2451ae115bc7Smrj * architecture, so check it again. 2452ae115bc7Smrj */ 2453eb2bd662Svikram if ((get_boot_cap(rootbuf) != BAM_SUCCESS) || 2454ae115bc7Smrj (update_archive(rootbuf, opt) != BAM_SUCCESS)) 24557c478bd9Sstevel@tonic-gate ret = BAM_ERROR; 24567c478bd9Sstevel@tonic-gate } 24577c478bd9Sstevel@tonic-gate 24587c478bd9Sstevel@tonic-gate (void) fclose(fp); 24597c478bd9Sstevel@tonic-gate 2460b610f78eSvikram out: 2461fbac2b2bSvikram /* 2462963390b4Svikram * We no longer use biosdev for Live Upgrade. Hence 2463963390b4Svikram * there is no need to defer (to shutdown time) any fdisk 2464963390b4Svikram * updates 2465fbac2b2bSvikram */ 2466963390b4Svikram if (stat(GRUB_fdisk, &sb) == 0 || stat(GRUB_fdisk_target, &sb) == 0) { 2467963390b4Svikram bam_error(FDISK_FILES_FOUND, GRUB_fdisk, GRUB_fdisk_target); 2468fbac2b2bSvikram } 2469fbac2b2bSvikram 2470963390b4Svikram /* 2471963390b4Svikram * If user has updated menu in current BE, propagate the 2472963390b4Svikram * updates to all BEs. 2473963390b4Svikram */ 2474*19397407SSherry Moore if (sync_menu && synchronize_BE_menu() != BAM_SUCCESS) 2475963390b4Svikram ret = BAM_ERROR; 2476963390b4Svikram 24777c478bd9Sstevel@tonic-gate return (ret); 24787c478bd9Sstevel@tonic-gate } 24797c478bd9Sstevel@tonic-gate 24807c478bd9Sstevel@tonic-gate static void 24817c478bd9Sstevel@tonic-gate append_line(menu_t *mp, line_t *lp) 24827c478bd9Sstevel@tonic-gate { 24837c478bd9Sstevel@tonic-gate if (mp->start == NULL) { 24847c478bd9Sstevel@tonic-gate mp->start = lp; 24857c478bd9Sstevel@tonic-gate } else { 24867c478bd9Sstevel@tonic-gate mp->end->next = lp; 24878c1b6884Sszhou lp->prev = mp->end; 24887c478bd9Sstevel@tonic-gate } 24897c478bd9Sstevel@tonic-gate mp->end = lp; 24907c478bd9Sstevel@tonic-gate } 24917c478bd9Sstevel@tonic-gate 2492eb2bd662Svikram void 24938c1b6884Sszhou unlink_line(menu_t *mp, line_t *lp) 24948c1b6884Sszhou { 24958c1b6884Sszhou /* unlink from list */ 24968c1b6884Sszhou if (lp->prev) 24978c1b6884Sszhou lp->prev->next = lp->next; 24988c1b6884Sszhou else 24998c1b6884Sszhou mp->start = lp->next; 25008c1b6884Sszhou if (lp->next) 25018c1b6884Sszhou lp->next->prev = lp->prev; 25028c1b6884Sszhou else 25038c1b6884Sszhou mp->end = lp->prev; 25048c1b6884Sszhou } 25058c1b6884Sszhou 25068c1b6884Sszhou static entry_t * 25078c1b6884Sszhou boot_entry_new(menu_t *mp, line_t *start, line_t *end) 25088c1b6884Sszhou { 25098c1b6884Sszhou entry_t *ent, *prev; 2510eb2bd662Svikram const char *fcn = "boot_entry_new()"; 2511eb2bd662Svikram 2512eb2bd662Svikram assert(mp); 2513eb2bd662Svikram assert(start); 2514eb2bd662Svikram assert(end); 25158c1b6884Sszhou 25168c1b6884Sszhou ent = s_calloc(1, sizeof (entry_t)); 2517eb2bd662Svikram BAM_DPRINTF((D_ENTRY_NEW, fcn)); 25188c1b6884Sszhou ent->start = start; 25198c1b6884Sszhou ent->end = end; 25208c1b6884Sszhou 25218c1b6884Sszhou if (mp->entries == NULL) { 25228c1b6884Sszhou mp->entries = ent; 2523eb2bd662Svikram BAM_DPRINTF((D_ENTRY_NEW_FIRST, fcn)); 25248c1b6884Sszhou return (ent); 25258c1b6884Sszhou } 25268c1b6884Sszhou 25278c1b6884Sszhou prev = mp->entries; 25288c1b6884Sszhou while (prev->next) 25298c1b6884Sszhou prev = prev->next; 25308c1b6884Sszhou prev->next = ent; 25318c1b6884Sszhou ent->prev = prev; 2532eb2bd662Svikram BAM_DPRINTF((D_ENTRY_NEW_LINKED, fcn)); 25338c1b6884Sszhou return (ent); 25348c1b6884Sszhou } 25358c1b6884Sszhou 25368c1b6884Sszhou static void 25378c1b6884Sszhou boot_entry_addline(entry_t *ent, line_t *lp) 25388c1b6884Sszhou { 25398c1b6884Sszhou if (ent) 25408c1b6884Sszhou ent->end = lp; 25418c1b6884Sszhou } 25428c1b6884Sszhou 25437c478bd9Sstevel@tonic-gate /* 2544843e1988Sjohnlev * Check whether cmd matches the one indexed by which, and whether arg matches 2545843e1988Sjohnlev * str. which must be either KERNEL_CMD or MODULE_CMD, and a match to the 2546843e1988Sjohnlev * respective *_DOLLAR_CMD is also acceptable. The arg is searched using 2547843e1988Sjohnlev * strstr(), so it can be a partial match. 2548843e1988Sjohnlev */ 2549843e1988Sjohnlev static int 2550843e1988Sjohnlev check_cmd(const char *cmd, const int which, const char *arg, const char *str) 2551843e1988Sjohnlev { 2552eb2bd662Svikram int ret; 2553eb2bd662Svikram const char *fcn = "check_cmd()"; 2554eb2bd662Svikram 2555eb2bd662Svikram BAM_DPRINTF((D_FUNC_ENTRY2, fcn, arg, str)); 2556eb2bd662Svikram 2557843e1988Sjohnlev if ((strcmp(cmd, menu_cmds[which]) != 0) && 2558843e1988Sjohnlev (strcmp(cmd, menu_cmds[which + 1]) != 0)) { 2559eb2bd662Svikram BAM_DPRINTF((D_CHECK_CMD_CMD_NOMATCH, 2560eb2bd662Svikram fcn, cmd, menu_cmds[which])); 2561843e1988Sjohnlev return (0); 2562843e1988Sjohnlev } 2563eb2bd662Svikram ret = (strstr(arg, str) != NULL); 2564eb2bd662Svikram 2565eb2bd662Svikram if (ret) { 2566eb2bd662Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 2567eb2bd662Svikram } else { 2568eb2bd662Svikram BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 2569eb2bd662Svikram } 2570eb2bd662Svikram 2571eb2bd662Svikram return (ret); 2572eb2bd662Svikram } 2573eb2bd662Svikram 2574eb2bd662Svikram static error_t 2575eb2bd662Svikram kernel_parser(entry_t *entry, char *cmd, char *arg, int linenum) 2576eb2bd662Svikram { 2577eb2bd662Svikram const char *fcn = "kernel_parser()"; 2578eb2bd662Svikram 2579eb2bd662Svikram assert(entry); 2580eb2bd662Svikram assert(cmd); 2581eb2bd662Svikram assert(arg); 2582eb2bd662Svikram 2583eb2bd662Svikram if (strcmp(cmd, menu_cmds[KERNEL_CMD]) != 0 && 2584eb2bd662Svikram strcmp(cmd, menu_cmds[KERNEL_DOLLAR_CMD]) != 0) { 2585eb2bd662Svikram BAM_DPRINTF((D_NOT_KERNEL_CMD, fcn, cmd)); 2586eb2bd662Svikram return (BAM_ERROR); 2587eb2bd662Svikram } 2588eb2bd662Svikram 2589eb2bd662Svikram if (strncmp(arg, DIRECT_BOOT_32, sizeof (DIRECT_BOOT_32) - 1) == 0) { 2590eb2bd662Svikram BAM_DPRINTF((D_SET_DBOOT_32, fcn, arg)); 2591eb2bd662Svikram entry->flags |= BAM_ENTRY_DBOOT | BAM_ENTRY_32BIT; 2592eb2bd662Svikram } else if (strncmp(arg, DIRECT_BOOT_KERNEL, 2593eb2bd662Svikram sizeof (DIRECT_BOOT_KERNEL) - 1) == 0) { 2594eb2bd662Svikram BAM_DPRINTF((D_SET_DBOOT, fcn, arg)); 2595eb2bd662Svikram entry->flags |= BAM_ENTRY_DBOOT; 2596eb2bd662Svikram } else if (strncmp(arg, DIRECT_BOOT_64, 2597eb2bd662Svikram sizeof (DIRECT_BOOT_64) - 1) == 0) { 2598eb2bd662Svikram BAM_DPRINTF((D_SET_DBOOT_64, fcn, arg)); 2599eb2bd662Svikram entry->flags |= BAM_ENTRY_DBOOT | BAM_ENTRY_64BIT; 2600eb2bd662Svikram } else if (strncmp(arg, DIRECT_BOOT_FAILSAFE_KERNEL, 2601eb2bd662Svikram sizeof (DIRECT_BOOT_FAILSAFE_KERNEL) - 1) == 0) { 2602eb2bd662Svikram BAM_DPRINTF((D_SET_DBOOT_FAILSAFE, fcn, arg)); 2603eb2bd662Svikram entry->flags |= BAM_ENTRY_DBOOT | BAM_ENTRY_FAILSAFE; 2604eb2bd662Svikram } else if (strncmp(arg, MULTI_BOOT, sizeof (MULTI_BOOT) - 1) == 0) { 2605eb2bd662Svikram BAM_DPRINTF((D_SET_MULTIBOOT, fcn, arg)); 2606eb2bd662Svikram entry->flags |= BAM_ENTRY_MULTIBOOT; 2607eb2bd662Svikram } else if (strncmp(arg, MULTI_BOOT_FAILSAFE, 2608eb2bd662Svikram sizeof (MULTI_BOOT_FAILSAFE) - 1) == 0) { 2609eb2bd662Svikram BAM_DPRINTF((D_SET_MULTIBOOT_FAILSAFE, fcn, arg)); 2610eb2bd662Svikram entry->flags |= BAM_ENTRY_MULTIBOOT | BAM_ENTRY_FAILSAFE; 2611eb2bd662Svikram } else if (strstr(arg, XEN_KERNEL_SUBSTR)) { 2612eb2bd662Svikram BAM_DPRINTF((D_SET_HV, fcn, arg)); 2613eb2bd662Svikram entry->flags |= BAM_ENTRY_HV; 2614eb2bd662Svikram } else if (!(entry->flags & (BAM_ENTRY_BOOTADM|BAM_ENTRY_LU))) { 2615eb2bd662Svikram BAM_DPRINTF((D_SET_HAND_KERNEL, fcn, arg)); 2616eb2bd662Svikram return (BAM_ERROR); 2617eb2bd662Svikram } else { 2618eb2bd662Svikram BAM_DPRINTF((D_IS_UNKNOWN_KERNEL, fcn, arg)); 2619eb2bd662Svikram bam_error(UNKNOWN_KERNEL_LINE, linenum); 2620eb2bd662Svikram return (BAM_ERROR); 2621eb2bd662Svikram } 2622eb2bd662Svikram 2623eb2bd662Svikram return (BAM_SUCCESS); 2624eb2bd662Svikram } 2625eb2bd662Svikram 2626eb2bd662Svikram static error_t 2627eb2bd662Svikram module_parser(entry_t *entry, char *cmd, char *arg, int linenum) 2628eb2bd662Svikram { 2629eb2bd662Svikram const char *fcn = "module_parser()"; 2630eb2bd662Svikram 2631eb2bd662Svikram assert(entry); 2632eb2bd662Svikram assert(cmd); 2633eb2bd662Svikram assert(arg); 2634eb2bd662Svikram 2635eb2bd662Svikram if (strcmp(cmd, menu_cmds[MODULE_CMD]) != 0 && 2636eb2bd662Svikram strcmp(cmd, menu_cmds[MODULE_DOLLAR_CMD]) != 0) { 2637eb2bd662Svikram BAM_DPRINTF((D_NOT_MODULE_CMD, fcn, cmd)); 2638eb2bd662Svikram return (BAM_ERROR); 2639eb2bd662Svikram } 2640eb2bd662Svikram 2641eb2bd662Svikram if (strcmp(arg, DIRECT_BOOT_ARCHIVE) == 0 || 2642eb2bd662Svikram strcmp(arg, DIRECT_BOOT_ARCHIVE_32) == 0 || 2643eb2bd662Svikram strcmp(arg, DIRECT_BOOT_ARCHIVE_64) == 0 || 2644eb2bd662Svikram strcmp(arg, MULTIBOOT_ARCHIVE) == 0 || 2645eb2bd662Svikram strcmp(arg, FAILSAFE_ARCHIVE) == 0 || 2646eb2bd662Svikram strcmp(arg, XEN_KERNEL_MODULE_LINE) == 0 || 2647eb2bd662Svikram strcmp(arg, XEN_KERNEL_MODULE_LINE_ZFS) == 0) { 2648eb2bd662Svikram BAM_DPRINTF((D_BOOTADM_LU_MODULE, fcn, arg)); 2649eb2bd662Svikram return (BAM_SUCCESS); 2650eb2bd662Svikram } else if (!(entry->flags & BAM_ENTRY_BOOTADM) && 2651eb2bd662Svikram !(entry->flags & BAM_ENTRY_LU)) { 2652eb2bd662Svikram /* don't emit warning for hand entries */ 2653eb2bd662Svikram BAM_DPRINTF((D_IS_HAND_MODULE, fcn, arg)); 2654eb2bd662Svikram return (BAM_ERROR); 2655eb2bd662Svikram } else { 2656eb2bd662Svikram BAM_DPRINTF((D_IS_UNKNOWN_MODULE, fcn, arg)); 2657eb2bd662Svikram bam_error(UNKNOWN_MODULE_LINE, linenum); 2658eb2bd662Svikram return (BAM_ERROR); 2659eb2bd662Svikram } 2660843e1988Sjohnlev } 2661843e1988Sjohnlev 2662843e1988Sjohnlev /* 26637c478bd9Sstevel@tonic-gate * A line in menu.lst looks like 26647c478bd9Sstevel@tonic-gate * [ ]*<cmd>[ \t=]*<arg>* 26657c478bd9Sstevel@tonic-gate */ 26667c478bd9Sstevel@tonic-gate static void 26677c478bd9Sstevel@tonic-gate line_parser(menu_t *mp, char *str, int *lineNum, int *entryNum) 26687c478bd9Sstevel@tonic-gate { 26697c478bd9Sstevel@tonic-gate /* 26707c478bd9Sstevel@tonic-gate * save state across calls. This is so that 26717c478bd9Sstevel@tonic-gate * header gets the right entry# after title has 26727c478bd9Sstevel@tonic-gate * been processed 26737c478bd9Sstevel@tonic-gate */ 26748c1b6884Sszhou static line_t *prev = NULL; 26758c1b6884Sszhou static entry_t *curr_ent = NULL; 2676ae115bc7Smrj static int in_liveupgrade = 0; 26777c478bd9Sstevel@tonic-gate 26787c478bd9Sstevel@tonic-gate line_t *lp; 26797c478bd9Sstevel@tonic-gate char *cmd, *sep, *arg; 26807c478bd9Sstevel@tonic-gate char save, *cp, *line; 26817c478bd9Sstevel@tonic-gate menu_flag_t flag = BAM_INVALID; 2682eb2bd662Svikram const char *fcn = "line_parser()"; 26837c478bd9Sstevel@tonic-gate 26847c478bd9Sstevel@tonic-gate if (str == NULL) { 26857c478bd9Sstevel@tonic-gate return; 26867c478bd9Sstevel@tonic-gate } 26877c478bd9Sstevel@tonic-gate 26887c478bd9Sstevel@tonic-gate /* 26897c478bd9Sstevel@tonic-gate * First save a copy of the entire line. 26907c478bd9Sstevel@tonic-gate * We use this later to set the line field. 26917c478bd9Sstevel@tonic-gate */ 26927c478bd9Sstevel@tonic-gate line = s_strdup(str); 26937c478bd9Sstevel@tonic-gate 26947c478bd9Sstevel@tonic-gate /* Eat up leading whitespace */ 26957c478bd9Sstevel@tonic-gate while (*str == ' ' || *str == '\t') 26967c478bd9Sstevel@tonic-gate str++; 26977c478bd9Sstevel@tonic-gate 26987c478bd9Sstevel@tonic-gate if (*str == '#') { /* comment */ 26997c478bd9Sstevel@tonic-gate cmd = s_strdup("#"); 27007c478bd9Sstevel@tonic-gate sep = NULL; 27017c478bd9Sstevel@tonic-gate arg = s_strdup(str + 1); 27027c478bd9Sstevel@tonic-gate flag = BAM_COMMENT; 2703ae115bc7Smrj if (strstr(arg, BAM_LU_HDR) != NULL) { 2704ae115bc7Smrj in_liveupgrade = 1; 2705ae115bc7Smrj } else if (strstr(arg, BAM_LU_FTR) != NULL) { 2706ae115bc7Smrj in_liveupgrade = 0; 2707ae115bc7Smrj } 27087c478bd9Sstevel@tonic-gate } else if (*str == '\0') { /* blank line */ 27097c478bd9Sstevel@tonic-gate cmd = sep = arg = NULL; 27107c478bd9Sstevel@tonic-gate flag = BAM_EMPTY; 27117c478bd9Sstevel@tonic-gate } else { 27127c478bd9Sstevel@tonic-gate /* 27137c478bd9Sstevel@tonic-gate * '=' is not a documented separator in grub syntax. 27147c478bd9Sstevel@tonic-gate * However various development bits use '=' as a 27157c478bd9Sstevel@tonic-gate * separator. In addition, external users also 27167c478bd9Sstevel@tonic-gate * use = as a separator. So we will allow that usage. 27177c478bd9Sstevel@tonic-gate */ 27187c478bd9Sstevel@tonic-gate cp = str; 27197c478bd9Sstevel@tonic-gate while (*str != ' ' && *str != '\t' && *str != '=') { 27207c478bd9Sstevel@tonic-gate if (*str == '\0') { 27217c478bd9Sstevel@tonic-gate cmd = s_strdup(cp); 27227c478bd9Sstevel@tonic-gate sep = arg = NULL; 27237c478bd9Sstevel@tonic-gate break; 27247c478bd9Sstevel@tonic-gate } 27257c478bd9Sstevel@tonic-gate str++; 27267c478bd9Sstevel@tonic-gate } 27277c478bd9Sstevel@tonic-gate 27287c478bd9Sstevel@tonic-gate if (*str != '\0') { 27297c478bd9Sstevel@tonic-gate save = *str; 27307c478bd9Sstevel@tonic-gate *str = '\0'; 27317c478bd9Sstevel@tonic-gate cmd = s_strdup(cp); 27327c478bd9Sstevel@tonic-gate *str = save; 27337c478bd9Sstevel@tonic-gate 27347c478bd9Sstevel@tonic-gate str++; 27357c478bd9Sstevel@tonic-gate save = *str; 27367c478bd9Sstevel@tonic-gate *str = '\0'; 27377c478bd9Sstevel@tonic-gate sep = s_strdup(str - 1); 27387c478bd9Sstevel@tonic-gate *str = save; 27397c478bd9Sstevel@tonic-gate 27407c478bd9Sstevel@tonic-gate while (*str == ' ' || *str == '\t') 27417c478bd9Sstevel@tonic-gate str++; 27427c478bd9Sstevel@tonic-gate if (*str == '\0') 27437c478bd9Sstevel@tonic-gate arg = NULL; 27447c478bd9Sstevel@tonic-gate else 27457c478bd9Sstevel@tonic-gate arg = s_strdup(str); 27467c478bd9Sstevel@tonic-gate } 27477c478bd9Sstevel@tonic-gate } 27487c478bd9Sstevel@tonic-gate 27497c478bd9Sstevel@tonic-gate lp = s_calloc(1, sizeof (line_t)); 27507c478bd9Sstevel@tonic-gate 27517c478bd9Sstevel@tonic-gate lp->cmd = cmd; 27527c478bd9Sstevel@tonic-gate lp->sep = sep; 27537c478bd9Sstevel@tonic-gate lp->arg = arg; 27547c478bd9Sstevel@tonic-gate lp->line = line; 27557c478bd9Sstevel@tonic-gate lp->lineNum = ++(*lineNum); 27567c478bd9Sstevel@tonic-gate if (cmd && strcmp(cmd, menu_cmds[TITLE_CMD]) == 0) { 27577c478bd9Sstevel@tonic-gate lp->entryNum = ++(*entryNum); 27587c478bd9Sstevel@tonic-gate lp->flags = BAM_TITLE; 27597c478bd9Sstevel@tonic-gate if (prev && prev->flags == BAM_COMMENT && 2760ae115bc7Smrj prev->arg && strcmp(prev->arg, BAM_BOOTADM_HDR) == 0) { 27617c478bd9Sstevel@tonic-gate prev->entryNum = lp->entryNum; 27628c1b6884Sszhou curr_ent = boot_entry_new(mp, prev, lp); 2763eb2bd662Svikram curr_ent->flags |= BAM_ENTRY_BOOTADM; 2764eb2bd662Svikram BAM_DPRINTF((D_IS_BOOTADM_ENTRY, fcn, arg)); 27658c1b6884Sszhou } else { 27668c1b6884Sszhou curr_ent = boot_entry_new(mp, lp, lp); 2767ae115bc7Smrj if (in_liveupgrade) { 2768eb2bd662Svikram curr_ent->flags |= BAM_ENTRY_LU; 2769eb2bd662Svikram BAM_DPRINTF((D_IS_LU_ENTRY, fcn, arg)); 27708c1b6884Sszhou } 2771ae115bc7Smrj } 2772ae115bc7Smrj curr_ent->entryNum = *entryNum; 27737c478bd9Sstevel@tonic-gate } else if (flag != BAM_INVALID) { 27747c478bd9Sstevel@tonic-gate /* 27757c478bd9Sstevel@tonic-gate * For header comments, the entry# is "fixed up" 27767c478bd9Sstevel@tonic-gate * by the subsequent title 27777c478bd9Sstevel@tonic-gate */ 27787c478bd9Sstevel@tonic-gate lp->entryNum = *entryNum; 27797c478bd9Sstevel@tonic-gate lp->flags = flag; 27807c478bd9Sstevel@tonic-gate } else { 27817c478bd9Sstevel@tonic-gate lp->entryNum = *entryNum; 2782ae115bc7Smrj 2783ae115bc7Smrj if (*entryNum == ENTRY_INIT) { 2784ae115bc7Smrj lp->flags = BAM_GLOBAL; 2785ae115bc7Smrj } else { 2786ae115bc7Smrj lp->flags = BAM_ENTRY; 2787ae115bc7Smrj 2788ae115bc7Smrj if (cmd && arg) { 2789eb2bd662Svikram if (strcmp(cmd, menu_cmds[ROOT_CMD]) == 0) { 2790eb2bd662Svikram BAM_DPRINTF((D_IS_ROOT_CMD, fcn, arg)); 2791ae115bc7Smrj curr_ent->flags |= BAM_ENTRY_ROOT; 2792eb2bd662Svikram } else if (strcmp(cmd, menu_cmds[FINDROOT_CMD]) 2793eb2bd662Svikram == 0) { 2794eb2bd662Svikram BAM_DPRINTF((D_IS_FINDROOT_CMD, fcn, 2795eb2bd662Svikram arg)); 2796eb2bd662Svikram curr_ent->flags |= BAM_ENTRY_FINDROOT; 2797eb2bd662Svikram } else if (strcmp(cmd, 2798eb2bd662Svikram menu_cmds[CHAINLOADER_CMD]) == 0) { 2799eb2bd662Svikram BAM_DPRINTF((D_IS_CHAINLOADER_CMD, fcn, 2800eb2bd662Svikram arg)); 2801ae115bc7Smrj curr_ent->flags |= 2802ae115bc7Smrj BAM_ENTRY_CHAINLOADER; 2803eb2bd662Svikram } else if (kernel_parser(curr_ent, cmd, arg, 2804eb2bd662Svikram lp->lineNum) != BAM_SUCCESS) { 2805eb2bd662Svikram (void) module_parser(curr_ent, cmd, 2806eb2bd662Svikram arg, lp->lineNum); 2807eb2bd662Svikram } 2808ae115bc7Smrj } 2809ae115bc7Smrj } 28107c478bd9Sstevel@tonic-gate } 28117c478bd9Sstevel@tonic-gate 28128c1b6884Sszhou /* record default, old default, and entry line ranges */ 28138c1b6884Sszhou if (lp->flags == BAM_GLOBAL && 28148c1b6884Sszhou strcmp(lp->cmd, menu_cmds[DEFAULT_CMD]) == 0) { 28158c1b6884Sszhou mp->curdefault = lp; 28168c1b6884Sszhou } else if (lp->flags == BAM_COMMENT && 28178c1b6884Sszhou strncmp(lp->arg, BAM_OLDDEF, strlen(BAM_OLDDEF)) == 0) { 28188c1b6884Sszhou mp->olddefault = lp; 2819ae115bc7Smrj } else if (lp->flags == BAM_COMMENT && 2820ae115bc7Smrj strncmp(lp->arg, BAM_OLD_RC_DEF, strlen(BAM_OLD_RC_DEF)) == 0) { 2821ae115bc7Smrj mp->old_rc_default = lp; 28228c1b6884Sszhou } else if (lp->flags == BAM_ENTRY || 2823ae115bc7Smrj (lp->flags == BAM_COMMENT && 2824ae115bc7Smrj strcmp(lp->arg, BAM_BOOTADM_FTR) == 0)) { 28258c1b6884Sszhou boot_entry_addline(curr_ent, lp); 28268c1b6884Sszhou } 28277c478bd9Sstevel@tonic-gate append_line(mp, lp); 28287c478bd9Sstevel@tonic-gate 28297c478bd9Sstevel@tonic-gate prev = lp; 28307c478bd9Sstevel@tonic-gate } 28317c478bd9Sstevel@tonic-gate 2832eb2bd662Svikram void 283340541d5dSvikram update_numbering(menu_t *mp) 283440541d5dSvikram { 283540541d5dSvikram int lineNum; 283640541d5dSvikram int entryNum; 283740541d5dSvikram int old_default_value; 283840541d5dSvikram line_t *lp, *prev, *default_lp, *default_entry; 283940541d5dSvikram char buf[PATH_MAX]; 284040541d5dSvikram 284140541d5dSvikram if (mp->start == NULL) { 284240541d5dSvikram return; 284340541d5dSvikram } 284440541d5dSvikram 284540541d5dSvikram lineNum = LINE_INIT; 284640541d5dSvikram entryNum = ENTRY_INIT; 284740541d5dSvikram old_default_value = ENTRY_INIT; 284840541d5dSvikram lp = default_lp = default_entry = NULL; 284940541d5dSvikram 285040541d5dSvikram prev = NULL; 285140541d5dSvikram for (lp = mp->start; lp; prev = lp, lp = lp->next) { 285240541d5dSvikram lp->lineNum = ++lineNum; 285340541d5dSvikram 285440541d5dSvikram /* 285540541d5dSvikram * Get the value of the default command 285640541d5dSvikram */ 285740541d5dSvikram if (lp->entryNum == ENTRY_INIT && lp->cmd && 285840541d5dSvikram strcmp(lp->cmd, menu_cmds[DEFAULT_CMD]) == 0 && 285940541d5dSvikram lp->arg) { 286040541d5dSvikram old_default_value = atoi(lp->arg); 286140541d5dSvikram default_lp = lp; 286240541d5dSvikram } 286340541d5dSvikram 286440541d5dSvikram /* 2865eb2bd662Svikram * If not a booting entry, nothing else to fix for this 286640541d5dSvikram * entry 286740541d5dSvikram */ 286840541d5dSvikram if (lp->entryNum == ENTRY_INIT) 286940541d5dSvikram continue; 287040541d5dSvikram 287140541d5dSvikram /* 287240541d5dSvikram * Record the position of the default entry. 287340541d5dSvikram * The following works because global 287440541d5dSvikram * commands like default and timeout should precede 287540541d5dSvikram * actual boot entries, so old_default_value 287640541d5dSvikram * is already known (or default cmd is missing). 287740541d5dSvikram */ 287840541d5dSvikram if (default_entry == NULL && 287940541d5dSvikram old_default_value != ENTRY_INIT && 288040541d5dSvikram lp->entryNum == old_default_value) { 288140541d5dSvikram default_entry = lp; 288240541d5dSvikram } 288340541d5dSvikram 288440541d5dSvikram /* 288540541d5dSvikram * Now fixup the entry number 288640541d5dSvikram */ 288740541d5dSvikram if (lp->cmd && strcmp(lp->cmd, menu_cmds[TITLE_CMD]) == 0) { 288840541d5dSvikram lp->entryNum = ++entryNum; 288940541d5dSvikram /* fixup the bootadm header */ 289040541d5dSvikram if (prev && prev->flags == BAM_COMMENT && 2891ae115bc7Smrj prev->arg && 2892ae115bc7Smrj strcmp(prev->arg, BAM_BOOTADM_HDR) == 0) { 289340541d5dSvikram prev->entryNum = lp->entryNum; 289440541d5dSvikram } 289540541d5dSvikram } else { 289640541d5dSvikram lp->entryNum = entryNum; 289740541d5dSvikram } 289840541d5dSvikram } 289940541d5dSvikram 290040541d5dSvikram /* 290140541d5dSvikram * No default command in menu, simply return 290240541d5dSvikram */ 290340541d5dSvikram if (default_lp == NULL) { 290440541d5dSvikram return; 290540541d5dSvikram } 290640541d5dSvikram 290740541d5dSvikram free(default_lp->arg); 290840541d5dSvikram free(default_lp->line); 290940541d5dSvikram 291040541d5dSvikram if (default_entry == NULL) { 291140541d5dSvikram default_lp->arg = s_strdup("0"); 291240541d5dSvikram } else { 291340541d5dSvikram (void) snprintf(buf, sizeof (buf), "%d", 291440541d5dSvikram default_entry->entryNum); 291540541d5dSvikram default_lp->arg = s_strdup(buf); 291640541d5dSvikram } 291740541d5dSvikram 291840541d5dSvikram /* 291940541d5dSvikram * The following is required since only the line field gets 292040541d5dSvikram * written back to menu.lst 292140541d5dSvikram */ 292240541d5dSvikram (void) snprintf(buf, sizeof (buf), "%s%s%s", 292340541d5dSvikram menu_cmds[DEFAULT_CMD], menu_cmds[SEP_CMD], default_lp->arg); 292440541d5dSvikram default_lp->line = s_strdup(buf); 292540541d5dSvikram } 292640541d5dSvikram 292740541d5dSvikram 29287c478bd9Sstevel@tonic-gate static menu_t * 29297c478bd9Sstevel@tonic-gate menu_read(char *menu_path) 29307c478bd9Sstevel@tonic-gate { 29317c478bd9Sstevel@tonic-gate FILE *fp; 29327c478bd9Sstevel@tonic-gate char buf[BAM_MAXLINE], *cp; 29337c478bd9Sstevel@tonic-gate menu_t *mp; 29347c478bd9Sstevel@tonic-gate int line, entry, len, n; 29357c478bd9Sstevel@tonic-gate 29367c478bd9Sstevel@tonic-gate mp = s_calloc(1, sizeof (menu_t)); 29377c478bd9Sstevel@tonic-gate 29387c478bd9Sstevel@tonic-gate fp = fopen(menu_path, "r"); 29397c478bd9Sstevel@tonic-gate if (fp == NULL) { /* Let the caller handle this error */ 29407c478bd9Sstevel@tonic-gate return (mp); 29417c478bd9Sstevel@tonic-gate } 29427c478bd9Sstevel@tonic-gate 29437c478bd9Sstevel@tonic-gate 29447c478bd9Sstevel@tonic-gate /* Note: GRUB boot entry number starts with 0 */ 29457c478bd9Sstevel@tonic-gate line = LINE_INIT; 29467c478bd9Sstevel@tonic-gate entry = ENTRY_INIT; 29477c478bd9Sstevel@tonic-gate cp = buf; 29487c478bd9Sstevel@tonic-gate len = sizeof (buf); 29497c478bd9Sstevel@tonic-gate while (s_fgets(cp, len, fp) != NULL) { 29507c478bd9Sstevel@tonic-gate n = strlen(cp); 29517c478bd9Sstevel@tonic-gate if (cp[n - 1] == '\\') { 29527c478bd9Sstevel@tonic-gate len -= n - 1; 29537c478bd9Sstevel@tonic-gate assert(len >= 2); 29547c478bd9Sstevel@tonic-gate cp += n - 1; 29557c478bd9Sstevel@tonic-gate continue; 29567c478bd9Sstevel@tonic-gate } 29577c478bd9Sstevel@tonic-gate line_parser(mp, buf, &line, &entry); 29587c478bd9Sstevel@tonic-gate cp = buf; 29597c478bd9Sstevel@tonic-gate len = sizeof (buf); 29607c478bd9Sstevel@tonic-gate } 29617c478bd9Sstevel@tonic-gate 29627c478bd9Sstevel@tonic-gate if (fclose(fp) == EOF) { 29637c478bd9Sstevel@tonic-gate bam_error(CLOSE_FAIL, menu_path, strerror(errno)); 29647c478bd9Sstevel@tonic-gate } 29657c478bd9Sstevel@tonic-gate 29667c478bd9Sstevel@tonic-gate return (mp); 29677c478bd9Sstevel@tonic-gate } 29687c478bd9Sstevel@tonic-gate 29697c478bd9Sstevel@tonic-gate static error_t 29707c478bd9Sstevel@tonic-gate selector(menu_t *mp, char *opt, int *entry, char **title) 29717c478bd9Sstevel@tonic-gate { 29727c478bd9Sstevel@tonic-gate char *eq; 29737c478bd9Sstevel@tonic-gate char *opt_dup; 29747c478bd9Sstevel@tonic-gate int entryNum; 29757c478bd9Sstevel@tonic-gate 29767c478bd9Sstevel@tonic-gate assert(mp); 29777c478bd9Sstevel@tonic-gate assert(mp->start); 29787c478bd9Sstevel@tonic-gate assert(opt); 29797c478bd9Sstevel@tonic-gate 29807c478bd9Sstevel@tonic-gate opt_dup = s_strdup(opt); 29817c478bd9Sstevel@tonic-gate 29827c478bd9Sstevel@tonic-gate if (entry) 29837c478bd9Sstevel@tonic-gate *entry = ENTRY_INIT; 29847c478bd9Sstevel@tonic-gate if (title) 29857c478bd9Sstevel@tonic-gate *title = NULL; 29867c478bd9Sstevel@tonic-gate 29877c478bd9Sstevel@tonic-gate eq = strchr(opt_dup, '='); 29887c478bd9Sstevel@tonic-gate if (eq == NULL) { 29897c478bd9Sstevel@tonic-gate bam_error(INVALID_OPT, opt); 29907c478bd9Sstevel@tonic-gate free(opt_dup); 29917c478bd9Sstevel@tonic-gate return (BAM_ERROR); 29927c478bd9Sstevel@tonic-gate } 29937c478bd9Sstevel@tonic-gate 29947c478bd9Sstevel@tonic-gate *eq = '\0'; 29957c478bd9Sstevel@tonic-gate if (entry && strcmp(opt_dup, OPT_ENTRY_NUM) == 0) { 29967c478bd9Sstevel@tonic-gate assert(mp->end); 29977c478bd9Sstevel@tonic-gate entryNum = s_strtol(eq + 1); 29987c478bd9Sstevel@tonic-gate if (entryNum < 0 || entryNum > mp->end->entryNum) { 29997c478bd9Sstevel@tonic-gate bam_error(INVALID_ENTRY, eq + 1); 30007c478bd9Sstevel@tonic-gate free(opt_dup); 30017c478bd9Sstevel@tonic-gate return (BAM_ERROR); 30027c478bd9Sstevel@tonic-gate } 30037c478bd9Sstevel@tonic-gate *entry = entryNum; 30047c478bd9Sstevel@tonic-gate } else if (title && strcmp(opt_dup, menu_cmds[TITLE_CMD]) == 0) { 30057c478bd9Sstevel@tonic-gate *title = opt + (eq - opt_dup) + 1; 30067c478bd9Sstevel@tonic-gate } else { 30077c478bd9Sstevel@tonic-gate bam_error(INVALID_OPT, opt); 30087c478bd9Sstevel@tonic-gate free(opt_dup); 30097c478bd9Sstevel@tonic-gate return (BAM_ERROR); 30107c478bd9Sstevel@tonic-gate } 30117c478bd9Sstevel@tonic-gate 30127c478bd9Sstevel@tonic-gate free(opt_dup); 30137c478bd9Sstevel@tonic-gate return (BAM_SUCCESS); 30147c478bd9Sstevel@tonic-gate } 30157c478bd9Sstevel@tonic-gate 30167c478bd9Sstevel@tonic-gate /* 30177c478bd9Sstevel@tonic-gate * If invoked with no titles/entries (opt == NULL) 30187c478bd9Sstevel@tonic-gate * only title lines in file are printed. 30197c478bd9Sstevel@tonic-gate * 30207c478bd9Sstevel@tonic-gate * If invoked with a title or entry #, all 30217c478bd9Sstevel@tonic-gate * lines in *every* matching entry are listed 30227c478bd9Sstevel@tonic-gate */ 30237c478bd9Sstevel@tonic-gate static error_t 30247c478bd9Sstevel@tonic-gate list_entry(menu_t *mp, char *menu_path, char *opt) 30257c478bd9Sstevel@tonic-gate { 30267c478bd9Sstevel@tonic-gate line_t *lp; 30277c478bd9Sstevel@tonic-gate int entry = ENTRY_INIT; 30287c478bd9Sstevel@tonic-gate int found; 30297c478bd9Sstevel@tonic-gate char *title = NULL; 30307c478bd9Sstevel@tonic-gate 30317c478bd9Sstevel@tonic-gate assert(mp); 30327c478bd9Sstevel@tonic-gate assert(menu_path); 30337c478bd9Sstevel@tonic-gate 3034eb2bd662Svikram /* opt is optional */ 3035eb2bd662Svikram BAM_DPRINTF((D_FUNC_ENTRY2, "list_entry", menu_path, 3036eb2bd662Svikram opt ? opt : "<NULL>")); 3037eb2bd662Svikram 30387c478bd9Sstevel@tonic-gate if (mp->start == NULL) { 30397c478bd9Sstevel@tonic-gate bam_error(NO_MENU, menu_path); 30407c478bd9Sstevel@tonic-gate return (BAM_ERROR); 30417c478bd9Sstevel@tonic-gate } 30427c478bd9Sstevel@tonic-gate 30437c478bd9Sstevel@tonic-gate if (opt != NULL) { 30447c478bd9Sstevel@tonic-gate if (selector(mp, opt, &entry, &title) != BAM_SUCCESS) { 30457c478bd9Sstevel@tonic-gate return (BAM_ERROR); 30467c478bd9Sstevel@tonic-gate } 30477c478bd9Sstevel@tonic-gate assert((entry != ENTRY_INIT) ^ (title != NULL)); 30487c478bd9Sstevel@tonic-gate } else { 30497c478bd9Sstevel@tonic-gate (void) read_globals(mp, menu_path, menu_cmds[DEFAULT_CMD], 0); 30507c478bd9Sstevel@tonic-gate (void) read_globals(mp, menu_path, menu_cmds[TIMEOUT_CMD], 0); 30517c478bd9Sstevel@tonic-gate } 30527c478bd9Sstevel@tonic-gate 30537c478bd9Sstevel@tonic-gate found = 0; 30547c478bd9Sstevel@tonic-gate for (lp = mp->start; lp; lp = lp->next) { 30557c478bd9Sstevel@tonic-gate if (lp->flags == BAM_COMMENT || lp->flags == BAM_EMPTY) 30567c478bd9Sstevel@tonic-gate continue; 30577c478bd9Sstevel@tonic-gate if (opt == NULL && lp->flags == BAM_TITLE) { 30587c478bd9Sstevel@tonic-gate bam_print(PRINT_TITLE, lp->entryNum, 30597c478bd9Sstevel@tonic-gate lp->arg); 30607c478bd9Sstevel@tonic-gate found = 1; 30617c478bd9Sstevel@tonic-gate continue; 30627c478bd9Sstevel@tonic-gate } 30637c478bd9Sstevel@tonic-gate if (entry != ENTRY_INIT && lp->entryNum == entry) { 30647c478bd9Sstevel@tonic-gate bam_print(PRINT, lp->line); 30657c478bd9Sstevel@tonic-gate found = 1; 30667c478bd9Sstevel@tonic-gate continue; 30677c478bd9Sstevel@tonic-gate } 30687c478bd9Sstevel@tonic-gate 30697c478bd9Sstevel@tonic-gate /* 30707c478bd9Sstevel@tonic-gate * We set the entry value here so that all lines 30717c478bd9Sstevel@tonic-gate * in entry get printed. If we subsequently match 30727c478bd9Sstevel@tonic-gate * title in other entries, all lines in those 30737c478bd9Sstevel@tonic-gate * entries get printed as well. 30747c478bd9Sstevel@tonic-gate */ 30757c478bd9Sstevel@tonic-gate if (title && lp->flags == BAM_TITLE && lp->arg && 30767c478bd9Sstevel@tonic-gate strncmp(title, lp->arg, strlen(title)) == 0) { 30777c478bd9Sstevel@tonic-gate bam_print(PRINT, lp->line); 30787c478bd9Sstevel@tonic-gate entry = lp->entryNum; 30797c478bd9Sstevel@tonic-gate found = 1; 30807c478bd9Sstevel@tonic-gate continue; 30817c478bd9Sstevel@tonic-gate } 30827c478bd9Sstevel@tonic-gate } 30837c478bd9Sstevel@tonic-gate 30847c478bd9Sstevel@tonic-gate if (!found) { 30857c478bd9Sstevel@tonic-gate bam_error(NO_MATCH_ENTRY); 30867c478bd9Sstevel@tonic-gate return (BAM_ERROR); 30877c478bd9Sstevel@tonic-gate } 30887c478bd9Sstevel@tonic-gate 30897c478bd9Sstevel@tonic-gate return (BAM_SUCCESS); 30907c478bd9Sstevel@tonic-gate } 30917c478bd9Sstevel@tonic-gate 3092843e1988Sjohnlev int 30937c478bd9Sstevel@tonic-gate add_boot_entry(menu_t *mp, 30947c478bd9Sstevel@tonic-gate char *title, 3095eb2bd662Svikram char *findroot, 30967c478bd9Sstevel@tonic-gate char *kernel, 3097843e1988Sjohnlev char *mod_kernel, 30987c478bd9Sstevel@tonic-gate char *module) 30997c478bd9Sstevel@tonic-gate { 3100eb2bd662Svikram int lineNum; 3101eb2bd662Svikram int entryNum; 31027c478bd9Sstevel@tonic-gate char linebuf[BAM_MAXLINE]; 3103eb2bd662Svikram menu_cmd_t k_cmd; 3104eb2bd662Svikram menu_cmd_t m_cmd; 3105eb2bd662Svikram const char *fcn = "add_boot_entry()"; 31067c478bd9Sstevel@tonic-gate 31077c478bd9Sstevel@tonic-gate assert(mp); 31087c478bd9Sstevel@tonic-gate 3109eb2bd662Svikram INJECT_ERROR1("ADD_BOOT_ENTRY_FINDROOT_NULL", findroot = NULL); 3110eb2bd662Svikram if (findroot == NULL) { 3111eb2bd662Svikram bam_error(NULL_FINDROOT); 3112eb2bd662Svikram return (BAM_ERROR); 3113eb2bd662Svikram } 3114eb2bd662Svikram 31157c478bd9Sstevel@tonic-gate if (title == NULL) { 3116ee3b8144Sszhou title = "Solaris"; /* default to Solaris */ 31177c478bd9Sstevel@tonic-gate } 31187c478bd9Sstevel@tonic-gate if (kernel == NULL) { 31197c478bd9Sstevel@tonic-gate bam_error(SUBOPT_MISS, menu_cmds[KERNEL_CMD]); 31207c478bd9Sstevel@tonic-gate return (BAM_ERROR); 31217c478bd9Sstevel@tonic-gate } 31227c478bd9Sstevel@tonic-gate if (module == NULL) { 3123ae115bc7Smrj if (bam_direct != BAM_DIRECT_DBOOT) { 31247c478bd9Sstevel@tonic-gate bam_error(SUBOPT_MISS, menu_cmds[MODULE_CMD]); 31257c478bd9Sstevel@tonic-gate return (BAM_ERROR); 31267c478bd9Sstevel@tonic-gate } 31277c478bd9Sstevel@tonic-gate 3128ae115bc7Smrj /* Figure the commands out from the kernel line */ 3129ae115bc7Smrj if (strstr(kernel, "$ISADIR") != NULL) { 3130ae115bc7Smrj module = DIRECT_BOOT_ARCHIVE; 3131ae115bc7Smrj k_cmd = KERNEL_DOLLAR_CMD; 3132ae115bc7Smrj m_cmd = MODULE_DOLLAR_CMD; 3133ae115bc7Smrj } else if (strstr(kernel, "amd64") != NULL) { 3134ae115bc7Smrj module = DIRECT_BOOT_ARCHIVE_64; 3135ae115bc7Smrj k_cmd = KERNEL_CMD; 3136ae115bc7Smrj m_cmd = MODULE_CMD; 3137ae115bc7Smrj } else { 3138ae115bc7Smrj module = DIRECT_BOOT_ARCHIVE_32; 3139ae115bc7Smrj k_cmd = KERNEL_CMD; 3140ae115bc7Smrj m_cmd = MODULE_CMD; 3141ae115bc7Smrj } 3142ae115bc7Smrj } else if ((bam_direct == BAM_DIRECT_DBOOT) && 3143ae115bc7Smrj (strstr(kernel, "$ISADIR") != NULL)) { 3144ae115bc7Smrj /* 3145ae115bc7Smrj * If it's a non-failsafe dboot kernel, use the "kernel$" 3146ae115bc7Smrj * command. Otherwise, use "kernel". 3147ae115bc7Smrj */ 3148ae115bc7Smrj k_cmd = KERNEL_DOLLAR_CMD; 3149ae115bc7Smrj m_cmd = MODULE_DOLLAR_CMD; 3150ae115bc7Smrj } else { 3151ae115bc7Smrj k_cmd = KERNEL_CMD; 3152ae115bc7Smrj m_cmd = MODULE_CMD; 3153ae115bc7Smrj } 3154ae115bc7Smrj 31557c478bd9Sstevel@tonic-gate if (mp->start) { 31567c478bd9Sstevel@tonic-gate lineNum = mp->end->lineNum; 31577c478bd9Sstevel@tonic-gate entryNum = mp->end->entryNum; 31587c478bd9Sstevel@tonic-gate } else { 31597c478bd9Sstevel@tonic-gate lineNum = LINE_INIT; 31607c478bd9Sstevel@tonic-gate entryNum = ENTRY_INIT; 31617c478bd9Sstevel@tonic-gate } 31627c478bd9Sstevel@tonic-gate 31637c478bd9Sstevel@tonic-gate /* 31647c478bd9Sstevel@tonic-gate * No separator for comment (HDR/FTR) commands 31657c478bd9Sstevel@tonic-gate * The syntax for comments is #<comment> 31667c478bd9Sstevel@tonic-gate */ 31677c478bd9Sstevel@tonic-gate (void) snprintf(linebuf, sizeof (linebuf), "%s%s", 3168ae115bc7Smrj menu_cmds[COMMENT_CMD], BAM_BOOTADM_HDR); 31698c1b6884Sszhou line_parser(mp, linebuf, &lineNum, &entryNum); 31707c478bd9Sstevel@tonic-gate 31717c478bd9Sstevel@tonic-gate (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s", 31727c478bd9Sstevel@tonic-gate menu_cmds[TITLE_CMD], menu_cmds[SEP_CMD], title); 31738c1b6884Sszhou line_parser(mp, linebuf, &lineNum, &entryNum); 31747c478bd9Sstevel@tonic-gate 31757c478bd9Sstevel@tonic-gate (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s", 3176eb2bd662Svikram menu_cmds[FINDROOT_CMD], menu_cmds[SEP_CMD], findroot); 31778c1b6884Sszhou line_parser(mp, linebuf, &lineNum, &entryNum); 3178eb2bd662Svikram BAM_DPRINTF((D_ADD_FINDROOT_NUM, fcn, lineNum, entryNum)); 31797c478bd9Sstevel@tonic-gate 31807c478bd9Sstevel@tonic-gate (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s", 3181ae115bc7Smrj menu_cmds[k_cmd], menu_cmds[SEP_CMD], kernel); 31828c1b6884Sszhou line_parser(mp, linebuf, &lineNum, &entryNum); 31837c478bd9Sstevel@tonic-gate 3184843e1988Sjohnlev if (mod_kernel != NULL) { 3185843e1988Sjohnlev (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s", 3186843e1988Sjohnlev menu_cmds[m_cmd], menu_cmds[SEP_CMD], mod_kernel); 3187843e1988Sjohnlev line_parser(mp, linebuf, &lineNum, &entryNum); 3188843e1988Sjohnlev } 3189843e1988Sjohnlev 31907c478bd9Sstevel@tonic-gate (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s", 3191ae115bc7Smrj menu_cmds[m_cmd], menu_cmds[SEP_CMD], module); 31928c1b6884Sszhou line_parser(mp, linebuf, &lineNum, &entryNum); 31937c478bd9Sstevel@tonic-gate 31947c478bd9Sstevel@tonic-gate (void) snprintf(linebuf, sizeof (linebuf), "%s%s", 3195ae115bc7Smrj menu_cmds[COMMENT_CMD], BAM_BOOTADM_FTR); 31968c1b6884Sszhou line_parser(mp, linebuf, &lineNum, &entryNum); 31977c478bd9Sstevel@tonic-gate 31987c478bd9Sstevel@tonic-gate return (entryNum); 31997c478bd9Sstevel@tonic-gate } 32007c478bd9Sstevel@tonic-gate 32017c478bd9Sstevel@tonic-gate static error_t 32027c478bd9Sstevel@tonic-gate do_delete(menu_t *mp, int entryNum) 32037c478bd9Sstevel@tonic-gate { 3204eb2bd662Svikram line_t *lp; 3205eb2bd662Svikram line_t *freed; 3206eb2bd662Svikram entry_t *ent; 3207eb2bd662Svikram entry_t *tmp; 32087c478bd9Sstevel@tonic-gate int deleted; 3209eb2bd662Svikram const char *fcn = "do_delete()"; 32107c478bd9Sstevel@tonic-gate 32117c478bd9Sstevel@tonic-gate assert(entryNum != ENTRY_INIT); 32127c478bd9Sstevel@tonic-gate 3213eb2bd662Svikram tmp = NULL; 3214eb2bd662Svikram 32158c1b6884Sszhou ent = mp->entries; 32168c1b6884Sszhou while (ent) { 32178c1b6884Sszhou lp = ent->start; 32188c1b6884Sszhou /* check entry number and make sure it's a bootadm entry */ 32198c1b6884Sszhou if (lp->flags != BAM_COMMENT || 3220ae115bc7Smrj strcmp(lp->arg, BAM_BOOTADM_HDR) != 0 || 32218c1b6884Sszhou (entryNum != ALL_ENTRIES && lp->entryNum != entryNum)) { 32228c1b6884Sszhou ent = ent->next; 32237c478bd9Sstevel@tonic-gate continue; 32247c478bd9Sstevel@tonic-gate } 32257c478bd9Sstevel@tonic-gate 32268c1b6884Sszhou /* free the entry content */ 32278c1b6884Sszhou do { 32288c1b6884Sszhou freed = lp; 32298c1b6884Sszhou lp = lp->next; /* prev stays the same */ 3230eb2bd662Svikram BAM_DPRINTF((D_FREEING_LINE, fcn, freed->lineNum)); 32318c1b6884Sszhou unlink_line(mp, freed); 32328c1b6884Sszhou line_free(freed); 32338c1b6884Sszhou } while (freed != ent->end); 32347c478bd9Sstevel@tonic-gate 32358c1b6884Sszhou /* free the entry_t structure */ 3236eb2bd662Svikram assert(tmp == NULL); 32378c1b6884Sszhou tmp = ent; 32388c1b6884Sszhou ent = ent->next; 32398c1b6884Sszhou if (tmp->prev) 32408c1b6884Sszhou tmp->prev->next = ent; 32417c478bd9Sstevel@tonic-gate else 32428c1b6884Sszhou mp->entries = ent; 32438c1b6884Sszhou if (ent) 32448c1b6884Sszhou ent->prev = tmp->prev; 3245eb2bd662Svikram BAM_DPRINTF((D_FREEING_ENTRY, fcn, tmp->entryNum)); 3246eb2bd662Svikram free(tmp); 3247eb2bd662Svikram tmp = NULL; 32487c478bd9Sstevel@tonic-gate deleted = 1; 32497c478bd9Sstevel@tonic-gate } 32507c478bd9Sstevel@tonic-gate 3251eb2bd662Svikram assert(tmp == NULL); 3252eb2bd662Svikram 32537c478bd9Sstevel@tonic-gate if (!deleted && entryNum != ALL_ENTRIES) { 32547c478bd9Sstevel@tonic-gate bam_error(NO_BOOTADM_MATCH); 32557c478bd9Sstevel@tonic-gate return (BAM_ERROR); 32567c478bd9Sstevel@tonic-gate } 32577c478bd9Sstevel@tonic-gate 325840541d5dSvikram /* 325940541d5dSvikram * Now that we have deleted an entry, update 326040541d5dSvikram * the entry numbering and the default cmd. 326140541d5dSvikram */ 326240541d5dSvikram update_numbering(mp); 326340541d5dSvikram 32647c478bd9Sstevel@tonic-gate return (BAM_SUCCESS); 32657c478bd9Sstevel@tonic-gate } 32667c478bd9Sstevel@tonic-gate 32677c478bd9Sstevel@tonic-gate static error_t 3268eb2bd662Svikram delete_all_entries(menu_t *mp, char *dummy, char *opt) 32697c478bd9Sstevel@tonic-gate { 32707c478bd9Sstevel@tonic-gate assert(mp); 3271eb2bd662Svikram assert(dummy == NULL); 32727c478bd9Sstevel@tonic-gate assert(opt == NULL); 32737c478bd9Sstevel@tonic-gate 3274eb2bd662Svikram BAM_DPRINTF((D_FUNC_ENTRY0, "delete_all_entries")); 3275eb2bd662Svikram 32767c478bd9Sstevel@tonic-gate if (mp->start == NULL) { 3277eb2bd662Svikram bam_print(EMPTY_MENU); 32787c478bd9Sstevel@tonic-gate return (BAM_SUCCESS); 32797c478bd9Sstevel@tonic-gate } 32807c478bd9Sstevel@tonic-gate 32817c478bd9Sstevel@tonic-gate if (do_delete(mp, ALL_ENTRIES) != BAM_SUCCESS) { 32827c478bd9Sstevel@tonic-gate return (BAM_ERROR); 32837c478bd9Sstevel@tonic-gate } 32847c478bd9Sstevel@tonic-gate 32857c478bd9Sstevel@tonic-gate return (BAM_WRITE); 32867c478bd9Sstevel@tonic-gate } 32877c478bd9Sstevel@tonic-gate 32887c478bd9Sstevel@tonic-gate static FILE * 3289eb2bd662Svikram create_diskmap(char *osroot) 32907c478bd9Sstevel@tonic-gate { 32917c478bd9Sstevel@tonic-gate FILE *fp; 32927c478bd9Sstevel@tonic-gate char cmd[PATH_MAX]; 3293eb2bd662Svikram const char *fcn = "create_diskmap()"; 32947c478bd9Sstevel@tonic-gate 32957c478bd9Sstevel@tonic-gate /* make sure we have a map file */ 32967c478bd9Sstevel@tonic-gate fp = fopen(GRUBDISK_MAP, "r"); 32977c478bd9Sstevel@tonic-gate if (fp == NULL) { 32987c478bd9Sstevel@tonic-gate (void) snprintf(cmd, sizeof (cmd), 3299eb2bd662Svikram "%s/%s > /dev/null", osroot, CREATE_DISKMAP); 3300eb2bd662Svikram if (exec_cmd(cmd, NULL) != 0) 3301eb2bd662Svikram return (NULL); 33027c478bd9Sstevel@tonic-gate fp = fopen(GRUBDISK_MAP, "r"); 3303eb2bd662Svikram INJECT_ERROR1("DISKMAP_CREATE_FAIL", fp = NULL); 3304eb2bd662Svikram if (fp) { 3305eb2bd662Svikram BAM_DPRINTF((D_CREATED_DISKMAP, fcn, GRUBDISK_MAP)); 3306eb2bd662Svikram } else { 3307eb2bd662Svikram BAM_DPRINTF((D_CREATE_DISKMAP_FAIL, fcn, GRUBDISK_MAP)); 3308eb2bd662Svikram } 33097c478bd9Sstevel@tonic-gate } 33107c478bd9Sstevel@tonic-gate return (fp); 33117c478bd9Sstevel@tonic-gate } 33127c478bd9Sstevel@tonic-gate 33137c478bd9Sstevel@tonic-gate #define SECTOR_SIZE 512 33147c478bd9Sstevel@tonic-gate 33157c478bd9Sstevel@tonic-gate static int 33167c478bd9Sstevel@tonic-gate get_partition(char *device) 33177c478bd9Sstevel@tonic-gate { 33187c478bd9Sstevel@tonic-gate int i, fd, is_pcfs, partno = -1; 33197c478bd9Sstevel@tonic-gate struct mboot *mboot; 33207c478bd9Sstevel@tonic-gate char boot_sect[SECTOR_SIZE]; 33217c478bd9Sstevel@tonic-gate char *wholedisk, *slice; 33227c478bd9Sstevel@tonic-gate 33237c478bd9Sstevel@tonic-gate /* form whole disk (p0) */ 33247c478bd9Sstevel@tonic-gate slice = device + strlen(device) - 2; 33257c478bd9Sstevel@tonic-gate is_pcfs = (*slice != 's'); 33267c478bd9Sstevel@tonic-gate if (!is_pcfs) 33277c478bd9Sstevel@tonic-gate *slice = '\0'; 33287c478bd9Sstevel@tonic-gate wholedisk = s_calloc(1, strlen(device) + 3); 33297c478bd9Sstevel@tonic-gate (void) snprintf(wholedisk, strlen(device) + 3, "%sp0", device); 33307c478bd9Sstevel@tonic-gate if (!is_pcfs) 33317c478bd9Sstevel@tonic-gate *slice = 's'; 33327c478bd9Sstevel@tonic-gate 33337c478bd9Sstevel@tonic-gate /* read boot sector */ 33347c478bd9Sstevel@tonic-gate fd = open(wholedisk, O_RDONLY); 33357c478bd9Sstevel@tonic-gate free(wholedisk); 33367c478bd9Sstevel@tonic-gate if (fd == -1 || read(fd, boot_sect, SECTOR_SIZE) != SECTOR_SIZE) { 33377c478bd9Sstevel@tonic-gate return (partno); 33387c478bd9Sstevel@tonic-gate } 33397c478bd9Sstevel@tonic-gate (void) close(fd); 33407c478bd9Sstevel@tonic-gate 33417c478bd9Sstevel@tonic-gate /* parse fdisk table */ 33427c478bd9Sstevel@tonic-gate mboot = (struct mboot *)((void *)boot_sect); 33437c478bd9Sstevel@tonic-gate for (i = 0; i < FD_NUMPART; i++) { 33447c478bd9Sstevel@tonic-gate struct ipart *part = 33457c478bd9Sstevel@tonic-gate (struct ipart *)(uintptr_t)mboot->parts + i; 33467c478bd9Sstevel@tonic-gate if (is_pcfs) { /* looking for solaris boot part */ 33477c478bd9Sstevel@tonic-gate if (part->systid == 0xbe) { 33487c478bd9Sstevel@tonic-gate partno = i; 33497c478bd9Sstevel@tonic-gate break; 33507c478bd9Sstevel@tonic-gate } 33517c478bd9Sstevel@tonic-gate } else { /* look for solaris partition, old and new */ 33527c478bd9Sstevel@tonic-gate if (part->systid == SUNIXOS || 33537c478bd9Sstevel@tonic-gate part->systid == SUNIXOS2) { 33547c478bd9Sstevel@tonic-gate partno = i; 33557c478bd9Sstevel@tonic-gate break; 33567c478bd9Sstevel@tonic-gate } 33577c478bd9Sstevel@tonic-gate } 33587c478bd9Sstevel@tonic-gate } 33597c478bd9Sstevel@tonic-gate return (partno); 33607c478bd9Sstevel@tonic-gate } 33617c478bd9Sstevel@tonic-gate 3362eb2bd662Svikram char * 3363eb2bd662Svikram get_grubroot(char *osroot, char *osdev, char *menu_root) 33647c478bd9Sstevel@tonic-gate { 3365eb2bd662Svikram char *grubroot; /* (hd#,#,#) */ 33667c478bd9Sstevel@tonic-gate char *slice; 33677c478bd9Sstevel@tonic-gate char *grubhd; 33687c478bd9Sstevel@tonic-gate int fdiskpart; 33697c478bd9Sstevel@tonic-gate int found = 0; 3370eb2bd662Svikram char *devname; 3371eb2bd662Svikram char *ctdname = strstr(osdev, "dsk/"); 33727c478bd9Sstevel@tonic-gate char linebuf[PATH_MAX]; 3373eb2bd662Svikram FILE *fp; 3374eb2bd662Svikram const char *fcn = "get_grubroot()"; 33757c478bd9Sstevel@tonic-gate 3376eb2bd662Svikram INJECT_ERROR1("GRUBROOT_INVALID_OSDEV", ctdname = NULL); 3377eb2bd662Svikram if (ctdname == NULL) { 3378eb2bd662Svikram bam_error(INVALID_DEV_DSK, osdev); 33797c478bd9Sstevel@tonic-gate return (NULL); 3380eb2bd662Svikram } 3381eb2bd662Svikram 3382eb2bd662Svikram if (menu_root && !menu_on_bootdisk(osroot, menu_root)) { 3383eb2bd662Svikram /* menu bears no resemblance to our reality */ 3384eb2bd662Svikram bam_error(CANNOT_GRUBROOT_BOOTDISK, fcn, osdev); 3385eb2bd662Svikram return (NULL); 3386eb2bd662Svikram } 33877c478bd9Sstevel@tonic-gate 33887c478bd9Sstevel@tonic-gate ctdname += strlen("dsk/"); 33897c478bd9Sstevel@tonic-gate slice = strrchr(ctdname, 's'); 33907c478bd9Sstevel@tonic-gate if (slice) 33917c478bd9Sstevel@tonic-gate *slice = '\0'; 33927c478bd9Sstevel@tonic-gate 3393eb2bd662Svikram fp = create_diskmap(osroot); 3394eb2bd662Svikram if (fp == NULL) { 3395eb2bd662Svikram bam_error(DISKMAP_FAIL, osroot); 3396eb2bd662Svikram return (NULL); 3397eb2bd662Svikram } 3398eb2bd662Svikram 33997c478bd9Sstevel@tonic-gate rewind(fp); 34007c478bd9Sstevel@tonic-gate while (s_fgets(linebuf, sizeof (linebuf), fp) != NULL) { 34017c478bd9Sstevel@tonic-gate grubhd = strtok(linebuf, " \t\n"); 34027c478bd9Sstevel@tonic-gate if (grubhd) 34037c478bd9Sstevel@tonic-gate devname = strtok(NULL, " \t\n"); 34047c478bd9Sstevel@tonic-gate else 34057c478bd9Sstevel@tonic-gate devname = NULL; 34067c478bd9Sstevel@tonic-gate if (devname && strcmp(devname, ctdname) == 0) { 34077c478bd9Sstevel@tonic-gate found = 1; 34087c478bd9Sstevel@tonic-gate break; 34097c478bd9Sstevel@tonic-gate } 34107c478bd9Sstevel@tonic-gate } 34117c478bd9Sstevel@tonic-gate 34127c478bd9Sstevel@tonic-gate if (slice) 34137c478bd9Sstevel@tonic-gate *slice = 's'; 34147c478bd9Sstevel@tonic-gate 3415eb2bd662Svikram (void) fclose(fp); 3416eb2bd662Svikram fp = NULL; 3417eb2bd662Svikram 3418eb2bd662Svikram INJECT_ERROR1("GRUBROOT_BIOSDEV_FAIL", found = 0); 34197c478bd9Sstevel@tonic-gate if (found == 0) { 3420eb2bd662Svikram bam_error(BIOSDEV_FAIL, osdev); 3421eb2bd662Svikram return (NULL); 34227c478bd9Sstevel@tonic-gate } 34237c478bd9Sstevel@tonic-gate 3424eb2bd662Svikram fdiskpart = get_partition(osdev); 3425eb2bd662Svikram INJECT_ERROR1("GRUBROOT_FDISK_FAIL", fdiskpart = -1); 3426eb2bd662Svikram if (fdiskpart == -1) { 3427eb2bd662Svikram bam_error(FDISKPART_FAIL, osdev); 34287c478bd9Sstevel@tonic-gate return (NULL); 3429eb2bd662Svikram } 34307c478bd9Sstevel@tonic-gate 3431eb2bd662Svikram grubroot = s_calloc(1, 10); 34327c478bd9Sstevel@tonic-gate if (slice) { 3433eb2bd662Svikram (void) snprintf(grubroot, 10, "(hd%s,%d,%c)", 34347c478bd9Sstevel@tonic-gate grubhd, fdiskpart, slice[1] + 'a' - '0'); 34357c478bd9Sstevel@tonic-gate } else 3436eb2bd662Svikram (void) snprintf(grubroot, 10, "(hd%s,%d)", 34377c478bd9Sstevel@tonic-gate grubhd, fdiskpart); 34387c478bd9Sstevel@tonic-gate 3439eb2bd662Svikram assert(fp == NULL); 3440eb2bd662Svikram assert(strncmp(grubroot, "(hd", strlen("(hd")) == 0); 3441eb2bd662Svikram return (grubroot); 3442eb2bd662Svikram } 3443eb2bd662Svikram 3444eb2bd662Svikram static char * 3445eb2bd662Svikram find_primary_common(char *mntpt, char *fstype) 3446eb2bd662Svikram { 3447eb2bd662Svikram char signdir[PATH_MAX]; 3448eb2bd662Svikram char tmpsign[MAXNAMELEN + 1]; 3449eb2bd662Svikram char *lu; 3450eb2bd662Svikram char *ufs; 3451eb2bd662Svikram char *zfs; 3452eb2bd662Svikram DIR *dirp = NULL; 3453eb2bd662Svikram struct dirent *entp; 3454eb2bd662Svikram struct stat sb; 3455eb2bd662Svikram const char *fcn = "find_primary_common()"; 3456eb2bd662Svikram 3457eb2bd662Svikram (void) snprintf(signdir, sizeof (signdir), "%s/%s", 3458eb2bd662Svikram mntpt, GRUBSIGN_DIR); 3459eb2bd662Svikram 3460eb2bd662Svikram if (stat(signdir, &sb) == -1) { 3461eb2bd662Svikram BAM_DPRINTF((D_NO_SIGNDIR, fcn, signdir)); 3462eb2bd662Svikram return (NULL); 3463eb2bd662Svikram } 3464eb2bd662Svikram 3465eb2bd662Svikram dirp = opendir(signdir); 3466eb2bd662Svikram INJECT_ERROR1("SIGNDIR_OPENDIR_FAIL", dirp = NULL); 3467eb2bd662Svikram if (dirp == NULL) { 3468eb2bd662Svikram bam_error(OPENDIR_FAILED, signdir, strerror(errno)); 3469eb2bd662Svikram return (NULL); 3470eb2bd662Svikram } 3471eb2bd662Svikram 3472eb2bd662Svikram ufs = zfs = lu = NULL; 3473eb2bd662Svikram 3474eb2bd662Svikram while (entp = readdir(dirp)) { 3475eb2bd662Svikram if (strcmp(entp->d_name, ".") == 0 || 3476eb2bd662Svikram strcmp(entp->d_name, "..") == 0) 3477eb2bd662Svikram continue; 3478eb2bd662Svikram 3479eb2bd662Svikram (void) snprintf(tmpsign, sizeof (tmpsign), "%s", entp->d_name); 3480eb2bd662Svikram 3481eb2bd662Svikram if (lu == NULL && 3482eb2bd662Svikram strncmp(tmpsign, GRUBSIGN_LU_PREFIX, 3483eb2bd662Svikram strlen(GRUBSIGN_LU_PREFIX)) == 0) { 3484eb2bd662Svikram lu = s_strdup(tmpsign); 3485eb2bd662Svikram } 3486eb2bd662Svikram 3487eb2bd662Svikram if (ufs == NULL && 3488eb2bd662Svikram strncmp(tmpsign, GRUBSIGN_UFS_PREFIX, 3489eb2bd662Svikram strlen(GRUBSIGN_UFS_PREFIX)) == 0) { 3490eb2bd662Svikram ufs = s_strdup(tmpsign); 3491eb2bd662Svikram } 3492eb2bd662Svikram 3493eb2bd662Svikram if (zfs == NULL && 3494eb2bd662Svikram strncmp(tmpsign, GRUBSIGN_ZFS_PREFIX, 3495eb2bd662Svikram strlen(GRUBSIGN_ZFS_PREFIX)) == 0) { 3496eb2bd662Svikram zfs = s_strdup(tmpsign); 3497eb2bd662Svikram } 3498eb2bd662Svikram } 3499eb2bd662Svikram 3500eb2bd662Svikram BAM_DPRINTF((D_EXIST_PRIMARY_SIGNS, fcn, 3501eb2bd662Svikram zfs ? zfs : "NULL", 3502eb2bd662Svikram ufs ? ufs : "NULL", 3503eb2bd662Svikram lu ? lu : "NULL")); 3504eb2bd662Svikram 3505eb2bd662Svikram if (dirp) { 3506eb2bd662Svikram (void) closedir(dirp); 3507eb2bd662Svikram dirp = NULL; 3508eb2bd662Svikram } 3509eb2bd662Svikram 3510eb2bd662Svikram if (strcmp(fstype, "ufs") == 0 && zfs) { 3511eb2bd662Svikram bam_error(SIGN_FSTYPE_MISMATCH, zfs, "ufs"); 3512eb2bd662Svikram free(zfs); 3513eb2bd662Svikram zfs = NULL; 3514eb2bd662Svikram } else if (strcmp(fstype, "zfs") == 0 && ufs) { 3515eb2bd662Svikram bam_error(SIGN_FSTYPE_MISMATCH, ufs, "zfs"); 3516eb2bd662Svikram free(ufs); 3517eb2bd662Svikram ufs = NULL; 3518eb2bd662Svikram } 3519eb2bd662Svikram 3520eb2bd662Svikram assert(dirp == NULL); 3521eb2bd662Svikram 3522eb2bd662Svikram /* For now, we let Live Upgrade take care of its signature itself */ 3523eb2bd662Svikram if (lu) { 3524eb2bd662Svikram BAM_DPRINTF((D_FREEING_LU_SIGNS, fcn, lu)); 3525eb2bd662Svikram free(lu); 3526eb2bd662Svikram lu = NULL; 3527eb2bd662Svikram } 3528eb2bd662Svikram 3529eb2bd662Svikram return (zfs ? zfs : ufs); 3530eb2bd662Svikram } 3531eb2bd662Svikram 3532eb2bd662Svikram static char * 3533eb2bd662Svikram find_backup_common(char *mntpt, char *fstype) 3534eb2bd662Svikram { 3535eb2bd662Svikram FILE *bfp = NULL; 3536eb2bd662Svikram char tmpsign[MAXNAMELEN + 1]; 3537eb2bd662Svikram char backup[PATH_MAX]; 3538eb2bd662Svikram char *ufs; 3539eb2bd662Svikram char *zfs; 3540eb2bd662Svikram char *lu; 3541eb2bd662Svikram int error; 3542eb2bd662Svikram const char *fcn = "find_backup_common()"; 3543eb2bd662Svikram 3544eb2bd662Svikram /* 3545eb2bd662Svikram * We didn't find it in the primary directory. 3546eb2bd662Svikram * Look at the backup 3547eb2bd662Svikram */ 3548eb2bd662Svikram (void) snprintf(backup, sizeof (backup), "%s%s", 3549eb2bd662Svikram mntpt, GRUBSIGN_BACKUP); 3550eb2bd662Svikram 3551eb2bd662Svikram bfp = fopen(backup, "r"); 3552eb2bd662Svikram if (bfp == NULL) { 3553eb2bd662Svikram error = errno; 3554eb2bd662Svikram if (bam_verbose) { 3555eb2bd662Svikram bam_error(OPEN_FAIL, backup, strerror(error)); 3556eb2bd662Svikram } 3557eb2bd662Svikram BAM_DPRINTF((D_OPEN_FAIL, fcn, backup, strerror(error))); 3558eb2bd662Svikram return (NULL); 3559eb2bd662Svikram } 3560eb2bd662Svikram 3561eb2bd662Svikram ufs = zfs = lu = NULL; 3562eb2bd662Svikram 3563eb2bd662Svikram while (s_fgets(tmpsign, sizeof (tmpsign), bfp) != NULL) { 3564eb2bd662Svikram 3565eb2bd662Svikram if (lu == NULL && 3566eb2bd662Svikram strncmp(tmpsign, GRUBSIGN_LU_PREFIX, 3567eb2bd662Svikram strlen(GRUBSIGN_LU_PREFIX)) == 0) { 3568eb2bd662Svikram lu = s_strdup(tmpsign); 3569eb2bd662Svikram } 3570eb2bd662Svikram 3571eb2bd662Svikram if (ufs == NULL && 3572eb2bd662Svikram strncmp(tmpsign, GRUBSIGN_UFS_PREFIX, 3573eb2bd662Svikram strlen(GRUBSIGN_UFS_PREFIX)) == 0) { 3574eb2bd662Svikram ufs = s_strdup(tmpsign); 3575eb2bd662Svikram } 3576eb2bd662Svikram 3577eb2bd662Svikram if (zfs == NULL && 3578eb2bd662Svikram strncmp(tmpsign, GRUBSIGN_ZFS_PREFIX, 3579eb2bd662Svikram strlen(GRUBSIGN_ZFS_PREFIX)) == 0) { 3580eb2bd662Svikram zfs = s_strdup(tmpsign); 3581eb2bd662Svikram } 3582eb2bd662Svikram } 3583eb2bd662Svikram 3584eb2bd662Svikram BAM_DPRINTF((D_EXIST_BACKUP_SIGNS, fcn, 3585eb2bd662Svikram zfs ? zfs : "NULL", 3586eb2bd662Svikram ufs ? ufs : "NULL", 3587eb2bd662Svikram lu ? lu : "NULL")); 3588eb2bd662Svikram 3589eb2bd662Svikram if (bfp) { 3590eb2bd662Svikram (void) fclose(bfp); 3591eb2bd662Svikram bfp = NULL; 3592eb2bd662Svikram } 3593eb2bd662Svikram 3594eb2bd662Svikram if (strcmp(fstype, "ufs") == 0 && zfs) { 3595eb2bd662Svikram bam_error(SIGN_FSTYPE_MISMATCH, zfs, "ufs"); 3596eb2bd662Svikram free(zfs); 3597eb2bd662Svikram zfs = NULL; 3598eb2bd662Svikram } else if (strcmp(fstype, "zfs") == 0 && ufs) { 3599eb2bd662Svikram bam_error(SIGN_FSTYPE_MISMATCH, ufs, "zfs"); 3600eb2bd662Svikram free(ufs); 3601eb2bd662Svikram ufs = NULL; 3602eb2bd662Svikram } 3603eb2bd662Svikram 3604eb2bd662Svikram assert(bfp == NULL); 3605eb2bd662Svikram 3606eb2bd662Svikram /* For now, we let Live Upgrade take care of its signature itself */ 3607eb2bd662Svikram if (lu) { 3608eb2bd662Svikram BAM_DPRINTF((D_FREEING_LU_SIGNS, fcn, lu)); 3609eb2bd662Svikram free(lu); 3610eb2bd662Svikram lu = NULL; 3611eb2bd662Svikram } 3612eb2bd662Svikram 3613eb2bd662Svikram return (zfs ? zfs : ufs); 3614eb2bd662Svikram } 3615eb2bd662Svikram 3616eb2bd662Svikram static char * 3617eb2bd662Svikram find_ufs_existing(char *osroot) 3618eb2bd662Svikram { 3619eb2bd662Svikram char *sign; 3620eb2bd662Svikram const char *fcn = "find_ufs_existing()"; 3621eb2bd662Svikram 3622eb2bd662Svikram sign = find_primary_common(osroot, "ufs"); 3623eb2bd662Svikram if (sign == NULL) { 3624eb2bd662Svikram sign = find_backup_common(osroot, "ufs"); 3625eb2bd662Svikram BAM_DPRINTF((D_EXIST_BACKUP_SIGN, fcn, sign ? sign : "NULL")); 3626eb2bd662Svikram } else { 3627eb2bd662Svikram BAM_DPRINTF((D_EXIST_PRIMARY_SIGN, fcn, sign)); 3628eb2bd662Svikram } 3629eb2bd662Svikram 3630eb2bd662Svikram return (sign); 3631eb2bd662Svikram } 3632eb2bd662Svikram 3633eb2bd662Svikram char * 3634eb2bd662Svikram get_mountpoint(char *special, char *fstype) 3635eb2bd662Svikram { 3636eb2bd662Svikram FILE *mntfp; 3637eb2bd662Svikram struct mnttab mp = {0}; 3638eb2bd662Svikram struct mnttab mpref = {0}; 3639eb2bd662Svikram int error; 3640eb2bd662Svikram int ret; 3641eb2bd662Svikram const char *fcn = "get_mountpoint()"; 3642eb2bd662Svikram 3643eb2bd662Svikram BAM_DPRINTF((D_FUNC_ENTRY2, fcn, special, fstype)); 3644eb2bd662Svikram 3645eb2bd662Svikram mntfp = fopen(MNTTAB, "r"); 3646eb2bd662Svikram error = errno; 3647eb2bd662Svikram INJECT_ERROR1("MNTTAB_ERR_GET_MNTPT", mntfp = NULL); 3648eb2bd662Svikram if (mntfp == NULL) { 3649eb2bd662Svikram bam_error(OPEN_FAIL, MNTTAB, strerror(error)); 3650eb2bd662Svikram return (NULL); 3651eb2bd662Svikram } 3652eb2bd662Svikram 3653eb2bd662Svikram mpref.mnt_special = special; 3654eb2bd662Svikram mpref.mnt_fstype = fstype; 3655eb2bd662Svikram 3656eb2bd662Svikram ret = getmntany(mntfp, &mp, &mpref); 3657eb2bd662Svikram INJECT_ERROR1("GET_MOUNTPOINT_MNTANY", ret = 1); 3658eb2bd662Svikram if (ret != 0) { 3659eb2bd662Svikram (void) fclose(mntfp); 3660eb2bd662Svikram BAM_DPRINTF((D_NO_MNTPT, fcn, special, fstype)); 3661eb2bd662Svikram return (NULL); 3662eb2bd662Svikram } 3663eb2bd662Svikram (void) fclose(mntfp); 3664eb2bd662Svikram 3665eb2bd662Svikram assert(mp.mnt_mountp); 3666eb2bd662Svikram 3667eb2bd662Svikram BAM_DPRINTF((D_GET_MOUNTPOINT_RET, fcn, special, mp.mnt_mountp)); 3668eb2bd662Svikram 3669eb2bd662Svikram return (s_strdup(mp.mnt_mountp)); 3670eb2bd662Svikram } 3671eb2bd662Svikram 3672eb2bd662Svikram /* 3673eb2bd662Svikram * Mounts a "legacy" top dataset (if needed) 3674eb2bd662Svikram * Returns: The mountpoint of the legacy top dataset or NULL on error 3675eb2bd662Svikram * mnted returns one of the above values defined for zfs_mnted_t 3676eb2bd662Svikram */ 3677eb2bd662Svikram static char * 3678eb2bd662Svikram mount_legacy_dataset(char *pool, zfs_mnted_t *mnted) 3679eb2bd662Svikram { 3680eb2bd662Svikram char cmd[PATH_MAX]; 3681eb2bd662Svikram char tmpmnt[PATH_MAX]; 3682eb2bd662Svikram filelist_t flist = {0}; 3683eb2bd662Svikram char *is_mounted; 3684eb2bd662Svikram struct stat sb; 3685eb2bd662Svikram int ret; 3686eb2bd662Svikram const char *fcn = "mount_legacy_dataset()"; 3687eb2bd662Svikram 3688eb2bd662Svikram BAM_DPRINTF((D_FUNC_ENTRY1, fcn, pool)); 3689eb2bd662Svikram 3690eb2bd662Svikram *mnted = ZFS_MNT_ERROR; 3691eb2bd662Svikram 3692eb2bd662Svikram (void) snprintf(cmd, sizeof (cmd), 3693eb2bd662Svikram "/sbin/zfs get -Ho value mounted %s", 3694eb2bd662Svikram pool); 3695eb2bd662Svikram 3696eb2bd662Svikram ret = exec_cmd(cmd, &flist); 3697eb2bd662Svikram INJECT_ERROR1("Z_MOUNT_LEG_GET_MOUNTED_CMD", ret = 1); 3698eb2bd662Svikram if (ret != 0) { 3699eb2bd662Svikram bam_error(ZFS_MNTED_FAILED, pool); 3700eb2bd662Svikram return (NULL); 3701eb2bd662Svikram } 3702eb2bd662Svikram 3703eb2bd662Svikram INJECT_ERROR1("Z_MOUNT_LEG_GET_MOUNTED_OUT", flist.head = NULL); 3704eb2bd662Svikram if ((flist.head == NULL) || (flist.head != flist.tail)) { 3705eb2bd662Svikram bam_error(BAD_ZFS_MNTED, pool); 3706eb2bd662Svikram filelist_free(&flist); 3707eb2bd662Svikram return (NULL); 3708eb2bd662Svikram } 3709eb2bd662Svikram 3710eb2bd662Svikram is_mounted = strtok(flist.head->line, " \t\n"); 3711eb2bd662Svikram INJECT_ERROR1("Z_MOUNT_LEG_GET_MOUNTED_STRTOK_YES", is_mounted = "yes"); 3712eb2bd662Svikram INJECT_ERROR1("Z_MOUNT_LEG_GET_MOUNTED_STRTOK_NO", is_mounted = "no"); 3713eb2bd662Svikram if (strcmp(is_mounted, "no") != 0) { 3714eb2bd662Svikram filelist_free(&flist); 3715eb2bd662Svikram *mnted = LEGACY_ALREADY; 3716eb2bd662Svikram /* get_mountpoint returns a strdup'ed string */ 3717eb2bd662Svikram BAM_DPRINTF((D_Z_MOUNT_TOP_LEG_ALREADY, fcn, pool)); 3718eb2bd662Svikram return (get_mountpoint(pool, "zfs")); 3719eb2bd662Svikram } 3720eb2bd662Svikram 3721eb2bd662Svikram filelist_free(&flist); 3722eb2bd662Svikram 3723eb2bd662Svikram /* 3724eb2bd662Svikram * legacy top dataset is not mounted. Mount it now 3725eb2bd662Svikram * First create a mountpoint. 3726eb2bd662Svikram */ 3727eb2bd662Svikram (void) snprintf(tmpmnt, sizeof (tmpmnt), "%s.%d", 3728eb2bd662Svikram ZFS_LEGACY_MNTPT, getpid()); 3729eb2bd662Svikram 3730eb2bd662Svikram ret = stat(tmpmnt, &sb); 3731eb2bd662Svikram if (ret == -1) { 3732eb2bd662Svikram BAM_DPRINTF((D_Z_MOUNT_TOP_LEG_MNTPT_ABS, fcn, pool, tmpmnt)); 3733eb2bd662Svikram ret = mkdirp(tmpmnt, 0755); 3734eb2bd662Svikram INJECT_ERROR1("Z_MOUNT_TOP_LEG_MNTPT_MKDIRP", ret = -1); 3735eb2bd662Svikram if (ret == -1) { 3736eb2bd662Svikram bam_error(MKDIR_FAILED, tmpmnt, strerror(errno)); 3737eb2bd662Svikram return (NULL); 3738eb2bd662Svikram } 3739eb2bd662Svikram } else { 3740eb2bd662Svikram BAM_DPRINTF((D_Z_MOUNT_TOP_LEG_MNTPT_PRES, fcn, pool, tmpmnt)); 3741eb2bd662Svikram } 3742eb2bd662Svikram 3743eb2bd662Svikram (void) snprintf(cmd, sizeof (cmd), 3744eb2bd662Svikram "/sbin/mount -F zfs %s %s", 3745eb2bd662Svikram pool, tmpmnt); 3746eb2bd662Svikram 3747eb2bd662Svikram ret = exec_cmd(cmd, NULL); 3748eb2bd662Svikram INJECT_ERROR1("Z_MOUNT_TOP_LEG_MOUNT_CMD", ret = 1); 3749eb2bd662Svikram if (ret != 0) { 3750eb2bd662Svikram bam_error(ZFS_MOUNT_FAILED, pool); 3751eb2bd662Svikram (void) rmdir(tmpmnt); 3752eb2bd662Svikram return (NULL); 3753eb2bd662Svikram } 3754eb2bd662Svikram 3755eb2bd662Svikram *mnted = LEGACY_MOUNTED; 3756eb2bd662Svikram BAM_DPRINTF((D_Z_MOUNT_TOP_LEG_MOUNTED, fcn, pool, tmpmnt)); 3757eb2bd662Svikram return (s_strdup(tmpmnt)); 3758eb2bd662Svikram } 3759eb2bd662Svikram 3760eb2bd662Svikram /* 3761eb2bd662Svikram * Mounts the top dataset (if needed) 3762eb2bd662Svikram * Returns: The mountpoint of the top dataset or NULL on error 3763eb2bd662Svikram * mnted returns one of the above values defined for zfs_mnted_t 3764eb2bd662Svikram */ 3765eb2bd662Svikram static char * 3766eb2bd662Svikram mount_top_dataset(char *pool, zfs_mnted_t *mnted) 3767eb2bd662Svikram { 3768eb2bd662Svikram char cmd[PATH_MAX]; 3769eb2bd662Svikram filelist_t flist = {0}; 3770eb2bd662Svikram char *is_mounted; 3771eb2bd662Svikram char *mntpt; 3772eb2bd662Svikram char *zmntpt; 3773eb2bd662Svikram int ret; 3774eb2bd662Svikram const char *fcn = "mount_top_dataset()"; 3775eb2bd662Svikram 3776eb2bd662Svikram *mnted = ZFS_MNT_ERROR; 3777eb2bd662Svikram 3778eb2bd662Svikram BAM_DPRINTF((D_FUNC_ENTRY1, fcn, pool)); 3779eb2bd662Svikram 3780eb2bd662Svikram /* 3781eb2bd662Svikram * First check if the top dataset is a "legacy" dataset 3782eb2bd662Svikram */ 3783eb2bd662Svikram (void) snprintf(cmd, sizeof (cmd), 3784eb2bd662Svikram "/sbin/zfs get -Ho value mountpoint %s", 3785eb2bd662Svikram pool); 3786eb2bd662Svikram ret = exec_cmd(cmd, &flist); 3787eb2bd662Svikram INJECT_ERROR1("Z_MOUNT_TOP_GET_MNTPT", ret = 1); 3788eb2bd662Svikram if (ret != 0) { 3789eb2bd662Svikram bam_error(ZFS_MNTPT_FAILED, pool); 3790eb2bd662Svikram return (NULL); 3791eb2bd662Svikram } 3792eb2bd662Svikram 3793eb2bd662Svikram if (flist.head && (flist.head == flist.tail)) { 3794eb2bd662Svikram char *legacy = strtok(flist.head->line, " \t\n"); 3795eb2bd662Svikram if (legacy && strcmp(legacy, "legacy") == 0) { 3796eb2bd662Svikram filelist_free(&flist); 3797eb2bd662Svikram BAM_DPRINTF((D_Z_IS_LEGACY, fcn, pool)); 3798eb2bd662Svikram return (mount_legacy_dataset(pool, mnted)); 3799eb2bd662Svikram } 3800eb2bd662Svikram } 3801eb2bd662Svikram 3802eb2bd662Svikram filelist_free(&flist); 3803eb2bd662Svikram 3804eb2bd662Svikram BAM_DPRINTF((D_Z_IS_NOT_LEGACY, fcn, pool)); 3805eb2bd662Svikram 3806eb2bd662Svikram (void) snprintf(cmd, sizeof (cmd), 3807eb2bd662Svikram "/sbin/zfs get -Ho value mounted %s", 3808eb2bd662Svikram pool); 3809eb2bd662Svikram 3810eb2bd662Svikram ret = exec_cmd(cmd, &flist); 3811eb2bd662Svikram INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MOUNTED", ret = 1); 3812eb2bd662Svikram if (ret != 0) { 3813eb2bd662Svikram bam_error(ZFS_MNTED_FAILED, pool); 3814eb2bd662Svikram return (NULL); 3815eb2bd662Svikram } 3816eb2bd662Svikram 3817eb2bd662Svikram INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MOUNTED_VAL", flist.head = NULL); 3818eb2bd662Svikram if ((flist.head == NULL) || (flist.head != flist.tail)) { 3819eb2bd662Svikram bam_error(BAD_ZFS_MNTED, pool); 3820eb2bd662Svikram filelist_free(&flist); 3821eb2bd662Svikram return (NULL); 3822eb2bd662Svikram } 3823eb2bd662Svikram 3824eb2bd662Svikram is_mounted = strtok(flist.head->line, " \t\n"); 3825eb2bd662Svikram INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MOUNTED_YES", is_mounted = "yes"); 3826eb2bd662Svikram INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MOUNTED_NO", is_mounted = "no"); 3827eb2bd662Svikram if (strcmp(is_mounted, "no") != 0) { 3828eb2bd662Svikram filelist_free(&flist); 3829eb2bd662Svikram *mnted = ZFS_ALREADY; 3830eb2bd662Svikram BAM_DPRINTF((D_Z_MOUNT_TOP_NONLEG_MOUNTED_ALREADY, fcn, pool)); 3831eb2bd662Svikram goto mounted; 3832eb2bd662Svikram } 3833eb2bd662Svikram 3834eb2bd662Svikram filelist_free(&flist); 3835eb2bd662Svikram BAM_DPRINTF((D_Z_MOUNT_TOP_NONLEG_MOUNTED_NOT_ALREADY, fcn, pool)); 3836eb2bd662Svikram 3837eb2bd662Svikram /* top dataset is not mounted. Mount it now */ 3838eb2bd662Svikram (void) snprintf(cmd, sizeof (cmd), 3839eb2bd662Svikram "/sbin/zfs mount %s", pool); 3840eb2bd662Svikram ret = exec_cmd(cmd, NULL); 3841eb2bd662Svikram INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_MOUNT_CMD", ret = 1); 3842eb2bd662Svikram if (ret != 0) { 3843eb2bd662Svikram bam_error(ZFS_MOUNT_FAILED, pool); 3844eb2bd662Svikram return (NULL); 3845eb2bd662Svikram } 3846eb2bd662Svikram *mnted = ZFS_MOUNTED; 3847eb2bd662Svikram BAM_DPRINTF((D_Z_MOUNT_TOP_NONLEG_MOUNTED_NOW, fcn, pool)); 3848eb2bd662Svikram /*FALLTHRU*/ 3849eb2bd662Svikram mounted: 3850eb2bd662Svikram /* 3851eb2bd662Svikram * Now get the mountpoint 3852eb2bd662Svikram */ 3853eb2bd662Svikram (void) snprintf(cmd, sizeof (cmd), 3854eb2bd662Svikram "/sbin/zfs get -Ho value mountpoint %s", 3855eb2bd662Svikram pool); 3856eb2bd662Svikram 3857eb2bd662Svikram ret = exec_cmd(cmd, &flist); 3858eb2bd662Svikram INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MNTPT_CMD", ret = 1); 3859eb2bd662Svikram if (ret != 0) { 3860eb2bd662Svikram bam_error(ZFS_MNTPT_FAILED, pool); 3861eb2bd662Svikram goto error; 3862eb2bd662Svikram } 3863eb2bd662Svikram 3864eb2bd662Svikram INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MNTPT_OUT", flist.head = NULL); 3865eb2bd662Svikram if ((flist.head == NULL) || (flist.head != flist.tail)) { 3866eb2bd662Svikram bam_error(NULL_ZFS_MNTPT, pool); 3867eb2bd662Svikram goto error; 3868eb2bd662Svikram } 3869eb2bd662Svikram 3870eb2bd662Svikram mntpt = strtok(flist.head->line, " \t\n"); 3871eb2bd662Svikram INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MNTPT_STRTOK", mntpt = "foo"); 3872eb2bd662Svikram if (*mntpt != '/') { 3873eb2bd662Svikram bam_error(BAD_ZFS_MNTPT, pool, mntpt); 3874eb2bd662Svikram goto error; 3875eb2bd662Svikram } 3876eb2bd662Svikram zmntpt = s_strdup(mntpt); 3877eb2bd662Svikram 3878eb2bd662Svikram filelist_free(&flist); 3879eb2bd662Svikram 3880eb2bd662Svikram BAM_DPRINTF((D_Z_MOUNT_TOP_NONLEG_MNTPT, fcn, pool, zmntpt)); 3881eb2bd662Svikram 3882eb2bd662Svikram return (zmntpt); 3883eb2bd662Svikram 3884eb2bd662Svikram error: 3885eb2bd662Svikram filelist_free(&flist); 3886eb2bd662Svikram (void) umount_top_dataset(pool, *mnted, NULL); 3887eb2bd662Svikram BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 3888eb2bd662Svikram return (NULL); 3889eb2bd662Svikram } 3890eb2bd662Svikram 3891eb2bd662Svikram static int 3892eb2bd662Svikram umount_top_dataset(char *pool, zfs_mnted_t mnted, char *mntpt) 3893eb2bd662Svikram { 3894eb2bd662Svikram char cmd[PATH_MAX]; 3895eb2bd662Svikram int ret; 3896eb2bd662Svikram const char *fcn = "umount_top_dataset()"; 3897eb2bd662Svikram 3898eb2bd662Svikram INJECT_ERROR1("Z_UMOUNT_TOP_INVALID_STATE", mnted = ZFS_MNT_ERROR); 3899eb2bd662Svikram switch (mnted) { 3900eb2bd662Svikram case LEGACY_ALREADY: 3901eb2bd662Svikram case ZFS_ALREADY: 3902eb2bd662Svikram /* nothing to do */ 3903eb2bd662Svikram BAM_DPRINTF((D_Z_UMOUNT_TOP_ALREADY_NOP, fcn, pool, 3904eb2bd662Svikram mntpt ? mntpt : "NULL")); 3905eb2bd662Svikram free(mntpt); 3906eb2bd662Svikram return (BAM_SUCCESS); 3907eb2bd662Svikram case LEGACY_MOUNTED: 3908eb2bd662Svikram (void) snprintf(cmd, sizeof (cmd), 3909eb2bd662Svikram "/sbin/umount %s", pool); 3910eb2bd662Svikram ret = exec_cmd(cmd, NULL); 3911eb2bd662Svikram INJECT_ERROR1("Z_UMOUNT_TOP_LEGACY_UMOUNT_FAIL", ret = 1); 3912eb2bd662Svikram if (ret != 0) { 3913eb2bd662Svikram bam_error(UMOUNT_FAILED, pool); 3914eb2bd662Svikram free(mntpt); 3915eb2bd662Svikram return (BAM_ERROR); 3916eb2bd662Svikram } 3917eb2bd662Svikram if (mntpt) 3918eb2bd662Svikram (void) rmdir(mntpt); 3919eb2bd662Svikram free(mntpt); 3920eb2bd662Svikram BAM_DPRINTF((D_Z_UMOUNT_TOP_LEGACY, fcn, pool)); 3921eb2bd662Svikram return (BAM_SUCCESS); 3922eb2bd662Svikram case ZFS_MOUNTED: 3923eb2bd662Svikram free(mntpt); 3924eb2bd662Svikram (void) snprintf(cmd, sizeof (cmd), 3925eb2bd662Svikram "/sbin/zfs unmount %s", pool); 3926eb2bd662Svikram ret = exec_cmd(cmd, NULL); 3927eb2bd662Svikram INJECT_ERROR1("Z_UMOUNT_TOP_NONLEG_UMOUNT_FAIL", ret = 1); 3928eb2bd662Svikram if (ret != 0) { 3929eb2bd662Svikram bam_error(UMOUNT_FAILED, pool); 3930eb2bd662Svikram return (BAM_ERROR); 3931eb2bd662Svikram } 3932eb2bd662Svikram BAM_DPRINTF((D_Z_UMOUNT_TOP_NONLEG, fcn, pool)); 3933eb2bd662Svikram return (BAM_SUCCESS); 3934eb2bd662Svikram default: 3935eb2bd662Svikram bam_error(INT_BAD_MNTSTATE, pool); 3936eb2bd662Svikram return (BAM_ERROR); 3937eb2bd662Svikram } 3938eb2bd662Svikram /*NOTREACHED*/ 3939eb2bd662Svikram } 3940eb2bd662Svikram 3941eb2bd662Svikram /* 3942eb2bd662Svikram * For ZFS, osdev can be one of two forms 3943eb2bd662Svikram * It can be a "special" file as seen in mnttab: rpool/ROOT/szboot_0402 3944eb2bd662Svikram * It can be a /dev/[r]dsk special file. We handle both instances 3945eb2bd662Svikram */ 3946eb2bd662Svikram static char * 3947eb2bd662Svikram get_pool(char *osdev) 3948eb2bd662Svikram { 3949eb2bd662Svikram char cmd[PATH_MAX]; 3950eb2bd662Svikram char buf[PATH_MAX]; 3951eb2bd662Svikram filelist_t flist = {0}; 3952eb2bd662Svikram char *pool; 3953eb2bd662Svikram char *cp; 3954eb2bd662Svikram char *slash; 3955eb2bd662Svikram int ret; 3956eb2bd662Svikram const char *fcn = "get_pool()"; 3957eb2bd662Svikram 3958eb2bd662Svikram INJECT_ERROR1("GET_POOL_OSDEV", osdev = NULL); 3959eb2bd662Svikram if (osdev == NULL) { 3960eb2bd662Svikram bam_error(GET_POOL_OSDEV_NULL); 3961eb2bd662Svikram return (NULL); 3962eb2bd662Svikram } 3963eb2bd662Svikram 3964eb2bd662Svikram BAM_DPRINTF((D_GET_POOL_OSDEV, fcn, osdev)); 3965eb2bd662Svikram 3966eb2bd662Svikram if (osdev[0] != '/') { 3967eb2bd662Svikram (void) strlcpy(buf, osdev, sizeof (buf)); 3968eb2bd662Svikram slash = strchr(buf, '/'); 3969eb2bd662Svikram if (slash) 3970eb2bd662Svikram *slash = '\0'; 3971eb2bd662Svikram pool = s_strdup(buf); 3972eb2bd662Svikram BAM_DPRINTF((D_GET_POOL_RET, fcn, pool)); 3973eb2bd662Svikram return (pool); 3974eb2bd662Svikram } else if (strncmp(osdev, "/dev/dsk/", strlen("/dev/dsk/")) != 0 && 3975eb2bd662Svikram strncmp(osdev, "/dev/rdsk/", strlen("/dev/rdsk/")) != 0) { 3976eb2bd662Svikram bam_error(GET_POOL_BAD_OSDEV, osdev); 3977eb2bd662Svikram return (NULL); 3978eb2bd662Svikram } 3979eb2bd662Svikram 3980eb2bd662Svikram (void) snprintf(cmd, sizeof (cmd), 3981eb2bd662Svikram "/usr/sbin/fstyp -a %s 2>/dev/null | /bin/grep '^name:'", 3982eb2bd662Svikram osdev); 3983eb2bd662Svikram 3984eb2bd662Svikram ret = exec_cmd(cmd, &flist); 3985eb2bd662Svikram INJECT_ERROR1("GET_POOL_FSTYP", ret = 1); 3986eb2bd662Svikram if (ret != 0) { 3987eb2bd662Svikram bam_error(FSTYP_A_FAILED, osdev); 3988eb2bd662Svikram return (NULL); 3989eb2bd662Svikram } 3990eb2bd662Svikram 3991eb2bd662Svikram INJECT_ERROR1("GET_POOL_FSTYP_OUT", flist.head = NULL); 3992eb2bd662Svikram if ((flist.head == NULL) || (flist.head != flist.tail)) { 3993eb2bd662Svikram bam_error(NULL_FSTYP_A, osdev); 3994eb2bd662Svikram filelist_free(&flist); 3995eb2bd662Svikram return (NULL); 3996eb2bd662Svikram } 3997eb2bd662Svikram 3998eb2bd662Svikram (void) strtok(flist.head->line, "'"); 3999eb2bd662Svikram cp = strtok(NULL, "'"); 4000eb2bd662Svikram INJECT_ERROR1("GET_POOL_FSTYP_STRTOK", cp = NULL); 4001eb2bd662Svikram if (cp == NULL) { 4002eb2bd662Svikram bam_error(BAD_FSTYP_A, osdev); 4003eb2bd662Svikram filelist_free(&flist); 4004eb2bd662Svikram return (NULL); 4005eb2bd662Svikram } 4006eb2bd662Svikram 4007eb2bd662Svikram pool = s_strdup(cp); 4008eb2bd662Svikram 4009eb2bd662Svikram filelist_free(&flist); 4010eb2bd662Svikram 4011eb2bd662Svikram BAM_DPRINTF((D_GET_POOL_RET, fcn, pool)); 4012eb2bd662Svikram 4013eb2bd662Svikram return (pool); 4014eb2bd662Svikram } 4015eb2bd662Svikram 4016eb2bd662Svikram static char * 4017eb2bd662Svikram find_zfs_existing(char *osdev) 4018eb2bd662Svikram { 4019eb2bd662Svikram char *pool; 4020eb2bd662Svikram zfs_mnted_t mnted; 4021eb2bd662Svikram char *mntpt; 4022eb2bd662Svikram char *sign; 4023eb2bd662Svikram const char *fcn = "find_zfs_existing()"; 4024eb2bd662Svikram 4025eb2bd662Svikram pool = get_pool(osdev); 4026eb2bd662Svikram INJECT_ERROR1("ZFS_FIND_EXIST_POOL", pool = NULL); 4027eb2bd662Svikram if (pool == NULL) { 4028eb2bd662Svikram bam_error(ZFS_GET_POOL_FAILED, osdev); 4029eb2bd662Svikram return (NULL); 4030eb2bd662Svikram } 4031eb2bd662Svikram 4032eb2bd662Svikram mntpt = mount_top_dataset(pool, &mnted); 4033eb2bd662Svikram INJECT_ERROR1("ZFS_FIND_EXIST_MOUNT_TOP", mntpt = NULL); 4034eb2bd662Svikram if (mntpt == NULL) { 4035eb2bd662Svikram bam_error(ZFS_MOUNT_TOP_DATASET_FAILED, pool); 4036eb2bd662Svikram free(pool); 4037eb2bd662Svikram return (NULL); 4038eb2bd662Svikram } 4039eb2bd662Svikram 4040eb2bd662Svikram sign = find_primary_common(mntpt, "zfs"); 4041eb2bd662Svikram if (sign == NULL) { 4042eb2bd662Svikram sign = find_backup_common(mntpt, "zfs"); 4043eb2bd662Svikram BAM_DPRINTF((D_EXIST_BACKUP_SIGN, fcn, sign ? sign : "NULL")); 4044eb2bd662Svikram } else { 4045eb2bd662Svikram BAM_DPRINTF((D_EXIST_PRIMARY_SIGN, fcn, sign)); 4046eb2bd662Svikram } 4047eb2bd662Svikram 4048eb2bd662Svikram (void) umount_top_dataset(pool, mnted, mntpt); 4049eb2bd662Svikram 4050eb2bd662Svikram free(pool); 4051eb2bd662Svikram 4052eb2bd662Svikram return (sign); 4053eb2bd662Svikram } 4054eb2bd662Svikram 4055eb2bd662Svikram static char * 4056eb2bd662Svikram find_existing_sign(char *osroot, char *osdev, char *fstype) 4057eb2bd662Svikram { 4058eb2bd662Svikram const char *fcn = "find_existing_sign()"; 4059eb2bd662Svikram 4060eb2bd662Svikram INJECT_ERROR1("FIND_EXIST_NOTSUP_FS", fstype = "foofs"); 4061eb2bd662Svikram if (strcmp(fstype, "ufs") == 0) { 4062eb2bd662Svikram BAM_DPRINTF((D_CHECK_UFS_EXIST_SIGN, fcn)); 4063eb2bd662Svikram return (find_ufs_existing(osroot)); 4064eb2bd662Svikram } else if (strcmp(fstype, "zfs") == 0) { 4065eb2bd662Svikram BAM_DPRINTF((D_CHECK_ZFS_EXIST_SIGN, fcn)); 4066eb2bd662Svikram return (find_zfs_existing(osdev)); 4067eb2bd662Svikram } else { 4068eb2bd662Svikram bam_error(GRUBSIGN_NOTSUP, fstype); 4069eb2bd662Svikram return (NULL); 4070eb2bd662Svikram } 4071eb2bd662Svikram } 4072eb2bd662Svikram 4073eb2bd662Svikram #define MH_HASH_SZ 16 4074eb2bd662Svikram 4075eb2bd662Svikram typedef enum { 4076eb2bd662Svikram MH_ERROR = -1, 4077eb2bd662Svikram MH_NOMATCH, 4078eb2bd662Svikram MH_MATCH 4079eb2bd662Svikram } mh_search_t; 4080eb2bd662Svikram 4081eb2bd662Svikram typedef struct mcache { 4082eb2bd662Svikram char *mc_special; 4083eb2bd662Svikram char *mc_mntpt; 4084eb2bd662Svikram char *mc_fstype; 4085eb2bd662Svikram struct mcache *mc_next; 4086eb2bd662Svikram } mcache_t; 4087eb2bd662Svikram 4088eb2bd662Svikram typedef struct mhash { 4089eb2bd662Svikram mcache_t *mh_hash[MH_HASH_SZ]; 4090eb2bd662Svikram } mhash_t; 4091eb2bd662Svikram 4092eb2bd662Svikram static int 4093eb2bd662Svikram mhash_fcn(char *key) 4094eb2bd662Svikram { 4095eb2bd662Svikram int i; 4096eb2bd662Svikram uint64_t sum = 0; 4097eb2bd662Svikram 4098eb2bd662Svikram for (i = 0; key[i] != '\0'; i++) { 4099eb2bd662Svikram sum += (uchar_t)key[i]; 4100eb2bd662Svikram } 4101eb2bd662Svikram 4102eb2bd662Svikram sum %= MH_HASH_SZ; 4103eb2bd662Svikram 4104eb2bd662Svikram assert(sum < MH_HASH_SZ); 4105eb2bd662Svikram 4106eb2bd662Svikram return (sum); 4107eb2bd662Svikram } 4108eb2bd662Svikram 4109eb2bd662Svikram static mhash_t * 4110eb2bd662Svikram cache_mnttab(void) 4111eb2bd662Svikram { 4112eb2bd662Svikram FILE *mfp; 4113eb2bd662Svikram struct extmnttab mnt; 4114eb2bd662Svikram mcache_t *mcp; 4115eb2bd662Svikram mhash_t *mhp; 4116eb2bd662Svikram char *ctds; 4117eb2bd662Svikram int idx; 4118eb2bd662Svikram int error; 4119eb2bd662Svikram char *special_dup; 4120eb2bd662Svikram const char *fcn = "cache_mnttab()"; 4121eb2bd662Svikram 4122eb2bd662Svikram mfp = fopen(MNTTAB, "r"); 4123eb2bd662Svikram error = errno; 4124eb2bd662Svikram INJECT_ERROR1("CACHE_MNTTAB_MNTTAB_ERR", mfp = NULL); 4125eb2bd662Svikram if (mfp == NULL) { 4126eb2bd662Svikram bam_error(OPEN_FAIL, MNTTAB, strerror(error)); 4127eb2bd662Svikram return (NULL); 4128eb2bd662Svikram } 4129eb2bd662Svikram 4130eb2bd662Svikram mhp = s_calloc(1, sizeof (mhash_t)); 4131eb2bd662Svikram 4132eb2bd662Svikram resetmnttab(mfp); 4133eb2bd662Svikram 4134eb2bd662Svikram while (getextmntent(mfp, &mnt, sizeof (mnt)) == 0) { 4135eb2bd662Svikram /* only cache ufs */ 4136eb2bd662Svikram if (strcmp(mnt.mnt_fstype, "ufs") != 0) 4137eb2bd662Svikram continue; 4138eb2bd662Svikram 4139eb2bd662Svikram /* basename() modifies its arg, so dup it */ 4140eb2bd662Svikram special_dup = s_strdup(mnt.mnt_special); 4141eb2bd662Svikram ctds = basename(special_dup); 4142eb2bd662Svikram 4143eb2bd662Svikram mcp = s_calloc(1, sizeof (mcache_t)); 4144eb2bd662Svikram mcp->mc_special = s_strdup(ctds); 4145eb2bd662Svikram mcp->mc_mntpt = s_strdup(mnt.mnt_mountp); 4146eb2bd662Svikram mcp->mc_fstype = s_strdup(mnt.mnt_fstype); 4147eb2bd662Svikram BAM_DPRINTF((D_CACHE_MNTS, fcn, ctds, 4148eb2bd662Svikram mnt.mnt_mountp, mnt.mnt_fstype)); 4149eb2bd662Svikram idx = mhash_fcn(ctds); 4150eb2bd662Svikram mcp->mc_next = mhp->mh_hash[idx]; 4151eb2bd662Svikram mhp->mh_hash[idx] = mcp; 4152eb2bd662Svikram free(special_dup); 4153eb2bd662Svikram } 4154eb2bd662Svikram 4155eb2bd662Svikram (void) fclose(mfp); 4156eb2bd662Svikram 4157eb2bd662Svikram return (mhp); 4158eb2bd662Svikram } 4159eb2bd662Svikram 4160eb2bd662Svikram static void 4161eb2bd662Svikram free_mnttab(mhash_t *mhp) 4162eb2bd662Svikram { 4163eb2bd662Svikram mcache_t *mcp; 4164eb2bd662Svikram int i; 4165eb2bd662Svikram 4166eb2bd662Svikram for (i = 0; i < MH_HASH_SZ; i++) { 4167eb2bd662Svikram /*LINTED*/ 4168eb2bd662Svikram while (mcp = mhp->mh_hash[i]) { 4169eb2bd662Svikram mhp->mh_hash[i] = mcp->mc_next; 4170eb2bd662Svikram free(mcp->mc_special); 4171eb2bd662Svikram free(mcp->mc_mntpt); 4172eb2bd662Svikram free(mcp->mc_fstype); 4173eb2bd662Svikram free(mcp); 4174eb2bd662Svikram } 4175eb2bd662Svikram } 4176eb2bd662Svikram 4177eb2bd662Svikram for (i = 0; i < MH_HASH_SZ; i++) { 4178eb2bd662Svikram assert(mhp->mh_hash[i] == NULL); 4179eb2bd662Svikram } 4180eb2bd662Svikram free(mhp); 4181eb2bd662Svikram } 4182eb2bd662Svikram 4183eb2bd662Svikram static mh_search_t 4184eb2bd662Svikram search_hash(mhash_t *mhp, char *special, char **mntpt) 4185eb2bd662Svikram { 4186eb2bd662Svikram int idx; 4187eb2bd662Svikram mcache_t *mcp; 4188eb2bd662Svikram const char *fcn = "search_hash()"; 4189eb2bd662Svikram 4190eb2bd662Svikram assert(mntpt); 4191eb2bd662Svikram 4192eb2bd662Svikram *mntpt = NULL; 4193eb2bd662Svikram 4194eb2bd662Svikram INJECT_ERROR1("SEARCH_HASH_FULL_PATH", special = "/foo"); 4195eb2bd662Svikram if (strchr(special, '/')) { 4196eb2bd662Svikram bam_error(INVALID_MHASH_KEY, special); 4197eb2bd662Svikram return (MH_ERROR); 4198eb2bd662Svikram } 4199eb2bd662Svikram 4200eb2bd662Svikram idx = mhash_fcn(special); 4201eb2bd662Svikram 4202eb2bd662Svikram for (mcp = mhp->mh_hash[idx]; mcp; mcp = mcp->mc_next) { 4203eb2bd662Svikram if (strcmp(mcp->mc_special, special) == 0) 4204eb2bd662Svikram break; 4205eb2bd662Svikram } 4206eb2bd662Svikram 4207eb2bd662Svikram if (mcp == NULL) { 4208eb2bd662Svikram BAM_DPRINTF((D_MNTTAB_HASH_NOMATCH, fcn, special)); 4209eb2bd662Svikram return (MH_NOMATCH); 4210eb2bd662Svikram } 4211eb2bd662Svikram 4212eb2bd662Svikram assert(strcmp(mcp->mc_fstype, "ufs") == 0); 4213eb2bd662Svikram *mntpt = mcp->mc_mntpt; 4214eb2bd662Svikram BAM_DPRINTF((D_MNTTAB_HASH_MATCH, fcn, special)); 4215eb2bd662Svikram return (MH_MATCH); 4216eb2bd662Svikram } 4217eb2bd662Svikram 4218eb2bd662Svikram static int 4219eb2bd662Svikram check_add_ufs_sign_to_list(FILE *tfp, char *mntpt) 4220eb2bd662Svikram { 4221eb2bd662Svikram char *sign; 4222eb2bd662Svikram char *signline; 4223eb2bd662Svikram char signbuf[MAXNAMELEN]; 4224eb2bd662Svikram int len; 4225eb2bd662Svikram int error; 4226eb2bd662Svikram const char *fcn = "check_add_ufs_sign_to_list()"; 4227eb2bd662Svikram 4228eb2bd662Svikram /* safe to specify NULL as "osdev" arg for UFS */ 4229eb2bd662Svikram sign = find_existing_sign(mntpt, NULL, "ufs"); 4230eb2bd662Svikram if (sign == NULL) { 4231eb2bd662Svikram /* No existing signature, nothing to add to list */ 4232eb2bd662Svikram BAM_DPRINTF((D_NO_SIGN_TO_LIST, fcn, mntpt)); 4233eb2bd662Svikram return (0); 4234eb2bd662Svikram } 4235eb2bd662Svikram 4236eb2bd662Svikram (void) snprintf(signbuf, sizeof (signbuf), "%s\n", sign); 4237eb2bd662Svikram signline = signbuf; 4238eb2bd662Svikram 4239eb2bd662Svikram INJECT_ERROR1("UFS_MNTPT_SIGN_NOTUFS", signline = "pool_rpool10\n"); 4240eb2bd662Svikram if (strncmp(signline, GRUBSIGN_UFS_PREFIX, 4241eb2bd662Svikram strlen(GRUBSIGN_UFS_PREFIX))) { 4242eb2bd662Svikram bam_error(INVALID_UFS_SIGNATURE, sign); 4243eb2bd662Svikram free(sign); 4244eb2bd662Svikram /* ignore invalid signatures */ 4245eb2bd662Svikram return (0); 4246eb2bd662Svikram } 4247eb2bd662Svikram 4248eb2bd662Svikram len = fputs(signline, tfp); 4249eb2bd662Svikram error = errno; 4250eb2bd662Svikram INJECT_ERROR1("SIGN_LIST_PUTS_ERROR", len = 0); 4251eb2bd662Svikram if (len != strlen(signline)) { 4252eb2bd662Svikram bam_error(SIGN_LIST_FPUTS_ERR, sign, strerror(error)); 4253eb2bd662Svikram free(sign); 4254eb2bd662Svikram return (-1); 4255eb2bd662Svikram } 4256eb2bd662Svikram 4257eb2bd662Svikram free(sign); 4258eb2bd662Svikram 4259eb2bd662Svikram BAM_DPRINTF((D_SIGN_LIST_PUTS_DONE, fcn, mntpt)); 4260eb2bd662Svikram return (0); 4261eb2bd662Svikram } 4262eb2bd662Svikram 4263eb2bd662Svikram /* 4264eb2bd662Svikram * slice is a basename not a full pathname 4265eb2bd662Svikram */ 4266eb2bd662Svikram static int 4267eb2bd662Svikram process_slice_common(char *slice, FILE *tfp, mhash_t *mhp, char *tmpmnt) 4268eb2bd662Svikram { 4269eb2bd662Svikram int ret; 4270eb2bd662Svikram char cmd[PATH_MAX]; 4271eb2bd662Svikram char path[PATH_MAX]; 4272eb2bd662Svikram struct stat sbuf; 4273eb2bd662Svikram char *mntpt; 4274eb2bd662Svikram filelist_t flist = {0}; 4275eb2bd662Svikram char *fstype; 4276eb2bd662Svikram char blkslice[PATH_MAX]; 4277eb2bd662Svikram const char *fcn = "process_slice_common()"; 4278eb2bd662Svikram 4279eb2bd662Svikram 4280eb2bd662Svikram ret = search_hash(mhp, slice, &mntpt); 4281eb2bd662Svikram switch (ret) { 4282eb2bd662Svikram case MH_MATCH: 4283eb2bd662Svikram if (check_add_ufs_sign_to_list(tfp, mntpt) == -1) 4284eb2bd662Svikram return (-1); 4285eb2bd662Svikram else 4286eb2bd662Svikram return (0); 4287eb2bd662Svikram case MH_NOMATCH: 4288eb2bd662Svikram break; 4289eb2bd662Svikram case MH_ERROR: 4290eb2bd662Svikram default: 4291eb2bd662Svikram return (-1); 4292eb2bd662Svikram } 4293eb2bd662Svikram 4294eb2bd662Svikram (void) snprintf(path, sizeof (path), "/dev/rdsk/%s", slice); 4295eb2bd662Svikram if (stat(path, &sbuf) == -1) { 4296eb2bd662Svikram BAM_DPRINTF((D_SLICE_ENOENT, fcn, path)); 4297eb2bd662Svikram return (0); 4298eb2bd662Svikram } 4299eb2bd662Svikram 4300eb2bd662Svikram /* Check if ufs */ 4301eb2bd662Svikram (void) snprintf(cmd, sizeof (cmd), 4302eb2bd662Svikram "/usr/sbin/fstyp /dev/rdsk/%s 2>/dev/null", 4303eb2bd662Svikram slice); 4304eb2bd662Svikram 4305eb2bd662Svikram if (exec_cmd(cmd, &flist) != 0) { 4306eb2bd662Svikram if (bam_verbose) 4307eb2bd662Svikram bam_print(FSTYP_FAILED, slice); 4308eb2bd662Svikram return (0); 4309eb2bd662Svikram } 4310eb2bd662Svikram 4311eb2bd662Svikram if ((flist.head == NULL) || (flist.head != flist.tail)) { 4312eb2bd662Svikram if (bam_verbose) 4313eb2bd662Svikram bam_print(FSTYP_BAD, slice); 4314eb2bd662Svikram filelist_free(&flist); 4315eb2bd662Svikram return (0); 4316eb2bd662Svikram } 4317eb2bd662Svikram 4318eb2bd662Svikram fstype = strtok(flist.head->line, " \t\n"); 4319eb2bd662Svikram if (fstype == NULL || strcmp(fstype, "ufs") != 0) { 4320eb2bd662Svikram if (bam_verbose) 4321eb2bd662Svikram bam_print(NOT_UFS_SLICE, slice, fstype); 4322eb2bd662Svikram filelist_free(&flist); 4323eb2bd662Svikram return (0); 4324eb2bd662Svikram } 4325eb2bd662Svikram 4326eb2bd662Svikram filelist_free(&flist); 4327eb2bd662Svikram 4328eb2bd662Svikram /* 4329eb2bd662Svikram * Since we are mounting the filesystem read-only, the 4330eb2bd662Svikram * the last mount field of the superblock is unchanged 4331eb2bd662Svikram * and does not need to be fixed up post-mount; 4332eb2bd662Svikram */ 4333eb2bd662Svikram 4334eb2bd662Svikram (void) snprintf(blkslice, sizeof (blkslice), "/dev/dsk/%s", 4335eb2bd662Svikram slice); 4336eb2bd662Svikram 4337eb2bd662Svikram (void) snprintf(cmd, sizeof (cmd), 4338eb2bd662Svikram "/usr/sbin/mount -F ufs -o ro %s %s " 4339eb2bd662Svikram "> /dev/null 2>&1", blkslice, tmpmnt); 4340eb2bd662Svikram 4341eb2bd662Svikram if (exec_cmd(cmd, NULL) != 0) { 4342eb2bd662Svikram if (bam_verbose) 4343eb2bd662Svikram bam_print(MOUNT_FAILED, blkslice, "ufs"); 4344eb2bd662Svikram return (0); 4345eb2bd662Svikram } 4346eb2bd662Svikram 4347eb2bd662Svikram ret = check_add_ufs_sign_to_list(tfp, tmpmnt); 4348eb2bd662Svikram 4349eb2bd662Svikram (void) snprintf(cmd, sizeof (cmd), 4350eb2bd662Svikram "/usr/sbin/umount -f %s > /dev/null 2>&1", 4351eb2bd662Svikram tmpmnt); 4352eb2bd662Svikram 4353eb2bd662Svikram if (exec_cmd(cmd, NULL) != 0) { 4354eb2bd662Svikram bam_print(UMOUNT_FAILED, slice); 4355eb2bd662Svikram return (0); 4356eb2bd662Svikram } 4357eb2bd662Svikram 4358eb2bd662Svikram return (ret); 4359eb2bd662Svikram } 4360eb2bd662Svikram 4361eb2bd662Svikram static int 4362eb2bd662Svikram process_vtoc_slices( 4363eb2bd662Svikram char *s0, 4364eb2bd662Svikram struct vtoc *vtoc, 4365eb2bd662Svikram FILE *tfp, 4366eb2bd662Svikram mhash_t *mhp, 4367eb2bd662Svikram char *tmpmnt) 4368eb2bd662Svikram { 4369eb2bd662Svikram int idx; 4370eb2bd662Svikram char slice[PATH_MAX]; 4371eb2bd662Svikram size_t len; 4372eb2bd662Svikram char *cp; 4373eb2bd662Svikram const char *fcn = "process_vtoc_slices()"; 4374eb2bd662Svikram 4375eb2bd662Svikram len = strlen(s0); 4376eb2bd662Svikram 4377eb2bd662Svikram assert(s0[len - 2] == 's' && s0[len - 1] == '0'); 4378eb2bd662Svikram 4379eb2bd662Svikram s0[len - 1] = '\0'; 4380eb2bd662Svikram 4381eb2bd662Svikram (void) strlcpy(slice, s0, sizeof (slice)); 4382eb2bd662Svikram 4383eb2bd662Svikram s0[len - 1] = '0'; 4384eb2bd662Svikram 4385eb2bd662Svikram cp = slice + len - 1; 4386eb2bd662Svikram 4387eb2bd662Svikram for (idx = 0; idx < vtoc->v_nparts; idx++) { 4388eb2bd662Svikram 4389eb2bd662Svikram (void) snprintf(cp, sizeof (slice) - (len - 1), "%u", idx); 4390eb2bd662Svikram 4391eb2bd662Svikram if (vtoc->v_part[idx].p_size == 0) { 4392eb2bd662Svikram BAM_DPRINTF((D_VTOC_SIZE_ZERO, fcn, slice)); 4393eb2bd662Svikram continue; 4394eb2bd662Svikram } 4395eb2bd662Svikram 4396eb2bd662Svikram /* Skip "SWAP", "USR", "BACKUP", "VAR", "HOME", "ALTSCTR" */ 4397eb2bd662Svikram switch (vtoc->v_part[idx].p_tag) { 4398eb2bd662Svikram case V_SWAP: 4399eb2bd662Svikram case V_USR: 4400eb2bd662Svikram case V_BACKUP: 4401eb2bd662Svikram case V_VAR: 4402eb2bd662Svikram case V_HOME: 4403eb2bd662Svikram case V_ALTSCTR: 4404eb2bd662Svikram BAM_DPRINTF((D_VTOC_NOT_ROOT_TAG, fcn, slice)); 4405eb2bd662Svikram continue; 4406eb2bd662Svikram default: 4407eb2bd662Svikram BAM_DPRINTF((D_VTOC_ROOT_TAG, fcn, slice)); 4408eb2bd662Svikram break; 4409eb2bd662Svikram } 4410eb2bd662Svikram 4411eb2bd662Svikram /* skip unmountable and readonly slices */ 4412eb2bd662Svikram switch (vtoc->v_part[idx].p_flag) { 4413eb2bd662Svikram case V_UNMNT: 4414eb2bd662Svikram case V_RONLY: 4415eb2bd662Svikram BAM_DPRINTF((D_VTOC_NOT_RDWR_FLAG, fcn, slice)); 4416eb2bd662Svikram continue; 4417eb2bd662Svikram default: 4418eb2bd662Svikram BAM_DPRINTF((D_VTOC_RDWR_FLAG, fcn, slice)); 4419eb2bd662Svikram break; 4420eb2bd662Svikram } 4421eb2bd662Svikram 4422eb2bd662Svikram if (process_slice_common(slice, tfp, mhp, tmpmnt) == -1) { 4423eb2bd662Svikram return (-1); 4424eb2bd662Svikram } 4425eb2bd662Svikram } 4426eb2bd662Svikram 4427eb2bd662Svikram return (0); 4428eb2bd662Svikram } 4429eb2bd662Svikram 4430eb2bd662Svikram static int 4431eb2bd662Svikram process_efi_slices( 4432eb2bd662Svikram char *s0, 4433eb2bd662Svikram struct dk_gpt *efi, 4434eb2bd662Svikram FILE *tfp, 4435eb2bd662Svikram mhash_t *mhp, 4436eb2bd662Svikram char *tmpmnt) 4437eb2bd662Svikram { 4438eb2bd662Svikram int idx; 4439eb2bd662Svikram char slice[PATH_MAX]; 4440eb2bd662Svikram size_t len; 4441eb2bd662Svikram char *cp; 4442eb2bd662Svikram const char *fcn = "process_efi_slices()"; 4443eb2bd662Svikram 4444eb2bd662Svikram len = strlen(s0); 4445eb2bd662Svikram 4446eb2bd662Svikram assert(s0[len - 2] == 's' && s0[len - 1] == '0'); 4447eb2bd662Svikram 4448eb2bd662Svikram s0[len - 1] = '\0'; 4449eb2bd662Svikram 4450eb2bd662Svikram (void) strlcpy(slice, s0, sizeof (slice)); 4451eb2bd662Svikram 4452eb2bd662Svikram s0[len - 1] = '0'; 4453eb2bd662Svikram 4454eb2bd662Svikram cp = slice + len - 1; 4455eb2bd662Svikram 4456eb2bd662Svikram for (idx = 0; idx < efi->efi_nparts; idx++) { 4457eb2bd662Svikram 4458eb2bd662Svikram (void) snprintf(cp, sizeof (slice) - (len - 1), "%u", idx); 4459eb2bd662Svikram 4460eb2bd662Svikram if (efi->efi_parts[idx].p_size == 0) { 4461eb2bd662Svikram BAM_DPRINTF((D_EFI_SIZE_ZERO, fcn, slice)); 4462eb2bd662Svikram continue; 4463eb2bd662Svikram } 4464eb2bd662Svikram 4465eb2bd662Svikram /* Skip "SWAP", "USR", "BACKUP", "VAR", "HOME", "ALTSCTR" */ 4466eb2bd662Svikram switch (efi->efi_parts[idx].p_tag) { 4467eb2bd662Svikram case V_SWAP: 4468eb2bd662Svikram case V_USR: 4469eb2bd662Svikram case V_BACKUP: 4470eb2bd662Svikram case V_VAR: 4471eb2bd662Svikram case V_HOME: 4472eb2bd662Svikram case V_ALTSCTR: 4473eb2bd662Svikram BAM_DPRINTF((D_EFI_NOT_ROOT_TAG, fcn, slice)); 4474eb2bd662Svikram continue; 4475eb2bd662Svikram default: 4476eb2bd662Svikram BAM_DPRINTF((D_EFI_ROOT_TAG, fcn, slice)); 4477eb2bd662Svikram break; 4478eb2bd662Svikram } 4479eb2bd662Svikram 4480eb2bd662Svikram /* skip unmountable and readonly slices */ 4481eb2bd662Svikram switch (efi->efi_parts[idx].p_flag) { 4482eb2bd662Svikram case V_UNMNT: 4483eb2bd662Svikram case V_RONLY: 4484eb2bd662Svikram BAM_DPRINTF((D_EFI_NOT_RDWR_FLAG, fcn, slice)); 4485eb2bd662Svikram continue; 4486eb2bd662Svikram default: 4487eb2bd662Svikram BAM_DPRINTF((D_EFI_RDWR_FLAG, fcn, slice)); 4488eb2bd662Svikram break; 4489eb2bd662Svikram } 4490eb2bd662Svikram 4491eb2bd662Svikram if (process_slice_common(slice, tfp, mhp, tmpmnt) == -1) { 4492eb2bd662Svikram return (-1); 4493eb2bd662Svikram } 4494eb2bd662Svikram } 4495eb2bd662Svikram 4496eb2bd662Svikram return (0); 4497eb2bd662Svikram } 4498eb2bd662Svikram 4499eb2bd662Svikram /* 4500eb2bd662Svikram * s0 is a basename not a full path 4501eb2bd662Svikram */ 4502eb2bd662Svikram static int 4503eb2bd662Svikram process_slice0(char *s0, FILE *tfp, mhash_t *mhp, char *tmpmnt) 4504eb2bd662Svikram { 4505eb2bd662Svikram struct vtoc vtoc; 4506eb2bd662Svikram struct dk_gpt *efi; 4507eb2bd662Svikram char s0path[PATH_MAX]; 4508eb2bd662Svikram struct stat sbuf; 4509eb2bd662Svikram int e_flag; 4510eb2bd662Svikram int v_flag; 4511eb2bd662Svikram int retval; 4512eb2bd662Svikram int err; 4513eb2bd662Svikram int fd; 4514eb2bd662Svikram const char *fcn = "process_slice0()"; 4515eb2bd662Svikram 4516eb2bd662Svikram (void) snprintf(s0path, sizeof (s0path), "/dev/rdsk/%s", s0); 4517eb2bd662Svikram 4518eb2bd662Svikram if (stat(s0path, &sbuf) == -1) { 4519eb2bd662Svikram BAM_DPRINTF((D_SLICE0_ENOENT, fcn, s0path)); 4520eb2bd662Svikram return (0); 4521eb2bd662Svikram } 4522eb2bd662Svikram 4523eb2bd662Svikram fd = open(s0path, O_NONBLOCK|O_RDONLY); 4524eb2bd662Svikram if (fd == -1) { 4525eb2bd662Svikram bam_error(OPEN_FAIL, s0path, strerror(errno)); 4526eb2bd662Svikram return (0); 4527eb2bd662Svikram } 4528eb2bd662Svikram 4529eb2bd662Svikram e_flag = v_flag = 0; 4530eb2bd662Svikram retval = ((err = read_vtoc(fd, &vtoc)) >= 0) ? 0 : err; 4531eb2bd662Svikram switch (retval) { 4532eb2bd662Svikram case VT_EIO: 4533eb2bd662Svikram BAM_DPRINTF((D_VTOC_READ_FAIL, fcn, s0path)); 4534eb2bd662Svikram break; 4535eb2bd662Svikram case VT_EINVAL: 4536eb2bd662Svikram BAM_DPRINTF((D_VTOC_INVALID, fcn, s0path)); 4537eb2bd662Svikram break; 4538eb2bd662Svikram case VT_ERROR: 4539eb2bd662Svikram BAM_DPRINTF((D_VTOC_UNKNOWN_ERR, fcn, s0path)); 4540eb2bd662Svikram break; 4541eb2bd662Svikram case VT_ENOTSUP: 4542eb2bd662Svikram e_flag = 1; 4543eb2bd662Svikram BAM_DPRINTF((D_VTOC_NOTSUP, fcn, s0path)); 4544eb2bd662Svikram break; 4545eb2bd662Svikram case 0: 4546eb2bd662Svikram v_flag = 1; 4547eb2bd662Svikram BAM_DPRINTF((D_VTOC_READ_SUCCESS, fcn, s0path)); 4548eb2bd662Svikram break; 4549eb2bd662Svikram default: 4550eb2bd662Svikram BAM_DPRINTF((D_VTOC_UNKNOWN_RETCODE, fcn, s0path)); 4551eb2bd662Svikram break; 4552eb2bd662Svikram } 4553eb2bd662Svikram 4554eb2bd662Svikram 4555eb2bd662Svikram if (e_flag) { 4556eb2bd662Svikram e_flag = 0; 4557eb2bd662Svikram retval = ((err = efi_alloc_and_read(fd, &efi)) >= 0) ? 0 : err; 4558eb2bd662Svikram switch (retval) { 4559eb2bd662Svikram case VT_EIO: 4560eb2bd662Svikram BAM_DPRINTF((D_EFI_READ_FAIL, fcn, s0path)); 4561eb2bd662Svikram break; 4562eb2bd662Svikram case VT_EINVAL: 4563eb2bd662Svikram BAM_DPRINTF((D_EFI_INVALID, fcn, s0path)); 4564eb2bd662Svikram break; 4565eb2bd662Svikram case VT_ERROR: 4566eb2bd662Svikram BAM_DPRINTF((D_EFI_UNKNOWN_ERR, fcn, s0path)); 4567eb2bd662Svikram break; 4568eb2bd662Svikram case VT_ENOTSUP: 4569eb2bd662Svikram BAM_DPRINTF((D_EFI_NOTSUP, fcn, s0path)); 4570eb2bd662Svikram break; 4571eb2bd662Svikram case 0: 4572eb2bd662Svikram e_flag = 1; 4573eb2bd662Svikram BAM_DPRINTF((D_EFI_READ_SUCCESS, fcn, s0path)); 4574eb2bd662Svikram break; 4575eb2bd662Svikram default: 4576eb2bd662Svikram BAM_DPRINTF((D_EFI_UNKNOWN_RETCODE, fcn, s0path)); 4577eb2bd662Svikram break; 4578eb2bd662Svikram } 4579eb2bd662Svikram } 4580eb2bd662Svikram 4581eb2bd662Svikram (void) close(fd); 4582eb2bd662Svikram 4583eb2bd662Svikram if (v_flag) { 4584eb2bd662Svikram retval = process_vtoc_slices(s0, 4585eb2bd662Svikram &vtoc, tfp, mhp, tmpmnt); 4586eb2bd662Svikram } else if (e_flag) { 4587eb2bd662Svikram retval = process_efi_slices(s0, 4588eb2bd662Svikram efi, tfp, mhp, tmpmnt); 4589eb2bd662Svikram } else { 4590eb2bd662Svikram BAM_DPRINTF((D_NOT_VTOC_OR_EFI, fcn, s0path)); 4591eb2bd662Svikram return (0); 4592eb2bd662Svikram } 4593eb2bd662Svikram 4594eb2bd662Svikram return (retval); 4595eb2bd662Svikram } 4596eb2bd662Svikram 4597eb2bd662Svikram /* 4598eb2bd662Svikram * Find and create a list of all existing UFS boot signatures 4599eb2bd662Svikram */ 4600eb2bd662Svikram static int 4601eb2bd662Svikram FindAllUfsSignatures(void) 4602eb2bd662Svikram { 4603eb2bd662Svikram mhash_t *mnttab_hash; 4604eb2bd662Svikram DIR *dirp = NULL; 4605eb2bd662Svikram struct dirent *dp; 4606eb2bd662Svikram char tmpmnt[PATH_MAX]; 4607eb2bd662Svikram char cmd[PATH_MAX]; 4608eb2bd662Svikram struct stat sb; 4609eb2bd662Svikram int fd; 4610eb2bd662Svikram FILE *tfp; 4611eb2bd662Svikram size_t len; 4612eb2bd662Svikram int ret; 4613eb2bd662Svikram int error; 4614eb2bd662Svikram const char *fcn = "FindAllUfsSignatures()"; 4615eb2bd662Svikram 4616eb2bd662Svikram if (stat(UFS_SIGNATURE_LIST, &sb) != -1) { 4617eb2bd662Svikram bam_print(SIGNATURE_LIST_EXISTS, UFS_SIGNATURE_LIST); 4618eb2bd662Svikram return (0); 4619eb2bd662Svikram } 4620eb2bd662Svikram 4621eb2bd662Svikram fd = open(UFS_SIGNATURE_LIST".tmp", 4622eb2bd662Svikram O_RDWR|O_CREAT|O_TRUNC, 0644); 4623eb2bd662Svikram error = errno; 4624eb2bd662Svikram INJECT_ERROR1("SIGN_LIST_TMP_TRUNC", fd = -1); 4625eb2bd662Svikram if (fd == -1) { 4626eb2bd662Svikram bam_error(OPEN_FAIL, UFS_SIGNATURE_LIST".tmp", strerror(error)); 4627eb2bd662Svikram return (-1); 4628eb2bd662Svikram } 4629eb2bd662Svikram 4630eb2bd662Svikram ret = close(fd); 4631eb2bd662Svikram error = errno; 4632eb2bd662Svikram INJECT_ERROR1("SIGN_LIST_TMP_CLOSE", ret = -1); 4633eb2bd662Svikram if (ret == -1) { 4634eb2bd662Svikram bam_error(CLOSE_FAIL, UFS_SIGNATURE_LIST".tmp", 4635eb2bd662Svikram strerror(error)); 4636eb2bd662Svikram (void) unlink(UFS_SIGNATURE_LIST".tmp"); 4637eb2bd662Svikram return (-1); 4638eb2bd662Svikram } 4639eb2bd662Svikram 4640eb2bd662Svikram tfp = fopen(UFS_SIGNATURE_LIST".tmp", "a"); 4641eb2bd662Svikram error = errno; 4642eb2bd662Svikram INJECT_ERROR1("SIGN_LIST_APPEND_FOPEN", tfp = NULL); 4643eb2bd662Svikram if (tfp == NULL) { 4644eb2bd662Svikram bam_error(OPEN_FAIL, UFS_SIGNATURE_LIST".tmp", strerror(error)); 4645eb2bd662Svikram (void) unlink(UFS_SIGNATURE_LIST".tmp"); 4646eb2bd662Svikram return (-1); 4647eb2bd662Svikram } 4648eb2bd662Svikram 4649eb2bd662Svikram mnttab_hash = cache_mnttab(); 4650eb2bd662Svikram INJECT_ERROR1("CACHE_MNTTAB_ERROR", mnttab_hash = NULL); 4651eb2bd662Svikram if (mnttab_hash == NULL) { 4652eb2bd662Svikram (void) fclose(tfp); 4653eb2bd662Svikram (void) unlink(UFS_SIGNATURE_LIST".tmp"); 4654eb2bd662Svikram bam_error(CACHE_MNTTAB_FAIL, fcn); 4655eb2bd662Svikram return (-1); 4656eb2bd662Svikram } 4657eb2bd662Svikram 4658eb2bd662Svikram (void) snprintf(tmpmnt, sizeof (tmpmnt), 4659eb2bd662Svikram "/tmp/bootadm_ufs_sign_mnt.%d", getpid()); 4660eb2bd662Svikram (void) unlink(tmpmnt); 4661eb2bd662Svikram 4662eb2bd662Svikram ret = mkdirp(tmpmnt, 0755); 4663eb2bd662Svikram error = errno; 4664eb2bd662Svikram INJECT_ERROR1("MKDIRP_SIGN_MNT", ret = -1); 4665eb2bd662Svikram if (ret == -1) { 4666eb2bd662Svikram bam_error(MKDIR_FAILED, tmpmnt, strerror(error)); 4667eb2bd662Svikram free_mnttab(mnttab_hash); 4668eb2bd662Svikram (void) fclose(tfp); 4669eb2bd662Svikram (void) unlink(UFS_SIGNATURE_LIST".tmp"); 4670eb2bd662Svikram return (-1); 4671eb2bd662Svikram } 4672eb2bd662Svikram 4673eb2bd662Svikram dirp = opendir("/dev/rdsk"); 4674eb2bd662Svikram error = errno; 4675eb2bd662Svikram INJECT_ERROR1("OPENDIR_DEV_RDSK", dirp = NULL); 4676eb2bd662Svikram if (dirp == NULL) { 4677eb2bd662Svikram bam_error(OPENDIR_FAILED, "/dev/rdsk", strerror(error)); 4678eb2bd662Svikram goto fail; 4679eb2bd662Svikram } 4680eb2bd662Svikram 4681eb2bd662Svikram while (dp = readdir(dirp)) { 4682eb2bd662Svikram if (strcmp(dp->d_name, ".") == 0 || 4683eb2bd662Svikram strcmp(dp->d_name, "..") == 0) 4684eb2bd662Svikram continue; 4685eb2bd662Svikram 4686eb2bd662Svikram /* 4687eb2bd662Svikram * we only look for the s0 slice. This is guranteed to 4688eb2bd662Svikram * have 's' at len - 2. 4689eb2bd662Svikram */ 4690eb2bd662Svikram len = strlen(dp->d_name); 4691eb2bd662Svikram if (dp->d_name[len - 2 ] != 's' || dp->d_name[len - 1] != '0') { 4692eb2bd662Svikram BAM_DPRINTF((D_SKIP_SLICE_NOTZERO, fcn, dp->d_name)); 4693eb2bd662Svikram continue; 4694eb2bd662Svikram } 4695eb2bd662Svikram 4696eb2bd662Svikram ret = process_slice0(dp->d_name, tfp, mnttab_hash, tmpmnt); 4697eb2bd662Svikram INJECT_ERROR1("PROCESS_S0_FAIL", ret = -1); 4698eb2bd662Svikram if (ret == -1) 4699eb2bd662Svikram goto fail; 4700eb2bd662Svikram } 4701eb2bd662Svikram 4702eb2bd662Svikram (void) closedir(dirp); 4703eb2bd662Svikram free_mnttab(mnttab_hash); 4704eb2bd662Svikram (void) rmdir(tmpmnt); 4705eb2bd662Svikram 4706eb2bd662Svikram ret = fclose(tfp); 4707eb2bd662Svikram error = errno; 4708eb2bd662Svikram INJECT_ERROR1("FCLOSE_SIGNLIST_TMP", ret = EOF); 4709eb2bd662Svikram if (ret == EOF) { 4710eb2bd662Svikram bam_error(CLOSE_FAIL, UFS_SIGNATURE_LIST".tmp", 4711eb2bd662Svikram strerror(error)); 4712eb2bd662Svikram (void) unlink(UFS_SIGNATURE_LIST".tmp"); 4713eb2bd662Svikram return (-1); 4714eb2bd662Svikram } 4715eb2bd662Svikram 4716eb2bd662Svikram /* We have a list of existing GRUB signatures. Sort it first */ 4717eb2bd662Svikram (void) snprintf(cmd, sizeof (cmd), 4718eb2bd662Svikram "/usr/bin/sort -u %s.tmp > %s.sorted", 4719eb2bd662Svikram UFS_SIGNATURE_LIST, UFS_SIGNATURE_LIST); 4720eb2bd662Svikram 4721eb2bd662Svikram ret = exec_cmd(cmd, NULL); 4722eb2bd662Svikram INJECT_ERROR1("SORT_SIGN_LIST", ret = 1); 4723eb2bd662Svikram if (ret != 0) { 4724eb2bd662Svikram bam_error(GRUBSIGN_SORT_FAILED); 4725eb2bd662Svikram (void) unlink(UFS_SIGNATURE_LIST".sorted"); 4726eb2bd662Svikram (void) unlink(UFS_SIGNATURE_LIST".tmp"); 4727eb2bd662Svikram return (-1); 4728eb2bd662Svikram } 4729eb2bd662Svikram 4730eb2bd662Svikram (void) unlink(UFS_SIGNATURE_LIST".tmp"); 4731eb2bd662Svikram 4732eb2bd662Svikram ret = rename(UFS_SIGNATURE_LIST".sorted", UFS_SIGNATURE_LIST); 4733eb2bd662Svikram error = errno; 4734eb2bd662Svikram INJECT_ERROR1("RENAME_TMP_SIGNLIST", ret = -1); 4735eb2bd662Svikram if (ret == -1) { 4736eb2bd662Svikram bam_error(RENAME_FAIL, UFS_SIGNATURE_LIST, strerror(error)); 4737eb2bd662Svikram (void) unlink(UFS_SIGNATURE_LIST".sorted"); 4738eb2bd662Svikram return (-1); 4739eb2bd662Svikram } 4740eb2bd662Svikram 4741eb2bd662Svikram if (stat(UFS_SIGNATURE_LIST, &sb) == 0 && sb.st_size == 0) { 4742eb2bd662Svikram BAM_DPRINTF((D_ZERO_LEN_SIGNLIST, fcn, UFS_SIGNATURE_LIST)); 4743eb2bd662Svikram } 4744eb2bd662Svikram 4745eb2bd662Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 4746eb2bd662Svikram return (0); 4747eb2bd662Svikram 4748eb2bd662Svikram fail: 4749eb2bd662Svikram if (dirp) 4750eb2bd662Svikram (void) closedir(dirp); 4751eb2bd662Svikram free_mnttab(mnttab_hash); 4752eb2bd662Svikram (void) rmdir(tmpmnt); 4753eb2bd662Svikram (void) fclose(tfp); 4754eb2bd662Svikram (void) unlink(UFS_SIGNATURE_LIST".tmp"); 4755eb2bd662Svikram BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 4756eb2bd662Svikram return (-1); 4757eb2bd662Svikram } 4758eb2bd662Svikram 4759eb2bd662Svikram static char * 4760eb2bd662Svikram create_ufs_sign(void) 4761eb2bd662Svikram { 4762eb2bd662Svikram struct stat sb; 4763eb2bd662Svikram int signnum = -1; 4764eb2bd662Svikram char tmpsign[MAXNAMELEN + 1]; 4765eb2bd662Svikram char *numstr; 4766eb2bd662Svikram int i; 4767eb2bd662Svikram FILE *tfp; 4768eb2bd662Svikram int ret; 4769eb2bd662Svikram int error; 4770eb2bd662Svikram const char *fcn = "create_ufs_sign()"; 4771eb2bd662Svikram 4772eb2bd662Svikram bam_print(SEARCHING_UFS_SIGN); 4773eb2bd662Svikram 4774eb2bd662Svikram ret = FindAllUfsSignatures(); 4775eb2bd662Svikram INJECT_ERROR1("FIND_ALL_UFS", ret = -1); 4776eb2bd662Svikram if (ret == -1) { 4777eb2bd662Svikram bam_error(ERR_FIND_UFS_SIGN); 4778eb2bd662Svikram return (NULL); 4779eb2bd662Svikram } 4780eb2bd662Svikram 4781eb2bd662Svikram /* Make sure the list exists and is owned by root */ 4782eb2bd662Svikram INJECT_ERROR1("SIGNLIST_NOT_CREATED", 4783eb2bd662Svikram (void) unlink(UFS_SIGNATURE_LIST)); 4784eb2bd662Svikram if (stat(UFS_SIGNATURE_LIST, &sb) == -1 || sb.st_uid != 0) { 4785eb2bd662Svikram (void) unlink(UFS_SIGNATURE_LIST); 4786eb2bd662Svikram bam_error(UFS_SIGNATURE_LIST_MISS, UFS_SIGNATURE_LIST); 4787eb2bd662Svikram return (NULL); 4788eb2bd662Svikram } 4789eb2bd662Svikram 4790eb2bd662Svikram if (sb.st_size == 0) { 4791eb2bd662Svikram bam_print(GRUBSIGN_UFS_NONE); 4792eb2bd662Svikram i = 0; 4793eb2bd662Svikram goto found; 4794eb2bd662Svikram } 4795eb2bd662Svikram 4796eb2bd662Svikram /* The signature list was sorted when it was created */ 4797eb2bd662Svikram tfp = fopen(UFS_SIGNATURE_LIST, "r"); 4798eb2bd662Svikram error = errno; 4799eb2bd662Svikram INJECT_ERROR1("FOPEN_SIGN_LIST", tfp = NULL); 4800eb2bd662Svikram if (tfp == NULL) { 4801eb2bd662Svikram bam_error(UFS_SIGNATURE_LIST_OPENERR, 4802eb2bd662Svikram UFS_SIGNATURE_LIST, strerror(error)); 4803eb2bd662Svikram (void) unlink(UFS_SIGNATURE_LIST); 4804eb2bd662Svikram return (NULL); 4805eb2bd662Svikram } 4806eb2bd662Svikram 4807eb2bd662Svikram for (i = 0; s_fgets(tmpsign, sizeof (tmpsign), tfp); i++) { 4808eb2bd662Svikram 4809eb2bd662Svikram if (strncmp(tmpsign, GRUBSIGN_UFS_PREFIX, 4810eb2bd662Svikram strlen(GRUBSIGN_UFS_PREFIX)) != 0) { 4811eb2bd662Svikram (void) fclose(tfp); 4812eb2bd662Svikram (void) unlink(UFS_SIGNATURE_LIST); 4813eb2bd662Svikram bam_error(UFS_BADSIGN, tmpsign); 4814eb2bd662Svikram return (NULL); 4815eb2bd662Svikram } 4816eb2bd662Svikram numstr = tmpsign + strlen(GRUBSIGN_UFS_PREFIX); 4817eb2bd662Svikram 4818eb2bd662Svikram if (numstr[0] == '\0' || !isdigit(numstr[0])) { 4819eb2bd662Svikram (void) fclose(tfp); 4820eb2bd662Svikram (void) unlink(UFS_SIGNATURE_LIST); 4821eb2bd662Svikram bam_error(UFS_BADSIGN, tmpsign); 4822eb2bd662Svikram return (NULL); 4823eb2bd662Svikram } 4824eb2bd662Svikram 4825eb2bd662Svikram signnum = atoi(numstr); 4826eb2bd662Svikram INJECT_ERROR1("NEGATIVE_SIGN", signnum = -1); 4827eb2bd662Svikram if (signnum < 0) { 4828eb2bd662Svikram (void) fclose(tfp); 4829eb2bd662Svikram (void) unlink(UFS_SIGNATURE_LIST); 4830eb2bd662Svikram bam_error(UFS_BADSIGN, tmpsign); 4831eb2bd662Svikram return (NULL); 4832eb2bd662Svikram } 4833eb2bd662Svikram 4834eb2bd662Svikram if (i != signnum) { 4835eb2bd662Svikram BAM_DPRINTF((D_FOUND_HOLE_SIGNLIST, fcn, i)); 4836eb2bd662Svikram break; 4837eb2bd662Svikram } 4838eb2bd662Svikram } 4839eb2bd662Svikram 4840eb2bd662Svikram (void) fclose(tfp); 4841eb2bd662Svikram 4842eb2bd662Svikram found: 4843eb2bd662Svikram (void) snprintf(tmpsign, sizeof (tmpsign), "rootfs%d", i); 4844eb2bd662Svikram 4845eb2bd662Svikram /* add the ufs signature to the /var/run list of signatures */ 4846eb2bd662Svikram ret = ufs_add_to_sign_list(tmpsign); 4847eb2bd662Svikram INJECT_ERROR1("UFS_ADD_TO_SIGN_LIST", ret = -1); 4848eb2bd662Svikram if (ret == -1) { 4849eb2bd662Svikram (void) unlink(UFS_SIGNATURE_LIST); 4850eb2bd662Svikram bam_error(FAILED_ADD_SIGNLIST, tmpsign); 4851eb2bd662Svikram return (NULL); 4852eb2bd662Svikram } 4853eb2bd662Svikram 4854eb2bd662Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 4855eb2bd662Svikram 4856eb2bd662Svikram return (s_strdup(tmpsign)); 4857eb2bd662Svikram } 4858eb2bd662Svikram 4859eb2bd662Svikram static char * 4860eb2bd662Svikram get_fstype(char *osroot) 4861eb2bd662Svikram { 4862eb2bd662Svikram FILE *mntfp; 4863eb2bd662Svikram struct mnttab mp = {0}; 4864eb2bd662Svikram struct mnttab mpref = {0}; 4865eb2bd662Svikram int error; 4866eb2bd662Svikram int ret; 4867eb2bd662Svikram const char *fcn = "get_fstype()"; 4868eb2bd662Svikram 4869eb2bd662Svikram INJECT_ERROR1("GET_FSTYPE_OSROOT", osroot = NULL); 4870eb2bd662Svikram if (osroot == NULL) { 4871eb2bd662Svikram bam_error(GET_FSTYPE_ARGS); 4872eb2bd662Svikram return (NULL); 4873eb2bd662Svikram } 4874eb2bd662Svikram 4875eb2bd662Svikram mntfp = fopen(MNTTAB, "r"); 4876eb2bd662Svikram error = errno; 4877eb2bd662Svikram INJECT_ERROR1("GET_FSTYPE_FOPEN", mntfp = NULL); 4878eb2bd662Svikram if (mntfp == NULL) { 4879eb2bd662Svikram bam_error(OPEN_FAIL, MNTTAB, strerror(error)); 4880eb2bd662Svikram return (NULL); 4881eb2bd662Svikram } 4882eb2bd662Svikram 4883eb2bd662Svikram if (*osroot == '\0') 4884eb2bd662Svikram mpref.mnt_mountp = "/"; 4885eb2bd662Svikram else 4886eb2bd662Svikram mpref.mnt_mountp = osroot; 4887eb2bd662Svikram 4888eb2bd662Svikram ret = getmntany(mntfp, &mp, &mpref); 4889eb2bd662Svikram INJECT_ERROR1("GET_FSTYPE_GETMNTANY", ret = 1); 4890eb2bd662Svikram if (ret != 0) { 4891eb2bd662Svikram bam_error(MNTTAB_MNTPT_NOT_FOUND, osroot, MNTTAB); 4892eb2bd662Svikram (void) fclose(mntfp); 4893eb2bd662Svikram return (NULL); 4894eb2bd662Svikram } 4895eb2bd662Svikram (void) fclose(mntfp); 4896eb2bd662Svikram 4897eb2bd662Svikram INJECT_ERROR1("GET_FSTYPE_NULL", mp.mnt_fstype = NULL); 4898eb2bd662Svikram if (mp.mnt_fstype == NULL) { 4899eb2bd662Svikram bam_error(MNTTAB_FSTYPE_NULL, osroot); 4900eb2bd662Svikram return (NULL); 4901eb2bd662Svikram } 4902eb2bd662Svikram 4903eb2bd662Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 4904eb2bd662Svikram 4905eb2bd662Svikram return (s_strdup(mp.mnt_fstype)); 4906eb2bd662Svikram } 4907eb2bd662Svikram 4908eb2bd662Svikram static char * 4909eb2bd662Svikram create_zfs_sign(char *osdev) 4910eb2bd662Svikram { 4911eb2bd662Svikram char tmpsign[PATH_MAX]; 4912eb2bd662Svikram char *pool; 4913eb2bd662Svikram const char *fcn = "create_zfs_sign()"; 4914eb2bd662Svikram 4915eb2bd662Svikram BAM_DPRINTF((D_FUNC_ENTRY1, fcn, osdev)); 4916eb2bd662Svikram 4917eb2bd662Svikram /* 4918eb2bd662Svikram * First find the pool name 4919eb2bd662Svikram */ 4920eb2bd662Svikram pool = get_pool(osdev); 4921eb2bd662Svikram INJECT_ERROR1("CREATE_ZFS_SIGN_GET_POOL", pool = NULL); 4922eb2bd662Svikram if (pool == NULL) { 4923eb2bd662Svikram bam_error(GET_POOL_FAILED, osdev); 4924eb2bd662Svikram return (NULL); 4925eb2bd662Svikram } 4926eb2bd662Svikram 4927eb2bd662Svikram (void) snprintf(tmpsign, sizeof (tmpsign), "pool_%s", pool); 4928eb2bd662Svikram 4929eb2bd662Svikram BAM_DPRINTF((D_CREATED_ZFS_SIGN, fcn, tmpsign)); 4930eb2bd662Svikram 4931eb2bd662Svikram free(pool); 4932eb2bd662Svikram 4933eb2bd662Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 4934eb2bd662Svikram 4935eb2bd662Svikram return (s_strdup(tmpsign)); 4936eb2bd662Svikram } 4937eb2bd662Svikram 4938eb2bd662Svikram static char * 4939eb2bd662Svikram create_new_sign(char *osdev, char *fstype) 4940eb2bd662Svikram { 4941eb2bd662Svikram char *sign; 4942eb2bd662Svikram const char *fcn = "create_new_sign()"; 4943eb2bd662Svikram 4944eb2bd662Svikram INJECT_ERROR1("NEW_SIGN_FSTYPE", fstype = "foofs"); 4945eb2bd662Svikram 4946eb2bd662Svikram if (strcmp(fstype, "zfs") == 0) { 4947eb2bd662Svikram BAM_DPRINTF((D_CREATE_NEW_ZFS, fcn)); 4948eb2bd662Svikram sign = create_zfs_sign(osdev); 4949eb2bd662Svikram } else if (strcmp(fstype, "ufs") == 0) { 4950eb2bd662Svikram BAM_DPRINTF((D_CREATE_NEW_UFS, fcn)); 4951eb2bd662Svikram sign = create_ufs_sign(); 4952eb2bd662Svikram } else { 4953eb2bd662Svikram bam_error(GRUBSIGN_NOTSUP, fstype); 4954eb2bd662Svikram sign = NULL; 4955eb2bd662Svikram } 4956eb2bd662Svikram 4957eb2bd662Svikram BAM_DPRINTF((D_CREATED_NEW_SIGN, fcn, sign ? sign : "<NULL>")); 4958eb2bd662Svikram return (sign); 4959eb2bd662Svikram } 4960eb2bd662Svikram 4961eb2bd662Svikram static int 4962eb2bd662Svikram set_backup_common(char *mntpt, char *sign) 4963eb2bd662Svikram { 4964eb2bd662Svikram FILE *bfp; 4965eb2bd662Svikram char backup[PATH_MAX]; 4966eb2bd662Svikram char tmpsign[PATH_MAX]; 4967eb2bd662Svikram int error; 4968eb2bd662Svikram char *bdir; 4969eb2bd662Svikram char *backup_dup; 4970eb2bd662Svikram struct stat sb; 4971eb2bd662Svikram int ret; 4972eb2bd662Svikram const char *fcn = "set_backup_common()"; 4973eb2bd662Svikram 4974eb2bd662Svikram (void) snprintf(backup, sizeof (backup), "%s%s", 4975eb2bd662Svikram mntpt, GRUBSIGN_BACKUP); 4976eb2bd662Svikram 4977eb2bd662Svikram /* First read the backup */ 4978eb2bd662Svikram bfp = fopen(backup, "r"); 4979eb2bd662Svikram if (bfp != NULL) { 4980eb2bd662Svikram while (s_fgets(tmpsign, sizeof (tmpsign), bfp)) { 4981eb2bd662Svikram if (strcmp(tmpsign, sign) == 0) { 4982eb2bd662Svikram BAM_DPRINTF((D_FOUND_IN_BACKUP, fcn, sign)); 4983eb2bd662Svikram (void) fclose(bfp); 4984eb2bd662Svikram return (0); 4985eb2bd662Svikram } 4986eb2bd662Svikram } 4987eb2bd662Svikram (void) fclose(bfp); 4988eb2bd662Svikram BAM_DPRINTF((D_NOT_FOUND_IN_EXIST_BACKUP, fcn, sign)); 4989eb2bd662Svikram } else { 4990eb2bd662Svikram BAM_DPRINTF((D_BACKUP_NOT_EXIST, fcn, backup)); 4991eb2bd662Svikram } 4992eb2bd662Svikram 4993eb2bd662Svikram /* 4994eb2bd662Svikram * Didn't find the correct signature. First create 4995eb2bd662Svikram * the directory if necessary. 4996eb2bd662Svikram */ 4997eb2bd662Svikram 4998eb2bd662Svikram /* dirname() modifies its argument so dup it */ 4999eb2bd662Svikram backup_dup = s_strdup(backup); 5000eb2bd662Svikram bdir = dirname(backup_dup); 5001eb2bd662Svikram assert(bdir); 5002eb2bd662Svikram 5003eb2bd662Svikram ret = stat(bdir, &sb); 5004eb2bd662Svikram INJECT_ERROR1("SET_BACKUP_STAT", ret = -1); 5005eb2bd662Svikram if (ret == -1) { 5006eb2bd662Svikram BAM_DPRINTF((D_BACKUP_DIR_NOEXIST, fcn, bdir)); 5007eb2bd662Svikram ret = mkdirp(bdir, 0755); 5008eb2bd662Svikram error = errno; 5009eb2bd662Svikram INJECT_ERROR1("SET_BACKUP_MKDIRP", ret = -1); 5010eb2bd662Svikram if (ret == -1) { 5011eb2bd662Svikram bam_error(GRUBSIGN_BACKUP_MKDIRERR, 5012eb2bd662Svikram GRUBSIGN_BACKUP, strerror(error)); 5013eb2bd662Svikram free(backup_dup); 5014eb2bd662Svikram return (-1); 5015eb2bd662Svikram } 5016eb2bd662Svikram } 5017eb2bd662Svikram free(backup_dup); 5018eb2bd662Svikram 5019eb2bd662Svikram /* 5020eb2bd662Svikram * Open the backup in append mode to add the correct 5021eb2bd662Svikram * signature; 5022eb2bd662Svikram */ 5023eb2bd662Svikram bfp = fopen(backup, "a"); 5024eb2bd662Svikram error = errno; 5025eb2bd662Svikram INJECT_ERROR1("SET_BACKUP_FOPEN_A", bfp = NULL); 5026eb2bd662Svikram if (bfp == NULL) { 5027eb2bd662Svikram bam_error(GRUBSIGN_BACKUP_OPENERR, 5028eb2bd662Svikram GRUBSIGN_BACKUP, strerror(error)); 5029eb2bd662Svikram return (-1); 5030eb2bd662Svikram } 5031eb2bd662Svikram 5032eb2bd662Svikram (void) snprintf(tmpsign, sizeof (tmpsign), "%s\n", sign); 5033eb2bd662Svikram 5034eb2bd662Svikram ret = fputs(tmpsign, bfp); 5035eb2bd662Svikram error = errno; 5036eb2bd662Svikram INJECT_ERROR1("SET_BACKUP_FPUTS", ret = 0); 5037eb2bd662Svikram if (ret != strlen(tmpsign)) { 5038eb2bd662Svikram bam_error(GRUBSIGN_BACKUP_WRITEERR, 5039eb2bd662Svikram GRUBSIGN_BACKUP, strerror(error)); 5040eb2bd662Svikram (void) fclose(bfp); 5041eb2bd662Svikram return (-1); 5042eb2bd662Svikram } 5043eb2bd662Svikram 5044eb2bd662Svikram (void) fclose(bfp); 5045eb2bd662Svikram 5046eb2bd662Svikram if (bam_verbose) 5047eb2bd662Svikram bam_print(GRUBSIGN_BACKUP_UPDATED, GRUBSIGN_BACKUP); 5048eb2bd662Svikram 5049eb2bd662Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 5050eb2bd662Svikram 5051eb2bd662Svikram return (0); 5052eb2bd662Svikram } 5053eb2bd662Svikram 5054eb2bd662Svikram static int 5055eb2bd662Svikram set_backup_ufs(char *osroot, char *sign) 5056eb2bd662Svikram { 5057eb2bd662Svikram const char *fcn = "set_backup_ufs()"; 5058eb2bd662Svikram 5059eb2bd662Svikram BAM_DPRINTF((D_FUNC_ENTRY2, fcn, osroot, sign)); 5060eb2bd662Svikram return (set_backup_common(osroot, sign)); 5061eb2bd662Svikram } 5062eb2bd662Svikram 5063eb2bd662Svikram static int 5064eb2bd662Svikram set_backup_zfs(char *osdev, char *sign) 5065eb2bd662Svikram { 5066eb2bd662Svikram char *pool; 5067eb2bd662Svikram char *mntpt; 5068eb2bd662Svikram zfs_mnted_t mnted; 5069eb2bd662Svikram int ret; 5070eb2bd662Svikram const char *fcn = "set_backup_zfs()"; 5071eb2bd662Svikram 5072eb2bd662Svikram BAM_DPRINTF((D_FUNC_ENTRY2, fcn, osdev, sign)); 5073eb2bd662Svikram 5074eb2bd662Svikram pool = get_pool(osdev); 5075eb2bd662Svikram INJECT_ERROR1("SET_BACKUP_GET_POOL", pool = NULL); 5076eb2bd662Svikram if (pool == NULL) { 5077eb2bd662Svikram bam_error(GET_POOL_FAILED, osdev); 5078eb2bd662Svikram return (-1); 5079eb2bd662Svikram } 5080eb2bd662Svikram 5081eb2bd662Svikram mntpt = mount_top_dataset(pool, &mnted); 5082eb2bd662Svikram INJECT_ERROR1("SET_BACKUP_MOUNT_DATASET", mntpt = NULL); 5083eb2bd662Svikram if (mntpt == NULL) { 5084eb2bd662Svikram bam_error(FAIL_MNT_TOP_DATASET, pool); 5085eb2bd662Svikram free(pool); 5086eb2bd662Svikram return (-1); 5087eb2bd662Svikram } 5088eb2bd662Svikram 5089eb2bd662Svikram ret = set_backup_common(mntpt, sign); 5090eb2bd662Svikram 5091eb2bd662Svikram (void) umount_top_dataset(pool, mnted, mntpt); 5092eb2bd662Svikram 5093eb2bd662Svikram free(pool); 5094eb2bd662Svikram 5095eb2bd662Svikram INJECT_ERROR1("SET_BACKUP_ZFS_FAIL", ret = 1); 5096eb2bd662Svikram if (ret == 0) { 5097eb2bd662Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 5098eb2bd662Svikram } else { 5099eb2bd662Svikram BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 5100eb2bd662Svikram } 5101eb2bd662Svikram 5102eb2bd662Svikram return (ret); 5103eb2bd662Svikram } 5104eb2bd662Svikram 5105eb2bd662Svikram static int 5106eb2bd662Svikram set_backup(char *osroot, char *osdev, char *sign, char *fstype) 5107eb2bd662Svikram { 5108eb2bd662Svikram const char *fcn = "set_backup()"; 5109eb2bd662Svikram int ret; 5110eb2bd662Svikram 5111eb2bd662Svikram INJECT_ERROR1("SET_BACKUP_FSTYPE", fstype = "foofs"); 5112eb2bd662Svikram 5113eb2bd662Svikram if (strcmp(fstype, "ufs") == 0) { 5114eb2bd662Svikram BAM_DPRINTF((D_SET_BACKUP_UFS, fcn)); 5115eb2bd662Svikram ret = set_backup_ufs(osroot, sign); 5116eb2bd662Svikram } else if (strcmp(fstype, "zfs") == 0) { 5117eb2bd662Svikram BAM_DPRINTF((D_SET_BACKUP_ZFS, fcn)); 5118eb2bd662Svikram ret = set_backup_zfs(osdev, sign); 5119eb2bd662Svikram } else { 5120eb2bd662Svikram bam_error(GRUBSIGN_NOTSUP, fstype); 5121eb2bd662Svikram ret = -1; 5122eb2bd662Svikram } 5123eb2bd662Svikram 5124eb2bd662Svikram if (ret == 0) { 5125eb2bd662Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 5126eb2bd662Svikram } else { 5127eb2bd662Svikram BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 5128eb2bd662Svikram } 5129eb2bd662Svikram 5130eb2bd662Svikram return (ret); 5131eb2bd662Svikram } 5132eb2bd662Svikram 5133eb2bd662Svikram static int 5134eb2bd662Svikram set_primary_common(char *mntpt, char *sign) 5135eb2bd662Svikram { 5136eb2bd662Svikram char signfile[PATH_MAX]; 5137eb2bd662Svikram char signdir[PATH_MAX]; 5138eb2bd662Svikram struct stat sb; 5139eb2bd662Svikram int fd; 5140eb2bd662Svikram int error; 5141eb2bd662Svikram int ret; 5142eb2bd662Svikram const char *fcn = "set_primary_common()"; 5143eb2bd662Svikram 5144eb2bd662Svikram (void) snprintf(signfile, sizeof (signfile), "%s/%s/%s", 5145eb2bd662Svikram mntpt, GRUBSIGN_DIR, sign); 5146eb2bd662Svikram 5147eb2bd662Svikram if (stat(signfile, &sb) != -1) { 5148eb2bd662Svikram if (bam_verbose) 5149eb2bd662Svikram bam_print(PRIMARY_SIGN_EXISTS, sign); 5150eb2bd662Svikram return (0); 5151eb2bd662Svikram } else { 5152eb2bd662Svikram BAM_DPRINTF((D_PRIMARY_NOT_EXIST, fcn, signfile)); 5153eb2bd662Svikram } 5154eb2bd662Svikram 5155eb2bd662Svikram (void) snprintf(signdir, sizeof (signdir), "%s/%s", 5156eb2bd662Svikram mntpt, GRUBSIGN_DIR); 5157eb2bd662Svikram 5158eb2bd662Svikram if (stat(signdir, &sb) == -1) { 5159eb2bd662Svikram BAM_DPRINTF((D_PRIMARY_DIR_NOEXIST, fcn, signdir)); 5160eb2bd662Svikram ret = mkdirp(signdir, 0755); 5161eb2bd662Svikram error = errno; 5162eb2bd662Svikram INJECT_ERROR1("SET_PRIMARY_MKDIRP", ret = -1); 5163eb2bd662Svikram if (ret == -1) { 5164eb2bd662Svikram bam_error(GRUBSIGN_MKDIR_ERR, signdir, strerror(errno)); 5165eb2bd662Svikram return (-1); 5166eb2bd662Svikram } 5167eb2bd662Svikram } 5168eb2bd662Svikram 5169eb2bd662Svikram fd = open(signfile, O_RDWR|O_CREAT|O_TRUNC, 0444); 5170eb2bd662Svikram error = errno; 5171eb2bd662Svikram INJECT_ERROR1("PRIMARY_SIGN_CREAT", fd = -1); 5172eb2bd662Svikram if (fd == -1) { 5173eb2bd662Svikram bam_error(GRUBSIGN_PRIMARY_CREATERR, signfile, strerror(error)); 5174eb2bd662Svikram return (-1); 5175eb2bd662Svikram } 5176eb2bd662Svikram 5177eb2bd662Svikram ret = fsync(fd); 5178eb2bd662Svikram error = errno; 5179eb2bd662Svikram INJECT_ERROR1("PRIMARY_FSYNC", ret = -1); 5180eb2bd662Svikram if (ret != 0) { 5181eb2bd662Svikram bam_error(GRUBSIGN_PRIMARY_SYNCERR, signfile, strerror(error)); 5182eb2bd662Svikram } 5183eb2bd662Svikram 5184eb2bd662Svikram (void) close(fd); 5185eb2bd662Svikram 5186eb2bd662Svikram if (bam_verbose) 5187eb2bd662Svikram bam_print(GRUBSIGN_CREATED_PRIMARY, signfile); 5188eb2bd662Svikram 5189eb2bd662Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 5190eb2bd662Svikram 5191eb2bd662Svikram return (0); 5192eb2bd662Svikram } 5193eb2bd662Svikram 5194eb2bd662Svikram static int 5195eb2bd662Svikram set_primary_ufs(char *osroot, char *sign) 5196eb2bd662Svikram { 5197eb2bd662Svikram const char *fcn = "set_primary_ufs()"; 5198eb2bd662Svikram 5199eb2bd662Svikram BAM_DPRINTF((D_FUNC_ENTRY2, fcn, osroot, sign)); 5200eb2bd662Svikram return (set_primary_common(osroot, sign)); 5201eb2bd662Svikram } 5202eb2bd662Svikram 5203eb2bd662Svikram static int 5204eb2bd662Svikram set_primary_zfs(char *osdev, char *sign) 5205eb2bd662Svikram { 5206eb2bd662Svikram char *pool; 5207eb2bd662Svikram char *mntpt; 5208eb2bd662Svikram zfs_mnted_t mnted; 5209eb2bd662Svikram int ret; 5210eb2bd662Svikram const char *fcn = "set_primary_zfs()"; 5211eb2bd662Svikram 5212eb2bd662Svikram BAM_DPRINTF((D_FUNC_ENTRY2, fcn, osdev, sign)); 5213eb2bd662Svikram 5214eb2bd662Svikram pool = get_pool(osdev); 5215eb2bd662Svikram INJECT_ERROR1("SET_PRIMARY_ZFS_GET_POOL", pool = NULL); 5216eb2bd662Svikram if (pool == NULL) { 5217eb2bd662Svikram bam_error(GET_POOL_FAILED, osdev); 5218eb2bd662Svikram return (-1); 5219eb2bd662Svikram } 5220eb2bd662Svikram 5221eb2bd662Svikram /* Pool name must exist in the sign */ 5222eb2bd662Svikram ret = (strstr(sign, pool) != NULL); 5223eb2bd662Svikram INJECT_ERROR1("SET_PRIMARY_ZFS_POOL_SIGN_INCOMPAT", ret = 0); 5224eb2bd662Svikram if (ret == 0) { 5225eb2bd662Svikram bam_error(POOL_SIGN_INCOMPAT, pool, sign); 5226eb2bd662Svikram free(pool); 5227eb2bd662Svikram return (-1); 5228eb2bd662Svikram } 5229eb2bd662Svikram 5230eb2bd662Svikram mntpt = mount_top_dataset(pool, &mnted); 5231eb2bd662Svikram INJECT_ERROR1("SET_PRIMARY_ZFS_MOUNT_DATASET", mntpt = NULL); 5232eb2bd662Svikram if (mntpt == NULL) { 5233eb2bd662Svikram bam_error(FAIL_MNT_TOP_DATASET, pool); 5234eb2bd662Svikram free(pool); 5235eb2bd662Svikram return (-1); 5236eb2bd662Svikram } 5237eb2bd662Svikram 5238eb2bd662Svikram ret = set_primary_common(mntpt, sign); 5239eb2bd662Svikram 5240eb2bd662Svikram (void) umount_top_dataset(pool, mnted, mntpt); 5241eb2bd662Svikram 5242eb2bd662Svikram free(pool); 5243eb2bd662Svikram 5244eb2bd662Svikram INJECT_ERROR1("SET_PRIMARY_ZFS_FAIL", ret = 1); 5245eb2bd662Svikram if (ret == 0) { 5246eb2bd662Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 5247eb2bd662Svikram } else { 5248eb2bd662Svikram BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 5249eb2bd662Svikram } 5250eb2bd662Svikram 5251eb2bd662Svikram return (ret); 5252eb2bd662Svikram } 5253eb2bd662Svikram 5254eb2bd662Svikram static int 5255eb2bd662Svikram set_primary(char *osroot, char *osdev, char *sign, char *fstype) 5256eb2bd662Svikram { 5257eb2bd662Svikram const char *fcn = "set_primary()"; 5258eb2bd662Svikram int ret; 5259eb2bd662Svikram 5260eb2bd662Svikram INJECT_ERROR1("SET_PRIMARY_FSTYPE", fstype = "foofs"); 5261eb2bd662Svikram if (strcmp(fstype, "ufs") == 0) { 5262eb2bd662Svikram BAM_DPRINTF((D_SET_PRIMARY_UFS, fcn)); 5263eb2bd662Svikram ret = set_primary_ufs(osroot, sign); 5264eb2bd662Svikram } else if (strcmp(fstype, "zfs") == 0) { 5265eb2bd662Svikram BAM_DPRINTF((D_SET_PRIMARY_ZFS, fcn)); 5266eb2bd662Svikram ret = set_primary_zfs(osdev, sign); 5267eb2bd662Svikram } else { 5268eb2bd662Svikram bam_error(GRUBSIGN_NOTSUP, fstype); 5269eb2bd662Svikram ret = -1; 5270eb2bd662Svikram } 5271eb2bd662Svikram 5272eb2bd662Svikram if (ret == 0) { 5273eb2bd662Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 5274eb2bd662Svikram } else { 5275eb2bd662Svikram BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 5276eb2bd662Svikram } 5277eb2bd662Svikram 5278eb2bd662Svikram return (ret); 5279eb2bd662Svikram } 5280eb2bd662Svikram 5281eb2bd662Svikram static int 5282eb2bd662Svikram ufs_add_to_sign_list(char *sign) 5283eb2bd662Svikram { 5284eb2bd662Svikram FILE *tfp; 5285eb2bd662Svikram char signline[MAXNAMELEN]; 5286eb2bd662Svikram char cmd[PATH_MAX]; 5287eb2bd662Svikram int ret; 5288eb2bd662Svikram int error; 5289eb2bd662Svikram const char *fcn = "ufs_add_to_sign_list()"; 5290eb2bd662Svikram 5291eb2bd662Svikram INJECT_ERROR1("ADD_TO_SIGN_LIST_NOT_UFS", sign = "pool_rpool5"); 5292eb2bd662Svikram if (strncmp(sign, GRUBSIGN_UFS_PREFIX, 5293eb2bd662Svikram strlen(GRUBSIGN_UFS_PREFIX)) != 0) { 5294eb2bd662Svikram bam_error(INVALID_UFS_SIGN, sign); 5295eb2bd662Svikram (void) unlink(UFS_SIGNATURE_LIST); 5296eb2bd662Svikram return (-1); 5297eb2bd662Svikram } 5298eb2bd662Svikram 5299eb2bd662Svikram /* 5300eb2bd662Svikram * most failures in this routine are not a fatal error 5301eb2bd662Svikram * We simply unlink the /var/run file and continue 5302eb2bd662Svikram */ 5303eb2bd662Svikram 5304eb2bd662Svikram ret = rename(UFS_SIGNATURE_LIST, UFS_SIGNATURE_LIST".tmp"); 5305eb2bd662Svikram error = errno; 5306eb2bd662Svikram INJECT_ERROR1("ADD_TO_SIGN_LIST_RENAME", ret = -1); 5307eb2bd662Svikram if (ret == -1) { 5308eb2bd662Svikram bam_error(RENAME_FAIL, UFS_SIGNATURE_LIST".tmp", 5309eb2bd662Svikram strerror(error)); 5310eb2bd662Svikram (void) unlink(UFS_SIGNATURE_LIST); 5311eb2bd662Svikram return (0); 5312eb2bd662Svikram } 5313eb2bd662Svikram 5314eb2bd662Svikram tfp = fopen(UFS_SIGNATURE_LIST".tmp", "a"); 5315eb2bd662Svikram error = errno; 5316eb2bd662Svikram INJECT_ERROR1("ADD_TO_SIGN_LIST_FOPEN", tfp = NULL); 5317eb2bd662Svikram if (tfp == NULL) { 5318eb2bd662Svikram bam_error(OPEN_FAIL, UFS_SIGNATURE_LIST".tmp", strerror(error)); 5319eb2bd662Svikram (void) unlink(UFS_SIGNATURE_LIST".tmp"); 5320eb2bd662Svikram return (0); 5321eb2bd662Svikram } 5322eb2bd662Svikram 5323eb2bd662Svikram (void) snprintf(signline, sizeof (signline), "%s\n", sign); 5324eb2bd662Svikram 5325eb2bd662Svikram ret = fputs(signline, tfp); 5326eb2bd662Svikram error = errno; 5327eb2bd662Svikram INJECT_ERROR1("ADD_TO_SIGN_LIST_FPUTS", ret = 0); 5328eb2bd662Svikram if (ret != strlen(signline)) { 5329eb2bd662Svikram bam_error(SIGN_LIST_FPUTS_ERR, sign, strerror(error)); 5330eb2bd662Svikram (void) fclose(tfp); 5331eb2bd662Svikram (void) unlink(UFS_SIGNATURE_LIST".tmp"); 5332eb2bd662Svikram return (0); 5333eb2bd662Svikram } 5334eb2bd662Svikram 5335eb2bd662Svikram ret = fclose(tfp); 5336eb2bd662Svikram error = errno; 5337eb2bd662Svikram INJECT_ERROR1("ADD_TO_SIGN_LIST_FCLOSE", ret = EOF); 5338eb2bd662Svikram if (ret == EOF) { 5339eb2bd662Svikram bam_error(CLOSE_FAIL, UFS_SIGNATURE_LIST".tmp", 5340eb2bd662Svikram strerror(error)); 5341eb2bd662Svikram (void) unlink(UFS_SIGNATURE_LIST".tmp"); 5342eb2bd662Svikram return (0); 5343eb2bd662Svikram } 5344eb2bd662Svikram 5345eb2bd662Svikram /* Sort the list again */ 5346eb2bd662Svikram (void) snprintf(cmd, sizeof (cmd), 5347eb2bd662Svikram "/usr/bin/sort -u %s.tmp > %s.sorted", 5348eb2bd662Svikram UFS_SIGNATURE_LIST, UFS_SIGNATURE_LIST); 5349eb2bd662Svikram 5350eb2bd662Svikram ret = exec_cmd(cmd, NULL); 5351eb2bd662Svikram INJECT_ERROR1("ADD_TO_SIGN_LIST_SORT", ret = 1); 5352eb2bd662Svikram if (ret != 0) { 5353eb2bd662Svikram bam_error(GRUBSIGN_SORT_FAILED); 5354eb2bd662Svikram (void) unlink(UFS_SIGNATURE_LIST".sorted"); 5355eb2bd662Svikram (void) unlink(UFS_SIGNATURE_LIST".tmp"); 5356eb2bd662Svikram return (0); 5357eb2bd662Svikram } 5358eb2bd662Svikram 5359eb2bd662Svikram (void) unlink(UFS_SIGNATURE_LIST".tmp"); 5360eb2bd662Svikram 5361eb2bd662Svikram ret = rename(UFS_SIGNATURE_LIST".sorted", UFS_SIGNATURE_LIST); 5362eb2bd662Svikram error = errno; 5363eb2bd662Svikram INJECT_ERROR1("ADD_TO_SIGN_LIST_RENAME2", ret = -1); 5364eb2bd662Svikram if (ret == -1) { 5365eb2bd662Svikram bam_error(RENAME_FAIL, UFS_SIGNATURE_LIST, strerror(error)); 5366eb2bd662Svikram (void) unlink(UFS_SIGNATURE_LIST".sorted"); 5367eb2bd662Svikram return (0); 5368eb2bd662Svikram } 5369eb2bd662Svikram 5370eb2bd662Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 5371eb2bd662Svikram 5372eb2bd662Svikram return (0); 5373eb2bd662Svikram } 5374eb2bd662Svikram 5375eb2bd662Svikram static int 5376eb2bd662Svikram set_signature(char *osroot, char *osdev, char *sign, char *fstype) 5377eb2bd662Svikram { 5378eb2bd662Svikram int ret; 5379eb2bd662Svikram const char *fcn = "set_signature()"; 5380eb2bd662Svikram 5381eb2bd662Svikram BAM_DPRINTF((D_FUNC_ENTRY4, fcn, osroot, osdev, sign, fstype)); 5382eb2bd662Svikram 5383eb2bd662Svikram ret = set_backup(osroot, osdev, sign, fstype); 5384eb2bd662Svikram INJECT_ERROR1("SET_SIGNATURE_BACKUP", ret = -1); 5385eb2bd662Svikram if (ret == -1) { 5386eb2bd662Svikram BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 5387eb2bd662Svikram bam_error(SET_BACKUP_FAILED, sign, osroot, osdev); 5388eb2bd662Svikram return (-1); 5389eb2bd662Svikram } 5390eb2bd662Svikram 5391eb2bd662Svikram ret = set_primary(osroot, osdev, sign, fstype); 5392eb2bd662Svikram INJECT_ERROR1("SET_SIGNATURE_PRIMARY", ret = -1); 5393eb2bd662Svikram 5394eb2bd662Svikram if (ret == 0) { 5395eb2bd662Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 5396eb2bd662Svikram } else { 5397eb2bd662Svikram BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 5398eb2bd662Svikram bam_error(SET_PRIMARY_FAILED, sign, osroot, osdev); 5399eb2bd662Svikram 5400eb2bd662Svikram } 5401eb2bd662Svikram return (ret); 5402eb2bd662Svikram } 5403eb2bd662Svikram 5404eb2bd662Svikram char * 5405eb2bd662Svikram get_grubsign(char *osroot, char *osdev) 5406eb2bd662Svikram { 5407eb2bd662Svikram char *grubsign; /* (<sign>,#,#) */ 5408eb2bd662Svikram char *slice; 5409eb2bd662Svikram int fdiskpart; 5410eb2bd662Svikram char *sign; 5411eb2bd662Svikram char *fstype; 5412eb2bd662Svikram int ret; 5413eb2bd662Svikram const char *fcn = "get_grubsign()"; 5414eb2bd662Svikram 5415eb2bd662Svikram BAM_DPRINTF((D_FUNC_ENTRY2, fcn, osroot, osdev)); 5416eb2bd662Svikram 5417eb2bd662Svikram fstype = get_fstype(osroot); 5418eb2bd662Svikram INJECT_ERROR1("GET_GRUBSIGN_FSTYPE", fstype = NULL); 5419eb2bd662Svikram if (fstype == NULL) { 5420eb2bd662Svikram bam_error(GET_FSTYPE_FAILED, osroot); 5421eb2bd662Svikram return (NULL); 5422eb2bd662Svikram } 5423eb2bd662Svikram 5424eb2bd662Svikram sign = find_existing_sign(osroot, osdev, fstype); 5425eb2bd662Svikram INJECT_ERROR1("FIND_EXISTING_SIGN", sign = NULL); 5426eb2bd662Svikram if (sign == NULL) { 5427eb2bd662Svikram BAM_DPRINTF((D_GET_GRUBSIGN_NO_EXISTING, fcn, osroot, osdev)); 5428eb2bd662Svikram sign = create_new_sign(osdev, fstype); 5429eb2bd662Svikram INJECT_ERROR1("CREATE_NEW_SIGN", sign = NULL); 5430eb2bd662Svikram if (sign == NULL) { 5431eb2bd662Svikram bam_error(GRUBSIGN_CREATE_FAIL, osdev); 5432eb2bd662Svikram free(fstype); 5433eb2bd662Svikram return (NULL); 5434eb2bd662Svikram } 5435eb2bd662Svikram } 5436eb2bd662Svikram 5437eb2bd662Svikram ret = set_signature(osroot, osdev, sign, fstype); 5438eb2bd662Svikram INJECT_ERROR1("SET_SIGNATURE_FAIL", ret = -1); 5439eb2bd662Svikram if (ret == -1) { 5440eb2bd662Svikram bam_error(GRUBSIGN_WRITE_FAIL, osdev); 5441eb2bd662Svikram free(sign); 5442eb2bd662Svikram free(fstype); 5443eb2bd662Svikram (void) unlink(UFS_SIGNATURE_LIST); 5444eb2bd662Svikram return (NULL); 5445eb2bd662Svikram } 5446eb2bd662Svikram 5447eb2bd662Svikram free(fstype); 5448eb2bd662Svikram 5449eb2bd662Svikram if (bam_verbose) 5450eb2bd662Svikram bam_print(GRUBSIGN_FOUND_OR_CREATED, sign, osdev); 5451eb2bd662Svikram 5452eb2bd662Svikram fdiskpart = get_partition(osdev); 5453eb2bd662Svikram INJECT_ERROR1("GET_GRUBSIGN_FDISK", fdiskpart = -1); 5454eb2bd662Svikram if (fdiskpart == -1) { 5455eb2bd662Svikram bam_error(FDISKPART_FAIL, osdev); 5456eb2bd662Svikram free(sign); 5457eb2bd662Svikram return (NULL); 5458eb2bd662Svikram } 5459eb2bd662Svikram 5460eb2bd662Svikram slice = strrchr(osdev, 's'); 5461eb2bd662Svikram 5462eb2bd662Svikram grubsign = s_calloc(1, MAXNAMELEN + 10); 5463eb2bd662Svikram if (slice) { 5464eb2bd662Svikram (void) snprintf(grubsign, MAXNAMELEN + 10, "(%s,%d,%c)", 5465eb2bd662Svikram sign, fdiskpart, slice[1] + 'a' - '0'); 5466eb2bd662Svikram } else 5467eb2bd662Svikram (void) snprintf(grubsign, MAXNAMELEN + 10, "(%s,%d)", 5468eb2bd662Svikram sign, fdiskpart); 5469eb2bd662Svikram 5470eb2bd662Svikram free(sign); 5471eb2bd662Svikram 5472eb2bd662Svikram BAM_DPRINTF((D_GET_GRUBSIGN_SUCCESS, fcn, grubsign)); 5473eb2bd662Svikram 5474eb2bd662Svikram return (grubsign); 54757c478bd9Sstevel@tonic-gate } 54767c478bd9Sstevel@tonic-gate 5477ee3b8144Sszhou static char * 5478ee3b8144Sszhou get_title(char *rootdir) 54797c478bd9Sstevel@tonic-gate { 5480eb2bd662Svikram static char title[80]; 5481eb2bd662Svikram char *cp = NULL; 5482eb2bd662Svikram char release[PATH_MAX]; 54837c478bd9Sstevel@tonic-gate FILE *fp; 5484eb2bd662Svikram const char *fcn = "get_title()"; 54857c478bd9Sstevel@tonic-gate 54867c478bd9Sstevel@tonic-gate /* open the /etc/release file */ 54877c478bd9Sstevel@tonic-gate (void) snprintf(release, sizeof (release), "%s/etc/release", rootdir); 54887c478bd9Sstevel@tonic-gate 54897c478bd9Sstevel@tonic-gate fp = fopen(release, "r"); 5490eb2bd662Svikram if (fp == NULL) { 5491eb2bd662Svikram bam_error(OPEN_FAIL, release, strerror(errno)); 5492eb2bd662Svikram cp = NULL; 5493eb2bd662Svikram goto out; 5494eb2bd662Svikram } 54957c478bd9Sstevel@tonic-gate 54967c478bd9Sstevel@tonic-gate while (s_fgets(title, sizeof (title), fp) != NULL) { 54977c478bd9Sstevel@tonic-gate cp = strstr(title, "Solaris"); 54987c478bd9Sstevel@tonic-gate if (cp) 54997c478bd9Sstevel@tonic-gate break; 55007c478bd9Sstevel@tonic-gate } 55017c478bd9Sstevel@tonic-gate (void) fclose(fp); 5502eb2bd662Svikram 5503eb2bd662Svikram out: 5504eb2bd662Svikram cp = cp ? cp : "Solaris"; 5505eb2bd662Svikram 5506eb2bd662Svikram BAM_DPRINTF((D_GET_TITLE, fcn, cp)); 5507eb2bd662Svikram 5508eb2bd662Svikram return (cp); 55097c478bd9Sstevel@tonic-gate } 55107c478bd9Sstevel@tonic-gate 5511ae115bc7Smrj char * 55127c478bd9Sstevel@tonic-gate get_special(char *mountp) 55137c478bd9Sstevel@tonic-gate { 55147c478bd9Sstevel@tonic-gate FILE *mntfp; 5515eb2bd662Svikram struct mnttab mp = {0}; 5516eb2bd662Svikram struct mnttab mpref = {0}; 5517eb2bd662Svikram int error; 5518eb2bd662Svikram int ret; 5519eb2bd662Svikram const char *fcn = "get_special()"; 5520eb2bd662Svikram 5521eb2bd662Svikram INJECT_ERROR1("GET_SPECIAL_MNTPT", mountp = NULL); 5522eb2bd662Svikram if (mountp == NULL) { 5523eb2bd662Svikram bam_error(GET_SPECIAL_NULL_MNTPT); 5524eb2bd662Svikram return (NULL); 5525eb2bd662Svikram } 55267c478bd9Sstevel@tonic-gate 55277c478bd9Sstevel@tonic-gate mntfp = fopen(MNTTAB, "r"); 5528eb2bd662Svikram error = errno; 5529eb2bd662Svikram INJECT_ERROR1("GET_SPECIAL_MNTTAB_OPEN", mntfp = NULL); 55307c478bd9Sstevel@tonic-gate if (mntfp == NULL) { 5531eb2bd662Svikram bam_error(OPEN_FAIL, MNTTAB, strerror(error)); 5532eb2bd662Svikram return (NULL); 55337c478bd9Sstevel@tonic-gate } 55347c478bd9Sstevel@tonic-gate 55357c478bd9Sstevel@tonic-gate if (*mountp == '\0') 55367c478bd9Sstevel@tonic-gate mpref.mnt_mountp = "/"; 55377c478bd9Sstevel@tonic-gate else 55387c478bd9Sstevel@tonic-gate mpref.mnt_mountp = mountp; 5539eb2bd662Svikram 5540eb2bd662Svikram ret = getmntany(mntfp, &mp, &mpref); 5541eb2bd662Svikram INJECT_ERROR1("GET_SPECIAL_MNTTAB_SEARCH", ret = 1); 5542eb2bd662Svikram if (ret != 0) { 55437c478bd9Sstevel@tonic-gate (void) fclose(mntfp); 5544eb2bd662Svikram BAM_DPRINTF((D_GET_SPECIAL_NOT_IN_MNTTAB, fcn, mountp)); 55457c478bd9Sstevel@tonic-gate return (NULL); 55467c478bd9Sstevel@tonic-gate } 55477c478bd9Sstevel@tonic-gate (void) fclose(mntfp); 55487c478bd9Sstevel@tonic-gate 5549eb2bd662Svikram BAM_DPRINTF((D_GET_SPECIAL, fcn, mp.mnt_special)); 5550eb2bd662Svikram 55517c478bd9Sstevel@tonic-gate return (s_strdup(mp.mnt_special)); 55527c478bd9Sstevel@tonic-gate } 55537c478bd9Sstevel@tonic-gate 5554eb2bd662Svikram static void 5555eb2bd662Svikram free_physarray(char **physarray, int n) 55567c478bd9Sstevel@tonic-gate { 5557eb2bd662Svikram int i; 5558eb2bd662Svikram const char *fcn = "free_physarray()"; 55597c478bd9Sstevel@tonic-gate 5560eb2bd662Svikram assert(physarray); 5561eb2bd662Svikram assert(n); 5562eb2bd662Svikram 5563eb2bd662Svikram BAM_DPRINTF((D_FUNC_ENTRY_N1, fcn, n)); 5564eb2bd662Svikram 5565eb2bd662Svikram for (i = 0; i < n; i++) { 5566eb2bd662Svikram free(physarray[i]); 55677c478bd9Sstevel@tonic-gate } 5568eb2bd662Svikram free(physarray); 5569eb2bd662Svikram 5570eb2bd662Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 5571eb2bd662Svikram } 5572eb2bd662Svikram 5573eb2bd662Svikram static int 5574eb2bd662Svikram zfs_get_physical(char *special, char ***physarray, int *n) 5575eb2bd662Svikram { 5576eb2bd662Svikram char sdup[PATH_MAX]; 5577eb2bd662Svikram char cmd[PATH_MAX]; 5578eb2bd662Svikram char dsk[PATH_MAX]; 5579eb2bd662Svikram char *pool; 5580eb2bd662Svikram filelist_t flist = {0}; 5581eb2bd662Svikram line_t *lp; 5582eb2bd662Svikram line_t *startlp; 5583eb2bd662Svikram char *comp1; 5584eb2bd662Svikram int i; 5585eb2bd662Svikram int ret; 5586eb2bd662Svikram const char *fcn = "zfs_get_physical()"; 5587eb2bd662Svikram 5588eb2bd662Svikram assert(special); 5589eb2bd662Svikram 5590eb2bd662Svikram BAM_DPRINTF((D_FUNC_ENTRY1, fcn, special)); 5591eb2bd662Svikram 5592eb2bd662Svikram INJECT_ERROR1("INVALID_ZFS_SPECIAL", special = "/foo"); 5593eb2bd662Svikram if (special[0] == '/') { 5594eb2bd662Svikram bam_error(INVALID_ZFS_SPECIAL, special); 5595eb2bd662Svikram return (-1); 5596eb2bd662Svikram } 5597eb2bd662Svikram 5598eb2bd662Svikram (void) strlcpy(sdup, special, sizeof (sdup)); 5599eb2bd662Svikram 5600eb2bd662Svikram pool = strtok(sdup, "/"); 5601eb2bd662Svikram INJECT_ERROR1("ZFS_GET_PHYS_POOL", pool = NULL); 5602eb2bd662Svikram if (pool == NULL) { 5603eb2bd662Svikram bam_error(CANT_FIND_POOL_FROM_SPECIAL, special); 5604eb2bd662Svikram return (-1); 5605eb2bd662Svikram } 5606eb2bd662Svikram 5607eb2bd662Svikram (void) snprintf(cmd, sizeof (cmd), "/sbin/zpool status %s", pool); 5608eb2bd662Svikram 5609eb2bd662Svikram ret = exec_cmd(cmd, &flist); 5610eb2bd662Svikram INJECT_ERROR1("ZFS_GET_PHYS_STATUS", ret = 1); 5611eb2bd662Svikram if (ret != 0) { 5612eb2bd662Svikram bam_error(ZFS_GET_POOL_STATUS, pool); 5613eb2bd662Svikram return (-1); 5614eb2bd662Svikram } 5615eb2bd662Svikram 5616eb2bd662Svikram INJECT_ERROR1("ZFS_GET_PHYS_STATUS_OUT", flist.head = NULL); 5617eb2bd662Svikram if (flist.head == NULL) { 5618eb2bd662Svikram bam_error(BAD_ZPOOL_STATUS, pool); 5619eb2bd662Svikram filelist_free(&flist); 5620eb2bd662Svikram return (-1); 5621eb2bd662Svikram } 5622eb2bd662Svikram 5623eb2bd662Svikram for (lp = flist.head; lp; lp = lp->next) { 5624eb2bd662Svikram BAM_DPRINTF((D_STRTOK_ZPOOL_STATUS, fcn, lp->line)); 5625eb2bd662Svikram comp1 = strtok(lp->line, " \t"); 5626eb2bd662Svikram if (comp1 == NULL) { 5627eb2bd662Svikram free(lp->line); 5628eb2bd662Svikram lp->line = NULL; 5629eb2bd662Svikram } else { 5630eb2bd662Svikram comp1 = s_strdup(comp1); 5631eb2bd662Svikram free(lp->line); 5632eb2bd662Svikram lp->line = comp1; 5633eb2bd662Svikram } 5634eb2bd662Svikram } 5635eb2bd662Svikram 5636eb2bd662Svikram for (lp = flist.head; lp; lp = lp->next) { 5637eb2bd662Svikram if (lp->line == NULL) 5638eb2bd662Svikram continue; 5639eb2bd662Svikram if (strcmp(lp->line, pool) == 0) { 5640eb2bd662Svikram BAM_DPRINTF((D_FOUND_POOL_IN_ZPOOL_STATUS, fcn, pool)); 5641eb2bd662Svikram break; 5642eb2bd662Svikram } 5643eb2bd662Svikram } 5644eb2bd662Svikram 5645eb2bd662Svikram if (lp == NULL) { 5646eb2bd662Svikram bam_error(NO_POOL_IN_ZPOOL_STATUS, pool); 5647eb2bd662Svikram filelist_free(&flist); 5648eb2bd662Svikram return (-1); 5649eb2bd662Svikram } 5650eb2bd662Svikram 5651eb2bd662Svikram startlp = lp->next; 5652eb2bd662Svikram for (i = 0, lp = startlp; lp; lp = lp->next) { 5653eb2bd662Svikram if (lp->line == NULL) 5654eb2bd662Svikram continue; 5655eb2bd662Svikram if (strcmp(lp->line, "mirror") == 0) 5656eb2bd662Svikram continue; 5657eb2bd662Svikram if (lp->line[0] == '\0' || strcmp(lp->line, "errors:") == 0) 5658eb2bd662Svikram break; 5659eb2bd662Svikram i++; 5660eb2bd662Svikram BAM_DPRINTF((D_COUNTING_ZFS_PHYS, fcn, i)); 5661eb2bd662Svikram } 5662eb2bd662Svikram 5663eb2bd662Svikram if (i == 0) { 5664eb2bd662Svikram bam_error(NO_PHYS_IN_ZPOOL_STATUS, pool); 5665eb2bd662Svikram filelist_free(&flist); 5666eb2bd662Svikram return (-1); 5667eb2bd662Svikram } 5668eb2bd662Svikram 5669eb2bd662Svikram *n = i; 5670eb2bd662Svikram *physarray = s_calloc(*n, sizeof (char *)); 5671eb2bd662Svikram for (i = 0, lp = startlp; lp; lp = lp->next) { 5672eb2bd662Svikram if (lp->line == NULL) 5673eb2bd662Svikram continue; 5674eb2bd662Svikram if (strcmp(lp->line, "mirror") == 0) 5675eb2bd662Svikram continue; 5676eb2bd662Svikram if (strcmp(lp->line, "errors:") == 0) 5677eb2bd662Svikram break; 5678eb2bd662Svikram if (strncmp(lp->line, "/dev/dsk/", strlen("/dev/dsk/")) != 0 && 5679eb2bd662Svikram strncmp(lp->line, "/dev/rdsk/", 5680eb2bd662Svikram strlen("/dev/rdsk/")) != 0) { 5681eb2bd662Svikram (void) snprintf(dsk, sizeof (dsk), "/dev/dsk/%s", 5682eb2bd662Svikram lp->line); 5683eb2bd662Svikram } else { 5684eb2bd662Svikram (void) strlcpy(dsk, lp->line, sizeof (dsk)); 5685eb2bd662Svikram } 5686eb2bd662Svikram BAM_DPRINTF((D_ADDING_ZFS_PHYS, fcn, dsk, pool)); 5687eb2bd662Svikram (*physarray)[i++] = s_strdup(dsk); 5688eb2bd662Svikram } 5689eb2bd662Svikram 5690eb2bd662Svikram assert(i == *n); 5691eb2bd662Svikram 5692eb2bd662Svikram filelist_free(&flist); 5693eb2bd662Svikram 5694eb2bd662Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 5695eb2bd662Svikram return (0); 5696eb2bd662Svikram } 5697eb2bd662Svikram 5698963390b4Svikram /* 5699963390b4Svikram * Certain services needed to run metastat successfully may not 5700963390b4Svikram * be enabled. Enable them now. 5701963390b4Svikram */ 5702963390b4Svikram /* 5703963390b4Svikram * Checks if the specified service is online 5704963390b4Svikram * Returns: 1 if the service is online 5705963390b4Svikram * 0 if the service is not online 5706963390b4Svikram * -1 on error 5707963390b4Svikram */ 5708963390b4Svikram static int 5709963390b4Svikram is_svc_online(char *svc) 5710963390b4Svikram { 5711963390b4Svikram char *state; 5712963390b4Svikram const char *fcn = "is_svc_online()"; 5713963390b4Svikram 5714963390b4Svikram BAM_DPRINTF((D_FUNC_ENTRY1, fcn, svc)); 5715963390b4Svikram 5716963390b4Svikram state = smf_get_state(svc); 5717963390b4Svikram INJECT_ERROR2("GET_SVC_STATE", free(state), state = NULL); 5718963390b4Svikram if (state == NULL) { 5719963390b4Svikram bam_error(GET_SVC_STATE_ERR, svc); 5720963390b4Svikram return (-1); 5721963390b4Svikram } 5722963390b4Svikram BAM_DPRINTF((D_GOT_SVC_STATUS, fcn, svc)); 5723963390b4Svikram 5724963390b4Svikram if (strcmp(state, SCF_STATE_STRING_ONLINE) == 0) { 5725963390b4Svikram BAM_DPRINTF((D_SVC_ONLINE, fcn, svc)); 5726963390b4Svikram free(state); 5727963390b4Svikram return (1); 5728963390b4Svikram } 5729963390b4Svikram 5730963390b4Svikram BAM_DPRINTF((D_SVC_NOT_ONLINE, fcn, state, svc)); 5731963390b4Svikram 5732963390b4Svikram free(state); 5733963390b4Svikram 5734963390b4Svikram return (0); 5735963390b4Svikram } 5736963390b4Svikram 5737963390b4Svikram static int 5738963390b4Svikram enable_svc(char *svc) 5739963390b4Svikram { 5740963390b4Svikram int ret; 5741963390b4Svikram int sleeptime; 5742963390b4Svikram const char *fcn = "enable_svc()"; 5743963390b4Svikram 5744963390b4Svikram ret = is_svc_online(svc); 5745963390b4Svikram if (ret == -1) { 5746963390b4Svikram bam_error(SVC_IS_ONLINE_FAILED, svc); 5747963390b4Svikram return (-1); 5748963390b4Svikram } else if (ret == 1) { 5749963390b4Svikram BAM_DPRINTF((D_SVC_ALREADY_ONLINE, fcn, svc)); 5750963390b4Svikram return (0); 5751963390b4Svikram } 5752963390b4Svikram 5753963390b4Svikram /* Service is not enabled. Enable it now. */ 5754963390b4Svikram ret = smf_enable_instance(svc, 0); 5755963390b4Svikram INJECT_ERROR1("ENABLE_SVC_FAILED", ret = -1); 5756963390b4Svikram if (ret != 0) { 5757963390b4Svikram bam_error(ENABLE_SVC_FAILED, svc); 5758963390b4Svikram return (-1); 5759963390b4Svikram } 5760963390b4Svikram 5761963390b4Svikram BAM_DPRINTF((D_SVC_ONLINE_INITIATED, fcn, svc)); 5762963390b4Svikram 5763963390b4Svikram sleeptime = 0; 5764963390b4Svikram do { 5765963390b4Svikram ret = is_svc_online(svc); 5766963390b4Svikram INJECT_ERROR1("SVC_ONLINE_SUCCESS", ret = 1); 5767963390b4Svikram INJECT_ERROR1("SVC_ONLINE_FAILURE", ret = -1); 5768963390b4Svikram INJECT_ERROR1("SVC_ONLINE_NOTYET", ret = 0); 5769963390b4Svikram if (ret == -1) { 5770963390b4Svikram bam_error(ERR_SVC_GET_ONLINE, svc); 5771963390b4Svikram return (-1); 5772963390b4Svikram } else if (ret == 1) { 5773963390b4Svikram BAM_DPRINTF((D_SVC_NOW_ONLINE, fcn, svc)); 5774963390b4Svikram return (1); 5775963390b4Svikram } 5776963390b4Svikram (void) sleep(1); 5777963390b4Svikram } while (sleeptime < 60); 5778963390b4Svikram 5779963390b4Svikram bam_error(TIMEOUT_ENABLE_SVC, svc); 5780963390b4Svikram 5781963390b4Svikram return (-1); 5782963390b4Svikram } 5783963390b4Svikram 5784eb2bd662Svikram static int 5785eb2bd662Svikram ufs_get_physical(char *special, char ***physarray, int *n) 5786eb2bd662Svikram { 5787eb2bd662Svikram char cmd[PATH_MAX]; 5788eb2bd662Svikram char *shortname; 5789eb2bd662Svikram filelist_t flist = {0}; 5790eb2bd662Svikram char *meta; 5791eb2bd662Svikram char *type; 5792eb2bd662Svikram char *comp1; 5793eb2bd662Svikram char *comp2; 5794eb2bd662Svikram char *comp3; 5795eb2bd662Svikram char *comp4; 5796eb2bd662Svikram int i; 5797eb2bd662Svikram line_t *lp; 5798eb2bd662Svikram int ret; 5799963390b4Svikram char *svc; 5800eb2bd662Svikram const char *fcn = "ufs_get_physical()"; 5801eb2bd662Svikram 5802eb2bd662Svikram assert(special); 5803eb2bd662Svikram 5804eb2bd662Svikram BAM_DPRINTF((D_FUNC_ENTRY1, fcn, special)); 5805eb2bd662Svikram 5806eb2bd662Svikram if (strncmp(special, "/dev/md/", strlen("/dev/md/")) != 0) { 5807eb2bd662Svikram bam_error(UFS_GET_PHYS_NOT_SVM, special); 5808eb2bd662Svikram return (-1); 5809eb2bd662Svikram } 5810eb2bd662Svikram 5811eb2bd662Svikram if (strncmp(special, "/dev/md/dsk/", strlen("/dev/md/dsk/")) == 0) { 5812eb2bd662Svikram shortname = special + strlen("/dev/md/dsk/"); 5813eb2bd662Svikram } else if (strncmp(special, "/dev/md/rdsk/", 5814eb2bd662Svikram strlen("/dev/md/rdsk/")) == 0) { 5815eb2bd662Svikram shortname = special + strlen("/dev/md/rdsk"); 5816eb2bd662Svikram } else { 5817eb2bd662Svikram bam_error(UFS_GET_PHYS_INVALID_SVM, special); 5818eb2bd662Svikram return (-1); 5819eb2bd662Svikram } 5820eb2bd662Svikram 5821eb2bd662Svikram BAM_DPRINTF((D_UFS_SVM_SHORT, fcn, special, shortname)); 5822eb2bd662Svikram 5823963390b4Svikram svc = "network/rpc/meta:default"; 5824963390b4Svikram if (enable_svc(svc) == -1) { 5825963390b4Svikram bam_error(UFS_SVM_METASTAT_SVC_ERR, svc); 5826963390b4Svikram } 5827963390b4Svikram 5828eb2bd662Svikram (void) snprintf(cmd, sizeof (cmd), "/sbin/metastat -p %s", shortname); 5829eb2bd662Svikram 5830eb2bd662Svikram ret = exec_cmd(cmd, &flist); 5831eb2bd662Svikram INJECT_ERROR1("UFS_SVM_METASTAT", ret = 1); 5832eb2bd662Svikram if (ret != 0) { 5833eb2bd662Svikram bam_error(UFS_SVM_METASTAT_ERR, shortname); 5834eb2bd662Svikram return (-1); 5835eb2bd662Svikram } 5836eb2bd662Svikram 5837eb2bd662Svikram INJECT_ERROR1("UFS_SVM_METASTAT_OUT", flist.head = NULL); 5838eb2bd662Svikram if (flist.head == NULL) { 5839eb2bd662Svikram bam_error(BAD_UFS_SVM_METASTAT, shortname); 5840eb2bd662Svikram filelist_free(&flist); 5841eb2bd662Svikram return (-1); 58427c478bd9Sstevel@tonic-gate } 58437c478bd9Sstevel@tonic-gate 58447c478bd9Sstevel@tonic-gate /* 5845eb2bd662Svikram * Check if not a mirror. We only parse a single metadevice 5846eb2bd662Svikram * if not a mirror 5847eb2bd662Svikram */ 5848eb2bd662Svikram meta = strtok(flist.head->line, " \t"); 5849eb2bd662Svikram type = strtok(NULL, " \t"); 5850eb2bd662Svikram if (meta == NULL || type == NULL) { 5851eb2bd662Svikram bam_error(ERROR_PARSE_UFS_SVM_METASTAT, shortname); 5852eb2bd662Svikram filelist_free(&flist); 5853eb2bd662Svikram return (-1); 5854eb2bd662Svikram } 5855eb2bd662Svikram if (strcmp(type, "-m") != 0) { 5856eb2bd662Svikram comp1 = strtok(NULL, " \t"); 5857eb2bd662Svikram comp2 = strtok(NULL, " \t"); 5858eb2bd662Svikram if (comp1 == NULL || comp2 != NULL) { 5859eb2bd662Svikram bam_error(INVALID_UFS_SVM_METASTAT, shortname); 5860eb2bd662Svikram filelist_free(&flist); 5861eb2bd662Svikram return (-1); 5862eb2bd662Svikram } 5863eb2bd662Svikram BAM_DPRINTF((D_UFS_SVM_ONE_COMP, fcn, comp1, shortname)); 5864eb2bd662Svikram *physarray = s_calloc(1, sizeof (char *)); 5865eb2bd662Svikram (*physarray)[0] = s_strdup(comp1); 5866eb2bd662Svikram *n = 1; 5867eb2bd662Svikram filelist_free(&flist); 5868eb2bd662Svikram return (0); 5869eb2bd662Svikram } 5870eb2bd662Svikram 5871eb2bd662Svikram /* 5872eb2bd662Svikram * Okay we have a mirror. Everything after the first line 5873eb2bd662Svikram * is a submirror 5874eb2bd662Svikram */ 5875eb2bd662Svikram for (i = 0, lp = flist.head->next; lp; lp = lp->next) { 5876eb2bd662Svikram if (strstr(lp->line, "/dev/dsk/") == NULL && 5877eb2bd662Svikram strstr(lp->line, "/dev/rdsk/") == NULL) { 5878eb2bd662Svikram bam_error(CANNOT_PARSE_UFS_SVM_METASTAT, shortname); 5879eb2bd662Svikram filelist_free(&flist); 5880eb2bd662Svikram return (-1); 5881eb2bd662Svikram } 5882eb2bd662Svikram i++; 5883eb2bd662Svikram } 5884eb2bd662Svikram 5885eb2bd662Svikram *physarray = s_calloc(i, sizeof (char *)); 5886eb2bd662Svikram *n = i; 5887eb2bd662Svikram 5888eb2bd662Svikram for (i = 0, lp = flist.head->next; lp; lp = lp->next) { 5889eb2bd662Svikram comp1 = strtok(lp->line, " \t"); 5890eb2bd662Svikram comp2 = strtok(NULL, " \t"); 5891eb2bd662Svikram comp3 = strtok(NULL, " \t"); 5892eb2bd662Svikram comp4 = strtok(NULL, " \t"); 5893eb2bd662Svikram 5894eb2bd662Svikram if (comp3 == NULL || comp4 == NULL || 5895eb2bd662Svikram (strncmp(comp4, "/dev/dsk/", strlen("/dev/dsk/")) != 0 && 5896eb2bd662Svikram strncmp(comp4, "/dev/rdsk/", strlen("/dev/rdsk/")) != 0)) { 5897eb2bd662Svikram bam_error(CANNOT_PARSE_UFS_SVM_SUBMIRROR, shortname); 5898eb2bd662Svikram filelist_free(&flist); 5899eb2bd662Svikram free_physarray(*physarray, *n); 5900eb2bd662Svikram return (-1); 5901eb2bd662Svikram } 5902eb2bd662Svikram 5903eb2bd662Svikram (*physarray)[i++] = s_strdup(comp4); 5904eb2bd662Svikram } 5905eb2bd662Svikram 5906eb2bd662Svikram assert(i == *n); 5907eb2bd662Svikram 5908eb2bd662Svikram filelist_free(&flist); 5909eb2bd662Svikram 5910eb2bd662Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 5911eb2bd662Svikram return (0); 5912eb2bd662Svikram } 5913eb2bd662Svikram 5914eb2bd662Svikram static int 5915eb2bd662Svikram get_physical(char *menu_root, char ***physarray, int *n) 5916eb2bd662Svikram { 5917eb2bd662Svikram char *special; 5918eb2bd662Svikram int ret; 5919eb2bd662Svikram const char *fcn = "get_physical()"; 5920eb2bd662Svikram 5921eb2bd662Svikram assert(menu_root); 5922eb2bd662Svikram assert(physarray); 5923eb2bd662Svikram assert(n); 5924eb2bd662Svikram 5925eb2bd662Svikram *physarray = NULL; 5926eb2bd662Svikram *n = 0; 5927eb2bd662Svikram 5928eb2bd662Svikram BAM_DPRINTF((D_FUNC_ENTRY1, fcn, menu_root)); 5929eb2bd662Svikram 5930eb2bd662Svikram /* First get the device special file from /etc/mnttab */ 5931eb2bd662Svikram special = get_special(menu_root); 5932eb2bd662Svikram INJECT_ERROR1("GET_PHYSICAL_SPECIAL", special = NULL); 5933eb2bd662Svikram if (special == NULL) { 5934eb2bd662Svikram bam_error(GET_SPECIAL_NULL, menu_root); 5935eb2bd662Svikram return (-1); 5936eb2bd662Svikram } 5937eb2bd662Svikram 5938eb2bd662Svikram /* If already a physical device nothing to do */ 5939eb2bd662Svikram if (strncmp(special, "/dev/dsk/", strlen("/dev/dsk/")) == 0 || 5940eb2bd662Svikram strncmp(special, "/dev/rdsk/", strlen("/dev/rdsk/")) == 0) { 5941eb2bd662Svikram BAM_DPRINTF((D_GET_PHYSICAL_ALREADY, fcn, menu_root, special)); 5942eb2bd662Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 5943eb2bd662Svikram *physarray = s_calloc(1, sizeof (char *)); 5944eb2bd662Svikram (*physarray)[0] = special; 5945eb2bd662Svikram *n = 1; 5946eb2bd662Svikram return (0); 5947eb2bd662Svikram } 5948eb2bd662Svikram 5949eb2bd662Svikram if (is_zfs(menu_root)) { 5950eb2bd662Svikram ret = zfs_get_physical(special, physarray, n); 5951eb2bd662Svikram } else if (is_ufs(menu_root)) { 5952eb2bd662Svikram ret = ufs_get_physical(special, physarray, n); 5953eb2bd662Svikram } else { 5954eb2bd662Svikram bam_error(GET_PHYSICAL_NOTSUP_FSTYPE, menu_root, special); 5955eb2bd662Svikram ret = -1; 5956eb2bd662Svikram } 5957eb2bd662Svikram 5958eb2bd662Svikram free(special); 5959eb2bd662Svikram 5960eb2bd662Svikram INJECT_ERROR1("GET_PHYSICAL_RET", ret = -1); 5961eb2bd662Svikram if (ret == -1) { 5962eb2bd662Svikram BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 5963eb2bd662Svikram } else { 5964eb2bd662Svikram int i; 5965eb2bd662Svikram assert (*n > 0); 5966eb2bd662Svikram for (i = 0; i < *n; i++) { 5967eb2bd662Svikram BAM_DPRINTF((D_GET_PHYSICAL_RET, fcn, (*physarray)[i])); 5968eb2bd662Svikram } 5969eb2bd662Svikram } 5970eb2bd662Svikram 5971eb2bd662Svikram return (ret); 5972eb2bd662Svikram } 5973eb2bd662Svikram 5974eb2bd662Svikram static int 5975eb2bd662Svikram is_bootdisk(char *osroot, char *physical) 5976eb2bd662Svikram { 5977eb2bd662Svikram int ret; 5978eb2bd662Svikram char *grubroot; 5979eb2bd662Svikram char *bootp; 5980eb2bd662Svikram const char *fcn = "is_bootdisk()"; 5981eb2bd662Svikram 5982eb2bd662Svikram assert(osroot); 5983eb2bd662Svikram assert(physical); 5984eb2bd662Svikram 5985eb2bd662Svikram BAM_DPRINTF((D_FUNC_ENTRY2, fcn, osroot, physical)); 5986eb2bd662Svikram 5987eb2bd662Svikram bootp = strstr(physical, "p0:boot"); 5988eb2bd662Svikram if (bootp) 5989eb2bd662Svikram *bootp = '\0'; 5990eb2bd662Svikram /* 5991eb2bd662Svikram * We just want the BIOS mapping for menu disk. 5992eb2bd662Svikram * Don't pass menu_root to get_grubroot() as the 5993eb2bd662Svikram * check that it is used for is not relevant here. 5994eb2bd662Svikram * The osroot is immaterial as well - it is only used to 5995eb2bd662Svikram * to find create_diskmap script. Everything hinges on 5996eb2bd662Svikram * "physical" 5997eb2bd662Svikram */ 5998eb2bd662Svikram grubroot = get_grubroot(osroot, physical, NULL); 5999eb2bd662Svikram 6000eb2bd662Svikram INJECT_ERROR1("IS_BOOTDISK_GRUBROOT", grubroot = NULL); 6001eb2bd662Svikram if (grubroot == NULL) { 6002eb2bd662Svikram bam_error(NO_GRUBROOT_FOR_DISK, fcn, physical); 6003eb2bd662Svikram return (0); 6004eb2bd662Svikram } 6005eb2bd662Svikram ret = grubroot[3] == '0'; 6006eb2bd662Svikram free(grubroot); 6007eb2bd662Svikram 6008eb2bd662Svikram BAM_DPRINTF((D_RETURN_RET, fcn, ret)); 6009eb2bd662Svikram 6010eb2bd662Svikram return (ret); 6011eb2bd662Svikram } 6012eb2bd662Svikram 6013eb2bd662Svikram /* 6014eb2bd662Svikram * Check if menu is on the boot device 60157c478bd9Sstevel@tonic-gate * Return 0 (false) on error 60167c478bd9Sstevel@tonic-gate */ 60177c478bd9Sstevel@tonic-gate static int 6018eb2bd662Svikram menu_on_bootdisk(char *osroot, char *menu_root) 60197c478bd9Sstevel@tonic-gate { 6020eb2bd662Svikram char **physarray; 60217c478bd9Sstevel@tonic-gate int ret; 6022eb2bd662Svikram int n; 6023eb2bd662Svikram int i; 6024eb2bd662Svikram int on_bootdisk; 6025eb2bd662Svikram const char *fcn = "menu_on_bootdisk()"; 60267c478bd9Sstevel@tonic-gate 6027eb2bd662Svikram BAM_DPRINTF((D_FUNC_ENTRY2, fcn, osroot, menu_root)); 60287c478bd9Sstevel@tonic-gate 6029eb2bd662Svikram ret = get_physical(menu_root, &physarray, &n); 6030eb2bd662Svikram INJECT_ERROR1("MENU_ON_BOOTDISK_PHYSICAL", ret = -1); 6031eb2bd662Svikram if (ret != 0) { 6032eb2bd662Svikram bam_error(GET_PHYSICAL_MENU_NULL, menu_root); 60337c478bd9Sstevel@tonic-gate return (0); 6034eb2bd662Svikram } 6035eb2bd662Svikram 6036eb2bd662Svikram assert(physarray); 6037eb2bd662Svikram assert(n > 0); 6038eb2bd662Svikram 6039eb2bd662Svikram on_bootdisk = 0; 6040eb2bd662Svikram for (i = 0; i < n; i++) { 6041eb2bd662Svikram assert(strncmp(physarray[i], "/dev/dsk/", 6042eb2bd662Svikram strlen("/dev/dsk/")) == 0 || 6043eb2bd662Svikram strncmp(physarray[i], "/dev/rdsk/", 6044eb2bd662Svikram strlen("/dev/rdsk/")) == 0); 6045eb2bd662Svikram 6046eb2bd662Svikram BAM_DPRINTF((D_CHECK_ON_BOOTDISK, fcn, physarray[i])); 6047eb2bd662Svikram if (is_bootdisk(osroot, physarray[i])) { 6048eb2bd662Svikram on_bootdisk = 1; 6049eb2bd662Svikram BAM_DPRINTF((D_IS_ON_BOOTDISK, fcn, physarray[i])); 6050eb2bd662Svikram } 6051eb2bd662Svikram } 6052eb2bd662Svikram 6053eb2bd662Svikram free_physarray(physarray, n); 6054eb2bd662Svikram 6055eb2bd662Svikram INJECT_ERROR1("ON_BOOTDISK_YES", on_bootdisk = 1); 6056eb2bd662Svikram INJECT_ERROR1("ON_BOOTDISK_NO", on_bootdisk = 0); 6057eb2bd662Svikram if (on_bootdisk) { 6058eb2bd662Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 6059eb2bd662Svikram } else { 6060eb2bd662Svikram BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 6061eb2bd662Svikram } 6062eb2bd662Svikram 6063eb2bd662Svikram return (on_bootdisk); 6064eb2bd662Svikram } 6065eb2bd662Svikram 6066eb2bd662Svikram void 6067eb2bd662Svikram bam_add_line(menu_t *mp, entry_t *entry, line_t *prev, line_t *lp) 6068eb2bd662Svikram { 6069eb2bd662Svikram const char *fcn = "bam_add_line()"; 6070eb2bd662Svikram 6071eb2bd662Svikram assert(mp); 6072eb2bd662Svikram assert(entry); 6073eb2bd662Svikram assert(prev); 6074eb2bd662Svikram assert(lp); 6075eb2bd662Svikram 6076eb2bd662Svikram lp->next = prev->next; 6077eb2bd662Svikram if (prev->next) { 6078eb2bd662Svikram BAM_DPRINTF((D_ADD_LINE_PREV_NEXT, fcn)); 6079eb2bd662Svikram prev->next->prev = lp; 6080eb2bd662Svikram } else { 6081eb2bd662Svikram BAM_DPRINTF((D_ADD_LINE_NOT_PREV_NEXT, fcn)); 6082eb2bd662Svikram } 6083eb2bd662Svikram prev->next = lp; 6084eb2bd662Svikram lp->prev = prev; 6085eb2bd662Svikram 6086eb2bd662Svikram if (entry->end == prev) { 6087eb2bd662Svikram BAM_DPRINTF((D_ADD_LINE_LAST_LINE_IN_ENTRY, fcn)); 6088eb2bd662Svikram entry->end = lp; 6089eb2bd662Svikram } 6090eb2bd662Svikram if (mp->end == prev) { 6091eb2bd662Svikram assert(lp->next == NULL); 6092eb2bd662Svikram mp->end = lp; 6093eb2bd662Svikram BAM_DPRINTF((D_ADD_LINE_LAST_LINE_IN_MENU, fcn)); 6094eb2bd662Svikram } 60957c478bd9Sstevel@tonic-gate } 60967c478bd9Sstevel@tonic-gate 60978c1b6884Sszhou /* 60988c1b6884Sszhou * look for matching bootadm entry with specified parameters 60998c1b6884Sszhou * Here are the rules (based on existing usage): 61008c1b6884Sszhou * - If title is specified, match on title only 6101eb2bd662Svikram * - Else, match on root/findroot, kernel, and module. 6102eb2bd662Svikram * Note that, if root_opt is non-zero, the absence of 6103eb2bd662Svikram * root line is considered a match. 61048c1b6884Sszhou */ 61058c1b6884Sszhou static entry_t * 6106eb2bd662Svikram find_boot_entry( 6107eb2bd662Svikram menu_t *mp, 6108eb2bd662Svikram char *title, 6109eb2bd662Svikram char *kernel, 6110eb2bd662Svikram char *findroot, 6111eb2bd662Svikram char *root, 6112eb2bd662Svikram char *module, 6113eb2bd662Svikram int root_opt, 6114eb2bd662Svikram int *entry_num) 61158c1b6884Sszhou { 61168c1b6884Sszhou int i; 61178c1b6884Sszhou line_t *lp; 61188c1b6884Sszhou entry_t *ent; 6119eb2bd662Svikram const char *fcn = "find_boot_entry()"; 6120eb2bd662Svikram 6121eb2bd662Svikram if (entry_num) 6122eb2bd662Svikram *entry_num = BAM_ERROR; 61238c1b6884Sszhou 61248c1b6884Sszhou /* find matching entry */ 61258c1b6884Sszhou for (i = 0, ent = mp->entries; ent; i++, ent = ent->next) { 61268c1b6884Sszhou lp = ent->start; 61278c1b6884Sszhou 61288c1b6884Sszhou /* first line of entry must be bootadm comment */ 61298c1b6884Sszhou lp = ent->start; 6130ae115bc7Smrj if (lp->flags != BAM_COMMENT || 6131ae115bc7Smrj strcmp(lp->arg, BAM_BOOTADM_HDR) != 0) { 61328c1b6884Sszhou continue; 61338c1b6884Sszhou } 61348c1b6884Sszhou 61358c1b6884Sszhou /* advance to title line */ 61368c1b6884Sszhou lp = lp->next; 61378c1b6884Sszhou if (title) { 61388c1b6884Sszhou if (lp->flags == BAM_TITLE && lp->arg && 6139eb2bd662Svikram strcmp(lp->arg, title) == 0) { 6140eb2bd662Svikram BAM_DPRINTF((D_MATCHED_TITLE, fcn, title)); 61418c1b6884Sszhou break; 6142eb2bd662Svikram } 6143eb2bd662Svikram BAM_DPRINTF((D_NOMATCH_TITLE, fcn, title, lp->arg)); 61448c1b6884Sszhou continue; /* check title only */ 61458c1b6884Sszhou } 61468c1b6884Sszhou 61478c1b6884Sszhou lp = lp->next; /* advance to root line */ 6148843e1988Sjohnlev if (lp == NULL) { 6149843e1988Sjohnlev continue; 6150eb2bd662Svikram } else if (strcmp(lp->cmd, menu_cmds[FINDROOT_CMD]) == 0) { 6151eb2bd662Svikram INJECT_ERROR1("FIND_BOOT_ENTRY_NULL_FINDROOT", 6152eb2bd662Svikram findroot = NULL); 6153eb2bd662Svikram if (findroot == NULL) { 6154eb2bd662Svikram BAM_DPRINTF((D_NOMATCH_FINDROOT_NULL, 6155eb2bd662Svikram fcn, lp->arg)); 61568c1b6884Sszhou continue; 61578c1b6884Sszhou } 6158eb2bd662Svikram /* findroot command found, try match */ 6159eb2bd662Svikram if (strcmp(lp->arg, findroot) != 0) { 6160eb2bd662Svikram BAM_DPRINTF((D_NOMATCH_FINDROOT, 6161eb2bd662Svikram fcn, findroot, lp->arg)); 6162eb2bd662Svikram continue; 6163eb2bd662Svikram } 6164eb2bd662Svikram BAM_DPRINTF((D_MATCHED_FINDROOT, fcn, findroot)); 6165eb2bd662Svikram lp = lp->next; /* advance to kernel line */ 6166eb2bd662Svikram } else if (strcmp(lp->cmd, menu_cmds[ROOT_CMD]) == 0) { 6167eb2bd662Svikram INJECT_ERROR1("FIND_BOOT_ENTRY_NULL_ROOT", root = NULL); 6168eb2bd662Svikram if (root == NULL) { 6169eb2bd662Svikram BAM_DPRINTF((D_NOMATCH_ROOT_NULL, 6170eb2bd662Svikram fcn, lp->arg)); 6171eb2bd662Svikram continue; 6172eb2bd662Svikram } 6173eb2bd662Svikram /* root cmd found, try match */ 6174eb2bd662Svikram if (strcmp(lp->arg, root) != 0) { 6175eb2bd662Svikram BAM_DPRINTF((D_NOMATCH_ROOT, 6176eb2bd662Svikram fcn, root, lp->arg)); 6177eb2bd662Svikram continue; 6178eb2bd662Svikram } 6179eb2bd662Svikram BAM_DPRINTF((D_MATCHED_ROOT, fcn, root)); 61808c1b6884Sszhou lp = lp->next; /* advance to kernel line */ 61818c1b6884Sszhou } else { 6182eb2bd662Svikram INJECT_ERROR1("FIND_BOOT_ENTRY_ROOT_OPT_NO", 6183eb2bd662Svikram root_opt = 0); 6184eb2bd662Svikram INJECT_ERROR1("FIND_BOOT_ENTRY_ROOT_OPT_YES", 6185eb2bd662Svikram root_opt = 1); 61868c1b6884Sszhou /* no root command, see if root is optional */ 61878c1b6884Sszhou if (root_opt == 0) { 6188eb2bd662Svikram BAM_DPRINTF((D_NO_ROOT_OPT, fcn)); 61898c1b6884Sszhou continue; 61908c1b6884Sszhou } 6191eb2bd662Svikram BAM_DPRINTF((D_ROOT_OPT, fcn)); 61928c1b6884Sszhou } 61938c1b6884Sszhou 61948c1b6884Sszhou if (lp == NULL || lp->next == NULL) { 61958c1b6884Sszhou continue; 61968c1b6884Sszhou } 61978c1b6884Sszhou 6198843e1988Sjohnlev if (kernel && 6199843e1988Sjohnlev (!check_cmd(lp->cmd, KERNEL_CMD, lp->arg, kernel))) { 62008c1b6884Sszhou continue; 62018c1b6884Sszhou } 6202eb2bd662Svikram BAM_DPRINTF((D_KERNEL_MATCH, fcn, kernel, lp->arg)); 6203843e1988Sjohnlev 6204843e1988Sjohnlev /* 6205843e1988Sjohnlev * Check for matching module entry (failsafe or normal). 6206843e1988Sjohnlev * If it fails to match, we go around the loop again. 6207843e1988Sjohnlev * For xpv entries, there are two module lines, so we 6208843e1988Sjohnlev * do the check twice. 6209843e1988Sjohnlev */ 6210843e1988Sjohnlev lp = lp->next; /* advance to module line */ 6211843e1988Sjohnlev if (check_cmd(lp->cmd, MODULE_CMD, lp->arg, module) || 6212843e1988Sjohnlev (((lp = lp->next) != NULL) && 6213843e1988Sjohnlev check_cmd(lp->cmd, MODULE_CMD, lp->arg, module))) { 6214843e1988Sjohnlev /* match found */ 6215eb2bd662Svikram BAM_DPRINTF((D_MODULE_MATCH, fcn, module, lp->arg)); 6216843e1988Sjohnlev break; 6217843e1988Sjohnlev } 62188c1b6884Sszhou } 62198c1b6884Sszhou 6220eb2bd662Svikram if (ent && entry_num) { 62218c1b6884Sszhou *entry_num = i; 6222843e1988Sjohnlev } 6223eb2bd662Svikram 6224eb2bd662Svikram if (ent) { 6225eb2bd662Svikram BAM_DPRINTF((D_RETURN_RET, fcn, i)); 6226eb2bd662Svikram } else { 6227eb2bd662Svikram BAM_DPRINTF((D_RETURN_RET, fcn, BAM_ERROR)); 6228eb2bd662Svikram } 62298c1b6884Sszhou return (ent); 62308c1b6884Sszhou } 62318c1b6884Sszhou 62328c1b6884Sszhou static int 6233eb2bd662Svikram update_boot_entry(menu_t *mp, char *title, char *findroot, char *root, 6234eb2bd662Svikram char *kernel, char *mod_kernel, char *module, int root_opt) 62358c1b6884Sszhou { 6236eb2bd662Svikram int i; 6237eb2bd662Svikram int change_kernel = 0; 62388c1b6884Sszhou entry_t *ent; 62398c1b6884Sszhou line_t *lp; 6240eb2bd662Svikram line_t *tlp; 62418c1b6884Sszhou char linebuf[BAM_MAXLINE]; 6242eb2bd662Svikram const char *fcn = "update_boot_entry()"; 62438c1b6884Sszhou 62448c1b6884Sszhou /* note: don't match on title, it's updated on upgrade */ 6245eb2bd662Svikram ent = find_boot_entry(mp, NULL, kernel, findroot, root, module, 6246eb2bd662Svikram root_opt, &i); 6247ae115bc7Smrj if ((ent == NULL) && (bam_direct == BAM_DIRECT_DBOOT)) { 6248ae115bc7Smrj /* 6249ae115bc7Smrj * We may be upgrading a kernel from multiboot to 6250eb2bd662Svikram * directboot. Look for a multiboot entry. A multiboot 6251eb2bd662Svikram * entry will not have a findroot line. 6252ae115bc7Smrj */ 6253eb2bd662Svikram ent = find_boot_entry(mp, NULL, "multiboot", NULL, root, 6254eb2bd662Svikram MULTIBOOT_ARCHIVE, root_opt, &i); 6255ae115bc7Smrj if (ent != NULL) { 6256eb2bd662Svikram BAM_DPRINTF((D_UPGRADE_FROM_MULTIBOOT, fcn, root)); 6257ae115bc7Smrj change_kernel = 1; 6258ae115bc7Smrj } 6259eb2bd662Svikram } else if (ent) { 6260eb2bd662Svikram BAM_DPRINTF((D_FOUND_FINDROOT, fcn, findroot)); 6261ae115bc7Smrj } 62628c1b6884Sszhou 6263eb2bd662Svikram if (ent == NULL) { 6264eb2bd662Svikram BAM_DPRINTF((D_ENTRY_NOT_FOUND_CREATING, fcn, findroot)); 6265eb2bd662Svikram return (add_boot_entry(mp, title, findroot, 6266eb2bd662Svikram kernel, mod_kernel, module)); 6267eb2bd662Svikram } 6268eb2bd662Svikram 6269eb2bd662Svikram /* replace title of existing entry and update findroot line */ 62708c1b6884Sszhou lp = ent->start; 62718c1b6884Sszhou lp = lp->next; /* title line */ 62728c1b6884Sszhou (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s", 62738c1b6884Sszhou menu_cmds[TITLE_CMD], menu_cmds[SEP_CMD], title); 62748c1b6884Sszhou free(lp->arg); 62758c1b6884Sszhou free(lp->line); 62768c1b6884Sszhou lp->arg = s_strdup(title); 62778c1b6884Sszhou lp->line = s_strdup(linebuf); 6278eb2bd662Svikram BAM_DPRINTF((D_CHANGING_TITLE, fcn, title)); 62798c1b6884Sszhou 6280eb2bd662Svikram tlp = lp; /* title line */ 62818c1b6884Sszhou lp = lp->next; /* root line */ 6282eb2bd662Svikram 6283eb2bd662Svikram /* if no root or findroot command, create a new line_t */ 6284eb2bd662Svikram if (strcmp(lp->cmd, menu_cmds[ROOT_CMD]) != 0 && 6285eb2bd662Svikram strcmp(lp->cmd, menu_cmds[FINDROOT_CMD]) != 0) { 6286eb2bd662Svikram lp = s_calloc(1, sizeof (line_t)); 6287eb2bd662Svikram bam_add_line(mp, ent, tlp, lp); 6288eb2bd662Svikram } else { 6289eb2bd662Svikram free(lp->cmd); 6290eb2bd662Svikram free(lp->sep); 6291eb2bd662Svikram free(lp->arg); 6292eb2bd662Svikram free(lp->line); 62938c1b6884Sszhou } 6294ae115bc7Smrj 6295eb2bd662Svikram lp->cmd = s_strdup(menu_cmds[FINDROOT_CMD]); 6296eb2bd662Svikram lp->sep = s_strdup(menu_cmds[SEP_CMD]); 6297eb2bd662Svikram lp->arg = s_strdup(findroot); 6298eb2bd662Svikram (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s", 6299eb2bd662Svikram menu_cmds[FINDROOT_CMD], menu_cmds[SEP_CMD], findroot); 6300eb2bd662Svikram lp->line = s_strdup(linebuf); 6301eb2bd662Svikram BAM_DPRINTF((D_ADDING_FINDROOT_LINE, fcn, findroot)); 6302eb2bd662Svikram 6303eb2bd662Svikram /* kernel line */ 6304eb2bd662Svikram lp = lp->next; 6305eb2bd662Svikram 6306ae115bc7Smrj if (change_kernel) { 6307ae115bc7Smrj /* 6308ae115bc7Smrj * We're upgrading from multiboot to directboot. 6309ae115bc7Smrj */ 6310ae115bc7Smrj if (strcmp(lp->cmd, menu_cmds[KERNEL_CMD]) == 0) { 6311ae115bc7Smrj (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s", 6312ae115bc7Smrj menu_cmds[KERNEL_DOLLAR_CMD], menu_cmds[SEP_CMD], 6313ae115bc7Smrj kernel); 6314eb2bd662Svikram free(lp->cmd); 6315ae115bc7Smrj free(lp->arg); 6316ae115bc7Smrj free(lp->line); 6317eb2bd662Svikram lp->cmd = s_strdup(menu_cmds[KERNEL_DOLLAR_CMD]); 6318ae115bc7Smrj lp->arg = s_strdup(kernel); 6319ae115bc7Smrj lp->line = s_strdup(linebuf); 6320ae115bc7Smrj lp = lp->next; 6321eb2bd662Svikram BAM_DPRINTF((D_ADDING_KERNEL_DOLLAR, fcn, kernel)); 6322ae115bc7Smrj } 6323ae115bc7Smrj if (strcmp(lp->cmd, menu_cmds[MODULE_CMD]) == 0) { 6324ae115bc7Smrj (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s", 6325ae115bc7Smrj menu_cmds[MODULE_DOLLAR_CMD], menu_cmds[SEP_CMD], 6326ae115bc7Smrj module); 6327eb2bd662Svikram free(lp->cmd); 6328ae115bc7Smrj free(lp->arg); 6329ae115bc7Smrj free(lp->line); 6330eb2bd662Svikram lp->cmd = s_strdup(menu_cmds[MODULE_DOLLAR_CMD]); 6331ae115bc7Smrj lp->arg = s_strdup(module); 6332ae115bc7Smrj lp->line = s_strdup(linebuf); 6333ae115bc7Smrj lp = lp->next; 6334eb2bd662Svikram BAM_DPRINTF((D_ADDING_MODULE_DOLLAR, fcn, module)); 6335ae115bc7Smrj } 6336ae115bc7Smrj } 6337eb2bd662Svikram BAM_DPRINTF((D_RETURN_RET, fcn, i)); 63388c1b6884Sszhou return (i); 63398c1b6884Sszhou } 63408c1b6884Sszhou 6341eb2bd662Svikram int 6342eb2bd662Svikram root_optional(char *osroot, char *menu_root) 6343eb2bd662Svikram { 6344eb2bd662Svikram char *ospecial; 6345eb2bd662Svikram char *mspecial; 6346eb2bd662Svikram char *slash; 6347eb2bd662Svikram int root_opt; 6348eb2bd662Svikram int ret1; 6349eb2bd662Svikram int ret2; 6350eb2bd662Svikram const char *fcn = "root_optional()"; 6351eb2bd662Svikram 6352eb2bd662Svikram BAM_DPRINTF((D_FUNC_ENTRY2, fcn, osroot, menu_root)); 6353eb2bd662Svikram 6354eb2bd662Svikram /* 6355eb2bd662Svikram * For all filesystems except ZFS, a straight compare of osroot 6356eb2bd662Svikram * and menu_root will tell us if root is optional. 6357eb2bd662Svikram * For ZFS, the situation is complicated by the fact that 6358eb2bd662Svikram * menu_root and osroot are always different 6359eb2bd662Svikram */ 6360eb2bd662Svikram ret1 = is_zfs(osroot); 6361eb2bd662Svikram ret2 = is_zfs(menu_root); 6362eb2bd662Svikram INJECT_ERROR1("ROOT_OPT_NOT_ZFS", ret1 = 0); 6363eb2bd662Svikram if (!ret1 || !ret2) { 6364eb2bd662Svikram BAM_DPRINTF((D_ROOT_OPT_NOT_ZFS, fcn, osroot, menu_root)); 6365eb2bd662Svikram root_opt = (strcmp(osroot, menu_root) == 0); 6366eb2bd662Svikram goto out; 6367eb2bd662Svikram } 6368eb2bd662Svikram 6369eb2bd662Svikram ospecial = get_special(osroot); 6370eb2bd662Svikram INJECT_ERROR1("ROOT_OPTIONAL_OSPECIAL", ospecial = NULL); 6371eb2bd662Svikram if (ospecial == NULL) { 6372eb2bd662Svikram bam_error(GET_OSROOT_SPECIAL_ERR, osroot); 6373eb2bd662Svikram return (0); 6374eb2bd662Svikram } 6375eb2bd662Svikram BAM_DPRINTF((D_ROOT_OPTIONAL_OSPECIAL, fcn, ospecial, osroot)); 6376eb2bd662Svikram 6377eb2bd662Svikram mspecial = get_special(menu_root); 6378eb2bd662Svikram INJECT_ERROR1("ROOT_OPTIONAL_MSPECIAL", mspecial = NULL); 6379eb2bd662Svikram if (mspecial == NULL) { 6380eb2bd662Svikram bam_error(GET_MENU_ROOT_SPECIAL_ERR, menu_root); 6381eb2bd662Svikram free(ospecial); 6382eb2bd662Svikram return (0); 6383eb2bd662Svikram } 6384eb2bd662Svikram BAM_DPRINTF((D_ROOT_OPTIONAL_MSPECIAL, fcn, mspecial, menu_root)); 6385eb2bd662Svikram 6386eb2bd662Svikram slash = strchr(ospecial, '/'); 6387eb2bd662Svikram if (slash) 6388eb2bd662Svikram *slash = '\0'; 6389eb2bd662Svikram BAM_DPRINTF((D_ROOT_OPTIONAL_FIXED_OSPECIAL, fcn, ospecial, osroot)); 6390eb2bd662Svikram 6391eb2bd662Svikram root_opt = (strcmp(ospecial, mspecial) == 0); 6392eb2bd662Svikram 6393eb2bd662Svikram free(ospecial); 6394eb2bd662Svikram free(mspecial); 6395eb2bd662Svikram 6396eb2bd662Svikram out: 6397eb2bd662Svikram INJECT_ERROR1("ROOT_OPTIONAL_NO", root_opt = 0); 6398eb2bd662Svikram INJECT_ERROR1("ROOT_OPTIONAL_YES", root_opt = 1); 6399eb2bd662Svikram if (root_opt) { 6400eb2bd662Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 6401eb2bd662Svikram } else { 6402eb2bd662Svikram BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 6403eb2bd662Svikram } 6404eb2bd662Svikram 6405eb2bd662Svikram return (root_opt); 6406eb2bd662Svikram } 6407eb2bd662Svikram 64087c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 64097c478bd9Sstevel@tonic-gate static error_t 6410eb2bd662Svikram update_entry(menu_t *mp, char *menu_root, char *osdev) 64117c478bd9Sstevel@tonic-gate { 64127c478bd9Sstevel@tonic-gate int entry; 6413eb2bd662Svikram char *grubsign; 6414eb2bd662Svikram char *grubroot; 6415eb2bd662Svikram char *title; 6416eb2bd662Svikram char osroot[PATH_MAX]; 6417eb2bd662Svikram char *failsafe_kernel = NULL; 64188c1b6884Sszhou struct stat sbuf; 64198c1b6884Sszhou char failsafe[256]; 6420eb2bd662Svikram int ret; 6421eb2bd662Svikram const char *fcn = "update_entry()"; 64227c478bd9Sstevel@tonic-gate 64237c478bd9Sstevel@tonic-gate assert(mp); 6424eb2bd662Svikram assert(menu_root); 6425eb2bd662Svikram assert(osdev); 6426eb2bd662Svikram assert(bam_root); 64277c478bd9Sstevel@tonic-gate 6428eb2bd662Svikram BAM_DPRINTF((D_FUNC_ENTRY3, fcn, menu_root, osdev, bam_root)); 6429eb2bd662Svikram 6430eb2bd662Svikram (void) strlcpy(osroot, bam_root, sizeof (osroot)); 6431eb2bd662Svikram 64327c478bd9Sstevel@tonic-gate title = get_title(osroot); 6433eb2bd662Svikram assert(title); 64347c478bd9Sstevel@tonic-gate 6435eb2bd662Svikram grubsign = get_grubsign(osroot, osdev); 6436eb2bd662Svikram INJECT_ERROR1("GET_GRUBSIGN_FAIL", grubsign = NULL); 6437eb2bd662Svikram if (grubsign == NULL) { 6438eb2bd662Svikram bam_error(GET_GRUBSIGN_ERROR, osroot, osdev); 64397c478bd9Sstevel@tonic-gate return (BAM_ERROR); 64407c478bd9Sstevel@tonic-gate } 6441eb2bd662Svikram 6442eb2bd662Svikram /* 6443eb2bd662Svikram * It is not a fatal error if get_grubroot() fails 6444eb2bd662Svikram * We no longer rely on biosdev to populate the 6445eb2bd662Svikram * menu 6446eb2bd662Svikram */ 6447eb2bd662Svikram grubroot = get_grubroot(osroot, osdev, menu_root); 6448eb2bd662Svikram INJECT_ERROR1("GET_GRUBROOT_FAIL", grubroot = NULL); 6449eb2bd662Svikram if (grubroot) { 6450eb2bd662Svikram BAM_DPRINTF((D_GET_GRUBROOT_SUCCESS, 6451eb2bd662Svikram fcn, osroot, osdev, menu_root)); 6452eb2bd662Svikram } else { 6453eb2bd662Svikram BAM_DPRINTF((D_GET_GRUBROOT_FAILURE, 6454eb2bd662Svikram fcn, osroot, osdev, menu_root)); 64557c478bd9Sstevel@tonic-gate } 64567c478bd9Sstevel@tonic-gate 64577c478bd9Sstevel@tonic-gate /* add the entry for normal Solaris */ 6458eb2bd662Svikram INJECT_ERROR1("UPDATE_ENTRY_MULTIBOOT", 6459eb2bd662Svikram bam_direct = BAM_DIRECT_MULTIBOOT); 6460ae115bc7Smrj if (bam_direct == BAM_DIRECT_DBOOT) { 6461eb2bd662Svikram entry = update_boot_entry(mp, title, grubsign, grubroot, 6462e7cbe64fSgw25295 (bam_zfs ? DIRECT_BOOT_KERNEL_ZFS : DIRECT_BOOT_KERNEL), 6463eb2bd662Svikram NULL, DIRECT_BOOT_ARCHIVE, 6464eb2bd662Svikram root_optional(osroot, menu_root)); 6465eb2bd662Svikram BAM_DPRINTF((D_UPDATED_BOOT_ENTRY, fcn, bam_zfs, grubsign)); 6466843e1988Sjohnlev if ((entry != BAM_ERROR) && (bam_is_hv == BAM_HV_PRESENT)) { 6467eb2bd662Svikram (void) update_boot_entry(mp, NEW_HV_ENTRY, grubsign, 6468eb2bd662Svikram grubroot, XEN_MENU, bam_zfs ? 6469eb2bd662Svikram XEN_KERNEL_MODULE_LINE_ZFS : XEN_KERNEL_MODULE_LINE, 6470eb2bd662Svikram DIRECT_BOOT_ARCHIVE, 6471eb2bd662Svikram root_optional(osroot, menu_root)); 6472eb2bd662Svikram BAM_DPRINTF((D_UPDATED_HV_ENTRY, 6473eb2bd662Svikram fcn, bam_zfs, grubsign)); 6474ae115bc7Smrj } 6475843e1988Sjohnlev } else { 6476eb2bd662Svikram entry = update_boot_entry(mp, title, grubsign, grubroot, 6477eb2bd662Svikram MULTI_BOOT, NULL, MULTIBOOT_ARCHIVE, 6478eb2bd662Svikram root_optional(osroot, menu_root)); 6479eb2bd662Svikram 6480eb2bd662Svikram BAM_DPRINTF((D_UPDATED_MULTIBOOT_ENTRY, fcn, grubsign)); 6481843e1988Sjohnlev } 64827c478bd9Sstevel@tonic-gate 6483843e1988Sjohnlev /* 6484843e1988Sjohnlev * Add the entry for failsafe archive. On a bfu'd system, the 6485843e1988Sjohnlev * failsafe may be different than the installed kernel. 6486843e1988Sjohnlev */ 6487eb2bd662Svikram (void) snprintf(failsafe, sizeof (failsafe), "%s%s", 6488eb2bd662Svikram osroot, FAILSAFE_ARCHIVE); 6489ae115bc7Smrj if (stat(failsafe, &sbuf) == 0) { 649060d0a590Srscott 649160d0a590Srscott /* Figure out where the kernel line should point */ 649260d0a590Srscott (void) snprintf(failsafe, sizeof (failsafe), "%s%s", osroot, 649360d0a590Srscott DIRECT_BOOT_FAILSAFE_KERNEL); 649460d0a590Srscott if (stat(failsafe, &sbuf) == 0) { 6495963390b4Svikram failsafe_kernel = DIRECT_BOOT_FAILSAFE_LINE; 649660d0a590Srscott } else { 649760d0a590Srscott (void) snprintf(failsafe, sizeof (failsafe), "%s%s", 649860d0a590Srscott osroot, MULTI_BOOT_FAILSAFE); 649960d0a590Srscott if (stat(failsafe, &sbuf) == 0) { 650060d0a590Srscott failsafe_kernel = MULTI_BOOT_FAILSAFE_LINE; 650160d0a590Srscott } 650260d0a590Srscott } 650360d0a590Srscott if (failsafe_kernel != NULL) { 6504eb2bd662Svikram (void) update_boot_entry(mp, FAILSAFE_TITLE, grubsign, 6505eb2bd662Svikram grubroot, failsafe_kernel, NULL, FAILSAFE_ARCHIVE, 6506eb2bd662Svikram root_optional(osroot, menu_root)); 6507eb2bd662Svikram BAM_DPRINTF((D_UPDATED_FAILSAFE_ENTRY, fcn, 6508eb2bd662Svikram failsafe_kernel)); 650960d0a590Srscott } 6510ae115bc7Smrj } 6511eb2bd662Svikram free(grubroot); 65127c478bd9Sstevel@tonic-gate 6513eb2bd662Svikram INJECT_ERROR1("UPDATE_ENTRY_ERROR", entry = BAM_ERROR); 65147c478bd9Sstevel@tonic-gate if (entry == BAM_ERROR) { 6515eb2bd662Svikram bam_error(FAILED_TO_ADD_BOOT_ENTRY, title, grubsign); 6516eb2bd662Svikram free(grubsign); 65177c478bd9Sstevel@tonic-gate return (BAM_ERROR); 65187c478bd9Sstevel@tonic-gate } 6519eb2bd662Svikram free(grubsign); 6520eb2bd662Svikram 6521eb2bd662Svikram update_numbering(mp); 6522eb2bd662Svikram ret = set_global(mp, menu_cmds[DEFAULT_CMD], entry); 6523eb2bd662Svikram INJECT_ERROR1("SET_DEFAULT_ERROR", ret = BAM_ERROR); 6524eb2bd662Svikram if (ret == BAM_ERROR) { 6525eb2bd662Svikram bam_error(SET_DEFAULT_FAILED, entry); 6526eb2bd662Svikram } 6527eb2bd662Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 65287c478bd9Sstevel@tonic-gate return (BAM_WRITE); 65297c478bd9Sstevel@tonic-gate } 65307c478bd9Sstevel@tonic-gate 65318c1b6884Sszhou static void 6532ae115bc7Smrj save_default_entry(menu_t *mp, const char *which) 65338c1b6884Sszhou { 6534eb2bd662Svikram int lineNum; 6535eb2bd662Svikram int entryNum; 65368c1b6884Sszhou int entry = 0; /* default is 0 */ 65378c1b6884Sszhou char linebuf[BAM_MAXLINE]; 65388c1b6884Sszhou line_t *lp = mp->curdefault; 6539eb2bd662Svikram const char *fcn = "save_default_entry()"; 65408c1b6884Sszhou 6541bff269d0Svikram if (mp->start) { 6542bff269d0Svikram lineNum = mp->end->lineNum; 6543bff269d0Svikram entryNum = mp->end->entryNum; 6544bff269d0Svikram } else { 6545bff269d0Svikram lineNum = LINE_INIT; 6546bff269d0Svikram entryNum = ENTRY_INIT; 6547bff269d0Svikram } 6548bff269d0Svikram 65498c1b6884Sszhou if (lp) 65508c1b6884Sszhou entry = s_strtol(lp->arg); 65518c1b6884Sszhou 6552ae115bc7Smrj (void) snprintf(linebuf, sizeof (linebuf), "#%s%d", which, entry); 6553eb2bd662Svikram BAM_DPRINTF((D_SAVING_DEFAULT_TO, fcn, linebuf)); 65548c1b6884Sszhou line_parser(mp, linebuf, &lineNum, &entryNum); 6555eb2bd662Svikram BAM_DPRINTF((D_SAVED_DEFAULT_TO, fcn, lineNum, entryNum)); 65568c1b6884Sszhou } 65578c1b6884Sszhou 65588c1b6884Sszhou static void 6559ae115bc7Smrj restore_default_entry(menu_t *mp, const char *which, line_t *lp) 65608c1b6884Sszhou { 65618c1b6884Sszhou int entry; 65628c1b6884Sszhou char *str; 6563eb2bd662Svikram const char *fcn = "restore_default_entry()"; 65648c1b6884Sszhou 6565eb2bd662Svikram if (lp == NULL) { 6566eb2bd662Svikram BAM_DPRINTF((D_RESTORE_DEFAULT_NULL, fcn)); 65678c1b6884Sszhou return; /* nothing to restore */ 6568eb2bd662Svikram } 6569eb2bd662Svikram 6570eb2bd662Svikram BAM_DPRINTF((D_RESTORE_DEFAULT_STR, fcn, which)); 65718c1b6884Sszhou 6572ae115bc7Smrj str = lp->arg + strlen(which); 65738c1b6884Sszhou entry = s_strtol(str); 65748c1b6884Sszhou (void) set_global(mp, menu_cmds[DEFAULT_CMD], entry); 65758c1b6884Sszhou 6576eb2bd662Svikram BAM_DPRINTF((D_RESTORED_DEFAULT_TO, fcn, entry)); 6577eb2bd662Svikram 65788c1b6884Sszhou /* delete saved old default line */ 65798c1b6884Sszhou unlink_line(mp, lp); 65808c1b6884Sszhou line_free(lp); 65818c1b6884Sszhou } 65828c1b6884Sszhou 65837c478bd9Sstevel@tonic-gate /* 65847c478bd9Sstevel@tonic-gate * This function is for supporting reboot with args. 65857c478bd9Sstevel@tonic-gate * The opt value can be: 65867c478bd9Sstevel@tonic-gate * NULL delete temp entry, if present 6587eb2bd662Svikram * entry=<n> switches default entry to <n> 65887c478bd9Sstevel@tonic-gate * else treated as boot-args and setup a temperary menu entry 65897c478bd9Sstevel@tonic-gate * and make it the default 6590eb2bd662Svikram * Note that we are always rebooting the current OS instance 6591eb2bd662Svikram * so osroot == / always. 65927c478bd9Sstevel@tonic-gate */ 65937c478bd9Sstevel@tonic-gate #define REBOOT_TITLE "Solaris_reboot_transient" 65947c478bd9Sstevel@tonic-gate 65958c1b6884Sszhou /*ARGSUSED*/ 65967c478bd9Sstevel@tonic-gate static error_t 6597eb2bd662Svikram update_temp(menu_t *mp, char *dummy, char *opt) 65987c478bd9Sstevel@tonic-gate { 65997c478bd9Sstevel@tonic-gate int entry; 6600eb2bd662Svikram char *osdev; 6601eb2bd662Svikram char *fstype; 6602eb2bd662Svikram char *sign; 6603eb2bd662Svikram char *opt_ptr; 6604eb2bd662Svikram char *path; 6605ae115bc7Smrj char kernbuf[BUFSIZ]; 6606ae115bc7Smrj char args_buf[BUFSIZ]; 6607eb2bd662Svikram char signbuf[PATH_MAX]; 6608eb2bd662Svikram int ret; 6609eb2bd662Svikram const char *fcn = "update_temp()"; 66107c478bd9Sstevel@tonic-gate 66117c478bd9Sstevel@tonic-gate assert(mp); 6612eb2bd662Svikram assert(dummy == NULL); 6613eb2bd662Svikram 6614eb2bd662Svikram /* opt can be NULL */ 6615eb2bd662Svikram BAM_DPRINTF((D_FUNC_ENTRY1, fcn, opt ? opt : "<NULL>")); 6616eb2bd662Svikram BAM_DPRINTF((D_BAM_ROOT, fcn, bam_alt_root, bam_root)); 6617eb2bd662Svikram 6618eb2bd662Svikram if (bam_alt_root || bam_rootlen != 1 || 6619eb2bd662Svikram strcmp(bam_root, "/") != 0 || 6620eb2bd662Svikram strcmp(rootbuf, "/") != 0) { 6621eb2bd662Svikram bam_error(ALT_ROOT_INVALID, bam_root); 6622eb2bd662Svikram return (BAM_ERROR); 6623eb2bd662Svikram } 66247c478bd9Sstevel@tonic-gate 66258c1b6884Sszhou /* If no option, delete exiting reboot menu entry */ 66268c1b6884Sszhou if (opt == NULL) { 6627eb2bd662Svikram entry_t *ent; 6628eb2bd662Svikram BAM_DPRINTF((D_OPT_NULL, fcn)); 6629eb2bd662Svikram ent = find_boot_entry(mp, REBOOT_TITLE, NULL, NULL, 6630eb2bd662Svikram NULL, NULL, 0, &entry); 6631eb2bd662Svikram if (ent == NULL) { /* not found is ok */ 6632eb2bd662Svikram BAM_DPRINTF((D_TRANSIENT_NOTFOUND, fcn)); 66338c1b6884Sszhou return (BAM_SUCCESS); 6634eb2bd662Svikram } 66358c1b6884Sszhou (void) do_delete(mp, entry); 6636ae115bc7Smrj restore_default_entry(mp, BAM_OLDDEF, mp->olddefault); 6637ae115bc7Smrj mp->olddefault = NULL; 6638eb2bd662Svikram BAM_DPRINTF((D_RESTORED_DEFAULT, fcn)); 6639eb2bd662Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 66408c1b6884Sszhou return (BAM_WRITE); 66418c1b6884Sszhou } 66428c1b6884Sszhou 66438c1b6884Sszhou /* if entry= is specified, set the default entry */ 6644eb2bd662Svikram if (strncmp(opt, "entry=", strlen("entry=")) == 0) { 6645eb2bd662Svikram int entryNum = s_strtol(opt + strlen("entry=")); 6646eb2bd662Svikram BAM_DPRINTF((D_ENTRY_EQUALS, fcn, opt)); 6647eb2bd662Svikram if (selector(mp, opt, &entry, NULL) == BAM_SUCCESS) { 66487c478bd9Sstevel@tonic-gate /* this is entry=# option */ 6649eb2bd662Svikram ret = set_global(mp, menu_cmds[DEFAULT_CMD], entry); 6650eb2bd662Svikram BAM_DPRINTF((D_ENTRY_SET_IS, fcn, entry, ret)); 6651eb2bd662Svikram return (ret); 6652eb2bd662Svikram } else { 6653eb2bd662Svikram bam_error(SET_DEFAULT_FAILED, entryNum); 6654eb2bd662Svikram return (BAM_ERROR); 6655eb2bd662Svikram } 66567c478bd9Sstevel@tonic-gate } 66577c478bd9Sstevel@tonic-gate 66587c478bd9Sstevel@tonic-gate /* 6659eb2bd662Svikram * add a new menu entry based on opt and make it the default 6660b610f78eSvikram */ 6661eb2bd662Svikram 6662eb2bd662Svikram fstype = get_fstype("/"); 6663eb2bd662Svikram INJECT_ERROR1("REBOOT_FSTYPE_NULL", fstype = NULL); 6664eb2bd662Svikram if (fstype == NULL) { 6665eb2bd662Svikram bam_error(REBOOT_FSTYPE_FAILED); 6666eb2bd662Svikram return (BAM_ERROR); 66677c478bd9Sstevel@tonic-gate } 6668eb2bd662Svikram 6669eb2bd662Svikram osdev = get_special("/"); 6670eb2bd662Svikram INJECT_ERROR1("REBOOT_SPECIAL_NULL", osdev = NULL); 6671eb2bd662Svikram if (osdev == NULL) { 6672eb2bd662Svikram free(fstype); 6673eb2bd662Svikram bam_error(REBOOT_SPECIAL_FAILED); 6674eb2bd662Svikram return (BAM_ERROR); 6675b610f78eSvikram } 6676eb2bd662Svikram 6677eb2bd662Svikram sign = find_existing_sign("/", osdev, fstype); 6678eb2bd662Svikram INJECT_ERROR1("REBOOT_SIGN_NULL", sign = NULL); 6679eb2bd662Svikram if (sign == NULL) { 6680eb2bd662Svikram free(fstype); 6681eb2bd662Svikram free(osdev); 6682eb2bd662Svikram bam_error(REBOOT_SIGN_FAILED); 6683eb2bd662Svikram return (BAM_ERROR); 6684eb2bd662Svikram } 6685eb2bd662Svikram 6686eb2bd662Svikram free(fstype); 6687eb2bd662Svikram free(osdev); 6688eb2bd662Svikram (void) strlcpy(signbuf, sign, sizeof (signbuf)); 6689eb2bd662Svikram free(sign); 6690eb2bd662Svikram 6691eb2bd662Svikram assert(strchr(signbuf, '(') == NULL && strchr(signbuf, ',') == NULL && 6692eb2bd662Svikram strchr(signbuf, ')') == NULL); 6693eb2bd662Svikram 6694eb2bd662Svikram /* 6695eb2bd662Svikram * There is no alternate root while doing reboot with args 6696eb2bd662Svikram * This version of bootadm is only delivered with a DBOOT 6697eb2bd662Svikram * version of Solaris. 6698eb2bd662Svikram */ 6699eb2bd662Svikram INJECT_ERROR1("REBOOT_NOT_DBOOT", bam_direct = BAM_DIRECT_MULTIBOOT); 6700eb2bd662Svikram if (bam_direct != BAM_DIRECT_DBOOT) { 6701eb2bd662Svikram bam_error(REBOOT_DIRECT_FAILED); 67027c478bd9Sstevel@tonic-gate return (BAM_ERROR); 67037c478bd9Sstevel@tonic-gate } 67047c478bd9Sstevel@tonic-gate 67057c478bd9Sstevel@tonic-gate /* add an entry for Solaris reboot */ 6706ae115bc7Smrj if (opt[0] == '-') { 6707ae115bc7Smrj /* It's an option - first see if boot-file is set */ 6708eb2bd662Svikram ret = get_kernel(mp, KERNEL_CMD, kernbuf, sizeof (kernbuf)); 6709eb2bd662Svikram INJECT_ERROR1("REBOOT_GET_KERNEL", ret = BAM_ERROR); 6710eb2bd662Svikram if (ret != BAM_SUCCESS) { 6711eb2bd662Svikram bam_error(REBOOT_GET_KERNEL_FAILED); 6712ae115bc7Smrj return (BAM_ERROR); 6713eb2bd662Svikram } 6714ae115bc7Smrj if (kernbuf[0] == '\0') 6715eb2bd662Svikram (void) strlcpy(kernbuf, DIRECT_BOOT_KERNEL, 6716eb2bd662Svikram sizeof (kernbuf)); 6717eb2bd662Svikram (void) strlcat(kernbuf, " ", sizeof (kernbuf)); 6718eb2bd662Svikram (void) strlcat(kernbuf, opt, sizeof (kernbuf)); 6719eb2bd662Svikram BAM_DPRINTF((D_REBOOT_OPTION, fcn, kernbuf)); 6720ae115bc7Smrj } else if (opt[0] == '/') { 6721455710d3Srscott /* It's a full path, so write it out. */ 6722eb2bd662Svikram (void) strlcpy(kernbuf, opt, sizeof (kernbuf)); 6723455710d3Srscott 6724455710d3Srscott /* 6725455710d3Srscott * If someone runs: 6726455710d3Srscott * 6727455710d3Srscott * # eeprom boot-args='-kd' 6728455710d3Srscott * # reboot /platform/i86pc/kernel/unix 6729455710d3Srscott * 6730455710d3Srscott * we want to use the boot-args as part of the boot 6731455710d3Srscott * line. On the other hand, if someone runs: 6732455710d3Srscott * 6733455710d3Srscott * # reboot "/platform/i86pc/kernel/unix -kd" 6734455710d3Srscott * 6735455710d3Srscott * we don't need to mess with boot-args. If there's 6736455710d3Srscott * no space in the options string, assume we're in the 6737455710d3Srscott * first case. 6738455710d3Srscott */ 6739455710d3Srscott if (strchr(opt, ' ') == NULL) { 6740eb2bd662Svikram ret = get_kernel(mp, ARGS_CMD, args_buf, 6741eb2bd662Svikram sizeof (args_buf)); 6742eb2bd662Svikram INJECT_ERROR1("REBOOT_GET_ARGS", ret = BAM_ERROR); 6743eb2bd662Svikram if (ret != BAM_SUCCESS) { 6744eb2bd662Svikram bam_error(REBOOT_GET_ARGS_FAILED); 6745455710d3Srscott return (BAM_ERROR); 6746eb2bd662Svikram } 6747455710d3Srscott 6748455710d3Srscott if (args_buf[0] != '\0') { 6749eb2bd662Svikram (void) strlcat(kernbuf, " ", sizeof (kernbuf)); 6750455710d3Srscott (void) strlcat(kernbuf, args_buf, 6751eb2bd662Svikram sizeof (kernbuf)); 6752455710d3Srscott } 6753455710d3Srscott } 6754eb2bd662Svikram BAM_DPRINTF((D_REBOOT_ABSPATH, fcn, kernbuf)); 6755ae115bc7Smrj } else { 6756455710d3Srscott /* 6757455710d3Srscott * It may be a partial path, or it may be a partial 6758455710d3Srscott * path followed by options. Assume that only options 6759455710d3Srscott * follow a space. If someone sends us a kernel path 6760455710d3Srscott * that includes a space, they deserve to be broken. 6761455710d3Srscott */ 6762455710d3Srscott opt_ptr = strchr(opt, ' '); 6763455710d3Srscott if (opt_ptr != NULL) { 6764455710d3Srscott *opt_ptr = '\0'; 6765455710d3Srscott } 6766455710d3Srscott 6767ae115bc7Smrj path = expand_path(opt); 6768ae115bc7Smrj if (path != NULL) { 6769eb2bd662Svikram (void) strlcpy(kernbuf, path, sizeof (kernbuf)); 6770ae115bc7Smrj free(path); 6771455710d3Srscott 6772455710d3Srscott /* 6773455710d3Srscott * If there were options given, use those. 6774455710d3Srscott * Otherwise, copy over the default options. 6775455710d3Srscott */ 6776455710d3Srscott if (opt_ptr != NULL) { 6777455710d3Srscott /* Restore the space in opt string */ 6778455710d3Srscott *opt_ptr = ' '; 6779455710d3Srscott (void) strlcat(kernbuf, opt_ptr, 6780eb2bd662Svikram sizeof (kernbuf)); 6781455710d3Srscott } else { 6782eb2bd662Svikram ret = get_kernel(mp, ARGS_CMD, args_buf, 6783eb2bd662Svikram sizeof (args_buf)); 6784eb2bd662Svikram INJECT_ERROR1("UPDATE_TEMP_PARTIAL_ARGS", 6785eb2bd662Svikram ret = BAM_ERROR); 6786eb2bd662Svikram if (ret != BAM_SUCCESS) { 6787eb2bd662Svikram bam_error(REBOOT_GET_ARGS_FAILED); 6788ae115bc7Smrj return (BAM_ERROR); 6789eb2bd662Svikram } 6790ae115bc7Smrj 6791ae115bc7Smrj if (args_buf[0] != '\0') { 6792ae115bc7Smrj (void) strlcat(kernbuf, " ", 6793eb2bd662Svikram sizeof (kernbuf)); 6794ae115bc7Smrj (void) strlcat(kernbuf, 6795eb2bd662Svikram args_buf, sizeof (kernbuf)); 6796ae115bc7Smrj } 6797ae115bc7Smrj } 6798eb2bd662Svikram BAM_DPRINTF((D_REBOOT_RESOLVED_PARTIAL, fcn, kernbuf)); 6799455710d3Srscott } else { 6800455710d3Srscott bam_error(UNKNOWN_KERNEL, opt); 6801455710d3Srscott bam_print_stderr(UNKNOWN_KERNEL_REBOOT); 6802455710d3Srscott return (BAM_ERROR); 6803ae115bc7Smrj } 6804ae115bc7Smrj } 6805eb2bd662Svikram entry = add_boot_entry(mp, REBOOT_TITLE, signbuf, kernbuf, 6806843e1988Sjohnlev NULL, NULL); 6807eb2bd662Svikram INJECT_ERROR1("REBOOT_ADD_BOOT_ENTRY", entry = BAM_ERROR); 68087c478bd9Sstevel@tonic-gate if (entry == BAM_ERROR) { 6809eb2bd662Svikram bam_error(REBOOT_WITH_ARGS_ADD_ENTRY_FAILED); 68107c478bd9Sstevel@tonic-gate return (BAM_ERROR); 68117c478bd9Sstevel@tonic-gate } 68128c1b6884Sszhou 6813ae115bc7Smrj save_default_entry(mp, BAM_OLDDEF); 6814eb2bd662Svikram ret = set_global(mp, menu_cmds[DEFAULT_CMD], entry); 6815eb2bd662Svikram INJECT_ERROR1("REBOOT_SET_GLOBAL", ret = BAM_ERROR); 6816eb2bd662Svikram if (ret == BAM_ERROR) { 6817eb2bd662Svikram bam_error(REBOOT_SET_DEFAULT_FAILED, entry); 6818eb2bd662Svikram } 6819eb2bd662Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 68207c478bd9Sstevel@tonic-gate return (BAM_WRITE); 68217c478bd9Sstevel@tonic-gate } 68227c478bd9Sstevel@tonic-gate 68237c478bd9Sstevel@tonic-gate static error_t 68247c478bd9Sstevel@tonic-gate set_global(menu_t *mp, char *globalcmd, int val) 68257c478bd9Sstevel@tonic-gate { 6826eb2bd662Svikram line_t *lp; 6827eb2bd662Svikram line_t *found; 6828eb2bd662Svikram line_t *last; 6829eb2bd662Svikram char *cp; 6830eb2bd662Svikram char *str; 68317c478bd9Sstevel@tonic-gate char prefix[BAM_MAXLINE]; 68327c478bd9Sstevel@tonic-gate size_t len; 6833eb2bd662Svikram const char *fcn = "set_global()"; 68347c478bd9Sstevel@tonic-gate 68357c478bd9Sstevel@tonic-gate assert(mp); 68367c478bd9Sstevel@tonic-gate assert(globalcmd); 68377c478bd9Sstevel@tonic-gate 6838b610f78eSvikram if (strcmp(globalcmd, menu_cmds[DEFAULT_CMD]) == 0) { 6839eb2bd662Svikram INJECT_ERROR1("SET_GLOBAL_VAL_NEG", val = -1); 6840eb2bd662Svikram INJECT_ERROR1("SET_GLOBAL_MENU_EMPTY", mp->end = NULL); 6841eb2bd662Svikram INJECT_ERROR1("SET_GLOBAL_VAL_TOO_BIG", val = 100); 6842b610f78eSvikram if (val < 0 || mp->end == NULL || val > mp->end->entryNum) { 6843b610f78eSvikram (void) snprintf(prefix, sizeof (prefix), "%d", val); 6844b610f78eSvikram bam_error(INVALID_ENTRY, prefix); 6845b610f78eSvikram return (BAM_ERROR); 6846b610f78eSvikram } 6847b610f78eSvikram } 6848b610f78eSvikram 68497c478bd9Sstevel@tonic-gate found = last = NULL; 68507c478bd9Sstevel@tonic-gate for (lp = mp->start; lp; lp = lp->next) { 68517c478bd9Sstevel@tonic-gate if (lp->flags != BAM_GLOBAL) 68527c478bd9Sstevel@tonic-gate continue; 68537c478bd9Sstevel@tonic-gate 68547c478bd9Sstevel@tonic-gate last = lp; /* track the last global found */ 68557c478bd9Sstevel@tonic-gate 6856eb2bd662Svikram INJECT_ERROR1("SET_GLOBAL_NULL_CMD", lp->cmd = NULL); 68577c478bd9Sstevel@tonic-gate if (lp->cmd == NULL) { 68587c478bd9Sstevel@tonic-gate bam_error(NO_CMD, lp->lineNum); 68597c478bd9Sstevel@tonic-gate continue; 68607c478bd9Sstevel@tonic-gate } 68617c478bd9Sstevel@tonic-gate if (strcmp(globalcmd, lp->cmd) != 0) 68627c478bd9Sstevel@tonic-gate continue; 68637c478bd9Sstevel@tonic-gate 6864eb2bd662Svikram BAM_DPRINTF((D_FOUND_GLOBAL, fcn, globalcmd)); 6865eb2bd662Svikram 68667c478bd9Sstevel@tonic-gate if (found) { 68677c478bd9Sstevel@tonic-gate bam_error(DUP_CMD, globalcmd, lp->lineNum, bam_root); 68687c478bd9Sstevel@tonic-gate } 68697c478bd9Sstevel@tonic-gate found = lp; 68707c478bd9Sstevel@tonic-gate } 68717c478bd9Sstevel@tonic-gate 68727c478bd9Sstevel@tonic-gate if (found == NULL) { 68737c478bd9Sstevel@tonic-gate lp = s_calloc(1, sizeof (line_t)); 68747c478bd9Sstevel@tonic-gate if (last == NULL) { 68757c478bd9Sstevel@tonic-gate lp->next = mp->start; 68767c478bd9Sstevel@tonic-gate mp->start = lp; 68777c478bd9Sstevel@tonic-gate mp->end = (mp->end) ? mp->end : lp; 68787c478bd9Sstevel@tonic-gate } else { 68797c478bd9Sstevel@tonic-gate lp->next = last->next; 68807c478bd9Sstevel@tonic-gate last->next = lp; 68817c478bd9Sstevel@tonic-gate if (lp->next == NULL) 68827c478bd9Sstevel@tonic-gate mp->end = lp; 68837c478bd9Sstevel@tonic-gate } 68847c478bd9Sstevel@tonic-gate lp->flags = BAM_GLOBAL; /* other fields not needed for writes */ 68857c478bd9Sstevel@tonic-gate len = strlen(globalcmd) + strlen(menu_cmds[SEP_CMD]); 68867c478bd9Sstevel@tonic-gate len += 10; /* val < 10 digits */ 68877c478bd9Sstevel@tonic-gate lp->line = s_calloc(1, len); 68887c478bd9Sstevel@tonic-gate (void) snprintf(lp->line, len, "%s%s%d", 68897c478bd9Sstevel@tonic-gate globalcmd, menu_cmds[SEP_CMD], val); 6890eb2bd662Svikram BAM_DPRINTF((D_SET_GLOBAL_WROTE_NEW, fcn, lp->line)); 6891eb2bd662Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 68927c478bd9Sstevel@tonic-gate return (BAM_WRITE); 68937c478bd9Sstevel@tonic-gate } 68947c478bd9Sstevel@tonic-gate 68957c478bd9Sstevel@tonic-gate /* 68967c478bd9Sstevel@tonic-gate * We are changing an existing entry. Retain any prefix whitespace, 68977c478bd9Sstevel@tonic-gate * but overwrite everything else. This preserves tabs added for 68987c478bd9Sstevel@tonic-gate * readability. 68997c478bd9Sstevel@tonic-gate */ 69007c478bd9Sstevel@tonic-gate str = found->line; 69017c478bd9Sstevel@tonic-gate cp = prefix; 69027c478bd9Sstevel@tonic-gate while (*str == ' ' || *str == '\t') 69037c478bd9Sstevel@tonic-gate *(cp++) = *(str++); 69047c478bd9Sstevel@tonic-gate *cp = '\0'; /* Terminate prefix */ 69057c478bd9Sstevel@tonic-gate len = strlen(prefix) + strlen(globalcmd); 69067c478bd9Sstevel@tonic-gate len += strlen(menu_cmds[SEP_CMD]) + 10; 69077c478bd9Sstevel@tonic-gate 69087c478bd9Sstevel@tonic-gate free(found->line); 69097c478bd9Sstevel@tonic-gate found->line = s_calloc(1, len); 69107c478bd9Sstevel@tonic-gate (void) snprintf(found->line, len, 69117c478bd9Sstevel@tonic-gate "%s%s%s%d", prefix, globalcmd, menu_cmds[SEP_CMD], val); 69127c478bd9Sstevel@tonic-gate 6913eb2bd662Svikram BAM_DPRINTF((D_SET_GLOBAL_REPLACED, fcn, found->line)); 6914eb2bd662Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 69157c478bd9Sstevel@tonic-gate return (BAM_WRITE); /* need a write to menu */ 69167c478bd9Sstevel@tonic-gate } 69177c478bd9Sstevel@tonic-gate 6918ae115bc7Smrj /* 6919ae115bc7Smrj * partial_path may be anything like "kernel/unix" or "kmdb". Try to 6920455710d3Srscott * expand it to a full unix path. The calling function is expected to 6921455710d3Srscott * output a message if an error occurs and NULL is returned. 6922ae115bc7Smrj */ 6923ae115bc7Smrj static char * 6924ae115bc7Smrj expand_path(const char *partial_path) 6925ae115bc7Smrj { 6926ae115bc7Smrj int new_path_len; 6927eb2bd662Svikram char *new_path; 6928eb2bd662Svikram char new_path2[PATH_MAX]; 6929ae115bc7Smrj struct stat sb; 6930eb2bd662Svikram const char *fcn = "expand_path()"; 6931ae115bc7Smrj 6932ae115bc7Smrj new_path_len = strlen(partial_path) + 64; 6933ae115bc7Smrj new_path = s_calloc(1, new_path_len); 6934ae115bc7Smrj 6935ae115bc7Smrj /* First, try the simplest case - something like "kernel/unix" */ 6936ae115bc7Smrj (void) snprintf(new_path, new_path_len, "/platform/i86pc/%s", 6937ae115bc7Smrj partial_path); 6938ae115bc7Smrj if (stat(new_path, &sb) == 0) { 6939eb2bd662Svikram BAM_DPRINTF((D_EXPAND_PATH, fcn, new_path)); 6940ae115bc7Smrj return (new_path); 6941ae115bc7Smrj } 6942ae115bc7Smrj 6943ae115bc7Smrj if (strcmp(partial_path, "kmdb") == 0) { 6944ae115bc7Smrj (void) snprintf(new_path, new_path_len, "%s -k", 6945ae115bc7Smrj DIRECT_BOOT_KERNEL); 6946eb2bd662Svikram BAM_DPRINTF((D_EXPAND_PATH, fcn, new_path)); 6947ae115bc7Smrj return (new_path); 6948ae115bc7Smrj } 6949ae115bc7Smrj 6950ae115bc7Smrj /* 6951ae115bc7Smrj * We've quickly reached unsupported usage. Try once more to 6952ae115bc7Smrj * see if we were just given a glom name. 6953ae115bc7Smrj */ 6954ae115bc7Smrj (void) snprintf(new_path, new_path_len, "/platform/i86pc/%s/unix", 6955ae115bc7Smrj partial_path); 6956ae115bc7Smrj (void) snprintf(new_path2, PATH_MAX, "/platform/i86pc/%s/amd64/unix", 6957ae115bc7Smrj partial_path); 6958ae115bc7Smrj if (stat(new_path, &sb) == 0) { 6959ae115bc7Smrj if (stat(new_path2, &sb) == 0) { 6960ae115bc7Smrj /* 6961ae115bc7Smrj * We matched both, so we actually 6962ae115bc7Smrj * want to write the $ISADIR version. 6963ae115bc7Smrj */ 6964ae115bc7Smrj (void) snprintf(new_path, new_path_len, 6965ae115bc7Smrj "/platform/i86pc/kernel/%s/$ISADIR/unix", 6966ae115bc7Smrj partial_path); 6967ae115bc7Smrj } 6968eb2bd662Svikram BAM_DPRINTF((D_EXPAND_PATH, fcn, new_path)); 6969ae115bc7Smrj return (new_path); 6970ae115bc7Smrj } 6971ae115bc7Smrj 6972ae115bc7Smrj free(new_path); 6973eb2bd662Svikram BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 6974ae115bc7Smrj return (NULL); 6975ae115bc7Smrj } 6976ae115bc7Smrj 6977ae115bc7Smrj /* 6978ae115bc7Smrj * The kernel cmd and arg have been changed, so 6979ae115bc7Smrj * check whether the archive line needs to change. 6980ae115bc7Smrj */ 6981ae115bc7Smrj static void 6982ae115bc7Smrj set_archive_line(entry_t *entryp, line_t *kernelp) 6983ae115bc7Smrj { 6984ae115bc7Smrj line_t *lp = entryp->start; 6985ae115bc7Smrj char *new_archive; 6986ae115bc7Smrj menu_cmd_t m_cmd; 6987eb2bd662Svikram const char *fcn = "set_archive_line()"; 6988ae115bc7Smrj 6989ae115bc7Smrj for (; lp != NULL; lp = lp->next) { 6990ae115bc7Smrj if (strncmp(lp->cmd, menu_cmds[MODULE_CMD], 6991ae115bc7Smrj sizeof (menu_cmds[MODULE_CMD]) - 1) == 0) { 6992ae115bc7Smrj break; 6993ae115bc7Smrj } 6994eb2bd662Svikram 6995eb2bd662Svikram INJECT_ERROR1("SET_ARCHIVE_LINE_END_ENTRY", lp = entryp->end); 6996eb2bd662Svikram if (lp == entryp->end) { 6997eb2bd662Svikram BAM_DPRINTF((D_ARCHIVE_LINE_NONE, fcn, 6998eb2bd662Svikram entryp->entryNum)); 6999ae115bc7Smrj return; 7000ae115bc7Smrj } 7001eb2bd662Svikram } 7002eb2bd662Svikram INJECT_ERROR1("SET_ARCHIVE_LINE_END_MENU", lp = NULL); 7003eb2bd662Svikram if (lp == NULL) { 7004eb2bd662Svikram BAM_DPRINTF((D_ARCHIVE_LINE_NONE, fcn, entryp->entryNum)); 7005ae115bc7Smrj return; 7006eb2bd662Svikram } 7007ae115bc7Smrj 7008ae115bc7Smrj if (strstr(kernelp->arg, "$ISADIR") != NULL) { 7009ae115bc7Smrj new_archive = DIRECT_BOOT_ARCHIVE; 7010ae115bc7Smrj m_cmd = MODULE_DOLLAR_CMD; 7011ae115bc7Smrj } else if (strstr(kernelp->arg, "amd64") != NULL) { 7012ae115bc7Smrj new_archive = DIRECT_BOOT_ARCHIVE_64; 7013ae115bc7Smrj m_cmd = MODULE_CMD; 7014ae115bc7Smrj } else { 7015ae115bc7Smrj new_archive = DIRECT_BOOT_ARCHIVE_32; 7016ae115bc7Smrj m_cmd = MODULE_CMD; 7017ae115bc7Smrj } 7018ae115bc7Smrj 7019eb2bd662Svikram if (strcmp(lp->arg, new_archive) == 0) { 7020eb2bd662Svikram BAM_DPRINTF((D_ARCHIVE_LINE_NOCHANGE, fcn, lp->arg)); 7021ae115bc7Smrj return; 7022eb2bd662Svikram } 7023ae115bc7Smrj 7024ae115bc7Smrj if (strcmp(lp->cmd, menu_cmds[m_cmd]) != 0) { 7025ae115bc7Smrj free(lp->cmd); 7026ae115bc7Smrj lp->cmd = s_strdup(menu_cmds[m_cmd]); 7027ae115bc7Smrj } 7028ae115bc7Smrj 7029ae115bc7Smrj free(lp->arg); 7030ae115bc7Smrj lp->arg = s_strdup(new_archive); 7031ae115bc7Smrj update_line(lp); 7032eb2bd662Svikram BAM_DPRINTF((D_ARCHIVE_LINE_REPLACED, fcn, lp->line)); 7033ae115bc7Smrj } 7034ae115bc7Smrj 7035ae115bc7Smrj /* 7036ae115bc7Smrj * Title for an entry to set properties that once went in bootenv.rc. 7037ae115bc7Smrj */ 7038ae115bc7Smrj #define BOOTENV_RC_TITLE "Solaris bootenv rc" 7039ae115bc7Smrj 7040ae115bc7Smrj /* 7041ae115bc7Smrj * If path is NULL, return the kernel (optnum == KERNEL_CMD) or arguments 7042ae115bc7Smrj * (optnum == ARGS_CMD) in the argument buf. If path is a zero-length 7043ae115bc7Smrj * string, reset the value to the default. If path is a non-zero-length 7044ae115bc7Smrj * string, set the kernel or arguments. 7045ae115bc7Smrj */ 7046ae115bc7Smrj static error_t 7047eb2bd662Svikram get_set_kernel( 7048eb2bd662Svikram menu_t *mp, 7049eb2bd662Svikram menu_cmd_t optnum, 7050eb2bd662Svikram char *path, 7051eb2bd662Svikram char *buf, 7052eb2bd662Svikram size_t bufsize) 7053ae115bc7Smrj { 7054eb2bd662Svikram int entryNum; 7055eb2bd662Svikram int rv = BAM_SUCCESS; 7056eb2bd662Svikram int free_new_path = 0; 7057ae115bc7Smrj entry_t *entryp; 7058eb2bd662Svikram line_t *ptr; 7059eb2bd662Svikram line_t *kernelp; 7060eb2bd662Svikram char *new_arg; 7061eb2bd662Svikram char *old_args; 7062eb2bd662Svikram char *space; 7063eb2bd662Svikram char *new_path; 7064ae115bc7Smrj char old_space; 7065eb2bd662Svikram size_t old_kernel_len; 7066eb2bd662Svikram size_t new_str_len; 7067eb2bd662Svikram char *fstype; 7068eb2bd662Svikram char *osdev; 7069eb2bd662Svikram char *sign; 7070eb2bd662Svikram char signbuf[PATH_MAX]; 7071eb2bd662Svikram int ret; 7072eb2bd662Svikram const char *fcn = "get_set_kernel()"; 7073ae115bc7Smrj 7074ae115bc7Smrj assert(bufsize > 0); 7075ae115bc7Smrj 7076ae115bc7Smrj ptr = kernelp = NULL; 7077ae115bc7Smrj new_arg = old_args = space = NULL; 7078eb2bd662Svikram new_path = NULL; 7079ae115bc7Smrj buf[0] = '\0'; 7080ae115bc7Smrj 7081eb2bd662Svikram INJECT_ERROR1("GET_SET_KERNEL_NOT_DBOOT", 7082eb2bd662Svikram bam_direct = BAM_DIRECT_MULTIBOOT); 7083ae115bc7Smrj if (bam_direct != BAM_DIRECT_DBOOT) { 7084ae115bc7Smrj bam_error(NOT_DBOOT, optnum == KERNEL_CMD ? "kernel" : "args"); 7085ae115bc7Smrj return (BAM_ERROR); 7086ae115bc7Smrj } 7087ae115bc7Smrj 7088ae115bc7Smrj /* 7089ae115bc7Smrj * If a user changed the default entry to a non-bootadm controlled 7090ae115bc7Smrj * one, we don't want to mess with it. Just print an error and 7091ae115bc7Smrj * return. 7092ae115bc7Smrj */ 7093ae115bc7Smrj if (mp->curdefault) { 7094ae115bc7Smrj entryNum = s_strtol(mp->curdefault->arg); 7095ae115bc7Smrj for (entryp = mp->entries; entryp; entryp = entryp->next) { 7096ae115bc7Smrj if (entryp->entryNum == entryNum) 7097ae115bc7Smrj break; 7098ae115bc7Smrj } 7099ae115bc7Smrj if ((entryp != NULL) && 7100ae115bc7Smrj ((entryp->flags & (BAM_ENTRY_BOOTADM|BAM_ENTRY_LU)) == 0)) { 7101ae115bc7Smrj bam_error(DEFAULT_NOT_BAM); 7102ae115bc7Smrj return (BAM_ERROR); 7103ae115bc7Smrj } 7104ae115bc7Smrj } 7105ae115bc7Smrj 7106eb2bd662Svikram entryp = find_boot_entry(mp, BOOTENV_RC_TITLE, NULL, NULL, NULL, NULL, 7107eb2bd662Svikram 0, &entryNum); 7108ae115bc7Smrj 7109ae115bc7Smrj if (entryp != NULL) { 7110ae115bc7Smrj for (ptr = entryp->start; ptr && ptr != entryp->end; 7111ae115bc7Smrj ptr = ptr->next) { 7112ae115bc7Smrj if (strncmp(ptr->cmd, menu_cmds[KERNEL_CMD], 7113ae115bc7Smrj sizeof (menu_cmds[KERNEL_CMD]) - 1) == 0) { 7114ae115bc7Smrj kernelp = ptr; 7115ae115bc7Smrj break; 7116ae115bc7Smrj } 7117ae115bc7Smrj } 7118ae115bc7Smrj if (kernelp == NULL) { 7119ae115bc7Smrj bam_error(NO_KERNEL, entryNum); 7120ae115bc7Smrj return (BAM_ERROR); 7121ae115bc7Smrj } 7122ae115bc7Smrj 7123ae115bc7Smrj old_kernel_len = strcspn(kernelp->arg, " \t"); 7124ae115bc7Smrj space = old_args = kernelp->arg + old_kernel_len; 7125ae115bc7Smrj while ((*old_args == ' ') || (*old_args == '\t')) 7126ae115bc7Smrj old_args++; 7127ae115bc7Smrj } 7128ae115bc7Smrj 7129ae115bc7Smrj if (path == NULL) { 7130eb2bd662Svikram if (entryp == NULL) { 7131eb2bd662Svikram BAM_DPRINTF((D_GET_SET_KERNEL_NO_RC, fcn)); 7132eb2bd662Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 7133ae115bc7Smrj return (BAM_SUCCESS); 7134eb2bd662Svikram } 7135eb2bd662Svikram assert(kernelp); 7136ae115bc7Smrj if (optnum == ARGS_CMD) { 7137eb2bd662Svikram if (old_args[0] != '\0') { 7138ae115bc7Smrj (void) strlcpy(buf, old_args, bufsize); 7139eb2bd662Svikram BAM_DPRINTF((D_GET_SET_KERNEL_ARGS, fcn, buf)); 7140eb2bd662Svikram } 7141ae115bc7Smrj } else { 7142ae115bc7Smrj /* 7143ae115bc7Smrj * We need to print the kernel, so we just turn the 7144ae115bc7Smrj * first space into a '\0' and print the beginning. 7145ae115bc7Smrj * We don't print anything if it's the default kernel. 7146ae115bc7Smrj */ 7147ae115bc7Smrj old_space = *space; 7148ae115bc7Smrj *space = '\0'; 7149eb2bd662Svikram if (strcmp(kernelp->arg, DIRECT_BOOT_KERNEL) != 0) { 7150ae115bc7Smrj (void) strlcpy(buf, kernelp->arg, bufsize); 7151eb2bd662Svikram BAM_DPRINTF((D_GET_SET_KERNEL_KERN, fcn, buf)); 7152eb2bd662Svikram } 7153ae115bc7Smrj *space = old_space; 7154ae115bc7Smrj } 7155eb2bd662Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 7156ae115bc7Smrj return (BAM_SUCCESS); 7157ae115bc7Smrj } 7158ae115bc7Smrj 7159ae115bc7Smrj /* 7160ae115bc7Smrj * First, check if we're resetting an entry to the default. 7161ae115bc7Smrj */ 7162ae115bc7Smrj if ((path[0] == '\0') || 7163ae115bc7Smrj ((optnum == KERNEL_CMD) && 7164ae115bc7Smrj (strcmp(path, DIRECT_BOOT_KERNEL) == 0))) { 7165ae115bc7Smrj if ((entryp == NULL) || (kernelp == NULL)) { 7166ae115bc7Smrj /* No previous entry, it's already the default */ 7167eb2bd662Svikram BAM_DPRINTF((D_GET_SET_KERNEL_ALREADY, fcn)); 7168ae115bc7Smrj return (BAM_SUCCESS); 7169ae115bc7Smrj } 7170ae115bc7Smrj 7171ae115bc7Smrj /* 7172ae115bc7Smrj * Check if we can delete the entry. If we're resetting the 7173ae115bc7Smrj * kernel command, and the args is already empty, or if we're 7174ae115bc7Smrj * resetting the args command, and the kernel is already the 7175ae115bc7Smrj * default, we can restore the old default and delete the entry. 7176ae115bc7Smrj */ 7177ae115bc7Smrj if (((optnum == KERNEL_CMD) && 7178ae115bc7Smrj ((old_args == NULL) || (old_args[0] == '\0'))) || 7179ae115bc7Smrj ((optnum == ARGS_CMD) && 7180ae115bc7Smrj (strncmp(kernelp->arg, DIRECT_BOOT_KERNEL, 7181ae115bc7Smrj sizeof (DIRECT_BOOT_KERNEL) - 1) == 0))) { 7182ae115bc7Smrj kernelp = NULL; 7183ae115bc7Smrj (void) do_delete(mp, entryNum); 7184ae115bc7Smrj restore_default_entry(mp, BAM_OLD_RC_DEF, 7185ae115bc7Smrj mp->old_rc_default); 7186ae115bc7Smrj mp->old_rc_default = NULL; 7187ae115bc7Smrj rv = BAM_WRITE; 7188eb2bd662Svikram BAM_DPRINTF((D_GET_SET_KERNEL_RESTORE_DEFAULT, fcn)); 7189ae115bc7Smrj goto done; 7190ae115bc7Smrj } 7191ae115bc7Smrj 7192ae115bc7Smrj if (optnum == KERNEL_CMD) { 7193ae115bc7Smrj /* 7194ae115bc7Smrj * At this point, we've already checked that old_args 7195ae115bc7Smrj * and entryp are valid pointers. The "+ 2" is for 7196ae115bc7Smrj * a space a the string termination character. 7197ae115bc7Smrj */ 7198ae115bc7Smrj new_str_len = (sizeof (DIRECT_BOOT_KERNEL) - 1) + 7199ae115bc7Smrj strlen(old_args) + 2; 7200ae115bc7Smrj new_arg = s_calloc(1, new_str_len); 7201ae115bc7Smrj (void) snprintf(new_arg, new_str_len, "%s %s", 7202ae115bc7Smrj DIRECT_BOOT_KERNEL, old_args); 7203ae115bc7Smrj free(kernelp->arg); 7204ae115bc7Smrj kernelp->arg = new_arg; 7205ae115bc7Smrj 7206ae115bc7Smrj /* 7207ae115bc7Smrj * We have changed the kernel line, so we may need 7208ae115bc7Smrj * to update the archive line as well. 7209ae115bc7Smrj */ 7210ae115bc7Smrj set_archive_line(entryp, kernelp); 7211eb2bd662Svikram BAM_DPRINTF((D_GET_SET_KERNEL_RESET_KERNEL_SET_ARG, 7212eb2bd662Svikram fcn, kernelp->arg)); 7213ae115bc7Smrj } else { 7214ae115bc7Smrj /* 7215ae115bc7Smrj * We're resetting the boot args to nothing, so 7216ae115bc7Smrj * we only need to copy the kernel. We've already 7217ae115bc7Smrj * checked that the kernel is not the default. 7218ae115bc7Smrj */ 7219ae115bc7Smrj new_arg = s_calloc(1, old_kernel_len + 1); 7220ae115bc7Smrj (void) snprintf(new_arg, old_kernel_len + 1, "%s", 7221ae115bc7Smrj kernelp->arg); 7222ae115bc7Smrj free(kernelp->arg); 7223ae115bc7Smrj kernelp->arg = new_arg; 7224eb2bd662Svikram BAM_DPRINTF((D_GET_SET_KERNEL_RESET_ARG_SET_KERNEL, 7225eb2bd662Svikram fcn, kernelp->arg)); 7226ae115bc7Smrj } 7227ae115bc7Smrj rv = BAM_WRITE; 7228ae115bc7Smrj goto done; 7229ae115bc7Smrj } 7230ae115bc7Smrj 7231ae115bc7Smrj /* 7232ae115bc7Smrj * Expand the kernel file to a full path, if necessary 7233ae115bc7Smrj */ 7234ae115bc7Smrj if ((optnum == KERNEL_CMD) && (path[0] != '/')) { 7235ae115bc7Smrj new_path = expand_path(path); 7236ae115bc7Smrj if (new_path == NULL) { 7237455710d3Srscott bam_error(UNKNOWN_KERNEL, path); 7238eb2bd662Svikram BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 7239ae115bc7Smrj return (BAM_ERROR); 7240ae115bc7Smrj } 7241ae115bc7Smrj free_new_path = 1; 7242ae115bc7Smrj } else { 7243ae115bc7Smrj new_path = path; 7244ae115bc7Smrj free_new_path = 0; 7245ae115bc7Smrj } 7246ae115bc7Smrj 7247ae115bc7Smrj /* 7248ae115bc7Smrj * At this point, we know we're setting a new value. First, take care 7249ae115bc7Smrj * of the case where there was no previous entry. 7250ae115bc7Smrj */ 7251ae115bc7Smrj if (entryp == NULL) { 7252eb2bd662Svikram 7253ae115bc7Smrj /* Similar to code in update_temp */ 7254eb2bd662Svikram fstype = get_fstype("/"); 7255eb2bd662Svikram INJECT_ERROR1("GET_SET_KERNEL_FSTYPE", fstype = NULL); 7256eb2bd662Svikram if (fstype == NULL) { 7257eb2bd662Svikram bam_error(BOOTENV_FSTYPE_FAILED); 7258ae115bc7Smrj rv = BAM_ERROR; 7259ae115bc7Smrj goto done; 7260ae115bc7Smrj } 7261eb2bd662Svikram 7262eb2bd662Svikram osdev = get_special("/"); 7263eb2bd662Svikram INJECT_ERROR1("GET_SET_KERNEL_SPECIAL", osdev = NULL); 7264eb2bd662Svikram if (osdev == NULL) { 7265eb2bd662Svikram free(fstype); 7266eb2bd662Svikram bam_error(BOOTENV_SPECIAL_FAILED); 7267eb2bd662Svikram rv = BAM_ERROR; 7268eb2bd662Svikram goto done; 7269eb2bd662Svikram } 7270eb2bd662Svikram 7271eb2bd662Svikram sign = find_existing_sign("/", osdev, fstype); 7272eb2bd662Svikram INJECT_ERROR1("GET_SET_KERNEL_SIGN", sign = NULL); 7273eb2bd662Svikram if (sign == NULL) { 7274eb2bd662Svikram free(fstype); 7275eb2bd662Svikram free(osdev); 7276eb2bd662Svikram bam_error(BOOTENV_SIGN_FAILED); 7277eb2bd662Svikram rv = BAM_ERROR; 7278eb2bd662Svikram goto done; 7279eb2bd662Svikram } 7280eb2bd662Svikram 7281eb2bd662Svikram free(fstype); 7282eb2bd662Svikram free(osdev); 7283eb2bd662Svikram (void) strlcpy(signbuf, sign, sizeof (signbuf)); 7284eb2bd662Svikram free(sign); 7285eb2bd662Svikram assert(strchr(signbuf, '(') == NULL && 7286eb2bd662Svikram strchr(signbuf, ',') == NULL && 7287eb2bd662Svikram strchr(signbuf, ')') == NULL); 7288eb2bd662Svikram 7289ae115bc7Smrj if (optnum == KERNEL_CMD) { 7290eb2bd662Svikram BAM_DPRINTF((D_GET_SET_KERNEL_NEW_KERN, fcn, new_path)); 7291ae115bc7Smrj entryNum = add_boot_entry(mp, BOOTENV_RC_TITLE, 7292eb2bd662Svikram signbuf, new_path, NULL, NULL); 7293ae115bc7Smrj } else { 7294ae115bc7Smrj new_str_len = strlen(DIRECT_BOOT_KERNEL) + 7295ae115bc7Smrj strlen(path) + 8; 7296ae115bc7Smrj new_arg = s_calloc(1, new_str_len); 7297ae115bc7Smrj 7298ae115bc7Smrj (void) snprintf(new_arg, new_str_len, "%s %s", 7299ae115bc7Smrj DIRECT_BOOT_KERNEL, path); 7300eb2bd662Svikram BAM_DPRINTF((D_GET_SET_KERNEL_NEW_ARG, fcn, new_arg)); 7301ae115bc7Smrj entryNum = add_boot_entry(mp, BOOTENV_RC_TITLE, 7302eb2bd662Svikram signbuf, new_arg, NULL, DIRECT_BOOT_ARCHIVE); 7303eb2bd662Svikram free(new_arg); 7304eb2bd662Svikram } 7305eb2bd662Svikram INJECT_ERROR1("GET_SET_KERNEL_ADD_BOOT_ENTRY", 7306eb2bd662Svikram entryNum = BAM_ERROR); 7307eb2bd662Svikram if (entryNum == BAM_ERROR) { 7308eb2bd662Svikram bam_error(GET_SET_KERNEL_ADD_BOOT_ENTRY, 7309eb2bd662Svikram BOOTENV_RC_TITLE); 7310eb2bd662Svikram rv = BAM_ERROR; 7311eb2bd662Svikram goto done; 7312ae115bc7Smrj } 7313ae115bc7Smrj save_default_entry(mp, BAM_OLD_RC_DEF); 7314eb2bd662Svikram ret = set_global(mp, menu_cmds[DEFAULT_CMD], entryNum); 7315eb2bd662Svikram INJECT_ERROR1("GET_SET_KERNEL_SET_GLOBAL", ret = BAM_ERROR); 7316eb2bd662Svikram if (ret == BAM_ERROR) { 7317eb2bd662Svikram bam_error(GET_SET_KERNEL_SET_GLOBAL, entryNum); 7318eb2bd662Svikram } 7319ae115bc7Smrj rv = BAM_WRITE; 7320ae115bc7Smrj goto done; 7321ae115bc7Smrj } 7322ae115bc7Smrj 7323ae115bc7Smrj /* 7324ae115bc7Smrj * There was already an bootenv entry which we need to edit. 7325ae115bc7Smrj */ 7326ae115bc7Smrj if (optnum == KERNEL_CMD) { 7327ae115bc7Smrj new_str_len = strlen(new_path) + strlen(old_args) + 2; 7328ae115bc7Smrj new_arg = s_calloc(1, new_str_len); 7329ae115bc7Smrj (void) snprintf(new_arg, new_str_len, "%s %s", new_path, 7330ae115bc7Smrj old_args); 7331ae115bc7Smrj free(kernelp->arg); 7332ae115bc7Smrj kernelp->arg = new_arg; 7333ae115bc7Smrj 7334ae115bc7Smrj /* 7335ae115bc7Smrj * If we have changed the kernel line, we may need to update 7336ae115bc7Smrj * the archive line as well. 7337ae115bc7Smrj */ 7338ae115bc7Smrj set_archive_line(entryp, kernelp); 7339eb2bd662Svikram BAM_DPRINTF((D_GET_SET_KERNEL_REPLACED_KERNEL_SAME_ARG, fcn, 7340eb2bd662Svikram kernelp->arg)); 7341ae115bc7Smrj } else { 7342ae115bc7Smrj new_str_len = old_kernel_len + strlen(path) + 8; 7343ae115bc7Smrj new_arg = s_calloc(1, new_str_len); 7344ae115bc7Smrj (void) strncpy(new_arg, kernelp->arg, old_kernel_len); 7345ae115bc7Smrj (void) strlcat(new_arg, " ", new_str_len); 7346ae115bc7Smrj (void) strlcat(new_arg, path, new_str_len); 7347ae115bc7Smrj free(kernelp->arg); 7348ae115bc7Smrj kernelp->arg = new_arg; 7349eb2bd662Svikram BAM_DPRINTF((D_GET_SET_KERNEL_SAME_KERNEL_REPLACED_ARG, fcn, 7350eb2bd662Svikram kernelp->arg)); 7351ae115bc7Smrj } 7352ae115bc7Smrj rv = BAM_WRITE; 7353ae115bc7Smrj 7354ae115bc7Smrj done: 7355ae115bc7Smrj if ((rv == BAM_WRITE) && kernelp) 7356ae115bc7Smrj update_line(kernelp); 7357ae115bc7Smrj if (free_new_path) 7358ae115bc7Smrj free(new_path); 7359eb2bd662Svikram if (rv == BAM_WRITE) { 7360eb2bd662Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 7361eb2bd662Svikram } else { 7362eb2bd662Svikram BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 7363eb2bd662Svikram } 7364ae115bc7Smrj return (rv); 7365ae115bc7Smrj } 7366ae115bc7Smrj 7367eb2bd662Svikram static error_t 7368eb2bd662Svikram get_kernel(menu_t *mp, menu_cmd_t optnum, char *buf, size_t bufsize) 7369eb2bd662Svikram { 7370eb2bd662Svikram const char *fcn = "get_kernel()"; 7371eb2bd662Svikram BAM_DPRINTF((D_FUNC_ENTRY1, fcn, menu_cmds[optnum])); 7372eb2bd662Svikram return (get_set_kernel(mp, optnum, NULL, buf, bufsize)); 7373eb2bd662Svikram } 7374eb2bd662Svikram 7375eb2bd662Svikram static error_t 7376eb2bd662Svikram set_kernel(menu_t *mp, menu_cmd_t optnum, char *path, char *buf, size_t bufsize) 7377eb2bd662Svikram { 7378eb2bd662Svikram const char *fcn = "set_kernel()"; 7379eb2bd662Svikram assert(path != NULL); 7380eb2bd662Svikram BAM_DPRINTF((D_FUNC_ENTRY2, fcn, menu_cmds[optnum], path)); 7381eb2bd662Svikram return (get_set_kernel(mp, optnum, path, buf, bufsize)); 7382eb2bd662Svikram } 7383eb2bd662Svikram 73847c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 73857c478bd9Sstevel@tonic-gate static error_t 7386eb2bd662Svikram set_option(menu_t *mp, char *dummy, char *opt) 73877c478bd9Sstevel@tonic-gate { 7388eb2bd662Svikram int optnum; 7389eb2bd662Svikram int optval; 73907c478bd9Sstevel@tonic-gate char *val; 7391ae115bc7Smrj char buf[BUFSIZ] = ""; 7392ae115bc7Smrj error_t rv; 7393eb2bd662Svikram const char *fcn = "set_option()"; 73947c478bd9Sstevel@tonic-gate 73957c478bd9Sstevel@tonic-gate assert(mp); 73967c478bd9Sstevel@tonic-gate assert(opt); 7397eb2bd662Svikram assert(dummy == NULL); 7398eb2bd662Svikram 7399eb2bd662Svikram /* opt is set from bam_argv[0] and is always non-NULL */ 7400eb2bd662Svikram BAM_DPRINTF((D_FUNC_ENTRY1, fcn, opt)); 74017c478bd9Sstevel@tonic-gate 74027c478bd9Sstevel@tonic-gate val = strchr(opt, '='); 7403ae115bc7Smrj if (val != NULL) { 7404ae115bc7Smrj *val = '\0'; 74057c478bd9Sstevel@tonic-gate } 74067c478bd9Sstevel@tonic-gate 74077c478bd9Sstevel@tonic-gate if (strcmp(opt, "default") == 0) { 74087c478bd9Sstevel@tonic-gate optnum = DEFAULT_CMD; 74097c478bd9Sstevel@tonic-gate } else if (strcmp(opt, "timeout") == 0) { 74107c478bd9Sstevel@tonic-gate optnum = TIMEOUT_CMD; 7411ae115bc7Smrj } else if (strcmp(opt, menu_cmds[KERNEL_CMD]) == 0) { 7412ae115bc7Smrj optnum = KERNEL_CMD; 7413ae115bc7Smrj } else if (strcmp(opt, menu_cmds[ARGS_CMD]) == 0) { 7414ae115bc7Smrj optnum = ARGS_CMD; 74157c478bd9Sstevel@tonic-gate } else { 7416eb2bd662Svikram bam_error(INVALID_OPTION, opt); 74177c478bd9Sstevel@tonic-gate return (BAM_ERROR); 74187c478bd9Sstevel@tonic-gate } 74197c478bd9Sstevel@tonic-gate 7420ae115bc7Smrj /* 7421ae115bc7Smrj * kernel and args are allowed without "=new_value" strings. All 7422ae115bc7Smrj * others cause errors 7423ae115bc7Smrj */ 7424ae115bc7Smrj if ((val == NULL) && (optnum != KERNEL_CMD) && (optnum != ARGS_CMD)) { 7425eb2bd662Svikram bam_error(NO_OPTION_ARG, opt); 7426ae115bc7Smrj return (BAM_ERROR); 7427ae115bc7Smrj } else if (val != NULL) { 74287c478bd9Sstevel@tonic-gate *val = '='; 7429ae115bc7Smrj } 7430ae115bc7Smrj 7431ae115bc7Smrj if ((optnum == KERNEL_CMD) || (optnum == ARGS_CMD)) { 7432eb2bd662Svikram BAM_DPRINTF((D_SET_OPTION, fcn, menu_cmds[optnum], 7433eb2bd662Svikram val ? val + 1 : "NULL")); 7434eb2bd662Svikram 7435eb2bd662Svikram if (val) 7436eb2bd662Svikram rv = set_kernel(mp, optnum, val + 1, buf, sizeof (buf)); 7437eb2bd662Svikram else 7438eb2bd662Svikram rv = get_kernel(mp, optnum, buf, sizeof (buf)); 7439ae115bc7Smrj if ((rv == BAM_SUCCESS) && (buf[0] != '\0')) 7440ae115bc7Smrj (void) printf("%s\n", buf); 7441ae115bc7Smrj } else { 7442ae115bc7Smrj optval = s_strtol(val + 1); 7443eb2bd662Svikram BAM_DPRINTF((D_SET_OPTION, fcn, menu_cmds[optnum], val + 1)); 7444eb2bd662Svikram rv = set_global(mp, menu_cmds[optnum], optval); 74457c478bd9Sstevel@tonic-gate } 7446eb2bd662Svikram 7447eb2bd662Svikram if (rv == BAM_WRITE || rv == BAM_SUCCESS) { 7448eb2bd662Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 7449eb2bd662Svikram } else { 7450eb2bd662Svikram BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 7451eb2bd662Svikram } 7452eb2bd662Svikram 7453eb2bd662Svikram return (rv); 7454ae115bc7Smrj } 74557c478bd9Sstevel@tonic-gate 74567c478bd9Sstevel@tonic-gate /* 74577c478bd9Sstevel@tonic-gate * The quiet argument suppresses messages. This is used 74587c478bd9Sstevel@tonic-gate * when invoked in the context of other commands (e.g. list_entry) 74597c478bd9Sstevel@tonic-gate */ 74607c478bd9Sstevel@tonic-gate static error_t 74617c478bd9Sstevel@tonic-gate read_globals(menu_t *mp, char *menu_path, char *globalcmd, int quiet) 74627c478bd9Sstevel@tonic-gate { 74637c478bd9Sstevel@tonic-gate line_t *lp; 74647c478bd9Sstevel@tonic-gate char *arg; 74657c478bd9Sstevel@tonic-gate int done, ret = BAM_SUCCESS; 74667c478bd9Sstevel@tonic-gate 74677c478bd9Sstevel@tonic-gate assert(mp); 74687c478bd9Sstevel@tonic-gate assert(menu_path); 74697c478bd9Sstevel@tonic-gate assert(globalcmd); 74707c478bd9Sstevel@tonic-gate 74717c478bd9Sstevel@tonic-gate if (mp->start == NULL) { 74727c478bd9Sstevel@tonic-gate if (!quiet) 74737c478bd9Sstevel@tonic-gate bam_error(NO_MENU, menu_path); 74747c478bd9Sstevel@tonic-gate return (BAM_ERROR); 74757c478bd9Sstevel@tonic-gate } 74767c478bd9Sstevel@tonic-gate 74777c478bd9Sstevel@tonic-gate done = 0; 74787c478bd9Sstevel@tonic-gate for (lp = mp->start; lp; lp = lp->next) { 74797c478bd9Sstevel@tonic-gate if (lp->flags != BAM_GLOBAL) 74807c478bd9Sstevel@tonic-gate continue; 74817c478bd9Sstevel@tonic-gate 74827c478bd9Sstevel@tonic-gate if (lp->cmd == NULL) { 74837c478bd9Sstevel@tonic-gate if (!quiet) 74847c478bd9Sstevel@tonic-gate bam_error(NO_CMD, lp->lineNum); 74857c478bd9Sstevel@tonic-gate continue; 74867c478bd9Sstevel@tonic-gate } 74877c478bd9Sstevel@tonic-gate 74887c478bd9Sstevel@tonic-gate if (strcmp(globalcmd, lp->cmd) != 0) 74897c478bd9Sstevel@tonic-gate continue; 74907c478bd9Sstevel@tonic-gate 74917c478bd9Sstevel@tonic-gate /* Found global. Check for duplicates */ 74927c478bd9Sstevel@tonic-gate if (done && !quiet) { 74937c478bd9Sstevel@tonic-gate bam_error(DUP_CMD, globalcmd, lp->lineNum, bam_root); 74947c478bd9Sstevel@tonic-gate ret = BAM_ERROR; 74957c478bd9Sstevel@tonic-gate } 74967c478bd9Sstevel@tonic-gate 74977c478bd9Sstevel@tonic-gate arg = lp->arg ? lp->arg : ""; 74987c478bd9Sstevel@tonic-gate bam_print(GLOBAL_CMD, globalcmd, arg); 74997c478bd9Sstevel@tonic-gate done = 1; 75007c478bd9Sstevel@tonic-gate } 75017c478bd9Sstevel@tonic-gate 75027c478bd9Sstevel@tonic-gate if (!done && bam_verbose) 75037c478bd9Sstevel@tonic-gate bam_print(NO_ENTRY, globalcmd); 75047c478bd9Sstevel@tonic-gate 75057c478bd9Sstevel@tonic-gate return (ret); 75067c478bd9Sstevel@tonic-gate } 75077c478bd9Sstevel@tonic-gate 75087c478bd9Sstevel@tonic-gate static error_t 75097c478bd9Sstevel@tonic-gate menu_write(char *root, menu_t *mp) 75107c478bd9Sstevel@tonic-gate { 7511eb2bd662Svikram const char *fcn = "menu_write()"; 7512eb2bd662Svikram 7513eb2bd662Svikram BAM_DPRINTF((D_MENU_WRITE_ENTER, fcn, root)); 75147c478bd9Sstevel@tonic-gate return (list2file(root, MENU_TMP, GRUB_MENU, mp->start)); 75157c478bd9Sstevel@tonic-gate } 75167c478bd9Sstevel@tonic-gate 7517eb2bd662Svikram void 75187c478bd9Sstevel@tonic-gate line_free(line_t *lp) 75197c478bd9Sstevel@tonic-gate { 75207c478bd9Sstevel@tonic-gate if (lp == NULL) 75217c478bd9Sstevel@tonic-gate return; 75227c478bd9Sstevel@tonic-gate 75237c478bd9Sstevel@tonic-gate if (lp->cmd) 75247c478bd9Sstevel@tonic-gate free(lp->cmd); 75257c478bd9Sstevel@tonic-gate if (lp->sep) 75267c478bd9Sstevel@tonic-gate free(lp->sep); 75277c478bd9Sstevel@tonic-gate if (lp->arg) 75287c478bd9Sstevel@tonic-gate free(lp->arg); 75297c478bd9Sstevel@tonic-gate if (lp->line) 75307c478bd9Sstevel@tonic-gate free(lp->line); 75317c478bd9Sstevel@tonic-gate free(lp); 75327c478bd9Sstevel@tonic-gate } 75337c478bd9Sstevel@tonic-gate 75347c478bd9Sstevel@tonic-gate static void 75357c478bd9Sstevel@tonic-gate linelist_free(line_t *start) 75367c478bd9Sstevel@tonic-gate { 75377c478bd9Sstevel@tonic-gate line_t *lp; 75387c478bd9Sstevel@tonic-gate 75397c478bd9Sstevel@tonic-gate while (start) { 75407c478bd9Sstevel@tonic-gate lp = start; 75417c478bd9Sstevel@tonic-gate start = start->next; 75427c478bd9Sstevel@tonic-gate line_free(lp); 75437c478bd9Sstevel@tonic-gate } 75447c478bd9Sstevel@tonic-gate } 75457c478bd9Sstevel@tonic-gate 75467c478bd9Sstevel@tonic-gate static void 75477c478bd9Sstevel@tonic-gate filelist_free(filelist_t *flistp) 75487c478bd9Sstevel@tonic-gate { 75497c478bd9Sstevel@tonic-gate linelist_free(flistp->head); 75507c478bd9Sstevel@tonic-gate flistp->head = NULL; 75517c478bd9Sstevel@tonic-gate flistp->tail = NULL; 75527c478bd9Sstevel@tonic-gate } 75537c478bd9Sstevel@tonic-gate 75547c478bd9Sstevel@tonic-gate static void 75557c478bd9Sstevel@tonic-gate menu_free(menu_t *mp) 75567c478bd9Sstevel@tonic-gate { 75578c1b6884Sszhou entry_t *ent, *tmp; 75587c478bd9Sstevel@tonic-gate assert(mp); 75597c478bd9Sstevel@tonic-gate 75607c478bd9Sstevel@tonic-gate if (mp->start) 75617c478bd9Sstevel@tonic-gate linelist_free(mp->start); 75628c1b6884Sszhou ent = mp->entries; 75638c1b6884Sszhou while (ent) { 75648c1b6884Sszhou tmp = ent; 75658c1b6884Sszhou ent = tmp->next; 75668c1b6884Sszhou free(tmp); 75678c1b6884Sszhou } 75687c478bd9Sstevel@tonic-gate 75698c1b6884Sszhou free(mp); 75707c478bd9Sstevel@tonic-gate } 75717c478bd9Sstevel@tonic-gate 75727c478bd9Sstevel@tonic-gate /* 75737c478bd9Sstevel@tonic-gate * Utility routines 75747c478bd9Sstevel@tonic-gate */ 75757c478bd9Sstevel@tonic-gate 75767c478bd9Sstevel@tonic-gate 75777c478bd9Sstevel@tonic-gate /* 75787c478bd9Sstevel@tonic-gate * Returns 0 on success 75797c478bd9Sstevel@tonic-gate * Any other value indicates an error 75807c478bd9Sstevel@tonic-gate */ 75817c478bd9Sstevel@tonic-gate static int 7582986fd29aSsetje exec_cmd(char *cmdline, filelist_t *flistp) 75837c478bd9Sstevel@tonic-gate { 75847c478bd9Sstevel@tonic-gate char buf[BUFSIZ]; 75857c478bd9Sstevel@tonic-gate int ret; 75867c478bd9Sstevel@tonic-gate FILE *ptr; 75877c478bd9Sstevel@tonic-gate sigset_t set; 75887c478bd9Sstevel@tonic-gate void (*disp)(int); 75897c478bd9Sstevel@tonic-gate 75907c478bd9Sstevel@tonic-gate /* 75917c478bd9Sstevel@tonic-gate * For security 75927c478bd9Sstevel@tonic-gate * - only absolute paths are allowed 75937c478bd9Sstevel@tonic-gate * - set IFS to space and tab 75947c478bd9Sstevel@tonic-gate */ 75957c478bd9Sstevel@tonic-gate if (*cmdline != '/') { 75967c478bd9Sstevel@tonic-gate bam_error(ABS_PATH_REQ, cmdline); 75977c478bd9Sstevel@tonic-gate return (-1); 75987c478bd9Sstevel@tonic-gate } 75997c478bd9Sstevel@tonic-gate (void) putenv("IFS= \t"); 76007c478bd9Sstevel@tonic-gate 76017c478bd9Sstevel@tonic-gate /* 76027c478bd9Sstevel@tonic-gate * We may have been exec'ed with SIGCHLD blocked 76037c478bd9Sstevel@tonic-gate * unblock it here 76047c478bd9Sstevel@tonic-gate */ 76057c478bd9Sstevel@tonic-gate (void) sigemptyset(&set); 76067c478bd9Sstevel@tonic-gate (void) sigaddset(&set, SIGCHLD); 76077c478bd9Sstevel@tonic-gate if (sigprocmask(SIG_UNBLOCK, &set, NULL) != 0) { 76087c478bd9Sstevel@tonic-gate bam_error(CANT_UNBLOCK_SIGCHLD, strerror(errno)); 76097c478bd9Sstevel@tonic-gate return (-1); 76107c478bd9Sstevel@tonic-gate } 76117c478bd9Sstevel@tonic-gate 76127c478bd9Sstevel@tonic-gate /* 76137c478bd9Sstevel@tonic-gate * Set SIGCHLD disposition to SIG_DFL for popen/pclose 76147c478bd9Sstevel@tonic-gate */ 76157c478bd9Sstevel@tonic-gate disp = sigset(SIGCHLD, SIG_DFL); 76167c478bd9Sstevel@tonic-gate if (disp == SIG_ERR) { 76177c478bd9Sstevel@tonic-gate bam_error(FAILED_SIG, strerror(errno)); 76187c478bd9Sstevel@tonic-gate return (-1); 76197c478bd9Sstevel@tonic-gate } 76207c478bd9Sstevel@tonic-gate if (disp == SIG_HOLD) { 76217c478bd9Sstevel@tonic-gate bam_error(BLOCKED_SIG, cmdline); 76227c478bd9Sstevel@tonic-gate return (-1); 76237c478bd9Sstevel@tonic-gate } 76247c478bd9Sstevel@tonic-gate 76257c478bd9Sstevel@tonic-gate ptr = popen(cmdline, "r"); 76267c478bd9Sstevel@tonic-gate if (ptr == NULL) { 76277c478bd9Sstevel@tonic-gate bam_error(POPEN_FAIL, cmdline, strerror(errno)); 76287c478bd9Sstevel@tonic-gate return (-1); 76297c478bd9Sstevel@tonic-gate } 76307c478bd9Sstevel@tonic-gate 76317c478bd9Sstevel@tonic-gate /* 76327c478bd9Sstevel@tonic-gate * If we simply do a pclose() following a popen(), pclose() 76337c478bd9Sstevel@tonic-gate * will close the reader end of the pipe immediately even 76347c478bd9Sstevel@tonic-gate * if the child process has not started/exited. pclose() 76357c478bd9Sstevel@tonic-gate * does wait for cmd to terminate before returning though. 76367c478bd9Sstevel@tonic-gate * When the executed command writes its output to the pipe 76377c478bd9Sstevel@tonic-gate * there is no reader process and the command dies with 76387c478bd9Sstevel@tonic-gate * SIGPIPE. To avoid this we read repeatedly until read 76397c478bd9Sstevel@tonic-gate * terminates with EOF. This indicates that the command 76407c478bd9Sstevel@tonic-gate * (writer) has closed the pipe and we can safely do a 76417c478bd9Sstevel@tonic-gate * pclose(). 76427c478bd9Sstevel@tonic-gate * 76437c478bd9Sstevel@tonic-gate * Since pclose() does wait for the command to exit, 76447c478bd9Sstevel@tonic-gate * we can safely reap the exit status of the command 76457c478bd9Sstevel@tonic-gate * from the value returned by pclose() 76467c478bd9Sstevel@tonic-gate */ 7647986fd29aSsetje while (s_fgets(buf, sizeof (buf), ptr) != NULL) { 7648986fd29aSsetje if (flistp == NULL) { 7649986fd29aSsetje /* s_fgets strips newlines, so insert them at the end */ 7650986fd29aSsetje bam_print(PRINT, buf); 7651986fd29aSsetje } else { 7652986fd29aSsetje append_to_flist(flistp, buf); 76537c478bd9Sstevel@tonic-gate } 76547c478bd9Sstevel@tonic-gate } 76557c478bd9Sstevel@tonic-gate 76567c478bd9Sstevel@tonic-gate ret = pclose(ptr); 76577c478bd9Sstevel@tonic-gate if (ret == -1) { 76587c478bd9Sstevel@tonic-gate bam_error(PCLOSE_FAIL, cmdline, strerror(errno)); 76597c478bd9Sstevel@tonic-gate return (-1); 76607c478bd9Sstevel@tonic-gate } 76617c478bd9Sstevel@tonic-gate 76627c478bd9Sstevel@tonic-gate if (WIFEXITED(ret)) { 76637c478bd9Sstevel@tonic-gate return (WEXITSTATUS(ret)); 76647c478bd9Sstevel@tonic-gate } else { 76657c478bd9Sstevel@tonic-gate bam_error(EXEC_FAIL, cmdline, ret); 76667c478bd9Sstevel@tonic-gate return (-1); 76677c478bd9Sstevel@tonic-gate } 76687c478bd9Sstevel@tonic-gate } 76697c478bd9Sstevel@tonic-gate 76707c478bd9Sstevel@tonic-gate /* 76717c478bd9Sstevel@tonic-gate * Since this function returns -1 on error 76727c478bd9Sstevel@tonic-gate * it cannot be used to convert -1. However, 76737c478bd9Sstevel@tonic-gate * that is sufficient for what we need. 76747c478bd9Sstevel@tonic-gate */ 76757c478bd9Sstevel@tonic-gate static long 76767c478bd9Sstevel@tonic-gate s_strtol(char *str) 76777c478bd9Sstevel@tonic-gate { 76787c478bd9Sstevel@tonic-gate long l; 76797c478bd9Sstevel@tonic-gate char *res = NULL; 76807c478bd9Sstevel@tonic-gate 76817c478bd9Sstevel@tonic-gate if (str == NULL) { 76827c478bd9Sstevel@tonic-gate return (-1); 76837c478bd9Sstevel@tonic-gate } 76847c478bd9Sstevel@tonic-gate 76857c478bd9Sstevel@tonic-gate errno = 0; 76867c478bd9Sstevel@tonic-gate l = strtol(str, &res, 10); 76877c478bd9Sstevel@tonic-gate if (errno || *res != '\0') { 76887c478bd9Sstevel@tonic-gate return (-1); 76897c478bd9Sstevel@tonic-gate } 76907c478bd9Sstevel@tonic-gate 76917c478bd9Sstevel@tonic-gate return (l); 76927c478bd9Sstevel@tonic-gate } 76937c478bd9Sstevel@tonic-gate 76947c478bd9Sstevel@tonic-gate /* 76957c478bd9Sstevel@tonic-gate * Wrapper around fputs, that adds a newline (since fputs doesn't) 76967c478bd9Sstevel@tonic-gate */ 76977c478bd9Sstevel@tonic-gate static int 76987c478bd9Sstevel@tonic-gate s_fputs(char *str, FILE *fp) 76997c478bd9Sstevel@tonic-gate { 77007c478bd9Sstevel@tonic-gate char linebuf[BAM_MAXLINE]; 77017c478bd9Sstevel@tonic-gate 77027c478bd9Sstevel@tonic-gate (void) snprintf(linebuf, sizeof (linebuf), "%s\n", str); 77037c478bd9Sstevel@tonic-gate return (fputs(linebuf, fp)); 77047c478bd9Sstevel@tonic-gate } 77057c478bd9Sstevel@tonic-gate 77067c478bd9Sstevel@tonic-gate /* 77077c478bd9Sstevel@tonic-gate * Wrapper around fgets, that strips newlines returned by fgets 77087c478bd9Sstevel@tonic-gate */ 7709ae115bc7Smrj char * 77107c478bd9Sstevel@tonic-gate s_fgets(char *buf, int buflen, FILE *fp) 77117c478bd9Sstevel@tonic-gate { 77127c478bd9Sstevel@tonic-gate int n; 77137c478bd9Sstevel@tonic-gate 77147c478bd9Sstevel@tonic-gate buf = fgets(buf, buflen, fp); 77157c478bd9Sstevel@tonic-gate if (buf) { 77167c478bd9Sstevel@tonic-gate n = strlen(buf); 77177c478bd9Sstevel@tonic-gate if (n == buflen - 1 && buf[n-1] != '\n') 77187c478bd9Sstevel@tonic-gate bam_error(TOO_LONG, buflen - 1, buf); 77197c478bd9Sstevel@tonic-gate buf[n-1] = (buf[n-1] == '\n') ? '\0' : buf[n-1]; 77207c478bd9Sstevel@tonic-gate } 77217c478bd9Sstevel@tonic-gate 77227c478bd9Sstevel@tonic-gate return (buf); 77237c478bd9Sstevel@tonic-gate } 77247c478bd9Sstevel@tonic-gate 7725ae115bc7Smrj void * 77267c478bd9Sstevel@tonic-gate s_calloc(size_t nelem, size_t sz) 77277c478bd9Sstevel@tonic-gate { 77287c478bd9Sstevel@tonic-gate void *ptr; 77297c478bd9Sstevel@tonic-gate 77307c478bd9Sstevel@tonic-gate ptr = calloc(nelem, sz); 77317c478bd9Sstevel@tonic-gate if (ptr == NULL) { 77327c478bd9Sstevel@tonic-gate bam_error(NO_MEM, nelem*sz); 77337c478bd9Sstevel@tonic-gate bam_exit(1); 77347c478bd9Sstevel@tonic-gate } 77357c478bd9Sstevel@tonic-gate return (ptr); 77367c478bd9Sstevel@tonic-gate } 77377c478bd9Sstevel@tonic-gate 7738ae115bc7Smrj void * 7739ae115bc7Smrj s_realloc(void *ptr, size_t sz) 7740ae115bc7Smrj { 7741ae115bc7Smrj ptr = realloc(ptr, sz); 7742ae115bc7Smrj if (ptr == NULL) { 7743ae115bc7Smrj bam_error(NO_MEM, sz); 7744ae115bc7Smrj bam_exit(1); 7745ae115bc7Smrj } 7746ae115bc7Smrj return (ptr); 7747ae115bc7Smrj } 7748ae115bc7Smrj 7749eb2bd662Svikram char * 77507c478bd9Sstevel@tonic-gate s_strdup(char *str) 77517c478bd9Sstevel@tonic-gate { 77527c478bd9Sstevel@tonic-gate char *ptr; 77537c478bd9Sstevel@tonic-gate 77547c478bd9Sstevel@tonic-gate if (str == NULL) 77557c478bd9Sstevel@tonic-gate return (NULL); 77567c478bd9Sstevel@tonic-gate 77577c478bd9Sstevel@tonic-gate ptr = strdup(str); 77587c478bd9Sstevel@tonic-gate if (ptr == NULL) { 77597c478bd9Sstevel@tonic-gate bam_error(NO_MEM, strlen(str) + 1); 77607c478bd9Sstevel@tonic-gate bam_exit(1); 77617c478bd9Sstevel@tonic-gate } 77627c478bd9Sstevel@tonic-gate return (ptr); 77637c478bd9Sstevel@tonic-gate } 77647c478bd9Sstevel@tonic-gate 77657c478bd9Sstevel@tonic-gate /* 77667c478bd9Sstevel@tonic-gate * Returns 1 if amd64 (or sparc, for syncing x86 diskless clients) 77677c478bd9Sstevel@tonic-gate * Returns 0 otherwise 77687c478bd9Sstevel@tonic-gate */ 77697c478bd9Sstevel@tonic-gate static int 77707c478bd9Sstevel@tonic-gate is_amd64(void) 77717c478bd9Sstevel@tonic-gate { 77727c478bd9Sstevel@tonic-gate static int amd64 = -1; 77737c478bd9Sstevel@tonic-gate char isabuf[257]; /* from sysinfo(2) manpage */ 77747c478bd9Sstevel@tonic-gate 77757c478bd9Sstevel@tonic-gate if (amd64 != -1) 77767c478bd9Sstevel@tonic-gate return (amd64); 77777c478bd9Sstevel@tonic-gate 7778d876c67dSjg if (bam_alt_platform) { 7779d876c67dSjg if (strcmp(bam_platform, "i86pc") == 0) { 77807c478bd9Sstevel@tonic-gate amd64 = 1; /* diskless server */ 7781d876c67dSjg } 7782d876c67dSjg } else { 7783d876c67dSjg if (sysinfo(SI_ISALIST, isabuf, sizeof (isabuf)) > 0 && 7784d876c67dSjg strncmp(isabuf, "amd64 ", strlen("amd64 ")) == 0) { 7785d876c67dSjg amd64 = 1; 7786d876c67dSjg } else if (strstr(isabuf, "i386") == NULL) { 7787d876c67dSjg amd64 = 1; /* diskless server */ 7788d876c67dSjg } 7789d876c67dSjg } 7790d876c67dSjg if (amd64 == -1) 77917c478bd9Sstevel@tonic-gate amd64 = 0; 77927c478bd9Sstevel@tonic-gate 77937c478bd9Sstevel@tonic-gate return (amd64); 77947c478bd9Sstevel@tonic-gate } 77957c478bd9Sstevel@tonic-gate 779679755401Ssetje static char * 779779755401Ssetje get_machine(void) 7798986fd29aSsetje { 779979755401Ssetje static int cached = -1; 780079755401Ssetje static char mbuf[257]; /* from sysinfo(2) manpage */ 7801986fd29aSsetje 780279755401Ssetje if (cached == 0) 780379755401Ssetje return (mbuf); 7804d876c67dSjg 7805d876c67dSjg if (bam_alt_platform) { 780679755401Ssetje return (bam_platform); 7807d876c67dSjg } else { 780879755401Ssetje if (sysinfo(SI_MACHINE, mbuf, sizeof (mbuf)) > 0) { 780979755401Ssetje cached = 1; 7810d876c67dSjg } 7811d876c67dSjg } 781279755401Ssetje if (cached == -1) { 781379755401Ssetje mbuf[0] = '\0'; 781479755401Ssetje cached = 0; 7815986fd29aSsetje } 7816986fd29aSsetje 781779755401Ssetje return (mbuf); 7818986fd29aSsetje } 7819986fd29aSsetje 7820eb2bd662Svikram int 7821eb2bd662Svikram is_sparc(void) 7822eb2bd662Svikram { 782379755401Ssetje static int issparc = -1; 782479755401Ssetje char mbuf[257]; /* from sysinfo(2) manpage */ 782579755401Ssetje 782679755401Ssetje if (issparc != -1) 782779755401Ssetje return (issparc); 782879755401Ssetje 782979755401Ssetje if (bam_alt_platform) { 783079755401Ssetje if (strncmp(bam_platform, "sun4", 4) == 0) { 783179755401Ssetje issparc = 1; 783279755401Ssetje } 783379755401Ssetje } else { 783479755401Ssetje if (sysinfo(SI_ARCHITECTURE, mbuf, sizeof (mbuf)) > 0 && 7835d7d0f93bSjg strcmp(mbuf, "sparc") == 0) { 783679755401Ssetje issparc = 1; 783779755401Ssetje } 7838d7d0f93bSjg } 7839d7d0f93bSjg if (issparc == -1) 7840d7d0f93bSjg issparc = 0; 784179755401Ssetje 784279755401Ssetje return (issparc); 7843eb2bd662Svikram } 7844986fd29aSsetje 78457c478bd9Sstevel@tonic-gate static void 78467c478bd9Sstevel@tonic-gate append_to_flist(filelist_t *flistp, char *s) 78477c478bd9Sstevel@tonic-gate { 78487c478bd9Sstevel@tonic-gate line_t *lp; 78497c478bd9Sstevel@tonic-gate 78507c478bd9Sstevel@tonic-gate lp = s_calloc(1, sizeof (line_t)); 78517c478bd9Sstevel@tonic-gate lp->line = s_strdup(s); 78527c478bd9Sstevel@tonic-gate if (flistp->head == NULL) 78537c478bd9Sstevel@tonic-gate flistp->head = lp; 78547c478bd9Sstevel@tonic-gate else 78557c478bd9Sstevel@tonic-gate flistp->tail->next = lp; 78567c478bd9Sstevel@tonic-gate flistp->tail = lp; 78577c478bd9Sstevel@tonic-gate } 78582449e17fSsherrym 7859986fd29aSsetje #if !defined(_OPB) 78602449e17fSsherrym 78612449e17fSsherrym UCODE_VENDORS; 78622449e17fSsherrym 78632449e17fSsherrym /*ARGSUSED*/ 78642449e17fSsherrym static void 78652449e17fSsherrym ucode_install(char *root) 78662449e17fSsherrym { 78672449e17fSsherrym int i; 78682449e17fSsherrym 78692449e17fSsherrym for (i = 0; ucode_vendors[i].filestr != NULL; i++) { 78702449e17fSsherrym int cmd_len = PATH_MAX + 256; 78712449e17fSsherrym char cmd[PATH_MAX + 256]; 78722449e17fSsherrym char file[PATH_MAX]; 78732449e17fSsherrym char timestamp[PATH_MAX]; 78742449e17fSsherrym struct stat fstatus, tstatus; 78752449e17fSsherrym struct utimbuf u_times; 78762449e17fSsherrym 7877adc586deSMark Johnson (void) snprintf(file, PATH_MAX, "%s/%s/%s-ucode.%s", 7878adc586deSMark Johnson bam_root, UCODE_INSTALL_PATH, ucode_vendors[i].filestr, 7879adc586deSMark Johnson ucode_vendors[i].extstr); 78802449e17fSsherrym 78812449e17fSsherrym if (stat(file, &fstatus) != 0 || !(S_ISREG(fstatus.st_mode))) 78822449e17fSsherrym continue; 78832449e17fSsherrym 78842449e17fSsherrym (void) snprintf(timestamp, PATH_MAX, "%s.ts", file); 78852449e17fSsherrym 78862449e17fSsherrym if (stat(timestamp, &tstatus) == 0 && 78872449e17fSsherrym fstatus.st_mtime <= tstatus.st_mtime) 78882449e17fSsherrym continue; 78892449e17fSsherrym 78902449e17fSsherrym (void) snprintf(cmd, cmd_len, "/usr/sbin/ucodeadm -i -R " 78912449e17fSsherrym "%s/%s/%s %s > /dev/null 2>&1", bam_root, 78922449e17fSsherrym UCODE_INSTALL_PATH, ucode_vendors[i].vendorstr, file); 78932449e17fSsherrym if (system(cmd) != 0) 78942449e17fSsherrym return; 78952449e17fSsherrym 78962449e17fSsherrym if (creat(timestamp, S_IRUSR | S_IWUSR) == -1) 78972449e17fSsherrym return; 78982449e17fSsherrym 78992449e17fSsherrym u_times.actime = fstatus.st_atime; 79002449e17fSsherrym u_times.modtime = fstatus.st_mtime; 79012449e17fSsherrym (void) utime(timestamp, &u_times); 79022449e17fSsherrym } 79032449e17fSsherrym } 79042449e17fSsherrym #endif 7905