Add mkimg, a utility for making disk images from raw partition contents.

The partitioning scheme can be one of the schemes supported by gpart.

Reviewed by:	sjg
Obtained from:	Juniper Networks, Inc.
This commit is contained in:
marcel 2014-03-29 19:03:10 +00:00
commit b01bad4f56
13 changed files with 2080 additions and 0 deletions

26
usr.bin/mkimg/Makefile Normal file
View File

@ -0,0 +1,26 @@
# $FreeBSD$
PROG= mkimg
SRCS= mkimg.c scheme.c
MAN= mkimg.1
CFLAGS+=-DSPARSE_WRITE
# List of schemes to support
SRCS+= \
apm.c \
bsd.c \
ebr.c \
gpt.c \
mbr.c \
pc98.c \
vtoc8.c
BINDIR?=/usr/bin
DPADD= ${LIBUTIL}
LDADD= -lutil
WARNS?= 6
.include <bsd.prog.mk>

119
usr.bin/mkimg/apm.c Normal file
View File

@ -0,0 +1,119 @@
/*-
* Copyright (c) 2014 Juniper Networks, Inc.
* All rights reserved.
*
* 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 AUTHOR 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 AUTHOR 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.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <sys/apm.h>
#include <sys/endian.h>
#include <sys/errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "mkimg.h"
#include "scheme.h"
static struct mkimg_alias apm_aliases[] = {
{ ALIAS_FREEBSD, ALIAS_PTR2TYPE(APM_ENT_TYPE_FREEBSD) },
{ ALIAS_FREEBSD_NANDFS, ALIAS_PTR2TYPE(APM_ENT_TYPE_FREEBSD_NANDFS) },
{ ALIAS_FREEBSD_SWAP, ALIAS_PTR2TYPE(APM_ENT_TYPE_FREEBSD_SWAP) },
{ ALIAS_FREEBSD_UFS, ALIAS_PTR2TYPE(APM_ENT_TYPE_FREEBSD_UFS) },
{ ALIAS_FREEBSD_VINUM, ALIAS_PTR2TYPE(APM_ENT_TYPE_FREEBSD_VINUM) },
{ ALIAS_FREEBSD_ZFS, ALIAS_PTR2TYPE(APM_ENT_TYPE_FREEBSD_ZFS) },
{ ALIAS_NONE, 0 }
};
static u_int
apm_metadata(u_int where)
{
u_int secs;
secs = (where == SCHEME_META_IMG_START) ? nparts + 2 : 0;
return (secs);
}
static int
apm_write(int fd __unused, lba_t imgsz __unused, void *bootcode __unused)
{
u_char *buf;
struct apm_ddr *ddr;
struct apm_ent *ent;
struct part *part;
ssize_t nbytes;
int error;
buf = calloc(nparts + 2, secsz);
if (buf == NULL)
return (ENOMEM);
ddr = (void *)buf;
be16enc(&ddr->ddr_sig, APM_DDR_SIG);
be16enc(&ddr->ddr_blksize, secsz);
be32enc(&ddr->ddr_blkcount, imgsz);
/* partition entry for the partition table itself. */
ent = (void *)(buf + secsz);
be16enc(&ent->ent_sig, APM_ENT_SIG);
be32enc(&ent->ent_pmblkcnt, nparts + 1);
be32enc(&ent->ent_start, 1);
be32enc(&ent->ent_size, nparts + 1);
strcpy(ent->ent_type, APM_ENT_TYPE_SELF);
strcpy(ent->ent_name, "Apple");
STAILQ_FOREACH(part, &partlist, link) {
ent = (void *)(buf + (part->index + 2) * secsz);
be16enc(&ent->ent_sig, APM_ENT_SIG);
be32enc(&ent->ent_pmblkcnt, nparts + 1);
be32enc(&ent->ent_start, part->block);
be32enc(&ent->ent_size, part->size);
strcpy(ent->ent_type, ALIAS_TYPE2PTR(part->type));
if (part->label != NULL)
strcpy(ent->ent_name, part->label);
}
error = mkimg_seek(fd, 0);
if (error == 0) {
nbytes = (nparts + 2) * secsz;
if (write(fd, buf, nbytes) != nbytes)
error = errno;
}
free(buf);
return (error);
}
static struct mkimg_scheme apm_scheme = {
.name = "apm",
.description = "Apple Partition Map",
.aliases = apm_aliases,
.metadata = apm_metadata,
.write = apm_write,
.nparts = 4096,
.labellen = APM_ENT_NAMELEN - 1,
.maxsecsz = 4096
};
SCHEME_DEFINE(apm_scheme);

130
usr.bin/mkimg/bsd.c Normal file
View File

