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 "/dev/ramdisk/"
112 #define GRUBSIGN_DIR "/boot/grub/bootsign"
113 #define GRUBSIGN_BACKUP "/etc/bootsign"
114 #define GRUBSIGN_UFS_PREFIX "rootfs"
115 #define GRUBSIGN_ZFS_PREFIX "pool_"
116 #define GRUBSIGN_LU_PREFIX "BE_"
117 #define UFS_SIGNATURE_LIST "/var/run/grub_ufs_signatures"
118 #define ZFS_LEGACY_MNTPT "/tmp/bootadm_mnt_zfs_legacy"
121 #define BE_DEFAULTS "/etc/default/be"
122 #define BE_DFLT_BE_HAS_GRUB "BE_HAS_GRUB="
124 #define BOOTADM_RDONLY_TEST "BOOTADM_RDONLY_TEST"
127 #define BAM_LOCK_FILE "/var/run/bootadm.lock"
128 #define LOCK_FILE_PERMS (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
130 #define CREATE_RAMDISK "boot/solaris/bin/create_ramdisk"
131 #define CREATE_DISKMAP "boot/solaris/bin/create_diskmap"
132 #define EXTRACT_BOOT_FILELIST "boot/solaris/bin/extract_boot_filelist"
133 #define GRUBDISK_MAP "/var/run/solaris_grubdisk.map"
135 #define GRUB_slice "/etc/lu/GRUB_slice"
136 #define GRUB_root "/etc/lu/GRUB_root"
137 #define GRUB_fdisk "/etc/lu/GRUB_fdisk"
138 #define GRUB_fdisk_target "/etc/lu/GRUB_fdisk_target"
139 #define FINDROOT_INSTALLGRUB "/etc/lu/installgrub.findroot"
140 #define LULIB "/usr/lib/lu/lulib"
141 #define LULIB_PROPAGATE_FILE "lulib_propagate_file"
142 #define CKSUM "/usr/bin/cksum"
143 #define LU_MENU_CKSUM "/etc/lu/menu.cksum"
144 #define BOOTADM "/sbin/bootadm"
146 #define INSTALLGRUB "/sbin/installgrub"
147 #define STAGE1 "/boot/grub/stage1"
148 #define STAGE2 "/boot/grub/stage2"
151 * Default file attributes
153 #define DEFAULT_DEV_MODE 0644 /* default permissions */
154 #define DEFAULT_DEV_UID 0 /* user root */
155 #define DEFAULT_DEV_GID 3 /* group sys */
165 #define BOOT_FILE_LIST "boot/solaris/filelist.ramdisk"
166 #define ETC_FILE_LIST "etc/boot/solaris/filelist.ramdisk"
168 #define FILE_STAT "boot/solaris/filestat.ramdisk"
169 #define FILE_STAT_TMP "boot/solaris/filestat.ramdisk.tmp"
170 #define DIR_PERMS (S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
171 #define FILE_STAT_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
173 #define FILE_STAT_TIMESTAMP "boot/solaris/timestamp.cache"
180 static subcmd_t bam_cmd
;
183 static int bam_root_readonly
;
185 static int bam_extend
= 0;
186 static int bam_purge
= 0;
187 static char *bam_subcmd
;
188 static char *bam_opt
;
189 static char **bam_argv
;
190 static char *bam_pool
;
192 static int bam_check
;
193 static int bam_saved_check
;
194 static int bam_smf_check
;
195 static int bam_lock_fd
= -1;
198 char rootbuf
[PATH_MAX
] = "/";
199 static int bam_update_all
;
200 static int bam_alt_platform
;
201 static char *bam_platform
;
202 static char *bam_home_env
= NULL
;
204 /* function prototypes */
205 static void parse_args_internal(int, char *[]);
206 static void parse_args(int, char *argv
[]);
207 static error_t
bam_install(char *, char *);
208 static error_t
bam_archive(char *, char *);
210 static void bam_lock(void);
211 static void bam_unlock(void);
213 static int exec_cmd(char *, filelist_t
*);
214 static void linelist_free(line_t
*);
215 static void filelist_free(filelist_t
*);
217 static error_t
install_bootloader(void);
218 static error_t
update_archive(char *, char *);
219 static error_t
list_archive(char *, char *);
220 static error_t
update_all(char *, char *);
221 static error_t
read_list(char *, filelist_t
*);
223 static long s_strtol(char *);
225 static int is_amd64(void);
226 static char *get_machine(void);
227 static void append_to_flist(filelist_t
*, char *);
230 static void ucode_install();
234 /* Menu related sub commands */
235 static subcmd_defn_t menu_subcmds
[] = {
236 "set_option", OPT_ABSENT
, set_option
, 0, /* PUB */
237 "list_entry", OPT_OPTIONAL
, list_entry
, 1, /* PUB */
238 "delete_all_entries", OPT_ABSENT
, delete_all_entries
, 0, /* PVT */
239 "update_entry", OPT_REQ
, update_entry
, 0, /* menu */
240 "update_temp", OPT_OPTIONAL
, update_temp
, 0, /* reboot */
241 "upgrade", OPT_ABSENT
, upgrade_menu
, 0, /* menu */
242 "list_setting", OPT_OPTIONAL
, list_setting
, 1, /* menu */
243 "disable_hypervisor", OPT_ABSENT
, cvt_to_metal
, 0, /* menu */
244 "enable_hypervisor", OPT_ABSENT
, cvt_to_hyper
, 0, /* menu */
245 NULL
, 0, NULL
, 0 /* must be last */
249 /* Archive related sub commands */
250 static subcmd_defn_t arch_subcmds
[] = {
251 { "update", OPT_ABSENT
, update_archive
, 0 }, /* PUB */
252 { "update_all", OPT_ABSENT
, update_all
, 0 }, /* PVT */
253 { "list", OPT_OPTIONAL
, list_archive
, 1 }, /* PUB */
254 { NULL
, 0, NULL
, 0 } /* must be last */
257 /* Install related sub commands */
258 static subcmd_defn_t inst_subcmds
[] = {
259 { "install_bootloader", OPT_ABSENT
, install_bootloader
, 0 }, /* PUB */
260 { NULL
, 0, NULL
, 0 } /* must be last */
263 enum dircache_copy_opt
{
270 * Directory specific flags:
271 * NEED_UPDATE : the specified archive needs to be updated
272 * NO_MULTI : don't extend the specified archive, but recreate it
274 #define NEED_UPDATE 0x00000001
275 #define NO_MULTI 0x00000002
277 #define set_dir_flag(id, f) (walk_arg.dirinfo[id].flags |= f)
278 #define unset_dir_flag(id, f) (walk_arg.dirinfo[id].flags &= ~f)
279 #define is_dir_flag_on(id, f) (walk_arg.dirinfo[id].flags & f ? 1 : 0)
281 #define get_cachedir(id) (walk_arg.dirinfo[id].cdir_path)
282 #define get_updatedir(id) (walk_arg.dirinfo[id].update_path)
283 #define get_count(id) (walk_arg.dirinfo[id].count)
284 #define has_cachedir(id) (walk_arg.dirinfo[id].has_dir)
285 #define set_dir_present(id) (walk_arg.dirinfo[id].has_dir = 1)
288 * dirinfo_t (specific cache directory information):
289 * cdir_path: path to the archive cache directory
290 * update_path: path to the update directory (contains the files that will be
291 * used to extend the archive)
292 * has_dir: the specified cache directory is active
293 * count: the number of files to update
294 * flags: directory specific flags
296 typedef struct _dirinfo
{
297 char cdir_path
[PATH_MAX
];
298 char update_path
[PATH_MAX
];
306 * NEED_CACHE_DIR : cache directory is missing and needs to be created
307 * IS_SPARC_TARGET : the target mountpoint is a SPARC environment
308 * UPDATE_ERROR : an error occourred while traversing the list of files
309 * RDONLY_FSCHK : the target filesystem is read-only
310 * RAMDSK_FSCHK : the target filesystem is on a ramdisk
312 #define NEED_CACHE_DIR 0x00000001
313 #define IS_SPARC_TARGET 0x00000002
314 #define UPDATE_ERROR 0x00000004
315 #define RDONLY_FSCHK 0x00000008
316 #define INVALIDATE_CACHE 0x00000010
318 #define is_flag_on(flag) (walk_arg.update_flags & flag ? 1 : 0)
319 #define set_flag(flag) (walk_arg.update_flags |= flag)
320 #define unset_flag(flag) (walk_arg.update_flags &= ~flag)
324 * update_flags: flags related to the current updating process
325 * new_nvlp/old_nvlp: new and old list of archive-files / attributes pairs
326 * sparcfile: list of file paths for mkisofs -path-list (SPARC only)
333 dirinfo_t dirinfo
[CACHEDIR_NUM
];
338 struct safefile
*next
;
341 static struct safefile
*safefiles
= NULL
;
344 * svc:/system/filesystem/usr:default service checks for this file and
345 * does a boot archive update and then reboot the system.
347 #define NEED_UPDATE_FILE "/etc/svc/volatile/boot_archive_needs_update"
350 * svc:/system/boot-archive-update:default checks for this file and
351 * updates the boot archive.
353 #define NEED_UPDATE_SAFE_FILE "/etc/svc/volatile/boot_archive_safefile_update"
355 /* Thanks growisofs */
356 #define CD_BLOCK ((off64_t)2048)
357 #define VOLDESC_OFF 16
358 #define DVD_BLOCK (32*1024)
362 unsigned char type
[1];
363 unsigned char id
[5];
364 unsigned char void1
[80-5-1];
365 unsigned char volume_space_size
[8];
366 unsigned char void2
[2048-80-8];
370 * COUNT_MAX: maximum number of changed files to justify a multisession update
371 * BA_SIZE_MAX: maximum size of the boot_archive to justify a multisession
375 #define BA_SIZE_MAX (50 * 1024 * 1024)
377 #define bam_nowrite() (bam_check || bam_smf_check)
382 (void) fprintf(stderr
, "USAGE:\n");
385 (void) fprintf(stderr
,
386 "\t%s update-archive [-vn] [-R altroot [-p platform]]\n", prog
);
387 (void) fprintf(stderr
,
388 "\t%s list-archive [-R altroot [-p platform]]\n", prog
);
390 (void) fprintf(stderr
,
391 "\t%s install-bootloader [-fv] [-R altroot] [-P pool]\n", prog
);
393 (void) fprintf(stderr
,
394 "\t%s install-bootloader [-Mfv] [-R altroot] [-P pool]\n", prog
);
398 (void) fprintf(stderr
, "\t%s set-menu [-R altroot] key=value\n", prog
);
399 (void) fprintf(stderr
, "\t%s list-menu [-R altroot]\n", prog
);
404 * Best effort attempt to restore the $HOME value.
409 char home_env
[PATH_MAX
];
412 (void) snprintf(home_env
, sizeof (home_env
), "HOME=%s",
414 (void) putenv(home_env
);
423 * Sanitize the environment in which bootadm will execute its sub-processes
424 * (ex. mkisofs). This is done to prevent those processes from attempting
425 * to access files (ex. .mkisofsrc) or stat paths that might be on NFS
426 * or, potentially, insecure.
433 /* don't depend on caller umask */
436 /* move away from a potential unsafe current working directory */
437 while (chdir("/") == -1) {
438 if (errno
!= EINTR
) {
439 bam_print("WARNING: unable to chdir to /");
444 bam_home_env
= getenv("HOME");
445 while (bam_home_env
!= NULL
&& putenv("HOME=/") == -1) {
446 if (errno
== ENOMEM
) {
447 /* retry no more than MAX_TRIES times */
448 if (++stry
> MAX_TRIES
) {
449 bam_print("WARNING: unable to recover from "
450 "system memory pressure... aborting \n");
451 bam_exit(EXIT_FAILURE
);
453 /* memory is tight, try to sleep */
454 bam_print("Attempting to recover from memory pressure: "
455 "sleeping for %d seconds\n", SLEEP_TIME
* stry
);
456 (void) sleep(SLEEP_TIME
* stry
);
458 bam_print("WARNING: unable to sanitize HOME\n");
464 main(int argc
, char *argv
[])
466 error_t ret
= BAM_SUCCESS
;
468 (void) setlocale(LC_ALL
, "");
469 (void) textdomain(TEXT_DOMAIN
);
471 if ((prog
= strrchr(argv
[0], '/')) == NULL
) {
477 INJECT_ERROR1("ASSERT_ON", assert(0))
481 parse_args(argc
, argv
);
485 ret
= bam_loader_menu(bam_subcmd
, bam_opt
,
489 ret
= bam_archive(bam_subcmd
, bam_opt
);
492 ret
= bam_install(bam_subcmd
, bam_opt
);
499 if (ret
!= BAM_SUCCESS
)
500 bam_exit((ret
== BAM_NOCHANGE
) ? 2 : 1);
507 * Equivalence of public and internal commands:
508 * update-archive -- -a update
509 * list-archive -- -a list
510 * set-menu -- -m set_option
511 * list-menu -- -m list_entry
512 * update-menu -- -m update_entry
513 * install-bootloader -- -i install_bootloader
515 static struct cmd_map
{
520 { "update-archive", BAM_ARCHIVE
, "update"},
521 { "list-archive", BAM_ARCHIVE
, "list"},
522 { "set-menu", BAM_MENU
, "set_option"},
523 { "list-menu", BAM_MENU
, "list_entry"},
524 { "update-menu", BAM_MENU
, "update_entry"},
525 { "install-bootloader", BAM_INSTALL
, "install_bootloader"},
530 * Commands syntax published in bootadm(1M) are parsed here
533 parse_args(int argc
, char *argv
[])
535 struct cmd_map
*cmp
= cmd_map
;
537 /* command conforming to the final spec */
538 if (argc
> 1 && argv
[1][0] != '-') {
540 * Map commands to internal table.
542 while (cmp
->bam_cmdname
) {
543 if (strcmp(argv
[1], cmp
->bam_cmdname
) == 0) {
544 bam_cmd
= cmp
->bam_cmd
;
545 bam_subcmd
= cmp
->bam_subcmd
;
550 if (cmp
->bam_cmdname
== NULL
) {
558 parse_args_internal(argc
, argv
);
562 * A combination of public and private commands are parsed here.
563 * The internal syntax and the corresponding functionality are:
564 * -a update -- update-archive
565 * -a list -- list-archive
566 * -a update-all -- (reboot to sync all mnted OS archive)
567 * -i install_bootloader -- install-bootloader
568 * -m update_entry -- update-menu
569 * -m list_entry -- list-menu
570 * -m update_temp -- (reboot -- [boot-args])
571 * -m delete_all_entries -- (called from install)
572 * -m enable_hypervisor [args] -- cvt_to_hyper
573 * -m disable_hypervisor -- cvt_to_metal
574 * -m list_setting [entry] [value] -- list_setting
576 * A set of private flags is there too:
577 * -F -- purge the cache directories and rebuild them
578 * -e -- use the (faster) archive update approach (used by
582 parse_args_internal(int argc
, char *argv
[])
586 extern int optind
, opterr
;
588 const char *optstring
= "a:d:fi:m:no:veFCR:p:P:XZ";
590 const char *optstring
= "a:d:fi:m:no:veFCMR:p:P:XZ";
593 /* Suppress error message from getopt */
597 while ((c
= getopt(argc
, argv
, optstring
)) != -1) {
603 _("multiple commands specified: -%c\n"), c
);
605 bam_cmd
= BAM_ARCHIVE
;
612 _("duplicate options specified: -%c\n"), c
);
614 bam_debug
= s_strtol(optarg
);
626 _("multiple commands specified: -%c\n"), c
);
628 bam_cmd
= BAM_INSTALL
;
635 _("multiple commands specified: -%c\n"), c
);
648 * We save the original value of bam_check. The new
649 * approach in case of a read-only filesystem is to
650 * behave as a check, so we need a way to restore the
651 * original value after the evaluation of the read-only
652 * filesystem has been done.
653 * Even if we don't allow at the moment a check with
654 * update_all, this approach is more robust than
655 * simply resetting bam_check to zero.
663 _("duplicate options specified: -%c\n"), c
);
674 if (bam_pool
!= NULL
) {
677 _("duplicate options specified: -%c\n"), c
);
685 _("duplicate options specified: -%c\n"), c
);
687 } else if (realpath(optarg
, rootbuf
) == NULL
) {
689 bam_error(_("cannot resolve path %s: %s\n"),
690 optarg
, strerror(errno
));
695 bam_rootlen
= strlen(rootbuf
);
698 bam_alt_platform
= 1;
699 bam_platform
= optarg
;
700 if ((strcmp(bam_platform
, "i86pc") != 0) &&
701 (strcmp(bam_platform
, "sun4u") != 0) &&
702 (strcmp(bam_platform
, "sun4v") != 0)) {
704 bam_error(_("invalid platform %s - must be "
705 "one of sun4u, sun4v or i86pc\n"),
710 bam_is_hv
= BAM_HV_PRESENT
;
720 bam_error(_("invalid option or missing option "
721 "argument: -%c\n"), optopt
);
725 bam_error(_("invalid option or missing option "
726 "argument: -%c\n"), c
);
732 * An alternate platform requires an alternate root
734 if (bam_alt_platform
&& bam_alt_root
== 0) {
740 * A command option must be specfied
743 if (bam_opt
&& strcmp(bam_opt
, "all") == 0) {
747 bam_error(_("a command option must be specified\n"));
757 bam_error(_("Internal error: %s\n"), "parse_args");
759 } else if (optind
< argc
) {
760 bam_argv
= &argv
[optind
];
761 bam_argc
= argc
- optind
;
765 * mbr and pool are options for install_bootloader
767 if (bam_cmd
!= BAM_INSTALL
&& (bam_mbr
|| bam_pool
!= NULL
)) {
773 * -n implies verbose mode
780 check_subcmd_and_options(
783 subcmd_defn_t
*table
,
788 if (subcmd
== NULL
) {
789 bam_error(_("this command requires a sub-command\n"));
793 if (strcmp(subcmd
, "set_option") == 0) {
794 if (bam_argc
== 0 || bam_argv
== NULL
|| bam_argv
[0] == NULL
) {
795 bam_error(_("missing argument for sub-command\n"));
798 } else if (bam_argc
> 1 || bam_argv
[1] != NULL
) {
799 bam_error(_("invalid trailing arguments\n"));
803 } else if (strcmp(subcmd
, "update_all") == 0) {
805 * The only option we accept for the "update_all"
806 * subcmd is "fastboot".
808 if (bam_argc
> 1 || (bam_argc
== 1 &&
809 strcmp(bam_argv
[0], "fastboot") != 0)) {
810 bam_error(_("invalid trailing arguments\n"));
814 } else if (((strcmp(subcmd
, "enable_hypervisor") != 0) &&
815 (strcmp(subcmd
, "list_setting") != 0)) && (bam_argc
|| bam_argv
)) {
817 * Of the remaining subcommands, only "enable_hypervisor" and
818 * "list_setting" take trailing arguments.
820 bam_error(_("invalid trailing arguments\n"));
825 if (bam_root
== NULL
) {
830 /* verify that subcmd is valid */
831 for (i
= 0; table
[i
].subcmd
!= NULL
; i
++) {
832 if (strcmp(table
[i
].subcmd
, subcmd
) == 0)
836 if (table
[i
].subcmd
== NULL
) {
837 bam_error(_("invalid sub-command specified: %s\n"), subcmd
);
841 if (table
[i
].unpriv
== 0 && geteuid() != 0) {
842 bam_error(_("you must be root to run this command\n"));
847 * Currently only privileged commands need a lock
849 if (table
[i
].unpriv
== 0)
852 /* subcmd verifies that opt is appropriate */
853 if (table
[i
].option
!= OPT_OPTIONAL
) {
854 if ((table
[i
].option
== OPT_REQ
) ^ (opt
!= NULL
)) {
856 bam_error(_("this sub-command (%s) does not "
857 "take options\n"), subcmd
);
859 bam_error(_("an option is required for this "
860 "sub-command: %s\n"), subcmd
);
865 *fp
= table
[i
].handler
;
867 return (BAM_SUCCESS
);
871 * NOTE: A single "/" is also considered a trailing slash and will
875 elide_trailing_slash(const char *src
, char *dst
, size_t dstsize
)
882 (void) strlcpy(dst
, src
, dstsize
);
884 dstlen
= strlen(dst
);
885 if (dst
[dstlen
- 1] == '/') {
886 dst
[dstlen
- 1] = '\0';
891 is_safe_exec(char *path
)
895 if (lstat(path
, &sb
) != 0) {
896 bam_error(_("stat of file failed: %s: %s\n"), path
,
901 if (!S_ISREG(sb
.st_mode
)) {
902 bam_error(_("%s is not a regular file, skipping\n"), path
);
906 if (sb
.st_uid
!= getuid()) {
907 bam_error(_("%s is not owned by %d, skipping\n"),
912 if (sb
.st_mode
& S_IWOTH
|| sb
.st_mode
& S_IWGRP
) {
913 bam_error(_("%s is others or group writable, skipping\n"),
918 return (BAM_SUCCESS
);
922 install_bootloader(void)
927 struct extmnttab mnt
;
928 struct stat statbuf
= {0};
929 be_node_list_t
*be_nodes
, *node
;
931 char *root_ds
= NULL
;
934 if (nvlist_alloc(&nvl
, NV_UNIQUE_NAME
, 0) != 0) {
935 bam_error(_("out of memory\n"));
940 * if bam_alt_root is set, the stage files are used from alt root.
941 * if pool is set, the target devices are pool devices, stage files
942 * are read from pool bootfs unless alt root is set.
944 * use arguments as targets, stage files are from alt or current root
945 * if no arguments and no pool, install on current boot pool.
949 if (stat(bam_root
, &statbuf
) != 0) {
950 bam_error(_("stat of file failed: %s: %s\n"), bam_root
,
954 if ((fp
= fopen(MNTTAB
, "r")) == NULL
) {
955 bam_error(_("failed to open file: %s: %s\n"),
956 MNTTAB
, strerror(errno
));
960 while (getextmntent(fp
, &mnt
, sizeof (mnt
)) == 0) {
961 if (mnt
.mnt_major
== major(statbuf
.st_dev
) &&
962 mnt
.mnt_minor
== minor(statbuf
.st_dev
)) {
964 root_ds
= strdup(mnt
.mnt_special
);
971 bam_error(_("alternate root %s not in mnttab\n"),
975 if (root_ds
== NULL
) {
976 bam_error(_("out of memory\n"));
980 if (be_list(NULL
, &be_nodes
) != BE_SUCCESS
) {
981 bam_error(_("No BE's found\n"));
984 for (node
= be_nodes
; node
!= NULL
; node
= node
->be_next_node
)
985 if (strcmp(root_ds
, node
->be_root_ds
) == 0)
989 bam_error(_("BE (%s) does not exist\n"), root_ds
);
994 be_free_list(be_nodes
);
997 ret
= nvlist_add_string(nvl
, BE_ATTR_ORIG_BE_NAME
,
999 ret
|= nvlist_add_string(nvl
, BE_ATTR_ORIG_BE_ROOT
,
1001 be_free_list(be_nodes
);
1009 flags
|= BE_INSTALLBOOT_FLAG_FORCE
;
1011 flags
|= BE_INSTALLBOOT_FLAG_MBR
;
1013 flags
|= BE_INSTALLBOOT_FLAG_VERBOSE
;
1015 if (nvlist_add_uint16(nvl
, BE_ATTR_INSTALL_FLAGS
, flags
) != 0) {
1016 bam_error(_("out of memory\n"));
1022 * if altroot was set, we got be name and be root, only need
1023 * to set pool name as target.
1024 * if no altroot, need to find be name and root from pool.
1026 if (bam_pool
!= NULL
) {
1027 ret
= nvlist_add_string(nvl
, BE_ATTR_ORIG_BE_POOL
, bam_pool
);
1033 ret
= be_installboot(nvl
);
1040 if (be_list(NULL
, &be_nodes
) != BE_SUCCESS
) {
1041 bam_error(_("No BE's found\n"));
1046 if (bam_pool
!= NULL
) {
1048 * find active be_node in bam_pool
1050 for (node
= be_nodes
; node
!= NULL
; node
= node
->be_next_node
) {
1051 if (strcmp(bam_pool
, node
->be_rpool
) != 0)
1053 if (node
->be_active_on_boot
)
1057 bam_error(_("No active BE in %s\n"), bam_pool
);
1058 be_free_list(be_nodes
);
1062 ret
= nvlist_add_string(nvl
, BE_ATTR_ORIG_BE_NAME
,
1063 node
->be_node_name
);
1064 ret
|= nvlist_add_string(nvl
, BE_ATTR_ORIG_BE_ROOT
,
1066 be_free_list(be_nodes
);
1071 ret
= be_installboot(nvl
);
1078 * get dataset for "/" and fill up the args.
1080 if ((fp
= fopen(MNTTAB
, "r")) == NULL
) {
1081 bam_error(_("failed to open file: %s: %s\n"),
1082 MNTTAB
, strerror(errno
));
1084 be_free_list(be_nodes
);
1089 while (getextmntent(fp
, &mnt
, sizeof (mnt
)) == 0) {
1090 if (strcmp(mnt
.mnt_mountp
, "/") == 0) {
1092 root_ds
= strdup(mnt
.mnt_special
);
1099 bam_error(_("alternate root %s not in mnttab\n"), "/");
1101 be_free_list(be_nodes
);
1104 if (root_ds
== NULL
) {
1105 bam_error(_("out of memory\n"));
1107 be_free_list(be_nodes
);
1111 for (node
= be_nodes
; node
!= NULL
; node
= node
->be_next_node
) {
1112 if (strcmp(root_ds
, node
->be_root_ds
) == 0)
1117 bam_error(_("No such BE: %s\n"), root_ds
);
1119 be_free_list(be_nodes
);
1125 ret
= nvlist_add_string(nvl
, BE_ATTR_ORIG_BE_NAME
, node
->be_node_name
);
1126 ret
|= nvlist_add_string(nvl
, BE_ATTR_ORIG_BE_ROOT
, node
->be_root_ds
);
1127 ret
|= nvlist_add_string(nvl
, BE_ATTR_ORIG_BE_POOL
, node
->be_rpool
);
1128 be_free_list(be_nodes
);
1133 ret
= be_installboot(nvl
) ? BAM_ERROR
: 0;
1141 bam_install(char *subcmd
, char *opt
)
1148 if (check_subcmd_and_options(subcmd
, opt
, inst_subcmds
, &f
) ==
1161 error_t (*f
)(char *root
, char *opt
);
1162 const char *fcn
= "bam_archive()";
1165 * Add trailing / for archive subcommands
1167 if (rootbuf
[strlen(rootbuf
) - 1] != '/')
1168 (void) strcat(rootbuf
, "/");
1169 bam_rootlen
= strlen(rootbuf
);
1174 ret
= check_subcmd_and_options(subcmd
, opt
, arch_subcmds
, &f
);
1175 if (ret
!= BAM_SUCCESS
) {
1179 ret
= get_boot_cap(rootbuf
);
1180 if (ret
!= BAM_SUCCESS
) {
1181 BAM_DPRINTF(("%s: Failed to get boot capability\n", fcn
));
1186 * Check archive not supported with update_all
1187 * since it is awkward to display out-of-sync
1188 * information for each BE.
1190 if (bam_check
&& strcmp(subcmd
, "update_all") == 0) {
1191 bam_error(_("the check option is not supported with "
1192 "subcmd: %s\n"), subcmd
);
1196 if (strcmp(subcmd
, "update_all") == 0)
1200 ucode_install(bam_root
);
1203 ret
= f(bam_root
, opt
);
1212 bam_error(char *format
, ...)
1216 va_start(ap
, format
);
1217 (void) fprintf(stderr
, "%s: ", prog
);
1218 (void) vfprintf(stderr
, format
, ap
);
1224 bam_derror(char *format
, ...)
1230 va_start(ap
, format
);
1231 (void) fprintf(stderr
, "DEBUG: ");
1232 (void) vfprintf(stderr
, format
, ap
);
1238 bam_print(char *format
, ...)
1242 va_start(ap
, format
);
1243 (void) vfprintf(stdout
, format
, ap
);
1249 bam_print_stderr(char *format
, ...)
1253 va_start(ap
, format
);
1254 (void) vfprintf(stderr
, format
, ap
);
1259 bam_exit(int excode
)
1272 bam_lock_fd
= open(BAM_LOCK_FILE
, O_CREAT
|O_RDWR
, LOCK_FILE_PERMS
);
1273 if (bam_lock_fd
< 0) {
1275 * We may be invoked early in boot for archive verification.
1276 * In this case, root is readonly and /var/run may not exist.
1277 * Proceed without the lock
1279 if (errno
== EROFS
|| errno
== ENOENT
) {
1280 bam_root_readonly
= 1;
1284 bam_error(_("failed to open file: %s: %s\n"),
1285 BAM_LOCK_FILE
, strerror(errno
));
1289 lock
.l_type
= F_WRLCK
;
1290 lock
.l_whence
= SEEK_SET
;
1294 if (fcntl(bam_lock_fd
, F_SETLK
, &lock
) == -1) {
1295 if (errno
!= EACCES
&& errno
!= EAGAIN
) {
1296 bam_error(_("failed to lock file: %s: %s\n"),
1297 BAM_LOCK_FILE
, strerror(errno
));
1298 (void) close(bam_lock_fd
);
1303 (void) pread(bam_lock_fd
, &pid
, sizeof (pid_t
), 0);
1305 _("another instance of bootadm (pid %lu) is running\n"),
1308 lock
.l_type
= F_WRLCK
;
1309 lock
.l_whence
= SEEK_SET
;
1312 if (fcntl(bam_lock_fd
, F_SETLKW
, &lock
) == -1) {
1313 bam_error(_("failed to lock file: %s: %s\n"),
1314 BAM_LOCK_FILE
, strerror(errno
));
1315 (void) close(bam_lock_fd
);
1321 /* We own the lock now */
1323 (void) write(bam_lock_fd
, &pid
, sizeof (pid
));
1329 struct flock unlock
;
1332 * NOP if we don't hold the lock
1334 if (bam_lock_fd
< 0) {
1338 unlock
.l_type
= F_UNLCK
;
1339 unlock
.l_whence
= SEEK_SET
;
1343 if (fcntl(bam_lock_fd
, F_SETLK
, &unlock
) == -1) {
1344 bam_error(_("failed to unlock file: %s: %s\n"),
1345 BAM_LOCK_FILE
, strerror(errno
));
1348 if (close(bam_lock_fd
) == -1) {
1349 bam_error(_("failed to close file: %s: %s\n"),
1350 BAM_LOCK_FILE
, strerror(errno
));
1356 list_archive(char *root
, char *opt
)
1359 filelist_t
*flistp
= &flist
;
1363 assert(opt
== NULL
);
1365 flistp
->head
= flistp
->tail
= NULL
;
1366 if (read_list(root
, flistp
) != BAM_SUCCESS
) {
1369 assert(flistp
->head
&& flistp
->tail
);
1371 for (lp
= flistp
->head
; lp
; lp
= lp
->next
) {
1372 bam_print(_("%s\n"), lp
->line
);
1375 filelist_free(flistp
);
1377 return (BAM_SUCCESS
);
1381 * Checks if the path specified (without the file name at the end) exists
1382 * and creates it if not. If the path exists and is not a directory, an attempt
1383 * to unlink is made.
1386 setup_path(char *path
)
1392 p
= strrchr(path
, '/');
1395 if (stat(path
, &sb
) != 0 || !(S_ISDIR(sb
.st_mode
))) {
1396 /* best effort attempt, mkdirp will catch the error */
1397 (void) unlink(path
);
1399 bam_print(_("need to create directory "
1400 "path for %s\n"), path
);
1401 ret
= mkdirp(path
, DIR_PERMS
);
1403 bam_error(_("mkdir of %s failed: %s\n"),
1404 path
, strerror(errno
));
1410 return (BAM_SUCCESS
);
1412 return (BAM_SUCCESS
);
1421 char path
[PATH_MAX
];
1426 setup_file(char *base
, const char *path
, cachefile
*cf
)
1431 /* init gzfile or fdfile in case we fail before opening */
1432 if (bam_direct
== BAM_DIRECT_DBOOT
)
1433 cf
->out
.gzfile
= NULL
;
1435 cf
->out
.fdfile
= -1;
1437 /* strip the trailing altroot path */
1438 strip
= (char *)path
+ strlen(rootbuf
);
1440 ret
= snprintf(cf
->path
, sizeof (cf
->path
), "%s/%s", base
, strip
);
1441 if (ret
>= sizeof (cf
->path
)) {
1442 bam_error(_("unable to create path on mountpoint %s, "
1443 "path too long\n"), rootbuf
);
1447 /* Check if path is present in the archive cache directory */
1448 if (setup_path(cf
->path
) == BAM_ERROR
)
1451 if (bam_direct
== BAM_DIRECT_DBOOT
) {
1452 if ((cf
->out
.gzfile
= gzopen(cf
->path
, "wb")) == NULL
) {
1453 bam_error(_("failed to open file: %s: %s\n"),
1454 cf
->path
, strerror(errno
));
1457 (void) gzsetparams(cf
->out
.gzfile
, Z_BEST_SPEED
,
1458 Z_DEFAULT_STRATEGY
);
1460 if ((cf
->out
.fdfile
= open(cf
->path
, O_WRONLY
| O_CREAT
, 0644))
1462 bam_error(_("failed to open file: %s: %s\n"),
1463 cf
->path
, strerror(errno
));
1468 return (BAM_SUCCESS
);
1472 cache_write(cachefile cf
, char *buf
, int size
)
1476 if (bam_direct
== BAM_DIRECT_DBOOT
) {
1477 if (gzwrite(cf
.out
.gzfile
, buf
, size
) < 1) {
1478 bam_error(_("failed to write to %s\n"),
1479 gzerror(cf
.out
.gzfile
, &err
));
1480 if (err
== Z_ERRNO
&& bam_verbose
) {
1481 bam_error(_("write to file failed: %s: %s\n"),
1482 cf
.path
, strerror(errno
));
1487 if (write(cf
.out
.fdfile
, buf
, size
) < 1) {
1488 bam_error(_("write to file failed: %s: %s\n"),
1489 cf
.path
, strerror(errno
));
1493 return (BAM_SUCCESS
);
1497 cache_close(cachefile cf
)
1501 if (bam_direct
== BAM_DIRECT_DBOOT
) {
1502 if (cf
.out
.gzfile
) {
1503 ret
= gzclose(cf
.out
.gzfile
);
1505 bam_error(_("failed to close file: %s: %s\n"),
1506 cf
.path
, strerror(errno
));
1511 if (cf
.out
.fdfile
!= -1) {
1512 ret
= close(cf
.out
.fdfile
);
1514 bam_error(_("failed to close file: %s: %s\n"),
1515 cf
.path
, strerror(errno
));
1521 return (BAM_SUCCESS
);
1525 dircache_updatefile(const char *path
, int what
)
1530 cachefile outfile
, outupdt
;
1532 if (bam_nowrite()) {
1533 set_dir_flag(what
, NEED_UPDATE
);
1534 return (BAM_SUCCESS
);
1537 if (!has_cachedir(what
))
1538 return (BAM_SUCCESS
);
1540 if ((infile
= fopen(path
, "rb")) == NULL
) {
1541 bam_error(_("failed to open file: %s: %s\n"), path
,
1546 ret
= setup_file(get_cachedir(what
), path
, &outfile
);
1547 if (ret
== BAM_ERROR
) {
1548 exitcode
= BAM_ERROR
;
1551 if (!is_dir_flag_on(what
, NO_MULTI
)) {
1552 ret
= setup_file(get_updatedir(what
), path
, &outupdt
);
1553 if (ret
== BAM_ERROR
)
1554 set_dir_flag(what
, NO_MULTI
);
1557 while ((ret
= fread(buf
, 1, sizeof (buf
), infile
)) > 0) {
1558 if (cache_write(outfile
, buf
, ret
) == BAM_ERROR
) {
1559 exitcode
= BAM_ERROR
;
1562 if (!is_dir_flag_on(what
, NO_MULTI
))
1563 if (cache_write(outupdt
, buf
, ret
) == BAM_ERROR
)
1564 set_dir_flag(what
, NO_MULTI
);
1567 set_dir_flag(what
, NEED_UPDATE
);
1569 if (get_count(what
) > COUNT_MAX
)
1570 set_dir_flag(what
, NO_MULTI
);
1571 exitcode
= BAM_SUCCESS
;
1573 (void) fclose(infile
);
1574 if (cache_close(outfile
) == BAM_ERROR
)
1575 exitcode
= BAM_ERROR
;
1576 if (!is_dir_flag_on(what
, NO_MULTI
) &&
1577 cache_close(outupdt
) == BAM_ERROR
)
1578 exitcode
= BAM_ERROR
;
1579 if (exitcode
== BAM_ERROR
)
1580 set_flag(UPDATE_ERROR
);
1585 dircache_updatedir(const char *path
, int what
, int updt
)
1588 char dpath
[PATH_MAX
];
1592 strip
= (char *)path
+ strlen(rootbuf
);
1594 ret
= snprintf(dpath
, sizeof (dpath
), "%s/%s", updt
?
1595 get_updatedir(what
) : get_cachedir(what
), strip
);
1597 if (ret
>= sizeof (dpath
)) {
1598 bam_error(_("unable to create path on mountpoint %s, "
1599 "path too long\n"), rootbuf
);
1600 set_flag(UPDATE_ERROR
);
1604 if (stat(dpath
, &sb
) == 0 && S_ISDIR(sb
.st_mode
))
1605 return (BAM_SUCCESS
);
1608 if (!is_dir_flag_on(what
, NO_MULTI
))
1609 if (!bam_nowrite() && mkdirp(dpath
, DIR_PERMS
) == -1)
1610 set_dir_flag(what
, NO_MULTI
);
1612 if (!bam_nowrite() && mkdirp(dpath
, DIR_PERMS
) == -1) {
1613 set_flag(UPDATE_ERROR
);
1618 set_dir_flag(what
, NEED_UPDATE
);
1619 return (BAM_SUCCESS
);
1622 #define DO_CACHE_DIR 0
1623 #define DO_UPDATE_DIR 1
1625 #if defined(_LP64) || defined(_LONGLONG_TYPE)
1626 typedef Elf64_Ehdr _elfhdr
;
1628 typedef Elf32_Ehdr _elfhdr
;
1632 * This routine updates the contents of the cache directory
1635 update_dircache(const char *path
, int flags
)
1637 int rc
= BAM_SUCCESS
;
1645 if ((fd
= open(path
, O_RDONLY
)) < 0) {
1646 bam_error(_("failed to open file: %s: %s\n"),
1647 path
, strerror(errno
));
1648 set_flag(UPDATE_ERROR
);
1654 * libelf and gelf would be a cleaner and easier way to handle
1655 * this, but libelf fails compilation if _ILP32 is defined &&
1656 * _FILE_OFFSET_BITS is != 32 ...
1658 if (read(fd
, (void *)&elf
, sizeof (_elfhdr
)) < 0) {
1659 bam_error(_("read failed for file: %s: %s\n"),
1660 path
, strerror(errno
));
1661 set_flag(UPDATE_ERROR
);
1669 * If the file is not an executable and is not inside an amd64
1670 * directory, we copy it in both the cache directories,
1671 * otherwise, we only copy it inside the 64-bit one.
1673 if (memcmp(elf
.e_ident
, ELFMAG
, 4) != 0) {
1674 if (strstr(path
, "/amd64")) {
1675 rc
= dircache_updatefile(path
, FILE64
);
1677 rc
= dircache_updatefile(path
, FILE32
);
1678 if (rc
== BAM_SUCCESS
)
1679 rc
= dircache_updatefile(path
, FILE64
);
1683 * Based on the ELF class we copy the file in the 32-bit
1684 * or the 64-bit cache directory.
1686 if (elf
.e_ident
[EI_CLASS
] == ELFCLASS32
) {
1687 rc
= dircache_updatefile(path
, FILE32
);
1688 } else if (elf
.e_ident
[EI_CLASS
] == ELFCLASS64
) {
1689 rc
= dircache_updatefile(path
, FILE64
);
1691 bam_print(_("WARNING: file %s is neither a "
1692 "32-bit nor a 64-bit ELF\n"), path
);
1694 rc
= dircache_updatefile(path
, FILE32
);
1695 if (rc
== BAM_SUCCESS
)
1696 rc
= dircache_updatefile(path
, FILE64
);
1702 if (strstr(path
, "/amd64") == NULL
) {
1703 rc
= dircache_updatedir(path
, FILE32
, DO_UPDATE_DIR
);
1704 if (rc
== BAM_SUCCESS
)
1705 rc
= dircache_updatedir(path
, FILE32
,
1708 if (has_cachedir(FILE64
)) {
1709 rc
= dircache_updatedir(path
, FILE64
,
1711 if (rc
== BAM_SUCCESS
)
1712 rc
= dircache_updatedir(path
, FILE64
,
1729 const struct stat
*st
,
1735 uint64_t filestat
[2];
1736 int error
, ret
, status
;
1738 struct safefile
*safefilep
;
1744 * On SPARC we create/update links too.
1746 if (flags
!= FTW_F
&& flags
!= FTW_D
&& (flags
== FTW_SL
&&
1747 !is_flag_on(IS_SPARC_TARGET
)))
1751 * Ignore broken links
1753 if (flags
== FTW_SL
&& stat(file
, &sb
) < 0)
1757 * new_nvlp may be NULL if there were errors earlier
1758 * but this is not fatal to update determination.
1760 if (walk_arg
.new_nvlp
) {
1761 filestat
[0] = st
->st_size
;
1762 filestat
[1] = st
->st_mtime
;
1763 error
= nvlist_add_uint64_array(walk_arg
.new_nvlp
,
1764 file
+ bam_rootlen
, filestat
, 2);
1766 bam_error(_("failed to update stat data for: %s: %s\n"),
1767 file
, strerror(error
));
1771 * If we are invoked as part of system/filesystem/boot-archive, then
1772 * there are a number of things we should not worry about
1774 if (bam_smf_check
) {
1775 /* ignore amd64 modules unless we are booted amd64. */
1776 if (!is_amd64() && strstr(file
, "/amd64/") != 0)
1779 /* read in list of safe files */
1780 if (safefiles
== NULL
) {
1781 fp
= fopen("/boot/solaris/filelist.safe", "r");
1783 safefiles
= s_calloc(1,
1784 sizeof (struct safefile
));
1785 safefilep
= safefiles
;
1786 safefilep
->name
= s_calloc(1, MAXPATHLEN
+
1788 safefilep
->next
= NULL
;
1789 while (s_fgets(safefilep
->name
, MAXPATHLEN
+
1790 MAXNAMELEN
, fp
) != NULL
) {
1791 safefilep
->next
= s_calloc(1,
1792 sizeof (struct safefile
));
1793 safefilep
= safefilep
->next
;
1794 safefilep
->name
= s_calloc(1,
1795 MAXPATHLEN
+ MAXNAMELEN
);
1796 safefilep
->next
= NULL
;
1804 * On SPARC we create a -path-list file for mkisofs
1806 if (is_flag_on(IS_SPARC_TARGET
) && !bam_nowrite()) {
1807 if (flags
!= FTW_D
) {
1810 strip
= (char *)file
+ strlen(rootbuf
);
1811 (void) fprintf(walk_arg
.sparcfile
, "/%s=%s\n", strip
,
1817 * We are transitioning from the old model to the dircache or the cache
1818 * directory was removed: create the entry without further checkings.
1820 if (is_flag_on(NEED_CACHE_DIR
)) {
1822 bam_print(_(" new %s\n"), file
);
1824 if (is_flag_on(IS_SPARC_TARGET
)) {
1825 set_dir_flag(FILE64
, NEED_UPDATE
);
1829 ret
= update_dircache(file
, flags
);
1830 if (ret
== BAM_ERROR
) {
1831 bam_error(_("directory cache update failed for %s\n"),
1840 * We need an update if file doesn't exist in old archive
1842 if (walk_arg
.old_nvlp
== NULL
||
1843 nvlist_lookup_uint64_array(walk_arg
.old_nvlp
,
1844 file
+ bam_rootlen
, &value
, &sz
) != 0) {
1845 if (bam_smf_check
) /* ignore new during smf check */
1848 if (is_flag_on(IS_SPARC_TARGET
)) {
1849 set_dir_flag(FILE64
, NEED_UPDATE
);
1851 ret
= update_dircache(file
, flags
);
1852 if (ret
== BAM_ERROR
) {
1853 bam_error(_("directory cache update "
1854 "failed for %s\n"), file
);
1860 bam_print(_(" new %s\n"), file
);
1865 * If we got there, the file is already listed as to be included in the
1866 * iso image. We just need to know if we are going to rebuild it or not
1868 if (is_flag_on(IS_SPARC_TARGET
) &&
1869 is_dir_flag_on(FILE64
, NEED_UPDATE
) && !bam_nowrite())
1872 * File exists in old archive. Check if file has changed
1875 bcopy(value
, filestat
, sizeof (filestat
));
1877 if (flags
!= FTW_D
&& (filestat
[0] != st
->st_size
||
1878 filestat
[1] != st
->st_mtime
)) {
1879 if (bam_smf_check
) {
1880 safefilep
= safefiles
;
1881 while (safefilep
!= NULL
&&
1882 safefilep
->name
[0] != '\0') {
1883 if (regcomp(&re
, safefilep
->name
,
1884 REG_EXTENDED
|REG_NOSUB
) == 0) {
1885 status
= regexec(&re
,
1886 file
+ bam_rootlen
, 0, NULL
, 0);
1890 NEED_UPDATE_SAFE_FILE
,
1895 safefilep
= safefilep
->next
;
1899 if (is_flag_on(IS_SPARC_TARGET
)) {
1900 set_dir_flag(FILE64
, NEED_UPDATE
);
1902 ret
= update_dircache(file
, flags
);
1903 if (ret
== BAM_ERROR
) {
1904 bam_error(_("directory cache update failed "
1912 bam_print(" %s\n", file
);
1914 bam_print(_(" changed %s\n"), file
);
1922 * Remove a directory path recursively
1927 struct dirent
*d
= NULL
;
1929 char tpath
[PATH_MAX
];
1932 if ((dir
= opendir(path
)) == NULL
)
1935 while ((d
= readdir(dir
)) != NULL
) {
1936 if ((strcmp(d
->d_name
, ".") != 0) &&
1937 (strcmp(d
->d_name
, "..") != 0)) {
1938 (void) snprintf(tpath
, sizeof (tpath
), "%s/%s",
1940 if (stat(tpath
, &sb
) == 0) {
1941 if (sb
.st_mode
& S_IFDIR
)
1942 (void) rmdir_r(tpath
);
1944 (void) remove(tpath
);
1948 return (remove(path
));
1952 * Check if cache directory exists and, if not, create it and update flags
1953 * accordingly. If the path exists, but it's not a directory, a best effort
1954 * attempt to remove and recreate it is made.
1955 * If the user requested a 'purge', always recreate the directory from scratch.
1958 set_cache_dir(char *root
, int what
)
1963 ret
= snprintf(get_cachedir(what
), sizeof (get_cachedir(what
)),
1964 "%s%s%s%s%s", root
, ARCHIVE_PREFIX
, get_machine(), what
== FILE64
?
1965 "/amd64" : "", CACHEDIR_SUFFIX
);
1967 if (ret
>= sizeof (get_cachedir(what
))) {
1968 bam_error(_("unable to create path on mountpoint %s, "
1969 "path too long\n"), rootbuf
);
1973 if (bam_purge
|| is_flag_on(INVALIDATE_CACHE
))
1974 (void) rmdir_r(get_cachedir(what
));
1976 if (stat(get_cachedir(what
), &sb
) != 0 || !(S_ISDIR(sb
.st_mode
))) {
1977 /* best effort unlink attempt, mkdir will catch errors */
1978 (void) unlink(get_cachedir(what
));
1981 bam_print(_("archive cache directory not found: %s\n"),
1982 get_cachedir(what
));
1983 ret
= mkdir(get_cachedir(what
), DIR_PERMS
);
1985 bam_error(_("mkdir of %s failed: %s\n"),
1986 get_cachedir(what
), strerror(errno
));
1987 get_cachedir(what
)[0] = '\0';
1990 set_flag(NEED_CACHE_DIR
);
1991 set_dir_flag(what
, NO_MULTI
);
1994 return (BAM_SUCCESS
);
1998 set_update_dir(char *root
, int what
)
2003 if (is_dir_flag_on(what
, NO_MULTI
))
2004 return (BAM_SUCCESS
);
2007 set_dir_flag(what
, NO_MULTI
);
2008 return (BAM_SUCCESS
);
2011 if (what
== FILE64
&& !is_flag_on(IS_SPARC_TARGET
))
2012 ret
= snprintf(get_updatedir(what
),
2013 sizeof (get_updatedir(what
)), "%s%s%s/amd64%s", root
,
2014 ARCHIVE_PREFIX
, get_machine(), UPDATEDIR_SUFFIX
);
2016 ret
= snprintf(get_updatedir(what
),
2017 sizeof (get_updatedir(what
)), "%s%s%s%s", root
,
2018 ARCHIVE_PREFIX
, get_machine(), UPDATEDIR_SUFFIX
);
2020 if (ret
>= sizeof (get_updatedir(what
))) {
2021 bam_error(_("unable to create path on mountpoint %s, "
2022 "path too long\n"), rootbuf
);
2026 if (stat(get_updatedir(what
), &sb
) == 0) {
2027 if (S_ISDIR(sb
.st_mode
))
2028 ret
= rmdir_r(get_updatedir(what
));
2030 ret
= unlink(get_updatedir(what
));
2033 set_dir_flag(what
, NO_MULTI
);
2036 if (mkdir(get_updatedir(what
), DIR_PERMS
) < 0)
2037 set_dir_flag(what
, NO_MULTI
);
2039 return (BAM_SUCCESS
);
2043 is_valid_archive(char *root
, int what
)
2045 char archive_path
[PATH_MAX
];
2046 char timestamp_path
[PATH_MAX
];
2047 struct stat sb
, timestamp
;
2050 if (what
== FILE64
&& !is_flag_on(IS_SPARC_TARGET
))
2051 ret
= snprintf(archive_path
, sizeof (archive_path
),
2052 "%s%s%s/amd64%s", root
, ARCHIVE_PREFIX
, get_machine(),
2055 ret
= snprintf(archive_path
, sizeof (archive_path
), "%s%s%s%s",
2056 root
, ARCHIVE_PREFIX
, get_machine(), ARCHIVE_SUFFIX
);
2058 if (ret
>= sizeof (archive_path
)) {
2059 bam_error(_("unable to create path on mountpoint %s, "
2060 "path too long\n"), rootbuf
);
2064 if (stat(archive_path
, &sb
) != 0) {
2065 if (bam_verbose
&& !bam_check
)
2066 bam_print(_("archive not found: %s\n"), archive_path
);
2067 set_dir_flag(what
, NEED_UPDATE
);
2068 set_dir_flag(what
, NO_MULTI
);
2069 return (BAM_SUCCESS
);
2073 * The timestamp file is used to prevent stale files in the archive
2075 * Stale files can happen if the system is booted back and forth across
2076 * the transition from bootadm-before-the-cache to
2077 * bootadm-after-the-cache, since older versions of bootadm don't know
2078 * about the existence of the archive cache.
2080 * Since only bootadm-after-the-cache versions know about about this
2081 * file, we require that the boot archive be older than this file.
2083 ret
= snprintf(timestamp_path
, sizeof (timestamp_path
), "%s%s", root
,
2084 FILE_STAT_TIMESTAMP
);
2086 if (ret
>= sizeof (timestamp_path
)) {
2087 bam_error(_("unable to create path on mountpoint %s, "
2088 "path too long\n"), rootbuf
);
2092 if (stat(timestamp_path
, ×tamp
) != 0 ||
2093 sb
.st_mtime
> timestamp
.st_mtime
) {
2094 if (bam_verbose
&& !bam_check
)
2096 _("archive cache is out of sync. Rebuilding.\n"));
2098 * Don't generate a false positive for the boot-archive service
2099 * but trigger an update of the archive cache in
2100 * boot-archive-update.
2102 if (bam_smf_check
) {
2103 (void) creat(NEED_UPDATE_FILE
, 0644);
2104 return (BAM_SUCCESS
);
2107 set_flag(INVALIDATE_CACHE
);
2108 set_dir_flag(what
, NEED_UPDATE
);
2109 set_dir_flag(what
, NO_MULTI
);
2110 return (BAM_SUCCESS
);
2113 if (is_flag_on(IS_SPARC_TARGET
))
2114 return (BAM_SUCCESS
);
2116 if (bam_extend
&& sb
.st_size
> BA_SIZE_MAX
) {
2117 if (bam_verbose
&& !bam_check
)
2118 bam_print(_("archive %s is bigger than %d bytes and "
2119 "will be rebuilt\n"), archive_path
, BA_SIZE_MAX
);
2120 set_dir_flag(what
, NO_MULTI
);
2123 return (BAM_SUCCESS
);
2127 * Check flags and presence of required files and directories.
2128 * The force flag and/or absence of files should
2129 * trigger an update.
2130 * Suppress stdout output if check (-n) option is set
2131 * (as -n should only produce parseable output.)
2134 check_flags_and_files(char *root
)
2141 * If archive is missing, create archive
2143 if (is_flag_on(IS_SPARC_TARGET
)) {
2144 ret
= is_valid_archive(root
, FILE64
);
2145 if (ret
== BAM_ERROR
)
2150 ret
= is_valid_archive(root
, what
);
2151 if (ret
== BAM_ERROR
)
2154 } while (bam_direct
== BAM_DIRECT_DBOOT
&& what
< CACHEDIR_NUM
);
2158 return (BAM_SUCCESS
);
2162 * check if cache directories exist on x86.
2163 * check (and always open) the cache file on SPARC.
2166 ret
= snprintf(get_cachedir(FILE64
),
2167 sizeof (get_cachedir(FILE64
)), "%s%s%s/%s", root
,
2168 ARCHIVE_PREFIX
, get_machine(), CACHEDIR_SUFFIX
);
2170 if (ret
>= sizeof (get_cachedir(FILE64
))) {
2171 bam_error(_("unable to create path on mountpoint %s, "
2172 "path too long\n"), rootbuf
);
2176 if (stat(get_cachedir(FILE64
), &sb
) != 0) {
2177 set_flag(NEED_CACHE_DIR
);
2178 set_dir_flag(FILE64
, NEED_UPDATE
);
2181 walk_arg
.sparcfile
= fopen(get_cachedir(FILE64
), "w");
2182 if (walk_arg
.sparcfile
== NULL
) {
2183 bam_error(_("failed to open file: %s: %s\n"),
2184 get_cachedir(FILE64
), strerror(errno
));
2188 set_dir_present(FILE64
);
2193 if (set_cache_dir(root
, what
) != 0)
2196 set_dir_present(what
);
2198 if (set_update_dir(root
, what
) != 0)
2201 } while (bam_direct
== BAM_DIRECT_DBOOT
&& what
< CACHEDIR_NUM
);
2205 * if force, create archive unconditionally
2209 set_dir_flag(FILE32
, NEED_UPDATE
);
2210 set_dir_flag(FILE64
, NEED_UPDATE
);
2212 bam_print(_("forced update of archive requested\n"));
2213 return (BAM_SUCCESS
);
2216 return (BAM_SUCCESS
);
2220 read_one_list(char *root
, filelist_t
*flistp
, char *filelist
)
2222 char path
[PATH_MAX
];
2224 char buf
[BAM_MAXLINE
];
2225 const char *fcn
= "read_one_list()";
2227 (void) snprintf(path
, sizeof (path
), "%s%s", root
, filelist
);
2229 fp
= fopen(path
, "r");
2231 BAM_DPRINTF(("%s: failed to open archive filelist: %s: %s\n",
2232 fcn
, path
, strerror(errno
)));
2235 while (s_fgets(buf
, sizeof (buf
), fp
) != NULL
) {
2236 /* skip blank lines */
2237 if (strspn(buf
, " \t") == strlen(buf
))
2239 append_to_flist(flistp
, buf
);
2241 if (fclose(fp
) != 0) {
2242 bam_error(_("failed to close file: %s: %s\n"),
2243 path
, strerror(errno
));
2246 return (BAM_SUCCESS
);
2250 read_list(char *root
, filelist_t
*flistp
)
2252 char path
[PATH_MAX
];
2256 const char *fcn
= "read_list()";
2258 flistp
->head
= flistp
->tail
= NULL
;
2261 * build and check path to extract_boot_filelist.ksh
2263 n
= snprintf(path
, sizeof (path
), "%s%s", root
, EXTRACT_BOOT_FILELIST
);
2264 if (n
>= sizeof (path
)) {
2265 bam_error(_("archive filelist is empty\n"));
2269 if (is_safe_exec(path
) == BAM_ERROR
)
2273 * If extract_boot_filelist is present, exec it, otherwise read
2274 * the filelists directly, for compatibility with older images.
2276 if (stat(path
, &sb
) == 0) {
2278 * build arguments to exec extract_boot_filelist.ksh
2280 char *rootarg
, *platarg
;
2281 int platarglen
= 1, rootarglen
= 1;
2282 if (strlen(root
) > 1)
2283 rootarglen
+= strlen(root
) + strlen("-R ");
2284 if (bam_alt_platform
)
2285 platarglen
+= strlen(bam_platform
) + strlen("-p ");
2286 platarg
= s_calloc(1, platarglen
);
2287 rootarg
= s_calloc(1, rootarglen
);
2291 if (strlen(root
) > 1) {
2292 (void) snprintf(rootarg
, rootarglen
,
2295 if (bam_alt_platform
) {
2296 (void) snprintf(platarg
, platarglen
,
2297 "-p %s", bam_platform
);
2299 n
= snprintf(cmd
, sizeof (cmd
), "%s %s %s /%s /%s",
2300 path
, rootarg
, platarg
, BOOT_FILE_LIST
, ETC_FILE_LIST
);
2303 if (n
>= sizeof (cmd
)) {
2304 bam_error(_("archive filelist is empty\n"));
2307 if (exec_cmd(cmd
, flistp
) != 0) {
2308 BAM_DPRINTF(("%s: failed to open archive "
2309 "filelist: %s: %s\n", fcn
, path
, strerror(errno
)));
2314 * Read current lists of files - only the first is mandatory
2316 rval
= read_one_list(root
, flistp
, BOOT_FILE_LIST
);
2317 if (rval
!= BAM_SUCCESS
)
2319 (void) read_one_list(root
, flistp
, ETC_FILE_LIST
);
2322 if (flistp
->head
== NULL
) {
2323 bam_error(_("archive filelist is empty\n"));
2327 return (BAM_SUCCESS
);
2331 getoldstat(char *root
)
2333 char path
[PATH_MAX
];
2338 (void) snprintf(path
, sizeof (path
), "%s%s", root
, FILE_STAT
);
2339 fd
= open(path
, O_RDONLY
);
2342 bam_print(_("failed to open file: %s: %s\n"),
2343 path
, strerror(errno
));
2347 if (fstat(fd
, &sb
) != 0) {
2348 bam_error(_("stat of file failed: %s: %s\n"), path
,
2353 ostat
= s_calloc(1, sb
.st_size
);
2355 if (read(fd
, ostat
, sb
.st_size
) != sb
.st_size
) {
2356 bam_error(_("read failed for file: %s: %s\n"), path
,
2365 walk_arg
.old_nvlp
= NULL
;
2366 error
= nvlist_unpack(ostat
, sb
.st_size
, &walk_arg
.old_nvlp
, 0);
2371 bam_error(_("failed to unpack stat data: %s: %s\n"),
2372 path
, strerror(error
));
2373 walk_arg
.old_nvlp
= NULL
;
2382 if (!is_flag_on(IS_SPARC_TARGET
))
2383 set_dir_flag(FILE32
, NEED_UPDATE
);
2384 set_dir_flag(FILE64
, NEED_UPDATE
);
2387 /* Best effort stale entry removal */
2389 delete_stale(char *file
, int what
)
2391 char path
[PATH_MAX
];
2394 (void) snprintf(path
, sizeof (path
), "%s/%s", get_cachedir(what
), file
);
2395 if (!bam_check
&& stat(path
, &sb
) == 0) {
2396 if (sb
.st_mode
& S_IFDIR
)
2397 (void) rmdir_r(path
);
2399 (void) unlink(path
);
2401 set_dir_flag(what
, (NEED_UPDATE
| NO_MULTI
));
2406 * Checks if a file in the current (old) archive has
2407 * been deleted from the root filesystem.
2410 check4stale(char *root
)
2415 char path
[PATH_MAX
];
2418 * Skip stale file check during smf check
2424 * If we need to (re)create the cache, there's no need to check for
2427 if (is_flag_on(NEED_CACHE_DIR
))
2430 /* Nothing to do if no old stats */
2431 if ((nvlp
= walk_arg
.old_nvlp
) == NULL
)
2434 for (nvp
= nvlist_next_nvpair(nvlp
, NULL
); nvp
;
2435 nvp
= nvlist_next_nvpair(nvlp
, nvp
)) {
2436 file
= nvpair_name(nvp
);
2439 (void) snprintf(path
, sizeof (path
), "%s/%s",
2441 if (access(path
, F_OK
) < 0) {
2445 bam_print(_(" stale %s\n"), path
);
2447 if (is_flag_on(IS_SPARC_TARGET
)) {
2448 set_dir_flag(FILE64
, NEED_UPDATE
);
2450 for (what
= FILE32
; what
< CACHEDIR_NUM
; what
++)
2451 if (has_cachedir(what
))
2452 delete_stale(file
, what
);
2459 create_newstat(void)
2463 error
= nvlist_alloc(&walk_arg
.new_nvlp
, NV_UNIQUE_NAME
, 0);
2466 * Not fatal - we can still create archive
2468 walk_arg
.new_nvlp
= NULL
;
2469 bam_error(_("failed to create stat data: %s\n"),
2475 walk_list(char *root
, filelist_t
*flistp
)
2477 char path
[PATH_MAX
];
2480 for (lp
= flistp
->head
; lp
; lp
= lp
->next
) {
2482 * Don't follow symlinks. A symlink must refer to
2483 * a file that would appear in the archive through
2484 * a direct reference. This matches the archive
2485 * construction behavior.
2487 (void) snprintf(path
, sizeof (path
), "%s%s", root
, lp
->line
);
2488 if (nftw(path
, cmpstat
, 20, FTW_PHYS
) == -1) {
2489 if (is_flag_on(UPDATE_ERROR
))
2492 * Some files may not exist.
2493 * For example: etc/rtc_config on a x86 diskless system
2494 * Emit verbose message only
2497 bam_print(_("cannot find: %s: %s\n"),
2498 path
, strerror(errno
));
2502 return (BAM_SUCCESS
);
2506 * Update the timestamp file.
2509 update_timestamp(char *root
)
2511 char timestamp_path
[PATH_MAX
];
2513 /* this path length has already been checked in check_flags_and_files */
2514 (void) snprintf(timestamp_path
, sizeof (timestamp_path
), "%s%s", root
,
2515 FILE_STAT_TIMESTAMP
);
2518 * recreate the timestamp file. Since an outdated or absent timestamp
2519 * file translates in a complete rebuild of the archive cache, notify
2520 * the user of the performance issue.
2522 if (creat(timestamp_path
, FILE_STAT_MODE
) < 0) {
2523 bam_error(_("failed to open file: %s: %s\n"), timestamp_path
,
2525 bam_error(_("failed to update the timestamp file, next"
2526 " archive update may experience reduced performance\n"));
2534 char path
[PATH_MAX
];
2535 char path2
[PATH_MAX
];
2538 int fd
, wrote
, error
;
2542 error
= nvlist_pack(walk_arg
.new_nvlp
, &nstat
, &sz
,
2545 bam_error(_("failed to pack stat data: %s\n"),
2550 (void) snprintf(path
, sizeof (path
), "%s%s", root
, FILE_STAT_TMP
);
2551 fd
= open(path
, O_RDWR
|O_CREAT
|O_TRUNC
, FILE_STAT_MODE
);
2553 bam_error(_("failed to open file: %s: %s\n"), path
,
2558 wrote
= write(fd
, nstat
, sz
);
2560 bam_error(_("write to file failed: %s: %s\n"), path
,
2569 (void) snprintf(path2
, sizeof (path2
), "%s%s", root
, FILE_STAT
);
2570 if (rename(path
, path2
) != 0) {
2571 bam_error(_("rename to file failed: %s: %s\n"), path2
,
2576 #define init_walk_args() bzero(&walk_arg, sizeof (walk_arg))
2579 clear_walk_args(void)
2581 nvlist_free(walk_arg
.old_nvlp
);
2582 nvlist_free(walk_arg
.new_nvlp
);
2583 if (walk_arg
.sparcfile
)
2584 (void) fclose(walk_arg
.sparcfile
);
2585 walk_arg
.old_nvlp
= NULL
;
2586 walk_arg
.new_nvlp
= NULL
;
2587 walk_arg
.sparcfile
= NULL
;
2592 * 0 - no update necessary
2593 * 1 - update required.
2594 * BAM_ERROR (-1) - An error occurred
2596 * Special handling for check (-n):
2597 * ================================
2598 * The check (-n) option produces parseable output.
2599 * To do this, we suppress all stdout messages unrelated
2600 * to out of sync files.
2601 * All stderr messages are still printed though.
2605 update_required(char *root
)
2608 char path
[PATH_MAX
];
2610 filelist_t
*flistp
= &flist
;
2613 flistp
->head
= flistp
->tail
= NULL
;
2616 set_flag(IS_SPARC_TARGET
);
2619 * Check if cache directories and archives are present
2622 ret
= check_flags_and_files(root
);
2627 * In certain deployment scenarios, filestat may not
2628 * exist. Do not stop the boot process, but trigger an update
2629 * of the archives (which will recreate filestat.ramdisk).
2631 if (bam_smf_check
) {
2632 (void) snprintf(path
, sizeof (path
), "%s%s", root
, FILE_STAT
);
2633 if (stat(path
, &sb
) != 0) {
2634 (void) creat(NEED_UPDATE_FILE
, 0644);
2642 * Check if the archive contains files that are no longer
2643 * present on the root filesystem.
2648 * read list of files
2650 if (read_list(root
, flistp
) != BAM_SUCCESS
) {
2655 assert(flistp
->head
&& flistp
->tail
);
2658 * At this point either the update is required
2659 * or the decision is pending. In either case
2660 * we need to create new stat nvlist
2664 * This walk does 2 things:
2665 * - gets new stat data for every file
2666 * - (optional) compare old and new stat data
2668 ret
= walk_list(root
, &flist
);
2670 /* done with the file list */
2671 filelist_free(flistp
);
2673 /* something went wrong */
2675 if (ret
== BAM_ERROR
) {
2676 bam_error(_("Failed to gather cache files, archives "
2677 "generation aborted\n"));
2681 if (walk_arg
.new_nvlp
== NULL
) {
2682 if (walk_arg
.sparcfile
!= NULL
)
2683 (void) fclose(walk_arg
.sparcfile
);
2684 bam_error(_("cannot create new stat data\n"));
2687 /* If nothing was updated, discard newstat. */
2689 if (!is_dir_flag_on(FILE32
, NEED_UPDATE
) &&
2690 !is_dir_flag_on(FILE64
, NEED_UPDATE
)) {
2695 if (walk_arg
.sparcfile
!= NULL
)
2696 (void) fclose(walk_arg
.sparcfile
);
2704 char cmd
[PATH_MAX
+ 30];
2706 (void) snprintf(cmd
, sizeof (cmd
), "%s -f \"%s\" 2>/dev/null",
2709 return (exec_cmd(cmd
, NULL
));
2713 do_archive_copy(char *source
, char *dest
)
2718 /* the equivalent of mv archive-new-$pid boot_archive */
2719 if (rename(source
, dest
) != 0) {
2720 (void) unlink(source
);
2724 if (flushfs(bam_root
) != 0)
2727 return (BAM_SUCCESS
);
2731 check_cmdline(filelist_t flist
)
2735 for (lp
= flist
.head
; lp
; lp
= lp
->next
) {
2736 if (strstr(lp
->line
, "Error:") != NULL
||
2737 strstr(lp
->line
, "Inode number overflow") != NULL
) {
2738 (void) fprintf(stderr
, "%s\n", lp
->line
);
2743 return (BAM_SUCCESS
);
2747 dump_errormsg(filelist_t flist
)
2751 for (lp
= flist
.head
; lp
; lp
= lp
->next
)
2752 (void) fprintf(stderr
, "%s\n", lp
->line
);
2756 check_archive(char *dest
)
2760 if (stat(dest
, &sb
) != 0 || !S_ISREG(sb
.st_mode
) ||
2761 sb
.st_size
< 10000) {
2762 bam_error(_("archive file %s not generated correctly\n"), dest
);
2763 (void) unlink(dest
);
2767 return (BAM_SUCCESS
);
2774 libzfs_handle_t
*hdl
;
2775 be_node_list_t
*be_nodes
= NULL
;
2776 be_node_list_t
*cur_be
;
2777 boolean_t be_exist
= B_FALSE
;
2778 char ds_path
[ZFS_MAX_DATASET_NAME_LEN
];
2783 * Get dataset for mountpoint
2785 if ((hdl
= libzfs_init()) == NULL
)
2788 if ((zhp
= zfs_path_to_zhandle(hdl
, root
,
2789 ZFS_TYPE_FILESYSTEM
)) == NULL
) {
2794 (void) strlcpy(ds_path
, zfs_get_name(zhp
), sizeof (ds_path
));
2797 * Check if the current dataset is BE
2799 if (be_list(NULL
, &be_nodes
) == BE_SUCCESS
) {
2800 for (cur_be
= be_nodes
; cur_be
!= NULL
;
2801 cur_be
= cur_be
->be_next_node
) {
2804 * Because we guarantee that cur_be->be_root_ds
2805 * is null-terminated by internal data structure,
2806 * we can safely use strcmp()
2808 if (strcmp(ds_path
, cur_be
->be_root_ds
) == 0) {
2813 be_free_list(be_nodes
);
2822 * Returns 1 if mkiso is in the expected PATH, 0 otherwise
2827 if (access(MKISOFS_PATH
, X_OK
) == 0)
2832 #define MKISO_PARAMS " -quiet -graft-points -dlrDJN -relaxed-filenames "
2835 create_sparc_archive(char *archive
, char *tempname
, char *bootblk
, char *list
)
2838 char cmdline
[3 * PATH_MAX
+ 64];
2839 filelist_t flist
= {0};
2840 const char *func
= "create_sparc_archive()";
2842 if (access(bootblk
, R_OK
) == 1) {
2843 bam_error(_("unable to access bootblk file : %s\n"), bootblk
);
2848 * Prepare mkisofs command line and execute it
2850 (void) snprintf(cmdline
, sizeof (cmdline
), "%s %s -G %s -o \"%s\" "
2851 "-path-list \"%s\" 2>&1", MKISOFS_PATH
, MKISO_PARAMS
, bootblk
,
2854 BAM_DPRINTF(("%s: executing: %s\n", func
, cmdline
));
2856 ret
= exec_cmd(cmdline
, &flist
);
2857 if (ret
!= 0 || check_cmdline(flist
) == BAM_ERROR
) {
2858 dump_errormsg(flist
);
2862 filelist_free(&flist
);
2865 * Prepare dd command line to copy the bootblk on the new archive and
2868 (void) snprintf(cmdline
, sizeof (cmdline
), "%s if=\"%s\" of=\"%s\""
2869 " bs=1b oseek=1 count=15 conv=notrunc conv=sync 2>&1", DD_PATH_USR
,
2872 BAM_DPRINTF(("%s: executing: %s\n", func
, cmdline
));
2874 ret
= exec_cmd(cmdline
, &flist
);
2875 if (ret
!= 0 || check_cmdline(flist
) == BAM_ERROR
)
2878 filelist_free(&flist
);
2880 /* Did we get a valid archive ? */
2881 if (check_archive(tempname
) == BAM_ERROR
)
2884 return (do_archive_copy(tempname
, archive
));
2887 filelist_free(&flist
);
2888 bam_error(_("boot-archive creation FAILED, command: '%s'\n"), cmdline
);
2889 (void) unlink(tempname
);
2894 from_733(unsigned char *s
)
2897 unsigned int ret
= 0;
2899 for (i
= 0; i
< 4; i
++)
2900 ret
|= s
[i
] << (8 * i
);
2906 to_733(unsigned char *s
, unsigned int val
)
2910 for (i
= 0; i
< 4; i
++)
2911 s
[i
] = s
[7-i
] = (val
>> (8 * i
)) & 0xFF;
2915 * creates sha1 hash of archive
2918 digest_archive(const char *archive
)
2925 (void) asprintf(&archive_hash
, "%s.hash", archive
);
2926 if (archive_hash
== NULL
)
2929 if ((ret
= bootadm_digest(archive
, &hash
)) == BAM_ERROR
) {
2934 fp
= fopen(archive_hash
, "w");
2941 (void) fprintf(fp
, "%s\n", hash
);
2945 return (BAM_SUCCESS
);
2949 * Extends the current boot archive without recreating it from scratch
2952 extend_iso_archive(char *archive
, char *tempname
, char *update_dir
)
2954 int fd
= -1, newfd
= -1, ret
, i
;
2955 int next_session
= 0, new_size
= 0;
2956 char cmdline
[3 * PATH_MAX
+ 64];
2957 const char *func
= "extend_iso_archive()";
2958 filelist_t flist
= {0};
2959 struct iso_pdesc saved_desc
[MAX_IVDs
];
2961 fd
= open(archive
, O_RDWR
);
2964 bam_error(_("failed to open file: %s: %s\n"),
2965 archive
, strerror(errno
));
2970 * A partial read is likely due to a corrupted file
2972 ret
= pread64(fd
, saved_desc
, sizeof (saved_desc
),
2973 VOLDESC_OFF
* CD_BLOCK
);
2974 if (ret
!= sizeof (saved_desc
)) {
2976 bam_error(_("read failed for file: %s: %s\n"),
2977 archive
, strerror(errno
));
2981 if (memcmp(saved_desc
[0].type
, "\1CD001", 6)) {
2983 bam_error(_("iso descriptor signature for %s is "
2984 "invalid\n"), archive
);
2989 * Read primary descriptor and locate next_session offset (it should
2990 * point to the end of the archive)
2992 next_session
= P2ROUNDUP(from_733(saved_desc
[0].volume_space_size
), 16);
2994 (void) snprintf(cmdline
, sizeof (cmdline
), "%s -C 16,%d -M %s %s -o \""
2995 "%s\" \"%s\" 2>&1", MKISOFS_PATH
, next_session
, archive
,
2996 MKISO_PARAMS
, tempname
, update_dir
);
2998 BAM_DPRINTF(("%s: executing: %s\n", func
, cmdline
));
3000 ret
= exec_cmd(cmdline
, &flist
);
3001 if (ret
!= 0 || check_cmdline(flist
) == BAM_ERROR
) {
3003 bam_error(_("Command '%s' failed while generating "
3004 "multisession archive\n"), cmdline
);
3005 dump_errormsg(flist
);
3009 filelist_free(&flist
);
3011 newfd
= open(tempname
, O_RDONLY
);
3014 bam_error(_("failed to open file: %s: %s\n"),
3015 archive
, strerror(errno
));
3019 ret
= pread64(newfd
, saved_desc
, sizeof (saved_desc
),
3020 VOLDESC_OFF
* CD_BLOCK
);
3021 if (ret
!= sizeof (saved_desc
)) {
3023 bam_error(_("read failed for file: %s: %s\n"),
3024 archive
, strerror(errno
));
3028 if (memcmp(saved_desc
[0].type
, "\1CD001", 6)) {
3030 bam_error(_("iso descriptor signature for %s is "
3031 "invalid\n"), archive
);
3035 new_size
= from_733(saved_desc
[0].volume_space_size
) + next_session
;
3036 to_733(saved_desc
[0].volume_space_size
, new_size
);
3038 for (i
= 1; i
< MAX_IVDs
; i
++) {
3039 if (saved_desc
[i
].type
[0] == (unsigned char)255)
3041 if (memcmp(saved_desc
[i
].id
, "CD001", 5))
3045 bam_print("%s: Updating descriptor entry [%d]\n", func
,
3048 to_733(saved_desc
[i
].volume_space_size
, new_size
);
3051 ret
= pwrite64(fd
, saved_desc
, DVD_BLOCK
, VOLDESC_OFF
*CD_BLOCK
);
3052 if (ret
!= DVD_BLOCK
) {
3054 bam_error(_("write to file failed: %s: %s\n"),
3055 archive
, strerror(errno
));
3058 (void) close(newfd
);
3068 bam_error(_("failed to close file: %s: %s\n"),
3069 archive
, strerror(errno
));
3074 (void) snprintf(cmdline
, sizeof (cmdline
), "%s if=%s of=%s bs=32k "
3075 "seek=%d conv=sync 2>&1", DD_PATH_USR
, tempname
, archive
,
3078 BAM_DPRINTF(("%s: executing: %s\n", func
, cmdline
));
3080 ret
= exec_cmd(cmdline
, &flist
);
3081 if (ret
!= 0 || check_cmdline(flist
) == BAM_ERROR
) {
3083 bam_error(_("Command '%s' failed while generating "
3084 "multisession archive\n"), cmdline
);
3087 filelist_free(&flist
);
3089 (void) unlink(tempname
);
3091 if (digest_archive(archive
) == BAM_ERROR
&& bam_verbose
)
3092 bam_print("boot archive hashing failed\n");
3094 if (flushfs(bam_root
) != 0)
3098 bam_print("boot archive updated successfully\n");
3100 return (BAM_SUCCESS
);
3103 filelist_free(&flist
);
3108 (void) close(newfd
);
3113 create_x86_archive(char *archive
, char *tempname
, char *update_dir
)
3116 char cmdline
[3 * PATH_MAX
+ 64];
3117 filelist_t flist
= {0};
3118 const char *func
= "create_x86_archive()";
3120 (void) snprintf(cmdline
, sizeof (cmdline
), "%s %s -o \"%s\" \"%s\" "
3121 "2>&1", MKISOFS_PATH
, MKISO_PARAMS
, tempname
, update_dir
);
3123 BAM_DPRINTF(("%s: executing: %s\n", func
, cmdline
));
3125 ret
= exec_cmd(cmdline
, &flist
);
3126 if (ret
!= 0 || check_cmdline(flist
) == BAM_ERROR
) {
3127 bam_error(_("boot-archive creation FAILED, command: '%s'\n"),
3129 dump_errormsg(flist
);
3130 filelist_free(&flist
);
3131 (void) unlink(tempname
);
3135 filelist_free(&flist
);
3137 if (check_archive(tempname
) == BAM_ERROR
)
3140 return (do_archive_copy(tempname
, archive
));
3144 mkisofs_archive(char *root
, int what
)
3147 char temp
[PATH_MAX
];
3148 char bootblk
[PATH_MAX
];
3149 char boot_archive
[PATH_MAX
];
3151 if (what
== FILE64
&& !is_flag_on(IS_SPARC_TARGET
))
3152 ret
= snprintf(temp
, sizeof (temp
),
3153 "%s%s%s/amd64/archive-new-%d", root
, ARCHIVE_PREFIX
,
3154 get_machine(), getpid());
3156 ret
= snprintf(temp
, sizeof (temp
), "%s%s%s/archive-new-%d",
3157 root
, ARCHIVE_PREFIX
, get_machine(), getpid());
3159 if (ret
>= sizeof (temp
))
3162 if (what
== FILE64
&& !is_flag_on(IS_SPARC_TARGET
))
3163 ret
= snprintf(boot_archive
, sizeof (boot_archive
),
3164 "%s%s%s/amd64%s", root
, ARCHIVE_PREFIX
, get_machine(),
3167 ret
= snprintf(boot_archive
, sizeof (boot_archive
),
3168 "%s%s%s%s", root
, ARCHIVE_PREFIX
, get_machine(),
3171 if (ret
>= sizeof (boot_archive
))
3174 bam_print("updating %s\n", boot_archive
);
3176 if (is_flag_on(IS_SPARC_TARGET
)) {
3177 ret
= snprintf(bootblk
, sizeof (bootblk
),
3178 "%s/platform/%s/lib/fs/hsfs/bootblk", root
, get_machine());
3179 if (ret
>= sizeof (bootblk
))
3182 ret
= create_sparc_archive(boot_archive
, temp
, bootblk
,
3183 get_cachedir(what
));
3185 if (!is_dir_flag_on(what
, NO_MULTI
)) {
3187 bam_print("Attempting to extend x86 archive: "
3188 "%s\n", boot_archive
);
3190 ret
= extend_iso_archive(boot_archive
, temp
,
3191 get_updatedir(what
));
3192 if (ret
== BAM_SUCCESS
) {
3194 bam_print("Successfully extended %s\n",
3197 (void) rmdir_r(get_updatedir(what
));
3198 return (BAM_SUCCESS
);
3202 * The boot archive will be recreated from scratch. We get here
3203 * if at least one of these conditions is true:
3204 * - bootadm was called without the -e switch
3205 * - the archive (or the archive cache) doesn't exist
3206 * - archive size is bigger than BA_SIZE_MAX
3207 * - more than COUNT_MAX files need to be updated
3208 * - an error occourred either populating the /updates directory
3209 * or extend_iso_archive() failed
3212 bam_print("Unable to extend %s... rebuilding archive\n",
3215 if (get_updatedir(what
)[0] != '\0')
3216 (void) rmdir_r(get_updatedir(what
));
3219 ret
= create_x86_archive(boot_archive
, temp
,
3220 get_cachedir(what
));
3223 if (digest_archive(boot_archive
) == BAM_ERROR
&& bam_verbose
)
3224 bam_print("boot archive hashing failed\n");
3226 if (ret
== BAM_SUCCESS
&& bam_verbose
)
3227 bam_print("Successfully created %s\n", boot_archive
);
3232 bam_error(_("unable to create path on mountpoint %s, path too long\n"),
3238 create_ramdisk(char *root
)
3240 char *cmdline
, path
[PATH_MAX
];
3243 int ret
, what
, status
= BAM_SUCCESS
;
3245 /* If there is mkisofs, use it to create the required archives */
3247 for (what
= FILE32
; what
< CACHEDIR_NUM
; what
++) {
3248 if (has_cachedir(what
) && is_dir_flag_on(what
,
3250 ret
= mkisofs_archive(root
, what
);
3259 * Else setup command args for create_ramdisk.ksh for the UFS archives
3260 * Note: we will not create hash here, CREATE_RAMDISK should create it.
3263 bam_print("mkisofs not found, creating UFS archive\n");
3265 (void) snprintf(path
, sizeof (path
), "%s/%s", root
, CREATE_RAMDISK
);
3266 if (stat(path
, &sb
) != 0) {
3267 bam_error(_("archive creation file not found: %s: %s\n"),
3268 path
, strerror(errno
));
3272 if (is_safe_exec(path
) == BAM_ERROR
)
3275 len
= strlen(path
) + strlen(root
) + 10; /* room for space + -R */
3276 if (bam_alt_platform
)
3277 len
+= strlen(bam_platform
) + strlen("-p ");
3278 cmdline
= s_calloc(1, len
);
3280 if (bam_alt_platform
) {
3281 assert(strlen(root
) > 1);
3282 (void) snprintf(cmdline
, len
, "%s -p %s -R %s",
3283 path
, bam_platform
, root
);
3284 /* chop off / at the end */
3285 cmdline
[strlen(cmdline
) - 1] = '\0';
3286 } else if (strlen(root
) > 1) {
3287 (void) snprintf(cmdline
, len
, "%s -R %s", path
, root
);
3288 /* chop off / at the end */
3289 cmdline
[strlen(cmdline
) - 1] = '\0';
3291 (void) snprintf(cmdline
, len
, "%s", path
);
3293 if (exec_cmd(cmdline
, NULL
) != 0) {
3294 bam_error(_("boot-archive creation FAILED, command: '%s'\n"),
3301 * The existence of the expected archives used to be
3302 * verified here. This check is done in create_ramdisk as
3303 * it needs to be in sync with the altroot operated upon.
3305 return (BAM_SUCCESS
);
3309 * Checks if target filesystem is on a ramdisk
3312 * When in doubt assume it is not a ramdisk.
3315 is_ramdisk(char *root
)
3317 struct extmnttab mnt
;
3320 char mntpt
[PATH_MAX
];
3324 * There are 3 situations where creating archive is
3326 * - create boot_archive on a lofi-mounted boot_archive
3327 * - create it on a ramdisk which is the root filesystem
3328 * - create it on a ramdisk mounted somewhere else
3329 * The first is not easy to detect and checking for it is not
3331 * The other two conditions are handled here
3333 fp
= fopen(MNTTAB
, "r");
3335 bam_error(_("failed to open file: %s: %s\n"),
3336 MNTTAB
, strerror(errno
));
3343 * Remove any trailing / from the mount point
3345 (void) strlcpy(mntpt
, root
, sizeof (mntpt
));
3346 if (strcmp(root
, "/") != 0) {
3347 cp
= mntpt
+ strlen(mntpt
) - 1;
3352 while (getextmntent(fp
, &mnt
, sizeof (mnt
)) == 0) {
3353 if (strcmp(mnt
.mnt_mountp
, mntpt
) == 0) {
3361 bam_error(_("alternate root %s not in mnttab\n"),
3367 if (strncmp(mnt
.mnt_special
, RAMDISK_SPECIAL
,
3368 strlen(RAMDISK_SPECIAL
)) == 0) {
3370 bam_error(_("%s is on a ramdisk device\n"), bam_root
);
3381 is_boot_archive(char *root
)
3383 char path
[PATH_MAX
];
3386 const char *fcn
= "is_boot_archive()";
3389 * We can't create an archive without the create_ramdisk script
3391 (void) snprintf(path
, sizeof (path
), "%s/%s", root
, CREATE_RAMDISK
);
3392 error
= stat(path
, &sb
);
3393 INJECT_ERROR1("NOT_ARCHIVE_BASED", error
= -1);
3396 bam_print(_("file not found: %s\n"), path
);
3397 BAM_DPRINTF(("%s: not a boot archive based Solaris "
3398 "instance: %s\n", fcn
, root
));
3402 BAM_DPRINTF(("%s: *IS* a boot archive based Solaris instance: %s\n",
3412 const char *fcn
= "is_zfs()";
3414 ret
= statvfs(root
, &vfs
);
3415 INJECT_ERROR1("STATVFS_ZFS", ret
= 1);
3417 bam_error(_("statvfs failed for %s: %s\n"), root
,
3422 if (strncmp(vfs
.f_basetype
, "zfs", strlen("zfs")) == 0) {
3423 BAM_DPRINTF(("%s: is a ZFS filesystem: %s\n", fcn
, root
));
3426 BAM_DPRINTF(("%s: is *NOT* a ZFS filesystem: %s\n", fcn
, root
));
3432 is_readonly(char *root
)
3436 char testfile
[PATH_MAX
];
3437 const char *fcn
= "is_readonly()";
3440 * Using statvfs() to check for a read-only filesystem is not
3441 * reliable. The only way to reliably test is to attempt to
3444 (void) snprintf(testfile
, sizeof (testfile
), "%s/%s.%d",
3445 root
, BOOTADM_RDONLY_TEST
, getpid());
3447 (void) unlink(testfile
);
3450 fd
= open(testfile
, O_RDWR
|O_CREAT
|O_EXCL
, 0644);
3452 INJECT_ERROR2("RDONLY_TEST_ERROR", fd
= -1, error
= EACCES
);
3453 if (fd
== -1 && error
== EROFS
) {
3454 BAM_DPRINTF(("%s: is a READONLY filesystem: %s\n", fcn
, root
));
3456 } else if (fd
== -1) {
3457 bam_error(_("error during read-only test on %s: %s\n"),
3458 root
, strerror(error
));
3462 (void) unlink(testfile
);
3464 BAM_DPRINTF(("%s: is a RDWR filesystem: %s\n", fcn
, root
));
3469 update_archive(char *root
, char *opt
)
3474 assert(opt
== NULL
);
3480 * Never update non-BE root in update_all
3482 if (!is_be(root
) && bam_update_all
)
3483 return (BAM_SUCCESS
);
3485 * root must belong to a boot archive based OS,
3487 if (!is_boot_archive(root
)) {
3489 * Emit message only if not in context of update_all.
3490 * If in update_all, emit only if verbose flag is set.
3492 if (!bam_update_all
|| bam_verbose
)
3493 bam_print(_("%s: not a boot archive based Solaris "
3494 "instance\n"), root
);
3499 * If smf check is requested when / is writable (can happen
3500 * on first reboot following an upgrade because service
3501 * dependency is messed up), skip the check.
3503 if (bam_smf_check
&& !bam_root_readonly
&& !is_zfs(root
))
3504 return (BAM_SUCCESS
);
3507 * Don't generate archive on ramdisk.
3509 if (is_ramdisk(root
))
3510 return (BAM_SUCCESS
);
3513 * root must be writable. This check applies to alternate
3514 * root (-R option); bam_root_readonly applies to '/' only.
3515 * The behaviour translates into being the one of a 'check'.
3517 if (!bam_smf_check
&& !bam_check
&& is_readonly(root
)) {
3518 set_flag(RDONLY_FSCHK
);
3523 * Now check if an update is really needed.
3525 ret
= update_required(root
);
3528 * The check command (-n) is *not* a dry run.
3529 * It only checks if the archive is in sync.
3530 * A readonly filesystem has to be considered an error only if an update
3533 if (bam_nowrite()) {
3534 if (is_flag_on(RDONLY_FSCHK
)) {
3535 bam_check
= bam_saved_check
;
3537 bam_error(_("%s filesystem is read-only, "
3538 "skipping archives update\n"), root
);
3540 return ((ret
!= 0) ? BAM_ERROR
: BAM_SUCCESS
);
3543 bam_exit((ret
!= 0) ? 1 : 0);
3547 /* create the ramdisk */
3548 ret
= create_ramdisk(root
);
3552 * if the archive is updated, save the new stat data and update the
3555 if (ret
== 0 && walk_arg
.new_nvlp
!= NULL
) {
3557 update_timestamp(root
);
3566 update_all(char *root
, char *opt
)
3568 struct extmnttab mnt
;
3571 char multibt
[PATH_MAX
];
3572 char creatram
[PATH_MAX
];
3573 error_t ret
= BAM_SUCCESS
;
3576 assert(opt
== NULL
);
3578 if (bam_rootlen
!= 1 || *root
!= '/') {
3579 elide_trailing_slash(root
, multibt
, sizeof (multibt
));
3580 bam_error(_("an alternate root (%s) cannot be used with this "
3581 "sub-command\n"), multibt
);
3586 * First update archive for current root
3588 if (update_archive(root
, opt
) != BAM_SUCCESS
)
3591 if (ret
== BAM_ERROR
)
3595 * Now walk the mount table, performing archive update
3596 * for all mounted Newboot root filesystems
3598 fp
= fopen(MNTTAB
, "r");
3600 bam_error(_("failed to open file: %s: %s\n"),
3601 MNTTAB
, strerror(errno
));
3608 while (getextmntent(fp
, &mnt
, sizeof (mnt
)) == 0) {
3609 if (mnt
.mnt_special
== NULL
)
3611 if ((strcmp(mnt
.mnt_fstype
, MNTTYPE_ZFS
) != 0) &&
3612 (strncmp(mnt
.mnt_special
, "/dev/", strlen("/dev/")) != 0))
3614 if (strcmp(mnt
.mnt_mountp
, "/") == 0)
3617 (void) snprintf(creatram
, sizeof (creatram
), "%s/%s",
3618 mnt
.mnt_mountp
, CREATE_RAMDISK
);
3620 if (stat(creatram
, &sb
) == -1)
3624 * We put a trailing slash to be consistent with root = "/"
3625 * case, such that we don't have to print // in some cases.
3627 (void) snprintf(rootbuf
, sizeof (rootbuf
), "%s/",
3629 bam_rootlen
= strlen(rootbuf
);
3632 * It's possible that other mounts may be an alternate boot
3633 * architecture, so check it again.
3635 if ((get_boot_cap(rootbuf
) != BAM_SUCCESS
) ||
3636 (update_archive(rootbuf
, opt
) != BAM_SUCCESS
))
3644 * We no longer use biosdev for Live Upgrade. Hence
3645 * there is no need to defer (to shutdown time) any fdisk
3648 if (stat(GRUB_fdisk
, &sb
) == 0 || stat(GRUB_fdisk_target
, &sb
) == 0) {
3649 bam_error(_("Deferred FDISK update file(s) found: %s, %s. "
3650 "Not supported.\n"), GRUB_fdisk
, GRUB_fdisk_target
);
3657 get_mountpoint(char *special
, char *fstype
)
3660 struct mnttab mp
= {0};
3661 struct mnttab mpref
= {0};
3664 const char *fcn
= "get_mountpoint()";
3666 BAM_DPRINTF(("%s: entered. args: %s %s\n", fcn
, special
, fstype
));
3668 mntfp
= fopen(MNTTAB
, "r");
3670 INJECT_ERROR1("MNTTAB_ERR_GET_MNTPT", mntfp
= NULL
);
3671 if (mntfp
== NULL
) {
3672 bam_error(_("failed to open file: %s: %s\n"),
3673 MNTTAB
, strerror(error
));
3677 mpref
.mnt_special
= special
;
3678 mpref
.mnt_fstype
= fstype
;
3680 ret
= getmntany(mntfp
, &mp
, &mpref
);
3681 INJECT_ERROR1("GET_MOUNTPOINT_MNTANY", ret
= 1);
3683 (void) fclose(mntfp
);
3684 BAM_DPRINTF(("%s: no mount-point for special=%s and "
3685 "fstype=%s\n", fcn
, special
, fstype
));
3688 (void) fclose(mntfp
);
3690 assert(mp
.mnt_mountp
);
3692 BAM_DPRINTF(("%s: returning mount-point for special %s: %s\n",
3693 fcn
, special
, mp
.mnt_mountp
));
3695 return (s_strdup(mp
.mnt_mountp
));
3699 * Mounts a "legacy" top dataset (if needed)
3700 * Returns: The mountpoint of the legacy top dataset or NULL on error
3701 * mnted returns one of the above values defined for zfs_mnted_t
3704 mount_legacy_dataset(char *pool
, zfs_mnted_t
*mnted
)
3707 char tmpmnt
[PATH_MAX
];
3708 filelist_t flist
= {0};
3712 const char *fcn
= "mount_legacy_dataset()";
3714 BAM_DPRINTF(("%s: entered. arg: %s\n", fcn
, pool
));
3716 *mnted
= ZFS_MNT_ERROR
;
3718 (void) snprintf(cmd
, sizeof (cmd
),
3719 "/sbin/zfs get -Ho value mounted %s",
3722 ret
= exec_cmd(cmd
, &flist
);
3723 INJECT_ERROR1("Z_MOUNT_LEG_GET_MOUNTED_CMD", ret
= 1);
3725 bam_error(_("failed to determine mount status of ZFS "
3726 "pool %s\n"), pool
);
3730 INJECT_ERROR1("Z_MOUNT_LEG_GET_MOUNTED_OUT", flist
.head
= NULL
);
3731 if ((flist
.head
== NULL
) || (flist
.head
!= flist
.tail
)) {
3732 bam_error(_("ZFS pool %s has bad mount status\n"), pool
);
3733 filelist_free(&flist
);
3737 is_mounted
= strtok(flist
.head
->line
, " \t\n");
3738 INJECT_ERROR1("Z_MOUNT_LEG_GET_MOUNTED_STRTOK_YES", is_mounted
= "yes");
3739 INJECT_ERROR1("Z_MOUNT_LEG_GET_MOUNTED_STRTOK_NO", is_mounted
= "no");
3740 if (strcmp(is_mounted
, "no") != 0) {
3741 filelist_free(&flist
);
3742 *mnted
= LEGACY_ALREADY
;
3743 /* get_mountpoint returns a strdup'ed string */
3744 BAM_DPRINTF(("%s: legacy pool %s already mounted\n",
3746 return (get_mountpoint(pool
, "zfs"));
3749 filelist_free(&flist
);
3752 * legacy top dataset is not mounted. Mount it now
3753 * First create a mountpoint.
3755 (void) snprintf(tmpmnt
, sizeof (tmpmnt
), "%s.%d",
3756 ZFS_LEGACY_MNTPT
, getpid());
3758 ret
= stat(tmpmnt
, &sb
);
3760 BAM_DPRINTF(("%s: legacy pool %s mount-point %s absent\n",
3761 fcn
, pool
, tmpmnt
));
3762 ret
= mkdirp(tmpmnt
, DIR_PERMS
);
3763 INJECT_ERROR1("Z_MOUNT_TOP_LEG_MNTPT_MKDIRP", ret
= -1);
3765 bam_error(_("mkdir of %s failed: %s\n"), tmpmnt
,
3770 BAM_DPRINTF(("%s: legacy pool %s mount-point %s is already "
3771 "present\n", fcn
, pool
, tmpmnt
));
3774 (void) snprintf(cmd
, sizeof (cmd
),
3775 "/sbin/mount -F zfs %s %s",
3778 ret
= exec_cmd(cmd
, NULL
);
3779 INJECT_ERROR1("Z_MOUNT_TOP_LEG_MOUNT_CMD", ret
= 1);
3781 bam_error(_("mount of ZFS pool %s failed\n"), pool
);
3782 (void) rmdir(tmpmnt
);
3786 *mnted
= LEGACY_MOUNTED
;
3787 BAM_DPRINTF(("%s: legacy pool %s successfully mounted at %s\n",
3788 fcn
, pool
, tmpmnt
));
3789 return (s_strdup(tmpmnt
));
3793 * Mounts the top dataset (if needed)
3794 * Returns: The mountpoint of the top dataset or NULL on error
3795 * mnted returns one of the above values defined for zfs_mnted_t
3798 mount_top_dataset(char *pool
, zfs_mnted_t
*mnted
)
3801 filelist_t flist
= {0};
3806 const char *fcn
= "mount_top_dataset()";
3808 *mnted
= ZFS_MNT_ERROR
;
3810 BAM_DPRINTF(("%s: entered. arg: %s\n", fcn
, pool
));
3813 * First check if the top dataset is a "legacy" dataset
3815 (void) snprintf(cmd
, sizeof (cmd
),
3816 "/sbin/zfs get -Ho value mountpoint %s",
3818 ret
= exec_cmd(cmd
, &flist
);
3819 INJECT_ERROR1("Z_MOUNT_TOP_GET_MNTPT", ret
= 1);
3821 bam_error(_("failed to determine mount point of ZFS pool %s\n"),
3826 if (flist
.head
&& (flist
.head
== flist
.tail
)) {
3827 char *legacy
= strtok(flist
.head
->line
, " \t\n");
3828 if (legacy
&& strcmp(legacy
, "legacy") == 0) {
3829 filelist_free(&flist
);
3830 BAM_DPRINTF(("%s: is legacy, pool=%s\n", fcn
, pool
));
3831 return (mount_legacy_dataset(pool
, mnted
));
3835 filelist_free(&flist
);
3837 BAM_DPRINTF(("%s: is *NOT* legacy, pool=%s\n", fcn
, pool
));
3839 (void) snprintf(cmd
, sizeof (cmd
),
3840 "/sbin/zfs get -Ho value mounted %s",
3843 ret
= exec_cmd(cmd
, &flist
);
3844 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MOUNTED", ret
= 1);
3846 bam_error(_("failed to determine mount status of ZFS "
3847 "pool %s\n"), pool
);
3851 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MOUNTED_VAL", flist
.head
= NULL
);
3852 if ((flist
.head
== NULL
) || (flist
.head
!= flist
.tail
)) {
3853 bam_error(_("ZFS pool %s has bad mount status\n"), pool
);
3854 filelist_free(&flist
);
3858 is_mounted
= strtok(flist
.head
->line
, " \t\n");
3859 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MOUNTED_YES", is_mounted
= "yes");
3860 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MOUNTED_NO", is_mounted
= "no");
3861 if (strcmp(is_mounted
, "no") != 0) {
3862 filelist_free(&flist
);
3863 *mnted
= ZFS_ALREADY
;
3864 BAM_DPRINTF(("%s: non-legacy pool %s mounted already\n",
3869 filelist_free(&flist
);
3870 BAM_DPRINTF(("%s: non-legacy pool %s *NOT* already mounted\n",
3873 /* top dataset is not mounted. Mount it now */
3874 (void) snprintf(cmd
, sizeof (cmd
),
3875 "/sbin/zfs mount %s", pool
);
3876 ret
= exec_cmd(cmd
, NULL
);
3877 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_MOUNT_CMD", ret
= 1);
3879 bam_error(_("mount of ZFS pool %s failed\n"), pool
);
3882 *mnted
= ZFS_MOUNTED
;
3883 BAM_DPRINTF(("%s: non-legacy pool %s mounted now\n", fcn
, pool
));
3887 * Now get the mountpoint
3889 (void) snprintf(cmd
, sizeof (cmd
),
3890 "/sbin/zfs get -Ho value mountpoint %s",
3893 ret
= exec_cmd(cmd
, &flist
);
3894 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MNTPT_CMD", ret
= 1);
3896 bam_error(_("failed to determine mount point of ZFS pool %s\n"),
3901 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MNTPT_OUT", flist
.head
= NULL
);
3902 if ((flist
.head
== NULL
) || (flist
.head
!= flist
.tail
)) {
3903 bam_error(_("ZFS pool %s has no mount-point\n"), pool
);
3907 mntpt
= strtok(flist
.head
->line
, " \t\n");
3908 INJECT_ERROR1("Z_MOUNT_TOP_NONLEG_GET_MNTPT_STRTOK", mntpt
= "foo");
3909 if (*mntpt
!= '/') {
3910 bam_error(_("ZFS pool %s has bad mount-point %s\n"),
3914 zmntpt
= s_strdup(mntpt
);
3916 filelist_free(&flist
);
3918 BAM_DPRINTF(("%s: non-legacy pool %s is mounted at %s\n",
3919 fcn
, pool
, zmntpt
));
3924 filelist_free(&flist
);
3925 (void) umount_top_dataset(pool
, *mnted
, NULL
);
3926 BAM_DPRINTF(("%s: returning FAILURE\n", fcn
));
3931 umount_top_dataset(char *pool
, zfs_mnted_t mnted
, char *mntpt
)
3935 const char *fcn
= "umount_top_dataset()";
3937 INJECT_ERROR1("Z_UMOUNT_TOP_INVALID_STATE", mnted
= ZFS_MNT_ERROR
);
3939 case LEGACY_ALREADY
:
3942 BAM_DPRINTF(("%s: pool %s was already mounted at %s, Nothing "
3943 "to umount\n", fcn
, pool
, mntpt
? mntpt
: "NULL"));
3945 return (BAM_SUCCESS
);
3946 case LEGACY_MOUNTED
:
3947 (void) snprintf(cmd
, sizeof (cmd
),
3948 "/sbin/umount %s", pool
);
3949 ret
= exec_cmd(cmd
, NULL
);
3950 INJECT_ERROR1("Z_UMOUNT_TOP_LEGACY_UMOUNT_FAIL", ret
= 1);
3952 bam_error(_("umount of %s failed\n"), pool
);
3957 (void) rmdir(mntpt
);
3959 BAM_DPRINTF(("%s: legacy pool %s was mounted by us, "
3960 "successfully unmounted\n", fcn
, pool
));
3961 return (BAM_SUCCESS
);
3964 (void) snprintf(cmd
, sizeof (cmd
),
3965 "/sbin/zfs unmount %s", pool
);
3966 ret
= exec_cmd(cmd
, NULL
);
3967 INJECT_ERROR1("Z_UMOUNT_TOP_NONLEG_UMOUNT_FAIL", ret
= 1);
3969 bam_error(_("umount of %s failed\n"), pool
);
3972 BAM_DPRINTF(("%s: nonleg pool %s was mounted by us, "
3973 "successfully unmounted\n", fcn
, pool
));
3974 return (BAM_SUCCESS
);
3976 bam_error(_("Internal error: bad saved mount state for "
3977 "pool %s\n"), pool
);
3984 get_special(char *mountp
)
3987 struct mnttab mp
= {0};
3988 struct mnttab mpref
= {0};
3991 const char *fcn
= "get_special()";
3993 INJECT_ERROR1("GET_SPECIAL_MNTPT", mountp
= NULL
);
3994 if (mountp
== NULL
) {
3995 bam_error(_("cannot get special file: NULL mount-point\n"));
3999 mntfp
= fopen(MNTTAB
, "r");
4001 INJECT_ERROR1("GET_SPECIAL_MNTTAB_OPEN", mntfp
= NULL
);
4002 if (mntfp
== NULL
) {
4003 bam_error(_("failed to open file: %s: %s\n"), MNTTAB
,
4008 if (*mountp
== '\0')
4009 mpref
.mnt_mountp
= "/";
4011 mpref
.mnt_mountp
= mountp
;
4013 ret
= getmntany(mntfp
, &mp
, &mpref
);
4014 INJECT_ERROR1("GET_SPECIAL_MNTTAB_SEARCH", ret
= 1);
4016 (void) fclose(mntfp
);
4017 BAM_DPRINTF(("%s: Cannot get special file: mount-point %s "
4018 "not in mnttab\n", fcn
, mountp
));
4021 (void) fclose(mntfp
);
4023 BAM_DPRINTF(("%s: returning special: %s\n", fcn
, mp
.mnt_special
));
4025 return (s_strdup(mp
.mnt_special
));
4029 line_free(line_t
*lp
)
4042 linelist_free(line_t
*start
)
4048 start
= start
->next
;
4054 filelist_free(filelist_t
*flistp
)
4056 linelist_free(flistp
->head
);
4057 flistp
->head
= NULL
;
4058 flistp
->tail
= NULL
;
4067 * Returns 0 on success
4068 * Any other value indicates an error
4071 exec_cmd(char *cmdline
, filelist_t
*flistp
)
4081 * - only absolute paths are allowed
4082 * - set IFS to space and tab
4084 if (*cmdline
!= '/') {
4085 bam_error(_("path is not absolute: %s\n"), cmdline
);
4088 (void) putenv("IFS= \t");
4091 * We may have been exec'ed with SIGCHLD blocked
4094 (void) sigemptyset(&set
);
4095 (void) sigaddset(&set
, SIGCHLD
);
4096 if (sigprocmask(SIG_UNBLOCK
, &set
, NULL
) != 0) {
4097 bam_error(_("cannot unblock SIGCHLD: %s\n"), strerror(errno
));
4102 * Set SIGCHLD disposition to SIG_DFL for popen/pclose
4104 disp
= sigset(SIGCHLD
, SIG_DFL
);
4105 if (disp
== SIG_ERR
) {
4106 bam_error(_("cannot set SIGCHLD disposition: %s\n"),
4110 if (disp
== SIG_HOLD
) {
4111 bam_error(_("SIGCHLD signal blocked. Cannot exec: %s\n"),
4116 ptr
= popen(cmdline
, "r");
4118 bam_error(_("popen failed: %s: %s\n"), cmdline
,
4124 * If we simply do a pclose() following a popen(), pclose()
4125 * will close the reader end of the pipe immediately even
4126 * if the child process has not started/exited. pclose()
4127 * does wait for cmd to terminate before returning though.
4128 * When the executed command writes its output to the pipe
4129 * there is no reader process and the command dies with
4130 * SIGPIPE. To avoid this we read repeatedly until read
4131 * terminates with EOF. This indicates that the command
4132 * (writer) has closed the pipe and we can safely do a
4135 * Since pclose() does wait for the command to exit,
4136 * we can safely reap the exit status of the command
4137 * from the value returned by pclose()
4139 while (s_fgets(buf
, sizeof (buf
), ptr
) != NULL
) {
4140 if (flistp
== NULL
) {
4141 /* s_fgets strips newlines, so insert them at the end */
4142 bam_print(_("%s\n"), buf
);
4144 append_to_flist(flistp
, buf
);
4150 bam_error(_("pclose failed: %s: %s\n"), cmdline
,
4155 if (WIFEXITED(ret
)) {
4156 return (WEXITSTATUS(ret
));
4158 bam_error(_("command terminated abnormally: %s: %d\n"),
4165 * Since this function returns -1 on error
4166 * it cannot be used to convert -1. However,
4167 * that is sufficient for what we need.
4180 l
= strtol(str
, &res
, 10);
4181 if (errno
|| *res
!= '\0') {
4189 * Wrapper around fgets, that strips newlines returned by fgets
4192 s_fgets(char *buf
, int buflen
, FILE *fp
)
4196 buf
= fgets(buf
, buflen
, fp
);
4199 if (n
== buflen
- 1 && buf
[n
-1] != '\n')
4200 bam_error(_("the following line is too long "
4201 "(> %d chars)\n\t%s\n"), buflen
- 1, buf
);
4202 buf
[n
-1] = (buf
[n
-1] == '\n') ? '\0' : buf
[n
-1];
4209 s_calloc(size_t nelem
, size_t sz
)
4213 ptr
= calloc(nelem
, sz
);
4215 bam_error(_("could not allocate memory: size = %u\n"),
4223 s_realloc(void *ptr
, size_t sz
)
4225 ptr
= realloc(ptr
, sz
);
4227 bam_error(_("could not allocate memory: size = %u\n"), sz
);
4243 bam_error(_("could not allocate memory: size = %u\n"),
4251 * Returns 1 if amd64 (or sparc, for syncing x86 diskless clients)
4252 * Returns 0 otherwise
4257 static int amd64
= -1;
4258 char isabuf
[257]; /* from sysinfo(2) manpage */
4263 if (bam_alt_platform
) {
4264 if (strcmp(bam_platform
, "i86pc") == 0) {
4265 amd64
= 1; /* diskless server */
4268 if (sysinfo(SI_ISALIST
, isabuf
, sizeof (isabuf
)) > 0 &&
4269 strncmp(isabuf
, "amd64 ", strlen("amd64 ")) == 0) {
4271 } else if (strstr(isabuf
, "i386") == NULL
) {
4272 amd64
= 1; /* diskless server */
4284 static int cached
= -1;
4285 static char mbuf
[257]; /* from sysinfo(2) manpage */
4290 if (bam_alt_platform
) {
4291 return (bam_platform
);
4293 if (sysinfo(SI_MACHINE
, mbuf
, sizeof (mbuf
)) > 0) {
4308 static int issparc
= -1;
4309 char mbuf
[257]; /* from sysinfo(2) manpage */
4314 if (bam_alt_platform
) {
4315 if (strncmp(bam_platform
, "sun4", 4) == 0) {
4319 if (sysinfo(SI_ARCHITECTURE
, mbuf
, sizeof (mbuf
)) > 0 &&
4320 strcmp(mbuf
, "sparc") == 0) {
4331 append_to_flist(filelist_t
*flistp
, char *s
)
4335 lp
= s_calloc(1, sizeof (line_t
));
4336 lp
->line
= s_strdup(s
);
4337 if (flistp
->head
== NULL
)
4340 flistp
->tail
->next
= lp
;
4350 ucode_install(char *root
)
4354 for (i
= 0; ucode_vendors
[i
].filestr
!= NULL
; i
++) {
4355 int cmd_len
= PATH_MAX
+ 256;
4356 char cmd
[PATH_MAX
+ 256];
4357 char file
[PATH_MAX
];
4358 char timestamp
[PATH_MAX
];
4359 struct stat fstatus
, tstatus
;
4360 struct utimbuf u_times
;
4362 (void) snprintf(file
, PATH_MAX
, "%s/%s/%s-ucode.%s",
4363 bam_root
, UCODE_INSTALL_PATH
, ucode_vendors
[i
].filestr
,
4364 ucode_vendors
[i
].extstr
);
4366 if (stat(file
, &fstatus
) != 0 || !(S_ISREG(fstatus
.st_mode
)))
4369 (void) snprintf(timestamp
, PATH_MAX
, "%s.ts", file
);
4371 if (stat(timestamp
, &tstatus
) == 0 &&
4372 fstatus
.st_mtime
<= tstatus
.st_mtime
)
4375 (void) snprintf(cmd
, cmd_len
, "/usr/sbin/ucodeadm -i -R "
4376 "%s/%s/%s %s > /dev/null 2>&1", bam_root
,
4377 UCODE_INSTALL_PATH
, ucode_vendors
[i
].vendorstr
, file
);
4378 if (system(cmd
) != 0)
4381 if (creat(timestamp
, S_IRUSR
| S_IWUSR
) == -1)
4384 u_times
.actime
= fstatus
.st_atime
;
4385 u_times
.modtime
= fstatus
.st_mtime
;
4386 (void) utime(timestamp
, &u_times
);