1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate /* 30*7c478bd9Sstevel@tonic-gate * bootadm(1M) is a new utility for managing bootability of 31*7c478bd9Sstevel@tonic-gate * Solaris *Newboot* environments. It has two primary tasks: 32*7c478bd9Sstevel@tonic-gate * - Allow end users to manage bootability of Newboot Solaris instances 33*7c478bd9Sstevel@tonic-gate * - Provide services to other subsystems in Solaris (primarily Install) 34*7c478bd9Sstevel@tonic-gate */ 35*7c478bd9Sstevel@tonic-gate 36*7c478bd9Sstevel@tonic-gate /* Headers */ 37*7c478bd9Sstevel@tonic-gate #include <stdio.h> 38*7c478bd9Sstevel@tonic-gate #include <errno.h> 39*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 40*7c478bd9Sstevel@tonic-gate #include <string.h> 41*7c478bd9Sstevel@tonic-gate #include <unistd.h> 42*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 43*7c478bd9Sstevel@tonic-gate #include <sys/stat.h> 44*7c478bd9Sstevel@tonic-gate #include <stdarg.h> 45*7c478bd9Sstevel@tonic-gate #include <limits.h> 46*7c478bd9Sstevel@tonic-gate #include <signal.h> 47*7c478bd9Sstevel@tonic-gate #include <sys/wait.h> 48*7c478bd9Sstevel@tonic-gate #include <sys/mnttab.h> 49*7c478bd9Sstevel@tonic-gate #include <sys/statvfs.h> 50*7c478bd9Sstevel@tonic-gate #include <libnvpair.h> 51*7c478bd9Sstevel@tonic-gate #include <ftw.h> 52*7c478bd9Sstevel@tonic-gate #include <fcntl.h> 53*7c478bd9Sstevel@tonic-gate #include <strings.h> 54*7c478bd9Sstevel@tonic-gate #include <sys/systeminfo.h> 55*7c478bd9Sstevel@tonic-gate #include <sys/dktp/fdisk.h> 56*7c478bd9Sstevel@tonic-gate 57*7c478bd9Sstevel@tonic-gate #include <pwd.h> 58*7c478bd9Sstevel@tonic-gate #include <grp.h> 59*7c478bd9Sstevel@tonic-gate #include <device_info.h> 60*7c478bd9Sstevel@tonic-gate 61*7c478bd9Sstevel@tonic-gate #include <libintl.h> 62*7c478bd9Sstevel@tonic-gate #include <locale.h> 63*7c478bd9Sstevel@tonic-gate 64*7c478bd9Sstevel@tonic-gate #include <assert.h> 65*7c478bd9Sstevel@tonic-gate 66*7c478bd9Sstevel@tonic-gate #include "message.h" 67*7c478bd9Sstevel@tonic-gate 68*7c478bd9Sstevel@tonic-gate #ifndef TEXT_DOMAIN 69*7c478bd9Sstevel@tonic-gate #define TEXT_DOMAIN "SUNW_OST_OSCMD" 70*7c478bd9Sstevel@tonic-gate #endif /* TEXT_DOMAIN */ 71*7c478bd9Sstevel@tonic-gate 72*7c478bd9Sstevel@tonic-gate /* Type definitions */ 73*7c478bd9Sstevel@tonic-gate 74*7c478bd9Sstevel@tonic-gate /* Primary subcmds */ 75*7c478bd9Sstevel@tonic-gate typedef enum { 76*7c478bd9Sstevel@tonic-gate BAM_MENU = 3, 77*7c478bd9Sstevel@tonic-gate BAM_ARCHIVE 78*7c478bd9Sstevel@tonic-gate } subcmd_t; 79*7c478bd9Sstevel@tonic-gate 80*7c478bd9Sstevel@tonic-gate /* GRUB menu per-line classification */ 81*7c478bd9Sstevel@tonic-gate typedef enum { 82*7c478bd9Sstevel@tonic-gate BAM_INVALID = 0, 83*7c478bd9Sstevel@tonic-gate BAM_EMPTY, 84*7c478bd9Sstevel@tonic-gate BAM_COMMENT, 85*7c478bd9Sstevel@tonic-gate BAM_GLOBAL, 86*7c478bd9Sstevel@tonic-gate BAM_ENTRY, 87*7c478bd9Sstevel@tonic-gate BAM_TITLE 88*7c478bd9Sstevel@tonic-gate } menu_flag_t; 89*7c478bd9Sstevel@tonic-gate 90*7c478bd9Sstevel@tonic-gate /* struct for menu.lst contents */ 91*7c478bd9Sstevel@tonic-gate typedef struct line { 92*7c478bd9Sstevel@tonic-gate int lineNum; /* Line number in menu.lst */ 93*7c478bd9Sstevel@tonic-gate int entryNum; /* menu boot entry #. ENTRY_INIT if not applicable */ 94*7c478bd9Sstevel@tonic-gate char *cmd; 95*7c478bd9Sstevel@tonic-gate char *sep; 96*7c478bd9Sstevel@tonic-gate char *arg; 97*7c478bd9Sstevel@tonic-gate char *line; 98*7c478bd9Sstevel@tonic-gate menu_flag_t flags; 99*7c478bd9Sstevel@tonic-gate struct line *next; 100*7c478bd9Sstevel@tonic-gate } line_t; 101*7c478bd9Sstevel@tonic-gate 102*7c478bd9Sstevel@tonic-gate typedef struct { 103*7c478bd9Sstevel@tonic-gate line_t *start; 104*7c478bd9Sstevel@tonic-gate line_t *end; 105*7c478bd9Sstevel@tonic-gate } menu_t; 106*7c478bd9Sstevel@tonic-gate 107*7c478bd9Sstevel@tonic-gate typedef enum { 108*7c478bd9Sstevel@tonic-gate OPT_ABSENT = 0, /* No option */ 109*7c478bd9Sstevel@tonic-gate OPT_REQ, /* option required */ 110*7c478bd9Sstevel@tonic-gate OPT_OPTIONAL /* option may or may not be present */ 111*7c478bd9Sstevel@tonic-gate } option_t; 112*7c478bd9Sstevel@tonic-gate 113*7c478bd9Sstevel@tonic-gate typedef enum { 114*7c478bd9Sstevel@tonic-gate BAM_ERROR = -1, 115*7c478bd9Sstevel@tonic-gate BAM_SUCCESS = 0, 116*7c478bd9Sstevel@tonic-gate BAM_WRITE = 2 117*7c478bd9Sstevel@tonic-gate } error_t; 118*7c478bd9Sstevel@tonic-gate 119*7c478bd9Sstevel@tonic-gate typedef struct { 120*7c478bd9Sstevel@tonic-gate char *subcmd; 121*7c478bd9Sstevel@tonic-gate option_t option; 122*7c478bd9Sstevel@tonic-gate error_t (*handler)(); 123*7c478bd9Sstevel@tonic-gate } subcmd_defn_t; 124*7c478bd9Sstevel@tonic-gate 125*7c478bd9Sstevel@tonic-gate 126*7c478bd9Sstevel@tonic-gate #define BAM_MAXLINE 8192 127*7c478bd9Sstevel@tonic-gate 128*7c478bd9Sstevel@tonic-gate #define LINE_INIT 0 /* lineNum initial value */ 129*7c478bd9Sstevel@tonic-gate #define ENTRY_INIT -1 /* entryNum initial value */ 130*7c478bd9Sstevel@tonic-gate #define ALL_ENTRIES -2 /* selects all boot entries */ 131*7c478bd9Sstevel@tonic-gate 132*7c478bd9Sstevel@tonic-gate #define GRUB_DIR "/boot/grub" 133*7c478bd9Sstevel@tonic-gate #define MULTI_BOOT "/platform/i86pc/multiboot" 134*7c478bd9Sstevel@tonic-gate #define BOOT_ARCHIVE "/platform/i86pc/boot_archive" 135*7c478bd9Sstevel@tonic-gate #define GRUB_MENU "/boot/grub/menu.lst" 136*7c478bd9Sstevel@tonic-gate #define MENU_TMP "/boot/grub/menu.lst.tmp" 137*7c478bd9Sstevel@tonic-gate #define RAMDISK_SPECIAL "/ramdisk" 138*7c478bd9Sstevel@tonic-gate 139*7c478bd9Sstevel@tonic-gate /* lock related */ 140*7c478bd9Sstevel@tonic-gate #define BAM_LOCK_FILE "/var/run/bootadm.lock" 141*7c478bd9Sstevel@tonic-gate #define LOCK_FILE_PERMS (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) 142*7c478bd9Sstevel@tonic-gate 143*7c478bd9Sstevel@tonic-gate #define CREATE_RAMDISK "/boot/solaris/bin/create_ramdisk" 144*7c478bd9Sstevel@tonic-gate #define CREATE_DISKMAP "/boot/solaris/bin/create_diskmap" 145*7c478bd9Sstevel@tonic-gate #define GRUBDISK_MAP "/var/run/solaris_grubdisk.map" 146*7c478bd9Sstevel@tonic-gate 147*7c478bd9Sstevel@tonic-gate /* 148*7c478bd9Sstevel@tonic-gate * Default file attributes 149*7c478bd9Sstevel@tonic-gate */ 150*7c478bd9Sstevel@tonic-gate #define DEFAULT_DEV_MODE 0644 /* default permissions */ 151*7c478bd9Sstevel@tonic-gate #define DEFAULT_DEV_UID 0 /* user root */ 152*7c478bd9Sstevel@tonic-gate #define DEFAULT_DEV_GID 3 /* group sys */ 153*7c478bd9Sstevel@tonic-gate 154*7c478bd9Sstevel@tonic-gate /* 155*7c478bd9Sstevel@tonic-gate * Menu related 156*7c478bd9Sstevel@tonic-gate * menu_cmd_t and menu_cmds must be kept in sync 157*7c478bd9Sstevel@tonic-gate */ 158*7c478bd9Sstevel@tonic-gate typedef enum { 159*7c478bd9Sstevel@tonic-gate DEFAULT_CMD = 0, 160*7c478bd9Sstevel@tonic-gate TIMEOUT_CMD, 161*7c478bd9Sstevel@tonic-gate TITLE_CMD, 162*7c478bd9Sstevel@tonic-gate ROOT_CMD, 163*7c478bd9Sstevel@tonic-gate KERNEL_CMD, 164*7c478bd9Sstevel@tonic-gate MODULE_CMD, 165*7c478bd9Sstevel@tonic-gate SEP_CMD, 166*7c478bd9Sstevel@tonic-gate COMMENT_CMD 167*7c478bd9Sstevel@tonic-gate } menu_cmd_t; 168*7c478bd9Sstevel@tonic-gate 169*7c478bd9Sstevel@tonic-gate static char *menu_cmds[] = { 170*7c478bd9Sstevel@tonic-gate "default", /* DEFAULT_CMD */ 171*7c478bd9Sstevel@tonic-gate "timeout", /* TIMEOUT_CMD */ 172*7c478bd9Sstevel@tonic-gate "title", /* TITLE_CMD */ 173*7c478bd9Sstevel@tonic-gate "root", /* ROOT_CMD */ 174*7c478bd9Sstevel@tonic-gate "kernel", /* KERNEL_CMD */ 175*7c478bd9Sstevel@tonic-gate "module", /* MODULE_CMD */ 176*7c478bd9Sstevel@tonic-gate " ", /* SEP_CMD */ 177*7c478bd9Sstevel@tonic-gate "#", /* COMMENT_CMD */ 178*7c478bd9Sstevel@tonic-gate NULL 179*7c478bd9Sstevel@tonic-gate }; 180*7c478bd9Sstevel@tonic-gate 181*7c478bd9Sstevel@tonic-gate #define OPT_ENTRY_NUM "entry" 182*7c478bd9Sstevel@tonic-gate 183*7c478bd9Sstevel@tonic-gate /* 184*7c478bd9Sstevel@tonic-gate * archive related 185*7c478bd9Sstevel@tonic-gate */ 186*7c478bd9Sstevel@tonic-gate typedef struct { 187*7c478bd9Sstevel@tonic-gate line_t *head; 188*7c478bd9Sstevel@tonic-gate line_t *tail; 189*7c478bd9Sstevel@tonic-gate } filelist_t; 190*7c478bd9Sstevel@tonic-gate 191*7c478bd9Sstevel@tonic-gate #define BOOT_FILE_LIST "boot/solaris/filelist.ramdisk" 192*7c478bd9Sstevel@tonic-gate #define ETC_FILE_LIST "etc/boot/solaris/filelist.ramdisk" 193*7c478bd9Sstevel@tonic-gate 194*7c478bd9Sstevel@tonic-gate #define FILE_STAT "boot/solaris/filestat.ramdisk" 195*7c478bd9Sstevel@tonic-gate #define FILE_STAT_TMP "boot/solaris/filestat.ramdisk.tmp" 196*7c478bd9Sstevel@tonic-gate #define DIR_PERMS (S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) 197*7c478bd9Sstevel@tonic-gate #define FILE_STAT_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) 198*7c478bd9Sstevel@tonic-gate 199*7c478bd9Sstevel@tonic-gate #define BAM_HDR "---------- ADDED BY BOOTADM - DO NOT EDIT ----------" 200*7c478bd9Sstevel@tonic-gate #define BAM_FTR "---------------------END BOOTADM--------------------" 201*7c478bd9Sstevel@tonic-gate 202*7c478bd9Sstevel@tonic-gate 203*7c478bd9Sstevel@tonic-gate /* Globals */ 204*7c478bd9Sstevel@tonic-gate static char *prog; 205*7c478bd9Sstevel@tonic-gate static subcmd_t bam_cmd; 206*7c478bd9Sstevel@tonic-gate static char *bam_root; 207*7c478bd9Sstevel@tonic-gate static int bam_rootlen; 208*7c478bd9Sstevel@tonic-gate static int bam_root_readonly; 209*7c478bd9Sstevel@tonic-gate static char *bam_subcmd; 210*7c478bd9Sstevel@tonic-gate static char *bam_opt; 211*7c478bd9Sstevel@tonic-gate static int bam_debug; 212*7c478bd9Sstevel@tonic-gate static char **bam_argv; 213*7c478bd9Sstevel@tonic-gate static int bam_argc; 214*7c478bd9Sstevel@tonic-gate static int bam_force; 215*7c478bd9Sstevel@tonic-gate static int bam_verbose; 216*7c478bd9Sstevel@tonic-gate static int bam_check; 217*7c478bd9Sstevel@tonic-gate static int bam_smf_check; 218*7c478bd9Sstevel@tonic-gate static int bam_lock_fd = -1; 219*7c478bd9Sstevel@tonic-gate static char rootbuf[PATH_MAX] = "/"; 220*7c478bd9Sstevel@tonic-gate 221*7c478bd9Sstevel@tonic-gate /* function prototypes */ 222*7c478bd9Sstevel@tonic-gate static void parse_args_internal(int argc, char *argv[]); 223*7c478bd9Sstevel@tonic-gate static void parse_args(int argc, char *argv[]); 224*7c478bd9Sstevel@tonic-gate static error_t bam_menu(char *subcmd, char *opt, int argc, char *argv[]); 225*7c478bd9Sstevel@tonic-gate static error_t bam_archive(char *subcmd, char *opt); 226*7c478bd9Sstevel@tonic-gate 227*7c478bd9Sstevel@tonic-gate static void bam_error(char *format, ...); 228*7c478bd9Sstevel@tonic-gate static void bam_print(char *format, ...); 229*7c478bd9Sstevel@tonic-gate static void bam_exit(int excode); 230*7c478bd9Sstevel@tonic-gate static void bam_lock(void); 231*7c478bd9Sstevel@tonic-gate static void bam_unlock(void); 232*7c478bd9Sstevel@tonic-gate 233*7c478bd9Sstevel@tonic-gate static int exec_cmd(char *cmdline, char *output, int64_t osize); 234*7c478bd9Sstevel@tonic-gate static error_t read_globals(menu_t *mp, char *menu_path, 235*7c478bd9Sstevel@tonic-gate char *globalcmd, int quiet); 236*7c478bd9Sstevel@tonic-gate 237*7c478bd9Sstevel@tonic-gate static menu_t *menu_read(char *menu_path); 238*7c478bd9Sstevel@tonic-gate static error_t menu_write(char *root, menu_t *mp); 239*7c478bd9Sstevel@tonic-gate static void linelist_free(line_t *start); 240*7c478bd9Sstevel@tonic-gate static void menu_free(menu_t *mp); 241*7c478bd9Sstevel@tonic-gate static void line_free(line_t *lp); 242*7c478bd9Sstevel@tonic-gate static void filelist_free(filelist_t *flistp); 243*7c478bd9Sstevel@tonic-gate static error_t list2file(char *root, char *tmp, 244*7c478bd9Sstevel@tonic-gate char *final, line_t *start); 245*7c478bd9Sstevel@tonic-gate static error_t list_entry(menu_t *mp, char *menu_path, char *opt); 246*7c478bd9Sstevel@tonic-gate static error_t delete_entry(menu_t *mp, char *menu_path, char *opt); 247*7c478bd9Sstevel@tonic-gate static error_t delete_all_entries(menu_t *mp, char *menu_path, char *opt); 248*7c478bd9Sstevel@tonic-gate static error_t update_entry(menu_t *mp, char *root, char *opt); 249*7c478bd9Sstevel@tonic-gate static error_t update_temp(menu_t *mp, char *root, char *opt); 250*7c478bd9Sstevel@tonic-gate 251*7c478bd9Sstevel@tonic-gate static error_t update_archive(char *root, char *opt); 252*7c478bd9Sstevel@tonic-gate static error_t list_archive(char *root, char *opt); 253*7c478bd9Sstevel@tonic-gate static error_t update_all(char *root, char *opt); 254*7c478bd9Sstevel@tonic-gate static error_t read_list(char *root, filelist_t *flistp); 255*7c478bd9Sstevel@tonic-gate static error_t set_global(menu_t *mp, char *globalcmd, int val); 256*7c478bd9Sstevel@tonic-gate static error_t set_option(menu_t *mp, char *globalcmd, char *opt); 257*7c478bd9Sstevel@tonic-gate 258*7c478bd9Sstevel@tonic-gate static long s_strtol(char *str); 259*7c478bd9Sstevel@tonic-gate static char *s_fgets(char *buf, int n, FILE *fp); 260*7c478bd9Sstevel@tonic-gate static int s_fputs(char *str, FILE *fp); 261*7c478bd9Sstevel@tonic-gate 262*7c478bd9Sstevel@tonic-gate static void *s_calloc(size_t nelem, size_t sz); 263*7c478bd9Sstevel@tonic-gate static char *s_strdup(char *str); 264*7c478bd9Sstevel@tonic-gate static int is_readonly(char *); 265*7c478bd9Sstevel@tonic-gate static int is_amd64(void); 266*7c478bd9Sstevel@tonic-gate static void append_to_flist(filelist_t *, char *); 267*7c478bd9Sstevel@tonic-gate 268*7c478bd9Sstevel@tonic-gate #if defined(__sparc) 269*7c478bd9Sstevel@tonic-gate static void sparc_abort(void); 270*7c478bd9Sstevel@tonic-gate #endif 271*7c478bd9Sstevel@tonic-gate 272*7c478bd9Sstevel@tonic-gate /* Menu related sub commands */ 273*7c478bd9Sstevel@tonic-gate static subcmd_defn_t menu_subcmds[] = { 274*7c478bd9Sstevel@tonic-gate "set_option", OPT_OPTIONAL, set_option, /* PUB */ 275*7c478bd9Sstevel@tonic-gate "list_entry", OPT_OPTIONAL, list_entry, /* PUB */ 276*7c478bd9Sstevel@tonic-gate "delete_all_entries", OPT_ABSENT, delete_all_entries, /* PVT */ 277*7c478bd9Sstevel@tonic-gate "update_entry", OPT_REQ, update_entry, /* menu */ 278*7c478bd9Sstevel@tonic-gate "update_temp", OPT_OPTIONAL, update_temp, /* reboot */ 279*7c478bd9Sstevel@tonic-gate NULL, 0, NULL /* must be last */ 280*7c478bd9Sstevel@tonic-gate }; 281*7c478bd9Sstevel@tonic-gate 282*7c478bd9Sstevel@tonic-gate /* Archive related sub commands */ 283*7c478bd9Sstevel@tonic-gate static subcmd_defn_t arch_subcmds[] = { 284*7c478bd9Sstevel@tonic-gate "update", OPT_ABSENT, update_archive, /* PUB */ 285*7c478bd9Sstevel@tonic-gate "update_all", OPT_ABSENT, update_all, /* PVT */ 286*7c478bd9Sstevel@tonic-gate "list", OPT_OPTIONAL, list_archive, /* PUB */ 287*7c478bd9Sstevel@tonic-gate NULL, 0, NULL /* must be last */ 288*7c478bd9Sstevel@tonic-gate }; 289*7c478bd9Sstevel@tonic-gate 290*7c478bd9Sstevel@tonic-gate static struct { 291*7c478bd9Sstevel@tonic-gate nvlist_t *new_nvlp; 292*7c478bd9Sstevel@tonic-gate nvlist_t *old_nvlp; 293*7c478bd9Sstevel@tonic-gate int need_update; 294*7c478bd9Sstevel@tonic-gate } walk_arg; 295*7c478bd9Sstevel@tonic-gate 296*7c478bd9Sstevel@tonic-gate static void 297*7c478bd9Sstevel@tonic-gate usage(void) 298*7c478bd9Sstevel@tonic-gate { 299*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "USAGE:\n"); 300*7c478bd9Sstevel@tonic-gate 301*7c478bd9Sstevel@tonic-gate 302*7c478bd9Sstevel@tonic-gate /* archive usage */ 303*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "\t%s update-archive [-vn] [-R altroot]\n", 304*7c478bd9Sstevel@tonic-gate prog); 305*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "\t%s list-archive [-R altroot]\n", prog); 306*7c478bd9Sstevel@tonic-gate #ifndef __sparc 307*7c478bd9Sstevel@tonic-gate /* x86 only */ 308*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "\t%s set-menu [-R altroot] key=value\n", prog); 309*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "\t%s list-menu [-R altroot]\n", prog); 310*7c478bd9Sstevel@tonic-gate #endif 311*7c478bd9Sstevel@tonic-gate } 312*7c478bd9Sstevel@tonic-gate 313*7c478bd9Sstevel@tonic-gate int 314*7c478bd9Sstevel@tonic-gate main(int argc, char *argv[]) 315*7c478bd9Sstevel@tonic-gate { 316*7c478bd9Sstevel@tonic-gate error_t ret; 317*7c478bd9Sstevel@tonic-gate 318*7c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 319*7c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 320*7c478bd9Sstevel@tonic-gate 321*7c478bd9Sstevel@tonic-gate if ((prog = strrchr(argv[0], '/')) == NULL) { 322*7c478bd9Sstevel@tonic-gate prog = argv[0]; 323*7c478bd9Sstevel@tonic-gate } else { 324*7c478bd9Sstevel@tonic-gate prog++; 325*7c478bd9Sstevel@tonic-gate } 326*7c478bd9Sstevel@tonic-gate 327*7c478bd9Sstevel@tonic-gate if (geteuid() != 0) { 328*7c478bd9Sstevel@tonic-gate bam_error(MUST_BE_ROOT); 329*7c478bd9Sstevel@tonic-gate bam_exit(1); 330*7c478bd9Sstevel@tonic-gate } 331*7c478bd9Sstevel@tonic-gate 332*7c478bd9Sstevel@tonic-gate bam_lock(); 333*7c478bd9Sstevel@tonic-gate 334*7c478bd9Sstevel@tonic-gate /* 335*7c478bd9Sstevel@tonic-gate * Don't depend on caller's umask 336*7c478bd9Sstevel@tonic-gate */ 337*7c478bd9Sstevel@tonic-gate (void) umask(0022); 338*7c478bd9Sstevel@tonic-gate 339*7c478bd9Sstevel@tonic-gate parse_args(argc, argv); 340*7c478bd9Sstevel@tonic-gate 341*7c478bd9Sstevel@tonic-gate #if defined(__sparc) 342*7c478bd9Sstevel@tonic-gate /* 343*7c478bd9Sstevel@tonic-gate * There are only two valid invocations of bootadm 344*7c478bd9Sstevel@tonic-gate * on SPARC: 345*7c478bd9Sstevel@tonic-gate * 346*7c478bd9Sstevel@tonic-gate * - SPARC diskless server creating boot_archive for i386 clients 347*7c478bd9Sstevel@tonic-gate * - archive creation call during reboot of a SPARC system 348*7c478bd9Sstevel@tonic-gate * 349*7c478bd9Sstevel@tonic-gate * The latter should be a NOP 350*7c478bd9Sstevel@tonic-gate */ 351*7c478bd9Sstevel@tonic-gate if (bam_cmd != BAM_ARCHIVE) { 352*7c478bd9Sstevel@tonic-gate sparc_abort(); 353*7c478bd9Sstevel@tonic-gate } 354*7c478bd9Sstevel@tonic-gate #endif 355*7c478bd9Sstevel@tonic-gate 356*7c478bd9Sstevel@tonic-gate switch (bam_cmd) { 357*7c478bd9Sstevel@tonic-gate case BAM_MENU: 358*7c478bd9Sstevel@tonic-gate ret = bam_menu(bam_subcmd, bam_opt, bam_argc, bam_argv); 359*7c478bd9Sstevel@tonic-gate break; 360*7c478bd9Sstevel@tonic-gate case BAM_ARCHIVE: 361*7c478bd9Sstevel@tonic-gate ret = bam_archive(bam_subcmd, bam_opt); 362*7c478bd9Sstevel@tonic-gate break; 363*7c478bd9Sstevel@tonic-gate default: 364*7c478bd9Sstevel@tonic-gate usage(); 365*7c478bd9Sstevel@tonic-gate bam_exit(1); 366*7c478bd9Sstevel@tonic-gate } 367*7c478bd9Sstevel@tonic-gate 368*7c478bd9Sstevel@tonic-gate if (ret != BAM_SUCCESS) 369*7c478bd9Sstevel@tonic-gate bam_exit(1); 370*7c478bd9Sstevel@tonic-gate 371*7c478bd9Sstevel@tonic-gate bam_unlock(); 372*7c478bd9Sstevel@tonic-gate return (0); 373*7c478bd9Sstevel@tonic-gate } 374*7c478bd9Sstevel@tonic-gate 375*7c478bd9Sstevel@tonic-gate #if defined(__sparc) 376*7c478bd9Sstevel@tonic-gate 377*7c478bd9Sstevel@tonic-gate static void 378*7c478bd9Sstevel@tonic-gate sparc_abort(void) 379*7c478bd9Sstevel@tonic-gate { 380*7c478bd9Sstevel@tonic-gate bam_error(NOT_ON_SPARC); 381*7c478bd9Sstevel@tonic-gate bam_exit(1); 382*7c478bd9Sstevel@tonic-gate } 383*7c478bd9Sstevel@tonic-gate 384*7c478bd9Sstevel@tonic-gate #endif 385*7c478bd9Sstevel@tonic-gate 386*7c478bd9Sstevel@tonic-gate /* 387*7c478bd9Sstevel@tonic-gate * Equivalence of public and internal commands: 388*7c478bd9Sstevel@tonic-gate * update-archive -- -a update 389*7c478bd9Sstevel@tonic-gate * list-archive -- -a list 390*7c478bd9Sstevel@tonic-gate * set-menu -- -m set_option 391*7c478bd9Sstevel@tonic-gate * list-menu -- -m list_entry 392*7c478bd9Sstevel@tonic-gate * update-menu -- -m update_entry 393*7c478bd9Sstevel@tonic-gate */ 394*7c478bd9Sstevel@tonic-gate static struct cmd_map { 395*7c478bd9Sstevel@tonic-gate char *bam_cmdname; 396*7c478bd9Sstevel@tonic-gate int bam_cmd; 397*7c478bd9Sstevel@tonic-gate char *bam_subcmd; 398*7c478bd9Sstevel@tonic-gate } cmd_map[] = { 399*7c478bd9Sstevel@tonic-gate { "update-archive", BAM_ARCHIVE, "update"}, 400*7c478bd9Sstevel@tonic-gate { "list-archive", BAM_ARCHIVE, "list"}, 401*7c478bd9Sstevel@tonic-gate { "set-menu", BAM_MENU, "set_option"}, 402*7c478bd9Sstevel@tonic-gate { "list-menu", BAM_MENU, "list_entry"}, 403*7c478bd9Sstevel@tonic-gate { "update-menu", BAM_MENU, "update_entry"}, 404*7c478bd9Sstevel@tonic-gate { NULL, 0, NULL} 405*7c478bd9Sstevel@tonic-gate }; 406*7c478bd9Sstevel@tonic-gate 407*7c478bd9Sstevel@tonic-gate /* 408*7c478bd9Sstevel@tonic-gate * Commands syntax published in bootadm(1M) are parsed here 409*7c478bd9Sstevel@tonic-gate */ 410*7c478bd9Sstevel@tonic-gate static void 411*7c478bd9Sstevel@tonic-gate parse_args(int argc, char *argv[]) 412*7c478bd9Sstevel@tonic-gate { 413*7c478bd9Sstevel@tonic-gate struct cmd_map *cmp = cmd_map; 414*7c478bd9Sstevel@tonic-gate 415*7c478bd9Sstevel@tonic-gate /* command conforming to the final spec */ 416*7c478bd9Sstevel@tonic-gate if (argc > 1 && argv[1][0] != '-') { 417*7c478bd9Sstevel@tonic-gate /* 418*7c478bd9Sstevel@tonic-gate * Map commands to internal table. 419*7c478bd9Sstevel@tonic-gate */ 420*7c478bd9Sstevel@tonic-gate while (cmp->bam_cmdname) { 421*7c478bd9Sstevel@tonic-gate if (strcmp(argv[1], cmp->bam_cmdname) == 0) { 422*7c478bd9Sstevel@tonic-gate bam_cmd = cmp->bam_cmd; 423*7c478bd9Sstevel@tonic-gate bam_subcmd = cmp->bam_subcmd; 424*7c478bd9Sstevel@tonic-gate break; 425*7c478bd9Sstevel@tonic-gate } 426*7c478bd9Sstevel@tonic-gate cmp++; 427*7c478bd9Sstevel@tonic-gate } 428*7c478bd9Sstevel@tonic-gate if (cmp->bam_cmdname == NULL) { 429*7c478bd9Sstevel@tonic-gate usage(); 430*7c478bd9Sstevel@tonic-gate bam_exit(1); 431*7c478bd9Sstevel@tonic-gate } 432*7c478bd9Sstevel@tonic-gate argc--; 433*7c478bd9Sstevel@tonic-gate argv++; 434*7c478bd9Sstevel@tonic-gate } 435*7c478bd9Sstevel@tonic-gate 436*7c478bd9Sstevel@tonic-gate parse_args_internal(argc, argv); 437*7c478bd9Sstevel@tonic-gate } 438*7c478bd9Sstevel@tonic-gate 439*7c478bd9Sstevel@tonic-gate /* 440*7c478bd9Sstevel@tonic-gate * A combination of public and private commands are parsed here. 441*7c478bd9Sstevel@tonic-gate * The internal syntax and the corresponding functionality are: 442*7c478bd9Sstevel@tonic-gate * -a update -- update-archive 443*7c478bd9Sstevel@tonic-gate * -a list -- list-archive 444*7c478bd9Sstevel@tonic-gate * -a update-all -- (reboot to sync all mounted OS archive) 445*7c478bd9Sstevel@tonic-gate * -m update_entry -- update-menu 446*7c478bd9Sstevel@tonic-gate * -m list_entry -- list-menu 447*7c478bd9Sstevel@tonic-gate * -m update_temp -- (reboot -- [boot-args]) 448*7c478bd9Sstevel@tonic-gate * -m delete_all_entries -- (called from install) 449*7c478bd9Sstevel@tonic-gate */ 450*7c478bd9Sstevel@tonic-gate static void 451*7c478bd9Sstevel@tonic-gate parse_args_internal(int argc, char *argv[]) 452*7c478bd9Sstevel@tonic-gate { 453*7c478bd9Sstevel@tonic-gate int c, error; 454*7c478bd9Sstevel@tonic-gate extern char *optarg; 455*7c478bd9Sstevel@tonic-gate extern int optind, opterr; 456*7c478bd9Sstevel@tonic-gate 457*7c478bd9Sstevel@tonic-gate /* Suppress error message from getopt */ 458*7c478bd9Sstevel@tonic-gate opterr = 0; 459*7c478bd9Sstevel@tonic-gate 460*7c478bd9Sstevel@tonic-gate error = 0; 461*7c478bd9Sstevel@tonic-gate while ((c = getopt(argc, argv, "a:d:fm:no:vR:")) != -1) { 462*7c478bd9Sstevel@tonic-gate switch (c) { 463*7c478bd9Sstevel@tonic-gate case 'a': 464*7c478bd9Sstevel@tonic-gate if (bam_cmd) { 465*7c478bd9Sstevel@tonic-gate error = 1; 466*7c478bd9Sstevel@tonic-gate bam_error(MULT_CMDS, c); 467*7c478bd9Sstevel@tonic-gate } 468*7c478bd9Sstevel@tonic-gate bam_cmd = BAM_ARCHIVE; 469*7c478bd9Sstevel@tonic-gate bam_subcmd = optarg; 470*7c478bd9Sstevel@tonic-gate break; 471*7c478bd9Sstevel@tonic-gate case 'd': 472*7c478bd9Sstevel@tonic-gate if (bam_debug) { 473*7c478bd9Sstevel@tonic-gate error = 1; 474*7c478bd9Sstevel@tonic-gate bam_error(DUP_OPT, c); 475*7c478bd9Sstevel@tonic-gate } 476*7c478bd9Sstevel@tonic-gate bam_debug = s_strtol(optarg); 477*7c478bd9Sstevel@tonic-gate break; 478*7c478bd9Sstevel@tonic-gate case 'f': 479*7c478bd9Sstevel@tonic-gate if (bam_force) { 480*7c478bd9Sstevel@tonic-gate error = 1; 481*7c478bd9Sstevel@tonic-gate bam_error(DUP_OPT, c); 482*7c478bd9Sstevel@tonic-gate } 483*7c478bd9Sstevel@tonic-gate bam_force = 1; 484*7c478bd9Sstevel@tonic-gate break; 485*7c478bd9Sstevel@tonic-gate case 'm': 486*7c478bd9Sstevel@tonic-gate if (bam_cmd) { 487*7c478bd9Sstevel@tonic-gate error = 1; 488*7c478bd9Sstevel@tonic-gate bam_error(MULT_CMDS, c); 489*7c478bd9Sstevel@tonic-gate } 490*7c478bd9Sstevel@tonic-gate bam_cmd = BAM_MENU; 491*7c478bd9Sstevel@tonic-gate bam_subcmd = optarg; 492*7c478bd9Sstevel@tonic-gate break; 493*7c478bd9Sstevel@tonic-gate case 'n': 494*7c478bd9Sstevel@tonic-gate if (bam_check) { 495*7c478bd9Sstevel@tonic-gate error = 1; 496*7c478bd9Sstevel@tonic-gate bam_error(DUP_OPT, c); 497*7c478bd9Sstevel@tonic-gate } 498*7c478bd9Sstevel@tonic-gate bam_check = 1; 499*7c478bd9Sstevel@tonic-gate bam_smf_check = bam_root_readonly; 500*7c478bd9Sstevel@tonic-gate break; 501*7c478bd9Sstevel@tonic-gate case 'o': 502*7c478bd9Sstevel@tonic-gate if (bam_opt) { 503*7c478bd9Sstevel@tonic-gate error = 1; 504*7c478bd9Sstevel@tonic-gate bam_error(DUP_OPT, c); 505*7c478bd9Sstevel@tonic-gate } 506*7c478bd9Sstevel@tonic-gate bam_opt = optarg; 507*7c478bd9Sstevel@tonic-gate break; 508*7c478bd9Sstevel@tonic-gate case 'v': 509*7c478bd9Sstevel@tonic-gate if (bam_verbose) { 510*7c478bd9Sstevel@tonic-gate error = 1; 511*7c478bd9Sstevel@tonic-gate bam_error(DUP_OPT, c); 512*7c478bd9Sstevel@tonic-gate } 513*7c478bd9Sstevel@tonic-gate bam_verbose = 1; 514*7c478bd9Sstevel@tonic-gate break; 515*7c478bd9Sstevel@tonic-gate case 'R': 516*7c478bd9Sstevel@tonic-gate if (bam_root) { 517*7c478bd9Sstevel@tonic-gate error = 1; 518*7c478bd9Sstevel@tonic-gate bam_error(DUP_OPT, c); 519*7c478bd9Sstevel@tonic-gate break; 520*7c478bd9Sstevel@tonic-gate } else if (realpath(optarg, rootbuf) == NULL) { 521*7c478bd9Sstevel@tonic-gate error = 1; 522*7c478bd9Sstevel@tonic-gate bam_error(CANT_RESOLVE, optarg, 523*7c478bd9Sstevel@tonic-gate strerror(errno)); 524*7c478bd9Sstevel@tonic-gate break; 525*7c478bd9Sstevel@tonic-gate } 526*7c478bd9Sstevel@tonic-gate bam_root = rootbuf; 527*7c478bd9Sstevel@tonic-gate if (rootbuf[strlen(rootbuf) - 1] != '/') 528*7c478bd9Sstevel@tonic-gate (void) strcat(rootbuf, "/"); 529*7c478bd9Sstevel@tonic-gate bam_rootlen = strlen(rootbuf); 530*7c478bd9Sstevel@tonic-gate break; 531*7c478bd9Sstevel@tonic-gate case '?': 532*7c478bd9Sstevel@tonic-gate error = 1; 533*7c478bd9Sstevel@tonic-gate bam_error(BAD_OPT, optopt); 534*7c478bd9Sstevel@tonic-gate break; 535*7c478bd9Sstevel@tonic-gate default : 536*7c478bd9Sstevel@tonic-gate error = 1; 537*7c478bd9Sstevel@tonic-gate bam_error(BAD_OPT, c); 538*7c478bd9Sstevel@tonic-gate break; 539*7c478bd9Sstevel@tonic-gate } 540*7c478bd9Sstevel@tonic-gate } 541*7c478bd9Sstevel@tonic-gate 542*7c478bd9Sstevel@tonic-gate /* 543*7c478bd9Sstevel@tonic-gate * A command option must be specfied 544*7c478bd9Sstevel@tonic-gate */ 545*7c478bd9Sstevel@tonic-gate if (!bam_cmd) { 546*7c478bd9Sstevel@tonic-gate if (bam_opt && strcmp(bam_opt, "all") == 0) { 547*7c478bd9Sstevel@tonic-gate usage(); 548*7c478bd9Sstevel@tonic-gate bam_exit(0); 549*7c478bd9Sstevel@tonic-gate } 550*7c478bd9Sstevel@tonic-gate bam_error(NEED_CMD); 551*7c478bd9Sstevel@tonic-gate error = 1; 552*7c478bd9Sstevel@tonic-gate } 553*7c478bd9Sstevel@tonic-gate 554*7c478bd9Sstevel@tonic-gate if (error) { 555*7c478bd9Sstevel@tonic-gate usage(); 556*7c478bd9Sstevel@tonic-gate bam_exit(1); 557*7c478bd9Sstevel@tonic-gate } 558*7c478bd9Sstevel@tonic-gate 559*7c478bd9Sstevel@tonic-gate if (optind > argc) { 560*7c478bd9Sstevel@tonic-gate bam_error(INT_ERROR, "parse_args"); 561*7c478bd9Sstevel@tonic-gate bam_exit(1); 562*7c478bd9Sstevel@tonic-gate } else if (optind < argc) { 563*7c478bd9Sstevel@tonic-gate bam_argv = &argv[optind]; 564*7c478bd9Sstevel@tonic-gate bam_argc = argc - optind; 565*7c478bd9Sstevel@tonic-gate } 566*7c478bd9Sstevel@tonic-gate 567*7c478bd9Sstevel@tonic-gate /* 568*7c478bd9Sstevel@tonic-gate * -n implies verbose mode 569*7c478bd9Sstevel@tonic-gate */ 570*7c478bd9Sstevel@tonic-gate if (bam_check) 571*7c478bd9Sstevel@tonic-gate bam_verbose = 1; 572*7c478bd9Sstevel@tonic-gate } 573*7c478bd9Sstevel@tonic-gate 574*7c478bd9Sstevel@tonic-gate static error_t 575*7c478bd9Sstevel@tonic-gate check_subcmd_and_options( 576*7c478bd9Sstevel@tonic-gate char *subcmd, 577*7c478bd9Sstevel@tonic-gate char *opt, 578*7c478bd9Sstevel@tonic-gate subcmd_defn_t *table, 579*7c478bd9Sstevel@tonic-gate error_t (**fp)()) 580*7c478bd9Sstevel@tonic-gate { 581*7c478bd9Sstevel@tonic-gate int i; 582*7c478bd9Sstevel@tonic-gate 583*7c478bd9Sstevel@tonic-gate if (subcmd == NULL) { 584*7c478bd9Sstevel@tonic-gate bam_error(NEED_SUBCMD); 585*7c478bd9Sstevel@tonic-gate return (BAM_ERROR); 586*7c478bd9Sstevel@tonic-gate } 587*7c478bd9Sstevel@tonic-gate 588*7c478bd9Sstevel@tonic-gate if (bam_root == NULL) { 589*7c478bd9Sstevel@tonic-gate bam_root = rootbuf; 590*7c478bd9Sstevel@tonic-gate bam_rootlen = 1; 591*7c478bd9Sstevel@tonic-gate } 592*7c478bd9Sstevel@tonic-gate 593*7c478bd9Sstevel@tonic-gate /* verify that subcmd is valid */ 594*7c478bd9Sstevel@tonic-gate for (i = 0; table[i].subcmd != NULL; i++) { 595*7c478bd9Sstevel@tonic-gate if (strcmp(table[i].subcmd, subcmd) == 0) 596*7c478bd9Sstevel@tonic-gate break; 597*7c478bd9Sstevel@tonic-gate } 598*7c478bd9Sstevel@tonic-gate 599*7c478bd9Sstevel@tonic-gate if (table[i].subcmd == NULL) { 600*7c478bd9Sstevel@tonic-gate bam_error(INVALID_SUBCMD, subcmd); 601*7c478bd9Sstevel@tonic-gate return (BAM_ERROR); 602*7c478bd9Sstevel@tonic-gate } 603*7c478bd9Sstevel@tonic-gate 604*7c478bd9Sstevel@tonic-gate /* subcmd verifies that opt is appropriate */ 605*7c478bd9Sstevel@tonic-gate if (table[i].option != OPT_OPTIONAL) { 606*7c478bd9Sstevel@tonic-gate if ((table[i].option == OPT_REQ) ^ (opt != NULL)) { 607*7c478bd9Sstevel@tonic-gate if (opt) 608*7c478bd9Sstevel@tonic-gate bam_error(NO_OPT_REQ, subcmd); 609*7c478bd9Sstevel@tonic-gate else 610*7c478bd9Sstevel@tonic-gate bam_error(MISS_OPT, subcmd); 611*7c478bd9Sstevel@tonic-gate return (BAM_ERROR); 612*7c478bd9Sstevel@tonic-gate } 613*7c478bd9Sstevel@tonic-gate } 614*7c478bd9Sstevel@tonic-gate 615*7c478bd9Sstevel@tonic-gate *fp = table[i].handler; 616*7c478bd9Sstevel@tonic-gate 617*7c478bd9Sstevel@tonic-gate return (BAM_SUCCESS); 618*7c478bd9Sstevel@tonic-gate } 619*7c478bd9Sstevel@tonic-gate 620*7c478bd9Sstevel@tonic-gate static error_t 621*7c478bd9Sstevel@tonic-gate bam_menu(char *subcmd, char *opt, int largc, char *largv[]) 622*7c478bd9Sstevel@tonic-gate { 623*7c478bd9Sstevel@tonic-gate error_t ret; 624*7c478bd9Sstevel@tonic-gate char menu_path[PATH_MAX]; 625*7c478bd9Sstevel@tonic-gate menu_t *menu; 626*7c478bd9Sstevel@tonic-gate error_t (*f)(menu_t *mp, char *menu_path, char *opt); 627*7c478bd9Sstevel@tonic-gate 628*7c478bd9Sstevel@tonic-gate /* 629*7c478bd9Sstevel@tonic-gate * Check arguments 630*7c478bd9Sstevel@tonic-gate */ 631*7c478bd9Sstevel@tonic-gate ret = check_subcmd_and_options(subcmd, opt, menu_subcmds, &f); 632*7c478bd9Sstevel@tonic-gate if (ret == BAM_ERROR) { 633*7c478bd9Sstevel@tonic-gate return (BAM_ERROR); 634*7c478bd9Sstevel@tonic-gate } 635*7c478bd9Sstevel@tonic-gate 636*7c478bd9Sstevel@tonic-gate (void) snprintf(menu_path, sizeof (menu_path), "%s%s", 637*7c478bd9Sstevel@tonic-gate bam_root, GRUB_MENU); 638*7c478bd9Sstevel@tonic-gate 639*7c478bd9Sstevel@tonic-gate menu = menu_read(menu_path); 640*7c478bd9Sstevel@tonic-gate assert(menu); 641*7c478bd9Sstevel@tonic-gate 642*7c478bd9Sstevel@tonic-gate /* 643*7c478bd9Sstevel@tonic-gate * Special handling for setting timeout and default 644*7c478bd9Sstevel@tonic-gate */ 645*7c478bd9Sstevel@tonic-gate if (strcmp(subcmd, "set_option") == 0) { 646*7c478bd9Sstevel@tonic-gate if (largc != 1 || largv[0] == NULL) { 647*7c478bd9Sstevel@tonic-gate usage(); 648*7c478bd9Sstevel@tonic-gate return (BAM_ERROR); 649*7c478bd9Sstevel@tonic-gate } 650*7c478bd9Sstevel@tonic-gate opt = largv[0]; 651*7c478bd9Sstevel@tonic-gate } else if (largc != 0) { 652*7c478bd9Sstevel@tonic-gate usage(); 653*7c478bd9Sstevel@tonic-gate return (BAM_ERROR); 654*7c478bd9Sstevel@tonic-gate } 655*7c478bd9Sstevel@tonic-gate 656*7c478bd9Sstevel@tonic-gate /* 657*7c478bd9Sstevel@tonic-gate * Once the sub-cmd handler has run 658*7c478bd9Sstevel@tonic-gate * only the line field is guaranteed to have valid values 659*7c478bd9Sstevel@tonic-gate */ 660*7c478bd9Sstevel@tonic-gate if (strcmp(subcmd, "update_entry") == 0) 661*7c478bd9Sstevel@tonic-gate ret = f(menu, bam_root, opt); 662*7c478bd9Sstevel@tonic-gate else 663*7c478bd9Sstevel@tonic-gate ret = f(menu, menu_path, opt); 664*7c478bd9Sstevel@tonic-gate if (ret == BAM_WRITE) { 665*7c478bd9Sstevel@tonic-gate ret = menu_write(bam_root, menu); 666*7c478bd9Sstevel@tonic-gate } 667*7c478bd9Sstevel@tonic-gate 668*7c478bd9Sstevel@tonic-gate menu_free(menu); 669*7c478bd9Sstevel@tonic-gate 670*7c478bd9Sstevel@tonic-gate return (ret); 671*7c478bd9Sstevel@tonic-gate } 672*7c478bd9Sstevel@tonic-gate 673*7c478bd9Sstevel@tonic-gate 674*7c478bd9Sstevel@tonic-gate static error_t 675*7c478bd9Sstevel@tonic-gate bam_archive( 676*7c478bd9Sstevel@tonic-gate char *subcmd, 677*7c478bd9Sstevel@tonic-gate char *opt) 678*7c478bd9Sstevel@tonic-gate { 679*7c478bd9Sstevel@tonic-gate error_t ret; 680*7c478bd9Sstevel@tonic-gate error_t (*f)(char *root, char *opt); 681*7c478bd9Sstevel@tonic-gate 682*7c478bd9Sstevel@tonic-gate /* 683*7c478bd9Sstevel@tonic-gate * Check arguments 684*7c478bd9Sstevel@tonic-gate */ 685*7c478bd9Sstevel@tonic-gate ret = check_subcmd_and_options(subcmd, opt, arch_subcmds, &f); 686*7c478bd9Sstevel@tonic-gate if (ret != BAM_SUCCESS) { 687*7c478bd9Sstevel@tonic-gate return (BAM_ERROR); 688*7c478bd9Sstevel@tonic-gate } 689*7c478bd9Sstevel@tonic-gate 690*7c478bd9Sstevel@tonic-gate #if defined(__sparc) 691*7c478bd9Sstevel@tonic-gate /* 692*7c478bd9Sstevel@tonic-gate * A NOP if called on SPARC during reboot 693*7c478bd9Sstevel@tonic-gate */ 694*7c478bd9Sstevel@tonic-gate if (strcmp(subcmd, "update_all") == 0) 695*7c478bd9Sstevel@tonic-gate return (BAM_SUCCESS); 696*7c478bd9Sstevel@tonic-gate else if (strcmp(subcmd, "update") != 0) 697*7c478bd9Sstevel@tonic-gate sparc_abort(); 698*7c478bd9Sstevel@tonic-gate #endif 699*7c478bd9Sstevel@tonic-gate 700*7c478bd9Sstevel@tonic-gate /* 701*7c478bd9Sstevel@tonic-gate * Check archive not supported with update_all 702*7c478bd9Sstevel@tonic-gate * since it is awkward to display out-of-sync 703*7c478bd9Sstevel@tonic-gate * information for each BE. 704*7c478bd9Sstevel@tonic-gate */ 705*7c478bd9Sstevel@tonic-gate if (bam_check && strcmp(subcmd, "update_all") == 0) { 706*7c478bd9Sstevel@tonic-gate bam_error(CHECK_NOT_SUPPORTED, subcmd); 707*7c478bd9Sstevel@tonic-gate return (BAM_ERROR); 708*7c478bd9Sstevel@tonic-gate } 709*7c478bd9Sstevel@tonic-gate 710*7c478bd9Sstevel@tonic-gate return (f(bam_root, opt)); 711*7c478bd9Sstevel@tonic-gate } 712*7c478bd9Sstevel@tonic-gate 713*7c478bd9Sstevel@tonic-gate /*PRINTFLIKE1*/ 714*7c478bd9Sstevel@tonic-gate static void 715*7c478bd9Sstevel@tonic-gate bam_error(char *format, ...) 716*7c478bd9Sstevel@tonic-gate { 717*7c478bd9Sstevel@tonic-gate va_list ap; 718*7c478bd9Sstevel@tonic-gate 719*7c478bd9Sstevel@tonic-gate va_start(ap, format); 720*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: ", prog); 721*7c478bd9Sstevel@tonic-gate (void) vfprintf(stderr, format, ap); 722*7c478bd9Sstevel@tonic-gate va_end(ap); 723*7c478bd9Sstevel@tonic-gate } 724*7c478bd9Sstevel@tonic-gate 725*7c478bd9Sstevel@tonic-gate /*PRINTFLIKE1*/ 726*7c478bd9Sstevel@tonic-gate static void 727*7c478bd9Sstevel@tonic-gate bam_print(char *format, ...) 728*7c478bd9Sstevel@tonic-gate { 729*7c478bd9Sstevel@tonic-gate va_list ap; 730*7c478bd9Sstevel@tonic-gate 731*7c478bd9Sstevel@tonic-gate va_start(ap, format); 732*7c478bd9Sstevel@tonic-gate (void) vfprintf(stdout, format, ap); 733*7c478bd9Sstevel@tonic-gate va_end(ap); 734*7c478bd9Sstevel@tonic-gate } 735*7c478bd9Sstevel@tonic-gate 736*7c478bd9Sstevel@tonic-gate static void 737*7c478bd9Sstevel@tonic-gate bam_exit(int excode) 738*7c478bd9Sstevel@tonic-gate { 739*7c478bd9Sstevel@tonic-gate bam_unlock(); 740*7c478bd9Sstevel@tonic-gate exit(excode); 741*7c478bd9Sstevel@tonic-gate } 742*7c478bd9Sstevel@tonic-gate 743*7c478bd9Sstevel@tonic-gate static void 744*7c478bd9Sstevel@tonic-gate bam_lock(void) 745*7c478bd9Sstevel@tonic-gate { 746*7c478bd9Sstevel@tonic-gate struct flock lock; 747*7c478bd9Sstevel@tonic-gate pid_t pid; 748*7c478bd9Sstevel@tonic-gate 749*7c478bd9Sstevel@tonic-gate bam_lock_fd = open(BAM_LOCK_FILE, O_CREAT|O_RDWR, LOCK_FILE_PERMS); 750*7c478bd9Sstevel@tonic-gate if (bam_lock_fd < 0) { 751*7c478bd9Sstevel@tonic-gate /* 752*7c478bd9Sstevel@tonic-gate * We may be invoked early in boot for archive verification. 753*7c478bd9Sstevel@tonic-gate * In this case, root is readonly and /var/run may not exist. 754*7c478bd9Sstevel@tonic-gate * Proceed without the lock 755*7c478bd9Sstevel@tonic-gate */ 756*7c478bd9Sstevel@tonic-gate if (errno == EROFS || errno == ENOENT) { 757*7c478bd9Sstevel@tonic-gate bam_root_readonly = 1; 758*7c478bd9Sstevel@tonic-gate return; 759*7c478bd9Sstevel@tonic-gate } 760*7c478bd9Sstevel@tonic-gate 761*7c478bd9Sstevel@tonic-gate bam_error(OPEN_FAIL, BAM_LOCK_FILE, strerror(errno)); 762*7c478bd9Sstevel@tonic-gate bam_exit(1); 763*7c478bd9Sstevel@tonic-gate } 764*7c478bd9Sstevel@tonic-gate 765*7c478bd9Sstevel@tonic-gate lock.l_type = F_WRLCK; 766*7c478bd9Sstevel@tonic-gate lock.l_whence = SEEK_SET; 767*7c478bd9Sstevel@tonic-gate lock.l_start = 0; 768*7c478bd9Sstevel@tonic-gate lock.l_len = 0; 769*7c478bd9Sstevel@tonic-gate 770*7c478bd9Sstevel@tonic-gate if (fcntl(bam_lock_fd, F_SETLK, &lock) == -1) { 771*7c478bd9Sstevel@tonic-gate if (errno != EACCES && errno != EAGAIN) { 772*7c478bd9Sstevel@tonic-gate bam_error(LOCK_FAIL, BAM_LOCK_FILE, strerror(errno)); 773*7c478bd9Sstevel@tonic-gate (void) close(bam_lock_fd); 774*7c478bd9Sstevel@tonic-gate bam_lock_fd = -1; 775*7c478bd9Sstevel@tonic-gate bam_exit(1); 776*7c478bd9Sstevel@tonic-gate } 777*7c478bd9Sstevel@tonic-gate pid = 0; 778*7c478bd9Sstevel@tonic-gate (void) pread(bam_lock_fd, &pid, sizeof (pid_t), 0); 779*7c478bd9Sstevel@tonic-gate bam_print(FILE_LOCKED, pid); 780*7c478bd9Sstevel@tonic-gate 781*7c478bd9Sstevel@tonic-gate lock.l_type = F_WRLCK; 782*7c478bd9Sstevel@tonic-gate lock.l_whence = SEEK_SET; 783*7c478bd9Sstevel@tonic-gate lock.l_start = 0; 784*7c478bd9Sstevel@tonic-gate lock.l_len = 0; 785*7c478bd9Sstevel@tonic-gate if (fcntl(bam_lock_fd, F_SETLKW, &lock) == -1) { 786*7c478bd9Sstevel@tonic-gate bam_error(LOCK_FAIL, BAM_LOCK_FILE, strerror(errno)); 787*7c478bd9Sstevel@tonic-gate (void) close(bam_lock_fd); 788*7c478bd9Sstevel@tonic-gate bam_lock_fd = -1; 789*7c478bd9Sstevel@tonic-gate bam_exit(1); 790*7c478bd9Sstevel@tonic-gate } 791*7c478bd9Sstevel@tonic-gate } 792*7c478bd9Sstevel@tonic-gate 793*7c478bd9Sstevel@tonic-gate /* We own the lock now */ 794*7c478bd9Sstevel@tonic-gate pid = getpid(); 795*7c478bd9Sstevel@tonic-gate (void) write(bam_lock_fd, &pid, sizeof (pid)); 796*7c478bd9Sstevel@tonic-gate } 797*7c478bd9Sstevel@tonic-gate 798*7c478bd9Sstevel@tonic-gate static void 799*7c478bd9Sstevel@tonic-gate bam_unlock(void) 800*7c478bd9Sstevel@tonic-gate { 801*7c478bd9Sstevel@tonic-gate struct flock unlock; 802*7c478bd9Sstevel@tonic-gate 803*7c478bd9Sstevel@tonic-gate /* 804*7c478bd9Sstevel@tonic-gate * NOP if we don't hold the lock 805*7c478bd9Sstevel@tonic-gate */ 806*7c478bd9Sstevel@tonic-gate if (bam_lock_fd < 0) { 807*7c478bd9Sstevel@tonic-gate return; 808*7c478bd9Sstevel@tonic-gate } 809*7c478bd9Sstevel@tonic-gate 810*7c478bd9Sstevel@tonic-gate unlock.l_type = F_UNLCK; 811*7c478bd9Sstevel@tonic-gate unlock.l_whence = SEEK_SET; 812*7c478bd9Sstevel@tonic-gate unlock.l_start = 0; 813*7c478bd9Sstevel@tonic-gate unlock.l_len = 0; 814*7c478bd9Sstevel@tonic-gate 815*7c478bd9Sstevel@tonic-gate if (fcntl(bam_lock_fd, F_SETLK, &unlock) == -1) { 816*7c478bd9Sstevel@tonic-gate bam_error(UNLOCK_FAIL, BAM_LOCK_FILE, strerror(errno)); 817*7c478bd9Sstevel@tonic-gate } 818*7c478bd9Sstevel@tonic-gate 819*7c478bd9Sstevel@tonic-gate if (close(bam_lock_fd) == -1) { 820*7c478bd9Sstevel@tonic-gate bam_error(CLOSE_FAIL, BAM_LOCK_FILE, strerror(errno)); 821*7c478bd9Sstevel@tonic-gate } 822*7c478bd9Sstevel@tonic-gate bam_lock_fd = -1; 823*7c478bd9Sstevel@tonic-gate } 824*7c478bd9Sstevel@tonic-gate 825*7c478bd9Sstevel@tonic-gate static error_t 826*7c478bd9Sstevel@tonic-gate list_archive(char *root, char *opt) 827*7c478bd9Sstevel@tonic-gate { 828*7c478bd9Sstevel@tonic-gate filelist_t flist; 829*7c478bd9Sstevel@tonic-gate filelist_t *flistp = &flist; 830*7c478bd9Sstevel@tonic-gate line_t *lp; 831*7c478bd9Sstevel@tonic-gate 832*7c478bd9Sstevel@tonic-gate assert(root); 833*7c478bd9Sstevel@tonic-gate assert(opt == NULL); 834*7c478bd9Sstevel@tonic-gate 835*7c478bd9Sstevel@tonic-gate flistp->head = flistp->tail = NULL; 836*7c478bd9Sstevel@tonic-gate if (read_list(root, flistp) != BAM_SUCCESS) { 837*7c478bd9Sstevel@tonic-gate return (BAM_ERROR); 838*7c478bd9Sstevel@tonic-gate } 839*7c478bd9Sstevel@tonic-gate assert(flistp->head && flistp->tail); 840*7c478bd9Sstevel@tonic-gate 841*7c478bd9Sstevel@tonic-gate for (lp = flistp->head; lp; lp = lp->next) { 842*7c478bd9Sstevel@tonic-gate bam_print(PRINT, lp->line); 843*7c478bd9Sstevel@tonic-gate } 844*7c478bd9Sstevel@tonic-gate 845*7c478bd9Sstevel@tonic-gate filelist_free(flistp); 846*7c478bd9Sstevel@tonic-gate 847*7c478bd9Sstevel@tonic-gate return (BAM_SUCCESS); 848*7c478bd9Sstevel@tonic-gate } 849*7c478bd9Sstevel@tonic-gate 850*7c478bd9Sstevel@tonic-gate /* 851*7c478bd9Sstevel@tonic-gate * This routine writes a list of lines to a file. 852*7c478bd9Sstevel@tonic-gate * The list is *not* freed 853*7c478bd9Sstevel@tonic-gate */ 854*7c478bd9Sstevel@tonic-gate static error_t 855*7c478bd9Sstevel@tonic-gate list2file(char *root, char *tmp, char *final, line_t *start) 856*7c478bd9Sstevel@tonic-gate { 857*7c478bd9Sstevel@tonic-gate char tmpfile[PATH_MAX]; 858*7c478bd9Sstevel@tonic-gate char path[PATH_MAX]; 859*7c478bd9Sstevel@tonic-gate FILE *fp; 860*7c478bd9Sstevel@tonic-gate int ret; 861*7c478bd9Sstevel@tonic-gate struct stat sb; 862*7c478bd9Sstevel@tonic-gate mode_t mode; 863*7c478bd9Sstevel@tonic-gate uid_t root_uid; 864*7c478bd9Sstevel@tonic-gate gid_t sys_gid; 865*7c478bd9Sstevel@tonic-gate struct passwd *pw; 866*7c478bd9Sstevel@tonic-gate struct group *gp; 867*7c478bd9Sstevel@tonic-gate 868*7c478bd9Sstevel@tonic-gate 869*7c478bd9Sstevel@tonic-gate (void) snprintf(path, sizeof (path), "%s%s", root, final); 870*7c478bd9Sstevel@tonic-gate 871*7c478bd9Sstevel@tonic-gate if (start == NULL) { 872*7c478bd9Sstevel@tonic-gate if (stat(path, &sb) != -1) { 873*7c478bd9Sstevel@tonic-gate bam_print(UNLINK_EMPTY, path); 874*7c478bd9Sstevel@tonic-gate if (unlink(path) != 0) { 875*7c478bd9Sstevel@tonic-gate bam_error(UNLINK_FAIL, path, strerror(errno)); 876*7c478bd9Sstevel@tonic-gate return (BAM_ERROR); 877*7c478bd9Sstevel@tonic-gate } else { 878*7c478bd9Sstevel@tonic-gate return (BAM_SUCCESS); 879*7c478bd9Sstevel@tonic-gate } 880*7c478bd9Sstevel@tonic-gate } 881*7c478bd9Sstevel@tonic-gate } 882*7c478bd9Sstevel@tonic-gate 883*7c478bd9Sstevel@tonic-gate /* 884*7c478bd9Sstevel@tonic-gate * Preserve attributes of existing file if possible, 885*7c478bd9Sstevel@tonic-gate * otherwise ask the system for uid/gid of root/sys. 886*7c478bd9Sstevel@tonic-gate * If all fails, fall back on hard-coded defaults. 887*7c478bd9Sstevel@tonic-gate */ 888*7c478bd9Sstevel@tonic-gate if (stat(path, &sb) != -1) { 889*7c478bd9Sstevel@tonic-gate mode = sb.st_mode; 890*7c478bd9Sstevel@tonic-gate root_uid = sb.st_uid; 891*7c478bd9Sstevel@tonic-gate sys_gid = sb.st_gid; 892*7c478bd9Sstevel@tonic-gate } else { 893*7c478bd9Sstevel@tonic-gate mode = DEFAULT_DEV_MODE; 894*7c478bd9Sstevel@tonic-gate if ((pw = getpwnam(DEFAULT_DEV_USER)) != NULL) { 895*7c478bd9Sstevel@tonic-gate root_uid = pw->pw_uid; 896*7c478bd9Sstevel@tonic-gate } else { 897*7c478bd9Sstevel@tonic-gate if (bam_verbose) 898*7c478bd9Sstevel@tonic-gate bam_error(CANT_FIND_USER, 899*7c478bd9Sstevel@tonic-gate DEFAULT_DEV_USER, DEFAULT_DEV_UID); 900*7c478bd9Sstevel@tonic-gate root_uid = (uid_t)DEFAULT_DEV_UID; 901*7c478bd9Sstevel@tonic-gate } 902*7c478bd9Sstevel@tonic-gate if ((gp = getgrnam(DEFAULT_DEV_GROUP)) != NULL) { 903*7c478bd9Sstevel@tonic-gate sys_gid = gp->gr_gid; 904*7c478bd9Sstevel@tonic-gate } else { 905*7c478bd9Sstevel@tonic-gate if (bam_verbose) 906*7c478bd9Sstevel@tonic-gate bam_error(CANT_FIND_GROUP, 907*7c478bd9Sstevel@tonic-gate DEFAULT_DEV_GROUP, DEFAULT_DEV_GID); 908*7c478bd9Sstevel@tonic-gate sys_gid = (gid_t)DEFAULT_DEV_GID; 909*7c478bd9Sstevel@tonic-gate } 910*7c478bd9Sstevel@tonic-gate } 911*7c478bd9Sstevel@tonic-gate 912*7c478bd9Sstevel@tonic-gate (void) snprintf(tmpfile, sizeof (tmpfile), "%s%s", root, tmp); 913*7c478bd9Sstevel@tonic-gate 914*7c478bd9Sstevel@tonic-gate /* Truncate tmpfile first */ 915*7c478bd9Sstevel@tonic-gate fp = fopen(tmpfile, "w"); 916*7c478bd9Sstevel@tonic-gate if (fp == NULL) { 917*7c478bd9Sstevel@tonic-gate bam_error(OPEN_FAIL, tmpfile, strerror(errno)); 918*7c478bd9Sstevel@tonic-gate return (BAM_ERROR); 919*7c478bd9Sstevel@tonic-gate } 920*7c478bd9Sstevel@tonic-gate ret = fclose(fp); 921*7c478bd9Sstevel@tonic-gate if (ret == EOF) { 922*7c478bd9Sstevel@tonic-gate bam_error(CLOSE_FAIL, tmpfile, strerror(errno)); 923*7c478bd9Sstevel@tonic-gate return (BAM_ERROR); 924*7c478bd9Sstevel@tonic-gate } 925*7c478bd9Sstevel@tonic-gate 926*7c478bd9Sstevel@tonic-gate /* Now open it in append mode */ 927*7c478bd9Sstevel@tonic-gate fp = fopen(tmpfile, "a"); 928*7c478bd9Sstevel@tonic-gate if (fp == NULL) { 929*7c478bd9Sstevel@tonic-gate bam_error(OPEN_FAIL, tmpfile, strerror(errno)); 930*7c478bd9Sstevel@tonic-gate return (BAM_ERROR); 931*7c478bd9Sstevel@tonic-gate } 932*7c478bd9Sstevel@tonic-gate 933*7c478bd9Sstevel@tonic-gate for (; start; start = start->next) { 934*7c478bd9Sstevel@tonic-gate ret = s_fputs(start->line, fp); 935*7c478bd9Sstevel@tonic-gate if (ret == EOF) { 936*7c478bd9Sstevel@tonic-gate bam_error(WRITE_FAIL, tmpfile, strerror(errno)); 937*7c478bd9Sstevel@tonic-gate (void) fclose(fp); 938*7c478bd9Sstevel@tonic-gate return (BAM_ERROR); 939*7c478bd9Sstevel@tonic-gate } 940*7c478bd9Sstevel@tonic-gate } 941*7c478bd9Sstevel@tonic-gate 942*7c478bd9Sstevel@tonic-gate ret = fclose(fp); 943*7c478bd9Sstevel@tonic-gate if (ret == EOF) { 944*7c478bd9Sstevel@tonic-gate bam_error(CLOSE_FAIL, tmpfile, strerror(errno)); 945*7c478bd9Sstevel@tonic-gate return (BAM_ERROR); 946*7c478bd9Sstevel@tonic-gate } 947*7c478bd9Sstevel@tonic-gate 948*7c478bd9Sstevel@tonic-gate /* 949*7c478bd9Sstevel@tonic-gate * Set up desired attributes 950*7c478bd9Sstevel@tonic-gate */ 951*7c478bd9Sstevel@tonic-gate ret = chmod(tmpfile, mode); 952*7c478bd9Sstevel@tonic-gate if (ret == -1) { 953*7c478bd9Sstevel@tonic-gate bam_error(CHMOD_FAIL, tmpfile, strerror(errno)); 954*7c478bd9Sstevel@tonic-gate return (BAM_ERROR); 955*7c478bd9Sstevel@tonic-gate } 956*7c478bd9Sstevel@tonic-gate 957*7c478bd9Sstevel@tonic-gate ret = chown(tmpfile, root_uid, sys_gid); 958*7c478bd9Sstevel@tonic-gate if (ret == -1) { 959*7c478bd9Sstevel@tonic-gate bam_error(CHOWN_FAIL, tmpfile, strerror(errno)); 960*7c478bd9Sstevel@tonic-gate return (BAM_ERROR); 961*7c478bd9Sstevel@tonic-gate } 962*7c478bd9Sstevel@tonic-gate 963*7c478bd9Sstevel@tonic-gate 964*7c478bd9Sstevel@tonic-gate /* 965*7c478bd9Sstevel@tonic-gate * Do an atomic rename 966*7c478bd9Sstevel@tonic-gate */ 967*7c478bd9Sstevel@tonic-gate ret = rename(tmpfile, path); 968*7c478bd9Sstevel@tonic-gate if (ret != 0) { 969*7c478bd9Sstevel@tonic-gate bam_error(RENAME_FAIL, path, strerror(errno)); 970*7c478bd9Sstevel@tonic-gate return (BAM_ERROR); 971*7c478bd9Sstevel@tonic-gate } 972*7c478bd9Sstevel@tonic-gate 973*7c478bd9Sstevel@tonic-gate return (BAM_SUCCESS); 974*7c478bd9Sstevel@tonic-gate } 975*7c478bd9Sstevel@tonic-gate 976*7c478bd9Sstevel@tonic-gate /* 977*7c478bd9Sstevel@tonic-gate * This function should always return 0 - since we want 978*7c478bd9Sstevel@tonic-gate * to create stat data for *all* files in the list. 979*7c478bd9Sstevel@tonic-gate */ 980*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 981*7c478bd9Sstevel@tonic-gate static int 982*7c478bd9Sstevel@tonic-gate cmpstat( 983*7c478bd9Sstevel@tonic-gate const char *file, 984*7c478bd9Sstevel@tonic-gate const struct stat *stat, 985*7c478bd9Sstevel@tonic-gate int flags, 986*7c478bd9Sstevel@tonic-gate struct FTW *ftw) 987*7c478bd9Sstevel@tonic-gate { 988*7c478bd9Sstevel@tonic-gate uint_t sz; 989*7c478bd9Sstevel@tonic-gate uint64_t *value; 990*7c478bd9Sstevel@tonic-gate uint64_t filestat[2]; 991*7c478bd9Sstevel@tonic-gate int error; 992*7c478bd9Sstevel@tonic-gate 993*7c478bd9Sstevel@tonic-gate /* 994*7c478bd9Sstevel@tonic-gate * We only want regular files 995*7c478bd9Sstevel@tonic-gate */ 996*7c478bd9Sstevel@tonic-gate if (!S_ISREG(stat->st_mode)) 997*7c478bd9Sstevel@tonic-gate return (0); 998*7c478bd9Sstevel@tonic-gate 999*7c478bd9Sstevel@tonic-gate /* 1000*7c478bd9Sstevel@tonic-gate * new_nvlp may be NULL if there were errors earlier 1001*7c478bd9Sstevel@tonic-gate * but this is not fatal to update determination. 1002*7c478bd9Sstevel@tonic-gate */ 1003*7c478bd9Sstevel@tonic-gate if (walk_arg.new_nvlp) { 1004*7c478bd9Sstevel@tonic-gate filestat[0] = stat->st_size; 1005*7c478bd9Sstevel@tonic-gate filestat[1] = stat->st_mtime; 1006*7c478bd9Sstevel@tonic-gate error = nvlist_add_uint64_array(walk_arg.new_nvlp, 1007*7c478bd9Sstevel@tonic-gate file + bam_rootlen, filestat, 2); 1008*7c478bd9Sstevel@tonic-gate if (error) 1009*7c478bd9Sstevel@tonic-gate bam_error(NVADD_FAIL, file, strerror(error)); 1010*7c478bd9Sstevel@tonic-gate } 1011*7c478bd9Sstevel@tonic-gate 1012*7c478bd9Sstevel@tonic-gate /* 1013*7c478bd9Sstevel@tonic-gate * The remaining steps are only required if we haven't made a 1014*7c478bd9Sstevel@tonic-gate * decision about update or if we are checking (-n) 1015*7c478bd9Sstevel@tonic-gate */ 1016*7c478bd9Sstevel@tonic-gate if (walk_arg.need_update && !bam_check) 1017*7c478bd9Sstevel@tonic-gate return (0); 1018*7c478bd9Sstevel@tonic-gate 1019*7c478bd9Sstevel@tonic-gate /* 1020*7c478bd9Sstevel@tonic-gate * If we are invoked as part of system/filesyste/boot-archive 1021*7c478bd9Sstevel@tonic-gate * SMF service, ignore amd64 modules unless we are booted amd64. 1022*7c478bd9Sstevel@tonic-gate */ 1023*7c478bd9Sstevel@tonic-gate if (bam_smf_check && !is_amd64() && strstr(file, "/amd64/") == 0) 1024*7c478bd9Sstevel@tonic-gate return (0); 1025*7c478bd9Sstevel@tonic-gate 1026*7c478bd9Sstevel@tonic-gate /* 1027*7c478bd9Sstevel@tonic-gate * We need an update if file doesn't exist in old archive 1028*7c478bd9Sstevel@tonic-gate */ 1029*7c478bd9Sstevel@tonic-gate if (walk_arg.old_nvlp == NULL || 1030*7c478bd9Sstevel@tonic-gate nvlist_lookup_uint64_array(walk_arg.old_nvlp, 1031*7c478bd9Sstevel@tonic-gate file + bam_rootlen, &value, &sz) != 0) { 1032*7c478bd9Sstevel@tonic-gate if (bam_smf_check) /* ignore new during smf check */ 1033*7c478bd9Sstevel@tonic-gate return (0); 1034*7c478bd9Sstevel@tonic-gate walk_arg.need_update = 1; 1035*7c478bd9Sstevel@tonic-gate if (bam_verbose) 1036*7c478bd9Sstevel@tonic-gate bam_print(PARSEABLE_NEW_FILE, file); 1037*7c478bd9Sstevel@tonic-gate return (0); 1038*7c478bd9Sstevel@tonic-gate } 1039*7c478bd9Sstevel@tonic-gate 1040*7c478bd9Sstevel@tonic-gate /* 1041*7c478bd9Sstevel@tonic-gate * File exists in old archive. Check if file has changed 1042*7c478bd9Sstevel@tonic-gate */ 1043*7c478bd9Sstevel@tonic-gate assert(sz == 2); 1044*7c478bd9Sstevel@tonic-gate bcopy(value, filestat, sizeof (filestat)); 1045*7c478bd9Sstevel@tonic-gate 1046*7c478bd9Sstevel@tonic-gate if (filestat[0] != stat->st_size || 1047*7c478bd9Sstevel@tonic-gate filestat[1] != stat->st_mtime) { 1048*7c478bd9Sstevel@tonic-gate walk_arg.need_update = 1; 1049*7c478bd9Sstevel@tonic-gate if (bam_verbose) 1050*7c478bd9Sstevel@tonic-gate if (bam_smf_check) 1051*7c478bd9Sstevel@tonic-gate bam_print(" %s\n", file); 1052*7c478bd9Sstevel@tonic-gate else 1053*7c478bd9Sstevel@tonic-gate bam_print(PARSEABLE_OUT_DATE, file); 1054*7c478bd9Sstevel@tonic-gate } 1055*7c478bd9Sstevel@tonic-gate 1056*7c478bd9Sstevel@tonic-gate return (0); 1057*7c478bd9Sstevel@tonic-gate } 1058*7c478bd9Sstevel@tonic-gate 1059*7c478bd9Sstevel@tonic-gate /* 1060*7c478bd9Sstevel@tonic-gate * Check flags and presence of required files. 1061*7c478bd9Sstevel@tonic-gate * The force flag and/or absence of files should 1062*7c478bd9Sstevel@tonic-gate * trigger an update. 1063*7c478bd9Sstevel@tonic-gate * Suppress stdout output if check (-n) option is set 1064*7c478bd9Sstevel@tonic-gate * (as -n should only produce parseable output.) 1065*7c478bd9Sstevel@tonic-gate */ 1066*7c478bd9Sstevel@tonic-gate static void 1067*7c478bd9Sstevel@tonic-gate check_flags_and_files(char *root) 1068*7c478bd9Sstevel@tonic-gate { 1069*7c478bd9Sstevel@tonic-gate char path[PATH_MAX]; 1070*7c478bd9Sstevel@tonic-gate struct stat sb; 1071*7c478bd9Sstevel@tonic-gate 1072*7c478bd9Sstevel@tonic-gate /* 1073*7c478bd9Sstevel@tonic-gate * if force, create archive unconditionally 1074*7c478bd9Sstevel@tonic-gate */ 1075*7c478bd9Sstevel@tonic-gate if (bam_force) { 1076*7c478bd9Sstevel@tonic-gate walk_arg.need_update = 1; 1077*7c478bd9Sstevel@tonic-gate if (bam_verbose && !bam_check) 1078*7c478bd9Sstevel@tonic-gate bam_print(UPDATE_FORCE); 1079*7c478bd9Sstevel@tonic-gate return; 1080*7c478bd9Sstevel@tonic-gate } 1081*7c478bd9Sstevel@tonic-gate 1082*7c478bd9Sstevel@tonic-gate /* 1083*7c478bd9Sstevel@tonic-gate * If archive is missing, create archive 1084*7c478bd9Sstevel@tonic-gate */ 1085*7c478bd9Sstevel@tonic-gate (void) snprintf(path, sizeof (path), "%s%s", root, BOOT_ARCHIVE); 1086*7c478bd9Sstevel@tonic-gate if (stat(path, &sb) != 0) { 1087*7c478bd9Sstevel@tonic-gate if (bam_verbose && !bam_check) 1088*7c478bd9Sstevel@tonic-gate bam_print(UPDATE_ARCH_MISS, path); 1089*7c478bd9Sstevel@tonic-gate walk_arg.need_update = 1; 1090*7c478bd9Sstevel@tonic-gate return; 1091*7c478bd9Sstevel@tonic-gate } 1092*7c478bd9Sstevel@tonic-gate } 1093*7c478bd9Sstevel@tonic-gate 1094*7c478bd9Sstevel@tonic-gate static error_t 1095*7c478bd9Sstevel@tonic-gate read_one_list(char *root, filelist_t *flistp, char *filelist) 1096*7c478bd9Sstevel@tonic-gate { 1097*7c478bd9Sstevel@tonic-gate char path[PATH_MAX]; 1098*7c478bd9Sstevel@tonic-gate FILE *fp; 1099*7c478bd9Sstevel@tonic-gate char buf[BAM_MAXLINE]; 1100*7c478bd9Sstevel@tonic-gate 1101*7c478bd9Sstevel@tonic-gate (void) snprintf(path, sizeof (path), "%s%s", root, filelist); 1102*7c478bd9Sstevel@tonic-gate 1103*7c478bd9Sstevel@tonic-gate fp = fopen(path, "r"); 1104*7c478bd9Sstevel@tonic-gate if (fp == NULL) { 1105*7c478bd9Sstevel@tonic-gate if (bam_debug) 1106*7c478bd9Sstevel@tonic-gate bam_error(FLIST_FAIL, path, strerror(errno)); 1107*7c478bd9Sstevel@tonic-gate return (BAM_ERROR); 1108*7c478bd9Sstevel@tonic-gate } 1109*7c478bd9Sstevel@tonic-gate while (s_fgets(buf, sizeof (buf), fp) != NULL) { 1110*7c478bd9Sstevel@tonic-gate append_to_flist(flistp, buf); 1111*7c478bd9Sstevel@tonic-gate } 1112*7c478bd9Sstevel@tonic-gate if (fclose(fp) != 0) { 1113*7c478bd9Sstevel@tonic-gate bam_error(CLOSE_FAIL, path, strerror(errno)); 1114*7c478bd9Sstevel@tonic-gate return (BAM_ERROR); 1115*7c478bd9Sstevel@tonic-gate } 1116*7c478bd9Sstevel@tonic-gate return (BAM_SUCCESS); 1117*7c478bd9Sstevel@tonic-gate } 1118*7c478bd9Sstevel@tonic-gate 1119*7c478bd9Sstevel@tonic-gate static error_t 1120*7c478bd9Sstevel@tonic-gate read_list(char *root, filelist_t *flistp) 1121*7c478bd9Sstevel@tonic-gate { 1122*7c478bd9Sstevel@tonic-gate int rval; 1123*7c478bd9Sstevel@tonic-gate 1124*7c478bd9Sstevel@tonic-gate flistp->head = flistp->tail = NULL; 1125*7c478bd9Sstevel@tonic-gate 1126*7c478bd9Sstevel@tonic-gate /* 1127*7c478bd9Sstevel@tonic-gate * Read current lists of files - only the first is mandatory 1128*7c478bd9Sstevel@tonic-gate */ 1129*7c478bd9Sstevel@tonic-gate rval = read_one_list(root, flistp, BOOT_FILE_LIST); 1130*7c478bd9Sstevel@tonic-gate if (rval != BAM_SUCCESS) 1131*7c478bd9Sstevel@tonic-gate return (rval); 1132*7c478bd9Sstevel@tonic-gate (void) read_one_list(root, flistp, ETC_FILE_LIST); 1133*7c478bd9Sstevel@tonic-gate 1134*7c478bd9Sstevel@tonic-gate if (flistp->head == NULL) { 1135*7c478bd9Sstevel@tonic-gate bam_error(NO_FLIST); 1136*7c478bd9Sstevel@tonic-gate return (BAM_ERROR); 1137*7c478bd9Sstevel@tonic-gate } 1138*7c478bd9Sstevel@tonic-gate 1139*7c478bd9Sstevel@tonic-gate return (BAM_SUCCESS); 1140*7c478bd9Sstevel@tonic-gate } 1141*7c478bd9Sstevel@tonic-gate 1142*7c478bd9Sstevel@tonic-gate static void 1143*7c478bd9Sstevel@tonic-gate getoldstat(char *root) 1144*7c478bd9Sstevel@tonic-gate { 1145*7c478bd9Sstevel@tonic-gate char path[PATH_MAX]; 1146*7c478bd9Sstevel@tonic-gate int fd, error; 1147*7c478bd9Sstevel@tonic-gate struct stat sb; 1148*7c478bd9Sstevel@tonic-gate char *ostat; 1149*7c478bd9Sstevel@tonic-gate 1150*7c478bd9Sstevel@tonic-gate (void) snprintf(path, sizeof (path), "%s%s", root, FILE_STAT); 1151*7c478bd9Sstevel@tonic-gate fd = open(path, O_RDONLY); 1152*7c478bd9Sstevel@tonic-gate if (fd == -1) { 1153*7c478bd9Sstevel@tonic-gate if (bam_verbose) 1154*7c478bd9Sstevel@tonic-gate bam_print(OPEN_FAIL, path, strerror(errno)); 1155*7c478bd9Sstevel@tonic-gate walk_arg.need_update = 1; 1156*7c478bd9Sstevel@tonic-gate return; 1157*7c478bd9Sstevel@tonic-gate } 1158*7c478bd9Sstevel@tonic-gate 1159*7c478bd9Sstevel@tonic-gate if (fstat(fd, &sb) != 0) { 1160*7c478bd9Sstevel@tonic-gate bam_error(STAT_FAIL, path, strerror(errno)); 1161*7c478bd9Sstevel@tonic-gate (void) close(fd); 1162*7c478bd9Sstevel@tonic-gate walk_arg.need_update = 1; 1163*7c478bd9Sstevel@tonic-gate return; 1164*7c478bd9Sstevel@tonic-gate } 1165*7c478bd9Sstevel@tonic-gate 1166*7c478bd9Sstevel@tonic-gate ostat = s_calloc(1, sb.st_size); 1167*7c478bd9Sstevel@tonic-gate 1168*7c478bd9Sstevel@tonic-gate if (read(fd, ostat, sb.st_size) != sb.st_size) { 1169*7c478bd9Sstevel@tonic-gate bam_error(READ_FAIL, path, strerror(errno)); 1170*7c478bd9Sstevel@tonic-gate (void) close(fd); 1171*7c478bd9Sstevel@tonic-gate free(ostat); 1172*7c478bd9Sstevel@tonic-gate walk_arg.need_update = 1; 1173*7c478bd9Sstevel@tonic-gate return; 1174*7c478bd9Sstevel@tonic-gate } 1175*7c478bd9Sstevel@tonic-gate 1176*7c478bd9Sstevel@tonic-gate (void) close(fd); 1177*7c478bd9Sstevel@tonic-gate 1178*7c478bd9Sstevel@tonic-gate walk_arg.old_nvlp = NULL; 1179*7c478bd9Sstevel@tonic-gate error = nvlist_unpack(ostat, sb.st_size, &walk_arg.old_nvlp, 0); 1180*7c478bd9Sstevel@tonic-gate 1181*7c478bd9Sstevel@tonic-gate free(ostat); 1182*7c478bd9Sstevel@tonic-gate 1183*7c478bd9Sstevel@tonic-gate if (error) { 1184*7c478bd9Sstevel@tonic-gate bam_error(UNPACK_FAIL, path, strerror(error)); 1185*7c478bd9Sstevel@tonic-gate walk_arg.old_nvlp = NULL; 1186*7c478bd9Sstevel@tonic-gate walk_arg.need_update = 1; 1187*7c478bd9Sstevel@tonic-gate return; 1188*7c478bd9Sstevel@tonic-gate } 1189*7c478bd9Sstevel@tonic-gate } 1190*7c478bd9Sstevel@tonic-gate 1191*7c478bd9Sstevel@tonic-gate static void 1192*7c478bd9Sstevel@tonic-gate create_newstat(void) 1193*7c478bd9Sstevel@tonic-gate { 1194*7c478bd9Sstevel@tonic-gate int error; 1195*7c478bd9Sstevel@tonic-gate 1196*7c478bd9Sstevel@tonic-gate error = nvlist_alloc(&walk_arg.new_nvlp, NV_UNIQUE_NAME, 0); 1197*7c478bd9Sstevel@tonic-gate if (error) { 1198*7c478bd9Sstevel@tonic-gate /* 1199*7c478bd9Sstevel@tonic-gate * Not fatal - we can still create archive 1200*7c478bd9Sstevel@tonic-gate */ 1201*7c478bd9Sstevel@tonic-gate walk_arg.new_nvlp = NULL; 1202*7c478bd9Sstevel@tonic-gate bam_error(NVALLOC_FAIL, strerror(error)); 1203*7c478bd9Sstevel@tonic-gate } 1204*7c478bd9Sstevel@tonic-gate } 1205*7c478bd9Sstevel@tonic-gate 1206*7c478bd9Sstevel@tonic-gate static void 1207*7c478bd9Sstevel@tonic-gate walk_list(char *root, filelist_t *flistp) 1208*7c478bd9Sstevel@tonic-gate { 1209*7c478bd9Sstevel@tonic-gate char path[PATH_MAX]; 1210*7c478bd9Sstevel@tonic-gate line_t *lp; 1211*7c478bd9Sstevel@tonic-gate 1212*7c478bd9Sstevel@tonic-gate for (lp = flistp->head; lp; lp = lp->next) { 1213*7c478bd9Sstevel@tonic-gate (void) snprintf(path, sizeof (path), "%s%s", root, lp->line); 1214*7c478bd9Sstevel@tonic-gate /* XXX shouldn't we use FTW_MOUNT ? */ 1215*7c478bd9Sstevel@tonic-gate if (nftw(path, cmpstat, 20, 0) == -1) { 1216*7c478bd9Sstevel@tonic-gate /* 1217*7c478bd9Sstevel@tonic-gate * Some files may not exist. 1218*7c478bd9Sstevel@tonic-gate * For example: etc/rtc_config on a x86 diskless system 1219*7c478bd9Sstevel@tonic-gate * Emit verbose message only 1220*7c478bd9Sstevel@tonic-gate */ 1221*7c478bd9Sstevel@tonic-gate if (bam_verbose) 1222*7c478bd9Sstevel@tonic-gate bam_print(NFTW_FAIL, path, strerror(errno)); 1223*7c478bd9Sstevel@tonic-gate } 1224*7c478bd9Sstevel@tonic-gate } 1225*7c478bd9Sstevel@tonic-gate } 1226*7c478bd9Sstevel@tonic-gate 1227*7c478bd9Sstevel@tonic-gate static void 1228*7c478bd9Sstevel@tonic-gate savenew(char *root) 1229*7c478bd9Sstevel@tonic-gate { 1230*7c478bd9Sstevel@tonic-gate char path[PATH_MAX]; 1231*7c478bd9Sstevel@tonic-gate char path2[PATH_MAX]; 1232*7c478bd9Sstevel@tonic-gate size_t sz; 1233*7c478bd9Sstevel@tonic-gate char *nstat; 1234*7c478bd9Sstevel@tonic-gate int fd, wrote, error; 1235*7c478bd9Sstevel@tonic-gate 1236*7c478bd9Sstevel@tonic-gate nstat = NULL; 1237*7c478bd9Sstevel@tonic-gate sz = 0; 1238*7c478bd9Sstevel@tonic-gate error = nvlist_pack(walk_arg.new_nvlp, &nstat, &sz, 1239*7c478bd9Sstevel@tonic-gate NV_ENCODE_XDR, 0); 1240*7c478bd9Sstevel@tonic-gate if (error) { 1241*7c478bd9Sstevel@tonic-gate bam_error(PACK_FAIL, strerror(error)); 1242*7c478bd9Sstevel@tonic-gate return; 1243*7c478bd9Sstevel@tonic-gate } 1244*7c478bd9Sstevel@tonic-gate 1245*7c478bd9Sstevel@tonic-gate (void) snprintf(path, sizeof (path), "%s%s", root, FILE_STAT_TMP); 1246*7c478bd9Sstevel@tonic-gate fd = open(path, O_RDWR|O_CREAT|O_TRUNC, FILE_STAT_MODE); 1247*7c478bd9Sstevel@tonic-gate if (fd == -1) { 1248*7c478bd9Sstevel@tonic-gate bam_error(OPEN_FAIL, path, strerror(errno)); 1249*7c478bd9Sstevel@tonic-gate free(nstat); 1250*7c478bd9Sstevel@tonic-gate return; 1251*7c478bd9Sstevel@tonic-gate } 1252*7c478bd9Sstevel@tonic-gate wrote = write(fd, nstat, sz); 1253*7c478bd9Sstevel@tonic-gate if (wrote != sz) { 1254*7c478bd9Sstevel@tonic-gate bam_error(WRITE_FAIL, path, strerror(errno)); 1255*7c478bd9Sstevel@tonic-gate (void) close(fd); 1256*7c478bd9Sstevel@tonic-gate free(nstat); 1257*7c478bd9Sstevel@tonic-gate return; 1258*7c478bd9Sstevel@tonic-gate } 1259*7c478bd9Sstevel@tonic-gate (void) close(fd); 1260*7c478bd9Sstevel@tonic-gate free(nstat); 1261*7c478bd9Sstevel@tonic-gate 1262*7c478bd9Sstevel@tonic-gate (void) snprintf(path2, sizeof (path2), "%s%s", root, FILE_STAT); 1263*7c478bd9Sstevel@tonic-gate if (rename(path, path2) != 0) { 1264*7c478bd9Sstevel@tonic-gate bam_error(RENAME_FAIL, path2, strerror(errno)); 1265*7c478bd9Sstevel@tonic-gate } 1266*7c478bd9Sstevel@tonic-gate } 1267*7c478bd9Sstevel@tonic-gate 1268*7c478bd9Sstevel@tonic-gate static void 1269*7c478bd9Sstevel@tonic-gate clear_walk_args(void) 1270*7c478bd9Sstevel@tonic-gate { 1271*7c478bd9Sstevel@tonic-gate if (walk_arg.old_nvlp) 1272*7c478bd9Sstevel@tonic-gate nvlist_free(walk_arg.old_nvlp); 1273*7c478bd9Sstevel@tonic-gate if (walk_arg.new_nvlp) 1274*7c478bd9Sstevel@tonic-gate nvlist_free(walk_arg.new_nvlp); 1275*7c478bd9Sstevel@tonic-gate walk_arg.need_update = 0; 1276*7c478bd9Sstevel@tonic-gate walk_arg.old_nvlp = NULL; 1277*7c478bd9Sstevel@tonic-gate walk_arg.new_nvlp = NULL; 1278*7c478bd9Sstevel@tonic-gate } 1279*7c478bd9Sstevel@tonic-gate 1280*7c478bd9Sstevel@tonic-gate /* 1281*7c478bd9Sstevel@tonic-gate * Returns: 1282*7c478bd9Sstevel@tonic-gate * 0 - no update necessary 1283*7c478bd9Sstevel@tonic-gate * 1 - update required. 1284*7c478bd9Sstevel@tonic-gate * BAM_ERROR (-1) - An error occurred 1285*7c478bd9Sstevel@tonic-gate * 1286*7c478bd9Sstevel@tonic-gate * Special handling for check (-n): 1287*7c478bd9Sstevel@tonic-gate * ================================ 1288*7c478bd9Sstevel@tonic-gate * The check (-n) option produces parseable output. 1289*7c478bd9Sstevel@tonic-gate * To do this, we suppress all stdout messages unrelated 1290*7c478bd9Sstevel@tonic-gate * to out of sync files. 1291*7c478bd9Sstevel@tonic-gate * All stderr messages are still printed though. 1292*7c478bd9Sstevel@tonic-gate * 1293*7c478bd9Sstevel@tonic-gate */ 1294*7c478bd9Sstevel@tonic-gate static int 1295*7c478bd9Sstevel@tonic-gate update_required(char *root) 1296*7c478bd9Sstevel@tonic-gate { 1297*7c478bd9Sstevel@tonic-gate struct stat sb; 1298*7c478bd9Sstevel@tonic-gate char path[PATH_MAX]; 1299*7c478bd9Sstevel@tonic-gate filelist_t flist; 1300*7c478bd9Sstevel@tonic-gate filelist_t *flistp = &flist; 1301*7c478bd9Sstevel@tonic-gate int need_update; 1302*7c478bd9Sstevel@tonic-gate 1303*7c478bd9Sstevel@tonic-gate flistp->head = flistp->tail = NULL; 1304*7c478bd9Sstevel@tonic-gate 1305*7c478bd9Sstevel@tonic-gate walk_arg.need_update = 0; 1306*7c478bd9Sstevel@tonic-gate 1307*7c478bd9Sstevel@tonic-gate /* 1308*7c478bd9Sstevel@tonic-gate * Without consulting stat data, check if we need update 1309*7c478bd9Sstevel@tonic-gate */ 1310*7c478bd9Sstevel@tonic-gate check_flags_and_files(root); 1311*7c478bd9Sstevel@tonic-gate 1312*7c478bd9Sstevel@tonic-gate /* 1313*7c478bd9Sstevel@tonic-gate * In certain deployment scenarios, filestat may not 1314*7c478bd9Sstevel@tonic-gate * exist. Ignore it during boot-archive SMF check. 1315*7c478bd9Sstevel@tonic-gate */ 1316*7c478bd9Sstevel@tonic-gate if (bam_smf_check) { 1317*7c478bd9Sstevel@tonic-gate (void) snprintf(path, sizeof (path), "%s%s", root, FILE_STAT); 1318*7c478bd9Sstevel@tonic-gate if (stat(path, &sb) != 0) 1319*7c478bd9Sstevel@tonic-gate return (0); 1320*7c478bd9Sstevel@tonic-gate } 1321*7c478bd9Sstevel@tonic-gate 1322*7c478bd9Sstevel@tonic-gate /* 1323*7c478bd9Sstevel@tonic-gate * consult stat data only if we haven't made a decision 1324*7c478bd9Sstevel@tonic-gate * about update. If checking (-n) however, we always 1325*7c478bd9Sstevel@tonic-gate * need stat data (since we want to compare old and new) 1326*7c478bd9Sstevel@tonic-gate */ 1327*7c478bd9Sstevel@tonic-gate if (!walk_arg.need_update || bam_check) 1328*7c478bd9Sstevel@tonic-gate getoldstat(root); 1329*7c478bd9Sstevel@tonic-gate 1330*7c478bd9Sstevel@tonic-gate /* 1331*7c478bd9Sstevel@tonic-gate * read list of files 1332*7c478bd9Sstevel@tonic-gate */ 1333*7c478bd9Sstevel@tonic-gate if (read_list(root, flistp) != BAM_SUCCESS) { 1334*7c478bd9Sstevel@tonic-gate clear_walk_args(); 1335*7c478bd9Sstevel@tonic-gate return (BAM_ERROR); 1336*7c478bd9Sstevel@tonic-gate } 1337*7c478bd9Sstevel@tonic-gate 1338*7c478bd9Sstevel@tonic-gate assert(flistp->head && flistp->tail); 1339*7c478bd9Sstevel@tonic-gate 1340*7c478bd9Sstevel@tonic-gate /* 1341*7c478bd9Sstevel@tonic-gate * At this point either the update is required 1342*7c478bd9Sstevel@tonic-gate * or the decision is pending. In either case 1343*7c478bd9Sstevel@tonic-gate * we need to create new stat nvlist 1344*7c478bd9Sstevel@tonic-gate */ 1345*7c478bd9Sstevel@tonic-gate create_newstat(); 1346*7c478bd9Sstevel@tonic-gate 1347*7c478bd9Sstevel@tonic-gate /* 1348*7c478bd9Sstevel@tonic-gate * This walk does 2 things: 1349*7c478bd9Sstevel@tonic-gate * - gets new stat data for every file 1350*7c478bd9Sstevel@tonic-gate * - (optional) compare old and new stat data 1351*7c478bd9Sstevel@tonic-gate */ 1352*7c478bd9Sstevel@tonic-gate walk_list(root, &flist); 1353*7c478bd9Sstevel@tonic-gate 1354*7c478bd9Sstevel@tonic-gate /* done with the file list */ 1355*7c478bd9Sstevel@tonic-gate filelist_free(flistp); 1356*7c478bd9Sstevel@tonic-gate 1357*7c478bd9Sstevel@tonic-gate /* 1358*7c478bd9Sstevel@tonic-gate * if we didn't succeed in creating new stat data above 1359*7c478bd9Sstevel@tonic-gate * just return result of update check so that archive is built. 1360*7c478bd9Sstevel@tonic-gate */ 1361*7c478bd9Sstevel@tonic-gate if (walk_arg.new_nvlp == NULL) { 1362*7c478bd9Sstevel@tonic-gate bam_error(NO_NEW_STAT); 1363*7c478bd9Sstevel@tonic-gate need_update = walk_arg.need_update; 1364*7c478bd9Sstevel@tonic-gate clear_walk_args(); 1365*7c478bd9Sstevel@tonic-gate return (need_update ? 1 : 0); 1366*7c478bd9Sstevel@tonic-gate } 1367*7c478bd9Sstevel@tonic-gate 1368*7c478bd9Sstevel@tonic-gate 1369*7c478bd9Sstevel@tonic-gate /* 1370*7c478bd9Sstevel@tonic-gate * If no update required, discard newstat 1371*7c478bd9Sstevel@tonic-gate */ 1372*7c478bd9Sstevel@tonic-gate if (!walk_arg.need_update) { 1373*7c478bd9Sstevel@tonic-gate clear_walk_args(); 1374*7c478bd9Sstevel@tonic-gate return (0); 1375*7c478bd9Sstevel@tonic-gate } 1376*7c478bd9Sstevel@tonic-gate 1377*7c478bd9Sstevel@tonic-gate /* 1378*7c478bd9Sstevel@tonic-gate * At this point we need an update - so save new stat data 1379*7c478bd9Sstevel@tonic-gate * However, if only checking (-n), don't save new stat data. 1380*7c478bd9Sstevel@tonic-gate */ 1381*7c478bd9Sstevel@tonic-gate if (!bam_check) 1382*7c478bd9Sstevel@tonic-gate savenew(root); 1383*7c478bd9Sstevel@tonic-gate 1384*7c478bd9Sstevel@tonic-gate clear_walk_args(); 1385*7c478bd9Sstevel@tonic-gate 1386*7c478bd9Sstevel@tonic-gate return (1); 1387*7c478bd9Sstevel@tonic-gate } 1388*7c478bd9Sstevel@tonic-gate 1389*7c478bd9Sstevel@tonic-gate static error_t 1390*7c478bd9Sstevel@tonic-gate create_ramdisk(char *root) 1391*7c478bd9Sstevel@tonic-gate { 1392*7c478bd9Sstevel@tonic-gate char *cmdline, path[PATH_MAX]; 1393*7c478bd9Sstevel@tonic-gate size_t len; 1394*7c478bd9Sstevel@tonic-gate struct stat sb; 1395*7c478bd9Sstevel@tonic-gate 1396*7c478bd9Sstevel@tonic-gate /* 1397*7c478bd9Sstevel@tonic-gate * Setup command args for create_ramdisk.ksh 1398*7c478bd9Sstevel@tonic-gate */ 1399*7c478bd9Sstevel@tonic-gate (void) snprintf(path, sizeof (path), "%s%s", root, CREATE_RAMDISK); 1400*7c478bd9Sstevel@tonic-gate if (stat(path, &sb) != 0) { 1401*7c478bd9Sstevel@tonic-gate bam_error(ARCH_EXEC_MISS, path, strerror(errno)); 1402*7c478bd9Sstevel@tonic-gate return (BAM_ERROR); 1403*7c478bd9Sstevel@tonic-gate } 1404*7c478bd9Sstevel@tonic-gate 1405*7c478bd9Sstevel@tonic-gate len = strlen(path) + strlen(root) + 10; /* room for space + -R */ 1406*7c478bd9Sstevel@tonic-gate cmdline = s_calloc(1, len); 1407*7c478bd9Sstevel@tonic-gate 1408*7c478bd9Sstevel@tonic-gate if (strlen(root) > 1) { 1409*7c478bd9Sstevel@tonic-gate (void) snprintf(cmdline, len, "%s -R %s", path, root); 1410*7c478bd9Sstevel@tonic-gate /* chop off / at the end */ 1411*7c478bd9Sstevel@tonic-gate cmdline[strlen(cmdline) - 1] = '\0'; 1412*7c478bd9Sstevel@tonic-gate } else 1413*7c478bd9Sstevel@tonic-gate (void) snprintf(cmdline, len, "%s", path); 1414*7c478bd9Sstevel@tonic-gate 1415*7c478bd9Sstevel@tonic-gate if (exec_cmd(cmdline, NULL, 0) != 0) { 1416*7c478bd9Sstevel@tonic-gate bam_error(ARCHIVE_FAIL, cmdline); 1417*7c478bd9Sstevel@tonic-gate free(cmdline); 1418*7c478bd9Sstevel@tonic-gate return (BAM_ERROR); 1419*7c478bd9Sstevel@tonic-gate } 1420*7c478bd9Sstevel@tonic-gate free(cmdline); 1421*7c478bd9Sstevel@tonic-gate 1422*7c478bd9Sstevel@tonic-gate /* 1423*7c478bd9Sstevel@tonic-gate * Verify that the archive has been created 1424*7c478bd9Sstevel@tonic-gate */ 1425*7c478bd9Sstevel@tonic-gate (void) snprintf(path, sizeof (path), "%s%s", root, BOOT_ARCHIVE); 1426*7c478bd9Sstevel@tonic-gate if (stat(path, &sb) != 0) { 1427*7c478bd9Sstevel@tonic-gate bam_error(ARCHIVE_NOT_CREATED, path); 1428*7c478bd9Sstevel@tonic-gate return (BAM_ERROR); 1429*7c478bd9Sstevel@tonic-gate } 1430*7c478bd9Sstevel@tonic-gate 1431*7c478bd9Sstevel@tonic-gate return (BAM_SUCCESS); 1432*7c478bd9Sstevel@tonic-gate } 1433*7c478bd9Sstevel@tonic-gate 1434*7c478bd9Sstevel@tonic-gate /* 1435*7c478bd9Sstevel@tonic-gate * Checks if target filesystem is on a ramdisk 1436*7c478bd9Sstevel@tonic-gate * 1 - is miniroot 1437*7c478bd9Sstevel@tonic-gate * 0 - is not 1438*7c478bd9Sstevel@tonic-gate * When in doubt assume it is not a ramdisk. 1439*7c478bd9Sstevel@tonic-gate */ 1440*7c478bd9Sstevel@tonic-gate static int 1441*7c478bd9Sstevel@tonic-gate is_ramdisk(char *root) 1442*7c478bd9Sstevel@tonic-gate { 1443*7c478bd9Sstevel@tonic-gate struct extmnttab mnt; 1444*7c478bd9Sstevel@tonic-gate FILE *fp; 1445*7c478bd9Sstevel@tonic-gate int found; 1446*7c478bd9Sstevel@tonic-gate 1447*7c478bd9Sstevel@tonic-gate /* 1448*7c478bd9Sstevel@tonic-gate * There are 3 situations where creating archive is 1449*7c478bd9Sstevel@tonic-gate * of dubious value: 1450*7c478bd9Sstevel@tonic-gate * - create boot_archive on a boot_archive 1451*7c478bd9Sstevel@tonic-gate * - create it on a ramdisk which is the root filesystem 1452*7c478bd9Sstevel@tonic-gate * - create it on a ramdisk mounted somewhere else 1453*7c478bd9Sstevel@tonic-gate * The first is not easy to detect and checking for it is not 1454*7c478bd9Sstevel@tonic-gate * worth it. 1455*7c478bd9Sstevel@tonic-gate * The other two conditions are handled here 1456*7c478bd9Sstevel@tonic-gate */ 1457*7c478bd9Sstevel@tonic-gate 1458*7c478bd9Sstevel@tonic-gate fp = fopen(MNTTAB, "r"); 1459*7c478bd9Sstevel@tonic-gate if (fp == NULL) { 1460*7c478bd9Sstevel@tonic-gate bam_error(OPEN_FAIL, MNTTAB, strerror(errno)); 1461*7c478bd9Sstevel@tonic-gate return (0); 1462*7c478bd9Sstevel@tonic-gate } 1463*7c478bd9Sstevel@tonic-gate 1464*7c478bd9Sstevel@tonic-gate resetmnttab(fp); 1465*7c478bd9Sstevel@tonic-gate 1466*7c478bd9Sstevel@tonic-gate found = 0; 1467*7c478bd9Sstevel@tonic-gate while (getextmntent(fp, &mnt, sizeof (mnt)) == 0) { 1468*7c478bd9Sstevel@tonic-gate if (strcmp(mnt.mnt_mountp, root) == 0) { 1469*7c478bd9Sstevel@tonic-gate found = 1; 1470*7c478bd9Sstevel@tonic-gate break; 1471*7c478bd9Sstevel@tonic-gate } 1472*7c478bd9Sstevel@tonic-gate } 1473*7c478bd9Sstevel@tonic-gate 1474*7c478bd9Sstevel@tonic-gate if (!found) { 1475*7c478bd9Sstevel@tonic-gate if (bam_verbose) 1476*7c478bd9Sstevel@tonic-gate bam_error(NOT_IN_MNTTAB, root); 1477*7c478bd9Sstevel@tonic-gate (void) fclose(fp); 1478*7c478bd9Sstevel@tonic-gate return (0); 1479*7c478bd9Sstevel@tonic-gate } 1480*7c478bd9Sstevel@tonic-gate 1481*7c478bd9Sstevel@tonic-gate if (strstr(mnt.mnt_special, RAMDISK_SPECIAL) != NULL) { 1482*7c478bd9Sstevel@tonic-gate if (bam_verbose) 1483*7c478bd9Sstevel@tonic-gate bam_error(IS_RAMDISK, bam_root); 1484*7c478bd9Sstevel@tonic-gate (void) fclose(fp); 1485*7c478bd9Sstevel@tonic-gate return (1); 1486*7c478bd9Sstevel@tonic-gate } 1487*7c478bd9Sstevel@tonic-gate 1488*7c478bd9Sstevel@tonic-gate (void) fclose(fp); 1489*7c478bd9Sstevel@tonic-gate 1490*7c478bd9Sstevel@tonic-gate return (0); 1491*7c478bd9Sstevel@tonic-gate } 1492*7c478bd9Sstevel@tonic-gate 1493*7c478bd9Sstevel@tonic-gate static int 1494*7c478bd9Sstevel@tonic-gate is_newboot(char *root) 1495*7c478bd9Sstevel@tonic-gate { 1496*7c478bd9Sstevel@tonic-gate char path[PATH_MAX]; 1497*7c478bd9Sstevel@tonic-gate struct stat sb; 1498*7c478bd9Sstevel@tonic-gate 1499*7c478bd9Sstevel@tonic-gate /* 1500*7c478bd9Sstevel@tonic-gate * We can't boot without MULTI_BOOT 1501*7c478bd9Sstevel@tonic-gate */ 1502*7c478bd9Sstevel@tonic-gate (void) snprintf(path, sizeof (path), "%s%s", root, MULTI_BOOT); 1503*7c478bd9Sstevel@tonic-gate if (stat(path, &sb) == -1) { 1504*7c478bd9Sstevel@tonic-gate if (bam_verbose) 1505*7c478bd9Sstevel@tonic-gate bam_print(FILE_MISS, path); 1506*7c478bd9Sstevel@tonic-gate return (0); 1507*7c478bd9Sstevel@tonic-gate } 1508*7c478bd9Sstevel@tonic-gate 1509*7c478bd9Sstevel@tonic-gate /* 1510*7c478bd9Sstevel@tonic-gate * We can't generate archive without GRUB_DIR 1511*7c478bd9Sstevel@tonic-gate */ 1512*7c478bd9Sstevel@tonic-gate (void) snprintf(path, sizeof (path), "%s%s", root, GRUB_DIR); 1513*7c478bd9Sstevel@tonic-gate if (stat(path, &sb) == -1) { 1514*7c478bd9Sstevel@tonic-gate if (bam_verbose) 1515*7c478bd9Sstevel@tonic-gate bam_print(DIR_MISS, path); 1516*7c478bd9Sstevel@tonic-gate return (0); 1517*7c478bd9Sstevel@tonic-gate } 1518*7c478bd9Sstevel@tonic-gate 1519*7c478bd9Sstevel@tonic-gate return (1); 1520*7c478bd9Sstevel@tonic-gate } 1521*7c478bd9Sstevel@tonic-gate 1522*7c478bd9Sstevel@tonic-gate static int 1523*7c478bd9Sstevel@tonic-gate is_readonly(char *root) 1524*7c478bd9Sstevel@tonic-gate { 1525*7c478bd9Sstevel@tonic-gate struct statvfs vfs; 1526*7c478bd9Sstevel@tonic-gate 1527*7c478bd9Sstevel@tonic-gate /* 1528*7c478bd9Sstevel@tonic-gate * Check for RDONLY filesystem 1529*7c478bd9Sstevel@tonic-gate * When in doubt assume it is not readonly 1530*7c478bd9Sstevel@tonic-gate */ 1531*7c478bd9Sstevel@tonic-gate if (statvfs(root, &vfs) != 0) { 1532*7c478bd9Sstevel@tonic-gate if (bam_verbose) 1533*7c478bd9Sstevel@tonic-gate bam_error(STATVFS_FAIL, root, strerror(errno)); 1534*7c478bd9Sstevel@tonic-gate return (0); 1535*7c478bd9Sstevel@tonic-gate } 1536*7c478bd9Sstevel@tonic-gate 1537*7c478bd9Sstevel@tonic-gate if (vfs.f_flag & ST_RDONLY) { 1538*7c478bd9Sstevel@tonic-gate return (1); 1539*7c478bd9Sstevel@tonic-gate } 1540*7c478bd9Sstevel@tonic-gate 1541*7c478bd9Sstevel@tonic-gate return (0); 1542*7c478bd9Sstevel@tonic-gate } 1543*7c478bd9Sstevel@tonic-gate 1544*7c478bd9Sstevel@tonic-gate static error_t 1545*7c478bd9Sstevel@tonic-gate update_archive(char *root, char *opt) 1546*7c478bd9Sstevel@tonic-gate { 1547*7c478bd9Sstevel@tonic-gate error_t ret; 1548*7c478bd9Sstevel@tonic-gate 1549*7c478bd9Sstevel@tonic-gate assert(root); 1550*7c478bd9Sstevel@tonic-gate assert(opt == NULL); 1551*7c478bd9Sstevel@tonic-gate 1552*7c478bd9Sstevel@tonic-gate /* 1553*7c478bd9Sstevel@tonic-gate * root must belong to a newboot OS, 1554*7c478bd9Sstevel@tonic-gate * don't care on sparc except for diskless clients 1555*7c478bd9Sstevel@tonic-gate */ 1556*7c478bd9Sstevel@tonic-gate if (!is_newboot(root)) { 1557*7c478bd9Sstevel@tonic-gate if (bam_verbose) 1558*7c478bd9Sstevel@tonic-gate bam_print(NOT_NEWBOOT); 1559*7c478bd9Sstevel@tonic-gate return (BAM_SUCCESS); 1560*7c478bd9Sstevel@tonic-gate } 1561*7c478bd9Sstevel@tonic-gate 1562*7c478bd9Sstevel@tonic-gate /* 1563*7c478bd9Sstevel@tonic-gate * root must be writable 1564*7c478bd9Sstevel@tonic-gate * Note: statvfs() does not always report the truth 1565*7c478bd9Sstevel@tonic-gate */ 1566*7c478bd9Sstevel@tonic-gate if (is_readonly(root)) { 1567*7c478bd9Sstevel@tonic-gate if (!bam_smf_check && bam_verbose) 1568*7c478bd9Sstevel@tonic-gate bam_print(RDONLY_FS, root); 1569*7c478bd9Sstevel@tonic-gate return (BAM_SUCCESS); 1570*7c478bd9Sstevel@tonic-gate } 1571*7c478bd9Sstevel@tonic-gate 1572*7c478bd9Sstevel@tonic-gate /* 1573*7c478bd9Sstevel@tonic-gate * Don't generate archive on ramdisk 1574*7c478bd9Sstevel@tonic-gate */ 1575*7c478bd9Sstevel@tonic-gate if (is_ramdisk(root)) { 1576*7c478bd9Sstevel@tonic-gate if (bam_verbose) 1577*7c478bd9Sstevel@tonic-gate bam_print(SKIP_RAMDISK); 1578*7c478bd9Sstevel@tonic-gate return (BAM_SUCCESS); 1579*7c478bd9Sstevel@tonic-gate } 1580*7c478bd9Sstevel@tonic-gate 1581*7c478bd9Sstevel@tonic-gate /* 1582*7c478bd9Sstevel@tonic-gate * Now check if updated is really needed 1583*7c478bd9Sstevel@tonic-gate */ 1584*7c478bd9Sstevel@tonic-gate ret = update_required(root); 1585*7c478bd9Sstevel@tonic-gate 1586*7c478bd9Sstevel@tonic-gate /* 1587*7c478bd9Sstevel@tonic-gate * The check command (-n) is *not* a dry run 1588*7c478bd9Sstevel@tonic-gate * It only checks if the archive is in sync. 1589*7c478bd9Sstevel@tonic-gate */ 1590*7c478bd9Sstevel@tonic-gate if (bam_check) { 1591*7c478bd9Sstevel@tonic-gate bam_exit((ret != 0) ? 1 : 0); 1592*7c478bd9Sstevel@tonic-gate } 1593*7c478bd9Sstevel@tonic-gate 1594*7c478bd9Sstevel@tonic-gate if (ret == 1) { 1595*7c478bd9Sstevel@tonic-gate /* create the ramdisk */ 1596*7c478bd9Sstevel@tonic-gate ret = create_ramdisk(root); 1597*7c478bd9Sstevel@tonic-gate } 1598*7c478bd9Sstevel@tonic-gate return (ret); 1599*7c478bd9Sstevel@tonic-gate } 1600*7c478bd9Sstevel@tonic-gate 1601*7c478bd9Sstevel@tonic-gate static error_t 1602*7c478bd9Sstevel@tonic-gate update_all(char *root, char *opt) 1603*7c478bd9Sstevel@tonic-gate { 1604*7c478bd9Sstevel@tonic-gate struct extmnttab mnt; 1605*7c478bd9Sstevel@tonic-gate struct stat sb; 1606*7c478bd9Sstevel@tonic-gate FILE *fp; 1607*7c478bd9Sstevel@tonic-gate char multibt[PATH_MAX]; 1608*7c478bd9Sstevel@tonic-gate error_t ret = BAM_SUCCESS; 1609*7c478bd9Sstevel@tonic-gate 1610*7c478bd9Sstevel@tonic-gate assert(bam_rootlen == 1 && root[0] == '/'); 1611*7c478bd9Sstevel@tonic-gate assert(opt == NULL); 1612*7c478bd9Sstevel@tonic-gate 1613*7c478bd9Sstevel@tonic-gate /* 1614*7c478bd9Sstevel@tonic-gate * First update archive for current root 1615*7c478bd9Sstevel@tonic-gate */ 1616*7c478bd9Sstevel@tonic-gate if (update_archive(root, opt) != BAM_SUCCESS) 1617*7c478bd9Sstevel@tonic-gate ret = BAM_ERROR; 1618*7c478bd9Sstevel@tonic-gate 1619*7c478bd9Sstevel@tonic-gate /* 1620*7c478bd9Sstevel@tonic-gate * Now walk the mount table, performing archive update 1621*7c478bd9Sstevel@tonic-gate * for all mounted Newboot root filesystems 1622*7c478bd9Sstevel@tonic-gate */ 1623*7c478bd9Sstevel@tonic-gate fp = fopen(MNTTAB, "r"); 1624*7c478bd9Sstevel@tonic-gate if (fp == NULL) { 1625*7c478bd9Sstevel@tonic-gate bam_error(OPEN_FAIL, MNTTAB, strerror(errno)); 1626*7c478bd9Sstevel@tonic-gate return (BAM_ERROR); 1627*7c478bd9Sstevel@tonic-gate } 1628*7c478bd9Sstevel@tonic-gate 1629*7c478bd9Sstevel@tonic-gate resetmnttab(fp); 1630*7c478bd9Sstevel@tonic-gate 1631*7c478bd9Sstevel@tonic-gate while (getextmntent(fp, &mnt, sizeof (mnt)) == 0) { 1632*7c478bd9Sstevel@tonic-gate if (mnt.mnt_special == NULL) 1633*7c478bd9Sstevel@tonic-gate continue; 1634*7c478bd9Sstevel@tonic-gate if (strncmp(mnt.mnt_special, "/dev/", strlen("/dev/")) != 0) 1635*7c478bd9Sstevel@tonic-gate continue; 1636*7c478bd9Sstevel@tonic-gate if (strcmp(mnt.mnt_mountp, "/") == 0) 1637*7c478bd9Sstevel@tonic-gate continue; 1638*7c478bd9Sstevel@tonic-gate 1639*7c478bd9Sstevel@tonic-gate (void) snprintf(multibt, sizeof (multibt), "%s%s", 1640*7c478bd9Sstevel@tonic-gate mnt.mnt_mountp, MULTI_BOOT); 1641*7c478bd9Sstevel@tonic-gate 1642*7c478bd9Sstevel@tonic-gate if (stat(multibt, &sb) == -1) 1643*7c478bd9Sstevel@tonic-gate continue; 1644*7c478bd9Sstevel@tonic-gate 1645*7c478bd9Sstevel@tonic-gate /* 1646*7c478bd9Sstevel@tonic-gate * We put a trailing slash to be consistent with root = "/" 1647*7c478bd9Sstevel@tonic-gate * case, such that we don't have to print // in some cases. 1648*7c478bd9Sstevel@tonic-gate */ 1649*7c478bd9Sstevel@tonic-gate (void) snprintf(rootbuf, sizeof (rootbuf), "%s/", 1650*7c478bd9Sstevel@tonic-gate mnt.mnt_mountp); 1651*7c478bd9Sstevel@tonic-gate bam_rootlen = strlen(rootbuf); 1652*7c478bd9Sstevel@tonic-gate if (update_archive(rootbuf, opt) != BAM_SUCCESS) 1653*7c478bd9Sstevel@tonic-gate ret = BAM_ERROR; 1654*7c478bd9Sstevel@tonic-gate } 1655*7c478bd9Sstevel@tonic-gate 1656*7c478bd9Sstevel@tonic-gate (void) fclose(fp); 1657*7c478bd9Sstevel@tonic-gate 1658*7c478bd9Sstevel@tonic-gate return (ret); 1659*7c478bd9Sstevel@tonic-gate } 1660*7c478bd9Sstevel@tonic-gate 1661*7c478bd9Sstevel@tonic-gate static void 1662*7c478bd9Sstevel@tonic-gate append_line(menu_t *mp, line_t *lp) 1663*7c478bd9Sstevel@tonic-gate { 1664*7c478bd9Sstevel@tonic-gate if (mp->start == NULL) { 1665*7c478bd9Sstevel@tonic-gate mp->start = lp; 1666*7c478bd9Sstevel@tonic-gate } else { 1667*7c478bd9Sstevel@tonic-gate mp->end->next = lp; 1668*7c478bd9Sstevel@tonic-gate } 1669*7c478bd9Sstevel@tonic-gate mp->end = lp; 1670*7c478bd9Sstevel@tonic-gate } 1671*7c478bd9Sstevel@tonic-gate 1672*7c478bd9Sstevel@tonic-gate /* 1673*7c478bd9Sstevel@tonic-gate * A line in menu.lst looks like 1674*7c478bd9Sstevel@tonic-gate * [ ]*<cmd>[ \t=]*<arg>* 1675*7c478bd9Sstevel@tonic-gate */ 1676*7c478bd9Sstevel@tonic-gate static void 1677*7c478bd9Sstevel@tonic-gate line_parser(menu_t *mp, char *str, int *lineNum, int *entryNum) 1678*7c478bd9Sstevel@tonic-gate { 1679*7c478bd9Sstevel@tonic-gate /* 1680*7c478bd9Sstevel@tonic-gate * save state across calls. This is so that 1681*7c478bd9Sstevel@tonic-gate * header gets the right entry# after title has 1682*7c478bd9Sstevel@tonic-gate * been processed 1683*7c478bd9Sstevel@tonic-gate */ 1684*7c478bd9Sstevel@tonic-gate static line_t *prev; 1685*7c478bd9Sstevel@tonic-gate 1686*7c478bd9Sstevel@tonic-gate line_t *lp; 1687*7c478bd9Sstevel@tonic-gate char *cmd, *sep, *arg; 1688*7c478bd9Sstevel@tonic-gate char save, *cp, *line; 1689*7c478bd9Sstevel@tonic-gate menu_flag_t flag = BAM_INVALID; 1690*7c478bd9Sstevel@tonic-gate 1691*7c478bd9Sstevel@tonic-gate if (str == NULL) { 1692*7c478bd9Sstevel@tonic-gate return; 1693*7c478bd9Sstevel@tonic-gate } 1694*7c478bd9Sstevel@tonic-gate 1695*7c478bd9Sstevel@tonic-gate /* 1696*7c478bd9Sstevel@tonic-gate * First save a copy of the entire line. 1697*7c478bd9Sstevel@tonic-gate * We use this later to set the line field. 1698*7c478bd9Sstevel@tonic-gate */ 1699*7c478bd9Sstevel@tonic-gate line = s_strdup(str); 1700*7c478bd9Sstevel@tonic-gate 1701*7c478bd9Sstevel@tonic-gate /* Eat up leading whitespace */ 1702*7c478bd9Sstevel@tonic-gate while (*str == ' ' || *str == '\t') 1703*7c478bd9Sstevel@tonic-gate str++; 1704*7c478bd9Sstevel@tonic-gate 1705*7c478bd9Sstevel@tonic-gate if (*str == '#') { /* comment */ 1706*7c478bd9Sstevel@tonic-gate cmd = s_strdup("#"); 1707*7c478bd9Sstevel@tonic-gate sep = NULL; 1708*7c478bd9Sstevel@tonic-gate arg = s_strdup(str + 1); 1709*7c478bd9Sstevel@tonic-gate flag = BAM_COMMENT; 1710*7c478bd9Sstevel@tonic-gate } else if (*str == '\0') { /* blank line */ 1711*7c478bd9Sstevel@tonic-gate cmd = sep = arg = NULL; 1712*7c478bd9Sstevel@tonic-gate flag = BAM_EMPTY; 1713*7c478bd9Sstevel@tonic-gate } else { 1714*7c478bd9Sstevel@tonic-gate /* 1715*7c478bd9Sstevel@tonic-gate * '=' is not a documented separator in grub syntax. 1716*7c478bd9Sstevel@tonic-gate * However various development bits use '=' as a 1717*7c478bd9Sstevel@tonic-gate * separator. In addition, external users also 1718*7c478bd9Sstevel@tonic-gate * use = as a separator. So we will allow that usage. 1719*7c478bd9Sstevel@tonic-gate */ 1720*7c478bd9Sstevel@tonic-gate cp = str; 1721*7c478bd9Sstevel@tonic-gate while (*str != ' ' && *str != '\t' && *str != '=') { 1722*7c478bd9Sstevel@tonic-gate if (*str == '\0') { 1723*7c478bd9Sstevel@tonic-gate cmd = s_strdup(cp); 1724*7c478bd9Sstevel@tonic-gate sep = arg = NULL; 1725*7c478bd9Sstevel@tonic-gate break; 1726*7c478bd9Sstevel@tonic-gate } 1727*7c478bd9Sstevel@tonic-gate str++; 1728*7c478bd9Sstevel@tonic-gate } 1729*7c478bd9Sstevel@tonic-gate 1730*7c478bd9Sstevel@tonic-gate if (*str != '\0') { 1731*7c478bd9Sstevel@tonic-gate save = *str; 1732*7c478bd9Sstevel@tonic-gate *str = '\0'; 1733*7c478bd9Sstevel@tonic-gate cmd = s_strdup(cp); 1734*7c478bd9Sstevel@tonic-gate *str = save; 1735*7c478bd9Sstevel@tonic-gate 1736*7c478bd9Sstevel@tonic-gate str++; 1737*7c478bd9Sstevel@tonic-gate save = *str; 1738*7c478bd9Sstevel@tonic-gate *str = '\0'; 1739*7c478bd9Sstevel@tonic-gate sep = s_strdup(str - 1); 1740*7c478bd9Sstevel@tonic-gate *str = save; 1741*7c478bd9Sstevel@tonic-gate 1742*7c478bd9Sstevel@tonic-gate while (*str == ' ' || *str == '\t') 1743*7c478bd9Sstevel@tonic-gate str++; 1744*7c478bd9Sstevel@tonic-gate if (*str == '\0') 1745*7c478bd9Sstevel@tonic-gate arg = NULL; 1746*7c478bd9Sstevel@tonic-gate else 1747*7c478bd9Sstevel@tonic-gate arg = s_strdup(str); 1748*7c478bd9Sstevel@tonic-gate } 1749*7c478bd9Sstevel@tonic-gate } 1750*7c478bd9Sstevel@tonic-gate 1751*7c478bd9Sstevel@tonic-gate lp = s_calloc(1, sizeof (line_t)); 1752*7c478bd9Sstevel@tonic-gate 1753*7c478bd9Sstevel@tonic-gate lp->cmd = cmd; 1754*7c478bd9Sstevel@tonic-gate lp->sep = sep; 1755*7c478bd9Sstevel@tonic-gate lp->arg = arg; 1756*7c478bd9Sstevel@tonic-gate lp->line = line; 1757*7c478bd9Sstevel@tonic-gate lp->lineNum = ++(*lineNum); 1758*7c478bd9Sstevel@tonic-gate if (cmd && strcmp(cmd, menu_cmds[TITLE_CMD]) == 0) { 1759*7c478bd9Sstevel@tonic-gate lp->entryNum = ++(*entryNum); 1760*7c478bd9Sstevel@tonic-gate lp->flags = BAM_TITLE; 1761*7c478bd9Sstevel@tonic-gate if (prev && prev->flags == BAM_COMMENT && 1762*7c478bd9Sstevel@tonic-gate prev->arg && strcmp(prev->arg, BAM_HDR) == 0) 1763*7c478bd9Sstevel@tonic-gate prev->entryNum = lp->entryNum; 1764*7c478bd9Sstevel@tonic-gate } else if (flag != BAM_INVALID) { 1765*7c478bd9Sstevel@tonic-gate /* 1766*7c478bd9Sstevel@tonic-gate * For header comments, the entry# is "fixed up" 1767*7c478bd9Sstevel@tonic-gate * by the subsequent title 1768*7c478bd9Sstevel@tonic-gate */ 1769*7c478bd9Sstevel@tonic-gate lp->entryNum = *entryNum; 1770*7c478bd9Sstevel@tonic-gate lp->flags = flag; 1771*7c478bd9Sstevel@tonic-gate } else { 1772*7c478bd9Sstevel@tonic-gate lp->entryNum = *entryNum; 1773*7c478bd9Sstevel@tonic-gate lp->flags = (*entryNum == ENTRY_INIT) ? BAM_GLOBAL : BAM_ENTRY; 1774*7c478bd9Sstevel@tonic-gate } 1775*7c478bd9Sstevel@tonic-gate 1776*7c478bd9Sstevel@tonic-gate append_line(mp, lp); 1777*7c478bd9Sstevel@tonic-gate 1778*7c478bd9Sstevel@tonic-gate prev = lp; 1779*7c478bd9Sstevel@tonic-gate } 1780*7c478bd9Sstevel@tonic-gate 1781*7c478bd9Sstevel@tonic-gate static menu_t * 1782*7c478bd9Sstevel@tonic-gate menu_read(char *menu_path) 1783*7c478bd9Sstevel@tonic-gate { 1784*7c478bd9Sstevel@tonic-gate FILE *fp; 1785*7c478bd9Sstevel@tonic-gate char buf[BAM_MAXLINE], *cp; 1786*7c478bd9Sstevel@tonic-gate menu_t *mp; 1787*7c478bd9Sstevel@tonic-gate int line, entry, len, n; 1788*7c478bd9Sstevel@tonic-gate 1789*7c478bd9Sstevel@tonic-gate mp = s_calloc(1, sizeof (menu_t)); 1790*7c478bd9Sstevel@tonic-gate 1791*7c478bd9Sstevel@tonic-gate fp = fopen(menu_path, "r"); 1792*7c478bd9Sstevel@tonic-gate if (fp == NULL) { /* Let the caller handle this error */ 1793*7c478bd9Sstevel@tonic-gate return (mp); 1794*7c478bd9Sstevel@tonic-gate } 1795*7c478bd9Sstevel@tonic-gate 1796*7c478bd9Sstevel@tonic-gate 1797*7c478bd9Sstevel@tonic-gate /* Note: GRUB boot entry number starts with 0 */ 1798*7c478bd9Sstevel@tonic-gate line = LINE_INIT; 1799*7c478bd9Sstevel@tonic-gate entry = ENTRY_INIT; 1800*7c478bd9Sstevel@tonic-gate cp = buf; 1801*7c478bd9Sstevel@tonic-gate len = sizeof (buf); 1802*7c478bd9Sstevel@tonic-gate while (s_fgets(cp, len, fp) != NULL) { 1803*7c478bd9Sstevel@tonic-gate n = strlen(cp); 1804*7c478bd9Sstevel@tonic-gate if (cp[n - 1] == '\\') { 1805*7c478bd9Sstevel@tonic-gate len -= n - 1; 1806*7c478bd9Sstevel@tonic-gate assert(len >= 2); 1807*7c478bd9Sstevel@tonic-gate cp += n - 1; 1808*7c478bd9Sstevel@tonic-gate continue; 1809*7c478bd9Sstevel@tonic-gate } 1810*7c478bd9Sstevel@tonic-gate line_parser(mp, buf, &line, &entry); 1811*7c478bd9Sstevel@tonic-gate cp = buf; 1812*7c478bd9Sstevel@tonic-gate len = sizeof (buf); 1813*7c478bd9Sstevel@tonic-gate } 1814*7c478bd9Sstevel@tonic-gate 1815*7c478bd9Sstevel@tonic-gate if (fclose(fp) == EOF) { 1816*7c478bd9Sstevel@tonic-gate bam_error(CLOSE_FAIL, menu_path, strerror(errno)); 1817*7c478bd9Sstevel@tonic-gate } 1818*7c478bd9Sstevel@tonic-gate 1819*7c478bd9Sstevel@tonic-gate return (mp); 1820*7c478bd9Sstevel@tonic-gate } 1821*7c478bd9Sstevel@tonic-gate 1822*7c478bd9Sstevel@tonic-gate static error_t 1823*7c478bd9Sstevel@tonic-gate selector(menu_t *mp, char *opt, int *entry, char **title) 1824*7c478bd9Sstevel@tonic-gate { 1825*7c478bd9Sstevel@tonic-gate char *eq; 1826*7c478bd9Sstevel@tonic-gate char *opt_dup; 1827*7c478bd9Sstevel@tonic-gate int entryNum; 1828*7c478bd9Sstevel@tonic-gate 1829*7c478bd9Sstevel@tonic-gate assert(mp); 1830*7c478bd9Sstevel@tonic-gate assert(mp->start); 1831*7c478bd9Sstevel@tonic-gate assert(opt); 1832*7c478bd9Sstevel@tonic-gate 1833*7c478bd9Sstevel@tonic-gate opt_dup = s_strdup(opt); 1834*7c478bd9Sstevel@tonic-gate 1835*7c478bd9Sstevel@tonic-gate if (entry) 1836*7c478bd9Sstevel@tonic-gate *entry = ENTRY_INIT; 1837*7c478bd9Sstevel@tonic-gate if (title) 1838*7c478bd9Sstevel@tonic-gate *title = NULL; 1839*7c478bd9Sstevel@tonic-gate 1840*7c478bd9Sstevel@tonic-gate eq = strchr(opt_dup, '='); 1841*7c478bd9Sstevel@tonic-gate if (eq == NULL) { 1842*7c478bd9Sstevel@tonic-gate bam_error(INVALID_OPT, opt); 1843*7c478bd9Sstevel@tonic-gate free(opt_dup); 1844*7c478bd9Sstevel@tonic-gate return (BAM_ERROR); 1845*7c478bd9Sstevel@tonic-gate } 1846*7c478bd9Sstevel@tonic-gate 1847*7c478bd9Sstevel@tonic-gate *eq = '\0'; 1848*7c478bd9Sstevel@tonic-gate if (entry && strcmp(opt_dup, OPT_ENTRY_NUM) == 0) { 1849*7c478bd9Sstevel@tonic-gate assert(mp->end); 1850*7c478bd9Sstevel@tonic-gate entryNum = s_strtol(eq + 1); 1851*7c478bd9Sstevel@tonic-gate if (entryNum < 0 || entryNum > mp->end->entryNum) { 1852*7c478bd9Sstevel@tonic-gate bam_error(INVALID_ENTRY, eq + 1); 1853*7c478bd9Sstevel@tonic-gate free(opt_dup); 1854*7c478bd9Sstevel@tonic-gate return (BAM_ERROR); 1855*7c478bd9Sstevel@tonic-gate } 1856*7c478bd9Sstevel@tonic-gate *entry = entryNum; 1857*7c478bd9Sstevel@tonic-gate } else if (title && strcmp(opt_dup, menu_cmds[TITLE_CMD]) == 0) { 1858*7c478bd9Sstevel@tonic-gate *title = opt + (eq - opt_dup) + 1; 1859*7c478bd9Sstevel@tonic-gate } else { 1860*7c478bd9Sstevel@tonic-gate bam_error(INVALID_OPT, opt); 1861*7c478bd9Sstevel@tonic-gate free(opt_dup); 1862*7c478bd9Sstevel@tonic-gate return (BAM_ERROR); 1863*7c478bd9Sstevel@tonic-gate } 1864*7c478bd9Sstevel@tonic-gate 1865*7c478bd9Sstevel@tonic-gate free(opt_dup); 1866*7c478bd9Sstevel@tonic-gate return (BAM_SUCCESS); 1867*7c478bd9Sstevel@tonic-gate } 1868*7c478bd9Sstevel@tonic-gate 1869*7c478bd9Sstevel@tonic-gate /* 1870*7c478bd9Sstevel@tonic-gate * If invoked with no titles/entries (opt == NULL) 1871*7c478bd9Sstevel@tonic-gate * only title lines in file are printed. 1872*7c478bd9Sstevel@tonic-gate * 1873*7c478bd9Sstevel@tonic-gate * If invoked with a title or entry #, all 1874*7c478bd9Sstevel@tonic-gate * lines in *every* matching entry are listed 1875*7c478bd9Sstevel@tonic-gate */ 1876*7c478bd9Sstevel@tonic-gate static error_t 1877*7c478bd9Sstevel@tonic-gate list_entry(menu_t *mp, char *menu_path, char *opt) 1878*7c478bd9Sstevel@tonic-gate { 1879*7c478bd9Sstevel@tonic-gate line_t *lp; 1880*7c478bd9Sstevel@tonic-gate int entry = ENTRY_INIT; 1881*7c478bd9Sstevel@tonic-gate int found; 1882*7c478bd9Sstevel@tonic-gate char *title = NULL; 1883*7c478bd9Sstevel@tonic-gate 1884*7c478bd9Sstevel@tonic-gate assert(mp); 1885*7c478bd9Sstevel@tonic-gate assert(menu_path); 1886*7c478bd9Sstevel@tonic-gate 1887*7c478bd9Sstevel@tonic-gate if (mp->start == NULL) { 1888*7c478bd9Sstevel@tonic-gate bam_error(NO_MENU, menu_path); 1889*7c478bd9Sstevel@tonic-gate return (BAM_ERROR); 1890*7c478bd9Sstevel@tonic-gate } 1891*7c478bd9Sstevel@tonic-gate 1892*7c478bd9Sstevel@tonic-gate if (opt != NULL) { 1893*7c478bd9Sstevel@tonic-gate if (selector(mp, opt, &entry, &title) != BAM_SUCCESS) { 1894*7c478bd9Sstevel@tonic-gate return (BAM_ERROR); 1895*7c478bd9Sstevel@tonic-gate } 1896*7c478bd9Sstevel@tonic-gate assert((entry != ENTRY_INIT) ^ (title != NULL)); 1897*7c478bd9Sstevel@tonic-gate } else { 1898*7c478bd9Sstevel@tonic-gate (void) read_globals(mp, menu_path, menu_cmds[DEFAULT_CMD], 0); 1899*7c478bd9Sstevel@tonic-gate (void) read_globals(mp, menu_path, menu_cmds[TIMEOUT_CMD], 0); 1900*7c478bd9Sstevel@tonic-gate } 1901*7c478bd9Sstevel@tonic-gate 1902*7c478bd9Sstevel@tonic-gate found = 0; 1903*7c478bd9Sstevel@tonic-gate for (lp = mp->start; lp; lp = lp->next) { 1904*7c478bd9Sstevel@tonic-gate if (lp->flags == BAM_COMMENT || lp->flags == BAM_EMPTY) 1905*7c478bd9Sstevel@tonic-gate continue; 1906*7c478bd9Sstevel@tonic-gate if (opt == NULL && lp->flags == BAM_TITLE) { 1907*7c478bd9Sstevel@tonic-gate bam_print(PRINT_TITLE, lp->entryNum, 1908*7c478bd9Sstevel@tonic-gate lp->arg); 1909*7c478bd9Sstevel@tonic-gate found = 1; 1910*7c478bd9Sstevel@tonic-gate continue; 1911*7c478bd9Sstevel@tonic-gate } 1912*7c478bd9Sstevel@tonic-gate if (entry != ENTRY_INIT && lp->entryNum == entry) { 1913*7c478bd9Sstevel@tonic-gate bam_print(PRINT, lp->line); 1914*7c478bd9Sstevel@tonic-gate found = 1; 1915*7c478bd9Sstevel@tonic-gate continue; 1916*7c478bd9Sstevel@tonic-gate } 1917*7c478bd9Sstevel@tonic-gate 1918*7c478bd9Sstevel@tonic-gate /* 1919*7c478bd9Sstevel@tonic-gate * We set the entry value here so that all lines 1920*7c478bd9Sstevel@tonic-gate * in entry get printed. If we subsequently match 1921*7c478bd9Sstevel@tonic-gate * title in other entries, all lines in those 1922*7c478bd9Sstevel@tonic-gate * entries get printed as well. 1923*7c478bd9Sstevel@tonic-gate */ 1924*7c478bd9Sstevel@tonic-gate if (title && lp->flags == BAM_TITLE && lp->arg && 1925*7c478bd9Sstevel@tonic-gate strncmp(title, lp->arg, strlen(title)) == 0) { 1926*7c478bd9Sstevel@tonic-gate bam_print(PRINT, lp->line); 1927*7c478bd9Sstevel@tonic-gate entry = lp->entryNum; 1928*7c478bd9Sstevel@tonic-gate found = 1; 1929*7c478bd9Sstevel@tonic-gate continue; 1930*7c478bd9Sstevel@tonic-gate } 1931*7c478bd9Sstevel@tonic-gate } 1932*7c478bd9Sstevel@tonic-gate 1933*7c478bd9Sstevel@tonic-gate if (!found) { 1934*7c478bd9Sstevel@tonic-gate bam_error(NO_MATCH_ENTRY); 1935*7c478bd9Sstevel@tonic-gate return (BAM_ERROR); 1936*7c478bd9Sstevel@tonic-gate } 1937*7c478bd9Sstevel@tonic-gate 1938*7c478bd9Sstevel@tonic-gate return (BAM_SUCCESS); 1939*7c478bd9Sstevel@tonic-gate } 1940*7c478bd9Sstevel@tonic-gate 1941*7c478bd9Sstevel@tonic-gate static int 1942*7c478bd9Sstevel@tonic-gate add_boot_entry(menu_t *mp, 1943*7c478bd9Sstevel@tonic-gate char *title, 1944*7c478bd9Sstevel@tonic-gate char *root, 1945*7c478bd9Sstevel@tonic-gate char *kernel, 1946*7c478bd9Sstevel@tonic-gate char *module) 1947*7c478bd9Sstevel@tonic-gate { 1948*7c478bd9Sstevel@tonic-gate menu_t dummy; 1949*7c478bd9Sstevel@tonic-gate int lineNum, entryNum; 1950*7c478bd9Sstevel@tonic-gate char linebuf[BAM_MAXLINE]; 1951*7c478bd9Sstevel@tonic-gate 1952*7c478bd9Sstevel@tonic-gate assert(mp); 1953*7c478bd9Sstevel@tonic-gate 1954*7c478bd9Sstevel@tonic-gate if (title == NULL) { 1955*7c478bd9Sstevel@tonic-gate bam_error(SUBOPT_MISS, menu_cmds[TITLE_CMD]); 1956*7c478bd9Sstevel@tonic-gate return (BAM_ERROR); 1957*7c478bd9Sstevel@tonic-gate } 1958*7c478bd9Sstevel@tonic-gate if (root == NULL) { 1959*7c478bd9Sstevel@tonic-gate bam_error(SUBOPT_MISS, menu_cmds[ROOT_CMD]); 1960*7c478bd9Sstevel@tonic-gate return (BAM_ERROR); 1961*7c478bd9Sstevel@tonic-gate } 1962*7c478bd9Sstevel@tonic-gate if (kernel == NULL) { 1963*7c478bd9Sstevel@tonic-gate bam_error(SUBOPT_MISS, menu_cmds[KERNEL_CMD]); 1964*7c478bd9Sstevel@tonic-gate return (BAM_ERROR); 1965*7c478bd9Sstevel@tonic-gate } 1966*7c478bd9Sstevel@tonic-gate if (module == NULL) { 1967*7c478bd9Sstevel@tonic-gate bam_error(SUBOPT_MISS, menu_cmds[MODULE_CMD]); 1968*7c478bd9Sstevel@tonic-gate return (BAM_ERROR); 1969*7c478bd9Sstevel@tonic-gate } 1970*7c478bd9Sstevel@tonic-gate 1971*7c478bd9Sstevel@tonic-gate if (mp->start) { 1972*7c478bd9Sstevel@tonic-gate lineNum = mp->end->lineNum; 1973*7c478bd9Sstevel@tonic-gate entryNum = mp->end->entryNum; 1974*7c478bd9Sstevel@tonic-gate } else { 1975*7c478bd9Sstevel@tonic-gate lineNum = LINE_INIT; 1976*7c478bd9Sstevel@tonic-gate entryNum = ENTRY_INIT; 1977*7c478bd9Sstevel@tonic-gate } 1978*7c478bd9Sstevel@tonic-gate 1979*7c478bd9Sstevel@tonic-gate /* 1980*7c478bd9Sstevel@tonic-gate * No separator for comment (HDR/FTR) commands 1981*7c478bd9Sstevel@tonic-gate * The syntax for comments is #<comment> 1982*7c478bd9Sstevel@tonic-gate */ 1983*7c478bd9Sstevel@tonic-gate (void) snprintf(linebuf, sizeof (linebuf), "%s%s", 1984*7c478bd9Sstevel@tonic-gate menu_cmds[COMMENT_CMD], BAM_HDR); 1985*7c478bd9Sstevel@tonic-gate dummy.start = dummy.end = NULL; 1986*7c478bd9Sstevel@tonic-gate line_parser(&dummy, linebuf, &lineNum, &entryNum); 1987*7c478bd9Sstevel@tonic-gate if (dummy.start == NULL || dummy.start->flags != BAM_COMMENT) { 1988*7c478bd9Sstevel@tonic-gate line_free(dummy.start); 1989*7c478bd9Sstevel@tonic-gate bam_error(INVALID_HDR, BAM_HDR); 1990*7c478bd9Sstevel@tonic-gate return (BAM_ERROR); 1991*7c478bd9Sstevel@tonic-gate } 1992*7c478bd9Sstevel@tonic-gate assert(dummy.start == dummy.end); 1993*7c478bd9Sstevel@tonic-gate append_line(mp, dummy.start); 1994*7c478bd9Sstevel@tonic-gate 1995*7c478bd9Sstevel@tonic-gate (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s", 1996*7c478bd9Sstevel@tonic-gate menu_cmds[TITLE_CMD], menu_cmds[SEP_CMD], title); 1997*7c478bd9Sstevel@tonic-gate dummy.start = dummy.end = NULL; 1998*7c478bd9Sstevel@tonic-gate line_parser(&dummy, linebuf, &lineNum, &entryNum); 1999*7c478bd9Sstevel@tonic-gate if (dummy.start == NULL || dummy.start->flags != BAM_TITLE) { 2000*7c478bd9Sstevel@tonic-gate line_free(dummy.start); 2001*7c478bd9Sstevel@tonic-gate bam_error(INVALID_TITLE, title); 2002*7c478bd9Sstevel@tonic-gate return (BAM_ERROR); 2003*7c478bd9Sstevel@tonic-gate } 2004*7c478bd9Sstevel@tonic-gate assert(dummy.start == dummy.end); 2005*7c478bd9Sstevel@tonic-gate append_line(mp, dummy.start); 2006*7c478bd9Sstevel@tonic-gate 2007*7c478bd9Sstevel@tonic-gate 2008*7c478bd9Sstevel@tonic-gate (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s", 2009*7c478bd9Sstevel@tonic-gate menu_cmds[ROOT_CMD], menu_cmds[SEP_CMD], root); 2010*7c478bd9Sstevel@tonic-gate dummy.start = dummy.end = NULL; 2011*7c478bd9Sstevel@tonic-gate line_parser(&dummy, linebuf, &lineNum, &entryNum); 2012*7c478bd9Sstevel@tonic-gate if (dummy.start == NULL || dummy.start->flags != BAM_ENTRY) { 2013*7c478bd9Sstevel@tonic-gate line_free(dummy.start); 2014*7c478bd9Sstevel@tonic-gate bam_error(INVALID_ROOT, root); 2015*7c478bd9Sstevel@tonic-gate return (BAM_ERROR); 2016*7c478bd9Sstevel@tonic-gate } 2017*7c478bd9Sstevel@tonic-gate assert(dummy.start == dummy.end); 2018*7c478bd9Sstevel@tonic-gate append_line(mp, dummy.start); 2019*7c478bd9Sstevel@tonic-gate 2020*7c478bd9Sstevel@tonic-gate 2021*7c478bd9Sstevel@tonic-gate (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s", 2022*7c478bd9Sstevel@tonic-gate menu_cmds[KERNEL_CMD], menu_cmds[SEP_CMD], kernel); 2023*7c478bd9Sstevel@tonic-gate dummy.start = dummy.end = NULL; 2024*7c478bd9Sstevel@tonic-gate line_parser(&dummy, linebuf, &lineNum, &entryNum); 2025*7c478bd9Sstevel@tonic-gate if (dummy.start == NULL || dummy.start->flags != BAM_ENTRY) { 2026*7c478bd9Sstevel@tonic-gate line_free(dummy.start); 2027*7c478bd9Sstevel@tonic-gate bam_error(INVALID_KERNEL, kernel); 2028*7c478bd9Sstevel@tonic-gate return (BAM_ERROR); 2029*7c478bd9Sstevel@tonic-gate } 2030*7c478bd9Sstevel@tonic-gate assert(dummy.start == dummy.end); 2031*7c478bd9Sstevel@tonic-gate append_line(mp, dummy.start); 2032*7c478bd9Sstevel@tonic-gate 2033*7c478bd9Sstevel@tonic-gate (void) snprintf(linebuf, sizeof (linebuf), "%s%s%s", 2034*7c478bd9Sstevel@tonic-gate menu_cmds[MODULE_CMD], menu_cmds[SEP_CMD], module); 2035*7c478bd9Sstevel@tonic-gate dummy.start = dummy.end = NULL; 2036*7c478bd9Sstevel@tonic-gate line_parser(&dummy, linebuf, &lineNum, &entryNum); 2037*7c478bd9Sstevel@tonic-gate if (dummy.start == NULL || dummy.start->flags != BAM_ENTRY) { 2038*7c478bd9Sstevel@tonic-gate line_free(dummy.start); 2039*7c478bd9Sstevel@tonic-gate bam_error(INVALID_MODULE, module); 2040*7c478bd9Sstevel@tonic-gate return (BAM_ERROR); 2041*7c478bd9Sstevel@tonic-gate } 2042*7c478bd9Sstevel@tonic-gate assert(dummy.start == dummy.end); 2043*7c478bd9Sstevel@tonic-gate append_line(mp, dummy.start); 2044*7c478bd9Sstevel@tonic-gate 2045*7c478bd9Sstevel@tonic-gate (void) snprintf(linebuf, sizeof (linebuf), "%s%s", 2046*7c478bd9Sstevel@tonic-gate menu_cmds[COMMENT_CMD], BAM_FTR); 2047*7c478bd9Sstevel@tonic-gate dummy.start = dummy.end = NULL; 2048*7c478bd9Sstevel@tonic-gate line_parser(&dummy, linebuf, &lineNum, &entryNum); 2049*7c478bd9Sstevel@tonic-gate if (dummy.start == NULL || dummy.start->flags != BAM_COMMENT) { 2050*7c478bd9Sstevel@tonic-gate line_free(dummy.start); 2051*7c478bd9Sstevel@tonic-gate bam_error(INVALID_FOOTER, BAM_FTR); 2052*7c478bd9Sstevel@tonic-gate return (BAM_ERROR); 2053*7c478bd9Sstevel@tonic-gate } 2054*7c478bd9Sstevel@tonic-gate assert(dummy.start == dummy.end); 2055*7c478bd9Sstevel@tonic-gate append_line(mp, dummy.start); 2056*7c478bd9Sstevel@tonic-gate 2057*7c478bd9Sstevel@tonic-gate return (entryNum); 2058*7c478bd9Sstevel@tonic-gate } 2059*7c478bd9Sstevel@tonic-gate 2060*7c478bd9Sstevel@tonic-gate static error_t 2061*7c478bd9Sstevel@tonic-gate do_delete(menu_t *mp, int entryNum) 2062*7c478bd9Sstevel@tonic-gate { 2063*7c478bd9Sstevel@tonic-gate int bootadm_entry = 0; 2064*7c478bd9Sstevel@tonic-gate line_t *lp, *prev, *save; 2065*7c478bd9Sstevel@tonic-gate int deleted; 2066*7c478bd9Sstevel@tonic-gate 2067*7c478bd9Sstevel@tonic-gate assert(entryNum != ENTRY_INIT); 2068*7c478bd9Sstevel@tonic-gate 2069*7c478bd9Sstevel@tonic-gate deleted = 0; 2070*7c478bd9Sstevel@tonic-gate prev = NULL; 2071*7c478bd9Sstevel@tonic-gate for (lp = mp->start; lp; ) { 2072*7c478bd9Sstevel@tonic-gate 2073*7c478bd9Sstevel@tonic-gate if (lp->entryNum == ENTRY_INIT) { 2074*7c478bd9Sstevel@tonic-gate prev = lp; 2075*7c478bd9Sstevel@tonic-gate lp = lp->next; 2076*7c478bd9Sstevel@tonic-gate continue; 2077*7c478bd9Sstevel@tonic-gate } 2078*7c478bd9Sstevel@tonic-gate 2079*7c478bd9Sstevel@tonic-gate if (entryNum != ALL_ENTRIES && lp->entryNum != entryNum) { 2080*7c478bd9Sstevel@tonic-gate prev = lp; 2081*7c478bd9Sstevel@tonic-gate lp = lp->next; 2082*7c478bd9Sstevel@tonic-gate continue; 2083*7c478bd9Sstevel@tonic-gate } 2084*7c478bd9Sstevel@tonic-gate 2085*7c478bd9Sstevel@tonic-gate /* 2086*7c478bd9Sstevel@tonic-gate * can only delete bootadm entries 2087*7c478bd9Sstevel@tonic-gate */ 2088*7c478bd9Sstevel@tonic-gate if (lp->flags == BAM_COMMENT && strcmp(lp->arg, BAM_HDR) == 0) { 2089*7c478bd9Sstevel@tonic-gate bootadm_entry = 1; 2090*7c478bd9Sstevel@tonic-gate } 2091*7c478bd9Sstevel@tonic-gate 2092*7c478bd9Sstevel@tonic-gate if (!bootadm_entry) { 2093*7c478bd9Sstevel@tonic-gate prev = lp; 2094*7c478bd9Sstevel@tonic-gate lp = lp->next; 2095*7c478bd9Sstevel@tonic-gate continue; 2096*7c478bd9Sstevel@tonic-gate } 2097*7c478bd9Sstevel@tonic-gate 2098*7c478bd9Sstevel@tonic-gate if (lp->flags == BAM_COMMENT && strcmp(lp->arg, BAM_FTR) == 0) 2099*7c478bd9Sstevel@tonic-gate bootadm_entry = 0; 2100*7c478bd9Sstevel@tonic-gate 2101*7c478bd9Sstevel@tonic-gate if (prev == NULL) 2102*7c478bd9Sstevel@tonic-gate mp->start = lp->next; 2103*7c478bd9Sstevel@tonic-gate else 2104*7c478bd9Sstevel@tonic-gate prev->next = lp->next; 2105*7c478bd9Sstevel@tonic-gate if (mp->end == lp) 2106*7c478bd9Sstevel@tonic-gate mp->end = prev; 2107*7c478bd9Sstevel@tonic-gate save = lp->next; 2108*7c478bd9Sstevel@tonic-gate line_free(lp); 2109*7c478bd9Sstevel@tonic-gate lp = save; /* prev stays the same */ 2110*7c478bd9Sstevel@tonic-gate 2111*7c478bd9Sstevel@tonic-gate deleted = 1; 2112*7c478bd9Sstevel@tonic-gate } 2113*7c478bd9Sstevel@tonic-gate 2114*7c478bd9Sstevel@tonic-gate if (!deleted && entryNum != ALL_ENTRIES) { 2115*7c478bd9Sstevel@tonic-gate bam_error(NO_BOOTADM_MATCH); 2116*7c478bd9Sstevel@tonic-gate return (BAM_ERROR); 2117*7c478bd9Sstevel@tonic-gate } 2118*7c478bd9Sstevel@tonic-gate 2119*7c478bd9Sstevel@tonic-gate return (BAM_SUCCESS); 2120*7c478bd9Sstevel@tonic-gate } 2121*7c478bd9Sstevel@tonic-gate 2122*7c478bd9Sstevel@tonic-gate static error_t 2123*7c478bd9Sstevel@tonic-gate delete_entry(menu_t *mp, char *menu_path, char *opt) 2124*7c478bd9Sstevel@tonic-gate { 2125*7c478bd9Sstevel@tonic-gate int entry = ENTRY_INIT; 2126*7c478bd9Sstevel@tonic-gate char *title = NULL; 2127*7c478bd9Sstevel@tonic-gate line_t *lp; 2128*7c478bd9Sstevel@tonic-gate 2129*7c478bd9Sstevel@tonic-gate assert(mp); 2130*7c478bd9Sstevel@tonic-gate assert(opt); 2131*7c478bd9Sstevel@tonic-gate 2132*7c478bd9Sstevel@tonic-gate /* 2133*7c478bd9Sstevel@tonic-gate * Do a quick check. If the file is empty 2134*7c478bd9Sstevel@tonic-gate * we have nothing to delete 2135*7c478bd9Sstevel@tonic-gate */ 2136*7c478bd9Sstevel@tonic-gate if (mp->start == NULL) { 2137*7c478bd9Sstevel@tonic-gate bam_print(EMPTY_FILE, menu_path); 2138*7c478bd9Sstevel@tonic-gate return (BAM_SUCCESS); 2139*7c478bd9Sstevel@tonic-gate } 2140*7c478bd9Sstevel@tonic-gate 2141*7c478bd9Sstevel@tonic-gate if (selector(mp, opt, &entry, &title) != BAM_SUCCESS) { 2142*7c478bd9Sstevel@tonic-gate return (BAM_ERROR); 2143*7c478bd9Sstevel@tonic-gate } 2144*7c478bd9Sstevel@tonic-gate assert((entry != ENTRY_INIT) ^ (title != NULL)); 2145*7c478bd9Sstevel@tonic-gate 2146*7c478bd9Sstevel@tonic-gate for (lp = mp->start; lp; lp = lp->next) { 2147*7c478bd9Sstevel@tonic-gate if (entry != ENTRY_INIT) 2148*7c478bd9Sstevel@tonic-gate break; 2149*7c478bd9Sstevel@tonic-gate assert(title); 2150*7c478bd9Sstevel@tonic-gate if (lp->flags == BAM_TITLE && 2151*7c478bd9Sstevel@tonic-gate lp->arg && strcmp(lp->arg, title) == 0) { 2152*7c478bd9Sstevel@tonic-gate entry = lp->entryNum; 2153*7c478bd9Sstevel@tonic-gate break; 2154*7c478bd9Sstevel@tonic-gate } 2155*7c478bd9Sstevel@tonic-gate } 2156*7c478bd9Sstevel@tonic-gate 2157*7c478bd9Sstevel@tonic-gate if (entry == ENTRY_INIT) { 2158*7c478bd9Sstevel@tonic-gate bam_error(NO_MATCH, title); 2159*7c478bd9Sstevel@tonic-gate return (BAM_ERROR); 2160*7c478bd9Sstevel@tonic-gate } 2161*7c478bd9Sstevel@tonic-gate 2162*7c478bd9Sstevel@tonic-gate if (do_delete(mp, entry) != BAM_SUCCESS) { 2163*7c478bd9Sstevel@tonic-gate return (BAM_ERROR); 2164*7c478bd9Sstevel@tonic-gate } 2165*7c478bd9Sstevel@tonic-gate 2166*7c478bd9Sstevel@tonic-gate return (BAM_WRITE); 2167*7c478bd9Sstevel@tonic-gate } 2168*7c478bd9Sstevel@tonic-gate 2169*7c478bd9Sstevel@tonic-gate static error_t 2170*7c478bd9Sstevel@tonic-gate delete_all_entries(menu_t *mp, char *menu_path, char *opt) 2171*7c478bd9Sstevel@tonic-gate { 2172*7c478bd9Sstevel@tonic-gate assert(mp); 2173*7c478bd9Sstevel@tonic-gate assert(opt == NULL); 2174*7c478bd9Sstevel@tonic-gate 2175*7c478bd9Sstevel@tonic-gate if (mp->start == NULL) { 2176*7c478bd9Sstevel@tonic-gate bam_print(EMPTY_FILE, menu_path); 2177*7c478bd9Sstevel@tonic-gate return (BAM_SUCCESS); 2178*7c478bd9Sstevel@tonic-gate } 2179*7c478bd9Sstevel@tonic-gate 2180*7c478bd9Sstevel@tonic-gate if (do_delete(mp, ALL_ENTRIES) != BAM_SUCCESS) { 2181*7c478bd9Sstevel@tonic-gate return (BAM_ERROR); 2182*7c478bd9Sstevel@tonic-gate } 2183*7c478bd9Sstevel@tonic-gate 2184*7c478bd9Sstevel@tonic-gate return (BAM_WRITE); 2185*7c478bd9Sstevel@tonic-gate } 2186*7c478bd9Sstevel@tonic-gate 2187*7c478bd9Sstevel@tonic-gate static FILE * 2188*7c478bd9Sstevel@tonic-gate open_diskmap(void) 2189*7c478bd9Sstevel@tonic-gate { 2190*7c478bd9Sstevel@tonic-gate FILE *fp; 2191*7c478bd9Sstevel@tonic-gate char cmd[PATH_MAX]; 2192*7c478bd9Sstevel@tonic-gate 2193*7c478bd9Sstevel@tonic-gate /* make sure we have a map file */ 2194*7c478bd9Sstevel@tonic-gate fp = fopen(GRUBDISK_MAP, "r"); 2195*7c478bd9Sstevel@tonic-gate if (fp == NULL) { 2196*7c478bd9Sstevel@tonic-gate (void) snprintf(cmd, sizeof (cmd), 2197*7c478bd9Sstevel@tonic-gate "%s > /dev/null", CREATE_DISKMAP); 2198*7c478bd9Sstevel@tonic-gate (void) system(cmd); 2199*7c478bd9Sstevel@tonic-gate fp = fopen(GRUBDISK_MAP, "r"); 2200*7c478bd9Sstevel@tonic-gate } 2201*7c478bd9Sstevel@tonic-gate return (fp); 2202*7c478bd9Sstevel@tonic-gate } 2203*7c478bd9Sstevel@tonic-gate 2204*7c478bd9Sstevel@tonic-gate #define SECTOR_SIZE 512 2205*7c478bd9Sstevel@tonic-gate 2206*7c478bd9Sstevel@tonic-gate static int 2207*7c478bd9Sstevel@tonic-gate get_partition(char *device) 2208*7c478bd9Sstevel@tonic-gate { 2209*7c478bd9Sstevel@tonic-gate int i, fd, is_pcfs, partno = -1; 2210*7c478bd9Sstevel@tonic-gate struct mboot *mboot; 2211*7c478bd9Sstevel@tonic-gate char boot_sect[SECTOR_SIZE]; 2212*7c478bd9Sstevel@tonic-gate char *wholedisk, *slice; 2213*7c478bd9Sstevel@tonic-gate 2214*7c478bd9Sstevel@tonic-gate /* form whole disk (p0) */ 2215*7c478bd9Sstevel@tonic-gate slice = device + strlen(device) - 2; 2216*7c478bd9Sstevel@tonic-gate is_pcfs = (*slice != 's'); 2217*7c478bd9Sstevel@tonic-gate if (!is_pcfs) 2218*7c478bd9Sstevel@tonic-gate *slice = '\0'; 2219*7c478bd9Sstevel@tonic-gate wholedisk = s_calloc(1, strlen(device) + 3); 2220*7c478bd9Sstevel@tonic-gate (void) snprintf(wholedisk, strlen(device) + 3, "%sp0", device); 2221*7c478bd9Sstevel@tonic-gate if (!is_pcfs) 2222*7c478bd9Sstevel@tonic-gate *slice = 's'; 2223*7c478bd9Sstevel@tonic-gate 2224*7c478bd9Sstevel@tonic-gate /* read boot sector */ 2225*7c478bd9Sstevel@tonic-gate fd = open(wholedisk, O_RDONLY); 2226*7c478bd9Sstevel@tonic-gate free(wholedisk); 2227*7c478bd9Sstevel@tonic-gate if (fd == -1 || read(fd, boot_sect, SECTOR_SIZE) != SECTOR_SIZE) { 2228*7c478bd9Sstevel@tonic-gate return (partno); 2229*7c478bd9Sstevel@tonic-gate } 2230*7c478bd9Sstevel@tonic-gate (void) close(fd); 2231*7c478bd9Sstevel@tonic-gate 2232*7c478bd9Sstevel@tonic-gate /* parse fdisk table */ 2233*7c478bd9Sstevel@tonic-gate mboot = (struct mboot *)((void *)boot_sect); 2234*7c478bd9Sstevel@tonic-gate for (i = 0; i < FD_NUMPART; i++) { 2235*7c478bd9Sstevel@tonic-gate struct ipart *part = 2236*7c478bd9Sstevel@tonic-gate (struct ipart *)(uintptr_t)mboot->parts + i; 2237*7c478bd9Sstevel@tonic-gate if (is_pcfs) { /* looking for solaris boot part */ 2238*7c478bd9Sstevel@tonic-gate if (part->systid == 0xbe) { 2239*7c478bd9Sstevel@tonic-gate partno = i; 2240*7c478bd9Sstevel@tonic-gate break; 2241*7c478bd9Sstevel@tonic-gate } 2242*7c478bd9Sstevel@tonic-gate } else { /* look for solaris partition, old and new */ 2243*7c478bd9Sstevel@tonic-gate if (part->systid == SUNIXOS || 2244*7c478bd9Sstevel@tonic-gate part->systid == SUNIXOS2) { 2245*7c478bd9Sstevel@tonic-gate partno = i; 2246*7c478bd9Sstevel@tonic-gate break; 2247*7c478bd9Sstevel@tonic-gate } 2248*7c478bd9Sstevel@tonic-gate } 2249*7c478bd9Sstevel@tonic-gate } 2250*7c478bd9Sstevel@tonic-gate return (partno); 2251*7c478bd9Sstevel@tonic-gate } 2252*7c478bd9Sstevel@tonic-gate 2253*7c478bd9Sstevel@tonic-gate static char * 2254*7c478bd9Sstevel@tonic-gate get_grubdisk(char *rootdev, FILE *fp, int on_bootdev) 2255*7c478bd9Sstevel@tonic-gate { 2256*7c478bd9Sstevel@tonic-gate char *grubdisk; /* (hd#,#,#) */ 2257*7c478bd9Sstevel@tonic-gate char *slice; 2258*7c478bd9Sstevel@tonic-gate char *grubhd; 2259*7c478bd9Sstevel@tonic-gate int fdiskpart; 2260*7c478bd9Sstevel@tonic-gate int found = 0; 2261*7c478bd9Sstevel@tonic-gate char *devname, *ctdname = strstr(rootdev, "dsk/"); 2262*7c478bd9Sstevel@tonic-gate char linebuf[PATH_MAX]; 2263*7c478bd9Sstevel@tonic-gate 2264*7c478bd9Sstevel@tonic-gate if (ctdname == NULL) 2265*7c478bd9Sstevel@tonic-gate return (NULL); 2266*7c478bd9Sstevel@tonic-gate 2267*7c478bd9Sstevel@tonic-gate ctdname += strlen("dsk/"); 2268*7c478bd9Sstevel@tonic-gate slice = strrchr(ctdname, 's'); 2269*7c478bd9Sstevel@tonic-gate if (slice) 2270*7c478bd9Sstevel@tonic-gate *slice = '\0'; 2271*7c478bd9Sstevel@tonic-gate 2272*7c478bd9Sstevel@tonic-gate rewind(fp); 2273*7c478bd9Sstevel@tonic-gate while (s_fgets(linebuf, sizeof (linebuf), fp) != NULL) { 2274*7c478bd9Sstevel@tonic-gate grubhd = strtok(linebuf, " \t\n"); 2275*7c478bd9Sstevel@tonic-gate if (grubhd) 2276*7c478bd9Sstevel@tonic-gate devname = strtok(NULL, " \t\n"); 2277*7c478bd9Sstevel@tonic-gate else 2278*7c478bd9Sstevel@tonic-gate devname = NULL; 2279*7c478bd9Sstevel@tonic-gate if (devname && strcmp(devname, ctdname) == 0) { 2280*7c478bd9Sstevel@tonic-gate found = 1; 2281*7c478bd9Sstevel@tonic-gate break; 2282*7c478bd9Sstevel@tonic-gate } 2283*7c478bd9Sstevel@tonic-gate } 2284*7c478bd9Sstevel@tonic-gate 2285*7c478bd9Sstevel@tonic-gate if (slice) 2286*7c478bd9Sstevel@tonic-gate *slice = 's'; 2287*7c478bd9Sstevel@tonic-gate 2288*7c478bd9Sstevel@tonic-gate if (found == 0) { 2289*7c478bd9Sstevel@tonic-gate if (bam_verbose) 2290*7c478bd9Sstevel@tonic-gate bam_print(DISKMAP_FAIL_NONFATAL, rootdev); 2291*7c478bd9Sstevel@tonic-gate grubhd = "0"; /* assume disk 0 if can't match */ 2292*7c478bd9Sstevel@tonic-gate } 2293*7c478bd9Sstevel@tonic-gate 2294*7c478bd9Sstevel@tonic-gate fdiskpart = get_partition(rootdev); 2295*7c478bd9Sstevel@tonic-gate if (fdiskpart == -1) 2296*7c478bd9Sstevel@tonic-gate return (NULL); 2297*7c478bd9Sstevel@tonic-gate 2298*7c478bd9Sstevel@tonic-gate grubdisk = s_calloc(1, 10); 2299*7c478bd9Sstevel@tonic-gate if (slice) { 2300*7c478bd9Sstevel@tonic-gate (void) snprintf(grubdisk, 10, "(hd%s,%d,%c)", 2301*7c478bd9Sstevel@tonic-gate grubhd, fdiskpart, slice[1] + 'a' - '0'); 2302*7c478bd9Sstevel@tonic-gate } else 2303*7c478bd9Sstevel@tonic-gate (void) snprintf(grubdisk, 10, "(hd%s,%d)", 2304*7c478bd9Sstevel@tonic-gate grubhd, fdiskpart); 2305*7c478bd9Sstevel@tonic-gate 2306*7c478bd9Sstevel@tonic-gate /* if root not on bootdev, change GRUB disk to 0 */ 2307*7c478bd9Sstevel@tonic-gate if (!on_bootdev) 2308*7c478bd9Sstevel@tonic-gate grubdisk[3] = '0'; 2309*7c478bd9Sstevel@tonic-gate return (grubdisk); 2310*7c478bd9Sstevel@tonic-gate } 2311*7c478bd9Sstevel@tonic-gate 2312*7c478bd9Sstevel@tonic-gate static char *get_title(char *rootdir) 2313*7c478bd9Sstevel@tonic-gate { 2314*7c478bd9Sstevel@tonic-gate static char title[80]; /* from /etc/release */ 2315*7c478bd9Sstevel@tonic-gate char *cp, release[PATH_MAX]; 2316*7c478bd9Sstevel@tonic-gate FILE *fp; 2317*7c478bd9Sstevel@tonic-gate 2318*7c478bd9Sstevel@tonic-gate /* open the /etc/release file */ 2319*7c478bd9Sstevel@tonic-gate (void) snprintf(release, sizeof (release), "%s/etc/release", rootdir); 2320*7c478bd9Sstevel@tonic-gate 2321*7c478bd9Sstevel@tonic-gate fp = fopen(release, "r"); 2322*7c478bd9Sstevel@tonic-gate if (fp == NULL) 2323*7c478bd9Sstevel@tonic-gate return ("Solaris"); /* default to Solaris */ 2324*7c478bd9Sstevel@tonic-gate 2325*7c478bd9Sstevel@tonic-gate while (s_fgets(title, sizeof (title), fp) != NULL) { 2326*7c478bd9Sstevel@tonic-gate cp = strstr(title, "Solaris"); 2327*7c478bd9Sstevel@tonic-gate if (cp) 2328*7c478bd9Sstevel@tonic-gate break; 2329*7c478bd9Sstevel@tonic-gate } 2330*7c478bd9Sstevel@tonic-gate (void) fclose(fp); 2331*7c478bd9Sstevel@tonic-gate return (cp); 2332*7c478bd9Sstevel@tonic-gate } 2333*7c478bd9Sstevel@tonic-gate 2334*7c478bd9Sstevel@tonic-gate static char * 2335*7c478bd9Sstevel@tonic-gate get_special(char *mountp) 2336*7c478bd9Sstevel@tonic-gate { 2337*7c478bd9Sstevel@tonic-gate FILE *mntfp; 2338*7c478bd9Sstevel@tonic-gate struct mnttab mp = {0}, mpref = {0}; 2339*7c478bd9Sstevel@tonic-gate 2340*7c478bd9Sstevel@tonic-gate mntfp = fopen(MNTTAB, "r"); 2341*7c478bd9Sstevel@tonic-gate if (mntfp == NULL) { 2342*7c478bd9Sstevel@tonic-gate return (0); 2343*7c478bd9Sstevel@tonic-gate } 2344*7c478bd9Sstevel@tonic-gate 2345*7c478bd9Sstevel@tonic-gate if (*mountp == '\0') 2346*7c478bd9Sstevel@tonic-gate mpref.mnt_mountp = "/"; 2347*7c478bd9Sstevel@tonic-gate else 2348*7c478bd9Sstevel@tonic-gate mpref.mnt_mountp = mountp; 2349*7c478bd9Sstevel@tonic-gate if (getmntany(mntfp, &mp, &mpref) != 0) { 2350*7c478bd9Sstevel@tonic-gate (void) fclose(mntfp); 2351*7c478bd9Sstevel@tonic-gate return (NULL); 2352*7c478bd9Sstevel@tonic-gate } 2353*7c478bd9Sstevel@tonic-gate (void) fclose(mntfp); 2354*7c478bd9Sstevel@tonic-gate 2355*7c478bd9Sstevel@tonic-gate return (s_strdup(mp.mnt_special)); 2356*7c478bd9Sstevel@tonic-gate } 2357*7c478bd9Sstevel@tonic-gate 2358*7c478bd9Sstevel@tonic-gate static char * 2359*7c478bd9Sstevel@tonic-gate os_to_grubdisk(char *osdisk, int on_bootdev) 2360*7c478bd9Sstevel@tonic-gate { 2361*7c478bd9Sstevel@tonic-gate FILE *fp; 2362*7c478bd9Sstevel@tonic-gate char *grubdisk; 2363*7c478bd9Sstevel@tonic-gate 2364*7c478bd9Sstevel@tonic-gate /* translate /dev/dsk name to grub disk name */ 2365*7c478bd9Sstevel@tonic-gate fp = open_diskmap(); 2366*7c478bd9Sstevel@tonic-gate if (fp == NULL) { 2367*7c478bd9Sstevel@tonic-gate bam_error(DISKMAP_FAIL, osdisk); 2368*7c478bd9Sstevel@tonic-gate return (NULL); 2369*7c478bd9Sstevel@tonic-gate } 2370*7c478bd9Sstevel@tonic-gate grubdisk = get_grubdisk(osdisk, fp, on_bootdev); 2371*7c478bd9Sstevel@tonic-gate (void) fclose(fp); 2372*7c478bd9Sstevel@tonic-gate return (grubdisk); 2373*7c478bd9Sstevel@tonic-gate } 2374*7c478bd9Sstevel@tonic-gate 2375*7c478bd9Sstevel@tonic-gate /* 2376*7c478bd9Sstevel@tonic-gate * Check if root is on the boot device 2377*7c478bd9Sstevel@tonic-gate * Return 0 (false) on error 2378*7c478bd9Sstevel@tonic-gate */ 2379*7c478bd9Sstevel@tonic-gate static int 2380*7c478bd9Sstevel@tonic-gate menu_on_bootdev(char *menu_root, FILE *fp) 2381*7c478bd9Sstevel@tonic-gate { 2382*7c478bd9Sstevel@tonic-gate int ret; 2383*7c478bd9Sstevel@tonic-gate char *grubhd, *bootp, *special; 2384*7c478bd9Sstevel@tonic-gate 2385*7c478bd9Sstevel@tonic-gate special = get_special(menu_root); 2386*7c478bd9Sstevel@tonic-gate if (special == NULL) 2387*7c478bd9Sstevel@tonic-gate return (0); 2388*7c478bd9Sstevel@tonic-gate bootp = strstr(special, "p0:boot"); 2389*7c478bd9Sstevel@tonic-gate if (bootp) 2390*7c478bd9Sstevel@tonic-gate *bootp = '\0'; 2391*7c478bd9Sstevel@tonic-gate grubhd = get_grubdisk(special, fp, 1); 2392*7c478bd9Sstevel@tonic-gate free(special); 2393*7c478bd9Sstevel@tonic-gate 2394*7c478bd9Sstevel@tonic-gate if (grubhd == NULL) 2395*7c478bd9Sstevel@tonic-gate return (0); 2396*7c478bd9Sstevel@tonic-gate ret = grubhd[3] == '0'; 2397*7c478bd9Sstevel@tonic-gate free(grubhd); 2398*7c478bd9Sstevel@tonic-gate return (ret); 2399*7c478bd9Sstevel@tonic-gate } 2400*7c478bd9Sstevel@tonic-gate 2401*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2402*7c478bd9Sstevel@tonic-gate static error_t 2403*7c478bd9Sstevel@tonic-gate update_entry(menu_t *mp, char *menu_root, char *opt) 2404*7c478bd9Sstevel@tonic-gate { 2405*7c478bd9Sstevel@tonic-gate FILE *fp; 2406*7c478bd9Sstevel@tonic-gate int entry; 2407*7c478bd9Sstevel@tonic-gate line_t *lp; 2408*7c478bd9Sstevel@tonic-gate char *grubdisk, *title, *osdev, *osroot; 2409*7c478bd9Sstevel@tonic-gate int bootadm_entry, entry_to_delete; 2410*7c478bd9Sstevel@tonic-gate 2411*7c478bd9Sstevel@tonic-gate assert(mp); 2412*7c478bd9Sstevel@tonic-gate assert(opt); 2413*7c478bd9Sstevel@tonic-gate 2414*7c478bd9Sstevel@tonic-gate osdev = strtok(opt, ","); 2415*7c478bd9Sstevel@tonic-gate osroot = strtok(NULL, ","); 2416*7c478bd9Sstevel@tonic-gate if (osroot == NULL) 2417*7c478bd9Sstevel@tonic-gate osroot = menu_root; 2418*7c478bd9Sstevel@tonic-gate title = get_title(osroot); 2419*7c478bd9Sstevel@tonic-gate 2420*7c478bd9Sstevel@tonic-gate /* translate /dev/dsk name to grub disk name */ 2421*7c478bd9Sstevel@tonic-gate fp = open_diskmap(); 2422*7c478bd9Sstevel@tonic-gate if (fp == NULL) { 2423*7c478bd9Sstevel@tonic-gate bam_error(DISKMAP_FAIL, osdev); 2424*7c478bd9Sstevel@tonic-gate return (BAM_ERROR); 2425*7c478bd9Sstevel@tonic-gate } 2426*7c478bd9Sstevel@tonic-gate grubdisk = get_grubdisk(osdev, fp, menu_on_bootdev(menu_root, fp)); 2427*7c478bd9Sstevel@tonic-gate (void) fclose(fp); 2428*7c478bd9Sstevel@tonic-gate if (grubdisk == NULL) { 2429*7c478bd9Sstevel@tonic-gate bam_error(DISKMAP_FAIL, osdev); 2430*7c478bd9Sstevel@tonic-gate return (BAM_ERROR); 2431*7c478bd9Sstevel@tonic-gate } 2432*7c478bd9Sstevel@tonic-gate 2433*7c478bd9Sstevel@tonic-gate /* delete existing entries with matching grub hd name */ 2434*7c478bd9Sstevel@tonic-gate for (;;) { 2435*7c478bd9Sstevel@tonic-gate entry_to_delete = -1; 2436*7c478bd9Sstevel@tonic-gate bootadm_entry = 0; 2437*7c478bd9Sstevel@tonic-gate for (lp = mp->start; lp; lp = lp->next) { 2438*7c478bd9Sstevel@tonic-gate /* 2439*7c478bd9Sstevel@tonic-gate * can only delete bootadm entries 2440*7c478bd9Sstevel@tonic-gate */ 2441*7c478bd9Sstevel@tonic-gate if (lp->flags == BAM_COMMENT) { 2442*7c478bd9Sstevel@tonic-gate if (strcmp(lp->arg, BAM_HDR) == 0) 2443*7c478bd9Sstevel@tonic-gate bootadm_entry = 1; 2444*7c478bd9Sstevel@tonic-gate else if (strcmp(lp->arg, BAM_FTR) == 0) 2445*7c478bd9Sstevel@tonic-gate bootadm_entry = 0; 2446*7c478bd9Sstevel@tonic-gate } 2447*7c478bd9Sstevel@tonic-gate 2448*7c478bd9Sstevel@tonic-gate if (bootadm_entry && lp->flags == BAM_ENTRY && 2449*7c478bd9Sstevel@tonic-gate strcmp(lp->cmd, menu_cmds[ROOT_CMD]) == 0 && 2450*7c478bd9Sstevel@tonic-gate strcmp(lp->arg, grubdisk) == 0) { 2451*7c478bd9Sstevel@tonic-gate entry_to_delete = lp->entryNum; 2452*7c478bd9Sstevel@tonic-gate } 2453*7c478bd9Sstevel@tonic-gate } 2454*7c478bd9Sstevel@tonic-gate if (entry_to_delete == -1) 2455*7c478bd9Sstevel@tonic-gate break; 2456*7c478bd9Sstevel@tonic-gate (void) do_delete(mp, entry_to_delete); 2457*7c478bd9Sstevel@tonic-gate } 2458*7c478bd9Sstevel@tonic-gate 2459*7c478bd9Sstevel@tonic-gate /* add the entry for normal Solaris */ 2460*7c478bd9Sstevel@tonic-gate entry = add_boot_entry(mp, title, grubdisk, 2461*7c478bd9Sstevel@tonic-gate "/platform/i86pc/multiboot", 2462*7c478bd9Sstevel@tonic-gate "/platform/i86pc/boot_archive"); 2463*7c478bd9Sstevel@tonic-gate 2464*7c478bd9Sstevel@tonic-gate /* add the entry for failsafe archive */ 2465*7c478bd9Sstevel@tonic-gate (void) add_boot_entry(mp, "Solaris failsafe", grubdisk, 2466*7c478bd9Sstevel@tonic-gate "/boot/multiboot kernel/unix -s", 2467*7c478bd9Sstevel@tonic-gate "/boot/x86.miniroot-safe"); 2468*7c478bd9Sstevel@tonic-gate free(grubdisk); 2469*7c478bd9Sstevel@tonic-gate 2470*7c478bd9Sstevel@tonic-gate if (entry == BAM_ERROR) { 2471*7c478bd9Sstevel@tonic-gate return (BAM_ERROR); 2472*7c478bd9Sstevel@tonic-gate } 2473*7c478bd9Sstevel@tonic-gate (void) set_global(mp, menu_cmds[DEFAULT_CMD], entry); 2474*7c478bd9Sstevel@tonic-gate return (BAM_WRITE); 2475*7c478bd9Sstevel@tonic-gate } 2476*7c478bd9Sstevel@tonic-gate 2477*7c478bd9Sstevel@tonic-gate /* 2478*7c478bd9Sstevel@tonic-gate * This function is for supporting reboot with args. 2479*7c478bd9Sstevel@tonic-gate * The opt value can be: 2480*7c478bd9Sstevel@tonic-gate * NULL delete temp entry, if present 2481*7c478bd9Sstevel@tonic-gate * entry=# switches default entry to 1 2482*7c478bd9Sstevel@tonic-gate * else treated as boot-args and setup a temperary menu entry 2483*7c478bd9Sstevel@tonic-gate * and make it the default 2484*7c478bd9Sstevel@tonic-gate */ 2485*7c478bd9Sstevel@tonic-gate #define REBOOT_TITLE "Solaris_reboot_transient" 2486*7c478bd9Sstevel@tonic-gate 2487*7c478bd9Sstevel@tonic-gate static error_t 2488*7c478bd9Sstevel@tonic-gate update_temp(menu_t *mp, char *menupath, char *opt) 2489*7c478bd9Sstevel@tonic-gate { 2490*7c478bd9Sstevel@tonic-gate int entry; 2491*7c478bd9Sstevel@tonic-gate char *grubdisk, *rootdev; 2492*7c478bd9Sstevel@tonic-gate char kernbuf[1024]; 2493*7c478bd9Sstevel@tonic-gate 2494*7c478bd9Sstevel@tonic-gate assert(mp); 2495*7c478bd9Sstevel@tonic-gate 2496*7c478bd9Sstevel@tonic-gate if (opt != NULL && 2497*7c478bd9Sstevel@tonic-gate strncmp(opt, "entry=", strlen("entry=")) == 0 && 2498*7c478bd9Sstevel@tonic-gate selector(mp, opt, &entry, NULL) == BAM_SUCCESS) { 2499*7c478bd9Sstevel@tonic-gate /* this is entry=# option */ 2500*7c478bd9Sstevel@tonic-gate return (set_global(mp, menu_cmds[DEFAULT_CMD], entry)); 2501*7c478bd9Sstevel@tonic-gate } 2502*7c478bd9Sstevel@tonic-gate 2503*7c478bd9Sstevel@tonic-gate /* If no option, delete exiting reboot menu entry */ 2504*7c478bd9Sstevel@tonic-gate if (opt == NULL) 2505*7c478bd9Sstevel@tonic-gate return (delete_entry(mp, menupath, "title="REBOOT_TITLE)); 2506*7c478bd9Sstevel@tonic-gate 2507*7c478bd9Sstevel@tonic-gate /* 2508*7c478bd9Sstevel@tonic-gate * add a new menu entry base on opt and make it the default 2509*7c478bd9Sstevel@tonic-gate * 1. First get root disk name from mnttab 2510*7c478bd9Sstevel@tonic-gate * 2. Translate disk name to grub name 2511*7c478bd9Sstevel@tonic-gate * 3. Add the new menu entry 2512*7c478bd9Sstevel@tonic-gate */ 2513*7c478bd9Sstevel@tonic-gate rootdev = get_special("/"); 2514*7c478bd9Sstevel@tonic-gate if (rootdev) { 2515*7c478bd9Sstevel@tonic-gate grubdisk = os_to_grubdisk(rootdev, 1); 2516*7c478bd9Sstevel@tonic-gate free(rootdev); 2517*7c478bd9Sstevel@tonic-gate } 2518*7c478bd9Sstevel@tonic-gate if (grubdisk == NULL) { 2519*7c478bd9Sstevel@tonic-gate return (BAM_ERROR); 2520*7c478bd9Sstevel@tonic-gate } 2521*7c478bd9Sstevel@tonic-gate 2522*7c478bd9Sstevel@tonic-gate /* add an entry for Solaris reboot */ 2523*7c478bd9Sstevel@tonic-gate (void) snprintf(kernbuf, sizeof (kernbuf), 2524*7c478bd9Sstevel@tonic-gate "/platform/i86pc/multiboot %s", opt); 2525*7c478bd9Sstevel@tonic-gate entry = add_boot_entry(mp, REBOOT_TITLE, grubdisk, kernbuf, 2526*7c478bd9Sstevel@tonic-gate "/platform/i86pc/boot_archive"); 2527*7c478bd9Sstevel@tonic-gate free(grubdisk); 2528*7c478bd9Sstevel@tonic-gate 2529*7c478bd9Sstevel@tonic-gate if (entry == BAM_ERROR) { 2530*7c478bd9Sstevel@tonic-gate return (BAM_ERROR); 2531*7c478bd9Sstevel@tonic-gate } 2532*7c478bd9Sstevel@tonic-gate (void) set_global(mp, menu_cmds[DEFAULT_CMD], entry); 2533*7c478bd9Sstevel@tonic-gate return (BAM_WRITE); 2534*7c478bd9Sstevel@tonic-gate } 2535*7c478bd9Sstevel@tonic-gate 2536*7c478bd9Sstevel@tonic-gate static error_t 2537*7c478bd9Sstevel@tonic-gate set_global(menu_t *mp, char *globalcmd, int val) 2538*7c478bd9Sstevel@tonic-gate { 2539*7c478bd9Sstevel@tonic-gate line_t *lp, *found, *last; 2540*7c478bd9Sstevel@tonic-gate char *cp, *str; 2541*7c478bd9Sstevel@tonic-gate char prefix[BAM_MAXLINE]; 2542*7c478bd9Sstevel@tonic-gate size_t len; 2543*7c478bd9Sstevel@tonic-gate 2544*7c478bd9Sstevel@tonic-gate assert(mp); 2545*7c478bd9Sstevel@tonic-gate assert(globalcmd); 2546*7c478bd9Sstevel@tonic-gate 2547*7c478bd9Sstevel@tonic-gate found = last = NULL; 2548*7c478bd9Sstevel@tonic-gate for (lp = mp->start; lp; lp = lp->next) { 2549*7c478bd9Sstevel@tonic-gate if (lp->flags != BAM_GLOBAL) 2550*7c478bd9Sstevel@tonic-gate continue; 2551*7c478bd9Sstevel@tonic-gate 2552*7c478bd9Sstevel@tonic-gate last = lp; /* track the last global found */ 2553*7c478bd9Sstevel@tonic-gate 2554*7c478bd9Sstevel@tonic-gate if (lp->cmd == NULL) { 2555*7c478bd9Sstevel@tonic-gate bam_error(NO_CMD, lp->lineNum); 2556*7c478bd9Sstevel@tonic-gate continue; 2557*7c478bd9Sstevel@tonic-gate } 2558*7c478bd9Sstevel@tonic-gate if (strcmp(globalcmd, lp->cmd) != 0) 2559*7c478bd9Sstevel@tonic-gate continue; 2560*7c478bd9Sstevel@tonic-gate 2561*7c478bd9Sstevel@tonic-gate if (found) { 2562*7c478bd9Sstevel@tonic-gate bam_error(DUP_CMD, globalcmd, lp->lineNum, bam_root); 2563*7c478bd9Sstevel@tonic-gate } 2564*7c478bd9Sstevel@tonic-gate found = lp; 2565*7c478bd9Sstevel@tonic-gate } 2566*7c478bd9Sstevel@tonic-gate 2567*7c478bd9Sstevel@tonic-gate if (found == NULL) { 2568*7c478bd9Sstevel@tonic-gate lp = s_calloc(1, sizeof (line_t)); 2569*7c478bd9Sstevel@tonic-gate if (last == NULL) { 2570*7c478bd9Sstevel@tonic-gate lp->next = mp->start; 2571*7c478bd9Sstevel@tonic-gate mp->start = lp; 2572*7c478bd9Sstevel@tonic-gate mp->end = (mp->end) ? mp->end : lp; 2573*7c478bd9Sstevel@tonic-gate } else { 2574*7c478bd9Sstevel@tonic-gate lp->next = last->next; 2575*7c478bd9Sstevel@tonic-gate last->next = lp; 2576*7c478bd9Sstevel@tonic-gate if (lp->next == NULL) 2577*7c478bd9Sstevel@tonic-gate mp->end = lp; 2578*7c478bd9Sstevel@tonic-gate } 2579*7c478bd9Sstevel@tonic-gate lp->flags = BAM_GLOBAL; /* other fields not needed for writes */ 2580*7c478bd9Sstevel@tonic-gate len = strlen(globalcmd) + strlen(menu_cmds[SEP_CMD]); 2581*7c478bd9Sstevel@tonic-gate len += 10; /* val < 10 digits */ 2582*7c478bd9Sstevel@tonic-gate lp->line = s_calloc(1, len); 2583*7c478bd9Sstevel@tonic-gate (void) snprintf(lp->line, len, "%s%s%d", 2584*7c478bd9Sstevel@tonic-gate globalcmd, menu_cmds[SEP_CMD], val); 2585*7c478bd9Sstevel@tonic-gate return (BAM_WRITE); 2586*7c478bd9Sstevel@tonic-gate } 2587*7c478bd9Sstevel@tonic-gate 2588*7c478bd9Sstevel@tonic-gate /* 2589*7c478bd9Sstevel@tonic-gate * We are changing an existing entry. Retain any prefix whitespace, 2590*7c478bd9Sstevel@tonic-gate * but overwrite everything else. This preserves tabs added for 2591*7c478bd9Sstevel@tonic-gate * readability. 2592*7c478bd9Sstevel@tonic-gate */ 2593*7c478bd9Sstevel@tonic-gate str = found->line; 2594*7c478bd9Sstevel@tonic-gate cp = prefix; 2595*7c478bd9Sstevel@tonic-gate while (*str == ' ' || *str == '\t') 2596*7c478bd9Sstevel@tonic-gate *(cp++) = *(str++); 2597*7c478bd9Sstevel@tonic-gate *cp = '\0'; /* Terminate prefix */ 2598*7c478bd9Sstevel@tonic-gate len = strlen(prefix) + strlen(globalcmd); 2599*7c478bd9Sstevel@tonic-gate len += strlen(menu_cmds[SEP_CMD]) + 10; 2600*7c478bd9Sstevel@tonic-gate 2601*7c478bd9Sstevel@tonic-gate free(found->line); 2602*7c478bd9Sstevel@tonic-gate found->line = s_calloc(1, len); 2603*7c478bd9Sstevel@tonic-gate (void) snprintf(found->line, len, 2604*7c478bd9Sstevel@tonic-gate "%s%s%s%d", prefix, globalcmd, menu_cmds[SEP_CMD], val); 2605*7c478bd9Sstevel@tonic-gate 2606*7c478bd9Sstevel@tonic-gate return (BAM_WRITE); /* need a write to menu */ 2607*7c478bd9Sstevel@tonic-gate } 2608*7c478bd9Sstevel@tonic-gate 2609*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2610*7c478bd9Sstevel@tonic-gate static error_t 2611*7c478bd9Sstevel@tonic-gate set_option(menu_t *mp, char *menu_path, char *opt) 2612*7c478bd9Sstevel@tonic-gate { 2613*7c478bd9Sstevel@tonic-gate int optnum, optval; 2614*7c478bd9Sstevel@tonic-gate char *val; 2615*7c478bd9Sstevel@tonic-gate 2616*7c478bd9Sstevel@tonic-gate assert(mp); 2617*7c478bd9Sstevel@tonic-gate assert(opt); 2618*7c478bd9Sstevel@tonic-gate 2619*7c478bd9Sstevel@tonic-gate val = strchr(opt, '='); 2620*7c478bd9Sstevel@tonic-gate if (val == NULL) { 2621*7c478bd9Sstevel@tonic-gate bam_error(INVALID_ENTRY, opt); 2622*7c478bd9Sstevel@tonic-gate return (BAM_ERROR); 2623*7c478bd9Sstevel@tonic-gate } 2624*7c478bd9Sstevel@tonic-gate 2625*7c478bd9Sstevel@tonic-gate *val = '\0'; 2626*7c478bd9Sstevel@tonic-gate if (strcmp(opt, "default") == 0) { 2627*7c478bd9Sstevel@tonic-gate optnum = DEFAULT_CMD; 2628*7c478bd9Sstevel@tonic-gate } else if (strcmp(opt, "timeout") == 0) { 2629*7c478bd9Sstevel@tonic-gate optnum = TIMEOUT_CMD; 2630*7c478bd9Sstevel@tonic-gate } else { 2631*7c478bd9Sstevel@tonic-gate bam_error(INVALID_ENTRY, opt); 2632*7c478bd9Sstevel@tonic-gate return (BAM_ERROR); 2633*7c478bd9Sstevel@tonic-gate } 2634*7c478bd9Sstevel@tonic-gate 2635*7c478bd9Sstevel@tonic-gate optval = s_strtol(val + 1); 2636*7c478bd9Sstevel@tonic-gate *val = '='; 2637*7c478bd9Sstevel@tonic-gate return (set_global(mp, menu_cmds[optnum], optval)); 2638*7c478bd9Sstevel@tonic-gate } 2639*7c478bd9Sstevel@tonic-gate 2640*7c478bd9Sstevel@tonic-gate /* 2641*7c478bd9Sstevel@tonic-gate * The quiet argument suppresses messages. This is used 2642*7c478bd9Sstevel@tonic-gate * when invoked in the context of other commands (e.g. list_entry) 2643*7c478bd9Sstevel@tonic-gate */ 2644*7c478bd9Sstevel@tonic-gate static error_t 2645*7c478bd9Sstevel@tonic-gate read_globals(menu_t *mp, char *menu_path, char *globalcmd, int quiet) 2646*7c478bd9Sstevel@tonic-gate { 2647*7c478bd9Sstevel@tonic-gate line_t *lp; 2648*7c478bd9Sstevel@tonic-gate char *arg; 2649*7c478bd9Sstevel@tonic-gate int done, ret = BAM_SUCCESS; 2650*7c478bd9Sstevel@tonic-gate 2651*7c478bd9Sstevel@tonic-gate assert(mp); 2652*7c478bd9Sstevel@tonic-gate assert(menu_path); 2653*7c478bd9Sstevel@tonic-gate assert(globalcmd); 2654*7c478bd9Sstevel@tonic-gate 2655*7c478bd9Sstevel@tonic-gate if (mp->start == NULL) { 2656*7c478bd9Sstevel@tonic-gate if (!quiet) 2657*7c478bd9Sstevel@tonic-gate bam_error(NO_MENU, menu_path); 2658*7c478bd9Sstevel@tonic-gate return (BAM_ERROR); 2659*7c478bd9Sstevel@tonic-gate } 2660*7c478bd9Sstevel@tonic-gate 2661*7c478bd9Sstevel@tonic-gate done = 0; 2662*7c478bd9Sstevel@tonic-gate for (lp = mp->start; lp; lp = lp->next) { 2663*7c478bd9Sstevel@tonic-gate if (lp->flags != BAM_GLOBAL) 2664*7c478bd9Sstevel@tonic-gate continue; 2665*7c478bd9Sstevel@tonic-gate 2666*7c478bd9Sstevel@tonic-gate if (lp->cmd == NULL) { 2667*7c478bd9Sstevel@tonic-gate if (!quiet) 2668*7c478bd9Sstevel@tonic-gate bam_error(NO_CMD, lp->lineNum); 2669*7c478bd9Sstevel@tonic-gate continue; 2670*7c478bd9Sstevel@tonic-gate } 2671*7c478bd9Sstevel@tonic-gate 2672*7c478bd9Sstevel@tonic-gate if (strcmp(globalcmd, lp->cmd) != 0) 2673*7c478bd9Sstevel@tonic-gate continue; 2674*7c478bd9Sstevel@tonic-gate 2675*7c478bd9Sstevel@tonic-gate /* Found global. Check for duplicates */ 2676*7c478bd9Sstevel@tonic-gate if (done && !quiet) { 2677*7c478bd9Sstevel@tonic-gate bam_error(DUP_CMD, globalcmd, lp->lineNum, bam_root); 2678*7c478bd9Sstevel@tonic-gate ret = BAM_ERROR; 2679*7c478bd9Sstevel@tonic-gate } 2680*7c478bd9Sstevel@tonic-gate 2681*7c478bd9Sstevel@tonic-gate arg = lp->arg ? lp->arg : ""; 2682*7c478bd9Sstevel@tonic-gate bam_print(GLOBAL_CMD, globalcmd, arg); 2683*7c478bd9Sstevel@tonic-gate done = 1; 2684*7c478bd9Sstevel@tonic-gate } 2685*7c478bd9Sstevel@tonic-gate 2686*7c478bd9Sstevel@tonic-gate if (!done && bam_verbose) 2687*7c478bd9Sstevel@tonic-gate bam_print(NO_ENTRY, globalcmd); 2688*7c478bd9Sstevel@tonic-gate 2689*7c478bd9Sstevel@tonic-gate return (ret); 2690*7c478bd9Sstevel@tonic-gate } 2691*7c478bd9Sstevel@tonic-gate 2692*7c478bd9Sstevel@tonic-gate static error_t 2693*7c478bd9Sstevel@tonic-gate menu_write(char *root, menu_t *mp) 2694*7c478bd9Sstevel@tonic-gate { 2695*7c478bd9Sstevel@tonic-gate return (list2file(root, MENU_TMP, GRUB_MENU, mp->start)); 2696*7c478bd9Sstevel@tonic-gate } 2697*7c478bd9Sstevel@tonic-gate 2698*7c478bd9Sstevel@tonic-gate static void 2699*7c478bd9Sstevel@tonic-gate line_free(line_t *lp) 2700*7c478bd9Sstevel@tonic-gate { 2701*7c478bd9Sstevel@tonic-gate if (lp == NULL) 2702*7c478bd9Sstevel@tonic-gate return; 2703*7c478bd9Sstevel@tonic-gate 2704*7c478bd9Sstevel@tonic-gate if (lp->cmd) 2705*7c478bd9Sstevel@tonic-gate free(lp->cmd); 2706*7c478bd9Sstevel@tonic-gate if (lp->sep) 2707*7c478bd9Sstevel@tonic-gate free(lp->sep); 2708*7c478bd9Sstevel@tonic-gate if (lp->arg) 2709*7c478bd9Sstevel@tonic-gate free(lp->arg); 2710*7c478bd9Sstevel@tonic-gate if (lp->line) 2711*7c478bd9Sstevel@tonic-gate free(lp->line); 2712*7c478bd9Sstevel@tonic-gate free(lp); 2713*7c478bd9Sstevel@tonic-gate } 2714*7c478bd9Sstevel@tonic-gate 2715*7c478bd9Sstevel@tonic-gate static void 2716*7c478bd9Sstevel@tonic-gate linelist_free(line_t *start) 2717*7c478bd9Sstevel@tonic-gate { 2718*7c478bd9Sstevel@tonic-gate line_t *lp; 2719*7c478bd9Sstevel@tonic-gate 2720*7c478bd9Sstevel@tonic-gate while (start) { 2721*7c478bd9Sstevel@tonic-gate lp = start; 2722*7c478bd9Sstevel@tonic-gate start = start->next; 2723*7c478bd9Sstevel@tonic-gate line_free(lp); 2724*7c478bd9Sstevel@tonic-gate } 2725*7c478bd9Sstevel@tonic-gate } 2726*7c478bd9Sstevel@tonic-gate 2727*7c478bd9Sstevel@tonic-gate static void 2728*7c478bd9Sstevel@tonic-gate filelist_free(filelist_t *flistp) 2729*7c478bd9Sstevel@tonic-gate { 2730*7c478bd9Sstevel@tonic-gate linelist_free(flistp->head); 2731*7c478bd9Sstevel@tonic-gate flistp->head = NULL; 2732*7c478bd9Sstevel@tonic-gate flistp->tail = NULL; 2733*7c478bd9Sstevel@tonic-gate } 2734*7c478bd9Sstevel@tonic-gate 2735*7c478bd9Sstevel@tonic-gate static void 2736*7c478bd9Sstevel@tonic-gate menu_free(menu_t *mp) 2737*7c478bd9Sstevel@tonic-gate { 2738*7c478bd9Sstevel@tonic-gate assert(mp); 2739*7c478bd9Sstevel@tonic-gate 2740*7c478bd9Sstevel@tonic-gate if (mp->start) 2741*7c478bd9Sstevel@tonic-gate linelist_free(mp->start); 2742*7c478bd9Sstevel@tonic-gate free(mp); 2743*7c478bd9Sstevel@tonic-gate 2744*7c478bd9Sstevel@tonic-gate } 2745*7c478bd9Sstevel@tonic-gate 2746*7c478bd9Sstevel@tonic-gate /* 2747*7c478bd9Sstevel@tonic-gate * Utility routines 2748*7c478bd9Sstevel@tonic-gate */ 2749*7c478bd9Sstevel@tonic-gate 2750*7c478bd9Sstevel@tonic-gate 2751*7c478bd9Sstevel@tonic-gate /* 2752*7c478bd9Sstevel@tonic-gate * Returns 0 on success 2753*7c478bd9Sstevel@tonic-gate * Any other value indicates an error 2754*7c478bd9Sstevel@tonic-gate */ 2755*7c478bd9Sstevel@tonic-gate static int 2756*7c478bd9Sstevel@tonic-gate exec_cmd(char *cmdline, char *output, int64_t osize) 2757*7c478bd9Sstevel@tonic-gate { 2758*7c478bd9Sstevel@tonic-gate char buf[BUFSIZ]; 2759*7c478bd9Sstevel@tonic-gate int ret; 2760*7c478bd9Sstevel@tonic-gate FILE *ptr; 2761*7c478bd9Sstevel@tonic-gate size_t len; 2762*7c478bd9Sstevel@tonic-gate sigset_t set; 2763*7c478bd9Sstevel@tonic-gate void (*disp)(int); 2764*7c478bd9Sstevel@tonic-gate 2765*7c478bd9Sstevel@tonic-gate /* 2766*7c478bd9Sstevel@tonic-gate * For security 2767*7c478bd9Sstevel@tonic-gate * - only absolute paths are allowed 2768*7c478bd9Sstevel@tonic-gate * - set IFS to space and tab 2769*7c478bd9Sstevel@tonic-gate */ 2770*7c478bd9Sstevel@tonic-gate if (*cmdline != '/') { 2771*7c478bd9Sstevel@tonic-gate bam_error(ABS_PATH_REQ, cmdline); 2772*7c478bd9Sstevel@tonic-gate return (-1); 2773*7c478bd9Sstevel@tonic-gate } 2774*7c478bd9Sstevel@tonic-gate (void) putenv("IFS= \t"); 2775*7c478bd9Sstevel@tonic-gate 2776*7c478bd9Sstevel@tonic-gate /* 2777*7c478bd9Sstevel@tonic-gate * We may have been exec'ed with SIGCHLD blocked 2778*7c478bd9Sstevel@tonic-gate * unblock it here 2779*7c478bd9Sstevel@tonic-gate */ 2780*7c478bd9Sstevel@tonic-gate (void) sigemptyset(&set); 2781*7c478bd9Sstevel@tonic-gate (void) sigaddset(&set, SIGCHLD); 2782*7c478bd9Sstevel@tonic-gate if (sigprocmask(SIG_UNBLOCK, &set, NULL) != 0) { 2783*7c478bd9Sstevel@tonic-gate bam_error(CANT_UNBLOCK_SIGCHLD, strerror(errno)); 2784*7c478bd9Sstevel@tonic-gate return (-1); 2785*7c478bd9Sstevel@tonic-gate } 2786*7c478bd9Sstevel@tonic-gate 2787*7c478bd9Sstevel@tonic-gate /* 2788*7c478bd9Sstevel@tonic-gate * Set SIGCHLD disposition to SIG_DFL for popen/pclose 2789*7c478bd9Sstevel@tonic-gate */ 2790*7c478bd9Sstevel@tonic-gate disp = sigset(SIGCHLD, SIG_DFL); 2791*7c478bd9Sstevel@tonic-gate if (disp == SIG_ERR) { 2792*7c478bd9Sstevel@tonic-gate bam_error(FAILED_SIG, strerror(errno)); 2793*7c478bd9Sstevel@tonic-gate return (-1); 2794*7c478bd9Sstevel@tonic-gate } 2795*7c478bd9Sstevel@tonic-gate if (disp == SIG_HOLD) { 2796*7c478bd9Sstevel@tonic-gate bam_error(BLOCKED_SIG, cmdline); 2797*7c478bd9Sstevel@tonic-gate return (-1); 2798*7c478bd9Sstevel@tonic-gate } 2799*7c478bd9Sstevel@tonic-gate 2800*7c478bd9Sstevel@tonic-gate ptr = popen(cmdline, "r"); 2801*7c478bd9Sstevel@tonic-gate if (ptr == NULL) { 2802*7c478bd9Sstevel@tonic-gate bam_error(POPEN_FAIL, cmdline, strerror(errno)); 2803*7c478bd9Sstevel@tonic-gate return (-1); 2804*7c478bd9Sstevel@tonic-gate } 2805*7c478bd9Sstevel@tonic-gate 2806*7c478bd9Sstevel@tonic-gate /* 2807*7c478bd9Sstevel@tonic-gate * If we simply do a pclose() following a popen(), pclose() 2808*7c478bd9Sstevel@tonic-gate * will close the reader end of the pipe immediately even 2809*7c478bd9Sstevel@tonic-gate * if the child process has not started/exited. pclose() 2810*7c478bd9Sstevel@tonic-gate * does wait for cmd to terminate before returning though. 2811*7c478bd9Sstevel@tonic-gate * When the executed command writes its output to the pipe 2812*7c478bd9Sstevel@tonic-gate * there is no reader process and the command dies with 2813*7c478bd9Sstevel@tonic-gate * SIGPIPE. To avoid this we read repeatedly until read 2814*7c478bd9Sstevel@tonic-gate * terminates with EOF. This indicates that the command 2815*7c478bd9Sstevel@tonic-gate * (writer) has closed the pipe and we can safely do a 2816*7c478bd9Sstevel@tonic-gate * pclose(). 2817*7c478bd9Sstevel@tonic-gate * 2818*7c478bd9Sstevel@tonic-gate * Since pclose() does wait for the command to exit, 2819*7c478bd9Sstevel@tonic-gate * we can safely reap the exit status of the command 2820*7c478bd9Sstevel@tonic-gate * from the value returned by pclose() 2821*7c478bd9Sstevel@tonic-gate */ 2822*7c478bd9Sstevel@tonic-gate while (fgets(buf, sizeof (buf), ptr) != NULL) { 2823*7c478bd9Sstevel@tonic-gate /* if (bam_verbose) XXX */ 2824*7c478bd9Sstevel@tonic-gate bam_print(PRINT_NO_NEWLINE, buf); 2825*7c478bd9Sstevel@tonic-gate if (output && osize > 0) { 2826*7c478bd9Sstevel@tonic-gate (void) snprintf(output, osize, "%s", buf); 2827*7c478bd9Sstevel@tonic-gate len = strlen(buf); 2828*7c478bd9Sstevel@tonic-gate output += len; 2829*7c478bd9Sstevel@tonic-gate osize -= len; 2830*7c478bd9Sstevel@tonic-gate } 2831*7c478bd9Sstevel@tonic-gate } 2832*7c478bd9Sstevel@tonic-gate 2833*7c478bd9Sstevel@tonic-gate ret = pclose(ptr); 2834*7c478bd9Sstevel@tonic-gate if (ret == -1) { 2835*7c478bd9Sstevel@tonic-gate bam_error(PCLOSE_FAIL, cmdline, strerror(errno)); 2836*7c478bd9Sstevel@tonic-gate return (-1); 2837*7c478bd9Sstevel@tonic-gate } 2838*7c478bd9Sstevel@tonic-gate 2839*7c478bd9Sstevel@tonic-gate if (WIFEXITED(ret)) { 2840*7c478bd9Sstevel@tonic-gate return (WEXITSTATUS(ret)); 2841*7c478bd9Sstevel@tonic-gate } else { 2842*7c478bd9Sstevel@tonic-gate bam_error(EXEC_FAIL, cmdline, ret); 2843*7c478bd9Sstevel@tonic-gate return (-1); 2844*7c478bd9Sstevel@tonic-gate } 2845*7c478bd9Sstevel@tonic-gate } 2846*7c478bd9Sstevel@tonic-gate 2847*7c478bd9Sstevel@tonic-gate /* 2848*7c478bd9Sstevel@tonic-gate * Since this function returns -1 on error 2849*7c478bd9Sstevel@tonic-gate * it cannot be used to convert -1. However, 2850*7c478bd9Sstevel@tonic-gate * that is sufficient for what we need. 2851*7c478bd9Sstevel@tonic-gate */ 2852*7c478bd9Sstevel@tonic-gate static long 2853*7c478bd9Sstevel@tonic-gate s_strtol(char *str) 2854*7c478bd9Sstevel@tonic-gate { 2855*7c478bd9Sstevel@tonic-gate long l; 2856*7c478bd9Sstevel@tonic-gate char *res = NULL; 2857*7c478bd9Sstevel@tonic-gate 2858*7c478bd9Sstevel@tonic-gate if (str == NULL) { 2859*7c478bd9Sstevel@tonic-gate return (-1); 2860*7c478bd9Sstevel@tonic-gate } 2861*7c478bd9Sstevel@tonic-gate 2862*7c478bd9Sstevel@tonic-gate errno = 0; 2863*7c478bd9Sstevel@tonic-gate l = strtol(str, &res, 10); 2864*7c478bd9Sstevel@tonic-gate if (errno || *res != '\0') { 2865*7c478bd9Sstevel@tonic-gate return (-1); 2866*7c478bd9Sstevel@tonic-gate } 2867*7c478bd9Sstevel@tonic-gate 2868*7c478bd9Sstevel@tonic-gate return (l); 2869*7c478bd9Sstevel@tonic-gate } 2870*7c478bd9Sstevel@tonic-gate 2871*7c478bd9Sstevel@tonic-gate /* 2872*7c478bd9Sstevel@tonic-gate * Wrapper around fputs, that adds a newline (since fputs doesn't) 2873*7c478bd9Sstevel@tonic-gate */ 2874*7c478bd9Sstevel@tonic-gate static int 2875*7c478bd9Sstevel@tonic-gate s_fputs(char *str, FILE *fp) 2876*7c478bd9Sstevel@tonic-gate { 2877*7c478bd9Sstevel@tonic-gate char linebuf[BAM_MAXLINE]; 2878*7c478bd9Sstevel@tonic-gate 2879*7c478bd9Sstevel@tonic-gate (void) snprintf(linebuf, sizeof (linebuf), "%s\n", str); 2880*7c478bd9Sstevel@tonic-gate return (fputs(linebuf, fp)); 2881*7c478bd9Sstevel@tonic-gate } 2882*7c478bd9Sstevel@tonic-gate 2883*7c478bd9Sstevel@tonic-gate /* 2884*7c478bd9Sstevel@tonic-gate * Wrapper around fgets, that strips newlines returned by fgets 2885*7c478bd9Sstevel@tonic-gate */ 2886*7c478bd9Sstevel@tonic-gate static char * 2887*7c478bd9Sstevel@tonic-gate s_fgets(char *buf, int buflen, FILE *fp) 2888*7c478bd9Sstevel@tonic-gate { 2889*7c478bd9Sstevel@tonic-gate int n; 2890*7c478bd9Sstevel@tonic-gate 2891*7c478bd9Sstevel@tonic-gate buf = fgets(buf, buflen, fp); 2892*7c478bd9Sstevel@tonic-gate if (buf) { 2893*7c478bd9Sstevel@tonic-gate n = strlen(buf); 2894*7c478bd9Sstevel@tonic-gate if (n == buflen - 1 && buf[n-1] != '\n') 2895*7c478bd9Sstevel@tonic-gate bam_error(TOO_LONG, buflen - 1, buf); 2896*7c478bd9Sstevel@tonic-gate buf[n-1] = (buf[n-1] == '\n') ? '\0' : buf[n-1]; 2897*7c478bd9Sstevel@tonic-gate } 2898*7c478bd9Sstevel@tonic-gate 2899*7c478bd9Sstevel@tonic-gate return (buf); 2900*7c478bd9Sstevel@tonic-gate } 2901*7c478bd9Sstevel@tonic-gate 2902*7c478bd9Sstevel@tonic-gate static void * 2903*7c478bd9Sstevel@tonic-gate s_calloc(size_t nelem, size_t sz) 2904*7c478bd9Sstevel@tonic-gate { 2905*7c478bd9Sstevel@tonic-gate void *ptr; 2906*7c478bd9Sstevel@tonic-gate 2907*7c478bd9Sstevel@tonic-gate ptr = calloc(nelem, sz); 2908*7c478bd9Sstevel@tonic-gate if (ptr == NULL) { 2909*7c478bd9Sstevel@tonic-gate bam_error(NO_MEM, nelem*sz); 2910*7c478bd9Sstevel@tonic-gate bam_exit(1); 2911*7c478bd9Sstevel@tonic-gate } 2912*7c478bd9Sstevel@tonic-gate return (ptr); 2913*7c478bd9Sstevel@tonic-gate } 2914*7c478bd9Sstevel@tonic-gate 2915*7c478bd9Sstevel@tonic-gate static char * 2916*7c478bd9Sstevel@tonic-gate s_strdup(char *str) 2917*7c478bd9Sstevel@tonic-gate { 2918*7c478bd9Sstevel@tonic-gate char *ptr; 2919*7c478bd9Sstevel@tonic-gate 2920*7c478bd9Sstevel@tonic-gate if (str == NULL) 2921*7c478bd9Sstevel@tonic-gate return (NULL); 2922*7c478bd9Sstevel@tonic-gate 2923*7c478bd9Sstevel@tonic-gate ptr = strdup(str); 2924*7c478bd9Sstevel@tonic-gate if (ptr == NULL) { 2925*7c478bd9Sstevel@tonic-gate bam_error(NO_MEM, strlen(str) + 1); 2926*7c478bd9Sstevel@tonic-gate bam_exit(1); 2927*7c478bd9Sstevel@tonic-gate } 2928*7c478bd9Sstevel@tonic-gate return (ptr); 2929*7c478bd9Sstevel@tonic-gate } 2930*7c478bd9Sstevel@tonic-gate 2931*7c478bd9Sstevel@tonic-gate /* 2932*7c478bd9Sstevel@tonic-gate * Returns 1 if amd64 (or sparc, for syncing x86 diskless clients) 2933*7c478bd9Sstevel@tonic-gate * Returns 0 otherwise 2934*7c478bd9Sstevel@tonic-gate */ 2935*7c478bd9Sstevel@tonic-gate static int 2936*7c478bd9Sstevel@tonic-gate is_amd64(void) 2937*7c478bd9Sstevel@tonic-gate { 2938*7c478bd9Sstevel@tonic-gate static int amd64 = -1; 2939*7c478bd9Sstevel@tonic-gate char isabuf[257]; /* from sysinfo(2) manpage */ 2940*7c478bd9Sstevel@tonic-gate 2941*7c478bd9Sstevel@tonic-gate if (amd64 != -1) 2942*7c478bd9Sstevel@tonic-gate return (amd64); 2943*7c478bd9Sstevel@tonic-gate 2944*7c478bd9Sstevel@tonic-gate if (sysinfo(SI_ISALIST, isabuf, sizeof (isabuf)) > 0 && 2945*7c478bd9Sstevel@tonic-gate strncmp(isabuf, "amd64 ", strlen("amd64 ")) == 0) 2946*7c478bd9Sstevel@tonic-gate amd64 = 1; 2947*7c478bd9Sstevel@tonic-gate else if (strstr(isabuf, "i386") == NULL) 2948*7c478bd9Sstevel@tonic-gate amd64 = 1; /* diskless server */ 2949*7c478bd9Sstevel@tonic-gate else 2950*7c478bd9Sstevel@tonic-gate amd64 = 0; 2951*7c478bd9Sstevel@tonic-gate 2952*7c478bd9Sstevel@tonic-gate return (amd64); 2953*7c478bd9Sstevel@tonic-gate } 2954*7c478bd9Sstevel@tonic-gate 2955*7c478bd9Sstevel@tonic-gate static void 2956*7c478bd9Sstevel@tonic-gate append_to_flist(filelist_t *flistp, char *s) 2957*7c478bd9Sstevel@tonic-gate { 2958*7c478bd9Sstevel@tonic-gate line_t *lp; 2959*7c478bd9Sstevel@tonic-gate 2960*7c478bd9Sstevel@tonic-gate lp = s_calloc(1, sizeof (line_t)); 2961*7c478bd9Sstevel@tonic-gate lp->line = s_strdup(s); 2962*7c478bd9Sstevel@tonic-gate if (flistp->head == NULL) 2963*7c478bd9Sstevel@tonic-gate flistp->head = lp; 2964*7c478bd9Sstevel@tonic-gate else 2965*7c478bd9Sstevel@tonic-gate flistp->tail->next = lp; 2966*7c478bd9Sstevel@tonic-gate flistp->tail = lp; 2967*7c478bd9Sstevel@tonic-gate } 2968