@ -0,0 +1,130 @@
/*-
* Copyright (c) 2014 Juniper Networks, Inc.
* All rights reserved.
*
* 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 AUTHOR 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 AUTHOR 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.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <sys/disklabel.h>
#include <sys/endian.h>
#include <sys/errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "mkimg.h"
#include "scheme.h"
static struct mkimg_alias bsd_aliases[] = {
{ ALIAS_FREEBSD_NANDFS, ALIAS_INT2TYPE(FS_NANDFS) },
{ ALIAS_FREEBSD_SWAP, ALIAS_INT2TYPE(FS_SWAP) },
{ ALIAS_FREEBSD_UFS, ALIAS_INT2TYPE(FS_BSDFFS) },
{ ALIAS_FREEBSD_VINUM, ALIAS_INT2TYPE(FS_VINUM) },
{ ALIAS_FREEBSD_ZFS, ALIAS_INT2TYPE(FS_ZFS) },
{ ALIAS_NONE, 0 }
};
static u_int
bsd_metadata(u_int where)
{
u_int secs;
secs = BBSIZE / secsz;
return ((where == SCHEME_META_IMG_START) ? secs : 0);
}
static int
bsd_write(int fd, lba_t imgsz, void *bootcode)
{
u_char *buf, *p;
struct disklabel *d;
struct partition *dp;
struct part *part;
int error, n;
uint16_t checksum;
buf = malloc(BBSIZE);
if (buf == NULL)
return (ENOMEM);
if (bootcode != NULL) {
memcpy(buf, bootcode, BBSIZE);
memset(buf + secsz, 0, secsz);
} else
memset(buf, 0, BBSIZE);
imgsz = ncyls * nheads * nsecs;
ftruncate(fd, imgsz * secsz);
d = (void *)(buf + secsz);
le32enc(&d->d_magic, DISKMAGIC);
le32enc(&d->d_secsize, secsz);
le32enc(&d->d_nsectors, nsecs);
le32enc(&d->d_ntracks, nheads);
le32enc(&d->d_ncylinders, ncyls);
le32enc(&d->d_secpercyl, nsecs * nheads);
le32enc(&d->d_secperunit, imgsz);
le16enc(&d->d_rpm, 3600);
le32enc(&d->d_magic2, DISKMAGIC);
le16enc(&d->d_npartitions, (8 > nparts + 1) ? 8 : nparts + 1);
le32enc(&d->d_bbsize, BBSIZE);
dp = &d->d_partitions[RAW_PART];
le32enc(&dp->p_size, imgsz);
STAILQ_FOREACH(part, &partlist, link) {
n = part->index + ((part->index >= RAW_PART) ? 1 : 0);
dp = &d->d_partitions[n];
le32enc(&dp->p_size, part->size);
le32enc(&dp->p_offset, part->block);
dp->p_fstype = ALIAS_TYPE2INT(part->type);
}
dp = &d->d_partitions[nparts + 1];
checksum = 0;
for (p = buf; p < (u_char *)dp; p += 2)
checksum ^= le16dec(p);
le16enc(&d->d_checksum, checksum);
error = mkimg_seek(fd, 0);
if (error == 0) {
if (write(fd, buf, BBSIZE) != BBSIZE)
error = errno;
}
free(buf);
return (error);
}
static struct mkimg_scheme bsd_scheme = {
.name = "bsd",
.description = "BSD disk label",
.aliases = bsd_aliases,
.metadata = bsd_metadata,
.write = bsd_write,
.nparts = 19,
.bootcode = BBSIZE,
.maxsecsz = 512
};
SCHEME_DEFINE(bsd_scheme);

128
usr.bin/mkimg/ebr.c Normal file
View File

@ -0,0 +1,128 @@
/*-
* Copyright (c) 2014 Juniper Networks, Inc.
* All rights reserved.
*
* 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 AUTHOR 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 AUTHOR 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.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <sys/diskmbr.h>
#include <sys/endian.h>
#include <sys/errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "mkimg.h"
#include "scheme.h"
static struct mkimg_alias ebr_aliases[] = {
{ ALIAS_FAT32, ALIAS_INT2TYPE(DOSPTYP_FAT32) },
{ ALIAS_FREEBSD, ALIAS_INT2TYPE(DOSPTYP_386BSD) },
{ ALIAS_NONE, 0 }
};
static u_int
ebr_metadata(u_int where)
{
u_int secs;
secs = (where == SCHEME_META_PART_BEFORE) ? nsecs : 0;
return (secs);
}
static void
ebr_chs(u_char *cyl, u_char *hd, u_char *sec, uint32_t lba __unused)
{
*cyl = 0xff; /* XXX */
*hd = 0xff; /* XXX */
*sec = 0xff; /* XXX */
}
static int
ebr_write(int fd, lba_t imgsz __unused, void *bootcode __unused)
{
u_char *ebr;
struct dos_partition *dp;
struct part *part, *next;
lba_t block;
int error;
ebr = malloc(secsz);
if (ebr == NULL)
return (ENOMEM);
memset(ebr, 0, secsz);
le16enc(ebr + DOSMAGICOFFSET, DOSMAGIC);
error = 0;
STAILQ_FOREACH_SAFE(part, &partlist, link, next) {
block = part->block - nsecs;
dp = (void *)(ebr + DOSPARTOFF);
ebr_chs(&dp->dp_scyl, &dp->dp_shd, &dp->dp_ssect, nsecs);
dp->dp_typ = ALIAS_TYPE2INT(part->type);
ebr_chs(&dp->dp_ecyl, &dp->dp_ehd, &dp->dp_esect,
part->block + part->size - 1);
le32enc(&dp->dp_start, nsecs);
le32enc(&dp->dp_size, part->size);
/* Add link entry */
if (next != NULL) {
dp++;
ebr_chs(&dp->dp_scyl, &dp->dp_shd, &dp->dp_ssect,
next->block - nsecs);
dp->dp_typ = DOSPTYP_EXT;
ebr_chs(&dp->dp_ecyl, &dp->dp_ehd, &dp->dp_esect,
next->block + next->size - 1);
le32enc(&dp->dp_start, next->block - nsecs);
le32enc(&dp->dp_size, next->size + nsecs);
}
error = mkimg_seek(fd, block);
if (error == 0) {
if (write(fd, ebr, secsz) != (ssize_t)secsz)
error = errno;
}
if (error)
break;
memset(ebr + DOSPARTOFF, 0, 2 * DOSPARTSIZE);
}
free(ebr);
return (error);
}
static struct mkimg_scheme ebr_scheme = {
.name = "ebr",
.description = "Extended Boot Record",
.aliases = ebr_aliases,
.metadata = ebr_metadata,
.write = ebr_write,
.nparts = 4096,
.maxsecsz = 4096
};
SCHEME_DEFINE(ebr_scheme);

303
usr.bin/mkimg/gpt.c Normal file
View File

