4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
26 * Copyright 2012 Milan Jurik. All rights reserved.
27 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
28 * Copyright (c) 2015 by Delphix. All rights reserved.
32 * bootadm(1M) is a new utility for managing bootability of
33 * Solaris *Newboot* environments. It has two primary tasks:
34 * - Allow end users to manage bootability of Newboot Solaris instances
35 * - Provide services to other subsystems in Solaris (primarily Install)
44 #include <sys/types.h>
51 #include <sys/mnttab.h>
52 #include <sys/mntent.h>
53 #include <sys/statvfs.h>
54 #include <libnvpair.h>
59 #include <sys/systeminfo.h>
60 #include <sys/dktp/fdisk.h>
61 #include <sys/param.h>
65 #include <sys/sysmacros.h>
69 #include <sys/lockfs.h>
70 #include <sys/filio.h>
77 #include <sys/ucode.h>
82 #include <device_info.h>
84 #include <sys/efi_partition.h>
87 #include <sys/mkdev.h>
93 #define TEXT_DOMAIN "SUNW_OST_OSCMD"
94 #endif /* TEXT_DOMAIN */
96 /* Type definitions */
106 OPT_ABSENT
= 0, /* No option */
107 OPT_REQ
, /* option required */
108 OPT_OPTIONAL
/* option may or may not be present */
114 error_t (*handler
)();
115 int unpriv
; /* is this an unprivileged command */
118 #define LINE_INIT 0 /* lineNum initial value */
119 #define ENTRY_INIT -1 /* entryNum initial value */
120 #define ALL_ENTRIES -2 /* selects all boot entries */
122 #define PARTNO_NOTFOUND -1 /* Solaris partition not found */
123 #define PARTNO_EFI -2 /* EFI partition table found */
125 #define GRUB_DIR "/boot/grub"
126 #define GRUB_STAGE2 GRUB_DIR "/stage2"
127 #define GRUB_MENU "/boot/grub/menu.lst"
128 #define MENU_TMP "/boot/grub/menu.lst.tmp"
129 #define GRUB_BACKUP_MENU "/etc/lu/GRUB_backup_menu"
130 #define RAMDISK_SPECIAL "/dev/ramdisk/"
131 #define STUBBOOT "/stubboot"
132 #define MULTIBOOT "/platform/i86pc/multiboot"
133 #define GRUBSIGN_DIR "/boot/grub/bootsign"
134 #define GRUBSIGN_BACKUP "/etc/bootsign"
135 #define GRUBSIGN_UFS_PREFIX "rootfs"
136 #define GRUBSIGN_ZFS_PREFIX "pool_"
137 #define GRUBSIGN_LU_PREFIX "BE_"
138 #define UFS_SIGNATURE_LIST "/var/run/grub_ufs_signatures"
139 #define ZFS_LEGACY_MNTPT "/tmp/bootadm_mnt_zfs_legacy"
141 #define BOOTADM_RDONLY_TEST "BOOTADM_RDONLY_TEST"
144 #define BAM_LOCK_FILE "/var/run/bootadm.lock"
145 #define LOCK_FILE_PERMS (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
147 #define CREATE_RAMDISK "boot/solaris/bin/create_ramdisk"
148 #define CREATE_DISKMAP "boot/solaris/bin/create_diskmap"
149 #define EXTRACT_BOOT_FILELIST "boot/solaris/bin/extract_boot_filelist"
150 #define GRUBDISK_MAP "/var/run/solaris_grubdisk.map"
152 #define GRUB_slice "/etc/lu/GRUB_slice"
153 #define GRUB_root "/etc/lu/GRUB_root"
154 #define GRUB_fdisk "/etc/lu/GRUB_fdisk"
155 #define GRUB_fdisk_target "/etc/lu/GRUB_fdisk_target"
156 #define FINDROOT_INSTALLGRUB "/etc/lu/installgrub.findroot"
157 #define LULIB "/usr/lib/lu/lulib"
158 #define LULIB_PROPAGATE_FILE "lulib_propagate_file"
159 #define CKSUM "/usr/bin/cksum"
160 #define LU_MENU_CKSUM "/etc/lu/menu.cksum"
161 #define BOOTADM "/sbin/bootadm"
163 #define INSTALLGRUB "/sbin/installgrub"
164 #define STAGE1 "/boot/grub/stage1"
165 #define STAGE2 "/boot/grub/stage2"
167 typedef enum zfs_mnted
{
176 * Default file attributes
178 #define DEFAULT_DEV_MODE 0644 /* default permissions */
179 #define DEFAULT_DEV_UID 0 /* user root */
180 #define DEFAULT_DEV_GID 3 /* group sys */
184 * menu_cmd_t and menu_cmds must be kept in sync
186 char *menu_cmds
[] = {
187 "default", /* DEFAULT_CMD */
188 "timeout", /* TIMEOUT_CMD */
189 "title", /* TITLE_CMD */
190 "root", /* ROOT_CMD */
191 "kernel", /* KERNEL_CMD */
192 "kernel$", /* KERNEL_DOLLAR_CMD */
193 "module", /* MODULE_CMD */
194 "module$", /* MODULE_DOLLAR_CMD */
196 "#", /* COMMENT_CMD */
197 "chainloader", /* CHAINLOADER_CMD */
198 "args", /* ARGS_CMD */
199 "findroot", /* FINDROOT_CMD */
200 "bootfs", /* BOOTFS_CMD */
204 #define OPT_ENTRY_NUM "entry"
214 #define BOOT_FILE_LIST "boot/solaris/filelist.ramdisk"
215 #define ETC_FILE_LIST "etc/boot/solaris/filelist.ramdisk"
217 #define FILE_STAT "boot/solaris/filestat.ramdisk"
218 #define FILE_STAT_TMP "boot/solaris/filestat.ramdisk.tmp"
219 #define DIR_PERMS (S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
220 #define FILE_STAT_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
222 #define FILE_STAT_TIMESTAMP "boot/solaris/timestamp.cache"
229 static subcmd_t bam_cmd
;
230 static char *bam_root
;
231 static int bam_rootlen
;
232 static int bam_root_readonly
;
233 static int bam_alt_root
;
234 static int bam_extend
= 0;
235 static int bam_purge
= 0;
236 static char *bam_subcmd
;
237 static char *bam_opt
;
238 static char **bam_argv
;
239 static char *bam_pool
;
241 static int bam_check
;
242 static int bam_saved_check
;
243 static int bam_smf_check
;
244 static int bam_lock_fd
= -1;
247 static char rootbuf
[PATH_MAX
] = "/";
248 static int bam_update_all
;
249 static int bam_alt_platform
;
250 static char *bam_platform
;
251 static char *bam_home_env
= NULL
;
253 /* function prototypes */
254 static void parse_args_internal(int, char *[]);
255 static void parse_args(int, char *argv
[]);
256 static error_t
bam_menu(char *, char *, int, char *[]);
257 static error_t
bam_install(char *, char *);
258 static error_t
bam_archive(char *, char *);
260 static void bam_lock(void);
261 static void bam_unlock(void);
263 static int exec_cmd(char *, filelist_t
*);
264 static error_t
read_globals(menu_t
*, char *, char *, int);
265 static int menu_on_bootdisk(char *os_root
, char *menu_root
);
266 static menu_t
*menu_read(char *);
267 static error_t
menu_write(char *, menu_t
*);
268 static void linelist_free(line_t
*);
269 static void menu_free(menu_t
*);
270 static void filelist_free(filelist_t
*);
271 static error_t
list2file(char *, char *, char *, line_t
*);
272 static error_t
list_entry(menu_t
*, char *, char *);
273 static error_t
list_setting(menu_t
*, char *, char *);
274 static error_t
delete_all_entries(menu_t
*, char *, char *);
275 static error_t
update_entry(menu_t
*mp
, char *menu_root
, char *opt
);
276 static error_t
update_temp(menu_t
*mp
, char *dummy
, char *opt
);
278 static error_t
install_bootloader(void);
279 static error_t
update_archive(char *, char *);
280 static error_t
list_archive(char *, char *);
281 static error_t
update_all(char *, char *);
282 static error_t
read_list(char *, filelist_t
*);
283 static error_t
set_option(menu_t
*, char *, char *);
284 static error_t
set_kernel(menu_t
*, menu_cmd_t
, char *, char *, size_t);
285 static error_t
get_kernel(menu_t
*, menu_cmd_t
, char *, size_t);
286 static char *expand_path(const char *);
288 static long s_strtol(char *);
289 static int s_fputs(char *, FILE *);
291 static int is_zfs(char *root
);
292 static int is_ufs(char *root
);
293 static int is_pcfs(char *root
);
294 static int is_amd64(void);
295 static char *get_machine(void);
296 static void append_to_flist(filelist_t
*, char *);
297 static char *mount_top_dataset(char *pool
, zfs_mnted_t
*mnted
);
298 static int umount_top_dataset(char *pool
, zfs_mnted_t mnted
, char *mntpt
);
299 static int ufs_add_to_sign_list(char *sign
);
300 static error_t
synchronize_BE_menu(void);
303 static void ucode_install();
306 /* Menu related sub commands */
307 static subcmd_defn_t menu_subcmds
[] = {
308 "set_option", OPT_ABSENT
, set_option
, 0, /* PUB */
309 "list_entry", OPT_OPTIONAL
, list_entry
, 1, /* PUB */
310 "delete_all_entries", OPT_ABSENT
, delete_all_entries
, 0, /* PVT */
311 "update_entry", OPT_REQ
, update_entry
, 0, /* menu */
312 "update_temp", OPT_OPTIONAL
, update_temp
, 0, /* reboot */
313 "upgrade", OPT_ABSENT
, upgrade_menu
, 0, /* menu */
314 "list_setting", OPT_OPTIONAL
, list_setting
, 1, /* menu */
315 "disable_hypervisor", OPT_ABSENT
, cvt_to_metal
, 0, /* menu */
316 "enable_hypervisor", OPT_ABSENT
, cvt_to_hyper
, 0, /* menu */
317 NULL
, 0, NULL
, 0 /* must be last */
320 /* Archive related sub commands */
321 static subcmd_defn_t arch_subcmds
[] = {
322 "update", OPT_ABSENT
, update_archive
, 0, /* PUB */
323 "update_all", OPT_ABSENT
, update_all
, 0, /* PVT */
324 "list", OPT_OPTIONAL
, list_archive
, 1, /* PUB */
325 NULL
, 0, NULL
, 0 /* must be last */
328 /* Install related sub commands */
329 static subcmd_defn_t inst_subcmds
[] = {
330 "install_bootloader", OPT_ABSENT
, install_bootloader
, 0, /* PUB */
331 NULL
, 0, NULL
, 0 /* must be last */
334 enum dircache_copy_opt
{
341 * Directory specific flags:
342 * NEED_UPDATE : the specified archive needs to be updated
343 * NO_MULTI : don't extend the specified archive, but recreate it
345 #define NEED_UPDATE 0x00000001
346 #define NO_MULTI 0x00000002
348 #define set_dir_flag(id, f) (walk_arg.dirinfo[id].flags |= f)
349 #define unset_dir_flag(id, f) (walk_arg.dirinfo[id].flags &= ~f)
350 #define is_dir_flag_on(id, f) (walk_arg.dirinfo[id].flags & f ? 1 : 0)
352 #define get_cachedir(id) (walk_arg.dirinfo[id].cdir_path)
353 #define get_updatedir(id) (walk_arg.dirinfo[id].update_path)
354 #define get_count(id) (walk_arg.dirinfo[id].count)
355 #define has_cachedir(id) (walk_arg.dirinfo[id].has_dir)
356 #define set_dir_present(id) (walk_arg.dirinfo[id].has_dir = 1)
359 * dirinfo_t (specific cache directory information):
360 * cdir_path: path to the archive cache directory
361 * update_path: path to the update directory (contains the files that will be
362 * used to extend the archive)
363 * has_dir: the specified cache directory is active
364 * count: the number of files to update
365 * flags: directory specific flags
367 typedef struct _dirinfo
{
368 char cdir_path
[PATH_MAX
];
369 char update_path
[PATH_MAX
];
377 * NEED_CACHE_DIR : cache directory is missing and needs to be created
378 * IS_SPARC_TARGET : the target mountpoint is a SPARC environment
379 * UPDATE_ERROR : an error occourred while traversing the list of files
380 * RDONLY_FSCHK : the target filesystem is read-only
381 * RAMDSK_FSCHK : the target filesystem is on a ramdisk
383 #define NEED_CACHE_DIR 0x00000001
384 #define IS_SPARC_TARGET 0x00000002
385 #define UPDATE_ERROR 0x00000004
386 #define RDONLY_FSCHK 0x00000008
387 #define INVALIDATE_CACHE 0x00000010
389 #define is_flag_on(flag) (walk_arg.update_flags & flag ? 1 : 0)
390 #define set_flag(flag) (walk_arg.update_flags |= flag)
391 #define unset_flag(flag) (walk_arg.update_flags &= ~flag)
395 * update_flags: flags related to the current updating process
396 * new_nvlp/old_nvlp: new and old list of archive-files / attributes pairs
397 * sparcfile: list of file paths for mkisofs -path-list (SPARC only)
404 dirinfo_t dirinfo
[CACHEDIR_NUM
];
409 struct safefile
*next
;
412 static struct safefile
*safefiles
= NULL
;
415 * svc:/system/filesystem/usr:default service checks for this file and
416 * does a boot archive update and then reboot the system.
418 #define NEED_UPDATE_FILE "/etc/svc/volatile/boot_archive_needs_update"
421 * svc:/system/boot-archive-update:default checks for this file and
422 * updates the boot archive.
424 #define NEED_UPDATE_SAFE_FILE "/etc/svc/volatile/boot_archive_safefile_update"
426 /* Thanks growisofs */
427 #define CD_BLOCK ((off64_t)2048)
428 #define VOLDESC_OFF 16
429 #define DVD_BLOCK (32*1024)
433 unsigned char type
[1];
434 unsigned char id
[5];
435 unsigned char void1
[80-5-1];
436 unsigned char volume_space_size
[8];
437 unsigned char void2
[2048-80-8];
441 * COUNT_MAX: maximum number of changed files to justify a multisession update
442 * BA_SIZE_MAX: maximum size of the boot_archive to justify a multisession
446 #define BA_SIZE_MAX (50 * 1024 * 1024)
448 #define bam_nowrite() (bam_check || bam_smf_check)
450 static int sync_menu
= 1; /* whether we need to sync the BE menus */
455 (void) fprintf(stderr
, "USAGE:\n");
458 (void) fprintf(stderr
,
459 "\t%s update-archive [-vn] [-R altroot [-p platform]]\n", prog
);
460 (void) fprintf(stderr
,
461 "\t%s list-archive [-R altroot [-p platform]]\n", prog
);
463 (void) fprintf(stderr
,
464 "\t%s install-bootloader [-fv] [-R altroot] [-P pool]\n", prog
);
466 (void) fprintf(stderr
,
467 "\t%s install-bootloader [-Mfv] [-R altroot] [-P pool]\n", prog
);
471 (void) fprintf(stderr
, "\t%s set-menu [-R altroot] key=value\n", prog
);
472 (void) fprintf(stderr
, "\t%s list-menu [-R altroot]\n", prog
);
477 * Best effort attempt to restore the $HOME value.
482 char home_env
[PATH_MAX
];
485 (void) snprintf(home_env
, sizeof (home_env
), "HOME=%s",
487 (void) putenv(home_env
);
496 * Sanitize the environment in which bootadm will execute its sub-processes
497 * (ex. mkisofs). This is done to prevent those processes from attempting
498 * to access files (ex. .mkisofsrc) or stat paths that might be on NFS
499 * or, potentially, insecure.
506 /* don't depend on caller umask */
509 /* move away from a potential unsafe current working directory */
510 while (chdir("/") == -1) {
511 if (errno
!= EINTR
) {
512 bam_print("WARNING: unable to chdir to /");
517 bam_home_env
= getenv("HOME");
518 while (bam_home_env
!= NULL
&& putenv("HOME=/") == -1) {
519 if (errno
== ENOMEM
) {
520 /* retry no more than MAX_TRIES times */
521 if (++stry
> MAX_TRIES
) {
522 bam_print("WARNING: unable to recover from "
523 "system memory pressure... aborting \n");
524 bam_exit(EXIT_FAILURE
);
526 /* memory is tight, try to sleep */
527 bam_print("Attempting to recover from memory pressure: "
528 "sleeping for %d seconds\n", SLEEP_TIME
* stry
);
529 (void) sleep(SLEEP_TIME
* stry
);
531 bam_print("WARNING: unable to sanitize HOME\n");
537 main(int argc
, char *argv
[])
539 error_t ret
= BAM_SUCCESS
;
541 (void) setlocale(LC_ALL
, "");
542 (void) textdomain(TEXT_DOMAIN
);
544 if ((prog
= strrchr(argv
[0], '/')) == NULL
) {
550 INJECT_ERROR1("ASSERT_ON", assert(0))
554 parse_args(argc
, argv
);
558 ret
= bam_menu(bam_subcmd
, bam_opt
, bam_argc
, bam_argv
);
561 ret
= bam_archive(bam_subcmd
, bam_opt
);
564 ret
= bam_install(bam_subcmd
, bam_opt
);
571 if (ret
!= BAM_SUCCESS
)
572 bam_exit((ret
== BAM_NOCHANGE
) ? 2 : 1);
579 * Equivalence of public and internal commands:
580 * update-archive -- -a update
581 * list-archive -- -a list
582 * set-menu -- -m set_option
583 * list-menu -- -m list_entry
584 * update-menu -- -m update_entry
585 * install-bootloader -- -i install_bootloader
587 static struct cmd_map
{
592 { "update-archive", BAM_ARCHIVE
, "update"},
593 { "list-archive", BAM_ARCHIVE
, "list"},
594 { "set-menu", BAM_MENU
, "set_option"},
595 { "list-menu", BAM_MENU
, "list_entry"},
596 { "update-menu", BAM_MENU
, "update_entry"},
597 { "install-bootloader", BAM_INSTALL
, "install_bootloader"},
602 * Commands syntax published in bootadm(1M) are parsed here
605 parse_args(int argc
, char *argv
[])
607 struct cmd_map
*cmp
= cmd_map
;
609 /* command conforming to the final spec */
610 if (argc
> 1 && argv
[1][0] != '-') {
612 * Map commands to internal table.
614 while (cmp
->bam_cmdname
) {
615 if (strcmp(argv
[1], cmp
->bam_cmdname
) == 0) {
616 bam_cmd
= cmp
->bam_cmd
;
617 bam_subcmd
= cmp
->bam_subcmd
;
622 if (cmp
->bam_cmdname
== NULL
) {
630 parse_args_internal(argc
, argv
);
634 * A combination of public and private commands are parsed here.
635 * The internal syntax and the corresponding functionality are:
636 * -a update -- update-archive
637 * -a list -- list-archive
638 * -a update-all -- (reboot to sync all mnted OS archive)
639 * -i install_bootloader -- install-bootloader
640 * -m update_entry -- update-menu
641 * -m list_entry -- list-menu
642 * -m update_temp -- (reboot -- [boot-args])
643 * -m delete_all_entries -- (called from install)
644 * -m enable_hypervisor [args] -- cvt_to_hyper
645 * -m disable_hypervisor -- cvt_to_metal
646 * -m list_setting [entry] [value] -- list_setting
648 * A set of private flags is there too:
649 * -F -- purge the cache directories and rebuild them
650 * -e -- use the (faster) archive update approach (used by
654 parse_args_internal(int argc
, char *argv
[])
658 extern int optind
, opterr
;
660 const char *optstring
= "a:d:fi:m:no:veFCR:p:P:XZ";
662 const char *optstring
= "a:d:fi:m:no:veFCMR:p:P:XZ";
665 /* Suppress error message from getopt */
669 while ((c
= getopt(argc
, argv
, optstring
)) != -1) {
674 bam_error(MULT_CMDS
, c
);
676 bam_cmd
= BAM_ARCHIVE
;
682 bam_error(DUP_OPT
, c
);
684 bam_debug
= s_strtol(optarg
);
695 bam_error(MULT_CMDS
, c
);
697 bam_cmd
= BAM_INSTALL
;
703 bam_error(MULT_CMDS
, c
);
716 * We save the original value of bam_check. The new
717 * approach in case of a read-only filesystem is to
718 * behave as a check, so we need a way to restore the
719 * original value after the evaluation of the read-only
720 * filesystem has been done.
721 * Even if we don't allow at the moment a check with
722 * update_all, this approach is more robust than
723 * simply resetting bam_check to zero.
730 bam_error(DUP_OPT
, c
);
741 if (bam_pool
!= NULL
) {
743 bam_error(DUP_OPT
, c
);
750 bam_error(DUP_OPT
, c
);
752 } else if (realpath(optarg
, rootbuf
) == NULL
) {
754 bam_error(CANT_RESOLVE
, optarg
,
760 bam_rootlen
= strlen(rootbuf
);
763 bam_alt_platform
= 1;
764 bam_platform
= optarg
;
765 if ((strcmp(bam_platform
, "i86pc") != 0) &&
766 (strcmp(bam_platform
, "sun4u") != 0) &&
767 (strcmp(bam_platform
, "sun4v") != 0)) {
769 bam_error(INVALID_PLAT
, bam_platform
);
773 bam_is_hv
= BAM_HV_PRESENT
;
783 bam_error(BAD_OPT
, optopt
);
787 bam_error(BAD_OPT
, c
);
793 * An alternate platform requires an alternate root
795 if (bam_alt_platform
&& bam_alt_root
== 0) {
801 * A command option must be specfied
804 if (bam_opt
&& strcmp(bam_opt
, "all") == 0) {
818 bam_error(INT_ERROR
, "parse_args");
820 } else if (optind
< argc
) {
821 bam_argv
= &argv
[optind
];
822 bam_argc
= argc
- optind
;
826 * mbr and pool are options for install_bootloader
828 if (bam_cmd
!= BAM_INSTALL
&& (bam_mbr
|| bam_pool
!= NULL
)) {
834 * -n implies verbose mode
841 check_subcmd_and_options(
844 subcmd_defn_t
*table
,
849 if (subcmd
== NULL
) {
850 bam_error(NEED_SUBCMD
);
854 if (strcmp(subcmd
, "set_option") == 0) {
855 if (bam_argc
== 0 || bam_argv
== NULL
|| bam_argv
[0] == NULL
) {
856 bam_error(MISSING_ARG
);
859 } else if (bam_argc
> 1 || bam_argv
[1] != NULL
) {
860 bam_error(TRAILING_ARGS
);
864 } else if (strcmp(subcmd
, "update_all") == 0) {
866 * The only option we accept for the "update_all"
867 * subcmd is "fastboot".
869 if (bam_argc
> 1 || (bam_argc
== 1 &&
870 strcmp(bam_argv
[0], "fastboot") != 0)) {
871 bam_error(TRAILING_ARGS
);
877 } else if (((strcmp(subcmd
, "enable_hypervisor") != 0) &&
878 (strcmp(subcmd
, "list_setting") != 0)) && (bam_argc
|| bam_argv
)) {
880 * Of the remaining subcommands, only "enable_hypervisor" and
881 * "list_setting" take trailing arguments.
883 bam_error(TRAILING_ARGS
);
888 if (bam_root
== NULL
) {
893 /* verify that subcmd is valid */
894 for (i
= 0; table
[i
].subcmd
!= NULL
; i
++) {
895 if (strcmp(table
[i
].subcmd
, subcmd
) == 0)
899 if (table
[i
].subcmd
== NULL
) {
900 bam_error(INVALID_SUBCMD
, subcmd
);
904 if (table
[i
].unpriv
== 0 && geteuid() != 0) {
905 bam_error(MUST_BE_ROOT
);
910 * Currently only privileged commands need a lock
912 if (table
[i
].unpriv
== 0)
915 /* subcmd verifies that opt is appropriate */
916 if (table
[i
].option
!= OPT_OPTIONAL
) {
917 if ((table
[i
].option
== OPT_REQ
) ^ (opt
!= NULL
)) {
919 bam_error(NO_OPT_REQ
, subcmd
);
921 bam_error(MISS_OPT
, subcmd
);
926 *fp
= table
[i
].handler
;
928 return (BAM_SUCCESS
);
932 * NOTE: A single "/" is also considered a trailing slash and will
936 elide_trailing_slash(const char *src
, char *dst
, size_t dstsize
)
943 (void) strlcpy(dst
, src
, dstsize
);
945 dstlen
= strlen(dst
);
946 if (dst
[dstlen
- 1] == '/') {
947 dst
[dstlen
- 1] = '\0';
952 is_safe_exec(char *path
)
956 if (lstat(path
, &sb
) != 0) {
957 bam_error(STAT_FAIL
, path
, strerror(errno
));
961 if (!S_ISREG(sb
.st_mode
)) {
962 bam_error(PATH_EXEC_LINK
, path
);
966 if (sb
.st_uid
!= getuid()) {
967 bam_error(PATH_EXEC_OWNER
, path
, getuid());
971 if (sb
.st_mode
& S_IWOTH
|| sb
.st_mode
& S_IWGRP
) {
972 bam_error(PATH_EXEC_PERMS
, path
);
976 return (BAM_SUCCESS
);
980 list_setting(menu_t
*mp
, char *which
, char *setting
)
993 if (*which
!= NULL
) {
995 * If "which" is not a number, assume it's a setting we want
996 * to look for and so set up the routine to look for "which"
997 * in the default entry.
1000 if (!(isdigit((int)*p
++))) {
1002 which
= mp
->curdefault
->arg
;
1006 which
= mp
->curdefault
->arg
;
1009 entry
= atoi(which
);
1011 for (ent
= mp
->entries
; ((ent
!= NULL
) && (ent
->entryNum
!= entry
));
1016 bam_error(NO_MATCH_ENTRY
);
1020 found
= (*setting
== NULL
);
1022 for (lp
= ent
->start
; lp
!= NULL
; lp
= lp
->next
) {
1023 if ((*setting
== NULL
) && (lp
->flags
!= BAM_COMMENT
))
1024 bam_print(PRINT
, lp
->line
);
1025 else if (lp
->cmd
!= NULL
&& strcmp(setting
, lp
->cmd
) == 0) {
1026 bam_print(PRINT
, lp
->arg
);
1035 bam_error(NO_MATCH_ENTRY
);
1039 return (BAM_SUCCESS
);
1043 install_bootloader(void)
1048 struct extmnttab mnt
;
1049 struct stat statbuf
= {0};
1050 be_node_list_t
*be_nodes
, *node
;
1052 char *root_ds
= NULL
;
1053 int ret
= BAM_ERROR
;
1055 if (nvlist_alloc(&nvl
, NV_UNIQUE_NAME
, 0) != 0) {
1056 bam_error(_("out of memory\n"));
1061 * if bam_alt_root is set, the stage files are used from alt root.
1062 * if pool is set, the target devices are pool devices, stage files
1063 * are read from pool bootfs unless alt root is set.
1065 * use arguments as targets, stage files are from alt or current root
1066 * if no arguments and no pool, install on current boot pool.
1070 if (stat(bam_root
, &statbuf
) != 0) {
1071 bam_error(STAT_FAIL
, bam_root
, strerror(errno
));
1074 if ((fp
= fopen(MNTTAB
, "r")) == NULL
) {
1075 bam_error(OPEN_FAIL
, MNTTAB
, strerror(errno
));
1079 while (getextmntent(fp
, &mnt
, sizeof (mnt
)) == 0) {
1080 if (mnt
.mnt_major
== major(statbuf
.st_dev
) &&
1081 mnt
.mnt_minor
== minor(statbuf
.st_dev
)) {
1083 root_ds
= strdup(mnt
.mnt_special
);
1090 bam_error(NOT_IN_MNTTAB
, bam_root
);
1093 if (root_ds
== NULL
) {
1094 bam_error(_("out of memory\n"));
1098 if (be_list(NULL
, &be_nodes
) != BE_SUCCESS
) {
1099 bam_error(_("No BE's found\n"));
1102 for (node
= be_nodes
; node
!= NULL
; node
= node
->be_next_node
)
1103 if (strcmp(root_ds
, node
->be_root_ds
) == 0)
1107 bam_error(_("BE (%s) does not exist\n"), root_ds
);
1112 be_free_list(be_nodes
);
1115 ret
= nvlist_add_string(nvl
, BE_ATTR_ORIG_BE_NAME
,
1116 node
->be_node_name
);
1117 ret
|= nvlist_add_string(nvl
, BE_ATTR_ORIG_BE_ROOT
,
1119 be_free_list(be_nodes
);
1127 flags
|= BE_INSTALLBOOT_FLAG_FORCE
;
1129 flags
|= BE_INSTALLBOOT_FLAG_MBR
;
1131 flags
|= BE_INSTALLBOOT_FLAG_VERBOSE
;
1133 if (nvlist_add_uint16(nvl
, BE_ATTR_INSTALL_FLAGS
, flags
) != 0) {
1134 bam_error(_("out of memory\n"));
1140 * if altroot was set, we got be name and be root, only need
1141 * to set pool name as target.
1142 * if no altroot, need to find be name and root from pool.
1144 if (bam_pool
!= NULL
) {
1145 ret
= nvlist_add_string(nvl
, BE_ATTR_ORIG_BE_POOL
, bam_pool
);
1151 ret
= be_installboot(nvl
);
1158 if (be_list(NULL
, &be_nodes
) != BE_SUCCESS
) {
1159 bam_error(_("No BE's found\n"));
1164 if (bam_pool
!= NULL
) {
1166 * find active be_node in bam_pool
1168 for (node
= be_nodes
; node
!= NULL
; node
= node
->be_next_node
) {
1169 if (strcmp(bam_pool
, node
->be_rpool
) != 0)
1171 if (node
->be_active_on_boot
)
1175 bam_error(_("No active BE in %s\n"), bam_pool
);
1176 be_free_list(be_nodes
);
1180 ret
= nvlist_add_string(nvl
, BE_ATTR_ORIG_BE_NAME
,
1181 node
->be_node_name
);
1182 ret
|= nvlist_add_string(nvl
, BE_ATTR_ORIG_BE_ROOT
,
1184 be_free_list(be_nodes
);
1189 ret
= be_installboot(nvl
);
1196 * get dataset for "/" and fill up the args.
1198 if ((fp
= fopen(MNTTAB
, "r")) == NULL
) {
1199 bam_error(OPEN_FAIL
, MNTTAB
, strerror(errno
));
1201 be_free_list(be_nodes
);
1206 while (getextmntent(fp
, &mnt
, sizeof (mnt
)) == 0) {
1207 if (strcmp(mnt
.mnt_mountp
, "/") == 0) {
1209 root_ds
= strdup(mnt
.mnt_special
);
1216 bam_error(NOT_IN_MNTTAB
, "/");
1218 be_free_list(be_nodes
);
1221 if (root_ds
== NULL
) {
1222 bam_error(_("out of memory\n"));
1224 be_free_list(be_nodes
);
1228 for (node
= be_nodes
; node
!= NULL
; node
= node
->be_next_node
) {
1229 if (strcmp(root_ds
, node
->be_root_ds
) == 0)
1234 bam_error(_("No such BE: %s\n"), root_ds
);
1236 be_free_list(be_nodes
);
1242 ret
= nvlist_add_string(nvl
, BE_ATTR_ORIG_BE_NAME
, node
->be_node_name
);
1243 ret
|= nvlist_add_string(nvl
, BE_ATTR_ORIG_BE_ROOT
, node
->be_root_ds
);
1244 ret
|= nvlist_add_string(nvl
, BE_ATTR_ORIG_BE_POOL
, node
->be_rpool
);
1245 be_free_list(be_nodes
);
1250 ret
= be_installboot(nvl
) ? BAM_ERROR
: 0;
1258 bam_install(char *subcmd
, char *opt
)
1265 if (check_subcmd_and_options(subcmd
, opt
, inst_subcmds
, &f
) ==
1273 bam_menu(char *subcmd
, char *opt
, int largc
, char *largv
[])
1276 char menu_path
[PATH_MAX
];
1277 char clean_menu_root
[PATH_MAX
];
1278 char path
[PATH_MAX
];
1280 char menu_root
[PATH_MAX
];
1282 error_t (*f
)(menu_t
*mp
, char *menu_path
, char *opt
);
1283 char *special
= NULL
;
1286 char *zmntpt
= NULL
;
1289 const char *fcn
= "bam_menu()";
1292 * Menu sub-command only applies to GRUB (i.e. x86)
1294 if (!is_grub(bam_alt_root
? bam_root
: "/")) {
1295 bam_error(NOT_GRUB_BOOT
);
1302 ret
= check_subcmd_and_options(subcmd
, opt
, menu_subcmds
, &f
);
1303 if (ret
== BAM_ERROR
) {
1309 (void) strlcpy(menu_root
, bam_root
, sizeof (menu_root
));
1310 osdev
= osroot
= NULL
;
1312 if (strcmp(subcmd
, "update_entry") == 0) {
1315 osdev
= strtok(opt
, ",");
1317 osroot
= strtok(NULL
, ",");
1319 /* fixup bam_root so that it points at osroot */
1320 if (realpath(osroot
, rootbuf
) == NULL
) {
1321 bam_error(CANT_RESOLVE
, osroot
,
1327 bam_rootlen
= strlen(rootbuf
);
1332 * We support menu on PCFS (under certain conditions), but
1335 if (is_pcfs(bam_root
)) {
1336 bam_error(PCFS_ROOT_NOTSUP
, bam_root
);
1340 if (stat(menu_root
, &sb
) == -1) {
1341 bam_error(CANNOT_LOCATE_GRUB_MENU
);
1345 BAM_DPRINTF((D_MENU_ROOT
, fcn
, menu_root
));
1348 * We no longer use the GRUB slice file. If it exists, then
1349 * the user is doing something that is unsupported (such as
1350 * standard upgrading an old Live Upgrade BE). If that
1351 * happens, mimic existing behavior i.e. pretend that it is
1352 * not a BE. Emit a warning though.
1355 (void) snprintf(path
, sizeof (path
), "%s%s", bam_root
,
1358 (void) snprintf(path
, sizeof (path
), "%s", GRUB_slice
);
1361 if (bam_verbose
&& stat(path
, &sb
) == 0)
1362 bam_error(GRUB_SLICE_FILE_EXISTS
, path
);
1364 if (is_zfs(menu_root
)) {
1365 assert(strcmp(menu_root
, bam_root
) == 0);
1366 special
= get_special(menu_root
);
1367 INJECT_ERROR1("Z_MENU_GET_SPECIAL", special
= NULL
);
1368 if (special
== NULL
) {
1369 bam_error(CANT_FIND_SPECIAL
, menu_root
);
1372 pool
= strtok(special
, "/");
1373 INJECT_ERROR1("Z_MENU_GET_POOL", pool
= NULL
);
1376 bam_error(CANT_FIND_POOL
, menu_root
);
1379 BAM_DPRINTF((D_Z_MENU_GET_POOL_FROM_SPECIAL
, fcn
, pool
));
1381 zmntpt
= mount_top_dataset(pool
, &zmnted
);
1382 INJECT_ERROR1("Z_MENU_MOUNT_TOP_DATASET", zmntpt
= NULL
);
1383 if (zmntpt
== NULL
) {
1384 bam_error(CANT_MOUNT_POOL_DATASET
, pool
);
1388 BAM_DPRINTF((D_Z_GET_MENU_MOUNT_TOP_DATASET
, fcn
, zmntpt
));
1390 (void) strlcpy(menu_root
, zmntpt
, sizeof (menu_root
));
1391 BAM_DPRINTF((D_Z_GET_MENU_MENU_ROOT
, fcn
, menu_root
));
1394 elide_trailing_slash(menu_root
, clean_menu_root
,
1395 sizeof (clean_menu_root
));
1397 BAM_DPRINTF((D_CLEAN_MENU_ROOT
, fcn
, clean_menu_root
));
1399 (void) strlcpy(menu_path
, clean_menu_root
, sizeof (menu_path
));
1400 (void) strlcat(menu_path
, GRUB_MENU
, sizeof (menu_path
));
1402 BAM_DPRINTF((D_MENU_PATH
, fcn
, menu_path
));
1405 * If listing the menu, display the menu location
1407 if (strcmp(subcmd
, "list_entry") == 0)
1408 bam_print(GRUB_MENU_PATH
, menu_path
);
1410 if ((menu
= menu_read(menu_path
)) == NULL
) {
1411 bam_error(CANNOT_LOCATE_GRUB_MENU_FILE
, menu_path
);
1418 * We already checked the following case in
1419 * check_subcmd_and_suboptions() above. Complete the
1422 if (strcmp(subcmd
, "set_option") == 0) {
1423 assert(largc
== 1 && largv
[0] && largv
[1] == NULL
);
1425 } else if ((strcmp(subcmd
, "enable_hypervisor") != 0) &&
1426 (strcmp(subcmd
, "list_setting") != 0)) {
1427 assert(largc
== 0 && largv
== NULL
);
1430 ret
= get_boot_cap(bam_root
);
1431 if (ret
!= BAM_SUCCESS
) {
1432 BAM_DPRINTF((D_BOOT_GET_CAP_FAILED
, fcn
));
1437 * Once the sub-cmd handler has run
1438 * only the line field is guaranteed to have valid values
1440 if (strcmp(subcmd
, "update_entry") == 0) {
1441 ret
= f(menu
, menu_root
, osdev
);
1442 } else if (strcmp(subcmd
, "upgrade") == 0) {
1443 ret
= f(menu
, bam_root
, menu_root
);
1444 } else if (strcmp(subcmd
, "list_entry") == 0) {
1445 ret
= f(menu
, menu_path
, opt
);
1446 } else if (strcmp(subcmd
, "list_setting") == 0) {
1447 ret
= f(menu
, ((largc
> 0) ? largv
[0] : ""),
1448 ((largc
> 1) ? largv
[1] : ""));
1449 } else if (strcmp(subcmd
, "disable_hypervisor") == 0) {
1451 bam_error(NO_SPARC
, subcmd
);
1454 ret
= f(menu
, bam_root
, NULL
);
1456 } else if (strcmp(subcmd
, "enable_hypervisor") == 0) {
1458 bam_error(NO_SPARC
, subcmd
);
1461 char *extra_args
= NULL
;
1464 * Compress all arguments passed in the largv[] array
1465 * into one string that can then be appended to the
1466 * end of the kernel$ string the routine to enable the
1467 * hypervisor will build.
1469 * This allows the caller to supply arbitrary unparsed
1470 * arguments, such as dom0 memory settings or APIC
1473 * This concatenation will be done without ANY syntax
1474 * checking whatsoever, so it's the responsibility of
1475 * the caller to make sure the arguments are valid and
1476 * do not duplicate arguments the conversion routines
1482 for (extra_len
= 0, i
= 0; i
< largc
; i
++)
1483 extra_len
+= strlen(largv
[i
]);
1486 * Allocate space for argument strings,
1487 * intervening spaces and terminating NULL.
1489 extra_args
= alloca(extra_len
+ largc
);
1491 (void) strcpy(extra_args
, largv
[0]);
1493 for (i
= 1; i
< largc
; i
++) {
1494 (void) strcat(extra_args
, " ");
1495 (void) strcat(extra_args
, largv
[i
]);
1499 ret
= f(menu
, bam_root
, extra_args
);
1502 ret
= f(menu
, NULL
, opt
);
1504 if (ret
== BAM_WRITE
) {
1505 BAM_DPRINTF((D_WRITING_MENU_ROOT
, fcn
, clean_menu_root
));
1506 ret
= menu_write(clean_menu_root
, menu
);
1510 INJECT_ERROR1("POOL_SET", pool
= "/pooldata");
1511 assert((is_zfs(menu_root
)) ^ (pool
== NULL
));
1513 (void) umount_top_dataset(pool
, zmnted
, zmntpt
);
1527 error_t (*f
)(char *root
, char *opt
);
1528 const char *fcn
= "bam_archive()";
1531 * Add trailing / for archive subcommands
1533 if (rootbuf
[strlen(rootbuf
) - 1] != '/')
1534 (void) strcat(rootbuf
, "/");
1535 bam_rootlen
= strlen(rootbuf
);
1540 ret
= check_subcmd_and_options(subcmd
, opt
, arch_subcmds
, &f
);
1541 if (ret
!= BAM_SUCCESS
) {
1545 ret
= get_boot_cap(rootbuf
);
1546 if (ret
!= BAM_SUCCESS
) {
1547 BAM_DPRINTF((D_BOOT_GET_CAP_FAILED
, fcn
));
1552 * Check archive not supported with update_all
1553 * since it is awkward to display out-of-sync
1554 * information for each BE.
1556 if (bam_check
&& strcmp(subcmd
, "update_all") == 0) {
1557 bam_error(CHECK_NOT_SUPPORTED
, subcmd
);
1561 if (strcmp(subcmd
, "update_all") == 0)
1565 ucode_install(bam_root
);
1568 ret
= f(bam_root
, opt
);
1577 bam_error(char *format
, ...)
1581 va_start(ap
, format
);
1582 (void) fprintf(stderr
, "%s: ", prog
);
1583 (void) vfprintf(stderr
, format
, ap
);
1589 bam_derror(char *format
, ...)
1595 va_start(ap
, format
);
1596 (void) fprintf(stderr
, "DEBUG: ");
1597 (void) vfprintf(stderr
, format
, ap
);
1603 bam_print(char *format
, ...)
1607 va_start(ap
, format
);
1608 (void) vfprintf(stdout
, format
, ap
);
1614 bam_print_stderr(char *format
, ...)
1618 va_start(ap
, format
);
1619 (void) vfprintf(stderr
, format
, ap
);
1624 bam_exit(int excode
)
1637 bam_lock_fd
= open(BAM_LOCK_FILE
, O_CREAT
|O_RDWR
, LOCK_FILE_PERMS
);
1638 if (bam_lock_fd
< 0) {
1640 * We may be invoked early in boot for archive verification.
1641 * In this case, root is readonly and /var/run may not exist.
1642 * Proceed without the lock
1644 if (errno
== EROFS
|| errno
== ENOENT
) {
1645 bam_root_readonly
= 1;
1649 bam_error(OPEN_FAIL
, BAM_LOCK_FILE
, strerror(errno
));
1653 lock
.l_type
= F_WRLCK
;
1654 lock
.l_whence
= SEEK_SET
;
1658 if (fcntl(bam_lock_fd
, F_SETLK
, &lock
) == -1) {
1659 if (errno
!= EACCES
&& errno
!= EAGAIN
) {
1660 bam_error(LOCK_FAIL
, BAM_LOCK_FILE
, strerror(errno
));
1661 (void) close(bam_lock_fd
);
1666 (void) pread(bam_lock_fd
, &pid
, sizeof (pid_t
), 0);
1667 bam_print(FILE_LOCKED
, pid
);
1669 lock
.l_type
= F_WRLCK
;
1670 lock
.l_whence
= SEEK_SET
;
1673 if (fcntl(bam_lock_fd
, F_SETLKW
, &lock
) == -1) {
1674 bam_error(LOCK_FAIL
, BAM_LOCK_FILE
, strerror(errno
));
1675 (void) close(bam_lock_fd
);
1681 /* We own the lock now */
1683 (void) write(bam_lock_fd
, &pid
, sizeof (pid
));
1689 struct flock unlock
;
1692 * NOP if we don't hold the lock
1694 if (bam_lock_fd
< 0) {
1698 unlock
.l_type
= F_UNLCK
;
1699 unlock
.l_whence
= SEEK_SET
;
1703 if (fcntl(bam_lock_fd
, F_SETLK
, &unlock
) == -1) {
1704 bam_error(UNLOCK_FAIL
, BAM_LOCK_FILE
, strerror(errno
));
1707 if (close(bam_lock_fd
) == -1) {
1708 bam_error(CLOSE_FAIL
, BAM_LOCK_FILE
, strerror(errno
));
1714 list_archive(char *root
, char *opt
)
1717 filelist_t
*flistp
= &flist
;
1721 assert(opt
== NULL
);
1723 flistp
->head
= flistp
->tail
= NULL
;
1724 if (read_list(root
, flistp
) != BAM_SUCCESS
) {
1727 assert(flistp
->head
&& flistp
->tail
);
1729 for (lp
= flistp
->head
; lp
; lp
= lp
->next
) {
1730 bam_print(PRINT
, lp
->line
);
1733 filelist_free(flistp
);
1735 return (BAM_SUCCESS
);
1739 * This routine writes a list of lines to a file.
1740 * The list is *not* freed
1743 list2file(char *root
, char *tmp
, char *final
, line_t
*start
)
1745 char tmpfile
[PATH_MAX
];
1746 char path
[PATH_MAX
];
1755 const char *fcn
= "list2file()";
1757 (void) snprintf(path
, sizeof (path
), "%s%s", root
, final
);
1759 if (start
== NULL
) {
1760 /* Empty GRUB menu */
1761 if (stat(path
, &sb
) != -1) {
1762 bam_print(UNLINK_EMPTY
, path
);
1763 if (unlink(path
) != 0) {
1764 bam_error(UNLINK_FAIL
, path
, strerror(errno
));
1767 return (BAM_SUCCESS
);
1770 return (BAM_SUCCESS
);
1774 * Preserve attributes of existing file if possible,
1775 * otherwise ask the system for uid/gid of root/sys.
1776 * If all fails, fall back on hard-coded defaults.
1778 if (stat(path
, &sb
) != -1) {
1780 root_uid
= sb
.st_uid
;
1781 sys_gid
= sb
.st_gid
;
1783 mode
= DEFAULT_DEV_MODE
;
1784 if ((pw
= getpwnam(DEFAULT_DEV_USER
)) != NULL
) {
1785 root_uid
= pw
->pw_uid
;
1787 bam_error(CANT_FIND_USER
,
1788 DEFAULT_DEV_USER
, DEFAULT_DEV_UID
);
1789 root_uid
= (uid_t
)DEFAULT_DEV_UID
;
1791 if ((gp
= getgrnam(DEFAULT_DEV_GROUP
)) != NULL
) {
1792 sys_gid
= gp
->gr_gid
;
1794 bam_error(CANT_FIND_GROUP
,
1795 DEFAULT_DEV_GROUP
, DEFAULT_DEV_GID
);
1796 sys_gid
= (gid_t
)DEFAULT_DEV_GID
;
1800 (void) snprintf(tmpfile
, sizeof (tmpfile
), "%s%s", root
, tmp
);
1802 /* Truncate tmpfile first */
1803 fp
= fopen(tmpfile
, "w");
1805 bam_error(OPEN_FAIL
, tmpfile
, strerror(errno
));
1809 INJECT_ERROR1("LIST2FILE_TRUNC_FCLOSE", ret
= EOF
);
1811 bam_error(CLOSE_FAIL
, tmpfile
, strerror(errno
));
1815 /* Now open it in append mode */
1816 fp
= fopen(tmpfile
, "a");
1818 bam_error(OPEN_FAIL
, tmpfile
, strerror(errno
));
1822 for (; start
; start
= start
->next
) {
1823 ret
= s_fputs(start
->line
, fp
);
1824 INJECT_ERROR1("LIST2FILE_FPUTS", ret
= EOF
);
1826 bam_error(WRITE_FAIL
, tmpfile
, strerror(errno
));
1833 INJECT_ERROR1("LIST2FILE_APPEND_FCLOSE", ret
= EOF
);
1835 bam_error(CLOSE_FAIL
, tmpfile
, strerror(errno
));
1840 * Set up desired attributes. Ignore failures on filesystems
1841 * not supporting these operations - pcfs reports unsupported
1842 * operations as EINVAL.
1844 ret
= chmod(tmpfile
, mode
);
1846 errno
!= EINVAL
&& errno
!= ENOTSUP
) {
1847 bam_error(CHMOD_FAIL
, tmpfile
, strerror(errno
));
1851 ret
= chown(tmpfile
, root_uid
, sys_gid
);
1853 errno
!= EINVAL
&& errno
!= ENOTSUP
) {
1854 bam_error(CHOWN_FAIL
, tmpfile
, strerror(errno
));
1859 * Do an atomic rename
1861 ret
= rename(tmpfile
, path
);
1862 INJECT_ERROR1("LIST2FILE_RENAME", ret
= -1);
1864 bam_error(RENAME_FAIL
, path
, strerror(errno
));
1868 BAM_DPRINTF((D_WROTE_FILE
, fcn
, path
));
1869 return (BAM_SUCCESS
);
1873 * Checks if the path specified (without the file name at the end) exists
1874 * and creates it if not. If the path exists and is not a directory, an attempt
1875 * to unlink is made.
1878 setup_path(char *path
)
1884 p
= strrchr(path
, '/');
1887 if (stat(path
, &sb
) != 0 || !(S_ISDIR(sb
.st_mode
))) {
1888 /* best effort attempt, mkdirp will catch the error */
1889 (void) unlink(path
);
1891 bam_print(NEED_DIRPATH
, path
);
1892 ret
= mkdirp(path
, DIR_PERMS
);
1894 bam_error(MKDIR_FAILED
, path
, strerror(errno
));
1900 return (BAM_SUCCESS
);
1902 return (BAM_SUCCESS
);
1911 char path
[PATH_MAX
];
1916 setup_file(char *base
, const char *path
, cachefile
*cf
)
1921 /* init gzfile or fdfile in case we fail before opening */
1922 if (bam_direct
== BAM_DIRECT_DBOOT
)
1923 cf
->out
.gzfile
= NULL
;
1925 cf
->out
.fdfile
= -1;
1927 /* strip the trailing altroot path */
1928 strip
= (char *)path
+ strlen(rootbuf
);
1930 ret
= snprintf(cf
->path
, sizeof (cf
->path
), "%s/%s", base
, strip
);
1931 if (ret
>= sizeof (cf
->path
)) {
1932 bam_error(PATH_TOO_LONG
, rootbuf
);
1936 /* Check if path is present in the archive cache directory */
1937 if (setup_path(cf
->path
) == BAM_ERROR
)
1940 if (bam_direct
== BAM_DIRECT_DBOOT
) {
1941 if ((cf
->out
.gzfile
= gzopen(cf
->path
, "wb")) == NULL
) {
1942 bam_error(OPEN_FAIL
, cf
->path
, strerror(errno
));
1945 (void) gzsetparams(cf
->out
.gzfile
, Z_BEST_SPEED
,
1946 Z_DEFAULT_STRATEGY
);
1948 if ((cf
->out
.fdfile
= open(cf
->path
, O_WRONLY
| O_CREAT
, 0644))
1950 bam_error(OPEN_FAIL
, cf
->path
, strerror(errno
));
1955 return (BAM_SUCCESS
);
1959 cache_write(cachefile cf
, char *buf
, int size
)
1963 if (bam_direct
== BAM_DIRECT_DBOOT
) {
1964 if (gzwrite(cf
.out
.gzfile
, buf
, size
) < 1) {
1965 bam_error(GZ_WRITE_FAIL
, gzerror(cf
.out
.gzfile
, &err
));
1966 if (err
== Z_ERRNO
&& bam_verbose
) {
1967 bam_error(WRITE_FAIL
, cf
.path
, strerror(errno
));
1972 if (write(cf
.out
.fdfile
, buf
, size
) < 1) {
1973 bam_error(WRITE_FAIL
, cf
.path
, strerror(errno
));
1977 return (BAM_SUCCESS
);
1981 cache_close(cachefile cf
)
1985 if (bam_direct
== BAM_DIRECT_DBOOT
) {
1986 if (cf
.out
.gzfile
) {
1987 ret
= gzclose(cf
.out
.gzfile
);
1989 bam_error(CLOSE_FAIL
, cf
.path
, strerror(errno
));
1994 if (cf
.out
.fdfile
!= -1) {
1995 ret
= close(cf
.out
.fdfile
);
1997 bam_error(CLOSE_FAIL
, cf
.path
, strerror(errno
));
2003 return (BAM_SUCCESS
);
2007 dircache_updatefile(const char *path
, int what
)
2012 cachefile outfile
, outupdt
;
2014 if (bam_nowrite()) {
2015 set_dir_flag(what
, NEED_UPDATE
);
2016 return (BAM_SUCCESS
);
2019 if (!has_cachedir(what
))
2020 return (BAM_SUCCESS
);
2022 if ((infile
= fopen(path
, "rb")) == NULL
) {
2023 bam_error(OPEN_FAIL
, path
, strerror(errno
));
2027 ret
= setup_file(get_cachedir(what
), path
, &outfile
);
2028 if (ret
== BAM_ERROR
) {
2029 exitcode
= BAM_ERROR
;
2032 if (!is_dir_flag_on(what
, NO_MULTI
)) {
2033 ret
= setup_file(get_updatedir(what
), path
, &outupdt
);
2034 if (ret
== BAM_ERROR
)
2035 set_dir_flag(what
, NO_MULTI
);
2038 while ((ret
= fread(buf
, 1, sizeof (buf
), infile
)) > 0) {
2039 if (cache_write(outfile
, buf
, ret
) == BAM_ERROR
) {
2040 exitcode
= BAM_ERROR
;
2043 if (!is_dir_flag_on(what
, NO_MULTI
))
2044 if (cache_write(outupdt
, buf
, ret
) == BAM_ERROR
)
2045 set_dir_flag(what
, NO_MULTI
);
2048 set_dir_flag(what
, NEED_UPDATE
);
2050 if (get_count(what
) > COUNT_MAX
)
2051 set_dir_flag(what
, NO_MULTI
);
2052 exitcode
= BAM_SUCCESS
;
2054 (void) fclose(infile
);
2055 if (cache_close(outfile
) == BAM_ERROR
)
2056 exitcode
= BAM_ERROR
;
2057 if (!is_dir_flag_on(what
, NO_MULTI
) &&
2058 cache_close(outupdt
) == BAM_ERROR
)
2059 exitcode
= BAM_ERROR
;
2060 if (exitcode
== BAM_ERROR
)
2061 set_flag(UPDATE_ERROR
);
2066 dircache_updatedir(const char *path
, int what
, int updt
)
2069 char dpath
[PATH_MAX
];
2073 strip
= (char *)path
+ strlen(rootbuf
);
2075 ret
= snprintf(dpath
, sizeof (dpath
), "%s/%s", updt
?
2076 get_updatedir(what
) : get_cachedir(what
), strip
);
2078 if (ret
>= sizeof (dpath
)) {
2079 bam_error(PATH_TOO_LONG
, rootbuf
);
2080 set_flag(UPDATE_ERROR
);
2084 if (stat(dpath
, &sb
) == 0 && S_ISDIR(sb
.st_mode
))
2085 return (BAM_SUCCESS
);
2088 if (!is_dir_flag_on(what
, NO_MULTI
))
2089 if (!bam_nowrite() && mkdirp(dpath
, DIR_PERMS
) == -1)
2090 set_dir_flag(what
, NO_MULTI
);
2092 if (!bam_nowrite() && mkdirp(dpath
, DIR_PERMS
) == -1) {
2093 set_flag(UPDATE_ERROR
);
2098 set_dir_flag(what
, NEED_UPDATE
);
2099 return (BAM_SUCCESS
);
2102 #define DO_CACHE_DIR 0
2103 #define DO_UPDATE_DIR 1
2105 #if defined(_LP64) || defined(_LONGLONG_TYPE)
2106 typedef Elf64_Ehdr _elfhdr
;
2108 typedef Elf32_Ehdr _elfhdr
;
2112 * This routine updates the contents of the cache directory
2115 update_dircache(const char *path
, int flags
)
2117 int rc
= BAM_SUCCESS
;
2125 if ((fd
= open(path
, O_RDONLY
)) < 0) {
2126 bam_error(OPEN_FAIL
, path
, strerror(errno
));
2127 set_flag(UPDATE_ERROR
);
2133 * libelf and gelf would be a cleaner and easier way to handle
2134 * this, but libelf fails compilation if _ILP32 is defined &&
2135 * _FILE_OFFSET_BITS is != 32 ...
2137 if (read(fd
, (void *)&elf
, sizeof (_elfhdr
)) < 0) {
2138 bam_error(READ_FAIL
, path
, strerror(errno
));
2139 set_flag(UPDATE_ERROR
);
2147 * If the file is not an executable and is not inside an amd64
2148 * directory, we copy it in both the cache directories,
2149 * otherwise, we only copy it inside the 64-bit one.
2151 if (memcmp(elf
.e_ident
, ELFMAG
, 4) != 0) {
2152 if (strstr(path
, "/amd64")) {
2153 rc
= dircache_updatefile(path
, FILE64
);
2155 rc
= dircache_updatefile(path
, FILE32
);
2156 if (rc
== BAM_SUCCESS
)
2157 rc
= dircache_updatefile(path
, FILE64
);
2161 * Based on the ELF class we copy the file in the 32-bit
2162 * or the 64-bit cache directory.
2164 if (elf
.e_ident
[EI_CLASS
] == ELFCLASS32
) {
2165 rc
= dircache_updatefile(path
, FILE32
);
2166 } else if (elf
.e_ident
[EI_CLASS
] == ELFCLASS64
) {
2167 rc
= dircache_updatefile(path
, FILE64
);
2169 bam_print(NO3264ELF
, path
);
2171 rc
= dircache_updatefile(path
, FILE32
);
2172 if (rc
== BAM_SUCCESS
)
2173 rc
= dircache_updatefile(path
, FILE64
);
2179 if (strstr(path
, "/amd64") == NULL
) {
2180 rc
= dircache_updatedir(path
, FILE32
, DO_UPDATE_DIR
);
2181 if (rc
== BAM_SUCCESS
)
2182 rc
= dircache_updatedir(path
, FILE32
,
2185 if (has_cachedir(FILE64
)) {
2186 rc
= dircache_updatedir(path
, FILE64
,
2188 if (rc
== BAM_SUCCESS
)
2189 rc
= dircache_updatedir(path
, FILE64
,
2206 const struct stat
*st
,
2212 uint64_t filestat
[2];
2213 int error
, ret
, status
;
2215 struct safefile
*safefilep
;
2221 * On SPARC we create/update links too.
2223 if (flags
!= FTW_F
&& flags
!= FTW_D
&& (flags
== FTW_SL
&&
2224 !is_flag_on(IS_SPARC_TARGET
)))
2228 * Ignore broken links
2230 if (flags
== FTW_SL
&& stat(file
, &sb
) < 0)
2234 * new_nvlp may be NULL if there were errors earlier
2235 * but this is not fatal to update determination.
2237 if (walk_arg
.new_nvlp
) {
2238 filestat
[0] = st
->st_size
;
2239 filestat
[1] = st
->st_mtime
;
2240 error
= nvlist_add_uint64_array(walk_arg
.new_nvlp
,
2241 file
+ bam_rootlen
, filestat
, 2);
2243 bam_error(NVADD_FAIL
, file
, strerror(error
));
2247 * If we are invoked as part of system/filesystem/boot-archive, then
2248 * there are a number of things we should not worry about
2250 if (bam_smf_check
) {
2251 /* ignore amd64 modules unless we are booted amd64. */
2252 if (!is_amd64() && strstr(file
, "/amd64/") != 0)
2255 /* read in list of safe files */
2256 if (safefiles
== NULL
) {
2257 fp
= fopen("/boot/solaris/filelist.safe", "r");
2259 safefiles
= s_calloc(1,
2260 sizeof (struct safefile
));
2261 safefilep
= safefiles
;
2262 safefilep
->name
= s_calloc(1, MAXPATHLEN
+
2264 safefilep
->next
= NULL
;
2265 while (s_fgets(safefilep
->name
, MAXPATHLEN
+
2266 MAXNAMELEN
, fp
) != NULL
) {
2267 safefilep
->next
= s_calloc(1,
2268 sizeof (struct safefile
));
2269 safefilep
= safefilep
->next
;
2270 safefilep
->name
= s_calloc(1,
2271 MAXPATHLEN
+ MAXNAMELEN
);
2272 safefilep
->next
= NULL
;
2280 * On SPARC we create a -path-list file for mkisofs
2282 if (is_flag_on(IS_SPARC_TARGET
) && !bam_nowrite()) {
2283 if (flags
!= FTW_D
) {
2286 strip
= (char *)file
+ strlen(rootbuf
);
2287 (void) fprintf(walk_arg
.sparcfile
, "/%s=%s\n", strip
,
2293 * We are transitioning from the old model to the dircache or the cache
2294 * directory was removed: create the entry without further checkings.
2296 if (is_flag_on(NEED_CACHE_DIR
)) {
2298 bam_print(PARSEABLE_NEW_FILE
, file
);
2300 if (is_flag_on(IS_SPARC_TARGET
)) {
2301 set_dir_flag(FILE64
, NEED_UPDATE
);
2305 ret
= update_dircache(file
, flags
);
2306 if (ret
== BAM_ERROR
) {
2307 bam_error(UPDT_CACHE_FAIL
, file
);
2315 * We need an update if file doesn't exist in old archive
2317 if (walk_arg
.old_nvlp
== NULL
||
2318 nvlist_lookup_uint64_array(walk_arg
.old_nvlp
,
2319 file
+ bam_rootlen
, &value
, &sz
) != 0) {
2320 if (bam_smf_check
) /* ignore new during smf check */
2323 if (is_flag_on(IS_SPARC_TARGET
)) {
2324 set_dir_flag(FILE64
, NEED_UPDATE
);
2326 ret
= update_dircache(file
, flags
);
2327 if (ret
== BAM_ERROR
) {
2328 bam_error(UPDT_CACHE_FAIL
, file
);
2334 bam_print(PARSEABLE_NEW_FILE
, file
);
2339 * If we got there, the file is already listed as to be included in the
2340 * iso image. We just need to know if we are going to rebuild it or not
2342 if (is_flag_on(IS_SPARC_TARGET
) &&
2343 is_dir_flag_on(FILE64
, NEED_UPDATE
) && !bam_nowrite())
2346 * File exists in old archive. Check if file has changed
2349 bcopy(value
, filestat
, sizeof (filestat
));
2351 if (flags
!= FTW_D
&& (filestat
[0] != st
->st_size
||
2352 filestat
[1] != st
->st_mtime
)) {
2353 if (bam_smf_check
) {
2354 safefilep
= safefiles
;
2355 while (safefilep
!= NULL
&&
2356 safefilep
->name
[0] != '\0') {
2357 if (regcomp(&re
, safefilep
->name
,
2358 REG_EXTENDED
|REG_NOSUB
) == 0) {
2359 status
= regexec(&re
,
2360 file
+ bam_rootlen
, 0, NULL
, 0);
2364 NEED_UPDATE_SAFE_FILE
,
2369 safefilep
= safefilep
->next
;
2373 if (is_flag_on(IS_SPARC_TARGET
)) {
2374 set_dir_flag(FILE64
, NEED_UPDATE
);
2376 ret
= update_dircache(file
, flags
);
2377 if (ret
== BAM_ERROR
) {
2378 bam_error(UPDT_CACHE_FAIL
, file
);
2385 bam_print(" %s\n", file
);
2387 bam_print(PARSEABLE_OUT_DATE
, file
);
2395 * Remove a directory path recursively
2400 struct dirent
*d
= NULL
;
2402 char tpath
[PATH_MAX
];
2405 if ((dir
= opendir(path
)) == NULL
)
2408 while ((d
= readdir(dir
)) != NULL
) {
2409 if ((strcmp(d
->d_name
, ".") != 0) &&
2410 (strcmp(d
->d_name
, "..") != 0)) {
2411 (void) snprintf(tpath
, sizeof (tpath
), "%s/%s",
2413 if (stat(tpath
, &sb
) == 0) {
2414 if (sb
.st_mode
& S_IFDIR
)
2415 (void) rmdir_r(tpath
);
2417 (void) remove(tpath
);
2421 return (remove(path
));
2425 * Check if cache directory exists and, if not, create it and update flags
2426 * accordingly. If the path exists, but it's not a directory, a best effort
2427 * attempt to remove and recreate it is made.
2428 * If the user requested a 'purge', always recreate the directory from scratch.
2431 set_cache_dir(char *root
, int what
)
2436 ret
= snprintf(get_cachedir(what
), sizeof (get_cachedir(what
)),
2437 "%s%s%s%s%s", root
, ARCHIVE_PREFIX
, get_machine(), what
== FILE64
?
2438 "/amd64" : "", CACHEDIR_SUFFIX
);
2440 if (ret
>= sizeof (get_cachedir(what
))) {
2441 bam_error(PATH_TOO_LONG
, rootbuf
);
2445 if (bam_purge
|| is_flag_on(INVALIDATE_CACHE
))
2446 (void) rmdir_r(get_cachedir(what
));
2448 if (stat(get_cachedir(what
), &sb
) != 0 || !(S_ISDIR(sb
.st_mode
))) {
2449 /* best effort unlink attempt, mkdir will catch errors */
2450 (void) unlink(get_cachedir(what
));
2453 bam_print(UPDATE_CDIR_MISS
, get_cachedir(what
));
2454 ret
= mkdir(get_cachedir(what
), DIR_PERMS
);
2456 bam_error(MKDIR_FAILED
, get_cachedir(what
),
2458 get_cachedir(what
)[0] = '\0';
2461 set_flag(NEED_CACHE_DIR
);
2462 set_dir_flag(what
, NO_MULTI
);
2465 return (BAM_SUCCESS
);
2469 set_update_dir(char *root
, int what
)
2474 if (is_dir_flag_on(what
, NO_MULTI
))
2475 return (BAM_SUCCESS
);
2478 set_dir_flag(what
, NO_MULTI
);
2479 return (BAM_SUCCESS
);
2482 if (what
== FILE64
&& !is_flag_on(IS_SPARC_TARGET
))
2483 ret
= snprintf(get_updatedir(what
),
2484 sizeof (get_updatedir(what
)), "%s%s%s/amd64%s", root
,
2485 ARCHIVE_PREFIX
, get_machine(), UPDATEDIR_SUFFIX
);
2487 ret
= snprintf(get_updatedir(what
),
2488 sizeof (get_updatedir(what
)), "%s%s%s%s", root
,
2489 ARCHIVE_PREFIX
, get_machine(), UPDATEDIR_SUFFIX
);
2491 if (ret
>= sizeof (get_updatedir(what
))) {
2492 bam_error(PATH_TOO_LONG
, rootbuf
);
2496 if (stat(get_updatedir(what
), &sb
) == 0) {
2497 if (S_ISDIR(sb
.st_mode
))
2498 ret
= rmdir_r(get_updatedir(what
));
2500 ret
= unlink(get_updatedir(what
));
2503 set_dir_flag(what
, NO_MULTI
);
2506 if (mkdir(get_updatedir(what
), DIR_PERMS
) < 0)
2507 set_dir_flag(what
, NO_MULTI
);
2509 return (BAM_SUCCESS
);
2513 is_valid_archive(char *root
, int what
)
2515 char archive_path
[PATH_MAX
];
2516 char timestamp_path
[PATH_MAX
];
2517 struct stat sb
, timestamp
;
2520 if (what
== FILE64
&& !is_flag_on(IS_SPARC_TARGET
))
2521 ret
= snprintf(archive_path
, sizeof (archive_path
),
2522 "%s%s%s/amd64%s", root
, ARCHIVE_PREFIX
, get_machine(),
2525 ret
= snprintf(archive_path
, sizeof (archive_path
), "%s%s%s%s",
2526 root
, ARCHIVE_PREFIX
, get_machine(), ARCHIVE_SUFFIX
);
2528 if (ret
>= sizeof (archive_path
)) {
2529 bam_error(PATH_TOO_LONG
, rootbuf
);
2533 if (stat(archive_path
, &sb
) != 0) {
2534 if (bam_verbose
&& !bam_check
)
2535 bam_print(UPDATE_ARCH_MISS
, archive_path
);
2536 set_dir_flag(what
, NEED_UPDATE
);
2537 set_dir_flag(what
, NO_MULTI
);
2538 return (BAM_SUCCESS
);
2542 * The timestamp file is used to prevent stale files in the archive
2544 * Stale files can happen if the system is booted back and forth across
2545 * the transition from bootadm-before-the-cache to
2546 * bootadm-after-the-cache, since older versions of bootadm don't know
2547 * about the existence of the archive cache.
2549 * Since only bootadm-after-the-cache versions know about about this
2550 * file, we require that the boot archive be older than this file.
2552 ret
= snprintf(timestamp_path
, sizeof (timestamp_path
), "%s%s", root
,
2553 FILE_STAT_TIMESTAMP
);
2555 if (ret
>= sizeof (timestamp_path
)) {
2556 bam_error(PATH_TOO_LONG
, rootbuf
);
2560 if (stat(timestamp_path
, ×tamp
) != 0 ||
2561 sb
.st_mtime
> timestamp
.st_mtime
) {
2562 if (bam_verbose
&& !bam_check
)
2563 bam_print(UPDATE_CACHE_OLD
);
2565 * Don't generate a false positive for the boot-archive service
2566 * but trigger an update of the archive cache in
2567 * boot-archive-update.
2569 if (bam_smf_check
) {
2570 (void) creat(NEED_UPDATE_FILE
, 0644);
2571 return (BAM_SUCCESS
);
2574 set_flag(INVALIDATE_CACHE
);
2575 set_dir_flag(what
, NEED_UPDATE
);
2576 set_dir_flag(what
, NO_MULTI
);
2577 return (BAM_SUCCESS
);
2580 if (is_flag_on(IS_SPARC_TARGET
))
2581 return (BAM_SUCCESS
);
2583 if (bam_extend
&& sb
.st_size
> BA_SIZE_MAX
) {
2584 if (bam_verbose
&& !bam_check
)
2585 bam_print(MULTI_SIZE
, archive_path
, BA_SIZE_MAX
);
2586 set_dir_flag(what
, NO_MULTI
);
2589 return (BAM_SUCCESS
);
2593 * Check flags and presence of required files and directories.
2594 * The force flag and/or absence of files should
2595 * trigger an update.
2596 * Suppress stdout output if check (-n) option is set
2597 * (as -n should only produce parseable output.)
2600 check_flags_and_files(char *root
)
2607 * If archive is missing, create archive
2609 if (is_flag_on(IS_SPARC_TARGET
)) {
2610 ret
= is_valid_archive(root
, FILE64
);
2611 if (ret
== BAM_ERROR
)
2616 ret
= is_valid_archive(root
, what
);
2617 if (ret
== BAM_ERROR
)
2620 } while (bam_direct
== BAM_DIRECT_DBOOT
&& what
< CACHEDIR_NUM
);
2624 return (BAM_SUCCESS
);
2628 * check if cache directories exist on x86.
2629 * check (and always open) the cache file on SPARC.
2632 ret
= snprintf(get_cachedir(FILE64
),
2633 sizeof (get_cachedir(FILE64
)), "%s%s%s/%s", root
,
2634 ARCHIVE_PREFIX
, get_machine(), CACHEDIR_SUFFIX
);
2636 if (ret
>= sizeof (get_cachedir(FILE64
))) {
2637 bam_error(PATH_TOO_LONG
, rootbuf
);
2641 if (stat(get_cachedir(FILE64
), &sb
) != 0) {
2642 set_flag(NEED_CACHE_DIR
);
2643 set_dir_flag(FILE64
, NEED_UPDATE
);
2646 walk_arg
.sparcfile
= fopen(get_cachedir(FILE64
), "w");
2647 if (walk_arg
.sparcfile
== NULL
) {
2648 bam_error(OPEN_FAIL
, get_cachedir(FILE64
),
2653 set_dir_present(FILE64
);
2658 if (set_cache_dir(root
, what
) != 0)
2661 set_dir_present(what
);
2663 if (set_update_dir(root
, what
) != 0)
2666 } while (bam_direct
== BAM_DIRECT_DBOOT
&& what
< CACHEDIR_NUM
);
2670 * if force, create archive unconditionally
2674 set_dir_flag(FILE32
, NEED_UPDATE
);
2675 set_dir_flag(FILE64
, NEED_UPDATE
);
2677 bam_print(UPDATE_FORCE
);
2678 return (BAM_SUCCESS
);
2681 return (BAM_SUCCESS
);
2685 read_one_list(char *root
, filelist_t
*flistp
, char *filelist
)
2687 char path
[PATH_MAX
];
2689 char buf
[BAM_MAXLINE
];
2690 const char *fcn
= "read_one_list()";
2692 (void) snprintf(path
, sizeof (path
), "%s%s", root
, filelist
);
2694 fp
= fopen(path
, "r");
2696 BAM_DPRINTF((D_FLIST_FAIL
, fcn
, path
, strerror(errno
)));
2699 while (s_fgets(buf
, sizeof (buf
), fp
) != NULL
) {
2700 /* skip blank lines */
2701 if (strspn(buf
, " \t") == strlen(buf
))
2703 append_to_flist(flistp
, buf
);
2705 if (fclose(fp
) != 0) {
2706 bam_error(CLOSE_FAIL
, path
, strerror(errno
));
2709 return (BAM_SUCCESS
);
2713 read_list(char *root
, filelist_t
*flistp
)
2715 char path
[PATH_MAX
];
2719 const char *fcn
= "read_list()";
2721 flistp
->head
= flistp
->tail
= NULL
;
2724 * build and check path to extract_boot_filelist.ksh
2726 n
= snprintf(path
, sizeof (path
), "%s%s", root
, EXTRACT_BOOT_FILELIST
);
2727 if (n
>= sizeof (path
)) {
2728 bam_error(NO_FLIST
);
2732 if (is_safe_exec(path
) == BAM_ERROR
)
2736 * If extract_boot_filelist is present, exec it, otherwise read
2737 * the filelists directly, for compatibility with older images.
2739 if (stat(path
, &sb
) == 0) {
2741 * build arguments to exec extract_boot_filelist.ksh
2743 char *rootarg
, *platarg
;
2744 int platarglen
= 1, rootarglen
= 1;
2745 if (strlen(root
) > 1)
2746 rootarglen
+= strlen(root
) + strlen("-R ");
2747 if (bam_alt_platform
)
2748 platarglen
+= strlen(bam_platform
) + strlen("-p ");
2749 platarg
= s_calloc(1, platarglen
);
2750 rootarg
= s_calloc(1, rootarglen
);
2754 if (strlen(root
) > 1) {
2755 (void) snprintf(rootarg
, rootarglen
,
2758 if (bam_alt_platform
) {
2759 (void) snprintf(platarg
, platarglen
,
2760 "-p %s", bam_platform
);
2762 n
= snprintf(cmd
, sizeof (cmd
), "%s %s %s /%s /%s",
2763 path
, rootarg
, platarg
, BOOT_FILE_LIST
, ETC_FILE_LIST
);
2766 if (n
>= sizeof (cmd
)) {
2767 bam_error(NO_FLIST
);
2770 if (exec_cmd(cmd
, flistp
) != 0) {
2771 BAM_DPRINTF((D_FLIST_FAIL
, fcn
, path
, strerror(errno
)));
2776 * Read current lists of files - only the first is mandatory
2778 rval
= read_one_list(root
, flistp
, BOOT_FILE_LIST
);
2779 if (rval
!= BAM_SUCCESS
)
2781 (void) read_one_list(root
, flistp
, ETC_FILE_LIST
);
2784 if (flistp
->head
== NULL
) {
2785 bam_error(NO_FLIST
);
2789 return (BAM_SUCCESS
);
2793 getoldstat(char *root
)
2795 char path
[PATH_MAX
];
2800 (void) snprintf(path
, sizeof (path
), "%s%s", root
, FILE_STAT
);
2801 fd
= open(path
, O_RDONLY
);
2804 bam_print(OPEN_FAIL
, path
, strerror(errno
));
2808 if (fstat(fd
, &sb
) != 0) {
2809 bam_error(STAT_FAIL
, path
, strerror(errno
));
2813 ostat
= s_calloc(1, sb
.st_size
);
2815 if (read(fd
, ostat
, sb
.st_size
) != sb
.st_size
) {
2816 bam_error(READ_FAIL
, path
, strerror(errno
));
2824 walk_arg
.old_nvlp
= NULL
;
2825 error
= nvlist_unpack(ostat
, sb
.st_size
, &walk_arg
.old_nvlp
, 0);
2830 bam_error(UNPACK_FAIL
, path
, strerror(error
));
2831 walk_arg
.old_nvlp
= NULL
;
2840 if (!is_flag_on(IS_SPARC_TARGET
))
2841 set_dir_flag(FILE32
, NEED_UPDATE
);
2842 set_dir_flag(FILE64
, NEED_UPDATE
);
2845 /* Best effort stale entry removal */
2847 delete_stale(char *file
, int what
)
2849 char path
[PATH_MAX
];
2852 (void) snprintf(path
, sizeof (path
), "%s/%s", get_cachedir(what
), file
);
2853 if (!bam_check
&& stat(path
, &sb
) == 0) {
2854 if (sb
.st_mode
& S_IFDIR
)
2855 (void) rmdir_r(path
);
2857 (void) unlink(path
);
2859 set_dir_flag(what
, (NEED_UPDATE
| NO_MULTI
));
2864 * Checks if a file in the current (old) archive has
2865 * been deleted from the root filesystem. This is needed for
2866 * software like Trusted Extensions (TX) that switch early
2867 * in boot based on presence/absence of a kernel module.
2870 check4stale(char *root
)
2875 char path
[PATH_MAX
];
2878 * Skip stale file check during smf check
2884 * If we need to (re)create the cache, there's no need to check for
2887 if (is_flag_on(NEED_CACHE_DIR
))
2890 /* Nothing to do if no old stats */
2891 if ((nvlp
= walk_arg
.old_nvlp
) == NULL
)
2894 for (nvp
= nvlist_next_nvpair(nvlp
, NULL
); nvp
;
2895 nvp
= nvlist_next_nvpair(nvlp
, nvp
)) {
2896 file
= nvpair_name(nvp
);
2899 (void) snprintf(path
, sizeof (path
), "%s/%s",
2901 if (access(path
, F_OK
) < 0) {
2905 bam_print(PARSEABLE_STALE_FILE
, path
);
2907 if (is_flag_on(IS_SPARC_TARGET
)) {
2908 set_dir_flag(FILE64
, NEED_UPDATE
);
2910 for (what
= FILE32
; what
< CACHEDIR_NUM
; what
++)
2911 if (has_cachedir(what
))
2912 delete_stale(file
, what
);
2919 create_newstat(void)
2923 error
= nvlist_alloc(&walk_arg
.new_nvlp
, NV_UNIQUE_NAME
, 0);
2926 * Not fatal - we can still create archive
2928 walk_arg
.new_nvlp
= NULL
;
2929 bam_error(NVALLOC_FAIL
, strerror(error
));
2934 walk_list(char *root
, filelist_t
*flistp
)
2936 char path
[PATH_MAX
];
2939 for (lp
= flistp
->head
; lp
; lp
= lp
->next
) {
2941 * Don't follow symlinks. A symlink must refer to
2942 * a file that would appear in the archive through
2943 * a direct reference. This matches the archive
2944 * construction behavior.
2946 (void) snprintf(path
, sizeof (path
), "%s%s", root
, lp
->line
);
2947 if (nftw(path
, cmpstat
, 20, FTW_PHYS
) == -1) {
2948 if (is_flag_on(UPDATE_ERROR
))
2951 * Some files may not exist.
2952 * For example: etc/rtc_config on a x86 diskless system
2953 * Emit verbose message only
2956 bam_print(NFTW_FAIL
, path
, strerror(errno
));
2960 return (BAM_SUCCESS
);
2964 * Update the timestamp file.
2967 update_timestamp(char *root
)
2969 char timestamp_path
[PATH_MAX
];
2971 /* this path length has already been checked in check_flags_and_files */
2972 (void) snprintf(timestamp_path
, sizeof (timestamp_path
), "%s%s", root
,
2973 FILE_STAT_TIMESTAMP
);
2976 * recreate the timestamp file. Since an outdated or absent timestamp
2977 * file translates in a complete rebuild of the archive cache, notify
2978 * the user of the performance issue.
2980 if (creat(timestamp_path
, FILE_STAT_MODE
) < 0) {
2981 bam_error(OPEN_FAIL
, timestamp_path
, strerror(errno
));
2982 bam_error(TIMESTAMP_FAIL
);
2990 char path
[PATH_MAX
];
2991 char path2
[PATH_MAX
];
2994 int fd
, wrote
, error
;
2998 error
= nvlist_pack(walk_arg
.new_nvlp
, &nstat
, &sz
,
3001 bam_error(PACK_FAIL
, strerror(error
));
3005 (void) snprintf(path
, sizeof (path
), "%s%s", root
, FILE_STAT_TMP
);
3006 fd
= open(path
, O_RDWR
|O_CREAT
|O_TRUNC
, FILE_STAT_MODE
);
3008 bam_error(OPEN_FAIL
, path
, strerror(errno
));
3012 wrote
= write(fd
, nstat
, sz
);
3014 bam_error(WRITE_FAIL
, path
, strerror(errno
));
3022 (void) snprintf(path2
, sizeof (path2
), "%s%s", root
, FILE_STAT
);
3023 if (rename(path
, path2
) != 0) {
3024 bam_error(RENAME_FAIL
, path2
, strerror(errno
));
3028 #define init_walk_args() bzero(&walk_arg, sizeof (walk_arg))
3031 clear_walk_args(void)
3033 nvlist_free(walk_arg
.old_nvlp
);
3034 nvlist_free(walk_arg
.new_nvlp
);
3035 if (walk_arg
.sparcfile
)
3036 (void) fclose(walk_arg
.sparcfile
);
3037 walk_arg
.old_nvlp
= NULL
;
3038 walk_arg
.new_nvlp
= NULL
;
3039 walk_arg
.sparcfile
= NULL
;
3044 * 0 - no update necessary
3045 * 1 - update required.
3046 * BAM_ERROR (-1) - An error occurred
3048 * Special handling for check (-n):
3049 * ================================
3050 * The check (-n) option produces parseable output.
3051 * To do this, we suppress all stdout messages unrelated
3052 * to out of sync files.
3053 * All stderr messages are still printed though.
3057 update_required(char *root
)
3060 char path
[PATH_MAX
];
3062 filelist_t
*flistp
= &flist
;
3065 flistp
->head
= flistp
->tail
= NULL
;
3068 set_flag(IS_SPARC_TARGET
);
3071 * Check if cache directories and archives are present
3074 ret
= check_flags_and_files(root
);
3079 * In certain deployment scenarios, filestat may not
3080 * exist. Do not stop the boot process, but trigger an update
3081 * of the archives (which will recreate filestat.ramdisk).
3083 if (bam_smf_check
) {
3084 (void) snprintf(path
, sizeof (path
), "%s%s", root
, FILE_STAT
);
3085 if (stat(path
, &sb
) != 0) {
3086 (void) creat(NEED_UPDATE_FILE
, 0644);
3094 * Check if the archive contains files that are no longer
3095 * present on the root filesystem.
3100 * read list of files
3102 if (read_list(root
, flistp
) != BAM_SUCCESS
) {
3107 assert(flistp
->head
&& flistp
->tail
);
3110 * At this point either the update is required
3111 * or the decision is pending. In either case
3112 * we need to create new stat nvlist
3116 * This walk does 2 things:
3117 * - gets new stat data for every file
3118 * - (optional) compare old and new stat data
3120 ret
= walk_list(root
, &flist
);
3122 /* done with the file list */
3123 filelist_free(flistp
);
3125 /* something went wrong */
3127 if (ret
== BAM_ERROR
) {
3128 bam_error(CACHE_FAIL
);
3132 if (walk_arg
.new_nvlp
== NULL
) {
3133 if (walk_arg
.sparcfile
!= NULL
)
3134 (void) fclose(walk_arg
.sparcfile
);
3135 bam_error(NO_NEW_STAT
);
3138 /* If nothing was updated, discard newstat. */
3140 if (!is_dir_flag_on(FILE32
, NEED_UPDATE
) &&
3141 !is_dir_flag_on(FILE64
, NEED_UPDATE
)) {
3146 if (walk_arg
.sparcfile
!= NULL
)
3147 (void) fclose(walk_arg
.sparcfile
);
3155 char cmd
[PATH_MAX
+ 30];
3157 (void) snprintf(cmd
, sizeof (cmd
), "%s -f \"%s\" 2>/dev/null",
3160 return (exec_cmd(cmd
, NULL
));
3164 do_archive_copy(char *source
, char *dest
)
3169 /* the equivalent of mv archive-new-$pid boot_archive */
3170 if (rename(source
, dest
) != 0) {
3171 (void) unlink(source
);
3175 if (flushfs(bam_root
) != 0)
3178 return (BAM_SUCCESS
);
3182 check_cmdline(filelist_t flist
)
3186 for (lp
= flist
.head
; lp
; lp
= lp
->next
) {
3187 if (strstr(lp
->line
, "Error:") != NULL
||
3188 strstr(lp
->line
, "Inode number overflow") != NULL
) {
3189 (void) fprintf(stderr
, "%s\n", lp
->line
);
3194 return (BAM_SUCCESS
);
3198 dump_errormsg(filelist_t flist
)
3202 for (lp
= flist
.head
; lp
; lp
= lp
->next
)
3203 (void) fprintf(stderr
, "%s\n", lp
->line
);
3207 check_archive(char *dest
)
3211 if (stat(dest
, &sb
) != 0 || !S_ISREG(sb
.st_mode
) ||
3212 sb
.st_size
< 10000) {
3213 bam_error(ARCHIVE_BAD
, dest
);
3214 (void) unlink(dest
);
3218 return (BAM_SUCCESS
);
3225 libzfs_handle_t
*hdl
;
3226 be_node_list_t
*be_nodes
= NULL
;
3227 be_node_list_t
*cur_be
;
3228 boolean_t be_exist
= B_FALSE
;
3229 char ds_path
[ZFS_MAX_DATASET_NAME_LEN
];
3234 * Get dataset for mountpoint
3236 if ((hdl
= libzfs_init()) == NULL
)
3239 if ((zhp
= zfs_path_to_zhandle(hdl
, root
,
3240 ZFS_TYPE_FILESYSTEM
)) == NULL
) {
3245 (void) strlcpy(ds_path
, zfs_get_name(zhp
), sizeof (ds_path
));
3248 * Check if the current dataset is BE
3250 if (be_list(NULL
, &be_nodes
) == BE_SUCCESS
) {
3251 for (cur_be
= be_nodes
; cur_be
!= NULL
;
3252 cur_be
= cur_be
->be_next_node
) {
3255 * Because we guarantee that cur_be->be_root_ds
3256 * is null-terminated by internal data structure,
3257 * we can safely use strcmp()
3259 if (strcmp(ds_path
, cur_be
->be_root_ds
) == 0) {
3264 be_free_list(be_nodes
);
3273 * Returns 1 if mkiso is in the expected PATH, 0 otherwise
3278 if (access(MKISOFS_PATH
, X_OK
) == 0)
3283 #define MKISO_PARAMS " -quiet -graft-points -dlrDJN -relaxed-filenames "
3286 create_sparc_archive(char *archive
, char *tempname
, char *bootblk
, char *list
)
3289 char cmdline
[3 * PATH_MAX
+ 64];
3290 filelist_t flist
= {0};
3291 const char *func
= "create_sparc_archive()";
3293 if (access(bootblk
, R_OK
) == 1) {
3294 bam_error(BOOTBLK_FAIL
, bootblk
);
3299 * Prepare mkisofs command line and execute it
3301 (void) snprintf(cmdline
, sizeof (cmdline
), "%s %s -G %s -o \"%s\" "
3302 "-path-list \"%s\" 2>&1", MKISOFS_PATH
, MKISO_PARAMS
, bootblk
,
3305 BAM_DPRINTF((D_CMDLINE
, func
, cmdline
));
3307 ret
= exec_cmd(cmdline
, &flist
);
3308 if (ret
!= 0 || check_cmdline(flist
) == BAM_ERROR
) {
3309 dump_errormsg(flist
);
3313 filelist_free(&flist
);
3316 * Prepare dd command line to copy the bootblk on the new archive and
3319 (void) snprintf(cmdline
, sizeof (cmdline
), "%s if=\"%s\" of=\"%s\""
3320 " bs=1b oseek=1 count=15 conv=notrunc conv=sync 2>&1", DD_PATH_USR
,
3323 BAM_DPRINTF((D_CMDLINE
, func
, cmdline
));
3325 ret
= exec_cmd(cmdline
, &flist
);
3326 if (ret
!= 0 || check_cmdline(flist
) == BAM_ERROR
)
3329 filelist_free(&flist
);
3331 /* Did we get a valid archive ? */
3332 if (check_archive(tempname
) == BAM_ERROR
)
3335 return (do_archive_copy(tempname
, archive
));
3338 filelist_free(&flist
);
3339 bam_error(ARCHIVE_FAIL
, cmdline
);
3340 (void) unlink(tempname
);
3345 from_733(unsigned char *s
)
3348 unsigned int ret
= 0;
3350 for (i
= 0; i
< 4; i
++)
3351 ret
|= s
[i
] << (8 * i
);
3357 to_733(unsigned char *s
, unsigned int val
)
3361 for (i
= 0; i
< 4; i
++)
3362 s
[i
] = s
[7-i
] = (val
>> (8 * i
)) & 0xFF;
3366 * Extends the current boot archive without recreating it from scratch
3369 extend_iso_archive(char *archive
, char *tempname
, char *update_dir
)
3371 int fd
= -1, newfd
= -1, ret
, i
;
3372 int next_session
= 0, new_size
= 0;
3373 char cmdline
[3 * PATH_MAX
+ 64];
3374 const char *func
= "extend_iso_archive()";
3375 filelist_t flist
= {0};
3376 struct iso_pdesc saved_desc
[MAX_IVDs
];
3378 fd
= open(archive
, O_RDWR
);
3381 bam_error(OPEN_FAIL
, archive
, strerror(errno
));
3386 * A partial read is likely due to a corrupted file
3388 ret
= pread64(fd
, saved_desc
, sizeof (saved_desc
),
3389 VOLDESC_OFF
* CD_BLOCK
);
3390 if (ret
!= sizeof (saved_desc
)) {
3392 bam_error(READ_FAIL
, archive
, strerror(errno
));
3396 if (memcmp(saved_desc
[0].type
, "\1CD001", 6)) {
3398 bam_error(SIGN_FAIL
, archive
);
3403 * Read primary descriptor and locate next_session offset (it should
3404 * point to the end of the archive)
3406 next_session
= P2ROUNDUP(from_733(saved_desc
[0].volume_space_size
), 16);
3408 (void) snprintf(cmdline
, sizeof (cmdline
), "%s -C 16,%d -M %s %s -o \""
3409 "%s\" \"%s\" 2>&1", MKISOFS_PATH
, next_session
, archive
,
3410 MKISO_PARAMS
, tempname
, update_dir
);
3412 BAM_DPRINTF((D_CMDLINE
, func
, cmdline
));
3414 ret
= exec_cmd(cmdline
, &flist
);
3415 if (ret
!= 0 || check_cmdline(flist
) == BAM_ERROR
) {
3417 bam_error(MULTI_FAIL
, cmdline
);
3418 dump_errormsg(flist
);
3422 filelist_free(&flist
);
3424 newfd
= open(tempname
, O_RDONLY
);
3427 bam_error(OPEN_FAIL
, archive
, strerror(errno
));
3431 ret
= pread64(newfd
, saved_desc
, sizeof (saved_desc
),
3432 VOLDESC_OFF
* CD_BLOCK
);
3433 if (ret
!= sizeof (saved_desc
)) {
3435 bam_error(READ_FAIL
, archive
, strerror(errno
));
3439 if (memcmp(saved_desc
[0].type
, "\1CD001", 6)) {
3441 bam_error(SIGN_FAIL
, archive
);
3445 new_size
= from_733(saved_desc
[0].volume_space_size
) + next_session
;
3446 to_733(saved_desc
[0].volume_space_size
, new_size
);
3448 for (i
= 1; i
< MAX_IVDs
; i
++) {
3449 if (saved_desc
[i
].type
[0] == (unsigned char)255)
3451 if (memcmp(saved_desc
[i
].id
, "CD001", 5))
3455 bam_print("%s: Updating descriptor entry [%d]\n", func
,
3458 to_733(saved_desc
[i
].volume_space_size
, new_size
);
3461 ret
= pwrite64(fd
, saved_desc
, DVD_BLOCK
, VOLDESC_OFF
*CD_BLOCK
);
3462 if (ret
!= DVD_BLOCK
) {
3464 bam_error(WRITE_FAIL
, archive
, strerror(errno
));
3467 (void) close(newfd
);
3477 bam_error(CLOSE_FAIL
, archive
, strerror(errno
));
3482 (void) snprintf(cmdline
, sizeof (cmdline
), "%s if=%s of=%s bs=32k "
3483 "seek=%d conv=sync 2>&1", DD_PATH_USR
, tempname
, archive
,
3486 BAM_DPRINTF((D_CMDLINE
, func
, cmdline
));
3488 ret
= exec_cmd(cmdline
, &flist
);
3489 if (ret
!= 0 || check_cmdline(flist
) == BAM_ERROR
) {
3491 bam_error(MULTI_FAIL
, cmdline
);
3494 filelist_free(&flist
);
3496 (void) unlink(tempname
);
3498 if (flushfs(bam_root
) != 0)
3502 bam_print("boot archive updated successfully\n");
3504 return (BAM_SUCCESS
);
3507 filelist_free(&flist
);
3512 (void) close(newfd
);
3517 create_x86_archive(char *archive
, char *tempname
, char *update_dir
)
3520 char cmdline
[3 * PATH_MAX
+ 64];
3521 filelist_t flist
= {0};
3522 const char *func
= "create_x86_archive()";
3524 (void) snprintf(cmdline
, sizeof (cmdline
), "%s %s -o \"%s\" \"%s\" "
3525 "2>&1", MKISOFS_PATH
, MKISO_PARAMS
, tempname
, update_dir
);
3527 BAM_DPRINTF((D_CMDLINE
, func
, cmdline
));
3529 ret
= exec_cmd(cmdline
, &flist
);
3530 if (ret
!= 0 || check_cmdline(flist
) == BAM_ERROR
) {
3531 bam_error(ARCHIVE_FAIL
, cmdline
);
3532 dump_errormsg(flist
);
3533 filelist_free(&flist
);
3534 (void) unlink(tempname
);
3538 filelist_free(&flist
);
3540 if (check_archive(tempname
) == BAM_ERROR
)
3543 return (do_archive_copy(tempname
, archive
));
3547 mkisofs_archive(char *root
, int what
)
3550 char temp
[PATH_MAX
];
3551 char bootblk
[PATH_MAX
];
3552 char boot_archive
[PATH_MAX
];
3554 if (what
== FILE64
&& !is_flag_on(IS_SPARC_TARGET
))
3555 ret
= snprintf(temp
, sizeof (temp
),
3556 "%s%s%s/amd64/archive-new-%d", root
, ARCHIVE_PREFIX
,
3557 get_machine(), getpid());
3559 ret
= snprintf(temp
, sizeof (temp
), "%s%s%s/archive-new-%d",
3560 root
, ARCHIVE_PREFIX
, get_machine(), getpid());
3562 if (ret
>= sizeof (temp
))
3565 if (what
== FILE64
&& !is_flag_on(IS_SPARC_TARGET
))
3566 ret
= snprintf(boot_archive
, sizeof (boot_archive
),
3567 "%s%s%s/amd64%s", root
, ARCHIVE_PREFIX
, get_machine(),
3570 ret
= snprintf(boot_archive
, sizeof (boot_archive
),
3571 "%s%s%s%s", root
, ARCHIVE_PREFIX
, get_machine(),
3574 if (ret
>= sizeof (boot_archive
))
3577 bam_print("updating %s\n", boot_archive
);
3579 if (is_flag_on(IS_SPARC_TARGET
)) {
3580 ret
= snprintf(bootblk
, sizeof (bootblk
),
3581 "%s/platform/%s/lib/fs/hsfs/bootblk", root
, get_machine());
3582 if (ret
>= sizeof (bootblk
))
3585 ret
= create_sparc_archive(boot_archive
, temp
, bootblk
,
3586 get_cachedir(what
));
3588 if (!is_dir_flag_on(what
, NO_MULTI
)) {
3590 bam_print("Attempting to extend x86 archive: "
3591 "%s\n", boot_archive
);
3593 ret
= extend_iso_archive(boot_archive
, temp
,
3594 get_updatedir(what
));
3595 if (ret
== BAM_SUCCESS
) {
3597 bam_print("Successfully extended %s\n",
3600 (void) rmdir_r(get_updatedir(what
));
3601 return (BAM_SUCCESS
);
3605 * The boot archive will be recreated from scratch. We get here
3606 * if at least one of these conditions is true:
3607 * - bootadm was called without the -e switch
3608 * - the archive (or the archive cache) doesn't exist
3609 * - archive size is bigger than BA_SIZE_MAX
3610 * - more than COUNT_MAX files need to be updated
3611 * - an error occourred either populating the /updates directory
3612 * or extend_iso_archive() failed
3615 bam_print("Unable to extend %s... rebuilding archive\n",
3618 if (get_updatedir(what
)[0] != '\0')
3619 (void) rmdir_r(get_updatedir(what
));
3622 ret
= create_x86_archive(boot_archive
, temp
,
3623 get_cachedir(what
));
3626 if (ret
== BAM_SUCCESS
&& bam_verbose
)
3627 bam_print("Successfully created %s\n", boot_archive
);
3632 bam_error(PATH_TOO_LONG
, root
);
3637 create_ramdisk(char *root
)
3639 char *cmdline
, path
[PATH_MAX
];
3642 int ret
, what
, status
= BAM_SUCCESS
;
3644 /* If there is mkisofs, use it to create the required archives */
3646 for (what
= FILE32
; what
< CACHEDIR_NUM
; what
++) {
3647 if (has_cachedir(what
) && is_dir_flag_on(what
,
3649 ret
= mkisofs_archive(root
, what
);
3658 * Else setup command args for create_ramdisk.ksh for the UFS archives
3661 bam_print("mkisofs not found, creating UFS archive\n");
3663 (void) snprintf(path
, sizeof (path
), "%s/%s", root
, CREATE_RAMDISK
);
3664 if (stat(path
, &sb
) != 0) {
3665 bam_error(ARCH_EXEC_MISS
, path
, strerror(errno
));
3669 if (is_safe_exec(path
) == BAM_ERROR
)
3672 len
= strlen(path
) + strlen(root
) + 10; /* room for space + -R */
3673 if (bam_alt_platform
)
3674 len
+= strlen(bam_platform
) + strlen("-p ");
3675 cmdline
= s_calloc(1, len
);
3677 if (bam_alt_platform
) {
3678 assert(strlen(root
) > 1);
3679 (void) snprintf(cmdline
, len
, "%s -p %s -R %s",
3680 path
, bam_platform
, root
);
3681 /* chop off / at the end */
3682 cmdline
[strlen(cmdline
) - 1] = '\0';
3683 } else if (strlen(root
) > 1) {
3684 (void) snprintf(cmdline
, len
, "%s -R %s", path
, root
);
3685 /* chop off / at the end */
3686 cmdline
[strlen(cmdline
) - 1] = '\0';
3688 (void) snprintf(cmdline
, len
, "%s", path
);
3690 if (exec_cmd(cmdline
, NULL
) != 0) {
3691 bam_error(ARCHIVE_FAIL
, cmdline
);
3697 * The existence of the expected archives used to be
3698 * verified here. This check is done in create_ramdisk as
3699 * it needs to be in sync with the altroot operated upon.
3701 return (BAM_SUCCESS
);
3705 * Checks if target filesystem is on a ramdisk
3708 * When in doubt assume it is not a ramdisk.
3711 is_ramdisk(char *root
)
3713 struct extmnttab mnt
;
3716 char mntpt
[PATH_MAX
];
3720 * There are 3 situations where creating archive is
3722 * - create boot_archive on a lofi-mounted boot_archive
3723 * - create it on a ramdisk which is the root filesystem
3724 * - create it on a ramdisk mounted somewhere else
3725 * The first is not easy to detect and checking for it is not
3727 * The other two conditions are handled here
3729 fp
= fopen(MNTTAB
, "r");
3731 bam_error(OPEN_FAIL
, MNTTAB
, strerror(errno
));
3738 * Remove any trailing / from the mount point
3740 (void) strlcpy(mntpt
, root
, sizeof (mntpt
));
3741 if (strcmp(root
, "/") != 0) {
3742 cp
= mntpt
+ strlen(mntpt
) - 1;
3747 while (getextmntent(fp
, &mnt
, sizeof (mnt
)) == 0) {
3748 if (strcmp(mnt
.mnt_mountp
, mntpt
) == 0) {
3756 bam_error(NOT_IN_MNTTAB
, mntpt
);
3761 if (strncmp(mnt
.mnt_special
, RAMDISK_SPECIAL
,
3762 strlen(RAMDISK_SPECIAL
)) == 0) {
3764 bam_error(IS_RAMDISK
, bam_root
);
3775 is_boot_archive(char *root
)
3777 char path
[PATH_MAX
];
3780 const char *fcn
= "is_boot_archive()";
3783 * We can't create an archive without the create_ramdisk script
3785 (void) snprintf(path
, sizeof (path
), "%s/%s", root
, CREATE_RAMDISK
);
3786 error
= stat(path
, &sb
);
3787 INJECT_ERROR1("NOT_ARCHIVE_BASED", error
= -1);
3790 bam_print(FILE_MISS
, path
);
3791 BAM_DPRINTF((D_NOT_ARCHIVE_BOOT
, fcn
, root
));
3795 BAM_DPRINTF((D_IS_ARCHIVE_BOOT
, fcn
, root
));
3800 * Need to call this for anything that operates on the GRUB menu
3801 * In the x86 live upgrade case the directory /boot/grub may be present
3802 * even on pre-newboot BEs. The authoritative way to check for a GRUB target
3803 * is to check for the presence of the stage2 binary which is present
3804 * only on GRUB targets (even on x86 boot partitions). Checking for the
3805 * presence of the multiboot binary is not correct as it is not present
3806 * on x86 boot partitions.
3809 is_grub(const char *root
)
3811 char path
[PATH_MAX
];
3813 const char *fcn
= "is_grub()";
3815 (void) snprintf(path
, sizeof (path
), "%s%s", root
, GRUB_STAGE2
);
3816 if (stat(path
, &sb
) == -1) {
3817 BAM_DPRINTF((D_NO_GRUB_DIR
, fcn
, path
));
3829 const char *fcn
= "is_zfs()";
3831 ret
= statvfs(root
, &vfs
);
3832 INJECT_ERROR1("STATVFS_ZFS", ret
= 1);
3834 bam_error(STATVFS_FAIL
, root
, strerror(errno
));
3838 if (strncmp(vfs
.f_basetype
, "zfs", strlen("zfs")) == 0) {
3839 BAM_DPRINTF((D_IS_ZFS
, fcn
, root
));
3842 BAM_DPRINTF((D_IS_NOT_ZFS
, fcn
, root
));
3852 const char *fcn
= "is_ufs()";
3854 ret
= statvfs(root
, &vfs
);
3855 INJECT_ERROR1("STATVFS_UFS", ret
= 1);
3857 bam_error(STATVFS_FAIL
, root
, strerror(errno
));
3861 if (strncmp(vfs
.f_basetype
, "ufs", strlen("ufs")) == 0) {
3862 BAM_DPRINTF((D_IS_UFS
, fcn
, root
));
3865 BAM_DPRINTF((D_IS_NOT_UFS
, fcn
, root
));
3875 const char *fcn
= "is_pcfs()";
3877 ret
= statvfs(root
, &vfs
);
3878 INJECT_ERROR1("STATVFS_PCFS", ret
= 1);
3880 bam_error(STATVFS_FAIL
, root
, strerror(errno
));
3884 if (strncmp(vfs
.f_basetype
, "pcfs", strlen("pcfs")) == 0) {
3885 BAM_DPRINTF((D_IS_PCFS
, fcn
, root
));
3888 BAM_DPRINTF((D_IS_NOT_PCFS
, fcn
, root
));
3894 is_readonly(char *root
)
3898 char testfile
[PATH_MAX
];
3899 const char *fcn
= "is_readonly()";
3902 * Using statvfs() to check for a read-only filesystem is not
3903 * reliable. The only way to reliably test is to attempt to
3906 (void) snprintf(testfile
, sizeof (testfile
), "%s/%s.%d",
3907 root
, BOOTADM_RDONLY_TEST
, getpid());
3909 (void) unlink(testfile
);
3912 fd
= open(testfile
, O_RDWR
|O_CREAT
|O_EXCL
, 0644);
3914 INJECT_ERROR2("RDONLY_TEST_ERROR", fd
= -1, error
= EACCES
);
3915 if (fd
== -1 && error
== EROFS
) {
3916 BAM_DPRINTF((D_RDONLY_FS
, fcn
, root
));
3918 } else if (fd
== -1) {
3919 bam_error(RDONLY_TEST_ERROR
, root
, strerror(error
));
3923 (void) unlink(testfile
);
3925 BAM_DPRINTF((D_RDWR_FS
, fcn
, root
));
3930 update_archive(char *root
, char *opt
)
3935 assert(opt
== NULL
);
3941 * Never update non-BE root in update_all
3943 if (!is_be(root
) && bam_update_all
)
3944 return (BAM_SUCCESS
);
3946 * root must belong to a boot archive based OS,
3948 if (!is_boot_archive(root
)) {
3950 * Emit message only if not in context of update_all.
3951 * If in update_all, emit only if verbose flag is set.
3953 if (!bam_update_all
|| bam_verbose
)
3954 bam_print(NOT_ARCHIVE_BOOT
, root
);
3959 * If smf check is requested when / is writable (can happen
3960 * on first reboot following an upgrade because service
3961 * dependency is messed up), skip the check.
3963 if (bam_smf_check
&& !bam_root_readonly
&& !is_zfs(root
))
3964 return (BAM_SUCCESS
);
3967 * Don't generate archive on ramdisk.
3969 if (is_ramdisk(root
))
3970 return (BAM_SUCCESS
);
3973 * root must be writable. This check applies to alternate
3974 * root (-R option); bam_root_readonly applies to '/' only.
3975 * The behaviour translates into being the one of a 'check'.
3977 if (!bam_smf_check
&& !bam_check
&& is_readonly(root
)) {
3978 set_flag(RDONLY_FSCHK
);
3983 * Now check if an update is really needed.
3985 ret
= update_required(root
);
3988 * The check command (-n) is *not* a dry run.
3989 * It only checks if the archive is in sync.
3990 * A readonly filesystem has to be considered an error only if an update
3993 if (bam_nowrite()) {
3994 if (is_flag_on(RDONLY_FSCHK
)) {
3995 bam_check
= bam_saved_check
;
3997 bam_error(RDONLY_FS
, root
);
3999 return ((ret
!= 0) ? BAM_ERROR
: BAM_SUCCESS
);
4002 bam_exit((ret
!= 0) ? 1 : 0);
4006 /* create the ramdisk */
4007 ret
= create_ramdisk(root
);
4011 * if the archive is updated, save the new stat data and update the
4014 if (ret
== 0 && walk_arg
.new_nvlp
!= NULL
) {
4016 update_timestamp(root
);
4027 char *special
= get_special("/");
4030 if (special
== NULL
)
4033 if (*special
== '/') {
4038 if ((p
= strchr(special
, '/')) != NULL
)
4045 synchronize_BE_menu(void)
4048 char cmdline
[PATH_MAX
];
4049 char cksum_line
[PATH_MAX
];
4050 filelist_t flist
= {0};
4051 char *old_cksum_str
;
4054 char *curr_cksum_str
;
4055 char *curr_size_str
;
4063 const char *fcn
= "synchronize_BE_menu()";
4065 BAM_DPRINTF((D_FUNC_ENTRY0
, fcn
));
4067 /* Check if findroot enabled LU BE */
4068 if (stat(FINDROOT_INSTALLGRUB
, &sb
) != 0) {
4069 BAM_DPRINTF((D_NOT_LU_BE
, fcn
));
4070 return (BAM_SUCCESS
);
4073 if (stat(LU_MENU_CKSUM
, &sb
) != 0) {
4074 BAM_DPRINTF((D_NO_CKSUM_FILE
, fcn
, LU_MENU_CKSUM
));
4078 cfp
= fopen(LU_MENU_CKSUM
, "r");
4079 INJECT_ERROR1("CKSUM_FILE_MISSING", cfp
= NULL
);
4081 bam_error(CANNOT_READ_LU_CKSUM
, LU_MENU_CKSUM
);
4084 BAM_DPRINTF((D_CKSUM_FILE_OPENED
, fcn
, LU_MENU_CKSUM
));
4087 while (s_fgets(cksum_line
, sizeof (cksum_line
), cfp
) != NULL
) {
4088 INJECT_ERROR1("MULTIPLE_CKSUM", found
= 1);
4090 bam_error(MULTIPLE_LU_CKSUM
, LU_MENU_CKSUM
);
4096 BAM_DPRINTF((D_CKSUM_FILE_READ
, fcn
, LU_MENU_CKSUM
));
4099 old_cksum_str
= strtok(cksum_line
, " \t");
4100 old_size_str
= strtok(NULL
, " \t");
4101 old_file
= strtok(NULL
, " \t");
4103 INJECT_ERROR1("OLD_CKSUM_NULL", old_cksum_str
= NULL
);
4104 INJECT_ERROR1("OLD_SIZE_NULL", old_size_str
= NULL
);
4105 INJECT_ERROR1("OLD_FILE_NULL", old_file
= NULL
);
4106 if (old_cksum_str
== NULL
|| old_size_str
== NULL
|| old_file
== NULL
) {
4107 bam_error(CANNOT_PARSE_LU_CKSUM
, LU_MENU_CKSUM
);
4110 BAM_DPRINTF((D_CKSUM_FILE_PARSED
, fcn
, LU_MENU_CKSUM
));
4112 /* Get checksum of current menu */
4113 pool
= find_root_pool();
4115 mntpt
= mount_top_dataset(pool
, &mnted
);
4116 if (mntpt
== NULL
) {
4117 bam_error(FAIL_MNT_TOP_DATASET
, pool
);
4121 (void) snprintf(cmdline
, sizeof (cmdline
), "%s %s%s",
4122 CKSUM
, mntpt
, GRUB_MENU
);
4124 (void) snprintf(cmdline
, sizeof (cmdline
), "%s %s",
4127 ret
= exec_cmd(cmdline
, &flist
);
4129 (void) umount_top_dataset(pool
, mnted
, mntpt
);
4132 INJECT_ERROR1("GET_CURR_CKSUM", ret
= 1);
4134 bam_error(MENU_CKSUM_FAIL
);
4137 BAM_DPRINTF((D_CKSUM_GEN_SUCCESS
, fcn
));
4139 INJECT_ERROR1("GET_CURR_CKSUM_OUTPUT", flist
.head
= NULL
);
4140 if ((flist
.head
== NULL
) || (flist
.head
!= flist
.tail
)) {
4141 bam_error(BAD_CKSUM
);
4142 filelist_free(&flist
);
4145 BAM_DPRINTF((D_CKSUM_GEN_OUTPUT_VALID
, fcn
));
4147 curr_cksum_str
= strtok(flist
.head
->line
, " \t");
4148 curr_size_str
= strtok(NULL
, " \t");
4149 curr_file
= strtok(NULL
, " \t");
4151 INJECT_ERROR1("CURR_CKSUM_NULL", curr_cksum_str
= NULL
);
4152 INJECT_ERROR1("CURR_SIZE_NULL", curr_size_str
= NULL
);
4153 INJECT_ERROR1("CURR_FILE_NULL", curr_file
= NULL
);
4154 if (curr_cksum_str
== NULL
|| curr_size_str
== NULL
||
4155 curr_file
== NULL
) {
4156 bam_error(BAD_CKSUM_PARSE
);
4157 filelist_free(&flist
);
4160 BAM_DPRINTF((D_CKSUM_GEN_PARSED
, fcn
));
4162 if (strcmp(old_cksum_str
, curr_cksum_str
) == 0 &&
4163 strcmp(old_size_str
, curr_size_str
) == 0 &&
4164 strcmp(old_file
, curr_file
) == 0) {
4165 filelist_free(&flist
);
4166 BAM_DPRINTF((D_CKSUM_NO_CHANGE
, fcn
));
4167 return (BAM_SUCCESS
);
4170 filelist_free(&flist
);
4172 /* cksum doesn't match - the menu has changed */
4173 BAM_DPRINTF((D_CKSUM_HAS_CHANGED
, fcn
));
4176 bam_print(PROP_GRUB_MENU
);
4178 (void) snprintf(cmdline
, sizeof (cmdline
),
4179 "/bin/sh -c '. %s > /dev/null; %s %s yes > /dev/null'",
4180 LULIB
, LULIB_PROPAGATE_FILE
, GRUB_MENU
);
4181 ret
= exec_cmd(cmdline
, NULL
);
4182 INJECT_ERROR1("PROPAGATE_MENU", ret
= 1);
4184 bam_error(MENU_PROP_FAIL
);
4187 BAM_DPRINTF((D_PROPAGATED_MENU
, fcn
));
4189 (void) snprintf(cmdline
, sizeof (cmdline
), "/bin/cp %s %s > /dev/null",
4190 GRUB_MENU
, GRUB_BACKUP_MENU
);
4191 ret
= exec_cmd(cmdline
, NULL
);
4192 INJECT_ERROR1("CREATE_BACKUP", ret
= 1);
4194 bam_error(MENU_BACKUP_FAIL
, GRUB_BACKUP_MENU
);
4197 BAM_DPRINTF((D_CREATED_BACKUP
, fcn
, GRUB_BACKUP_MENU
));
4199 (void) snprintf(cmdline
, sizeof (cmdline
),
4200 "/bin/sh -c '. %s > /dev/null; %s %s no > /dev/null'",
4201 LULIB
, LULIB_PROPAGATE_FILE
, GRUB_BACKUP_MENU
);
4202 ret
= exec_cmd(cmdline
, NULL
);
4203 INJECT_ERROR1("PROPAGATE_BACKUP", ret
= 1);
4205 bam_error(BACKUP_PROP_FAIL
, GRUB_BACKUP_MENU
);
4208 BAM_DPRINTF((D_PROPAGATED_BACKUP
, fcn
, GRUB_BACKUP_MENU
));
4210 (void) snprintf(cmdline
, sizeof (cmdline
), "%s %s > %s",
4211 CKSUM
, GRUB_MENU
, LU_MENU_CKSUM
);
4212 ret
= exec_cmd(cmdline
, NULL
);
4213 INJECT_ERROR1("CREATE_CKSUM_FILE", ret
= 1);
4215 bam_error(MENU_CKSUM_WRITE_FAIL
, LU_MENU_CKSUM
);
4218 BAM_DPRINTF((D_CREATED_CKSUM_FILE
, fcn
, LU_MENU_CKSUM
));
4220 (void) snprintf(cmdline
, sizeof (cmdline
),
4221 "/bin/sh -c '. %s > /dev/null; %s %s no > /dev/null'",
4222 LULIB
, LULIB_PROPAGATE_FILE
, LU_MENU_CKSUM
);
4223 ret
= exec_cmd(cmdline
, NULL
);
4224 INJECT_ERROR1("PROPAGATE_MENU_CKSUM_FILE", ret
= 1);
4226 bam_error(MENU_CKSUM_PROP_FAIL
, LU_MENU_CKSUM
);
4229 BAM_DPRINTF((D_PROPAGATED_CKSUM_FILE
, fcn
, LU_MENU_CKSUM
));
4231 return (BAM_SUCCESS
);
4235 update_all(char *root
, char *opt
)
4237 struct extmnttab mnt
;
4240 char multibt
[PATH_MAX
];
4241 char creatram
[PATH_MAX
];
4242 error_t ret
= BAM_SUCCESS
;
4245 assert(opt
== NULL
);
4247 if (bam_rootlen
!= 1 || *root
!= '/') {
4248 elide_trailing_slash(root
, multibt
, sizeof (multibt
));
4249 bam_error(ALT_ROOT_INVALID
, multibt
);
4254 * First update archive for current root
4256 if (update_archive(root
, opt
) != BAM_SUCCESS
)
4259 if (ret
== BAM_ERROR
)
4263 * Now walk the mount table, performing archive update
4264 * for all mounted Newboot root filesystems
4266 fp
= fopen(MNTTAB
, "r");
4268 bam_error(OPEN_FAIL
, MNTTAB
, strerror(errno
));
4275 while (getextmntent(fp
, &mnt
, sizeof (mnt
)) == 0) {
4276 if (mnt
.mnt_special
== NULL
)
4278 if ((strcmp(mnt
.mnt_fstype
, MNTTYPE_ZFS
) != 0) &&
4279 (strncmp(mnt
.mnt_special
, "/dev/", strlen("/dev/")) != 0))
4281 if (strcmp(mnt
.mnt_mountp
, "/") == 0)
4284 (void) snprintf(creatram
, sizeof (creatram
), "%s/%s",
4285 mnt
.mnt_mountp
, CREATE_RAMDISK
);
4287 if (stat(creatram
, &sb
) == -1)
4291 * We put a trailing slash to be consistent with root = "/"
4292 * case, such that we don't have to print // in some cases.
4294 (void) snprintf(rootbuf
, sizeof (rootbuf
), "%s/",
4296 bam_rootlen
= strlen(rootbuf
);
4299 * It's possible that other mounts may be an alternate boot
4300 * architecture, so check it again.
4302 if ((get_boot_cap(rootbuf
) != BAM_SUCCESS
) ||
4303 (update_archive(rootbuf
, opt
) != BAM_SUCCESS
))
4311 * We no longer use biosdev for Live Upgrade. Hence
4312 * there is no need to defer (to shutdown time) any fdisk
4315 if (stat(GRUB_fdisk
, &sb
) == 0 || stat(GRUB_fdisk_target
, &sb
) == 0) {
4316 bam_error(FDISK_FILES_FOUND
, GRUB_fdisk
, GRUB_fdisk_target
);
4320 * If user has updated menu in current BE, propagate the
4321 * updates to all BEs.
4323 if (sync_menu
&& synchronize_BE_menu() != BAM_SUCCESS
)
4330 append_line(menu_t
*mp
, line_t
*lp
)
4332 if (mp
->start
== NULL
) {
4342 unlink_line(menu_t
*mp
, line_t
*lp
)
4344 /* unlink from list */
4346 lp
->prev
->next
= lp
->next
;
4348 mp
->start
= lp
->next
;
4350 lp
->next
->prev
= lp
->prev
;
4356 boot_entry_new(menu_t
*mp
, line_t
*start
, line_t
*end
)
4358 entry_t
*ent
, *prev
;
4359 const char *fcn
= "boot_entry_new()";
4365 ent
= s_calloc(1, sizeof (entry_t
));
4366 BAM_DPRINTF((D_ENTRY_NEW
, fcn
));
4370 if (mp
->entries
== NULL
) {
4372 BAM_DPRINTF((D_ENTRY_NEW_FIRST
, fcn
));
4381 BAM_DPRINTF((D_ENTRY_NEW_LINKED
, fcn
));
4386 boot_entry_addline(entry_t
*ent
, line_t
*lp
)
4393 * Check whether cmd matches the one indexed by which, and whether arg matches
4394 * str. which must be either KERNEL_CMD or MODULE_CMD, and a match to the
4395 * respective *_DOLLAR_CMD is also acceptable. The arg is searched using
4396 * strstr(), so it can be a partial match.
4399 check_cmd(const char *cmd
, const int which
, const char *arg
, const char *str
)
4402 const char *fcn
= "check_cmd()";
4404 BAM_DPRINTF((D_FUNC_ENTRY2
, fcn
, arg
, str
));
4407 if ((strcmp(cmd
, menu_cmds
[which
]) != 0) &&
4408 (strcmp(cmd
, menu_cmds
[which
+ 1]) != 0)) {
4409 BAM_DPRINTF((D_CHECK_CMD_CMD_NOMATCH
,
4410 fcn
, cmd
, menu_cmds
[which
]));
4413 ret
= (strstr(arg
, str
) != NULL
);
4418 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
4420 BAM_DPRINTF((D_RETURN_FAILURE
, fcn
));
4427 kernel_parser(entry_t
*entry
, char *cmd
, char *arg
, int linenum
)
4429 const char *fcn
= "kernel_parser()";
4435 if (strcmp(cmd
, menu_cmds
[KERNEL_CMD
]) != 0 &&
4436 strcmp(cmd
, menu_cmds
[KERNEL_DOLLAR_CMD
]) != 0) {
4437 BAM_DPRINTF((D_NOT_KERNEL_CMD
, fcn
, cmd
));
4441 if (strncmp(arg
, DIRECT_BOOT_32
, sizeof (DIRECT_BOOT_32
) - 1) == 0) {
4442 BAM_DPRINTF((D_SET_DBOOT_32
, fcn
, arg
));
4443 entry
->flags
|= BAM_ENTRY_DBOOT
| BAM_ENTRY_32BIT
;
4444 } else if (strncmp(arg
, DIRECT_BOOT_KERNEL
,
4445 sizeof (DIRECT_BOOT_KERNEL
) - 1) == 0) {
4446 BAM_DPRINTF((D_SET_DBOOT
, fcn
, arg
));
4447 entry
->flags
|= BAM_ENTRY_DBOOT
;
4448 } else if (strncmp(arg
, DIRECT_BOOT_64
,
4449 sizeof (DIRECT_BOOT_64
) - 1) == 0) {
4450 BAM_DPRINTF((D_SET_DBOOT_64
, fcn
, arg
));
4451 entry
->flags
|= BAM_ENTRY_DBOOT
| BAM_ENTRY_64BIT
;
4452 } else if (strncmp(arg
, DIRECT_BOOT_FAILSAFE_KERNEL
,
4453 sizeof (DIRECT_BOOT_FAILSAFE_KERNEL
) - 1) == 0) {
4454 BAM_DPRINTF((D_SET_DBOOT_FAILSAFE
, fcn
, arg
));
4455 entry
->flags
|= BAM_ENTRY_DBOOT
| BAM_ENTRY_FAILSAFE
;
4456 } else if (strncmp(arg
, DIRECT_BOOT_FAILSAFE_32
,
4457 sizeof (DIRECT_BOOT_FAILSAFE_32
) - 1) == 0) {
4458 BAM_DPRINTF((D_SET_DBOOT_FAILSAFE_32
, fcn
, arg
));
4459 entry
->flags
|= BAM_ENTRY_DBOOT
| BAM_ENTRY_FAILSAFE
4461 } else if (strncmp(arg
, DIRECT_BOOT_FAILSAFE_64
,
4462 sizeof (DIRECT_BOOT_FAILSAFE_64
) - 1) == 0) {
4463 BAM_DPRINTF((D_SET_DBOOT_FAILSAFE_64
, fcn
, arg
));
4464 entry
->flags
|= BAM_ENTRY_DBOOT
| BAM_ENTRY_FAILSAFE
4466 } else if (strncmp(arg
, MULTI_BOOT
, sizeof (MULTI_BOOT
) - 1) == 0) {
4467 BAM_DPRINTF((D_SET_MULTIBOOT
, fcn
, arg
));
4468 entry
->flags
|= BAM_ENTRY_MULTIBOOT
;
4469 } else if (strncmp(arg
, MULTI_BOOT_FAILSAFE
,
4470 sizeof (MULTI_BOOT_FAILSAFE
) - 1) == 0) {
4471 BAM_DPRINTF((D_SET_MULTIBOOT_FAILSAFE
, fcn
, arg
));
4472 entry
->flags
|= BAM_ENTRY_MULTIBOOT
| BAM_ENTRY_FAILSAFE
;
4473 } else if (strstr(arg
, XEN_KERNEL_SUBSTR
)) {
4474 BAM_DPRINTF((D_SET_HV
, fcn
, arg
));
4475 entry
->flags
|= BAM_ENTRY_HV
;
4476 } else if (!(entry
->flags
& (BAM_ENTRY_BOOTADM
|BAM_ENTRY_LU
))) {
4477 BAM_DPRINTF((D_SET_HAND_KERNEL
, fcn
, arg
));
4479 } else if (strncmp(arg
, KERNEL_PREFIX
, strlen(KERNEL_PREFIX
)) == 0 &&
4480 strstr(arg
, UNIX_SPACE
)) {
4481 entry
->flags
|= BAM_ENTRY_DBOOT
| BAM_ENTRY_32BIT
;
4482 } else if (strncmp(arg
, KERNEL_PREFIX
, strlen(KERNEL_PREFIX
)) == 0 &&
4483 strstr(arg
, AMD_UNIX_SPACE
)) {
4484 entry
->flags
|= BAM_ENTRY_DBOOT
| BAM_ENTRY_64BIT
;
4486 BAM_DPRINTF((D_IS_UNKNOWN_KERNEL
, fcn
, arg
));
4487 bam_error(UNKNOWN_KERNEL_LINE
, linenum
);
4491 return (BAM_SUCCESS
);
4495 module_parser(entry_t
*entry
, char *cmd
, char *arg
, int linenum
)
4497 const char *fcn
= "module_parser()";
4503 if (strcmp(cmd
, menu_cmds
[MODULE_CMD
]) != 0 &&
4504 strcmp(cmd
, menu_cmds
[MODULE_DOLLAR_CMD
]) != 0) {
4505 BAM_DPRINTF((D_NOT_MODULE_CMD
, fcn
, cmd
));
4509 if (strcmp(arg
, DIRECT_BOOT_ARCHIVE
) == 0 ||
4510 strcmp(arg
, DIRECT_BOOT_ARCHIVE_32
) == 0 ||
4511 strcmp(arg
, DIRECT_BOOT_ARCHIVE_64
) == 0 ||
4512 strcmp(arg
, MULTIBOOT_ARCHIVE
) == 0 ||
4513 strcmp(arg
, FAILSAFE_ARCHIVE
) == 0 ||
4514 strcmp(arg
, FAILSAFE_ARCHIVE_32
) == 0 ||
4515 strcmp(arg
, FAILSAFE_ARCHIVE_64
) == 0 ||
4516 strcmp(arg
, XEN_KERNEL_MODULE_LINE
) == 0 ||
4517 strcmp(arg
, XEN_KERNEL_MODULE_LINE_ZFS
) == 0) {
4518 BAM_DPRINTF((D_BOOTADM_LU_MODULE
, fcn
, arg
));
4519 return (BAM_SUCCESS
);
4520 } else if (!(entry
->flags
& BAM_ENTRY_BOOTADM
) &&
4521 !(entry
->flags
& BAM_ENTRY_LU
)) {
4522 /* don't emit warning for hand entries */
4523 BAM_DPRINTF((D_IS_HAND_MODULE
, fcn
, arg
));
4526 BAM_DPRINTF((D_IS_UNKNOWN_MODULE
, fcn
, arg
));
4527 bam_error(UNKNOWN_MODULE_LINE
, linenum
);
4533 * A line in menu.lst looks like
4534 * [ ]*<cmd>[ \t=]*<arg>*
4537 line_parser(menu_t
*mp
, char *str
, int *lineNum
, int *entryNum
)
4540 * save state across calls. This is so that
4541 * header gets the right entry# after title has
4544 static line_t
*prev
= NULL
;
4545 static entry_t
*curr_ent
= NULL
;
4546 static int in_liveupgrade
= 0;
4547 static int is_libbe_ent
= 0;
4550 char *cmd
, *sep
, *arg
;
4551 char save
, *cp
, *line
;
4552 menu_flag_t flag
= BAM_INVALID
;
4553 const char *fcn
= "line_parser()";
4561 * First save a copy of the entire line.
4562 * We use this later to set the line field.
4564 line
= s_strdup(str
);
4566 /* Eat up leading whitespace */
4567 while (*str
== ' ' || *str
== '\t')
4570 if (*str
== '#') { /* comment */
4571 cmd
= s_strdup("#");
4573 arg
= s_strdup(str
+ 1);
4575 if (strstr(arg
, BAM_LU_HDR
) != NULL
) {
4577 } else if (strstr(arg
, BAM_LU_FTR
) != NULL
) {
4579 } else if (strstr(arg
, BAM_LIBBE_FTR
) != NULL
) {
4582 } else if (*str
== '\0') { /* blank line */
4583 cmd
= sep
= arg
= NULL
;
4587 * '=' is not a documented separator in grub syntax.
4588 * However various development bits use '=' as a
4589 * separator. In addition, external users also
4590 * use = as a separator. So we will allow that usage.
4593 while (*str
!= ' ' && *str
!= '\t' && *str
!= '=') {
4611 sep
= s_strdup(str
- 1);
4614 while (*str
== ' ' || *str
== '\t')
4619 arg
= s_strdup(str
);
4623 lp
= s_calloc(1, sizeof (line_t
));
4629 lp
->lineNum
= ++(*lineNum
);
4630 if (cmd
&& strcmp(cmd
, menu_cmds
[TITLE_CMD
]) == 0) {
4631 lp
->entryNum
= ++(*entryNum
);
4632 lp
->flags
= BAM_TITLE
;
4633 if (prev
&& prev
->flags
== BAM_COMMENT
&&
4634 prev
->arg
&& strcmp(prev
->arg
, BAM_BOOTADM_HDR
) == 0) {
4635 prev
->entryNum
= lp
->entryNum
;
4636 curr_ent
= boot_entry_new(mp
, prev
, lp
);
4637 curr_ent
->flags
|= BAM_ENTRY_BOOTADM
;
4638 BAM_DPRINTF((D_IS_BOOTADM_ENTRY
, fcn
, arg
));
4640 curr_ent
= boot_entry_new(mp
, lp
, lp
);
4641 if (in_liveupgrade
) {
4642 curr_ent
->flags
|= BAM_ENTRY_LU
;
4643 BAM_DPRINTF((D_IS_LU_ENTRY
, fcn
, arg
));
4646 curr_ent
->entryNum
= *entryNum
;
4647 } else if (flag
!= BAM_INVALID
) {
4649 * For header comments, the entry# is "fixed up"
4650 * by the subsequent title
4652 lp
->entryNum
= *entryNum
;
4655 lp
->entryNum
= *entryNum
;
4657 if (*entryNum
== ENTRY_INIT
) {
4658 lp
->flags
= BAM_GLOBAL
;
4660 lp
->flags
= BAM_ENTRY
;
4663 if (strcmp(cmd
, menu_cmds
[ROOT_CMD
]) == 0) {
4664 BAM_DPRINTF((D_IS_ROOT_CMD
, fcn
, arg
));
4665 curr_ent
->flags
|= BAM_ENTRY_ROOT
;
4666 } else if (strcmp(cmd
, menu_cmds
[FINDROOT_CMD
])
4668 BAM_DPRINTF((D_IS_FINDROOT_CMD
, fcn
,
4670 curr_ent
->flags
|= BAM_ENTRY_FINDROOT
;
4671 } else if (strcmp(cmd
,
4672 menu_cmds
[CHAINLOADER_CMD
]) == 0) {
4673 BAM_DPRINTF((D_IS_CHAINLOADER_CMD
, fcn
,
4676 BAM_ENTRY_CHAINLOADER
;
4677 } else if (kernel_parser(curr_ent
, cmd
, arg
,
4678 lp
->lineNum
) != BAM_SUCCESS
) {
4679 (void) module_parser(curr_ent
, cmd
,
4686 /* record default, old default, and entry line ranges */
4687 if (lp
->flags
== BAM_GLOBAL
&& lp
->cmd
!= NULL
&&
4688 strcmp(lp
->cmd
, menu_cmds
[DEFAULT_CMD
]) == 0) {
4689 mp
->curdefault
= lp
;
4690 } else if (lp
->flags
== BAM_COMMENT
&&
4691 strncmp(lp
->arg
, BAM_OLDDEF
, strlen(BAM_OLDDEF
)) == 0) {
4692 mp
->olddefault
= lp
;
4693 } else if (lp
->flags
== BAM_COMMENT
&&
4694 strncmp(lp
->arg
, BAM_OLD_RC_DEF
, strlen(BAM_OLD_RC_DEF
)) == 0) {
4695 mp
->old_rc_default
= lp
;
4696 } else if (lp
->flags
== BAM_ENTRY
||
4697 (lp
->flags
== BAM_COMMENT
&&
4698 ((strcmp(lp
->arg
, BAM_BOOTADM_FTR
) == 0) || is_libbe_ent
))) {
4700 curr_ent
->flags
|= BAM_ENTRY_LIBBE
;
4704 boot_entry_addline(curr_ent
, lp
);
4706 append_line(mp
, lp
);
4712 update_numbering(menu_t
*mp
)
4716 int old_default_value
;
4717 line_t
*lp
, *prev
, *default_lp
, *default_entry
;
4720 if (mp
->start
== NULL
) {
4724 lineNum
= LINE_INIT
;
4725 entryNum
= ENTRY_INIT
;
4726 old_default_value
= ENTRY_INIT
;
4727 lp
= default_lp
= default_entry
= NULL
;
4730 for (lp
= mp
->start
; lp
; prev
= lp
, lp
= lp
->next
) {
4731 lp
->lineNum
= ++lineNum
;
4734 * Get the value of the default command
4736 if (lp
->entryNum
== ENTRY_INIT
&& lp
->cmd
!= NULL
&&
4737 strcmp(lp
->cmd
, menu_cmds
[DEFAULT_CMD
]) == 0 &&
4739 old_default_value
= atoi(lp
->arg
);
4744 * If not a booting entry, nothing else to fix for this
4747 if (lp
->entryNum
== ENTRY_INIT
)
4751 * Record the position of the default entry.
4752 * The following works because global
4753 * commands like default and timeout should precede
4754 * actual boot entries, so old_default_value
4755 * is already known (or default cmd is missing).
4757 if (default_entry
== NULL
&&
4758 old_default_value
!= ENTRY_INIT
&&
4759 lp
->entryNum
== old_default_value
) {
4764 * Now fixup the entry number
4766 if (lp
->cmd
!= NULL
&&
4767 strcmp(lp
->cmd
, menu_cmds
[TITLE_CMD
]) == 0) {
4768 lp
->entryNum
= ++entryNum
;
4769 /* fixup the bootadm header */
4770 if (prev
&& prev
->flags
== BAM_COMMENT
&&
4772 strcmp(prev
->arg
, BAM_BOOTADM_HDR
) == 0) {
4773 prev
->entryNum
= lp
->entryNum
;
4776 lp
->entryNum
= entryNum
;
4781 * No default command in menu, simply return
4783 if (default_lp
== NULL
) {
4787 free(default_lp
->arg
);
4788 free(default_lp
->line
);
4790 if (default_entry
== NULL
) {
4791 default_lp
->arg
= s_strdup("0");
4793 (void) snprintf(buf
, sizeof (buf
), "%d",
4794 default_entry
->entryNum
);
4795 default_lp
->arg
= s_strdup(buf
);
4799 * The following is required since only the line field gets
4800 * written back to menu.lst
4802 (void) snprintf(buf
, sizeof (buf
), "%s%s%s",
4803 menu_cmds
[DEFAULT_CMD
], menu_cmds
[SEP_CMD
], default_lp
->arg
);
4804 default_lp
->line
= s_strdup(buf
);
4809 menu_read(char *menu_path
)
4812 char buf
[BAM_MAXLINE
], *cp
;
4814 int line
, entry
, len
, n
;
4816 mp
= s_calloc(1, sizeof (menu_t
));
4818 fp
= fopen(menu_path
, "r");
4819 if (fp
== NULL
) { /* Let the caller handle this error */
4824 /* Note: GRUB boot entry number starts with 0 */
4829 while (s_fgets(cp
, len
, fp
) != NULL
) {
4831 if (cp
[n
- 1] == '\\') {
4837 line_parser(mp
, buf
, &line
, &entry
);
4842 if (fclose(fp
) == EOF
) {
4843 bam_error(CLOSE_FAIL
, menu_path
, strerror(errno
));
4850 selector(menu_t
*mp
, char *opt
, int *entry
, char **title
)
4860 opt_dup
= s_strdup(opt
);
4863 *entry
= ENTRY_INIT
;
4867 eq
= strchr(opt_dup
, '=');
4869 bam_error(INVALID_OPT
, opt
);
4875 if (entry
&& strcmp(opt_dup
, OPT_ENTRY_NUM
) == 0) {
4877 entryNum
= s_strtol(eq
+ 1);
4878 if (entryNum
< 0 || entryNum
> mp
->end
->entryNum
) {
4879 bam_error(INVALID_ENTRY
, eq
+ 1);
4884 } else if (title
&& strcmp(opt_dup
, menu_cmds
[TITLE_CMD
]) == 0) {
4885 *title
= opt
+ (eq
- opt_dup
) + 1;
4887 bam_error(INVALID_OPT
, opt
);
4893 return (BAM_SUCCESS
);
4897 * If invoked with no titles/entries (opt == NULL)
4898 * only title lines in file are printed.
4900 * If invoked with a title or entry #, all
4901 * lines in *every* matching entry are listed
4904 list_entry(menu_t
*mp
, char *menu_path
, char *opt
)
4907 int entry
= ENTRY_INIT
;
4914 /* opt is optional */
4915 BAM_DPRINTF((D_FUNC_ENTRY2
, "list_entry", menu_path
,
4916 opt
? opt
: "<NULL>"));
4918 if (mp
->start
== NULL
) {
4919 bam_error(NO_MENU
, menu_path
);
4924 if (selector(mp
, opt
, &entry
, &title
) != BAM_SUCCESS
) {
4927 assert((entry
!= ENTRY_INIT
) ^ (title
!= NULL
));
4929 (void) read_globals(mp
, menu_path
, menu_cmds
[DEFAULT_CMD
], 0);
4930 (void) read_globals(mp
, menu_path
, menu_cmds
[TIMEOUT_CMD
], 0);
4934 for (lp
= mp
->start
; lp
; lp
= lp
->next
) {
4935 if (lp
->flags
== BAM_COMMENT
|| lp
->flags
== BAM_EMPTY
)
4937 if (opt
== NULL
&& lp
->flags
== BAM_TITLE
) {
4938 bam_print(PRINT_TITLE
, lp
->entryNum
,
4943 if (entry
!= ENTRY_INIT
&& lp
->entryNum
== entry
) {
4944 bam_print(PRINT
, lp
->line
);
4950 * We set the entry value here so that all lines
4951 * in entry get printed. If we subsequently match
4952 * title in other entries, all lines in those
4953 * entries get printed as well.
4955 if (title
&& lp
->flags
== BAM_TITLE
&& lp
->arg
&&
4956 strncmp(title
, lp
->arg
, strlen(title
)) == 0) {
4957 bam_print(PRINT
, lp
->line
);
4958 entry
= lp
->entryNum
;
4965 bam_error(NO_MATCH_ENTRY
);
4969 return (BAM_SUCCESS
);
4973 add_boot_entry(menu_t
*mp
,
4983 char linebuf
[BAM_MAXLINE
];
4986 const char *fcn
= "add_boot_entry()";
4990 INJECT_ERROR1("ADD_BOOT_ENTRY_FINDROOT_NULL", findroot
= NULL
);
4991 if (findroot
== NULL
) {
4992 bam_error(NULL_FINDROOT
);
4996 if (title
== NULL
) {
4997 title
= "Solaris"; /* default to Solaris */
4999 if (kernel
== NULL
) {
5000 bam_error(SUBOPT_MISS
, menu_cmds
[KERNEL_CMD
]);
5003 if (module
== NULL
) {
5004 if (bam_direct
!= BAM_DIRECT_DBOOT
) {
5005 bam_error(SUBOPT_MISS
, menu_cmds
[MODULE_CMD
]);
5009 /* Figure the commands out from the kernel line */
5010 if (strstr(kernel
, "$ISADIR") != NULL
) {
5011 module
= DIRECT_BOOT_ARCHIVE
;
5012 } else if (strstr(kernel
, "amd64") != NULL
) {
5013 module
= DIRECT_BOOT_ARCHIVE_64
;
5015 module
= DIRECT_BOOT_ARCHIVE_32
;
5019 k_cmd
= KERNEL_DOLLAR_CMD
;
5020 m_cmd
= MODULE_DOLLAR_CMD
;
5023 lineNum
= mp
->end
->lineNum
;
5024 entryNum
= mp
->end
->entryNum
;
5026 lineNum
= LINE_INIT
;
5027 entryNum
= ENTRY_INIT
;
5031 * No separator for comment (HDR/FTR) commands
5032 * The syntax for comments is #<comment>
5034 (void) snprintf(linebuf
, sizeof (linebuf
), "%s%s",
5035 menu_cmds
[COMMENT_CMD
], BAM_BOOTADM_HDR
);
5036 line_parser(mp
, linebuf
, &lineNum
, &entryNum
);
5038 (void) snprintf(linebuf
, sizeof (linebuf
), "%s%s%s",
5039 menu_cmds
[TITLE_CMD
], menu_cmds
[SEP_CMD
], title
);
5040 line_parser(mp
, linebuf
, &lineNum
, &entryNum
);
5042 (void) snprintf(linebuf
, sizeof (linebuf
), "%s%s%s",
5043 menu_cmds
[FINDROOT_CMD
], menu_cmds
[SEP_CMD
], findroot
);
5044 line_parser(mp
, linebuf
, &lineNum
, &entryNum
);
5045 BAM_DPRINTF((D_ADD_FINDROOT_NUM
, fcn
, lineNum
, entryNum
));
5047 if (bootfs
!= NULL
) {
5048 (void) snprintf(linebuf
, sizeof (linebuf
), "%s%s%s",
5049 menu_cmds
[BOOTFS_CMD
], menu_cmds
[SEP_CMD
], bootfs
);
5050 line_parser(mp
, linebuf
, &lineNum
, &entryNum
);
5053 (void) snprintf(linebuf
, sizeof (linebuf
), "%s%s%s",
5054 menu_cmds
[k_cmd
], menu_cmds
[SEP_CMD
], kernel
);
5055 line_parser(mp
, linebuf
, &lineNum
, &entryNum
);
5057 if (mod_kernel
!= NULL
) {
5058 (void) snprintf(linebuf
, sizeof (linebuf
), "%s%s%s",
5059 menu_cmds
[m_cmd
], menu_cmds
[SEP_CMD
], mod_kernel
);
5060 line_parser(mp
, linebuf
, &lineNum
, &entryNum
);
5063 (void) snprintf(linebuf
, sizeof (linebuf
), "%s%s%s",
5064 menu_cmds
[m_cmd
], menu_cmds
[SEP_CMD
], module
);
5065 line_parser(mp
, linebuf
, &lineNum
, &entryNum
);
5067 (void) snprintf(linebuf
, sizeof (linebuf
), "%s%s",
5068 menu_cmds
[COMMENT_CMD
], BAM_BOOTADM_FTR
);
5069 line_parser(mp
, linebuf
, &lineNum
, &entryNum
);
5075 delete_boot_entry(menu_t
*mp
, int entryNum
, int quiet
)
5082 const char *fcn
= "delete_boot_entry()";
5084 assert(entryNum
!= ENTRY_INIT
);
5093 * Check entry number and make sure it's a modifiable entry.
5096 * + We can modify a bootadm-created entry
5097 * + We can modify a libbe-created entry
5099 if ((lp
->flags
!= BAM_COMMENT
&&
5100 (((ent
->flags
& BAM_ENTRY_LIBBE
) == 0) &&
5101 strcmp(lp
->arg
, BAM_BOOTADM_HDR
) != 0)) ||
5102 (entryNum
!= ALL_ENTRIES
&& lp
->entryNum
!= entryNum
)) {
5107 /* free the entry content */
5110 lp
= lp
->next
; /* prev stays the same */
5111 BAM_DPRINTF((D_FREEING_LINE
, fcn
, freed
->lineNum
));
5112 unlink_line(mp
, freed
);
5114 } while (freed
!= ent
->end
);
5116 /* free the entry_t structure */
5117 assert(tmp
== NULL
);
5121 tmp
->prev
->next
= ent
;
5125 ent
->prev
= tmp
->prev
;
5126 BAM_DPRINTF((D_FREEING_ENTRY
, fcn
, tmp
->entryNum
));
5132 assert(tmp
== NULL
);
5134 if (!deleted
&& entryNum
!= ALL_ENTRIES
) {
5135 if (quiet
== DBE_PRINTERR
)
5136 bam_error(NO_BOOTADM_MATCH
);
5141 * Now that we have deleted an entry, update
5142 * the entry numbering and the default cmd.
5144 update_numbering(mp
);
5146 return (BAM_SUCCESS
);
5150 delete_all_entries(menu_t
*mp
, char *dummy
, char *opt
)
5153 assert(dummy
== NULL
);
5154 assert(opt
== NULL
);
5156 BAM_DPRINTF((D_FUNC_ENTRY0
, "delete_all_entries"));
5158 if (mp
->start
== NULL
) {
5159 bam_print(EMPTY_MENU
);
5160 return (BAM_SUCCESS
);
5163 if (delete_boot_entry(mp
, ALL_ENTRIES
, DBE_PRINTERR
) != BAM_SUCCESS
) {
5171 create_diskmap(char *osroot
)
5174 char cmd
[PATH_MAX
+ 16];
5175 char path
[PATH_MAX
];
5176 const char *fcn
= "create_diskmap()";
5178 /* make sure we have a map file */
5179 fp
= fopen(GRUBDISK_MAP
, "r");
5183 ret
= snprintf(path
, sizeof (path
), "%s/%s", osroot
,
5185 if (ret
>= sizeof (path
)) {
5186 bam_error(PATH_TOO_LONG
, osroot
);
5189 if (is_safe_exec(path
) == BAM_ERROR
)
5192 (void) snprintf(cmd
, sizeof (cmd
),
5193 "%s/%s > /dev/null", osroot
, CREATE_DISKMAP
);
5194 if (exec_cmd(cmd
, NULL
) != 0)
5196 fp
= fopen(GRUBDISK_MAP
, "r");
5197 INJECT_ERROR1("DISKMAP_CREATE_FAIL", fp
= NULL
);
5199 BAM_DPRINTF((D_CREATED_DISKMAP
, fcn
, GRUBDISK_MAP
));
5201 BAM_DPRINTF((D_CREATE_DISKMAP_FAIL
, fcn
, GRUBDISK_MAP
));
5207 #define SECTOR_SIZE 512
5210 get_partition(char *device
)
5212 int i
, fd
, is_pcfs
, partno
= PARTNO_NOTFOUND
;
5213 struct mboot
*mboot
;
5214 char boot_sect
[SECTOR_SIZE
];
5215 char *wholedisk
, *slice
;
5218 uint32_t secnum
, numsec
;
5219 int rval
, pno
, ext_partno
= PARTNO_NOTFOUND
;
5222 /* form whole disk (p0) */
5223 slice
= device
+ strlen(device
) - 2;
5224 is_pcfs
= (*slice
!= 's');
5227 wholedisk
= s_calloc(1, strlen(device
) + 3);
5228 (void) snprintf(wholedisk
, strlen(device
) + 3, "%sp0", device
);
5232 /* read boot sector */
5233 fd
= open(wholedisk
, O_RDONLY
);
5234 if (fd
== -1 || read(fd
, boot_sect
, SECTOR_SIZE
) != SECTOR_SIZE
) {
5240 /* Read/Initialize extended partition information */
5241 if ((rval
= libfdisk_init(&epp
, wholedisk
, NULL
, FDISK_READ_DISK
))
5245 * FDISK_EBADLOGDRIVE and FDISK_ENOLOGDRIVE can
5246 * be considered as soft errors and hence
5249 case FDISK_EBADLOGDRIVE
:
5251 case FDISK_ENOLOGDRIVE
:
5253 case FDISK_EBADMAGIC
:
5257 libfdisk_fini(&epp
);
5264 /* parse fdisk table */
5265 mboot
= (struct mboot
*)((void *)boot_sect
);
5266 for (i
= 0; i
< FD_NUMPART
; i
++) {
5267 struct ipart
*part
=
5268 (struct ipart
*)(uintptr_t)mboot
->parts
+ i
;
5269 if (is_pcfs
) { /* looking for solaris boot part */
5270 if (part
->systid
== 0xbe) {
5274 } else { /* look for solaris partition, old and new */
5275 if (part
->systid
== EFI_PMBR
) {
5276 partno
= PARTNO_EFI
;
5281 if ((part
->systid
== SUNIXOS
&&
5282 (fdisk_is_linux_swap(epp
, part
->relsect
,
5283 NULL
) != 0)) || part
->systid
== SUNIXOS2
) {
5285 if (part
->systid
== SUNIXOS
||
5286 part
->systid
== SUNIXOS2
) {
5293 if (fdisk_is_dos_extended(part
->systid
))
5299 /* If no primary solaris partition, check extended partition */
5300 if ((partno
== PARTNO_NOTFOUND
) && (ext_partno
!= PARTNO_NOTFOUND
)) {
5301 rval
= fdisk_get_solaris_part(epp
, &pno
, &secnum
, &numsec
);
5302 if (rval
== FDISK_SUCCESS
) {
5306 libfdisk_fini(&epp
);
5312 get_grubroot(char *osroot
, char *osdev
, char *menu_root
)
5314 char *grubroot
; /* (hd#,#,#) */
5316 char *grubhd
= NULL
;
5320 char *ctdname
= strstr(osdev
, "dsk/");
5321 char linebuf
[PATH_MAX
];
5324 INJECT_ERROR1("GRUBROOT_INVALID_OSDEV", ctdname
= NULL
);
5325 if (ctdname
== NULL
) {
5326 bam_error(INVALID_DEV_DSK
, osdev
);
5330 if (menu_root
&& !menu_on_bootdisk(osroot
, menu_root
)) {
5331 /* menu bears no resemblance to our reality */
5332 bam_error(CANNOT_GRUBROOT_BOOTDISK
, osdev
);
5336 ctdname
+= strlen("dsk/");
5337 slice
= strrchr(ctdname
, 's');
5341 fp
= create_diskmap(osroot
);
5343 bam_error(DISKMAP_FAIL
, osroot
);
5348 while (s_fgets(linebuf
, sizeof (linebuf
), fp
) != NULL
) {
5349 grubhd
= strtok(linebuf
, " \t\n");
5351 devname
= strtok(NULL
, " \t\n");
5354 if (devname
&& strcmp(devname
, ctdname
) == 0) {
5366 INJECT_ERROR1("GRUBROOT_BIOSDEV_FAIL", found
= 0);
5368 bam_error(BIOSDEV_SKIP
, osdev
);
5372 fdiskpart
= get_partition(osdev
);
5373 INJECT_ERROR1("GRUBROOT_FDISK_FAIL", fdiskpart
= PARTNO_NOTFOUND
);
5374 if (fdiskpart
== PARTNO_NOTFOUND
) {
5375 bam_error(FDISKPART_FAIL
, osdev
);
5379 grubroot
= s_calloc(1, 10);
5380 if (fdiskpart
== PARTNO_EFI
) {
5381 fdiskpart
= atoi(&slice
[1]);
5386 (void) snprintf(grubroot
, 10, "(hd%s,%d,%c)",
5387 grubhd
, fdiskpart
, slice
[1] + 'a' - '0');
5389 (void) snprintf(grubroot
, 10, "(hd%s,%d)",
5393 assert(strncmp(grubroot
, "(hd", strlen("(hd")) == 0);
5398 find_primary_common(char *mntpt
, char *fstype
)
5400 char signdir
[PATH_MAX
];
5401 char tmpsign
[MAXNAMELEN
+ 1];
5406 struct dirent
*entp
;
5408 const char *fcn
= "find_primary_common()";
5410 (void) snprintf(signdir
, sizeof (signdir
), "%s/%s",
5411 mntpt
, GRUBSIGN_DIR
);
5413 if (stat(signdir
, &sb
) == -1) {
5414 BAM_DPRINTF((D_NO_SIGNDIR
, fcn
, signdir
));
5418 dirp
= opendir(signdir
);
5419 INJECT_ERROR1("SIGNDIR_OPENDIR_FAIL", dirp
= NULL
);
5421 bam_error(OPENDIR_FAILED
, signdir
, strerror(errno
));
5425 ufs
= zfs
= lu
= NULL
;
5427 while ((entp
= readdir(dirp
)) != NULL
) {
5428 if (strcmp(entp
->d_name
, ".") == 0 ||
5429 strcmp(entp
->d_name
, "..") == 0)
5432 (void) snprintf(tmpsign
, sizeof (tmpsign
), "%s", entp
->d_name
);
5435 strncmp(tmpsign
, GRUBSIGN_LU_PREFIX
,
5436 strlen(GRUBSIGN_LU_PREFIX
)) == 0) {
5437 lu
= s_strdup(tmpsign
);
5441 strncmp(tmpsign
, GRUBSIGN_UFS_PREFIX
,
5442 strlen(GRUBSIGN_UFS_PREFIX
)) == 0) {
5443 ufs
= s_strdup(tmpsign
);
5447 strncmp(tmpsign
, GRUBSIGN_ZFS_PREFIX
,
5448 strlen(GRUBSIGN_ZFS_PREFIX
)) == 0) {
5449 zfs
= s_strdup(tmpsign
);
5453 BAM_DPRINTF((D_EXIST_PRIMARY_SIGNS
, fcn
,
5459 (void) closedir(dirp
);
5463 if (strcmp(fstype
, "ufs") == 0 && zfs
) {
5464 bam_error(SIGN_FSTYPE_MISMATCH
, zfs
, "ufs");
5467 } else if (strcmp(fstype
, "zfs") == 0 && ufs
) {
5468 bam_error(SIGN_FSTYPE_MISMATCH
, ufs
, "zfs");
5473 assert(dirp
== NULL
);
5475 /* For now, we let Live Upgrade take care of its signature itself */
5477 BAM_DPRINTF((D_FREEING_LU_SIGNS
, fcn
, lu
));
5482 return (zfs
? zfs
: ufs
);
5486 find_backup_common(char *mntpt
, char *fstype
)
5489 char tmpsign
[MAXNAMELEN
+ 1];
5490 char backup
[PATH_MAX
];
5495 const char *fcn
= "find_backup_common()";
5498 * We didn't find it in the primary directory.
5499 * Look at the backup
5501 (void) snprintf(backup
, sizeof (backup
), "%s%s",
5502 mntpt
, GRUBSIGN_BACKUP
);
5504 bfp
= fopen(backup
, "r");
5508 bam_error(OPEN_FAIL
, backup
, strerror(error
));
5510 BAM_DPRINTF((D_OPEN_FAIL
, fcn
, backup
, strerror(error
)));
5514 ufs
= zfs
= lu
= NULL
;
5516 while (s_fgets(tmpsign
, sizeof (tmpsign
), bfp
) != NULL
) {
5519 strncmp(tmpsign
, GRUBSIGN_LU_PREFIX
,
5520 strlen(GRUBSIGN_LU_PREFIX
)) == 0) {
5521 lu
= s_strdup(tmpsign
);
5525 strncmp(tmpsign
, GRUBSIGN_UFS_PREFIX
,
5526 strlen(GRUBSIGN_UFS_PREFIX
)) == 0) {
5527 ufs
= s_strdup(tmpsign
);
5531 strncmp(tmpsign
, GRUBSIGN_ZFS_PREFIX
,
5532 strlen(GRUBSIGN_ZFS_PREFIX
)) == 0) {
5533 zfs
= s_strdup(tmpsign
);
5537 BAM_DPRINTF((D_EXIST_BACKUP_SIGNS
, fcn
,
5547 if (strcmp(fstype
, "ufs") == 0 && zfs
) {
5548 bam_error(SIGN_FSTYPE_MISMATCH
, zfs
, "ufs");
5551 } else if (strcmp(fstype
, "zfs") == 0 && ufs
) {
5552 bam_error(SIGN_FSTYPE_MISMATCH
, ufs
, "zfs");
5557 assert(bfp
== NULL
);
5559 /* For now, we let Live Upgrade take care of its signature itself */
5561 BAM_DPRINTF((D_FREEING_LU_SIGNS
, fcn
, lu
));
5566 return (zfs
? zfs
: ufs
);
5570 find_ufs_existing(char *osroot
)
5573 const char *fcn
= "find_ufs_existing()";
5575 sign
= find_primary_common(osroot
, "ufs");
5577 sign
= find_backup_common(osroot
, "ufs");
5578 BAM_DPRINTF((D_EXIST_BACKUP_SIGN
, fcn
, sign
? sign
: "NULL"));
5580 BAM_DPRINTF((D_EXIST_PRIMARY_SIGN
, fcn
, sign
));
5587 get_mountpoint(char *special
, char *fstype
)
5590 struct mnttab mp
= {0};
5591 struct mnttab mpref
= {0};
5594 const char *fcn
= "get_mountpoint()";
5596 BAM_DPRINTF((D_FUNC_ENTRY2
, fcn
, special
, fstype
));
5598 mntfp
= fopen(MNTTAB
, "r");
5600 INJECT_ERROR1("MNTTAB_ERR_GET_MNTPT", mntfp
= NULL
);
5601 if (mntfp
== NULL
) {
5602 bam_error(OPEN_FAIL
, MNTTAB
, strerror(error
));
5606 mpref
.mnt_special
= special
;
5607 mpref
.mnt_fstype
= fstype
;
5609 ret
= getmntany(mntfp
, &mp
, &mpref
);
5610 INJECT_ERROR1("GET_MOUNTPOINT_MNTANY", ret
= 1);
5612 (void) fclose(mntfp
);
5613 BAM_DPRINTF((D_NO_MNTPT
, fcn
, special
, fstype
));
5616 (void) fclose(mntfp
);
5618 assert(mp
.mnt_mountp
);
5620 BAM_DPRINTF((D_GET_MOUNTPOINT_RET
, fcn
, special
, mp
.mnt_mountp
));
5622 return (s_strdup(mp
.mnt_mountp
));
5626 * Mounts a "legacy" top dataset (if needed)
5627 * Returns: The mountpoint of the legacy top dataset or NULL on error
5628 * mnted returns one of the above values defined for zfs_mnted_t
5631 mount_legacy_dataset(char *pool
, zfs_mnted_t
*mnted
)
5634 char tmpmnt
[PATH_MAX
];
5635 filelist_t flist
= {0};
5639 const char *fcn
= "mount_legacy_dataset()";
5641 BAM_DPRINTF((D_FUNC_ENTRY1
, fcn
, pool
));
5643 *mnted
= ZFS_MNT_ERROR
;
5645 (void) snprintf(cmd
, sizeof (cmd
),
5646 "/sbin/zfs get -Ho value mounted %s",
5649 ret
= exec_cmd(cmd
, &flist
);
5650 INJECT_ERROR1("Z_MOUNT_LEG_GET_MOUNTED_CMD", ret
= 1);
5652 bam_error(ZFS_MNTED_FAILED
, pool
);
5656 INJECT_ERROR1("Z_MOUNT_LEG_GET_MOUNTED_OUT", flist
.head
= NULL
);
5657 if ((flist
.head
== NULL
) || (flist
.head
!= flist
.tail
)) {
5658 bam_error(BAD_ZFS_MNTED
, pool
);
5659 filelist_free(&flist
);
5663 is_mounted
= strtok(flist
.head
->line
, " \t\n");
5664 INJECT_ERROR1("Z_MOUNT_LEG_GET_MOUNTED_STRTOK_YES", is_mounted
= "yes");
5665 INJECT_ERROR1("Z_MOUNT_LEG_GET_MOUNTED_STRTOK_NO", is_mounted
= "no");
5666 if (strcmp(is_mounted
, "no") != 0) {
5667 filelist_free(&flist
);
5668 *mnted
= LEGACY_ALREADY
;
5669 /* get_mountpoint returns a strdup'ed string */
5670 BAM_DPRINTF((D_Z_MOUNT_TOP_LEG_ALREADY
, fcn
, pool
));
5671 return (get_mountpoint(pool
, "zfs"));
5674 filelist_free(&flist
);
5677 * legacy top dataset is not mounted. Mount it now
5678 * First create a mountpoint.
5680 (void) snprintf(tmpmnt
, sizeof (tmpmnt
), "%s.%d",
5681 ZFS_LEGACY_MNTPT
, getpid());
5683 ret
= stat(tmpmnt
, &sb
);
5685 BAM_DPRINTF((D_Z_MOUNT_TOP_LEG_MNTPT_ABS
, fcn
, pool
, tmpmnt
));
5686 ret
= mkdirp(tmpmnt
, DIR_PERMS
);
5687 INJECT_ERROR1("Z_MOUNT_TOP_LEG_MNTPT_MKDIRP", ret
= -1);
5689 bam_error(MKDIR_FAILED
, tmpmnt
, strerror(errno
));
5693 BAM_DPRINTF((D_Z_MOUNT_TOP_LEG_MNTPT_PRES
, fcn
, pool
, tmpmnt
));
5696 (void) snprintf(cmd
, sizeof (cmd
),
5697 "/sbin/mount -F zfs %s %s",
5700 ret
= exec_cmd(cmd
, NULL
);
5701 INJECT_ERROR1("Z_MOUNT_TOP_LEG_MOUNT_CMD", ret
= 1);
5703 bam_error(ZFS_MOUNT_FAILED
, pool
);
5704 (void) rmdir(tmpmnt
);
5708 *mnted
= LEGACY_MOUNTED
;
5709 BAM_DPRINTF((D_Z_MOUNT_TOP_LEG_MOUNTED
, fcn
, pool
, tmpmnt
));
5710 return (s_strdup(tmpmnt
));
5714 * Mounts the top dataset (if needed)
5715 * Returns: The mountpoint of the top dataset or NULL on error
5716 * mnted returns one of the above values defined for zfs_mnted_t
5719 mount_top_dataset(char *pool
, zfs_mnted_t
*mnted
)
5722 filelist_t flist
= {0};
5727 const char *fcn
= "mount_top_dataset()";
5729 *mnted
= ZFS_MNT_ERROR
;
5731 BAM_DPRINTF((D_FUNC_ENTRY1
, fcn
, pool
));
5734 * First check if the top dataset is a "legacy" dataset
5736 (void) snprintf(cmd
, sizeof (cmd
),
5737 "/sbin/zfs get -Ho value mountpoint %s",
5739 ret
= exec_cmd(cmd
, &flist
);
5740 INJECT_ERROR1("Z_MOUNT_TOP_GET_MNTPT", ret
= 1);
5742 bam_error(ZFS_MNTPT_FAILED
, pool
);
5746 if (flist
.head
&& (flist
.head
== flist
.tail
)) {
5747 char *legacy
= strtok(flist
.head
->line
, " \t\n");
5748 if (legacy
&& strcmp(legacy
, "legacy") == 0) {
5749 filelist_free(&flist
);
5750 BAM_DPRINTF((D_Z_IS_LEGACY
, fcn
, pool
));
5751 return (mount_legacy_dataset(pool
, mnted
));
5755 filelist_free(&flist
);
5757 BAM_DPRINTF((D_Z_IS_NOT_LEGACY
, fcn
, pool
));
5759 (void) snprintf(cmd
, sizeof (cmd
),
5760 "/sbin/zfs get -Ho value mounted %s",
5763 ret
= exec_cmd(cmd
, &flist
);
5764 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MOUNTED", ret
= 1);
5766 bam_error(ZFS_MNTED_FAILED
, pool
);
5770 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MOUNTED_VAL", flist
.head
= NULL
);
5771 if ((flist
.head
== NULL
) || (flist
.head
!= flist
.tail
)) {
5772 bam_error(BAD_ZFS_MNTED
, pool
);
5773 filelist_free(&flist
);
5777 is_mounted
= strtok(flist
.head
->line
, " \t\n");
5778 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MOUNTED_YES", is_mounted
= "yes");
5779 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MOUNTED_NO", is_mounted
= "no");
5780 if (strcmp(is_mounted
, "no") != 0) {
5781 filelist_free(&flist
);
5782 *mnted
= ZFS_ALREADY
;
5783 BAM_DPRINTF((D_Z_MOUNT_TOP_NONLEG_MOUNTED_ALREADY
, fcn
, pool
));
5787 filelist_free(&flist
);
5788 BAM_DPRINTF((D_Z_MOUNT_TOP_NONLEG_MOUNTED_NOT_ALREADY
, fcn
, pool
));
5790 /* top dataset is not mounted. Mount it now */
5791 (void) snprintf(cmd
, sizeof (cmd
),
5792 "/sbin/zfs mount %s", pool
);
5793 ret
= exec_cmd(cmd
, NULL
);
5794 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_MOUNT_CMD", ret
= 1);
5796 bam_error(ZFS_MOUNT_FAILED
, pool
);
5799 *mnted
= ZFS_MOUNTED
;
5800 BAM_DPRINTF((D_Z_MOUNT_TOP_NONLEG_MOUNTED_NOW
, fcn
, pool
));
5804 * Now get the mountpoint
5806 (void) snprintf(cmd
, sizeof (cmd
),
5807 "/sbin/zfs get -Ho value mountpoint %s",
5810 ret
= exec_cmd(cmd
, &flist
);
5811 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MNTPT_CMD", ret
= 1);
5813 bam_error(ZFS_MNTPT_FAILED
, pool
);
5817 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MNTPT_OUT", flist
.head
= NULL
);
5818 if ((flist
.head
== NULL
) || (flist
.head
!= flist
.tail
)) {
5819 bam_error(NULL_ZFS_MNTPT
, pool
);
5823 mntpt
= strtok(flist
.head
->line
, " \t\n");
5824 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MNTPT_STRTOK", mntpt
= "foo");
5825 if (*mntpt
!= '/') {
5826 bam_error(BAD_ZFS_MNTPT
, pool
, mntpt
);
5829 zmntpt
= s_strdup(mntpt
);
5831 filelist_free(&flist
);
5833 BAM_DPRINTF((D_Z_MOUNT_TOP_NONLEG_MNTPT
, fcn
, pool
, zmntpt
));
5838 filelist_free(&flist
);
5839 (void) umount_top_dataset(pool
, *mnted
, NULL
);
5840 BAM_DPRINTF((D_RETURN_FAILURE
, fcn
));
5845 umount_top_dataset(char *pool
, zfs_mnted_t mnted
, char *mntpt
)
5849 const char *fcn
= "umount_top_dataset()";
5851 INJECT_ERROR1("Z_UMOUNT_TOP_INVALID_STATE", mnted
= ZFS_MNT_ERROR
);
5853 case LEGACY_ALREADY
:
5856 BAM_DPRINTF((D_Z_UMOUNT_TOP_ALREADY_NOP
, fcn
, pool
,
5857 mntpt
? mntpt
: "NULL"));
5859 return (BAM_SUCCESS
);
5860 case LEGACY_MOUNTED
:
5861 (void) snprintf(cmd
, sizeof (cmd
),
5862 "/sbin/umount %s", pool
);
5863 ret
= exec_cmd(cmd
, NULL
);
5864 INJECT_ERROR1("Z_UMOUNT_TOP_LEGACY_UMOUNT_FAIL", ret
= 1);
5866 bam_error(UMOUNT_FAILED
, pool
);
5871 (void) rmdir(mntpt
);
5873 BAM_DPRINTF((D_Z_UMOUNT_TOP_LEGACY
, fcn
, pool
));
5874 return (BAM_SUCCESS
);
5877 (void) snprintf(cmd
, sizeof (cmd
),
5878 "/sbin/zfs unmount %s", pool
);
5879 ret
= exec_cmd(cmd
, NULL
);
5880 INJECT_ERROR1("Z_UMOUNT_TOP_NONLEG_UMOUNT_FAIL", ret
= 1);
5882 bam_error(UMOUNT_FAILED
, pool
);
5885 BAM_DPRINTF((D_Z_UMOUNT_TOP_NONLEG
, fcn
, pool
));
5886 return (BAM_SUCCESS
);
5888 bam_error(INT_BAD_MNTSTATE
, pool
);
5895 * For ZFS, osdev can be one of two forms
5896 * It can be a "special" file as seen in mnttab: rpool/ROOT/szboot_0402
5897 * It can be a /dev/[r]dsk special file. We handle both instances
5900 get_pool(char *osdev
)
5904 filelist_t flist
= {0};
5909 const char *fcn
= "get_pool()";
5911 INJECT_ERROR1("GET_POOL_OSDEV", osdev
= NULL
);
5912 if (osdev
== NULL
) {
5913 bam_error(GET_POOL_OSDEV_NULL
);
5917 BAM_DPRINTF((D_GET_POOL_OSDEV
, fcn
, osdev
));
5919 if (osdev
[0] != '/') {
5920 (void) strlcpy(buf
, osdev
, sizeof (buf
));
5921 slash
= strchr(buf
, '/');
5924 pool
= s_strdup(buf
);
5925 BAM_DPRINTF((D_GET_POOL_RET
, fcn
, pool
));
5927 } else if (strncmp(osdev
, "/dev/dsk/", strlen("/dev/dsk/")) != 0 &&
5928 strncmp(osdev
, "/dev/rdsk/", strlen("/dev/rdsk/")) != 0) {
5929 bam_error(GET_POOL_BAD_OSDEV
, osdev
);
5934 * Call the zfs fstyp directly since this is a zpool. This avoids
5935 * potential pcfs conflicts if the first block wasn't cleared.
5937 (void) snprintf(cmd
, sizeof (cmd
),
5938 "/usr/lib/fs/zfs/fstyp -a %s 2>/dev/null | /bin/grep '^name:'",
5941 ret
= exec_cmd(cmd
, &flist
);
5942 INJECT_ERROR1("GET_POOL_FSTYP", ret
= 1);
5944 bam_error(FSTYP_A_FAILED
, osdev
);
5948 INJECT_ERROR1("GET_POOL_FSTYP_OUT", flist
.head
= NULL
);
5949 if ((flist
.head
== NULL
) || (flist
.head
!= flist
.tail
)) {
5950 bam_error(NULL_FSTYP_A
, osdev
);
5951 filelist_free(&flist
);
5955 (void) strtok(flist
.head
->line
, "'");
5956 cp
= strtok(NULL
, "'");
5957 INJECT_ERROR1("GET_POOL_FSTYP_STRTOK", cp
= NULL
);
5959 bam_error(BAD_FSTYP_A
, osdev
);
5960 filelist_free(&flist
);
5964 pool
= s_strdup(cp
);
5966 filelist_free(&flist
);
5968 BAM_DPRINTF((D_GET_POOL_RET
, fcn
, pool
));
5974 find_zfs_existing(char *osdev
)
5980 const char *fcn
= "find_zfs_existing()";
5982 pool
= get_pool(osdev
);
5983 INJECT_ERROR1("ZFS_FIND_EXIST_POOL", pool
= NULL
);
5985 bam_error(ZFS_GET_POOL_FAILED
, osdev
);
5989 mntpt
= mount_top_dataset(pool
, &mnted
);
5990 INJECT_ERROR1("ZFS_FIND_EXIST_MOUNT_TOP", mntpt
= NULL
);
5991 if (mntpt
== NULL
) {
5992 bam_error(ZFS_MOUNT_TOP_DATASET_FAILED
, pool
);
5997 sign
= find_primary_common(mntpt
, "zfs");
5999 sign
= find_backup_common(mntpt
, "zfs");
6000 BAM_DPRINTF((D_EXIST_BACKUP_SIGN
, fcn
, sign
? sign
: "NULL"));
6002 BAM_DPRINTF((D_EXIST_PRIMARY_SIGN
, fcn
, sign
));
6005 (void) umount_top_dataset(pool
, mnted
, mntpt
);
6013 find_existing_sign(char *osroot
, char *osdev
, char *fstype
)
6015 const char *fcn
= "find_existing_sign()";
6017 INJECT_ERROR1("FIND_EXIST_NOTSUP_FS", fstype
= "foofs");
6018 if (strcmp(fstype
, "ufs") == 0) {
6019 BAM_DPRINTF((D_CHECK_UFS_EXIST_SIGN
, fcn
));
6020 return (find_ufs_existing(osroot
));
6021 } else if (strcmp(fstype
, "zfs") == 0) {
6022 BAM_DPRINTF((D_CHECK_ZFS_EXIST_SIGN
, fcn
));
6023 return (find_zfs_existing(osdev
));
6025 bam_error(GRUBSIGN_NOTSUP
, fstype
);
6030 #define MH_HASH_SZ 16
6038 typedef struct mcache
{
6042 struct mcache
*mc_next
;
6045 typedef struct mhash
{
6046 mcache_t
*mh_hash
[MH_HASH_SZ
];
6050 mhash_fcn(char *key
)
6055 for (i
= 0; key
[i
] != '\0'; i
++) {
6056 sum
+= (uchar_t
)key
[i
];
6061 assert(sum
< MH_HASH_SZ
);
6070 struct extmnttab mnt
;
6077 const char *fcn
= "cache_mnttab()";
6079 mfp
= fopen(MNTTAB
, "r");
6081 INJECT_ERROR1("CACHE_MNTTAB_MNTTAB_ERR", mfp
= NULL
);
6083 bam_error(OPEN_FAIL
, MNTTAB
, strerror(error
));
6087 mhp
= s_calloc(1, sizeof (mhash_t
));
6091 while (getextmntent(mfp
, &mnt
, sizeof (mnt
)) == 0) {
6092 /* only cache ufs */
6093 if (strcmp(mnt
.mnt_fstype
, "ufs") != 0)
6096 /* basename() modifies its arg, so dup it */
6097 special_dup
= s_strdup(mnt
.mnt_special
);
6098 ctds
= basename(special_dup
);
6100 mcp
= s_calloc(1, sizeof (mcache_t
));
6101 mcp
->mc_special
= s_strdup(ctds
);
6102 mcp
->mc_mntpt
= s_strdup(mnt
.mnt_mountp
);
6103 mcp
->mc_fstype
= s_strdup(mnt
.mnt_fstype
);
6104 BAM_DPRINTF((D_CACHE_MNTS
, fcn
, ctds
,
6105 mnt
.mnt_mountp
, mnt
.mnt_fstype
));
6106 idx
= mhash_fcn(ctds
);
6107 mcp
->mc_next
= mhp
->mh_hash
[idx
];
6108 mhp
->mh_hash
[idx
] = mcp
;
6118 free_mnttab(mhash_t
*mhp
)
6123 for (i
= 0; i
< MH_HASH_SZ
; i
++) {
6124 while ((mcp
= mhp
->mh_hash
[i
]) != NULL
) {
6125 mhp
->mh_hash
[i
] = mcp
->mc_next
;
6126 free(mcp
->mc_special
);
6127 free(mcp
->mc_mntpt
);
6128 free(mcp
->mc_fstype
);
6133 for (i
= 0; i
< MH_HASH_SZ
; i
++) {
6134 assert(mhp
->mh_hash
[i
] == NULL
);
6140 search_hash(mhash_t
*mhp
, char *special
, char **mntpt
)
6144 const char *fcn
= "search_hash()";
6150 INJECT_ERROR1("SEARCH_HASH_FULL_PATH", special
= "/foo");
6151 if (strchr(special
, '/')) {
6152 bam_error(INVALID_MHASH_KEY
, special
);
6156 idx
= mhash_fcn(special
);
6158 for (mcp
= mhp
->mh_hash
[idx
]; mcp
; mcp
= mcp
->mc_next
) {
6159 if (strcmp(mcp
->mc_special
, special
) == 0)
6164 BAM_DPRINTF((D_MNTTAB_HASH_NOMATCH
, fcn
, special
));
6165 return (MH_NOMATCH
);
6168 assert(strcmp(mcp
->mc_fstype
, "ufs") == 0);
6169 *mntpt
= mcp
->mc_mntpt
;
6170 BAM_DPRINTF((D_MNTTAB_HASH_MATCH
, fcn
, special
));
6175 check_add_ufs_sign_to_list(FILE *tfp
, char *mntpt
)
6179 char signbuf
[MAXNAMELEN
];
6182 const char *fcn
= "check_add_ufs_sign_to_list()";
6184 /* safe to specify NULL as "osdev" arg for UFS */
6185 sign
= find_existing_sign(mntpt
, NULL
, "ufs");
6187 /* No existing signature, nothing to add to list */
6188 BAM_DPRINTF((D_NO_SIGN_TO_LIST
, fcn
, mntpt
));
6192 (void) snprintf(signbuf
, sizeof (signbuf
), "%s\n", sign
);
6195 INJECT_ERROR1("UFS_MNTPT_SIGN_NOTUFS", signline
= "pool_rpool10\n");
6196 if (strncmp(signline
, GRUBSIGN_UFS_PREFIX
,
6197 strlen(GRUBSIGN_UFS_PREFIX
))) {
6198 bam_error(INVALID_UFS_SIGNATURE
, sign
);
6200 /* ignore invalid signatures */
6204 len
= fputs(signline
, tfp
);
6206 INJECT_ERROR1("SIGN_LIST_PUTS_ERROR", len
= 0);
6207 if (len
!= strlen(signline
)) {
6208 bam_error(SIGN_LIST_FPUTS_ERR
, sign
, strerror(error
));
6215 BAM_DPRINTF((D_SIGN_LIST_PUTS_DONE
, fcn
, mntpt
));
6220 * slice is a basename not a full pathname
6223 process_slice_common(char *slice
, FILE *tfp
, mhash_t
*mhp
, char *tmpmnt
)
6227 char path
[PATH_MAX
];
6230 filelist_t flist
= {0};
6232 char blkslice
[PATH_MAX
];
6233 const char *fcn
= "process_slice_common()";
6236 ret
= search_hash(mhp
, slice
, &mntpt
);
6239 if (check_add_ufs_sign_to_list(tfp
, mntpt
) == -1)
6250 (void) snprintf(path
, sizeof (path
), "/dev/rdsk/%s", slice
);
6251 if (stat(path
, &sbuf
) == -1) {
6252 BAM_DPRINTF((D_SLICE_ENOENT
, fcn
, path
));
6256 /* Check if ufs. Call ufs fstyp directly to avoid pcfs conflicts. */
6257 (void) snprintf(cmd
, sizeof (cmd
),
6258 "/usr/lib/fs/ufs/fstyp /dev/rdsk/%s 2>/dev/null",
6261 if (exec_cmd(cmd
, &flist
) != 0) {
6263 bam_print(FSTYP_FAILED
, slice
);
6267 if ((flist
.head
== NULL
) || (flist
.head
!= flist
.tail
)) {
6269 bam_print(FSTYP_BAD
, slice
);
6270 filelist_free(&flist
);
6274 fstype
= strtok(flist
.head
->line
, " \t\n");
6275 if (fstype
== NULL
|| strcmp(fstype
, "ufs") != 0) {
6277 bam_print(NOT_UFS_SLICE
, slice
, fstype
);
6278 filelist_free(&flist
);
6282 filelist_free(&flist
);
6285 * Since we are mounting the filesystem read-only, the
6286 * the last mount field of the superblock is unchanged
6287 * and does not need to be fixed up post-mount;
6290 (void) snprintf(blkslice
, sizeof (blkslice
), "/dev/dsk/%s",
6293 (void) snprintf(cmd
, sizeof (cmd
),
6294 "/usr/sbin/mount -F ufs -o ro %s %s "
6295 "> /dev/null 2>&1", blkslice
, tmpmnt
);
6297 if (exec_cmd(cmd
, NULL
) != 0) {
6299 bam_print(MOUNT_FAILED
, blkslice
, "ufs");
6303 ret
= check_add_ufs_sign_to_list(tfp
, tmpmnt
);
6305 (void) snprintf(cmd
, sizeof (cmd
),
6306 "/usr/sbin/umount -f %s > /dev/null 2>&1",
6309 if (exec_cmd(cmd
, NULL
) != 0) {
6310 bam_print(UMOUNT_FAILED
, slice
);
6318 process_vtoc_slices(
6326 char slice
[PATH_MAX
];
6329 const char *fcn
= "process_vtoc_slices()";
6333 assert(s0
[len
- 2] == 's' && s0
[len
- 1] == '0');
6337 (void) strlcpy(slice
, s0
, sizeof (slice
));
6341 cp
= slice
+ len
- 1;
6343 for (idx
= 0; idx
< vtoc
->v_nparts
; idx
++) {
6345 (void) snprintf(cp
, sizeof (slice
) - (len
- 1), "%u", idx
);
6347 if (vtoc
->v_part
[idx
].p_size
== 0) {
6348 BAM_DPRINTF((D_VTOC_SIZE_ZERO
, fcn
, slice
));
6352 /* Skip "SWAP", "USR", "BACKUP", "VAR", "HOME", "ALTSCTR" */
6353 switch (vtoc
->v_part
[idx
].p_tag
) {
6360 BAM_DPRINTF((D_VTOC_NOT_ROOT_TAG
, fcn
, slice
));
6363 BAM_DPRINTF((D_VTOC_ROOT_TAG
, fcn
, slice
));
6367 /* skip unmountable and readonly slices */
6368 switch (vtoc
->v_part
[idx
].p_flag
) {
6371 BAM_DPRINTF((D_VTOC_NOT_RDWR_FLAG
, fcn
, slice
));
6374 BAM_DPRINTF((D_VTOC_RDWR_FLAG
, fcn
, slice
));
6378 if (process_slice_common(slice
, tfp
, mhp
, tmpmnt
) == -1) {
6395 char slice
[PATH_MAX
];
6398 const char *fcn
= "process_efi_slices()";
6402 assert(s0
[len
- 2] == 's' && s0
[len
- 1] == '0');
6406 (void) strlcpy(slice
, s0
, sizeof (slice
));
6410 cp
= slice
+ len
- 1;
6412 for (idx
= 0; idx
< efi
->efi_nparts
; idx
++) {
6414 (void) snprintf(cp
, sizeof (slice
) - (len
- 1), "%u", idx
);
6416 if (efi
->efi_parts
[idx
].p_size
== 0) {
6417 BAM_DPRINTF((D_EFI_SIZE_ZERO
, fcn
, slice
));
6421 /* Skip "SWAP", "USR", "BACKUP", "VAR", "HOME", "ALTSCTR" */
6422 switch (efi
->efi_parts
[idx
].p_tag
) {
6429 BAM_DPRINTF((D_EFI_NOT_ROOT_TAG
, fcn
, slice
));
6432 BAM_DPRINTF((D_EFI_ROOT_TAG
, fcn
, slice
));
6436 /* skip unmountable and readonly slices */
6437 switch (efi
->efi_parts
[idx
].p_flag
) {
6440 BAM_DPRINTF((D_EFI_NOT_RDWR_FLAG
, fcn
, slice
));
6443 BAM_DPRINTF((D_EFI_RDWR_FLAG
, fcn
, slice
));
6447 if (process_slice_common(slice
, tfp
, mhp
, tmpmnt
) == -1) {
6456 * s0 is a basename not a full path
6459 process_slice0(char *s0
, FILE *tfp
, mhash_t
*mhp
, char *tmpmnt
)
6463 char s0path
[PATH_MAX
];
6470 const char *fcn
= "process_slice0()";
6472 (void) snprintf(s0path
, sizeof (s0path
), "/dev/rdsk/%s", s0
);
6474 if (stat(s0path
, &sbuf
) == -1) {
6475 BAM_DPRINTF((D_SLICE0_ENOENT
, fcn
, s0path
));
6479 fd
= open(s0path
, O_NONBLOCK
|O_RDONLY
);
6481 bam_error(OPEN_FAIL
, s0path
, strerror(errno
));
6485 e_flag
= v_flag
= 0;
6486 retval
= ((err
= read_vtoc(fd
, &vtoc
)) >= 0) ? 0 : err
;
6489 BAM_DPRINTF((D_VTOC_READ_FAIL
, fcn
, s0path
));
6492 BAM_DPRINTF((D_VTOC_INVALID
, fcn
, s0path
));
6495 BAM_DPRINTF((D_VTOC_UNKNOWN_ERR
, fcn
, s0path
));
6499 BAM_DPRINTF((D_VTOC_NOTSUP
, fcn
, s0path
));
6503 BAM_DPRINTF((D_VTOC_READ_SUCCESS
, fcn
, s0path
));
6506 BAM_DPRINTF((D_VTOC_UNKNOWN_RETCODE
, fcn
, s0path
));
6513 retval
= ((err
= efi_alloc_and_read(fd
, &efi
)) >= 0) ? 0 : err
;
6516 BAM_DPRINTF((D_EFI_READ_FAIL
, fcn
, s0path
));
6519 BAM_DPRINTF((D_EFI_INVALID
, fcn
, s0path
));
6522 BAM_DPRINTF((D_EFI_UNKNOWN_ERR
, fcn
, s0path
));
6525 BAM_DPRINTF((D_EFI_NOTSUP
, fcn
, s0path
));
6529 BAM_DPRINTF((D_EFI_READ_SUCCESS
, fcn
, s0path
));
6532 BAM_DPRINTF((D_EFI_UNKNOWN_RETCODE
, fcn
, s0path
));
6540 retval
= process_vtoc_slices(s0
,
6541 &vtoc
, tfp
, mhp
, tmpmnt
);
6542 } else if (e_flag
) {
6543 retval
= process_efi_slices(s0
,
6544 efi
, tfp
, mhp
, tmpmnt
);
6546 BAM_DPRINTF((D_NOT_VTOC_OR_EFI
, fcn
, s0path
));
6554 * Find and create a list of all existing UFS boot signatures
6557 FindAllUfsSignatures(void)
6559 mhash_t
*mnttab_hash
;
6562 char tmpmnt
[PATH_MAX
];
6570 const char *fcn
= "FindAllUfsSignatures()";
6572 if (stat(UFS_SIGNATURE_LIST
, &sb
) != -1) {
6573 bam_print(SIGNATURE_LIST_EXISTS
, UFS_SIGNATURE_LIST
);
6577 fd
= open(UFS_SIGNATURE_LIST
".tmp",
6578 O_RDWR
|O_CREAT
|O_TRUNC
, 0644);
6580 INJECT_ERROR1("SIGN_LIST_TMP_TRUNC", fd
= -1);
6582 bam_error(OPEN_FAIL
, UFS_SIGNATURE_LIST
".tmp", strerror(error
));
6588 INJECT_ERROR1("SIGN_LIST_TMP_CLOSE", ret
= -1);
6590 bam_error(CLOSE_FAIL
, UFS_SIGNATURE_LIST
".tmp",
6592 (void) unlink(UFS_SIGNATURE_LIST
".tmp");
6596 tfp
= fopen(UFS_SIGNATURE_LIST
".tmp", "a");
6598 INJECT_ERROR1("SIGN_LIST_APPEND_FOPEN", tfp
= NULL
);
6600 bam_error(OPEN_FAIL
, UFS_SIGNATURE_LIST
".tmp", strerror(error
));
6601 (void) unlink(UFS_SIGNATURE_LIST
".tmp");
6605 mnttab_hash
= cache_mnttab();
6606 INJECT_ERROR1("CACHE_MNTTAB_ERROR", mnttab_hash
= NULL
);
6607 if (mnttab_hash
== NULL
) {
6609 (void) unlink(UFS_SIGNATURE_LIST
".tmp");
6610 bam_error(CACHE_MNTTAB_FAIL
, fcn
);
6614 (void) snprintf(tmpmnt
, sizeof (tmpmnt
),
6615 "/tmp/bootadm_ufs_sign_mnt.%d", getpid());
6616 (void) unlink(tmpmnt
);
6618 ret
= mkdirp(tmpmnt
, DIR_PERMS
);
6620 INJECT_ERROR1("MKDIRP_SIGN_MNT", ret
= -1);
6622 bam_error(MKDIR_FAILED
, tmpmnt
, strerror(error
));
6623 free_mnttab(mnttab_hash
);
6625 (void) unlink(UFS_SIGNATURE_LIST
".tmp");
6629 dirp
= opendir("/dev/rdsk");
6631 INJECT_ERROR1("OPENDIR_DEV_RDSK", dirp
= NULL
);
6633 bam_error(OPENDIR_FAILED
, "/dev/rdsk", strerror(error
));
6637 while ((dp
= readdir(dirp
)) != NULL
) {
6638 if (strcmp(dp
->d_name
, ".") == 0 ||
6639 strcmp(dp
->d_name
, "..") == 0)
6643 * we only look for the s0 slice. This is guranteed to
6644 * have 's' at len - 2.
6646 len
= strlen(dp
->d_name
);
6647 if (dp
->d_name
[len
- 2 ] != 's' || dp
->d_name
[len
- 1] != '0') {
6648 BAM_DPRINTF((D_SKIP_SLICE_NOTZERO
, fcn
, dp
->d_name
));
6652 ret
= process_slice0(dp
->d_name
, tfp
, mnttab_hash
, tmpmnt
);
6653 INJECT_ERROR1("PROCESS_S0_FAIL", ret
= -1);
6658 (void) closedir(dirp
);
6659 free_mnttab(mnttab_hash
);
6660 (void) rmdir(tmpmnt
);
6664 INJECT_ERROR1("FCLOSE_SIGNLIST_TMP", ret
= EOF
);
6666 bam_error(CLOSE_FAIL
, UFS_SIGNATURE_LIST
".tmp",
6668 (void) unlink(UFS_SIGNATURE_LIST
".tmp");
6672 /* We have a list of existing GRUB signatures. Sort it first */
6673 (void) snprintf(cmd
, sizeof (cmd
),
6674 "/usr/bin/sort -u %s.tmp > %s.sorted",
6675 UFS_SIGNATURE_LIST
, UFS_SIGNATURE_LIST
);
6677 ret
= exec_cmd(cmd
, NULL
);
6678 INJECT_ERROR1("SORT_SIGN_LIST", ret
= 1);
6680 bam_error(GRUBSIGN_SORT_FAILED
);
6681 (void) unlink(UFS_SIGNATURE_LIST
".sorted");
6682 (void) unlink(UFS_SIGNATURE_LIST
".tmp");
6686 (void) unlink(UFS_SIGNATURE_LIST
".tmp");
6688 ret
= rename(UFS_SIGNATURE_LIST
".sorted", UFS_SIGNATURE_LIST
);
6690 INJECT_ERROR1("RENAME_TMP_SIGNLIST", ret
= -1);
6692 bam_error(RENAME_FAIL
, UFS_SIGNATURE_LIST
, strerror(error
));
6693 (void) unlink(UFS_SIGNATURE_LIST
".sorted");
6697 if (stat(UFS_SIGNATURE_LIST
, &sb
) == 0 && sb
.st_size
== 0) {
6698 BAM_DPRINTF((D_ZERO_LEN_SIGNLIST
, fcn
, UFS_SIGNATURE_LIST
));
6701 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
6706 (void) closedir(dirp
);
6707 free_mnttab(mnttab_hash
);
6708 (void) rmdir(tmpmnt
);
6710 (void) unlink(UFS_SIGNATURE_LIST
".tmp");
6711 BAM_DPRINTF((D_RETURN_FAILURE
, fcn
));
6716 create_ufs_sign(void)
6720 char tmpsign
[MAXNAMELEN
+ 1];
6726 const char *fcn
= "create_ufs_sign()";
6728 bam_print(SEARCHING_UFS_SIGN
);
6730 ret
= FindAllUfsSignatures();
6731 INJECT_ERROR1("FIND_ALL_UFS", ret
= -1);
6733 bam_error(ERR_FIND_UFS_SIGN
);
6737 /* Make sure the list exists and is owned by root */
6738 INJECT_ERROR1("SIGNLIST_NOT_CREATED",
6739 (void) unlink(UFS_SIGNATURE_LIST
));
6740 if (stat(UFS_SIGNATURE_LIST
, &sb
) == -1 || sb
.st_uid
!= 0) {
6741 (void) unlink(UFS_SIGNATURE_LIST
);
6742 bam_error(UFS_SIGNATURE_LIST_MISS
, UFS_SIGNATURE_LIST
);
6746 if (sb
.st_size
== 0) {
6747 bam_print(GRUBSIGN_UFS_NONE
);
6752 /* The signature list was sorted when it was created */
6753 tfp
= fopen(UFS_SIGNATURE_LIST
, "r");
6755 INJECT_ERROR1("FOPEN_SIGN_LIST", tfp
= NULL
);
6757 bam_error(UFS_SIGNATURE_LIST_OPENERR
,
6758 UFS_SIGNATURE_LIST
, strerror(error
));
6759 (void) unlink(UFS_SIGNATURE_LIST
);
6763 for (i
= 0; s_fgets(tmpsign
, sizeof (tmpsign
), tfp
); i
++) {
6765 if (strncmp(tmpsign
, GRUBSIGN_UFS_PREFIX
,
6766 strlen(GRUBSIGN_UFS_PREFIX
)) != 0) {
6768 (void) unlink(UFS_SIGNATURE_LIST
);
6769 bam_error(UFS_BADSIGN
, tmpsign
);
6772 numstr
= tmpsign
+ strlen(GRUBSIGN_UFS_PREFIX
);
6774 if (numstr
[0] == '\0' || !isdigit(numstr
[0])) {
6776 (void) unlink(UFS_SIGNATURE_LIST
);
6777 bam_error(UFS_BADSIGN
, tmpsign
);
6781 signnum
= atoi(numstr
);
6782 INJECT_ERROR1("NEGATIVE_SIGN", signnum
= -1);
6785 (void) unlink(UFS_SIGNATURE_LIST
);
6786 bam_error(UFS_BADSIGN
, tmpsign
);
6791 BAM_DPRINTF((D_FOUND_HOLE_SIGNLIST
, fcn
, i
));
6799 (void) snprintf(tmpsign
, sizeof (tmpsign
), "rootfs%d", i
);
6801 /* add the ufs signature to the /var/run list of signatures */
6802 ret
= ufs_add_to_sign_list(tmpsign
);
6803 INJECT_ERROR1("UFS_ADD_TO_SIGN_LIST", ret
= -1);
6805 (void) unlink(UFS_SIGNATURE_LIST
);
6806 bam_error(FAILED_ADD_SIGNLIST
, tmpsign
);
6810 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
6812 return (s_strdup(tmpsign
));
6816 get_fstype(char *osroot
)
6819 struct mnttab mp
= {0};
6820 struct mnttab mpref
= {0};
6823 const char *fcn
= "get_fstype()";
6825 INJECT_ERROR1("GET_FSTYPE_OSROOT", osroot
= NULL
);
6826 if (osroot
== NULL
) {
6827 bam_error(GET_FSTYPE_ARGS
);
6831 mntfp
= fopen(MNTTAB
, "r");
6833 INJECT_ERROR1("GET_FSTYPE_FOPEN", mntfp
= NULL
);
6834 if (mntfp
== NULL
) {
6835 bam_error(OPEN_FAIL
, MNTTAB
, strerror(error
));
6839 if (*osroot
== '\0')
6840 mpref
.mnt_mountp
= "/";
6842 mpref
.mnt_mountp
= osroot
;
6844 ret
= getmntany(mntfp
, &mp
, &mpref
);
6845 INJECT_ERROR1("GET_FSTYPE_GETMNTANY", ret
= 1);
6847 bam_error(MNTTAB_MNTPT_NOT_FOUND
, osroot
, MNTTAB
);
6848 (void) fclose(mntfp
);
6851 (void) fclose(mntfp
);
6853 INJECT_ERROR1("GET_FSTYPE_NULL", mp
.mnt_fstype
= NULL
);
6854 if (mp
.mnt_fstype
== NULL
) {
6855 bam_error(MNTTAB_FSTYPE_NULL
, osroot
);
6859 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
6861 return (s_strdup(mp
.mnt_fstype
));
6865 create_zfs_sign(char *osdev
)
6867 char tmpsign
[PATH_MAX
];
6869 const char *fcn
= "create_zfs_sign()";
6871 BAM_DPRINTF((D_FUNC_ENTRY1
, fcn
, osdev
));
6874 * First find the pool name
6876 pool
= get_pool(osdev
);
6877 INJECT_ERROR1("CREATE_ZFS_SIGN_GET_POOL", pool
= NULL
);
6879 bam_error(GET_POOL_FAILED
, osdev
);
6883 (void) snprintf(tmpsign
, sizeof (tmpsign
), "pool_%s", pool
);
6885 BAM_DPRINTF((D_CREATED_ZFS_SIGN
, fcn
, tmpsign
));
6889 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
6891 return (s_strdup(tmpsign
));
6895 create_new_sign(char *osdev
, char *fstype
)
6898 const char *fcn
= "create_new_sign()";
6900 INJECT_ERROR1("NEW_SIGN_FSTYPE", fstype
= "foofs");
6902 if (strcmp(fstype
, "zfs") == 0) {
6903 BAM_DPRINTF((D_CREATE_NEW_ZFS
, fcn
));
6904 sign
= create_zfs_sign(osdev
);
6905 } else if (strcmp(fstype
, "ufs") == 0) {
6906 BAM_DPRINTF((D_CREATE_NEW_UFS
, fcn
));
6907 sign
= create_ufs_sign();
6909 bam_error(GRUBSIGN_NOTSUP
, fstype
);
6913 BAM_DPRINTF((D_CREATED_NEW_SIGN
, fcn
, sign
? sign
: "<NULL>"));
6918 set_backup_common(char *mntpt
, char *sign
)
6921 char backup
[PATH_MAX
];
6922 char tmpsign
[PATH_MAX
];
6928 const char *fcn
= "set_backup_common()";
6930 (void) snprintf(backup
, sizeof (backup
), "%s%s",
6931 mntpt
, GRUBSIGN_BACKUP
);
6933 /* First read the backup */
6934 bfp
= fopen(backup
, "r");
6936 while (s_fgets(tmpsign
, sizeof (tmpsign
), bfp
)) {
6937 if (strcmp(tmpsign
, sign
) == 0) {
6938 BAM_DPRINTF((D_FOUND_IN_BACKUP
, fcn
, sign
));
6944 BAM_DPRINTF((D_NOT_FOUND_IN_EXIST_BACKUP
, fcn
, sign
));
6946 BAM_DPRINTF((D_BACKUP_NOT_EXIST
, fcn
, backup
));
6950 * Didn't find the correct signature. First create
6951 * the directory if necessary.
6954 /* dirname() modifies its argument so dup it */
6955 backup_dup
= s_strdup(backup
);
6956 bdir
= dirname(backup_dup
);
6959 ret
= stat(bdir
, &sb
);
6960 INJECT_ERROR1("SET_BACKUP_STAT", ret
= -1);
6962 BAM_DPRINTF((D_BACKUP_DIR_NOEXIST
, fcn
, bdir
));
6963 ret
= mkdirp(bdir
, DIR_PERMS
);
6965 INJECT_ERROR1("SET_BACKUP_MKDIRP", ret
= -1);
6967 bam_error(GRUBSIGN_BACKUP_MKDIRERR
,
6968 GRUBSIGN_BACKUP
, strerror(error
));
6976 * Open the backup in append mode to add the correct
6979 bfp
= fopen(backup
, "a");
6981 INJECT_ERROR1("SET_BACKUP_FOPEN_A", bfp
= NULL
);
6983 bam_error(GRUBSIGN_BACKUP_OPENERR
,
6984 GRUBSIGN_BACKUP
, strerror(error
));
6988 (void) snprintf(tmpsign
, sizeof (tmpsign
), "%s\n", sign
);
6990 ret
= fputs(tmpsign
, bfp
);
6992 INJECT_ERROR1("SET_BACKUP_FPUTS", ret
= 0);
6993 if (ret
!= strlen(tmpsign
)) {
6994 bam_error(GRUBSIGN_BACKUP_WRITEERR
,
6995 GRUBSIGN_BACKUP
, strerror(error
));
7003 bam_print(GRUBSIGN_BACKUP_UPDATED
, GRUBSIGN_BACKUP
);
7005 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
7011 set_backup_ufs(char *osroot
, char *sign
)
7013 const char *fcn
= "set_backup_ufs()";
7015 BAM_DPRINTF((D_FUNC_ENTRY2
, fcn
, osroot
, sign
));
7016 return (set_backup_common(osroot
, sign
));
7020 set_backup_zfs(char *osdev
, char *sign
)
7026 const char *fcn
= "set_backup_zfs()";
7028 BAM_DPRINTF((D_FUNC_ENTRY2
, fcn
, osdev
, sign
));
7030 pool
= get_pool(osdev
);
7031 INJECT_ERROR1("SET_BACKUP_GET_POOL", pool
= NULL
);
7033 bam_error(GET_POOL_FAILED
, osdev
);
7037 mntpt
= mount_top_dataset(pool
, &mnted
);
7038 INJECT_ERROR1("SET_BACKUP_MOUNT_DATASET", mntpt
= NULL
);
7039 if (mntpt
== NULL
) {
7040 bam_error(FAIL_MNT_TOP_DATASET
, pool
);
7045 ret
= set_backup_common(mntpt
, sign
);
7047 (void) umount_top_dataset(pool
, mnted
, mntpt
);
7051 INJECT_ERROR1("SET_BACKUP_ZFS_FAIL", ret
= 1);
7053 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
7055 BAM_DPRINTF((D_RETURN_FAILURE
, fcn
));
7062 set_backup(char *osroot
, char *osdev
, char *sign
, char *fstype
)
7064 const char *fcn
= "set_backup()";
7067 INJECT_ERROR1("SET_BACKUP_FSTYPE", fstype
= "foofs");
7069 if (strcmp(fstype
, "ufs") == 0) {
7070 BAM_DPRINTF((D_SET_BACKUP_UFS
, fcn
));
7071 ret
= set_backup_ufs(osroot
, sign
);
7072 } else if (strcmp(fstype
, "zfs") == 0) {
7073 BAM_DPRINTF((D_SET_BACKUP_ZFS
, fcn
));
7074 ret
= set_backup_zfs(osdev
, sign
);
7076 bam_error(GRUBSIGN_NOTSUP
, fstype
);
7081 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
7083 BAM_DPRINTF((D_RETURN_FAILURE
, fcn
));
7090 set_primary_common(char *mntpt
, char *sign
)
7092 char signfile
[PATH_MAX
];
7093 char signdir
[PATH_MAX
];
7098 const char *fcn
= "set_primary_common()";
7100 (void) snprintf(signfile
, sizeof (signfile
), "%s/%s/%s",
7101 mntpt
, GRUBSIGN_DIR
, sign
);
7103 if (stat(signfile
, &sb
) != -1) {
7105 bam_print(PRIMARY_SIGN_EXISTS
, sign
);
7108 BAM_DPRINTF((D_PRIMARY_NOT_EXIST
, fcn
, signfile
));
7111 (void) snprintf(signdir
, sizeof (signdir
), "%s/%s",
7112 mntpt
, GRUBSIGN_DIR
);
7114 if (stat(signdir
, &sb
) == -1) {
7115 BAM_DPRINTF((D_PRIMARY_DIR_NOEXIST
, fcn
, signdir
));
7116 ret
= mkdirp(signdir
, DIR_PERMS
);
7118 INJECT_ERROR1("SET_PRIMARY_MKDIRP", ret
= -1);
7120 bam_error(GRUBSIGN_MKDIR_ERR
, signdir
, strerror(errno
));
7125 fd
= open(signfile
, O_RDWR
|O_CREAT
|O_TRUNC
, 0444);
7127 INJECT_ERROR1("PRIMARY_SIGN_CREAT", fd
= -1);
7129 bam_error(GRUBSIGN_PRIMARY_CREATERR
, signfile
, strerror(error
));
7135 INJECT_ERROR1("PRIMARY_FSYNC", ret
= -1);
7137 bam_error(GRUBSIGN_PRIMARY_SYNCERR
, signfile
, strerror(error
));
7143 bam_print(GRUBSIGN_CREATED_PRIMARY
, signfile
);
7145 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
7151 set_primary_ufs(char *osroot
, char *sign
)
7153 const char *fcn
= "set_primary_ufs()";
7155 BAM_DPRINTF((D_FUNC_ENTRY2
, fcn
, osroot
, sign
));
7156 return (set_primary_common(osroot
, sign
));
7160 set_primary_zfs(char *osdev
, char *sign
)
7166 const char *fcn
= "set_primary_zfs()";
7168 BAM_DPRINTF((D_FUNC_ENTRY2
, fcn
, osdev
, sign
));
7170 pool
= get_pool(osdev
);
7171 INJECT_ERROR1("SET_PRIMARY_ZFS_GET_POOL", pool
= NULL
);
7173 bam_error(GET_POOL_FAILED
, osdev
);
7177 /* Pool name must exist in the sign */
7178 ret
= (strstr(sign
, pool
) != NULL
);
7179 INJECT_ERROR1("SET_PRIMARY_ZFS_POOL_SIGN_INCOMPAT", ret
= 0);
7181 bam_error(POOL_SIGN_INCOMPAT
, pool
, sign
);
7186 mntpt
= mount_top_dataset(pool
, &mnted
);
7187 INJECT_ERROR1("SET_PRIMARY_ZFS_MOUNT_DATASET", mntpt
= NULL
);
7188 if (mntpt
== NULL
) {
7189 bam_error(FAIL_MNT_TOP_DATASET
, pool
);
7194 ret
= set_primary_common(mntpt
, sign
);
7196 (void) umount_top_dataset(pool
, mnted
, mntpt
);
7200 INJECT_ERROR1("SET_PRIMARY_ZFS_FAIL", ret
= 1);
7202 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
7204 BAM_DPRINTF((D_RETURN_FAILURE
, fcn
));
7211 set_primary(char *osroot
, char *osdev
, char *sign
, char *fstype
)
7213 const char *fcn
= "set_primary()";
7216 INJECT_ERROR1("SET_PRIMARY_FSTYPE", fstype
= "foofs");
7217 if (strcmp(fstype
, "ufs") == 0) {
7218 BAM_DPRINTF((D_SET_PRIMARY_UFS
, fcn
));
7219 ret
= set_primary_ufs(osroot
, sign
);
7220 } else if (strcmp(fstype
, "zfs") == 0) {
7221 BAM_DPRINTF((D_SET_PRIMARY_ZFS
, fcn
));
7222 ret
= set_primary_zfs(osdev
, sign
);
7224 bam_error(GRUBSIGN_NOTSUP
, fstype
);
7229 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
7231 BAM_DPRINTF((D_RETURN_FAILURE
, fcn
));
7238 ufs_add_to_sign_list(char *sign
)
7241 char signline
[MAXNAMELEN
];
7245 const char *fcn
= "ufs_add_to_sign_list()";
7247 INJECT_ERROR1("ADD_TO_SIGN_LIST_NOT_UFS", sign
= "pool_rpool5");
7248 if (strncmp(sign
, GRUBSIGN_UFS_PREFIX
,
7249 strlen(GRUBSIGN_UFS_PREFIX
)) != 0) {
7250 bam_error(INVALID_UFS_SIGN
, sign
);
7251 (void) unlink(UFS_SIGNATURE_LIST
);
7256 * most failures in this routine are not a fatal error
7257 * We simply unlink the /var/run file and continue
7260 ret
= rename(UFS_SIGNATURE_LIST
, UFS_SIGNATURE_LIST
".tmp");
7262 INJECT_ERROR1("ADD_TO_SIGN_LIST_RENAME", ret
= -1);
7264 bam_error(RENAME_FAIL
, UFS_SIGNATURE_LIST
".tmp",
7266 (void) unlink(UFS_SIGNATURE_LIST
);
7270 tfp
= fopen(UFS_SIGNATURE_LIST
".tmp", "a");
7272 INJECT_ERROR1("ADD_TO_SIGN_LIST_FOPEN", tfp
= NULL
);
7274 bam_error(OPEN_FAIL
, UFS_SIGNATURE_LIST
".tmp", strerror(error
));
7275 (void) unlink(UFS_SIGNATURE_LIST
".tmp");
7279 (void) snprintf(signline
, sizeof (signline
), "%s\n", sign
);
7281 ret
= fputs(signline
, tfp
);
7283 INJECT_ERROR1("ADD_TO_SIGN_LIST_FPUTS", ret
= 0);
7284 if (ret
!= strlen(signline
)) {
7285 bam_error(SIGN_LIST_FPUTS_ERR
, sign
, strerror(error
));
7287 (void) unlink(UFS_SIGNATURE_LIST
".tmp");
7293 INJECT_ERROR1("ADD_TO_SIGN_LIST_FCLOSE", ret
= EOF
);
7295 bam_error(CLOSE_FAIL
, UFS_SIGNATURE_LIST
".tmp",
7297 (void) unlink(UFS_SIGNATURE_LIST
".tmp");
7301 /* Sort the list again */
7302 (void) snprintf(cmd
, sizeof (cmd
),
7303 "/usr/bin/sort -u %s.tmp > %s.sorted",
7304 UFS_SIGNATURE_LIST
, UFS_SIGNATURE_LIST
);
7306 ret
= exec_cmd(cmd
, NULL
);
7307 INJECT_ERROR1("ADD_TO_SIGN_LIST_SORT", ret
= 1);
7309 bam_error(GRUBSIGN_SORT_FAILED
);
7310 (void) unlink(UFS_SIGNATURE_LIST
".sorted");
7311 (void) unlink(UFS_SIGNATURE_LIST
".tmp");
7315 (void) unlink(UFS_SIGNATURE_LIST
".tmp");
7317 ret
= rename(UFS_SIGNATURE_LIST
".sorted", UFS_SIGNATURE_LIST
);
7319 INJECT_ERROR1("ADD_TO_SIGN_LIST_RENAME2", ret
= -1);
7321 bam_error(RENAME_FAIL
, UFS_SIGNATURE_LIST
, strerror(error
));
7322 (void) unlink(UFS_SIGNATURE_LIST
".sorted");
7326 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
7332 set_signature(char *osroot
, char *osdev
, char *sign
, char *fstype
)
7335 const char *fcn
= "set_signature()";
7337 BAM_DPRINTF((D_FUNC_ENTRY4
, fcn
, osroot
, osdev
, sign
, fstype
));
7339 ret
= set_backup(osroot
, osdev
, sign
, fstype
);
7340 INJECT_ERROR1("SET_SIGNATURE_BACKUP", ret
= -1);
7342 BAM_DPRINTF((D_RETURN_FAILURE
, fcn
));
7343 bam_error(SET_BACKUP_FAILED
, sign
, osroot
, osdev
);
7347 ret
= set_primary(osroot
, osdev
, sign
, fstype
);
7348 INJECT_ERROR1("SET_SIGNATURE_PRIMARY", ret
= -1);
7351 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
7353 BAM_DPRINTF((D_RETURN_FAILURE
, fcn
));
7354 bam_error(SET_PRIMARY_FAILED
, sign
, osroot
, osdev
);
7361 get_grubsign(char *osroot
, char *osdev
)
7363 char *grubsign
; /* (<sign>,#,#) */
7369 const char *fcn
= "get_grubsign()";
7371 BAM_DPRINTF((D_FUNC_ENTRY2
, fcn
, osroot
, osdev
));
7372 fstype
= get_fstype(osroot
);
7373 INJECT_ERROR1("GET_GRUBSIGN_FSTYPE", fstype
= NULL
);
7374 if (fstype
== NULL
) {
7375 bam_error(GET_FSTYPE_FAILED
, osroot
);
7379 sign
= find_existing_sign(osroot
, osdev
, fstype
);
7380 INJECT_ERROR1("FIND_EXISTING_SIGN", sign
= NULL
);
7382 BAM_DPRINTF((D_GET_GRUBSIGN_NO_EXISTING
, fcn
, osroot
, osdev
));
7383 sign
= create_new_sign(osdev
, fstype
);
7384 INJECT_ERROR1("CREATE_NEW_SIGN", sign
= NULL
);
7386 bam_error(GRUBSIGN_CREATE_FAIL
, osdev
);
7392 ret
= set_signature(osroot
, osdev
, sign
, fstype
);
7393 INJECT_ERROR1("SET_SIGNATURE_FAIL", ret
= -1);
7395 bam_error(GRUBSIGN_WRITE_FAIL
, osdev
);
7398 (void) unlink(UFS_SIGNATURE_LIST
);
7405 bam_print(GRUBSIGN_FOUND_OR_CREATED
, sign
, osdev
);
7407 fdiskpart
= get_partition(osdev
);
7408 INJECT_ERROR1("GET_GRUBSIGN_FDISK", fdiskpart
= PARTNO_NOTFOUND
);
7409 if (fdiskpart
== PARTNO_NOTFOUND
) {
7410 bam_error(FDISKPART_FAIL
, osdev
);
7415 slice
= strrchr(osdev
, 's');
7417 if (fdiskpart
== PARTNO_EFI
) {
7418 fdiskpart
= atoi(&slice
[1]);
7422 grubsign
= s_calloc(1, MAXNAMELEN
+ 10);
7424 (void) snprintf(grubsign
, MAXNAMELEN
+ 10, "(%s,%d,%c)",
7425 sign
, fdiskpart
, slice
[1] + 'a' - '0');
7427 (void) snprintf(grubsign
, MAXNAMELEN
+ 10, "(%s,%d)",
7432 BAM_DPRINTF((D_GET_GRUBSIGN_SUCCESS
, fcn
, grubsign
));
7438 get_title(char *rootdir
)
7440 static char title
[80];
7442 char release
[PATH_MAX
];
7444 const char *fcn
= "get_title()";
7446 /* open the /etc/release file */
7447 (void) snprintf(release
, sizeof (release
), "%s/etc/release", rootdir
);
7449 fp
= fopen(release
, "r");
7451 bam_error(OPEN_FAIL
, release
, strerror(errno
));
7456 /* grab first line of /etc/release */
7457 cp
= s_fgets(title
, sizeof (title
), fp
);
7459 while (isspace(*cp
)) /* remove leading spaces */
7466 cp
= cp
? cp
: "Oracle Solaris";
7468 BAM_DPRINTF((D_GET_TITLE
, fcn
, cp
));
7474 get_special(char *mountp
)
7477 struct mnttab mp
= {0};
7478 struct mnttab mpref
= {0};
7481 const char *fcn
= "get_special()";
7483 INJECT_ERROR1("GET_SPECIAL_MNTPT", mountp
= NULL
);
7484 if (mountp
== NULL
) {
7485 bam_error(GET_SPECIAL_NULL_MNTPT
);
7489 mntfp
= fopen(MNTTAB
, "r");
7491 INJECT_ERROR1("GET_SPECIAL_MNTTAB_OPEN", mntfp
= NULL
);
7492 if (mntfp
== NULL
) {
7493 bam_error(OPEN_FAIL
, MNTTAB
, strerror(error
));
7497 if (*mountp
== '\0')
7498 mpref
.mnt_mountp
= "/";
7500 mpref
.mnt_mountp
= mountp
;
7502 ret
= getmntany(mntfp
, &mp
, &mpref
);
7503 INJECT_ERROR1("GET_SPECIAL_MNTTAB_SEARCH", ret
= 1);
7505 (void) fclose(mntfp
);
7506 BAM_DPRINTF((D_GET_SPECIAL_NOT_IN_MNTTAB
, fcn
, mountp
));
7509 (void) fclose(mntfp
);
7511 BAM_DPRINTF((D_GET_SPECIAL
, fcn
, mp
.mnt_special
));
7513 return (s_strdup(mp
.mnt_special
));
7517 free_physarray(char **physarray
, int n
)
7520 const char *fcn
= "free_physarray()";
7525 BAM_DPRINTF((D_FUNC_ENTRY_N1
, fcn
, n
));
7527 for (i
= 0; i
< n
; i
++) {
7532 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
7536 zfs_get_physical(char *special
, char ***physarray
, int *n
)
7538 char sdup
[PATH_MAX
];
7542 filelist_t flist
= {0};
7548 const char *fcn
= "zfs_get_physical()";
7552 BAM_DPRINTF((D_FUNC_ENTRY1
, fcn
, special
));
7554 INJECT_ERROR1("INVALID_ZFS_SPECIAL", special
= "/foo");
7555 if (special
[0] == '/') {
7556 bam_error(INVALID_ZFS_SPECIAL
, special
);
7560 (void) strlcpy(sdup
, special
, sizeof (sdup
));
7562 pool
= strtok(sdup
, "/");
7563 INJECT_ERROR1("ZFS_GET_PHYS_POOL", pool
= NULL
);
7565 bam_error(CANT_FIND_POOL_FROM_SPECIAL
, special
);
7569 (void) snprintf(cmd
, sizeof (cmd
), "/sbin/zpool status %s", pool
);
7571 ret
= exec_cmd(cmd
, &flist
);
7572 INJECT_ERROR1("ZFS_GET_PHYS_STATUS", ret
= 1);
7574 bam_error(ZFS_GET_POOL_STATUS
, pool
);
7578 INJECT_ERROR1("ZFS_GET_PHYS_STATUS_OUT", flist
.head
= NULL
);
7579 if (flist
.head
== NULL
) {
7580 bam_error(BAD_ZPOOL_STATUS
, pool
);
7581 filelist_free(&flist
);
7585 for (lp
= flist
.head
; lp
; lp
= lp
->next
) {
7586 BAM_DPRINTF((D_STRTOK_ZPOOL_STATUS
, fcn
, lp
->line
));
7587 comp1
= strtok(lp
->line
, " \t");
7588 if (comp1
== NULL
) {
7592 comp1
= s_strdup(comp1
);
7598 for (lp
= flist
.head
; lp
; lp
= lp
->next
) {
7599 if (lp
->line
== NULL
)
7601 if (strcmp(lp
->line
, pool
) == 0) {
7602 BAM_DPRINTF((D_FOUND_POOL_IN_ZPOOL_STATUS
, fcn
, pool
));
7608 bam_error(NO_POOL_IN_ZPOOL_STATUS
, pool
);
7609 filelist_free(&flist
);
7614 for (i
= 0, lp
= startlp
; lp
; lp
= lp
->next
) {
7615 if (lp
->line
== NULL
)
7617 if (strcmp(lp
->line
, "mirror") == 0)
7619 if (lp
->line
[0] == '\0' || strcmp(lp
->line
, "errors:") == 0)
7622 BAM_DPRINTF((D_COUNTING_ZFS_PHYS
, fcn
, i
));
7626 bam_error(NO_PHYS_IN_ZPOOL_STATUS
, pool
);
7627 filelist_free(&flist
);
7632 *physarray
= s_calloc(*n
, sizeof (char *));
7633 for (i
= 0, lp
= startlp
; lp
; lp
= lp
->next
) {
7634 if (lp
->line
== NULL
)
7636 if (strcmp(lp
->line
, "mirror") == 0)
7638 if (strcmp(lp
->line
, "errors:") == 0)
7640 if (strncmp(lp
->line
, "/dev/dsk/", strlen("/dev/dsk/")) != 0 &&
7641 strncmp(lp
->line
, "/dev/rdsk/",
7642 strlen("/dev/rdsk/")) != 0) {
7643 (void) snprintf(dsk
, sizeof (dsk
), "/dev/rdsk/%s",
7646 (void) strlcpy(dsk
, lp
->line
, sizeof (dsk
));
7648 BAM_DPRINTF((D_ADDING_ZFS_PHYS
, fcn
, dsk
, pool
));
7649 (*physarray
)[i
++] = s_strdup(dsk
);
7654 filelist_free(&flist
);
7656 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
7661 * Certain services needed to run metastat successfully may not
7662 * be enabled. Enable them now.
7665 * Checks if the specified service is online
7666 * Returns: 1 if the service is online
7667 * 0 if the service is not online
7671 is_svc_online(char *svc
)
7674 const char *fcn
= "is_svc_online()";
7676 BAM_DPRINTF((D_FUNC_ENTRY1
, fcn
, svc
));
7678 state
= smf_get_state(svc
);
7679 INJECT_ERROR2("GET_SVC_STATE", free(state
), state
= NULL
);
7680 if (state
== NULL
) {
7681 bam_error(GET_SVC_STATE_ERR
, svc
);
7684 BAM_DPRINTF((D_GOT_SVC_STATUS
, fcn
, svc
));
7686 if (strcmp(state
, SCF_STATE_STRING_ONLINE
) == 0) {
7687 BAM_DPRINTF((D_SVC_ONLINE
, fcn
, svc
));
7692 BAM_DPRINTF((D_SVC_NOT_ONLINE
, fcn
, state
, svc
));
7700 enable_svc(char *svc
)
7704 const char *fcn
= "enable_svc()";
7706 ret
= is_svc_online(svc
);
7708 bam_error(SVC_IS_ONLINE_FAILED
, svc
);
7710 } else if (ret
== 1) {
7711 BAM_DPRINTF((D_SVC_ALREADY_ONLINE
, fcn
, svc
));
7715 /* Service is not enabled. Enable it now. */
7716 ret
= smf_enable_instance(svc
, 0);
7717 INJECT_ERROR1("ENABLE_SVC_FAILED", ret
= -1);
7719 bam_error(ENABLE_SVC_FAILED
, svc
);
7723 BAM_DPRINTF((D_SVC_ONLINE_INITIATED
, fcn
, svc
));
7727 ret
= is_svc_online(svc
);
7728 INJECT_ERROR1("SVC_ONLINE_SUCCESS", ret
= 1);
7729 INJECT_ERROR1("SVC_ONLINE_FAILURE", ret
= -1);
7730 INJECT_ERROR1("SVC_ONLINE_NOTYET", ret
= 0);
7732 bam_error(ERR_SVC_GET_ONLINE
, svc
);
7734 } else if (ret
== 1) {
7735 BAM_DPRINTF((D_SVC_NOW_ONLINE
, fcn
, svc
));
7739 } while (++sleeptime
< 60);
7741 bam_error(TIMEOUT_ENABLE_SVC
, svc
);
7747 ufs_get_physical(char *special
, char ***physarray
, int *n
)
7751 filelist_t flist
= {0};
7762 const char *fcn
= "ufs_get_physical()";
7766 BAM_DPRINTF((D_FUNC_ENTRY1
, fcn
, special
));
7768 if (strncmp(special
, "/dev/md/", strlen("/dev/md/")) != 0) {
7769 bam_error(UFS_GET_PHYS_NOT_SVM
, special
);
7773 if (strncmp(special
, "/dev/md/dsk/", strlen("/dev/md/dsk/")) == 0) {
7774 shortname
= special
+ strlen("/dev/md/dsk/");
7775 } else if (strncmp(special
, "/dev/md/rdsk/",
7776 strlen("/dev/md/rdsk/")) == 0) {
7777 shortname
= special
+ strlen("/dev/md/rdsk");
7779 bam_error(UFS_GET_PHYS_INVALID_SVM
, special
);
7783 BAM_DPRINTF((D_UFS_SVM_SHORT
, fcn
, special
, shortname
));
7785 svc
= "network/rpc/meta:default";
7786 if (enable_svc(svc
) == -1) {
7787 bam_error(UFS_SVM_METASTAT_SVC_ERR
, svc
);
7790 (void) snprintf(cmd
, sizeof (cmd
), "/sbin/metastat -p %s", shortname
);
7792 ret
= exec_cmd(cmd
, &flist
);
7793 INJECT_ERROR1("UFS_SVM_METASTAT", ret
= 1);
7795 bam_error(UFS_SVM_METASTAT_ERR
, shortname
);
7799 INJECT_ERROR1("UFS_SVM_METASTAT_OUT", flist
.head
= NULL
);
7800 if (flist
.head
== NULL
) {
7801 bam_error(BAD_UFS_SVM_METASTAT
, shortname
);
7802 filelist_free(&flist
);
7807 * Check if not a mirror. We only parse a single metadevice
7810 meta
= strtok(flist
.head
->line
, " \t");
7811 type
= strtok(NULL
, " \t");
7812 if (meta
== NULL
|| type
== NULL
) {
7813 bam_error(ERROR_PARSE_UFS_SVM_METASTAT
, shortname
);
7814 filelist_free(&flist
);
7817 if (strcmp(type
, "-m") != 0) {
7818 comp1
= strtok(NULL
, " \t");
7819 comp2
= strtok(NULL
, " \t");
7820 if (comp1
== NULL
|| comp2
!= NULL
) {
7821 bam_error(INVALID_UFS_SVM_METASTAT
, shortname
);
7822 filelist_free(&flist
);
7825 BAM_DPRINTF((D_UFS_SVM_ONE_COMP
, fcn
, comp1
, shortname
));
7826 *physarray
= s_calloc(1, sizeof (char *));
7827 (*physarray
)[0] = s_strdup(comp1
);
7829 filelist_free(&flist
);
7834 * Okay we have a mirror. Everything after the first line
7837 for (i
= 0, lp
= flist
.head
->next
; lp
; lp
= lp
->next
) {
7838 if (strstr(lp
->line
, "/dev/dsk/") == NULL
&&
7839 strstr(lp
->line
, "/dev/rdsk/") == NULL
) {
7840 bam_error(CANNOT_PARSE_UFS_SVM_METASTAT
, shortname
);
7841 filelist_free(&flist
);
7847 *physarray
= s_calloc(i
, sizeof (char *));
7850 for (i
= 0, lp
= flist
.head
->next
; lp
; lp
= lp
->next
) {
7851 comp1
= strtok(lp
->line
, " \t");
7852 comp2
= strtok(NULL
, " \t");
7853 comp3
= strtok(NULL
, " \t");
7854 comp4
= strtok(NULL
, " \t");
7856 if (comp3
== NULL
|| comp4
== NULL
||
7857 (strncmp(comp4
, "/dev/dsk/", strlen("/dev/dsk/")) != 0 &&
7858 strncmp(comp4
, "/dev/rdsk/", strlen("/dev/rdsk/")) != 0)) {
7859 bam_error(CANNOT_PARSE_UFS_SVM_SUBMIRROR
, shortname
);
7860 filelist_free(&flist
);
7861 free_physarray(*physarray
, *n
);
7865 (*physarray
)[i
++] = s_strdup(comp4
);
7870 filelist_free(&flist
);
7872 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
7877 get_physical(char *menu_root
, char ***physarray
, int *n
)
7881 const char *fcn
= "get_physical()";
7890 BAM_DPRINTF((D_FUNC_ENTRY1
, fcn
, menu_root
));
7892 /* First get the device special file from /etc/mnttab */
7893 special
= get_special(menu_root
);
7894 INJECT_ERROR1("GET_PHYSICAL_SPECIAL", special
= NULL
);
7895 if (special
== NULL
) {
7896 bam_error(GET_SPECIAL_NULL
, menu_root
);
7900 /* If already a physical device nothing to do */
7901 if (strncmp(special
, "/dev/dsk/", strlen("/dev/dsk/")) == 0 ||
7902 strncmp(special
, "/dev/rdsk/", strlen("/dev/rdsk/")) == 0) {
7903 BAM_DPRINTF((D_GET_PHYSICAL_ALREADY
, fcn
, menu_root
, special
));
7904 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
7905 *physarray
= s_calloc(1, sizeof (char *));
7906 (*physarray
)[0] = special
;
7911 if (is_zfs(menu_root
)) {
7912 ret
= zfs_get_physical(special
, physarray
, n
);
7913 } else if (is_ufs(menu_root
)) {
7914 ret
= ufs_get_physical(special
, physarray
, n
);
7916 bam_error(GET_PHYSICAL_NOTSUP_FSTYPE
, menu_root
, special
);
7922 INJECT_ERROR1("GET_PHYSICAL_RET", ret
= -1);
7924 BAM_DPRINTF((D_RETURN_FAILURE
, fcn
));
7928 for (i
= 0; i
< *n
; i
++) {
7929 BAM_DPRINTF((D_GET_PHYSICAL_RET
, fcn
, (*physarray
)[i
]));
7937 is_bootdisk(char *osroot
, char *physical
)
7942 const char *fcn
= "is_bootdisk()";
7947 BAM_DPRINTF((D_FUNC_ENTRY2
, fcn
, osroot
, physical
));
7949 bootp
= strstr(physical
, "p0:boot");
7953 * We just want the BIOS mapping for menu disk.
7954 * Don't pass menu_root to get_grubroot() as the
7955 * check that it is used for is not relevant here.
7956 * The osroot is immaterial as well - it is only used to
7957 * to find create_diskmap script. Everything hinges on
7960 grubroot
= get_grubroot(osroot
, physical
, NULL
);
7962 INJECT_ERROR1("IS_BOOTDISK_GRUBROOT", grubroot
= NULL
);
7963 if (grubroot
== NULL
) {
7965 bam_error(NO_GRUBROOT_FOR_DISK
, physical
);
7968 ret
= grubroot
[3] == '0';
7971 BAM_DPRINTF((D_RETURN_RET
, fcn
, ret
));
7977 * Check if menu is on the boot device
7978 * Return 0 (false) on error
7981 menu_on_bootdisk(char *osroot
, char *menu_root
)
7988 const char *fcn
= "menu_on_bootdisk()";
7990 BAM_DPRINTF((D_FUNC_ENTRY2
, fcn
, osroot
, menu_root
));
7992 ret
= get_physical(menu_root
, &physarray
, &n
);
7993 INJECT_ERROR1("MENU_ON_BOOTDISK_PHYSICAL", ret
= -1);
7995 bam_error(GET_PHYSICAL_MENU_NULL
, menu_root
);
8003 for (i
= 0; i
< n
; i
++) {
8004 assert(strncmp(physarray
[i
], "/dev/dsk/",
8005 strlen("/dev/dsk/")) == 0 ||
8006 strncmp(physarray
[i
], "/dev/rdsk/",
8007 strlen("/dev/rdsk/")) == 0);
8009 BAM_DPRINTF((D_CHECK_ON_BOOTDISK
, fcn
, physarray
[i
]));
8010 if (is_bootdisk(osroot
, physarray
[i
])) {
8012 BAM_DPRINTF((D_IS_ON_BOOTDISK
, fcn
, physarray
[i
]));
8016 free_physarray(physarray
, n
);
8018 INJECT_ERROR1("ON_BOOTDISK_YES", on_bootdisk
= 1);
8019 INJECT_ERROR1("ON_BOOTDISK_NO", on_bootdisk
= 0);
8021 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
8023 BAM_DPRINTF((D_RETURN_FAILURE
, fcn
));
8026 return (on_bootdisk
);
8030 bam_add_line(menu_t
*mp
, entry_t
*entry
, line_t
*prev
, line_t
*lp
)
8032 const char *fcn
= "bam_add_line()";
8039 lp
->next
= prev
->next
;
8041 BAM_DPRINTF((D_ADD_LINE_PREV_NEXT
, fcn
));
8042 prev
->next
->prev
= lp
;
8044 BAM_DPRINTF((D_ADD_LINE_NOT_PREV_NEXT
, fcn
));
8049 if (entry
->end
== prev
) {
8050 BAM_DPRINTF((D_ADD_LINE_LAST_LINE_IN_ENTRY
, fcn
));
8053 if (mp
->end
== prev
) {
8054 assert(lp
->next
== NULL
);
8056 BAM_DPRINTF((D_ADD_LINE_LAST_LINE_IN_MENU
, fcn
));
8061 * look for matching bootadm entry with specified parameters
8062 * Here are the rules (based on existing usage):
8063 * - If title is specified, match on title only
8064 * - Else, match on root/findroot, kernel, and module.
8065 * Note that, if root_opt is non-zero, the absence of
8066 * root line is considered a match.
8082 const char *fcn
= "find_boot_entry()";
8085 *entry_num
= BAM_ERROR
;
8087 /* find matching entry */
8088 for (i
= 0, ent
= mp
->entries
; ent
; i
++, ent
= ent
->next
) {
8091 /* first line of entry must be bootadm comment */
8093 if (lp
->flags
!= BAM_COMMENT
||
8094 strcmp(lp
->arg
, BAM_BOOTADM_HDR
) != 0) {
8098 /* advance to title line */
8101 if (lp
->flags
== BAM_TITLE
&& lp
->arg
&&
8102 strcmp(lp
->arg
, title
) == 0) {
8103 BAM_DPRINTF((D_MATCHED_TITLE
, fcn
, title
));
8106 BAM_DPRINTF((D_NOMATCH_TITLE
, fcn
, title
, lp
->arg
));
8107 continue; /* check title only */
8110 lp
= lp
->next
; /* advance to root line */
8113 } else if (lp
->cmd
!= NULL
&&
8114 strcmp(lp
->cmd
, menu_cmds
[FINDROOT_CMD
]) == 0) {
8115 INJECT_ERROR1("FIND_BOOT_ENTRY_NULL_FINDROOT",
8117 if (findroot
== NULL
) {
8118 BAM_DPRINTF((D_NOMATCH_FINDROOT_NULL
,
8122 /* findroot command found, try match */
8123 if (strcmp(lp
->arg
, findroot
) != 0) {
8124 BAM_DPRINTF((D_NOMATCH_FINDROOT
,
8125 fcn
, findroot
, lp
->arg
));
8128 BAM_DPRINTF((D_MATCHED_FINDROOT
, fcn
, findroot
));
8129 lp
= lp
->next
; /* advance to kernel line */
8130 } else if (lp
->cmd
!= NULL
&&
8131 strcmp(lp
->cmd
, menu_cmds
[ROOT_CMD
]) == 0) {
8132 INJECT_ERROR1("FIND_BOOT_ENTRY_NULL_ROOT", root
= NULL
);
8134 BAM_DPRINTF((D_NOMATCH_ROOT_NULL
,
8138 /* root cmd found, try match */
8139 if (strcmp(lp
->arg
, root
) != 0) {
8140 BAM_DPRINTF((D_NOMATCH_ROOT
,
8141 fcn
, root
, lp
->arg
));
8144 BAM_DPRINTF((D_MATCHED_ROOT
, fcn
, root
));
8145 lp
= lp
->next
; /* advance to kernel line */
8147 INJECT_ERROR1("FIND_BOOT_ENTRY_ROOT_OPT_NO",
8149 INJECT_ERROR1("FIND_BOOT_ENTRY_ROOT_OPT_YES",
8151 /* no root command, see if root is optional */
8152 if (root_opt
== 0) {
8153 BAM_DPRINTF((D_NO_ROOT_OPT
, fcn
));
8156 BAM_DPRINTF((D_ROOT_OPT
, fcn
));
8159 if (lp
== NULL
|| lp
->next
== NULL
) {
8164 (!check_cmd(lp
->cmd
, KERNEL_CMD
, lp
->arg
, kernel
))) {
8165 if (!(ent
->flags
& BAM_ENTRY_FAILSAFE
) ||
8166 !(ent
->flags
& BAM_ENTRY_DBOOT
) ||
8167 strcmp(kernel
, DIRECT_BOOT_FAILSAFE_LINE
) != 0)
8170 ent
->flags
|= BAM_ENTRY_UPGFSKERNEL
;
8173 BAM_DPRINTF((D_KERNEL_MATCH
, fcn
, kernel
, lp
->arg
));
8176 * Check for matching module entry (failsafe or normal).
8177 * If it fails to match, we go around the loop again.
8178 * For xpv entries, there are two module lines, so we
8179 * do the check twice.
8181 lp
= lp
->next
; /* advance to module line */
8182 if (check_cmd(lp
->cmd
, MODULE_CMD
, lp
->arg
, module
) ||
8183 (((lp
= lp
->next
) != NULL
) &&
8184 check_cmd(lp
->cmd
, MODULE_CMD
, lp
->arg
, module
))) {
8186 BAM_DPRINTF((D_MODULE_MATCH
, fcn
, module
, lp
->arg
));
8190 if (strcmp(module
, FAILSAFE_ARCHIVE
) == 0 &&
8191 (strcmp(lp
->prev
->arg
, FAILSAFE_ARCHIVE_32
) == 0 ||
8192 strcmp(lp
->prev
->arg
, FAILSAFE_ARCHIVE_64
) == 0)) {
8193 ent
->flags
|= BAM_ENTRY_UPGFSMODULE
;
8199 if (ent
&& entry_num
) {
8204 BAM_DPRINTF((D_RETURN_RET
, fcn
, i
));
8206 BAM_DPRINTF((D_RETURN_RET
, fcn
, BAM_ERROR
));
8212 update_boot_entry(menu_t
*mp
, char *title
, char *findroot
, char *root
,
8213 char *kernel
, char *mod_kernel
, char *module
, int root_opt
)
8216 int change_kernel
= 0;
8220 char linebuf
[BAM_MAXLINE
];
8221 const char *fcn
= "update_boot_entry()";
8223 /* note: don't match on title, it's updated on upgrade */
8224 ent
= find_boot_entry(mp
, NULL
, kernel
, findroot
, root
, module
,
8226 if ((ent
== NULL
) && (bam_direct
== BAM_DIRECT_DBOOT
)) {
8228 * We may be upgrading a kernel from multiboot to
8229 * directboot. Look for a multiboot entry. A multiboot
8230 * entry will not have a findroot line.
8232 ent
= find_boot_entry(mp
, NULL
, "multiboot", NULL
, root
,
8233 MULTIBOOT_ARCHIVE
, root_opt
, &i
);
8235 BAM_DPRINTF((D_UPGRADE_FROM_MULTIBOOT
, fcn
, root
));
8239 BAM_DPRINTF((D_FOUND_FINDROOT
, fcn
, findroot
));
8243 BAM_DPRINTF((D_ENTRY_NOT_FOUND_CREATING
, fcn
, findroot
));
8244 return (add_boot_entry(mp
, title
, findroot
,
8245 kernel
, mod_kernel
, module
, NULL
));
8248 /* replace title of existing entry and update findroot line */
8250 lp
= lp
->next
; /* title line */
8251 (void) snprintf(linebuf
, sizeof (linebuf
), "%s%s%s",
8252 menu_cmds
[TITLE_CMD
], menu_cmds
[SEP_CMD
], title
);
8255 lp
->arg
= s_strdup(title
);
8256 lp
->line
= s_strdup(linebuf
);
8257 BAM_DPRINTF((D_CHANGING_TITLE
, fcn
, title
));
8259 tlp
= lp
; /* title line */
8260 lp
= lp
->next
; /* root line */
8262 /* if no root or findroot command, create a new line_t */
8263 if ((lp
->cmd
!= NULL
) && (strcmp(lp
->cmd
, menu_cmds
[ROOT_CMD
]) != 0 &&
8264 strcmp(lp
->cmd
, menu_cmds
[FINDROOT_CMD
]) != 0)) {
8265 lp
= s_calloc(1, sizeof (line_t
));
8266 bam_add_line(mp
, ent
, tlp
, lp
);
8268 if (lp
->cmd
!= NULL
)
8276 lp
->cmd
= s_strdup(menu_cmds
[FINDROOT_CMD
]);
8277 lp
->sep
= s_strdup(menu_cmds
[SEP_CMD
]);
8278 lp
->arg
= s_strdup(findroot
);
8279 (void) snprintf(linebuf
, sizeof (linebuf
), "%s%s%s",
8280 menu_cmds
[FINDROOT_CMD
], menu_cmds
[SEP_CMD
], findroot
);
8281 lp
->line
= s_strdup(linebuf
);
8282 BAM_DPRINTF((D_ADDING_FINDROOT_LINE
, fcn
, findroot
));
8287 if (ent
->flags
& BAM_ENTRY_UPGFSKERNEL
) {
8288 char *params
= NULL
;
8290 params
= strstr(lp
->line
, "-s");
8292 (void) snprintf(linebuf
, sizeof (linebuf
), "%s%s%s%s",
8293 menu_cmds
[KERNEL_DOLLAR_CMD
], menu_cmds
[SEP_CMD
],
8296 (void) snprintf(linebuf
, sizeof (linebuf
), "%s%s%s",
8297 menu_cmds
[KERNEL_DOLLAR_CMD
], menu_cmds
[SEP_CMD
],
8300 if (lp
->cmd
!= NULL
)
8305 lp
->cmd
= s_strdup(menu_cmds
[KERNEL_DOLLAR_CMD
]);
8306 lp
->arg
= s_strdup(strstr(linebuf
, "/"));
8307 lp
->line
= s_strdup(linebuf
);
8308 ent
->flags
&= ~BAM_ENTRY_UPGFSKERNEL
;
8309 BAM_DPRINTF((D_ADDING_KERNEL_DOLLAR
, fcn
, lp
->prev
->cmd
));
8312 if (change_kernel
) {
8314 * We're upgrading from multiboot to directboot.
8316 if (lp
->cmd
!= NULL
&&
8317 strcmp(lp
->cmd
, menu_cmds
[KERNEL_CMD
]) == 0) {
8318 (void) snprintf(linebuf
, sizeof (linebuf
), "%s%s%s",
8319 menu_cmds
[KERNEL_DOLLAR_CMD
], menu_cmds
[SEP_CMD
],
8324 lp
->cmd
= s_strdup(menu_cmds
[KERNEL_DOLLAR_CMD
]);
8325 lp
->arg
= s_strdup(kernel
);
8326 lp
->line
= s_strdup(linebuf
);
8328 BAM_DPRINTF((D_ADDING_KERNEL_DOLLAR
, fcn
, kernel
));
8330 if (lp
->cmd
!= NULL
&&
8331 strcmp(lp
->cmd
, menu_cmds
[MODULE_CMD
]) == 0) {
8332 (void) snprintf(linebuf
, sizeof (linebuf
), "%s%s%s",
8333 menu_cmds
[MODULE_DOLLAR_CMD
], menu_cmds
[SEP_CMD
],
8338 lp
->cmd
= s_strdup(menu_cmds
[MODULE_DOLLAR_CMD
]);
8339 lp
->arg
= s_strdup(module
);
8340 lp
->line
= s_strdup(linebuf
);
8342 BAM_DPRINTF((D_ADDING_MODULE_DOLLAR
, fcn
, module
));
8349 if (ent
->flags
& BAM_ENTRY_UPGFSMODULE
) {
8350 if (lp
->cmd
!= NULL
&&
8351 strcmp(lp
->cmd
, menu_cmds
[MODULE_CMD
]) == 0) {
8352 (void) snprintf(linebuf
, sizeof (linebuf
), "%s%s%s",
8353 menu_cmds
[MODULE_DOLLAR_CMD
], menu_cmds
[SEP_CMD
],
8358 lp
->cmd
= s_strdup(menu_cmds
[MODULE_DOLLAR_CMD
]);
8359 lp
->arg
= s_strdup(module
);
8360 lp
->line
= s_strdup(linebuf
);
8362 ent
->flags
&= ~BAM_ENTRY_UPGFSMODULE
;
8363 BAM_DPRINTF((D_ADDING_MODULE_DOLLAR
, fcn
, module
));
8367 BAM_DPRINTF((D_RETURN_RET
, fcn
, i
));
8372 root_optional(char *osroot
, char *menu_root
)
8380 const char *fcn
= "root_optional()";
8382 BAM_DPRINTF((D_FUNC_ENTRY2
, fcn
, osroot
, menu_root
));
8385 * For all filesystems except ZFS, a straight compare of osroot
8386 * and menu_root will tell us if root is optional.
8387 * For ZFS, the situation is complicated by the fact that
8388 * menu_root and osroot are always different
8390 ret1
= is_zfs(osroot
);
8391 ret2
= is_zfs(menu_root
);
8392 INJECT_ERROR1("ROOT_OPT_NOT_ZFS", ret1
= 0);
8393 if (!ret1
|| !ret2
) {
8394 BAM_DPRINTF((D_ROOT_OPT_NOT_ZFS
, fcn
, osroot
, menu_root
));
8395 root_opt
= (strcmp(osroot
, menu_root
) == 0);
8399 ospecial
= get_special(osroot
);
8400 INJECT_ERROR1("ROOT_OPTIONAL_OSPECIAL", ospecial
= NULL
);
8401 if (ospecial
== NULL
) {
8402 bam_error(GET_OSROOT_SPECIAL_ERR
, osroot
);
8405 BAM_DPRINTF((D_ROOT_OPTIONAL_OSPECIAL
, fcn
, ospecial
, osroot
));
8407 mspecial
= get_special(menu_root
);
8408 INJECT_ERROR1("ROOT_OPTIONAL_MSPECIAL", mspecial
= NULL
);
8409 if (mspecial
== NULL
) {
8410 bam_error(GET_MENU_ROOT_SPECIAL_ERR
, menu_root
);
8414 BAM_DPRINTF((D_ROOT_OPTIONAL_MSPECIAL
, fcn
, mspecial
, menu_root
));
8416 slash
= strchr(ospecial
, '/');
8419 BAM_DPRINTF((D_ROOT_OPTIONAL_FIXED_OSPECIAL
, fcn
, ospecial
, osroot
));
8421 root_opt
= (strcmp(ospecial
, mspecial
) == 0);
8427 INJECT_ERROR1("ROOT_OPTIONAL_NO", root_opt
= 0);
8428 INJECT_ERROR1("ROOT_OPTIONAL_YES", root_opt
= 1);
8430 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
8432 BAM_DPRINTF((D_RETURN_FAILURE
, fcn
));
8440 update_entry(menu_t
*mp
, char *menu_root
, char *osdev
)
8446 char osroot
[PATH_MAX
];
8447 char *failsafe_kernel
= NULL
;
8450 char failsafe_64
[256];
8452 const char *fcn
= "update_entry()";
8459 BAM_DPRINTF((D_FUNC_ENTRY3
, fcn
, menu_root
, osdev
, bam_root
));
8461 (void) strlcpy(osroot
, bam_root
, sizeof (osroot
));
8463 title
= get_title(osroot
);
8466 grubsign
= get_grubsign(osroot
, osdev
);
8467 INJECT_ERROR1("GET_GRUBSIGN_FAIL", grubsign
= NULL
);
8468 if (grubsign
== NULL
) {
8469 bam_error(GET_GRUBSIGN_ERROR
, osroot
, osdev
);
8474 * It is not a fatal error if get_grubroot() fails
8475 * We no longer rely on biosdev to populate the
8478 grubroot
= get_grubroot(osroot
, osdev
, menu_root
);
8479 INJECT_ERROR1("GET_GRUBROOT_FAIL", grubroot
= NULL
);
8481 BAM_DPRINTF((D_GET_GRUBROOT_SUCCESS
,
8482 fcn
, osroot
, osdev
, menu_root
));
8484 BAM_DPRINTF((D_GET_GRUBROOT_FAILURE
,
8485 fcn
, osroot
, osdev
, menu_root
));
8488 /* add the entry for normal Solaris */
8489 INJECT_ERROR1("UPDATE_ENTRY_MULTIBOOT",
8490 bam_direct
= BAM_DIRECT_MULTIBOOT
);
8491 if (bam_direct
== BAM_DIRECT_DBOOT
) {
8492 entry
= update_boot_entry(mp
, title
, grubsign
, grubroot
,
8493 (bam_zfs
? DIRECT_BOOT_KERNEL_ZFS
: DIRECT_BOOT_KERNEL
),
8494 NULL
, DIRECT_BOOT_ARCHIVE
,
8495 root_optional(osroot
, menu_root
));
8496 BAM_DPRINTF((D_UPDATED_BOOT_ENTRY
, fcn
, bam_zfs
, grubsign
));
8497 if ((entry
!= BAM_ERROR
) && (bam_is_hv
== BAM_HV_PRESENT
)) {
8498 (void) update_boot_entry(mp
, NEW_HV_ENTRY
, grubsign
,
8499 grubroot
, XEN_MENU
, bam_zfs
?
8500 XEN_KERNEL_MODULE_LINE_ZFS
: XEN_KERNEL_MODULE_LINE
,
8501 DIRECT_BOOT_ARCHIVE
,
8502 root_optional(osroot
, menu_root
));
8503 BAM_DPRINTF((D_UPDATED_HV_ENTRY
,
8504 fcn
, bam_zfs
, grubsign
));
8507 entry
= update_boot_entry(mp
, title
, grubsign
, grubroot
,
8508 MULTI_BOOT
, NULL
, MULTIBOOT_ARCHIVE
,
8509 root_optional(osroot
, menu_root
));
8511 BAM_DPRINTF((D_UPDATED_MULTIBOOT_ENTRY
, fcn
, grubsign
));
8515 * Add the entry for failsafe archive. On a bfu'd system, the
8516 * failsafe may be different than the installed kernel.
8518 (void) snprintf(failsafe
, sizeof (failsafe
), "%s%s",
8519 osroot
, FAILSAFE_ARCHIVE_32
);
8520 (void) snprintf(failsafe_64
, sizeof (failsafe_64
), "%s%s",
8521 osroot
, FAILSAFE_ARCHIVE_64
);
8524 * Check if at least one of the two archives exists
8525 * Using $ISADIR as the default line, we have an entry which works
8526 * for both the cases.
8529 if (stat(failsafe
, &sbuf
) == 0 || stat(failsafe_64
, &sbuf
) == 0) {
8531 /* Figure out where the kernel line should point */
8532 (void) snprintf(failsafe
, sizeof (failsafe
), "%s%s", osroot
,
8533 DIRECT_BOOT_FAILSAFE_32
);
8534 (void) snprintf(failsafe_64
, sizeof (failsafe_64
), "%s%s",
8535 osroot
, DIRECT_BOOT_FAILSAFE_64
);
8536 if (stat(failsafe
, &sbuf
) == 0 ||
8537 stat(failsafe_64
, &sbuf
) == 0) {
8538 failsafe_kernel
= DIRECT_BOOT_FAILSAFE_LINE
;
8540 (void) snprintf(failsafe
, sizeof (failsafe
), "%s%s",
8541 osroot
, MULTI_BOOT_FAILSAFE
);
8542 if (stat(failsafe
, &sbuf
) == 0) {
8543 failsafe_kernel
= MULTI_BOOT_FAILSAFE_LINE
;
8546 if (failsafe_kernel
!= NULL
) {
8547 (void) update_boot_entry(mp
, FAILSAFE_TITLE
, grubsign
,
8548 grubroot
, failsafe_kernel
, NULL
, FAILSAFE_ARCHIVE
,
8549 root_optional(osroot
, menu_root
));
8550 BAM_DPRINTF((D_UPDATED_FAILSAFE_ENTRY
, fcn
,
8556 INJECT_ERROR1("UPDATE_ENTRY_ERROR", entry
= BAM_ERROR
);
8557 if (entry
== BAM_ERROR
) {
8558 bam_error(FAILED_TO_ADD_BOOT_ENTRY
, title
, grubsign
);
8564 update_numbering(mp
);
8565 ret
= set_global(mp
, menu_cmds
[DEFAULT_CMD
], entry
);
8566 INJECT_ERROR1("SET_DEFAULT_ERROR", ret
= BAM_ERROR
);
8567 if (ret
== BAM_ERROR
) {
8568 bam_error(SET_DEFAULT_FAILED
, entry
);
8570 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
8575 save_default_entry(menu_t
*mp
, const char *which
)
8579 int entry
= 0; /* default is 0 */
8580 char linebuf
[BAM_MAXLINE
];
8581 line_t
*lp
= mp
->curdefault
;
8582 const char *fcn
= "save_default_entry()";
8585 lineNum
= mp
->end
->lineNum
;
8586 entryNum
= mp
->end
->entryNum
;
8588 lineNum
= LINE_INIT
;
8589 entryNum
= ENTRY_INIT
;
8593 entry
= s_strtol(lp
->arg
);
8595 (void) snprintf(linebuf
, sizeof (linebuf
), "#%s%d", which
, entry
);
8596 BAM_DPRINTF((D_SAVING_DEFAULT_TO
, fcn
, linebuf
));
8597 line_parser(mp
, linebuf
, &lineNum
, &entryNum
);
8598 BAM_DPRINTF((D_SAVED_DEFAULT_TO
, fcn
, lineNum
, entryNum
));
8602 restore_default_entry(menu_t
*mp
, const char *which
, line_t
*lp
)
8606 const char *fcn
= "restore_default_entry()";
8609 BAM_DPRINTF((D_RESTORE_DEFAULT_NULL
, fcn
));
8610 return; /* nothing to restore */
8613 BAM_DPRINTF((D_RESTORE_DEFAULT_STR
, fcn
, which
));
8615 str
= lp
->arg
+ strlen(which
);
8616 entry
= s_strtol(str
);
8617 (void) set_global(mp
, menu_cmds
[DEFAULT_CMD
], entry
);
8619 BAM_DPRINTF((D_RESTORED_DEFAULT_TO
, fcn
, entry
));
8621 /* delete saved old default line */
8622 unlink_line(mp
, lp
);
8627 * This function is for supporting reboot with args.
8628 * The opt value can be:
8629 * NULL delete temp entry, if present
8630 * entry=<n> switches default entry to <n>
8631 * else treated as boot-args and setup a temperary menu entry
8632 * and make it the default
8633 * Note that we are always rebooting the current OS instance
8634 * so osroot == / always.
8636 #define REBOOT_TITLE "Solaris_reboot_transient"
8640 update_temp(menu_t
*mp
, char *dummy
, char *opt
)
8648 char kernbuf
[BUFSIZ
];
8649 char args_buf
[BUFSIZ
];
8650 char signbuf
[PATH_MAX
];
8652 const char *fcn
= "update_temp()";
8655 assert(dummy
== NULL
);
8657 /* opt can be NULL */
8658 BAM_DPRINTF((D_FUNC_ENTRY1
, fcn
, opt
? opt
: "<NULL>"));
8659 BAM_DPRINTF((D_BAM_ROOT
, fcn
, bam_alt_root
, bam_root
));
8661 if (bam_alt_root
|| bam_rootlen
!= 1 ||
8662 strcmp(bam_root
, "/") != 0 ||
8663 strcmp(rootbuf
, "/") != 0) {
8664 bam_error(ALT_ROOT_INVALID
, bam_root
);
8668 /* If no option, delete exiting reboot menu entry */
8671 BAM_DPRINTF((D_OPT_NULL
, fcn
));
8672 ent
= find_boot_entry(mp
, REBOOT_TITLE
, NULL
, NULL
,
8673 NULL
, NULL
, 0, &entry
);
8674 if (ent
== NULL
) { /* not found is ok */
8675 BAM_DPRINTF((D_TRANSIENT_NOTFOUND
, fcn
));
8676 return (BAM_SUCCESS
);
8678 (void) delete_boot_entry(mp
, entry
, DBE_PRINTERR
);
8679 restore_default_entry(mp
, BAM_OLDDEF
, mp
->olddefault
);
8680 mp
->olddefault
= NULL
;
8681 BAM_DPRINTF((D_RESTORED_DEFAULT
, fcn
));
8682 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
8686 /* if entry= is specified, set the default entry */
8687 if (strncmp(opt
, "entry=", strlen("entry=")) == 0) {
8688 int entryNum
= s_strtol(opt
+ strlen("entry="));
8689 BAM_DPRINTF((D_ENTRY_EQUALS
, fcn
, opt
));
8690 if (selector(mp
, opt
, &entry
, NULL
) == BAM_SUCCESS
) {
8691 /* this is entry=# option */
8692 ret
= set_global(mp
, menu_cmds
[DEFAULT_CMD
], entry
);
8693 BAM_DPRINTF((D_ENTRY_SET_IS
, fcn
, entry
, ret
));
8696 bam_error(SET_DEFAULT_FAILED
, entryNum
);
8702 * add a new menu entry based on opt and make it the default
8705 fstype
= get_fstype("/");
8706 INJECT_ERROR1("REBOOT_FSTYPE_NULL", fstype
= NULL
);
8707 if (fstype
== NULL
) {
8708 bam_error(REBOOT_FSTYPE_FAILED
);
8712 osdev
= get_special("/");
8713 INJECT_ERROR1("REBOOT_SPECIAL_NULL", osdev
= NULL
);
8714 if (osdev
== NULL
) {
8716 bam_error(REBOOT_SPECIAL_FAILED
);
8720 sign
= find_existing_sign("/", osdev
, fstype
);
8721 INJECT_ERROR1("REBOOT_SIGN_NULL", sign
= NULL
);
8725 bam_error(REBOOT_SIGN_FAILED
);
8730 (void) strlcpy(signbuf
, sign
, sizeof (signbuf
));
8733 assert(strchr(signbuf
, '(') == NULL
&& strchr(signbuf
, ',') == NULL
&&
8734 strchr(signbuf
, ')') == NULL
);
8737 * There is no alternate root while doing reboot with args
8738 * This version of bootadm is only delivered with a DBOOT
8739 * version of Solaris.
8741 INJECT_ERROR1("REBOOT_NOT_DBOOT", bam_direct
= BAM_DIRECT_MULTIBOOT
);
8742 if (bam_direct
!= BAM_DIRECT_DBOOT
) {
8744 bam_error(REBOOT_DIRECT_FAILED
);
8748 /* add an entry for Solaris reboot */
8749 if (opt
[0] == '-') {
8750 /* It's an option - first see if boot-file is set */
8751 ret
= get_kernel(mp
, KERNEL_CMD
, kernbuf
, sizeof (kernbuf
));
8752 INJECT_ERROR1("REBOOT_GET_KERNEL", ret
= BAM_ERROR
);
8753 if (ret
!= BAM_SUCCESS
) {
8755 bam_error(REBOOT_GET_KERNEL_FAILED
);
8758 if (kernbuf
[0] == '\0')
8759 (void) strlcpy(kernbuf
, DIRECT_BOOT_KERNEL
,
8762 * If this is a zfs file system and kernbuf does not
8763 * have "-B $ZFS-BOOTFS" string yet, add it.
8765 if (strcmp(fstype
, "zfs") == 0 && !strstr(kernbuf
, ZFS_BOOT
)) {
8766 (void) strlcat(kernbuf
, " ", sizeof (kernbuf
));
8767 (void) strlcat(kernbuf
, ZFS_BOOT
, sizeof (kernbuf
));
8769 (void) strlcat(kernbuf
, " ", sizeof (kernbuf
));
8770 (void) strlcat(kernbuf
, opt
, sizeof (kernbuf
));
8771 BAM_DPRINTF((D_REBOOT_OPTION
, fcn
, kernbuf
));
8772 } else if (opt
[0] == '/') {
8773 /* It's a full path, so write it out. */
8774 (void) strlcpy(kernbuf
, opt
, sizeof (kernbuf
));
8779 * # eeprom boot-args='-kd'
8780 * # reboot /platform/i86pc/kernel/unix
8782 * we want to use the boot-args as part of the boot
8783 * line. On the other hand, if someone runs:
8785 * # reboot "/platform/i86pc/kernel/unix -kd"
8787 * we don't need to mess with boot-args. If there's
8788 * no space in the options string, assume we're in the
8791 if (strchr(opt
, ' ') == NULL
) {
8792 ret
= get_kernel(mp
, ARGS_CMD
, args_buf
,
8794 INJECT_ERROR1("REBOOT_GET_ARGS", ret
= BAM_ERROR
);
8795 if (ret
!= BAM_SUCCESS
) {
8797 bam_error(REBOOT_GET_ARGS_FAILED
);
8801 if (args_buf
[0] != '\0') {
8802 (void) strlcat(kernbuf
, " ", sizeof (kernbuf
));
8803 (void) strlcat(kernbuf
, args_buf
,
8807 BAM_DPRINTF((D_REBOOT_ABSPATH
, fcn
, kernbuf
));
8810 * It may be a partial path, or it may be a partial
8811 * path followed by options. Assume that only options
8812 * follow a space. If someone sends us a kernel path
8813 * that includes a space, they deserve to be broken.
8815 opt_ptr
= strchr(opt
, ' ');
8816 if (opt_ptr
!= NULL
) {
8820 path
= expand_path(opt
);
8822 (void) strlcpy(kernbuf
, path
, sizeof (kernbuf
));
8826 * If there were options given, use those.
8827 * Otherwise, copy over the default options.
8829 if (opt_ptr
!= NULL
) {
8830 /* Restore the space in opt string */
8832 (void) strlcat(kernbuf
, opt_ptr
,
8835 ret
= get_kernel(mp
, ARGS_CMD
, args_buf
,
8837 INJECT_ERROR1("UPDATE_TEMP_PARTIAL_ARGS",
8839 if (ret
!= BAM_SUCCESS
) {
8841 bam_error(REBOOT_GET_ARGS_FAILED
);
8845 if (args_buf
[0] != '\0') {
8846 (void) strlcat(kernbuf
, " ",
8848 (void) strlcat(kernbuf
,
8849 args_buf
, sizeof (kernbuf
));
8852 BAM_DPRINTF((D_REBOOT_RESOLVED_PARTIAL
, fcn
, kernbuf
));
8855 bam_error(UNKNOWN_KERNEL
, opt
);
8856 bam_print_stderr(UNKNOWN_KERNEL_REBOOT
);
8861 entry
= add_boot_entry(mp
, REBOOT_TITLE
, signbuf
, kernbuf
,
8863 INJECT_ERROR1("REBOOT_ADD_BOOT_ENTRY", entry
= BAM_ERROR
);
8864 if (entry
== BAM_ERROR
) {
8865 bam_error(REBOOT_WITH_ARGS_ADD_ENTRY_FAILED
);
8869 save_default_entry(mp
, BAM_OLDDEF
);
8870 ret
= set_global(mp
, menu_cmds
[DEFAULT_CMD
], entry
);
8871 INJECT_ERROR1("REBOOT_SET_GLOBAL", ret
= BAM_ERROR
);
8872 if (ret
== BAM_ERROR
) {
8873 bam_error(REBOOT_SET_DEFAULT_FAILED
, entry
);
8875 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
8880 set_global(menu_t
*mp
, char *globalcmd
, int val
)
8887 char prefix
[BAM_MAXLINE
];
8889 const char *fcn
= "set_global()";
8894 if (strcmp(globalcmd
, menu_cmds
[DEFAULT_CMD
]) == 0) {
8895 INJECT_ERROR1("SET_GLOBAL_VAL_NEG", val
= -1);
8896 INJECT_ERROR1("SET_GLOBAL_MENU_EMPTY", mp
->end
= NULL
);
8897 INJECT_ERROR1("SET_GLOBAL_VAL_TOO_BIG", val
= 100);
8898 if (val
< 0 || mp
->end
== NULL
|| val
> mp
->end
->entryNum
) {
8899 (void) snprintf(prefix
, sizeof (prefix
), "%d", val
);
8900 bam_error(INVALID_ENTRY
, prefix
);
8905 found
= last
= NULL
;
8906 for (lp
= mp
->start
; lp
; lp
= lp
->next
) {
8907 if (lp
->flags
!= BAM_GLOBAL
)
8910 last
= lp
; /* track the last global found */
8912 INJECT_ERROR1("SET_GLOBAL_NULL_CMD", lp
->cmd
= NULL
);
8913 if (lp
->cmd
== NULL
) {
8914 bam_error(NO_CMD
, lp
->lineNum
);
8917 if (strcmp(globalcmd
, lp
->cmd
) != 0)
8920 BAM_DPRINTF((D_FOUND_GLOBAL
, fcn
, globalcmd
));
8923 bam_error(DUP_CMD
, globalcmd
, lp
->lineNum
, bam_root
);
8928 if (found
== NULL
) {
8929 lp
= s_calloc(1, sizeof (line_t
));
8931 lp
->next
= mp
->start
;
8933 mp
->end
= (mp
->end
) ? mp
->end
: lp
;
8935 lp
->next
= last
->next
;
8937 if (lp
->next
== NULL
)
8940 lp
->flags
= BAM_GLOBAL
; /* other fields not needed for writes */
8941 len
= strlen(globalcmd
) + strlen(menu_cmds
[SEP_CMD
]);
8942 len
+= 10; /* val < 10 digits */
8943 lp
->line
= s_calloc(1, len
);
8944 (void) snprintf(lp
->line
, len
, "%s%s%d",
8945 globalcmd
, menu_cmds
[SEP_CMD
], val
);
8946 BAM_DPRINTF((D_SET_GLOBAL_WROTE_NEW
, fcn
, lp
->line
));
8947 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
8952 * We are changing an existing entry. Retain any prefix whitespace,
8953 * but overwrite everything else. This preserves tabs added for
8958 while (*str
== ' ' || *str
== '\t')
8960 *cp
= '\0'; /* Terminate prefix */
8961 len
= strlen(prefix
) + strlen(globalcmd
);
8962 len
+= strlen(menu_cmds
[SEP_CMD
]) + 10;
8965 found
->line
= s_calloc(1, len
);
8966 (void) snprintf(found
->line
, len
,
8967 "%s%s%s%d", prefix
, globalcmd
, menu_cmds
[SEP_CMD
], val
);
8969 BAM_DPRINTF((D_SET_GLOBAL_REPLACED
, fcn
, found
->line
));
8970 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
8971 return (BAM_WRITE
); /* need a write to menu */
8975 * partial_path may be anything like "kernel/unix" or "kmdb". Try to
8976 * expand it to a full unix path. The calling function is expected to
8977 * output a message if an error occurs and NULL is returned.
8980 expand_path(const char *partial_path
)
8984 char new_path2
[PATH_MAX
];
8986 const char *fcn
= "expand_path()";
8988 new_path_len
= strlen(partial_path
) + 64;
8989 new_path
= s_calloc(1, new_path_len
);
8991 /* First, try the simplest case - something like "kernel/unix" */
8992 (void) snprintf(new_path
, new_path_len
, "/platform/i86pc/%s",
8994 if (stat(new_path
, &sb
) == 0) {
8995 BAM_DPRINTF((D_EXPAND_PATH
, fcn
, new_path
));
8999 if (strcmp(partial_path
, "kmdb") == 0) {
9000 (void) snprintf(new_path
, new_path_len
, "%s -k",
9001 DIRECT_BOOT_KERNEL
);
9002 BAM_DPRINTF((D_EXPAND_PATH
, fcn
, new_path
));
9007 * We've quickly reached unsupported usage. Try once more to
9008 * see if we were just given a glom name.
9010 (void) snprintf(new_path
, new_path_len
, "/platform/i86pc/%s/unix",
9012 (void) snprintf(new_path2
, PATH_MAX
, "/platform/i86pc/%s/amd64/unix",
9014 if (stat(new_path
, &sb
) == 0) {
9015 if (stat(new_path2
, &sb
) == 0) {
9017 * We matched both, so we actually
9018 * want to write the $ISADIR version.
9020 (void) snprintf(new_path
, new_path_len
,
9021 "/platform/i86pc/kernel/%s/$ISADIR/unix",
9024 BAM_DPRINTF((D_EXPAND_PATH
, fcn
, new_path
));
9029 BAM_DPRINTF((D_RETURN_FAILURE
, fcn
));
9034 * The kernel cmd and arg have been changed, so
9035 * check whether the archive line needs to change.
9038 set_archive_line(entry_t
*entryp
, line_t
*kernelp
)
9040 line_t
*lp
= entryp
->start
;
9043 const char *fcn
= "set_archive_line()";
9045 for (; lp
!= NULL
; lp
= lp
->next
) {
9046 if (lp
->cmd
!= NULL
&& strncmp(lp
->cmd
, menu_cmds
[MODULE_CMD
],
9047 sizeof (menu_cmds
[MODULE_CMD
]) - 1) == 0) {
9051 INJECT_ERROR1("SET_ARCHIVE_LINE_END_ENTRY", lp
= entryp
->end
);
9052 if (lp
== entryp
->end
) {
9053 BAM_DPRINTF((D_ARCHIVE_LINE_NONE
, fcn
,
9058 INJECT_ERROR1("SET_ARCHIVE_LINE_END_MENU", lp
= NULL
);
9060 BAM_DPRINTF((D_ARCHIVE_LINE_NONE
, fcn
, entryp
->entryNum
));
9064 if (strstr(kernelp
->arg
, "$ISADIR") != NULL
) {
9065 new_archive
= DIRECT_BOOT_ARCHIVE
;
9066 m_cmd
= MODULE_DOLLAR_CMD
;
9067 } else if (strstr(kernelp
->arg
, "amd64") != NULL
) {
9068 new_archive
= DIRECT_BOOT_ARCHIVE_64
;
9071 new_archive
= DIRECT_BOOT_ARCHIVE_32
;
9075 if (strcmp(lp
->arg
, new_archive
) == 0) {
9076 BAM_DPRINTF((D_ARCHIVE_LINE_NOCHANGE
, fcn
, lp
->arg
));
9080 if (lp
->cmd
!= NULL
&& strcmp(lp
->cmd
, menu_cmds
[m_cmd
]) != 0) {
9082 lp
->cmd
= s_strdup(menu_cmds
[m_cmd
]);
9086 lp
->arg
= s_strdup(new_archive
);
9088 BAM_DPRINTF((D_ARCHIVE_LINE_REPLACED
, fcn
, lp
->line
));
9092 * Title for an entry to set properties that once went in bootenv.rc.
9094 #define BOOTENV_RC_TITLE "Solaris bootenv rc"
9097 * If path is NULL, return the kernel (optnum == KERNEL_CMD) or arguments
9098 * (optnum == ARGS_CMD) in the argument buf. If path is a zero-length
9099 * string, reset the value to the default. If path is a non-zero-length
9100 * string, set the kernel or arguments.
9111 int rv
= BAM_SUCCESS
;
9112 int free_new_path
= 0;
9121 size_t old_kernel_len
= 0;
9126 char signbuf
[PATH_MAX
];
9128 const char *fcn
= "get_set_kernel()";
9130 assert(bufsize
> 0);
9132 ptr
= kernelp
= NULL
;
9133 new_arg
= old_args
= space
= NULL
;
9137 INJECT_ERROR1("GET_SET_KERNEL_NOT_DBOOT",
9138 bam_direct
= BAM_DIRECT_MULTIBOOT
);
9139 if (bam_direct
!= BAM_DIRECT_DBOOT
) {
9140 bam_error(NOT_DBOOT
, optnum
== KERNEL_CMD
? "kernel" : "args");
9145 * If a user changed the default entry to a non-bootadm controlled
9146 * one, we don't want to mess with it. Just print an error and
9149 if (mp
->curdefault
) {
9150 entryNum
= s_strtol(mp
->curdefault
->arg
);
9151 for (entryp
= mp
->entries
; entryp
; entryp
= entryp
->next
) {
9152 if (entryp
->entryNum
== entryNum
)
9155 if ((entryp
!= NULL
) &&
9156 ((entryp
->flags
& (BAM_ENTRY_BOOTADM
|BAM_ENTRY_LU
)) == 0)) {
9157 bam_error(DEFAULT_NOT_BAM
);
9162 entryp
= find_boot_entry(mp
, BOOTENV_RC_TITLE
, NULL
, NULL
, NULL
, NULL
,
9165 if (entryp
!= NULL
) {
9166 for (ptr
= entryp
->start
; ptr
&& ptr
!= entryp
->end
;
9168 if (strncmp(ptr
->cmd
, menu_cmds
[KERNEL_CMD
],
9169 sizeof (menu_cmds
[KERNEL_CMD
]) - 1) == 0) {
9174 if (kernelp
== NULL
) {
9175 bam_error(NO_KERNEL
, entryNum
);
9179 old_kernel_len
= strcspn(kernelp
->arg
, " \t");
9180 space
= old_args
= kernelp
->arg
+ old_kernel_len
;
9181 while ((*old_args
== ' ') || (*old_args
== '\t'))
9186 if (entryp
== NULL
) {
9187 BAM_DPRINTF((D_GET_SET_KERNEL_NO_RC
, fcn
));
9188 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
9189 return (BAM_SUCCESS
);
9192 if (optnum
== ARGS_CMD
) {
9193 if (old_args
[0] != '\0') {
9194 (void) strlcpy(buf
, old_args
, bufsize
);
9195 BAM_DPRINTF((D_GET_SET_KERNEL_ARGS
, fcn
, buf
));
9199 * We need to print the kernel, so we just turn the
9200 * first space into a '\0' and print the beginning.
9201 * We don't print anything if it's the default kernel.
9205 if (strcmp(kernelp
->arg
, DIRECT_BOOT_KERNEL
) != 0) {
9206 (void) strlcpy(buf
, kernelp
->arg
, bufsize
);
9207 BAM_DPRINTF((D_GET_SET_KERNEL_KERN
, fcn
, buf
));
9211 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
9212 return (BAM_SUCCESS
);
9216 * First, check if we're resetting an entry to the default.
9218 if ((path
[0] == '\0') ||
9219 ((optnum
== KERNEL_CMD
) &&
9220 (strcmp(path
, DIRECT_BOOT_KERNEL
) == 0))) {
9221 if ((entryp
== NULL
) || (kernelp
== NULL
)) {
9222 /* No previous entry, it's already the default */
9223 BAM_DPRINTF((D_GET_SET_KERNEL_ALREADY
, fcn
));
9224 return (BAM_SUCCESS
);
9228 * Check if we can delete the entry. If we're resetting the
9229 * kernel command, and the args is already empty, or if we're
9230 * resetting the args command, and the kernel is already the
9231 * default, we can restore the old default and delete the entry.
9233 if (((optnum
== KERNEL_CMD
) &&
9234 ((old_args
== NULL
) || (old_args
[0] == '\0'))) ||
9235 ((optnum
== ARGS_CMD
) &&
9236 (strncmp(kernelp
->arg
, DIRECT_BOOT_KERNEL
,
9237 sizeof (DIRECT_BOOT_KERNEL
) - 1) == 0))) {
9239 (void) delete_boot_entry(mp
, entryNum
, DBE_PRINTERR
);
9240 restore_default_entry(mp
, BAM_OLD_RC_DEF
,
9241 mp
->old_rc_default
);
9242 mp
->old_rc_default
= NULL
;
9244 BAM_DPRINTF((D_GET_SET_KERNEL_RESTORE_DEFAULT
, fcn
));
9248 if (optnum
== KERNEL_CMD
) {
9250 * At this point, we've already checked that old_args
9251 * and entryp are valid pointers. The "+ 2" is for
9252 * a space a the string termination character.
9254 new_str_len
= (sizeof (DIRECT_BOOT_KERNEL
) - 1) +
9255 strlen(old_args
) + 2;
9256 new_arg
= s_calloc(1, new_str_len
);
9257 (void) snprintf(new_arg
, new_str_len
, "%s %s",
9258 DIRECT_BOOT_KERNEL
, old_args
);
9260 kernelp
->arg
= new_arg
;
9263 * We have changed the kernel line, so we may need
9264 * to update the archive line as well.
9266 set_archive_line(entryp
, kernelp
);
9267 BAM_DPRINTF((D_GET_SET_KERNEL_RESET_KERNEL_SET_ARG
,
9268 fcn
, kernelp
->arg
));
9271 * We're resetting the boot args to nothing, so
9272 * we only need to copy the kernel. We've already
9273 * checked that the kernel is not the default.
9275 new_arg
= s_calloc(1, old_kernel_len
+ 1);
9276 (void) snprintf(new_arg
, old_kernel_len
+ 1, "%s",
9279 kernelp
->arg
= new_arg
;
9280 BAM_DPRINTF((D_GET_SET_KERNEL_RESET_ARG_SET_KERNEL
,
9281 fcn
, kernelp
->arg
));
9288 * Expand the kernel file to a full path, if necessary
9290 if ((optnum
== KERNEL_CMD
) && (path
[0] != '/')) {
9291 new_path
= expand_path(path
);
9292 if (new_path
== NULL
) {
9293 bam_error(UNKNOWN_KERNEL
, path
);
9294 BAM_DPRINTF((D_RETURN_FAILURE
, fcn
));
9304 * At this point, we know we're setting a new value. First, take care
9305 * of the case where there was no previous entry.
9307 if (entryp
== NULL
) {
9309 /* Similar to code in update_temp */
9310 fstype
= get_fstype("/");
9311 INJECT_ERROR1("GET_SET_KERNEL_FSTYPE", fstype
= NULL
);
9312 if (fstype
== NULL
) {
9313 bam_error(BOOTENV_FSTYPE_FAILED
);
9318 osdev
= get_special("/");
9319 INJECT_ERROR1("GET_SET_KERNEL_SPECIAL", osdev
= NULL
);
9320 if (osdev
== NULL
) {
9322 bam_error(BOOTENV_SPECIAL_FAILED
);
9327 sign
= find_existing_sign("/", osdev
, fstype
);
9328 INJECT_ERROR1("GET_SET_KERNEL_SIGN", sign
= NULL
);
9332 bam_error(BOOTENV_SIGN_FAILED
);
9338 (void) strlcpy(signbuf
, sign
, sizeof (signbuf
));
9340 assert(strchr(signbuf
, '(') == NULL
&&
9341 strchr(signbuf
, ',') == NULL
&&
9342 strchr(signbuf
, ')') == NULL
);
9344 if (optnum
== KERNEL_CMD
) {
9345 if (strcmp(fstype
, "zfs") == 0) {
9346 new_str_len
= strlen(new_path
) +
9347 strlen(ZFS_BOOT
) + 8;
9348 new_arg
= s_calloc(1, new_str_len
);
9349 (void) snprintf(new_arg
, new_str_len
, "%s %s",
9350 new_path
, ZFS_BOOT
);
9351 BAM_DPRINTF((D_GET_SET_KERNEL_NEW_KERN
, fcn
,
9353 entryNum
= add_boot_entry(mp
, BOOTENV_RC_TITLE
,
9354 signbuf
, new_arg
, NULL
, NULL
, NULL
);
9357 BAM_DPRINTF((D_GET_SET_KERNEL_NEW_KERN
, fcn
,
9359 entryNum
= add_boot_entry(mp
, BOOTENV_RC_TITLE
,
9360 signbuf
, new_path
, NULL
, NULL
, NULL
);
9363 new_str_len
= strlen(path
) + 8;
9364 if (strcmp(fstype
, "zfs") == 0) {
9365 new_str_len
+= strlen(DIRECT_BOOT_KERNEL_ZFS
);
9366 new_arg
= s_calloc(1, new_str_len
);
9367 (void) snprintf(new_arg
, new_str_len
, "%s %s",
9368 DIRECT_BOOT_KERNEL_ZFS
, path
);
9370 new_str_len
+= strlen(DIRECT_BOOT_KERNEL
);
9371 new_arg
= s_calloc(1, new_str_len
);
9372 (void) snprintf(new_arg
, new_str_len
, "%s %s",
9373 DIRECT_BOOT_KERNEL
, path
);
9376 BAM_DPRINTF((D_GET_SET_KERNEL_NEW_ARG
, fcn
, new_arg
));
9377 entryNum
= add_boot_entry(mp
, BOOTENV_RC_TITLE
,
9378 signbuf
, new_arg
, NULL
, DIRECT_BOOT_ARCHIVE
, NULL
);
9382 INJECT_ERROR1("GET_SET_KERNEL_ADD_BOOT_ENTRY",
9383 entryNum
= BAM_ERROR
);
9384 if (entryNum
== BAM_ERROR
) {
9385 bam_error(GET_SET_KERNEL_ADD_BOOT_ENTRY
,
9390 save_default_entry(mp
, BAM_OLD_RC_DEF
);
9391 ret
= set_global(mp
, menu_cmds
[DEFAULT_CMD
], entryNum
);
9392 INJECT_ERROR1("GET_SET_KERNEL_SET_GLOBAL", ret
= BAM_ERROR
);
9393 if (ret
== BAM_ERROR
) {
9394 bam_error(GET_SET_KERNEL_SET_GLOBAL
, entryNum
);
9401 * There was already an bootenv entry which we need to edit.
9403 if (optnum
== KERNEL_CMD
) {
9404 new_str_len
= strlen(new_path
) + strlen(old_args
) + 2;
9405 new_arg
= s_calloc(1, new_str_len
);
9406 (void) snprintf(new_arg
, new_str_len
, "%s %s", new_path
,
9409 kernelp
->arg
= new_arg
;
9412 * If we have changed the kernel line, we may need to update
9413 * the archive line as well.
9415 set_archive_line(entryp
, kernelp
);
9416 BAM_DPRINTF((D_GET_SET_KERNEL_REPLACED_KERNEL_SAME_ARG
, fcn
,
9419 new_str_len
= old_kernel_len
+ strlen(path
) + 8;
9420 new_arg
= s_calloc(1, new_str_len
);
9421 (void) strncpy(new_arg
, kernelp
->arg
, old_kernel_len
);
9422 (void) strlcat(new_arg
, " ", new_str_len
);
9423 (void) strlcat(new_arg
, path
, new_str_len
);
9425 kernelp
->arg
= new_arg
;
9426 BAM_DPRINTF((D_GET_SET_KERNEL_SAME_KERNEL_REPLACED_ARG
, fcn
,
9432 if ((rv
== BAM_WRITE
) && kernelp
)
9433 update_line(kernelp
);
9436 if (rv
== BAM_WRITE
) {
9437 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
9439 BAM_DPRINTF((D_RETURN_FAILURE
, fcn
));
9445 get_kernel(menu_t
*mp
, menu_cmd_t optnum
, char *buf
, size_t bufsize
)
9447 const char *fcn
= "get_kernel()";
9448 BAM_DPRINTF((D_FUNC_ENTRY1
, fcn
, menu_cmds
[optnum
]));
9449 return (get_set_kernel(mp
, optnum
, NULL
, buf
, bufsize
));
9453 set_kernel(menu_t
*mp
, menu_cmd_t optnum
, char *path
, char *buf
, size_t bufsize
)
9455 const char *fcn
= "set_kernel()";
9456 assert(path
!= NULL
);
9457 BAM_DPRINTF((D_FUNC_ENTRY2
, fcn
, menu_cmds
[optnum
], path
));
9458 return (get_set_kernel(mp
, optnum
, path
, buf
, bufsize
));
9463 set_option(menu_t
*mp
, char *dummy
, char *opt
)
9468 char buf
[BUFSIZ
] = "";
9470 const char *fcn
= "set_option()";
9474 assert(dummy
== NULL
);
9476 /* opt is set from bam_argv[0] and is always non-NULL */
9477 BAM_DPRINTF((D_FUNC_ENTRY1
, fcn
, opt
));
9479 val
= strchr(opt
, '=');
9484 if (strcmp(opt
, "default") == 0) {
9485 optnum
= DEFAULT_CMD
;
9486 } else if (strcmp(opt
, "timeout") == 0) {
9487 optnum
= TIMEOUT_CMD
;
9488 } else if (strcmp(opt
, menu_cmds
[KERNEL_CMD
]) == 0) {
9489 optnum
= KERNEL_CMD
;
9490 } else if (strcmp(opt
, menu_cmds
[ARGS_CMD
]) == 0) {
9493 bam_error(INVALID_OPTION
, opt
);
9498 * kernel and args are allowed without "=new_value" strings. All
9499 * others cause errors
9501 if ((val
== NULL
) && (optnum
!= KERNEL_CMD
) && (optnum
!= ARGS_CMD
)) {
9502 bam_error(NO_OPTION_ARG
, opt
);
9504 } else if (val
!= NULL
) {
9508 if ((optnum
== KERNEL_CMD
) || (optnum
== ARGS_CMD
)) {
9509 BAM_DPRINTF((D_SET_OPTION
, fcn
, menu_cmds
[optnum
],
9510 val
? val
+ 1 : "NULL"));
9513 rv
= set_kernel(mp
, optnum
, val
+ 1, buf
, sizeof (buf
));
9515 rv
= get_kernel(mp
, optnum
, buf
, sizeof (buf
));
9516 if ((rv
== BAM_SUCCESS
) && (buf
[0] != '\0'))
9517 (void) printf("%s\n", buf
);
9519 optval
= s_strtol(val
+ 1);
9520 BAM_DPRINTF((D_SET_OPTION
, fcn
, menu_cmds
[optnum
], val
+ 1));
9521 rv
= set_global(mp
, menu_cmds
[optnum
], optval
);
9524 if (rv
== BAM_WRITE
|| rv
== BAM_SUCCESS
) {
9525 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
9527 BAM_DPRINTF((D_RETURN_FAILURE
, fcn
));
9534 * The quiet argument suppresses messages. This is used
9535 * when invoked in the context of other commands (e.g. list_entry)
9538 read_globals(menu_t
*mp
, char *menu_path
, char *globalcmd
, int quiet
)
9542 int done
, ret
= BAM_SUCCESS
;
9548 if (mp
->start
== NULL
) {
9550 bam_error(NO_MENU
, menu_path
);
9555 for (lp
= mp
->start
; lp
; lp
= lp
->next
) {
9556 if (lp
->flags
!= BAM_GLOBAL
)
9559 if (lp
->cmd
== NULL
) {
9561 bam_error(NO_CMD
, lp
->lineNum
);
9565 if (strcmp(globalcmd
, lp
->cmd
) != 0)
9568 /* Found global. Check for duplicates */
9569 if (done
&& !quiet
) {
9570 bam_error(DUP_CMD
, globalcmd
, lp
->lineNum
, bam_root
);
9574 arg
= lp
->arg
? lp
->arg
: "";
9575 bam_print(GLOBAL_CMD
, globalcmd
, arg
);
9579 if (!done
&& bam_verbose
)
9580 bam_print(NO_ENTRY
, globalcmd
);
9586 menu_write(char *root
, menu_t
*mp
)
9588 const char *fcn
= "menu_write()";
9590 BAM_DPRINTF((D_MENU_WRITE_ENTER
, fcn
, root
));
9591 return (list2file(root
, MENU_TMP
, GRUB_MENU
, mp
->start
));
9595 line_free(line_t
*lp
)
9600 if (lp
->cmd
!= NULL
)
9612 linelist_free(line_t
*start
)
9618 start
= start
->next
;
9624 filelist_free(filelist_t
*flistp
)
9626 linelist_free(flistp
->head
);
9627 flistp
->head
= NULL
;
9628 flistp
->tail
= NULL
;
9632 menu_free(menu_t
*mp
)
9638 linelist_free(mp
->start
);
9655 * Returns 0 on success
9656 * Any other value indicates an error
9659 exec_cmd(char *cmdline
, filelist_t
*flistp
)
9669 * - only absolute paths are allowed
9670 * - set IFS to space and tab
9672 if (*cmdline
!= '/') {
9673 bam_error(ABS_PATH_REQ
, cmdline
);
9676 (void) putenv("IFS= \t");
9679 * We may have been exec'ed with SIGCHLD blocked
9682 (void) sigemptyset(&set
);
9683 (void) sigaddset(&set
, SIGCHLD
);
9684 if (sigprocmask(SIG_UNBLOCK
, &set
, NULL
) != 0) {
9685 bam_error(CANT_UNBLOCK_SIGCHLD
, strerror(errno
));
9690 * Set SIGCHLD disposition to SIG_DFL for popen/pclose
9692 disp
= sigset(SIGCHLD
, SIG_DFL
);
9693 if (disp
== SIG_ERR
) {
9694 bam_error(FAILED_SIG
, strerror(errno
));
9697 if (disp
== SIG_HOLD
) {
9698 bam_error(BLOCKED_SIG
, cmdline
);
9702 ptr
= popen(cmdline
, "r");
9704 bam_error(POPEN_FAIL
, cmdline
, strerror(errno
));
9709 * If we simply do a pclose() following a popen(), pclose()
9710 * will close the reader end of the pipe immediately even
9711 * if the child process has not started/exited. pclose()
9712 * does wait for cmd to terminate before returning though.
9713 * When the executed command writes its output to the pipe
9714 * there is no reader process and the command dies with
9715 * SIGPIPE. To avoid this we read repeatedly until read
9716 * terminates with EOF. This indicates that the command
9717 * (writer) has closed the pipe and we can safely do a
9720 * Since pclose() does wait for the command to exit,
9721 * we can safely reap the exit status of the command
9722 * from the value returned by pclose()
9724 while (s_fgets(buf
, sizeof (buf
), ptr
) != NULL
) {
9725 if (flistp
== NULL
) {
9726 /* s_fgets strips newlines, so insert them at the end */
9727 bam_print(PRINT
, buf
);
9729 append_to_flist(flistp
, buf
);
9735 bam_error(PCLOSE_FAIL
, cmdline
, strerror(errno
));
9739 if (WIFEXITED(ret
)) {
9740 return (WEXITSTATUS(ret
));
9742 bam_error(EXEC_FAIL
, cmdline
, ret
);
9748 * Since this function returns -1 on error
9749 * it cannot be used to convert -1. However,
9750 * that is sufficient for what we need.
9763 l
= strtol(str
, &res
, 10);
9764 if (errno
|| *res
!= '\0') {
9772 * Wrapper around fputs, that adds a newline (since fputs doesn't)
9775 s_fputs(char *str
, FILE *fp
)
9777 char linebuf
[BAM_MAXLINE
];
9779 (void) snprintf(linebuf
, sizeof (linebuf
), "%s\n", str
);
9780 return (fputs(linebuf
, fp
));
9784 * Wrapper around fgets, that strips newlines returned by fgets
9787 s_fgets(char *buf
, int buflen
, FILE *fp
)
9791 buf
= fgets(buf
, buflen
, fp
);
9794 if (n
== buflen
- 1 && buf
[n
-1] != '\n')
9795 bam_error(TOO_LONG
, buflen
- 1, buf
);
9796 buf
[n
-1] = (buf
[n
-1] == '\n') ? '\0' : buf
[n
-1];
9803 s_calloc(size_t nelem
, size_t sz
)
9807 ptr
= calloc(nelem
, sz
);
9809 bam_error(NO_MEM
, nelem
*sz
);
9816 s_realloc(void *ptr
, size_t sz
)
9818 ptr
= realloc(ptr
, sz
);
9820 bam_error(NO_MEM
, sz
);
9836 bam_error(NO_MEM
, strlen(str
) + 1);
9843 * Returns 1 if amd64 (or sparc, for syncing x86 diskless clients)
9844 * Returns 0 otherwise
9849 static int amd64
= -1;
9850 char isabuf
[257]; /* from sysinfo(2) manpage */
9855 if (bam_alt_platform
) {
9856 if (strcmp(bam_platform
, "i86pc") == 0) {
9857 amd64
= 1; /* diskless server */
9860 if (sysinfo(SI_ISALIST
, isabuf
, sizeof (isabuf
)) > 0 &&
9861 strncmp(isabuf
, "amd64 ", strlen("amd64 ")) == 0) {
9863 } else if (strstr(isabuf
, "i386") == NULL
) {
9864 amd64
= 1; /* diskless server */
9876 static int cached
= -1;
9877 static char mbuf
[257]; /* from sysinfo(2) manpage */
9882 if (bam_alt_platform
) {
9883 return (bam_platform
);
9885 if (sysinfo(SI_MACHINE
, mbuf
, sizeof (mbuf
)) > 0) {
9900 static int issparc
= -1;
9901 char mbuf
[257]; /* from sysinfo(2) manpage */
9906 if (bam_alt_platform
) {
9907 if (strncmp(bam_platform
, "sun4", 4) == 0) {
9911 if (sysinfo(SI_ARCHITECTURE
, mbuf
, sizeof (mbuf
)) > 0 &&
9912 strcmp(mbuf
, "sparc") == 0) {
9923 append_to_flist(filelist_t
*flistp
, char *s
)
9927 lp
= s_calloc(1, sizeof (line_t
));
9928 lp
->line
= s_strdup(s
);
9929 if (flistp
->head
== NULL
)
9932 flistp
->tail
->next
= lp
;
9942 ucode_install(char *root
)
9946 for (i
= 0; ucode_vendors
[i
].filestr
!= NULL
; i
++) {
9947 int cmd_len
= PATH_MAX
+ 256;
9948 char cmd
[PATH_MAX
+ 256];
9949 char file
[PATH_MAX
];
9950 char timestamp
[PATH_MAX
];
9951 struct stat fstatus
, tstatus
;
9952 struct utimbuf u_times
;
9954 (void) snprintf(file
, PATH_MAX
, "%s/%s/%s-ucode.%s",
9955 bam_root
, UCODE_INSTALL_PATH
, ucode_vendors
[i
].filestr
,
9956 ucode_vendors
[i
].extstr
);
9958 if (stat(file
, &fstatus
) != 0 || !(S_ISREG(fstatus
.st_mode
)))
9961 (void) snprintf(timestamp
, PATH_MAX
, "%s.ts", file
);
9963 if (stat(timestamp
, &tstatus
) == 0 &&
9964 fstatus
.st_mtime
<= tstatus
.st_mtime
)
9967 (void) snprintf(cmd
, cmd_len
, "/usr/sbin/ucodeadm -i -R "
9968 "%s/%s/%s %s > /dev/null 2>&1", bam_root
,
9969 UCODE_INSTALL_PATH
, ucode_vendors
[i
].vendorstr
, file
);
9970 if (system(cmd
) != 0)
9973 if (creat(timestamp
, S_IRUSR
| S_IWUSR
) == -1)
9976 u_times
.actime
= fstatus
.st_atime
;
9977 u_times
.modtime
= fstatus
.st_mtime
;
9978 (void) utime(timestamp
, &u_times
);