/*-
* Copyright (c) 2003 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by David Laight.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/* needs whole LIF volume/directory and actual bootstrap by default */
bootstrap_mapsize = params->s1stat.st_size;
label = malloc(params->sectorsize);
if (label == NULL) {
warn("Failed to allocate memory for disklabel");
goto done;
}
#ifdef SUPPORT_CD9660
if (params->stage2 != NULL) {
/*
* Use contiguous blocks of SYS_BOOT in the target filesystem
* (assuming ISO9660) for a LIF directory entry used
* by BOOTROM on bootstrap.
*/
if (strcmp(params->fstype->name, "cd9660") != 0) {
warn("Target filesystem `%s' is unexpected",
params->fstype->name);
}
if (S_ISREG(params->fsstat.st_mode)) {
if (fsync(params->fsfd) == -1)
warn("Synchronising file system `%s'",
params->filesystem);
} else {
/* Don't allow real file systems for sanity */
warnx("`%s' must be a regular file to append "
"a bootstrap", params->filesystem);
goto done;
}
/* Allocate space for our block list. */
nblk = HP300_MAXBLOCKS;
blocks = malloc(sizeof(*blocks) * nblk);
if (blocks == NULL) {
warn("Allocating %lu bytes for block list",
(unsigned long)sizeof(*blocks) * nblk);
goto done;
}
/* Check the block of for the SYS_UBOOT in the target fs */
if (!params->fstype->findstage2(params, &nblk, blocks))
goto done;
if (nblk == 0) {
warnx("Secondary bootstrap `%s' is empty",
params->stage2);
goto done;
} else if (nblk > 1) {
warnx("Secondary bootstrap `%s' doesn't have "
"contiguous blocks", params->stage2);
goto done;
}
boot_offset = blocks[0].block * params->fstype->blocksize;
/* need to read only LIF volume and directories */
bootstrap_mapsize = LIF_VOLDIRSIZE;
if ((params->flags & IB_VERBOSE) != 0) {
printf("Bootstrap `%s' found at offset %lu in `%s'\n",
params->stage2, (unsigned long)boot_offset,
params->filesystem);
}
} else
#endif
if ((params->flags & IB_APPEND) != 0) {
if (!S_ISREG(params->fsstat.st_mode)) {
warnx(
"`%s' must be a regular file to append a bootstrap",
params->filesystem);
goto done;
}
boot_offset = roundup(params->fsstat.st_size, HP300_SECTSIZE);
} else {
/*
* The bootstrap can be well over 8k, and must go into a BOOT
* partition. Read NetBSD label to locate BOOT partition.
*/
if (pread(params->fsfd, label, params->sectorsize,
LABELSECTOR * params->sectorsize)
!= (ssize_t)params->sectorsize) {
warn("reading disklabel");
goto done;
}
/* And a quick validation - must be a big-endian label */
secsize = be32toh(label->d_secsize);
if (label->d_magic != htobe32(DISKMAGIC) ||
label->d_magic2 != htobe32(DISKMAGIC) ||
secsize == 0 || !powerof2(secsize) ||
be16toh(label->d_npartitions) > MAXMAXPARTITIONS) {
warnx("Invalid disklabel in %s", params->filesystem);
goto done;
}
i = be16toh(label->d_npartitions);
for (boot = label->d_partitions; ; boot++) {
if (--i < 0) {
warnx("No BOOT partition");
goto done;
}
if (boot->p_fstype == FS_BOOT)
break;
}
boot_size = be32toh(boot->p_size) * (uint64_t)secsize;
boot_offset = be32toh(boot->p_offset) * (uint64_t)secsize;
/*
* We put the entire LIF file into the BOOT partition even when
* it doesn't start at the beginning of the disk.
*
* Maybe we ought to be able to take a binary file and add
* it to the LIF filesystem.
*/
if (boot_size < (uint64_t)params->s1stat.st_size) {
warn("BOOT partition too small (%llu < %llu)",
(unsigned long long)boot_size,
(unsigned long long)params->s1stat.st_size);
goto done;
}
}
/* Write LIF volume header and directory to sectors 0 and 1 */
rv = pwrite(params->fsfd, bootstrap, LIF_VOLDIRSIZE, 0);
if (rv != LIF_VOLDIRSIZE) {
if (rv == -1)
warn("Writing `%s'", params->filesystem);
else
warnx("Writing `%s': short write", params->filesystem);
goto done;
}
#ifdef SUPPORT_CD9660
if (params->stage2 != NULL) {
/*
* Bootstrap in the target filesystem is used.
* No need to write bootstrap to BOOT partition.
*/
retval = 1;
goto done;
}
#endif
/* Write bootstrap to BOOT partition (or at EOF in IB_APPEND case) */
/* LIF header and directories, and disklabel should be preserved */
offset = (boot_offset <= LIF_PRESERVED) ? LIF_PRESERVED : 0;
size = roundup(params->s1stat.st_size, secsize) - offset;
rv = pwrite(params->fsfd, bootstrap + offset, size,
boot_offset + offset);
if (rv != size) {
if (rv == -1)
warn("Writing boot filesystem of `%s'",
params->filesystem);
else
warnx("Writing boot filesystem of `%s': short write",
params->filesystem);
goto done;
}
retval = 1;
done:
if (label != NULL)
free(label);
if (bootstrap != MAP_FAILED)
munmap(bootstrap, bootstrap_mapsize);
return retval;
}