@ -0,0 +1,303 @@
/*-
* Copyright (c) 2014 Juniper Networks, Inc.
* All rights reserved.
*
* 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 AUTHOR 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 AUTHOR 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.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <sys/diskmbr.h>
#include <sys/endian.h>
#include <sys/errno.h>
#include <sys/gpt.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <uuid.h>
#include "mkimg.h"
#include "scheme.h"
static uuid_t gpt_uuid_efi = GPT_ENT_TYPE_EFI;
static uuid_t gpt_uuid_freebsd = GPT_ENT_TYPE_FREEBSD;
static uuid_t gpt_uuid_freebsd_boot = GPT_ENT_TYPE_FREEBSD_BOOT;
static uuid_t gpt_uuid_freebsd_nandfs = GPT_ENT_TYPE_FREEBSD_NANDFS;
static uuid_t gpt_uuid_freebsd_swap = GPT_ENT_TYPE_FREEBSD_SWAP;
static uuid_t gpt_uuid_freebsd_ufs = GPT_ENT_TYPE_FREEBSD_UFS;
static uuid_t gpt_uuid_freebsd_vinum = GPT_ENT_TYPE_FREEBSD_VINUM;
static uuid_t gpt_uuid_freebsd_zfs = GPT_ENT_TYPE_FREEBSD_ZFS;
static uuid_t gpt_uuid_mbr = GPT_ENT_TYPE_MBR;
static struct mkimg_alias gpt_aliases[] = {
{ ALIAS_EFI, ALIAS_PTR2TYPE(&gpt_uuid_efi) },
{ ALIAS_FREEBSD, ALIAS_PTR2TYPE(&gpt_uuid_freebsd) },
{ ALIAS_FREEBSD_BOOT, ALIAS_PTR2TYPE(&gpt_uuid_freebsd_boot) },
{ ALIAS_FREEBSD_NANDFS, ALIAS_PTR2TYPE(&gpt_uuid_freebsd_nandfs) },
{ ALIAS_FREEBSD_SWAP, ALIAS_PTR2TYPE(&gpt_uuid_freebsd_swap) },
{ ALIAS_FREEBSD_UFS, ALIAS_PTR2TYPE(&gpt_uuid_freebsd_ufs) },
{ ALIAS_FREEBSD_VINUM, ALIAS_PTR2TYPE(&gpt_uuid_freebsd_vinum) },
{ ALIAS_FREEBSD_ZFS, ALIAS_PTR2TYPE(&gpt_uuid_freebsd_zfs) },
{ ALIAS_MBR, ALIAS_PTR2TYPE(&gpt_uuid_mbr) },
{ ALIAS_NONE, 0 } /* Keep last! */
};
/* CRC32 code derived from work by Gary S. Brown. */
static const uint32_t crc32_tab[] = {
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
static uint32_t
crc32(const void *buf, size_t sz)
{
const uint8_t *p = (const uint8_t *)buf;
uint32_t crc = ~0U;
while (sz--)
crc = crc32_tab[(crc ^ *p++) & 0xff] ^ (crc >> 8);
return (crc ^ ~0U);
}
static u_int
gpt_tblsz(void)
{
u_int ents;
ents = secsz / sizeof(struct gpt_ent);
return ((nparts + ents - 1) / ents);
}
static u_int
gpt_metadata(u_int where)
{
u_int secs;
if (where != SCHEME_META_IMG_START && where != SCHEME_META_IMG_END)
return (0);
secs = gpt_tblsz();
secs += (where == SCHEME_META_IMG_START) ? 2 : 1;
return (secs);
}
static int
gpt_filewrite(int fd, lba_t blk, void *buf, ssize_t bufsz)
{
int error;
error = mkimg_seek(fd, blk);
if (error == 0) {
if (write(fd, buf, bufsz) != bufsz)
error = errno;
}
return (error);
}
static int
gpt_write_pmbr(int fd, lba_t blks, void *bootcode)
{
u_char *pmbr;
uint32_t secs;
int error;
secs = (blks > UINT32_MAX) ? UINT32_MAX : (uint32_t)blks;
pmbr = malloc(secsz);
if (pmbr == NULL)
return (errno);
if (bootcode != NULL) {
memcpy(pmbr, bootcode, DOSPARTOFF);
memset(pmbr + DOSPARTOFF, 0, secsz - DOSPARTOFF);
} else
memset(pmbr, 0, secsz);
pmbr[DOSPARTOFF + 2] = 2;
pmbr[DOSPARTOFF + 4] = 0xee;
pmbr[DOSPARTOFF + 5] = 0xff;
pmbr[DOSPARTOFF + 6] = 0xff;
pmbr[DOSPARTOFF + 7] = 0xff;
le32enc(pmbr + DOSPARTOFF + 8, 1);
le32enc(pmbr + DOSPARTOFF + 12, secs);
le16enc(pmbr + DOSMAGICOFFSET, DOSMAGIC);
error = gpt_filewrite(fd, 0, pmbr, secsz);
free(pmbr);
return (error);
}
static struct gpt_ent *
gpt_mktbl(u_int tblsz)
{
uuid_t uuid;
struct gpt_ent *tbl, *ent;
struct part *part;
int c, idx;
tbl = calloc(tblsz, secsz);
if (tbl == NULL)
return (NULL);
STAILQ_FOREACH(part, &partlist, link) {
ent = tbl + part->index;
uuid_enc_le(&ent->ent_type, ALIAS_TYPE2PTR(part->type));
uuidgen(&uuid, 1);
uuid_enc_le(&ent->ent_uuid, &uuid);
le64enc(&ent->ent_lba_start, part->block);
le64enc(&ent->ent_lba_end, part->block + part->size - 1);
if (part->label != NULL) {
idx = 0;
while ((c = part->label[idx]) != '\0') {
le16enc(ent->ent_name + idx, c);
idx++;
}
}
}
return (tbl);
}
static int
gpt_write_hdr(int fd, struct gpt_hdr *hdr, uint64_t self, uint64_t alt,
uint64_t tbl)
{
uint32_t crc;
le64enc(&hdr->hdr_lba_self, self);
le64enc(&hdr->hdr_lba_alt, alt);
le64enc(&hdr->hdr_lba_table, tbl);
hdr->hdr_crc_self = 0;
crc = crc32(hdr, offsetof(struct gpt_hdr, padding));
le64enc(&hdr->hdr_crc_self, crc);
return (gpt_filewrite(fd, self, hdr, secsz));
}
static int
gpt_write(int fd, lba_t imgsz, void *bootcode)
{
uuid_t uuid;
struct gpt_ent *tbl;
struct gpt_hdr *hdr;
uint32_t crc;
u_int tblsz;
int error;
/* PMBR */
error = gpt_write_pmbr(fd, imgsz, bootcode);
if (error)
return (error);
/* GPT table(s) */
tblsz = gpt_tblsz();
tbl = gpt_mktbl(tblsz);
if (tbl == NULL)
return (errno);
error = gpt_filewrite(fd, 2, tbl, tblsz * secsz);
if (error)
goto out;
error = gpt_filewrite(fd, imgsz - (tblsz + 1), tbl, tblsz * secsz);
if (error)
goto out;
/* GPT header(s) */
hdr = malloc(secsz);
if (hdr == NULL) {
error = errno;
goto out;
}
memset(hdr, 0, secsz);
memcpy(hdr->hdr_sig, GPT_HDR_SIG, sizeof(hdr->hdr_sig));
le32enc(&hdr->hdr_revision, GPT_HDR_REVISION);
le32enc(&hdr->hdr_size, offsetof(struct gpt_hdr, padding));
le64enc(&hdr->hdr_lba_start, 2 + tblsz);
le64enc(&hdr->hdr_lba_end, imgsz - tblsz - 2);
uuidgen(&uuid, 1);
uuid_enc_le(&hdr->hdr_uuid, &uuid);
le32enc(&hdr->hdr_entries, nparts);
le32enc(&hdr->hdr_entsz, sizeof(struct gpt_ent));
crc = crc32(tbl, nparts * sizeof(struct gpt_ent));
le32enc(&hdr->hdr_crc_table, crc);
error = gpt_write_hdr(fd, hdr, 1, imgsz - 1, 2);
if (!error)
error = gpt_write_hdr(fd, hdr, imgsz - 1, 1, imgsz - tblsz - 1);
free(hdr);
out:
free(tbl);
return (error);
}
static struct mkimg_scheme gpt_scheme = {
.name = "gpt",
.description = "GUID Partition Table",
.aliases = gpt_aliases,
.metadata = gpt_metadata,
.write = gpt_write,
.nparts = 4096,
.labellen = 36,
.bootcode = 512,
.maxsecsz = 4096
};
SCHEME_DEFINE(gpt_scheme);

115
usr.bin/mkimg/mbr.c Normal file
View File

@ -0,0 +1,115 @@
/*-
* Copyright (c) 2014 Juniper Networks, Inc.
* All rights reserved.
*
* 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 AUTHOR 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 AUTHOR 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.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <sys/diskmbr.h>
#include <sys/endian.h>
#include <sys/errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "mkimg.h"
#include "scheme.h"
static struct mkimg_alias mbr_aliases[] = {
{ ALIAS_EBR, ALIAS_INT2TYPE(DOSPTYP_EXT) },
{ ALIAS_FAT32, ALIAS_INT2TYPE(DOSPTYP_FAT32) },
{ ALIAS_FREEBSD, ALIAS_INT2TYPE(DOSPTYP_386BSD) },
{ ALIAS_NONE, 0 } /* Keep last! */
};
static u_int
mbr_metadata(u_int where)
{
u_int secs;
secs = (where == SCHEME_META_IMG_START) ? nsecs : 0;
return (secs);
}
static void
mbr_chs(u_char *cyl, u_char *hd, u_char *sec, uint32_t lba __unused)
{
*cyl = 0xff; /* XXX */
*hd = 0xff; /* XXX */
*sec = 0xff; /* XXX */
}
static int
mbr_write(int fd, lba_t imgsz __unused, void *bootcode)
{
u_char *mbr;
struct dos_partition *dpbase, *dp;
struct part *part;
int error;
mbr = malloc(secsz);
if (mbr == NULL)
return (ENOMEM);
if (bootcode != NULL) {
memcpy(mbr, bootcode, DOSPARTOFF);
memset(mbr + DOSPARTOFF, 0, secsz - DOSPARTOFF);
} else
memset(mbr, 0, secsz);
le16enc(mbr + DOSMAGICOFFSET, DOSMAGIC);
dpbase = (void *)(mbr + DOSPARTOFF);
STAILQ_FOREACH(part, &partlist, link) {
dp = dpbase + part->index;
dp->dp_flag = (part->index == 0 && bootcode != NULL) ? 0x80 : 0;
mbr_chs(&dp->dp_scyl, &dp->dp_shd, &dp->dp_ssect,
part->block);
dp->dp_typ = ALIAS_TYPE2INT(part->type);
mbr_chs(&dp->dp_ecyl, &dp->dp_ehd, &dp->dp_esect,
part->block + part->size - 1);
le32enc(&dp->dp_start, part->block);
le32enc(&dp->dp_size, part->size);
}
error = mkimg_seek(fd, 0);
if (error == 0) {
if (write(fd, mbr, secsz) != (ssize_t)secsz)
error = errno;
}
free(mbr);
return (error);
}
static struct mkimg_scheme mbr_scheme = {
.name = "mbr",
.description = "Master Boot Record",
.aliases = mbr_aliases,
.metadata = mbr_metadata,
.write = mbr_write,
.bootcode = 512,
.nparts = NDOSPART,
.maxsecsz = 4096
};
SCHEME_DEFINE(mbr_scheme);

