Home | History | Annotate | Download | only in bootadm
      1      0     stevel /*
      2      0     stevel  * CDDL HEADER START
      3      0     stevel  *
      4      0     stevel  * The contents of this file are subject to the terms of the
      5   1746     vikram  * Common Development and Distribution License (the "License").
      6   1746     vikram  * You may not use this file except in compliance with the License.
      7      0     stevel  *
      8      0     stevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9      0     stevel  * or http://www.opensolaris.org/os/licensing.
     10      0     stevel  * See the License for the specific language governing permissions
     11      0     stevel  * and limitations under the License.
     12      0     stevel  *
     13      0     stevel  * When distributing Covered Code, include this CDDL HEADER in each
     14      0     stevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15      0     stevel  * If applicable, add the following below this CDDL HEADER, with the
     16      0     stevel  * fields enclosed by brackets "[]" replaced with your own identifying
     17      0     stevel  * information: Portions Copyright [yyyy] [name of copyright owner]
     18      0     stevel  *
     19      0     stevel  * CDDL HEADER END
     20      0     stevel  */
     21      0     stevel /*
     22   8642     Vikram  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23      0     stevel  * Use is subject to license terms.
     24      0     stevel  */
     25      0     stevel 
     26      0     stevel /*
     27      0     stevel  * bootadm(1M) is a new utility for managing bootability of
     28      0     stevel  * Solaris *Newboot* environments. It has two primary tasks:
     29      0     stevel  * 	- Allow end users to manage bootability of Newboot Solaris instances
     30      0     stevel  *	- Provide services to other subsystems in Solaris (primarily Install)
     31      0     stevel  */
     32      0     stevel 
     33      0     stevel /* Headers */
     34      0     stevel #include <stdio.h>
     35      0     stevel #include <errno.h>
     36      0     stevel #include <stdlib.h>
     37      0     stevel #include <string.h>
     38      0     stevel #include <unistd.h>
     39      0     stevel #include <sys/types.h>
     40      0     stevel #include <sys/stat.h>
     41  10499    William #include <alloca.h>
     42      0     stevel #include <stdarg.h>
     43      0     stevel #include <limits.h>
     44      0     stevel #include <signal.h>
     45      0     stevel #include <sys/wait.h>
     46      0     stevel #include <sys/mnttab.h>
     47   7543      Jerry #include <sys/mntent.h>
     48      0     stevel #include <sys/statvfs.h>
     49      0     stevel #include <libnvpair.h>
     50      0     stevel #include <ftw.h>
     51      0     stevel #include <fcntl.h>
     52      0     stevel #include <strings.h>
     53   4581    sherrym #include <utime.h>
     54      0     stevel #include <sys/systeminfo.h>
     55      0     stevel #include <sys/dktp/fdisk.h>
     56   2334      setje #include <sys/param.h>
     57   6448     vikram #include <dirent.h>
     58   6448     vikram #include <ctype.h>
     59   6448     vikram #include <libgen.h>
     60   6423    gw25295 #include <sys/sysmacros.h>
     61   8735     Enrico #include <sys/elf.h>
     62   6694     vikram #include <libscf.h>
     63   8735     Enrico #include <zlib.h>
     64   8735     Enrico #include <sys/lockfs.h>
     65   8735     Enrico #include <sys/filio.h>
     66  10682  Sheshadri #ifdef i386
     67  10682  Sheshadri #include <libfdisk.h>
     68  10682  Sheshadri #endif
     69   5648      setje 
     70   5648      setje #if !defined(_OPB)
     71   4581    sherrym #include <sys/ucode.h>
     72   4581    sherrym #endif
     73      0     stevel 
     74      0     stevel #include <pwd.h>
     75      0     stevel #include <grp.h>
     76      0     stevel #include <device_info.h>
     77   6448     vikram #include <sys/vtoc.h>
     78   6448     vikram #include <sys/efi_partition.h>
     79   9500  Gangadhar #include <regex.h>
     80      0     stevel #include <locale.h>
     81      0     stevel 
     82      0     stevel #include "message.h"
     83   3446        mrj #include "bootadm.h"
     84      0     stevel 
     85      0     stevel #ifndef TEXT_DOMAIN
     86      0     stevel #define	TEXT_DOMAIN	"SUNW_OST_OSCMD"
     87      0     stevel #endif	/* TEXT_DOMAIN */
     88      0     stevel 
     89      0     stevel /* Type definitions */
     90      0     stevel 
     91      0     stevel /* Primary subcmds */
     92      0     stevel typedef enum {
     93      0     stevel 	BAM_MENU = 3,
     94      0     stevel 	BAM_ARCHIVE
     95      0     stevel } subcmd_t;
     96      0     stevel 
     97      0     stevel typedef enum {
     98      0     stevel     OPT_ABSENT = 0,	/* No option */
     99      0     stevel     OPT_REQ,		/* option required */
    100      0     stevel     OPT_OPTIONAL	/* option may or may not be present */
    101      0     stevel } option_t;
    102      0     stevel 
    103      0     stevel typedef struct {
    104      0     stevel 	char	*subcmd;
    105      0     stevel 	option_t option;
    106      0     stevel 	error_t (*handler)();
    107   2115     vikram 	int	unpriv;			/* is this an unprivileged command */
    108      0     stevel } subcmd_defn_t;
    109      0     stevel 
    110      0     stevel #define	LINE_INIT	0	/* lineNum initial value */
    111      0     stevel #define	ENTRY_INIT	-1	/* entryNum initial value */
    112      0     stevel #define	ALL_ENTRIES	-2	/* selects all boot entries */
    113      0     stevel 
    114      0     stevel #define	GRUB_DIR		"/boot/grub"
    115   6694     vikram #define	GRUB_STAGE2		GRUB_DIR "/stage2"
    116      0     stevel #define	GRUB_MENU		"/boot/grub/menu.lst"
    117      0     stevel #define	MENU_TMP		"/boot/grub/menu.lst.tmp"
    118   6694     vikram #define	GRUB_BACKUP_MENU	"/etc/lu/GRUB_backup_menu"
    119      0     stevel #define	RAMDISK_SPECIAL		"/ramdisk"
    120    621     vikram #define	STUBBOOT		"/stubboot"
    121   6448     vikram #define	MULTIBOOT		"/platform/i86pc/multiboot"
    122   6448     vikram #define	GRUBSIGN_DIR		"/boot/grub/bootsign"
    123   6448     vikram #define	GRUBSIGN_BACKUP		"/etc/bootsign"
    124   6448     vikram #define	GRUBSIGN_UFS_PREFIX	"rootfs"
    125   6448     vikram #define	GRUBSIGN_ZFS_PREFIX	"pool_"
    126   6448     vikram #define	GRUBSIGN_LU_PREFIX	"BE_"
    127   6448     vikram #define	UFS_SIGNATURE_LIST	"/var/run/grub_ufs_signatures"
    128   6448     vikram #define	ZFS_LEGACY_MNTPT	"/tmp/bootadm_mnt_zfs_legacy"
    129   6448     vikram 
    130   6448     vikram #define	BOOTADM_RDONLY_TEST	"BOOTADM_RDONLY_TEST"
    131      0     stevel 
    132      0     stevel /* lock related */
    133      0     stevel #define	BAM_LOCK_FILE		"/var/run/bootadm.lock"
    134      0     stevel #define	LOCK_FILE_PERMS		(S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
    135      0     stevel 
    136   5648      setje #define	CREATE_RAMDISK		"boot/solaris/bin/create_ramdisk"
    137   5648      setje #define	CREATE_DISKMAP		"boot/solaris/bin/create_diskmap"
    138   5648      setje #define	EXTRACT_BOOT_FILELIST	"boot/solaris/bin/extract_boot_filelist"
    139      0     stevel #define	GRUBDISK_MAP		"/var/run/solaris_grubdisk.map"
    140    316     vikram 
    141    316     vikram #define	GRUB_slice		"/etc/lu/GRUB_slice"
    142    316     vikram #define	GRUB_root		"/etc/lu/GRUB_root"
    143   1746     vikram #define	GRUB_fdisk		"/etc/lu/GRUB_fdisk"
    144   1746     vikram #define	GRUB_fdisk_target	"/etc/lu/GRUB_fdisk_target"
    145   6694     vikram #define	FINDROOT_INSTALLGRUB	"/etc/lu/installgrub.findroot"
    146   6694     vikram #define	LULIB			"/usr/lib/lu/lulib"
    147   6694     vikram #define	LULIB_PROPAGATE_FILE	"lulib_propagate_file"
    148   6694     vikram #define	CKSUM			"/usr/bin/cksum"
    149   6694     vikram #define	LU_MENU_CKSUM		"/etc/lu/menu.cksum"
    150   6694     vikram #define	BOOTADM			"/sbin/bootadm"
    151    316     vikram 
    152    316     vikram #define	INSTALLGRUB		"/sbin/installgrub"
    153    316     vikram #define	STAGE1			"/boot/grub/stage1"
    154    316     vikram #define	STAGE2			"/boot/grub/stage2"
    155   6448     vikram 
    156   6448     vikram typedef enum zfs_mnted {
    157   6448     vikram 	ZFS_MNT_ERROR = -1,
    158   6448     vikram 	LEGACY_MOUNTED = 1,
    159   6448     vikram 	LEGACY_ALREADY,
    160   6448     vikram 	ZFS_MOUNTED,
    161   6448     vikram 	ZFS_ALREADY
    162   6448     vikram } zfs_mnted_t;
    163   6448     vikram 
    164      0     stevel /*
    165   4493   nadkarni  * The following two defines are used to detect and create the correct
    166   4493   nadkarni  * boot archive  when safemode patching is underway.  LOFS_PATCH_FILE is a
    167   4493   nadkarni  * contracted private interface between bootadm and the install
    168   4493   nadkarni  * consolidation.  It is set by pdo.c when a patch with SUNW_PATCH_SAFEMODE
    169   4493   nadkarni  * is applied.
    170   4493   nadkarni  */
    171   4493   nadkarni #define	LOFS_PATCH_FILE		"/var/run/.patch_loopback_mode"
    172   4493   nadkarni #define	LOFS_PATCH_MNT		"/var/run/.patch_root_loopbackmnt"
    173   4493   nadkarni 
    174   4493   nadkarni /*
    175      0     stevel  * Default file attributes
    176      0     stevel  */
    177      0     stevel #define	DEFAULT_DEV_MODE	0644	/* default permissions */
    178      0     stevel #define	DEFAULT_DEV_UID		0	/* user root */
    179      0     stevel #define	DEFAULT_DEV_GID		3	/* group sys */
    180      0     stevel 
    181      0     stevel /*
    182      0     stevel  * Menu related
    183      0     stevel  * menu_cmd_t and menu_cmds must be kept in sync
    184      0     stevel  */
    185   3446        mrj char *menu_cmds[] = {
    186      0     stevel 	"default",	/* DEFAULT_CMD */
    187      0     stevel 	"timeout",	/* TIMEOUT_CMD */
    188      0     stevel 	"title",	/* TITLE_CMD */
    189      0     stevel 	"root",		/* ROOT_CMD */
    190      0     stevel 	"kernel",	/* KERNEL_CMD */
    191   3446        mrj 	"kernel$",	/* KERNEL_DOLLAR_CMD */
    192      0     stevel 	"module",	/* MODULE_CMD */
    193   3446        mrj 	"module$",	/* MODULE_DOLLAR_CMD */
    194      0     stevel 	" ",		/* SEP_CMD */
    195      0     stevel 	"#",		/* COMMENT_CMD */
    196   3446        mrj 	"chainloader",	/* CHAINLOADER_CMD */
    197   3446        mrj 	"args",		/* ARGS_CMD */
    198   6448     vikram 	"findroot",	/* FINDROOT_CMD */
    199  10499    William 	"bootfs",	/* BOOTFS_CMD */
    200      0     stevel 	NULL
    201      0     stevel };
    202      0     stevel 
    203      0     stevel #define	OPT_ENTRY_NUM	"entry"
    204      0     stevel 
    205      0     stevel /*
    206   6448     vikram  * exec_cmd related
    207      0     stevel  */
    208      0     stevel typedef struct {
    209      0     stevel 	line_t *head;
    210      0     stevel 	line_t *tail;
    211      0     stevel } filelist_t;
    212      0     stevel 
    213      0     stevel #define	BOOT_FILE_LIST	"boot/solaris/filelist.ramdisk"
    214      0     stevel #define	ETC_FILE_LIST	"etc/boot/solaris/filelist.ramdisk"
    215      0     stevel 
    216      0     stevel #define	FILE_STAT	"boot/solaris/filestat.ramdisk"
    217      0     stevel #define	FILE_STAT_TMP	"boot/solaris/filestat.ramdisk.tmp"
    218      0     stevel #define	DIR_PERMS	(S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
    219      0     stevel #define	FILE_STAT_MODE	(S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
    220      0     stevel 
    221   9233     Enrico #define	FILE_STAT_TIMESTAMP	"boot/solaris/timestamp.cache"
    222   9233     Enrico 
    223      0     stevel /* Globals */
    224   3446        mrj int bam_verbose;
    225   3446        mrj int bam_force;
    226   6448     vikram int bam_debug;
    227      0     stevel static char *prog;
    228      0     stevel static subcmd_t bam_cmd;
    229      0     stevel static char *bam_root;
    230      0     stevel static int bam_rootlen;
    231      0     stevel static int bam_root_readonly;
    232    621     vikram static int bam_alt_root;
    233   8735     Enrico static int bam_extend = 0;
    234   8735     Enrico static int bam_purge = 0;
    235      0     stevel static char *bam_subcmd;
    236      0     stevel static char *bam_opt;
    237      0     stevel static char **bam_argv;
    238      0     stevel static int bam_argc;
    239      0     stevel static int bam_check;
    240   9216     Enrico static int bam_saved_check;
    241      0     stevel static int bam_smf_check;
    242      0     stevel static int bam_lock_fd = -1;
    243   6423    gw25295 static int bam_zfs;
    244      0     stevel static char rootbuf[PATH_MAX] = "/";
    245    316     vikram static int bam_update_all;
    246   6319         jg static int bam_alt_platform;
    247   6319         jg static char *bam_platform;
    248   8954     Enrico static char *bam_home_env = NULL;
    249      0     stevel 
    250      0     stevel /* function prototypes */
    251   5648      setje static void parse_args_internal(int, char *[]);
    252   5648      setje static void parse_args(int, char *argv[]);
    253   5648      setje static error_t bam_menu(char *, char *, int, char *[]);
    254   5648      setje static error_t bam_archive(char *, char *);
    255   5648      setje 
    256      0     stevel static void bam_lock(void);
    257      0     stevel static void bam_unlock(void);
    258      0     stevel 
    259   5648      setje static int exec_cmd(char *, filelist_t *);
    260   5648      setje static error_t read_globals(menu_t *, char *, char *, int);
    261   6448     vikram static int menu_on_bootdisk(char *os_root, char *menu_root);
    262   5648      setje static menu_t *menu_read(char *);
    263   5648      setje static error_t menu_write(char *, menu_t *);
    264   5648      setje static void linelist_free(line_t *);
    265   5648      setje static void menu_free(menu_t *);
    266   5648      setje static void filelist_free(filelist_t *);
    267   5648      setje static error_t list2file(char *, char *, char *, line_t *);
    268   5648      setje static error_t list_entry(menu_t *, char *, char *);
    269  10499    William static error_t list_setting(menu_t *, char *, char *);
    270   5648      setje static error_t delete_all_entries(menu_t *, char *, char *);
    271   6448     vikram static error_t update_entry(menu_t *mp, char *menu_root, char *opt);
    272   6448     vikram static error_t update_temp(menu_t *mp, char *dummy, char *opt);
    273   5648      setje 
    274   5648      setje static error_t update_archive(char *, char *);
    275   5648      setje static error_t list_archive(char *, char *);
    276   5648      setje static error_t update_all(char *, char *);
    277   5648      setje static error_t read_list(char *, filelist_t *);
    278   5648      setje static error_t set_option(menu_t *, char *, char *);
    279   5648      setje static error_t set_kernel(menu_t *, menu_cmd_t, char *, char *, size_t);
    280   6448     vikram static error_t get_kernel(menu_t *, menu_cmd_t, char *, size_t);
    281   5648      setje static char *expand_path(const char *);
    282   5648      setje 
    283   5648      setje static long s_strtol(char *);
    284   5648      setje static int s_fputs(char *, FILE *);
    285   5648      setje 
    286   6448     vikram static int is_zfs(char *root);
    287   6448     vikram static int is_ufs(char *root);
    288   6448     vikram static int is_pcfs(char *root);
    289      0     stevel static int is_amd64(void);
    290   6582      setje static char *get_machine(void);
    291      0     stevel static void append_to_flist(filelist_t *, char *);
    292   6448     vikram static char *mount_top_dataset(char *pool, zfs_mnted_t *mnted);
    293   6448     vikram static int umount_top_dataset(char *pool, zfs_mnted_t mnted, char *mntpt);
    294   6448     vikram static int ufs_add_to_sign_list(char *sign);
    295   6694     vikram static error_t synchronize_BE_menu(void);
    296      0     stevel 
    297   5648      setje #if !defined(_OPB)
    298   4581    sherrym static void ucode_install();
    299   4581    sherrym #endif
    300   4581    sherrym 
    301      0     stevel /* Menu related sub commands */
    302      0     stevel static subcmd_defn_t menu_subcmds[] = {
    303   6448     vikram 	"set_option",		OPT_ABSENT,	set_option, 0,	/* PUB */
    304   2115     vikram 	"list_entry",		OPT_OPTIONAL,	list_entry, 1,	/* PUB */
    305   2115     vikram 	"delete_all_entries",	OPT_ABSENT,	delete_all_entries, 0, /* PVT */
    306   2115     vikram 	"update_entry",		OPT_REQ,	update_entry, 0, /* menu */
    307   2115     vikram 	"update_temp",		OPT_OPTIONAL,	update_temp, 0,	/* reboot */
    308   3446        mrj 	"upgrade",		OPT_ABSENT,	upgrade_menu, 0, /* menu */
    309  10499    William 	"list_setting",		OPT_OPTIONAL,	list_setting, 1, /* menu */
    310  10499    William 	"disable_hypervisor",	OPT_ABSENT,	cvt_to_metal, 0, /* menu */
    311  10499    William 	"enable_hypervisor",	OPT_ABSENT,	cvt_to_hyper, 0, /* menu */
    312   2115     vikram 	NULL,			0,		NULL, 0	/* must be last */
    313      0     stevel };
    314      0     stevel 
    315      0     stevel /* Archive related sub commands */
    316      0     stevel static subcmd_defn_t arch_subcmds[] = {
    317   2115     vikram 	"update",		OPT_ABSENT,	update_archive, 0, /* PUB */
    318   2115     vikram 	"update_all",		OPT_ABSENT,	update_all, 0,	/* PVT */
    319   2115     vikram 	"list",			OPT_OPTIONAL,	list_archive, 1, /* PUB */
    320   2115     vikram 	NULL,			0,		NULL, 0	/* must be last */
    321      0     stevel };
    322      0     stevel 
    323   8735     Enrico enum dircache_copy_opt {
    324   8735     Enrico 	FILE32 = 0,
    325   8735     Enrico 	FILE64,
    326   8735     Enrico 	CACHEDIR_NUM
    327   8735     Enrico };
    328   8735     Enrico 
    329   8735     Enrico /*
    330   8735     Enrico  * Directory specific flags:
    331   8735     Enrico  * NEED_UPDATE : the specified archive needs to be updated
    332   8735     Enrico  * NO_MULTI : don't extend the specified archive, but recreate it
    333   8735     Enrico  */
    334   8735     Enrico #define	NEED_UPDATE		0x00000001
    335   8735     Enrico #define	NO_MULTI		0x00000002
    336   8735     Enrico 
    337   8735     Enrico #define	set_dir_flag(id, f)	(walk_arg.dirinfo[id].flags |= f)
    338   8735     Enrico #define	unset_dir_flag(id, f)	(walk_arg.dirinfo[id].flags &= ~f)
    339   8735     Enrico #define	is_dir_flag_on(id, f)	(walk_arg.dirinfo[id].flags & f ? 1 : 0)
    340   8735     Enrico 
    341   8735     Enrico #define	get_cachedir(id)	(walk_arg.dirinfo[id].cdir_path)
    342   8735     Enrico #define	get_updatedir(id)	(walk_arg.dirinfo[id].update_path)
    343   8735     Enrico #define	get_count(id)		(walk_arg.dirinfo[id].count)
    344   8735     Enrico #define	has_cachedir(id)	(walk_arg.dirinfo[id].has_dir)
    345   8735     Enrico #define	set_dir_present(id)	(walk_arg.dirinfo[id].has_dir = 1)
    346   8735     Enrico 
    347   8735     Enrico /*
    348   8735     Enrico  * dirinfo_t (specific cache directory information):
    349   8735     Enrico  * cdir_path:   path to the archive cache directory
    350   8735     Enrico  * update_path: path to the update directory (contains the files that will be
    351   8735     Enrico  *              used to extend the archive)
    352   8735     Enrico  * has_dir:	the specified cache directory is active
    353   8735     Enrico  * count:	the number of files to update
    354   8735     Enrico  * flags:	directory specific flags
    355   8735     Enrico  */
    356   8735     Enrico typedef struct _dirinfo {
    357   8735     Enrico 	char	cdir_path[PATH_MAX];
    358   8735     Enrico 	char	update_path[PATH_MAX];
    359   8735     Enrico 	int	has_dir;
    360   8735     Enrico 	int	count;
    361   8735     Enrico 	int	flags;
    362   8735     Enrico } dirinfo_t;
    363   8735     Enrico 
    364   8735     Enrico /*
    365   8735     Enrico  * Update flags:
    366   8735     Enrico  * NEED_CACHE_DIR : cache directory is missing and needs to be created
    367   8735     Enrico  * IS_SPARC_TARGET : the target mountpoint is a SPARC environment
    368   8735     Enrico  * UPDATE_ERROR : an error occourred while traversing the list of files
    369   8735     Enrico  * RDONLY_FSCHK : the target filesystem is read-only
    370   8735     Enrico  * RAMDSK_FSCHK : the target filesystem is on a ramdisk
    371   8735     Enrico  */
    372   8735     Enrico #define	NEED_CACHE_DIR		0x00000001
    373   8735     Enrico #define	IS_SPARC_TARGET		0x00000002
    374   8735     Enrico #define	UPDATE_ERROR		0x00000004
    375   8735     Enrico #define	RDONLY_FSCHK		0x00000008
    376   9233     Enrico #define	INVALIDATE_CACHE	0x00000010
    377   8735     Enrico 
    378   8735     Enrico #define	is_flag_on(flag)	(walk_arg.update_flags & flag ? 1 : 0)
    379   8735     Enrico #define	set_flag(flag)		(walk_arg.update_flags |= flag)
    380   8735     Enrico #define	unset_flag(flag)	(walk_arg.update_flags &= ~flag)
    381   8735     Enrico 
    382   8735     Enrico /*
    383   8735     Enrico  * struct walk_arg :
    384   8735     Enrico  * update_flags: flags related to the current updating process
    385   8735     Enrico  * new_nvlp/old_nvlp: new and old list of archive-files / attributes pairs
    386   8735     Enrico  * sparcfile: list of file paths for mkisofs -path-list (SPARC only)
    387   8735     Enrico  */
    388      0     stevel static struct {
    389   8735     Enrico 	int 		update_flags;
    390   8735     Enrico 	nvlist_t 	*new_nvlp;
    391   8735     Enrico 	nvlist_t 	*old_nvlp;
    392   8735     Enrico 	FILE 		*sparcfile;
    393   8735     Enrico 	dirinfo_t	dirinfo[CACHEDIR_NUM];
    394      0     stevel } walk_arg;
    395   2334      setje 
    396   2345      setje struct safefile {
    397   2334      setje 	char *name;
    398   2334      setje 	struct safefile *next;
    399   2334      setje };
    400   2334      setje 
    401   3446        mrj static struct safefile *safefiles = NULL;
    402   2334      setje #define	NEED_UPDATE_FILE "/etc/svc/volatile/boot_archive_needs_update"
    403      0     stevel 
    404   8735     Enrico /* Thanks growisofs */
    405   8735     Enrico #define	CD_BLOCK	((off64_t)2048)
    406   8735     Enrico #define	VOLDESC_OFF	16
    407   8735     Enrico #define	DVD_BLOCK	(32*1024)
    408   8735     Enrico #define	MAX_IVDs	16
    409   8735     Enrico 
    410   8735     Enrico struct iso_pdesc {
    411   8735     Enrico     unsigned char type	[1];
    412   8735     Enrico     unsigned char id	[5];
    413   8735     Enrico     unsigned char void1	[80-5-1];
    414   8735     Enrico     unsigned char volume_space_size [8];
    415   8735     Enrico     unsigned char void2	[2048-80-8];
    416   8735     Enrico };
    417   8735     Enrico 
    418   8735     Enrico /*
    419   8735     Enrico  * COUNT_MAX:	maximum number of changed files to justify a multisession update
    420   8735     Enrico  * BA_SIZE_MAX:	maximum size of the boot_archive to justify a multisession
    421   8735     Enrico  * 		update
    422   8735     Enrico  */
    423   8735     Enrico #define	COUNT_MAX		50
    424   8735     Enrico #define	BA_SIZE_MAX		(50 * 1024 * 1024)
    425   8735     Enrico 
    426   8735     Enrico #define	bam_nowrite()		(bam_check || bam_smf_check)
    427   8735     Enrico 
    428   7656     Sherry static int sync_menu = 1;	/* whether we need to sync the BE menus */
    429   7656     Sherry 
    430      0     stevel static void
    431      0     stevel usage(void)
    432      0     stevel {
    433      0     stevel 	(void) fprintf(stderr, "USAGE:\n");
    434      0     stevel 
    435      0     stevel 	/* archive usage */
    436   6319         jg 	(void) fprintf(stderr,
    437   6319         jg 	    "\t%s update-archive [-vn] [-R altroot [-p platform>]]\n", prog);
    438   6319         jg 	(void) fprintf(stderr,
    439   6319         jg 	    "\t%s list-archive [-R altroot [-p platform>]]\n", prog);
    440   5648      setje #if !defined(_OPB)
    441      0     stevel 	/* x86 only */
    442      0     stevel 	(void) fprintf(stderr, "\t%s set-menu [-R altroot] key=value\n", prog);
    443      0     stevel 	(void) fprintf(stderr, "\t%s list-menu [-R altroot]\n", prog);
    444      0     stevel #endif
    445      0     stevel }
    446      0     stevel 
    447   8954     Enrico /*
    448   8954     Enrico  * Best effort attempt to restore the $HOME value.
    449   8954     Enrico  */
    450   8954     Enrico static void
    451   8954     Enrico restore_env()
    452   8954     Enrico {
    453   8954     Enrico 	char	home_env[PATH_MAX];
    454   8954     Enrico 
    455   8954     Enrico 	if (bam_home_env) {
    456   8954     Enrico 		(void) snprintf(home_env, sizeof (home_env), "HOME=%s",
    457   8954     Enrico 		    bam_home_env);
    458   8954     Enrico 		(void) putenv(home_env);
    459   8954     Enrico 	}
    460   8954     Enrico }
    461   8954     Enrico 
    462   8954     Enrico 
    463   8954     Enrico #define		SLEEP_TIME	5
    464   8954     Enrico #define		MAX_TRIES	4
    465   8954     Enrico 
    466   8954     Enrico /*
    467   8954     Enrico  * Sanitize the environment in which bootadm will execute its sub-processes
    468   8954     Enrico  * (ex. mkisofs). This is done to prevent those processes from attempting
    469   8954     Enrico  * to access files (ex. .mkisofsrc) or stat paths that might be on NFS
    470   8954     Enrico  * or, potentially, insecure.
    471   8954     Enrico  */
    472   8954     Enrico static void
    473   8954     Enrico sanitize_env()
    474   8954     Enrico {
    475   8954     Enrico 	int	stry = 0;
    476   8954     Enrico 
    477   8954     Enrico 	/* don't depend on caller umask */
    478   8954     Enrico 	(void) umask(0022);
    479   8954     Enrico 
    480   8954     Enrico 	/* move away from a potential unsafe current working directory */
    481   8954     Enrico 	while (chdir("/") == -1) {
    482   8954     Enrico 		if (errno != EINTR) {
    483   8954     Enrico 			bam_print("WARNING: unable to chdir to /");
    484   8954     Enrico 			break;
    485   8954     Enrico 		}
    486   8954     Enrico 	}
    487   8954     Enrico 
    488   8954     Enrico 	bam_home_env = getenv("HOME");
    489   8954     Enrico 	while (bam_home_env != NULL && putenv("HOME=/") == -1) {
    490   8954     Enrico 		if (errno == ENOMEM) {
    491   8954     Enrico 			/* retry no more than MAX_TRIES times */
    492   8954     Enrico 			if (++stry > MAX_TRIES) {
    493   8954     Enrico 				bam_print("WARNING: unable to recover from "
    494   8954     Enrico 				    "system memory pressure... aborting \n");
    495   8954     Enrico 				bam_exit(EXIT_FAILURE);
    496   8954     Enrico 			}
    497   8954     Enrico 			/* memory is tight, try to sleep */
    498   8954     Enrico 			bam_print("Attempting to recover from memory pressure: "
    499   8954     Enrico 			    "sleeping for %d seconds\n", SLEEP_TIME * stry);
    500   8954     Enrico 			(void) sleep(SLEEP_TIME * stry);
    501   8954     Enrico 		} else {
    502   8954     Enrico 			bam_print("WARNING: unable to sanitize HOME\n");
    503   8954     Enrico 		}
    504   8954     Enrico 	}
    505   8954     Enrico }
    506   8954     Enrico 
    507      0     stevel int
    508      0     stevel main(int argc, char *argv[])
    509      0     stevel {
    510      0     stevel 	error_t ret;
    511      0     stevel 
    512      0     stevel 	(void) setlocale(LC_ALL, "");
    513      0     stevel 	(void) textdomain(TEXT_DOMAIN);
    514      0     stevel 
    515      0     stevel 	if ((prog = strrchr(argv[0], '/')) == NULL) {
    516      0     stevel 		prog = argv[0];
    517      0     stevel 	} else {
    518      0     stevel 		prog++;
    519      0     stevel 	}
    520      0     stevel 
    521   6448     vikram 	INJECT_ERROR1("ASSERT_ON", assert(0))
    522      0     stevel 
    523   8954     Enrico 	sanitize_env();
    524      0     stevel 
    525      0     stevel 	parse_args(argc, argv);
    526      0     stevel 
    527      0     stevel 	switch (bam_cmd) {
    528      0     stevel 		case BAM_MENU:
    529      0     stevel 			ret = bam_menu(bam_subcmd, bam_opt, bam_argc, bam_argv);
    530      0     stevel 			break;
    531      0     stevel 		case BAM_ARCHIVE:
    532      0     stevel 			ret = bam_archive(bam_subcmd, bam_opt);
    533      0     stevel 			break;
    534      0     stevel 		default:
    535      0     stevel 			usage();
    536      0     stevel 			bam_exit(1);
    537      0     stevel 	}
    538      0     stevel 
    539      0     stevel 	if (ret != BAM_SUCCESS)
    540  10499    William 		bam_exit((ret == BAM_NOCHANGE) ? 2 : 1);
    541      0     stevel 
    542      0     stevel 	bam_unlock();
    543      0     stevel 	return (0);
    544      0     stevel }
    545      0     stevel 
    546      0     stevel /*
    547      0     stevel  * Equivalence of public and internal commands:
    548      0     stevel  *	update-archive  -- -a update
    549      0     stevel  *	list-archive	-- -a list
    550      0     stevel  *	set-menu	-- -m set_option
    551      0     stevel  *	list-menu	-- -m list_entry
    552      0     stevel  *	update-menu	-- -m update_entry
    553      0     stevel  */
    554      0     stevel static struct cmd_map {
    555      0     stevel 	char *bam_cmdname;
    556      0     stevel 	int bam_cmd;
    557      0     stevel 	char *bam_subcmd;
    558      0     stevel } cmd_map[] = {
    559      0     stevel 	{ "update-archive",	BAM_ARCHIVE,	"update"},
    560      0     stevel 	{ "list-archive",	BAM_ARCHIVE,	"list"},
    561      0     stevel 	{ "set-menu",		BAM_MENU,	"set_option"},
    562      0     stevel 	{ "list-menu",		BAM_MENU,	"list_entry"},
    563      0     stevel 	{ "update-menu",	BAM_MENU,	"update_entry"},
    564      0     stevel 	{ NULL,			0,		NULL}
    565      0     stevel };
    566      0     stevel 
    567      0     stevel /*
    568      0     stevel  * Commands syntax published in bootadm(1M) are parsed here
    569      0     stevel  */
    570      0     stevel static void
    571      0     stevel parse_args(int argc, char *argv[])
    572      0     stevel {
    573      0     stevel 	struct cmd_map *cmp = cmd_map;
    574      0     stevel 
    575      0     stevel 	/* command conforming to the final spec */
    576      0     stevel 	if (argc > 1 && argv[1][0] != '-') {
    577      0     stevel 		/*
    578      0     stevel 		 * Map commands to internal table.
    579      0     stevel 		 */
    580      0     stevel 		while (cmp->bam_cmdname) {
    581      0     stevel 			if (strcmp(argv[1], cmp->bam_cmdname) == 0) {
    582      0     stevel 				bam_cmd = cmp->bam_cmd;
    583      0     stevel 				bam_subcmd = cmp->bam_subcmd;
    584      0     stevel 				break;
    585      0     stevel 			}
    586      0     stevel 			cmp++;
    587      0     stevel 		}
    588      0     stevel 		if (cmp->bam_cmdname == NULL) {
    589      0     stevel 			usage();
    590      0     stevel 			bam_exit(1);
    591      0     stevel 		}
    592      0     stevel 		argc--;
    593      0     stevel 		argv++;
    594      0     stevel 	}
    595      0     stevel 
    596      0     stevel 	parse_args_internal(argc, argv);
    597      0     stevel }
    598      0     stevel 
    599      0     stevel /*
    600      0     stevel  * A combination of public and private commands are parsed here.
    601      0     stevel  * The internal syntax and the corresponding functionality are:
    602  10499    William  *	-a update			-- update-archive
    603  10499    William  *	-a list				-- list-archive
    604  10499    William  *	-a update-all			-- (reboot to sync all mnted OS archive)
    605  10499    William  *	-m update_entry			-- update-menu
    606  10499    William  *	-m list_entry			-- list-menu
    607  10499    William  *	-m update_temp			-- (reboot -- [boot-args])
    608  10499    William  *	-m delete_all_entries		-- (called from install)
    609  10499    William  *	-m enable_hypervisor [args]	-- cvt_to_hyper
    610  10499    William  *	-m disable_hypervisor		-- cvt_to_metal
    611  10499    William  *	-m list_setting [entry] [value]	-- list_setting
    612  10499    William  *
    613   8735     Enrico  * A set of private flags is there too:
    614   8735     Enrico  *	-F		-- purge the cache directories and rebuild them
    615   8735     Enrico  *	-e		-- use the (faster) archive update approach (used by
    616   8735     Enrico  *			   reboot)
    617      0     stevel  */
    618      0     stevel static void
    619      0     stevel parse_args_internal(int argc, char *argv[])
    620      0     stevel {
    621      0     stevel 	int c, error;
    622      0     stevel 	extern char *optarg;
    623      0     stevel 	extern int optind, opterr;
    624      0     stevel 
    625      0     stevel 	/* Suppress error message from getopt */
    626      0     stevel 	opterr = 0;
    627      0     stevel 
    628      0     stevel 	error = 0;
    629  10405      Frank 	while ((c = getopt(argc, argv, "a:d:fm:no:veFCR:p:XZ")) != -1) {
    630      0     stevel 		switch (c) {
    631      0     stevel 		case 'a':
    632      0     stevel 			if (bam_cmd) {
    633      0     stevel 				error = 1;
    634      0     stevel 				bam_error(MULT_CMDS, c);
    635      0     stevel 			}
    636      0     stevel 			bam_cmd = BAM_ARCHIVE;
    637      0     stevel 			bam_subcmd = optarg;
    638      0     stevel 			break;
    639      0     stevel 		case 'd':
    640      0     stevel 			if (bam_debug) {
    641      0     stevel 				error = 1;
    642      0     stevel 				bam_error(DUP_OPT, c);
    643      0     stevel 			}
    644      0     stevel 			bam_debug = s_strtol(optarg);
    645      0     stevel 			break;
    646      0     stevel 		case 'f':
    647      0     stevel 			bam_force = 1;
    648   8735     Enrico 			break;
    649   8735     Enrico 		case 'F':
    650   8735     Enrico 			bam_purge = 1;
    651      0     stevel 			break;
    652      0     stevel 		case 'm':
    653      0     stevel 			if (bam_cmd) {
    654      0     stevel 				error = 1;
    655      0     stevel 				bam_error(MULT_CMDS, c);
    656      0     stevel 			}
    657      0     stevel 			bam_cmd = BAM_MENU;
    658      0     stevel 			bam_subcmd = optarg;
    659      0     stevel 			break;
    660      0     stevel 		case 'n':
    661      0     stevel 			bam_check = 1;
    662   9216     Enrico 			/*
    663   9216     Enrico 			 * We save the original value of bam_check. The new
    664   9216     Enrico 			 * approach in case of a read-only filesystem is to
    665   9216     Enrico 			 * behave as a check, so we need a way to restore the
    666   9216     Enrico 			 * original value after the evaluation of the read-only
    667   9216     Enrico 			 * filesystem has been done.
    668   9216     Enrico 			 * Even if we don't allow at the moment a check with
    669   9216     Enrico 			 * update_all, this approach is more robust than
    670   9216     Enrico 			 * simply resetting bam_check to zero.
    671   9216     Enrico 			 */
    672   9216     Enrico 			bam_saved_check = 1;
    673      0     stevel 			break;
    674      0     stevel 		case 'o':
    675      0     stevel 			if (bam_opt) {
    676      0     stevel 				error = 1;
    677      0     stevel 				bam_error(DUP_OPT, c);
    678      0     stevel 			}
    679      0     stevel 			bam_opt = optarg;
    680      0     stevel 			break;
    681      0     stevel 		case 'v':
    682      0     stevel 			bam_verbose = 1;
    683      0     stevel 			break;
    684    662      szhou 		case 'C':
    685    662      szhou 			bam_smf_check = 1;
    686    662      szhou 			break;
    687      0     stevel 		case 'R':
    688      0     stevel 			if (bam_root) {
    689      0     stevel 				error = 1;
    690      0     stevel 				bam_error(DUP_OPT, c);
    691      0     stevel 				break;
    692      0     stevel 			} else if (realpath(optarg, rootbuf) == NULL) {
    693      0     stevel 				error = 1;
    694      0     stevel 				bam_error(CANT_RESOLVE, optarg,
    695      0     stevel 				    strerror(errno));
    696      0     stevel 				break;
    697      0     stevel 			}
    698    621     vikram 			bam_alt_root = 1;
    699      0     stevel 			bam_root = rootbuf;
    700      0     stevel 			bam_rootlen = strlen(rootbuf);
    701      0     stevel 			break;
    702   6319         jg 		case 'p':
    703   6319         jg 			bam_alt_platform = 1;
    704   6319         jg 			bam_platform = optarg;
    705   6319         jg 			if ((strcmp(bam_platform, "i86pc") != 0) &&
    706   6319         jg 			    (strcmp(bam_platform, "sun4u") != 0) &&
    707   6319         jg 			    (strcmp(bam_platform, "sun4v") != 0)) {
    708   6319         jg 				error = 1;
    709   6319         jg 				bam_error(INVALID_PLAT, bam_platform);
    710   6319         jg 			}
    711  10405      Frank 			break;
    712  10405      Frank 		case 'X':
    713  10405      Frank 			bam_is_hv = BAM_HV_PRESENT;
    714   6423    gw25295 			break;
    715   6423    gw25295 		case 'Z':
    716   6423    gw25295 			bam_zfs = 1;
    717   8735     Enrico 			break;
    718   8735     Enrico 		case 'e':
    719   8735     Enrico 			bam_extend = 1;
    720   6319         jg 			break;
    721      0     stevel 		case '?':
    722      0     stevel 			error = 1;
    723      0     stevel 			bam_error(BAD_OPT, optopt);
    724      0     stevel 			break;
    725      0     stevel 		default :
    726      0     stevel 			error = 1;
    727      0     stevel 			bam_error(BAD_OPT, c);
    728      0     stevel 			break;
    729      0     stevel 		}
    730   6319         jg 	}
    731   6319         jg 
    732   6319         jg 	/*
    733   6319         jg 	 * An alternate platform requires an alternate root
    734   6319         jg 	 */
    735   6319         jg 	if (bam_alt_platform && bam_alt_root == 0) {
    736   6319         jg 		usage();
    737   6319         jg 		bam_exit(0);
    738      0     stevel 	}
    739      0     stevel 
    740      0     stevel 	/*
    741      0     stevel 	 * A command option must be specfied
    742      0     stevel 	 */
    743      0     stevel 	if (!bam_cmd) {
    744      0     stevel 		if (bam_opt && strcmp(bam_opt, "all") == 0) {
    745      0     stevel 			usage();
    746      0     stevel 			bam_exit(0);
    747      0     stevel 		}
    748      0     stevel 		bam_error(NEED_CMD);
    749      0     stevel 		error = 1;
    750      0     stevel 	}
    751      0     stevel 
    752      0     stevel 	if (error) {
    753      0     stevel 		usage();
    754      0     stevel 		bam_exit(1);
    755      0     stevel 	}
    756      0     stevel 
    757      0     stevel 	if (optind > argc) {
    758      0     stevel 		bam_error(INT_ERROR, "parse_args");
    759      0     stevel 		bam_exit(1);
    760      0     stevel 	} else if (optind < argc) {
    761      0     stevel 		bam_argv = &argv[optind];
    762      0     stevel 		bam_argc = argc - optind;
    763      0     stevel 	}
    764      0     stevel 
    765      0     stevel 	/*
    766      0     stevel 	 * -n implies verbose mode
    767      0     stevel 	 */
    768      0     stevel 	if (bam_check)
    769      0     stevel 		bam_verbose = 1;
    770      0     stevel }
    771      0     stevel 
    772      0     stevel static error_t
    773      0     stevel check_subcmd_and_options(
    774      0     stevel 	char *subcmd,
    775      0     stevel 	char *opt,
    776      0     stevel 	subcmd_defn_t *table,
    777      0     stevel 	error_t (**fp)())
    778      0     stevel {
    779      0     stevel 	int i;
    780      0     stevel 
    781      0     stevel 	if (subcmd == NULL) {
    782      0     stevel 		bam_error(NEED_SUBCMD);
    783      0     stevel 		return (BAM_ERROR);
    784      0     stevel 	}
    785      0     stevel 
    786   6448     vikram 	if (strcmp(subcmd, "set_option") == 0) {
    787   6448     vikram 		if (bam_argc == 0 || bam_argv == NULL || bam_argv[0] == NULL) {
    788   6448     vikram 			bam_error(MISSING_ARG);
    789   6448     vikram 			usage();
    790   6448     vikram 			return (BAM_ERROR);
    791   6448     vikram 		} else if (bam_argc > 1 || bam_argv[1] != NULL) {
    792   2115     vikram 			bam_error(TRAILING_ARGS);
    793   2115     vikram 			usage();
    794   2115     vikram 			return (BAM_ERROR);
    795   2115     vikram 		}
    796   7656     Sherry 	} else if (strcmp(subcmd, "update_all") == 0) {
    797   7656     Sherry 		/*
    798   7656     Sherry 		 * The only option we accept for the "update_all"
    799   7656     Sherry 		 * subcmd is "fastboot".
    800   7656     Sherry 		 */
    801   7656     Sherry 		if (bam_argc > 1 || (bam_argc == 1 &&
    802   7656     Sherry 		    strcmp(bam_argv[0], "fastboot") != 0)) {
    803   7656     Sherry 			bam_error(TRAILING_ARGS);
    804   7656     Sherry 			usage();
    805   7656     Sherry 			return (BAM_ERROR);
    806   7656     Sherry 		}
    807   7656     Sherry 		if (bam_argc == 1)
    808   7656     Sherry 			sync_menu = 0;
    809  10499    William 	} else if (((strcmp(subcmd, "enable_hypervisor") != 0) &&
    810  10499    William 	    (strcmp(subcmd, "list_setting") != 0)) && (bam_argc || bam_argv)) {
    811  10499    William 		/*
    812  10499    William 		 * Of the remaining subcommands, only "enable_hypervisor" and
    813  10499    William 		 * "list_setting" take trailing arguments.
    814  10499    William 		 */
    815   6448     vikram 		bam_error(TRAILING_ARGS);
    816   6448     vikram 		usage();
    817   6448     vikram 		return (BAM_ERROR);
    818   2115     vikram 	}
    819   2115     vikram 
    820      0     stevel 	if (bam_root == NULL) {
    821      0     stevel 		bam_root = rootbuf;
    822      0     stevel 		bam_rootlen = 1;
    823      0     stevel 	}
    824      0     stevel 
    825      0     stevel 	/* verify that subcmd is valid */
    826      0     stevel 	for (i = 0; table[i].subcmd != NULL; i++) {
    827      0     stevel 		if (strcmp(table[i].subcmd, subcmd) == 0)
    828      0     stevel 			break;
    829      0     stevel 	}
    830      0     stevel 
    831      0     stevel 	if (table[i].subcmd == NULL) {
    832      0     stevel 		bam_error(INVALID_SUBCMD, subcmd);
    833      0     stevel 		return (BAM_ERROR);
    834      0     stevel 	}
    835   2115     vikram 
    836   2115     vikram 	if (table[i].unpriv == 0 && geteuid() != 0) {
    837   2115     vikram 		bam_error(MUST_BE_ROOT);
    838   2115     vikram 		return (BAM_ERROR);
    839   2115     vikram 	}
    840   2115     vikram 
    841   2115     vikram 	/*
    842   2115     vikram 	 * Currently only privileged commands need a lock
    843   2115     vikram 	 */
    844   2115     vikram 	if (table[i].unpriv == 0)
    845   2115     vikram 		bam_lock();
    846      0     stevel 
    847      0     stevel 	/* subcmd verifies that opt is appropriate */
    848      0     stevel 	if (table[i].option != OPT_OPTIONAL) {
    849      0     stevel 		if ((table[i].option == OPT_REQ) ^ (opt != NULL)) {
    850      0     stevel 			if (opt)
    851      0     stevel 				bam_error(NO_OPT_REQ, subcmd);
    852      0     stevel 			else
    853      0     stevel 				bam_error(MISS_OPT, subcmd);
    854      0     stevel 			return (BAM_ERROR);
    855      0     stevel 		}
    856      0     stevel 	}
    857      0     stevel 
    858      0     stevel 	*fp = table[i].handler;
    859      0     stevel 
    860      0     stevel 	return (BAM_SUCCESS);
    861      0     stevel }
    862      0     stevel 
    863    621     vikram /*
    864    621     vikram  * NOTE: A single "/" is also considered a trailing slash and will
    865    621     vikram  * be deleted.
    866    621     vikram  */
    867    621     vikram static void
    868    621     vikram elide_trailing_slash(const char *src, char *dst, size_t dstsize)
    869    621     vikram {
    870    621     vikram 	size_t dstlen;
    871    621     vikram 
    872    621     vikram 	assert(src);
    873    621     vikram 	assert(dst);
    874    621     vikram 
    875    621     vikram 	(void) strlcpy(dst, src, dstsize);
    876    621     vikram 
    877    621     vikram 	dstlen = strlen(dst);
    878    621     vikram 	if (dst[dstlen - 1] == '/') {
    879    621     vikram 		dst[dstlen - 1] = '\0';
    880    621     vikram 	}
    881   8954     Enrico }
    882   8954     Enrico 
    883   8954     Enrico static int
    884   8954     Enrico is_safe_exec(char *path)
    885   8954     Enrico {
    886   8954     Enrico 	struct stat	sb;
    887   8954     Enrico 
    888   8954     Enrico 	if (lstat(path, &sb) != 0) {
    889   8954     Enrico 		bam_error(STAT_FAIL, path, strerror(errno));
    890   8954     Enrico 		return (BAM_ERROR);
    891   8954     Enrico 	}
    892   8954     Enrico 
    893   8954     Enrico 	if (!S_ISREG(sb.st_mode)) {
    894   8954     Enrico 		bam_error(PATH_EXEC_LINK, path);
    895   8954     Enrico 		return (BAM_ERROR);
    896   8954     Enrico 	}
    897   8954     Enrico 
    898   8954     Enrico 	if (sb.st_uid != getuid()) {
    899   8954     Enrico 		bam_error(PATH_EXEC_OWNER, path, getuid());
    900   8954     Enrico 		return (BAM_ERROR);
    901   8954     Enrico 	}
    902   8954     Enrico 
    903   8954     Enrico 	if (sb.st_mode & S_IWOTH || sb.st_mode & S_IWGRP) {
    904   8954     Enrico 		bam_error(PATH_EXEC_PERMS, path);
    905  10499    William 		return (BAM_ERROR);
    906  10499    William 	}
    907  10499    William 
    908  10499    William 	return (BAM_SUCCESS);
    909  10499    William }
    910  10499    William 
    911  10499    William static error_t
    912  10499    William list_setting(menu_t *mp, char *which, char *setting)
    913  10499    William {
    914  10499    William 	line_t	*lp;
    915  10499    William 	entry_t	*ent;
    916  10499    William 
    917  10499    William 	char	*p = which;
    918  10499    William 	int	entry;
    919  10499    William 
    920  10499    William 	int	found;
    921  10499    William 
    922  10499    William 	assert(which);
    923  10499    William 	assert(setting);
    924  10499    William 
    925  10499    William 	if (*which != NULL) {
    926  10499    William 		/*
    927  10499    William 		 * If "which" is not a number, assume it's a setting we want
    928  10499    William 		 * to look for and so set up the routine to look for "which"
    929  10499    William 		 * in the default entry.
    930  10499    William 		 */
    931  10499    William 		while (*p != NULL)
    932  10499    William 			if (!(isdigit((int)*p++))) {
    933  10499    William 				setting = which;
    934  10499    William 				which = mp->curdefault->arg;
    935  10499    William 				break;
    936  10499    William 			}
    937  10499    William 	} else {
    938  10499    William 		which = mp->curdefault->arg;
    939  10499    William 	}
    940  10499    William 
    941  10499    William 	entry = atoi(which);
    942  10499    William 
    943  10499    William 	for (ent = mp->entries; ((ent != NULL) && (ent->entryNum != entry));
    944  10499    William 	    ent = ent->next)
    945  10499    William 		;
    946  10499    William 
    947  10499    William 	if (!ent) {
    948  10499    William 		bam_error(NO_MATCH_ENTRY);
    949  10499    William 		return (BAM_ERROR);
    950  10499    William 	}
    951  10499    William 
    952  10499    William 	found = (*setting == NULL);
    953  10499    William 
    954  10499    William 	for (lp = ent->start; lp != NULL; lp = lp->next) {
    955  10499    William 		if ((*setting == NULL) && (lp->flags != BAM_COMMENT))
    956  10499    William 			bam_print(PRINT, lp->line);
    957  10499    William 		else if (strcmp(setting, lp->cmd) == 0) {
    958  10499    William 			bam_print(PRINT, lp->arg);
    959  10499    William 			found = 1;
    960  10499    William 		}
    961  10499    William 
    962  10499    William 		if (lp == ent->end)
    963  10499    William 			break;
    964  10499    William 	}
    965  10499    William 
    966  10499    William 	if (!found) {
    967  10499    William 		bam_error(NO_MATCH_ENTRY);
    968   8954     Enrico 		return (BAM_ERROR);
    969   8954     Enrico 	}
    970   8954     Enrico 
    971   8954     Enrico 	return (BAM_SUCCESS);
    972    316     vikram }
    973    316     vikram 
    974      0     stevel static error_t
    975      0     stevel bam_menu(char *subcmd, char *opt, int largc, char *largv[])
    976      0     stevel {
    977   6448     vikram 	error_t			ret;
    978   6448     vikram 	char			menu_path[PATH_MAX];
    979   6448     vikram 	char			clean_menu_root[PATH_MAX];
    980   6448     vikram 	char			path[PATH_MAX];
    981   6448     vikram 	menu_t			*menu;
    982   6448     vikram 	char			menu_root[PATH_MAX];
    983   6448     vikram 	struct stat		sb;
    984      0     stevel 	error_t (*f)(menu_t *mp, char *menu_path, char *opt);
    985   6448     vikram 	char			*special;
    986   6448     vikram 	char			*pool = NULL;
    987   6448     vikram 	zfs_mnted_t		zmnted;
    988   6448     vikram 	char			*zmntpt;
    989   6448     vikram 	char			*osdev;
    990   6448     vikram 	char			*osroot;
    991   6448     vikram 	const char		*fcn = "bam_menu()";
    992   5648      setje 
    993   5648      setje 	/*
    994   5648      setje 	 * Menu sub-command only applies to GRUB (i.e. x86)
    995   5648      setje 	 */
    996   6448     vikram 	if (!is_grub(bam_alt_root ? bam_root : "/")) {
    997   6448     vikram 		bam_error(NOT_GRUB_BOOT);
    998   5648      setje 		return (BAM_ERROR);
    999   5648      setje 	}
   1000      0     stevel 
   1001      0     stevel 	/*
   1002      0     stevel 	 * Check arguments
   1003      0     stevel 	 */
   1004      0     stevel 	ret = check_subcmd_and_options(subcmd, opt, menu_subcmds, &f);
   1005      0     stevel 	if (ret == BAM_ERROR) {
   1006      0     stevel 		return (BAM_ERROR);
   1007      0     stevel 	}
   1008      0     stevel 
   1009   6448     vikram 	assert(bam_root);
   1010   6448     vikram 
   1011   6448     vikram 	(void) strlcpy(menu_root, bam_root, sizeof (menu_root));
   1012   6448     vikram 	osdev = osroot = NULL;
   1013   6448     vikram 
   1014   6448     vikram 	if (strcmp(subcmd, "update_entry") == 0) {
   1015   6448     vikram 		assert(opt);
   1016   6448     vikram 
   1017   6448     vikram 		osdev = strtok(opt, ",");
   1018   6448     vikram 		assert(osdev);
   1019   6448     vikram 		osroot = strtok(NULL, ",");
   1020   6448     vikram 		if (osroot) {
   1021   6448     vikram 			/* fixup bam_root so that it points at osroot */
   1022   6448     vikram 			if (realpath(osroot, rootbuf) == NULL) {
   1023   6448     vikram 				bam_error(CANT_RESOLVE, osroot,
   1024   6448     vikram 				    strerror(errno));
   1025   6448     vikram 				return (BAM_ERROR);
   1026   6448     vikram 			}
   1027   6448     vikram 			bam_alt_root = 1;
   1028   6448     vikram 			bam_root  = rootbuf;
   1029   6448     vikram 			bam_rootlen = strlen(rootbuf);
   1030   6448     vikram 		}
   1031   6448     vikram 	}
   1032   6448     vikram 
   1033   6448     vikram 	/*
   1034   6448     vikram 	 * We support menu on PCFS (under certain conditions), but
   1035   6448     vikram 	 * not the OS root
   1036   6448     vikram 	 */
   1037   6448     vikram 	if (is_pcfs(bam_root)) {
   1038   6448     vikram 		bam_error(PCFS_ROOT_NOTSUP, bam_root);
   1039   6448     vikram 		return (BAM_ERROR);
   1040   6448     vikram 	}
   1041   6448     vikram 
   1042   6448     vikram 	if (stat(menu_root, &sb) == -1) {
   1043   6448     vikram 		bam_error(CANNOT_LOCATE_GRUB_MENU);
   1044   6448     vikram 		return (BAM_ERROR);
   1045   6448     vikram 	}
   1046   6448     vikram 
   1047   6448     vikram 	BAM_DPRINTF((D_MENU_ROOT, fcn, menu_root));
   1048   6448     vikram 
   1049   6448     vikram 	/*
   1050   6448     vikram 	 * We no longer use the GRUB slice file. If it exists, then
   1051   6448     vikram 	 * the user is doing something that is unsupported (such as
   1052   6448     vikram 	 * standard upgrading an old Live Upgrade BE). If that
   1053   6448     vikram 	 * happens, mimic existing behavior i.e. pretend that it is
   1054   6448     vikram 	 * not a BE. Emit a warning though.
   1055    621     vikram 	 */
   1056    621     vikram 	if (bam_alt_root) {
   1057   6448     vikram 		(void) snprintf(path, sizeof (path), "%s%s", bam_root,
   1058   6448     vikram 		    GRUB_slice);
   1059   6448     vikram 	} else {
   1060   6448     vikram 		(void) snprintf(path, sizeof (path), "%s", GRUB_slice);
   1061   6448     vikram 	}
   1062   6448     vikram 
   1063   8642     Vikram 	if (bam_verbose && stat(path, &sb) == 0)
   1064   6448     vikram 		bam_error(GRUB_SLICE_FILE_EXISTS, path);
   1065   6448     vikram 
   1066   6448     vikram 	if (is_zfs(menu_root)) {
   1067   6448     vikram 		assert(strcmp(menu_root, bam_root) == 0);
   1068   6448     vikram 		special = get_special(menu_root);
   1069   6448     vikram 		INJECT_ERROR1("Z_MENU_GET_SPECIAL", special = NULL);
   1070   6448     vikram 		if (special == NULL) {
   1071   6448     vikram 			bam_error(CANT_FIND_SPECIAL, menu_root);
   1072   6448     vikram 			return (BAM_ERROR);
   1073   6448     vikram 		}
   1074   6448     vikram 		pool = strtok(special, "/");
   1075   6448     vikram 		INJECT_ERROR1("Z_MENU_GET_POOL", pool = NULL);
   1076   6448     vikram 		if (pool == NULL) {
   1077   6448     vikram 			free(special);
   1078   6448     vikram 			bam_error(CANT_FIND_POOL, menu_root);
   1079   6448     vikram 			return (BAM_ERROR);
   1080   6448     vikram 		}
   1081   6448     vikram 		BAM_DPRINTF((D_Z_MENU_GET_POOL_FROM_SPECIAL, fcn, pool));
   1082   6448     vikram 
   1083   6448     vikram 		zmntpt = mount_top_dataset(pool, &zmnted);
   1084   6448     vikram 		INJECT_ERROR1("Z_MENU_MOUNT_TOP_DATASET", zmntpt = NULL);
   1085   6448     vikram 		if (zmntpt == NULL) {
   1086   6448     vikram 			bam_error(CANT_MOUNT_POOL_DATASET, pool);
   1087   6448     vikram 			free(special);
   1088   6448     vikram 			return (BAM_ERROR);
   1089   6448     vikram 		}
   1090   6448     vikram 		BAM_DPRINTF((D_Z_GET_MENU_MOUNT_TOP_DATASET, fcn, zmntpt));
   1091   6448     vikram 
   1092   6448     vikram 		(void) strlcpy(menu_root, zmntpt, sizeof (menu_root));
   1093   6448     vikram 		BAM_DPRINTF((D_Z_GET_MENU_MENU_ROOT, fcn, menu_root));
   1094   6448     vikram 	}
   1095   6448     vikram 
   1096   6448     vikram 	elide_trailing_slash(menu_root, clean_menu_root,
   1097   6448     vikram 	    sizeof (clean_menu_root));
   1098   6448     vikram 
   1099   6448     vikram 	BAM_DPRINTF((D_CLEAN_MENU_ROOT, fcn, clean_menu_root));
   1100   6448     vikram 
   1101   6448     vikram 	(void) strlcpy(menu_path, clean_menu_root, sizeof (menu_path));
   1102    621     vikram 	(void) strlcat(menu_path, GRUB_MENU, sizeof (menu_path));
   1103    621     vikram 
   1104   6448     vikram 	BAM_DPRINTF((D_MENU_PATH, fcn, menu_path));
   1105   6448     vikram 
   1106   6448     vikram 	/*
   1107   6448     vikram 	 * If listing the menu, display the menu location
   1108    621     vikram 	 */
   1109  10499    William 	if (strcmp(subcmd, "list_entry") == 0)
   1110   6448     vikram 		bam_print(GRUB_MENU_PATH, menu_path);
   1111  10499    William 
   1112  10499    William 	if ((menu = menu_read(menu_path)) == NULL) {
   1113  10499    William 		bam_error(CANNOT_LOCATE_GRUB_MENU_FILE, menu_path);
   1114  10499    William 		if (special != NULL)
   1115  10499    William 			free(special);
   1116  10499    William 
   1117  10499    William 		return (BAM_ERROR);
   1118  10499    William 	}
   1119      0     stevel 
   1120      0     stevel 	/*
   1121   6448     vikram 	 * We already checked the following case in
   1122   6448     vikram 	 * check_subcmd_and_suboptions() above. Complete the
   1123   6448     vikram 	 * final step now.
   1124      0     stevel 	 */
   1125      0     stevel 	if (strcmp(subcmd, "set_option") == 0) {
   1126   6448     vikram 		assert(largc == 1 && largv[0] && largv[1] == NULL);
   1127      0     stevel 		opt = largv[0];
   1128  10499    William 	} else if ((strcmp(subcmd, "enable_hypervisor") != 0) &&
   1129  10499    William 	    (strcmp(subcmd, "list_setting") != 0)) {
   1130   6448     vikram 		assert(largc == 0 && largv == NULL);
   1131   6448     vikram 	}
   1132   6448     vikram 
   1133   6448     vikram 	ret = get_boot_cap(bam_root);
   1134   6448     vikram 	if (ret != BAM_SUCCESS) {
   1135   6448     vikram 		BAM_DPRINTF((D_BOOT_GET_CAP_FAILED, fcn));
   1136   6448     vikram 		goto out;
   1137   6448     vikram 	}
   1138   3446        mrj 
   1139      0     stevel 	/*
   1140      0     stevel 	 * Once the sub-cmd handler has run
   1141      0     stevel 	 * only the line field is guaranteed to have valid values
   1142      0     stevel 	 */
   1143  10499    William 	if (strcmp(subcmd, "update_entry") == 0) {
   1144   6448     vikram 		ret = f(menu, menu_root, osdev);
   1145  10499    William 	} else if (strcmp(subcmd, "upgrade") == 0) {
   1146   6448     vikram 		ret = f(menu, bam_root, menu_root);
   1147  10499    William 	} else if (strcmp(subcmd, "list_entry") == 0) {
   1148   6448     vikram 		ret = f(menu, menu_path, opt);
   1149  10499    William 	} else if (strcmp(subcmd, "list_setting") == 0) {
   1150  10499    William 		ret = f(menu, ((largc > 0) ? largv[0] : ""),
   1151  10499    William 		    ((largc > 1) ? largv[1] : ""));
   1152  10499    William 	} else if (strcmp(subcmd, "disable_hypervisor") == 0) {
   1153  10499    William 		if (is_sparc()) {
   1154  10499    William 			bam_error(NO_SPARC, subcmd);
   1155  10499    William 			ret = BAM_ERROR;
   1156  10499    William 		} else {
   1157  10499    William 			ret = f(menu, bam_root, NULL);
   1158  10499    William 		}
   1159  10499    William 	} else if (strcmp(subcmd, "enable_hypervisor") == 0) {
   1160  10499    William 		if (is_sparc()) {
   1161  10499    William 			bam_error(NO_SPARC, subcmd);
   1162  10499    William 			ret = BAM_ERROR;
   1163  10499    William 		} else {
   1164  10499    William 			char *extra_args = NULL;
   1165  10499    William 
   1166  10499    William 			/*
   1167  10499    William 			 * Compress all arguments passed in the largv[] array
   1168  10499    William 			 * into one string that can then be appended to the
   1169  10499    William 			 * end of the kernel$ string the routine to enable the
   1170  10499    William 			 * hypervisor will build.
   1171  10499    William 			 *
   1172  10499    William 			 * This allows the caller to supply arbitrary unparsed
   1173  10499    William 			 * arguments, such as dom0 memory settings or APIC
   1174  10499    William 			 * options.
   1175  10499    William 			 *
   1176  10499    William 			 * This concatenation will be done without ANY syntax
   1177  10499    William 			 * checking whatsoever, so it's the responsibility of
   1178  10499    William 			 * the caller to make sure the arguments are valid and
   1179  10499    William 			 * do not duplicate arguments the conversion routines
   1180  10499    William 			 * may create.
   1181  10499    William 			 */
   1182  10499    William 			if (largc > 0) {
   1183  10499    William 				int extra_len, i;
   1184  10499    William 
   1185  10499    William 				for (extra_len = 0, i = 0; i < largc; i++)
   1186  10499    William 					extra_len += strlen(largv[i]);
   1187  10499    William 
   1188  10499    William 				/*
   1189  10499    William 				 * Allocate space for argument strings,
   1190  10499    William 				 * intervening spaces and terminating NULL.
   1191  10499    William 				 */
   1192  10499    William 				extra_args = alloca(extra_len + largc);
   1193  10499    William 
   1194  10499    William 				(void) strcpy(extra_args, largv[0]);
   1195  10499    William 
   1196  10499    William 				for (i = 1; i < largc; i++) {
   1197  10499    William 					(void) strcat(extra_args, " ");
   1198  10499    William 					(void) strcat(extra_args, largv[i]);
   1199  10499    William 				}
   1200  10499    William 			}
   1201  10499    William 
   1202  10499    William 			ret = f(menu, bam_root, extra_args);
   1203  10499    William 		}
   1204  10499    William 	} else
   1205   6448     vikram 		ret = f(menu, NULL, opt);
   1206   6448     vikram 
   1207      0     stevel 	if (ret == BAM_WRITE) {
   1208   6448     vikram 		BAM_DPRINTF((D_WRITING_MENU_ROOT, fcn, clean_menu_root));
   1209   6448     vikram 		ret = menu_write(clean_menu_root, menu);
   1210   6448     vikram 	}
   1211   6448     vikram 
   1212   6448     vikram out:
   1213   6448     vikram 	INJECT_ERROR1("POOL_SET", pool = "/pooldata");
   1214   6448     vikram 	assert((is_zfs(menu_root)) ^ (pool == NULL));
   1215   6448     vikram 	if (pool) {
   1216   6448     vikram 		(void) umount_top_dataset(pool, zmnted, zmntpt);
   1217   6448     vikram 		free(special);
   1218   6448     vikram 	}
   1219      0     stevel 	menu_free(menu);
   1220      0     stevel 	return (ret);
   1221      0     stevel }
   1222      0     stevel 
   1223      0     stevel 
   1224      0     stevel static error_t
   1225      0     stevel bam_archive(
   1226      0     stevel 	char *subcmd,
   1227      0     stevel 	char *opt)
   1228      0     stevel {
   1229   6448     vikram 	error_t			ret;
   1230   6448     vikram 	error_t			(*f)(char *root, char *opt);
   1231   6448     vikram 	const char		*fcn = "bam_archive()";
   1232      0     stevel 
   1233      0     stevel 	/*
   1234    662      szhou 	 * Add trailing / for archive subcommands
   1235    662      szhou 	 */
   1236    662      szhou 	if (rootbuf[strlen(rootbuf) - 1] != '/')
   1237    662      szhou 		(void) strcat(rootbuf, "/");
   1238    662      szhou 	bam_rootlen = strlen(rootbuf);
   1239    662      szhou 
   1240    662      szhou 	/*
   1241      0     stevel 	 * Check arguments
   1242      0     stevel 	 */
   1243      0     stevel 	ret = check_subcmd_and_options(subcmd, opt, arch_subcmds, &f);
   1244      0     stevel 	if (ret != BAM_SUCCESS) {
   1245      0     stevel 		return (BAM_ERROR);
   1246      0     stevel 	}
   1247      0     stevel 
   1248   6448     vikram 	ret = get_boot_cap(rootbuf);
   1249   6448     vikram 	if (ret != BAM_SUCCESS) {
   1250   6448     vikram 		BAM_DPRINTF((D_BOOT_GET_CAP_FAILED, fcn));
   1251   3446        mrj 		return (ret);
   1252   6448     vikram 	}
   1253   3446        mrj 
   1254      0     stevel 	/*
   1255      0     stevel 	 * Check archive not supported with update_all
   1256      0     stevel 	 * since it is awkward to display out-of-sync
   1257      0     stevel 	 * information for each BE.
   1258      0     stevel 	 */
   1259      0     stevel 	if (bam_check && strcmp(subcmd, "update_all") == 0) {
   1260      0     stevel 		bam_error(CHECK_NOT_SUPPORTED, subcmd);
   1261      0     stevel 		return (BAM_ERROR);
   1262      0     stevel 	}
   1263      0     stevel 
   1264    316     vikram 	if (strcmp(subcmd, "update_all") == 0)
   1265    316     vikram 		bam_update_all = 1;
   1266   4581    sherrym 
   1267   5648      setje #if !defined(_OPB)
   1268   4581    sherrym 	ucode_install(bam_root);
   1269   4581    sherrym #endif
   1270    316     vikram 
   1271    316     vikram 	ret = f(bam_root, opt);
   1272    316     vikram 
   1273    316     vikram 	bam_update_all = 0;
   1274    316     vikram 
   1275    316     vikram 	return (ret);
   1276      0     stevel }
   1277      0     stevel 
   1278      0     stevel /*PRINTFLIKE1*/
   1279   3446        mrj void
   1280      0     stevel bam_error(char *format, ...)
   1281      0     stevel {
   1282      0     stevel 	va_list ap;
   1283      0     stevel 
   1284      0     stevel 	va_start(ap, format);
   1285      0     stevel 	(void) fprintf(stderr, "%s: ", prog);
   1286      0     stevel 	(void) vfprintf(stderr, format, ap);
   1287      0     stevel 	va_end(ap);
   1288      0     stevel }
   1289      0     stevel 
   1290      0     stevel /*PRINTFLIKE1*/
   1291   6448     vikram void
   1292   6448     vikram bam_derror(char *format, ...)
   1293   6448     vikram {
   1294   6448     vikram 	va_list ap;
   1295   6448     vikram 
   1296   6448     vikram 	assert(bam_debug);
   1297   6448     vikram 
   1298   6448     vikram 	va_start(ap, format);
   1299   6448     vikram 	(void) fprintf(stderr, "DEBUG: ");
   1300   6448     vikram 	(void) vfprintf(stderr, format, ap);
   1301   6448     vikram 	va_end(ap);
   1302   6448     vikram }
   1303   6448     vikram 
   1304   6448     vikram /*PRINTFLIKE1*/
   1305   6448     vikram void
   1306      0     stevel bam_print(char *format, ...)
   1307      0     stevel {
   1308      0     stevel 	va_list ap;
   1309      0     stevel 
   1310      0     stevel 	va_start(ap, format);
   1311      0     stevel 	(void) vfprintf(stdout, format, ap);
   1312   3446        mrj 	va_end(ap);
   1313   3446        mrj }
   1314   3446        mrj 
   1315   3446        mrj /*PRINTFLIKE1*/
   1316   3446        mrj void
   1317   3446        mrj bam_print_stderr(char *format, ...)
   1318   3446        mrj {
   1319   3446        mrj 	va_list ap;
   1320   3446        mrj 
   1321   3446        mrj 	va_start(ap, format);
   1322   3446        mrj 	(void) vfprintf(stderr, format, ap);
   1323      0     stevel 	va_end(ap);
   1324      0     stevel }
   1325      0     stevel 
   1326  10787    William void
   1327      0     stevel bam_exit(int excode)
   1328      0     stevel {
   1329   8954     Enrico 	restore_env();
   1330      0     stevel 	bam_unlock();
   1331      0     stevel 	exit(excode);
   1332      0     stevel }
   1333      0     stevel 
   1334      0     stevel static void
   1335      0     stevel bam_lock(void)
   1336      0     stevel {
   1337      0     stevel 	struct flock lock;
   1338      0     stevel 	pid_t pid;
   1339      0     stevel 
   1340      0     stevel 	bam_lock_fd = open(BAM_LOCK_FILE, O_CREAT|O_RDWR, LOCK_FILE_PERMS);
   1341      0     stevel 	if (bam_lock_fd < 0) {
   1342      0     stevel 		/*
   1343      0     stevel 		 * We may be invoked early in boot for archive verification.
   1344      0     stevel 		 * In this case, root is readonly and /var/run may not exist.
   1345      0     stevel 		 * Proceed without the lock
   1346      0     stevel 		 */
   1347      0     stevel 		if (errno == EROFS || errno == ENOENT) {
   1348      0     stevel 			bam_root_readonly = 1;
   1349      0     stevel 			return;
   1350      0     stevel 		}
   1351      0     stevel 
   1352      0     stevel 		bam_error(OPEN_FAIL, BAM_LOCK_FILE, strerror(errno));
   1353      0     stevel 		bam_exit(1);
   1354      0     stevel 	}
   1355      0     stevel 
   1356      0     stevel 	lock.l_type = F_WRLCK;
   1357      0     stevel 	lock.l_whence = SEEK_SET;
   1358      0     stevel 	lock.l_start = 0;
   1359      0     stevel 	lock.l_len = 0;
   1360      0     stevel 
   1361      0     stevel 	if (fcntl(bam_lock_fd, F_SETLK, &lock) == -1) {
   1362      0     stevel 		if (errno != EACCES && errno != EAGAIN) {
   1363      0     stevel 			bam_error(LOCK_FAIL, BAM_LOCK_FILE, strerror(errno));
   1364      0     stevel 			(void) close(bam_lock_fd);
   1365      0     stevel 			bam_lock_fd = -1;
   1366      0     stevel 			bam_exit(1);
   1367      0     stevel 		}
   1368      0     stevel 		pid = 0;
   1369      0     stevel 		(void) pread(bam_lock_fd, &pid, sizeof (pid_t), 0);
   1370      0     stevel 		bam_print(FILE_LOCKED, pid);
   1371      0     stevel 
   1372      0     stevel 		lock.l_type = F_WRLCK;
   1373      0     stevel 		lock.l_whence = SEEK_SET;
   1374      0     stevel 		lock.l_start = 0;
   1375      0     stevel 		lock.l_len = 0;
   1376      0     stevel 		if (fcntl(bam_lock_fd, F_SETLKW, &lock) == -1) {
   1377      0     stevel 			bam_error(LOCK_FAIL, BAM_LOCK_FILE, strerror(errno));
   1378      0     stevel 			(void) close(bam_lock_fd);
   1379      0     stevel 			bam_lock_fd = -1;
   1380      0     stevel 			bam_exit(1);
   1381      0     stevel 		}
   1382      0     stevel 	}
   1383      0     stevel 
   1384      0     stevel 	/* We own the lock now */
   1385      0     stevel 	pid = getpid();
   1386      0     stevel 	(void) write(bam_lock_fd, &pid, sizeof (pid));
   1387      0     stevel }
   1388      0     stevel 
   1389      0     stevel static void
   1390      0     stevel bam_unlock(void)
   1391      0     stevel {
   1392      0     stevel 	struct flock unlock;
   1393      0     stevel 
   1394      0     stevel 	/*
   1395      0     stevel 	 * NOP if we don't hold the lock
   1396      0     stevel 	 */
   1397      0     stevel 	if (bam_lock_fd < 0) {
   1398      0     stevel 		return;
   1399      0     stevel 	}
   1400      0     stevel 
   1401      0     stevel 	unlock.l_type = F_UNLCK;
   1402      0     stevel 	unlock.l_whence = SEEK_SET;
   1403      0     stevel 	unlock.l_start = 0;
   1404      0     stevel 	unlock.l_len = 0;
   1405      0     stevel 
   1406      0     stevel 	if (fcntl(bam_lock_fd, F_SETLK, &unlock) == -1) {
   1407      0     stevel 		bam_error(UNLOCK_FAIL, BAM_LOCK_FILE, strerror(errno));
   1408      0     stevel 	}
   1409      0     stevel 
   1410      0     stevel 	if (close(bam_lock_fd) == -1) {
   1411      0     stevel 		bam_error(CLOSE_FAIL, BAM_LOCK_FILE, strerror(errno));
   1412      0     stevel 	}
   1413      0     stevel 	bam_lock_fd = -1;
   1414      0     stevel }
   1415      0     stevel 
   1416      0     stevel static error_t
   1417      0     stevel list_archive(char *root, char *opt)
   1418      0     stevel {
   1419      0     stevel 	filelist_t flist;
   1420      0     stevel 	filelist_t *flistp = &flist;
   1421      0     stevel 	line_t *lp;
   1422      0     stevel 
   1423      0     stevel 	assert(root);
   1424      0     stevel 	assert(opt == NULL);
   1425      0     stevel 
   1426      0     stevel 	flistp->head = flistp->tail = NULL;
   1427      0     stevel 	if (read_list(root, flistp) != BAM_SUCCESS) {
   1428      0     stevel 		return (BAM_ERROR);
   1429      0     stevel 	}
   1430      0     stevel 	assert(flistp->head && flistp->tail);
   1431      0     stevel 
   1432      0     stevel 	for (lp = flistp->head; lp; lp = lp->next) {
   1433      0     stevel 		bam_print(PRINT, lp->line);
   1434      0     stevel 	}
   1435      0     stevel 
   1436      0     stevel 	filelist_free(flistp);
   1437      0     stevel 
   1438      0     stevel 	return (BAM_SUCCESS);
   1439      0     stevel }
   1440      0     stevel 
   1441      0     stevel /*
   1442      0     stevel  * This routine writes a list of lines to a file.
   1443      0     stevel  * The list is *not* freed
   1444      0     stevel  */
   1445      0     stevel static error_t
   1446      0     stevel list2file(char *root, char *tmp, char *final, line_t *start)
   1447      0     stevel {
   1448   6448     vikram 	char		tmpfile[PATH_MAX];
   1449   6448     vikram 	char		path[PATH_MAX];
   1450   6448     vikram 	FILE		*fp;
   1451   6448     vikram 	int		ret;
   1452   6448     vikram 	struct stat	sb;
   1453   6448     vikram 	mode_t		mode;
   1454   6448     vikram 	uid_t		root_uid;
   1455   6448     vikram 	gid_t		sys_gid;
   1456   6448     vikram 	struct passwd	*pw;
   1457   6448     vikram 	struct group	*gp;
   1458   6448     vikram 	const char	*fcn = "list2file()";
   1459      0     stevel 
   1460      0     stevel 	(void) snprintf(path, sizeof (path), "%s%s", root, final);
   1461      0     stevel 
   1462      0     stevel 	if (start == NULL) {
   1463   6448     vikram 		/* Empty GRUB menu */
   1464      0     stevel 		if (stat(path, &sb) != -1) {
   1465      0     stevel 			bam_print(UNLINK_EMPTY, path);
   1466      0     stevel 			if (unlink(path) != 0) {
   1467      0     stevel 				bam_error(UNLINK_FAIL, path, strerror(errno));
   1468      0     stevel 				return (BAM_ERROR);
   1469      0     stevel 			} else {
   1470      0     stevel 				return (BAM_SUCCESS);
   1471      0     stevel 			}
   1472      0     stevel 		}
   1473   6448     vikram 		return (BAM_SUCCESS);
   1474      0     stevel 	}
   1475      0     stevel 
   1476      0     stevel 	/*
   1477      0     stevel 	 * Preserve attributes of existing file if possible,
   1478      0     stevel 	 * otherwise ask the system for uid/gid of root/sys.
   1479      0     stevel 	 * If all fails, fall back on hard-coded defaults.
   1480      0     stevel 	 */
   1481      0     stevel 	if (stat(path, &sb) != -1) {
   1482      0     stevel 		mode = sb.st_mode;
   1483      0     stevel 		root_uid = sb.st_uid;
   1484      0     stevel 		sys_gid = sb.st_gid;
   1485      0     stevel 	} else {
   1486      0     stevel 		mode = DEFAULT_DEV_MODE;
   1487      0     stevel 		if ((pw = getpwnam(DEFAULT_DEV_USER)) != NULL) {
   1488      0     stevel 			root_uid = pw->pw_uid;
   1489      0     stevel 		} else {
   1490   6448     vikram 			bam_error(CANT_FIND_USER,
   1491   6448     vikram 			    DEFAULT_DEV_USER, DEFAULT_DEV_UID);
   1492      0     stevel 			root_uid = (uid_t)DEFAULT_DEV_UID;
   1493      0     stevel 		}
   1494      0     stevel 		if ((gp = getgrnam(DEFAULT_DEV_GROUP)) != NULL) {
   1495      0     stevel 			sys_gid = gp->gr_gid;
   1496      0     stevel 		} else {
   1497   6448     vikram 			bam_error(CANT_FIND_GROUP,
   1498   6448     vikram 			    DEFAULT_DEV_GROUP, DEFAULT_DEV_GID);
   1499      0     stevel 			sys_gid = (gid_t)DEFAULT_DEV_GID;
   1500      0     stevel 		}
   1501      0     stevel 	}
   1502      0     stevel 
   1503      0     stevel 	(void) snprintf(tmpfile, sizeof (tmpfile), "%s%s", root, tmp);
   1504      0     stevel 
   1505      0     stevel 	/* Truncate tmpfile first */
   1506      0     stevel 	fp = fopen(tmpfile, "w");
   1507      0     stevel 	if (fp == NULL) {
   1508      0     stevel 		bam_error(OPEN_FAIL, tmpfile, strerror(errno));
   1509      0     stevel 		return (BAM_ERROR);
   1510      0     stevel 	}
   1511   6694     vikram 	ret = fclose(fp);
   1512   6694     vikram 	INJECT_ERROR1("LIST2FILE_TRUNC_FCLOSE", ret = EOF);
   1513   6694     vikram 	if (ret == EOF) {
   1514      0     stevel 		bam_error(CLOSE_FAIL, tmpfile, strerror(errno));
   1515      0     stevel 		return (BAM_ERROR);
   1516      0     stevel 	}
   1517      0     stevel 
   1518      0     stevel 	/* Now open it in append mode */
   1519      0     stevel 	fp = fopen(tmpfile, "a");
   1520      0     stevel 	if (fp == NULL) {
   1521      0     stevel 		bam_error(OPEN_FAIL, tmpfile, strerror(errno));
   1522      0     stevel 		return (BAM_ERROR);
   1523      0     stevel 	}
   1524      0     stevel 
   1525      0     stevel 	for (; start; start = start->next) {
   1526   6694     vikram 		ret = s_fputs(start->line, fp);
   1527   6694     vikram 		INJECT_ERROR1("LIST2FILE_FPUTS", ret = EOF);
   1528   6694     vikram 		if (ret == EOF) {
   1529      0     stevel 			bam_error(WRITE_FAIL, tmpfile, strerror(errno));
   1530      0     stevel 			(void) fclose(fp);
   1531      0     stevel 			return (BAM_ERROR);
   1532      0     stevel 		}
   1533      0     stevel 	}
   1534      0     stevel 
   1535   6694     vikram 	ret = fclose(fp);
   1536   6694     vikram 	INJECT_ERROR1("LIST2FILE_APPEND_FCLOSE", ret = EOF);
   1537   6694     vikram 	if (ret == EOF) {
   1538      0     stevel 		bam_error(CLOSE_FAIL, tmpfile, strerror(errno));
   1539      0     stevel 		return (BAM_ERROR);
   1540      0     stevel 	}
   1541      0     stevel 
   1542      0     stevel 	/*
   1543    271         jg 	 * Set up desired attributes.  Ignore failures on filesystems
   1544    271         jg 	 * not supporting these operations - pcfs reports unsupported
   1545    271         jg 	 * operations as EINVAL.
   1546      0     stevel 	 */
   1547      0     stevel 	ret = chmod(tmpfile, mode);
   1548    271         jg 	if (ret == -1 &&
   1549    271         jg 	    errno != EINVAL && errno != ENOTSUP) {
   1550      0     stevel 		bam_error(CHMOD_FAIL, tmpfile, strerror(errno));
   1551      0     stevel 		return (BAM_ERROR);
   1552      0     stevel 	}
   1553      0     stevel 
   1554      0     stevel 	ret = chown(tmpfile, root_uid, sys_gid);
   1555    271         jg 	if (ret == -1 &&
   1556    271         jg 	    errno != EINVAL && errno != ENOTSUP) {
   1557      0     stevel 		bam_error(CHOWN_FAIL, tmpfile, strerror(errno));
   1558      0     stevel 		return (BAM_ERROR);
   1559      0     stevel 	}
   1560      0     stevel 
   1561      0     stevel 	/*
   1562      0     stevel 	 * Do an atomic rename
   1563      0     stevel 	 */
   1564      0     stevel 	ret = rename(tmpfile, path);
   1565   6694     vikram 	INJECT_ERROR1("LIST2FILE_RENAME", ret = -1);
   1566      0     stevel 	if (ret != 0) {
   1567      0     stevel 		bam_error(RENAME_FAIL, path, strerror(errno));
   1568      0     stevel 		return (BAM_ERROR);
   1569      0     stevel 	}
   1570      0     stevel 
   1571   6448     vikram 	BAM_DPRINTF((D_WROTE_FILE, fcn, path));
   1572      0     stevel 	return (BAM_SUCCESS);
   1573      0     stevel }
   1574      0     stevel 
   1575      0     stevel /*
   1576   8735     Enrico  * Checks if the path specified (without the file name at the end) exists
   1577   8735     Enrico  * and creates it if not. If the path exists and is not a directory, an attempt
   1578   8735     Enrico  * to unlink is made.
   1579   8735     Enrico  */
   1580   8735     Enrico static int
   1581   8735     Enrico setup_path(char *path)
   1582   8735     Enrico {
   1583   8735     Enrico 	char 		*p;
   1584   8735     Enrico 	int		ret;
   1585   8735     Enrico 	struct stat	sb;
   1586   8735     Enrico 
   1587   8735     Enrico 	p = strrchr(path, '/');
   1588   8735     Enrico 	if (p != NULL) {
   1589   8735     Enrico 		*p = '\0';
   1590   8735     Enrico 		if (stat(path, &sb) != 0 || !(S_ISDIR(sb.st_mode))) {
   1591   8735     Enrico 			/* best effort attempt, mkdirp will catch the error */
   1592   8735     Enrico 			(void) unlink(path);
   1593   8735     Enrico 			if (bam_verbose)
   1594   8735     Enrico 				bam_print(NEED_DIRPATH, path);
   1595   8735     Enrico 			ret = mkdirp(path, DIR_PERMS);
   1596   8735     Enrico 			if (ret == -1) {
   1597   8735     Enrico 				bam_error(MKDIR_FAILED, path, strerror(errno));
   1598   8735     Enrico 				*p = '/';
   1599   8735     Enrico 				return (BAM_ERROR);
   1600   8735     Enrico 			}
   1601   8735     Enrico 		}
   1602   8735     Enrico 		*p = '/';
   1603   8735     Enrico 		return (BAM_SUCCESS);
   1604   8735     Enrico 	}
   1605   8735     Enrico 	return (BAM_SUCCESS);
   1606   8735     Enrico }
   1607   8735     Enrico 
   1608   8735     Enrico typedef union {
   1609   8735     Enrico 	gzFile	gzfile;
   1610   8735     Enrico 	int	fdfile;
   1611   8735     Enrico } outfile;
   1612   8735     Enrico 
   1613   8735     Enrico typedef struct {
   1614   8735     Enrico 	char		path[PATH_MAX];
   1615   8735     Enrico 	outfile		out;
   1616   8735     Enrico } cachefile;
   1617   8735     Enrico 
   1618   8735     Enrico static int
   1619   8735     Enrico setup_file(char *base, const char *path, cachefile *cf)
   1620   8735     Enrico {
   1621   8735     Enrico 	int	ret;
   1622   8735     Enrico 	char	*strip;
   1623   8735     Enrico 
   1624   8735     Enrico 	/* init gzfile or fdfile in case we fail before opening */
   1625   8735     Enrico 	if (bam_direct == BAM_DIRECT_DBOOT)
   1626   8735     Enrico 		cf->out.gzfile = NULL;
   1627   8735     Enrico 	else
   1628   8735     Enrico 		cf->out.fdfile = -1;
   1629   8735     Enrico 
   1630   8735     Enrico 	/* strip the trailing altroot path */
   1631   8735     Enrico 	strip = (char *)path + strlen(rootbuf);
   1632   8735     Enrico 
   1633   8735     Enrico 	ret = snprintf(cf->path, sizeof (cf->path), "%s/%s", base, strip);
   1634   8735     Enrico 	if (ret >= sizeof (cf->path)) {
   1635   8735     Enrico 		bam_error(PATH_TOO_LONG, rootbuf);
   1636   8735     Enrico 		return (BAM_ERROR);
   1637   8735     Enrico 	}
   1638   8735     Enrico 
   1639   8735     Enrico 	/* Check if path is present in the archive cache directory */
   1640   8735     Enrico 	if (setup_path(cf->path) == BAM_ERROR)
   1641   8735     Enrico 		return (BAM_ERROR);
   1642   8735     Enrico 
   1643   8735     Enrico 	if (bam_direct == BAM_DIRECT_DBOOT) {
   1644   8735     Enrico 		if ((cf->out.gzfile = gzopen(cf->path, "wb")) == NULL) {
   1645   8954     Enrico 			bam_error(OPEN_FAIL, cf->path, strerror(errno));
   1646   8735     Enrico 			return (BAM_ERROR);
   1647   8735     Enrico 		}
   1648   8735     Enrico 		(void) gzsetparams(cf->out.gzfile, Z_BEST_SPEED,
   1649   8735     Enrico 		    Z_DEFAULT_STRATEGY);
   1650   8735     Enrico 	} else {
   1651   8735     Enrico 		if ((cf->out.fdfile = open(cf->path, O_WRONLY | O_CREAT, 0644))
   1652   8735     Enrico 		    == -1) {
   1653   8735     Enrico 			bam_error(OPEN_FAIL, cf->path, strerror(errno));
   1654   8735     Enrico 			return (BAM_ERROR);
   1655   8735     Enrico 		}
   1656   8735     Enrico 	}
   1657   8735     Enrico 
   1658   8735     Enrico 	return (BAM_SUCCESS);
   1659   8735     Enrico }
   1660   8735     Enrico 
   1661   8735     Enrico static int
   1662   8735     Enrico cache_write(cachefile cf, char *buf, int size)
   1663   8735     Enrico {
   1664   8735     Enrico 	int	err;
   1665   8735     Enrico 
   1666   8735     Enrico 	if (bam_direct == BAM_DIRECT_DBOOT) {
   1667   8735     Enrico 		if (gzwrite(cf.out.gzfile, buf, size) < 1) {
   1668   8735     Enrico 			bam_error(GZ_WRITE_FAIL, gzerror(cf.out.gzfile, &err));
   1669   8954     Enrico 			if (err == Z_ERRNO && bam_verbose) {
   1670   8735     Enrico 				bam_error(WRITE_FAIL, cf.path, strerror(errno));
   1671   8954     Enrico 			}
   1672   8735     Enrico 			return (BAM_ERROR);
   1673   8735     Enrico 		}
   1674   8735     Enrico 	} else {
   1675   8735     Enrico 		if (write(cf.out.fdfile, buf, size) < 1) {
   1676   8735     Enrico 			bam_error(WRITE_FAIL, cf.path, strerror(errno));
   1677   8735     Enrico 			return (BAM_ERROR);
   1678   8735     Enrico 		}
   1679   8735     Enrico 	}
   1680   8735     Enrico 	return (BAM_SUCCESS);
   1681   8735     Enrico }
   1682   8735     Enrico 
   1683   8735     Enrico static int
   1684   8735     Enrico cache_close(cachefile cf)
   1685   8735     Enrico {
   1686   8735     Enrico 	int	ret;
   1687   8735     Enrico 
   1688   8735     Enrico 	if (bam_direct == BAM_DIRECT_DBOOT) {
   1689   8735     Enrico 		if (cf.out.gzfile) {
   1690   8735     Enrico 			ret = gzclose(cf.out.gzfile);
   1691   8954     Enrico 			if (ret != Z_OK) {
   1692   8735     Enrico 				bam_error(CLOSE_FAIL, cf.path, strerror(errno));
   1693   8954     Enrico 				return (BAM_ERROR);
   1694   8954     Enrico 			}
   1695   8735     Enrico 		}
   1696   8735     Enrico 	} else {
   1697   8735     Enrico 		if (cf.out.fdfile != -1) {
   1698   8735     Enrico 			ret = close(cf.out.fdfile);
   1699   8735     Enrico 			if (ret != 0) {
   1700   8735     Enrico 				bam_error(CLOSE_FAIL, cf.path, strerror(errno));
   1701   8735     Enrico 				return (BAM_ERROR);
   1702   8735     Enrico 			}
   1703   8735     Enrico 		}
   1704   8735     Enrico 	}
   1705   8735     Enrico 
   1706   8735     Enrico 	return (BAM_SUCCESS);
   1707   8735     Enrico }
   1708   8735     Enrico 
   1709   8735     Enrico static int
   1710   8735     Enrico dircache_updatefile(const char *path, int what)
   1711   8735     Enrico {
   1712   8735     Enrico 	int 		ret, exitcode;
   1713   8735     Enrico 	char 		buf[4096 * 4];
   1714   8735     Enrico 	FILE 		*infile;
   1715   8735     Enrico 	cachefile 	outfile, outupdt;
   1716   8735     Enrico 
   1717   8954     Enrico 	if (bam_nowrite()) {
   1718   8954     Enrico 		set_dir_flag(what, NEED_UPDATE);
   1719   8954     Enrico 		return (BAM_SUCCESS);
   1720   8954     Enrico 	}
   1721   8954     Enrico 
   1722   8954     Enrico 	if (!has_cachedir(what))
   1723   8735     Enrico 		return (BAM_SUCCESS);
   1724   8735     Enrico 
   1725   8735     Enrico 	if ((infile = fopen(path, "rb")) == NULL) {
   1726   8735     Enrico 		bam_error(OPEN_FAIL, path, strerror(errno));
   1727   8735     Enrico 		return (BAM_ERROR);
   1728   8735     Enrico 	}
   1729   8735     Enrico 
   1730   8735     Enrico 	ret = setup_file(get_cachedir(what), path, &outfile);
   1731   8735     Enrico 	if (ret == BAM_ERROR) {
   1732   8735     Enrico 		exitcode = BAM_ERROR;
   1733   8735     Enrico 		goto out;
   1734   8735     Enrico 	}
   1735   8735     Enrico 	if (!is_dir_flag_on(what, NO_MULTI)) {
   1736   8735     Enrico 		ret = setup_file(get_updatedir(what), path, &outupdt);
   1737   8735     Enrico 		if (ret == BAM_ERROR)
   1738   8735     Enrico 			set_dir_flag(what, NO_MULTI);
   1739   8735     Enrico 	}
   1740   8735     Enrico 
   1741   8735     Enrico 	while ((ret = fread(buf, 1, sizeof (buf), infile)) > 0) {
   1742   8735     Enrico 		if (cache_write(outfile, buf, ret) == BAM_ERROR) {
   1743   8735     Enrico 			exitcode = BAM_ERROR;
   1744   8735     Enrico 			goto out;
   1745   8735     Enrico 		}
   1746   8735     Enrico 		if (!is_dir_flag_on(what, NO_MULTI))
   1747   8735     Enrico 			if (cache_write(outupdt, buf, ret) == BAM_ERROR)
   1748   8735     Enrico 				set_dir_flag(what, NO_MULTI);
   1749   8735     Enrico 	}
   1750   8735     Enrico 
   1751   8735     Enrico 	set_dir_flag(what, NEED_UPDATE);
   1752   8735     Enrico 	get_count(what)++;
   1753   8954     Enrico 	if (get_count(what) > COUNT_MAX)
   1754   8954     Enrico 		set_dir_flag(what, NO_MULTI);
   1755   8735     Enrico 	exitcode = BAM_SUCCESS;
   1756   8735     Enrico out:
   1757   8735     Enrico 	(void) fclose(infile);
   1758   8735     Enrico 	if (cache_close(outfile) == BAM_ERROR)
   1759   8735     Enrico 		exitcode = BAM_ERROR;
   1760   8735     Enrico 	if (!is_dir_flag_on(what, NO_MULTI) &&
   1761   8735     Enrico 	    cache_close(outupdt) == BAM_ERROR)
   1762   8735     Enrico 		exitcode = BAM_ERROR;
   1763   8735     Enrico 	if (exitcode == BAM_ERROR)
   1764   8735     Enrico 		set_flag(UPDATE_ERROR);
   1765   8735     Enrico 	return (exitcode);
   1766   8735     Enrico }
   1767   8735     Enrico 
   1768   8735     Enrico static int
   1769   8735     Enrico dircache_updatedir(const char *path, int what, int updt)
   1770   8735     Enrico {
   1771   8735     Enrico 	int		ret;
   1772   8735     Enrico 	char		dpath[PATH_MAX];
   1773   8735     Enrico 	char		*strip;
   1774   8735     Enrico 	struct stat	sb;
   1775   8735     Enrico 
   1776   8735     Enrico 	strip = (char *)path + strlen(rootbuf);
   1777   8735     Enrico 
   1778   8735     Enrico 	ret = snprintf(dpath, sizeof (dpath), "%s/%s", updt ?
   1779   8735     Enrico 	    get_updatedir(what) : get_cachedir(what), strip);
   1780   8735     Enrico 
   1781   8735     Enrico 	if (ret >= sizeof (dpath)) {
   1782   8735     Enrico 		bam_error(PATH_TOO_LONG, rootbuf);
   1783   8735     Enrico 		set_flag(UPDATE_ERROR);
   1784   8735     Enrico 		return (BAM_ERROR);
   1785   8735     Enrico 	}
   1786   8735     Enrico 
   1787   8735     Enrico 	if (stat(dpath, &sb) == 0 && S_ISDIR(sb.st_mode))
   1788   8735     Enrico 		return (BAM_SUCCESS);
   1789   8735     Enrico 
   1790   8735     Enrico 	if (updt) {
   1791   8735     Enrico 		if (!is_dir_flag_on(what, NO_MULTI))
   1792   8735     Enrico 			if (!bam_nowrite() && mkdirp(dpath, DIR_PERMS) == -1)
   1793   8735     Enrico 				set_dir_flag(what, NO_MULTI);
   1794   8735     Enrico 	} else {
   1795   8735     Enrico 		if (!bam_nowrite() && mkdirp(dpath, DIR_PERMS) == -1) {
   1796   8735     Enrico 			set_flag(UPDATE_ERROR);
   1797   8735     Enrico 			return (BAM_ERROR);
   1798   8735     Enrico 		}
   1799   8735     Enrico 	}
   1800   8735     Enrico 
   1801   8735     Enrico 	set_dir_flag(what, NEED_UPDATE);
   1802   8735     Enrico 	return (BAM_SUCCESS);
   1803   8735     Enrico }
   1804   8735     Enrico 
   1805   8735     Enrico #define	DO_CACHE_DIR	0
   1806   8735     Enrico #define	DO_UPDATE_DIR	1
   1807   8735     Enrico 
   1808   8735     Enrico #if defined(_LP64) || defined(_LONGLONG_TYPE)
   1809   8735     Enrico typedef		Elf64_Ehdr	_elfhdr;
   1810   8735     Enrico #else
   1811   8735     Enrico typedef		Elf32_Ehdr	_elfhdr;
   1812   8735     Enrico #endif
   1813   8735     Enrico 
   1814   8735     Enrico /*
   1815   8735     Enrico  * This routine updates the contents of the cache directory
   1816   8735     Enrico  */
   1817   8735     Enrico static int
   1818   8735     Enrico update_dircache(const char *path, int flags)
   1819   8735     Enrico {
   1820   8735     Enrico 	int rc = BAM_SUCCESS;
   1821   8735     Enrico 
   1822   8735     Enrico 	switch (flags) {
   1823   8735     Enrico 	case FTW_F:
   1824   8735     Enrico 		{
   1825   8735     Enrico 		int	fd;
   1826   8735     Enrico 		_elfhdr	elf;
   1827   8735     Enrico 
   1828   8735     Enrico 		if ((fd = open(path, O_RDONLY)) < 0) {
   1829   8735     Enrico 			bam_error(OPEN_FAIL, path, strerror(errno));
   1830   8735     Enrico 			set_flag(UPDATE_ERROR);
   1831   8735     Enrico 			rc = BAM_ERROR;
   1832   8735     Enrico 			break;
   1833   8735     Enrico 		}
   1834   8735     Enrico 
   1835   8735     Enrico 		/*
   1836   8735     Enrico 		 * libelf and gelf would be a cleaner and easier way to handle
   1837   8735     Enrico 		 * this, but libelf fails compilation if _ILP32 is defined &&
   1838   8735     Enrico 		 * _FILE_OFFSET_BITS is != 32 ...
   1839   8735     Enrico 		 */
   1840   8735     Enrico 		if (read(fd, (void *)&elf, sizeof (_elfhdr)) < 0) {
   1841   8735     Enrico 			bam_error(READ_FAIL, path, strerror(errno));
   1842   8735     Enrico 			set_flag(UPDATE_ERROR);
   1843   8735     Enrico 			(void) close(fd);
   1844   8735     Enrico 			rc = BAM_ERROR;
   1845   8735     Enrico 			break;
   1846   8735     Enrico 		}
   1847   8735     Enrico 		(void) close(fd);
   1848   8735     Enrico 
   1849   8735     Enrico 		/*
   1850   8735     Enrico 		 * If the file is not an executable and is not inside an amd64
   1851   8735     Enrico 		 * directory, we copy it in both the cache directories,
   1852   8735     Enrico 		 * otherwise, we only copy it inside the 64-bit one.
   1853   8735     Enrico 		 */
   1854   8735     Enrico 		if (memcmp(elf.e_ident, ELFMAG, 4) != 0) {
   1855   8735     Enrico 			if (strstr(path, "/amd64")) {
   1856   8954     Enrico 				rc = dircache_updatefile(path, FILE64);
   1857   8954     Enrico 			} else {
   1858   8735     Enrico 				rc = dircache_updatefile(path, FILE32);
   1859   8735     Enrico 				if (rc == BAM_SUCCESS)
   1860   8735     Enrico 					rc = dircache_updatefile(path, FILE64);
   1861   8735     Enrico 			}
   1862   8735     Enrico 		} else {
   1863   8735     Enrico 			/*
   1864   8735     Enrico 			 * Based on the ELF class we copy the file in the 32-bit
   1865   8735     Enrico 			 * or the 64-bit cache directory.
   1866   8735     Enrico 			 */
   1867   8954     Enrico 			if (elf.e_ident[EI_CLASS] == ELFCLASS32) {
   1868   8735     Enrico 				rc = dircache_updatefile(path, FILE32);
   1869   8954     Enrico 			} else if (elf.e_ident[EI_CLASS] == ELFCLASS64) {
   1870   8954     Enrico 				rc = dircache_updatefile(path, FILE64);
   1871   8954     Enrico 			} else {
   1872   8735     Enrico 				bam_print(NO3264ELF, path);
   1873   8735     Enrico 				/* paranoid */
   1874   8735     Enrico 				rc  = dircache_updatefile(path, FILE32);
   1875   8735     Enrico 				if (rc == BAM_SUCCESS)
   1876   8735     Enrico 					rc = dircache_updatefile(path, FILE64);
   1877   8735     Enrico 			}
   1878   8735     Enrico 		}
   1879   8735     Enrico 		break;
   1880   8735     Enrico 		}
   1881   8735     Enrico 	case FTW_D:
   1882   8735     Enrico 		if (strstr(path, "/amd64") == NULL) {
   1883   8735     Enrico 			rc = dircache_updatedir(path, FILE32, DO_UPDATE_DIR);
   1884   8735     Enrico 			if (rc == BAM_SUCCESS)
   1885   8735     Enrico 				rc = dircache_updatedir(path, FILE32,
   1886   8735     Enrico 				    DO_CACHE_DIR);
   1887   8735     Enrico 		} else {
   1888   8735     Enrico 			if (has_cachedir(FILE64)) {
   1889   8735     Enrico 				rc = dircache_updatedir(path, FILE64,
   1890   8735     Enrico 				    DO_UPDATE_DIR);
   1891   8735     Enrico 				if (rc == BAM_SUCCESS)
   1892   8735     Enrico 					rc = dircache_updatedir(path, FILE64,
   1893   8735     Enrico 					    DO_CACHE_DIR);
   1894   8735     Enrico 			}
   1895   8735     Enrico 		}
   1896   8735     Enrico 		break;
   1897   8735     Enrico 	default:
   1898   8735     Enrico 		rc = BAM_ERROR;
   1899   8735     Enrico 		break;
   1900   8735     Enrico 	}
   1901   8735     Enrico 
   1902   8735     Enrico 	return (rc);
   1903   8735     Enrico }
   1904   8735     Enrico 
   1905      0     stevel /*ARGSUSED*/
   1906      0     stevel static int
   1907      0     stevel cmpstat(
   1908      0     stevel 	const char *file,
   1909   8735     Enrico 	const struct stat *st,
   1910      0     stevel 	int flags,
   1911      0     stevel 	struct FTW *ftw)
   1912      0     stevel {
   1913   8735     Enrico 	uint_t 		sz;
   1914   8735     Enrico 	uint64_t 	*value;
   1915   8735     Enrico 	uint64_t 	filestat[2];
   1916   9500  Gangadhar 	int 		error, ret, status;
   1917      0     stevel 
   1918   2334      setje 	struct safefile *safefilep;
   1919   8735     Enrico 	FILE 		*fp;
   1920   8735     Enrico 	struct stat	sb;
   1921   9500  Gangadhar 	regex_t re;
   1922   8735     Enrico 
   1923   8735     Enrico 	/*
   1924   8735     Enrico 	 * On SPARC we create/update links too.
   1925   8735     Enrico 	 */
   1926   8735     Enrico 	if (flags != FTW_F && flags != FTW_D && (flags == FTW_SL &&
   1927   8735     Enrico 	    !is_flag_on(IS_SPARC_TARGET)))
   1928   8735     Enrico 		return (0);
   1929   8735     Enrico 
   1930   8735     Enrico 	/*
   1931   8735     Enrico 	 * Ignore broken links
   1932   8735     Enrico 	 */
   1933   8735     Enrico 	if (flags == FTW_SL && stat(file, &sb) < 0)
   1934      0     stevel 		return (0);
   1935      0     stevel 
   1936      0     stevel 	/*
   1937      0     stevel 	 * new_nvlp may be NULL if there were errors earlier
   1938      0     stevel 	 * but this is not fatal to update determination.
   1939      0     stevel 	 */
   1940      0     stevel 	if (walk_arg.new_nvlp) {
   1941   8735     Enrico 		filestat[0] = st->st_size;
   1942   8735     Enrico 		filestat[1] = st->st_mtime;
   1943      0     stevel 		error = nvlist_add_uint64_array(walk_arg.new_nvlp,
   1944      0     stevel 		    file + bam_rootlen, filestat, 2);
   1945      0     stevel 		if (error)
   1946      0     stevel 			bam_error(NVADD_FAIL, file, strerror(error));
   1947      0     stevel 	}
   1948      0     stevel 
   1949      0     stevel 	/*
   1950   6319         jg 	 * If we are invoked as part of system/filesystem/boot-archive, then
   1951   2334      setje 	 * there are a number of things we should not worry about
   1952      0     stevel 	 */
   1953   2334      setje 	if (bam_smf_check) {
   1954   2334      setje 		/* ignore amd64 modules unless we are booted amd64. */
   1955   2334      setje 		if (!is_amd64() && strstr(file, "/amd64/") != 0)
   1956   2334      setje 			return (0);
   1957   2334      setje 
   1958   2334      setje 		/* read in list of safe files */
   1959   2334      setje 		if (safefiles == NULL)
   1960   2334      setje 			if (fp = fopen("/boot/solaris/filelist.safe", "r")) {
   1961   2334      setje 				safefiles = s_calloc(1,
   1962   2334      setje 				    sizeof (struct safefile));
   1963   2334      setje 				safefilep = safefiles;
   1964   2334      setje 				safefilep->name = s_calloc(1, MAXPATHLEN +
   1965   2334      setje 				    MAXNAMELEN);
   1966   2334      setje 				safefilep->next = NULL;
   1967   2334      setje 				while (s_fgets(safefilep->name, MAXPATHLEN +
   1968   2334      setje 				    MAXNAMELEN, fp) != NULL) {
   1969   2334      setje 					safefilep->next = s_calloc(1,
   1970   2334      setje 					    sizeof (struct safefile));
   1971   2334      setje 					safefilep = safefilep->next;
   1972   2334      setje 					safefilep->name = s_calloc(1,
   1973   2334      setje 					    MAXPATHLEN + MAXNAMELEN);
   1974   2334      setje 					safefilep->next = NULL;
   1975   2334      setje 				}
   1976   2334      setje 				(void) fclose(fp);
   1977   2334      setje 			}
   1978   2334      setje 	}
   1979      0     stevel 
   1980      0     stevel 	/*
   1981   8735     Enrico 	 * On SPARC we create a -path-list file for mkisofs
   1982   8735     Enrico 	 */
   1983   8735     Enrico 	if (is_flag_on(IS_SPARC_TARGET) && !bam_nowrite()) {
   1984   8735     Enrico 		if (flags != FTW_D) {
   1985   8735     Enrico 			char	*strip;
   1986   8735     Enrico 
   1987   8735     Enrico 			strip = (char *)file + strlen(rootbuf);
   1988   8735     Enrico 			(void) fprintf(walk_arg.sparcfile, "/%s=%s\n", strip,
   1989   8735     Enrico 			    file);
   1990   8735     Enrico 		}
   1991   8735     Enrico 	}
   1992   8735     Enrico 
   1993   8735     Enrico 	/*
   1994   8735     Enrico 	 * We are transitioning from the old model to the dircache or the cache
   1995   8735     Enrico 	 * directory was removed: create the entry without further checkings.
   1996   8735     Enrico 	 */
   1997   8735     Enrico 	if (is_flag_on(NEED_CACHE_DIR)) {
   1998   8735     Enrico 		if (bam_verbose)
   1999   8735     Enrico 			bam_print(PARSEABLE_NEW_FILE, file);
   2000   8735     Enrico 
   2001   8735     Enrico 		if (is_flag_on(IS_SPARC_TARGET)) {
   2002   8735     Enrico 			set_dir_flag(FILE64, NEED_UPDATE);
   2003   8735     Enrico 			return (0);
   2004   8735     Enrico 		}
   2005   8735     Enrico 
   2006   8735     Enrico 		ret = update_dircache(file, flags);
   2007   8735     Enrico 		if (ret == BAM_ERROR) {
   2008   8735     Enrico 			bam_error(UPDT_CACHE_FAIL, file);
   2009   8735     Enrico 			return (-1);
   2010   8735     Enrico 		}
   2011   8735     Enrico 
   2012   8735     Enrico 		return (0);
   2013   8735     Enrico 	}
   2014   8735     Enrico 
   2015   8735     Enrico 	/*
   2016      0     stevel 	 * We need an update if file doesn't exist in old archive
   2017      0     stevel 	 */
   2018      0     stevel 	if (walk_arg.old_nvlp == NULL ||
   2019      0     stevel 	    nvlist_lookup_uint64_array(walk_arg.old_nvlp,
   2020      0     stevel 	    file + bam_rootlen, &value, &sz) != 0) {
   2021      0     stevel 		if (bam_smf_check)	/* ignore new during smf check */
   2022      0     stevel 			return (0);
   2023   8735     Enrico 
   2024   8735     Enrico 		if (is_flag_on(IS_SPARC_TARGET)) {
   2025   8735     Enrico 			set_dir_flag(FILE64, NEED_UPDATE);
   2026   8735     Enrico 		} else {
   2027   8735     Enrico 			ret = update_dircache(file, flags);
   2028   8735     Enrico 			if (ret == BAM_ERROR) {
   2029   8735     Enrico 				bam_error(UPDT_CACHE_FAIL, file);
   2030   8735     Enrico 				return (-1);
   2031   8735     Enrico 			}
   2032   8735     Enrico 		}
   2033   8735     Enrico 
   2034      0     stevel 		if (bam_verbose)
   2035      0     stevel 			bam_print(PARSEABLE_NEW_FILE, file);
   2036      0     stevel 		return (0);
   2037      0     stevel 	}
   2038   8735     Enrico 
   2039   8735     Enrico 	/*
   2040   8735     Enrico 	 * If we got there, the file is already listed as to be included in the
   2041   8735     Enrico 	 * iso image. We just need to know if we are going to rebuild it or not
   2042   8735     Enrico 	 */
   2043   8735     Enrico 	if (is_flag_on(IS_SPARC_TARGET) &&
   2044   8954     Enrico 	    is_dir_flag_on(FILE64, NEED_UPDATE) && !bam_nowrite())
   2045   8954     Enrico 		return (0);
   2046      0     stevel 	/*
   2047      0     stevel 	 * File exists in old archive. Check if file has changed
   2048      0     stevel 	 */
   2049      0     stevel 	assert(sz == 2);
   2050      0     stevel 	bcopy(value, filestat, sizeof (filestat));
   2051      0     stevel 
   2052   8735     Enrico 	if (flags != FTW_D && (filestat[0] != st->st_size ||
   2053   8735     Enrico 	    filestat[1] != st->st_mtime)) {
   2054   3615      setje 		if (bam_smf_check) {
   2055   3615      setje 			safefilep = safefiles;
   2056   9500  Gangadhar 			while (safefilep != NULL &&
   2057   9500  Gangadhar 			    safefilep->name[0] != '\0') {
   2058   9500  Gangadhar 				if (regcomp(&re, safefilep->name,
   2059   9500  Gangadhar 				    REG_EXTENDED|REG_NOSUB) == 0) {
   2060   9500  Gangadhar 					status = regexec(&re,
   2061   9500  Gangadhar 					    file + bam_rootlen, 0, NULL, 0);
   2062   9500  Gangadhar 					regfree(&re);
   2063   9500  Gangadhar 					if (status == 0) {
   2064   9500  Gangadhar 						(void) creat(NEED_UPDATE_FILE,
   2065   9500  Gangadhar 						    0644);
   2066   9500  Gangadhar 						return (0);
   2067   9500  Gangadhar 					}
   2068   3615      setje 				}
   2069   3615      setje 				safefilep = safefilep->next;
   2070   3615      setje 			}
   2071   3615      setje 		}
   2072   8735     Enrico 
   2073   8735     Enrico 		if (is_flag_on(IS_SPARC_TARGET)) {
   2074   8735     Enrico 			set_dir_flag(FILE64, NEED_UPDATE);
   2075   8735     Enrico 		} else {
   2076   8735     Enrico 			ret = update_dircache(file, flags);
   2077   8735     Enrico 			if (ret == BAM_ERROR) {
   2078   8735     Enrico 				bam_error(UPDT_CACHE_FAIL, file);
   2079   8735     Enrico 				return (-1);
   2080   8735     Enrico 			}
   2081   8735     Enrico 		}
   2082   8735     Enrico 
   2083      0     stevel 		if (bam_verbose)
   2084      0     stevel 			if (bam_smf_check)
   2085      0     stevel 				bam_print("    %s\n", file);
   2086      0     stevel 			else
   2087      0     stevel 				bam_print(PARSEABLE_OUT_DATE, file);
   2088      0     stevel 	}
   2089      0     stevel 
   2090      0     stevel 	return (0);
   2091      0     stevel }
   2092      0     stevel 
   2093      0     stevel /*
   2094   8735     Enrico  * Remove a directory path recursively
   2095   8735     Enrico  */
   2096   8735     Enrico static int
   2097   8735     Enrico rmdir_r(char *path)
   2098   8735     Enrico {
   2099   8735     Enrico 	struct dirent 	*d = NULL;
   2100   8735     Enrico 	DIR 		*dir = NULL;
   2101   8735     Enrico 	char 		tpath[PATH_MAX];
   2102   8735     Enrico 	struct stat 	sb;
   2103   8735     Enrico 
   2104   8735     Enrico 	if ((dir = opendir(path)) == NULL)
   2105   8735     Enrico 		return (-1);
   2106   8735     Enrico 
   2107   8735     Enrico 	while (d = readdir(dir)) {
   2108   8735     Enrico 		if ((strcmp(d->d_name, ".") != 0) &&
   2109   8735     Enrico 		    (strcmp(d->d_name, "..") != 0)) {
   2110   8735     Enrico 			(void) snprintf(tpath, sizeof (tpath), "%s/%s",
   2111   8735     Enrico 			    path, d->d_name);
   2112   8735     Enrico 			if (stat(tpath, &sb) == 0) {
   2113   8735     Enrico 				if (sb.st_mode & S_IFDIR)
   2114   8735     Enrico 					(void) rmdir_r(tpath);
   2115   8735     Enrico 				else
   2116   8735     Enrico 					(void) remove(tpath);
   2117   8735     Enrico 			}
   2118   8735     Enrico 		}
   2119   8735     Enrico 	}
   2120   8735     Enrico 	return (remove(path));
   2121   8735     Enrico }
   2122   8735     Enrico 
   2123   8735     Enrico /*
   2124   8735     Enrico  * Check if cache directory exists and, if not, create it and update flags
   2125   8735     Enrico  * accordingly. If the path exists, but it's not a directory, a best effort
   2126   8735     Enrico  * attempt to remove and recreate it is made.
   2127   8735     Enrico  * If the user requested a 'purge', always recreate the directory from scratch.
   2128   8735     Enrico  */
   2129   8735     Enrico static int
   2130   8735     Enrico set_cache_dir(char *root, int what)
   2131   8735     Enrico {
   2132   8735     Enrico 	struct stat	sb;
   2133   8735     Enrico 	int		ret = 0;
   2134   8735     Enrico 
   2135   8735     Enrico 	ret = snprintf(get_cachedir(what), sizeof (get_cachedir(what)),
   2136   8735     Enrico 	    "%s%s%s%s%s", root, ARCHIVE_PREFIX, get_machine(), what == FILE64 ?
   2137   8735     Enrico 	    "/amd64" : "", CACHEDIR_SUFFIX);
   2138   8735     Enrico 
   2139   8735     Enrico 	if (ret >= sizeof (get_cachedir(what))) {
   2140   8735     Enrico 		bam_error(PATH_TOO_LONG, rootbuf);
   2141   8735     Enrico 		return (BAM_ERROR);
   2142   8735     Enrico 	}
   2143   8735     Enrico 
   2144   9233     Enrico 	if (bam_purge || is_flag_on(INVALIDATE_CACHE))
   2145   8735     Enrico 		(void) rmdir_r(get_cachedir(what));
   2146   8735     Enrico 
   2147   8735     Enrico 	if (stat(get_cachedir(what), &sb) != 0 || !(S_ISDIR(sb.st_mode))) {
   2148   8735     Enrico 		/* best effort unlink attempt, mkdir will catch errors */
   2149   8735     Enrico 		(void) unlink(get_cachedir(what));
   2150   8735     Enrico 
   2151   8735     Enrico 		if (bam_verbose)
   2152   8735     Enrico 			bam_print(UPDATE_CDIR_MISS, get_cachedir(what));
   2153   8735     Enrico 		ret = mkdir(get_cachedir(what), DIR_PERMS);
   2154   8735     Enrico 		if (ret < 0) {
   2155   8735     Enrico 			bam_error(MKDIR_FAILED, get_cachedir(what),
   2156   8735     Enrico 			    strerror(errno));
   2157   8735     Enrico 			get_cachedir(what)[0] = '\0';
   2158   8735     Enrico 			return (ret);
   2159   8735     Enrico 		}
   2160   8735     Enrico 		set_flag(NEED_CACHE_DIR);
   2161   8735     Enrico 		set_dir_flag(what, NO_MULTI);
   2162   8735     Enrico 	}
   2163   8735     Enrico 
   2164   8735     Enrico 	return (BAM_SUCCESS);
   2165   8735     Enrico }
   2166   8735     Enrico 
   2167   8735     Enrico static int
   2168   8735     Enrico set_update_dir(char *root, int what)
   2169   8735     Enrico {
   2170   8735     Enrico 	struct stat	sb;
   2171   8735     Enrico 	int		ret;
   2172   8735     Enrico 
   2173   8735     Enrico 	if (is_dir_flag_on(what, NO_MULTI))
   2174   8735     Enrico 		return (BAM_SUCCESS);
   2175   8735     Enrico 
   2176   8735     Enrico 	if (!bam_extend) {
   2177   8735     Enrico 		set_dir_flag(what, NO_MULTI);
   2178   8735     Enrico 		return (BAM_SUCCESS);
   2179   8735     Enrico 	}
   2180   8735     Enrico 
   2181   8735     Enrico 	if (what == FILE64 && !is_flag_on(IS_SPARC_TARGET))
   2182   8735     Enrico 		ret = snprintf(get_updatedir(what),
   2183   8735     Enrico 		    sizeof (get_updatedir(what)), "%s%s%s/amd64%s", root,
   2184   8735     Enrico 		    ARCHIVE_PREFIX, get_machine(), UPDATEDIR_SUFFIX);
   2185   8735     Enrico 	else
   2186   8735     Enrico 		ret = snprintf(get_updatedir(what),
   2187   8735     Enrico 		    sizeof (get_updatedir(what)), "%s%s%s%s", root,
   2188   8735     Enrico 		    ARCHIVE_PREFIX, get_machine(), UPDATEDIR_SUFFIX);
   2189   8735     Enrico 
   2190   8735     Enrico 	if (ret >= sizeof (get_updatedir(what))) {
   2191   8735     Enrico 		bam_error(PATH_TOO_LONG, rootbuf);
   2192   8735     Enrico 		return (BAM_ERROR);
   2193   8735     Enrico 	}
   2194   8735     Enrico 
   2195   8735     Enrico 	if (stat(get_updatedir(what), &sb) == 0) {
   2196   8735     Enrico 		if (S_ISDIR(sb.st_mode))
   2197   8735     Enrico 			ret = rmdir_r(get_updatedir(what));
   2198   8735     Enrico 		else
   2199   8735     Enrico 			ret = unlink(get_updatedir(what));
   2200   8735     Enrico 
   2201   8735     Enrico 		if (ret != 0)
   2202   8735     Enrico 			set_dir_flag(what, NO_MULTI);
   2203   8735     Enrico 	}
   2204   8735     Enrico 
   2205   8735     Enrico 	if (mkdir(get_updatedir(what), DIR_PERMS) < 0)
   2206   8735     Enrico 		set_dir_flag(what, NO_MULTI);
   2207   8735     Enrico 
   2208   8735     Enrico 	return (BAM_SUCCESS);
   2209   8735     Enrico }
   2210   8735     Enrico 
   2211   8735     Enrico static int
   2212   8735     Enrico is_valid_archive(char *root, int what)
   2213   8735     Enrico {
   2214   8735     Enrico 	char 		archive_path[PATH_MAX];
   2215   9233     Enrico 	char		timestamp_path[PATH_MAX];
   2216   9233     Enrico 	struct stat 	sb, timestamp;
   2217   8735     Enrico 	int 		ret;
   2218   8735     Enrico 
   2219   8735     Enrico 	if (what == FILE64 && !is_flag_on(IS_SPARC_TARGET))
   2220   8735     Enrico 		ret = snprintf(archive_path, sizeof (archive_path),
   2221   8735     Enrico 		    "%s%s%s/amd64%s", root, ARCHIVE_PREFIX, get_machine(),
   2222   8735     Enrico 		    ARCHIVE_SUFFIX);
   2223   8735     Enrico 	else
   2224   8735     Enrico 		ret = snprintf(archive_path, sizeof (archive_path), "%s%s%s%s",
   2225   8735     Enrico 		    root, ARCHIVE_PREFIX, get_machine(), ARCHIVE_SUFFIX);
   2226   8735     Enrico 
   2227   8735     Enrico 	if (ret >= sizeof (archive_path)) {
   2228   8735     Enrico 		bam_error(PATH_TOO_LONG, rootbuf);
   2229   8735     Enrico 		return (BAM_ERROR);
   2230   8735     Enrico 	}
   2231   8735     Enrico 
   2232   8735     Enrico 	if (stat(archive_path, &sb) != 0) {
   2233   8735     Enrico 		if (bam_verbose && !bam_check)
   2234   8735     Enrico 			bam_print(UPDATE_ARCH_MISS, archive_path);
   2235   9233     Enrico 		set_dir_flag(what, NEED_UPDATE);
   2236   9233     Enrico 		set_dir_flag(what, NO_MULTI);
   2237   9233     Enrico 		return (BAM_SUCCESS);
   2238   9233     Enrico 	}
   2239   9233     Enrico 
   2240   9233     Enrico 	/*
   2241   9233     Enrico 	 * The timestamp file is used to prevent stale files in the archive
   2242   9233     Enrico 	 * cache.
   2243   9233     Enrico 	 * Stale files can happen if the system is booted back and forth across
   2244   9233     Enrico 	 * the transition from bootadm-before-the-cache to
   2245   9233     Enrico 	 * bootadm-after-the-cache, since older versions of bootadm don't know
   2246   9233     Enrico 	 * about the existence of the archive cache.
   2247   9233     Enrico 	 *
   2248   9233     Enrico 	 * Since only bootadm-after-the-cache versions know about about this
   2249   9233     Enrico 	 * file, we require that the boot archive be older than this file.
   2250   9233     Enrico 	 */
   2251   9233     Enrico 	ret = snprintf(timestamp_path, sizeof (timestamp_path), "%s%s", root,
   2252   9233     Enrico 	    FILE_STAT_TIMESTAMP);
   2253   9233     Enrico 
   2254   9233     Enrico 	if (ret >= sizeof (timestamp_path)) {
   2255   9233     Enrico 		bam_error(PATH_TOO_LONG, rootbuf);
   2256   9233     Enrico 		return (BAM_ERROR);
   2257   9233     Enrico 	}
   2258   9233     Enrico 
   2259   9233     Enrico 	if (stat(timestamp_path, &timestamp) != 0 ||
   2260   9233     Enrico 	    sb.st_mtime > timestamp.st_mtime) {
   2261   9233     Enrico 		if (bam_verbose && !bam_check)
   2262   9233     Enrico 			bam_print(UPDATE_CACHE_OLD, timestamp);
   2263   9233     Enrico 		/*
   2264   9233     Enrico 		 * Don't generate a false positive for the boot-archive service
   2265   9233     Enrico 		 * but trigger an update of the archive cache in
   2266   9233     Enrico 		 * boot-archive-update.
   2267   9233     Enrico 		 */
   2268   9233     Enrico 		if (bam_smf_check) {
   2269   9233     Enrico 			(void) creat(NEED_UPDATE_FILE, 0644);
   2270   9233     Enrico 			return (BAM_SUCCESS);
   2271   9233     Enrico 		}
   2272   9233     Enrico 
   2273   9233     Enrico 		set_flag(INVALIDATE_CACHE);
   2274   8735     Enrico 		set_dir_flag(what, NEED_UPDATE);
   2275   8735     Enrico 		set_dir_flag(what, NO_MULTI);
   2276   8735     Enrico 		return (BAM_SUCCESS);
   2277   8735     Enrico 	}
   2278   8735     Enrico 
   2279   8735     Enrico 	if (is_flag_on(IS_SPARC_TARGET))
   2280   8735     Enrico 		return (BAM_SUCCESS);
   2281   8735     Enrico 
   2282   8735     Enrico 	if (bam_extend && sb.st_size > BA_SIZE_MAX) {
   2283   8735     Enrico 		if (bam_verbose && !bam_check)
   2284   8735     Enrico 			bam_print(MULTI_SIZE, archive_path, BA_SIZE_MAX);
   2285   8735     Enrico 		set_dir_flag(what, NO_MULTI);
   2286   8735     Enrico 	}
   2287   8735     Enrico 
   2288   8735     Enrico 	return (BAM_SUCCESS);
   2289   8735     Enrico }
   2290   8735     Enrico 
   2291   8735     Enrico /*
   2292   8735     Enrico  * Check flags and presence of required files and directories.
   2293      0     stevel  * The force flag and/or absence of files should
   2294      0     stevel  * trigger an update.
   2295      0     stevel  * Suppress stdout output if check (-n) option is set
   2296      0     stevel  * (as -n should only produce parseable output.)
   2297      0     stevel  */
   2298   8735     Enrico static int
   2299      0     stevel check_flags_and_files(char *root)
   2300      0     stevel {
   2301   8735     Enrico 
   2302   8735     Enrico 	struct stat 	sb;
   2303   8735     Enrico 	int 		ret;
   2304   8735     Enrico 
   2305   8735     Enrico 	/*
   2306   8735     Enrico 	 * If archive is missing, create archive
   2307   8735     Enrico 	 */
   2308   8735     Enrico 	if (is_flag_on(IS_SPARC_TARGET)) {
   2309   8735     Enrico 		ret = is_valid_archive(root, FILE64);
   2310   8954     Enrico 		if (ret == BAM_ERROR)
   2311   8954     Enrico 			return (BAM_ERROR);
   2312   8735     Enrico 	} else {
   2313   8735     Enrico 		int	what = FILE32;
   2314   8735     Enrico 		do {
   2315   8735     Enrico 			ret = is_valid_archive(root, what);
   2316   8735     Enrico 			if (ret == BAM_ERROR)
   2317   8735     Enrico 				return (BAM_ERROR);
   2318   8735     Enrico 			what++;
   2319   8735     Enrico 		} while (bam_direct == BAM_DIRECT_DBOOT && what < CACHEDIR_NUM);
   2320   8735     Enrico 	}
   2321   8735     Enrico 
   2322   8735     Enrico 	if (bam_nowrite())
   2323   8735     Enrico 		return (BAM_SUCCESS);
   2324   8735     Enrico 
   2325   8735     Enrico 
   2326   8735     Enrico 	/*
   2327   8735     Enrico 	 * check if cache directories exist on x86.
   2328   8735     Enrico 	 * check (and always open) the cache file on SPARC.
   2329   8735     Enrico 	 */
   2330   8735     Enrico 	if (is_sparc()) {
   2331   8735     Enrico 		ret = snprintf(get_cachedir(FILE64),
   2332   8735     Enrico 		    sizeof (get_cachedir(FILE64)), "%s%s%s/%s", root,
   2333   8735     Enrico 		    ARCHIVE_PREFIX, get_machine(), CACHEDIR_SUFFIX);
   2334   8735     Enrico 
   2335   8735     Enrico 		if (ret >= sizeof (get_cachedir(FILE64))) {
   2336   8735     Enrico 			bam_error(PATH_TOO_LONG, rootbuf);
   2337   8735     Enrico 			return (BAM_ERROR);
   2338   8735     Enrico 		}
   2339   8735     Enrico 
   2340   8735     Enrico 		if (stat(get_cachedir(FILE64), &sb) != 0) {
   2341   8735     Enrico 			set_flag(NEED_CACHE_DIR);
   2342   8735     Enrico 			set_dir_flag(FILE64, NEED_UPDATE);
   2343   8735     Enrico 		}
   2344   8735     Enrico 
   2345   8735     Enrico 		walk_arg.sparcfile = fopen(get_cachedir(FILE64), "w");
   2346   8735     Enrico 		if (walk_arg.sparcfile == NULL) {
   2347   8735     Enrico 			bam_error(OPEN_FAIL, get_cachedir(FILE64),
   2348   8735     Enrico 			    strerror(errno));
   2349   8735     Enrico 			return (BAM_ERROR);
   2350   8735     Enrico 		}
   2351   8735     Enrico 
   2352   8735     Enrico 		set_dir_present(FILE64);
   2353   8735     Enrico 	} else {
   2354   8735     Enrico 		int	what = FILE32;
   2355   8735     Enrico 
   2356   8735     Enrico 		do {
   2357   8735     Enrico 			if (set_cache_dir(root, what) != 0)
   2358   8735     Enrico 				return (BAM_ERROR);
   2359   8735     Enrico 
   2360   8735     Enrico 			set_dir_present(what);
   2361   8735     Enrico 
   2362   8735     Enrico 			if (set_update_dir(root, what) != 0)
   2363   8735     Enrico 				return (BAM_ERROR);
   2364   8735     Enrico 			what++;
   2365   8735     Enrico 		} while (bam_direct == BAM_DIRECT_DBOOT && what < CACHEDIR_NUM);
   2366   8735     Enrico 	}
   2367      0     stevel 
   2368      0     stevel 	/*
   2369      0     stevel 	 * if force, create archive unconditionally
   2370      0     stevel 	 */
   2371      0     stevel 	if (bam_force) {
   2372   8735     Enrico 		if (!is_sparc())
   2373   8735     Enrico 			set_dir_flag(FILE32, NEED_UPDATE);
   2374   8735     Enrico 		set_dir_flag(FILE64, NEED_UPDATE);
   2375   8735     Enrico 		if (bam_verbose)
   2376      0     stevel 			bam_print(UPDATE_FORCE);
   2377   8735     Enrico 		return (BAM_SUCCESS);
   2378   8735     Enrico 	}
   2379   8735     Enrico 
   2380   8735     Enrico 	return (BAM_SUCCESS);
   2381      0     stevel }
   2382      0     stevel 
   2383      0     stevel static error_t
   2384      0     stevel read_one_list(char *root, filelist_t  *flistp, char *filelist)
   2385      0     stevel {
   2386   8735     Enrico 	char 		path[PATH_MAX];
   2387   8735     Enrico 	FILE 		*fp;
   2388   8735     Enrico 	char 		buf[BAM_MAXLINE];
   2389   8735     Enrico 	const char 	*fcn = "read_one_list()";
   2390      0     stevel 
   2391      0     stevel 	(void) snprintf(path, sizeof (path), "%s%s", root, filelist);
   2392      0     stevel 
   2393      0     stevel 	fp = fopen(path, "r");
   2394      0     stevel 	if (fp == NULL) {
   2395   6448     vikram 		BAM_DPRINTF((D_FLIST_FAIL, fcn, path, strerror(errno)));
   2396      0     stevel 		return (BAM_ERROR);
   2397      0     stevel 	}
   2398      0     stevel 	while (s_fgets(buf, sizeof (buf), fp) != NULL) {
   2399    316     vikram 		/* skip blank lines */
   2400    316     vikram 		if (strspn(buf, " \t") == strlen(buf))
   2401    316     vikram 			continue;
   2402      0     stevel 		append_to_flist(flistp, buf);
   2403      0     stevel 	}
   2404      0     stevel 	if (fclose(fp) != 0) {
   2405      0     stevel 		bam_error(CLOSE_FAIL, path, strerror(errno));
   2406      0     stevel 		return (BAM_ERROR);
   2407      0     stevel 	}
   2408      0     stevel 	return (BAM_SUCCESS);
   2409      0     stevel }
   2410      0     stevel 
   2411      0     stevel static error_t
   2412      0     stevel read_list(char *root, filelist_t  *flistp)
   2413      0     stevel {
   2414   8735     Enrico 	char 		path[PATH_MAX];
   2415   8735     Enrico 	char 		cmd[PATH_MAX];
   2416   8735     Enrico 	struct stat 	sb;
   2417   8735     Enrico 	int 		n, rval;
   2418   8735     Enrico 	const char 	*fcn = "read_list()";
   2419      0     stevel 
   2420      0     stevel 	flistp->head = flistp->tail = NULL;
   2421      0     stevel 
   2422      0     stevel 	/*
   2423   5648      setje 	 * build and check path to extract_boot_filelist.ksh
   2424   5648      setje 	 */
   2425   5648      setje 	n = snprintf(path, sizeof (path), "%s%s", root, EXTRACT_BOOT_FILELIST);
   2426   5648      setje 	if (n >= sizeof (path)) {
   2427   5648      setje 		bam_error(NO_FLIST);
   2428   5648      setje 		return (BAM_ERROR);
   2429   5648      setje 	}
   2430   8954     Enrico 
   2431   8954     Enrico 	if (is_safe_exec(path) == BAM_ERROR)
   2432   8954     Enrico 		return (BAM_ERROR);
   2433   5648      setje 
   2434   5648      setje 	/*
   2435   5648      setje 	 * If extract_boot_filelist is present, exec it, otherwise read
   2436   5648      setje 	 * the filelists directly, for compatibility with older images.
   2437   5648      setje 	 */
   2438   5648      setje 	if (stat(path, &sb) == 0) {
   2439   5648      setje 		/*
   2440   5648      setje 		 * build arguments to exec extract_boot_filelist.ksh
   2441   5648      setje 		 */
   2442   6319         jg 		char *rootarg, *platarg;
   2443   6319         jg 		int platarglen = 1, rootarglen = 1;
   2444   6319         jg 		if (strlen(root) > 1)
   2445   6319         jg 			rootarglen += strlen(root) + strlen("-R ");
   2446   6319         jg 		if (bam_alt_platform)
   2447   6319         jg 			platarglen += strlen(bam_platform) + strlen("-p ");
   2448   6319         jg 		platarg = s_calloc(1, platarglen);
   2449   6319         jg 		rootarg = s_calloc(1, rootarglen);
   2450   6319         jg 		*platarg = 0;
   2451   6319         jg 		*rootarg = 0;
   2452   6319         jg 
   2453   5648      setje 		if (strlen(root) > 1) {
   2454   6319         jg 			(void) snprintf(rootarg, rootarglen,
   2455   6319         jg 			    "-R %s", root);
   2456   6319         jg 		}
   2457   6319         jg 		if (bam_alt_platform) {
   2458   6319         jg 			(void) snprintf(platarg, platarglen,
   2459   6319         jg 			    "-p %s", bam_platform);
   2460   6319         jg 		}
   2461   6319         jg 		n = snprintf(cmd, sizeof (cmd), "%s %s %s /%s /%s",
   2462   6319         jg 		    path, rootarg, platarg, BOOT_FILE_LIST, ETC_FILE_LIST);
   2463   6319         jg 		free(platarg);
   2464   6319         jg 		free(rootarg);
   2465   5648      setje 		if (n >= sizeof (cmd)) {
   2466   5648      setje 			bam_error(NO_FLIST);
   2467   5648      setje 			return (BAM_ERROR);
   2468   5648      setje 		}
   2469   5648      setje 		if (exec_cmd(cmd, flistp) != 0) {
   2470   6448     vikram 			BAM_DPRINTF((D_FLIST_FAIL, fcn, path, strerror(errno)));
   2471   5648      setje 			return (BAM_ERROR);
   2472   5648      setje 		}
   2473   5648      setje 	} else {
   2474   5648      setje 		/*
   2475   5648      setje 		 * Read current lists of files - only the first is mandatory
   2476   5648      setje 		 */
   2477   5648      setje 		rval = read_one_list(root, flistp, BOOT_FILE_LIST);
   2478   5648      setje 		if (rval != BAM_SUCCESS)
   2479   5648      setje 			return (rval);
   2480   5648      setje 		(void) read_one_list(root, flistp, ETC_FILE_LIST);
   2481   5648      setje 	}
   2482      0     stevel 
   2483      0     stevel 	if (flistp->head == NULL) {
   2484      0     stevel 		bam_error(NO_FLIST);
   2485      0     stevel 		return (BAM_ERROR);
   2486      0     stevel 	}
   2487      0     stevel 
   2488      0     stevel 	return (BAM_SUCCESS);
   2489      0     stevel }
   2490      0     stevel 
   2491      0     stevel static void
   2492      0     stevel getoldstat(char *root)
   2493      0     stevel {
   2494   8735     Enrico 	char 		path[PATH_MAX];
   2495   8735     Enrico 	int 		fd, error;
   2496   8735     Enrico 	struct stat 	sb;
   2497   8735     Enrico 	char 		*ostat;
   2498      0     stevel 
   2499      0     stevel 	(void) snprintf(path, sizeof (path), "%s%s", root, FILE_STAT);
   2500      0     stevel 	fd = open(path, O_RDONLY);
   2501      0     stevel 	if (fd == -1) {
   2502      0     stevel 		if (bam_verbose)
   2503      0     stevel 			bam_print(OPEN_FAIL, path, strerror(errno));
   2504   8735     Enrico 		goto out_err;
   2505      0     stevel 	}
   2506      0     stevel 
   2507      0     stevel 	if (fstat(fd, &sb) != 0) {
   2508      0     stevel 		bam_error(STAT_FAIL, path, strerror(errno));
   2509   8735     Enrico 		goto out_err;
   2510      0     stevel 	}
   2511      0     stevel 
   2512      0     stevel 	ostat = s_calloc(1, sb.st_size);
   2513      0     stevel 
   2514      0     stevel 	if (read(fd, ostat, sb.st_size) != sb.st_size) {
   2515      0     stevel 		bam_error(READ_FAIL, path, strerror(errno));
   2516      0     stevel 		free(ostat);
   2517   8735     Enrico 		goto out_err;
   2518      0     stevel 	}
   2519      0     stevel 
   2520      0     stevel 	(void) close(fd);
   2521   8735     Enrico 	fd = -1;
   2522      0     stevel 
   2523      0     stevel 	walk_arg.old_nvlp = NULL;
   2524      0     stevel 	error = nvlist_unpack(ostat, sb.st_size, &walk_arg.old_nvlp, 0);
   2525      0     stevel 
   2526      0     stevel 	free(ostat);
   2527      0     stevel 
   2528      0     stevel 	if (error) {
   2529      0     stevel 		bam_error(UNPACK_FAIL, path, strerror(error));
   2530      0     stevel 		walk_arg.old_nvlp = NULL;
   2531   8735     Enrico 		goto out_err;
   2532   8735     Enrico 	} else {
   2533   8735     Enrico 		return;
   2534   8735     Enrico 	}
   2535   8735     Enrico 
   2536   8735     Enrico out_err:
   2537   8735     Enrico 	if (fd != -1)
   2538   8735     Enrico 		(void) close(fd);
   2539   8954     Enrico 	if (!is_flag_on(IS_SPARC_TARGET))
   2540   8954     Enrico 		set_dir_flag(FILE32, NEED_UPDATE);
   2541   8735     Enrico 	set_dir_flag(FILE64, NEED_UPDATE);
   2542   8735     Enrico }
   2543   8735     Enrico 
   2544   8735     Enrico /* Best effort stale entry removal */
   2545   8735     Enrico static void
   2546   8735     Enrico delete_stale(char *file, int what)
   2547   8735     Enrico {
   2548   8735     Enrico 	char		path[PATH_MAX];
   2549   8735     Enrico 	struct stat	sb;
   2550   8735     Enrico 
   2551   8735     Enrico 	(void) snprintf(path, sizeof (path), "%s/%s", get_cachedir(what), file);
   2552   8735     Enrico 	if (!bam_check && stat(path, &sb) == 0) {
   2553   8735     Enrico 		if (sb.st_mode & S_IFDIR)
   2554   8735     Enrico 			(void) rmdir_r(path);
   2555   8735     Enrico 		else
   2556   8735     Enrico 			(void) unlink(path);
   2557   8735     Enrico 
   2558   8735     Enrico 		set_dir_flag(what, (NEED_UPDATE | NO_MULTI));
   2559   8735     Enrico 	}
   2560      0     stevel }
   2561      0     stevel 
   2562   2583     vikram /*
   2563   2583     vikram  * Checks if a file in the current (old) archive has
   2564   2583     vikram  * been deleted from the root filesystem. This is needed for
   2565   2583     vikram  * software like Trusted Extensions (TX) that switch early
   2566   2583     vikram  * in boot based on presence/absence of a kernel module.
   2567   2583     vikram  */
   2568   2583     vikram static void
   2569   2583     vikram check4stale(char *root)
   2570   2583     vikram {
   2571   2583     vikram 	nvpair_t	*nvp;
   2572   2583     vikram 	nvlist_t	*nvlp;
   2573   2583     vikram 	char 		*file;
   2574   2583     vikram 	char		path[PATH_MAX];
   2575   2583     vikram 
   2576   2583     vikram 	/*
   2577   2583     vikram 	 * Skip stale file check during smf check
   2578   2583     vikram 	 */
   2579   2583     vikram 	if (bam_smf_check)
   2580   8735     Enrico 		return;
   2581   8735     Enrico 
   2582   8735     Enrico 	/*
   2583   8735     Enrico 	 * If we need to (re)create the cache, there's no need to check for
   2584   8735     Enrico 	 * stale files
   2585   8735     Enrico 	 */
   2586   8735     Enrico 	if (is_flag_on(NEED_CACHE_DIR))
   2587   2583     vikram 		return;
   2588   2583     vikram 
   2589   2583     vikram 	/* Nothing to do if no old stats */
   2590   2583     vikram 	if ((nvlp = walk_arg.old_nvlp) == NULL)
   2591   2583     vikram 		return;
   2592   2583     vikram 
   2593   2583     vikram 	for (nvp = nvlist_next_nvpair(nvlp, NULL); nvp;
   2594   2583     vikram 	    nvp = nvlist_next_nvpair(nvlp, nvp)) {
   2595   2583     vikram 		file = nvpair_name(nvp);
   2596   2583     vikram 		if (file == NULL)
   2597   2583     vikram 			continue;
   2598   2583     vikram 		(void) snprintf(path, sizeof (path), "%s/%s",
   2599   2583     vikram 		    root, file);
   2600   8735     Enrico 		if (access(path, F_OK) < 0) {
   2601   8735     Enrico 			int	what;
   2602   8735     Enrico 
   2603   8954     Enrico 			if (bam_verbose)
   2604   8954     Enrico 				bam_print(PARSEABLE_STALE_FILE, path);
   2605   8954     Enrico 
   2606   8954     Enrico 			if (is_flag_on(IS_SPARC_TARGET)) {
   2607   8735     Enrico 				set_dir_flag(FILE64, NEED_UPDATE);
   2608   8954     Enrico 			} else {
   2609   8954     Enrico 				for (what = FILE32; what < CACHEDIR_NUM; what++)
   2610   8954     Enrico 					if (has_cachedir(what))
   2611   8954     Enrico 						delete_stale(file, what);
   2612   8954     Enrico 			}
   2613   2583     vikram 		}
   2614   2583     vikram 	}
   2615   2583     vikram }
   2616   2583     vikram 
   2617      0     stevel static void
   2618      0     stevel create_newstat(void)
   2619      0     stevel {
   2620      0     stevel 	int error;
   2621      0     stevel 
   2622      0     stevel 	error = nvlist_alloc(&walk_arg.new_nvlp, NV_UNIQUE_NAME, 0);
   2623      0     stevel 	if (error) {
   2624      0     stevel 		/*
   2625      0     stevel 		 * Not fatal - we can still create archive
   2626      0     stevel 		 */
   2627      0     stevel 		walk_arg.new_nvlp = NULL;
   2628      0     stevel 		bam_error(NVALLOC_FAIL, strerror(error));
   2629      0     stevel 	}
   2630      0     stevel }
   2631      0     stevel 
   2632   8735     Enrico static int
   2633      0     stevel walk_list(char *root, filelist_t *flistp)
   2634      0     stevel {
   2635      0     stevel 	char path[PATH_MAX];
   2636      0     stevel 	line_t *lp;
   2637      0     stevel 
   2638      0     stevel 	for (lp = flistp->head; lp; lp = lp->next) {
   2639   5648      setje 		/*
   2640   5648      setje 		 * Don't follow symlinks.  A symlink must refer to
   2641   5648      setje 		 * a file that would appear in the archive through
   2642   5648      setje 		 * a direct reference.  This matches the archive
   2643   5648      setje 		 * construction behavior.
   2644   5648      setje 		 */
   2645      0     stevel 		(void) snprintf(path, sizeof (path), "%s%s", root, lp->line);
   2646   5648      setje 		if (nftw(path, cmpstat, 20, FTW_PHYS) == -1) {
   2647   8735     Enrico 			if (is_flag_on(UPDATE_ERROR))
   2648   8735     Enrico 				return (BAM_ERROR);
   2649      0     stevel 			/*
   2650      0     stevel 			 * Some files may not exist.
   2651      0     stevel 			 * For example: etc/rtc_config on a x86 diskless system
   2652      0     stevel 			 * Emit verbose message only
   2653      0     stevel 			 */
   2654      0     stevel 			if (bam_verbose)
   2655      0     stevel 				bam_print(NFTW_FAIL, path, strerror(errno));
   2656      0     stevel 		}
   2657      0     stevel 	}
   2658   8735     Enrico 
   2659   8735     Enrico 	return (BAM_SUCCESS);
   2660      0     stevel }
   2661   9233     Enrico 
   2662   9233     Enrico /*
   2663   9233     Enrico  * Update the timestamp file.
   2664   9233     Enrico  */
   2665   9233     Enrico static void
   2666   9233     Enrico update_timestamp(char *root)
   2667   9233     Enrico {
   2668   9233     Enrico 	char	timestamp_path[PATH_MAX];
   2669   9233     Enrico 
   2670   9233     Enrico 	/* this path length has already been checked in check_flags_and_files */
   2671   9233     Enrico 	(void) snprintf(timestamp_path, sizeof (timestamp_path), "%s%s", root,
   2672   9233     Enrico 	    FILE_STAT_TIMESTAMP);
   2673   9233     Enrico 
   2674   9233     Enrico 	/*
   2675   9233     Enrico 	 * recreate the timestamp file. Since an outdated or absent timestamp
   2676   9233     Enrico 	 * file translates in a complete rebuild of the archive cache, notify
   2677   9233     Enrico 	 * the user of the performance issue.
   2678   9233     Enrico 	 */
   2679   9233     Enrico 	if (creat(timestamp_path, FILE_STAT_MODE) < 0) {
   2680   9233     Enrico 		bam_error(OPEN_FAIL, timestamp_path, strerror(errno));
   2681   9233     Enrico 		bam_error(TIMESTAMP_FAIL, rootbuf);
   2682   9233     Enrico 	}
   2683   9233     Enrico }
   2684   9233     Enrico 
   2685      0     stevel 
   2686      0     stevel static void
   2687      0     stevel savenew(char *root)
   2688      0     stevel {
   2689   8735     Enrico 	char 	path[PATH_MAX];
   2690   8735     Enrico 	char 	path2[PATH_MAX];
   2691   8735     Enrico 	size_t 	sz;
   2692   8735     Enrico 	char 	*nstat;
   2693   8735     Enrico 	int 	fd, wrote, error;
   2694      0     stevel 
   2695      0     stevel 	nstat = NULL;
   2696      0     stevel 	sz = 0;
   2697      0     stevel 	error = nvlist_pack(walk_arg.new_nvlp, &nstat, &sz,
   2698      0     stevel 	    NV_ENCODE_XDR, 0);
   2699      0     stevel 	if (error) {
   2700      0     stevel 		bam_error(PACK_FAIL, strerror(error));
   2701      0     stevel 		return;
   2702      0     stevel 	}
   2703      0     stevel 
   2704      0     stevel 	(void) snprintf(path, sizeof (path), "%s%s", root, FILE_STAT_TMP);
   2705      0     stevel 	fd = open(path, O_RDWR|O_CREAT|O_TRUNC, FILE_STAT_MODE);
   2706      0     stevel 	if (fd == -1) {
   2707      0     stevel 		bam_error(OPEN_FAIL, path, strerror(errno));
   2708      0     stevel 		free(nstat);
   2709      0     stevel 		return;
   2710      0     stevel 	}
   2711      0     stevel 	wrote = write(fd, nstat, sz);
   2712      0     stevel 	if (wrote != sz) {
   2713      0     stevel 		bam_error(WRITE_FAIL, path, strerror(errno));
   2714      0     stevel 		(void) close(fd);
   2715      0     stevel 		free(nstat);
   2716      0     stevel 		return;
   2717      0     stevel 	}
   2718      0     stevel 	(void) close(fd);
   2719      0     stevel 	free(nstat);
   2720      0     stevel 
   2721      0     stevel 	(void) snprintf(path2, sizeof (path2), "%s%s", root, FILE_STAT);
   2722      0     stevel 	if (rename(path, path2) != 0) {
   2723      0     stevel 		bam_error(RENAME_FAIL, path2, strerror(errno));
   2724      0     stevel 	}
   2725      0     stevel }
   2726      0     stevel 
   2727   8735     Enrico #define	init_walk_args()	bzero(&walk_arg, sizeof (walk_arg))
   2728   8735     Enrico 
   2729      0     stevel static void
   2730      0     stevel clear_walk_args(void)
   2731      0     stevel {
   2732      0     stevel 	if (walk_arg.old_nvlp)
   2733      0     stevel 		nvlist_free(walk_arg.old_nvlp);
   2734      0     stevel 	if (walk_arg.new_nvlp)
   2735      0     stevel 		nvlist_free(walk_arg.new_nvlp);
   2736   8735     Enrico 	if (walk_arg.sparcfile)
   2737   8735     Enrico 		(void) fclose(walk_arg.sparcfile);
   2738      0     stevel 	walk_arg.old_nvlp = NULL;
   2739      0     stevel 	walk_arg.new_nvlp = NULL;
   2740   8735     Enrico 	walk_arg.sparcfile = NULL;
   2741      0     stevel }
   2742      0     stevel 
   2743      0     stevel /*
   2744      0     stevel  * Returns:
   2745      0     stevel  *	0 - no update necessary
   2746      0     stevel  *	1 - update required.
   2747      0     stevel  *	BAM_ERROR (-1) - An error occurred
   2748      0     stevel  *
   2749      0     stevel  * Special handling for check (-n):
   2750      0     stevel  * ================================
   2751      0     stevel  * The check (-n) option produces parseable output.
   2752      0     stevel  * To do this, we suppress all stdout messages unrelated
   2753      0     stevel  * to out of sync files.
   2754      0     stevel  * All stderr messages are still printed though.
   2755      0     stevel  *
   2756      0     stevel  */
   2757      0     stevel static int
   2758      0     stevel update_required(char *root)
   2759      0     stevel {
   2760   8735     Enrico 	struct stat 	sb;
   2761   8735     Enrico 	char 		path[PATH_MAX];
   2762   8735     Enrico 	filelist_t 	flist;
   2763   8735     Enrico 	filelist_t 	*flistp = &flist;
   2764   8735     Enrico 	int 		ret;
   2765      0     stevel 
   2766      0     stevel 	flistp->head = flistp->tail = NULL;
   2767      0     stevel 
   2768   8735     Enrico 	if (is_sparc())
   2769   8735     Enrico 		set_flag(IS_SPARC_TARGET);
   2770   8735     Enrico 
   2771   8735     Enrico 	/*
   2772   8735     Enrico 	 * Check if cache directories and archives are present
   2773   8735     Enrico 	 */
   2774   8735     Enrico 
   2775   8735     Enrico 	ret = check_flags_and_files(root);
   2776   8735     Enrico 	if (ret < 0)
   2777   8735     Enrico 		return (BAM_ERROR);
   2778      0     stevel 
   2779      0     stevel 	/*
   2780      0     stevel 	 * In certain deployment scenarios, filestat may not
   2781      0     stevel 	 * exist. Ignore it during boot-archive SMF check.
   2782      0     stevel 	 */
   2783      0     stevel 	if (bam_smf_check) {
   2784      0     stevel 		(void) snprintf(path, sizeof (path), "%s%s", root, FILE_STAT);
   2785      0     stevel 		if (stat(path, &sb) != 0)
   2786      0     stevel 			return (0);
   2787      0     stevel 	}
   2788      0     stevel 
   2789   8735     Enrico 	getoldstat(root);
   2790   2583     vikram 
   2791   2583     vikram 	/*
   2792   2583     vikram 	 * Check if the archive contains files that are no longer
   2793   2583     vikram 	 * present on the root filesystem.
   2794   2583     vikram 	 */
   2795   8735     Enrico 	check4stale(root);
   2796      0     stevel 
   2797      0     stevel 	/*
   2798      0     stevel 	 * read list of files
   2799      0     stevel 	 */
   2800      0     stevel 	if (read_list(root, flistp) != BAM_SUCCESS) {
   2801      0     stevel 		clear_walk_args();
   2802      0     stevel 		return (BAM_ERROR);
   2803      0     stevel 	}
   2804      0     stevel 
   2805      0     stevel 	assert(flistp->head && flistp->tail);
   2806      0     stevel 
   2807      0     stevel 	/*
   2808      0     stevel 	 * At this point either the update is required
   2809      0     stevel 	 * or the decision is pending. In either case
   2810      0     stevel 	 * we need to create new stat nvlist
   2811      0     stevel 	 */
   2812      0     stevel 	create_newstat();
   2813      0     stevel 	/*
   2814      0     stevel 	 * This walk does 2 things:
   2815      0     stevel 	 *  	- gets new stat data for every file
   2816      0     stevel 	 *	- (optional) compare old and new stat data
   2817      0     stevel 	 */
   2818   8735     Enrico 	ret = walk_list(root, &flist);
   2819      0     stevel 
   2820      0     stevel 	/* done with the file list */
   2821      0     stevel 	filelist_free(flistp);
   2822      0     stevel 
   2823   8735     Enrico 	/* something went wrong */
   2824   8735     Enrico 
   2825   8735     Enrico 	if (ret == BAM_ERROR) {
   2826   8735     Enrico 		bam_error(CACHE_FAIL);
   2827   8735     Enrico 		return (BAM_ERROR);
   2828   8735     Enrico 	}
   2829   8735     Enrico 
   2830      0     stevel 	if (walk_arg.new_nvlp == NULL) {
   2831   8954     Enrico 		if (walk_arg.sparcfile != NULL)
   2832   8954     Enrico 			(void) fclose(walk_arg.sparcfile);
   2833      0     stevel 		bam_error(NO_NEW_STAT);
   2834   8735     Enrico 	}
   2835   8735     Enrico 
   2836   8735     Enrico 	/* If nothing was updated, discard newstat. */
   2837   8735     Enrico 
   2838   8735     Enrico 	if (!is_dir_flag_on(FILE32, NEED_UPDATE) &&
   2839   8735     Enrico 	    !is_dir_flag_on(FILE64, NEED_UPDATE)) {
   2840      0     stevel 		clear_walk_args();
   2841   8735     Enrico 		return (0);
   2842   8735     Enrico 	}
   2843   8735     Enrico 
   2844   8954     Enrico 	if (walk_arg.sparcfile != NULL)
   2845   8954     Enrico 		(void) fclose(walk_arg.sparcfile);
   2846      0     stevel 
   2847      0     stevel 	return (1);
   2848   8735     Enrico }
   2849   8735     Enrico 
   2850   8735     Enrico static int
   2851   8735     Enrico flushfs(char *root)
   2852   8735     Enrico {
   2853   8735     Enrico 	char	cmd[PATH_MAX + 30];
   2854   8735     Enrico 
   2855   8735     Enrico 	(void) snprintf(cmd, sizeof (cmd), "%s -f \"%s\" 2>/dev/null",
   2856   8735     Enrico 	    LOCKFS_PATH, root);
   2857   8735     Enrico 
   2858   8735     Enrico 	return (exec_cmd(cmd, NULL));
   2859   8735     Enrico }
   2860   8735     Enrico 
   2861   8735     Enrico static int
   2862   8735     Enrico do_archive_copy(char *source, char *dest)
   2863   8735     Enrico {
   2864   8735     Enrico 
   2865   8954     Enrico 	sync();
   2866   8735     Enrico 
   2867   8735     Enrico 	/* the equivalent of mv archive-new-$pid boot_archive */
   2868   8954     Enrico 	if (rename(source, dest) != 0) {
   2869   8954     Enrico 		(void) unlink(source);
   2870   8954     Enrico 		return (BAM_ERROR);
   2871   8954     Enrico 	}
   2872   8735     Enrico 
   2873   8735     Enrico 	if (flushfs(bam_root) != 0)
   2874   8954     Enrico 		sync();
   2875   8735     Enrico 
   2876   8735     Enrico 	return (BAM_SUCCESS);
   2877   8735     Enrico }
   2878   8735     Enrico 
   2879   8735     Enrico static int
   2880   8735     Enrico check_cmdline(filelist_t flist)
   2881   8735     Enrico {
   2882   8735     Enrico 	line_t	*lp;
   2883   8735     Enrico 
   2884   8735     Enrico 	for (lp = flist.head; lp; lp = lp->next) {
   2885   8735     Enrico 		if (strstr(lp->line, "Error:") != NULL ||
   2886   8735     Enrico 		    strstr(lp->line, "Inode number overflow") != NULL) {
   2887   8954     Enrico 			(void) fprintf(stderr, "%s\n", lp->line);
   2888   8954     Enrico 			return (BAM_ERROR);
   2889   8954     Enrico 		}
   2890   8954     Enrico 	}
   2891   8954     Enrico 
   2892   8954     Enrico 	return (BAM_SUCCESS);
   2893   8954     Enrico }
   2894   8954     Enrico 
   2895   8954     Enrico static void
   2896   8954     Enrico dump_errormsg(filelist_t flist)
   2897   8954     Enrico {
   2898   8954     Enrico 	line_t	*lp;
   2899   8954     Enrico 
   2900   8954     Enrico 	for (lp = flist.head; lp; lp = lp->next)
   2901   8954     Enrico 		(void) fprintf(stderr, "%s\n", lp->line);
   2902   8735     Enrico }
   2903   8735     Enrico 
   2904   8735     Enrico static int
   2905   8735     Enrico check_archive(char *dest)
   2906   8735     Enrico {
   2907   8735     Enrico 	struct stat	sb;
   2908   8735     Enrico 
   2909   8735     Enrico 	if (stat(dest, &sb) != 0 || !S_ISREG(sb.st_mode) ||
   2910   8735     Enrico 	    sb.st_size < 10000) {
   2911   8735     Enrico 		bam_error(ARCHIVE_BAD, dest);
   2912   8735     Enrico 		(void) unlink(dest);
   2913   8735     Enrico 		return (BAM_ERROR);
   2914   8735     Enrico 	}
   2915   8735     Enrico 
   2916   8735     Enrico 	return (BAM_SUCCESS);
   2917   8735     Enrico }
   2918   8735     Enrico 
   2919   8735     Enrico /*
   2920   8735     Enrico  * Returns 1 if mkiso is in the expected PATH, 0 otherwise
   2921   8735     Enrico  */
   2922   8735     Enrico static int
   2923   8735     Enrico is_mkisofs()
   2924   8735     Enrico {
   2925   8954     Enrico 	if (access(MKISOFS_PATH, X_OK) == 0)
   2926   8954     Enrico 		return (1);
   2927   8735     Enrico 	return (0);
   2928   8735     Enrico }
   2929   8735     Enrico 
   2930   8735     Enrico #define	MKISO_PARAMS	" -quiet -graft-points -dlrDJN -relaxed-filenames "
   2931   8735     Enrico 
   2932   8735     Enrico static int
   2933   8735     Enrico create_sparc_archive(char *archive, char *tempname, char *bootblk, char *list)
   2934   8735     Enrico {
   2935   8735     Enrico 	int		ret;
   2936   8735     Enrico 	char		cmdline[3 * PATH_MAX + 64];
   2937   8735     Enrico 	filelist_t	flist = {0};
   2938   8735     Enrico 	const char	*func = "create_sparc_archive()";
   2939   8735     Enrico 
   2940   8735     Enrico 	if (access(bootblk, R_OK) == 1) {
   2941   8735     Enrico 		bam_error(BOOTBLK_FAIL, bootblk);
   2942   8735     Enrico 		return (BAM_ERROR);
   2943   8735     Enrico 	}
   2944   8735     Enrico 
   2945   8735     Enrico 	/*
   2946   8735     Enrico 	 * Prepare mkisofs command line and execute it
   2947   8735     Enrico 	 */
   2948   8735     Enrico 	(void) snprintf(cmdline, sizeof (cmdline), "%s %s -G %s -o \"%s\" "
   2949   8954     Enrico 	    "-path-list \"%s\" 2>&1", MKISOFS_PATH, MKISO_PARAMS, bootblk,
   2950   8735     Enrico 	    tempname, list);
   2951   8735     Enrico 
   2952   8735     Enrico 	BAM_DPRINTF((D_CMDLINE, func, cmdline));
   2953   8735     Enrico 
   2954   8735     Enrico 	ret = exec_cmd(cmdline, &flist);
   2955   8954     Enrico 	if (ret != 0 || check_cmdline(flist) == BAM_ERROR) {
   2956   8954     Enrico 		dump_errormsg(flist);
   2957   8954     Enrico 		goto out_err;
   2958   8954     Enrico 	}
   2959   8735     Enrico 
   2960   8735     Enrico 	filelist_free(&flist);
   2961   8735     Enrico 
   2962   8735     Enrico 	/*
   2963   8735     Enrico 	 * Prepare dd command line to copy the bootblk on the new archive and
   2964   8735     Enrico 	 * execute it
   2965   8735     Enrico 	 */
   2966   8735     Enrico 	(void) snprintf(cmdline, sizeof (cmdline), "%s if=\"%s\" of=\"%s\""
   2967   8954     Enrico 	    " bs=1b oseek=1 count=15 conv=notrunc conv=sync 2>&1", DD_PATH_USR,
   2968   8735     Enrico 	    bootblk, tempname);
   2969   8735     Enrico 
   2970   8735     Enrico 	BAM_DPRINTF((D_CMDLINE, func, cmdline));
   2971   8735     Enrico 
   2972   8735     Enrico 	ret = exec_cmd(cmdline, &flist);
   2973   8735     Enrico 	if (ret != 0 || check_cmdline(flist) == BAM_ERROR)
   2974   8735     Enrico 		goto out_err;
   2975   8735     Enrico 
   2976   8735     Enrico 	filelist_free(&flist);
   2977   8735     Enrico 
   2978   8735     Enrico 	/* Did we get a valid archive ? */
   2979   8735     Enrico 	if (check_archive(tempname) == BAM_ERROR)
   2980   8735     Enrico 		return (BAM_ERROR);
   2981   8735     Enrico 
   2982   8735     Enrico 	return (do_archive_copy(tempname, archive));
   2983   8735     Enrico 
   2984   8735     Enrico out_err:
   2985   8735     Enrico 	filelist_free(&flist);
   2986   8735     Enrico 	bam_error(ARCHIVE_FAIL, cmdline);
   2987   8735     Enrico 	(void) unlink(tempname);
   2988   8735     Enrico 	return (BAM_ERROR);
   2989   8735     Enrico }
   2990   8735     Enrico 
   2991   8735     Enrico static unsigned int
   2992   8735     Enrico from_733(unsigned char *s)
   2993   8735     Enrico {
   2994   8735     Enrico 	int		i;
   2995   8735     Enrico 	unsigned int	ret = 0;
   2996   8735     Enrico 
   2997   8735     Enrico 	for (i = 0; i < 4; i++)
   2998   8735     Enrico 		ret |= s[i] << (8 * i);
   2999   8735     Enrico 
   3000   8735     Enrico 	return (ret);
   3001   8735     Enrico }
   3002   8735     Enrico 
   3003   8735     Enrico static void
   3004   8735     Enrico to_733(unsigned char *s, unsigned int val)
   3005   8735     Enrico {
   3006   8735     Enrico 	int	i;
   3007   8735     Enrico 
   3008   8735     Enrico 	for (i = 0; i < 4; i++)
   3009   8735     Enrico 		s[i] = s[7-i] = (val >> (8 * i)) & 0xFF;
   3010   8735     Enrico }
   3011   8735     Enrico 
   3012   8735     Enrico /*
   3013   8735     Enrico  * Extends the current boot archive without recreating it from scratch
   3014   8735     Enrico  */
   3015   8735     Enrico static int
   3016   8735     Enrico extend_iso_archive(char *archive, char *tempname, char *update_dir)
   3017   8735     Enrico {
   3018   8735     Enrico 	int			fd = -1, newfd = -1, ret, i;
   3019   8735     Enrico 	int			next_session = 0, new_size = 0;
   3020   8735     Enrico 	char			cmdline[3 * PATH_MAX + 64];
   3021   8735     Enrico 	const char		*func = "extend_iso_archive()";
   3022   8735     Enrico 	filelist_t		flist = {0};
   3023   8735     Enrico 	struct iso_pdesc	saved_desc[MAX_IVDs];
   3024   8735     Enrico 
   3025   8735     Enrico 	fd = open(archive, O_RDWR);
   3026   8735     Enrico 	if (fd == -1) {
   3027   8954     Enrico 		if (bam_verbose)
   3028   8954     Enrico 			bam_error(OPEN_FAIL, archive, strerror(errno));
   3029   8735     Enrico 		goto out_err;
   3030   8735     Enrico 	}
   3031   8735     Enrico 
   3032   8735     Enrico 	/*
   3033   8735     Enrico 	 * A partial read is likely due to a corrupted file
   3034   8735     Enrico 	 */
   3035   8735     Enrico 	ret = pread64(fd, saved_desc, sizeof (saved_desc),
   3036   8735     Enrico 	    VOLDESC_OFF * CD_BLOCK);
   3037   8735     Enrico 	if (ret != sizeof (saved_desc)) {
   3038   8954     Enrico 		if (bam_verbose)
   3039   8954     Enrico 			bam_error(READ_FAIL, archive, strerror(errno));
   3040   8735     Enrico 		goto out_err;
   3041   8735     Enrico 	}
   3042   8735     Enrico 
   3043   8735     Enrico 	if (memcmp(saved_desc[0].type, "\1CD001", 6)) {
   3044   8954     Enrico 		if (bam_verbose)
   3045   8954     Enrico 			bam_error(SIGN_FAIL, archive);
   3046   8735     Enrico 		goto out_err;
   3047   8735     Enrico 	}
   3048   8735     Enrico 
   3049   8735     Enrico 	/*
   3050   8735     Enrico 	 * Read primary descriptor and locate next_session offset (it should
   3051   8735     Enrico 	 * point to the end of the archive)
   3052   8735     Enrico 	 */
   3053   8735     Enrico 	next_session = P2ROUNDUP(from_733(saved_desc[0].volume_space_size), 16);
   3054   8735     Enrico 
   3055   8735     Enrico 	(void) snprintf(cmdline, sizeof (cmdline), "%s -C 16,%d -M %s %s -o \""
   3056   8954     Enrico 	    "%s\" \"%s\" 2>&1", MKISOFS_PATH, next_session, archive,
   3057   8954     Enrico 	    MKISO_PARAMS, tempname, update_dir);
   3058   8735     Enrico 
   3059   8735     Enrico 	BAM_DPRINTF((D_CMDLINE, func, cmdline));
   3060   8735     Enrico 
   3061   8735     Enrico 	ret = exec_cmd(cmdline, &flist);
   3062   8735     Enrico 	if (ret != 0 || check_cmdline(flist) == BAM_ERROR) {
   3063   8954     Enrico 		if (bam_verbose) {
   3064   8954     Enrico 			bam_error(MULTI_FAIL, cmdline);
   3065   8954     Enrico 			dump_errormsg(flist);
   3066   8954     Enrico 		}
   3067   8735     Enrico 		goto out_flist_err;
   3068   8735     Enrico 	}
   3069   8735     Enrico 	filelist_free(&flist);
   3070   8735     Enrico 
   3071   8735     Enrico 	newfd = open(tempname, O_RDONLY);
   3072   8735     Enrico 	if (newfd == -1) {
   3073   8954     Enrico 		if (bam_verbose)
   3074   8954     Enrico 			bam_error(OPEN_FAIL, archive, strerror(errno));
   3075   8735     Enrico 		goto out_err;
   3076   8735     Enrico 	}
   3077   8735     Enrico 
   3078   8735     Enrico 	ret = pread64(newfd, saved_desc, sizeof (saved_desc),
   3079   8735     Enrico 	    VOLDESC_OFF * CD_BLOCK);
   3080   8735     Enrico 	if (ret != sizeof (saved_desc)) {
   3081   8954     Enrico 		if (bam_verbose)
   3082   8954     Enrico 			bam_error(READ_FAIL, archive, strerror(errno));
   3083   8735     Enrico 		goto out_err;
   3084   8735     Enrico 	}
   3085   8735     Enrico 
   3086   8735     Enrico 	if (memcmp(saved_desc[0].type, "\1CD001", 6)) {
   3087   8954     Enrico 		if (bam_verbose)
   3088   8954     Enrico 			bam_error(SIGN_FAIL, archive);
   3089   8735     Enrico 		goto out_err;
   3090   8735     Enrico 	}
   3091   8735     Enrico 
   3092   8735     Enrico 	new_size = from_733(saved_desc[0].volume_space_size) + next_session;
   3093   8735     Enrico 	to_733(saved_desc[0].volume_space_size, new_size);
   3094   8735     Enrico 
   3095   8735     Enrico 	for (i = 1; i < MAX_IVDs; i++) {
   3096   8735     Enrico 		if (saved_desc[i].type[0] == (unsigned char)255)
   3097   8735     Enrico 			break;
   3098   8735     Enrico 		if (memcmp(saved_desc[i].id, "CD001", 5))
   3099   8735     Enrico 			break;
   3100   8735     Enrico 
   3101   8735     Enrico 		if (bam_verbose)
   3102   8735     Enrico 			bam_print("%s: Updating descriptor entry [%d]\n", func,
   3103   8735