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]
23 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2012 Milan Jurik. All rights reserved.
25 * Copyright (c) 2015 by Delphix. All rights reserved.
26 * Copyright 2016 Toomas Soome <tsoome@me.com>
27 * Copyright 2016 Nexenta Systems, Inc.
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>
77 #include <sys/ucode.h>
82 #include <device_info.h>
84 #include <sys/efi_partition.h>
87 #include <sys/mkdev.h>
92 #define TEXT_DOMAIN "SUNW_OST_OSCMD"
93 #endif /* TEXT_DOMAIN */
95 /* Type definitions */
104 #define LINE_INIT 0 /* lineNum initial value */
105 #define ENTRY_INIT -1 /* entryNum initial value */
106 #define ALL_ENTRIES -2 /* selects all boot entries */
108 #define PARTNO_NOTFOUND -1 /* Solaris partition not found */
109 #define PARTNO_EFI -2 /* EFI partition table found */
111 #define RAMDISK_SPECIAL "/devices/ramdisk"
112 #define ZFS_LEGACY_MNTPT "/tmp/bootadm_mnt_zfs_legacy"
114 #define BOOTADM_RDONLY_TEST "BOOTADM_RDONLY_TEST"
117 #define BAM_LOCK_FILE "/var/run/bootadm.lock"
118 #define LOCK_FILE_PERMS (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
120 #define CREATE_RAMDISK "boot/solaris/bin/create_ramdisk"
121 #define EXTRACT_BOOT_FILELIST "boot/solaris/bin/extract_boot_filelist"
123 #define GRUB_fdisk "/etc/lu/GRUB_fdisk"
124 #define GRUB_fdisk_target "/etc/lu/GRUB_fdisk_target"
134 #define BOOT_FILE_LIST "boot/solaris/filelist.ramdisk"
135 #define ETC_FILE_LIST "etc/boot/solaris/filelist.ramdisk"
137 #define FILE_STAT "boot/solaris/filestat.ramdisk"
138 #define FILE_STAT_TMP "boot/solaris/filestat.ramdisk.tmp"
139 #define DIR_PERMS (S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
140 #define FILE_STAT_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
142 #define FILE_STAT_TIMESTAMP "boot/solaris/timestamp.cache"
149 static subcmd_t bam_cmd
;
152 static int bam_root_readonly
;
154 static int bam_purge
= 0;
155 static char *bam_subcmd
;
156 static char *bam_opt
;
157 static char **bam_argv
;
158 static char *bam_pool
;
160 static int bam_check
;
161 static int bam_saved_check
;
162 static int bam_smf_check
;
163 static int bam_lock_fd
= -1;
166 char rootbuf
[PATH_MAX
] = "/";
167 static int bam_update_all
;
168 static int bam_alt_platform
;
169 static char *bam_platform
;
170 static char *bam_home_env
= NULL
;
172 /* function prototypes */
173 static void parse_args_internal(int, char *[]);
174 static void parse_args(int, char *argv
[]);
175 static error_t
bam_install(char *, char *);
176 static error_t
bam_archive(char *, char *);
178 static void bam_lock(void);
179 static void bam_unlock(void);
181 static int exec_cmd(char *, filelist_t
*);
182 static void linelist_free(line_t
*);
183 static void filelist_free(filelist_t
*);
185 static error_t
install_bootloader(void);
186 static error_t
update_archive(char *, char *);
187 static error_t
list_archive(char *, char *);
188 static error_t
update_all(char *, char *);
189 static error_t
read_list(char *, filelist_t
*);
191 static long s_strtol(char *);
193 static int is_amd64(void);
194 static char *get_machine(void);
195 static void append_to_flist(filelist_t
*, char *);
198 static void ucode_install();
202 /* Menu related sub commands */
203 static subcmd_defn_t menu_subcmds
[] = {
204 "set_option", OPT_ABSENT
, set_option
, 0, /* PUB */
205 "list_entry", OPT_OPTIONAL
, list_entry
, 1, /* PUB */
206 "delete_all_entries", OPT_ABSENT
, delete_all_entries
, 0, /* PVT */
207 "update_entry", OPT_REQ
, update_entry
, 0, /* menu */
208 "update_temp", OPT_OPTIONAL
, update_temp
, 0, /* reboot */
209 "upgrade", OPT_ABSENT
, upgrade_menu
, 0, /* menu */
210 "list_setting", OPT_OPTIONAL
, list_setting
, 1, /* menu */
211 "disable_hypervisor", OPT_ABSENT
, cvt_to_metal
, 0, /* menu */
212 "enable_hypervisor", OPT_ABSENT
, cvt_to_hyper
, 0, /* menu */
213 NULL
, 0, NULL
, 0 /* must be last */
217 /* Archive related sub commands */
218 static subcmd_defn_t arch_subcmds
[] = {
219 { "update", OPT_ABSENT
, update_archive
, 0 }, /* PUB */
220 { "update_all", OPT_ABSENT
, update_all
, 0 }, /* PVT */
221 { "list", OPT_OPTIONAL
, list_archive
, 1 }, /* PUB */
222 { NULL
, 0, NULL
, 0 } /* must be last */
225 /* Install related sub commands */
226 static subcmd_defn_t inst_subcmds
[] = {
227 { "install_bootloader", OPT_ABSENT
, install_bootloader
, 0 }, /* PUB */
228 { NULL
, 0, NULL
, 0 } /* must be last */
231 enum dircache_copy_opt
{
238 * Directory specific flags:
239 * NEED_UPDATE : the specified archive needs to be updated
241 #define NEED_UPDATE 0x00000001
243 #define set_dir_flag(id, f) (walk_arg.dirinfo[id].flags |= f)
244 #define unset_dir_flag(id, f) (walk_arg.dirinfo[id].flags &= ~f)
245 #define is_dir_flag_on(id, f) (walk_arg.dirinfo[id].flags & f ? 1 : 0)
247 #define get_cachedir(id) (walk_arg.dirinfo[id].cdir_path)
248 #define get_count(id) (walk_arg.dirinfo[id].count)
249 #define has_cachedir(id) (walk_arg.dirinfo[id].has_dir)
250 #define set_dir_present(id) (walk_arg.dirinfo[id].has_dir = 1)
253 * dirinfo_t (specific cache directory information):
254 * cdir_path: path to the archive cache directory
255 * has_dir: the specified cache directory is active
256 * count: the number of files to update
257 * flags: directory specific flags
259 typedef struct _dirinfo
{
260 char cdir_path
[PATH_MAX
];
268 * NEED_CACHE_DIR : cache directory is missing and needs to be created
269 * IS_SPARC_TARGET : the target mountpoint is a SPARC environment
270 * UPDATE_ERROR : an error occourred while traversing the list of files
271 * RDONLY_FSCHK : the target filesystem is read-only
272 * RAMDSK_FSCHK : the target filesystem is on a ramdisk
274 #define NEED_CACHE_DIR 0x00000001
275 #define IS_SPARC_TARGET 0x00000002
276 #define UPDATE_ERROR 0x00000004
277 #define RDONLY_FSCHK 0x00000008
278 #define INVALIDATE_CACHE 0x00000010
280 #define is_flag_on(flag) (walk_arg.update_flags & flag ? 1 : 0)
281 #define set_flag(flag) (walk_arg.update_flags |= flag)
282 #define unset_flag(flag) (walk_arg.update_flags &= ~flag)
286 * update_flags: flags related to the current updating process
287 * new_nvlp/old_nvlp: new and old list of archive-files / attributes pairs
288 * sparcfile: list of file paths for mkisofs -path-list (SPARC only)
295 dirinfo_t dirinfo
[CACHEDIR_NUM
];
300 struct safefile
*next
;
303 static struct safefile
*safefiles
= NULL
;
306 * svc:/system/filesystem/usr:default service checks for this file and
307 * does a boot archive update and then reboot the system.
309 #define NEED_UPDATE_FILE "/etc/svc/volatile/boot_archive_needs_update"
312 * svc:/system/boot-archive-update:default checks for this file and
313 * updates the boot archive.
315 #define NEED_UPDATE_SAFE_FILE "/etc/svc/volatile/boot_archive_safefile_update"
317 /* Thanks growisofs */
318 #define CD_BLOCK ((off64_t)2048)
319 #define VOLDESC_OFF 16
320 #define DVD_BLOCK (32*1024)
324 unsigned char type
[1];
325 unsigned char id
[5];
326 unsigned char void1
[80-5-1];
327 unsigned char volume_space_size
[8];
328 unsigned char void2
[2048-80-8];
331 #define bam_nowrite() (bam_check || bam_smf_check)
336 (void) fprintf(stderr
, "USAGE:\n");
339 (void) fprintf(stderr
,
340 "\t%s update-archive [-vn] [-R altroot [-p platform]]\n", prog
);
341 (void) fprintf(stderr
,
342 "\t%s list-archive [-R altroot [-p platform]]\n", prog
);
344 (void) fprintf(stderr
,
345 "\t%s install-bootloader [-fv] [-R altroot] [-P pool]\n", prog
);
347 (void) fprintf(stderr
,
348 "\t%s install-bootloader [-Mfv] [-R altroot] [-P pool]\n", prog
);
352 (void) fprintf(stderr
, "\t%s set-menu [-R altroot] key=value\n", prog
);
353 (void) fprintf(stderr
, "\t%s list-menu [-R altroot]\n", prog
);
358 * Best effort attempt to restore the $HOME value.
363 char home_env
[PATH_MAX
];
366 (void) snprintf(home_env
, sizeof (home_env
), "HOME=%s",
368 (void) putenv(home_env
);
377 * Sanitize the environment in which bootadm will execute its sub-processes
378 * (ex. mkisofs). This is done to prevent those processes from attempting
379 * to access files (ex. .mkisofsrc) or stat paths that might be on NFS
380 * or, potentially, insecure.
387 /* don't depend on caller umask */
390 /* move away from a potential unsafe current working directory */
391 while (chdir("/") == -1) {
392 if (errno
!= EINTR
) {
393 bam_print("WARNING: unable to chdir to /");
398 bam_home_env
= getenv("HOME");
399 while (bam_home_env
!= NULL
&& putenv("HOME=/") == -1) {
400 if (errno
== ENOMEM
) {
401 /* retry no more than MAX_TRIES times */
402 if (++stry
> MAX_TRIES
) {
403 bam_print("WARNING: unable to recover from "
404 "system memory pressure... aborting \n");
405 bam_exit(EXIT_FAILURE
);
407 /* memory is tight, try to sleep */
408 bam_print("Attempting to recover from memory pressure: "
409 "sleeping for %d seconds\n", SLEEP_TIME
* stry
);
410 (void) sleep(SLEEP_TIME
* stry
);
412 bam_print("WARNING: unable to sanitize HOME\n");
418 main(int argc
, char *argv
[])
420 error_t ret
= BAM_SUCCESS
;
422 (void) setlocale(LC_ALL
, "");
423 (void) textdomain(TEXT_DOMAIN
);
425 if ((prog
= strrchr(argv
[0], '/')) == NULL
) {
431 INJECT_ERROR1("ASSERT_ON", assert(0))
435 parse_args(argc
, argv
);
439 ret
= bam_loader_menu(bam_subcmd
, bam_opt
,
443 ret
= bam_archive(bam_subcmd
, bam_opt
);
446 ret
= bam_install(bam_subcmd
, bam_opt
);
453 if (ret
!= BAM_SUCCESS
)
454 bam_exit((ret
== BAM_NOCHANGE
) ? 2 : 1);
461 * Equivalence of public and internal commands:
462 * update-archive -- -a update
463 * list-archive -- -a list
464 * set-menu -- -m set_option
465 * list-menu -- -m list_entry
466 * update-menu -- -m update_entry
467 * install-bootloader -- -i install_bootloader
469 static struct cmd_map
{
474 { "update-archive", BAM_ARCHIVE
, "update"},
475 { "list-archive", BAM_ARCHIVE
, "list"},
476 { "set-menu", BAM_MENU
, "set_option"},
477 { "list-menu", BAM_MENU
, "list_entry"},
478 { "update-menu", BAM_MENU
, "update_entry"},
479 { "install-bootloader", BAM_INSTALL
, "install_bootloader"},
484 * Commands syntax published in bootadm(1M) are parsed here
487 parse_args(int argc
, char *argv
[])
489 struct cmd_map
*cmp
= cmd_map
;
491 /* command conforming to the final spec */
492 if (argc
> 1 && argv
[1][0] != '-') {
494 * Map commands to internal table.
496 while (cmp
->bam_cmdname
) {
497 if (strcmp(argv
[1], cmp
->bam_cmdname
) == 0) {
498 bam_cmd
= cmp
->bam_cmd
;
499 bam_subcmd
= cmp
->bam_subcmd
;
504 if (cmp
->bam_cmdname
== NULL
) {
512 parse_args_internal(argc
, argv
);
516 * A combination of public and private commands are parsed here.
517 * The internal syntax and the corresponding functionality are:
518 * -a update -- update-archive
519 * -a list -- list-archive
520 * -a update-all -- (reboot to sync all mnted OS archive)
521 * -i install_bootloader -- install-bootloader
522 * -m update_entry -- update-menu
523 * -m list_entry -- list-menu
524 * -m update_temp -- (reboot -- [boot-args])
525 * -m delete_all_entries -- (called from install)
526 * -m enable_hypervisor [args] -- cvt_to_hyper
527 * -m disable_hypervisor -- cvt_to_metal
528 * -m list_setting [entry] [value] -- list_setting
530 * A set of private flags is there too:
531 * -F -- purge the cache directories and rebuild them
534 parse_args_internal(int argc
, char *argv
[])
538 extern int optind
, opterr
;
540 const char *optstring
= "a:d:fi:m:no:vFCR:p:P:XZ";
542 const char *optstring
= "a:d:fi:m:no:vFCMR:p:P:XZ";
545 /* Suppress error message from getopt */
549 while ((c
= getopt(argc
, argv
, optstring
)) != -1) {
555 _("multiple commands specified: -%c\n"), c
);
557 bam_cmd
= BAM_ARCHIVE
;
564 _("duplicate options specified: -%c\n"), c
);
566 bam_debug
= s_strtol(optarg
);
578 _("multiple commands specified: -%c\n"), c
);
580 bam_cmd
= BAM_INSTALL
;
587 _("multiple commands specified: -%c\n"), c
);
600 * We save the original value of bam_check. The new
601 * approach in case of a read-only filesystem is to
602 * behave as a check, so we need a way to restore the
603 * original value after the evaluation of the read-only
604 * filesystem has been done.
605 * Even if we don't allow at the moment a check with
606 * update_all, this approach is more robust than
607 * simply resetting bam_check to zero.
615 _("duplicate options specified: -%c\n"), c
);
626 if (bam_pool
!= NULL
) {
629 _("duplicate options specified: -%c\n"), c
);
637 _("duplicate options specified: -%c\n"), c
);
639 } else if (realpath(optarg
, rootbuf
) == NULL
) {
641 bam_error(_("cannot resolve path %s: %s\n"),
642 optarg
, strerror(errno
));
647 bam_rootlen
= strlen(rootbuf
);
650 bam_alt_platform
= 1;
651 bam_platform
= optarg
;
652 if ((strcmp(bam_platform
, "i86pc") != 0) &&
653 (strcmp(bam_platform
, "sun4u") != 0) &&
654 (strcmp(bam_platform
, "sun4v") != 0)) {
656 bam_error(_("invalid platform %s - must be "
657 "one of sun4u, sun4v or i86pc\n"),
662 bam_is_hv
= BAM_HV_PRESENT
;
669 bam_error(_("invalid option or missing option "
670 "argument: -%c\n"), optopt
);
674 bam_error(_("invalid option or missing option "
675 "argument: -%c\n"), c
);
681 * An alternate platform requires an alternate root
683 if (bam_alt_platform
&& bam_alt_root
== 0) {
689 * A command option must be specfied
692 if (bam_opt
&& strcmp(bam_opt
, "all") == 0) {
696 bam_error(_("a command option must be specified\n"));
706 bam_error(_("Internal error: %s\n"), "parse_args");
708 } else if (optind
< argc
) {
709 bam_argv
= &argv
[optind
];
710 bam_argc
= argc
- optind
;
714 * mbr and pool are options for install_bootloader
716 if (bam_cmd
!= BAM_INSTALL
&& (bam_mbr
|| bam_pool
!= NULL
)) {
722 * -n implies verbose mode
729 check_subcmd_and_options(
732 subcmd_defn_t
*table
,
737 if (subcmd
== NULL
) {
738 bam_error(_("this command requires a sub-command\n"));
742 if (strcmp(subcmd
, "set_option") == 0) {
743 if (bam_argc
== 0 || bam_argv
== NULL
|| bam_argv
[0] == NULL
) {
744 bam_error(_("missing argument for sub-command\n"));
747 } else if (bam_argc
> 1 || bam_argv
[1] != NULL
) {
748 bam_error(_("invalid trailing arguments\n"));
752 } else if (strcmp(subcmd
, "update_all") == 0) {
754 * The only option we accept for the "update_all"
755 * subcmd is "fastboot".
757 if (bam_argc
> 1 || (bam_argc
== 1 &&
758 strcmp(bam_argv
[0], "fastboot") != 0)) {
759 bam_error(_("invalid trailing arguments\n"));
763 } else if (((strcmp(subcmd
, "enable_hypervisor") != 0) &&
764 (strcmp(subcmd
, "list_setting") != 0)) && (bam_argc
|| bam_argv
)) {
766 * Of the remaining subcommands, only "enable_hypervisor" and
767 * "list_setting" take trailing arguments.
769 bam_error(_("invalid trailing arguments\n"));
774 if (bam_root
== NULL
) {
779 /* verify that subcmd is valid */
780 for (i
= 0; table
[i
].subcmd
!= NULL
; i
++) {
781 if (strcmp(table
[i
].subcmd
, subcmd
) == 0)
785 if (table
[i
].subcmd
== NULL
) {
786 bam_error(_("invalid sub-command specified: %s\n"), subcmd
);
790 if (table
[i
].unpriv
== 0 && geteuid() != 0) {
791 bam_error(_("you must be root to run this command\n"));
796 * Currently only privileged commands need a lock
798 if (table
[i
].unpriv
== 0)
801 /* subcmd verifies that opt is appropriate */
802 if (table
[i
].option
!= OPT_OPTIONAL
) {
803 if ((table
[i
].option
== OPT_REQ
) ^ (opt
!= NULL
)) {
805 bam_error(_("this sub-command (%s) does not "
806 "take options\n"), subcmd
);
808 bam_error(_("an option is required for this "
809 "sub-command: %s\n"), subcmd
);
814 *fp
= table
[i
].handler
;
816 return (BAM_SUCCESS
);
820 * NOTE: A single "/" is also considered a trailing slash and will
824 elide_trailing_slash(const char *src
, char *dst
, size_t dstsize
)
831 (void) strlcpy(dst
, src
, dstsize
);
833 dstlen
= strlen(dst
);
834 if (dst
[dstlen
- 1] == '/') {
835 dst
[dstlen
- 1] = '\0';
840 is_safe_exec(char *path
)
844 if (lstat(path
, &sb
) != 0) {
845 bam_error(_("stat of file failed: %s: %s\n"), path
,
850 if (!S_ISREG(sb
.st_mode
)) {
851 bam_error(_("%s is not a regular file, skipping\n"), path
);
855 if (sb
.st_uid
!= getuid()) {
856 bam_error(_("%s is not owned by %d, skipping\n"),
861 if (sb
.st_mode
& S_IWOTH
|| sb
.st_mode
& S_IWGRP
) {
862 bam_error(_("%s is others or group writable, skipping\n"),
867 return (BAM_SUCCESS
);
871 install_bootloader(void)
876 struct extmnttab mnt
;
877 struct stat statbuf
= {0};
878 be_node_list_t
*be_nodes
, *node
;
880 char *root_ds
= NULL
;
883 if (nvlist_alloc(&nvl
, NV_UNIQUE_NAME
, 0) != 0) {
884 bam_error(_("out of memory\n"));
889 * if bam_alt_root is set, the stage files are used from alt root.
890 * if pool is set, the target devices are pool devices, stage files
891 * are read from pool bootfs unless alt root is set.
893 * use arguments as targets, stage files are from alt or current root
894 * if no arguments and no pool, install on current boot pool.
898 if (stat(bam_root
, &statbuf
) != 0) {
899 bam_error(_("stat of file failed: %s: %s\n"), bam_root
,
903 if ((fp
= fopen(MNTTAB
, "r")) == NULL
) {
904 bam_error(_("failed to open file: %s: %s\n"),
905 MNTTAB
, strerror(errno
));
909 while (getextmntent(fp
, &mnt
, sizeof (mnt
)) == 0) {
910 if (mnt
.mnt_major
== major(statbuf
.st_dev
) &&
911 mnt
.mnt_minor
== minor(statbuf
.st_dev
)) {
913 root_ds
= strdup(mnt
.mnt_special
);
920 bam_error(_("alternate root %s not in mnttab\n"),
924 if (root_ds
== NULL
) {
925 bam_error(_("out of memory\n"));
929 if (be_list(NULL
, &be_nodes
) != BE_SUCCESS
) {
930 bam_error(_("No BE's found\n"));
933 for (node
= be_nodes
; node
!= NULL
; node
= node
->be_next_node
)
934 if (strcmp(root_ds
, node
->be_root_ds
) == 0)
938 bam_error(_("BE (%s) does not exist\n"), root_ds
);
943 be_free_list(be_nodes
);
946 ret
= nvlist_add_string(nvl
, BE_ATTR_ORIG_BE_NAME
,
948 ret
|= nvlist_add_string(nvl
, BE_ATTR_ORIG_BE_ROOT
,
950 be_free_list(be_nodes
);
958 flags
|= BE_INSTALLBOOT_FLAG_FORCE
;
960 flags
|= BE_INSTALLBOOT_FLAG_MBR
;
962 flags
|= BE_INSTALLBOOT_FLAG_VERBOSE
;
964 if (nvlist_add_uint16(nvl
, BE_ATTR_INSTALL_FLAGS
, flags
) != 0) {
965 bam_error(_("out of memory\n"));
971 * if altroot was set, we got be name and be root, only need
972 * to set pool name as target.
973 * if no altroot, need to find be name and root from pool.
975 if (bam_pool
!= NULL
) {
976 ret
= nvlist_add_string(nvl
, BE_ATTR_ORIG_BE_POOL
, bam_pool
);
982 ret
= be_installboot(nvl
);
989 if (be_list(NULL
, &be_nodes
) != BE_SUCCESS
) {
990 bam_error(_("No BE's found\n"));
995 if (bam_pool
!= NULL
) {
997 * find active be_node in bam_pool
999 for (node
= be_nodes
; node
!= NULL
; node
= node
->be_next_node
) {
1000 if (strcmp(bam_pool
, node
->be_rpool
) != 0)
1002 if (node
->be_active_on_boot
)
1006 bam_error(_("No active BE in %s\n"), bam_pool
);
1007 be_free_list(be_nodes
);
1011 ret
= nvlist_add_string(nvl
, BE_ATTR_ORIG_BE_NAME
,
1012 node
->be_node_name
);
1013 ret
|= nvlist_add_string(nvl
, BE_ATTR_ORIG_BE_ROOT
,
1015 be_free_list(be_nodes
);
1020 ret
= be_installboot(nvl
);
1027 * get dataset for "/" and fill up the args.
1029 if ((fp
= fopen(MNTTAB
, "r")) == NULL
) {
1030 bam_error(_("failed to open file: %s: %s\n"),
1031 MNTTAB
, strerror(errno
));
1033 be_free_list(be_nodes
);
1038 while (getextmntent(fp
, &mnt
, sizeof (mnt
)) == 0) {
1039 if (strcmp(mnt
.mnt_mountp
, "/") == 0) {
1041 root_ds
= strdup(mnt
.mnt_special
);
1048 bam_error(_("alternate root %s not in mnttab\n"), "/");
1050 be_free_list(be_nodes
);
1053 if (root_ds
== NULL
) {
1054 bam_error(_("out of memory\n"));
1056 be_free_list(be_nodes
);
1060 for (node
= be_nodes
; node
!= NULL
; node
= node
->be_next_node
) {
1061 if (strcmp(root_ds
, node
->be_root_ds
) == 0)
1066 bam_error(_("No such BE: %s\n"), root_ds
);
1068 be_free_list(be_nodes
);
1074 ret
= nvlist_add_string(nvl
, BE_ATTR_ORIG_BE_NAME
, node
->be_node_name
);
1075 ret
|= nvlist_add_string(nvl
, BE_ATTR_ORIG_BE_ROOT
, node
->be_root_ds
);
1076 ret
|= nvlist_add_string(nvl
, BE_ATTR_ORIG_BE_POOL
, node
->be_rpool
);
1077 be_free_list(be_nodes
);
1082 ret
= be_installboot(nvl
) ? BAM_ERROR
: 0;
1090 bam_install(char *subcmd
, char *opt
)
1097 if (check_subcmd_and_options(subcmd
, opt
, inst_subcmds
, &f
) ==
1110 error_t (*f
)(char *root
, char *opt
);
1111 const char *fcn
= "bam_archive()";
1114 * Add trailing / for archive subcommands
1116 if (rootbuf
[strlen(rootbuf
) - 1] != '/')
1117 (void) strcat(rootbuf
, "/");
1118 bam_rootlen
= strlen(rootbuf
);
1123 ret
= check_subcmd_and_options(subcmd
, opt
, arch_subcmds
, &f
);
1124 if (ret
!= BAM_SUCCESS
) {
1128 ret
= get_boot_cap(rootbuf
);
1129 if (ret
!= BAM_SUCCESS
) {
1130 BAM_DPRINTF(("%s: Failed to get boot capability\n", fcn
));
1135 * Check archive not supported with update_all
1136 * since it is awkward to display out-of-sync
1137 * information for each BE.
1139 if (bam_check
&& strcmp(subcmd
, "update_all") == 0) {
1140 bam_error(_("the check option is not supported with "
1141 "subcmd: %s\n"), subcmd
);
1145 if (strcmp(subcmd
, "update_all") == 0)
1149 ucode_install(bam_root
);
1152 ret
= f(bam_root
, opt
);
1161 bam_error(char *format
, ...)
1165 va_start(ap
, format
);
1166 (void) fprintf(stderr
, "%s: ", prog
);
1167 (void) vfprintf(stderr
, format
, ap
);
1173 bam_derror(char *format
, ...)
1179 va_start(ap
, format
);
1180 (void) fprintf(stderr
, "DEBUG: ");
1181 (void) vfprintf(stderr
, format
, ap
);
1187 bam_print(char *format
, ...)
1191 va_start(ap
, format
);
1192 (void) vfprintf(stdout
, format
, ap
);
1198 bam_print_stderr(char *format
, ...)
1202 va_start(ap
, format
);
1203 (void) vfprintf(stderr
, format
, ap
);
1208 bam_exit(int excode
)
1221 bam_lock_fd
= open(BAM_LOCK_FILE
, O_CREAT
|O_RDWR
, LOCK_FILE_PERMS
);
1222 if (bam_lock_fd
< 0) {
1224 * We may be invoked early in boot for archive verification.
1225 * In this case, root is readonly and /var/run may not exist.
1226 * Proceed without the lock
1228 if (errno
== EROFS
|| errno
== ENOENT
) {
1229 bam_root_readonly
= 1;
1233 bam_error(_("failed to open file: %s: %s\n"),
1234 BAM_LOCK_FILE
, strerror(errno
));
1238 lock
.l_type
= F_WRLCK
;
1239 lock
.l_whence
= SEEK_SET
;
1243 if (fcntl(bam_lock_fd
, F_SETLK
, &lock
) == -1) {
1244 if (errno
!= EACCES
&& errno
!= EAGAIN
) {
1245 bam_error(_("failed to lock file: %s: %s\n"),
1246 BAM_LOCK_FILE
, strerror(errno
));
1247 (void) close(bam_lock_fd
);
1252 (void) pread(bam_lock_fd
, &pid
, sizeof (pid_t
), 0);
1254 _("another instance of bootadm (pid %lu) is running\n"),
1257 lock
.l_type
= F_WRLCK
;
1258 lock
.l_whence
= SEEK_SET
;
1261 if (fcntl(bam_lock_fd
, F_SETLKW
, &lock
) == -1) {
1262 bam_error(_("failed to lock file: %s: %s\n"),
1263 BAM_LOCK_FILE
, strerror(errno
));
1264 (void) close(bam_lock_fd
);
1270 /* We own the lock now */
1272 (void) write(bam_lock_fd
, &pid
, sizeof (pid
));
1278 struct flock unlock
;
1281 * NOP if we don't hold the lock
1283 if (bam_lock_fd
< 0) {
1287 unlock
.l_type
= F_UNLCK
;
1288 unlock
.l_whence
= SEEK_SET
;
1292 if (fcntl(bam_lock_fd
, F_SETLK
, &unlock
) == -1) {
1293 bam_error(_("failed to unlock file: %s: %s\n"),
1294 BAM_LOCK_FILE
, strerror(errno
));
1297 if (close(bam_lock_fd
) == -1) {
1298 bam_error(_("failed to close file: %s: %s\n"),
1299 BAM_LOCK_FILE
, strerror(errno
));
1305 list_archive(char *root
, char *opt
)
1308 filelist_t
*flistp
= &flist
;
1312 assert(opt
== NULL
);
1314 flistp
->head
= flistp
->tail
= NULL
;
1315 if (read_list(root
, flistp
) != BAM_SUCCESS
) {
1318 assert(flistp
->head
&& flistp
->tail
);
1320 for (lp
= flistp
->head
; lp
; lp
= lp
->next
) {
1321 bam_print(_("%s\n"), lp
->line
);
1324 filelist_free(flistp
);
1326 return (BAM_SUCCESS
);
1330 * Checks if the path specified (without the file name at the end) exists
1331 * and creates it if not. If the path exists and is not a directory, an attempt
1332 * to unlink is made.
1335 setup_path(char *path
)
1341 p
= strrchr(path
, '/');
1344 if (stat(path
, &sb
) != 0 || !(S_ISDIR(sb
.st_mode
))) {
1345 /* best effort attempt, mkdirp will catch the error */
1346 (void) unlink(path
);
1348 bam_print(_("need to create directory "
1349 "path for %s\n"), path
);
1350 ret
= mkdirp(path
, DIR_PERMS
);
1352 bam_error(_("mkdir of %s failed: %s\n"),
1353 path
, strerror(errno
));
1359 return (BAM_SUCCESS
);
1361 return (BAM_SUCCESS
);
1370 char path
[PATH_MAX
];
1375 setup_file(char *base
, const char *path
, cachefile
*cf
)
1380 /* init gzfile or fdfile in case we fail before opening */
1381 if (bam_direct
== BAM_DIRECT_DBOOT
)
1382 cf
->out
.gzfile
= NULL
;
1384 cf
->out
.fdfile
= -1;
1386 /* strip the trailing altroot path */
1387 strip
= (char *)path
+ strlen(rootbuf
);
1389 ret
= snprintf(cf
->path
, sizeof (cf
->path
), "%s/%s", base
, strip
);
1390 if (ret
>= sizeof (cf
->path
)) {
1391 bam_error(_("unable to create path on mountpoint %s, "
1392 "path too long\n"), rootbuf
);
1396 /* Check if path is present in the archive cache directory */
1397 if (setup_path(cf
->path
) == BAM_ERROR
)
1400 if (bam_direct
== BAM_DIRECT_DBOOT
) {
1401 if ((cf
->out
.gzfile
= gzopen(cf
->path
, "wb")) == NULL
) {
1402 bam_error(_("failed to open file: %s: %s\n"),
1403 cf
->path
, strerror(errno
));
1406 (void) gzsetparams(cf
->out
.gzfile
, Z_BEST_SPEED
,
1407 Z_DEFAULT_STRATEGY
);
1409 if ((cf
->out
.fdfile
= open(cf
->path
, O_WRONLY
| O_CREAT
, 0644))
1411 bam_error(_("failed to open file: %s: %s\n"),
1412 cf
->path
, strerror(errno
));
1417 return (BAM_SUCCESS
);
1421 cache_write(cachefile cf
, char *buf
, int size
)
1425 if (bam_direct
== BAM_DIRECT_DBOOT
) {
1426 if (gzwrite(cf
.out
.gzfile
, buf
, size
) < 1) {
1427 bam_error(_("failed to write to %s\n"),
1428 gzerror(cf
.out
.gzfile
, &err
));
1429 if (err
== Z_ERRNO
&& bam_verbose
) {
1430 bam_error(_("write to file failed: %s: %s\n"),
1431 cf
.path
, strerror(errno
));
1436 if (write(cf
.out
.fdfile
, buf
, size
) < 1) {
1437 bam_error(_("write to file failed: %s: %s\n"),
1438 cf
.path
, strerror(errno
));
1442 return (BAM_SUCCESS
);
1446 cache_close(cachefile cf
)
1450 if (bam_direct
== BAM_DIRECT_DBOOT
) {
1451 if (cf
.out
.gzfile
) {
1452 ret
= gzclose(cf
.out
.gzfile
);
1454 bam_error(_("failed to close file: %s: %s\n"),
1455 cf
.path
, strerror(errno
));
1460 if (cf
.out
.fdfile
!= -1) {
1461 ret
= close(cf
.out
.fdfile
);
1463 bam_error(_("failed to close file: %s: %s\n"),
1464 cf
.path
, strerror(errno
));
1470 return (BAM_SUCCESS
);
1474 dircache_updatefile(const char *path
, int what
)
1481 if (bam_nowrite()) {
1482 set_dir_flag(what
, NEED_UPDATE
);
1483 return (BAM_SUCCESS
);
1486 if (!has_cachedir(what
))
1487 return (BAM_SUCCESS
);
1489 if ((infile
= fopen(path
, "rb")) == NULL
) {
1490 bam_error(_("failed to open file: %s: %s\n"), path
,
1495 ret
= setup_file(get_cachedir(what
), path
, &outfile
);
1496 if (ret
== BAM_ERROR
) {
1497 exitcode
= BAM_ERROR
;
1501 while ((ret
= fread(buf
, 1, sizeof (buf
), infile
)) > 0) {
1502 if (cache_write(outfile
, buf
, ret
) == BAM_ERROR
) {
1503 exitcode
= BAM_ERROR
;
1508 set_dir_flag(what
, NEED_UPDATE
);
1510 exitcode
= BAM_SUCCESS
;
1512 (void) fclose(infile
);
1513 if (cache_close(outfile
) == BAM_ERROR
)
1514 exitcode
= BAM_ERROR
;
1515 if (exitcode
== BAM_ERROR
)
1516 set_flag(UPDATE_ERROR
);
1521 dircache_updatedir(const char *path
, int what
)
1524 char dpath
[PATH_MAX
];
1528 strip
= (char *)path
+ strlen(rootbuf
);
1530 ret
= snprintf(dpath
, sizeof (dpath
), "%s/%s", get_cachedir(what
), strip
);
1532 if (ret
>= sizeof (dpath
)) {
1533 bam_error(_("unable to create path on mountpoint %s, "
1534 "path too long\n"), rootbuf
);
1535 set_flag(UPDATE_ERROR
);
1539 if (stat(dpath
, &sb
) == 0 && S_ISDIR(sb
.st_mode
))
1540 return (BAM_SUCCESS
);
1542 if (!bam_nowrite() && mkdirp(dpath
, DIR_PERMS
) == -1) {
1543 set_flag(UPDATE_ERROR
);
1547 set_dir_flag(what
, NEED_UPDATE
);
1548 return (BAM_SUCCESS
);
1551 #define DO_CACHE_DIR 0
1552 #define DO_UPDATE_DIR 1
1554 #if defined(_LP64) || defined(_LONGLONG_TYPE)
1555 typedef Elf64_Ehdr _elfhdr
;
1557 typedef Elf32_Ehdr _elfhdr
;
1561 * This routine updates the contents of the cache directory
1564 update_dircache(const char *path
, int flags
)
1566 int rc
= BAM_SUCCESS
;
1574 if ((fd
= open(path
, O_RDONLY
)) < 0) {
1575 bam_error(_("failed to open file: %s: %s\n"),
1576 path
, strerror(errno
));
1577 set_flag(UPDATE_ERROR
);
1583 * libelf and gelf would be a cleaner and easier way to handle
1584 * this, but libelf fails compilation if _ILP32 is defined &&
1585 * _FILE_OFFSET_BITS is != 32 ...
1587 if (read(fd
, (void *)&elf
, sizeof (_elfhdr
)) < 0) {
1588 bam_error(_("read failed for file: %s: %s\n"),
1589 path
, strerror(errno
));
1590 set_flag(UPDATE_ERROR
);
1598 * If the file is not an executable and is not inside an amd64
1599 * directory, we copy it in both the cache directories,
1600 * otherwise, we only copy it inside the 64-bit one.
1602 if (memcmp(elf
.e_ident
, ELFMAG
, 4) != 0) {
1603 if (strstr(path
, "/amd64")) {
1604 rc
= dircache_updatefile(path
, FILE64
);
1606 rc
= dircache_updatefile(path
, FILE32
);
1607 if (rc
== BAM_SUCCESS
)
1608 rc
= dircache_updatefile(path
, FILE64
);
1612 * Based on the ELF class we copy the file in the 32-bit
1613 * or the 64-bit cache directory.
1615 if (elf
.e_ident
[EI_CLASS
] == ELFCLASS32
) {
1616 rc
= dircache_updatefile(path
, FILE32
);
1617 } else if (elf
.e_ident
[EI_CLASS
] == ELFCLASS64
) {
1618 rc
= dircache_updatefile(path
, FILE64
);
1620 bam_print(_("WARNING: file %s is neither a "
1621 "32-bit nor a 64-bit ELF\n"), path
);
1623 rc
= dircache_updatefile(path
, FILE32
);
1624 if (rc
== BAM_SUCCESS
)
1625 rc
= dircache_updatefile(path
, FILE64
);
1631 if (strstr(path
, "/amd64") == NULL
) {
1632 rc
= dircache_updatedir(path
, FILE32
);
1634 if (has_cachedir(FILE64
)) {
1635 rc
= dircache_updatedir(path
, FILE64
);
1651 const struct stat
*st
,
1657 uint64_t filestat
[2];
1658 int error
, ret
, status
;
1660 struct safefile
*safefilep
;
1666 * On SPARC we create/update links too.
1668 if (flags
!= FTW_F
&& flags
!= FTW_D
&& (flags
== FTW_SL
&&
1669 !is_flag_on(IS_SPARC_TARGET
)))
1673 * Ignore broken links
1675 if (flags
== FTW_SL
&& stat(file
, &sb
) < 0)
1679 * new_nvlp may be NULL if there were errors earlier
1680 * but this is not fatal to update determination.
1682 if (walk_arg
.new_nvlp
) {
1683 filestat
[0] = st
->st_size
;
1684 filestat
[1] = st
->st_mtime
;
1685 error
= nvlist_add_uint64_array(walk_arg
.new_nvlp
,
1686 file
+ bam_rootlen
, filestat
, 2);
1688 bam_error(_("failed to update stat data for: %s: %s\n"),
1689 file
, strerror(error
));
1693 * If we are invoked as part of system/filesystem/boot-archive, then
1694 * there are a number of things we should not worry about
1696 if (bam_smf_check
) {
1697 /* ignore amd64 modules unless we are booted amd64. */
1698 if (!is_amd64() && strstr(file
, "/amd64/") != 0)
1701 /* read in list of safe files */
1702 if (safefiles
== NULL
) {
1703 fp
= fopen("/boot/solaris/filelist.safe", "r");
1705 safefiles
= s_calloc(1,
1706 sizeof (struct safefile
));
1707 safefilep
= safefiles
;
1708 safefilep
->name
= s_calloc(1, MAXPATHLEN
+
1710 safefilep
->next
= NULL
;
1711 while (s_fgets(safefilep
->name
, MAXPATHLEN
+
1712 MAXNAMELEN
, fp
) != NULL
) {
1713 safefilep
->next
= s_calloc(1,
1714 sizeof (struct safefile
));
1715 safefilep
= safefilep
->next
;
1716 safefilep
->name
= s_calloc(1,
1717 MAXPATHLEN
+ MAXNAMELEN
);
1718 safefilep
->next
= NULL
;
1726 * On SPARC we create a -path-list file for mkisofs
1728 if (is_flag_on(IS_SPARC_TARGET
) && !bam_nowrite()) {
1729 if (flags
!= FTW_D
) {
1732 strip
= (char *)file
+ strlen(rootbuf
);
1733 (void) fprintf(walk_arg
.sparcfile
, "/%s=%s\n", strip
,
1739 * We are transitioning from the old model to the dircache or the cache
1740 * directory was removed: create the entry without further checkings.
1742 if (is_flag_on(NEED_CACHE_DIR
)) {
1744 bam_print(_(" new %s\n"), file
);
1746 if (is_flag_on(IS_SPARC_TARGET
)) {
1747 set_dir_flag(FILE64
, NEED_UPDATE
);
1751 ret
= update_dircache(file
, flags
);
1752 if (ret
== BAM_ERROR
) {
1753 bam_error(_("directory cache update failed for %s\n"),
1762 * We need an update if file doesn't exist in old archive
1764 if (walk_arg
.old_nvlp
== NULL
||
1765 nvlist_lookup_uint64_array(walk_arg
.old_nvlp
,
1766 file
+ bam_rootlen
, &value
, &sz
) != 0) {
1767 if (bam_smf_check
) /* ignore new during smf check */
1770 if (is_flag_on(IS_SPARC_TARGET
)) {
1771 set_dir_flag(FILE64
, NEED_UPDATE
);
1773 ret
= update_dircache(file
, flags
);
1774 if (ret
== BAM_ERROR
) {
1775 bam_error(_("directory cache update "
1776 "failed for %s\n"), file
);
1782 bam_print(_(" new %s\n"), file
);
1787 * If we got there, the file is already listed as to be included in the
1788 * iso image. We just need to know if we are going to rebuild it or not
1790 if (is_flag_on(IS_SPARC_TARGET
) &&
1791 is_dir_flag_on(FILE64
, NEED_UPDATE
) && !bam_nowrite())
1794 * File exists in old archive. Check if file has changed
1797 bcopy(value
, filestat
, sizeof (filestat
));
1799 if (flags
!= FTW_D
&& (filestat
[0] != st
->st_size
||
1800 filestat
[1] != st
->st_mtime
)) {
1801 if (bam_smf_check
) {
1802 safefilep
= safefiles
;
1803 while (safefilep
!= NULL
&&
1804 safefilep
->name
[0] != '\0') {
1805 if (regcomp(&re
, safefilep
->name
,
1806 REG_EXTENDED
|REG_NOSUB
) == 0) {
1807 status
= regexec(&re
,
1808 file
+ bam_rootlen
, 0, NULL
, 0);
1812 NEED_UPDATE_SAFE_FILE
,
1817 safefilep
= safefilep
->next
;
1821 if (is_flag_on(IS_SPARC_TARGET
)) {
1822 set_dir_flag(FILE64
, NEED_UPDATE
);
1824 ret
= update_dircache(file
, flags
);
1825 if (ret
== BAM_ERROR
) {
1826 bam_error(_("directory cache update failed "
1834 bam_print(" %s\n", file
);
1836 bam_print(_(" changed %s\n"), file
);
1844 * Remove a directory path recursively
1849 struct dirent
*d
= NULL
;
1851 char tpath
[PATH_MAX
];
1854 if ((dir
= opendir(path
)) == NULL
)
1857 while ((d
= readdir(dir
)) != NULL
) {
1858 if ((strcmp(d
->d_name
, ".") != 0) &&
1859 (strcmp(d
->d_name
, "..") != 0)) {
1860 (void) snprintf(tpath
, sizeof (tpath
), "%s/%s",
1862 if (stat(tpath
, &sb
) == 0) {
1863 if (sb
.st_mode
& S_IFDIR
)
1864 (void) rmdir_r(tpath
);
1866 (void) remove(tpath
);
1870 return (remove(path
));
1874 * Check if cache directory exists and, if not, create it and update flags
1875 * accordingly. If the path exists, but it's not a directory, a best effort
1876 * attempt to remove and recreate it is made.
1877 * If the user requested a 'purge', always recreate the directory from scratch.
1880 set_cache_dir(char *root
, int what
)
1885 ret
= snprintf(get_cachedir(what
), sizeof (get_cachedir(what
)),
1886 "%s%s%s%s%s", root
, ARCHIVE_PREFIX
, get_machine(), what
== FILE64
?
1887 "/amd64" : "", CACHEDIR_SUFFIX
);
1889 if (ret
>= sizeof (get_cachedir(what
))) {
1890 bam_error(_("unable to create path on mountpoint %s, "
1891 "path too long\n"), rootbuf
);
1895 if (bam_purge
|| is_flag_on(INVALIDATE_CACHE
))
1896 (void) rmdir_r(get_cachedir(what
));
1898 if (stat(get_cachedir(what
), &sb
) != 0 || !(S_ISDIR(sb
.st_mode
))) {
1899 /* best effort unlink attempt, mkdir will catch errors */
1900 (void) unlink(get_cachedir(what
));
1903 bam_print(_("archive cache directory not found: %s\n"),
1904 get_cachedir(what
));
1905 ret
= mkdir(get_cachedir(what
), DIR_PERMS
);
1907 bam_error(_("mkdir of %s failed: %s\n"),
1908 get_cachedir(what
), strerror(errno
));
1909 get_cachedir(what
)[0] = '\0';
1912 set_flag(NEED_CACHE_DIR
);
1915 return (BAM_SUCCESS
);
1919 is_valid_archive(char *root
, int what
)
1921 char archive_path
[PATH_MAX
];
1922 char timestamp_path
[PATH_MAX
];
1923 struct stat sb
, timestamp
;
1926 if (what
== FILE64
&& !is_flag_on(IS_SPARC_TARGET
))
1927 ret
= snprintf(archive_path
, sizeof (archive_path
),
1928 "%s%s%s/amd64%s", root
, ARCHIVE_PREFIX
, get_machine(),
1931 ret
= snprintf(archive_path
, sizeof (archive_path
), "%s%s%s%s",
1932 root
, ARCHIVE_PREFIX
, get_machine(), ARCHIVE_SUFFIX
);
1934 if (ret
>= sizeof (archive_path
)) {
1935 bam_error(_("unable to create path on mountpoint %s, "
1936 "path too long\n"), rootbuf
);
1940 if (stat(archive_path
, &sb
) != 0) {
1941 if (bam_verbose
&& !bam_check
)
1942 bam_print(_("archive not found: %s\n"), archive_path
);
1943 set_dir_flag(what
, NEED_UPDATE
);
1944 return (BAM_SUCCESS
);
1948 * The timestamp file is used to prevent stale files in the archive
1950 * Stale files can happen if the system is booted back and forth across
1951 * the transition from bootadm-before-the-cache to
1952 * bootadm-after-the-cache, since older versions of bootadm don't know
1953 * about the existence of the archive cache.
1955 * Since only bootadm-after-the-cache versions know about about this
1956 * file, we require that the boot archive be older than this file.
1958 ret
= snprintf(timestamp_path
, sizeof (timestamp_path
), "%s%s", root
,
1959 FILE_STAT_TIMESTAMP
);
1961 if (ret
>= sizeof (timestamp_path
)) {
1962 bam_error(_("unable to create path on mountpoint %s, "
1963 "path too long\n"), rootbuf
);
1967 if (stat(timestamp_path
, ×tamp
) != 0 ||
1968 sb
.st_mtime
> timestamp
.st_mtime
) {
1969 if (bam_verbose
&& !bam_check
)
1971 _("archive cache is out of sync. Rebuilding.\n"));
1973 * Don't generate a false positive for the boot-archive service
1974 * but trigger an update of the archive cache in
1975 * boot-archive-update.
1977 if (bam_smf_check
) {
1978 (void) creat(NEED_UPDATE_FILE
, 0644);
1979 return (BAM_SUCCESS
);
1982 set_flag(INVALIDATE_CACHE
);
1983 set_dir_flag(what
, NEED_UPDATE
);
1984 return (BAM_SUCCESS
);
1987 return (BAM_SUCCESS
);
1991 * Check flags and presence of required files and directories.
1992 * The force flag and/or absence of files should
1993 * trigger an update.
1994 * Suppress stdout output if check (-n) option is set
1995 * (as -n should only produce parseable output.)
1998 check_flags_and_files(char *root
)
2005 * If archive is missing, create archive
2007 if (is_flag_on(IS_SPARC_TARGET
)) {
2008 ret
= is_valid_archive(root
, FILE64
);
2009 if (ret
== BAM_ERROR
)
2014 ret
= is_valid_archive(root
, what
);
2015 if (ret
== BAM_ERROR
)
2018 } while (bam_direct
== BAM_DIRECT_DBOOT
&& what
< CACHEDIR_NUM
);
2022 return (BAM_SUCCESS
);
2026 * check if cache directories exist on x86.
2027 * check (and always open) the cache file on SPARC.
2030 ret
= snprintf(get_cachedir(FILE64
),
2031 sizeof (get_cachedir(FILE64
)), "%s%s%s/%s", root
,
2032 ARCHIVE_PREFIX
, get_machine(), CACHEDIR_SUFFIX
);
2034 if (ret
>= sizeof (get_cachedir(FILE64
))) {
2035 bam_error(_("unable to create path on mountpoint %s, "
2036 "path too long\n"), rootbuf
);
2040 if (stat(get_cachedir(FILE64
), &sb
) != 0) {
2041 set_flag(NEED_CACHE_DIR
);
2042 set_dir_flag(FILE64
, NEED_UPDATE
);
2045 walk_arg
.sparcfile
= fopen(get_cachedir(FILE64
), "w");
2046 if (walk_arg
.sparcfile
== NULL
) {
2047 bam_error(_("failed to open file: %s: %s\n"),
2048 get_cachedir(FILE64
), strerror(errno
));
2052 set_dir_present(FILE64
);
2057 if (set_cache_dir(root
, what
) != 0)
2060 set_dir_present(what
);
2063 } while (bam_direct
== BAM_DIRECT_DBOOT
&& what
< CACHEDIR_NUM
);
2067 * if force, create archive unconditionally
2071 set_dir_flag(FILE32
, NEED_UPDATE
);
2072 set_dir_flag(FILE64
, NEED_UPDATE
);
2074 bam_print(_("forced update of archive requested\n"));
2077 return (BAM_SUCCESS
);
2081 read_one_list(char *root
, filelist_t
*flistp
, char *filelist
)
2083 char path
[PATH_MAX
];
2085 char buf
[BAM_MAXLINE
];
2086 const char *fcn
= "read_one_list()";
2088 (void) snprintf(path
, sizeof (path
), "%s%s", root
, filelist
);
2090 fp
= fopen(path
, "r");
2092 BAM_DPRINTF(("%s: failed to open archive filelist: %s: %s\n",
2093 fcn
, path
, strerror(errno
)));
2096 while (s_fgets(buf
, sizeof (buf
), fp
) != NULL
) {
2097 /* skip blank lines */
2098 if (strspn(buf
, " \t") == strlen(buf
))
2100 append_to_flist(flistp
, buf
);
2102 if (fclose(fp
) != 0) {
2103 bam_error(_("failed to close file: %s: %s\n"),
2104 path
, strerror(errno
));
2107 return (BAM_SUCCESS
);
2111 read_list(char *root
, filelist_t
*flistp
)
2113 char path
[PATH_MAX
];
2117 const char *fcn
= "read_list()";
2119 flistp
->head
= flistp
->tail
= NULL
;
2122 * build and check path to extract_boot_filelist.ksh
2124 n
= snprintf(path
, sizeof (path
), "%s%s", root
, EXTRACT_BOOT_FILELIST
);
2125 if (n
>= sizeof (path
)) {
2126 bam_error(_("archive filelist is empty\n"));
2130 if (is_safe_exec(path
) == BAM_ERROR
)
2134 * If extract_boot_filelist is present, exec it, otherwise read
2135 * the filelists directly, for compatibility with older images.
2137 if (stat(path
, &sb
) == 0) {
2139 * build arguments to exec extract_boot_filelist.ksh
2141 char *rootarg
, *platarg
;
2142 int platarglen
= 1, rootarglen
= 1;
2143 if (strlen(root
) > 1)
2144 rootarglen
+= strlen(root
) + strlen("-R ");
2145 if (bam_alt_platform
)
2146 platarglen
+= strlen(bam_platform
) + strlen("-p ");
2147 platarg
= s_calloc(1, platarglen
);
2148 rootarg
= s_calloc(1, rootarglen
);
2152 if (strlen(root
) > 1) {
2153 (void) snprintf(rootarg
, rootarglen
,
2156 if (bam_alt_platform
) {
2157 (void) snprintf(platarg
, platarglen
,
2158 "-p %s", bam_platform
);
2160 n
= snprintf(cmd
, sizeof (cmd
), "%s %s %s /%s /%s",
2161 path
, rootarg
, platarg
, BOOT_FILE_LIST
, ETC_FILE_LIST
);
2164 if (n
>= sizeof (cmd
)) {
2165 bam_error(_("archive filelist is empty\n"));
2168 if (exec_cmd(cmd
, flistp
) != 0) {
2169 BAM_DPRINTF(("%s: failed to open archive "
2170 "filelist: %s: %s\n", fcn
, path
, strerror(errno
)));
2175 * Read current lists of files - only the first is mandatory
2177 rval
= read_one_list(root
, flistp
, BOOT_FILE_LIST
);
2178 if (rval
!= BAM_SUCCESS
)
2180 (void) read_one_list(root
, flistp
, ETC_FILE_LIST
);
2183 if (flistp
->head
== NULL
) {
2184 bam_error(_("archive filelist is empty\n"));
2188 return (BAM_SUCCESS
);
2192 getoldstat(char *root
)
2194 char path
[PATH_MAX
];
2199 (void) snprintf(path
, sizeof (path
), "%s%s", root
, FILE_STAT
);
2200 fd
= open(path
, O_RDONLY
);
2203 bam_print(_("failed to open file: %s: %s\n"),
2204 path
, strerror(errno
));
2208 if (fstat(fd
, &sb
) != 0) {
2209 bam_error(_("stat of file failed: %s: %s\n"), path
,
2214 ostat
= s_calloc(1, sb
.st_size
);
2216 if (read(fd
, ostat
, sb
.st_size
) != sb
.st_size
) {
2217 bam_error(_("read failed for file: %s: %s\n"), path
,
2226 walk_arg
.old_nvlp
= NULL
;
2227 error
= nvlist_unpack(ostat
, sb
.st_size
, &walk_arg
.old_nvlp
, 0);
2232 bam_error(_("failed to unpack stat data: %s: %s\n"),
2233 path
, strerror(error
));
2234 walk_arg
.old_nvlp
= NULL
;
2243 if (!is_flag_on(IS_SPARC_TARGET
))
2244 set_dir_flag(FILE32
, NEED_UPDATE
);
2245 set_dir_flag(FILE64
, NEED_UPDATE
);
2248 /* Best effort stale entry removal */
2250 delete_stale(char *file
, int what
)
2252 char path
[PATH_MAX
];
2255 (void) snprintf(path
, sizeof (path
), "%s/%s", get_cachedir(what
), file
);
2256 if (!bam_check
&& stat(path
, &sb
) == 0) {
2257 if (sb
.st_mode
& S_IFDIR
)
2258 (void) rmdir_r(path
);
2260 (void) unlink(path
);
2262 set_dir_flag(what
, NEED_UPDATE
);
2267 * Checks if a file in the current (old) archive has
2268 * been deleted from the root filesystem.
2271 check4stale(char *root
)
2276 char path
[PATH_MAX
];
2279 * Skip stale file check during smf check
2285 * If we need to (re)create the cache, there's no need to check for
2288 if (is_flag_on(NEED_CACHE_DIR
))
2291 /* Nothing to do if no old stats */
2292 if ((nvlp
= walk_arg
.old_nvlp
) == NULL
)
2295 for (nvp
= nvlist_next_nvpair(nvlp
, NULL
); nvp
;
2296 nvp
= nvlist_next_nvpair(nvlp
, nvp
)) {
2297 file
= nvpair_name(nvp
);
2300 (void) snprintf(path
, sizeof (path
), "%s/%s",
2302 if (access(path
, F_OK
) < 0) {
2306 bam_print(_(" stale %s\n"), path
);
2308 if (is_flag_on(IS_SPARC_TARGET
)) {
2309 set_dir_flag(FILE64
, NEED_UPDATE
);
2311 for (what
= FILE32
; what
< CACHEDIR_NUM
; what
++)
2312 if (has_cachedir(what
))
2313 delete_stale(file
, what
);
2320 create_newstat(void)
2324 error
= nvlist_alloc(&walk_arg
.new_nvlp
, NV_UNIQUE_NAME
, 0);
2327 * Not fatal - we can still create archive
2329 walk_arg
.new_nvlp
= NULL
;
2330 bam_error(_("failed to create stat data: %s\n"),
2336 walk_list(char *root
, filelist_t
*flistp
)
2338 char path
[PATH_MAX
];
2341 for (lp
= flistp
->head
; lp
; lp
= lp
->next
) {
2343 * Don't follow symlinks. A symlink must refer to
2344 * a file that would appear in the archive through
2345 * a direct reference. This matches the archive
2346 * construction behavior.
2348 (void) snprintf(path
, sizeof (path
), "%s%s", root
, lp
->line
);
2349 if (nftw(path
, cmpstat
, 20, FTW_PHYS
) == -1) {
2350 if (is_flag_on(UPDATE_ERROR
))
2353 * Some files may not exist.
2354 * For example: etc/rtc_config on a x86 diskless system
2355 * Emit verbose message only
2358 bam_print(_("cannot find: %s: %s\n"),
2359 path
, strerror(errno
));
2363 return (BAM_SUCCESS
);
2367 * Update the timestamp file.
2370 update_timestamp(char *root
)
2372 char timestamp_path
[PATH_MAX
];
2374 /* this path length has already been checked in check_flags_and_files */
2375 (void) snprintf(timestamp_path
, sizeof (timestamp_path
), "%s%s", root
,
2376 FILE_STAT_TIMESTAMP
);
2379 * recreate the timestamp file. Since an outdated or absent timestamp
2380 * file translates in a complete rebuild of the archive cache, notify
2381 * the user of the performance issue.
2383 if (creat(timestamp_path
, FILE_STAT_MODE
) < 0) {
2384 bam_error(_("failed to open file: %s: %s\n"), timestamp_path
,
2386 bam_error(_("failed to update the timestamp file, next"
2387 " archive update may experience reduced performance\n"));
2395 char path
[PATH_MAX
];
2396 char path2
[PATH_MAX
];
2399 int fd
, wrote
, error
;
2403 error
= nvlist_pack(walk_arg
.new_nvlp
, &nstat
, &sz
,
2406 bam_error(_("failed to pack stat data: %s\n"),
2411 (void) snprintf(path
, sizeof (path
), "%s%s", root
, FILE_STAT_TMP
);
2412 fd
= open(path
, O_RDWR
|O_CREAT
|O_TRUNC
, FILE_STAT_MODE
);
2414 bam_error(_("failed to open file: %s: %s\n"), path
,
2419 wrote
= write(fd
, nstat
, sz
);
2421 bam_error(_("write to file failed: %s: %s\n"), path
,
2430 (void) snprintf(path2
, sizeof (path2
), "%s%s", root
, FILE_STAT
);
2431 if (rename(path
, path2
) != 0) {
2432 bam_error(_("rename to file failed: %s: %s\n"), path2
,
2437 #define init_walk_args() bzero(&walk_arg, sizeof (walk_arg))
2440 clear_walk_args(void)
2442 nvlist_free(walk_arg
.old_nvlp
);
2443 nvlist_free(walk_arg
.new_nvlp
);
2444 if (walk_arg
.sparcfile
)
2445 (void) fclose(walk_arg
.sparcfile
);
2446 walk_arg
.old_nvlp
= NULL
;
2447 walk_arg
.new_nvlp
= NULL
;
2448 walk_arg
.sparcfile
= NULL
;
2453 * 0 - no update necessary
2454 * 1 - update required.
2455 * BAM_ERROR (-1) - An error occurred
2457 * Special handling for check (-n):
2458 * ================================
2459 * The check (-n) option produces parseable output.
2460 * To do this, we suppress all stdout messages unrelated
2461 * to out of sync files.
2462 * All stderr messages are still printed though.
2466 update_required(char *root
)
2469 char path
[PATH_MAX
];
2471 filelist_t
*flistp
= &flist
;
2474 flistp
->head
= flistp
->tail
= NULL
;
2477 set_flag(IS_SPARC_TARGET
);
2480 * Check if cache directories and archives are present
2483 ret
= check_flags_and_files(root
);
2488 * In certain deployment scenarios, filestat may not
2489 * exist. Do not stop the boot process, but trigger an update
2490 * of the archives (which will recreate filestat.ramdisk).
2492 if (bam_smf_check
) {
2493 (void) snprintf(path
, sizeof (path
), "%s%s", root
, FILE_STAT
);
2494 if (stat(path
, &sb
) != 0) {
2495 (void) creat(NEED_UPDATE_FILE
, 0644);
2503 * Check if the archive contains files that are no longer
2504 * present on the root filesystem.
2509 * read list of files
2511 if (read_list(root
, flistp
) != BAM_SUCCESS
) {
2516 assert(flistp
->head
&& flistp
->tail
);
2519 * At this point either the update is required
2520 * or the decision is pending. In either case
2521 * we need to create new stat nvlist
2525 * This walk does 2 things:
2526 * - gets new stat data for every file
2527 * - (optional) compare old and new stat data
2529 ret
= walk_list(root
, &flist
);
2531 /* done with the file list */
2532 filelist_free(flistp
);
2534 /* something went wrong */
2536 if (ret
== BAM_ERROR
) {
2537 bam_error(_("Failed to gather cache files, archives "
2538 "generation aborted\n"));
2542 if (walk_arg
.new_nvlp
== NULL
) {
2543 if (walk_arg
.sparcfile
!= NULL
)
2544 (void) fclose(walk_arg
.sparcfile
);
2545 bam_error(_("cannot create new stat data\n"));
2548 /* If nothing was updated, discard newstat. */
2550 if (!is_dir_flag_on(FILE32
, NEED_UPDATE
) &&
2551 !is_dir_flag_on(FILE64
, NEED_UPDATE
)) {
2556 if (walk_arg
.sparcfile
!= NULL
)
2557 (void) fclose(walk_arg
.sparcfile
);
2566 libzfs_handle_t
*hdl
;
2567 be_node_list_t
*be_nodes
= NULL
;
2568 be_node_list_t
*cur_be
;
2569 boolean_t be_exist
= B_FALSE
;
2570 char ds_path
[ZFS_MAX_DATASET_NAME_LEN
];
2575 * Get dataset for mountpoint
2577 if ((hdl
= libzfs_init()) == NULL
)
2580 if ((zhp
= zfs_path_to_zhandle(hdl
, root
,
2581 ZFS_TYPE_FILESYSTEM
)) == NULL
) {
2586 (void) strlcpy(ds_path
, zfs_get_name(zhp
), sizeof (ds_path
));
2589 * Check if the current dataset is BE
2591 if (be_list(NULL
, &be_nodes
) == BE_SUCCESS
) {
2592 for (cur_be
= be_nodes
; cur_be
!= NULL
;
2593 cur_be
= cur_be
->be_next_node
) {
2596 * Because we guarantee that cur_be->be_root_ds
2597 * is null-terminated by internal data structure,
2598 * we can safely use strcmp()
2600 if (strcmp(ds_path
, cur_be
->be_root_ds
) == 0) {
2605 be_free_list(be_nodes
);
2614 create_ramdisk(char *root
)
2616 char *cmdline
, path
[PATH_MAX
];
2621 * Setup command args for create_ramdisk.ksh for the cpio archives
2622 * Note: we will not create hash here, CREATE_RAMDISK should create it.
2625 (void) snprintf(path
, sizeof (path
), "%s/%s", root
, CREATE_RAMDISK
);
2626 if (stat(path
, &sb
) != 0) {
2627 bam_error(_("archive creation file not found: %s: %s\n"),
2628 path
, strerror(errno
));
2632 if (is_safe_exec(path
) == BAM_ERROR
)
2635 len
= strlen(path
) + strlen(root
) + 10; /* room for space + -R */
2636 if (bam_alt_platform
)
2637 len
+= strlen(bam_platform
) + strlen("-p ");
2638 cmdline
= s_calloc(1, len
);
2640 if (bam_alt_platform
) {
2641 assert(strlen(root
) > 1);
2642 (void) snprintf(cmdline
, len
, "%s -p %s -R %s",
2643 path
, bam_platform
, root
);
2644 /* chop off / at the end */
2645 cmdline
[strlen(cmdline
) - 1] = '\0';
2646 } else if (strlen(root
) > 1) {
2647 (void) snprintf(cmdline
, len
, "%s -R %s", path
, root
);
2648 /* chop off / at the end */
2649 cmdline
[strlen(cmdline
) - 1] = '\0';
2651 (void) snprintf(cmdline
, len
, "%s", path
);
2653 if (exec_cmd(cmdline
, NULL
) != 0) {
2654 bam_error(_("boot-archive creation FAILED, command: '%s'\n"),
2661 * The existence of the expected archives used to be
2662 * verified here. This check is done in create_ramdisk as
2663 * it needs to be in sync with the altroot operated upon.
2665 return (BAM_SUCCESS
);
2669 * Checks if target filesystem is on a ramdisk
2672 * When in doubt assume it is not a ramdisk.
2675 is_ramdisk(char *root
)
2677 struct extmnttab mnt
;
2680 char mntpt
[PATH_MAX
];
2684 * There are 3 situations where creating archive is
2686 * - create boot_archive on a lofi-mounted boot_archive
2687 * - create it on a ramdisk which is the root filesystem
2688 * - create it on a ramdisk mounted somewhere else
2689 * The first is not easy to detect and checking for it is not
2691 * The other two conditions are handled here
2693 fp
= fopen(MNTTAB
, "r");
2695 bam_error(_("failed to open file: %s: %s\n"),
2696 MNTTAB
, strerror(errno
));
2703 * Remove any trailing / from the mount point
2705 (void) strlcpy(mntpt
, root
, sizeof (mntpt
));
2706 if (strcmp(root
, "/") != 0) {
2707 cp
= mntpt
+ strlen(mntpt
) - 1;
2712 while (getextmntent(fp
, &mnt
, sizeof (mnt
)) == 0) {
2713 if (strcmp(mnt
.mnt_mountp
, mntpt
) == 0) {
2721 bam_error(_("alternate root %s not in mnttab\n"),
2727 if (strncmp(mnt
.mnt_special
, RAMDISK_SPECIAL
,
2728 strlen(RAMDISK_SPECIAL
)) == 0) {
2730 bam_error(_("%s is on a ramdisk device\n"), bam_root
);
2741 is_boot_archive(char *root
)
2743 char path
[PATH_MAX
];
2746 const char *fcn
= "is_boot_archive()";
2749 * We can't create an archive without the create_ramdisk script
2751 (void) snprintf(path
, sizeof (path
), "%s/%s", root
, CREATE_RAMDISK
);
2752 error
= stat(path
, &sb
);
2753 INJECT_ERROR1("NOT_ARCHIVE_BASED", error
= -1);
2756 bam_print(_("file not found: %s\n"), path
);
2757 BAM_DPRINTF(("%s: not a boot archive based Solaris "
2758 "instance: %s\n", fcn
, root
));
2762 BAM_DPRINTF(("%s: *IS* a boot archive based Solaris instance: %s\n",
2772 const char *fcn
= "is_zfs()";
2774 ret
= statvfs(root
, &vfs
);
2775 INJECT_ERROR1("STATVFS_ZFS", ret
= 1);
2777 bam_error(_("statvfs failed for %s: %s\n"), root
,
2782 if (strncmp(vfs
.f_basetype
, "zfs", strlen("zfs")) == 0) {
2783 BAM_DPRINTF(("%s: is a ZFS filesystem: %s\n", fcn
, root
));
2786 BAM_DPRINTF(("%s: is *NOT* a ZFS filesystem: %s\n", fcn
, root
));
2792 is_readonly(char *root
)
2796 char testfile
[PATH_MAX
];
2797 const char *fcn
= "is_readonly()";
2800 * Using statvfs() to check for a read-only filesystem is not
2801 * reliable. The only way to reliably test is to attempt to
2804 (void) snprintf(testfile
, sizeof (testfile
), "%s/%s.%d",
2805 root
, BOOTADM_RDONLY_TEST
, getpid());
2807 (void) unlink(testfile
);
2810 fd
= open(testfile
, O_RDWR
|O_CREAT
|O_EXCL
, 0644);
2812 INJECT_ERROR2("RDONLY_TEST_ERROR", fd
= -1, error
= EACCES
);
2813 if (fd
== -1 && error
== EROFS
) {
2814 BAM_DPRINTF(("%s: is a READONLY filesystem: %s\n", fcn
, root
));
2816 } else if (fd
== -1) {
2817 bam_error(_("error during read-only test on %s: %s\n"),
2818 root
, strerror(error
));
2822 (void) unlink(testfile
);
2824 BAM_DPRINTF(("%s: is a RDWR filesystem: %s\n", fcn
, root
));
2829 update_archive(char *root
, char *opt
)
2834 assert(opt
== NULL
);
2840 * Never update non-BE root in update_all
2842 if (!is_be(root
) && bam_update_all
)
2843 return (BAM_SUCCESS
);
2845 * root must belong to a boot archive based OS,
2847 if (!is_boot_archive(root
)) {
2849 * Emit message only if not in context of update_all.
2850 * If in update_all, emit only if verbose flag is set.
2852 if (!bam_update_all
|| bam_verbose
)
2853 bam_print(_("%s: not a boot archive based Solaris "
2854 "instance\n"), root
);
2859 * If smf check is requested when / is writable (can happen
2860 * on first reboot following an upgrade because service
2861 * dependency is messed up), skip the check.
2863 if (bam_smf_check
&& !bam_root_readonly
&& !is_zfs(root
))
2864 return (BAM_SUCCESS
);
2867 * Don't generate archive on ramdisk.
2869 if (is_ramdisk(root
))
2870 return (BAM_SUCCESS
);
2873 * root must be writable. This check applies to alternate
2874 * root (-R option); bam_root_readonly applies to '/' only.
2875 * The behaviour translates into being the one of a 'check'.
2877 if (!bam_smf_check
&& !bam_check
&& is_readonly(root
)) {
2878 set_flag(RDONLY_FSCHK
);
2883 * Now check if an update is really needed.
2885 ret
= update_required(root
);
2888 * The check command (-n) is *not* a dry run.
2889 * It only checks if the archive is in sync.
2890 * A readonly filesystem has to be considered an error only if an update
2893 if (bam_nowrite()) {
2894 if (is_flag_on(RDONLY_FSCHK
)) {
2895 bam_check
= bam_saved_check
;
2897 bam_error(_("%s filesystem is read-only, "
2898 "skipping archives update\n"), root
);
2900 return ((ret
!= 0) ? BAM_ERROR
: BAM_SUCCESS
);
2903 bam_exit((ret
!= 0) ? 1 : 0);
2907 /* create the ramdisk */
2908 ret
= create_ramdisk(root
);
2912 * if the archive is updated, save the new stat data and update the
2915 if (ret
== 0 && walk_arg
.new_nvlp
!= NULL
) {
2917 update_timestamp(root
);
2926 update_all(char *root
, char *opt
)
2928 struct extmnttab mnt
;
2931 char multibt
[PATH_MAX
];
2932 char creatram
[PATH_MAX
];
2933 error_t ret
= BAM_SUCCESS
;
2936 assert(opt
== NULL
);
2938 if (bam_rootlen
!= 1 || *root
!= '/') {
2939 elide_trailing_slash(root
, multibt
, sizeof (multibt
));
2940 bam_error(_("an alternate root (%s) cannot be used with this "
2941 "sub-command\n"), multibt
);
2946 * First update archive for current root
2948 if (update_archive(root
, opt
) != BAM_SUCCESS
)
2951 if (ret
== BAM_ERROR
)
2955 * Now walk the mount table, performing archive update
2956 * for all mounted Newboot root filesystems
2958 fp
= fopen(MNTTAB
, "r");
2960 bam_error(_("failed to open file: %s: %s\n"),
2961 MNTTAB
, strerror(errno
));
2968 while (getextmntent(fp
, &mnt
, sizeof (mnt
)) == 0) {
2969 if (mnt
.mnt_special
== NULL
)
2971 if ((strcmp(mnt
.mnt_fstype
, MNTTYPE_ZFS
) != 0) &&
2972 (strncmp(mnt
.mnt_special
, "/dev/", strlen("/dev/")) != 0))
2974 if (strcmp(mnt
.mnt_mountp
, "/") == 0)
2977 (void) snprintf(creatram
, sizeof (creatram
), "%s/%s",
2978 mnt
.mnt_mountp
, CREATE_RAMDISK
);
2980 if (stat(creatram
, &sb
) == -1)
2984 * We put a trailing slash to be consistent with root = "/"
2985 * case, such that we don't have to print // in some cases.
2987 (void) snprintf(rootbuf
, sizeof (rootbuf
), "%s/",
2989 bam_rootlen
= strlen(rootbuf
);
2992 * It's possible that other mounts may be an alternate boot
2993 * architecture, so check it again.
2995 if ((get_boot_cap(rootbuf
) != BAM_SUCCESS
) ||
2996 (update_archive(rootbuf
, opt
) != BAM_SUCCESS
))
3004 * We no longer use biosdev for Live Upgrade. Hence
3005 * there is no need to defer (to shutdown time) any fdisk
3008 if (stat(GRUB_fdisk
, &sb
) == 0 || stat(GRUB_fdisk_target
, &sb
) == 0) {
3009 bam_error(_("Deferred FDISK update file(s) found: %s, %s. "
3010 "Not supported.\n"), GRUB_fdisk
, GRUB_fdisk_target
);
3017 get_mountpoint(char *special
, char *fstype
)
3020 struct mnttab mp
= {0};
3021 struct mnttab mpref
= {0};
3024 const char *fcn
= "get_mountpoint()";
3026 BAM_DPRINTF(("%s: entered. args: %s %s\n", fcn
, special
, fstype
));
3028 mntfp
= fopen(MNTTAB
, "r");
3030 INJECT_ERROR1("MNTTAB_ERR_GET_MNTPT", mntfp
= NULL
);
3031 if (mntfp
== NULL
) {
3032 bam_error(_("failed to open file: %s: %s\n"),
3033 MNTTAB
, strerror(error
));
3037 mpref
.mnt_special
= special
;
3038 mpref
.mnt_fstype
= fstype
;
3040 ret
= getmntany(mntfp
, &mp
, &mpref
);
3041 INJECT_ERROR1("GET_MOUNTPOINT_MNTANY", ret
= 1);
3043 (void) fclose(mntfp
);
3044 BAM_DPRINTF(("%s: no mount-point for special=%s and "
3045 "fstype=%s\n", fcn
, special
, fstype
));
3048 (void) fclose(mntfp
);
3050 assert(mp
.mnt_mountp
);
3052 BAM_DPRINTF(("%s: returning mount-point for special %s: %s\n",
3053 fcn
, special
, mp
.mnt_mountp
));
3055 return (s_strdup(mp
.mnt_mountp
));
3059 * Mounts a "legacy" top dataset (if needed)
3060 * Returns: The mountpoint of the legacy top dataset or NULL on error
3061 * mnted returns one of the above values defined for zfs_mnted_t
3064 mount_legacy_dataset(char *pool
, zfs_mnted_t
*mnted
)
3067 char tmpmnt
[PATH_MAX
];
3068 filelist_t flist
= {0};
3072 const char *fcn
= "mount_legacy_dataset()";
3074 BAM_DPRINTF(("%s: entered. arg: %s\n", fcn
, pool
));
3076 *mnted
= ZFS_MNT_ERROR
;
3078 (void) snprintf(cmd
, sizeof (cmd
),
3079 "/sbin/zfs get -Ho value mounted %s",
3082 ret
= exec_cmd(cmd
, &flist
);
3083 INJECT_ERROR1("Z_MOUNT_LEG_GET_MOUNTED_CMD", ret
= 1);
3085 bam_error(_("failed to determine mount status of ZFS "
3086 "pool %s\n"), pool
);
3090 INJECT_ERROR1("Z_MOUNT_LEG_GET_MOUNTED_OUT", flist
.head
= NULL
);
3091 if ((flist
.head
== NULL
) || (flist
.head
!= flist
.tail
)) {
3092 bam_error(_("ZFS pool %s has bad mount status\n"), pool
);
3093 filelist_free(&flist
);
3097 is_mounted
= strtok(flist
.head
->line
, " \t\n");
3098 INJECT_ERROR1("Z_MOUNT_LEG_GET_MOUNTED_STRTOK_YES", is_mounted
= "yes");
3099 INJECT_ERROR1("Z_MOUNT_LEG_GET_MOUNTED_STRTOK_NO", is_mounted
= "no");
3100 if (strcmp(is_mounted
, "no") != 0) {
3101 filelist_free(&flist
);
3102 *mnted
= LEGACY_ALREADY
;
3103 /* get_mountpoint returns a strdup'ed string */
3104 BAM_DPRINTF(("%s: legacy pool %s already mounted\n",
3106 return (get_mountpoint(pool
, "zfs"));
3109 filelist_free(&flist
);
3112 * legacy top dataset is not mounted. Mount it now
3113 * First create a mountpoint.
3115 (void) snprintf(tmpmnt
, sizeof (tmpmnt
), "%s.%d",
3116 ZFS_LEGACY_MNTPT
, getpid());
3118 ret
= stat(tmpmnt
, &sb
);
3120 BAM_DPRINTF(("%s: legacy pool %s mount-point %s absent\n",
3121 fcn
, pool
, tmpmnt
));
3122 ret
= mkdirp(tmpmnt
, DIR_PERMS
);
3123 INJECT_ERROR1("Z_MOUNT_TOP_LEG_MNTPT_MKDIRP", ret
= -1);
3125 bam_error(_("mkdir of %s failed: %s\n"), tmpmnt
,
3130 BAM_DPRINTF(("%s: legacy pool %s mount-point %s is already "
3131 "present\n", fcn
, pool
, tmpmnt
));
3134 (void) snprintf(cmd
, sizeof (cmd
),
3135 "/sbin/mount -F zfs %s %s",
3138 ret
= exec_cmd(cmd
, NULL
);
3139 INJECT_ERROR1("Z_MOUNT_TOP_LEG_MOUNT_CMD", ret
= 1);
3141 bam_error(_("mount of ZFS pool %s failed\n"), pool
);
3142 (void) rmdir(tmpmnt
);
3146 *mnted
= LEGACY_MOUNTED
;
3147 BAM_DPRINTF(("%s: legacy pool %s successfully mounted at %s\n",
3148 fcn
, pool
, tmpmnt
));
3149 return (s_strdup(tmpmnt
));
3153 * Mounts the top dataset (if needed)
3154 * Returns: The mountpoint of the top dataset or NULL on error
3155 * mnted returns one of the above values defined for zfs_mnted_t
3158 mount_top_dataset(char *pool
, zfs_mnted_t
*mnted
)
3161 filelist_t flist
= {0};
3166 const char *fcn
= "mount_top_dataset()";
3168 *mnted
= ZFS_MNT_ERROR
;
3170 BAM_DPRINTF(("%s: entered. arg: %s\n", fcn
, pool
));
3173 * First check if the top dataset is a "legacy" dataset
3175 (void) snprintf(cmd
, sizeof (cmd
),
3176 "/sbin/zfs get -Ho value mountpoint %s",
3178 ret
= exec_cmd(cmd
, &flist
);
3179 INJECT_ERROR1("Z_MOUNT_TOP_GET_MNTPT", ret
= 1);
3181 bam_error(_("failed to determine mount point of ZFS pool %s\n"),
3186 if (flist
.head
&& (flist
.head
== flist
.tail
)) {
3187 char *legacy
= strtok(flist
.head
->line
, " \t\n");
3188 if (legacy
&& strcmp(legacy
, "legacy") == 0) {
3189 filelist_free(&flist
);
3190 BAM_DPRINTF(("%s: is legacy, pool=%s\n", fcn
, pool
));
3191 return (mount_legacy_dataset(pool
, mnted
));
3195 filelist_free(&flist
);
3197 BAM_DPRINTF(("%s: is *NOT* legacy, pool=%s\n", fcn
, pool
));
3199 (void) snprintf(cmd
, sizeof (cmd
),
3200 "/sbin/zfs get -Ho value mounted %s",
3203 ret
= exec_cmd(cmd
, &flist
);
3204 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MOUNTED", ret
= 1);
3206 bam_error(_("failed to determine mount status of ZFS "
3207 "pool %s\n"), pool
);
3211 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MOUNTED_VAL", flist
.head
= NULL
);
3212 if ((flist
.head
== NULL
) || (flist
.head
!= flist
.tail
)) {
3213 bam_error(_("ZFS pool %s has bad mount status\n"), pool
);
3214 filelist_free(&flist
);
3218 is_mounted
= strtok(flist
.head
->line
, " \t\n");
3219 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MOUNTED_YES", is_mounted
= "yes");
3220 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MOUNTED_NO", is_mounted
= "no");
3221 if (strcmp(is_mounted
, "no") != 0) {
3222 filelist_free(&flist
);
3223 *mnted
= ZFS_ALREADY
;
3224 BAM_DPRINTF(("%s: non-legacy pool %s mounted already\n",
3229 filelist_free(&flist
);
3230 BAM_DPRINTF(("%s: non-legacy pool %s *NOT* already mounted\n",
3233 /* top dataset is not mounted. Mount it now */
3234 (void) snprintf(cmd
, sizeof (cmd
),
3235 "/sbin/zfs mount %s", pool
);
3236 ret
= exec_cmd(cmd
, NULL
);
3237 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_MOUNT_CMD", ret
= 1);
3239 bam_error(_("mount of ZFS pool %s failed\n"), pool
);
3242 *mnted
= ZFS_MOUNTED
;
3243 BAM_DPRINTF(("%s: non-legacy pool %s mounted now\n", fcn
, pool
));
3247 * Now get the mountpoint
3249 (void) snprintf(cmd
, sizeof (cmd
),
3250 "/sbin/zfs get -Ho value mountpoint %s",
3253 ret
= exec_cmd(cmd
, &flist
);
3254 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MNTPT_CMD", ret
= 1);
3256 bam_error(_("failed to determine mount point of ZFS pool %s\n"),
3261 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MNTPT_OUT", flist
.head
= NULL
);
3262 if ((flist
.head
== NULL
) || (flist
.head
!= flist
.tail
)) {
3263 bam_error(_("ZFS pool %s has no mount-point\n"), pool
);
3267 mntpt
= strtok(flist
.head
->line
, " \t\n");
3268 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MNTPT_STRTOK", mntpt
= "foo");
3269 if (*mntpt
!= '/') {
3270 bam_error(_("ZFS pool %s has bad mount-point %s\n"),
3274 zmntpt
= s_strdup(mntpt
);
3276 filelist_free(&flist
);
3278 BAM_DPRINTF(("%s: non-legacy pool %s is mounted at %s\n",
3279 fcn
, pool
, zmntpt
));
3284 filelist_free(&flist
);
3285 (void) umount_top_dataset(pool
, *mnted
, NULL
);
3286 BAM_DPRINTF(("%s: returning FAILURE\n", fcn
));
3291 umount_top_dataset(char *pool
, zfs_mnted_t mnted
, char *mntpt
)
3295 const char *fcn
= "umount_top_dataset()";
3297 INJECT_ERROR1("Z_UMOUNT_TOP_INVALID_STATE", mnted
= ZFS_MNT_ERROR
);
3299 case LEGACY_ALREADY
:
3302 BAM_DPRINTF(("%s: pool %s was already mounted at %s, Nothing "
3303 "to umount\n", fcn
, pool
, mntpt
? mntpt
: "NULL"));
3305 return (BAM_SUCCESS
);
3306 case LEGACY_MOUNTED
:
3307 (void) snprintf(cmd
, sizeof (cmd
),
3308 "/sbin/umount %s", pool
);
3309 ret
= exec_cmd(cmd
, NULL
);
3310 INJECT_ERROR1("Z_UMOUNT_TOP_LEGACY_UMOUNT_FAIL", ret
= 1);
3312 bam_error(_("umount of %s failed\n"), pool
);
3317 (void) rmdir(mntpt
);
3319 BAM_DPRINTF(("%s: legacy pool %s was mounted by us, "
3320 "successfully unmounted\n", fcn
, pool
));
3321 return (BAM_SUCCESS
);
3324 (void) snprintf(cmd
, sizeof (cmd
),
3325 "/sbin/zfs unmount %s", pool
);
3326 ret
= exec_cmd(cmd
, NULL
);
3327 INJECT_ERROR1("Z_UMOUNT_TOP_NONLEG_UMOUNT_FAIL", ret
= 1);
3329 bam_error(_("umount of %s failed\n"), pool
);
3332 BAM_DPRINTF(("%s: nonleg pool %s was mounted by us, "
3333 "successfully unmounted\n", fcn
, pool
));
3334 return (BAM_SUCCESS
);
3336 bam_error(_("Internal error: bad saved mount state for "
3337 "pool %s\n"), pool
);
3344 get_special(char *mountp
)
3347 struct mnttab mp
= {0};
3348 struct mnttab mpref
= {0};
3351 const char *fcn
= "get_special()";
3353 INJECT_ERROR1("GET_SPECIAL_MNTPT", mountp
= NULL
);
3354 if (mountp
== NULL
) {
3355 bam_error(_("cannot get special file: NULL mount-point\n"));
3359 mntfp
= fopen(MNTTAB
, "r");
3361 INJECT_ERROR1("GET_SPECIAL_MNTTAB_OPEN", mntfp
= NULL
);
3362 if (mntfp
== NULL
) {
3363 bam_error(_("failed to open file: %s: %s\n"), MNTTAB
,
3368 if (*mountp
== '\0')
3369 mpref
.mnt_mountp
= "/";
3371 mpref
.mnt_mountp
= mountp
;
3373 ret
= getmntany(mntfp
, &mp
, &mpref
);
3374 INJECT_ERROR1("GET_SPECIAL_MNTTAB_SEARCH", ret
= 1);
3376 (void) fclose(mntfp
);
3377 BAM_DPRINTF(("%s: Cannot get special file: mount-point %s "
3378 "not in mnttab\n", fcn
, mountp
));
3381 (void) fclose(mntfp
);
3383 BAM_DPRINTF(("%s: returning special: %s\n", fcn
, mp
.mnt_special
));
3385 return (s_strdup(mp
.mnt_special
));
3389 line_free(line_t
*lp
)
3402 linelist_free(line_t
*start
)
3408 start
= start
->next
;
3414 filelist_free(filelist_t
*flistp
)
3416 linelist_free(flistp
->head
);
3417 flistp
->head
= NULL
;
3418 flistp
->tail
= NULL
;
3427 * Returns 0 on success
3428 * Any other value indicates an error
3431 exec_cmd(char *cmdline
, filelist_t
*flistp
)
3441 * - only absolute paths are allowed
3442 * - set IFS to space and tab
3444 if (*cmdline
!= '/') {
3445 bam_error(_("path is not absolute: %s\n"), cmdline
);
3448 (void) putenv("IFS= \t");
3451 * We may have been exec'ed with SIGCHLD blocked
3454 (void) sigemptyset(&set
);
3455 (void) sigaddset(&set
, SIGCHLD
);
3456 if (sigprocmask(SIG_UNBLOCK
, &set
, NULL
) != 0) {
3457 bam_error(_("cannot unblock SIGCHLD: %s\n"), strerror(errno
));
3462 * Set SIGCHLD disposition to SIG_DFL for popen/pclose
3464 disp
= sigset(SIGCHLD
, SIG_DFL
);
3465 if (disp
== SIG_ERR
) {
3466 bam_error(_("cannot set SIGCHLD disposition: %s\n"),
3470 if (disp
== SIG_HOLD
) {
3471 bam_error(_("SIGCHLD signal blocked. Cannot exec: %s\n"),
3476 ptr
= popen(cmdline
, "r");
3478 bam_error(_("popen failed: %s: %s\n"), cmdline
,
3484 * If we simply do a pclose() following a popen(), pclose()
3485 * will close the reader end of the pipe immediately even
3486 * if the child process has not started/exited. pclose()
3487 * does wait for cmd to terminate before returning though.
3488 * When the executed command writes its output to the pipe
3489 * there is no reader process and the command dies with
3490 * SIGPIPE. To avoid this we read repeatedly until read
3491 * terminates with EOF. This indicates that the command
3492 * (writer) has closed the pipe and we can safely do a
3495 * Since pclose() does wait for the command to exit,
3496 * we can safely reap the exit status of the command
3497 * from the value returned by pclose()
3499 while (s_fgets(buf
, sizeof (buf
), ptr
) != NULL
) {
3500 if (flistp
== NULL
) {
3501 /* s_fgets strips newlines, so insert them at the end */
3502 bam_print(_("%s\n"), buf
);
3504 append_to_flist(flistp
, buf
);
3510 bam_error(_("pclose failed: %s: %s\n"), cmdline
,
3515 if (WIFEXITED(ret
)) {
3516 return (WEXITSTATUS(ret
));
3518 bam_error(_("command terminated abnormally: %s: %d\n"),
3525 * Since this function returns -1 on error
3526 * it cannot be used to convert -1. However,
3527 * that is sufficient for what we need.
3540 l
= strtol(str
, &res
, 10);
3541 if (errno
|| *res
!= '\0') {
3549 * Wrapper around fgets, that strips newlines returned by fgets
3552 s_fgets(char *buf
, int buflen
, FILE *fp
)
3556 buf
= fgets(buf
, buflen
, fp
);
3559 if (n
== buflen
- 1 && buf
[n
-1] != '\n')
3560 bam_error(_("the following line is too long "
3561 "(> %d chars)\n\t%s\n"), buflen
- 1, buf
);
3562 buf
[n
-1] = (buf
[n
-1] == '\n') ? '\0' : buf
[n
-1];
3569 s_calloc(size_t nelem
, size_t sz
)
3573 ptr
= calloc(nelem
, sz
);
3575 bam_error(_("could not allocate memory: size = %u\n"),
3583 s_realloc(void *ptr
, size_t sz
)
3585 ptr
= realloc(ptr
, sz
);
3587 bam_error(_("could not allocate memory: size = %u\n"), sz
);
3603 bam_error(_("could not allocate memory: size = %u\n"),
3611 * Returns 1 if amd64 (or sparc, for syncing x86 diskless clients)
3612 * Returns 0 otherwise
3617 static int amd64
= -1;
3618 char isabuf
[257]; /* from sysinfo(2) manpage */
3623 if (bam_alt_platform
) {
3624 if (strcmp(bam_platform
, "i86pc") == 0) {
3625 amd64
= 1; /* diskless server */
3628 if (sysinfo(SI_ISALIST
, isabuf
, sizeof (isabuf
)) > 0 &&
3629 strncmp(isabuf
, "amd64 ", strlen("amd64 ")) == 0) {
3631 } else if (strstr(isabuf
, "i386") == NULL
) {
3632 amd64
= 1; /* diskless server */
3644 static int cached
= -1;
3645 static char mbuf
[257]; /* from sysinfo(2) manpage */
3650 if (bam_alt_platform
) {
3651 return (bam_platform
);
3653 if (sysinfo(SI_MACHINE
, mbuf
, sizeof (mbuf
)) > 0) {
3668 static int issparc
= -1;
3669 char mbuf
[257]; /* from sysinfo(2) manpage */
3674 if (bam_alt_platform
) {
3675 if (strncmp(bam_platform
, "sun4", 4) == 0) {
3679 if (sysinfo(SI_ARCHITECTURE
, mbuf
, sizeof (mbuf
)) > 0 &&
3680 strcmp(mbuf
, "sparc") == 0) {
3691 append_to_flist(filelist_t
*flistp
, char *s
)
3695 lp
= s_calloc(1, sizeof (line_t
));
3696 lp
->line
= s_strdup(s
);
3697 if (flistp
->head
== NULL
)
3700 flistp
->tail
->next
= lp
;
3710 ucode_install(char *root
)
3714 for (i
= 0; ucode_vendors
[i
].filestr
!= NULL
; i
++) {
3715 int cmd_len
= PATH_MAX
+ 256;
3716 char cmd
[PATH_MAX
+ 256];
3717 char file
[PATH_MAX
];
3718 char timestamp
[PATH_MAX
];
3719 struct stat fstatus
, tstatus
;
3720 struct utimbuf u_times
;
3722 (void) snprintf(file
, PATH_MAX
, "%s/%s/%s-ucode.%s",
3723 bam_root
, UCODE_INSTALL_PATH
, ucode_vendors
[i
].filestr
,
3724 ucode_vendors
[i
].extstr
);
3726 if (stat(file
, &fstatus
) != 0 || !(S_ISREG(fstatus
.st_mode
)))
3729 (void) snprintf(timestamp
, PATH_MAX
, "%s.ts", file
);
3731 if (stat(timestamp
, &tstatus
) == 0 &&
3732 fstatus
.st_mtime
<= tstatus
.st_mtime
)
3735 (void) snprintf(cmd
, cmd_len
, "/usr/sbin/ucodeadm -i -R "
3736 "%s/%s/%s %s > /dev/null 2>&1", bam_root
,
3737 UCODE_INSTALL_PATH
, ucode_vendors
[i
].vendorstr
, file
);
3738 if (system(cmd
) != 0)
3741 if (creat(timestamp
, S_IRUSR
| S_IWUSR
) == -1)
3744 u_times
.actime
= fstatus
.st_atime
;
3745 u_times
.modtime
= fstatus
.st_mtime
;
3746 (void) utime(timestamp
, &u_times
);