162
usr.bin/mkimg/mkimg.1 Normal file
View File

@ -0,0 +1,162 @@
.\" Copyright (c) 2013, 2014 Juniper Networks, Inc.
.\" All rights reserved.
.\"
.\" 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 AUTHOR ``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 AUTHOR 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.
.\"
.\" $FreeBSD$
.\"
.Dd March 27, 2014
.Dt MKIMG 1
.Os
.Sh NAME
.Nm mkimg
.Nd "utility to make a disk image"
.Sh SYNOPSIS
.Nm
.Op Fl H Ar heads
.Op Fl P Ar blksz
.Op Fl S Ar secsz
.Op Fl T Ar tracksz
.Op Fl b Ar bootcode
.Op Fl o Ar outfile
.Op Fl v
.Fl s Ar scheme
.Fl p Ar partition
.Op Fl p Ar partition ...
.Sh DESCRIPTION
The
.Nm
utility creates a disk image from the raw partition contents specified with
the
.Ar partition
argument(s) and using the partitioning scheme specified with the
.Ar scheme
argument.
The disk image is written to
.Ar stdout
by default or the file specified with the
.Ar outfile
argument.
.Pp
The disk image can be made bootable by specifying the scheme-specific boot
block contents with the
.Ar bootcode
argument and,
depending on the scheme,
with a boot partition.
The contents of such a boot partition is provided like any other partition
and the
.Nm
utility does not treat it any differently from other partitions.
.Pp
Some partitioning schemes need a disk geometry and for those the
.Nm
utility accepts the
.Ar tracksz
and
.Ar heads
arguments, specifying the number of sectors per track and the number of
heads per cylinder (resp.)
.Pp
Both the logical and physical sector size can be specified and for that the
.Nm
utility
accepts the
.Ar secsz
and
.Ar blksz
arguments.
The
.Ar secsz
argument is used to specify the logical sector size.
This is the sector size reported by a disk when queried for its capacity.
Modern disks use a larger sector size internally,
referred to as block size by the
.Nm
utility and this can be specified by the
.Ar blksz
argument.
The
.Nm
utility will use the (physical) block size to determine the start of
partitions and to round the size of the disk image.
.Pp
The
.Op Fl v
option increases the level of output that the
.Nm
utility prints.
.Pp
For a complete list of supported partitioning schemes or for a detailed
description of how to specify partitions, run the
.Nm
utility without any arguments.
.Sh EXAMPLES
To create a bootable disk image that is partitioned using the GPT scheme and
containing a root file system that was previously created using
.Xr makefs
and also containing a swap partition, run the
.Nm
utility as follows:
.Dl % mkimg -s gpt -b /boot/pmbr -p freebsd-boot:=/boot/gptboot \
-p freebsd-ufs:=root-file-system.ufs -p freebsd-swap::1G \
-o gpt.img
.Pp
A nested partitioning scheme is created by running the
.Nm
utility twice.
The output of the first will be fed as the contents of a partition to the
second.
This can be done using a temporary file, like so:
.Dl % mkimg -s bsd -b /boot/boot -p freebsd-ufs:=root-file-system.ufs \
-p freebsd-swap::1G -o /tmp/bsd.img
.Dl % mkimg -s mbr -b /boot/mbr -p freebsd:=/tmp/bsd.img -o mbr-bsd.img
.Pp
Alternatively, the
.Nm
utility can be run in a cascaded fashion, whereby the output of the
first is fed directly into the second.
To do this, run the
.Nm
utility as follows:
.Dl % mkimg -s mbr -b /boot/mbr -p freebsd:-'mkimg -s bsd -b /boot/boot \
-p freebsd-ufs:=root-file-system.ufs -p freebsd-swap::1G' -o mbr-bsd.img
.Pp
For partitioning schemes that feature partition labels, the
.Nm
utility supports assigning labels to the partitions specified.
In the following example the file system partition is labeled as 'backup':
.Dl % mkimg -s gpt -p freebsd-ufs/backup:=file-system.ufs -o gpt.img
.Sh SEE ALSO
.Xr gpart 8
.Xr makefs 8
.Xr mdconfig 8
.Xr newfs 8
.Sh HISTORY
The
.Nm
utility appeared in
.Fx 11.0
.Sh AUTHORS
The
.Nm
utility and manpage were written by Marcel Moolenaar <marcelm@juniper.net>

