summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormarcel <marcel@FreeBSD.org>2014-07-02 14:54:41 +0000
committermarcel <marcel@FreeBSD.org>2014-07-02 14:54:41 +0000
commita33844e926a330bdb5c1966b112da53d2735b82a (patch)
tree26c8d3108a777e90434c7a3347a4cfee6c3ed237
parent62024097ea597140238f1338c25f54390d09d619 (diff)
downloadFreeBSD-src-a33844e926a330bdb5c1966b112da53d2735b82a.zip
FreeBSD-src-a33844e926a330bdb5c1966b112da53d2735b82a.tar.gz
MFC mkimg(1) -- revisions 268159, 268134, 266556, 266514, 266513,
266512, 266511, 266510, 266509, 266176, 265468, 265467, 265462, 265170, 263926, 263924, 263923, 263919 and 263918. Revision 267182 changed mkimg.1 alongside other unrelated manpages. The change to mkimg.1 has been applied without registering a merge of the revision. This allows a future merge of r267182 to happen. Relnotes: yes
-rw-r--r--usr.bin/Makefile1
-rw-r--r--usr.bin/mkimg/Makefile31
-rw-r--r--usr.bin/mkimg/apm.c121
-rw-r--r--usr.bin/mkimg/bsd.c135
-rw-r--r--usr.bin/mkimg/ebr.c129
-rw-r--r--usr.bin/mkimg/format.c91
-rw-r--r--usr.bin/mkimg/format.h49
-rw-r--r--usr.bin/mkimg/gpt.c310
-rw-r--r--usr.bin/mkimg/image.c179
-rw-r--r--usr.bin/mkimg/image.h41
-rw-r--r--usr.bin/mkimg/mbr.c116
-rw-r--r--usr.bin/mkimg/mkimg.1181
-rw-r--r--usr.bin/mkimg/mkimg.c469
-rw-r--r--usr.bin/mkimg/mkimg.h74
-rw-r--r--usr.bin/mkimg/pc98.c127
-rw-r--r--usr.bin/mkimg/raw.c63
-rw-r--r--usr.bin/mkimg/scheme.c188
-rw-r--r--usr.bin/mkimg/scheme.h90
-rw-r--r--usr.bin/mkimg/vmdk.c226
-rw-r--r--usr.bin/mkimg/vtoc8.c123
20 files changed, 2744 insertions, 0 deletions
diff --git a/usr.bin/Makefile b/usr.bin/Makefile
index b88768b..f81ce7d 100644
--- a/usr.bin/Makefile
+++ b/usr.bin/Makefile
@@ -106,6 +106,7 @@ SUBDIR= alias \
mkdep \
${_mkesdb} \
mkfifo \
+ mkimg \
mklocale \
mktemp \
mkulzma \
diff --git a/usr.bin/mkimg/Makefile b/usr.bin/mkimg/Makefile
new file mode 100644
index 0000000..582ca60
--- /dev/null
+++ b/usr.bin/mkimg/Makefile
@@ -0,0 +1,31 @@
+# $FreeBSD$
+
+PROG= mkimg
+SRCS= format.c image.c mkimg.c scheme.c
+MAN= mkimg.1
+
+CFLAGS+=-DSPARSE_WRITE
+
+# List of formats to support
+SRCS+= \
+ raw.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
+
+DPADD= ${LIBUTIL}
+LDADD= -lutil
+
+WARNS?= 6
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/mkimg/apm.c b/usr.bin/mkimg/apm.c
new file mode 100644
index 0000000..1877a54
--- /dev/null
+++ b/usr.bin/mkimg/apm.c
@@ -0,0 +1,121 @@
+/*-
+ * 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 "image.h"
+#include "mkimg.h"
+#include "scheme.h"
+
+#ifndef APM_ENT_TYPE_FREEBSD_NANDFS
+#define APM_ENT_TYPE_FREEBSD_NANDFS "FreeBSD-nandfs"
+#endif
+
+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 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(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));
+
+ 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);
+ 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);
diff --git a/usr.bin/mkimg/bsd.c b/usr.bin/mkimg/bsd.c
new file mode 100644
index 0000000..03af5cd
--- /dev/null
+++ b/usr.bin/mkimg/bsd.c
@@ -0,0 +1,135 @@
+/*-
+ * 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 "image.h"
+#include "mkimg.h"
+#include "scheme.h"
+
+#ifndef FS_NANDFS
+#define FS_NANDFS 30
+#endif
+
+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(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 = (lba_t)ncyls * nheads * nsecs;
+ error = image_set_size(imgsz);
+ if (error) {
+ free(buf);
+ return (error);
+ }
+
+ 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 = image_write(0, buf, BBSIZE / 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 = 19,
+ .bootcode = BBSIZE,
+ .maxsecsz = 512
+};
+
+SCHEME_DEFINE(bsd_scheme);
diff --git a/usr.bin/mkimg/ebr.c b/usr.bin/mkimg/ebr.c
new file mode 100644
index 0000000..77204d7
--- /dev/null
+++ b/usr.bin/mkimg/ebr.c
@@ -0,0 +1,129 @@
+/*-
+ * 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 "image.h"
+#include "mkimg.h"
+#include "scheme.h"
+
+#ifndef DOSPTYP_FAT32
+#define DOSPTYP_FAT32 0x0b
+#endif
+
+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(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 = 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);
diff --git a/usr.bin/mkimg/format.c b/usr.bin/mkimg/format.c
new file mode 100644
index 0000000..57bbd98
--- /dev/null
+++ b/usr.bin/mkimg/format.c
@@ -0,0 +1,91 @@
+/*-
+ * 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/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 "image.h"
+#include "format.h"
+#include "mkimg.h"
+
+static struct mkimg_format *format;
+
+int
+format_resize(lba_t end)
+{
+
+ if (format == NULL)
+ return (ENOSYS);
+ return (format->resize(end));
+}
+
+int
+format_select(const char *spec)
+{
+ struct mkimg_format *f, **iter;
+
+ SET_FOREACH(iter, formats) {
+ f = *iter;
+ if (strcasecmp(spec, f->name) == 0) {
+ format = f;
+ return (0);
+ }
+ }
+ return (EINVAL);
+}
+
+struct mkimg_format *
+format_selected(void)
+{
+
+ return (format);
+}
+
+int
+format_write(int fd)
+{
+ lba_t size;
+ int error;
+
+ if (format == NULL)
+ return (ENOSYS);
+ size = image_get_size();
+ error = format->resize(size);
+ if (!error)
+ error = format->write(fd);
+ return (error);
+}
diff --git a/usr.bin/mkimg/format.h b/usr.bin/mkimg/format.h
new file mode 100644
index 0000000..aa00e6e
--- /dev/null
+++ b/usr.bin/mkimg/format.h
@@ -0,0 +1,49 @@
+/*-
+ * 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_FORMAT_H_
+#define _MKIMG_FORMAT_H_
+
+#include <sys/linker_set.h>
+
+struct mkimg_format {
+ const char *name;
+ const char *description;
+ int (*resize)(lba_t);
+ int (*write)(int);
+};
+
+SET_DECLARE(formats, struct mkimg_format);
+#define FORMAT_DEFINE(nm) DATA_SET(formats, nm)
+
+int format_resize(lba_t);
+int format_select(const char *);
+struct mkimg_format *format_selected(void);
+int format_write(int);
+
+#endif /* _MKIMG_FORMAT_H_ */
diff --git a/usr.bin/mkimg/gpt.c b/usr.bin/mkimg/gpt.c
new file mode 100644
index 0000000..47fa64a
--- /dev/null
+++ b/usr.bin/mkimg/gpt.c
@@ -0,0 +1,310 @@
+/*-
+ * 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 "image.h"
+#include "mkimg.h"
+#include "scheme.h"
+
+#ifndef GPT_ENT_TYPE_FREEBSD_NANDFS
+#define GPT_ENT_TYPE_FREEBSD_NANDFS \
+ {0x74ba7dd9,0xa689,0x11e1,0xbd,0x04,{0x00,0xe0,0x81,0x28,0x6a,0xcf}}
+#endif
+
+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 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 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_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;
+ 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;
+ gpt_uuid_enc(&ent->ent_type, ALIAS_TYPE2PTR(part->type));
+ uuidgen(&uuid, 1);
+ gpt_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;
+ 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);
+ uuidgen(&uuid, 1);
+ gpt_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);
diff --git a/usr.bin/mkimg/image.c b/usr.bin/mkimg/image.c
new file mode 100644
index 0000000..e8dc8fe
--- /dev/null
+++ b/usr.bin/mkimg/image.c
@@ -0,0 +1,179 @@
+/*-
+ * 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 <assert.h>
+#include <errno.h>
+#include <limits.h>
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "image.h"
+#include "mkimg.h"
+
+#define BUFFER_SIZE (1024*1024)
+
+static char image_tmpfile[PATH_MAX];
+static int image_fd = -1;
+static lba_t image_size;
+
+static void
+cleanup(void)
+{
+
+ if (image_fd != -1)
+ close(image_fd);
+ unlink(image_tmpfile);
+}
+
+int
+image_copyin(lba_t blk, int fd, uint64_t *sizep)
+{
+ char *buffer;
+ uint64_t bytesize;
+ ssize_t bcnt, rdsz;
+ int error, partial;
+
+ assert(BUFFER_SIZE % secsz == 0);
+
+ buffer = malloc(BUFFER_SIZE);
+ if (buffer == NULL)
+ return (ENOMEM);
+ bytesize = 0;
+ partial = 0;
+ while (1) {
+ rdsz = read(fd, buffer, BUFFER_SIZE);
+ if (rdsz <= 0) {
+ error = (rdsz < 0) ? errno : 0;
+ break;
+ }
+ if (partial)
+ abort();
+ bytesize += rdsz;
+ bcnt = (rdsz + secsz - 1) / secsz;
+ error = image_write(blk, buffer, bcnt);
+ if (error)
+ break;
+ blk += bcnt;
+ partial = ((ssize_t)(bcnt * secsz) != rdsz) ? 1 : 0;
+ }
+ free(buffer);
+ if (sizep != NULL)
+ *sizep = bytesize;
+ return (error);
+}
+
+int
+image_copyout(int fd)
+{
+ char *buffer;
+ off_t ofs;
+ ssize_t rdsz, wrsz;
+ int error;
+
+ ofs = lseek(fd, 0L, SEEK_CUR);
+
+ if (lseek(image_fd, 0, SEEK_SET) != 0)
+ return (errno);
+ buffer = malloc(BUFFER_SIZE);
+ if (buffer == NULL)
+ return (errno);
+ error = 0;
+ while (1) {
+ rdsz = read(image_fd, buffer, BUFFER_SIZE);
+ if (rdsz <= 0) {
+ error = (rdsz < 0) ? errno : 0;
+ break;
+ }
+ wrsz = (ofs == -1) ?
+ write(fd, buffer, rdsz) :
+ sparse_write(fd, buffer, rdsz);
+ if (wrsz < 0) {
+ error = errno;
+ break;
+ }
+ }
+ free(buffer);
+ if (error)
+ return (error);
+ ofs = lseek(fd, 0L, SEEK_CUR);
+ if (ofs == -1)
+ return (errno);
+ error = (ftruncate(fd, ofs) == -1) ? errno : 0;
+ return (error);
+}
+
+lba_t
+image_get_size(void)
+{
+
+ return (image_size);
+}
+
+int
+image_set_size(lba_t blk)
+{
+
+ image_size = blk;
+ if (ftruncate(image_fd, blk * secsz) == -1)
+ return (errno);
+ return (0);
+}
+
+int
+image_write(lba_t blk, void *buf, ssize_t len)
+{
+
+ blk *= secsz;
+ if (lseek(image_fd, blk, SEEK_SET) != blk)
+ return (errno);
+ len *= secsz;
+ if (sparse_write(image_fd, buf, len) != len)
+ return (errno);
+ return (0);
+}
+
+int
+image_init(void)
+{
+ const char *tmpdir;
+
+ if (atexit(cleanup) == -1)
+ return (errno);
+ if ((tmpdir = getenv("TMPDIR")) == NULL || *tmpdir == '\0')
+ tmpdir = _PATH_TMP;
+ snprintf(image_tmpfile, sizeof(image_tmpfile), "%s/mkimg-XXXXXX",
+ tmpdir);
+ image_fd = mkstemp(image_tmpfile);
+ if (image_fd == -1)
+ return (errno);
+ return (0);
+}
diff --git a/usr.bin/mkimg/image.h b/usr.bin/mkimg/image.h
new file mode 100644
index 0000000..d30e11b
--- /dev/null
+++ b/usr.bin/mkimg/image.h
@@ -0,0 +1,41 @@
+/*-
+ * 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_IMAGE_H_
+#define _MKIMG_IMAGE_H_
+
+typedef int64_t lba_t;
+
+int image_copyin(lba_t blk, int fd, uint64_t *sizep);
+int image_copyout(int fd);
+lba_t image_get_size(void);
+int image_init(void);
+int image_set_size(lba_t blk);
+int image_write(lba_t blk, void *buf, ssize_t len);
+
+#endif /* _MKIMG_IMAGE_H_ */
diff --git a/usr.bin/mkimg/mbr.c b/usr.bin/mkimg/mbr.c
new file mode 100644
index 0000000..4b0f242
--- /dev/null
+++ b/usr.bin/mkimg/mbr.c
@@ -0,0 +1,116 @@
+/*-
+ * 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 "image.h"
+#include "mkimg.h"
+#include "scheme.h"
+
+#ifndef DOSPTYP_FAT32
+#define DOSPTYP_FAT32 0x0b
+#endif
+
+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(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 = 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);
diff --git a/usr.bin/mkimg/mkimg.1 b/usr.bin/mkimg/mkimg.1
new file mode 100644
index 0000000..0ed0dac
--- /dev/null
+++ b/usr.bin/mkimg/mkimg.1
@@ -0,0 +1,181 @@
+.\" 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 July 2, 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 f Ar format
+.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.
+The image file is a raw disk image by default, but the format of the
+image file can be specified with the
+.Ar format
+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 supported output
+format, or for a detailed description of how to specify partitions, run the
+.Nm
+utility without any arguments.
+.Sh ENVIRONMENT
+.Bl -tag -width "TMPDIR" -compact
+.It Ev TMPDIR
+Directory to put temporary files in; default is
+.Pa /tmp .
+.El
+.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
+The command line given above results in a raw image file.
+This is because no output format was given.
+To create a VMDK image for example, add the
+.Fl f Ar vmdk
+argument to the
+.Nm
+utility and name the output file accordingly.
+.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 first appeared in
+.Fx 10.1 .
+.Sh AUTHORS
+The
+.Nm
+utility and manpage were written by Marcel Moolenaar <marcelm@juniper.net>
diff --git a/usr.bin/mkimg/mkimg.c b/usr.bin/mkimg/mkimg.c
new file mode 100644
index 0000000..45d09d5
--- /dev/null
+++ b/usr.bin/mkimg/mkimg.c
@@ -0,0 +1,469 @@
+/*-
+ * 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 "image.h"
+#include "format.h"
+#include "mkimg.h"
+#include "scheme.h"
+
+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 void
+usage(const char *why)
+{
+ struct mkimg_format *f, **f_iter;
+ struct mkimg_scheme *s, **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-f <format>\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, "\n formats:\n");
+ SET_FOREACH(f_iter, formats) {
+ f = *f_iter;
+ fprintf(stderr, "\t%s\t- %s\n", f->name, f->description);
+ }
+
+ fprintf(stderr, "\n schemes:\n");
+ SET_FOREACH(s_iter, schemes) {
+ s = *s_iter;
+ fprintf(stderr, "\t%s\t- %s\n", s->name, s->description);
+ }
+
+ fprintf(stderr, "\n 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)
+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 */
+
+static void
+mkimg(void)
+{
+ FILE *fp;
+ struct part *part;
+ lba_t block;
+ off_t bytesize;
+ int error, fd;
+
+ /* 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;
+ 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 = format_resize(block);
+ if (error)
+ errc(EX_IOERR, error, "image sizing");
+ block = image_get_size();
+ 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(argc, argv, "b:f: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 '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 '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 (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);
+ 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);
+}
diff --git a/usr.bin/mkimg/mkimg.h b/usr.bin/mkimg/mkimg.h
new file mode 100644
index 0000000..290ca1e
--- /dev/null
+++ b/usr.bin/mkimg/mkimg.h
@@ -0,0 +1,74 @@
+/*-
+ * 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>
+
+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));
+}
+
+#if !defined(SPARSE_WRITE)
+#define sparse_write write
+#else
+ssize_t sparse_write(int, const void *, size_t);
+#endif
+
+#endif /* _MKIMG_MKIMG_H_ */
diff --git a/usr.bin/mkimg/pc98.c b/usr.bin/mkimg/pc98.c
new file mode 100644
index 0000000..24b9156
--- /dev/null
+++ b/usr.bin/mkimg/pc98.c
@@ -0,0 +1,127 @@
+/*-
+ * 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 "image.h"
+#include "mkimg.h"
+#include "scheme.h"
+
+#ifndef PC98_MAGIC
+#define PC98_MAGIC 0xaa55
+#endif
+#ifndef PC98_MAGICOFS
+#define PC98_MAGICOFS 510
+#endif
+#ifndef PC98_NPARTS
+#define PC98_NPARTS 16
+#endif
+#ifndef PC98_PTYP_386BSD
+#define PC98_PTYP_386BSD 0xc494
+#endif
+
+#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(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 = 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);
diff --git a/usr.bin/mkimg/raw.c b/usr.bin/mkimg/raw.c
new file mode 100644
index 0000000..ea13931
--- /dev/null
+++ b/usr.bin/mkimg/raw.c
@@ -0,0 +1,63 @@
+/*-
+ * 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 "image.h"
+#include "format.h"
+#include "mkimg.h"
+
+static int
+raw_resize(lba_t imgsz __unused)
+{
+
+ return (0);
+}
+
+static int
+raw_write(int fd)
+{
+
+ return (image_copyout(fd));
+}
+
+static struct mkimg_format raw_format = {
+ .name = "raw",
+ .description = "Raw Disk",
+ .resize = raw_resize,
+ .write = raw_write,
+};
+
+FORMAT_DEFINE(raw_format);
diff --git a/usr.bin/mkimg/scheme.c b/usr.bin/mkimg/scheme.c
new file mode 100644
index 0000000..7546ae2
--- /dev/null
+++ b/usr.bin/mkimg/scheme.c
@@ -0,0 +1,188 @@
+/*-
+ * 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 "image.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;
+
+ if (scheme->bootcode == 0)
+ return (ENXIO);
+
+ if (fstat(fd, &sb) == -1)
+ return (errno);
+ 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(lba_t end)
+{
+ int error;
+
+ end = image_get_size();
+ error = scheme->write(end, bootcode);
+ return (error);
+}
diff --git a/usr.bin/mkimg/scheme.h b/usr.bin/mkimg/scheme.h
new file mode 100644
index 0000000..8224930
--- /dev/null
+++ b/usr.bin/mkimg/scheme.h
@@ -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)(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(lba_t);
+
+#endif /* _MKIMG_SCHEME_H_ */
diff --git a/usr.bin/mkimg/vmdk.c b/usr.bin/mkimg/vmdk.c
new file mode 100644
index 0000000..b277003
--- /dev/null
+++ b/usr.bin/mkimg/vmdk.c
@@ -0,0 +1,226 @@
+/*-
+ * 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 <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "image.h"
+#include "format.h"
+#include "mkimg.h"
+
+#define VMDK_IMAGE_ROUND 1048576
+#define VMDK_MIN_GRAIN_SIZE 8192
+#define VMDK_SECTOR_SIZE 512
+
+struct vmdk_header {
+ uint32_t magic;
+#define VMDK_MAGIC 0x564d444b
+ uint32_t version;
+#define VMDK_VERSION 1
+ uint32_t flags;
+#define VMDK_FLAGS_NL_TEST (1 << 0)
+#define VMDK_FLAGS_RGT_USED (1 << 1)
+#define VMDK_FLAGS_COMPRESSED (1 << 16)
+#define VMDK_FLAGS_MARKERS (1 << 17)
+ uint64_t capacity;
+ uint64_t grain_size;
+ uint64_t desc_offset;
+ uint64_t desc_size;
+ uint32_t ngtes;
+#define VMDK_NGTES 512
+ uint64_t rgd_offset;
+ uint64_t gd_offset;
+ uint64_t overhead;
+ uint8_t unclean;
+ uint32_t nl_test;
+#define VMDK_NL_TEST 0x0a200d0a
+ uint16_t compress;
+#define VMDK_COMPRESS_NONE 0
+#define VMDK_COMPRESS_DEFLATE 1
+ char padding[433];
+} __attribute__((__packed__));
+
+static const char desc_fmt[] =
+ "# Disk DescriptorFile\n"
+ "version=%d\n"
+ "CID=%08x\n"
+ "parentCID=ffffffff\n"
+ "createType=\"monolithicSparse\"\n"
+ "# Extent description\n"
+ "RW %ju SPARSE \"%s\"\n"
+ "# The Disk Data Base\n"
+ "#DDB\n"
+ "ddb.adapterType = \"ide\"\n"
+ "ddb.geometry.cylinders = \"%u\"\n"
+ "ddb.geometry.heads = \"%u\"\n"
+ "ddb.geometry.sectors = \"%u\"\n";
+
+static uint64_t grainsz;
+
+static int
+vmdk_resize(lba_t imgsz)
+{
+ uint64_t imagesz;
+
+ imagesz = imgsz * secsz;
+ imagesz = (imagesz + VMDK_IMAGE_ROUND - 1) & ~(VMDK_IMAGE_ROUND - 1);
+ grainsz = (blksz < VMDK_MIN_GRAIN_SIZE) ? VMDK_MIN_GRAIN_SIZE : blksz;
+
+ if (verbose)
+ fprintf(stderr, "VMDK: image size = %ju, grain size = %ju\n",
+ (uintmax_t)imagesz, (uintmax_t)grainsz);
+
+ grainsz /= VMDK_SECTOR_SIZE;
+ return (image_set_size(imagesz / secsz));
+}
+
+static int
+vmdk_write(int fd)
+{
+ struct vmdk_header hdr;
+ uint32_t *gt, *gd;
+ char *buf, *desc;
+ off_t cur, lim;
+ uint64_t imagesz;
+ size_t gdsz, gtsz;
+ uint32_t sec;
+ int error, desc_len, n, ngrains, ngts;
+
+ imagesz = (image_get_size() * secsz) / VMDK_SECTOR_SIZE;
+
+ memset(&hdr, 0, sizeof(hdr));
+ le32enc(&hdr.magic, VMDK_MAGIC);
+ le32enc(&hdr.version, VMDK_VERSION);
+ le32enc(&hdr.flags, VMDK_FLAGS_NL_TEST | VMDK_FLAGS_RGT_USED);
+ le64enc(&hdr.capacity, imagesz);
+ le64enc(&hdr.grain_size, grainsz);
+
+ n = asprintf(&desc, desc_fmt, 1 /*version*/, 0 /*CID*/,
+ (uintmax_t)imagesz /*size*/, "" /*name*/,
+ ncyls /*cylinders*/, nheads /*heads*/, nsecs /*sectors*/);
+ if (n == -1)
+ return (ENOMEM);
+
+ desc_len = (n + VMDK_SECTOR_SIZE - 1) & ~(VMDK_SECTOR_SIZE - 1);
+ desc = realloc(desc, desc_len);
+ memset(desc + n, 0, desc_len - n);
+
+ le64enc(&hdr.desc_offset, 1);
+ le64enc(&hdr.desc_size, desc_len / VMDK_SECTOR_SIZE);
+ le32enc(&hdr.ngtes, VMDK_NGTES);
+
+ sec = desc_len / VMDK_SECTOR_SIZE + 1;
+ le64enc(&hdr.rgd_offset, sec);
+ le64enc(&hdr.gd_offset, sec);
+
+ ngrains = imagesz / grainsz;
+ ngts = (ngrains + VMDK_NGTES - 1) / VMDK_NGTES;
+ gdsz = (ngts * sizeof(uint32_t) + VMDK_SECTOR_SIZE - 1) &
+ ~(VMDK_SECTOR_SIZE - 1);
+ gd = calloc(gdsz, 1);
+ if (gd == NULL) {
+ free(desc);
+ return (ENOMEM);
+ }
+
+ sec += gdsz / VMDK_SECTOR_SIZE;
+ for (n = 0; n < ngts; n++) {
+ le32enc(gd + n, sec);
+ sec += VMDK_NGTES * sizeof(uint32_t) / VMDK_SECTOR_SIZE;
+ }
+
+ sec = (sec + grainsz - 1) & ~(grainsz - 1);
+
+ if (verbose)
+ fprintf(stderr, "VMDK: overhead = %ju\n",
+ (uintmax_t)(sec * VMDK_SECTOR_SIZE));
+
+ le64enc(&hdr.overhead, sec);
+ be32enc(&hdr.nl_test, VMDK_NL_TEST);
+
+ gtsz = ngts * VMDK_NGTES * sizeof(uint32_t);
+ gt = calloc(gtsz, 1);
+ if (gt == NULL) {
+ free(gd);
+ free(desc);
+ return (ENOMEM);
+ }
+
+ for (n = 0; n < ngrains; n++)
+ le32enc(gt + n, sec + n * grainsz);
+
+ error = 0;
+ if (!error && sparse_write(fd, &hdr, VMDK_SECTOR_SIZE) < 0)
+ error = errno;
+ if (!error && sparse_write(fd, desc, desc_len) < 0)
+ error = errno;
+ if (!error && sparse_write(fd, gd, gdsz) < 0)
+ error = errno;
+ if (!error && sparse_write(fd, gt, gtsz) < 0)
+ error = errno;
+ free(gt);
+ free(gd);
+ free(desc);
+ if (error)
+ return (error);
+
+ cur = VMDK_SECTOR_SIZE + desc_len + gdsz + gtsz;
+ lim = sec * VMDK_SECTOR_SIZE;
+ if (cur < lim) {
+ buf = calloc(VMDK_SECTOR_SIZE, 1);
+ if (buf == NULL)
+ error = ENOMEM;
+ while (!error && cur < lim) {
+ if (sparse_write(fd, buf, VMDK_SECTOR_SIZE) < 0)
+ error = errno;
+ cur += VMDK_SECTOR_SIZE;
+ }
+ if (buf != NULL)
+ free(buf);
+ }
+ if (!error)
+ error = image_copyout(fd);
+ return (error);
+}
+
+static struct mkimg_format vmdk_format = {
+ .name = "vmdk",
+ .description = "Virtual Machine Disk",
+ .resize = vmdk_resize,
+ .write = vmdk_write,
+};
+
+FORMAT_DEFINE(vmdk_format);
diff --git a/usr.bin/mkimg/vtoc8.c b/usr.bin/mkimg/vtoc8.c
new file mode 100644
index 0000000..8eb7d24
--- /dev/null
+++ b/usr.bin/mkimg/vtoc8.c
@@ -0,0 +1,123 @@
+/*-
+ * 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 "image.h"
+#include "mkimg.h"
+#include "scheme.h"
+
+#ifndef VTOC_TAG_FREEBSD_NANDFS
+#define VTOC_TAG_FREEBSD_NANDFS 0x0905
+#endif
+
+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(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);
+
+ error = image_set_size(imgsz);
+ if (error)
+ return (error);
+
+ 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 = 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);
OpenPOWER on IntegriCloud