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, ×tamp) != 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