501
usr.bin/mkimg/mkimg.c Normal file
View File

@ -0,0 +1,501 @@
/*-
* Copyright (c) 2013,2014 Juniper Networks, Inc.
* All rights reserved.
*
* 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 AUTHOR 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 AUTHOR 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.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/linker_set.h>
#include <sys/queue.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#include <err.h>
#include <fcntl.h>
#include <libutil.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sysexits.h>
#include <unistd.h>
#include "mkimg.h"
#include "scheme.h"
#if !defined(SPARSE_WRITE)
#define sparse_write write
#endif
#define BUFFER_SIZE (1024*1024)
struct partlisthead partlist = STAILQ_HEAD_INITIALIZER(partlist);
u_int nparts = 0;
u_int verbose;
u_int ncyls = 0;
u_int nheads = 1;
u_int nsecs = 1;
u_int secsz = 512;
u_int blksz = 0;
static int bcfd = -1;
static int outfd = 0;
static int tmpfd = -1;
static char tmpfname[] = "/tmp/mkimg-XXXXXX";
static void
cleanup(void)
{
if (tmpfd != -1)
close(tmpfd);
unlink(tmpfname);
}
static void
usage(const char *why)
{
struct mkimg_scheme *s, **iter;
warnx("error: %s", why);
fprintf(stderr, "\nusage: %s <options>\n", getprogname());
fprintf(stderr, " options:\n");
fprintf(stderr, "\t-b <file>\t- file containing boot code\n");
fprintf(stderr, "\t-o <file>\t- file to write image into\n");
fprintf(stderr, "\t-p <partition>\n");
fprintf(stderr, "\t-s <scheme>\n");
fprintf(stderr, "\t-H <num>\t- number of heads to simulate\n");
fprintf(stderr, "\t-P <num>\t- physical sector size\n");
fprintf(stderr, "\t-S <num>\t- logical sector size\n");
fprintf(stderr, "\t-T <num>\t- number of tracks to simulate\n");
fprintf(stderr, " schemes:\n");
SET_FOREACH(iter, schemes) {
s = *iter;
fprintf(stderr, "\t%s\t- %s\n", s->name, s->description);
}
fprintf(stderr, " partition specification:\n");
fprintf(stderr, "\t<t>[/<l>]::<size>\t- empty partition of given "
"size\n");
fprintf(stderr, "\t<t>[/<l>]:=<file>\t- partition content and size "
"are determined\n\t\t\t\t by the named file\n");
fprintf(stderr, "\t<t>[/<l>]:-<cmd>\t- partition content and size "
"are taken from\n\t\t\t\t the output of the command to run\n");
fprintf(stderr, "\t where:\n");
fprintf(stderr, "\t\t<t>\t- scheme neutral partition type\n");
fprintf(stderr, "\t\t<l>\t- optional scheme-dependent partition "
"label\n");
exit(EX_USAGE);
}
static int
parse_number(u_int *valp, u_int min, u_int max, const char *arg)
{
uint64_t val;
if (expand_number(arg, &val) == -1)
return (errno);
if (val > UINT_MAX || val < (uint64_t)min || val > (uint64_t)max)
return (EINVAL);
*valp = (u_int)val;
return (0);
}
static int
pwr_of_two(u_int nr)
{
return (((nr & (nr - 1)) == 0) ? 1 : 0);
}
/*
* A partition specification has the following format:
* <type> ':' <kind> <contents>
* where:
* type the partition type alias
* kind the interpretation of the contents specification
* ':' contents holds the size of an empty partition
* '=' contents holds the name of a file to read
* '-' contents holds a command to run; the output of
* which is the contents of the partition.
* contents the specification of a partition's contents
*/
static int
parse_part(const char *spec)
{
struct part *part;
char *sep;
size_t len;
int error;
part = calloc(1, sizeof(struct part));
if (part == NULL)
return (ENOMEM);
sep = strchr(spec, ':');
if (sep == NULL) {
error = EINVAL;
goto errout;
}
len = sep - spec + 1;
if (len < 2) {
error = EINVAL;
goto errout;
}
part->alias = malloc(len);
if (part->alias == NULL) {
error = ENOMEM;
goto errout;
}
strlcpy(part->alias, spec, len);
spec = sep + 1;
switch (*spec) {
case ':':
part->kind = PART_KIND_SIZE;
break;
case '=':
part->kind = PART_KIND_FILE;
break;
case '-':
part->kind = PART_KIND_PIPE;
break;
default:
error = EINVAL;
goto errout;
}
spec++;
part->contents = strdup(spec);
if (part->contents == NULL) {
error = ENOMEM;
goto errout;
}
spec = part->alias;
sep = strchr(spec, '/');
if (sep != NULL) {
*sep++ = '\0';
if (strlen(part->alias) == 0 || strlen(sep) == 0) {
error = EINVAL;
goto errout;
}
part->label = strdup(sep);
if (part->label == NULL) {
error = ENOMEM;
goto errout;
}
}
part->index = nparts;
STAILQ_INSERT_TAIL(&partlist, part, link);
nparts++;
return (0);
errout:
if (part->alias != NULL)
free(part->alias);
free(part);
return (error);
}
#if defined(SPARSE_WRITE)
static ssize_t
sparse_write(int fd, const char *buf, size_t sz)
{
const char *p;
off_t ofs;
size_t len;
ssize_t wr, wrsz;
wrsz = 0;
p = memchr(buf, 0, sz);
while (sz > 0) {
len = (p != NULL) ? (size_t)(p - buf) : sz;
if (len > 0) {
len = (len + secsz - 1) & ~(secsz - 1);
if (len > sz)
len = sz;
wr = write(fd, buf, len);
if (wr < 0)
return (-1);
} else {
while (len < sz && *p++ == '\0')
len++;
if (len < sz)
len &= ~(secsz - 1);
if (len == 0)
continue;
ofs = lseek(fd, len, SEEK_CUR);
if (ofs < 0)
return (-1);
wr = len;
}
buf += wr;
sz -= wr;
wrsz += wr;
p = memchr(buf, 0, sz);
}
return (wrsz);
}
#endif /* SPARSE_WRITE */
static int
fdcopy(int src, int dst, uint64_t *count)
{
char *buffer;
off_t ofs;
ssize_t rdsz, wrsz;
/* A return value of -1 means that we can't write a sparse file. */
ofs = lseek(dst, 0L, SEEK_CUR);
if (count != NULL)
*count = 0;
buffer = malloc(BUFFER_SIZE);
if (buffer == NULL)
return (errno);
while (1) {
rdsz = read(src, buffer, BUFFER_SIZE);
if (rdsz <= 0) {
free(buffer);
return ((rdsz < 0) ? errno : 0);
}
if (count != NULL)
*count += rdsz;
wrsz = (ofs == -1) ?
write(dst, buffer, rdsz) :
sparse_write(dst, buffer, rdsz);
if (wrsz < 0)
break;
}
free(buffer);
return (errno);
}
int
mkimg_seek(int fd, lba_t blk)
{
off_t off;
off = blk * secsz;
if (lseek(fd, off, SEEK_SET) != off)
return (errno);
return (0);
}
static void
mkimg(int bfd)
{
FILE *fp;
struct part *part;
lba_t block;
off_t bytesize;
int error, fd;
error = scheme_bootcode(bfd);
if (error)
errc(EX_DATAERR, error, "boot code");
/* First check partition information */
STAILQ_FOREACH(part, &partlist, link) {
error = scheme_check_part(part);
if (error)
errc(EX_DATAERR, error, "partition %d", part->index+1);
}
block = scheme_metadata(SCHEME_META_IMG_START, 0);
STAILQ_FOREACH(part, &partlist, link) {
block = scheme_metadata(SCHEME_META_PART_BEFORE, block);
if (verbose)
fprintf(stderr, "partition %d: starting block %llu "
"... ", part->index + 1, (long long)block);
part->block = block;
error = mkimg_seek(tmpfd, block);
switch (part->kind) {
case PART_KIND_SIZE:
if (expand_number(part->contents, &bytesize) == -1)
error = errno;
break;
case PART_KIND_FILE:
fd = open(part->contents, O_RDONLY, 0);
if (fd != -1) {
error = fdcopy(fd, tmpfd, &bytesize);
close(fd);
} else
error = errno;
break;
case PART_KIND_PIPE:
fp = popen(part->contents, "r");
if (fp != NULL) {
error = fdcopy(fileno(fp), tmpfd, &bytesize);
pclose(fp);
} else
error = errno;
break;
}
if (error)
errc(EX_IOERR, error, "partition %d", part->index + 1);
part->size = (bytesize + secsz - 1) / secsz;
if (verbose) {
bytesize = part->size * secsz;
fprintf(stderr, "size %llu bytes (%llu blocks)\n",
(long long)bytesize, (long long)part->size);
}
block = scheme_metadata(SCHEME_META_PART_AFTER,
part->block + part->size);
}
block = scheme_metadata(SCHEME_META_IMG_END, block);
error = (scheme_write(tmpfd, block));
}
int
main(int argc, char *argv[])
{
int c, error;
while ((c = getopt(argc, argv, "b:o:p:s:vH:P:S:T:")) != -1) {
switch (c) {
case 'b': /* BOOT CODE */
if (bcfd != -1)
usage("multiple bootcode given");
bcfd = open(optarg, O_RDONLY, 0);
if (bcfd == -1)
err(EX_UNAVAILABLE, "%s", optarg);
break;
case 'o': /* OUTPUT FILE */
if (outfd != 0)
usage("multiple output files given");
outfd = open(optarg, O_WRONLY | O_CREAT | O_TRUNC,
S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH);
if (outfd == -1)
err(EX_CANTCREAT, "%s", optarg);
break;
case 'p': /* PARTITION */
error = parse_part(optarg);
if (error)
errc(EX_DATAERR, error, "partition");
break;
case 's': /* SCHEME */
if (scheme_selected() != NULL)
usage("multiple schemes given");
error = scheme_select(optarg);
if (error)
errc(EX_DATAERR, error, "scheme");
break;
case 'v':
verbose++;
break;
case 'H': /* GEOMETRY: HEADS */
error = parse_number(&nheads, 1, 255, optarg);
if (error)
errc(EX_DATAERR, error, "number of heads");
break;
case 'P': /* GEOMETRY: PHYSICAL SECTOR SIZE */
error = parse_number(&blksz, 512, INT_MAX+1U, optarg);
if (error == 0 && !pwr_of_two(blksz))
error = EINVAL;
if (error)
errc(EX_DATAERR, error, "physical sector size");
break;
case 'S': /* GEOMETRY: LOGICAL SECTOR SIZE */
error = parse_number(&secsz, 512, INT_MAX+1U, optarg);
if (error == 0 && !pwr_of_two(secsz))
error = EINVAL;
if (error)
errc(EX_DATAERR, error, "logical sector size");
break;
case 'T': /* GEOMETRY: TRACK SIZE */
error = parse_number(&nsecs, 1, 63, optarg);
if (error)
errc(EX_DATAERR, error, "track size");
break;
default:
usage("unknown option");
}
}
if (argc > optind)
usage("trailing arguments");
if (scheme_selected() == NULL)
usage("no scheme");
if (nparts == 0)
usage("no partitions");
if (secsz > blksz) {
if (blksz != 0)
errx(EX_DATAERR, "the physical block size cannot "
"be smaller than the sector size");
blksz = secsz;
}
if (secsz > scheme_max_secsz())
errx(EX_DATAERR, "maximum sector size supported is %u; "
"size specified is %u", scheme_max_secsz(), secsz);
if (nparts > scheme_max_parts())
errx(EX_DATAERR, "%d partitions supported; %d given",
scheme_max_parts(), nparts);
if (outfd == 0) {
if (atexit(cleanup) == -1)
err(EX_OSERR, "cannot register cleanup function");
outfd = 1;
tmpfd = mkstemp(tmpfname);
if (tmpfd == -1)
err(EX_OSERR, "cannot create temporary file");
} else
tmpfd = outfd;
if (verbose) {
fprintf(stderr, "Logical sector size: %u\n", secsz);
fprintf(stderr, "Physical block size: %u\n", blksz);
fprintf(stderr, "Sectors per track: %u\n", nsecs);
fprintf(stderr, "Number of heads: %u\n", nheads);
}
mkimg(bcfd);
if (verbose)
fprintf(stderr, "Number of cylinders: %u\n", ncyls);
if (tmpfd != outfd) {
error = mkimg_seek(tmpfd, 0);
if (error == 0)
error = fdcopy(tmpfd, outfd, NULL);
if (error)
errc(EX_IOERR, error, "writing to stdout");
}
return (0);
}

