summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEnrico Perla - Sun Microsystems <Enrico.Perla@Sun.COM>2009-02-09 15:30:07 -0800
committerEnrico Perla - Sun Microsystems <Enrico.Perla@Sun.COM>2009-02-09 15:30:07 -0800
commit488474949328b517188fdfc12c28c8e44e23a9f4 (patch)
treea94bb6a15230ee9a1ea5e05fe8fbf762cb00c4ea
parent28b1e50e4eed7be353f9778497714aab53ef2a0d (diff)
downloadillumos-joyent-488474949328b517188fdfc12c28c8e44e23a9f4.tar.gz
6802006 Improving boot-archive creation performance
6630948 mkdir: Failed to make directory during JumpStart install for x86 during create_ramdisk 6726135 bootadm should print out error message on error 6798895 filling up the rootfs during boot_archive creation can result in driving on with a truncated archive
-rw-r--r--usr/src/cmd/boot/bootadm/Makefile9
-rw-r--r--usr/src/cmd/boot/bootadm/bootadm.c1494
-rw-r--r--usr/src/cmd/boot/bootadm/bootadm.h14
-rw-r--r--usr/src/cmd/boot/bootadm/message.h107
-rw-r--r--usr/src/cmd/boot/scripts/create_ramdisk.ksh21
-rw-r--r--usr/src/cmd/halt/halt.c52
-rw-r--r--usr/src/cmd/init/init.c31
7 files changed, 1505 insertions, 223 deletions
diff --git a/usr/src/cmd/boot/bootadm/Makefile b/usr/src/cmd/boot/bootadm/Makefile
index 8dde7f9a1c..e0aa385f27 100644
--- a/usr/src/cmd/boot/bootadm/Makefile
+++ b/usr/src/cmd/boot/bootadm/Makefile
@@ -19,10 +19,8 @@
# CDDL HEADER END
#
#
-# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
-#
-# ident "%Z%%M% %I% %E% SMI"
#
PROG= bootadm
@@ -37,7 +35,7 @@ include ../Makefile.com
.KEEP_STATE:
-LDLIBS += -lnvpair -lgen -ladm -lefi -lscf
+LDLIBS += -lnvpair -lgen -ladm -lefi -lscf -lz
# Writing into string literals is incorrect. We need to match gcc's
# behavior, which causes us to take SIGSEGV on such a write.
@@ -45,6 +43,9 @@ CFLAGS += $(XSTRCONST)
CPPFLAGS += -D_FILE_OFFSET_BITS=64
CPPFLAGS += -I../../../uts/common -I../../../common
+LINTFLAGS += -erroff=E_INCONS_ARG_DECL2
+LINTFLAGS += -erroff=E_INCONS_VAL_TYPE_DECL2
+
all: $(PROG)
$(PROG): $(OBJS) bootadm.h
diff --git a/usr/src/cmd/boot/bootadm/bootadm.c b/usr/src/cmd/boot/bootadm/bootadm.c
index 7ad3b1bb3d..890a09ed14 100644
--- a/usr/src/cmd/boot/bootadm/bootadm.c
+++ b/usr/src/cmd/boot/bootadm/bootadm.c
@@ -57,7 +57,11 @@
#include <ctype.h>
#include <libgen.h>
#include <sys/sysmacros.h>
+#include <sys/elf.h>
#include <libscf.h>
+#include <zlib.h>
+#include <sys/lockfs.h>
+#include <sys/filio.h>
#if !defined(_OPB)
#include <sys/ucode.h>
@@ -153,9 +157,6 @@ typedef enum zfs_mnted {
ZFS_ALREADY
} zfs_mnted_t;
-
-
-
/*
* The following two defines are used to detect and create the correct
* boot archive when safemode patching is underway. LOFS_PATCH_FILE is a
@@ -163,7 +164,6 @@ typedef enum zfs_mnted {
* consolidation. It is set by pdo.c when a patch with SUNW_PATCH_SAFEMODE
* is applied.
*/
-
#define LOFS_PATCH_FILE "/var/run/.patch_loopback_mode"
#define LOFS_PATCH_MNT "/var/run/.patch_root_loopbackmnt"
@@ -223,6 +223,8 @@ static char *bam_root;
static int bam_rootlen;
static int bam_root_readonly;
static int bam_alt_root;
+static int bam_extend = 0;
+static int bam_purge = 0;
static char *bam_subcmd;
static char *bam_opt;
static char **bam_argv;
@@ -307,13 +309,79 @@ static subcmd_defn_t arch_subcmds[] = {
NULL, 0, NULL, 0 /* must be last */
};
+enum dircache_copy_opt {
+ FILE32 = 0,
+ FILE64,
+ CACHEDIR_NUM
+};
+
+/*
+ * Directory specific flags:
+ * NEED_UPDATE : the specified archive needs to be updated
+ * NO_MULTI : don't extend the specified archive, but recreate it
+ */
+#define NEED_UPDATE 0x00000001
+#define NO_MULTI 0x00000002
+
+#define set_dir_flag(id, f) (walk_arg.dirinfo[id].flags |= f)
+#define unset_dir_flag(id, f) (walk_arg.dirinfo[id].flags &= ~f)
+#define is_dir_flag_on(id, f) (walk_arg.dirinfo[id].flags & f ? 1 : 0)
+
+#define get_cachedir(id) (walk_arg.dirinfo[id].cdir_path)
+#define get_updatedir(id) (walk_arg.dirinfo[id].update_path)
+#define get_count(id) (walk_arg.dirinfo[id].count)
+#define has_cachedir(id) (walk_arg.dirinfo[id].has_dir)
+#define set_dir_present(id) (walk_arg.dirinfo[id].has_dir = 1)
+
+/*
+ * dirinfo_t (specific cache directory information):
+ * cdir_path: path to the archive cache directory
+ * update_path: path to the update directory (contains the files that will be
+ * used to extend the archive)
+ * has_dir: the specified cache directory is active
+ * count: the number of files to update
+ * flags: directory specific flags
+ */
+typedef struct _dirinfo {
+ char cdir_path[PATH_MAX];
+ char update_path[PATH_MAX];
+ int has_dir;
+ int count;
+ int flags;
+} dirinfo_t;
+
+/*
+ * Update flags:
+ * NEED_CACHE_DIR : cache directory is missing and needs to be created
+ * IS_SPARC_TARGET : the target mountpoint is a SPARC environment
+ * UPDATE_ERROR : an error occourred while traversing the list of files
+ * RDONLY_FSCHK : the target filesystem is read-only
+ * RAMDSK_FSCHK : the target filesystem is on a ramdisk
+ */
+#define NEED_CACHE_DIR 0x00000001
+#define IS_SPARC_TARGET 0x00000002
+#define UPDATE_ERROR 0x00000004
+#define RDONLY_FSCHK 0x00000008
+#define RAMDSK_FSCHK 0x00000010
+
+#define is_flag_on(flag) (walk_arg.update_flags & flag ? 1 : 0)
+#define set_flag(flag) (walk_arg.update_flags |= flag)
+#define unset_flag(flag) (walk_arg.update_flags &= ~flag)
+
+/*
+ * struct walk_arg :
+ * update_flags: flags related to the current updating process
+ * new_nvlp/old_nvlp: new and old list of archive-files / attributes pairs
+ * sparcfile: list of file paths for mkisofs -path-list (SPARC only)
+ */
static struct {
- nvlist_t *new_nvlp;
- nvlist_t *old_nvlp;
- int need_update;
+ int update_flags;
+ nvlist_t *new_nvlp;
+ nvlist_t *old_nvlp;
+ FILE *sparcfile;
+ dirinfo_t dirinfo[CACHEDIR_NUM];
} walk_arg;
-
struct safefile {
char *name;
struct safefile *next;
@@ -322,6 +390,30 @@ struct safefile {
static struct safefile *safefiles = NULL;
#define NEED_UPDATE_FILE "/etc/svc/volatile/boot_archive_needs_update"
+/* Thanks growisofs */
+#define CD_BLOCK ((off64_t)2048)
+#define VOLDESC_OFF 16
+#define DVD_BLOCK (32*1024)
+#define MAX_IVDs 16
+
+struct iso_pdesc {
+ unsigned char type [1];
+ unsigned char id [5];
+ unsigned char void1 [80-5-1];
+ unsigned char volume_space_size [8];
+ unsigned char void2 [2048-80-8];
+};
+
+/*
+ * COUNT_MAX: maximum number of changed files to justify a multisession update
+ * BA_SIZE_MAX: maximum size of the boot_archive to justify a multisession
+ * update
+ */
+#define COUNT_MAX 50
+#define BA_SIZE_MAX (50 * 1024 * 1024)
+
+#define bam_nowrite() (bam_check || bam_smf_check)
+
static int sync_menu = 1; /* whether we need to sync the BE menus */
static void
@@ -329,7 +421,6 @@ usage(void)
{
(void) fprintf(stderr, "USAGE:\n");
-
/* archive usage */
(void) fprintf(stderr,
"\t%s update-archive [-vn] [-R altroot [-p platform>]]\n", prog);
@@ -447,6 +538,10 @@ parse_args(int argc, char *argv[])
* -m list_entry -- list-menu
* -m update_temp -- (reboot -- [boot-args])
* -m delete_all_entries -- (called from install)
+ * A set of private flags is there too:
+ * -F -- purge the cache directories and rebuild them
+ * -e -- use the (faster) archive update approach (used by
+ * reboot)
*/
static void
parse_args_internal(int argc, char *argv[])
@@ -459,7 +554,7 @@ parse_args_internal(int argc, char *argv[])
opterr = 0;
error = 0;
- while ((c = getopt(argc, argv, "a:d:fm:no:vCR:p:Z")) != -1) {
+ while ((c = getopt(argc, argv, "a:d:fm:no:veFCR:p:Z")) != -1) {
switch (c) {
case 'a':
if (bam_cmd) {
@@ -477,12 +572,11 @@ parse_args_internal(int argc, char *argv[])
bam_debug = s_strtol(optarg);
break;
case 'f':
- if (bam_force) {
- error = 1;
- bam_error(DUP_OPT, c);
- }
bam_force = 1;
break;
+ case 'F':
+ bam_purge = 1;
+ break;
case 'm':
if (bam_cmd) {
error = 1;
@@ -492,10 +586,6 @@ parse_args_internal(int argc, char *argv[])
bam_subcmd = optarg;
break;
case 'n':
- if (bam_check) {
- error = 1;
- bam_error(DUP_OPT, c);
- }
bam_check = 1;
break;
case 'o':
@@ -506,10 +596,6 @@ parse_args_internal(int argc, char *argv[])
bam_opt = optarg;
break;
case 'v':
- if (bam_verbose) {
- error = 1;
- bam_error(DUP_OPT, c);
- }
bam_verbose = 1;
break;
case 'C':
@@ -543,6 +629,9 @@ parse_args_internal(int argc, char *argv[])
case 'Z':
bam_zfs = 1;
break;
+ case 'e':
+ bam_extend = 1;
+ break;
case '?':
error = 1;
bam_error(BAD_OPT, optopt);
@@ -1243,29 +1332,363 @@ list2file(char *root, char *tmp, char *final, line_t *start)
}
/*
- * This function should always return 0 - since we want
- * to create stat data for *all* files in the list.
+ * Checks if the path specified (without the file name at the end) exists
+ * and creates it if not. If the path exists and is not a directory, an attempt
+ * to unlink is made.
*/
+static int
+setup_path(char *path)
+{
+ char *p;
+ int ret;
+ struct stat sb;
+
+ p = strrchr(path, '/');
+ if (p != NULL) {
+ *p = '\0';
+ if (stat(path, &sb) != 0 || !(S_ISDIR(sb.st_mode))) {
+ /* best effort attempt, mkdirp will catch the error */
+ (void) unlink(path);
+ if (bam_verbose)
+ bam_print(NEED_DIRPATH, path);
+ ret = mkdirp(path, DIR_PERMS);
+ if (ret == -1) {
+ bam_error(MKDIR_FAILED, path, strerror(errno));
+ *p = '/';
+ return (BAM_ERROR);
+ }
+ }
+ *p = '/';
+ return (BAM_SUCCESS);
+ }
+ return (BAM_SUCCESS);
+}
+
+typedef union {
+ gzFile gzfile;
+ int fdfile;
+} outfile;
+
+typedef struct {
+ char path[PATH_MAX];
+ outfile out;
+} cachefile;
+
+static int
+setup_file(char *base, const char *path, cachefile *cf)
+{
+ int ret;
+ char *strip;
+
+ /* init gzfile or fdfile in case we fail before opening */
+ if (bam_direct == BAM_DIRECT_DBOOT)
+ cf->out.gzfile = NULL;
+ else
+ cf->out.fdfile = -1;
+
+ /* strip the trailing altroot path */
+ strip = (char *)path + strlen(rootbuf);
+
+ ret = snprintf(cf->path, sizeof (cf->path), "%s/%s", base, strip);
+ if (ret >= sizeof (cf->path)) {
+ bam_error(PATH_TOO_LONG, rootbuf);
+ return (BAM_ERROR);
+ }
+
+ /* Check if path is present in the archive cache directory */
+ if (setup_path(cf->path) == BAM_ERROR)
+ return (BAM_ERROR);
+
+ if (bam_direct == BAM_DIRECT_DBOOT) {
+ if ((cf->out.gzfile = gzopen(cf->path, "wb")) == NULL) {
+ bam_error(GZ_OPEN_FAIL, gzerror(cf->out.gzfile, NULL));
+ return (BAM_ERROR);
+ }
+ (void) gzsetparams(cf->out.gzfile, Z_BEST_SPEED,
+ Z_DEFAULT_STRATEGY);
+ } else {
+ if ((cf->out.fdfile = open(cf->path, O_WRONLY | O_CREAT, 0644))
+ == -1) {
+ bam_error(OPEN_FAIL, cf->path, strerror(errno));
+ return (BAM_ERROR);
+ }
+ }
+
+ return (BAM_SUCCESS);
+}
+
+static int
+cache_write(cachefile cf, char *buf, int size)
+{
+ int err;
+
+ if (bam_direct == BAM_DIRECT_DBOOT) {
+ if (gzwrite(cf.out.gzfile, buf, size) < 1) {
+ bam_error(GZ_WRITE_FAIL, gzerror(cf.out.gzfile, &err));
+ if (err == Z_ERRNO)
+ bam_error(WRITE_FAIL, cf.path, strerror(errno));
+ return (BAM_ERROR);
+ }
+ } else {
+ if (write(cf.out.fdfile, buf, size) < 1) {
+ bam_error(WRITE_FAIL, cf.path, strerror(errno));
+ return (BAM_ERROR);
+ }
+ }
+ return (BAM_SUCCESS);
+}
+
+static int
+cache_close(cachefile cf)
+{
+ int ret;
+
+ if (bam_direct == BAM_DIRECT_DBOOT) {
+ if (cf.out.gzfile) {
+ ret = gzclose(cf.out.gzfile);
+ if (ret == Z_OK)
+ return (BAM_SUCCESS);
+ else if (ret == Z_ERRNO)
+ bam_error(CLOSE_FAIL, cf.path, strerror(errno));
+ else
+ bam_error(GZCLOSE_FAIL, gzerror(cf.out.gzfile,
+ NULL));
+ return (BAM_ERROR);
+ }
+ } else {
+ if (cf.out.fdfile != -1) {
+ ret = close(cf.out.fdfile);
+ if (ret != 0) {
+ bam_error(CLOSE_FAIL, cf.path, strerror(errno));
+ return (BAM_ERROR);
+ }
+ }
+ }
+
+ return (BAM_SUCCESS);
+}
+
+static int
+dircache_updatefile(const char *path, int what)
+{
+ int ret, exitcode;
+ char buf[4096 * 4];
+ FILE *infile;
+ cachefile outfile, outupdt;
+
+ if (bam_nowrite())
+ return (BAM_SUCCESS);
+
+ if ((infile = fopen(path, "rb")) == NULL) {
+ bam_error(OPEN_FAIL, path, strerror(errno));
+ return (BAM_ERROR);
+ }
+
+ ret = setup_file(get_cachedir(what), path, &outfile);
+ if (ret == BAM_ERROR) {
+ exitcode = BAM_ERROR;
+ goto out;
+ }
+ if (!is_dir_flag_on(what, NO_MULTI)) {
+ ret = setup_file(get_updatedir(what), path, &outupdt);
+ if (ret == BAM_ERROR)
+ set_dir_flag(what, NO_MULTI);
+ }
+
+ while ((ret = fread(buf, 1, sizeof (buf), infile)) > 0) {
+ if (cache_write(outfile, buf, ret) == BAM_ERROR) {
+ exitcode = BAM_ERROR;
+ goto out;
+ }
+ if (!is_dir_flag_on(what, NO_MULTI))
+ if (cache_write(outupdt, buf, ret) == BAM_ERROR)
+ set_dir_flag(what, NO_MULTI);
+ }
+
+ set_dir_flag(what, NEED_UPDATE);
+ get_count(what)++;
+ exitcode = BAM_SUCCESS;
+out:
+ (void) fclose(infile);
+ if (cache_close(outfile) == BAM_ERROR)
+ exitcode = BAM_ERROR;
+ if (!is_dir_flag_on(what, NO_MULTI) &&
+ cache_close(outupdt) == BAM_ERROR)
+ exitcode = BAM_ERROR;
+ if (exitcode == BAM_ERROR)
+ set_flag(UPDATE_ERROR);
+ return (exitcode);
+}
+
+static int
+dircache_updatedir(const char *path, int what, int updt)
+{
+ int ret;
+ char dpath[PATH_MAX];
+ char *strip;
+ struct stat sb;
+
+ strip = (char *)path + strlen(rootbuf);
+
+ ret = snprintf(dpath, sizeof (dpath), "%s/%s", updt ?
+ get_updatedir(what) : get_cachedir(what), strip);
+
+ if (ret >= sizeof (dpath)) {
+ bam_error(PATH_TOO_LONG, rootbuf);
+ set_flag(UPDATE_ERROR);
+ return (BAM_ERROR);
+ }
+
+ if (stat(dpath, &sb) == 0 && S_ISDIR(sb.st_mode))
+ return (BAM_SUCCESS);
+
+ if (updt) {
+ if (!is_dir_flag_on(what, NO_MULTI))
+ if (!bam_nowrite() && mkdirp(dpath, DIR_PERMS) == -1)
+ set_dir_flag(what, NO_MULTI);
+ } else {
+ if (!bam_nowrite() && mkdirp(dpath, DIR_PERMS) == -1) {
+ set_flag(UPDATE_ERROR);
+ return (BAM_ERROR);
+ }
+ }
+
+ set_dir_flag(what, NEED_UPDATE);
+ return (BAM_SUCCESS);
+}
+
+#define DO_CACHE_DIR 0
+#define DO_UPDATE_DIR 1
+
+#if defined(_LP64) || defined(_LONGLONG_TYPE)
+typedef Elf64_Ehdr _elfhdr;
+#else
+typedef Elf32_Ehdr _elfhdr;
+#endif
+
+/*
+ * This routine updates the contents of the cache directory
+ */
+static int
+update_dircache(const char *path, int flags)
+{
+ int rc = BAM_SUCCESS;
+
+ switch (flags) {
+ case FTW_F:
+ {
+ int fd;
+ _elfhdr elf;
+
+ if ((fd = open(path, O_RDONLY)) < 0) {
+ bam_error(OPEN_FAIL, path, strerror(errno));
+ set_flag(UPDATE_ERROR);
+ rc = BAM_ERROR;
+ break;
+ }
+
+ /*
+ * libelf and gelf would be a cleaner and easier way to handle
+ * this, but libelf fails compilation if _ILP32 is defined &&
+ * _FILE_OFFSET_BITS is != 32 ...
+ */
+ if (read(fd, (void *)&elf, sizeof (_elfhdr)) < 0) {
+ bam_error(READ_FAIL, path, strerror(errno));
+ set_flag(UPDATE_ERROR);
+ (void) close(fd);
+ rc = BAM_ERROR;
+ break;
+ }
+ (void) close(fd);
+
+ /*
+ * If the file is not an executable and is not inside an amd64
+ * directory, we copy it in both the cache directories,
+ * otherwise, we only copy it inside the 64-bit one.
+ */
+ if (memcmp(elf.e_ident, ELFMAG, 4) != 0) {
+ if (strstr(path, "/amd64")) {
+ if (has_cachedir(FILE64))
+ rc = dircache_updatefile(path, FILE64);
+ } else if (has_cachedir(FILE64)) {
+ rc = dircache_updatefile(path, FILE32);
+ if (rc == BAM_SUCCESS)
+ rc = dircache_updatefile(path, FILE64);
+ } else {
+ rc = dircache_updatefile(path, FILE32);
+ }
+ } else {
+ /*
+ * Based on the ELF class we copy the file in the 32-bit
+ * or the 64-bit cache directory.
+ */
+ if (elf.e_ident[EI_CLASS] == ELFCLASS32)
+ rc = dircache_updatefile(path, FILE32);
+ else if (elf.e_ident[EI_CLASS] == ELFCLASS64)
+ if (has_cachedir(FILE64))
+ rc = dircache_updatefile(path, FILE64);
+ else {
+ bam_print(NO3264ELF, path);
+ /* paranoid */
+ rc = dircache_updatefile(path, FILE32);
+ if (rc == BAM_SUCCESS)
+ rc = dircache_updatefile(path, FILE64);
+ }
+ }
+ break;
+ }
+ case FTW_D:
+ if (strstr(path, "/amd64") == NULL) {
+ rc = dircache_updatedir(path, FILE32, DO_UPDATE_DIR);
+ if (rc == BAM_SUCCESS)
+ rc = dircache_updatedir(path, FILE32,
+ DO_CACHE_DIR);
+ } else {
+ if (has_cachedir(FILE64)) {
+ rc = dircache_updatedir(path, FILE64,
+ DO_UPDATE_DIR);
+ if (rc == BAM_SUCCESS)
+ rc = dircache_updatedir(path, FILE64,
+ DO_CACHE_DIR);
+ }
+ }
+ break;
+ default:
+ rc = BAM_ERROR;
+ break;
+ }
+
+ return (rc);
+}
+
/*ARGSUSED*/
static int
cmpstat(
const char *file,
- const struct stat *stat,
+ const struct stat *st,
int flags,
struct FTW *ftw)
{
- uint_t sz;
- uint64_t *value;
- uint64_t filestat[2];
- int error;
+ uint_t sz;
+ uint64_t *value;
+ uint64_t filestat[2];
+ int error, ret;
struct safefile *safefilep;
- FILE *fp;
+ FILE *fp;
+ struct stat sb;
+
+ /*
+ * On SPARC we create/update links too.
+ */
+ if (flags != FTW_F && flags != FTW_D && (flags == FTW_SL &&
+ !is_flag_on(IS_SPARC_TARGET)))
+ return (0);
/*
- * We only want regular files
+ * Ignore broken links
*/
- if (!S_ISREG(stat->st_mode))
+ if (flags == FTW_SL && stat(file, &sb) < 0)
return (0);
/*
@@ -1273,8 +1696,8 @@ cmpstat(
* but this is not fatal to update determination.
*/
if (walk_arg.new_nvlp) {
- filestat[0] = stat->st_size;
- filestat[1] = stat->st_mtime;
+ filestat[0] = st->st_size;
+ filestat[1] = st->st_mtime;
error = nvlist_add_uint64_array(walk_arg.new_nvlp,
file + bam_rootlen, filestat, 2);
if (error)
@@ -1282,13 +1705,6 @@ cmpstat(
}
/*
- * The remaining steps are only required if we haven't made a
- * decision about update or if we are checking (-n)
- */
- if (walk_arg.need_update && !bam_check)
- return (0);
-
- /*
* If we are invoked as part of system/filesystem/boot-archive, then
* there are a number of things we should not worry about
*/
@@ -1320,6 +1736,41 @@ cmpstat(
}
/*
+ * On SPARC we create a -path-list file for mkisofs
+ */
+ if (is_flag_on(IS_SPARC_TARGET) && !bam_nowrite()) {
+ if (flags != FTW_D) {
+ char *strip;
+
+ strip = (char *)file + strlen(rootbuf);
+ (void) fprintf(walk_arg.sparcfile, "/%s=%s\n", strip,
+ file);
+ }
+ }
+
+ /*
+ * We are transitioning from the old model to the dircache or the cache
+ * directory was removed: create the entry without further checkings.
+ */
+ if (is_flag_on(NEED_CACHE_DIR)) {
+ if (bam_verbose)
+ bam_print(PARSEABLE_NEW_FILE, file);
+
+ if (is_flag_on(IS_SPARC_TARGET)) {
+ set_dir_flag(FILE64, NEED_UPDATE);
+ return (0);
+ }
+
+ ret = update_dircache(file, flags);
+ if (ret == BAM_ERROR) {
+ bam_error(UPDT_CACHE_FAIL, file);
+ return (-1);
+ }
+
+ return (0);
+ }
+
+ /*
* We need an update if file doesn't exist in old archive
*/
if (walk_arg.old_nvlp == NULL ||
@@ -1327,20 +1778,39 @@ cmpstat(
file + bam_rootlen, &value, &sz) != 0) {
if (bam_smf_check) /* ignore new during smf check */
return (0);
- walk_arg.need_update = 1;
+
+ if (is_flag_on(IS_SPARC_TARGET)) {
+ set_dir_flag(FILE64, NEED_UPDATE);
+ } else {
+ ret = update_dircache(file, flags);
+ if (ret == BAM_ERROR) {
+ bam_error(UPDT_CACHE_FAIL, file);
+ return (-1);
+ }
+ }
+
if (bam_verbose)
bam_print(PARSEABLE_NEW_FILE, file);
return (0);
}
/*
+ * If we got there, the file is already listed as to be included in the
+ * iso image. We just need to know if we are going to rebuild it or not
+ */
+
+ if (is_flag_on(IS_SPARC_TARGET) &&
+ is_dir_flag_on(FILE64, NEED_UPDATE) && !bam_smf_check)
+ return (0);
+
+ /*
* File exists in old archive. Check if file has changed
*/
assert(sz == 2);
bcopy(value, filestat, sizeof (filestat));
- if (filestat[0] != stat->st_size ||
- filestat[1] != stat->st_mtime) {
+ if (flags != FTW_D && (filestat[0] != st->st_size ||
+ filestat[1] != st->st_mtime)) {
if (bam_smf_check) {
safefilep = safefiles;
while (safefilep != NULL) {
@@ -1352,7 +1822,17 @@ cmpstat(
safefilep = safefilep->next;
}
}
- walk_arg.need_update = 1;
+
+ if (is_flag_on(IS_SPARC_TARGET)) {
+ set_dir_flag(FILE64, NEED_UPDATE);
+ } else {
+ ret = update_dircache(file, flags);
+ if (ret == BAM_ERROR) {
+ bam_error(UPDT_CACHE_FAIL, file);
+ return (-1);
+ }
+ }
+
if (bam_verbose)
if (bam_smf_check)
bam_print(" %s\n", file);
@@ -1364,64 +1844,260 @@ cmpstat(
}
/*
- * Check flags and presence of required files.
+ * Remove a directory path recursively
+ */
+static int
+rmdir_r(char *path)
+{
+ struct dirent *d = NULL;
+ DIR *dir = NULL;
+ char tpath[PATH_MAX];
+ struct stat sb;
+
+ if ((dir = opendir(path)) == NULL)
+ return (-1);
+
+ while (d = readdir(dir)) {
+ if ((strcmp(d->d_name, ".") != 0) &&
+ (strcmp(d->d_name, "..") != 0)) {
+ (void) snprintf(tpath, sizeof (tpath), "%s/%s",
+ path, d->d_name);
+ if (stat(tpath, &sb) == 0) {
+ if (sb.st_mode & S_IFDIR)
+ (void) rmdir_r(tpath);
+ else
+ (void) remove(tpath);
+ }
+ }
+ }
+ return (remove(path));
+}
+
+/*
+ * Check if cache directory exists and, if not, create it and update flags
+ * accordingly. If the path exists, but it's not a directory, a best effort
+ * attempt to remove and recreate it is made.
+ * If the user requested a 'purge', always recreate the directory from scratch.
+ */
+static int
+set_cache_dir(char *root, int what)
+{
+ struct stat sb;
+ int ret = 0;
+
+ ret = snprintf(get_cachedir(what), sizeof (get_cachedir(what)),
+ "%s%s%s%s%s", root, ARCHIVE_PREFIX, get_machine(), what == FILE64 ?
+ "/amd64" : "", CACHEDIR_SUFFIX);
+
+ if (ret >= sizeof (get_cachedir(what))) {
+ bam_error(PATH_TOO_LONG, rootbuf);
+ return (BAM_ERROR);
+ }
+
+ if (bam_purge)
+ (void) rmdir_r(get_cachedir(what));
+
+ if (stat(get_cachedir(what), &sb) != 0 || !(S_ISDIR(sb.st_mode))) {
+ /* best effort unlink attempt, mkdir will catch errors */
+ (void) unlink(get_cachedir(what));
+
+ if (bam_verbose)
+ bam_print(UPDATE_CDIR_MISS, get_cachedir(what));
+ ret = mkdir(get_cachedir(what), DIR_PERMS);
+ if (ret < 0) {
+ bam_error(MKDIR_FAILED, get_cachedir(what),
+ strerror(errno));
+ get_cachedir(what)[0] = '\0';
+ return (ret);
+ }
+ set_flag(NEED_CACHE_DIR);
+ set_dir_flag(what, NO_MULTI);
+ }
+
+ return (BAM_SUCCESS);
+}
+
+static int
+set_update_dir(char *root, int what)
+{
+ struct stat sb;
+ int ret;
+
+ if (is_dir_flag_on(what, NO_MULTI))
+ return (BAM_SUCCESS);
+
+ if (!bam_extend) {
+ set_dir_flag(what, NO_MULTI);
+ return (BAM_SUCCESS);
+ }
+
+ if (what == FILE64 && !is_flag_on(IS_SPARC_TARGET))
+ ret = snprintf(get_updatedir(what),
+ sizeof (get_updatedir(what)), "%s%s%s/amd64%s", root,
+ ARCHIVE_PREFIX, get_machine(), UPDATEDIR_SUFFIX);
+ else
+ ret = snprintf(get_updatedir(what),
+ sizeof (get_updatedir(what)), "%s%s%s%s", root,
+ ARCHIVE_PREFIX, get_machine(), UPDATEDIR_SUFFIX);
+
+ if (ret >= sizeof (get_updatedir(what))) {
+ bam_error(PATH_TOO_LONG, rootbuf);
+ return (BAM_ERROR);
+ }
+
+ if (stat(get_updatedir(what), &sb) == 0) {
+ if (S_ISDIR(sb.st_mode))
+ ret = rmdir_r(get_updatedir(what));
+ else
+ ret = unlink(get_updatedir(what));
+
+ if (ret != 0)
+ set_dir_flag(what, NO_MULTI);
+ }
+
+ if (mkdir(get_updatedir(what), DIR_PERMS) < 0)
+ set_dir_flag(what, NO_MULTI);
+
+ return (BAM_SUCCESS);
+}
+
+static int
+is_valid_archive(char *root, int what)
+{
+ char archive_path[PATH_MAX];
+ struct stat sb;
+ int ret;
+
+ if (what == FILE64 && !is_flag_on(IS_SPARC_TARGET))
+ ret = snprintf(archive_path, sizeof (archive_path),
+ "%s%s%s/amd64%s", root, ARCHIVE_PREFIX, get_machine(),
+ ARCHIVE_SUFFIX);
+ else
+ ret = snprintf(archive_path, sizeof (archive_path), "%s%s%s%s",
+ root, ARCHIVE_PREFIX, get_machine(), ARCHIVE_SUFFIX);
+
+ if (ret >= sizeof (archive_path)) {
+ bam_error(PATH_TOO_LONG, rootbuf);
+ return (BAM_ERROR);
+ }
+
+ if (stat(archive_path, &sb) != 0) {
+ if (bam_verbose && !bam_check)
+ bam_print(UPDATE_ARCH_MISS, archive_path);
+ set_dir_flag(what, NEED_UPDATE);
+ set_dir_flag(what, NO_MULTI);
+ return (BAM_SUCCESS);
+ }
+
+ if (is_flag_on(IS_SPARC_TARGET))
+ return (BAM_SUCCESS);
+
+ if (bam_extend && sb.st_size > BA_SIZE_MAX) {
+ if (bam_verbose && !bam_check)
+ bam_print(MULTI_SIZE, archive_path, BA_SIZE_MAX);
+ set_dir_flag(what, NO_MULTI);
+ }
+
+ return (BAM_SUCCESS);
+}
+
+/*
+ * Check flags and presence of required files and directories.
* The force flag and/or absence of files should
* trigger an update.
* Suppress stdout output if check (-n) option is set
* (as -n should only produce parseable output.)
*/
-static void
+static int
check_flags_and_files(char *root)
{
- char path[PATH_MAX];
- struct stat sb;
+
+ struct stat sb;
+ int ret;
/*
- * if force, create archive unconditionally
+ * If archive is missing, create archive
*/
- if (bam_force) {
- walk_arg.need_update = 1;
- if (bam_verbose && !bam_check)
- bam_print(UPDATE_FORCE);
- return;
+ if (is_flag_on(IS_SPARC_TARGET)) {
+ ret = is_valid_archive(root, FILE64);
+ } else {
+ int what = FILE32;
+ do {
+ ret = is_valid_archive(root, what);
+ if (ret == BAM_ERROR)
+ return (BAM_ERROR);
+ what++;
+ } while (bam_direct == BAM_DIRECT_DBOOT && what < CACHEDIR_NUM);
}
+ if (bam_nowrite())
+ return (BAM_SUCCESS);
+
+
/*
- * If archive is missing, create archive
+ * check if cache directories exist on x86.
+ * check (and always open) the cache file on SPARC.
*/
if (is_sparc()) {
- (void) snprintf(path, sizeof (path), "%s%s%s%s", root,
- ARCHIVE_PREFIX, get_machine(), ARCHIVE_SUFFIX);
- } else {
- if (bam_direct == BAM_DIRECT_DBOOT) {
- (void) snprintf(path, sizeof (path), "%s%s", root,
- DIRECT_BOOT_ARCHIVE_64);
- if (stat(path, &sb) != 0) {
- if (bam_verbose && !bam_check)
- bam_print(UPDATE_ARCH_MISS, path);
- walk_arg.need_update = 1;
- return;
- }
+ ret = snprintf(get_cachedir(FILE64),
+ sizeof (get_cachedir(FILE64)), "%s%s%s/%s", root,
+ ARCHIVE_PREFIX, get_machine(), CACHEDIR_SUFFIX);
+
+ if (ret >= sizeof (get_cachedir(FILE64))) {
+ bam_error(PATH_TOO_LONG, rootbuf);
+ return (BAM_ERROR);
+ }
+
+ if (stat(get_cachedir(FILE64), &sb) != 0) {
+ set_flag(NEED_CACHE_DIR);
+ set_dir_flag(FILE64, NEED_UPDATE);
}
- (void) snprintf(path, sizeof (path), "%s%s", root,
- DIRECT_BOOT_ARCHIVE_32);
+
+ walk_arg.sparcfile = fopen(get_cachedir(FILE64), "w");
+ if (walk_arg.sparcfile == NULL) {
+ bam_error(OPEN_FAIL, get_cachedir(FILE64),
+ strerror(errno));
+ return (BAM_ERROR);
+ }
+
+ set_dir_present(FILE64);
+ } else {
+ int what = FILE32;
+
+ do {
+ if (set_cache_dir(root, what) != 0)
+ return (BAM_ERROR);
+
+ set_dir_present(what);
+
+ if (set_update_dir(root, what) != 0)
+ return (BAM_ERROR);
+ what++;
+ } while (bam_direct == BAM_DIRECT_DBOOT && what < CACHEDIR_NUM);
}
- if (stat(path, &sb) != 0) {
- if (bam_verbose && !bam_check)
- bam_print(UPDATE_ARCH_MISS, path);
- walk_arg.need_update = 1;
- return;
+ /*
+ * if force, create archive unconditionally
+ */
+ if (bam_force) {
+ if (!is_sparc())
+ set_dir_flag(FILE32, NEED_UPDATE);
+ set_dir_flag(FILE64, NEED_UPDATE);
+ if (bam_verbose)
+ bam_print(UPDATE_FORCE);
+ return (BAM_SUCCESS);
}
+
+ return (BAM_SUCCESS);
}
static error_t
read_one_list(char *root, filelist_t *flistp, char *filelist)
{
- char path[PATH_MAX];
- FILE *fp;
- char buf[BAM_MAXLINE];
- const char *fcn = "read_one_list()";
+ char path[PATH_MAX];
+ FILE *fp;
+ char buf[BAM_MAXLINE];
+ const char *fcn = "read_one_list()";
(void) snprintf(path, sizeof (path), "%s%s", root, filelist);
@@ -1446,11 +2122,11 @@ read_one_list(char *root, filelist_t *flistp, char *filelist)
static error_t
read_list(char *root, filelist_t *flistp)
{
- char path[PATH_MAX];
- char cmd[PATH_MAX];
- struct stat sb;
- int n, rval;
- const char *fcn = "read_list()";
+ char path[PATH_MAX];
+ char cmd[PATH_MAX];
+ struct stat sb;
+ int n, rval;
+ const char *fcn = "read_list()";
flistp->head = flistp->tail = NULL;
@@ -1523,38 +2199,34 @@ read_list(char *root, filelist_t *flistp)
static void
getoldstat(char *root)
{
- char path[PATH_MAX];
- int fd, error;
- struct stat sb;
- char *ostat;
+ char path[PATH_MAX];
+ int fd, error;
+ struct stat sb;
+ char *ostat;
(void) snprintf(path, sizeof (path), "%s%s", root, FILE_STAT);
fd = open(path, O_RDONLY);
if (fd == -1) {
if (bam_verbose)
bam_print(OPEN_FAIL, path, strerror(errno));
- walk_arg.need_update = 1;
- return;
+ goto out_err;
}
if (fstat(fd, &sb) != 0) {
bam_error(STAT_FAIL, path, strerror(errno));
- (void) close(fd);
- walk_arg.need_update = 1;
- return;
+ goto out_err;
}
ostat = s_calloc(1, sb.st_size);
if (read(fd, ostat, sb.st_size) != sb.st_size) {
bam_error(READ_FAIL, path, strerror(errno));
- (void) close(fd);
free(ostat);
- walk_arg.need_update = 1;
- return;
+ goto out_err;
}
(void) close(fd);
+ fd = -1;
walk_arg.old_nvlp = NULL;
error = nvlist_unpack(ostat, sb.st_size, &walk_arg.old_nvlp, 0);
@@ -1564,9 +2236,36 @@ getoldstat(char *root)
if (error) {
bam_error(UNPACK_FAIL, path, strerror(error));
walk_arg.old_nvlp = NULL;
- walk_arg.need_update = 1;
+ goto out_err;
+ } else {
return;
}
+
+out_err:
+ if (fd != -1)
+ (void) close(fd);
+ set_dir_flag(FILE32, NEED_UPDATE);
+ set_dir_flag(FILE64, NEED_UPDATE);
+}
+
+/* Best effort stale entry removal */
+static void
+delete_stale(char *file, int what)
+{
+ char path[PATH_MAX];
+ struct stat sb;
+
+ (void) snprintf(path, sizeof (path), "%s/%s", get_cachedir(what), file);
+ if (!bam_check && stat(path, &sb) == 0) {
+ if (sb.st_mode & S_IFDIR)
+ (void) rmdir_r(path);
+ else
+ (void) unlink(path);
+
+ set_dir_flag(what, (NEED_UPDATE | NO_MULTI));
+ }
+ if (bam_verbose)
+ bam_print(PARSEABLE_STALE_FILE, path);
}
/*
@@ -1582,7 +2281,6 @@ check4stale(char *root)
nvlist_t *nvlp;
char *file;
char path[PATH_MAX];
- struct stat sb;
/*
* Skip stale file check during smf check
@@ -1590,6 +2288,13 @@ check4stale(char *root)
if (bam_smf_check)
return;
+ /*
+ * If we need to (re)create the cache, there's no need to check for
+ * stale files
+ */
+ if (is_flag_on(NEED_CACHE_DIR))
+ return;
+
/* Nothing to do if no old stats */
if ((nvlp = walk_arg.old_nvlp) == NULL)
return;
@@ -1601,10 +2306,15 @@ check4stale(char *root)
continue;
(void) snprintf(path, sizeof (path), "%s/%s",
root, file);
- if (stat(path, &sb) == -1) {
- walk_arg.need_update = 1;
- if (bam_verbose)
- bam_print(PARSEABLE_STALE_FILE, path);
+ if (access(path, F_OK) < 0) {
+ int what;
+
+ if (is_flag_on(IS_SPARC_TARGET))
+ set_dir_flag(FILE64, NEED_UPDATE);
+
+ for (what = FILE32; what < CACHEDIR_NUM; what++)
+ if (has_cachedir(what))
+ delete_stale(file, what);
}
}
}
@@ -1624,7 +2334,7 @@ create_newstat(void)
}
}
-static void
+static int
walk_list(char *root, filelist_t *flistp)
{
char path[PATH_MAX];
@@ -1639,6 +2349,8 @@ walk_list(char *root, filelist_t *flistp)
*/
(void) snprintf(path, sizeof (path), "%s%s", root, lp->line);
if (nftw(path, cmpstat, 20, FTW_PHYS) == -1) {
+ if (is_flag_on(UPDATE_ERROR))
+ return (BAM_ERROR);
/*
* Some files may not exist.
* For example: etc/rtc_config on a x86 diskless system
@@ -1648,16 +2360,18 @@ walk_list(char *root, filelist_t *flistp)
bam_print(NFTW_FAIL, path, strerror(errno));
}
}
+
+ return (BAM_SUCCESS);
}
static void
savenew(char *root)
{
- char path[PATH_MAX];
- char path2[PATH_MAX];
- size_t sz;
- char *nstat;
- int fd, wrote, error;
+ char path[PATH_MAX];
+ char path2[PATH_MAX];
+ size_t sz;
+ char *nstat;
+ int fd, wrote, error;
nstat = NULL;
sz = 0;
@@ -1691,6 +2405,8 @@ savenew(char *root)
}
}
+#define init_walk_args() bzero(&walk_arg, sizeof (walk_arg))
+
static void
clear_walk_args(void)
{
@@ -1698,9 +2414,11 @@ clear_walk_args(void)
nvlist_free(walk_arg.old_nvlp);
if (walk_arg.new_nvlp)
nvlist_free(walk_arg.new_nvlp);
- walk_arg.need_update = 0;
+ if (walk_arg.sparcfile)
+ (void) fclose(walk_arg.sparcfile);
walk_arg.old_nvlp = NULL;
walk_arg.new_nvlp = NULL;
+ walk_arg.sparcfile = NULL;
}
/*
@@ -1720,20 +2438,24 @@ clear_walk_args(void)
static int
update_required(char *root)
{
- struct stat sb;
- char path[PATH_MAX];
- filelist_t flist;
- filelist_t *flistp = &flist;
- int need_update;
+ struct stat sb;
+ char path[PATH_MAX];
+ filelist_t flist;
+ filelist_t *flistp = &flist;
+ int ret;
flistp->head = flistp->tail = NULL;
- walk_arg.need_update = 0;
+ if (is_sparc())
+ set_flag(IS_SPARC_TARGET);
/*
- * Without consulting stat data, check if we need update
+ * Check if cache directories and archives are present
*/
- check_flags_and_files(root);
+
+ ret = check_flags_and_files(root);
+ if (ret < 0)
+ return (BAM_ERROR);
/*
* In certain deployment scenarios, filestat may not
@@ -1745,20 +2467,13 @@ update_required(char *root)
return (0);
}
- /*
- * consult stat data only if we haven't made a decision
- * about update. If checking (-n) however, we always
- * need stat data (since we want to compare old and new)
- */
- if (!walk_arg.need_update || bam_check)
- getoldstat(root);
+ getoldstat(root);
/*
* Check if the archive contains files that are no longer
* present on the root filesystem.
*/
- if (!walk_arg.need_update || bam_check)
- check4stale(root);
+ check4stale(root);
/*
* read list of files
@@ -1776,50 +2491,499 @@ update_required(char *root)
* we need to create new stat nvlist
*/
create_newstat();
-
/*
* This walk does 2 things:
* - gets new stat data for every file
* - (optional) compare old and new stat data
*/
- walk_list(root, &flist);
+ ret = walk_list(root, &flist);
/* done with the file list */
filelist_free(flistp);
- /*
- * if we didn't succeed in creating new stat data above
- * just return result of update check so that archive is built.
- */
+ /* something went wrong */
+
+ if (ret == BAM_ERROR) {
+ bam_error(CACHE_FAIL);
+ return (BAM_ERROR);
+ }
+
if (walk_arg.new_nvlp == NULL) {
+ (void) fclose(walk_arg.sparcfile);
bam_error(NO_NEW_STAT);
- need_update = walk_arg.need_update;
- clear_walk_args();
- return (need_update ? 1 : 0);
}
+ /* If nothing was updated, discard newstat. */
- /*
- * If no update required, discard newstat
- */
- if (!walk_arg.need_update) {
+ if (!is_dir_flag_on(FILE32, NEED_UPDATE) &&
+ !is_dir_flag_on(FILE64, NEED_UPDATE)) {
clear_walk_args();
return (0);
}
+ (void) fclose(walk_arg.sparcfile);
+
return (1);
}
+/*
+ * Returns 1 if we're dealing with a bfu archive update, 0 otherwise
+ */
+static int
+is_bfu()
+{
+ char *path;
+
+ path = getenv("PATH");
+ if (path != NULL &&
+ strncmp(path, "/tmp/bfubin", strlen("/tmp/bfubin")) == 0) {
+ struct stat sb;
+ if (stat("/tmp/bfubin", &sb) == 0) {
+ if (!(sb.st_mode & S_IFDIR))
+ return (0);
+ if (sb.st_uid != getuid())
+ return (0);
+ return (1);
+ }
+ }
+ return (0);
+}
+
+#define LOCKFS_PATH (is_bfu() ? LOCKFS_BFU : LOCKFS_BIN)
+
+static int
+flushfs(char *root)
+{
+ char cmd[PATH_MAX + 30];
+
+ (void) snprintf(cmd, sizeof (cmd), "%s -f \"%s\" 2>/dev/null",
+ LOCKFS_PATH, root);
+
+ return (exec_cmd(cmd, NULL));
+}
+
+static int
+do_archive_copy(char *source, char *dest)
+{
+
+ (void) sync();
+
+ /* the equivalent of mv archive-new-$pid boot_archive */
+ if (rename(source, dest) != 0)
+ return (BAM_ERROR);
+
+ if (flushfs(bam_root) != 0)
+ (void) sync();
+
+ return (BAM_SUCCESS);
+}
+
+static int
+check_cmdline(filelist_t flist)
+{
+ line_t *lp;
+
+ for (lp = flist.head; lp; lp = lp->next) {
+ if (strstr(lp->line, "Error:") != NULL ||
+ strstr(lp->line, "Inode number overflow") != NULL) {
+ (void) fprintf(stderr, "%s", lp->line);
+ return (BAM_ERROR);
+ }
+ }
+
+ return (BAM_SUCCESS);
+}
+
+static int
+check_archive(char *dest)
+{
+ struct stat sb;
+
+ if (stat(dest, &sb) != 0 || !S_ISREG(sb.st_mode) ||
+ sb.st_size < 10000) {
+ bam_error(ARCHIVE_BAD, dest);
+ (void) unlink(dest);
+ return (BAM_ERROR);
+ }
+
+ return (BAM_SUCCESS);
+}
+
+/*
+ * Returns 1 if mkiso is in the expected PATH, 0 otherwise
+ */
+static int
+is_mkisofs()
+{
+ if (is_bfu()) {
+ if (access(MKISOFS_BFUBIN, X_OK) == 0)
+ return (1);
+ } else {
+ if (access(MKISOFS_BIN, X_OK) == 0)
+ return (1);
+ }
+ return (0);
+}
+
+#define MKISO_PARAMS " -quiet -graft-points -dlrDJN -relaxed-filenames "
+#define MKISO_PATH (is_bfu() ? MKISOFS_BFUBIN : MKISOFS_BIN)
+#define DD_PATH (is_bfu() ? DD_PATH_BFU : DD_PATH_USR)
+
+static int
+create_sparc_archive(char *archive, char *tempname, char *bootblk, char *list)
+{
+ int ret;
+ char cmdline[3 * PATH_MAX + 64];
+ filelist_t flist = {0};
+ const char *func = "create_sparc_archive()";
+
+ if (access(bootblk, R_OK) == 1) {
+ bam_error(BOOTBLK_FAIL, bootblk);
+ return (BAM_ERROR);
+ }
+
+ /*
+ * Prepare mkisofs command line and execute it
+ */
+ (void) snprintf(cmdline, sizeof (cmdline), "%s %s -G %s -o \"%s\" "
+ "-path-list \"%s\" 2>&1", MKISO_PATH, MKISO_PARAMS, bootblk,
+ tempname, list);
+
+ BAM_DPRINTF((D_CMDLINE, func, cmdline));
+
+ ret = exec_cmd(cmdline, &flist);
+ if (ret != 0 || check_cmdline(flist) == BAM_ERROR)
+ goto out_err;
+
+ filelist_free(&flist);
+
+ /*
+ * Prepare dd command line to copy the bootblk on the new archive and
+ * execute it
+ */
+ (void) snprintf(cmdline, sizeof (cmdline), "%s if=\"%s\" of=\"%s\""
+ " bs=1b oseek=1 count=15 conv=notrunc conv=sync 2>&1", DD_PATH,
+ bootblk, tempname);
+
+ BAM_DPRINTF((D_CMDLINE, func, cmdline));
+
+ ret = exec_cmd(cmdline, &flist);
+ if (ret != 0 || check_cmdline(flist) == BAM_ERROR)
+ goto out_err;
+
+ filelist_free(&flist);
+
+ /* Did we get a valid archive ? */
+ if (check_archive(tempname) == BAM_ERROR)
+ return (BAM_ERROR);
+
+ return (do_archive_copy(tempname, archive));
+
+out_err:
+ filelist_free(&flist);
+ bam_error(ARCHIVE_FAIL, cmdline);
+ (void) unlink(tempname);
+ return (BAM_ERROR);
+}
+
+static unsigned int
+from_733(unsigned char *s)
+{
+ int i;
+ unsigned int ret = 0;
+
+ for (i = 0; i < 4; i++)
+ ret |= s[i] << (8 * i);
+
+ return (ret);
+}
+
+static void
+to_733(unsigned char *s, unsigned int val)
+{
+ int i;
+
+ for (i = 0; i < 4; i++)
+ s[i] = s[7-i] = (val >> (8 * i)) & 0xFF;
+}
+
+/*
+ * Extends the current boot archive without recreating it from scratch
+ */
+static int
+extend_iso_archive(char *archive, char *tempname, char *update_dir)
+{
+ int fd = -1, newfd = -1, ret, i;
+ int next_session = 0, new_size = 0;
+ char cmdline[3 * PATH_MAX + 64];
+ const char *func = "extend_iso_archive()";
+ filelist_t flist = {0};
+ struct iso_pdesc saved_desc[MAX_IVDs];
+
+ fd = open(archive, O_RDWR);
+ if (fd == -1) {
+ bam_error(OPEN_FAIL, archive, strerror(errno));
+ goto out_err;
+ }
+
+ /*
+ * A partial read is likely due to a corrupted file
+ */
+ ret = pread64(fd, saved_desc, sizeof (saved_desc),
+ VOLDESC_OFF * CD_BLOCK);
+ if (ret != sizeof (saved_desc)) {
+ bam_error(READ_FAIL, archive, strerror(errno));
+ goto out_err;
+ }
+
+ if (memcmp(saved_desc[0].type, "\1CD001", 6)) {
+ bam_error(SIGN_FAIL, archive);
+ goto out_err;
+ }
+
+ /*
+ * Read primary descriptor and locate next_session offset (it should
+ * point to the end of the archive)
+ */
+ next_session = P2ROUNDUP(from_733(saved_desc[0].volume_space_size), 16);
+
+ (void) snprintf(cmdline, sizeof (cmdline), "%s -C 16,%d -M %s %s -o \""
+ "%s\" \"%s\" 2>&1", MKISO_PATH, next_session, archive, MKISO_PARAMS,
+ tempname, update_dir);
+
+ BAM_DPRINTF((D_CMDLINE, func, cmdline));
+
+ ret = exec_cmd(cmdline, &flist);
+ if (ret != 0 || check_cmdline(flist) == BAM_ERROR) {
+ bam_error(MULTI_FAIL, cmdline);
+ goto out_flist_err;
+ }
+ filelist_free(&flist);
+
+ newfd = open(tempname, O_RDONLY);
+ if (newfd == -1) {
+ bam_error(OPEN_FAIL, archive, strerror(errno));
+ goto out_err;
+ }
+
+ ret = pread64(newfd, saved_desc, sizeof (saved_desc),
+ VOLDESC_OFF * CD_BLOCK);
+ if (ret != sizeof (saved_desc)) {
+ bam_error(READ_FAIL, archive, strerror(errno));
+ goto out_err;
+ }
+
+ if (memcmp(saved_desc[0].type, "\1CD001", 6)) {
+ bam_error(SIGN_FAIL, archive);
+ goto out_err;
+ }
+
+ new_size = from_733(saved_desc[0].volume_space_size) + next_session;
+ to_733(saved_desc[0].volume_space_size, new_size);
+
+ for (i = 1; i < MAX_IVDs; i++) {
+ if (saved_desc[i].type[0] == (unsigned char)255)
+ break;
+ if (memcmp(saved_desc[i].id, "CD001", 5))
+ break;
+
+ if (bam_verbose)
+ bam_print("%s: Updating descriptor entry [%d]\n", func,
+ i);
+
+ to_733(saved_desc[i].volume_space_size, new_size);
+ }
+
+ ret = pwrite64(fd, saved_desc, DVD_BLOCK, VOLDESC_OFF*CD_BLOCK);
+ if (ret != DVD_BLOCK) {
+ bam_error(WRITE_FAIL, archive, strerror(errno));
+ goto out_err;
+ }
+ (void) close(newfd);
+ newfd = -1;
+
+ ret = close(fd);
+ if (ret != 0) {
+ bam_error(CLOSE_FAIL, archive, strerror(errno));
+ return (BAM_ERROR);
+ }
+ fd = -1;
+
+ (void) snprintf(cmdline, sizeof (cmdline), "%s if=%s of=%s bs=32k "
+ "seek=%d conv=sync 2>&1", DD_PATH, tempname, archive,
+ (next_session/16));
+
+ BAM_DPRINTF((D_CMDLINE, func, cmdline));
+
+ ret = exec_cmd(cmdline, &flist);
+ if (ret != 0 || check_cmdline(flist) == BAM_ERROR) {
+ bam_error(MULTI_FAIL, cmdline);
+ goto out_flist_err;
+ }
+ filelist_free(&flist);
+
+ (void) unlink(tempname);
+
+ if (bam_verbose)
+ bam_print("boot archive updated successfully\n");
+
+ return (BAM_SUCCESS);
+
+out_flist_err:
+ filelist_free(&flist);
+out_err:
+ if (fd != -1)
+ (void) close(fd);
+ if (newfd != -1)
+ (void) close(newfd);
+ return (BAM_ERROR);
+}
+
+static int
+create_x86_archive(char *archive, char *tempname, char *update_dir)
+{
+ int ret;
+ char cmdline[3 * PATH_MAX + 64];
+ filelist_t flist = {0};
+ const char *func = "create_x86_archive()";
+
+ (void) snprintf(cmdline, sizeof (cmdline), "%s %s -o \"%s\" \"%s\" "
+ "2>&1", MKISO_PATH, MKISO_PARAMS, tempname, update_dir);
+
+ BAM_DPRINTF((D_CMDLINE, func, cmdline));
+
+ ret = exec_cmd(cmdline, &flist);
+ if (ret != 0 || check_cmdline(flist) == BAM_ERROR) {
+ bam_error(ARCHIVE_FAIL, cmdline);
+ filelist_free(&flist);
+ (void) unlink(tempname);
+ return (BAM_ERROR);
+ }
+
+ filelist_free(&flist);
+
+ if (check_archive(tempname) == BAM_ERROR)
+ return (BAM_ERROR);
+
+ return (do_archive_copy(tempname, archive));
+}
+
+static int
+mkisofs_archive(char *root, int what)
+{
+ int ret;
+ char temp[PATH_MAX];
+ char bootblk[PATH_MAX];
+ char boot_archive[PATH_MAX];
+
+ if (what == FILE64 && !is_flag_on(IS_SPARC_TARGET))
+ ret = snprintf(temp, sizeof (temp),
+ "%s%s%s/amd64/archive-new-%d", root, ARCHIVE_PREFIX,
+ get_machine(), getpid());
+ else
+ ret = snprintf(temp, sizeof (temp), "%s%s%s/archive-new-%d",
+ root, ARCHIVE_PREFIX, get_machine(), getpid());
+
+ if (ret >= sizeof (temp))
+ goto out_path_err;
+
+ if (what == FILE64 && !is_flag_on(IS_SPARC_TARGET))
+ ret = snprintf(boot_archive, sizeof (boot_archive),
+ "%s%s%s/amd64%s", root, ARCHIVE_PREFIX, get_machine(),
+ ARCHIVE_SUFFIX);
+ else
+ ret = snprintf(boot_archive, sizeof (boot_archive),
+ "%s%s%s%s", root, ARCHIVE_PREFIX, get_machine(),
+ ARCHIVE_SUFFIX);
+
+ if (ret >= sizeof (boot_archive))
+ goto out_path_err;
+
+ bam_print("updating %s\n", boot_archive);
+
+ if (is_flag_on(IS_SPARC_TARGET)) {
+ ret = snprintf(bootblk, sizeof (bootblk),
+ "%s/platform/%s/lib/fs/hsfs/bootblk", root, get_machine());
+ if (ret >= sizeof (bootblk))
+ goto out_path_err;
+
+ ret = create_sparc_archive(boot_archive, temp, bootblk,
+ get_cachedir(what));
+ } else {
+ if (!is_dir_flag_on(what, NO_MULTI)) {
+ if (bam_verbose)
+ bam_print("Attempting to extend x86 archive: "
+ "%s\n", boot_archive);
+
+ ret = extend_iso_archive(boot_archive, temp,
+ get_updatedir(what));
+ if (ret == BAM_SUCCESS) {
+ if (bam_verbose)
+ bam_print("Successfully extended %s\n",
+ boot_archive);
+
+ (void) rmdir_r(get_updatedir(what));
+ return (BAM_SUCCESS);
+ }
+ }
+ /*
+ * The boot archive will be recreated from scratch. We get here
+ * if at least one of these conditions is true:
+ * - bootadm was called without the -e switch
+ * - the archive (or the archive cache) doesn't exist
+ * - archive size is bigger than BA_SIZE_MAX
+ * - more than COUNT_MAX files need to be updated
+ * - an error occourred either populating the /updates directory
+ * or extend_iso_archive() failed
+ */
+ if (bam_verbose)
+ bam_print("Unable to extend %s... rebuilding archive\n",
+ boot_archive);
+
+ if (get_updatedir(what)[0] != '\0')
+ (void) rmdir_r(get_updatedir(what));
+
+
+ ret = create_x86_archive(boot_archive, temp,
+ get_cachedir(what));
+ }
+
+ if (ret == BAM_SUCCESS && bam_verbose)
+ bam_print("Successfully created %s\n", boot_archive);
+
+ return (ret);
+
+out_path_err:
+ bam_error(PATH_TOO_LONG, root);
+ return (BAM_ERROR);
+}
+
static error_t
create_ramdisk(char *root)
{
char *cmdline, path[PATH_MAX];
size_t len;
struct stat sb;
+ int ret, what;
+
+ /* If there is mkisofs, use it to create the required archives */
+ if (is_mkisofs()) {
+ for (what = FILE32; what < CACHEDIR_NUM; what++) {
+ if (is_dir_flag_on(what, NEED_UPDATE)) {
+ ret = mkisofs_archive(root, what);
+ if (ret != 0)
+ return (BAM_ERROR);
+ }
+ }
+ return (BAM_SUCCESS);
+ }
/*
- * Setup command args for create_ramdisk.ksh
+ * Else setup command args for create_ramdisk.ksh for the UFS archives
*/
+ if (bam_verbose)
+ bam_print("mkisofs not found, creating UFS archive\n");
+
(void) snprintf(path, sizeof (path), "%s/%s", root, CREATE_RAMDISK);
if (stat(path, &sb) != 0) {
bam_error(ARCH_EXEC_MISS, path, strerror(errno));
@@ -1850,13 +3014,11 @@ create_ramdisk(char *root)
return (BAM_ERROR);
}
free(cmdline);
-
/*
* The existence of the expected archives used to be
* verified here. This check is done in create_ramdisk as
* it needs to be in sync with the altroot operated upon.
*/
-
return (BAM_SUCCESS);
}
@@ -1885,7 +3047,6 @@ is_ramdisk(char *root)
* worth it.
* The other two conditions are handled here
*/
-
fp = fopen(MNTTAB, "r");
if (fp == NULL) {
bam_error(OPEN_FAIL, MNTTAB, strerror(errno));
@@ -2093,6 +3254,9 @@ update_archive(char *root, char *opt)
assert(root);
assert(opt == NULL);
+ init_walk_args();
+ (void) umask(022);
+
/*
* root must belong to a boot archive based OS,
*/
@@ -2103,7 +3267,7 @@ update_archive(char *root, char *opt)
*/
if (!bam_update_all || bam_verbose)
bam_print(NOT_ARCHIVE_BOOT, root);
- return (BAM_SUCCESS);
+ return (BAM_ERROR);
}
/*
@@ -2111,26 +3275,26 @@ update_archive(char *root, char *opt)
* on first reboot following an upgrade because service
* dependency is messed up), skip the check.
*/
- if (bam_smf_check && !bam_root_readonly)
+ if (bam_smf_check && !bam_root_readonly && !is_zfs(root))
return (BAM_SUCCESS);
/*
* root must be writable. This check applies to alternate
* root (-R option); bam_root_readonly applies to '/' only.
+ * The behaviour translates into being the one of a 'check'.
*/
if (!bam_smf_check && !bam_check && is_readonly(root)) {
- if (bam_verbose)
- bam_print(RDONLY_FS, root);
- return (BAM_SUCCESS);
+ set_flag(RDONLY_FSCHK);
+ bam_check = 1;
}
/*
- * Don't generate archive on ramdisk
+ * Don't generate archive on ramdisk, but still check if the
+ * archive is up-to-date
*/
if (is_ramdisk(root)) {
- if (bam_verbose)
- bam_print(SKIP_RAMDISK);
- return (BAM_SUCCESS);
+ set_flag(RAMDSK_FSCHK);
+ bam_check = 1;
}
/*
@@ -2141,8 +3305,24 @@ update_archive(char *root, char *opt)
/*
* The check command (-n) is *not* a dry run
* It only checks if the archive is in sync.
+ * A readonly filesystem or being on a ramdisk have to be considered
+ * errors only if an update is required.
*/
if (bam_check) {
+ if (is_flag_on(RDONLY_FSCHK)) {
+ if (ret > 0)
+ bam_error(RDONLY_FS, root);
+ if (bam_update_all)
+ return ((ret != 0) ? BAM_ERROR : BAM_SUCCESS);
+ }
+
+ if (is_flag_on(RAMDSK_FSCHK)) {
+ if (ret > 0)
+ bam_error(SKIP_RAMDISK, root);
+ if (bam_update_all)
+ return ((ret != 0) ? BAM_ERROR : BAM_SUCCESS);
+ }
+
bam_exit((ret != 0) ? 1 : 0);
}
@@ -2369,7 +3549,7 @@ update_all(char *root, char *opt)
* mount of root.
*/
if (stat(LOFS_PATCH_FILE, &sb) == 0) {
- if (mkdir(LOFS_PATCH_MNT, 0755) == -1 &&
+ if (mkdir(LOFS_PATCH_MNT, DIR_PERMS) == -1 &&
errno != EEXIST) {
bam_error(MKDIR_FAILED, "%s", LOFS_PATCH_MNT,
strerror(errno));
@@ -3747,7 +4927,7 @@ mount_legacy_dataset(char *pool, zfs_mnted_t *mnted)
ret = stat(tmpmnt, &sb);
if (ret == -1) {
BAM_DPRINTF((D_Z_MOUNT_TOP_LEG_MNTPT_ABS, fcn, pool, tmpmnt));
- ret = mkdirp(tmpmnt, 0755);
+ ret = mkdirp(tmpmnt, DIR_PERMS);
INJECT_ERROR1("Z_MOUNT_TOP_LEG_MNTPT_MKDIRP", ret = -1);
if (ret == -1) {
bam_error(MKDIR_FAILED, tmpmnt, strerror(errno));
@@ -4676,7 +5856,7 @@ FindAllUfsSignatures(void)
"/tmp/bootadm_ufs_sign_mnt.%d", getpid());
(void) unlink(tmpmnt);
- ret = mkdirp(tmpmnt, 0755);
+ ret = mkdirp(tmpmnt, DIR_PERMS);
error = errno;
INJECT_ERROR1("MKDIRP_SIGN_MNT", ret = -1);
if (ret == -1) {
@@ -5021,7 +6201,7 @@ set_backup_common(char *mntpt, char *sign)
INJECT_ERROR1("SET_BACKUP_STAT", ret = -1);
if (ret == -1) {
BAM_DPRINTF((D_BACKUP_DIR_NOEXIST, fcn, bdir));
- ret = mkdirp(bdir, 0755);
+ ret = mkdirp(bdir, DIR_PERMS);
error = errno;
INJECT_ERROR1("SET_BACKUP_MKDIRP", ret = -1);
if (ret == -1) {
@@ -5174,7 +6354,7 @@ set_primary_common(char *mntpt, char *sign)
if (stat(signdir, &sb) == -1) {
BAM_DPRINTF((D_PRIMARY_DIR_NOEXIST, fcn, signdir));
- ret = mkdirp(signdir, 0755);
+ ret = mkdirp(signdir, DIR_PERMS);
error = errno;
INJECT_ERROR1("SET_PRIMARY_MKDIRP", ret = -1);
if (ret == -1) {
diff --git a/usr/src/cmd/boot/bootadm/bootadm.h b/usr/src/cmd/boot/bootadm/bootadm.h
index 9bd3f85bd2..4772e69e8e 100644
--- a/usr/src/cmd/boot/bootadm/bootadm.h
+++ b/usr/src/cmd/boot/bootadm/bootadm.h
@@ -231,6 +231,8 @@ extern int is_sparc(void);
/* Boot archives */
#define ARCHIVE_PREFIX "/platform/"
#define ARCHIVE_SUFFIX "/boot_archive"
+#define CACHEDIR_SUFFIX "/archive_cache"
+#define UPDATEDIR_SUFFIX "/updates"
#define DIRECT_BOOT_ARCHIVE "/platform/i86pc/$ISADIR/boot_archive"
#define DIRECT_BOOT_ARCHIVE_32 "/platform/i86pc/boot_archive"
#define DIRECT_BOOT_ARCHIVE_64 "/platform/i86pc/amd64/boot_archive"
@@ -238,6 +240,10 @@ extern int is_sparc(void);
#define FAILSAFE_ARCHIVE "/boot/$ISADIR/x86.miniroot-safe"
#define FAILSAFE_ARCHIVE_32 "/boot/x86.miniroot-safe"
#define FAILSAFE_ARCHIVE_64 "/boot/amd64/x86.miniroot-safe"
+#define CACHEDIR_32 "/platform/i86pc/archive_cache"
+#define CACHEDIR_64 "/platform/i86pc/amd64/archive_cache"
+#define UPDATEDIR_32 "/platform/i86pc/updates"
+#define UPDATEDIR_64 "/platform/i86pc/amd64/updates"
/* Hypervisors */
#define XEN_32 "/boot/xen.gz"
@@ -248,6 +254,14 @@ extern int is_sparc(void);
#define XEN_KERNEL_MODULE_LINE_ZFS \
HYPERVISOR_KERNEL " " HYPERVISOR_KERNEL " " ZFS_BOOT
+/* Helpers */
+#define MKISOFS_BIN "/usr/bin/mkisofs"
+#define MKISOFS_BFUBIN "/tmp/bfubin/mkisofs"
+#define DD_PATH_USR "/usr/bin/dd"
+#define DD_PATH_BFU "/tmp/bfubin/dd"
+#define LOCKFS_BIN "/usr/sbin/lockfs"
+#define LOCKFS_BFU "/tmp/bfubin/lockfs"
+
/* A first guess at the number of entries in a menu */
#define BAM_ENTRY_NUM 10
diff --git a/usr/src/cmd/boot/bootadm/message.h b/usr/src/cmd/boot/bootadm/message.h
index bf75aad16e..4083449a51 100644
--- a/usr/src/cmd/boot/bootadm/message.h
+++ b/usr/src/cmd/boot/bootadm/message.h
@@ -59,6 +59,9 @@ extern "C" {
#define ABS_PATH_REQ gettext("path is not absolute: %s\n")
+#define PATH_TOO_LONG \
+ gettext("unable to create path on mountpoint %s, path too long\n")
+
#define TOO_LONG gettext("the following line is too long (> %d chars)\n\t%s\n")
#define NOT_GRUB_BOOT \
@@ -79,7 +82,7 @@ extern "C" {
#define CANNOT_LOCATE_GRUB_MENU gettext("cannot find GRUB menu\n")
-#define GRUB_MENU_PATH gettext("The location for the active GRUB menu is: %s\n")
+#define GRUB_MENU_PATH gettext("the location for the active GRUB menu is: %s\n")
#define STUBBOOT_DIR_NOT_FOUND gettext("cannot find stubboot directory\n")
@@ -98,9 +101,9 @@ extern "C" {
#define SUBOPT_MISS gettext("missing suboption: %s\n")
-#define NO_KERNEL gettext("No kernel line found in entry %d\n")
+#define NO_KERNEL gettext("no kernel line found in entry %d\n")
-#define EMPTY_MENU gettext("The GRUB menu is empty\n")
+#define EMPTY_MENU gettext("the GRUB menu is empty\n")
#define UNLINK_EMPTY gettext("file is empty, deleting file: %s\n")
@@ -110,9 +113,12 @@ extern "C" {
#define INVALID_OPT gettext("invalid option: %s\n")
-#define FAILED_SIG gettext("Cannot set SIGCHLD disposition: %s\n")
+#define FAILED_SIG gettext("cannot set SIGCHLD disposition: %s\n")
+
+#define CANT_UNBLOCK_SIGCHLD gettext("cannot unblock SIGCHLD: %s\n")
-#define CANT_UNBLOCK_SIGCHLD gettext("Cannot unblock SIGCHLD: %s\n")
+#define NO3264ELF \
+ gettext("WARNING: file %s is neither a 32-bit nor a 64-bit ELF\n")
#define BLOCKED_SIG gettext("SIGCHLD signal blocked. Cannot exec: %s\n")
@@ -124,18 +130,22 @@ extern "C" {
#define OPEN_FAIL gettext("failed to open file: %s: %s\n")
+#define GZ_OPEN_FAIL gettext("failed to open %s\n")
+
#define LOCK_FAIL gettext("failed to lock file: %s: %s\n")
#define UNLOCK_FAIL gettext("failed to unlock file: %s: %s\n")
#define MMAP_FAIL gettext("failed to mmap file: %s: %s\n")
-#define FILE_LOCKED gettext("Another instance of bootadm (pid %u) is running\n")
+#define FILE_LOCKED gettext("another instance of bootadm (pid %u) is running\n")
#define NO_FLIST gettext("archive filelist is empty\n")
#define CLOSE_FAIL gettext("failed to close file: %s: %s\n")
+#define GZCLOSE_FAIL gettext("unable to close %s\n")
+
#define RENAME_FAIL gettext("rename to file failed: %s: %s\n")
#define NOT_IN_MNTTAB gettext("alternate root %s not in mnttab\n")
@@ -144,10 +154,24 @@ extern "C" {
#define ROOT_ABS gettext("this sub-command doesn't take root arguments: %s\n")
-#define ARCHIVE_FAIL gettext("Command '%s' failed to create boot archive\n")
+#define ARCHIVE_FAIL gettext("boot-archive creation FAILED, command: '%s'\n")
+
+#define MULTI_FAIL \
+ gettext("Command '%s' failed while generating multisession archive\n")
+
+#define INFILE_FAIL gettext("unable to read from %s: %s\n")
+
+#define ARCHIVE_BAD gettext("archive file %s not generated correctly\n")
+
+#define CACHE_FAIL \
+ gettext("Failed to gather cache files, archives generation aborted\n")
+
+#define BOOTBLK_FAIL gettext("unable to access bootblk file : %s\n")
#define WRITE_FAIL gettext("write to file failed: %s: %s\n")
+#define GZ_WRITE_FAIL gettext("failed to write to %s\n")
+
#define STAT_FAIL gettext("stat of file failed: %s: %s\n")
#define PACK_FAIL gettext("failed to pack stat data: %s\n")
@@ -177,17 +201,25 @@ extern "C" {
#define UPDATE_ARCH_MISS gettext("archive not found: %s\n")
+#define UPDATE_CDIR_MISS gettext("archive cache directory not found: %s\n")
+
+#define MULTI_SIZE \
+ gettext("archive %s is bigger than %d bytes and will be rebuilt\n")
+
#define READ_FAIL gettext("read failed for file: %s: %s\n")
#define UNPACK_FAIL gettext("failed to unpack stat data: %s: %s\n")
#define NFTW_FAIL gettext("cannot find: %s: %s\n")
+#define SIGN_FAIL gettext("iso descriptor signature for %s is invalid\n")
+
#define STATVFS_FAIL gettext("statvfs failed for %s: %s\n")
#define IS_RAMDISK gettext("%s is on a ramdisk device\n")
-#define SKIP_RAMDISK gettext("Skipping archive creation\n")
+#define SKIP_RAMDISK \
+ gettext("Filesystem %s is on a ramdisk, skipping archive creation\n")
#define PRINT gettext("%s\n")
@@ -238,7 +270,7 @@ extern "C" {
#define FDISK_FILES_FOUND \
gettext("Deferred FDISK update file(s) found: %s, %s. Not supported.\n")
-#define UNKNOWN_KERNEL gettext("Unable to expand %s to a full file path.\n")
+#define UNKNOWN_KERNEL gettext("unable to expand %s to a full file path.\n")
#define UNKNOWN_KERNEL_REBOOT \
gettext("Rebooting with default kernel and options.\n")
@@ -364,23 +396,23 @@ updated. Not updating line %d\n")
#define INVALID_DEV_DSK gettext("not a /dev/[r]dsk name: %s\n")
-#define CVT_FINDROOT gettext("Converting entries to findroot...\n")
+#define CVT_FINDROOT gettext("converting entries to findroot...\n")
-#define CVT_HV gettext("Adding xVM entries...\n")
+#define CVT_HV gettext("adding xVM entries...\n")
-#define CVT_DBOOT gettext("Converting entries to dboot...\n")
+#define CVT_DBOOT gettext("converting entries to dboot...\n")
#define DOWNGRADE_NOTSUP \
-gettext("Automated downgrade of GRUB menu to older version not supported.\n")
+gettext("automated downgrade of GRUB menu to older version not supported.\n")
-#define CANT_FIND_GRUBSIGN gettext("Cannot find GRUB signature for %s\n")
+#define CANT_FIND_GRUBSIGN gettext("cannot find GRUB signature for %s\n")
#define CVT_TODO \
-gettext("One or more GRUB menu entries were not automatically upgraded\n\
+gettext("one or more GRUB menu entries were not automatically upgraded\n\
For details on manually updating entries, see %s\n")
#define CVT_ABORT \
-gettext("Error upgrading GRUB menu entries on %s. Aborting.\n\
+gettext("error upgrading GRUB menu entries on %s. Aborting.\n\
For details on manually updating entries, see %s\n")
#define HAND_ADDED_ENTRIES \
@@ -389,57 +421,58 @@ bootadm(1M) or lu(1M). The following entries on %s will not be upgraded.\n\
For details on manually updating entries, see %s\n")
#define SIGN_FSTYPE_MISMATCH \
-gettext("Found mismatched boot signature %s for filesystem type: %s.\n")
+gettext("found mismatched boot signature %s for filesystem type: %s.\n")
#define REBOOT_FSTYPE_FAILED \
-gettext("Failed to determine filesystem type for \"/\". Reboot with \n\
+gettext("failed to determine filesystem type for \"/\". Reboot with \n\
arguments failed.\n")
#define REBOOT_SPECIAL_FAILED \
-gettext("Failed to find device special file for \"/\". Reboot with \n\
+gettext("failed to find device special file for \"/\". Reboot with \n\
arguments failed.\n")
#define REBOOT_SIGN_FAILED \
-gettext("Failed to find boot signature. Reboot with arguments failed.\n")
+gettext("failed to find boot signature. Reboot with arguments failed.\n")
#define REBOOT_DIRECT_FAILED \
-gettext("The root filesystem is not a dboot Solaris instance. \n\
+gettext("the root filesystem is not a dboot Solaris instance. \n\
This version of bootadm is not supported on this version of Solaris.\n")
#define BOOTENV_FSTYPE_FAILED \
-gettext("Cannot determine filesystem type for \"/\".\n\
+gettext("cannot determine filesystem type for \"/\".\n\
Cannot generate GRUB menu entry with EEPROM arguments.\n")
#define BOOTENV_SPECIAL_FAILED \
-gettext("Cannot determine device special file for \"/\".\n\
+gettext("cannot determine device special file for \"/\".\n\
Cannot generate GRUB menu entry with EEPROM arguments.\n")
#define BOOTENV_SIGN_FAILED \
-gettext("Cannot determine boot signature for \"/\".\n\
+gettext("cannot determine boot signature for \"/\".\n\
Cannot generate GRUB menu entry with EEPROM arguments.\n")
#define GRUB_SLICE_FILE_EXISTS \
gettext("unsupported GRUB slice file (%s) exists - ignoring.\n")
#define GRUBSIGN_FOUND_OR_CREATED \
-gettext("Found or created GRUB signature %s for %s\n")
+gettext("found or created GRUB signature %s for %s\n")
-#define GET_FSTYPE_ARGS gettext("No OS mountpoint. Cannot determine fstype\n")
+#define GET_FSTYPE_ARGS gettext("no OS mountpoint. Cannot determine fstype\n")
#define MNTTAB_MNTPT_NOT_FOUND \
- gettext("Failed to find OS mountpoint %s in %s\n")
+ gettext("failed to find OS mountpoint %s in %s\n")
#define MNTTAB_FSTYPE_NULL gettext("NULL fstype found for OS root %s\n")
-#define MISSING_ARG gettext("Missing argument for sub-command\n")
+#define MISSING_ARG gettext("missing argument for sub-command\n")
-#define INVALID_BINARY gettext("Invalid or corrupted binary: %s\n")
+#define INVALID_BINARY gettext("invalid or corrupted binary: %s\n")
#define PCFS_ROOT_NOTSUP gettext("root <%s> on PCFS is not supported\n")
#define NO_O_OSROOT gettext("OS root not specified with -o option: %s\n")
-#define RDONLY_FS gettext("is a READONLY filesystem: %s\n")
+#define RDONLY_FS \
+ gettext("archive update failed for %s: filesystem is readonly\n")
#define RDONLY_TEST_ERROR gettext("error during read-only test on %s: %s\n")
@@ -469,13 +502,13 @@ gettext("failed to set primary sign (%s) for %s: %s\n")
#define GET_FSTYPE_FAILED gettext("failed to get fstype for %s\n")
#define GET_SPECIAL_NULL_MNTPT \
- gettext("Cannot get special file: NULL mount-point\n")
+ gettext("cannot get special file: NULL mount-point\n")
#define GET_SPECIAL_NULL \
- gettext("Cannot get special file for mount-point: %s\n")
+ gettext("cannot get special file for mount-point: %s\n")
#define GET_PHYSICAL_MENU_NULL \
- gettext("Cannot get physical device special file for menu root: %s\n")
+ gettext("cannot get physical device special file for menu root: %s\n")
#define GET_GRUBSIGN_ERROR \
gettext("failed to get grubsign for root: %s, device %s\n")
@@ -622,6 +655,10 @@ gettext("failed to get special file for menu_root: %s\n")
#define PROP_GRUB_MENU \
gettext("propagating updated GRUB menu\n")
+#define NEED_DIRPATH gettext("need to create directory path for %s\n")
+
+#define UPDT_CACHE_FAIL gettext("directory cache update failed for %s\n")
+
/*
* NOTE: The following are debug messages and not I18Ned
*/
@@ -1047,6 +1084,8 @@ gettext("failed to get special file for menu_root: %s\n")
#define D_SET_HV "%s: setting XEN HV flag: %s\n"
+#define D_REC_MKDIR "%s: making recursive directory %s\n"
+
#define D_SET_HAND_KERNEL "%s: is HAND kernel flag: %s\n"
#define D_IS_UNKNOWN_KERNEL "%s: is UNKNOWN kernel entry: %s\n"
@@ -1067,6 +1106,8 @@ gettext("failed to get special file for menu_root: %s\n")
#define D_IS_FINDROOT_CMD "%s: setting FINDROOT: %s\n"
+#define D_CMDLINE "%s: executing: %s\n"
+
#define D_IS_CHAINLOADER_CMD "%s: setting CHAINLOADER: %s\n"
#define D_ADD_FINDROOT_NUM "%s: findroot added: line#: %d: entry#: %d\n"
diff --git a/usr/src/cmd/boot/scripts/create_ramdisk.ksh b/usr/src/cmd/boot/scripts/create_ramdisk.ksh
index 51d1f130db..f7e15b4bdf 100644
--- a/usr/src/cmd/boot/scripts/create_ramdisk.ksh
+++ b/usr/src/cmd/boot/scripts/create_ramdisk.ksh
@@ -20,7 +20,7 @@
# CDDL HEADER END
#
-# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
format=ufs
@@ -263,7 +263,7 @@ function create_ufs
# do the actual copy
copy_files "$list"
- umount "$rdmnt"
+ umount -f "$rdmnt"
rmdir "$rdmnt"
if [ $ISA = sparc ] ; then
@@ -288,6 +288,10 @@ function create_ufs
else
cat "$rdfile" > "${archive}-new"
fi
+
+ if [ $? -ne 0 ] ; then
+ rm -f "${archive}-new"
+ fi
}
#
@@ -340,6 +344,8 @@ function create_isofs
# compressed, and the final compression will accomplish very
# little. To save time, we skip the gzip in this case.
#
+ mkiso_ret=0
+
if [ $ISA = i386 ] &&[ $compress = no ] && [ -x $GZIP_CMD ]
then
ksh -c "$isocmd" 2> "$errlog" | \
@@ -348,6 +354,13 @@ function create_isofs
ksh -c "$isocmd" 2> "$errlog" > "${archive}-new"
fi
+ if [ $? -ne 0 ]; then
+ cat "$errlog"
+ rm -f "${archive}-new" 2> /dev/null
+ rm -f "$errlog" 2> /dev/null
+ return
+ fi
+
dd_ret=0
if [ $ISA = sparc ] ; then
bb="$ALT_ROOT/platform/$PLATFORM/lib/fs/hsfs/bootblk"
@@ -382,7 +395,7 @@ function create_archive
# sanity check the archive before moving it into place
#
- ARCHIVE_SIZE=`ls -l "${archive}-new" | nawk '{ print $5 }'`
+ ARCHIVE_SIZE=`ls -l "${archive}-new" 2> /dev/null | nawk '{ print $5 }'`
if [ $compress = yes ] || [ $ISA = sparc ] ; then
#
# 'file' will report "English text" for uncompressed
@@ -398,7 +411,7 @@ function create_archive
LC_MESSAGES=C file "${archive}-new" | grep gzip > /dev/null
fi
- if [ $? = 1 ] && [ -x $GZIP_CMD ] || [ $ARCHIVE_SIZE -lt 5000 ]
+ if [ $? = 1 ] && [ -x $GZIP_CMD ] || [ "$ARCHIVE_SIZE" -lt 10000 ]
then
#
# Two of these functions may be run in parallel. We
diff --git a/usr/src/cmd/halt/halt.c b/usr/src/cmd/halt/halt.c
index bc78ed1155..053067fe9f 100644
--- a/usr/src/cmd/halt/halt.c
+++ b/usr/src/cmd/halt/halt.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -1366,24 +1366,25 @@ main(int argc, char *argv[])
need_check_zones = halt_zones();
}
- /* sync boot archive in the global zone */
- if (zoneid == GLOBAL_ZONEID && !nosync) {
- char *fast_argv[] = {"/sbin/bootadm", "-a", "update_all",
+ /* if we're dumping, do the archive update here and don't defer it */
+
+ if (cmd == A_DUMP && zoneid == GLOBAL_ZONEID && !nosync) {
+ char *fast_argv[] = {"/sbin/bootadm", "-ea", "update_all",
"fastboot", NULL};
- char *b_argv[] = {"/sbin/bootadm", "-a", "update_all", NULL};
+ char *b_argv[] = {"/sbin/bootadm", "-ea", "update_all", NULL};
if (fast_reboot)
r = posix_spawn(NULL, fast_argv[0], NULL, NULL,
fast_argv, NULL);
- else
+ else
r = posix_spawn(NULL, b_argv[0], NULL, NULL, b_argv,
NULL);
- /* if posix_spawn fails we emit a warning and continue rebooting */
+ /* if posix_spawn fails we emit a warning and continue */
if (r != 0)
(void) fprintf(stderr, gettext("%s: WARNING, unable to"
- "start boot archive update\n"), cmdname);
+ " start boot archive update\n"), cmdname);
else
(void) wait(NULL);
}
@@ -1441,8 +1442,41 @@ main(int argc, char *argv[])
* handle a SIGTERM and clean up properly.
*/
if (cmd != A_DUMP) {
+ int start, end, delta;
+
(void) kill(-1, SIGTERM);
- (void) sleep(5);
+ start = time(NULL);
+
+ if (zoneid == GLOBAL_ZONEID && !nosync) {
+ char *fast_argv[] = {"/sbin/bootadm", "-ea",
+ "update_all", "fastboot", NULL};
+ char *b_argv[] = {"/sbin/bootadm", "-ea", "update_all",
+ NULL};
+
+ if (fast_reboot)
+ r = posix_spawn(NULL, fast_argv[0], NULL, NULL,
+ fast_argv, NULL);
+ else
+ r = posix_spawn(NULL, b_argv[0], NULL, NULL,
+ b_argv, NULL);
+
+ /*
+ * if posix_spawn fails we emit a warning and
+ * continue
+ */
+
+ if (r != 0)
+ (void) fprintf(stderr, gettext("%s: WARNING, "
+ "unable to start boot archive update\n"),
+ cmdname);
+ else
+ (void) wait(NULL);
+ }
+
+ end = time(NULL);
+ delta = end - start;
+ if (delta < 5)
+ (void) sleep(5 - delta);
}
(void) signal(SIGINT, SIG_IGN);
diff --git a/usr/src/cmd/init/init.c b/usr/src/cmd/init/init.c
index 568f97e03b..aa15e5d5eb 100644
--- a/usr/src/cmd/init/init.c
+++ b/usr/src/cmd/init/init.c
@@ -922,7 +922,7 @@ update_boot_archive(int new_state)
if (getzoneid() != GLOBAL_ZONEID)
return;
- (void) system("/sbin/bootadm -a update_all");
+ (void) system("/sbin/bootadm -ea update_all");
}
/*
@@ -1290,8 +1290,8 @@ retry_for_proc_slot:
*/
if (op_modes == NORMAL_MODES &&
(cmd.c_action == M_OFF ||
- (cmd.c_action & (M_ONCE|M_WAIT)) &&
- cur_state == prev_state))
+ (cmd.c_action & (M_ONCE|M_WAIT)) &&
+ cur_state == prev_state))
continue;
/*
@@ -1307,7 +1307,8 @@ retry_for_proc_slot:
} else {
spawn(pp, &cmd);
- while (waitproc(pp) == FAILURE);
+ while (waitproc(pp) == FAILURE)
+ ;
(void) account(DEAD_PROCESS, pp, NULL);
pp->p_flags = 0;
}
@@ -1932,12 +1933,12 @@ init_env()
if (rflg) {
glob_envp[1] =
- malloc((unsigned)(strlen("_DVFS_RECONFIG=YES")+2));
+ malloc((unsigned)(strlen("_DVFS_RECONFIG=YES")+2));
(void) strcpy(glob_envp[1], "_DVFS_RECONFIG=YES");
++glob_envn;
} else if (bflg == 1) {
glob_envp[1] =
- malloc((unsigned)(strlen("RB_NOBOOTRC=YES")+2));
+ malloc((unsigned)(strlen("RB_NOBOOTRC=YES")+2));
(void) strcpy(glob_envp[1], "RB_NOBOOTRC=YES");
++glob_envn;
}
@@ -2109,7 +2110,7 @@ boot_init()
(char *)0, glob_envp);
console(B_TRUE,
"Command\n\"%s\"\n failed to execute. errno = %d (exec of shell failed)\n",
- cmd.c_command, errno);
+ cmd.c_command, errno);
exit(1);
} else while (waitproc(process) == FAILURE);
process->p_flags = 0;
@@ -2312,7 +2313,7 @@ siglvl(int sig, siginfo_t *sip, ucontext_t *ucp)
* data preventing the fixed command line from executing.
*/
for (process = proc_table;
- (process < proc_table + num_proc); process++) {
+ (process < proc_table + num_proc); process++) {
process->p_time = 0L;
process->p_count = 0;
}
@@ -2370,7 +2371,7 @@ childeath_single()
pid = wait(&status);
for (process = proc_table;
- (process < proc_table + num_proc); process++) {
+ (process < proc_table + num_proc); process++) {
if ((process->p_flags & (LIVING|OCCUPIED)) ==
(LIVING|OCCUPIED) && process->p_pid == pid) {
@@ -2510,7 +2511,7 @@ efork(int action, struct PROC_TABLE *process, int modes)
* for a free slot.
*/
for (process = proc_table; process->p_flags != 0 &&
- (process < proc_table + num_proc); process++)
+ (process < proc_table + num_proc); process++)
;
if (process == (proc_table + num_proc)) {
@@ -2719,7 +2720,7 @@ account(short state, struct PROC_TABLE *process, char *program)
bcopy(oldu->ut_line, u->ut_line, sizeof (u->ut_line));
bcopy(oldu->ut_host, u->ut_host, sizeof (u->ut_host));
u->ut_syslen = (tmplen = strlen(u->ut_host)) ?
- min(tmplen + 1, sizeof (u->ut_host)) : 0;
+ min(tmplen + 1, sizeof (u->ut_host)) : 0;
if (oldu->ut_type == USER_PROCESS && state == DEAD_PROCESS) {
notify_pam_dead(oldu);
@@ -2849,10 +2850,8 @@ prog_name(char *string)
* '/', thus when a ' ', '\t', '\n', or '\0' is found, "ptr" will
* point to the last element of the pathname.
*/
- for (ptr = string;
- *string != ' ' && *string != '\t' && *string != '\n' &&
- *string != '\0';
- string++) {
+ for (ptr = string; *string != ' ' && *string != '\t' &&
+ *string != '\n' && *string != '\0'; string++) {
if (*string == '/')
ptr = string+1;
}
@@ -4455,7 +4454,7 @@ startd_run(const char *cline, int tmpl, ctid_t old_ctid)
/* Put smf_options in the environment. */
glob_envp[glob_envn] =
malloc(sizeof ("SMF_OPTIONS=") - 1 +
- strlen(smf_options) + 1);
+ strlen(smf_options) + 1);
if (glob_envp[glob_envn] != NULL) {
/* LINTED */