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> 46*f904d32dSJerry 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> 59e7cbe64fSgw #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 15998892a30Snadkarni /* 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 1707c478bd9Sstevel@tonic-gate /* 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; 233e7cbe64fSgw 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); 262986fd29aSsetje 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 *); 272986fd29aSsetje 273986fd29aSsetje static long s_strtol(char *); 274986fd29aSsetje static int s_fputs(char *, FILE *); 275986fd29aSsetje 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 3257c478bd9Sstevel@tonic-gate static void 3267c478bd9Sstevel@tonic-gate usage(void) 3277c478bd9Sstevel@tonic-gate { 3287c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "USAGE:\n"); 3297c478bd9Sstevel@tonic-gate 3307c478bd9Sstevel@tonic-gate 3317c478bd9Sstevel@tonic-gate /* archive usage */ 332d876c67dSjg (void) fprintf(stderr, 333d876c67dSjg "\t%s update-archive [-vn] [-R altroot [-p platform>]]\n", prog); 334d876c67dSjg (void) fprintf(stderr, 335d876c67dSjg "\t%s list-archive [-R altroot [-p platform>]]\n", prog); 336986fd29aSsetje #if !defined(_OPB) 3377c478bd9Sstevel@tonic-gate /* x86 only */ 3387c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "\t%s set-menu [-R altroot] key=value\n", prog); 3397c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "\t%s list-menu [-R altroot]\n", prog); 3407c478bd9Sstevel@tonic-gate #endif 3417c478bd9Sstevel@tonic-gate } 3427c478bd9Sstevel@tonic-gate 3437c478bd9Sstevel@tonic-gate int 3447c478bd9Sstevel@tonic-gate main(int argc, char *argv[]) 3457c478bd9Sstevel@tonic-gate { 3467c478bd9Sstevel@tonic-gate error_t ret; 3477c478bd9Sstevel@tonic-gate 3487c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 3497c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 3507c478bd9Sstevel@tonic-gate 3517c478bd9Sstevel@tonic-gate if ((prog = strrchr(argv[0], '/')) == NULL) { 3527c478bd9Sstevel@tonic-gate prog = argv[0]; 3537c478bd9Sstevel@tonic-gate } else { 3547c478bd9Sstevel@tonic-gate prog++; 3557c478bd9Sstevel@tonic-gate } 3567c478bd9Sstevel@tonic-gate 357eb2bd662Svikram INJECT_ERROR1("ASSERT_ON", assert(0)) 3587c478bd9Sstevel@tonic-gate 3597c478bd9Sstevel@tonic-gate /* 3607c478bd9Sstevel@tonic-gate * Don't depend on caller's umask 3617c478bd9Sstevel@tonic-gate */ 3627c478bd9Sstevel@tonic-gate (void) umask(0022); 3637c478bd9Sstevel@tonic-gate 3647c478bd9Sstevel@tonic-gate parse_args(argc, argv); 3657c478bd9Sstevel@tonic-gate 3667c478bd9Sstevel@tonic-gate switch (bam_cmd) { 3677c478bd9Sstevel@tonic-gate case BAM_MENU: 3687c478bd9Sstevel@tonic-gate ret = bam_menu(bam_subcmd, bam_opt, bam_argc, bam_argv); 3697c478bd9Sstevel@tonic-gate break; 3707c478bd9Sstevel@tonic-gate case BAM_ARCHIVE: 3717c478bd9Sstevel@tonic-gate ret = bam_archive(bam_subcmd, bam_opt); 3727c478bd9Sstevel@tonic-gate break; 3737c478bd9Sstevel@tonic-gate default: 3747c478bd9Sstevel@tonic-gate usage(); 3757c478bd9Sstevel@tonic-gate bam_exit(1); 3767c478bd9Sstevel@tonic-gate } 3777c478bd9Sstevel@tonic-gate 3787c478bd9Sstevel@tonic-gate if (ret != BAM_SUCCESS) 3797c478bd9Sstevel@tonic-gate bam_exit(1); 3807c478bd9Sstevel@tonic-gate 3817c478bd9Sstevel@tonic-gate bam_unlock(); 3827c478bd9Sstevel@tonic-gate return (0); 3837c478bd9Sstevel@tonic-gate } 3847c478bd9Sstevel@tonic-gate 3857c478bd9Sstevel@tonic-gate /* 3867c478bd9Sstevel@tonic-gate * Equivalence of public and internal commands: 3877c478bd9Sstevel@tonic-gate * update-archive -- -a update 3887c478bd9Sstevel@tonic-gate * list-archive -- -a list 3897c478bd9Sstevel@tonic-gate * set-menu -- -m set_option 3907c478bd9Sstevel@tonic-gate * list-menu -- -m list_entry 3917c478bd9Sstevel@tonic-gate * update-menu -- -m update_entry 3927c478bd9Sstevel@tonic-gate */ 3937c478bd9Sstevel@tonic-gate static struct cmd_map { 3947c478bd9Sstevel@tonic-gate char *bam_cmdname; 3957c478bd9Sstevel@tonic-gate int bam_cmd; 3967c478bd9Sstevel@tonic-gate char *bam_subcmd; 3977c478bd9Sstevel@tonic-gate } cmd_map[] = { 3987c478bd9Sstevel@tonic-gate { "update-archive", BAM_ARCHIVE, "update"}, 3997c478bd9Sstevel@tonic-gate { "list-archive", BAM_ARCHIVE, "list"}, 4007c478bd9Sstevel@tonic-gate { "set-menu", BAM_MENU, "set_option"}, 4017c478bd9Sstevel@tonic-gate { "list-menu", BAM_MENU, "list_entry"}, 4027c478bd9Sstevel@tonic-gate { "update-menu", BAM_MENU, "update_entry"}, 4037c478bd9Sstevel@tonic-gate { NULL, 0, NULL} 4047c478bd9Sstevel@tonic-gate }; 4057c478bd9Sstevel@tonic-gate 4067c478bd9Sstevel@tonic-gate /* 4077c478bd9Sstevel@tonic-gate * Commands syntax published in bootadm(1M) are parsed here 4087c478bd9Sstevel@tonic-gate */ 4097c478bd9Sstevel@tonic-gate static void 4107c478bd9Sstevel@tonic-gate parse_args(int argc, char *argv[]) 4117c478bd9Sstevel@tonic-gate { 4127c478bd9Sstevel@tonic-gate struct cmd_map *cmp = cmd_map; 4137c478bd9Sstevel@tonic-gate 4147c478bd9Sstevel@tonic-gate /* command conforming to the final spec */ 4157c478bd9Sstevel@tonic-gate if (argc > 1 && argv[1][0] != '-') { 4167c478bd9Sstevel@tonic-gate /* 4177c478bd9Sstevel@tonic-gate * Map commands to internal table. 4187c478bd9Sstevel@tonic-gate */ 4197c478bd9Sstevel@tonic-gate while (cmp->bam_cmdname) { 4207c478bd9Sstevel@tonic-gate if (strcmp(argv[1], cmp->bam_cmdname) == 0) { 4217c478bd9Sstevel@tonic-gate bam_cmd = cmp->bam_cmd; 4227c478bd9Sstevel@tonic-gate bam_subcmd = cmp->bam_subcmd; 4237c478bd9Sstevel@tonic-gate break; 4247c478bd9Sstevel@tonic-gate } 4257c478bd9Sstevel@tonic-gate cmp++; 4267c478bd9Sstevel@tonic-gate } 4277c478bd9Sstevel@tonic-gate if (cmp->bam_cmdname == NULL) { 4287c478bd9Sstevel@tonic-gate usage(); 4297c478bd9Sstevel@tonic-gate bam_exit(1); 4307c478bd9Sstevel@tonic-gate } 4317c478bd9Sstevel@tonic-gate argc--; 4327c478bd9Sstevel@tonic-gate argv++; 4337c478bd9Sstevel@tonic-gate } 4347c478bd9Sstevel@tonic-gate 4357c478bd9Sstevel@tonic-gate parse_args_internal(argc, argv); 4367c478bd9Sstevel@tonic-gate } 4377c478bd9Sstevel@tonic-gate 4387c478bd9Sstevel@tonic-gate /* 4397c478bd9Sstevel@tonic-gate * A combination of public and private commands are parsed here. 4407c478bd9Sstevel@tonic-gate * The internal syntax and the corresponding functionality are: 4417c478bd9Sstevel@tonic-gate * -a update -- update-archive 4427c478bd9Sstevel@tonic-gate * -a list -- list-archive 4437c478bd9Sstevel@tonic-gate * -a update-all -- (reboot to sync all mounted OS archive) 4447c478bd9Sstevel@tonic-gate * -m update_entry -- update-menu 4457c478bd9Sstevel@tonic-gate * -m list_entry -- list-menu 4467c478bd9Sstevel@tonic-gate * -m update_temp -- (reboot -- [boot-args]) 4477c478bd9Sstevel@tonic-gate * -m delete_all_entries -- (called from install) 4487c478bd9Sstevel@tonic-gate */ 4497c478bd9Sstevel@tonic-gate static void 4507c478bd9Sstevel@tonic-gate parse_args_internal(int argc, char *argv[]) 4517c478bd9Sstevel@tonic-gate { 4527c478bd9Sstevel@tonic-gate int c, error; 4537c478bd9Sstevel@tonic-gate extern char *optarg; 4547c478bd9Sstevel@tonic-gate extern int optind, opterr; 4557c478bd9Sstevel@tonic-gate 4567c478bd9Sstevel@tonic-gate /* Suppress error message from getopt */ 4577c478bd9Sstevel@tonic-gate opterr = 0; 4587c478bd9Sstevel@tonic-gate 4597c478bd9Sstevel@tonic-gate error = 0; 460e7cbe64fSgw while ((c = getopt(argc, argv, "a:d:fm:no:vCR:p:Z")) != -1) { 4617c478bd9Sstevel@tonic-gate switch (c) { 4627c478bd9Sstevel@tonic-gate case 'a': 4637c478bd9Sstevel@tonic-gate if (bam_cmd) { 4647c478bd9Sstevel@tonic-gate error = 1; 4657c478bd9Sstevel@tonic-gate bam_error(MULT_CMDS, c); 4667c478bd9Sstevel@tonic-gate } 4677c478bd9Sstevel@tonic-gate bam_cmd = BAM_ARCHIVE; 4687c478bd9Sstevel@tonic-gate bam_subcmd = optarg; 4697c478bd9Sstevel@tonic-gate break; 4707c478bd9Sstevel@tonic-gate case 'd': 4717c478bd9Sstevel@tonic-gate if (bam_debug) { 4727c478bd9Sstevel@tonic-gate error = 1; 4737c478bd9Sstevel@tonic-gate bam_error(DUP_OPT, c); 4747c478bd9Sstevel@tonic-gate } 4757c478bd9Sstevel@tonic-gate bam_debug = s_strtol(optarg); 4767c478bd9Sstevel@tonic-gate break; 4777c478bd9Sstevel@tonic-gate case 'f': 4787c478bd9Sstevel@tonic-gate if (bam_force) { 4797c478bd9Sstevel@tonic-gate error = 1; 4807c478bd9Sstevel@tonic-gate bam_error(DUP_OPT, c); 4817c478bd9Sstevel@tonic-gate } 4827c478bd9Sstevel@tonic-gate bam_force = 1; 4837c478bd9Sstevel@tonic-gate break; 4847c478bd9Sstevel@tonic-gate case 'm': 4857c478bd9Sstevel@tonic-gate if (bam_cmd) { 4867c478bd9Sstevel@tonic-gate error = 1; 4877c478bd9Sstevel@tonic-gate bam_error(MULT_CMDS, c); 4887c478bd9Sstevel@tonic-gate } 4897c478bd9Sstevel@tonic-gate bam_cmd = BAM_MENU; 4907c478bd9Sstevel@tonic-gate bam_subcmd = optarg; 4917c478bd9Sstevel@tonic-gate break; 4927c478bd9Sstevel@tonic-gate case 'n': 4937c478bd9Sstevel@tonic-gate if (bam_check) { 4947c478bd9Sstevel@tonic-gate error = 1; 4957c478bd9Sstevel@tonic-gate bam_error(DUP_OPT, c); 4967c478bd9Sstevel@tonic-gate } 4977c478bd9Sstevel@tonic-gate bam_check = 1; 4987c478bd9Sstevel@tonic-gate break; 4997c478bd9Sstevel@tonic-gate case 'o': 5007c478bd9Sstevel@tonic-gate if (bam_opt) { 5017c478bd9Sstevel@tonic-gate error = 1; 5027c478bd9Sstevel@tonic-gate bam_error(DUP_OPT, c); 5037c478bd9Sstevel@tonic-gate } 5047c478bd9Sstevel@tonic-gate bam_opt = optarg; 5057c478bd9Sstevel@tonic-gate break; 5067c478bd9Sstevel@tonic-gate case 'v': 5077c478bd9Sstevel@tonic-gate if (bam_verbose) { 5087c478bd9Sstevel@tonic-gate error = 1; 5097c478bd9Sstevel@tonic-gate bam_error(DUP_OPT, c); 5107c478bd9Sstevel@tonic-gate } 5117c478bd9Sstevel@tonic-gate bam_verbose = 1; 5127c478bd9Sstevel@tonic-gate break; 5138c1b6884Sszhou case 'C': 5148c1b6884Sszhou bam_smf_check = 1; 5158c1b6884Sszhou break; 5167c478bd9Sstevel@tonic-gate case 'R': 5177c478bd9Sstevel@tonic-gate if (bam_root) { 5187c478bd9Sstevel@tonic-gate error = 1; 5197c478bd9Sstevel@tonic-gate bam_error(DUP_OPT, c); 5207c478bd9Sstevel@tonic-gate break; 5217c478bd9Sstevel@tonic-gate } else if (realpath(optarg, rootbuf) == NULL) { 5227c478bd9Sstevel@tonic-gate error = 1; 5237c478bd9Sstevel@tonic-gate bam_error(CANT_RESOLVE, optarg, 5247c478bd9Sstevel@tonic-gate strerror(errno)); 5257c478bd9Sstevel@tonic-gate break; 5267c478bd9Sstevel@tonic-gate } 52740541d5dSvikram bam_alt_root = 1; 5287c478bd9Sstevel@tonic-gate bam_root = rootbuf; 5297c478bd9Sstevel@tonic-gate bam_rootlen = strlen(rootbuf); 5307c478bd9Sstevel@tonic-gate break; 531d876c67dSjg case 'p': 532d876c67dSjg bam_alt_platform = 1; 533d876c67dSjg bam_platform = optarg; 534d876c67dSjg if ((strcmp(bam_platform, "i86pc") != 0) && 535d876c67dSjg (strcmp(bam_platform, "sun4u") != 0) && 536d876c67dSjg (strcmp(bam_platform, "sun4v") != 0)) { 537d876c67dSjg error = 1; 538d876c67dSjg bam_error(INVALID_PLAT, bam_platform); 539d876c67dSjg } 540d876c67dSjg break; 541e7cbe64fSgw case 'Z': 542e7cbe64fSgw bam_zfs = 1; 543e7cbe64fSgw break; 5447c478bd9Sstevel@tonic-gate case '?': 5457c478bd9Sstevel@tonic-gate error = 1; 5467c478bd9Sstevel@tonic-gate bam_error(BAD_OPT, optopt); 5477c478bd9Sstevel@tonic-gate break; 5487c478bd9Sstevel@tonic-gate default : 5497c478bd9Sstevel@tonic-gate error = 1; 5507c478bd9Sstevel@tonic-gate bam_error(BAD_OPT, c); 5517c478bd9Sstevel@tonic-gate break; 5527c478bd9Sstevel@tonic-gate } 5537c478bd9Sstevel@tonic-gate } 5547c478bd9Sstevel@tonic-gate 555d876c67dSjg /* 556d876c67dSjg * An alternate platform requires an alternate root 557d876c67dSjg */ 558d876c67dSjg if (bam_alt_platform && bam_alt_root == 0) { 559d876c67dSjg usage(); 560d876c67dSjg bam_exit(0); 561d876c67dSjg } 562d876c67dSjg 5637c478bd9Sstevel@tonic-gate /* 5647c478bd9Sstevel@tonic-gate * A command option must be specfied 5657c478bd9Sstevel@tonic-gate */ 5667c478bd9Sstevel@tonic-gate if (!bam_cmd) { 5677c478bd9Sstevel@tonic-gate if (bam_opt && strcmp(bam_opt, "all") == 0) { 5687c478bd9Sstevel@tonic-gate usage(); 5697c478bd9Sstevel@tonic-gate bam_exit(0); 5707c478bd9Sstevel@tonic-gate } 5717c478bd9Sstevel@tonic-gate bam_error(NEED_CMD); 5727c478bd9Sstevel@tonic-gate error = 1; 5737c478bd9Sstevel@tonic-gate } 5747c478bd9Sstevel@tonic-gate 5757c478bd9Sstevel@tonic-gate if (error) { 5767c478bd9Sstevel@tonic-gate usage(); 5777c478bd9Sstevel@tonic-gate bam_exit(1); 5787c478bd9Sstevel@tonic-gate } 5797c478bd9Sstevel@tonic-gate 5807c478bd9Sstevel@tonic-gate if (optind > argc) { 5817c478bd9Sstevel@tonic-gate bam_error(INT_ERROR, "parse_args"); 5827c478bd9Sstevel@tonic-gate bam_exit(1); 5837c478bd9Sstevel@tonic-gate } else if (optind < argc) { 5847c478bd9Sstevel@tonic-gate bam_argv = &argv[optind]; 5857c478bd9Sstevel@tonic-gate bam_argc = argc - optind; 5867c478bd9Sstevel@tonic-gate } 5877c478bd9Sstevel@tonic-gate 5887c478bd9Sstevel@tonic-gate /* 5897c478bd9Sstevel@tonic-gate * -n implies verbose mode 5907c478bd9Sstevel@tonic-gate */ 5917c478bd9Sstevel@tonic-gate if (bam_check) 5927c478bd9Sstevel@tonic-gate bam_verbose = 1; 5937c478bd9Sstevel@tonic-gate } 5947c478bd9Sstevel@tonic-gate 5957c478bd9Sstevel@tonic-gate static error_t 5967c478bd9Sstevel@tonic-gate check_subcmd_and_options( 5977c478bd9Sstevel@tonic-gate char *subcmd, 5987c478bd9Sstevel@tonic-gate char *opt, 5997c478bd9Sstevel@tonic-gate subcmd_defn_t *table, 6007c478bd9Sstevel@tonic-gate error_t (**fp)()) 6017c478bd9Sstevel@tonic-gate { 6027c478bd9Sstevel@tonic-gate int i; 6037c478bd9Sstevel@tonic-gate 6047c478bd9Sstevel@tonic-gate if (subcmd == NULL) { 6057c478bd9Sstevel@tonic-gate bam_error(NEED_SUBCMD); 6067c478bd9Sstevel@tonic-gate return (BAM_ERROR); 6077c478bd9Sstevel@tonic-gate } 6087c478bd9Sstevel@tonic-gate 609eb2bd662Svikram if (strcmp(subcmd, "set_option") == 0) { 610eb2bd662Svikram if (bam_argc == 0 || bam_argv == NULL || bam_argv[0] == NULL) { 611eb2bd662Svikram bam_error(MISSING_ARG); 612eb2bd662Svikram usage(); 613eb2bd662Svikram return (BAM_ERROR); 614eb2bd662Svikram } else if (bam_argc > 1 || bam_argv[1] != NULL) { 6151a97e40eSvikram bam_error(TRAILING_ARGS); 6161a97e40eSvikram usage(); 6171a97e40eSvikram return (BAM_ERROR); 6181a97e40eSvikram } 619eb2bd662Svikram } else if (bam_argc || bam_argv) { 620eb2bd662Svikram bam_error(TRAILING_ARGS); 621eb2bd662Svikram usage(); 622eb2bd662Svikram return (BAM_ERROR); 6231a97e40eSvikram } 6241a97e40eSvikram 6257c478bd9Sstevel@tonic-gate if (bam_root == NULL) { 6267c478bd9Sstevel@tonic-gate bam_root = rootbuf; 6277c478bd9Sstevel@tonic-gate bam_rootlen = 1; 6287c478bd9Sstevel@tonic-gate } 6297c478bd9Sstevel@tonic-gate 6307c478bd9Sstevel@tonic-gate /* verify that subcmd is valid */ 6317c478bd9Sstevel@tonic-gate for (i = 0; table[i].subcmd != NULL; i++) { 6327c478bd9Sstevel@tonic-gate if (strcmp(table[i].subcmd, subcmd) == 0) 6337c478bd9Sstevel@tonic-gate break; 6347c478bd9Sstevel@tonic-gate } 6357c478bd9Sstevel@tonic-gate 6367c478bd9Sstevel@tonic-gate if (table[i].subcmd == NULL) { 6377c478bd9Sstevel@tonic-gate bam_error(INVALID_SUBCMD, subcmd); 6387c478bd9Sstevel@tonic-gate return (BAM_ERROR); 6397c478bd9Sstevel@tonic-gate } 6407c478bd9Sstevel@tonic-gate 6411a97e40eSvikram if (table[i].unpriv == 0 && geteuid() != 0) { 6421a97e40eSvikram bam_error(MUST_BE_ROOT); 6431a97e40eSvikram return (BAM_ERROR); 6441a97e40eSvikram } 6451a97e40eSvikram 6461a97e40eSvikram /* 6471a97e40eSvikram * Currently only privileged commands need a lock 6481a97e40eSvikram */ 6491a97e40eSvikram if (table[i].unpriv == 0) 6501a97e40eSvikram bam_lock(); 6511a97e40eSvikram 6527c478bd9Sstevel@tonic-gate /* subcmd verifies that opt is appropriate */ 6537c478bd9Sstevel@tonic-gate if (table[i].option != OPT_OPTIONAL) { 6547c478bd9Sstevel@tonic-gate if ((table[i].option == OPT_REQ) ^ (opt != NULL)) { 6557c478bd9Sstevel@tonic-gate if (opt) 6567c478bd9Sstevel@tonic-gate bam_error(NO_OPT_REQ, subcmd); 6577c478bd9Sstevel@tonic-gate else 6587c478bd9Sstevel@tonic-gate bam_error(MISS_OPT, subcmd); 6597c478bd9Sstevel@tonic-gate return (BAM_ERROR); 6607c478bd9Sstevel@tonic-gate } 6617c478bd9Sstevel@tonic-gate } 6627c478bd9Sstevel@tonic-gate 6637c478bd9Sstevel@tonic-gate *fp = table[i].handler; 6647c478bd9Sstevel@tonic-gate 6657c478bd9Sstevel@tonic-gate return (BAM_SUCCESS); 6667c478bd9Sstevel@tonic-gate } 6677c478bd9Sstevel@tonic-gate 66840541d5dSvikram /* 66940541d5dSvikram * NOTE: A single "/" is also considered a trailing slash and will 67040541d5dSvikram * be deleted. 67140541d5dSvikram */ 67240541d5dSvikram static void 67340541d5dSvikram elide_trailing_slash(const char *src, char *dst, size_t dstsize) 67440541d5dSvikram { 67540541d5dSvikram size_t dstlen; 67640541d5dSvikram 67740541d5dSvikram assert(src); 67840541d5dSvikram assert(dst); 67940541d5dSvikram 68040541d5dSvikram (void) strlcpy(dst, src, dstsize); 68140541d5dSvikram 68240541d5dSvikram dstlen = strlen(dst); 68340541d5dSvikram if (dst[dstlen - 1] == '/') { 68440541d5dSvikram dst[dstlen - 1] = '\0'; 68540541d5dSvikram } 68640541d5dSvikram } 68740541d5dSvikram 6887c478bd9Sstevel@tonic-gate static error_t 6897c478bd9Sstevel@tonic-gate bam_menu(char *subcmd, char *opt, int largc, char *largv[]) 6907c478bd9Sstevel@tonic-gate { 691eb2bd662Svikram error_t ret; 692eb2bd662Svikram char menu_path[PATH_MAX]; 693eb2bd662Svikram char clean_menu_root[PATH_MAX]; 694eb2bd662Svikram char path[PATH_MAX]; 695eb2bd662Svikram menu_t *menu; 696eb2bd662Svikram char menu_root[PATH_MAX]; 697eb2bd662Svikram struct stat sb; 6987c478bd9Sstevel@tonic-gate error_t (*f)(menu_t *mp, char *menu_path, char *opt); 699eb2bd662Svikram char *special; 700eb2bd662Svikram char *pool = NULL; 701eb2bd662Svikram zfs_mnted_t zmnted; 702eb2bd662Svikram char *zmntpt; 703eb2bd662Svikram char *osdev; 704eb2bd662Svikram char *osroot; 705eb2bd662Svikram const char *fcn = "bam_menu()"; 706986fd29aSsetje 707986fd29aSsetje /* 708986fd29aSsetje * Menu sub-command only applies to GRUB (i.e. x86) 709986fd29aSsetje */ 710eb2bd662Svikram if (!is_grub(bam_alt_root ? bam_root : "/")) { 711eb2bd662Svikram bam_error(NOT_GRUB_BOOT); 712986fd29aSsetje return (BAM_ERROR); 713986fd29aSsetje } 7147c478bd9Sstevel@tonic-gate 7157c478bd9Sstevel@tonic-gate /* 7167c478bd9Sstevel@tonic-gate * Check arguments 7177c478bd9Sstevel@tonic-gate */ 7187c478bd9Sstevel@tonic-gate ret = check_subcmd_and_options(subcmd, opt, menu_subcmds, &f); 7197c478bd9Sstevel@tonic-gate if (ret == BAM_ERROR) { 7207c478bd9Sstevel@tonic-gate return (BAM_ERROR); 7217c478bd9Sstevel@tonic-gate } 7227c478bd9Sstevel@tonic-gate 723eb2bd662Svikram assert(bam_root); 72440541d5dSvikram 725eb2bd662Svikram (void) strlcpy(menu_root, bam_root, sizeof (menu_root)); 726eb2bd662Svikram osdev = osroot = NULL; 727eb2bd662Svikram 728eb2bd662Svikram if (strcmp(subcmd, "update_entry") == 0) { 729eb2bd662Svikram assert(opt); 730eb2bd662Svikram 731eb2bd662Svikram osdev = strtok(opt, ","); 732eb2bd662Svikram assert(osdev); 733eb2bd662Svikram osroot = strtok(NULL, ","); 734eb2bd662Svikram if (osroot) { 735eb2bd662Svikram /* fixup bam_root so that it points at osroot */ 736eb2bd662Svikram if (realpath(osroot, rootbuf) == NULL) { 737eb2bd662Svikram bam_error(CANT_RESOLVE, osroot, 738eb2bd662Svikram strerror(errno)); 739eb2bd662Svikram return (BAM_ERROR); 740eb2bd662Svikram } 741eb2bd662Svikram bam_alt_root = 1; 742eb2bd662Svikram bam_root = rootbuf; 743eb2bd662Svikram bam_rootlen = strlen(rootbuf); 744eb2bd662Svikram } 745ae115bc7Smrj } 746ae115bc7Smrj 747eb2bd662Svikram /* 748eb2bd662Svikram * We support menu on PCFS (under certain conditions), but 749eb2bd662Svikram * not the OS root 750eb2bd662Svikram */ 751eb2bd662Svikram if (is_pcfs(bam_root)) { 752eb2bd662Svikram bam_error(PCFS_ROOT_NOTSUP, bam_root); 753eb2bd662Svikram return (BAM_ERROR); 754b610f78eSvikram } 755b610f78eSvikram 756eb2bd662Svikram if (stat(menu_root, &sb) == -1) { 75740541d5dSvikram bam_error(CANNOT_LOCATE_GRUB_MENU); 75840541d5dSvikram return (BAM_ERROR); 75940541d5dSvikram } 76040541d5dSvikram 761eb2bd662Svikram BAM_DPRINTF((D_MENU_ROOT, fcn, menu_root)); 762eb2bd662Svikram 763e7cbe64fSgw /* 764eb2bd662Svikram * We no longer use the GRUB slice file. If it exists, then 765eb2bd662Svikram * the user is doing something that is unsupported (such as 766eb2bd662Svikram * standard upgrading an old Live Upgrade BE). If that 767eb2bd662Svikram * happens, mimic existing behavior i.e. pretend that it is 768eb2bd662Svikram * not a BE. Emit a warning though. 769e7cbe64fSgw */ 770eb2bd662Svikram if (bam_alt_root) { 771eb2bd662Svikram (void) snprintf(path, sizeof (path), "%s%s", bam_root, 772eb2bd662Svikram GRUB_slice); 773eb2bd662Svikram } else { 774eb2bd662Svikram (void) snprintf(path, sizeof (path), "%s", GRUB_slice); 775eb2bd662Svikram } 776eb2bd662Svikram 777eb2bd662Svikram if (stat(path, &sb) == 0) 778eb2bd662Svikram bam_error(GRUB_SLICE_FILE_EXISTS, path); 779eb2bd662Svikram 780eb2bd662Svikram if (is_zfs(menu_root)) { 781eb2bd662Svikram assert(strcmp(menu_root, bam_root) == 0); 782eb2bd662Svikram special = get_special(menu_root); 783eb2bd662Svikram INJECT_ERROR1("Z_MENU_GET_SPECIAL", special = NULL); 784eb2bd662Svikram if (special == NULL) { 785eb2bd662Svikram bam_error(CANT_FIND_SPECIAL, menu_root); 786eb2bd662Svikram return (BAM_ERROR); 787eb2bd662Svikram } 788eb2bd662Svikram pool = strtok(special, "/"); 789eb2bd662Svikram INJECT_ERROR1("Z_MENU_GET_POOL", pool = NULL); 790eb2bd662Svikram if (pool == NULL) { 791eb2bd662Svikram free(special); 792eb2bd662Svikram bam_error(CANT_FIND_POOL, menu_root); 793eb2bd662Svikram return (BAM_ERROR); 794eb2bd662Svikram } 795eb2bd662Svikram BAM_DPRINTF((D_Z_MENU_GET_POOL_FROM_SPECIAL, fcn, pool)); 796e7cbe64fSgw 797eb2bd662Svikram zmntpt = mount_top_dataset(pool, &zmnted); 798eb2bd662Svikram INJECT_ERROR1("Z_MENU_MOUNT_TOP_DATASET", zmntpt = NULL); 799eb2bd662Svikram if (zmntpt == NULL) { 800eb2bd662Svikram bam_error(CANT_MOUNT_POOL_DATASET, pool); 801eb2bd662Svikram free(special); 802eb2bd662Svikram return (BAM_ERROR); 803eb2bd662Svikram } 804eb2bd662Svikram BAM_DPRINTF((D_Z_GET_MENU_MOUNT_TOP_DATASET, fcn, zmntpt)); 805eb2bd662Svikram 806eb2bd662Svikram (void) strlcpy(menu_root, zmntpt, sizeof (menu_root)); 807eb2bd662Svikram BAM_DPRINTF((D_Z_GET_MENU_MENU_ROOT, fcn, menu_root)); 808e7cbe64fSgw } 809e7cbe64fSgw 810eb2bd662Svikram elide_trailing_slash(menu_root, clean_menu_root, 811eb2bd662Svikram sizeof (clean_menu_root)); 812eb2bd662Svikram 813eb2bd662Svikram BAM_DPRINTF((D_CLEAN_MENU_ROOT, fcn, clean_menu_root)); 814eb2bd662Svikram 815eb2bd662Svikram (void) strlcpy(menu_path, clean_menu_root, sizeof (menu_path)); 81640541d5dSvikram (void) strlcat(menu_path, GRUB_MENU, sizeof (menu_path)); 81740541d5dSvikram 818eb2bd662Svikram BAM_DPRINTF((D_MENU_PATH, fcn, menu_path)); 819eb2bd662Svikram 82040541d5dSvikram /* 821eb2bd662Svikram * If listing the menu, display the menu location 82240541d5dSvikram */ 82340541d5dSvikram if (strcmp(subcmd, "list_entry") == 0) { 824eb2bd662Svikram bam_print(GRUB_MENU_PATH, menu_path); 82540541d5dSvikram } 8267c478bd9Sstevel@tonic-gate 827eb2bd662Svikram 8287c478bd9Sstevel@tonic-gate menu = menu_read(menu_path); 8297c478bd9Sstevel@tonic-gate assert(menu); 8307c478bd9Sstevel@tonic-gate 8317c478bd9Sstevel@tonic-gate /* 832eb2bd662Svikram * We already checked the following case in 833eb2bd662Svikram * check_subcmd_and_suboptions() above. Complete the 834eb2bd662Svikram * final step now. 8357c478bd9Sstevel@tonic-gate */ 8367c478bd9Sstevel@tonic-gate if (strcmp(subcmd, "set_option") == 0) { 837eb2bd662Svikram assert(largc == 1 && largv[0] && largv[1] == NULL); 8387c478bd9Sstevel@tonic-gate opt = largv[0]; 839eb2bd662Svikram } else { 840eb2bd662Svikram assert(largc == 0 && largv == NULL); 8417c478bd9Sstevel@tonic-gate } 8427c478bd9Sstevel@tonic-gate 843eb2bd662Svikram ret = get_boot_cap(bam_root); 844eb2bd662Svikram if (ret != BAM_SUCCESS) { 845eb2bd662Svikram BAM_DPRINTF((D_BOOT_GET_CAP_FAILED, fcn)); 846eb2bd662Svikram goto out; 847eb2bd662Svikram } 848ae115bc7Smrj 8497c478bd9Sstevel@tonic-gate /* 8507c478bd9Sstevel@tonic-gate * Once the sub-cmd handler has run 8517c478bd9Sstevel@tonic-gate * only the line field is guaranteed to have valid values 8527c478bd9Sstevel@tonic-gate */ 853eb2bd662Svikram if (strcmp(subcmd, "update_entry") == 0) 854eb2bd662Svikram ret = f(menu, menu_root, osdev); 855eb2bd662Svikram else if (strcmp(subcmd, "upgrade") == 0) 856eb2bd662Svikram ret = f(menu, bam_root, menu_root); 857eb2bd662Svikram else if (strcmp(subcmd, "list_entry") == 0) 8587c478bd9Sstevel@tonic-gate ret = f(menu, menu_path, opt); 859eb2bd662Svikram else 860eb2bd662Svikram ret = f(menu, NULL, opt); 861eb2bd662Svikram 8627c478bd9Sstevel@tonic-gate if (ret == BAM_WRITE) { 863eb2bd662Svikram BAM_DPRINTF((D_WRITING_MENU_ROOT, fcn, clean_menu_root)); 864eb2bd662Svikram ret = menu_write(clean_menu_root, menu); 8657c478bd9Sstevel@tonic-gate } 8667c478bd9Sstevel@tonic-gate 867eb2bd662Svikram out: 868eb2bd662Svikram INJECT_ERROR1("POOL_SET", pool = "/pooldata"); 869eb2bd662Svikram assert((is_zfs(menu_root)) ^ (pool == NULL)); 870eb2bd662Svikram if (pool) { 871eb2bd662Svikram (void) umount_top_dataset(pool, zmnted, zmntpt); 872eb2bd662Svikram free(special); 873eb2bd662Svikram } 8747c478bd9Sstevel@tonic-gate menu_free(menu); 8757c478bd9Sstevel@tonic-gate return (ret); 8767c478bd9Sstevel@tonic-gate } 8777c478bd9Sstevel@tonic-gate 8787c478bd9Sstevel@tonic-gate 8797c478bd9Sstevel@tonic-gate static error_t 8807c478bd9Sstevel@tonic-gate bam_archive( 8817c478bd9Sstevel@tonic-gate char *subcmd, 8827c478bd9Sstevel@tonic-gate char *opt) 8837c478bd9Sstevel@tonic-gate { 884eb2bd662Svikram error_t ret; 885eb2bd662Svikram error_t (*f)(char *root, char *opt); 886eb2bd662Svikram const char *fcn = "bam_archive()"; 8877c478bd9Sstevel@tonic-gate 8888c1b6884Sszhou /* 8898c1b6884Sszhou * Add trailing / for archive subcommands 8908c1b6884Sszhou */ 8918c1b6884Sszhou if (rootbuf[strlen(rootbuf) - 1] != '/') 8928c1b6884Sszhou (void) strcat(rootbuf, "/"); 8938c1b6884Sszhou bam_rootlen = strlen(rootbuf); 8948c1b6884Sszhou 8957c478bd9Sstevel@tonic-gate /* 8967c478bd9Sstevel@tonic-gate * Check arguments 8977c478bd9Sstevel@tonic-gate */ 8987c478bd9Sstevel@tonic-gate ret = check_subcmd_and_options(subcmd, opt, arch_subcmds, &f); 8997c478bd9Sstevel@tonic-gate if (ret != BAM_SUCCESS) { 9007c478bd9Sstevel@tonic-gate return (BAM_ERROR); 9017c478bd9Sstevel@tonic-gate } 9027c478bd9Sstevel@tonic-gate 903eb2bd662Svikram ret = get_boot_cap(rootbuf); 904eb2bd662Svikram if (ret != BAM_SUCCESS) { 905eb2bd662Svikram BAM_DPRINTF((D_BOOT_GET_CAP_FAILED, fcn)); 906ae115bc7Smrj return (ret); 907eb2bd662Svikram } 908ae115bc7Smrj 9097c478bd9Sstevel@tonic-gate /* 9107c478bd9Sstevel@tonic-gate * Check archive not supported with update_all 9117c478bd9Sstevel@tonic-gate * since it is awkward to display out-of-sync 9127c478bd9Sstevel@tonic-gate * information for each BE. 9137c478bd9Sstevel@tonic-gate */ 9147c478bd9Sstevel@tonic-gate if (bam_check && strcmp(subcmd, "update_all") == 0) { 9157c478bd9Sstevel@tonic-gate bam_error(CHECK_NOT_SUPPORTED, subcmd); 9167c478bd9Sstevel@tonic-gate return (BAM_ERROR); 9177c478bd9Sstevel@tonic-gate } 9187c478bd9Sstevel@tonic-gate 919b610f78eSvikram if (strcmp(subcmd, "update_all") == 0) 920b610f78eSvikram bam_update_all = 1; 921b610f78eSvikram 922986fd29aSsetje #if !defined(_OPB) 9232449e17fSsherrym ucode_install(bam_root); 9242449e17fSsherrym #endif 9252449e17fSsherrym 926b610f78eSvikram ret = f(bam_root, opt); 927b610f78eSvikram 928b610f78eSvikram bam_update_all = 0; 929b610f78eSvikram 930b610f78eSvikram return (ret); 9317c478bd9Sstevel@tonic-gate } 9327c478bd9Sstevel@tonic-gate 9337c478bd9Sstevel@tonic-gate /*PRINTFLIKE1*/ 934ae115bc7Smrj void 9357c478bd9Sstevel@tonic-gate bam_error(char *format, ...) 9367c478bd9Sstevel@tonic-gate { 9377c478bd9Sstevel@tonic-gate va_list ap; 9387c478bd9Sstevel@tonic-gate 9397c478bd9Sstevel@tonic-gate va_start(ap, format); 9407c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: ", prog); 9417c478bd9Sstevel@tonic-gate (void) vfprintf(stderr, format, ap); 9427c478bd9Sstevel@tonic-gate va_end(ap); 9437c478bd9Sstevel@tonic-gate } 9447c478bd9Sstevel@tonic-gate 9457c478bd9Sstevel@tonic-gate /*PRINTFLIKE1*/ 946eb2bd662Svikram void 947eb2bd662Svikram bam_derror(char *format, ...) 948eb2bd662Svikram { 949eb2bd662Svikram va_list ap; 950eb2bd662Svikram 951eb2bd662Svikram assert(bam_debug); 952eb2bd662Svikram 953eb2bd662Svikram va_start(ap, format); 954eb2bd662Svikram (void) fprintf(stderr, "DEBUG: "); 955eb2bd662Svikram (void) vfprintf(stderr, format, ap); 956eb2bd662Svikram va_end(ap); 957eb2bd662Svikram } 958eb2bd662Svikram 959eb2bd662Svikram /*PRINTFLIKE1*/ 960eb2bd662Svikram void 9617c478bd9Sstevel@tonic-gate bam_print(char *format, ...) 9627c478bd9Sstevel@tonic-gate { 9637c478bd9Sstevel@tonic-gate va_list ap; 9647c478bd9Sstevel@tonic-gate 9657c478bd9Sstevel@tonic-gate va_start(ap, format); 9667c478bd9Sstevel@tonic-gate (void) vfprintf(stdout, format, ap); 9677c478bd9Sstevel@tonic-gate va_end(ap); 9687c478bd9Sstevel@tonic-gate } 9697c478bd9Sstevel@tonic-gate 970ae115bc7Smrj /*PRINTFLIKE1*/ 971ae115bc7Smrj void 972ae115bc7Smrj bam_print_stderr(char *format, ...) 973ae115bc7Smrj { 974ae115bc7Smrj va_list ap; 975ae115bc7Smrj 976ae115bc7Smrj va_start(ap, format); 977ae115bc7Smrj (void) vfprintf(stderr, format, ap); 978ae115bc7Smrj va_end(ap); 979ae115bc7Smrj } 980ae115bc7Smrj 9817c478bd9Sstevel@tonic-gate static void 9827c478bd9Sstevel@tonic-gate bam_exit(int excode) 9837c478bd9Sstevel@tonic-gate { 9847c478bd9Sstevel@tonic-gate bam_unlock(); 9857c478bd9Sstevel@tonic-gate exit(excode); 9867c478bd9Sstevel@tonic-gate } 9877c478bd9Sstevel@tonic-gate 9887c478bd9Sstevel@tonic-gate static void 9897c478bd9Sstevel@tonic-gate bam_lock(void) 9907c478bd9Sstevel@tonic-gate { 9917c478bd9Sstevel@tonic-gate struct flock lock; 9927c478bd9Sstevel@tonic-gate pid_t pid; 9937c478bd9Sstevel@tonic-gate 9947c478bd9Sstevel@tonic-gate bam_lock_fd = open(BAM_LOCK_FILE, O_CREAT|O_RDWR, LOCK_FILE_PERMS); 9957c478bd9Sstevel@tonic-gate if (bam_lock_fd < 0) { 9967c478bd9Sstevel@tonic-gate /* 9977c478bd9Sstevel@tonic-gate * We may be invoked early in boot for archive verification. 9987c478bd9Sstevel@tonic-gate * In this case, root is readonly and /var/run may not exist. 9997c478bd9Sstevel@tonic-gate * Proceed without the lock 10007c478bd9Sstevel@tonic-gate */ 10017c478bd9Sstevel@tonic-gate if (errno == EROFS || errno == ENOENT) { 10027c478bd9Sstevel@tonic-gate bam_root_readonly = 1; 10037c478bd9Sstevel@tonic-gate return; 10047c478bd9Sstevel@tonic-gate } 10057c478bd9Sstevel@tonic-gate 10067c478bd9Sstevel@tonic-gate bam_error(OPEN_FAIL, BAM_LOCK_FILE, strerror(errno)); 10077c478bd9Sstevel@tonic-gate bam_exit(1); 10087c478bd9Sstevel@tonic-gate } 10097c478bd9Sstevel@tonic-gate 10107c478bd9Sstevel@tonic-gate lock.l_type = F_WRLCK; 10117c478bd9Sstevel@tonic-gate lock.l_whence = SEEK_SET; 10127c478bd9Sstevel@tonic-gate lock.l_start = 0; 10137c478bd9Sstevel@tonic-gate lock.l_len = 0; 10147c478bd9Sstevel@tonic-gate 10157c478bd9Sstevel@tonic-gate if (fcntl(bam_lock_fd, F_SETLK, &lock) == -1) { 10167c478bd9Sstevel@tonic-gate if (errno != EACCES && errno != EAGAIN) { 10177c478bd9Sstevel@tonic-gate bam_error(LOCK_FAIL, BAM_LOCK_FILE, strerror(errno)); 10187c478bd9Sstevel@tonic-gate (void) close(bam_lock_fd); 10197c478bd9Sstevel@tonic-gate bam_lock_fd = -1; 10207c478bd9Sstevel@tonic-gate bam_exit(1); 10217c478bd9Sstevel@tonic-gate } 10227c478bd9Sstevel@tonic-gate pid = 0; 10237c478bd9Sstevel@tonic-gate (void) pread(bam_lock_fd, &pid, sizeof (pid_t), 0); 10247c478bd9Sstevel@tonic-gate bam_print(FILE_LOCKED, pid); 10257c478bd9Sstevel@tonic-gate 10267c478bd9Sstevel@tonic-gate lock.l_type = F_WRLCK; 10277c478bd9Sstevel@tonic-gate lock.l_whence = SEEK_SET; 10287c478bd9Sstevel@tonic-gate lock.l_start = 0; 10297c478bd9Sstevel@tonic-gate lock.l_len = 0; 10307c478bd9Sstevel@tonic-gate if (fcntl(bam_lock_fd, F_SETLKW, &lock) == -1) { 10317c478bd9Sstevel@tonic-gate bam_error(LOCK_FAIL, BAM_LOCK_FILE, strerror(errno)); 10327c478bd9Sstevel@tonic-gate (void) close(bam_lock_fd); 10337c478bd9Sstevel@tonic-gate bam_lock_fd = -1; 10347c478bd9Sstevel@tonic-gate bam_exit(1); 10357c478bd9Sstevel@tonic-gate } 10367c478bd9Sstevel@tonic-gate } 10377c478bd9Sstevel@tonic-gate 10387c478bd9Sstevel@tonic-gate /* We own the lock now */ 10397c478bd9Sstevel@tonic-gate pid = getpid(); 10407c478bd9Sstevel@tonic-gate (void) write(bam_lock_fd, &pid, sizeof (pid)); 10417c478bd9Sstevel@tonic-gate } 10427c478bd9Sstevel@tonic-gate 10437c478bd9Sstevel@tonic-gate static void 10447c478bd9Sstevel@tonic-gate bam_unlock(void) 10457c478bd9Sstevel@tonic-gate { 10467c478bd9Sstevel@tonic-gate struct flock unlock; 10477c478bd9Sstevel@tonic-gate 10487c478bd9Sstevel@tonic-gate /* 10497c478bd9Sstevel@tonic-gate * NOP if we don't hold the lock 10507c478bd9Sstevel@tonic-gate */ 10517c478bd9Sstevel@tonic-gate if (bam_lock_fd < 0) { 10527c478bd9Sstevel@tonic-gate return; 10537c478bd9Sstevel@tonic-gate } 10547c478bd9Sstevel@tonic-gate 10557c478bd9Sstevel@tonic-gate unlock.l_type = F_UNLCK; 10567c478bd9Sstevel@tonic-gate unlock.l_whence = SEEK_SET; 10577c478bd9Sstevel@tonic-gate unlock.l_start = 0; 10587c478bd9Sstevel@tonic-gate unlock.l_len = 0; 10597c478bd9Sstevel@tonic-gate 10607c478bd9Sstevel@tonic-gate if (fcntl(bam_lock_fd, F_SETLK, &unlock) == -1) { 10617c478bd9Sstevel@tonic-gate bam_error(UNLOCK_FAIL, BAM_LOCK_FILE, strerror(errno)); 10627c478bd9Sstevel@tonic-gate } 10637c478bd9Sstevel@tonic-gate 10647c478bd9Sstevel@tonic-gate if (close(bam_lock_fd) == -1) { 10657c478bd9Sstevel@tonic-gate bam_error(CLOSE_FAIL, BAM_LOCK_FILE, strerror(errno)); 10667c478bd9Sstevel@tonic-gate } 10677c478bd9Sstevel@tonic-gate bam_lock_fd = -1; 10687c478bd9Sstevel@tonic-gate } 10697c478bd9Sstevel@tonic-gate 10707c478bd9Sstevel@tonic-gate static error_t 10717c478bd9Sstevel@tonic-gate list_archive(char *root, char *opt) 10727c478bd9Sstevel@tonic-gate { 10737c478bd9Sstevel@tonic-gate filelist_t flist; 10747c478bd9Sstevel@tonic-gate filelist_t *flistp = &flist; 10757c478bd9Sstevel@tonic-gate line_t *lp; 10767c478bd9Sstevel@tonic-gate 10777c478bd9Sstevel@tonic-gate assert(root); 10787c478bd9Sstevel@tonic-gate assert(opt == NULL); 10797c478bd9Sstevel@tonic-gate 10807c478bd9Sstevel@tonic-gate flistp->head = flistp->tail = NULL; 10817c478bd9Sstevel@tonic-gate if (read_list(root, flistp) != BAM_SUCCESS) { 10827c478bd9Sstevel@tonic-gate return (BAM_ERROR); 10837c478bd9Sstevel@tonic-gate } 10847c478bd9Sstevel@tonic-gate assert(flistp->head && flistp->tail); 10857c478bd9Sstevel@tonic-gate 10867c478bd9Sstevel@tonic-gate for (lp = flistp->head; lp; lp = lp->next) { 10877c478bd9Sstevel@tonic-gate bam_print(PRINT, lp->line); 10887c478bd9Sstevel@tonic-gate } 10897c478bd9Sstevel@tonic-gate 10907c478bd9Sstevel@tonic-gate filelist_free(flistp); 10917c478bd9Sstevel@tonic-gate 10927c478bd9Sstevel@tonic-gate return (BAM_SUCCESS); 10937c478bd9Sstevel@tonic-gate } 10947c478bd9Sstevel@tonic-gate 10957c478bd9Sstevel@tonic-gate /* 10967c478bd9Sstevel@tonic-gate * This routine writes a list of lines to a file. 10977c478bd9Sstevel@tonic-gate * The list is *not* freed 10987c478bd9Sstevel@tonic-gate */ 10997c478bd9Sstevel@tonic-gate static error_t 11007c478bd9Sstevel@tonic-gate list2file(char *root, char *tmp, char *final, line_t *start) 11017c478bd9Sstevel@tonic-gate { 1102eb2bd662Svikram char tmpfile[PATH_MAX]; 1103eb2bd662Svikram char path[PATH_MAX]; 1104eb2bd662Svikram FILE *fp; 1105eb2bd662Svikram int ret; 1106eb2bd662Svikram struct stat sb; 1107eb2bd662Svikram mode_t mode; 1108eb2bd662Svikram uid_t root_uid; 1109eb2bd662Svikram gid_t sys_gid; 1110eb2bd662Svikram struct passwd *pw; 1111eb2bd662Svikram struct group *gp; 1112eb2bd662Svikram const char *fcn = "list2file()"; 11137c478bd9Sstevel@tonic-gate 11147c478bd9Sstevel@tonic-gate (void) snprintf(path, sizeof (path), "%s%s", root, final); 11157c478bd9Sstevel@tonic-gate 11167c478bd9Sstevel@tonic-gate if (start == NULL) { 1117eb2bd662Svikram /* Empty GRUB menu */ 11187c478bd9Sstevel@tonic-gate if (stat(path, &sb) != -1) { 11197c478bd9Sstevel@tonic-gate bam_print(UNLINK_EMPTY, path); 11207c478bd9Sstevel@tonic-gate if (unlink(path) != 0) { 11217c478bd9Sstevel@tonic-gate bam_error(UNLINK_FAIL, path, strerror(errno)); 11227c478bd9Sstevel@tonic-gate return (BAM_ERROR); 11237c478bd9Sstevel@tonic-gate } else { 11247c478bd9Sstevel@tonic-gate return (BAM_SUCCESS); 11257c478bd9Sstevel@tonic-gate } 11267c478bd9Sstevel@tonic-gate } 1127eb2bd662Svikram return (BAM_SUCCESS); 11287c478bd9Sstevel@tonic-gate } 11297c478bd9Sstevel@tonic-gate 11307c478bd9Sstevel@tonic-gate /* 11317c478bd9Sstevel@tonic-gate * Preserve attributes of existing file if possible, 11327c478bd9Sstevel@tonic-gate * otherwise ask the system for uid/gid of root/sys. 11337c478bd9Sstevel@tonic-gate * If all fails, fall back on hard-coded defaults. 11347c478bd9Sstevel@tonic-gate */ 11357c478bd9Sstevel@tonic-gate if (stat(path, &sb) != -1) { 11367c478bd9Sstevel@tonic-gate mode = sb.st_mode; 11377c478bd9Sstevel@tonic-gate root_uid = sb.st_uid; 11387c478bd9Sstevel@tonic-gate sys_gid = sb.st_gid; 11397c478bd9Sstevel@tonic-gate } else { 11407c478bd9Sstevel@tonic-gate mode = DEFAULT_DEV_MODE; 11417c478bd9Sstevel@tonic-gate if ((pw = getpwnam(DEFAULT_DEV_USER)) != NULL) { 11427c478bd9Sstevel@tonic-gate root_uid = pw->pw_uid; 11437c478bd9Sstevel@tonic-gate } else { 1144eb2bd662Svikram bam_error(CANT_FIND_USER, 1145eb2bd662Svikram DEFAULT_DEV_USER, DEFAULT_DEV_UID); 11467c478bd9Sstevel@tonic-gate root_uid = (uid_t)DEFAULT_DEV_UID; 11477c478bd9Sstevel@tonic-gate } 11487c478bd9Sstevel@tonic-gate if ((gp = getgrnam(DEFAULT_DEV_GROUP)) != NULL) { 11497c478bd9Sstevel@tonic-gate sys_gid = gp->gr_gid; 11507c478bd9Sstevel@tonic-gate } else { 1151eb2bd662Svikram bam_error(CANT_FIND_GROUP, 1152eb2bd662Svikram DEFAULT_DEV_GROUP, DEFAULT_DEV_GID); 11537c478bd9Sstevel@tonic-gate sys_gid = (gid_t)DEFAULT_DEV_GID; 11547c478bd9Sstevel@tonic-gate } 11557c478bd9Sstevel@tonic-gate } 11567c478bd9Sstevel@tonic-gate 11577c478bd9Sstevel@tonic-gate (void) snprintf(tmpfile, sizeof (tmpfile), "%s%s", root, tmp); 11587c478bd9Sstevel@tonic-gate 11597c478bd9Sstevel@tonic-gate /* Truncate tmpfile first */ 11607c478bd9Sstevel@tonic-gate fp = fopen(tmpfile, "w"); 11617c478bd9Sstevel@tonic-gate if (fp == NULL) { 11627c478bd9Sstevel@tonic-gate bam_error(OPEN_FAIL, tmpfile, strerror(errno)); 11637c478bd9Sstevel@tonic-gate return (BAM_ERROR); 11647c478bd9Sstevel@tonic-gate } 1165963390b4Svikram ret = fclose(fp); 1166963390b4Svikram INJECT_ERROR1("LIST2FILE_TRUNC_FCLOSE", ret = EOF); 1167963390b4Svikram if (ret == EOF) { 11687c478bd9Sstevel@tonic-gate bam_error(CLOSE_FAIL, tmpfile, strerror(errno)); 11697c478bd9Sstevel@tonic-gate return (BAM_ERROR); 11707c478bd9Sstevel@tonic-gate } 11717c478bd9Sstevel@tonic-gate 11727c478bd9Sstevel@tonic-gate /* Now open it in append mode */ 11737c478bd9Sstevel@tonic-gate fp = fopen(tmpfile, "a"); 11747c478bd9Sstevel@tonic-gate if (fp == NULL) { 11757c478bd9Sstevel@tonic-gate bam_error(OPEN_FAIL, tmpfile, strerror(errno)); 11767c478bd9Sstevel@tonic-gate return (BAM_ERROR); 11777c478bd9Sstevel@tonic-gate } 11787c478bd9Sstevel@tonic-gate 11797c478bd9Sstevel@tonic-gate for (; start; start = start->next) { 1180963390b4Svikram ret = s_fputs(start->line, fp); 1181963390b4Svikram INJECT_ERROR1("LIST2FILE_FPUTS", ret = EOF); 1182963390b4Svikram if (ret == EOF) { 11837c478bd9Sstevel@tonic-gate bam_error(WRITE_FAIL, tmpfile, strerror(errno)); 11847c478bd9Sstevel@tonic-gate (void) fclose(fp); 11857c478bd9Sstevel@tonic-gate return (BAM_ERROR); 11867c478bd9Sstevel@tonic-gate } 11877c478bd9Sstevel@tonic-gate } 11887c478bd9Sstevel@tonic-gate 1189963390b4Svikram ret = fclose(fp); 1190963390b4Svikram INJECT_ERROR1("LIST2FILE_APPEND_FCLOSE", ret = EOF); 1191963390b4Svikram if (ret == EOF) { 11927c478bd9Sstevel@tonic-gate bam_error(CLOSE_FAIL, tmpfile, strerror(errno)); 11937c478bd9Sstevel@tonic-gate return (BAM_ERROR); 11947c478bd9Sstevel@tonic-gate } 11957c478bd9Sstevel@tonic-gate 11967c478bd9Sstevel@tonic-gate /* 1197de531be4Sjg * Set up desired attributes. Ignore failures on filesystems 1198de531be4Sjg * not supporting these operations - pcfs reports unsupported 1199de531be4Sjg * operations as EINVAL. 12007c478bd9Sstevel@tonic-gate */ 12017c478bd9Sstevel@tonic-gate ret = chmod(tmpfile, mode); 1202de531be4Sjg if (ret == -1 && 1203de531be4Sjg errno != EINVAL && errno != ENOTSUP) { 12047c478bd9Sstevel@tonic-gate bam_error(CHMOD_FAIL, tmpfile, strerror(errno)); 12057c478bd9Sstevel@tonic-gate return (BAM_ERROR); 12067c478bd9Sstevel@tonic-gate } 12077c478bd9Sstevel@tonic-gate 12087c478bd9Sstevel@tonic-gate ret = chown(tmpfile, root_uid, sys_gid); 1209de531be4Sjg if (ret == -1 && 1210de531be4Sjg errno != EINVAL && errno != ENOTSUP) { 12117c478bd9Sstevel@tonic-gate bam_error(CHOWN_FAIL, tmpfile, strerror(errno)); 12127c478bd9Sstevel@tonic-gate return (BAM_ERROR); 12137c478bd9Sstevel@tonic-gate } 12147c478bd9Sstevel@tonic-gate 12157c478bd9Sstevel@tonic-gate 12167c478bd9Sstevel@tonic-gate /* 12177c478bd9Sstevel@tonic-gate * Do an atomic rename 12187c478bd9Sstevel@tonic-gate */ 12197c478bd9Sstevel@tonic-gate ret = rename(tmpfile, path); 1220963390b4Svikram INJECT_ERROR1("LIST2FILE_RENAME", ret = -1); 12217c478bd9Sstevel@tonic-gate if (ret != 0) { 12227c478bd9Sstevel@tonic-gate bam_error(RENAME_FAIL, path, strerror(errno)); 12237c478bd9Sstevel@tonic-gate return (BAM_ERROR); 12247c478bd9Sstevel@tonic-gate } 12257c478bd9Sstevel@tonic-gate 1226eb2bd662Svikram BAM_DPRINTF((D_WROTE_FILE, fcn, path)); 12277c478bd9Sstevel@tonic-gate return (BAM_SUCCESS); 12287c478bd9Sstevel@tonic-gate } 12297c478bd9Sstevel@tonic-gate 12307c478bd9Sstevel@tonic-gate /* 12317c478bd9Sstevel@tonic-gate * This function should always return 0 - since we want 12327c478bd9Sstevel@tonic-gate * to create stat data for *all* files in the list. 12337c478bd9Sstevel@tonic-gate */ 12347c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 12357c478bd9Sstevel@tonic-gate static int 12367c478bd9Sstevel@tonic-gate cmpstat( 12377c478bd9Sstevel@tonic-gate const char *file, 12387c478bd9Sstevel@tonic-gate const struct stat *stat, 12397c478bd9Sstevel@tonic-gate int flags, 12407c478bd9Sstevel@tonic-gate struct FTW *ftw) 12417c478bd9Sstevel@tonic-gate { 12427c478bd9Sstevel@tonic-gate uint_t sz; 12437c478bd9Sstevel@tonic-gate uint64_t *value; 12447c478bd9Sstevel@tonic-gate uint64_t filestat[2]; 12457c478bd9Sstevel@tonic-gate int error; 12467c478bd9Sstevel@tonic-gate 124758091fd8Ssetje struct safefile *safefilep; 124858091fd8Ssetje FILE *fp; 124958091fd8Ssetje 12507c478bd9Sstevel@tonic-gate /* 12517c478bd9Sstevel@tonic-gate * We only want regular files 12527c478bd9Sstevel@tonic-gate */ 12537c478bd9Sstevel@tonic-gate if (!S_ISREG(stat->st_mode)) 12547c478bd9Sstevel@tonic-gate return (0); 12557c478bd9Sstevel@tonic-gate 12567c478bd9Sstevel@tonic-gate /* 12577c478bd9Sstevel@tonic-gate * new_nvlp may be NULL if there were errors earlier 12587c478bd9Sstevel@tonic-gate * but this is not fatal to update determination. 12597c478bd9Sstevel@tonic-gate */ 12607c478bd9Sstevel@tonic-gate if (walk_arg.new_nvlp) { 12617c478bd9Sstevel@tonic-gate filestat[0] = stat->st_size; 12627c478bd9Sstevel@tonic-gate filestat[1] = stat->st_mtime; 12637c478bd9Sstevel@tonic-gate error = nvlist_add_uint64_array(walk_arg.new_nvlp, 12647c478bd9Sstevel@tonic-gate file + bam_rootlen, filestat, 2); 12657c478bd9Sstevel@tonic-gate if (error) 12667c478bd9Sstevel@tonic-gate bam_error(NVADD_FAIL, file, strerror(error)); 12677c478bd9Sstevel@tonic-gate } 12687c478bd9Sstevel@tonic-gate 12697c478bd9Sstevel@tonic-gate /* 12707c478bd9Sstevel@tonic-gate * The remaining steps are only required if we haven't made a 12717c478bd9Sstevel@tonic-gate * decision about update or if we are checking (-n) 12727c478bd9Sstevel@tonic-gate */ 12737c478bd9Sstevel@tonic-gate if (walk_arg.need_update && !bam_check) 12747c478bd9Sstevel@tonic-gate return (0); 12757c478bd9Sstevel@tonic-gate 12767c478bd9Sstevel@tonic-gate /* 1277d876c67dSjg * If we are invoked as part of system/filesystem/boot-archive, then 127858091fd8Ssetje * there are a number of things we should not worry about 12797c478bd9Sstevel@tonic-gate */ 128058091fd8Ssetje if (bam_smf_check) { 128158091fd8Ssetje /* ignore amd64 modules unless we are booted amd64. */ 128258091fd8Ssetje if (!is_amd64() && strstr(file, "/amd64/") != 0) 128358091fd8Ssetje return (0); 128458091fd8Ssetje 128558091fd8Ssetje /* read in list of safe files */ 128658091fd8Ssetje if (safefiles == NULL) 128758091fd8Ssetje if (fp = fopen("/boot/solaris/filelist.safe", "r")) { 128858091fd8Ssetje safefiles = s_calloc(1, 128958091fd8Ssetje sizeof (struct safefile)); 129058091fd8Ssetje safefilep = safefiles; 129158091fd8Ssetje safefilep->name = s_calloc(1, MAXPATHLEN + 129258091fd8Ssetje MAXNAMELEN); 129358091fd8Ssetje safefilep->next = NULL; 129458091fd8Ssetje while (s_fgets(safefilep->name, MAXPATHLEN + 129558091fd8Ssetje MAXNAMELEN, fp) != NULL) { 129658091fd8Ssetje safefilep->next = s_calloc(1, 129758091fd8Ssetje sizeof (struct safefile)); 129858091fd8Ssetje safefilep = safefilep->next; 129958091fd8Ssetje safefilep->name = s_calloc(1, 130058091fd8Ssetje MAXPATHLEN + MAXNAMELEN); 130158091fd8Ssetje safefilep->next = NULL; 130258091fd8Ssetje } 130358091fd8Ssetje (void) fclose(fp); 130458091fd8Ssetje } 130558091fd8Ssetje } 13067c478bd9Sstevel@tonic-gate 13077c478bd9Sstevel@tonic-gate /* 13087c478bd9Sstevel@tonic-gate * We need an update if file doesn't exist in old archive 13097c478bd9Sstevel@tonic-gate */ 13107c478bd9Sstevel@tonic-gate if (walk_arg.old_nvlp == NULL || 13117c478bd9Sstevel@tonic-gate nvlist_lookup_uint64_array(walk_arg.old_nvlp, 13127c478bd9Sstevel@tonic-gate file + bam_rootlen, &value, &sz) != 0) { 13137c478bd9Sstevel@tonic-gate if (bam_smf_check) /* ignore new during smf check */ 13147c478bd9Sstevel@tonic-gate return (0); 13157c478bd9Sstevel@tonic-gate walk_arg.need_update = 1; 13167c478bd9Sstevel@tonic-gate if (bam_verbose) 13177c478bd9Sstevel@tonic-gate bam_print(PARSEABLE_NEW_FILE, file); 13187c478bd9Sstevel@tonic-gate return (0); 13197c478bd9Sstevel@tonic-gate } 13207c478bd9Sstevel@tonic-gate 13217c478bd9Sstevel@tonic-gate /* 13227c478bd9Sstevel@tonic-gate * File exists in old archive. Check if file has changed 13237c478bd9Sstevel@tonic-gate */ 13247c478bd9Sstevel@tonic-gate assert(sz == 2); 13257c478bd9Sstevel@tonic-gate bcopy(value, filestat, sizeof (filestat)); 13267c478bd9Sstevel@tonic-gate 13277c478bd9Sstevel@tonic-gate if (filestat[0] != stat->st_size || 13287c478bd9Sstevel@tonic-gate filestat[1] != stat->st_mtime) { 13297c609327Ssetje if (bam_smf_check) { 13307c609327Ssetje safefilep = safefiles; 13317c609327Ssetje while (safefilep != NULL) { 13327c609327Ssetje if (strcmp(file + bam_rootlen, 13337c609327Ssetje safefilep->name) == 0) { 13347c609327Ssetje (void) creat(NEED_UPDATE_FILE, 0644); 13357c609327Ssetje return (0); 13367c609327Ssetje } 13377c609327Ssetje safefilep = safefilep->next; 13387c609327Ssetje } 13397c609327Ssetje } 13407c478bd9Sstevel@tonic-gate walk_arg.need_update = 1; 13417c478bd9Sstevel@tonic-gate if (bam_verbose) 13427c478bd9Sstevel@tonic-gate if (bam_smf_check) 13437c478bd9Sstevel@tonic-gate bam_print(" %s\n", file); 13447c478bd9Sstevel@tonic-gate else 13457c478bd9Sstevel@tonic-gate bam_print(PARSEABLE_OUT_DATE, file); 13467c478bd9Sstevel@tonic-gate } 13477c478bd9Sstevel@tonic-gate 13487c478bd9Sstevel@tonic-gate return (0); 13497c478bd9Sstevel@tonic-gate } 13507c478bd9Sstevel@tonic-gate 13517c478bd9Sstevel@tonic-gate /* 13527c478bd9Sstevel@tonic-gate * Check flags and presence of required files. 13537c478bd9Sstevel@tonic-gate * The force flag and/or absence of files should 13547c478bd9Sstevel@tonic-gate * trigger an update. 13557c478bd9Sstevel@tonic-gate * Suppress stdout output if check (-n) option is set 13567c478bd9Sstevel@tonic-gate * (as -n should only produce parseable output.) 13577c478bd9Sstevel@tonic-gate */ 13587c478bd9Sstevel@tonic-gate static void 13597c478bd9Sstevel@tonic-gate check_flags_and_files(char *root) 13607c478bd9Sstevel@tonic-gate { 13617c478bd9Sstevel@tonic-gate char path[PATH_MAX]; 13627c478bd9Sstevel@tonic-gate struct stat sb; 13637c478bd9Sstevel@tonic-gate 13647c478bd9Sstevel@tonic-gate /* 13657c478bd9Sstevel@tonic-gate * if force, create archive unconditionally 13667c478bd9Sstevel@tonic-gate */ 13677c478bd9Sstevel@tonic-gate if (bam_force) { 13687c478bd9Sstevel@tonic-gate walk_arg.need_update = 1; 13697c478bd9Sstevel@tonic-gate if (bam_verbose && !bam_check) 13707c478bd9Sstevel@tonic-gate bam_print(UPDATE_FORCE); 13717c478bd9Sstevel@tonic-gate return; 13727c478bd9Sstevel@tonic-gate } 13737c478bd9Sstevel@tonic-gate 13747c478bd9Sstevel@tonic-gate /* 13757c478bd9Sstevel@tonic-gate * If archive is missing, create archive 13767c478bd9Sstevel@tonic-gate */ 137779755401Ssetje if (is_sparc()) { 137879755401Ssetje (void) snprintf(path, sizeof (path), "%s%s%s%s", root, 137979755401Ssetje ARCHIVE_PREFIX, get_machine(), ARCHIVE_SUFFIX); 1380d876c67dSjg } else { 1381986fd29aSsetje if (bam_direct == BAM_DIRECT_DBOOT) { 1382986fd29aSsetje (void) snprintf(path, sizeof (path), "%s%s", root, 1383986fd29aSsetje DIRECT_BOOT_ARCHIVE_64); 1384986fd29aSsetje if (stat(path, &sb) != 0) { 1385986fd29aSsetje if (bam_verbose && !bam_check) 1386986fd29aSsetje bam_print(UPDATE_ARCH_MISS, path); 1387986fd29aSsetje walk_arg.need_update = 1; 1388986fd29aSsetje return; 1389986fd29aSsetje } 1390986fd29aSsetje } 1391986fd29aSsetje (void) snprintf(path, sizeof (path), "%s%s", root, 1392986fd29aSsetje DIRECT_BOOT_ARCHIVE_32); 1393986fd29aSsetje } 1394986fd29aSsetje 13957c478bd9Sstevel@tonic-gate if (stat(path, &sb) != 0) { 13967c478bd9Sstevel@tonic-gate if (bam_verbose && !bam_check) 13977c478bd9Sstevel@tonic-gate bam_print(UPDATE_ARCH_MISS, path); 13987c478bd9Sstevel@tonic-gate walk_arg.need_update = 1; 13997c478bd9Sstevel@tonic-gate return; 14007c478bd9Sstevel@tonic-gate } 14017c478bd9Sstevel@tonic-gate } 14027c478bd9Sstevel@tonic-gate 14037c478bd9Sstevel@tonic-gate static error_t 14047c478bd9Sstevel@tonic-gate read_one_list(char *root, filelist_t *flistp, char *filelist) 14057c478bd9Sstevel@tonic-gate { 14067c478bd9Sstevel@tonic-gate char path[PATH_MAX]; 14077c478bd9Sstevel@tonic-gate FILE *fp; 14087c478bd9Sstevel@tonic-gate char buf[BAM_MAXLINE]; 1409eb2bd662Svikram const char *fcn = "read_one_list()"; 14107c478bd9Sstevel@tonic-gate 14117c478bd9Sstevel@tonic-gate (void) snprintf(path, sizeof (path), "%s%s", root, filelist); 14127c478bd9Sstevel@tonic-gate 14137c478bd9Sstevel@tonic-gate fp = fopen(path, "r"); 14147c478bd9Sstevel@tonic-gate if (fp == NULL) { 1415eb2bd662Svikram BAM_DPRINTF((D_FLIST_FAIL, fcn, path, strerror(errno))); 14167c478bd9Sstevel@tonic-gate return (BAM_ERROR); 14177c478bd9Sstevel@tonic-gate } 14187c478bd9Sstevel@tonic-gate while (s_fgets(buf, sizeof (buf), fp) != NULL) { 1419b610f78eSvikram /* skip blank lines */ 1420b610f78eSvikram if (strspn(buf, " \t") == strlen(buf)) 1421b610f78eSvikram continue; 14227c478bd9Sstevel@tonic-gate append_to_flist(flistp, buf); 14237c478bd9Sstevel@tonic-gate } 14247c478bd9Sstevel@tonic-gate if (fclose(fp) != 0) { 14257c478bd9Sstevel@tonic-gate bam_error(CLOSE_FAIL, path, strerror(errno)); 14267c478bd9Sstevel@tonic-gate return (BAM_ERROR); 14277c478bd9Sstevel@tonic-gate } 14287c478bd9Sstevel@tonic-gate return (BAM_SUCCESS); 14297c478bd9Sstevel@tonic-gate } 14307c478bd9Sstevel@tonic-gate 14317c478bd9Sstevel@tonic-gate static error_t 14327c478bd9Sstevel@tonic-gate read_list(char *root, filelist_t *flistp) 14337c478bd9Sstevel@tonic-gate { 1434986fd29aSsetje char path[PATH_MAX]; 1435986fd29aSsetje char cmd[PATH_MAX]; 1436986fd29aSsetje struct stat sb; 1437986fd29aSsetje int n, rval; 1438eb2bd662Svikram const char *fcn = "read_list()"; 14397c478bd9Sstevel@tonic-gate 14407c478bd9Sstevel@tonic-gate flistp->head = flistp->tail = NULL; 14417c478bd9Sstevel@tonic-gate 14427c478bd9Sstevel@tonic-gate /* 1443986fd29aSsetje * build and check path to extract_boot_filelist.ksh 14447c478bd9Sstevel@tonic-gate */ 1445986fd29aSsetje n = snprintf(path, sizeof (path), "%s%s", root, EXTRACT_BOOT_FILELIST); 1446986fd29aSsetje if (n >= sizeof (path)) { 1447986fd29aSsetje bam_error(NO_FLIST); 1448986fd29aSsetje return (BAM_ERROR); 1449986fd29aSsetje } 1450986fd29aSsetje 1451986fd29aSsetje /* 1452986fd29aSsetje * If extract_boot_filelist is present, exec it, otherwise read 1453986fd29aSsetje * the filelists directly, for compatibility with older images. 1454986fd29aSsetje */ 1455986fd29aSsetje if (stat(path, &sb) == 0) { 1456986fd29aSsetje /* 1457986fd29aSsetje * build arguments to exec extract_boot_filelist.ksh 1458986fd29aSsetje */ 1459d876c67dSjg char *rootarg, *platarg; 1460d876c67dSjg int platarglen = 1, rootarglen = 1; 1461d876c67dSjg if (strlen(root) > 1) 1462d876c67dSjg rootarglen += strlen(root) + strlen("-R "); 1463d876c67dSjg if (bam_alt_platform) 1464d876c67dSjg platarglen += strlen(bam_platform) + strlen("-p "); 1465d876c67dSjg platarg = s_calloc(1, platarglen); 1466d876c67dSjg rootarg = s_calloc(1, rootarglen); 1467d876c67dSjg *platarg = 0; 1468d876c67dSjg *rootarg = 0; 1469d876c67dSjg 1470986fd29aSsetje if (strlen(root) > 1) { 1471d876c67dSjg (void) snprintf(rootarg, rootarglen, 1472d876c67dSjg "-R %s", root); 1473986fd29aSsetje } 1474d876c67dSjg if (bam_alt_platform) { 1475d876c67dSjg (void) snprintf(platarg, platarglen, 1476d876c67dSjg "-p %s", bam_platform); 1477d876c67dSjg } 1478d876c67dSjg n = snprintf(cmd, sizeof (cmd), "%s %s %s /%s /%s", 1479d876c67dSjg path, rootarg, platarg, BOOT_FILE_LIST, ETC_FILE_LIST); 1480d876c67dSjg free(platarg); 1481d876c67dSjg free(rootarg); 1482986fd29aSsetje if (n >= sizeof (cmd)) { 1483986fd29aSsetje bam_error(NO_FLIST); 1484986fd29aSsetje return (BAM_ERROR); 1485986fd29aSsetje } 1486986fd29aSsetje if (exec_cmd(cmd, flistp) != 0) { 1487eb2bd662Svikram BAM_DPRINTF((D_FLIST_FAIL, fcn, path, strerror(errno))); 1488986fd29aSsetje return (BAM_ERROR); 1489986fd29aSsetje } 1490986fd29aSsetje } else { 1491986fd29aSsetje /* 1492986fd29aSsetje * Read current lists of files - only the first is mandatory 1493986fd29aSsetje */ 1494986fd29aSsetje rval = read_one_list(root, flistp, BOOT_FILE_LIST); 1495986fd29aSsetje if (rval != BAM_SUCCESS) 1496986fd29aSsetje return (rval); 1497986fd29aSsetje (void) read_one_list(root, flistp, ETC_FILE_LIST); 1498986fd29aSsetje } 14997c478bd9Sstevel@tonic-gate 15007c478bd9Sstevel@tonic-gate if (flistp->head == NULL) { 15017c478bd9Sstevel@tonic-gate bam_error(NO_FLIST); 15027c478bd9Sstevel@tonic-gate return (BAM_ERROR); 15037c478bd9Sstevel@tonic-gate } 15047c478bd9Sstevel@tonic-gate 15057c478bd9Sstevel@tonic-gate return (BAM_SUCCESS); 15067c478bd9Sstevel@tonic-gate } 15077c478bd9Sstevel@tonic-gate 15087c478bd9Sstevel@tonic-gate static void 15097c478bd9Sstevel@tonic-gate getoldstat(char *root) 15107c478bd9Sstevel@tonic-gate { 15117c478bd9Sstevel@tonic-gate char path[PATH_MAX]; 15127c478bd9Sstevel@tonic-gate int fd, error; 15137c478bd9Sstevel@tonic-gate struct stat sb; 15147c478bd9Sstevel@tonic-gate char *ostat; 15157c478bd9Sstevel@tonic-gate 15167c478bd9Sstevel@tonic-gate (void) snprintf(path, sizeof (path), "%s%s", root, FILE_STAT); 15177c478bd9Sstevel@tonic-gate fd = open(path, O_RDONLY); 15187c478bd9Sstevel@tonic-gate if (fd == -1) { 15197c478bd9Sstevel@tonic-gate if (bam_verbose) 15207c478bd9Sstevel@tonic-gate bam_print(OPEN_FAIL, path, strerror(errno)); 15217c478bd9Sstevel@tonic-gate walk_arg.need_update = 1; 15227c478bd9Sstevel@tonic-gate return; 15237c478bd9Sstevel@tonic-gate } 15247c478bd9Sstevel@tonic-gate 15257c478bd9Sstevel@tonic-gate if (fstat(fd, &sb) != 0) { 15267c478bd9Sstevel@tonic-gate bam_error(STAT_FAIL, path, strerror(errno)); 15277c478bd9Sstevel@tonic-gate (void) close(fd); 15287c478bd9Sstevel@tonic-gate walk_arg.need_update = 1; 15297c478bd9Sstevel@tonic-gate return; 15307c478bd9Sstevel@tonic-gate } 15317c478bd9Sstevel@tonic-gate 15327c478bd9Sstevel@tonic-gate ostat = s_calloc(1, sb.st_size); 15337c478bd9Sstevel@tonic-gate 15347c478bd9Sstevel@tonic-gate if (read(fd, ostat, sb.st_size) != sb.st_size) { 15357c478bd9Sstevel@tonic-gate bam_error(READ_FAIL, path, strerror(errno)); 15367c478bd9Sstevel@tonic-gate (void) close(fd); 15377c478bd9Sstevel@tonic-gate free(ostat); 15387c478bd9Sstevel@tonic-gate walk_arg.need_update = 1; 15397c478bd9Sstevel@tonic-gate return; 15407c478bd9Sstevel@tonic-gate } 15417c478bd9Sstevel@tonic-gate 15427c478bd9Sstevel@tonic-gate (void) close(fd); 15437c478bd9Sstevel@tonic-gate 15447c478bd9Sstevel@tonic-gate walk_arg.old_nvlp = NULL; 15457c478bd9Sstevel@tonic-gate error = nvlist_unpack(ostat, sb.st_size, &walk_arg.old_nvlp, 0); 15467c478bd9Sstevel@tonic-gate 15477c478bd9Sstevel@tonic-gate free(ostat); 15487c478bd9Sstevel@tonic-gate 15497c478bd9Sstevel@tonic-gate if (error) { 15507c478bd9Sstevel@tonic-gate bam_error(UNPACK_FAIL, path, strerror(error)); 15517c478bd9Sstevel@tonic-gate walk_arg.old_nvlp = NULL; 15527c478bd9Sstevel@tonic-gate walk_arg.need_update = 1; 15537c478bd9Sstevel@tonic-gate return; 15547c478bd9Sstevel@tonic-gate } 15557c478bd9Sstevel@tonic-gate } 15567c478bd9Sstevel@tonic-gate 1557a28d77b8Svikram /* 1558a28d77b8Svikram * Checks if a file in the current (old) archive has 1559a28d77b8Svikram * been deleted from the root filesystem. This is needed for 1560a28d77b8Svikram * software like Trusted Extensions (TX) that switch early 1561a28d77b8Svikram * in boot based on presence/absence of a kernel module. 1562a28d77b8Svikram */ 1563a28d77b8Svikram static void 1564a28d77b8Svikram check4stale(char *root) 1565a28d77b8Svikram { 1566a28d77b8Svikram nvpair_t *nvp; 1567a28d77b8Svikram nvlist_t *nvlp; 1568a28d77b8Svikram char *file; 1569a28d77b8Svikram char path[PATH_MAX]; 1570a28d77b8Svikram struct stat sb; 1571a28d77b8Svikram 1572a28d77b8Svikram /* 1573a28d77b8Svikram * Skip stale file check during smf check 1574a28d77b8Svikram */ 1575a28d77b8Svikram if (bam_smf_check) 1576a28d77b8Svikram return; 1577a28d77b8Svikram 1578a28d77b8Svikram /* Nothing to do if no old stats */ 1579a28d77b8Svikram if ((nvlp = walk_arg.old_nvlp) == NULL) 1580a28d77b8Svikram return; 1581a28d77b8Svikram 1582a28d77b8Svikram for (nvp = nvlist_next_nvpair(nvlp, NULL); nvp; 1583a28d77b8Svikram nvp = nvlist_next_nvpair(nvlp, nvp)) { 1584a28d77b8Svikram file = nvpair_name(nvp); 1585a28d77b8Svikram if (file == NULL) 1586a28d77b8Svikram continue; 1587a28d77b8Svikram (void) snprintf(path, sizeof (path), "%s/%s", 1588a28d77b8Svikram root, file); 1589a28d77b8Svikram if (stat(path, &sb) == -1) { 1590a28d77b8Svikram walk_arg.need_update = 1; 1591a28d77b8Svikram if (bam_verbose) 1592a28d77b8Svikram bam_print(PARSEABLE_STALE_FILE, path); 1593a28d77b8Svikram } 1594a28d77b8Svikram } 1595a28d77b8Svikram } 1596a28d77b8Svikram 15977c478bd9Sstevel@tonic-gate static void 15987c478bd9Sstevel@tonic-gate create_newstat(void) 15997c478bd9Sstevel@tonic-gate { 16007c478bd9Sstevel@tonic-gate int error; 16017c478bd9Sstevel@tonic-gate 16027c478bd9Sstevel@tonic-gate error = nvlist_alloc(&walk_arg.new_nvlp, NV_UNIQUE_NAME, 0); 16037c478bd9Sstevel@tonic-gate if (error) { 16047c478bd9Sstevel@tonic-gate /* 16057c478bd9Sstevel@tonic-gate * Not fatal - we can still create archive 16067c478bd9Sstevel@tonic-gate */ 16077c478bd9Sstevel@tonic-gate walk_arg.new_nvlp = NULL; 16087c478bd9Sstevel@tonic-gate bam_error(NVALLOC_FAIL, strerror(error)); 16097c478bd9Sstevel@tonic-gate } 16107c478bd9Sstevel@tonic-gate } 16117c478bd9Sstevel@tonic-gate 16127c478bd9Sstevel@tonic-gate static void 16137c478bd9Sstevel@tonic-gate walk_list(char *root, filelist_t *flistp) 16147c478bd9Sstevel@tonic-gate { 16157c478bd9Sstevel@tonic-gate char path[PATH_MAX]; 16167c478bd9Sstevel@tonic-gate line_t *lp; 16177c478bd9Sstevel@tonic-gate 16187c478bd9Sstevel@tonic-gate for (lp = flistp->head; lp; lp = lp->next) { 1619986fd29aSsetje /* 1620986fd29aSsetje * Don't follow symlinks. A symlink must refer to 1621986fd29aSsetje * a file that would appear in the archive through 1622986fd29aSsetje * a direct reference. This matches the archive 1623986fd29aSsetje * construction behavior. 1624986fd29aSsetje */ 16257c478bd9Sstevel@tonic-gate (void) snprintf(path, sizeof (path), "%s%s", root, lp->line); 1626986fd29aSsetje if (nftw(path, cmpstat, 20, FTW_PHYS) == -1) { 16277c478bd9Sstevel@tonic-gate /* 16287c478bd9Sstevel@tonic-gate * Some files may not exist. 16297c478bd9Sstevel@tonic-gate * For example: etc/rtc_config on a x86 diskless system 16307c478bd9Sstevel@tonic-gate * Emit verbose message only 16317c478bd9Sstevel@tonic-gate */ 16327c478bd9Sstevel@tonic-gate if (bam_verbose) 16337c478bd9Sstevel@tonic-gate bam_print(NFTW_FAIL, path, strerror(errno)); 16347c478bd9Sstevel@tonic-gate } 16357c478bd9Sstevel@tonic-gate } 16367c478bd9Sstevel@tonic-gate } 16377c478bd9Sstevel@tonic-gate 16387c478bd9Sstevel@tonic-gate static void 16397c478bd9Sstevel@tonic-gate savenew(char *root) 16407c478bd9Sstevel@tonic-gate { 16417c478bd9Sstevel@tonic-gate char path[PATH_MAX]; 16427c478bd9Sstevel@tonic-gate char path2[PATH_MAX]; 16437c478bd9Sstevel@tonic-gate size_t sz; 16447c478bd9Sstevel@tonic-gate char *nstat; 16457c478bd9Sstevel@tonic-gate int fd, wrote, error; 16467c478bd9Sstevel@tonic-gate 16477c478bd9Sstevel@tonic-gate nstat = NULL; 16487c478bd9Sstevel@tonic-gate sz = 0; 16497c478bd9Sstevel@tonic-gate error = nvlist_pack(walk_arg.new_nvlp, &nstat, &sz, 16507c478bd9Sstevel@tonic-gate NV_ENCODE_XDR, 0); 16517c478bd9Sstevel@tonic-gate if (error) { 16527c478bd9Sstevel@tonic-gate bam_error(PACK_FAIL, strerror(error)); 16537c478bd9Sstevel@tonic-gate return; 16547c478bd9Sstevel@tonic-gate } 16557c478bd9Sstevel@tonic-gate 16567c478bd9Sstevel@tonic-gate (void) snprintf(path, sizeof (path), "%s%s", root, FILE_STAT_TMP); 16577c478bd9Sstevel@tonic-gate fd = open(path, O_RDWR|O_CREAT|O_TRUNC, FILE_STAT_MODE); 16587c478bd9Sstevel@tonic-gate if (fd == -1) { 16597c478bd9Sstevel@tonic-gate bam_error(OPEN_FAIL, path, strerror(errno)); 16607c478bd9Sstevel@tonic-gate free(nstat); 16617c478bd9Sstevel@tonic-gate return; 16627c478bd9Sstevel@tonic-gate } 16637c478bd9Sstevel@tonic-gate wrote = write(fd, nstat, sz); 16647c478bd9Sstevel@tonic-gate if (wrote != sz) { 16657c478bd9Sstevel@tonic-gate bam_error(WRITE_FAIL, path, strerror(errno)); 16667c478bd9Sstevel@tonic-gate (void) close(fd); 16677c478bd9Sstevel@tonic-gate free(nstat); 16687c478bd9Sstevel@tonic-gate return; 16697c478bd9Sstevel@tonic-gate } 16707c478bd9Sstevel@tonic-gate (void) close(fd); 16717c478bd9Sstevel@tonic-gate free(nstat); 16727c478bd9Sstevel@tonic-gate 16737c478bd9Sstevel@tonic-gate (void) snprintf(path2, sizeof (path2), "%s%s", root, FILE_STAT); 16747c478bd9Sstevel@tonic-gate if (rename(path, path2) != 0) { 16757c478bd9Sstevel@tonic-gate bam_error(RENAME_FAIL, path2, strerror(errno)); 16767c478bd9Sstevel@tonic-gate } 16777c478bd9Sstevel@tonic-gate } 16787c478bd9Sstevel@tonic-gate 16797c478bd9Sstevel@tonic-gate static void 16807c478bd9Sstevel@tonic-gate clear_walk_args(void) 16817c478bd9Sstevel@tonic-gate { 16827c478bd9Sstevel@tonic-gate if (walk_arg.old_nvlp) 16837c478bd9Sstevel@tonic-gate nvlist_free(walk_arg.old_nvlp); 16847c478bd9Sstevel@tonic-gate if (walk_arg.new_nvlp) 16857c478bd9Sstevel@tonic-gate nvlist_free(walk_arg.new_nvlp); 16867c478bd9Sstevel@tonic-gate walk_arg.need_update = 0; 16877c478bd9Sstevel@tonic-gate walk_arg.old_nvlp = NULL; 16887c478bd9Sstevel@tonic-gate walk_arg.new_nvlp = NULL; 16897c478bd9Sstevel@tonic-gate } 16907c478bd9Sstevel@tonic-gate 16917c478bd9Sstevel@tonic-gate /* 16927c478bd9Sstevel@tonic-gate * Returns: 16937c478bd9Sstevel@tonic-gate * 0 - no update necessary 16947c478bd9Sstevel@tonic-gate * 1 - update required. 16957c478bd9Sstevel@tonic-gate * BAM_ERROR (-1) - An error occurred 16967c478bd9Sstevel@tonic-gate * 16977c478bd9Sstevel@tonic-gate * Special handling for check (-n): 16987c478bd9Sstevel@tonic-gate * ================================ 16997c478bd9Sstevel@tonic-gate * The check (-n) option produces parseable output. 17007c478bd9Sstevel@tonic-gate * To do this, we suppress all stdout messages unrelated 17017c478bd9Sstevel@tonic-gate * to out of sync files. 17027c478bd9Sstevel@tonic-gate * All stderr messages are still printed though. 17037c478bd9Sstevel@tonic-gate * 17047c478bd9Sstevel@tonic-gate */ 17057c478bd9Sstevel@tonic-gate static int 17067c478bd9Sstevel@tonic-gate update_required(char *root) 17077c478bd9Sstevel@tonic-gate { 17087c478bd9Sstevel@tonic-gate struct stat sb; 17097c478bd9Sstevel@tonic-gate char path[PATH_MAX]; 17107c478bd9Sstevel@tonic-gate filelist_t flist; 17117c478bd9Sstevel@tonic-gate filelist_t *flistp = &flist; 17127c478bd9Sstevel@tonic-gate int need_update; 17137c478bd9Sstevel@tonic-gate 17147c478bd9Sstevel@tonic-gate flistp->head = flistp->tail = NULL; 17157c478bd9Sstevel@tonic-gate 17167c478bd9Sstevel@tonic-gate walk_arg.need_update = 0; 17177c478bd9Sstevel@tonic-gate 17187c478bd9Sstevel@tonic-gate /* 17197c478bd9Sstevel@tonic-gate * Without consulting stat data, check if we need update 17207c478bd9Sstevel@tonic-gate */ 17217c478bd9Sstevel@tonic-gate check_flags_and_files(root); 17227c478bd9Sstevel@tonic-gate 17237c478bd9Sstevel@tonic-gate /* 17247c478bd9Sstevel@tonic-gate * In certain deployment scenarios, filestat may not 17257c478bd9Sstevel@tonic-gate * exist. Ignore it during boot-archive SMF check. 17267c478bd9Sstevel@tonic-gate */ 17277c478bd9Sstevel@tonic-gate if (bam_smf_check) { 17287c478bd9Sstevel@tonic-gate (void) snprintf(path, sizeof (path), "%s%s", root, FILE_STAT); 17297c478bd9Sstevel@tonic-gate if (stat(path, &sb) != 0) 17307c478bd9Sstevel@tonic-gate return (0); 17317c478bd9Sstevel@tonic-gate } 17327c478bd9Sstevel@tonic-gate 17337c478bd9Sstevel@tonic-gate /* 17347c478bd9Sstevel@tonic-gate * consult stat data only if we haven't made a decision 17357c478bd9Sstevel@tonic-gate * about update. If checking (-n) however, we always 17367c478bd9Sstevel@tonic-gate * need stat data (since we want to compare old and new) 17377c478bd9Sstevel@tonic-gate */ 17387c478bd9Sstevel@tonic-gate if (!walk_arg.need_update || bam_check) 17397c478bd9Sstevel@tonic-gate getoldstat(root); 17407c478bd9Sstevel@tonic-gate 1741a28d77b8Svikram /* 1742a28d77b8Svikram * Check if the archive contains files that are no longer 1743a28d77b8Svikram * present on the root filesystem. 1744a28d77b8Svikram */ 1745a28d77b8Svikram if (!walk_arg.need_update || bam_check) 1746a28d77b8Svikram check4stale(root); 1747a28d77b8Svikram 17487c478bd9Sstevel@tonic-gate /* 17497c478bd9Sstevel@tonic-gate * read list of files 17507c478bd9Sstevel@tonic-gate */ 17517c478bd9Sstevel@tonic-gate if (read_list(root, flistp) != BAM_SUCCESS) { 17527c478bd9Sstevel@tonic-gate clear_walk_args(); 17537c478bd9Sstevel@tonic-gate return (BAM_ERROR); 17547c478bd9Sstevel@tonic-gate } 17557c478bd9Sstevel@tonic-gate 17567c478bd9Sstevel@tonic-gate assert(flistp->head && flistp->tail); 17577c478bd9Sstevel@tonic-gate 17587c478bd9Sstevel@tonic-gate /* 17597c478bd9Sstevel@tonic-gate * At this point either the update is required 17607c478bd9Sstevel@tonic-gate * or the decision is pending. In either case 17617c478bd9Sstevel@tonic-gate * we need to create new stat nvlist 17627c478bd9Sstevel@tonic-gate */ 17637c478bd9Sstevel@tonic-gate create_newstat(); 17647c478bd9Sstevel@tonic-gate 17657c478bd9Sstevel@tonic-gate /* 17667c478bd9Sstevel@tonic-gate * This walk does 2 things: 17677c478bd9Sstevel@tonic-gate * - gets new stat data for every file 17687c478bd9Sstevel@tonic-gate * - (optional) compare old and new stat data 17697c478bd9Sstevel@tonic-gate */ 17707c478bd9Sstevel@tonic-gate walk_list(root, &flist); 17717c478bd9Sstevel@tonic-gate 17727c478bd9Sstevel@tonic-gate /* done with the file list */ 17737c478bd9Sstevel@tonic-gate filelist_free(flistp); 17747c478bd9Sstevel@tonic-gate 17757c478bd9Sstevel@tonic-gate /* 17767c478bd9Sstevel@tonic-gate * if we didn't succeed in creating new stat data above 17777c478bd9Sstevel@tonic-gate * just return result of update check so that archive is built. 17787c478bd9Sstevel@tonic-gate */ 17797c478bd9Sstevel@tonic-gate if (walk_arg.new_nvlp == NULL) { 17807c478bd9Sstevel@tonic-gate bam_error(NO_NEW_STAT); 17817c478bd9Sstevel@tonic-gate need_update = walk_arg.need_update; 17827c478bd9Sstevel@tonic-gate clear_walk_args(); 17837c478bd9Sstevel@tonic-gate return (need_update ? 1 : 0); 17847c478bd9Sstevel@tonic-gate } 17857c478bd9Sstevel@tonic-gate 17867c478bd9Sstevel@tonic-gate 17877c478bd9Sstevel@tonic-gate /* 17887c478bd9Sstevel@tonic-gate * If no update required, discard newstat 17897c478bd9Sstevel@tonic-gate */ 17907c478bd9Sstevel@tonic-gate if (!walk_arg.need_update) { 17917c478bd9Sstevel@tonic-gate clear_walk_args(); 17927c478bd9Sstevel@tonic-gate return (0); 17937c478bd9Sstevel@tonic-gate } 17947c478bd9Sstevel@tonic-gate 17957c478bd9Sstevel@tonic-gate return (1); 17967c478bd9Sstevel@tonic-gate } 17977c478bd9Sstevel@tonic-gate 17987c478bd9Sstevel@tonic-gate static error_t 17997c478bd9Sstevel@tonic-gate create_ramdisk(char *root) 18007c478bd9Sstevel@tonic-gate { 18017c478bd9Sstevel@tonic-gate char *cmdline, path[PATH_MAX]; 18027c478bd9Sstevel@tonic-gate size_t len; 18037c478bd9Sstevel@tonic-gate struct stat sb; 18047c478bd9Sstevel@tonic-gate 18057c478bd9Sstevel@tonic-gate /* 18067c478bd9Sstevel@tonic-gate * Setup command args for create_ramdisk.ksh 18077c478bd9Sstevel@tonic-gate */ 1808986fd29aSsetje (void) snprintf(path, sizeof (path), "%s/%s", root, CREATE_RAMDISK); 18097c478bd9Sstevel@tonic-gate if (stat(path, &sb) != 0) { 18107c478bd9Sstevel@tonic-gate bam_error(ARCH_EXEC_MISS, path, strerror(errno)); 18117c478bd9Sstevel@tonic-gate return (BAM_ERROR); 18127c478bd9Sstevel@tonic-gate } 18137c478bd9Sstevel@tonic-gate 18147c478bd9Sstevel@tonic-gate len = strlen(path) + strlen(root) + 10; /* room for space + -R */ 1815d876c67dSjg if (bam_alt_platform) 1816d876c67dSjg len += strlen(bam_platform) + strlen("-p "); 18177c478bd9Sstevel@tonic-gate cmdline = s_calloc(1, len); 18187c478bd9Sstevel@tonic-gate 1819d876c67dSjg if (bam_alt_platform) { 1820d876c67dSjg assert(strlen(root) > 1); 1821d876c67dSjg (void) snprintf(cmdline, len, "%s -p %s -R %s", 1822d876c67dSjg path, bam_platform, root); 1823d876c67dSjg /* chop off / at the end */ 1824d876c67dSjg cmdline[strlen(cmdline) - 1] = '\0'; 1825d876c67dSjg } else if (strlen(root) > 1) { 18267c478bd9Sstevel@tonic-gate (void) snprintf(cmdline, len, "%s -R %s", path, root); 18277c478bd9Sstevel@tonic-gate /* chop off / at the end */ 18287c478bd9Sstevel@tonic-gate cmdline[strlen(cmdline) - 1] = '\0'; 18297c478bd9Sstevel@tonic-gate } else 18307c478bd9Sstevel@tonic-gate (void) snprintf(cmdline, len, "%s", path); 18317c478bd9Sstevel@tonic-gate 1832986fd29aSsetje if (exec_cmd(cmdline, NULL) != 0) { 18337c478bd9Sstevel@tonic-gate bam_error(ARCHIVE_FAIL, cmdline); 18347c478bd9Sstevel@tonic-gate free(cmdline); 18357c478bd9Sstevel@tonic-gate return (BAM_ERROR); 18367c478bd9Sstevel@tonic-gate } 18377c478bd9Sstevel@tonic-gate free(cmdline); 18387c478bd9Sstevel@tonic-gate 18397c478bd9Sstevel@tonic-gate /* 1840986fd29aSsetje * The existence of the expected archives used to be 1841986fd29aSsetje * verified here. This check is done in create_ramdisk as 1842986fd29aSsetje * it needs to be in sync with the altroot operated upon. 18437c478bd9Sstevel@tonic-gate */ 18447c478bd9Sstevel@tonic-gate 18457c478bd9Sstevel@tonic-gate return (BAM_SUCCESS); 18467c478bd9Sstevel@tonic-gate } 18477c478bd9Sstevel@tonic-gate 18487c478bd9Sstevel@tonic-gate /* 18497c478bd9Sstevel@tonic-gate * Checks if target filesystem is on a ramdisk 18507c478bd9Sstevel@tonic-gate * 1 - is miniroot 18517c478bd9Sstevel@tonic-gate * 0 - is not 18527c478bd9Sstevel@tonic-gate * When in doubt assume it is not a ramdisk. 18537c478bd9Sstevel@tonic-gate */ 18547c478bd9Sstevel@tonic-gate static int 18557c478bd9Sstevel@tonic-gate is_ramdisk(char *root) 18567c478bd9Sstevel@tonic-gate { 18577c478bd9Sstevel@tonic-gate struct extmnttab mnt; 18587c478bd9Sstevel@tonic-gate FILE *fp; 18597c478bd9Sstevel@tonic-gate int found; 1860b610f78eSvikram char mntpt[PATH_MAX]; 1861b610f78eSvikram char *cp; 18627c478bd9Sstevel@tonic-gate 18637c478bd9Sstevel@tonic-gate /* 18647c478bd9Sstevel@tonic-gate * There are 3 situations where creating archive is 18657c478bd9Sstevel@tonic-gate * of dubious value: 1866b610f78eSvikram * - create boot_archive on a lofi-mounted boot_archive 18677c478bd9Sstevel@tonic-gate * - create it on a ramdisk which is the root filesystem 18687c478bd9Sstevel@tonic-gate * - create it on a ramdisk mounted somewhere else 18697c478bd9Sstevel@tonic-gate * The first is not easy to detect and checking for it is not 18707c478bd9Sstevel@tonic-gate * worth it. 18717c478bd9Sstevel@tonic-gate * The other two conditions are handled here 18727c478bd9Sstevel@tonic-gate */ 18737c478bd9Sstevel@tonic-gate 18747c478bd9Sstevel@tonic-gate fp = fopen(MNTTAB, "r"); 18757c478bd9Sstevel@tonic-gate if (fp == NULL) { 18767c478bd9Sstevel@tonic-gate bam_error(OPEN_FAIL, MNTTAB, strerror(errno)); 18777c478bd9Sstevel@tonic-gate return (0); 18787c478bd9Sstevel@tonic-gate } 18797c478bd9Sstevel@tonic-gate 18807c478bd9Sstevel@tonic-gate resetmnttab(fp); 18817c478bd9Sstevel@tonic-gate 1882b610f78eSvikram /* 1883b610f78eSvikram * Remove any trailing / from the mount point 1884b610f78eSvikram */ 1885b610f78eSvikram (void) strlcpy(mntpt, root, sizeof (mntpt)); 1886b610f78eSvikram if (strcmp(root, "/") != 0) { 1887b610f78eSvikram cp = mntpt + strlen(mntpt) - 1; 1888b610f78eSvikram if (*cp == '/') 1889b610f78eSvikram *cp = '\0'; 1890b610f78eSvikram } 18917c478bd9Sstevel@tonic-gate found = 0; 18927c478bd9Sstevel@tonic-gate while (getextmntent(fp, &mnt, sizeof (mnt)) == 0) { 1893b610f78eSvikram if (strcmp(mnt.mnt_mountp, mntpt) == 0) { 18947c478bd9Sstevel@tonic-gate found = 1; 18957c478bd9Sstevel@tonic-gate break; 18967c478bd9Sstevel@tonic-gate } 18977c478bd9Sstevel@tonic-gate } 18987c478bd9Sstevel@tonic-gate 18997c478bd9Sstevel@tonic-gate if (!found) { 19007c478bd9Sstevel@tonic-gate if (bam_verbose) 1901b610f78eSvikram bam_error(NOT_IN_MNTTAB, mntpt); 19027c478bd9Sstevel@tonic-gate (void) fclose(fp); 19037c478bd9Sstevel@tonic-gate return (0); 19047c478bd9Sstevel@tonic-gate } 19057c478bd9Sstevel@tonic-gate 19067c478bd9Sstevel@tonic-gate if (strstr(mnt.mnt_special, RAMDISK_SPECIAL) != NULL) { 19077c478bd9Sstevel@tonic-gate if (bam_verbose) 19087c478bd9Sstevel@tonic-gate bam_error(IS_RAMDISK, bam_root); 19097c478bd9Sstevel@tonic-gate (void) fclose(fp); 19107c478bd9Sstevel@tonic-gate return (1); 19117c478bd9Sstevel@tonic-gate } 19127c478bd9Sstevel@tonic-gate 19137c478bd9Sstevel@tonic-gate (void) fclose(fp); 19147c478bd9Sstevel@tonic-gate 19157c478bd9Sstevel@tonic-gate return (0); 19167c478bd9Sstevel@tonic-gate } 19177c478bd9Sstevel@tonic-gate 19187c478bd9Sstevel@tonic-gate static int 1919986fd29aSsetje is_boot_archive(char *root) 19207c478bd9Sstevel@tonic-gate { 1921eb2bd662Svikram char path[PATH_MAX]; 1922eb2bd662Svikram struct stat sb; 1923eb2bd662Svikram int error; 1924eb2bd662Svikram const char *fcn = "is_boot_archive()"; 19257c478bd9Sstevel@tonic-gate 19267c478bd9Sstevel@tonic-gate /* 1927986fd29aSsetje * We can't create an archive without the create_ramdisk script 19287c478bd9Sstevel@tonic-gate */ 1929986fd29aSsetje (void) snprintf(path, sizeof (path), "%s/%s", root, CREATE_RAMDISK); 1930eb2bd662Svikram error = stat(path, &sb); 1931eb2bd662Svikram INJECT_ERROR1("NOT_ARCHIVE_BASED", error = -1); 1932eb2bd662Svikram if (error == -1) { 19337c478bd9Sstevel@tonic-gate if (bam_verbose) 19347c478bd9Sstevel@tonic-gate bam_print(FILE_MISS, path); 1935eb2bd662Svikram BAM_DPRINTF((D_NOT_ARCHIVE_BOOT, fcn, root)); 19367c478bd9Sstevel@tonic-gate return (0); 19377c478bd9Sstevel@tonic-gate } 19387c478bd9Sstevel@tonic-gate 1939eb2bd662Svikram BAM_DPRINTF((D_IS_ARCHIVE_BOOT, fcn, root)); 1940986fd29aSsetje return (1); 1941986fd29aSsetje } 1942986fd29aSsetje 1943986fd29aSsetje /* 1944986fd29aSsetje * Need to call this for anything that operates on the GRUB menu 1945963390b4Svikram * In the x86 live upgrade case the directory /boot/grub may be present 1946963390b4Svikram * even on pre-newboot BEs. The authoritative way to check for a GRUB target 1947963390b4Svikram * is to check for the presence of the stage2 binary which is present 1948963390b4Svikram * only on GRUB targets (even on x86 boot partitions). Checking for the 1949963390b4Svikram * presence of the multiboot binary is not correct as it is not present 1950963390b4Svikram * on x86 boot partitions. 1951986fd29aSsetje */ 1952986fd29aSsetje int 1953986fd29aSsetje is_grub(const char *root) 1954986fd29aSsetje { 1955986fd29aSsetje char path[PATH_MAX]; 1956986fd29aSsetje struct stat sb; 1957eb2bd662Svikram const char *fcn = "is_grub()"; 1958986fd29aSsetje 1959963390b4Svikram (void) snprintf(path, sizeof (path), "%s%s", root, GRUB_STAGE2); 19607c478bd9Sstevel@tonic-gate if (stat(path, &sb) == -1) { 1961eb2bd662Svikram BAM_DPRINTF((D_NO_GRUB_DIR, fcn, path)); 19627c478bd9Sstevel@tonic-gate return (0); 19637c478bd9Sstevel@tonic-gate } 19647c478bd9Sstevel@tonic-gate 19657c478bd9Sstevel@tonic-gate return (1); 19667c478bd9Sstevel@tonic-gate } 19677c478bd9Sstevel@tonic-gate 19687c478bd9Sstevel@tonic-gate static int 1969eb2bd662Svikram is_zfs(char *root) 19707c478bd9Sstevel@tonic-gate { 1971eb2bd662Svikram struct statvfs vfs; 1972eb2bd662Svikram int ret; 1973eb2bd662Svikram const char *fcn = "is_zfs()"; 19747c478bd9Sstevel@tonic-gate 1975eb2bd662Svikram ret = statvfs(root, &vfs); 1976eb2bd662Svikram INJECT_ERROR1("STATVFS_ZFS", ret = 1); 1977eb2bd662Svikram if (ret != 0) { 1978eb2bd662Svikram bam_error(STATVFS_FAIL, root, strerror(errno)); 19797c478bd9Sstevel@tonic-gate return (0); 19807c478bd9Sstevel@tonic-gate } 19817c478bd9Sstevel@tonic-gate 1982eb2bd662Svikram if (strncmp(vfs.f_basetype, "zfs", strlen("zfs")) == 0) { 1983eb2bd662Svikram BAM_DPRINTF((D_IS_ZFS, fcn, root)); 19847c478bd9Sstevel@tonic-gate return (1); 1985eb2bd662Svikram } else { 1986eb2bd662Svikram BAM_DPRINTF((D_IS_NOT_ZFS, fcn, root)); 1987eb2bd662Svikram return (0); 19887c478bd9Sstevel@tonic-gate } 19897c478bd9Sstevel@tonic-gate } 19907c478bd9Sstevel@tonic-gate 1991e7cbe64fSgw static int 1992eb2bd662Svikram is_ufs(char *root) 1993e7cbe64fSgw { 1994eb2bd662Svikram struct statvfs vfs; 1995eb2bd662Svikram int ret; 1996eb2bd662Svikram const char *fcn = "is_ufs()"; 1997e7cbe64fSgw 1998eb2bd662Svikram ret = statvfs(root, &vfs); 1999eb2bd662Svikram INJECT_ERROR1("STATVFS_UFS", ret = 1); 2000eb2bd662Svikram if (ret != 0) { 2001eb2bd662Svikram bam_error(STATVFS_FAIL, root, strerror(errno)); 2002eb2bd662Svikram return (0); 2003eb2bd662Svikram } 2004e7cbe64fSgw 2005eb2bd662Svikram if (strncmp(vfs.f_basetype, "ufs", strlen("ufs")) == 0) { 2006eb2bd662Svikram BAM_DPRINTF((D_IS_UFS, fcn, root)); 2007eb2bd662Svikram return (1); 2008eb2bd662Svikram } else { 2009eb2bd662Svikram BAM_DPRINTF((D_IS_NOT_UFS, fcn, root)); 2010e7cbe64fSgw return (0); 2011e7cbe64fSgw } 2012eb2bd662Svikram } 2013eb2bd662Svikram 2014eb2bd662Svikram static int 2015eb2bd662Svikram is_pcfs(char *root) 2016eb2bd662Svikram { 2017eb2bd662Svikram struct statvfs vfs; 2018eb2bd662Svikram int ret; 2019eb2bd662Svikram const char *fcn = "is_pcfs()"; 2020e7cbe64fSgw 2021eb2bd662Svikram ret = statvfs(root, &vfs); 2022eb2bd662Svikram INJECT_ERROR1("STATVFS_PCFS", ret = 1); 2023eb2bd662Svikram if (ret != 0) { 2024eb2bd662Svikram bam_error(STATVFS_FAIL, root, strerror(errno)); 2025e7cbe64fSgw return (0); 2026eb2bd662Svikram } 2027e7cbe64fSgw 2028eb2bd662Svikram if (strncmp(vfs.f_basetype, "pcfs", strlen("pcfs")) == 0) { 2029eb2bd662Svikram BAM_DPRINTF((D_IS_PCFS, fcn, root)); 2030e7cbe64fSgw return (1); 2031eb2bd662Svikram } else { 2032eb2bd662Svikram BAM_DPRINTF((D_IS_NOT_PCFS, fcn, root)); 2033e7cbe64fSgw return (0); 2034e7cbe64fSgw } 2035eb2bd662Svikram } 2036e7cbe64fSgw 2037eb2bd662Svikram static int 2038eb2bd662Svikram is_readonly(char *root) 2039eb2bd662Svikram { 2040eb2bd662Svikram int fd; 2041eb2bd662Svikram int error; 2042eb2bd662Svikram char testfile[PATH_MAX]; 2043eb2bd662Svikram const char *fcn = "is_readonly()"; 2044e7cbe64fSgw 2045eb2bd662Svikram /* 2046eb2bd662Svikram * Using statvfs() to check for a read-only filesystem is not 2047eb2bd662Svikram * reliable. The only way to reliably test is to attempt to 2048eb2bd662Svikram * create a file 2049eb2bd662Svikram */ 2050eb2bd662Svikram (void) snprintf(testfile, sizeof (testfile), "%s/%s.%d", 2051eb2bd662Svikram root, BOOTADM_RDONLY_TEST, getpid()); 2052e7cbe64fSgw 2053eb2bd662Svikram (void) unlink(testfile); 2054e7cbe64fSgw 2055eb2bd662Svikram errno = 0; 2056eb2bd662Svikram fd = open(testfile, O_RDWR|O_CREAT|O_EXCL, 0644); 2057eb2bd662Svikram error = errno; 2058eb2bd662Svikram INJECT_ERROR2("RDONLY_TEST_ERROR", fd = -1, error = EACCES); 2059eb2bd662Svikram if (fd == -1 && error == EROFS) { 2060eb2bd662Svikram BAM_DPRINTF((D_RDONLY_FS, fcn, root)); 2061e7cbe64fSgw return (1); 2062eb2bd662Svikram } else if (fd == -1) { 2063eb2bd662Svikram bam_error(RDONLY_TEST_ERROR, root, strerror(error)); 2064e7cbe64fSgw } 2065e7cbe64fSgw 2066eb2bd662Svikram (void) close(fd); 2067eb2bd662Svikram (void) unlink(testfile); 2068eb2bd662Svikram 2069eb2bd662Svikram BAM_DPRINTF((D_RDWR_FS, fcn, root)); 2070e7cbe64fSgw return (0); 2071e7cbe64fSgw } 2072e7cbe64fSgw 20737c478bd9Sstevel@tonic-gate static error_t 20747c478bd9Sstevel@tonic-gate update_archive(char *root, char *opt) 20757c478bd9Sstevel@tonic-gate { 20767c478bd9Sstevel@tonic-gate error_t ret; 20777c478bd9Sstevel@tonic-gate 20787c478bd9Sstevel@tonic-gate assert(root); 20797c478bd9Sstevel@tonic-gate assert(opt == NULL); 20807c478bd9Sstevel@tonic-gate 20817c478bd9Sstevel@tonic-gate /* 2082eb2bd662Svikram * root must belong to a boot archive based OS, 20837c478bd9Sstevel@tonic-gate */ 2084986fd29aSsetje if (!is_boot_archive(root)) { 2085b610f78eSvikram /* 2086b610f78eSvikram * Emit message only if not in context of update_all. 2087b610f78eSvikram * If in update_all, emit only if verbose flag is set. 2088b610f78eSvikram */ 2089b610f78eSvikram if (!bam_update_all || bam_verbose) 2090eb2bd662Svikram bam_print(NOT_ARCHIVE_BOOT, root); 20917c478bd9Sstevel@tonic-gate return (BAM_SUCCESS); 20927c478bd9Sstevel@tonic-gate } 20937c478bd9Sstevel@tonic-gate 20947c478bd9Sstevel@tonic-gate /* 20958c1b6884Sszhou * If smf check is requested when / is writable (can happen 20968c1b6884Sszhou * on first reboot following an upgrade because service 20978c1b6884Sszhou * dependency is messed up), skip the check. 20988c1b6884Sszhou */ 20998c1b6884Sszhou if (bam_smf_check && !bam_root_readonly) 21008c1b6884Sszhou return (BAM_SUCCESS); 21018c1b6884Sszhou 21028c1b6884Sszhou /* 21038c1b6884Sszhou * root must be writable. This check applies to alternate 21048c1b6884Sszhou * root (-R option); bam_root_readonly applies to '/' only. 21057c478bd9Sstevel@tonic-gate */ 210661cb17bdSsetje if (!bam_smf_check && !bam_check && is_readonly(root)) { 21078c1b6884Sszhou if (bam_verbose) 21087c478bd9Sstevel@tonic-gate bam_print(RDONLY_FS, root); 21097c478bd9Sstevel@tonic-gate return (BAM_SUCCESS); 21107c478bd9Sstevel@tonic-gate } 21117c478bd9Sstevel@tonic-gate 21127c478bd9Sstevel@tonic-gate /* 21137c478bd9Sstevel@tonic-gate * Don't generate archive on ramdisk 21147c478bd9Sstevel@tonic-gate */ 21157c478bd9Sstevel@tonic-gate if (is_ramdisk(root)) { 21167c478bd9Sstevel@tonic-gate if (bam_verbose) 21177c478bd9Sstevel@tonic-gate bam_print(SKIP_RAMDISK); 21187c478bd9Sstevel@tonic-gate return (BAM_SUCCESS); 21197c478bd9Sstevel@tonic-gate } 21207c478bd9Sstevel@tonic-gate 21217c478bd9Sstevel@tonic-gate /* 21227c478bd9Sstevel@tonic-gate * Now check if updated is really needed 21237c478bd9Sstevel@tonic-gate */ 21247c478bd9Sstevel@tonic-gate ret = update_required(root); 21257c478bd9Sstevel@tonic-gate 21267c478bd9Sstevel@tonic-gate /* 21277c478bd9Sstevel@tonic-gate * The check command (-n) is *not* a dry run 21287c478bd9Sstevel@tonic-gate * It only checks if the archive is in sync. 21297c478bd9Sstevel@tonic-gate */ 21307c478bd9Sstevel@tonic-gate if (bam_check) { 21317c478bd9Sstevel@tonic-gate bam_exit((ret != 0) ? 1 : 0); 21327c478bd9Sstevel@tonic-gate } 21337c478bd9Sstevel@tonic-gate 21347c478bd9Sstevel@tonic-gate if (ret == 1) { 21357c478bd9Sstevel@tonic-gate /* create the ramdisk */ 21367c478bd9Sstevel@tonic-gate ret = create_ramdisk(root); 21377c478bd9Sstevel@tonic-gate } 2138986fd29aSsetje 2139986fd29aSsetje /* if the archive is updated, save the new stat data */ 2140986fd29aSsetje if (ret == 0 && walk_arg.new_nvlp != NULL) { 2141986fd29aSsetje savenew(root); 2142986fd29aSsetje } 2143986fd29aSsetje 2144986fd29aSsetje clear_walk_args(); 2145986fd29aSsetje 21467c478bd9Sstevel@tonic-gate return (ret); 21477c478bd9Sstevel@tonic-gate } 21487c478bd9Sstevel@tonic-gate 2149963390b4Svikram static error_t 2150963390b4Svikram synchronize_BE_menu(void) 2151fbac2b2bSvikram { 2152963390b4Svikram struct stat sb; 2153963390b4Svikram char cmdline[PATH_MAX]; 2154963390b4Svikram char cksum_line[PATH_MAX]; 2155963390b4Svikram filelist_t flist = {0}; 2156963390b4Svikram char *old_cksum_str; 2157963390b4Svikram char *old_size_str; 2158963390b4Svikram char *old_file; 2159963390b4Svikram char *curr_cksum_str; 2160963390b4Svikram char *curr_size_str; 2161963390b4Svikram char *curr_file; 2162963390b4Svikram FILE *cfp; 2163963390b4Svikram int found; 2164963390b4Svikram int ret; 2165963390b4Svikram const char *fcn = "synchronize_BE_menu()"; 2166fbac2b2bSvikram 2167963390b4Svikram BAM_DPRINTF((D_FUNC_ENTRY0, fcn)); 2168fbac2b2bSvikram 2169963390b4Svikram /* Check if findroot enabled LU BE */ 2170963390b4Svikram if (stat(FINDROOT_INSTALLGRUB, &sb) != 0) { 2171963390b4Svikram BAM_DPRINTF((D_NOT_LU_BE, fcn)); 2172963390b4Svikram return (BAM_SUCCESS); 2173963390b4Svikram } 2174fbac2b2bSvikram 2175963390b4Svikram if (stat(LU_MENU_CKSUM, &sb) != 0) { 2176963390b4Svikram BAM_DPRINTF((D_NO_CKSUM_FILE, fcn, LU_MENU_CKSUM)); 2177963390b4Svikram goto menu_sync; 2178fbac2b2bSvikram } 2179fbac2b2bSvikram 2180963390b4Svikram cfp = fopen(LU_MENU_CKSUM, "r"); 2181963390b4Svikram INJECT_ERROR1("CKSUM_FILE_MISSING", cfp = NULL); 2182963390b4Svikram if (cfp == NULL) { 2183963390b4Svikram bam_error(CANNOT_READ_LU_CKSUM, LU_MENU_CKSUM); 2184963390b4Svikram goto menu_sync; 2185963390b4Svikram } 2186963390b4Svikram BAM_DPRINTF((D_CKSUM_FILE_OPENED, fcn, LU_MENU_CKSUM)); 2187963390b4Svikram 2188963390b4Svikram found = 0; 2189963390b4Svikram while (s_fgets(cksum_line, sizeof (cksum_line), cfp) != NULL) { 2190963390b4Svikram INJECT_ERROR1("MULTIPLE_CKSUM", found = 1); 2191963390b4Svikram if (found) { 2192963390b4Svikram bam_error(MULTIPLE_LU_CKSUM, LU_MENU_CKSUM); 2193963390b4Svikram (void) fclose(cfp); 2194963390b4Svikram goto menu_sync; 2195963390b4Svikram } 2196963390b4Svikram found = 1; 2197963390b4Svikram } 2198963390b4Svikram BAM_DPRINTF((D_CKSUM_FILE_READ, fcn, LU_MENU_CKSUM)); 2199963390b4Svikram 2200963390b4Svikram 2201963390b4Svikram old_cksum_str = strtok(cksum_line, " \t"); 2202963390b4Svikram old_size_str = strtok(NULL, " \t"); 2203963390b4Svikram old_file = strtok(NULL, " \t"); 2204963390b4Svikram 2205963390b4Svikram INJECT_ERROR1("OLD_CKSUM_NULL", old_cksum_str = NULL); 2206963390b4Svikram INJECT_ERROR1("OLD_SIZE_NULL", old_size_str = NULL); 2207963390b4Svikram INJECT_ERROR1("OLD_FILE_NULL", old_file = NULL); 2208963390b4Svikram if (old_cksum_str == NULL || old_size_str == NULL || old_file == NULL) { 2209963390b4Svikram bam_error(CANNOT_PARSE_LU_CKSUM, LU_MENU_CKSUM); 2210963390b4Svikram goto menu_sync; 2211963390b4Svikram } 2212963390b4Svikram BAM_DPRINTF((D_CKSUM_FILE_PARSED, fcn, LU_MENU_CKSUM)); 2213963390b4Svikram 2214963390b4Svikram /* Get checksum of current menu */ 2215963390b4Svikram (void) snprintf(cmdline, sizeof (cmdline), "%s %s", 2216963390b4Svikram CKSUM, GRUB_MENU); 2217963390b4Svikram ret = exec_cmd(cmdline, &flist); 2218963390b4Svikram INJECT_ERROR1("GET_CURR_CKSUM", ret = 1); 2219963390b4Svikram if (ret != 0) { 2220963390b4Svikram bam_error(MENU_CKSUM_FAIL); 2221963390b4Svikram return (BAM_ERROR); 2222963390b4Svikram } 2223963390b4Svikram BAM_DPRINTF((D_CKSUM_GEN_SUCCESS, fcn)); 2224963390b4Svikram 2225963390b4Svikram INJECT_ERROR1("GET_CURR_CKSUM_OUTPUT", flist.head = NULL); 2226963390b4Svikram if ((flist.head == NULL) || (flist.head != flist.tail)) { 2227963390b4Svikram bam_error(BAD_CKSUM); 2228963390b4Svikram filelist_free(&flist); 2229963390b4Svikram return (BAM_ERROR); 2230963390b4Svikram } 2231963390b4Svikram BAM_DPRINTF((D_CKSUM_GEN_OUTPUT_VALID, fcn)); 2232963390b4Svikram 2233963390b4Svikram curr_cksum_str = strtok(flist.head->line, " \t"); 2234963390b4Svikram curr_size_str = strtok(NULL, " \t"); 2235963390b4Svikram curr_file = strtok(NULL, " \t"); 2236963390b4Svikram 2237963390b4Svikram INJECT_ERROR1("CURR_CKSUM_NULL", curr_cksum_str = NULL); 2238963390b4Svikram INJECT_ERROR1("CURR_SIZE_NULL", curr_size_str = NULL); 2239963390b4Svikram INJECT_ERROR1("CURR_FILE_NULL", curr_file = NULL); 2240963390b4Svikram if (curr_cksum_str == NULL || curr_size_str == NULL || 2241963390b4Svikram curr_file == NULL) { 2242963390b4Svikram bam_error(BAD_CKSUM_PARSE); 2243963390b4Svikram filelist_free(&flist); 2244963390b4Svikram return (BAM_ERROR); 2245963390b4Svikram } 2246963390b4Svikram BAM_DPRINTF((D_CKSUM_GEN_PARSED, fcn)); 2247963390b4Svikram 2248963390b4Svikram if (strcmp(old_cksum_str, curr_cksum_str) == 0 && 2249963390b4Svikram strcmp(old_size_str, curr_size_str) == 0 && 2250963390b4Svikram strcmp(old_file, curr_file) == 0) { 2251963390b4Svikram filelist_free(&flist); 2252963390b4Svikram BAM_DPRINTF((D_CKSUM_NO_CHANGE, fcn)); 2253963390b4Svikram return (BAM_SUCCESS); 2254963390b4Svikram } 2255963390b4Svikram 2256963390b4Svikram filelist_free(&flist); 2257963390b4Svikram 2258963390b4Svikram /* cksum doesn't match - the menu has changed */ 2259963390b4Svikram BAM_DPRINTF((D_CKSUM_HAS_CHANGED, fcn)); 2260963390b4Svikram 2261963390b4Svikram menu_sync: 2262963390b4Svikram bam_print(PROP_GRUB_MENU); 2263963390b4Svikram 2264963390b4Svikram (void) snprintf(cmdline, sizeof (cmdline), 2265a6968364Svikram "/bin/sh -c '. %s > /dev/null; %s %s yes > /dev/null'", 2266963390b4Svikram LULIB, LULIB_PROPAGATE_FILE, GRUB_MENU); 2267963390b4Svikram ret = exec_cmd(cmdline, NULL); 2268963390b4Svikram INJECT_ERROR1("PROPAGATE_MENU", ret = 1); 2269963390b4Svikram if (ret != 0) { 2270963390b4Svikram bam_error(MENU_PROP_FAIL); 2271963390b4Svikram return (BAM_ERROR); 2272963390b4Svikram } 2273963390b4Svikram BAM_DPRINTF((D_PROPAGATED_MENU, fcn)); 2274963390b4Svikram 2275a6968364Svikram (void) snprintf(cmdline, sizeof (cmdline), "/bin/cp %s %s > /dev/null", 2276963390b4Svikram GRUB_MENU, GRUB_BACKUP_MENU); 2277963390b4Svikram ret = exec_cmd(cmdline, NULL); 2278963390b4Svikram INJECT_ERROR1("CREATE_BACKUP", ret = 1); 2279963390b4Svikram if (ret != 0) { 2280963390b4Svikram bam_error(MENU_BACKUP_FAIL, GRUB_BACKUP_MENU); 2281963390b4Svikram return (BAM_ERROR); 2282963390b4Svikram } 2283963390b4Svikram BAM_DPRINTF((D_CREATED_BACKUP, fcn, GRUB_BACKUP_MENU)); 2284963390b4Svikram 2285963390b4Svikram (void) snprintf(cmdline, sizeof (cmdline), 2286a6968364Svikram "/bin/sh -c '. %s > /dev/null; %s %s no > /dev/null'", 2287963390b4Svikram LULIB, LULIB_PROPAGATE_FILE, GRUB_BACKUP_MENU); 2288963390b4Svikram ret = exec_cmd(cmdline, NULL); 2289963390b4Svikram INJECT_ERROR1("PROPAGATE_BACKUP", ret = 1); 2290963390b4Svikram if (ret != 0) { 2291963390b4Svikram bam_error(BACKUP_PROP_FAIL, GRUB_BACKUP_MENU); 2292963390b4Svikram return (BAM_ERROR); 2293963390b4Svikram } 2294963390b4Svikram BAM_DPRINTF((D_PROPAGATED_BACKUP, fcn, GRUB_BACKUP_MENU)); 2295963390b4Svikram 2296963390b4Svikram (void) snprintf(cmdline, sizeof (cmdline), "%s %s > %s", 2297963390b4Svikram CKSUM, GRUB_MENU, LU_MENU_CKSUM); 2298963390b4Svikram ret = exec_cmd(cmdline, NULL); 2299963390b4Svikram INJECT_ERROR1("CREATE_CKSUM_FILE", ret = 1); 2300963390b4Svikram if (ret != 0) { 2301963390b4Svikram bam_error(MENU_CKSUM_WRITE_FAIL, LU_MENU_CKSUM); 2302963390b4Svikram return (BAM_ERROR); 2303963390b4Svikram } 2304963390b4Svikram BAM_DPRINTF((D_CREATED_CKSUM_FILE, fcn, LU_MENU_CKSUM)); 2305963390b4Svikram 2306963390b4Svikram (void) snprintf(cmdline, sizeof (cmdline), 2307a6968364Svikram "/bin/sh -c '. %s > /dev/null; %s %s no > /dev/null'", 2308963390b4Svikram LULIB, LULIB_PROPAGATE_FILE, LU_MENU_CKSUM); 2309963390b4Svikram ret = exec_cmd(cmdline, NULL); 2310963390b4Svikram INJECT_ERROR1("PROPAGATE_MENU_CKSUM_FILE", ret = 1); 2311963390b4Svikram if (ret != 0) { 2312963390b4Svikram bam_error(MENU_CKSUM_PROP_FAIL, LU_MENU_CKSUM); 2313963390b4Svikram return (BAM_ERROR); 2314963390b4Svikram } 2315963390b4Svikram BAM_DPRINTF((D_PROPAGATED_CKSUM_FILE, fcn, LU_MENU_CKSUM)); 2316963390b4Svikram 2317963390b4Svikram (void) snprintf(cmdline, sizeof (cmdline), 2318a6968364Svikram "/bin/sh -c '. %s > /dev/null; %s %s no > /dev/null'", 2319963390b4Svikram LULIB, LULIB_PROPAGATE_FILE, BOOTADM); 2320963390b4Svikram ret = exec_cmd(cmdline, NULL); 2321963390b4Svikram INJECT_ERROR1("PROPAGATE_BOOTADM_FILE", ret = 1); 2322963390b4Svikram if (ret != 0) { 2323963390b4Svikram bam_error(BOOTADM_PROP_FAIL, BOOTADM); 2324963390b4Svikram return (BAM_ERROR); 2325fbac2b2bSvikram } 2326963390b4Svikram BAM_DPRINTF((D_PROPAGATED_BOOTADM, fcn, BOOTADM)); 2327963390b4Svikram 2328963390b4Svikram return (BAM_SUCCESS); 2329fbac2b2bSvikram } 2330fbac2b2bSvikram 23317c478bd9Sstevel@tonic-gate static error_t 23327c478bd9Sstevel@tonic-gate update_all(char *root, char *opt) 23337c478bd9Sstevel@tonic-gate { 23347c478bd9Sstevel@tonic-gate struct extmnttab mnt; 23357c478bd9Sstevel@tonic-gate struct stat sb; 23367c478bd9Sstevel@tonic-gate FILE *fp; 23377c478bd9Sstevel@tonic-gate char multibt[PATH_MAX]; 2338986fd29aSsetje char creatram[PATH_MAX]; 23397c478bd9Sstevel@tonic-gate error_t ret = BAM_SUCCESS; 23407c478bd9Sstevel@tonic-gate 234140541d5dSvikram assert(root); 23427c478bd9Sstevel@tonic-gate assert(opt == NULL); 23437c478bd9Sstevel@tonic-gate 234440541d5dSvikram if (bam_rootlen != 1 || *root != '/') { 234540541d5dSvikram elide_trailing_slash(root, multibt, sizeof (multibt)); 234640541d5dSvikram bam_error(ALT_ROOT_INVALID, multibt); 234740541d5dSvikram return (BAM_ERROR); 234840541d5dSvikram } 234940541d5dSvikram 23507c478bd9Sstevel@tonic-gate /* 235198892a30Snadkarni * Check to see if we are in the midst of safemode patching 235298892a30Snadkarni * If so skip building the archive for /. Instead build it 235398892a30Snadkarni * against the latest bits obtained by creating a fresh lofs 235498892a30Snadkarni * mount of root. 23557c478bd9Sstevel@tonic-gate */ 235698892a30Snadkarni if (stat(LOFS_PATCH_FILE, &sb) == 0) { 235798892a30Snadkarni if (mkdir(LOFS_PATCH_MNT, 0755) == -1 && 235898892a30Snadkarni errno != EEXIST) { 235998892a30Snadkarni bam_error(MKDIR_FAILED, "%s", LOFS_PATCH_MNT, 236098892a30Snadkarni strerror(errno)); 236198892a30Snadkarni ret = BAM_ERROR; 236298892a30Snadkarni goto out; 236398892a30Snadkarni } 236498892a30Snadkarni (void) snprintf(multibt, sizeof (multibt), 236598892a30Snadkarni "/sbin/mount -F lofs -o nosub / %s", LOFS_PATCH_MNT); 2366986fd29aSsetje if (exec_cmd(multibt, NULL) != 0) { 236798892a30Snadkarni bam_error(MOUNT_FAILED, LOFS_PATCH_MNT, "lofs"); 236898892a30Snadkarni ret = BAM_ERROR; 236998892a30Snadkarni } 237098892a30Snadkarni if (ret != BAM_ERROR) { 237198892a30Snadkarni (void) snprintf(rootbuf, sizeof (rootbuf), "%s/", 237298892a30Snadkarni LOFS_PATCH_MNT); 237398892a30Snadkarni bam_rootlen = strlen(rootbuf); 237498892a30Snadkarni if (update_archive(rootbuf, opt) != BAM_SUCCESS) 237598892a30Snadkarni ret = BAM_ERROR; 237695b1e0e9Snadkarni /* 237795b1e0e9Snadkarni * unmount the lofs mount since there could be 237895b1e0e9Snadkarni * multiple invocations of bootadm -a update_all 237995b1e0e9Snadkarni */ 238095b1e0e9Snadkarni (void) snprintf(multibt, sizeof (multibt), 238195b1e0e9Snadkarni "/sbin/umount %s", LOFS_PATCH_MNT); 2382986fd29aSsetje if (exec_cmd(multibt, NULL) != 0) { 238395b1e0e9Snadkarni bam_error(UMOUNT_FAILED, LOFS_PATCH_MNT); 238495b1e0e9Snadkarni ret = BAM_ERROR; 238595b1e0e9Snadkarni } 238698892a30Snadkarni } 238798892a30Snadkarni } else { 238898892a30Snadkarni /* 238998892a30Snadkarni * First update archive for current root 239098892a30Snadkarni */ 239198892a30Snadkarni if (update_archive(root, opt) != BAM_SUCCESS) 239298892a30Snadkarni ret = BAM_ERROR; 239398892a30Snadkarni } 239498892a30Snadkarni 239598892a30Snadkarni if (ret == BAM_ERROR) 239698892a30Snadkarni goto out; 23977c478bd9Sstevel@tonic-gate 23987c478bd9Sstevel@tonic-gate /* 23997c478bd9Sstevel@tonic-gate * Now walk the mount table, performing archive update 24007c478bd9Sstevel@tonic-gate * for all mounted Newboot root filesystems 24017c478bd9Sstevel@tonic-gate */ 24027c478bd9Sstevel@tonic-gate fp = fopen(MNTTAB, "r"); 24037c478bd9Sstevel@tonic-gate if (fp == NULL) { 24047c478bd9Sstevel@tonic-gate bam_error(OPEN_FAIL, MNTTAB, strerror(errno)); 2405b610f78eSvikram ret = BAM_ERROR; 2406b610f78eSvikram goto out; 24077c478bd9Sstevel@tonic-gate } 24087c478bd9Sstevel@tonic-gate 24097c478bd9Sstevel@tonic-gate resetmnttab(fp); 24107c478bd9Sstevel@tonic-gate 24117c478bd9Sstevel@tonic-gate while (getextmntent(fp, &mnt, sizeof (mnt)) == 0) { 24127c478bd9Sstevel@tonic-gate if (mnt.mnt_special == NULL) 24137c478bd9Sstevel@tonic-gate continue; 2414*f904d32dSJerry Gilliam if ((strcmp(mnt.mnt_fstype, MNTTYPE_ZFS) != 0) && 2415*f904d32dSJerry Gilliam (strncmp(mnt.mnt_special, "/dev/", strlen("/dev/")) != 0)) 24167c478bd9Sstevel@tonic-gate continue; 24177c478bd9Sstevel@tonic-gate if (strcmp(mnt.mnt_mountp, "/") == 0) 24187c478bd9Sstevel@tonic-gate continue; 24197c478bd9Sstevel@tonic-gate 2420986fd29aSsetje (void) snprintf(creatram, sizeof (creatram), "%s/%s", 2421986fd29aSsetje mnt.mnt_mountp, CREATE_RAMDISK); 24227c478bd9Sstevel@tonic-gate 2423986fd29aSsetje if (stat(creatram, &sb) == -1) 24247c478bd9Sstevel@tonic-gate continue; 24257c478bd9Sstevel@tonic-gate 24267c478bd9Sstevel@tonic-gate /* 24277c478bd9Sstevel@tonic-gate * We put a trailing slash to be consistent with root = "/" 24287c478bd9Sstevel@tonic-gate * case, such that we don't have to print // in some cases. 24297c478bd9Sstevel@tonic-gate */ 24307c478bd9Sstevel@tonic-gate (void) snprintf(rootbuf, sizeof (rootbuf), "%s/", 24317c478bd9Sstevel@tonic-gate mnt.mnt_mountp); 24327c478bd9Sstevel@tonic-gate bam_rootlen = strlen(rootbuf); 2433ae115bc7Smrj 2434ae115bc7Smrj /* 2435ae115bc7Smrj * It's possible that other mounts may be an alternate boot 2436ae115bc7Smrj * architecture, so check it again. 2437ae115bc7Smrj */ 2438eb2bd662Svikram if ((get_boot_cap(rootbuf) != BAM_SUCCESS) || 2439ae115bc7Smrj (update_archive(rootbuf, opt) != BAM_SUCCESS)) 24407c478bd9Sstevel@tonic-gate ret = BAM_ERROR; 24417c478bd9Sstevel@tonic-gate } 24427c478bd9Sstevel@tonic-gate 24437c478bd9Sstevel@tonic-gate (void) fclose(fp); 24447c478bd9Sstevel@tonic-gate 2445b610f78eSvikram out: 2446fbac2b2bSvikram /* 2447963390b4Svikram * We no longer use biosdev for Live Upgrade. Hence 2448963390b4Svikram * there is no need to defer (to shutdown time) any fdisk 2449963390b4Svikram * updates 2450fbac2b2bSvikram */ 2451963390b4Svikram if (stat(GRUB_fdisk, &sb) == 0 || stat(GRUB_fdisk_target, &sb) == 0) { 2452963390b4Svikram bam_error(FDISK_FILES_FOUND, GRUB_fdisk, GRUB_fdisk_target); 2453fbac2b2bSvikram } 2454fbac2b2bSvikram 2455963390b4Svikram /* 2456963390b4Svikram * If user has updated menu in current BE, propagate the 2457963390b4Svikram * updates to all BEs. 2458963390b4Svikram */ 2459963390b4Svikram if (synchronize_BE_menu() != BAM_SUCCESS) 2460963390b4Svikram ret = BAM_ERROR; 2461963390b4Svikram 24627c478bd9Sstevel@tonic-gate return (ret); 24637c478bd9Sstevel@tonic-gate } 24647c478bd9Sstevel@tonic-gate 24657c478bd9Sstevel@tonic-gate static void 24667c478bd9Sstevel@tonic-gate append_line(menu_t *mp, line_t *lp) 24677c478bd9Sstevel@tonic-gate { 24687c478bd9Sstevel@tonic-gate if (mp->start == NULL) { 24697c478bd9Sstevel@tonic-gate mp->start = lp; 24707c478bd9Sstevel@tonic-gate } else { 24717c478bd9Sstevel@tonic-gate mp->end->next = lp; 24728c1b6884Sszhou lp->prev = mp->end; 24737c478bd9Sstevel@tonic-gate } 24747c478bd9Sstevel@tonic-gate mp->end = lp; 24757c478bd9Sstevel@tonic-gate } 24767c478bd9Sstevel@tonic-gate 2477eb2bd662Svikram void 24788c1b6884Sszhou unlink_line(menu_t *mp, line_t *lp) 24798c1b6884Sszhou { 24808c1b6884Sszhou /* unlink from list */ 24818c1b6884Sszhou if (lp->prev) 24828c1b6884Sszhou lp->prev->next = lp->next; 24838c1b6884Sszhou else 24848c1b6884Sszhou mp->start = lp->next; 24858c1b6884Sszhou if (lp->next) 24868c1b6884Sszhou lp->next->prev = lp->prev; 24878c1b6884Sszhou else 24888c1b6884Sszhou mp->end = lp->prev; 24898c1b6884Sszhou } 24908c1b6884Sszhou 24918c1b6884Sszhou static entry_t * 24928c1b6884Sszhou boot_entry_new(menu_t *mp, line_t *start, line_t *end) 24938c1b6884Sszhou { 24948c1b6884Sszhou entry_t *ent, *prev; 2495eb2bd662Svikram const char *fcn = "boot_entry_new()"; 2496eb2bd662Svikram 2497eb2bd662Svikram assert(mp); 2498eb2bd662Svikram assert(start); 2499eb2bd662Svikram assert(end); 25008c1b6884Sszhou 25018c1b6884Sszhou ent = s_calloc(1, sizeof (entry_t)); 2502eb2bd662Svikram BAM_DPRINTF((D_ENTRY_NEW, fcn)); 25038c1b6884Sszhou ent->start = start; 25048c1b6884Sszhou ent->end = end; 25058c1b6884Sszhou 25068c1b6884Sszhou if (mp->entries == NULL) { 25078c1b6884Sszhou mp->entries = ent; 2508eb2bd662Svikram BAM_DPRINTF((D_ENTRY_NEW_FIRST, fcn)); 25098c1b6884Sszhou return (ent); 25108c1b6884Sszhou } 25118c1b6884Sszhou 25128c1b6884Sszhou prev = mp->entries; 25138c1b6884Sszhou while (prev->next) 2514eb2bd662Svikram prev = prev->next; 25158c1b6884Sszhou prev->next = ent; 25168c1b6884Sszhou ent->prev = prev; 2517eb2bd662Svikram BAM_DPRINTF((D_ENTRY_NEW_LINKED, fcn)); 25188c1b6884Sszhou return (ent); 25198c1b6884Sszhou } 25208c1b6884Sszhou 25218c1b6884Sszhou static void 25228c1b6884Sszhou boot_entry_addline(entry_t *ent, line_t *lp) 25238c1b6884Sszhou { 25248c1b6884Sszhou if (ent) 25258c1b6884Sszhou ent->end = lp; 25268c1b6884Sszhou } 25278c1b6884Sszhou 2528843e1988Sjohnlev /* 2529843e1988Sjohnlev * Check whether cmd matches the one indexed by which, and whether arg matches 2530843e1988Sjohnlev * str. which must be either KERNEL_CMD or MODULE_CMD, and a match to the 2531843e1988Sjohnlev * respective *_DOLLAR_CMD is also acceptable. The arg is searched using 2532843e1988Sjohnlev * strstr(), so it can be a partial match. 2533843e1988Sjohnlev */ 2534843e1988Sjohnlev static int 2535843e1988Sjohnlev check_cmd(const char *cmd, const int which, const char *arg, const char *str) 2536843e1988Sjohnlev { 2537eb2bd662Svikram int ret; 2538eb2bd662Svikram const char *fcn = "check_cmd()"; 2539eb2bd662Svikram 2540eb2bd662Svikram BAM_DPRINTF((D_FUNC_ENTRY2, fcn, arg, str)); 2541eb2bd662Svikram 2542843e1988Sjohnlev if ((strcmp(cmd, menu_cmds[which]) != 0) && 2543843e1988Sjohnlev (strcmp(cmd, menu_cmds[which + 1]) != 0)) { 2544eb2bd662Svikram BAM_DPRINTF((D_CHECK_CMD_CMD_NOMATCH, 2545eb2bd662Svikram fcn, cmd, menu_cmds[which])); 2546843e1988Sjohnlev return (0); 2547843e1988Sjohnlev } 2548eb2bd662Svikram ret = (strstr(arg, str) != NULL); 2549eb2bd662Svikram 2550eb2bd662Svikram if (ret) { 2551eb2bd662Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 2552eb2bd662Svikram } else { 2553eb2bd662Svikram BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 2554eb2bd662Svikram } 2555eb2bd662Svikram 2556eb2bd662Svikram return (ret); 2557eb2bd662Svikram } 2558eb2bd662Svikram 2559eb2bd662Svikram static error_t 2560eb2bd662Svikram kernel_parser(entry_t *entry, char *cmd, char *arg, int linenum) 2561eb2bd662Svikram { 2562eb2bd662Svikram const char *fcn = "kernel_parser()"; 2563eb2bd662Svikram 2564eb2bd662Svikram assert(entry); 2565eb2bd662Svikram assert(cmd); 2566eb2bd662Svikram assert(arg); 2567eb2bd662Svikram 2568eb2bd662Svikram if (strcmp(cmd, menu_cmds[KERNEL_CMD]) != 0 && 2569eb2bd662Svikram strcmp(cmd, menu_cmds[KERNEL_DOLLAR_CMD]) != 0) { 2570eb2bd662Svikram BAM_DPRINTF((D_NOT_KERNEL_CMD, fcn, cmd)); 2571eb2bd662Svikram return (BAM_ERROR); 2572eb2bd662Svikram } 2573eb2bd662Svikram 2574eb2bd662Svikram if (strncmp(arg, DIRECT_BOOT_32, sizeof (DIRECT_BOOT_32) - 1) == 0) { 2575eb2bd662Svikram BAM_DPRINTF((D_SET_DBOOT_32, fcn, arg)); 2576eb2bd662Svikram entry->flags |= BAM_ENTRY_DBOOT | BAM_ENTRY_32BIT; 2577eb2bd662Svikram } else if (strncmp(arg, DIRECT_BOOT_KERNEL, 2578eb2bd662Svikram sizeof (DIRECT_BOOT_KERNEL) - 1) == 0) { 2579eb2bd662Svikram BAM_DPRINTF((D_SET_DBOOT, fcn, arg)); 2580eb2bd662Svikram entry->flags |= BAM_ENTRY_DBOOT; 2581eb2bd662Svikram } else if (strncmp(arg, DIRECT_BOOT_64, 2582eb2bd662Svikram sizeof (DIRECT_BOOT_64) - 1) == 0) { 2583eb2bd662Svikram BAM_DPRINTF((D_SET_DBOOT_64, fcn, arg)); 2584eb2bd662Svikram entry->flags |= BAM_ENTRY_DBOOT | BAM_ENTRY_64BIT; 2585eb2bd662Svikram } else if (strncmp(arg, DIRECT_BOOT_FAILSAFE_KERNEL, 2586eb2bd662Svikram sizeof (DIRECT_BOOT_FAILSAFE_KERNEL) - 1) == 0) { 2587eb2bd662Svikram BAM_DPRINTF((D_SET_DBOOT_FAILSAFE, fcn, arg)); 2588eb2bd662Svikram entry->flags |= BAM_ENTRY_DBOOT | BAM_ENTRY_FAILSAFE; 2589eb2bd662Svikram } else if (strncmp(arg, MULTI_BOOT, sizeof (MULTI_BOOT) - 1) == 0) { 2590eb2bd662Svikram BAM_DPRINTF((D_SET_MULTIBOOT, fcn, arg)); 2591eb2bd662Svikram entry->flags |= BAM_ENTRY_MULTIBOOT; 2592eb2bd662Svikram } else if (strncmp(arg, MULTI_BOOT_FAILSAFE, 2593eb2bd662Svikram sizeof (MULTI_BOOT_FAILSAFE) - 1) == 0) { 2594eb2bd662Svikram BAM_DPRINTF((D_SET_MULTIBOOT_FAILSAFE, fcn, arg)); 2595eb2bd662Svikram entry->flags |= BAM_ENTRY_MULTIBOOT | BAM_ENTRY_FAILSAFE; 2596eb2bd662Svikram } else if (strstr(arg, XEN_KERNEL_SUBSTR)) { 2597eb2bd662Svikram BAM_DPRINTF((D_SET_HV, fcn, arg)); 2598eb2bd662Svikram entry->flags |= BAM_ENTRY_HV; 2599eb2bd662Svikram } else if (!(entry->flags & (BAM_ENTRY_BOOTADM|BAM_ENTRY_LU))) { 2600eb2bd662Svikram BAM_DPRINTF((D_SET_HAND_KERNEL, fcn, arg)); 2601eb2bd662Svikram return (BAM_ERROR); 2602eb2bd662Svikram } else { 2603eb2bd662Svikram BAM_DPRINTF((D_IS_UNKNOWN_KERNEL, fcn, arg)); 2604eb2bd662Svikram bam_error(UNKNOWN_KERNEL_LINE, linenum); 2605eb2bd662Svikram return (BAM_ERROR); 2606eb2bd662Svikram } 2607eb2bd662Svikram 2608eb2bd662Svikram return (BAM_SUCCESS); 2609eb2bd662Svikram } 2610eb2bd662Svikram 2611eb2bd662Svikram static error_t 2612eb2bd662Svikram module_parser(entry_t *entry, char *cmd, char *arg, int linenum) 2613eb2bd662Svikram { 2614eb2bd662Svikram const char *fcn = "module_parser()"; 2615eb2bd662Svikram 2616eb2bd662Svikram assert(entry); 2617eb2bd662Svikram assert(cmd); 2618eb2bd662Svikram assert(arg); 2619eb2bd662Svikram 2620eb2bd662Svikram if (strcmp(cmd, menu_cmds[MODULE_CMD]) != 0 && 2621eb2bd662Svikram strcmp(cmd, menu_cmds[MODULE_DOLLAR_CMD]) != 0) { 2622eb2bd662Svikram BAM_DPRINTF((D_NOT_MODULE_CMD, fcn, cmd)); 2623eb2bd662Svikram return (BAM_ERROR); 2624eb2bd662Svikram } 2625eb2bd662Svikram 2626eb2bd662Svikram if (strcmp(arg, DIRECT_BOOT_ARCHIVE) == 0 || 2627eb2bd662Svikram strcmp(arg, DIRECT_BOOT_ARCHIVE_32) == 0 || 2628eb2bd662Svikram strcmp(arg, DIRECT_BOOT_ARCHIVE_64) == 0 || 2629eb2bd662Svikram strcmp(arg, MULTIBOOT_ARCHIVE) == 0 || 2630eb2bd662Svikram strcmp(arg, FAILSAFE_ARCHIVE) == 0 || 2631eb2bd662Svikram strcmp(arg, XEN_KERNEL_MODULE_LINE) == 0 || 2632eb2bd662Svikram strcmp(arg, XEN_KERNEL_MODULE_LINE_ZFS) == 0) { 2633eb2bd662Svikram BAM_DPRINTF((D_BOOTADM_LU_MODULE, fcn, arg)); 2634eb2bd662Svikram return (BAM_SUCCESS); 2635eb2bd662Svikram } else if (!(entry->flags & BAM_ENTRY_BOOTADM) && 2636eb2bd662Svikram !(entry->flags & BAM_ENTRY_LU)) { 2637eb2bd662Svikram /* don't emit warning for hand entries */ 2638eb2bd662Svikram BAM_DPRINTF((D_IS_HAND_MODULE, fcn, arg)); 2639eb2bd662Svikram return (BAM_ERROR); 2640eb2bd662Svikram } else { 2641eb2bd662Svikram BAM_DPRINTF((D_IS_UNKNOWN_MODULE, fcn, arg)); 2642eb2bd662Svikram bam_error(UNKNOWN_MODULE_LINE, linenum); 2643eb2bd662Svikram return (BAM_ERROR); 2644eb2bd662Svikram } 2645843e1988Sjohnlev } 2646843e1988Sjohnlev 26477c478bd9Sstevel@tonic-gate /* 26487c478bd9Sstevel@tonic-gate * A line in menu.lst looks like 26497c478bd9Sstevel@tonic-gate * [ ]*<cmd>[ \t=]*<arg>* 26507c478bd9Sstevel@tonic-gate */ 26517c478bd9Sstevel@tonic-gate static void 26527c478bd9Sstevel@tonic-gate line_parser(menu_t *mp, char *str, int *lineNum, int *entryNum) 26537c478bd9Sstevel@tonic-gate { 26547c478bd9Sstevel@tonic-gate /* 26557c478bd9Sstevel@tonic-gate * save state across calls. This is so that 26567c478bd9Sstevel@tonic-gate * header gets the right entry# after title has 26577c478bd9Sstevel@tonic-gate * been processed 26587c478bd9Sstevel@tonic-gate */ 26598c1b6884Sszhou static line_t *prev = NULL; 26608c1b6884Sszhou static entry_t *curr_ent = NULL; 2661ae115bc7Smrj static int in_liveupgrade = 0; 26627c478bd9Sstevel@tonic-gate 26637c478bd9Sstevel@tonic-gate line_t *lp; 26647c478bd9Sstevel@tonic-gate char *cmd, *sep, *arg; 26657c478bd9Sstevel@tonic-gate char save, *cp, *line; 26667c478bd9Sstevel@tonic-gate menu_flag_t flag = BAM_INVALID; 2667eb2bd662Svikram const char *fcn = "line_parser()"; 26687c478bd9Sstevel@tonic-gate 26697c478bd9Sstevel@tonic-gate if (str == NULL) { 26707c478bd9Sstevel@tonic-gate return; 26717c478bd9Sstevel@tonic-gate } 26727c478bd9Sstevel@tonic-gate 26737c478bd9Sstevel@tonic-gate /* 26747c478bd9Sstevel@tonic-gate * First save a copy of the entire line. 26757c478bd9Sstevel@tonic-gate * We use this later to set the line field. 26767c478bd9Sstevel@tonic-gate */ 26777c478bd9Sstevel@tonic-gate line = s_strdup(str); 26787c478bd9Sstevel@tonic-gate 26797c478bd9Sstevel@tonic-gate /* Eat up leading whitespace */ 26807c478bd9Sstevel@tonic-gate while (*str == ' ' || *str == '\t') 26817c478bd9Sstevel@tonic-gate str++; 26827c478bd9Sstevel@tonic-gate 26837c478bd9Sstevel@tonic-gate if (*str == '#') { /* comment */ 26847c478bd9Sstevel@tonic-gate cmd = s_strdup("#"); 26857c478bd9Sstevel@tonic-gate sep = NULL; 26867c478bd9Sstevel@tonic-gate arg = s_strdup(str + 1); 26877c478bd9Sstevel@tonic-gate flag = BAM_COMMENT; 2688ae115bc7Smrj if (strstr(arg, BAM_LU_HDR) != NULL) { 2689ae115bc7Smrj in_liveupgrade = 1; 2690ae115bc7Smrj } else if (strstr(arg, BAM_LU_FTR) != NULL) { 2691ae115bc7Smrj in_liveupgrade = 0; 2692ae115bc7Smrj } 26937c478bd9Sstevel@tonic-gate } else if (*str == '\0') { /* blank line */ 26947c478bd9Sstevel@tonic-gate cmd = sep = arg = NULL; 26957c478bd9Sstevel@tonic-gate flag = BAM_EMPTY; 26967c478bd9Sstevel@tonic-gate } else { 26977c478bd9Sstevel@tonic-gate /* 26987c478bd9Sstevel@tonic-gate * '=' is not a documented separator in grub syntax. 26997c478bd9Sstevel@tonic-gate * However various development bits use '=' as a 27007c478bd9Sstevel@tonic-gate * separator. In addition, external users also 27017c478bd9Sstevel@tonic-gate * use = as a separator. So we will allow that usage. 27027c478bd9Sstevel@tonic-gate */ 27037c478bd9Sstevel@tonic-gate cp = str; 27047c478bd9Sstevel@tonic-gate while (*str != ' ' && *str != '\t' && *str != '=') { 27057c478bd9Sstevel@tonic-gate if (*str == '\0') { 27067c478bd9Sstevel@tonic-gate cmd = s_strdup(cp); 27077c478bd9Sstevel@tonic-gate sep = arg = NULL; 27087c478bd9Sstevel@tonic-gate break; 27097c478bd9Sstevel@tonic-gate } 27107c478bd9Sstevel@tonic-gate str++; 27117c478bd9Sstevel@tonic-gate } 27127c478bd9Sstevel@tonic-gate 27137c478bd9Sstevel@tonic-gate if (*str != '\0') { 27147c478bd9Sstevel@tonic-gate save = *str; 27157c478bd9Sstevel@tonic-gate *str = '\0'; 27167c478bd9Sstevel@tonic-gate cmd = s_strdup(cp); 27177c478bd9Sstevel@tonic-gate *str = save; 27187c478bd9Sstevel@tonic-gate 27197c478bd9Sstevel@tonic-gate str++; 27207c478bd9Sstevel@tonic-gate save = *str; 27217c478bd9Sstevel@tonic-gate *str = '\0'; 27227c478bd9Sstevel@tonic-gate sep = s_strdup(str - 1); 27237c478bd9Sstevel@tonic-gate *str = save; 27247c478bd9Sstevel@tonic-gate 27257c478bd9Sstevel@tonic-gate while (*str == ' ' || *str == '\t') 27267c478bd9Sstevel@tonic-gate str++; 27277c478bd9Sstevel@tonic-gate if (*str == '\0') 27287c478bd9Sstevel@tonic-gate arg = NULL; 27297c478bd9Sstevel@tonic-gate else 27307c478bd9Sstevel@tonic-gate arg = s_strdup(str); 27317c478bd9Sstevel@tonic-gate } 27327c478bd9Sstevel@tonic-gate } 27337c478bd9Sstevel@tonic-gate 27347c478bd9Sstevel@tonic-gate lp = s_calloc(1, sizeof (line_t)); 27357c478bd9Sstevel@tonic-gate 27367c478bd9Sstevel@tonic-gate lp->cmd = cmd; 27377c478bd9Sstevel@tonic-gate lp->sep = sep; 27387c478bd9Sstevel@tonic-gate lp->arg = arg; 27397c478bd9Sstevel@tonic-gate lp->line = line; 27407c478bd9Sstevel@tonic-gate lp->lineNum = ++(*lineNum); 27417c478bd9Sstevel@tonic-gate if (cmd && strcmp(cmd, menu_cmds[TITLE_CMD]) == 0) { 27427c478bd9Sstevel@tonic-gate lp->entryNum = ++(*entryNum); 27437c478bd9Sstevel@tonic-gate lp->flags = BAM_TITLE; 27447c478bd9Sstevel@tonic-gate if (prev && prev->flags == BAM_COMMENT && 2745ae115bc7Smrj prev->arg && strcmp(prev->arg, BAM_BOOTADM_HDR) == 0) { 27467c478bd9Sstevel@tonic-gate prev->entryNum = lp->entryNum; 27478c1b6884Sszhou curr_ent = boot_entry_new(mp, prev, lp); 2748eb2bd662Svikram curr_ent->flags |= BAM_ENTRY_BOOTADM; 2749eb2bd662Svikram BAM_DPRINTF((D_IS_BOOTADM_ENTRY, fcn, arg)); 27508c1b6884Sszhou } else { 27518c1b6884Sszhou curr_ent = boot_entry_new(mp, lp, lp); 2752ae115bc7Smrj if (in_liveupgrade) { 2753eb2bd662Svikram curr_ent->flags |= BAM_ENTRY_LU; 2754eb2bd662Svikram BAM_DPRINTF((D_IS_LU_ENTRY, fcn, arg)); 2755ae115bc7Smrj } 27568c1b6884Sszhou } 2757ae115bc7Smrj curr_ent->entryNum = *entryNum; 27587c478bd9Sstevel@tonic-gate } else if (flag != BAM_INVALID) { 27597c478bd9Sstevel@tonic-gate /* 27607c478bd9Sstevel@tonic-gate * For header comments, the entry# is "fixed up" 27617c478bd9Sstevel@tonic-gate * by the subsequent title 27627c478bd9Sstevel@tonic-gate */ 27637c478bd9Sstevel@tonic-gate lp->entryNum = *entryNum; 27647c478bd9Sstevel@tonic-gate lp->flags = flag; 27657c478bd9Sstevel@tonic-gate } else { 27667c478bd9Sstevel@tonic-gate lp->entryNum = *entryNum; 2767ae115bc7Smrj 2768ae115bc7Smrj if (*entryNum == ENTRY_INIT) { 2769ae115bc7Smrj lp->flags = BAM_GLOBAL; 2770ae115bc7Smrj } else { 2771ae115bc7Smrj lp->flags = BAM_ENTRY; 2772ae115bc7Smrj 2773ae115bc7Smrj if (cmd && arg) { 2774eb2bd662Svikram if (strcmp(cmd, menu_cmds[ROOT_CMD]) == 0) { 2775eb2bd662Svikram BAM_DPRINTF((D_IS_ROOT_CMD, fcn, arg)); 2776ae115bc7Smrj curr_ent->flags |= BAM_ENTRY_ROOT; 2777eb2bd662Svikram } else if (strcmp(cmd, menu_cmds[FINDROOT_CMD]) 2778eb2bd662Svikram == 0) { 2779eb2bd662Svikram BAM_DPRINTF((D_IS_FINDROOT_CMD, fcn, 2780eb2bd662Svikram arg)); 2781eb2bd662Svikram curr_ent->flags |= BAM_ENTRY_FINDROOT; 2782eb2bd662Svikram } else if (strcmp(cmd, 2783eb2bd662Svikram menu_cmds[CHAINLOADER_CMD]) == 0) { 2784eb2bd662Svikram BAM_DPRINTF((D_IS_CHAINLOADER_CMD, fcn, 2785eb2bd662Svikram arg)); 2786ae115bc7Smrj curr_ent->flags |= 2787ae115bc7Smrj BAM_ENTRY_CHAINLOADER; 2788eb2bd662Svikram } else if (kernel_parser(curr_ent, cmd, arg, 2789eb2bd662Svikram lp->lineNum) != BAM_SUCCESS) { 2790eb2bd662Svikram (void) module_parser(curr_ent, cmd, 2791eb2bd662Svikram arg, lp->lineNum); 2792eb2bd662Svikram } 2793ae115bc7Smrj } 2794ae115bc7Smrj } 27957c478bd9Sstevel@tonic-gate } 27967c478bd9Sstevel@tonic-gate 27978c1b6884Sszhou /* record default, old default, and entry line ranges */ 27988c1b6884Sszhou if (lp->flags == BAM_GLOBAL && 27998c1b6884Sszhou strcmp(lp->cmd, menu_cmds[DEFAULT_CMD]) == 0) { 28008c1b6884Sszhou mp->curdefault = lp; 28018c1b6884Sszhou } else if (lp->flags == BAM_COMMENT && 28028c1b6884Sszhou strncmp(lp->arg, BAM_OLDDEF, strlen(BAM_OLDDEF)) == 0) { 28038c1b6884Sszhou mp->olddefault = lp; 2804ae115bc7Smrj } else if (lp->flags == BAM_COMMENT && 2805ae115bc7Smrj strncmp(lp->arg, BAM_OLD_RC_DEF, strlen(BAM_OLD_RC_DEF)) == 0) { 2806ae115bc7Smrj mp->old_rc_default = lp; 28078c1b6884Sszhou } else if (lp->flags == BAM_ENTRY || 2808ae115bc7Smrj (lp->flags == BAM_COMMENT && 2809ae115bc7Smrj strcmp(lp->arg, BAM_BOOTADM_FTR) == 0)) { 28108c1b6884Sszhou boot_entry_addline(curr_ent, lp); 28118c1b6884Sszhou } 28127c478bd9Sstevel@tonic-gate append_line(mp, lp); 28137c478bd9Sstevel@tonic-gate 28147c478bd9Sstevel@tonic-gate prev = lp; 28157c478bd9Sstevel@tonic-gate } 28167c478bd9Sstevel@tonic-gate 2817eb2bd662Svikram void 281840541d5dSvikram update_numbering(menu_t *mp) 281940541d5dSvikram { 282040541d5dSvikram int lineNum; 282140541d5dSvikram int entryNum; 282240541d5dSvikram int old_default_value; 282340541d5dSvikram line_t *lp, *prev, *default_lp, *default_entry; 282440541d5dSvikram char buf[PATH_MAX]; 282540541d5dSvikram 282640541d5dSvikram if (mp->start == NULL) { 282740541d5dSvikram return; 282840541d5dSvikram } 282940541d5dSvikram 283040541d5dSvikram lineNum = LINE_INIT; 283140541d5dSvikram entryNum = ENTRY_INIT; 283240541d5dSvikram old_default_value = ENTRY_INIT; 283340541d5dSvikram lp = default_lp = default_entry = NULL; 283440541d5dSvikram 283540541d5dSvikram prev = NULL; 283640541d5dSvikram for (lp = mp->start; lp; prev = lp, lp = lp->next) { 283740541d5dSvikram lp->lineNum = ++lineNum; 283840541d5dSvikram 283940541d5dSvikram /* 284040541d5dSvikram * Get the value of the default command 284140541d5dSvikram */ 284240541d5dSvikram if (lp->entryNum == ENTRY_INIT && lp->cmd && 284340541d5dSvikram strcmp(lp->cmd, menu_cmds[DEFAULT_CMD]) == 0 && 284440541d5dSvikram lp->arg) { 284540541d5dSvikram old_default_value = atoi(lp->arg); 284640541d5dSvikram default_lp = lp; 284740541d5dSvikram } 284840541d5dSvikram 284940541d5dSvikram /* 2850eb2bd662Svikram * If not a booting entry, nothing else to fix for this 285140541d5dSvikram * entry 285240541d5dSvikram */ 285340541d5dSvikram if (lp->entryNum == ENTRY_INIT) 285440541d5dSvikram continue; 285540541d5dSvikram 285640541d5dSvikram /* 285740541d5dSvikram * Record the position of the default entry. 285840541d5dSvikram * The following works because global 285940541d5dSvikram * commands like default and timeout should precede 286040541d5dSvikram * actual boot entries, so old_default_value 286140541d5dSvikram * is already known (or default cmd is missing). 286240541d5dSvikram */ 286340541d5dSvikram if (default_entry == NULL && 286440541d5dSvikram old_default_value != ENTRY_INIT && 286540541d5dSvikram lp->entryNum == old_default_value) { 286640541d5dSvikram default_entry = lp; 286740541d5dSvikram } 286840541d5dSvikram 286940541d5dSvikram /* 287040541d5dSvikram * Now fixup the entry number 287140541d5dSvikram */ 287240541d5dSvikram if (lp->cmd && strcmp(lp->cmd, menu_cmds[TITLE_CMD]) == 0) { 287340541d5dSvikram lp->entryNum = ++entryNum; 287440541d5dSvikram /* fixup the bootadm header */ 287540541d5dSvikram if (prev && prev->flags == BAM_COMMENT && 2876ae115bc7Smrj prev->arg && 2877ae115bc7Smrj strcmp(prev->arg, BAM_BOOTADM_HDR) == 0) { 287840541d5dSvikram prev->entryNum = lp->entryNum; 287940541d5dSvikram } 288040541d5dSvikram } else { 288140541d5dSvikram lp->entryNum = entryNum; 288240541d5dSvikram } 288340541d5dSvikram } 288440541d5dSvikram 288540541d5dSvikram /* 288640541d5dSvikram * No default command in menu, simply return 288740541d5dSvikram */ 288840541d5dSvikram if (default_lp == NULL) { 288940541d5dSvikram return; 289040541d5dSvikram } 289140541d5dSvikram 289240541d5dSvikram free(default_lp->arg); 289340541d5dSvikram free(default_lp->line); 289440541d5dSvikram 289540541d5dSvikram if (default_entry == NULL) { 289640541d5dSvikram default_lp->arg = s_strdup("0"); 289740541d5dSvikram } else { 289840541d5dSvikram (void) snprintf(buf, sizeof (buf), "%d", 289940541d5dSvikram default_entry->entryNum); 290040541d5dSvikram default_lp->arg = s_strdup(buf); 290140541d5dSvikram } 290240541d5dSvikram 290340541d5dSvikram /* 290440541d5dSvikram * The following is required since only the line field gets 290540541d5dSvikram * written back to menu.lst 290640541d5dSvikram */ 290740541d5dSvikram (void) snprintf(buf, sizeof (buf), "%s%s%s", 290840541d5dSvikram menu_cmds[DEFAULT_CMD], menu_cmds[SEP_CMD], default_lp->arg); 290940541d5dSvikram default_lp->line = s_strdup(buf); 291040541d5dSvikram } 291140541d5dSvikram 291240541d5dSvikram 29137c478bd9Sstevel@tonic-gate static menu_t * 29147c478bd9Sstevel@tonic-gate menu_read(char *menu_path) 29157c478bd9Sstevel@tonic-gate { 29167c478bd9Sstevel@tonic-gate FILE *fp; 29177c478bd9Sstevel@tonic-gate char buf[BAM_MAXLINE], *cp; 29187c478bd9Sstevel@tonic-gate menu_t *mp; 29197c478bd9Sstevel@tonic-gate int line, entry, len, n; 29207c478bd9Sstevel@tonic-gate 29217c478bd9Sstevel@tonic-gate mp = s_calloc(1, sizeof (menu_t)); 29227c478bd9Sstevel@tonic-gate 29237c478bd9Sstevel@tonic-gate fp = fopen(menu_path, "r"); 29247c478bd9Sstevel@tonic-gate if (fp == NULL) { /* Let the caller handle this error */ 29257c478bd9Sstevel@tonic-gate return (mp); 29267c478bd9Sstevel@tonic-gate } 29277c478bd9Sstevel@tonic-gate 29287c478bd9Sstevel@tonic-gate 29297c478bd9Sstevel@tonic-gate /* Note: GRUB boot entry number starts with 0 */ 29307c478bd9Sstevel@tonic-gate line = LINE_INIT; 29317c478bd9Sstevel@tonic-gate entry = ENTRY_INIT; 29327c478bd9Sstevel@tonic-gate cp = buf; 29337c478bd9Sstevel@tonic-gate len = sizeof (buf); 29347c478bd9Sstevel@tonic-gate while (s_fgets(cp, len, fp) != NULL) { 29357c478bd9Sstevel@tonic-gate n = strlen(cp); 29367c478bd9Sstevel@tonic-gate if (cp[n - 1] == '\\') { 29377c478bd9Sstevel@tonic-gate len -= n - 1; 29387c478bd9Sstevel@tonic-gate assert(len >= 2); 29397c478bd9Sstevel@tonic-gate cp += n - 1; 29407c478bd9Sstevel@tonic-gate continue; 29417c478bd9Sstevel@tonic-gate } 29427c478bd9Sstevel@tonic-gate line_parser(mp, buf, &line, &entry); 29437c478bd9Sstevel@tonic-gate cp = buf; 29447c478bd9Sstevel@tonic-gate len = sizeof (buf); 29457c478bd9Sstevel@tonic-gate } 29467c478bd9Sstevel@tonic-gate 29477c478bd9Sstevel@tonic-gate if (fclose(fp) == EOF) { 29487c478bd9Sstevel@tonic-gate bam_error(CLOSE_FAIL, menu_path, strerror(errno)); 29497c478bd9Sstevel@tonic-gate } 29507c478bd9Sstevel@tonic-gate 29517c478bd9Sstevel@tonic-gate return (mp); 29527c478bd9Sstevel@tonic-gate } 29537c478bd9Sstevel@tonic-gate 29547c478bd9Sstevel@tonic-gate static error_t 29557c478bd9Sstevel@tonic-gate selector(menu_t *mp, char *opt, int *entry, char **title) 29567c478bd9Sstevel@tonic-gate { 29577c478bd9Sstevel@tonic-gate char *eq; 29587c478bd9Sstevel@tonic-gate char *opt_dup; 29597c478bd9Sstevel@tonic-gate int entryNum; 29607c478bd9Sstevel@tonic-gate 29617c478bd9Sstevel@tonic-gate assert(mp); 29627c478bd9Sstevel@tonic-gate assert(mp->start); 29637c478bd9Sstevel@tonic-gate assert(opt); 29647c478bd9Sstevel@tonic-gate 29657c478bd9Sstevel@tonic-gate opt_dup = s_strdup(opt); 29667c478bd9Sstevel@tonic-gate 29677c478bd9Sstevel@tonic-gate if (entry) 29687c478bd9Sstevel@tonic-gate *entry = ENTRY_INIT; 29697c478bd9Sstevel@tonic-gate if (title) 29707c478bd9Sstevel@tonic-gate *title = NULL; 29717c478bd9Sstevel@tonic-gate 29727c478bd9Sstevel@tonic-gate eq = strchr(opt_dup, '='); 29737c478bd9Sstevel@tonic-gate if (eq == NULL) { 29747c478bd9Sstevel@tonic-gate bam_error(INVALID_OPT, opt); 29757c478bd9Sstevel@tonic-gate free(opt_dup); 29767c478bd9Sstevel@tonic-gate return (BAM_ERROR); 29777c478bd9Sstevel@tonic-gate } 29787c478bd9Sstevel@tonic-gate 29797c478bd9Sstevel@tonic-gate *eq = '\0'; 29807c478bd9Sstevel@tonic-gate if (entry && strcmp(opt_dup, OPT_ENTRY_NUM) == 0) { 29817c478bd9Sstevel@tonic-gate assert(mp->end); 29827c478bd9Sstevel@tonic-gate entryNum = s_strtol(eq + 1); 29837c478bd9Sstevel@tonic-gate if (entryNum < 0 || entryNum > mp->end->entryNum) { 29847c478bd9Sstevel@tonic-gate bam_error(INVALID_ENTRY, eq + 1); 29857c478bd9Sstevel@tonic-gate free(opt_dup); 29867c478bd9Sstevel@tonic-gate return (BAM_ERROR); 29877c478bd9Sstevel@tonic-gate } 29887c478bd9Sstevel@tonic-gate *entry = entryNum; 29897c478bd9Sstevel@tonic-gate } else if (title && strcmp(opt_dup, menu_cmds[TITLE_CMD]) == 0) { 29907c478bd9Sstevel@tonic-gate *title = opt + (eq - opt_dup) + 1; 29917c478bd9Sstevel@tonic-gate } else { 29927c478bd9Sstevel@tonic-gate bam_error(INVALID_OPT, opt); 29937c478bd9Sstevel@tonic-gate free(opt_dup); 29947c478bd9Sstevel@tonic-gate return (BAM_ERROR); 29957c478bd9Sstevel@tonic-gate } 29967c478bd9Sstevel@tonic-gate 29977c478bd9Sstevel@tonic-gate free(opt_dup); 29987c478bd9Sstevel@tonic-gate return (BAM_SUCCESS); 29997c478bd9Sstevel@tonic-gate } 30007c478bd9Sstevel@tonic-gate 30017c478bd9Sstevel@tonic-gate /* 30027c478bd9Sstevel@tonic-gate * If invoked with no titles/entries (opt == NULL) 30037c478bd9Sstevel@tonic-gate * only title lines in file are printed. 30047c478bd9Sstevel@tonic-gate * 30057c478bd9Sstevel@tonic-gate * If invoked with a title or entry #, all 30067c478bd9Sstevel@tonic-gate * lines in *every* matching entry are listed 30077c478bd9Sstevel@tonic-gate */ 30087c478bd9Sstevel@tonic-gate static error_t 30097c478bd9Sstevel@tonic-gate list_entry(menu_t *mp, char *menu_path, char *opt) 30107c478bd9Sstevel@tonic-gate { 30117c478bd9Sstevel@tonic-gate line_t *lp; 30127c478bd9Sstevel@tonic-gate int entry = ENTRY_INIT; 30137c478bd9Sstevel@tonic-gate int found; 30147c478bd9Sstevel@tonic-gate char *title = NULL; 30157c478bd9Sstevel@tonic-gate 30167c478bd9Sstevel@tonic-gate assert(mp); 30177c478bd9Sstevel@tonic-gate assert(menu_path); 30187c478bd9Sstevel@tonic-gate 3019eb2bd662Svikram /* opt is optional */ 3020eb2bd662Svikram BAM_DPRINTF((D_FUNC_ENTRY2, "list_entry", menu_path, 3021eb2bd662Svikram opt ? opt : "<NULL>")); 3022eb2bd662Svikram 30237c478bd9Sstevel@tonic-gate if (mp->start == NULL) { 30247c478bd9Sstevel@tonic-gate bam_error(NO_MENU, menu_path); 30257c478bd9Sstevel@tonic-gate return (BAM_ERROR); 30267c478bd9Sstevel@tonic-gate } 30277c478bd9Sstevel@tonic-gate 30287c478bd9Sstevel@tonic-gate if (opt != NULL) { 30297c478bd9Sstevel@tonic-gate if (selector(mp, opt, &entry, &title) != BAM_SUCCESS) { 30307c478bd9Sstevel@tonic-gate return (BAM_ERROR); 30317c478bd9Sstevel@tonic-gate } 30327c478bd9Sstevel@tonic-gate assert((entry != ENTRY_INIT) ^ (title != NULL)); 30337c478bd9Sstevel@tonic-gate } else { 30347c478bd9Sstevel@tonic-gate (void) read_globals(mp, menu_path, menu_cmds[DEFAULT_CMD], 0); 30357c478bd9Sstevel@tonic-gate (void) read_globals(mp, menu_path, menu_cmds[TIMEOUT_CMD], 0); 30367c478bd9Sstevel@tonic-gate } 30377c478bd9Sstevel@tonic-gate 30387c478bd9Sstevel@tonic-gate found = 0; 30397c478bd9Sstevel@tonic-gate for (lp = mp->start; lp; lp = lp->next) { 30407c478bd9Sstevel@tonic-gate if (lp->flags == BAM_COMMENT || lp->flags == BAM_EMPTY) 30417c478bd9Sstevel@tonic-gate continue; 30427c478bd9Sstevel@tonic-gate if (opt == NULL && lp->flags == BAM_TITLE) { 30437c478bd9Sstevel@tonic-gate bam_print(PRINT_TITLE, lp->entryNum, 30447c478bd9Sstevel@tonic-gate lp->arg); 30457c478bd9Sstevel@tonic-gate found = 1; 30467c478bd9Sstevel@tonic-gate continue; 30477c478bd9Sstevel@tonic-gate } 30487c478bd9Sstevel@tonic-gate if (entry != ENTRY_INIT && lp->entryNum == entry) { 30497c478bd9Sstevel@tonic-gate bam_print(PRINT, lp->line); 30507c478bd9Sstevel@tonic-gate found = 1; 30517c478bd9Sstevel@tonic-gate continue; 30527c478bd9Sstevel@tonic-gate } 30537c478bd9Sstevel@tonic-gate 30547c478bd9Sstevel@tonic-gate /* 30557c478bd9Sstevel@tonic-gate * We set the entry value here so that all lines 30567c478bd9Sstevel@tonic-gate * in entry get printed. If we subsequently match 30577c478bd9Sstevel@tonic-gate * title in other entries, all lines in those 30587c478bd9Sstevel@tonic-gate * entries get printed as well. 30597c478bd9Sstevel@tonic-gate */ 30607c478bd9Sstevel@tonic-gate if (title && lp->flags == BAM_TITLE && lp->arg && 30617c478bd9Sstevel@tonic-gate strncmp(title, lp->arg, strlen(title)) == 0) { 30627c478bd9Sstevel@tonic-gate bam_print(PRINT, lp->line); 30637c478bd9Sstevel@tonic-gate entry = lp->entryNum; 30647c478bd9Sstevel@tonic-gate found = 1; 30657c478bd9Sstevel@tonic-gate continue; 30667c478bd9Sstevel@tonic-gate } 30677c478bd9Sstevel@tonic-gate } 30687c478bd9Sstevel@tonic-gate 30697c478bd9Sstevel@tonic-gate if (!found) { 30707c478bd9Sstevel@tonic-gate bam_error(NO_MATCH_ENTRY); 30717c478bd9Sstevel@tonic-gate return (BAM_ERROR); 30727c478bd9Sstevel@tonic-gate } 30737c478bd9Sstevel@tonic-gate 30747c478bd9Sstevel@tonic-gate return (BAM_SUCCESS); 30757c478bd9Sstevel@tonic-gate } 30767c478bd9Sstevel@tonic-gate 3077843e1988Sjohnlev int 30787c478bd9Sstevel@tonic-gate add_boot_entry(menu_t *mp, 30797c478bd9Sstevel@tonic-gate char *title, 3080eb2bd662Svikram char *findroot, 30817c478bd9Sstevel@tonic-gate char *kernel, 3082843e1988Sjohnlev char *mod_kernel, 30837c478bd9Sstevel@tonic-gate char *module) 30847c478bd9Sstevel@tonic-gate { 3085eb2bd662Svikram int lineNum; 3086eb2bd662Svikram int entryNum; 3087eb2bd662Svikram char linebuf[BAM_MAXLINE]; 3088eb2bd662Svikram menu_cmd_t k_cmd; 3089eb2bd662Svikram menu_cmd_t m_cmd; 3090eb2bd662Svikram const char *fcn = "add_boot_entry()"; 30917c478bd9Sstevel@tonic-gate 30927c478bd9Sstevel@tonic-gate assert(mp); 30937c478bd9Sstevel@tonic-gate 3094eb2bd662Svikram INJECT_ERROR1("ADD_BOOT_ENTRY_FINDROOT_NULL", findroot = NULL); 3095eb2bd662Svikram if (findroot == NULL) { 3096eb2bd662Svikram bam_error(NULL_FINDROOT); 3097eb2bd662Svikram return (BAM_ERROR); 3098eb2bd662Svikram } 3099eb2bd662Svikram 31007c478bd9Sstevel@tonic-gate if (title == NULL) { 3101ee3b8144Sszhou title = "Solaris"; /* default to Solaris */ 31027c478bd9Sstevel@tonic-gate } 31037c478bd9Sstevel@tonic-gate if (kernel == NULL) { 31047c478bd9Sstevel@tonic-gate bam_error(SUBOPT_MISS, menu_cmds[KERNEL_CMD]); 31057c478bd9Sstevel@tonic-gate return (BAM_ERROR); 31067c478bd9Sstevel@tonic-gate } 31077c478bd9Sstevel@tonic-gate if (module == NULL) { 3108ae115bc7Smrj if (bam_direct != BAM_DIRECT_DBOOT) { 3109ae115bc7Smrj bam_error(SUBOPT_MISS, menu_cmds[MODULE_CMD]); 3110ae115bc7Smrj return (BAM_ERROR); 3111ae115bc7Smrj } 3112ae115bc7Smrj 3113ae115bc7Smrj /* Figure the commands out from the kernel line */ 3114ae115bc7Smrj if (strstr(kernel, "$ISADIR") != NULL) { 3115ae115bc7Smrj module = DIRECT_BOOT_ARCHIVE; 3116ae115bc7Smrj k_cmd = KERNEL_DOLLAR_CMD; 3117ae115bc7Smrj m_cmd = MODULE_DOLLAR_CMD; 3118ae115bc7Smrj } else if (strstr(kernel, "amd64") != NULL) { 3119ae115bc7Smrj module = DIRECT_BOOT_ARCHIVE_64; 3120ae115bc7Smrj k_cmd = KERNEL_CMD; 3121ae115bc7Smrj m_cmd = MODULE_CMD; 3122ae115bc7Smrj } else { 3123ae115bc7Smrj module = DIRECT_BOOT_ARCHIVE_32; 3124ae115bc7Smrj k_cmd = KERNEL_CMD; 3125ae115bc7Smrj m_cmd = MODULE_CMD; 3126ae115bc7Smrj } 3127ae115bc7Smrj } else if ((bam_direct == BAM_DIRECT_DBOOT) && 3128ae115bc7Smrj (strstr(kernel, "$ISADIR") != NULL)) { 3129ae115bc7Smrj /* 3130ae115bc7Smrj * If it's a non-failsafe dboot kernel, use the "kernel$" 3131ae115bc7Smrj * command. Otherwise, use "kernel". 3132ae115bc7Smrj */ 3133ae115bc7Smrj k_cmd = KERNEL_DOLLAR_CMD; 3134ae115bc7Smrj m_cmd = MODULE_DOLLAR_CMD; 3135ae115bc7Smrj } else { 3136ae115bc7Smrj k_cmd = KERNEL_CMD; 3137ae115bc7Smrj m_cmd = MODULE_CMD; 31387c478bd9Sstevel@tonic-gate } 31397c478bd9Sstevel@tonic-gate 31407c478bd9Sstevel@tonic-gate if (mp->start) { 31417c478bd9Sstevel@tonic-gate lineNum = mp->end->lineNum; 31427c478bd9Sstevel@tonic-gate entryNum = mp->end->entryNum; 31437c478bd9Sstevel@tonic-gate } else { 31447c478bd9Sstevel@tonic-gate lineNum = LINE_INIT; 31457c478bd9Sstevel@tonic-gate entryNum = ENTRY_INIT; 31467c478bd9Sstevel@tonic-gate } 31477c478bd9Sstevel@tonic-gate 31487c478bd9Sstevel@tonic-gate /* 31497c478bd9Sstevel@tonic-gate * No separator for comment (HDR/FTR) commands 31507c478bd9Sstevel@tonic-gate * The syntax for comments is #<comment> 31517c478bd9Sstevel@tonic-gate */ 31527c478bd9Sstevel@tonic-gate (void) snprintf(linebuf, sizeof (linebuf), "%s%s", 3153ae115bc7Smrj menu_cmds[COMMENT_CMD], BAM_BOOTADM_HDR); 31548c1b6884Sszhou line_parser(mp, linebuf, &lineNum, &entryNum); 31557c478bd9Sstevel@tonic-gate 31567c478bd9Sstevel@tonic-gate (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s", 31577c478bd9Sstevel@tonic-gate menu_cmds[TITLE_CMD], menu_cmds[SEP_CMD], title); 31588c1b6884Sszhou line_parser(mp, linebuf, &lineNum, &entryNum); 31597c478bd9Sstevel@tonic-gate 3160eb2bd662Svikram (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s", 3161eb2bd662Svikram menu_cmds[FINDROOT_CMD], menu_cmds[SEP_CMD], findroot); 3162eb2bd662Svikram line_parser(mp, linebuf, &lineNum, &entryNum); 3163eb2bd662Svikram BAM_DPRINTF((D_ADD_FINDROOT_NUM, fcn, lineNum, entryNum)); 31647c478bd9Sstevel@tonic-gate 31657c478bd9Sstevel@tonic-gate (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s", 3166ae115bc7Smrj menu_cmds[k_cmd], menu_cmds[SEP_CMD], kernel); 31678c1b6884Sszhou line_parser(mp, linebuf, &lineNum, &entryNum); 31687c478bd9Sstevel@tonic-gate 3169843e1988Sjohnlev if (mod_kernel != NULL) { 3170843e1988Sjohnlev (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s", 3171843e1988Sjohnlev menu_cmds[m_cmd], menu_cmds[SEP_CMD], mod_kernel); 3172843e1988Sjohnlev line_parser(mp, linebuf, &lineNum, &entryNum); 3173843e1988Sjohnlev } 3174843e1988Sjohnlev 31757c478bd9Sstevel@tonic-gate (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s", 3176ae115bc7Smrj menu_cmds[m_cmd], menu_cmds[SEP_CMD], module); 31778c1b6884Sszhou line_parser(mp, linebuf, &lineNum, &entryNum); 31787c478bd9Sstevel@tonic-gate 31797c478bd9Sstevel@tonic-gate (void) snprintf(linebuf, sizeof (linebuf), "%s%s", 3180ae115bc7Smrj menu_cmds[COMMENT_CMD], BAM_BOOTADM_FTR); 31818c1b6884Sszhou line_parser(mp, linebuf, &lineNum, &entryNum); 31827c478bd9Sstevel@tonic-gate 31837c478bd9Sstevel@tonic-gate return (entryNum); 31847c478bd9Sstevel@tonic-gate } 31857c478bd9Sstevel@tonic-gate 31867c478bd9Sstevel@tonic-gate static error_t 31877c478bd9Sstevel@tonic-gate do_delete(menu_t *mp, int entryNum) 31887c478bd9Sstevel@tonic-gate { 3189eb2bd662Svikram line_t *lp; 3190eb2bd662Svikram line_t *freed; 3191eb2bd662Svikram entry_t *ent; 3192eb2bd662Svikram entry_t *tmp; 3193eb2bd662Svikram int deleted; 3194eb2bd662Svikram const char *fcn = "do_delete()"; 31957c478bd9Sstevel@tonic-gate 31967c478bd9Sstevel@tonic-gate assert(entryNum != ENTRY_INIT); 31977c478bd9Sstevel@tonic-gate 3198eb2bd662Svikram tmp = NULL; 3199eb2bd662Svikram 32008c1b6884Sszhou ent = mp->entries; 32018c1b6884Sszhou while (ent) { 32028c1b6884Sszhou lp = ent->start; 32038c1b6884Sszhou /* check entry number and make sure it's a bootadm entry */ 32048c1b6884Sszhou if (lp->flags != BAM_COMMENT || 3205ae115bc7Smrj strcmp(lp->arg, BAM_BOOTADM_HDR) != 0 || 32068c1b6884Sszhou (entryNum != ALL_ENTRIES && lp->entryNum != entryNum)) { 32078c1b6884Sszhou ent = ent->next; 32087c478bd9Sstevel@tonic-gate continue; 32097c478bd9Sstevel@tonic-gate } 32107c478bd9Sstevel@tonic-gate 32118c1b6884Sszhou /* free the entry content */ 32128c1b6884Sszhou do { 32138c1b6884Sszhou freed = lp; 32148c1b6884Sszhou lp = lp->next; /* prev stays the same */ 3215eb2bd662Svikram BAM_DPRINTF((D_FREEING_LINE, fcn, freed->lineNum)); 32168c1b6884Sszhou unlink_line(mp, freed); 32178c1b6884Sszhou line_free(freed); 32188c1b6884Sszhou } while (freed != ent->end); 32198c1b6884Sszhou 32208c1b6884Sszhou /* free the entry_t structure */ 3221eb2bd662Svikram assert(tmp == NULL); 32228c1b6884Sszhou tmp = ent; 32238c1b6884Sszhou ent = ent->next; 32248c1b6884Sszhou if (tmp->prev) 32258c1b6884Sszhou tmp->prev->next = ent; 32267c478bd9Sstevel@tonic-gate else 32278c1b6884Sszhou mp->entries = ent; 32288c1b6884Sszhou if (ent) 32298c1b6884Sszhou ent->prev = tmp->prev; 3230eb2bd662Svikram BAM_DPRINTF((D_FREEING_ENTRY, fcn, tmp->entryNum)); 3231eb2bd662Svikram free(tmp); 3232eb2bd662Svikram tmp = NULL; 32337c478bd9Sstevel@tonic-gate deleted = 1; 32347c478bd9Sstevel@tonic-gate } 32357c478bd9Sstevel@tonic-gate 3236eb2bd662Svikram assert(tmp == NULL); 3237eb2bd662Svikram 32387c478bd9Sstevel@tonic-gate if (!deleted && entryNum != ALL_ENTRIES) { 32397c478bd9Sstevel@tonic-gate bam_error(NO_BOOTADM_MATCH); 32407c478bd9Sstevel@tonic-gate return (BAM_ERROR); 32417c478bd9Sstevel@tonic-gate } 32427c478bd9Sstevel@tonic-gate 324340541d5dSvikram /* 324440541d5dSvikram * Now that we have deleted an entry, update 324540541d5dSvikram * the entry numbering and the default cmd. 324640541d5dSvikram */ 324740541d5dSvikram update_numbering(mp); 324840541d5dSvikram 32497c478bd9Sstevel@tonic-gate return (BAM_SUCCESS); 32507c478bd9Sstevel@tonic-gate } 32517c478bd9Sstevel@tonic-gate 32527c478bd9Sstevel@tonic-gate static error_t 3253eb2bd662Svikram delete_all_entries(menu_t *mp, char *dummy, char *opt) 32547c478bd9Sstevel@tonic-gate { 32557c478bd9Sstevel@tonic-gate assert(mp); 3256eb2bd662Svikram assert(dummy == NULL); 32577c478bd9Sstevel@tonic-gate assert(opt == NULL); 32587c478bd9Sstevel@tonic-gate 3259eb2bd662Svikram BAM_DPRINTF((D_FUNC_ENTRY0, "delete_all_entries")); 3260eb2bd662Svikram 32617c478bd9Sstevel@tonic-gate if (mp->start == NULL) { 3262eb2bd662Svikram bam_print(EMPTY_MENU); 32637c478bd9Sstevel@tonic-gate return (BAM_SUCCESS); 32647c478bd9Sstevel@tonic-gate } 32657c478bd9Sstevel@tonic-gate 32667c478bd9Sstevel@tonic-gate if (do_delete(mp, ALL_ENTRIES) != BAM_SUCCESS) { 32677c478bd9Sstevel@tonic-gate return (BAM_ERROR); 32687c478bd9Sstevel@tonic-gate } 32697c478bd9Sstevel@tonic-gate 32707c478bd9Sstevel@tonic-gate return (BAM_WRITE); 32717c478bd9Sstevel@tonic-gate } 32727c478bd9Sstevel@tonic-gate 32737c478bd9Sstevel@tonic-gate static FILE * 3274eb2bd662Svikram create_diskmap(char *osroot) 32757c478bd9Sstevel@tonic-gate { 32767c478bd9Sstevel@tonic-gate FILE *fp; 32777c478bd9Sstevel@tonic-gate char cmd[PATH_MAX]; 3278eb2bd662Svikram const char *fcn = "create_diskmap()"; 32797c478bd9Sstevel@tonic-gate 32807c478bd9Sstevel@tonic-gate /* make sure we have a map file */ 32817c478bd9Sstevel@tonic-gate fp = fopen(GRUBDISK_MAP, "r"); 32827c478bd9Sstevel@tonic-gate if (fp == NULL) { 32837c478bd9Sstevel@tonic-gate (void) snprintf(cmd, sizeof (cmd), 3284eb2bd662Svikram "%s/%s > /dev/null", osroot, CREATE_DISKMAP); 3285eb2bd662Svikram if (exec_cmd(cmd, NULL) != 0) 3286eb2bd662Svikram return (NULL); 32877c478bd9Sstevel@tonic-gate fp = fopen(GRUBDISK_MAP, "r"); 3288eb2bd662Svikram INJECT_ERROR1("DISKMAP_CREATE_FAIL", fp = NULL); 3289eb2bd662Svikram if (fp) { 3290eb2bd662Svikram BAM_DPRINTF((D_CREATED_DISKMAP, fcn, GRUBDISK_MAP)); 3291eb2bd662Svikram } else { 3292eb2bd662Svikram BAM_DPRINTF((D_CREATE_DISKMAP_FAIL, fcn, GRUBDISK_MAP)); 3293eb2bd662Svikram } 32947c478bd9Sstevel@tonic-gate } 32957c478bd9Sstevel@tonic-gate return (fp); 32967c478bd9Sstevel@tonic-gate } 32977c478bd9Sstevel@tonic-gate 32987c478bd9Sstevel@tonic-gate #define SECTOR_SIZE 512 32997c478bd9Sstevel@tonic-gate 33007c478bd9Sstevel@tonic-gate static int 33017c478bd9Sstevel@tonic-gate get_partition(char *device) 33027c478bd9Sstevel@tonic-gate { 33037c478bd9Sstevel@tonic-gate int i, fd, is_pcfs, partno = -1; 33047c478bd9Sstevel@tonic-gate struct mboot *mboot; 33057c478bd9Sstevel@tonic-gate char boot_sect[SECTOR_SIZE]; 33067c478bd9Sstevel@tonic-gate char *wholedisk, *slice; 33077c478bd9Sstevel@tonic-gate 33087c478bd9Sstevel@tonic-gate /* form whole disk (p0) */ 33097c478bd9Sstevel@tonic-gate slice = device + strlen(device) - 2; 33107c478bd9Sstevel@tonic-gate is_pcfs = (*slice != 's'); 33117c478bd9Sstevel@tonic-gate if (!is_pcfs) 33127c478bd9Sstevel@tonic-gate *slice = '\0'; 33137c478bd9Sstevel@tonic-gate wholedisk = s_calloc(1, strlen(device) + 3); 33147c478bd9Sstevel@tonic-gate (void) snprintf(wholedisk, strlen(device) + 3, "%sp0", device); 33157c478bd9Sstevel@tonic-gate if (!is_pcfs) 33167c478bd9Sstevel@tonic-gate *slice = 's'; 33177c478bd9Sstevel@tonic-gate 33187c478bd9Sstevel@tonic-gate /* read boot sector */ 33197c478bd9Sstevel@tonic-gate fd = open(wholedisk, O_RDONLY); 33207c478bd9Sstevel@tonic-gate free(wholedisk); 33217c478bd9Sstevel@tonic-gate if (fd == -1 || read(fd, boot_sect, SECTOR_SIZE) != SECTOR_SIZE) { 33227c478bd9Sstevel@tonic-gate return (partno); 33237c478bd9Sstevel@tonic-gate } 33247c478bd9Sstevel@tonic-gate (void) close(fd); 33257c478bd9Sstevel@tonic-gate 33267c478bd9Sstevel@tonic-gate /* parse fdisk table */ 33277c478bd9Sstevel@tonic-gate mboot = (struct mboot *)((void *)boot_sect); 33287c478bd9Sstevel@tonic-gate for (i = 0; i < FD_NUMPART; i++) { 33297c478bd9Sstevel@tonic-gate struct ipart *part = 33307c478bd9Sstevel@tonic-gate (struct ipart *)(uintptr_t)mboot->parts + i; 33317c478bd9Sstevel@tonic-gate if (is_pcfs) { /* looking for solaris boot part */ 33327c478bd9Sstevel@tonic-gate if (part->systid == 0xbe) { 33337c478bd9Sstevel@tonic-gate partno = i; 33347c478bd9Sstevel@tonic-gate break; 33357c478bd9Sstevel@tonic-gate } 33367c478bd9Sstevel@tonic-gate } else { /* look for solaris partition, old and new */ 33377c478bd9Sstevel@tonic-gate if (part->systid == SUNIXOS || 33387c478bd9Sstevel@tonic-gate part->systid == SUNIXOS2) { 33397c478bd9Sstevel@tonic-gate partno = i; 33407c478bd9Sstevel@tonic-gate break; 33417c478bd9Sstevel@tonic-gate } 33427c478bd9Sstevel@tonic-gate } 33437c478bd9Sstevel@tonic-gate } 33447c478bd9Sstevel@tonic-gate return (partno); 33457c478bd9Sstevel@tonic-gate } 33467c478bd9Sstevel@tonic-gate 3347eb2bd662Svikram char * 3348eb2bd662Svikram get_grubroot(char *osroot, char *osdev, char *menu_root) 33497c478bd9Sstevel@tonic-gate { 3350eb2bd662Svikram char *grubroot; /* (hd#,#,#) */ 3351eb2bd662Svikram char *slice; 3352eb2bd662Svikram char *grubhd; 3353eb2bd662Svikram int fdiskpart; 3354eb2bd662Svikram int found = 0; 3355eb2bd662Svikram char *devname; 3356eb2bd662Svikram char *ctdname = strstr(osdev, "dsk/"); 3357eb2bd662Svikram char linebuf[PATH_MAX]; 3358eb2bd662Svikram FILE *fp; 3359eb2bd662Svikram const char *fcn = "get_grubroot()"; 3360eb2bd662Svikram 3361eb2bd662Svikram INJECT_ERROR1("GRUBROOT_INVALID_OSDEV", ctdname = NULL); 3362eb2bd662Svikram if (ctdname == NULL) { 3363eb2bd662Svikram bam_error(INVALID_DEV_DSK, osdev); 3364eb2bd662Svikram return (NULL); 3365eb2bd662Svikram } 33667c478bd9Sstevel@tonic-gate 3367eb2bd662Svikram if (menu_root && !menu_on_bootdisk(osroot, menu_root)) { 3368eb2bd662Svikram /* menu bears no resemblance to our reality */ 3369eb2bd662Svikram bam_error(CANNOT_GRUBROOT_BOOTDISK, fcn, osdev); 33707c478bd9Sstevel@tonic-gate return (NULL); 3371eb2bd662Svikram } 33727c478bd9Sstevel@tonic-gate 33737c478bd9Sstevel@tonic-gate ctdname += strlen("dsk/"); 33747c478bd9Sstevel@tonic-gate slice = strrchr(ctdname, 's'); 33757c478bd9Sstevel@tonic-gate if (slice) 33767c478bd9Sstevel@tonic-gate *slice = '\0'; 33777c478bd9Sstevel@tonic-gate 3378eb2bd662Svikram fp = create_diskmap(osroot); 3379eb2bd662Svikram if (fp == NULL) { 3380eb2bd662Svikram bam_error(DISKMAP_FAIL, osroot); 3381eb2bd662Svikram return (NULL); 3382eb2bd662Svikram } 3383eb2bd662Svikram 33847c478bd9Sstevel@tonic-gate rewind(fp); 33857c478bd9Sstevel@tonic-gate while (s_fgets(linebuf, sizeof (linebuf), fp) != NULL) { 33867c478bd9Sstevel@tonic-gate grubhd = strtok(linebuf, " \t\n"); 33877c478bd9Sstevel@tonic-gate if (grubhd) 33887c478bd9Sstevel@tonic-gate devname = strtok(NULL, " \t\n"); 33897c478bd9Sstevel@tonic-gate else 33907c478bd9Sstevel@tonic-gate devname = NULL; 33917c478bd9Sstevel@tonic-gate if (devname && strcmp(devname, ctdname) == 0) { 33927c478bd9Sstevel@tonic-gate found = 1; 33937c478bd9Sstevel@tonic-gate break; 33947c478bd9Sstevel@tonic-gate } 33957c478bd9Sstevel@tonic-gate } 33967c478bd9Sstevel@tonic-gate 33977c478bd9Sstevel@tonic-gate if (slice) 33987c478bd9Sstevel@tonic-gate *slice = 's'; 33997c478bd9Sstevel@tonic-gate 3400eb2bd662Svikram (void) fclose(fp); 3401eb2bd662Svikram fp = NULL; 3402eb2bd662Svikram 3403eb2bd662Svikram INJECT_ERROR1("GRUBROOT_BIOSDEV_FAIL", found = 0); 34047c478bd9Sstevel@tonic-gate if (found == 0) { 3405eb2bd662Svikram bam_error(BIOSDEV_FAIL, osdev); 3406eb2bd662Svikram return (NULL); 34077c478bd9Sstevel@tonic-gate } 34087c478bd9Sstevel@tonic-gate 3409eb2bd662Svikram fdiskpart = get_partition(osdev); 3410eb2bd662Svikram INJECT_ERROR1("GRUBROOT_FDISK_FAIL", fdiskpart = -1); 3411eb2bd662Svikram if (fdiskpart == -1) { 3412eb2bd662Svikram bam_error(FDISKPART_FAIL, osdev); 34137c478bd9Sstevel@tonic-gate return (NULL); 3414eb2bd662Svikram } 34157c478bd9Sstevel@tonic-gate 3416eb2bd662Svikram grubroot = s_calloc(1, 10); 34177c478bd9Sstevel@tonic-gate if (slice) { 3418eb2bd662Svikram (void) snprintf(grubroot, 10, "(hd%s,%d,%c)", 34197c478bd9Sstevel@tonic-gate grubhd, fdiskpart, slice[1] + 'a' - '0'); 34207c478bd9Sstevel@tonic-gate } else 3421eb2bd662Svikram (void) snprintf(grubroot, 10, "(hd%s,%d)", 34227c478bd9Sstevel@tonic-gate grubhd, fdiskpart); 34237c478bd9Sstevel@tonic-gate 3424eb2bd662Svikram assert(fp == NULL); 3425eb2bd662Svikram assert(strncmp(grubroot, "(hd", strlen("(hd")) == 0); 3426eb2bd662Svikram return (grubroot); 34277c478bd9Sstevel@tonic-gate } 34287c478bd9Sstevel@tonic-gate 3429ee3b8144Sszhou static char * 3430eb2bd662Svikram find_primary_common(char *mntpt, char *fstype) 34317c478bd9Sstevel@tonic-gate { 3432eb2bd662Svikram char signdir[PATH_MAX]; 3433eb2bd662Svikram char tmpsign[MAXNAMELEN + 1]; 3434eb2bd662Svikram char *lu; 3435eb2bd662Svikram char *ufs; 3436eb2bd662Svikram char *zfs; 3437eb2bd662Svikram DIR *dirp = NULL; 3438eb2bd662Svikram struct dirent *entp; 3439eb2bd662Svikram struct stat sb; 3440eb2bd662Svikram const char *fcn = "find_primary_common()"; 34417c478bd9Sstevel@tonic-gate 3442eb2bd662Svikram (void) snprintf(signdir, sizeof (signdir), "%s/%s", 3443eb2bd662Svikram mntpt, GRUBSIGN_DIR); 34447c478bd9Sstevel@tonic-gate 3445eb2bd662Svikram if (stat(signdir, &sb) == -1) { 3446eb2bd662Svikram BAM_DPRINTF((D_NO_SIGNDIR, fcn, signdir)); 3447ee3b8144Sszhou return (NULL); 3448eb2bd662Svikram } 34497c478bd9Sstevel@tonic-gate 3450eb2bd662Svikram dirp = opendir(signdir); 3451eb2bd662Svikram INJECT_ERROR1("SIGNDIR_OPENDIR_FAIL", dirp = NULL); 3452eb2bd662Svikram if (dirp == NULL) { 3453eb2bd662Svikram bam_error(OPENDIR_FAILED, signdir, strerror(errno)); 3454eb2bd662Svikram return (NULL); 34557c478bd9Sstevel@tonic-gate } 3456eb2bd662Svikram 3457eb2bd662Svikram ufs = zfs = lu = NULL; 3458eb2bd662Svikram 3459eb2bd662Svikram while (entp = readdir(dirp)) { 3460eb2bd662Svikram if (strcmp(entp->d_name, ".") == 0 || 3461eb2bd662Svikram strcmp(entp->d_name, "..") == 0) 3462eb2bd662Svikram continue; 3463eb2bd662Svikram 3464eb2bd662Svikram (void) snprintf(tmpsign, sizeof (tmpsign), "%s", entp->d_name); 3465eb2bd662Svikram 3466eb2bd662Svikram if (lu == NULL && 3467eb2bd662Svikram strncmp(tmpsign, GRUBSIGN_LU_PREFIX, 3468eb2bd662Svikram strlen(GRUBSIGN_LU_PREFIX)) == 0) { 3469eb2bd662Svikram lu = s_strdup(tmpsign); 3470eb2bd662Svikram } 3471eb2bd662Svikram 3472eb2bd662Svikram if (ufs == NULL && 3473eb2bd662Svikram strncmp(tmpsign, GRUBSIGN_UFS_PREFIX, 3474eb2bd662Svikram strlen(GRUBSIGN_UFS_PREFIX)) == 0) { 3475eb2bd662Svikram ufs = s_strdup(tmpsign); 3476eb2bd662Svikram } 3477eb2bd662Svikram 3478eb2bd662Svikram if (zfs == NULL && 3479eb2bd662Svikram strncmp(tmpsign, GRUBSIGN_ZFS_PREFIX, 3480eb2bd662Svikram strlen(GRUBSIGN_ZFS_PREFIX)) == 0) { 3481eb2bd662Svikram zfs = s_strdup(tmpsign); 3482eb2bd662Svikram } 3483eb2bd662Svikram } 3484eb2bd662Svikram 3485eb2bd662Svikram BAM_DPRINTF((D_EXIST_PRIMARY_SIGNS, fcn, 3486eb2bd662Svikram zfs ? zfs : "NULL", 3487eb2bd662Svikram ufs ? ufs : "NULL", 3488eb2bd662Svikram lu ? lu : "NULL")); 3489eb2bd662Svikram 3490eb2bd662Svikram if (dirp) { 3491eb2bd662Svikram (void) closedir(dirp); 3492eb2bd662Svikram dirp = NULL; 3493eb2bd662Svikram } 3494eb2bd662Svikram 3495eb2bd662Svikram if (strcmp(fstype, "ufs") == 0 && zfs) { 3496eb2bd662Svikram bam_error(SIGN_FSTYPE_MISMATCH, zfs, "ufs"); 3497eb2bd662Svikram free(zfs); 3498eb2bd662Svikram zfs = NULL; 3499eb2bd662Svikram } else if (strcmp(fstype, "zfs") == 0 && ufs) { 3500eb2bd662Svikram bam_error(SIGN_FSTYPE_MISMATCH, ufs, "zfs"); 3501eb2bd662Svikram free(ufs); 3502eb2bd662Svikram ufs = NULL; 3503eb2bd662Svikram } 3504eb2bd662Svikram 3505eb2bd662Svikram assert(dirp == NULL); 3506eb2bd662Svikram 3507eb2bd662Svikram /* For now, we let Live Upgrade take care of its signature itself */ 3508eb2bd662Svikram if (lu) { 3509eb2bd662Svikram BAM_DPRINTF((D_FREEING_LU_SIGNS, fcn, lu)); 3510eb2bd662Svikram free(lu); 3511eb2bd662Svikram lu = NULL; 3512eb2bd662Svikram } 3513eb2bd662Svikram 3514eb2bd662Svikram return (zfs ? zfs : ufs); 3515eb2bd662Svikram } 3516eb2bd662Svikram 3517eb2bd662Svikram static char * 3518eb2bd662Svikram find_backup_common(char *mntpt, char *fstype) 3519eb2bd662Svikram { 3520eb2bd662Svikram FILE *bfp = NULL; 3521eb2bd662Svikram char tmpsign[MAXNAMELEN + 1]; 3522eb2bd662Svikram char backup[PATH_MAX]; 3523eb2bd662Svikram char *ufs; 3524eb2bd662Svikram char *zfs; 3525eb2bd662Svikram char *lu; 3526eb2bd662Svikram int error; 3527eb2bd662Svikram const char *fcn = "find_backup_common()"; 3528eb2bd662Svikram 3529eb2bd662Svikram /* 3530eb2bd662Svikram * We didn't find it in the primary directory. 3531eb2bd662Svikram * Look at the backup 3532eb2bd662Svikram */ 3533eb2bd662Svikram (void) snprintf(backup, sizeof (backup), "%s%s", 3534eb2bd662Svikram mntpt, GRUBSIGN_BACKUP); 3535eb2bd662Svikram 3536eb2bd662Svikram bfp = fopen(backup, "r"); 3537eb2bd662Svikram if (bfp == NULL) { 3538eb2bd662Svikram error = errno; 3539eb2bd662Svikram if (bam_verbose) { 3540eb2bd662Svikram bam_error(OPEN_FAIL, backup, strerror(error)); 3541eb2bd662Svikram } 3542eb2bd662Svikram BAM_DPRINTF((D_OPEN_FAIL, fcn, backup, strerror(error))); 3543eb2bd662Svikram return (NULL); 3544eb2bd662Svikram } 3545eb2bd662Svikram 3546eb2bd662Svikram ufs = zfs = lu = NULL; 3547eb2bd662Svikram 3548eb2bd662Svikram while (s_fgets(tmpsign, sizeof (tmpsign), bfp) != NULL) { 3549eb2bd662Svikram 3550eb2bd662Svikram if (lu == NULL && 3551eb2bd662Svikram strncmp(tmpsign, GRUBSIGN_LU_PREFIX, 3552eb2bd662Svikram strlen(GRUBSIGN_LU_PREFIX)) == 0) { 3553eb2bd662Svikram lu = s_strdup(tmpsign); 3554eb2bd662Svikram } 3555eb2bd662Svikram 3556eb2bd662Svikram if (ufs == NULL && 3557eb2bd662Svikram strncmp(tmpsign, GRUBSIGN_UFS_PREFIX, 3558eb2bd662Svikram strlen(GRUBSIGN_UFS_PREFIX)) == 0) { 3559eb2bd662Svikram ufs = s_strdup(tmpsign); 3560eb2bd662Svikram } 3561eb2bd662Svikram 3562eb2bd662Svikram if (zfs == NULL && 3563eb2bd662Svikram strncmp(tmpsign, GRUBSIGN_ZFS_PREFIX, 3564eb2bd662Svikram strlen(GRUBSIGN_ZFS_PREFIX)) == 0) { 3565eb2bd662Svikram zfs = s_strdup(tmpsign); 3566eb2bd662Svikram } 3567eb2bd662Svikram } 3568eb2bd662Svikram 3569eb2bd662Svikram BAM_DPRINTF((D_EXIST_BACKUP_SIGNS, fcn, 3570eb2bd662Svikram zfs ? zfs : "NULL", 3571eb2bd662Svikram ufs ? ufs : "NULL", 3572eb2bd662Svikram lu ? lu : "NULL")); 3573eb2bd662Svikram 3574eb2bd662Svikram if (bfp) { 3575eb2bd662Svikram (void) fclose(bfp); 3576eb2bd662Svikram bfp = NULL; 3577eb2bd662Svikram } 3578eb2bd662Svikram 3579eb2bd662Svikram if (strcmp(fstype, "ufs") == 0 && zfs) { 3580eb2bd662Svikram bam_error(SIGN_FSTYPE_MISMATCH, zfs, "ufs"); 3581eb2bd662Svikram free(zfs); 3582eb2bd662Svikram zfs = NULL; 3583eb2bd662Svikram } else if (strcmp(fstype, "zfs") == 0 && ufs) { 3584eb2bd662Svikram bam_error(SIGN_FSTYPE_MISMATCH, ufs, "zfs"); 3585eb2bd662Svikram free(ufs); 3586eb2bd662Svikram ufs = NULL; 3587eb2bd662Svikram } 3588eb2bd662Svikram 3589eb2bd662Svikram assert(bfp == NULL); 3590eb2bd662Svikram 3591eb2bd662Svikram /* For now, we let Live Upgrade take care of its signature itself */ 3592eb2bd662Svikram if (lu) { 3593eb2bd662Svikram BAM_DPRINTF((D_FREEING_LU_SIGNS, fcn, lu)); 3594eb2bd662Svikram free(lu); 3595eb2bd662Svikram lu = NULL; 3596eb2bd662Svikram } 3597eb2bd662Svikram 3598eb2bd662Svikram return (zfs ? zfs : ufs); 3599eb2bd662Svikram } 3600eb2bd662Svikram 3601eb2bd662Svikram static char * 3602eb2bd662Svikram find_ufs_existing(char *osroot) 3603eb2bd662Svikram { 3604eb2bd662Svikram char *sign; 3605eb2bd662Svikram const char *fcn = "find_ufs_existing()"; 3606eb2bd662Svikram 3607eb2bd662Svikram sign = find_primary_common(osroot, "ufs"); 3608eb2bd662Svikram if (sign == NULL) { 3609eb2bd662Svikram sign = find_backup_common(osroot, "ufs"); 3610eb2bd662Svikram BAM_DPRINTF((D_EXIST_BACKUP_SIGN, fcn, sign ? sign : "NULL")); 3611eb2bd662Svikram } else { 3612eb2bd662Svikram BAM_DPRINTF((D_EXIST_PRIMARY_SIGN, fcn, sign)); 3613eb2bd662Svikram } 3614eb2bd662Svikram 3615eb2bd662Svikram return (sign); 36167c478bd9Sstevel@tonic-gate } 36177c478bd9Sstevel@tonic-gate 3618ae115bc7Smrj char * 3619eb2bd662Svikram get_mountpoint(char *special, char *fstype) 36207c478bd9Sstevel@tonic-gate { 3621eb2bd662Svikram FILE *mntfp; 3622eb2bd662Svikram struct mnttab mp = {0}; 3623eb2bd662Svikram struct mnttab mpref = {0}; 3624eb2bd662Svikram int error; 3625eb2bd662Svikram int ret; 3626eb2bd662Svikram const char *fcn = "get_mountpoint()"; 3627eb2bd662Svikram 3628eb2bd662Svikram BAM_DPRINTF((D_FUNC_ENTRY2, fcn, special, fstype)); 36297c478bd9Sstevel@tonic-gate 36307c478bd9Sstevel@tonic-gate mntfp = fopen(MNTTAB, "r"); 3631eb2bd662Svikram error = errno; 3632eb2bd662Svikram INJECT_ERROR1("MNTTAB_ERR_GET_MNTPT", mntfp = NULL); 36337c478bd9Sstevel@tonic-gate if (mntfp == NULL) { 3634eb2bd662Svikram bam_error(OPEN_FAIL, MNTTAB, strerror(error)); 3635eb2bd662Svikram return (NULL); 36367c478bd9Sstevel@tonic-gate } 36377c478bd9Sstevel@tonic-gate 3638eb2bd662Svikram mpref.mnt_special = special; 3639eb2bd662Svikram mpref.mnt_fstype = fstype; 3640eb2bd662Svikram 3641eb2bd662Svikram ret = getmntany(mntfp, &mp, &mpref); 3642eb2bd662Svikram INJECT_ERROR1("GET_MOUNTPOINT_MNTANY", ret = 1); 3643eb2bd662Svikram if (ret != 0) { 36447c478bd9Sstevel@tonic-gate (void) fclose(mntfp); 3645eb2bd662Svikram BAM_DPRINTF((D_NO_MNTPT, fcn, special, fstype)); 36467c478bd9Sstevel@tonic-gate return (NULL); 36477c478bd9Sstevel@tonic-gate } 36487c478bd9Sstevel@tonic-gate (void) fclose(mntfp); 36497c478bd9Sstevel@tonic-gate 3650eb2bd662Svikram assert(mp.mnt_mountp); 3651eb2bd662Svikram 3652eb2bd662Svikram BAM_DPRINTF((D_GET_MOUNTPOINT_RET, fcn, special, mp.mnt_mountp)); 3653eb2bd662Svikram 3654eb2bd662Svikram return (s_strdup(mp.mnt_mountp)); 36557c478bd9Sstevel@tonic-gate } 36567c478bd9Sstevel@tonic-gate 3657eb2bd662Svikram /* 3658eb2bd662Svikram * Mounts a "legacy" top dataset (if needed) 3659eb2bd662Svikram * Returns: The mountpoint of the legacy top dataset or NULL on error 3660eb2bd662Svikram * mnted returns one of the above values defined for zfs_mnted_t 3661eb2bd662Svikram */ 3662eb2bd662Svikram static char * 3663eb2bd662Svikram mount_legacy_dataset(char *pool, zfs_mnted_t *mnted) 36647c478bd9Sstevel@tonic-gate { 3665eb2bd662Svikram char cmd[PATH_MAX]; 3666eb2bd662Svikram char tmpmnt[PATH_MAX]; 3667eb2bd662Svikram filelist_t flist = {0}; 3668eb2bd662Svikram char *is_mounted; 3669eb2bd662Svikram struct stat sb; 3670eb2bd662Svikram int ret; 3671eb2bd662Svikram const char *fcn = "mount_legacy_dataset()"; 36727c478bd9Sstevel@tonic-gate 3673eb2bd662Svikram BAM_DPRINTF((D_FUNC_ENTRY1, fcn, pool)); 3674eb2bd662Svikram 3675eb2bd662Svikram *mnted = ZFS_MNT_ERROR; 3676eb2bd662Svikram 3677eb2bd662Svikram (void) snprintf(cmd, sizeof (cmd), 3678eb2bd662Svikram "/sbin/zfs get -Ho value mounted %s", 3679eb2bd662Svikram pool); 3680eb2bd662Svikram 3681eb2bd662Svikram ret = exec_cmd(cmd, &flist); 3682eb2bd662Svikram INJECT_ERROR1("Z_MOUNT_LEG_GET_MOUNTED_CMD", ret = 1); 3683eb2bd662Svikram if (ret != 0) { 3684eb2bd662Svikram bam_error(ZFS_MNTED_FAILED, pool); 3685eb2bd662Svikram return (NULL); 3686eb2bd662Svikram } 3687eb2bd662Svikram 3688eb2bd662Svikram INJECT_ERROR1("Z_MOUNT_LEG_GET_MOUNTED_OUT", flist.head = NULL); 3689eb2bd662Svikram if ((flist.head == NULL) || (flist.head != flist.tail)) { 3690eb2bd662Svikram bam_error(BAD_ZFS_MNTED, pool); 3691eb2bd662Svikram filelist_free(&flist); 36927c478bd9Sstevel@tonic-gate return (NULL); 36937c478bd9Sstevel@tonic-gate } 3694eb2bd662Svikram 3695eb2bd662Svikram is_mounted = strtok(flist.head->line, " \t\n"); 3696eb2bd662Svikram INJECT_ERROR1("Z_MOUNT_LEG_GET_MOUNTED_STRTOK_YES", is_mounted = "yes"); 3697eb2bd662Svikram INJECT_ERROR1("Z_MOUNT_LEG_GET_MOUNTED_STRTOK_NO", is_mounted = "no"); 3698eb2bd662Svikram if (strcmp(is_mounted, "no") != 0) { 3699eb2bd662Svikram filelist_free(&flist); 3700eb2bd662Svikram *mnted = LEGACY_ALREADY; 3701eb2bd662Svikram /* get_mountpoint returns a strdup'ed string */ 3702eb2bd662Svikram BAM_DPRINTF((D_Z_MOUNT_TOP_LEG_ALREADY, fcn, pool)); 3703eb2bd662Svikram return (get_mountpoint(pool, "zfs")); 3704eb2bd662Svikram } 3705eb2bd662Svikram 3706eb2bd662Svikram filelist_free(&flist); 3707eb2bd662Svikram 3708eb2bd662Svikram /* 3709eb2bd662Svikram * legacy top dataset is not mounted. Mount it now 3710eb2bd662Svikram * First create a mountpoint. 3711eb2bd662Svikram */ 3712eb2bd662Svikram (void) snprintf(tmpmnt, sizeof (tmpmnt), "%s.%d", 3713eb2bd662Svikram ZFS_LEGACY_MNTPT, getpid()); 3714eb2bd662Svikram 3715eb2bd662Svikram ret = stat(tmpmnt, &sb); 3716eb2bd662Svikram if (ret == -1) { 3717eb2bd662Svikram BAM_DPRINTF((D_Z_MOUNT_TOP_LEG_MNTPT_ABS, fcn, pool, tmpmnt)); 3718eb2bd662Svikram ret = mkdirp(tmpmnt, 0755); 3719eb2bd662Svikram INJECT_ERROR1("Z_MOUNT_TOP_LEG_MNTPT_MKDIRP", ret = -1); 3720eb2bd662Svikram if (ret == -1) { 3721eb2bd662Svikram bam_error(MKDIR_FAILED, tmpmnt, strerror(errno)); 3722eb2bd662Svikram return (NULL); 3723eb2bd662Svikram } 3724eb2bd662Svikram } else { 3725eb2bd662Svikram BAM_DPRINTF((D_Z_MOUNT_TOP_LEG_MNTPT_PRES, fcn, pool, tmpmnt)); 3726eb2bd662Svikram } 3727eb2bd662Svikram 3728eb2bd662Svikram (void) snprintf(cmd, sizeof (cmd), 3729eb2bd662Svikram "/sbin/mount -F zfs %s %s", 3730eb2bd662Svikram pool, tmpmnt); 3731eb2bd662Svikram 3732eb2bd662Svikram ret = exec_cmd(cmd, NULL); 3733eb2bd662Svikram INJECT_ERROR1("Z_MOUNT_TOP_LEG_MOUNT_CMD", ret = 1); 3734eb2bd662Svikram if (ret != 0) { 3735eb2bd662Svikram bam_error(ZFS_MOUNT_FAILED, pool); 3736eb2bd662Svikram (void) rmdir(tmpmnt); 3737eb2bd662Svikram return (NULL); 3738eb2bd662Svikram } 3739eb2bd662Svikram 3740eb2bd662Svikram *mnted = LEGACY_MOUNTED; 3741eb2bd662Svikram BAM_DPRINTF((D_Z_MOUNT_TOP_LEG_MOUNTED, fcn, pool, tmpmnt)); 3742eb2bd662Svikram return (s_strdup(tmpmnt)); 3743eb2bd662Svikram } 3744eb2bd662Svikram 3745eb2bd662Svikram /* 3746eb2bd662Svikram * Mounts the top dataset (if needed) 3747eb2bd662Svikram * Returns: The mountpoint of the top dataset or NULL on error 3748eb2bd662Svikram * mnted returns one of the above values defined for zfs_mnted_t 3749eb2bd662Svikram */ 3750eb2bd662Svikram static char * 3751eb2bd662Svikram mount_top_dataset(char *pool, zfs_mnted_t *mnted) 3752eb2bd662Svikram { 3753eb2bd662Svikram char cmd[PATH_MAX]; 3754eb2bd662Svikram filelist_t flist = {0}; 3755eb2bd662Svikram char *is_mounted; 3756eb2bd662Svikram char *mntpt; 3757eb2bd662Svikram char *zmntpt; 3758eb2bd662Svikram int ret; 3759eb2bd662Svikram const char *fcn = "mount_top_dataset()"; 3760eb2bd662Svikram 3761eb2bd662Svikram *mnted = ZFS_MNT_ERROR; 3762eb2bd662Svikram 3763eb2bd662Svikram BAM_DPRINTF((D_FUNC_ENTRY1, fcn, pool)); 3764eb2bd662Svikram 3765eb2bd662Svikram /* 3766eb2bd662Svikram * First check if the top dataset is a "legacy" dataset 3767eb2bd662Svikram */ 3768eb2bd662Svikram (void) snprintf(cmd, sizeof (cmd), 3769eb2bd662Svikram "/sbin/zfs get -Ho value mountpoint %s", 3770eb2bd662Svikram pool); 3771eb2bd662Svikram ret = exec_cmd(cmd, &flist); 3772eb2bd662Svikram INJECT_ERROR1("Z_MOUNT_TOP_GET_MNTPT", ret = 1); 3773eb2bd662Svikram if (ret != 0) { 3774eb2bd662Svikram bam_error(ZFS_MNTPT_FAILED, pool); 3775eb2bd662Svikram return (NULL); 3776eb2bd662Svikram } 3777eb2bd662Svikram 3778eb2bd662Svikram if (flist.head && (flist.head == flist.tail)) { 3779eb2bd662Svikram char *legacy = strtok(flist.head->line, " \t\n"); 3780eb2bd662Svikram if (legacy && strcmp(legacy, "legacy") == 0) { 3781eb2bd662Svikram filelist_free(&flist); 3782eb2bd662Svikram BAM_DPRINTF((D_Z_IS_LEGACY, fcn, pool)); 3783eb2bd662Svikram return (mount_legacy_dataset(pool, mnted)); 3784eb2bd662Svikram } 3785eb2bd662Svikram } 3786eb2bd662Svikram 3787eb2bd662Svikram filelist_free(&flist); 3788eb2bd662Svikram 3789eb2bd662Svikram BAM_DPRINTF((D_Z_IS_NOT_LEGACY, fcn, pool)); 3790eb2bd662Svikram 3791eb2bd662Svikram (void) snprintf(cmd, sizeof (cmd), 3792eb2bd662Svikram "/sbin/zfs get -Ho value mounted %s", 3793eb2bd662Svikram pool); 3794eb2bd662Svikram 3795eb2bd662Svikram ret = exec_cmd(cmd, &flist); 3796eb2bd662Svikram INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MOUNTED", ret = 1); 3797eb2bd662Svikram if (ret != 0) { 3798eb2bd662Svikram bam_error(ZFS_MNTED_FAILED, pool); 3799eb2bd662Svikram return (NULL); 3800eb2bd662Svikram } 3801eb2bd662Svikram 3802eb2bd662Svikram INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MOUNTED_VAL", flist.head = NULL); 3803eb2bd662Svikram if ((flist.head == NULL) || (flist.head != flist.tail)) { 3804eb2bd662Svikram bam_error(BAD_ZFS_MNTED, pool); 3805eb2bd662Svikram filelist_free(&flist); 3806eb2bd662Svikram return (NULL); 3807eb2bd662Svikram } 3808eb2bd662Svikram 3809eb2bd662Svikram is_mounted = strtok(flist.head->line, " \t\n"); 3810eb2bd662Svikram INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MOUNTED_YES", is_mounted = "yes"); 3811eb2bd662Svikram INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MOUNTED_NO", is_mounted = "no"); 3812eb2bd662Svikram if (strcmp(is_mounted, "no") != 0) { 3813eb2bd662Svikram filelist_free(&flist); 3814eb2bd662Svikram *mnted = ZFS_ALREADY; 3815eb2bd662Svikram BAM_DPRINTF((D_Z_MOUNT_TOP_NONLEG_MOUNTED_ALREADY, fcn, pool)); 3816eb2bd662Svikram goto mounted; 3817eb2bd662Svikram } 3818eb2bd662Svikram 3819eb2bd662Svikram filelist_free(&flist); 3820eb2bd662Svikram BAM_DPRINTF((D_Z_MOUNT_TOP_NONLEG_MOUNTED_NOT_ALREADY, fcn, pool)); 3821eb2bd662Svikram 3822eb2bd662Svikram /* top dataset is not mounted. Mount it now */ 3823eb2bd662Svikram (void) snprintf(cmd, sizeof (cmd), 3824eb2bd662Svikram "/sbin/zfs mount %s", pool); 3825eb2bd662Svikram ret = exec_cmd(cmd, NULL); 3826eb2bd662Svikram INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_MOUNT_CMD", ret = 1); 3827eb2bd662Svikram if (ret != 0) { 3828eb2bd662Svikram bam_error(ZFS_MOUNT_FAILED, pool); 3829eb2bd662Svikram return (NULL); 3830eb2bd662Svikram } 3831eb2bd662Svikram *mnted = ZFS_MOUNTED; 3832eb2bd662Svikram BAM_DPRINTF((D_Z_MOUNT_TOP_NONLEG_MOUNTED_NOW, fcn, pool)); 3833eb2bd662Svikram /*FALLTHRU*/ 3834eb2bd662Svikram mounted: 3835eb2bd662Svikram /* 3836eb2bd662Svikram * Now get the mountpoint 3837eb2bd662Svikram */ 3838eb2bd662Svikram (void) snprintf(cmd, sizeof (cmd), 3839eb2bd662Svikram "/sbin/zfs get -Ho value mountpoint %s", 3840eb2bd662Svikram pool); 3841eb2bd662Svikram 3842eb2bd662Svikram ret = exec_cmd(cmd, &flist); 3843eb2bd662Svikram INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MNTPT_CMD", ret = 1); 3844eb2bd662Svikram if (ret != 0) { 3845eb2bd662Svikram bam_error(ZFS_MNTPT_FAILED, pool); 3846eb2bd662Svikram goto error; 3847eb2bd662Svikram } 3848eb2bd662Svikram 3849eb2bd662Svikram INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MNTPT_OUT", flist.head = NULL); 3850eb2bd662Svikram if ((flist.head == NULL) || (flist.head != flist.tail)) { 3851eb2bd662Svikram bam_error(NULL_ZFS_MNTPT, pool); 3852eb2bd662Svikram goto error; 3853eb2bd662Svikram } 3854eb2bd662Svikram 3855eb2bd662Svikram mntpt = strtok(flist.head->line, " \t\n"); 3856eb2bd662Svikram INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MNTPT_STRTOK", mntpt = "foo"); 3857eb2bd662Svikram if (*mntpt != '/') { 3858eb2bd662Svikram bam_error(BAD_ZFS_MNTPT, pool, mntpt); 3859eb2bd662Svikram goto error; 3860eb2bd662Svikram } 3861eb2bd662Svikram zmntpt = s_strdup(mntpt); 3862eb2bd662Svikram 3863eb2bd662Svikram filelist_free(&flist); 3864eb2bd662Svikram 3865eb2bd662Svikram BAM_DPRINTF((D_Z_MOUNT_TOP_NONLEG_MNTPT, fcn, pool, zmntpt)); 3866eb2bd662Svikram 3867eb2bd662Svikram return (zmntpt); 3868eb2bd662Svikram 3869eb2bd662Svikram error: 3870eb2bd662Svikram filelist_free(&flist); 3871eb2bd662Svikram (void) umount_top_dataset(pool, *mnted, NULL); 3872eb2bd662Svikram BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 3873eb2bd662Svikram return (NULL); 3874eb2bd662Svikram } 3875eb2bd662Svikram 3876eb2bd662Svikram static int 3877eb2bd662Svikram umount_top_dataset(char *pool, zfs_mnted_t mnted, char *mntpt) 3878eb2bd662Svikram { 3879eb2bd662Svikram char cmd[PATH_MAX]; 3880eb2bd662Svikram int ret; 3881eb2bd662Svikram const char *fcn = "umount_top_dataset()"; 3882eb2bd662Svikram 3883eb2bd662Svikram INJECT_ERROR1("Z_UMOUNT_TOP_INVALID_STATE", mnted = ZFS_MNT_ERROR); 3884eb2bd662Svikram switch (mnted) { 3885eb2bd662Svikram case LEGACY_ALREADY: 3886eb2bd662Svikram case ZFS_ALREADY: 3887eb2bd662Svikram /* nothing to do */ 3888eb2bd662Svikram BAM_DPRINTF((D_Z_UMOUNT_TOP_ALREADY_NOP, fcn, pool, 3889eb2bd662Svikram mntpt ? mntpt : "NULL")); 3890eb2bd662Svikram free(mntpt); 3891eb2bd662Svikram return (BAM_SUCCESS); 3892eb2bd662Svikram case LEGACY_MOUNTED: 3893eb2bd662Svikram (void) snprintf(cmd, sizeof (cmd), 3894eb2bd662Svikram "/sbin/umount %s", pool); 3895eb2bd662Svikram ret = exec_cmd(cmd, NULL); 3896eb2bd662Svikram INJECT_ERROR1("Z_UMOUNT_TOP_LEGACY_UMOUNT_FAIL", ret = 1); 3897eb2bd662Svikram if (ret != 0) { 3898eb2bd662Svikram bam_error(UMOUNT_FAILED, pool); 3899eb2bd662Svikram free(mntpt); 3900eb2bd662Svikram return (BAM_ERROR); 3901eb2bd662Svikram } 3902eb2bd662Svikram if (mntpt) 3903eb2bd662Svikram (void) rmdir(mntpt); 3904eb2bd662Svikram free(mntpt); 3905eb2bd662Svikram BAM_DPRINTF((D_Z_UMOUNT_TOP_LEGACY, fcn, pool)); 3906eb2bd662Svikram return (BAM_SUCCESS); 3907eb2bd662Svikram case ZFS_MOUNTED: 3908eb2bd662Svikram free(mntpt); 3909eb2bd662Svikram (void) snprintf(cmd, sizeof (cmd), 3910eb2bd662Svikram "/sbin/zfs unmount %s", pool); 3911eb2bd662Svikram ret = exec_cmd(cmd, NULL); 3912eb2bd662Svikram INJECT_ERROR1("Z_UMOUNT_TOP_NONLEG_UMOUNT_FAIL", ret = 1); 3913eb2bd662Svikram if (ret != 0) { 3914eb2bd662Svikram bam_error(UMOUNT_FAILED, pool); 3915eb2bd662Svikram return (BAM_ERROR); 3916eb2bd662Svikram } 3917eb2bd662Svikram BAM_DPRINTF((D_Z_UMOUNT_TOP_NONLEG, fcn, pool)); 3918eb2bd662Svikram return (BAM_SUCCESS); 3919eb2bd662Svikram default: 3920eb2bd662Svikram bam_error(INT_BAD_MNTSTATE, pool); 3921eb2bd662Svikram return (BAM_ERROR); 3922eb2bd662Svikram } 3923eb2bd662Svikram /*NOTREACHED*/ 3924eb2bd662Svikram } 3925eb2bd662Svikram 3926eb2bd662Svikram /* 3927eb2bd662Svikram * For ZFS, osdev can be one of two forms 3928eb2bd662Svikram * It can be a "special" file as seen in mnttab: rpool/ROOT/szboot_0402 3929eb2bd662Svikram * It can be a /dev/[r]dsk special file. We handle both instances 3930eb2bd662Svikram */ 3931eb2bd662Svikram static char * 3932eb2bd662Svikram get_pool(char *osdev) 3933eb2bd662Svikram { 3934eb2bd662Svikram char cmd[PATH_MAX]; 3935eb2bd662Svikram char buf[PATH_MAX]; 3936eb2bd662Svikram filelist_t flist = {0}; 3937eb2bd662Svikram char *pool; 3938eb2bd662Svikram char *cp; 3939eb2bd662Svikram char *slash; 3940eb2bd662Svikram int ret; 3941eb2bd662Svikram const char *fcn = "get_pool()"; 3942eb2bd662Svikram 3943eb2bd662Svikram INJECT_ERROR1("GET_POOL_OSDEV", osdev = NULL); 3944eb2bd662Svikram if (osdev == NULL) { 3945eb2bd662Svikram bam_error(GET_POOL_OSDEV_NULL); 3946eb2bd662Svikram return (NULL); 3947eb2bd662Svikram } 3948eb2bd662Svikram 3949eb2bd662Svikram BAM_DPRINTF((D_GET_POOL_OSDEV, fcn, osdev)); 3950eb2bd662Svikram 3951eb2bd662Svikram if (osdev[0] != '/') { 3952eb2bd662Svikram (void) strlcpy(buf, osdev, sizeof (buf)); 3953eb2bd662Svikram slash = strchr(buf, '/'); 3954eb2bd662Svikram if (slash) 3955eb2bd662Svikram *slash = '\0'; 3956eb2bd662Svikram pool = s_strdup(buf); 3957eb2bd662Svikram BAM_DPRINTF((D_GET_POOL_RET, fcn, pool)); 3958eb2bd662Svikram return (pool); 3959eb2bd662Svikram } else if (strncmp(osdev, "/dev/dsk/", strlen("/dev/dsk/")) != 0 && 3960eb2bd662Svikram strncmp(osdev, "/dev/rdsk/", strlen("/dev/rdsk/")) != 0) { 3961eb2bd662Svikram bam_error(GET_POOL_BAD_OSDEV, osdev); 3962eb2bd662Svikram return (NULL); 3963eb2bd662Svikram } 3964eb2bd662Svikram 3965eb2bd662Svikram (void) snprintf(cmd, sizeof (cmd), 3966eb2bd662Svikram "/usr/sbin/fstyp -a %s 2>/dev/null | /bin/grep '^name:'", 3967eb2bd662Svikram osdev); 3968eb2bd662Svikram 3969eb2bd662Svikram ret = exec_cmd(cmd, &flist); 3970eb2bd662Svikram INJECT_ERROR1("GET_POOL_FSTYP", ret = 1); 3971eb2bd662Svikram if (ret != 0) { 3972eb2bd662Svikram bam_error(FSTYP_A_FAILED, osdev); 3973eb2bd662Svikram return (NULL); 3974eb2bd662Svikram } 3975eb2bd662Svikram 3976eb2bd662Svikram INJECT_ERROR1("GET_POOL_FSTYP_OUT", flist.head = NULL); 3977eb2bd662Svikram if ((flist.head == NULL) || (flist.head != flist.tail)) { 3978eb2bd662Svikram bam_error(NULL_FSTYP_A, osdev); 3979eb2bd662Svikram filelist_free(&flist); 3980eb2bd662Svikram return (NULL); 3981eb2bd662Svikram } 3982eb2bd662Svikram 3983eb2bd662Svikram (void) strtok(flist.head->line, "'"); 3984eb2bd662Svikram cp = strtok(NULL, "'"); 3985eb2bd662Svikram INJECT_ERROR1("GET_POOL_FSTYP_STRTOK", cp = NULL); 3986eb2bd662Svikram if (cp == NULL) { 3987eb2bd662Svikram bam_error(BAD_FSTYP_A, osdev); 3988eb2bd662Svikram filelist_free(&flist); 3989eb2bd662Svikram return (NULL); 3990eb2bd662Svikram } 3991eb2bd662Svikram 3992eb2bd662Svikram pool = s_strdup(cp); 3993eb2bd662Svikram 3994eb2bd662Svikram filelist_free(&flist); 3995eb2bd662Svikram 3996eb2bd662Svikram BAM_DPRINTF((D_GET_POOL_RET, fcn, pool)); 3997eb2bd662Svikram 3998eb2bd662Svikram return (pool); 3999eb2bd662Svikram } 4000eb2bd662Svikram 4001eb2bd662Svikram static char * 4002eb2bd662Svikram find_zfs_existing(char *osdev) 4003eb2bd662Svikram { 4004eb2bd662Svikram char *pool; 4005eb2bd662Svikram zfs_mnted_t mnted; 4006eb2bd662Svikram char *mntpt; 4007eb2bd662Svikram char *sign; 4008eb2bd662Svikram const char *fcn = "find_zfs_existing()"; 4009eb2bd662Svikram 4010eb2bd662Svikram pool = get_pool(osdev); 4011eb2bd662Svikram INJECT_ERROR1("ZFS_FIND_EXIST_POOL", pool = NULL); 4012eb2bd662Svikram if (pool == NULL) { 4013eb2bd662Svikram bam_error(ZFS_GET_POOL_FAILED, osdev); 4014eb2bd662Svikram return (NULL); 4015eb2bd662Svikram } 4016eb2bd662Svikram 4017eb2bd662Svikram mntpt = mount_top_dataset(pool, &mnted); 4018eb2bd662Svikram INJECT_ERROR1("ZFS_FIND_EXIST_MOUNT_TOP", mntpt = NULL); 4019eb2bd662Svikram if (mntpt == NULL) { 4020eb2bd662Svikram bam_error(ZFS_MOUNT_TOP_DATASET_FAILED, pool); 4021eb2bd662Svikram free(pool); 4022eb2bd662Svikram return (NULL); 4023eb2bd662Svikram } 4024eb2bd662Svikram 4025eb2bd662Svikram sign = find_primary_common(mntpt, "zfs"); 4026eb2bd662Svikram if (sign == NULL) { 4027eb2bd662Svikram sign = find_backup_common(mntpt, "zfs"); 4028eb2bd662Svikram BAM_DPRINTF((D_EXIST_BACKUP_SIGN, fcn, sign ? sign : "NULL")); 4029eb2bd662Svikram } else { 4030eb2bd662Svikram BAM_DPRINTF((D_EXIST_PRIMARY_SIGN, fcn, sign)); 4031eb2bd662Svikram } 4032eb2bd662Svikram 4033eb2bd662Svikram (void) umount_top_dataset(pool, mnted, mntpt); 4034eb2bd662Svikram 4035eb2bd662Svikram free(pool); 4036eb2bd662Svikram 4037eb2bd662Svikram return (sign); 4038eb2bd662Svikram } 4039eb2bd662Svikram 4040eb2bd662Svikram static char * 4041eb2bd662Svikram find_existing_sign(char *osroot, char *osdev, char *fstype) 4042eb2bd662Svikram { 4043eb2bd662Svikram const char *fcn = "find_existing_sign()"; 4044eb2bd662Svikram 4045eb2bd662Svikram INJECT_ERROR1("FIND_EXIST_NOTSUP_FS", fstype = "foofs"); 4046eb2bd662Svikram if (strcmp(fstype, "ufs") == 0) { 4047eb2bd662Svikram BAM_DPRINTF((D_CHECK_UFS_EXIST_SIGN, fcn)); 4048eb2bd662Svikram return (find_ufs_existing(osroot)); 4049eb2bd662Svikram } else if (strcmp(fstype, "zfs") == 0) { 4050eb2bd662Svikram BAM_DPRINTF((D_CHECK_ZFS_EXIST_SIGN, fcn)); 4051eb2bd662Svikram return (find_zfs_existing(osdev)); 4052eb2bd662Svikram } else { 4053eb2bd662Svikram bam_error(GRUBSIGN_NOTSUP, fstype); 4054eb2bd662Svikram return (NULL); 4055eb2bd662Svikram } 4056eb2bd662Svikram } 4057eb2bd662Svikram 4058eb2bd662Svikram #define MH_HASH_SZ 16 4059eb2bd662Svikram 4060eb2bd662Svikram typedef enum { 4061eb2bd662Svikram MH_ERROR = -1, 4062eb2bd662Svikram MH_NOMATCH, 4063eb2bd662Svikram MH_MATCH 4064eb2bd662Svikram } mh_search_t; 4065eb2bd662Svikram 4066eb2bd662Svikram typedef struct mcache { 4067eb2bd662Svikram char *mc_special; 4068eb2bd662Svikram char *mc_mntpt; 4069eb2bd662Svikram char *mc_fstype; 4070eb2bd662Svikram struct mcache *mc_next; 4071eb2bd662Svikram } mcache_t; 4072eb2bd662Svikram 4073eb2bd662Svikram typedef struct mhash { 4074eb2bd662Svikram mcache_t *mh_hash[MH_HASH_SZ]; 4075eb2bd662Svikram } mhash_t; 4076eb2bd662Svikram 4077eb2bd662Svikram static int 4078eb2bd662Svikram mhash_fcn(char *key) 4079eb2bd662Svikram { 4080eb2bd662Svikram int i; 4081eb2bd662Svikram uint64_t sum = 0; 4082eb2bd662Svikram 4083eb2bd662Svikram for (i = 0; key[i] != '\0'; i++) { 4084eb2bd662Svikram sum += (uchar_t)key[i]; 4085eb2bd662Svikram } 4086eb2bd662Svikram 4087eb2bd662Svikram sum %= MH_HASH_SZ; 4088eb2bd662Svikram 4089eb2bd662Svikram assert(sum < MH_HASH_SZ); 4090eb2bd662Svikram 4091eb2bd662Svikram return (sum); 4092eb2bd662Svikram } 4093eb2bd662Svikram 4094eb2bd662Svikram static mhash_t * 4095eb2bd662Svikram cache_mnttab(void) 4096eb2bd662Svikram { 4097eb2bd662Svikram FILE *mfp; 4098eb2bd662Svikram struct extmnttab mnt; 4099eb2bd662Svikram mcache_t *mcp; 4100eb2bd662Svikram mhash_t *mhp; 4101eb2bd662Svikram char *ctds; 4102eb2bd662Svikram int idx; 4103eb2bd662Svikram int error; 4104eb2bd662Svikram char *special_dup; 4105eb2bd662Svikram const char *fcn = "cache_mnttab()"; 4106eb2bd662Svikram 4107eb2bd662Svikram mfp = fopen(MNTTAB, "r"); 4108eb2bd662Svikram error = errno; 4109eb2bd662Svikram INJECT_ERROR1("CACHE_MNTTAB_MNTTAB_ERR", mfp = NULL); 4110eb2bd662Svikram if (mfp == NULL) { 4111eb2bd662Svikram bam_error(OPEN_FAIL, MNTTAB, strerror(error)); 4112eb2bd662Svikram return (NULL); 4113eb2bd662Svikram } 4114eb2bd662Svikram 4115eb2bd662Svikram mhp = s_calloc(1, sizeof (mhash_t)); 4116eb2bd662Svikram 4117eb2bd662Svikram resetmnttab(mfp); 4118eb2bd662Svikram 4119eb2bd662Svikram while (getextmntent(mfp, &mnt, sizeof (mnt)) == 0) { 4120eb2bd662Svikram /* only cache ufs */ 4121eb2bd662Svikram if (strcmp(mnt.mnt_fstype, "ufs") != 0) 4122eb2bd662Svikram continue; 4123eb2bd662Svikram 4124eb2bd662Svikram /* basename() modifies its arg, so dup it */ 4125eb2bd662Svikram special_dup = s_strdup(mnt.mnt_special); 4126eb2bd662Svikram ctds = basename(special_dup); 4127eb2bd662Svikram 4128eb2bd662Svikram mcp = s_calloc(1, sizeof (mcache_t)); 4129eb2bd662Svikram mcp->mc_special = s_strdup(ctds); 4130eb2bd662Svikram mcp->mc_mntpt = s_strdup(mnt.mnt_mountp); 4131eb2bd662Svikram mcp->mc_fstype = s_strdup(mnt.mnt_fstype); 4132eb2bd662Svikram BAM_DPRINTF((D_CACHE_MNTS, fcn, ctds, 4133eb2bd662Svikram mnt.mnt_mountp, mnt.mnt_fstype)); 4134eb2bd662Svikram idx = mhash_fcn(ctds); 4135eb2bd662Svikram mcp->mc_next = mhp->mh_hash[idx]; 4136eb2bd662Svikram mhp->mh_hash[idx] = mcp; 4137eb2bd662Svikram free(special_dup); 4138eb2bd662Svikram } 4139eb2bd662Svikram 4140eb2bd662Svikram (void) fclose(mfp); 4141eb2bd662Svikram 4142eb2bd662Svikram return (mhp); 4143eb2bd662Svikram } 4144eb2bd662Svikram 4145eb2bd662Svikram static void 4146eb2bd662Svikram free_mnttab(mhash_t *mhp) 4147eb2bd662Svikram { 4148eb2bd662Svikram mcache_t *mcp; 4149eb2bd662Svikram int i; 4150eb2bd662Svikram 4151eb2bd662Svikram for (i = 0; i < MH_HASH_SZ; i++) { 4152eb2bd662Svikram /*LINTED*/ 4153eb2bd662Svikram while (mcp = mhp->mh_hash[i]) { 4154eb2bd662Svikram mhp->mh_hash[i] = mcp->mc_next; 4155eb2bd662Svikram free(mcp->mc_special); 4156eb2bd662Svikram free(mcp->mc_mntpt); 4157eb2bd662Svikram free(mcp->mc_fstype); 4158eb2bd662Svikram free(mcp); 4159eb2bd662Svikram } 4160eb2bd662Svikram } 4161eb2bd662Svikram 4162eb2bd662Svikram for (i = 0; i < MH_HASH_SZ; i++) { 4163eb2bd662Svikram assert(mhp->mh_hash[i] == NULL); 4164eb2bd662Svikram } 4165eb2bd662Svikram free(mhp); 4166eb2bd662Svikram } 4167eb2bd662Svikram 4168eb2bd662Svikram static mh_search_t 4169eb2bd662Svikram search_hash(mhash_t *mhp, char *special, char **mntpt) 4170eb2bd662Svikram { 4171eb2bd662Svikram int idx; 4172eb2bd662Svikram mcache_t *mcp; 4173eb2bd662Svikram const char *fcn = "search_hash()"; 4174eb2bd662Svikram 4175eb2bd662Svikram assert(mntpt); 4176eb2bd662Svikram 4177eb2bd662Svikram *mntpt = NULL; 4178eb2bd662Svikram 4179eb2bd662Svikram INJECT_ERROR1("SEARCH_HASH_FULL_PATH", special = "/foo"); 4180eb2bd662Svikram if (strchr(special, '/')) { 4181eb2bd662Svikram bam_error(INVALID_MHASH_KEY, special); 4182eb2bd662Svikram return (MH_ERROR); 4183eb2bd662Svikram } 4184eb2bd662Svikram 4185eb2bd662Svikram idx = mhash_fcn(special); 4186eb2bd662Svikram 4187eb2bd662Svikram for (mcp = mhp->mh_hash[idx]; mcp; mcp = mcp->mc_next) { 4188eb2bd662Svikram if (strcmp(mcp->mc_special, special) == 0) 4189eb2bd662Svikram break; 4190eb2bd662Svikram } 4191eb2bd662Svikram 4192eb2bd662Svikram if (mcp == NULL) { 4193eb2bd662Svikram BAM_DPRINTF((D_MNTTAB_HASH_NOMATCH, fcn, special)); 4194eb2bd662Svikram return (MH_NOMATCH); 4195eb2bd662Svikram } 4196eb2bd662Svikram 4197eb2bd662Svikram assert(strcmp(mcp->mc_fstype, "ufs") == 0); 4198eb2bd662Svikram *mntpt = mcp->mc_mntpt; 4199eb2bd662Svikram BAM_DPRINTF((D_MNTTAB_HASH_MATCH, fcn, special)); 4200eb2bd662Svikram return (MH_MATCH); 4201eb2bd662Svikram } 4202eb2bd662Svikram 4203eb2bd662Svikram static int 4204eb2bd662Svikram check_add_ufs_sign_to_list(FILE *tfp, char *mntpt) 4205eb2bd662Svikram { 4206eb2bd662Svikram char *sign; 4207eb2bd662Svikram char *signline; 4208eb2bd662Svikram char signbuf[MAXNAMELEN]; 4209eb2bd662Svikram int len; 4210eb2bd662Svikram int error; 4211eb2bd662Svikram const char *fcn = "check_add_ufs_sign_to_list()"; 4212eb2bd662Svikram 4213eb2bd662Svikram /* safe to specify NULL as "osdev" arg for UFS */ 4214eb2bd662Svikram sign = find_existing_sign(mntpt, NULL, "ufs"); 4215eb2bd662Svikram if (sign == NULL) { 4216eb2bd662Svikram /* No existing signature, nothing to add to list */ 4217eb2bd662Svikram BAM_DPRINTF((D_NO_SIGN_TO_LIST, fcn, mntpt)); 4218eb2bd662Svikram return (0); 4219eb2bd662Svikram } 4220eb2bd662Svikram 4221eb2bd662Svikram (void) snprintf(signbuf, sizeof (signbuf), "%s\n", sign); 4222eb2bd662Svikram signline = signbuf; 4223eb2bd662Svikram 4224eb2bd662Svikram INJECT_ERROR1("UFS_MNTPT_SIGN_NOTUFS", signline = "pool_rpool10\n"); 4225eb2bd662Svikram if (strncmp(signline, GRUBSIGN_UFS_PREFIX, 4226eb2bd662Svikram strlen(GRUBSIGN_UFS_PREFIX))) { 4227eb2bd662Svikram bam_error(INVALID_UFS_SIGNATURE, sign); 4228eb2bd662Svikram free(sign); 4229eb2bd662Svikram /* ignore invalid signatures */ 4230eb2bd662Svikram return (0); 4231eb2bd662Svikram } 4232eb2bd662Svikram 4233eb2bd662Svikram len = fputs(signline, tfp); 4234eb2bd662Svikram error = errno; 4235eb2bd662Svikram INJECT_ERROR1("SIGN_LIST_PUTS_ERROR", len = 0); 4236eb2bd662Svikram if (len != strlen(signline)) { 4237eb2bd662Svikram bam_error(SIGN_LIST_FPUTS_ERR, sign, strerror(error)); 4238eb2bd662Svikram free(sign); 4239eb2bd662Svikram return (-1); 4240eb2bd662Svikram } 4241eb2bd662Svikram 4242eb2bd662Svikram free(sign); 4243eb2bd662Svikram 4244eb2bd662Svikram BAM_DPRINTF((D_SIGN_LIST_PUTS_DONE, fcn, mntpt)); 4245eb2bd662Svikram return (0); 4246eb2bd662Svikram } 4247eb2bd662Svikram 4248eb2bd662Svikram /* 4249eb2bd662Svikram * slice is a basename not a full pathname 4250eb2bd662Svikram */ 4251eb2bd662Svikram static int 4252eb2bd662Svikram process_slice_common(char *slice, FILE *tfp, mhash_t *mhp, char *tmpmnt) 4253eb2bd662Svikram { 4254eb2bd662Svikram int ret; 4255eb2bd662Svikram char cmd[PATH_MAX]; 4256eb2bd662Svikram char path[PATH_MAX]; 4257eb2bd662Svikram struct stat sbuf; 4258eb2bd662Svikram char *mntpt; 4259eb2bd662Svikram filelist_t flist = {0}; 4260eb2bd662Svikram char *fstype; 4261eb2bd662Svikram char blkslice[PATH_MAX]; 4262eb2bd662Svikram const char *fcn = "process_slice_common()"; 4263eb2bd662Svikram 4264eb2bd662Svikram 4265eb2bd662Svikram ret = search_hash(mhp, slice, &mntpt); 4266eb2bd662Svikram switch (ret) { 4267eb2bd662Svikram case MH_MATCH: 4268eb2bd662Svikram if (check_add_ufs_sign_to_list(tfp, mntpt) == -1) 4269eb2bd662Svikram return (-1); 4270eb2bd662Svikram else 4271eb2bd662Svikram return (0); 4272eb2bd662Svikram case MH_NOMATCH: 4273eb2bd662Svikram break; 4274eb2bd662Svikram case MH_ERROR: 4275eb2bd662Svikram default: 4276eb2bd662Svikram return (-1); 4277eb2bd662Svikram } 4278eb2bd662Svikram 4279eb2bd662Svikram (void) snprintf(path, sizeof (path), "/dev/rdsk/%s", slice); 4280eb2bd662Svikram if (stat(path, &sbuf) == -1) { 4281eb2bd662Svikram BAM_DPRINTF((D_SLICE_ENOENT, fcn, path)); 4282eb2bd662Svikram return (0); 4283eb2bd662Svikram } 4284eb2bd662Svikram 4285eb2bd662Svikram /* Check if ufs */ 4286eb2bd662Svikram (void) snprintf(cmd, sizeof (cmd), 4287eb2bd662Svikram "/usr/sbin/fstyp /dev/rdsk/%s 2>/dev/null", 4288eb2bd662Svikram slice); 4289eb2bd662Svikram 4290eb2bd662Svikram if (exec_cmd(cmd, &flist) != 0) { 4291eb2bd662Svikram if (bam_verbose) 4292eb2bd662Svikram bam_print(FSTYP_FAILED, slice); 4293eb2bd662Svikram return (0); 4294eb2bd662Svikram } 4295eb2bd662Svikram 4296eb2bd662Svikram if ((flist.head == NULL) || (flist.head != flist.tail)) { 4297eb2bd662Svikram if (bam_verbose) 4298eb2bd662Svikram bam_print(FSTYP_BAD, slice); 4299eb2bd662Svikram filelist_free(&flist); 4300eb2bd662Svikram return (0); 4301eb2bd662Svikram } 4302eb2bd662Svikram 4303eb2bd662Svikram fstype = strtok(flist.head->line, " \t\n"); 4304eb2bd662Svikram if (fstype == NULL || strcmp(fstype, "ufs") != 0) { 4305eb2bd662Svikram if (bam_verbose) 4306eb2bd662Svikram bam_print(NOT_UFS_SLICE, slice, fstype); 4307eb2bd662Svikram filelist_free(&flist); 4308eb2bd662Svikram return (0); 4309eb2bd662Svikram } 4310eb2bd662Svikram 4311eb2bd662Svikram filelist_free(&flist); 4312eb2bd662Svikram 4313eb2bd662Svikram /* 4314eb2bd662Svikram * Since we are mounting the filesystem read-only, the 4315eb2bd662Svikram * the last mount field of the superblock is unchanged 4316eb2bd662Svikram * and does not need to be fixed up post-mount; 4317eb2bd662Svikram */ 4318eb2bd662Svikram 4319eb2bd662Svikram (void) snprintf(blkslice, sizeof (blkslice), "/dev/dsk/%s", 4320eb2bd662Svikram slice); 4321eb2bd662Svikram 4322eb2bd662Svikram (void) snprintf(cmd, sizeof (cmd), 4323eb2bd662Svikram "/usr/sbin/mount -F ufs -o ro %s %s " 4324eb2bd662Svikram "> /dev/null 2>&1", blkslice, tmpmnt); 4325eb2bd662Svikram 4326eb2bd662Svikram if (exec_cmd(cmd, NULL) != 0) { 4327eb2bd662Svikram if (bam_verbose) 4328eb2bd662Svikram bam_print(MOUNT_FAILED, blkslice, "ufs"); 4329eb2bd662Svikram return (0); 4330eb2bd662Svikram } 4331eb2bd662Svikram 4332eb2bd662Svikram ret = check_add_ufs_sign_to_list(tfp, tmpmnt); 4333eb2bd662Svikram 4334eb2bd662Svikram (void) snprintf(cmd, sizeof (cmd), 4335eb2bd662Svikram "/usr/sbin/umount -f %s > /dev/null 2>&1", 4336eb2bd662Svikram tmpmnt); 4337eb2bd662Svikram 4338eb2bd662Svikram if (exec_cmd(cmd, NULL) != 0) { 4339eb2bd662Svikram bam_print(UMOUNT_FAILED, slice); 4340eb2bd662Svikram return (0); 4341eb2bd662Svikram } 4342eb2bd662Svikram 4343eb2bd662Svikram return (ret); 4344eb2bd662Svikram } 4345eb2bd662Svikram 4346eb2bd662Svikram static int 4347eb2bd662Svikram process_vtoc_slices( 4348eb2bd662Svikram char *s0, 4349eb2bd662Svikram struct vtoc *vtoc, 4350eb2bd662Svikram FILE *tfp, 4351eb2bd662Svikram mhash_t *mhp, 4352eb2bd662Svikram char *tmpmnt) 4353eb2bd662Svikram { 4354eb2bd662Svikram int idx; 4355eb2bd662Svikram char slice[PATH_MAX]; 4356eb2bd662Svikram size_t len; 4357eb2bd662Svikram char *cp; 4358eb2bd662Svikram const char *fcn = "process_vtoc_slices()"; 4359eb2bd662Svikram 4360eb2bd662Svikram len = strlen(s0); 4361eb2bd662Svikram 4362eb2bd662Svikram assert(s0[len - 2] == 's' && s0[len - 1] == '0'); 4363eb2bd662Svikram 4364eb2bd662Svikram s0[len - 1] = '\0'; 4365eb2bd662Svikram 4366eb2bd662Svikram (void) strlcpy(slice, s0, sizeof (slice)); 4367eb2bd662Svikram 4368eb2bd662Svikram s0[len - 1] = '0'; 4369eb2bd662Svikram 4370eb2bd662Svikram cp = slice + len - 1; 4371eb2bd662Svikram 4372eb2bd662Svikram for (idx = 0; idx < vtoc->v_nparts; idx++) { 4373eb2bd662Svikram 4374eb2bd662Svikram (void) snprintf(cp, sizeof (slice) - (len - 1), "%u", idx); 4375eb2bd662Svikram 4376eb2bd662Svikram if (vtoc->v_part[idx].p_size == 0) { 4377eb2bd662Svikram BAM_DPRINTF((D_VTOC_SIZE_ZERO, fcn, slice)); 4378eb2bd662Svikram continue; 4379eb2bd662Svikram } 4380eb2bd662Svikram 4381eb2bd662Svikram /* Skip "SWAP", "USR", "BACKUP", "VAR", "HOME", "ALTSCTR" */ 4382eb2bd662Svikram switch (vtoc->v_part[idx].p_tag) { 4383eb2bd662Svikram case V_SWAP: 4384eb2bd662Svikram case V_USR: 4385eb2bd662Svikram case V_BACKUP: 4386eb2bd662Svikram case V_VAR: 4387eb2bd662Svikram case V_HOME: 4388eb2bd662Svikram case V_ALTSCTR: 4389eb2bd662Svikram BAM_DPRINTF((D_VTOC_NOT_ROOT_TAG, fcn, slice)); 4390eb2bd662Svikram continue; 4391eb2bd662Svikram default: 4392eb2bd662Svikram BAM_DPRINTF((D_VTOC_ROOT_TAG, fcn, slice)); 4393eb2bd662Svikram break; 4394eb2bd662Svikram } 4395eb2bd662Svikram 4396eb2bd662Svikram /* skip unmountable and readonly slices */ 4397eb2bd662Svikram switch (vtoc->v_part[idx].p_flag) { 4398eb2bd662Svikram case V_UNMNT: 4399eb2bd662Svikram case V_RONLY: 4400eb2bd662Svikram BAM_DPRINTF((D_VTOC_NOT_RDWR_FLAG, fcn, slice)); 4401eb2bd662Svikram continue; 4402eb2bd662Svikram default: 4403eb2bd662Svikram BAM_DPRINTF((D_VTOC_RDWR_FLAG, fcn, slice)); 4404eb2bd662Svikram break; 4405eb2bd662Svikram } 4406eb2bd662Svikram 4407eb2bd662Svikram if (process_slice_common(slice, tfp, mhp, tmpmnt) == -1) { 4408eb2bd662Svikram return (-1); 4409eb2bd662Svikram } 4410eb2bd662Svikram } 4411eb2bd662Svikram 4412eb2bd662Svikram return (0); 4413eb2bd662Svikram } 4414eb2bd662Svikram 4415eb2bd662Svikram static int 4416eb2bd662Svikram process_efi_slices( 4417eb2bd662Svikram char *s0, 4418eb2bd662Svikram struct dk_gpt *efi, 4419eb2bd662Svikram FILE *tfp, 4420eb2bd662Svikram mhash_t *mhp, 4421eb2bd662Svikram char *tmpmnt) 4422eb2bd662Svikram { 4423eb2bd662Svikram int idx; 4424eb2bd662Svikram char slice[PATH_MAX]; 4425eb2bd662Svikram size_t len; 4426eb2bd662Svikram char *cp; 4427eb2bd662Svikram const char *fcn = "process_efi_slices()"; 4428eb2bd662Svikram 4429eb2bd662Svikram len = strlen(s0); 4430eb2bd662Svikram 4431eb2bd662Svikram assert(s0[len - 2] == 's' && s0[len - 1] == '0'); 4432eb2bd662Svikram 4433eb2bd662Svikram s0[len - 1] = '\0'; 4434eb2bd662Svikram 4435eb2bd662Svikram (void) strlcpy(slice, s0, sizeof (slice)); 4436eb2bd662Svikram 4437eb2bd662Svikram s0[len - 1] = '0'; 4438eb2bd662Svikram 4439eb2bd662Svikram cp = slice + len - 1; 4440eb2bd662Svikram 4441eb2bd662Svikram for (idx = 0; idx < efi->efi_nparts; idx++) { 4442eb2bd662Svikram 4443eb2bd662Svikram (void) snprintf(cp, sizeof (slice) - (len - 1), "%u", idx); 4444eb2bd662Svikram 4445eb2bd662Svikram if (efi->efi_parts[idx].p_size == 0) { 4446eb2bd662Svikram BAM_DPRINTF((D_EFI_SIZE_ZERO, fcn, slice)); 4447eb2bd662Svikram continue; 4448eb2bd662Svikram } 4449eb2bd662Svikram 4450eb2bd662Svikram /* Skip "SWAP", "USR", "BACKUP", "VAR", "HOME", "ALTSCTR" */ 4451eb2bd662Svikram switch (efi->efi_parts[idx].p_tag) { 4452eb2bd662Svikram case V_SWAP: 4453eb2bd662Svikram case V_USR: 4454eb2bd662Svikram case V_BACKUP: 4455eb2bd662Svikram case V_VAR: 4456eb2bd662Svikram case V_HOME: 4457eb2bd662Svikram case V_ALTSCTR: 4458eb2bd662Svikram BAM_DPRINTF((D_EFI_NOT_ROOT_TAG, fcn, slice)); 4459eb2bd662Svikram continue; 4460eb2bd662Svikram default: 4461eb2bd662Svikram BAM_DPRINTF((D_EFI_ROOT_TAG, fcn, slice)); 4462eb2bd662Svikram break; 4463eb2bd662Svikram } 4464eb2bd662Svikram 4465eb2bd662Svikram /* skip unmountable and readonly slices */ 4466eb2bd662Svikram switch (efi->efi_parts[idx].p_flag) { 4467eb2bd662Svikram case V_UNMNT: 4468eb2bd662Svikram case V_RONLY: 4469eb2bd662Svikram BAM_DPRINTF((D_EFI_NOT_RDWR_FLAG, fcn, slice)); 4470eb2bd662Svikram continue; 4471eb2bd662Svikram default: 4472eb2bd662Svikram BAM_DPRINTF((D_EFI_RDWR_FLAG, fcn, slice)); 4473eb2bd662Svikram break; 4474eb2bd662Svikram } 4475eb2bd662Svikram 4476eb2bd662Svikram if (process_slice_common(slice, tfp, mhp, tmpmnt) == -1) { 4477eb2bd662Svikram return (-1); 4478eb2bd662Svikram } 4479eb2bd662Svikram } 4480eb2bd662Svikram 4481eb2bd662Svikram return (0); 4482eb2bd662Svikram } 4483eb2bd662Svikram 4484eb2bd662Svikram /* 4485eb2bd662Svikram * s0 is a basename not a full path 4486eb2bd662Svikram */ 4487eb2bd662Svikram static int 4488eb2bd662Svikram process_slice0(char *s0, FILE *tfp, mhash_t *mhp, char *tmpmnt) 4489eb2bd662Svikram { 4490eb2bd662Svikram struct vtoc vtoc; 4491eb2bd662Svikram struct dk_gpt *efi; 4492eb2bd662Svikram char s0path[PATH_MAX]; 4493eb2bd662Svikram struct stat sbuf; 4494eb2bd662Svikram int e_flag; 4495eb2bd662Svikram int v_flag; 4496eb2bd662Svikram int retval; 4497eb2bd662Svikram int err; 4498eb2bd662Svikram int fd; 4499eb2bd662Svikram const char *fcn = "process_slice0()"; 4500eb2bd662Svikram 4501eb2bd662Svikram (void) snprintf(s0path, sizeof (s0path), "/dev/rdsk/%s", s0); 4502eb2bd662Svikram 4503eb2bd662Svikram if (stat(s0path, &sbuf) == -1) { 4504eb2bd662Svikram BAM_DPRINTF((D_SLICE0_ENOENT, fcn, s0path)); 4505eb2bd662Svikram return (0); 4506eb2bd662Svikram } 4507eb2bd662Svikram 4508eb2bd662Svikram fd = open(s0path, O_NONBLOCK|O_RDONLY); 4509eb2bd662Svikram if (fd == -1) { 4510eb2bd662Svikram bam_error(OPEN_FAIL, s0path, strerror(errno)); 4511eb2bd662Svikram return (0); 4512eb2bd662Svikram } 4513eb2bd662Svikram 4514eb2bd662Svikram e_flag = v_flag = 0; 4515eb2bd662Svikram retval = ((err = read_vtoc(fd, &vtoc)) >= 0) ? 0 : err; 4516eb2bd662Svikram switch (retval) { 4517eb2bd662Svikram case VT_EIO: 4518eb2bd662Svikram BAM_DPRINTF((D_VTOC_READ_FAIL, fcn, s0path)); 4519eb2bd662Svikram break; 4520eb2bd662Svikram case VT_EINVAL: 4521eb2bd662Svikram BAM_DPRINTF((D_VTOC_INVALID, fcn, s0path)); 4522eb2bd662Svikram break; 4523eb2bd662Svikram case VT_ERROR: 4524eb2bd662Svikram BAM_DPRINTF((D_VTOC_UNKNOWN_ERR, fcn, s0path)); 4525eb2bd662Svikram break; 4526eb2bd662Svikram case VT_ENOTSUP: 4527eb2bd662Svikram e_flag = 1; 4528eb2bd662Svikram BAM_DPRINTF((D_VTOC_NOTSUP, fcn, s0path)); 4529eb2bd662Svikram break; 4530eb2bd662Svikram case 0: 4531eb2bd662Svikram v_flag = 1; 4532eb2bd662Svikram BAM_DPRINTF((D_VTOC_READ_SUCCESS, fcn, s0path)); 4533eb2bd662Svikram break; 4534eb2bd662Svikram default: 4535eb2bd662Svikram BAM_DPRINTF((D_VTOC_UNKNOWN_RETCODE, fcn, s0path)); 4536eb2bd662Svikram break; 4537eb2bd662Svikram } 4538eb2bd662Svikram 4539eb2bd662Svikram 4540eb2bd662Svikram if (e_flag) { 4541eb2bd662Svikram e_flag = 0; 4542eb2bd662Svikram retval = ((err = efi_alloc_and_read(fd, &efi)) >= 0) ? 0 : err; 4543eb2bd662Svikram switch (retval) { 4544eb2bd662Svikram case VT_EIO: 4545eb2bd662Svikram BAM_DPRINTF((D_EFI_READ_FAIL, fcn, s0path)); 4546eb2bd662Svikram break; 4547eb2bd662Svikram case VT_EINVAL: 4548eb2bd662Svikram BAM_DPRINTF((D_EFI_INVALID, fcn, s0path)); 4549eb2bd662Svikram break; 4550eb2bd662Svikram case VT_ERROR: 4551eb2bd662Svikram BAM_DPRINTF((D_EFI_UNKNOWN_ERR, fcn, s0path)); 4552eb2bd662Svikram break; 4553eb2bd662Svikram case VT_ENOTSUP: 4554eb2bd662Svikram BAM_DPRINTF((D_EFI_NOTSUP, fcn, s0path)); 4555eb2bd662Svikram break; 4556eb2bd662Svikram case 0: 4557eb2bd662Svikram e_flag = 1; 4558eb2bd662Svikram BAM_DPRINTF((D_EFI_READ_SUCCESS, fcn, s0path)); 4559eb2bd662Svikram break; 4560eb2bd662Svikram default: 4561eb2bd662Svikram BAM_DPRINTF((D_EFI_UNKNOWN_RETCODE, fcn, s0path)); 4562eb2bd662Svikram break; 4563eb2bd662Svikram } 4564eb2bd662Svikram } 4565eb2bd662Svikram 4566eb2bd662Svikram (void) close(fd); 4567eb2bd662Svikram 4568eb2bd662Svikram if (v_flag) { 4569eb2bd662Svikram retval = process_vtoc_slices(s0, 4570eb2bd662Svikram &vtoc, tfp, mhp, tmpmnt); 4571eb2bd662Svikram } else if (e_flag) { 4572eb2bd662Svikram retval = process_efi_slices(s0, 4573eb2bd662Svikram efi, tfp, mhp, tmpmnt); 4574eb2bd662Svikram } else { 4575eb2bd662Svikram BAM_DPRINTF((D_NOT_VTOC_OR_EFI, fcn, s0path)); 4576eb2bd662Svikram return (0); 4577eb2bd662Svikram } 4578eb2bd662Svikram 4579eb2bd662Svikram return (retval); 4580eb2bd662Svikram } 4581eb2bd662Svikram 4582eb2bd662Svikram /* 4583eb2bd662Svikram * Find and create a list of all existing UFS boot signatures 4584eb2bd662Svikram */ 4585eb2bd662Svikram static int 4586eb2bd662Svikram FindAllUfsSignatures(void) 4587eb2bd662Svikram { 4588eb2bd662Svikram mhash_t *mnttab_hash; 4589eb2bd662Svikram DIR *dirp = NULL; 4590eb2bd662Svikram struct dirent *dp; 4591eb2bd662Svikram char tmpmnt[PATH_MAX]; 4592eb2bd662Svikram char cmd[PATH_MAX]; 4593eb2bd662Svikram struct stat sb; 4594eb2bd662Svikram int fd; 4595eb2bd662Svikram FILE *tfp; 4596eb2bd662Svikram size_t len; 4597eb2bd662Svikram int ret; 4598eb2bd662Svikram int error; 4599eb2bd662Svikram const char *fcn = "FindAllUfsSignatures()"; 4600eb2bd662Svikram 4601eb2bd662Svikram if (stat(UFS_SIGNATURE_LIST, &sb) != -1) { 4602eb2bd662Svikram bam_print(SIGNATURE_LIST_EXISTS, UFS_SIGNATURE_LIST); 4603eb2bd662Svikram return (0); 4604eb2bd662Svikram } 4605eb2bd662Svikram 4606eb2bd662Svikram fd = open(UFS_SIGNATURE_LIST".tmp", 4607eb2bd662Svikram O_RDWR|O_CREAT|O_TRUNC, 0644); 4608eb2bd662Svikram error = errno; 4609eb2bd662Svikram INJECT_ERROR1("SIGN_LIST_TMP_TRUNC", fd = -1); 4610eb2bd662Svikram if (fd == -1) { 4611eb2bd662Svikram bam_error(OPEN_FAIL, UFS_SIGNATURE_LIST".tmp", strerror(error)); 4612eb2bd662Svikram return (-1); 4613eb2bd662Svikram } 4614eb2bd662Svikram 4615eb2bd662Svikram ret = close(fd); 4616eb2bd662Svikram error = errno; 4617eb2bd662Svikram INJECT_ERROR1("SIGN_LIST_TMP_CLOSE", ret = -1); 4618eb2bd662Svikram if (ret == -1) { 4619eb2bd662Svikram bam_error(CLOSE_FAIL, UFS_SIGNATURE_LIST".tmp", 4620eb2bd662Svikram strerror(error)); 4621eb2bd662Svikram (void) unlink(UFS_SIGNATURE_LIST".tmp"); 4622eb2bd662Svikram return (-1); 4623eb2bd662Svikram } 4624eb2bd662Svikram 4625eb2bd662Svikram tfp = fopen(UFS_SIGNATURE_LIST".tmp", "a"); 4626eb2bd662Svikram error = errno; 4627eb2bd662Svikram INJECT_ERROR1("SIGN_LIST_APPEND_FOPEN", tfp = NULL); 4628eb2bd662Svikram if (tfp == NULL) { 4629eb2bd662Svikram bam_error(OPEN_FAIL, UFS_SIGNATURE_LIST".tmp", strerror(error)); 4630eb2bd662Svikram (void) unlink(UFS_SIGNATURE_LIST".tmp"); 4631eb2bd662Svikram return (-1); 4632eb2bd662Svikram } 4633eb2bd662Svikram 4634eb2bd662Svikram mnttab_hash = cache_mnttab(); 4635eb2bd662Svikram INJECT_ERROR1("CACHE_MNTTAB_ERROR", mnttab_hash = NULL); 4636eb2bd662Svikram if (mnttab_hash == NULL) { 4637eb2bd662Svikram (void) fclose(tfp); 4638eb2bd662Svikram (void) unlink(UFS_SIGNATURE_LIST".tmp"); 4639eb2bd662Svikram bam_error(CACHE_MNTTAB_FAIL, fcn); 4640eb2bd662Svikram return (-1); 4641eb2bd662Svikram } 4642eb2bd662Svikram 4643eb2bd662Svikram (void) snprintf(tmpmnt, sizeof (tmpmnt), 4644eb2bd662Svikram "/tmp/bootadm_ufs_sign_mnt.%d", getpid()); 4645eb2bd662Svikram (void) unlink(tmpmnt); 4646eb2bd662Svikram 4647eb2bd662Svikram ret = mkdirp(tmpmnt, 0755); 4648eb2bd662Svikram error = errno; 4649eb2bd662Svikram INJECT_ERROR1("MKDIRP_SIGN_MNT", ret = -1); 4650eb2bd662Svikram if (ret == -1) { 4651eb2bd662Svikram bam_error(MKDIR_FAILED, tmpmnt, strerror(error)); 4652eb2bd662Svikram free_mnttab(mnttab_hash); 4653eb2bd662Svikram (void) fclose(tfp); 4654eb2bd662Svikram (void) unlink(UFS_SIGNATURE_LIST".tmp"); 4655eb2bd662Svikram return (-1); 4656eb2bd662Svikram } 4657eb2bd662Svikram 4658eb2bd662Svikram dirp = opendir("/dev/rdsk"); 4659eb2bd662Svikram error = errno; 4660eb2bd662Svikram INJECT_ERROR1("OPENDIR_DEV_RDSK", dirp = NULL); 4661eb2bd662Svikram if (dirp == NULL) { 4662eb2bd662Svikram bam_error(OPENDIR_FAILED, "/dev/rdsk", strerror(error)); 4663eb2bd662Svikram goto fail; 4664eb2bd662Svikram } 4665eb2bd662Svikram 4666eb2bd662Svikram while (dp = readdir(dirp)) { 4667eb2bd662Svikram if (strcmp(dp->d_name, ".") == 0 || 4668eb2bd662Svikram strcmp(dp->d_name, "..") == 0) 4669eb2bd662Svikram continue; 4670eb2bd662Svikram 4671eb2bd662Svikram /* 4672eb2bd662Svikram * we only look for the s0 slice. This is guranteed to 4673eb2bd662Svikram * have 's' at len - 2. 4674eb2bd662Svikram */ 4675eb2bd662Svikram len = strlen(dp->d_name); 4676eb2bd662Svikram if (dp->d_name[len - 2 ] != 's' || dp->d_name[len - 1] != '0') { 4677eb2bd662Svikram BAM_DPRINTF((D_SKIP_SLICE_NOTZERO, fcn, dp->d_name)); 4678eb2bd662Svikram continue; 4679eb2bd662Svikram } 4680eb2bd662Svikram 4681eb2bd662Svikram ret = process_slice0(dp->d_name, tfp, mnttab_hash, tmpmnt); 4682eb2bd662Svikram INJECT_ERROR1("PROCESS_S0_FAIL", ret = -1); 4683eb2bd662Svikram if (ret == -1) 4684eb2bd662Svikram goto fail; 4685eb2bd662Svikram } 4686eb2bd662Svikram 4687eb2bd662Svikram (void) closedir(dirp); 4688eb2bd662Svikram free_mnttab(mnttab_hash); 4689eb2bd662Svikram (void) rmdir(tmpmnt); 4690eb2bd662Svikram 4691eb2bd662Svikram ret = fclose(tfp); 4692eb2bd662Svikram error = errno; 4693eb2bd662Svikram INJECT_ERROR1("FCLOSE_SIGNLIST_TMP", ret = EOF); 4694eb2bd662Svikram if (ret == EOF) { 4695eb2bd662Svikram bam_error(CLOSE_FAIL, UFS_SIGNATURE_LIST".tmp", 4696eb2bd662Svikram strerror(error)); 4697eb2bd662Svikram (void) unlink(UFS_SIGNATURE_LIST".tmp"); 4698eb2bd662Svikram return (-1); 4699eb2bd662Svikram } 4700eb2bd662Svikram 4701eb2bd662Svikram /* We have a list of existing GRUB signatures. Sort it first */ 4702eb2bd662Svikram (void) snprintf(cmd, sizeof (cmd), 4703eb2bd662Svikram "/usr/bin/sort -u %s.tmp > %s.sorted", 4704eb2bd662Svikram UFS_SIGNATURE_LIST, UFS_SIGNATURE_LIST); 4705eb2bd662Svikram 4706eb2bd662Svikram ret = exec_cmd(cmd, NULL); 4707eb2bd662Svikram INJECT_ERROR1("SORT_SIGN_LIST", ret = 1); 4708eb2bd662Svikram if (ret != 0) { 4709eb2bd662Svikram bam_error(GRUBSIGN_SORT_FAILED); 4710eb2bd662Svikram (void) unlink(UFS_SIGNATURE_LIST".sorted"); 4711eb2bd662Svikram (void) unlink(UFS_SIGNATURE_LIST".tmp"); 4712eb2bd662Svikram return (-1); 4713eb2bd662Svikram } 4714eb2bd662Svikram 4715eb2bd662Svikram (void) unlink(UFS_SIGNATURE_LIST".tmp"); 4716eb2bd662Svikram 4717eb2bd662Svikram ret = rename(UFS_SIGNATURE_LIST".sorted", UFS_SIGNATURE_LIST); 4718eb2bd662Svikram error = errno; 4719eb2bd662Svikram INJECT_ERROR1("RENAME_TMP_SIGNLIST", ret = -1); 4720eb2bd662Svikram if (ret == -1) { 4721eb2bd662Svikram bam_error(RENAME_FAIL, UFS_SIGNATURE_LIST, strerror(error)); 4722eb2bd662Svikram (void) unlink(UFS_SIGNATURE_LIST".sorted"); 4723eb2bd662Svikram return (-1); 4724eb2bd662Svikram } 4725eb2bd662Svikram 4726eb2bd662Svikram if (stat(UFS_SIGNATURE_LIST, &sb) == 0 && sb.st_size == 0) { 4727eb2bd662Svikram BAM_DPRINTF((D_ZERO_LEN_SIGNLIST, fcn, UFS_SIGNATURE_LIST)); 4728eb2bd662Svikram } 4729eb2bd662Svikram 4730eb2bd662Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 4731eb2bd662Svikram return (0); 4732eb2bd662Svikram 4733eb2bd662Svikram fail: 4734eb2bd662Svikram if (dirp) 4735eb2bd662Svikram (void) closedir(dirp); 4736eb2bd662Svikram free_mnttab(mnttab_hash); 4737eb2bd662Svikram (void) rmdir(tmpmnt); 4738eb2bd662Svikram (void) fclose(tfp); 4739eb2bd662Svikram (void) unlink(UFS_SIGNATURE_LIST".tmp"); 4740eb2bd662Svikram BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 4741eb2bd662Svikram return (-1); 4742eb2bd662Svikram } 4743eb2bd662Svikram 4744eb2bd662Svikram static char * 4745eb2bd662Svikram create_ufs_sign(void) 4746eb2bd662Svikram { 4747eb2bd662Svikram struct stat sb; 4748eb2bd662Svikram int signnum = -1; 4749eb2bd662Svikram char tmpsign[MAXNAMELEN + 1]; 4750eb2bd662Svikram char *numstr; 4751eb2bd662Svikram int i; 4752eb2bd662Svikram FILE *tfp; 4753eb2bd662Svikram int ret; 4754eb2bd662Svikram int error; 4755eb2bd662Svikram const char *fcn = "create_ufs_sign()"; 4756eb2bd662Svikram 4757eb2bd662Svikram bam_print(SEARCHING_UFS_SIGN); 4758eb2bd662Svikram 4759eb2bd662Svikram ret = FindAllUfsSignatures(); 4760eb2bd662Svikram INJECT_ERROR1("FIND_ALL_UFS", ret = -1); 4761eb2bd662Svikram if (ret == -1) { 4762eb2bd662Svikram bam_error(ERR_FIND_UFS_SIGN); 4763eb2bd662Svikram return (NULL); 4764eb2bd662Svikram } 4765eb2bd662Svikram 4766eb2bd662Svikram /* Make sure the list exists and is owned by root */ 4767eb2bd662Svikram INJECT_ERROR1("SIGNLIST_NOT_CREATED", 4768eb2bd662Svikram (void) unlink(UFS_SIGNATURE_LIST)); 4769eb2bd662Svikram if (stat(UFS_SIGNATURE_LIST, &sb) == -1 || sb.st_uid != 0) { 4770eb2bd662Svikram (void) unlink(UFS_SIGNATURE_LIST); 4771eb2bd662Svikram bam_error(UFS_SIGNATURE_LIST_MISS, UFS_SIGNATURE_LIST); 4772eb2bd662Svikram return (NULL); 4773eb2bd662Svikram } 4774eb2bd662Svikram 4775eb2bd662Svikram if (sb.st_size == 0) { 4776eb2bd662Svikram bam_print(GRUBSIGN_UFS_NONE); 4777eb2bd662Svikram i = 0; 4778eb2bd662Svikram goto found; 4779eb2bd662Svikram } 4780eb2bd662Svikram 4781eb2bd662Svikram /* The signature list was sorted when it was created */ 4782eb2bd662Svikram tfp = fopen(UFS_SIGNATURE_LIST, "r"); 4783eb2bd662Svikram error = errno; 4784eb2bd662Svikram INJECT_ERROR1("FOPEN_SIGN_LIST", tfp = NULL); 4785eb2bd662Svikram if (tfp == NULL) { 4786eb2bd662Svikram bam_error(UFS_SIGNATURE_LIST_OPENERR, 4787eb2bd662Svikram UFS_SIGNATURE_LIST, strerror(error)); 4788eb2bd662Svikram (void) unlink(UFS_SIGNATURE_LIST); 4789eb2bd662Svikram return (NULL); 4790eb2bd662Svikram } 4791eb2bd662Svikram 4792eb2bd662Svikram for (i = 0; s_fgets(tmpsign, sizeof (tmpsign), tfp); i++) { 4793eb2bd662Svikram 4794eb2bd662Svikram if (strncmp(tmpsign, GRUBSIGN_UFS_PREFIX, 4795eb2bd662Svikram strlen(GRUBSIGN_UFS_PREFIX)) != 0) { 4796eb2bd662Svikram (void) fclose(tfp); 4797eb2bd662Svikram (void) unlink(UFS_SIGNATURE_LIST); 4798eb2bd662Svikram bam_error(UFS_BADSIGN, tmpsign); 4799eb2bd662Svikram return (NULL); 4800eb2bd662Svikram } 4801eb2bd662Svikram numstr = tmpsign + strlen(GRUBSIGN_UFS_PREFIX); 4802eb2bd662Svikram 4803eb2bd662Svikram if (numstr[0] == '\0' || !isdigit(numstr[0])) { 4804eb2bd662Svikram (void) fclose(tfp); 4805eb2bd662Svikram (void) unlink(UFS_SIGNATURE_LIST); 4806eb2bd662Svikram bam_error(UFS_BADSIGN, tmpsign); 4807eb2bd662Svikram return (NULL); 4808eb2bd662Svikram } 4809eb2bd662Svikram 4810eb2bd662Svikram signnum = atoi(numstr); 4811eb2bd662Svikram INJECT_ERROR1("NEGATIVE_SIGN", signnum = -1); 4812eb2bd662Svikram if (signnum < 0) { 4813eb2bd662Svikram (void) fclose(tfp); 4814eb2bd662Svikram (void) unlink(UFS_SIGNATURE_LIST); 4815eb2bd662Svikram bam_error(UFS_BADSIGN, tmpsign); 4816eb2bd662Svikram return (NULL); 4817eb2bd662Svikram } 4818eb2bd662Svikram 4819eb2bd662Svikram if (i != signnum) { 4820eb2bd662Svikram BAM_DPRINTF((D_FOUND_HOLE_SIGNLIST, fcn, i)); 4821eb2bd662Svikram break; 4822eb2bd662Svikram } 4823eb2bd662Svikram } 4824eb2bd662Svikram 4825eb2bd662Svikram (void) fclose(tfp); 4826eb2bd662Svikram 4827eb2bd662Svikram found: 4828eb2bd662Svikram (void) snprintf(tmpsign, sizeof (tmpsign), "rootfs%d", i); 4829eb2bd662Svikram 4830eb2bd662Svikram /* add the ufs signature to the /var/run list of signatures */ 4831eb2bd662Svikram ret = ufs_add_to_sign_list(tmpsign); 4832eb2bd662Svikram INJECT_ERROR1("UFS_ADD_TO_SIGN_LIST", ret = -1); 4833eb2bd662Svikram if (ret == -1) { 4834eb2bd662Svikram (void) unlink(UFS_SIGNATURE_LIST); 4835eb2bd662Svikram bam_error(FAILED_ADD_SIGNLIST, tmpsign); 4836eb2bd662Svikram return (NULL); 4837eb2bd662Svikram } 4838eb2bd662Svikram 4839eb2bd662Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 4840eb2bd662Svikram 4841eb2bd662Svikram return (s_strdup(tmpsign)); 4842eb2bd662Svikram } 4843eb2bd662Svikram 4844eb2bd662Svikram static char * 4845eb2bd662Svikram get_fstype(char *osroot) 4846eb2bd662Svikram { 4847eb2bd662Svikram FILE *mntfp; 4848eb2bd662Svikram struct mnttab mp = {0}; 4849eb2bd662Svikram struct mnttab mpref = {0}; 4850eb2bd662Svikram int error; 4851eb2bd662Svikram int ret; 4852eb2bd662Svikram const char *fcn = "get_fstype()"; 4853eb2bd662Svikram 4854eb2bd662Svikram INJECT_ERROR1("GET_FSTYPE_OSROOT", osroot = NULL); 4855eb2bd662Svikram if (osroot == NULL) { 4856eb2bd662Svikram bam_error(GET_FSTYPE_ARGS); 4857eb2bd662Svikram return (NULL); 4858eb2bd662Svikram } 4859eb2bd662Svikram 4860eb2bd662Svikram mntfp = fopen(MNTTAB, "r"); 4861eb2bd662Svikram error = errno; 4862eb2bd662Svikram INJECT_ERROR1("GET_FSTYPE_FOPEN", mntfp = NULL); 4863eb2bd662Svikram if (mntfp == NULL) { 4864eb2bd662Svikram bam_error(OPEN_FAIL, MNTTAB, strerror(error)); 4865eb2bd662Svikram return (NULL); 4866eb2bd662Svikram } 4867eb2bd662Svikram 4868eb2bd662Svikram if (*osroot == '\0') 4869eb2bd662Svikram mpref.mnt_mountp = "/"; 4870eb2bd662Svikram else 4871eb2bd662Svikram mpref.mnt_mountp = osroot; 4872eb2bd662Svikram 4873eb2bd662Svikram ret = getmntany(mntfp, &mp, &mpref); 4874eb2bd662Svikram INJECT_ERROR1("GET_FSTYPE_GETMNTANY", ret = 1); 4875eb2bd662Svikram if (ret != 0) { 4876eb2bd662Svikram bam_error(MNTTAB_MNTPT_NOT_FOUND, osroot, MNTTAB); 4877eb2bd662Svikram (void) fclose(mntfp); 4878eb2bd662Svikram return (NULL); 4879eb2bd662Svikram } 4880eb2bd662Svikram (void) fclose(mntfp); 4881eb2bd662Svikram 4882eb2bd662Svikram INJECT_ERROR1("GET_FSTYPE_NULL", mp.mnt_fstype = NULL); 4883eb2bd662Svikram if (mp.mnt_fstype == NULL) { 4884eb2bd662Svikram bam_error(MNTTAB_FSTYPE_NULL, osroot); 4885eb2bd662Svikram return (NULL); 4886eb2bd662Svikram } 4887eb2bd662Svikram 4888eb2bd662Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 4889eb2bd662Svikram 4890eb2bd662Svikram return (s_strdup(mp.mnt_fstype)); 4891eb2bd662Svikram } 4892eb2bd662Svikram 4893eb2bd662Svikram static char * 4894eb2bd662Svikram create_zfs_sign(char *osdev) 4895eb2bd662Svikram { 4896eb2bd662Svikram char tmpsign[PATH_MAX]; 4897eb2bd662Svikram char *pool; 4898eb2bd662Svikram const char *fcn = "create_zfs_sign()"; 4899eb2bd662Svikram 4900eb2bd662Svikram BAM_DPRINTF((D_FUNC_ENTRY1, fcn, osdev)); 4901eb2bd662Svikram 4902eb2bd662Svikram /* 4903eb2bd662Svikram * First find the pool name 4904eb2bd662Svikram */ 4905eb2bd662Svikram pool = get_pool(osdev); 4906eb2bd662Svikram INJECT_ERROR1("CREATE_ZFS_SIGN_GET_POOL", pool = NULL); 4907eb2bd662Svikram if (pool == NULL) { 4908eb2bd662Svikram bam_error(GET_POOL_FAILED, osdev); 4909eb2bd662Svikram return (NULL); 4910eb2bd662Svikram } 4911eb2bd662Svikram 4912eb2bd662Svikram (void) snprintf(tmpsign, sizeof (tmpsign), "pool_%s", pool); 4913eb2bd662Svikram 4914eb2bd662Svikram BAM_DPRINTF((D_CREATED_ZFS_SIGN, fcn, tmpsign)); 4915eb2bd662Svikram 4916eb2bd662Svikram free(pool); 4917eb2bd662Svikram 4918eb2bd662Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 4919eb2bd662Svikram 4920eb2bd662Svikram return (s_strdup(tmpsign)); 4921eb2bd662Svikram } 4922eb2bd662Svikram 4923eb2bd662Svikram static char * 4924eb2bd662Svikram create_new_sign(char *osdev, char *fstype) 4925eb2bd662Svikram { 4926eb2bd662Svikram char *sign; 4927eb2bd662Svikram const char *fcn = "create_new_sign()"; 4928eb2bd662Svikram 4929eb2bd662Svikram INJECT_ERROR1("NEW_SIGN_FSTYPE", fstype = "foofs"); 4930eb2bd662Svikram 4931eb2bd662Svikram if (strcmp(fstype, "zfs") == 0) { 4932eb2bd662Svikram BAM_DPRINTF((D_CREATE_NEW_ZFS, fcn)); 4933eb2bd662Svikram sign = create_zfs_sign(osdev); 4934eb2bd662Svikram } else if (strcmp(fstype, "ufs") == 0) { 4935eb2bd662Svikram BAM_DPRINTF((D_CREATE_NEW_UFS, fcn)); 4936eb2bd662Svikram sign = create_ufs_sign(); 4937eb2bd662Svikram } else { 4938eb2bd662Svikram bam_error(GRUBSIGN_NOTSUP, fstype); 4939eb2bd662Svikram sign = NULL; 4940eb2bd662Svikram } 4941eb2bd662Svikram 4942eb2bd662Svikram BAM_DPRINTF((D_CREATED_NEW_SIGN, fcn, sign ? sign : "<NULL>")); 4943eb2bd662Svikram return (sign); 4944eb2bd662Svikram } 4945eb2bd662Svikram 4946eb2bd662Svikram static int 4947eb2bd662Svikram set_backup_common(char *mntpt, char *sign) 4948eb2bd662Svikram { 4949eb2bd662Svikram FILE *bfp; 4950eb2bd662Svikram char backup[PATH_MAX]; 4951eb2bd662Svikram char tmpsign[PATH_MAX]; 4952eb2bd662Svikram int error; 4953eb2bd662Svikram char *bdir; 4954eb2bd662Svikram char *backup_dup; 4955eb2bd662Svikram struct stat sb; 4956eb2bd662Svikram int ret; 4957eb2bd662Svikram const char *fcn = "set_backup_common()"; 4958eb2bd662Svikram 4959eb2bd662Svikram (void) snprintf(backup, sizeof (backup), "%s%s", 4960eb2bd662Svikram mntpt, GRUBSIGN_BACKUP); 4961eb2bd662Svikram 4962eb2bd662Svikram /* First read the backup */ 4963eb2bd662Svikram bfp = fopen(backup, "r"); 4964eb2bd662Svikram if (bfp != NULL) { 4965eb2bd662Svikram while (s_fgets(tmpsign, sizeof (tmpsign), bfp)) { 4966eb2bd662Svikram if (strcmp(tmpsign, sign) == 0) { 4967eb2bd662Svikram BAM_DPRINTF((D_FOUND_IN_BACKUP, fcn, sign)); 4968eb2bd662Svikram (void) fclose(bfp); 4969eb2bd662Svikram return (0); 4970eb2bd662Svikram } 4971eb2bd662Svikram } 4972eb2bd662Svikram (void) fclose(bfp); 4973eb2bd662Svikram BAM_DPRINTF((D_NOT_FOUND_IN_EXIST_BACKUP, fcn, sign)); 4974eb2bd662Svikram } else { 4975eb2bd662Svikram BAM_DPRINTF((D_BACKUP_NOT_EXIST, fcn, backup)); 4976eb2bd662Svikram } 4977eb2bd662Svikram 4978eb2bd662Svikram /* 4979eb2bd662Svikram * Didn't find the correct signature. First create 4980eb2bd662Svikram * the directory if necessary. 4981eb2bd662Svikram */ 4982eb2bd662Svikram 4983eb2bd662Svikram /* dirname() modifies its argument so dup it */ 4984eb2bd662Svikram backup_dup = s_strdup(backup); 4985eb2bd662Svikram bdir = dirname(backup_dup); 4986eb2bd662Svikram assert(bdir); 4987eb2bd662Svikram 4988eb2bd662Svikram ret = stat(bdir, &sb); 4989eb2bd662Svikram INJECT_ERROR1("SET_BACKUP_STAT", ret = -1); 4990eb2bd662Svikram if (ret == -1) { 4991eb2bd662Svikram BAM_DPRINTF((D_BACKUP_DIR_NOEXIST, fcn, bdir)); 4992eb2bd662Svikram ret = mkdirp(bdir, 0755); 4993eb2bd662Svikram error = errno; 4994eb2bd662Svikram INJECT_ERROR1("SET_BACKUP_MKDIRP", ret = -1); 4995eb2bd662Svikram if (ret == -1) { 4996eb2bd662Svikram bam_error(GRUBSIGN_BACKUP_MKDIRERR, 4997eb2bd662Svikram GRUBSIGN_BACKUP, strerror(error)); 4998eb2bd662Svikram free(backup_dup); 4999eb2bd662Svikram return (-1); 5000eb2bd662Svikram } 5001eb2bd662Svikram } 5002eb2bd662Svikram free(backup_dup); 5003eb2bd662Svikram 5004eb2bd662Svikram /* 5005eb2bd662Svikram * Open the backup in append mode to add the correct 5006eb2bd662Svikram * signature; 5007eb2bd662Svikram */ 5008eb2bd662Svikram bfp = fopen(backup, "a"); 5009eb2bd662Svikram error = errno; 5010eb2bd662Svikram INJECT_ERROR1("SET_BACKUP_FOPEN_A", bfp = NULL); 5011eb2bd662Svikram if (bfp == NULL) { 5012eb2bd662Svikram bam_error(GRUBSIGN_BACKUP_OPENERR, 5013eb2bd662Svikram GRUBSIGN_BACKUP, strerror(error)); 5014eb2bd662Svikram return (-1); 5015eb2bd662Svikram } 5016eb2bd662Svikram 5017eb2bd662Svikram (void) snprintf(tmpsign, sizeof (tmpsign), "%s\n", sign); 5018eb2bd662Svikram 5019eb2bd662Svikram ret = fputs(tmpsign, bfp); 5020eb2bd662Svikram error = errno; 5021eb2bd662Svikram INJECT_ERROR1("SET_BACKUP_FPUTS", ret = 0); 5022eb2bd662Svikram if (ret != strlen(tmpsign)) { 5023eb2bd662Svikram bam_error(GRUBSIGN_BACKUP_WRITEERR, 5024eb2bd662Svikram GRUBSIGN_BACKUP, strerror(error)); 5025eb2bd662Svikram (void) fclose(bfp); 5026eb2bd662Svikram return (-1); 5027eb2bd662Svikram } 5028eb2bd662Svikram 5029eb2bd662Svikram (void) fclose(bfp); 5030eb2bd662Svikram 5031eb2bd662Svikram if (bam_verbose) 5032eb2bd662Svikram bam_print(GRUBSIGN_BACKUP_UPDATED, GRUBSIGN_BACKUP); 5033eb2bd662Svikram 5034eb2bd662Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 5035eb2bd662Svikram 5036eb2bd662Svikram return (0); 5037eb2bd662Svikram } 5038eb2bd662Svikram 5039eb2bd662Svikram static int 5040eb2bd662Svikram set_backup_ufs(char *osroot, char *sign) 5041eb2bd662Svikram { 5042eb2bd662Svikram const char *fcn = "set_backup_ufs()"; 5043eb2bd662Svikram 5044eb2bd662Svikram BAM_DPRINTF((D_FUNC_ENTRY2, fcn, osroot, sign)); 5045eb2bd662Svikram return (set_backup_common(osroot, sign)); 5046eb2bd662Svikram } 5047eb2bd662Svikram 5048eb2bd662Svikram static int 5049eb2bd662Svikram set_backup_zfs(char *osdev, char *sign) 5050eb2bd662Svikram { 5051eb2bd662Svikram char *pool; 5052eb2bd662Svikram char *mntpt; 5053eb2bd662Svikram zfs_mnted_t mnted; 5054eb2bd662Svikram int ret; 5055eb2bd662Svikram const char *fcn = "set_backup_zfs()"; 5056eb2bd662Svikram 5057eb2bd662Svikram BAM_DPRINTF((D_FUNC_ENTRY2, fcn, osdev, sign)); 5058eb2bd662Svikram 5059eb2bd662Svikram pool = get_pool(osdev); 5060eb2bd662Svikram INJECT_ERROR1("SET_BACKUP_GET_POOL", pool = NULL); 5061eb2bd662Svikram if (pool == NULL) { 5062eb2bd662Svikram bam_error(GET_POOL_FAILED, osdev); 5063eb2bd662Svikram return (-1); 5064eb2bd662Svikram } 5065eb2bd662Svikram 5066eb2bd662Svikram mntpt = mount_top_dataset(pool, &mnted); 5067eb2bd662Svikram INJECT_ERROR1("SET_BACKUP_MOUNT_DATASET", mntpt = NULL); 5068eb2bd662Svikram if (mntpt == NULL) { 5069eb2bd662Svikram bam_error(FAIL_MNT_TOP_DATASET, pool); 5070eb2bd662Svikram free(pool); 5071eb2bd662Svikram return (-1); 5072eb2bd662Svikram } 5073eb2bd662Svikram 5074eb2bd662Svikram ret = set_backup_common(mntpt, sign); 5075eb2bd662Svikram 5076eb2bd662Svikram (void) umount_top_dataset(pool, mnted, mntpt); 5077eb2bd662Svikram 5078eb2bd662Svikram free(pool); 5079eb2bd662Svikram 5080eb2bd662Svikram INJECT_ERROR1("SET_BACKUP_ZFS_FAIL", ret = 1); 5081eb2bd662Svikram if (ret == 0) { 5082eb2bd662Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 5083eb2bd662Svikram } else { 5084eb2bd662Svikram BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 5085eb2bd662Svikram } 5086eb2bd662Svikram 5087eb2bd662Svikram return (ret); 5088eb2bd662Svikram } 5089eb2bd662Svikram 5090eb2bd662Svikram static int 5091eb2bd662Svikram set_backup(char *osroot, char *osdev, char *sign, char *fstype) 5092eb2bd662Svikram { 5093eb2bd662Svikram const char *fcn = "set_backup()"; 5094eb2bd662Svikram int ret; 5095eb2bd662Svikram 5096eb2bd662Svikram INJECT_ERROR1("SET_BACKUP_FSTYPE", fstype = "foofs"); 5097eb2bd662Svikram 5098eb2bd662Svikram if (strcmp(fstype, "ufs") == 0) { 5099eb2bd662Svikram BAM_DPRINTF((D_SET_BACKUP_UFS, fcn)); 5100eb2bd662Svikram ret = set_backup_ufs(osroot, sign); 5101eb2bd662Svikram } else if (strcmp(fstype, "zfs") == 0) { 5102eb2bd662Svikram BAM_DPRINTF((D_SET_BACKUP_ZFS, fcn)); 5103eb2bd662Svikram ret = set_backup_zfs(osdev, sign); 5104eb2bd662Svikram } else { 5105eb2bd662Svikram bam_error(GRUBSIGN_NOTSUP, fstype); 5106eb2bd662Svikram ret = -1; 5107eb2bd662Svikram } 5108eb2bd662Svikram 5109eb2bd662Svikram if (ret == 0) { 5110eb2bd662Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 5111eb2bd662Svikram } else { 5112eb2bd662Svikram BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 5113eb2bd662Svikram } 5114eb2bd662Svikram 5115eb2bd662Svikram return (ret); 5116eb2bd662Svikram } 5117eb2bd662Svikram 5118eb2bd662Svikram static int 5119eb2bd662Svikram set_primary_common(char *mntpt, char *sign) 5120eb2bd662Svikram { 5121eb2bd662Svikram char signfile[PATH_MAX]; 5122eb2bd662Svikram char signdir[PATH_MAX]; 5123eb2bd662Svikram struct stat sb; 5124eb2bd662Svikram int fd; 5125eb2bd662Svikram int error; 5126eb2bd662Svikram int ret; 5127eb2bd662Svikram const char *fcn = "set_primary_common()"; 5128eb2bd662Svikram 5129eb2bd662Svikram (void) snprintf(signfile, sizeof (signfile), "%s/%s/%s", 5130eb2bd662Svikram mntpt, GRUBSIGN_DIR, sign); 5131eb2bd662Svikram 5132eb2bd662Svikram if (stat(signfile, &sb) != -1) { 5133eb2bd662Svikram if (bam_verbose) 5134eb2bd662Svikram bam_print(PRIMARY_SIGN_EXISTS, sign); 5135eb2bd662Svikram return (0); 5136eb2bd662Svikram } else { 5137eb2bd662Svikram BAM_DPRINTF((D_PRIMARY_NOT_EXIST, fcn, signfile)); 5138eb2bd662Svikram } 5139eb2bd662Svikram 5140eb2bd662Svikram (void) snprintf(signdir, sizeof (signdir), "%s/%s", 5141eb2bd662Svikram mntpt, GRUBSIGN_DIR); 5142eb2bd662Svikram 5143eb2bd662Svikram if (stat(signdir, &sb) == -1) { 5144eb2bd662Svikram BAM_DPRINTF((D_PRIMARY_DIR_NOEXIST, fcn, signdir)); 5145eb2bd662Svikram ret = mkdirp(signdir, 0755); 5146eb2bd662Svikram error = errno; 5147eb2bd662Svikram INJECT_ERROR1("SET_PRIMARY_MKDIRP", ret = -1); 5148eb2bd662Svikram if (ret == -1) { 5149eb2bd662Svikram bam_error(GRUBSIGN_MKDIR_ERR, signdir, strerror(errno)); 5150eb2bd662Svikram return (-1); 5151eb2bd662Svikram } 5152eb2bd662Svikram } 5153eb2bd662Svikram 5154eb2bd662Svikram fd = open(signfile, O_RDWR|O_CREAT|O_TRUNC, 0444); 5155eb2bd662Svikram error = errno; 5156eb2bd662Svikram INJECT_ERROR1("PRIMARY_SIGN_CREAT", fd = -1); 5157eb2bd662Svikram if (fd == -1) { 5158eb2bd662Svikram bam_error(GRUBSIGN_PRIMARY_CREATERR, signfile, strerror(error)); 5159eb2bd662Svikram return (-1); 5160eb2bd662Svikram } 5161eb2bd662Svikram 5162eb2bd662Svikram ret = fsync(fd); 5163eb2bd662Svikram error = errno; 5164eb2bd662Svikram INJECT_ERROR1("PRIMARY_FSYNC", ret = -1); 5165eb2bd662Svikram if (ret != 0) { 5166eb2bd662Svikram bam_error(GRUBSIGN_PRIMARY_SYNCERR, signfile, strerror(error)); 5167eb2bd662Svikram } 5168eb2bd662Svikram 5169eb2bd662Svikram (void) close(fd); 5170eb2bd662Svikram 5171eb2bd662Svikram if (bam_verbose) 5172eb2bd662Svikram bam_print(GRUBSIGN_CREATED_PRIMARY, signfile); 5173eb2bd662Svikram 5174eb2bd662Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 5175eb2bd662Svikram 5176eb2bd662Svikram return (0); 5177eb2bd662Svikram } 5178eb2bd662Svikram 5179eb2bd662Svikram static int 5180eb2bd662Svikram set_primary_ufs(char *osroot, char *sign) 5181eb2bd662Svikram { 5182eb2bd662Svikram const char *fcn = "set_primary_ufs()"; 5183eb2bd662Svikram 5184eb2bd662Svikram BAM_DPRINTF((D_FUNC_ENTRY2, fcn, osroot, sign)); 5185eb2bd662Svikram return (set_primary_common(osroot, sign)); 5186eb2bd662Svikram } 5187eb2bd662Svikram 5188eb2bd662Svikram static int 5189eb2bd662Svikram set_primary_zfs(char *osdev, char *sign) 5190eb2bd662Svikram { 5191eb2bd662Svikram char *pool; 5192eb2bd662Svikram char *mntpt; 5193eb2bd662Svikram zfs_mnted_t mnted; 5194eb2bd662Svikram int ret; 5195eb2bd662Svikram const char *fcn = "set_primary_zfs()"; 5196eb2bd662Svikram 5197eb2bd662Svikram BAM_DPRINTF((D_FUNC_ENTRY2, fcn, osdev, sign)); 5198eb2bd662Svikram 5199eb2bd662Svikram pool = get_pool(osdev); 5200eb2bd662Svikram INJECT_ERROR1("SET_PRIMARY_ZFS_GET_POOL", pool = NULL); 5201eb2bd662Svikram if (pool == NULL) { 5202eb2bd662Svikram bam_error(GET_POOL_FAILED, osdev); 5203eb2bd662Svikram return (-1); 5204eb2bd662Svikram } 5205eb2bd662Svikram 5206eb2bd662Svikram /* Pool name must exist in the sign */ 5207eb2bd662Svikram ret = (strstr(sign, pool) != NULL); 5208eb2bd662Svikram INJECT_ERROR1("SET_PRIMARY_ZFS_POOL_SIGN_INCOMPAT", ret = 0); 5209eb2bd662Svikram if (ret == 0) { 5210eb2bd662Svikram bam_error(POOL_SIGN_INCOMPAT, pool, sign); 5211eb2bd662Svikram free(pool); 5212eb2bd662Svikram return (-1); 5213eb2bd662Svikram } 5214eb2bd662Svikram 5215eb2bd662Svikram mntpt = mount_top_dataset(pool, &mnted); 5216eb2bd662Svikram INJECT_ERROR1("SET_PRIMARY_ZFS_MOUNT_DATASET", mntpt = NULL); 5217eb2bd662Svikram if (mntpt == NULL) { 5218eb2bd662Svikram bam_error(FAIL_MNT_TOP_DATASET, pool); 5219eb2bd662Svikram free(pool); 5220eb2bd662Svikram return (-1); 5221eb2bd662Svikram } 5222eb2bd662Svikram 5223eb2bd662Svikram ret = set_primary_common(mntpt, sign); 5224eb2bd662Svikram 5225eb2bd662Svikram (void) umount_top_dataset(pool, mnted, mntpt); 5226eb2bd662Svikram 5227eb2bd662Svikram free(pool); 5228eb2bd662Svikram 5229eb2bd662Svikram INJECT_ERROR1("SET_PRIMARY_ZFS_FAIL", ret = 1); 5230eb2bd662Svikram if (ret == 0) { 5231eb2bd662Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 5232eb2bd662Svikram } else { 5233eb2bd662Svikram BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 5234eb2bd662Svikram } 5235eb2bd662Svikram 5236eb2bd662Svikram return (ret); 5237eb2bd662Svikram } 5238eb2bd662Svikram 5239eb2bd662Svikram static int 5240eb2bd662Svikram set_primary(char *osroot, char *osdev, char *sign, char *fstype) 5241eb2bd662Svikram { 5242eb2bd662Svikram const char *fcn = "set_primary()"; 5243eb2bd662Svikram int ret; 5244eb2bd662Svikram 5245eb2bd662Svikram INJECT_ERROR1("SET_PRIMARY_FSTYPE", fstype = "foofs"); 5246eb2bd662Svikram if (strcmp(fstype, "ufs") == 0) { 5247eb2bd662Svikram BAM_DPRINTF((D_SET_PRIMARY_UFS, fcn)); 5248eb2bd662Svikram ret = set_primary_ufs(osroot, sign); 5249eb2bd662Svikram } else if (strcmp(fstype, "zfs") == 0) { 5250eb2bd662Svikram BAM_DPRINTF((D_SET_PRIMARY_ZFS, fcn)); 5251eb2bd662Svikram ret = set_primary_zfs(osdev, sign); 5252eb2bd662Svikram } else { 5253eb2bd662Svikram bam_error(GRUBSIGN_NOTSUP, fstype); 5254eb2bd662Svikram ret = -1; 5255eb2bd662Svikram } 5256eb2bd662Svikram 5257eb2bd662Svikram if (ret == 0) { 5258eb2bd662Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 5259eb2bd662Svikram } else { 5260eb2bd662Svikram BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 5261eb2bd662Svikram } 5262eb2bd662Svikram 5263eb2bd662Svikram return (ret); 5264eb2bd662Svikram } 5265eb2bd662Svikram 5266eb2bd662Svikram static int 5267eb2bd662Svikram ufs_add_to_sign_list(char *sign) 5268eb2bd662Svikram { 5269eb2bd662Svikram FILE *tfp; 5270eb2bd662Svikram char signline[MAXNAMELEN]; 5271eb2bd662Svikram char cmd[PATH_MAX]; 5272eb2bd662Svikram int ret; 5273eb2bd662Svikram int error; 5274eb2bd662Svikram const char *fcn = "ufs_add_to_sign_list()"; 5275eb2bd662Svikram 5276eb2bd662Svikram INJECT_ERROR1("ADD_TO_SIGN_LIST_NOT_UFS", sign = "pool_rpool5"); 5277eb2bd662Svikram if (strncmp(sign, GRUBSIGN_UFS_PREFIX, 5278eb2bd662Svikram strlen(GRUBSIGN_UFS_PREFIX)) != 0) { 5279eb2bd662Svikram bam_error(INVALID_UFS_SIGN, sign); 5280eb2bd662Svikram (void) unlink(UFS_SIGNATURE_LIST); 5281eb2bd662Svikram return (-1); 5282eb2bd662Svikram } 5283eb2bd662Svikram 5284eb2bd662Svikram /* 5285eb2bd662Svikram * most failures in this routine are not a fatal error 5286eb2bd662Svikram * We simply unlink the /var/run file and continue 5287eb2bd662Svikram */ 5288eb2bd662Svikram 5289eb2bd662Svikram ret = rename(UFS_SIGNATURE_LIST, UFS_SIGNATURE_LIST".tmp"); 5290eb2bd662Svikram error = errno; 5291eb2bd662Svikram INJECT_ERROR1("ADD_TO_SIGN_LIST_RENAME", ret = -1); 5292eb2bd662Svikram if (ret == -1) { 5293eb2bd662Svikram bam_error(RENAME_FAIL, UFS_SIGNATURE_LIST".tmp", 5294eb2bd662Svikram strerror(error)); 5295eb2bd662Svikram (void) unlink(UFS_SIGNATURE_LIST); 5296eb2bd662Svikram return (0); 5297eb2bd662Svikram } 5298eb2bd662Svikram 5299eb2bd662Svikram tfp = fopen(UFS_SIGNATURE_LIST".tmp", "a"); 5300eb2bd662Svikram error = errno; 5301eb2bd662Svikram INJECT_ERROR1("ADD_TO_SIGN_LIST_FOPEN", tfp = NULL); 5302eb2bd662Svikram if (tfp == NULL) { 5303eb2bd662Svikram bam_error(OPEN_FAIL, UFS_SIGNATURE_LIST".tmp", strerror(error)); 5304eb2bd662Svikram (void) unlink(UFS_SIGNATURE_LIST".tmp"); 5305eb2bd662Svikram return (0); 5306eb2bd662Svikram } 5307eb2bd662Svikram 5308eb2bd662Svikram (void) snprintf(signline, sizeof (signline), "%s\n", sign); 5309eb2bd662Svikram 5310eb2bd662Svikram ret = fputs(signline, tfp); 5311eb2bd662Svikram error = errno; 5312eb2bd662Svikram INJECT_ERROR1("ADD_TO_SIGN_LIST_FPUTS", ret = 0); 5313eb2bd662Svikram if (ret != strlen(signline)) { 5314eb2bd662Svikram bam_error(SIGN_LIST_FPUTS_ERR, sign, strerror(error)); 5315eb2bd662Svikram (void) fclose(tfp); 5316eb2bd662Svikram (void) unlink(UFS_SIGNATURE_LIST".tmp"); 5317eb2bd662Svikram return (0); 5318eb2bd662Svikram } 5319eb2bd662Svikram 5320eb2bd662Svikram ret = fclose(tfp); 5321eb2bd662Svikram error = errno; 5322eb2bd662Svikram INJECT_ERROR1("ADD_TO_SIGN_LIST_FCLOSE", ret = EOF); 5323eb2bd662Svikram if (ret == EOF) { 5324eb2bd662Svikram bam_error(CLOSE_FAIL, UFS_SIGNATURE_LIST".tmp", 5325eb2bd662Svikram strerror(error)); 5326eb2bd662Svikram (void) unlink(UFS_SIGNATURE_LIST".tmp"); 5327eb2bd662Svikram return (0); 5328eb2bd662Svikram } 5329eb2bd662Svikram 5330eb2bd662Svikram /* Sort the list again */ 5331eb2bd662Svikram (void) snprintf(cmd, sizeof (cmd), 5332eb2bd662Svikram "/usr/bin/sort -u %s.tmp > %s.sorted", 5333eb2bd662Svikram UFS_SIGNATURE_LIST, UFS_SIGNATURE_LIST); 5334eb2bd662Svikram 5335eb2bd662Svikram ret = exec_cmd(cmd, NULL); 5336eb2bd662Svikram INJECT_ERROR1("ADD_TO_SIGN_LIST_SORT", ret = 1); 5337eb2bd662Svikram if (ret != 0) { 5338eb2bd662Svikram bam_error(GRUBSIGN_SORT_FAILED); 5339eb2bd662Svikram (void) unlink(UFS_SIGNATURE_LIST".sorted"); 5340eb2bd662Svikram (void) unlink(UFS_SIGNATURE_LIST".tmp"); 5341eb2bd662Svikram return (0); 5342eb2bd662Svikram } 5343eb2bd662Svikram 5344eb2bd662Svikram (void) unlink(UFS_SIGNATURE_LIST".tmp"); 5345eb2bd662Svikram 5346eb2bd662Svikram ret = rename(UFS_SIGNATURE_LIST".sorted", UFS_SIGNATURE_LIST); 5347eb2bd662Svikram error = errno; 5348eb2bd662Svikram INJECT_ERROR1("ADD_TO_SIGN_LIST_RENAME2", ret = -1); 5349eb2bd662Svikram if (ret == -1) { 5350eb2bd662Svikram bam_error(RENAME_FAIL, UFS_SIGNATURE_LIST, strerror(error)); 5351eb2bd662Svikram (void) unlink(UFS_SIGNATURE_LIST".sorted"); 5352eb2bd662Svikram return (0); 5353eb2bd662Svikram } 5354eb2bd662Svikram 5355eb2bd662Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 5356eb2bd662Svikram 5357eb2bd662Svikram return (0); 5358eb2bd662Svikram } 5359eb2bd662Svikram 5360eb2bd662Svikram static int 5361eb2bd662Svikram set_signature(char *osroot, char *osdev, char *sign, char *fstype) 5362eb2bd662Svikram { 5363eb2bd662Svikram int ret; 5364eb2bd662Svikram const char *fcn = "set_signature()"; 5365eb2bd662Svikram 5366eb2bd662Svikram BAM_DPRINTF((D_FUNC_ENTRY4, fcn, osroot, osdev, sign, fstype)); 5367eb2bd662Svikram 5368eb2bd662Svikram ret = set_backup(osroot, osdev, sign, fstype); 5369eb2bd662Svikram INJECT_ERROR1("SET_SIGNATURE_BACKUP", ret = -1); 5370eb2bd662Svikram if (ret == -1) { 5371eb2bd662Svikram BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 5372eb2bd662Svikram bam_error(SET_BACKUP_FAILED, sign, osroot, osdev); 5373eb2bd662Svikram return (-1); 5374eb2bd662Svikram } 5375eb2bd662Svikram 5376eb2bd662Svikram ret = set_primary(osroot, osdev, sign, fstype); 5377eb2bd662Svikram INJECT_ERROR1("SET_SIGNATURE_PRIMARY", ret = -1); 5378eb2bd662Svikram 5379eb2bd662Svikram if (ret == 0) { 5380eb2bd662Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 5381eb2bd662Svikram } else { 5382eb2bd662Svikram BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 5383eb2bd662Svikram bam_error(SET_PRIMARY_FAILED, sign, osroot, osdev); 5384eb2bd662Svikram 5385eb2bd662Svikram } 5386eb2bd662Svikram return (ret); 5387eb2bd662Svikram } 5388eb2bd662Svikram 5389eb2bd662Svikram char * 5390eb2bd662Svikram get_grubsign(char *osroot, char *osdev) 5391eb2bd662Svikram { 5392eb2bd662Svikram char *grubsign; /* (<sign>,#,#) */ 5393eb2bd662Svikram char *slice; 5394eb2bd662Svikram int fdiskpart; 5395eb2bd662Svikram char *sign; 5396eb2bd662Svikram char *fstype; 5397eb2bd662Svikram int ret; 5398eb2bd662Svikram const char *fcn = "get_grubsign()"; 5399eb2bd662Svikram 5400eb2bd662Svikram BAM_DPRINTF((D_FUNC_ENTRY2, fcn, osroot, osdev)); 5401eb2bd662Svikram 5402eb2bd662Svikram fstype = get_fstype(osroot); 5403eb2bd662Svikram INJECT_ERROR1("GET_GRUBSIGN_FSTYPE", fstype = NULL); 5404eb2bd662Svikram if (fstype == NULL) { 5405eb2bd662Svikram bam_error(GET_FSTYPE_FAILED, osroot); 5406eb2bd662Svikram return (NULL); 5407eb2bd662Svikram } 5408eb2bd662Svikram 5409eb2bd662Svikram sign = find_existing_sign(osroot, osdev, fstype); 5410eb2bd662Svikram INJECT_ERROR1("FIND_EXISTING_SIGN", sign = NULL); 5411eb2bd662Svikram if (sign == NULL) { 5412eb2bd662Svikram BAM_DPRINTF((D_GET_GRUBSIGN_NO_EXISTING, fcn, osroot, osdev)); 5413eb2bd662Svikram sign = create_new_sign(osdev, fstype); 5414eb2bd662Svikram INJECT_ERROR1("CREATE_NEW_SIGN", sign = NULL); 5415eb2bd662Svikram if (sign == NULL) { 5416eb2bd662Svikram bam_error(GRUBSIGN_CREATE_FAIL, osdev); 5417eb2bd662Svikram free(fstype); 5418eb2bd662Svikram return (NULL); 5419eb2bd662Svikram } 5420eb2bd662Svikram } 5421eb2bd662Svikram 5422eb2bd662Svikram ret = set_signature(osroot, osdev, sign, fstype); 5423eb2bd662Svikram INJECT_ERROR1("SET_SIGNATURE_FAIL", ret = -1); 5424eb2bd662Svikram if (ret == -1) { 5425eb2bd662Svikram bam_error(GRUBSIGN_WRITE_FAIL, osdev); 5426eb2bd662Svikram free(sign); 5427eb2bd662Svikram free(fstype); 5428eb2bd662Svikram (void) unlink(UFS_SIGNATURE_LIST); 5429eb2bd662Svikram return (NULL); 5430eb2bd662Svikram } 5431eb2bd662Svikram 5432eb2bd662Svikram free(fstype); 5433eb2bd662Svikram 5434eb2bd662Svikram if (bam_verbose) 5435eb2bd662Svikram bam_print(GRUBSIGN_FOUND_OR_CREATED, sign, osdev); 5436eb2bd662Svikram 5437eb2bd662Svikram fdiskpart = get_partition(osdev); 5438eb2bd662Svikram INJECT_ERROR1("GET_GRUBSIGN_FDISK", fdiskpart = -1); 5439eb2bd662Svikram if (fdiskpart == -1) { 5440eb2bd662Svikram bam_error(FDISKPART_FAIL, osdev); 5441eb2bd662Svikram free(sign); 5442eb2bd662Svikram return (NULL); 5443eb2bd662Svikram } 5444eb2bd662Svikram 5445eb2bd662Svikram slice = strrchr(osdev, 's'); 5446eb2bd662Svikram 5447eb2bd662Svikram grubsign = s_calloc(1, MAXNAMELEN + 10); 5448eb2bd662Svikram if (slice) { 5449eb2bd662Svikram (void) snprintf(grubsign, MAXNAMELEN + 10, "(%s,%d,%c)", 5450eb2bd662Svikram sign, fdiskpart, slice[1] + 'a' - '0'); 5451eb2bd662Svikram } else 5452eb2bd662Svikram (void) snprintf(grubsign, MAXNAMELEN + 10, "(%s,%d)", 5453eb2bd662Svikram sign, fdiskpart); 5454eb2bd662Svikram 5455eb2bd662Svikram free(sign); 5456eb2bd662Svikram 5457eb2bd662Svikram BAM_DPRINTF((D_GET_GRUBSIGN_SUCCESS, fcn, grubsign)); 5458eb2bd662Svikram 5459eb2bd662Svikram return (grubsign); 5460eb2bd662Svikram } 5461eb2bd662Svikram 5462eb2bd662Svikram static char * 5463eb2bd662Svikram get_title(char *rootdir) 5464eb2bd662Svikram { 5465eb2bd662Svikram static char title[80]; 5466eb2bd662Svikram char *cp = NULL; 5467eb2bd662Svikram char release[PATH_MAX]; 5468eb2bd662Svikram FILE *fp; 5469eb2bd662Svikram const char *fcn = "get_title()"; 5470eb2bd662Svikram 5471eb2bd662Svikram /* open the /etc/release file */ 5472eb2bd662Svikram (void) snprintf(release, sizeof (release), "%s/etc/release", rootdir); 5473eb2bd662Svikram 5474eb2bd662Svikram fp = fopen(release, "r"); 5475eb2bd662Svikram if (fp == NULL) { 5476eb2bd662Svikram bam_error(OPEN_FAIL, release, strerror(errno)); 5477eb2bd662Svikram cp = NULL; 5478eb2bd662Svikram goto out; 5479eb2bd662Svikram } 5480eb2bd662Svikram 5481eb2bd662Svikram while (s_fgets(title, sizeof (title), fp) != NULL) { 5482eb2bd662Svikram cp = strstr(title, "Solaris"); 5483eb2bd662Svikram if (cp) 5484eb2bd662Svikram break; 5485eb2bd662Svikram } 5486eb2bd662Svikram (void) fclose(fp); 5487eb2bd662Svikram 5488eb2bd662Svikram out: 5489eb2bd662Svikram cp = cp ? cp : "Solaris"; 5490eb2bd662Svikram 5491eb2bd662Svikram BAM_DPRINTF((D_GET_TITLE, fcn, cp)); 5492eb2bd662Svikram 5493eb2bd662Svikram return (cp); 5494eb2bd662Svikram } 5495eb2bd662Svikram 5496eb2bd662Svikram char * 5497eb2bd662Svikram get_special(char *mountp) 5498eb2bd662Svikram { 5499eb2bd662Svikram FILE *mntfp; 5500eb2bd662Svikram struct mnttab mp = {0}; 5501eb2bd662Svikram struct mnttab mpref = {0}; 5502eb2bd662Svikram int error; 5503eb2bd662Svikram int ret; 5504eb2bd662Svikram const char *fcn = "get_special()"; 5505eb2bd662Svikram 5506eb2bd662Svikram INJECT_ERROR1("GET_SPECIAL_MNTPT", mountp = NULL); 5507eb2bd662Svikram if (mountp == NULL) { 5508eb2bd662Svikram bam_error(GET_SPECIAL_NULL_MNTPT); 5509eb2bd662Svikram return (NULL); 5510eb2bd662Svikram } 5511eb2bd662Svikram 5512eb2bd662Svikram mntfp = fopen(MNTTAB, "r"); 5513eb2bd662Svikram error = errno; 5514eb2bd662Svikram INJECT_ERROR1("GET_SPECIAL_MNTTAB_OPEN", mntfp = NULL); 5515eb2bd662Svikram if (mntfp == NULL) { 5516eb2bd662Svikram bam_error(OPEN_FAIL, MNTTAB, strerror(error)); 5517eb2bd662Svikram return (NULL); 5518eb2bd662Svikram } 5519eb2bd662Svikram 5520eb2bd662Svikram if (*mountp == '\0') 5521eb2bd662Svikram mpref.mnt_mountp = "/"; 5522eb2bd662Svikram else 5523eb2bd662Svikram mpref.mnt_mountp = mountp; 5524eb2bd662Svikram 5525eb2bd662Svikram ret = getmntany(mntfp, &mp, &mpref); 5526eb2bd662Svikram INJECT_ERROR1("GET_SPECIAL_MNTTAB_SEARCH", ret = 1); 5527eb2bd662Svikram if (ret != 0) { 5528eb2bd662Svikram (void) fclose(mntfp); 5529eb2bd662Svikram BAM_DPRINTF((D_GET_SPECIAL_NOT_IN_MNTTAB, fcn, mountp)); 5530eb2bd662Svikram return (NULL); 5531eb2bd662Svikram } 5532eb2bd662Svikram (void) fclose(mntfp); 5533eb2bd662Svikram 5534eb2bd662Svikram BAM_DPRINTF((D_GET_SPECIAL, fcn, mp.mnt_special)); 5535eb2bd662Svikram 5536eb2bd662Svikram return (s_strdup(mp.mnt_special)); 5537eb2bd662Svikram } 5538eb2bd662Svikram 5539eb2bd662Svikram static void 5540eb2bd662Svikram free_physarray(char **physarray, int n) 5541eb2bd662Svikram { 5542eb2bd662Svikram int i; 5543eb2bd662Svikram const char *fcn = "free_physarray()"; 5544eb2bd662Svikram 5545eb2bd662Svikram assert(physarray); 5546eb2bd662Svikram assert(n); 5547eb2bd662Svikram 5548eb2bd662Svikram BAM_DPRINTF((D_FUNC_ENTRY_N1, fcn, n)); 5549eb2bd662Svikram 5550eb2bd662Svikram for (i = 0; i < n; i++) { 5551eb2bd662Svikram free(physarray[i]); 5552eb2bd662Svikram } 5553eb2bd662Svikram free(physarray); 5554eb2bd662Svikram 5555eb2bd662Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 5556eb2bd662Svikram } 5557eb2bd662Svikram 5558eb2bd662Svikram static int 5559eb2bd662Svikram zfs_get_physical(char *special, char ***physarray, int *n) 5560eb2bd662Svikram { 5561eb2bd662Svikram char sdup[PATH_MAX]; 5562eb2bd662Svikram char cmd[PATH_MAX]; 5563eb2bd662Svikram char dsk[PATH_MAX]; 5564eb2bd662Svikram char *pool; 5565eb2bd662Svikram filelist_t flist = {0}; 5566eb2bd662Svikram line_t *lp; 5567eb2bd662Svikram line_t *startlp; 5568eb2bd662Svikram char *comp1; 5569eb2bd662Svikram int i; 5570eb2bd662Svikram int ret; 5571eb2bd662Svikram const char *fcn = "zfs_get_physical()"; 5572eb2bd662Svikram 5573eb2bd662Svikram assert(special); 5574eb2bd662Svikram 5575eb2bd662Svikram BAM_DPRINTF((D_FUNC_ENTRY1, fcn, special)); 5576eb2bd662Svikram 5577eb2bd662Svikram INJECT_ERROR1("INVALID_ZFS_SPECIAL", special = "/foo"); 5578eb2bd662Svikram if (special[0] == '/') { 5579eb2bd662Svikram bam_error(INVALID_ZFS_SPECIAL, special); 5580eb2bd662Svikram return (-1); 5581eb2bd662Svikram } 5582eb2bd662Svikram 5583eb2bd662Svikram (void) strlcpy(sdup, special, sizeof (sdup)); 5584eb2bd662Svikram 5585eb2bd662Svikram pool = strtok(sdup, "/"); 5586eb2bd662Svikram INJECT_ERROR1("ZFS_GET_PHYS_POOL", pool = NULL); 5587eb2bd662Svikram if (pool == NULL) { 5588eb2bd662Svikram bam_error(CANT_FIND_POOL_FROM_SPECIAL, special); 5589eb2bd662Svikram return (-1); 5590eb2bd662Svikram } 5591eb2bd662Svikram 5592eb2bd662Svikram (void) snprintf(cmd, sizeof (cmd), "/sbin/zpool status %s", pool); 5593eb2bd662Svikram 5594eb2bd662Svikram ret = exec_cmd(cmd, &flist); 5595eb2bd662Svikram INJECT_ERROR1("ZFS_GET_PHYS_STATUS", ret = 1); 5596eb2bd662Svikram if (ret != 0) { 5597eb2bd662Svikram bam_error(ZFS_GET_POOL_STATUS, pool); 5598eb2bd662Svikram return (-1); 5599eb2bd662Svikram } 5600eb2bd662Svikram 5601eb2bd662Svikram INJECT_ERROR1("ZFS_GET_PHYS_STATUS_OUT", flist.head = NULL); 5602eb2bd662Svikram if (flist.head == NULL) { 5603eb2bd662Svikram bam_error(BAD_ZPOOL_STATUS, pool); 5604eb2bd662Svikram filelist_free(&flist); 5605eb2bd662Svikram return (-1); 5606eb2bd662Svikram } 5607eb2bd662Svikram 5608eb2bd662Svikram for (lp = flist.head; lp; lp = lp->next) { 5609eb2bd662Svikram BAM_DPRINTF((D_STRTOK_ZPOOL_STATUS, fcn, lp->line)); 5610eb2bd662Svikram comp1 = strtok(lp->line, " \t"); 5611eb2bd662Svikram if (comp1 == NULL) { 5612eb2bd662Svikram free(lp->line); 5613eb2bd662Svikram lp->line = NULL; 5614eb2bd662Svikram } else { 5615eb2bd662Svikram comp1 = s_strdup(comp1); 5616eb2bd662Svikram free(lp->line); 5617eb2bd662Svikram lp->line = comp1; 5618eb2bd662Svikram } 5619eb2bd662Svikram } 5620eb2bd662Svikram 5621eb2bd662Svikram for (lp = flist.head; lp; lp = lp->next) { 5622eb2bd662Svikram if (lp->line == NULL) 5623eb2bd662Svikram continue; 5624eb2bd662Svikram if (strcmp(lp->line, pool) == 0) { 5625eb2bd662Svikram BAM_DPRINTF((D_FOUND_POOL_IN_ZPOOL_STATUS, fcn, pool)); 5626eb2bd662Svikram break; 5627eb2bd662Svikram } 5628eb2bd662Svikram } 5629eb2bd662Svikram 5630eb2bd662Svikram if (lp == NULL) { 5631eb2bd662Svikram bam_error(NO_POOL_IN_ZPOOL_STATUS, pool); 5632eb2bd662Svikram filelist_free(&flist); 5633eb2bd662Svikram return (-1); 5634eb2bd662Svikram } 5635eb2bd662Svikram 5636eb2bd662Svikram startlp = lp->next; 5637eb2bd662Svikram for (i = 0, lp = startlp; lp; lp = lp->next) { 5638eb2bd662Svikram if (lp->line == NULL) 5639eb2bd662Svikram continue; 5640eb2bd662Svikram if (strcmp(lp->line, "mirror") == 0) 5641eb2bd662Svikram continue; 5642eb2bd662Svikram if (lp->line[0] == '\0' || strcmp(lp->line, "errors:") == 0) 5643eb2bd662Svikram break; 5644eb2bd662Svikram i++; 5645eb2bd662Svikram BAM_DPRINTF((D_COUNTING_ZFS_PHYS, fcn, i)); 5646eb2bd662Svikram } 5647eb2bd662Svikram 5648eb2bd662Svikram if (i == 0) { 5649eb2bd662Svikram bam_error(NO_PHYS_IN_ZPOOL_STATUS, pool); 5650eb2bd662Svikram filelist_free(&flist); 5651eb2bd662Svikram return (-1); 5652eb2bd662Svikram } 5653eb2bd662Svikram 5654eb2bd662Svikram *n = i; 5655eb2bd662Svikram *physarray = s_calloc(*n, sizeof (char *)); 5656eb2bd662Svikram for (i = 0, lp = startlp; lp; lp = lp->next) { 5657eb2bd662Svikram if (lp->line == NULL) 5658eb2bd662Svikram continue; 5659eb2bd662Svikram if (strcmp(lp->line, "mirror") == 0) 5660eb2bd662Svikram continue; 5661eb2bd662Svikram if (strcmp(lp->line, "errors:") == 0) 5662eb2bd662Svikram break; 5663eb2bd662Svikram if (strncmp(lp->line, "/dev/dsk/", strlen("/dev/dsk/")) != 0 && 5664eb2bd662Svikram strncmp(lp->line, "/dev/rdsk/", 5665eb2bd662Svikram strlen("/dev/rdsk/")) != 0) { 5666eb2bd662Svikram (void) snprintf(dsk, sizeof (dsk), "/dev/dsk/%s", 5667eb2bd662Svikram lp->line); 5668eb2bd662Svikram } else { 5669eb2bd662Svikram (void) strlcpy(dsk, lp->line, sizeof (dsk)); 5670eb2bd662Svikram } 5671eb2bd662Svikram BAM_DPRINTF((D_ADDING_ZFS_PHYS, fcn, dsk, pool)); 5672eb2bd662Svikram (*physarray)[i++] = s_strdup(dsk); 5673eb2bd662Svikram } 5674eb2bd662Svikram 5675eb2bd662Svikram assert(i == *n); 5676eb2bd662Svikram 5677eb2bd662Svikram filelist_free(&flist); 5678eb2bd662Svikram 5679eb2bd662Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 5680eb2bd662Svikram return (0); 5681eb2bd662Svikram } 5682eb2bd662Svikram 5683963390b4Svikram /* 5684963390b4Svikram * Certain services needed to run metastat successfully may not 5685963390b4Svikram * be enabled. Enable them now. 5686963390b4Svikram */ 5687963390b4Svikram /* 5688963390b4Svikram * Checks if the specified service is online 5689963390b4Svikram * Returns: 1 if the service is online 5690963390b4Svikram * 0 if the service is not online 5691963390b4Svikram * -1 on error 5692963390b4Svikram */ 5693963390b4Svikram static int 5694963390b4Svikram is_svc_online(char *svc) 5695963390b4Svikram { 5696963390b4Svikram char *state; 5697963390b4Svikram const char *fcn = "is_svc_online()"; 5698963390b4Svikram 5699963390b4Svikram BAM_DPRINTF((D_FUNC_ENTRY1, fcn, svc)); 5700963390b4Svikram 5701963390b4Svikram state = smf_get_state(svc); 5702963390b4Svikram INJECT_ERROR2("GET_SVC_STATE", free(state), state = NULL); 5703963390b4Svikram if (state == NULL) { 5704963390b4Svikram bam_error(GET_SVC_STATE_ERR, svc); 5705963390b4Svikram return (-1); 5706963390b4Svikram } 5707963390b4Svikram BAM_DPRINTF((D_GOT_SVC_STATUS, fcn, svc)); 5708963390b4Svikram 5709963390b4Svikram if (strcmp(state, SCF_STATE_STRING_ONLINE) == 0) { 5710963390b4Svikram BAM_DPRINTF((D_SVC_ONLINE, fcn, svc)); 5711963390b4Svikram free(state); 5712963390b4Svikram return (1); 5713963390b4Svikram } 5714963390b4Svikram 5715963390b4Svikram BAM_DPRINTF((D_SVC_NOT_ONLINE, fcn, state, svc)); 5716963390b4Svikram 5717963390b4Svikram free(state); 5718963390b4Svikram 5719963390b4Svikram return (0); 5720963390b4Svikram } 5721963390b4Svikram 5722963390b4Svikram static int 5723963390b4Svikram enable_svc(char *svc) 5724963390b4Svikram { 5725963390b4Svikram int ret; 5726963390b4Svikram int sleeptime; 5727963390b4Svikram const char *fcn = "enable_svc()"; 5728963390b4Svikram 5729963390b4Svikram ret = is_svc_online(svc); 5730963390b4Svikram if (ret == -1) { 5731963390b4Svikram bam_error(SVC_IS_ONLINE_FAILED, svc); 5732963390b4Svikram return (-1); 5733963390b4Svikram } else if (ret == 1) { 5734963390b4Svikram BAM_DPRINTF((D_SVC_ALREADY_ONLINE, fcn, svc)); 5735963390b4Svikram return (0); 5736963390b4Svikram } 5737963390b4Svikram 5738963390b4Svikram /* Service is not enabled. Enable it now. */ 5739963390b4Svikram ret = smf_enable_instance(svc, 0); 5740963390b4Svikram INJECT_ERROR1("ENABLE_SVC_FAILED", ret = -1); 5741963390b4Svikram if (ret != 0) { 5742963390b4Svikram bam_error(ENABLE_SVC_FAILED, svc); 5743963390b4Svikram return (-1); 5744963390b4Svikram } 5745963390b4Svikram 5746963390b4Svikram BAM_DPRINTF((D_SVC_ONLINE_INITIATED, fcn, svc)); 5747963390b4Svikram 5748963390b4Svikram sleeptime = 0; 5749963390b4Svikram do { 5750963390b4Svikram ret = is_svc_online(svc); 5751963390b4Svikram INJECT_ERROR1("SVC_ONLINE_SUCCESS", ret = 1); 5752963390b4Svikram INJECT_ERROR1("SVC_ONLINE_FAILURE", ret = -1); 5753963390b4Svikram INJECT_ERROR1("SVC_ONLINE_NOTYET", ret = 0); 5754963390b4Svikram if (ret == -1) { 5755963390b4Svikram bam_error(ERR_SVC_GET_ONLINE, svc); 5756963390b4Svikram return (-1); 5757963390b4Svikram } else if (ret == 1) { 5758963390b4Svikram BAM_DPRINTF((D_SVC_NOW_ONLINE, fcn, svc)); 5759963390b4Svikram return (1); 5760963390b4Svikram } 5761963390b4Svikram (void) sleep(1); 5762963390b4Svikram } while (sleeptime < 60); 5763963390b4Svikram 5764963390b4Svikram bam_error(TIMEOUT_ENABLE_SVC, svc); 5765963390b4Svikram 5766963390b4Svikram return (-1); 5767963390b4Svikram } 5768963390b4Svikram 5769eb2bd662Svikram static int 5770eb2bd662Svikram ufs_get_physical(char *special, char ***physarray, int *n) 5771eb2bd662Svikram { 5772eb2bd662Svikram char cmd[PATH_MAX]; 5773eb2bd662Svikram char *shortname; 5774eb2bd662Svikram filelist_t flist = {0}; 5775eb2bd662Svikram char *meta; 5776eb2bd662Svikram char *type; 5777eb2bd662Svikram char *comp1; 5778eb2bd662Svikram char *comp2; 5779eb2bd662Svikram char *comp3; 5780eb2bd662Svikram char *comp4; 5781eb2bd662Svikram int i; 5782eb2bd662Svikram line_t *lp; 5783eb2bd662Svikram int ret; 5784963390b4Svikram char *svc; 5785eb2bd662Svikram const char *fcn = "ufs_get_physical()"; 5786eb2bd662Svikram 5787eb2bd662Svikram assert(special); 5788eb2bd662Svikram 5789eb2bd662Svikram BAM_DPRINTF((D_FUNC_ENTRY1, fcn, special)); 5790eb2bd662Svikram 5791eb2bd662Svikram if (strncmp(special, "/dev/md/", strlen("/dev/md/")) != 0) { 5792eb2bd662Svikram bam_error(UFS_GET_PHYS_NOT_SVM, special); 5793eb2bd662Svikram return (-1); 5794eb2bd662Svikram } 5795eb2bd662Svikram 5796eb2bd662Svikram if (strncmp(special, "/dev/md/dsk/", strlen("/dev/md/dsk/")) == 0) { 5797eb2bd662Svikram shortname = special + strlen("/dev/md/dsk/"); 5798eb2bd662Svikram } else if (strncmp(special, "/dev/md/rdsk/", 5799eb2bd662Svikram strlen("/dev/md/rdsk/")) == 0) { 5800eb2bd662Svikram shortname = special + strlen("/dev/md/rdsk"); 5801eb2bd662Svikram } else { 5802eb2bd662Svikram bam_error(UFS_GET_PHYS_INVALID_SVM, special); 5803eb2bd662Svikram return (-1); 5804eb2bd662Svikram } 5805eb2bd662Svikram 5806eb2bd662Svikram BAM_DPRINTF((D_UFS_SVM_SHORT, fcn, special, shortname)); 5807eb2bd662Svikram 5808963390b4Svikram svc = "network/rpc/meta:default"; 5809963390b4Svikram if (enable_svc(svc) == -1) { 5810963390b4Svikram bam_error(UFS_SVM_METASTAT_SVC_ERR, svc); 5811963390b4Svikram } 5812963390b4Svikram 5813eb2bd662Svikram (void) snprintf(cmd, sizeof (cmd), "/sbin/metastat -p %s", shortname); 5814eb2bd662Svikram 5815eb2bd662Svikram ret = exec_cmd(cmd, &flist); 5816eb2bd662Svikram INJECT_ERROR1("UFS_SVM_METASTAT", ret = 1); 5817eb2bd662Svikram if (ret != 0) { 5818eb2bd662Svikram bam_error(UFS_SVM_METASTAT_ERR, shortname); 5819eb2bd662Svikram return (-1); 5820eb2bd662Svikram } 5821eb2bd662Svikram 5822eb2bd662Svikram INJECT_ERROR1("UFS_SVM_METASTAT_OUT", flist.head = NULL); 5823eb2bd662Svikram if (flist.head == NULL) { 5824eb2bd662Svikram bam_error(BAD_UFS_SVM_METASTAT, shortname); 5825eb2bd662Svikram filelist_free(&flist); 5826eb2bd662Svikram return (-1); 5827eb2bd662Svikram } 5828eb2bd662Svikram 5829eb2bd662Svikram /* 5830eb2bd662Svikram * Check if not a mirror. We only parse a single metadevice 5831eb2bd662Svikram * if not a mirror 5832eb2bd662Svikram */ 5833eb2bd662Svikram meta = strtok(flist.head->line, " \t"); 5834eb2bd662Svikram type = strtok(NULL, " \t"); 5835eb2bd662Svikram if (meta == NULL || type == NULL) { 5836eb2bd662Svikram bam_error(ERROR_PARSE_UFS_SVM_METASTAT, shortname); 5837eb2bd662Svikram filelist_free(&flist); 5838eb2bd662Svikram return (-1); 5839eb2bd662Svikram } 5840eb2bd662Svikram if (strcmp(type, "-m") != 0) { 5841eb2bd662Svikram comp1 = strtok(NULL, " \t"); 5842eb2bd662Svikram comp2 = strtok(NULL, " \t"); 5843eb2bd662Svikram if (comp1 == NULL || comp2 != NULL) { 5844eb2bd662Svikram bam_error(INVALID_UFS_SVM_METASTAT, shortname); 5845eb2bd662Svikram filelist_free(&flist); 5846eb2bd662Svikram return (-1); 5847eb2bd662Svikram } 5848eb2bd662Svikram BAM_DPRINTF((D_UFS_SVM_ONE_COMP, fcn, comp1, shortname)); 5849eb2bd662Svikram *physarray = s_calloc(1, sizeof (char *)); 5850eb2bd662Svikram (*physarray)[0] = s_strdup(comp1); 5851eb2bd662Svikram *n = 1; 5852eb2bd662Svikram filelist_free(&flist); 5853eb2bd662Svikram return (0); 5854eb2bd662Svikram } 5855eb2bd662Svikram 5856eb2bd662Svikram /* 5857eb2bd662Svikram * Okay we have a mirror. Everything after the first line 5858eb2bd662Svikram * is a submirror 5859eb2bd662Svikram */ 5860eb2bd662Svikram for (i = 0, lp = flist.head->next; lp; lp = lp->next) { 5861eb2bd662Svikram if (strstr(lp->line, "/dev/dsk/") == NULL && 5862eb2bd662Svikram strstr(lp->line, "/dev/rdsk/") == NULL) { 5863eb2bd662Svikram bam_error(CANNOT_PARSE_UFS_SVM_METASTAT, shortname); 5864eb2bd662Svikram filelist_free(&flist); 5865eb2bd662Svikram return (-1); 5866eb2bd662Svikram } 5867eb2bd662Svikram i++; 5868eb2bd662Svikram } 5869eb2bd662Svikram 5870eb2bd662Svikram *physarray = s_calloc(i, sizeof (char *)); 5871eb2bd662Svikram *n = i; 5872eb2bd662Svikram 5873eb2bd662Svikram for (i = 0, lp = flist.head->next; lp; lp = lp->next) { 5874eb2bd662Svikram comp1 = strtok(lp->line, " \t"); 5875eb2bd662Svikram comp2 = strtok(NULL, " \t"); 5876eb2bd662Svikram comp3 = strtok(NULL, " \t"); 5877eb2bd662Svikram comp4 = strtok(NULL, " \t"); 5878eb2bd662Svikram 5879eb2bd662Svikram if (comp3 == NULL || comp4 == NULL || 5880eb2bd662Svikram (strncmp(comp4, "/dev/dsk/", strlen("/dev/dsk/")) != 0 && 5881eb2bd662Svikram strncmp(comp4, "/dev/rdsk/", strlen("/dev/rdsk/")) != 0)) { 5882eb2bd662Svikram bam_error(CANNOT_PARSE_UFS_SVM_SUBMIRROR, shortname); 5883eb2bd662Svikram filelist_free(&flist); 5884eb2bd662Svikram free_physarray(*physarray, *n); 5885eb2bd662Svikram return (-1); 5886eb2bd662Svikram } 5887eb2bd662Svikram 5888eb2bd662Svikram (*physarray)[i++] = s_strdup(comp4); 5889eb2bd662Svikram } 5890eb2bd662Svikram 5891eb2bd662Svikram assert(i == *n); 5892eb2bd662Svikram 5893eb2bd662Svikram filelist_free(&flist); 5894eb2bd662Svikram 5895eb2bd662Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 5896eb2bd662Svikram return (0); 5897eb2bd662Svikram } 5898eb2bd662Svikram 5899eb2bd662Svikram static int 5900eb2bd662Svikram get_physical(char *menu_root, char ***physarray, int *n) 5901eb2bd662Svikram { 5902eb2bd662Svikram char *special; 5903eb2bd662Svikram int ret; 5904eb2bd662Svikram const char *fcn = "get_physical()"; 5905eb2bd662Svikram 5906eb2bd662Svikram assert(menu_root); 5907eb2bd662Svikram assert(physarray); 5908eb2bd662Svikram assert(n); 5909eb2bd662Svikram 5910eb2bd662Svikram *physarray = NULL; 5911eb2bd662Svikram *n = 0; 5912eb2bd662Svikram 5913eb2bd662Svikram BAM_DPRINTF((D_FUNC_ENTRY1, fcn, menu_root)); 5914eb2bd662Svikram 5915eb2bd662Svikram /* First get the device special file from /etc/mnttab */ 5916eb2bd662Svikram special = get_special(menu_root); 5917eb2bd662Svikram INJECT_ERROR1("GET_PHYSICAL_SPECIAL", special = NULL); 5918eb2bd662Svikram if (special == NULL) { 5919eb2bd662Svikram bam_error(GET_SPECIAL_NULL, menu_root); 5920eb2bd662Svikram return (-1); 5921eb2bd662Svikram } 5922eb2bd662Svikram 5923eb2bd662Svikram /* If already a physical device nothing to do */ 5924eb2bd662Svikram if (strncmp(special, "/dev/dsk/", strlen("/dev/dsk/")) == 0 || 5925eb2bd662Svikram strncmp(special, "/dev/rdsk/", strlen("/dev/rdsk/")) == 0) { 5926eb2bd662Svikram BAM_DPRINTF((D_GET_PHYSICAL_ALREADY, fcn, menu_root, special)); 5927eb2bd662Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 5928eb2bd662Svikram *physarray = s_calloc(1, sizeof (char *)); 5929eb2bd662Svikram (*physarray)[0] = special; 5930eb2bd662Svikram *n = 1; 5931eb2bd662Svikram return (0); 5932eb2bd662Svikram } 5933eb2bd662Svikram 5934eb2bd662Svikram if (is_zfs(menu_root)) { 5935eb2bd662Svikram ret = zfs_get_physical(special, physarray, n); 5936eb2bd662Svikram } else if (is_ufs(menu_root)) { 5937eb2bd662Svikram ret = ufs_get_physical(special, physarray, n); 5938eb2bd662Svikram } else { 5939eb2bd662Svikram bam_error(GET_PHYSICAL_NOTSUP_FSTYPE, menu_root, special); 5940eb2bd662Svikram ret = -1; 5941eb2bd662Svikram } 5942eb2bd662Svikram 5943eb2bd662Svikram free(special); 5944eb2bd662Svikram 5945eb2bd662Svikram INJECT_ERROR1("GET_PHYSICAL_RET", ret = -1); 5946eb2bd662Svikram if (ret == -1) { 5947eb2bd662Svikram BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 5948eb2bd662Svikram } else { 5949eb2bd662Svikram int i; 5950eb2bd662Svikram assert (*n > 0); 5951eb2bd662Svikram for (i = 0; i < *n; i++) { 5952eb2bd662Svikram BAM_DPRINTF((D_GET_PHYSICAL_RET, fcn, (*physarray)[i])); 5953eb2bd662Svikram } 5954eb2bd662Svikram } 5955eb2bd662Svikram 5956eb2bd662Svikram return (ret); 5957eb2bd662Svikram } 5958eb2bd662Svikram 5959eb2bd662Svikram static int 5960eb2bd662Svikram is_bootdisk(char *osroot, char *physical) 5961eb2bd662Svikram { 5962eb2bd662Svikram int ret; 5963eb2bd662Svikram char *grubroot; 5964eb2bd662Svikram char *bootp; 5965eb2bd662Svikram const char *fcn = "is_bootdisk()"; 5966eb2bd662Svikram 5967eb2bd662Svikram assert(osroot); 5968eb2bd662Svikram assert(physical); 5969eb2bd662Svikram 5970eb2bd662Svikram BAM_DPRINTF((D_FUNC_ENTRY2, fcn, osroot, physical)); 5971eb2bd662Svikram 5972eb2bd662Svikram bootp = strstr(physical, "p0:boot"); 5973eb2bd662Svikram if (bootp) 5974eb2bd662Svikram *bootp = '\0'; 5975eb2bd662Svikram /* 5976eb2bd662Svikram * We just want the BIOS mapping for menu disk. 5977eb2bd662Svikram * Don't pass menu_root to get_grubroot() as the 5978eb2bd662Svikram * check that it is used for is not relevant here. 5979eb2bd662Svikram * The osroot is immaterial as well - it is only used to 5980eb2bd662Svikram * to find create_diskmap script. Everything hinges on 5981eb2bd662Svikram * "physical" 5982eb2bd662Svikram */ 5983eb2bd662Svikram grubroot = get_grubroot(osroot, physical, NULL); 5984eb2bd662Svikram 5985eb2bd662Svikram INJECT_ERROR1("IS_BOOTDISK_GRUBROOT", grubroot = NULL); 5986eb2bd662Svikram if (grubroot == NULL) { 5987eb2bd662Svikram bam_error(NO_GRUBROOT_FOR_DISK, fcn, physical); 5988eb2bd662Svikram return (0); 5989eb2bd662Svikram } 5990eb2bd662Svikram ret = grubroot[3] == '0'; 5991eb2bd662Svikram free(grubroot); 5992eb2bd662Svikram 5993eb2bd662Svikram BAM_DPRINTF((D_RETURN_RET, fcn, ret)); 5994eb2bd662Svikram 5995eb2bd662Svikram return (ret); 5996eb2bd662Svikram } 5997eb2bd662Svikram 5998eb2bd662Svikram /* 5999eb2bd662Svikram * Check if menu is on the boot device 6000eb2bd662Svikram * Return 0 (false) on error 6001eb2bd662Svikram */ 6002eb2bd662Svikram static int 6003eb2bd662Svikram menu_on_bootdisk(char *osroot, char *menu_root) 6004eb2bd662Svikram { 6005eb2bd662Svikram char **physarray; 6006eb2bd662Svikram int ret; 6007eb2bd662Svikram int n; 6008eb2bd662Svikram int i; 6009eb2bd662Svikram int on_bootdisk; 6010eb2bd662Svikram const char *fcn = "menu_on_bootdisk()"; 6011eb2bd662Svikram 6012eb2bd662Svikram BAM_DPRINTF((D_FUNC_ENTRY2, fcn, osroot, menu_root)); 6013eb2bd662Svikram 6014eb2bd662Svikram ret = get_physical(menu_root, &physarray, &n); 6015eb2bd662Svikram INJECT_ERROR1("MENU_ON_BOOTDISK_PHYSICAL", ret = -1); 6016eb2bd662Svikram if (ret != 0) { 6017eb2bd662Svikram bam_error(GET_PHYSICAL_MENU_NULL, menu_root); 6018eb2bd662Svikram return (0); 6019eb2bd662Svikram } 6020eb2bd662Svikram 6021eb2bd662Svikram assert(physarray); 6022eb2bd662Svikram assert(n > 0); 6023eb2bd662Svikram 6024eb2bd662Svikram on_bootdisk = 0; 6025eb2bd662Svikram for (i = 0; i < n; i++) { 6026eb2bd662Svikram assert(strncmp(physarray[i], "/dev/dsk/", 6027eb2bd662Svikram strlen("/dev/dsk/")) == 0 || 6028eb2bd662Svikram strncmp(physarray[i], "/dev/rdsk/", 6029eb2bd662Svikram strlen("/dev/rdsk/")) == 0); 6030eb2bd662Svikram 6031eb2bd662Svikram BAM_DPRINTF((D_CHECK_ON_BOOTDISK, fcn, physarray[i])); 6032eb2bd662Svikram if (is_bootdisk(osroot, physarray[i])) { 6033eb2bd662Svikram on_bootdisk = 1; 6034eb2bd662Svikram BAM_DPRINTF((D_IS_ON_BOOTDISK, fcn, physarray[i])); 6035eb2bd662Svikram } 6036eb2bd662Svikram } 6037eb2bd662Svikram 6038eb2bd662Svikram free_physarray(physarray, n); 6039eb2bd662Svikram 6040eb2bd662Svikram INJECT_ERROR1("ON_BOOTDISK_YES", on_bootdisk = 1); 6041eb2bd662Svikram INJECT_ERROR1("ON_BOOTDISK_NO", on_bootdisk = 0); 6042eb2bd662Svikram if (on_bootdisk) { 6043eb2bd662Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 6044eb2bd662Svikram } else { 6045eb2bd662Svikram BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 6046eb2bd662Svikram } 6047eb2bd662Svikram 6048eb2bd662Svikram return (on_bootdisk); 60497c478bd9Sstevel@tonic-gate } 60507c478bd9Sstevel@tonic-gate 6051eb2bd662Svikram void 6052eb2bd662Svikram bam_add_line(menu_t *mp, entry_t *entry, line_t *prev, line_t *lp) 60537c478bd9Sstevel@tonic-gate { 6054eb2bd662Svikram const char *fcn = "bam_add_line()"; 60557c478bd9Sstevel@tonic-gate 6056eb2bd662Svikram assert(mp); 6057eb2bd662Svikram assert(entry); 6058eb2bd662Svikram assert(prev); 6059eb2bd662Svikram assert(lp); 6060eb2bd662Svikram 6061eb2bd662Svikram lp->next = prev->next; 6062eb2bd662Svikram if (prev->next) { 6063eb2bd662Svikram BAM_DPRINTF((D_ADD_LINE_PREV_NEXT, fcn)); 6064eb2bd662Svikram prev->next->prev = lp; 6065eb2bd662Svikram } else { 6066eb2bd662Svikram BAM_DPRINTF((D_ADD_LINE_NOT_PREV_NEXT, fcn)); 6067eb2bd662Svikram } 6068eb2bd662Svikram prev->next = lp; 6069eb2bd662Svikram lp->prev = prev; 60707c478bd9Sstevel@tonic-gate 6071eb2bd662Svikram if (entry->end == prev) { 6072eb2bd662Svikram BAM_DPRINTF((D_ADD_LINE_LAST_LINE_IN_ENTRY, fcn)); 6073eb2bd662Svikram entry->end = lp; 6074eb2bd662Svikram } 6075eb2bd662Svikram if (mp->end == prev) { 6076eb2bd662Svikram assert(lp->next == NULL); 6077eb2bd662Svikram mp->end = lp; 6078eb2bd662Svikram BAM_DPRINTF((D_ADD_LINE_LAST_LINE_IN_MENU, fcn)); 6079eb2bd662Svikram } 60807c478bd9Sstevel@tonic-gate } 60817c478bd9Sstevel@tonic-gate 60828c1b6884Sszhou /* 60838c1b6884Sszhou * look for matching bootadm entry with specified parameters 60848c1b6884Sszhou * Here are the rules (based on existing usage): 60858c1b6884Sszhou * - If title is specified, match on title only 6086eb2bd662Svikram * - Else, match on root/findroot, kernel, and module. 6087eb2bd662Svikram * Note that, if root_opt is non-zero, the absence of 6088eb2bd662Svikram * root line is considered a match. 60898c1b6884Sszhou */ 60908c1b6884Sszhou static entry_t * 6091eb2bd662Svikram find_boot_entry( 6092eb2bd662Svikram menu_t *mp, 6093eb2bd662Svikram char *title, 6094eb2bd662Svikram char *kernel, 6095eb2bd662Svikram char *findroot, 6096eb2bd662Svikram char *root, 6097eb2bd662Svikram char *module, 6098eb2bd662Svikram int root_opt, 6099eb2bd662Svikram int *entry_num) 61008c1b6884Sszhou { 6101eb2bd662Svikram int i; 6102eb2bd662Svikram line_t *lp; 6103eb2bd662Svikram entry_t *ent; 6104eb2bd662Svikram const char *fcn = "find_boot_entry()"; 6105eb2bd662Svikram 6106eb2bd662Svikram if (entry_num) 6107eb2bd662Svikram *entry_num = BAM_ERROR; 61088c1b6884Sszhou 61098c1b6884Sszhou /* find matching entry */ 61108c1b6884Sszhou for (i = 0, ent = mp->entries; ent; i++, ent = ent->next) { 61118c1b6884Sszhou lp = ent->start; 61128c1b6884Sszhou 61138c1b6884Sszhou /* first line of entry must be bootadm comment */ 61148c1b6884Sszhou lp = ent->start; 6115ae115bc7Smrj if (lp->flags != BAM_COMMENT || 6116ae115bc7Smrj strcmp(lp->arg, BAM_BOOTADM_HDR) != 0) { 61178c1b6884Sszhou continue; 61188c1b6884Sszhou } 61198c1b6884Sszhou 61208c1b6884Sszhou /* advance to title line */ 61218c1b6884Sszhou lp = lp->next; 61228c1b6884Sszhou if (title) { 61238c1b6884Sszhou if (lp->flags == BAM_TITLE && lp->arg && 6124eb2bd662Svikram strcmp(lp->arg, title) == 0) { 6125eb2bd662Svikram BAM_DPRINTF((D_MATCHED_TITLE, fcn, title)); 61268c1b6884Sszhou break; 6127eb2bd662Svikram } 6128eb2bd662Svikram BAM_DPRINTF((D_NOMATCH_TITLE, fcn, title, lp->arg)); 61298c1b6884Sszhou continue; /* check title only */ 61308c1b6884Sszhou } 61318c1b6884Sszhou 61328c1b6884Sszhou lp = lp->next; /* advance to root line */ 6133843e1988Sjohnlev if (lp == NULL) { 6134843e1988Sjohnlev continue; 6135eb2bd662Svikram } else if (strcmp(lp->cmd, menu_cmds[FINDROOT_CMD]) == 0) { 6136eb2bd662Svikram INJECT_ERROR1("FIND_BOOT_ENTRY_NULL_FINDROOT", 6137eb2bd662Svikram findroot = NULL); 6138eb2bd662Svikram if (findroot == NULL) { 6139eb2bd662Svikram BAM_DPRINTF((D_NOMATCH_FINDROOT_NULL, 6140eb2bd662Svikram fcn, lp->arg)); 6141eb2bd662Svikram continue; 6142eb2bd662Svikram } 6143eb2bd662Svikram /* findroot command found, try match */ 6144eb2bd662Svikram if (strcmp(lp->arg, findroot) != 0) { 6145eb2bd662Svikram BAM_DPRINTF((D_NOMATCH_FINDROOT, 6146eb2bd662Svikram fcn, findroot, lp->arg)); 6147eb2bd662Svikram continue; 6148eb2bd662Svikram } 6149eb2bd662Svikram BAM_DPRINTF((D_MATCHED_FINDROOT, fcn, findroot)); 6150eb2bd662Svikram lp = lp->next; /* advance to kernel line */ 6151843e1988Sjohnlev } else if (strcmp(lp->cmd, menu_cmds[ROOT_CMD]) == 0) { 6152eb2bd662Svikram INJECT_ERROR1("FIND_BOOT_ENTRY_NULL_ROOT", root = NULL); 6153eb2bd662Svikram if (root == NULL) { 6154eb2bd662Svikram BAM_DPRINTF((D_NOMATCH_ROOT_NULL, 6155eb2bd662Svikram fcn, lp->arg)); 6156eb2bd662Svikram continue; 6157eb2bd662Svikram } 6158eb2bd662Svikram /* root cmd found, try match */ 61598c1b6884Sszhou if (strcmp(lp->arg, root) != 0) { 6160eb2bd662Svikram BAM_DPRINTF((D_NOMATCH_ROOT, 6161eb2bd662Svikram fcn, root, lp->arg)); 61628c1b6884Sszhou continue; 61638c1b6884Sszhou } 6164eb2bd662Svikram BAM_DPRINTF((D_MATCHED_ROOT, fcn, root)); 61658c1b6884Sszhou lp = lp->next; /* advance to kernel line */ 61668c1b6884Sszhou } else { 6167eb2bd662Svikram INJECT_ERROR1("FIND_BOOT_ENTRY_ROOT_OPT_NO", 6168eb2bd662Svikram root_opt = 0); 6169eb2bd662Svikram INJECT_ERROR1("FIND_BOOT_ENTRY_ROOT_OPT_YES", 6170eb2bd662Svikram root_opt = 1); 61718c1b6884Sszhou /* no root command, see if root is optional */ 61728c1b6884Sszhou if (root_opt == 0) { 6173eb2bd662Svikram BAM_DPRINTF((D_NO_ROOT_OPT, fcn)); 61748c1b6884Sszhou continue; 61758c1b6884Sszhou } 6176eb2bd662Svikram BAM_DPRINTF((D_ROOT_OPT, fcn)); 61778c1b6884Sszhou } 61788c1b6884Sszhou 61798c1b6884Sszhou if (lp == NULL || lp->next == NULL) { 61808c1b6884Sszhou continue; 61818c1b6884Sszhou } 61828c1b6884Sszhou 6183843e1988Sjohnlev if (kernel && 6184843e1988Sjohnlev (!check_cmd(lp->cmd, KERNEL_CMD, lp->arg, kernel))) { 6185843e1988Sjohnlev continue; 6186843e1988Sjohnlev } 6187eb2bd662Svikram BAM_DPRINTF((D_KERNEL_MATCH, fcn, kernel, lp->arg)); 6188843e1988Sjohnlev 61890d69385cSrscott /* 6190843e1988Sjohnlev * Check for matching module entry (failsafe or normal). 6191843e1988Sjohnlev * If it fails to match, we go around the loop again. 6192843e1988Sjohnlev * For xpv entries, there are two module lines, so we 6193843e1988Sjohnlev * do the check twice. 61940d69385cSrscott */ 61958c1b6884Sszhou lp = lp->next; /* advance to module line */ 6196843e1988Sjohnlev if (check_cmd(lp->cmd, MODULE_CMD, lp->arg, module) || 6197843e1988Sjohnlev (((lp = lp->next) != NULL) && 6198843e1988Sjohnlev check_cmd(lp->cmd, MODULE_CMD, lp->arg, module))) { 6199843e1988Sjohnlev /* match found */ 6200eb2bd662Svikram BAM_DPRINTF((D_MODULE_MATCH, fcn, module, lp->arg)); 6201843e1988Sjohnlev break; 62028c1b6884Sszhou } 62038c1b6884Sszhou } 62048c1b6884Sszhou 6205eb2bd662Svikram if (ent && entry_num) { 6206843e1988Sjohnlev *entry_num = i; 6207843e1988Sjohnlev } 6208eb2bd662Svikram 6209eb2bd662Svikram if (ent) { 6210eb2bd662Svikram BAM_DPRINTF((D_RETURN_RET, fcn, i)); 6211eb2bd662Svikram } else { 6212eb2bd662Svikram BAM_DPRINTF((D_RETURN_RET, fcn, BAM_ERROR)); 6213eb2bd662Svikram } 62148c1b6884Sszhou return (ent); 62158c1b6884Sszhou } 62168c1b6884Sszhou 62178c1b6884Sszhou static int 6218eb2bd662Svikram update_boot_entry(menu_t *mp, char *title, char *findroot, char *root, 6219eb2bd662Svikram char *kernel, char *mod_kernel, char *module, int root_opt) 62208c1b6884Sszhou { 6221eb2bd662Svikram int i; 6222eb2bd662Svikram int change_kernel = 0; 6223eb2bd662Svikram entry_t *ent; 6224eb2bd662Svikram line_t *lp; 6225eb2bd662Svikram line_t *tlp; 6226eb2bd662Svikram char linebuf[BAM_MAXLINE]; 6227eb2bd662Svikram const char *fcn = "update_boot_entry()"; 62288c1b6884Sszhou 62298c1b6884Sszhou /* note: don't match on title, it's updated on upgrade */ 6230eb2bd662Svikram ent = find_boot_entry(mp, NULL, kernel, findroot, root, module, 6231eb2bd662Svikram root_opt, &i); 6232ae115bc7Smrj if ((ent == NULL) && (bam_direct == BAM_DIRECT_DBOOT)) { 6233ae115bc7Smrj /* 6234ae115bc7Smrj * We may be upgrading a kernel from multiboot to 6235eb2bd662Svikram * directboot. Look for a multiboot entry. A multiboot 6236eb2bd662Svikram * entry will not have a findroot line. 6237ae115bc7Smrj */ 6238eb2bd662Svikram ent = find_boot_entry(mp, NULL, "multiboot", NULL, root, 6239eb2bd662Svikram MULTIBOOT_ARCHIVE, root_opt, &i); 6240ae115bc7Smrj if (ent != NULL) { 6241eb2bd662Svikram BAM_DPRINTF((D_UPGRADE_FROM_MULTIBOOT, fcn, root)); 6242ae115bc7Smrj change_kernel = 1; 6243ae115bc7Smrj } 6244eb2bd662Svikram } else if (ent) { 6245eb2bd662Svikram BAM_DPRINTF((D_FOUND_FINDROOT, fcn, findroot)); 6246ae115bc7Smrj } 6247eb2bd662Svikram 6248eb2bd662Svikram if (ent == NULL) { 6249eb2bd662Svikram BAM_DPRINTF((D_ENTRY_NOT_FOUND_CREATING, fcn, findroot)); 6250eb2bd662Svikram return (add_boot_entry(mp, title, findroot, 6251843e1988Sjohnlev kernel, mod_kernel, module)); 6252eb2bd662Svikram } 62538c1b6884Sszhou 6254eb2bd662Svikram /* replace title of existing entry and update findroot line */ 62558c1b6884Sszhou lp = ent->start; 62568c1b6884Sszhou lp = lp->next; /* title line */ 62578c1b6884Sszhou (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s", 62588c1b6884Sszhou menu_cmds[TITLE_CMD], menu_cmds[SEP_CMD], title); 62598c1b6884Sszhou free(lp->arg); 62608c1b6884Sszhou free(lp->line); 62618c1b6884Sszhou lp->arg = s_strdup(title); 62628c1b6884Sszhou lp->line = s_strdup(linebuf); 6263eb2bd662Svikram BAM_DPRINTF((D_CHANGING_TITLE, fcn, title)); 62648c1b6884Sszhou 6265eb2bd662Svikram tlp = lp; /* title line */ 62668c1b6884Sszhou lp = lp->next; /* root line */ 6267eb2bd662Svikram 6268eb2bd662Svikram /* if no root or findroot command, create a new line_t */ 6269eb2bd662Svikram if (strcmp(lp->cmd, menu_cmds[ROOT_CMD]) != 0 && 6270eb2bd662Svikram strcmp(lp->cmd, menu_cmds[FINDROOT_CMD]) != 0) { 6271eb2bd662Svikram lp = s_calloc(1, sizeof (line_t)); 6272eb2bd662Svikram bam_add_line(mp, ent, tlp, lp); 6273eb2bd662Svikram } else { 6274eb2bd662Svikram free(lp->cmd); 6275eb2bd662Svikram free(lp->sep); 6276eb2bd662Svikram free(lp->arg); 6277eb2bd662Svikram free(lp->line); 62788c1b6884Sszhou } 6279ae115bc7Smrj 6280eb2bd662Svikram lp->cmd = s_strdup(menu_cmds[FINDROOT_CMD]); 6281eb2bd662Svikram lp->sep = s_strdup(menu_cmds[SEP_CMD]); 6282eb2bd662Svikram lp->arg = s_strdup(findroot); 6283eb2bd662Svikram (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s", 6284eb2bd662Svikram menu_cmds[FINDROOT_CMD], menu_cmds[SEP_CMD], findroot); 6285eb2bd662Svikram lp->line = s_strdup(linebuf); 6286eb2bd662Svikram BAM_DPRINTF((D_ADDING_FINDROOT_LINE, fcn, findroot)); 6287eb2bd662Svikram 6288eb2bd662Svikram /* kernel line */ 6289eb2bd662Svikram lp = lp->next; 6290eb2bd662Svikram 6291ae115bc7Smrj if (change_kernel) { 6292ae115bc7Smrj /* 6293ae115bc7Smrj * We're upgrading from multiboot to directboot. 6294ae115bc7Smrj */ 6295ae115bc7Smrj if (strcmp(lp->cmd, menu_cmds[KERNEL_CMD]) == 0) { 6296ae115bc7Smrj (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s", 6297ae115bc7Smrj menu_cmds[KERNEL_DOLLAR_CMD], menu_cmds[SEP_CMD], 6298ae115bc7Smrj kernel); 6299eb2bd662Svikram free(lp->cmd); 6300ae115bc7Smrj free(lp->arg); 6301ae115bc7Smrj free(lp->line); 6302eb2bd662Svikram lp->cmd = s_strdup(menu_cmds[KERNEL_DOLLAR_CMD]); 6303ae115bc7Smrj lp->arg = s_strdup(kernel); 6304ae115bc7Smrj lp->line = s_strdup(linebuf); 6305ae115bc7Smrj lp = lp->next; 6306eb2bd662Svikram BAM_DPRINTF((D_ADDING_KERNEL_DOLLAR, fcn, kernel)); 6307ae115bc7Smrj } 6308ae115bc7Smrj if (strcmp(lp->cmd, menu_cmds[MODULE_CMD]) == 0) { 6309ae115bc7Smrj (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s", 6310ae115bc7Smrj menu_cmds[MODULE_DOLLAR_CMD], menu_cmds[SEP_CMD], 6311ae115bc7Smrj module); 6312eb2bd662Svikram free(lp->cmd); 6313ae115bc7Smrj free(lp->arg); 6314ae115bc7Smrj free(lp->line); 6315eb2bd662Svikram lp->cmd = s_strdup(menu_cmds[MODULE_DOLLAR_CMD]); 6316ae115bc7Smrj lp->arg = s_strdup(module); 6317ae115bc7Smrj lp->line = s_strdup(linebuf); 6318ae115bc7Smrj lp = lp->next; 6319eb2bd662Svikram BAM_DPRINTF((D_ADDING_MODULE_DOLLAR, fcn, module)); 6320ae115bc7Smrj } 6321ae115bc7Smrj } 6322eb2bd662Svikram BAM_DPRINTF((D_RETURN_RET, fcn, i)); 63238c1b6884Sszhou return (i); 63248c1b6884Sszhou } 63258c1b6884Sszhou 6326eb2bd662Svikram int 6327eb2bd662Svikram root_optional(char *osroot, char *menu_root) 6328eb2bd662Svikram { 6329eb2bd662Svikram char *ospecial; 6330eb2bd662Svikram char *mspecial; 6331eb2bd662Svikram char *slash; 6332eb2bd662Svikram int root_opt; 6333eb2bd662Svikram int ret1; 6334eb2bd662Svikram int ret2; 6335eb2bd662Svikram const char *fcn = "root_optional()"; 6336eb2bd662Svikram 6337eb2bd662Svikram BAM_DPRINTF((D_FUNC_ENTRY2, fcn, osroot, menu_root)); 6338eb2bd662Svikram 6339eb2bd662Svikram /* 6340eb2bd662Svikram * For all filesystems except ZFS, a straight compare of osroot 6341eb2bd662Svikram * and menu_root will tell us if root is optional. 6342eb2bd662Svikram * For ZFS, the situation is complicated by the fact that 6343eb2bd662Svikram * menu_root and osroot are always different 6344eb2bd662Svikram */ 6345eb2bd662Svikram ret1 = is_zfs(osroot); 6346eb2bd662Svikram ret2 = is_zfs(menu_root); 6347eb2bd662Svikram INJECT_ERROR1("ROOT_OPT_NOT_ZFS", ret1 = 0); 6348eb2bd662Svikram if (!ret1 || !ret2) { 6349eb2bd662Svikram BAM_DPRINTF((D_ROOT_OPT_NOT_ZFS, fcn, osroot, menu_root)); 6350eb2bd662Svikram root_opt = (strcmp(osroot, menu_root) == 0); 6351eb2bd662Svikram goto out; 6352eb2bd662Svikram } 6353eb2bd662Svikram 6354eb2bd662Svikram ospecial = get_special(osroot); 6355eb2bd662Svikram INJECT_ERROR1("ROOT_OPTIONAL_OSPECIAL", ospecial = NULL); 6356eb2bd662Svikram if (ospecial == NULL) { 6357eb2bd662Svikram bam_error(GET_OSROOT_SPECIAL_ERR, osroot); 6358eb2bd662Svikram return (0); 6359eb2bd662Svikram } 6360eb2bd662Svikram BAM_DPRINTF((D_ROOT_OPTIONAL_OSPECIAL, fcn, ospecial, osroot)); 6361eb2bd662Svikram 6362eb2bd662Svikram mspecial = get_special(menu_root); 6363eb2bd662Svikram INJECT_ERROR1("ROOT_OPTIONAL_MSPECIAL", mspecial = NULL); 6364eb2bd662Svikram if (mspecial == NULL) { 6365eb2bd662Svikram bam_error(GET_MENU_ROOT_SPECIAL_ERR, menu_root); 6366eb2bd662Svikram free(ospecial); 6367eb2bd662Svikram return (0); 6368eb2bd662Svikram } 6369eb2bd662Svikram BAM_DPRINTF((D_ROOT_OPTIONAL_MSPECIAL, fcn, mspecial, menu_root)); 6370eb2bd662Svikram 6371eb2bd662Svikram slash = strchr(ospecial, '/'); 6372eb2bd662Svikram if (slash) 6373eb2bd662Svikram *slash = '\0'; 6374eb2bd662Svikram BAM_DPRINTF((D_ROOT_OPTIONAL_FIXED_OSPECIAL, fcn, ospecial, osroot)); 6375eb2bd662Svikram 6376eb2bd662Svikram root_opt = (strcmp(ospecial, mspecial) == 0); 6377eb2bd662Svikram 6378eb2bd662Svikram free(ospecial); 6379eb2bd662Svikram free(mspecial); 6380eb2bd662Svikram 6381eb2bd662Svikram out: 6382eb2bd662Svikram INJECT_ERROR1("ROOT_OPTIONAL_NO", root_opt = 0); 6383eb2bd662Svikram INJECT_ERROR1("ROOT_OPTIONAL_YES", root_opt = 1); 6384eb2bd662Svikram if (root_opt) { 6385eb2bd662Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 6386eb2bd662Svikram } else { 6387eb2bd662Svikram BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 6388eb2bd662Svikram } 6389eb2bd662Svikram 6390eb2bd662Svikram return (root_opt); 6391eb2bd662Svikram } 6392eb2bd662Svikram 63937c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 63947c478bd9Sstevel@tonic-gate static error_t 6395eb2bd662Svikram update_entry(menu_t *mp, char *menu_root, char *osdev) 63967c478bd9Sstevel@tonic-gate { 6397eb2bd662Svikram int entry; 6398eb2bd662Svikram char *grubsign; 6399eb2bd662Svikram char *grubroot; 6400eb2bd662Svikram char *title; 6401eb2bd662Svikram char osroot[PATH_MAX]; 6402eb2bd662Svikram char *failsafe_kernel = NULL; 6403eb2bd662Svikram struct stat sbuf; 6404eb2bd662Svikram char failsafe[256]; 6405eb2bd662Svikram int ret; 6406eb2bd662Svikram const char *fcn = "update_entry()"; 64077c478bd9Sstevel@tonic-gate 64087c478bd9Sstevel@tonic-gate assert(mp); 6409eb2bd662Svikram assert(menu_root); 6410eb2bd662Svikram assert(osdev); 6411eb2bd662Svikram assert(bam_root); 6412eb2bd662Svikram 6413eb2bd662Svikram BAM_DPRINTF((D_FUNC_ENTRY3, fcn, menu_root, osdev, bam_root)); 6414eb2bd662Svikram 6415eb2bd662Svikram (void) strlcpy(osroot, bam_root, sizeof (osroot)); 64167c478bd9Sstevel@tonic-gate 64177c478bd9Sstevel@tonic-gate title = get_title(osroot); 6418eb2bd662Svikram assert(title); 64197c478bd9Sstevel@tonic-gate 6420eb2bd662Svikram grubsign = get_grubsign(osroot, osdev); 6421eb2bd662Svikram INJECT_ERROR1("GET_GRUBSIGN_FAIL", grubsign = NULL); 6422eb2bd662Svikram if (grubsign == NULL) { 6423eb2bd662Svikram bam_error(GET_GRUBSIGN_ERROR, osroot, osdev); 64247c478bd9Sstevel@tonic-gate return (BAM_ERROR); 64257c478bd9Sstevel@tonic-gate } 6426eb2bd662Svikram 6427eb2bd662Svikram /* 6428eb2bd662Svikram * It is not a fatal error if get_grubroot() fails 6429eb2bd662Svikram * We no longer rely on biosdev to populate the 6430eb2bd662Svikram * menu 6431eb2bd662Svikram */ 6432eb2bd662Svikram grubroot = get_grubroot(osroot, osdev, menu_root); 6433eb2bd662Svikram INJECT_ERROR1("GET_GRUBROOT_FAIL", grubroot = NULL); 6434eb2bd662Svikram if (grubroot) { 6435eb2bd662Svikram BAM_DPRINTF((D_GET_GRUBROOT_SUCCESS, 6436eb2bd662Svikram fcn, osroot, osdev, menu_root)); 6437eb2bd662Svikram } else { 6438eb2bd662Svikram BAM_DPRINTF((D_GET_GRUBROOT_FAILURE, 6439eb2bd662Svikram fcn, osroot, osdev, menu_root)); 64407c478bd9Sstevel@tonic-gate } 64417c478bd9Sstevel@tonic-gate 64427c478bd9Sstevel@tonic-gate /* add the entry for normal Solaris */ 6443eb2bd662Svikram INJECT_ERROR1("UPDATE_ENTRY_MULTIBOOT", 6444eb2bd662Svikram bam_direct = BAM_DIRECT_MULTIBOOT); 6445ae115bc7Smrj if (bam_direct == BAM_DIRECT_DBOOT) { 6446eb2bd662Svikram entry = update_boot_entry(mp, title, grubsign, grubroot, 6447e7cbe64fSgw (bam_zfs ? DIRECT_BOOT_KERNEL_ZFS : DIRECT_BOOT_KERNEL), 6448eb2bd662Svikram NULL, DIRECT_BOOT_ARCHIVE, 6449eb2bd662Svikram root_optional(osroot, menu_root)); 6450eb2bd662Svikram BAM_DPRINTF((D_UPDATED_BOOT_ENTRY, fcn, bam_zfs, grubsign)); 6451843e1988Sjohnlev if ((entry != BAM_ERROR) && (bam_is_hv == BAM_HV_PRESENT)) { 6452eb2bd662Svikram (void) update_boot_entry(mp, NEW_HV_ENTRY, grubsign, 6453eb2bd662Svikram grubroot, XEN_MENU, bam_zfs ? 6454eb2bd662Svikram XEN_KERNEL_MODULE_LINE_ZFS : XEN_KERNEL_MODULE_LINE, 6455eb2bd662Svikram DIRECT_BOOT_ARCHIVE, 6456eb2bd662Svikram root_optional(osroot, menu_root)); 6457eb2bd662Svikram BAM_DPRINTF((D_UPDATED_HV_ENTRY, 6458eb2bd662Svikram fcn, bam_zfs, grubsign)); 6459843e1988Sjohnlev } 6460ae115bc7Smrj } else { 6461eb2bd662Svikram entry = update_boot_entry(mp, title, grubsign, grubroot, 6462eb2bd662Svikram MULTI_BOOT, NULL, MULTIBOOT_ARCHIVE, 6463eb2bd662Svikram root_optional(osroot, menu_root)); 6464eb2bd662Svikram 6465eb2bd662Svikram BAM_DPRINTF((D_UPDATED_MULTIBOOT_ENTRY, fcn, grubsign)); 6466ae115bc7Smrj } 64677c478bd9Sstevel@tonic-gate 6468843e1988Sjohnlev /* 6469843e1988Sjohnlev * Add the entry for failsafe archive. On a bfu'd system, the 6470843e1988Sjohnlev * failsafe may be different than the installed kernel. 6471843e1988Sjohnlev */ 6472eb2bd662Svikram (void) snprintf(failsafe, sizeof (failsafe), "%s%s", 6473eb2bd662Svikram osroot, FAILSAFE_ARCHIVE); 6474ae115bc7Smrj if (stat(failsafe, &sbuf) == 0) { 647560d0a590Srscott 647660d0a590Srscott /* Figure out where the kernel line should point */ 647760d0a590Srscott (void) snprintf(failsafe, sizeof (failsafe), "%s%s", osroot, 647860d0a590Srscott DIRECT_BOOT_FAILSAFE_KERNEL); 647960d0a590Srscott if (stat(failsafe, &sbuf) == 0) { 6480963390b4Svikram failsafe_kernel = DIRECT_BOOT_FAILSAFE_LINE; 648160d0a590Srscott } else { 648260d0a590Srscott (void) snprintf(failsafe, sizeof (failsafe), "%s%s", 648360d0a590Srscott osroot, MULTI_BOOT_FAILSAFE); 648460d0a590Srscott if (stat(failsafe, &sbuf) == 0) { 648560d0a590Srscott failsafe_kernel = MULTI_BOOT_FAILSAFE_LINE; 648660d0a590Srscott } 648760d0a590Srscott } 648860d0a590Srscott if (failsafe_kernel != NULL) { 6489eb2bd662Svikram (void) update_boot_entry(mp, FAILSAFE_TITLE, grubsign, 6490eb2bd662Svikram grubroot, failsafe_kernel, NULL, FAILSAFE_ARCHIVE, 6491eb2bd662Svikram root_optional(osroot, menu_root)); 6492eb2bd662Svikram BAM_DPRINTF((D_UPDATED_FAILSAFE_ENTRY, fcn, 6493eb2bd662Svikram failsafe_kernel)); 649460d0a590Srscott } 6495ae115bc7Smrj } 6496eb2bd662Svikram free(grubroot); 64977c478bd9Sstevel@tonic-gate 6498eb2bd662Svikram INJECT_ERROR1("UPDATE_ENTRY_ERROR", entry = BAM_ERROR); 64997c478bd9Sstevel@tonic-gate if (entry == BAM_ERROR) { 6500eb2bd662Svikram bam_error(FAILED_TO_ADD_BOOT_ENTRY, title, grubsign); 6501eb2bd662Svikram free(grubsign); 65027c478bd9Sstevel@tonic-gate return (BAM_ERROR); 65037c478bd9Sstevel@tonic-gate } 6504eb2bd662Svikram free(grubsign); 6505b610f78eSvikram 6506eb2bd662Svikram update_numbering(mp); 6507eb2bd662Svikram ret = set_global(mp, menu_cmds[DEFAULT_CMD], entry); 6508eb2bd662Svikram INJECT_ERROR1("SET_DEFAULT_ERROR", ret = BAM_ERROR); 6509eb2bd662Svikram if (ret == BAM_ERROR) { 6510eb2bd662Svikram bam_error(SET_DEFAULT_FAILED, entry); 6511b610f78eSvikram } 6512eb2bd662Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 6513eb2bd662Svikram return (BAM_WRITE); 6514b610f78eSvikram } 6515b610f78eSvikram 65168c1b6884Sszhou static void 6517ae115bc7Smrj save_default_entry(menu_t *mp, const char *which) 65188c1b6884Sszhou { 6519eb2bd662Svikram int lineNum; 6520eb2bd662Svikram int entryNum; 6521eb2bd662Svikram int entry = 0; /* default is 0 */ 6522eb2bd662Svikram char linebuf[BAM_MAXLINE]; 6523eb2bd662Svikram line_t *lp = mp->curdefault; 6524eb2bd662Svikram const char *fcn = "save_default_entry()"; 65258c1b6884Sszhou 6526bff269d0Svikram if (mp->start) { 6527bff269d0Svikram lineNum = mp->end->lineNum; 6528bff269d0Svikram entryNum = mp->end->entryNum; 6529bff269d0Svikram } else { 6530bff269d0Svikram lineNum = LINE_INIT; 6531bff269d0Svikram entryNum = ENTRY_INIT; 6532bff269d0Svikram } 6533bff269d0Svikram 65348c1b6884Sszhou if (lp) 65358c1b6884Sszhou entry = s_strtol(lp->arg); 65368c1b6884Sszhou 6537ae115bc7Smrj (void) snprintf(linebuf, sizeof (linebuf), "#%s%d", which, entry); 6538eb2bd662Svikram BAM_DPRINTF((D_SAVING_DEFAULT_TO, fcn, linebuf)); 65398c1b6884Sszhou line_parser(mp, linebuf, &lineNum, &entryNum); 6540eb2bd662Svikram BAM_DPRINTF((D_SAVED_DEFAULT_TO, fcn, lineNum, entryNum)); 65418c1b6884Sszhou } 65428c1b6884Sszhou 65438c1b6884Sszhou static void 6544ae115bc7Smrj restore_default_entry(menu_t *mp, const char *which, line_t *lp) 65458c1b6884Sszhou { 6546eb2bd662Svikram int entry; 6547eb2bd662Svikram char *str; 6548eb2bd662Svikram const char *fcn = "restore_default_entry()"; 65498c1b6884Sszhou 6550eb2bd662Svikram if (lp == NULL) { 6551eb2bd662Svikram BAM_DPRINTF((D_RESTORE_DEFAULT_NULL, fcn)); 65528c1b6884Sszhou return; /* nothing to restore */ 6553eb2bd662Svikram } 6554eb2bd662Svikram 6555eb2bd662Svikram BAM_DPRINTF((D_RESTORE_DEFAULT_STR, fcn, which)); 65568c1b6884Sszhou 6557ae115bc7Smrj str = lp->arg + strlen(which); 65588c1b6884Sszhou entry = s_strtol(str); 65598c1b6884Sszhou (void) set_global(mp, menu_cmds[DEFAULT_CMD], entry); 65608c1b6884Sszhou 6561eb2bd662Svikram BAM_DPRINTF((D_RESTORED_DEFAULT_TO, fcn, entry)); 6562eb2bd662Svikram 65638c1b6884Sszhou /* delete saved old default line */ 65648c1b6884Sszhou unlink_line(mp, lp); 65658c1b6884Sszhou line_free(lp); 65668c1b6884Sszhou } 65678c1b6884Sszhou 65687c478bd9Sstevel@tonic-gate /* 65697c478bd9Sstevel@tonic-gate * This function is for supporting reboot with args. 65707c478bd9Sstevel@tonic-gate * The opt value can be: 65717c478bd9Sstevel@tonic-gate * NULL delete temp entry, if present 6572eb2bd662Svikram * entry=<n> switches default entry to <n> 65737c478bd9Sstevel@tonic-gate * else treated as boot-args and setup a temperary menu entry 65747c478bd9Sstevel@tonic-gate * and make it the default 6575eb2bd662Svikram * Note that we are always rebooting the current OS instance 6576eb2bd662Svikram * so osroot == / always. 65777c478bd9Sstevel@tonic-gate */ 65787c478bd9Sstevel@tonic-gate #define REBOOT_TITLE "Solaris_reboot_transient" 65797c478bd9Sstevel@tonic-gate 65808c1b6884Sszhou /*ARGSUSED*/ 65817c478bd9Sstevel@tonic-gate static error_t 6582eb2bd662Svikram update_temp(menu_t *mp, char *dummy, char *opt) 65837c478bd9Sstevel@tonic-gate { 6584eb2bd662Svikram int entry; 6585eb2bd662Svikram char *osdev; 6586eb2bd662Svikram char *fstype; 6587eb2bd662Svikram char *sign; 6588eb2bd662Svikram char *opt_ptr; 6589eb2bd662Svikram char *path; 6590eb2bd662Svikram char kernbuf[BUFSIZ]; 6591eb2bd662Svikram char args_buf[BUFSIZ]; 6592eb2bd662Svikram char signbuf[PATH_MAX]; 6593eb2bd662Svikram int ret; 6594eb2bd662Svikram const char *fcn = "update_temp()"; 65957c478bd9Sstevel@tonic-gate 65967c478bd9Sstevel@tonic-gate assert(mp); 6597eb2bd662Svikram assert(dummy == NULL); 6598eb2bd662Svikram 6599eb2bd662Svikram /* opt can be NULL */ 6600eb2bd662Svikram BAM_DPRINTF((D_FUNC_ENTRY1, fcn, opt ? opt : "<NULL>")); 6601eb2bd662Svikram BAM_DPRINTF((D_BAM_ROOT, fcn, bam_alt_root, bam_root)); 6602eb2bd662Svikram 6603eb2bd662Svikram if (bam_alt_root || bam_rootlen != 1 || 6604eb2bd662Svikram strcmp(bam_root, "/") != 0 || 6605eb2bd662Svikram strcmp(rootbuf, "/") != 0) { 6606eb2bd662Svikram bam_error(ALT_ROOT_INVALID, bam_root); 6607eb2bd662Svikram return (BAM_ERROR); 6608eb2bd662Svikram } 66097c478bd9Sstevel@tonic-gate 66108c1b6884Sszhou /* If no option, delete exiting reboot menu entry */ 66118c1b6884Sszhou if (opt == NULL) { 6612eb2bd662Svikram entry_t *ent; 6613eb2bd662Svikram BAM_DPRINTF((D_OPT_NULL, fcn)); 6614eb2bd662Svikram ent = find_boot_entry(mp, REBOOT_TITLE, NULL, NULL, 6615eb2bd662Svikram NULL, NULL, 0, &entry); 6616eb2bd662Svikram if (ent == NULL) { /* not found is ok */ 6617eb2bd662Svikram BAM_DPRINTF((D_TRANSIENT_NOTFOUND, fcn)); 66188c1b6884Sszhou return (BAM_SUCCESS); 6619eb2bd662Svikram } 66208c1b6884Sszhou (void) do_delete(mp, entry); 6621ae115bc7Smrj restore_default_entry(mp, BAM_OLDDEF, mp->olddefault); 6622ae115bc7Smrj mp->olddefault = NULL; 6623eb2bd662Svikram BAM_DPRINTF((D_RESTORED_DEFAULT, fcn)); 6624eb2bd662Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 66258c1b6884Sszhou return (BAM_WRITE); 66268c1b6884Sszhou } 66278c1b6884Sszhou 66288c1b6884Sszhou /* if entry= is specified, set the default entry */ 6629eb2bd662Svikram if (strncmp(opt, "entry=", strlen("entry=")) == 0) { 6630eb2bd662Svikram int entryNum = s_strtol(opt + strlen("entry=")); 6631eb2bd662Svikram BAM_DPRINTF((D_ENTRY_EQUALS, fcn, opt)); 6632eb2bd662Svikram if (selector(mp, opt, &entry, NULL) == BAM_SUCCESS) { 6633eb2bd662Svikram /* this is entry=# option */ 6634eb2bd662Svikram ret = set_global(mp, menu_cmds[DEFAULT_CMD], entry); 6635eb2bd662Svikram BAM_DPRINTF((D_ENTRY_SET_IS, fcn, entry, ret)); 6636eb2bd662Svikram return (ret); 6637eb2bd662Svikram } else { 6638eb2bd662Svikram bam_error(SET_DEFAULT_FAILED, entryNum); 6639eb2bd662Svikram return (BAM_ERROR); 6640eb2bd662Svikram } 6641eb2bd662Svikram } 6642eb2bd662Svikram 6643eb2bd662Svikram /* 6644eb2bd662Svikram * add a new menu entry based on opt and make it the default 6645eb2bd662Svikram */ 6646eb2bd662Svikram 6647eb2bd662Svikram fstype = get_fstype("/"); 6648eb2bd662Svikram INJECT_ERROR1("REBOOT_FSTYPE_NULL", fstype = NULL); 6649eb2bd662Svikram if (fstype == NULL) { 6650eb2bd662Svikram bam_error(REBOOT_FSTYPE_FAILED); 6651eb2bd662Svikram return (BAM_ERROR); 66527c478bd9Sstevel@tonic-gate } 66537c478bd9Sstevel@tonic-gate 6654eb2bd662Svikram osdev = get_special("/"); 6655eb2bd662Svikram INJECT_ERROR1("REBOOT_SPECIAL_NULL", osdev = NULL); 6656eb2bd662Svikram if (osdev == NULL) { 6657eb2bd662Svikram free(fstype); 6658eb2bd662Svikram bam_error(REBOOT_SPECIAL_FAILED); 6659eb2bd662Svikram return (BAM_ERROR); 6660eb2bd662Svikram } 6661eb2bd662Svikram 6662eb2bd662Svikram sign = find_existing_sign("/", osdev, fstype); 6663eb2bd662Svikram INJECT_ERROR1("REBOOT_SIGN_NULL", sign = NULL); 6664eb2bd662Svikram if (sign == NULL) { 6665eb2bd662Svikram free(fstype); 6666eb2bd662Svikram free(osdev); 6667eb2bd662Svikram bam_error(REBOOT_SIGN_FAILED); 6668eb2bd662Svikram return (BAM_ERROR); 6669eb2bd662Svikram } 6670eb2bd662Svikram 6671eb2bd662Svikram free(fstype); 6672eb2bd662Svikram free(osdev); 6673eb2bd662Svikram (void) strlcpy(signbuf, sign, sizeof (signbuf)); 6674eb2bd662Svikram free(sign); 6675eb2bd662Svikram 6676eb2bd662Svikram assert(strchr(signbuf, '(') == NULL && strchr(signbuf, ',') == NULL && 6677eb2bd662Svikram strchr(signbuf, ')') == NULL); 6678eb2bd662Svikram 66797c478bd9Sstevel@tonic-gate /* 6680eb2bd662Svikram * There is no alternate root while doing reboot with args 6681eb2bd662Svikram * This version of bootadm is only delivered with a DBOOT 6682eb2bd662Svikram * version of Solaris. 66837c478bd9Sstevel@tonic-gate */ 6684eb2bd662Svikram INJECT_ERROR1("REBOOT_NOT_DBOOT", bam_direct = BAM_DIRECT_MULTIBOOT); 6685eb2bd662Svikram if (bam_direct != BAM_DIRECT_DBOOT) { 6686eb2bd662Svikram bam_error(REBOOT_DIRECT_FAILED); 6687eb2bd662Svikram return (BAM_ERROR); 6688eb2bd662Svikram } 6689eb2bd662Svikram 6690eb2bd662Svikram /* add an entry for Solaris reboot */ 6691eb2bd662Svikram if (opt[0] == '-') { 6692eb2bd662Svikram /* It's an option - first see if boot-file is set */ 6693eb2bd662Svikram ret = get_kernel(mp, KERNEL_CMD, kernbuf, sizeof (kernbuf)); 6694eb2bd662Svikram INJECT_ERROR1("REBOOT_GET_KERNEL", ret = BAM_ERROR); 6695eb2bd662Svikram if (ret != BAM_SUCCESS) { 6696eb2bd662Svikram bam_error(REBOOT_GET_KERNEL_FAILED); 6697eb2bd662Svikram return (BAM_ERROR); 6698eb2bd662Svikram } 6699eb2bd662Svikram if (kernbuf[0] == '\0') 6700eb2bd662Svikram (void) strlcpy(kernbuf, DIRECT_BOOT_KERNEL, 6701eb2bd662Svikram sizeof (kernbuf)); 6702eb2bd662Svikram (void) strlcat(kernbuf, " ", sizeof (kernbuf)); 6703eb2bd662Svikram (void) strlcat(kernbuf, opt, sizeof (kernbuf)); 6704eb2bd662Svikram BAM_DPRINTF((D_REBOOT_OPTION, fcn, kernbuf)); 6705eb2bd662Svikram } else if (opt[0] == '/') { 6706eb2bd662Svikram /* It's a full path, so write it out. */ 6707eb2bd662Svikram (void) strlcpy(kernbuf, opt, sizeof (kernbuf)); 6708eb2bd662Svikram 6709b610f78eSvikram /* 6710eb2bd662Svikram * If someone runs: 6711eb2bd662Svikram * 6712eb2bd662Svikram * # eeprom boot-args='-kd' 6713eb2bd662Svikram * # reboot /platform/i86pc/kernel/unix 6714eb2bd662Svikram * 6715eb2bd662Svikram * we want to use the boot-args as part of the boot 6716eb2bd662Svikram * line. On the other hand, if someone runs: 6717eb2bd662Svikram * 6718eb2bd662Svikram * # reboot "/platform/i86pc/kernel/unix -kd" 6719eb2bd662Svikram * 6720eb2bd662Svikram * we don't need to mess with boot-args. If there's 6721eb2bd662Svikram * no space in the options string, assume we're in the 6722eb2bd662Svikram * first case. 6723b610f78eSvikram */ 6724eb2bd662Svikram if (strchr(opt, ' ') == NULL) { 6725eb2bd662Svikram ret = get_kernel(mp, ARGS_CMD, args_buf, 6726eb2bd662Svikram sizeof (args_buf)); 6727eb2bd662Svikram INJECT_ERROR1("REBOOT_GET_ARGS", ret = BAM_ERROR); 6728eb2bd662Svikram if (ret != BAM_SUCCESS) { 6729eb2bd662Svikram bam_error(REBOOT_GET_ARGS_FAILED); 6730eb2bd662Svikram return (BAM_ERROR); 6731eb2bd662Svikram } 6732eb2bd662Svikram 6733eb2bd662Svikram if (args_buf[0] != '\0') { 6734eb2bd662Svikram (void) strlcat(kernbuf, " ", sizeof (kernbuf)); 6735eb2bd662Svikram (void) strlcat(kernbuf, args_buf, 6736eb2bd662Svikram sizeof (kernbuf)); 6737eb2bd662Svikram } 6738b610f78eSvikram } 6739eb2bd662Svikram BAM_DPRINTF((D_REBOOT_ABSPATH, fcn, kernbuf)); 6740b610f78eSvikram } else { 6741b610f78eSvikram /* 6742eb2bd662Svikram * It may be a partial path, or it may be a partial 6743eb2bd662Svikram * path followed by options. Assume that only options 6744eb2bd662Svikram * follow a space. If someone sends us a kernel path 6745eb2bd662Svikram * that includes a space, they deserve to be broken. 6746b610f78eSvikram */ 6747eb2bd662Svikram opt_ptr = strchr(opt, ' '); 6748eb2bd662Svikram if (opt_ptr != NULL) { 6749eb2bd662Svikram *opt_ptr = '\0'; 6750eb2bd662Svikram } 67517c478bd9Sstevel@tonic-gate 6752eb2bd662Svikram path = expand_path(opt); 6753eb2bd662Svikram if (path != NULL) { 6754eb2bd662Svikram (void) strlcpy(kernbuf, path, sizeof (kernbuf)); 6755eb2bd662Svikram free(path); 6756455710d3Srscott 6757455710d3Srscott /* 6758eb2bd662Svikram * If there were options given, use those. 6759eb2bd662Svikram * Otherwise, copy over the default options. 6760455710d3Srscott */ 6761eb2bd662Svikram if (opt_ptr != NULL) { 6762eb2bd662Svikram /* Restore the space in opt string */ 6763eb2bd662Svikram *opt_ptr = ' '; 6764eb2bd662Svikram (void) strlcat(kernbuf, opt_ptr, 6765eb2bd662Svikram sizeof (kernbuf)); 6766eb2bd662Svikram } else { 6767eb2bd662Svikram ret = get_kernel(mp, ARGS_CMD, args_buf, 6768eb2bd662Svikram sizeof (args_buf)); 6769eb2bd662Svikram INJECT_ERROR1("UPDATE_TEMP_PARTIAL_ARGS", 6770eb2bd662Svikram ret = BAM_ERROR); 6771eb2bd662Svikram if (ret != BAM_SUCCESS) { 6772eb2bd662Svikram bam_error(REBOOT_GET_ARGS_FAILED); 6773455710d3Srscott return (BAM_ERROR); 6774eb2bd662Svikram } 6775455710d3Srscott 6776455710d3Srscott if (args_buf[0] != '\0') { 6777eb2bd662Svikram (void) strlcat(kernbuf, " ", 6778eb2bd662Svikram sizeof (kernbuf)); 6779eb2bd662Svikram (void) strlcat(kernbuf, 6780eb2bd662Svikram args_buf, sizeof (kernbuf)); 6781455710d3Srscott } 6782455710d3Srscott } 6783eb2bd662Svikram BAM_DPRINTF((D_REBOOT_RESOLVED_PARTIAL, fcn, kernbuf)); 6784ae115bc7Smrj } else { 6785eb2bd662Svikram bam_error(UNKNOWN_KERNEL, opt); 6786eb2bd662Svikram bam_print_stderr(UNKNOWN_KERNEL_REBOOT); 6787eb2bd662Svikram return (BAM_ERROR); 6788ae115bc7Smrj } 6789ae115bc7Smrj } 6790eb2bd662Svikram entry = add_boot_entry(mp, REBOOT_TITLE, signbuf, kernbuf, 6791eb2bd662Svikram NULL, NULL); 6792eb2bd662Svikram INJECT_ERROR1("REBOOT_ADD_BOOT_ENTRY", entry = BAM_ERROR); 67937c478bd9Sstevel@tonic-gate if (entry == BAM_ERROR) { 6794eb2bd662Svikram bam_error(REBOOT_WITH_ARGS_ADD_ENTRY_FAILED); 67957c478bd9Sstevel@tonic-gate return (BAM_ERROR); 67967c478bd9Sstevel@tonic-gate } 67978c1b6884Sszhou 6798ae115bc7Smrj save_default_entry(mp, BAM_OLDDEF); 6799eb2bd662Svikram ret = set_global(mp, menu_cmds[DEFAULT_CMD], entry); 6800eb2bd662Svikram INJECT_ERROR1("REBOOT_SET_GLOBAL", ret = BAM_ERROR); 6801eb2bd662Svikram if (ret == BAM_ERROR) { 6802eb2bd662Svikram bam_error(REBOOT_SET_DEFAULT_FAILED, entry); 6803eb2bd662Svikram } 6804eb2bd662Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 68057c478bd9Sstevel@tonic-gate return (BAM_WRITE); 68067c478bd9Sstevel@tonic-gate } 68077c478bd9Sstevel@tonic-gate 68087c478bd9Sstevel@tonic-gate static error_t 68097c478bd9Sstevel@tonic-gate set_global(menu_t *mp, char *globalcmd, int val) 68107c478bd9Sstevel@tonic-gate { 6811eb2bd662Svikram line_t *lp; 6812eb2bd662Svikram line_t *found; 6813eb2bd662Svikram line_t *last; 6814eb2bd662Svikram char *cp; 6815eb2bd662Svikram char *str; 6816eb2bd662Svikram char prefix[BAM_MAXLINE]; 6817eb2bd662Svikram size_t len; 6818eb2bd662Svikram const char *fcn = "set_global()"; 68197c478bd9Sstevel@tonic-gate 68207c478bd9Sstevel@tonic-gate assert(mp); 68217c478bd9Sstevel@tonic-gate assert(globalcmd); 68227c478bd9Sstevel@tonic-gate 6823b610f78eSvikram if (strcmp(globalcmd, menu_cmds[DEFAULT_CMD]) == 0) { 6824eb2bd662Svikram INJECT_ERROR1("SET_GLOBAL_VAL_NEG", val = -1); 6825eb2bd662Svikram INJECT_ERROR1("SET_GLOBAL_MENU_EMPTY", mp->end = NULL); 6826eb2bd662Svikram INJECT_ERROR1("SET_GLOBAL_VAL_TOO_BIG", val = 100); 6827b610f78eSvikram if (val < 0 || mp->end == NULL || val > mp->end->entryNum) { 6828b610f78eSvikram (void) snprintf(prefix, sizeof (prefix), "%d", val); 6829b610f78eSvikram bam_error(INVALID_ENTRY, prefix); 6830b610f78eSvikram return (BAM_ERROR); 6831b610f78eSvikram } 6832b610f78eSvikram } 6833b610f78eSvikram 68347c478bd9Sstevel@tonic-gate found = last = NULL; 68357c478bd9Sstevel@tonic-gate for (lp = mp->start; lp; lp = lp->next) { 68367c478bd9Sstevel@tonic-gate if (lp->flags != BAM_GLOBAL) 68377c478bd9Sstevel@tonic-gate continue; 68387c478bd9Sstevel@tonic-gate 68397c478bd9Sstevel@tonic-gate last = lp; /* track the last global found */ 68407c478bd9Sstevel@tonic-gate 6841eb2bd662Svikram INJECT_ERROR1("SET_GLOBAL_NULL_CMD", lp->cmd = NULL); 68427c478bd9Sstevel@tonic-gate if (lp->cmd == NULL) { 68437c478bd9Sstevel@tonic-gate bam_error(NO_CMD, lp->lineNum); 68447c478bd9Sstevel@tonic-gate continue; 68457c478bd9Sstevel@tonic-gate } 68467c478bd9Sstevel@tonic-gate if (strcmp(globalcmd, lp->cmd) != 0) 68477c478bd9Sstevel@tonic-gate continue; 68487c478bd9Sstevel@tonic-gate 6849eb2bd662Svikram BAM_DPRINTF((D_FOUND_GLOBAL, fcn, globalcmd)); 6850eb2bd662Svikram 68517c478bd9Sstevel@tonic-gate if (found) { 68527c478bd9Sstevel@tonic-gate bam_error(DUP_CMD, globalcmd, lp->lineNum, bam_root); 68537c478bd9Sstevel@tonic-gate } 68547c478bd9Sstevel@tonic-gate found = lp; 68557c478bd9Sstevel@tonic-gate } 68567c478bd9Sstevel@tonic-gate 68577c478bd9Sstevel@tonic-gate if (found == NULL) { 68587c478bd9Sstevel@tonic-gate lp = s_calloc(1, sizeof (line_t)); 68597c478bd9Sstevel@tonic-gate if (last == NULL) { 68607c478bd9Sstevel@tonic-gate lp->next = mp->start; 68617c478bd9Sstevel@tonic-gate mp->start = lp; 68627c478bd9Sstevel@tonic-gate mp->end = (mp->end) ? mp->end : lp; 68637c478bd9Sstevel@tonic-gate } else { 68647c478bd9Sstevel@tonic-gate lp->next = last->next; 68657c478bd9Sstevel@tonic-gate last->next = lp; 68667c478bd9Sstevel@tonic-gate if (lp->next == NULL) 68677c478bd9Sstevel@tonic-gate mp->end = lp; 68687c478bd9Sstevel@tonic-gate } 68697c478bd9Sstevel@tonic-gate lp->flags = BAM_GLOBAL; /* other fields not needed for writes */ 68707c478bd9Sstevel@tonic-gate len = strlen(globalcmd) + strlen(menu_cmds[SEP_CMD]); 68717c478bd9Sstevel@tonic-gate len += 10; /* val < 10 digits */ 68727c478bd9Sstevel@tonic-gate lp->line = s_calloc(1, len); 68737c478bd9Sstevel@tonic-gate (void) snprintf(lp->line, len, "%s%s%d", 68747c478bd9Sstevel@tonic-gate globalcmd, menu_cmds[SEP_CMD], val); 6875eb2bd662Svikram BAM_DPRINTF((D_SET_GLOBAL_WROTE_NEW, fcn, lp->line)); 6876eb2bd662Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 68777c478bd9Sstevel@tonic-gate return (BAM_WRITE); 68787c478bd9Sstevel@tonic-gate } 68797c478bd9Sstevel@tonic-gate 68807c478bd9Sstevel@tonic-gate /* 68817c478bd9Sstevel@tonic-gate * We are changing an existing entry. Retain any prefix whitespace, 68827c478bd9Sstevel@tonic-gate * but overwrite everything else. This preserves tabs added for 68837c478bd9Sstevel@tonic-gate * readability. 68847c478bd9Sstevel@tonic-gate */ 68857c478bd9Sstevel@tonic-gate str = found->line; 68867c478bd9Sstevel@tonic-gate cp = prefix; 68877c478bd9Sstevel@tonic-gate while (*str == ' ' || *str == '\t') 68887c478bd9Sstevel@tonic-gate *(cp++) = *(str++); 68897c478bd9Sstevel@tonic-gate *cp = '\0'; /* Terminate prefix */ 68907c478bd9Sstevel@tonic-gate len = strlen(prefix) + strlen(globalcmd); 68917c478bd9Sstevel@tonic-gate len += strlen(menu_cmds[SEP_CMD]) + 10; 68927c478bd9Sstevel@tonic-gate 68937c478bd9Sstevel@tonic-gate free(found->line); 68947c478bd9Sstevel@tonic-gate found->line = s_calloc(1, len); 68957c478bd9Sstevel@tonic-gate (void) snprintf(found->line, len, 6896455710d3Srscott "%s%s%s%d", prefix, globalcmd, menu_cmds[SEP_CMD], val); 68977c478bd9Sstevel@tonic-gate 6898eb2bd662Svikram BAM_DPRINTF((D_SET_GLOBAL_REPLACED, fcn, found->line)); 6899eb2bd662Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 69007c478bd9Sstevel@tonic-gate return (BAM_WRITE); /* need a write to menu */ 69017c478bd9Sstevel@tonic-gate } 69027c478bd9Sstevel@tonic-gate 6903ae115bc7Smrj /* 6904ae115bc7Smrj * partial_path may be anything like "kernel/unix" or "kmdb". Try to 6905455710d3Srscott * expand it to a full unix path. The calling function is expected to 6906455710d3Srscott * output a message if an error occurs and NULL is returned. 6907ae115bc7Smrj */ 6908ae115bc7Smrj static char * 6909ae115bc7Smrj expand_path(const char *partial_path) 6910ae115bc7Smrj { 6911eb2bd662Svikram int new_path_len; 6912eb2bd662Svikram char *new_path; 6913eb2bd662Svikram char new_path2[PATH_MAX]; 6914eb2bd662Svikram struct stat sb; 6915eb2bd662Svikram const char *fcn = "expand_path()"; 6916ae115bc7Smrj 6917ae115bc7Smrj new_path_len = strlen(partial_path) + 64; 6918ae115bc7Smrj new_path = s_calloc(1, new_path_len); 6919ae115bc7Smrj 6920ae115bc7Smrj /* First, try the simplest case - something like "kernel/unix" */ 6921ae115bc7Smrj (void) snprintf(new_path, new_path_len, "/platform/i86pc/%s", 6922ae115bc7Smrj partial_path); 6923ae115bc7Smrj if (stat(new_path, &sb) == 0) { 6924eb2bd662Svikram BAM_DPRINTF((D_EXPAND_PATH, fcn, new_path)); 6925ae115bc7Smrj return (new_path); 6926ae115bc7Smrj } 6927ae115bc7Smrj 6928ae115bc7Smrj if (strcmp(partial_path, "kmdb") == 0) { 6929ae115bc7Smrj (void) snprintf(new_path, new_path_len, "%s -k", 6930ae115bc7Smrj DIRECT_BOOT_KERNEL); 6931eb2bd662Svikram BAM_DPRINTF((D_EXPAND_PATH, fcn, new_path)); 6932ae115bc7Smrj return (new_path); 6933ae115bc7Smrj } 6934ae115bc7Smrj 6935ae115bc7Smrj /* 6936ae115bc7Smrj * We've quickly reached unsupported usage. Try once more to 6937ae115bc7Smrj * see if we were just given a glom name. 6938ae115bc7Smrj */ 6939ae115bc7Smrj (void) snprintf(new_path, new_path_len, "/platform/i86pc/%s/unix", 6940ae115bc7Smrj partial_path); 6941ae115bc7Smrj (void) snprintf(new_path2, PATH_MAX, "/platform/i86pc/%s/amd64/unix", 6942ae115bc7Smrj partial_path); 6943ae115bc7Smrj if (stat(new_path, &sb) == 0) { 6944ae115bc7Smrj if (stat(new_path2, &sb) == 0) { 6945ae115bc7Smrj /* 6946ae115bc7Smrj * We matched both, so we actually 6947ae115bc7Smrj * want to write the $ISADIR version. 6948ae115bc7Smrj */ 6949ae115bc7Smrj (void) snprintf(new_path, new_path_len, 6950ae115bc7Smrj "/platform/i86pc/kernel/%s/$ISADIR/unix", 6951ae115bc7Smrj partial_path); 6952ae115bc7Smrj } 6953eb2bd662Svikram BAM_DPRINTF((D_EXPAND_PATH, fcn, new_path)); 6954ae115bc7Smrj return (new_path); 6955ae115bc7Smrj } 6956ae115bc7Smrj 6957ae115bc7Smrj free(new_path); 6958eb2bd662Svikram BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 6959ae115bc7Smrj return (NULL); 6960ae115bc7Smrj } 6961ae115bc7Smrj 6962ae115bc7Smrj /* 6963ae115bc7Smrj * The kernel cmd and arg have been changed, so 6964ae115bc7Smrj * check whether the archive line needs to change. 6965ae115bc7Smrj */ 6966ae115bc7Smrj static void 6967ae115bc7Smrj set_archive_line(entry_t *entryp, line_t *kernelp) 6968ae115bc7Smrj { 6969eb2bd662Svikram line_t *lp = entryp->start; 6970eb2bd662Svikram char *new_archive; 6971eb2bd662Svikram menu_cmd_t m_cmd; 6972eb2bd662Svikram const char *fcn = "set_archive_line()"; 6973ae115bc7Smrj 6974ae115bc7Smrj for (; lp != NULL; lp = lp->next) { 6975ae115bc7Smrj if (strncmp(lp->cmd, menu_cmds[MODULE_CMD], 6976ae115bc7Smrj sizeof (menu_cmds[MODULE_CMD]) - 1) == 0) { 6977ae115bc7Smrj break; 6978ae115bc7Smrj } 6979eb2bd662Svikram 6980eb2bd662Svikram INJECT_ERROR1("SET_ARCHIVE_LINE_END_ENTRY", lp = entryp->end); 6981eb2bd662Svikram if (lp == entryp->end) { 6982eb2bd662Svikram BAM_DPRINTF((D_ARCHIVE_LINE_NONE, fcn, 6983eb2bd662Svikram entryp->entryNum)); 6984ae115bc7Smrj return; 6985eb2bd662Svikram } 6986ae115bc7Smrj } 6987eb2bd662Svikram INJECT_ERROR1("SET_ARCHIVE_LINE_END_MENU", lp = NULL); 6988eb2bd662Svikram if (lp == NULL) { 6989eb2bd662Svikram BAM_DPRINTF((D_ARCHIVE_LINE_NONE, fcn, entryp->entryNum)); 6990ae115bc7Smrj return; 6991eb2bd662Svikram } 6992ae115bc7Smrj 6993ae115bc7Smrj if (strstr(kernelp->arg, "$ISADIR") != NULL) { 6994ae115bc7Smrj new_archive = DIRECT_BOOT_ARCHIVE; 6995ae115bc7Smrj m_cmd = MODULE_DOLLAR_CMD; 6996ae115bc7Smrj } else if (strstr(kernelp->arg, "amd64") != NULL) { 6997ae115bc7Smrj new_archive = DIRECT_BOOT_ARCHIVE_64; 6998ae115bc7Smrj m_cmd = MODULE_CMD; 6999ae115bc7Smrj } else { 7000ae115bc7Smrj new_archive = DIRECT_BOOT_ARCHIVE_32; 7001ae115bc7Smrj m_cmd = MODULE_CMD; 7002ae115bc7Smrj } 7003ae115bc7Smrj 7004eb2bd662Svikram if (strcmp(lp->arg, new_archive) == 0) { 7005eb2bd662Svikram BAM_DPRINTF((D_ARCHIVE_LINE_NOCHANGE, fcn, lp->arg)); 7006ae115bc7Smrj return; 7007eb2bd662Svikram } 7008ae115bc7Smrj 7009ae115bc7Smrj if (strcmp(lp->cmd, menu_cmds[m_cmd]) != 0) { 7010ae115bc7Smrj free(lp->cmd); 7011ae115bc7Smrj lp->cmd = s_strdup(menu_cmds[m_cmd]); 7012ae115bc7Smrj } 7013ae115bc7Smrj 7014ae115bc7Smrj free(lp->arg); 7015ae115bc7Smrj lp->arg = s_strdup(new_archive); 7016ae115bc7Smrj update_line(lp); 7017eb2bd662Svikram BAM_DPRINTF((D_ARCHIVE_LINE_REPLACED, fcn, lp->line)); 7018ae115bc7Smrj } 7019ae115bc7Smrj 7020ae115bc7Smrj /* 7021ae115bc7Smrj * Title for an entry to set properties that once went in bootenv.rc. 7022ae115bc7Smrj */ 7023ae115bc7Smrj #define BOOTENV_RC_TITLE "Solaris bootenv rc" 7024ae115bc7Smrj 7025ae115bc7Smrj /* 7026ae115bc7Smrj * If path is NULL, return the kernel (optnum == KERNEL_CMD) or arguments 7027ae115bc7Smrj * (optnum == ARGS_CMD) in the argument buf. If path is a zero-length 7028ae115bc7Smrj * string, reset the value to the default. If path is a non-zero-length 7029ae115bc7Smrj * string, set the kernel or arguments. 7030ae115bc7Smrj */ 7031ae115bc7Smrj static error_t 7032eb2bd662Svikram get_set_kernel( 7033eb2bd662Svikram menu_t *mp, 7034eb2bd662Svikram menu_cmd_t optnum, 7035eb2bd662Svikram char *path, 7036eb2bd662Svikram char *buf, 7037eb2bd662Svikram size_t bufsize) 7038ae115bc7Smrj { 7039eb2bd662Svikram int entryNum; 7040eb2bd662Svikram int rv = BAM_SUCCESS; 7041eb2bd662Svikram int free_new_path = 0; 7042eb2bd662Svikram entry_t *entryp; 7043eb2bd662Svikram line_t *ptr; 7044eb2bd662Svikram line_t *kernelp; 7045eb2bd662Svikram char *new_arg; 7046eb2bd662Svikram char *old_args; 7047eb2bd662Svikram char *space; 7048eb2bd662Svikram char *new_path; 7049eb2bd662Svikram char old_space; 7050eb2bd662Svikram size_t old_kernel_len; 7051eb2bd662Svikram size_t new_str_len; 7052eb2bd662Svikram char *fstype; 7053eb2bd662Svikram char *osdev; 7054eb2bd662Svikram char *sign; 7055eb2bd662Svikram char signbuf[PATH_MAX]; 7056eb2bd662Svikram int ret; 7057eb2bd662Svikram const char *fcn = "get_set_kernel()"; 7058ae115bc7Smrj 7059ae115bc7Smrj assert(bufsize > 0); 7060ae115bc7Smrj 7061ae115bc7Smrj ptr = kernelp = NULL; 7062ae115bc7Smrj new_arg = old_args = space = NULL; 7063eb2bd662Svikram new_path = NULL; 7064ae115bc7Smrj buf[0] = '\0'; 7065ae115bc7Smrj 7066eb2bd662Svikram INJECT_ERROR1("GET_SET_KERNEL_NOT_DBOOT", 7067eb2bd662Svikram bam_direct = BAM_DIRECT_MULTIBOOT); 7068ae115bc7Smrj if (bam_direct != BAM_DIRECT_DBOOT) { 7069ae115bc7Smrj bam_error(NOT_DBOOT, optnum == KERNEL_CMD ? "kernel" : "args"); 7070ae115bc7Smrj return (BAM_ERROR); 7071ae115bc7Smrj } 7072ae115bc7Smrj 7073ae115bc7Smrj /* 7074ae115bc7Smrj * If a user changed the default entry to a non-bootadm controlled 7075ae115bc7Smrj * one, we don't want to mess with it. Just print an error and 7076ae115bc7Smrj * return. 7077ae115bc7Smrj */ 7078ae115bc7Smrj if (mp->curdefault) { 7079ae115bc7Smrj entryNum = s_strtol(mp->curdefault->arg); 7080ae115bc7Smrj for (entryp = mp->entries; entryp; entryp = entryp->next) { 7081ae115bc7Smrj if (entryp->entryNum == entryNum) 7082ae115bc7Smrj break; 7083ae115bc7Smrj } 7084ae115bc7Smrj if ((entryp != NULL) && 7085ae115bc7Smrj ((entryp->flags & (BAM_ENTRY_BOOTADM|BAM_ENTRY_LU)) == 0)) { 7086ae115bc7Smrj bam_error(DEFAULT_NOT_BAM); 7087ae115bc7Smrj return (BAM_ERROR); 7088ae115bc7Smrj } 7089ae115bc7Smrj } 7090ae115bc7Smrj 7091eb2bd662Svikram entryp = find_boot_entry(mp, BOOTENV_RC_TITLE, NULL, NULL, NULL, NULL, 7092eb2bd662Svikram 0, &entryNum); 7093ae115bc7Smrj 7094ae115bc7Smrj if (entryp != NULL) { 7095ae115bc7Smrj for (ptr = entryp->start; ptr && ptr != entryp->end; 7096ae115bc7Smrj ptr = ptr->next) { 7097ae115bc7Smrj if (strncmp(ptr->cmd, menu_cmds[KERNEL_CMD], 7098ae115bc7Smrj sizeof (menu_cmds[KERNEL_CMD]) - 1) == 0) { 7099ae115bc7Smrj kernelp = ptr; 7100ae115bc7Smrj break; 7101ae115bc7Smrj } 7102ae115bc7Smrj } 7103ae115bc7Smrj if (kernelp == NULL) { 7104ae115bc7Smrj bam_error(NO_KERNEL, entryNum); 7105ae115bc7Smrj return (BAM_ERROR); 7106ae115bc7Smrj } 7107ae115bc7Smrj 7108ae115bc7Smrj old_kernel_len = strcspn(kernelp->arg, " \t"); 7109ae115bc7Smrj space = old_args = kernelp->arg + old_kernel_len; 7110ae115bc7Smrj while ((*old_args == ' ') || (*old_args == '\t')) 7111ae115bc7Smrj old_args++; 7112ae115bc7Smrj } 7113ae115bc7Smrj 7114ae115bc7Smrj if (path == NULL) { 7115eb2bd662Svikram if (entryp == NULL) { 7116eb2bd662Svikram BAM_DPRINTF((D_GET_SET_KERNEL_NO_RC, fcn)); 7117eb2bd662Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 7118ae115bc7Smrj return (BAM_SUCCESS); 7119eb2bd662Svikram } 7120eb2bd662Svikram assert(kernelp); 7121ae115bc7Smrj if (optnum == ARGS_CMD) { 7122eb2bd662Svikram if (old_args[0] != '\0') { 7123ae115bc7Smrj (void) strlcpy(buf, old_args, bufsize); 7124eb2bd662Svikram BAM_DPRINTF((D_GET_SET_KERNEL_ARGS, fcn, buf)); 7125eb2bd662Svikram } 7126ae115bc7Smrj } else { 7127ae115bc7Smrj /* 7128ae115bc7Smrj * We need to print the kernel, so we just turn the 7129ae115bc7Smrj * first space into a '\0' and print the beginning. 7130ae115bc7Smrj * We don't print anything if it's the default kernel. 7131ae115bc7Smrj */ 7132ae115bc7Smrj old_space = *space; 7133ae115bc7Smrj *space = '\0'; 7134eb2bd662Svikram if (strcmp(kernelp->arg, DIRECT_BOOT_KERNEL) != 0) { 7135ae115bc7Smrj (void) strlcpy(buf, kernelp->arg, bufsize); 7136eb2bd662Svikram BAM_DPRINTF((D_GET_SET_KERNEL_KERN, fcn, buf)); 7137eb2bd662Svikram } 7138ae115bc7Smrj *space = old_space; 7139ae115bc7Smrj } 7140eb2bd662Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 7141ae115bc7Smrj return (BAM_SUCCESS); 7142ae115bc7Smrj } 7143ae115bc7Smrj 7144ae115bc7Smrj /* 7145ae115bc7Smrj * First, check if we're resetting an entry to the default. 7146ae115bc7Smrj */ 7147ae115bc7Smrj if ((path[0] == '\0') || 7148ae115bc7Smrj ((optnum == KERNEL_CMD) && 7149ae115bc7Smrj (strcmp(path, DIRECT_BOOT_KERNEL) == 0))) { 7150ae115bc7Smrj if ((entryp == NULL) || (kernelp == NULL)) { 7151ae115bc7Smrj /* No previous entry, it's already the default */ 7152eb2bd662Svikram BAM_DPRINTF((D_GET_SET_KERNEL_ALREADY, fcn)); 7153ae115bc7Smrj return (BAM_SUCCESS); 7154ae115bc7Smrj } 7155ae115bc7Smrj 7156ae115bc7Smrj /* 7157ae115bc7Smrj * Check if we can delete the entry. If we're resetting the 7158ae115bc7Smrj * kernel command, and the args is already empty, or if we're 7159ae115bc7Smrj * resetting the args command, and the kernel is already the 7160ae115bc7Smrj * default, we can restore the old default and delete the entry. 7161ae115bc7Smrj */ 7162ae115bc7Smrj if (((optnum == KERNEL_CMD) && 7163ae115bc7Smrj ((old_args == NULL) || (old_args[0] == '\0'))) || 7164ae115bc7Smrj ((optnum == ARGS_CMD) && 7165ae115bc7Smrj (strncmp(kernelp->arg, DIRECT_BOOT_KERNEL, 7166ae115bc7Smrj sizeof (DIRECT_BOOT_KERNEL) - 1) == 0))) { 7167ae115bc7Smrj kernelp = NULL; 7168ae115bc7Smrj (void) do_delete(mp, entryNum); 7169ae115bc7Smrj restore_default_entry(mp, BAM_OLD_RC_DEF, 7170ae115bc7Smrj mp->old_rc_default); 7171ae115bc7Smrj mp->old_rc_default = NULL; 7172ae115bc7Smrj rv = BAM_WRITE; 7173eb2bd662Svikram BAM_DPRINTF((D_GET_SET_KERNEL_RESTORE_DEFAULT, fcn)); 7174ae115bc7Smrj goto done; 7175ae115bc7Smrj } 7176ae115bc7Smrj 7177ae115bc7Smrj if (optnum == KERNEL_CMD) { 7178ae115bc7Smrj /* 7179ae115bc7Smrj * At this point, we've already checked that old_args 7180ae115bc7Smrj * and entryp are valid pointers. The "+ 2" is for 7181ae115bc7Smrj * a space a the string termination character. 7182ae115bc7Smrj */ 7183ae115bc7Smrj new_str_len = (sizeof (DIRECT_BOOT_KERNEL) - 1) + 7184ae115bc7Smrj strlen(old_args) + 2; 7185ae115bc7Smrj new_arg = s_calloc(1, new_str_len); 7186ae115bc7Smrj (void) snprintf(new_arg, new_str_len, "%s %s", 7187ae115bc7Smrj DIRECT_BOOT_KERNEL, old_args); 7188ae115bc7Smrj free(kernelp->arg); 7189ae115bc7Smrj kernelp->arg = new_arg; 7190ae115bc7Smrj 7191ae115bc7Smrj /* 7192ae115bc7Smrj * We have changed the kernel line, so we may need 7193ae115bc7Smrj * to update the archive line as well. 7194ae115bc7Smrj */ 7195ae115bc7Smrj set_archive_line(entryp, kernelp); 7196eb2bd662Svikram BAM_DPRINTF((D_GET_SET_KERNEL_RESET_KERNEL_SET_ARG, 7197eb2bd662Svikram fcn, kernelp->arg)); 7198ae115bc7Smrj } else { 7199ae115bc7Smrj /* 7200ae115bc7Smrj * We're resetting the boot args to nothing, so 7201ae115bc7Smrj * we only need to copy the kernel. We've already 7202ae115bc7Smrj * checked that the kernel is not the default. 7203ae115bc7Smrj */ 7204ae115bc7Smrj new_arg = s_calloc(1, old_kernel_len + 1); 7205ae115bc7Smrj (void) snprintf(new_arg, old_kernel_len + 1, "%s", 7206ae115bc7Smrj kernelp->arg); 7207ae115bc7Smrj free(kernelp->arg); 7208ae115bc7Smrj kernelp->arg = new_arg; 7209eb2bd662Svikram BAM_DPRINTF((D_GET_SET_KERNEL_RESET_ARG_SET_KERNEL, 7210eb2bd662Svikram fcn, kernelp->arg)); 7211ae115bc7Smrj } 7212ae115bc7Smrj rv = BAM_WRITE; 7213ae115bc7Smrj goto done; 7214ae115bc7Smrj } 7215ae115bc7Smrj 7216ae115bc7Smrj /* 7217ae115bc7Smrj * Expand the kernel file to a full path, if necessary 7218ae115bc7Smrj */ 7219ae115bc7Smrj if ((optnum == KERNEL_CMD) && (path[0] != '/')) { 7220ae115bc7Smrj new_path = expand_path(path); 7221ae115bc7Smrj if (new_path == NULL) { 7222455710d3Srscott bam_error(UNKNOWN_KERNEL, path); 7223eb2bd662Svikram BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 7224ae115bc7Smrj return (BAM_ERROR); 7225ae115bc7Smrj } 7226ae115bc7Smrj free_new_path = 1; 7227ae115bc7Smrj } else { 7228ae115bc7Smrj new_path = path; 7229ae115bc7Smrj free_new_path = 0; 7230ae115bc7Smrj } 7231ae115bc7Smrj 7232ae115bc7Smrj /* 7233ae115bc7Smrj * At this point, we know we're setting a new value. First, take care 7234ae115bc7Smrj * of the case where there was no previous entry. 7235ae115bc7Smrj */ 7236ae115bc7Smrj if (entryp == NULL) { 7237eb2bd662Svikram 7238ae115bc7Smrj /* Similar to code in update_temp */ 7239eb2bd662Svikram fstype = get_fstype("/"); 7240eb2bd662Svikram INJECT_ERROR1("GET_SET_KERNEL_FSTYPE", fstype = NULL); 7241eb2bd662Svikram if (fstype == NULL) { 7242eb2bd662Svikram bam_error(BOOTENV_FSTYPE_FAILED); 7243eb2bd662Svikram rv = BAM_ERROR; 7244eb2bd662Svikram goto done; 7245eb2bd662Svikram } 7246eb2bd662Svikram 7247eb2bd662Svikram osdev = get_special("/"); 7248eb2bd662Svikram INJECT_ERROR1("GET_SET_KERNEL_SPECIAL", osdev = NULL); 7249eb2bd662Svikram if (osdev == NULL) { 7250eb2bd662Svikram free(fstype); 7251eb2bd662Svikram bam_error(BOOTENV_SPECIAL_FAILED); 7252eb2bd662Svikram rv = BAM_ERROR; 7253eb2bd662Svikram goto done; 7254ae115bc7Smrj } 7255eb2bd662Svikram 7256eb2bd662Svikram sign = find_existing_sign("/", osdev, fstype); 7257eb2bd662Svikram INJECT_ERROR1("GET_SET_KERNEL_SIGN", sign = NULL); 7258eb2bd662Svikram if (sign == NULL) { 7259eb2bd662Svikram free(fstype); 7260eb2bd662Svikram free(osdev); 7261eb2bd662Svikram bam_error(BOOTENV_SIGN_FAILED); 7262ae115bc7Smrj rv = BAM_ERROR; 7263ae115bc7Smrj goto done; 7264ae115bc7Smrj } 7265eb2bd662Svikram 7266eb2bd662Svikram free(fstype); 7267eb2bd662Svikram free(osdev); 7268eb2bd662Svikram (void) strlcpy(signbuf, sign, sizeof (signbuf)); 7269eb2bd662Svikram free(sign); 7270eb2bd662Svikram assert(strchr(signbuf, '(') == NULL && 7271eb2bd662Svikram strchr(signbuf, ',') == NULL && 7272eb2bd662Svikram strchr(signbuf, ')') == NULL); 7273eb2bd662Svikram 7274ae115bc7Smrj if (optnum == KERNEL_CMD) { 7275eb2bd662Svikram BAM_DPRINTF((D_GET_SET_KERNEL_NEW_KERN, fcn, new_path)); 7276ae115bc7Smrj entryNum = add_boot_entry(mp, BOOTENV_RC_TITLE, 7277eb2bd662Svikram signbuf, new_path, NULL, NULL); 7278ae115bc7Smrj } else { 7279ae115bc7Smrj new_str_len = strlen(DIRECT_BOOT_KERNEL) + 7280ae115bc7Smrj strlen(path) + 8; 7281ae115bc7Smrj new_arg = s_calloc(1, new_str_len); 7282ae115bc7Smrj 7283ae115bc7Smrj (void) snprintf(new_arg, new_str_len, "%s %s", 7284ae115bc7Smrj DIRECT_BOOT_KERNEL, path); 7285eb2bd662Svikram BAM_DPRINTF((D_GET_SET_KERNEL_NEW_ARG, fcn, new_arg)); 7286ae115bc7Smrj entryNum = add_boot_entry(mp, BOOTENV_RC_TITLE, 7287eb2bd662Svikram signbuf, new_arg, NULL, DIRECT_BOOT_ARCHIVE); 7288eb2bd662Svikram free(new_arg); 7289eb2bd662Svikram } 7290eb2bd662Svikram INJECT_ERROR1("GET_SET_KERNEL_ADD_BOOT_ENTRY", 7291eb2bd662Svikram entryNum = BAM_ERROR); 7292eb2bd662Svikram if (entryNum == BAM_ERROR) { 7293eb2bd662Svikram bam_error(GET_SET_KERNEL_ADD_BOOT_ENTRY, 7294eb2bd662Svikram BOOTENV_RC_TITLE); 7295eb2bd662Svikram rv = BAM_ERROR; 7296eb2bd662Svikram goto done; 7297ae115bc7Smrj } 7298ae115bc7Smrj save_default_entry(mp, BAM_OLD_RC_DEF); 7299eb2bd662Svikram ret = set_global(mp, menu_cmds[DEFAULT_CMD], entryNum); 7300eb2bd662Svikram INJECT_ERROR1("GET_SET_KERNEL_SET_GLOBAL", ret = BAM_ERROR); 7301eb2bd662Svikram if (ret == BAM_ERROR) { 7302eb2bd662Svikram bam_error(GET_SET_KERNEL_SET_GLOBAL, entryNum); 7303eb2bd662Svikram } 7304ae115bc7Smrj rv = BAM_WRITE; 7305ae115bc7Smrj goto done; 7306ae115bc7Smrj } 7307ae115bc7Smrj 7308ae115bc7Smrj /* 7309ae115bc7Smrj * There was already an bootenv entry which we need to edit. 7310ae115bc7Smrj */ 7311ae115bc7Smrj if (optnum == KERNEL_CMD) { 7312ae115bc7Smrj new_str_len = strlen(new_path) + strlen(old_args) + 2; 7313ae115bc7Smrj new_arg = s_calloc(1, new_str_len); 7314ae115bc7Smrj (void) snprintf(new_arg, new_str_len, "%s %s", new_path, 7315ae115bc7Smrj old_args); 7316ae115bc7Smrj free(kernelp->arg); 7317ae115bc7Smrj kernelp->arg = new_arg; 7318ae115bc7Smrj 7319ae115bc7Smrj /* 7320ae115bc7Smrj * If we have changed the kernel line, we may need to update 7321ae115bc7Smrj * the archive line as well. 7322ae115bc7Smrj */ 7323ae115bc7Smrj set_archive_line(entryp, kernelp); 7324eb2bd662Svikram BAM_DPRINTF((D_GET_SET_KERNEL_REPLACED_KERNEL_SAME_ARG, fcn, 7325eb2bd662Svikram kernelp->arg)); 7326ae115bc7Smrj } else { 7327ae115bc7Smrj new_str_len = old_kernel_len + strlen(path) + 8; 7328ae115bc7Smrj new_arg = s_calloc(1, new_str_len); 7329ae115bc7Smrj (void) strncpy(new_arg, kernelp->arg, old_kernel_len); 7330ae115bc7Smrj (void) strlcat(new_arg, " ", new_str_len); 7331ae115bc7Smrj (void) strlcat(new_arg, path, new_str_len); 7332ae115bc7Smrj free(kernelp->arg); 7333ae115bc7Smrj kernelp->arg = new_arg; 7334eb2bd662Svikram BAM_DPRINTF((D_GET_SET_KERNEL_SAME_KERNEL_REPLACED_ARG, fcn, 7335eb2bd662Svikram kernelp->arg)); 7336ae115bc7Smrj } 7337ae115bc7Smrj rv = BAM_WRITE; 7338ae115bc7Smrj 7339ae115bc7Smrj done: 7340ae115bc7Smrj if ((rv == BAM_WRITE) && kernelp) 7341ae115bc7Smrj update_line(kernelp); 7342ae115bc7Smrj if (free_new_path) 7343ae115bc7Smrj free(new_path); 7344eb2bd662Svikram if (rv == BAM_WRITE) { 7345eb2bd662Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 7346eb2bd662Svikram } else { 7347eb2bd662Svikram BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 7348eb2bd662Svikram } 7349ae115bc7Smrj return (rv); 7350ae115bc7Smrj } 7351ae115bc7Smrj 7352eb2bd662Svikram static error_t 7353eb2bd662Svikram get_kernel(menu_t *mp, menu_cmd_t optnum, char *buf, size_t bufsize) 7354eb2bd662Svikram { 7355eb2bd662Svikram const char *fcn = "get_kernel()"; 7356eb2bd662Svikram BAM_DPRINTF((D_FUNC_ENTRY1, fcn, menu_cmds[optnum])); 7357eb2bd662Svikram return (get_set_kernel(mp, optnum, NULL, buf, bufsize)); 7358eb2bd662Svikram } 7359eb2bd662Svikram 7360eb2bd662Svikram static error_t 7361eb2bd662Svikram set_kernel(menu_t *mp, menu_cmd_t optnum, char *path, char *buf, size_t bufsize) 7362eb2bd662Svikram { 7363eb2bd662Svikram const char *fcn = "set_kernel()"; 7364eb2bd662Svikram assert(path != NULL); 7365eb2bd662Svikram BAM_DPRINTF((D_FUNC_ENTRY2, fcn, menu_cmds[optnum], path)); 7366eb2bd662Svikram return (get_set_kernel(mp, optnum, path, buf, bufsize)); 7367eb2bd662Svikram } 7368eb2bd662Svikram 73697c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 73707c478bd9Sstevel@tonic-gate static error_t 7371eb2bd662Svikram set_option(menu_t *mp, char *dummy, char *opt) 73727c478bd9Sstevel@tonic-gate { 7373eb2bd662Svikram int optnum; 7374eb2bd662Svikram int optval; 7375eb2bd662Svikram char *val; 7376eb2bd662Svikram char buf[BUFSIZ] = ""; 7377eb2bd662Svikram error_t rv; 7378eb2bd662Svikram const char *fcn = "set_option()"; 73797c478bd9Sstevel@tonic-gate 73807c478bd9Sstevel@tonic-gate assert(mp); 73817c478bd9Sstevel@tonic-gate assert(opt); 7382eb2bd662Svikram assert(dummy == NULL); 7383eb2bd662Svikram 7384eb2bd662Svikram /* opt is set from bam_argv[0] and is always non-NULL */ 7385eb2bd662Svikram BAM_DPRINTF((D_FUNC_ENTRY1, fcn, opt)); 73867c478bd9Sstevel@tonic-gate 73877c478bd9Sstevel@tonic-gate val = strchr(opt, '='); 7388ae115bc7Smrj if (val != NULL) { 7389ae115bc7Smrj *val = '\0'; 73907c478bd9Sstevel@tonic-gate } 73917c478bd9Sstevel@tonic-gate 73927c478bd9Sstevel@tonic-gate if (strcmp(opt, "default") == 0) { 73937c478bd9Sstevel@tonic-gate optnum = DEFAULT_CMD; 73947c478bd9Sstevel@tonic-gate } else if (strcmp(opt, "timeout") == 0) { 73957c478bd9Sstevel@tonic-gate optnum = TIMEOUT_CMD; 7396ae115bc7Smrj } else if (strcmp(opt, menu_cmds[KERNEL_CMD]) == 0) { 7397ae115bc7Smrj optnum = KERNEL_CMD; 7398ae115bc7Smrj } else if (strcmp(opt, menu_cmds[ARGS_CMD]) == 0) { 7399ae115bc7Smrj optnum = ARGS_CMD; 74007c478bd9Sstevel@tonic-gate } else { 7401eb2bd662Svikram bam_error(INVALID_OPTION, opt); 74027c478bd9Sstevel@tonic-gate return (BAM_ERROR); 74037c478bd9Sstevel@tonic-gate } 74047c478bd9Sstevel@tonic-gate 7405ae115bc7Smrj /* 7406ae115bc7Smrj * kernel and args are allowed without "=new_value" strings. All 7407ae115bc7Smrj * others cause errors 7408ae115bc7Smrj */ 7409ae115bc7Smrj if ((val == NULL) && (optnum != KERNEL_CMD) && (optnum != ARGS_CMD)) { 7410eb2bd662Svikram bam_error(NO_OPTION_ARG, opt); 7411ae115bc7Smrj return (BAM_ERROR); 7412ae115bc7Smrj } else if (val != NULL) { 7413ae115bc7Smrj *val = '='; 7414ae115bc7Smrj } 7415ae115bc7Smrj 7416ae115bc7Smrj if ((optnum == KERNEL_CMD) || (optnum == ARGS_CMD)) { 7417eb2bd662Svikram BAM_DPRINTF((D_SET_OPTION, fcn, menu_cmds[optnum], 7418eb2bd662Svikram val ? val + 1 : "NULL")); 7419eb2bd662Svikram 7420eb2bd662Svikram if (val) 7421eb2bd662Svikram rv = set_kernel(mp, optnum, val + 1, buf, sizeof (buf)); 7422eb2bd662Svikram else 7423eb2bd662Svikram rv = get_kernel(mp, optnum, buf, sizeof (buf)); 7424ae115bc7Smrj if ((rv == BAM_SUCCESS) && (buf[0] != '\0')) 7425ae115bc7Smrj (void) printf("%s\n", buf); 7426ae115bc7Smrj } else { 7427ae115bc7Smrj optval = s_strtol(val + 1); 7428eb2bd662Svikram BAM_DPRINTF((D_SET_OPTION, fcn, menu_cmds[optnum], val + 1)); 7429eb2bd662Svikram rv = set_global(mp, menu_cmds[optnum], optval); 7430eb2bd662Svikram } 7431eb2bd662Svikram 7432eb2bd662Svikram if (rv == BAM_WRITE || rv == BAM_SUCCESS) { 7433eb2bd662Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 7434eb2bd662Svikram } else { 7435eb2bd662Svikram BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 7436ae115bc7Smrj } 7437eb2bd662Svikram 7438eb2bd662Svikram return (rv); 74397c478bd9Sstevel@tonic-gate } 74407c478bd9Sstevel@tonic-gate 74417c478bd9Sstevel@tonic-gate /* 74427c478bd9Sstevel@tonic-gate * The quiet argument suppresses messages. This is used 74437c478bd9Sstevel@tonic-gate * when invoked in the context of other commands (e.g. list_entry) 74447c478bd9Sstevel@tonic-gate */ 74457c478bd9Sstevel@tonic-gate static error_t 74467c478bd9Sstevel@tonic-gate read_globals(menu_t *mp, char *menu_path, char *globalcmd, int quiet) 74477c478bd9Sstevel@tonic-gate { 74487c478bd9Sstevel@tonic-gate line_t *lp; 74497c478bd9Sstevel@tonic-gate char *arg; 74507c478bd9Sstevel@tonic-gate int done, ret = BAM_SUCCESS; 74517c478bd9Sstevel@tonic-gate 74527c478bd9Sstevel@tonic-gate assert(mp); 74537c478bd9Sstevel@tonic-gate assert(menu_path); 74547c478bd9Sstevel@tonic-gate assert(globalcmd); 74557c478bd9Sstevel@tonic-gate 74567c478bd9Sstevel@tonic-gate if (mp->start == NULL) { 74577c478bd9Sstevel@tonic-gate if (!quiet) 74587c478bd9Sstevel@tonic-gate bam_error(NO_MENU, menu_path); 74597c478bd9Sstevel@tonic-gate return (BAM_ERROR); 74607c478bd9Sstevel@tonic-gate } 74617c478bd9Sstevel@tonic-gate 74627c478bd9Sstevel@tonic-gate done = 0; 74637c478bd9Sstevel@tonic-gate for (lp = mp->start; lp; lp = lp->next) { 74647c478bd9Sstevel@tonic-gate if (lp->flags != BAM_GLOBAL) 74657c478bd9Sstevel@tonic-gate continue; 74667c478bd9Sstevel@tonic-gate 74677c478bd9Sstevel@tonic-gate if (lp->cmd == NULL) { 74687c478bd9Sstevel@tonic-gate if (!quiet) 74697c478bd9Sstevel@tonic-gate bam_error(NO_CMD, lp->lineNum); 74707c478bd9Sstevel@tonic-gate continue; 74717c478bd9Sstevel@tonic-gate } 74727c478bd9Sstevel@tonic-gate 74737c478bd9Sstevel@tonic-gate if (strcmp(globalcmd, lp->cmd) != 0) 74747c478bd9Sstevel@tonic-gate continue; 74757c478bd9Sstevel@tonic-gate 74767c478bd9Sstevel@tonic-gate /* Found global. Check for duplicates */ 74777c478bd9Sstevel@tonic-gate if (done && !quiet) { 74787c478bd9Sstevel@tonic-gate bam_error(DUP_CMD, globalcmd, lp->lineNum, bam_root); 74797c478bd9Sstevel@tonic-gate ret = BAM_ERROR; 74807c478bd9Sstevel@tonic-gate } 74817c478bd9Sstevel@tonic-gate 74827c478bd9Sstevel@tonic-gate arg = lp->arg ? lp->arg : ""; 74837c478bd9Sstevel@tonic-gate bam_print(GLOBAL_CMD, globalcmd, arg); 74847c478bd9Sstevel@tonic-gate done = 1; 74857c478bd9Sstevel@tonic-gate } 74867c478bd9Sstevel@tonic-gate 74877c478bd9Sstevel@tonic-gate if (!done && bam_verbose) 74887c478bd9Sstevel@tonic-gate bam_print(NO_ENTRY, globalcmd); 74897c478bd9Sstevel@tonic-gate 74907c478bd9Sstevel@tonic-gate return (ret); 74917c478bd9Sstevel@tonic-gate } 74927c478bd9Sstevel@tonic-gate 74937c478bd9Sstevel@tonic-gate static error_t 74947c478bd9Sstevel@tonic-gate menu_write(char *root, menu_t *mp) 74957c478bd9Sstevel@tonic-gate { 7496eb2bd662Svikram const char *fcn = "menu_write()"; 7497eb2bd662Svikram 7498eb2bd662Svikram BAM_DPRINTF((D_MENU_WRITE_ENTER, fcn, root)); 74997c478bd9Sstevel@tonic-gate return (list2file(root, MENU_TMP, GRUB_MENU, mp->start)); 75007c478bd9Sstevel@tonic-gate } 75017c478bd9Sstevel@tonic-gate 7502eb2bd662Svikram void 75037c478bd9Sstevel@tonic-gate line_free(line_t *lp) 75047c478bd9Sstevel@tonic-gate { 75057c478bd9Sstevel@tonic-gate if (lp == NULL) 75067c478bd9Sstevel@tonic-gate return; 75077c478bd9Sstevel@tonic-gate 75087c478bd9Sstevel@tonic-gate if (lp->cmd) 75097c478bd9Sstevel@tonic-gate free(lp->cmd); 75107c478bd9Sstevel@tonic-gate if (lp->sep) 75117c478bd9Sstevel@tonic-gate free(lp->sep); 75127c478bd9Sstevel@tonic-gate if (lp->arg) 75137c478bd9Sstevel@tonic-gate free(lp->arg); 75147c478bd9Sstevel@tonic-gate if (lp->line) 75157c478bd9Sstevel@tonic-gate free(lp->line); 75167c478bd9Sstevel@tonic-gate free(lp); 75177c478bd9Sstevel@tonic-gate } 75187c478bd9Sstevel@tonic-gate 75197c478bd9Sstevel@tonic-gate static void 75207c478bd9Sstevel@tonic-gate linelist_free(line_t *start) 75217c478bd9Sstevel@tonic-gate { 75227c478bd9Sstevel@tonic-gate line_t *lp; 75237c478bd9Sstevel@tonic-gate 75247c478bd9Sstevel@tonic-gate while (start) { 75257c478bd9Sstevel@tonic-gate lp = start; 75267c478bd9Sstevel@tonic-gate start = start->next; 75277c478bd9Sstevel@tonic-gate line_free(lp); 75287c478bd9Sstevel@tonic-gate } 75297c478bd9Sstevel@tonic-gate } 75307c478bd9Sstevel@tonic-gate 75317c478bd9Sstevel@tonic-gate static void 75327c478bd9Sstevel@tonic-gate filelist_free(filelist_t *flistp) 75337c478bd9Sstevel@tonic-gate { 75347c478bd9Sstevel@tonic-gate linelist_free(flistp->head); 75357c478bd9Sstevel@tonic-gate flistp->head = NULL; 75367c478bd9Sstevel@tonic-gate flistp->tail = NULL; 75377c478bd9Sstevel@tonic-gate } 75387c478bd9Sstevel@tonic-gate 75397c478bd9Sstevel@tonic-gate static void 75407c478bd9Sstevel@tonic-gate menu_free(menu_t *mp) 75417c478bd9Sstevel@tonic-gate { 75428c1b6884Sszhou entry_t *ent, *tmp; 75437c478bd9Sstevel@tonic-gate assert(mp); 75447c478bd9Sstevel@tonic-gate 75457c478bd9Sstevel@tonic-gate if (mp->start) 75467c478bd9Sstevel@tonic-gate linelist_free(mp->start); 75478c1b6884Sszhou ent = mp->entries; 75488c1b6884Sszhou while (ent) { 75498c1b6884Sszhou tmp = ent; 75508c1b6884Sszhou ent = tmp->next; 75518c1b6884Sszhou free(tmp); 75528c1b6884Sszhou } 75537c478bd9Sstevel@tonic-gate 75548c1b6884Sszhou free(mp); 75557c478bd9Sstevel@tonic-gate } 75567c478bd9Sstevel@tonic-gate 75577c478bd9Sstevel@tonic-gate /* 75587c478bd9Sstevel@tonic-gate * Utility routines 75597c478bd9Sstevel@tonic-gate */ 75607c478bd9Sstevel@tonic-gate 75617c478bd9Sstevel@tonic-gate 75627c478bd9Sstevel@tonic-gate /* 75637c478bd9Sstevel@tonic-gate * Returns 0 on success 75647c478bd9Sstevel@tonic-gate * Any other value indicates an error 75657c478bd9Sstevel@tonic-gate */ 75667c478bd9Sstevel@tonic-gate static int 7567986fd29aSsetje exec_cmd(char *cmdline, filelist_t *flistp) 75687c478bd9Sstevel@tonic-gate { 75697c478bd9Sstevel@tonic-gate char buf[BUFSIZ]; 75707c478bd9Sstevel@tonic-gate int ret; 75717c478bd9Sstevel@tonic-gate FILE *ptr; 75727c478bd9Sstevel@tonic-gate sigset_t set; 75737c478bd9Sstevel@tonic-gate void (*disp)(int); 75747c478bd9Sstevel@tonic-gate 75757c478bd9Sstevel@tonic-gate /* 75767c478bd9Sstevel@tonic-gate * For security 75777c478bd9Sstevel@tonic-gate * - only absolute paths are allowed 75787c478bd9Sstevel@tonic-gate * - set IFS to space and tab 75797c478bd9Sstevel@tonic-gate */ 75807c478bd9Sstevel@tonic-gate if (*cmdline != '/') { 75817c478bd9Sstevel@tonic-gate bam_error(ABS_PATH_REQ, cmdline); 75827c478bd9Sstevel@tonic-gate return (-1); 75837c478bd9Sstevel@tonic-gate } 75847c478bd9Sstevel@tonic-gate (void) putenv("IFS= \t"); 75857c478bd9Sstevel@tonic-gate 75867c478bd9Sstevel@tonic-gate /* 75877c478bd9Sstevel@tonic-gate * We may have been exec'ed with SIGCHLD blocked 75887c478bd9Sstevel@tonic-gate * unblock it here 75897c478bd9Sstevel@tonic-gate */ 75907c478bd9Sstevel@tonic-gate (void) sigemptyset(&set); 75917c478bd9Sstevel@tonic-gate (void) sigaddset(&set, SIGCHLD); 75927c478bd9Sstevel@tonic-gate if (sigprocmask(SIG_UNBLOCK, &set, NULL) != 0) { 75937c478bd9Sstevel@tonic-gate bam_error(CANT_UNBLOCK_SIGCHLD, strerror(errno)); 75947c478bd9Sstevel@tonic-gate return (-1); 75957c478bd9Sstevel@tonic-gate } 75967c478bd9Sstevel@tonic-gate 75977c478bd9Sstevel@tonic-gate /* 75987c478bd9Sstevel@tonic-gate * Set SIGCHLD disposition to SIG_DFL for popen/pclose 75997c478bd9Sstevel@tonic-gate */ 76007c478bd9Sstevel@tonic-gate disp = sigset(SIGCHLD, SIG_DFL); 76017c478bd9Sstevel@tonic-gate if (disp == SIG_ERR) { 76027c478bd9Sstevel@tonic-gate bam_error(FAILED_SIG, strerror(errno)); 76037c478bd9Sstevel@tonic-gate return (-1); 76047c478bd9Sstevel@tonic-gate } 76057c478bd9Sstevel@tonic-gate if (disp == SIG_HOLD) { 76067c478bd9Sstevel@tonic-gate bam_error(BLOCKED_SIG, cmdline); 76077c478bd9Sstevel@tonic-gate return (-1); 76087c478bd9Sstevel@tonic-gate } 76097c478bd9Sstevel@tonic-gate 76107c478bd9Sstevel@tonic-gate ptr = popen(cmdline, "r"); 76117c478bd9Sstevel@tonic-gate if (ptr == NULL) { 76127c478bd9Sstevel@tonic-gate bam_error(POPEN_FAIL, cmdline, strerror(errno)); 76137c478bd9Sstevel@tonic-gate return (-1); 76147c478bd9Sstevel@tonic-gate } 76157c478bd9Sstevel@tonic-gate 76167c478bd9Sstevel@tonic-gate /* 76177c478bd9Sstevel@tonic-gate * If we simply do a pclose() following a popen(), pclose() 76187c478bd9Sstevel@tonic-gate * will close the reader end of the pipe immediately even 76197c478bd9Sstevel@tonic-gate * if the child process has not started/exited. pclose() 76207c478bd9Sstevel@tonic-gate * does wait for cmd to terminate before returning though. 76217c478bd9Sstevel@tonic-gate * When the executed command writes its output to the pipe 76227c478bd9Sstevel@tonic-gate * there is no reader process and the command dies with 76237c478bd9Sstevel@tonic-gate * SIGPIPE. To avoid this we read repeatedly until read 76247c478bd9Sstevel@tonic-gate * terminates with EOF. This indicates that the command 76257c478bd9Sstevel@tonic-gate * (writer) has closed the pipe and we can safely do a 76267c478bd9Sstevel@tonic-gate * pclose(). 76277c478bd9Sstevel@tonic-gate * 76287c478bd9Sstevel@tonic-gate * Since pclose() does wait for the command to exit, 76297c478bd9Sstevel@tonic-gate * we can safely reap the exit status of the command 76307c478bd9Sstevel@tonic-gate * from the value returned by pclose() 76317c478bd9Sstevel@tonic-gate */ 7632986fd29aSsetje while (s_fgets(buf, sizeof (buf), ptr) != NULL) { 7633986fd29aSsetje if (flistp == NULL) { 7634986fd29aSsetje /* s_fgets strips newlines, so insert them at the end */ 7635986fd29aSsetje bam_print(PRINT, buf); 7636986fd29aSsetje } else { 7637986fd29aSsetje append_to_flist(flistp, buf); 76387c478bd9Sstevel@tonic-gate } 76397c478bd9Sstevel@tonic-gate } 76407c478bd9Sstevel@tonic-gate 76417c478bd9Sstevel@tonic-gate ret = pclose(ptr); 76427c478bd9Sstevel@tonic-gate if (ret == -1) { 76437c478bd9Sstevel@tonic-gate bam_error(PCLOSE_FAIL, cmdline, strerror(errno)); 76447c478bd9Sstevel@tonic-gate return (-1); 76457c478bd9Sstevel@tonic-gate } 76467c478bd9Sstevel@tonic-gate 76477c478bd9Sstevel@tonic-gate if (WIFEXITED(ret)) { 76487c478bd9Sstevel@tonic-gate return (WEXITSTATUS(ret)); 76497c478bd9Sstevel@tonic-gate } else { 76507c478bd9Sstevel@tonic-gate bam_error(EXEC_FAIL, cmdline, ret); 76517c478bd9Sstevel@tonic-gate return (-1); 76527c478bd9Sstevel@tonic-gate } 76537c478bd9Sstevel@tonic-gate } 76547c478bd9Sstevel@tonic-gate 76557c478bd9Sstevel@tonic-gate /* 76567c478bd9Sstevel@tonic-gate * Since this function returns -1 on error 76577c478bd9Sstevel@tonic-gate * it cannot be used to convert -1. However, 76587c478bd9Sstevel@tonic-gate * that is sufficient for what we need. 76597c478bd9Sstevel@tonic-gate */ 76607c478bd9Sstevel@tonic-gate static long 76617c478bd9Sstevel@tonic-gate s_strtol(char *str) 76627c478bd9Sstevel@tonic-gate { 76637c478bd9Sstevel@tonic-gate long l; 76647c478bd9Sstevel@tonic-gate char *res = NULL; 76657c478bd9Sstevel@tonic-gate 76667c478bd9Sstevel@tonic-gate if (str == NULL) { 76677c478bd9Sstevel@tonic-gate return (-1); 76687c478bd9Sstevel@tonic-gate } 76697c478bd9Sstevel@tonic-gate 76707c478bd9Sstevel@tonic-gate errno = 0; 76717c478bd9Sstevel@tonic-gate l = strtol(str, &res, 10); 76727c478bd9Sstevel@tonic-gate if (errno || *res != '\0') { 76737c478bd9Sstevel@tonic-gate return (-1); 76747c478bd9Sstevel@tonic-gate } 76757c478bd9Sstevel@tonic-gate 76767c478bd9Sstevel@tonic-gate return (l); 76777c478bd9Sstevel@tonic-gate } 76787c478bd9Sstevel@tonic-gate 76797c478bd9Sstevel@tonic-gate /* 76807c478bd9Sstevel@tonic-gate * Wrapper around fputs, that adds a newline (since fputs doesn't) 76817c478bd9Sstevel@tonic-gate */ 76827c478bd9Sstevel@tonic-gate static int 76837c478bd9Sstevel@tonic-gate s_fputs(char *str, FILE *fp) 76847c478bd9Sstevel@tonic-gate { 76857c478bd9Sstevel@tonic-gate char linebuf[BAM_MAXLINE]; 76867c478bd9Sstevel@tonic-gate 76877c478bd9Sstevel@tonic-gate (void) snprintf(linebuf, sizeof (linebuf), "%s\n", str); 76887c478bd9Sstevel@tonic-gate return (fputs(linebuf, fp)); 76897c478bd9Sstevel@tonic-gate } 76907c478bd9Sstevel@tonic-gate 76917c478bd9Sstevel@tonic-gate /* 76927c478bd9Sstevel@tonic-gate * Wrapper around fgets, that strips newlines returned by fgets 76937c478bd9Sstevel@tonic-gate */ 7694ae115bc7Smrj char * 76957c478bd9Sstevel@tonic-gate s_fgets(char *buf, int buflen, FILE *fp) 76967c478bd9Sstevel@tonic-gate { 76977c478bd9Sstevel@tonic-gate int n; 76987c478bd9Sstevel@tonic-gate 76997c478bd9Sstevel@tonic-gate buf = fgets(buf, buflen, fp); 77007c478bd9Sstevel@tonic-gate if (buf) { 77017c478bd9Sstevel@tonic-gate n = strlen(buf); 77027c478bd9Sstevel@tonic-gate if (n == buflen - 1 && buf[n-1] != '\n') 77037c478bd9Sstevel@tonic-gate bam_error(TOO_LONG, buflen - 1, buf); 77047c478bd9Sstevel@tonic-gate buf[n-1] = (buf[n-1] == '\n') ? '\0' : buf[n-1]; 77057c478bd9Sstevel@tonic-gate } 77067c478bd9Sstevel@tonic-gate 77077c478bd9Sstevel@tonic-gate return (buf); 77087c478bd9Sstevel@tonic-gate } 77097c478bd9Sstevel@tonic-gate 7710ae115bc7Smrj void * 77117c478bd9Sstevel@tonic-gate s_calloc(size_t nelem, size_t sz) 77127c478bd9Sstevel@tonic-gate { 77137c478bd9Sstevel@tonic-gate void *ptr; 77147c478bd9Sstevel@tonic-gate 77157c478bd9Sstevel@tonic-gate ptr = calloc(nelem, sz); 77167c478bd9Sstevel@tonic-gate if (ptr == NULL) { 77177c478bd9Sstevel@tonic-gate bam_error(NO_MEM, nelem*sz); 77187c478bd9Sstevel@tonic-gate bam_exit(1); 77197c478bd9Sstevel@tonic-gate } 77207c478bd9Sstevel@tonic-gate return (ptr); 77217c478bd9Sstevel@tonic-gate } 77227c478bd9Sstevel@tonic-gate 7723ae115bc7Smrj void * 7724ae115bc7Smrj s_realloc(void *ptr, size_t sz) 7725ae115bc7Smrj { 7726ae115bc7Smrj ptr = realloc(ptr, sz); 7727ae115bc7Smrj if (ptr == NULL) { 7728ae115bc7Smrj bam_error(NO_MEM, sz); 7729ae115bc7Smrj bam_exit(1); 7730ae115bc7Smrj } 7731ae115bc7Smrj return (ptr); 7732ae115bc7Smrj } 7733ae115bc7Smrj 7734eb2bd662Svikram char * 77357c478bd9Sstevel@tonic-gate s_strdup(char *str) 77367c478bd9Sstevel@tonic-gate { 77377c478bd9Sstevel@tonic-gate char *ptr; 77387c478bd9Sstevel@tonic-gate 77397c478bd9Sstevel@tonic-gate if (str == NULL) 77407c478bd9Sstevel@tonic-gate return (NULL); 77417c478bd9Sstevel@tonic-gate 77427c478bd9Sstevel@tonic-gate ptr = strdup(str); 77437c478bd9Sstevel@tonic-gate if (ptr == NULL) { 77447c478bd9Sstevel@tonic-gate bam_error(NO_MEM, strlen(str) + 1); 77457c478bd9Sstevel@tonic-gate bam_exit(1); 77467c478bd9Sstevel@tonic-gate } 77477c478bd9Sstevel@tonic-gate return (ptr); 77487c478bd9Sstevel@tonic-gate } 77497c478bd9Sstevel@tonic-gate 77507c478bd9Sstevel@tonic-gate /* 77517c478bd9Sstevel@tonic-gate * Returns 1 if amd64 (or sparc, for syncing x86 diskless clients) 77527c478bd9Sstevel@tonic-gate * Returns 0 otherwise 77537c478bd9Sstevel@tonic-gate */ 77547c478bd9Sstevel@tonic-gate static int 77557c478bd9Sstevel@tonic-gate is_amd64(void) 77567c478bd9Sstevel@tonic-gate { 77577c478bd9Sstevel@tonic-gate static int amd64 = -1; 77587c478bd9Sstevel@tonic-gate char isabuf[257]; /* from sysinfo(2) manpage */ 77597c478bd9Sstevel@tonic-gate 77607c478bd9Sstevel@tonic-gate if (amd64 != -1) 77617c478bd9Sstevel@tonic-gate return (amd64); 77627c478bd9Sstevel@tonic-gate 7763d876c67dSjg if (bam_alt_platform) { 7764d876c67dSjg if (strcmp(bam_platform, "i86pc") == 0) { 7765d876c67dSjg amd64 = 1; /* diskless server */ 7766d876c67dSjg } 7767d876c67dSjg } else { 7768d876c67dSjg if (sysinfo(SI_ISALIST, isabuf, sizeof (isabuf)) > 0 && 7769d876c67dSjg strncmp(isabuf, "amd64 ", strlen("amd64 ")) == 0) { 7770d876c67dSjg amd64 = 1; 7771d876c67dSjg } else if (strstr(isabuf, "i386") == NULL) { 7772d876c67dSjg amd64 = 1; /* diskless server */ 7773d876c67dSjg } 7774d876c67dSjg } 7775d876c67dSjg if (amd64 == -1) 77767c478bd9Sstevel@tonic-gate amd64 = 0; 77777c478bd9Sstevel@tonic-gate 77787c478bd9Sstevel@tonic-gate return (amd64); 77797c478bd9Sstevel@tonic-gate } 77807c478bd9Sstevel@tonic-gate 778179755401Ssetje static char * 778279755401Ssetje get_machine(void) 7783986fd29aSsetje { 778479755401Ssetje static int cached = -1; 778579755401Ssetje static char mbuf[257]; /* from sysinfo(2) manpage */ 7786986fd29aSsetje 778779755401Ssetje if (cached == 0) 778879755401Ssetje return (mbuf); 7789d876c67dSjg 7790d876c67dSjg if (bam_alt_platform) { 779179755401Ssetje return (bam_platform); 7792d876c67dSjg } else { 779379755401Ssetje if (sysinfo(SI_MACHINE, mbuf, sizeof (mbuf)) > 0) { 779479755401Ssetje cached = 1; 7795d876c67dSjg } 7796d876c67dSjg } 779779755401Ssetje if (cached == -1) { 779879755401Ssetje mbuf[0] = '\0'; 779979755401Ssetje cached = 0; 780079755401Ssetje } 7801986fd29aSsetje 780279755401Ssetje return (mbuf); 7803986fd29aSsetje } 7804986fd29aSsetje 780579755401Ssetje int 780679755401Ssetje is_sparc(void) 7807986fd29aSsetje { 780879755401Ssetje static int issparc = -1; 7809986fd29aSsetje char mbuf[257]; /* from sysinfo(2) manpage */ 7810986fd29aSsetje 781179755401Ssetje if (issparc != -1) 781279755401Ssetje return (issparc); 7813d876c67dSjg 7814d876c67dSjg if (bam_alt_platform) { 781579755401Ssetje if (strncmp(bam_platform, "sun4", 4) == 0) { 781679755401Ssetje issparc = 1; 7817d876c67dSjg } 7818d876c67dSjg } else { 781979755401Ssetje if (sysinfo(SI_ARCHITECTURE, mbuf, sizeof (mbuf)) > 0 && 7820d7d0f93bSjg strcmp(mbuf, "sparc") == 0) { 782179755401Ssetje issparc = 1; 7822d7d0f93bSjg } 7823d876c67dSjg } 7824d7d0f93bSjg if (issparc == -1) 7825d7d0f93bSjg issparc = 0; 7826986fd29aSsetje 782779755401Ssetje return (issparc); 7828eb2bd662Svikram } 7829986fd29aSsetje 78307c478bd9Sstevel@tonic-gate static void 78317c478bd9Sstevel@tonic-gate append_to_flist(filelist_t *flistp, char *s) 78327c478bd9Sstevel@tonic-gate { 78337c478bd9Sstevel@tonic-gate line_t *lp; 78347c478bd9Sstevel@tonic-gate 78357c478bd9Sstevel@tonic-gate lp = s_calloc(1, sizeof (line_t)); 78367c478bd9Sstevel@tonic-gate lp->line = s_strdup(s); 78377c478bd9Sstevel@tonic-gate if (flistp->head == NULL) 78387c478bd9Sstevel@tonic-gate flistp->head = lp; 78397c478bd9Sstevel@tonic-gate else 78407c478bd9Sstevel@tonic-gate flistp->tail->next = lp; 78417c478bd9Sstevel@tonic-gate flistp->tail = lp; 78427c478bd9Sstevel@tonic-gate } 78432449e17fSsherrym 7844986fd29aSsetje #if !defined(_OPB) 78452449e17fSsherrym 78462449e17fSsherrym UCODE_VENDORS; 78472449e17fSsherrym 78482449e17fSsherrym /*ARGSUSED*/ 78492449e17fSsherrym static void 78502449e17fSsherrym ucode_install(char *root) 78512449e17fSsherrym { 78522449e17fSsherrym int i; 78532449e17fSsherrym 78542449e17fSsherrym for (i = 0; ucode_vendors[i].filestr != NULL; i++) { 78552449e17fSsherrym int cmd_len = PATH_MAX + 256; 78562449e17fSsherrym char cmd[PATH_MAX + 256]; 78572449e17fSsherrym char file[PATH_MAX]; 78582449e17fSsherrym char timestamp[PATH_MAX]; 78592449e17fSsherrym struct stat fstatus, tstatus; 78602449e17fSsherrym struct utimbuf u_times; 78612449e17fSsherrym 78622449e17fSsherrym (void) snprintf(file, PATH_MAX, "%s/%s/%s-ucode.txt", 78632449e17fSsherrym bam_root, UCODE_INSTALL_PATH, ucode_vendors[i].filestr); 78642449e17fSsherrym 78652449e17fSsherrym if (stat(file, &fstatus) != 0 || !(S_ISREG(fstatus.st_mode))) 78662449e17fSsherrym continue; 78672449e17fSsherrym 78682449e17fSsherrym (void) snprintf(timestamp, PATH_MAX, "%s.ts", file); 78692449e17fSsherrym 78702449e17fSsherrym if (stat(timestamp, &tstatus) == 0 && 78712449e17fSsherrym fstatus.st_mtime <= tstatus.st_mtime) 78722449e17fSsherrym continue; 78732449e17fSsherrym 78742449e17fSsherrym (void) snprintf(cmd, cmd_len, "/usr/sbin/ucodeadm -i -R " 78752449e17fSsherrym "%s/%s/%s %s > /dev/null 2>&1", bam_root, 78762449e17fSsherrym UCODE_INSTALL_PATH, ucode_vendors[i].vendorstr, file); 78772449e17fSsherrym if (system(cmd) != 0) 78782449e17fSsherrym return; 78792449e17fSsherrym 78802449e17fSsherrym if (creat(timestamp, S_IRUSR | S_IWUSR) == -1) 78812449e17fSsherrym return; 78822449e17fSsherrym 78832449e17fSsherrym u_times.actime = fstatus.st_atime; 78842449e17fSsherrym u_times.modtime = fstatus.st_mtime; 78852449e17fSsherrym (void) utime(timestamp, &u_times); 78862449e17fSsherrym } 78872449e17fSsherrym } 78882449e17fSsherrym #endif 7889