72
usr.bin/mkimg/mkimg.h Normal file
View File

@ -0,0 +1,72 @@
/*-
* Copyright (c) 2014 Juniper Networks, Inc.
* All rights reserved.
*
* 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 AUTHOR 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 AUTHOR 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.
*
* $FreeBSD$
*/
#ifndef _MKIMG_MKIMG_H_
#define _MKIMG_MKIMG_H_
#include <sys/queue.h>
typedef int64_t lba_t;
struct part {
STAILQ_ENTRY(part) link;
char *alias; /* Partition type alias. */
char *contents; /* Contents/size specification. */
u_int kind; /* Content kind. */
#define PART_UNDEF 0
#define PART_KIND_FILE 1
#define PART_KIND_PIPE 2
#define PART_KIND_SIZE 3
u_int index; /* Partition index (0-based). */
uintptr_t type; /* Scheme-specific partition type. */
lba_t block; /* Block-offset of partition in image. */
lba_t size; /* Size in blocks of partition. */
char *label; /* Partition label. */
};
extern STAILQ_HEAD(partlisthead, part) partlist;
extern u_int nparts;
extern u_int verbose;
extern u_int ncyls;
extern u_int nheads;
extern u_int nsecs;
extern u_int secsz; /* Logical block size. */
extern u_int blksz; /* Physical block size. */
static inline lba_t
round_block(lba_t n)
{
lba_t b = blksz / secsz;
return ((n + b - 1) & ~(b - 1));
}
int mkimg_seek(int fd, lba_t blk);
#endif /* _MKIMG_MKIMG_H_ */

