10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 51746Svikram * Common Development and Distribution License (the "License"). 61746Svikram * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 226319Sjg * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 270Sstevel@tonic-gate 280Sstevel@tonic-gate /* 290Sstevel@tonic-gate * bootadm(1M) is a new utility for managing bootability of 300Sstevel@tonic-gate * Solaris *Newboot* environments. It has two primary tasks: 310Sstevel@tonic-gate * - Allow end users to manage bootability of Newboot Solaris instances 320Sstevel@tonic-gate * - Provide services to other subsystems in Solaris (primarily Install) 330Sstevel@tonic-gate */ 340Sstevel@tonic-gate 350Sstevel@tonic-gate /* Headers */ 360Sstevel@tonic-gate #include <stdio.h> 370Sstevel@tonic-gate #include <errno.h> 380Sstevel@tonic-gate #include <stdlib.h> 390Sstevel@tonic-gate #include <string.h> 400Sstevel@tonic-gate #include <unistd.h> 410Sstevel@tonic-gate #include <sys/types.h> 420Sstevel@tonic-gate #include <sys/stat.h> 430Sstevel@tonic-gate #include <stdarg.h> 440Sstevel@tonic-gate #include <limits.h> 450Sstevel@tonic-gate #include <signal.h> 460Sstevel@tonic-gate #include <sys/wait.h> 470Sstevel@tonic-gate #include <sys/mnttab.h> 480Sstevel@tonic-gate #include <sys/statvfs.h> 490Sstevel@tonic-gate #include <libnvpair.h> 500Sstevel@tonic-gate #include <ftw.h> 510Sstevel@tonic-gate #include <fcntl.h> 520Sstevel@tonic-gate #include <strings.h> 534581Ssherrym #include <utime.h> 540Sstevel@tonic-gate #include <sys/systeminfo.h> 550Sstevel@tonic-gate #include <sys/dktp/fdisk.h> 562334Ssetje #include <sys/param.h> 576448Svikram #include <dirent.h> 586448Svikram #include <ctype.h> 596448Svikram #include <libgen.h> 606423Sgw25295 #include <sys/sysmacros.h> 616694Svikram #include <libscf.h> 625648Ssetje 635648Ssetje #if !defined(_OPB) 644581Ssherrym #include <sys/ucode.h> 654581Ssherrym #endif 660Sstevel@tonic-gate 670Sstevel@tonic-gate #include <pwd.h> 680Sstevel@tonic-gate #include <grp.h> 690Sstevel@tonic-gate #include <device_info.h> 706448Svikram #include <sys/vtoc.h> 716448Svikram #include <sys/efi_partition.h> 726448Svikram 730Sstevel@tonic-gate #include <locale.h> 740Sstevel@tonic-gate 750Sstevel@tonic-gate #include "message.h" 763446Smrj #include "bootadm.h" 770Sstevel@tonic-gate 780Sstevel@tonic-gate #ifndef TEXT_DOMAIN 790Sstevel@tonic-gate #define TEXT_DOMAIN "SUNW_OST_OSCMD" 800Sstevel@tonic-gate #endif /* TEXT_DOMAIN */ 810Sstevel@tonic-gate 820Sstevel@tonic-gate /* Type definitions */ 830Sstevel@tonic-gate 840Sstevel@tonic-gate /* Primary subcmds */ 850Sstevel@tonic-gate typedef enum { 860Sstevel@tonic-gate BAM_MENU = 3, 870Sstevel@tonic-gate BAM_ARCHIVE 880Sstevel@tonic-gate } subcmd_t; 890Sstevel@tonic-gate 900Sstevel@tonic-gate typedef enum { 910Sstevel@tonic-gate OPT_ABSENT = 0, /* No option */ 920Sstevel@tonic-gate OPT_REQ, /* option required */ 930Sstevel@tonic-gate OPT_OPTIONAL /* option may or may not be present */ 940Sstevel@tonic-gate } option_t; 950Sstevel@tonic-gate 960Sstevel@tonic-gate typedef struct { 970Sstevel@tonic-gate char *subcmd; 980Sstevel@tonic-gate option_t option; 990Sstevel@tonic-gate error_t (*handler)(); 1002115Svikram int unpriv; /* is this an unprivileged command */ 1010Sstevel@tonic-gate } subcmd_defn_t; 1020Sstevel@tonic-gate 1030Sstevel@tonic-gate #define LINE_INIT 0 /* lineNum initial value */ 1040Sstevel@tonic-gate #define ENTRY_INIT -1 /* entryNum initial value */ 1050Sstevel@tonic-gate #define ALL_ENTRIES -2 /* selects all boot entries */ 1060Sstevel@tonic-gate 1070Sstevel@tonic-gate #define GRUB_DIR "/boot/grub" 1086694Svikram #define GRUB_STAGE2 GRUB_DIR "/stage2" 1090Sstevel@tonic-gate #define GRUB_MENU "/boot/grub/menu.lst" 1100Sstevel@tonic-gate #define MENU_TMP "/boot/grub/menu.lst.tmp" 1116694Svikram #define GRUB_BACKUP_MENU "/etc/lu/GRUB_backup_menu" 1120Sstevel@tonic-gate #define RAMDISK_SPECIAL "/ramdisk" 113621Svikram #define STUBBOOT "/stubboot" 1146448Svikram #define MULTIBOOT "/platform/i86pc/multiboot" 1156448Svikram #define GRUBSIGN_DIR "/boot/grub/bootsign" 1166448Svikram #define GRUBSIGN_BACKUP "/etc/bootsign" 1176448Svikram #define GRUBSIGN_UFS_PREFIX "rootfs" 1186448Svikram #define GRUBSIGN_ZFS_PREFIX "pool_" 1196448Svikram #define GRUBSIGN_LU_PREFIX "BE_" 1206448Svikram #define UFS_SIGNATURE_LIST "/var/run/grub_ufs_signatures" 1216448Svikram #define ZFS_LEGACY_MNTPT "/tmp/bootadm_mnt_zfs_legacy" 1226448Svikram 1236448Svikram #define BOOTADM_RDONLY_TEST "BOOTADM_RDONLY_TEST" 1240Sstevel@tonic-gate 1250Sstevel@tonic-gate /* lock related */ 1260Sstevel@tonic-gate #define BAM_LOCK_FILE "/var/run/bootadm.lock" 1270Sstevel@tonic-gate #define LOCK_FILE_PERMS (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) 1280Sstevel@tonic-gate 1295648Ssetje #define CREATE_RAMDISK "boot/solaris/bin/create_ramdisk" 1305648Ssetje #define CREATE_DISKMAP "boot/solaris/bin/create_diskmap" 1315648Ssetje #define EXTRACT_BOOT_FILELIST "boot/solaris/bin/extract_boot_filelist" 1320Sstevel@tonic-gate #define GRUBDISK_MAP "/var/run/solaris_grubdisk.map" 1330Sstevel@tonic-gate 134316Svikram #define GRUB_slice "/etc/lu/GRUB_slice" 135316Svikram #define GRUB_root "/etc/lu/GRUB_root" 1361746Svikram #define GRUB_fdisk "/etc/lu/GRUB_fdisk" 1371746Svikram #define GRUB_fdisk_target "/etc/lu/GRUB_fdisk_target" 1386694Svikram #define FINDROOT_INSTALLGRUB "/etc/lu/installgrub.findroot" 1396694Svikram #define LULIB "/usr/lib/lu/lulib" 1406694Svikram #define LULIB_PROPAGATE_FILE "lulib_propagate_file" 1416694Svikram #define CKSUM "/usr/bin/cksum" 1426694Svikram #define LU_MENU_CKSUM "/etc/lu/menu.cksum" 1436694Svikram #define BOOTADM "/sbin/bootadm" 144316Svikram 145316Svikram #define INSTALLGRUB "/sbin/installgrub" 146316Svikram #define STAGE1 "/boot/grub/stage1" 147316Svikram #define STAGE2 "/boot/grub/stage2" 148316Svikram 1496448Svikram typedef enum zfs_mnted { 1506448Svikram ZFS_MNT_ERROR = -1, 1516448Svikram LEGACY_MOUNTED = 1, 1526448Svikram LEGACY_ALREADY, 1536448Svikram ZFS_MOUNTED, 1546448Svikram ZFS_ALREADY 1556448Svikram } zfs_mnted_t; 1566448Svikram 1576448Svikram 1586448Svikram 1596448Svikram 1600Sstevel@tonic-gate /* 1614493Snadkarni * The following two defines are used to detect and create the correct 1624493Snadkarni * boot archive when safemode patching is underway. LOFS_PATCH_FILE is a 1634493Snadkarni * contracted private interface between bootadm and the install 1644493Snadkarni * consolidation. It is set by pdo.c when a patch with SUNW_PATCH_SAFEMODE 1654493Snadkarni * is applied. 1664493Snadkarni */ 1674493Snadkarni 1684493Snadkarni #define LOFS_PATCH_FILE "/var/run/.patch_loopback_mode" 1694493Snadkarni #define LOFS_PATCH_MNT "/var/run/.patch_root_loopbackmnt" 1704493Snadkarni 1714493Snadkarni /* 1720Sstevel@tonic-gate * Default file attributes 1730Sstevel@tonic-gate */ 1740Sstevel@tonic-gate #define DEFAULT_DEV_MODE 0644 /* default permissions */ 1750Sstevel@tonic-gate #define DEFAULT_DEV_UID 0 /* user root */ 1760Sstevel@tonic-gate #define DEFAULT_DEV_GID 3 /* group sys */ 1770Sstevel@tonic-gate 1780Sstevel@tonic-gate /* 1790Sstevel@tonic-gate * Menu related 1800Sstevel@tonic-gate * menu_cmd_t and menu_cmds must be kept in sync 1810Sstevel@tonic-gate */ 1823446Smrj char *menu_cmds[] = { 1830Sstevel@tonic-gate "default", /* DEFAULT_CMD */ 1840Sstevel@tonic-gate "timeout", /* TIMEOUT_CMD */ 1850Sstevel@tonic-gate "title", /* TITLE_CMD */ 1860Sstevel@tonic-gate "root", /* ROOT_CMD */ 1870Sstevel@tonic-gate "kernel", /* KERNEL_CMD */ 1883446Smrj "kernel$", /* KERNEL_DOLLAR_CMD */ 1890Sstevel@tonic-gate "module", /* MODULE_CMD */ 1903446Smrj "module$", /* MODULE_DOLLAR_CMD */ 1910Sstevel@tonic-gate " ", /* SEP_CMD */ 1920Sstevel@tonic-gate "#", /* COMMENT_CMD */ 1933446Smrj "chainloader", /* CHAINLOADER_CMD */ 1943446Smrj "args", /* ARGS_CMD */ 1956448Svikram "findroot", /* FINDROOT_CMD */ 1960Sstevel@tonic-gate NULL 1970Sstevel@tonic-gate }; 1980Sstevel@tonic-gate 1990Sstevel@tonic-gate #define OPT_ENTRY_NUM "entry" 2000Sstevel@tonic-gate 2010Sstevel@tonic-gate /* 2026448Svikram * exec_cmd related 2030Sstevel@tonic-gate */ 2040Sstevel@tonic-gate typedef struct { 2050Sstevel@tonic-gate line_t *head; 2060Sstevel@tonic-gate line_t *tail; 2070Sstevel@tonic-gate } filelist_t; 2080Sstevel@tonic-gate 2090Sstevel@tonic-gate #define BOOT_FILE_LIST "boot/solaris/filelist.ramdisk" 2100Sstevel@tonic-gate #define ETC_FILE_LIST "etc/boot/solaris/filelist.ramdisk" 2110Sstevel@tonic-gate 2120Sstevel@tonic-gate #define FILE_STAT "boot/solaris/filestat.ramdisk" 2130Sstevel@tonic-gate #define FILE_STAT_TMP "boot/solaris/filestat.ramdisk.tmp" 2140Sstevel@tonic-gate #define DIR_PERMS (S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) 2150Sstevel@tonic-gate #define FILE_STAT_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) 2160Sstevel@tonic-gate 2170Sstevel@tonic-gate /* Globals */ 2183446Smrj int bam_verbose; 2193446Smrj int bam_force; 2206448Svikram int bam_debug; 2210Sstevel@tonic-gate static char *prog; 2220Sstevel@tonic-gate static subcmd_t bam_cmd; 2230Sstevel@tonic-gate static char *bam_root; 2240Sstevel@tonic-gate static int bam_rootlen; 2250Sstevel@tonic-gate static int bam_root_readonly; 226621Svikram static int bam_alt_root; 2270Sstevel@tonic-gate static char *bam_subcmd; 2280Sstevel@tonic-gate static char *bam_opt; 2290Sstevel@tonic-gate static char **bam_argv; 2300Sstevel@tonic-gate static int bam_argc; 2310Sstevel@tonic-gate static int bam_check; 2320Sstevel@tonic-gate static int bam_smf_check; 2330Sstevel@tonic-gate static int bam_lock_fd = -1; 2346423Sgw25295 static int bam_zfs; 2350Sstevel@tonic-gate static char rootbuf[PATH_MAX] = "/"; 236316Svikram static int bam_update_all; 2376319Sjg static int bam_alt_platform; 2386319Sjg static char *bam_platform; 2390Sstevel@tonic-gate 2400Sstevel@tonic-gate /* function prototypes */ 2415648Ssetje static void parse_args_internal(int, char *[]); 2425648Ssetje static void parse_args(int, char *argv[]); 2435648Ssetje static error_t bam_menu(char *, char *, int, char *[]); 2445648Ssetje static error_t bam_archive(char *, char *); 2455648Ssetje 2465648Ssetje static void bam_exit(int); 2470Sstevel@tonic-gate static void bam_lock(void); 2480Sstevel@tonic-gate static void bam_unlock(void); 2490Sstevel@tonic-gate 2505648Ssetje static int exec_cmd(char *, filelist_t *); 2515648Ssetje static error_t read_globals(menu_t *, char *, char *, int); 2526448Svikram static int menu_on_bootdisk(char *os_root, char *menu_root); 2535648Ssetje static menu_t *menu_read(char *); 2545648Ssetje static error_t menu_write(char *, menu_t *); 2555648Ssetje static void linelist_free(line_t *); 2565648Ssetje static void menu_free(menu_t *); 2575648Ssetje static void filelist_free(filelist_t *); 2585648Ssetje static error_t list2file(char *, char *, char *, line_t *); 2595648Ssetje static error_t list_entry(menu_t *, char *, char *); 2605648Ssetje static error_t delete_all_entries(menu_t *, char *, char *); 2616448Svikram static error_t update_entry(menu_t *mp, char *menu_root, char *opt); 2626448Svikram static error_t update_temp(menu_t *mp, char *dummy, char *opt); 2635648Ssetje 2645648Ssetje static error_t update_archive(char *, char *); 2655648Ssetje static error_t list_archive(char *, char *); 2665648Ssetje static error_t update_all(char *, char *); 2675648Ssetje static error_t read_list(char *, filelist_t *); 2685648Ssetje static error_t set_global(menu_t *, char *, int); 2695648Ssetje static error_t set_option(menu_t *, char *, char *); 2705648Ssetje static error_t set_kernel(menu_t *, menu_cmd_t, char *, char *, size_t); 2716448Svikram static error_t get_kernel(menu_t *, menu_cmd_t, char *, size_t); 2725648Ssetje static char *expand_path(const char *); 2735648Ssetje 2745648Ssetje static long s_strtol(char *); 2755648Ssetje static int s_fputs(char *, FILE *); 2765648Ssetje 2776448Svikram static int is_zfs(char *root); 2786448Svikram static int is_ufs(char *root); 2796448Svikram static int is_pcfs(char *root); 2800Sstevel@tonic-gate static int is_amd64(void); 2816582Ssetje static char *get_machine(void); 2820Sstevel@tonic-gate static void append_to_flist(filelist_t *, char *); 2836448Svikram static char *mount_top_dataset(char *pool, zfs_mnted_t *mnted); 2846448Svikram static int umount_top_dataset(char *pool, zfs_mnted_t mnted, char *mntpt); 2856448Svikram static int ufs_add_to_sign_list(char *sign); 2866694Svikram static error_t synchronize_BE_menu(void); 2870Sstevel@tonic-gate 2885648Ssetje #if !defined(_OPB) 2894581Ssherrym static void ucode_install(); 2904581Ssherrym #endif 2914581Ssherrym 2920Sstevel@tonic-gate /* Menu related sub commands */ 2930Sstevel@tonic-gate static subcmd_defn_t menu_subcmds[] = { 2946448Svikram "set_option", OPT_ABSENT, set_option, 0, /* PUB */ 2952115Svikram "list_entry", OPT_OPTIONAL, list_entry, 1, /* PUB */ 2962115Svikram "delete_all_entries", OPT_ABSENT, delete_all_entries, 0, /* PVT */ 2972115Svikram "update_entry", OPT_REQ, update_entry, 0, /* menu */ 2982115Svikram "update_temp", OPT_OPTIONAL, update_temp, 0, /* reboot */ 2993446Smrj "upgrade", OPT_ABSENT, upgrade_menu, 0, /* menu */ 3002115Svikram NULL, 0, NULL, 0 /* must be last */ 3010Sstevel@tonic-gate }; 3020Sstevel@tonic-gate 3030Sstevel@tonic-gate /* Archive related sub commands */ 3040Sstevel@tonic-gate static subcmd_defn_t arch_subcmds[] = { 3052115Svikram "update", OPT_ABSENT, update_archive, 0, /* PUB */ 3062115Svikram "update_all", OPT_ABSENT, update_all, 0, /* PVT */ 3072115Svikram "list", OPT_OPTIONAL, list_archive, 1, /* PUB */ 3082115Svikram NULL, 0, NULL, 0 /* must be last */ 3090Sstevel@tonic-gate }; 3100Sstevel@tonic-gate 3110Sstevel@tonic-gate static struct { 3120Sstevel@tonic-gate nvlist_t *new_nvlp; 3130Sstevel@tonic-gate nvlist_t *old_nvlp; 3140Sstevel@tonic-gate int need_update; 3150Sstevel@tonic-gate } walk_arg; 3160Sstevel@tonic-gate 3172334Ssetje 3182345Ssetje struct safefile { 3192334Ssetje char *name; 3202334Ssetje struct safefile *next; 3212334Ssetje }; 3222334Ssetje 3233446Smrj static struct safefile *safefiles = NULL; 3242334Ssetje #define NEED_UPDATE_FILE "/etc/svc/volatile/boot_archive_needs_update" 3252334Ssetje 3260Sstevel@tonic-gate static void 3270Sstevel@tonic-gate usage(void) 3280Sstevel@tonic-gate { 3290Sstevel@tonic-gate (void) fprintf(stderr, "USAGE:\n"); 3300Sstevel@tonic-gate 3310Sstevel@tonic-gate 3320Sstevel@tonic-gate /* archive usage */ 3336319Sjg (void) fprintf(stderr, 3346319Sjg "\t%s update-archive [-vn] [-R altroot [-p platform>]]\n", prog); 3356319Sjg (void) fprintf(stderr, 3366319Sjg "\t%s list-archive [-R altroot [-p platform>]]\n", prog); 3375648Ssetje #if !defined(_OPB) 3380Sstevel@tonic-gate /* x86 only */ 3390Sstevel@tonic-gate (void) fprintf(stderr, "\t%s set-menu [-R altroot] key=value\n", prog); 3400Sstevel@tonic-gate (void) fprintf(stderr, "\t%s list-menu [-R altroot]\n", prog); 3410Sstevel@tonic-gate #endif 3420Sstevel@tonic-gate } 3430Sstevel@tonic-gate 3440Sstevel@tonic-gate int 3450Sstevel@tonic-gate main(int argc, char *argv[]) 3460Sstevel@tonic-gate { 3470Sstevel@tonic-gate error_t ret; 3480Sstevel@tonic-gate 3490Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 3500Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 3510Sstevel@tonic-gate 3520Sstevel@tonic-gate if ((prog = strrchr(argv[0], '/')) == NULL) { 3530Sstevel@tonic-gate prog = argv[0]; 3540Sstevel@tonic-gate } else { 3550Sstevel@tonic-gate prog++; 3560Sstevel@tonic-gate } 3570Sstevel@tonic-gate 3586448Svikram INJECT_ERROR1("ASSERT_ON", assert(0)) 3590Sstevel@tonic-gate 3600Sstevel@tonic-gate /* 3610Sstevel@tonic-gate * Don't depend on caller's umask 3620Sstevel@tonic-gate */ 3630Sstevel@tonic-gate (void) umask(0022); 3640Sstevel@tonic-gate 3650Sstevel@tonic-gate parse_args(argc, argv); 3660Sstevel@tonic-gate 3670Sstevel@tonic-gate switch (bam_cmd) { 3680Sstevel@tonic-gate case BAM_MENU: 3690Sstevel@tonic-gate ret = bam_menu(bam_subcmd, bam_opt, bam_argc, bam_argv); 3700Sstevel@tonic-gate break; 3710Sstevel@tonic-gate case BAM_ARCHIVE: 3720Sstevel@tonic-gate ret = bam_archive(bam_subcmd, bam_opt); 3730Sstevel@tonic-gate break; 3740Sstevel@tonic-gate default: 3750Sstevel@tonic-gate usage(); 3760Sstevel@tonic-gate bam_exit(1); 3770Sstevel@tonic-gate } 3780Sstevel@tonic-gate 3790Sstevel@tonic-gate if (ret != BAM_SUCCESS) 3800Sstevel@tonic-gate bam_exit(1); 3810Sstevel@tonic-gate 3820Sstevel@tonic-gate bam_unlock(); 3830Sstevel@tonic-gate return (0); 3840Sstevel@tonic-gate } 3850Sstevel@tonic-gate 3860Sstevel@tonic-gate /* 3870Sstevel@tonic-gate * Equivalence of public and internal commands: 3880Sstevel@tonic-gate * update-archive -- -a update 3890Sstevel@tonic-gate * list-archive -- -a list 3900Sstevel@tonic-gate * set-menu -- -m set_option 3910Sstevel@tonic-gate * list-menu -- -m list_entry 3920Sstevel@tonic-gate * update-menu -- -m update_entry 3930Sstevel@tonic-gate */ 3940Sstevel@tonic-gate static struct cmd_map { 3950Sstevel@tonic-gate char *bam_cmdname; 3960Sstevel@tonic-gate int bam_cmd; 3970Sstevel@tonic-gate char *bam_subcmd; 3980Sstevel@tonic-gate } cmd_map[] = { 3990Sstevel@tonic-gate { "update-archive", BAM_ARCHIVE, "update"}, 4000Sstevel@tonic-gate { "list-archive", BAM_ARCHIVE, "list"}, 4010Sstevel@tonic-gate { "set-menu", BAM_MENU, "set_option"}, 4020Sstevel@tonic-gate { "list-menu", BAM_MENU, "list_entry"}, 4030Sstevel@tonic-gate { "update-menu", BAM_MENU, "update_entry"}, 4040Sstevel@tonic-gate { NULL, 0, NULL} 4050Sstevel@tonic-gate }; 4060Sstevel@tonic-gate 4070Sstevel@tonic-gate /* 4080Sstevel@tonic-gate * Commands syntax published in bootadm(1M) are parsed here 4090Sstevel@tonic-gate */ 4100Sstevel@tonic-gate static void 4110Sstevel@tonic-gate parse_args(int argc, char *argv[]) 4120Sstevel@tonic-gate { 4130Sstevel@tonic-gate struct cmd_map *cmp = cmd_map; 4140Sstevel@tonic-gate 4150Sstevel@tonic-gate /* command conforming to the final spec */ 4160Sstevel@tonic-gate if (argc > 1 && argv[1][0] != '-') { 4170Sstevel@tonic-gate /* 4180Sstevel@tonic-gate * Map commands to internal table. 4190Sstevel@tonic-gate */ 4200Sstevel@tonic-gate while (cmp->bam_cmdname) { 4210Sstevel@tonic-gate if (strcmp(argv[1], cmp->bam_cmdname) == 0) { 4220Sstevel@tonic-gate bam_cmd = cmp->bam_cmd; 4230Sstevel@tonic-gate bam_subcmd = cmp->bam_subcmd; 4240Sstevel@tonic-gate break; 4250Sstevel@tonic-gate } 4260Sstevel@tonic-gate cmp++; 4270Sstevel@tonic-gate } 4280Sstevel@tonic-gate if (cmp->bam_cmdname == NULL) { 4290Sstevel@tonic-gate usage(); 4300Sstevel@tonic-gate bam_exit(1); 4310Sstevel@tonic-gate } 4320Sstevel@tonic-gate argc--; 4330Sstevel@tonic-gate argv++; 4340Sstevel@tonic-gate } 4350Sstevel@tonic-gate 4360Sstevel@tonic-gate parse_args_internal(argc, argv); 4370Sstevel@tonic-gate } 4380Sstevel@tonic-gate 4390Sstevel@tonic-gate /* 4400Sstevel@tonic-gate * A combination of public and private commands are parsed here. 4410Sstevel@tonic-gate * The internal syntax and the corresponding functionality are: 4420Sstevel@tonic-gate * -a update -- update-archive 4430Sstevel@tonic-gate * -a list -- list-archive 4440Sstevel@tonic-gate * -a update-all -- (reboot to sync all mounted OS archive) 4450Sstevel@tonic-gate * -m update_entry -- update-menu 4460Sstevel@tonic-gate * -m list_entry -- list-menu 4470Sstevel@tonic-gate * -m update_temp -- (reboot -- [boot-args]) 4480Sstevel@tonic-gate * -m delete_all_entries -- (called from install) 4490Sstevel@tonic-gate */ 4500Sstevel@tonic-gate static void 4510Sstevel@tonic-gate parse_args_internal(int argc, char *argv[]) 4520Sstevel@tonic-gate { 4530Sstevel@tonic-gate int c, error; 4540Sstevel@tonic-gate extern char *optarg; 4550Sstevel@tonic-gate extern int optind, opterr; 4560Sstevel@tonic-gate 4570Sstevel@tonic-gate /* Suppress error message from getopt */ 4580Sstevel@tonic-gate opterr = 0; 4590Sstevel@tonic-gate 4600Sstevel@tonic-gate error = 0; 4616423Sgw25295 while ((c = getopt(argc, argv, "a:d:fm:no:vCR:p:Z")) != -1) { 4620Sstevel@tonic-gate switch (c) { 4630Sstevel@tonic-gate case 'a': 4640Sstevel@tonic-gate if (bam_cmd) { 4650Sstevel@tonic-gate error = 1; 4660Sstevel@tonic-gate bam_error(MULT_CMDS, c); 4670Sstevel@tonic-gate } 4680Sstevel@tonic-gate bam_cmd = BAM_ARCHIVE; 4690Sstevel@tonic-gate bam_subcmd = optarg; 4700Sstevel@tonic-gate break; 4710Sstevel@tonic-gate case 'd': 4720Sstevel@tonic-gate if (bam_debug) { 4730Sstevel@tonic-gate error = 1; 4740Sstevel@tonic-gate bam_error(DUP_OPT, c); 4750Sstevel@tonic-gate } 4760Sstevel@tonic-gate bam_debug = s_strtol(optarg); 4770Sstevel@tonic-gate break; 4780Sstevel@tonic-gate case 'f': 4790Sstevel@tonic-gate if (bam_force) { 4800Sstevel@tonic-gate error = 1; 4810Sstevel@tonic-gate bam_error(DUP_OPT, c); 4820Sstevel@tonic-gate } 4830Sstevel@tonic-gate bam_force = 1; 4840Sstevel@tonic-gate break; 4850Sstevel@tonic-gate case 'm': 4860Sstevel@tonic-gate if (bam_cmd) { 4870Sstevel@tonic-gate error = 1; 4880Sstevel@tonic-gate bam_error(MULT_CMDS, c); 4890Sstevel@tonic-gate } 4900Sstevel@tonic-gate bam_cmd = BAM_MENU; 4910Sstevel@tonic-gate bam_subcmd = optarg; 4920Sstevel@tonic-gate break; 4930Sstevel@tonic-gate case 'n': 4940Sstevel@tonic-gate if (bam_check) { 4950Sstevel@tonic-gate error = 1; 4960Sstevel@tonic-gate bam_error(DUP_OPT, c); 4970Sstevel@tonic-gate } 4980Sstevel@tonic-gate bam_check = 1; 4990Sstevel@tonic-gate break; 5000Sstevel@tonic-gate case 'o': 5010Sstevel@tonic-gate if (bam_opt) { 5020Sstevel@tonic-gate error = 1; 5030Sstevel@tonic-gate bam_error(DUP_OPT, c); 5040Sstevel@tonic-gate } 5050Sstevel@tonic-gate bam_opt = optarg; 5060Sstevel@tonic-gate break; 5070Sstevel@tonic-gate case 'v': 5080Sstevel@tonic-gate if (bam_verbose) { 5090Sstevel@tonic-gate error = 1; 5100Sstevel@tonic-gate bam_error(DUP_OPT, c); 5110Sstevel@tonic-gate } 5120Sstevel@tonic-gate bam_verbose = 1; 5130Sstevel@tonic-gate break; 514662Sszhou case 'C': 515662Sszhou bam_smf_check = 1; 516662Sszhou break; 5170Sstevel@tonic-gate case 'R': 5180Sstevel@tonic-gate if (bam_root) { 5190Sstevel@tonic-gate error = 1; 5200Sstevel@tonic-gate bam_error(DUP_OPT, c); 5210Sstevel@tonic-gate break; 5220Sstevel@tonic-gate } else if (realpath(optarg, rootbuf) == NULL) { 5230Sstevel@tonic-gate error = 1; 5240Sstevel@tonic-gate bam_error(CANT_RESOLVE, optarg, 5250Sstevel@tonic-gate strerror(errno)); 5260Sstevel@tonic-gate break; 5270Sstevel@tonic-gate } 528621Svikram bam_alt_root = 1; 5290Sstevel@tonic-gate bam_root = rootbuf; 5300Sstevel@tonic-gate bam_rootlen = strlen(rootbuf); 5310Sstevel@tonic-gate break; 5326319Sjg case 'p': 5336319Sjg bam_alt_platform = 1; 5346319Sjg bam_platform = optarg; 5356319Sjg if ((strcmp(bam_platform, "i86pc") != 0) && 5366319Sjg (strcmp(bam_platform, "sun4u") != 0) && 5376319Sjg (strcmp(bam_platform, "sun4v") != 0)) { 5386319Sjg error = 1; 5396319Sjg bam_error(INVALID_PLAT, bam_platform); 5406319Sjg } 5416319Sjg break; 5426423Sgw25295 case 'Z': 5436423Sgw25295 bam_zfs = 1; 5446423Sgw25295 break; 5450Sstevel@tonic-gate case '?': 5460Sstevel@tonic-gate error = 1; 5470Sstevel@tonic-gate bam_error(BAD_OPT, optopt); 5480Sstevel@tonic-gate break; 5490Sstevel@tonic-gate default : 5500Sstevel@tonic-gate error = 1; 5510Sstevel@tonic-gate bam_error(BAD_OPT, c); 5520Sstevel@tonic-gate break; 5530Sstevel@tonic-gate } 5540Sstevel@tonic-gate } 5550Sstevel@tonic-gate 5560Sstevel@tonic-gate /* 5576319Sjg * An alternate platform requires an alternate root 5586319Sjg */ 5596319Sjg if (bam_alt_platform && bam_alt_root == 0) { 5606319Sjg usage(); 5616319Sjg bam_exit(0); 5626319Sjg } 5636319Sjg 5646319Sjg /* 5650Sstevel@tonic-gate * A command option must be specfied 5660Sstevel@tonic-gate */ 5670Sstevel@tonic-gate if (!bam_cmd) { 5680Sstevel@tonic-gate if (bam_opt && strcmp(bam_opt, "all") == 0) { 5690Sstevel@tonic-gate usage(); 5700Sstevel@tonic-gate bam_exit(0); 5710Sstevel@tonic-gate } 5720Sstevel@tonic-gate bam_error(NEED_CMD); 5730Sstevel@tonic-gate error = 1; 5740Sstevel@tonic-gate } 5750Sstevel@tonic-gate 5760Sstevel@tonic-gate if (error) { 5770Sstevel@tonic-gate usage(); 5780Sstevel@tonic-gate bam_exit(1); 5790Sstevel@tonic-gate } 5800Sstevel@tonic-gate 5810Sstevel@tonic-gate if (optind > argc) { 5820Sstevel@tonic-gate bam_error(INT_ERROR, "parse_args"); 5830Sstevel@tonic-gate bam_exit(1); 5840Sstevel@tonic-gate } else if (optind < argc) { 5850Sstevel@tonic-gate bam_argv = &argv[optind]; 5860Sstevel@tonic-gate bam_argc = argc - optind; 5870Sstevel@tonic-gate } 5880Sstevel@tonic-gate 5890Sstevel@tonic-gate /* 5900Sstevel@tonic-gate * -n implies verbose mode 5910Sstevel@tonic-gate */ 5920Sstevel@tonic-gate if (bam_check) 5930Sstevel@tonic-gate bam_verbose = 1; 5940Sstevel@tonic-gate } 5950Sstevel@tonic-gate 5960Sstevel@tonic-gate static error_t 5970Sstevel@tonic-gate check_subcmd_and_options( 5980Sstevel@tonic-gate char *subcmd, 5990Sstevel@tonic-gate char *opt, 6000Sstevel@tonic-gate subcmd_defn_t *table, 6010Sstevel@tonic-gate error_t (**fp)()) 6020Sstevel@tonic-gate { 6030Sstevel@tonic-gate int i; 6040Sstevel@tonic-gate 6050Sstevel@tonic-gate if (subcmd == NULL) { 6060Sstevel@tonic-gate bam_error(NEED_SUBCMD); 6070Sstevel@tonic-gate return (BAM_ERROR); 6080Sstevel@tonic-gate } 6090Sstevel@tonic-gate 6106448Svikram if (strcmp(subcmd, "set_option") == 0) { 6116448Svikram if (bam_argc == 0 || bam_argv == NULL || bam_argv[0] == NULL) { 6126448Svikram bam_error(MISSING_ARG); 6136448Svikram usage(); 6146448Svikram return (BAM_ERROR); 6156448Svikram } else if (bam_argc > 1 || bam_argv[1] != NULL) { 6162115Svikram bam_error(TRAILING_ARGS); 6172115Svikram usage(); 6182115Svikram return (BAM_ERROR); 6192115Svikram } 6206448Svikram } else if (bam_argc || bam_argv) { 6216448Svikram bam_error(TRAILING_ARGS); 6226448Svikram usage(); 6236448Svikram return (BAM_ERROR); 6242115Svikram } 6252115Svikram 6260Sstevel@tonic-gate if (bam_root == NULL) { 6270Sstevel@tonic-gate bam_root = rootbuf; 6280Sstevel@tonic-gate bam_rootlen = 1; 6290Sstevel@tonic-gate } 6300Sstevel@tonic-gate 6310Sstevel@tonic-gate /* verify that subcmd is valid */ 6320Sstevel@tonic-gate for (i = 0; table[i].subcmd != NULL; i++) { 6330Sstevel@tonic-gate if (strcmp(table[i].subcmd, subcmd) == 0) 6340Sstevel@tonic-gate break; 6350Sstevel@tonic-gate } 6360Sstevel@tonic-gate 6370Sstevel@tonic-gate if (table[i].subcmd == NULL) { 6380Sstevel@tonic-gate bam_error(INVALID_SUBCMD, subcmd); 6390Sstevel@tonic-gate return (BAM_ERROR); 6400Sstevel@tonic-gate } 6410Sstevel@tonic-gate 6422115Svikram if (table[i].unpriv == 0 && geteuid() != 0) { 6432115Svikram bam_error(MUST_BE_ROOT); 6442115Svikram return (BAM_ERROR); 6452115Svikram } 6462115Svikram 6472115Svikram /* 6482115Svikram * Currently only privileged commands need a lock 6492115Svikram */ 6502115Svikram if (table[i].unpriv == 0) 6512115Svikram bam_lock(); 6522115Svikram 6530Sstevel@tonic-gate /* subcmd verifies that opt is appropriate */ 6540Sstevel@tonic-gate if (table[i].option != OPT_OPTIONAL) { 6550Sstevel@tonic-gate if ((table[i].option == OPT_REQ) ^ (opt != NULL)) { 6560Sstevel@tonic-gate if (opt) 6570Sstevel@tonic-gate bam_error(NO_OPT_REQ, subcmd); 6580Sstevel@tonic-gate else 6590Sstevel@tonic-gate bam_error(MISS_OPT, subcmd); 6600Sstevel@tonic-gate return (BAM_ERROR); 6610Sstevel@tonic-gate } 6620Sstevel@tonic-gate } 6630Sstevel@tonic-gate 6640Sstevel@tonic-gate *fp = table[i].handler; 6650Sstevel@tonic-gate 6660Sstevel@tonic-gate return (BAM_SUCCESS); 6670Sstevel@tonic-gate } 6680Sstevel@tonic-gate 669621Svikram /* 670621Svikram * NOTE: A single "/" is also considered a trailing slash and will 671621Svikram * be deleted. 672621Svikram */ 673621Svikram static void 674621Svikram elide_trailing_slash(const char *src, char *dst, size_t dstsize) 675621Svikram { 676621Svikram size_t dstlen; 677621Svikram 678621Svikram assert(src); 679621Svikram assert(dst); 680621Svikram 681621Svikram (void) strlcpy(dst, src, dstsize); 682621Svikram 683621Svikram dstlen = strlen(dst); 684621Svikram if (dst[dstlen - 1] == '/') { 685621Svikram dst[dstlen - 1] = '\0'; 686621Svikram } 687621Svikram } 688621Svikram 6890Sstevel@tonic-gate static error_t 6900Sstevel@tonic-gate bam_menu(char *subcmd, char *opt, int largc, char *largv[]) 6910Sstevel@tonic-gate { 6926448Svikram error_t ret; 6936448Svikram char menu_path[PATH_MAX]; 6946448Svikram char clean_menu_root[PATH_MAX]; 6956448Svikram char path[PATH_MAX]; 6966448Svikram menu_t *menu; 6976448Svikram char menu_root[PATH_MAX]; 6986448Svikram struct stat sb; 6990Sstevel@tonic-gate error_t (*f)(menu_t *mp, char *menu_path, char *opt); 7006448Svikram char *special; 7016448Svikram char *pool = NULL; 7026448Svikram zfs_mnted_t zmnted; 7036448Svikram char *zmntpt; 7046448Svikram char *osdev; 7056448Svikram char *osroot; 7066448Svikram const char *fcn = "bam_menu()"; 7075648Ssetje 7085648Ssetje /* 7095648Ssetje * Menu sub-command only applies to GRUB (i.e. x86) 7105648Ssetje */ 7116448Svikram if (!is_grub(bam_alt_root ? bam_root : "/")) { 7126448Svikram bam_error(NOT_GRUB_BOOT); 7135648Ssetje return (BAM_ERROR); 7145648Ssetje } 7150Sstevel@tonic-gate 7160Sstevel@tonic-gate /* 7170Sstevel@tonic-gate * Check arguments 7180Sstevel@tonic-gate */ 7190Sstevel@tonic-gate ret = check_subcmd_and_options(subcmd, opt, menu_subcmds, &f); 7200Sstevel@tonic-gate if (ret == BAM_ERROR) { 7210Sstevel@tonic-gate return (BAM_ERROR); 7220Sstevel@tonic-gate } 7230Sstevel@tonic-gate 7246448Svikram assert(bam_root); 7256448Svikram 7266448Svikram (void) strlcpy(menu_root, bam_root, sizeof (menu_root)); 7276448Svikram osdev = osroot = NULL; 7286448Svikram 7296448Svikram if (strcmp(subcmd, "update_entry") == 0) { 7306448Svikram assert(opt); 7316448Svikram 7326448Svikram osdev = strtok(opt, ","); 7336448Svikram assert(osdev); 7346448Svikram osroot = strtok(NULL, ","); 7356448Svikram if (osroot) { 7366448Svikram /* fixup bam_root so that it points at osroot */ 7376448Svikram if (realpath(osroot, rootbuf) == NULL) { 7386448Svikram bam_error(CANT_RESOLVE, osroot, 7396448Svikram strerror(errno)); 7406448Svikram return (BAM_ERROR); 7416448Svikram } 7426448Svikram bam_alt_root = 1; 7436448Svikram bam_root = rootbuf; 7446448Svikram bam_rootlen = strlen(rootbuf); 7456448Svikram } 746621Svikram } 747621Svikram 7486423Sgw25295 /* 7496448Svikram * We support menu on PCFS (under certain conditions), but 7506448Svikram * not the OS root 7516423Sgw25295 */ 7526448Svikram if (is_pcfs(bam_root)) { 7536448Svikram bam_error(PCFS_ROOT_NOTSUP, bam_root); 7546448Svikram return (BAM_ERROR); 7556448Svikram } 7566448Svikram 7576448Svikram if (stat(menu_root, &sb) == -1) { 7586448Svikram bam_error(CANNOT_LOCATE_GRUB_MENU); 7596448Svikram return (BAM_ERROR); 7606448Svikram } 7616448Svikram 7626448Svikram BAM_DPRINTF((D_MENU_ROOT, fcn, menu_root)); 7636423Sgw25295 7646423Sgw25295 /* 7656448Svikram * We no longer use the GRUB slice file. If it exists, then 7666448Svikram * the user is doing something that is unsupported (such as 7676448Svikram * standard upgrading an old Live Upgrade BE). If that 7686448Svikram * happens, mimic existing behavior i.e. pretend that it is 7696448Svikram * not a BE. Emit a warning though. 7706423Sgw25295 */ 7716448Svikram if (bam_alt_root) { 7726448Svikram (void) snprintf(path, sizeof (path), "%s%s", bam_root, 7736448Svikram GRUB_slice); 7746448Svikram } else { 7756448Svikram (void) snprintf(path, sizeof (path), "%s", GRUB_slice); 7766448Svikram } 7776448Svikram 7786448Svikram if (stat(path, &sb) == 0) 7796448Svikram bam_error(GRUB_SLICE_FILE_EXISTS, path); 7806448Svikram 7816448Svikram if (is_zfs(menu_root)) { 7826448Svikram assert(strcmp(menu_root, bam_root) == 0); 7836448Svikram special = get_special(menu_root); 7846448Svikram INJECT_ERROR1("Z_MENU_GET_SPECIAL", special = NULL); 7856448Svikram if (special == NULL) { 7866448Svikram bam_error(CANT_FIND_SPECIAL, menu_root); 7876448Svikram return (BAM_ERROR); 7886448Svikram } 7896448Svikram pool = strtok(special, "/"); 7906448Svikram INJECT_ERROR1("Z_MENU_GET_POOL", pool = NULL); 7916448Svikram if (pool == NULL) { 7926448Svikram free(special); 7936448Svikram bam_error(CANT_FIND_POOL, menu_root); 7946448Svikram return (BAM_ERROR); 7956448Svikram } 7966448Svikram BAM_DPRINTF((D_Z_MENU_GET_POOL_FROM_SPECIAL, fcn, pool)); 7976448Svikram 7986448Svikram zmntpt = mount_top_dataset(pool, &zmnted); 7996448Svikram INJECT_ERROR1("Z_MENU_MOUNT_TOP_DATASET", zmntpt = NULL); 8006448Svikram if (zmntpt == NULL) { 8016448Svikram bam_error(CANT_MOUNT_POOL_DATASET, pool); 8026448Svikram free(special); 8036448Svikram return (BAM_ERROR); 8046448Svikram } 8056448Svikram BAM_DPRINTF((D_Z_GET_MENU_MOUNT_TOP_DATASET, fcn, zmntpt)); 8066448Svikram 8076448Svikram (void) strlcpy(menu_root, zmntpt, sizeof (menu_root)); 8086448Svikram BAM_DPRINTF((D_Z_GET_MENU_MENU_ROOT, fcn, menu_root)); 8096448Svikram } 8106448Svikram 8116448Svikram elide_trailing_slash(menu_root, clean_menu_root, 8126448Svikram sizeof (clean_menu_root)); 8136448Svikram 8146448Svikram BAM_DPRINTF((D_CLEAN_MENU_ROOT, fcn, clean_menu_root)); 8156448Svikram 8166448Svikram (void) strlcpy(menu_path, clean_menu_root, sizeof (menu_path)); 817621Svikram (void) strlcat(menu_path, GRUB_MENU, sizeof (menu_path)); 818621Svikram 8196448Svikram BAM_DPRINTF((D_MENU_PATH, fcn, menu_path)); 8206448Svikram 821621Svikram /* 8226448Svikram * If listing the menu, display the menu location 823621Svikram */ 824621Svikram if (strcmp(subcmd, "list_entry") == 0) { 8256448Svikram bam_print(GRUB_MENU_PATH, menu_path); 8266448Svikram } 8276448Svikram 8280Sstevel@tonic-gate 8290Sstevel@tonic-gate menu = menu_read(menu_path); 8300Sstevel@tonic-gate assert(menu); 8310Sstevel@tonic-gate 8320Sstevel@tonic-gate /* 8336448Svikram * We already checked the following case in 8346448Svikram * check_subcmd_and_suboptions() above. Complete the 8356448Svikram * final step now. 8360Sstevel@tonic-gate */ 8370Sstevel@tonic-gate if (strcmp(subcmd, "set_option") == 0) { 8386448Svikram assert(largc == 1 && largv[0] && largv[1] == NULL); 8390Sstevel@tonic-gate opt = largv[0]; 8406448Svikram } else { 8416448Svikram assert(largc == 0 && largv == NULL); 8426448Svikram } 8436448Svikram 8446448Svikram ret = get_boot_cap(bam_root); 8456448Svikram if (ret != BAM_SUCCESS) { 8466448Svikram BAM_DPRINTF((D_BOOT_GET_CAP_FAILED, fcn)); 8476448Svikram goto out; 8486448Svikram } 8493446Smrj 8500Sstevel@tonic-gate /* 8510Sstevel@tonic-gate * Once the sub-cmd handler has run 8520Sstevel@tonic-gate * only the line field is guaranteed to have valid values 8530Sstevel@tonic-gate */ 8546448Svikram if (strcmp(subcmd, "update_entry") == 0) 8556448Svikram ret = f(menu, menu_root, osdev); 8566448Svikram else if (strcmp(subcmd, "upgrade") == 0) 8576448Svikram ret = f(menu, bam_root, menu_root); 8586448Svikram else if (strcmp(subcmd, "list_entry") == 0) 8596448Svikram ret = f(menu, menu_path, opt); 8600Sstevel@tonic-gate else 8616448Svikram ret = f(menu, NULL, opt); 8626448Svikram 8630Sstevel@tonic-gate if (ret == BAM_WRITE) { 8646448Svikram BAM_DPRINTF((D_WRITING_MENU_ROOT, fcn, clean_menu_root)); 8656448Svikram ret = menu_write(clean_menu_root, menu); 8666448Svikram } 8676448Svikram 8686448Svikram out: 8696448Svikram INJECT_ERROR1("POOL_SET", pool = "/pooldata"); 8706448Svikram assert((is_zfs(menu_root)) ^ (pool == NULL)); 8716448Svikram if (pool) { 8726448Svikram (void) umount_top_dataset(pool, zmnted, zmntpt); 8736448Svikram free(special); 8746448Svikram } 8750Sstevel@tonic-gate menu_free(menu); 8760Sstevel@tonic-gate return (ret); 8770Sstevel@tonic-gate } 8780Sstevel@tonic-gate 8790Sstevel@tonic-gate 8800Sstevel@tonic-gate static error_t 8810Sstevel@tonic-gate bam_archive( 8820Sstevel@tonic-gate char *subcmd, 8830Sstevel@tonic-gate char *opt) 8840Sstevel@tonic-gate { 8856448Svikram error_t ret; 8866448Svikram error_t (*f)(char *root, char *opt); 8876448Svikram const char *fcn = "bam_archive()"; 8880Sstevel@tonic-gate 8890Sstevel@tonic-gate /* 890662Sszhou * Add trailing / for archive subcommands 891662Sszhou */ 892662Sszhou if (rootbuf[strlen(rootbuf) - 1] != '/') 893662Sszhou (void) strcat(rootbuf, "/"); 894662Sszhou bam_rootlen = strlen(rootbuf); 895662Sszhou 896662Sszhou /* 8970Sstevel@tonic-gate * Check arguments 8980Sstevel@tonic-gate */ 8990Sstevel@tonic-gate ret = check_subcmd_and_options(subcmd, opt, arch_subcmds, &f); 9000Sstevel@tonic-gate if (ret != BAM_SUCCESS) { 9010Sstevel@tonic-gate return (BAM_ERROR); 9020Sstevel@tonic-gate } 9030Sstevel@tonic-gate 9046448Svikram ret = get_boot_cap(rootbuf); 9056448Svikram if (ret != BAM_SUCCESS) { 9066448Svikram BAM_DPRINTF((D_BOOT_GET_CAP_FAILED, fcn)); 9073446Smrj return (ret); 9086448Svikram } 9093446Smrj 9100Sstevel@tonic-gate /* 9110Sstevel@tonic-gate * Check archive not supported with update_all 9120Sstevel@tonic-gate * since it is awkward to display out-of-sync 9130Sstevel@tonic-gate * information for each BE. 9140Sstevel@tonic-gate */ 9150Sstevel@tonic-gate if (bam_check && strcmp(subcmd, "update_all") == 0) { 9160Sstevel@tonic-gate bam_error(CHECK_NOT_SUPPORTED, subcmd); 9170Sstevel@tonic-gate return (BAM_ERROR); 9180Sstevel@tonic-gate } 9190Sstevel@tonic-gate 920316Svikram if (strcmp(subcmd, "update_all") == 0) 921316Svikram bam_update_all = 1; 922316Svikram 9235648Ssetje #if !defined(_OPB) 9244581Ssherrym ucode_install(bam_root); 9254581Ssherrym #endif 9264581Ssherrym 927316Svikram ret = f(bam_root, opt); 928316Svikram 929316Svikram bam_update_all = 0; 930316Svikram 931316Svikram return (ret); 9320Sstevel@tonic-gate } 9330Sstevel@tonic-gate 9340Sstevel@tonic-gate /*PRINTFLIKE1*/ 9353446Smrj void 9360Sstevel@tonic-gate bam_error(char *format, ...) 9370Sstevel@tonic-gate { 9380Sstevel@tonic-gate va_list ap; 9390Sstevel@tonic-gate 9400Sstevel@tonic-gate va_start(ap, format); 9410Sstevel@tonic-gate (void) fprintf(stderr, "%s: ", prog); 9420Sstevel@tonic-gate (void) vfprintf(stderr, format, ap); 9430Sstevel@tonic-gate va_end(ap); 9440Sstevel@tonic-gate } 9450Sstevel@tonic-gate 9460Sstevel@tonic-gate /*PRINTFLIKE1*/ 9476448Svikram void 9486448Svikram bam_derror(char *format, ...) 9496448Svikram { 9506448Svikram va_list ap; 9516448Svikram 9526448Svikram assert(bam_debug); 9536448Svikram 9546448Svikram va_start(ap, format); 9556448Svikram (void) fprintf(stderr, "DEBUG: "); 9566448Svikram (void) vfprintf(stderr, format, ap); 9576448Svikram va_end(ap); 9586448Svikram } 9596448Svikram 9606448Svikram /*PRINTFLIKE1*/ 9616448Svikram void 9620Sstevel@tonic-gate bam_print(char *format, ...) 9630Sstevel@tonic-gate { 9640Sstevel@tonic-gate va_list ap; 9650Sstevel@tonic-gate 9660Sstevel@tonic-gate va_start(ap, format); 9670Sstevel@tonic-gate (void) vfprintf(stdout, format, ap); 9680Sstevel@tonic-gate va_end(ap); 9690Sstevel@tonic-gate } 9700Sstevel@tonic-gate 9713446Smrj /*PRINTFLIKE1*/ 9723446Smrj void 9733446Smrj bam_print_stderr(char *format, ...) 9743446Smrj { 9753446Smrj va_list ap; 9763446Smrj 9773446Smrj va_start(ap, format); 9783446Smrj (void) vfprintf(stderr, format, ap); 9793446Smrj va_end(ap); 9803446Smrj } 9813446Smrj 9820Sstevel@tonic-gate static void 9830Sstevel@tonic-gate bam_exit(int excode) 9840Sstevel@tonic-gate { 9850Sstevel@tonic-gate bam_unlock(); 9860Sstevel@tonic-gate exit(excode); 9870Sstevel@tonic-gate } 9880Sstevel@tonic-gate 9890Sstevel@tonic-gate static void 9900Sstevel@tonic-gate bam_lock(void) 9910Sstevel@tonic-gate { 9920Sstevel@tonic-gate struct flock lock; 9930Sstevel@tonic-gate pid_t pid; 9940Sstevel@tonic-gate 9950Sstevel@tonic-gate bam_lock_fd = open(BAM_LOCK_FILE, O_CREAT|O_RDWR, LOCK_FILE_PERMS); 9960Sstevel@tonic-gate if (bam_lock_fd < 0) { 9970Sstevel@tonic-gate /* 9980Sstevel@tonic-gate * We may be invoked early in boot for archive verification. 9990Sstevel@tonic-gate * In this case, root is readonly and /var/run may not exist. 10000Sstevel@tonic-gate * Proceed without the lock 10010Sstevel@tonic-gate */ 10020Sstevel@tonic-gate if (errno == EROFS || errno == ENOENT) { 10030Sstevel@tonic-gate bam_root_readonly = 1; 10040Sstevel@tonic-gate return; 10050Sstevel@tonic-gate } 10060Sstevel@tonic-gate 10070Sstevel@tonic-gate bam_error(OPEN_FAIL, BAM_LOCK_FILE, strerror(errno)); 10080Sstevel@tonic-gate bam_exit(1); 10090Sstevel@tonic-gate } 10100Sstevel@tonic-gate 10110Sstevel@tonic-gate lock.l_type = F_WRLCK; 10120Sstevel@tonic-gate lock.l_whence = SEEK_SET; 10130Sstevel@tonic-gate lock.l_start = 0; 10140Sstevel@tonic-gate lock.l_len = 0; 10150Sstevel@tonic-gate 10160Sstevel@tonic-gate if (fcntl(bam_lock_fd, F_SETLK, &lock) == -1) { 10170Sstevel@tonic-gate if (errno != EACCES && errno != EAGAIN) { 10180Sstevel@tonic-gate bam_error(LOCK_FAIL, BAM_LOCK_FILE, strerror(errno)); 10190Sstevel@tonic-gate (void) close(bam_lock_fd); 10200Sstevel@tonic-gate bam_lock_fd = -1; 10210Sstevel@tonic-gate bam_exit(1); 10220Sstevel@tonic-gate } 10230Sstevel@tonic-gate pid = 0; 10240Sstevel@tonic-gate (void) pread(bam_lock_fd, &pid, sizeof (pid_t), 0); 10250Sstevel@tonic-gate bam_print(FILE_LOCKED, pid); 10260Sstevel@tonic-gate 10270Sstevel@tonic-gate lock.l_type = F_WRLCK; 10280Sstevel@tonic-gate lock.l_whence = SEEK_SET; 10290Sstevel@tonic-gate lock.l_start = 0; 10300Sstevel@tonic-gate lock.l_len = 0; 10310Sstevel@tonic-gate if (fcntl(bam_lock_fd, F_SETLKW, &lock) == -1) { 10320Sstevel@tonic-gate bam_error(LOCK_FAIL, BAM_LOCK_FILE, strerror(errno)); 10330Sstevel@tonic-gate (void) close(bam_lock_fd); 10340Sstevel@tonic-gate bam_lock_fd = -1; 10350Sstevel@tonic-gate bam_exit(1); 10360Sstevel@tonic-gate } 10370Sstevel@tonic-gate } 10380Sstevel@tonic-gate 10390Sstevel@tonic-gate /* We own the lock now */ 10400Sstevel@tonic-gate pid = getpid(); 10410Sstevel@tonic-gate (void) write(bam_lock_fd, &pid, sizeof (pid)); 10420Sstevel@tonic-gate } 10430Sstevel@tonic-gate 10440Sstevel@tonic-gate static void 10450Sstevel@tonic-gate bam_unlock(void) 10460Sstevel@tonic-gate { 10470Sstevel@tonic-gate struct flock unlock; 10480Sstevel@tonic-gate 10490Sstevel@tonic-gate /* 10500Sstevel@tonic-gate * NOP if we don't hold the lock 10510Sstevel@tonic-gate */ 10520Sstevel@tonic-gate if (bam_lock_fd < 0) { 10530Sstevel@tonic-gate return; 10540Sstevel@tonic-gate } 10550Sstevel@tonic-gate 10560Sstevel@tonic-gate unlock.l_type = F_UNLCK; 10570Sstevel@tonic-gate unlock.l_whence = SEEK_SET; 10580Sstevel@tonic-gate unlock.l_start = 0; 10590Sstevel@tonic-gate unlock.l_len = 0; 10600Sstevel@tonic-gate 10610Sstevel@tonic-gate if (fcntl(bam_lock_fd, F_SETLK, &unlock) == -1) { 10620Sstevel@tonic-gate bam_error(UNLOCK_FAIL, BAM_LOCK_FILE, strerror(errno)); 10630Sstevel@tonic-gate } 10640Sstevel@tonic-gate 10650Sstevel@tonic-gate if (close(bam_lock_fd) == -1) { 10660Sstevel@tonic-gate bam_error(CLOSE_FAIL, BAM_LOCK_FILE, strerror(errno)); 10670Sstevel@tonic-gate } 10680Sstevel@tonic-gate bam_lock_fd = -1; 10690Sstevel@tonic-gate } 10700Sstevel@tonic-gate 10710Sstevel@tonic-gate static error_t 10720Sstevel@tonic-gate list_archive(char *root, char *opt) 10730Sstevel@tonic-gate { 10740Sstevel@tonic-gate filelist_t flist; 10750Sstevel@tonic-gate filelist_t *flistp = &flist; 10760Sstevel@tonic-gate line_t *lp; 10770Sstevel@tonic-gate 10780Sstevel@tonic-gate assert(root); 10790Sstevel@tonic-gate assert(opt == NULL); 10800Sstevel@tonic-gate 10810Sstevel@tonic-gate flistp->head = flistp->tail = NULL; 10820Sstevel@tonic-gate if (read_list(root, flistp) != BAM_SUCCESS) { 10830Sstevel@tonic-gate return (BAM_ERROR); 10840Sstevel@tonic-gate } 10850Sstevel@tonic-gate assert(flistp->head && flistp->tail); 10860Sstevel@tonic-gate 10870Sstevel@tonic-gate for (lp = flistp->head; lp; lp = lp->next) { 10880Sstevel@tonic-gate bam_print(PRINT, lp->line); 10890Sstevel@tonic-gate } 10900Sstevel@tonic-gate 10910Sstevel@tonic-gate filelist_free(flistp); 10920Sstevel@tonic-gate 10930Sstevel@tonic-gate return (BAM_SUCCESS); 10940Sstevel@tonic-gate } 10950Sstevel@tonic-gate 10960Sstevel@tonic-gate /* 10970Sstevel@tonic-gate * This routine writes a list of lines to a file. 10980Sstevel@tonic-gate * The list is *not* freed 10990Sstevel@tonic-gate */ 11000Sstevel@tonic-gate static error_t 11010Sstevel@tonic-gate list2file(char *root, char *tmp, char *final, line_t *start) 11020Sstevel@tonic-gate { 11036448Svikram char tmpfile[PATH_MAX]; 11046448Svikram char path[PATH_MAX]; 11056448Svikram FILE *fp; 11066448Svikram int ret; 11076448Svikram struct stat sb; 11086448Svikram mode_t mode; 11096448Svikram uid_t root_uid; 11106448Svikram gid_t sys_gid; 11116448Svikram struct passwd *pw; 11126448Svikram struct group *gp; 11136448Svikram const char *fcn = "list2file()"; 11140Sstevel@tonic-gate 11150Sstevel@tonic-gate (void) snprintf(path, sizeof (path), "%s%s", root, final); 11160Sstevel@tonic-gate 11170Sstevel@tonic-gate if (start == NULL) { 11186448Svikram /* Empty GRUB menu */ 11190Sstevel@tonic-gate if (stat(path, &sb) != -1) { 11200Sstevel@tonic-gate bam_print(UNLINK_EMPTY, path); 11210Sstevel@tonic-gate if (unlink(path) != 0) { 11220Sstevel@tonic-gate bam_error(UNLINK_FAIL, path, strerror(errno)); 11230Sstevel@tonic-gate return (BAM_ERROR); 11240Sstevel@tonic-gate } else { 11250Sstevel@tonic-gate return (BAM_SUCCESS); 11260Sstevel@tonic-gate } 11270Sstevel@tonic-gate } 11286448Svikram return (BAM_SUCCESS); 11290Sstevel@tonic-gate } 11300Sstevel@tonic-gate 11310Sstevel@tonic-gate /* 11320Sstevel@tonic-gate * Preserve attributes of existing file if possible, 11330Sstevel@tonic-gate * otherwise ask the system for uid/gid of root/sys. 11340Sstevel@tonic-gate * If all fails, fall back on hard-coded defaults. 11350Sstevel@tonic-gate */ 11360Sstevel@tonic-gate if (stat(path, &sb) != -1) { 11370Sstevel@tonic-gate mode = sb.st_mode; 11380Sstevel@tonic-gate root_uid = sb.st_uid; 11390Sstevel@tonic-gate sys_gid = sb.st_gid; 11400Sstevel@tonic-gate } else { 11410Sstevel@tonic-gate mode = DEFAULT_DEV_MODE; 11420Sstevel@tonic-gate if ((pw = getpwnam(DEFAULT_DEV_USER)) != NULL) { 11430Sstevel@tonic-gate root_uid = pw->pw_uid; 11440Sstevel@tonic-gate } else { 11456448Svikram bam_error(CANT_FIND_USER, 11466448Svikram DEFAULT_DEV_USER, DEFAULT_DEV_UID); 11470Sstevel@tonic-gate root_uid = (uid_t)DEFAULT_DEV_UID; 11480Sstevel@tonic-gate } 11490Sstevel@tonic-gate if ((gp = getgrnam(DEFAULT_DEV_GROUP)) != NULL) { 11500Sstevel@tonic-gate sys_gid = gp->gr_gid; 11510Sstevel@tonic-gate } else { 11526448Svikram bam_error(CANT_FIND_GROUP, 11536448Svikram DEFAULT_DEV_GROUP, DEFAULT_DEV_GID); 11540Sstevel@tonic-gate sys_gid = (gid_t)DEFAULT_DEV_GID; 11550Sstevel@tonic-gate } 11560Sstevel@tonic-gate } 11570Sstevel@tonic-gate 11580Sstevel@tonic-gate (void) snprintf(tmpfile, sizeof (tmpfile), "%s%s", root, tmp); 11590Sstevel@tonic-gate 11600Sstevel@tonic-gate /* Truncate tmpfile first */ 11610Sstevel@tonic-gate fp = fopen(tmpfile, "w"); 11620Sstevel@tonic-gate if (fp == NULL) { 11630Sstevel@tonic-gate bam_error(OPEN_FAIL, tmpfile, strerror(errno)); 11640Sstevel@tonic-gate return (BAM_ERROR); 11650Sstevel@tonic-gate } 11666694Svikram ret = fclose(fp); 11676694Svikram INJECT_ERROR1("LIST2FILE_TRUNC_FCLOSE", ret = EOF); 11686694Svikram if (ret == EOF) { 11690Sstevel@tonic-gate bam_error(CLOSE_FAIL, tmpfile, strerror(errno)); 11700Sstevel@tonic-gate return (BAM_ERROR); 11710Sstevel@tonic-gate } 11720Sstevel@tonic-gate 11730Sstevel@tonic-gate /* Now open it in append mode */ 11740Sstevel@tonic-gate fp = fopen(tmpfile, "a"); 11750Sstevel@tonic-gate if (fp == NULL) { 11760Sstevel@tonic-gate bam_error(OPEN_FAIL, tmpfile, strerror(errno)); 11770Sstevel@tonic-gate return (BAM_ERROR); 11780Sstevel@tonic-gate } 11790Sstevel@tonic-gate 11800Sstevel@tonic-gate for (; start; start = start->next) { 11816694Svikram ret = s_fputs(start->line, fp); 11826694Svikram INJECT_ERROR1("LIST2FILE_FPUTS", ret = EOF); 11836694Svikram if (ret == EOF) { 11840Sstevel@tonic-gate bam_error(WRITE_FAIL, tmpfile, strerror(errno)); 11850Sstevel@tonic-gate (void) fclose(fp); 11860Sstevel@tonic-gate return (BAM_ERROR); 11870Sstevel@tonic-gate } 11880Sstevel@tonic-gate } 11890Sstevel@tonic-gate 11906694Svikram ret = fclose(fp); 11916694Svikram INJECT_ERROR1("LIST2FILE_APPEND_FCLOSE", ret = EOF); 11926694Svikram if (ret == EOF) { 11930Sstevel@tonic-gate bam_error(CLOSE_FAIL, tmpfile, strerror(errno)); 11940Sstevel@tonic-gate return (BAM_ERROR); 11950Sstevel@tonic-gate } 11960Sstevel@tonic-gate 11970Sstevel@tonic-gate /* 1198271Sjg * Set up desired attributes. Ignore failures on filesystems 1199271Sjg * not supporting these operations - pcfs reports unsupported 1200271Sjg * operations as EINVAL. 12010Sstevel@tonic-gate */ 12020Sstevel@tonic-gate ret = chmod(tmpfile, mode); 1203271Sjg if (ret == -1 && 1204271Sjg errno != EINVAL && errno != ENOTSUP) { 12050Sstevel@tonic-gate bam_error(CHMOD_FAIL, tmpfile, strerror(errno)); 12060Sstevel@tonic-gate return (BAM_ERROR); 12070Sstevel@tonic-gate } 12080Sstevel@tonic-gate 12090Sstevel@tonic-gate ret = chown(tmpfile, root_uid, sys_gid); 1210271Sjg if (ret == -1 && 1211271Sjg errno != EINVAL && errno != ENOTSUP) { 12120Sstevel@tonic-gate bam_error(CHOWN_FAIL, tmpfile, strerror(errno)); 12130Sstevel@tonic-gate return (BAM_ERROR); 12140Sstevel@tonic-gate } 12150Sstevel@tonic-gate 12160Sstevel@tonic-gate 12170Sstevel@tonic-gate /* 12180Sstevel@tonic-gate * Do an atomic rename 12190Sstevel@tonic-gate */ 12200Sstevel@tonic-gate ret = rename(tmpfile, path); 12216694Svikram INJECT_ERROR1("LIST2FILE_RENAME", ret = -1); 12220Sstevel@tonic-gate if (ret != 0) { 12230Sstevel@tonic-gate bam_error(RENAME_FAIL, path, strerror(errno)); 12240Sstevel@tonic-gate return (BAM_ERROR); 12250Sstevel@tonic-gate } 12260Sstevel@tonic-gate 12276448Svikram BAM_DPRINTF((D_WROTE_FILE, fcn, path)); 12280Sstevel@tonic-gate return (BAM_SUCCESS); 12290Sstevel@tonic-gate } 12300Sstevel@tonic-gate 12310Sstevel@tonic-gate /* 12320Sstevel@tonic-gate * This function should always return 0 - since we want 12330Sstevel@tonic-gate * to create stat data for *all* files in the list. 12340Sstevel@tonic-gate */ 12350Sstevel@tonic-gate /*ARGSUSED*/ 12360Sstevel@tonic-gate static int 12370Sstevel@tonic-gate cmpstat( 12380Sstevel@tonic-gate const char *file, 12390Sstevel@tonic-gate const struct stat *stat, 12400Sstevel@tonic-gate int flags, 12410Sstevel@tonic-gate struct FTW *ftw) 12420Sstevel@tonic-gate { 12430Sstevel@tonic-gate uint_t sz; 12440Sstevel@tonic-gate uint64_t *value; 12450Sstevel@tonic-gate uint64_t filestat[2]; 12460Sstevel@tonic-gate int error; 12470Sstevel@tonic-gate 12482334Ssetje struct safefile *safefilep; 12492334Ssetje FILE *fp; 12502334Ssetje 12510Sstevel@tonic-gate /* 12520Sstevel@tonic-gate * We only want regular files 12530Sstevel@tonic-gate */ 12540Sstevel@tonic-gate if (!S_ISREG(stat->st_mode)) 12550Sstevel@tonic-gate return (0); 12560Sstevel@tonic-gate 12570Sstevel@tonic-gate /* 12580Sstevel@tonic-gate * new_nvlp may be NULL if there were errors earlier 12590Sstevel@tonic-gate * but this is not fatal to update determination. 12600Sstevel@tonic-gate */ 12610Sstevel@tonic-gate if (walk_arg.new_nvlp) { 12620Sstevel@tonic-gate filestat[0] = stat->st_size; 12630Sstevel@tonic-gate filestat[1] = stat->st_mtime; 12640Sstevel@tonic-gate error = nvlist_add_uint64_array(walk_arg.new_nvlp, 12650Sstevel@tonic-gate file + bam_rootlen, filestat, 2); 12660Sstevel@tonic-gate if (error) 12670Sstevel@tonic-gate bam_error(NVADD_FAIL, file, strerror(error)); 12680Sstevel@tonic-gate } 12690Sstevel@tonic-gate 12700Sstevel@tonic-gate /* 12710Sstevel@tonic-gate * The remaining steps are only required if we haven't made a 12720Sstevel@tonic-gate * decision about update or if we are checking (-n) 12730Sstevel@tonic-gate */ 12740Sstevel@tonic-gate if (walk_arg.need_update && !bam_check) 12750Sstevel@tonic-gate return (0); 12760Sstevel@tonic-gate 12770Sstevel@tonic-gate /* 12786319Sjg * If we are invoked as part of system/filesystem/boot-archive, then 12792334Ssetje * there are a number of things we should not worry about 12800Sstevel@tonic-gate */ 12812334Ssetje if (bam_smf_check) { 12822334Ssetje /* ignore amd64 modules unless we are booted amd64. */ 12832334Ssetje if (!is_amd64() && strstr(file, "/amd64/") != 0) 12842334Ssetje return (0); 12852334Ssetje 12862334Ssetje /* read in list of safe files */ 12872334Ssetje if (safefiles == NULL) 12882334Ssetje if (fp = fopen("/boot/solaris/filelist.safe", "r")) { 12892334Ssetje safefiles = s_calloc(1, 12902334Ssetje sizeof (struct safefile)); 12912334Ssetje safefilep = safefiles; 12922334Ssetje safefilep->name = s_calloc(1, MAXPATHLEN + 12932334Ssetje MAXNAMELEN); 12942334Ssetje safefilep->next = NULL; 12952334Ssetje while (s_fgets(safefilep->name, MAXPATHLEN + 12962334Ssetje MAXNAMELEN, fp) != NULL) { 12972334Ssetje safefilep->next = s_calloc(1, 12982334Ssetje sizeof (struct safefile)); 12992334Ssetje safefilep = safefilep->next; 13002334Ssetje safefilep->name = s_calloc(1, 13012334Ssetje MAXPATHLEN + MAXNAMELEN); 13022334Ssetje safefilep->next = NULL; 13032334Ssetje } 13042334Ssetje (void) fclose(fp); 13052334Ssetje } 13062334Ssetje } 13070Sstevel@tonic-gate 13080Sstevel@tonic-gate /* 13090Sstevel@tonic-gate * We need an update if file doesn't exist in old archive 13100Sstevel@tonic-gate */ 13110Sstevel@tonic-gate if (walk_arg.old_nvlp == NULL || 13120Sstevel@tonic-gate nvlist_lookup_uint64_array(walk_arg.old_nvlp, 13130Sstevel@tonic-gate file + bam_rootlen, &value, &sz) != 0) { 13140Sstevel@tonic-gate if (bam_smf_check) /* ignore new during smf check */ 13150Sstevel@tonic-gate return (0); 13160Sstevel@tonic-gate walk_arg.need_update = 1; 13170Sstevel@tonic-gate if (bam_verbose) 13180Sstevel@tonic-gate bam_print(PARSEABLE_NEW_FILE, file); 13190Sstevel@tonic-gate return (0); 13200Sstevel@tonic-gate } 13210Sstevel@tonic-gate 13220Sstevel@tonic-gate /* 13230Sstevel@tonic-gate * File exists in old archive. Check if file has changed 13240Sstevel@tonic-gate */ 13250Sstevel@tonic-gate assert(sz == 2); 13260Sstevel@tonic-gate bcopy(value, filestat, sizeof (filestat)); 13270Sstevel@tonic-gate 13280Sstevel@tonic-gate if (filestat[0] != stat->st_size || 13290Sstevel@tonic-gate filestat[1] != stat->st_mtime) { 13303615Ssetje if (bam_smf_check) { 13313615Ssetje safefilep = safefiles; 13323615Ssetje while (safefilep != NULL) { 13333615Ssetje if (strcmp(file + bam_rootlen, 13343615Ssetje safefilep->name) == 0) { 13353615Ssetje (void) creat(NEED_UPDATE_FILE, 0644); 13363615Ssetje return (0); 13373615Ssetje } 13383615Ssetje safefilep = safefilep->next; 13393615Ssetje } 13403615Ssetje } 13410Sstevel@tonic-gate walk_arg.need_update = 1; 13420Sstevel@tonic-gate if (bam_verbose) 13430Sstevel@tonic-gate if (bam_smf_check) 13440Sstevel@tonic-gate bam_print(" %s\n", file); 13450Sstevel@tonic-gate else 13460Sstevel@tonic-gate bam_print(PARSEABLE_OUT_DATE, file); 13470Sstevel@tonic-gate } 13480Sstevel@tonic-gate 13490Sstevel@tonic-gate return (0); 13500Sstevel@tonic-gate } 13510Sstevel@tonic-gate 13520Sstevel@tonic-gate /* 13530Sstevel@tonic-gate * Check flags and presence of required files. 13540Sstevel@tonic-gate * The force flag and/or absence of files should 13550Sstevel@tonic-gate * trigger an update. 13560Sstevel@tonic-gate * Suppress stdout output if check (-n) option is set 13570Sstevel@tonic-gate * (as -n should only produce parseable output.) 13580Sstevel@tonic-gate */ 13590Sstevel@tonic-gate static void 13600Sstevel@tonic-gate check_flags_and_files(char *root) 13610Sstevel@tonic-gate { 13620Sstevel@tonic-gate char path[PATH_MAX]; 13630Sstevel@tonic-gate struct stat sb; 13640Sstevel@tonic-gate 13650Sstevel@tonic-gate /* 13660Sstevel@tonic-gate * if force, create archive unconditionally 13670Sstevel@tonic-gate */ 13680Sstevel@tonic-gate if (bam_force) { 13690Sstevel@tonic-gate walk_arg.need_update = 1; 13700Sstevel@tonic-gate if (bam_verbose && !bam_check) 13710Sstevel@tonic-gate bam_print(UPDATE_FORCE); 13720Sstevel@tonic-gate return; 13730Sstevel@tonic-gate } 13740Sstevel@tonic-gate 13750Sstevel@tonic-gate /* 13760Sstevel@tonic-gate * If archive is missing, create archive 13770Sstevel@tonic-gate */ 13786582Ssetje if (is_sparc()) { 13796582Ssetje (void) snprintf(path, sizeof (path), "%s%s%s%s", root, 13806582Ssetje ARCHIVE_PREFIX, get_machine(), ARCHIVE_SUFFIX); 13816319Sjg } else { 13825648Ssetje if (bam_direct == BAM_DIRECT_DBOOT) { 13835648Ssetje (void) snprintf(path, sizeof (path), "%s%s", root, 13845648Ssetje DIRECT_BOOT_ARCHIVE_64); 13855648Ssetje if (stat(path, &sb) != 0) { 13865648Ssetje if (bam_verbose && !bam_check) 13875648Ssetje bam_print(UPDATE_ARCH_MISS, path); 13885648Ssetje walk_arg.need_update = 1; 13895648Ssetje return; 13905648Ssetje } 13915648Ssetje } 13925648Ssetje (void) snprintf(path, sizeof (path), "%s%s", root, 13935648Ssetje DIRECT_BOOT_ARCHIVE_32); 13945648Ssetje } 13955648Ssetje 13960Sstevel@tonic-gate if (stat(path, &sb) != 0) { 13970Sstevel@tonic-gate if (bam_verbose && !bam_check) 13980Sstevel@tonic-gate bam_print(UPDATE_ARCH_MISS, path); 13990Sstevel@tonic-gate walk_arg.need_update = 1; 14000Sstevel@tonic-gate return; 14010Sstevel@tonic-gate } 14020Sstevel@tonic-gate } 14030Sstevel@tonic-gate 14040Sstevel@tonic-gate static error_t 14050Sstevel@tonic-gate read_one_list(char *root, filelist_t *flistp, char *filelist) 14060Sstevel@tonic-gate { 14070Sstevel@tonic-gate char path[PATH_MAX]; 14080Sstevel@tonic-gate FILE *fp; 14090Sstevel@tonic-gate char buf[BAM_MAXLINE]; 14106448Svikram const char *fcn = "read_one_list()"; 14110Sstevel@tonic-gate 14120Sstevel@tonic-gate (void) snprintf(path, sizeof (path), "%s%s", root, filelist); 14130Sstevel@tonic-gate 14140Sstevel@tonic-gate fp = fopen(path, "r"); 14150Sstevel@tonic-gate if (fp == NULL) { 14166448Svikram BAM_DPRINTF((D_FLIST_FAIL, fcn, path, strerror(errno))); 14170Sstevel@tonic-gate return (BAM_ERROR); 14180Sstevel@tonic-gate } 14190Sstevel@tonic-gate while (s_fgets(buf, sizeof (buf), fp) != NULL) { 1420316Svikram /* skip blank lines */ 1421316Svikram if (strspn(buf, " \t") == strlen(buf)) 1422316Svikram continue; 14230Sstevel@tonic-gate append_to_flist(flistp, buf); 14240Sstevel@tonic-gate } 14250Sstevel@tonic-gate if (fclose(fp) != 0) { 14260Sstevel@tonic-gate bam_error(CLOSE_FAIL, path, strerror(errno)); 14270Sstevel@tonic-gate return (BAM_ERROR); 14280Sstevel@tonic-gate } 14290Sstevel@tonic-gate return (BAM_SUCCESS); 14300Sstevel@tonic-gate } 14310Sstevel@tonic-gate 14320Sstevel@tonic-gate static error_t 14330Sstevel@tonic-gate read_list(char *root, filelist_t *flistp) 14340Sstevel@tonic-gate { 14355648Ssetje char path[PATH_MAX]; 14365648Ssetje char cmd[PATH_MAX]; 14375648Ssetje struct stat sb; 14385648Ssetje int n, rval; 14396448Svikram const char *fcn = "read_list()"; 14400Sstevel@tonic-gate 14410Sstevel@tonic-gate flistp->head = flistp->tail = NULL; 14420Sstevel@tonic-gate 14430Sstevel@tonic-gate /* 14445648Ssetje * build and check path to extract_boot_filelist.ksh 14455648Ssetje */ 14465648Ssetje n = snprintf(path, sizeof (path), "%s%s", root, EXTRACT_BOOT_FILELIST); 14475648Ssetje if (n >= sizeof (path)) { 14485648Ssetje bam_error(NO_FLIST); 14495648Ssetje return (BAM_ERROR); 14505648Ssetje } 14515648Ssetje 14525648Ssetje /* 14535648Ssetje * If extract_boot_filelist is present, exec it, otherwise read 14545648Ssetje * the filelists directly, for compatibility with older images. 14550Sstevel@tonic-gate */ 14565648Ssetje if (stat(path, &sb) == 0) { 14575648Ssetje /* 14585648Ssetje * build arguments to exec extract_boot_filelist.ksh 14595648Ssetje */ 14606319Sjg char *rootarg, *platarg; 14616319Sjg int platarglen = 1, rootarglen = 1; 14626319Sjg if (strlen(root) > 1) 14636319Sjg rootarglen += strlen(root) + strlen("-R "); 14646319Sjg if (bam_alt_platform) 14656319Sjg platarglen += strlen(bam_platform) + strlen("-p "); 14666319Sjg platarg = s_calloc(1, platarglen); 14676319Sjg rootarg = s_calloc(1, rootarglen); 14686319Sjg *platarg = 0; 14696319Sjg *rootarg = 0; 14706319Sjg 14715648Ssetje if (strlen(root) > 1) { 14726319Sjg (void) snprintf(rootarg, rootarglen, 14736319Sjg "-R %s", root); 14745648Ssetje } 14756319Sjg if (bam_alt_platform) { 14766319Sjg (void) snprintf(platarg, platarglen, 14776319Sjg "-p %s", bam_platform); 14786319Sjg } 14796319Sjg n = snprintf(cmd, sizeof (cmd), "%s %s %s /%s /%s", 14806319Sjg path, rootarg, platarg, BOOT_FILE_LIST, ETC_FILE_LIST); 14816319Sjg free(platarg); 14826319Sjg free(rootarg); 14835648Ssetje if (n >= sizeof (cmd)) { 14845648Ssetje bam_error(NO_FLIST); 14855648Ssetje return (BAM_ERROR); 14865648Ssetje } 14875648Ssetje if (exec_cmd(cmd, flistp) != 0) { 14886448Svikram BAM_DPRINTF((D_FLIST_FAIL, fcn, path, strerror(errno))); 14895648Ssetje return (BAM_ERROR); 14905648Ssetje } 14915648Ssetje } else { 14925648Ssetje /* 14935648Ssetje * Read current lists of files - only the first is mandatory 14945648Ssetje */ 14955648Ssetje rval = read_one_list(root, flistp, BOOT_FILE_LIST); 14965648Ssetje if (rval != BAM_SUCCESS) 14975648Ssetje return (rval); 14985648Ssetje (void) read_one_list(root, flistp, ETC_FILE_LIST); 14995648Ssetje } 15000Sstevel@tonic-gate 15010Sstevel@tonic-gate if (flistp->head == NULL) { 15020Sstevel@tonic-gate bam_error(NO_FLIST); 15030Sstevel@tonic-gate return (BAM_ERROR); 15040Sstevel@tonic-gate } 15050Sstevel@tonic-gate 15060Sstevel@tonic-gate return (BAM_SUCCESS); 15070Sstevel@tonic-gate } 15080Sstevel@tonic-gate 15090Sstevel@tonic-gate static void 15100Sstevel@tonic-gate getoldstat(char *root) 15110Sstevel@tonic-gate { 15120Sstevel@tonic-gate char path[PATH_MAX]; 15130Sstevel@tonic-gate int fd, error; 15140Sstevel@tonic-gate struct stat sb; 15150Sstevel@tonic-gate char *ostat; 15160Sstevel@tonic-gate 15170Sstevel@tonic-gate (void) snprintf(path, sizeof (path), "%s%s", root, FILE_STAT); 15180Sstevel@tonic-gate fd = open(path, O_RDONLY); 15190Sstevel@tonic-gate if (fd == -1) { 15200Sstevel@tonic-gate if (bam_verbose) 15210Sstevel@tonic-gate bam_print(OPEN_FAIL, path, strerror(errno)); 15220Sstevel@tonic-gate walk_arg.need_update = 1; 15230Sstevel@tonic-gate return; 15240Sstevel@tonic-gate } 15250Sstevel@tonic-gate 15260Sstevel@tonic-gate if (fstat(fd, &sb) != 0) { 15270Sstevel@tonic-gate bam_error(STAT_FAIL, path, strerror(errno)); 15280Sstevel@tonic-gate (void) close(fd); 15290Sstevel@tonic-gate walk_arg.need_update = 1; 15300Sstevel@tonic-gate return; 15310Sstevel@tonic-gate } 15320Sstevel@tonic-gate 15330Sstevel@tonic-gate ostat = s_calloc(1, sb.st_size); 15340Sstevel@tonic-gate 15350Sstevel@tonic-gate if (read(fd, ostat, sb.st_size) != sb.st_size) { 15360Sstevel@tonic-gate bam_error(READ_FAIL, path, strerror(errno)); 15370Sstevel@tonic-gate (void) close(fd); 15380Sstevel@tonic-gate free(ostat); 15390Sstevel@tonic-gate walk_arg.need_update = 1; 15400Sstevel@tonic-gate return; 15410Sstevel@tonic-gate } 15420Sstevel@tonic-gate 15430Sstevel@tonic-gate (void) close(fd); 15440Sstevel@tonic-gate 15450Sstevel@tonic-gate walk_arg.old_nvlp = NULL; 15460Sstevel@tonic-gate error = nvlist_unpack(ostat, sb.st_size, &walk_arg.old_nvlp, 0); 15470Sstevel@tonic-gate 15480Sstevel@tonic-gate free(ostat); 15490Sstevel@tonic-gate 15500Sstevel@tonic-gate if (error) { 15510Sstevel@tonic-gate bam_error(UNPACK_FAIL, path, strerror(error)); 15520Sstevel@tonic-gate walk_arg.old_nvlp = NULL; 15530Sstevel@tonic-gate walk_arg.need_update = 1; 15540Sstevel@tonic-gate return; 15550Sstevel@tonic-gate } 15560Sstevel@tonic-gate } 15570Sstevel@tonic-gate 15582583Svikram /* 15592583Svikram * Checks if a file in the current (old) archive has 15602583Svikram * been deleted from the root filesystem. This is needed for 15612583Svikram * software like Trusted Extensions (TX) that switch early 15622583Svikram * in boot based on presence/absence of a kernel module. 15632583Svikram */ 15642583Svikram static void 15652583Svikram check4stale(char *root) 15662583Svikram { 15672583Svikram nvpair_t *nvp; 15682583Svikram nvlist_t *nvlp; 15692583Svikram char *file; 15702583Svikram char path[PATH_MAX]; 15712583Svikram struct stat sb; 15722583Svikram 15732583Svikram /* 15742583Svikram * Skip stale file check during smf check 15752583Svikram */ 15762583Svikram if (bam_smf_check) 15772583Svikram return; 15782583Svikram 15792583Svikram /* Nothing to do if no old stats */ 15802583Svikram if ((nvlp = walk_arg.old_nvlp) == NULL) 15812583Svikram return; 15822583Svikram 15832583Svikram for (nvp = nvlist_next_nvpair(nvlp, NULL); nvp; 15842583Svikram nvp = nvlist_next_nvpair(nvlp, nvp)) { 15852583Svikram file = nvpair_name(nvp); 15862583Svikram if (file == NULL) 15872583Svikram continue; 15882583Svikram (void) snprintf(path, sizeof (path), "%s/%s", 15892583Svikram root, file); 15902583Svikram if (stat(path, &sb) == -1) { 15912583Svikram walk_arg.need_update = 1; 15922583Svikram if (bam_verbose) 15932583Svikram bam_print(PARSEABLE_STALE_FILE, path); 15942583Svikram } 15952583Svikram } 15962583Svikram } 15972583Svikram 15980Sstevel@tonic-gate static void 15990Sstevel@tonic-gate create_newstat(void) 16000Sstevel@tonic-gate { 16010Sstevel@tonic-gate int error; 16020Sstevel@tonic-gate 16030Sstevel@tonic-gate error = nvlist_alloc(&walk_arg.new_nvlp, NV_UNIQUE_NAME, 0); 16040Sstevel@tonic-gate if (error) { 16050Sstevel@tonic-gate /* 16060Sstevel@tonic-gate * Not fatal - we can still create archive 16070Sstevel@tonic-gate */ 16080Sstevel@tonic-gate walk_arg.new_nvlp = NULL; 16090Sstevel@tonic-gate bam_error(NVALLOC_FAIL, strerror(error)); 16100Sstevel@tonic-gate } 16110Sstevel@tonic-gate } 16120Sstevel@tonic-gate 16130Sstevel@tonic-gate static void 16140Sstevel@tonic-gate walk_list(char *root, filelist_t *flistp) 16150Sstevel@tonic-gate { 16160Sstevel@tonic-gate char path[PATH_MAX]; 16170Sstevel@tonic-gate line_t *lp; 16180Sstevel@tonic-gate 16190Sstevel@tonic-gate for (lp = flistp->head; lp; lp = lp->next) { 16205648Ssetje /* 16215648Ssetje * Don't follow symlinks. A symlink must refer to 16225648Ssetje * a file that would appear in the archive through 16235648Ssetje * a direct reference. This matches the archive 16245648Ssetje * construction behavior. 16255648Ssetje */ 16260Sstevel@tonic-gate (void) snprintf(path, sizeof (path), "%s%s", root, lp->line); 16275648Ssetje if (nftw(path, cmpstat, 20, FTW_PHYS) == -1) { 16280Sstevel@tonic-gate /* 16290Sstevel@tonic-gate * Some files may not exist. 16300Sstevel@tonic-gate * For example: etc/rtc_config on a x86 diskless system 16310Sstevel@tonic-gate * Emit verbose message only 16320Sstevel@tonic-gate */ 16330Sstevel@tonic-gate if (bam_verbose) 16340Sstevel@tonic-gate bam_print(NFTW_FAIL, path, strerror(errno)); 16350Sstevel@tonic-gate } 16360Sstevel@tonic-gate } 16370Sstevel@tonic-gate } 16380Sstevel@tonic-gate 16390Sstevel@tonic-gate static void 16400Sstevel@tonic-gate savenew(char *root) 16410Sstevel@tonic-gate { 16420Sstevel@tonic-gate char path[PATH_MAX]; 16430Sstevel@tonic-gate char path2[PATH_MAX]; 16440Sstevel@tonic-gate size_t sz; 16450Sstevel@tonic-gate char *nstat; 16460Sstevel@tonic-gate int fd, wrote, error; 16470Sstevel@tonic-gate 16480Sstevel@tonic-gate nstat = NULL; 16490Sstevel@tonic-gate sz = 0; 16500Sstevel@tonic-gate error = nvlist_pack(walk_arg.new_nvlp, &nstat, &sz, 16510Sstevel@tonic-gate NV_ENCODE_XDR, 0); 16520Sstevel@tonic-gate if (error) { 16530Sstevel@tonic-gate bam_error(PACK_FAIL, strerror(error)); 16540Sstevel@tonic-gate return; 16550Sstevel@tonic-gate } 16560Sstevel@tonic-gate 16570Sstevel@tonic-gate (void) snprintf(path, sizeof (path), "%s%s", root, FILE_STAT_TMP); 16580Sstevel@tonic-gate fd = open(path, O_RDWR|O_CREAT|O_TRUNC, FILE_STAT_MODE); 16590Sstevel@tonic-gate if (fd == -1) { 16600Sstevel@tonic-gate bam_error(OPEN_FAIL, path, strerror(errno)); 16610Sstevel@tonic-gate free(nstat); 16620Sstevel@tonic-gate return; 16630Sstevel@tonic-gate } 16640Sstevel@tonic-gate wrote = write(fd, nstat, sz); 16650Sstevel@tonic-gate if (wrote != sz) { 16660Sstevel@tonic-gate bam_error(WRITE_FAIL, path, strerror(errno)); 16670Sstevel@tonic-gate (void) close(fd); 16680Sstevel@tonic-gate free(nstat); 16690Sstevel@tonic-gate return; 16700Sstevel@tonic-gate } 16710Sstevel@tonic-gate (void) close(fd); 16720Sstevel@tonic-gate free(nstat); 16730Sstevel@tonic-gate 16740Sstevel@tonic-gate (void) snprintf(path2, sizeof (path2), "%s%s", root, FILE_STAT); 16750Sstevel@tonic-gate if (rename(path, path2) != 0) { 16760Sstevel@tonic-gate bam_error(RENAME_FAIL, path2, strerror(errno)); 16770Sstevel@tonic-gate } 16780Sstevel@tonic-gate } 16790Sstevel@tonic-gate 16800Sstevel@tonic-gate static void 16810Sstevel@tonic-gate clear_walk_args(void) 16820Sstevel@tonic-gate { 16830Sstevel@tonic-gate if (walk_arg.old_nvlp) 16840Sstevel@tonic-gate nvlist_free(walk_arg.old_nvlp); 16850Sstevel@tonic-gate if (walk_arg.new_nvlp) 16860Sstevel@tonic-gate nvlist_free(walk_arg.new_nvlp); 16870Sstevel@tonic-gate walk_arg.need_update = 0; 16880Sstevel@tonic-gate walk_arg.old_nvlp = NULL; 16890Sstevel@tonic-gate walk_arg.new_nvlp = NULL; 16900Sstevel@tonic-gate } 16910Sstevel@tonic-gate 16920Sstevel@tonic-gate /* 16930Sstevel@tonic-gate * Returns: 16940Sstevel@tonic-gate * 0 - no update necessary 16950Sstevel@tonic-gate * 1 - update required. 16960Sstevel@tonic-gate * BAM_ERROR (-1) - An error occurred 16970Sstevel@tonic-gate * 16980Sstevel@tonic-gate * Special handling for check (-n): 16990Sstevel@tonic-gate * ================================ 17000Sstevel@tonic-gate * The check (-n) option produces parseable output. 17010Sstevel@tonic-gate * To do this, we suppress all stdout messages unrelated 17020Sstevel@tonic-gate * to out of sync files. 17030Sstevel@tonic-gate * All stderr messages are still printed though. 17040Sstevel@tonic-gate * 17050Sstevel@tonic-gate */ 17060Sstevel@tonic-gate static int 17070Sstevel@tonic-gate update_required(char *root) 17080Sstevel@tonic-gate { 17090Sstevel@tonic-gate struct stat sb; 17100Sstevel@tonic-gate char path[PATH_MAX]; 17110Sstevel@tonic-gate filelist_t flist; 17120Sstevel@tonic-gate filelist_t *flistp = &flist; 17130Sstevel@tonic-gate int need_update; 17140Sstevel@tonic-gate 17150Sstevel@tonic-gate flistp->head = flistp->tail = NULL; 17160Sstevel@tonic-gate 17170Sstevel@tonic-gate walk_arg.need_update = 0; 17180Sstevel@tonic-gate 17190Sstevel@tonic-gate /* 17200Sstevel@tonic-gate * Without consulting stat data, check if we need update 17210Sstevel@tonic-gate */ 17220Sstevel@tonic-gate check_flags_and_files(root); 17230Sstevel@tonic-gate 17240Sstevel@tonic-gate /* 17250Sstevel@tonic-gate * In certain deployment scenarios, filestat may not 17260Sstevel@tonic-gate * exist. Ignore it during boot-archive SMF check. 17270Sstevel@tonic-gate */ 17280Sstevel@tonic-gate if (bam_smf_check) { 17290Sstevel@tonic-gate (void) snprintf(path, sizeof (path), "%s%s", root, FILE_STAT); 17300Sstevel@tonic-gate if (stat(path, &sb) != 0) 17310Sstevel@tonic-gate return (0); 17320Sstevel@tonic-gate } 17330Sstevel@tonic-gate 17340Sstevel@tonic-gate /* 17350Sstevel@tonic-gate * consult stat data only if we haven't made a decision 17360Sstevel@tonic-gate * about update. If checking (-n) however, we always 17370Sstevel@tonic-gate * need stat data (since we want to compare old and new) 17380Sstevel@tonic-gate */ 17390Sstevel@tonic-gate if (!walk_arg.need_update || bam_check) 17400Sstevel@tonic-gate getoldstat(root); 17410Sstevel@tonic-gate 17420Sstevel@tonic-gate /* 17432583Svikram * Check if the archive contains files that are no longer 17442583Svikram * present on the root filesystem. 17452583Svikram */ 17462583Svikram if (!walk_arg.need_update || bam_check) 17472583Svikram check4stale(root); 17482583Svikram 17492583Svikram /* 17500Sstevel@tonic-gate * read list of files 17510Sstevel@tonic-gate */ 17520Sstevel@tonic-gate if (read_list(root, flistp) != BAM_SUCCESS) { 17530Sstevel@tonic-gate clear_walk_args(); 17540Sstevel@tonic-gate return (BAM_ERROR); 17550Sstevel@tonic-gate } 17560Sstevel@tonic-gate 17570Sstevel@tonic-gate assert(flistp->head && flistp->tail); 17580Sstevel@tonic-gate 17590Sstevel@tonic-gate /* 17600Sstevel@tonic-gate * At this point either the update is required 17610Sstevel@tonic-gate * or the decision is pending. In either case 17620Sstevel@tonic-gate * we need to create new stat nvlist 17630Sstevel@tonic-gate */ 17640Sstevel@tonic-gate create_newstat(); 17650Sstevel@tonic-gate 17660Sstevel@tonic-gate /* 17670Sstevel@tonic-gate * This walk does 2 things: 17680Sstevel@tonic-gate * - gets new stat data for every file 17690Sstevel@tonic-gate * - (optional) compare old and new stat data 17700Sstevel@tonic-gate */ 17710Sstevel@tonic-gate walk_list(root, &flist); 17720Sstevel@tonic-gate 17730Sstevel@tonic-gate /* done with the file list */ 17740Sstevel@tonic-gate filelist_free(flistp); 17750Sstevel@tonic-gate 17760Sstevel@tonic-gate /* 17770Sstevel@tonic-gate * if we didn't succeed in creating new stat data above 17780Sstevel@tonic-gate * just return result of update check so that archive is built. 17790Sstevel@tonic-gate */ 17800Sstevel@tonic-gate if (walk_arg.new_nvlp == NULL) { 17810Sstevel@tonic-gate bam_error(NO_NEW_STAT); 17820Sstevel@tonic-gate need_update = walk_arg.need_update; 17830Sstevel@tonic-gate clear_walk_args(); 17840Sstevel@tonic-gate return (need_update ? 1 : 0); 17850Sstevel@tonic-gate } 17860Sstevel@tonic-gate 17870Sstevel@tonic-gate 17880Sstevel@tonic-gate /* 17890Sstevel@tonic-gate * If no update required, discard newstat 17900Sstevel@tonic-gate */ 17910Sstevel@tonic-gate if (!walk_arg.need_update) { 17920Sstevel@tonic-gate clear_walk_args(); 17930Sstevel@tonic-gate return (0); 17940Sstevel@tonic-gate } 17950Sstevel@tonic-gate 17960Sstevel@tonic-gate return (1); 17970Sstevel@tonic-gate } 17980Sstevel@tonic-gate 17990Sstevel@tonic-gate static error_t 18000Sstevel@tonic-gate create_ramdisk(char *root) 18010Sstevel@tonic-gate { 18020Sstevel@tonic-gate char *cmdline, path[PATH_MAX]; 18030Sstevel@tonic-gate size_t len; 18040Sstevel@tonic-gate struct stat sb; 18050Sstevel@tonic-gate 18060Sstevel@tonic-gate /* 18070Sstevel@tonic-gate * Setup command args for create_ramdisk.ksh 18080Sstevel@tonic-gate */ 18095648Ssetje (void) snprintf(path, sizeof (path), "%s/%s", root, CREATE_RAMDISK); 18100Sstevel@tonic-gate if (stat(path, &sb) != 0) { 18110Sstevel@tonic-gate bam_error(ARCH_EXEC_MISS, path, strerror(errno)); 18120Sstevel@tonic-gate return (BAM_ERROR); 18130Sstevel@tonic-gate } 18140Sstevel@tonic-gate 18150Sstevel@tonic-gate len = strlen(path) + strlen(root) + 10; /* room for space + -R */ 18166319Sjg if (bam_alt_platform) 18176319Sjg len += strlen(bam_platform) + strlen("-p "); 18180Sstevel@tonic-gate cmdline = s_calloc(1, len); 18190Sstevel@tonic-gate 18206319Sjg if (bam_alt_platform) { 18216319Sjg assert(strlen(root) > 1); 18226319Sjg (void) snprintf(cmdline, len, "%s -p %s -R %s", 18236319Sjg path, bam_platform, root); 18246319Sjg /* chop off / at the end */ 18256319Sjg cmdline[strlen(cmdline) - 1] = '\0'; 18266319Sjg } else if (strlen(root) > 1) { 18270Sstevel@tonic-gate (void) snprintf(cmdline, len, "%s -R %s", path, root); 18280Sstevel@tonic-gate /* chop off / at the end */ 18290Sstevel@tonic-gate cmdline[strlen(cmdline) - 1] = '\0'; 18300Sstevel@tonic-gate } else 18310Sstevel@tonic-gate (void) snprintf(cmdline, len, "%s", path); 18320Sstevel@tonic-gate 18335648Ssetje if (exec_cmd(cmdline, NULL) != 0) { 18340Sstevel@tonic-gate bam_error(ARCHIVE_FAIL, cmdline); 18350Sstevel@tonic-gate free(cmdline); 18360Sstevel@tonic-gate return (BAM_ERROR); 18370Sstevel@tonic-gate } 18380Sstevel@tonic-gate free(cmdline); 18390Sstevel@tonic-gate 18400Sstevel@tonic-gate /* 18415648Ssetje * The existence of the expected archives used to be 18425648Ssetje * verified here. This check is done in create_ramdisk as 18435648Ssetje * it needs to be in sync with the altroot operated upon. 18440Sstevel@tonic-gate */ 18450Sstevel@tonic-gate 18460Sstevel@tonic-gate return (BAM_SUCCESS); 18470Sstevel@tonic-gate } 18480Sstevel@tonic-gate 18490Sstevel@tonic-gate /* 18500Sstevel@tonic-gate * Checks if target filesystem is on a ramdisk 18510Sstevel@tonic-gate * 1 - is miniroot 18520Sstevel@tonic-gate * 0 - is not 18530Sstevel@tonic-gate * When in doubt assume it is not a ramdisk. 18540Sstevel@tonic-gate */ 18550Sstevel@tonic-gate static int 18560Sstevel@tonic-gate is_ramdisk(char *root) 18570Sstevel@tonic-gate { 18580Sstevel@tonic-gate struct extmnttab mnt; 18590Sstevel@tonic-gate FILE *fp; 18600Sstevel@tonic-gate int found; 1861316Svikram char mntpt[PATH_MAX]; 1862316Svikram char *cp; 18630Sstevel@tonic-gate 18640Sstevel@tonic-gate /* 18650Sstevel@tonic-gate * There are 3 situations where creating archive is 18660Sstevel@tonic-gate * of dubious value: 1867316Svikram * - create boot_archive on a lofi-mounted boot_archive 18680Sstevel@tonic-gate * - create it on a ramdisk which is the root filesystem 18690Sstevel@tonic-gate * - create it on a ramdisk mounted somewhere else 18700Sstevel@tonic-gate * The first is not easy to detect and checking for it is not 18710Sstevel@tonic-gate * worth it. 18720Sstevel@tonic-gate * The other two conditions are handled here 18730Sstevel@tonic-gate */ 18740Sstevel@tonic-gate 18750Sstevel@tonic-gate fp = fopen(MNTTAB, "r"); 18760Sstevel@tonic-gate if (fp == NULL) { 18770Sstevel@tonic-gate bam_error(OPEN_FAIL, MNTTAB, strerror(errno)); 18780Sstevel@tonic-gate return (0); 18790Sstevel@tonic-gate } 18800Sstevel@tonic-gate 18810Sstevel@tonic-gate resetmnttab(fp); 18820Sstevel@tonic-gate 1883316Svikram /* 1884316Svikram * Remove any trailing / from the mount point 1885316Svikram */ 1886316Svikram (void) strlcpy(mntpt, root, sizeof (mntpt)); 1887316Svikram if (strcmp(root, "/") != 0) { 1888316Svikram cp = mntpt + strlen(mntpt) - 1; 1889316Svikram if (*cp == '/') 1890316Svikram *cp = '\0'; 1891316Svikram } 18920Sstevel@tonic-gate found = 0; 18930Sstevel@tonic-gate while (getextmntent(fp, &mnt, sizeof (mnt)) == 0) { 1894316Svikram if (strcmp(mnt.mnt_mountp, mntpt) == 0) { 18950Sstevel@tonic-gate found = 1; 18960Sstevel@tonic-gate break; 18970Sstevel@tonic-gate } 18980Sstevel@tonic-gate } 18990Sstevel@tonic-gate 19000Sstevel@tonic-gate if (!found) { 19010Sstevel@tonic-gate if (bam_verbose) 1902316Svikram bam_error(NOT_IN_MNTTAB, mntpt); 19030Sstevel@tonic-gate (void) fclose(fp); 19040Sstevel@tonic-gate return (0); 19050Sstevel@tonic-gate } 19060Sstevel@tonic-gate 19070Sstevel@tonic-gate if (strstr(mnt.mnt_special, RAMDISK_SPECIAL) != NULL) { 19080Sstevel@tonic-gate if (bam_verbose) 19090Sstevel@tonic-gate bam_error(IS_RAMDISK, bam_root); 19100Sstevel@tonic-gate (void) fclose(fp); 19110Sstevel@tonic-gate return (1); 19120Sstevel@tonic-gate } 19130Sstevel@tonic-gate 19140Sstevel@tonic-gate (void) fclose(fp); 19150Sstevel@tonic-gate 19160Sstevel@tonic-gate return (0); 19170Sstevel@tonic-gate } 19180Sstevel@tonic-gate 19190Sstevel@tonic-gate static int 19205648Ssetje is_boot_archive(char *root) 19210Sstevel@tonic-gate { 19226448Svikram char path[PATH_MAX]; 19236448Svikram struct stat sb; 19246448Svikram int error; 19256448Svikram const char *fcn = "is_boot_archive()"; 19260Sstevel@tonic-gate 19270Sstevel@tonic-gate /* 19285648Ssetje * We can't create an archive without the create_ramdisk script 19290Sstevel@tonic-gate */ 19305648Ssetje (void) snprintf(path, sizeof (path), "%s/%s", root, CREATE_RAMDISK); 19316448Svikram error = stat(path, &sb); 19326448Svikram INJECT_ERROR1("NOT_ARCHIVE_BASED", error = -1); 19336448Svikram if (error == -1) { 19340Sstevel@tonic-gate if (bam_verbose) 19350Sstevel@tonic-gate bam_print(FILE_MISS, path); 19366448Svikram BAM_DPRINTF((D_NOT_ARCHIVE_BOOT, fcn, root)); 19370Sstevel@tonic-gate return (0); 19380Sstevel@tonic-gate } 19390Sstevel@tonic-gate 19406448Svikram BAM_DPRINTF((D_IS_ARCHIVE_BOOT, fcn, root)); 19415648Ssetje return (1); 19425648Ssetje } 19435648Ssetje 19445648Ssetje /* 19455648Ssetje * Need to call this for anything that operates on the GRUB menu 19466694Svikram * In the x86 live upgrade case the directory /boot/grub may be present 19476694Svikram * even on pre-newboot BEs. The authoritative way to check for a GRUB target 19486694Svikram * is to check for the presence of the stage2 binary which is present 19496694Svikram * only on GRUB targets (even on x86 boot partitions). Checking for the 19506694Svikram * presence of the multiboot binary is not correct as it is not present 19516694Svikram * on x86 boot partitions. 19525648Ssetje */ 19535648Ssetje int 19545648Ssetje is_grub(const char *root) 19555648Ssetje { 19565648Ssetje char path[PATH_MAX]; 19575648Ssetje struct stat sb; 19586448Svikram const char *fcn = "is_grub()"; 19596448Svikram 19606694Svikram (void) snprintf(path, sizeof (path), "%s%s", root, GRUB_STAGE2); 19610Sstevel@tonic-gate if (stat(path, &sb) == -1) { 19626448Svikram BAM_DPRINTF((D_NO_GRUB_DIR, fcn, path)); 19630Sstevel@tonic-gate return (0); 19640Sstevel@tonic-gate } 19650Sstevel@tonic-gate 19660Sstevel@tonic-gate return (1); 19670Sstevel@tonic-gate } 19680Sstevel@tonic-gate 19690Sstevel@tonic-gate static int 19706448Svikram is_zfs(char *root) 19716448Svikram { 19726448Svikram struct statvfs vfs; 19736448Svikram int ret; 19746448Svikram const char *fcn = "is_zfs()"; 19756448Svikram 19766448Svikram ret = statvfs(root, &vfs); 19776448Svikram INJECT_ERROR1("STATVFS_ZFS", ret = 1); 19786448Svikram if (ret != 0) { 19796448Svikram bam_error(STATVFS_FAIL, root, strerror(errno)); 19806448Svikram return (0); 19816448Svikram } 19826448Svikram 19836448Svikram if (strncmp(vfs.f_basetype, "zfs", strlen("zfs")) == 0) { 19846448Svikram BAM_DPRINTF((D_IS_ZFS, fcn, root)); 19856448Svikram return (1); 19866448Svikram } else { 19876448Svikram BAM_DPRINTF((D_IS_NOT_ZFS, fcn, root)); 19880Sstevel@tonic-gate return (0); 19890Sstevel@tonic-gate } 19906448Svikram } 19916448Svikram 19926448Svikram static int 19936448Svikram is_ufs(char *root) 19946448Svikram { 19956448Svikram struct statvfs vfs; 19966448Svikram int ret; 19976448Svikram const char *fcn = "is_ufs()"; 19986448Svikram 19996448Svikram ret = statvfs(root, &vfs); 20006448Svikram INJECT_ERROR1("STATVFS_UFS", ret = 1); 20016448Svikram if (ret != 0) { 20026448Svikram bam_error(STATVFS_FAIL, root, strerror(errno)); 20036448Svikram return (0); 20046448Svikram } 20056448Svikram 20066448Svikram if (strncmp(vfs.f_basetype, "ufs", strlen("ufs")) == 0) { 20076448Svikram BAM_DPRINTF((D_IS_UFS, fcn, root)); 20080Sstevel@tonic-gate return (1); 20096448Svikram } else { 20106448Svikram BAM_DPRINTF((D_IS_NOT_UFS, fcn, root)); 20116448Svikram return (0); 20126448Svikram } 20130Sstevel@tonic-gate } 20140Sstevel@tonic-gate 20156423Sgw25295 static int 20166448Svikram is_pcfs(char *root) 20176448Svikram { 20186448Svikram struct statvfs vfs; 20196448Svikram int ret; 20206448Svikram const char *fcn = "is_pcfs()"; 20216448Svikram 20226448Svikram ret = statvfs(root, &vfs); 20236448Svikram INJECT_ERROR1("STATVFS_PCFS", ret = 1); 20246448Svikram if (ret != 0) { 20256448Svikram bam_error(STATVFS_FAIL, root, strerror(errno)); 20266423Sgw25295 return (0); 20276423Sgw25295 } 20286423Sgw25295 20296448Svikram if (strncmp(vfs.f_basetype, "pcfs", strlen("pcfs")) == 0) { 20306448Svikram BAM_DPRINTF((D_IS_PCFS, fcn, root)); 20316448Svikram return (1); 20326448Svikram } else { 20336448Svikram BAM_DPRINTF((D_IS_NOT_PCFS, fcn, root)); 20346423Sgw25295 return (0); 20356448Svikram } 20366448Svikram } 20376448Svikram 20386448Svikram static int 20396448Svikram is_readonly(char *root) 20406448Svikram { 20416448Svikram int fd; 20426448Svikram int error; 20436448Svikram char testfile[PATH_MAX]; 20446448Svikram const char *fcn = "is_readonly()"; 20456423Sgw25295 20466423Sgw25295 /* 20476448Svikram * Using statvfs() to check for a read-only filesystem is not 20486448Svikram * reliable. The only way to reliably test is to attempt to 20496448Svikram * create a file 20506423Sgw25295 */ 20516448Svikram (void) snprintf(testfile, sizeof (testfile), "%s/%s.%d", 20526448Svikram root, BOOTADM_RDONLY_TEST, getpid()); 20536448Svikram 20546448Svikram (void) unlink(testfile); 20556448Svikram 20566448Svikram errno = 0; 20576448Svikram fd = open(testfile, O_RDWR|O_CREAT|O_EXCL, 0644); 20586448Svikram error = errno; 20596448Svikram INJECT_ERROR2("RDONLY_TEST_ERROR", fd = -1, error = EACCES); 20606448Svikram if (fd == -1 && error == EROFS) { 20616448Svikram BAM_DPRINTF((D_RDONLY_FS, fcn, root)); 20626423Sgw25295 return (1); 20636448Svikram } else if (fd == -1) { 20646448Svikram bam_error(RDONLY_TEST_ERROR, root, strerror(error)); 20656448Svikram } 20666448Svikram 20676448Svikram (void) close(fd); 20686448Svikram (void) unlink(testfile); 20696448Svikram 20706448Svikram BAM_DPRINTF((D_RDWR_FS, fcn, root)); 20716423Sgw25295 return (0); 20726423Sgw25295 } 20736423Sgw25295 20740Sstevel@tonic-gate static error_t 20750Sstevel@tonic-gate update_archive(char *root, char *opt) 20760Sstevel@tonic-gate { 20770Sstevel@tonic-gate error_t ret; 20780Sstevel@tonic-gate 20790Sstevel@tonic-gate assert(root); 20800Sstevel@tonic-gate assert(opt == NULL); 20810Sstevel@tonic-gate 20820Sstevel@tonic-gate /* 20836448Svikram * root must belong to a boot archive based OS, 20840Sstevel@tonic-gate */ 20855648Ssetje if (!is_boot_archive(root)) { 2086316Svikram /* 2087316Svikram * Emit message only if not in context of update_all. 2088316Svikram * If in update_all, emit only if verbose flag is set. 2089316Svikram */ 2090316Svikram if (!bam_update_all || bam_verbose) 20916448Svikram bam_print(NOT_ARCHIVE_BOOT, root); 20920Sstevel@tonic-gate return (BAM_SUCCESS); 20930Sstevel@tonic-gate } 20940Sstevel@tonic-gate 20950Sstevel@tonic-gate /* 2096662Sszhou * If smf check is requested when / is writable (can happen 2097662Sszhou * on first reboot following an upgrade because service 2098662Sszhou * dependency is messed up), skip the check. 2099662Sszhou */ 2100662Sszhou if (bam_smf_check && !bam_root_readonly) 2101662Sszhou return (BAM_SUCCESS); 2102662Sszhou 2103662Sszhou /* 2104662Sszhou * root must be writable. This check applies to alternate 2105662Sszhou * root (-R option); bam_root_readonly applies to '/' only. 21060Sstevel@tonic-gate */ 2107756Ssetje if (!bam_smf_check && !bam_check && is_readonly(root)) { 2108662Sszhou if (bam_verbose) 21090Sstevel@tonic-gate bam_print(RDONLY_FS, root); 21100Sstevel@tonic-gate return (BAM_SUCCESS); 21110Sstevel@tonic-gate } 21120Sstevel@tonic-gate 21130Sstevel@tonic-gate /* 21140Sstevel@tonic-gate * Don't generate archive on ramdisk 21150Sstevel@tonic-gate */ 21160Sstevel@tonic-gate if (is_ramdisk(root)) { 21170Sstevel@tonic-gate if (bam_verbose) 21180Sstevel@tonic-gate bam_print(SKIP_RAMDISK); 21190Sstevel@tonic-gate return (BAM_SUCCESS); 21200Sstevel@tonic-gate } 21210Sstevel@tonic-gate 21220Sstevel@tonic-gate /* 21230Sstevel@tonic-gate * Now check if updated is really needed 21240Sstevel@tonic-gate */ 21250Sstevel@tonic-gate ret = update_required(root); 21260Sstevel@tonic-gate 21270Sstevel@tonic-gate /* 21280Sstevel@tonic-gate * The check command (-n) is *not* a dry run 21290Sstevel@tonic-gate * It only checks if the archive is in sync. 21300Sstevel@tonic-gate */ 21310Sstevel@tonic-gate if (bam_check) { 21320Sstevel@tonic-gate bam_exit((ret != 0) ? 1 : 0); 21330Sstevel@tonic-gate } 21340Sstevel@tonic-gate 21350Sstevel@tonic-gate if (ret == 1) { 21360Sstevel@tonic-gate /* create the ramdisk */ 21370Sstevel@tonic-gate ret = create_ramdisk(root); 21380Sstevel@tonic-gate } 21395648Ssetje 21405648Ssetje /* if the archive is updated, save the new stat data */ 21415648Ssetje if (ret == 0 && walk_arg.new_nvlp != NULL) { 21425648Ssetje savenew(root); 21435648Ssetje } 21445648Ssetje 21455648Ssetje clear_walk_args(); 21465648Ssetje 21470Sstevel@tonic-gate return (ret); 21480Sstevel@tonic-gate } 21490Sstevel@tonic-gate 21506694Svikram static error_t 21516694Svikram synchronize_BE_menu(void) 21526694Svikram { 21536694Svikram struct stat sb; 21546694Svikram char cmdline[PATH_MAX]; 21556694Svikram char cksum_line[PATH_MAX]; 21566694Svikram filelist_t flist = {0}; 21576694Svikram char *old_cksum_str; 21586694Svikram char *old_size_str; 21596694Svikram char *old_file; 21606694Svikram char *curr_cksum_str; 21616694Svikram char *curr_size_str; 21626694Svikram char *curr_file; 21636694Svikram FILE *cfp; 21646694Svikram int found; 21656694Svikram int ret; 21666694Svikram const char *fcn = "synchronize_BE_menu()"; 21676694Svikram 21686694Svikram BAM_DPRINTF((D_FUNC_ENTRY0, fcn)); 21696694Svikram 21706694Svikram /* Check if findroot enabled LU BE */ 21716694Svikram if (stat(FINDROOT_INSTALLGRUB, &sb) != 0) { 21726694Svikram BAM_DPRINTF((D_NOT_LU_BE, fcn)); 21736694Svikram return (BAM_SUCCESS); 21746694Svikram } 21756694Svikram 21766694Svikram if (stat(LU_MENU_CKSUM, &sb) != 0) { 21776694Svikram BAM_DPRINTF((D_NO_CKSUM_FILE, fcn, LU_MENU_CKSUM)); 21786694Svikram goto menu_sync; 21796694Svikram } 21806694Svikram 21816694Svikram cfp = fopen(LU_MENU_CKSUM, "r"); 21826694Svikram INJECT_ERROR1("CKSUM_FILE_MISSING", cfp = NULL); 21836694Svikram if (cfp == NULL) { 21846694Svikram bam_error(CANNOT_READ_LU_CKSUM, LU_MENU_CKSUM); 21856694Svikram goto menu_sync; 21866694Svikram } 21876694Svikram BAM_DPRINTF((D_CKSUM_FILE_OPENED, fcn, LU_MENU_CKSUM)); 21886694Svikram 21896694Svikram found = 0; 21906694Svikram while (s_fgets(cksum_line, sizeof (cksum_line), cfp) != NULL) { 21916694Svikram INJECT_ERROR1("MULTIPLE_CKSUM", found = 1); 21926694Svikram if (found) { 21936694Svikram bam_error(MULTIPLE_LU_CKSUM, LU_MENU_CKSUM); 21946694Svikram (void) fclose(cfp); 21956694Svikram goto menu_sync; 21966694Svikram } 21976694Svikram found = 1; 21986694Svikram } 21996694Svikram BAM_DPRINTF((D_CKSUM_FILE_READ, fcn, LU_MENU_CKSUM)); 22006694Svikram 22016694Svikram 22026694Svikram old_cksum_str = strtok(cksum_line, " \t"); 22036694Svikram old_size_str = strtok(NULL, " \t"); 22046694Svikram old_file = strtok(NULL, " \t"); 22056694Svikram 22066694Svikram INJECT_ERROR1("OLD_CKSUM_NULL", old_cksum_str = NULL); 22076694Svikram INJECT_ERROR1("OLD_SIZE_NULL", old_size_str = NULL); 22086694Svikram INJECT_ERROR1("OLD_FILE_NULL", old_file = NULL); 22096694Svikram if (old_cksum_str == NULL || old_size_str == NULL || old_file == NULL) { 22106694Svikram bam_error(CANNOT_PARSE_LU_CKSUM, LU_MENU_CKSUM); 22116694Svikram goto menu_sync; 22126694Svikram } 22136694Svikram BAM_DPRINTF((D_CKSUM_FILE_PARSED, fcn, LU_MENU_CKSUM)); 22146694Svikram 22156694Svikram /* Get checksum of current menu */ 22166694Svikram (void) snprintf(cmdline, sizeof (cmdline), "%s %s", 22176694Svikram CKSUM, GRUB_MENU); 22186694Svikram ret = exec_cmd(cmdline, &flist); 22196694Svikram INJECT_ERROR1("GET_CURR_CKSUM", ret = 1); 22206694Svikram if (ret != 0) { 22216694Svikram bam_error(MENU_CKSUM_FAIL); 22226694Svikram return (BAM_ERROR); 22236694Svikram } 22246694Svikram BAM_DPRINTF((D_CKSUM_GEN_SUCCESS, fcn)); 22256694Svikram 22266694Svikram INJECT_ERROR1("GET_CURR_CKSUM_OUTPUT", flist.head = NULL); 22276694Svikram if ((flist.head == NULL) || (flist.head != flist.tail)) { 22286694Svikram bam_error(BAD_CKSUM); 22296694Svikram filelist_free(&flist); 22306694Svikram return (BAM_ERROR); 22316694Svikram } 22326694Svikram BAM_DPRINTF((D_CKSUM_GEN_OUTPUT_VALID, fcn)); 22336694Svikram 22346694Svikram curr_cksum_str = strtok(flist.head->line, " \t"); 22356694Svikram curr_size_str = strtok(NULL, " \t"); 22366694Svikram curr_file = strtok(NULL, " \t"); 22376694Svikram 22386694Svikram INJECT_ERROR1("CURR_CKSUM_NULL", curr_cksum_str = NULL); 22396694Svikram INJECT_ERROR1("CURR_SIZE_NULL", curr_size_str = NULL); 22406694Svikram INJECT_ERROR1("CURR_FILE_NULL", curr_file = NULL); 22416694Svikram if (curr_cksum_str == NULL || curr_size_str == NULL || 22426694Svikram curr_file == NULL) { 22436694Svikram bam_error(BAD_CKSUM_PARSE); 22446694Svikram filelist_free(&flist); 22456694Svikram return (BAM_ERROR); 22466694Svikram } 22476694Svikram BAM_DPRINTF((D_CKSUM_GEN_PARSED, fcn)); 22486694Svikram 22496694Svikram if (strcmp(old_cksum_str, curr_cksum_str) == 0 && 22506694Svikram strcmp(old_size_str, curr_size_str) == 0 && 22516694Svikram strcmp(old_file, curr_file) == 0) { 22526694Svikram filelist_free(&flist); 22536694Svikram BAM_DPRINTF((D_CKSUM_NO_CHANGE, fcn)); 22546694Svikram return (BAM_SUCCESS); 22556694Svikram } 22566694Svikram 22576694Svikram filelist_free(&flist); 22586694Svikram 22596694Svikram /* cksum doesn't match - the menu has changed */ 22606694Svikram BAM_DPRINTF((D_CKSUM_HAS_CHANGED, fcn)); 22616694Svikram 22626694Svikram menu_sync: 22636694Svikram bam_print(PROP_GRUB_MENU); 22646694Svikram 22656694Svikram (void) snprintf(cmdline, sizeof (cmdline), 22667048Svikram "/bin/sh -c '. %s > /dev/null; %s %s yes > /dev/null'", 22676694Svikram LULIB, LULIB_PROPAGATE_FILE, GRUB_MENU); 22686694Svikram ret = exec_cmd(cmdline, NULL); 22696694Svikram INJECT_ERROR1("PROPAGATE_MENU", ret = 1); 22706694Svikram if (ret != 0) { 22716694Svikram bam_error(MENU_PROP_FAIL); 22726694Svikram return (BAM_ERROR); 22736694Svikram } 22746694Svikram BAM_DPRINTF((D_PROPAGATED_MENU, fcn)); 22756694Svikram 22767048Svikram (void) snprintf(cmdline, sizeof (cmdline), "/bin/cp %s %s > /dev/null", 22776694Svikram GRUB_MENU, GRUB_BACKUP_MENU); 22786694Svikram ret = exec_cmd(cmdline, NULL); 22796694Svikram INJECT_ERROR1("CREATE_BACKUP", ret = 1); 22806694Svikram if (ret != 0) { 22816694Svikram bam_error(MENU_BACKUP_FAIL, GRUB_BACKUP_MENU); 22826694Svikram return (BAM_ERROR); 22836694Svikram } 22846694Svikram BAM_DPRINTF((D_CREATED_BACKUP, fcn, GRUB_BACKUP_MENU)); 22856694Svikram 22866694Svikram (void) snprintf(cmdline, sizeof (cmdline), 22877048Svikram "/bin/sh -c '. %s > /dev/null; %s %s no > /dev/null'", 22886694Svikram LULIB, LULIB_PROPAGATE_FILE, GRUB_BACKUP_MENU); 22896694Svikram ret = exec_cmd(cmdline, NULL); 22906694Svikram INJECT_ERROR1("PROPAGATE_BACKUP", ret = 1); 22916694Svikram if (ret != 0) { 22926694Svikram bam_error(BACKUP_PROP_FAIL, GRUB_BACKUP_MENU); 22936694Svikram return (BAM_ERROR); 22946694Svikram } 22956694Svikram BAM_DPRINTF((D_PROPAGATED_BACKUP, fcn, GRUB_BACKUP_MENU)); 22966694Svikram 22976694Svikram (void) snprintf(cmdline, sizeof (cmdline), "%s %s > %s", 22986694Svikram CKSUM, GRUB_MENU, LU_MENU_CKSUM); 22996694Svikram ret = exec_cmd(cmdline, NULL); 23006694Svikram INJECT_ERROR1("CREATE_CKSUM_FILE", ret = 1); 23016694Svikram if (ret != 0) { 23026694Svikram bam_error(MENU_CKSUM_WRITE_FAIL, LU_MENU_CKSUM); 23036694Svikram return (BAM_ERROR); 23046694Svikram } 23056694Svikram BAM_DPRINTF((D_CREATED_CKSUM_FILE, fcn, LU_MENU_CKSUM)); 23066694Svikram 23076694Svikram (void) snprintf(cmdline, sizeof (cmdline), 23087048Svikram "/bin/sh -c '. %s > /dev/null; %s %s no > /dev/null'", 23096694Svikram LULIB, LULIB_PROPAGATE_FILE, LU_MENU_CKSUM); 23106694Svikram ret = exec_cmd(cmdline, NULL); 23116694Svikram INJECT_ERROR1("PROPAGATE_MENU_CKSUM_FILE", ret = 1); 23126694Svikram if (ret != 0) { 23136694Svikram bam_error(MENU_CKSUM_PROP_FAIL, LU_MENU_CKSUM); 23146694Svikram return (BAM_ERROR); 23156694Svikram } 23166694Svikram BAM_DPRINTF((D_PROPAGATED_CKSUM_FILE, fcn, LU_MENU_CKSUM)); 23176694Svikram 23186694Svikram (void) snprintf(cmdline, sizeof (cmdline), 23197048Svikram "/bin/sh -c '. %s > /dev/null; %s %s no > /dev/null'", 23206694Svikram LULIB, LULIB_PROPAGATE_FILE, BOOTADM); 23216694Svikram ret = exec_cmd(cmdline, NULL); 23226694Svikram INJECT_ERROR1("PROPAGATE_BOOTADM_FILE", ret = 1); 23236694Svikram if (ret != 0) { 23246694Svikram bam_error(BOOTADM_PROP_FAIL, BOOTADM); 23256694Svikram return (BAM_ERROR); 23266694Svikram } 23276694Svikram BAM_DPRINTF((D_PROPAGATED_BOOTADM, fcn, BOOTADM)); 23286694Svikram 23296694Svikram return (BAM_SUCCESS); 23301746Svikram } 23311746Svikram 23320Sstevel@tonic-gate static error_t 23330Sstevel@tonic-gate update_all(char *root, char *opt) 23340Sstevel@tonic-gate { 23350Sstevel@tonic-gate struct extmnttab mnt; 23360Sstevel@tonic-gate struct stat sb; 23370Sstevel@tonic-gate FILE *fp; 23380Sstevel@tonic-gate char multibt[PATH_MAX]; 23395648Ssetje char creatram[PATH_MAX]; 23400Sstevel@tonic-gate error_t ret = BAM_SUCCESS; 23410Sstevel@tonic-gate 2342621Svikram assert(root); 23430Sstevel@tonic-gate assert(opt == NULL); 23440Sstevel@tonic-gate 2345621Svikram if (bam_rootlen != 1 || *root != '/') { 2346621Svikram elide_trailing_slash(root, multibt, sizeof (multibt)); 2347621Svikram bam_error(ALT_ROOT_INVALID, multibt); 2348621Svikram return (BAM_ERROR); 2349621Svikram } 2350621Svikram 23510Sstevel@tonic-gate /* 23524493Snadkarni * Check to see if we are in the midst of safemode patching 23534493Snadkarni * If so skip building the archive for /. Instead build it 23544493Snadkarni * against the latest bits obtained by creating a fresh lofs 23554493Snadkarni * mount of root. 23560Sstevel@tonic-gate */ 23574493Snadkarni if (stat(LOFS_PATCH_FILE, &sb) == 0) { 23584493Snadkarni if (mkdir(LOFS_PATCH_MNT, 0755) == -1 && 23594493Snadkarni errno != EEXIST) { 23604493Snadkarni bam_error(MKDIR_FAILED, "%s", LOFS_PATCH_MNT, 23614493Snadkarni strerror(errno)); 23624493Snadkarni ret = BAM_ERROR; 23634493Snadkarni goto out; 23644493Snadkarni } 23654493Snadkarni (void) snprintf(multibt, sizeof (multibt), 23664493Snadkarni "/sbin/mount -F lofs -o nosub / %s", LOFS_PATCH_MNT); 23675648Ssetje if (exec_cmd(multibt, NULL) != 0) { 23684493Snadkarni bam_error(MOUNT_FAILED, LOFS_PATCH_MNT, "lofs"); 23694493Snadkarni ret = BAM_ERROR; 23704493Snadkarni } 23714493Snadkarni if (ret != BAM_ERROR) { 23724493Snadkarni (void) snprintf(rootbuf, sizeof (rootbuf), "%s/", 23734493Snadkarni LOFS_PATCH_MNT); 23744493Snadkarni bam_rootlen = strlen(rootbuf); 23754493Snadkarni if (update_archive(rootbuf, opt) != BAM_SUCCESS) 23764493Snadkarni ret = BAM_ERROR; 23774550Snadkarni /* 23784550Snadkarni * unmount the lofs mount since there could be 23794550Snadkarni * multiple invocations of bootadm -a update_all 23804550Snadkarni */ 23814550Snadkarni (void) snprintf(multibt, sizeof (multibt), 23824550Snadkarni "/sbin/umount %s", LOFS_PATCH_MNT); 23835648Ssetje if (exec_cmd(multibt, NULL) != 0) { 23844550Snadkarni bam_error(UMOUNT_FAILED, LOFS_PATCH_MNT); 23854550Snadkarni ret = BAM_ERROR; 23864550Snadkarni } 23874493Snadkarni } 23884493Snadkarni } else { 23894493Snadkarni /* 23904493Snadkarni * First update archive for current root 23914493Snadkarni */ 23924493Snadkarni if (update_archive(root, opt) != BAM_SUCCESS) 23934493Snadkarni ret = BAM_ERROR; 23944493Snadkarni } 23954493Snadkarni 23964493Snadkarni if (ret == BAM_ERROR) 23974493Snadkarni goto out; 23980Sstevel@tonic-gate 23990Sstevel@tonic-gate /* 24000Sstevel@tonic-gate * Now walk the mount table, performing archive update 24010Sstevel@tonic-gate * for all mounted Newboot root filesystems 24020Sstevel@tonic-gate */ 24030Sstevel@tonic-gate fp = fopen(MNTTAB, "r"); 24040Sstevel@tonic-gate if (fp == NULL) { 24050Sstevel@tonic-gate bam_error(OPEN_FAIL, MNTTAB, strerror(errno)); 2406316Svikram ret = BAM_ERROR; 2407316Svikram goto out; 24080Sstevel@tonic-gate } 24090Sstevel@tonic-gate 24100Sstevel@tonic-gate resetmnttab(fp); 24110Sstevel@tonic-gate 24120Sstevel@tonic-gate while (getextmntent(fp, &mnt, sizeof (mnt)) == 0) { 24130Sstevel@tonic-gate if (mnt.mnt_special == NULL) 24140Sstevel@tonic-gate continue; 24150Sstevel@tonic-gate if (strncmp(mnt.mnt_special, "/dev/", strlen("/dev/")) != 0) 24160Sstevel@tonic-gate continue; 24170Sstevel@tonic-gate if (strcmp(mnt.mnt_mountp, "/") == 0) 24180Sstevel@tonic-gate continue; 24190Sstevel@tonic-gate 24205648Ssetje (void) snprintf(creatram, sizeof (creatram), "%s/%s", 24215648Ssetje mnt.mnt_mountp, CREATE_RAMDISK); 24225648Ssetje 24235648Ssetje if (stat(creatram, &sb) == -1) 24240Sstevel@tonic-gate continue; 24250Sstevel@tonic-gate 24260Sstevel@tonic-gate /* 24270Sstevel@tonic-gate * We put a trailing slash to be consistent with root = "/" 24280Sstevel@tonic-gate * case, such that we don't have to print // in some cases. 24290Sstevel@tonic-gate */ 24300Sstevel@tonic-gate (void) snprintf(rootbuf, sizeof (rootbuf), "%s/", 24310Sstevel@tonic-gate mnt.mnt_mountp); 24320Sstevel@tonic-gate bam_rootlen = strlen(rootbuf); 24333446Smrj 24343446Smrj /* 24353446Smrj * It's possible that other mounts may be an alternate boot 24363446Smrj * architecture, so check it again. 24373446Smrj */ 24386448Svikram if ((get_boot_cap(rootbuf) != BAM_SUCCESS) || 24393446Smrj (update_archive(rootbuf, opt) != BAM_SUCCESS)) 24400Sstevel@tonic-gate ret = BAM_ERROR; 24410Sstevel@tonic-gate } 24420Sstevel@tonic-gate 24430Sstevel@tonic-gate (void) fclose(fp); 24440Sstevel@tonic-gate 2445316Svikram out: 24461746Svikram /* 24476694Svikram * We no longer use biosdev for Live Upgrade. Hence 24486694Svikram * there is no need to defer (to shutdown time) any fdisk 24496694Svikram * updates 24501746Svikram */ 24516694Svikram if (stat(GRUB_fdisk, &sb) == 0 || stat(GRUB_fdisk_target, &sb) == 0) { 24526694Svikram bam_error(FDISK_FILES_FOUND, GRUB_fdisk, GRUB_fdisk_target); 24536694Svikram } 24546694Svikram 24556694Svikram /* 24566694Svikram * If user has updated menu in current BE, propagate the 24576694Svikram * updates to all BEs. 24586694Svikram */ 24596694Svikram if (synchronize_BE_menu() != BAM_SUCCESS) 24601746Svikram ret = BAM_ERROR; 24611746Svikram 24620Sstevel@tonic-gate return (ret); 24630Sstevel@tonic-gate } 24640Sstevel@tonic-gate 24650Sstevel@tonic-gate static void 24660Sstevel@tonic-gate append_line(menu_t *mp, line_t *lp) 24670Sstevel@tonic-gate { 24680Sstevel@tonic-gate if (mp->start == NULL) { 24690Sstevel@tonic-gate mp->start = lp; 24700Sstevel@tonic-gate } else { 24710Sstevel@tonic-gate mp->end->next = lp; 2472662Sszhou lp->prev = mp->end; 24730Sstevel@tonic-gate } 24740Sstevel@tonic-gate mp->end = lp; 24750Sstevel@tonic-gate } 24760Sstevel@tonic-gate 24776448Svikram void 2478662Sszhou unlink_line(menu_t *mp, line_t *lp) 2479662Sszhou { 2480662Sszhou /* unlink from list */ 2481662Sszhou if (lp->prev) 2482662Sszhou lp->prev->next = lp->next; 2483662Sszhou else 2484662Sszhou mp->start = lp->next; 2485662Sszhou if (lp->next) 2486662Sszhou lp->next->prev = lp->prev; 2487662Sszhou else 2488662Sszhou mp->end = lp->prev; 2489662Sszhou } 2490662Sszhou 2491662Sszhou static entry_t * 2492662Sszhou boot_entry_new(menu_t *mp, line_t *start, line_t *end) 2493662Sszhou { 2494662Sszhou entry_t *ent, *prev; 24956448Svikram const char *fcn = "boot_entry_new()"; 24966448Svikram 24976448Svikram assert(mp); 24986448Svikram assert(start); 24996448Svikram assert(end); 2500662Sszhou 2501662Sszhou ent = s_calloc(1, sizeof (entry_t)); 25026448Svikram BAM_DPRINTF((D_ENTRY_NEW, fcn)); 2503662Sszhou ent->start = start; 2504662Sszhou ent->end = end; 2505662Sszhou 2506662Sszhou if (mp->entries == NULL) { 2507662Sszhou mp->entries = ent; 25086448Svikram BAM_DPRINTF((D_ENTRY_NEW_FIRST, fcn)); 2509662Sszhou return (ent); 2510662Sszhou } 2511662Sszhou 2512662Sszhou prev = mp->entries; 2513662Sszhou while (prev->next) 25146448Svikram prev = prev->next; 2515662Sszhou prev->next = ent; 2516662Sszhou ent->prev = prev; 25176448Svikram BAM_DPRINTF((D_ENTRY_NEW_LINKED, fcn)); 2518662Sszhou return (ent); 2519662Sszhou } 2520662Sszhou 2521662Sszhou static void 2522662Sszhou boot_entry_addline(entry_t *ent, line_t *lp) 2523662Sszhou { 2524662Sszhou if (ent) 2525662Sszhou ent->end = lp; 2526662Sszhou } 2527662Sszhou 25280Sstevel@tonic-gate /* 25295084Sjohnlev * Check whether cmd matches the one indexed by which, and whether arg matches 25305084Sjohnlev * str. which must be either KERNEL_CMD or MODULE_CMD, and a match to the 25315084Sjohnlev * respective *_DOLLAR_CMD is also acceptable. The arg is searched using 25325084Sjohnlev * strstr(), so it can be a partial match. 25335084Sjohnlev */ 25345084Sjohnlev static int 25355084Sjohnlev check_cmd(const char *cmd, const int which, const char *arg, const char *str) 25365084Sjohnlev { 25376448Svikram int ret; 25386448Svikram const char *fcn = "check_cmd()"; 25396448Svikram 25406448Svikram BAM_DPRINTF((D_FUNC_ENTRY2, fcn, arg, str)); 25416448Svikram 25425084Sjohnlev if ((strcmp(cmd, menu_cmds[which]) != 0) && 25435084Sjohnlev (strcmp(cmd, menu_cmds[which + 1]) != 0)) { 25446448Svikram BAM_DPRINTF((D_CHECK_CMD_CMD_NOMATCH, 25456448Svikram fcn, cmd, menu_cmds[which])); 25465084Sjohnlev return (0); 25475084Sjohnlev } 25486448Svikram ret = (strstr(arg, str) != NULL); 25496448Svikram 25506448Svikram if (ret) { 25516448Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 25526448Svikram } else { 25536448Svikram BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 25546448Svikram } 25556448Svikram 25566448Svikram return (ret); 25576448Svikram } 25586448Svikram 25596448Svikram static error_t 25606448Svikram kernel_parser(entry_t *entry, char *cmd, char *arg, int linenum) 25616448Svikram { 25626448Svikram const char *fcn = "kernel_parser()"; 25636448Svikram 25646448Svikram assert(entry); 25656448Svikram assert(cmd); 25666448Svikram assert(arg); 25676448Svikram 25686448Svikram if (strcmp(cmd, menu_cmds[KERNEL_CMD]) != 0 && 25696448Svikram strcmp(cmd, menu_cmds[KERNEL_DOLLAR_CMD]) != 0) { 25706448Svikram BAM_DPRINTF((D_NOT_KERNEL_CMD, fcn, cmd)); 25716448Svikram return (BAM_ERROR); 25726448Svikram } 25736448Svikram 25746448Svikram if (strncmp(arg, DIRECT_BOOT_32, sizeof (DIRECT_BOOT_32) - 1) == 0) { 25756448Svikram BAM_DPRINTF((D_SET_DBOOT_32, fcn, arg)); 25766448Svikram entry->flags |= BAM_ENTRY_DBOOT | BAM_ENTRY_32BIT; 25776448Svikram } else if (strncmp(arg, DIRECT_BOOT_KERNEL, 25786448Svikram sizeof (DIRECT_BOOT_KERNEL) - 1) == 0) { 25796448Svikram BAM_DPRINTF((D_SET_DBOOT, fcn, arg)); 25806448Svikram entry->flags |= BAM_ENTRY_DBOOT; 25816448Svikram } else if (strncmp(arg, DIRECT_BOOT_64, 25826448Svikram sizeof (DIRECT_BOOT_64) - 1) == 0) { 25836448Svikram BAM_DPRINTF((D_SET_DBOOT_64, fcn, arg)); 25846448Svikram entry->flags |= BAM_ENTRY_DBOOT | BAM_ENTRY_64BIT; 25856448Svikram } else if (strncmp(arg, DIRECT_BOOT_FAILSAFE_KERNEL, 25866448Svikram sizeof (DIRECT_BOOT_FAILSAFE_KERNEL) - 1) == 0) { 25876448Svikram BAM_DPRINTF((D_SET_DBOOT_FAILSAFE, fcn, arg)); 25886448Svikram entry->flags |= BAM_ENTRY_DBOOT | BAM_ENTRY_FAILSAFE; 25896448Svikram } else if (strncmp(arg, MULTI_BOOT, sizeof (MULTI_BOOT) - 1) == 0) { 25906448Svikram BAM_DPRINTF((D_SET_MULTIBOOT, fcn, arg)); 25916448Svikram entry->flags |= BAM_ENTRY_MULTIBOOT; 25926448Svikram } else if (strncmp(arg, MULTI_BOOT_FAILSAFE, 25936448Svikram sizeof (MULTI_BOOT_FAILSAFE) - 1) == 0) { 25946448Svikram BAM_DPRINTF((D_SET_MULTIBOOT_FAILSAFE, fcn, arg)); 25956448Svikram entry->flags |= BAM_ENTRY_MULTIBOOT | BAM_ENTRY_FAILSAFE; 25966448Svikram } else if (strstr(arg, XEN_KERNEL_SUBSTR)) { 25976448Svikram BAM_DPRINTF((D_SET_HV, fcn, arg)); 25986448Svikram entry->flags |= BAM_ENTRY_HV; 25996448Svikram } else if (!(entry->flags & (BAM_ENTRY_BOOTADM|BAM_ENTRY_LU))) { 26006448Svikram BAM_DPRINTF((D_SET_HAND_KERNEL, fcn, arg)); 26016448Svikram return (BAM_ERROR); 26026448Svikram } else { 26036448Svikram BAM_DPRINTF((D_IS_UNKNOWN_KERNEL, fcn, arg)); 26046448Svikram bam_error(UNKNOWN_KERNEL_LINE, linenum); 26056448Svikram return (BAM_ERROR); 26066448Svikram } 26076448Svikram 26086448Svikram return (BAM_SUCCESS); 26096448Svikram } 26106448Svikram 26116448Svikram static error_t 26126448Svikram module_parser(entry_t *entry, char *cmd, char *arg, int linenum) 26136448Svikram { 26146448Svikram const char *fcn = "module_parser()"; 26156448Svikram 26166448Svikram assert(entry); 26176448Svikram assert(cmd); 26186448Svikram assert(arg); 26196448Svikram 26206448Svikram if (strcmp(cmd, menu_cmds[MODULE_CMD]) != 0 && 26216448Svikram strcmp(cmd, menu_cmds[MODULE_DOLLAR_CMD]) != 0) { 26226448Svikram BAM_DPRINTF((D_NOT_MODULE_CMD, fcn, cmd)); 26236448Svikram return (BAM_ERROR); 26246448Svikram } 26256448Svikram 26266448Svikram if (strcmp(arg, DIRECT_BOOT_ARCHIVE) == 0 || 26276448Svikram strcmp(arg, DIRECT_BOOT_ARCHIVE_32) == 0 || 26286448Svikram strcmp(arg, DIRECT_BOOT_ARCHIVE_64) == 0 || 26296448Svikram strcmp(arg, MULTIBOOT_ARCHIVE) == 0 || 26306448Svikram strcmp(arg, FAILSAFE_ARCHIVE) == 0 || 26316448Svikram strcmp(arg, XEN_KERNEL_MODULE_LINE) == 0 || 26326448Svikram strcmp(arg, XEN_KERNEL_MODULE_LINE_ZFS) == 0) { 26336448Svikram BAM_DPRINTF((D_BOOTADM_LU_MODULE, fcn, arg)); 26346448Svikram return (BAM_SUCCESS); 26356448Svikram } else if (!(entry->flags & BAM_ENTRY_BOOTADM) && 26366448Svikram !(entry->flags & BAM_ENTRY_LU)) { 26376448Svikram /* don't emit warning for hand entries */ 26386448Svikram BAM_DPRINTF((D_IS_HAND_MODULE, fcn, arg)); 26396448Svikram return (BAM_ERROR); 26406448Svikram } else { 26416448Svikram BAM_DPRINTF((D_IS_UNKNOWN_MODULE, fcn, arg)); 26426448Svikram bam_error(UNKNOWN_MODULE_LINE, linenum); 26436448Svikram return (BAM_ERROR); 26446448Svikram } 26455084Sjohnlev } 26465084Sjohnlev 26475084Sjohnlev /* 26480Sstevel@tonic-gate * A line in menu.lst looks like 26490Sstevel@tonic-gate * [ ]*<cmd>[ \t=]*<arg>* 26500Sstevel@tonic-gate */ 26510Sstevel@tonic-gate static void 26520Sstevel@tonic-gate line_parser(menu_t *mp, char *str, int *lineNum, int *entryNum) 26530Sstevel@tonic-gate { 26540Sstevel@tonic-gate /* 26550Sstevel@tonic-gate * save state across calls. This is so that 26560Sstevel@tonic-gate * header gets the right entry# after title has 26570Sstevel@tonic-gate * been processed 26580Sstevel@tonic-gate */ 2659662Sszhou static line_t *prev = NULL; 2660662Sszhou static entry_t *curr_ent = NULL; 26613446Smrj static int in_liveupgrade = 0; 26620Sstevel@tonic-gate 26630Sstevel@tonic-gate line_t *lp; 26640Sstevel@tonic-gate char *cmd, *sep, *arg; 26650Sstevel@tonic-gate char save, *cp, *line; 26660Sstevel@tonic-gate menu_flag_t flag = BAM_INVALID; 26676448Svikram const char *fcn = "line_parser()"; 26680Sstevel@tonic-gate 26690Sstevel@tonic-gate if (str == NULL) { 26700Sstevel@tonic-gate return; 26710Sstevel@tonic-gate } 26720Sstevel@tonic-gate 26730Sstevel@tonic-gate /* 26740Sstevel@tonic-gate * First save a copy of the entire line. 26750Sstevel@tonic-gate * We use this later to set the line field. 26760Sstevel@tonic-gate */ 26770Sstevel@tonic-gate line = s_strdup(str); 26780Sstevel@tonic-gate 26790Sstevel@tonic-gate /* Eat up leading whitespace */ 26800Sstevel@tonic-gate while (*str == ' ' || *str == '\t') 26810Sstevel@tonic-gate str++; 26820Sstevel@tonic-gate 26830Sstevel@tonic-gate if (*str == '#') { /* comment */ 26840Sstevel@tonic-gate cmd = s_strdup("#"); 26850Sstevel@tonic-gate sep = NULL; 26860Sstevel@tonic-gate arg = s_strdup(str + 1); 26870Sstevel@tonic-gate flag = BAM_COMMENT; 26883446Smrj if (strstr(arg, BAM_LU_HDR) != NULL) { 26893446Smrj in_liveupgrade = 1; 26903446Smrj } else if (strstr(arg, BAM_LU_FTR) != NULL) { 26913446Smrj in_liveupgrade = 0; 26923446Smrj } 26930Sstevel@tonic-gate } else if (*str == '\0') { /* blank line */ 26940Sstevel@tonic-gate cmd = sep = arg = NULL; 26950Sstevel@tonic-gate flag = BAM_EMPTY; 26960Sstevel@tonic-gate } else { 26970Sstevel@tonic-gate /* 26980Sstevel@tonic-gate * '=' is not a documented separator in grub syntax. 26990Sstevel@tonic-gate * However various development bits use '=' as a 27000Sstevel@tonic-gate * separator. In addition, external users also 27010Sstevel@tonic-gate * use = as a separator. So we will allow that usage. 27020Sstevel@tonic-gate */ 27030Sstevel@tonic-gate cp = str; 27040Sstevel@tonic-gate while (*str != ' ' && *str != '\t' && *str != '=') { 27050Sstevel@tonic-gate if (*str == '\0') { 27060Sstevel@tonic-gate cmd = s_strdup(cp); 27070Sstevel@tonic-gate sep = arg = NULL; 27080Sstevel@tonic-gate break; 27090Sstevel@tonic-gate } 27100Sstevel@tonic-gate str++; 27110Sstevel@tonic-gate } 27120Sstevel@tonic-gate 27130Sstevel@tonic-gate if (*str != '\0') { 27140Sstevel@tonic-gate save = *str; 27150Sstevel@tonic-gate *str = '\0'; 27160Sstevel@tonic-gate cmd = s_strdup(cp); 27170Sstevel@tonic-gate *str = save; 27180Sstevel@tonic-gate 27190Sstevel@tonic-gate str++; 27200Sstevel@tonic-gate save = *str; 27210Sstevel@tonic-gate *str = '\0'; 27220Sstevel@tonic-gate sep = s_strdup(str - 1); 27230Sstevel@tonic-gate *str = save; 27240Sstevel@tonic-gate 27250Sstevel@tonic-gate while (*str == ' ' || *str == '\t') 27260Sstevel@tonic-gate str++; 27270Sstevel@tonic-gate if (*str == '\0') 27280Sstevel@tonic-gate arg = NULL; 27290Sstevel@tonic-gate else 27300Sstevel@tonic-gate arg = s_strdup(str); 27310Sstevel@tonic-gate } 27320Sstevel@tonic-gate } 27330Sstevel@tonic-gate 27340Sstevel@tonic-gate lp = s_calloc(1, sizeof (line_t)); 27350Sstevel@tonic-gate 27360Sstevel@tonic-gate lp->cmd = cmd; 27370Sstevel@tonic-gate lp->sep = sep; 27380Sstevel@tonic-gate lp->arg = arg; 27390Sstevel@tonic-gate lp->line = line; 27400Sstevel@tonic-gate lp->lineNum = ++(*lineNum); 27410Sstevel@tonic-gate if (cmd && strcmp(cmd, menu_cmds[TITLE_CMD]) == 0) { 27420Sstevel@tonic-gate lp->entryNum = ++(*entryNum); 27430Sstevel@tonic-gate lp->flags = BAM_TITLE; 27440Sstevel@tonic-gate if (prev && prev->flags == BAM_COMMENT && 27453446Smrj prev->arg && strcmp(prev->arg, BAM_BOOTADM_HDR) == 0) { 27460Sstevel@tonic-gate prev->entryNum = lp->entryNum; 2747662Sszhou curr_ent = boot_entry_new(mp, prev, lp); 27486448Svikram curr_ent->flags |= BAM_ENTRY_BOOTADM; 27496448Svikram BAM_DPRINTF((D_IS_BOOTADM_ENTRY, fcn, arg)); 2750662Sszhou } else { 2751662Sszhou curr_ent = boot_entry_new(mp, lp, lp); 27523446Smrj if (in_liveupgrade) { 27536448Svikram curr_ent->flags |= BAM_ENTRY_LU; 27546448Svikram BAM_DPRINTF((D_IS_LU_ENTRY, fcn, arg)); 27553446Smrj } 2756662Sszhou } 27573446Smrj curr_ent->entryNum = *entryNum; 27580Sstevel@tonic-gate } else if (flag != BAM_INVALID) { 27590Sstevel@tonic-gate /* 27600Sstevel@tonic-gate * For header comments, the entry# is "fixed up" 27610Sstevel@tonic-gate * by the subsequent title 27620Sstevel@tonic-gate */ 27630Sstevel@tonic-gate lp->entryNum = *entryNum; 27640Sstevel@tonic-gate lp->flags = flag; 27650Sstevel@tonic-gate } else { 27660Sstevel@tonic-gate lp->entryNum = *entryNum; 27673446Smrj 27683446Smrj if (*entryNum == ENTRY_INIT) { 27693446Smrj lp->flags = BAM_GLOBAL; 27703446Smrj } else { 27713446Smrj lp->flags = BAM_ENTRY; 27723446Smrj 27733446Smrj if (cmd && arg) { 27746448Svikram if (strcmp(cmd, menu_cmds[ROOT_CMD]) == 0) { 27756448Svikram BAM_DPRINTF((D_IS_ROOT_CMD, fcn, arg)); 27763446Smrj curr_ent->flags |= BAM_ENTRY_ROOT; 27776448Svikram } else if (strcmp(cmd, menu_cmds[FINDROOT_CMD]) 27786448Svikram == 0) { 27796448Svikram BAM_DPRINTF((D_IS_FINDROOT_CMD, fcn, 27806448Svikram arg)); 27816448Svikram curr_ent->flags |= BAM_ENTRY_FINDROOT; 27826448Svikram } else if (strcmp(cmd, 27836448Svikram menu_cmds[CHAINLOADER_CMD]) == 0) { 27846448Svikram BAM_DPRINTF((D_IS_CHAINLOADER_CMD, fcn, 27856448Svikram arg)); 27863446Smrj curr_ent->flags |= 27873446Smrj BAM_ENTRY_CHAINLOADER; 27886448Svikram } else if (kernel_parser(curr_ent, cmd, arg, 27896448Svikram lp->lineNum) != BAM_SUCCESS) { 27906448Svikram (void) module_parser(curr_ent, cmd, 27916448Svikram arg, lp->lineNum); 27926448Svikram } 27933446Smrj } 27943446Smrj } 27950Sstevel@tonic-gate } 27960Sstevel@tonic-gate 2797662Sszhou /* record default, old default, and entry line ranges */ 2798662Sszhou if (lp->flags == BAM_GLOBAL && 2799662Sszhou strcmp(lp->cmd, menu_cmds[DEFAULT_CMD]) == 0) { 2800662Sszhou mp->curdefault = lp; 2801662Sszhou } else if (lp->flags == BAM_COMMENT && 2802662Sszhou strncmp(lp->arg, BAM_OLDDEF, strlen(BAM_OLDDEF)) == 0) { 2803662Sszhou mp->olddefault = lp; 28043446Smrj } else if (lp->flags == BAM_COMMENT && 28053446Smrj strncmp(lp->arg, BAM_OLD_RC_DEF, strlen(BAM_OLD_RC_DEF)) == 0) { 28063446Smrj mp->old_rc_default = lp; 2807662Sszhou } else if (lp->flags == BAM_ENTRY || 28083446Smrj (lp->flags == BAM_COMMENT && 28093446Smrj strcmp(lp->arg, BAM_BOOTADM_FTR) == 0)) { 2810662Sszhou boot_entry_addline(curr_ent, lp); 2811662Sszhou } 28120Sstevel@tonic-gate append_line(mp, lp); 28130Sstevel@tonic-gate 28140Sstevel@tonic-gate prev = lp; 28150Sstevel@tonic-gate } 28160Sstevel@tonic-gate 28176448Svikram void 2818621Svikram update_numbering(menu_t *mp) 2819621Svikram { 2820621Svikram int lineNum; 2821621Svikram int entryNum; 2822621Svikram int old_default_value; 2823621Svikram line_t *lp, *prev, *default_lp, *default_entry; 2824621Svikram char buf[PATH_MAX]; 2825621Svikram 2826621Svikram if (mp->start == NULL) { 2827621Svikram return; 2828621Svikram } 2829621Svikram 2830621Svikram lineNum = LINE_INIT; 2831621Svikram entryNum = ENTRY_INIT; 2832621Svikram old_default_value = ENTRY_INIT; 2833621Svikram lp = default_lp = default_entry = NULL; 2834621Svikram 2835621Svikram prev = NULL; 2836621Svikram for (lp = mp->start; lp; prev = lp, lp = lp->next) { 2837621Svikram lp->lineNum = ++lineNum; 2838621Svikram 2839621Svikram /* 2840621Svikram * Get the value of the default command 2841621Svikram */ 2842621Svikram if (lp->entryNum == ENTRY_INIT && lp->cmd && 2843621Svikram strcmp(lp->cmd, menu_cmds[DEFAULT_CMD]) == 0 && 2844621Svikram lp->arg) { 2845621Svikram old_default_value = atoi(lp->arg); 2846621Svikram default_lp = lp; 2847621Svikram } 2848621Svikram 2849621Svikram /* 28506448Svikram * If not a booting entry, nothing else to fix for this 2851621Svikram * entry 2852621Svikram */ 2853621Svikram if (lp->entryNum == ENTRY_INIT) 2854621Svikram continue; 2855621Svikram 2856621Svikram /* 2857621Svikram * Record the position of the default entry. 2858621Svikram * The following works because global 2859621Svikram * commands like default and timeout should precede 2860621Svikram * actual boot entries, so old_default_value 2861621Svikram * is already known (or default cmd is missing). 2862621Svikram */ 2863621Svikram if (default_entry == NULL && 2864621Svikram old_default_value != ENTRY_INIT && 2865621Svikram lp->entryNum == old_default_value) { 2866621Svikram default_entry = lp; 2867621Svikram } 2868621Svikram 2869621Svikram /* 2870621Svikram * Now fixup the entry number 2871621Svikram */ 2872621Svikram if (lp->cmd && strcmp(lp->cmd, menu_cmds[TITLE_CMD]) == 0) { 2873621Svikram lp->entryNum = ++entryNum; 2874621Svikram /* fixup the bootadm header */ 2875621Svikram if (prev && prev->flags == BAM_COMMENT && 28763446Smrj prev->arg && 28773446Smrj strcmp(prev->arg, BAM_BOOTADM_HDR) == 0) { 2878621Svikram prev->entryNum = lp->entryNum; 2879621Svikram } 2880621Svikram } else { 2881621Svikram lp->entryNum = entryNum; 2882621Svikram } 2883621Svikram } 2884621Svikram 2885621Svikram /* 2886621Svikram * No default command in menu, simply return 2887621Svikram */ 2888621Svikram if (default_lp == NULL) { 2889621Svikram return; 2890621Svikram } 2891621Svikram 2892621Svikram free(default_lp->arg); 2893621Svikram free(default_lp->line); 2894621Svikram 2895621Svikram if (default_entry == NULL) { 2896621Svikram default_lp->arg = s_strdup("0"); 2897621Svikram } else { 2898621Svikram (void) snprintf(buf, sizeof (buf), "%d", 2899621Svikram default_entry->entryNum); 2900621Svikram default_lp->arg = s_strdup(buf); 2901621Svikram } 2902621Svikram 2903621Svikram /* 2904621Svikram * The following is required since only the line field gets 2905621Svikram * written back to menu.lst 2906621Svikram */ 2907621Svikram (void) snprintf(buf, sizeof (buf), "%s%s%s", 2908621Svikram menu_cmds[DEFAULT_CMD], menu_cmds[SEP_CMD], default_lp->arg); 2909621Svikram default_lp->line = s_strdup(buf); 2910621Svikram } 2911621Svikram 2912621Svikram 29130Sstevel@tonic-gate static menu_t * 29140Sstevel@tonic-gate menu_read(char *menu_path) 29150Sstevel@tonic-gate { 29160Sstevel@tonic-gate FILE *fp; 29170Sstevel@tonic-gate char buf[BAM_MAXLINE], *cp; 29180Sstevel@tonic-gate menu_t *mp; 29190Sstevel@tonic-gate int line, entry, len, n; 29200Sstevel@tonic-gate 29210Sstevel@tonic-gate mp = s_calloc(1, sizeof (menu_t)); 29220Sstevel@tonic-gate 29230Sstevel@tonic-gate fp = fopen(menu_path, "r"); 29240Sstevel@tonic-gate if (fp == NULL) { /* Let the caller handle this error */ 29250Sstevel@tonic-gate return (mp); 29260Sstevel@tonic-gate } 29270Sstevel@tonic-gate 29280Sstevel@tonic-gate 29290Sstevel@tonic-gate /* Note: GRUB boot entry number starts with 0 */ 29300Sstevel@tonic-gate line = LINE_INIT; 29310Sstevel@tonic-gate entry = ENTRY_INIT; 29320Sstevel@tonic-gate cp = buf; 29330Sstevel@tonic-gate len = sizeof (buf); 29340Sstevel@tonic-gate while (s_fgets(cp, len, fp) != NULL) { 29350Sstevel@tonic-gate n = strlen(cp); 29360Sstevel@tonic-gate if (cp[n - 1] == '\\') { 29370Sstevel@tonic-gate len -= n - 1; 29380Sstevel@tonic-gate assert(len >= 2); 29390Sstevel@tonic-gate cp += n - 1; 29400Sstevel@tonic-gate continue; 29410Sstevel@tonic-gate } 29420Sstevel@tonic-gate line_parser(mp, buf, &line, &entry); 29430Sstevel@tonic-gate cp = buf; 29440Sstevel@tonic-gate len = sizeof (buf); 29450Sstevel@tonic-gate } 29460Sstevel@tonic-gate 29470Sstevel@tonic-gate if (fclose(fp) == EOF) { 29480Sstevel@tonic-gate bam_error(CLOSE_FAIL, menu_path, strerror(errno)); 29490Sstevel@tonic-gate } 29500Sstevel@tonic-gate 29510Sstevel@tonic-gate return (mp); 29520Sstevel@tonic-gate } 29530Sstevel@tonic-gate 29540Sstevel@tonic-gate static error_t 29550Sstevel@tonic-gate selector(menu_t *mp, char *opt, int *entry, char **title) 29560Sstevel@tonic-gate { 29570Sstevel@tonic-gate char *eq; 29580Sstevel@tonic-gate char *opt_dup; 29590Sstevel@tonic-gate int entryNum; 29600Sstevel@tonic-gate 29610Sstevel@tonic-gate assert(mp); 29620Sstevel@tonic-gate assert(mp->start); 29630Sstevel@tonic-gate assert(opt); 29640Sstevel@tonic-gate 29650Sstevel@tonic-gate opt_dup = s_strdup(opt); 29660Sstevel@tonic-gate 29670Sstevel@tonic-gate if (entry) 29680Sstevel@tonic-gate *entry = ENTRY_INIT; 29690Sstevel@tonic-gate if (title) 29700Sstevel@tonic-gate *title = NULL; 29710Sstevel@tonic-gate 29720Sstevel@tonic-gate eq = strchr(opt_dup, '='); 29730Sstevel@tonic-gate if (eq == NULL) { 29740Sstevel@tonic-gate bam_error(INVALID_OPT, opt); 29750Sstevel@tonic-gate free(opt_dup); 29760Sstevel@tonic-gate return (BAM_ERROR); 29770Sstevel@tonic-gate } 29780Sstevel@tonic-gate 29790Sstevel@tonic-gate *eq = '\0'; 29800Sstevel@tonic-gate if (entry && strcmp(opt_dup, OPT_ENTRY_NUM) == 0) { 29810Sstevel@tonic-gate assert(mp->end); 29820Sstevel@tonic-gate entryNum = s_strtol(eq + 1); 29830Sstevel@tonic-gate if (entryNum < 0 || entryNum > mp->end->entryNum) { 29840Sstevel@tonic-gate bam_error(INVALID_ENTRY, eq + 1); 29850Sstevel@tonic-gate free(opt_dup); 29860Sstevel@tonic-gate return (BAM_ERROR); 29870Sstevel@tonic-gate } 29880Sstevel@tonic-gate *entry = entryNum; 29890Sstevel@tonic-gate } else if (title && strcmp(opt_dup, menu_cmds[TITLE_CMD]) == 0) { 29900Sstevel@tonic-gate *title = opt + (eq - opt_dup) + 1; 29910Sstevel@tonic-gate } else { 29920Sstevel@tonic-gate bam_error(INVALID_OPT, opt); 29930Sstevel@tonic-gate free(opt_dup); 29940Sstevel@tonic-gate return (BAM_ERROR); 29950Sstevel@tonic-gate } 29960Sstevel@tonic-gate 29970Sstevel@tonic-gate free(opt_dup); 29980Sstevel@tonic-gate return (BAM_SUCCESS); 29990Sstevel@tonic-gate } 30000Sstevel@tonic-gate 30010Sstevel@tonic-gate /* 30020Sstevel@tonic-gate * If invoked with no titles/entries (opt == NULL) 30030Sstevel@tonic-gate * only title lines in file are printed. 30040Sstevel@tonic-gate * 30050Sstevel@tonic-gate * If invoked with a title or entry #, all 30060Sstevel@tonic-gate * lines in *every* matching entry are listed 30070Sstevel@tonic-gate */ 30080Sstevel@tonic-gate static error_t 30090Sstevel@tonic-gate list_entry(menu_t *mp, char *menu_path, char *opt) 30100Sstevel@tonic-gate { 30110Sstevel@tonic-gate line_t *lp; 30120Sstevel@tonic-gate int entry = ENTRY_INIT; 30130Sstevel@tonic-gate int found; 30140Sstevel@tonic-gate char *title = NULL; 30150Sstevel@tonic-gate 30160Sstevel@tonic-gate assert(mp); 30170Sstevel@tonic-gate assert(menu_path); 30180Sstevel@tonic-gate 30196448Svikram /* opt is optional */ 30206448Svikram BAM_DPRINTF((D_FUNC_ENTRY2, "list_entry", menu_path, 30216448Svikram opt ? opt : "<NULL>")); 30226448Svikram 30230Sstevel@tonic-gate if (mp->start == NULL) { 30240Sstevel@tonic-gate bam_error(NO_MENU, menu_path); 30250Sstevel@tonic-gate return (BAM_ERROR); 30260Sstevel@tonic-gate } 30270Sstevel@tonic-gate 30280Sstevel@tonic-gate if (opt != NULL) { 30290Sstevel@tonic-gate if (selector(mp, opt, &entry, &title) != BAM_SUCCESS) { 30300Sstevel@tonic-gate return (BAM_ERROR); 30310Sstevel@tonic-gate } 30320Sstevel@tonic-gate assert((entry != ENTRY_INIT) ^ (title != NULL)); 30330Sstevel@tonic-gate } else { 30340Sstevel@tonic-gate (void) read_globals(mp, menu_path, menu_cmds[DEFAULT_CMD], 0); 30350Sstevel@tonic-gate (void) read_globals(mp, menu_path, menu_cmds[TIMEOUT_CMD], 0); 30360Sstevel@tonic-gate } 30370Sstevel@tonic-gate 30380Sstevel@tonic-gate found = 0; 30390Sstevel@tonic-gate for (lp = mp->start; lp; lp = lp->next) { 30400Sstevel@tonic-gate if (lp->flags == BAM_COMMENT || lp->flags == BAM_EMPTY) 30410Sstevel@tonic-gate continue; 30420Sstevel@tonic-gate if (opt == NULL && lp->flags == BAM_TITLE) { 30430Sstevel@tonic-gate bam_print(PRINT_TITLE, lp->entryNum, 30440Sstevel@tonic-gate lp->arg); 30450Sstevel@tonic-gate found = 1; 30460Sstevel@tonic-gate continue; 30470Sstevel@tonic-gate } 30480Sstevel@tonic-gate if (entry != ENTRY_INIT && lp->entryNum == entry) { 30490Sstevel@tonic-gate bam_print(PRINT, lp->line); 30500Sstevel@tonic-gate found = 1; 30510Sstevel@tonic-gate continue; 30520Sstevel@tonic-gate } 30530Sstevel@tonic-gate 30540Sstevel@tonic-gate /* 30550Sstevel@tonic-gate * We set the entry value here so that all lines 30560Sstevel@tonic-gate * in entry get printed. If we subsequently match 30570Sstevel@tonic-gate * title in other entries, all lines in those 30580Sstevel@tonic-gate * entries get printed as well. 30590Sstevel@tonic-gate */ 30600Sstevel@tonic-gate if (title && lp->flags == BAM_TITLE && lp->arg && 30610Sstevel@tonic-gate strncmp(title, lp->arg, strlen(title)) == 0) { 30620Sstevel@tonic-gate bam_print(PRINT, lp->line); 30630Sstevel@tonic-gate entry = lp->entryNum; 30640Sstevel@tonic-gate found = 1; 30650Sstevel@tonic-gate continue; 30660Sstevel@tonic-gate } 30670Sstevel@tonic-gate } 30680Sstevel@tonic-gate 30690Sstevel@tonic-gate if (!found) { 30700Sstevel@tonic-gate bam_error(NO_MATCH_ENTRY); 30710Sstevel@tonic-gate return (BAM_ERROR); 30720Sstevel@tonic-gate } 30730Sstevel@tonic-gate 30740Sstevel@tonic-gate return (BAM_SUCCESS); 30750Sstevel@tonic-gate } 30760Sstevel@tonic-gate 30775084Sjohnlev int 30780Sstevel@tonic-gate add_boot_entry(menu_t *mp, 30790Sstevel@tonic-gate char *title, 30806448Svikram char *findroot, 30810Sstevel@tonic-gate char *kernel, 30825084Sjohnlev char *mod_kernel, 30830Sstevel@tonic-gate char *module) 30840Sstevel@tonic-gate { 30856448Svikram int lineNum; 30866448Svikram int entryNum; 30876448Svikram char linebuf[BAM_MAXLINE]; 30886448Svikram menu_cmd_t k_cmd; 30896448Svikram menu_cmd_t m_cmd; 30906448Svikram const char *fcn = "add_boot_entry()"; 30910Sstevel@tonic-gate 30920Sstevel@tonic-gate assert(mp); 30930Sstevel@tonic-gate 30946448Svikram INJECT_ERROR1("ADD_BOOT_ENTRY_FINDROOT_NULL", findroot = NULL); 30956448Svikram if (findroot == NULL) { 30966448Svikram bam_error(NULL_FINDROOT); 30976448Svikram return (BAM_ERROR); 30986448Svikram } 30996448Svikram 31000Sstevel@tonic-gate if (title == NULL) { 3101656Sszhou title = "Solaris"; /* default to Solaris */ 31020Sstevel@tonic-gate } 31030Sstevel@tonic-gate if (kernel == NULL) { 31040Sstevel@tonic-gate bam_error(SUBOPT_MISS, menu_cmds[KERNEL_CMD]); 31050Sstevel@tonic-gate return (BAM_ERROR); 31060Sstevel@tonic-gate } 31070Sstevel@tonic-gate if (module == NULL) { 31083446Smrj if (bam_direct != BAM_DIRECT_DBOOT) { 31093446Smrj bam_error(SUBOPT_MISS, menu_cmds[MODULE_CMD]); 31103446Smrj return (BAM_ERROR); 31113446Smrj } 31123446Smrj 31133446Smrj /* Figure the commands out from the kernel line */ 31143446Smrj if (strstr(kernel, "$ISADIR") != NULL) { 31153446Smrj module = DIRECT_BOOT_ARCHIVE; 31163446Smrj k_cmd = KERNEL_DOLLAR_CMD; 31173446Smrj m_cmd = MODULE_DOLLAR_CMD; 31183446Smrj } else if (strstr(kernel, "amd64") != NULL) { 31193446Smrj module = DIRECT_BOOT_ARCHIVE_64; 31203446Smrj k_cmd = KERNEL_CMD; 31213446Smrj m_cmd = MODULE_CMD; 31223446Smrj } else { 31233446Smrj module = DIRECT_BOOT_ARCHIVE_32; 31243446Smrj k_cmd = KERNEL_CMD; 31253446Smrj m_cmd = MODULE_CMD; 31263446Smrj } 31273446Smrj } else if ((bam_direct == BAM_DIRECT_DBOOT) && 31283446Smrj (strstr(kernel, "$ISADIR") != NULL)) { 31293446Smrj /* 31303446Smrj * If it's a non-failsafe dboot kernel, use the "kernel$" 31313446Smrj * command. Otherwise, use "kernel". 31323446Smrj */ 31333446Smrj k_cmd = KERNEL_DOLLAR_CMD; 31343446Smrj m_cmd = MODULE_DOLLAR_CMD; 31353446Smrj } else { 31363446Smrj k_cmd = KERNEL_CMD; 31373446Smrj m_cmd = MODULE_CMD; 31380Sstevel@tonic-gate } 31390Sstevel@tonic-gate 31400Sstevel@tonic-gate if (mp->start) { 31410Sstevel@tonic-gate lineNum = mp->end->lineNum; 31420Sstevel@tonic-gate entryNum = mp->end->entryNum; 31430Sstevel@tonic-gate } else { 31440Sstevel@tonic-gate lineNum = LINE_INIT; 31450Sstevel@tonic-gate entryNum = ENTRY_INIT; 31460Sstevel@tonic-gate } 31470Sstevel@tonic-gate 31480Sstevel@tonic-gate /* 31490Sstevel@tonic-gate * No separator for comment (HDR/FTR) commands 31500Sstevel@tonic-gate * The syntax for comments is #<comment> 31510Sstevel@tonic-gate */ 31520Sstevel@tonic-gate (void) snprintf(linebuf, sizeof (linebuf), "%s%s", 31533446Smrj menu_cmds[COMMENT_CMD], BAM_BOOTADM_HDR); 3154662Sszhou line_parser(mp, linebuf, &lineNum, &entryNum); 31550Sstevel@tonic-gate 31560Sstevel@tonic-gate (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s", 31570Sstevel@tonic-gate menu_cmds[TITLE_CMD], menu_cmds[SEP_CMD], title); 3158662Sszhou line_parser(mp, linebuf, &lineNum, &entryNum); 3159662Sszhou 31606448Svikram (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s", 31616448Svikram menu_cmds[FINDROOT_CMD], menu_cmds[SEP_CMD], findroot); 31626448Svikram line_parser(mp, linebuf, &lineNum, &entryNum); 31636448Svikram BAM_DPRINTF((D_ADD_FINDROOT_NUM, fcn, lineNum, entryNum)); 31640Sstevel@tonic-gate 31650Sstevel@tonic-gate (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s", 31663446Smrj menu_cmds[k_cmd], menu_cmds[SEP_CMD], kernel); 3167662Sszhou line_parser(mp, linebuf, &lineNum, &entryNum); 31680Sstevel@tonic-gate 31695084Sjohnlev if (mod_kernel != NULL) { 31705084Sjohnlev (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s", 31715084Sjohnlev menu_cmds[m_cmd], menu_cmds[SEP_CMD], mod_kernel); 31725084Sjohnlev line_parser(mp, linebuf, &lineNum, &entryNum); 31735084Sjohnlev } 31745084Sjohnlev 31750Sstevel@tonic-gate (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s", 31763446Smrj menu_cmds[m_cmd], menu_cmds[SEP_CMD], module); 3177662Sszhou line_parser(mp, linebuf, &lineNum, &entryNum); 31780Sstevel@tonic-gate 31790Sstevel@tonic-gate (void) snprintf(linebuf, sizeof (linebuf), "%s%s", 31803446Smrj menu_cmds[COMMENT_CMD], BAM_BOOTADM_FTR); 3181662Sszhou line_parser(mp, linebuf, &lineNum, &entryNum); 31820Sstevel@tonic-gate 31830Sstevel@tonic-gate return (entryNum); 31840Sstevel@tonic-gate } 31850Sstevel@tonic-gate 31860Sstevel@tonic-gate static error_t 31870Sstevel@tonic-gate do_delete(menu_t *mp, int entryNum) 31880Sstevel@tonic-gate { 31896448Svikram line_t *lp; 31906448Svikram line_t *freed; 31916448Svikram entry_t *ent; 31926448Svikram entry_t *tmp; 31936448Svikram int deleted; 31946448Svikram const char *fcn = "do_delete()"; 31950Sstevel@tonic-gate 31960Sstevel@tonic-gate assert(entryNum != ENTRY_INIT); 31970Sstevel@tonic-gate 31986448Svikram tmp = NULL; 31996448Svikram 3200662Sszhou ent = mp->entries; 3201662Sszhou while (ent) { 3202662Sszhou lp = ent->start; 3203662Sszhou /* check entry number and make sure it's a bootadm entry */ 3204662Sszhou if (lp->flags != BAM_COMMENT || 32053446Smrj strcmp(lp->arg, BAM_BOOTADM_HDR) != 0 || 3206662Sszhou (entryNum != ALL_ENTRIES && lp->entryNum != entryNum)) { 3207662Sszhou ent = ent->next; 32080Sstevel@tonic-gate continue; 32090Sstevel@tonic-gate } 32100Sstevel@tonic-gate 3211662Sszhou /* free the entry content */ 3212662Sszhou do { 3213662Sszhou freed = lp; 3214662Sszhou lp = lp->next; /* prev stays the same */ 32156448Svikram BAM_DPRINTF((D_FREEING_LINE, fcn, freed->lineNum)); 3216662Sszhou unlink_line(mp, freed); 3217662Sszhou line_free(freed); 3218662Sszhou } while (freed != ent->end); 3219662Sszhou 3220662Sszhou /* free the entry_t structure */ 32216448Svikram assert(tmp == NULL); 3222662Sszhou tmp = ent; 3223662Sszhou ent = ent->next; 3224662Sszhou if (tmp->prev) 3225662Sszhou tmp->prev->next = ent; 32260Sstevel@tonic-gate else 3227662Sszhou mp->entries = ent; 3228662Sszhou if (ent) 3229662Sszhou ent->prev = tmp->prev; 32306448Svikram BAM_DPRINTF((D_FREEING_ENTRY, fcn, tmp->entryNum)); 32316448Svikram free(tmp); 32326448Svikram tmp = NULL; 32330Sstevel@tonic-gate deleted = 1; 32340Sstevel@tonic-gate } 32350Sstevel@tonic-gate 32366448Svikram assert(tmp == NULL); 32376448Svikram 32380Sstevel@tonic-gate if (!deleted && entryNum != ALL_ENTRIES) { 32390Sstevel@tonic-gate bam_error(NO_BOOTADM_MATCH); 32400Sstevel@tonic-gate return (BAM_ERROR); 32410Sstevel@tonic-gate } 32420Sstevel@tonic-gate 3243621Svikram /* 3244621Svikram * Now that we have deleted an entry, update 3245621Svikram * the entry numbering and the default cmd. 3246621Svikram */ 3247621Svikram update_numbering(mp); 3248621Svikram 32490Sstevel@tonic-gate return (BAM_SUCCESS); 32500Sstevel@tonic-gate } 32510Sstevel@tonic-gate 32520Sstevel@tonic-gate static error_t 32536448Svikram delete_all_entries(menu_t *mp, char *dummy, char *opt) 32540Sstevel@tonic-gate { 32550Sstevel@tonic-gate assert(mp); 32566448Svikram assert(dummy == NULL); 32570Sstevel@tonic-gate assert(opt == NULL); 32580Sstevel@tonic-gate 32596448Svikram BAM_DPRINTF((D_FUNC_ENTRY0, "delete_all_entries")); 32606448Svikram 32610Sstevel@tonic-gate if (mp->start == NULL) { 32626448Svikram bam_print(EMPTY_MENU); 32630Sstevel@tonic-gate return (BAM_SUCCESS); 32640Sstevel@tonic-gate } 32650Sstevel@tonic-gate 32660Sstevel@tonic-gate if (do_delete(mp, ALL_ENTRIES) != BAM_SUCCESS) { 32670Sstevel@tonic-gate return (BAM_ERROR); 32680Sstevel@tonic-gate } 32690Sstevel@tonic-gate 32700Sstevel@tonic-gate return (BAM_WRITE); 32710Sstevel@tonic-gate } 32720Sstevel@tonic-gate 32730Sstevel@tonic-gate static FILE * 32746448Svikram create_diskmap(char *osroot) 32750Sstevel@tonic-gate { 32760Sstevel@tonic-gate FILE *fp; 32770Sstevel@tonic-gate char cmd[PATH_MAX]; 32786448Svikram const char *fcn = "create_diskmap()"; 32790Sstevel@tonic-gate 32800Sstevel@tonic-gate /* make sure we have a map file */ 32810Sstevel@tonic-gate fp = fopen(GRUBDISK_MAP, "r"); 32820Sstevel@tonic-gate if (fp == NULL) { 32830Sstevel@tonic-gate (void) snprintf(cmd, sizeof (cmd), 32846448Svikram "%s/%s > /dev/null", osroot, CREATE_DISKMAP); 32856448Svikram if (exec_cmd(cmd, NULL) != 0) 32866448Svikram return (NULL); 32870Sstevel@tonic-gate fp = fopen(GRUBDISK_MAP, "r"); 32886448Svikram INJECT_ERROR1("DISKMAP_CREATE_FAIL", fp = NULL); 32896448Svikram if (fp) { 32906448Svikram BAM_DPRINTF((D_CREATED_DISKMAP, fcn, GRUBDISK_MAP)); 32916448Svikram } else { 32926448Svikram BAM_DPRINTF((D_CREATE_DISKMAP_FAIL, fcn, GRUBDISK_MAP)); 32936448Svikram } 32940Sstevel@tonic-gate } 32950Sstevel@tonic-gate return (fp); 32960Sstevel@tonic-gate } 32970Sstevel@tonic-gate 32980Sstevel@tonic-gate #define SECTOR_SIZE 512 32990Sstevel@tonic-gate 33000Sstevel@tonic-gate static int 33010Sstevel@tonic-gate get_partition(char *device) 33020Sstevel@tonic-gate { 33030Sstevel@tonic-gate int i, fd, is_pcfs, partno = -1; 33040Sstevel@tonic-gate struct mboot *mboot; 33050Sstevel@tonic-gate char boot_sect[SECTOR_SIZE]; 33060Sstevel@tonic-gate char *wholedisk, *slice; 33070Sstevel@tonic-gate 33080Sstevel@tonic-gate /* form whole disk (p0) */ 33090Sstevel@tonic-gate slice = device + strlen(device) - 2; 33100Sstevel@tonic-gate is_pcfs = (*slice != 's'); 33110Sstevel@tonic-gate if (!is_pcfs) 33120Sstevel@tonic-gate *slice = '\0'; 33130Sstevel@tonic-gate wholedisk = s_calloc(1, strlen(device) + 3); 33140Sstevel@tonic-gate (void) snprintf(wholedisk, strlen(device) + 3, "%sp0", device); 33150Sstevel@tonic-gate if (!is_pcfs) 33160Sstevel@tonic-gate *slice = 's'; 33170Sstevel@tonic-gate 33180Sstevel@tonic-gate /* read boot sector */ 33190Sstevel@tonic-gate fd = open(wholedisk, O_RDONLY); 33200Sstevel@tonic-gate free(wholedisk); 33210Sstevel@tonic-gate if (fd == -1 || read(fd, boot_sect, SECTOR_SIZE) != SECTOR_SIZE) { 33220Sstevel@tonic-gate return (partno); 33230Sstevel@tonic-gate } 33240Sstevel@tonic-gate (void) close(fd); 33250Sstevel@tonic-gate 33260Sstevel@tonic-gate /* parse fdisk table */ 33270Sstevel@tonic-gate mboot = (struct mboot *)((void *)boot_sect); 33280Sstevel@tonic-gate for (i = 0; i < FD_NUMPART; i++) { 33290Sstevel@tonic-gate struct ipart *part = 33300Sstevel@tonic-gate (struct ipart *)(uintptr_t)mboot->parts + i; 33310Sstevel@tonic-gate if (is_pcfs) { /* looking for solaris boot part */ 33320Sstevel@tonic-gate if (part->systid == 0xbe) { 33330Sstevel@tonic-gate partno = i; 33340Sstevel@tonic-gate break; 33350Sstevel@tonic-gate } 33360Sstevel@tonic-gate } else { /* look for solaris partition, old and new */ 33370Sstevel@tonic-gate if (part->systid == SUNIXOS || 33380Sstevel@tonic-gate part->systid == SUNIXOS2) { 33390Sstevel@tonic-gate partno = i; 33400Sstevel@tonic-gate break; 33410Sstevel@tonic-gate } 33420Sstevel@tonic-gate } 33430Sstevel@tonic-gate } 33440Sstevel@tonic-gate return (partno); 33450Sstevel@tonic-gate } 33460Sstevel@tonic-gate 33476448Svikram char * 33486448Svikram get_grubroot(char *osroot, char *osdev, char *menu_root) 33496448Svikram { 33506448Svikram char *grubroot; /* (hd#,#,#) */ 33516448Svikram char *slice; 33526448Svikram char *grubhd; 33536448Svikram int fdiskpart; 33546448Svikram int found = 0; 33556448Svikram char *devname; 33566448Svikram char *ctdname = strstr(osdev, "dsk/"); 33576448Svikram char linebuf[PATH_MAX]; 33586448Svikram FILE *fp; 33596448Svikram const char *fcn = "get_grubroot()"; 33606448Svikram 33616448Svikram INJECT_ERROR1("GRUBROOT_INVALID_OSDEV", ctdname = NULL); 33626448Svikram if (ctdname == NULL) { 33636448Svikram bam_error(INVALID_DEV_DSK, osdev); 33640Sstevel@tonic-gate return (NULL); 33656448Svikram } 33666448Svikram 33676448Svikram if (menu_root && !menu_on_bootdisk(osroot, menu_root)) { 33686448Svikram /* menu bears no resemblance to our reality */ 33696448Svikram bam_error(CANNOT_GRUBROOT_BOOTDISK, fcn, osdev); 33706448Svikram return (NULL); 33716448Svikram } 33720Sstevel@tonic-gate 33730Sstevel@tonic-gate ctdname += strlen("dsk/"); 33740Sstevel@tonic-gate slice = strrchr(ctdname, 's'); 33750Sstevel@tonic-gate if (slice) 33760Sstevel@tonic-gate *slice = '\0'; 33770Sstevel@tonic-gate 33786448Svikram fp = create_diskmap(osroot); 33796448Svikram if (fp == NULL) { 33806448Svikram bam_error(DISKMAP_FAIL, osroot); 33816448Svikram return (NULL); 33826448Svikram } 33836448Svikram 33840Sstevel@tonic-gate rewind(fp); 33850Sstevel@tonic-gate while (s_fgets(linebuf, sizeof (linebuf), fp) != NULL) { 33860Sstevel@tonic-gate grubhd = strtok(linebuf, " \t\n"); 33870Sstevel@tonic-gate if (grubhd) 33880Sstevel@tonic-gate devname = strtok(NULL, " \t\n"); 33890Sstevel@tonic-gate else 33900Sstevel@tonic-gate devname = NULL; 33910Sstevel@tonic-gate if (devname && strcmp(devname, ctdname) == 0) { 33920Sstevel@tonic-gate found = 1; 33930Sstevel@tonic-gate break; 33940Sstevel@tonic-gate } 33950Sstevel@tonic-gate } 33960Sstevel@tonic-gate 33970Sstevel@tonic-gate if (slice) 33980Sstevel@tonic-gate *slice = 's'; 33990Sstevel@tonic-gate 34006448Svikram (void) fclose(fp); 34016448Svikram fp = NULL; 34026448Svikram 34036448Svikram INJECT_ERROR1("GRUBROOT_BIOSDEV_FAIL", found = 0); 34040Sstevel@tonic-gate if (found == 0) { 34056448Svikram bam_error(BIOSDEV_FAIL, osdev); 34060Sstevel@tonic-gate return (NULL); 34076448Svikram } 34086448Svikram 34096448Svikram fdiskpart = get_partition(osdev); 34106448Svikram INJECT_ERROR1("GRUBROOT_FDISK_FAIL", fdiskpart = -1); 34116448Svikram if (fdiskpart == -1) { 34126448Svikram bam_error(FDISKPART_FAIL, osdev); 34136448Svikram return (NULL); 34146448Svikram } 34156448Svikram 34166448Svikram grubroot = s_calloc(1, 10); 34170Sstevel@tonic-gate if (slice) { 34186448Svikram (void) snprintf(grubroot, 10, "(hd%s,%d,%c)", 34190Sstevel@tonic-gate grubhd, fdiskpart, slice[1] + 'a' - '0'); 34200Sstevel@tonic-gate } else 34216448Svikram (void) snprintf(grubroot, 10, "(hd%s,%d)", 34220Sstevel@tonic-gate grubhd, fdiskpart); 34230Sstevel@tonic-gate 34246448Svikram assert(fp == NULL); 34256448Svikram assert(strncmp(grubroot, "(hd", strlen("(hd")) == 0); 34266448Svikram return (grubroot); 34276448Svikram } 34286448Svikram 34296448Svikram static char * 34306448Svikram find_primary_common(char *mntpt, char *fstype) 34316448Svikram { 34326448Svikram char signdir[PATH_MAX]; 34336448Svikram char tmpsign[MAXNAMELEN + 1]; 34346448Svikram char *lu; 34356448Svikram char *ufs; 34366448Svikram char *zfs; 34376448Svikram DIR *dirp = NULL; 34386448Svikram struct dirent *entp; 34396448Svikram struct stat sb; 34406448Svikram const char *fcn = "find_primary_common()"; 34416448Svikram 34426448Svikram (void) snprintf(signdir, sizeof (signdir), "%s/%s", 34436448Svikram mntpt, GRUBSIGN_DIR); 34446448Svikram 34456448Svikram if (stat(signdir, &sb) == -1) { 34466448Svikram BAM_DPRINTF((D_NO_SIGNDIR, fcn, signdir)); 34476448Svikram return (NULL); 34486448Svikram } 34496448Svikram 34506448Svikram dirp = opendir(signdir); 34516448Svikram INJECT_ERROR1("SIGNDIR_OPENDIR_FAIL", dirp = NULL); 34526448Svikram if (dirp == NULL) { 34536448Svikram bam_error(OPENDIR_FAILED, signdir, strerror(errno)); 34546448Svikram return (NULL); 34556448Svikram } 34566448Svikram 34576448Svikram ufs = zfs = lu = NULL; 34586448Svikram 34596448Svikram while (entp = readdir(dirp)) { 34606448Svikram if (strcmp(entp->d_name, ".") == 0 || 34616448Svikram strcmp(entp->d_name, "..") == 0) 34626448Svikram continue; 34636448Svikram 34646448Svikram (void) snprintf(tmpsign, sizeof (tmpsign), "%s", entp->d_name); 34656448Svikram 34666448Svikram if (lu == NULL && 34676448Svikram strncmp(tmpsign, GRUBSIGN_LU_PREFIX, 34686448Svikram strlen(GRUBSIGN_LU_PREFIX)) == 0) { 34696448Svikram lu = s_strdup(tmpsign); 34706448Svikram } 34716448Svikram 34726448Svikram if (ufs == NULL && 34736448Svikram strncmp(tmpsign, GRUBSIGN_UFS_PREFIX, 34746448Svikram strlen(GRUBSIGN_UFS_PREFIX)) == 0) { 34756448Svikram ufs = s_strdup(tmpsign); 34766448Svikram } 34776448Svikram 34786448Svikram if (zfs == NULL && 34796448Svikram strncmp(tmpsign, GRUBSIGN_ZFS_PREFIX, 34806448Svikram strlen(GRUBSIGN_ZFS_PREFIX)) == 0) { 34816448Svikram zfs = s_strdup(tmpsign); 34826448Svikram } 34836448Svikram } 34846448Svikram 34856448Svikram BAM_DPRINTF((D_EXIST_PRIMARY_SIGNS, fcn, 34866448Svikram zfs ? zfs : "NULL", 34876448Svikram ufs ? ufs : "NULL", 34886448Svikram lu ? lu : "NULL")); 34896448Svikram 34906448Svikram if (dirp) { 34916448Svikram (void) closedir(dirp); 34926448Svikram dirp = NULL; 34936448Svikram } 34946448Svikram 34956448Svikram if (strcmp(fstype, "ufs") == 0 && zfs) { 34966448Svikram bam_error(SIGN_FSTYPE_MISMATCH, zfs, "ufs"); 34976448Svikram free(zfs); 34986448Svikram zfs = NULL; 34996448Svikram } else if (strcmp(fstype, "zfs") == 0 && ufs) { 35006448Svikram bam_error(SIGN_FSTYPE_MISMATCH, ufs, "zfs"); 35016448Svikram free(ufs); 35026448Svikram ufs = NULL; 35036448Svikram } 35046448Svikram 35056448Svikram assert(dirp == NULL); 35066448Svikram 35076448Svikram /* For now, we let Live Upgrade take care of its signature itself */ 35086448Svikram if (lu) { 35096448Svikram BAM_DPRINTF((D_FREEING_LU_SIGNS, fcn, lu)); 35106448Svikram free(lu); 35116448Svikram lu = NULL; 35126448Svikram } 35136448Svikram 35146448Svikram return (zfs ? zfs : ufs); 35156448Svikram } 35166448Svikram 35176448Svikram static char * 35186448Svikram find_backup_common(char *mntpt, char *fstype) 35196448Svikram { 35206448Svikram FILE *bfp = NULL; 35216448Svikram char tmpsign[MAXNAMELEN + 1]; 35226448Svikram char backup[PATH_MAX]; 35236448Svikram char *ufs; 35246448Svikram char *zfs; 35256448Svikram char *lu; 35266448Svikram int error; 35276448Svikram const char *fcn = "find_backup_common()"; 35286448Svikram 35296448Svikram /* 35306448Svikram * We didn't find it in the primary directory. 35316448Svikram * Look at the backup 35326448Svikram */ 35336448Svikram (void) snprintf(backup, sizeof (backup), "%s%s", 35346448Svikram mntpt, GRUBSIGN_BACKUP); 35356448Svikram 35366448Svikram bfp = fopen(backup, "r"); 35376448Svikram if (bfp == NULL) { 35386448Svikram error = errno; 35396448Svikram if (bam_verbose) { 35406448Svikram bam_error(OPEN_FAIL, backup, strerror(error)); 35416448Svikram } 35426448Svikram BAM_DPRINTF((D_OPEN_FAIL, fcn, backup, strerror(error))); 35436448Svikram return (NULL); 35446448Svikram } 35456448Svikram 35466448Svikram ufs = zfs = lu = NULL; 35476448Svikram 35486448Svikram while (s_fgets(tmpsign, sizeof (tmpsign), bfp) != NULL) { 35496448Svikram 35506448Svikram if (lu == NULL && 35516448Svikram strncmp(tmpsign, GRUBSIGN_LU_PREFIX, 35526448Svikram strlen(GRUBSIGN_LU_PREFIX)) == 0) { 35536448Svikram lu = s_strdup(tmpsign); 35546448Svikram } 35556448Svikram 35566448Svikram if (ufs == NULL && 35576448Svikram strncmp(tmpsign, GRUBSIGN_UFS_PREFIX, 35586448Svikram strlen(GRUBSIGN_UFS_PREFIX)) == 0) { 35596448Svikram ufs = s_strdup(tmpsign); 35606448Svikram } 35616448Svikram 35626448Svikram if (zfs == NULL && 35636448Svikram strncmp(tmpsign, GRUBSIGN_ZFS_PREFIX, 35646448Svikram strlen(GRUBSIGN_ZFS_PREFIX)) == 0) { 35656448Svikram zfs = s_strdup(tmpsign); 35666448Svikram } 35676448Svikram } 35686448Svikram 35696448Svikram BAM_DPRINTF((D_EXIST_BACKUP_SIGNS, fcn, 35706448Svikram zfs ? zfs : "NULL", 35716448Svikram ufs ? ufs : "NULL", 35726448Svikram lu ? lu : "NULL")); 35736448Svikram 35746448Svikram if (bfp) { 35756448Svikram (void) fclose(bfp); 35766448Svikram bfp = NULL; 35776448Svikram } 35786448Svikram 35796448Svikram if (strcmp(fstype, "ufs") == 0 && zfs) { 35806448Svikram bam_error(SIGN_FSTYPE_MISMATCH, zfs, "ufs"); 35816448Svikram free(zfs); 35826448Svikram zfs = NULL; 35836448Svikram } else if (strcmp(fstype, "zfs") == 0 && ufs) { 35846448Svikram bam_error(SIGN_FSTYPE_MISMATCH, ufs, "zfs"); 35856448Svikram free(ufs); 35866448Svikram ufs = NULL; 35876448Svikram } 35886448Svikram 35896448Svikram assert(bfp == NULL); 35906448Svikram 35916448Svikram /* For now, we let Live Upgrade take care of its signature itself */ 35926448Svikram if (lu) { 35936448Svikram BAM_DPRINTF((D_FREEING_LU_SIGNS, fcn, lu)); 35946448Svikram free(lu); 35956448Svikram lu = NULL; 35966448Svikram } 35976448Svikram 35986448Svikram return (zfs ? zfs : ufs); 35996448Svikram } 36006448Svikram 36016448Svikram static char * 36026448Svikram find_ufs_existing(char *osroot) 36036448Svikram { 36046448Svikram char *sign; 36056448Svikram const char *fcn = "find_ufs_existing()"; 36066448Svikram 36076448Svikram sign = find_primary_common(osroot, "ufs"); 36086448Svikram if (sign == NULL) { 36096448Svikram sign = find_backup_common(osroot, "ufs"); 36106448Svikram BAM_DPRINTF((D_EXIST_BACKUP_SIGN, fcn, sign ? sign : "NULL")); 36116448Svikram } else { 36126448Svikram BAM_DPRINTF((D_EXIST_PRIMARY_SIGN, fcn, sign)); 36136448Svikram } 36146448Svikram 36156448Svikram return (sign); 36166448Svikram } 36176448Svikram 36186448Svikram char * 36196448Svikram get_mountpoint(char *special, char *fstype) 36206448Svikram { 36216448Svikram FILE *mntfp; 36226448Svikram struct mnttab mp = {0}; 36236448Svikram struct mnttab mpref = {0}; 36246448Svikram int error; 36256448Svikram int ret; 36266448Svikram const char *fcn = "get_mountpoint()"; 36276448Svikram 36286448Svikram BAM_DPRINTF((D_FUNC_ENTRY2, fcn, special, fstype)); 36296448Svikram 36306448Svikram mntfp = fopen(MNTTAB, "r"); 36316448Svikram error = errno; 36326448Svikram INJECT_ERROR1("MNTTAB_ERR_GET_MNTPT", mntfp = NULL); 36336448Svikram if (mntfp == NULL) { 36346448Svikram bam_error(OPEN_FAIL, MNTTAB, strerror(error)); 36356448Svikram return (NULL); 36366448Svikram } 36376448Svikram 36386448Svikram mpref.mnt_special = special; 36396448Svikram mpref.mnt_fstype = fstype; 36406448Svikram 36416448Svikram ret = getmntany(mntfp, &mp, &mpref); 36426448Svikram INJECT_ERROR1("GET_MOUNTPOINT_MNTANY", ret = 1); 36436448Svikram if (ret != 0) { 36446448Svikram (void) fclose(mntfp); 36456448Svikram BAM_DPRINTF((D_NO_MNTPT, fcn, special, fstype)); 36466448Svikram return (NULL); 36476448Svikram } 36486448Svikram (void) fclose(mntfp); 36496448Svikram 36506448Svikram assert(mp.mnt_mountp); 36516448Svikram 36526448Svikram BAM_DPRINTF((D_GET_MOUNTPOINT_RET, fcn, special, mp.mnt_mountp)); 36536448Svikram 36546448Svikram return (s_strdup(mp.mnt_mountp)); 36556448Svikram } 36566448Svikram 36576448Svikram /* 36586448Svikram * Mounts a "legacy" top dataset (if needed) 36596448Svikram * Returns: The mountpoint of the legacy top dataset or NULL on error 36606448Svikram * mnted returns one of the above values defined for zfs_mnted_t 36616448Svikram */ 36626448Svikram static char * 36636448Svikram mount_legacy_dataset(char *pool, zfs_mnted_t *mnted) 36646448Svikram { 36656448Svikram char cmd[PATH_MAX]; 36666448Svikram char tmpmnt[PATH_MAX]; 36676448Svikram filelist_t flist = {0}; 36686448Svikram char *is_mounted; 36696448Svikram struct stat sb; 36706448Svikram int ret; 36716448Svikram const char *fcn = "mount_legacy_dataset()"; 36726448Svikram 36736448Svikram BAM_DPRINTF((D_FUNC_ENTRY1, fcn, pool)); 36746448Svikram 36756448Svikram *mnted = ZFS_MNT_ERROR; 36766448Svikram 36776448Svikram (void) snprintf(cmd, sizeof (cmd), 36786448Svikram "/sbin/zfs get -Ho value mounted %s", 36796448Svikram pool); 36806448Svikram 36816448Svikram ret = exec_cmd(cmd, &flist); 36826448Svikram INJECT_ERROR1("Z_MOUNT_LEG_GET_MOUNTED_CMD", ret = 1); 36836448Svikram if (ret != 0) { 36846448Svikram bam_error(ZFS_MNTED_FAILED, pool); 36856448Svikram return (NULL); 36866448Svikram } 36876448Svikram 36886448Svikram INJECT_ERROR1("Z_MOUNT_LEG_GET_MOUNTED_OUT", flist.head = NULL); 36896448Svikram if ((flist.head == NULL) || (flist.head != flist.tail)) { 36906448Svikram bam_error(BAD_ZFS_MNTED, pool); 36916448Svikram filelist_free(&flist); 36926448Svikram return (NULL); 36936448Svikram } 36946448Svikram 36956448Svikram is_mounted = strtok(flist.head->line, " \t\n"); 36966448Svikram INJECT_ERROR1("Z_MOUNT_LEG_GET_MOUNTED_STRTOK_YES", is_mounted = "yes"); 36976448Svikram INJECT_ERROR1("Z_MOUNT_LEG_GET_MOUNTED_STRTOK_NO", is_mounted = "no"); 36986448Svikram if (strcmp(is_mounted, "no") != 0) { 36996448Svikram filelist_free(&flist); 37006448Svikram *mnted = LEGACY_ALREADY; 37016448Svikram /* get_mountpoint returns a strdup'ed string */ 37026448Svikram BAM_DPRINTF((D_Z_MOUNT_TOP_LEG_ALREADY, fcn, pool)); 37036448Svikram return (get_mountpoint(pool, "zfs")); 37046448Svikram } 37056448Svikram 37066448Svikram filelist_free(&flist); 37076448Svikram 37086448Svikram /* 37096448Svikram * legacy top dataset is not mounted. Mount it now 37106448Svikram * First create a mountpoint. 37116448Svikram */ 37126448Svikram (void) snprintf(tmpmnt, sizeof (tmpmnt), "%s.%d", 37136448Svikram ZFS_LEGACY_MNTPT, getpid()); 37146448Svikram 37156448Svikram ret = stat(tmpmnt, &sb); 37166448Svikram if (ret == -1) { 37176448Svikram BAM_DPRINTF((D_Z_MOUNT_TOP_LEG_MNTPT_ABS, fcn, pool, tmpmnt)); 37186448Svikram ret = mkdirp(tmpmnt, 0755); 37196448Svikram INJECT_ERROR1("Z_MOUNT_TOP_LEG_MNTPT_MKDIRP", ret = -1); 37206448Svikram if (ret == -1) { 37216448Svikram bam_error(MKDIR_FAILED, tmpmnt, strerror(errno)); 37226448Svikram return (NULL); 37236448Svikram } 37246448Svikram } else { 37256448Svikram BAM_DPRINTF((D_Z_MOUNT_TOP_LEG_MNTPT_PRES, fcn, pool, tmpmnt)); 37266448Svikram } 37276448Svikram 37286448Svikram (void) snprintf(cmd, sizeof (cmd), 37296448Svikram "/sbin/mount -F zfs %s %s", 37306448Svikram pool, tmpmnt); 37316448Svikram 37326448Svikram ret = exec_cmd(cmd, NULL); 37336448Svikram INJECT_ERROR1("Z_MOUNT_TOP_LEG_MOUNT_CMD", ret = 1); 37346448Svikram if (ret != 0) { 37356448Svikram bam_error(ZFS_MOUNT_FAILED, pool); 37366448Svikram (void) rmdir(tmpmnt); 37376448Svikram return (NULL); 37386448Svikram } 37396448Svikram 37406448Svikram *mnted = LEGACY_MOUNTED; 37416448Svikram BAM_DPRINTF((D_Z_MOUNT_TOP_LEG_MOUNTED, fcn, pool, tmpmnt)); 37426448Svikram return (s_strdup(tmpmnt)); 37436448Svikram } 37446448Svikram 37456448Svikram /* 37466448Svikram * Mounts the top dataset (if needed) 37476448Svikram * Returns: The mountpoint of the top dataset or NULL on error 37486448Svikram * mnted returns one of the above values defined for zfs_mnted_t 37496448Svikram */ 37506448Svikram static char * 37516448Svikram mount_top_dataset(char *pool, zfs_mnted_t *mnted) 37526448Svikram { 37536448Svikram char cmd[PATH_MAX]; 37546448Svikram filelist_t flist = {0}; 37556448Svikram char *is_mounted; 37566448Svikram char *mntpt; 37576448Svikram char *zmntpt; 37586448Svikram int ret; 37596448Svikram const char *fcn = "mount_top_dataset()"; 37606448Svikram 37616448Svikram *mnted = ZFS_MNT_ERROR; 37626448Svikram 37636448Svikram BAM_DPRINTF((D_FUNC_ENTRY1, fcn, pool)); 37646448Svikram 37656448Svikram /* 37666448Svikram * First check if the top dataset is a "legacy" dataset 37676448Svikram */ 37686448Svikram (void) snprintf(cmd, sizeof (cmd), 37696448Svikram "/sbin/zfs get -Ho value mountpoint %s", 37706448Svikram pool); 37716448Svikram ret = exec_cmd(cmd, &flist); 37726448Svikram INJECT_ERROR1("Z_MOUNT_TOP_GET_MNTPT", ret = 1); 37736448Svikram if (ret != 0) { 37746448Svikram bam_error(ZFS_MNTPT_FAILED, pool); 37756448Svikram return (NULL); 37766448Svikram } 37776448Svikram 37786448Svikram if (flist.head && (flist.head == flist.tail)) { 37796448Svikram char *legacy = strtok(flist.head->line, " \t\n"); 37806448Svikram if (legacy && strcmp(legacy, "legacy") == 0) { 37816448Svikram filelist_free(&flist); 37826448Svikram BAM_DPRINTF((D_Z_IS_LEGACY, fcn, pool)); 37836448Svikram return (mount_legacy_dataset(pool, mnted)); 37846448Svikram } 37856448Svikram } 37866448Svikram 37876448Svikram filelist_free(&flist); 37886448Svikram 37896448Svikram BAM_DPRINTF((D_Z_IS_NOT_LEGACY, fcn, pool)); 37906448Svikram 37916448Svikram (void) snprintf(cmd, sizeof (cmd), 37926448Svikram "/sbin/zfs get -Ho value mounted %s", 37936448Svikram pool); 37946448Svikram 37956448Svikram ret = exec_cmd(cmd, &flist); 37966448Svikram INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MOUNTED", ret = 1); 37976448Svikram if (ret != 0) { 37986448Svikram bam_error(ZFS_MNTED_FAILED, pool); 37996448Svikram return (NULL); 38006448Svikram } 38016448Svikram 38026448Svikram INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MOUNTED_VAL", flist.head = NULL); 38036448Svikram if ((flist.head == NULL) || (flist.head != flist.tail)) { 38046448Svikram bam_error(BAD_ZFS_MNTED, pool); 38056448Svikram filelist_free(&flist); 38066448Svikram return (NULL); 38076448Svikram } 38086448Svikram 38096448Svikram is_mounted = strtok(flist.head->line, " \t\n"); 38106448Svikram INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MOUNTED_YES", is_mounted = "yes"); 38116448Svikram INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MOUNTED_NO", is_mounted = "no"); 38126448Svikram if (strcmp(is_mounted, "no") != 0) { 38136448Svikram filelist_free(&flist); 38146448Svikram *mnted = ZFS_ALREADY; 38156448Svikram BAM_DPRINTF((D_Z_MOUNT_TOP_NONLEG_MOUNTED_ALREADY, fcn, pool)); 38166448Svikram goto mounted; 38176448Svikram } 38186448Svikram 38196448Svikram filelist_free(&flist); 38206448Svikram BAM_DPRINTF((D_Z_MOUNT_TOP_NONLEG_MOUNTED_NOT_ALREADY, fcn, pool)); 38216448Svikram 38226448Svikram /* top dataset is not mounted. Mount it now */ 38236448Svikram (void) snprintf(cmd, sizeof (cmd), 38246448Svikram "/sbin/zfs mount %s", pool); 38256448Svikram ret = exec_cmd(cmd, NULL); 38266448Svikram INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_MOUNT_CMD", ret = 1); 38276448Svikram if (ret != 0) { 38286448Svikram bam_error(ZFS_MOUNT_FAILED, pool); 38296448Svikram return (NULL); 38306448Svikram } 38316448Svikram *mnted = ZFS_MOUNTED; 38326448Svikram BAM_DPRINTF((D_Z_MOUNT_TOP_NONLEG_MOUNTED_NOW, fcn, pool)); 38336448Svikram /*FALLTHRU*/ 38346448Svikram mounted: 38356448Svikram /* 38366448Svikram * Now get the mountpoint 38376448Svikram */ 38386448Svikram (void) snprintf(cmd, sizeof (cmd), 38396448Svikram "/sbin/zfs get -Ho value mountpoint %s", 38406448Svikram pool); 38416448Svikram 38426448Svikram ret = exec_cmd(cmd, &flist); 38436448Svikram INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MNTPT_CMD", ret = 1); 38446448Svikram if (ret != 0) { 38456448Svikram bam_error(ZFS_MNTPT_FAILED, pool); 38466448Svikram goto error; 38476448Svikram } 38486448Svikram 38496448Svikram INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MNTPT_OUT", flist.head = NULL); 38506448Svikram if ((flist.head == NULL) || (flist.head != flist.tail)) { 38516448Svikram bam_error(NULL_ZFS_MNTPT, pool); 38526448Svikram goto error; 38536448Svikram } 38546448Svikram 38556448Svikram mntpt = strtok(flist.head->line, " \t\n"); 38566448Svikram INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MNTPT_STRTOK", mntpt = "foo"); 38576448Svikram if (*mntpt != '/') { 38586448Svikram bam_error(BAD_ZFS_MNTPT, pool, mntpt); 38596448Svikram goto error; 38606448Svikram } 38616448Svikram zmntpt = s_strdup(mntpt); 38626448Svikram 38636448Svikram filelist_free(&flist); 38646448Svikram 38656448Svikram BAM_DPRINTF((D_Z_MOUNT_TOP_NONLEG_MNTPT, fcn, pool, zmntpt)); 38666448Svikram 38676448Svikram return (zmntpt); 38686448Svikram 38696448Svikram error: 38706448Svikram filelist_free(&flist); 38716448Svikram (void) umount_top_dataset(pool, *mnted, NULL); 38726448Svikram BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 38736448Svikram return (NULL); 38746448Svikram } 38756448Svikram 38766448Svikram static int 38776448Svikram umount_top_dataset(char *pool, zfs_mnted_t mnted, char *mntpt) 38786448Svikram { 38796448Svikram char cmd[PATH_MAX]; 38806448Svikram int ret; 38816448Svikram const char *fcn = "umount_top_dataset()"; 38826448Svikram 38836448Svikram INJECT_ERROR1("Z_UMOUNT_TOP_INVALID_STATE", mnted = ZFS_MNT_ERROR); 38846448Svikram switch (mnted) { 38856448Svikram case LEGACY_ALREADY: 38866448Svikram case ZFS_ALREADY: 38876448Svikram /* nothing to do */ 38886448Svikram BAM_DPRINTF((D_Z_UMOUNT_TOP_ALREADY_NOP, fcn, pool, 38896448Svikram mntpt ? mntpt : "NULL")); 38906448Svikram free(mntpt); 38916448Svikram return (BAM_SUCCESS); 38926448Svikram case LEGACY_MOUNTED: 38936448Svikram (void) snprintf(cmd, sizeof (cmd), 38946448Svikram "/sbin/umount %s", pool); 38956448Svikram ret = exec_cmd(cmd, NULL); 38966448Svikram INJECT_ERROR1("Z_UMOUNT_TOP_LEGACY_UMOUNT_FAIL", ret = 1); 38976448Svikram if (ret != 0) { 38986448Svikram bam_error(UMOUNT_FAILED, pool); 38996448Svikram free(mntpt); 39006448Svikram return (BAM_ERROR); 39016448Svikram } 39026448Svikram if (mntpt) 39036448Svikram (void) rmdir(mntpt); 39046448Svikram free(mntpt); 39056448Svikram BAM_DPRINTF((D_Z_UMOUNT_TOP_LEGACY, fcn, pool)); 39066448Svikram return (BAM_SUCCESS); 39076448Svikram case ZFS_MOUNTED: 39086448Svikram free(mntpt); 39096448Svikram (void) snprintf(cmd, sizeof (cmd), 39106448Svikram "/sbin/zfs unmount %s", pool); 39116448Svikram ret = exec_cmd(cmd, NULL); 39126448Svikram INJECT_ERROR1("Z_UMOUNT_TOP_NONLEG_UMOUNT_FAIL", ret = 1); 39136448Svikram if (ret != 0) { 39146448Svikram bam_error(UMOUNT_FAILED, pool); 39156448Svikram return (BAM_ERROR); 39166448Svikram } 39176448Svikram BAM_DPRINTF((D_Z_UMOUNT_TOP_NONLEG, fcn, pool)); 39186448Svikram return (BAM_SUCCESS); 39196448Svikram default: 39206448Svikram bam_error(INT_BAD_MNTSTATE, pool); 39216448Svikram return (BAM_ERROR); 39226448Svikram } 39236448Svikram /*NOTREACHED*/ 39246448Svikram } 39256448Svikram 39266448Svikram /* 39276448Svikram * For ZFS, osdev can be one of two forms 39286448Svikram * It can be a "special" file as seen in mnttab: rpool/ROOT/szboot_0402 39296448Svikram * It can be a /dev/[r]dsk special file. We handle both instances 39306448Svikram */ 39316448Svikram static char * 39326448Svikram get_pool(char *osdev) 39336448Svikram { 39346448Svikram char cmd[PATH_MAX]; 39356448Svikram char buf[PATH_MAX]; 39366448Svikram filelist_t flist = {0}; 39376448Svikram char *pool; 39386448Svikram char *cp; 39396448Svikram char *slash; 39406448Svikram int ret; 39416448Svikram const char *fcn = "get_pool()"; 39426448Svikram 39436448Svikram INJECT_ERROR1("GET_POOL_OSDEV", osdev = NULL); 39446448Svikram if (osdev == NULL) { 39456448Svikram bam_error(GET_POOL_OSDEV_NULL); 39466448Svikram return (NULL); 39476448Svikram } 39486448Svikram 39496448Svikram BAM_DPRINTF((D_GET_POOL_OSDEV, fcn, osdev)); 39506448Svikram 39516448Svikram if (osdev[0] != '/') { 39526448Svikram (void) strlcpy(buf, osdev, sizeof (buf)); 39536448Svikram slash = strchr(buf, '/'); 39546448Svikram if (slash) 39556448Svikram *slash = '\0'; 39566448Svikram pool = s_strdup(buf); 39576448Svikram BAM_DPRINTF((D_GET_POOL_RET, fcn, pool)); 39586448Svikram return (pool); 39596448Svikram } else if (strncmp(osdev, "/dev/dsk/", strlen("/dev/dsk/")) != 0 && 39606448Svikram strncmp(osdev, "/dev/rdsk/", strlen("/dev/rdsk/")) != 0) { 39616448Svikram bam_error(GET_POOL_BAD_OSDEV, osdev); 39626448Svikram return (NULL); 39636448Svikram } 39646448Svikram 39656448Svikram (void) snprintf(cmd, sizeof (cmd), 39666448Svikram "/usr/sbin/fstyp -a %s 2>/dev/null | /bin/grep '^name:'", 39676448Svikram osdev); 39686448Svikram 39696448Svikram ret = exec_cmd(cmd, &flist); 39706448Svikram INJECT_ERROR1("GET_POOL_FSTYP", ret = 1); 39716448Svikram if (ret != 0) { 39726448Svikram bam_error(FSTYP_A_FAILED, osdev); 39736448Svikram return (NULL); 39746448Svikram } 39756448Svikram 39766448Svikram INJECT_ERROR1("GET_POOL_FSTYP_OUT", flist.head = NULL); 39776448Svikram if ((flist.head == NULL) || (flist.head != flist.tail)) { 39786448Svikram bam_error(NULL_FSTYP_A, osdev); 39796448Svikram filelist_free(&flist); 39806448Svikram return (NULL); 39816448Svikram } 39826448Svikram 39836448Svikram (void) strtok(flist.head->line, "'"); 39846448Svikram cp = strtok(NULL, "'"); 39856448Svikram INJECT_ERROR1("GET_POOL_FSTYP_STRTOK", cp = NULL); 39866448Svikram if (cp == NULL) { 39876448Svikram bam_error(BAD_FSTYP_A, osdev); 39886448Svikram filelist_free(&flist); 39896448Svikram return (NULL); 39906448Svikram } 39916448Svikram 39926448Svikram pool = s_strdup(cp); 39936448Svikram 39946448Svikram filelist_free(&flist); 39956448Svikram 39966448Svikram BAM_DPRINTF((D_GET_POOL_RET, fcn, pool)); 39976448Svikram 39986448Svikram return (pool); 39996448Svikram } 40006448Svikram 40016448Svikram static char * 40026448Svikram find_zfs_existing(char *osdev) 40036448Svikram { 40046448Svikram char *pool; 40056448Svikram zfs_mnted_t mnted; 40066448Svikram char *mntpt; 40076448Svikram char *sign; 40086448Svikram const char *fcn = "find_zfs_existing()"; 40096448Svikram 40106448Svikram pool = get_pool(osdev); 40116448Svikram INJECT_ERROR1("ZFS_FIND_EXIST_POOL", pool = NULL); 40126448Svikram if (pool == NULL) { 40136448Svikram bam_error(ZFS_GET_POOL_FAILED, osdev); 40146448Svikram return (NULL); 40156448Svikram } 40166448Svikram 40176448Svikram mntpt = mount_top_dataset(pool, &mnted); 40186448Svikram INJECT_ERROR1("ZFS_FIND_EXIST_MOUNT_TOP", mntpt = NULL); 40196448Svikram if (mntpt == NULL) { 40206448Svikram bam_error(ZFS_MOUNT_TOP_DATASET_FAILED, pool); 40216448Svikram free(pool); 40226448Svikram return (NULL); 40236448Svikram } 40246448Svikram 40256448Svikram sign = find_primary_common(mntpt, "zfs"); 40266448Svikram if (sign == NULL) { 40276448Svikram sign = find_backup_common(mntpt, "zfs"); 40286448Svikram BAM_DPRINTF((D_EXIST_BACKUP_SIGN, fcn, sign ? sign : "NULL")); 40296448Svikram } else { 40306448Svikram BAM_DPRINTF((D_EXIST_PRIMARY_SIGN, fcn, sign)); 40316448Svikram } 40326448Svikram 40336448Svikram (void) umount_top_dataset(pool, mnted, mntpt); 40346448Svikram 40356448Svikram free(pool); 40366448Svikram 40376448Svikram return (sign); 40386448Svikram } 40396448Svikram 40406448Svikram static char * 40416448Svikram find_existing_sign(char *osroot, char *osdev, char *fstype) 40426448Svikram { 40436448Svikram const char *fcn = "find_existing_sign()"; 40446448Svikram 40456448Svikram INJECT_ERROR1("FIND_EXIST_NOTSUP_FS", fstype = "foofs"); 40466448Svikram if (strcmp(fstype, "ufs") == 0) { 40476448Svikram BAM_DPRINTF((D_CHECK_UFS_EXIST_SIGN, fcn)); 40486448Svikram return (find_ufs_existing(osroot)); 40496448Svikram } else if (strcmp(fstype, "zfs") == 0) { 40506448Svikram BAM_DPRINTF((D_CHECK_ZFS_EXIST_SIGN, fcn)); 40516448Svikram return (find_zfs_existing(osdev)); 40526448Svikram } else { 40536448Svikram bam_error(GRUBSIGN_NOTSUP, fstype); 40546448Svikram return (NULL); 40556448Svikram } 40566448Svikram } 40576448Svikram 40586448Svikram #define MH_HASH_SZ 16 40596448Svikram 40606448Svikram typedef enum { 40616448Svikram MH_ERROR = -1, 40626448Svikram MH_NOMATCH, 40636448Svikram MH_MATCH 40646448Svikram } mh_search_t; 40656448Svikram 40666448Svikram typedef struct mcache { 40676448Svikram char *mc_special; 40686448Svikram char *mc_mntpt; 40696448Svikram char *mc_fstype; 40706448Svikram struct mcache *mc_next; 40716448Svikram } mcache_t; 40726448Svikram 40736448Svikram typedef struct mhash { 40746448Svikram mcache_t *mh_hash[MH_HASH_SZ]; 40756448Svikram } mhash_t; 40766448Svikram 40776448Svikram static int 40786448Svikram mhash_fcn(char *key) 40796448Svikram { 40806448Svikram int i; 40816448Svikram uint64_t sum = 0; 40826448Svikram 40836448Svikram for (i = 0; key[i] != '\0'; i++) { 40846448Svikram sum += (uchar_t)key[i]; 40856448Svikram } 40866448Svikram 40876448Svikram sum %= MH_HASH_SZ; 40886448Svikram 40896448Svikram assert(sum < MH_HASH_SZ); 40906448Svikram 40916448Svikram return (sum); 40926448Svikram } 40936448Svikram 40946448Svikram static mhash_t * 40956448Svikram cache_mnttab(void) 40966448Svikram { 40976448Svikram FILE *mfp; 40986448Svikram struct extmnttab mnt; 40996448Svikram mcache_t *mcp; 41006448Svikram mhash_t *mhp; 41016448Svikram char *ctds; 41026448Svikram int idx; 41036448Svikram int error; 41046448Svikram char *special_dup; 41056448Svikram const char *fcn = "cache_mnttab()"; 41066448Svikram 41076448Svikram mfp = fopen(MNTTAB, "r"); 41086448Svikram error = errno; 41096448Svikram INJECT_ERROR1("CACHE_MNTTAB_MNTTAB_ERR", mfp = NULL); 41106448Svikram if (mfp == NULL) { 41116448Svikram bam_error(OPEN_FAIL, MNTTAB, strerror(error)); 41126448Svikram return (NULL); 41136448Svikram } 41146448Svikram 41156448Svikram mhp = s_calloc(1, sizeof (mhash_t)); 41166448Svikram 41176448Svikram resetmnttab(mfp); 41186448Svikram 41196448Svikram while (getextmntent(mfp, &mnt, sizeof (mnt)) == 0) { 41206448Svikram /* only cache ufs */ 41216448Svikram if (strcmp(mnt.mnt_fstype, "ufs") != 0) 41226448Svikram continue; 41236448Svikram 41246448Svikram /* basename() modifies its arg, so dup it */ 41256448Svikram special_dup = s_strdup(mnt.mnt_special); 41266448Svikram ctds = basename(special_dup); 41276448Svikram 41286448Svikram mcp = s_calloc(1, sizeof (mcache_t)); 41296448Svikram mcp->mc_special = s_strdup(ctds); 41306448Svikram mcp->mc_mntpt = s_strdup(mnt.mnt_mountp); 41316448Svikram mcp->mc_fstype = s_strdup(mnt.mnt_fstype); 41326448Svikram BAM_DPRINTF((D_CACHE_MNTS, fcn, ctds, 41336448Svikram mnt.mnt_mountp, mnt.mnt_fstype)); 41346448Svikram idx = mhash_fcn(ctds); 41356448Svikram mcp->mc_next = mhp->mh_hash[idx]; 41366448Svikram mhp->mh_hash[idx] = mcp; 41376448Svikram free(special_dup); 41386448Svikram } 41396448Svikram 41406448Svikram (void) fclose(mfp); 41416448Svikram 41426448Svikram return (mhp); 41436448Svikram } 41446448Svikram 41456448Svikram static void 41466448Svikram free_mnttab(mhash_t *mhp) 41476448Svikram { 41486448Svikram mcache_t *mcp; 41496448Svikram int i; 41506448Svikram 41516448Svikram for (i = 0; i < MH_HASH_SZ; i++) { 41526448Svikram /*LINTED*/ 41536448Svikram while (mcp = mhp->mh_hash[i]) { 41546448Svikram mhp->mh_hash[i] = mcp->mc_next; 41556448Svikram free(mcp->mc_special); 41566448Svikram free(mcp->mc_mntpt); 41576448Svikram free(mcp->mc_fstype); 41586448Svikram free(mcp); 41596448Svikram } 41606448Svikram } 41616448Svikram 41626448Svikram for (i = 0; i < MH_HASH_SZ; i++) { 41636448Svikram assert(mhp->mh_hash[i] == NULL); 41646448Svikram } 41656448Svikram free(mhp); 41666448Svikram } 41676448Svikram 41686448Svikram static mh_search_t 41696448Svikram search_hash(mhash_t *mhp, char *special, char **mntpt) 41706448Svikram { 41716448Svikram int idx; 41726448Svikram mcache_t *mcp; 41736448Svikram const char *fcn = "search_hash()"; 41746448Svikram 41756448Svikram assert(mntpt); 41766448Svikram 41776448Svikram *mntpt = NULL; 41786448Svikram 41796448Svikram INJECT_ERROR1("SEARCH_HASH_FULL_PATH", special = "/foo"); 41806448Svikram if (strchr(special, '/')) { 41816448Svikram bam_error(INVALID_MHASH_KEY, special); 41826448Svikram return (MH_ERROR); 41836448Svikram } 41846448Svikram 41856448Svikram idx = mhash_fcn(special); 41866448Svikram 41876448Svikram for (mcp = mhp->mh_hash[idx]; mcp; mcp = mcp->mc_next) { 41886448Svikram if (strcmp(mcp->mc_special, special) == 0) 41896448Svikram break; 41906448Svikram } 41916448Svikram 41926448Svikram if (mcp == NULL) { 41936448Svikram BAM_DPRINTF((D_MNTTAB_HASH_NOMATCH, fcn, special)); 41946448Svikram return (MH_NOMATCH); 41956448Svikram } 41966448Svikram 41976448Svikram assert(strcmp(mcp->mc_fstype, "ufs") == 0); 41986448Svikram *mntpt = mcp->mc_mntpt; 41996448Svikram BAM_DPRINTF((D_MNTTAB_HASH_MATCH, fcn, special)); 42006448Svikram return (MH_MATCH); 42016448Svikram } 42026448Svikram 42036448Svikram static int 42046448Svikram check_add_ufs_sign_to_list(FILE *tfp, char *mntpt) 42056448Svikram { 42066448Svikram char *sign; 42076448Svikram char *signline; 42086448Svikram char signbuf[MAXNAMELEN]; 42096448Svikram int len; 42106448Svikram int error; 42116448Svikram const char *fcn = "check_add_ufs_sign_to_list()"; 42126448Svikram 42136448Svikram /* safe to specify NULL as "osdev" arg for UFS */ 42146448Svikram sign = find_existing_sign(mntpt, NULL, "ufs"); 42156448Svikram if (sign == NULL) { 42166448Svikram /* No existing signature, nothing to add to list */ 42176448Svikram BAM_DPRINTF((D_NO_SIGN_TO_LIST, fcn, mntpt)); 42186448Svikram return (0); 42196448Svikram } 42206448Svikram 42216448Svikram (void) snprintf(signbuf, sizeof (signbuf), "%s\n", sign); 42226448Svikram signline = signbuf; 42236448Svikram 42246448Svikram INJECT_ERROR1("UFS_MNTPT_SIGN_NOTUFS", signline = "pool_rpool10\n"); 42256448Svikram if (strncmp(signline, GRUBSIGN_UFS_PREFIX, 42266448Svikram strlen(GRUBSIGN_UFS_PREFIX))) { 42276448Svikram bam_error(INVALID_UFS_SIGNATURE, sign); 42286448Svikram free(sign); 42296448Svikram /* ignore invalid signatures */ 42306448Svikram return (0); 42316448Svikram } 42326448Svikram 42336448Svikram len = fputs(signline, tfp); 42346448Svikram error = errno; 42356448Svikram INJECT_ERROR1("SIGN_LIST_PUTS_ERROR", len = 0); 42366448Svikram if (len != strlen(signline)) { 42376448Svikram bam_error(SIGN_LIST_FPUTS_ERR, sign, strerror(error)); 42386448Svikram free(sign); 42396448Svikram return (-1); 42406448Svikram } 42416448Svikram 42426448Svikram free(sign); 42436448Svikram 42446448Svikram BAM_DPRINTF((D_SIGN_LIST_PUTS_DONE, fcn, mntpt)); 42456448Svikram return (0); 42466448Svikram } 42476448Svikram 42486448Svikram /* 42496448Svikram * slice is a basename not a full pathname 42506448Svikram */ 42516448Svikram static int 42526448Svikram process_slice_common(char *slice, FILE *tfp, mhash_t *mhp, char *tmpmnt) 42536448Svikram { 42546448Svikram int ret; 42556448Svikram char cmd[PATH_MAX]; 42566448Svikram char path[PATH_MAX]; 42576448Svikram struct stat sbuf; 42586448Svikram char *mntpt; 42596448Svikram filelist_t flist = {0}; 42606448Svikram char *fstype; 42616448Svikram char blkslice[PATH_MAX]; 42626448Svikram const char *fcn = "process_slice_common()"; 42636448Svikram 42646448Svikram 42656448Svikram ret = search_hash(mhp, slice, &mntpt); 42666448Svikram switch (ret) { 42676448Svikram case MH_MATCH: 42686448Svikram if (check_add_ufs_sign_to_list(tfp, mntpt) == -1) 42696448Svikram return (-1); 42706448Svikram else 42716448Svikram return (0); 42726448Svikram case MH_NOMATCH: 42736448Svikram break; 42746448Svikram case MH_ERROR: 42756448Svikram default: 42766448Svikram return (-1); 42776448Svikram } 42786448Svikram 42796448Svikram (void) snprintf(path, sizeof (path), "/dev/rdsk/%s", slice); 42806448Svikram if (stat(path, &sbuf) == -1) { 42816448Svikram BAM_DPRINTF((D_SLICE_ENOENT, fcn, path)); 42826448Svikram return (0); 42836448Svikram } 42846448Svikram 42856448Svikram /* Check if ufs */ 42866448Svikram (void) snprintf(cmd, sizeof (cmd), 42876448Svikram "/usr/sbin/fstyp /dev/rdsk/%s 2>/dev/null", 42886448Svikram slice); 42896448Svikram 42906448Svikram if (exec_cmd(cmd, &flist) != 0) { 42916448Svikram if (bam_verbose) 42926448Svikram bam_print(FSTYP_FAILED, slice); 42936448Svikram return (0); 42946448Svikram } 42956448Svikram 42966448Svikram if ((flist.head == NULL) || (flist.head != flist.tail)) { 42976448Svikram if (bam_verbose) 42986448Svikram bam_print(FSTYP_BAD, slice); 42996448Svikram filelist_free(&flist); 43006448Svikram return (0); 43016448Svikram } 43026448Svikram 43036448Svikram fstype = strtok(flist.head->line, " \t\n"); 43046448Svikram if (fstype == NULL || strcmp(fstype, "ufs") != 0) { 43056448Svikram if (bam_verbose) 43066448Svikram bam_print(NOT_UFS_SLICE, slice, fstype); 43076448Svikram filelist_free(&flist); 43086448Svikram return (0); 43096448Svikram } 43106448Svikram 43116448Svikram filelist_free(&flist); 43126448Svikram 43136448Svikram /* 43146448Svikram * Since we are mounting the filesystem read-only, the 43156448Svikram * the last mount field of the superblock is unchanged 43166448Svikram * and does not need to be fixed up post-mount; 43176448Svikram */ 43186448Svikram 43196448Svikram (void) snprintf(blkslice, sizeof (blkslice), "/dev/dsk/%s", 43206448Svikram slice); 43216448Svikram 43226448Svikram (void) snprintf(cmd, sizeof (cmd), 43236448Svikram "/usr/sbin/mount -F ufs -o ro %s %s " 43246448Svikram "> /dev/null 2>&1", blkslice, tmpmnt); 43256448Svikram 43266448Svikram if (exec_cmd(cmd, NULL) != 0) { 43276448Svikram if (bam_verbose) 43286448Svikram bam_print(MOUNT_FAILED, blkslice, "ufs"); 43296448Svikram return (0); 43306448Svikram } 43316448Svikram 43326448Svikram ret = check_add_ufs_sign_to_list(tfp, tmpmnt); 43336448Svikram 43346448Svikram (void) snprintf(cmd, sizeof (cmd), 43356448Svikram "/usr/sbin/umount -f %s > /dev/null 2>&1", 43366448Svikram tmpmnt); 43376448Svikram 43386448Svikram if (exec_cmd(cmd, NULL) != 0) { 43396448Svikram bam_print(UMOUNT_FAILED, slice); 43406448Svikram return (0); 43416448Svikram } 43426448Svikram 43436448Svikram return (ret); 43446448Svikram } 43456448Svikram 43466448Svikram static int 43476448Svikram process_vtoc_slices( 43486448Svikram char *s0, 43496448Svikram struct vtoc *vtoc, 43506448Svikram FILE *tfp, 43516448Svikram mhash_t *mhp, 43526448Svikram char *tmpmnt) 43536448Svikram { 43546448Svikram int idx; 43556448Svikram char slice[PATH_MAX]; 43566448Svikram size_t len; 43576448Svikram char *cp; 43586448Svikram const char *fcn = "process_vtoc_slices()"; 43596448Svikram 43606448Svikram len = strlen(s0); 43616448Svikram 43626448Svikram assert(s0[len - 2] == 's' && s0[len - 1] == '0'); 43636448Svikram 43646448Svikram s0[len - 1] = '\0'; 43656448Svikram 43666448Svikram (void) strlcpy(slice, s0, sizeof (slice)); 43676448Svikram 43686448Svikram s0[len - 1] = '0'; 43696448Svikram 43706448Svikram cp = slice + len - 1; 43716448Svikram 43726448Svikram for (idx = 0; idx < vtoc->v_nparts; idx++) { 43736448Svikram 43746448Svikram (void) snprintf(cp, sizeof (slice) - (len - 1), "%u", idx); 43756448Svikram 43766448Svikram if (vtoc->v_part[idx].p_size == 0) { 43776448Svikram BAM_DPRINTF((D_VTOC_SIZE_ZERO, fcn, slice)); 43786448Svikram continue; 43796448Svikram } 43806448Svikram 43816448Svikram /* Skip "SWAP", "USR", "BACKUP", "VAR", "HOME", "ALTSCTR" */ 43826448Svikram switch (vtoc->v_part[idx].p_tag) { 43836448Svikram case V_SWAP: 43846448Svikram case V_USR: 43856448Svikram case V_BACKUP: 43866448Svikram case V_VAR: 43876448Svikram case V_HOME: 43886448Svikram case V_ALTSCTR: 43896448Svikram BAM_DPRINTF((D_VTOC_NOT_ROOT_TAG, fcn, slice)); 43906448Svikram continue; 43916448Svikram default: 43926448Svikram BAM_DPRINTF((D_VTOC_ROOT_TAG, fcn, slice)); 43936448Svikram break; 43946448Svikram } 43956448Svikram 43966448Svikram /* skip unmountable and readonly slices */ 43976448Svikram switch (vtoc->v_part[idx].p_flag) { 43986448Svikram case V_UNMNT: 43996448Svikram case V_RONLY: 44006448Svikram BAM_DPRINTF((D_VTOC_NOT_RDWR_FLAG, fcn, slice)); 44016448Svikram continue; 44026448Svikram default: 44036448Svikram BAM_DPRINTF((D_VTOC_RDWR_FLAG, fcn, slice)); 44046448Svikram break; 44056448Svikram } 44066448Svikram 44076448Svikram if (process_slice_common(slice, tfp, mhp, tmpmnt) == -1) { 44086448Svikram return (-1); 44096448Svikram } 44106448Svikram } 44116448Svikram 44126448Svikram return (0); 44136448Svikram } 44146448Svikram 44156448Svikram static int 44166448Svikram process_efi_slices( 44176448Svikram char *s0, 44186448Svikram struct dk_gpt *efi, 44196448Svikram FILE *tfp, 44206448Svikram mhash_t *mhp, 44216448Svikram char *tmpmnt) 44226448Svikram { 44236448Svikram int idx; 44246448Svikram char slice[PATH_MAX]; 44256448Svikram size_t len; 44266448Svikram char *cp; 44276448Svikram const char *fcn = "process_efi_slices()"; 44286448Svikram 44296448Svikram len = strlen(s0); 44306448Svikram 44316448Svikram assert(s0[len - 2] == 's' && s0[len - 1] == '0'); 44326448Svikram 44336448Svikram s0[len - 1] = '\0'; 44346448Svikram 44356448Svikram (void) strlcpy(slice, s0, sizeof (slice)); 44366448Svikram 44376448Svikram s0[len - 1] = '0'; 44386448Svikram 44396448Svikram cp = slice + len - 1; 44406448Svikram 44416448Svikram for (idx = 0; idx < efi->efi_nparts; idx++) { 44426448Svikram 44436448Svikram (void) snprintf(cp, sizeof (slice) - (len - 1), "%u", idx); 44446448Svikram 44456448Svikram if (efi->efi_parts[idx].p_size == 0) { 44466448Svikram BAM_DPRINTF((D_EFI_SIZE_ZERO, fcn, slice)); 44476448Svikram continue; 44486448Svikram } 44496448Svikram 44506448Svikram /* Skip "SWAP", "USR", "BACKUP", "VAR", "HOME", "ALTSCTR" */ 44516448Svikram switch (efi->efi_parts[idx].p_tag) { 44526448Svikram case V_SWAP: 44536448Svikram case V_USR: 44546448Svikram case V_BACKUP: 44556448Svikram case V_VAR: 44566448Svikram case V_HOME: 44576448Svikram case V_ALTSCTR: 44586448Svikram BAM_DPRINTF((D_EFI_NOT_ROOT_TAG, fcn, slice)); 44596448Svikram continue; 44606448Svikram default: 44616448Svikram BAM_DPRINTF((D_EFI_ROOT_TAG, fcn, slice)); 44626448Svikram break; 44636448Svikram } 44646448Svikram 44656448Svikram /* skip unmountable and readonly slices */ 44666448Svikram switch (efi->efi_parts[idx].p_flag) { 44676448Svikram case V_UNMNT: 44686448Svikram case V_RONLY: 44696448Svikram BAM_DPRINTF((D_EFI_NOT_RDWR_FLAG, fcn, slice)); 44706448Svikram continue; 44716448Svikram default: 44726448Svikram BAM_DPRINTF((D_EFI_RDWR_FLAG, fcn, slice)); 44736448Svikram break; 44746448Svikram } 44756448Svikram 44766448Svikram if (process_slice_common(slice, tfp, mhp, tmpmnt) == -1) { 44776448Svikram return (-1); 44786448Svikram } 44796448Svikram } 44806448Svikram 44816448Svikram return (0); 44826448Svikram } 44836448Svikram 44846448Svikram /* 44856448Svikram * s0 is a basename not a full path 44866448Svikram */ 44876448Svikram static int 44886448Svikram process_slice0(char *s0, FILE *tfp, mhash_t *mhp, char *tmpmnt) 44896448Svikram { 44906448Svikram struct vtoc vtoc; 44916448Svikram struct dk_gpt *efi; 44926448Svikram char s0path[PATH_MAX]; 44936448Svikram struct stat sbuf; 44946448Svikram int e_flag; 44956448Svikram int v_flag; 44966448Svikram int retval; 44976448Svikram int err; 44986448Svikram int fd; 44996448Svikram const char *fcn = "process_slice0()"; 45006448Svikram 45016448Svikram (void) snprintf(s0path, sizeof (s0path), "/dev/rdsk/%s", s0); 45026448Svikram 45036448Svikram if (stat(s0path, &sbuf) == -1) { 45046448Svikram BAM_DPRINTF((D_SLICE0_ENOENT, fcn, s0path)); 45056448Svikram return (0); 45066448Svikram } 45076448Svikram 45086448Svikram fd = open(s0path, O_NONBLOCK|O_RDONLY); 45096448Svikram if (fd == -1) { 45106448Svikram bam_error(OPEN_FAIL, s0path, strerror(errno)); 45116448Svikram return (0); 45126448Svikram } 45136448Svikram 45146448Svikram e_flag = v_flag = 0; 45156448Svikram retval = ((err = read_vtoc(fd, &vtoc)) >= 0) ? 0 : err; 45166448Svikram switch (retval) { 45176448Svikram case VT_EIO: 45186448Svikram BAM_DPRINTF((D_VTOC_READ_FAIL, fcn, s0path)); 45196448Svikram break; 45206448Svikram case VT_EINVAL: 45216448Svikram BAM_DPRINTF((D_VTOC_INVALID, fcn, s0path)); 45226448Svikram break; 45236448Svikram case VT_ERROR: 45246448Svikram BAM_DPRINTF((D_VTOC_UNKNOWN_ERR, fcn, s0path)); 45256448Svikram break; 45266448Svikram case VT_ENOTSUP: 45276448Svikram e_flag = 1; 45286448Svikram BAM_DPRINTF((D_VTOC_NOTSUP, fcn, s0path)); 45296448Svikram break; 45306448Svikram case 0: 45316448Svikram v_flag = 1; 45326448Svikram BAM_DPRINTF((D_VTOC_READ_SUCCESS, fcn, s0path)); 45336448Svikram break; 45346448Svikram default: 45356448Svikram BAM_DPRINTF((D_VTOC_UNKNOWN_RETCODE, fcn, s0path)); 45366448Svikram break; 45376448Svikram } 45386448Svikram 45396448Svikram 45406448Svikram if (e_flag) { 45416448Svikram e_flag = 0; 45426448Svikram retval = ((err = efi_alloc_and_read(fd, &efi)) >= 0) ? 0 : err; 45436448Svikram switch (retval) { 45446448Svikram case VT_EIO: 45456448Svikram BAM_DPRINTF((D_EFI_READ_FAIL, fcn, s0path)); 45466448Svikram break; 45476448Svikram case VT_EINVAL: 45486448Svikram BAM_DPRINTF((D_EFI_INVALID, fcn, s0path)); 45496448Svikram break; 45506448Svikram case VT_ERROR: 45516448Svikram BAM_DPRINTF((D_EFI_UNKNOWN_ERR, fcn, s0path)); 45526448Svikram break; 45536448Svikram case VT_ENOTSUP: 45546448Svikram BAM_DPRINTF((D_EFI_NOTSUP, fcn, s0path)); 45556448Svikram break; 45566448Svikram case 0: 45576448Svikram e_flag = 1; 45586448Svikram BAM_DPRINTF((D_EFI_READ_SUCCESS, fcn, s0path)); 45596448Svikram break; 45606448Svikram default: 45616448Svikram BAM_DPRINTF((D_EFI_UNKNOWN_RETCODE, fcn, s0path)); 45626448Svikram break; 45636448Svikram } 45646448Svikram } 45656448Svikram 45666448Svikram (void) close(fd); 45676448Svikram 45686448Svikram if (v_flag) { 45696448Svikram retval = process_vtoc_slices(s0, 45706448Svikram &vtoc, tfp, mhp, tmpmnt); 45716448Svikram } else if (e_flag) { 45726448Svikram retval = process_efi_slices(s0, 45736448Svikram efi, tfp, mhp, tmpmnt); 45746448Svikram } else { 45756448Svikram BAM_DPRINTF((D_NOT_VTOC_OR_EFI, fcn, s0path)); 45766448Svikram return (0); 45776448Svikram } 45786448Svikram 45796448Svikram return (retval); 45806448Svikram } 45816448Svikram 45826448Svikram /* 45836448Svikram * Find and create a list of all existing UFS boot signatures 45846448Svikram */ 45856448Svikram static int 45866448Svikram FindAllUfsSignatures(void) 45876448Svikram { 45886448Svikram mhash_t *mnttab_hash; 45896448Svikram DIR *dirp = NULL; 45906448Svikram struct dirent *dp; 45916448Svikram char tmpmnt[PATH_MAX]; 45926448Svikram char cmd[PATH_MAX]; 45936448Svikram struct stat sb; 45946448Svikram int fd; 45956448Svikram FILE *tfp; 45966448Svikram size_t len; 45976448Svikram int ret; 45986448Svikram int error; 45996448Svikram const char *fcn = "FindAllUfsSignatures()"; 46006448Svikram 46016448Svikram if (stat(UFS_SIGNATURE_LIST, &sb) != -1) { 46026448Svikram bam_print(SIGNATURE_LIST_EXISTS, UFS_SIGNATURE_LIST); 46036448Svikram return (0); 46046448Svikram } 46056448Svikram 46066448Svikram fd = open(UFS_SIGNATURE_LIST".tmp", 46076448Svikram O_RDWR|O_CREAT|O_TRUNC, 0644); 46086448Svikram error = errno; 46096448Svikram INJECT_ERROR1("SIGN_LIST_TMP_TRUNC", fd = -1); 46106448Svikram if (fd == -1) { 46116448Svikram bam_error(OPEN_FAIL, UFS_SIGNATURE_LIST".tmp", strerror(error)); 46126448Svikram return (-1); 46136448Svikram } 46146448Svikram 46156448Svikram ret = close(fd); 46166448Svikram error = errno; 46176448Svikram INJECT_ERROR1("SIGN_LIST_TMP_CLOSE", ret = -1); 46186448Svikram if (ret == -1) { 46196448Svikram bam_error(CLOSE_FAIL, UFS_SIGNATURE_LIST".tmp", 46206448Svikram strerror(error)); 46216448Svikram (void) unlink(UFS_SIGNATURE_LIST".tmp"); 46226448Svikram return (-1); 46236448Svikram } 46246448Svikram 46256448Svikram tfp = fopen(UFS_SIGNATURE_LIST".tmp", "a"); 46266448Svikram error = errno; 46276448Svikram INJECT_ERROR1("SIGN_LIST_APPEND_FOPEN", tfp = NULL); 46286448Svikram if (tfp == NULL) { 46296448Svikram bam_error(OPEN_FAIL, UFS_SIGNATURE_LIST".tmp", strerror(error)); 46306448Svikram (void) unlink(UFS_SIGNATURE_LIST".tmp"); 46316448Svikram return (-1); 46326448Svikram } 46336448Svikram 46346448Svikram mnttab_hash = cache_mnttab(); 46356448Svikram INJECT_ERROR1("CACHE_MNTTAB_ERROR", mnttab_hash = NULL); 46366448Svikram if (mnttab_hash == NULL) { 46376448Svikram (void) fclose(tfp); 46386448Svikram (void) unlink(UFS_SIGNATURE_LIST".tmp"); 46396448Svikram bam_error(CACHE_MNTTAB_FAIL, fcn); 46406448Svikram return (-1); 46416448Svikram } 46426448Svikram 46436448Svikram (void) snprintf(tmpmnt, sizeof (tmpmnt), 46446448Svikram "/tmp/bootadm_ufs_sign_mnt.%d", getpid()); 46456448Svikram (void) unlink(tmpmnt); 46466448Svikram 46476448Svikram ret = mkdirp(tmpmnt, 0755); 46486448Svikram error = errno; 46496448Svikram INJECT_ERROR1("MKDIRP_SIGN_MNT", ret = -1); 46506448Svikram if (ret == -1) { 46516448Svikram bam_error(MKDIR_FAILED, tmpmnt, strerror(error)); 46526448Svikram free_mnttab(mnttab_hash); 46536448Svikram (void) fclose(tfp); 46546448Svikram (void) unlink(UFS_SIGNATURE_LIST".tmp"); 46556448Svikram return (-1); 46566448Svikram } 46576448Svikram 46586448Svikram dirp = opendir("/dev/rdsk"); 46596448Svikram error = errno; 46606448Svikram INJECT_ERROR1("OPENDIR_DEV_RDSK", dirp = NULL); 46616448Svikram if (dirp == NULL) { 46626448Svikram bam_error(OPENDIR_FAILED, "/dev/rdsk", strerror(error)); 46636448Svikram goto fail; 46646448Svikram } 46656448Svikram 46666448Svikram while (dp = readdir(dirp)) { 46676448Svikram if (strcmp(dp->d_name, ".") == 0 || 46686448Svikram strcmp(dp->d_name, "..") == 0) 46696448Svikram continue; 46706448Svikram 46716448Svikram /* 46726448Svikram * we only look for the s0 slice. This is guranteed to 46736448Svikram * have 's' at len - 2. 46746448Svikram */ 46756448Svikram len = strlen(dp->d_name); 46766448Svikram if (dp->d_name[len - 2 ] != 's' || dp->d_name[len - 1] != '0') { 46776448Svikram BAM_DPRINTF((D_SKIP_SLICE_NOTZERO, fcn, dp->d_name)); 46786448Svikram continue; 46796448Svikram } 46806448Svikram 46816448Svikram ret = process_slice0(dp->d_name, tfp, mnttab_hash, tmpmnt); 46826448Svikram INJECT_ERROR1("PROCESS_S0_FAIL", ret = -1); 46836448Svikram if (ret == -1) 46846448Svikram goto fail; 46856448Svikram } 46866448Svikram 46876448Svikram (void) closedir(dirp); 46886448Svikram free_mnttab(mnttab_hash); 46896448Svikram (void) rmdir(tmpmnt); 46906448Svikram 46916448Svikram ret = fclose(tfp); 46926448Svikram error = errno; 46936448Svikram INJECT_ERROR1("FCLOSE_SIGNLIST_TMP", ret = EOF); 46946448Svikram if (ret == EOF) { 46956448Svikram bam_error(CLOSE_FAIL, UFS_SIGNATURE_LIST".tmp", 46966448Svikram strerror(error)); 46976448Svikram (void) unlink(UFS_SIGNATURE_LIST".tmp"); 46986448Svikram return (-1); 46996448Svikram } 47006448Svikram 47016448Svikram /* We have a list of existing GRUB signatures. Sort it first */ 47026448Svikram (void) snprintf(cmd, sizeof (cmd), 47036448Svikram "/usr/bin/sort -u %s.tmp > %s.sorted", 47046448Svikram UFS_SIGNATURE_LIST, UFS_SIGNATURE_LIST); 47056448Svikram 47066448Svikram ret = exec_cmd(cmd, NULL); 47076448Svikram INJECT_ERROR1("SORT_SIGN_LIST", ret = 1); 47086448Svikram if (ret != 0) { 47096448Svikram bam_error(GRUBSIGN_SORT_FAILED); 47106448Svikram (void) unlink(UFS_SIGNATURE_LIST".sorted"); 47116448Svikram (void) unlink(UFS_SIGNATURE_LIST".tmp"); 47126448Svikram return (-1); 47136448Svikram } 47146448Svikram 47156448Svikram (void) unlink(UFS_SIGNATURE_LIST".tmp"); 47166448Svikram 47176448Svikram ret = rename(UFS_SIGNATURE_LIST".sorted", UFS_SIGNATURE_LIST); 47186448Svikram error = errno; 47196448Svikram INJECT_ERROR1("RENAME_TMP_SIGNLIST", ret = -1); 47206448Svikram if (ret == -1) { 47216448Svikram bam_error(RENAME_FAIL, UFS_SIGNATURE_LIST, strerror(error)); 47226448Svikram (void) unlink(UFS_SIGNATURE_LIST".sorted"); 47236448Svikram return (-1); 47246448Svikram } 47256448Svikram 47266448Svikram if (stat(UFS_SIGNATURE_LIST, &sb) == 0 && sb.st_size == 0) { 47276448Svikram BAM_DPRINTF((D_ZERO_LEN_SIGNLIST, fcn, UFS_SIGNATURE_LIST)); 47286448Svikram } 47296448Svikram 47306448Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 47316448Svikram return (0); 47326448Svikram 47336448Svikram fail: 47346448Svikram if (dirp) 47356448Svikram (void) closedir(dirp); 47366448Svikram free_mnttab(mnttab_hash); 47376448Svikram (void) rmdir(tmpmnt); 47386448Svikram (void) fclose(tfp); 47396448Svikram (void) unlink(UFS_SIGNATURE_LIST".tmp"); 47406448Svikram BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 47416448Svikram return (-1); 47426448Svikram } 47436448Svikram 47446448Svikram static char * 47456448Svikram create_ufs_sign(void) 47466448Svikram { 47476448Svikram struct stat sb; 47486448Svikram int signnum = -1; 47496448Svikram char tmpsign[MAXNAMELEN + 1]; 47506448Svikram char *numstr; 47516448Svikram int i; 47526448Svikram FILE *tfp; 47536448Svikram int ret; 47546448Svikram int error; 47556448Svikram const char *fcn = "create_ufs_sign()"; 47566448Svikram 47576448Svikram bam_print(SEARCHING_UFS_SIGN); 47586448Svikram 47596448Svikram ret = FindAllUfsSignatures(); 47606448Svikram INJECT_ERROR1("FIND_ALL_UFS", ret = -1); 47616448Svikram if (ret == -1) { 47626448Svikram bam_error(ERR_FIND_UFS_SIGN); 47636448Svikram return (NULL); 47646448Svikram } 47656448Svikram 47666448Svikram /* Make sure the list exists and is owned by root */ 47676448Svikram INJECT_ERROR1("SIGNLIST_NOT_CREATED", 47686448Svikram (void) unlink(UFS_SIGNATURE_LIST)); 47696448Svikram if (stat(UFS_SIGNATURE_LIST, &sb) == -1 || sb.st_uid != 0) { 47706448Svikram (void) unlink(UFS_SIGNATURE_LIST); 47716448Svikram bam_error(UFS_SIGNATURE_LIST_MISS, UFS_SIGNATURE_LIST); 47726448Svikram return (NULL); 47736448Svikram } 47746448Svikram 47756448Svikram if (sb.st_size == 0) { 47766448Svikram bam_print(GRUBSIGN_UFS_NONE); 47776448Svikram i = 0; 47786448Svikram goto found; 47796448Svikram } 47806448Svikram 47816448Svikram /* The signature list was sorted when it was created */ 47826448Svikram tfp = fopen(UFS_SIGNATURE_LIST, "r"); 47836448Svikram error = errno; 47846448Svikram INJECT_ERROR1("FOPEN_SIGN_LIST", tfp = NULL); 47856448Svikram if (tfp == NULL) { 47866448Svikram bam_error(UFS_SIGNATURE_LIST_OPENERR, 47876448Svikram UFS_SIGNATURE_LIST, strerror(error)); 47886448Svikram (void) unlink(UFS_SIGNATURE_LIST); 47896448Svikram return (NULL); 47906448Svikram } 47916448Svikram 47926448Svikram for (i = 0; s_fgets(tmpsign, sizeof (tmpsign), tfp); i++) { 47936448Svikram 47946448Svikram if (strncmp(tmpsign, GRUBSIGN_UFS_PREFIX, 47956448Svikram strlen(GRUBSIGN_UFS_PREFIX)) != 0) { 47966448Svikram (void) fclose(tfp); 47976448Svikram (void) unlink(UFS_SIGNATURE_LIST); 47986448Svikram bam_error(UFS_BADSIGN, tmpsign); 47996448Svikram return (NULL); 48006448Svikram } 48016448Svikram numstr = tmpsign + strlen(GRUBSIGN_UFS_PREFIX); 48026448Svikram 48036448Svikram if (numstr[0] == '\0' || !isdigit(numstr[0])) { 48046448Svikram (void) fclose(tfp); 48056448Svikram (void) unlink(UFS_SIGNATURE_LIST); 48066448Svikram bam_error(UFS_BADSIGN, tmpsign); 48076448Svikram return (NULL); 48086448Svikram } 48096448Svikram 48106448Svikram signnum = atoi(numstr); 48116448Svikram INJECT_ERROR1("NEGATIVE_SIGN", signnum = -1); 48126448Svikram if (signnum < 0) { 48136448Svikram (void) fclose(tfp); 48146448Svikram (void) unlink(UFS_SIGNATURE_LIST); 48156448Svikram bam_error(UFS_BADSIGN, tmpsign); 48166448Svikram return (NULL); 48176448Svikram } 48186448Svikram 48196448Svikram if (i != signnum) { 48206448Svikram BAM_DPRINTF((D_FOUND_HOLE_SIGNLIST, fcn, i)); 48216448Svikram break; 48226448Svikram } 48236448Svikram } 48246448Svikram 48256448Svikram (void) fclose(tfp); 48266448Svikram 48276448Svikram found: 48286448Svikram (void) snprintf(tmpsign, sizeof (tmpsign), "rootfs%d", i); 48296448Svikram 48306448Svikram /* add the ufs signature to the /var/run list of signatures */ 48316448Svikram ret = ufs_add_to_sign_list(tmpsign); 48326448Svikram INJECT_ERROR1("UFS_ADD_TO_SIGN_LIST", ret = -1); 48336448Svikram if (ret == -1) { 48346448Svikram (void) unlink(UFS_SIGNATURE_LIST); 48356448Svikram bam_error(FAILED_ADD_SIGNLIST, tmpsign); 48366448Svikram return (NULL); 48376448Svikram } 48386448Svikram 48396448Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 48406448Svikram 48416448Svikram return (s_strdup(tmpsign)); 48426448Svikram } 48436448Svikram 48446448Svikram static char * 48456448Svikram get_fstype(char *osroot) 48466448Svikram { 48476448Svikram FILE *mntfp; 48486448Svikram struct mnttab mp = {0}; 48496448Svikram struct mnttab mpref = {0}; 48506448Svikram int error; 48516448Svikram int ret; 48526448Svikram const char *fcn = "get_fstype()"; 48536448Svikram 48546448Svikram INJECT_ERROR1("GET_FSTYPE_OSROOT", osroot = NULL); 48556448Svikram if (osroot == NULL) { 48566448Svikram bam_error(GET_FSTYPE_ARGS); 48576448Svikram return (NULL); 48586448Svikram } 48596448Svikram 48606448Svikram mntfp = fopen(MNTTAB, "r"); 48616448Svikram error = errno; 48626448Svikram INJECT_ERROR1("GET_FSTYPE_FOPEN", mntfp = NULL); 48636448Svikram if (mntfp == NULL) { 48646448Svikram bam_error(OPEN_FAIL, MNTTAB, strerror(error)); 48656448Svikram return (NULL); 48666448Svikram } 48676448Svikram 48686448Svikram if (*osroot == '\0') 48696448Svikram mpref.mnt_mountp = "/"; 48706448Svikram else 48716448Svikram mpref.mnt_mountp = osroot; 48726448Svikram 48736448Svikram ret = getmntany(mntfp, &mp, &mpref); 48746448Svikram INJECT_ERROR1("GET_FSTYPE_GETMNTANY", ret = 1); 48756448Svikram if (ret != 0) { 48766448Svikram bam_error(MNTTAB_MNTPT_NOT_FOUND, osroot, MNTTAB); 48776448Svikram (void) fclose(mntfp); 48786448Svikram return (NULL); 48796448Svikram } 48806448Svikram (void) fclose(mntfp); 48816448Svikram 48826448Svikram INJECT_ERROR1("GET_FSTYPE_NULL", mp.mnt_fstype = NULL); 48836448Svikram if (mp.mnt_fstype == NULL) { 48846448Svikram bam_error(MNTTAB_FSTYPE_NULL, osroot); 48856448Svikram return (NULL); 48866448Svikram } 48876448Svikram 48886448Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 48896448Svikram 48906448Svikram return (s_strdup(mp.mnt_fstype)); 48916448Svikram } 48926448Svikram 48936448Svikram static char * 48946448Svikram create_zfs_sign(char *osdev) 48956448Svikram { 48966448Svikram char tmpsign[PATH_MAX]; 48976448Svikram char *pool; 48986448Svikram const char *fcn = "create_zfs_sign()"; 48996448Svikram 49006448Svikram BAM_DPRINTF((D_FUNC_ENTRY1, fcn, osdev)); 49016448Svikram 49026448Svikram /* 49036448Svikram * First find the pool name 49046448Svikram */ 49056448Svikram pool = get_pool(osdev); 49066448Svikram INJECT_ERROR1("CREATE_ZFS_SIGN_GET_POOL", pool = NULL); 49076448Svikram if (pool == NULL) { 49086448Svikram bam_error(GET_POOL_FAILED, osdev); 49096448Svikram return (NULL); 49106448Svikram } 49116448Svikram 49126448Svikram (void) snprintf(tmpsign, sizeof (tmpsign), "pool_%s", pool); 49136448Svikram 49146448Svikram BAM_DPRINTF((D_CREATED_ZFS_SIGN, fcn, tmpsign)); 49156448Svikram 49166448Svikram free(pool); 49176448Svikram 49186448Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 49196448Svikram 49206448Svikram return (s_strdup(tmpsign)); 49216448Svikram } 49226448Svikram 49236448Svikram static char * 49246448Svikram create_new_sign(char *osdev, char *fstype) 49256448Svikram { 49266448Svikram char *sign; 49276448Svikram const char *fcn = "create_new_sign()"; 49286448Svikram 49296448Svikram INJECT_ERROR1("NEW_SIGN_FSTYPE", fstype = "foofs"); 49306448Svikram 49316448Svikram if (strcmp(fstype, "zfs") == 0) { 49326448Svikram BAM_DPRINTF((D_CREATE_NEW_ZFS, fcn)); 49336448Svikram sign = create_zfs_sign(osdev); 49346448Svikram } else if (strcmp(fstype, "ufs") == 0) { 49356448Svikram BAM_DPRINTF((D_CREATE_NEW_UFS, fcn)); 49366448Svikram sign = create_ufs_sign(); 49376448Svikram } else { 49386448Svikram bam_error(GRUBSIGN_NOTSUP, fstype); 49396448Svikram sign = NULL; 49406448Svikram } 49416448Svikram 49426448Svikram BAM_DPRINTF((D_CREATED_NEW_SIGN, fcn, sign ? sign : "<NULL>")); 49436448Svikram return (sign); 49446448Svikram } 49456448Svikram 49466448Svikram static int 49476448Svikram set_backup_common(char *mntpt, char *sign) 49486448Svikram { 49496448Svikram FILE *bfp; 49506448Svikram char backup[PATH_MAX]; 49516448Svikram char tmpsign[PATH_MAX]; 49526448Svikram int error; 49536448Svikram char *bdir; 49546448Svikram char *backup_dup; 49556448Svikram struct stat sb; 49566448Svikram int ret; 49576448Svikram const char *fcn = "set_backup_common()"; 49586448Svikram 49596448Svikram (void) snprintf(backup, sizeof (backup), "%s%s", 49606448Svikram mntpt, GRUBSIGN_BACKUP); 49616448Svikram 49626448Svikram /* First read the backup */ 49636448Svikram bfp = fopen(backup, "r"); 49646448Svikram if (bfp != NULL) { 49656448Svikram while (s_fgets(tmpsign, sizeof (tmpsign), bfp)) { 49666448Svikram if (strcmp(tmpsign, sign) == 0) { 49676448Svikram BAM_DPRINTF((D_FOUND_IN_BACKUP, fcn, sign)); 49686448Svikram (void) fclose(bfp); 49696448Svikram return (0); 49706448Svikram } 49716448Svikram } 49726448Svikram (void) fclose(bfp); 49736448Svikram BAM_DPRINTF((D_NOT_FOUND_IN_EXIST_BACKUP, fcn, sign)); 49746448Svikram } else { 49756448Svikram BAM_DPRINTF((D_BACKUP_NOT_EXIST, fcn, backup)); 49766448Svikram } 49776448Svikram 49786448Svikram /* 49796448Svikram * Didn't find the correct signature. First create 49806448Svikram * the directory if necessary. 49816448Svikram */ 49826448Svikram 49836448Svikram /* dirname() modifies its argument so dup it */ 49846448Svikram backup_dup = s_strdup(backup); 49856448Svikram bdir = dirname(backup_dup); 49866448Svikram assert(bdir); 49876448Svikram 49886448Svikram ret = stat(bdir, &sb); 49896448Svikram INJECT_ERROR1("SET_BACKUP_STAT", ret = -1); 49906448Svikram if (ret == -1) { 49916448Svikram BAM_DPRINTF((D_BACKUP_DIR_NOEXIST, fcn, bdir)); 49926448Svikram ret = mkdirp(bdir, 0755); 49936448Svikram error = errno; 49946448Svikram INJECT_ERROR1("SET_BACKUP_MKDIRP", ret = -1); 49956448Svikram if (ret == -1) { 49966448Svikram bam_error(GRUBSIGN_BACKUP_MKDIRERR, 49976448Svikram GRUBSIGN_BACKUP, strerror(error)); 49986448Svikram free(backup_dup); 49996448Svikram return (-1); 50006448Svikram } 50016448Svikram } 50026448Svikram free(backup_dup); 50036448Svikram 50046448Svikram /* 50056448Svikram * Open the backup in append mode to add the correct 50066448Svikram * signature; 50076448Svikram */ 50086448Svikram bfp = fopen(backup, "a"); 50096448Svikram error = errno; 50106448Svikram INJECT_ERROR1("SET_BACKUP_FOPEN_A", bfp = NULL); 50116448Svikram if (bfp == NULL) { 50126448Svikram bam_error(GRUBSIGN_BACKUP_OPENERR, 50136448Svikram GRUBSIGN_BACKUP, strerror(error)); 50146448Svikram return (-1); 50156448Svikram } 50166448Svikram 50176448Svikram (void) snprintf(tmpsign, sizeof (tmpsign), "%s\n", sign); 50186448Svikram 50196448Svikram ret = fputs(tmpsign, bfp); 50206448Svikram error = errno; 50216448Svikram INJECT_ERROR1("SET_BACKUP_FPUTS", ret = 0); 50226448Svikram if (ret != strlen(tmpsign)) { 50236448Svikram bam_error(GRUBSIGN_BACKUP_WRITEERR, 50246448Svikram GRUBSIGN_BACKUP, strerror(error)); 50256448Svikram (void) fclose(bfp); 50266448Svikram return (-1); 50276448Svikram } 50286448Svikram 50296448Svikram (void) fclose(bfp); 50306448Svikram 50316448Svikram if (bam_verbose) 50326448Svikram bam_print(GRUBSIGN_BACKUP_UPDATED, GRUBSIGN_BACKUP); 50336448Svikram 50346448Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 50356448Svikram 50366448Svikram return (0); 50376448Svikram } 50386448Svikram 50396448Svikram static int 50406448Svikram set_backup_ufs(char *osroot, char *sign) 50416448Svikram { 50426448Svikram const char *fcn = "set_backup_ufs()"; 50436448Svikram 50446448Svikram BAM_DPRINTF((D_FUNC_ENTRY2, fcn, osroot, sign)); 50456448Svikram return (set_backup_common(osroot, sign)); 50466448Svikram } 50476448Svikram 50486448Svikram static int 50496448Svikram set_backup_zfs(char *osdev, char *sign) 50506448Svikram { 50516448Svikram char *pool; 50526448Svikram char *mntpt; 50536448Svikram zfs_mnted_t mnted; 50546448Svikram int ret; 50556448Svikram const char *fcn = "set_backup_zfs()"; 50566448Svikram 50576448Svikram BAM_DPRINTF((D_FUNC_ENTRY2, fcn, osdev, sign)); 50586448Svikram 50596448Svikram pool = get_pool(osdev); 50606448Svikram INJECT_ERROR1("SET_BACKUP_GET_POOL", pool = NULL); 50616448Svikram if (pool == NULL) { 50626448Svikram bam_error(GET_POOL_FAILED, osdev); 50636448Svikram return (-1); 50646448Svikram } 50656448Svikram 50666448Svikram mntpt = mount_top_dataset(pool, &mnted); 50676448Svikram INJECT_ERROR1("SET_BACKUP_MOUNT_DATASET", mntpt = NULL); 50686448Svikram if (mntpt == NULL) { 50696448Svikram bam_error(FAIL_MNT_TOP_DATASET, pool); 50706448Svikram free(pool); 50716448Svikram return (-1); 50726448Svikram } 50736448Svikram 50746448Svikram ret = set_backup_common(mntpt, sign); 50756448Svikram 50766448Svikram (void) umount_top_dataset(pool, mnted, mntpt); 50776448Svikram 50786448Svikram free(pool); 50796448Svikram 50806448Svikram INJECT_ERROR1("SET_BACKUP_ZFS_FAIL", ret = 1); 50816448Svikram if (ret == 0) { 50826448Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 50836448Svikram } else { 50846448Svikram BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 50856448Svikram } 50866448Svikram 50876448Svikram return (ret); 50886448Svikram } 50896448Svikram 50906448Svikram static int 50916448Svikram set_backup(char *osroot, char *osdev, char *sign, char *fstype) 50926448Svikram { 50936448Svikram const char *fcn = "set_backup()"; 50946448Svikram int ret; 50956448Svikram 50966448Svikram INJECT_ERROR1("SET_BACKUP_FSTYPE", fstype = "foofs"); 50976448Svikram 50986448Svikram if (strcmp(fstype, "ufs") == 0) { 50996448Svikram BAM_DPRINTF((D_SET_BACKUP_UFS, fcn)); 51006448Svikram ret = set_backup_ufs(osroot, sign); 51016448Svikram } else if (strcmp(fstype, "zfs") == 0) { 51026448Svikram BAM_DPRINTF((D_SET_BACKUP_ZFS, fcn)); 51036448Svikram ret = set_backup_zfs(osdev, sign); 51046448Svikram } else { 51056448Svikram bam_error(GRUBSIGN_NOTSUP, fstype); 51066448Svikram ret = -1; 51076448Svikram } 51086448Svikram 51096448Svikram if (ret == 0) { 51106448Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 51116448Svikram } else { 51126448Svikram BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 51136448Svikram } 51146448Svikram 51156448Svikram return (ret); 51166448Svikram } 51176448Svikram 51186448Svikram static int 51196448Svikram set_primary_common(char *mntpt, char *sign) 51206448Svikram { 51216448Svikram char signfile[PATH_MAX]; 51226448Svikram char signdir[PATH_MAX]; 51236448Svikram struct stat sb; 51246448Svikram int fd; 51256448Svikram int error; 51266448Svikram int ret; 51276448Svikram const char *fcn = "set_primary_common()"; 51286448Svikram 51296448Svikram (void) snprintf(signfile, sizeof (signfile), "%s/%s/%s", 51306448Svikram mntpt, GRUBSIGN_DIR, sign); 51316448Svikram 51326448Svikram if (stat(signfile, &sb) != -1) { 51336448Svikram if (bam_verbose) 51346448Svikram bam_print(PRIMARY_SIGN_EXISTS, sign); 51356448Svikram return (0); 51366448Svikram } else { 51376448Svikram BAM_DPRINTF((D_PRIMARY_NOT_EXIST, fcn, signfile)); 51386448Svikram } 51396448Svikram 51406448Svikram (void) snprintf(signdir, sizeof (signdir), "%s/%s", 51416448Svikram mntpt, GRUBSIGN_DIR); 51426448Svikram 51436448Svikram if (stat(signdir, &sb) == -1) { 51446448Svikram BAM_DPRINTF((D_PRIMARY_DIR_NOEXIST, fcn, signdir)); 51456448Svikram ret = mkdirp(signdir, 0755); 51466448Svikram error = errno; 51476448Svikram INJECT_ERROR1("SET_PRIMARY_MKDIRP", ret = -1); 51486448Svikram if (ret == -1) { 51496448Svikram bam_error(GRUBSIGN_MKDIR_ERR, signdir, strerror(errno)); 51506448Svikram return (-1); 51516448Svikram } 51526448Svikram } 51536448Svikram 51546448Svikram fd = open(signfile, O_RDWR|O_CREAT|O_TRUNC, 0444); 51556448Svikram error = errno; 51566448Svikram INJECT_ERROR1("PRIMARY_SIGN_CREAT", fd = -1); 51576448Svikram if (fd == -1) { 51586448Svikram bam_error(GRUBSIGN_PRIMARY_CREATERR, signfile, strerror(error)); 51596448Svikram return (-1); 51606448Svikram } 51616448Svikram 51626448Svikram ret = fsync(fd); 51636448Svikram error = errno; 51646448Svikram INJECT_ERROR1("PRIMARY_FSYNC", ret = -1); 51656448Svikram if (ret != 0) { 51666448Svikram bam_error(GRUBSIGN_PRIMARY_SYNCERR, signfile, strerror(error)); 51676448Svikram } 51686448Svikram 51696448Svikram (void) close(fd); 51706448Svikram 51716448Svikram if (bam_verbose) 51726448Svikram bam_print(GRUBSIGN_CREATED_PRIMARY, signfile); 51736448Svikram 51746448Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 51756448Svikram 51766448Svikram return (0); 51776448Svikram } 51786448Svikram 51796448Svikram static int 51806448Svikram set_primary_ufs(char *osroot, char *sign) 51816448Svikram { 51826448Svikram const char *fcn = "set_primary_ufs()"; 51836448Svikram 51846448Svikram BAM_DPRINTF((D_FUNC_ENTRY2, fcn, osroot, sign)); 51856448Svikram return (set_primary_common(osroot, sign)); 51866448Svikram } 51876448Svikram 51886448Svikram static int 51896448Svikram set_primary_zfs(char *osdev, char *sign) 51906448Svikram { 51916448Svikram char *pool; 51926448Svikram char *mntpt; 51936448Svikram zfs_mnted_t mnted; 51946448Svikram int ret; 51956448Svikram const char *fcn = "set_primary_zfs()"; 51966448Svikram 51976448Svikram BAM_DPRINTF((D_FUNC_ENTRY2, fcn, osdev, sign)); 51986448Svikram 51996448Svikram pool = get_pool(osdev); 52006448Svikram INJECT_ERROR1("SET_PRIMARY_ZFS_GET_POOL", pool = NULL); 52016448Svikram if (pool == NULL) { 52026448Svikram bam_error(GET_POOL_FAILED, osdev); 52036448Svikram return (-1); 52046448Svikram } 52056448Svikram 52066448Svikram /* Pool name must exist in the sign */ 52076448Svikram ret = (strstr(sign, pool) != NULL); 52086448Svikram INJECT_ERROR1("SET_PRIMARY_ZFS_POOL_SIGN_INCOMPAT", ret = 0); 52096448Svikram if (ret == 0) { 52106448Svikram bam_error(POOL_SIGN_INCOMPAT, pool, sign); 52116448Svikram free(pool); 52126448Svikram return (-1); 52136448Svikram } 52146448Svikram 52156448Svikram mntpt = mount_top_dataset(pool, &mnted); 52166448Svikram INJECT_ERROR1("SET_PRIMARY_ZFS_MOUNT_DATASET", mntpt = NULL); 52176448Svikram if (mntpt == NULL) { 52186448Svikram bam_error(FAIL_MNT_TOP_DATASET, pool); 52196448Svikram free(pool); 52206448Svikram return (-1); 52216448Svikram } 52226448Svikram 52236448Svikram ret = set_primary_common(mntpt, sign); 52246448Svikram 52256448Svikram (void) umount_top_dataset(pool, mnted, mntpt); 52266448Svikram 52276448Svikram free(pool); 52286448Svikram 52296448Svikram INJECT_ERROR1("SET_PRIMARY_ZFS_FAIL", ret = 1); 52306448Svikram if (ret == 0) { 52316448Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 52326448Svikram } else { 52336448Svikram BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 52346448Svikram } 52356448Svikram 52366448Svikram return (ret); 52376448Svikram } 52386448Svikram 52396448Svikram static int 52406448Svikram set_primary(char *osroot, char *osdev, char *sign, char *fstype) 52416448Svikram { 52426448Svikram const char *fcn = "set_primary()"; 52436448Svikram int ret; 52446448Svikram 52456448Svikram INJECT_ERROR1("SET_PRIMARY_FSTYPE", fstype = "foofs"); 52466448Svikram if (strcmp(fstype, "ufs") == 0) { 52476448Svikram BAM_DPRINTF((D_SET_PRIMARY_UFS, fcn)); 52486448Svikram ret = set_primary_ufs(osroot, sign); 52496448Svikram } else if (strcmp(fstype, "zfs") == 0) { 52506448Svikram BAM_DPRINTF((D_SET_PRIMARY_ZFS, fcn)); 52516448Svikram ret = set_primary_zfs(osdev, sign); 52526448Svikram } else { 52536448Svikram bam_error(GRUBSIGN_NOTSUP, fstype); 52546448Svikram ret = -1; 52556448Svikram } 52566448Svikram 52576448Svikram if (ret == 0) { 52586448Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 52596448Svikram } else { 52606448Svikram BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 52616448Svikram } 52626448Svikram 52636448Svikram return (ret); 52646448Svikram } 52656448Svikram 52666448Svikram static int 52676448Svikram ufs_add_to_sign_list(char *sign) 52686448Svikram { 52696448Svikram FILE *tfp; 52706448Svikram char signline[MAXNAMELEN]; 52716448Svikram char cmd[PATH_MAX]; 52726448Svikram int ret; 52736448Svikram int error; 52746448Svikram const char *fcn = "ufs_add_to_sign_list()"; 52756448Svikram 52766448Svikram INJECT_ERROR1("ADD_TO_SIGN_LIST_NOT_UFS", sign = "pool_rpool5"); 52776448Svikram if (strncmp(sign, GRUBSIGN_UFS_PREFIX, 52786448Svikram strlen(GRUBSIGN_UFS_PREFIX)) != 0) { 52796448Svikram bam_error(INVALID_UFS_SIGN, sign); 52806448Svikram (void) unlink(UFS_SIGNATURE_LIST); 52816448Svikram return (-1); 52826448Svikram } 52836448Svikram 52846448Svikram /* 52856448Svikram * most failures in this routine are not a fatal error 52866448Svikram * We simply unlink the /var/run file and continue 52876448Svikram */ 52886448Svikram 52896448Svikram ret = rename(UFS_SIGNATURE_LIST, UFS_SIGNATURE_LIST".tmp"); 52906448Svikram error = errno; 52916448Svikram INJECT_ERROR1("ADD_TO_SIGN_LIST_RENAME", ret = -1); 52926448Svikram if (ret == -1) { 52936448Svikram bam_error(RENAME_FAIL, UFS_SIGNATURE_LIST".tmp", 52946448Svikram strerror(error)); 52956448Svikram (void) unlink(UFS_SIGNATURE_LIST); 52966448Svikram return (0); 52976448Svikram } 52986448Svikram 52996448Svikram tfp = fopen(UFS_SIGNATURE_LIST".tmp", "a"); 53006448Svikram error = errno; 53016448Svikram INJECT_ERROR1("ADD_TO_SIGN_LIST_FOPEN", tfp = NULL); 53026448Svikram if (tfp == NULL) { 53036448Svikram bam_error(OPEN_FAIL, UFS_SIGNATURE_LIST".tmp", strerror(error)); 53046448Svikram (void) unlink(UFS_SIGNATURE_LIST".tmp"); 53056448Svikram return (0); 53066448Svikram } 53076448Svikram 53086448Svikram (void) snprintf(signline, sizeof (signline), "%s\n", sign); 53096448Svikram 53106448Svikram ret = fputs(signline, tfp); 53116448Svikram error = errno; 53126448Svikram INJECT_ERROR1("ADD_TO_SIGN_LIST_FPUTS", ret = 0); 53136448Svikram if (ret != strlen(signline)) { 53146448Svikram bam_error(SIGN_LIST_FPUTS_ERR, sign, strerror(error)); 53156448Svikram (void) fclose(tfp); 53166448Svikram (void) unlink(UFS_SIGNATURE_LIST".tmp"); 53176448Svikram return (0); 53186448Svikram } 53196448Svikram 53206448Svikram ret = fclose(tfp); 53216448Svikram error = errno; 53226448Svikram INJECT_ERROR1("ADD_TO_SIGN_LIST_FCLOSE", ret = EOF); 53236448Svikram if (ret == EOF) { 53246448Svikram bam_error(CLOSE_FAIL, UFS_SIGNATURE_LIST".tmp", 53256448Svikram strerror(error)); 53266448Svikram (void) unlink(UFS_SIGNATURE_LIST".tmp"); 53276448Svikram return (0); 53286448Svikram } 53296448Svikram 53306448Svikram /* Sort the list again */ 53316448Svikram (void) snprintf(cmd, sizeof (cmd), 53326448Svikram "/usr/bin/sort -u %s.tmp > %s.sorted", 53336448Svikram UFS_SIGNATURE_LIST, UFS_SIGNATURE_LIST); 53346448Svikram 53356448Svikram ret = exec_cmd(cmd, NULL); 53366448Svikram INJECT_ERROR1("ADD_TO_SIGN_LIST_SORT", ret = 1); 53376448Svikram if (ret != 0) { 53386448Svikram bam_error(GRUBSIGN_SORT_FAILED); 53396448Svikram (void) unlink(UFS_SIGNATURE_LIST".sorted"); 53406448Svikram (void) unlink(UFS_SIGNATURE_LIST".tmp"); 53416448Svikram return (0); 53426448Svikram } 53436448Svikram 53446448Svikram (void) unlink(UFS_SIGNATURE_LIST".tmp"); 53456448Svikram 53466448Svikram ret = rename(UFS_SIGNATURE_LIST".sorted", UFS_SIGNATURE_LIST); 53476448Svikram error = errno; 53486448Svikram INJECT_ERROR1("ADD_TO_SIGN_LIST_RENAME2", ret = -1); 53496448Svikram if (ret == -1) { 53506448Svikram bam_error(RENAME_FAIL, UFS_SIGNATURE_LIST, strerror(error)); 53516448Svikram (void) unlink(UFS_SIGNATURE_LIST".sorted"); 53526448Svikram return (0); 53536448Svikram } 53546448Svikram 53556448Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 53566448Svikram 53576448Svikram return (0); 53586448Svikram } 53596448Svikram 53606448Svikram static int 53616448Svikram set_signature(char *osroot, char *osdev, char *sign, char *fstype) 53626448Svikram { 53636448Svikram int ret; 53646448Svikram const char *fcn = "set_signature()"; 53656448Svikram 53666448Svikram BAM_DPRINTF((D_FUNC_ENTRY4, fcn, osroot, osdev, sign, fstype)); 53676448Svikram 53686448Svikram ret = set_backup(osroot, osdev, sign, fstype); 53696448Svikram INJECT_ERROR1("SET_SIGNATURE_BACKUP", ret = -1); 53706448Svikram if (ret == -1) { 53716448Svikram BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 53726448Svikram bam_error(SET_BACKUP_FAILED, sign, osroot, osdev); 53736448Svikram return (-1); 53746448Svikram } 53756448Svikram 53766448Svikram ret = set_primary(osroot, osdev, sign, fstype); 53776448Svikram INJECT_ERROR1("SET_SIGNATURE_PRIMARY", ret = -1); 53786448Svikram 53796448Svikram if (ret == 0) { 53806448Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 53816448Svikram } else { 53826448Svikram BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 53836448Svikram bam_error(SET_PRIMARY_FAILED, sign, osroot, osdev); 53846448Svikram 53856448Svikram } 53866448Svikram return (ret); 53876448Svikram } 53886448Svikram 53896448Svikram char * 53906448Svikram get_grubsign(char *osroot, char *osdev) 53916448Svikram { 53926448Svikram char *grubsign; /* (<sign>,#,#) */ 53936448Svikram char *slice; 53946448Svikram int fdiskpart; 53956448Svikram char *sign; 53966448Svikram char *fstype; 53976448Svikram int ret; 53986448Svikram const char *fcn = "get_grubsign()"; 53996448Svikram 54006448Svikram BAM_DPRINTF((D_FUNC_ENTRY2, fcn, osroot, osdev)); 54016448Svikram 54026448Svikram fstype = get_fstype(osroot); 54036448Svikram INJECT_ERROR1("GET_GRUBSIGN_FSTYPE", fstype = NULL); 54046448Svikram if (fstype == NULL) { 54056448Svikram bam_error(GET_FSTYPE_FAILED, osroot); 54066448Svikram return (NULL); 54076448Svikram } 54086448Svikram 54096448Svikram sign = find_existing_sign(osroot, osdev, fstype); 54106448Svikram INJECT_ERROR1("FIND_EXISTING_SIGN", sign = NULL); 54116448Svikram if (sign == NULL) { 54126448Svikram BAM_DPRINTF((D_GET_GRUBSIGN_NO_EXISTING, fcn, osroot, osdev)); 54136448Svikram sign = create_new_sign(osdev, fstype); 54146448Svikram INJECT_ERROR1("CREATE_NEW_SIGN", sign = NULL); 54156448Svikram if (sign == NULL) { 54166448Svikram bam_error(GRUBSIGN_CREATE_FAIL, osdev); 54176448Svikram free(fstype); 54186448Svikram return (NULL); 54196448Svikram } 54206448Svikram } 54216448Svikram 54226448Svikram ret = set_signature(osroot, osdev, sign, fstype); 54236448Svikram INJECT_ERROR1("SET_SIGNATURE_FAIL", ret = -1); 54246448Svikram if (ret == -1) { 54256448Svikram bam_error(GRUBSIGN_WRITE_FAIL, osdev); 54266448Svikram free(sign); 54276448Svikram free(fstype); 54286448Svikram (void) unlink(UFS_SIGNATURE_LIST); 54296448Svikram return (NULL); 54306448Svikram } 54316448Svikram 54326448Svikram free(fstype); 54336448Svikram 54346448Svikram if (bam_verbose) 54356448Svikram bam_print(GRUBSIGN_FOUND_OR_CREATED, sign, osdev); 54366448Svikram 54376448Svikram fdiskpart = get_partition(osdev); 54386448Svikram INJECT_ERROR1("GET_GRUBSIGN_FDISK", fdiskpart = -1); 54396448Svikram if (fdiskpart == -1) { 54406448Svikram bam_error(FDISKPART_FAIL, osdev); 54416448Svikram free(sign); 54426448Svikram return (NULL); 54436448Svikram } 54446448Svikram 54456448Svikram slice = strrchr(osdev, 's'); 54466448Svikram 54476448Svikram grubsign = s_calloc(1, MAXNAMELEN + 10); 54486448Svikram if (slice) { 54496448Svikram (void) snprintf(grubsign, MAXNAMELEN + 10, "(%s,%d,%c)", 54506448Svikram sign, fdiskpart, slice[1] + 'a' - '0'); 54516448Svikram } else 54526448Svikram (void) snprintf(grubsign, MAXNAMELEN + 10, "(%s,%d)", 54536448Svikram sign, fdiskpart); 54546448Svikram 54556448Svikram free(sign); 54566448Svikram 54576448Svikram BAM_DPRINTF((D_GET_GRUBSIGN_SUCCESS, fcn, grubsign)); 54586448Svikram 54596448Svikram return (grubsign); 54600Sstevel@tonic-gate } 54610Sstevel@tonic-gate 5462656Sszhou static char * 5463656Sszhou get_title(char *rootdir) 54640Sstevel@tonic-gate { 54656448Svikram static char title[80]; 54666448Svikram char *cp = NULL; 54676448Svikram char release[PATH_MAX]; 54686448Svikram FILE *fp; 54696448Svikram const char *fcn = "get_title()"; 54700Sstevel@tonic-gate 54710Sstevel@tonic-gate /* open the /etc/release file */ 54720Sstevel@tonic-gate (void) snprintf(release, sizeof (release), "%s/etc/release", rootdir); 54730Sstevel@tonic-gate 54740Sstevel@tonic-gate fp = fopen(release, "r"); 54756448Svikram if (fp == NULL) { 54766448Svikram bam_error(OPEN_FAIL, release, strerror(errno)); 54776448Svikram cp = NULL; 54786448Svikram goto out; 54796448Svikram } 54800Sstevel@tonic-gate 54810Sstevel@tonic-gate while (s_fgets(title, sizeof (title), fp) != NULL) { 54820Sstevel@tonic-gate cp = strstr(title, "Solaris"); 54830Sstevel@tonic-gate if (cp) 54840Sstevel@tonic-gate break; 54850Sstevel@tonic-gate } 54860Sstevel@tonic-gate (void) fclose(fp); 54876448Svikram 54886448Svikram out: 54896448Svikram cp = cp ? cp : "Solaris"; 54906448Svikram 54916448Svikram BAM_DPRINTF((D_GET_TITLE, fcn, cp)); 54926448Svikram 54936448Svikram return (cp); 54940Sstevel@tonic-gate } 54950Sstevel@tonic-gate 54963446Smrj char * 54970Sstevel@tonic-gate get_special(char *mountp) 54980Sstevel@tonic-gate { 54996448Svikram FILE *mntfp; 55006448Svikram struct mnttab mp = {0}; 55016448Svikram struct mnttab mpref = {0}; 55026448Svikram int error; 55036448Svikram int ret; 55046448Svikram const char *fcn = "get_special()"; 55056448Svikram 55066448Svikram INJECT_ERROR1("GET_SPECIAL_MNTPT", mountp = NULL); 55076448Svikram if (mountp == NULL) { 55086448Svikram bam_error(GET_SPECIAL_NULL_MNTPT); 55096448Svikram return (NULL); 55106448Svikram } 55110Sstevel@tonic-gate 55120Sstevel@tonic-gate mntfp = fopen(MNTTAB, "r"); 55136448Svikram error = errno; 55146448Svikram INJECT_ERROR1("GET_SPECIAL_MNTTAB_OPEN", mntfp = NULL); 55150Sstevel@tonic-gate if (mntfp == NULL) { 55166448Svikram bam_error(OPEN_FAIL, MNTTAB, strerror(error)); 55176448Svikram return (NULL); 55180Sstevel@tonic-gate } 55190Sstevel@tonic-gate 55200Sstevel@tonic-gate if (*mountp == '\0') 55210Sstevel@tonic-gate mpref.mnt_mountp = "/"; 55220Sstevel@tonic-gate else 55230Sstevel@tonic-gate mpref.mnt_mountp = mountp; 55246448Svikram 55256448Svikram ret = getmntany(mntfp, &mp, &mpref); 55266448Svikram INJECT_ERROR1("GET_SPECIAL_MNTTAB_SEARCH", ret = 1); 55276448Svikram if (ret != 0) { 55280Sstevel@tonic-gate (void) fclose(mntfp); 55296448Svikram BAM_DPRINTF((D_GET_SPECIAL_NOT_IN_MNTTAB, fcn, mountp)); 55300Sstevel@tonic-gate return (NULL); 55310Sstevel@tonic-gate } 55320Sstevel@tonic-gate (void) fclose(mntfp); 55330Sstevel@tonic-gate 55346448Svikram BAM_DPRINTF((D_GET_SPECIAL, fcn, mp.mnt_special)); 55356448Svikram 55360Sstevel@tonic-gate return (s_strdup(mp.mnt_special)); 55370Sstevel@tonic-gate } 55380Sstevel@tonic-gate 55396448Svikram static void 55406448Svikram free_physarray(char **physarray, int n) 55416448Svikram { 55426448Svikram int i; 55436448Svikram const char *fcn = "free_physarray()"; 55446448Svikram 55456448Svikram assert(physarray); 55466448Svikram assert(n); 55476448Svikram 55486448Svikram BAM_DPRINTF((D_FUNC_ENTRY_N1, fcn, n)); 55496448Svikram 55506448Svikram for (i = 0; i < n; i++) { 55516448Svikram free(physarray[i]); 55526448Svikram } 55536448Svikram free(physarray); 55546448Svikram 55556448Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 55566448Svikram } 55576448Svikram 55586448Svikram static int 55596448Svikram zfs_get_physical(char *special, char ***physarray, int *n) 55606448Svikram { 55616448Svikram char sdup[PATH_MAX]; 55626448Svikram char cmd[PATH_MAX]; 55636448Svikram char dsk[PATH_MAX]; 55646448Svikram char *pool; 55656448Svikram filelist_t flist = {0}; 55666448Svikram line_t *lp; 55676448Svikram line_t *startlp; 55686448Svikram char *comp1; 55696448Svikram int i; 55706448Svikram int ret; 55716448Svikram const char *fcn = "zfs_get_physical()"; 55726448Svikram 55736448Svikram assert(special); 55746448Svikram 55756448Svikram BAM_DPRINTF((D_FUNC_ENTRY1, fcn, special)); 55766448Svikram 55776448Svikram INJECT_ERROR1("INVALID_ZFS_SPECIAL", special = "/foo"); 55786448Svikram if (special[0] == '/') { 55796448Svikram bam_error(INVALID_ZFS_SPECIAL, special); 55806448Svikram return (-1); 55816448Svikram } 55826448Svikram 55836448Svikram (void) strlcpy(sdup, special, sizeof (sdup)); 55846448Svikram 55856448Svikram pool = strtok(sdup, "/"); 55866448Svikram INJECT_ERROR1("ZFS_GET_PHYS_POOL", pool = NULL); 55876448Svikram if (pool == NULL) { 55886448Svikram bam_error(CANT_FIND_POOL_FROM_SPECIAL, special); 55896448Svikram return (-1); 55906448Svikram } 55916448Svikram 55926448Svikram (void) snprintf(cmd, sizeof (cmd), "/sbin/zpool status %s", pool); 55936448Svikram 55946448Svikram ret = exec_cmd(cmd, &flist); 55956448Svikram INJECT_ERROR1("ZFS_GET_PHYS_STATUS", ret = 1); 55966448Svikram if (ret != 0) { 55976448Svikram bam_error(ZFS_GET_POOL_STATUS, pool); 55986448Svikram return (-1); 55996448Svikram } 56006448Svikram 56016448Svikram INJECT_ERROR1("ZFS_GET_PHYS_STATUS_OUT", flist.head = NULL); 56026448Svikram if (flist.head == NULL) { 56036448Svikram bam_error(BAD_ZPOOL_STATUS, pool); 56046448Svikram filelist_free(&flist); 56056448Svikram return (-1); 56066448Svikram } 56076448Svikram 56086448Svikram for (lp = flist.head; lp; lp = lp->next) { 56096448Svikram BAM_DPRINTF((D_STRTOK_ZPOOL_STATUS, fcn, lp->line)); 56106448Svikram comp1 = strtok(lp->line, " \t"); 56116448Svikram if (comp1 == NULL) { 56126448Svikram free(lp->line); 56136448Svikram lp->line = NULL; 56146448Svikram } else { 56156448Svikram comp1 = s_strdup(comp1); 56166448Svikram free(lp->line); 56176448Svikram lp->line = comp1; 56186448Svikram } 56196448Svikram } 56206448Svikram 56216448Svikram for (lp = flist.head; lp; lp = lp->next) { 56226448Svikram if (lp->line == NULL) 56236448Svikram continue; 56246448Svikram if (strcmp(lp->line, pool) == 0) { 56256448Svikram BAM_DPRINTF((D_FOUND_POOL_IN_ZPOOL_STATUS, fcn, pool)); 56266448Svikram break; 56276448Svikram } 56286448Svikram } 56296448Svikram 56306448Svikram if (lp == NULL) { 56316448Svikram bam_error(NO_POOL_IN_ZPOOL_STATUS, pool); 56326448Svikram filelist_free(&flist); 56336448Svikram return (-1); 56346448Svikram } 56356448Svikram 56366448Svikram startlp = lp->next; 56376448Svikram for (i = 0, lp = startlp; lp; lp = lp->next) { 56386448Svikram if (lp->line == NULL) 56396448Svikram continue; 56406448Svikram if (strcmp(lp->line, "mirror") == 0) 56416448Svikram continue; 56426448Svikram if (lp->line[0] == '\0' || strcmp(lp->line, "errors:") == 0) 56436448Svikram break; 56446448Svikram i++; 56456448Svikram BAM_DPRINTF((D_COUNTING_ZFS_PHYS, fcn, i)); 56466448Svikram } 56476448Svikram 56486448Svikram if (i == 0) { 56496448Svikram bam_error(NO_PHYS_IN_ZPOOL_STATUS, pool); 56506448Svikram filelist_free(&flist); 56516448Svikram return (-1); 56526448Svikram } 56536448Svikram 56546448Svikram *n = i; 56556448Svikram *physarray = s_calloc(*n, sizeof (char *)); 56566448Svikram for (i = 0, lp = startlp; lp; lp = lp->next) { 56576448Svikram if (lp->line == NULL) 56586448Svikram continue; 56596448Svikram if (strcmp(lp->line, "mirror") == 0) 56606448Svikram continue; 56616448Svikram if (strcmp(lp->line, "errors:") == 0) 56626448Svikram break; 56636448Svikram if (strncmp(lp->line, "/dev/dsk/", strlen("/dev/dsk/")) != 0 && 56646448Svikram strncmp(lp->line, "/dev/rdsk/", 56656448Svikram strlen("/dev/rdsk/")) != 0) { 56666448Svikram (void) snprintf(dsk, sizeof (dsk), "/dev/dsk/%s", 56676448Svikram lp->line); 56686448Svikram } else { 56696448Svikram (void) strlcpy(dsk, lp->line, sizeof (dsk)); 56706448Svikram } 56716448Svikram BAM_DPRINTF((D_ADDING_ZFS_PHYS, fcn, dsk, pool)); 56726448Svikram (*physarray)[i++] = s_strdup(dsk); 56736448Svikram } 56746448Svikram 56756448Svikram assert(i == *n); 56766448Svikram 56776448Svikram filelist_free(&flist); 56786448Svikram 56796448Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 56806448Svikram return (0); 56816448Svikram } 56826448Svikram 56836694Svikram /* 56846694Svikram * Certain services needed to run metastat successfully may not 56856694Svikram * be enabled. Enable them now. 56866694Svikram */ 56876694Svikram /* 56886694Svikram * Checks if the specified service is online 56896694Svikram * Returns: 1 if the service is online 56906694Svikram * 0 if the service is not online 56916694Svikram * -1 on error 56926694Svikram */ 56936694Svikram static int 56946694Svikram is_svc_online(char *svc) 56956694Svikram { 56966694Svikram char *state; 56976694Svikram const char *fcn = "is_svc_online()"; 56986694Svikram 56996694Svikram BAM_DPRINTF((D_FUNC_ENTRY1, fcn, svc)); 57006694Svikram 57016694Svikram state = smf_get_state(svc); 57026694Svikram INJECT_ERROR2("GET_SVC_STATE", free(state), state = NULL); 57036694Svikram if (state == NULL) { 57046694Svikram bam_error(GET_SVC_STATE_ERR, svc); 57056694Svikram return (-1); 57066694Svikram } 57076694Svikram BAM_DPRINTF((D_GOT_SVC_STATUS, fcn, svc)); 57086694Svikram 57096694Svikram if (strcmp(state, SCF_STATE_STRING_ONLINE) == 0) { 57106694Svikram BAM_DPRINTF((D_SVC_ONLINE, fcn, svc)); 57116694Svikram free(state); 57126694Svikram return (1); 57136694Svikram } 57146694Svikram 57156694Svikram BAM_DPRINTF((D_SVC_NOT_ONLINE, fcn, state, svc)); 57166694Svikram 57176694Svikram free(state); 57186694Svikram 57196694Svikram return (0); 57206694Svikram } 57216694Svikram 57226694Svikram static int 57236694Svikram enable_svc(char *svc) 57246694Svikram { 57256694Svikram int ret; 57266694Svikram int sleeptime; 57276694Svikram const char *fcn = "enable_svc()"; 57286694Svikram 57296694Svikram ret = is_svc_online(svc); 57306694Svikram if (ret == -1) { 57316694Svikram bam_error(SVC_IS_ONLINE_FAILED, svc); 57326694Svikram return (-1); 57336694Svikram } else if (ret == 1) { 57346694Svikram BAM_DPRINTF((D_SVC_ALREADY_ONLINE, fcn, svc)); 57356694Svikram return (0); 57366694Svikram } 57376694Svikram 57386694Svikram /* Service is not enabled. Enable it now. */ 57396694Svikram ret = smf_enable_instance(svc, 0); 57406694Svikram INJECT_ERROR1("ENABLE_SVC_FAILED", ret = -1); 57416694Svikram if (ret != 0) { 57426694Svikram bam_error(ENABLE_SVC_FAILED, svc); 57436694Svikram return (-1); 57446694Svikram } 57456694Svikram 57466694Svikram BAM_DPRINTF((D_SVC_ONLINE_INITIATED, fcn, svc)); 57476694Svikram 57486694Svikram sleeptime = 0; 57496694Svikram do { 57506694Svikram ret = is_svc_online(svc); 57516694Svikram INJECT_ERROR1("SVC_ONLINE_SUCCESS", ret = 1); 57526694Svikram INJECT_ERROR1("SVC_ONLINE_FAILURE", ret = -1); 57536694Svikram INJECT_ERROR1("SVC_ONLINE_NOTYET", ret = 0); 57546694Svikram if (ret == -1) { 57556694Svikram bam_error(ERR_SVC_GET_ONLINE, svc); 57566694Svikram return (-1); 57576694Svikram } else if (ret == 1) { 57586694Svikram BAM_DPRINTF((D_SVC_NOW_ONLINE, fcn, svc)); 57596694Svikram return (1); 57606694Svikram } 57616694Svikram (void) sleep(1); 57626694Svikram } while (sleeptime < 60); 57636694Svikram 57646694Svikram bam_error(TIMEOUT_ENABLE_SVC, svc); 57656694Svikram 57666694Svikram return (-1); 57676694Svikram } 57686694Svikram 57696448Svikram static int 57706448Svikram ufs_get_physical(char *special, char ***physarray, int *n) 57716448Svikram { 57726448Svikram char cmd[PATH_MAX]; 57736448Svikram char *shortname; 57746448Svikram filelist_t flist = {0}; 57756448Svikram char *meta; 57766448Svikram char *type; 57776448Svikram char *comp1; 57786448Svikram char *comp2; 57796448Svikram char *comp3; 57806448Svikram char *comp4; 57816448Svikram int i; 57826448Svikram line_t *lp; 57836448Svikram int ret; 57846694Svikram char *svc; 57856448Svikram const char *fcn = "ufs_get_physical()"; 57866448Svikram 57876448Svikram assert(special); 57886448Svikram 57896448Svikram BAM_DPRINTF((D_FUNC_ENTRY1, fcn, special)); 57906448Svikram 57916448Svikram if (strncmp(special, "/dev/md/", strlen("/dev/md/")) != 0) { 57926448Svikram bam_error(UFS_GET_PHYS_NOT_SVM, special); 57936448Svikram return (-1); 57946448Svikram } 57956448Svikram 57966448Svikram if (strncmp(special, "/dev/md/dsk/", strlen("/dev/md/dsk/")) == 0) { 57976448Svikram shortname = special + strlen("/dev/md/dsk/"); 57986448Svikram } else if (strncmp(special, "/dev/md/rdsk/", 57996448Svikram strlen("/dev/md/rdsk/")) == 0) { 58006448Svikram shortname = special + strlen("/dev/md/rdsk"); 58016448Svikram } else { 58026448Svikram bam_error(UFS_GET_PHYS_INVALID_SVM, special); 58036448Svikram return (-1); 58046448Svikram } 58056448Svikram 58066448Svikram BAM_DPRINTF((D_UFS_SVM_SHORT, fcn, special, shortname)); 58076448Svikram 58086694Svikram svc = "network/rpc/meta:default"; 58096694Svikram if (enable_svc(svc) == -1) { 58106694Svikram bam_error(UFS_SVM_METASTAT_SVC_ERR, svc); 58116694Svikram } 58126694Svikram 58136448Svikram (void) snprintf(cmd, sizeof (cmd), "/sbin/metastat -p %s", shortname); 58146448Svikram 58156448Svikram ret = exec_cmd(cmd, &flist); 58166448Svikram INJECT_ERROR1("UFS_SVM_METASTAT", ret = 1); 58176448Svikram if (ret != 0) { 58186448Svikram bam_error(UFS_SVM_METASTAT_ERR, shortname); 58196448Svikram return (-1); 58206448Svikram } 58216448Svikram 58226448Svikram INJECT_ERROR1("UFS_SVM_METASTAT_OUT", flist.head = NULL); 58236448Svikram if (flist.head == NULL) { 58246448Svikram bam_error(BAD_UFS_SVM_METASTAT, shortname); 58256448Svikram filelist_free(&flist); 58266448Svikram return (-1); 58276448Svikram } 58286448Svikram 58296448Svikram /* 58306448Svikram * Check if not a mirror. We only parse a single metadevice 58316448Svikram * if not a mirror 58326448Svikram */ 58336448Svikram meta = strtok(flist.head->line, " \t"); 58346448Svikram type = strtok(NULL, " \t"); 58356448Svikram if (meta == NULL || type == NULL) { 58366448Svikram bam_error(ERROR_PARSE_UFS_SVM_METASTAT, shortname); 58376448Svikram filelist_free(&flist); 58386448Svikram return (-1); 58396448Svikram } 58406448Svikram if (strcmp(type, "-m") != 0) { 58416448Svikram comp1 = strtok(NULL, " \t"); 58426448Svikram comp2 = strtok(NULL, " \t"); 58436448Svikram if (comp1 == NULL || comp2 != NULL) { 58446448Svikram bam_error(INVALID_UFS_SVM_METASTAT, shortname); 58456448Svikram filelist_free(&flist); 58466448Svikram return (-1); 58476448Svikram } 58486448Svikram BAM_DPRINTF((D_UFS_SVM_ONE_COMP, fcn, comp1, shortname)); 58496448Svikram *physarray = s_calloc(1, sizeof (char *)); 58506448Svikram (*physarray)[0] = s_strdup(comp1); 58516448Svikram *n = 1; 58526448Svikram filelist_free(&flist); 58536448Svikram return (0); 58546448Svikram } 58556448Svikram 58566448Svikram /* 58576448Svikram * Okay we have a mirror. Everything after the first line 58586448Svikram * is a submirror 58596448Svikram */ 58606448Svikram for (i = 0, lp = flist.head->next; lp; lp = lp->next) { 58616448Svikram if (strstr(lp->line, "/dev/dsk/") == NULL && 58626448Svikram strstr(lp->line, "/dev/rdsk/") == NULL) { 58636448Svikram bam_error(CANNOT_PARSE_UFS_SVM_METASTAT, shortname); 58646448Svikram filelist_free(&flist); 58656448Svikram return (-1); 58666448Svikram } 58676448Svikram i++; 58686448Svikram } 58696448Svikram 58706448Svikram *physarray = s_calloc(i, sizeof (char *)); 58716448Svikram *n = i; 58726448Svikram 58736448Svikram for (i = 0, lp = flist.head->next; lp; lp = lp->next) { 58746448Svikram comp1 = strtok(lp->line, " \t"); 58756448Svikram comp2 = strtok(NULL, " \t"); 58766448Svikram comp3 = strtok(NULL, " \t"); 58776448Svikram comp4 = strtok(NULL, " \t"); 58786448Svikram 58796448Svikram if (comp3 == NULL || comp4 == NULL || 58806448Svikram (strncmp(comp4, "/dev/dsk/", strlen("/dev/dsk/")) != 0 && 58816448Svikram strncmp(comp4, "/dev/rdsk/", strlen("/dev/rdsk/")) != 0)) { 58826448Svikram bam_error(CANNOT_PARSE_UFS_SVM_SUBMIRROR, shortname); 58836448Svikram filelist_free(&flist); 58846448Svikram free_physarray(*physarray, *n); 58856448Svikram return (-1); 58866448Svikram } 58876448Svikram 58886448Svikram (*physarray)[i++] = s_strdup(comp4); 58896448Svikram } 58906448Svikram 58916448Svikram assert(i == *n); 58926448Svikram 58936448Svikram filelist_free(&flist); 58946448Svikram 58956448Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 58966448Svikram return (0); 58976448Svikram } 58986448Svikram 58996448Svikram static int 59006448Svikram get_physical(char *menu_root, char ***physarray, int *n) 59016448Svikram { 59026448Svikram char *special; 59036448Svikram int ret; 59046448Svikram const char *fcn = "get_physical()"; 59056448Svikram 59066448Svikram assert(menu_root); 59076448Svikram assert(physarray); 59086448Svikram assert(n); 59096448Svikram 59106448Svikram *physarray = NULL; 59116448Svikram *n = 0; 59126448Svikram 59136448Svikram BAM_DPRINTF((D_FUNC_ENTRY1, fcn, menu_root)); 59146448Svikram 59156448Svikram /* First get the device special file from /etc/mnttab */ 59166448Svikram special = get_special(menu_root); 59176448Svikram INJECT_ERROR1("GET_PHYSICAL_SPECIAL", special = NULL); 59186448Svikram if (special == NULL) { 59196448Svikram bam_error(GET_SPECIAL_NULL, menu_root); 59206448Svikram return (-1); 59216448Svikram } 59226448Svikram 59236448Svikram /* If already a physical device nothing to do */ 59246448Svikram if (strncmp(special, "/dev/dsk/", strlen("/dev/dsk/")) == 0 || 59256448Svikram strncmp(special, "/dev/rdsk/", strlen("/dev/rdsk/")) == 0) { 59266448Svikram BAM_DPRINTF((D_GET_PHYSICAL_ALREADY, fcn, menu_root, special)); 59276448Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 59286448Svikram *physarray = s_calloc(1, sizeof (char *)); 59296448Svikram (*physarray)[0] = special; 59306448Svikram *n = 1; 59316448Svikram return (0); 59326448Svikram } 59336448Svikram 59346448Svikram if (is_zfs(menu_root)) { 59356448Svikram ret = zfs_get_physical(special, physarray, n); 59366448Svikram } else if (is_ufs(menu_root)) { 59376448Svikram ret = ufs_get_physical(special, physarray, n); 59386448Svikram } else { 59396448Svikram bam_error(GET_PHYSICAL_NOTSUP_FSTYPE, menu_root, special); 59406448Svikram ret = -1; 59416448Svikram } 59426448Svikram 59436448Svikram free(special); 59446448Svikram 59456448Svikram INJECT_ERROR1("GET_PHYSICAL_RET", ret = -1); 59466448Svikram if (ret == -1) { 59476448Svikram BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 59486448Svikram } else { 59496448Svikram int i; 59506448Svikram assert (*n > 0); 59516448Svikram for (i = 0; i < *n; i++) { 59526448Svikram BAM_DPRINTF((D_GET_PHYSICAL_RET, fcn, (*physarray)[i])); 59536448Svikram } 59546448Svikram } 59556448Svikram 59566448Svikram return (ret); 59576448Svikram } 59586448Svikram 59596448Svikram static int 59606448Svikram is_bootdisk(char *osroot, char *physical) 59616448Svikram { 59626448Svikram int ret; 59636448Svikram char *grubroot; 59646448Svikram char *bootp; 59656448Svikram const char *fcn = "is_bootdisk()"; 59666448Svikram 59676448Svikram assert(osroot); 59686448Svikram assert(physical); 59696448Svikram 59706448Svikram BAM_DPRINTF((D_FUNC_ENTRY2, fcn, osroot, physical)); 59716448Svikram 59726448Svikram bootp = strstr(physical, "p0:boot"); 59736448Svikram if (bootp) 59746448Svikram *bootp = '\0'; 59756448Svikram /* 59766448Svikram * We just want the BIOS mapping for menu disk. 59776448Svikram * Don't pass menu_root to get_grubroot() as the 59786448Svikram * check that it is used for is not relevant here. 59796448Svikram * The osroot is immaterial as well - it is only used to 59806448Svikram * to find create_diskmap script. Everything hinges on 59816448Svikram * "physical" 59826448Svikram */ 59836448Svikram grubroot = get_grubroot(osroot, physical, NULL); 59846448Svikram 59856448Svikram INJECT_ERROR1("IS_BOOTDISK_GRUBROOT", grubroot = NULL); 59866448Svikram if (grubroot == NULL) { 59876448Svikram bam_error(NO_GRUBROOT_FOR_DISK, fcn, physical); 59886448Svikram return (0); 59896448Svikram } 59906448Svikram ret = grubroot[3] == '0'; 59916448Svikram free(grubroot); 59926448Svikram 59936448Svikram BAM_DPRINTF((D_RETURN_RET, fcn, ret)); 59946448Svikram 59956448Svikram return (ret); 59960Sstevel@tonic-gate } 59970Sstevel@tonic-gate 59980Sstevel@tonic-gate /* 59996448Svikram * Check if menu is on the boot device 60000Sstevel@tonic-gate * Return 0 (false) on error 60010Sstevel@tonic-gate */ 60020Sstevel@tonic-gate static int 60036448Svikram menu_on_bootdisk(char *osroot, char *menu_root) 60046448Svikram { 60056448Svikram char **physarray; 60066448Svikram int ret; 60076448Svikram int n; 60086448Svikram int i; 60096448Svikram int on_bootdisk; 60106448Svikram const char *fcn = "menu_on_bootdisk()"; 60116448Svikram 60126448Svikram BAM_DPRINTF((D_FUNC_ENTRY2, fcn, osroot, menu_root)); 60136448Svikram 60146448Svikram ret = get_physical(menu_root, &physarray, &n); 60156448Svikram INJECT_ERROR1("MENU_ON_BOOTDISK_PHYSICAL", ret = -1); 60166448Svikram if (ret != 0) { 60176448Svikram bam_error(GET_PHYSICAL_MENU_NULL, menu_root); 60180Sstevel@tonic-gate return (0); 60196448Svikram } 60206448Svikram 60216448Svikram assert(physarray); 60226448Svikram assert(n > 0); 60236448Svikram 60246448Svikram on_bootdisk = 0; 60256448Svikram for (i = 0; i < n; i++) { 60266448Svikram assert(strncmp(physarray[i], "/dev/dsk/", 60276448Svikram strlen("/dev/dsk/")) == 0 || 60286448Svikram strncmp(physarray[i], "/dev/rdsk/", 60296448Svikram strlen("/dev/rdsk/")) == 0); 60306448Svikram 60316448Svikram BAM_DPRINTF((D_CHECK_ON_BOOTDISK, fcn, physarray[i])); 60326448Svikram if (is_bootdisk(osroot, physarray[i])) { 60336448Svikram on_bootdisk = 1; 60346448Svikram BAM_DPRINTF((D_IS_ON_BOOTDISK, fcn, physarray[i])); 60356448Svikram } 60366448Svikram } 60376448Svikram 60386448Svikram free_physarray(physarray, n); 60396448Svikram 60406448Svikram INJECT_ERROR1("ON_BOOTDISK_YES", on_bootdisk = 1); 60416448Svikram INJECT_ERROR1("ON_BOOTDISK_NO", on_bootdisk = 0); 60426448Svikram if (on_bootdisk) { 60436448Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 60446448Svikram } else { 60456448Svikram BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 60466448Svikram } 60476448Svikram 60486448Svikram return (on_bootdisk); 60496448Svikram } 60506448Svikram 60516448Svikram void 60526448Svikram bam_add_line(menu_t *mp, entry_t *entry, line_t *prev, line_t *lp) 60536448Svikram { 60546448Svikram const char *fcn = "bam_add_line()"; 60556448Svikram 60566448Svikram assert(mp); 60576448Svikram assert(entry); 60586448Svikram assert(prev); 60596448Svikram assert(lp); 60606448Svikram 60616448Svikram lp->next = prev->next; 60626448Svikram if (prev->next) { 60636448Svikram BAM_DPRINTF((D_ADD_LINE_PREV_NEXT, fcn)); 60646448Svikram prev->next->prev = lp; 60656448Svikram } else { 60666448Svikram BAM_DPRINTF((D_ADD_LINE_NOT_PREV_NEXT, fcn)); 60676448Svikram } 60686448Svikram prev->next = lp; 60696448Svikram lp->prev = prev; 60706448Svikram 60716448Svikram if (entry->end == prev) { 60726448Svikram BAM_DPRINTF((D_ADD_LINE_LAST_LINE_IN_ENTRY, fcn)); 60736448Svikram entry->end = lp; 60746448Svikram } 60756448Svikram if (mp->end == prev) { 60766448Svikram assert(lp->next == NULL); 60776448Svikram mp->end = lp; 60786448Svikram BAM_DPRINTF((D_ADD_LINE_LAST_LINE_IN_MENU, fcn)); 60796448Svikram } 60800Sstevel@tonic-gate } 60810Sstevel@tonic-gate 6082662Sszhou /* 6083662Sszhou * look for matching bootadm entry with specified parameters 6084662Sszhou * Here are the rules (based on existing usage): 6085662Sszhou * - If title is specified, match on title only 60866448Svikram * - Else, match on root/findroot, kernel, and module. 60876448Svikram * Note that, if root_opt is non-zero, the absence of 60886448Svikram * root line is considered a match. 6089662Sszhou */ 6090662Sszhou static entry_t * 60916448Svikram find_boot_entry( 60926448Svikram menu_t *mp, 60936448Svikram char *title, 60946448Svikram char *kernel, 60956448Svikram char *findroot, 60966448Svikram char *root, 60976448Svikram char *module, 60986448Svikram int root_opt, 60996448Svikram int *entry_num) 61006448Svikram { 61016448Svikram int i; 61026448Svikram line_t *lp; 61036448Svikram entry_t *ent; 61046448Svikram const char *fcn = "find_boot_entry()"; 61056448Svikram 61066448Svikram if (entry_num) 61076448Svikram *entry_num = BAM_ERROR; 6108662Sszhou 6109662Sszhou /* find matching entry */ 6110662Sszhou for (i = 0, ent = mp->entries; ent; i++, ent = ent->next) { 6111662Sszhou lp = ent->start; 6112662Sszhou 6113662Sszhou /* first line of entry must be bootadm comment */ 6114662Sszhou lp = ent->start; 61153446Smrj if (lp->flags != BAM_COMMENT || 61163446Smrj strcmp(lp->arg, BAM_BOOTADM_HDR) != 0) { 6117662Sszhou continue; 6118662Sszhou } 6119662Sszhou 6120662Sszhou /* advance to title line */ 6121662Sszhou lp = lp->next; 6122662Sszhou if (title) { 6123662Sszhou if (lp->flags == BAM_TITLE && lp->arg && 61246448Svikram strcmp(lp->arg, title) == 0) { 61256448Svikram BAM_DPRINTF((D_MATCHED_TITLE, fcn, title)); 6126662Sszhou break; 61276448Svikram } 61286448Svikram BAM_DPRINTF((D_NOMATCH_TITLE, fcn, title, lp->arg)); 6129662Sszhou continue; /* check title only */ 6130662Sszhou } 6131662Sszhou 6132662Sszhou lp = lp->next; /* advance to root line */ 61335084Sjohnlev if (lp == NULL) { 61345084Sjohnlev continue; 61356448Svikram } else if (strcmp(lp->cmd, menu_cmds[FINDROOT_CMD]) == 0) { 61366448Svikram INJECT_ERROR1("FIND_BOOT_ENTRY_NULL_FINDROOT", 61376448Svikram findroot = NULL); 61386448Svikram if (findroot == NULL) { 61396448Svikram BAM_DPRINTF((D_NOMATCH_FINDROOT_NULL, 61406448Svikram fcn, lp->arg)); 61416448Svikram continue; 61426448Svikram } 61436448Svikram /* findroot command found, try match */ 61446448Svikram if (strcmp(lp->arg, findroot) != 0) { 61456448Svikram BAM_DPRINTF((D_NOMATCH_FINDROOT, 61466448Svikram fcn, findroot, lp->arg)); 6147662Sszhou continue; 6148662Sszhou } 61496448Svikram BAM_DPRINTF((D_MATCHED_FINDROOT, fcn, findroot)); 61506448Svikram lp = lp->next; /* advance to kernel line */ 61516448Svikram } else if (strcmp(lp->cmd, menu_cmds[ROOT_CMD]) == 0) { 61526448Svikram INJECT_ERROR1("FIND_BOOT_ENTRY_NULL_ROOT", root = NULL); 61536448Svikram if (root == NULL) { 61546448Svikram BAM_DPRINTF((D_NOMATCH_ROOT_NULL, 61556448Svikram fcn, lp->arg)); 61566448Svikram continue; 61576448Svikram } 61586448Svikram /* root cmd found, try match */ 61596448Svikram if (strcmp(lp->arg, root) != 0) { 61606448Svikram BAM_DPRINTF((D_NOMATCH_ROOT, 61616448Svikram fcn, root, lp->arg)); 61626448Svikram continue; 61636448Svikram } 61646448Svikram BAM_DPRINTF((D_MATCHED_ROOT, fcn, root)); 6165662Sszhou lp = lp->next; /* advance to kernel line */ 6166662Sszhou } else { 61676448Svikram INJECT_ERROR1("FIND_BOOT_ENTRY_ROOT_OPT_NO", 61686448Svikram root_opt = 0); 61696448Svikram INJECT_ERROR1("FIND_BOOT_ENTRY_ROOT_OPT_YES", 61706448Svikram root_opt = 1); 6171662Sszhou /* no root command, see if root is optional */ 6172662Sszhou if (root_opt == 0) { 61736448Svikram BAM_DPRINTF((D_NO_ROOT_OPT, fcn)); 6174662Sszhou continue; 6175662Sszhou } 61766448Svikram BAM_DPRINTF((D_ROOT_OPT, fcn)); 6177662Sszhou } 6178662Sszhou 6179662Sszhou if (lp == NULL || lp->next == NULL) { 6180662Sszhou continue; 6181662Sszhou } 6182662Sszhou 61835084Sjohnlev if (kernel && 61845084Sjohnlev (!check_cmd(lp->cmd, KERNEL_CMD, lp->arg, kernel))) { 61855084Sjohnlev continue; 61865084Sjohnlev } 61876448Svikram BAM_DPRINTF((D_KERNEL_MATCH, fcn, kernel, lp->arg)); 61885084Sjohnlev 61893467Srscott /* 61905084Sjohnlev * Check for matching module entry (failsafe or normal). 61915084Sjohnlev * If it fails to match, we go around the loop again. 61925084Sjohnlev * For xpv entries, there are two module lines, so we 61935084Sjohnlev * do the check twice. 61943467Srscott */ 6195662Sszhou lp = lp->next; /* advance to module line */ 61965084Sjohnlev if (check_cmd(lp->cmd, MODULE_CMD, lp->arg, module) || 61975084Sjohnlev (((lp = lp->next) != NULL) && 61985084Sjohnlev check_cmd(lp->cmd, MODULE_CMD, lp->arg, module))) { 61995084Sjohnlev /* match found */ 62006448Svikram BAM_DPRINTF((D_MODULE_MATCH, fcn, module, lp->arg)); 62015084Sjohnlev break; 6202662Sszhou } 62035084Sjohnlev } 62045084Sjohnlev 62056448Svikram if (ent && entry_num) { 62065084Sjohnlev *entry_num = i; 62075084Sjohnlev } 62086448Svikram 62096448Svikram if (ent) { 62106448Svikram BAM_DPRINTF((D_RETURN_RET, fcn, i)); 62116448Svikram } else { 62126448Svikram BAM_DPRINTF((D_RETURN_RET, fcn, BAM_ERROR)); 62136448Svikram } 6214662Sszhou return (ent); 6215662Sszhou } 6216662Sszhou 6217662Sszhou static int 62186448Svikram update_boot_entry(menu_t *mp, char *title, char *findroot, char *root, 62196448Svikram char *kernel, char *mod_kernel, char *module, int root_opt) 62206448Svikram { 62216448Svikram int i; 62226448Svikram int change_kernel = 0; 62236448Svikram entry_t *ent; 62246448Svikram line_t *lp; 62256448Svikram line_t *tlp; 62266448Svikram char linebuf[BAM_MAXLINE]; 62276448Svikram const char *fcn = "update_boot_entry()"; 6228662Sszhou 6229662Sszhou /* note: don't match on title, it's updated on upgrade */ 62306448Svikram ent = find_boot_entry(mp, NULL, kernel, findroot, root, module, 62316448Svikram root_opt, &i); 62323446Smrj if ((ent == NULL) && (bam_direct == BAM_DIRECT_DBOOT)) { 62333446Smrj /* 62343446Smrj * We may be upgrading a kernel from multiboot to 62356448Svikram * directboot. Look for a multiboot entry. A multiboot 62366448Svikram * entry will not have a findroot line. 62373446Smrj */ 62386448Svikram ent = find_boot_entry(mp, NULL, "multiboot", NULL, root, 62396448Svikram MULTIBOOT_ARCHIVE, root_opt, &i); 62403446Smrj if (ent != NULL) { 62416448Svikram BAM_DPRINTF((D_UPGRADE_FROM_MULTIBOOT, fcn, root)); 62423446Smrj change_kernel = 1; 62433446Smrj } 62446448Svikram } else if (ent) { 62456448Svikram BAM_DPRINTF((D_FOUND_FINDROOT, fcn, findroot)); 62466448Svikram } 62476448Svikram 62486448Svikram if (ent == NULL) { 62496448Svikram BAM_DPRINTF((D_ENTRY_NOT_FOUND_CREATING, fcn, findroot)); 62506448Svikram return (add_boot_entry(mp, title, findroot, 62515084Sjohnlev kernel, mod_kernel, module)); 62526448Svikram } 62536448Svikram 62546448Svikram /* replace title of existing entry and update findroot line */ 6255662Sszhou lp = ent->start; 6256662Sszhou lp = lp->next; /* title line */ 6257662Sszhou (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s", 6258662Sszhou menu_cmds[TITLE_CMD], menu_cmds[SEP_CMD], title); 6259662Sszhou free(lp->arg); 6260662Sszhou free(lp->line); 6261662Sszhou lp->arg = s_strdup(title); 6262662Sszhou lp->line = s_strdup(linebuf); 62636448Svikram BAM_DPRINTF((D_CHANGING_TITLE, fcn, title)); 62646448Svikram 62656448Svikram tlp = lp; /* title line */ 6266662Sszhou lp = lp->next; /* root line */ 62676448Svikram 62686448Svikram /* if no root or findroot command, create a new line_t */ 62696448Svikram if (strcmp(lp->cmd, menu_cmds[ROOT_CMD]) != 0 && 62706448Svikram strcmp(lp->cmd, menu_cmds[FINDROOT_CMD]) != 0) { 62716448Svikram lp = s_calloc(1, sizeof (line_t)); 62726448Svikram bam_add_line(mp, ent, tlp, lp); 62736448Svikram } else { 62746448Svikram free(lp->cmd); 62756448Svikram free(lp->sep); 62766448Svikram free(lp->arg); 62776448Svikram free(lp->line); 62786448Svikram } 62796448Svikram 62806448Svikram lp->cmd = s_strdup(menu_cmds[FINDROOT_CMD]); 62816448Svikram lp->sep = s_strdup(menu_cmds[SEP_CMD]); 62826448Svikram lp->arg = s_strdup(findroot); 62836448Svikram (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s", 62846448Svikram menu_cmds[FINDROOT_CMD], menu_cmds[SEP_CMD], findroot); 62856448Svikram lp->line = s_strdup(linebuf); 62866448Svikram BAM_DPRINTF((D_ADDING_FINDROOT_LINE, fcn, findroot)); 62876448Svikram 62886448Svikram /* kernel line */ 62896448Svikram lp = lp->next; 62903446Smrj 62913446Smrj if (change_kernel) { 62923446Smrj /* 62933446Smrj * We're upgrading from multiboot to directboot. 62943446Smrj */ 62953446Smrj if (strcmp(lp->cmd, menu_cmds[KERNEL_CMD]) == 0) { 62963446Smrj (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s", 62973446Smrj menu_cmds[KERNEL_DOLLAR_CMD], menu_cmds[SEP_CMD], 62983446Smrj kernel); 62996448Svikram free(lp->cmd); 63003446Smrj free(lp->arg); 63013446Smrj free(lp->line); 63026448Svikram lp->cmd = s_strdup(menu_cmds[KERNEL_DOLLAR_CMD]); 63033446Smrj lp->arg = s_strdup(kernel); 63043446Smrj lp->line = s_strdup(linebuf); 63053446Smrj lp = lp->next; 63066448Svikram BAM_DPRINTF((D_ADDING_KERNEL_DOLLAR, fcn, kernel)); 63073446Smrj } 63083446Smrj if (strcmp(lp->cmd, menu_cmds[MODULE_CMD]) == 0) { 63093446Smrj (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s", 63103446Smrj menu_cmds[MODULE_DOLLAR_CMD], menu_cmds[SEP_CMD], 63113446Smrj module); 63126448Svikram free(lp->cmd); 63133446Smrj free(lp->arg); 63143446Smrj free(lp->line); 63156448Svikram lp->cmd = s_strdup(menu_cmds[MODULE_DOLLAR_CMD]); 63163446Smrj lp->arg = s_strdup(module); 63173446Smrj lp->line = s_strdup(linebuf); 63183446Smrj lp = lp->next; 63196448Svikram BAM_DPRINTF((D_ADDING_MODULE_DOLLAR, fcn, module)); 63206448Svikram } 63216448Svikram } 63226448Svikram BAM_DPRINTF((D_RETURN_RET, fcn, i)); 6323662Sszhou return (i); 6324662Sszhou } 6325662Sszhou 63266448Svikram int 63276448Svikram root_optional(char *osroot, char *menu_root) 63286448Svikram { 63296448Svikram char *ospecial; 63306448Svikram char *mspecial; 63316448Svikram char *slash; 63326448Svikram int root_opt; 63336448Svikram int ret1; 63346448Svikram int ret2; 63356448Svikram const char *fcn = "root_optional()"; 63366448Svikram 63376448Svikram BAM_DPRINTF((D_FUNC_ENTRY2, fcn, osroot, menu_root)); 63386448Svikram 63396448Svikram /* 63406448Svikram * For all filesystems except ZFS, a straight compare of osroot 63416448Svikram * and menu_root will tell us if root is optional. 63426448Svikram * For ZFS, the situation is complicated by the fact that 63436448Svikram * menu_root and osroot are always different 63446448Svikram */ 63456448Svikram ret1 = is_zfs(osroot); 63466448Svikram ret2 = is_zfs(menu_root); 63476448Svikram INJECT_ERROR1("ROOT_OPT_NOT_ZFS", ret1 = 0); 63486448Svikram if (!ret1 || !ret2) { 63496448Svikram BAM_DPRINTF((D_ROOT_OPT_NOT_ZFS, fcn, osroot, menu_root)); 63506448Svikram root_opt = (strcmp(osroot, menu_root) == 0); 63516448Svikram goto out; 63526448Svikram } 63536448Svikram 63546448Svikram ospecial = get_special(osroot); 63556448Svikram INJECT_ERROR1("ROOT_OPTIONAL_OSPECIAL", ospecial = NULL); 63566448Svikram if (ospecial == NULL) { 63576448Svikram bam_error(GET_OSROOT_SPECIAL_ERR, osroot); 63586448Svikram return (0); 63596448Svikram } 63606448Svikram BAM_DPRINTF((D_ROOT_OPTIONAL_OSPECIAL, fcn, ospecial, osroot)); 63616448Svikram 63626448Svikram mspecial = get_special(menu_root); 63636448Svikram INJECT_ERROR1("ROOT_OPTIONAL_MSPECIAL", mspecial = NULL); 63646448Svikram if (mspecial == NULL) { 63656448Svikram bam_error(GET_MENU_ROOT_SPECIAL_ERR, menu_root); 63666448Svikram free(ospecial); 63676448Svikram return (0); 63686448Svikram } 63696448Svikram BAM_DPRINTF((D_ROOT_OPTIONAL_MSPECIAL, fcn, mspecial, menu_root)); 63706448Svikram 63716448Svikram slash = strchr(ospecial, '/'); 63726448Svikram if (slash) 63736448Svikram *slash = '\0'; 63746448Svikram BAM_DPRINTF((D_ROOT_OPTIONAL_FIXED_OSPECIAL, fcn, ospecial, osroot)); 63756448Svikram 63766448Svikram root_opt = (strcmp(ospecial, mspecial) == 0); 63776448Svikram 63786448Svikram free(ospecial); 63796448Svikram free(mspecial); 63806448Svikram 63816448Svikram out: 63826448Svikram INJECT_ERROR1("ROOT_OPTIONAL_NO", root_opt = 0); 63836448Svikram INJECT_ERROR1("ROOT_OPTIONAL_YES", root_opt = 1); 63846448Svikram if (root_opt) { 63856448Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 63866448Svikram } else { 63876448Svikram BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 63886448Svikram } 63896448Svikram 63906448Svikram return (root_opt); 63916448Svikram } 63926448Svikram 63930Sstevel@tonic-gate /*ARGSUSED*/ 63940Sstevel@tonic-gate static error_t 63956448Svikram update_entry(menu_t *mp, char *menu_root, char *osdev) 63966448Svikram { 63976448Svikram int entry; 63986448Svikram char *grubsign; 63996448Svikram char *grubroot; 64006448Svikram char *title; 64016448Svikram char osroot[PATH_MAX]; 64026448Svikram char *failsafe_kernel = NULL; 64036448Svikram struct stat sbuf; 64046448Svikram char failsafe[256]; 64056448Svikram int ret; 64066448Svikram const char *fcn = "update_entry()"; 64070Sstevel@tonic-gate 64080Sstevel@tonic-gate assert(mp); 64096448Svikram assert(menu_root); 64106448Svikram assert(osdev); 64116448Svikram assert(bam_root); 64126448Svikram 64136448Svikram BAM_DPRINTF((D_FUNC_ENTRY3, fcn, menu_root, osdev, bam_root)); 64146448Svikram 64156448Svikram (void) strlcpy(osroot, bam_root, sizeof (osroot)); 64166448Svikram 64170Sstevel@tonic-gate title = get_title(osroot); 64186448Svikram assert(title); 64196448Svikram 64206448Svikram grubsign = get_grubsign(osroot, osdev); 64216448Svikram INJECT_ERROR1("GET_GRUBSIGN_FAIL", grubsign = NULL); 64226448Svikram if (grubsign == NULL) { 64236448Svikram bam_error(GET_GRUBSIGN_ERROR, osroot, osdev); 64240Sstevel@tonic-gate return (BAM_ERROR); 64250Sstevel@tonic-gate } 64266448Svikram 64276448Svikram /* 64286448Svikram * It is not a fatal error if get_grubroot() fails 64296448Svikram * We no longer rely on biosdev to populate the 64306448Svikram * menu 64316448Svikram */ 64326448Svikram grubroot = get_grubroot(osroot, osdev, menu_root); 64336448Svikram INJECT_ERROR1("GET_GRUBROOT_FAIL", grubroot = NULL); 64346448Svikram if (grubroot) { 64356448Svikram BAM_DPRINTF((D_GET_GRUBROOT_SUCCESS, 64366448Svikram fcn, osroot, osdev, menu_root)); 64376448Svikram } else { 64386448Svikram BAM_DPRINTF((D_GET_GRUBROOT_FAILURE, 64396448Svikram fcn, osroot, osdev, menu_root)); 64400Sstevel@tonic-gate } 64410Sstevel@tonic-gate 64420Sstevel@tonic-gate /* add the entry for normal Solaris */ 64436448Svikram INJECT_ERROR1("UPDATE_ENTRY_MULTIBOOT", 64446448Svikram bam_direct = BAM_DIRECT_MULTIBOOT); 64453446Smrj if (bam_direct == BAM_DIRECT_DBOOT) { 64466448Svikram entry = update_boot_entry(mp, title, grubsign, grubroot, 64476423Sgw25295 (bam_zfs ? DIRECT_BOOT_KERNEL_ZFS : DIRECT_BOOT_KERNEL), 64486448Svikram NULL, DIRECT_BOOT_ARCHIVE, 64496448Svikram root_optional(osroot, menu_root)); 64506448Svikram BAM_DPRINTF((D_UPDATED_BOOT_ENTRY, fcn, bam_zfs, grubsign)); 64515084Sjohnlev if ((entry != BAM_ERROR) && (bam_is_hv == BAM_HV_PRESENT)) { 64526448Svikram (void) update_boot_entry(mp, NEW_HV_ENTRY, grubsign, 64536448Svikram grubroot, XEN_MENU, bam_zfs ? 64546448Svikram XEN_KERNEL_MODULE_LINE_ZFS : XEN_KERNEL_MODULE_LINE, 64556448Svikram DIRECT_BOOT_ARCHIVE, 64566448Svikram root_optional(osroot, menu_root)); 64576448Svikram BAM_DPRINTF((D_UPDATED_HV_ENTRY, 64586448Svikram fcn, bam_zfs, grubsign)); 64595084Sjohnlev } 64603446Smrj } else { 64616448Svikram entry = update_boot_entry(mp, title, grubsign, grubroot, 64626448Svikram MULTI_BOOT, NULL, MULTIBOOT_ARCHIVE, 64636448Svikram root_optional(osroot, menu_root)); 64646448Svikram 64656448Svikram BAM_DPRINTF((D_UPDATED_MULTIBOOT_ENTRY, fcn, grubsign)); 64665084Sjohnlev } 64675084Sjohnlev 64685084Sjohnlev /* 64695084Sjohnlev * Add the entry for failsafe archive. On a bfu'd system, the 64705084Sjohnlev * failsafe may be different than the installed kernel. 64715084Sjohnlev */ 64726448Svikram (void) snprintf(failsafe, sizeof (failsafe), "%s%s", 64736448Svikram osroot, FAILSAFE_ARCHIVE); 64743446Smrj if (stat(failsafe, &sbuf) == 0) { 64753449Srscott 64763449Srscott /* Figure out where the kernel line should point */ 64773449Srscott (void) snprintf(failsafe, sizeof (failsafe), "%s%s", osroot, 64783449Srscott DIRECT_BOOT_FAILSAFE_KERNEL); 64793449Srscott if (stat(failsafe, &sbuf) == 0) { 64806694Svikram failsafe_kernel = DIRECT_BOOT_FAILSAFE_LINE; 64813449Srscott } else { 64823449Srscott (void) snprintf(failsafe, sizeof (failsafe), "%s%s", 64833449Srscott osroot, MULTI_BOOT_FAILSAFE); 64843449Srscott if (stat(failsafe, &sbuf) == 0) { 64853449Srscott failsafe_kernel = MULTI_BOOT_FAILSAFE_LINE; 64863449Srscott } 64873449Srscott } 64883449Srscott if (failsafe_kernel != NULL) { 64896448Svikram (void) update_boot_entry(mp, FAILSAFE_TITLE, grubsign, 64906448Svikram grubroot, failsafe_kernel, NULL, FAILSAFE_ARCHIVE, 64916448Svikram root_optional(osroot, menu_root)); 64926448Svikram BAM_DPRINTF((D_UPDATED_FAILSAFE_ENTRY, fcn, 64936448Svikram failsafe_kernel)); 64946448Svikram } 64956448Svikram } 64966448Svikram free(grubroot); 64976448Svikram 64986448Svikram INJECT_ERROR1("UPDATE_ENTRY_ERROR", entry = BAM_ERROR); 64990Sstevel@tonic-gate if (entry == BAM_ERROR) { 65006448Svikram bam_error(FAILED_TO_ADD_BOOT_ENTRY, title, grubsign); 65016448Svikram free(grubsign); 65020Sstevel@tonic-gate return (BAM_ERROR); 65030Sstevel@tonic-gate } 65046448Svikram free(grubsign); 65056448Svikram 65066448Svikram update_numbering(mp); 65076448Svikram ret = set_global(mp, menu_cmds[DEFAULT_CMD], entry); 65086448Svikram INJECT_ERROR1("SET_DEFAULT_ERROR", ret = BAM_ERROR); 65096448Svikram if (ret == BAM_ERROR) { 65106448Svikram bam_error(SET_DEFAULT_FAILED, entry); 65116448Svikram } 65126448Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 65130Sstevel@tonic-gate return (BAM_WRITE); 65140Sstevel@tonic-gate } 65150Sstevel@tonic-gate 6516662Sszhou static void 65173446Smrj save_default_entry(menu_t *mp, const char *which) 6518662Sszhou { 65196448Svikram int lineNum; 65206448Svikram int entryNum; 65216448Svikram int entry = 0; /* default is 0 */ 65226448Svikram char linebuf[BAM_MAXLINE]; 65236448Svikram line_t *lp = mp->curdefault; 65246448Svikram const char *fcn = "save_default_entry()"; 6525662Sszhou 65263381Svikram if (mp->start) { 65273381Svikram lineNum = mp->end->lineNum; 65283381Svikram entryNum = mp->end->entryNum; 65293381Svikram } else { 65303381Svikram lineNum = LINE_INIT; 65313381Svikram entryNum = ENTRY_INIT; 65323381Svikram } 65333381Svikram 6534662Sszhou if (lp) 6535662Sszhou entry = s_strtol(lp->arg); 6536662Sszhou 65373446Smrj (void) snprintf(linebuf, sizeof (linebuf), "#%s%d", which, entry); 65386448Svikram BAM_DPRINTF((D_SAVING_DEFAULT_TO, fcn, linebuf)); 6539662Sszhou line_parser(mp, linebuf, &lineNum, &entryNum); 65406448Svikram BAM_DPRINTF((D_SAVED_DEFAULT_TO, fcn, lineNum, entryNum)); 6541662Sszhou } 6542662Sszhou 6543662Sszhou static void 65443446Smrj restore_default_entry(menu_t *mp, const char *which, line_t *lp) 6545662Sszhou { 65466448Svikram int entry; 65476448Svikram char *str; 65486448Svikram const char *fcn = "restore_default_entry()"; 65496448Svikram 65506448Svikram if (lp == NULL) { 65516448Svikram BAM_DPRINTF((D_RESTORE_DEFAULT_NULL, fcn)); 6552662Sszhou return; /* nothing to restore */ 65536448Svikram } 65546448Svikram 65556448Svikram BAM_DPRINTF((D_RESTORE_DEFAULT_STR, fcn, which)); 6556662Sszhou 65573446Smrj str = lp->arg + strlen(which); 6558662Sszhou entry = s_strtol(str); 6559662Sszhou (void) set_global(mp, menu_cmds[DEFAULT_CMD], entry); 6560662Sszhou 65616448Svikram BAM_DPRINTF((D_RESTORED_DEFAULT_TO, fcn, entry)); 65626448Svikram 6563662Sszhou /* delete saved old default line */ 6564662Sszhou unlink_line(mp, lp); 6565662Sszhou line_free(lp); 6566662Sszhou } 6567662Sszhou 65680Sstevel@tonic-gate /* 65690Sstevel@tonic-gate * This function is for supporting reboot with args. 65700Sstevel@tonic-gate * The opt value can be: 65710Sstevel@tonic-gate * NULL delete temp entry, if present 65726448Svikram * entry=<n> switches default entry to <n> 65730Sstevel@tonic-gate * else treated as boot-args and setup a temperary menu entry 65740Sstevel@tonic-gate * and make it the default 65756448Svikram * Note that we are always rebooting the current OS instance 65766448Svikram * so osroot == / always. 65770Sstevel@tonic-gate */ 65780Sstevel@tonic-gate #define REBOOT_TITLE "Solaris_reboot_transient" 65790Sstevel@tonic-gate 6580662Sszhou /*ARGSUSED*/ 65810Sstevel@tonic-gate static error_t 65826448Svikram update_temp(menu_t *mp, char *dummy, char *opt) 65836448Svikram { 65846448Svikram int entry; 65856448Svikram char *osdev; 65866448Svikram char *fstype; 65876448Svikram char *sign; 65886448Svikram char *opt_ptr; 65896448Svikram char *path; 65906448Svikram char kernbuf[BUFSIZ]; 65916448Svikram char args_buf[BUFSIZ]; 65926448Svikram char signbuf[PATH_MAX]; 65936448Svikram int ret; 65946448Svikram const char *fcn = "update_temp()"; 65950Sstevel@tonic-gate 65960Sstevel@tonic-gate assert(mp); 65976448Svikram assert(dummy == NULL); 65986448Svikram 65996448Svikram /* opt can be NULL */ 66006448Svikram BAM_DPRINTF((D_FUNC_ENTRY1, fcn, opt ? opt : "<NULL>")); 66016448Svikram BAM_DPRINTF((D_BAM_ROOT, fcn, bam_alt_root, bam_root)); 66026448Svikram 66036448Svikram if (bam_alt_root || bam_rootlen != 1 || 66046448Svikram strcmp(bam_root, "/") != 0 || 66056448Svikram strcmp(rootbuf, "/") != 0) { 66066448Svikram bam_error(ALT_ROOT_INVALID, bam_root); 66076448Svikram return (BAM_ERROR); 66086448Svikram } 66090Sstevel@tonic-gate 6610662Sszhou /* If no option, delete exiting reboot menu entry */ 6611662Sszhou if (opt == NULL) { 66126448Svikram entry_t *ent; 66136448Svikram BAM_DPRINTF((D_OPT_NULL, fcn)); 66146448Svikram ent = find_boot_entry(mp, REBOOT_TITLE, NULL, NULL, 66156448Svikram NULL, NULL, 0, &entry); 66166448Svikram if (ent == NULL) { /* not found is ok */ 66176448Svikram BAM_DPRINTF((D_TRANSIENT_NOTFOUND, fcn)); 6618662Sszhou return (BAM_SUCCESS); 66196448Svikram } 6620662Sszhou (void) do_delete(mp, entry); 66213446Smrj restore_default_entry(mp, BAM_OLDDEF, mp->olddefault); 66223446Smrj mp->olddefault = NULL; 66236448Svikram BAM_DPRINTF((D_RESTORED_DEFAULT, fcn)); 66246448Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 6625662Sszhou return (BAM_WRITE); 6626662Sszhou } 6627662Sszhou 6628662Sszhou /* if entry= is specified, set the default entry */ 66296448Svikram if (strncmp(opt, "entry=", strlen("entry=")) == 0) { 66306448Svikram int entryNum = s_strtol(opt + strlen("entry=")); 66316448Svikram BAM_DPRINTF((D_ENTRY_EQUALS, fcn, opt)); 66326448Svikram if (selector(mp, opt, &entry, NULL) == BAM_SUCCESS) { 66336448Svikram /* this is entry=# option */ 66346448Svikram ret = set_global(mp, menu_cmds[DEFAULT_CMD], entry); 66356448Svikram BAM_DPRINTF((D_ENTRY_SET_IS, fcn, entry, ret)); 66366448Svikram return (ret); 66376448Svikram } else { 66386448Svikram bam_error(SET_DEFAULT_FAILED, entryNum); 66396448Svikram return (BAM_ERROR); 66406448Svikram } 66410Sstevel@tonic-gate } 66420Sstevel@tonic-gate 66430Sstevel@tonic-gate /* 66446448Svikram * add a new menu entry based on opt and make it the default 66450Sstevel@tonic-gate */ 66466448Svikram 66476448Svikram fstype = get_fstype("/"); 66486448Svikram INJECT_ERROR1("REBOOT_FSTYPE_NULL", fstype = NULL); 66496448Svikram if (fstype == NULL) { 66506448Svikram bam_error(REBOOT_FSTYPE_FAILED); 66516448Svikram return (BAM_ERROR); 66526448Svikram } 66536448Svikram 66546448Svikram osdev = get_special("/"); 66556448Svikram INJECT_ERROR1("REBOOT_SPECIAL_NULL", osdev = NULL); 66566448Svikram if (osdev == NULL) { 66576448Svikram free(fstype); 66586448Svikram bam_error(REBOOT_SPECIAL_FAILED); 66596448Svikram return (BAM_ERROR); 66606448Svikram } 66616448Svikram 66626448Svikram sign = find_existing_sign("/", osdev, fstype); 66636448Svikram INJECT_ERROR1("REBOOT_SIGN_NULL", sign = NULL); 66646448Svikram if (sign == NULL) { 66656448Svikram free(fstype); 66666448Svikram free(osdev); 66676448Svikram bam_error(REBOOT_SIGN_FAILED); 66686448Svikram return (BAM_ERROR); 66696448Svikram } 66706448Svikram 66716448Svikram free(fstype); 66726448Svikram free(osdev); 66736448Svikram (void) strlcpy(signbuf, sign, sizeof (signbuf)); 66746448Svikram free(sign); 66756448Svikram 66766448Svikram assert(strchr(signbuf, '(') == NULL && strchr(signbuf, ',') == NULL && 66776448Svikram strchr(signbuf, ')') == NULL); 66786448Svikram 66796448Svikram /* 66806448Svikram * There is no alternate root while doing reboot with args 66816448Svikram * This version of bootadm is only delivered with a DBOOT 66826448Svikram * version of Solaris. 66836448Svikram */ 66846448Svikram INJECT_ERROR1("REBOOT_NOT_DBOOT", bam_direct = BAM_DIRECT_MULTIBOOT); 66856448Svikram if (bam_direct != BAM_DIRECT_DBOOT) { 66866448Svikram bam_error(REBOOT_DIRECT_FAILED); 66870Sstevel@tonic-gate return (BAM_ERROR); 66880Sstevel@tonic-gate } 66890Sstevel@tonic-gate 66900Sstevel@tonic-gate /* add an entry for Solaris reboot */ 66916448Svikram if (opt[0] == '-') { 66926448Svikram /* It's an option - first see if boot-file is set */ 66936448Svikram ret = get_kernel(mp, KERNEL_CMD, kernbuf, sizeof (kernbuf)); 66946448Svikram INJECT_ERROR1("REBOOT_GET_KERNEL", ret = BAM_ERROR); 66956448Svikram if (ret != BAM_SUCCESS) { 66966448Svikram bam_error(REBOOT_GET_KERNEL_FAILED); 66976448Svikram return (BAM_ERROR); 66986448Svikram } 66996448Svikram if (kernbuf[0] == '\0') 67006448Svikram (void) strlcpy(kernbuf, DIRECT_BOOT_KERNEL, 67016448Svikram sizeof (kernbuf)); 67026448Svikram (void) strlcat(kernbuf, " ", sizeof (kernbuf)); 67036448Svikram (void) strlcat(kernbuf, opt, sizeof (kernbuf)); 67046448Svikram BAM_DPRINTF((D_REBOOT_OPTION, fcn, kernbuf)); 67056448Svikram } else if (opt[0] == '/') { 67066448Svikram /* It's a full path, so write it out. */ 67076448Svikram (void) strlcpy(kernbuf, opt, sizeof (kernbuf)); 67086448Svikram 67096448Svikram /* 67106448Svikram * If someone runs: 67116448Svikram * 67126448Svikram * # eeprom boot-args='-kd' 67136448Svikram * # reboot /platform/i86pc/kernel/unix 67146448Svikram * 67156448Svikram * we want to use the boot-args as part of the boot 67166448Svikram * line. On the other hand, if someone runs: 67176448Svikram * 67186448Svikram * # reboot "/platform/i86pc/kernel/unix -kd" 67196448Svikram * 67206448Svikram * we don't need to mess with boot-args. If there's 67216448Svikram * no space in the options string, assume we're in the 67226448Svikram * first case. 67236448Svikram */ 67246448Svikram if (strchr(opt, ' ') == NULL) { 67256448Svikram ret = get_kernel(mp, ARGS_CMD, args_buf, 67266448Svikram sizeof (args_buf)); 67276448Svikram INJECT_ERROR1("REBOOT_GET_ARGS", ret = BAM_ERROR); 67286448Svikram if (ret != BAM_SUCCESS) { 67296448Svikram bam_error(REBOOT_GET_ARGS_FAILED); 67303446Smrj return (BAM_ERROR); 67316448Svikram } 67326448Svikram 67336448Svikram if (args_buf[0] != '\0') { 67346448Svikram (void) strlcat(kernbuf, " ", sizeof (kernbuf)); 67356448Svikram (void) strlcat(kernbuf, args_buf, 67366448Svikram sizeof (kernbuf)); 67376448Svikram } 67386448Svikram } 67396448Svikram BAM_DPRINTF((D_REBOOT_ABSPATH, fcn, kernbuf)); 67406448Svikram } else { 67416448Svikram /* 67426448Svikram * It may be a partial path, or it may be a partial 67436448Svikram * path followed by options. Assume that only options 67446448Svikram * follow a space. If someone sends us a kernel path 67456448Svikram * that includes a space, they deserve to be broken. 67466448Svikram */ 67476448Svikram opt_ptr = strchr(opt, ' '); 67486448Svikram if (opt_ptr != NULL) { 67496448Svikram *opt_ptr = '\0'; 67506448Svikram } 67516448Svikram 67526448Svikram path = expand_path(opt); 67536448Svikram if (path != NULL) { 67546448Svikram (void) strlcpy(kernbuf, path, sizeof (kernbuf)); 67556448Svikram free(path); 67564346Srscott 67574346Srscott /* 67586448Svikram * If there were options given, use those. 67596448Svikram * Otherwise, copy over the default options. 67604346Srscott */ 67616448Svikram if (opt_ptr != NULL) { 67626448Svikram /* Restore the space in opt string */ 67636448Svikram *opt_ptr = ' '; 67646448Svikram (void) strlcat(kernbuf, opt_ptr, 67656448Svikram sizeof (kernbuf)); 67666448Svikram } else { 67676448Svikram ret = get_kernel(mp, ARGS_CMD, args_buf, 67686448Svikram sizeof (args_buf)); 67696448Svikram INJECT_ERROR1("UPDATE_TEMP_PARTIAL_ARGS", 67706448Svikram ret = BAM_ERROR); 67716448Svikram if (ret != BAM_SUCCESS) { 67726448Svikram bam_error(REBOOT_GET_ARGS_FAILED); 67734346Srscott return (BAM_ERROR); 67746448Svikram } 67754346Srscott 67764346Srscott if (args_buf[0] != '\0') { 67776448Svikram (void) strlcat(kernbuf, " ", 67786448Svikram sizeof (kernbuf)); 67796448Svikram (void) strlcat(kernbuf, 67806448Svikram args_buf, sizeof (kernbuf)); 67814346Srscott } 67824346Srscott } 67836448Svikram BAM_DPRINTF((D_REBOOT_RESOLVED_PARTIAL, fcn, kernbuf)); 67843446Smrj } else { 67856448Svikram bam_error(UNKNOWN_KERNEL, opt); 67866448Svikram bam_print_stderr(UNKNOWN_KERNEL_REBOOT); 67876448Svikram return (BAM_ERROR); 67886448Svikram } 67896448Svikram } 67906448Svikram entry = add_boot_entry(mp, REBOOT_TITLE, signbuf, kernbuf, 67916448Svikram NULL, NULL); 67926448Svikram INJECT_ERROR1("REBOOT_ADD_BOOT_ENTRY", entry = BAM_ERROR); 67930Sstevel@tonic-gate if (entry == BAM_ERROR) { 67946448Svikram bam_error(REBOOT_WITH_ARGS_ADD_ENTRY_FAILED); 67950Sstevel@tonic-gate return (BAM_ERROR); 67960Sstevel@tonic-gate } 6797662Sszhou 67983446Smrj save_default_entry(mp, BAM_OLDDEF); 67996448Svikram ret = set_global(mp, menu_cmds[DEFAULT_CMD], entry); 68006448Svikram INJECT_ERROR1("REBOOT_SET_GLOBAL", ret = BAM_ERROR); 68016448Svikram if (ret == BAM_ERROR) { 68026448Svikram bam_error(REBOOT_SET_DEFAULT_FAILED, entry); 68036448Svikram } 68046448Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 68050Sstevel@tonic-gate return (BAM_WRITE); 68060Sstevel@tonic-gate } 68070Sstevel@tonic-gate 68080Sstevel@tonic-gate static error_t 68090Sstevel@tonic-gate set_global(menu_t *mp, char *globalcmd, int val) 68100Sstevel@tonic-gate { 68116448Svikram line_t *lp; 68126448Svikram line_t *found; 68136448Svikram line_t *last; 68146448Svikram char *cp; 68156448Svikram char *str; 68166448Svikram char prefix[BAM_MAXLINE]; 68176448Svikram size_t len; 68186448Svikram const char *fcn = "set_global()"; 68190Sstevel@tonic-gate 68200Sstevel@tonic-gate assert(mp); 68210Sstevel@tonic-gate assert(globalcmd); 68220Sstevel@tonic-gate 6823316Svikram if (strcmp(globalcmd, menu_cmds[DEFAULT_CMD]) == 0) { 68246448Svikram INJECT_ERROR1("SET_GLOBAL_VAL_NEG", val = -1); 68256448Svikram INJECT_ERROR1("SET_GLOBAL_MENU_EMPTY", mp->end = NULL); 68266448Svikram INJECT_ERROR1("SET_GLOBAL_VAL_TOO_BIG", val = 100); 6827316Svikram if (val < 0 || mp->end == NULL || val > mp->end->entryNum) { 6828316Svikram (void) snprintf(prefix, sizeof (prefix), "%d", val); 6829316Svikram bam_error(INVALID_ENTRY, prefix); 6830316Svikram return (BAM_ERROR); 6831316Svikram } 6832316Svikram } 6833316Svikram 68340Sstevel@tonic-gate found = last = NULL; 68350Sstevel@tonic-gate for (lp = mp->start; lp; lp = lp->next) { 68360Sstevel@tonic-gate if (lp->flags != BAM_GLOBAL) 68370Sstevel@tonic-gate continue; 68380Sstevel@tonic-gate 68390Sstevel@tonic-gate last = lp; /* track the last global found */ 68400Sstevel@tonic-gate 68416448Svikram INJECT_ERROR1("SET_GLOBAL_NULL_CMD", lp->cmd = NULL); 68420Sstevel@tonic-gate if (lp->cmd == NULL) { 68430Sstevel@tonic-gate bam_error(NO_CMD, lp->lineNum); 68440Sstevel@tonic-gate continue; 68450Sstevel@tonic-gate } 68460Sstevel@tonic-gate if (strcmp(globalcmd, lp->cmd) != 0) 68470Sstevel@tonic-gate continue; 68480Sstevel@tonic-gate 68496448Svikram BAM_DPRINTF((D_FOUND_GLOBAL, fcn, globalcmd)); 68506448Svikram 68510Sstevel@tonic-gate if (found) { 68520Sstevel@tonic-gate bam_error(DUP_CMD, globalcmd, lp->lineNum, bam_root); 68530Sstevel@tonic-gate } 68540Sstevel@tonic-gate found = lp; 68550Sstevel@tonic-gate } 68560Sstevel@tonic-gate 68570Sstevel@tonic-gate if (found == NULL) { 68580Sstevel@tonic-gate lp = s_calloc(1, sizeof (line_t)); 68590Sstevel@tonic-gate if (last == NULL) { 68600Sstevel@tonic-gate lp->next = mp->start; 68610Sstevel@tonic-gate mp->start = lp; 68620Sstevel@tonic-gate mp->end = (mp->end) ? mp->end : lp; 68630Sstevel@tonic-gate } else { 68640Sstevel@tonic-gate lp->next = last->next; 68650Sstevel@tonic-gate last->next = lp; 68660Sstevel@tonic-gate if (lp->next == NULL) 68670Sstevel@tonic-gate mp->end = lp; 68680Sstevel@tonic-gate } 68690Sstevel@tonic-gate lp->flags = BAM_GLOBAL; /* other fields not needed for writes */ 68700Sstevel@tonic-gate len = strlen(globalcmd) + strlen(menu_cmds[SEP_CMD]); 68710Sstevel@tonic-gate len += 10; /* val < 10 digits */ 68720Sstevel@tonic-gate lp->line = s_calloc(1, len); 68730Sstevel@tonic-gate (void) snprintf(lp->line, len, "%s%s%d", 68740Sstevel@tonic-gate globalcmd, menu_cmds[SEP_CMD], val); 68756448Svikram BAM_DPRINTF((D_SET_GLOBAL_WROTE_NEW, fcn, lp->line)); 68766448Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 68770Sstevel@tonic-gate return (BAM_WRITE); 68780Sstevel@tonic-gate } 68790Sstevel@tonic-gate 68800Sstevel@tonic-gate /* 68810Sstevel@tonic-gate * We are changing an existing entry. Retain any prefix whitespace, 68820Sstevel@tonic-gate * but overwrite everything else. This preserves tabs added for 68830Sstevel@tonic-gate * readability. 68840Sstevel@tonic-gate */ 68850Sstevel@tonic-gate str = found->line; 68860Sstevel@tonic-gate cp = prefix; 68870Sstevel@tonic-gate while (*str == ' ' || *str == '\t') 68880Sstevel@tonic-gate *(cp++) = *(str++); 68890Sstevel@tonic-gate *cp = '\0'; /* Terminate prefix */ 68900Sstevel@tonic-gate len = strlen(prefix) + strlen(globalcmd); 68910Sstevel@tonic-gate len += strlen(menu_cmds[SEP_CMD]) + 10; 68920Sstevel@tonic-gate 68930Sstevel@tonic-gate free(found->line); 68940Sstevel@tonic-gate found->line = s_calloc(1, len); 68950Sstevel@tonic-gate (void) snprintf(found->line, len, 68964346Srscott "%s%s%s%d", prefix, globalcmd, menu_cmds[SEP_CMD], val); 68970Sstevel@tonic-gate 68986448Svikram BAM_DPRINTF((D_SET_GLOBAL_REPLACED, fcn, found->line)); 68996448Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 69000Sstevel@tonic-gate return (BAM_WRITE); /* need a write to menu */ 69010Sstevel@tonic-gate } 69020Sstevel@tonic-gate 69033446Smrj /* 69043446Smrj * partial_path may be anything like "kernel/unix" or "kmdb". Try to 69054346Srscott * expand it to a full unix path. The calling function is expected to 69064346Srscott * output a message if an error occurs and NULL is returned. 69073446Smrj */ 69083446Smrj static char * 69093446Smrj expand_path(const char *partial_path) 69103446Smrj { 69116448Svikram int new_path_len; 69126448Svikram char *new_path; 69136448Svikram char new_path2[PATH_MAX]; 69146448Svikram struct stat sb; 69156448Svikram const char *fcn = "expand_path()"; 69163446Smrj 69173446Smrj new_path_len = strlen(partial_path) + 64; 69183446Smrj new_path = s_calloc(1, new_path_len); 69193446Smrj 69203446Smrj /* First, try the simplest case - something like "kernel/unix" */ 69213446Smrj (void) snprintf(new_path, new_path_len, "/platform/i86pc/%s", 69223446Smrj partial_path); 69233446Smrj if (stat(new_path, &sb) == 0) { 69246448Svikram BAM_DPRINTF((D_EXPAND_PATH, fcn, new_path)); 69253446Smrj return (new_path); 69263446Smrj } 69273446Smrj 69283446Smrj if (strcmp(partial_path, "kmdb") == 0) { 69293446Smrj (void) snprintf(new_path, new_path_len, "%s -k", 69303446Smrj DIRECT_BOOT_KERNEL); 69316448Svikram BAM_DPRINTF((D_EXPAND_PATH, fcn, new_path)); 69323446Smrj return (new_path); 69333446Smrj } 69343446Smrj 69353446Smrj /* 69363446Smrj * We've quickly reached unsupported usage. Try once more to 69373446Smrj * see if we were just given a glom name. 69383446Smrj */ 69393446Smrj (void) snprintf(new_path, new_path_len, "/platform/i86pc/%s/unix", 69403446Smrj partial_path); 69413446Smrj (void) snprintf(new_path2, PATH_MAX, "/platform/i86pc/%s/amd64/unix", 69423446Smrj partial_path); 69433446Smrj if (stat(new_path, &sb) == 0) { 69443446Smrj if (stat(new_path2, &sb) == 0) { 69453446Smrj /* 69463446Smrj * We matched both, so we actually 69473446Smrj * want to write the $ISADIR version. 69483446Smrj */ 69493446Smrj (void) snprintf(new_path, new_path_len, 69503446Smrj "/platform/i86pc/kernel/%s/$ISADIR/unix", 69513446Smrj partial_path); 69523446Smrj } 69536448Svikram BAM_DPRINTF((D_EXPAND_PATH, fcn, new_path)); 69543446Smrj return (new_path); 69553446Smrj } 69563446Smrj 69573446Smrj free(new_path); 69586448Svikram BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 69593446Smrj return (NULL); 69603446Smrj } 69613446Smrj 69623446Smrj /* 69633446Smrj * The kernel cmd and arg have been changed, so 69643446Smrj * check whether the archive line needs to change. 69653446Smrj */ 69663446Smrj static void 69673446Smrj set_archive_line(entry_t *entryp, line_t *kernelp) 69683446Smrj { 69696448Svikram line_t *lp = entryp->start; 69706448Svikram char *new_archive; 69716448Svikram menu_cmd_t m_cmd; 69726448Svikram const char *fcn = "set_archive_line()"; 69733446Smrj 69743446Smrj for (; lp != NULL; lp = lp->next) { 69753446Smrj if (strncmp(lp->cmd, menu_cmds[MODULE_CMD], 69763446Smrj sizeof (menu_cmds[MODULE_CMD]) - 1) == 0) { 69773446Smrj break; 69783446Smrj } 69796448Svikram 69806448Svikram INJECT_ERROR1("SET_ARCHIVE_LINE_END_ENTRY", lp = entryp->end); 69816448Svikram if (lp == entryp->end) { 69826448Svikram BAM_DPRINTF((D_ARCHIVE_LINE_NONE, fcn, 69836448Svikram entryp->entryNum)); 69843446Smrj return; 69856448Svikram } 69866448Svikram } 69876448Svikram INJECT_ERROR1("SET_ARCHIVE_LINE_END_MENU", lp = NULL); 69886448Svikram if (lp == NULL) { 69896448Svikram BAM_DPRINTF((D_ARCHIVE_LINE_NONE, fcn, entryp->entryNum)); 69903446Smrj return; 69916448Svikram } 69923446Smrj 69933446Smrj if (strstr(kernelp->arg, "$ISADIR") != NULL) { 69943446Smrj new_archive = DIRECT_BOOT_ARCHIVE; 69953446Smrj m_cmd = MODULE_DOLLAR_CMD; 69963446Smrj } else if (strstr(kernelp->arg, "amd64") != NULL) { 69973446Smrj new_archive = DIRECT_BOOT_ARCHIVE_64; 69983446Smrj m_cmd = MODULE_CMD; 69993446Smrj } else { 70003446Smrj new_archive = DIRECT_BOOT_ARCHIVE_32; 70013446Smrj m_cmd = MODULE_CMD; 70023446Smrj } 70033446Smrj 70046448Svikram if (strcmp(lp->arg, new_archive) == 0) { 70056448Svikram BAM_DPRINTF((D_ARCHIVE_LINE_NOCHANGE, fcn, lp->arg)); 70063446Smrj return; 70076448Svikram } 70083446Smrj 70093446Smrj if (strcmp(lp->cmd, menu_cmds[m_cmd]) != 0) { 70103446Smrj free(lp->cmd); 70113446Smrj lp->cmd = s_strdup(menu_cmds[m_cmd]); 70123446Smrj } 70133446Smrj 70143446Smrj free(lp->arg); 70153446Smrj lp->arg = s_strdup(new_archive); 70163446Smrj update_line(lp); 70176448Svikram BAM_DPRINTF((D_ARCHIVE_LINE_REPLACED, fcn, lp->line)); 70183446Smrj } 70193446Smrj 70203446Smrj /* 70213446Smrj * Title for an entry to set properties that once went in bootenv.rc. 70223446Smrj */ 70233446Smrj #define BOOTENV_RC_TITLE "Solaris bootenv rc" 70243446Smrj 70253446Smrj /* 70263446Smrj * If path is NULL, return the kernel (optnum == KERNEL_CMD) or arguments 70273446Smrj * (optnum == ARGS_CMD) in the argument buf. If path is a zero-length 70283446Smrj * string, reset the value to the default. If path is a non-zero-length 70293446Smrj * string, set the kernel or arguments. 70303446Smrj */ 70313446Smrj static error_t 70326448Svikram get_set_kernel( 70336448Svikram menu_t *mp, 70346448Svikram menu_cmd_t optnum, 70356448Svikram char *path, 70366448Svikram char *buf, 70376448Svikram size_t bufsize) 70386448Svikram { 70396448Svikram int entryNum; 70406448Svikram int rv = BAM_SUCCESS; 70416448Svikram int free_new_path = 0; 70426448Svikram entry_t *entryp; 70436448Svikram line_t *ptr; 70446448Svikram line_t *kernelp; 70456448Svikram char *new_arg; 70466448Svikram char *old_args; 70476448Svikram char *space; 70486448Svikram char *new_path; 70496448Svikram char old_space; 70506448Svikram size_t old_kernel_len; 70516448Svikram size_t new_str_len; 70526448Svikram char *fstype; 70536448Svikram char *osdev; 70546448Svikram char *sign; 70556448Svikram char signbuf[PATH_MAX]; 70566448Svikram int ret; 70576448Svikram const char *fcn = "get_set_kernel()"; 70583446Smrj 70593446Smrj assert(bufsize > 0); 70603446Smrj 70613446Smrj ptr = kernelp = NULL; 70623446Smrj new_arg = old_args = space = NULL; 70636448Svikram new_path = NULL; 70643446Smrj buf[0] = '\0'; 70653446Smrj 70666448Svikram INJECT_ERROR1("GET_SET_KERNEL_NOT_DBOOT", 70676448Svikram bam_direct = BAM_DIRECT_MULTIBOOT); 70683446Smrj if (bam_direct != BAM_DIRECT_DBOOT) { 70693446Smrj bam_error(NOT_DBOOT, optnum == KERNEL_CMD ? "kernel" : "args"); 70703446Smrj return (BAM_ERROR); 70713446Smrj } 70723446Smrj 70733446Smrj /* 70743446Smrj * If a user changed the default entry to a non-bootadm controlled 70753446Smrj * one, we don't want to mess with it. Just print an error and 70763446Smrj * return. 70773446Smrj */ 70783446Smrj if (mp->curdefault) { 70793446Smrj entryNum = s_strtol(mp->curdefault->arg); 70803446Smrj for (entryp = mp->entries; entryp; entryp = entryp->next) { 70813446Smrj if (entryp->entryNum == entryNum) 70823446Smrj break; 70833446Smrj } 70843446Smrj if ((entryp != NULL) && 70853446Smrj ((entryp->flags & (BAM_ENTRY_BOOTADM|BAM_ENTRY_LU)) == 0)) { 70863446Smrj bam_error(DEFAULT_NOT_BAM); 70873446Smrj return (BAM_ERROR); 70883446Smrj } 70893446Smrj } 70903446Smrj 70916448Svikram entryp = find_boot_entry(mp, BOOTENV_RC_TITLE, NULL, NULL, NULL, NULL, 70926448Svikram 0, &entryNum); 70933446Smrj 70943446Smrj if (entryp != NULL) { 70953446Smrj for (ptr = entryp->start; ptr && ptr != entryp->end; 70963446Smrj ptr = ptr->next) { 70973446Smrj if (strncmp(ptr->cmd, menu_cmds[KERNEL_CMD], 70983446Smrj sizeof (menu_cmds[KERNEL_CMD]) - 1) == 0) { 70993446Smrj kernelp = ptr; 71003446Smrj break; 71013446Smrj } 71023446Smrj } 71033446Smrj if (kernelp == NULL) { 71043446Smrj bam_error(NO_KERNEL, entryNum); 71053446Smrj return (BAM_ERROR); 71063446Smrj } 71073446Smrj 71083446Smrj old_kernel_len = strcspn(kernelp->arg, " \t"); 71093446Smrj space = old_args = kernelp->arg + old_kernel_len; 71103446Smrj while ((*old_args == ' ') || (*old_args == '\t')) 71113446Smrj old_args++; 71123446Smrj } 71133446Smrj 71143446Smrj if (path == NULL) { 71156448Svikram if (entryp == NULL) { 71166448Svikram BAM_DPRINTF((D_GET_SET_KERNEL_NO_RC, fcn)); 71176448Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 71183446Smrj return (BAM_SUCCESS); 71196448Svikram } 71206448Svikram assert(kernelp); 71213446Smrj if (optnum == ARGS_CMD) { 71226448Svikram if (old_args[0] != '\0') { 71233446Smrj (void) strlcpy(buf, old_args, bufsize); 71246448Svikram BAM_DPRINTF((D_GET_SET_KERNEL_ARGS, fcn, buf)); 71256448Svikram } 71263446Smrj } else { 71273446Smrj /* 71283446Smrj * We need to print the kernel, so we just turn the 71293446Smrj * first space into a '\0' and print the beginning. 71303446Smrj * We don't print anything if it's the default kernel. 71313446Smrj */ 71323446Smrj old_space = *space; 71333446Smrj *space = '\0'; 71346448Svikram if (strcmp(kernelp->arg, DIRECT_BOOT_KERNEL) != 0) { 71353446Smrj (void) strlcpy(buf, kernelp->arg, bufsize); 71366448Svikram BAM_DPRINTF((D_GET_SET_KERNEL_KERN, fcn, buf)); 71376448Svikram } 71383446Smrj *space = old_space; 71393446Smrj } 71406448Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 71413446Smrj return (BAM_SUCCESS); 71423446Smrj } 71433446Smrj 71443446Smrj /* 71453446Smrj * First, check if we're resetting an entry to the default. 71463446Smrj */ 71473446Smrj if ((path[0] == '\0') || 71483446Smrj ((optnum == KERNEL_CMD) && 71493446Smrj (strcmp(path, DIRECT_BOOT_KERNEL) == 0))) { 71503446Smrj if ((entryp == NULL) || (kernelp == NULL)) { 71513446Smrj /* No previous entry, it's already the default */ 71526448Svikram BAM_DPRINTF((D_GET_SET_KERNEL_ALREADY, fcn)); 71533446Smrj return (BAM_SUCCESS); 71543446Smrj } 71553446Smrj 71563446Smrj /* 71573446Smrj * Check if we can delete the entry. If we're resetting the 71583446Smrj * kernel command, and the args is already empty, or if we're 71593446Smrj * resetting the args command, and the kernel is already the 71603446Smrj * default, we can restore the old default and delete the entry. 71613446Smrj */ 71623446Smrj if (((optnum == KERNEL_CMD) && 71633446Smrj ((old_args == NULL) || (old_args[0] == '\0'))) || 71643446Smrj ((optnum == ARGS_CMD) && 71653446Smrj (strncmp(kernelp->arg, DIRECT_BOOT_KERNEL, 71663446Smrj sizeof (DIRECT_BOOT_KERNEL) - 1) == 0))) { 71673446Smrj kernelp = NULL; 71683446Smrj (void) do_delete(mp, entryNum); 71693446Smrj restore_default_entry(mp, BAM_OLD_RC_DEF, 71703446Smrj mp->old_rc_default); 71713446Smrj mp->old_rc_default = NULL; 71723446Smrj rv = BAM_WRITE; 71736448Svikram BAM_DPRINTF((D_GET_SET_KERNEL_RESTORE_DEFAULT, fcn)); 71743446Smrj goto done; 71753446Smrj } 71763446Smrj 71773446Smrj if (optnum == KERNEL_CMD) { 71783446Smrj /* 71793446Smrj * At this point, we've already checked that old_args 71803446Smrj * and entryp are valid pointers. The "+ 2" is for 71813446Smrj * a space a the string termination character. 71823446Smrj */ 71833446Smrj new_str_len = (sizeof (DIRECT_BOOT_KERNEL) - 1) + 71843446Smrj strlen(old_args) + 2; 71853446Smrj new_arg = s_calloc(1, new_str_len); 71863446Smrj (void) snprintf(new_arg, new_str_len, "%s %s", 71873446Smrj DIRECT_BOOT_KERNEL, old_args); 71883446Smrj free(kernelp->arg); 71893446Smrj kernelp->arg = new_arg; 71903446Smrj 71913446Smrj /* 71923446Smrj * We have changed the kernel line, so we may need 71933446Smrj * to update the archive line as well. 71943446Smrj */ 71953446Smrj set_archive_line(entryp, kernelp); 71966448Svikram BAM_DPRINTF((D_GET_SET_KERNEL_RESET_KERNEL_SET_ARG, 71976448Svikram fcn, kernelp->arg)); 71983446Smrj } else { 71993446Smrj /* 72003446Smrj * We're resetting the boot args to nothing, so 72013446Smrj * we only need to copy the kernel. We've already 72023446Smrj * checked that the kernel is not the default. 72033446Smrj */ 72043446Smrj new_arg = s_calloc(1, old_kernel_len + 1); 72053446Smrj (void) snprintf(new_arg, old_kernel_len + 1, "%s", 72063446Smrj kernelp->arg); 72073446Smrj free(kernelp->arg); 72083446Smrj kernelp->arg = new_arg; 72096448Svikram BAM_DPRINTF((D_GET_SET_KERNEL_RESET_ARG_SET_KERNEL, 72106448Svikram fcn, kernelp->arg)); 72113446Smrj } 72123446Smrj rv = BAM_WRITE; 72133446Smrj goto done; 72143446Smrj } 72153446Smrj 72163446Smrj /* 72173446Smrj * Expand the kernel file to a full path, if necessary 72183446Smrj */ 72193446Smrj if ((optnum == KERNEL_CMD) && (path[0] != '/')) { 72203446Smrj new_path = expand_path(path); 72213446Smrj if (new_path == NULL) { 72224346Srscott bam_error(UNKNOWN_KERNEL, path); 72236448Svikram BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 72243446Smrj return (BAM_ERROR); 72253446Smrj } 72263446Smrj free_new_path = 1; 72273446Smrj } else { 72283446Smrj new_path = path; 72293446Smrj free_new_path = 0; 72303446Smrj } 72313446Smrj 72323446Smrj /* 72333446Smrj * At this point, we know we're setting a new value. First, take care 72343446Smrj * of the case where there was no previous entry. 72353446Smrj */ 72363446Smrj if (entryp == NULL) { 72376448Svikram 72383446Smrj /* Similar to code in update_temp */ 72396448Svikram fstype = get_fstype("/"); 72406448Svikram INJECT_ERROR1("GET_SET_KERNEL_FSTYPE", fstype = NULL); 72416448Svikram if (fstype == NULL) { 72426448Svikram bam_error(BOOTENV_FSTYPE_FAILED); 72436448Svikram rv = BAM_ERROR; 72446448Svikram goto done; 72456448Svikram } 72466448Svikram 72476448Svikram osdev = get_special("/"); 72486448Svikram INJECT_ERROR1("GET_SET_KERNEL_SPECIAL", osdev = NULL); 72496448Svikram if (osdev == NULL) { 72506448Svikram free(fstype); 72516448Svikram bam_error(BOOTENV_SPECIAL_FAILED); 72523446Smrj rv = BAM_ERROR; 72533446Smrj goto done; 72543446Smrj } 72556448Svikram 72566448Svikram sign = find_existing_sign("/", osdev, fstype); 72576448Svikram INJECT_ERROR1("GET_SET_KERNEL_SIGN", sign = NULL); 72586448Svikram if (sign == NULL) { 72596448Svikram free(fstype); 72606448Svikram free(osdev); 72616448Svikram bam_error(BOOTENV_SIGN_FAILED); 72626448Svikram rv = BAM_ERROR; 72636448Svikram goto done; 72646448Svikram } 72656448Svikram 72666448Svikram free(fstype); 72676448Svikram free(osdev); 72686448Svikram (void) strlcpy(signbuf, sign, sizeof (signbuf)); 72696448Svikram free(sign); 72706448Svikram assert(strchr(signbuf, '(') == NULL && 72716448Svikram strchr(signbuf, ',') == NULL && 72726448Svikram strchr(signbuf, ')') == NULL); 72736448Svikram 72743446Smrj if (optnum == KERNEL_CMD) { 72756448Svikram BAM_DPRINTF((D_GET_SET_KERNEL_NEW_KERN, fcn, new_path)); 72763446Smrj entryNum = add_boot_entry(mp, BOOTENV_RC_TITLE, 72776448Svikram signbuf, new_path, NULL, NULL); 72783446Smrj } else { 72793446Smrj new_str_len = strlen(DIRECT_BOOT_KERNEL) + 72803446Smrj strlen(path) + 8; 72813446Smrj new_arg = s_calloc(1, new_str_len); 72823446Smrj 72833446Smrj (void) snprintf(new_arg, new_str_len, "%s %s", 72843446Smrj DIRECT_BOOT_KERNEL, path); 72856448Svikram BAM_DPRINTF((D_GET_SET_KERNEL_NEW_ARG, fcn, new_arg)); 72863446Smrj entryNum = add_boot_entry(mp, BOOTENV_RC_TITLE, 72876448Svikram signbuf, new_arg, NULL, DIRECT_BOOT_ARCHIVE); 72886448Svikram free(new_arg); 72896448Svikram } 72906448Svikram INJECT_ERROR1("GET_SET_KERNEL_ADD_BOOT_ENTRY", 72916448Svikram entryNum = BAM_ERROR); 72926448Svikram if (entryNum == BAM_ERROR) { 72936448Svikram bam_error(GET_SET_KERNEL_ADD_BOOT_ENTRY, 72946448Svikram BOOTENV_RC_TITLE); 72956448Svikram rv = BAM_ERROR; 72966448Svikram goto done; 72973446Smrj } 72983446Smrj save_default_entry(mp, BAM_OLD_RC_DEF); 72996448Svikram ret = set_global(mp, menu_cmds[DEFAULT_CMD], entryNum); 73006448Svikram INJECT_ERROR1("GET_SET_KERNEL_SET_GLOBAL", ret = BAM_ERROR); 73016448Svikram if (ret == BAM_ERROR) { 73026448Svikram bam_error(GET_SET_KERNEL_SET_GLOBAL, entryNum); 73036448Svikram } 73043446Smrj rv = BAM_WRITE; 73053446Smrj goto done; 73063446Smrj } 73073446Smrj 73083446Smrj /* 73093446Smrj * There was already an bootenv entry which we need to edit. 73103446Smrj */ 73113446Smrj if (optnum == KERNEL_CMD) { 73123446Smrj new_str_len = strlen(new_path) + strlen(old_args) + 2; 73133446Smrj new_arg = s_calloc(1, new_str_len); 73143446Smrj (void) snprintf(new_arg, new_str_len, "%s %s", new_path, 73153446Smrj old_args); 73163446Smrj free(kernelp->arg); 73173446Smrj kernelp->arg = new_arg; 73183446Smrj 73193446Smrj /* 73203446Smrj * If we have changed the kernel line, we may need to update 73213446Smrj * the archive line as well. 73223446Smrj */ 73233446Smrj set_archive_line(entryp, kernelp); 73246448Svikram BAM_DPRINTF((D_GET_SET_KERNEL_REPLACED_KERNEL_SAME_ARG, fcn, 73256448Svikram kernelp->arg)); 73263446Smrj } else { 73273446Smrj new_str_len = old_kernel_len + strlen(path) + 8; 73283446Smrj new_arg = s_calloc(1, new_str_len); 73293446Smrj (void) strncpy(new_arg, kernelp->arg, old_kernel_len); 73303446Smrj (void) strlcat(new_arg, " ", new_str_len); 73313446Smrj (void) strlcat(new_arg, path, new_str_len); 73323446Smrj free(kernelp->arg); 73333446Smrj kernelp->arg = new_arg; 73346448Svikram BAM_DPRINTF((D_GET_SET_KERNEL_SAME_KERNEL_REPLACED_ARG, fcn, 73356448Svikram kernelp->arg)); 73363446Smrj } 73373446Smrj rv = BAM_WRITE; 73383446Smrj 73393446Smrj done: 73403446Smrj if ((rv == BAM_WRITE) && kernelp) 73413446Smrj update_line(kernelp); 73423446Smrj if (free_new_path) 73433446Smrj free(new_path); 73446448Svikram if (rv == BAM_WRITE) { 73456448Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 73466448Svikram } else { 73476448Svikram BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 73486448Svikram } 73493446Smrj return (rv); 73503446Smrj } 73513446Smrj 73526448Svikram static error_t 73536448Svikram get_kernel(menu_t *mp, menu_cmd_t optnum, char *buf, size_t bufsize) 73546448Svikram { 73556448Svikram const char *fcn = "get_kernel()"; 73566448Svikram BAM_DPRINTF((D_FUNC_ENTRY1, fcn, menu_cmds[optnum])); 73576448Svikram return (get_set_kernel(mp, optnum, NULL, buf, bufsize)); 73586448Svikram } 73596448Svikram 73606448Svikram static error_t 73616448Svikram set_kernel(menu_t *mp, menu_cmd_t optnum, char *path, char *buf, size_t bufsize) 73626448Svikram { 73636448Svikram const char *fcn = "set_kernel()"; 73646448Svikram assert(path != NULL); 73656448Svikram BAM_DPRINTF((D_FUNC_ENTRY2, fcn, menu_cmds[optnum], path)); 73666448Svikram return (get_set_kernel(mp, optnum, path, buf, bufsize)); 73676448Svikram } 73686448Svikram 73690Sstevel@tonic-gate /*ARGSUSED*/ 73700Sstevel@tonic-gate static error_t 73716448Svikram set_option(menu_t *mp, char *dummy, char *opt) 73726448Svikram { 73736448Svikram int optnum; 73746448Svikram int optval; 73756448Svikram char *val; 73766448Svikram char buf[BUFSIZ] = ""; 73776448Svikram error_t rv; 73786448Svikram const char *fcn = "set_option()"; 73790Sstevel@tonic-gate 73800Sstevel@tonic-gate assert(mp); 73810Sstevel@tonic-gate assert(opt); 73826448Svikram assert(dummy == NULL); 73836448Svikram 73846448Svikram /* opt is set from bam_argv[0] and is always non-NULL */ 73856448Svikram BAM_DPRINTF((D_FUNC_ENTRY1, fcn, opt)); 73860Sstevel@tonic-gate 73870Sstevel@tonic-gate val = strchr(opt, '='); 73883446Smrj if (val != NULL) { 73893446Smrj *val = '\0'; 73900Sstevel@tonic-gate } 73910Sstevel@tonic-gate 73920Sstevel@tonic-gate if (strcmp(opt, "default") == 0) { 73930Sstevel@tonic-gate optnum = DEFAULT_CMD; 73940Sstevel@tonic-gate } else if (strcmp(opt, "timeout") == 0) { 73950Sstevel@tonic-gate optnum = TIMEOUT_CMD; 73963446Smrj } else if (strcmp(opt, menu_cmds[KERNEL_CMD]) == 0) { 73973446Smrj optnum = KERNEL_CMD; 73983446Smrj } else if (strcmp(opt, menu_cmds[ARGS_CMD]) == 0) { 73993446Smrj optnum = ARGS_CMD; 74000Sstevel@tonic-gate } else { 74016448Svikram bam_error(INVALID_OPTION, opt); 74020Sstevel@tonic-gate return (BAM_ERROR); 74030Sstevel@tonic-gate } 74040Sstevel@tonic-gate 74053446Smrj /* 74063446Smrj * kernel and args are allowed without "=new_value" strings. All 74073446Smrj * others cause errors 74083446Smrj */ 74093446Smrj if ((val == NULL) && (optnum != KERNEL_CMD) && (optnum != ARGS_CMD)) { 74106448Svikram bam_error(NO_OPTION_ARG, opt); 74113446Smrj return (BAM_ERROR); 74123446Smrj } else if (val != NULL) { 74133446Smrj *val = '='; 74143446Smrj } 74153446Smrj 74163446Smrj if ((optnum == KERNEL_CMD) || (optnum == ARGS_CMD)) { 74176448Svikram BAM_DPRINTF((D_SET_OPTION, fcn, menu_cmds[optnum], 74186448Svikram val ? val + 1 : "NULL")); 74196448Svikram 74206448Svikram if (val) 74216448Svikram rv = set_kernel(mp, optnum, val + 1, buf, sizeof (buf)); 74226448Svikram else 74236448Svikram rv = get_kernel(mp, optnum, buf, sizeof (buf)); 74243446Smrj if ((rv == BAM_SUCCESS) && (buf[0] != '\0')) 74253446Smrj (void) printf("%s\n", buf); 74263446Smrj } else { 74273446Smrj optval = s_strtol(val + 1); 74286448Svikram BAM_DPRINTF((D_SET_OPTION, fcn, menu_cmds[optnum], val + 1)); 74296448Svikram rv = set_global(mp, menu_cmds[optnum], optval); 74306448Svikram } 74316448Svikram 74326448Svikram if (rv == BAM_WRITE || rv == BAM_SUCCESS) { 74336448Svikram BAM_DPRINTF((D_RETURN_SUCCESS, fcn)); 74346448Svikram } else { 74356448Svikram BAM_DPRINTF((D_RETURN_FAILURE, fcn)); 74366448Svikram } 74376448Svikram 74386448Svikram return (rv); 74390Sstevel@tonic-gate } 74400Sstevel@tonic-gate 74410Sstevel@tonic-gate /* 74420Sstevel@tonic-gate * The quiet argument suppresses messages. This is used 74430Sstevel@tonic-gate * when invoked in the context of other commands (e.g. list_entry) 74440Sstevel@tonic-gate */ 74450Sstevel@tonic-gate static error_t 74460Sstevel@tonic-gate read_globals(menu_t *mp, char *menu_path, char *globalcmd, int quiet) 74470Sstevel@tonic-gate { 74480Sstevel@tonic-gate line_t *lp; 74490Sstevel@tonic-gate char *arg; 74500Sstevel@tonic-gate int done, ret = BAM_SUCCESS; 74510Sstevel@tonic-gate 74520Sstevel@tonic-gate assert(mp); 74530Sstevel@tonic-gate assert(menu_path); 74540Sstevel@tonic-gate assert(globalcmd); 74550Sstevel@tonic-gate 74560Sstevel@tonic-gate if (mp->start == NULL) { 74570Sstevel@tonic-gate if (!quiet) 74580Sstevel@tonic-gate bam_error(NO_MENU, menu_path); 74590Sstevel@tonic-gate return (BAM_ERROR); 74600Sstevel@tonic-gate } 74610Sstevel@tonic-gate 74620Sstevel@tonic-gate done = 0; 74630Sstevel@tonic-gate for (lp = mp->start; lp; lp = lp->next) { 74640Sstevel@tonic-gate if (lp->flags != BAM_GLOBAL) 74650Sstevel@tonic-gate continue; 74660Sstevel@tonic-gate 74670Sstevel@tonic-gate if (lp->cmd == NULL) { 74680Sstevel@tonic-gate if (!quiet) 74690Sstevel@tonic-gate bam_error(NO_CMD, lp->lineNum); 74700Sstevel@tonic-gate continue; 74710Sstevel@tonic-gate } 74720Sstevel@tonic-gate 74730Sstevel@tonic-gate if (strcmp(globalcmd, lp->cmd) != 0) 74740Sstevel@tonic-gate continue; 74750Sstevel@tonic-gate 74760Sstevel@tonic-gate /* Found global. Check for duplicates */ 74770Sstevel@tonic-gate if (done && !quiet) { 74780Sstevel@tonic-gate bam_error(DUP_CMD, globalcmd, lp->lineNum, bam_root); 74790Sstevel@tonic-gate ret = BAM_ERROR; 74800Sstevel@tonic-gate } 74810Sstevel@tonic-gate 74820Sstevel@tonic-gate arg = lp->arg ? lp->arg : ""; 74830Sstevel@tonic-gate bam_print(GLOBAL_CMD, globalcmd, arg); 74840Sstevel@tonic-gate done = 1; 74850Sstevel@tonic-gate } 74860Sstevel@tonic-gate 74870Sstevel@tonic-gate if (!done && bam_verbose) 74880Sstevel@tonic-gate bam_print(NO_ENTRY, globalcmd); 74890Sstevel@tonic-gate 74900Sstevel@tonic-gate return (ret); 74910Sstevel@tonic-gate } 74920Sstevel@tonic-gate 74930Sstevel@tonic-gate static error_t 74940Sstevel@tonic-gate menu_write(char *root, menu_t *mp) 74950Sstevel@tonic-gate { 74966448Svikram const char *fcn = "menu_write()"; 74976448Svikram 74986448Svikram BAM_DPRINTF((D_MENU_WRITE_ENTER, fcn, root)); 74990Sstevel@tonic-gate return (list2file(root, MENU_TMP, GRUB_MENU, mp->start)); 75000Sstevel@tonic-gate } 75010Sstevel@tonic-gate 75026448Svikram void 75030Sstevel@tonic-gate line_free(line_t *lp) 75040Sstevel@tonic-gate { 75050Sstevel@tonic-gate if (lp == NULL) 75060Sstevel@tonic-gate return; 75070Sstevel@tonic-gate 75080Sstevel@tonic-gate if (lp->cmd) 75090Sstevel@tonic-gate free(lp->cmd); 75100Sstevel@tonic-gate if (lp->sep) 75110Sstevel@tonic-gate free(lp->sep); 75120Sstevel@tonic-gate if (lp->arg) 75130Sstevel@tonic-gate free(lp->arg); 75140Sstevel@tonic-gate if (lp->line) 75150Sstevel@tonic-gate free(lp->line); 75160Sstevel@tonic-gate free(lp); 75170Sstevel@tonic-gate } 75180Sstevel@tonic-gate 75190Sstevel@tonic-gate static void 75200Sstevel@tonic-gate linelist_free(line_t *start) 75210Sstevel@tonic-gate { 75220Sstevel@tonic-gate line_t *lp; 75230Sstevel@tonic-gate 75240Sstevel@tonic-gate while (start) { 75250Sstevel@tonic-gate lp = start; 75260Sstevel@tonic-gate start = start->next; 75270Sstevel@tonic-gate line_free(lp); 75280Sstevel@tonic-gate } 75290Sstevel@tonic-gate } 75300Sstevel@tonic-gate 75310Sstevel@tonic-gate static void 75320Sstevel@tonic-gate filelist_free(filelist_t *flistp) 75330Sstevel@tonic-gate { 75340Sstevel@tonic-gate linelist_free(flistp->head); 75350Sstevel@tonic-gate flistp->head = NULL; 75360Sstevel@tonic-gate flistp->tail = NULL; 75370Sstevel@tonic-gate } 75380Sstevel@tonic-gate 75390Sstevel@tonic-gate static void 75400Sstevel@tonic-gate menu_free(menu_t *mp) 75410Sstevel@tonic-gate { 7542662Sszhou entry_t *ent, *tmp; 75430Sstevel@tonic-gate assert(mp); 75440Sstevel@tonic-gate 75450Sstevel@tonic-gate if (mp->start) 75460Sstevel@tonic-gate linelist_free(mp->start); 7547662Sszhou ent = mp->entries; 7548662Sszhou while (ent) { 7549662Sszhou tmp = ent; 7550662Sszhou ent = tmp->next; 7551662Sszhou free(tmp); 7552662Sszhou } 7553662Sszhou 75540Sstevel@tonic-gate free(mp); 75550Sstevel@tonic-gate } 75560Sstevel@tonic-gate 75570Sstevel@tonic-gate /* 75580Sstevel@tonic-gate * Utility routines 75590Sstevel@tonic-gate */ 75600Sstevel@tonic-gate 75610Sstevel@tonic-gate 75620Sstevel@tonic-gate /* 75630Sstevel@tonic-gate * Returns 0 on success 75640Sstevel@tonic-gate * Any other value indicates an error 75650Sstevel@tonic-gate */ 75660Sstevel@tonic-gate static int 75675648Ssetje exec_cmd(char *cmdline, filelist_t *flistp) 75680Sstevel@tonic-gate { 75690Sstevel@tonic-gate char buf[BUFSIZ]; 75700Sstevel@tonic-gate int ret; 75710Sstevel@tonic-gate FILE *ptr; 75720Sstevel@tonic-gate sigset_t set; 75730Sstevel@tonic-gate void (*disp)(int); 75740Sstevel@tonic-gate 75750Sstevel@tonic-gate /* 75760Sstevel@tonic-gate * For security 75770Sstevel@tonic-gate * - only absolute paths are allowed 75780Sstevel@tonic-gate * - set IFS to space and tab 75790Sstevel@tonic-gate */ 75800Sstevel@tonic-gate if (*cmdline != '/') { 75810Sstevel@tonic-gate bam_error(ABS_PATH_REQ, cmdline); 75820Sstevel@tonic-gate return (-1); 75830Sstevel@tonic-gate } 75840Sstevel@tonic-gate (void) putenv("IFS= \t"); 75850Sstevel@tonic-gate 75860Sstevel@tonic-gate /* 75870Sstevel@tonic-gate * We may have been exec'ed with SIGCHLD blocked 75880Sstevel@tonic-gate * unblock it here 75890Sstevel@tonic-gate */ 75900Sstevel@tonic-gate (void) sigemptyset(&set); 75910Sstevel@tonic-gate (void) sigaddset(&set, SIGCHLD); 75920Sstevel@tonic-gate if (sigprocmask(SIG_UNBLOCK, &set, NULL) != 0) { 75930Sstevel@tonic-gate bam_error(CANT_UNBLOCK_SIGCHLD, strerror(errno)); 75940Sstevel@tonic-gate return (-1); 75950Sstevel@tonic-gate } 75960Sstevel@tonic-gate 75970Sstevel@tonic-gate /* 75980Sstevel@tonic-gate * Set SIGCHLD disposition to SIG_DFL for popen/pclose 75990Sstevel@tonic-gate */ 76000Sstevel@tonic-gate disp = sigset(SIGCHLD, SIG_DFL); 76010Sstevel@tonic-gate if (disp == SIG_ERR) { 76020Sstevel@tonic-gate bam_error(FAILED_SIG, strerror(errno)); 76030Sstevel@tonic-gate return (-1); 76040Sstevel@tonic-gate } 76050Sstevel@tonic-gate if (disp == SIG_HOLD) { 76060Sstevel@tonic-gate bam_error(BLOCKED_SIG, cmdline); 76070Sstevel@tonic-gate return (-1); 76080Sstevel@tonic-gate } 76090Sstevel@tonic-gate 76100Sstevel@tonic-gate ptr = popen(cmdline, "r"); 76110Sstevel@tonic-gate if (ptr == NULL) { 76120Sstevel@tonic-gate bam_error(POPEN_FAIL, cmdline, strerror(errno)); 76130Sstevel@tonic-gate return (-1); 76140Sstevel@tonic-gate } 76150Sstevel@tonic-gate 76160Sstevel@tonic-gate /* 76170Sstevel@tonic-gate * If we simply do a pclose() following a popen(), pclose() 76180Sstevel@tonic-gate * will close the reader end of the pipe immediately even 76190Sstevel@tonic-gate * if the child process has not started/exited. pclose() 76200Sstevel@tonic-gate * does wait for cmd to terminate before returning though. 76210Sstevel@tonic-gate * When the executed command writes its output to the pipe 76220Sstevel@tonic-gate * there is no reader process and the command dies with 76230Sstevel@tonic-gate * SIGPIPE. To avoid this we read repeatedly until read 76240Sstevel@tonic-gate * terminates with EOF. This indicates that the command 76250Sstevel@tonic-gate * (writer) has closed the pipe and we can safely do a 76260Sstevel@tonic-gate * pclose(). 76270Sstevel@tonic-gate * 76280Sstevel@tonic-gate * Since pclose() does wait for the command to exit, 76290Sstevel@tonic-gate * we can safely reap the exit status of the command 76300Sstevel@tonic-gate * from the value returned by pclose() 76310Sstevel@tonic-gate */ 76325648Ssetje while (s_fgets(buf, sizeof (buf), ptr) != NULL) { 76335648Ssetje if (flistp == NULL) { 76345648Ssetje /* s_fgets strips newlines, so insert them at the end */ 76355648Ssetje bam_print(PRINT, buf); 76365648Ssetje } else { 76375648Ssetje append_to_flist(flistp, buf); 76380Sstevel@tonic-gate } 76390Sstevel@tonic-gate } 76400Sstevel@tonic-gate 76410Sstevel@tonic-gate ret = pclose(ptr); 76420Sstevel@tonic-gate if (ret == -1) { 76430Sstevel@tonic-gate bam_error(PCLOSE_FAIL, cmdline, strerror(errno)); 76440Sstevel@tonic-gate return (-1); 76450Sstevel@tonic-gate } 76460Sstevel@tonic-gate 76470Sstevel@tonic-gate if (WIFEXITED(ret)) { 76480Sstevel@tonic-gate return (WEXITSTATUS(ret)); 76490Sstevel@tonic-gate } else { 76500Sstevel@tonic-gate bam_error(EXEC_FAIL, cmdline, ret); 76510Sstevel@tonic-gate return (-1); 76520Sstevel@tonic-gate } 76530Sstevel@tonic-gate } 76540Sstevel@tonic-gate 76550Sstevel@tonic-gate /* 76560Sstevel@tonic-gate * Since this function returns -1 on error 76570Sstevel@tonic-gate * it cannot be used to convert -1. However, 76580Sstevel@tonic-gate * that is sufficient for what we need. 76590Sstevel@tonic-gate */ 76600Sstevel@tonic-gate static long 76610Sstevel@tonic-gate s_strtol(char *str) 76620Sstevel@tonic-gate { 76630Sstevel@tonic-gate long l; 76640Sstevel@tonic-gate char *res = NULL; 76650Sstevel@tonic-gate 76660Sstevel@tonic-gate if (str == NULL) { 76670Sstevel@tonic-gate return (-1); 76680Sstevel@tonic-gate } 76690Sstevel@tonic-gate 76700Sstevel@tonic-gate errno = 0; 76710Sstevel@tonic-gate l = strtol(str, &res, 10); 76720Sstevel@tonic-gate if (errno || *res != '\0') { 76730Sstevel@tonic-gate return (-1); 76740Sstevel@tonic-gate } 76750Sstevel@tonic-gate 76760Sstevel@tonic-gate return (l); 76770Sstevel@tonic-gate } 76780Sstevel@tonic-gate 76790Sstevel@tonic-gate /* 76800Sstevel@tonic-gate * Wrapper around fputs, that adds a newline (since fputs doesn't) 76810Sstevel@tonic-gate */ 76820Sstevel@tonic-gate static int 76830Sstevel@tonic-gate s_fputs(char *str, FILE *fp) 76840Sstevel@tonic-gate { 76850Sstevel@tonic-gate char linebuf[BAM_MAXLINE]; 76860Sstevel@tonic-gate 76870Sstevel@tonic-gate (void) snprintf(linebuf, sizeof (linebuf), "%s\n", str); 76880Sstevel@tonic-gate return (fputs(linebuf, fp)); 76890Sstevel@tonic-gate } 76900Sstevel@tonic-gate 76910Sstevel@tonic-gate /* 76920Sstevel@tonic-gate * Wrapper around fgets, that strips newlines returned by fgets 76930Sstevel@tonic-gate */ 76943446Smrj char * 76950Sstevel@tonic-gate s_fgets(char *buf, int buflen, FILE *fp) 76960Sstevel@tonic-gate { 76970Sstevel@tonic-gate int n; 76980Sstevel@tonic-gate 76990Sstevel@tonic-gate buf = fgets(buf, buflen, fp); 77000Sstevel@tonic-gate if (buf) { 77010Sstevel@tonic-gate n = strlen(buf); 77020Sstevel@tonic-gate if (n == buflen - 1 && buf[n-1] != '\n') 77030Sstevel@tonic-gate bam_error(TOO_LONG, buflen - 1, buf); 77040Sstevel@tonic-gate buf[n-1] = (buf[n-1] == '\n') ? '\0' : buf[n-1]; 77050Sstevel@tonic-gate } 77060Sstevel@tonic-gate 77070Sstevel@tonic-gate return (buf); 77080Sstevel@tonic-gate } 77090Sstevel@tonic-gate 77103446Smrj void * 77110Sstevel@tonic-gate s_calloc(size_t nelem, size_t sz) 77120Sstevel@tonic-gate { 77130Sstevel@tonic-gate void *ptr; 77140Sstevel@tonic-gate 77150Sstevel@tonic-gate ptr = calloc(nelem, sz); 77160Sstevel@tonic-gate if (ptr == NULL) { 77170Sstevel@tonic-gate bam_error(NO_MEM, nelem*sz); 77180Sstevel@tonic-gate bam_exit(1); 77190Sstevel@tonic-gate } 77200Sstevel@tonic-gate return (ptr); 77210Sstevel@tonic-gate } 77220Sstevel@tonic-gate 77233446Smrj void * 77243446Smrj s_realloc(void *ptr, size_t sz) 77253446Smrj { 77263446Smrj ptr = realloc(ptr, sz); 77273446Smrj if (ptr == NULL) { 77283446Smrj bam_error(NO_MEM, sz); 77293446Smrj bam_exit(1); 77303446Smrj } 77313446Smrj return (ptr); 77323446Smrj } 77333446Smrj 77346448Svikram char * 77350Sstevel@tonic-gate s_strdup(char *str) 77360Sstevel@tonic-gate { 77370Sstevel@tonic-gate char *ptr; 77380Sstevel@tonic-gate 77390Sstevel@tonic-gate if (str == NULL) 77400Sstevel@tonic-gate return (NULL); 77410Sstevel@tonic-gate 77420Sstevel@tonic-gate ptr = strdup(str); 77430Sstevel@tonic-gate if (ptr == NULL) { 77440Sstevel@tonic-gate bam_error(NO_MEM, strlen(str) + 1); 77450Sstevel@tonic-gate bam_exit(1); 77460Sstevel@tonic-gate } 77470Sstevel@tonic-gate return (ptr); 77480Sstevel@tonic-gate } 77490Sstevel@tonic-gate 77500Sstevel@tonic-gate /* 77510Sstevel@tonic-gate * Returns 1 if amd64 (or sparc, for syncing x86 diskless clients) 77520Sstevel@tonic-gate * Returns 0 otherwise 77530Sstevel@tonic-gate */ 77540Sstevel@tonic-gate static int 77550Sstevel@tonic-gate is_amd64(void) 77560Sstevel@tonic-gate { 77570Sstevel@tonic-gate static int amd64 = -1; 77580Sstevel@tonic-gate char isabuf[257]; /* from sysinfo(2) manpage */ 77590Sstevel@tonic-gate 77600Sstevel@tonic-gate if (amd64 != -1) 77610Sstevel@tonic-gate return (amd64); 77620Sstevel@tonic-gate 77636319Sjg if (bam_alt_platform) { 77646319Sjg if (strcmp(bam_platform, "i86pc") == 0) { 77656319Sjg amd64 = 1; /* diskless server */ 77666319Sjg } 77676319Sjg } else { 77686319Sjg if (sysinfo(SI_ISALIST, isabuf, sizeof (isabuf)) > 0 && 77696319Sjg strncmp(isabuf, "amd64 ", strlen("amd64 ")) == 0) { 77706319Sjg amd64 = 1; 77716319Sjg } else if (strstr(isabuf, "i386") == NULL) { 77726319Sjg amd64 = 1; /* diskless server */ 77736319Sjg } 77746319Sjg } 77756319Sjg if (amd64 == -1) 77760Sstevel@tonic-gate amd64 = 0; 77770Sstevel@tonic-gate 77780Sstevel@tonic-gate return (amd64); 77790Sstevel@tonic-gate } 77800Sstevel@tonic-gate 77816582Ssetje static char * 77826582Ssetje get_machine(void) 77836582Ssetje { 77846582Ssetje static int cached = -1; 77856582Ssetje static char mbuf[257]; /* from sysinfo(2) manpage */ 77866582Ssetje 77876582Ssetje if (cached == 0) 77886582Ssetje return (mbuf); 77896319Sjg 77906319Sjg if (bam_alt_platform) { 77916582Ssetje return (bam_platform); 77926319Sjg } else { 77936582Ssetje if (sysinfo(SI_MACHINE, mbuf, sizeof (mbuf)) > 0) { 77946582Ssetje cached = 1; 77956582Ssetje } 77966582Ssetje } 77976582Ssetje if (cached == -1) { 77986582Ssetje mbuf[0] = '\0'; 77996582Ssetje cached = 0; 78006582Ssetje } 78016582Ssetje 78026582Ssetje return (mbuf); 78035648Ssetje } 78045648Ssetje 78056448Svikram int 78066448Svikram is_sparc(void) 78076448Svikram { 78086582Ssetje static int issparc = -1; 78096582Ssetje char mbuf[257]; /* from sysinfo(2) manpage */ 78106582Ssetje 78116582Ssetje if (issparc != -1) 78126582Ssetje return (issparc); 78136582Ssetje 78146582Ssetje if (bam_alt_platform) { 78156582Ssetje if (strncmp(bam_platform, "sun4", 4) == 0) { 78166582Ssetje issparc = 1; 78176582Ssetje } 78186582Ssetje } else { 78196582Ssetje if (sysinfo(SI_ARCHITECTURE, mbuf, sizeof (mbuf)) > 0 && 7820*7111Sjg strcmp(mbuf, "sparc") == 0) { 78216582Ssetje issparc = 1; 7822*7111Sjg } 7823*7111Sjg } 7824*7111Sjg if (issparc == -1) 7825*7111Sjg issparc = 0; 78266582Ssetje 78276582Ssetje return (issparc); 78286448Svikram } 78295648Ssetje 78300Sstevel@tonic-gate static void 78310Sstevel@tonic-gate append_to_flist(filelist_t *flistp, char *s) 78320Sstevel@tonic-gate { 78330Sstevel@tonic-gate line_t *lp; 78340Sstevel@tonic-gate 78350Sstevel@tonic-gate lp = s_calloc(1, sizeof (line_t)); 78360Sstevel@tonic-gate lp->line = s_strdup(s); 78370Sstevel@tonic-gate if (flistp->head == NULL) 78380Sstevel@tonic-gate flistp->head = lp; 78390Sstevel@tonic-gate else 78400Sstevel@tonic-gate flistp->tail->next = lp; 78410Sstevel@tonic-gate flistp->tail = lp; 78420Sstevel@tonic-gate } 78434581Ssherrym 78445648Ssetje #if !defined(_OPB) 78454581Ssherrym 78464581Ssherrym UCODE_VENDORS; 78474581Ssherrym 78484581Ssherrym /*ARGSUSED*/ 78494581Ssherrym static void 78504581Ssherrym ucode_install(char *root) 78514581Ssherrym { 78524581Ssherrym int i; 78534581Ssherrym 78544581Ssherrym for (i = 0; ucode_vendors[i].filestr != NULL; i++) { 78554581Ssherrym int cmd_len = PATH_MAX + 256; 78564581Ssherrym char cmd[PATH_MAX + 256]; 78574581Ssherrym char file[PATH_MAX]; 78584581Ssherrym char timestamp[PATH_MAX]; 78594581Ssherrym struct stat fstatus, tstatus; 78604581Ssherrym struct utimbuf u_times; 78614581Ssherrym 78624581Ssherrym (void) snprintf(file, PATH_MAX, "%s/%s/%s-ucode.txt", 78634581Ssherrym bam_root, UCODE_INSTALL_PATH, ucode_vendors[i].filestr); 78644581Ssherrym 78654581Ssherrym if (stat(file, &fstatus) != 0 || !(S_ISREG(fstatus.st_mode))) 78664581Ssherrym continue; 78674581Ssherrym 78684581Ssherrym (void) snprintf(timestamp, PATH_MAX, "%s.ts", file); 78694581Ssherrym 78704581Ssherrym if (stat(timestamp, &tstatus) == 0 && 78714581Ssherrym fstatus.st_mtime <= tstatus.st_mtime) 78724581Ssherrym continue; 78734581Ssherrym 78744581Ssherrym (void) snprintf(cmd, cmd_len, "/usr/sbin/ucodeadm -i -R " 78754581Ssherrym "%s/%s/%s %s > /dev/null 2>&1", bam_root, 78764581Ssherrym UCODE_INSTALL_PATH, ucode_vendors[i].vendorstr, file); 78774581Ssherrym if (system(cmd) != 0) 78784581Ssherrym return; 78794581Ssherrym 78804581Ssherrym if (creat(timestamp, S_IRUSR | S_IWUSR) == -1) 78814581Ssherrym return; 78824581Ssherrym 78834581Ssherrym u_times.actime = fstatus.st_atime; 78844581Ssherrym u_times.modtime = fstatus.st_mtime; 78854581Ssherrym (void) utime(timestamp, &u_times); 78864581Ssherrym } 78874581Ssherrym } 78884581Ssherrym #endif 7889