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.
29 * Copyright 2016 Toomas Soome <tsoome@me.com>
33 * bootadm(1M) is a new utility for managing bootability of
34 * Solaris *Newboot* environments. It has two primary tasks:
35 * - Allow end users to manage bootability of Newboot Solaris instances
36 * - Provide services to other subsystems in Solaris (primarily Install)
45 #include <sys/types.h>
52 #include <sys/mnttab.h>
53 #include <sys/mntent.h>
54 #include <sys/statvfs.h>
55 #include <libnvpair.h>
60 #include <sys/systeminfo.h>
61 #include <sys/dktp/fdisk.h>
62 #include <sys/param.h>
66 #include <sys/sysmacros.h>
70 #include <sys/lockfs.h>
71 #include <sys/filio.h>
78 #include <sys/ucode.h>
83 #include <device_info.h>
85 #include <sys/efi_partition.h>
88 #include <sys/mkdev.h>
94 #define TEXT_DOMAIN "SUNW_OST_OSCMD"
95 #endif /* TEXT_DOMAIN */
97 /* Type definitions */
107 OPT_ABSENT
= 0, /* No option */
108 OPT_REQ
, /* option required */
109 OPT_OPTIONAL
/* option may or may not be present */
115 error_t (*handler
)();
116 int unpriv
; /* is this an unprivileged command */
119 #define LINE_INIT 0 /* lineNum initial value */
120 #define ENTRY_INIT -1 /* entryNum initial value */
121 #define ALL_ENTRIES -2 /* selects all boot entries */
123 #define PARTNO_NOTFOUND -1 /* Solaris partition not found */
124 #define PARTNO_EFI -2 /* EFI partition table found */
126 #define GRUB_DIR "/boot/grub"
127 #define GRUB_STAGE2 GRUB_DIR "/stage2"
128 #define GRUB_MENU "/boot/grub/menu.lst"
129 #define MENU_TMP "/boot/grub/menu.lst.tmp"
130 #define GRUB_BACKUP_MENU "/etc/lu/GRUB_backup_menu"
131 #define RAMDISK_SPECIAL "/dev/ramdisk/"
132 #define STUBBOOT "/stubboot"
133 #define MULTIBOOT "/platform/i86pc/multiboot"
134 #define GRUBSIGN_DIR "/boot/grub/bootsign"
135 #define GRUBSIGN_BACKUP "/etc/bootsign"
136 #define GRUBSIGN_UFS_PREFIX "rootfs"
137 #define GRUBSIGN_ZFS_PREFIX "pool_"
138 #define GRUBSIGN_LU_PREFIX "BE_"
139 #define UFS_SIGNATURE_LIST "/var/run/grub_ufs_signatures"
140 #define ZFS_LEGACY_MNTPT "/tmp/bootadm_mnt_zfs_legacy"
142 #define BOOTADM_RDONLY_TEST "BOOTADM_RDONLY_TEST"
145 #define BAM_LOCK_FILE "/var/run/bootadm.lock"
146 #define LOCK_FILE_PERMS (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
148 #define CREATE_RAMDISK "boot/solaris/bin/create_ramdisk"
149 #define CREATE_DISKMAP "boot/solaris/bin/create_diskmap"
150 #define EXTRACT_BOOT_FILELIST "boot/solaris/bin/extract_boot_filelist"
151 #define GRUBDISK_MAP "/var/run/solaris_grubdisk.map"
153 #define GRUB_slice "/etc/lu/GRUB_slice"
154 #define GRUB_root "/etc/lu/GRUB_root"
155 #define GRUB_fdisk "/etc/lu/GRUB_fdisk"
156 #define GRUB_fdisk_target "/etc/lu/GRUB_fdisk_target"
157 #define FINDROOT_INSTALLGRUB "/etc/lu/installgrub.findroot"
158 #define LULIB "/usr/lib/lu/lulib"
159 #define LULIB_PROPAGATE_FILE "lulib_propagate_file"
160 #define CKSUM "/usr/bin/cksum"
161 #define LU_MENU_CKSUM "/etc/lu/menu.cksum"
162 #define BOOTADM "/sbin/bootadm"
164 #define INSTALLGRUB "/sbin/installgrub"
165 #define STAGE1 "/boot/grub/stage1"
166 #define STAGE2 "/boot/grub/stage2"
168 typedef enum zfs_mnted
{
177 * Default file attributes
179 #define DEFAULT_DEV_MODE 0644 /* default permissions */
180 #define DEFAULT_DEV_UID 0 /* user root */
181 #define DEFAULT_DEV_GID 3 /* group sys */
185 * menu_cmd_t and menu_cmds must be kept in sync
187 char *menu_cmds
[] = {
188 "default", /* DEFAULT_CMD */
189 "timeout", /* TIMEOUT_CMD */
190 "title", /* TITLE_CMD */
191 "root", /* ROOT_CMD */
192 "kernel", /* KERNEL_CMD */
193 "kernel$", /* KERNEL_DOLLAR_CMD */
194 "module", /* MODULE_CMD */
195 "module$", /* MODULE_DOLLAR_CMD */
197 "#", /* COMMENT_CMD */
198 "chainloader", /* CHAINLOADER_CMD */
199 "args", /* ARGS_CMD */
200 "findroot", /* FINDROOT_CMD */
201 "bootfs", /* BOOTFS_CMD */
205 #define OPT_ENTRY_NUM "entry"
215 #define BOOT_FILE_LIST "boot/solaris/filelist.ramdisk"
216 #define ETC_FILE_LIST "etc/boot/solaris/filelist.ramdisk"
218 #define FILE_STAT "boot/solaris/filestat.ramdisk"
219 #define FILE_STAT_TMP "boot/solaris/filestat.ramdisk.tmp"
220 #define DIR_PERMS (S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
221 #define FILE_STAT_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
223 #define FILE_STAT_TIMESTAMP "boot/solaris/timestamp.cache"
230 static subcmd_t bam_cmd
;
231 static char *bam_root
;
232 static int bam_rootlen
;
233 static int bam_root_readonly
;
234 static int bam_alt_root
;
235 static int bam_extend
= 0;
236 static int bam_purge
= 0;
237 static char *bam_subcmd
;
238 static char *bam_opt
;
239 static char **bam_argv
;
240 static char *bam_pool
;
242 static int bam_check
;
243 static int bam_saved_check
;
244 static int bam_smf_check
;
245 static int bam_lock_fd
= -1;
248 static char rootbuf
[PATH_MAX
] = "/";
249 static int bam_update_all
;
250 static int bam_alt_platform
;
251 static char *bam_platform
;
252 static char *bam_home_env
= NULL
;
254 /* function prototypes */
255 static void parse_args_internal(int, char *[]);
256 static void parse_args(int, char *argv
[]);
257 static error_t
bam_menu(char *, char *, int, char *[]);
258 static error_t
bam_install(char *, char *);
259 static error_t
bam_archive(char *, char *);
261 static void bam_lock(void);
262 static void bam_unlock(void);
264 static int exec_cmd(char *, filelist_t
*);
265 static error_t
read_globals(menu_t
*, char *, char *, int);
266 static int menu_on_bootdisk(char *os_root
, char *menu_root
);
267 static menu_t
*menu_read(char *);
268 static error_t
menu_write(char *, menu_t
*);
269 static void linelist_free(line_t
*);
270 static void menu_free(menu_t
*);
271 static void filelist_free(filelist_t
*);
272 static error_t
list2file(char *, char *, char *, line_t
*);
273 static error_t
list_entry(menu_t
*, char *, char *);
274 static error_t
list_setting(menu_t
*, char *, char *);
275 static error_t
delete_all_entries(menu_t
*, char *, char *);
276 static error_t
update_entry(menu_t
*mp
, char *menu_root
, char *opt
);
277 static error_t
update_temp(menu_t
*mp
, char *dummy
, char *opt
);
279 static error_t
install_bootloader(void);
280 static error_t
update_archive(char *, char *);
281 static error_t
list_archive(char *, char *);
282 static error_t
update_all(char *, char *);
283 static error_t
read_list(char *, filelist_t
*);
284 static error_t
set_option(menu_t
*, char *, char *);
285 static error_t
set_kernel(menu_t
*, menu_cmd_t
, char *, char *, size_t);
286 static error_t
get_kernel(menu_t
*, menu_cmd_t
, char *, size_t);
287 static char *expand_path(const char *);
289 static long s_strtol(char *);
290 static int s_fputs(char *, FILE *);
292 static int is_zfs(char *root
);
293 static int is_ufs(char *root
);
294 static int is_pcfs(char *root
);
295 static int is_amd64(void);
296 static char *get_machine(void);
297 static void append_to_flist(filelist_t
*, char *);
298 static char *mount_top_dataset(char *pool
, zfs_mnted_t
*mnted
);
299 static int umount_top_dataset(char *pool
, zfs_mnted_t mnted
, char *mntpt
);
300 static int ufs_add_to_sign_list(char *sign
);
301 static error_t
synchronize_BE_menu(void);
304 static void ucode_install();
307 /* Menu related sub commands */
308 static subcmd_defn_t menu_subcmds
[] = {
309 "set_option", OPT_ABSENT
, set_option
, 0, /* PUB */
310 "list_entry", OPT_OPTIONAL
, list_entry
, 1, /* PUB */
311 "delete_all_entries", OPT_ABSENT
, delete_all_entries
, 0, /* PVT */
312 "update_entry", OPT_REQ
, update_entry
, 0, /* menu */
313 "update_temp", OPT_OPTIONAL
, update_temp
, 0, /* reboot */
314 "upgrade", OPT_ABSENT
, upgrade_menu
, 0, /* menu */
315 "list_setting", OPT_OPTIONAL
, list_setting
, 1, /* menu */
316 "disable_hypervisor", OPT_ABSENT
, cvt_to_metal
, 0, /* menu */
317 "enable_hypervisor", OPT_ABSENT
, cvt_to_hyper
, 0, /* menu */
318 NULL
, 0, NULL
, 0 /* must be last */
321 /* Archive related sub commands */
322 static subcmd_defn_t arch_subcmds
[] = {
323 "update", OPT_ABSENT
, update_archive
, 0, /* PUB */
324 "update_all", OPT_ABSENT
, update_all
, 0, /* PVT */
325 "list", OPT_OPTIONAL
, list_archive
, 1, /* PUB */
326 NULL
, 0, NULL
, 0 /* must be last */
329 /* Install related sub commands */
330 static subcmd_defn_t inst_subcmds
[] = {
331 "install_bootloader", OPT_ABSENT
, install_bootloader
, 0, /* PUB */
332 NULL
, 0, NULL
, 0 /* must be last */
335 enum dircache_copy_opt
{
342 * Directory specific flags:
343 * NEED_UPDATE : the specified archive needs to be updated
344 * NO_MULTI : don't extend the specified archive, but recreate it
346 #define NEED_UPDATE 0x00000001
347 #define NO_MULTI 0x00000002
349 #define set_dir_flag(id, f) (walk_arg.dirinfo[id].flags |= f)
350 #define unset_dir_flag(id, f) (walk_arg.dirinfo[id].flags &= ~f)
351 #define is_dir_flag_on(id, f) (walk_arg.dirinfo[id].flags & f ? 1 : 0)
353 #define get_cachedir(id) (walk_arg.dirinfo[id].cdir_path)
354 #define get_updatedir(id) (walk_arg.dirinfo[id].update_path)
355 #define get_count(id) (walk_arg.dirinfo[id].count)
356 #define has_cachedir(id) (walk_arg.dirinfo[id].has_dir)
357 #define set_dir_present(id) (walk_arg.dirinfo[id].has_dir = 1)
360 * dirinfo_t (specific cache directory information):
361 * cdir_path: path to the archive cache directory
362 * update_path: path to the update directory (contains the files that will be
363 * used to extend the archive)
364 * has_dir: the specified cache directory is active
365 * count: the number of files to update
366 * flags: directory specific flags
368 typedef struct _dirinfo
{
369 char cdir_path
[PATH_MAX
];
370 char update_path
[PATH_MAX
];
378 * NEED_CACHE_DIR : cache directory is missing and needs to be created
379 * IS_SPARC_TARGET : the target mountpoint is a SPARC environment
380 * UPDATE_ERROR : an error occourred while traversing the list of files
381 * RDONLY_FSCHK : the target filesystem is read-only
382 * RAMDSK_FSCHK : the target filesystem is on a ramdisk
384 #define NEED_CACHE_DIR 0x00000001
385 #define IS_SPARC_TARGET 0x00000002
386 #define UPDATE_ERROR 0x00000004
387 #define RDONLY_FSCHK 0x00000008
388 #define INVALIDATE_CACHE 0x00000010
390 #define is_flag_on(flag) (walk_arg.update_flags & flag ? 1 : 0)
391 #define set_flag(flag) (walk_arg.update_flags |= flag)
392 #define unset_flag(flag) (walk_arg.update_flags &= ~flag)
396 * update_flags: flags related to the current updating process
397 * new_nvlp/old_nvlp: new and old list of archive-files / attributes pairs
398 * sparcfile: list of file paths for mkisofs -path-list (SPARC only)
405 dirinfo_t dirinfo
[CACHEDIR_NUM
];
410 struct safefile
*next
;
413 static struct safefile
*safefiles
= NULL
;
416 * svc:/system/filesystem/usr:default service checks for this file and
417 * does a boot archive update and then reboot the system.
419 #define NEED_UPDATE_FILE "/etc/svc/volatile/boot_archive_needs_update"
422 * svc:/system/boot-archive-update:default checks for this file and
423 * updates the boot archive.
425 #define NEED_UPDATE_SAFE_FILE "/etc/svc/volatile/boot_archive_safefile_update"
427 /* Thanks growisofs */
428 #define CD_BLOCK ((off64_t)2048)
429 #define VOLDESC_OFF 16
430 #define DVD_BLOCK (32*1024)
434 unsigned char type
[1];
435 unsigned char id
[5];
436 unsigned char void1
[80-5-1];
437 unsigned char volume_space_size
[8];
438 unsigned char void2
[2048-80-8];
442 * COUNT_MAX: maximum number of changed files to justify a multisession update
443 * BA_SIZE_MAX: maximum size of the boot_archive to justify a multisession
447 #define BA_SIZE_MAX (50 * 1024 * 1024)
449 #define bam_nowrite() (bam_check || bam_smf_check)
451 static int sync_menu
= 1; /* whether we need to sync the BE menus */
456 (void) fprintf(stderr
, "USAGE:\n");
459 (void) fprintf(stderr
,
460 "\t%s update-archive [-vn] [-R altroot [-p platform]]\n", prog
);
461 (void) fprintf(stderr
,
462 "\t%s list-archive [-R altroot [-p platform]]\n", prog
);
464 (void) fprintf(stderr
,
465 "\t%s install-bootloader [-fv] [-R altroot] [-P pool]\n", prog
);
467 (void) fprintf(stderr
,
468 "\t%s install-bootloader [-Mfv] [-R altroot] [-P pool]\n", prog
);
472 (void) fprintf(stderr
, "\t%s set-menu [-R altroot] key=value\n", prog
);
473 (void) fprintf(stderr
, "\t%s list-menu [-R altroot]\n", prog
);
478 * Best effort attempt to restore the $HOME value.
483 char home_env
[PATH_MAX
];
486 (void) snprintf(home_env
, sizeof (home_env
), "HOME=%s",
488 (void) putenv(home_env
);
497 * Sanitize the environment in which bootadm will execute its sub-processes
498 * (ex. mkisofs). This is done to prevent those processes from attempting
499 * to access files (ex. .mkisofsrc) or stat paths that might be on NFS
500 * or, potentially, insecure.
507 /* don't depend on caller umask */
510 /* move away from a potential unsafe current working directory */
511 while (chdir("/") == -1) {
512 if (errno
!= EINTR
) {
513 bam_print("WARNING: unable to chdir to /");
518 bam_home_env
= getenv("HOME");
519 while (bam_home_env
!= NULL
&& putenv("HOME=/") == -1) {
520 if (errno
== ENOMEM
) {
521 /* retry no more than MAX_TRIES times */
522 if (++stry
> MAX_TRIES
) {
523 bam_print("WARNING: unable to recover from "
524 "system memory pressure... aborting \n");
525 bam_exit(EXIT_FAILURE
);
527 /* memory is tight, try to sleep */
528 bam_print("Attempting to recover from memory pressure: "
529 "sleeping for %d seconds\n", SLEEP_TIME
* stry
);
530 (void) sleep(SLEEP_TIME
* stry
);
532 bam_print("WARNING: unable to sanitize HOME\n");
538 main(int argc
, char *argv
[])
542 (void) setlocale(LC_ALL
, "");
543 (void) textdomain(TEXT_DOMAIN
);
545 if ((prog
= strrchr(argv
[0], '/')) == NULL
) {
551 INJECT_ERROR1("ASSERT_ON", assert(0))
555 parse_args(argc
, argv
);
559 ret
= bam_menu(bam_subcmd
, bam_opt
, bam_argc
, bam_argv
);
562 ret
= bam_archive(bam_subcmd
, bam_opt
);
565 ret
= bam_install(bam_subcmd
, bam_opt
);
572 if (ret
!= BAM_SUCCESS
)
573 bam_exit((ret
== BAM_NOCHANGE
) ? 2 : 1);
580 * Equivalence of public and internal commands:
581 * update-archive -- -a update
582 * list-archive -- -a list
583 * set-menu -- -m set_option
584 * list-menu -- -m list_entry
585 * update-menu -- -m update_entry
586 * install-bootloader -- -i install_bootloader
588 static struct cmd_map
{
593 { "update-archive", BAM_ARCHIVE
, "update"},
594 { "list-archive", BAM_ARCHIVE
, "list"},
595 { "set-menu", BAM_MENU
, "set_option"},
596 { "list-menu", BAM_MENU
, "list_entry"},
597 { "update-menu", BAM_MENU
, "update_entry"},
598 { "install-bootloader", BAM_INSTALL
, "install_bootloader"},
603 * Commands syntax published in bootadm(1M) are parsed here
606 parse_args(int argc
, char *argv
[])
608 struct cmd_map
*cmp
= cmd_map
;
610 /* command conforming to the final spec */
611 if (argc
> 1 && argv
[1][0] != '-') {
613 * Map commands to internal table.
615 while (cmp
->bam_cmdname
) {
616 if (strcmp(argv
[1], cmp
->bam_cmdname
) == 0) {
617 bam_cmd
= cmp
->bam_cmd
;
618 bam_subcmd
= cmp
->bam_subcmd
;
623 if (cmp
->bam_cmdname
== NULL
) {
631 parse_args_internal(argc
, argv
);
635 * A combination of public and private commands are parsed here.
636 * The internal syntax and the corresponding functionality are:
637 * -a update -- update-archive
638 * -a list -- list-archive
639 * -a update-all -- (reboot to sync all mnted OS archive)
640 * -i install_bootloader -- install-bootloader
641 * -m update_entry -- update-menu
642 * -m list_entry -- list-menu
643 * -m update_temp -- (reboot -- [boot-args])
644 * -m delete_all_entries -- (called from install)
645 * -m enable_hypervisor [args] -- cvt_to_hyper
646 * -m disable_hypervisor -- cvt_to_metal
647 * -m list_setting [entry] [value] -- list_setting
649 * A set of private flags is there too:
650 * -F -- purge the cache directories and rebuild them
651 * -e -- use the (faster) archive update approach (used by
655 parse_args_internal(int argc
, char *argv
[])
659 extern int optind
, opterr
;
661 const char *optstring
= "a:d:fi:m:no:veFCR:p:P:XZ";
663 const char *optstring
= "a:d:fi:m:no:veFCMR:p:P:XZ";
666 /* Suppress error message from getopt */
670 while ((c
= getopt(argc
, argv
, optstring
)) != -1) {
675 bam_error(MULT_CMDS
, c
);
677 bam_cmd
= BAM_ARCHIVE
;
683 bam_error(DUP_OPT
, c
);
685 bam_debug
= s_strtol(optarg
);
696 bam_error(MULT_CMDS
, c
);
698 bam_cmd
= BAM_INSTALL
;
704 bam_error(MULT_CMDS
, c
);
717 * We save the original value of bam_check. The new
718 * approach in case of a read-only filesystem is to
719 * behave as a check, so we need a way to restore the
720 * original value after the evaluation of the read-only
721 * filesystem has been done.
722 * Even if we don't allow at the moment a check with
723 * update_all, this approach is more robust than
724 * simply resetting bam_check to zero.
731 bam_error(DUP_OPT
, c
);
742 if (bam_pool
!= NULL
) {
744 bam_error(DUP_OPT
, c
);
751 bam_error(DUP_OPT
, c
);
753 } else if (realpath(optarg
, rootbuf
) == NULL
) {
755 bam_error(CANT_RESOLVE
, optarg
,
761 bam_rootlen
= strlen(rootbuf
);
764 bam_alt_platform
= 1;
765 bam_platform
= optarg
;
766 if ((strcmp(bam_platform
, "i86pc") != 0) &&
767 (strcmp(bam_platform
, "sun4u") != 0) &&
768 (strcmp(bam_platform
, "sun4v") != 0)) {
770 bam_error(INVALID_PLAT
, bam_platform
);
774 bam_is_hv
= BAM_HV_PRESENT
;
784 bam_error(BAD_OPT
, optopt
);
788 bam_error(BAD_OPT
, c
);
794 * An alternate platform requires an alternate root
796 if (bam_alt_platform
&& bam_alt_root
== 0) {
802 * A command option must be specfied
805 if (bam_opt
&& strcmp(bam_opt
, "all") == 0) {
819 bam_error(INT_ERROR
, "parse_args");
821 } else if (optind
< argc
) {
822 bam_argv
= &argv
[optind
];
823 bam_argc
= argc
- optind
;
827 * mbr and pool are options for install_bootloader
829 if (bam_cmd
!= BAM_INSTALL
&& (bam_mbr
|| bam_pool
!= NULL
)) {
835 * -n implies verbose mode
842 check_subcmd_and_options(
845 subcmd_defn_t
*table
,
850 if (subcmd
== NULL
) {
851 bam_error(NEED_SUBCMD
);
855 if (strcmp(subcmd
, "set_option") == 0) {
856 if (bam_argc
== 0 || bam_argv
== NULL
|| bam_argv
[0] == NULL
) {
857 bam_error(MISSING_ARG
);
860 } else if (bam_argc
> 1 || bam_argv
[1] != NULL
) {
861 bam_error(TRAILING_ARGS
);
865 } else if (strcmp(subcmd
, "update_all") == 0) {
867 * The only option we accept for the "update_all"
868 * subcmd is "fastboot".
870 if (bam_argc
> 1 || (bam_argc
== 1 &&
871 strcmp(bam_argv
[0], "fastboot") != 0)) {
872 bam_error(TRAILING_ARGS
);
878 } else if (((strcmp(subcmd
, "enable_hypervisor") != 0) &&
879 (strcmp(subcmd
, "list_setting") != 0)) && (bam_argc
|| bam_argv
)) {
881 * Of the remaining subcommands, only "enable_hypervisor" and
882 * "list_setting" take trailing arguments.
884 bam_error(TRAILING_ARGS
);
889 if (bam_root
== NULL
) {
894 /* verify that subcmd is valid */
895 for (i
= 0; table
[i
].subcmd
!= NULL
; i
++) {
896 if (strcmp(table
[i
].subcmd
, subcmd
) == 0)
900 if (table
[i
].subcmd
== NULL
) {
901 bam_error(INVALID_SUBCMD
, subcmd
);
905 if (table
[i
].unpriv
== 0 && geteuid() != 0) {
906 bam_error(MUST_BE_ROOT
);
911 * Currently only privileged commands need a lock
913 if (table
[i
].unpriv
== 0)
916 /* subcmd verifies that opt is appropriate */
917 if (table
[i
].option
!= OPT_OPTIONAL
) {
918 if ((table
[i
].option
== OPT_REQ
) ^ (opt
!= NULL
)) {
920 bam_error(NO_OPT_REQ
, subcmd
);
922 bam_error(MISS_OPT
, subcmd
);
927 *fp
= table
[i
].handler
;
929 return (BAM_SUCCESS
);
933 * NOTE: A single "/" is also considered a trailing slash and will
937 elide_trailing_slash(const char *src
, char *dst
, size_t dstsize
)
944 (void) strlcpy(dst
, src
, dstsize
);
946 dstlen
= strlen(dst
);
947 if (dst
[dstlen
- 1] == '/') {
948 dst
[dstlen
- 1] = '\0';
953 is_safe_exec(char *path
)
957 if (lstat(path
, &sb
) != 0) {
958 bam_error(STAT_FAIL
, path
, strerror(errno
));
962 if (!S_ISREG(sb
.st_mode
)) {
963 bam_error(PATH_EXEC_LINK
, path
);
967 if (sb
.st_uid
!= getuid()) {
968 bam_error(PATH_EXEC_OWNER
, path
, getuid());
972 if (sb
.st_mode
& S_IWOTH
|| sb
.st_mode
& S_IWGRP
) {
973 bam_error(PATH_EXEC_PERMS
, path
);
977 return (BAM_SUCCESS
);
981 list_setting(menu_t
*mp
, char *which
, char *setting
)
994 if (*which
!= NULL
) {
996 * If "which" is not a number, assume it's a setting we want
997 * to look for and so set up the routine to look for "which"
998 * in the default entry.
1001 if (!(isdigit((int)*p
++))) {
1003 which
= mp
->curdefault
->arg
;
1007 which
= mp
->curdefault
->arg
;
1010 entry
= atoi(which
);
1012 for (ent
= mp
->entries
; ((ent
!= NULL
) && (ent
->entryNum
!= entry
));
1017 bam_error(NO_MATCH_ENTRY
);
1021 found
= (*setting
== NULL
);
1023 for (lp
= ent
->start
; lp
!= NULL
; lp
= lp
->next
) {
1024 if ((*setting
== NULL
) && (lp
->flags
!= BAM_COMMENT
))
1025 bam_print(PRINT
, lp
->line
);
1026 else if (lp
->cmd
!= NULL
&& strcmp(setting
, lp
->cmd
) == 0) {
1027 bam_print(PRINT
, lp
->arg
);
1036 bam_error(NO_MATCH_ENTRY
);
1040 return (BAM_SUCCESS
);
1044 install_bootloader(void)
1049 struct extmnttab mnt
;
1050 struct stat statbuf
= {0};
1051 be_node_list_t
*be_nodes
, *node
;
1053 char *root_ds
= NULL
;
1056 if (nvlist_alloc(&nvl
, NV_UNIQUE_NAME
, 0) != 0) {
1057 bam_error(_("out of memory\n"));
1062 * if bam_alt_root is set, the stage files are used from alt root.
1063 * if pool is set, the target devices are pool devices, stage files
1064 * are read from pool bootfs unless alt root is set.
1066 * use arguments as targets, stage files are from alt or current root
1067 * if no arguments and no pool, install on current boot pool.
1071 if (stat(bam_root
, &statbuf
) != 0) {
1072 bam_error(STAT_FAIL
, bam_root
, strerror(errno
));
1076 if ((fp
= fopen(MNTTAB
, "r")) == NULL
) {
1077 bam_error(OPEN_FAIL
, MNTTAB
, strerror(errno
));
1082 while (getextmntent(fp
, &mnt
, sizeof (mnt
)) == 0) {
1083 if (mnt
.mnt_major
== major(statbuf
.st_dev
) &&
1084 mnt
.mnt_minor
== minor(statbuf
.st_dev
)) {
1086 root_ds
= strdup(mnt
.mnt_special
);
1093 bam_error(NOT_IN_MNTTAB
, bam_root
);
1097 if (root_ds
== NULL
) {
1098 bam_error(_("out of memory\n"));
1103 if (be_list(NULL
, &be_nodes
) != BE_SUCCESS
) {
1104 bam_error(_("No BE's found\n"));
1108 for (node
= be_nodes
; node
!= NULL
; node
= node
->be_next_node
)
1109 if (strcmp(root_ds
, node
->be_root_ds
) == 0)
1113 bam_error(_("BE (%s) does not exist\n"), root_ds
);
1118 be_free_list(be_nodes
);
1122 ret
= nvlist_add_string(nvl
, BE_ATTR_ORIG_BE_NAME
,
1123 node
->be_node_name
);
1124 ret
|= nvlist_add_string(nvl
, BE_ATTR_ORIG_BE_ROOT
,
1126 be_free_list(be_nodes
);
1134 flags
|= BE_INSTALLBOOT_FLAG_FORCE
;
1136 flags
|= BE_INSTALLBOOT_FLAG_MBR
;
1138 flags
|= BE_INSTALLBOOT_FLAG_VERBOSE
;
1140 if (nvlist_add_uint16(nvl
, BE_ATTR_INSTALL_FLAGS
, flags
) != 0) {
1141 bam_error(_("out of memory\n"));
1146 * if altroot was set, we got be name and be root, only need
1147 * to set pool name as target.
1148 * if no altroot, need to find be name and root from pool.
1150 if (bam_pool
!= NULL
) {
1151 ret
= nvlist_add_string(nvl
, BE_ATTR_ORIG_BE_POOL
, bam_pool
);
1157 ret
= be_installboot(nvl
);
1164 if (be_list(NULL
, &be_nodes
) != BE_SUCCESS
) {
1165 bam_error(_("No BE's found\n"));
1170 if (bam_pool
!= NULL
) {
1172 * find active be_node in bam_pool
1174 for (node
= be_nodes
; node
!= NULL
; node
= node
->be_next_node
) {
1175 if (strcmp(bam_pool
, node
->be_rpool
) != 0)
1177 if (node
->be_active_on_boot
)
1181 bam_error(_("No active BE in %s\n"), bam_pool
);
1182 be_free_list(be_nodes
);
1186 ret
= nvlist_add_string(nvl
, BE_ATTR_ORIG_BE_NAME
,
1187 node
->be_node_name
);
1188 ret
|= nvlist_add_string(nvl
, BE_ATTR_ORIG_BE_ROOT
,
1190 be_free_list(be_nodes
);
1195 ret
= be_installboot(nvl
);
1202 * get dataset for "/" and fill up the args.
1204 if ((fp
= fopen(MNTTAB
, "r")) == NULL
) {
1205 bam_error(OPEN_FAIL
, MNTTAB
, strerror(errno
));
1207 be_free_list(be_nodes
);
1212 while (getextmntent(fp
, &mnt
, sizeof (mnt
)) == 0) {
1213 if (strcmp(mnt
.mnt_mountp
, "/") == 0) {
1215 root_ds
= strdup(mnt
.mnt_special
);
1222 bam_error(NOT_IN_MNTTAB
, "/");
1224 be_free_list(be_nodes
);
1227 if (root_ds
== NULL
) {
1228 bam_error(_("out of memory\n"));
1230 be_free_list(be_nodes
);
1234 for (node
= be_nodes
; node
!= NULL
; node
= node
->be_next_node
) {
1235 if (strcmp(root_ds
, node
->be_root_ds
) == 0)
1240 bam_error(_("No such BE: %s\n"), root_ds
);
1242 be_free_list(be_nodes
);
1248 ret
= nvlist_add_string(nvl
, BE_ATTR_ORIG_BE_NAME
, node
->be_node_name
);
1249 ret
|= nvlist_add_string(nvl
, BE_ATTR_ORIG_BE_ROOT
, node
->be_root_ds
);
1250 ret
|= nvlist_add_string(nvl
, BE_ATTR_ORIG_BE_POOL
, node
->be_rpool
);
1251 be_free_list(be_nodes
);
1256 ret
= be_installboot(nvl
) ? BAM_ERROR
: 0;
1264 bam_install(char *subcmd
, char *opt
)
1271 if (check_subcmd_and_options(subcmd
, opt
, inst_subcmds
, &f
) ==
1279 bam_menu(char *subcmd
, char *opt
, int largc
, char *largv
[])
1282 char menu_path
[PATH_MAX
];
1283 char clean_menu_root
[PATH_MAX
];
1284 char path
[PATH_MAX
];
1286 char menu_root
[PATH_MAX
];
1288 error_t (*f
)(menu_t
*mp
, char *menu_path
, char *opt
);
1295 const char *fcn
= "bam_menu()";
1298 * Menu sub-command only applies to GRUB (i.e. x86)
1300 if (!is_grub(bam_alt_root
? bam_root
: "/")) {
1301 bam_error(NOT_GRUB_BOOT
);
1308 ret
= check_subcmd_and_options(subcmd
, opt
, menu_subcmds
, &f
);
1309 if (ret
== BAM_ERROR
) {
1315 (void) strlcpy(menu_root
, bam_root
, sizeof (menu_root
));
1316 osdev
= osroot
= NULL
;
1318 if (strcmp(subcmd
, "update_entry") == 0) {
1321 osdev
= strtok(opt
, ",");
1323 osroot
= strtok(NULL
, ",");
1325 /* fixup bam_root so that it points at osroot */
1326 if (realpath(osroot
, rootbuf
) == NULL
) {
1327 bam_error(CANT_RESOLVE
, osroot
,
1333 bam_rootlen
= strlen(rootbuf
);
1338 * We support menu on PCFS (under certain conditions), but
1341 if (is_pcfs(bam_root
)) {
1342 bam_error(PCFS_ROOT_NOTSUP
, bam_root
);
1346 if (stat(menu_root
, &sb
) == -1) {
1347 bam_error(CANNOT_LOCATE_GRUB_MENU
);
1351 BAM_DPRINTF((D_MENU_ROOT
, fcn
, menu_root
));
1354 * We no longer use the GRUB slice file. If it exists, then
1355 * the user is doing something that is unsupported (such as
1356 * standard upgrading an old Live Upgrade BE). If that
1357 * happens, mimic existing behavior i.e. pretend that it is
1358 * not a BE. Emit a warning though.
1361 (void) snprintf(path
, sizeof (path
), "%s%s", bam_root
,
1364 (void) snprintf(path
, sizeof (path
), "%s", GRUB_slice
);
1367 if (bam_verbose
&& stat(path
, &sb
) == 0)
1368 bam_error(GRUB_SLICE_FILE_EXISTS
, path
);
1370 if (is_zfs(menu_root
)) {
1371 assert(strcmp(menu_root
, bam_root
) == 0);
1372 special
= get_special(menu_root
);
1373 INJECT_ERROR1("Z_MENU_GET_SPECIAL", special
= NULL
);
1374 if (special
== NULL
) {
1375 bam_error(CANT_FIND_SPECIAL
, menu_root
);
1378 pool
= strtok(special
, "/");
1379 INJECT_ERROR1("Z_MENU_GET_POOL", pool
= NULL
);
1382 bam_error(CANT_FIND_POOL
, menu_root
);
1385 BAM_DPRINTF((D_Z_MENU_GET_POOL_FROM_SPECIAL
, fcn
, pool
));
1387 zmntpt
= mount_top_dataset(pool
, &zmnted
);
1388 INJECT_ERROR1("Z_MENU_MOUNT_TOP_DATASET", zmntpt
= NULL
);
1389 if (zmntpt
== NULL
) {
1390 bam_error(CANT_MOUNT_POOL_DATASET
, pool
);
1394 BAM_DPRINTF((D_Z_GET_MENU_MOUNT_TOP_DATASET
, fcn
, zmntpt
));
1396 (void) strlcpy(menu_root
, zmntpt
, sizeof (menu_root
));
1397 BAM_DPRINTF((D_Z_GET_MENU_MENU_ROOT
, fcn
, menu_root
));
1400 elide_trailing_slash(menu_root
, clean_menu_root
,
1401 sizeof (clean_menu_root
));
1403 BAM_DPRINTF((D_CLEAN_MENU_ROOT
, fcn
, clean_menu_root
));
1405 (void) strlcpy(menu_path
, clean_menu_root
, sizeof (menu_path
));
1406 (void) strlcat(menu_path
, GRUB_MENU
, sizeof (menu_path
));
1408 BAM_DPRINTF((D_MENU_PATH
, fcn
, menu_path
));
1411 * If listing the menu, display the menu location
1413 if (strcmp(subcmd
, "list_entry") == 0)
1414 bam_print(GRUB_MENU_PATH
, menu_path
);
1416 if ((menu
= menu_read(menu_path
)) == NULL
) {
1417 bam_error(CANNOT_LOCATE_GRUB_MENU_FILE
, menu_path
);
1418 if (special
!= NULL
)
1425 * We already checked the following case in
1426 * check_subcmd_and_suboptions() above. Complete the
1429 if (strcmp(subcmd
, "set_option") == 0) {
1430 assert(largc
== 1 && largv
[0] && largv
[1] == NULL
);
1432 } else if ((strcmp(subcmd
, "enable_hypervisor") != 0) &&
1433 (strcmp(subcmd
, "list_setting") != 0)) {
1434 assert(largc
== 0 && largv
== NULL
);
1437 ret
= get_boot_cap(bam_root
);
1438 if (ret
!= BAM_SUCCESS
) {
1439 BAM_DPRINTF((D_BOOT_GET_CAP_FAILED
, fcn
));
1444 * Once the sub-cmd handler has run
1445 * only the line field is guaranteed to have valid values
1447 if (strcmp(subcmd
, "update_entry") == 0) {
1448 ret
= f(menu
, menu_root
, osdev
);
1449 } else if (strcmp(subcmd
, "upgrade") == 0) {
1450 ret
= f(menu
, bam_root
, menu_root
);
1451 } else if (strcmp(subcmd
, "list_entry") == 0) {
1452 ret
= f(menu
, menu_path
, opt
);
1453 } else if (strcmp(subcmd
, "list_setting") == 0) {
1454 ret
= f(menu
, ((largc
> 0) ? largv
[0] : ""),
1455 ((largc
> 1) ? largv
[1] : ""));
1456 } else if (strcmp(subcmd
, "disable_hypervisor") == 0) {
1458 bam_error(NO_SPARC
, subcmd
);
1461 ret
= f(menu
, bam_root
, NULL
);
1463 } else if (strcmp(subcmd
, "enable_hypervisor") == 0) {
1465 bam_error(NO_SPARC
, subcmd
);
1468 char *extra_args
= NULL
;
1471 * Compress all arguments passed in the largv[] array
1472 * into one string that can then be appended to the
1473 * end of the kernel$ string the routine to enable the
1474 * hypervisor will build.
1476 * This allows the caller to supply arbitrary unparsed
1477 * arguments, such as dom0 memory settings or APIC
1480 * This concatenation will be done without ANY syntax
1481 * checking whatsoever, so it's the responsibility of
1482 * the caller to make sure the arguments are valid and
1483 * do not duplicate arguments the conversion routines
1489 for (extra_len
= 0, i
= 0; i
< largc
; i
++)
1490 extra_len
+= strlen(largv
[i
]);
1493 * Allocate space for argument strings,
1494 * intervening spaces and terminating NULL.
1496 extra_args
= alloca(extra_len
+ largc
);
1498 (void) strcpy(extra_args
, largv
[0]);
1500 for (i
= 1; i
< largc
; i
++) {
1501 (void) strcat(extra_args
, " ");
1502 (void) strcat(extra_args
, largv
[i
]);
1506 ret
= f(menu
, bam_root
, extra_args
);
1509 ret
= f(menu
, NULL
, opt
);
1511 if (ret
== BAM_WRITE
) {
1512 BAM_DPRINTF((D_WRITING_MENU_ROOT
, fcn
, clean_menu_root
));
1513 ret
= menu_write(clean_menu_root
, menu
);
1517 INJECT_ERROR1("POOL_SET", pool
= "/pooldata");
1518 assert((is_zfs(menu_root
)) ^ (pool
== NULL
));
1520 (void) umount_top_dataset(pool
, zmnted
, zmntpt
);
1534 error_t (*f
)(char *root
, char *opt
);
1535 const char *fcn
= "bam_archive()";
1538 * Add trailing / for archive subcommands
1540 if (rootbuf
[strlen(rootbuf
) - 1] != '/')
1541 (void) strcat(rootbuf
, "/");
1542 bam_rootlen
= strlen(rootbuf
);
1547 ret
= check_subcmd_and_options(subcmd
, opt
, arch_subcmds
, &f
);
1548 if (ret
!= BAM_SUCCESS
) {
1552 ret
= get_boot_cap(rootbuf
);
1553 if (ret
!= BAM_SUCCESS
) {
1554 BAM_DPRINTF((D_BOOT_GET_CAP_FAILED
, fcn
));
1559 * Check archive not supported with update_all
1560 * since it is awkward to display out-of-sync
1561 * information for each BE.
1563 if (bam_check
&& strcmp(subcmd
, "update_all") == 0) {
1564 bam_error(CHECK_NOT_SUPPORTED
, subcmd
);
1568 if (strcmp(subcmd
, "update_all") == 0)
1572 ucode_install(bam_root
);
1575 ret
= f(bam_root
, opt
);
1584 bam_error(char *format
, ...)
1588 va_start(ap
, format
);
1589 (void) fprintf(stderr
, "%s: ", prog
);
1590 (void) vfprintf(stderr
, format
, ap
);
1596 bam_derror(char *format
, ...)
1602 va_start(ap
, format
);
1603 (void) fprintf(stderr
, "DEBUG: ");
1604 (void) vfprintf(stderr
, format
, ap
);
1610 bam_print(char *format
, ...)
1614 va_start(ap
, format
);
1615 (void) vfprintf(stdout
, format
, ap
);
1621 bam_print_stderr(char *format
, ...)
1625 va_start(ap
, format
);
1626 (void) vfprintf(stderr
, format
, ap
);
1631 bam_exit(int excode
)
1644 bam_lock_fd
= open(BAM_LOCK_FILE
, O_CREAT
|O_RDWR
, LOCK_FILE_PERMS
);
1645 if (bam_lock_fd
< 0) {
1647 * We may be invoked early in boot for archive verification.
1648 * In this case, root is readonly and /var/run may not exist.
1649 * Proceed without the lock
1651 if (errno
== EROFS
|| errno
== ENOENT
) {
1652 bam_root_readonly
= 1;
1656 bam_error(OPEN_FAIL
, BAM_LOCK_FILE
, strerror(errno
));
1660 lock
.l_type
= F_WRLCK
;
1661 lock
.l_whence
= SEEK_SET
;
1665 if (fcntl(bam_lock_fd
, F_SETLK
, &lock
) == -1) {
1666 if (errno
!= EACCES
&& errno
!= EAGAIN
) {
1667 bam_error(LOCK_FAIL
, BAM_LOCK_FILE
, strerror(errno
));
1668 (void) close(bam_lock_fd
);
1673 (void) pread(bam_lock_fd
, &pid
, sizeof (pid_t
), 0);
1674 bam_print(FILE_LOCKED
, pid
);
1676 lock
.l_type
= F_WRLCK
;
1677 lock
.l_whence
= SEEK_SET
;
1680 if (fcntl(bam_lock_fd
, F_SETLKW
, &lock
) == -1) {
1681 bam_error(LOCK_FAIL
, BAM_LOCK_FILE
, strerror(errno
));
1682 (void) close(bam_lock_fd
);
1688 /* We own the lock now */
1690 (void) write(bam_lock_fd
, &pid
, sizeof (pid
));
1696 struct flock unlock
;
1699 * NOP if we don't hold the lock
1701 if (bam_lock_fd
< 0) {
1705 unlock
.l_type
= F_UNLCK
;
1706 unlock
.l_whence
= SEEK_SET
;
1710 if (fcntl(bam_lock_fd
, F_SETLK
, &unlock
) == -1) {
1711 bam_error(UNLOCK_FAIL
, BAM_LOCK_FILE
, strerror(errno
));
1714 if (close(bam_lock_fd
) == -1) {
1715 bam_error(CLOSE_FAIL
, BAM_LOCK_FILE
, strerror(errno
));
1721 list_archive(char *root
, char *opt
)
1724 filelist_t
*flistp
= &flist
;
1728 assert(opt
== NULL
);
1730 flistp
->head
= flistp
->tail
= NULL
;
1731 if (read_list(root
, flistp
) != BAM_SUCCESS
) {
1734 assert(flistp
->head
&& flistp
->tail
);
1736 for (lp
= flistp
->head
; lp
; lp
= lp
->next
) {
1737 bam_print(PRINT
, lp
->line
);
1740 filelist_free(flistp
);
1742 return (BAM_SUCCESS
);
1746 * This routine writes a list of lines to a file.
1747 * The list is *not* freed
1750 list2file(char *root
, char *tmp
, char *final
, line_t
*start
)
1752 char tmpfile
[PATH_MAX
];
1753 char path
[PATH_MAX
];
1762 const char *fcn
= "list2file()";
1764 (void) snprintf(path
, sizeof (path
), "%s%s", root
, final
);
1766 if (start
== NULL
) {
1767 /* Empty GRUB menu */
1768 if (stat(path
, &sb
) != -1) {
1769 bam_print(UNLINK_EMPTY
, path
);
1770 if (unlink(path
) != 0) {
1771 bam_error(UNLINK_FAIL
, path
, strerror(errno
));
1774 return (BAM_SUCCESS
);
1777 return (BAM_SUCCESS
);
1781 * Preserve attributes of existing file if possible,
1782 * otherwise ask the system for uid/gid of root/sys.
1783 * If all fails, fall back on hard-coded defaults.
1785 if (stat(path
, &sb
) != -1) {
1787 root_uid
= sb
.st_uid
;
1788 sys_gid
= sb
.st_gid
;
1790 mode
= DEFAULT_DEV_MODE
;
1791 if ((pw
= getpwnam(DEFAULT_DEV_USER
)) != NULL
) {
1792 root_uid
= pw
->pw_uid
;
1794 bam_error(CANT_FIND_USER
,
1795 DEFAULT_DEV_USER
, DEFAULT_DEV_UID
);
1796 root_uid
= (uid_t
)DEFAULT_DEV_UID
;
1798 if ((gp
= getgrnam(DEFAULT_DEV_GROUP
)) != NULL
) {
1799 sys_gid
= gp
->gr_gid
;
1801 bam_error(CANT_FIND_GROUP
,
1802 DEFAULT_DEV_GROUP
, DEFAULT_DEV_GID
);
1803 sys_gid
= (gid_t
)DEFAULT_DEV_GID
;
1807 (void) snprintf(tmpfile
, sizeof (tmpfile
), "%s%s", root
, tmp
);
1809 /* Truncate tmpfile first */
1810 fp
= fopen(tmpfile
, "w");
1812 bam_error(OPEN_FAIL
, tmpfile
, strerror(errno
));
1816 INJECT_ERROR1("LIST2FILE_TRUNC_FCLOSE", ret
= EOF
);
1818 bam_error(CLOSE_FAIL
, tmpfile
, strerror(errno
));
1822 /* Now open it in append mode */
1823 fp
= fopen(tmpfile
, "a");
1825 bam_error(OPEN_FAIL
, tmpfile
, strerror(errno
));
1829 for (; start
; start
= start
->next
) {
1830 ret
= s_fputs(start
->line
, fp
);
1831 INJECT_ERROR1("LIST2FILE_FPUTS", ret
= EOF
);
1833 bam_error(WRITE_FAIL
, tmpfile
, strerror(errno
));
1840 INJECT_ERROR1("LIST2FILE_APPEND_FCLOSE", ret
= EOF
);
1842 bam_error(CLOSE_FAIL
, tmpfile
, strerror(errno
));
1847 * Set up desired attributes. Ignore failures on filesystems
1848 * not supporting these operations - pcfs reports unsupported
1849 * operations as EINVAL.
1851 ret
= chmod(tmpfile
, mode
);
1853 errno
!= EINVAL
&& errno
!= ENOTSUP
) {
1854 bam_error(CHMOD_FAIL
, tmpfile
, strerror(errno
));
1858 ret
= chown(tmpfile
, root_uid
, sys_gid
);
1860 errno
!= EINVAL
&& errno
!= ENOTSUP
) {
1861 bam_error(CHOWN_FAIL
, tmpfile
, strerror(errno
));
1866 * Do an atomic rename
1868 ret
= rename(tmpfile
, path
);
1869 INJECT_ERROR1("LIST2FILE_RENAME", ret
= -1);
1871 bam_error(RENAME_FAIL
, path
, strerror(errno
));
1875 BAM_DPRINTF((D_WROTE_FILE
, fcn
, path
));
1876 return (BAM_SUCCESS
);
1880 * Checks if the path specified (without the file name at the end) exists
1881 * and creates it if not. If the path exists and is not a directory, an attempt
1882 * to unlink is made.
1885 setup_path(char *path
)
1891 p
= strrchr(path
, '/');
1894 if (stat(path
, &sb
) != 0 || !(S_ISDIR(sb
.st_mode
))) {
1895 /* best effort attempt, mkdirp will catch the error */
1896 (void) unlink(path
);
1898 bam_print(NEED_DIRPATH
, path
);
1899 ret
= mkdirp(path
, DIR_PERMS
);
1901 bam_error(MKDIR_FAILED
, path
, strerror(errno
));
1907 return (BAM_SUCCESS
);
1909 return (BAM_SUCCESS
);
1918 char path
[PATH_MAX
];
1923 setup_file(char *base
, const char *path
, cachefile
*cf
)
1928 /* init gzfile or fdfile in case we fail before opening */
1929 if (bam_direct
== BAM_DIRECT_DBOOT
)
1930 cf
->out
.gzfile
= NULL
;
1932 cf
->out
.fdfile
= -1;
1934 /* strip the trailing altroot path */
1935 strip
= (char *)path
+ strlen(rootbuf
);
1937 ret
= snprintf(cf
->path
, sizeof (cf
->path
), "%s/%s", base
, strip
);
1938 if (ret
>= sizeof (cf
->path
)) {
1939 bam_error(PATH_TOO_LONG
, rootbuf
);
1943 /* Check if path is present in the archive cache directory */
1944 if (setup_path(cf
->path
) == BAM_ERROR
)
1947 if (bam_direct
== BAM_DIRECT_DBOOT
) {
1948 if ((cf
->out
.gzfile
= gzopen(cf
->path
, "wb")) == NULL
) {
1949 bam_error(OPEN_FAIL
, cf
->path
, strerror(errno
));
1952 (void) gzsetparams(cf
->out
.gzfile
, Z_BEST_SPEED
,
1953 Z_DEFAULT_STRATEGY
);
1955 if ((cf
->out
.fdfile
= open(cf
->path
, O_WRONLY
| O_CREAT
, 0644))
1957 bam_error(OPEN_FAIL
, cf
->path
, strerror(errno
));
1962 return (BAM_SUCCESS
);
1966 cache_write(cachefile cf
, char *buf
, int size
)
1970 if (bam_direct
== BAM_DIRECT_DBOOT
) {
1971 if (gzwrite(cf
.out
.gzfile
, buf
, size
) < 1) {
1972 bam_error(GZ_WRITE_FAIL
, gzerror(cf
.out
.gzfile
, &err
));
1973 if (err
== Z_ERRNO
&& bam_verbose
) {
1974 bam_error(WRITE_FAIL
, cf
.path
, strerror(errno
));
1979 if (write(cf
.out
.fdfile
, buf
, size
) < 1) {
1980 bam_error(WRITE_FAIL
, cf
.path
, strerror(errno
));
1984 return (BAM_SUCCESS
);
1988 cache_close(cachefile cf
)
1992 if (bam_direct
== BAM_DIRECT_DBOOT
) {
1993 if (cf
.out
.gzfile
) {
1994 ret
= gzclose(cf
.out
.gzfile
);
1996 bam_error(CLOSE_FAIL
, cf
.path
, strerror(errno
));
2001 if (cf
.out
.fdfile
!= -1) {
2002 ret
= close(cf
.out
.fdfile
);
2004 bam_error(CLOSE_FAIL
, cf
.path
, strerror(errno
));
2010 return (BAM_SUCCESS
);
2014 dircache_updatefile(const char *path
, int what
)
2019 cachefile outfile
, outupdt
;
2021 if (bam_nowrite()) {
2022 set_dir_flag(what
, NEED_UPDATE
);
2023 return (BAM_SUCCESS
);
2026 if (!has_cachedir(what
))
2027 return (BAM_SUCCESS
);
2029 if ((infile
= fopen(path
, "rb")) == NULL
) {
2030 bam_error(OPEN_FAIL
, path
, strerror(errno
));
2034 ret
= setup_file(get_cachedir(what
), path
, &outfile
);
2035 if (ret
== BAM_ERROR
) {
2036 exitcode
= BAM_ERROR
;
2039 if (!is_dir_flag_on(what
, NO_MULTI
)) {
2040 ret
= setup_file(get_updatedir(what
), path
, &outupdt
);
2041 if (ret
== BAM_ERROR
)
2042 set_dir_flag(what
, NO_MULTI
);
2045 while ((ret
= fread(buf
, 1, sizeof (buf
), infile
)) > 0) {
2046 if (cache_write(outfile
, buf
, ret
) == BAM_ERROR
) {
2047 exitcode
= BAM_ERROR
;
2050 if (!is_dir_flag_on(what
, NO_MULTI
))
2051 if (cache_write(outupdt
, buf
, ret
) == BAM_ERROR
)
2052 set_dir_flag(what
, NO_MULTI
);
2055 set_dir_flag(what
, NEED_UPDATE
);
2057 if (get_count(what
) > COUNT_MAX
)
2058 set_dir_flag(what
, NO_MULTI
);
2059 exitcode
= BAM_SUCCESS
;
2061 (void) fclose(infile
);
2062 if (cache_close(outfile
) == BAM_ERROR
)
2063 exitcode
= BAM_ERROR
;
2064 if (!is_dir_flag_on(what
, NO_MULTI
) &&
2065 cache_close(outupdt
) == BAM_ERROR
)
2066 exitcode
= BAM_ERROR
;
2067 if (exitcode
== BAM_ERROR
)
2068 set_flag(UPDATE_ERROR
);
2073 dircache_updatedir(const char *path
, int what
, int updt
)
2076 char dpath
[PATH_MAX
];
2080 strip
= (char *)path
+ strlen(rootbuf
);
2082 ret
= snprintf(dpath
, sizeof (dpath
), "%s/%s", updt
?
2083 get_updatedir(what
) : get_cachedir(what
), strip
);
2085 if (ret
>= sizeof (dpath
)) {
2086 bam_error(PATH_TOO_LONG
, rootbuf
);
2087 set_flag(UPDATE_ERROR
);
2091 if (stat(dpath
, &sb
) == 0 && S_ISDIR(sb
.st_mode
))
2092 return (BAM_SUCCESS
);
2095 if (!is_dir_flag_on(what
, NO_MULTI
))
2096 if (!bam_nowrite() && mkdirp(dpath
, DIR_PERMS
) == -1)
2097 set_dir_flag(what
, NO_MULTI
);
2099 if (!bam_nowrite() && mkdirp(dpath
, DIR_PERMS
) == -1) {
2100 set_flag(UPDATE_ERROR
);
2105 set_dir_flag(what
, NEED_UPDATE
);
2106 return (BAM_SUCCESS
);
2109 #define DO_CACHE_DIR 0
2110 #define DO_UPDATE_DIR 1
2112 #if defined(_LP64) || defined(_LONGLONG_TYPE)
2113 typedef Elf64_Ehdr _elfhdr
;
2115 typedef Elf32_Ehdr _elfhdr
;
2119 * This routine updates the contents of the cache directory
2122 update_dircache(const char *path
, int flags
)
2124 int rc
= BAM_SUCCESS
;
2132 if ((fd
= open(path
, O_RDONLY
)) < 0) {
2133 bam_error(OPEN_FAIL
, path
, strerror(errno
));
2134 set_flag(UPDATE_ERROR
);
2140 * libelf and gelf would be a cleaner and easier way to handle
2141 * this, but libelf fails compilation if _ILP32 is defined &&
2142 * _FILE_OFFSET_BITS is != 32 ...
2144 if (read(fd
, (void *)&elf
, sizeof (_elfhdr
)) < 0) {
2145 bam_error(READ_FAIL
, path
, strerror(errno
));
2146 set_flag(UPDATE_ERROR
);
2154 * If the file is not an executable and is not inside an amd64
2155 * directory, we copy it in both the cache directories,
2156 * otherwise, we only copy it inside the 64-bit one.
2158 if (memcmp(elf
.e_ident
, ELFMAG
, 4) != 0) {
2159 if (strstr(path
, "/amd64")) {
2160 rc
= dircache_updatefile(path
, FILE64
);
2162 rc
= dircache_updatefile(path
, FILE32
);
2163 if (rc
== BAM_SUCCESS
)
2164 rc
= dircache_updatefile(path
, FILE64
);
2168 * Based on the ELF class we copy the file in the 32-bit
2169 * or the 64-bit cache directory.
2171 if (elf
.e_ident
[EI_CLASS
] == ELFCLASS32
) {
2172 rc
= dircache_updatefile(path
, FILE32
);
2173 } else if (elf
.e_ident
[EI_CLASS
] == ELFCLASS64
) {
2174 rc
= dircache_updatefile(path
, FILE64
);
2176 bam_print(NO3264ELF
, path
);
2178 rc
= dircache_updatefile(path
, FILE32
);
2179 if (rc
== BAM_SUCCESS
)
2180 rc
= dircache_updatefile(path
, FILE64
);
2186 if (strstr(path
, "/amd64") == NULL
) {
2187 rc
= dircache_updatedir(path
, FILE32
, DO_UPDATE_DIR
);
2188 if (rc
== BAM_SUCCESS
)
2189 rc
= dircache_updatedir(path
, FILE32
,
2192 if (has_cachedir(FILE64
)) {
2193 rc
= dircache_updatedir(path
, FILE64
,
2195 if (rc
== BAM_SUCCESS
)
2196 rc
= dircache_updatedir(path
, FILE64
,
2213 const struct stat
*st
,
2219 uint64_t filestat
[2];
2220 int error
, ret
, status
;
2222 struct safefile
*safefilep
;
2228 * On SPARC we create/update links too.
2230 if (flags
!= FTW_F
&& flags
!= FTW_D
&& (flags
== FTW_SL
&&
2231 !is_flag_on(IS_SPARC_TARGET
)))
2235 * Ignore broken links
2237 if (flags
== FTW_SL
&& stat(file
, &sb
) < 0)
2241 * new_nvlp may be NULL if there were errors earlier
2242 * but this is not fatal to update determination.
2244 if (walk_arg
.new_nvlp
) {
2245 filestat
[0] = st
->st_size
;
2246 filestat
[1] = st
->st_mtime
;
2247 error
= nvlist_add_uint64_array(walk_arg
.new_nvlp
,
2248 file
+ bam_rootlen
, filestat
, 2);
2250 bam_error(NVADD_FAIL
, file
, strerror(error
));
2254 * If we are invoked as part of system/filesystem/boot-archive, then
2255 * there are a number of things we should not worry about
2257 if (bam_smf_check
) {
2258 /* ignore amd64 modules unless we are booted amd64. */
2259 if (!is_amd64() && strstr(file
, "/amd64/") != 0)
2262 /* read in list of safe files */
2263 if (safefiles
== NULL
)
2264 if (fp
= fopen("/boot/solaris/filelist.safe", "r")) {
2265 safefiles
= s_calloc(1,
2266 sizeof (struct safefile
));
2267 safefilep
= safefiles
;
2268 safefilep
->name
= s_calloc(1, MAXPATHLEN
+
2270 safefilep
->next
= NULL
;
2271 while (s_fgets(safefilep
->name
, MAXPATHLEN
+
2272 MAXNAMELEN
, fp
) != NULL
) {
2273 safefilep
->next
= s_calloc(1,
2274 sizeof (struct safefile
));
2275 safefilep
= safefilep
->next
;
2276 safefilep
->name
= s_calloc(1,
2277 MAXPATHLEN
+ MAXNAMELEN
);
2278 safefilep
->next
= NULL
;
2285 * On SPARC we create a -path-list file for mkisofs
2287 if (is_flag_on(IS_SPARC_TARGET
) && !bam_nowrite()) {
2288 if (flags
!= FTW_D
) {
2291 strip
= (char *)file
+ strlen(rootbuf
);
2292 (void) fprintf(walk_arg
.sparcfile
, "/%s=%s\n", strip
,
2298 * We are transitioning from the old model to the dircache or the cache
2299 * directory was removed: create the entry without further checkings.
2301 if (is_flag_on(NEED_CACHE_DIR
)) {
2303 bam_print(PARSEABLE_NEW_FILE
, file
);
2305 if (is_flag_on(IS_SPARC_TARGET
)) {
2306 set_dir_flag(FILE64
, NEED_UPDATE
);
2310 ret
= update_dircache(file
, flags
);
2311 if (ret
== BAM_ERROR
) {
2312 bam_error(UPDT_CACHE_FAIL
, file
);
2320 * We need an update if file doesn't exist in old archive
2322 if (walk_arg
.old_nvlp
== NULL
||
2323 nvlist_lookup_uint64_array(walk_arg
.old_nvlp
,
2324 file
+ bam_rootlen
, &value
, &sz
) != 0) {
2325 if (bam_smf_check
) /* ignore new during smf check */
2328 if (is_flag_on(IS_SPARC_TARGET
)) {
2329 set_dir_flag(FILE64
, NEED_UPDATE
);
2331 ret
= update_dircache(file
, flags
);
2332 if (ret
== BAM_ERROR
) {
2333 bam_error(UPDT_CACHE_FAIL
, file
);
2339 bam_print(PARSEABLE_NEW_FILE
, file
);
2344 * If we got there, the file is already listed as to be included in the
2345 * iso image. We just need to know if we are going to rebuild it or not
2347 if (is_flag_on(IS_SPARC_TARGET
) &&
2348 is_dir_flag_on(FILE64
, NEED_UPDATE
) && !bam_nowrite())
2351 * File exists in old archive. Check if file has changed
2354 bcopy(value
, filestat
, sizeof (filestat
));
2356 if (flags
!= FTW_D
&& (filestat
[0] != st
->st_size
||
2357 filestat
[1] != st
->st_mtime
)) {
2358 if (bam_smf_check
) {
2359 safefilep
= safefiles
;
2360 while (safefilep
!= NULL
&&
2361 safefilep
->name
[0] != '\0') {
2362 if (regcomp(&re
, safefilep
->name
,
2363 REG_EXTENDED
|REG_NOSUB
) == 0) {
2364 status
= regexec(&re
,
2365 file
+ bam_rootlen
, 0, NULL
, 0);
2369 NEED_UPDATE_SAFE_FILE
,
2374 safefilep
= safefilep
->next
;
2378 if (is_flag_on(IS_SPARC_TARGET
)) {
2379 set_dir_flag(FILE64
, NEED_UPDATE
);
2381 ret
= update_dircache(file
, flags
);
2382 if (ret
== BAM_ERROR
) {
2383 bam_error(UPDT_CACHE_FAIL
, file
);
2390 bam_print(" %s\n", file
);
2392 bam_print(PARSEABLE_OUT_DATE
, file
);
2399 * Remove a directory path recursively
2404 struct dirent
*d
= NULL
;
2406 char tpath
[PATH_MAX
];
2409 if ((dir
= opendir(path
)) == NULL
)
2412 while (d
= readdir(dir
)) {
2413 if ((strcmp(d
->d_name
, ".") != 0) &&
2414 (strcmp(d
->d_name
, "..") != 0)) {
2415 (void) snprintf(tpath
, sizeof (tpath
), "%s/%s",
2417 if (stat(tpath
, &sb
) == 0) {
2418 if (sb
.st_mode
& S_IFDIR
)
2419 (void) rmdir_r(tpath
);
2421 (void) remove(tpath
);
2425 return (remove(path
));
2429 * Check if cache directory exists and, if not, create it and update flags
2430 * accordingly. If the path exists, but it's not a directory, a best effort
2431 * attempt to remove and recreate it is made.
2432 * If the user requested a 'purge', always recreate the directory from scratch.
2435 set_cache_dir(char *root
, int what
)
2440 ret
= snprintf(get_cachedir(what
), sizeof (get_cachedir(what
)),
2441 "%s%s%s%s%s", root
, ARCHIVE_PREFIX
, get_machine(), what
== FILE64
?
2442 "/amd64" : "", CACHEDIR_SUFFIX
);
2444 if (ret
>= sizeof (get_cachedir(what
))) {
2445 bam_error(PATH_TOO_LONG
, rootbuf
);
2449 if (bam_purge
|| is_flag_on(INVALIDATE_CACHE
))
2450 (void) rmdir_r(get_cachedir(what
));
2452 if (stat(get_cachedir(what
), &sb
) != 0 || !(S_ISDIR(sb
.st_mode
))) {
2453 /* best effort unlink attempt, mkdir will catch errors */
2454 (void) unlink(get_cachedir(what
));
2457 bam_print(UPDATE_CDIR_MISS
, get_cachedir(what
));
2458 ret
= mkdir(get_cachedir(what
), DIR_PERMS
);
2460 bam_error(MKDIR_FAILED
, get_cachedir(what
),
2462 get_cachedir(what
)[0] = '\0';
2465 set_flag(NEED_CACHE_DIR
);
2466 set_dir_flag(what
, NO_MULTI
);
2469 return (BAM_SUCCESS
);
2473 set_update_dir(char *root
, int what
)
2478 if (is_dir_flag_on(what
, NO_MULTI
))
2479 return (BAM_SUCCESS
);
2482 set_dir_flag(what
, NO_MULTI
);
2483 return (BAM_SUCCESS
);
2486 if (what
== FILE64
&& !is_flag_on(IS_SPARC_TARGET
))
2487 ret
= snprintf(get_updatedir(what
),
2488 sizeof (get_updatedir(what
)), "%s%s%s/amd64%s", root
,
2489 ARCHIVE_PREFIX
, get_machine(), UPDATEDIR_SUFFIX
);
2491 ret
= snprintf(get_updatedir(what
),
2492 sizeof (get_updatedir(what
)), "%s%s%s%s", root
,
2493 ARCHIVE_PREFIX
, get_machine(), UPDATEDIR_SUFFIX
);
2495 if (ret
>= sizeof (get_updatedir(what
))) {
2496 bam_error(PATH_TOO_LONG
, rootbuf
);
2500 if (stat(get_updatedir(what
), &sb
) == 0) {
2501 if (S_ISDIR(sb
.st_mode
))
2502 ret
= rmdir_r(get_updatedir(what
));
2504 ret
= unlink(get_updatedir(what
));
2507 set_dir_flag(what
, NO_MULTI
);
2510 if (mkdir(get_updatedir(what
), DIR_PERMS
) < 0)
2511 set_dir_flag(what
, NO_MULTI
);
2513 return (BAM_SUCCESS
);
2517 is_valid_archive(char *root
, int what
)
2519 char archive_path
[PATH_MAX
];
2520 char timestamp_path
[PATH_MAX
];
2521 struct stat sb
, timestamp
;
2524 if (what
== FILE64
&& !is_flag_on(IS_SPARC_TARGET
))
2525 ret
= snprintf(archive_path
, sizeof (archive_path
),
2526 "%s%s%s/amd64%s", root
, ARCHIVE_PREFIX
, get_machine(),
2529 ret
= snprintf(archive_path
, sizeof (archive_path
), "%s%s%s%s",
2530 root
, ARCHIVE_PREFIX
, get_machine(), ARCHIVE_SUFFIX
);
2532 if (ret
>= sizeof (archive_path
)) {
2533 bam_error(PATH_TOO_LONG
, rootbuf
);
2537 if (stat(archive_path
, &sb
) != 0) {
2538 if (bam_verbose
&& !bam_check
)
2539 bam_print(UPDATE_ARCH_MISS
, archive_path
);
2540 set_dir_flag(what
, NEED_UPDATE
);
2541 set_dir_flag(what
, NO_MULTI
);
2542 return (BAM_SUCCESS
);
2546 * The timestamp file is used to prevent stale files in the archive
2548 * Stale files can happen if the system is booted back and forth across
2549 * the transition from bootadm-before-the-cache to
2550 * bootadm-after-the-cache, since older versions of bootadm don't know
2551 * about the existence of the archive cache.
2553 * Since only bootadm-after-the-cache versions know about about this
2554 * file, we require that the boot archive be older than this file.
2556 ret
= snprintf(timestamp_path
, sizeof (timestamp_path
), "%s%s", root
,
2557 FILE_STAT_TIMESTAMP
);
2559 if (ret
>= sizeof (timestamp_path
)) {
2560 bam_error(PATH_TOO_LONG
, rootbuf
);
2564 if (stat(timestamp_path
, ×tamp
) != 0 ||
2565 sb
.st_mtime
> timestamp
.st_mtime
) {
2566 if (bam_verbose
&& !bam_check
)
2567 bam_print(UPDATE_CACHE_OLD
);
2569 * Don't generate a false positive for the boot-archive service
2570 * but trigger an update of the archive cache in
2571 * boot-archive-update.
2573 if (bam_smf_check
) {
2574 (void) creat(NEED_UPDATE_FILE
, 0644);
2575 return (BAM_SUCCESS
);
2578 set_flag(INVALIDATE_CACHE
);
2579 set_dir_flag(what
, NEED_UPDATE
);
2580 set_dir_flag(what
, NO_MULTI
);
2581 return (BAM_SUCCESS
);
2584 if (is_flag_on(IS_SPARC_TARGET
))
2585 return (BAM_SUCCESS
);
2587 if (bam_extend
&& sb
.st_size
> BA_SIZE_MAX
) {
2588 if (bam_verbose
&& !bam_check
)
2589 bam_print(MULTI_SIZE
, archive_path
, BA_SIZE_MAX
);
2590 set_dir_flag(what
, NO_MULTI
);
2593 return (BAM_SUCCESS
);
2597 * Check flags and presence of required files and directories.
2598 * The force flag and/or absence of files should
2599 * trigger an update.
2600 * Suppress stdout output if check (-n) option is set
2601 * (as -n should only produce parseable output.)
2604 check_flags_and_files(char *root
)
2611 * If archive is missing, create archive
2613 if (is_flag_on(IS_SPARC_TARGET
)) {
2614 ret
= is_valid_archive(root
, FILE64
);
2615 if (ret
== BAM_ERROR
)
2620 ret
= is_valid_archive(root
, what
);
2621 if (ret
== BAM_ERROR
)
2624 } while (bam_direct
== BAM_DIRECT_DBOOT
&& what
< CACHEDIR_NUM
);
2628 return (BAM_SUCCESS
);
2632 * check if cache directories exist on x86.
2633 * check (and always open) the cache file on SPARC.
2636 ret
= snprintf(get_cachedir(FILE64
),
2637 sizeof (get_cachedir(FILE64
)), "%s%s%s/%s", root
,
2638 ARCHIVE_PREFIX
, get_machine(), CACHEDIR_SUFFIX
);
2640 if (ret
>= sizeof (get_cachedir(FILE64
))) {
2641 bam_error(PATH_TOO_LONG
, rootbuf
);
2645 if (stat(get_cachedir(FILE64
), &sb
) != 0) {
2646 set_flag(NEED_CACHE_DIR
);
2647 set_dir_flag(FILE64
, NEED_UPDATE
);
2650 walk_arg
.sparcfile
= fopen(get_cachedir(FILE64
), "w");
2651 if (walk_arg
.sparcfile
== NULL
) {
2652 bam_error(OPEN_FAIL
, get_cachedir(FILE64
),
2657 set_dir_present(FILE64
);
2662 if (set_cache_dir(root
, what
) != 0)
2665 set_dir_present(what
);
2667 if (set_update_dir(root
, what
) != 0)
2670 } while (bam_direct
== BAM_DIRECT_DBOOT
&& what
< CACHEDIR_NUM
);
2674 * if force, create archive unconditionally
2678 set_dir_flag(FILE32
, NEED_UPDATE
);
2679 set_dir_flag(FILE64
, NEED_UPDATE
);
2681 bam_print(UPDATE_FORCE
);
2682 return (BAM_SUCCESS
);
2685 return (BAM_SUCCESS
);
2689 read_one_list(char *root
, filelist_t
*flistp
, char *filelist
)
2691 char path
[PATH_MAX
];
2693 char buf
[BAM_MAXLINE
];
2694 const char *fcn
= "read_one_list()";
2696 (void) snprintf(path
, sizeof (path
), "%s%s", root
, filelist
);
2698 fp
= fopen(path
, "r");
2700 BAM_DPRINTF((D_FLIST_FAIL
, fcn
, path
, strerror(errno
)));
2703 while (s_fgets(buf
, sizeof (buf
), fp
) != NULL
) {
2704 /* skip blank lines */
2705 if (strspn(buf
, " \t") == strlen(buf
))
2707 append_to_flist(flistp
, buf
);
2709 if (fclose(fp
) != 0) {
2710 bam_error(CLOSE_FAIL
, path
, strerror(errno
));
2713 return (BAM_SUCCESS
);
2717 read_list(char *root
, filelist_t
*flistp
)
2719 char path
[PATH_MAX
];
2723 const char *fcn
= "read_list()";
2725 flistp
->head
= flistp
->tail
= NULL
;
2728 * build and check path to extract_boot_filelist.ksh
2730 n
= snprintf(path
, sizeof (path
), "%s%s", root
, EXTRACT_BOOT_FILELIST
);
2731 if (n
>= sizeof (path
)) {
2732 bam_error(NO_FLIST
);
2736 if (is_safe_exec(path
) == BAM_ERROR
)
2740 * If extract_boot_filelist is present, exec it, otherwise read
2741 * the filelists directly, for compatibility with older images.
2743 if (stat(path
, &sb
) == 0) {
2745 * build arguments to exec extract_boot_filelist.ksh
2747 char *rootarg
, *platarg
;
2748 int platarglen
= 1, rootarglen
= 1;
2749 if (strlen(root
) > 1)
2750 rootarglen
+= strlen(root
) + strlen("-R ");
2751 if (bam_alt_platform
)
2752 platarglen
+= strlen(bam_platform
) + strlen("-p ");
2753 platarg
= s_calloc(1, platarglen
);
2754 rootarg
= s_calloc(1, rootarglen
);
2758 if (strlen(root
) > 1) {
2759 (void) snprintf(rootarg
, rootarglen
,
2762 if (bam_alt_platform
) {
2763 (void) snprintf(platarg
, platarglen
,
2764 "-p %s", bam_platform
);
2766 n
= snprintf(cmd
, sizeof (cmd
), "%s %s %s /%s /%s",
2767 path
, rootarg
, platarg
, BOOT_FILE_LIST
, ETC_FILE_LIST
);
2770 if (n
>= sizeof (cmd
)) {
2771 bam_error(NO_FLIST
);
2774 if (exec_cmd(cmd
, flistp
) != 0) {
2775 BAM_DPRINTF((D_FLIST_FAIL
, fcn
, path
, strerror(errno
)));
2780 * Read current lists of files - only the first is mandatory
2782 rval
= read_one_list(root
, flistp
, BOOT_FILE_LIST
);
2783 if (rval
!= BAM_SUCCESS
)
2785 (void) read_one_list(root
, flistp
, ETC_FILE_LIST
);
2788 if (flistp
->head
== NULL
) {
2789 bam_error(NO_FLIST
);
2793 return (BAM_SUCCESS
);
2797 getoldstat(char *root
)
2799 char path
[PATH_MAX
];
2804 (void) snprintf(path
, sizeof (path
), "%s%s", root
, FILE_STAT
);
2805 fd
= open(path
, O_RDONLY
);
2808 bam_print(OPEN_FAIL
, path
, strerror(errno
));
2812 if (fstat(fd
, &sb
) != 0) {
2813 bam_error(STAT_FAIL
, path
, strerror(errno
));
2817 ostat
= s_calloc(1, sb
.st_size
);
2819 if (read(fd
, ostat
, sb
.st_size
) != sb
.st_size
) {
2820 bam_error(READ_FAIL
, path
, strerror(errno
));
2828 walk_arg
.old_nvlp
= NULL
;
2829 error
= nvlist_unpack(ostat
, sb
.st_size
, &walk_arg
.old_nvlp
, 0);
2834 bam_error(UNPACK_FAIL
, path
, strerror(error
));
2835 walk_arg
.old_nvlp
= NULL
;
2844 if (!is_flag_on(IS_SPARC_TARGET
))
2845 set_dir_flag(FILE32
, NEED_UPDATE
);
2846 set_dir_flag(FILE64
, NEED_UPDATE
);
2849 /* Best effort stale entry removal */
2851 delete_stale(char *file
, int what
)
2853 char path
[PATH_MAX
];
2856 (void) snprintf(path
, sizeof (path
), "%s/%s", get_cachedir(what
), file
);
2857 if (!bam_check
&& stat(path
, &sb
) == 0) {
2858 if (sb
.st_mode
& S_IFDIR
)
2859 (void) rmdir_r(path
);
2861 (void) unlink(path
);
2863 set_dir_flag(what
, (NEED_UPDATE
| NO_MULTI
));
2868 * Checks if a file in the current (old) archive has
2869 * been deleted from the root filesystem. This is needed for
2870 * software like Trusted Extensions (TX) that switch early
2871 * in boot based on presence/absence of a kernel module.
2874 check4stale(char *root
)
2879 char path
[PATH_MAX
];
2882 * Skip stale file check during smf check
2888 * If we need to (re)create the cache, there's no need to check for
2891 if (is_flag_on(NEED_CACHE_DIR
))
2894 /* Nothing to do if no old stats */
2895 if ((nvlp
= walk_arg
.old_nvlp
) == NULL
)
2898 for (nvp
= nvlist_next_nvpair(nvlp
, NULL
); nvp
;
2899 nvp
= nvlist_next_nvpair(nvlp
, nvp
)) {
2900 file
= nvpair_name(nvp
);
2903 (void) snprintf(path
, sizeof (path
), "%s/%s",
2905 if (access(path
, F_OK
) < 0) {
2909 bam_print(PARSEABLE_STALE_FILE
, path
);
2911 if (is_flag_on(IS_SPARC_TARGET
)) {
2912 set_dir_flag(FILE64
, NEED_UPDATE
);
2914 for (what
= FILE32
; what
< CACHEDIR_NUM
; what
++)
2915 if (has_cachedir(what
))
2916 delete_stale(file
, what
);
2923 create_newstat(void)
2927 error
= nvlist_alloc(&walk_arg
.new_nvlp
, NV_UNIQUE_NAME
, 0);
2930 * Not fatal - we can still create archive
2932 walk_arg
.new_nvlp
= NULL
;
2933 bam_error(NVALLOC_FAIL
, strerror(error
));
2938 walk_list(char *root
, filelist_t
*flistp
)
2940 char path
[PATH_MAX
];
2943 for (lp
= flistp
->head
; lp
; lp
= lp
->next
) {
2945 * Don't follow symlinks. A symlink must refer to
2946 * a file that would appear in the archive through
2947 * a direct reference. This matches the archive
2948 * construction behavior.
2950 (void) snprintf(path
, sizeof (path
), "%s%s", root
, lp
->line
);
2951 if (nftw(path
, cmpstat
, 20, FTW_PHYS
) == -1) {
2952 if (is_flag_on(UPDATE_ERROR
))
2955 * Some files may not exist.
2956 * For example: etc/rtc_config on a x86 diskless system
2957 * Emit verbose message only
2960 bam_print(NFTW_FAIL
, path
, strerror(errno
));
2964 return (BAM_SUCCESS
);
2968 * Update the timestamp file.
2971 update_timestamp(char *root
)
2973 char timestamp_path
[PATH_MAX
];
2975 /* this path length has already been checked in check_flags_and_files */
2976 (void) snprintf(timestamp_path
, sizeof (timestamp_path
), "%s%s", root
,
2977 FILE_STAT_TIMESTAMP
);
2980 * recreate the timestamp file. Since an outdated or absent timestamp
2981 * file translates in a complete rebuild of the archive cache, notify
2982 * the user of the performance issue.
2984 if (creat(timestamp_path
, FILE_STAT_MODE
) < 0) {
2985 bam_error(OPEN_FAIL
, timestamp_path
, strerror(errno
));
2986 bam_error(TIMESTAMP_FAIL
);
2994 char path
[PATH_MAX
];
2995 char path2
[PATH_MAX
];
2998 int fd
, wrote
, error
;
3002 error
= nvlist_pack(walk_arg
.new_nvlp
, &nstat
, &sz
,
3005 bam_error(PACK_FAIL
, strerror(error
));
3009 (void) snprintf(path
, sizeof (path
), "%s%s", root
, FILE_STAT_TMP
);
3010 fd
= open(path
, O_RDWR
|O_CREAT
|O_TRUNC
, FILE_STAT_MODE
);
3012 bam_error(OPEN_FAIL
, path
, strerror(errno
));
3016 wrote
= write(fd
, nstat
, sz
);
3018 bam_error(WRITE_FAIL
, path
, strerror(errno
));
3026 (void) snprintf(path2
, sizeof (path2
), "%s%s", root
, FILE_STAT
);
3027 if (rename(path
, path2
) != 0) {
3028 bam_error(RENAME_FAIL
, path2
, strerror(errno
));
3032 #define init_walk_args() bzero(&walk_arg, sizeof (walk_arg))
3035 clear_walk_args(void)
3037 nvlist_free(walk_arg
.old_nvlp
);
3038 nvlist_free(walk_arg
.new_nvlp
);
3039 if (walk_arg
.sparcfile
)
3040 (void) fclose(walk_arg
.sparcfile
);
3041 walk_arg
.old_nvlp
= NULL
;
3042 walk_arg
.new_nvlp
= NULL
;
3043 walk_arg
.sparcfile
= NULL
;
3048 * 0 - no update necessary
3049 * 1 - update required.
3050 * BAM_ERROR (-1) - An error occurred
3052 * Special handling for check (-n):
3053 * ================================
3054 * The check (-n) option produces parseable output.
3055 * To do this, we suppress all stdout messages unrelated
3056 * to out of sync files.
3057 * All stderr messages are still printed though.
3061 update_required(char *root
)
3064 char path
[PATH_MAX
];
3066 filelist_t
*flistp
= &flist
;
3069 flistp
->head
= flistp
->tail
= NULL
;
3072 set_flag(IS_SPARC_TARGET
);
3075 * Check if cache directories and archives are present
3078 ret
= check_flags_and_files(root
);
3083 * In certain deployment scenarios, filestat may not
3084 * exist. Do not stop the boot process, but trigger an update
3085 * of the archives (which will recreate filestat.ramdisk).
3087 if (bam_smf_check
) {
3088 (void) snprintf(path
, sizeof (path
), "%s%s", root
, FILE_STAT
);
3089 if (stat(path
, &sb
) != 0) {
3090 (void) creat(NEED_UPDATE_FILE
, 0644);
3098 * Check if the archive contains files that are no longer
3099 * present on the root filesystem.
3104 * read list of files
3106 if (read_list(root
, flistp
) != BAM_SUCCESS
) {
3111 assert(flistp
->head
&& flistp
->tail
);
3114 * At this point either the update is required
3115 * or the decision is pending. In either case
3116 * we need to create new stat nvlist
3120 * This walk does 2 things:
3121 * - gets new stat data for every file
3122 * - (optional) compare old and new stat data
3124 ret
= walk_list(root
, &flist
);
3126 /* done with the file list */
3127 filelist_free(flistp
);
3129 /* something went wrong */
3131 if (ret
== BAM_ERROR
) {
3132 bam_error(CACHE_FAIL
);
3136 if (walk_arg
.new_nvlp
== NULL
) {
3137 if (walk_arg
.sparcfile
!= NULL
)
3138 (void) fclose(walk_arg
.sparcfile
);
3139 bam_error(NO_NEW_STAT
);
3142 /* If nothing was updated, discard newstat. */
3144 if (!is_dir_flag_on(FILE32
, NEED_UPDATE
) &&
3145 !is_dir_flag_on(FILE64
, NEED_UPDATE
)) {
3150 if (walk_arg
.sparcfile
!= NULL
)
3151 (void) fclose(walk_arg
.sparcfile
);
3159 char cmd
[PATH_MAX
+ 30];
3161 (void) snprintf(cmd
, sizeof (cmd
), "%s -f \"%s\" 2>/dev/null",
3164 return (exec_cmd(cmd
, NULL
));
3168 do_archive_copy(char *source
, char *dest
)
3173 /* the equivalent of mv archive-new-$pid boot_archive */
3174 if (rename(source
, dest
) != 0) {
3175 (void) unlink(source
);
3179 if (flushfs(bam_root
) != 0)
3182 return (BAM_SUCCESS
);
3186 check_cmdline(filelist_t flist
)
3190 for (lp
= flist
.head
; lp
; lp
= lp
->next
) {
3191 if (strstr(lp
->line
, "Error:") != NULL
||
3192 strstr(lp
->line
, "Inode number overflow") != NULL
) {
3193 (void) fprintf(stderr
, "%s\n", lp
->line
);
3198 return (BAM_SUCCESS
);
3202 dump_errormsg(filelist_t flist
)
3206 for (lp
= flist
.head
; lp
; lp
= lp
->next
)
3207 (void) fprintf(stderr
, "%s\n", lp
->line
);
3211 check_archive(char *dest
)
3215 if (stat(dest
, &sb
) != 0 || !S_ISREG(sb
.st_mode
) ||
3216 sb
.st_size
< 10000) {
3217 bam_error(ARCHIVE_BAD
, dest
);
3218 (void) unlink(dest
);
3222 return (BAM_SUCCESS
);
3229 libzfs_handle_t
*hdl
;
3230 be_node_list_t
*be_nodes
= NULL
;
3231 be_node_list_t
*cur_be
;
3232 boolean_t be_exist
= B_FALSE
;
3233 char ds_path
[ZFS_MAX_DATASET_NAME_LEN
];
3238 * Get dataset for mountpoint
3240 if ((hdl
= libzfs_init()) == NULL
)
3243 if ((zhp
= zfs_path_to_zhandle(hdl
, root
,
3244 ZFS_TYPE_FILESYSTEM
)) == NULL
) {
3249 (void) strlcpy(ds_path
, zfs_get_name(zhp
), sizeof (ds_path
));
3252 * Check if the current dataset is BE
3254 if (be_list(NULL
, &be_nodes
) == BE_SUCCESS
) {
3255 for (cur_be
= be_nodes
; cur_be
!= NULL
;
3256 cur_be
= cur_be
->be_next_node
) {
3259 * Because we guarantee that cur_be->be_root_ds
3260 * is null-terminated by internal data structure,
3261 * we can safely use strcmp()
3263 if (strcmp(ds_path
, cur_be
->be_root_ds
) == 0) {
3268 be_free_list(be_nodes
);
3277 * Returns 1 if mkiso is in the expected PATH, 0 otherwise
3282 if (access(MKISOFS_PATH
, X_OK
) == 0)
3287 #define MKISO_PARAMS " -quiet -graft-points -dlrDJN -relaxed-filenames "
3290 create_sparc_archive(char *archive
, char *tempname
, char *bootblk
, char *list
)
3293 char cmdline
[3 * PATH_MAX
+ 64];
3294 filelist_t flist
= {0};
3295 const char *func
= "create_sparc_archive()";
3297 if (access(bootblk
, R_OK
) == 1) {
3298 bam_error(BOOTBLK_FAIL
, bootblk
);
3303 * Prepare mkisofs command line and execute it
3305 (void) snprintf(cmdline
, sizeof (cmdline
), "%s %s -G %s -o \"%s\" "
3306 "-path-list \"%s\" 2>&1", MKISOFS_PATH
, MKISO_PARAMS
, bootblk
,
3309 BAM_DPRINTF((D_CMDLINE
, func
, cmdline
));
3311 ret
= exec_cmd(cmdline
, &flist
);
3312 if (ret
!= 0 || check_cmdline(flist
) == BAM_ERROR
) {
3313 dump_errormsg(flist
);
3317 filelist_free(&flist
);
3320 * Prepare dd command line to copy the bootblk on the new archive and
3323 (void) snprintf(cmdline
, sizeof (cmdline
), "%s if=\"%s\" of=\"%s\""
3324 " bs=1b oseek=1 count=15 conv=notrunc conv=sync 2>&1", DD_PATH_USR
,
3327 BAM_DPRINTF((D_CMDLINE
, func
, cmdline
));
3329 ret
= exec_cmd(cmdline
, &flist
);
3330 if (ret
!= 0 || check_cmdline(flist
) == BAM_ERROR
)
3333 filelist_free(&flist
);
3335 /* Did we get a valid archive ? */
3336 if (check_archive(tempname
) == BAM_ERROR
)
3339 return (do_archive_copy(tempname
, archive
));
3342 filelist_free(&flist
);
3343 bam_error(ARCHIVE_FAIL
, cmdline
);
3344 (void) unlink(tempname
);
3349 from_733(unsigned char *s
)
3352 unsigned int ret
= 0;
3354 for (i
= 0; i
< 4; i
++)
3355 ret
|= s
[i
] << (8 * i
);
3361 to_733(unsigned char *s
, unsigned int val
)
3365 for (i
= 0; i
< 4; i
++)
3366 s
[i
] = s
[7-i
] = (val
>> (8 * i
)) & 0xFF;
3370 * creates sha1 hash of archive
3373 digest_archive(const char *archive
)
3380 (void) asprintf(&archive_hash
, "%s.hash", archive
);
3381 if (archive_hash
== NULL
)
3384 if ((ret
= bootadm_digest(archive
, &hash
)) == BAM_ERROR
) {
3389 fp
= fopen(archive_hash
, "w");
3396 (void) fprintf(fp
, "%s\n", hash
);
3400 return (BAM_SUCCESS
);
3404 * Extends the current boot archive without recreating it from scratch
3407 extend_iso_archive(char *archive
, char *tempname
, char *update_dir
)
3409 int fd
= -1, newfd
= -1, ret
, i
;
3410 int next_session
= 0, new_size
= 0;
3411 char cmdline
[3 * PATH_MAX
+ 64];
3412 const char *func
= "extend_iso_archive()";
3413 filelist_t flist
= {0};
3414 struct iso_pdesc saved_desc
[MAX_IVDs
];
3416 fd
= open(archive
, O_RDWR
);
3419 bam_error(OPEN_FAIL
, archive
, strerror(errno
));
3424 * A partial read is likely due to a corrupted file
3426 ret
= pread64(fd
, saved_desc
, sizeof (saved_desc
),
3427 VOLDESC_OFF
* CD_BLOCK
);
3428 if (ret
!= sizeof (saved_desc
)) {
3430 bam_error(READ_FAIL
, archive
, strerror(errno
));
3434 if (memcmp(saved_desc
[0].type
, "\1CD001", 6)) {
3436 bam_error(SIGN_FAIL
, archive
);
3441 * Read primary descriptor and locate next_session offset (it should
3442 * point to the end of the archive)
3444 next_session
= P2ROUNDUP(from_733(saved_desc
[0].volume_space_size
), 16);
3446 (void) snprintf(cmdline
, sizeof (cmdline
), "%s -C 16,%d -M %s %s -o \""
3447 "%s\" \"%s\" 2>&1", MKISOFS_PATH
, next_session
, archive
,
3448 MKISO_PARAMS
, tempname
, update_dir
);
3450 BAM_DPRINTF((D_CMDLINE
, func
, cmdline
));
3452 ret
= exec_cmd(cmdline
, &flist
);
3453 if (ret
!= 0 || check_cmdline(flist
) == BAM_ERROR
) {
3455 bam_error(MULTI_FAIL
, cmdline
);
3456 dump_errormsg(flist
);
3460 filelist_free(&flist
);
3462 newfd
= open(tempname
, O_RDONLY
);
3465 bam_error(OPEN_FAIL
, archive
, strerror(errno
));
3469 ret
= pread64(newfd
, saved_desc
, sizeof (saved_desc
),
3470 VOLDESC_OFF
* CD_BLOCK
);
3471 if (ret
!= sizeof (saved_desc
)) {
3473 bam_error(READ_FAIL
, archive
, strerror(errno
));
3477 if (memcmp(saved_desc
[0].type
, "\1CD001", 6)) {
3479 bam_error(SIGN_FAIL
, archive
);
3483 new_size
= from_733(saved_desc
[0].volume_space_size
) + next_session
;
3484 to_733(saved_desc
[0].volume_space_size
, new_size
);
3486 for (i
= 1; i
< MAX_IVDs
; i
++) {
3487 if (saved_desc
[i
].type
[0] == (unsigned char)255)
3489 if (memcmp(saved_desc
[i
].id
, "CD001", 5))
3493 bam_print("%s: Updating descriptor entry [%d]\n", func
,
3496 to_733(saved_desc
[i
].volume_space_size
, new_size
);
3499 ret
= pwrite64(fd
, saved_desc
, DVD_BLOCK
, VOLDESC_OFF
*CD_BLOCK
);
3500 if (ret
!= DVD_BLOCK
) {
3502 bam_error(WRITE_FAIL
, archive
, strerror(errno
));
3505 (void) close(newfd
);
3515 bam_error(CLOSE_FAIL
, archive
, strerror(errno
));
3520 (void) snprintf(cmdline
, sizeof (cmdline
), "%s if=%s of=%s bs=32k "
3521 "seek=%d conv=sync 2>&1", DD_PATH_USR
, tempname
, archive
,
3524 BAM_DPRINTF((D_CMDLINE
, func
, cmdline
));
3526 ret
= exec_cmd(cmdline
, &flist
);
3527 if (ret
!= 0 || check_cmdline(flist
) == BAM_ERROR
) {
3529 bam_error(MULTI_FAIL
, cmdline
);
3532 filelist_free(&flist
);
3534 (void) unlink(tempname
);
3536 if (digest_archive(archive
) == BAM_ERROR
&& bam_verbose
)
3537 bam_print("boot archive hashing failed\n");
3539 if (flushfs(bam_root
) != 0)
3543 bam_print("boot archive updated successfully\n");
3545 return (BAM_SUCCESS
);
3548 filelist_free(&flist
);
3553 (void) close(newfd
);
3558 create_x86_archive(char *archive
, char *tempname
, char *update_dir
)
3561 char cmdline
[3 * PATH_MAX
+ 64];
3562 filelist_t flist
= {0};
3563 const char *func
= "create_x86_archive()";
3565 (void) snprintf(cmdline
, sizeof (cmdline
), "%s %s -o \"%s\" \"%s\" "
3566 "2>&1", MKISOFS_PATH
, MKISO_PARAMS
, tempname
, update_dir
);
3568 BAM_DPRINTF((D_CMDLINE
, func
, cmdline
));
3570 ret
= exec_cmd(cmdline
, &flist
);
3571 if (ret
!= 0 || check_cmdline(flist
) == BAM_ERROR
) {
3572 bam_error(ARCHIVE_FAIL
, cmdline
);
3573 dump_errormsg(flist
);
3574 filelist_free(&flist
);
3575 (void) unlink(tempname
);
3579 filelist_free(&flist
);
3581 if (check_archive(tempname
) == BAM_ERROR
)
3584 return (do_archive_copy(tempname
, archive
));
3588 mkisofs_archive(char *root
, int what
)
3591 char temp
[PATH_MAX
];
3592 char bootblk
[PATH_MAX
];
3593 char boot_archive
[PATH_MAX
];
3595 if (what
== FILE64
&& !is_flag_on(IS_SPARC_TARGET
))
3596 ret
= snprintf(temp
, sizeof (temp
),
3597 "%s%s%s/amd64/archive-new-%d", root
, ARCHIVE_PREFIX
,
3598 get_machine(), getpid());
3600 ret
= snprintf(temp
, sizeof (temp
), "%s%s%s/archive-new-%d",
3601 root
, ARCHIVE_PREFIX
, get_machine(), getpid());
3603 if (ret
>= sizeof (temp
))
3606 if (what
== FILE64
&& !is_flag_on(IS_SPARC_TARGET
))
3607 ret
= snprintf(boot_archive
, sizeof (boot_archive
),
3608 "%s%s%s/amd64%s", root
, ARCHIVE_PREFIX
, get_machine(),
3611 ret
= snprintf(boot_archive
, sizeof (boot_archive
),
3612 "%s%s%s%s", root
, ARCHIVE_PREFIX
, get_machine(),
3615 if (ret
>= sizeof (boot_archive
))
3618 bam_print("updating %s\n", boot_archive
);
3620 if (is_flag_on(IS_SPARC_TARGET
)) {
3621 ret
= snprintf(bootblk
, sizeof (bootblk
),
3622 "%s/platform/%s/lib/fs/hsfs/bootblk", root
, get_machine());
3623 if (ret
>= sizeof (bootblk
))
3626 ret
= create_sparc_archive(boot_archive
, temp
, bootblk
,
3627 get_cachedir(what
));
3629 if (!is_dir_flag_on(what
, NO_MULTI
)) {
3631 bam_print("Attempting to extend x86 archive: "
3632 "%s\n", boot_archive
);
3634 ret
= extend_iso_archive(boot_archive
, temp
,
3635 get_updatedir(what
));
3636 if (ret
== BAM_SUCCESS
) {
3638 bam_print("Successfully extended %s\n",
3641 (void) rmdir_r(get_updatedir(what
));
3642 return (BAM_SUCCESS
);
3646 * The boot archive will be recreated from scratch. We get here
3647 * if at least one of these conditions is true:
3648 * - bootadm was called without the -e switch
3649 * - the archive (or the archive cache) doesn't exist
3650 * - archive size is bigger than BA_SIZE_MAX
3651 * - more than COUNT_MAX files need to be updated
3652 * - an error occourred either populating the /updates directory
3653 * or extend_iso_archive() failed
3656 bam_print("Unable to extend %s... rebuilding archive\n",
3659 if (get_updatedir(what
)[0] != '\0')
3660 (void) rmdir_r(get_updatedir(what
));
3663 ret
= create_x86_archive(boot_archive
, temp
,
3664 get_cachedir(what
));
3667 if (digest_archive(boot_archive
) == BAM_ERROR
&& bam_verbose
)
3668 bam_print("boot archive hashing failed\n");
3670 if (ret
== BAM_SUCCESS
&& bam_verbose
)
3671 bam_print("Successfully created %s\n", boot_archive
);
3676 bam_error(PATH_TOO_LONG
, root
);
3681 create_ramdisk(char *root
)
3683 char *cmdline
, path
[PATH_MAX
];
3686 int ret
, what
, status
= BAM_SUCCESS
;
3688 /* If there is mkisofs, use it to create the required archives */
3690 for (what
= FILE32
; what
< CACHEDIR_NUM
; what
++) {
3691 if (has_cachedir(what
) && is_dir_flag_on(what
,
3693 ret
= mkisofs_archive(root
, what
);
3702 * Else setup command args for create_ramdisk.ksh for the UFS archives
3703 * Note: we will not create hash here, CREATE_RAMDISK should create it.
3706 bam_print("mkisofs not found, creating UFS archive\n");
3708 (void) snprintf(path
, sizeof (path
), "%s/%s", root
, CREATE_RAMDISK
);
3709 if (stat(path
, &sb
) != 0) {
3710 bam_error(ARCH_EXEC_MISS
, path
, strerror(errno
));
3714 if (is_safe_exec(path
) == BAM_ERROR
)
3717 len
= strlen(path
) + strlen(root
) + 10; /* room for space + -R */
3718 if (bam_alt_platform
)
3719 len
+= strlen(bam_platform
) + strlen("-p ");
3720 cmdline
= s_calloc(1, len
);
3722 if (bam_alt_platform
) {
3723 assert(strlen(root
) > 1);
3724 (void) snprintf(cmdline
, len
, "%s -p %s -R %s",
3725 path
, bam_platform
, root
);
3726 /* chop off / at the end */
3727 cmdline
[strlen(cmdline
) - 1] = '\0';
3728 } else if (strlen(root
) > 1) {
3729 (void) snprintf(cmdline
, len
, "%s -R %s", path
, root
);
3730 /* chop off / at the end */
3731 cmdline
[strlen(cmdline
) - 1] = '\0';
3733 (void) snprintf(cmdline
, len
, "%s", path
);
3735 if (exec_cmd(cmdline
, NULL
) != 0) {
3736 bam_error(ARCHIVE_FAIL
, cmdline
);
3742 * The existence of the expected archives used to be
3743 * verified here. This check is done in create_ramdisk as
3744 * it needs to be in sync with the altroot operated upon.
3746 return (BAM_SUCCESS
);
3750 * Checks if target filesystem is on a ramdisk
3753 * When in doubt assume it is not a ramdisk.
3756 is_ramdisk(char *root
)
3758 struct extmnttab mnt
;
3761 char mntpt
[PATH_MAX
];
3765 * There are 3 situations where creating archive is
3767 * - create boot_archive on a lofi-mounted boot_archive
3768 * - create it on a ramdisk which is the root filesystem
3769 * - create it on a ramdisk mounted somewhere else
3770 * The first is not easy to detect and checking for it is not
3772 * The other two conditions are handled here
3774 fp
= fopen(MNTTAB
, "r");
3776 bam_error(OPEN_FAIL
, MNTTAB
, strerror(errno
));
3783 * Remove any trailing / from the mount point
3785 (void) strlcpy(mntpt
, root
, sizeof (mntpt
));
3786 if (strcmp(root
, "/") != 0) {
3787 cp
= mntpt
+ strlen(mntpt
) - 1;
3792 while (getextmntent(fp
, &mnt
, sizeof (mnt
)) == 0) {
3793 if (strcmp(mnt
.mnt_mountp
, mntpt
) == 0) {
3801 bam_error(NOT_IN_MNTTAB
, mntpt
);
3806 if (strncmp(mnt
.mnt_special
, RAMDISK_SPECIAL
,
3807 strlen(RAMDISK_SPECIAL
)) == 0) {
3809 bam_error(IS_RAMDISK
, bam_root
);
3820 is_boot_archive(char *root
)
3822 char path
[PATH_MAX
];
3825 const char *fcn
= "is_boot_archive()";
3828 * We can't create an archive without the create_ramdisk script
3830 (void) snprintf(path
, sizeof (path
), "%s/%s", root
, CREATE_RAMDISK
);
3831 error
= stat(path
, &sb
);
3832 INJECT_ERROR1("NOT_ARCHIVE_BASED", error
= -1);
3835 bam_print(FILE_MISS
, path
);
3836 BAM_DPRINTF((D_NOT_ARCHIVE_BOOT
, fcn
, root
));
3840 BAM_DPRINTF((D_IS_ARCHIVE_BOOT
, fcn
, root
));
3845 * Need to call this for anything that operates on the GRUB menu
3846 * In the x86 live upgrade case the directory /boot/grub may be present
3847 * even on pre-newboot BEs. The authoritative way to check for a GRUB target
3848 * is to check for the presence of the stage2 binary which is present
3849 * only on GRUB targets (even on x86 boot partitions). Checking for the
3850 * presence of the multiboot binary is not correct as it is not present
3851 * on x86 boot partitions.
3854 is_grub(const char *root
)
3856 char path
[PATH_MAX
];
3858 const char *fcn
= "is_grub()";
3860 (void) snprintf(path
, sizeof (path
), "%s%s", root
, GRUB_STAGE2
);
3861 if (stat(path
, &sb
) == -1) {
3862 BAM_DPRINTF((D_NO_GRUB_DIR
, fcn
, path
));
3874 const char *fcn
= "is_zfs()";
3876 ret
= statvfs(root
, &vfs
);
3877 INJECT_ERROR1("STATVFS_ZFS", ret
= 1);
3879 bam_error(STATVFS_FAIL
, root
, strerror(errno
));
3883 if (strncmp(vfs
.f_basetype
, "zfs", strlen("zfs")) == 0) {
3884 BAM_DPRINTF((D_IS_ZFS
, fcn
, root
));
3887 BAM_DPRINTF((D_IS_NOT_ZFS
, fcn
, root
));
3897 const char *fcn
= "is_ufs()";
3899 ret
= statvfs(root
, &vfs
);
3900 INJECT_ERROR1("STATVFS_UFS", ret
= 1);
3902 bam_error(STATVFS_FAIL
, root
, strerror(errno
));
3906 if (strncmp(vfs
.f_basetype
, "ufs", strlen("ufs")) == 0) {
3907 BAM_DPRINTF((D_IS_UFS
, fcn
, root
));
3910 BAM_DPRINTF((D_IS_NOT_UFS
, fcn
, root
));
3920 const char *fcn
= "is_pcfs()";
3922 ret
= statvfs(root
, &vfs
);
3923 INJECT_ERROR1("STATVFS_PCFS", ret
= 1);
3925 bam_error(STATVFS_FAIL
, root
, strerror(errno
));
3929 if (strncmp(vfs
.f_basetype
, "pcfs", strlen("pcfs")) == 0) {
3930 BAM_DPRINTF((D_IS_PCFS
, fcn
, root
));
3933 BAM_DPRINTF((D_IS_NOT_PCFS
, fcn
, root
));
3939 is_readonly(char *root
)
3943 char testfile
[PATH_MAX
];
3944 const char *fcn
= "is_readonly()";
3947 * Using statvfs() to check for a read-only filesystem is not
3948 * reliable. The only way to reliably test is to attempt to
3951 (void) snprintf(testfile
, sizeof (testfile
), "%s/%s.%d",
3952 root
, BOOTADM_RDONLY_TEST
, getpid());
3954 (void) unlink(testfile
);
3957 fd
= open(testfile
, O_RDWR
|O_CREAT
|O_EXCL
, 0644);
3959 INJECT_ERROR2("RDONLY_TEST_ERROR", fd
= -1, error
= EACCES
);
3960 if (fd
== -1 && error
== EROFS
) {
3961 BAM_DPRINTF((D_RDONLY_FS
, fcn
, root
));
3963 } else if (fd
== -1) {
3964 bam_error(RDONLY_TEST_ERROR
, root
, strerror(error
));
3968 (void) unlink(testfile
);
3970 BAM_DPRINTF((D_RDWR_FS
, fcn
, root
));
3975 update_archive(char *root
, char *opt
)
3980 assert(opt
== NULL
);
3986 * Never update non-BE root in update_all
3988 if (!is_be(root
) && bam_update_all
)
3989 return (BAM_SUCCESS
);
3991 * root must belong to a boot archive based OS,
3993 if (!is_boot_archive(root
)) {
3995 * Emit message only if not in context of update_all.
3996 * If in update_all, emit only if verbose flag is set.
3998 if (!bam_update_all
|| bam_verbose
)
3999 bam_print(NOT_ARCHIVE_BOOT
, root
);
4004 * If smf check is requested when / is writable (can happen
4005 * on first reboot following an upgrade because service
4006 * dependency is messed up), skip the check.
4008 if (bam_smf_check
&& !bam_root_readonly
&& !is_zfs(root
))
4009 return (BAM_SUCCESS
);
4012 * Don't generate archive on ramdisk.
4014 if (is_ramdisk(root
))
4015 return (BAM_SUCCESS
);
4018 * root must be writable. This check applies to alternate
4019 * root (-R option); bam_root_readonly applies to '/' only.
4020 * The behaviour translates into being the one of a 'check'.
4022 if (!bam_smf_check
&& !bam_check
&& is_readonly(root
)) {
4023 set_flag(RDONLY_FSCHK
);
4028 * Now check if an update is really needed.
4030 ret
= update_required(root
);
4033 * The check command (-n) is *not* a dry run.
4034 * It only checks if the archive is in sync.
4035 * A readonly filesystem has to be considered an error only if an update
4038 if (bam_nowrite()) {
4039 if (is_flag_on(RDONLY_FSCHK
)) {
4040 bam_check
= bam_saved_check
;
4042 bam_error(RDONLY_FS
, root
);
4044 return ((ret
!= 0) ? BAM_ERROR
: BAM_SUCCESS
);
4047 bam_exit((ret
!= 0) ? 1 : 0);
4051 /* create the ramdisk */
4052 ret
= create_ramdisk(root
);
4056 * if the archive is updated, save the new stat data and update the
4059 if (ret
== 0 && walk_arg
.new_nvlp
!= NULL
) {
4061 update_timestamp(root
);
4072 char *special
= get_special("/");
4075 if (special
== NULL
)
4078 if (*special
== '/') {
4083 if ((p
= strchr(special
, '/')) != NULL
)
4090 synchronize_BE_menu(void)
4093 char cmdline
[PATH_MAX
];
4094 char cksum_line
[PATH_MAX
];
4095 filelist_t flist
= {0};
4096 char *old_cksum_str
;
4099 char *curr_cksum_str
;
4100 char *curr_size_str
;
4108 const char *fcn
= "synchronize_BE_menu()";
4110 BAM_DPRINTF((D_FUNC_ENTRY0
, fcn
));
4112 /* Check if findroot enabled LU BE */
4113 if (stat(FINDROOT_INSTALLGRUB
, &sb
) != 0) {
4114 BAM_DPRINTF((D_NOT_LU_BE
, fcn
));
4115 return (BAM_SUCCESS
);
4118 if (stat(LU_MENU_CKSUM
, &sb
) != 0) {
4119 BAM_DPRINTF((D_NO_CKSUM_FILE
, fcn
, LU_MENU_CKSUM
));
4123 cfp
= fopen(LU_MENU_CKSUM
, "r");
4124 INJECT_ERROR1("CKSUM_FILE_MISSING", cfp
= NULL
);
4126 bam_error(CANNOT_READ_LU_CKSUM
, LU_MENU_CKSUM
);
4129 BAM_DPRINTF((D_CKSUM_FILE_OPENED
, fcn
, LU_MENU_CKSUM
));
4132 while (s_fgets(cksum_line
, sizeof (cksum_line
), cfp
) != NULL
) {
4133 INJECT_ERROR1("MULTIPLE_CKSUM", found
= 1);
4135 bam_error(MULTIPLE_LU_CKSUM
, LU_MENU_CKSUM
);
4141 BAM_DPRINTF((D_CKSUM_FILE_READ
, fcn
, LU_MENU_CKSUM
));
4144 old_cksum_str
= strtok(cksum_line
, " \t");
4145 old_size_str
= strtok(NULL
, " \t");
4146 old_file
= strtok(NULL
, " \t");
4148 INJECT_ERROR1("OLD_CKSUM_NULL", old_cksum_str
= NULL
);
4149 INJECT_ERROR1("OLD_SIZE_NULL", old_size_str
= NULL
);
4150 INJECT_ERROR1("OLD_FILE_NULL", old_file
= NULL
);
4151 if (old_cksum_str
== NULL
|| old_size_str
== NULL
|| old_file
== NULL
) {
4152 bam_error(CANNOT_PARSE_LU_CKSUM
, LU_MENU_CKSUM
);
4155 BAM_DPRINTF((D_CKSUM_FILE_PARSED
, fcn
, LU_MENU_CKSUM
));
4157 /* Get checksum of current menu */
4158 pool
= find_root_pool();
4160 mntpt
= mount_top_dataset(pool
, &mnted
);
4161 if (mntpt
== NULL
) {
4162 bam_error(FAIL_MNT_TOP_DATASET
, pool
);
4166 (void) snprintf(cmdline
, sizeof (cmdline
), "%s %s%s",
4167 CKSUM
, mntpt
, GRUB_MENU
);
4169 (void) snprintf(cmdline
, sizeof (cmdline
), "%s %s",
4172 ret
= exec_cmd(cmdline
, &flist
);
4174 (void) umount_top_dataset(pool
, mnted
, mntpt
);
4177 INJECT_ERROR1("GET_CURR_CKSUM", ret
= 1);
4179 bam_error(MENU_CKSUM_FAIL
);
4182 BAM_DPRINTF((D_CKSUM_GEN_SUCCESS
, fcn
));
4184 INJECT_ERROR1("GET_CURR_CKSUM_OUTPUT", flist
.head
= NULL
);
4185 if ((flist
.head
== NULL
) || (flist
.head
!= flist
.tail
)) {
4186 bam_error(BAD_CKSUM
);
4187 filelist_free(&flist
);
4190 BAM_DPRINTF((D_CKSUM_GEN_OUTPUT_VALID
, fcn
));
4192 curr_cksum_str
= strtok(flist
.head
->line
, " \t");
4193 curr_size_str
= strtok(NULL
, " \t");
4194 curr_file
= strtok(NULL
, " \t");
4196 INJECT_ERROR1("CURR_CKSUM_NULL", curr_cksum_str
= NULL
);
4197 INJECT_ERROR1("CURR_SIZE_NULL", curr_size_str
= NULL
);
4198 INJECT_ERROR1("CURR_FILE_NULL", curr_file
= NULL
);
4199 if (curr_cksum_str
== NULL
|| curr_size_str
== NULL
||
4200 curr_file
== NULL
) {
4201 bam_error(BAD_CKSUM_PARSE
);
4202 filelist_free(&flist
);
4205 BAM_DPRINTF((D_CKSUM_GEN_PARSED
, fcn
));
4207 if (strcmp(old_cksum_str
, curr_cksum_str
) == 0 &&
4208 strcmp(old_size_str
, curr_size_str
) == 0 &&
4209 strcmp(old_file
, curr_file
) == 0) {
4210 filelist_free(&flist
);
4211 BAM_DPRINTF((D_CKSUM_NO_CHANGE
, fcn
));
4212 return (BAM_SUCCESS
);
4215 filelist_free(&flist
);
4217 /* cksum doesn't match - the menu has changed */
4218 BAM_DPRINTF((D_CKSUM_HAS_CHANGED
, fcn
));
4221 bam_print(PROP_GRUB_MENU
);
4223 (void) snprintf(cmdline
, sizeof (cmdline
),
4224 "/bin/sh -c '. %s > /dev/null; %s %s yes > /dev/null'",
4225 LULIB
, LULIB_PROPAGATE_FILE
, GRUB_MENU
);
4226 ret
= exec_cmd(cmdline
, NULL
);
4227 INJECT_ERROR1("PROPAGATE_MENU", ret
= 1);
4229 bam_error(MENU_PROP_FAIL
);
4232 BAM_DPRINTF((D_PROPAGATED_MENU
, fcn
));
4234 (void) snprintf(cmdline
, sizeof (cmdline
), "/bin/cp %s %s > /dev/null",
4235 GRUB_MENU
, GRUB_BACKUP_MENU
);
4236 ret
= exec_cmd(cmdline
, NULL
);
4237 INJECT_ERROR1("CREATE_BACKUP", ret
= 1);
4239 bam_error(MENU_BACKUP_FAIL
, GRUB_BACKUP_MENU
);
4242 BAM_DPRINTF((D_CREATED_BACKUP
, fcn
, GRUB_BACKUP_MENU
));
4244 (void) snprintf(cmdline
, sizeof (cmdline
),
4245 "/bin/sh -c '. %s > /dev/null; %s %s no > /dev/null'",
4246 LULIB
, LULIB_PROPAGATE_FILE
, GRUB_BACKUP_MENU
);
4247 ret
= exec_cmd(cmdline
, NULL
);
4248 INJECT_ERROR1("PROPAGATE_BACKUP", ret
= 1);
4250 bam_error(BACKUP_PROP_FAIL
, GRUB_BACKUP_MENU
);
4253 BAM_DPRINTF((D_PROPAGATED_BACKUP
, fcn
, GRUB_BACKUP_MENU
));
4255 (void) snprintf(cmdline
, sizeof (cmdline
), "%s %s > %s",
4256 CKSUM
, GRUB_MENU
, LU_MENU_CKSUM
);
4257 ret
= exec_cmd(cmdline
, NULL
);
4258 INJECT_ERROR1("CREATE_CKSUM_FILE", ret
= 1);
4260 bam_error(MENU_CKSUM_WRITE_FAIL
, LU_MENU_CKSUM
);
4263 BAM_DPRINTF((D_CREATED_CKSUM_FILE
, fcn
, LU_MENU_CKSUM
));
4265 (void) snprintf(cmdline
, sizeof (cmdline
),
4266 "/bin/sh -c '. %s > /dev/null; %s %s no > /dev/null'",
4267 LULIB
, LULIB_PROPAGATE_FILE
, LU_MENU_CKSUM
);
4268 ret
= exec_cmd(cmdline
, NULL
);
4269 INJECT_ERROR1("PROPAGATE_MENU_CKSUM_FILE", ret
= 1);
4271 bam_error(MENU_CKSUM_PROP_FAIL
, LU_MENU_CKSUM
);
4274 BAM_DPRINTF((D_PROPAGATED_CKSUM_FILE
, fcn
, LU_MENU_CKSUM
));
4276 return (BAM_SUCCESS
);
4280 update_all(char *root
, char *opt
)
4282 struct extmnttab mnt
;
4285 char multibt
[PATH_MAX
];
4286 char creatram
[PATH_MAX
];
4287 error_t ret
= BAM_SUCCESS
;
4290 assert(opt
== NULL
);
4292 if (bam_rootlen
!= 1 || *root
!= '/') {
4293 elide_trailing_slash(root
, multibt
, sizeof (multibt
));
4294 bam_error(ALT_ROOT_INVALID
, multibt
);
4299 * First update archive for current root
4301 if (update_archive(root
, opt
) != BAM_SUCCESS
)
4304 if (ret
== BAM_ERROR
)
4308 * Now walk the mount table, performing archive update
4309 * for all mounted Newboot root filesystems
4311 fp
= fopen(MNTTAB
, "r");
4313 bam_error(OPEN_FAIL
, MNTTAB
, strerror(errno
));
4320 while (getextmntent(fp
, &mnt
, sizeof (mnt
)) == 0) {
4321 if (mnt
.mnt_special
== NULL
)
4323 if ((strcmp(mnt
.mnt_fstype
, MNTTYPE_ZFS
) != 0) &&
4324 (strncmp(mnt
.mnt_special
, "/dev/", strlen("/dev/")) != 0))
4326 if (strcmp(mnt
.mnt_mountp
, "/") == 0)
4329 (void) snprintf(creatram
, sizeof (creatram
), "%s/%s",
4330 mnt
.mnt_mountp
, CREATE_RAMDISK
);
4332 if (stat(creatram
, &sb
) == -1)
4336 * We put a trailing slash to be consistent with root = "/"
4337 * case, such that we don't have to print // in some cases.
4339 (void) snprintf(rootbuf
, sizeof (rootbuf
), "%s/",
4341 bam_rootlen
= strlen(rootbuf
);
4344 * It's possible that other mounts may be an alternate boot
4345 * architecture, so check it again.
4347 if ((get_boot_cap(rootbuf
) != BAM_SUCCESS
) ||
4348 (update_archive(rootbuf
, opt
) != BAM_SUCCESS
))
4356 * We no longer use biosdev for Live Upgrade. Hence
4357 * there is no need to defer (to shutdown time) any fdisk
4360 if (stat(GRUB_fdisk
, &sb
) == 0 || stat(GRUB_fdisk_target
, &sb
) == 0) {
4361 bam_error(FDISK_FILES_FOUND
, GRUB_fdisk
, GRUB_fdisk_target
);
4365 * If user has updated menu in current BE, propagate the
4366 * updates to all BEs.
4368 if (sync_menu
&& synchronize_BE_menu() != BAM_SUCCESS
)
4375 append_line(menu_t
*mp
, line_t
*lp
)
4377 if (mp
->start
== NULL
) {
4387 unlink_line(menu_t
*mp
, line_t
*lp
)
4389 /* unlink from list */
4391 lp
->prev
->next
= lp
->next
;
4393 mp
->start
= lp
->next
;
4395 lp
->next
->prev
= lp
->prev
;
4401 boot_entry_new(menu_t
*mp
, line_t
*start
, line_t
*end
)
4403 entry_t
*ent
, *prev
;
4404 const char *fcn
= "boot_entry_new()";
4410 ent
= s_calloc(1, sizeof (entry_t
));
4411 BAM_DPRINTF((D_ENTRY_NEW
, fcn
));
4415 if (mp
->entries
== NULL
) {
4417 BAM_DPRINTF((D_ENTRY_NEW_FIRST
, fcn
));
4426 BAM_DPRINTF((D_ENTRY_NEW_LINKED
, fcn
));
4431 boot_entry_addline(entry_t
*ent
, line_t
*lp
)
4438 * Check whether cmd matches the one indexed by which, and whether arg matches
4439 * str. which must be either KERNEL_CMD or MODULE_CMD, and a match to the
4440 * respective *_DOLLAR_CMD is also acceptable. The arg is searched using
4441 * strstr(), so it can be a partial match.
4444 check_cmd(const char *cmd
, const int which
, const char *arg
, const char *str
)
4447 const char *fcn
= "check_cmd()";
4449 BAM_DPRINTF((D_FUNC_ENTRY2
, fcn
, arg
, str
));
4452 if ((strcmp(cmd
, menu_cmds
[which
]) != 0) &&
4453 (strcmp(cmd
, menu_cmds
[which
+ 1]) != 0)) {
4454 BAM_DPRINTF((D_CHECK_CMD_CMD_NOMATCH
,
4455 fcn
, cmd
, menu_cmds
[which
]));
4458 ret
= (strstr(arg
, str
) != NULL
);
4463 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
4465 BAM_DPRINTF((D_RETURN_FAILURE
, fcn
));
4472 kernel_parser(entry_t
*entry
, char *cmd
, char *arg
, int linenum
)
4474 const char *fcn
= "kernel_parser()";
4480 if (strcmp(cmd
, menu_cmds
[KERNEL_CMD
]) != 0 &&
4481 strcmp(cmd
, menu_cmds
[KERNEL_DOLLAR_CMD
]) != 0) {
4482 BAM_DPRINTF((D_NOT_KERNEL_CMD
, fcn
, cmd
));
4486 if (strncmp(arg
, DIRECT_BOOT_32
, sizeof (DIRECT_BOOT_32
) - 1) == 0) {
4487 BAM_DPRINTF((D_SET_DBOOT_32
, fcn
, arg
));
4488 entry
->flags
|= BAM_ENTRY_DBOOT
| BAM_ENTRY_32BIT
;
4489 } else if (strncmp(arg
, DIRECT_BOOT_KERNEL
,
4490 sizeof (DIRECT_BOOT_KERNEL
) - 1) == 0) {
4491 BAM_DPRINTF((D_SET_DBOOT
, fcn
, arg
));
4492 entry
->flags
|= BAM_ENTRY_DBOOT
;
4493 } else if (strncmp(arg
, DIRECT_BOOT_64
,
4494 sizeof (DIRECT_BOOT_64
) - 1) == 0) {
4495 BAM_DPRINTF((D_SET_DBOOT_64
, fcn
, arg
));
4496 entry
->flags
|= BAM_ENTRY_DBOOT
| BAM_ENTRY_64BIT
;
4497 } else if (strncmp(arg
, DIRECT_BOOT_FAILSAFE_KERNEL
,
4498 sizeof (DIRECT_BOOT_FAILSAFE_KERNEL
) - 1) == 0) {
4499 BAM_DPRINTF((D_SET_DBOOT_FAILSAFE
, fcn
, arg
));
4500 entry
->flags
|= BAM_ENTRY_DBOOT
| BAM_ENTRY_FAILSAFE
;
4501 } else if (strncmp(arg
, DIRECT_BOOT_FAILSAFE_32
,
4502 sizeof (DIRECT_BOOT_FAILSAFE_32
) - 1) == 0) {
4503 BAM_DPRINTF((D_SET_DBOOT_FAILSAFE_32
, fcn
, arg
));
4504 entry
->flags
|= BAM_ENTRY_DBOOT
| BAM_ENTRY_FAILSAFE
4506 } else if (strncmp(arg
, DIRECT_BOOT_FAILSAFE_64
,
4507 sizeof (DIRECT_BOOT_FAILSAFE_64
) - 1) == 0) {
4508 BAM_DPRINTF((D_SET_DBOOT_FAILSAFE_64
, fcn
, arg
));
4509 entry
->flags
|= BAM_ENTRY_DBOOT
| BAM_ENTRY_FAILSAFE
4511 } else if (strncmp(arg
, MULTI_BOOT
, sizeof (MULTI_BOOT
) - 1) == 0) {
4512 BAM_DPRINTF((D_SET_MULTIBOOT
, fcn
, arg
));
4513 entry
->flags
|= BAM_ENTRY_MULTIBOOT
;
4514 } else if (strncmp(arg
, MULTI_BOOT_FAILSAFE
,
4515 sizeof (MULTI_BOOT_FAILSAFE
) - 1) == 0) {
4516 BAM_DPRINTF((D_SET_MULTIBOOT_FAILSAFE
, fcn
, arg
));
4517 entry
->flags
|= BAM_ENTRY_MULTIBOOT
| BAM_ENTRY_FAILSAFE
;
4518 } else if (strstr(arg
, XEN_KERNEL_SUBSTR
)) {
4519 BAM_DPRINTF((D_SET_HV
, fcn
, arg
));
4520 entry
->flags
|= BAM_ENTRY_HV
;
4521 } else if (!(entry
->flags
& (BAM_ENTRY_BOOTADM
|BAM_ENTRY_LU
))) {
4522 BAM_DPRINTF((D_SET_HAND_KERNEL
, fcn
, arg
));
4524 } else if (strncmp(arg
, KERNEL_PREFIX
, strlen(KERNEL_PREFIX
)) == 0 &&
4525 strstr(arg
, UNIX_SPACE
)) {
4526 entry
->flags
|= BAM_ENTRY_DBOOT
| BAM_ENTRY_32BIT
;
4527 } else if (strncmp(arg
, KERNEL_PREFIX
, strlen(KERNEL_PREFIX
)) == 0 &&
4528 strstr(arg
, AMD_UNIX_SPACE
)) {
4529 entry
->flags
|= BAM_ENTRY_DBOOT
| BAM_ENTRY_64BIT
;
4531 BAM_DPRINTF((D_IS_UNKNOWN_KERNEL
, fcn
, arg
));
4532 bam_error(UNKNOWN_KERNEL_LINE
, linenum
);
4536 return (BAM_SUCCESS
);
4540 module_parser(entry_t
*entry
, char *cmd
, char *arg
, int linenum
)
4542 const char *fcn
= "module_parser()";
4548 if (strcmp(cmd
, menu_cmds
[MODULE_CMD
]) != 0 &&
4549 strcmp(cmd
, menu_cmds
[MODULE_DOLLAR_CMD
]) != 0) {
4550 BAM_DPRINTF((D_NOT_MODULE_CMD
, fcn
, cmd
));
4554 if (strcmp(arg
, DIRECT_BOOT_ARCHIVE
) == 0 ||
4555 strcmp(arg
, DIRECT_BOOT_ARCHIVE_32
) == 0 ||
4556 strcmp(arg
, DIRECT_BOOT_ARCHIVE_64
) == 0 ||
4557 strcmp(arg
, MULTIBOOT_ARCHIVE
) == 0 ||
4558 strcmp(arg
, FAILSAFE_ARCHIVE
) == 0 ||
4559 strcmp(arg
, FAILSAFE_ARCHIVE_32
) == 0 ||
4560 strcmp(arg
, FAILSAFE_ARCHIVE_64
) == 0 ||
4561 strcmp(arg
, XEN_KERNEL_MODULE_LINE
) == 0 ||
4562 strcmp(arg
, XEN_KERNEL_MODULE_LINE_ZFS
) == 0) {
4563 BAM_DPRINTF((D_BOOTADM_LU_MODULE
, fcn
, arg
));
4564 return (BAM_SUCCESS
);
4565 } else if (!(entry
->flags
& BAM_ENTRY_BOOTADM
) &&
4566 !(entry
->flags
& BAM_ENTRY_LU
)) {
4567 /* don't emit warning for hand entries */
4568 BAM_DPRINTF((D_IS_HAND_MODULE
, fcn
, arg
));
4571 BAM_DPRINTF((D_IS_UNKNOWN_MODULE
, fcn
, arg
));
4572 bam_error(UNKNOWN_MODULE_LINE
, linenum
);
4578 * A line in menu.lst looks like
4579 * [ ]*<cmd>[ \t=]*<arg>*
4582 line_parser(menu_t
*mp
, char *str
, int *lineNum
, int *entryNum
)
4585 * save state across calls. This is so that
4586 * header gets the right entry# after title has
4589 static line_t
*prev
= NULL
;
4590 static entry_t
*curr_ent
= NULL
;
4591 static int in_liveupgrade
= 0;
4592 static int is_libbe_ent
= 0;
4595 char *cmd
, *sep
, *arg
;
4596 char save
, *cp
, *line
;
4597 menu_flag_t flag
= BAM_INVALID
;
4598 const char *fcn
= "line_parser()";
4605 * First save a copy of the entire line.
4606 * We use this later to set the line field.
4608 line
= s_strdup(str
);
4610 /* Eat up leading whitespace */
4611 while (*str
== ' ' || *str
== '\t')
4614 if (*str
== '#') { /* comment */
4615 cmd
= s_strdup("#");
4617 arg
= s_strdup(str
+ 1);
4619 if (strstr(arg
, BAM_LU_HDR
) != NULL
) {
4621 } else if (strstr(arg
, BAM_LU_FTR
) != NULL
) {
4623 } else if (strstr(arg
, BAM_LIBBE_FTR
) != NULL
) {
4626 } else if (*str
== '\0') { /* blank line */
4627 cmd
= sep
= arg
= NULL
;
4631 * '=' is not a documented separator in grub syntax.
4632 * However various development bits use '=' as a
4633 * separator. In addition, external users also
4634 * use = as a separator. So we will allow that usage.
4637 while (*str
!= ' ' && *str
!= '\t' && *str
!= '=') {
4655 sep
= s_strdup(str
- 1);
4658 while (*str
== ' ' || *str
== '\t')
4663 arg
= s_strdup(str
);
4667 lp
= s_calloc(1, sizeof (line_t
));
4673 lp
->lineNum
= ++(*lineNum
);
4674 if (cmd
&& strcmp(cmd
, menu_cmds
[TITLE_CMD
]) == 0) {
4675 lp
->entryNum
= ++(*entryNum
);
4676 lp
->flags
= BAM_TITLE
;
4677 if (prev
&& prev
->flags
== BAM_COMMENT
&&
4678 prev
->arg
&& strcmp(prev
->arg
, BAM_BOOTADM_HDR
) == 0) {
4679 prev
->entryNum
= lp
->entryNum
;
4680 curr_ent
= boot_entry_new(mp
, prev
, lp
);
4681 curr_ent
->flags
|= BAM_ENTRY_BOOTADM
;
4682 BAM_DPRINTF((D_IS_BOOTADM_ENTRY
, fcn
, arg
));
4684 curr_ent
= boot_entry_new(mp
, lp
, lp
);
4685 if (in_liveupgrade
) {
4686 curr_ent
->flags
|= BAM_ENTRY_LU
;
4687 BAM_DPRINTF((D_IS_LU_ENTRY
, fcn
, arg
));
4690 curr_ent
->entryNum
= *entryNum
;
4691 } else if (flag
!= BAM_INVALID
) {
4693 * For header comments, the entry# is "fixed up"
4694 * by the subsequent title
4696 lp
->entryNum
= *entryNum
;
4699 lp
->entryNum
= *entryNum
;
4701 if (*entryNum
== ENTRY_INIT
) {
4702 lp
->flags
= BAM_GLOBAL
;
4704 lp
->flags
= BAM_ENTRY
;
4707 if (strcmp(cmd
, menu_cmds
[ROOT_CMD
]) == 0) {
4708 BAM_DPRINTF((D_IS_ROOT_CMD
, fcn
, arg
));
4709 curr_ent
->flags
|= BAM_ENTRY_ROOT
;
4710 } else if (strcmp(cmd
, menu_cmds
[FINDROOT_CMD
])
4712 BAM_DPRINTF((D_IS_FINDROOT_CMD
, fcn
,
4714 curr_ent
->flags
|= BAM_ENTRY_FINDROOT
;
4715 } else if (strcmp(cmd
,
4716 menu_cmds
[CHAINLOADER_CMD
]) == 0) {
4717 BAM_DPRINTF((D_IS_CHAINLOADER_CMD
, fcn
,
4720 BAM_ENTRY_CHAINLOADER
;
4721 } else if (kernel_parser(curr_ent
, cmd
, arg
,
4722 lp
->lineNum
) != BAM_SUCCESS
) {
4723 (void) module_parser(curr_ent
, cmd
,
4730 /* record default, old default, and entry line ranges */
4731 if (lp
->flags
== BAM_GLOBAL
&& lp
->cmd
!= NULL
&&
4732 strcmp(lp
->cmd
, menu_cmds
[DEFAULT_CMD
]) == 0) {
4733 mp
->curdefault
= lp
;
4734 } else if (lp
->flags
== BAM_COMMENT
&&
4735 strncmp(lp
->arg
, BAM_OLDDEF
, strlen(BAM_OLDDEF
)) == 0) {
4736 mp
->olddefault
= lp
;
4737 } else if (lp
->flags
== BAM_COMMENT
&&
4738 strncmp(lp
->arg
, BAM_OLD_RC_DEF
, strlen(BAM_OLD_RC_DEF
)) == 0) {
4739 mp
->old_rc_default
= lp
;
4740 } else if (lp
->flags
== BAM_ENTRY
||
4741 (lp
->flags
== BAM_COMMENT
&&
4742 ((strcmp(lp
->arg
, BAM_BOOTADM_FTR
) == 0) || is_libbe_ent
))) {
4744 curr_ent
->flags
|= BAM_ENTRY_LIBBE
;
4748 boot_entry_addline(curr_ent
, lp
);
4750 append_line(mp
, lp
);
4756 update_numbering(menu_t
*mp
)
4760 int old_default_value
;
4761 line_t
*lp
, *prev
, *default_lp
, *default_entry
;
4764 if (mp
->start
== NULL
) {
4768 lineNum
= LINE_INIT
;
4769 entryNum
= ENTRY_INIT
;
4770 old_default_value
= ENTRY_INIT
;
4771 lp
= default_lp
= default_entry
= NULL
;
4774 for (lp
= mp
->start
; lp
; prev
= lp
, lp
= lp
->next
) {
4775 lp
->lineNum
= ++lineNum
;
4778 * Get the value of the default command
4780 if (lp
->entryNum
== ENTRY_INIT
&& lp
->cmd
!= NULL
&&
4781 strcmp(lp
->cmd
, menu_cmds
[DEFAULT_CMD
]) == 0 &&
4783 old_default_value
= atoi(lp
->arg
);
4788 * If not a booting entry, nothing else to fix for this
4791 if (lp
->entryNum
== ENTRY_INIT
)
4795 * Record the position of the default entry.
4796 * The following works because global
4797 * commands like default and timeout should precede
4798 * actual boot entries, so old_default_value
4799 * is already known (or default cmd is missing).
4801 if (default_entry
== NULL
&&
4802 old_default_value
!= ENTRY_INIT
&&
4803 lp
->entryNum
== old_default_value
) {
4808 * Now fixup the entry number
4810 if (lp
->cmd
!= NULL
&&
4811 strcmp(lp
->cmd
, menu_cmds
[TITLE_CMD
]) == 0) {
4812 lp
->entryNum
= ++entryNum
;
4813 /* fixup the bootadm header */
4814 if (prev
&& prev
->flags
== BAM_COMMENT
&&
4816 strcmp(prev
->arg
, BAM_BOOTADM_HDR
) == 0) {
4817 prev
->entryNum
= lp
->entryNum
;
4820 lp
->entryNum
= entryNum
;
4825 * No default command in menu, simply return
4827 if (default_lp
== NULL
) {
4831 free(default_lp
->arg
);
4832 free(default_lp
->line
);
4834 if (default_entry
== NULL
) {
4835 default_lp
->arg
= s_strdup("0");
4837 (void) snprintf(buf
, sizeof (buf
), "%d",
4838 default_entry
->entryNum
);
4839 default_lp
->arg
= s_strdup(buf
);
4843 * The following is required since only the line field gets
4844 * written back to menu.lst
4846 (void) snprintf(buf
, sizeof (buf
), "%s%s%s",
4847 menu_cmds
[DEFAULT_CMD
], menu_cmds
[SEP_CMD
], default_lp
->arg
);
4848 default_lp
->line
= s_strdup(buf
);
4853 menu_read(char *menu_path
)
4856 char buf
[BAM_MAXLINE
], *cp
;
4858 int line
, entry
, len
, n
;
4860 mp
= s_calloc(1, sizeof (menu_t
));
4862 fp
= fopen(menu_path
, "r");
4863 if (fp
== NULL
) { /* Let the caller handle this error */
4868 /* Note: GRUB boot entry number starts with 0 */
4873 while (s_fgets(cp
, len
, fp
) != NULL
) {
4875 if (cp
[n
- 1] == '\\') {
4881 line_parser(mp
, buf
, &line
, &entry
);
4886 if (fclose(fp
) == EOF
) {
4887 bam_error(CLOSE_FAIL
, menu_path
, strerror(errno
));
4894 selector(menu_t
*mp
, char *opt
, int *entry
, char **title
)
4904 opt_dup
= s_strdup(opt
);
4907 *entry
= ENTRY_INIT
;
4911 eq
= strchr(opt_dup
, '=');
4913 bam_error(INVALID_OPT
, opt
);
4919 if (entry
&& strcmp(opt_dup
, OPT_ENTRY_NUM
) == 0) {
4921 entryNum
= s_strtol(eq
+ 1);
4922 if (entryNum
< 0 || entryNum
> mp
->end
->entryNum
) {
4923 bam_error(INVALID_ENTRY
, eq
+ 1);
4928 } else if (title
&& strcmp(opt_dup
, menu_cmds
[TITLE_CMD
]) == 0) {
4929 *title
= opt
+ (eq
- opt_dup
) + 1;
4931 bam_error(INVALID_OPT
, opt
);
4937 return (BAM_SUCCESS
);
4941 * If invoked with no titles/entries (opt == NULL)
4942 * only title lines in file are printed.
4944 * If invoked with a title or entry #, all
4945 * lines in *every* matching entry are listed
4948 list_entry(menu_t
*mp
, char *menu_path
, char *opt
)
4951 int entry
= ENTRY_INIT
;
4958 /* opt is optional */
4959 BAM_DPRINTF((D_FUNC_ENTRY2
, "list_entry", menu_path
,
4960 opt
? opt
: "<NULL>"));
4962 if (mp
->start
== NULL
) {
4963 bam_error(NO_MENU
, menu_path
);
4968 if (selector(mp
, opt
, &entry
, &title
) != BAM_SUCCESS
) {
4971 assert((entry
!= ENTRY_INIT
) ^ (title
!= NULL
));
4973 (void) read_globals(mp
, menu_path
, menu_cmds
[DEFAULT_CMD
], 0);
4974 (void) read_globals(mp
, menu_path
, menu_cmds
[TIMEOUT_CMD
], 0);
4978 for (lp
= mp
->start
; lp
; lp
= lp
->next
) {
4979 if (lp
->flags
== BAM_COMMENT
|| lp
->flags
== BAM_EMPTY
)
4981 if (opt
== NULL
&& lp
->flags
== BAM_TITLE
) {
4982 bam_print(PRINT_TITLE
, lp
->entryNum
,
4987 if (entry
!= ENTRY_INIT
&& lp
->entryNum
== entry
) {
4988 bam_print(PRINT
, lp
->line
);
4994 * We set the entry value here so that all lines
4995 * in entry get printed. If we subsequently match
4996 * title in other entries, all lines in those
4997 * entries get printed as well.
4999 if (title
&& lp
->flags
== BAM_TITLE
&& lp
->arg
&&
5000 strncmp(title
, lp
->arg
, strlen(title
)) == 0) {
5001 bam_print(PRINT
, lp
->line
);
5002 entry
= lp
->entryNum
;
5009 bam_error(NO_MATCH_ENTRY
);
5013 return (BAM_SUCCESS
);
5017 add_boot_entry(menu_t
*mp
,
5027 char linebuf
[BAM_MAXLINE
];
5030 const char *fcn
= "add_boot_entry()";
5034 INJECT_ERROR1("ADD_BOOT_ENTRY_FINDROOT_NULL", findroot
= NULL
);
5035 if (findroot
== NULL
) {
5036 bam_error(NULL_FINDROOT
);
5040 if (title
== NULL
) {
5041 title
= "Solaris"; /* default to Solaris */
5043 if (kernel
== NULL
) {
5044 bam_error(SUBOPT_MISS
, menu_cmds
[KERNEL_CMD
]);
5047 if (module
== NULL
) {
5048 if (bam_direct
!= BAM_DIRECT_DBOOT
) {
5049 bam_error(SUBOPT_MISS
, menu_cmds
[MODULE_CMD
]);
5053 /* Figure the commands out from the kernel line */
5054 if (strstr(kernel
, "$ISADIR") != NULL
) {
5055 module
= DIRECT_BOOT_ARCHIVE
;
5056 } else if (strstr(kernel
, "amd64") != NULL
) {
5057 module
= DIRECT_BOOT_ARCHIVE_64
;
5059 module
= DIRECT_BOOT_ARCHIVE_32
;
5063 k_cmd
= KERNEL_DOLLAR_CMD
;
5064 m_cmd
= MODULE_DOLLAR_CMD
;
5067 lineNum
= mp
->end
->lineNum
;
5068 entryNum
= mp
->end
->entryNum
;
5070 lineNum
= LINE_INIT
;
5071 entryNum
= ENTRY_INIT
;
5075 * No separator for comment (HDR/FTR) commands
5076 * The syntax for comments is #<comment>
5078 (void) snprintf(linebuf
, sizeof (linebuf
), "%s%s",
5079 menu_cmds
[COMMENT_CMD
], BAM_BOOTADM_HDR
);
5080 line_parser(mp
, linebuf
, &lineNum
, &entryNum
);
5082 (void) snprintf(linebuf
, sizeof (linebuf
), "%s%s%s",
5083 menu_cmds
[TITLE_CMD
], menu_cmds
[SEP_CMD
], title
);
5084 line_parser(mp
, linebuf
, &lineNum
, &entryNum
);
5086 (void) snprintf(linebuf
, sizeof (linebuf
), "%s%s%s",
5087 menu_cmds
[FINDROOT_CMD
], menu_cmds
[SEP_CMD
], findroot
);
5088 line_parser(mp
, linebuf
, &lineNum
, &entryNum
);
5089 BAM_DPRINTF((D_ADD_FINDROOT_NUM
, fcn
, lineNum
, entryNum
));
5091 if (bootfs
!= NULL
) {
5092 (void) snprintf(linebuf
, sizeof (linebuf
), "%s%s%s",
5093 menu_cmds
[BOOTFS_CMD
], menu_cmds
[SEP_CMD
], bootfs
);
5094 line_parser(mp
, linebuf
, &lineNum
, &entryNum
);
5097 (void) snprintf(linebuf
, sizeof (linebuf
), "%s%s%s",
5098 menu_cmds
[k_cmd
], menu_cmds
[SEP_CMD
], kernel
);
5099 line_parser(mp
, linebuf
, &lineNum
, &entryNum
);
5101 if (mod_kernel
!= NULL
) {
5102 (void) snprintf(linebuf
, sizeof (linebuf
), "%s%s%s",
5103 menu_cmds
[m_cmd
], menu_cmds
[SEP_CMD
], mod_kernel
);
5104 line_parser(mp
, linebuf
, &lineNum
, &entryNum
);
5107 (void) snprintf(linebuf
, sizeof (linebuf
), "%s%s%s",
5108 menu_cmds
[m_cmd
], menu_cmds
[SEP_CMD
], module
);
5109 line_parser(mp
, linebuf
, &lineNum
, &entryNum
);
5111 (void) snprintf(linebuf
, sizeof (linebuf
), "%s%s",
5112 menu_cmds
[COMMENT_CMD
], BAM_BOOTADM_FTR
);
5113 line_parser(mp
, linebuf
, &lineNum
, &entryNum
);
5119 delete_boot_entry(menu_t
*mp
, int entryNum
, int quiet
)
5126 const char *fcn
= "delete_boot_entry()";
5128 assert(entryNum
!= ENTRY_INIT
);
5137 * Check entry number and make sure it's a modifiable entry.
5140 * + We can modify a bootadm-created entry
5141 * + We can modify a libbe-created entry
5143 if ((lp
->flags
!= BAM_COMMENT
&&
5144 (((ent
->flags
& BAM_ENTRY_LIBBE
) == 0) &&
5145 strcmp(lp
->arg
, BAM_BOOTADM_HDR
) != 0)) ||
5146 (entryNum
!= ALL_ENTRIES
&& lp
->entryNum
!= entryNum
)) {
5151 /* free the entry content */
5154 lp
= lp
->next
; /* prev stays the same */
5155 BAM_DPRINTF((D_FREEING_LINE
, fcn
, freed
->lineNum
));
5156 unlink_line(mp
, freed
);
5158 } while (freed
!= ent
->end
);
5160 /* free the entry_t structure */
5161 assert(tmp
== NULL
);
5165 tmp
->prev
->next
= ent
;
5169 ent
->prev
= tmp
->prev
;
5170 BAM_DPRINTF((D_FREEING_ENTRY
, fcn
, tmp
->entryNum
));
5176 assert(tmp
== NULL
);
5178 if (!deleted
&& entryNum
!= ALL_ENTRIES
) {
5179 if (quiet
== DBE_PRINTERR
)
5180 bam_error(NO_BOOTADM_MATCH
);
5185 * Now that we have deleted an entry, update
5186 * the entry numbering and the default cmd.
5188 update_numbering(mp
);
5190 return (BAM_SUCCESS
);
5194 delete_all_entries(menu_t
*mp
, char *dummy
, char *opt
)
5197 assert(dummy
== NULL
);
5198 assert(opt
== NULL
);
5200 BAM_DPRINTF((D_FUNC_ENTRY0
, "delete_all_entries"));
5202 if (mp
->start
== NULL
) {
5203 bam_print(EMPTY_MENU
);
5204 return (BAM_SUCCESS
);
5207 if (delete_boot_entry(mp
, ALL_ENTRIES
, DBE_PRINTERR
) != BAM_SUCCESS
) {
5215 create_diskmap(char *osroot
)
5218 char cmd
[PATH_MAX
+ 16];
5219 char path
[PATH_MAX
];
5220 const char *fcn
= "create_diskmap()";
5222 /* make sure we have a map file */
5223 fp
= fopen(GRUBDISK_MAP
, "r");
5227 ret
= snprintf(path
, sizeof (path
), "%s/%s", osroot
,
5229 if (ret
>= sizeof (path
)) {
5230 bam_error(PATH_TOO_LONG
, osroot
);
5233 if (is_safe_exec(path
) == BAM_ERROR
)
5236 (void) snprintf(cmd
, sizeof (cmd
),
5237 "%s/%s > /dev/null", osroot
, CREATE_DISKMAP
);
5238 if (exec_cmd(cmd
, NULL
) != 0)
5240 fp
= fopen(GRUBDISK_MAP
, "r");
5241 INJECT_ERROR1("DISKMAP_CREATE_FAIL", fp
= NULL
);
5243 BAM_DPRINTF((D_CREATED_DISKMAP
, fcn
, GRUBDISK_MAP
));
5245 BAM_DPRINTF((D_CREATE_DISKMAP_FAIL
, fcn
, GRUBDISK_MAP
));
5251 #define SECTOR_SIZE 512
5254 get_partition(char *device
)
5256 int i
, fd
, is_pcfs
, partno
= PARTNO_NOTFOUND
;
5257 struct mboot
*mboot
;
5258 char boot_sect
[SECTOR_SIZE
];
5259 char *wholedisk
, *slice
;
5262 uint32_t secnum
, numsec
;
5263 int rval
, pno
, ext_partno
= PARTNO_NOTFOUND
;
5266 /* form whole disk (p0) */
5267 slice
= device
+ strlen(device
) - 2;
5268 is_pcfs
= (*slice
!= 's');
5271 wholedisk
= s_calloc(1, strlen(device
) + 3);
5272 (void) snprintf(wholedisk
, strlen(device
) + 3, "%sp0", device
);
5276 /* read boot sector */
5277 fd
= open(wholedisk
, O_RDONLY
);
5278 if (fd
== -1 || read(fd
, boot_sect
, SECTOR_SIZE
) != SECTOR_SIZE
) {
5284 /* Read/Initialize extended partition information */
5285 if ((rval
= libfdisk_init(&epp
, wholedisk
, NULL
, FDISK_READ_DISK
))
5289 * FDISK_EBADLOGDRIVE and FDISK_ENOLOGDRIVE can
5290 * be considered as soft errors and hence
5293 case FDISK_EBADLOGDRIVE
:
5295 case FDISK_ENOLOGDRIVE
:
5297 case FDISK_EBADMAGIC
:
5301 libfdisk_fini(&epp
);
5308 /* parse fdisk table */
5309 mboot
= (struct mboot
*)((void *)boot_sect
);
5310 for (i
= 0; i
< FD_NUMPART
; i
++) {
5311 struct ipart
*part
=
5312 (struct ipart
*)(uintptr_t)mboot
->parts
+ i
;
5313 if (is_pcfs
) { /* looking for solaris boot part */
5314 if (part
->systid
== 0xbe) {
5318 } else { /* look for solaris partition, old and new */
5319 if (part
->systid
== EFI_PMBR
) {
5320 partno
= PARTNO_EFI
;
5325 if ((part
->systid
== SUNIXOS
&&
5326 (fdisk_is_linux_swap(epp
, part
->relsect
,
5327 NULL
) != 0)) || part
->systid
== SUNIXOS2
) {
5329 if (part
->systid
== SUNIXOS
||
5330 part
->systid
== SUNIXOS2
) {
5337 if (fdisk_is_dos_extended(part
->systid
))
5343 /* If no primary solaris partition, check extended partition */
5344 if ((partno
== PARTNO_NOTFOUND
) && (ext_partno
!= PARTNO_NOTFOUND
)) {
5345 rval
= fdisk_get_solaris_part(epp
, &pno
, &secnum
, &numsec
);
5346 if (rval
== FDISK_SUCCESS
) {
5350 libfdisk_fini(&epp
);
5356 get_grubroot(char *osroot
, char *osdev
, char *menu_root
)
5358 char *grubroot
; /* (hd#,#,#) */
5364 char *ctdname
= strstr(osdev
, "dsk/");
5365 char linebuf
[PATH_MAX
];
5368 INJECT_ERROR1("GRUBROOT_INVALID_OSDEV", ctdname
= NULL
);
5369 if (ctdname
== NULL
) {
5370 bam_error(INVALID_DEV_DSK
, osdev
);
5374 if (menu_root
&& !menu_on_bootdisk(osroot
, menu_root
)) {
5375 /* menu bears no resemblance to our reality */
5376 bam_error(CANNOT_GRUBROOT_BOOTDISK
, osdev
);
5380 ctdname
+= strlen("dsk/");
5381 slice
= strrchr(ctdname
, 's');
5385 fp
= create_diskmap(osroot
);
5387 bam_error(DISKMAP_FAIL
, osroot
);
5392 while (s_fgets(linebuf
, sizeof (linebuf
), fp
) != NULL
) {
5393 grubhd
= strtok(linebuf
, " \t\n");
5395 devname
= strtok(NULL
, " \t\n");
5398 if (devname
&& strcmp(devname
, ctdname
) == 0) {
5410 INJECT_ERROR1("GRUBROOT_BIOSDEV_FAIL", found
= 0);
5412 bam_error(BIOSDEV_SKIP
, osdev
);
5416 fdiskpart
= get_partition(osdev
);
5417 INJECT_ERROR1("GRUBROOT_FDISK_FAIL", fdiskpart
= PARTNO_NOTFOUND
);
5418 if (fdiskpart
== PARTNO_NOTFOUND
) {
5419 bam_error(FDISKPART_FAIL
, osdev
);
5423 grubroot
= s_calloc(1, 10);
5424 if (fdiskpart
== PARTNO_EFI
) {
5425 fdiskpart
= atoi(&slice
[1]);
5430 (void) snprintf(grubroot
, 10, "(hd%s,%d,%c)",
5431 grubhd
, fdiskpart
, slice
[1] + 'a' - '0');
5433 (void) snprintf(grubroot
, 10, "(hd%s,%d)",
5437 assert(strncmp(grubroot
, "(hd", strlen("(hd")) == 0);
5442 find_primary_common(char *mntpt
, char *fstype
)
5444 char signdir
[PATH_MAX
];
5445 char tmpsign
[MAXNAMELEN
+ 1];
5450 struct dirent
*entp
;
5452 const char *fcn
= "find_primary_common()";
5454 (void) snprintf(signdir
, sizeof (signdir
), "%s/%s",
5455 mntpt
, GRUBSIGN_DIR
);
5457 if (stat(signdir
, &sb
) == -1) {
5458 BAM_DPRINTF((D_NO_SIGNDIR
, fcn
, signdir
));
5462 dirp
= opendir(signdir
);
5463 INJECT_ERROR1("SIGNDIR_OPENDIR_FAIL", dirp
= NULL
);
5465 bam_error(OPENDIR_FAILED
, signdir
, strerror(errno
));
5469 ufs
= zfs
= lu
= NULL
;
5471 while (entp
= readdir(dirp
)) {
5472 if (strcmp(entp
->d_name
, ".") == 0 ||
5473 strcmp(entp
->d_name
, "..") == 0)
5476 (void) snprintf(tmpsign
, sizeof (tmpsign
), "%s", entp
->d_name
);
5479 strncmp(tmpsign
, GRUBSIGN_LU_PREFIX
,
5480 strlen(GRUBSIGN_LU_PREFIX
)) == 0) {
5481 lu
= s_strdup(tmpsign
);
5485 strncmp(tmpsign
, GRUBSIGN_UFS_PREFIX
,
5486 strlen(GRUBSIGN_UFS_PREFIX
)) == 0) {
5487 ufs
= s_strdup(tmpsign
);
5491 strncmp(tmpsign
, GRUBSIGN_ZFS_PREFIX
,
5492 strlen(GRUBSIGN_ZFS_PREFIX
)) == 0) {
5493 zfs
= s_strdup(tmpsign
);
5497 BAM_DPRINTF((D_EXIST_PRIMARY_SIGNS
, fcn
,
5503 (void) closedir(dirp
);
5507 if (strcmp(fstype
, "ufs") == 0 && zfs
) {
5508 bam_error(SIGN_FSTYPE_MISMATCH
, zfs
, "ufs");
5511 } else if (strcmp(fstype
, "zfs") == 0 && ufs
) {
5512 bam_error(SIGN_FSTYPE_MISMATCH
, ufs
, "zfs");
5517 assert(dirp
== NULL
);
5519 /* For now, we let Live Upgrade take care of its signature itself */
5521 BAM_DPRINTF((D_FREEING_LU_SIGNS
, fcn
, lu
));
5526 return (zfs
? zfs
: ufs
);
5530 find_backup_common(char *mntpt
, char *fstype
)
5533 char tmpsign
[MAXNAMELEN
+ 1];
5534 char backup
[PATH_MAX
];
5539 const char *fcn
= "find_backup_common()";
5542 * We didn't find it in the primary directory.
5543 * Look at the backup
5545 (void) snprintf(backup
, sizeof (backup
), "%s%s",
5546 mntpt
, GRUBSIGN_BACKUP
);
5548 bfp
= fopen(backup
, "r");
5552 bam_error(OPEN_FAIL
, backup
, strerror(error
));
5554 BAM_DPRINTF((D_OPEN_FAIL
, fcn
, backup
, strerror(error
)));
5558 ufs
= zfs
= lu
= NULL
;
5560 while (s_fgets(tmpsign
, sizeof (tmpsign
), bfp
) != NULL
) {
5563 strncmp(tmpsign
, GRUBSIGN_LU_PREFIX
,
5564 strlen(GRUBSIGN_LU_PREFIX
)) == 0) {
5565 lu
= s_strdup(tmpsign
);
5569 strncmp(tmpsign
, GRUBSIGN_UFS_PREFIX
,
5570 strlen(GRUBSIGN_UFS_PREFIX
)) == 0) {
5571 ufs
= s_strdup(tmpsign
);
5575 strncmp(tmpsign
, GRUBSIGN_ZFS_PREFIX
,
5576 strlen(GRUBSIGN_ZFS_PREFIX
)) == 0) {
5577 zfs
= s_strdup(tmpsign
);
5581 BAM_DPRINTF((D_EXIST_BACKUP_SIGNS
, fcn
,
5591 if (strcmp(fstype
, "ufs") == 0 && zfs
) {
5592 bam_error(SIGN_FSTYPE_MISMATCH
, zfs
, "ufs");
5595 } else if (strcmp(fstype
, "zfs") == 0 && ufs
) {
5596 bam_error(SIGN_FSTYPE_MISMATCH
, ufs
, "zfs");
5601 assert(bfp
== NULL
);
5603 /* For now, we let Live Upgrade take care of its signature itself */
5605 BAM_DPRINTF((D_FREEING_LU_SIGNS
, fcn
, lu
));
5610 return (zfs
? zfs
: ufs
);
5614 find_ufs_existing(char *osroot
)
5617 const char *fcn
= "find_ufs_existing()";
5619 sign
= find_primary_common(osroot
, "ufs");
5621 sign
= find_backup_common(osroot
, "ufs");
5622 BAM_DPRINTF((D_EXIST_BACKUP_SIGN
, fcn
, sign
? sign
: "NULL"));
5624 BAM_DPRINTF((D_EXIST_PRIMARY_SIGN
, fcn
, sign
));
5631 get_mountpoint(char *special
, char *fstype
)
5634 struct mnttab mp
= {0};
5635 struct mnttab mpref
= {0};
5638 const char *fcn
= "get_mountpoint()";
5640 BAM_DPRINTF((D_FUNC_ENTRY2
, fcn
, special
, fstype
));
5642 mntfp
= fopen(MNTTAB
, "r");
5644 INJECT_ERROR1("MNTTAB_ERR_GET_MNTPT", mntfp
= NULL
);
5645 if (mntfp
== NULL
) {
5646 bam_error(OPEN_FAIL
, MNTTAB
, strerror(error
));
5650 mpref
.mnt_special
= special
;
5651 mpref
.mnt_fstype
= fstype
;
5653 ret
= getmntany(mntfp
, &mp
, &mpref
);
5654 INJECT_ERROR1("GET_MOUNTPOINT_MNTANY", ret
= 1);
5656 (void) fclose(mntfp
);
5657 BAM_DPRINTF((D_NO_MNTPT
, fcn
, special
, fstype
));
5660 (void) fclose(mntfp
);
5662 assert(mp
.mnt_mountp
);
5664 BAM_DPRINTF((D_GET_MOUNTPOINT_RET
, fcn
, special
, mp
.mnt_mountp
));
5666 return (s_strdup(mp
.mnt_mountp
));
5670 * Mounts a "legacy" top dataset (if needed)
5671 * Returns: The mountpoint of the legacy top dataset or NULL on error
5672 * mnted returns one of the above values defined for zfs_mnted_t
5675 mount_legacy_dataset(char *pool
, zfs_mnted_t
*mnted
)
5678 char tmpmnt
[PATH_MAX
];
5679 filelist_t flist
= {0};
5683 const char *fcn
= "mount_legacy_dataset()";
5685 BAM_DPRINTF((D_FUNC_ENTRY1
, fcn
, pool
));
5687 *mnted
= ZFS_MNT_ERROR
;
5689 (void) snprintf(cmd
, sizeof (cmd
),
5690 "/sbin/zfs get -Ho value mounted %s",
5693 ret
= exec_cmd(cmd
, &flist
);
5694 INJECT_ERROR1("Z_MOUNT_LEG_GET_MOUNTED_CMD", ret
= 1);
5696 bam_error(ZFS_MNTED_FAILED
, pool
);
5700 INJECT_ERROR1("Z_MOUNT_LEG_GET_MOUNTED_OUT", flist
.head
= NULL
);
5701 if ((flist
.head
== NULL
) || (flist
.head
!= flist
.tail
)) {
5702 bam_error(BAD_ZFS_MNTED
, pool
);
5703 filelist_free(&flist
);
5707 is_mounted
= strtok(flist
.head
->line
, " \t\n");
5708 INJECT_ERROR1("Z_MOUNT_LEG_GET_MOUNTED_STRTOK_YES", is_mounted
= "yes");
5709 INJECT_ERROR1("Z_MOUNT_LEG_GET_MOUNTED_STRTOK_NO", is_mounted
= "no");
5710 if (strcmp(is_mounted
, "no") != 0) {
5711 filelist_free(&flist
);
5712 *mnted
= LEGACY_ALREADY
;
5713 /* get_mountpoint returns a strdup'ed string */
5714 BAM_DPRINTF((D_Z_MOUNT_TOP_LEG_ALREADY
, fcn
, pool
));
5715 return (get_mountpoint(pool
, "zfs"));
5718 filelist_free(&flist
);
5721 * legacy top dataset is not mounted. Mount it now
5722 * First create a mountpoint.
5724 (void) snprintf(tmpmnt
, sizeof (tmpmnt
), "%s.%d",
5725 ZFS_LEGACY_MNTPT
, getpid());
5727 ret
= stat(tmpmnt
, &sb
);
5729 BAM_DPRINTF((D_Z_MOUNT_TOP_LEG_MNTPT_ABS
, fcn
, pool
, tmpmnt
));
5730 ret
= mkdirp(tmpmnt
, DIR_PERMS
);
5731 INJECT_ERROR1("Z_MOUNT_TOP_LEG_MNTPT_MKDIRP", ret
= -1);
5733 bam_error(MKDIR_FAILED
, tmpmnt
, strerror(errno
));
5737 BAM_DPRINTF((D_Z_MOUNT_TOP_LEG_MNTPT_PRES
, fcn
, pool
, tmpmnt
));
5740 (void) snprintf(cmd
, sizeof (cmd
),
5741 "/sbin/mount -F zfs %s %s",
5744 ret
= exec_cmd(cmd
, NULL
);
5745 INJECT_ERROR1("Z_MOUNT_TOP_LEG_MOUNT_CMD", ret
= 1);
5747 bam_error(ZFS_MOUNT_FAILED
, pool
);
5748 (void) rmdir(tmpmnt
);
5752 *mnted
= LEGACY_MOUNTED
;
5753 BAM_DPRINTF((D_Z_MOUNT_TOP_LEG_MOUNTED
, fcn
, pool
, tmpmnt
));
5754 return (s_strdup(tmpmnt
));
5758 * Mounts the top dataset (if needed)
5759 * Returns: The mountpoint of the top dataset or NULL on error
5760 * mnted returns one of the above values defined for zfs_mnted_t
5763 mount_top_dataset(char *pool
, zfs_mnted_t
*mnted
)
5766 filelist_t flist
= {0};
5771 const char *fcn
= "mount_top_dataset()";
5773 *mnted
= ZFS_MNT_ERROR
;
5775 BAM_DPRINTF((D_FUNC_ENTRY1
, fcn
, pool
));
5778 * First check if the top dataset is a "legacy" dataset
5780 (void) snprintf(cmd
, sizeof (cmd
),
5781 "/sbin/zfs get -Ho value mountpoint %s",
5783 ret
= exec_cmd(cmd
, &flist
);
5784 INJECT_ERROR1("Z_MOUNT_TOP_GET_MNTPT", ret
= 1);
5786 bam_error(ZFS_MNTPT_FAILED
, pool
);
5790 if (flist
.head
&& (flist
.head
== flist
.tail
)) {
5791 char *legacy
= strtok(flist
.head
->line
, " \t\n");
5792 if (legacy
&& strcmp(legacy
, "legacy") == 0) {
5793 filelist_free(&flist
);
5794 BAM_DPRINTF((D_Z_IS_LEGACY
, fcn
, pool
));
5795 return (mount_legacy_dataset(pool
, mnted
));
5799 filelist_free(&flist
);
5801 BAM_DPRINTF((D_Z_IS_NOT_LEGACY
, fcn
, pool
));
5803 (void) snprintf(cmd
, sizeof (cmd
),
5804 "/sbin/zfs get -Ho value mounted %s",
5807 ret
= exec_cmd(cmd
, &flist
);
5808 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MOUNTED", ret
= 1);
5810 bam_error(ZFS_MNTED_FAILED
, pool
);
5814 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MOUNTED_VAL", flist
.head
= NULL
);
5815 if ((flist
.head
== NULL
) || (flist
.head
!= flist
.tail
)) {
5816 bam_error(BAD_ZFS_MNTED
, pool
);
5817 filelist_free(&flist
);
5821 is_mounted
= strtok(flist
.head
->line
, " \t\n");
5822 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MOUNTED_YES", is_mounted
= "yes");
5823 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MOUNTED_NO", is_mounted
= "no");
5824 if (strcmp(is_mounted
, "no") != 0) {
5825 filelist_free(&flist
);
5826 *mnted
= ZFS_ALREADY
;
5827 BAM_DPRINTF((D_Z_MOUNT_TOP_NONLEG_MOUNTED_ALREADY
, fcn
, pool
));
5831 filelist_free(&flist
);
5832 BAM_DPRINTF((D_Z_MOUNT_TOP_NONLEG_MOUNTED_NOT_ALREADY
, fcn
, pool
));
5834 /* top dataset is not mounted. Mount it now */
5835 (void) snprintf(cmd
, sizeof (cmd
),
5836 "/sbin/zfs mount %s", pool
);
5837 ret
= exec_cmd(cmd
, NULL
);
5838 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_MOUNT_CMD", ret
= 1);
5840 bam_error(ZFS_MOUNT_FAILED
, pool
);
5843 *mnted
= ZFS_MOUNTED
;
5844 BAM_DPRINTF((D_Z_MOUNT_TOP_NONLEG_MOUNTED_NOW
, fcn
, pool
));
5848 * Now get the mountpoint
5850 (void) snprintf(cmd
, sizeof (cmd
),
5851 "/sbin/zfs get -Ho value mountpoint %s",
5854 ret
= exec_cmd(cmd
, &flist
);
5855 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MNTPT_CMD", ret
= 1);
5857 bam_error(ZFS_MNTPT_FAILED
, pool
);
5861 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MNTPT_OUT", flist
.head
= NULL
);
5862 if ((flist
.head
== NULL
) || (flist
.head
!= flist
.tail
)) {
5863 bam_error(NULL_ZFS_MNTPT
, pool
);
5867 mntpt
= strtok(flist
.head
->line
, " \t\n");
5868 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MNTPT_STRTOK", mntpt
= "foo");
5869 if (*mntpt
!= '/') {
5870 bam_error(BAD_ZFS_MNTPT
, pool
, mntpt
);
5873 zmntpt
= s_strdup(mntpt
);
5875 filelist_free(&flist
);
5877 BAM_DPRINTF((D_Z_MOUNT_TOP_NONLEG_MNTPT
, fcn
, pool
, zmntpt
));
5882 filelist_free(&flist
);
5883 (void) umount_top_dataset(pool
, *mnted
, NULL
);
5884 BAM_DPRINTF((D_RETURN_FAILURE
, fcn
));
5889 umount_top_dataset(char *pool
, zfs_mnted_t mnted
, char *mntpt
)
5893 const char *fcn
= "umount_top_dataset()";
5895 INJECT_ERROR1("Z_UMOUNT_TOP_INVALID_STATE", mnted
= ZFS_MNT_ERROR
);
5897 case LEGACY_ALREADY
:
5900 BAM_DPRINTF((D_Z_UMOUNT_TOP_ALREADY_NOP
, fcn
, pool
,
5901 mntpt
? mntpt
: "NULL"));
5903 return (BAM_SUCCESS
);
5904 case LEGACY_MOUNTED
:
5905 (void) snprintf(cmd
, sizeof (cmd
),
5906 "/sbin/umount %s", pool
);
5907 ret
= exec_cmd(cmd
, NULL
);
5908 INJECT_ERROR1("Z_UMOUNT_TOP_LEGACY_UMOUNT_FAIL", ret
= 1);
5910 bam_error(UMOUNT_FAILED
, pool
);
5915 (void) rmdir(mntpt
);
5917 BAM_DPRINTF((D_Z_UMOUNT_TOP_LEGACY
, fcn
, pool
));
5918 return (BAM_SUCCESS
);
5921 (void) snprintf(cmd
, sizeof (cmd
),
5922 "/sbin/zfs unmount %s", pool
);
5923 ret
= exec_cmd(cmd
, NULL
);
5924 INJECT_ERROR1("Z_UMOUNT_TOP_NONLEG_UMOUNT_FAIL", ret
= 1);
5926 bam_error(UMOUNT_FAILED
, pool
);
5929 BAM_DPRINTF((D_Z_UMOUNT_TOP_NONLEG
, fcn
, pool
));
5930 return (BAM_SUCCESS
);
5932 bam_error(INT_BAD_MNTSTATE
, pool
);
5939 * For ZFS, osdev can be one of two forms
5940 * It can be a "special" file as seen in mnttab: rpool/ROOT/szboot_0402
5941 * It can be a /dev/[r]dsk special file. We handle both instances
5944 get_pool(char *osdev
)
5948 filelist_t flist
= {0};
5953 const char *fcn
= "get_pool()";
5955 INJECT_ERROR1("GET_POOL_OSDEV", osdev
= NULL
);
5956 if (osdev
== NULL
) {
5957 bam_error(GET_POOL_OSDEV_NULL
);
5961 BAM_DPRINTF((D_GET_POOL_OSDEV
, fcn
, osdev
));
5963 if (osdev
[0] != '/') {
5964 (void) strlcpy(buf
, osdev
, sizeof (buf
));
5965 slash
= strchr(buf
, '/');
5968 pool
= s_strdup(buf
);
5969 BAM_DPRINTF((D_GET_POOL_RET
, fcn
, pool
));
5971 } else if (strncmp(osdev
, "/dev/dsk/", strlen("/dev/dsk/")) != 0 &&
5972 strncmp(osdev
, "/dev/rdsk/", strlen("/dev/rdsk/")) != 0) {
5973 bam_error(GET_POOL_BAD_OSDEV
, osdev
);
5978 * Call the zfs fstyp directly since this is a zpool. This avoids
5979 * potential pcfs conflicts if the first block wasn't cleared.
5981 (void) snprintf(cmd
, sizeof (cmd
),
5982 "/usr/lib/fs/zfs/fstyp -a %s 2>/dev/null | /bin/grep '^name:'",
5985 ret
= exec_cmd(cmd
, &flist
);
5986 INJECT_ERROR1("GET_POOL_FSTYP", ret
= 1);
5988 bam_error(FSTYP_A_FAILED
, osdev
);
5992 INJECT_ERROR1("GET_POOL_FSTYP_OUT", flist
.head
= NULL
);
5993 if ((flist
.head
== NULL
) || (flist
.head
!= flist
.tail
)) {
5994 bam_error(NULL_FSTYP_A
, osdev
);
5995 filelist_free(&flist
);
5999 (void) strtok(flist
.head
->line
, "'");
6000 cp
= strtok(NULL
, "'");
6001 INJECT_ERROR1("GET_POOL_FSTYP_STRTOK", cp
= NULL
);
6003 bam_error(BAD_FSTYP_A
, osdev
);
6004 filelist_free(&flist
);
6008 pool
= s_strdup(cp
);
6010 filelist_free(&flist
);
6012 BAM_DPRINTF((D_GET_POOL_RET
, fcn
, pool
));
6018 find_zfs_existing(char *osdev
)
6024 const char *fcn
= "find_zfs_existing()";
6026 pool
= get_pool(osdev
);
6027 INJECT_ERROR1("ZFS_FIND_EXIST_POOL", pool
= NULL
);
6029 bam_error(ZFS_GET_POOL_FAILED
, osdev
);
6033 mntpt
= mount_top_dataset(pool
, &mnted
);
6034 INJECT_ERROR1("ZFS_FIND_EXIST_MOUNT_TOP", mntpt
= NULL
);
6035 if (mntpt
== NULL
) {
6036 bam_error(ZFS_MOUNT_TOP_DATASET_FAILED
, pool
);
6041 sign
= find_primary_common(mntpt
, "zfs");
6043 sign
= find_backup_common(mntpt
, "zfs");
6044 BAM_DPRINTF((D_EXIST_BACKUP_SIGN
, fcn
, sign
? sign
: "NULL"));
6046 BAM_DPRINTF((D_EXIST_PRIMARY_SIGN
, fcn
, sign
));
6049 (void) umount_top_dataset(pool
, mnted
, mntpt
);
6057 find_existing_sign(char *osroot
, char *osdev
, char *fstype
)
6059 const char *fcn
= "find_existing_sign()";
6061 INJECT_ERROR1("FIND_EXIST_NOTSUP_FS", fstype
= "foofs");
6062 if (strcmp(fstype
, "ufs") == 0) {
6063 BAM_DPRINTF((D_CHECK_UFS_EXIST_SIGN
, fcn
));
6064 return (find_ufs_existing(osroot
));
6065 } else if (strcmp(fstype
, "zfs") == 0) {
6066 BAM_DPRINTF((D_CHECK_ZFS_EXIST_SIGN
, fcn
));
6067 return (find_zfs_existing(osdev
));
6069 bam_error(GRUBSIGN_NOTSUP
, fstype
);
6074 #define MH_HASH_SZ 16
6082 typedef struct mcache
{
6086 struct mcache
*mc_next
;
6089 typedef struct mhash
{
6090 mcache_t
*mh_hash
[MH_HASH_SZ
];
6094 mhash_fcn(char *key
)
6099 for (i
= 0; key
[i
] != '\0'; i
++) {
6100 sum
+= (uchar_t
)key
[i
];
6105 assert(sum
< MH_HASH_SZ
);
6114 struct extmnttab mnt
;
6121 const char *fcn
= "cache_mnttab()";
6123 mfp
= fopen(MNTTAB
, "r");
6125 INJECT_ERROR1("CACHE_MNTTAB_MNTTAB_ERR", mfp
= NULL
);
6127 bam_error(OPEN_FAIL
, MNTTAB
, strerror(error
));
6131 mhp
= s_calloc(1, sizeof (mhash_t
));
6135 while (getextmntent(mfp
, &mnt
, sizeof (mnt
)) == 0) {
6136 /* only cache ufs */
6137 if (strcmp(mnt
.mnt_fstype
, "ufs") != 0)
6140 /* basename() modifies its arg, so dup it */
6141 special_dup
= s_strdup(mnt
.mnt_special
);
6142 ctds
= basename(special_dup
);
6144 mcp
= s_calloc(1, sizeof (mcache_t
));
6145 mcp
->mc_special
= s_strdup(ctds
);
6146 mcp
->mc_mntpt
= s_strdup(mnt
.mnt_mountp
);
6147 mcp
->mc_fstype
= s_strdup(mnt
.mnt_fstype
);
6148 BAM_DPRINTF((D_CACHE_MNTS
, fcn
, ctds
,
6149 mnt
.mnt_mountp
, mnt
.mnt_fstype
));
6150 idx
= mhash_fcn(ctds
);
6151 mcp
->mc_next
= mhp
->mh_hash
[idx
];
6152 mhp
->mh_hash
[idx
] = mcp
;
6162 free_mnttab(mhash_t
*mhp
)
6167 for (i
= 0; i
< MH_HASH_SZ
; i
++) {
6169 while (mcp
= mhp
->mh_hash
[i
]) {
6170 mhp
->mh_hash
[i
] = mcp
->mc_next
;
6171 free(mcp
->mc_special
);
6172 free(mcp
->mc_mntpt
);
6173 free(mcp
->mc_fstype
);
6178 for (i
= 0; i
< MH_HASH_SZ
; i
++) {
6179 assert(mhp
->mh_hash
[i
] == NULL
);
6185 search_hash(mhash_t
*mhp
, char *special
, char **mntpt
)
6189 const char *fcn
= "search_hash()";
6195 INJECT_ERROR1("SEARCH_HASH_FULL_PATH", special
= "/foo");
6196 if (strchr(special
, '/')) {
6197 bam_error(INVALID_MHASH_KEY
, special
);
6201 idx
= mhash_fcn(special
);
6203 for (mcp
= mhp
->mh_hash
[idx
]; mcp
; mcp
= mcp
->mc_next
) {
6204 if (strcmp(mcp
->mc_special
, special
) == 0)
6209 BAM_DPRINTF((D_MNTTAB_HASH_NOMATCH
, fcn
, special
));
6210 return (MH_NOMATCH
);
6213 assert(strcmp(mcp
->mc_fstype
, "ufs") == 0);
6214 *mntpt
= mcp
->mc_mntpt
;
6215 BAM_DPRINTF((D_MNTTAB_HASH_MATCH
, fcn
, special
));
6220 check_add_ufs_sign_to_list(FILE *tfp
, char *mntpt
)
6224 char signbuf
[MAXNAMELEN
];
6227 const char *fcn
= "check_add_ufs_sign_to_list()";
6229 /* safe to specify NULL as "osdev" arg for UFS */
6230 sign
= find_existing_sign(mntpt
, NULL
, "ufs");
6232 /* No existing signature, nothing to add to list */
6233 BAM_DPRINTF((D_NO_SIGN_TO_LIST
, fcn
, mntpt
));
6237 (void) snprintf(signbuf
, sizeof (signbuf
), "%s\n", sign
);
6240 INJECT_ERROR1("UFS_MNTPT_SIGN_NOTUFS", signline
= "pool_rpool10\n");
6241 if (strncmp(signline
, GRUBSIGN_UFS_PREFIX
,
6242 strlen(GRUBSIGN_UFS_PREFIX
))) {
6243 bam_error(INVALID_UFS_SIGNATURE
, sign
);
6245 /* ignore invalid signatures */
6249 len
= fputs(signline
, tfp
);
6251 INJECT_ERROR1("SIGN_LIST_PUTS_ERROR", len
= 0);
6252 if (len
!= strlen(signline
)) {
6253 bam_error(SIGN_LIST_FPUTS_ERR
, sign
, strerror(error
));
6260 BAM_DPRINTF((D_SIGN_LIST_PUTS_DONE
, fcn
, mntpt
));
6265 * slice is a basename not a full pathname
6268 process_slice_common(char *slice
, FILE *tfp
, mhash_t
*mhp
, char *tmpmnt
)
6272 char path
[PATH_MAX
];
6275 filelist_t flist
= {0};
6277 char blkslice
[PATH_MAX
];
6278 const char *fcn
= "process_slice_common()";
6281 ret
= search_hash(mhp
, slice
, &mntpt
);
6284 if (check_add_ufs_sign_to_list(tfp
, mntpt
) == -1)
6295 (void) snprintf(path
, sizeof (path
), "/dev/rdsk/%s", slice
);
6296 if (stat(path
, &sbuf
) == -1) {
6297 BAM_DPRINTF((D_SLICE_ENOENT
, fcn
, path
));
6301 /* Check if ufs. Call ufs fstyp directly to avoid pcfs conflicts. */
6302 (void) snprintf(cmd
, sizeof (cmd
),
6303 "/usr/lib/fs/ufs/fstyp /dev/rdsk/%s 2>/dev/null",
6306 if (exec_cmd(cmd
, &flist
) != 0) {
6308 bam_print(FSTYP_FAILED
, slice
);
6312 if ((flist
.head
== NULL
) || (flist
.head
!= flist
.tail
)) {
6314 bam_print(FSTYP_BAD
, slice
);
6315 filelist_free(&flist
);
6319 fstype
= strtok(flist
.head
->line
, " \t\n");
6320 if (fstype
== NULL
|| strcmp(fstype
, "ufs") != 0) {
6322 bam_print(NOT_UFS_SLICE
, slice
, fstype
);
6323 filelist_free(&flist
);
6327 filelist_free(&flist
);
6330 * Since we are mounting the filesystem read-only, the
6331 * the last mount field of the superblock is unchanged
6332 * and does not need to be fixed up post-mount;
6335 (void) snprintf(blkslice
, sizeof (blkslice
), "/dev/dsk/%s",
6338 (void) snprintf(cmd
, sizeof (cmd
),
6339 "/usr/sbin/mount -F ufs -o ro %s %s "
6340 "> /dev/null 2>&1", blkslice
, tmpmnt
);
6342 if (exec_cmd(cmd
, NULL
) != 0) {
6344 bam_print(MOUNT_FAILED
, blkslice
, "ufs");
6348 ret
= check_add_ufs_sign_to_list(tfp
, tmpmnt
);
6350 (void) snprintf(cmd
, sizeof (cmd
),
6351 "/usr/sbin/umount -f %s > /dev/null 2>&1",
6354 if (exec_cmd(cmd
, NULL
) != 0) {
6355 bam_print(UMOUNT_FAILED
, slice
);
6363 process_vtoc_slices(
6371 char slice
[PATH_MAX
];
6374 const char *fcn
= "process_vtoc_slices()";
6378 assert(s0
[len
- 2] == 's' && s0
[len
- 1] == '0');
6382 (void) strlcpy(slice
, s0
, sizeof (slice
));
6386 cp
= slice
+ len
- 1;
6388 for (idx
= 0; idx
< vtoc
->v_nparts
; idx
++) {
6390 (void) snprintf(cp
, sizeof (slice
) - (len
- 1), "%u", idx
);
6392 if (vtoc
->v_part
[idx
].p_size
== 0) {
6393 BAM_DPRINTF((D_VTOC_SIZE_ZERO
, fcn
, slice
));
6397 /* Skip "SWAP", "USR", "BACKUP", "VAR", "HOME", "ALTSCTR" */
6398 switch (vtoc
->v_part
[idx
].p_tag
) {
6405 BAM_DPRINTF((D_VTOC_NOT_ROOT_TAG
, fcn
, slice
));
6408 BAM_DPRINTF((D_VTOC_ROOT_TAG
, fcn
, slice
));
6412 /* skip unmountable and readonly slices */
6413 switch (vtoc
->v_part
[idx
].p_flag
) {
6416 BAM_DPRINTF((D_VTOC_NOT_RDWR_FLAG
, fcn
, slice
));
6419 BAM_DPRINTF((D_VTOC_RDWR_FLAG
, fcn
, slice
));
6423 if (process_slice_common(slice
, tfp
, mhp
, tmpmnt
) == -1) {
6440 char slice
[PATH_MAX
];
6443 const char *fcn
= "process_efi_slices()";
6447 assert(s0
[len
- 2] == 's' && s0
[len
- 1] == '0');
6451 (void) strlcpy(slice
, s0
, sizeof (slice
));
6455 cp
= slice
+ len
- 1;
6457 for (idx
= 0; idx
< efi
->efi_nparts
; idx
++) {
6459 (void) snprintf(cp
, sizeof (slice
) - (len
- 1), "%u", idx
);
6461 if (efi
->efi_parts
[idx
].p_size
== 0) {
6462 BAM_DPRINTF((D_EFI_SIZE_ZERO
, fcn
, slice
));
6466 /* Skip "SWAP", "USR", "BACKUP", "VAR", "HOME", "ALTSCTR" */
6467 switch (efi
->efi_parts
[idx
].p_tag
) {
6474 BAM_DPRINTF((D_EFI_NOT_ROOT_TAG
, fcn
, slice
));
6477 BAM_DPRINTF((D_EFI_ROOT_TAG
, fcn
, slice
));
6481 /* skip unmountable and readonly slices */
6482 switch (efi
->efi_parts
[idx
].p_flag
) {
6485 BAM_DPRINTF((D_EFI_NOT_RDWR_FLAG
, fcn
, slice
));
6488 BAM_DPRINTF((D_EFI_RDWR_FLAG
, fcn
, slice
));
6492 if (process_slice_common(slice
, tfp
, mhp
, tmpmnt
) == -1) {
6501 * s0 is a basename not a full path
6504 process_slice0(char *s0
, FILE *tfp
, mhash_t
*mhp
, char *tmpmnt
)
6508 char s0path
[PATH_MAX
];
6515 const char *fcn
= "process_slice0()";
6517 (void) snprintf(s0path
, sizeof (s0path
), "/dev/rdsk/%s", s0
);
6519 if (stat(s0path
, &sbuf
) == -1) {
6520 BAM_DPRINTF((D_SLICE0_ENOENT
, fcn
, s0path
));
6524 fd
= open(s0path
, O_NONBLOCK
|O_RDONLY
);
6526 bam_error(OPEN_FAIL
, s0path
, strerror(errno
));
6530 e_flag
= v_flag
= 0;
6531 retval
= ((err
= read_vtoc(fd
, &vtoc
)) >= 0) ? 0 : err
;
6534 BAM_DPRINTF((D_VTOC_READ_FAIL
, fcn
, s0path
));
6537 BAM_DPRINTF((D_VTOC_INVALID
, fcn
, s0path
));
6540 BAM_DPRINTF((D_VTOC_UNKNOWN_ERR
, fcn
, s0path
));
6544 BAM_DPRINTF((D_VTOC_NOTSUP
, fcn
, s0path
));
6548 BAM_DPRINTF((D_VTOC_READ_SUCCESS
, fcn
, s0path
));
6551 BAM_DPRINTF((D_VTOC_UNKNOWN_RETCODE
, fcn
, s0path
));
6558 retval
= ((err
= efi_alloc_and_read(fd
, &efi
)) >= 0) ? 0 : err
;
6561 BAM_DPRINTF((D_EFI_READ_FAIL
, fcn
, s0path
));
6564 BAM_DPRINTF((D_EFI_INVALID
, fcn
, s0path
));
6567 BAM_DPRINTF((D_EFI_UNKNOWN_ERR
, fcn
, s0path
));
6570 BAM_DPRINTF((D_EFI_NOTSUP
, fcn
, s0path
));
6574 BAM_DPRINTF((D_EFI_READ_SUCCESS
, fcn
, s0path
));
6577 BAM_DPRINTF((D_EFI_UNKNOWN_RETCODE
, fcn
, s0path
));
6585 retval
= process_vtoc_slices(s0
,
6586 &vtoc
, tfp
, mhp
, tmpmnt
);
6587 } else if (e_flag
) {
6588 retval
= process_efi_slices(s0
,
6589 efi
, tfp
, mhp
, tmpmnt
);
6591 BAM_DPRINTF((D_NOT_VTOC_OR_EFI
, fcn
, s0path
));
6599 * Find and create a list of all existing UFS boot signatures
6602 FindAllUfsSignatures(void)
6604 mhash_t
*mnttab_hash
;
6607 char tmpmnt
[PATH_MAX
];
6615 const char *fcn
= "FindAllUfsSignatures()";
6617 if (stat(UFS_SIGNATURE_LIST
, &sb
) != -1) {
6618 bam_print(SIGNATURE_LIST_EXISTS
, UFS_SIGNATURE_LIST
);
6622 fd
= open(UFS_SIGNATURE_LIST
".tmp",
6623 O_RDWR
|O_CREAT
|O_TRUNC
, 0644);
6625 INJECT_ERROR1("SIGN_LIST_TMP_TRUNC", fd
= -1);
6627 bam_error(OPEN_FAIL
, UFS_SIGNATURE_LIST
".tmp", strerror(error
));
6633 INJECT_ERROR1("SIGN_LIST_TMP_CLOSE", ret
= -1);
6635 bam_error(CLOSE_FAIL
, UFS_SIGNATURE_LIST
".tmp",
6637 (void) unlink(UFS_SIGNATURE_LIST
".tmp");
6641 tfp
= fopen(UFS_SIGNATURE_LIST
".tmp", "a");
6643 INJECT_ERROR1("SIGN_LIST_APPEND_FOPEN", tfp
= NULL
);
6645 bam_error(OPEN_FAIL
, UFS_SIGNATURE_LIST
".tmp", strerror(error
));
6646 (void) unlink(UFS_SIGNATURE_LIST
".tmp");
6650 mnttab_hash
= cache_mnttab();
6651 INJECT_ERROR1("CACHE_MNTTAB_ERROR", mnttab_hash
= NULL
);
6652 if (mnttab_hash
== NULL
) {
6654 (void) unlink(UFS_SIGNATURE_LIST
".tmp");
6655 bam_error(CACHE_MNTTAB_FAIL
, fcn
);
6659 (void) snprintf(tmpmnt
, sizeof (tmpmnt
),
6660 "/tmp/bootadm_ufs_sign_mnt.%d", getpid());
6661 (void) unlink(tmpmnt
);
6663 ret
= mkdirp(tmpmnt
, DIR_PERMS
);
6665 INJECT_ERROR1("MKDIRP_SIGN_MNT", ret
= -1);
6667 bam_error(MKDIR_FAILED
, tmpmnt
, strerror(error
));
6668 free_mnttab(mnttab_hash
);
6670 (void) unlink(UFS_SIGNATURE_LIST
".tmp");
6674 dirp
= opendir("/dev/rdsk");
6676 INJECT_ERROR1("OPENDIR_DEV_RDSK", dirp
= NULL
);
6678 bam_error(OPENDIR_FAILED
, "/dev/rdsk", strerror(error
));
6682 while (dp
= readdir(dirp
)) {
6683 if (strcmp(dp
->d_name
, ".") == 0 ||
6684 strcmp(dp
->d_name
, "..") == 0)
6688 * we only look for the s0 slice. This is guranteed to
6689 * have 's' at len - 2.
6691 len
= strlen(dp
->d_name
);
6692 if (dp
->d_name
[len
- 2 ] != 's' || dp
->d_name
[len
- 1] != '0') {
6693 BAM_DPRINTF((D_SKIP_SLICE_NOTZERO
, fcn
, dp
->d_name
));
6697 ret
= process_slice0(dp
->d_name
, tfp
, mnttab_hash
, tmpmnt
);
6698 INJECT_ERROR1("PROCESS_S0_FAIL", ret
= -1);
6703 (void) closedir(dirp
);
6704 free_mnttab(mnttab_hash
);
6705 (void) rmdir(tmpmnt
);
6709 INJECT_ERROR1("FCLOSE_SIGNLIST_TMP", ret
= EOF
);
6711 bam_error(CLOSE_FAIL
, UFS_SIGNATURE_LIST
".tmp",
6713 (void) unlink(UFS_SIGNATURE_LIST
".tmp");
6717 /* We have a list of existing GRUB signatures. Sort it first */
6718 (void) snprintf(cmd
, sizeof (cmd
),
6719 "/usr/bin/sort -u %s.tmp > %s.sorted",
6720 UFS_SIGNATURE_LIST
, UFS_SIGNATURE_LIST
);
6722 ret
= exec_cmd(cmd
, NULL
);
6723 INJECT_ERROR1("SORT_SIGN_LIST", ret
= 1);
6725 bam_error(GRUBSIGN_SORT_FAILED
);
6726 (void) unlink(UFS_SIGNATURE_LIST
".sorted");
6727 (void) unlink(UFS_SIGNATURE_LIST
".tmp");
6731 (void) unlink(UFS_SIGNATURE_LIST
".tmp");
6733 ret
= rename(UFS_SIGNATURE_LIST
".sorted", UFS_SIGNATURE_LIST
);
6735 INJECT_ERROR1("RENAME_TMP_SIGNLIST", ret
= -1);
6737 bam_error(RENAME_FAIL
, UFS_SIGNATURE_LIST
, strerror(error
));
6738 (void) unlink(UFS_SIGNATURE_LIST
".sorted");
6742 if (stat(UFS_SIGNATURE_LIST
, &sb
) == 0 && sb
.st_size
== 0) {
6743 BAM_DPRINTF((D_ZERO_LEN_SIGNLIST
, fcn
, UFS_SIGNATURE_LIST
));
6746 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
6751 (void) closedir(dirp
);
6752 free_mnttab(mnttab_hash
);
6753 (void) rmdir(tmpmnt
);
6755 (void) unlink(UFS_SIGNATURE_LIST
".tmp");
6756 BAM_DPRINTF((D_RETURN_FAILURE
, fcn
));
6761 create_ufs_sign(void)
6765 char tmpsign
[MAXNAMELEN
+ 1];
6771 const char *fcn
= "create_ufs_sign()";
6773 bam_print(SEARCHING_UFS_SIGN
);
6775 ret
= FindAllUfsSignatures();
6776 INJECT_ERROR1("FIND_ALL_UFS", ret
= -1);
6778 bam_error(ERR_FIND_UFS_SIGN
);
6782 /* Make sure the list exists and is owned by root */
6783 INJECT_ERROR1("SIGNLIST_NOT_CREATED",
6784 (void) unlink(UFS_SIGNATURE_LIST
));
6785 if (stat(UFS_SIGNATURE_LIST
, &sb
) == -1 || sb
.st_uid
!= 0) {
6786 (void) unlink(UFS_SIGNATURE_LIST
);
6787 bam_error(UFS_SIGNATURE_LIST_MISS
, UFS_SIGNATURE_LIST
);
6791 if (sb
.st_size
== 0) {
6792 bam_print(GRUBSIGN_UFS_NONE
);
6797 /* The signature list was sorted when it was created */
6798 tfp
= fopen(UFS_SIGNATURE_LIST
, "r");
6800 INJECT_ERROR1("FOPEN_SIGN_LIST", tfp
= NULL
);
6802 bam_error(UFS_SIGNATURE_LIST_OPENERR
,
6803 UFS_SIGNATURE_LIST
, strerror(error
));
6804 (void) unlink(UFS_SIGNATURE_LIST
);
6808 for (i
= 0; s_fgets(tmpsign
, sizeof (tmpsign
), tfp
); i
++) {
6810 if (strncmp(tmpsign
, GRUBSIGN_UFS_PREFIX
,
6811 strlen(GRUBSIGN_UFS_PREFIX
)) != 0) {
6813 (void) unlink(UFS_SIGNATURE_LIST
);
6814 bam_error(UFS_BADSIGN
, tmpsign
);
6817 numstr
= tmpsign
+ strlen(GRUBSIGN_UFS_PREFIX
);
6819 if (numstr
[0] == '\0' || !isdigit(numstr
[0])) {
6821 (void) unlink(UFS_SIGNATURE_LIST
);
6822 bam_error(UFS_BADSIGN
, tmpsign
);
6826 signnum
= atoi(numstr
);
6827 INJECT_ERROR1("NEGATIVE_SIGN", signnum
= -1);
6830 (void) unlink(UFS_SIGNATURE_LIST
);
6831 bam_error(UFS_BADSIGN
, tmpsign
);
6836 BAM_DPRINTF((D_FOUND_HOLE_SIGNLIST
, fcn
, i
));
6844 (void) snprintf(tmpsign
, sizeof (tmpsign
), "rootfs%d", i
);
6846 /* add the ufs signature to the /var/run list of signatures */
6847 ret
= ufs_add_to_sign_list(tmpsign
);
6848 INJECT_ERROR1("UFS_ADD_TO_SIGN_LIST", ret
= -1);
6850 (void) unlink(UFS_SIGNATURE_LIST
);
6851 bam_error(FAILED_ADD_SIGNLIST
, tmpsign
);
6855 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
6857 return (s_strdup(tmpsign
));
6861 get_fstype(char *osroot
)
6864 struct mnttab mp
= {0};
6865 struct mnttab mpref
= {0};
6868 const char *fcn
= "get_fstype()";
6870 INJECT_ERROR1("GET_FSTYPE_OSROOT", osroot
= NULL
);
6871 if (osroot
== NULL
) {
6872 bam_error(GET_FSTYPE_ARGS
);
6876 mntfp
= fopen(MNTTAB
, "r");
6878 INJECT_ERROR1("GET_FSTYPE_FOPEN", mntfp
= NULL
);
6879 if (mntfp
== NULL
) {
6880 bam_error(OPEN_FAIL
, MNTTAB
, strerror(error
));
6884 if (*osroot
== '\0')
6885 mpref
.mnt_mountp
= "/";
6887 mpref
.mnt_mountp
= osroot
;
6889 ret
= getmntany(mntfp
, &mp
, &mpref
);
6890 INJECT_ERROR1("GET_FSTYPE_GETMNTANY", ret
= 1);
6892 bam_error(MNTTAB_MNTPT_NOT_FOUND
, osroot
, MNTTAB
);
6893 (void) fclose(mntfp
);
6896 (void) fclose(mntfp
);
6898 INJECT_ERROR1("GET_FSTYPE_NULL", mp
.mnt_fstype
= NULL
);
6899 if (mp
.mnt_fstype
== NULL
) {
6900 bam_error(MNTTAB_FSTYPE_NULL
, osroot
);
6904 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
6906 return (s_strdup(mp
.mnt_fstype
));
6910 create_zfs_sign(char *osdev
)
6912 char tmpsign
[PATH_MAX
];
6914 const char *fcn
= "create_zfs_sign()";
6916 BAM_DPRINTF((D_FUNC_ENTRY1
, fcn
, osdev
));
6919 * First find the pool name
6921 pool
= get_pool(osdev
);
6922 INJECT_ERROR1("CREATE_ZFS_SIGN_GET_POOL", pool
= NULL
);
6924 bam_error(GET_POOL_FAILED
, osdev
);
6928 (void) snprintf(tmpsign
, sizeof (tmpsign
), "pool_%s", pool
);
6930 BAM_DPRINTF((D_CREATED_ZFS_SIGN
, fcn
, tmpsign
));
6934 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
6936 return (s_strdup(tmpsign
));
6940 create_new_sign(char *osdev
, char *fstype
)
6943 const char *fcn
= "create_new_sign()";
6945 INJECT_ERROR1("NEW_SIGN_FSTYPE", fstype
= "foofs");
6947 if (strcmp(fstype
, "zfs") == 0) {
6948 BAM_DPRINTF((D_CREATE_NEW_ZFS
, fcn
));
6949 sign
= create_zfs_sign(osdev
);
6950 } else if (strcmp(fstype
, "ufs") == 0) {
6951 BAM_DPRINTF((D_CREATE_NEW_UFS
, fcn
));
6952 sign
= create_ufs_sign();
6954 bam_error(GRUBSIGN_NOTSUP
, fstype
);
6958 BAM_DPRINTF((D_CREATED_NEW_SIGN
, fcn
, sign
? sign
: "<NULL>"));
6963 set_backup_common(char *mntpt
, char *sign
)
6966 char backup
[PATH_MAX
];
6967 char tmpsign
[PATH_MAX
];
6973 const char *fcn
= "set_backup_common()";
6975 (void) snprintf(backup
, sizeof (backup
), "%s%s",
6976 mntpt
, GRUBSIGN_BACKUP
);
6978 /* First read the backup */
6979 bfp
= fopen(backup
, "r");
6981 while (s_fgets(tmpsign
, sizeof (tmpsign
), bfp
)) {
6982 if (strcmp(tmpsign
, sign
) == 0) {
6983 BAM_DPRINTF((D_FOUND_IN_BACKUP
, fcn
, sign
));
6989 BAM_DPRINTF((D_NOT_FOUND_IN_EXIST_BACKUP
, fcn
, sign
));
6991 BAM_DPRINTF((D_BACKUP_NOT_EXIST
, fcn
, backup
));
6995 * Didn't find the correct signature. First create
6996 * the directory if necessary.
6999 /* dirname() modifies its argument so dup it */
7000 backup_dup
= s_strdup(backup
);
7001 bdir
= dirname(backup_dup
);
7004 ret
= stat(bdir
, &sb
);
7005 INJECT_ERROR1("SET_BACKUP_STAT", ret
= -1);
7007 BAM_DPRINTF((D_BACKUP_DIR_NOEXIST
, fcn
, bdir
));
7008 ret
= mkdirp(bdir
, DIR_PERMS
);
7010 INJECT_ERROR1("SET_BACKUP_MKDIRP", ret
= -1);
7012 bam_error(GRUBSIGN_BACKUP_MKDIRERR
,
7013 GRUBSIGN_BACKUP
, strerror(error
));
7021 * Open the backup in append mode to add the correct
7024 bfp
= fopen(backup
, "a");
7026 INJECT_ERROR1("SET_BACKUP_FOPEN_A", bfp
= NULL
);
7028 bam_error(GRUBSIGN_BACKUP_OPENERR
,
7029 GRUBSIGN_BACKUP
, strerror(error
));
7033 (void) snprintf(tmpsign
, sizeof (tmpsign
), "%s\n", sign
);
7035 ret
= fputs(tmpsign
, bfp
);
7037 INJECT_ERROR1("SET_BACKUP_FPUTS", ret
= 0);
7038 if (ret
!= strlen(tmpsign
)) {
7039 bam_error(GRUBSIGN_BACKUP_WRITEERR
,
7040 GRUBSIGN_BACKUP
, strerror(error
));
7048 bam_print(GRUBSIGN_BACKUP_UPDATED
, GRUBSIGN_BACKUP
);
7050 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
7056 set_backup_ufs(char *osroot
, char *sign
)
7058 const char *fcn
= "set_backup_ufs()";
7060 BAM_DPRINTF((D_FUNC_ENTRY2
, fcn
, osroot
, sign
));
7061 return (set_backup_common(osroot
, sign
));
7065 set_backup_zfs(char *osdev
, char *sign
)
7071 const char *fcn
= "set_backup_zfs()";
7073 BAM_DPRINTF((D_FUNC_ENTRY2
, fcn
, osdev
, sign
));
7075 pool
= get_pool(osdev
);
7076 INJECT_ERROR1("SET_BACKUP_GET_POOL", pool
= NULL
);
7078 bam_error(GET_POOL_FAILED
, osdev
);
7082 mntpt
= mount_top_dataset(pool
, &mnted
);
7083 INJECT_ERROR1("SET_BACKUP_MOUNT_DATASET", mntpt
= NULL
);
7084 if (mntpt
== NULL
) {
7085 bam_error(FAIL_MNT_TOP_DATASET
, pool
);
7090 ret
= set_backup_common(mntpt
, sign
);
7092 (void) umount_top_dataset(pool
, mnted
, mntpt
);
7096 INJECT_ERROR1("SET_BACKUP_ZFS_FAIL", ret
= 1);
7098 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
7100 BAM_DPRINTF((D_RETURN_FAILURE
, fcn
));
7107 set_backup(char *osroot
, char *osdev
, char *sign
, char *fstype
)
7109 const char *fcn
= "set_backup()";
7112 INJECT_ERROR1("SET_BACKUP_FSTYPE", fstype
= "foofs");
7114 if (strcmp(fstype
, "ufs") == 0) {
7115 BAM_DPRINTF((D_SET_BACKUP_UFS
, fcn
));
7116 ret
= set_backup_ufs(osroot
, sign
);
7117 } else if (strcmp(fstype
, "zfs") == 0) {
7118 BAM_DPRINTF((D_SET_BACKUP_ZFS
, fcn
));
7119 ret
= set_backup_zfs(osdev
, sign
);
7121 bam_error(GRUBSIGN_NOTSUP
, fstype
);
7126 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
7128 BAM_DPRINTF((D_RETURN_FAILURE
, fcn
));
7135 set_primary_common(char *mntpt
, char *sign
)
7137 char signfile
[PATH_MAX
];
7138 char signdir
[PATH_MAX
];
7143 const char *fcn
= "set_primary_common()";
7145 (void) snprintf(signfile
, sizeof (signfile
), "%s/%s/%s",
7146 mntpt
, GRUBSIGN_DIR
, sign
);
7148 if (stat(signfile
, &sb
) != -1) {
7150 bam_print(PRIMARY_SIGN_EXISTS
, sign
);
7153 BAM_DPRINTF((D_PRIMARY_NOT_EXIST
, fcn
, signfile
));
7156 (void) snprintf(signdir
, sizeof (signdir
), "%s/%s",
7157 mntpt
, GRUBSIGN_DIR
);
7159 if (stat(signdir
, &sb
) == -1) {
7160 BAM_DPRINTF((D_PRIMARY_DIR_NOEXIST
, fcn
, signdir
));
7161 ret
= mkdirp(signdir
, DIR_PERMS
);
7163 INJECT_ERROR1("SET_PRIMARY_MKDIRP", ret
= -1);
7165 bam_error(GRUBSIGN_MKDIR_ERR
, signdir
, strerror(errno
));
7170 fd
= open(signfile
, O_RDWR
|O_CREAT
|O_TRUNC
, 0444);
7172 INJECT_ERROR1("PRIMARY_SIGN_CREAT", fd
= -1);
7174 bam_error(GRUBSIGN_PRIMARY_CREATERR
, signfile
, strerror(error
));
7180 INJECT_ERROR1("PRIMARY_FSYNC", ret
= -1);
7182 bam_error(GRUBSIGN_PRIMARY_SYNCERR
, signfile
, strerror(error
));
7188 bam_print(GRUBSIGN_CREATED_PRIMARY
, signfile
);
7190 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
7196 set_primary_ufs(char *osroot
, char *sign
)
7198 const char *fcn
= "set_primary_ufs()";
7200 BAM_DPRINTF((D_FUNC_ENTRY2
, fcn
, osroot
, sign
));
7201 return (set_primary_common(osroot
, sign
));
7205 set_primary_zfs(char *osdev
, char *sign
)
7211 const char *fcn
= "set_primary_zfs()";
7213 BAM_DPRINTF((D_FUNC_ENTRY2
, fcn
, osdev
, sign
));
7215 pool
= get_pool(osdev
);
7216 INJECT_ERROR1("SET_PRIMARY_ZFS_GET_POOL", pool
= NULL
);
7218 bam_error(GET_POOL_FAILED
, osdev
);
7222 /* Pool name must exist in the sign */
7223 ret
= (strstr(sign
, pool
) != NULL
);
7224 INJECT_ERROR1("SET_PRIMARY_ZFS_POOL_SIGN_INCOMPAT", ret
= 0);
7226 bam_error(POOL_SIGN_INCOMPAT
, pool
, sign
);
7231 mntpt
= mount_top_dataset(pool
, &mnted
);
7232 INJECT_ERROR1("SET_PRIMARY_ZFS_MOUNT_DATASET", mntpt
= NULL
);
7233 if (mntpt
== NULL
) {
7234 bam_error(FAIL_MNT_TOP_DATASET
, pool
);
7239 ret
= set_primary_common(mntpt
, sign
);
7241 (void) umount_top_dataset(pool
, mnted
, mntpt
);
7245 INJECT_ERROR1("SET_PRIMARY_ZFS_FAIL", ret
= 1);
7247 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
7249 BAM_DPRINTF((D_RETURN_FAILURE
, fcn
));
7256 set_primary(char *osroot
, char *osdev
, char *sign
, char *fstype
)
7258 const char *fcn
= "set_primary()";
7261 INJECT_ERROR1("SET_PRIMARY_FSTYPE", fstype
= "foofs");
7262 if (strcmp(fstype
, "ufs") == 0) {
7263 BAM_DPRINTF((D_SET_PRIMARY_UFS
, fcn
));
7264 ret
= set_primary_ufs(osroot
, sign
);
7265 } else if (strcmp(fstype
, "zfs") == 0) {
7266 BAM_DPRINTF((D_SET_PRIMARY_ZFS
, fcn
));
7267 ret
= set_primary_zfs(osdev
, sign
);
7269 bam_error(GRUBSIGN_NOTSUP
, fstype
);
7274 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
7276 BAM_DPRINTF((D_RETURN_FAILURE
, fcn
));
7283 ufs_add_to_sign_list(char *sign
)
7286 char signline
[MAXNAMELEN
];
7290 const char *fcn
= "ufs_add_to_sign_list()";
7292 INJECT_ERROR1("ADD_TO_SIGN_LIST_NOT_UFS", sign
= "pool_rpool5");
7293 if (strncmp(sign
, GRUBSIGN_UFS_PREFIX
,
7294 strlen(GRUBSIGN_UFS_PREFIX
)) != 0) {
7295 bam_error(INVALID_UFS_SIGN
, sign
);
7296 (void) unlink(UFS_SIGNATURE_LIST
);
7301 * most failures in this routine are not a fatal error
7302 * We simply unlink the /var/run file and continue
7305 ret
= rename(UFS_SIGNATURE_LIST
, UFS_SIGNATURE_LIST
".tmp");
7307 INJECT_ERROR1("ADD_TO_SIGN_LIST_RENAME", ret
= -1);
7309 bam_error(RENAME_FAIL
, UFS_SIGNATURE_LIST
".tmp",
7311 (void) unlink(UFS_SIGNATURE_LIST
);
7315 tfp
= fopen(UFS_SIGNATURE_LIST
".tmp", "a");
7317 INJECT_ERROR1("ADD_TO_SIGN_LIST_FOPEN", tfp
= NULL
);
7319 bam_error(OPEN_FAIL
, UFS_SIGNATURE_LIST
".tmp", strerror(error
));
7320 (void) unlink(UFS_SIGNATURE_LIST
".tmp");
7324 (void) snprintf(signline
, sizeof (signline
), "%s\n", sign
);
7326 ret
= fputs(signline
, tfp
);
7328 INJECT_ERROR1("ADD_TO_SIGN_LIST_FPUTS", ret
= 0);
7329 if (ret
!= strlen(signline
)) {
7330 bam_error(SIGN_LIST_FPUTS_ERR
, sign
, strerror(error
));
7332 (void) unlink(UFS_SIGNATURE_LIST
".tmp");
7338 INJECT_ERROR1("ADD_TO_SIGN_LIST_FCLOSE", ret
= EOF
);
7340 bam_error(CLOSE_FAIL
, UFS_SIGNATURE_LIST
".tmp",
7342 (void) unlink(UFS_SIGNATURE_LIST
".tmp");
7346 /* Sort the list again */
7347 (void) snprintf(cmd
, sizeof (cmd
),
7348 "/usr/bin/sort -u %s.tmp > %s.sorted",
7349 UFS_SIGNATURE_LIST
, UFS_SIGNATURE_LIST
);
7351 ret
= exec_cmd(cmd
, NULL
);
7352 INJECT_ERROR1("ADD_TO_SIGN_LIST_SORT", ret
= 1);
7354 bam_error(GRUBSIGN_SORT_FAILED
);
7355 (void) unlink(UFS_SIGNATURE_LIST
".sorted");
7356 (void) unlink(UFS_SIGNATURE_LIST
".tmp");
7360 (void) unlink(UFS_SIGNATURE_LIST
".tmp");
7362 ret
= rename(UFS_SIGNATURE_LIST
".sorted", UFS_SIGNATURE_LIST
);
7364 INJECT_ERROR1("ADD_TO_SIGN_LIST_RENAME2", ret
= -1);
7366 bam_error(RENAME_FAIL
, UFS_SIGNATURE_LIST
, strerror(error
));
7367 (void) unlink(UFS_SIGNATURE_LIST
".sorted");
7371 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
7377 set_signature(char *osroot
, char *osdev
, char *sign
, char *fstype
)
7380 const char *fcn
= "set_signature()";
7382 BAM_DPRINTF((D_FUNC_ENTRY4
, fcn
, osroot
, osdev
, sign
, fstype
));
7384 ret
= set_backup(osroot
, osdev
, sign
, fstype
);
7385 INJECT_ERROR1("SET_SIGNATURE_BACKUP", ret
= -1);
7387 BAM_DPRINTF((D_RETURN_FAILURE
, fcn
));
7388 bam_error(SET_BACKUP_FAILED
, sign
, osroot
, osdev
);
7392 ret
= set_primary(osroot
, osdev
, sign
, fstype
);
7393 INJECT_ERROR1("SET_SIGNATURE_PRIMARY", ret
= -1);
7396 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
7398 BAM_DPRINTF((D_RETURN_FAILURE
, fcn
));
7399 bam_error(SET_PRIMARY_FAILED
, sign
, osroot
, osdev
);
7406 get_grubsign(char *osroot
, char *osdev
)
7408 char *grubsign
; /* (<sign>,#,#) */
7414 const char *fcn
= "get_grubsign()";
7416 BAM_DPRINTF((D_FUNC_ENTRY2
, fcn
, osroot
, osdev
));
7417 fstype
= get_fstype(osroot
);
7418 INJECT_ERROR1("GET_GRUBSIGN_FSTYPE", fstype
= NULL
);
7419 if (fstype
== NULL
) {
7420 bam_error(GET_FSTYPE_FAILED
, osroot
);
7424 sign
= find_existing_sign(osroot
, osdev
, fstype
);
7425 INJECT_ERROR1("FIND_EXISTING_SIGN", sign
= NULL
);
7427 BAM_DPRINTF((D_GET_GRUBSIGN_NO_EXISTING
, fcn
, osroot
, osdev
));
7428 sign
= create_new_sign(osdev
, fstype
);
7429 INJECT_ERROR1("CREATE_NEW_SIGN", sign
= NULL
);
7431 bam_error(GRUBSIGN_CREATE_FAIL
, osdev
);
7437 ret
= set_signature(osroot
, osdev
, sign
, fstype
);
7438 INJECT_ERROR1("SET_SIGNATURE_FAIL", ret
= -1);
7440 bam_error(GRUBSIGN_WRITE_FAIL
, osdev
);
7443 (void) unlink(UFS_SIGNATURE_LIST
);
7450 bam_print(GRUBSIGN_FOUND_OR_CREATED
, sign
, osdev
);
7452 fdiskpart
= get_partition(osdev
);
7453 INJECT_ERROR1("GET_GRUBSIGN_FDISK", fdiskpart
= PARTNO_NOTFOUND
);
7454 if (fdiskpart
== PARTNO_NOTFOUND
) {
7455 bam_error(FDISKPART_FAIL
, osdev
);
7460 slice
= strrchr(osdev
, 's');
7462 if (fdiskpart
== PARTNO_EFI
) {
7463 fdiskpart
= atoi(&slice
[1]);
7467 grubsign
= s_calloc(1, MAXNAMELEN
+ 10);
7469 (void) snprintf(grubsign
, MAXNAMELEN
+ 10, "(%s,%d,%c)",
7470 sign
, fdiskpart
, slice
[1] + 'a' - '0');
7472 (void) snprintf(grubsign
, MAXNAMELEN
+ 10, "(%s,%d)",
7477 BAM_DPRINTF((D_GET_GRUBSIGN_SUCCESS
, fcn
, grubsign
));
7483 get_title(char *rootdir
)
7485 static char title
[80];
7487 char release
[PATH_MAX
];
7489 const char *fcn
= "get_title()";
7491 /* open the /etc/release file */
7492 (void) snprintf(release
, sizeof (release
), "%s/etc/release", rootdir
);
7494 fp
= fopen(release
, "r");
7496 bam_error(OPEN_FAIL
, release
, strerror(errno
));
7501 /* grab first line of /etc/release */
7502 cp
= s_fgets(title
, sizeof (title
), fp
);
7504 while (isspace(*cp
)) /* remove leading spaces */
7511 cp
= cp
? cp
: "Oracle Solaris";
7513 BAM_DPRINTF((D_GET_TITLE
, fcn
, cp
));
7519 get_special(char *mountp
)
7522 struct mnttab mp
= {0};
7523 struct mnttab mpref
= {0};
7526 const char *fcn
= "get_special()";
7528 INJECT_ERROR1("GET_SPECIAL_MNTPT", mountp
= NULL
);
7529 if (mountp
== NULL
) {
7530 bam_error(GET_SPECIAL_NULL_MNTPT
);
7534 mntfp
= fopen(MNTTAB
, "r");
7536 INJECT_ERROR1("GET_SPECIAL_MNTTAB_OPEN", mntfp
= NULL
);
7537 if (mntfp
== NULL
) {
7538 bam_error(OPEN_FAIL
, MNTTAB
, strerror(error
));
7542 if (*mountp
== '\0')
7543 mpref
.mnt_mountp
= "/";
7545 mpref
.mnt_mountp
= mountp
;
7547 ret
= getmntany(mntfp
, &mp
, &mpref
);
7548 INJECT_ERROR1("GET_SPECIAL_MNTTAB_SEARCH", ret
= 1);
7550 (void) fclose(mntfp
);
7551 BAM_DPRINTF((D_GET_SPECIAL_NOT_IN_MNTTAB
, fcn
, mountp
));
7554 (void) fclose(mntfp
);
7556 BAM_DPRINTF((D_GET_SPECIAL
, fcn
, mp
.mnt_special
));
7558 return (s_strdup(mp
.mnt_special
));
7562 free_physarray(char **physarray
, int n
)
7565 const char *fcn
= "free_physarray()";
7570 BAM_DPRINTF((D_FUNC_ENTRY_N1
, fcn
, n
));
7572 for (i
= 0; i
< n
; i
++) {
7577 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
7581 zfs_get_physical(char *special
, char ***physarray
, int *n
)
7583 char sdup
[PATH_MAX
];
7587 filelist_t flist
= {0};
7593 const char *fcn
= "zfs_get_physical()";
7597 BAM_DPRINTF((D_FUNC_ENTRY1
, fcn
, special
));
7599 INJECT_ERROR1("INVALID_ZFS_SPECIAL", special
= "/foo");
7600 if (special
[0] == '/') {
7601 bam_error(INVALID_ZFS_SPECIAL
, special
);
7605 (void) strlcpy(sdup
, special
, sizeof (sdup
));
7607 pool
= strtok(sdup
, "/");
7608 INJECT_ERROR1("ZFS_GET_PHYS_POOL", pool
= NULL
);
7610 bam_error(CANT_FIND_POOL_FROM_SPECIAL
, special
);
7614 (void) snprintf(cmd
, sizeof (cmd
), "/sbin/zpool status %s", pool
);
7616 ret
= exec_cmd(cmd
, &flist
);
7617 INJECT_ERROR1("ZFS_GET_PHYS_STATUS", ret
= 1);
7619 bam_error(ZFS_GET_POOL_STATUS
, pool
);
7623 INJECT_ERROR1("ZFS_GET_PHYS_STATUS_OUT", flist
.head
= NULL
);
7624 if (flist
.head
== NULL
) {
7625 bam_error(BAD_ZPOOL_STATUS
, pool
);
7626 filelist_free(&flist
);
7630 for (lp
= flist
.head
; lp
; lp
= lp
->next
) {
7631 BAM_DPRINTF((D_STRTOK_ZPOOL_STATUS
, fcn
, lp
->line
));
7632 comp1
= strtok(lp
->line
, " \t");
7633 if (comp1
== NULL
) {
7637 comp1
= s_strdup(comp1
);
7643 for (lp
= flist
.head
; lp
; lp
= lp
->next
) {
7644 if (lp
->line
== NULL
)
7646 if (strcmp(lp
->line
, pool
) == 0) {
7647 BAM_DPRINTF((D_FOUND_POOL_IN_ZPOOL_STATUS
, fcn
, pool
));
7653 bam_error(NO_POOL_IN_ZPOOL_STATUS
, pool
);
7654 filelist_free(&flist
);
7659 for (i
= 0, lp
= startlp
; lp
; lp
= lp
->next
) {
7660 if (lp
->line
== NULL
)
7662 if (strcmp(lp
->line
, "mirror") == 0)
7664 if (lp
->line
[0] == '\0' || strcmp(lp
->line
, "errors:") == 0)
7667 BAM_DPRINTF((D_COUNTING_ZFS_PHYS
, fcn
, i
));
7671 bam_error(NO_PHYS_IN_ZPOOL_STATUS
, pool
);
7672 filelist_free(&flist
);
7677 *physarray
= s_calloc(*n
, sizeof (char *));
7678 for (i
= 0, lp
= startlp
; lp
; lp
= lp
->next
) {
7679 if (lp
->line
== NULL
)
7681 if (strcmp(lp
->line
, "mirror") == 0)
7683 if (strcmp(lp
->line
, "errors:") == 0)
7685 if (strncmp(lp
->line
, "/dev/dsk/", strlen("/dev/dsk/")) != 0 &&
7686 strncmp(lp
->line
, "/dev/rdsk/",
7687 strlen("/dev/rdsk/")) != 0) {
7688 (void) snprintf(dsk
, sizeof (dsk
), "/dev/rdsk/%s",
7691 (void) strlcpy(dsk
, lp
->line
, sizeof (dsk
));
7693 BAM_DPRINTF((D_ADDING_ZFS_PHYS
, fcn
, dsk
, pool
));
7694 (*physarray
)[i
++] = s_strdup(dsk
);
7699 filelist_free(&flist
);
7701 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
7706 * Certain services needed to run metastat successfully may not
7707 * be enabled. Enable them now.
7710 * Checks if the specified service is online
7711 * Returns: 1 if the service is online
7712 * 0 if the service is not online
7716 is_svc_online(char *svc
)
7719 const char *fcn
= "is_svc_online()";
7721 BAM_DPRINTF((D_FUNC_ENTRY1
, fcn
, svc
));
7723 state
= smf_get_state(svc
);
7724 INJECT_ERROR2("GET_SVC_STATE", free(state
), state
= NULL
);
7725 if (state
== NULL
) {
7726 bam_error(GET_SVC_STATE_ERR
, svc
);
7729 BAM_DPRINTF((D_GOT_SVC_STATUS
, fcn
, svc
));
7731 if (strcmp(state
, SCF_STATE_STRING_ONLINE
) == 0) {
7732 BAM_DPRINTF((D_SVC_ONLINE
, fcn
, svc
));
7737 BAM_DPRINTF((D_SVC_NOT_ONLINE
, fcn
, state
, svc
));
7745 enable_svc(char *svc
)
7749 const char *fcn
= "enable_svc()";
7751 ret
= is_svc_online(svc
);
7753 bam_error(SVC_IS_ONLINE_FAILED
, svc
);
7755 } else if (ret
== 1) {
7756 BAM_DPRINTF((D_SVC_ALREADY_ONLINE
, fcn
, svc
));
7760 /* Service is not enabled. Enable it now. */
7761 ret
= smf_enable_instance(svc
, 0);
7762 INJECT_ERROR1("ENABLE_SVC_FAILED", ret
= -1);
7764 bam_error(ENABLE_SVC_FAILED
, svc
);
7768 BAM_DPRINTF((D_SVC_ONLINE_INITIATED
, fcn
, svc
));
7772 ret
= is_svc_online(svc
);
7773 INJECT_ERROR1("SVC_ONLINE_SUCCESS", ret
= 1);
7774 INJECT_ERROR1("SVC_ONLINE_FAILURE", ret
= -1);
7775 INJECT_ERROR1("SVC_ONLINE_NOTYET", ret
= 0);
7777 bam_error(ERR_SVC_GET_ONLINE
, svc
);
7779 } else if (ret
== 1) {
7780 BAM_DPRINTF((D_SVC_NOW_ONLINE
, fcn
, svc
));
7784 } while (++sleeptime
< 60);
7786 bam_error(TIMEOUT_ENABLE_SVC
, svc
);
7792 ufs_get_physical(char *special
, char ***physarray
, int *n
)
7796 filelist_t flist
= {0};
7807 const char *fcn
= "ufs_get_physical()";
7811 BAM_DPRINTF((D_FUNC_ENTRY1
, fcn
, special
));
7813 if (strncmp(special
, "/dev/md/", strlen("/dev/md/")) != 0) {
7814 bam_error(UFS_GET_PHYS_NOT_SVM
, special
);
7818 if (strncmp(special
, "/dev/md/dsk/", strlen("/dev/md/dsk/")) == 0) {
7819 shortname
= special
+ strlen("/dev/md/dsk/");
7820 } else if (strncmp(special
, "/dev/md/rdsk/",
7821 strlen("/dev/md/rdsk/")) == 0) {
7822 shortname
= special
+ strlen("/dev/md/rdsk");
7824 bam_error(UFS_GET_PHYS_INVALID_SVM
, special
);
7828 BAM_DPRINTF((D_UFS_SVM_SHORT
, fcn
, special
, shortname
));
7830 svc
= "network/rpc/meta:default";
7831 if (enable_svc(svc
) == -1) {
7832 bam_error(UFS_SVM_METASTAT_SVC_ERR
, svc
);
7835 (void) snprintf(cmd
, sizeof (cmd
), "/sbin/metastat -p %s", shortname
);
7837 ret
= exec_cmd(cmd
, &flist
);
7838 INJECT_ERROR1("UFS_SVM_METASTAT", ret
= 1);
7840 bam_error(UFS_SVM_METASTAT_ERR
, shortname
);
7844 INJECT_ERROR1("UFS_SVM_METASTAT_OUT", flist
.head
= NULL
);
7845 if (flist
.head
== NULL
) {
7846 bam_error(BAD_UFS_SVM_METASTAT
, shortname
);
7847 filelist_free(&flist
);
7852 * Check if not a mirror. We only parse a single metadevice
7855 meta
= strtok(flist
.head
->line
, " \t");
7856 type
= strtok(NULL
, " \t");
7857 if (meta
== NULL
|| type
== NULL
) {
7858 bam_error(ERROR_PARSE_UFS_SVM_METASTAT
, shortname
);
7859 filelist_free(&flist
);
7862 if (strcmp(type
, "-m") != 0) {
7863 comp1
= strtok(NULL
, " \t");
7864 comp2
= strtok(NULL
, " \t");
7865 if (comp1
== NULL
|| comp2
!= NULL
) {
7866 bam_error(INVALID_UFS_SVM_METASTAT
, shortname
);
7867 filelist_free(&flist
);
7870 BAM_DPRINTF((D_UFS_SVM_ONE_COMP
, fcn
, comp1
, shortname
));
7871 *physarray
= s_calloc(1, sizeof (char *));
7872 (*physarray
)[0] = s_strdup(comp1
);
7874 filelist_free(&flist
);
7879 * Okay we have a mirror. Everything after the first line
7882 for (i
= 0, lp
= flist
.head
->next
; lp
; lp
= lp
->next
) {
7883 if (strstr(lp
->line
, "/dev/dsk/") == NULL
&&
7884 strstr(lp
->line
, "/dev/rdsk/") == NULL
) {
7885 bam_error(CANNOT_PARSE_UFS_SVM_METASTAT
, shortname
);
7886 filelist_free(&flist
);
7892 *physarray
= s_calloc(i
, sizeof (char *));
7895 for (i
= 0, lp
= flist
.head
->next
; lp
; lp
= lp
->next
) {
7896 comp1
= strtok(lp
->line
, " \t");
7897 comp2
= strtok(NULL
, " \t");
7898 comp3
= strtok(NULL
, " \t");
7899 comp4
= strtok(NULL
, " \t");
7901 if (comp3
== NULL
|| comp4
== NULL
||
7902 (strncmp(comp4
, "/dev/dsk/", strlen("/dev/dsk/")) != 0 &&
7903 strncmp(comp4
, "/dev/rdsk/", strlen("/dev/rdsk/")) != 0)) {
7904 bam_error(CANNOT_PARSE_UFS_SVM_SUBMIRROR
, shortname
);
7905 filelist_free(&flist
);
7906 free_physarray(*physarray
, *n
);
7910 (*physarray
)[i
++] = s_strdup(comp4
);
7915 filelist_free(&flist
);
7917 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
7922 get_physical(char *menu_root
, char ***physarray
, int *n
)
7926 const char *fcn
= "get_physical()";
7935 BAM_DPRINTF((D_FUNC_ENTRY1
, fcn
, menu_root
));
7937 /* First get the device special file from /etc/mnttab */
7938 special
= get_special(menu_root
);
7939 INJECT_ERROR1("GET_PHYSICAL_SPECIAL", special
= NULL
);
7940 if (special
== NULL
) {
7941 bam_error(GET_SPECIAL_NULL
, menu_root
);
7945 /* If already a physical device nothing to do */
7946 if (strncmp(special
, "/dev/dsk/", strlen("/dev/dsk/")) == 0 ||
7947 strncmp(special
, "/dev/rdsk/", strlen("/dev/rdsk/")) == 0) {
7948 BAM_DPRINTF((D_GET_PHYSICAL_ALREADY
, fcn
, menu_root
, special
));
7949 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
7950 *physarray
= s_calloc(1, sizeof (char *));
7951 (*physarray
)[0] = special
;
7956 if (is_zfs(menu_root
)) {
7957 ret
= zfs_get_physical(special
, physarray
, n
);
7958 } else if (is_ufs(menu_root
)) {
7959 ret
= ufs_get_physical(special
, physarray
, n
);
7961 bam_error(GET_PHYSICAL_NOTSUP_FSTYPE
, menu_root
, special
);
7967 INJECT_ERROR1("GET_PHYSICAL_RET", ret
= -1);
7969 BAM_DPRINTF((D_RETURN_FAILURE
, fcn
));
7973 for (i
= 0; i
< *n
; i
++) {
7974 BAM_DPRINTF((D_GET_PHYSICAL_RET
, fcn
, (*physarray
)[i
]));
7982 is_bootdisk(char *osroot
, char *physical
)
7987 const char *fcn
= "is_bootdisk()";
7992 BAM_DPRINTF((D_FUNC_ENTRY2
, fcn
, osroot
, physical
));
7994 bootp
= strstr(physical
, "p0:boot");
7998 * We just want the BIOS mapping for menu disk.
7999 * Don't pass menu_root to get_grubroot() as the
8000 * check that it is used for is not relevant here.
8001 * The osroot is immaterial as well - it is only used to
8002 * to find create_diskmap script. Everything hinges on
8005 grubroot
= get_grubroot(osroot
, physical
, NULL
);
8007 INJECT_ERROR1("IS_BOOTDISK_GRUBROOT", grubroot
= NULL
);
8008 if (grubroot
== NULL
) {
8010 bam_error(NO_GRUBROOT_FOR_DISK
, physical
);
8013 ret
= grubroot
[3] == '0';
8016 BAM_DPRINTF((D_RETURN_RET
, fcn
, ret
));
8022 * Check if menu is on the boot device
8023 * Return 0 (false) on error
8026 menu_on_bootdisk(char *osroot
, char *menu_root
)
8033 const char *fcn
= "menu_on_bootdisk()";
8035 BAM_DPRINTF((D_FUNC_ENTRY2
, fcn
, osroot
, menu_root
));
8037 ret
= get_physical(menu_root
, &physarray
, &n
);
8038 INJECT_ERROR1("MENU_ON_BOOTDISK_PHYSICAL", ret
= -1);
8040 bam_error(GET_PHYSICAL_MENU_NULL
, menu_root
);
8048 for (i
= 0; i
< n
; i
++) {
8049 assert(strncmp(physarray
[i
], "/dev/dsk/",
8050 strlen("/dev/dsk/")) == 0 ||
8051 strncmp(physarray
[i
], "/dev/rdsk/",
8052 strlen("/dev/rdsk/")) == 0);
8054 BAM_DPRINTF((D_CHECK_ON_BOOTDISK
, fcn
, physarray
[i
]));
8055 if (is_bootdisk(osroot
, physarray
[i
])) {
8057 BAM_DPRINTF((D_IS_ON_BOOTDISK
, fcn
, physarray
[i
]));
8061 free_physarray(physarray
, n
);
8063 INJECT_ERROR1("ON_BOOTDISK_YES", on_bootdisk
= 1);
8064 INJECT_ERROR1("ON_BOOTDISK_NO", on_bootdisk
= 0);
8066 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
8068 BAM_DPRINTF((D_RETURN_FAILURE
, fcn
));
8071 return (on_bootdisk
);
8075 bam_add_line(menu_t
*mp
, entry_t
*entry
, line_t
*prev
, line_t
*lp
)
8077 const char *fcn
= "bam_add_line()";
8084 lp
->next
= prev
->next
;
8086 BAM_DPRINTF((D_ADD_LINE_PREV_NEXT
, fcn
));
8087 prev
->next
->prev
= lp
;
8089 BAM_DPRINTF((D_ADD_LINE_NOT_PREV_NEXT
, fcn
));
8094 if (entry
->end
== prev
) {
8095 BAM_DPRINTF((D_ADD_LINE_LAST_LINE_IN_ENTRY
, fcn
));
8098 if (mp
->end
== prev
) {
8099 assert(lp
->next
== NULL
);
8101 BAM_DPRINTF((D_ADD_LINE_LAST_LINE_IN_MENU
, fcn
));
8106 * look for matching bootadm entry with specified parameters
8107 * Here are the rules (based on existing usage):
8108 * - If title is specified, match on title only
8109 * - Else, match on root/findroot, kernel, and module.
8110 * Note that, if root_opt is non-zero, the absence of
8111 * root line is considered a match.
8127 const char *fcn
= "find_boot_entry()";
8130 *entry_num
= BAM_ERROR
;
8132 /* find matching entry */
8133 for (i
= 0, ent
= mp
->entries
; ent
; i
++, ent
= ent
->next
) {
8136 /* first line of entry must be bootadm comment */
8138 if (lp
->flags
!= BAM_COMMENT
||
8139 strcmp(lp
->arg
, BAM_BOOTADM_HDR
) != 0) {
8143 /* advance to title line */
8146 if (lp
->flags
== BAM_TITLE
&& lp
->arg
&&
8147 strcmp(lp
->arg
, title
) == 0) {
8148 BAM_DPRINTF((D_MATCHED_TITLE
, fcn
, title
));
8151 BAM_DPRINTF((D_NOMATCH_TITLE
, fcn
, title
, lp
->arg
));
8152 continue; /* check title only */
8155 lp
= lp
->next
; /* advance to root line */
8158 } else if (lp
->cmd
!= NULL
&&
8159 strcmp(lp
->cmd
, menu_cmds
[FINDROOT_CMD
]) == 0) {
8160 INJECT_ERROR1("FIND_BOOT_ENTRY_NULL_FINDROOT",
8162 if (findroot
== NULL
) {
8163 BAM_DPRINTF((D_NOMATCH_FINDROOT_NULL
,
8167 /* findroot command found, try match */
8168 if (strcmp(lp
->arg
, findroot
) != 0) {
8169 BAM_DPRINTF((D_NOMATCH_FINDROOT
,
8170 fcn
, findroot
, lp
->arg
));
8173 BAM_DPRINTF((D_MATCHED_FINDROOT
, fcn
, findroot
));
8174 lp
= lp
->next
; /* advance to kernel line */
8175 } else if (lp
->cmd
!= NULL
&&
8176 strcmp(lp
->cmd
, menu_cmds
[ROOT_CMD
]) == 0) {
8177 INJECT_ERROR1("FIND_BOOT_ENTRY_NULL_ROOT", root
= NULL
);
8179 BAM_DPRINTF((D_NOMATCH_ROOT_NULL
,
8183 /* root cmd found, try match */
8184 if (strcmp(lp
->arg
, root
) != 0) {
8185 BAM_DPRINTF((D_NOMATCH_ROOT
,
8186 fcn
, root
, lp
->arg
));
8189 BAM_DPRINTF((D_MATCHED_ROOT
, fcn
, root
));
8190 lp
= lp
->next
; /* advance to kernel line */
8192 INJECT_ERROR1("FIND_BOOT_ENTRY_ROOT_OPT_NO",
8194 INJECT_ERROR1("FIND_BOOT_ENTRY_ROOT_OPT_YES",
8196 /* no root command, see if root is optional */
8197 if (root_opt
== 0) {
8198 BAM_DPRINTF((D_NO_ROOT_OPT
, fcn
));
8201 BAM_DPRINTF((D_ROOT_OPT
, fcn
));
8204 if (lp
== NULL
|| lp
->next
== NULL
) {
8209 (!check_cmd(lp
->cmd
, KERNEL_CMD
, lp
->arg
, kernel
))) {
8210 if (!(ent
->flags
& BAM_ENTRY_FAILSAFE
) ||
8211 !(ent
->flags
& BAM_ENTRY_DBOOT
) ||
8212 strcmp(kernel
, DIRECT_BOOT_FAILSAFE_LINE
) != 0)
8215 ent
->flags
|= BAM_ENTRY_UPGFSKERNEL
;
8218 BAM_DPRINTF((D_KERNEL_MATCH
, fcn
, kernel
, lp
->arg
));
8221 * Check for matching module entry (failsafe or normal).
8222 * If it fails to match, we go around the loop again.
8223 * For xpv entries, there are two module lines, so we
8224 * do the check twice.
8226 lp
= lp
->next
; /* advance to module line */
8227 if (check_cmd(lp
->cmd
, MODULE_CMD
, lp
->arg
, module
) ||
8228 (((lp
= lp
->next
) != NULL
) &&
8229 check_cmd(lp
->cmd
, MODULE_CMD
, lp
->arg
, module
))) {
8231 BAM_DPRINTF((D_MODULE_MATCH
, fcn
, module
, lp
->arg
));
8235 if (strcmp(module
, FAILSAFE_ARCHIVE
) == 0 &&
8236 (strcmp(lp
->prev
->arg
, FAILSAFE_ARCHIVE_32
) == 0 ||
8237 strcmp(lp
->prev
->arg
, FAILSAFE_ARCHIVE_64
) == 0)) {
8238 ent
->flags
|= BAM_ENTRY_UPGFSMODULE
;
8244 if (ent
&& entry_num
) {
8249 BAM_DPRINTF((D_RETURN_RET
, fcn
, i
));
8251 BAM_DPRINTF((D_RETURN_RET
, fcn
, BAM_ERROR
));
8257 update_boot_entry(menu_t
*mp
, char *title
, char *findroot
, char *root
,
8258 char *kernel
, char *mod_kernel
, char *module
, int root_opt
)
8261 int change_kernel
= 0;
8265 char linebuf
[BAM_MAXLINE
];
8266 const char *fcn
= "update_boot_entry()";
8268 /* note: don't match on title, it's updated on upgrade */
8269 ent
= find_boot_entry(mp
, NULL
, kernel
, findroot
, root
, module
,
8271 if ((ent
== NULL
) && (bam_direct
== BAM_DIRECT_DBOOT
)) {
8273 * We may be upgrading a kernel from multiboot to
8274 * directboot. Look for a multiboot entry. A multiboot
8275 * entry will not have a findroot line.
8277 ent
= find_boot_entry(mp
, NULL
, "multiboot", NULL
, root
,
8278 MULTIBOOT_ARCHIVE
, root_opt
, &i
);
8280 BAM_DPRINTF((D_UPGRADE_FROM_MULTIBOOT
, fcn
, root
));
8284 BAM_DPRINTF((D_FOUND_FINDROOT
, fcn
, findroot
));
8288 BAM_DPRINTF((D_ENTRY_NOT_FOUND_CREATING
, fcn
, findroot
));
8289 return (add_boot_entry(mp
, title
, findroot
,
8290 kernel
, mod_kernel
, module
, NULL
));
8293 /* replace title of existing entry and update findroot line */
8295 lp
= lp
->next
; /* title line */
8296 (void) snprintf(linebuf
, sizeof (linebuf
), "%s%s%s",
8297 menu_cmds
[TITLE_CMD
], menu_cmds
[SEP_CMD
], title
);
8300 lp
->arg
= s_strdup(title
);
8301 lp
->line
= s_strdup(linebuf
);
8302 BAM_DPRINTF((D_CHANGING_TITLE
, fcn
, title
));
8304 tlp
= lp
; /* title line */
8305 lp
= lp
->next
; /* root line */
8307 /* if no root or findroot command, create a new line_t */
8308 if ((lp
->cmd
!= NULL
) && (strcmp(lp
->cmd
, menu_cmds
[ROOT_CMD
]) != 0 &&
8309 strcmp(lp
->cmd
, menu_cmds
[FINDROOT_CMD
]) != 0)) {
8310 lp
= s_calloc(1, sizeof (line_t
));
8311 bam_add_line(mp
, ent
, tlp
, lp
);
8313 if (lp
->cmd
!= NULL
)
8321 lp
->cmd
= s_strdup(menu_cmds
[FINDROOT_CMD
]);
8322 lp
->sep
= s_strdup(menu_cmds
[SEP_CMD
]);
8323 lp
->arg
= s_strdup(findroot
);
8324 (void) snprintf(linebuf
, sizeof (linebuf
), "%s%s%s",
8325 menu_cmds
[FINDROOT_CMD
], menu_cmds
[SEP_CMD
], findroot
);
8326 lp
->line
= s_strdup(linebuf
);
8327 BAM_DPRINTF((D_ADDING_FINDROOT_LINE
, fcn
, findroot
));
8332 if (ent
->flags
& BAM_ENTRY_UPGFSKERNEL
) {
8333 char *params
= NULL
;
8335 params
= strstr(lp
->line
, "-s");
8337 (void) snprintf(linebuf
, sizeof (linebuf
), "%s%s%s%s",
8338 menu_cmds
[KERNEL_DOLLAR_CMD
], menu_cmds
[SEP_CMD
],
8341 (void) snprintf(linebuf
, sizeof (linebuf
), "%s%s%s",
8342 menu_cmds
[KERNEL_DOLLAR_CMD
], menu_cmds
[SEP_CMD
],
8345 if (lp
->cmd
!= NULL
)
8350 lp
->cmd
= s_strdup(menu_cmds
[KERNEL_DOLLAR_CMD
]);
8351 lp
->arg
= s_strdup(strstr(linebuf
, "/"));
8352 lp
->line
= s_strdup(linebuf
);
8353 ent
->flags
&= ~BAM_ENTRY_UPGFSKERNEL
;
8354 BAM_DPRINTF((D_ADDING_KERNEL_DOLLAR
, fcn
, lp
->prev
->cmd
));
8357 if (change_kernel
) {
8359 * We're upgrading from multiboot to directboot.
8361 if (lp
->cmd
!= NULL
&&
8362 strcmp(lp
->cmd
, menu_cmds
[KERNEL_CMD
]) == 0) {
8363 (void) snprintf(linebuf
, sizeof (linebuf
), "%s%s%s",
8364 menu_cmds
[KERNEL_DOLLAR_CMD
], menu_cmds
[SEP_CMD
],
8369 lp
->cmd
= s_strdup(menu_cmds
[KERNEL_DOLLAR_CMD
]);
8370 lp
->arg
= s_strdup(kernel
);
8371 lp
->line
= s_strdup(linebuf
);
8373 BAM_DPRINTF((D_ADDING_KERNEL_DOLLAR
, fcn
, kernel
));
8375 if (lp
->cmd
!= NULL
&&
8376 strcmp(lp
->cmd
, menu_cmds
[MODULE_CMD
]) == 0) {
8377 (void) snprintf(linebuf
, sizeof (linebuf
), "%s%s%s",
8378 menu_cmds
[MODULE_DOLLAR_CMD
], menu_cmds
[SEP_CMD
],
8383 lp
->cmd
= s_strdup(menu_cmds
[MODULE_DOLLAR_CMD
]);
8384 lp
->arg
= s_strdup(module
);
8385 lp
->line
= s_strdup(linebuf
);
8387 BAM_DPRINTF((D_ADDING_MODULE_DOLLAR
, fcn
, module
));
8394 if (ent
->flags
& BAM_ENTRY_UPGFSMODULE
) {
8395 if (lp
->cmd
!= NULL
&&
8396 strcmp(lp
->cmd
, menu_cmds
[MODULE_CMD
]) == 0) {
8397 (void) snprintf(linebuf
, sizeof (linebuf
), "%s%s%s",
8398 menu_cmds
[MODULE_DOLLAR_CMD
], menu_cmds
[SEP_CMD
],
8403 lp
->cmd
= s_strdup(menu_cmds
[MODULE_DOLLAR_CMD
]);
8404 lp
->arg
= s_strdup(module
);
8405 lp
->line
= s_strdup(linebuf
);
8407 ent
->flags
&= ~BAM_ENTRY_UPGFSMODULE
;
8408 BAM_DPRINTF((D_ADDING_MODULE_DOLLAR
, fcn
, module
));
8412 BAM_DPRINTF((D_RETURN_RET
, fcn
, i
));
8417 root_optional(char *osroot
, char *menu_root
)
8425 const char *fcn
= "root_optional()";
8427 BAM_DPRINTF((D_FUNC_ENTRY2
, fcn
, osroot
, menu_root
));
8430 * For all filesystems except ZFS, a straight compare of osroot
8431 * and menu_root will tell us if root is optional.
8432 * For ZFS, the situation is complicated by the fact that
8433 * menu_root and osroot are always different
8435 ret1
= is_zfs(osroot
);
8436 ret2
= is_zfs(menu_root
);
8437 INJECT_ERROR1("ROOT_OPT_NOT_ZFS", ret1
= 0);
8438 if (!ret1
|| !ret2
) {
8439 BAM_DPRINTF((D_ROOT_OPT_NOT_ZFS
, fcn
, osroot
, menu_root
));
8440 root_opt
= (strcmp(osroot
, menu_root
) == 0);
8444 ospecial
= get_special(osroot
);
8445 INJECT_ERROR1("ROOT_OPTIONAL_OSPECIAL", ospecial
= NULL
);
8446 if (ospecial
== NULL
) {
8447 bam_error(GET_OSROOT_SPECIAL_ERR
, osroot
);
8450 BAM_DPRINTF((D_ROOT_OPTIONAL_OSPECIAL
, fcn
, ospecial
, osroot
));
8452 mspecial
= get_special(menu_root
);
8453 INJECT_ERROR1("ROOT_OPTIONAL_MSPECIAL", mspecial
= NULL
);
8454 if (mspecial
== NULL
) {
8455 bam_error(GET_MENU_ROOT_SPECIAL_ERR
, menu_root
);
8459 BAM_DPRINTF((D_ROOT_OPTIONAL_MSPECIAL
, fcn
, mspecial
, menu_root
));
8461 slash
= strchr(ospecial
, '/');
8464 BAM_DPRINTF((D_ROOT_OPTIONAL_FIXED_OSPECIAL
, fcn
, ospecial
, osroot
));
8466 root_opt
= (strcmp(ospecial
, mspecial
) == 0);
8472 INJECT_ERROR1("ROOT_OPTIONAL_NO", root_opt
= 0);
8473 INJECT_ERROR1("ROOT_OPTIONAL_YES", root_opt
= 1);
8475 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
8477 BAM_DPRINTF((D_RETURN_FAILURE
, fcn
));
8485 update_entry(menu_t
*mp
, char *menu_root
, char *osdev
)
8491 char osroot
[PATH_MAX
];
8492 char *failsafe_kernel
= NULL
;
8495 char failsafe_64
[256];
8497 const char *fcn
= "update_entry()";
8504 BAM_DPRINTF((D_FUNC_ENTRY3
, fcn
, menu_root
, osdev
, bam_root
));
8506 (void) strlcpy(osroot
, bam_root
, sizeof (osroot
));
8508 title
= get_title(osroot
);
8511 grubsign
= get_grubsign(osroot
, osdev
);
8512 INJECT_ERROR1("GET_GRUBSIGN_FAIL", grubsign
= NULL
);
8513 if (grubsign
== NULL
) {
8514 bam_error(GET_GRUBSIGN_ERROR
, osroot
, osdev
);
8519 * It is not a fatal error if get_grubroot() fails
8520 * We no longer rely on biosdev to populate the
8523 grubroot
= get_grubroot(osroot
, osdev
, menu_root
);
8524 INJECT_ERROR1("GET_GRUBROOT_FAIL", grubroot
= NULL
);
8526 BAM_DPRINTF((D_GET_GRUBROOT_SUCCESS
,
8527 fcn
, osroot
, osdev
, menu_root
));
8529 BAM_DPRINTF((D_GET_GRUBROOT_FAILURE
,
8530 fcn
, osroot
, osdev
, menu_root
));
8533 /* add the entry for normal Solaris */
8534 INJECT_ERROR1("UPDATE_ENTRY_MULTIBOOT",
8535 bam_direct
= BAM_DIRECT_MULTIBOOT
);
8536 if (bam_direct
== BAM_DIRECT_DBOOT
) {
8537 entry
= update_boot_entry(mp
, title
, grubsign
, grubroot
,
8538 (bam_zfs
? DIRECT_BOOT_KERNEL_ZFS
: DIRECT_BOOT_KERNEL
),
8539 NULL
, DIRECT_BOOT_ARCHIVE
,
8540 root_optional(osroot
, menu_root
));
8541 BAM_DPRINTF((D_UPDATED_BOOT_ENTRY
, fcn
, bam_zfs
, grubsign
));
8542 if ((entry
!= BAM_ERROR
) && (bam_is_hv
== BAM_HV_PRESENT
)) {
8543 (void) update_boot_entry(mp
, NEW_HV_ENTRY
, grubsign
,
8544 grubroot
, XEN_MENU
, bam_zfs
?
8545 XEN_KERNEL_MODULE_LINE_ZFS
: XEN_KERNEL_MODULE_LINE
,
8546 DIRECT_BOOT_ARCHIVE
,
8547 root_optional(osroot
, menu_root
));
8548 BAM_DPRINTF((D_UPDATED_HV_ENTRY
,
8549 fcn
, bam_zfs
, grubsign
));
8552 entry
= update_boot_entry(mp
, title
, grubsign
, grubroot
,
8553 MULTI_BOOT
, NULL
, MULTIBOOT_ARCHIVE
,
8554 root_optional(osroot
, menu_root
));
8556 BAM_DPRINTF((D_UPDATED_MULTIBOOT_ENTRY
, fcn
, grubsign
));
8560 * Add the entry for failsafe archive. On a bfu'd system, the
8561 * failsafe may be different than the installed kernel.
8563 (void) snprintf(failsafe
, sizeof (failsafe
), "%s%s",
8564 osroot
, FAILSAFE_ARCHIVE_32
);
8565 (void) snprintf(failsafe_64
, sizeof (failsafe_64
), "%s%s",
8566 osroot
, FAILSAFE_ARCHIVE_64
);
8569 * Check if at least one of the two archives exists
8570 * Using $ISADIR as the default line, we have an entry which works
8571 * for both the cases.
8574 if (stat(failsafe
, &sbuf
) == 0 || stat(failsafe_64
, &sbuf
) == 0) {
8576 /* Figure out where the kernel line should point */
8577 (void) snprintf(failsafe
, sizeof (failsafe
), "%s%s", osroot
,
8578 DIRECT_BOOT_FAILSAFE_32
);
8579 (void) snprintf(failsafe_64
, sizeof (failsafe_64
), "%s%s",
8580 osroot
, DIRECT_BOOT_FAILSAFE_64
);
8581 if (stat(failsafe
, &sbuf
) == 0 ||
8582 stat(failsafe_64
, &sbuf
) == 0) {
8583 failsafe_kernel
= DIRECT_BOOT_FAILSAFE_LINE
;
8585 (void) snprintf(failsafe
, sizeof (failsafe
), "%s%s",
8586 osroot
, MULTI_BOOT_FAILSAFE
);
8587 if (stat(failsafe
, &sbuf
) == 0) {
8588 failsafe_kernel
= MULTI_BOOT_FAILSAFE_LINE
;
8591 if (failsafe_kernel
!= NULL
) {
8592 (void) update_boot_entry(mp
, FAILSAFE_TITLE
, grubsign
,
8593 grubroot
, failsafe_kernel
, NULL
, FAILSAFE_ARCHIVE
,
8594 root_optional(osroot
, menu_root
));
8595 BAM_DPRINTF((D_UPDATED_FAILSAFE_ENTRY
, fcn
,
8601 INJECT_ERROR1("UPDATE_ENTRY_ERROR", entry
= BAM_ERROR
);
8602 if (entry
== BAM_ERROR
) {
8603 bam_error(FAILED_TO_ADD_BOOT_ENTRY
, title
, grubsign
);
8609 update_numbering(mp
);
8610 ret
= set_global(mp
, menu_cmds
[DEFAULT_CMD
], entry
);
8611 INJECT_ERROR1("SET_DEFAULT_ERROR", ret
= BAM_ERROR
);
8612 if (ret
== BAM_ERROR
) {
8613 bam_error(SET_DEFAULT_FAILED
, entry
);
8615 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
8620 save_default_entry(menu_t
*mp
, const char *which
)
8624 int entry
= 0; /* default is 0 */
8625 char linebuf
[BAM_MAXLINE
];
8626 line_t
*lp
= mp
->curdefault
;
8627 const char *fcn
= "save_default_entry()";
8630 lineNum
= mp
->end
->lineNum
;
8631 entryNum
= mp
->end
->entryNum
;
8633 lineNum
= LINE_INIT
;
8634 entryNum
= ENTRY_INIT
;
8638 entry
= s_strtol(lp
->arg
);
8640 (void) snprintf(linebuf
, sizeof (linebuf
), "#%s%d", which
, entry
);
8641 BAM_DPRINTF((D_SAVING_DEFAULT_TO
, fcn
, linebuf
));
8642 line_parser(mp
, linebuf
, &lineNum
, &entryNum
);
8643 BAM_DPRINTF((D_SAVED_DEFAULT_TO
, fcn
, lineNum
, entryNum
));
8647 restore_default_entry(menu_t
*mp
, const char *which
, line_t
*lp
)
8651 const char *fcn
= "restore_default_entry()";
8654 BAM_DPRINTF((D_RESTORE_DEFAULT_NULL
, fcn
));
8655 return; /* nothing to restore */
8658 BAM_DPRINTF((D_RESTORE_DEFAULT_STR
, fcn
, which
));
8660 str
= lp
->arg
+ strlen(which
);
8661 entry
= s_strtol(str
);
8662 (void) set_global(mp
, menu_cmds
[DEFAULT_CMD
], entry
);
8664 BAM_DPRINTF((D_RESTORED_DEFAULT_TO
, fcn
, entry
));
8666 /* delete saved old default line */
8667 unlink_line(mp
, lp
);
8672 * This function is for supporting reboot with args.
8673 * The opt value can be:
8674 * NULL delete temp entry, if present
8675 * entry=<n> switches default entry to <n>
8676 * else treated as boot-args and setup a temperary menu entry
8677 * and make it the default
8678 * Note that we are always rebooting the current OS instance
8679 * so osroot == / always.
8681 #define REBOOT_TITLE "Solaris_reboot_transient"
8685 update_temp(menu_t
*mp
, char *dummy
, char *opt
)
8693 char kernbuf
[BUFSIZ
];
8694 char args_buf
[BUFSIZ
];
8695 char signbuf
[PATH_MAX
];
8697 const char *fcn
= "update_temp()";
8700 assert(dummy
== NULL
);
8702 /* opt can be NULL */
8703 BAM_DPRINTF((D_FUNC_ENTRY1
, fcn
, opt
? opt
: "<NULL>"));
8704 BAM_DPRINTF((D_BAM_ROOT
, fcn
, bam_alt_root
, bam_root
));
8706 if (bam_alt_root
|| bam_rootlen
!= 1 ||
8707 strcmp(bam_root
, "/") != 0 ||
8708 strcmp(rootbuf
, "/") != 0) {
8709 bam_error(ALT_ROOT_INVALID
, bam_root
);
8713 /* If no option, delete exiting reboot menu entry */
8716 BAM_DPRINTF((D_OPT_NULL
, fcn
));
8717 ent
= find_boot_entry(mp
, REBOOT_TITLE
, NULL
, NULL
,
8718 NULL
, NULL
, 0, &entry
);
8719 if (ent
== NULL
) { /* not found is ok */
8720 BAM_DPRINTF((D_TRANSIENT_NOTFOUND
, fcn
));
8721 return (BAM_SUCCESS
);
8723 (void) delete_boot_entry(mp
, entry
, DBE_PRINTERR
);
8724 restore_default_entry(mp
, BAM_OLDDEF
, mp
->olddefault
);
8725 mp
->olddefault
= NULL
;
8726 BAM_DPRINTF((D_RESTORED_DEFAULT
, fcn
));
8727 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
8731 /* if entry= is specified, set the default entry */
8732 if (strncmp(opt
, "entry=", strlen("entry=")) == 0) {
8733 int entryNum
= s_strtol(opt
+ strlen("entry="));
8734 BAM_DPRINTF((D_ENTRY_EQUALS
, fcn
, opt
));
8735 if (selector(mp
, opt
, &entry
, NULL
) == BAM_SUCCESS
) {
8736 /* this is entry=# option */
8737 ret
= set_global(mp
, menu_cmds
[DEFAULT_CMD
], entry
);
8738 BAM_DPRINTF((D_ENTRY_SET_IS
, fcn
, entry
, ret
));
8741 bam_error(SET_DEFAULT_FAILED
, entryNum
);
8747 * add a new menu entry based on opt and make it the default
8750 fstype
= get_fstype("/");
8751 INJECT_ERROR1("REBOOT_FSTYPE_NULL", fstype
= NULL
);
8752 if (fstype
== NULL
) {
8753 bam_error(REBOOT_FSTYPE_FAILED
);
8757 osdev
= get_special("/");
8758 INJECT_ERROR1("REBOOT_SPECIAL_NULL", osdev
= NULL
);
8759 if (osdev
== NULL
) {
8761 bam_error(REBOOT_SPECIAL_FAILED
);
8765 sign
= find_existing_sign("/", osdev
, fstype
);
8766 INJECT_ERROR1("REBOOT_SIGN_NULL", sign
= NULL
);
8770 bam_error(REBOOT_SIGN_FAILED
);
8775 (void) strlcpy(signbuf
, sign
, sizeof (signbuf
));
8778 assert(strchr(signbuf
, '(') == NULL
&& strchr(signbuf
, ',') == NULL
&&
8779 strchr(signbuf
, ')') == NULL
);
8782 * There is no alternate root while doing reboot with args
8783 * This version of bootadm is only delivered with a DBOOT
8784 * version of Solaris.
8786 INJECT_ERROR1("REBOOT_NOT_DBOOT", bam_direct
= BAM_DIRECT_MULTIBOOT
);
8787 if (bam_direct
!= BAM_DIRECT_DBOOT
) {
8789 bam_error(REBOOT_DIRECT_FAILED
);
8793 /* add an entry for Solaris reboot */
8794 if (opt
[0] == '-') {
8795 /* It's an option - first see if boot-file is set */
8796 ret
= get_kernel(mp
, KERNEL_CMD
, kernbuf
, sizeof (kernbuf
));
8797 INJECT_ERROR1("REBOOT_GET_KERNEL", ret
= BAM_ERROR
);
8798 if (ret
!= BAM_SUCCESS
) {
8800 bam_error(REBOOT_GET_KERNEL_FAILED
);
8803 if (kernbuf
[0] == '\0')
8804 (void) strlcpy(kernbuf
, DIRECT_BOOT_KERNEL
,
8807 * If this is a zfs file system and kernbuf does not
8808 * have "-B $ZFS-BOOTFS" string yet, add it.
8810 if (strcmp(fstype
, "zfs") == 0 && !strstr(kernbuf
, ZFS_BOOT
)) {
8811 (void) strlcat(kernbuf
, " ", sizeof (kernbuf
));
8812 (void) strlcat(kernbuf
, ZFS_BOOT
, sizeof (kernbuf
));
8814 (void) strlcat(kernbuf
, " ", sizeof (kernbuf
));
8815 (void) strlcat(kernbuf
, opt
, sizeof (kernbuf
));
8816 BAM_DPRINTF((D_REBOOT_OPTION
, fcn
, kernbuf
));
8817 } else if (opt
[0] == '/') {
8818 /* It's a full path, so write it out. */
8819 (void) strlcpy(kernbuf
, opt
, sizeof (kernbuf
));
8824 * # eeprom boot-args='-kd'
8825 * # reboot /platform/i86pc/kernel/unix
8827 * we want to use the boot-args as part of the boot
8828 * line. On the other hand, if someone runs:
8830 * # reboot "/platform/i86pc/kernel/unix -kd"
8832 * we don't need to mess with boot-args. If there's
8833 * no space in the options string, assume we're in the
8836 if (strchr(opt
, ' ') == NULL
) {
8837 ret
= get_kernel(mp
, ARGS_CMD
, args_buf
,
8839 INJECT_ERROR1("REBOOT_GET_ARGS", ret
= BAM_ERROR
);
8840 if (ret
!= BAM_SUCCESS
) {
8842 bam_error(REBOOT_GET_ARGS_FAILED
);
8846 if (args_buf
[0] != '\0') {
8847 (void) strlcat(kernbuf
, " ", sizeof (kernbuf
));
8848 (void) strlcat(kernbuf
, args_buf
,
8852 BAM_DPRINTF((D_REBOOT_ABSPATH
, fcn
, kernbuf
));
8855 * It may be a partial path, or it may be a partial
8856 * path followed by options. Assume that only options
8857 * follow a space. If someone sends us a kernel path
8858 * that includes a space, they deserve to be broken.
8860 opt_ptr
= strchr(opt
, ' ');
8861 if (opt_ptr
!= NULL
) {
8865 path
= expand_path(opt
);
8867 (void) strlcpy(kernbuf
, path
, sizeof (kernbuf
));
8871 * If there were options given, use those.
8872 * Otherwise, copy over the default options.
8874 if (opt_ptr
!= NULL
) {
8875 /* Restore the space in opt string */
8877 (void) strlcat(kernbuf
, opt_ptr
,
8880 ret
= get_kernel(mp
, ARGS_CMD
, args_buf
,
8882 INJECT_ERROR1("UPDATE_TEMP_PARTIAL_ARGS",
8884 if (ret
!= BAM_SUCCESS
) {
8886 bam_error(REBOOT_GET_ARGS_FAILED
);
8890 if (args_buf
[0] != '\0') {
8891 (void) strlcat(kernbuf
, " ",
8893 (void) strlcat(kernbuf
,
8894 args_buf
, sizeof (kernbuf
));
8897 BAM_DPRINTF((D_REBOOT_RESOLVED_PARTIAL
, fcn
, kernbuf
));
8900 bam_error(UNKNOWN_KERNEL
, opt
);
8901 bam_print_stderr(UNKNOWN_KERNEL_REBOOT
);
8906 entry
= add_boot_entry(mp
, REBOOT_TITLE
, signbuf
, kernbuf
,
8908 INJECT_ERROR1("REBOOT_ADD_BOOT_ENTRY", entry
= BAM_ERROR
);
8909 if (entry
== BAM_ERROR
) {
8910 bam_error(REBOOT_WITH_ARGS_ADD_ENTRY_FAILED
);
8914 save_default_entry(mp
, BAM_OLDDEF
);
8915 ret
= set_global(mp
, menu_cmds
[DEFAULT_CMD
], entry
);
8916 INJECT_ERROR1("REBOOT_SET_GLOBAL", ret
= BAM_ERROR
);
8917 if (ret
== BAM_ERROR
) {
8918 bam_error(REBOOT_SET_DEFAULT_FAILED
, entry
);
8920 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
8925 set_global(menu_t
*mp
, char *globalcmd
, int val
)
8932 char prefix
[BAM_MAXLINE
];
8934 const char *fcn
= "set_global()";
8939 if (strcmp(globalcmd
, menu_cmds
[DEFAULT_CMD
]) == 0) {
8940 INJECT_ERROR1("SET_GLOBAL_VAL_NEG", val
= -1);
8941 INJECT_ERROR1("SET_GLOBAL_MENU_EMPTY", mp
->end
= NULL
);
8942 INJECT_ERROR1("SET_GLOBAL_VAL_TOO_BIG", val
= 100);
8943 if (val
< 0 || mp
->end
== NULL
|| val
> mp
->end
->entryNum
) {
8944 (void) snprintf(prefix
, sizeof (prefix
), "%d", val
);
8945 bam_error(INVALID_ENTRY
, prefix
);
8950 found
= last
= NULL
;
8951 for (lp
= mp
->start
; lp
; lp
= lp
->next
) {
8952 if (lp
->flags
!= BAM_GLOBAL
)
8955 last
= lp
; /* track the last global found */
8957 INJECT_ERROR1("SET_GLOBAL_NULL_CMD", lp
->cmd
= NULL
);
8958 if (lp
->cmd
== NULL
) {
8959 bam_error(NO_CMD
, lp
->lineNum
);
8962 if (strcmp(globalcmd
, lp
->cmd
) != 0)
8965 BAM_DPRINTF((D_FOUND_GLOBAL
, fcn
, globalcmd
));
8968 bam_error(DUP_CMD
, globalcmd
, lp
->lineNum
, bam_root
);
8973 if (found
== NULL
) {
8974 lp
= s_calloc(1, sizeof (line_t
));
8976 lp
->next
= mp
->start
;
8978 mp
->end
= (mp
->end
) ? mp
->end
: lp
;
8980 lp
->next
= last
->next
;
8982 if (lp
->next
== NULL
)
8985 lp
->flags
= BAM_GLOBAL
; /* other fields not needed for writes */
8986 len
= strlen(globalcmd
) + strlen(menu_cmds
[SEP_CMD
]);
8987 len
+= 10; /* val < 10 digits */
8988 lp
->line
= s_calloc(1, len
);
8989 (void) snprintf(lp
->line
, len
, "%s%s%d",
8990 globalcmd
, menu_cmds
[SEP_CMD
], val
);
8991 BAM_DPRINTF((D_SET_GLOBAL_WROTE_NEW
, fcn
, lp
->line
));
8992 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
8997 * We are changing an existing entry. Retain any prefix whitespace,
8998 * but overwrite everything else. This preserves tabs added for
9003 while (*str
== ' ' || *str
== '\t')
9005 *cp
= '\0'; /* Terminate prefix */
9006 len
= strlen(prefix
) + strlen(globalcmd
);
9007 len
+= strlen(menu_cmds
[SEP_CMD
]) + 10;
9010 found
->line
= s_calloc(1, len
);
9011 (void) snprintf(found
->line
, len
,
9012 "%s%s%s%d", prefix
, globalcmd
, menu_cmds
[SEP_CMD
], val
);
9014 BAM_DPRINTF((D_SET_GLOBAL_REPLACED
, fcn
, found
->line
));
9015 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
9016 return (BAM_WRITE
); /* need a write to menu */
9020 * partial_path may be anything like "kernel/unix" or "kmdb". Try to
9021 * expand it to a full unix path. The calling function is expected to
9022 * output a message if an error occurs and NULL is returned.
9025 expand_path(const char *partial_path
)
9029 char new_path2
[PATH_MAX
];
9031 const char *fcn
= "expand_path()";
9033 new_path_len
= strlen(partial_path
) + 64;
9034 new_path
= s_calloc(1, new_path_len
);
9036 /* First, try the simplest case - something like "kernel/unix" */
9037 (void) snprintf(new_path
, new_path_len
, "/platform/i86pc/%s",
9039 if (stat(new_path
, &sb
) == 0) {
9040 BAM_DPRINTF((D_EXPAND_PATH
, fcn
, new_path
));
9044 if (strcmp(partial_path
, "kmdb") == 0) {
9045 (void) snprintf(new_path
, new_path_len
, "%s -k",
9046 DIRECT_BOOT_KERNEL
);
9047 BAM_DPRINTF((D_EXPAND_PATH
, fcn
, new_path
));
9052 * We've quickly reached unsupported usage. Try once more to
9053 * see if we were just given a glom name.
9055 (void) snprintf(new_path
, new_path_len
, "/platform/i86pc/%s/unix",
9057 (void) snprintf(new_path2
, PATH_MAX
, "/platform/i86pc/%s/amd64/unix",
9059 if (stat(new_path
, &sb
) == 0) {
9060 if (stat(new_path2
, &sb
) == 0) {
9062 * We matched both, so we actually
9063 * want to write the $ISADIR version.
9065 (void) snprintf(new_path
, new_path_len
,
9066 "/platform/i86pc/kernel/%s/$ISADIR/unix",
9069 BAM_DPRINTF((D_EXPAND_PATH
, fcn
, new_path
));
9074 BAM_DPRINTF((D_RETURN_FAILURE
, fcn
));
9079 * The kernel cmd and arg have been changed, so
9080 * check whether the archive line needs to change.
9083 set_archive_line(entry_t
*entryp
, line_t
*kernelp
)
9085 line_t
*lp
= entryp
->start
;
9088 const char *fcn
= "set_archive_line()";
9090 for (; lp
!= NULL
; lp
= lp
->next
) {
9091 if (lp
->cmd
!= NULL
&& strncmp(lp
->cmd
, menu_cmds
[MODULE_CMD
],
9092 sizeof (menu_cmds
[MODULE_CMD
]) - 1) == 0) {
9096 INJECT_ERROR1("SET_ARCHIVE_LINE_END_ENTRY", lp
= entryp
->end
);
9097 if (lp
== entryp
->end
) {
9098 BAM_DPRINTF((D_ARCHIVE_LINE_NONE
, fcn
,
9103 INJECT_ERROR1("SET_ARCHIVE_LINE_END_MENU", lp
= NULL
);
9105 BAM_DPRINTF((D_ARCHIVE_LINE_NONE
, fcn
, entryp
->entryNum
));
9109 if (strstr(kernelp
->arg
, "$ISADIR") != NULL
) {
9110 new_archive
= DIRECT_BOOT_ARCHIVE
;
9111 m_cmd
= MODULE_DOLLAR_CMD
;
9112 } else if (strstr(kernelp
->arg
, "amd64") != NULL
) {
9113 new_archive
= DIRECT_BOOT_ARCHIVE_64
;
9116 new_archive
= DIRECT_BOOT_ARCHIVE_32
;
9120 if (strcmp(lp
->arg
, new_archive
) == 0) {
9121 BAM_DPRINTF((D_ARCHIVE_LINE_NOCHANGE
, fcn
, lp
->arg
));
9125 if (lp
->cmd
!= NULL
&& strcmp(lp
->cmd
, menu_cmds
[m_cmd
]) != 0) {
9127 lp
->cmd
= s_strdup(menu_cmds
[m_cmd
]);
9131 lp
->arg
= s_strdup(new_archive
);
9133 BAM_DPRINTF((D_ARCHIVE_LINE_REPLACED
, fcn
, lp
->line
));
9137 * Title for an entry to set properties that once went in bootenv.rc.
9139 #define BOOTENV_RC_TITLE "Solaris bootenv rc"
9142 * If path is NULL, return the kernel (optnum == KERNEL_CMD) or arguments
9143 * (optnum == ARGS_CMD) in the argument buf. If path is a zero-length
9144 * string, reset the value to the default. If path is a non-zero-length
9145 * string, set the kernel or arguments.
9156 int rv
= BAM_SUCCESS
;
9157 int free_new_path
= 0;
9166 size_t old_kernel_len
;
9171 char signbuf
[PATH_MAX
];
9173 const char *fcn
= "get_set_kernel()";
9175 assert(bufsize
> 0);
9177 ptr
= kernelp
= NULL
;
9178 new_arg
= old_args
= space
= NULL
;
9182 INJECT_ERROR1("GET_SET_KERNEL_NOT_DBOOT",
9183 bam_direct
= BAM_DIRECT_MULTIBOOT
);
9184 if (bam_direct
!= BAM_DIRECT_DBOOT
) {
9185 bam_error(NOT_DBOOT
, optnum
== KERNEL_CMD
? "kernel" : "args");
9190 * If a user changed the default entry to a non-bootadm controlled
9191 * one, we don't want to mess with it. Just print an error and
9194 if (mp
->curdefault
) {
9195 entryNum
= s_strtol(mp
->curdefault
->arg
);
9196 for (entryp
= mp
->entries
; entryp
; entryp
= entryp
->next
) {
9197 if (entryp
->entryNum
== entryNum
)
9200 if ((entryp
!= NULL
) &&
9201 ((entryp
->flags
& (BAM_ENTRY_BOOTADM
|BAM_ENTRY_LU
)) == 0)) {
9202 bam_error(DEFAULT_NOT_BAM
);
9207 entryp
= find_boot_entry(mp
, BOOTENV_RC_TITLE
, NULL
, NULL
, NULL
, NULL
,
9210 if (entryp
!= NULL
) {
9211 for (ptr
= entryp
->start
; ptr
&& ptr
!= entryp
->end
;
9213 if (strncmp(ptr
->cmd
, menu_cmds
[KERNEL_CMD
],
9214 sizeof (menu_cmds
[KERNEL_CMD
]) - 1) == 0) {
9219 if (kernelp
== NULL
) {
9220 bam_error(NO_KERNEL
, entryNum
);
9224 old_kernel_len
= strcspn(kernelp
->arg
, " \t");
9225 space
= old_args
= kernelp
->arg
+ old_kernel_len
;
9226 while ((*old_args
== ' ') || (*old_args
== '\t'))
9231 if (entryp
== NULL
) {
9232 BAM_DPRINTF((D_GET_SET_KERNEL_NO_RC
, fcn
));
9233 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
9234 return (BAM_SUCCESS
);
9237 if (optnum
== ARGS_CMD
) {
9238 if (old_args
[0] != '\0') {
9239 (void) strlcpy(buf
, old_args
, bufsize
);
9240 BAM_DPRINTF((D_GET_SET_KERNEL_ARGS
, fcn
, buf
));
9244 * We need to print the kernel, so we just turn the
9245 * first space into a '\0' and print the beginning.
9246 * We don't print anything if it's the default kernel.
9250 if (strcmp(kernelp
->arg
, DIRECT_BOOT_KERNEL
) != 0) {
9251 (void) strlcpy(buf
, kernelp
->arg
, bufsize
);
9252 BAM_DPRINTF((D_GET_SET_KERNEL_KERN
, fcn
, buf
));
9256 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
9257 return (BAM_SUCCESS
);
9261 * First, check if we're resetting an entry to the default.
9263 if ((path
[0] == '\0') ||
9264 ((optnum
== KERNEL_CMD
) &&
9265 (strcmp(path
, DIRECT_BOOT_KERNEL
) == 0))) {
9266 if ((entryp
== NULL
) || (kernelp
== NULL
)) {
9267 /* No previous entry, it's already the default */
9268 BAM_DPRINTF((D_GET_SET_KERNEL_ALREADY
, fcn
));
9269 return (BAM_SUCCESS
);
9273 * Check if we can delete the entry. If we're resetting the
9274 * kernel command, and the args is already empty, or if we're
9275 * resetting the args command, and the kernel is already the
9276 * default, we can restore the old default and delete the entry.
9278 if (((optnum
== KERNEL_CMD
) &&
9279 ((old_args
== NULL
) || (old_args
[0] == '\0'))) ||
9280 ((optnum
== ARGS_CMD
) &&
9281 (strncmp(kernelp
->arg
, DIRECT_BOOT_KERNEL
,
9282 sizeof (DIRECT_BOOT_KERNEL
) - 1) == 0))) {
9284 (void) delete_boot_entry(mp
, entryNum
, DBE_PRINTERR
);
9285 restore_default_entry(mp
, BAM_OLD_RC_DEF
,
9286 mp
->old_rc_default
);
9287 mp
->old_rc_default
= NULL
;
9289 BAM_DPRINTF((D_GET_SET_KERNEL_RESTORE_DEFAULT
, fcn
));
9293 if (optnum
== KERNEL_CMD
) {
9295 * At this point, we've already checked that old_args
9296 * and entryp are valid pointers. The "+ 2" is for
9297 * a space a the string termination character.
9299 new_str_len
= (sizeof (DIRECT_BOOT_KERNEL
) - 1) +
9300 strlen(old_args
) + 2;
9301 new_arg
= s_calloc(1, new_str_len
);
9302 (void) snprintf(new_arg
, new_str_len
, "%s %s",
9303 DIRECT_BOOT_KERNEL
, old_args
);
9305 kernelp
->arg
= new_arg
;
9308 * We have changed the kernel line, so we may need
9309 * to update the archive line as well.
9311 set_archive_line(entryp
, kernelp
);
9312 BAM_DPRINTF((D_GET_SET_KERNEL_RESET_KERNEL_SET_ARG
,
9313 fcn
, kernelp
->arg
));
9316 * We're resetting the boot args to nothing, so
9317 * we only need to copy the kernel. We've already
9318 * checked that the kernel is not the default.
9320 new_arg
= s_calloc(1, old_kernel_len
+ 1);
9321 (void) snprintf(new_arg
, old_kernel_len
+ 1, "%s",
9324 kernelp
->arg
= new_arg
;
9325 BAM_DPRINTF((D_GET_SET_KERNEL_RESET_ARG_SET_KERNEL
,
9326 fcn
, kernelp
->arg
));
9333 * Expand the kernel file to a full path, if necessary
9335 if ((optnum
== KERNEL_CMD
) && (path
[0] != '/')) {
9336 new_path
= expand_path(path
);
9337 if (new_path
== NULL
) {
9338 bam_error(UNKNOWN_KERNEL
, path
);
9339 BAM_DPRINTF((D_RETURN_FAILURE
, fcn
));
9349 * At this point, we know we're setting a new value. First, take care
9350 * of the case where there was no previous entry.
9352 if (entryp
== NULL
) {
9354 /* Similar to code in update_temp */
9355 fstype
= get_fstype("/");
9356 INJECT_ERROR1("GET_SET_KERNEL_FSTYPE", fstype
= NULL
);
9357 if (fstype
== NULL
) {
9358 bam_error(BOOTENV_FSTYPE_FAILED
);
9363 osdev
= get_special("/");
9364 INJECT_ERROR1("GET_SET_KERNEL_SPECIAL", osdev
= NULL
);
9365 if (osdev
== NULL
) {
9367 bam_error(BOOTENV_SPECIAL_FAILED
);
9372 sign
= find_existing_sign("/", osdev
, fstype
);
9373 INJECT_ERROR1("GET_SET_KERNEL_SIGN", sign
= NULL
);
9377 bam_error(BOOTENV_SIGN_FAILED
);
9383 (void) strlcpy(signbuf
, sign
, sizeof (signbuf
));
9385 assert(strchr(signbuf
, '(') == NULL
&&
9386 strchr(signbuf
, ',') == NULL
&&
9387 strchr(signbuf
, ')') == NULL
);
9389 if (optnum
== KERNEL_CMD
) {
9390 if (strcmp(fstype
, "zfs") == 0) {
9391 new_str_len
= strlen(new_path
) +
9392 strlen(ZFS_BOOT
) + 8;
9393 new_arg
= s_calloc(1, new_str_len
);
9394 (void) snprintf(new_arg
, new_str_len
, "%s %s",
9395 new_path
, ZFS_BOOT
);
9396 BAM_DPRINTF((D_GET_SET_KERNEL_NEW_KERN
, fcn
,
9398 entryNum
= add_boot_entry(mp
, BOOTENV_RC_TITLE
,
9399 signbuf
, new_arg
, NULL
, NULL
, NULL
);
9402 BAM_DPRINTF((D_GET_SET_KERNEL_NEW_KERN
, fcn
,
9404 entryNum
= add_boot_entry(mp
, BOOTENV_RC_TITLE
,
9405 signbuf
, new_path
, NULL
, NULL
, NULL
);
9408 new_str_len
= strlen(path
) + 8;
9409 if (strcmp(fstype
, "zfs") == 0) {
9410 new_str_len
+= strlen(DIRECT_BOOT_KERNEL_ZFS
);
9411 new_arg
= s_calloc(1, new_str_len
);
9412 (void) snprintf(new_arg
, new_str_len
, "%s %s",
9413 DIRECT_BOOT_KERNEL_ZFS
, path
);
9415 new_str_len
+= strlen(DIRECT_BOOT_KERNEL
);
9416 new_arg
= s_calloc(1, new_str_len
);
9417 (void) snprintf(new_arg
, new_str_len
, "%s %s",
9418 DIRECT_BOOT_KERNEL
, path
);
9421 BAM_DPRINTF((D_GET_SET_KERNEL_NEW_ARG
, fcn
, new_arg
));
9422 entryNum
= add_boot_entry(mp
, BOOTENV_RC_TITLE
,
9423 signbuf
, new_arg
, NULL
, DIRECT_BOOT_ARCHIVE
, NULL
);
9427 INJECT_ERROR1("GET_SET_KERNEL_ADD_BOOT_ENTRY",
9428 entryNum
= BAM_ERROR
);
9429 if (entryNum
== BAM_ERROR
) {
9430 bam_error(GET_SET_KERNEL_ADD_BOOT_ENTRY
,
9435 save_default_entry(mp
, BAM_OLD_RC_DEF
);
9436 ret
= set_global(mp
, menu_cmds
[DEFAULT_CMD
], entryNum
);
9437 INJECT_ERROR1("GET_SET_KERNEL_SET_GLOBAL", ret
= BAM_ERROR
);
9438 if (ret
== BAM_ERROR
) {
9439 bam_error(GET_SET_KERNEL_SET_GLOBAL
, entryNum
);
9446 * There was already an bootenv entry which we need to edit.
9448 if (optnum
== KERNEL_CMD
) {
9449 new_str_len
= strlen(new_path
) + strlen(old_args
) + 2;
9450 new_arg
= s_calloc(1, new_str_len
);
9451 (void) snprintf(new_arg
, new_str_len
, "%s %s", new_path
,
9454 kernelp
->arg
= new_arg
;
9457 * If we have changed the kernel line, we may need to update
9458 * the archive line as well.
9460 set_archive_line(entryp
, kernelp
);
9461 BAM_DPRINTF((D_GET_SET_KERNEL_REPLACED_KERNEL_SAME_ARG
, fcn
,
9464 new_str_len
= old_kernel_len
+ strlen(path
) + 8;
9465 new_arg
= s_calloc(1, new_str_len
);
9466 (void) strncpy(new_arg
, kernelp
->arg
, old_kernel_len
);
9467 (void) strlcat(new_arg
, " ", new_str_len
);
9468 (void) strlcat(new_arg
, path
, new_str_len
);
9470 kernelp
->arg
= new_arg
;
9471 BAM_DPRINTF((D_GET_SET_KERNEL_SAME_KERNEL_REPLACED_ARG
, fcn
,
9477 if ((rv
== BAM_WRITE
) && kernelp
)
9478 update_line(kernelp
);
9481 if (rv
== BAM_WRITE
) {
9482 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
9484 BAM_DPRINTF((D_RETURN_FAILURE
, fcn
));
9490 get_kernel(menu_t
*mp
, menu_cmd_t optnum
, char *buf
, size_t bufsize
)
9492 const char *fcn
= "get_kernel()";
9493 BAM_DPRINTF((D_FUNC_ENTRY1
, fcn
, menu_cmds
[optnum
]));
9494 return (get_set_kernel(mp
, optnum
, NULL
, buf
, bufsize
));
9498 set_kernel(menu_t
*mp
, menu_cmd_t optnum
, char *path
, char *buf
, size_t bufsize
)
9500 const char *fcn
= "set_kernel()";
9501 assert(path
!= NULL
);
9502 BAM_DPRINTF((D_FUNC_ENTRY2
, fcn
, menu_cmds
[optnum
], path
));
9503 return (get_set_kernel(mp
, optnum
, path
, buf
, bufsize
));
9508 set_option(menu_t
*mp
, char *dummy
, char *opt
)
9513 char buf
[BUFSIZ
] = "";
9515 const char *fcn
= "set_option()";
9519 assert(dummy
== NULL
);
9521 /* opt is set from bam_argv[0] and is always non-NULL */
9522 BAM_DPRINTF((D_FUNC_ENTRY1
, fcn
, opt
));
9524 val
= strchr(opt
, '=');
9529 if (strcmp(opt
, "default") == 0) {
9530 optnum
= DEFAULT_CMD
;
9531 } else if (strcmp(opt
, "timeout") == 0) {
9532 optnum
= TIMEOUT_CMD
;
9533 } else if (strcmp(opt
, menu_cmds
[KERNEL_CMD
]) == 0) {
9534 optnum
= KERNEL_CMD
;
9535 } else if (strcmp(opt
, menu_cmds
[ARGS_CMD
]) == 0) {
9538 bam_error(INVALID_OPTION
, opt
);
9543 * kernel and args are allowed without "=new_value" strings. All
9544 * others cause errors
9546 if ((val
== NULL
) && (optnum
!= KERNEL_CMD
) && (optnum
!= ARGS_CMD
)) {
9547 bam_error(NO_OPTION_ARG
, opt
);
9549 } else if (val
!= NULL
) {
9553 if ((optnum
== KERNEL_CMD
) || (optnum
== ARGS_CMD
)) {
9554 BAM_DPRINTF((D_SET_OPTION
, fcn
, menu_cmds
[optnum
],
9555 val
? val
+ 1 : "NULL"));
9558 rv
= set_kernel(mp
, optnum
, val
+ 1, buf
, sizeof (buf
));
9560 rv
= get_kernel(mp
, optnum
, buf
, sizeof (buf
));
9561 if ((rv
== BAM_SUCCESS
) && (buf
[0] != '\0'))
9562 (void) printf("%s\n", buf
);
9564 optval
= s_strtol(val
+ 1);
9565 BAM_DPRINTF((D_SET_OPTION
, fcn
, menu_cmds
[optnum
], val
+ 1));
9566 rv
= set_global(mp
, menu_cmds
[optnum
], optval
);
9569 if (rv
== BAM_WRITE
|| rv
== BAM_SUCCESS
) {
9570 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
9572 BAM_DPRINTF((D_RETURN_FAILURE
, fcn
));
9579 * The quiet argument suppresses messages. This is used
9580 * when invoked in the context of other commands (e.g. list_entry)
9583 read_globals(menu_t
*mp
, char *menu_path
, char *globalcmd
, int quiet
)
9587 int done
, ret
= BAM_SUCCESS
;
9593 if (mp
->start
== NULL
) {
9595 bam_error(NO_MENU
, menu_path
);
9600 for (lp
= mp
->start
; lp
; lp
= lp
->next
) {
9601 if (lp
->flags
!= BAM_GLOBAL
)
9604 if (lp
->cmd
== NULL
) {
9606 bam_error(NO_CMD
, lp
->lineNum
);
9610 if (strcmp(globalcmd
, lp
->cmd
) != 0)
9613 /* Found global. Check for duplicates */
9614 if (done
&& !quiet
) {
9615 bam_error(DUP_CMD
, globalcmd
, lp
->lineNum
, bam_root
);
9619 arg
= lp
->arg
? lp
->arg
: "";
9620 bam_print(GLOBAL_CMD
, globalcmd
, arg
);
9624 if (!done
&& bam_verbose
)
9625 bam_print(NO_ENTRY
, globalcmd
);
9631 menu_write(char *root
, menu_t
*mp
)
9633 const char *fcn
= "menu_write()";
9635 BAM_DPRINTF((D_MENU_WRITE_ENTER
, fcn
, root
));
9636 return (list2file(root
, MENU_TMP
, GRUB_MENU
, mp
->start
));
9640 line_free(line_t
*lp
)
9645 if (lp
->cmd
!= NULL
)
9657 linelist_free(line_t
*start
)
9663 start
= start
->next
;
9669 filelist_free(filelist_t
*flistp
)
9671 linelist_free(flistp
->head
);
9672 flistp
->head
= NULL
;
9673 flistp
->tail
= NULL
;
9677 menu_free(menu_t
*mp
)
9683 linelist_free(mp
->start
);
9700 * Returns 0 on success
9701 * Any other value indicates an error
9704 exec_cmd(char *cmdline
, filelist_t
*flistp
)
9714 * - only absolute paths are allowed
9715 * - set IFS to space and tab
9717 if (*cmdline
!= '/') {
9718 bam_error(ABS_PATH_REQ
, cmdline
);
9721 (void) putenv("IFS= \t");
9724 * We may have been exec'ed with SIGCHLD blocked
9727 (void) sigemptyset(&set
);
9728 (void) sigaddset(&set
, SIGCHLD
);
9729 if (sigprocmask(SIG_UNBLOCK
, &set
, NULL
) != 0) {
9730 bam_error(CANT_UNBLOCK_SIGCHLD
, strerror(errno
));
9735 * Set SIGCHLD disposition to SIG_DFL for popen/pclose
9737 disp
= sigset(SIGCHLD
, SIG_DFL
);
9738 if (disp
== SIG_ERR
) {
9739 bam_error(FAILED_SIG
, strerror(errno
));
9742 if (disp
== SIG_HOLD
) {
9743 bam_error(BLOCKED_SIG
, cmdline
);
9747 ptr
= popen(cmdline
, "r");
9749 bam_error(POPEN_FAIL
, cmdline
, strerror(errno
));
9754 * If we simply do a pclose() following a popen(), pclose()
9755 * will close the reader end of the pipe immediately even
9756 * if the child process has not started/exited. pclose()
9757 * does wait for cmd to terminate before returning though.
9758 * When the executed command writes its output to the pipe
9759 * there is no reader process and the command dies with
9760 * SIGPIPE. To avoid this we read repeatedly until read
9761 * terminates with EOF. This indicates that the command
9762 * (writer) has closed the pipe and we can safely do a
9765 * Since pclose() does wait for the command to exit,
9766 * we can safely reap the exit status of the command
9767 * from the value returned by pclose()
9769 while (s_fgets(buf
, sizeof (buf
), ptr
) != NULL
) {
9770 if (flistp
== NULL
) {
9771 /* s_fgets strips newlines, so insert them at the end */
9772 bam_print(PRINT
, buf
);
9774 append_to_flist(flistp
, buf
);
9780 bam_error(PCLOSE_FAIL
, cmdline
, strerror(errno
));
9784 if (WIFEXITED(ret
)) {
9785 return (WEXITSTATUS(ret
));
9787 bam_error(EXEC_FAIL
, cmdline
, ret
);
9793 * Since this function returns -1 on error
9794 * it cannot be used to convert -1. However,
9795 * that is sufficient for what we need.
9808 l
= strtol(str
, &res
, 10);
9809 if (errno
|| *res
!= '\0') {
9817 * Wrapper around fputs, that adds a newline (since fputs doesn't)
9820 s_fputs(char *str
, FILE *fp
)
9822 char linebuf
[BAM_MAXLINE
];
9824 (void) snprintf(linebuf
, sizeof (linebuf
), "%s\n", str
);
9825 return (fputs(linebuf
, fp
));
9829 * Wrapper around fgets, that strips newlines returned by fgets
9832 s_fgets(char *buf
, int buflen
, FILE *fp
)
9836 buf
= fgets(buf
, buflen
, fp
);
9839 if (n
== buflen
- 1 && buf
[n
-1] != '\n')
9840 bam_error(TOO_LONG
, buflen
- 1, buf
);
9841 buf
[n
-1] = (buf
[n
-1] == '\n') ? '\0' : buf
[n
-1];
9848 s_calloc(size_t nelem
, size_t sz
)
9852 ptr
= calloc(nelem
, sz
);
9854 bam_error(NO_MEM
, nelem
*sz
);
9861 s_realloc(void *ptr
, size_t sz
)
9863 ptr
= realloc(ptr
, sz
);
9865 bam_error(NO_MEM
, sz
);
9881 bam_error(NO_MEM
, strlen(str
) + 1);
9888 * Returns 1 if amd64 (or sparc, for syncing x86 diskless clients)
9889 * Returns 0 otherwise
9894 static int amd64
= -1;
9895 char isabuf
[257]; /* from sysinfo(2) manpage */
9900 if (bam_alt_platform
) {
9901 if (strcmp(bam_platform
, "i86pc") == 0) {
9902 amd64
= 1; /* diskless server */
9905 if (sysinfo(SI_ISALIST
, isabuf
, sizeof (isabuf
)) > 0 &&
9906 strncmp(isabuf
, "amd64 ", strlen("amd64 ")) == 0) {
9908 } else if (strstr(isabuf
, "i386") == NULL
) {
9909 amd64
= 1; /* diskless server */
9921 static int cached
= -1;
9922 static char mbuf
[257]; /* from sysinfo(2) manpage */
9927 if (bam_alt_platform
) {
9928 return (bam_platform
);
9930 if (sysinfo(SI_MACHINE
, mbuf
, sizeof (mbuf
)) > 0) {
9945 static int issparc
= -1;
9946 char mbuf
[257]; /* from sysinfo(2) manpage */
9951 if (bam_alt_platform
) {
9952 if (strncmp(bam_platform
, "sun4", 4) == 0) {
9956 if (sysinfo(SI_ARCHITECTURE
, mbuf
, sizeof (mbuf
)) > 0 &&
9957 strcmp(mbuf
, "sparc") == 0) {
9968 append_to_flist(filelist_t
*flistp
, char *s
)
9972 lp
= s_calloc(1, sizeof (line_t
));
9973 lp
->line
= s_strdup(s
);
9974 if (flistp
->head
== NULL
)
9977 flistp
->tail
->next
= lp
;
9987 ucode_install(char *root
)
9991 for (i
= 0; ucode_vendors
[i
].filestr
!= NULL
; i
++) {
9992 int cmd_len
= PATH_MAX
+ 256;
9993 char cmd
[PATH_MAX
+ 256];
9994 char file
[PATH_MAX
];
9995 char timestamp
[PATH_MAX
];
9996 struct stat fstatus
, tstatus
;
9997 struct utimbuf u_times
;
9999 (void) snprintf(file
, PATH_MAX
, "%s/%s/%s-ucode.%s",
10000 bam_root
, UCODE_INSTALL_PATH
, ucode_vendors
[i
].filestr
,
10001 ucode_vendors
[i
].extstr
);
10003 if (stat(file
, &fstatus
) != 0 || !(S_ISREG(fstatus
.st_mode
)))
10006 (void) snprintf(timestamp
, PATH_MAX
, "%s.ts", file
);
10008 if (stat(timestamp
, &tstatus
) == 0 &&
10009 fstatus
.st_mtime
<= tstatus
.st_mtime
)
10012 (void) snprintf(cmd
, cmd_len
, "/usr/sbin/ucodeadm -i -R "
10013 "%s/%s/%s %s > /dev/null 2>&1", bam_root
,
10014 UCODE_INSTALL_PATH
, ucode_vendors
[i
].vendorstr
, file
);
10015 if (system(cmd
) != 0)
10018 if (creat(timestamp
, S_IRUSR
| S_IWUSR
) == -1)
10021 u_times
.actime
= fstatus
.st_atime
;
10022 u_times
.modtime
= fstatus
.st_mtime
;
10023 (void) utime(timestamp
, &u_times
);