117
usr.bin/mkimg/pc98.c Normal file
View File

@ -0,0 +1,117 @@
/*-
* Copyright (c) 2014 Juniper Networks, Inc.
* All rights reserved.
*
* 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 AUTHOR 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 AUTHOR 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.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <sys/diskpc98.h>
#include <sys/endian.h>
#include <sys/errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "mkimg.h"
#include "scheme.h"
#define PC98_BOOTCODESZ 8192
static struct mkimg_alias pc98_aliases[] = {
{ ALIAS_FREEBSD, ALIAS_INT2TYPE(PC98_PTYP_386BSD) },
{ ALIAS_NONE, 0 }
};
static u_int
pc98_metadata(u_int where)
{
u_int secs;
secs = PC98_BOOTCODESZ / secsz;
return ((where == SCHEME_META_IMG_START) ? secs : 0);
}
static void
pc98_chs(u_short *cyl, u_char *hd, u_char *sec, uint32_t lba __unused)
{
*cyl = 0xffff; /* XXX */
*hd = 0xff; /* XXX */
*sec = 0xff; /* XXX */
}
static int
pc98_write(int fd, lba_t imgsz __unused, void *bootcode)
{
struct part *part;
struct pc98_partition *dpbase, *dp;
u_char *buf;
int error, ptyp;
buf = malloc(PC98_BOOTCODESZ);
if (buf == NULL)
return (ENOMEM);
if (bootcode != NULL) {
memcpy(buf, bootcode, PC98_BOOTCODESZ);
memset(buf + secsz, 0, secsz);
} else
memset(buf, 0, PC98_BOOTCODESZ);
le16enc(buf + PC98_MAGICOFS, PC98_MAGIC);
dpbase = (void *)(buf + secsz);
STAILQ_FOREACH(part, &partlist, link) {
dp = dpbase + part->index;
ptyp = ALIAS_TYPE2INT(part->type);
dp->dp_mid = ptyp;
dp->dp_sid = ptyp >> 8;
pc98_chs(&dp->dp_scyl, &dp->dp_shd, &dp->dp_ssect,
part->block);
pc98_chs(&dp->dp_scyl, &dp->dp_shd, &dp->dp_ssect,
part->block + part->size - 1);
if (part->label != NULL)
memcpy(dp->dp_name, part->label, strlen(part->label));
}
error = mkimg_seek(fd, 0);
if (error == 0) {
if (write(fd, buf, PC98_BOOTCODESZ) != PC98_BOOTCODESZ)
error = errno;
}
free(buf);
return (error);
}
static struct mkimg_scheme pc98_scheme = {
.name = "pc98",
.description = "PC-9800 disk partitions",
.aliases = pc98_aliases,
.metadata = pc98_metadata,
.write = pc98_write,
.bootcode = PC98_BOOTCODESZ,
.labellen = 16,
.nparts = PC98_NPARTS,
.maxsecsz = 512
};
SCHEME_DEFINE(pc98_scheme);

197
usr.bin/mkimg/scheme.c Normal file
View File

@ -0,0 +1,197 @@
/*-
* Copyright (c) 2013,2014 Juniper Networks, Inc.
* All rights reserved.
*
* 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 AUTHOR 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 AUTHOR 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.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <sys/linker_set.h>
#include <sys/queue.h>
#include <sys/stat.h>
#include <err.h>
#include <errno.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "mkimg.h"
#include "scheme.h"
static struct {
const char *name;
enum alias alias;
} scheme_alias[] = {
{ "ebr", ALIAS_EBR },
{ "efi", ALIAS_EFI },
{ "fat32", ALIAS_FAT32 },
{ "freebsd", ALIAS_FREEBSD },
{ "freebsd-boot", ALIAS_FREEBSD_BOOT },
{ "freebsd-nandfs", ALIAS_FREEBSD_NANDFS },
{ "freebsd-swap", ALIAS_FREEBSD_SWAP },
{ "freebsd-ufs", ALIAS_FREEBSD_UFS },
{ "freebsd-vinum", ALIAS_FREEBSD_VINUM },
{ "freebsd-zfs", ALIAS_FREEBSD_ZFS },
{ "mbr", ALIAS_MBR },
{ NULL, ALIAS_NONE } /* Keep last! */
};
static struct mkimg_scheme *scheme;
static void *bootcode;
static enum alias
scheme_parse_alias(const char *name)
{
u_int idx;
idx = 0;
while (scheme_alias[idx].name != NULL) {
if (strcasecmp(scheme_alias[idx].name, name) == 0)
return (scheme_alias[idx].alias);
idx++;
}
return (ALIAS_NONE);
}
int
scheme_select(const char *spec)
{
struct mkimg_scheme *s, **iter;
SET_FOREACH(iter, schemes) {
s = *iter;
if (strcasecmp(spec, s->name) == 0) {
scheme = s;
return (0);
}
}
return (EINVAL);
}
struct mkimg_scheme *
scheme_selected(void)
{
return (scheme);
}
int
scheme_bootcode(int fd)
{
struct stat sb;
int error;
if (fd == -1)
return (0);
if (scheme->bootcode == 0)
return (ENXIO);
error = fstat(fd, &sb);
if (error)
return (error);
if (sb.st_size > scheme->bootcode)
return (EFBIG);
bootcode = malloc(scheme->bootcode);
if (bootcode == NULL)
return (ENOMEM);
memset(bootcode, 0, scheme->bootcode);
if (read(fd, bootcode, sb.st_size) != sb.st_size) {
free(bootcode);
bootcode = NULL;
return (errno);
}
return (0);
}
int
scheme_check_part(struct part *p)
{
struct mkimg_alias *iter;
enum alias alias;
/* Check the partition type alias */
alias = scheme_parse_alias(p->alias);
if (alias == ALIAS_NONE)
return (EINVAL);
iter = scheme->aliases;
while (iter->alias != ALIAS_NONE) {
if (alias == iter->alias)
break;
iter++;
}
if (iter->alias == ALIAS_NONE)
return (EINVAL);
p->type = iter->type;
/* Validate the optional label. */
if (p->label != NULL) {
if (strlen(p->label) > scheme->labellen)
return (EINVAL);
}
return (0);
}
u_int
scheme_max_parts(void)
{
return (scheme->nparts);
}
u_int
scheme_max_secsz(void)
{
return (scheme->maxsecsz);
}
lba_t
scheme_metadata(u_int where, lba_t start)
{
lba_t secs;
secs = scheme->metadata(where);
return (round_block(start + secs));
}
int
scheme_write(int fd, lba_t end)
{
u_int cylsz;
int error;
cylsz = nsecs * nheads;
ncyls = (end + cylsz - 1) / cylsz;
if (ftruncate(fd, end * secsz) == -1)
return (errno);
error = scheme->write(fd, end, bootcode);
return (error);
}

