Index: head/usr.bin/mkimg/Makefile =================================================================== --- head/usr.bin/mkimg/Makefile (revision 307543) +++ head/usr.bin/mkimg/Makefile (revision 307544) @@ -1,43 +1,43 @@ # $FreeBSD$ .include PROG= mkimg -SRCS= format.c image.c mkimg.c scheme.c +SRCS= format.c image.c mkimg.c scheme.c uuid.c MAN= mkimg.1 -MKIMG_VERSION=20151211 +MKIMG_VERSION=20161016 mkimg.o: Makefile CFLAGS+=-DMKIMG_VERSION=${MKIMG_VERSION} CFLAGS+=-DSPARSE_WRITE -CFLAGS+=-I${.CURDIR:H:H}/sys +CFLAGS+=-I${SRCTOP}/sys/sys/disk # List of formats to support SRCS+= \ qcow.c \ raw.c \ vhd.c \ vmdk.c # List of schemes to support SRCS+= \ apm.c \ bsd.c \ ebr.c \ gpt.c \ mbr.c \ pc98.c \ vtoc8.c BINDIR?=/usr/bin LIBADD= util WARNS?= 6 .if ${MK_TESTS} != "no" SUBDIR+= tests .endif .include Index: head/usr.bin/mkimg/apm.c =================================================================== --- head/usr.bin/mkimg/apm.c (revision 307543) +++ head/usr.bin/mkimg/apm.c (revision 307544) @@ -1,117 +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 __FBSDID("$FreeBSD$"); #include #include #include #include #include -#include +#include #include "endian.h" #include "image.h" #include "mkimg.h" #include "scheme.h" static struct mkimg_alias apm_aliases[] = { { ALIAS_FREEBSD, ALIAS_PTR2TYPE(APM_ENT_TYPE_FREEBSD) }, { ALIAS_FREEBSD_BOOT, ALIAS_PTR2TYPE(APM_ENT_TYPE_APPLE_BOOT) }, { 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 lba_t apm_metadata(u_int where, lba_t blk) { blk += (where == SCHEME_META_IMG_START) ? nparts + 2 : 0; return (round_block(blk)); } static int apm_write(lba_t imgsz, void *bootcode __unused) { u_char *buf; struct apm_ddr *ddr; struct apm_ent *ent; struct part *part; 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); strncpy(ent->ent_type, APM_ENT_TYPE_SELF, sizeof(ent->ent_type)); strncpy(ent->ent_name, "Apple", sizeof(ent->ent_name)); TAILQ_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); strncpy(ent->ent_type, ALIAS_TYPE2PTR(part->type), sizeof(ent->ent_type)); if (part->label != NULL) strncpy(ent->ent_name, part->label, sizeof(ent->ent_name)); } error = image_write(0, buf, nparts + 2); 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); Index: head/usr.bin/mkimg/bsd.c =================================================================== --- head/usr.bin/mkimg/bsd.c (revision 307543) +++ head/usr.bin/mkimg/bsd.c (revision 307544) @@ -1,136 +1,136 @@ /*- * 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 __FBSDID("$FreeBSD$"); #include #include #include #include #include -#include +#include #include "endian.h" #include "image.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 lba_t bsd_metadata(u_int where, lba_t blk) { if (where == SCHEME_META_IMG_START) blk += BSD_BOOTBLOCK_SIZE / secsz; else if (where == SCHEME_META_IMG_END) blk = round_cylinder(blk); else blk = round_block(blk); return (blk); } static int bsd_write(lba_t imgsz, void *bootcode) { u_char *buf, *p; struct disklabel *d; struct partition *dp; struct part *part; int bsdparts, error, n; uint16_t checksum; buf = malloc(BSD_BOOTBLOCK_SIZE); if (buf == NULL) return (ENOMEM); if (bootcode != NULL) { memcpy(buf, bootcode, BSD_BOOTBLOCK_SIZE); memset(buf + secsz, 0, sizeof(struct disklabel)); } else memset(buf, 0, BSD_BOOTBLOCK_SIZE); bsdparts = nparts + 1; /* Account for c partition */ if (bsdparts < BSD_NPARTS_MIN) bsdparts = BSD_NPARTS_MIN; d = (void *)(buf + secsz); le32enc(&d->d_magic, BSD_MAGIC); 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, BSD_MAGIC); le16enc(&d->d_npartitions, bsdparts); le32enc(&d->d_bbsize, BSD_BOOTBLOCK_SIZE); dp = &d->d_partitions[BSD_PART_RAW]; le32enc(&dp->p_size, imgsz); TAILQ_FOREACH(part, &partlist, link) { n = part->index + ((part->index >= BSD_PART_RAW) ? 1 : 0); dp = &d->d_partitions[n]; le32enc(&dp->p_size, part->size); le32enc(&dp->p_offset, part->block); le32enc(&dp->p_fsize, 0); dp->p_fstype = ALIAS_TYPE2INT(part->type); dp->p_frag = 0; le16enc(&dp->p_cpg, 0); } dp = &d->d_partitions[bsdparts]; checksum = 0; for (p = (void *)d; p < (u_char *)dp; p += 2) checksum ^= le16dec(p); le16enc(&d->d_checksum, checksum); error = image_write(0, buf, BSD_BOOTBLOCK_SIZE / secsz); 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 = BSD_NPARTS_MAX - 1, .bootcode = BSD_BOOTBLOCK_SIZE, .maxsecsz = 512 }; SCHEME_DEFINE(bsd_scheme); Index: head/usr.bin/mkimg/ebr.c =================================================================== --- head/usr.bin/mkimg/ebr.c (revision 307543) +++ head/usr.bin/mkimg/ebr.c (revision 307544) @@ -1,131 +1,131 @@ /*- * 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 __FBSDID("$FreeBSD$"); #include #include #include #include #include -#include +#include #include "endian.h" #include "image.h" #include "mkimg.h" #include "scheme.h" static struct mkimg_alias ebr_aliases[] = { { ALIAS_FAT16B, ALIAS_INT2TYPE(DOSPTYP_FAT16) }, { ALIAS_FAT32, ALIAS_INT2TYPE(DOSPTYP_FAT32) }, { ALIAS_FREEBSD, ALIAS_INT2TYPE(DOSPTYP_386BSD) }, { ALIAS_NONE, 0 } }; static lba_t ebr_metadata(u_int where, lba_t blk) { blk += (where == SCHEME_META_PART_BEFORE) ? 1 : 0; return (round_track(blk)); } static void ebr_chs(u_char *cylp, u_char *hdp, u_char *secp, lba_t lba) { u_int cyl, hd, sec; mkimg_chs(lba, 1023, &cyl, &hd, &sec); *cylp = cyl; *hdp = hd; *secp = (sec & 0x3f) | ((cyl >> 2) & 0xc0); } static int ebr_write(lba_t imgsz __unused, void *bootcode __unused) { u_char *ebr; struct dos_partition *dp; struct part *part, *next; lba_t block, size; int error; ebr = malloc(secsz); if (ebr == NULL) return (ENOMEM); memset(ebr, 0, secsz); le16enc(ebr + DOSMAGICOFFSET, DOSMAGIC); error = 0; TAILQ_FOREACH(part, &partlist, link) { block = part->block - nsecs; size = round_track(part->size); 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 + size - 1); le32enc(&dp->dp_start, nsecs); le32enc(&dp->dp_size, size); /* Add link entry */ next = TAILQ_NEXT(part, link); if (next != NULL) { size = round_track(next->size); 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 + size - 1); le32enc(&dp->dp_start, next->block - nsecs); le32enc(&dp->dp_size, size + nsecs); } error = image_write(block, ebr, 1); 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); Index: head/usr.bin/mkimg/gpt.c =================================================================== --- head/usr.bin/mkimg/gpt.c (revision 307543) +++ head/usr.bin/mkimg/gpt.c (revision 307544) @@ -1,305 +1,289 @@ /*- * 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 __FBSDID("$FreeBSD$"); #include #include #include #include #include #include -#include -#include -#include +#include +#include #include "endian.h" #include "image.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 uuid_t gpt_uuid_ms_basic_data = GPT_ENT_TYPE_MS_BASIC_DATA; +static mkimg_uuid_t gpt_uuid_efi = GPT_ENT_TYPE_EFI; +static mkimg_uuid_t gpt_uuid_freebsd = GPT_ENT_TYPE_FREEBSD; +static mkimg_uuid_t gpt_uuid_freebsd_boot = GPT_ENT_TYPE_FREEBSD_BOOT; +static mkimg_uuid_t gpt_uuid_freebsd_nandfs = GPT_ENT_TYPE_FREEBSD_NANDFS; +static mkimg_uuid_t gpt_uuid_freebsd_swap = GPT_ENT_TYPE_FREEBSD_SWAP; +static mkimg_uuid_t gpt_uuid_freebsd_ufs = GPT_ENT_TYPE_FREEBSD_UFS; +static mkimg_uuid_t gpt_uuid_freebsd_vinum = GPT_ENT_TYPE_FREEBSD_VINUM; +static mkimg_uuid_t gpt_uuid_freebsd_zfs = GPT_ENT_TYPE_FREEBSD_ZFS; +static mkimg_uuid_t gpt_uuid_mbr = GPT_ENT_TYPE_MBR; +static mkimg_uuid_t gpt_uuid_ms_basic_data = GPT_ENT_TYPE_MS_BASIC_DATA; 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_NTFS, ALIAS_PTR2TYPE(&gpt_uuid_ms_basic_data) }, { 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 void -gpt_uuid_enc(void *buf, const uuid_t *uuid) -{ - uint8_t *p = buf; - int i; - - le32enc(p, uuid->time_low); - le16enc(p + 4, uuid->time_mid); - le16enc(p + 6, uuid->time_hi_and_version); - p[8] = uuid->clock_seq_hi_and_reserved; - p[9] = uuid->clock_seq_low; - for (i = 0; i < _UUID_NODE_LEN; i++) - p[10 + i] = uuid->node[i]; -} - static u_int gpt_tblsz(void) { u_int ents; ents = secsz / sizeof(struct gpt_ent); return ((nparts + ents - 1) / ents); } static lba_t gpt_metadata(u_int where, lba_t blk) { if (where == SCHEME_META_IMG_START || where == SCHEME_META_IMG_END) { blk += gpt_tblsz(); blk += (where == SCHEME_META_IMG_START) ? 2 : 1; } return (round_block(blk)); } static int gpt_write_pmbr(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 = image_write(0, pmbr, 1); free(pmbr); return (error); } static struct gpt_ent * gpt_mktbl(u_int tblsz) { - uuid_t uuid; + mkimg_uuid_t uuid; struct gpt_ent *tbl, *ent; struct part *part; int c, idx; tbl = calloc(tblsz, secsz); if (tbl == NULL) return (NULL); TAILQ_FOREACH(part, &partlist, link) { ent = tbl + part->index; - gpt_uuid_enc(&ent->ent_type, ALIAS_TYPE2PTR(part->type)); + mkimg_uuid_enc(&ent->ent_type, ALIAS_TYPE2PTR(part->type)); mkimg_uuid(&uuid); - gpt_uuid_enc(&ent->ent_uuid, &uuid); + mkimg_uuid_enc(&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(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 (image_write(self, hdr, 1)); } static int gpt_write(lba_t imgsz, void *bootcode) { - uuid_t uuid; + mkimg_uuid_t uuid; struct gpt_ent *tbl; struct gpt_hdr *hdr; uint32_t crc; u_int tblsz; int error; /* PMBR */ error = gpt_write_pmbr(imgsz, bootcode); if (error) return (error); /* GPT table(s) */ tblsz = gpt_tblsz(); tbl = gpt_mktbl(tblsz); if (tbl == NULL) return (errno); error = image_write(2, tbl, tblsz); if (error) goto out; error = image_write(imgsz - (tblsz + 1), tbl, tblsz); 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); mkimg_uuid(&uuid); - gpt_uuid_enc(&hdr->hdr_uuid, &uuid); + mkimg_uuid_enc(&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(hdr, 1, imgsz - 1, 2); if (!error) error = gpt_write_hdr(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); Index: head/usr.bin/mkimg/mbr.c =================================================================== --- head/usr.bin/mkimg/mbr.c (revision 307543) +++ head/usr.bin/mkimg/mbr.c (revision 307544) @@ -1,120 +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 __FBSDID("$FreeBSD$"); #include #include #include #include #include -#include +#include #include "endian.h" #include "image.h" #include "mkimg.h" #include "scheme.h" static struct mkimg_alias mbr_aliases[] = { { ALIAS_EBR, ALIAS_INT2TYPE(DOSPTYP_EXT) }, { ALIAS_EFI, ALIAS_INT2TYPE(DOSPTYP_EFI) }, { ALIAS_FAT16B, ALIAS_INT2TYPE(DOSPTYP_FAT16) }, { ALIAS_FAT32, ALIAS_INT2TYPE(DOSPTYP_FAT32) }, { ALIAS_FREEBSD, ALIAS_INT2TYPE(DOSPTYP_386BSD) }, { ALIAS_NTFS, ALIAS_INT2TYPE(DOSPTYP_NTFS) }, { ALIAS_PPCBOOT, ALIAS_INT2TYPE(DOSPTYP_PPCBOOT) }, { ALIAS_NONE, 0 } /* Keep last! */ }; static lba_t mbr_metadata(u_int where, lba_t blk) { blk += (where == SCHEME_META_IMG_START) ? 1 : 0; return (round_track(blk)); } static void mbr_chs(u_char *cylp, u_char *hdp, u_char *secp, lba_t lba) { u_int cyl, hd, sec; mkimg_chs(lba, 1023, &cyl, &hd, &sec); *cylp = cyl; *hdp = hd; *secp = (sec & 0x3f) | ((cyl >> 2) & 0xc0); } static int mbr_write(lba_t imgsz __unused, void *bootcode) { u_char *mbr; struct dos_partition *dpbase, *dp; struct part *part; lba_t size; 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); TAILQ_FOREACH(part, &partlist, link) { size = round_track(part->size); 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 + size - 1); le32enc(&dp->dp_start, part->block); le32enc(&dp->dp_size, size); } error = image_write(0, mbr, 1); 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); Index: head/usr.bin/mkimg/mkimg.c =================================================================== --- head/usr.bin/mkimg/mkimg.c (revision 307543) +++ head/usr.bin/mkimg/mkimg.c (revision 307544) @@ -1,639 +1,622 @@ /*- * 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 __FBSDID("$FreeBSD$"); #include -#include #include #include #include #include #include #include #include #include #include #include #include #include #include "image.h" #include "format.h" #include "mkimg.h" #include "scheme.h" #define LONGOPT_FORMATS 0x01000001 #define LONGOPT_SCHEMES 0x01000002 #define LONGOPT_VERSION 0x01000003 static struct option longopts[] = { { "formats", no_argument, NULL, LONGOPT_FORMATS }, { "schemes", no_argument, NULL, LONGOPT_SCHEMES }, { "version", no_argument, NULL, LONGOPT_VERSION }, { NULL, 0, NULL, 0 } }; static uint64_t capacity; struct partlisthead partlist = TAILQ_HEAD_INITIALIZER(partlist); u_int nparts = 0; u_int unit_testing; u_int verbose; u_int ncyls = 0; u_int nheads = 1; u_int nsecs = 1; u_int secsz = 512; u_int blksz = 0; static void print_formats(int usage) { struct mkimg_format *f; const char *sep; if (usage) { fprintf(stderr, " formats:\n"); f = NULL; while ((f = format_iterate(f)) != NULL) { fprintf(stderr, "\t%s\t- %s\n", f->name, f->description); } } else { sep = ""; f = NULL; while ((f = format_iterate(f)) != NULL) { printf("%s%s", sep, f->name); sep = " "; } putchar('\n'); } } static void print_schemes(int usage) { struct mkimg_scheme *s; const char *sep; if (usage) { fprintf(stderr, " schemes:\n"); s = NULL; while ((s = scheme_iterate(s)) != NULL) { fprintf(stderr, "\t%s\t- %s\n", s->name, s->description); } } else { sep = ""; s = NULL; while ((s = scheme_iterate(s)) != NULL) { printf("%s%s", sep, s->name); sep = " "; } putchar('\n'); } } static void print_version(void) { u_int width; #ifdef __LP64__ width = 64; #else width = 32; #endif printf("mkimg %u (%u-bit)\n", MKIMG_VERSION, width); } static void usage(const char *why) { warnx("error: %s", why); fputc('\n', stderr); fprintf(stderr, "usage: %s \n", getprogname()); fprintf(stderr, " options:\n"); fprintf(stderr, "\t--formats\t- list image formats\n"); fprintf(stderr, "\t--schemes\t- list partition schemes\n"); fprintf(stderr, "\t--version\t- show version information\n"); fputc('\n', stderr); fprintf(stderr, "\t-b \t- file containing boot code\n"); fprintf(stderr, "\t-c \t- capacity (in bytes) of the disk\n"); fprintf(stderr, "\t-f \n"); fprintf(stderr, "\t-o \t- file to write image into\n"); fprintf(stderr, "\t-p \n"); fprintf(stderr, "\t-s \n"); fprintf(stderr, "\t-v\t\t- increase verbosity\n"); fprintf(stderr, "\t-y\t\t- [developers] enable unit test\n"); fprintf(stderr, "\t-H \t- number of heads to simulate\n"); fprintf(stderr, "\t-P \t- physical sector size\n"); fprintf(stderr, "\t-S \t- logical sector size\n"); fprintf(stderr, "\t-T \t- number of tracks to simulate\n"); fputc('\n', stderr); print_formats(1); fputc('\n', stderr); print_schemes(1); fputc('\n', stderr); fprintf(stderr, " partition specification:\n"); fprintf(stderr, "\t[/]::\t- empty partition of given " "size\n"); fprintf(stderr, "\t[/]:=\t- partition content and size " "are determined\n\t\t\t\t by the named file\n"); fprintf(stderr, "\t[/]:-\t- partition content and size " "are taken from\n\t\t\t\t the output of the command to run\n"); fprintf(stderr, "\t-\t\t\t- unused partition entry\n"); fprintf(stderr, "\t where:\n"); fprintf(stderr, "\t\t\t- scheme neutral partition type\n"); fprintf(stderr, "\t\t\t- optional scheme-dependent partition " "label\n"); exit(EX_USAGE); } static int parse_uint32(uint32_t *valp, uint32_t min, uint32_t 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 = (uint32_t)val; return (0); } static int parse_uint64(uint64_t *valp, uint64_t min, uint64_t max, const char *arg) { uint64_t val; if (expand_number(arg, &val) == -1) return (errno); if (val < min || val > max) return (EINVAL); *valp = 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: * ':' * 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 * * A specification that is a single dash indicates an unused partition * entry. */ static int parse_part(const char *spec) { struct part *part; char *sep; size_t len; int error; if (strcmp(spec, "-") == 0) { nparts++; return (0); } 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; TAILQ_INSERT_TAIL(&partlist, part, link); nparts++; return (0); errout: if (part->alias != NULL) free(part->alias); free(part); return (error); } #if defined(SPARSE_WRITE) ssize_t sparse_write(int fd, const void *ptr, size_t sz) { const char *buf, *p; off_t ofs; size_t len; ssize_t wr, wrsz; buf = ptr; 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 */ void mkimg_chs(lba_t lba, u_int maxcyl, u_int *cylp, u_int *hdp, u_int *secp) { u_int hd, sec; *cylp = *hdp = *secp = ~0U; if (nsecs == 1 || nheads == 1) return; sec = lba % nsecs + 1; lba /= nsecs; hd = lba % nheads; lba /= nheads; if (lba > maxcyl) return; *cylp = lba; *hdp = hd; *secp = sec; -} - -void -mkimg_uuid(struct uuid *uuid) -{ - static uint8_t gen[sizeof(struct uuid)]; - u_int i; - - if (!unit_testing) { - uuidgen(uuid, 1); - return; - } - - for (i = 0; i < sizeof(gen); i++) - gen[i]++; - memcpy(uuid, gen, sizeof(uuid_t)); } static int capacity_resize(lba_t end) { lba_t capsz; capsz = (capacity + secsz - 1) / secsz; if (end >= capsz) return (0); return (image_set_size(capsz)); } static void mkimg(void) { FILE *fp; struct part *part; lba_t block; off_t bytesize; int error, fd; /* First check partition information */ TAILQ_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); TAILQ_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; 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 = image_copyin(block, fd, &bytesize); close(fd); } else error = errno; break; case PART_KIND_PIPE: fp = popen(part->contents, "r"); if (fp != NULL) { fd = fileno(fp); error = image_copyin(block, fd, &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 = image_set_size(block); if (!error) { error = capacity_resize(block); block = image_get_size(); } if (!error) { error = format_resize(block); block = image_get_size(); } if (error) errc(EX_IOERR, error, "image sizing"); ncyls = block / (nsecs * nheads); error = scheme_write(block); if (error) errc(EX_IOERR, error, "writing metadata"); } int main(int argc, char *argv[]) { int bcfd, outfd; int c, error; bcfd = -1; outfd = 1; /* Write to stdout by default */ while ((c = getopt_long(argc, argv, "b:c:f:o:p:s:vyH:P:S:T:", longopts, NULL)) != -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 'c': /* CAPACITY */ error = parse_uint64(&capacity, 1, INT64_MAX, optarg); if (error) errc(EX_DATAERR, error, "capacity in bytes"); break; case 'f': /* OUTPUT FORMAT */ if (format_selected() != NULL) usage("multiple formats given"); error = format_select(optarg); if (error) errc(EX_DATAERR, error, "format"); break; case 'o': /* OUTPUT FILE */ if (outfd != 1) 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 'y': unit_testing++; break; case 'v': verbose++; break; case 'H': /* GEOMETRY: HEADS */ error = parse_uint32(&nheads, 1, 255, optarg); if (error) errc(EX_DATAERR, error, "number of heads"); break; case 'P': /* GEOMETRY: PHYSICAL SECTOR SIZE */ error = parse_uint32(&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_uint32(&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_uint32(&nsecs, 1, 63, optarg); if (error) errc(EX_DATAERR, error, "track size"); break; case LONGOPT_FORMATS: print_formats(0); exit(EX_OK); /*NOTREACHED*/ case LONGOPT_SCHEMES: print_schemes(0); exit(EX_OK); /*NOTREACHED*/ case LONGOPT_VERSION: print_version(); exit(EX_OK); /*NOTREACHED*/ default: usage("unknown option"); } } if (argc > optind) usage("trailing arguments"); if (scheme_selected() == NULL && nparts > 0) usage("no scheme"); if (nparts == 0 && capacity == 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 (format_selected() == NULL) format_select("raw"); if (bcfd != -1) { error = scheme_bootcode(bcfd); close(bcfd); if (error) errc(EX_DATAERR, error, "boot code"); } 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); fputc('\n', stderr); if (scheme_selected()) fprintf(stderr, "Partitioning scheme: %s\n", scheme_selected()->name); fprintf(stderr, "Output file format: %s\n", format_selected()->name); fputc('\n', stderr); } error = image_init(); if (error) errc(EX_OSERR, error, "cannot initialize"); mkimg(); if (verbose) { fputc('\n', stderr); fprintf(stderr, "Number of cylinders: %u\n", ncyls); } error = format_write(outfd); if (error) errc(EX_IOERR, error, "writing image"); return (0); } Index: head/usr.bin/mkimg/mkimg.h =================================================================== --- head/usr.bin/mkimg/mkimg.h (revision 307543) +++ head/usr.bin/mkimg/mkimg.h (revision 307544) @@ -1,95 +1,106 @@ /*- * 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 +#include struct part { TAILQ_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 TAILQ_HEAD(partlisthead, part) partlist; extern u_int nparts; extern u_int unit_testing; 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)); } static inline lba_t round_cylinder(lba_t n) { u_int cyl = nsecs * nheads; u_int r = n % cyl; return ((r == 0) ? n : n + cyl - r); } static inline lba_t round_track(lba_t n) { u_int r = n % nsecs; return ((r == 0) ? n : n + nsecs - r); } #if !defined(SPARSE_WRITE) #define sparse_write write #else ssize_t sparse_write(int, const void *, size_t); #endif void mkimg_chs(lba_t, u_int, u_int *, u_int *, u_int *); -struct uuid; -void mkimg_uuid(struct uuid *); +struct mkimg_uuid { + uint32_t time_low; + uint16_t time_mid; + uint16_t time_hi_and_version; + uint8_t clock_seq_hi_and_reserved; + uint8_t clock_seq_low; + uint8_t node[6]; +}; +typedef struct mkimg_uuid mkimg_uuid_t; + +void mkimg_uuid(mkimg_uuid_t *); +void mkimg_uuid_enc(void *, const mkimg_uuid_t *); #endif /* _MKIMG_MKIMG_H_ */ Index: head/usr.bin/mkimg/pc98.c =================================================================== --- head/usr.bin/mkimg/pc98.c (revision 307543) +++ head/usr.bin/mkimg/pc98.c (revision 307544) @@ -1,118 +1,118 @@ /*- * 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 __FBSDID("$FreeBSD$"); #include #include #include #include #include -#include +#include #include "endian.h" #include "image.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 lba_t pc98_metadata(u_int where, lba_t blk) { if (where == SCHEME_META_IMG_START) blk += PC98_BOOTCODESZ / secsz; return (round_track(blk)); } static void pc98_chs(u_short *cylp, u_char *hdp, u_char *secp, lba_t lba) { u_int cyl, hd, sec; mkimg_chs(lba, 0xffff, &cyl, &hd, &sec); le16enc(cylp, cyl); *hdp = hd; *secp = sec; } static int pc98_write(lba_t imgsz __unused, void *bootcode) { struct part *part; struct pc98_partition *dpbase, *dp; u_char *buf; lba_t size; 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); TAILQ_FOREACH(part, &partlist, link) { size = round_track(part->size); 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 + size - 1); if (part->label != NULL) memcpy(dp->dp_name, part->label, strlen(part->label)); } error = image_write(0, buf, PC98_BOOTCODESZ / secsz); 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); Index: head/usr.bin/mkimg/uuid.c =================================================================== --- head/usr.bin/mkimg/uuid.c (nonexistent) +++ head/usr.bin/mkimg/uuid.c (revision 307544) @@ -0,0 +1,125 @@ +/*- + * Copyright (c) 2016 Marcel Moolenaar + * 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include + +#include "endian.h" +#include "image.h" +#include "mkimg.h" + +static void osdep_uuidgen(mkimg_uuid_t *); + +#ifdef __APPLE__ +#include + +static void +osdep_uuidgen(mkimg_uuid_t *uuid) +{ + + uuid_generate_time((void *)uuid); +} +#endif /* __APPLE__ */ + +#ifdef __FreeBSD__ +#include + +static void +osdep_uuidgen(mkimg_uuid_t *uuid) +{ + + uuidgen((void *)uuid, 1); +} +#endif /* __FreeBSD__ */ + +#ifdef __linux__ +#include +#include + +static void +osdep_uuidgen(mkimg_uuid_t *uuid) +{ + struct timespec tp; + uint64_t time = 0x01B21DD213814000LL; + u_int i; + uint16_t seq; + + if (clock_gettime(CLOCK_REALTIME, &tp) == -1) + abort(); + + time += (uint64_t)tp.tv_sec * 10000000LL; + time += tp.tv_nsec / 100; + + uuid->time_low = (uint32_t)time; + uuid->time_mid = (uint16_t)(time >> 32); + uuid->time_hi_and_version = (uint16_t)(time >> 48) & 0xfff; + uuid->time_hi_and_version |= 1 << 12; + + seq = random(); + + uuid->clock_seq_hi_and_reserved = (uint8_t)(seq >> 8) & 0x3f; + uuid->clock_seq_low = (uint8_t)seq; + + for (i = 0; i < 6; i++) + uuid->node[i] = (uint8_t)random(); + uuid->node[0] |= 0x01; +} +#endif /* __linux__ */ + +void +mkimg_uuid(mkimg_uuid_t *uuid) +{ + static uint8_t gen[sizeof(mkimg_uuid_t)]; + u_int i; + + if (!unit_testing) { + osdep_uuidgen(uuid); + return; + } + + for (i = 0; i < sizeof(gen); i++) + gen[i]++; + memcpy(uuid, gen, sizeof(*uuid)); +} + +void +mkimg_uuid_enc(void *buf, const mkimg_uuid_t *uuid) +{ + uint8_t *p = buf; + u_int i; + + le32enc(p, uuid->time_low); + le16enc(p + 4, uuid->time_mid); + le16enc(p + 6, uuid->time_hi_and_version); + p[8] = uuid->clock_seq_hi_and_reserved; + p[9] = uuid->clock_seq_low; + for (i = 0; i < 6; i++) + p[10 + i] = uuid->node[i]; +} Property changes on: head/usr.bin/mkimg/uuid.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/usr.bin/mkimg/vhd.c =================================================================== --- head/usr.bin/mkimg/vhd.c (revision 307543) +++ head/usr.bin/mkimg/vhd.c (revision 307544) @@ -1,432 +1,416 @@ /*- * Copyright (c) 2014, 2015 Marcel Moolenaar * 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 __FBSDID("$FreeBSD$"); #include #include #include #include #include #include -#include #include "endian.h" #include "image.h" #include "format.h" #include "mkimg.h" #ifndef __has_extension #define __has_extension(x) 0 #endif /* * General notes: * o File is in network byte order. * o The timestamp is seconds since 1/1/2000 12:00:00 AM UTC * * This file is divided in 3 parts: * 1. Common definitions * 2. Dynamic VHD support * 3. Fixed VHD support */ /* * PART 1: Common definitions */ #define VHD_SECTOR_SIZE 512 #define VHD_BLOCK_SIZE (4096 * VHD_SECTOR_SIZE) /* 2MB blocks */ struct vhd_geom { uint16_t cylinders; uint8_t heads; uint8_t sectors; }; struct vhd_footer { uint64_t cookie; #define VHD_FOOTER_COOKIE 0x636f6e6563746978ULL uint32_t features; #define VHD_FEATURES_TEMPORARY 0x01 #define VHD_FEATURES_RESERVED 0x02 uint32_t version; #define VHD_VERSION 0x00010000 uint64_t data_offset; uint32_t timestamp; uint32_t creator_tool; #define VHD_CREATOR_TOOL 0x2a696d67 /* FreeBSD mkimg */ uint32_t creator_version; #define VHD_CREATOR_VERSION 0x00020000 uint32_t creator_os; #define VHD_CREATOR_OS 0x5769326b /* Wi2k */ uint64_t original_size; uint64_t current_size; struct vhd_geom geometry; uint32_t disk_type; #define VHD_DISK_TYPE_FIXED 2 #define VHD_DISK_TYPE_DYNAMIC 3 #define VHD_DISK_TYPE_DIFF 4 uint32_t checksum; - uuid_t id; + mkimg_uuid_t id; uint8_t saved_state; uint8_t _reserved[427]; }; #if __has_extension(c_static_assert) _Static_assert(sizeof(struct vhd_footer) == VHD_SECTOR_SIZE, "Wrong size for footer"); #endif static uint32_t vhd_checksum(void *buf, size_t sz) { uint8_t *p = buf; uint32_t sum; size_t ofs; sum = 0; for (ofs = 0; ofs < sz; ofs++) sum += p[ofs]; return (~sum); } static void vhd_geometry(uint64_t image_size, struct vhd_geom *geom) { lba_t imgsz; long cth; imgsz = image_size / VHD_SECTOR_SIZE; /* Respect command line options if possible. */ if (nheads > 1 && nheads < 256 && nsecs > 1 && nsecs < 256 && ncyls < 65536) { geom->cylinders = (ncyls != 0) ? ncyls : imgsz / (nheads * nsecs); geom->heads = nheads; geom->sectors = nsecs; return; } if (imgsz > 65536 * 16 * 255) imgsz = 65536 * 16 * 255; if (imgsz >= 65535 * 16 * 63) { geom->cylinders = imgsz / (16 * 255); geom->heads = 16; geom->sectors = 255; return; } geom->sectors = 17; cth = imgsz / 17; geom->heads = (cth + 1023) / 1024; if (geom->heads < 4) geom->heads = 4; if (cth >= (geom->heads * 1024) || geom->heads > 16) { geom->heads = 16; geom->sectors = 31; cth = imgsz / 31; } if (cth >= (geom->heads * 1024)) { geom->heads = 16; geom->sectors = 63; cth = imgsz / 63; } geom->cylinders = cth / geom->heads; } static uint64_t vhd_resize(uint64_t origsz) { struct vhd_geom geom; uint64_t newsz; /* * Round the image size to the pre-determined geometry that * matches the image size. This circular dependency implies * that we need to loop to handle boundary conditions. * The first time, newsz equals origsz and the geometry will * typically yield a new size that's smaller. We keep adding * cylinder's worth of sectors to the new size until its * larger or equal or origsz. But during those iterations, * the geometry can change, so we need to account for that. */ newsz = origsz; while (1) { vhd_geometry(newsz, &geom); newsz = (int64_t)geom.cylinders * geom.heads * geom.sectors * VHD_SECTOR_SIZE; if (newsz >= origsz) break; newsz += geom.heads * geom.sectors * VHD_SECTOR_SIZE; } return (newsz); } static uint32_t vhd_timestamp(void) { time_t t; if (!unit_testing) { t = time(NULL); return (t - 0x386d4380); } return (0x01234567); } static void -vhd_uuid_enc(void *buf, const uuid_t *uuid) -{ - uint8_t *p = buf; - int i; - - be32enc(p, uuid->time_low); - be16enc(p + 4, uuid->time_mid); - be16enc(p + 6, uuid->time_hi_and_version); - p[8] = uuid->clock_seq_hi_and_reserved; - p[9] = uuid->clock_seq_low; - for (i = 0; i < _UUID_NODE_LEN; i++) - p[10 + i] = uuid->node[i]; -} - -static void vhd_make_footer(struct vhd_footer *footer, uint64_t image_size, uint32_t disk_type, uint64_t data_offset) { - uuid_t id; + mkimg_uuid_t id; memset(footer, 0, sizeof(*footer)); be64enc(&footer->cookie, VHD_FOOTER_COOKIE); be32enc(&footer->features, VHD_FEATURES_RESERVED); be32enc(&footer->version, VHD_VERSION); be64enc(&footer->data_offset, data_offset); be32enc(&footer->timestamp, vhd_timestamp()); be32enc(&footer->creator_tool, VHD_CREATOR_TOOL); be32enc(&footer->creator_version, VHD_CREATOR_VERSION); be32enc(&footer->creator_os, VHD_CREATOR_OS); be64enc(&footer->original_size, image_size); be64enc(&footer->current_size, image_size); vhd_geometry(image_size, &footer->geometry); be16enc(&footer->geometry.cylinders, footer->geometry.cylinders); be32enc(&footer->disk_type, disk_type); mkimg_uuid(&id); - vhd_uuid_enc(&footer->id, &id); + mkimg_uuid_enc(&footer->id, &id); be32enc(&footer->checksum, vhd_checksum(footer, sizeof(*footer))); } /* * PART 2: Dynamic VHD support * * Notes: * o File layout: * copy of disk footer * dynamic disk header * block allocation table (BAT) * data blocks * disk footer */ struct vhd_dyn_header { uint64_t cookie; #define VHD_HEADER_COOKIE 0x6378737061727365ULL uint64_t data_offset; uint64_t table_offset; uint32_t version; uint32_t max_entries; uint32_t block_size; uint32_t checksum; - uuid_t parent_id; + mkimg_uuid_t parent_id; uint32_t parent_timestamp; char _reserved1[4]; uint16_t parent_name[256]; /* UTF-16 */ struct { uint32_t code; uint32_t data_space; uint32_t data_length; uint32_t _reserved; uint64_t data_offset; } parent_locator[8]; char _reserved2[256]; }; #if __has_extension(c_static_assert) _Static_assert(sizeof(struct vhd_dyn_header) == VHD_SECTOR_SIZE * 2, "Wrong size for header"); #endif static int vhd_dyn_resize(lba_t imgsz) { uint64_t imagesz; imagesz = vhd_resize(imgsz * secsz); return (image_set_size(imagesz / secsz)); } static int vhd_dyn_write(int fd) { struct vhd_footer footer; struct vhd_dyn_header header; uint64_t imgsz, rawsz; lba_t blk, blkcnt, nblks; uint32_t *bat; void *bitmap; size_t batsz; uint32_t sector; int bat_entries, error, entry; rawsz = image_get_size() * secsz; imgsz = (rawsz + VHD_BLOCK_SIZE - 1) & ~(VHD_BLOCK_SIZE - 1); vhd_make_footer(&footer, rawsz, VHD_DISK_TYPE_DYNAMIC, sizeof(footer)); if (sparse_write(fd, &footer, sizeof(footer)) < 0) return (errno); bat_entries = imgsz / VHD_BLOCK_SIZE; memset(&header, 0, sizeof(header)); be64enc(&header.cookie, VHD_HEADER_COOKIE); be64enc(&header.data_offset, ~0ULL); be64enc(&header.table_offset, sizeof(footer) + sizeof(header)); be32enc(&header.version, VHD_VERSION); be32enc(&header.max_entries, bat_entries); be32enc(&header.block_size, VHD_BLOCK_SIZE); be32enc(&header.checksum, vhd_checksum(&header, sizeof(header))); if (sparse_write(fd, &header, sizeof(header)) < 0) return (errno); batsz = bat_entries * sizeof(uint32_t); batsz = (batsz + VHD_SECTOR_SIZE - 1) & ~(VHD_SECTOR_SIZE - 1); bat = malloc(batsz); if (bat == NULL) return (errno); memset(bat, 0xff, batsz); blkcnt = VHD_BLOCK_SIZE / secsz; sector = (sizeof(footer) + sizeof(header) + batsz) / VHD_SECTOR_SIZE; for (entry = 0; entry < bat_entries; entry++) { blk = entry * blkcnt; if (image_data(blk, blkcnt)) { be32enc(&bat[entry], sector); sector += (VHD_BLOCK_SIZE / VHD_SECTOR_SIZE) + 1; } } if (sparse_write(fd, bat, batsz) < 0) { free(bat); return (errno); } free(bat); bitmap = malloc(VHD_SECTOR_SIZE); if (bitmap == NULL) return (errno); memset(bitmap, 0xff, VHD_SECTOR_SIZE); blk = 0; blkcnt = VHD_BLOCK_SIZE / secsz; error = 0; nblks = rawsz / secsz; while (blk < nblks) { if (!image_data(blk, blkcnt)) { blk += blkcnt; continue; } if (sparse_write(fd, bitmap, VHD_SECTOR_SIZE) < 0) { error = errno; break; } /* Handle partial last block */ if (blk + blkcnt > nblks) blkcnt = nblks - blk; error = image_copyout_region(fd, blk, blkcnt); if (error) break; blk += blkcnt; } free(bitmap); if (error) return (error); error = image_copyout_zeroes(fd, imgsz - rawsz); if (error) return (error); if (sparse_write(fd, &footer, sizeof(footer)) < 0) return (errno); return (0); } static struct mkimg_format vhd_dyn_format = { .name = "vhd", .description = "Virtual Hard Disk", .resize = vhd_dyn_resize, .write = vhd_dyn_write, }; FORMAT_DEFINE(vhd_dyn_format); /* * PART 3: Fixed VHD */ static int vhd_fix_resize(lba_t imgsz) { uint64_t imagesz; imagesz = vhd_resize(imgsz * secsz); /* * Azure demands that images are a whole number of megabytes. */ imagesz = (imagesz + 0xfffffULL) & ~0xfffffULL; return (image_set_size(imagesz / secsz)); } static int vhd_fix_write(int fd) { struct vhd_footer footer; uint64_t imagesz; int error; error = image_copyout(fd); if (error) return (error); imagesz = image_get_size() * secsz; vhd_make_footer(&footer, imagesz, VHD_DISK_TYPE_FIXED, ~0ULL); error = (sparse_write(fd, &footer, sizeof(footer)) < 0) ? errno : 0; return (error); } static struct mkimg_format vhd_fix_format = { .name = "vhdf", .description = "Fixed Virtual Hard Disk", .resize = vhd_fix_resize, .write = vhd_fix_write, }; FORMAT_DEFINE(vhd_fix_format); Index: head/usr.bin/mkimg/vtoc8.c =================================================================== --- head/usr.bin/mkimg/vtoc8.c (revision 307543) +++ head/usr.bin/mkimg/vtoc8.c (revision 307544) @@ -1,115 +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 __FBSDID("$FreeBSD$"); #include #include #include #include #include #include -#include +#include #include "endian.h" #include "image.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 lba_t vtoc8_metadata(u_int where, lba_t blk) { blk += (where == SCHEME_META_IMG_START) ? 1 : 0; return (round_cylinder(blk)); } static int vtoc8_write(lba_t imgsz, void *bootcode __unused) { struct vtoc8 vtoc8; struct part *part; u_char *p; int error, n; uint16_t ofs, sum; imgsz = (lba_t)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); be32enc(&vtoc8.map[VTOC_RAW_PART].nblks, imgsz); TAILQ_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 = image_write(0, &vtoc8, 1); 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);