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.
23 * Copyright 2012 Milan Jurik. All rights reserved.
27 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
31 * bootadm(1M) is a new utility for managing bootability of
32 * Solaris *Newboot* environments. It has two primary tasks:
33 * - Allow end users to manage bootability of Newboot Solaris instances
34 * - Provide services to other subsystems in Solaris (primarily Install)
43 #include <sys/types.h>
50 #include <sys/mnttab.h>
51 #include <sys/mntent.h>
52 #include <sys/statvfs.h>
53 #include <libnvpair.h>
58 #include <sys/systeminfo.h>
59 #include <sys/dktp/fdisk.h>
60 #include <sys/param.h>
64 #include <sys/sysmacros.h>
68 #include <sys/lockfs.h>
69 #include <sys/filio.h>
76 #include <sys/ucode.h>
81 #include <device_info.h>
83 #include <sys/efi_partition.h>
86 #include <sys/mkdev.h>
92 #define TEXT_DOMAIN "SUNW_OST_OSCMD"
93 #endif /* TEXT_DOMAIN */
95 /* Type definitions */
105 OPT_ABSENT
= 0, /* No option */
106 OPT_REQ
, /* option required */
107 OPT_OPTIONAL
/* option may or may not be present */
113 error_t (*handler
)();
114 int unpriv
; /* is this an unprivileged command */
117 #define LINE_INIT 0 /* lineNum initial value */
118 #define ENTRY_INIT -1 /* entryNum initial value */
119 #define ALL_ENTRIES -2 /* selects all boot entries */
121 #define PARTNO_NOTFOUND -1 /* Solaris partition not found */
122 #define PARTNO_EFI -2 /* EFI partition table found */
124 #define GRUB_DIR "/boot/grub"
125 #define GRUB_STAGE2 GRUB_DIR "/stage2"
126 #define GRUB_MENU "/boot/grub/menu.lst"
127 #define MENU_TMP "/boot/grub/menu.lst.tmp"
128 #define GRUB_BACKUP_MENU "/etc/lu/GRUB_backup_menu"
129 #define RAMDISK_SPECIAL "/dev/ramdisk/"
130 #define STUBBOOT "/stubboot"
131 #define MULTIBOOT "/platform/i86pc/multiboot"
132 #define GRUBSIGN_DIR "/boot/grub/bootsign"
133 #define GRUBSIGN_BACKUP "/etc/bootsign"
134 #define GRUBSIGN_UFS_PREFIX "rootfs"
135 #define GRUBSIGN_ZFS_PREFIX "pool_"
136 #define GRUBSIGN_LU_PREFIX "BE_"
137 #define UFS_SIGNATURE_LIST "/var/run/grub_ufs_signatures"
138 #define ZFS_LEGACY_MNTPT "/tmp/bootadm_mnt_zfs_legacy"
140 #define BOOTADM_RDONLY_TEST "BOOTADM_RDONLY_TEST"
143 #define BAM_LOCK_FILE "/var/run/bootadm.lock"
144 #define LOCK_FILE_PERMS (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
146 #define CREATE_RAMDISK "boot/solaris/bin/create_ramdisk"
147 #define CREATE_DISKMAP "boot/solaris/bin/create_diskmap"
148 #define EXTRACT_BOOT_FILELIST "boot/solaris/bin/extract_boot_filelist"
149 #define GRUBDISK_MAP "/var/run/solaris_grubdisk.map"
151 #define GRUB_slice "/etc/lu/GRUB_slice"
152 #define GRUB_root "/etc/lu/GRUB_root"
153 #define GRUB_fdisk "/etc/lu/GRUB_fdisk"
154 #define GRUB_fdisk_target "/etc/lu/GRUB_fdisk_target"
155 #define FINDROOT_INSTALLGRUB "/etc/lu/installgrub.findroot"
156 #define LULIB "/usr/lib/lu/lulib"
157 #define LULIB_PROPAGATE_FILE "lulib_propagate_file"
158 #define CKSUM "/usr/bin/cksum"
159 #define LU_MENU_CKSUM "/etc/lu/menu.cksum"
160 #define BOOTADM "/sbin/bootadm"
162 #define INSTALLGRUB "/sbin/installgrub"
163 #define STAGE1 "/boot/grub/stage1"
164 #define STAGE2 "/boot/grub/stage2"
166 typedef enum zfs_mnted
{
175 * Default file attributes
177 #define DEFAULT_DEV_MODE 0644 /* default permissions */
178 #define DEFAULT_DEV_UID 0 /* user root */
179 #define DEFAULT_DEV_GID 3 /* group sys */
183 * menu_cmd_t and menu_cmds must be kept in sync
185 char *menu_cmds
[] = {
186 "default", /* DEFAULT_CMD */
187 "timeout", /* TIMEOUT_CMD */
188 "title", /* TITLE_CMD */
189 "root", /* ROOT_CMD */
190 "kernel", /* KERNEL_CMD */
191 "kernel$", /* KERNEL_DOLLAR_CMD */
192 "module", /* MODULE_CMD */
193 "module$", /* MODULE_DOLLAR_CMD */
195 "#", /* COMMENT_CMD */
196 "chainloader", /* CHAINLOADER_CMD */
197 "args", /* ARGS_CMD */
198 "findroot", /* FINDROOT_CMD */
199 "bootfs", /* BOOTFS_CMD */
203 #define OPT_ENTRY_NUM "entry"
213 #define BOOT_FILE_LIST "boot/solaris/filelist.ramdisk"
214 #define ETC_FILE_LIST "etc/boot/solaris/filelist.ramdisk"
216 #define FILE_STAT "boot/solaris/filestat.ramdisk"
217 #define FILE_STAT_TMP "boot/solaris/filestat.ramdisk.tmp"
218 #define DIR_PERMS (S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
219 #define FILE_STAT_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
221 #define FILE_STAT_TIMESTAMP "boot/solaris/timestamp.cache"
228 static subcmd_t bam_cmd
;
229 static char *bam_root
;
230 static int bam_rootlen
;
231 static int bam_root_readonly
;
232 static int bam_alt_root
;
233 static int bam_extend
= 0;
234 static int bam_purge
= 0;
235 static char *bam_subcmd
;
236 static char *bam_opt
;
237 static char **bam_argv
;
238 static char *bam_pool
;
240 static int bam_check
;
241 static int bam_saved_check
;
242 static int bam_smf_check
;
243 static int bam_lock_fd
= -1;
246 static char rootbuf
[PATH_MAX
] = "/";
247 static int bam_update_all
;
248 static int bam_alt_platform
;
249 static char *bam_platform
;
250 static char *bam_home_env
= NULL
;
252 /* function prototypes */
253 static void parse_args_internal(int, char *[]);
254 static void parse_args(int, char *argv
[]);
255 static error_t
bam_menu(char *, char *, int, char *[]);
256 static error_t
bam_install(char *, char *);
257 static error_t
bam_archive(char *, char *);
259 static void bam_lock(void);
260 static void bam_unlock(void);
262 static int exec_cmd(char *, filelist_t
*);
263 static error_t
read_globals(menu_t
*, char *, char *, int);
264 static int menu_on_bootdisk(char *os_root
, char *menu_root
);
265 static menu_t
*menu_read(char *);
266 static error_t
menu_write(char *, menu_t
*);
267 static void linelist_free(line_t
*);
268 static void menu_free(menu_t
*);
269 static void filelist_free(filelist_t
*);
270 static error_t
list2file(char *, char *, char *, line_t
*);
271 static error_t
list_entry(menu_t
*, char *, char *);
272 static error_t
list_setting(menu_t
*, char *, char *);
273 static error_t
delete_all_entries(menu_t
*, char *, char *);
274 static error_t
update_entry(menu_t
*mp
, char *menu_root
, char *opt
);
275 static error_t
update_temp(menu_t
*mp
, char *dummy
, char *opt
);
277 static error_t
install_bootloader(void);
278 static error_t
update_archive(char *, char *);
279 static error_t
list_archive(char *, char *);
280 static error_t
update_all(char *, char *);
281 static error_t
read_list(char *, filelist_t
*);
282 static error_t
set_option(menu_t
*, char *, char *);
283 static error_t
set_kernel(menu_t
*, menu_cmd_t
, char *, char *, size_t);
284 static error_t
get_kernel(menu_t
*, menu_cmd_t
, char *, size_t);
285 static char *expand_path(const char *);
287 static long s_strtol(char *);
288 static int s_fputs(char *, FILE *);
290 static int is_zfs(char *root
);
291 static int is_ufs(char *root
);
292 static int is_pcfs(char *root
);
293 static int is_amd64(void);
294 static char *get_machine(void);
295 static void append_to_flist(filelist_t
*, char *);
296 static char *mount_top_dataset(char *pool
, zfs_mnted_t
*mnted
);
297 static int umount_top_dataset(char *pool
, zfs_mnted_t mnted
, char *mntpt
);
298 static int ufs_add_to_sign_list(char *sign
);
299 static error_t
synchronize_BE_menu(void);
302 static void ucode_install();
305 /* Menu related sub commands */
306 static subcmd_defn_t menu_subcmds
[] = {
307 "set_option", OPT_ABSENT
, set_option
, 0, /* PUB */
308 "list_entry", OPT_OPTIONAL
, list_entry
, 1, /* PUB */
309 "delete_all_entries", OPT_ABSENT
, delete_all_entries
, 0, /* PVT */
310 "update_entry", OPT_REQ
, update_entry
, 0, /* menu */
311 "update_temp", OPT_OPTIONAL
, update_temp
, 0, /* reboot */
312 "upgrade", OPT_ABSENT
, upgrade_menu
, 0, /* menu */
313 "list_setting", OPT_OPTIONAL
, list_setting
, 1, /* menu */
314 "disable_hypervisor", OPT_ABSENT
, cvt_to_metal
, 0, /* menu */
315 "enable_hypervisor", OPT_ABSENT
, cvt_to_hyper
, 0, /* menu */
316 NULL
, 0, NULL
, 0 /* must be last */
319 /* Archive related sub commands */
320 static subcmd_defn_t arch_subcmds
[] = {
321 "update", OPT_ABSENT
, update_archive
, 0, /* PUB */
322 "update_all", OPT_ABSENT
, update_all
, 0, /* PVT */
323 "list", OPT_OPTIONAL
, list_archive
, 1, /* PUB */
324 NULL
, 0, NULL
, 0 /* must be last */
327 /* Install related sub commands */
328 static subcmd_defn_t inst_subcmds
[] = {
329 "install_bootloader", OPT_ABSENT
, install_bootloader
, 0, /* PUB */
330 NULL
, 0, NULL
, 0 /* must be last */
333 enum dircache_copy_opt
{
340 * Directory specific flags:
341 * NEED_UPDATE : the specified archive needs to be updated
342 * NO_MULTI : don't extend the specified archive, but recreate it
344 #define NEED_UPDATE 0x00000001
345 #define NO_MULTI 0x00000002
347 #define set_dir_flag(id, f) (walk_arg.dirinfo[id].flags |= f)
348 #define unset_dir_flag(id, f) (walk_arg.dirinfo[id].flags &= ~f)
349 #define is_dir_flag_on(id, f) (walk_arg.dirinfo[id].flags & f ? 1 : 0)
351 #define get_cachedir(id) (walk_arg.dirinfo[id].cdir_path)
352 #define get_updatedir(id) (walk_arg.dirinfo[id].update_path)
353 #define get_count(id) (walk_arg.dirinfo[id].count)
354 #define has_cachedir(id) (walk_arg.dirinfo[id].has_dir)
355 #define set_dir_present(id) (walk_arg.dirinfo[id].has_dir = 1)
358 * dirinfo_t (specific cache directory information):
359 * cdir_path: path to the archive cache directory
360 * update_path: path to the update directory (contains the files that will be
361 * used to extend the archive)
362 * has_dir: the specified cache directory is active
363 * count: the number of files to update
364 * flags: directory specific flags
366 typedef struct _dirinfo
{
367 char cdir_path
[PATH_MAX
];
368 char update_path
[PATH_MAX
];
376 * NEED_CACHE_DIR : cache directory is missing and needs to be created
377 * IS_SPARC_TARGET : the target mountpoint is a SPARC environment
378 * UPDATE_ERROR : an error occourred while traversing the list of files
379 * RDONLY_FSCHK : the target filesystem is read-only
380 * RAMDSK_FSCHK : the target filesystem is on a ramdisk
382 #define NEED_CACHE_DIR 0x00000001
383 #define IS_SPARC_TARGET 0x00000002
384 #define UPDATE_ERROR 0x00000004
385 #define RDONLY_FSCHK 0x00000008
386 #define INVALIDATE_CACHE 0x00000010
388 #define is_flag_on(flag) (walk_arg.update_flags & flag ? 1 : 0)
389 #define set_flag(flag) (walk_arg.update_flags |= flag)
390 #define unset_flag(flag) (walk_arg.update_flags &= ~flag)
394 * update_flags: flags related to the current updating process
395 * new_nvlp/old_nvlp: new and old list of archive-files / attributes pairs
396 * sparcfile: list of file paths for mkisofs -path-list (SPARC only)
403 dirinfo_t dirinfo
[CACHEDIR_NUM
];
408 struct safefile
*next
;
411 static struct safefile
*safefiles
= NULL
;
414 * svc:/system/filesystem/usr:default service checks for this file and
415 * does a boot archive update and then reboot the system.
417 #define NEED_UPDATE_FILE "/etc/svc/volatile/boot_archive_needs_update"
420 * svc:/system/boot-archive-update:default checks for this file and
421 * updates the boot archive.
423 #define NEED_UPDATE_SAFE_FILE "/etc/svc/volatile/boot_archive_safefile_update"
425 /* Thanks growisofs */
426 #define CD_BLOCK ((off64_t)2048)
427 #define VOLDESC_OFF 16
428 #define DVD_BLOCK (32*1024)
432 unsigned char type
[1];
433 unsigned char id
[5];
434 unsigned char void1
[80-5-1];
435 unsigned char volume_space_size
[8];
436 unsigned char void2
[2048-80-8];
440 * COUNT_MAX: maximum number of changed files to justify a multisession update
441 * BA_SIZE_MAX: maximum size of the boot_archive to justify a multisession
445 #define BA_SIZE_MAX (50 * 1024 * 1024)
447 #define bam_nowrite() (bam_check || bam_smf_check)
449 static int sync_menu
= 1; /* whether we need to sync the BE menus */
454 (void) fprintf(stderr
, "USAGE:\n");
457 (void) fprintf(stderr
,
458 "\t%s update-archive [-vn] [-R altroot [-p platform]]\n", prog
);
459 (void) fprintf(stderr
,
460 "\t%s list-archive [-R altroot [-p platform]]\n", prog
);
462 (void) fprintf(stderr
,
463 "\t%s install-bootloader [-fv] [-R altroot] [-P pool]\n", prog
);
465 (void) fprintf(stderr
,
466 "\t%s install-bootloader [-Mfv] [-R altroot] [-P pool]\n", prog
);
470 (void) fprintf(stderr
, "\t%s set-menu [-R altroot] key=value\n", prog
);
471 (void) fprintf(stderr
, "\t%s list-menu [-R altroot]\n", prog
);
476 * Best effort attempt to restore the $HOME value.
481 char home_env
[PATH_MAX
];
484 (void) snprintf(home_env
, sizeof (home_env
), "HOME=%s",
486 (void) putenv(home_env
);
495 * Sanitize the environment in which bootadm will execute its sub-processes
496 * (ex. mkisofs). This is done to prevent those processes from attempting
497 * to access files (ex. .mkisofsrc) or stat paths that might be on NFS
498 * or, potentially, insecure.
505 /* don't depend on caller umask */
508 /* move away from a potential unsafe current working directory */
509 while (chdir("/") == -1) {
510 if (errno
!= EINTR
) {
511 bam_print("WARNING: unable to chdir to /");
516 bam_home_env
= getenv("HOME");
517 while (bam_home_env
!= NULL
&& putenv("HOME=/") == -1) {
518 if (errno
== ENOMEM
) {
519 /* retry no more than MAX_TRIES times */
520 if (++stry
> MAX_TRIES
) {
521 bam_print("WARNING: unable to recover from "
522 "system memory pressure... aborting \n");
523 bam_exit(EXIT_FAILURE
);
525 /* memory is tight, try to sleep */
526 bam_print("Attempting to recover from memory pressure: "
527 "sleeping for %d seconds\n", SLEEP_TIME
* stry
);
528 (void) sleep(SLEEP_TIME
* stry
);
530 bam_print("WARNING: unable to sanitize HOME\n");
536 main(int argc
, char *argv
[])
540 (void) setlocale(LC_ALL
, "");
541 (void) textdomain(TEXT_DOMAIN
);
543 if ((prog
= strrchr(argv
[0], '/')) == NULL
) {
549 INJECT_ERROR1("ASSERT_ON", assert(0))
553 parse_args(argc
, argv
);
557 ret
= bam_menu(bam_subcmd
, bam_opt
, bam_argc
, bam_argv
);
560 ret
= bam_archive(bam_subcmd
, bam_opt
);
563 ret
= bam_install(bam_subcmd
, bam_opt
);
570 if (ret
!= BAM_SUCCESS
)
571 bam_exit((ret
== BAM_NOCHANGE
) ? 2 : 1);
578 * Equivalence of public and internal commands:
579 * update-archive -- -a update
580 * list-archive -- -a list
581 * set-menu -- -m set_option
582 * list-menu -- -m list_entry
583 * update-menu -- -m update_entry
584 * install-bootloader -- -i install_bootloader
586 static struct cmd_map
{
591 { "update-archive", BAM_ARCHIVE
, "update"},
592 { "list-archive", BAM_ARCHIVE
, "list"},
593 { "set-menu", BAM_MENU
, "set_option"},
594 { "list-menu", BAM_MENU
, "list_entry"},
595 { "update-menu", BAM_MENU
, "update_entry"},
596 { "install-bootloader", BAM_INSTALL
, "install_bootloader"},
601 * Commands syntax published in bootadm(1M) are parsed here
604 parse_args(int argc
, char *argv
[])
606 struct cmd_map
*cmp
= cmd_map
;
608 /* command conforming to the final spec */
609 if (argc
> 1 && argv
[1][0] != '-') {
611 * Map commands to internal table.
613 while (cmp
->bam_cmdname
) {
614 if (strcmp(argv
[1], cmp
->bam_cmdname
) == 0) {
615 bam_cmd
= cmp
->bam_cmd
;
616 bam_subcmd
= cmp
->bam_subcmd
;
621 if (cmp
->bam_cmdname
== NULL
) {
629 parse_args_internal(argc
, argv
);
633 * A combination of public and private commands are parsed here.
634 * The internal syntax and the corresponding functionality are:
635 * -a update -- update-archive
636 * -a list -- list-archive
637 * -a update-all -- (reboot to sync all mnted OS archive)
638 * -i install_bootloader -- install-bootloader
639 * -m update_entry -- update-menu
640 * -m list_entry -- list-menu
641 * -m update_temp -- (reboot -- [boot-args])
642 * -m delete_all_entries -- (called from install)
643 * -m enable_hypervisor [args] -- cvt_to_hyper
644 * -m disable_hypervisor -- cvt_to_metal
645 * -m list_setting [entry] [value] -- list_setting
647 * A set of private flags is there too:
648 * -F -- purge the cache directories and rebuild them
649 * -e -- use the (faster) archive update approach (used by
653 parse_args_internal(int argc
, char *argv
[])
657 extern int optind
, opterr
;
659 const char *optstring
= "a:d:fi:m:no:veFCR:p:P:XZ";
661 const char *optstring
= "a:d:fi:m:no:veFCMR:p:P:XZ";
664 /* Suppress error message from getopt */
668 while ((c
= getopt(argc
, argv
, optstring
)) != -1) {
673 bam_error(MULT_CMDS
, c
);
675 bam_cmd
= BAM_ARCHIVE
;
681 bam_error(DUP_OPT
, c
);
683 bam_debug
= s_strtol(optarg
);
694 bam_error(MULT_CMDS
, c
);
696 bam_cmd
= BAM_INSTALL
;
702 bam_error(MULT_CMDS
, c
);
715 * We save the original value of bam_check. The new
716 * approach in case of a read-only filesystem is to
717 * behave as a check, so we need a way to restore the
718 * original value after the evaluation of the read-only
719 * filesystem has been done.
720 * Even if we don't allow at the moment a check with
721 * update_all, this approach is more robust than
722 * simply resetting bam_check to zero.
729 bam_error(DUP_OPT
, c
);
740 if (bam_pool
!= NULL
) {
742 bam_error(DUP_OPT
, c
);
749 bam_error(DUP_OPT
, c
);
751 } else if (realpath(optarg
, rootbuf
) == NULL
) {
753 bam_error(CANT_RESOLVE
, optarg
,
759 bam_rootlen
= strlen(rootbuf
);
762 bam_alt_platform
= 1;
763 bam_platform
= optarg
;
764 if ((strcmp(bam_platform
, "i86pc") != 0) &&
765 (strcmp(bam_platform
, "sun4u") != 0) &&
766 (strcmp(bam_platform
, "sun4v") != 0)) {
768 bam_error(INVALID_PLAT
, bam_platform
);
772 bam_is_hv
= BAM_HV_PRESENT
;
782 bam_error(BAD_OPT
, optopt
);
786 bam_error(BAD_OPT
, c
);
792 * An alternate platform requires an alternate root
794 if (bam_alt_platform
&& bam_alt_root
== 0) {
800 * A command option must be specfied
803 if (bam_opt
&& strcmp(bam_opt
, "all") == 0) {
817 bam_error(INT_ERROR
, "parse_args");
819 } else if (optind
< argc
) {
820 bam_argv
= &argv
[optind
];
821 bam_argc
= argc
- optind
;
825 * mbr and pool are options for install_bootloader
827 if (bam_cmd
!= BAM_INSTALL
&& (bam_mbr
|| bam_pool
!= NULL
)) {
833 * -n implies verbose mode
840 check_subcmd_and_options(
843 subcmd_defn_t
*table
,
848 if (subcmd
== NULL
) {
849 bam_error(NEED_SUBCMD
);
853 if (strcmp(subcmd
, "set_option") == 0) {
854 if (bam_argc
== 0 || bam_argv
== NULL
|| bam_argv
[0] == NULL
) {
855 bam_error(MISSING_ARG
);
858 } else if (bam_argc
> 1 || bam_argv
[1] != NULL
) {
859 bam_error(TRAILING_ARGS
);
863 } else if (strcmp(subcmd
, "update_all") == 0) {
865 * The only option we accept for the "update_all"
866 * subcmd is "fastboot".
868 if (bam_argc
> 1 || (bam_argc
== 1 &&
869 strcmp(bam_argv
[0], "fastboot") != 0)) {
870 bam_error(TRAILING_ARGS
);
876 } else if (((strcmp(subcmd
, "enable_hypervisor") != 0) &&
877 (strcmp(subcmd
, "list_setting") != 0)) && (bam_argc
|| bam_argv
)) {
879 * Of the remaining subcommands, only "enable_hypervisor" and
880 * "list_setting" take trailing arguments.
882 bam_error(TRAILING_ARGS
);
887 if (bam_root
== NULL
) {
892 /* verify that subcmd is valid */
893 for (i
= 0; table
[i
].subcmd
!= NULL
; i
++) {
894 if (strcmp(table
[i
].subcmd
, subcmd
) == 0)
898 if (table
[i
].subcmd
== NULL
) {
899 bam_error(INVALID_SUBCMD
, subcmd
);
903 if (table
[i
].unpriv
== 0 && geteuid() != 0) {
904 bam_error(MUST_BE_ROOT
);
909 * Currently only privileged commands need a lock
911 if (table
[i
].unpriv
== 0)
914 /* subcmd verifies that opt is appropriate */
915 if (table
[i
].option
!= OPT_OPTIONAL
) {
916 if ((table
[i
].option
== OPT_REQ
) ^ (opt
!= NULL
)) {
918 bam_error(NO_OPT_REQ
, subcmd
);
920 bam_error(MISS_OPT
, subcmd
);
925 *fp
= table
[i
].handler
;
927 return (BAM_SUCCESS
);
931 * NOTE: A single "/" is also considered a trailing slash and will
935 elide_trailing_slash(const char *src
, char *dst
, size_t dstsize
)
942 (void) strlcpy(dst
, src
, dstsize
);
944 dstlen
= strlen(dst
);
945 if (dst
[dstlen
- 1] == '/') {
946 dst
[dstlen
- 1] = '\0';
951 is_safe_exec(char *path
)
955 if (lstat(path
, &sb
) != 0) {
956 bam_error(STAT_FAIL
, path
, strerror(errno
));
960 if (!S_ISREG(sb
.st_mode
)) {
961 bam_error(PATH_EXEC_LINK
, path
);
965 if (sb
.st_uid
!= getuid()) {
966 bam_error(PATH_EXEC_OWNER
, path
, getuid());
970 if (sb
.st_mode
& S_IWOTH
|| sb
.st_mode
& S_IWGRP
) {
971 bam_error(PATH_EXEC_PERMS
, path
);
975 return (BAM_SUCCESS
);
979 list_setting(menu_t
*mp
, char *which
, char *setting
)
992 if (*which
!= NULL
) {
994 * If "which" is not a number, assume it's a setting we want
995 * to look for and so set up the routine to look for "which"
996 * in the default entry.
999 if (!(isdigit((int)*p
++))) {
1001 which
= mp
->curdefault
->arg
;
1005 which
= mp
->curdefault
->arg
;
1008 entry
= atoi(which
);
1010 for (ent
= mp
->entries
; ((ent
!= NULL
) && (ent
->entryNum
!= entry
));
1015 bam_error(NO_MATCH_ENTRY
);
1019 found
= (*setting
== NULL
);
1021 for (lp
= ent
->start
; lp
!= NULL
; lp
= lp
->next
) {
1022 if ((*setting
== NULL
) && (lp
->flags
!= BAM_COMMENT
))
1023 bam_print(PRINT
, lp
->line
);
1024 else if (lp
->cmd
!= NULL
&& strcmp(setting
, lp
->cmd
) == 0) {
1025 bam_print(PRINT
, lp
->arg
);
1034 bam_error(NO_MATCH_ENTRY
);
1038 return (BAM_SUCCESS
);
1042 install_bootloader(void)
1047 struct extmnttab mnt
;
1048 struct stat statbuf
= {0};
1049 be_node_list_t
*be_nodes
, *node
;
1051 char *root_ds
= NULL
;
1054 if (nvlist_alloc(&nvl
, NV_UNIQUE_NAME
, 0) != 0) {
1055 bam_error(_("out of memory\n"));
1060 * if bam_alt_root is set, the stage files are used from alt root.
1061 * if pool is set, the target devices are pool devices, stage files
1062 * are read from pool bootfs unless alt root is set.
1064 * use arguments as targets, stage files are from alt or current root
1065 * if no arguments and no pool, install on current boot pool.
1069 if (stat(bam_root
, &statbuf
) != 0) {
1070 bam_error(STAT_FAIL
, bam_root
, strerror(errno
));
1074 if ((fp
= fopen(MNTTAB
, "r")) == NULL
) {
1075 bam_error(OPEN_FAIL
, MNTTAB
, strerror(errno
));
1080 while (getextmntent(fp
, &mnt
, sizeof (mnt
)) == 0) {
1081 if (mnt
.mnt_major
== major(statbuf
.st_dev
) &&
1082 mnt
.mnt_minor
== minor(statbuf
.st_dev
)) {
1084 root_ds
= strdup(mnt
.mnt_special
);
1091 bam_error(NOT_IN_MNTTAB
, bam_root
);
1095 if (root_ds
== NULL
) {
1096 bam_error(_("out of memory\n"));
1101 if (be_list(NULL
, &be_nodes
) != BE_SUCCESS
) {
1102 bam_error(_("No BE's found\n"));
1106 for (node
= be_nodes
; node
!= NULL
; node
= node
->be_next_node
)
1107 if (strcmp(root_ds
, node
->be_root_ds
) == 0)
1111 bam_error(_("BE (%s) does not exist\n"), root_ds
);
1116 be_free_list(be_nodes
);
1120 ret
= nvlist_add_string(nvl
, BE_ATTR_ORIG_BE_NAME
,
1121 node
->be_node_name
);
1122 ret
|= nvlist_add_string(nvl
, BE_ATTR_ORIG_BE_ROOT
,
1124 be_free_list(be_nodes
);
1132 flags
|= BE_INSTALLBOOT_FLAG_FORCE
;
1134 flags
|= BE_INSTALLBOOT_FLAG_MBR
;
1136 flags
|= BE_INSTALLBOOT_FLAG_VERBOSE
;
1138 if (nvlist_add_uint16(nvl
, BE_ATTR_INSTALL_FLAGS
, flags
) != 0) {
1139 bam_error(_("out of memory\n"));
1144 * if altroot was set, we got be name and be root, only need
1145 * to set pool name as target.
1146 * if no altroot, need to find be name and root from pool.
1148 if (bam_pool
!= NULL
) {
1149 ret
= nvlist_add_string(nvl
, BE_ATTR_ORIG_BE_POOL
, bam_pool
);
1155 ret
= be_installboot(nvl
);
1162 if (be_list(NULL
, &be_nodes
) != BE_SUCCESS
) {
1163 bam_error(_("No BE's found\n"));
1168 if (bam_pool
!= NULL
) {
1170 * find active be_node in bam_pool
1172 for (node
= be_nodes
; node
!= NULL
; node
= node
->be_next_node
) {
1173 if (strcmp(bam_pool
, node
->be_rpool
) != 0)
1175 if (node
->be_active_on_boot
)
1179 bam_error(_("No active BE in %s\n"), bam_pool
);
1180 be_free_list(be_nodes
);
1184 ret
= nvlist_add_string(nvl
, BE_ATTR_ORIG_BE_NAME
,
1185 node
->be_node_name
);
1186 ret
|= nvlist_add_string(nvl
, BE_ATTR_ORIG_BE_ROOT
,
1188 be_free_list(be_nodes
);
1193 ret
= be_installboot(nvl
);
1200 * get dataset for "/" and fill up the args.
1202 if ((fp
= fopen(MNTTAB
, "r")) == NULL
) {
1203 bam_error(OPEN_FAIL
, MNTTAB
, strerror(errno
));
1205 be_free_list(be_nodes
);
1210 while (getextmntent(fp
, &mnt
, sizeof (mnt
)) == 0) {
1211 if (strcmp(mnt
.mnt_mountp
, "/") == 0) {
1213 root_ds
= strdup(mnt
.mnt_special
);
1220 bam_error(NOT_IN_MNTTAB
, "/");
1222 be_free_list(be_nodes
);
1225 if (root_ds
== NULL
) {
1226 bam_error(_("out of memory\n"));
1228 be_free_list(be_nodes
);
1232 for (node
= be_nodes
; node
!= NULL
; node
= node
->be_next_node
) {
1233 if (strcmp(root_ds
, node
->be_root_ds
) == 0)
1238 bam_error(_("No such BE: %s\n"), root_ds
);
1240 be_free_list(be_nodes
);
1246 ret
= nvlist_add_string(nvl
, BE_ATTR_ORIG_BE_NAME
, node
->be_node_name
);
1247 ret
|= nvlist_add_string(nvl
, BE_ATTR_ORIG_BE_ROOT
, node
->be_root_ds
);
1248 ret
|= nvlist_add_string(nvl
, BE_ATTR_ORIG_BE_POOL
, node
->be_rpool
);
1249 be_free_list(be_nodes
);
1254 ret
= be_installboot(nvl
) ? BAM_ERROR
: 0;
1262 bam_install(char *subcmd
, char *opt
)
1269 if (check_subcmd_and_options(subcmd
, opt
, inst_subcmds
, &f
) ==
1277 bam_menu(char *subcmd
, char *opt
, int largc
, char *largv
[])
1280 char menu_path
[PATH_MAX
];
1281 char clean_menu_root
[PATH_MAX
];
1282 char path
[PATH_MAX
];
1284 char menu_root
[PATH_MAX
];
1286 error_t (*f
)(menu_t
*mp
, char *menu_path
, char *opt
);
1293 const char *fcn
= "bam_menu()";
1296 * Menu sub-command only applies to GRUB (i.e. x86)
1298 if (!is_grub(bam_alt_root
? bam_root
: "/")) {
1299 bam_error(NOT_GRUB_BOOT
);
1306 ret
= check_subcmd_and_options(subcmd
, opt
, menu_subcmds
, &f
);
1307 if (ret
== BAM_ERROR
) {
1313 (void) strlcpy(menu_root
, bam_root
, sizeof (menu_root
));
1314 osdev
= osroot
= NULL
;
1316 if (strcmp(subcmd
, "update_entry") == 0) {
1319 osdev
= strtok(opt
, ",");
1321 osroot
= strtok(NULL
, ",");
1323 /* fixup bam_root so that it points at osroot */
1324 if (realpath(osroot
, rootbuf
) == NULL
) {
1325 bam_error(CANT_RESOLVE
, osroot
,
1331 bam_rootlen
= strlen(rootbuf
);
1336 * We support menu on PCFS (under certain conditions), but
1339 if (is_pcfs(bam_root
)) {
1340 bam_error(PCFS_ROOT_NOTSUP
, bam_root
);
1344 if (stat(menu_root
, &sb
) == -1) {
1345 bam_error(CANNOT_LOCATE_GRUB_MENU
);
1349 BAM_DPRINTF((D_MENU_ROOT
, fcn
, menu_root
));
1352 * We no longer use the GRUB slice file. If it exists, then
1353 * the user is doing something that is unsupported (such as
1354 * standard upgrading an old Live Upgrade BE). If that
1355 * happens, mimic existing behavior i.e. pretend that it is
1356 * not a BE. Emit a warning though.
1359 (void) snprintf(path
, sizeof (path
), "%s%s", bam_root
,
1362 (void) snprintf(path
, sizeof (path
), "%s", GRUB_slice
);
1365 if (bam_verbose
&& stat(path
, &sb
) == 0)
1366 bam_error(GRUB_SLICE_FILE_EXISTS
, path
);
1368 if (is_zfs(menu_root
)) {
1369 assert(strcmp(menu_root
, bam_root
) == 0);
1370 special
= get_special(menu_root
);
1371 INJECT_ERROR1("Z_MENU_GET_SPECIAL", special
= NULL
);
1372 if (special
== NULL
) {
1373 bam_error(CANT_FIND_SPECIAL
, menu_root
);
1376 pool
= strtok(special
, "/");
1377 INJECT_ERROR1("Z_MENU_GET_POOL", pool
= NULL
);
1380 bam_error(CANT_FIND_POOL
, menu_root
);
1383 BAM_DPRINTF((D_Z_MENU_GET_POOL_FROM_SPECIAL
, fcn
, pool
));
1385 zmntpt
= mount_top_dataset(pool
, &zmnted
);
1386 INJECT_ERROR1("Z_MENU_MOUNT_TOP_DATASET", zmntpt
= NULL
);
1387 if (zmntpt
== NULL
) {
1388 bam_error(CANT_MOUNT_POOL_DATASET
, pool
);
1392 BAM_DPRINTF((D_Z_GET_MENU_MOUNT_TOP_DATASET
, fcn
, zmntpt
));
1394 (void) strlcpy(menu_root
, zmntpt
, sizeof (menu_root
));
1395 BAM_DPRINTF((D_Z_GET_MENU_MENU_ROOT
, fcn
, menu_root
));
1398 elide_trailing_slash(menu_root
, clean_menu_root
,
1399 sizeof (clean_menu_root
));
1401 BAM_DPRINTF((D_CLEAN_MENU_ROOT
, fcn
, clean_menu_root
));
1403 (void) strlcpy(menu_path
, clean_menu_root
, sizeof (menu_path
));
1404 (void) strlcat(menu_path
, GRUB_MENU
, sizeof (menu_path
));
1406 BAM_DPRINTF((D_MENU_PATH
, fcn
, menu_path
));
1409 * If listing the menu, display the menu location
1411 if (strcmp(subcmd
, "list_entry") == 0)
1412 bam_print(GRUB_MENU_PATH
, menu_path
);
1414 if ((menu
= menu_read(menu_path
)) == NULL
) {
1415 bam_error(CANNOT_LOCATE_GRUB_MENU_FILE
, menu_path
);
1416 if (special
!= NULL
)
1423 * We already checked the following case in
1424 * check_subcmd_and_suboptions() above. Complete the
1427 if (strcmp(subcmd
, "set_option") == 0) {
1428 assert(largc
== 1 && largv
[0] && largv
[1] == NULL
);
1430 } else if ((strcmp(subcmd
, "enable_hypervisor") != 0) &&
1431 (strcmp(subcmd
, "list_setting") != 0)) {
1432 assert(largc
== 0 && largv
== NULL
);
1435 ret
= get_boot_cap(bam_root
);
1436 if (ret
!= BAM_SUCCESS
) {
1437 BAM_DPRINTF((D_BOOT_GET_CAP_FAILED
, fcn
));
1442 * Once the sub-cmd handler has run
1443 * only the line field is guaranteed to have valid values
1445 if (strcmp(subcmd
, "update_entry") == 0) {
1446 ret
= f(menu
, menu_root
, osdev
);
1447 } else if (strcmp(subcmd
, "upgrade") == 0) {
1448 ret
= f(menu
, bam_root
, menu_root
);
1449 } else if (strcmp(subcmd
, "list_entry") == 0) {
1450 ret
= f(menu
, menu_path
, opt
);
1451 } else if (strcmp(subcmd
, "list_setting") == 0) {
1452 ret
= f(menu
, ((largc
> 0) ? largv
[0] : ""),
1453 ((largc
> 1) ? largv
[1] : ""));
1454 } else if (strcmp(subcmd
, "disable_hypervisor") == 0) {
1456 bam_error(NO_SPARC
, subcmd
);
1459 ret
= f(menu
, bam_root
, NULL
);
1461 } else if (strcmp(subcmd
, "enable_hypervisor") == 0) {
1463 bam_error(NO_SPARC
, subcmd
);
1466 char *extra_args
= NULL
;
1469 * Compress all arguments passed in the largv[] array
1470 * into one string that can then be appended to the
1471 * end of the kernel$ string the routine to enable the
1472 * hypervisor will build.
1474 * This allows the caller to supply arbitrary unparsed
1475 * arguments, such as dom0 memory settings or APIC
1478 * This concatenation will be done without ANY syntax
1479 * checking whatsoever, so it's the responsibility of
1480 * the caller to make sure the arguments are valid and
1481 * do not duplicate arguments the conversion routines
1487 for (extra_len
= 0, i
= 0; i
< largc
; i
++)
1488 extra_len
+= strlen(largv
[i
]);
1491 * Allocate space for argument strings,
1492 * intervening spaces and terminating NULL.
1494 extra_args
= alloca(extra_len
+ largc
);
1496 (void) strcpy(extra_args
, largv
[0]);
1498 for (i
= 1; i
< largc
; i
++) {
1499 (void) strcat(extra_args
, " ");
1500 (void) strcat(extra_args
, largv
[i
]);
1504 ret
= f(menu
, bam_root
, extra_args
);
1507 ret
= f(menu
, NULL
, opt
);
1509 if (ret
== BAM_WRITE
) {
1510 BAM_DPRINTF((D_WRITING_MENU_ROOT
, fcn
, clean_menu_root
));
1511 ret
= menu_write(clean_menu_root
, menu
);
1515 INJECT_ERROR1("POOL_SET", pool
= "/pooldata");
1516 assert((is_zfs(menu_root
)) ^ (pool
== NULL
));
1518 (void) umount_top_dataset(pool
, zmnted
, zmntpt
);
1532 error_t (*f
)(char *root
, char *opt
);
1533 const char *fcn
= "bam_archive()";
1536 * Add trailing / for archive subcommands
1538 if (rootbuf
[strlen(rootbuf
) - 1] != '/')
1539 (void) strcat(rootbuf
, "/");
1540 bam_rootlen
= strlen(rootbuf
);
1545 ret
= check_subcmd_and_options(subcmd
, opt
, arch_subcmds
, &f
);
1546 if (ret
!= BAM_SUCCESS
) {
1550 ret
= get_boot_cap(rootbuf
);
1551 if (ret
!= BAM_SUCCESS
) {
1552 BAM_DPRINTF((D_BOOT_GET_CAP_FAILED
, fcn
));
1557 * Check archive not supported with update_all
1558 * since it is awkward to display out-of-sync
1559 * information for each BE.
1561 if (bam_check
&& strcmp(subcmd
, "update_all") == 0) {
1562 bam_error(CHECK_NOT_SUPPORTED
, subcmd
);
1566 if (strcmp(subcmd
, "update_all") == 0)
1570 ucode_install(bam_root
);
1573 ret
= f(bam_root
, opt
);
1582 bam_error(char *format
, ...)
1586 va_start(ap
, format
);
1587 (void) fprintf(stderr
, "%s: ", prog
);
1588 (void) vfprintf(stderr
, format
, ap
);
1594 bam_derror(char *format
, ...)
1600 va_start(ap
, format
);
1601 (void) fprintf(stderr
, "DEBUG: ");
1602 (void) vfprintf(stderr
, format
, ap
);
1608 bam_print(char *format
, ...)
1612 va_start(ap
, format
);
1613 (void) vfprintf(stdout
, format
, ap
);
1619 bam_print_stderr(char *format
, ...)
1623 va_start(ap
, format
);
1624 (void) vfprintf(stderr
, format
, ap
);
1629 bam_exit(int excode
)
1642 bam_lock_fd
= open(BAM_LOCK_FILE
, O_CREAT
|O_RDWR
, LOCK_FILE_PERMS
);
1643 if (bam_lock_fd
< 0) {
1645 * We may be invoked early in boot for archive verification.
1646 * In this case, root is readonly and /var/run may not exist.
1647 * Proceed without the lock
1649 if (errno
== EROFS
|| errno
== ENOENT
) {
1650 bam_root_readonly
= 1;
1654 bam_error(OPEN_FAIL
, BAM_LOCK_FILE
, strerror(errno
));
1658 lock
.l_type
= F_WRLCK
;
1659 lock
.l_whence
= SEEK_SET
;
1663 if (fcntl(bam_lock_fd
, F_SETLK
, &lock
) == -1) {
1664 if (errno
!= EACCES
&& errno
!= EAGAIN
) {
1665 bam_error(LOCK_FAIL
, BAM_LOCK_FILE
, strerror(errno
));
1666 (void) close(bam_lock_fd
);
1671 (void) pread(bam_lock_fd
, &pid
, sizeof (pid_t
), 0);
1672 bam_print(FILE_LOCKED
, pid
);
1674 lock
.l_type
= F_WRLCK
;
1675 lock
.l_whence
= SEEK_SET
;
1678 if (fcntl(bam_lock_fd
, F_SETLKW
, &lock
) == -1) {
1679 bam_error(LOCK_FAIL
, BAM_LOCK_FILE
, strerror(errno
));
1680 (void) close(bam_lock_fd
);
1686 /* We own the lock now */
1688 (void) write(bam_lock_fd
, &pid
, sizeof (pid
));
1694 struct flock unlock
;
1697 * NOP if we don't hold the lock
1699 if (bam_lock_fd
< 0) {
1703 unlock
.l_type
= F_UNLCK
;
1704 unlock
.l_whence
= SEEK_SET
;
1708 if (fcntl(bam_lock_fd
, F_SETLK
, &unlock
) == -1) {
1709 bam_error(UNLOCK_FAIL
, BAM_LOCK_FILE
, strerror(errno
));
1712 if (close(bam_lock_fd
) == -1) {
1713 bam_error(CLOSE_FAIL
, BAM_LOCK_FILE
, strerror(errno
));
1719 list_archive(char *root
, char *opt
)
1722 filelist_t
*flistp
= &flist
;
1726 assert(opt
== NULL
);
1728 flistp
->head
= flistp
->tail
= NULL
;
1729 if (read_list(root
, flistp
) != BAM_SUCCESS
) {
1732 assert(flistp
->head
&& flistp
->tail
);
1734 for (lp
= flistp
->head
; lp
; lp
= lp
->next
) {
1735 bam_print(PRINT
, lp
->line
);
1738 filelist_free(flistp
);
1740 return (BAM_SUCCESS
);
1744 * This routine writes a list of lines to a file.
1745 * The list is *not* freed
1748 list2file(char *root
, char *tmp
, char *final
, line_t
*start
)
1750 char tmpfile
[PATH_MAX
];
1751 char path
[PATH_MAX
];
1760 const char *fcn
= "list2file()";
1762 (void) snprintf(path
, sizeof (path
), "%s%s", root
, final
);
1764 if (start
== NULL
) {
1765 /* Empty GRUB menu */
1766 if (stat(path
, &sb
) != -1) {
1767 bam_print(UNLINK_EMPTY
, path
);
1768 if (unlink(path
) != 0) {
1769 bam_error(UNLINK_FAIL
, path
, strerror(errno
));
1772 return (BAM_SUCCESS
);
1775 return (BAM_SUCCESS
);
1779 * Preserve attributes of existing file if possible,
1780 * otherwise ask the system for uid/gid of root/sys.
1781 * If all fails, fall back on hard-coded defaults.
1783 if (stat(path
, &sb
) != -1) {
1785 root_uid
= sb
.st_uid
;
1786 sys_gid
= sb
.st_gid
;
1788 mode
= DEFAULT_DEV_MODE
;
1789 if ((pw
= getpwnam(DEFAULT_DEV_USER
)) != NULL
) {
1790 root_uid
= pw
->pw_uid
;
1792 bam_error(CANT_FIND_USER
,
1793 DEFAULT_DEV_USER
, DEFAULT_DEV_UID
);
1794 root_uid
= (uid_t
)DEFAULT_DEV_UID
;
1796 if ((gp
= getgrnam(DEFAULT_DEV_GROUP
)) != NULL
) {
1797 sys_gid
= gp
->gr_gid
;
1799 bam_error(CANT_FIND_GROUP
,
1800 DEFAULT_DEV_GROUP
, DEFAULT_DEV_GID
);
1801 sys_gid
= (gid_t
)DEFAULT_DEV_GID
;
1805 (void) snprintf(tmpfile
, sizeof (tmpfile
), "%s%s", root
, tmp
);
1807 /* Truncate tmpfile first */
1808 fp
= fopen(tmpfile
, "w");
1810 bam_error(OPEN_FAIL
, tmpfile
, strerror(errno
));
1814 INJECT_ERROR1("LIST2FILE_TRUNC_FCLOSE", ret
= EOF
);
1816 bam_error(CLOSE_FAIL
, tmpfile
, strerror(errno
));
1820 /* Now open it in append mode */
1821 fp
= fopen(tmpfile
, "a");
1823 bam_error(OPEN_FAIL
, tmpfile
, strerror(errno
));
1827 for (; start
; start
= start
->next
) {
1828 ret
= s_fputs(start
->line
, fp
);
1829 INJECT_ERROR1("LIST2FILE_FPUTS", ret
= EOF
);
1831 bam_error(WRITE_FAIL
, tmpfile
, strerror(errno
));
1838 INJECT_ERROR1("LIST2FILE_APPEND_FCLOSE", ret
= EOF
);
1840 bam_error(CLOSE_FAIL
, tmpfile
, strerror(errno
));
1845 * Set up desired attributes. Ignore failures on filesystems
1846 * not supporting these operations - pcfs reports unsupported
1847 * operations as EINVAL.
1849 ret
= chmod(tmpfile
, mode
);
1851 errno
!= EINVAL
&& errno
!= ENOTSUP
) {
1852 bam_error(CHMOD_FAIL
, tmpfile
, strerror(errno
));
1856 ret
= chown(tmpfile
, root_uid
, sys_gid
);
1858 errno
!= EINVAL
&& errno
!= ENOTSUP
) {
1859 bam_error(CHOWN_FAIL
, tmpfile
, strerror(errno
));
1864 * Do an atomic rename
1866 ret
= rename(tmpfile
, path
);
1867 INJECT_ERROR1("LIST2FILE_RENAME", ret
= -1);
1869 bam_error(RENAME_FAIL
, path
, strerror(errno
));
1873 BAM_DPRINTF((D_WROTE_FILE
, fcn
, path
));
1874 return (BAM_SUCCESS
);
1878 * Checks if the path specified (without the file name at the end) exists
1879 * and creates it if not. If the path exists and is not a directory, an attempt
1880 * to unlink is made.
1883 setup_path(char *path
)
1889 p
= strrchr(path
, '/');
1892 if (stat(path
, &sb
) != 0 || !(S_ISDIR(sb
.st_mode
))) {
1893 /* best effort attempt, mkdirp will catch the error */
1894 (void) unlink(path
);
1896 bam_print(NEED_DIRPATH
, path
);
1897 ret
= mkdirp(path
, DIR_PERMS
);
1899 bam_error(MKDIR_FAILED
, path
, strerror(errno
));
1905 return (BAM_SUCCESS
);
1907 return (BAM_SUCCESS
);
1916 char path
[PATH_MAX
];
1921 setup_file(char *base
, const char *path
, cachefile
*cf
)
1926 /* init gzfile or fdfile in case we fail before opening */
1927 if (bam_direct
== BAM_DIRECT_DBOOT
)
1928 cf
->out
.gzfile
= NULL
;
1930 cf
->out
.fdfile
= -1;
1932 /* strip the trailing altroot path */
1933 strip
= (char *)path
+ strlen(rootbuf
);
1935 ret
= snprintf(cf
->path
, sizeof (cf
->path
), "%s/%s", base
, strip
);
1936 if (ret
>= sizeof (cf
->path
)) {
1937 bam_error(PATH_TOO_LONG
, rootbuf
);
1941 /* Check if path is present in the archive cache directory */
1942 if (setup_path(cf
->path
) == BAM_ERROR
)
1945 if (bam_direct
== BAM_DIRECT_DBOOT
) {
1946 if ((cf
->out
.gzfile
= gzopen(cf
->path
, "wb")) == NULL
) {
1947 bam_error(OPEN_FAIL
, cf
->path
, strerror(errno
));
1950 (void) gzsetparams(cf
->out
.gzfile
, Z_BEST_SPEED
,
1951 Z_DEFAULT_STRATEGY
);
1953 if ((cf
->out
.fdfile
= open(cf
->path
, O_WRONLY
| O_CREAT
, 0644))
1955 bam_error(OPEN_FAIL
, cf
->path
, strerror(errno
));
1960 return (BAM_SUCCESS
);
1964 cache_write(cachefile cf
, char *buf
, int size
)
1968 if (bam_direct
== BAM_DIRECT_DBOOT
) {
1969 if (gzwrite(cf
.out
.gzfile
, buf
, size
) < 1) {
1970 bam_error(GZ_WRITE_FAIL
, gzerror(cf
.out
.gzfile
, &err
));
1971 if (err
== Z_ERRNO
&& bam_verbose
) {
1972 bam_error(WRITE_FAIL
, cf
.path
, strerror(errno
));
1977 if (write(cf
.out
.fdfile
, buf
, size
) < 1) {
1978 bam_error(WRITE_FAIL
, cf
.path
, strerror(errno
));
1982 return (BAM_SUCCESS
);
1986 cache_close(cachefile cf
)
1990 if (bam_direct
== BAM_DIRECT_DBOOT
) {
1991 if (cf
.out
.gzfile
) {
1992 ret
= gzclose(cf
.out
.gzfile
);
1994 bam_error(CLOSE_FAIL
, cf
.path
, strerror(errno
));
1999 if (cf
.out
.fdfile
!= -1) {
2000 ret
= close(cf
.out
.fdfile
);
2002 bam_error(CLOSE_FAIL
, cf
.path
, strerror(errno
));
2008 return (BAM_SUCCESS
);
2012 dircache_updatefile(const char *path
, int what
)
2017 cachefile outfile
, outupdt
;
2019 if (bam_nowrite()) {
2020 set_dir_flag(what
, NEED_UPDATE
);
2021 return (BAM_SUCCESS
);
2024 if (!has_cachedir(what
))
2025 return (BAM_SUCCESS
);
2027 if ((infile
= fopen(path
, "rb")) == NULL
) {
2028 bam_error(OPEN_FAIL
, path
, strerror(errno
));
2032 ret
= setup_file(get_cachedir(what
), path
, &outfile
);
2033 if (ret
== BAM_ERROR
) {
2034 exitcode
= BAM_ERROR
;
2037 if (!is_dir_flag_on(what
, NO_MULTI
)) {
2038 ret
= setup_file(get_updatedir(what
), path
, &outupdt
);
2039 if (ret
== BAM_ERROR
)
2040 set_dir_flag(what
, NO_MULTI
);
2043 while ((ret
= fread(buf
, 1, sizeof (buf
), infile
)) > 0) {
2044 if (cache_write(outfile
, buf
, ret
) == BAM_ERROR
) {
2045 exitcode
= BAM_ERROR
;
2048 if (!is_dir_flag_on(what
, NO_MULTI
))
2049 if (cache_write(outupdt
, buf
, ret
) == BAM_ERROR
)
2050 set_dir_flag(what
, NO_MULTI
);
2053 set_dir_flag(what
, NEED_UPDATE
);
2055 if (get_count(what
) > COUNT_MAX
)
2056 set_dir_flag(what
, NO_MULTI
);
2057 exitcode
= BAM_SUCCESS
;
2059 (void) fclose(infile
);
2060 if (cache_close(outfile
) == BAM_ERROR
)
2061 exitcode
= BAM_ERROR
;
2062 if (!is_dir_flag_on(what
, NO_MULTI
) &&
2063 cache_close(outupdt
) == BAM_ERROR
)
2064 exitcode
= BAM_ERROR
;
2065 if (exitcode
== BAM_ERROR
)
2066 set_flag(UPDATE_ERROR
);
2071 dircache_updatedir(const char *path
, int what
, int updt
)
2074 char dpath
[PATH_MAX
];
2078 strip
= (char *)path
+ strlen(rootbuf
);
2080 ret
= snprintf(dpath
, sizeof (dpath
), "%s/%s", updt
?
2081 get_updatedir(what
) : get_cachedir(what
), strip
);
2083 if (ret
>= sizeof (dpath
)) {
2084 bam_error(PATH_TOO_LONG
, rootbuf
);
2085 set_flag(UPDATE_ERROR
);
2089 if (stat(dpath
, &sb
) == 0 && S_ISDIR(sb
.st_mode
))
2090 return (BAM_SUCCESS
);
2093 if (!is_dir_flag_on(what
, NO_MULTI
))
2094 if (!bam_nowrite() && mkdirp(dpath
, DIR_PERMS
) == -1)
2095 set_dir_flag(what
, NO_MULTI
);
2097 if (!bam_nowrite() && mkdirp(dpath
, DIR_PERMS
) == -1) {
2098 set_flag(UPDATE_ERROR
);
2103 set_dir_flag(what
, NEED_UPDATE
);
2104 return (BAM_SUCCESS
);
2107 #define DO_CACHE_DIR 0
2108 #define DO_UPDATE_DIR 1
2110 #if defined(_LP64) || defined(_LONGLONG_TYPE)
2111 typedef Elf64_Ehdr _elfhdr
;
2113 typedef Elf32_Ehdr _elfhdr
;
2117 * This routine updates the contents of the cache directory
2120 update_dircache(const char *path
, int flags
)
2122 int rc
= BAM_SUCCESS
;
2130 if ((fd
= open(path
, O_RDONLY
)) < 0) {
2131 bam_error(OPEN_FAIL
, path
, strerror(errno
));
2132 set_flag(UPDATE_ERROR
);
2138 * libelf and gelf would be a cleaner and easier way to handle
2139 * this, but libelf fails compilation if _ILP32 is defined &&
2140 * _FILE_OFFSET_BITS is != 32 ...
2142 if (read(fd
, (void *)&elf
, sizeof (_elfhdr
)) < 0) {
2143 bam_error(READ_FAIL
, path
, strerror(errno
));
2144 set_flag(UPDATE_ERROR
);
2152 * If the file is not an executable and is not inside an amd64
2153 * directory, we copy it in both the cache directories,
2154 * otherwise, we only copy it inside the 64-bit one.
2156 if (memcmp(elf
.e_ident
, ELFMAG
, 4) != 0) {
2157 if (strstr(path
, "/amd64")) {
2158 rc
= dircache_updatefile(path
, FILE64
);
2160 rc
= dircache_updatefile(path
, FILE32
);
2161 if (rc
== BAM_SUCCESS
)
2162 rc
= dircache_updatefile(path
, FILE64
);
2166 * Based on the ELF class we copy the file in the 32-bit
2167 * or the 64-bit cache directory.
2169 if (elf
.e_ident
[EI_CLASS
] == ELFCLASS32
) {
2170 rc
= dircache_updatefile(path
, FILE32
);
2171 } else if (elf
.e_ident
[EI_CLASS
] == ELFCLASS64
) {
2172 rc
= dircache_updatefile(path
, FILE64
);
2174 bam_print(NO3264ELF
, path
);
2176 rc
= dircache_updatefile(path
, FILE32
);
2177 if (rc
== BAM_SUCCESS
)
2178 rc
= dircache_updatefile(path
, FILE64
);
2184 if (strstr(path
, "/amd64") == NULL
) {
2185 rc
= dircache_updatedir(path
, FILE32
, DO_UPDATE_DIR
);
2186 if (rc
== BAM_SUCCESS
)
2187 rc
= dircache_updatedir(path
, FILE32
,
2190 if (has_cachedir(FILE64
)) {
2191 rc
= dircache_updatedir(path
, FILE64
,
2193 if (rc
== BAM_SUCCESS
)
2194 rc
= dircache_updatedir(path
, FILE64
,
2211 const struct stat
*st
,
2217 uint64_t filestat
[2];
2218 int error
, ret
, status
;
2220 struct safefile
*safefilep
;
2226 * On SPARC we create/update links too.
2228 if (flags
!= FTW_F
&& flags
!= FTW_D
&& (flags
== FTW_SL
&&
2229 !is_flag_on(IS_SPARC_TARGET
)))
2233 * Ignore broken links
2235 if (flags
== FTW_SL
&& stat(file
, &sb
) < 0)
2239 * new_nvlp may be NULL if there were errors earlier
2240 * but this is not fatal to update determination.
2242 if (walk_arg
.new_nvlp
) {
2243 filestat
[0] = st
->st_size
;
2244 filestat
[1] = st
->st_mtime
;
2245 error
= nvlist_add_uint64_array(walk_arg
.new_nvlp
,
2246 file
+ bam_rootlen
, filestat
, 2);
2248 bam_error(NVADD_FAIL
, file
, strerror(error
));
2252 * If we are invoked as part of system/filesystem/boot-archive, then
2253 * there are a number of things we should not worry about
2255 if (bam_smf_check
) {
2256 /* ignore amd64 modules unless we are booted amd64. */
2257 if (!is_amd64() && strstr(file
, "/amd64/") != 0)
2260 /* read in list of safe files */
2261 if (safefiles
== NULL
)
2262 if (fp
= fopen("/boot/solaris/filelist.safe", "r")) {
2263 safefiles
= s_calloc(1,
2264 sizeof (struct safefile
));
2265 safefilep
= safefiles
;
2266 safefilep
->name
= s_calloc(1, MAXPATHLEN
+
2268 safefilep
->next
= NULL
;
2269 while (s_fgets(safefilep
->name
, MAXPATHLEN
+
2270 MAXNAMELEN
, fp
) != NULL
) {
2271 safefilep
->next
= s_calloc(1,
2272 sizeof (struct safefile
));
2273 safefilep
= safefilep
->next
;
2274 safefilep
->name
= s_calloc(1,
2275 MAXPATHLEN
+ MAXNAMELEN
);
2276 safefilep
->next
= NULL
;
2283 * On SPARC we create a -path-list file for mkisofs
2285 if (is_flag_on(IS_SPARC_TARGET
) && !bam_nowrite()) {
2286 if (flags
!= FTW_D
) {
2289 strip
= (char *)file
+ strlen(rootbuf
);
2290 (void) fprintf(walk_arg
.sparcfile
, "/%s=%s\n", strip
,
2296 * We are transitioning from the old model to the dircache or the cache
2297 * directory was removed: create the entry without further checkings.
2299 if (is_flag_on(NEED_CACHE_DIR
)) {
2301 bam_print(PARSEABLE_NEW_FILE
, file
);
2303 if (is_flag_on(IS_SPARC_TARGET
)) {
2304 set_dir_flag(FILE64
, NEED_UPDATE
);
2308 ret
= update_dircache(file
, flags
);
2309 if (ret
== BAM_ERROR
) {
2310 bam_error(UPDT_CACHE_FAIL
, file
);
2318 * We need an update if file doesn't exist in old archive
2320 if (walk_arg
.old_nvlp
== NULL
||
2321 nvlist_lookup_uint64_array(walk_arg
.old_nvlp
,
2322 file
+ bam_rootlen
, &value
, &sz
) != 0) {
2323 if (bam_smf_check
) /* ignore new during smf check */
2326 if (is_flag_on(IS_SPARC_TARGET
)) {
2327 set_dir_flag(FILE64
, NEED_UPDATE
);
2329 ret
= update_dircache(file
, flags
);
2330 if (ret
== BAM_ERROR
) {
2331 bam_error(UPDT_CACHE_FAIL
, file
);
2337 bam_print(PARSEABLE_NEW_FILE
, file
);
2342 * If we got there, the file is already listed as to be included in the
2343 * iso image. We just need to know if we are going to rebuild it or not
2345 if (is_flag_on(IS_SPARC_TARGET
) &&
2346 is_dir_flag_on(FILE64
, NEED_UPDATE
) && !bam_nowrite())
2349 * File exists in old archive. Check if file has changed
2352 bcopy(value
, filestat
, sizeof (filestat
));
2354 if (flags
!= FTW_D
&& (filestat
[0] != st
->st_size
||
2355 filestat
[1] != st
->st_mtime
)) {
2356 if (bam_smf_check
) {
2357 safefilep
= safefiles
;
2358 while (safefilep
!= NULL
&&
2359 safefilep
->name
[0] != '\0') {
2360 if (regcomp(&re
, safefilep
->name
,
2361 REG_EXTENDED
|REG_NOSUB
) == 0) {
2362 status
= regexec(&re
,
2363 file
+ bam_rootlen
, 0, NULL
, 0);
2367 NEED_UPDATE_SAFE_FILE
,
2372 safefilep
= safefilep
->next
;
2376 if (is_flag_on(IS_SPARC_TARGET
)) {
2377 set_dir_flag(FILE64
, NEED_UPDATE
);
2379 ret
= update_dircache(file
, flags
);
2380 if (ret
== BAM_ERROR
) {
2381 bam_error(UPDT_CACHE_FAIL
, file
);
2388 bam_print(" %s\n", file
);
2390 bam_print(PARSEABLE_OUT_DATE
, file
);
2397 * Remove a directory path recursively
2402 struct dirent
*d
= NULL
;
2404 char tpath
[PATH_MAX
];
2407 if ((dir
= opendir(path
)) == NULL
)
2410 while (d
= readdir(dir
)) {
2411 if ((strcmp(d
->d_name
, ".") != 0) &&
2412 (strcmp(d
->d_name
, "..") != 0)) {
2413 (void) snprintf(tpath
, sizeof (tpath
), "%s/%s",
2415 if (stat(tpath
, &sb
) == 0) {
2416 if (sb
.st_mode
& S_IFDIR
)
2417 (void) rmdir_r(tpath
);
2419 (void) remove(tpath
);
2423 return (remove(path
));
2427 * Check if cache directory exists and, if not, create it and update flags
2428 * accordingly. If the path exists, but it's not a directory, a best effort
2429 * attempt to remove and recreate it is made.
2430 * If the user requested a 'purge', always recreate the directory from scratch.
2433 set_cache_dir(char *root
, int what
)
2438 ret
= snprintf(get_cachedir(what
), sizeof (get_cachedir(what
)),
2439 "%s%s%s%s%s", root
, ARCHIVE_PREFIX
, get_machine(), what
== FILE64
?
2440 "/amd64" : "", CACHEDIR_SUFFIX
);
2442 if (ret
>= sizeof (get_cachedir(what
))) {
2443 bam_error(PATH_TOO_LONG
, rootbuf
);
2447 if (bam_purge
|| is_flag_on(INVALIDATE_CACHE
))
2448 (void) rmdir_r(get_cachedir(what
));
2450 if (stat(get_cachedir(what
), &sb
) != 0 || !(S_ISDIR(sb
.st_mode
))) {
2451 /* best effort unlink attempt, mkdir will catch errors */
2452 (void) unlink(get_cachedir(what
));
2455 bam_print(UPDATE_CDIR_MISS
, get_cachedir(what
));
2456 ret
= mkdir(get_cachedir(what
), DIR_PERMS
);
2458 bam_error(MKDIR_FAILED
, get_cachedir(what
),
2460 get_cachedir(what
)[0] = '\0';
2463 set_flag(NEED_CACHE_DIR
);
2464 set_dir_flag(what
, NO_MULTI
);
2467 return (BAM_SUCCESS
);
2471 set_update_dir(char *root
, int what
)
2476 if (is_dir_flag_on(what
, NO_MULTI
))
2477 return (BAM_SUCCESS
);
2480 set_dir_flag(what
, NO_MULTI
);
2481 return (BAM_SUCCESS
);
2484 if (what
== FILE64
&& !is_flag_on(IS_SPARC_TARGET
))
2485 ret
= snprintf(get_updatedir(what
),
2486 sizeof (get_updatedir(what
)), "%s%s%s/amd64%s", root
,
2487 ARCHIVE_PREFIX
, get_machine(), UPDATEDIR_SUFFIX
);
2489 ret
= snprintf(get_updatedir(what
),
2490 sizeof (get_updatedir(what
)), "%s%s%s%s", root
,
2491 ARCHIVE_PREFIX
, get_machine(), UPDATEDIR_SUFFIX
);
2493 if (ret
>= sizeof (get_updatedir(what
))) {
2494 bam_error(PATH_TOO_LONG
, rootbuf
);
2498 if (stat(get_updatedir(what
), &sb
) == 0) {
2499 if (S_ISDIR(sb
.st_mode
))
2500 ret
= rmdir_r(get_updatedir(what
));
2502 ret
= unlink(get_updatedir(what
));
2505 set_dir_flag(what
, NO_MULTI
);
2508 if (mkdir(get_updatedir(what
), DIR_PERMS
) < 0)
2509 set_dir_flag(what
, NO_MULTI
);
2511 return (BAM_SUCCESS
);
2515 is_valid_archive(char *root
, int what
)
2517 char archive_path
[PATH_MAX
];
2518 char timestamp_path
[PATH_MAX
];
2519 struct stat sb
, timestamp
;
2522 if (what
== FILE64
&& !is_flag_on(IS_SPARC_TARGET
))
2523 ret
= snprintf(archive_path
, sizeof (archive_path
),
2524 "%s%s%s/amd64%s", root
, ARCHIVE_PREFIX
, get_machine(),
2527 ret
= snprintf(archive_path
, sizeof (archive_path
), "%s%s%s%s",
2528 root
, ARCHIVE_PREFIX
, get_machine(), ARCHIVE_SUFFIX
);
2530 if (ret
>= sizeof (archive_path
)) {
2531 bam_error(PATH_TOO_LONG
, rootbuf
);
2535 if (stat(archive_path
, &sb
) != 0) {
2536 if (bam_verbose
&& !bam_check
)
2537 bam_print(UPDATE_ARCH_MISS
, archive_path
);
2538 set_dir_flag(what
, NEED_UPDATE
);
2539 set_dir_flag(what
, NO_MULTI
);
2540 return (BAM_SUCCESS
);
2544 * The timestamp file is used to prevent stale files in the archive
2546 * Stale files can happen if the system is booted back and forth across
2547 * the transition from bootadm-before-the-cache to
2548 * bootadm-after-the-cache, since older versions of bootadm don't know
2549 * about the existence of the archive cache.
2551 * Since only bootadm-after-the-cache versions know about about this
2552 * file, we require that the boot archive be older than this file.
2554 ret
= snprintf(timestamp_path
, sizeof (timestamp_path
), "%s%s", root
,
2555 FILE_STAT_TIMESTAMP
);
2557 if (ret
>= sizeof (timestamp_path
)) {
2558 bam_error(PATH_TOO_LONG
, rootbuf
);
2562 if (stat(timestamp_path
, ×tamp
) != 0 ||
2563 sb
.st_mtime
> timestamp
.st_mtime
) {
2564 if (bam_verbose
&& !bam_check
)
2565 bam_print(UPDATE_CACHE_OLD
);
2567 * Don't generate a false positive for the boot-archive service
2568 * but trigger an update of the archive cache in
2569 * boot-archive-update.
2571 if (bam_smf_check
) {
2572 (void) creat(NEED_UPDATE_FILE
, 0644);
2573 return (BAM_SUCCESS
);
2576 set_flag(INVALIDATE_CACHE
);
2577 set_dir_flag(what
, NEED_UPDATE
);
2578 set_dir_flag(what
, NO_MULTI
);
2579 return (BAM_SUCCESS
);
2582 if (is_flag_on(IS_SPARC_TARGET
))
2583 return (BAM_SUCCESS
);
2585 if (bam_extend
&& sb
.st_size
> BA_SIZE_MAX
) {
2586 if (bam_verbose
&& !bam_check
)
2587 bam_print(MULTI_SIZE
, archive_path
, BA_SIZE_MAX
);
2588 set_dir_flag(what
, NO_MULTI
);
2591 return (BAM_SUCCESS
);
2595 * Check flags and presence of required files and directories.
2596 * The force flag and/or absence of files should
2597 * trigger an update.
2598 * Suppress stdout output if check (-n) option is set
2599 * (as -n should only produce parseable output.)
2602 check_flags_and_files(char *root
)
2609 * If archive is missing, create archive
2611 if (is_flag_on(IS_SPARC_TARGET
)) {
2612 ret
= is_valid_archive(root
, FILE64
);
2613 if (ret
== BAM_ERROR
)
2618 ret
= is_valid_archive(root
, what
);
2619 if (ret
== BAM_ERROR
)
2622 } while (bam_direct
== BAM_DIRECT_DBOOT
&& what
< CACHEDIR_NUM
);
2626 return (BAM_SUCCESS
);
2630 * check if cache directories exist on x86.
2631 * check (and always open) the cache file on SPARC.
2634 ret
= snprintf(get_cachedir(FILE64
),
2635 sizeof (get_cachedir(FILE64
)), "%s%s%s/%s", root
,
2636 ARCHIVE_PREFIX
, get_machine(), CACHEDIR_SUFFIX
);
2638 if (ret
>= sizeof (get_cachedir(FILE64
))) {
2639 bam_error(PATH_TOO_LONG
, rootbuf
);
2643 if (stat(get_cachedir(FILE64
), &sb
) != 0) {
2644 set_flag(NEED_CACHE_DIR
);
2645 set_dir_flag(FILE64
, NEED_UPDATE
);
2648 walk_arg
.sparcfile
= fopen(get_cachedir(FILE64
), "w");
2649 if (walk_arg
.sparcfile
== NULL
) {
2650 bam_error(OPEN_FAIL
, get_cachedir(FILE64
),
2655 set_dir_present(FILE64
);
2660 if (set_cache_dir(root
, what
) != 0)
2663 set_dir_present(what
);
2665 if (set_update_dir(root
, what
) != 0)
2668 } while (bam_direct
== BAM_DIRECT_DBOOT
&& what
< CACHEDIR_NUM
);
2672 * if force, create archive unconditionally
2676 set_dir_flag(FILE32
, NEED_UPDATE
);
2677 set_dir_flag(FILE64
, NEED_UPDATE
);
2679 bam_print(UPDATE_FORCE
);
2680 return (BAM_SUCCESS
);
2683 return (BAM_SUCCESS
);
2687 read_one_list(char *root
, filelist_t
*flistp
, char *filelist
)
2689 char path
[PATH_MAX
];
2691 char buf
[BAM_MAXLINE
];
2692 const char *fcn
= "read_one_list()";
2694 (void) snprintf(path
, sizeof (path
), "%s%s", root
, filelist
);
2696 fp
= fopen(path
, "r");
2698 BAM_DPRINTF((D_FLIST_FAIL
, fcn
, path
, strerror(errno
)));
2701 while (s_fgets(buf
, sizeof (buf
), fp
) != NULL
) {
2702 /* skip blank lines */
2703 if (strspn(buf
, " \t") == strlen(buf
))
2705 append_to_flist(flistp
, buf
);
2707 if (fclose(fp
) != 0) {
2708 bam_error(CLOSE_FAIL
, path
, strerror(errno
));
2711 return (BAM_SUCCESS
);
2715 read_list(char *root
, filelist_t
*flistp
)
2717 char path
[PATH_MAX
];
2721 const char *fcn
= "read_list()";
2723 flistp
->head
= flistp
->tail
= NULL
;
2726 * build and check path to extract_boot_filelist.ksh
2728 n
= snprintf(path
, sizeof (path
), "%s%s", root
, EXTRACT_BOOT_FILELIST
);
2729 if (n
>= sizeof (path
)) {
2730 bam_error(NO_FLIST
);
2734 if (is_safe_exec(path
) == BAM_ERROR
)
2738 * If extract_boot_filelist is present, exec it, otherwise read
2739 * the filelists directly, for compatibility with older images.
2741 if (stat(path
, &sb
) == 0) {
2743 * build arguments to exec extract_boot_filelist.ksh
2745 char *rootarg
, *platarg
;
2746 int platarglen
= 1, rootarglen
= 1;
2747 if (strlen(root
) > 1)
2748 rootarglen
+= strlen(root
) + strlen("-R ");
2749 if (bam_alt_platform
)
2750 platarglen
+= strlen(bam_platform
) + strlen("-p ");
2751 platarg
= s_calloc(1, platarglen
);
2752 rootarg
= s_calloc(1, rootarglen
);
2756 if (strlen(root
) > 1) {
2757 (void) snprintf(rootarg
, rootarglen
,
2760 if (bam_alt_platform
) {
2761 (void) snprintf(platarg
, platarglen
,
2762 "-p %s", bam_platform
);
2764 n
= snprintf(cmd
, sizeof (cmd
), "%s %s %s /%s /%s",
2765 path
, rootarg
, platarg
, BOOT_FILE_LIST
, ETC_FILE_LIST
);
2768 if (n
>= sizeof (cmd
)) {
2769 bam_error(NO_FLIST
);
2772 if (exec_cmd(cmd
, flistp
) != 0) {
2773 BAM_DPRINTF((D_FLIST_FAIL
, fcn
, path
, strerror(errno
)));
2778 * Read current lists of files - only the first is mandatory
2780 rval
= read_one_list(root
, flistp
, BOOT_FILE_LIST
);
2781 if (rval
!= BAM_SUCCESS
)
2783 (void) read_one_list(root
, flistp
, ETC_FILE_LIST
);
2786 if (flistp
->head
== NULL
) {
2787 bam_error(NO_FLIST
);
2791 return (BAM_SUCCESS
);
2795 getoldstat(char *root
)
2797 char path
[PATH_MAX
];
2802 (void) snprintf(path
, sizeof (path
), "%s%s", root
, FILE_STAT
);
2803 fd
= open(path
, O_RDONLY
);
2806 bam_print(OPEN_FAIL
, path
, strerror(errno
));
2810 if (fstat(fd
, &sb
) != 0) {
2811 bam_error(STAT_FAIL
, path
, strerror(errno
));
2815 ostat
= s_calloc(1, sb
.st_size
);
2817 if (read(fd
, ostat
, sb
.st_size
) != sb
.st_size
) {
2818 bam_error(READ_FAIL
, path
, strerror(errno
));
2826 walk_arg
.old_nvlp
= NULL
;
2827 error
= nvlist_unpack(ostat
, sb
.st_size
, &walk_arg
.old_nvlp
, 0);
2832 bam_error(UNPACK_FAIL
, path
, strerror(error
));
2833 walk_arg
.old_nvlp
= NULL
;
2842 if (!is_flag_on(IS_SPARC_TARGET
))
2843 set_dir_flag(FILE32
, NEED_UPDATE
);
2844 set_dir_flag(FILE64
, NEED_UPDATE
);
2847 /* Best effort stale entry removal */
2849 delete_stale(char *file
, int what
)
2851 char path
[PATH_MAX
];
2854 (void) snprintf(path
, sizeof (path
), "%s/%s", get_cachedir(what
), file
);
2855 if (!bam_check
&& stat(path
, &sb
) == 0) {
2856 if (sb
.st_mode
& S_IFDIR
)
2857 (void) rmdir_r(path
);
2859 (void) unlink(path
);
2861 set_dir_flag(what
, (NEED_UPDATE
| NO_MULTI
));
2866 * Checks if a file in the current (old) archive has
2867 * been deleted from the root filesystem. This is needed for
2868 * software like Trusted Extensions (TX) that switch early
2869 * in boot based on presence/absence of a kernel module.
2872 check4stale(char *root
)
2877 char path
[PATH_MAX
];
2880 * Skip stale file check during smf check
2886 * If we need to (re)create the cache, there's no need to check for
2889 if (is_flag_on(NEED_CACHE_DIR
))
2892 /* Nothing to do if no old stats */
2893 if ((nvlp
= walk_arg
.old_nvlp
) == NULL
)
2896 for (nvp
= nvlist_next_nvpair(nvlp
, NULL
); nvp
;
2897 nvp
= nvlist_next_nvpair(nvlp
, nvp
)) {
2898 file
= nvpair_name(nvp
);
2901 (void) snprintf(path
, sizeof (path
), "%s/%s",
2903 if (access(path
, F_OK
) < 0) {
2907 bam_print(PARSEABLE_STALE_FILE
, path
);
2909 if (is_flag_on(IS_SPARC_TARGET
)) {
2910 set_dir_flag(FILE64
, NEED_UPDATE
);
2912 for (what
= FILE32
; what
< CACHEDIR_NUM
; what
++)
2913 if (has_cachedir(what
))
2914 delete_stale(file
, what
);
2921 create_newstat(void)
2925 error
= nvlist_alloc(&walk_arg
.new_nvlp
, NV_UNIQUE_NAME
, 0);
2928 * Not fatal - we can still create archive
2930 walk_arg
.new_nvlp
= NULL
;
2931 bam_error(NVALLOC_FAIL
, strerror(error
));
2936 walk_list(char *root
, filelist_t
*flistp
)
2938 char path
[PATH_MAX
];
2941 for (lp
= flistp
->head
; lp
; lp
= lp
->next
) {
2943 * Don't follow symlinks. A symlink must refer to
2944 * a file that would appear in the archive through
2945 * a direct reference. This matches the archive
2946 * construction behavior.
2948 (void) snprintf(path
, sizeof (path
), "%s%s", root
, lp
->line
);
2949 if (nftw(path
, cmpstat
, 20, FTW_PHYS
) == -1) {
2950 if (is_flag_on(UPDATE_ERROR
))
2953 * Some files may not exist.
2954 * For example: etc/rtc_config on a x86 diskless system
2955 * Emit verbose message only
2958 bam_print(NFTW_FAIL
, path
, strerror(errno
));
2962 return (BAM_SUCCESS
);
2966 * Update the timestamp file.
2969 update_timestamp(char *root
)
2971 char timestamp_path
[PATH_MAX
];
2973 /* this path length has already been checked in check_flags_and_files */
2974 (void) snprintf(timestamp_path
, sizeof (timestamp_path
), "%s%s", root
,
2975 FILE_STAT_TIMESTAMP
);
2978 * recreate the timestamp file. Since an outdated or absent timestamp
2979 * file translates in a complete rebuild of the archive cache, notify
2980 * the user of the performance issue.
2982 if (creat(timestamp_path
, FILE_STAT_MODE
) < 0) {
2983 bam_error(OPEN_FAIL
, timestamp_path
, strerror(errno
));
2984 bam_error(TIMESTAMP_FAIL
);
2992 char path
[PATH_MAX
];
2993 char path2
[PATH_MAX
];
2996 int fd
, wrote
, error
;
3000 error
= nvlist_pack(walk_arg
.new_nvlp
, &nstat
, &sz
,
3003 bam_error(PACK_FAIL
, strerror(error
));
3007 (void) snprintf(path
, sizeof (path
), "%s%s", root
, FILE_STAT_TMP
);
3008 fd
= open(path
, O_RDWR
|O_CREAT
|O_TRUNC
, FILE_STAT_MODE
);
3010 bam_error(OPEN_FAIL
, path
, strerror(errno
));
3014 wrote
= write(fd
, nstat
, sz
);
3016 bam_error(WRITE_FAIL
, path
, strerror(errno
));
3024 (void) snprintf(path2
, sizeof (path2
), "%s%s", root
, FILE_STAT
);
3025 if (rename(path
, path2
) != 0) {
3026 bam_error(RENAME_FAIL
, path2
, strerror(errno
));
3030 #define init_walk_args() bzero(&walk_arg, sizeof (walk_arg))
3033 clear_walk_args(void)
3035 nvlist_free(walk_arg
.old_nvlp
);
3036 nvlist_free(walk_arg
.new_nvlp
);
3037 if (walk_arg
.sparcfile
)
3038 (void) fclose(walk_arg
.sparcfile
);
3039 walk_arg
.old_nvlp
= NULL
;
3040 walk_arg
.new_nvlp
= NULL
;
3041 walk_arg
.sparcfile
= NULL
;
3046 * 0 - no update necessary
3047 * 1 - update required.
3048 * BAM_ERROR (-1) - An error occurred
3050 * Special handling for check (-n):
3051 * ================================
3052 * The check (-n) option produces parseable output.
3053 * To do this, we suppress all stdout messages unrelated
3054 * to out of sync files.
3055 * All stderr messages are still printed though.
3059 update_required(char *root
)
3062 char path
[PATH_MAX
];
3064 filelist_t
*flistp
= &flist
;
3067 flistp
->head
= flistp
->tail
= NULL
;
3070 set_flag(IS_SPARC_TARGET
);
3073 * Check if cache directories and archives are present
3076 ret
= check_flags_and_files(root
);
3081 * In certain deployment scenarios, filestat may not
3082 * exist. Do not stop the boot process, but trigger an update
3083 * of the archives (which will recreate filestat.ramdisk).
3085 if (bam_smf_check
) {
3086 (void) snprintf(path
, sizeof (path
), "%s%s", root
, FILE_STAT
);
3087 if (stat(path
, &sb
) != 0) {
3088 (void) creat(NEED_UPDATE_FILE
, 0644);
3096 * Check if the archive contains files that are no longer
3097 * present on the root filesystem.
3102 * read list of files
3104 if (read_list(root
, flistp
) != BAM_SUCCESS
) {
3109 assert(flistp
->head
&& flistp
->tail
);
3112 * At this point either the update is required
3113 * or the decision is pending. In either case
3114 * we need to create new stat nvlist
3118 * This walk does 2 things:
3119 * - gets new stat data for every file
3120 * - (optional) compare old and new stat data
3122 ret
= walk_list(root
, &flist
);
3124 /* done with the file list */
3125 filelist_free(flistp
);
3127 /* something went wrong */
3129 if (ret
== BAM_ERROR
) {
3130 bam_error(CACHE_FAIL
);
3134 if (walk_arg
.new_nvlp
== NULL
) {
3135 if (walk_arg
.sparcfile
!= NULL
)
3136 (void) fclose(walk_arg
.sparcfile
);
3137 bam_error(NO_NEW_STAT
);
3140 /* If nothing was updated, discard newstat. */
3142 if (!is_dir_flag_on(FILE32
, NEED_UPDATE
) &&
3143 !is_dir_flag_on(FILE64
, NEED_UPDATE
)) {
3148 if (walk_arg
.sparcfile
!= NULL
)
3149 (void) fclose(walk_arg
.sparcfile
);
3157 char cmd
[PATH_MAX
+ 30];
3159 (void) snprintf(cmd
, sizeof (cmd
), "%s -f \"%s\" 2>/dev/null",
3162 return (exec_cmd(cmd
, NULL
));
3166 do_archive_copy(char *source
, char *dest
)
3171 /* the equivalent of mv archive-new-$pid boot_archive */
3172 if (rename(source
, dest
) != 0) {
3173 (void) unlink(source
);
3177 if (flushfs(bam_root
) != 0)
3180 return (BAM_SUCCESS
);
3184 check_cmdline(filelist_t flist
)
3188 for (lp
= flist
.head
; lp
; lp
= lp
->next
) {
3189 if (strstr(lp
->line
, "Error:") != NULL
||
3190 strstr(lp
->line
, "Inode number overflow") != NULL
) {
3191 (void) fprintf(stderr
, "%s\n", lp
->line
);
3196 return (BAM_SUCCESS
);
3200 dump_errormsg(filelist_t flist
)
3204 for (lp
= flist
.head
; lp
; lp
= lp
->next
)
3205 (void) fprintf(stderr
, "%s\n", lp
->line
);
3209 check_archive(char *dest
)
3213 if (stat(dest
, &sb
) != 0 || !S_ISREG(sb
.st_mode
) ||
3214 sb
.st_size
< 10000) {
3215 bam_error(ARCHIVE_BAD
, dest
);
3216 (void) unlink(dest
);
3220 return (BAM_SUCCESS
);
3227 libzfs_handle_t
*hdl
;
3228 be_node_list_t
*be_nodes
= NULL
;
3229 be_node_list_t
*cur_be
;
3230 boolean_t be_exist
= B_FALSE
;
3231 char ds_path
[ZFS_MAXNAMELEN
];
3236 * Get dataset for mountpoint
3238 if ((hdl
= libzfs_init()) == NULL
)
3241 if ((zhp
= zfs_path_to_zhandle(hdl
, root
,
3242 ZFS_TYPE_FILESYSTEM
)) == NULL
) {
3247 (void) strlcpy(ds_path
, zfs_get_name(zhp
), sizeof (ds_path
));
3250 * Check if the current dataset is BE
3252 if (be_list(NULL
, &be_nodes
) == BE_SUCCESS
) {
3253 for (cur_be
= be_nodes
; cur_be
!= NULL
;
3254 cur_be
= cur_be
->be_next_node
) {
3257 * Because we guarantee that cur_be->be_root_ds
3258 * is null-terminated by internal data structure,
3259 * we can safely use strcmp()
3261 if (strcmp(ds_path
, cur_be
->be_root_ds
) == 0) {
3266 be_free_list(be_nodes
);
3275 * Returns 1 if mkiso is in the expected PATH, 0 otherwise
3280 if (access(MKISOFS_PATH
, X_OK
) == 0)
3285 #define MKISO_PARAMS " -quiet -graft-points -dlrDJN -relaxed-filenames "
3288 create_sparc_archive(char *archive
, char *tempname
, char *bootblk
, char *list
)
3291 char cmdline
[3 * PATH_MAX
+ 64];
3292 filelist_t flist
= {0};
3293 const char *func
= "create_sparc_archive()";
3295 if (access(bootblk
, R_OK
) == 1) {
3296 bam_error(BOOTBLK_FAIL
, bootblk
);
3301 * Prepare mkisofs command line and execute it
3303 (void) snprintf(cmdline
, sizeof (cmdline
), "%s %s -G %s -o \"%s\" "
3304 "-path-list \"%s\" 2>&1", MKISOFS_PATH
, MKISO_PARAMS
, bootblk
,
3307 BAM_DPRINTF((D_CMDLINE
, func
, cmdline
));
3309 ret
= exec_cmd(cmdline
, &flist
);
3310 if (ret
!= 0 || check_cmdline(flist
) == BAM_ERROR
) {
3311 dump_errormsg(flist
);
3315 filelist_free(&flist
);
3318 * Prepare dd command line to copy the bootblk on the new archive and
3321 (void) snprintf(cmdline
, sizeof (cmdline
), "%s if=\"%s\" of=\"%s\""
3322 " bs=1b oseek=1 count=15 conv=notrunc conv=sync 2>&1", DD_PATH_USR
,
3325 BAM_DPRINTF((D_CMDLINE
, func
, cmdline
));
3327 ret
= exec_cmd(cmdline
, &flist
);
3328 if (ret
!= 0 || check_cmdline(flist
) == BAM_ERROR
)
3331 filelist_free(&flist
);
3333 /* Did we get a valid archive ? */
3334 if (check_archive(tempname
) == BAM_ERROR
)
3337 return (do_archive_copy(tempname
, archive
));
3340 filelist_free(&flist
);
3341 bam_error(ARCHIVE_FAIL
, cmdline
);
3342 (void) unlink(tempname
);
3347 from_733(unsigned char *s
)
3350 unsigned int ret
= 0;
3352 for (i
= 0; i
< 4; i
++)
3353 ret
|= s
[i
] << (8 * i
);
3359 to_733(unsigned char *s
, unsigned int val
)
3363 for (i
= 0; i
< 4; i
++)
3364 s
[i
] = s
[7-i
] = (val
>> (8 * i
)) & 0xFF;
3368 * Extends the current boot archive without recreating it from scratch
3371 extend_iso_archive(char *archive
, char *tempname
, char *update_dir
)
3373 int fd
= -1, newfd
= -1, ret
, i
;
3374 int next_session
= 0, new_size
= 0;
3375 char cmdline
[3 * PATH_MAX
+ 64];
3376 const char *func
= "extend_iso_archive()";
3377 filelist_t flist
= {0};
3378 struct iso_pdesc saved_desc
[MAX_IVDs
];
3380 fd
= open(archive
, O_RDWR
);
3383 bam_error(OPEN_FAIL
, archive
, strerror(errno
));
3388 * A partial read is likely due to a corrupted file
3390 ret
= pread64(fd
, saved_desc
, sizeof (saved_desc
),
3391 VOLDESC_OFF
* CD_BLOCK
);
3392 if (ret
!= sizeof (saved_desc
)) {
3394 bam_error(READ_FAIL
, archive
, strerror(errno
));
3398 if (memcmp(saved_desc
[0].type
, "\1CD001", 6)) {
3400 bam_error(SIGN_FAIL
, archive
);
3405 * Read primary descriptor and locate next_session offset (it should
3406 * point to the end of the archive)
3408 next_session
= P2ROUNDUP(from_733(saved_desc
[0].volume_space_size
), 16);
3410 (void) snprintf(cmdline
, sizeof (cmdline
), "%s -C 16,%d -M %s %s -o \""
3411 "%s\" \"%s\" 2>&1", MKISOFS_PATH
, next_session
, archive
,
3412 MKISO_PARAMS
, tempname
, update_dir
);
3414 BAM_DPRINTF((D_CMDLINE
, func
, cmdline
));
3416 ret
= exec_cmd(cmdline
, &flist
);
3417 if (ret
!= 0 || check_cmdline(flist
) == BAM_ERROR
) {
3419 bam_error(MULTI_FAIL
, cmdline
);
3420 dump_errormsg(flist
);
3424 filelist_free(&flist
);
3426 newfd
= open(tempname
, O_RDONLY
);
3429 bam_error(OPEN_FAIL
, archive
, strerror(errno
));
3433 ret
= pread64(newfd
, saved_desc
, sizeof (saved_desc
),
3434 VOLDESC_OFF
* CD_BLOCK
);
3435 if (ret
!= sizeof (saved_desc
)) {
3437 bam_error(READ_FAIL
, archive
, strerror(errno
));
3441 if (memcmp(saved_desc
[0].type
, "\1CD001", 6)) {
3443 bam_error(SIGN_FAIL
, archive
);
3447 new_size
= from_733(saved_desc
[0].volume_space_size
) + next_session
;
3448 to_733(saved_desc
[0].volume_space_size
, new_size
);
3450 for (i
= 1; i
< MAX_IVDs
; i
++) {
3451 if (saved_desc
[i
].type
[0] == (unsigned char)255)
3453 if (memcmp(saved_desc
[i
].id
, "CD001", 5))
3457 bam_print("%s: Updating descriptor entry [%d]\n", func
,
3460 to_733(saved_desc
[i
].volume_space_size
, new_size
);
3463 ret
= pwrite64(fd
, saved_desc
, DVD_BLOCK
, VOLDESC_OFF
*CD_BLOCK
);
3464 if (ret
!= DVD_BLOCK
) {
3466 bam_error(WRITE_FAIL
, archive
, strerror(errno
));
3469 (void) close(newfd
);
3479 bam_error(CLOSE_FAIL
, archive
, strerror(errno
));
3484 (void) snprintf(cmdline
, sizeof (cmdline
), "%s if=%s of=%s bs=32k "
3485 "seek=%d conv=sync 2>&1", DD_PATH_USR
, tempname
, archive
,
3488 BAM_DPRINTF((D_CMDLINE
, func
, cmdline
));
3490 ret
= exec_cmd(cmdline
, &flist
);
3491 if (ret
!= 0 || check_cmdline(flist
) == BAM_ERROR
) {
3493 bam_error(MULTI_FAIL
, cmdline
);
3496 filelist_free(&flist
);
3498 (void) unlink(tempname
);
3500 if (flushfs(bam_root
) != 0)
3504 bam_print("boot archive updated successfully\n");
3506 return (BAM_SUCCESS
);
3509 filelist_free(&flist
);
3514 (void) close(newfd
);
3519 create_x86_archive(char *archive
, char *tempname
, char *update_dir
)
3522 char cmdline
[3 * PATH_MAX
+ 64];
3523 filelist_t flist
= {0};
3524 const char *func
= "create_x86_archive()";
3526 (void) snprintf(cmdline
, sizeof (cmdline
), "%s %s -o \"%s\" \"%s\" "
3527 "2>&1", MKISOFS_PATH
, MKISO_PARAMS
, tempname
, update_dir
);
3529 BAM_DPRINTF((D_CMDLINE
, func
, cmdline
));
3531 ret
= exec_cmd(cmdline
, &flist
);
3532 if (ret
!= 0 || check_cmdline(flist
) == BAM_ERROR
) {
3533 bam_error(ARCHIVE_FAIL
, cmdline
);
3534 dump_errormsg(flist
);
3535 filelist_free(&flist
);
3536 (void) unlink(tempname
);
3540 filelist_free(&flist
);
3542 if (check_archive(tempname
) == BAM_ERROR
)
3545 return (do_archive_copy(tempname
, archive
));
3549 mkisofs_archive(char *root
, int what
)
3552 char temp
[PATH_MAX
];
3553 char bootblk
[PATH_MAX
];
3554 char boot_archive
[PATH_MAX
];
3556 if (what
== FILE64
&& !is_flag_on(IS_SPARC_TARGET
))
3557 ret
= snprintf(temp
, sizeof (temp
),
3558 "%s%s%s/amd64/archive-new-%d", root
, ARCHIVE_PREFIX
,
3559 get_machine(), getpid());
3561 ret
= snprintf(temp
, sizeof (temp
), "%s%s%s/archive-new-%d",
3562 root
, ARCHIVE_PREFIX
, get_machine(), getpid());
3564 if (ret
>= sizeof (temp
))
3567 if (what
== FILE64
&& !is_flag_on(IS_SPARC_TARGET
))
3568 ret
= snprintf(boot_archive
, sizeof (boot_archive
),
3569 "%s%s%s/amd64%s", root
, ARCHIVE_PREFIX
, get_machine(),
3572 ret
= snprintf(boot_archive
, sizeof (boot_archive
),
3573 "%s%s%s%s", root
, ARCHIVE_PREFIX
, get_machine(),
3576 if (ret
>= sizeof (boot_archive
))
3579 bam_print("updating %s\n", boot_archive
);
3581 if (is_flag_on(IS_SPARC_TARGET
)) {
3582 ret
= snprintf(bootblk
, sizeof (bootblk
),
3583 "%s/platform/%s/lib/fs/hsfs/bootblk", root
, get_machine());
3584 if (ret
>= sizeof (bootblk
))
3587 ret
= create_sparc_archive(boot_archive
, temp
, bootblk
,
3588 get_cachedir(what
));
3590 if (!is_dir_flag_on(what
, NO_MULTI
)) {
3592 bam_print("Attempting to extend x86 archive: "
3593 "%s\n", boot_archive
);
3595 ret
= extend_iso_archive(boot_archive
, temp
,
3596 get_updatedir(what
));
3597 if (ret
== BAM_SUCCESS
) {
3599 bam_print("Successfully extended %s\n",
3602 (void) rmdir_r(get_updatedir(what
));
3603 return (BAM_SUCCESS
);
3607 * The boot archive will be recreated from scratch. We get here
3608 * if at least one of these conditions is true:
3609 * - bootadm was called without the -e switch
3610 * - the archive (or the archive cache) doesn't exist
3611 * - archive size is bigger than BA_SIZE_MAX
3612 * - more than COUNT_MAX files need to be updated
3613 * - an error occourred either populating the /updates directory
3614 * or extend_iso_archive() failed
3617 bam_print("Unable to extend %s... rebuilding archive\n",
3620 if (get_updatedir(what
)[0] != '\0')
3621 (void) rmdir_r(get_updatedir(what
));
3624 ret
= create_x86_archive(boot_archive
, temp
,
3625 get_cachedir(what
));
3628 if (ret
== BAM_SUCCESS
&& bam_verbose
)
3629 bam_print("Successfully created %s\n", boot_archive
);
3634 bam_error(PATH_TOO_LONG
, root
);
3639 create_ramdisk(char *root
)
3641 char *cmdline
, path
[PATH_MAX
];
3644 int ret
, what
, status
= BAM_SUCCESS
;
3646 /* If there is mkisofs, use it to create the required archives */
3648 for (what
= FILE32
; what
< CACHEDIR_NUM
; what
++) {
3649 if (has_cachedir(what
) && is_dir_flag_on(what
,
3651 ret
= mkisofs_archive(root
, what
);
3660 * Else setup command args for create_ramdisk.ksh for the UFS archives
3663 bam_print("mkisofs not found, creating UFS archive\n");
3665 (void) snprintf(path
, sizeof (path
), "%s/%s", root
, CREATE_RAMDISK
);
3666 if (stat(path
, &sb
) != 0) {
3667 bam_error(ARCH_EXEC_MISS
, path
, strerror(errno
));
3671 if (is_safe_exec(path
) == BAM_ERROR
)
3674 len
= strlen(path
) + strlen(root
) + 10; /* room for space + -R */
3675 if (bam_alt_platform
)
3676 len
+= strlen(bam_platform
) + strlen("-p ");
3677 cmdline
= s_calloc(1, len
);
3679 if (bam_alt_platform
) {
3680 assert(strlen(root
) > 1);
3681 (void) snprintf(cmdline
, len
, "%s -p %s -R %s",
3682 path
, bam_platform
, root
);
3683 /* chop off / at the end */
3684 cmdline
[strlen(cmdline
) - 1] = '\0';
3685 } else if (strlen(root
) > 1) {
3686 (void) snprintf(cmdline
, len
, "%s -R %s", path
, root
);
3687 /* chop off / at the end */
3688 cmdline
[strlen(cmdline
) - 1] = '\0';
3690 (void) snprintf(cmdline
, len
, "%s", path
);
3692 if (exec_cmd(cmdline
, NULL
) != 0) {
3693 bam_error(ARCHIVE_FAIL
, cmdline
);
3699 * The existence of the expected archives used to be
3700 * verified here. This check is done in create_ramdisk as
3701 * it needs to be in sync with the altroot operated upon.
3703 return (BAM_SUCCESS
);
3707 * Checks if target filesystem is on a ramdisk
3710 * When in doubt assume it is not a ramdisk.
3713 is_ramdisk(char *root
)
3715 struct extmnttab mnt
;
3718 char mntpt
[PATH_MAX
];
3722 * There are 3 situations where creating archive is
3724 * - create boot_archive on a lofi-mounted boot_archive
3725 * - create it on a ramdisk which is the root filesystem
3726 * - create it on a ramdisk mounted somewhere else
3727 * The first is not easy to detect and checking for it is not
3729 * The other two conditions are handled here
3731 fp
= fopen(MNTTAB
, "r");
3733 bam_error(OPEN_FAIL
, MNTTAB
, strerror(errno
));
3740 * Remove any trailing / from the mount point
3742 (void) strlcpy(mntpt
, root
, sizeof (mntpt
));
3743 if (strcmp(root
, "/") != 0) {
3744 cp
= mntpt
+ strlen(mntpt
) - 1;
3749 while (getextmntent(fp
, &mnt
, sizeof (mnt
)) == 0) {
3750 if (strcmp(mnt
.mnt_mountp
, mntpt
) == 0) {
3758 bam_error(NOT_IN_MNTTAB
, mntpt
);
3763 if (strncmp(mnt
.mnt_special
, RAMDISK_SPECIAL
,
3764 strlen(RAMDISK_SPECIAL
)) == 0) {
3766 bam_error(IS_RAMDISK
, bam_root
);
3777 is_boot_archive(char *root
)
3779 char path
[PATH_MAX
];
3782 const char *fcn
= "is_boot_archive()";
3785 * We can't create an archive without the create_ramdisk script
3787 (void) snprintf(path
, sizeof (path
), "%s/%s", root
, CREATE_RAMDISK
);
3788 error
= stat(path
, &sb
);
3789 INJECT_ERROR1("NOT_ARCHIVE_BASED", error
= -1);
3792 bam_print(FILE_MISS
, path
);
3793 BAM_DPRINTF((D_NOT_ARCHIVE_BOOT
, fcn
, root
));
3797 BAM_DPRINTF((D_IS_ARCHIVE_BOOT
, fcn
, root
));
3802 * Need to call this for anything that operates on the GRUB menu
3803 * In the x86 live upgrade case the directory /boot/grub may be present
3804 * even on pre-newboot BEs. The authoritative way to check for a GRUB target
3805 * is to check for the presence of the stage2 binary which is present
3806 * only on GRUB targets (even on x86 boot partitions). Checking for the
3807 * presence of the multiboot binary is not correct as it is not present
3808 * on x86 boot partitions.
3811 is_grub(const char *root
)
3813 char path
[PATH_MAX
];
3815 const char *fcn
= "is_grub()";
3817 (void) snprintf(path
, sizeof (path
), "%s%s", root
, GRUB_STAGE2
);
3818 if (stat(path
, &sb
) == -1) {
3819 BAM_DPRINTF((D_NO_GRUB_DIR
, fcn
, path
));
3831 const char *fcn
= "is_zfs()";
3833 ret
= statvfs(root
, &vfs
);
3834 INJECT_ERROR1("STATVFS_ZFS", ret
= 1);
3836 bam_error(STATVFS_FAIL
, root
, strerror(errno
));
3840 if (strncmp(vfs
.f_basetype
, "zfs", strlen("zfs")) == 0) {
3841 BAM_DPRINTF((D_IS_ZFS
, fcn
, root
));
3844 BAM_DPRINTF((D_IS_NOT_ZFS
, fcn
, root
));
3854 const char *fcn
= "is_ufs()";
3856 ret
= statvfs(root
, &vfs
);
3857 INJECT_ERROR1("STATVFS_UFS", ret
= 1);
3859 bam_error(STATVFS_FAIL
, root
, strerror(errno
));
3863 if (strncmp(vfs
.f_basetype
, "ufs", strlen("ufs")) == 0) {
3864 BAM_DPRINTF((D_IS_UFS
, fcn
, root
));
3867 BAM_DPRINTF((D_IS_NOT_UFS
, fcn
, root
));
3877 const char *fcn
= "is_pcfs()";
3879 ret
= statvfs(root
, &vfs
);
3880 INJECT_ERROR1("STATVFS_PCFS", ret
= 1);
3882 bam_error(STATVFS_FAIL
, root
, strerror(errno
));
3886 if (strncmp(vfs
.f_basetype
, "pcfs", strlen("pcfs")) == 0) {
3887 BAM_DPRINTF((D_IS_PCFS
, fcn
, root
));
3890 BAM_DPRINTF((D_IS_NOT_PCFS
, fcn
, root
));
3896 is_readonly(char *root
)
3900 char testfile
[PATH_MAX
];
3901 const char *fcn
= "is_readonly()";
3904 * Using statvfs() to check for a read-only filesystem is not
3905 * reliable. The only way to reliably test is to attempt to
3908 (void) snprintf(testfile
, sizeof (testfile
), "%s/%s.%d",
3909 root
, BOOTADM_RDONLY_TEST
, getpid());
3911 (void) unlink(testfile
);
3914 fd
= open(testfile
, O_RDWR
|O_CREAT
|O_EXCL
, 0644);
3916 INJECT_ERROR2("RDONLY_TEST_ERROR", fd
= -1, error
= EACCES
);
3917 if (fd
== -1 && error
== EROFS
) {
3918 BAM_DPRINTF((D_RDONLY_FS
, fcn
, root
));
3920 } else if (fd
== -1) {
3921 bam_error(RDONLY_TEST_ERROR
, root
, strerror(error
));
3925 (void) unlink(testfile
);
3927 BAM_DPRINTF((D_RDWR_FS
, fcn
, root
));
3932 update_archive(char *root
, char *opt
)
3937 assert(opt
== NULL
);
3943 * Never update non-BE root in update_all
3945 if (!is_be(root
) && bam_update_all
)
3946 return (BAM_SUCCESS
);
3948 * root must belong to a boot archive based OS,
3950 if (!is_boot_archive(root
)) {
3952 * Emit message only if not in context of update_all.
3953 * If in update_all, emit only if verbose flag is set.
3955 if (!bam_update_all
|| bam_verbose
)
3956 bam_print(NOT_ARCHIVE_BOOT
, root
);
3961 * If smf check is requested when / is writable (can happen
3962 * on first reboot following an upgrade because service
3963 * dependency is messed up), skip the check.
3965 if (bam_smf_check
&& !bam_root_readonly
&& !is_zfs(root
))
3966 return (BAM_SUCCESS
);
3969 * Don't generate archive on ramdisk.
3971 if (is_ramdisk(root
))
3972 return (BAM_SUCCESS
);
3975 * root must be writable. This check applies to alternate
3976 * root (-R option); bam_root_readonly applies to '/' only.
3977 * The behaviour translates into being the one of a 'check'.
3979 if (!bam_smf_check
&& !bam_check
&& is_readonly(root
)) {
3980 set_flag(RDONLY_FSCHK
);
3985 * Now check if an update is really needed.
3987 ret
= update_required(root
);
3990 * The check command (-n) is *not* a dry run.
3991 * It only checks if the archive is in sync.
3992 * A readonly filesystem has to be considered an error only if an update
3995 if (bam_nowrite()) {
3996 if (is_flag_on(RDONLY_FSCHK
)) {
3997 bam_check
= bam_saved_check
;
3999 bam_error(RDONLY_FS
, root
);
4001 return ((ret
!= 0) ? BAM_ERROR
: BAM_SUCCESS
);
4004 bam_exit((ret
!= 0) ? 1 : 0);
4008 /* create the ramdisk */
4009 ret
= create_ramdisk(root
);
4013 * if the archive is updated, save the new stat data and update the
4016 if (ret
== 0 && walk_arg
.new_nvlp
!= NULL
) {
4018 update_timestamp(root
);
4029 char *special
= get_special("/");
4032 if (special
== NULL
)
4035 if (*special
== '/') {
4040 if ((p
= strchr(special
, '/')) != NULL
)
4047 synchronize_BE_menu(void)
4050 char cmdline
[PATH_MAX
];
4051 char cksum_line
[PATH_MAX
];
4052 filelist_t flist
= {0};
4053 char *old_cksum_str
;
4056 char *curr_cksum_str
;
4057 char *curr_size_str
;
4065 const char *fcn
= "synchronize_BE_menu()";
4067 BAM_DPRINTF((D_FUNC_ENTRY0
, fcn
));
4069 /* Check if findroot enabled LU BE */
4070 if (stat(FINDROOT_INSTALLGRUB
, &sb
) != 0) {
4071 BAM_DPRINTF((D_NOT_LU_BE
, fcn
));
4072 return (BAM_SUCCESS
);
4075 if (stat(LU_MENU_CKSUM
, &sb
) != 0) {
4076 BAM_DPRINTF((D_NO_CKSUM_FILE
, fcn
, LU_MENU_CKSUM
));
4080 cfp
= fopen(LU_MENU_CKSUM
, "r");
4081 INJECT_ERROR1("CKSUM_FILE_MISSING", cfp
= NULL
);
4083 bam_error(CANNOT_READ_LU_CKSUM
, LU_MENU_CKSUM
);
4086 BAM_DPRINTF((D_CKSUM_FILE_OPENED
, fcn
, LU_MENU_CKSUM
));
4089 while (s_fgets(cksum_line
, sizeof (cksum_line
), cfp
) != NULL
) {
4090 INJECT_ERROR1("MULTIPLE_CKSUM", found
= 1);
4092 bam_error(MULTIPLE_LU_CKSUM
, LU_MENU_CKSUM
);
4098 BAM_DPRINTF((D_CKSUM_FILE_READ
, fcn
, LU_MENU_CKSUM
));
4101 old_cksum_str
= strtok(cksum_line
, " \t");
4102 old_size_str
= strtok(NULL
, " \t");
4103 old_file
= strtok(NULL
, " \t");
4105 INJECT_ERROR1("OLD_CKSUM_NULL", old_cksum_str
= NULL
);
4106 INJECT_ERROR1("OLD_SIZE_NULL", old_size_str
= NULL
);
4107 INJECT_ERROR1("OLD_FILE_NULL", old_file
= NULL
);
4108 if (old_cksum_str
== NULL
|| old_size_str
== NULL
|| old_file
== NULL
) {
4109 bam_error(CANNOT_PARSE_LU_CKSUM
, LU_MENU_CKSUM
);
4112 BAM_DPRINTF((D_CKSUM_FILE_PARSED
, fcn
, LU_MENU_CKSUM
));
4114 /* Get checksum of current menu */
4115 pool
= find_root_pool();
4117 mntpt
= mount_top_dataset(pool
, &mnted
);
4118 if (mntpt
== NULL
) {
4119 bam_error(FAIL_MNT_TOP_DATASET
, pool
);
4123 (void) snprintf(cmdline
, sizeof (cmdline
), "%s %s%s",
4124 CKSUM
, mntpt
, GRUB_MENU
);
4126 (void) snprintf(cmdline
, sizeof (cmdline
), "%s %s",
4129 ret
= exec_cmd(cmdline
, &flist
);
4131 (void) umount_top_dataset(pool
, mnted
, mntpt
);
4134 INJECT_ERROR1("GET_CURR_CKSUM", ret
= 1);
4136 bam_error(MENU_CKSUM_FAIL
);
4139 BAM_DPRINTF((D_CKSUM_GEN_SUCCESS
, fcn
));
4141 INJECT_ERROR1("GET_CURR_CKSUM_OUTPUT", flist
.head
= NULL
);
4142 if ((flist
.head
== NULL
) || (flist
.head
!= flist
.tail
)) {
4143 bam_error(BAD_CKSUM
);
4144 filelist_free(&flist
);
4147 BAM_DPRINTF((D_CKSUM_GEN_OUTPUT_VALID
, fcn
));
4149 curr_cksum_str
= strtok(flist
.head
->line
, " \t");
4150 curr_size_str
= strtok(NULL
, " \t");
4151 curr_file
= strtok(NULL
, " \t");
4153 INJECT_ERROR1("CURR_CKSUM_NULL", curr_cksum_str
= NULL
);
4154 INJECT_ERROR1("CURR_SIZE_NULL", curr_size_str
= NULL
);
4155 INJECT_ERROR1("CURR_FILE_NULL", curr_file
= NULL
);
4156 if (curr_cksum_str
== NULL
|| curr_size_str
== NULL
||
4157 curr_file
== NULL
) {
4158 bam_error(BAD_CKSUM_PARSE
);
4159 filelist_free(&flist
);
4162 BAM_DPRINTF((D_CKSUM_GEN_PARSED
, fcn
));
4164 if (strcmp(old_cksum_str
, curr_cksum_str
) == 0 &&
4165 strcmp(old_size_str
, curr_size_str
) == 0 &&
4166 strcmp(old_file
, curr_file
) == 0) {
4167 filelist_free(&flist
);
4168 BAM_DPRINTF((D_CKSUM_NO_CHANGE
, fcn
));
4169 return (BAM_SUCCESS
);
4172 filelist_free(&flist
);
4174 /* cksum doesn't match - the menu has changed */
4175 BAM_DPRINTF((D_CKSUM_HAS_CHANGED
, fcn
));
4178 bam_print(PROP_GRUB_MENU
);
4180 (void) snprintf(cmdline
, sizeof (cmdline
),
4181 "/bin/sh -c '. %s > /dev/null; %s %s yes > /dev/null'",
4182 LULIB
, LULIB_PROPAGATE_FILE
, GRUB_MENU
);
4183 ret
= exec_cmd(cmdline
, NULL
);
4184 INJECT_ERROR1("PROPAGATE_MENU", ret
= 1);
4186 bam_error(MENU_PROP_FAIL
);
4189 BAM_DPRINTF((D_PROPAGATED_MENU
, fcn
));
4191 (void) snprintf(cmdline
, sizeof (cmdline
), "/bin/cp %s %s > /dev/null",
4192 GRUB_MENU
, GRUB_BACKUP_MENU
);
4193 ret
= exec_cmd(cmdline
, NULL
);
4194 INJECT_ERROR1("CREATE_BACKUP", ret
= 1);
4196 bam_error(MENU_BACKUP_FAIL
, GRUB_BACKUP_MENU
);
4199 BAM_DPRINTF((D_CREATED_BACKUP
, fcn
, GRUB_BACKUP_MENU
));
4201 (void) snprintf(cmdline
, sizeof (cmdline
),
4202 "/bin/sh -c '. %s > /dev/null; %s %s no > /dev/null'",
4203 LULIB
, LULIB_PROPAGATE_FILE
, GRUB_BACKUP_MENU
);
4204 ret
= exec_cmd(cmdline
, NULL
);
4205 INJECT_ERROR1("PROPAGATE_BACKUP", ret
= 1);
4207 bam_error(BACKUP_PROP_FAIL
, GRUB_BACKUP_MENU
);
4210 BAM_DPRINTF((D_PROPAGATED_BACKUP
, fcn
, GRUB_BACKUP_MENU
));
4212 (void) snprintf(cmdline
, sizeof (cmdline
), "%s %s > %s",
4213 CKSUM
, GRUB_MENU
, LU_MENU_CKSUM
);
4214 ret
= exec_cmd(cmdline
, NULL
);
4215 INJECT_ERROR1("CREATE_CKSUM_FILE", ret
= 1);
4217 bam_error(MENU_CKSUM_WRITE_FAIL
, LU_MENU_CKSUM
);
4220 BAM_DPRINTF((D_CREATED_CKSUM_FILE
, fcn
, LU_MENU_CKSUM
));
4222 (void) snprintf(cmdline
, sizeof (cmdline
),
4223 "/bin/sh -c '. %s > /dev/null; %s %s no > /dev/null'",
4224 LULIB
, LULIB_PROPAGATE_FILE
, LU_MENU_CKSUM
);
4225 ret
= exec_cmd(cmdline
, NULL
);
4226 INJECT_ERROR1("PROPAGATE_MENU_CKSUM_FILE", ret
= 1);
4228 bam_error(MENU_CKSUM_PROP_FAIL
, LU_MENU_CKSUM
);
4231 BAM_DPRINTF((D_PROPAGATED_CKSUM_FILE
, fcn
, LU_MENU_CKSUM
));
4233 return (BAM_SUCCESS
);
4237 update_all(char *root
, char *opt
)
4239 struct extmnttab mnt
;
4242 char multibt
[PATH_MAX
];
4243 char creatram
[PATH_MAX
];
4244 error_t ret
= BAM_SUCCESS
;
4247 assert(opt
== NULL
);
4249 if (bam_rootlen
!= 1 || *root
!= '/') {
4250 elide_trailing_slash(root
, multibt
, sizeof (multibt
));
4251 bam_error(ALT_ROOT_INVALID
, multibt
);
4256 * First update archive for current root
4258 if (update_archive(root
, opt
) != BAM_SUCCESS
)
4261 if (ret
== BAM_ERROR
)
4265 * Now walk the mount table, performing archive update
4266 * for all mounted Newboot root filesystems
4268 fp
= fopen(MNTTAB
, "r");
4270 bam_error(OPEN_FAIL
, MNTTAB
, strerror(errno
));
4277 while (getextmntent(fp
, &mnt
, sizeof (mnt
)) == 0) {
4278 if (mnt
.mnt_special
== NULL
)
4280 if ((strcmp(mnt
.mnt_fstype
, MNTTYPE_ZFS
) != 0) &&
4281 (strncmp(mnt
.mnt_special
, "/dev/", strlen("/dev/")) != 0))
4283 if (strcmp(mnt
.mnt_mountp
, "/") == 0)
4286 (void) snprintf(creatram
, sizeof (creatram
), "%s/%s",
4287 mnt
.mnt_mountp
, CREATE_RAMDISK
);
4289 if (stat(creatram
, &sb
) == -1)
4293 * We put a trailing slash to be consistent with root = "/"
4294 * case, such that we don't have to print // in some cases.
4296 (void) snprintf(rootbuf
, sizeof (rootbuf
), "%s/",
4298 bam_rootlen
= strlen(rootbuf
);
4301 * It's possible that other mounts may be an alternate boot
4302 * architecture, so check it again.
4304 if ((get_boot_cap(rootbuf
) != BAM_SUCCESS
) ||
4305 (update_archive(rootbuf
, opt
) != BAM_SUCCESS
))
4313 * We no longer use biosdev for Live Upgrade. Hence
4314 * there is no need to defer (to shutdown time) any fdisk
4317 if (stat(GRUB_fdisk
, &sb
) == 0 || stat(GRUB_fdisk_target
, &sb
) == 0) {
4318 bam_error(FDISK_FILES_FOUND
, GRUB_fdisk
, GRUB_fdisk_target
);
4322 * If user has updated menu in current BE, propagate the
4323 * updates to all BEs.
4325 if (sync_menu
&& synchronize_BE_menu() != BAM_SUCCESS
)
4332 append_line(menu_t
*mp
, line_t
*lp
)
4334 if (mp
->start
== NULL
) {
4344 unlink_line(menu_t
*mp
, line_t
*lp
)
4346 /* unlink from list */
4348 lp
->prev
->next
= lp
->next
;
4350 mp
->start
= lp
->next
;
4352 lp
->next
->prev
= lp
->prev
;
4358 boot_entry_new(menu_t
*mp
, line_t
*start
, line_t
*end
)
4360 entry_t
*ent
, *prev
;
4361 const char *fcn
= "boot_entry_new()";
4367 ent
= s_calloc(1, sizeof (entry_t
));
4368 BAM_DPRINTF((D_ENTRY_NEW
, fcn
));
4372 if (mp
->entries
== NULL
) {
4374 BAM_DPRINTF((D_ENTRY_NEW_FIRST
, fcn
));
4383 BAM_DPRINTF((D_ENTRY_NEW_LINKED
, fcn
));
4388 boot_entry_addline(entry_t
*ent
, line_t
*lp
)
4395 * Check whether cmd matches the one indexed by which, and whether arg matches
4396 * str. which must be either KERNEL_CMD or MODULE_CMD, and a match to the
4397 * respective *_DOLLAR_CMD is also acceptable. The arg is searched using
4398 * strstr(), so it can be a partial match.
4401 check_cmd(const char *cmd
, const int which
, const char *arg
, const char *str
)
4404 const char *fcn
= "check_cmd()";
4406 BAM_DPRINTF((D_FUNC_ENTRY2
, fcn
, arg
, str
));
4409 if ((strcmp(cmd
, menu_cmds
[which
]) != 0) &&
4410 (strcmp(cmd
, menu_cmds
[which
+ 1]) != 0)) {
4411 BAM_DPRINTF((D_CHECK_CMD_CMD_NOMATCH
,
4412 fcn
, cmd
, menu_cmds
[which
]));
4415 ret
= (strstr(arg
, str
) != NULL
);
4420 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
4422 BAM_DPRINTF((D_RETURN_FAILURE
, fcn
));
4429 kernel_parser(entry_t
*entry
, char *cmd
, char *arg
, int linenum
)
4431 const char *fcn
= "kernel_parser()";
4437 if (strcmp(cmd
, menu_cmds
[KERNEL_CMD
]) != 0 &&
4438 strcmp(cmd
, menu_cmds
[KERNEL_DOLLAR_CMD
]) != 0) {
4439 BAM_DPRINTF((D_NOT_KERNEL_CMD
, fcn
, cmd
));
4443 if (strncmp(arg
, DIRECT_BOOT_32
, sizeof (DIRECT_BOOT_32
) - 1) == 0) {
4444 BAM_DPRINTF((D_SET_DBOOT_32
, fcn
, arg
));
4445 entry
->flags
|= BAM_ENTRY_DBOOT
| BAM_ENTRY_32BIT
;
4446 } else if (strncmp(arg
, DIRECT_BOOT_KERNEL
,
4447 sizeof (DIRECT_BOOT_KERNEL
) - 1) == 0) {
4448 BAM_DPRINTF((D_SET_DBOOT
, fcn
, arg
));
4449 entry
->flags
|= BAM_ENTRY_DBOOT
;
4450 } else if (strncmp(arg
, DIRECT_BOOT_64
,
4451 sizeof (DIRECT_BOOT_64
) - 1) == 0) {
4452 BAM_DPRINTF((D_SET_DBOOT_64
, fcn
, arg
));
4453 entry
->flags
|= BAM_ENTRY_DBOOT
| BAM_ENTRY_64BIT
;
4454 } else if (strncmp(arg
, DIRECT_BOOT_FAILSAFE_KERNEL
,
4455 sizeof (DIRECT_BOOT_FAILSAFE_KERNEL
) - 1) == 0) {
4456 BAM_DPRINTF((D_SET_DBOOT_FAILSAFE
, fcn
, arg
));
4457 entry
->flags
|= BAM_ENTRY_DBOOT
| BAM_ENTRY_FAILSAFE
;
4458 } else if (strncmp(arg
, DIRECT_BOOT_FAILSAFE_32
,
4459 sizeof (DIRECT_BOOT_FAILSAFE_32
) - 1) == 0) {
4460 BAM_DPRINTF((D_SET_DBOOT_FAILSAFE_32
, fcn
, arg
));
4461 entry
->flags
|= BAM_ENTRY_DBOOT
| BAM_ENTRY_FAILSAFE
4463 } else if (strncmp(arg
, DIRECT_BOOT_FAILSAFE_64
,
4464 sizeof (DIRECT_BOOT_FAILSAFE_64
) - 1) == 0) {
4465 BAM_DPRINTF((D_SET_DBOOT_FAILSAFE_64
, fcn
, arg
));
4466 entry
->flags
|= BAM_ENTRY_DBOOT
| BAM_ENTRY_FAILSAFE
4468 } else if (strncmp(arg
, MULTI_BOOT
, sizeof (MULTI_BOOT
) - 1) == 0) {
4469 BAM_DPRINTF((D_SET_MULTIBOOT
, fcn
, arg
));
4470 entry
->flags
|= BAM_ENTRY_MULTIBOOT
;
4471 } else if (strncmp(arg
, MULTI_BOOT_FAILSAFE
,
4472 sizeof (MULTI_BOOT_FAILSAFE
) - 1) == 0) {
4473 BAM_DPRINTF((D_SET_MULTIBOOT_FAILSAFE
, fcn
, arg
));
4474 entry
->flags
|= BAM_ENTRY_MULTIBOOT
| BAM_ENTRY_FAILSAFE
;
4475 } else if (strstr(arg
, XEN_KERNEL_SUBSTR
)) {
4476 BAM_DPRINTF((D_SET_HV
, fcn
, arg
));
4477 entry
->flags
|= BAM_ENTRY_HV
;
4478 } else if (!(entry
->flags
& (BAM_ENTRY_BOOTADM
|BAM_ENTRY_LU
))) {
4479 BAM_DPRINTF((D_SET_HAND_KERNEL
, fcn
, arg
));
4481 } else if (strncmp(arg
, KERNEL_PREFIX
, strlen(KERNEL_PREFIX
)) == 0 &&
4482 strstr(arg
, UNIX_SPACE
)) {
4483 entry
->flags
|= BAM_ENTRY_DBOOT
| BAM_ENTRY_32BIT
;
4484 } else if (strncmp(arg
, KERNEL_PREFIX
, strlen(KERNEL_PREFIX
)) == 0 &&
4485 strstr(arg
, AMD_UNIX_SPACE
)) {
4486 entry
->flags
|= BAM_ENTRY_DBOOT
| BAM_ENTRY_64BIT
;
4488 BAM_DPRINTF((D_IS_UNKNOWN_KERNEL
, fcn
, arg
));
4489 bam_error(UNKNOWN_KERNEL_LINE
, linenum
);
4493 return (BAM_SUCCESS
);
4497 module_parser(entry_t
*entry
, char *cmd
, char *arg
, int linenum
)
4499 const char *fcn
= "module_parser()";
4505 if (strcmp(cmd
, menu_cmds
[MODULE_CMD
]) != 0 &&
4506 strcmp(cmd
, menu_cmds
[MODULE_DOLLAR_CMD
]) != 0) {
4507 BAM_DPRINTF((D_NOT_MODULE_CMD
, fcn
, cmd
));
4511 if (strcmp(arg
, DIRECT_BOOT_ARCHIVE
) == 0 ||
4512 strcmp(arg
, DIRECT_BOOT_ARCHIVE_32
) == 0 ||
4513 strcmp(arg
, DIRECT_BOOT_ARCHIVE_64
) == 0 ||
4514 strcmp(arg
, MULTIBOOT_ARCHIVE
) == 0 ||
4515 strcmp(arg
, FAILSAFE_ARCHIVE
) == 0 ||
4516 strcmp(arg
, FAILSAFE_ARCHIVE_32
) == 0 ||
4517 strcmp(arg
, FAILSAFE_ARCHIVE_64
) == 0 ||
4518 strcmp(arg
, XEN_KERNEL_MODULE_LINE
) == 0 ||
4519 strcmp(arg
, XEN_KERNEL_MODULE_LINE_ZFS
) == 0) {
4520 BAM_DPRINTF((D_BOOTADM_LU_MODULE
, fcn
, arg
));
4521 return (BAM_SUCCESS
);
4522 } else if (!(entry
->flags
& BAM_ENTRY_BOOTADM
) &&
4523 !(entry
->flags
& BAM_ENTRY_LU
)) {
4524 /* don't emit warning for hand entries */
4525 BAM_DPRINTF((D_IS_HAND_MODULE
, fcn
, arg
));
4528 BAM_DPRINTF((D_IS_UNKNOWN_MODULE
, fcn
, arg
));
4529 bam_error(UNKNOWN_MODULE_LINE
, linenum
);
4535 * A line in menu.lst looks like
4536 * [ ]*<cmd>[ \t=]*<arg>*
4539 line_parser(menu_t
*mp
, char *str
, int *lineNum
, int *entryNum
)
4542 * save state across calls. This is so that
4543 * header gets the right entry# after title has
4546 static line_t
*prev
= NULL
;
4547 static entry_t
*curr_ent
= NULL
;
4548 static int in_liveupgrade
= 0;
4549 static int is_libbe_ent
= 0;
4552 char *cmd
, *sep
, *arg
;
4553 char save
, *cp
, *line
;
4554 menu_flag_t flag
= BAM_INVALID
;
4555 const char *fcn
= "line_parser()";
4562 * First save a copy of the entire line.
4563 * We use this later to set the line field.
4565 line
= s_strdup(str
);
4567 /* Eat up leading whitespace */
4568 while (*str
== ' ' || *str
== '\t')
4571 if (*str
== '#') { /* comment */
4572 cmd
= s_strdup("#");
4574 arg
= s_strdup(str
+ 1);
4576 if (strstr(arg
, BAM_LU_HDR
) != NULL
) {
4578 } else if (strstr(arg
, BAM_LU_FTR
) != NULL
) {
4580 } else if (strstr(arg
, BAM_LIBBE_FTR
) != NULL
) {
4583 } else if (*str
== '\0') { /* blank line */
4584 cmd
= sep
= arg
= NULL
;
4588 * '=' is not a documented separator in grub syntax.
4589 * However various development bits use '=' as a
4590 * separator. In addition, external users also
4591 * use = as a separator. So we will allow that usage.
4594 while (*str
!= ' ' && *str
!= '\t' && *str
!= '=') {
4612 sep
= s_strdup(str
- 1);
4615 while (*str
== ' ' || *str
== '\t')
4620 arg
= s_strdup(str
);
4624 lp
= s_calloc(1, sizeof (line_t
));
4630 lp
->lineNum
= ++(*lineNum
);
4631 if (cmd
&& strcmp(cmd
, menu_cmds
[TITLE_CMD
]) == 0) {
4632 lp
->entryNum
= ++(*entryNum
);
4633 lp
->flags
= BAM_TITLE
;
4634 if (prev
&& prev
->flags
== BAM_COMMENT
&&
4635 prev
->arg
&& strcmp(prev
->arg
, BAM_BOOTADM_HDR
) == 0) {
4636 prev
->entryNum
= lp
->entryNum
;
4637 curr_ent
= boot_entry_new(mp
, prev
, lp
);
4638 curr_ent
->flags
|= BAM_ENTRY_BOOTADM
;
4639 BAM_DPRINTF((D_IS_BOOTADM_ENTRY
, fcn
, arg
));
4641 curr_ent
= boot_entry_new(mp
, lp
, lp
);
4642 if (in_liveupgrade
) {
4643 curr_ent
->flags
|= BAM_ENTRY_LU
;
4644 BAM_DPRINTF((D_IS_LU_ENTRY
, fcn
, arg
));
4647 curr_ent
->entryNum
= *entryNum
;
4648 } else if (flag
!= BAM_INVALID
) {
4650 * For header comments, the entry# is "fixed up"
4651 * by the subsequent title
4653 lp
->entryNum
= *entryNum
;
4656 lp
->entryNum
= *entryNum
;
4658 if (*entryNum
== ENTRY_INIT
) {
4659 lp
->flags
= BAM_GLOBAL
;
4661 lp
->flags
= BAM_ENTRY
;
4664 if (strcmp(cmd
, menu_cmds
[ROOT_CMD
]) == 0) {
4665 BAM_DPRINTF((D_IS_ROOT_CMD
, fcn
, arg
));
4666 curr_ent
->flags
|= BAM_ENTRY_ROOT
;
4667 } else if (strcmp(cmd
, menu_cmds
[FINDROOT_CMD
])
4669 BAM_DPRINTF((D_IS_FINDROOT_CMD
, fcn
,
4671 curr_ent
->flags
|= BAM_ENTRY_FINDROOT
;
4672 } else if (strcmp(cmd
,
4673 menu_cmds
[CHAINLOADER_CMD
]) == 0) {
4674 BAM_DPRINTF((D_IS_CHAINLOADER_CMD
, fcn
,
4677 BAM_ENTRY_CHAINLOADER
;
4678 } else if (kernel_parser(curr_ent
, cmd
, arg
,
4679 lp
->lineNum
) != BAM_SUCCESS
) {
4680 (void) module_parser(curr_ent
, cmd
,
4687 /* record default, old default, and entry line ranges */
4688 if (lp
->flags
== BAM_GLOBAL
&& lp
->cmd
!= NULL
&&
4689 strcmp(lp
->cmd
, menu_cmds
[DEFAULT_CMD
]) == 0) {
4690 mp
->curdefault
= lp
;
4691 } else if (lp
->flags
== BAM_COMMENT
&&
4692 strncmp(lp
->arg
, BAM_OLDDEF
, strlen(BAM_OLDDEF
)) == 0) {
4693 mp
->olddefault
= lp
;
4694 } else if (lp
->flags
== BAM_COMMENT
&&
4695 strncmp(lp
->arg
, BAM_OLD_RC_DEF
, strlen(BAM_OLD_RC_DEF
)) == 0) {
4696 mp
->old_rc_default
= lp
;
4697 } else if (lp
->flags
== BAM_ENTRY
||
4698 (lp
->flags
== BAM_COMMENT
&&
4699 ((strcmp(lp
->arg
, BAM_BOOTADM_FTR
) == 0) || is_libbe_ent
))) {
4701 curr_ent
->flags
|= BAM_ENTRY_LIBBE
;
4705 boot_entry_addline(curr_ent
, lp
);
4707 append_line(mp
, lp
);
4713 update_numbering(menu_t
*mp
)
4717 int old_default_value
;
4718 line_t
*lp
, *prev
, *default_lp
, *default_entry
;
4721 if (mp
->start
== NULL
) {
4725 lineNum
= LINE_INIT
;
4726 entryNum
= ENTRY_INIT
;
4727 old_default_value
= ENTRY_INIT
;
4728 lp
= default_lp
= default_entry
= NULL
;
4731 for (lp
= mp
->start
; lp
; prev
= lp
, lp
= lp
->next
) {
4732 lp
->lineNum
= ++lineNum
;
4735 * Get the value of the default command
4737 if (lp
->entryNum
== ENTRY_INIT
&& lp
->cmd
!= NULL
&&
4738 strcmp(lp
->cmd
, menu_cmds
[DEFAULT_CMD
]) == 0 &&
4740 old_default_value
= atoi(lp
->arg
);
4745 * If not a booting entry, nothing else to fix for this
4748 if (lp
->entryNum
== ENTRY_INIT
)
4752 * Record the position of the default entry.
4753 * The following works because global
4754 * commands like default and timeout should precede
4755 * actual boot entries, so old_default_value
4756 * is already known (or default cmd is missing).
4758 if (default_entry
== NULL
&&
4759 old_default_value
!= ENTRY_INIT
&&
4760 lp
->entryNum
== old_default_value
) {
4765 * Now fixup the entry number
4767 if (lp
->cmd
!= NULL
&&
4768 strcmp(lp
->cmd
, menu_cmds
[TITLE_CMD
]) == 0) {
4769 lp
->entryNum
= ++entryNum
;
4770 /* fixup the bootadm header */
4771 if (prev
&& prev
->flags
== BAM_COMMENT
&&
4773 strcmp(prev
->arg
, BAM_BOOTADM_HDR
) == 0) {
4774 prev
->entryNum
= lp
->entryNum
;
4777 lp
->entryNum
= entryNum
;
4782 * No default command in menu, simply return
4784 if (default_lp
== NULL
) {
4788 free(default_lp
->arg
);
4789 free(default_lp
->line
);
4791 if (default_entry
== NULL
) {
4792 default_lp
->arg
= s_strdup("0");
4794 (void) snprintf(buf
, sizeof (buf
), "%d",
4795 default_entry
->entryNum
);
4796 default_lp
->arg
= s_strdup(buf
);
4800 * The following is required since only the line field gets
4801 * written back to menu.lst
4803 (void) snprintf(buf
, sizeof (buf
), "%s%s%s",
4804 menu_cmds
[DEFAULT_CMD
], menu_cmds
[SEP_CMD
], default_lp
->arg
);
4805 default_lp
->line
= s_strdup(buf
);
4810 menu_read(char *menu_path
)
4813 char buf
[BAM_MAXLINE
], *cp
;
4815 int line
, entry
, len
, n
;
4817 mp
= s_calloc(1, sizeof (menu_t
));
4819 fp
= fopen(menu_path
, "r");
4820 if (fp
== NULL
) { /* Let the caller handle this error */
4825 /* Note: GRUB boot entry number starts with 0 */
4830 while (s_fgets(cp
, len
, fp
) != NULL
) {
4832 if (cp
[n
- 1] == '\\') {
4838 line_parser(mp
, buf
, &line
, &entry
);
4843 if (fclose(fp
) == EOF
) {
4844 bam_error(CLOSE_FAIL
, menu_path
, strerror(errno
));
4851 selector(menu_t
*mp
, char *opt
, int *entry
, char **title
)
4861 opt_dup
= s_strdup(opt
);
4864 *entry
= ENTRY_INIT
;
4868 eq
= strchr(opt_dup
, '=');
4870 bam_error(INVALID_OPT
, opt
);
4876 if (entry
&& strcmp(opt_dup
, OPT_ENTRY_NUM
) == 0) {
4878 entryNum
= s_strtol(eq
+ 1);
4879 if (entryNum
< 0 || entryNum
> mp
->end
->entryNum
) {
4880 bam_error(INVALID_ENTRY
, eq
+ 1);
4885 } else if (title
&& strcmp(opt_dup
, menu_cmds
[TITLE_CMD
]) == 0) {
4886 *title
= opt
+ (eq
- opt_dup
) + 1;
4888 bam_error(INVALID_OPT
, opt
);
4894 return (BAM_SUCCESS
);
4898 * If invoked with no titles/entries (opt == NULL)
4899 * only title lines in file are printed.
4901 * If invoked with a title or entry #, all
4902 * lines in *every* matching entry are listed
4905 list_entry(menu_t
*mp
, char *menu_path
, char *opt
)
4908 int entry
= ENTRY_INIT
;
4915 /* opt is optional */
4916 BAM_DPRINTF((D_FUNC_ENTRY2
, "list_entry", menu_path
,
4917 opt
? opt
: "<NULL>"));
4919 if (mp
->start
== NULL
) {
4920 bam_error(NO_MENU
, menu_path
);
4925 if (selector(mp
, opt
, &entry
, &title
) != BAM_SUCCESS
) {
4928 assert((entry
!= ENTRY_INIT
) ^ (title
!= NULL
));
4930 (void) read_globals(mp
, menu_path
, menu_cmds
[DEFAULT_CMD
], 0);
4931 (void) read_globals(mp
, menu_path
, menu_cmds
[TIMEOUT_CMD
], 0);
4935 for (lp
= mp
->start
; lp
; lp
= lp
->next
) {
4936 if (lp
->flags
== BAM_COMMENT
|| lp
->flags
== BAM_EMPTY
)
4938 if (opt
== NULL
&& lp
->flags
== BAM_TITLE
) {
4939 bam_print(PRINT_TITLE
, lp
->entryNum
,
4944 if (entry
!= ENTRY_INIT
&& lp
->entryNum
== entry
) {
4945 bam_print(PRINT
, lp
->line
);
4951 * We set the entry value here so that all lines
4952 * in entry get printed. If we subsequently match
4953 * title in other entries, all lines in those
4954 * entries get printed as well.
4956 if (title
&& lp
->flags
== BAM_TITLE
&& lp
->arg
&&
4957 strncmp(title
, lp
->arg
, strlen(title
)) == 0) {
4958 bam_print(PRINT
, lp
->line
);
4959 entry
= lp
->entryNum
;
4966 bam_error(NO_MATCH_ENTRY
);
4970 return (BAM_SUCCESS
);
4974 add_boot_entry(menu_t
*mp
,
4984 char linebuf
[BAM_MAXLINE
];
4987 const char *fcn
= "add_boot_entry()";
4991 INJECT_ERROR1("ADD_BOOT_ENTRY_FINDROOT_NULL", findroot
= NULL
);
4992 if (findroot
== NULL
) {
4993 bam_error(NULL_FINDROOT
);
4997 if (title
== NULL
) {
4998 title
= "Solaris"; /* default to Solaris */
5000 if (kernel
== NULL
) {
5001 bam_error(SUBOPT_MISS
, menu_cmds
[KERNEL_CMD
]);
5004 if (module
== NULL
) {
5005 if (bam_direct
!= BAM_DIRECT_DBOOT
) {
5006 bam_error(SUBOPT_MISS
, menu_cmds
[MODULE_CMD
]);
5010 /* Figure the commands out from the kernel line */
5011 if (strstr(kernel
, "$ISADIR") != NULL
) {
5012 module
= DIRECT_BOOT_ARCHIVE
;
5013 } else if (strstr(kernel
, "amd64") != NULL
) {
5014 module
= DIRECT_BOOT_ARCHIVE_64
;
5016 module
= DIRECT_BOOT_ARCHIVE_32
;
5020 k_cmd
= KERNEL_DOLLAR_CMD
;
5021 m_cmd
= MODULE_DOLLAR_CMD
;
5024 lineNum
= mp
->end
->lineNum
;
5025 entryNum
= mp
->end
->entryNum
;
5027 lineNum
= LINE_INIT
;
5028 entryNum
= ENTRY_INIT
;
5032 * No separator for comment (HDR/FTR) commands
5033 * The syntax for comments is #<comment>
5035 (void) snprintf(linebuf
, sizeof (linebuf
), "%s%s",
5036 menu_cmds
[COMMENT_CMD
], BAM_BOOTADM_HDR
);
5037 line_parser(mp
, linebuf
, &lineNum
, &entryNum
);
5039 (void) snprintf(linebuf
, sizeof (linebuf
), "%s%s%s",
5040 menu_cmds
[TITLE_CMD
], menu_cmds
[SEP_CMD
], title
);
5041 line_parser(mp
, linebuf
, &lineNum
, &entryNum
);
5043 (void) snprintf(linebuf
, sizeof (linebuf
), "%s%s%s",
5044 menu_cmds
[FINDROOT_CMD
], menu_cmds
[SEP_CMD
], findroot
);
5045 line_parser(mp
, linebuf
, &lineNum
, &entryNum
);
5046 BAM_DPRINTF((D_ADD_FINDROOT_NUM
, fcn
, lineNum
, entryNum
));
5048 if (bootfs
!= NULL
) {
5049 (void) snprintf(linebuf
, sizeof (linebuf
), "%s%s%s",
5050 menu_cmds
[BOOTFS_CMD
], menu_cmds
[SEP_CMD
], bootfs
);
5051 line_parser(mp
, linebuf
, &lineNum
, &entryNum
);
5054 (void) snprintf(linebuf
, sizeof (linebuf
), "%s%s%s",
5055 menu_cmds
[k_cmd
], menu_cmds
[SEP_CMD
], kernel
);
5056 line_parser(mp
, linebuf
, &lineNum
, &entryNum
);
5058 if (mod_kernel
!= NULL
) {
5059 (void) snprintf(linebuf
, sizeof (linebuf
), "%s%s%s",
5060 menu_cmds
[m_cmd
], menu_cmds
[SEP_CMD
], mod_kernel
);
5061 line_parser(mp
, linebuf
, &lineNum
, &entryNum
);
5064 (void) snprintf(linebuf
, sizeof (linebuf
), "%s%s%s",
5065 menu_cmds
[m_cmd
], menu_cmds
[SEP_CMD
], module
);
5066 line_parser(mp
, linebuf
, &lineNum
, &entryNum
);
5068 (void) snprintf(linebuf
, sizeof (linebuf
), "%s%s",
5069 menu_cmds
[COMMENT_CMD
], BAM_BOOTADM_FTR
);
5070 line_parser(mp
, linebuf
, &lineNum
, &entryNum
);
5076 delete_boot_entry(menu_t
*mp
, int entryNum
, int quiet
)
5083 const char *fcn
= "delete_boot_entry()";
5085 assert(entryNum
!= ENTRY_INIT
);
5094 * Check entry number and make sure it's a modifiable entry.
5097 * + We can modify a bootadm-created entry
5098 * + We can modify a libbe-created entry
5100 if ((lp
->flags
!= BAM_COMMENT
&&
5101 (((ent
->flags
& BAM_ENTRY_LIBBE
) == 0) &&
5102 strcmp(lp
->arg
, BAM_BOOTADM_HDR
) != 0)) ||
5103 (entryNum
!= ALL_ENTRIES
&& lp
->entryNum
!= entryNum
)) {
5108 /* free the entry content */
5111 lp
= lp
->next
; /* prev stays the same */
5112 BAM_DPRINTF((D_FREEING_LINE
, fcn
, freed
->lineNum
));
5113 unlink_line(mp
, freed
);
5115 } while (freed
!= ent
->end
);
5117 /* free the entry_t structure */
5118 assert(tmp
== NULL
);
5122 tmp
->prev
->next
= ent
;
5126 ent
->prev
= tmp
->prev
;
5127 BAM_DPRINTF((D_FREEING_ENTRY
, fcn
, tmp
->entryNum
));
5133 assert(tmp
== NULL
);
5135 if (!deleted
&& entryNum
!= ALL_ENTRIES
) {
5136 if (quiet
== DBE_PRINTERR
)
5137 bam_error(NO_BOOTADM_MATCH
);
5142 * Now that we have deleted an entry, update
5143 * the entry numbering and the default cmd.
5145 update_numbering(mp
);
5147 return (BAM_SUCCESS
);
5151 delete_all_entries(menu_t
*mp
, char *dummy
, char *opt
)
5154 assert(dummy
== NULL
);
5155 assert(opt
== NULL
);
5157 BAM_DPRINTF((D_FUNC_ENTRY0
, "delete_all_entries"));
5159 if (mp
->start
== NULL
) {
5160 bam_print(EMPTY_MENU
);
5161 return (BAM_SUCCESS
);
5164 if (delete_boot_entry(mp
, ALL_ENTRIES
, DBE_PRINTERR
) != BAM_SUCCESS
) {
5172 create_diskmap(char *osroot
)
5175 char cmd
[PATH_MAX
+ 16];
5176 char path
[PATH_MAX
];
5177 const char *fcn
= "create_diskmap()";
5179 /* make sure we have a map file */
5180 fp
= fopen(GRUBDISK_MAP
, "r");
5184 ret
= snprintf(path
, sizeof (path
), "%s/%s", osroot
,
5186 if (ret
>= sizeof (path
)) {
5187 bam_error(PATH_TOO_LONG
, osroot
);
5190 if (is_safe_exec(path
) == BAM_ERROR
)
5193 (void) snprintf(cmd
, sizeof (cmd
),
5194 "%s/%s > /dev/null", osroot
, CREATE_DISKMAP
);
5195 if (exec_cmd(cmd
, NULL
) != 0)
5197 fp
= fopen(GRUBDISK_MAP
, "r");
5198 INJECT_ERROR1("DISKMAP_CREATE_FAIL", fp
= NULL
);
5200 BAM_DPRINTF((D_CREATED_DISKMAP
, fcn
, GRUBDISK_MAP
));
5202 BAM_DPRINTF((D_CREATE_DISKMAP_FAIL
, fcn
, GRUBDISK_MAP
));
5208 #define SECTOR_SIZE 512
5211 get_partition(char *device
)
5213 int i
, fd
, is_pcfs
, partno
= PARTNO_NOTFOUND
;
5214 struct mboot
*mboot
;
5215 char boot_sect
[SECTOR_SIZE
];
5216 char *wholedisk
, *slice
;
5219 uint32_t secnum
, numsec
;
5220 int rval
, pno
, ext_partno
= PARTNO_NOTFOUND
;
5223 /* form whole disk (p0) */
5224 slice
= device
+ strlen(device
) - 2;
5225 is_pcfs
= (*slice
!= 's');
5228 wholedisk
= s_calloc(1, strlen(device
) + 3);
5229 (void) snprintf(wholedisk
, strlen(device
) + 3, "%sp0", device
);
5233 /* read boot sector */
5234 fd
= open(wholedisk
, O_RDONLY
);
5235 if (fd
== -1 || read(fd
, boot_sect
, SECTOR_SIZE
) != SECTOR_SIZE
) {
5241 /* Read/Initialize extended partition information */
5242 if ((rval
= libfdisk_init(&epp
, wholedisk
, NULL
, FDISK_READ_DISK
))
5246 * FDISK_EBADLOGDRIVE and FDISK_ENOLOGDRIVE can
5247 * be considered as soft errors and hence
5250 case FDISK_EBADLOGDRIVE
:
5252 case FDISK_ENOLOGDRIVE
:
5254 case FDISK_EBADMAGIC
:
5258 libfdisk_fini(&epp
);
5265 /* parse fdisk table */
5266 mboot
= (struct mboot
*)((void *)boot_sect
);
5267 for (i
= 0; i
< FD_NUMPART
; i
++) {
5268 struct ipart
*part
=
5269 (struct ipart
*)(uintptr_t)mboot
->parts
+ i
;
5270 if (is_pcfs
) { /* looking for solaris boot part */
5271 if (part
->systid
== 0xbe) {
5275 } else { /* look for solaris partition, old and new */
5276 if (part
->systid
== EFI_PMBR
) {
5277 partno
= PARTNO_EFI
;
5282 if ((part
->systid
== SUNIXOS
&&
5283 (fdisk_is_linux_swap(epp
, part
->relsect
,
5284 NULL
) != 0)) || part
->systid
== SUNIXOS2
) {
5286 if (part
->systid
== SUNIXOS
||
5287 part
->systid
== SUNIXOS2
) {
5294 if (fdisk_is_dos_extended(part
->systid
))
5300 /* If no primary solaris partition, check extended partition */
5301 if ((partno
== PARTNO_NOTFOUND
) && (ext_partno
!= PARTNO_NOTFOUND
)) {
5302 rval
= fdisk_get_solaris_part(epp
, &pno
, &secnum
, &numsec
);
5303 if (rval
== FDISK_SUCCESS
) {
5307 libfdisk_fini(&epp
);
5313 get_grubroot(char *osroot
, char *osdev
, char *menu_root
)
5315 char *grubroot
; /* (hd#,#,#) */
5321 char *ctdname
= strstr(osdev
, "dsk/");
5322 char linebuf
[PATH_MAX
];
5325 INJECT_ERROR1("GRUBROOT_INVALID_OSDEV", ctdname
= NULL
);
5326 if (ctdname
== NULL
) {
5327 bam_error(INVALID_DEV_DSK
, osdev
);
5331 if (menu_root
&& !menu_on_bootdisk(osroot
, menu_root
)) {
5332 /* menu bears no resemblance to our reality */
5333 bam_error(CANNOT_GRUBROOT_BOOTDISK
, osdev
);
5337 ctdname
+= strlen("dsk/");
5338 slice
= strrchr(ctdname
, 's');
5342 fp
= create_diskmap(osroot
);
5344 bam_error(DISKMAP_FAIL
, osroot
);
5349 while (s_fgets(linebuf
, sizeof (linebuf
), fp
) != NULL
) {
5350 grubhd
= strtok(linebuf
, " \t\n");
5352 devname
= strtok(NULL
, " \t\n");
5355 if (devname
&& strcmp(devname
, ctdname
) == 0) {
5367 INJECT_ERROR1("GRUBROOT_BIOSDEV_FAIL", found
= 0);
5369 bam_error(BIOSDEV_SKIP
, osdev
);
5373 fdiskpart
= get_partition(osdev
);
5374 INJECT_ERROR1("GRUBROOT_FDISK_FAIL", fdiskpart
= PARTNO_NOTFOUND
);
5375 if (fdiskpart
== PARTNO_NOTFOUND
) {
5376 bam_error(FDISKPART_FAIL
, osdev
);
5380 grubroot
= s_calloc(1, 10);
5381 if (fdiskpart
== PARTNO_EFI
) {
5382 fdiskpart
= atoi(&slice
[1]);
5387 (void) snprintf(grubroot
, 10, "(hd%s,%d,%c)",
5388 grubhd
, fdiskpart
, slice
[1] + 'a' - '0');
5390 (void) snprintf(grubroot
, 10, "(hd%s,%d)",
5394 assert(strncmp(grubroot
, "(hd", strlen("(hd")) == 0);
5399 find_primary_common(char *mntpt
, char *fstype
)
5401 char signdir
[PATH_MAX
];
5402 char tmpsign
[MAXNAMELEN
+ 1];
5407 struct dirent
*entp
;
5409 const char *fcn
= "find_primary_common()";
5411 (void) snprintf(signdir
, sizeof (signdir
), "%s/%s",
5412 mntpt
, GRUBSIGN_DIR
);
5414 if (stat(signdir
, &sb
) == -1) {
5415 BAM_DPRINTF((D_NO_SIGNDIR
, fcn
, signdir
));
5419 dirp
= opendir(signdir
);
5420 INJECT_ERROR1("SIGNDIR_OPENDIR_FAIL", dirp
= NULL
);
5422 bam_error(OPENDIR_FAILED
, signdir
, strerror(errno
));
5426 ufs
= zfs
= lu
= NULL
;
5428 while (entp
= readdir(dirp
)) {
5429 if (strcmp(entp
->d_name
, ".") == 0 ||
5430 strcmp(entp
->d_name
, "..") == 0)
5433 (void) snprintf(tmpsign
, sizeof (tmpsign
), "%s", entp
->d_name
);
5436 strncmp(tmpsign
, GRUBSIGN_LU_PREFIX
,
5437 strlen(GRUBSIGN_LU_PREFIX
)) == 0) {
5438 lu
= s_strdup(tmpsign
);
5442 strncmp(tmpsign
, GRUBSIGN_UFS_PREFIX
,
5443 strlen(GRUBSIGN_UFS_PREFIX
)) == 0) {
5444 ufs
= s_strdup(tmpsign
);
5448 strncmp(tmpsign
, GRUBSIGN_ZFS_PREFIX
,
5449 strlen(GRUBSIGN_ZFS_PREFIX
)) == 0) {
5450 zfs
= s_strdup(tmpsign
);
5454 BAM_DPRINTF((D_EXIST_PRIMARY_SIGNS
, fcn
,
5460 (void) closedir(dirp
);
5464 if (strcmp(fstype
, "ufs") == 0 && zfs
) {
5465 bam_error(SIGN_FSTYPE_MISMATCH
, zfs
, "ufs");
5468 } else if (strcmp(fstype
, "zfs") == 0 && ufs
) {
5469 bam_error(SIGN_FSTYPE_MISMATCH
, ufs
, "zfs");
5474 assert(dirp
== NULL
);
5476 /* For now, we let Live Upgrade take care of its signature itself */
5478 BAM_DPRINTF((D_FREEING_LU_SIGNS
, fcn
, lu
));
5483 return (zfs
? zfs
: ufs
);
5487 find_backup_common(char *mntpt
, char *fstype
)
5490 char tmpsign
[MAXNAMELEN
+ 1];
5491 char backup
[PATH_MAX
];
5496 const char *fcn
= "find_backup_common()";
5499 * We didn't find it in the primary directory.
5500 * Look at the backup
5502 (void) snprintf(backup
, sizeof (backup
), "%s%s",
5503 mntpt
, GRUBSIGN_BACKUP
);
5505 bfp
= fopen(backup
, "r");
5509 bam_error(OPEN_FAIL
, backup
, strerror(error
));
5511 BAM_DPRINTF((D_OPEN_FAIL
, fcn
, backup
, strerror(error
)));
5515 ufs
= zfs
= lu
= NULL
;
5517 while (s_fgets(tmpsign
, sizeof (tmpsign
), bfp
) != NULL
) {
5520 strncmp(tmpsign
, GRUBSIGN_LU_PREFIX
,
5521 strlen(GRUBSIGN_LU_PREFIX
)) == 0) {
5522 lu
= s_strdup(tmpsign
);
5526 strncmp(tmpsign
, GRUBSIGN_UFS_PREFIX
,
5527 strlen(GRUBSIGN_UFS_PREFIX
)) == 0) {
5528 ufs
= s_strdup(tmpsign
);
5532 strncmp(tmpsign
, GRUBSIGN_ZFS_PREFIX
,
5533 strlen(GRUBSIGN_ZFS_PREFIX
)) == 0) {
5534 zfs
= s_strdup(tmpsign
);
5538 BAM_DPRINTF((D_EXIST_BACKUP_SIGNS
, fcn
,
5548 if (strcmp(fstype
, "ufs") == 0 && zfs
) {
5549 bam_error(SIGN_FSTYPE_MISMATCH
, zfs
, "ufs");
5552 } else if (strcmp(fstype
, "zfs") == 0 && ufs
) {
5553 bam_error(SIGN_FSTYPE_MISMATCH
, ufs
, "zfs");
5558 assert(bfp
== NULL
);
5560 /* For now, we let Live Upgrade take care of its signature itself */
5562 BAM_DPRINTF((D_FREEING_LU_SIGNS
, fcn
, lu
));
5567 return (zfs
? zfs
: ufs
);
5571 find_ufs_existing(char *osroot
)
5574 const char *fcn
= "find_ufs_existing()";
5576 sign
= find_primary_common(osroot
, "ufs");
5578 sign
= find_backup_common(osroot
, "ufs");
5579 BAM_DPRINTF((D_EXIST_BACKUP_SIGN
, fcn
, sign
? sign
: "NULL"));
5581 BAM_DPRINTF((D_EXIST_PRIMARY_SIGN
, fcn
, sign
));
5588 get_mountpoint(char *special
, char *fstype
)
5591 struct mnttab mp
= {0};
5592 struct mnttab mpref
= {0};
5595 const char *fcn
= "get_mountpoint()";
5597 BAM_DPRINTF((D_FUNC_ENTRY2
, fcn
, special
, fstype
));
5599 mntfp
= fopen(MNTTAB
, "r");
5601 INJECT_ERROR1("MNTTAB_ERR_GET_MNTPT", mntfp
= NULL
);
5602 if (mntfp
== NULL
) {
5603 bam_error(OPEN_FAIL
, MNTTAB
, strerror(error
));
5607 mpref
.mnt_special
= special
;
5608 mpref
.mnt_fstype
= fstype
;
5610 ret
= getmntany(mntfp
, &mp
, &mpref
);
5611 INJECT_ERROR1("GET_MOUNTPOINT_MNTANY", ret
= 1);
5613 (void) fclose(mntfp
);
5614 BAM_DPRINTF((D_NO_MNTPT
, fcn
, special
, fstype
));
5617 (void) fclose(mntfp
);
5619 assert(mp
.mnt_mountp
);
5621 BAM_DPRINTF((D_GET_MOUNTPOINT_RET
, fcn
, special
, mp
.mnt_mountp
));
5623 return (s_strdup(mp
.mnt_mountp
));
5627 * Mounts a "legacy" top dataset (if needed)
5628 * Returns: The mountpoint of the legacy top dataset or NULL on error
5629 * mnted returns one of the above values defined for zfs_mnted_t
5632 mount_legacy_dataset(char *pool
, zfs_mnted_t
*mnted
)
5635 char tmpmnt
[PATH_MAX
];
5636 filelist_t flist
= {0};
5640 const char *fcn
= "mount_legacy_dataset()";
5642 BAM_DPRINTF((D_FUNC_ENTRY1
, fcn
, pool
));
5644 *mnted
= ZFS_MNT_ERROR
;
5646 (void) snprintf(cmd
, sizeof (cmd
),
5647 "/sbin/zfs get -Ho value mounted %s",
5650 ret
= exec_cmd(cmd
, &flist
);
5651 INJECT_ERROR1("Z_MOUNT_LEG_GET_MOUNTED_CMD", ret
= 1);
5653 bam_error(ZFS_MNTED_FAILED
, pool
);
5657 INJECT_ERROR1("Z_MOUNT_LEG_GET_MOUNTED_OUT", flist
.head
= NULL
);
5658 if ((flist
.head
== NULL
) || (flist
.head
!= flist
.tail
)) {
5659 bam_error(BAD_ZFS_MNTED
, pool
);
5660 filelist_free(&flist
);
5664 is_mounted
= strtok(flist
.head
->line
, " \t\n");
5665 INJECT_ERROR1("Z_MOUNT_LEG_GET_MOUNTED_STRTOK_YES", is_mounted
= "yes");
5666 INJECT_ERROR1("Z_MOUNT_LEG_GET_MOUNTED_STRTOK_NO", is_mounted
= "no");
5667 if (strcmp(is_mounted
, "no") != 0) {
5668 filelist_free(&flist
);
5669 *mnted
= LEGACY_ALREADY
;
5670 /* get_mountpoint returns a strdup'ed string */
5671 BAM_DPRINTF((D_Z_MOUNT_TOP_LEG_ALREADY
, fcn
, pool
));
5672 return (get_mountpoint(pool
, "zfs"));
5675 filelist_free(&flist
);
5678 * legacy top dataset is not mounted. Mount it now
5679 * First create a mountpoint.
5681 (void) snprintf(tmpmnt
, sizeof (tmpmnt
), "%s.%d",
5682 ZFS_LEGACY_MNTPT
, getpid());
5684 ret
= stat(tmpmnt
, &sb
);
5686 BAM_DPRINTF((D_Z_MOUNT_TOP_LEG_MNTPT_ABS
, fcn
, pool
, tmpmnt
));
5687 ret
= mkdirp(tmpmnt
, DIR_PERMS
);
5688 INJECT_ERROR1("Z_MOUNT_TOP_LEG_MNTPT_MKDIRP", ret
= -1);
5690 bam_error(MKDIR_FAILED
, tmpmnt
, strerror(errno
));
5694 BAM_DPRINTF((D_Z_MOUNT_TOP_LEG_MNTPT_PRES
, fcn
, pool
, tmpmnt
));
5697 (void) snprintf(cmd
, sizeof (cmd
),
5698 "/sbin/mount -F zfs %s %s",
5701 ret
= exec_cmd(cmd
, NULL
);
5702 INJECT_ERROR1("Z_MOUNT_TOP_LEG_MOUNT_CMD", ret
= 1);
5704 bam_error(ZFS_MOUNT_FAILED
, pool
);
5705 (void) rmdir(tmpmnt
);
5709 *mnted
= LEGACY_MOUNTED
;
5710 BAM_DPRINTF((D_Z_MOUNT_TOP_LEG_MOUNTED
, fcn
, pool
, tmpmnt
));
5711 return (s_strdup(tmpmnt
));
5715 * Mounts the top dataset (if needed)
5716 * Returns: The mountpoint of the top dataset or NULL on error
5717 * mnted returns one of the above values defined for zfs_mnted_t
5720 mount_top_dataset(char *pool
, zfs_mnted_t
*mnted
)
5723 filelist_t flist
= {0};
5728 const char *fcn
= "mount_top_dataset()";
5730 *mnted
= ZFS_MNT_ERROR
;
5732 BAM_DPRINTF((D_FUNC_ENTRY1
, fcn
, pool
));
5735 * First check if the top dataset is a "legacy" dataset
5737 (void) snprintf(cmd
, sizeof (cmd
),
5738 "/sbin/zfs get -Ho value mountpoint %s",
5740 ret
= exec_cmd(cmd
, &flist
);
5741 INJECT_ERROR1("Z_MOUNT_TOP_GET_MNTPT", ret
= 1);
5743 bam_error(ZFS_MNTPT_FAILED
, pool
);
5747 if (flist
.head
&& (flist
.head
== flist
.tail
)) {
5748 char *legacy
= strtok(flist
.head
->line
, " \t\n");
5749 if (legacy
&& strcmp(legacy
, "legacy") == 0) {
5750 filelist_free(&flist
);
5751 BAM_DPRINTF((D_Z_IS_LEGACY
, fcn
, pool
));
5752 return (mount_legacy_dataset(pool
, mnted
));
5756 filelist_free(&flist
);
5758 BAM_DPRINTF((D_Z_IS_NOT_LEGACY
, fcn
, pool
));
5760 (void) snprintf(cmd
, sizeof (cmd
),
5761 "/sbin/zfs get -Ho value mounted %s",
5764 ret
= exec_cmd(cmd
, &flist
);
5765 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MOUNTED", ret
= 1);
5767 bam_error(ZFS_MNTED_FAILED
, pool
);
5771 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MOUNTED_VAL", flist
.head
= NULL
);
5772 if ((flist
.head
== NULL
) || (flist
.head
!= flist
.tail
)) {
5773 bam_error(BAD_ZFS_MNTED
, pool
);
5774 filelist_free(&flist
);
5778 is_mounted
= strtok(flist
.head
->line
, " \t\n");
5779 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MOUNTED_YES", is_mounted
= "yes");
5780 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MOUNTED_NO", is_mounted
= "no");
5781 if (strcmp(is_mounted
, "no") != 0) {
5782 filelist_free(&flist
);
5783 *mnted
= ZFS_ALREADY
;
5784 BAM_DPRINTF((D_Z_MOUNT_TOP_NONLEG_MOUNTED_ALREADY
, fcn
, pool
));
5788 filelist_free(&flist
);
5789 BAM_DPRINTF((D_Z_MOUNT_TOP_NONLEG_MOUNTED_NOT_ALREADY
, fcn
, pool
));
5791 /* top dataset is not mounted. Mount it now */
5792 (void) snprintf(cmd
, sizeof (cmd
),
5793 "/sbin/zfs mount %s", pool
);
5794 ret
= exec_cmd(cmd
, NULL
);
5795 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_MOUNT_CMD", ret
= 1);
5797 bam_error(ZFS_MOUNT_FAILED
, pool
);
5800 *mnted
= ZFS_MOUNTED
;
5801 BAM_DPRINTF((D_Z_MOUNT_TOP_NONLEG_MOUNTED_NOW
, fcn
, pool
));
5805 * Now get the mountpoint
5807 (void) snprintf(cmd
, sizeof (cmd
),
5808 "/sbin/zfs get -Ho value mountpoint %s",
5811 ret
= exec_cmd(cmd
, &flist
);
5812 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MNTPT_CMD", ret
= 1);
5814 bam_error(ZFS_MNTPT_FAILED
, pool
);
5818 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MNTPT_OUT", flist
.head
= NULL
);
5819 if ((flist
.head
== NULL
) || (flist
.head
!= flist
.tail
)) {
5820 bam_error(NULL_ZFS_MNTPT
, pool
);
5824 mntpt
= strtok(flist
.head
->line
, " \t\n");
5825 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MNTPT_STRTOK", mntpt
= "foo");
5826 if (*mntpt
!= '/') {
5827 bam_error(BAD_ZFS_MNTPT
, pool
, mntpt
);
5830 zmntpt
= s_strdup(mntpt
);
5832 filelist_free(&flist
);
5834 BAM_DPRINTF((D_Z_MOUNT_TOP_NONLEG_MNTPT
, fcn
, pool
, zmntpt
));
5839 filelist_free(&flist
);
5840 (void) umount_top_dataset(pool
, *mnted
, NULL
);
5841 BAM_DPRINTF((D_RETURN_FAILURE
, fcn
));
5846 umount_top_dataset(char *pool
, zfs_mnted_t mnted
, char *mntpt
)
5850 const char *fcn
= "umount_top_dataset()";
5852 INJECT_ERROR1("Z_UMOUNT_TOP_INVALID_STATE", mnted
= ZFS_MNT_ERROR
);
5854 case LEGACY_ALREADY
:
5857 BAM_DPRINTF((D_Z_UMOUNT_TOP_ALREADY_NOP
, fcn
, pool
,
5858 mntpt
? mntpt
: "NULL"));
5860 return (BAM_SUCCESS
);
5861 case LEGACY_MOUNTED
:
5862 (void) snprintf(cmd
, sizeof (cmd
),
5863 "/sbin/umount %s", pool
);
5864 ret
= exec_cmd(cmd
, NULL
);
5865 INJECT_ERROR1("Z_UMOUNT_TOP_LEGACY_UMOUNT_FAIL", ret
= 1);
5867 bam_error(UMOUNT_FAILED
, pool
);
5872 (void) rmdir(mntpt
);
5874 BAM_DPRINTF((D_Z_UMOUNT_TOP_LEGACY
, fcn
, pool
));
5875 return (BAM_SUCCESS
);
5878 (void) snprintf(cmd
, sizeof (cmd
),
5879 "/sbin/zfs unmount %s", pool
);
5880 ret
= exec_cmd(cmd
, NULL
);
5881 INJECT_ERROR1("Z_UMOUNT_TOP_NONLEG_UMOUNT_FAIL", ret
= 1);
5883 bam_error(UMOUNT_FAILED
, pool
);
5886 BAM_DPRINTF((D_Z_UMOUNT_TOP_NONLEG
, fcn
, pool
));
5887 return (BAM_SUCCESS
);
5889 bam_error(INT_BAD_MNTSTATE
, pool
);
5896 * For ZFS, osdev can be one of two forms
5897 * It can be a "special" file as seen in mnttab: rpool/ROOT/szboot_0402
5898 * It can be a /dev/[r]dsk special file. We handle both instances
5901 get_pool(char *osdev
)
5905 filelist_t flist
= {0};
5910 const char *fcn
= "get_pool()";
5912 INJECT_ERROR1("GET_POOL_OSDEV", osdev
= NULL
);
5913 if (osdev
== NULL
) {
5914 bam_error(GET_POOL_OSDEV_NULL
);
5918 BAM_DPRINTF((D_GET_POOL_OSDEV
, fcn
, osdev
));
5920 if (osdev
[0] != '/') {
5921 (void) strlcpy(buf
, osdev
, sizeof (buf
));
5922 slash
= strchr(buf
, '/');
5925 pool
= s_strdup(buf
);
5926 BAM_DPRINTF((D_GET_POOL_RET
, fcn
, pool
));
5928 } else if (strncmp(osdev
, "/dev/dsk/", strlen("/dev/dsk/")) != 0 &&
5929 strncmp(osdev
, "/dev/rdsk/", strlen("/dev/rdsk/")) != 0) {
5930 bam_error(GET_POOL_BAD_OSDEV
, osdev
);
5935 * Call the zfs fstyp directly since this is a zpool. This avoids
5936 * potential pcfs conflicts if the first block wasn't cleared.
5938 (void) snprintf(cmd
, sizeof (cmd
),
5939 "/usr/lib/fs/zfs/fstyp -a %s 2>/dev/null | /bin/grep '^name:'",
5942 ret
= exec_cmd(cmd
, &flist
);
5943 INJECT_ERROR1("GET_POOL_FSTYP", ret
= 1);
5945 bam_error(FSTYP_A_FAILED
, osdev
);
5949 INJECT_ERROR1("GET_POOL_FSTYP_OUT", flist
.head
= NULL
);
5950 if ((flist
.head
== NULL
) || (flist
.head
!= flist
.tail
)) {
5951 bam_error(NULL_FSTYP_A
, osdev
);
5952 filelist_free(&flist
);
5956 (void) strtok(flist
.head
->line
, "'");
5957 cp
= strtok(NULL
, "'");
5958 INJECT_ERROR1("GET_POOL_FSTYP_STRTOK", cp
= NULL
);
5960 bam_error(BAD_FSTYP_A
, osdev
);
5961 filelist_free(&flist
);
5965 pool
= s_strdup(cp
);
5967 filelist_free(&flist
);
5969 BAM_DPRINTF((D_GET_POOL_RET
, fcn
, pool
));
5975 find_zfs_existing(char *osdev
)
5981 const char *fcn
= "find_zfs_existing()";
5983 pool
= get_pool(osdev
);
5984 INJECT_ERROR1("ZFS_FIND_EXIST_POOL", pool
= NULL
);
5986 bam_error(ZFS_GET_POOL_FAILED
, osdev
);
5990 mntpt
= mount_top_dataset(pool
, &mnted
);
5991 INJECT_ERROR1("ZFS_FIND_EXIST_MOUNT_TOP", mntpt
= NULL
);
5992 if (mntpt
== NULL
) {
5993 bam_error(ZFS_MOUNT_TOP_DATASET_FAILED
, pool
);
5998 sign
= find_primary_common(mntpt
, "zfs");
6000 sign
= find_backup_common(mntpt
, "zfs");
6001 BAM_DPRINTF((D_EXIST_BACKUP_SIGN
, fcn
, sign
? sign
: "NULL"));
6003 BAM_DPRINTF((D_EXIST_PRIMARY_SIGN
, fcn
, sign
));
6006 (void) umount_top_dataset(pool
, mnted
, mntpt
);
6014 find_existing_sign(char *osroot
, char *osdev
, char *fstype
)
6016 const char *fcn
= "find_existing_sign()";
6018 INJECT_ERROR1("FIND_EXIST_NOTSUP_FS", fstype
= "foofs");
6019 if (strcmp(fstype
, "ufs") == 0) {
6020 BAM_DPRINTF((D_CHECK_UFS_EXIST_SIGN
, fcn
));
6021 return (find_ufs_existing(osroot
));
6022 } else if (strcmp(fstype
, "zfs") == 0) {
6023 BAM_DPRINTF((D_CHECK_ZFS_EXIST_SIGN
, fcn
));
6024 return (find_zfs_existing(osdev
));
6026 bam_error(GRUBSIGN_NOTSUP
, fstype
);
6031 #define MH_HASH_SZ 16
6039 typedef struct mcache
{
6043 struct mcache
*mc_next
;
6046 typedef struct mhash
{
6047 mcache_t
*mh_hash
[MH_HASH_SZ
];
6051 mhash_fcn(char *key
)
6056 for (i
= 0; key
[i
] != '\0'; i
++) {
6057 sum
+= (uchar_t
)key
[i
];
6062 assert(sum
< MH_HASH_SZ
);
6071 struct extmnttab mnt
;
6078 const char *fcn
= "cache_mnttab()";
6080 mfp
= fopen(MNTTAB
, "r");
6082 INJECT_ERROR1("CACHE_MNTTAB_MNTTAB_ERR", mfp
= NULL
);
6084 bam_error(OPEN_FAIL
, MNTTAB
, strerror(error
));
6088 mhp
= s_calloc(1, sizeof (mhash_t
));
6092 while (getextmntent(mfp
, &mnt
, sizeof (mnt
)) == 0) {
6093 /* only cache ufs */
6094 if (strcmp(mnt
.mnt_fstype
, "ufs") != 0)
6097 /* basename() modifies its arg, so dup it */
6098 special_dup
= s_strdup(mnt
.mnt_special
);
6099 ctds
= basename(special_dup
);
6101 mcp
= s_calloc(1, sizeof (mcache_t
));
6102 mcp
->mc_special
= s_strdup(ctds
);
6103 mcp
->mc_mntpt
= s_strdup(mnt
.mnt_mountp
);
6104 mcp
->mc_fstype
= s_strdup(mnt
.mnt_fstype
);
6105 BAM_DPRINTF((D_CACHE_MNTS
, fcn
, ctds
,
6106 mnt
.mnt_mountp
, mnt
.mnt_fstype
));
6107 idx
= mhash_fcn(ctds
);
6108 mcp
->mc_next
= mhp
->mh_hash
[idx
];
6109 mhp
->mh_hash
[idx
] = mcp
;
6119 free_mnttab(mhash_t
*mhp
)
6124 for (i
= 0; i
< MH_HASH_SZ
; i
++) {
6126 while (mcp
= mhp
->mh_hash
[i
]) {
6127 mhp
->mh_hash
[i
] = mcp
->mc_next
;
6128 free(mcp
->mc_special
);
6129 free(mcp
->mc_mntpt
);
6130 free(mcp
->mc_fstype
);
6135 for (i
= 0; i
< MH_HASH_SZ
; i
++) {
6136 assert(mhp
->mh_hash
[i
] == NULL
);
6142 search_hash(mhash_t
*mhp
, char *special
, char **mntpt
)
6146 const char *fcn
= "search_hash()";
6152 INJECT_ERROR1("SEARCH_HASH_FULL_PATH", special
= "/foo");
6153 if (strchr(special
, '/')) {
6154 bam_error(INVALID_MHASH_KEY
, special
);
6158 idx
= mhash_fcn(special
);
6160 for (mcp
= mhp
->mh_hash
[idx
]; mcp
; mcp
= mcp
->mc_next
) {
6161 if (strcmp(mcp
->mc_special
, special
) == 0)
6166 BAM_DPRINTF((D_MNTTAB_HASH_NOMATCH
, fcn
, special
));
6167 return (MH_NOMATCH
);
6170 assert(strcmp(mcp
->mc_fstype
, "ufs") == 0);
6171 *mntpt
= mcp
->mc_mntpt
;
6172 BAM_DPRINTF((D_MNTTAB_HASH_MATCH
, fcn
, special
));
6177 check_add_ufs_sign_to_list(FILE *tfp
, char *mntpt
)
6181 char signbuf
[MAXNAMELEN
];
6184 const char *fcn
= "check_add_ufs_sign_to_list()";
6186 /* safe to specify NULL as "osdev" arg for UFS */
6187 sign
= find_existing_sign(mntpt
, NULL
, "ufs");
6189 /* No existing signature, nothing to add to list */
6190 BAM_DPRINTF((D_NO_SIGN_TO_LIST
, fcn
, mntpt
));
6194 (void) snprintf(signbuf
, sizeof (signbuf
), "%s\n", sign
);
6197 INJECT_ERROR1("UFS_MNTPT_SIGN_NOTUFS", signline
= "pool_rpool10\n");
6198 if (strncmp(signline
, GRUBSIGN_UFS_PREFIX
,
6199 strlen(GRUBSIGN_UFS_PREFIX
))) {
6200 bam_error(INVALID_UFS_SIGNATURE
, sign
);
6202 /* ignore invalid signatures */
6206 len
= fputs(signline
, tfp
);
6208 INJECT_ERROR1("SIGN_LIST_PUTS_ERROR", len
= 0);
6209 if (len
!= strlen(signline
)) {
6210 bam_error(SIGN_LIST_FPUTS_ERR
, sign
, strerror(error
));
6217 BAM_DPRINTF((D_SIGN_LIST_PUTS_DONE
, fcn
, mntpt
));
6222 * slice is a basename not a full pathname
6225 process_slice_common(char *slice
, FILE *tfp
, mhash_t
*mhp
, char *tmpmnt
)
6229 char path
[PATH_MAX
];
6232 filelist_t flist
= {0};
6234 char blkslice
[PATH_MAX
];
6235 const char *fcn
= "process_slice_common()";
6238 ret
= search_hash(mhp
, slice
, &mntpt
);
6241 if (check_add_ufs_sign_to_list(tfp
, mntpt
) == -1)
6252 (void) snprintf(path
, sizeof (path
), "/dev/rdsk/%s", slice
);
6253 if (stat(path
, &sbuf
) == -1) {
6254 BAM_DPRINTF((D_SLICE_ENOENT
, fcn
, path
));
6258 /* Check if ufs. Call ufs fstyp directly to avoid pcfs conflicts. */
6259 (void) snprintf(cmd
, sizeof (cmd
),
6260 "/usr/lib/fs/ufs/fstyp /dev/rdsk/%s 2>/dev/null",
6263 if (exec_cmd(cmd
, &flist
) != 0) {
6265 bam_print(FSTYP_FAILED
, slice
);
6269 if ((flist
.head
== NULL
) || (flist
.head
!= flist
.tail
)) {
6271 bam_print(FSTYP_BAD
, slice
);
6272 filelist_free(&flist
);
6276 fstype
= strtok(flist
.head
->line
, " \t\n");
6277 if (fstype
== NULL
|| strcmp(fstype
, "ufs") != 0) {
6279 bam_print(NOT_UFS_SLICE
, slice
, fstype
);
6280 filelist_free(&flist
);
6284 filelist_free(&flist
);
6287 * Since we are mounting the filesystem read-only, the
6288 * the last mount field of the superblock is unchanged
6289 * and does not need to be fixed up post-mount;
6292 (void) snprintf(blkslice
, sizeof (blkslice
), "/dev/dsk/%s",
6295 (void) snprintf(cmd
, sizeof (cmd
),
6296 "/usr/sbin/mount -F ufs -o ro %s %s "
6297 "> /dev/null 2>&1", blkslice
, tmpmnt
);
6299 if (exec_cmd(cmd
, NULL
) != 0) {
6301 bam_print(MOUNT_FAILED
, blkslice
, "ufs");
6305 ret
= check_add_ufs_sign_to_list(tfp
, tmpmnt
);
6307 (void) snprintf(cmd
, sizeof (cmd
),
6308 "/usr/sbin/umount -f %s > /dev/null 2>&1",
6311 if (exec_cmd(cmd
, NULL
) != 0) {
6312 bam_print(UMOUNT_FAILED
, slice
);
6320 process_vtoc_slices(
6328 char slice
[PATH_MAX
];
6331 const char *fcn
= "process_vtoc_slices()";
6335 assert(s0
[len
- 2] == 's' && s0
[len
- 1] == '0');
6339 (void) strlcpy(slice
, s0
, sizeof (slice
));
6343 cp
= slice
+ len
- 1;
6345 for (idx
= 0; idx
< vtoc
->v_nparts
; idx
++) {
6347 (void) snprintf(cp
, sizeof (slice
) - (len
- 1), "%u", idx
);
6349 if (vtoc
->v_part
[idx
].p_size
== 0) {
6350 BAM_DPRINTF((D_VTOC_SIZE_ZERO
, fcn
, slice
));
6354 /* Skip "SWAP", "USR", "BACKUP", "VAR", "HOME", "ALTSCTR" */
6355 switch (vtoc
->v_part
[idx
].p_tag
) {
6362 BAM_DPRINTF((D_VTOC_NOT_ROOT_TAG
, fcn
, slice
));
6365 BAM_DPRINTF((D_VTOC_ROOT_TAG
, fcn
, slice
));
6369 /* skip unmountable and readonly slices */
6370 switch (vtoc
->v_part
[idx
].p_flag
) {
6373 BAM_DPRINTF((D_VTOC_NOT_RDWR_FLAG
, fcn
, slice
));
6376 BAM_DPRINTF((D_VTOC_RDWR_FLAG
, fcn
, slice
));
6380 if (process_slice_common(slice
, tfp
, mhp
, tmpmnt
) == -1) {
6397 char slice
[PATH_MAX
];
6400 const char *fcn
= "process_efi_slices()";
6404 assert(s0
[len
- 2] == 's' && s0
[len
- 1] == '0');
6408 (void) strlcpy(slice
, s0
, sizeof (slice
));
6412 cp
= slice
+ len
- 1;
6414 for (idx
= 0; idx
< efi
->efi_nparts
; idx
++) {
6416 (void) snprintf(cp
, sizeof (slice
) - (len
- 1), "%u", idx
);
6418 if (efi
->efi_parts
[idx
].p_size
== 0) {
6419 BAM_DPRINTF((D_EFI_SIZE_ZERO
, fcn
, slice
));
6423 /* Skip "SWAP", "USR", "BACKUP", "VAR", "HOME", "ALTSCTR" */
6424 switch (efi
->efi_parts
[idx
].p_tag
) {
6431 BAM_DPRINTF((D_EFI_NOT_ROOT_TAG
, fcn
, slice
));
6434 BAM_DPRINTF((D_EFI_ROOT_TAG
, fcn
, slice
));
6438 /* skip unmountable and readonly slices */
6439 switch (efi
->efi_parts
[idx
].p_flag
) {
6442 BAM_DPRINTF((D_EFI_NOT_RDWR_FLAG
, fcn
, slice
));
6445 BAM_DPRINTF((D_EFI_RDWR_FLAG
, fcn
, slice
));
6449 if (process_slice_common(slice
, tfp
, mhp
, tmpmnt
) == -1) {
6458 * s0 is a basename not a full path
6461 process_slice0(char *s0
, FILE *tfp
, mhash_t
*mhp
, char *tmpmnt
)
6465 char s0path
[PATH_MAX
];
6472 const char *fcn
= "process_slice0()";
6474 (void) snprintf(s0path
, sizeof (s0path
), "/dev/rdsk/%s", s0
);
6476 if (stat(s0path
, &sbuf
) == -1) {
6477 BAM_DPRINTF((D_SLICE0_ENOENT
, fcn
, s0path
));
6481 fd
= open(s0path
, O_NONBLOCK
|O_RDONLY
);
6483 bam_error(OPEN_FAIL
, s0path
, strerror(errno
));
6487 e_flag
= v_flag
= 0;
6488 retval
= ((err
= read_vtoc(fd
, &vtoc
)) >= 0) ? 0 : err
;
6491 BAM_DPRINTF((D_VTOC_READ_FAIL
, fcn
, s0path
));
6494 BAM_DPRINTF((D_VTOC_INVALID
, fcn
, s0path
));
6497 BAM_DPRINTF((D_VTOC_UNKNOWN_ERR
, fcn
, s0path
));
6501 BAM_DPRINTF((D_VTOC_NOTSUP
, fcn
, s0path
));
6505 BAM_DPRINTF((D_VTOC_READ_SUCCESS
, fcn
, s0path
));
6508 BAM_DPRINTF((D_VTOC_UNKNOWN_RETCODE
, fcn
, s0path
));
6515 retval
= ((err
= efi_alloc_and_read(fd
, &efi
)) >= 0) ? 0 : err
;
6518 BAM_DPRINTF((D_EFI_READ_FAIL
, fcn
, s0path
));
6521 BAM_DPRINTF((D_EFI_INVALID
, fcn
, s0path
));
6524 BAM_DPRINTF((D_EFI_UNKNOWN_ERR
, fcn
, s0path
));
6527 BAM_DPRINTF((D_EFI_NOTSUP
, fcn
, s0path
));
6531 BAM_DPRINTF((D_EFI_READ_SUCCESS
, fcn
, s0path
));
6534 BAM_DPRINTF((D_EFI_UNKNOWN_RETCODE
, fcn
, s0path
));
6542 retval
= process_vtoc_slices(s0
,
6543 &vtoc
, tfp
, mhp
, tmpmnt
);
6544 } else if (e_flag
) {
6545 retval
= process_efi_slices(s0
,
6546 efi
, tfp
, mhp
, tmpmnt
);
6548 BAM_DPRINTF((D_NOT_VTOC_OR_EFI
, fcn
, s0path
));
6556 * Find and create a list of all existing UFS boot signatures
6559 FindAllUfsSignatures(void)
6561 mhash_t
*mnttab_hash
;
6564 char tmpmnt
[PATH_MAX
];
6572 const char *fcn
= "FindAllUfsSignatures()";
6574 if (stat(UFS_SIGNATURE_LIST
, &sb
) != -1) {
6575 bam_print(SIGNATURE_LIST_EXISTS
, UFS_SIGNATURE_LIST
);
6579 fd
= open(UFS_SIGNATURE_LIST
".tmp",
6580 O_RDWR
|O_CREAT
|O_TRUNC
, 0644);
6582 INJECT_ERROR1("SIGN_LIST_TMP_TRUNC", fd
= -1);
6584 bam_error(OPEN_FAIL
, UFS_SIGNATURE_LIST
".tmp", strerror(error
));
6590 INJECT_ERROR1("SIGN_LIST_TMP_CLOSE", ret
= -1);
6592 bam_error(CLOSE_FAIL
, UFS_SIGNATURE_LIST
".tmp",
6594 (void) unlink(UFS_SIGNATURE_LIST
".tmp");
6598 tfp
= fopen(UFS_SIGNATURE_LIST
".tmp", "a");
6600 INJECT_ERROR1("SIGN_LIST_APPEND_FOPEN", tfp
= NULL
);
6602 bam_error(OPEN_FAIL
, UFS_SIGNATURE_LIST
".tmp", strerror(error
));
6603 (void) unlink(UFS_SIGNATURE_LIST
".tmp");
6607 mnttab_hash
= cache_mnttab();
6608 INJECT_ERROR1("CACHE_MNTTAB_ERROR", mnttab_hash
= NULL
);
6609 if (mnttab_hash
== NULL
) {
6611 (void) unlink(UFS_SIGNATURE_LIST
".tmp");
6612 bam_error(CACHE_MNTTAB_FAIL
, fcn
);
6616 (void) snprintf(tmpmnt
, sizeof (tmpmnt
),
6617 "/tmp/bootadm_ufs_sign_mnt.%d", getpid());
6618 (void) unlink(tmpmnt
);
6620 ret
= mkdirp(tmpmnt
, DIR_PERMS
);
6622 INJECT_ERROR1("MKDIRP_SIGN_MNT", ret
= -1);
6624 bam_error(MKDIR_FAILED
, tmpmnt
, strerror(error
));
6625 free_mnttab(mnttab_hash
);
6627 (void) unlink(UFS_SIGNATURE_LIST
".tmp");
6631 dirp
= opendir("/dev/rdsk");
6633 INJECT_ERROR1("OPENDIR_DEV_RDSK", dirp
= NULL
);
6635 bam_error(OPENDIR_FAILED
, "/dev/rdsk", strerror(error
));
6639 while (dp
= readdir(dirp
)) {
6640 if (strcmp(dp
->d_name
, ".") == 0 ||
6641 strcmp(dp
->d_name
, "..") == 0)
6645 * we only look for the s0 slice. This is guranteed to
6646 * have 's' at len - 2.
6648 len
= strlen(dp
->d_name
);
6649 if (dp
->d_name
[len
- 2 ] != 's' || dp
->d_name
[len
- 1] != '0') {
6650 BAM_DPRINTF((D_SKIP_SLICE_NOTZERO
, fcn
, dp
->d_name
));
6654 ret
= process_slice0(dp
->d_name
, tfp
, mnttab_hash
, tmpmnt
);
6655 INJECT_ERROR1("PROCESS_S0_FAIL", ret
= -1);
6660 (void) closedir(dirp
);
6661 free_mnttab(mnttab_hash
);
6662 (void) rmdir(tmpmnt
);
6666 INJECT_ERROR1("FCLOSE_SIGNLIST_TMP", ret
= EOF
);
6668 bam_error(CLOSE_FAIL
, UFS_SIGNATURE_LIST
".tmp",
6670 (void) unlink(UFS_SIGNATURE_LIST
".tmp");
6674 /* We have a list of existing GRUB signatures. Sort it first */
6675 (void) snprintf(cmd
, sizeof (cmd
),
6676 "/usr/bin/sort -u %s.tmp > %s.sorted",
6677 UFS_SIGNATURE_LIST
, UFS_SIGNATURE_LIST
);
6679 ret
= exec_cmd(cmd
, NULL
);
6680 INJECT_ERROR1("SORT_SIGN_LIST", ret
= 1);
6682 bam_error(GRUBSIGN_SORT_FAILED
);
6683 (void) unlink(UFS_SIGNATURE_LIST
".sorted");
6684 (void) unlink(UFS_SIGNATURE_LIST
".tmp");
6688 (void) unlink(UFS_SIGNATURE_LIST
".tmp");
6690 ret
= rename(UFS_SIGNATURE_LIST
".sorted", UFS_SIGNATURE_LIST
);
6692 INJECT_ERROR1("RENAME_TMP_SIGNLIST", ret
= -1);
6694 bam_error(RENAME_FAIL
, UFS_SIGNATURE_LIST
, strerror(error
));
6695 (void) unlink(UFS_SIGNATURE_LIST
".sorted");
6699 if (stat(UFS_SIGNATURE_LIST
, &sb
) == 0 && sb
.st_size
== 0) {
6700 BAM_DPRINTF((D_ZERO_LEN_SIGNLIST
, fcn
, UFS_SIGNATURE_LIST
));
6703 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
6708 (void) closedir(dirp
);
6709 free_mnttab(mnttab_hash
);
6710 (void) rmdir(tmpmnt
);
6712 (void) unlink(UFS_SIGNATURE_LIST
".tmp");
6713 BAM_DPRINTF((D_RETURN_FAILURE
, fcn
));
6718 create_ufs_sign(void)
6722 char tmpsign
[MAXNAMELEN
+ 1];
6728 const char *fcn
= "create_ufs_sign()";
6730 bam_print(SEARCHING_UFS_SIGN
);
6732 ret
= FindAllUfsSignatures();
6733 INJECT_ERROR1("FIND_ALL_UFS", ret
= -1);
6735 bam_error(ERR_FIND_UFS_SIGN
);
6739 /* Make sure the list exists and is owned by root */
6740 INJECT_ERROR1("SIGNLIST_NOT_CREATED",
6741 (void) unlink(UFS_SIGNATURE_LIST
));
6742 if (stat(UFS_SIGNATURE_LIST
, &sb
) == -1 || sb
.st_uid
!= 0) {
6743 (void) unlink(UFS_SIGNATURE_LIST
);
6744 bam_error(UFS_SIGNATURE_LIST_MISS
, UFS_SIGNATURE_LIST
);
6748 if (sb
.st_size
== 0) {
6749 bam_print(GRUBSIGN_UFS_NONE
);
6754 /* The signature list was sorted when it was created */
6755 tfp
= fopen(UFS_SIGNATURE_LIST
, "r");
6757 INJECT_ERROR1("FOPEN_SIGN_LIST", tfp
= NULL
);
6759 bam_error(UFS_SIGNATURE_LIST_OPENERR
,
6760 UFS_SIGNATURE_LIST
, strerror(error
));
6761 (void) unlink(UFS_SIGNATURE_LIST
);
6765 for (i
= 0; s_fgets(tmpsign
, sizeof (tmpsign
), tfp
); i
++) {
6767 if (strncmp(tmpsign
, GRUBSIGN_UFS_PREFIX
,
6768 strlen(GRUBSIGN_UFS_PREFIX
)) != 0) {
6770 (void) unlink(UFS_SIGNATURE_LIST
);
6771 bam_error(UFS_BADSIGN
, tmpsign
);
6774 numstr
= tmpsign
+ strlen(GRUBSIGN_UFS_PREFIX
);
6776 if (numstr
[0] == '\0' || !isdigit(numstr
[0])) {
6778 (void) unlink(UFS_SIGNATURE_LIST
);
6779 bam_error(UFS_BADSIGN
, tmpsign
);
6783 signnum
= atoi(numstr
);
6784 INJECT_ERROR1("NEGATIVE_SIGN", signnum
= -1);
6787 (void) unlink(UFS_SIGNATURE_LIST
);
6788 bam_error(UFS_BADSIGN
, tmpsign
);
6793 BAM_DPRINTF((D_FOUND_HOLE_SIGNLIST
, fcn
, i
));
6801 (void) snprintf(tmpsign
, sizeof (tmpsign
), "rootfs%d", i
);
6803 /* add the ufs signature to the /var/run list of signatures */
6804 ret
= ufs_add_to_sign_list(tmpsign
);
6805 INJECT_ERROR1("UFS_ADD_TO_SIGN_LIST", ret
= -1);
6807 (void) unlink(UFS_SIGNATURE_LIST
);
6808 bam_error(FAILED_ADD_SIGNLIST
, tmpsign
);
6812 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
6814 return (s_strdup(tmpsign
));
6818 get_fstype(char *osroot
)
6821 struct mnttab mp
= {0};
6822 struct mnttab mpref
= {0};
6825 const char *fcn
= "get_fstype()";
6827 INJECT_ERROR1("GET_FSTYPE_OSROOT", osroot
= NULL
);
6828 if (osroot
== NULL
) {
6829 bam_error(GET_FSTYPE_ARGS
);
6833 mntfp
= fopen(MNTTAB
, "r");
6835 INJECT_ERROR1("GET_FSTYPE_FOPEN", mntfp
= NULL
);
6836 if (mntfp
== NULL
) {
6837 bam_error(OPEN_FAIL
, MNTTAB
, strerror(error
));
6841 if (*osroot
== '\0')
6842 mpref
.mnt_mountp
= "/";
6844 mpref
.mnt_mountp
= osroot
;
6846 ret
= getmntany(mntfp
, &mp
, &mpref
);
6847 INJECT_ERROR1("GET_FSTYPE_GETMNTANY", ret
= 1);
6849 bam_error(MNTTAB_MNTPT_NOT_FOUND
, osroot
, MNTTAB
);
6850 (void) fclose(mntfp
);
6853 (void) fclose(mntfp
);
6855 INJECT_ERROR1("GET_FSTYPE_NULL", mp
.mnt_fstype
= NULL
);
6856 if (mp
.mnt_fstype
== NULL
) {
6857 bam_error(MNTTAB_FSTYPE_NULL
, osroot
);
6861 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
6863 return (s_strdup(mp
.mnt_fstype
));
6867 create_zfs_sign(char *osdev
)
6869 char tmpsign
[PATH_MAX
];
6871 const char *fcn
= "create_zfs_sign()";
6873 BAM_DPRINTF((D_FUNC_ENTRY1
, fcn
, osdev
));
6876 * First find the pool name
6878 pool
= get_pool(osdev
);
6879 INJECT_ERROR1("CREATE_ZFS_SIGN_GET_POOL", pool
= NULL
);
6881 bam_error(GET_POOL_FAILED
, osdev
);
6885 (void) snprintf(tmpsign
, sizeof (tmpsign
), "pool_%s", pool
);
6887 BAM_DPRINTF((D_CREATED_ZFS_SIGN
, fcn
, tmpsign
));
6891 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
6893 return (s_strdup(tmpsign
));
6897 create_new_sign(char *osdev
, char *fstype
)
6900 const char *fcn
= "create_new_sign()";
6902 INJECT_ERROR1("NEW_SIGN_FSTYPE", fstype
= "foofs");
6904 if (strcmp(fstype
, "zfs") == 0) {
6905 BAM_DPRINTF((D_CREATE_NEW_ZFS
, fcn
));
6906 sign
= create_zfs_sign(osdev
);
6907 } else if (strcmp(fstype
, "ufs") == 0) {
6908 BAM_DPRINTF((D_CREATE_NEW_UFS
, fcn
));
6909 sign
= create_ufs_sign();
6911 bam_error(GRUBSIGN_NOTSUP
, fstype
);
6915 BAM_DPRINTF((D_CREATED_NEW_SIGN
, fcn
, sign
? sign
: "<NULL>"));
6920 set_backup_common(char *mntpt
, char *sign
)
6923 char backup
[PATH_MAX
];
6924 char tmpsign
[PATH_MAX
];
6930 const char *fcn
= "set_backup_common()";
6932 (void) snprintf(backup
, sizeof (backup
), "%s%s",
6933 mntpt
, GRUBSIGN_BACKUP
);
6935 /* First read the backup */
6936 bfp
= fopen(backup
, "r");
6938 while (s_fgets(tmpsign
, sizeof (tmpsign
), bfp
)) {
6939 if (strcmp(tmpsign
, sign
) == 0) {
6940 BAM_DPRINTF((D_FOUND_IN_BACKUP
, fcn
, sign
));
6946 BAM_DPRINTF((D_NOT_FOUND_IN_EXIST_BACKUP
, fcn
, sign
));
6948 BAM_DPRINTF((D_BACKUP_NOT_EXIST
, fcn
, backup
));
6952 * Didn't find the correct signature. First create
6953 * the directory if necessary.
6956 /* dirname() modifies its argument so dup it */
6957 backup_dup
= s_strdup(backup
);
6958 bdir
= dirname(backup_dup
);
6961 ret
= stat(bdir
, &sb
);
6962 INJECT_ERROR1("SET_BACKUP_STAT", ret
= -1);
6964 BAM_DPRINTF((D_BACKUP_DIR_NOEXIST
, fcn
, bdir
));
6965 ret
= mkdirp(bdir
, DIR_PERMS
);
6967 INJECT_ERROR1("SET_BACKUP_MKDIRP", ret
= -1);
6969 bam_error(GRUBSIGN_BACKUP_MKDIRERR
,
6970 GRUBSIGN_BACKUP
, strerror(error
));
6978 * Open the backup in append mode to add the correct
6981 bfp
= fopen(backup
, "a");
6983 INJECT_ERROR1("SET_BACKUP_FOPEN_A", bfp
= NULL
);
6985 bam_error(GRUBSIGN_BACKUP_OPENERR
,
6986 GRUBSIGN_BACKUP
, strerror(error
));
6990 (void) snprintf(tmpsign
, sizeof (tmpsign
), "%s\n", sign
);
6992 ret
= fputs(tmpsign
, bfp
);
6994 INJECT_ERROR1("SET_BACKUP_FPUTS", ret
= 0);
6995 if (ret
!= strlen(tmpsign
)) {
6996 bam_error(GRUBSIGN_BACKUP_WRITEERR
,
6997 GRUBSIGN_BACKUP
, strerror(error
));
7005 bam_print(GRUBSIGN_BACKUP_UPDATED
, GRUBSIGN_BACKUP
);
7007 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
7013 set_backup_ufs(char *osroot
, char *sign
)
7015 const char *fcn
= "set_backup_ufs()";
7017 BAM_DPRINTF((D_FUNC_ENTRY2
, fcn
, osroot
, sign
));
7018 return (set_backup_common(osroot
, sign
));
7022 set_backup_zfs(char *osdev
, char *sign
)
7028 const char *fcn
= "set_backup_zfs()";
7030 BAM_DPRINTF((D_FUNC_ENTRY2
, fcn
, osdev
, sign
));
7032 pool
= get_pool(osdev
);
7033 INJECT_ERROR1("SET_BACKUP_GET_POOL", pool
= NULL
);
7035 bam_error(GET_POOL_FAILED
, osdev
);
7039 mntpt
= mount_top_dataset(pool
, &mnted
);
7040 INJECT_ERROR1("SET_BACKUP_MOUNT_DATASET", mntpt
= NULL
);
7041 if (mntpt
== NULL
) {
7042 bam_error(FAIL_MNT_TOP_DATASET
, pool
);
7047 ret
= set_backup_common(mntpt
, sign
);
7049 (void) umount_top_dataset(pool
, mnted
, mntpt
);
7053 INJECT_ERROR1("SET_BACKUP_ZFS_FAIL", ret
= 1);
7055 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
7057 BAM_DPRINTF((D_RETURN_FAILURE
, fcn
));
7064 set_backup(char *osroot
, char *osdev
, char *sign
, char *fstype
)
7066 const char *fcn
= "set_backup()";
7069 INJECT_ERROR1("SET_BACKUP_FSTYPE", fstype
= "foofs");
7071 if (strcmp(fstype
, "ufs") == 0) {
7072 BAM_DPRINTF((D_SET_BACKUP_UFS
, fcn
));
7073 ret
= set_backup_ufs(osroot
, sign
);
7074 } else if (strcmp(fstype
, "zfs") == 0) {
7075 BAM_DPRINTF((D_SET_BACKUP_ZFS
, fcn
));
7076 ret
= set_backup_zfs(osdev
, sign
);
7078 bam_error(GRUBSIGN_NOTSUP
, fstype
);
7083 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
7085 BAM_DPRINTF((D_RETURN_FAILURE
, fcn
));
7092 set_primary_common(char *mntpt
, char *sign
)
7094 char signfile
[PATH_MAX
];
7095 char signdir
[PATH_MAX
];
7100 const char *fcn
= "set_primary_common()";
7102 (void) snprintf(signfile
, sizeof (signfile
), "%s/%s/%s",
7103 mntpt
, GRUBSIGN_DIR
, sign
);
7105 if (stat(signfile
, &sb
) != -1) {
7107 bam_print(PRIMARY_SIGN_EXISTS
, sign
);
7110 BAM_DPRINTF((D_PRIMARY_NOT_EXIST
, fcn
, signfile
));
7113 (void) snprintf(signdir
, sizeof (signdir
), "%s/%s",
7114 mntpt
, GRUBSIGN_DIR
);
7116 if (stat(signdir
, &sb
) == -1) {
7117 BAM_DPRINTF((D_PRIMARY_DIR_NOEXIST
, fcn
, signdir
));
7118 ret
= mkdirp(signdir
, DIR_PERMS
);
7120 INJECT_ERROR1("SET_PRIMARY_MKDIRP", ret
= -1);
7122 bam_error(GRUBSIGN_MKDIR_ERR
, signdir
, strerror(errno
));
7127 fd
= open(signfile
, O_RDWR
|O_CREAT
|O_TRUNC
, 0444);
7129 INJECT_ERROR1("PRIMARY_SIGN_CREAT", fd
= -1);
7131 bam_error(GRUBSIGN_PRIMARY_CREATERR
, signfile
, strerror(error
));
7137 INJECT_ERROR1("PRIMARY_FSYNC", ret
= -1);
7139 bam_error(GRUBSIGN_PRIMARY_SYNCERR
, signfile
, strerror(error
));
7145 bam_print(GRUBSIGN_CREATED_PRIMARY
, signfile
);
7147 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
7153 set_primary_ufs(char *osroot
, char *sign
)
7155 const char *fcn
= "set_primary_ufs()";
7157 BAM_DPRINTF((D_FUNC_ENTRY2
, fcn
, osroot
, sign
));
7158 return (set_primary_common(osroot
, sign
));
7162 set_primary_zfs(char *osdev
, char *sign
)
7168 const char *fcn
= "set_primary_zfs()";
7170 BAM_DPRINTF((D_FUNC_ENTRY2
, fcn
, osdev
, sign
));
7172 pool
= get_pool(osdev
);
7173 INJECT_ERROR1("SET_PRIMARY_ZFS_GET_POOL", pool
= NULL
);
7175 bam_error(GET_POOL_FAILED
, osdev
);
7179 /* Pool name must exist in the sign */
7180 ret
= (strstr(sign
, pool
) != NULL
);
7181 INJECT_ERROR1("SET_PRIMARY_ZFS_POOL_SIGN_INCOMPAT", ret
= 0);
7183 bam_error(POOL_SIGN_INCOMPAT
, pool
, sign
);
7188 mntpt
= mount_top_dataset(pool
, &mnted
);
7189 INJECT_ERROR1("SET_PRIMARY_ZFS_MOUNT_DATASET", mntpt
= NULL
);
7190 if (mntpt
== NULL
) {
7191 bam_error(FAIL_MNT_TOP_DATASET
, pool
);
7196 ret
= set_primary_common(mntpt
, sign
);
7198 (void) umount_top_dataset(pool
, mnted
, mntpt
);
7202 INJECT_ERROR1("SET_PRIMARY_ZFS_FAIL", ret
= 1);
7204 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
7206 BAM_DPRINTF((D_RETURN_FAILURE
, fcn
));
7213 set_primary(char *osroot
, char *osdev
, char *sign
, char *fstype
)
7215 const char *fcn
= "set_primary()";
7218 INJECT_ERROR1("SET_PRIMARY_FSTYPE", fstype
= "foofs");
7219 if (strcmp(fstype
, "ufs") == 0) {
7220 BAM_DPRINTF((D_SET_PRIMARY_UFS
, fcn
));
7221 ret
= set_primary_ufs(osroot
, sign
);
7222 } else if (strcmp(fstype
, "zfs") == 0) {
7223 BAM_DPRINTF((D_SET_PRIMARY_ZFS
, fcn
));
7224 ret
= set_primary_zfs(osdev
, sign
);
7226 bam_error(GRUBSIGN_NOTSUP
, fstype
);
7231 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
7233 BAM_DPRINTF((D_RETURN_FAILURE
, fcn
));
7240 ufs_add_to_sign_list(char *sign
)
7243 char signline
[MAXNAMELEN
];
7247 const char *fcn
= "ufs_add_to_sign_list()";
7249 INJECT_ERROR1("ADD_TO_SIGN_LIST_NOT_UFS", sign
= "pool_rpool5");
7250 if (strncmp(sign
, GRUBSIGN_UFS_PREFIX
,
7251 strlen(GRUBSIGN_UFS_PREFIX
)) != 0) {
7252 bam_error(INVALID_UFS_SIGN
, sign
);
7253 (void) unlink(UFS_SIGNATURE_LIST
);
7258 * most failures in this routine are not a fatal error
7259 * We simply unlink the /var/run file and continue
7262 ret
= rename(UFS_SIGNATURE_LIST
, UFS_SIGNATURE_LIST
".tmp");
7264 INJECT_ERROR1("ADD_TO_SIGN_LIST_RENAME", ret
= -1);
7266 bam_error(RENAME_FAIL
, UFS_SIGNATURE_LIST
".tmp",
7268 (void) unlink(UFS_SIGNATURE_LIST
);
7272 tfp
= fopen(UFS_SIGNATURE_LIST
".tmp", "a");
7274 INJECT_ERROR1("ADD_TO_SIGN_LIST_FOPEN", tfp
= NULL
);
7276 bam_error(OPEN_FAIL
, UFS_SIGNATURE_LIST
".tmp", strerror(error
));
7277 (void) unlink(UFS_SIGNATURE_LIST
".tmp");
7281 (void) snprintf(signline
, sizeof (signline
), "%s\n", sign
);
7283 ret
= fputs(signline
, tfp
);
7285 INJECT_ERROR1("ADD_TO_SIGN_LIST_FPUTS", ret
= 0);
7286 if (ret
!= strlen(signline
)) {
7287 bam_error(SIGN_LIST_FPUTS_ERR
, sign
, strerror(error
));
7289 (void) unlink(UFS_SIGNATURE_LIST
".tmp");
7295 INJECT_ERROR1("ADD_TO_SIGN_LIST_FCLOSE", ret
= EOF
);
7297 bam_error(CLOSE_FAIL
, UFS_SIGNATURE_LIST
".tmp",
7299 (void) unlink(UFS_SIGNATURE_LIST
".tmp");
7303 /* Sort the list again */
7304 (void) snprintf(cmd
, sizeof (cmd
),
7305 "/usr/bin/sort -u %s.tmp > %s.sorted",
7306 UFS_SIGNATURE_LIST
, UFS_SIGNATURE_LIST
);
7308 ret
= exec_cmd(cmd
, NULL
);
7309 INJECT_ERROR1("ADD_TO_SIGN_LIST_SORT", ret
= 1);
7311 bam_error(GRUBSIGN_SORT_FAILED
);
7312 (void) unlink(UFS_SIGNATURE_LIST
".sorted");
7313 (void) unlink(UFS_SIGNATURE_LIST
".tmp");
7317 (void) unlink(UFS_SIGNATURE_LIST
".tmp");
7319 ret
= rename(UFS_SIGNATURE_LIST
".sorted", UFS_SIGNATURE_LIST
);
7321 INJECT_ERROR1("ADD_TO_SIGN_LIST_RENAME2", ret
= -1);
7323 bam_error(RENAME_FAIL
, UFS_SIGNATURE_LIST
, strerror(error
));
7324 (void) unlink(UFS_SIGNATURE_LIST
".sorted");
7328 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
7334 set_signature(char *osroot
, char *osdev
, char *sign
, char *fstype
)
7337 const char *fcn
= "set_signature()";
7339 BAM_DPRINTF((D_FUNC_ENTRY4
, fcn
, osroot
, osdev
, sign
, fstype
));
7341 ret
= set_backup(osroot
, osdev
, sign
, fstype
);
7342 INJECT_ERROR1("SET_SIGNATURE_BACKUP", ret
= -1);
7344 BAM_DPRINTF((D_RETURN_FAILURE
, fcn
));
7345 bam_error(SET_BACKUP_FAILED
, sign
, osroot
, osdev
);
7349 ret
= set_primary(osroot
, osdev
, sign
, fstype
);
7350 INJECT_ERROR1("SET_SIGNATURE_PRIMARY", ret
= -1);
7353 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
7355 BAM_DPRINTF((D_RETURN_FAILURE
, fcn
));
7356 bam_error(SET_PRIMARY_FAILED
, sign
, osroot
, osdev
);
7363 get_grubsign(char *osroot
, char *osdev
)
7365 char *grubsign
; /* (<sign>,#,#) */
7371 const char *fcn
= "get_grubsign()";
7373 BAM_DPRINTF((D_FUNC_ENTRY2
, fcn
, osroot
, osdev
));
7374 fstype
= get_fstype(osroot
);
7375 INJECT_ERROR1("GET_GRUBSIGN_FSTYPE", fstype
= NULL
);
7376 if (fstype
== NULL
) {
7377 bam_error(GET_FSTYPE_FAILED
, osroot
);
7381 sign
= find_existing_sign(osroot
, osdev
, fstype
);
7382 INJECT_ERROR1("FIND_EXISTING_SIGN", sign
= NULL
);
7384 BAM_DPRINTF((D_GET_GRUBSIGN_NO_EXISTING
, fcn
, osroot
, osdev
));
7385 sign
= create_new_sign(osdev
, fstype
);
7386 INJECT_ERROR1("CREATE_NEW_SIGN", sign
= NULL
);
7388 bam_error(GRUBSIGN_CREATE_FAIL
, osdev
);
7394 ret
= set_signature(osroot
, osdev
, sign
, fstype
);
7395 INJECT_ERROR1("SET_SIGNATURE_FAIL", ret
= -1);
7397 bam_error(GRUBSIGN_WRITE_FAIL
, osdev
);
7400 (void) unlink(UFS_SIGNATURE_LIST
);
7407 bam_print(GRUBSIGN_FOUND_OR_CREATED
, sign
, osdev
);
7409 fdiskpart
= get_partition(osdev
);
7410 INJECT_ERROR1("GET_GRUBSIGN_FDISK", fdiskpart
= PARTNO_NOTFOUND
);
7411 if (fdiskpart
== PARTNO_NOTFOUND
) {
7412 bam_error(FDISKPART_FAIL
, osdev
);
7417 slice
= strrchr(osdev
, 's');
7419 if (fdiskpart
== PARTNO_EFI
) {
7420 fdiskpart
= atoi(&slice
[1]);
7424 grubsign
= s_calloc(1, MAXNAMELEN
+ 10);
7426 (void) snprintf(grubsign
, MAXNAMELEN
+ 10, "(%s,%d,%c)",
7427 sign
, fdiskpart
, slice
[1] + 'a' - '0');
7429 (void) snprintf(grubsign
, MAXNAMELEN
+ 10, "(%s,%d)",
7434 BAM_DPRINTF((D_GET_GRUBSIGN_SUCCESS
, fcn
, grubsign
));
7440 get_title(char *rootdir
)
7442 static char title
[80];
7444 char release
[PATH_MAX
];
7446 const char *fcn
= "get_title()";
7448 /* open the /etc/release file */
7449 (void) snprintf(release
, sizeof (release
), "%s/etc/release", rootdir
);
7451 fp
= fopen(release
, "r");
7453 bam_error(OPEN_FAIL
, release
, strerror(errno
));
7458 /* grab first line of /etc/release */
7459 cp
= s_fgets(title
, sizeof (title
), fp
);
7461 while (isspace(*cp
)) /* remove leading spaces */
7468 cp
= cp
? cp
: "Oracle Solaris";
7470 BAM_DPRINTF((D_GET_TITLE
, fcn
, cp
));
7476 get_special(char *mountp
)
7479 struct mnttab mp
= {0};
7480 struct mnttab mpref
= {0};
7483 const char *fcn
= "get_special()";
7485 INJECT_ERROR1("GET_SPECIAL_MNTPT", mountp
= NULL
);
7486 if (mountp
== NULL
) {
7487 bam_error(GET_SPECIAL_NULL_MNTPT
);
7491 mntfp
= fopen(MNTTAB
, "r");
7493 INJECT_ERROR1("GET_SPECIAL_MNTTAB_OPEN", mntfp
= NULL
);
7494 if (mntfp
== NULL
) {
7495 bam_error(OPEN_FAIL
, MNTTAB
, strerror(error
));
7499 if (*mountp
== '\0')
7500 mpref
.mnt_mountp
= "/";
7502 mpref
.mnt_mountp
= mountp
;
7504 ret
= getmntany(mntfp
, &mp
, &mpref
);
7505 INJECT_ERROR1("GET_SPECIAL_MNTTAB_SEARCH", ret
= 1);
7507 (void) fclose(mntfp
);
7508 BAM_DPRINTF((D_GET_SPECIAL_NOT_IN_MNTTAB
, fcn
, mountp
));
7511 (void) fclose(mntfp
);
7513 BAM_DPRINTF((D_GET_SPECIAL
, fcn
, mp
.mnt_special
));
7515 return (s_strdup(mp
.mnt_special
));
7519 free_physarray(char **physarray
, int n
)
7522 const char *fcn
= "free_physarray()";
7527 BAM_DPRINTF((D_FUNC_ENTRY_N1
, fcn
, n
));
7529 for (i
= 0; i
< n
; i
++) {
7534 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
7538 zfs_get_physical(char *special
, char ***physarray
, int *n
)
7540 char sdup
[PATH_MAX
];
7544 filelist_t flist
= {0};
7550 const char *fcn
= "zfs_get_physical()";
7554 BAM_DPRINTF((D_FUNC_ENTRY1
, fcn
, special
));
7556 INJECT_ERROR1("INVALID_ZFS_SPECIAL", special
= "/foo");
7557 if (special
[0] == '/') {
7558 bam_error(INVALID_ZFS_SPECIAL
, special
);
7562 (void) strlcpy(sdup
, special
, sizeof (sdup
));
7564 pool
= strtok(sdup
, "/");
7565 INJECT_ERROR1("ZFS_GET_PHYS_POOL", pool
= NULL
);
7567 bam_error(CANT_FIND_POOL_FROM_SPECIAL
, special
);
7571 (void) snprintf(cmd
, sizeof (cmd
), "/sbin/zpool status %s", pool
);
7573 ret
= exec_cmd(cmd
, &flist
);
7574 INJECT_ERROR1("ZFS_GET_PHYS_STATUS", ret
= 1);
7576 bam_error(ZFS_GET_POOL_STATUS
, pool
);
7580 INJECT_ERROR1("ZFS_GET_PHYS_STATUS_OUT", flist
.head
= NULL
);
7581 if (flist
.head
== NULL
) {
7582 bam_error(BAD_ZPOOL_STATUS
, pool
);
7583 filelist_free(&flist
);
7587 for (lp
= flist
.head
; lp
; lp
= lp
->next
) {
7588 BAM_DPRINTF((D_STRTOK_ZPOOL_STATUS
, fcn
, lp
->line
));
7589 comp1
= strtok(lp
->line
, " \t");
7590 if (comp1
== NULL
) {
7594 comp1
= s_strdup(comp1
);
7600 for (lp
= flist
.head
; lp
; lp
= lp
->next
) {
7601 if (lp
->line
== NULL
)
7603 if (strcmp(lp
->line
, pool
) == 0) {
7604 BAM_DPRINTF((D_FOUND_POOL_IN_ZPOOL_STATUS
, fcn
, pool
));
7610 bam_error(NO_POOL_IN_ZPOOL_STATUS
, pool
);
7611 filelist_free(&flist
);
7616 for (i
= 0, lp
= startlp
; lp
; lp
= lp
->next
) {
7617 if (lp
->line
== NULL
)
7619 if (strcmp(lp
->line
, "mirror") == 0)
7621 if (lp
->line
[0] == '\0' || strcmp(lp
->line
, "errors:") == 0)
7624 BAM_DPRINTF((D_COUNTING_ZFS_PHYS
, fcn
, i
));
7628 bam_error(NO_PHYS_IN_ZPOOL_STATUS
, pool
);
7629 filelist_free(&flist
);
7634 *physarray
= s_calloc(*n
, sizeof (char *));
7635 for (i
= 0, lp
= startlp
; lp
; lp
= lp
->next
) {
7636 if (lp
->line
== NULL
)
7638 if (strcmp(lp
->line
, "mirror") == 0)
7640 if (strcmp(lp
->line
, "errors:") == 0)
7642 if (strncmp(lp
->line
, "/dev/dsk/", strlen("/dev/dsk/")) != 0 &&
7643 strncmp(lp
->line
, "/dev/rdsk/",
7644 strlen("/dev/rdsk/")) != 0) {
7645 (void) snprintf(dsk
, sizeof (dsk
), "/dev/rdsk/%s",
7648 (void) strlcpy(dsk
, lp
->line
, sizeof (dsk
));
7650 BAM_DPRINTF((D_ADDING_ZFS_PHYS
, fcn
, dsk
, pool
));
7651 (*physarray
)[i
++] = s_strdup(dsk
);
7656 filelist_free(&flist
);
7658 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
7663 * Certain services needed to run metastat successfully may not
7664 * be enabled. Enable them now.
7667 * Checks if the specified service is online
7668 * Returns: 1 if the service is online
7669 * 0 if the service is not online
7673 is_svc_online(char *svc
)
7676 const char *fcn
= "is_svc_online()";
7678 BAM_DPRINTF((D_FUNC_ENTRY1
, fcn
, svc
));
7680 state
= smf_get_state(svc
);
7681 INJECT_ERROR2("GET_SVC_STATE", free(state
), state
= NULL
);
7682 if (state
== NULL
) {
7683 bam_error(GET_SVC_STATE_ERR
, svc
);
7686 BAM_DPRINTF((D_GOT_SVC_STATUS
, fcn
, svc
));
7688 if (strcmp(state
, SCF_STATE_STRING_ONLINE
) == 0) {
7689 BAM_DPRINTF((D_SVC_ONLINE
, fcn
, svc
));
7694 BAM_DPRINTF((D_SVC_NOT_ONLINE
, fcn
, state
, svc
));
7702 enable_svc(char *svc
)
7706 const char *fcn
= "enable_svc()";
7708 ret
= is_svc_online(svc
);
7710 bam_error(SVC_IS_ONLINE_FAILED
, svc
);
7712 } else if (ret
== 1) {
7713 BAM_DPRINTF((D_SVC_ALREADY_ONLINE
, fcn
, svc
));
7717 /* Service is not enabled. Enable it now. */
7718 ret
= smf_enable_instance(svc
, 0);
7719 INJECT_ERROR1("ENABLE_SVC_FAILED", ret
= -1);
7721 bam_error(ENABLE_SVC_FAILED
, svc
);
7725 BAM_DPRINTF((D_SVC_ONLINE_INITIATED
, fcn
, svc
));
7729 ret
= is_svc_online(svc
);
7730 INJECT_ERROR1("SVC_ONLINE_SUCCESS", ret
= 1);
7731 INJECT_ERROR1("SVC_ONLINE_FAILURE", ret
= -1);
7732 INJECT_ERROR1("SVC_ONLINE_NOTYET", ret
= 0);
7734 bam_error(ERR_SVC_GET_ONLINE
, svc
);
7736 } else if (ret
== 1) {
7737 BAM_DPRINTF((D_SVC_NOW_ONLINE
, fcn
, svc
));
7741 } while (++sleeptime
< 60);
7743 bam_error(TIMEOUT_ENABLE_SVC
, svc
);
7749 ufs_get_physical(char *special
, char ***physarray
, int *n
)
7753 filelist_t flist
= {0};
7764 const char *fcn
= "ufs_get_physical()";
7768 BAM_DPRINTF((D_FUNC_ENTRY1
, fcn
, special
));
7770 if (strncmp(special
, "/dev/md/", strlen("/dev/md/")) != 0) {
7771 bam_error(UFS_GET_PHYS_NOT_SVM
, special
);
7775 if (strncmp(special
, "/dev/md/dsk/", strlen("/dev/md/dsk/")) == 0) {
7776 shortname
= special
+ strlen("/dev/md/dsk/");
7777 } else if (strncmp(special
, "/dev/md/rdsk/",
7778 strlen("/dev/md/rdsk/")) == 0) {
7779 shortname
= special
+ strlen("/dev/md/rdsk");
7781 bam_error(UFS_GET_PHYS_INVALID_SVM
, special
);
7785 BAM_DPRINTF((D_UFS_SVM_SHORT
, fcn
, special
, shortname
));
7787 svc
= "network/rpc/meta:default";
7788 if (enable_svc(svc
) == -1) {
7789 bam_error(UFS_SVM_METASTAT_SVC_ERR
, svc
);
7792 (void) snprintf(cmd
, sizeof (cmd
), "/sbin/metastat -p %s", shortname
);
7794 ret
= exec_cmd(cmd
, &flist
);
7795 INJECT_ERROR1("UFS_SVM_METASTAT", ret
= 1);
7797 bam_error(UFS_SVM_METASTAT_ERR
, shortname
);
7801 INJECT_ERROR1("UFS_SVM_METASTAT_OUT", flist
.head
= NULL
);
7802 if (flist
.head
== NULL
) {
7803 bam_error(BAD_UFS_SVM_METASTAT
, shortname
);
7804 filelist_free(&flist
);
7809 * Check if not a mirror. We only parse a single metadevice
7812 meta
= strtok(flist
.head
->line
, " \t");
7813 type
= strtok(NULL
, " \t");
7814 if (meta
== NULL
|| type
== NULL
) {
7815 bam_error(ERROR_PARSE_UFS_SVM_METASTAT
, shortname
);
7816 filelist_free(&flist
);
7819 if (strcmp(type
, "-m") != 0) {
7820 comp1
= strtok(NULL
, " \t");
7821 comp2
= strtok(NULL
, " \t");
7822 if (comp1
== NULL
|| comp2
!= NULL
) {
7823 bam_error(INVALID_UFS_SVM_METASTAT
, shortname
);
7824 filelist_free(&flist
);
7827 BAM_DPRINTF((D_UFS_SVM_ONE_COMP
, fcn
, comp1
, shortname
));
7828 *physarray
= s_calloc(1, sizeof (char *));
7829 (*physarray
)[0] = s_strdup(comp1
);
7831 filelist_free(&flist
);
7836 * Okay we have a mirror. Everything after the first line
7839 for (i
= 0, lp
= flist
.head
->next
; lp
; lp
= lp
->next
) {
7840 if (strstr(lp
->line
, "/dev/dsk/") == NULL
&&
7841 strstr(lp
->line
, "/dev/rdsk/") == NULL
) {
7842 bam_error(CANNOT_PARSE_UFS_SVM_METASTAT
, shortname
);
7843 filelist_free(&flist
);
7849 *physarray
= s_calloc(i
, sizeof (char *));
7852 for (i
= 0, lp
= flist
.head
->next
; lp
; lp
= lp
->next
) {
7853 comp1
= strtok(lp
->line
, " \t");
7854 comp2
= strtok(NULL
, " \t");
7855 comp3
= strtok(NULL
, " \t");
7856 comp4
= strtok(NULL
, " \t");
7858 if (comp3
== NULL
|| comp4
== NULL
||
7859 (strncmp(comp4
, "/dev/dsk/", strlen("/dev/dsk/")) != 0 &&
7860 strncmp(comp4
, "/dev/rdsk/", strlen("/dev/rdsk/")) != 0)) {
7861 bam_error(CANNOT_PARSE_UFS_SVM_SUBMIRROR
, shortname
);
7862 filelist_free(&flist
);
7863 free_physarray(*physarray
, *n
);
7867 (*physarray
)[i
++] = s_strdup(comp4
);
7872 filelist_free(&flist
);
7874 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
7879 get_physical(char *menu_root
, char ***physarray
, int *n
)
7883 const char *fcn
= "get_physical()";
7892 BAM_DPRINTF((D_FUNC_ENTRY1
, fcn
, menu_root
));
7894 /* First get the device special file from /etc/mnttab */
7895 special
= get_special(menu_root
);
7896 INJECT_ERROR1("GET_PHYSICAL_SPECIAL", special
= NULL
);
7897 if (special
== NULL
) {
7898 bam_error(GET_SPECIAL_NULL
, menu_root
);
7902 /* If already a physical device nothing to do */
7903 if (strncmp(special
, "/dev/dsk/", strlen("/dev/dsk/")) == 0 ||
7904 strncmp(special
, "/dev/rdsk/", strlen("/dev/rdsk/")) == 0) {
7905 BAM_DPRINTF((D_GET_PHYSICAL_ALREADY
, fcn
, menu_root
, special
));
7906 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
7907 *physarray
= s_calloc(1, sizeof (char *));
7908 (*physarray
)[0] = special
;
7913 if (is_zfs(menu_root
)) {
7914 ret
= zfs_get_physical(special
, physarray
, n
);
7915 } else if (is_ufs(menu_root
)) {
7916 ret
= ufs_get_physical(special
, physarray
, n
);
7918 bam_error(GET_PHYSICAL_NOTSUP_FSTYPE
, menu_root
, special
);
7924 INJECT_ERROR1("GET_PHYSICAL_RET", ret
= -1);
7926 BAM_DPRINTF((D_RETURN_FAILURE
, fcn
));
7930 for (i
= 0; i
< *n
; i
++) {
7931 BAM_DPRINTF((D_GET_PHYSICAL_RET
, fcn
, (*physarray
)[i
]));
7939 is_bootdisk(char *osroot
, char *physical
)
7944 const char *fcn
= "is_bootdisk()";
7949 BAM_DPRINTF((D_FUNC_ENTRY2
, fcn
, osroot
, physical
));
7951 bootp
= strstr(physical
, "p0:boot");
7955 * We just want the BIOS mapping for menu disk.
7956 * Don't pass menu_root to get_grubroot() as the
7957 * check that it is used for is not relevant here.
7958 * The osroot is immaterial as well - it is only used to
7959 * to find create_diskmap script. Everything hinges on
7962 grubroot
= get_grubroot(osroot
, physical
, NULL
);
7964 INJECT_ERROR1("IS_BOOTDISK_GRUBROOT", grubroot
= NULL
);
7965 if (grubroot
== NULL
) {
7967 bam_error(NO_GRUBROOT_FOR_DISK
, physical
);
7970 ret
= grubroot
[3] == '0';
7973 BAM_DPRINTF((D_RETURN_RET
, fcn
, ret
));
7979 * Check if menu is on the boot device
7980 * Return 0 (false) on error
7983 menu_on_bootdisk(char *osroot
, char *menu_root
)
7990 const char *fcn
= "menu_on_bootdisk()";
7992 BAM_DPRINTF((D_FUNC_ENTRY2
, fcn
, osroot
, menu_root
));
7994 ret
= get_physical(menu_root
, &physarray
, &n
);
7995 INJECT_ERROR1("MENU_ON_BOOTDISK_PHYSICAL", ret
= -1);
7997 bam_error(GET_PHYSICAL_MENU_NULL
, menu_root
);
8005 for (i
= 0; i
< n
; i
++) {
8006 assert(strncmp(physarray
[i
], "/dev/dsk/",
8007 strlen("/dev/dsk/")) == 0 ||
8008 strncmp(physarray
[i
], "/dev/rdsk/",
8009 strlen("/dev/rdsk/")) == 0);
8011 BAM_DPRINTF((D_CHECK_ON_BOOTDISK
, fcn
, physarray
[i
]));
8012 if (is_bootdisk(osroot
, physarray
[i
])) {
8014 BAM_DPRINTF((D_IS_ON_BOOTDISK
, fcn
, physarray
[i
]));
8018 free_physarray(physarray
, n
);
8020 INJECT_ERROR1("ON_BOOTDISK_YES", on_bootdisk
= 1);
8021 INJECT_ERROR1("ON_BOOTDISK_NO", on_bootdisk
= 0);
8023 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
8025 BAM_DPRINTF((D_RETURN_FAILURE
, fcn
));
8028 return (on_bootdisk
);
8032 bam_add_line(menu_t
*mp
, entry_t
*entry
, line_t
*prev
, line_t
*lp
)
8034 const char *fcn
= "bam_add_line()";
8041 lp
->next
= prev
->next
;
8043 BAM_DPRINTF((D_ADD_LINE_PREV_NEXT
, fcn
));
8044 prev
->next
->prev
= lp
;
8046 BAM_DPRINTF((D_ADD_LINE_NOT_PREV_NEXT
, fcn
));
8051 if (entry
->end
== prev
) {
8052 BAM_DPRINTF((D_ADD_LINE_LAST_LINE_IN_ENTRY
, fcn
));
8055 if (mp
->end
== prev
) {
8056 assert(lp
->next
== NULL
);
8058 BAM_DPRINTF((D_ADD_LINE_LAST_LINE_IN_MENU
, fcn
));
8063 * look for matching bootadm entry with specified parameters
8064 * Here are the rules (based on existing usage):
8065 * - If title is specified, match on title only
8066 * - Else, match on root/findroot, kernel, and module.
8067 * Note that, if root_opt is non-zero, the absence of
8068 * root line is considered a match.
8084 const char *fcn
= "find_boot_entry()";
8087 *entry_num
= BAM_ERROR
;
8089 /* find matching entry */
8090 for (i
= 0, ent
= mp
->entries
; ent
; i
++, ent
= ent
->next
) {
8093 /* first line of entry must be bootadm comment */
8095 if (lp
->flags
!= BAM_COMMENT
||
8096 strcmp(lp
->arg
, BAM_BOOTADM_HDR
) != 0) {
8100 /* advance to title line */
8103 if (lp
->flags
== BAM_TITLE
&& lp
->arg
&&
8104 strcmp(lp
->arg
, title
) == 0) {
8105 BAM_DPRINTF((D_MATCHED_TITLE
, fcn
, title
));
8108 BAM_DPRINTF((D_NOMATCH_TITLE
, fcn
, title
, lp
->arg
));
8109 continue; /* check title only */
8112 lp
= lp
->next
; /* advance to root line */
8115 } else if (lp
->cmd
!= NULL
&&
8116 strcmp(lp
->cmd
, menu_cmds
[FINDROOT_CMD
]) == 0) {
8117 INJECT_ERROR1("FIND_BOOT_ENTRY_NULL_FINDROOT",
8119 if (findroot
== NULL
) {
8120 BAM_DPRINTF((D_NOMATCH_FINDROOT_NULL
,
8124 /* findroot command found, try match */
8125 if (strcmp(lp
->arg
, findroot
) != 0) {
8126 BAM_DPRINTF((D_NOMATCH_FINDROOT
,
8127 fcn
, findroot
, lp
->arg
));
8130 BAM_DPRINTF((D_MATCHED_FINDROOT
, fcn
, findroot
));
8131 lp
= lp
->next
; /* advance to kernel line */
8132 } else if (lp
->cmd
!= NULL
&&
8133 strcmp(lp
->cmd
, menu_cmds
[ROOT_CMD
]) == 0) {
8134 INJECT_ERROR1("FIND_BOOT_ENTRY_NULL_ROOT", root
= NULL
);
8136 BAM_DPRINTF((D_NOMATCH_ROOT_NULL
,
8140 /* root cmd found, try match */
8141 if (strcmp(lp
->arg
, root
) != 0) {
8142 BAM_DPRINTF((D_NOMATCH_ROOT
,
8143 fcn
, root
, lp
->arg
));
8146 BAM_DPRINTF((D_MATCHED_ROOT
, fcn
, root
));
8147 lp
= lp
->next
; /* advance to kernel line */
8149 INJECT_ERROR1("FIND_BOOT_ENTRY_ROOT_OPT_NO",
8151 INJECT_ERROR1("FIND_BOOT_ENTRY_ROOT_OPT_YES",
8153 /* no root command, see if root is optional */
8154 if (root_opt
== 0) {
8155 BAM_DPRINTF((D_NO_ROOT_OPT
, fcn
));
8158 BAM_DPRINTF((D_ROOT_OPT
, fcn
));
8161 if (lp
== NULL
|| lp
->next
== NULL
) {
8166 (!check_cmd(lp
->cmd
, KERNEL_CMD
, lp
->arg
, kernel
))) {
8167 if (!(ent
->flags
& BAM_ENTRY_FAILSAFE
) ||
8168 !(ent
->flags
& BAM_ENTRY_DBOOT
) ||
8169 strcmp(kernel
, DIRECT_BOOT_FAILSAFE_LINE
) != 0)
8172 ent
->flags
|= BAM_ENTRY_UPGFSKERNEL
;
8175 BAM_DPRINTF((D_KERNEL_MATCH
, fcn
, kernel
, lp
->arg
));
8178 * Check for matching module entry (failsafe or normal).
8179 * If it fails to match, we go around the loop again.
8180 * For xpv entries, there are two module lines, so we
8181 * do the check twice.
8183 lp
= lp
->next
; /* advance to module line */
8184 if (check_cmd(lp
->cmd
, MODULE_CMD
, lp
->arg
, module
) ||
8185 (((lp
= lp
->next
) != NULL
) &&
8186 check_cmd(lp
->cmd
, MODULE_CMD
, lp
->arg
, module
))) {
8188 BAM_DPRINTF((D_MODULE_MATCH
, fcn
, module
, lp
->arg
));
8192 if (strcmp(module
, FAILSAFE_ARCHIVE
) == 0 &&
8193 (strcmp(lp
->prev
->arg
, FAILSAFE_ARCHIVE_32
) == 0 ||
8194 strcmp(lp
->prev
->arg
, FAILSAFE_ARCHIVE_64
) == 0)) {
8195 ent
->flags
|= BAM_ENTRY_UPGFSMODULE
;
8201 if (ent
&& entry_num
) {
8206 BAM_DPRINTF((D_RETURN_RET
, fcn
, i
));
8208 BAM_DPRINTF((D_RETURN_RET
, fcn
, BAM_ERROR
));
8214 update_boot_entry(menu_t
*mp
, char *title
, char *findroot
, char *root
,
8215 char *kernel
, char *mod_kernel
, char *module
, int root_opt
)
8218 int change_kernel
= 0;
8222 char linebuf
[BAM_MAXLINE
];
8223 const char *fcn
= "update_boot_entry()";
8225 /* note: don't match on title, it's updated on upgrade */
8226 ent
= find_boot_entry(mp
, NULL
, kernel
, findroot
, root
, module
,
8228 if ((ent
== NULL
) && (bam_direct
== BAM_DIRECT_DBOOT
)) {
8230 * We may be upgrading a kernel from multiboot to
8231 * directboot. Look for a multiboot entry. A multiboot
8232 * entry will not have a findroot line.
8234 ent
= find_boot_entry(mp
, NULL
, "multiboot", NULL
, root
,
8235 MULTIBOOT_ARCHIVE
, root_opt
, &i
);
8237 BAM_DPRINTF((D_UPGRADE_FROM_MULTIBOOT
, fcn
, root
));
8241 BAM_DPRINTF((D_FOUND_FINDROOT
, fcn
, findroot
));
8245 BAM_DPRINTF((D_ENTRY_NOT_FOUND_CREATING
, fcn
, findroot
));
8246 return (add_boot_entry(mp
, title
, findroot
,
8247 kernel
, mod_kernel
, module
, NULL
));
8250 /* replace title of existing entry and update findroot line */
8252 lp
= lp
->next
; /* title line */
8253 (void) snprintf(linebuf
, sizeof (linebuf
), "%s%s%s",
8254 menu_cmds
[TITLE_CMD
], menu_cmds
[SEP_CMD
], title
);
8257 lp
->arg
= s_strdup(title
);
8258 lp
->line
= s_strdup(linebuf
);
8259 BAM_DPRINTF((D_CHANGING_TITLE
, fcn
, title
));
8261 tlp
= lp
; /* title line */
8262 lp
= lp
->next
; /* root line */
8264 /* if no root or findroot command, create a new line_t */
8265 if ((lp
->cmd
!= NULL
) && (strcmp(lp
->cmd
, menu_cmds
[ROOT_CMD
]) != 0 &&
8266 strcmp(lp
->cmd
, menu_cmds
[FINDROOT_CMD
]) != 0)) {
8267 lp
= s_calloc(1, sizeof (line_t
));
8268 bam_add_line(mp
, ent
, tlp
, lp
);
8270 if (lp
->cmd
!= NULL
)
8278 lp
->cmd
= s_strdup(menu_cmds
[FINDROOT_CMD
]);
8279 lp
->sep
= s_strdup(menu_cmds
[SEP_CMD
]);
8280 lp
->arg
= s_strdup(findroot
);
8281 (void) snprintf(linebuf
, sizeof (linebuf
), "%s%s%s",
8282 menu_cmds
[FINDROOT_CMD
], menu_cmds
[SEP_CMD
], findroot
);
8283 lp
->line
= s_strdup(linebuf
);
8284 BAM_DPRINTF((D_ADDING_FINDROOT_LINE
, fcn
, findroot
));
8289 if (ent
->flags
& BAM_ENTRY_UPGFSKERNEL
) {
8290 char *params
= NULL
;
8292 params
= strstr(lp
->line
, "-s");
8294 (void) snprintf(linebuf
, sizeof (linebuf
), "%s%s%s%s",
8295 menu_cmds
[KERNEL_DOLLAR_CMD
], menu_cmds
[SEP_CMD
],
8298 (void) snprintf(linebuf
, sizeof (linebuf
), "%s%s%s",
8299 menu_cmds
[KERNEL_DOLLAR_CMD
], menu_cmds
[SEP_CMD
],
8302 if (lp
->cmd
!= NULL
)
8307 lp
->cmd
= s_strdup(menu_cmds
[KERNEL_DOLLAR_CMD
]);
8308 lp
->arg
= s_strdup(strstr(linebuf
, "/"));
8309 lp
->line
= s_strdup(linebuf
);
8310 ent
->flags
&= ~BAM_ENTRY_UPGFSKERNEL
;
8311 BAM_DPRINTF((D_ADDING_KERNEL_DOLLAR
, fcn
, lp
->prev
->cmd
));
8314 if (change_kernel
) {
8316 * We're upgrading from multiboot to directboot.
8318 if (lp
->cmd
!= NULL
&&
8319 strcmp(lp
->cmd
, menu_cmds
[KERNEL_CMD
]) == 0) {
8320 (void) snprintf(linebuf
, sizeof (linebuf
), "%s%s%s",
8321 menu_cmds
[KERNEL_DOLLAR_CMD
], menu_cmds
[SEP_CMD
],
8326 lp
->cmd
= s_strdup(menu_cmds
[KERNEL_DOLLAR_CMD
]);
8327 lp
->arg
= s_strdup(kernel
);
8328 lp
->line
= s_strdup(linebuf
);
8330 BAM_DPRINTF((D_ADDING_KERNEL_DOLLAR
, fcn
, kernel
));
8332 if (lp
->cmd
!= NULL
&&
8333 strcmp(lp
->cmd
, menu_cmds
[MODULE_CMD
]) == 0) {
8334 (void) snprintf(linebuf
, sizeof (linebuf
), "%s%s%s",
8335 menu_cmds
[MODULE_DOLLAR_CMD
], menu_cmds
[SEP_CMD
],
8340 lp
->cmd
= s_strdup(menu_cmds
[MODULE_DOLLAR_CMD
]);
8341 lp
->arg
= s_strdup(module
);
8342 lp
->line
= s_strdup(linebuf
);
8344 BAM_DPRINTF((D_ADDING_MODULE_DOLLAR
, fcn
, module
));
8351 if (ent
->flags
& BAM_ENTRY_UPGFSMODULE
) {
8352 if (lp
->cmd
!= NULL
&&
8353 strcmp(lp
->cmd
, menu_cmds
[MODULE_CMD
]) == 0) {
8354 (void) snprintf(linebuf
, sizeof (linebuf
), "%s%s%s",
8355 menu_cmds
[MODULE_DOLLAR_CMD
], menu_cmds
[SEP_CMD
],
8360 lp
->cmd
= s_strdup(menu_cmds
[MODULE_DOLLAR_CMD
]);
8361 lp
->arg
= s_strdup(module
);
8362 lp
->line
= s_strdup(linebuf
);
8364 ent
->flags
&= ~BAM_ENTRY_UPGFSMODULE
;
8365 BAM_DPRINTF((D_ADDING_MODULE_DOLLAR
, fcn
, module
));
8369 BAM_DPRINTF((D_RETURN_RET
, fcn
, i
));
8374 root_optional(char *osroot
, char *menu_root
)
8382 const char *fcn
= "root_optional()";
8384 BAM_DPRINTF((D_FUNC_ENTRY2
, fcn
, osroot
, menu_root
));
8387 * For all filesystems except ZFS, a straight compare of osroot
8388 * and menu_root will tell us if root is optional.
8389 * For ZFS, the situation is complicated by the fact that
8390 * menu_root and osroot are always different
8392 ret1
= is_zfs(osroot
);
8393 ret2
= is_zfs(menu_root
);
8394 INJECT_ERROR1("ROOT_OPT_NOT_ZFS", ret1
= 0);
8395 if (!ret1
|| !ret2
) {
8396 BAM_DPRINTF((D_ROOT_OPT_NOT_ZFS
, fcn
, osroot
, menu_root
));
8397 root_opt
= (strcmp(osroot
, menu_root
) == 0);
8401 ospecial
= get_special(osroot
);
8402 INJECT_ERROR1("ROOT_OPTIONAL_OSPECIAL", ospecial
= NULL
);
8403 if (ospecial
== NULL
) {
8404 bam_error(GET_OSROOT_SPECIAL_ERR
, osroot
);
8407 BAM_DPRINTF((D_ROOT_OPTIONAL_OSPECIAL
, fcn
, ospecial
, osroot
));
8409 mspecial
= get_special(menu_root
);
8410 INJECT_ERROR1("ROOT_OPTIONAL_MSPECIAL", mspecial
= NULL
);
8411 if (mspecial
== NULL
) {
8412 bam_error(GET_MENU_ROOT_SPECIAL_ERR
, menu_root
);
8416 BAM_DPRINTF((D_ROOT_OPTIONAL_MSPECIAL
, fcn
, mspecial
, menu_root
));
8418 slash
= strchr(ospecial
, '/');
8421 BAM_DPRINTF((D_ROOT_OPTIONAL_FIXED_OSPECIAL
, fcn
, ospecial
, osroot
));
8423 root_opt
= (strcmp(ospecial
, mspecial
) == 0);
8429 INJECT_ERROR1("ROOT_OPTIONAL_NO", root_opt
= 0);
8430 INJECT_ERROR1("ROOT_OPTIONAL_YES", root_opt
= 1);
8432 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
8434 BAM_DPRINTF((D_RETURN_FAILURE
, fcn
));
8442 update_entry(menu_t
*mp
, char *menu_root
, char *osdev
)
8448 char osroot
[PATH_MAX
];
8449 char *failsafe_kernel
= NULL
;
8452 char failsafe_64
[256];
8454 const char *fcn
= "update_entry()";
8461 BAM_DPRINTF((D_FUNC_ENTRY3
, fcn
, menu_root
, osdev
, bam_root
));
8463 (void) strlcpy(osroot
, bam_root
, sizeof (osroot
));
8465 title
= get_title(osroot
);
8468 grubsign
= get_grubsign(osroot
, osdev
);
8469 INJECT_ERROR1("GET_GRUBSIGN_FAIL", grubsign
= NULL
);
8470 if (grubsign
== NULL
) {
8471 bam_error(GET_GRUBSIGN_ERROR
, osroot
, osdev
);
8476 * It is not a fatal error if get_grubroot() fails
8477 * We no longer rely on biosdev to populate the
8480 grubroot
= get_grubroot(osroot
, osdev
, menu_root
);
8481 INJECT_ERROR1("GET_GRUBROOT_FAIL", grubroot
= NULL
);
8483 BAM_DPRINTF((D_GET_GRUBROOT_SUCCESS
,
8484 fcn
, osroot
, osdev
, menu_root
));
8486 BAM_DPRINTF((D_GET_GRUBROOT_FAILURE
,
8487 fcn
, osroot
, osdev
, menu_root
));
8490 /* add the entry for normal Solaris */
8491 INJECT_ERROR1("UPDATE_ENTRY_MULTIBOOT",
8492 bam_direct
= BAM_DIRECT_MULTIBOOT
);
8493 if (bam_direct
== BAM_DIRECT_DBOOT
) {
8494 entry
= update_boot_entry(mp
, title
, grubsign
, grubroot
,
8495 (bam_zfs
? DIRECT_BOOT_KERNEL_ZFS
: DIRECT_BOOT_KERNEL
),
8496 NULL
, DIRECT_BOOT_ARCHIVE
,
8497 root_optional(osroot
, menu_root
));
8498 BAM_DPRINTF((D_UPDATED_BOOT_ENTRY
, fcn
, bam_zfs
, grubsign
));
8499 if ((entry
!= BAM_ERROR
) && (bam_is_hv
== BAM_HV_PRESENT
)) {
8500 (void) update_boot_entry(mp
, NEW_HV_ENTRY
, grubsign
,
8501 grubroot
, XEN_MENU
, bam_zfs
?
8502 XEN_KERNEL_MODULE_LINE_ZFS
: XEN_KERNEL_MODULE_LINE
,
8503 DIRECT_BOOT_ARCHIVE
,
8504 root_optional(osroot
, menu_root
));
8505 BAM_DPRINTF((D_UPDATED_HV_ENTRY
,
8506 fcn
, bam_zfs
, grubsign
));
8509 entry
= update_boot_entry(mp
, title
, grubsign
, grubroot
,
8510 MULTI_BOOT
, NULL
, MULTIBOOT_ARCHIVE
,
8511 root_optional(osroot
, menu_root
));
8513 BAM_DPRINTF((D_UPDATED_MULTIBOOT_ENTRY
, fcn
, grubsign
));
8517 * Add the entry for failsafe archive. On a bfu'd system, the
8518 * failsafe may be different than the installed kernel.
8520 (void) snprintf(failsafe
, sizeof (failsafe
), "%s%s",
8521 osroot
, FAILSAFE_ARCHIVE_32
);
8522 (void) snprintf(failsafe_64
, sizeof (failsafe_64
), "%s%s",
8523 osroot
, FAILSAFE_ARCHIVE_64
);
8526 * Check if at least one of the two archives exists
8527 * Using $ISADIR as the default line, we have an entry which works
8528 * for both the cases.
8531 if (stat(failsafe
, &sbuf
) == 0 || stat(failsafe_64
, &sbuf
) == 0) {
8533 /* Figure out where the kernel line should point */
8534 (void) snprintf(failsafe
, sizeof (failsafe
), "%s%s", osroot
,
8535 DIRECT_BOOT_FAILSAFE_32
);
8536 (void) snprintf(failsafe_64
, sizeof (failsafe_64
), "%s%s",
8537 osroot
, DIRECT_BOOT_FAILSAFE_64
);
8538 if (stat(failsafe
, &sbuf
) == 0 ||
8539 stat(failsafe_64
, &sbuf
) == 0) {
8540 failsafe_kernel
= DIRECT_BOOT_FAILSAFE_LINE
;
8542 (void) snprintf(failsafe
, sizeof (failsafe
), "%s%s",
8543 osroot
, MULTI_BOOT_FAILSAFE
);
8544 if (stat(failsafe
, &sbuf
) == 0) {
8545 failsafe_kernel
= MULTI_BOOT_FAILSAFE_LINE
;
8548 if (failsafe_kernel
!= NULL
) {
8549 (void) update_boot_entry(mp
, FAILSAFE_TITLE
, grubsign
,
8550 grubroot
, failsafe_kernel
, NULL
, FAILSAFE_ARCHIVE
,
8551 root_optional(osroot
, menu_root
));
8552 BAM_DPRINTF((D_UPDATED_FAILSAFE_ENTRY
, fcn
,
8558 INJECT_ERROR1("UPDATE_ENTRY_ERROR", entry
= BAM_ERROR
);
8559 if (entry
== BAM_ERROR
) {
8560 bam_error(FAILED_TO_ADD_BOOT_ENTRY
, title
, grubsign
);
8566 update_numbering(mp
);
8567 ret
= set_global(mp
, menu_cmds
[DEFAULT_CMD
], entry
);
8568 INJECT_ERROR1("SET_DEFAULT_ERROR", ret
= BAM_ERROR
);
8569 if (ret
== BAM_ERROR
) {
8570 bam_error(SET_DEFAULT_FAILED
, entry
);
8572 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
8577 save_default_entry(menu_t
*mp
, const char *which
)
8581 int entry
= 0; /* default is 0 */
8582 char linebuf
[BAM_MAXLINE
];
8583 line_t
*lp
= mp
->curdefault
;
8584 const char *fcn
= "save_default_entry()";
8587 lineNum
= mp
->end
->lineNum
;
8588 entryNum
= mp
->end
->entryNum
;
8590 lineNum
= LINE_INIT
;
8591 entryNum
= ENTRY_INIT
;
8595 entry
= s_strtol(lp
->arg
);
8597 (void) snprintf(linebuf
, sizeof (linebuf
), "#%s%d", which
, entry
);
8598 BAM_DPRINTF((D_SAVING_DEFAULT_TO
, fcn
, linebuf
));
8599 line_parser(mp
, linebuf
, &lineNum
, &entryNum
);
8600 BAM_DPRINTF((D_SAVED_DEFAULT_TO
, fcn
, lineNum
, entryNum
));
8604 restore_default_entry(menu_t
*mp
, const char *which
, line_t
*lp
)
8608 const char *fcn
= "restore_default_entry()";
8611 BAM_DPRINTF((D_RESTORE_DEFAULT_NULL
, fcn
));
8612 return; /* nothing to restore */
8615 BAM_DPRINTF((D_RESTORE_DEFAULT_STR
, fcn
, which
));
8617 str
= lp
->arg
+ strlen(which
);
8618 entry
= s_strtol(str
);
8619 (void) set_global(mp
, menu_cmds
[DEFAULT_CMD
], entry
);
8621 BAM_DPRINTF((D_RESTORED_DEFAULT_TO
, fcn
, entry
));
8623 /* delete saved old default line */
8624 unlink_line(mp
, lp
);
8629 * This function is for supporting reboot with args.
8630 * The opt value can be:
8631 * NULL delete temp entry, if present
8632 * entry=<n> switches default entry to <n>
8633 * else treated as boot-args and setup a temperary menu entry
8634 * and make it the default
8635 * Note that we are always rebooting the current OS instance
8636 * so osroot == / always.
8638 #define REBOOT_TITLE "Solaris_reboot_transient"
8642 update_temp(menu_t
*mp
, char *dummy
, char *opt
)
8650 char kernbuf
[BUFSIZ
];
8651 char args_buf
[BUFSIZ
];
8652 char signbuf
[PATH_MAX
];
8654 const char *fcn
= "update_temp()";
8657 assert(dummy
== NULL
);
8659 /* opt can be NULL */
8660 BAM_DPRINTF((D_FUNC_ENTRY1
, fcn
, opt
? opt
: "<NULL>"));
8661 BAM_DPRINTF((D_BAM_ROOT
, fcn
, bam_alt_root
, bam_root
));
8663 if (bam_alt_root
|| bam_rootlen
!= 1 ||
8664 strcmp(bam_root
, "/") != 0 ||
8665 strcmp(rootbuf
, "/") != 0) {
8666 bam_error(ALT_ROOT_INVALID
, bam_root
);
8670 /* If no option, delete exiting reboot menu entry */
8673 BAM_DPRINTF((D_OPT_NULL
, fcn
));
8674 ent
= find_boot_entry(mp
, REBOOT_TITLE
, NULL
, NULL
,
8675 NULL
, NULL
, 0, &entry
);
8676 if (ent
== NULL
) { /* not found is ok */
8677 BAM_DPRINTF((D_TRANSIENT_NOTFOUND
, fcn
));
8678 return (BAM_SUCCESS
);
8680 (void) delete_boot_entry(mp
, entry
, DBE_PRINTERR
);
8681 restore_default_entry(mp
, BAM_OLDDEF
, mp
->olddefault
);
8682 mp
->olddefault
= NULL
;
8683 BAM_DPRINTF((D_RESTORED_DEFAULT
, fcn
));
8684 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
8688 /* if entry= is specified, set the default entry */
8689 if (strncmp(opt
, "entry=", strlen("entry=")) == 0) {
8690 int entryNum
= s_strtol(opt
+ strlen("entry="));
8691 BAM_DPRINTF((D_ENTRY_EQUALS
, fcn
, opt
));
8692 if (selector(mp
, opt
, &entry
, NULL
) == BAM_SUCCESS
) {
8693 /* this is entry=# option */
8694 ret
= set_global(mp
, menu_cmds
[DEFAULT_CMD
], entry
);
8695 BAM_DPRINTF((D_ENTRY_SET_IS
, fcn
, entry
, ret
));
8698 bam_error(SET_DEFAULT_FAILED
, entryNum
);
8704 * add a new menu entry based on opt and make it the default
8707 fstype
= get_fstype("/");
8708 INJECT_ERROR1("REBOOT_FSTYPE_NULL", fstype
= NULL
);
8709 if (fstype
== NULL
) {
8710 bam_error(REBOOT_FSTYPE_FAILED
);
8714 osdev
= get_special("/");
8715 INJECT_ERROR1("REBOOT_SPECIAL_NULL", osdev
= NULL
);
8716 if (osdev
== NULL
) {
8718 bam_error(REBOOT_SPECIAL_FAILED
);
8722 sign
= find_existing_sign("/", osdev
, fstype
);
8723 INJECT_ERROR1("REBOOT_SIGN_NULL", sign
= NULL
);
8727 bam_error(REBOOT_SIGN_FAILED
);
8732 (void) strlcpy(signbuf
, sign
, sizeof (signbuf
));
8735 assert(strchr(signbuf
, '(') == NULL
&& strchr(signbuf
, ',') == NULL
&&
8736 strchr(signbuf
, ')') == NULL
);
8739 * There is no alternate root while doing reboot with args
8740 * This version of bootadm is only delivered with a DBOOT
8741 * version of Solaris.
8743 INJECT_ERROR1("REBOOT_NOT_DBOOT", bam_direct
= BAM_DIRECT_MULTIBOOT
);
8744 if (bam_direct
!= BAM_DIRECT_DBOOT
) {
8746 bam_error(REBOOT_DIRECT_FAILED
);
8750 /* add an entry for Solaris reboot */
8751 if (opt
[0] == '-') {
8752 /* It's an option - first see if boot-file is set */
8753 ret
= get_kernel(mp
, KERNEL_CMD
, kernbuf
, sizeof (kernbuf
));
8754 INJECT_ERROR1("REBOOT_GET_KERNEL", ret
= BAM_ERROR
);
8755 if (ret
!= BAM_SUCCESS
) {
8757 bam_error(REBOOT_GET_KERNEL_FAILED
);
8760 if (kernbuf
[0] == '\0')
8761 (void) strlcpy(kernbuf
, DIRECT_BOOT_KERNEL
,
8764 * If this is a zfs file system and kernbuf does not
8765 * have "-B $ZFS-BOOTFS" string yet, add it.
8767 if (strcmp(fstype
, "zfs") == 0 && !strstr(kernbuf
, ZFS_BOOT
)) {
8768 (void) strlcat(kernbuf
, " ", sizeof (kernbuf
));
8769 (void) strlcat(kernbuf
, ZFS_BOOT
, sizeof (kernbuf
));
8771 (void) strlcat(kernbuf
, " ", sizeof (kernbuf
));
8772 (void) strlcat(kernbuf
, opt
, sizeof (kernbuf
));
8773 BAM_DPRINTF((D_REBOOT_OPTION
, fcn
, kernbuf
));
8774 } else if (opt
[0] == '/') {
8775 /* It's a full path, so write it out. */
8776 (void) strlcpy(kernbuf
, opt
, sizeof (kernbuf
));
8781 * # eeprom boot-args='-kd'
8782 * # reboot /platform/i86pc/kernel/unix
8784 * we want to use the boot-args as part of the boot
8785 * line. On the other hand, if someone runs:
8787 * # reboot "/platform/i86pc/kernel/unix -kd"
8789 * we don't need to mess with boot-args. If there's
8790 * no space in the options string, assume we're in the
8793 if (strchr(opt
, ' ') == NULL
) {
8794 ret
= get_kernel(mp
, ARGS_CMD
, args_buf
,
8796 INJECT_ERROR1("REBOOT_GET_ARGS", ret
= BAM_ERROR
);
8797 if (ret
!= BAM_SUCCESS
) {
8799 bam_error(REBOOT_GET_ARGS_FAILED
);
8803 if (args_buf
[0] != '\0') {
8804 (void) strlcat(kernbuf
, " ", sizeof (kernbuf
));
8805 (void) strlcat(kernbuf
, args_buf
,
8809 BAM_DPRINTF((D_REBOOT_ABSPATH
, fcn
, kernbuf
));
8812 * It may be a partial path, or it may be a partial
8813 * path followed by options. Assume that only options
8814 * follow a space. If someone sends us a kernel path
8815 * that includes a space, they deserve to be broken.
8817 opt_ptr
= strchr(opt
, ' ');
8818 if (opt_ptr
!= NULL
) {
8822 path
= expand_path(opt
);
8824 (void) strlcpy(kernbuf
, path
, sizeof (kernbuf
));
8828 * If there were options given, use those.
8829 * Otherwise, copy over the default options.
8831 if (opt_ptr
!= NULL
) {
8832 /* Restore the space in opt string */
8834 (void) strlcat(kernbuf
, opt_ptr
,
8837 ret
= get_kernel(mp
, ARGS_CMD
, args_buf
,
8839 INJECT_ERROR1("UPDATE_TEMP_PARTIAL_ARGS",
8841 if (ret
!= BAM_SUCCESS
) {
8843 bam_error(REBOOT_GET_ARGS_FAILED
);
8847 if (args_buf
[0] != '\0') {
8848 (void) strlcat(kernbuf
, " ",
8850 (void) strlcat(kernbuf
,
8851 args_buf
, sizeof (kernbuf
));
8854 BAM_DPRINTF((D_REBOOT_RESOLVED_PARTIAL
, fcn
, kernbuf
));
8857 bam_error(UNKNOWN_KERNEL
, opt
);
8858 bam_print_stderr(UNKNOWN_KERNEL_REBOOT
);
8863 entry
= add_boot_entry(mp
, REBOOT_TITLE
, signbuf
, kernbuf
,
8865 INJECT_ERROR1("REBOOT_ADD_BOOT_ENTRY", entry
= BAM_ERROR
);
8866 if (entry
== BAM_ERROR
) {
8867 bam_error(REBOOT_WITH_ARGS_ADD_ENTRY_FAILED
);
8871 save_default_entry(mp
, BAM_OLDDEF
);
8872 ret
= set_global(mp
, menu_cmds
[DEFAULT_CMD
], entry
);
8873 INJECT_ERROR1("REBOOT_SET_GLOBAL", ret
= BAM_ERROR
);
8874 if (ret
== BAM_ERROR
) {
8875 bam_error(REBOOT_SET_DEFAULT_FAILED
, entry
);
8877 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
8882 set_global(menu_t
*mp
, char *globalcmd
, int val
)
8889 char prefix
[BAM_MAXLINE
];
8891 const char *fcn
= "set_global()";
8896 if (strcmp(globalcmd
, menu_cmds
[DEFAULT_CMD
]) == 0) {
8897 INJECT_ERROR1("SET_GLOBAL_VAL_NEG", val
= -1);
8898 INJECT_ERROR1("SET_GLOBAL_MENU_EMPTY", mp
->end
= NULL
);
8899 INJECT_ERROR1("SET_GLOBAL_VAL_TOO_BIG", val
= 100);
8900 if (val
< 0 || mp
->end
== NULL
|| val
> mp
->end
->entryNum
) {
8901 (void) snprintf(prefix
, sizeof (prefix
), "%d", val
);
8902 bam_error(INVALID_ENTRY
, prefix
);
8907 found
= last
= NULL
;
8908 for (lp
= mp
->start
; lp
; lp
= lp
->next
) {
8909 if (lp
->flags
!= BAM_GLOBAL
)
8912 last
= lp
; /* track the last global found */
8914 INJECT_ERROR1("SET_GLOBAL_NULL_CMD", lp
->cmd
= NULL
);
8915 if (lp
->cmd
== NULL
) {
8916 bam_error(NO_CMD
, lp
->lineNum
);
8919 if (strcmp(globalcmd
, lp
->cmd
) != 0)
8922 BAM_DPRINTF((D_FOUND_GLOBAL
, fcn
, globalcmd
));
8925 bam_error(DUP_CMD
, globalcmd
, lp
->lineNum
, bam_root
);
8930 if (found
== NULL
) {
8931 lp
= s_calloc(1, sizeof (line_t
));
8933 lp
->next
= mp
->start
;
8935 mp
->end
= (mp
->end
) ? mp
->end
: lp
;
8937 lp
->next
= last
->next
;
8939 if (lp
->next
== NULL
)
8942 lp
->flags
= BAM_GLOBAL
; /* other fields not needed for writes */
8943 len
= strlen(globalcmd
) + strlen(menu_cmds
[SEP_CMD
]);
8944 len
+= 10; /* val < 10 digits */
8945 lp
->line
= s_calloc(1, len
);
8946 (void) snprintf(lp
->line
, len
, "%s%s%d",
8947 globalcmd
, menu_cmds
[SEP_CMD
], val
);
8948 BAM_DPRINTF((D_SET_GLOBAL_WROTE_NEW
, fcn
, lp
->line
));
8949 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
8954 * We are changing an existing entry. Retain any prefix whitespace,
8955 * but overwrite everything else. This preserves tabs added for
8960 while (*str
== ' ' || *str
== '\t')
8962 *cp
= '\0'; /* Terminate prefix */
8963 len
= strlen(prefix
) + strlen(globalcmd
);
8964 len
+= strlen(menu_cmds
[SEP_CMD
]) + 10;
8967 found
->line
= s_calloc(1, len
);
8968 (void) snprintf(found
->line
, len
,
8969 "%s%s%s%d", prefix
, globalcmd
, menu_cmds
[SEP_CMD
], val
);
8971 BAM_DPRINTF((D_SET_GLOBAL_REPLACED
, fcn
, found
->line
));
8972 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
8973 return (BAM_WRITE
); /* need a write to menu */
8977 * partial_path may be anything like "kernel/unix" or "kmdb". Try to
8978 * expand it to a full unix path. The calling function is expected to
8979 * output a message if an error occurs and NULL is returned.
8982 expand_path(const char *partial_path
)
8986 char new_path2
[PATH_MAX
];
8988 const char *fcn
= "expand_path()";
8990 new_path_len
= strlen(partial_path
) + 64;
8991 new_path
= s_calloc(1, new_path_len
);
8993 /* First, try the simplest case - something like "kernel/unix" */
8994 (void) snprintf(new_path
, new_path_len
, "/platform/i86pc/%s",
8996 if (stat(new_path
, &sb
) == 0) {
8997 BAM_DPRINTF((D_EXPAND_PATH
, fcn
, new_path
));
9001 if (strcmp(partial_path
, "kmdb") == 0) {
9002 (void) snprintf(new_path
, new_path_len
, "%s -k",
9003 DIRECT_BOOT_KERNEL
);
9004 BAM_DPRINTF((D_EXPAND_PATH
, fcn
, new_path
));
9009 * We've quickly reached unsupported usage. Try once more to
9010 * see if we were just given a glom name.
9012 (void) snprintf(new_path
, new_path_len
, "/platform/i86pc/%s/unix",
9014 (void) snprintf(new_path2
, PATH_MAX
, "/platform/i86pc/%s/amd64/unix",
9016 if (stat(new_path
, &sb
) == 0) {
9017 if (stat(new_path2
, &sb
) == 0) {
9019 * We matched both, so we actually
9020 * want to write the $ISADIR version.
9022 (void) snprintf(new_path
, new_path_len
,
9023 "/platform/i86pc/kernel/%s/$ISADIR/unix",
9026 BAM_DPRINTF((D_EXPAND_PATH
, fcn
, new_path
));
9031 BAM_DPRINTF((D_RETURN_FAILURE
, fcn
));
9036 * The kernel cmd and arg have been changed, so
9037 * check whether the archive line needs to change.
9040 set_archive_line(entry_t
*entryp
, line_t
*kernelp
)
9042 line_t
*lp
= entryp
->start
;
9045 const char *fcn
= "set_archive_line()";
9047 for (; lp
!= NULL
; lp
= lp
->next
) {
9048 if (lp
->cmd
!= NULL
&& strncmp(lp
->cmd
, menu_cmds
[MODULE_CMD
],
9049 sizeof (menu_cmds
[MODULE_CMD
]) - 1) == 0) {
9053 INJECT_ERROR1("SET_ARCHIVE_LINE_END_ENTRY", lp
= entryp
->end
);
9054 if (lp
== entryp
->end
) {
9055 BAM_DPRINTF((D_ARCHIVE_LINE_NONE
, fcn
,
9060 INJECT_ERROR1("SET_ARCHIVE_LINE_END_MENU", lp
= NULL
);
9062 BAM_DPRINTF((D_ARCHIVE_LINE_NONE
, fcn
, entryp
->entryNum
));
9066 if (strstr(kernelp
->arg
, "$ISADIR") != NULL
) {
9067 new_archive
= DIRECT_BOOT_ARCHIVE
;
9068 m_cmd
= MODULE_DOLLAR_CMD
;
9069 } else if (strstr(kernelp
->arg
, "amd64") != NULL
) {
9070 new_archive
= DIRECT_BOOT_ARCHIVE_64
;
9073 new_archive
= DIRECT_BOOT_ARCHIVE_32
;
9077 if (strcmp(lp
->arg
, new_archive
) == 0) {
9078 BAM_DPRINTF((D_ARCHIVE_LINE_NOCHANGE
, fcn
, lp
->arg
));
9082 if (lp
->cmd
!= NULL
&& strcmp(lp
->cmd
, menu_cmds
[m_cmd
]) != 0) {
9084 lp
->cmd
= s_strdup(menu_cmds
[m_cmd
]);
9088 lp
->arg
= s_strdup(new_archive
);
9090 BAM_DPRINTF((D_ARCHIVE_LINE_REPLACED
, fcn
, lp
->line
));
9094 * Title for an entry to set properties that once went in bootenv.rc.
9096 #define BOOTENV_RC_TITLE "Solaris bootenv rc"
9099 * If path is NULL, return the kernel (optnum == KERNEL_CMD) or arguments
9100 * (optnum == ARGS_CMD) in the argument buf. If path is a zero-length
9101 * string, reset the value to the default. If path is a non-zero-length
9102 * string, set the kernel or arguments.
9113 int rv
= BAM_SUCCESS
;
9114 int free_new_path
= 0;
9123 size_t old_kernel_len
;
9128 char signbuf
[PATH_MAX
];
9130 const char *fcn
= "get_set_kernel()";
9132 assert(bufsize
> 0);
9134 ptr
= kernelp
= NULL
;
9135 new_arg
= old_args
= space
= NULL
;
9139 INJECT_ERROR1("GET_SET_KERNEL_NOT_DBOOT",
9140 bam_direct
= BAM_DIRECT_MULTIBOOT
);
9141 if (bam_direct
!= BAM_DIRECT_DBOOT
) {
9142 bam_error(NOT_DBOOT
, optnum
== KERNEL_CMD
? "kernel" : "args");
9147 * If a user changed the default entry to a non-bootadm controlled
9148 * one, we don't want to mess with it. Just print an error and
9151 if (mp
->curdefault
) {
9152 entryNum
= s_strtol(mp
->curdefault
->arg
);
9153 for (entryp
= mp
->entries
; entryp
; entryp
= entryp
->next
) {
9154 if (entryp
->entryNum
== entryNum
)
9157 if ((entryp
!= NULL
) &&
9158 ((entryp
->flags
& (BAM_ENTRY_BOOTADM
|BAM_ENTRY_LU
)) == 0)) {
9159 bam_error(DEFAULT_NOT_BAM
);
9164 entryp
= find_boot_entry(mp
, BOOTENV_RC_TITLE
, NULL
, NULL
, NULL
, NULL
,
9167 if (entryp
!= NULL
) {
9168 for (ptr
= entryp
->start
; ptr
&& ptr
!= entryp
->end
;
9170 if (strncmp(ptr
->cmd
, menu_cmds
[KERNEL_CMD
],
9171 sizeof (menu_cmds
[KERNEL_CMD
]) - 1) == 0) {
9176 if (kernelp
== NULL
) {
9177 bam_error(NO_KERNEL
, entryNum
);
9181 old_kernel_len
= strcspn(kernelp
->arg
, " \t");
9182 space
= old_args
= kernelp
->arg
+ old_kernel_len
;
9183 while ((*old_args
== ' ') || (*old_args
== '\t'))
9188 if (entryp
== NULL
) {
9189 BAM_DPRINTF((D_GET_SET_KERNEL_NO_RC
, fcn
));
9190 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
9191 return (BAM_SUCCESS
);
9194 if (optnum
== ARGS_CMD
) {
9195 if (old_args
[0] != '\0') {
9196 (void) strlcpy(buf
, old_args
, bufsize
);
9197 BAM_DPRINTF((D_GET_SET_KERNEL_ARGS
, fcn
, buf
));
9201 * We need to print the kernel, so we just turn the
9202 * first space into a '\0' and print the beginning.
9203 * We don't print anything if it's the default kernel.
9207 if (strcmp(kernelp
->arg
, DIRECT_BOOT_KERNEL
) != 0) {
9208 (void) strlcpy(buf
, kernelp
->arg
, bufsize
);
9209 BAM_DPRINTF((D_GET_SET_KERNEL_KERN
, fcn
, buf
));
9213 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
9214 return (BAM_SUCCESS
);
9218 * First, check if we're resetting an entry to the default.
9220 if ((path
[0] == '\0') ||
9221 ((optnum
== KERNEL_CMD
) &&
9222 (strcmp(path
, DIRECT_BOOT_KERNEL
) == 0))) {
9223 if ((entryp
== NULL
) || (kernelp
== NULL
)) {
9224 /* No previous entry, it's already the default */
9225 BAM_DPRINTF((D_GET_SET_KERNEL_ALREADY
, fcn
));
9226 return (BAM_SUCCESS
);
9230 * Check if we can delete the entry. If we're resetting the
9231 * kernel command, and the args is already empty, or if we're
9232 * resetting the args command, and the kernel is already the
9233 * default, we can restore the old default and delete the entry.
9235 if (((optnum
== KERNEL_CMD
) &&
9236 ((old_args
== NULL
) || (old_args
[0] == '\0'))) ||
9237 ((optnum
== ARGS_CMD
) &&
9238 (strncmp(kernelp
->arg
, DIRECT_BOOT_KERNEL
,
9239 sizeof (DIRECT_BOOT_KERNEL
) - 1) == 0))) {
9241 (void) delete_boot_entry(mp
, entryNum
, DBE_PRINTERR
);
9242 restore_default_entry(mp
, BAM_OLD_RC_DEF
,
9243 mp
->old_rc_default
);
9244 mp
->old_rc_default
= NULL
;
9246 BAM_DPRINTF((D_GET_SET_KERNEL_RESTORE_DEFAULT
, fcn
));
9250 if (optnum
== KERNEL_CMD
) {
9252 * At this point, we've already checked that old_args
9253 * and entryp are valid pointers. The "+ 2" is for
9254 * a space a the string termination character.
9256 new_str_len
= (sizeof (DIRECT_BOOT_KERNEL
) - 1) +
9257 strlen(old_args
) + 2;
9258 new_arg
= s_calloc(1, new_str_len
);
9259 (void) snprintf(new_arg
, new_str_len
, "%s %s",
9260 DIRECT_BOOT_KERNEL
, old_args
);
9262 kernelp
->arg
= new_arg
;
9265 * We have changed the kernel line, so we may need
9266 * to update the archive line as well.
9268 set_archive_line(entryp
, kernelp
);
9269 BAM_DPRINTF((D_GET_SET_KERNEL_RESET_KERNEL_SET_ARG
,
9270 fcn
, kernelp
->arg
));
9273 * We're resetting the boot args to nothing, so
9274 * we only need to copy the kernel. We've already
9275 * checked that the kernel is not the default.
9277 new_arg
= s_calloc(1, old_kernel_len
+ 1);
9278 (void) snprintf(new_arg
, old_kernel_len
+ 1, "%s",
9281 kernelp
->arg
= new_arg
;
9282 BAM_DPRINTF((D_GET_SET_KERNEL_RESET_ARG_SET_KERNEL
,
9283 fcn
, kernelp
->arg
));
9290 * Expand the kernel file to a full path, if necessary
9292 if ((optnum
== KERNEL_CMD
) && (path
[0] != '/')) {
9293 new_path
= expand_path(path
);
9294 if (new_path
== NULL
) {
9295 bam_error(UNKNOWN_KERNEL
, path
);
9296 BAM_DPRINTF((D_RETURN_FAILURE
, fcn
));
9306 * At this point, we know we're setting a new value. First, take care
9307 * of the case where there was no previous entry.
9309 if (entryp
== NULL
) {
9311 /* Similar to code in update_temp */
9312 fstype
= get_fstype("/");
9313 INJECT_ERROR1("GET_SET_KERNEL_FSTYPE", fstype
= NULL
);
9314 if (fstype
== NULL
) {
9315 bam_error(BOOTENV_FSTYPE_FAILED
);
9320 osdev
= get_special("/");
9321 INJECT_ERROR1("GET_SET_KERNEL_SPECIAL", osdev
= NULL
);
9322 if (osdev
== NULL
) {
9324 bam_error(BOOTENV_SPECIAL_FAILED
);
9329 sign
= find_existing_sign("/", osdev
, fstype
);
9330 INJECT_ERROR1("GET_SET_KERNEL_SIGN", sign
= NULL
);
9334 bam_error(BOOTENV_SIGN_FAILED
);
9340 (void) strlcpy(signbuf
, sign
, sizeof (signbuf
));
9342 assert(strchr(signbuf
, '(') == NULL
&&
9343 strchr(signbuf
, ',') == NULL
&&
9344 strchr(signbuf
, ')') == NULL
);
9346 if (optnum
== KERNEL_CMD
) {
9347 if (strcmp(fstype
, "zfs") == 0) {
9348 new_str_len
= strlen(new_path
) +
9349 strlen(ZFS_BOOT
) + 8;
9350 new_arg
= s_calloc(1, new_str_len
);
9351 (void) snprintf(new_arg
, new_str_len
, "%s %s",
9352 new_path
, ZFS_BOOT
);
9353 BAM_DPRINTF((D_GET_SET_KERNEL_NEW_KERN
, fcn
,
9355 entryNum
= add_boot_entry(mp
, BOOTENV_RC_TITLE
,
9356 signbuf
, new_arg
, NULL
, NULL
, NULL
);
9359 BAM_DPRINTF((D_GET_SET_KERNEL_NEW_KERN
, fcn
,
9361 entryNum
= add_boot_entry(mp
, BOOTENV_RC_TITLE
,
9362 signbuf
, new_path
, NULL
, NULL
, NULL
);
9365 new_str_len
= strlen(path
) + 8;
9366 if (strcmp(fstype
, "zfs") == 0) {
9367 new_str_len
+= strlen(DIRECT_BOOT_KERNEL_ZFS
);
9368 new_arg
= s_calloc(1, new_str_len
);
9369 (void) snprintf(new_arg
, new_str_len
, "%s %s",
9370 DIRECT_BOOT_KERNEL_ZFS
, path
);
9372 new_str_len
+= strlen(DIRECT_BOOT_KERNEL
);
9373 new_arg
= s_calloc(1, new_str_len
);
9374 (void) snprintf(new_arg
, new_str_len
, "%s %s",
9375 DIRECT_BOOT_KERNEL
, path
);
9378 BAM_DPRINTF((D_GET_SET_KERNEL_NEW_ARG
, fcn
, new_arg
));
9379 entryNum
= add_boot_entry(mp
, BOOTENV_RC_TITLE
,
9380 signbuf
, new_arg
, NULL
, DIRECT_BOOT_ARCHIVE
, NULL
);
9384 INJECT_ERROR1("GET_SET_KERNEL_ADD_BOOT_ENTRY",
9385 entryNum
= BAM_ERROR
);
9386 if (entryNum
== BAM_ERROR
) {
9387 bam_error(GET_SET_KERNEL_ADD_BOOT_ENTRY
,
9392 save_default_entry(mp
, BAM_OLD_RC_DEF
);
9393 ret
= set_global(mp
, menu_cmds
[DEFAULT_CMD
], entryNum
);
9394 INJECT_ERROR1("GET_SET_KERNEL_SET_GLOBAL", ret
= BAM_ERROR
);
9395 if (ret
== BAM_ERROR
) {
9396 bam_error(GET_SET_KERNEL_SET_GLOBAL
, entryNum
);
9403 * There was already an bootenv entry which we need to edit.
9405 if (optnum
== KERNEL_CMD
) {
9406 new_str_len
= strlen(new_path
) + strlen(old_args
) + 2;
9407 new_arg
= s_calloc(1, new_str_len
);
9408 (void) snprintf(new_arg
, new_str_len
, "%s %s", new_path
,
9411 kernelp
->arg
= new_arg
;
9414 * If we have changed the kernel line, we may need to update
9415 * the archive line as well.
9417 set_archive_line(entryp
, kernelp
);
9418 BAM_DPRINTF((D_GET_SET_KERNEL_REPLACED_KERNEL_SAME_ARG
, fcn
,
9421 new_str_len
= old_kernel_len
+ strlen(path
) + 8;
9422 new_arg
= s_calloc(1, new_str_len
);
9423 (void) strncpy(new_arg
, kernelp
->arg
, old_kernel_len
);
9424 (void) strlcat(new_arg
, " ", new_str_len
);
9425 (void) strlcat(new_arg
, path
, new_str_len
);
9427 kernelp
->arg
= new_arg
;
9428 BAM_DPRINTF((D_GET_SET_KERNEL_SAME_KERNEL_REPLACED_ARG
, fcn
,
9434 if ((rv
== BAM_WRITE
) && kernelp
)
9435 update_line(kernelp
);
9438 if (rv
== BAM_WRITE
) {
9439 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
9441 BAM_DPRINTF((D_RETURN_FAILURE
, fcn
));
9447 get_kernel(menu_t
*mp
, menu_cmd_t optnum
, char *buf
, size_t bufsize
)
9449 const char *fcn
= "get_kernel()";
9450 BAM_DPRINTF((D_FUNC_ENTRY1
, fcn
, menu_cmds
[optnum
]));
9451 return (get_set_kernel(mp
, optnum
, NULL
, buf
, bufsize
));
9455 set_kernel(menu_t
*mp
, menu_cmd_t optnum
, char *path
, char *buf
, size_t bufsize
)
9457 const char *fcn
= "set_kernel()";
9458 assert(path
!= NULL
);
9459 BAM_DPRINTF((D_FUNC_ENTRY2
, fcn
, menu_cmds
[optnum
], path
));
9460 return (get_set_kernel(mp
, optnum
, path
, buf
, bufsize
));
9465 set_option(menu_t
*mp
, char *dummy
, char *opt
)
9470 char buf
[BUFSIZ
] = "";
9472 const char *fcn
= "set_option()";
9476 assert(dummy
== NULL
);
9478 /* opt is set from bam_argv[0] and is always non-NULL */
9479 BAM_DPRINTF((D_FUNC_ENTRY1
, fcn
, opt
));
9481 val
= strchr(opt
, '=');
9486 if (strcmp(opt
, "default") == 0) {
9487 optnum
= DEFAULT_CMD
;
9488 } else if (strcmp(opt
, "timeout") == 0) {
9489 optnum
= TIMEOUT_CMD
;
9490 } else if (strcmp(opt
, menu_cmds
[KERNEL_CMD
]) == 0) {
9491 optnum
= KERNEL_CMD
;
9492 } else if (strcmp(opt
, menu_cmds
[ARGS_CMD
]) == 0) {
9495 bam_error(INVALID_OPTION
, opt
);
9500 * kernel and args are allowed without "=new_value" strings. All
9501 * others cause errors
9503 if ((val
== NULL
) && (optnum
!= KERNEL_CMD
) && (optnum
!= ARGS_CMD
)) {
9504 bam_error(NO_OPTION_ARG
, opt
);
9506 } else if (val
!= NULL
) {
9510 if ((optnum
== KERNEL_CMD
) || (optnum
== ARGS_CMD
)) {
9511 BAM_DPRINTF((D_SET_OPTION
, fcn
, menu_cmds
[optnum
],
9512 val
? val
+ 1 : "NULL"));
9515 rv
= set_kernel(mp
, optnum
, val
+ 1, buf
, sizeof (buf
));
9517 rv
= get_kernel(mp
, optnum
, buf
, sizeof (buf
));
9518 if ((rv
== BAM_SUCCESS
) && (buf
[0] != '\0'))
9519 (void) printf("%s\n", buf
);
9521 optval
= s_strtol(val
+ 1);
9522 BAM_DPRINTF((D_SET_OPTION
, fcn
, menu_cmds
[optnum
], val
+ 1));
9523 rv
= set_global(mp
, menu_cmds
[optnum
], optval
);
9526 if (rv
== BAM_WRITE
|| rv
== BAM_SUCCESS
) {
9527 BAM_DPRINTF((D_RETURN_SUCCESS
, fcn
));
9529 BAM_DPRINTF((D_RETURN_FAILURE
, fcn
));
9536 * The quiet argument suppresses messages. This is used
9537 * when invoked in the context of other commands (e.g. list_entry)
9540 read_globals(menu_t
*mp
, char *menu_path
, char *globalcmd
, int quiet
)
9544 int done
, ret
= BAM_SUCCESS
;
9550 if (mp
->start
== NULL
) {
9552 bam_error(NO_MENU
, menu_path
);
9557 for (lp
= mp
->start
; lp
; lp
= lp
->next
) {
9558 if (lp
->flags
!= BAM_GLOBAL
)
9561 if (lp
->cmd
== NULL
) {
9563 bam_error(NO_CMD
, lp
->lineNum
);
9567 if (strcmp(globalcmd
, lp
->cmd
) != 0)
9570 /* Found global. Check for duplicates */
9571 if (done
&& !quiet
) {
9572 bam_error(DUP_CMD
, globalcmd
, lp
->lineNum
, bam_root
);
9576 arg
= lp
->arg
? lp
->arg
: "";
9577 bam_print(GLOBAL_CMD
, globalcmd
, arg
);
9581 if (!done
&& bam_verbose
)
9582 bam_print(NO_ENTRY
, globalcmd
);
9588 menu_write(char *root
, menu_t
*mp
)
9590 const char *fcn
= "menu_write()";
9592 BAM_DPRINTF((D_MENU_WRITE_ENTER
, fcn
, root
));
9593 return (list2file(root
, MENU_TMP
, GRUB_MENU
, mp
->start
));
9597 line_free(line_t
*lp
)
9602 if (lp
->cmd
!= NULL
)
9614 linelist_free(line_t
*start
)
9620 start
= start
->next
;
9626 filelist_free(filelist_t
*flistp
)
9628 linelist_free(flistp
->head
);
9629 flistp
->head
= NULL
;
9630 flistp
->tail
= NULL
;
9634 menu_free(menu_t
*mp
)
9640 linelist_free(mp
->start
);
9657 * Returns 0 on success
9658 * Any other value indicates an error
9661 exec_cmd(char *cmdline
, filelist_t
*flistp
)
9671 * - only absolute paths are allowed
9672 * - set IFS to space and tab
9674 if (*cmdline
!= '/') {
9675 bam_error(ABS_PATH_REQ
, cmdline
);
9678 (void) putenv("IFS= \t");
9681 * We may have been exec'ed with SIGCHLD blocked
9684 (void) sigemptyset(&set
);
9685 (void) sigaddset(&set
, SIGCHLD
);
9686 if (sigprocmask(SIG_UNBLOCK
, &set
, NULL
) != 0) {
9687 bam_error(CANT_UNBLOCK_SIGCHLD
, strerror(errno
));
9692 * Set SIGCHLD disposition to SIG_DFL for popen/pclose
9694 disp
= sigset(SIGCHLD
, SIG_DFL
);
9695 if (disp
== SIG_ERR
) {
9696 bam_error(FAILED_SIG
, strerror(errno
));
9699 if (disp
== SIG_HOLD
) {
9700 bam_error(BLOCKED_SIG
, cmdline
);
9704 ptr
= popen(cmdline
, "r");
9706 bam_error(POPEN_FAIL
, cmdline
, strerror(errno
));
9711 * If we simply do a pclose() following a popen(), pclose()
9712 * will close the reader end of the pipe immediately even
9713 * if the child process has not started/exited. pclose()
9714 * does wait for cmd to terminate before returning though.
9715 * When the executed command writes its output to the pipe
9716 * there is no reader process and the command dies with
9717 * SIGPIPE. To avoid this we read repeatedly until read
9718 * terminates with EOF. This indicates that the command
9719 * (writer) has closed the pipe and we can safely do a
9722 * Since pclose() does wait for the command to exit,
9723 * we can safely reap the exit status of the command
9724 * from the value returned by pclose()
9726 while (s_fgets(buf
, sizeof (buf
), ptr
) != NULL
) {
9727 if (flistp
== NULL
) {
9728 /* s_fgets strips newlines, so insert them at the end */
9729 bam_print(PRINT
, buf
);
9731 append_to_flist(flistp
, buf
);
9737 bam_error(PCLOSE_FAIL
, cmdline
, strerror(errno
));
9741 if (WIFEXITED(ret
)) {
9742 return (WEXITSTATUS(ret
));
9744 bam_error(EXEC_FAIL
, cmdline
, ret
);
9750 * Since this function returns -1 on error
9751 * it cannot be used to convert -1. However,
9752 * that is sufficient for what we need.
9765 l
= strtol(str
, &res
, 10);
9766 if (errno
|| *res
!= '\0') {
9774 * Wrapper around fputs, that adds a newline (since fputs doesn't)
9777 s_fputs(char *str
, FILE *fp
)
9779 char linebuf
[BAM_MAXLINE
];
9781 (void) snprintf(linebuf
, sizeof (linebuf
), "%s\n", str
);
9782 return (fputs(linebuf
, fp
));
9786 * Wrapper around fgets, that strips newlines returned by fgets
9789 s_fgets(char *buf
, int buflen
, FILE *fp
)
9793 buf
= fgets(buf
, buflen
, fp
);
9796 if (n
== buflen
- 1 && buf
[n
-1] != '\n')
9797 bam_error(TOO_LONG
, buflen
- 1, buf
);
9798 buf
[n
-1] = (buf
[n
-1] == '\n') ? '\0' : buf
[n
-1];
9805 s_calloc(size_t nelem
, size_t sz
)
9809 ptr
= calloc(nelem
, sz
);
9811 bam_error(NO_MEM
, nelem
*sz
);
9818 s_realloc(void *ptr
, size_t sz
)
9820 ptr
= realloc(ptr
, sz
);
9822 bam_error(NO_MEM
, sz
);
9838 bam_error(NO_MEM
, strlen(str
) + 1);
9845 * Returns 1 if amd64 (or sparc, for syncing x86 diskless clients)
9846 * Returns 0 otherwise
9851 static int amd64
= -1;
9852 char isabuf
[257]; /* from sysinfo(2) manpage */
9857 if (bam_alt_platform
) {
9858 if (strcmp(bam_platform
, "i86pc") == 0) {
9859 amd64
= 1; /* diskless server */
9862 if (sysinfo(SI_ISALIST
, isabuf
, sizeof (isabuf
)) > 0 &&
9863 strncmp(isabuf
, "amd64 ", strlen("amd64 ")) == 0) {
9865 } else if (strstr(isabuf
, "i386") == NULL
) {
9866 amd64
= 1; /* diskless server */
9878 static int cached
= -1;
9879 static char mbuf
[257]; /* from sysinfo(2) manpage */
9884 if (bam_alt_platform
) {
9885 return (bam_platform
);
9887 if (sysinfo(SI_MACHINE
, mbuf
, sizeof (mbuf
)) > 0) {
9902 static int issparc
= -1;
9903 char mbuf
[257]; /* from sysinfo(2) manpage */
9908 if (bam_alt_platform
) {
9909 if (strncmp(bam_platform
, "sun4", 4) == 0) {
9913 if (sysinfo(SI_ARCHITECTURE
, mbuf
, sizeof (mbuf
)) > 0 &&
9914 strcmp(mbuf
, "sparc") == 0) {
9925 append_to_flist(filelist_t
*flistp
, char *s
)
9929 lp
= s_calloc(1, sizeof (line_t
));
9930 lp
->line
= s_strdup(s
);
9931 if (flistp
->head
== NULL
)
9934 flistp
->tail
->next
= lp
;
9944 ucode_install(char *root
)
9948 for (i
= 0; ucode_vendors
[i
].filestr
!= NULL
; i
++) {
9949 int cmd_len
= PATH_MAX
+ 256;
9950 char cmd
[PATH_MAX
+ 256];
9951 char file
[PATH_MAX
];
9952 char timestamp
[PATH_MAX
];
9953 struct stat fstatus
, tstatus
;
9954 struct utimbuf u_times
;
9956 (void) snprintf(file
, PATH_MAX
, "%s/%s/%s-ucode.%s",
9957 bam_root
, UCODE_INSTALL_PATH
, ucode_vendors
[i
].filestr
,
9958 ucode_vendors
[i
].extstr
);
9960 if (stat(file
, &fstatus
) != 0 || !(S_ISREG(fstatus
.st_mode
)))
9963 (void) snprintf(timestamp
, PATH_MAX
, "%s.ts", file
);
9965 if (stat(timestamp
, &tstatus
) == 0 &&
9966 fstatus
.st_mtime
<= tstatus
.st_mtime
)
9969 (void) snprintf(cmd
, cmd_len
, "/usr/sbin/ucodeadm -i -R "
9970 "%s/%s/%s %s > /dev/null 2>&1", bam_root
,
9971 UCODE_INSTALL_PATH
, ucode_vendors
[i
].vendorstr
, file
);
9972 if (system(cmd
) != 0)
9975 if (creat(timestamp
, S_IRUSR
| S_IWUSR
) == -1)
9978 u_times
.actime
= fstatus
.st_atime
;
9979 u_times
.modtime
= fstatus
.st_mtime
;
9980 (void) utime(timestamp
, &u_times
);