90
usr.bin/mkimg/scheme.h Normal file
View File

@ -0,0 +1,90 @@
/*-
* Copyright (c) 2013,2014 Juniper Networks, Inc.
* All rights reserved.
*
* 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 AUTHOR 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 AUTHOR 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.
*
* $FreeBSD$
*/
#ifndef _MKIMG_SCHEME_H_
#define _MKIMG_SCHEME_H_
#include <sys/linker_set.h>
enum alias {
ALIAS_NONE, /* Keep first! */
/* start */
ALIAS_EBR,
ALIAS_EFI,
ALIAS_FAT32,
ALIAS_FREEBSD,
ALIAS_FREEBSD_BOOT,
ALIAS_FREEBSD_NANDFS,
ALIAS_FREEBSD_SWAP,
ALIAS_FREEBSD_UFS,
ALIAS_FREEBSD_VINUM,
ALIAS_FREEBSD_ZFS,
ALIAS_MBR,
/* end */
ALIAS_COUNT /* Keep last! */
};
struct mkimg_alias {
u_int alias;
uintptr_t type;
#define ALIAS_PTR2TYPE(p) (uintptr_t)(p)
#define ALIAS_INT2TYPE(i) (i)
#define ALIAS_TYPE2PTR(p) (void *)(p)
#define ALIAS_TYPE2INT(i) (i)
};
struct mkimg_scheme {
const char *name;
const char *description;
struct mkimg_alias *aliases;
u_int (*metadata)(u_int);
#define SCHEME_META_IMG_START 1
#define SCHEME_META_IMG_END 2
#define SCHEME_META_PART_BEFORE 3
#define SCHEME_META_PART_AFTER 4
int (*write)(int, lba_t, void *);
u_int nparts;
u_int labellen;
u_int bootcode;
u_int maxsecsz;
};
SET_DECLARE(schemes, struct mkimg_scheme);
#define SCHEME_DEFINE(nm) DATA_SET(schemes, nm)
int scheme_select(const char *);
struct mkimg_scheme *scheme_selected(void);
int scheme_bootcode(int fd);
int scheme_check_part(struct part *);
u_int scheme_max_parts(void);
u_int scheme_max_secsz(void);
lba_t scheme_metadata(u_int, lba_t);
int scheme_write(int, lba_t);
#endif /* _MKIMG_SCHEME_H_ */

120
usr.bin/mkimg/vtoc8.c Normal file
View File

@ -0,0 +1,120 @@
/*-
* Copyright (c) 2014 Juniper Networks, Inc.
* All rights reserved.
*
* 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 AUTHOR 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 AUTHOR 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.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <sys/endian.h>
#include <sys/errno.h>
#include <sys/vtoc.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "mkimg.h"
#include "scheme.h"
static struct mkimg_alias vtoc8_aliases[] = {
{ ALIAS_FREEBSD_NANDFS, ALIAS_INT2TYPE(VTOC_TAG_FREEBSD_NANDFS) },
{ ALIAS_FREEBSD_SWAP, ALIAS_INT2TYPE(VTOC_TAG_FREEBSD_SWAP) },
{ ALIAS_FREEBSD_UFS, ALIAS_INT2TYPE(VTOC_TAG_FREEBSD_UFS) },
{ ALIAS_FREEBSD_VINUM, ALIAS_INT2TYPE(VTOC_TAG_FREEBSD_VINUM) },
{ ALIAS_FREEBSD_ZFS, ALIAS_INT2TYPE(VTOC_TAG_FREEBSD_NANDFS) },
{ ALIAS_NONE, 0 }
};
static u_int
vtoc8_metadata(u_int where)
{
u_int secs;
secs = (where == SCHEME_META_IMG_START) ? nsecs * nheads : 0;
return (secs);
}
static int
vtoc8_write(int fd, lba_t imgsz, void *bootcode __unused)
{
struct vtoc8 vtoc8;
struct part *part;
u_char *p;
int error, n;
uint16_t ofs, sum;
imgsz = ncyls * nheads * nsecs;
memset(&vtoc8, 0, sizeof(vtoc8));
sprintf(vtoc8.ascii, "FreeBSD%lldM",
(long long)(imgsz * secsz / 1048576));
be32enc(&vtoc8.version, VTOC_VERSION);
be16enc(&vtoc8.nparts, VTOC8_NPARTS);
be32enc(&vtoc8.sanity, VTOC_SANITY);
be16enc(&vtoc8.rpm, 3600);
be16enc(&vtoc8.physcyls, ncyls);
be16enc(&vtoc8.ncyls, ncyls);
be16enc(&vtoc8.altcyls, 0);
be16enc(&vtoc8.nheads, nheads);
be16enc(&vtoc8.nsecs, nsecs);
be16enc(&vtoc8.magic, VTOC_MAGIC);
ftruncate(fd, imgsz * secsz);
be32enc(&vtoc8.map[VTOC_RAW_PART].nblks, imgsz);
STAILQ_FOREACH(part, &partlist, link) {
n = part->index + ((part->index >= VTOC_RAW_PART) ? 1 : 0);
be16enc(&vtoc8.part[n].tag, ALIAS_TYPE2INT(part->type));
be32enc(&vtoc8.map[n].cyl, part->block / (nsecs * nheads));
be32enc(&vtoc8.map[n].nblks, part->size);
}
/* Calculate checksum. */
sum = 0;
p = (void *)&vtoc8;
for (ofs = 0; ofs < sizeof(vtoc8) - 2; ofs += 2)
sum ^= be16dec(p + ofs);
be16enc(&vtoc8.cksum, sum);
error = mkimg_seek(fd, 0);
if (error == 0) {
if (write(fd, &vtoc8, sizeof(vtoc8)) != sizeof(vtoc8))
error = errno;
}
return (error);
}
static struct mkimg_scheme vtoc8_scheme = {
.name = "vtoc8",
.description = "SMI VTOC8 disk labels",
.aliases = vtoc8_aliases,
.metadata = vtoc8_metadata,
.write = vtoc8_write,
.nparts = VTOC8_NPARTS - 1,
.maxsecsz = 512
};
SCHEME_DEFINE(vtoc8_scheme);