MFuser/marcel/mkimg:

Add support for different output formats:
1.  The output file that was previously written is now called the raw format.
2.  Add the vmdk output format to create VMDK images.

When the format is not given, the raw output format is assumed.
This commit is contained in:
Marcel Moolenaar 2014-05-15 19:19:57 +00:00
parent e4988af98e
commit f0e9dced5c
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=266176
19 changed files with 775 additions and 160 deletions

View File

@ -1,11 +1,16 @@
# $FreeBSD$
PROG= mkimg
SRCS= mkimg.c scheme.c
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 \

View File

@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$");
#include <string.h>
#include <unistd.h>
#include "image.h"
#include "mkimg.h"
#include "scheme.h"
@ -63,7 +64,7 @@ apm_metadata(u_int where)
}
static int
apm_write(int fd, lba_t imgsz, void *bootcode __unused)
apm_write(lba_t imgsz, void *bootcode __unused)
{
u_char *buf;
struct apm_ddr *ddr;
@ -99,7 +100,7 @@ apm_write(int fd, lba_t imgsz, void *bootcode __unused)
strcpy(ent->ent_name, part->label);
}
error = mkimg_write(fd, 0, buf, nparts + 2);
error = image_write(0, buf, nparts + 2);
free(buf);
return (error);
}

View File

@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$");
#include <string.h>
#include <unistd.h>
#include "image.h"
#include "mkimg.h"
#include "scheme.h"
@ -61,7 +62,7 @@ bsd_metadata(u_int where)
}
static int
bsd_write(int fd, lba_t imgsz, void *bootcode)
bsd_write(lba_t imgsz, void *bootcode)
{
u_char *buf, *p;
struct disklabel *d;
@ -80,7 +81,9 @@ bsd_write(int fd, lba_t imgsz, void *bootcode)
memset(buf, 0, BBSIZE);
imgsz = ncyls * nheads * nsecs;
ftruncate(fd, imgsz * secsz);
error = image_set_size(imgsz);
if (error)
return (error);
d = (void *)(buf + secsz);
le32enc(&d->d_magic, DISKMAGIC);
@ -111,7 +114,7 @@ bsd_write(int fd, lba_t imgsz, void *bootcode)
checksum ^= le16dec(p);
le16enc(&d->d_checksum, checksum);
error = mkimg_write(fd, 0, buf, BBSIZE / secsz);
error = image_write(0, buf, BBSIZE / secsz);
free(buf);
return (error);
}

View File

@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$");
#include <string.h>
#include <unistd.h>
#include "image.h"
#include "mkimg.h"
#include "scheme.h"
@ -67,7 +68,7 @@ ebr_chs(u_char *cyl, u_char *hd, u_char *sec, uint32_t lba __unused)
}
static int
ebr_write(int fd, lba_t imgsz __unused, void *bootcode __unused)
ebr_write(lba_t imgsz __unused, void *bootcode __unused)
{
u_char *ebr;
struct dos_partition *dp;
@ -104,7 +105,7 @@ ebr_write(int fd, lba_t imgsz __unused, void *bootcode __unused)
le32enc(&dp->dp_size, next->size + nsecs);
}
error = mkimg_write(fd, block, ebr, 1);
error = image_write(block, ebr, 1);
if (error)
break;

91
usr.bin/mkimg/format.c Normal file
View File

@ -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);
}

49
usr.bin/mkimg/format.h Normal file
View File

@ -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_ */

View File

@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$");
#include <unistd.h>
#include <uuid.h>
#include "image.h"
#include "mkimg.h"
#include "scheme.h"
@ -166,7 +167,7 @@ gpt_metadata(u_int where)
}
static int
gpt_write_pmbr(int fd, lba_t blks, void *bootcode)
gpt_write_pmbr(lba_t blks, void *bootcode)
{
u_char *pmbr;
uint32_t secs;
@ -190,7 +191,7 @@ gpt_write_pmbr(int fd, lba_t blks, void *bootcode)
le32enc(pmbr + DOSPARTOFF + 8, 1);
le32enc(pmbr + DOSPARTOFF + 12, secs);
le16enc(pmbr + DOSMAGICOFFSET, DOSMAGIC);
error = mkimg_write(fd, 0, pmbr, 1);
error = image_write(0, pmbr, 1);
free(pmbr);
return (error);
}
@ -226,8 +227,7 @@ gpt_mktbl(u_int tblsz)
}
static int
gpt_write_hdr(int fd, struct gpt_hdr *hdr, uint64_t self, uint64_t alt,
uint64_t tbl)
gpt_write_hdr(struct gpt_hdr *hdr, uint64_t self, uint64_t alt, uint64_t tbl)
{
uint32_t crc;
@ -237,11 +237,11 @@ gpt_write_hdr(int fd, struct gpt_hdr *hdr, uint64_t self, uint64_t alt,
hdr->hdr_crc_self = 0;
crc = crc32(hdr, offsetof(struct gpt_hdr, padding));
le64enc(&hdr->hdr_crc_self, crc);
return (mkimg_write(fd, self, hdr, 1));
return (image_write(self, hdr, 1));
}
static int
gpt_write(int fd, lba_t imgsz, void *bootcode)
gpt_write(lba_t imgsz, void *bootcode)
{
uuid_t uuid;
struct gpt_ent *tbl;
@ -251,7 +251,7 @@ gpt_write(int fd, lba_t imgsz, void *bootcode)
int error;
/* PMBR */
error = gpt_write_pmbr(fd, imgsz, bootcode);
error = gpt_write_pmbr(imgsz, bootcode);
if (error)
return (error);
@ -260,10 +260,10 @@ gpt_write(int fd, lba_t imgsz, void *bootcode)
tbl = gpt_mktbl(tblsz);
if (tbl == NULL)
return (errno);
error = mkimg_write(fd, 2, tbl, tblsz);
error = image_write(2, tbl, tblsz);
if (error)
goto out;
error = mkimg_write(fd, imgsz - (tblsz + 1), tbl, tblsz);
error = image_write(imgsz - (tblsz + 1), tbl, tblsz);
if (error)
goto out;
@ -285,9 +285,9 @@ gpt_write(int fd, lba_t imgsz, void *bootcode)
le32enc(&hdr->hdr_entsz, sizeof(struct gpt_ent));
crc = crc32(tbl, nparts * sizeof(struct gpt_ent));
le32enc(&hdr->hdr_crc_table, crc);
error = gpt_write_hdr(fd, hdr, 1, imgsz - 1, 2);
error = gpt_write_hdr(hdr, 1, imgsz - 1, 2);
if (!error)
error = gpt_write_hdr(fd, hdr, imgsz - 1, 1, imgsz - tblsz - 1);
error = gpt_write_hdr(hdr, imgsz - 1, 1, imgsz - tblsz - 1);
free(hdr);
out:

167
usr.bin/mkimg/image.c Normal file
View File

@ -0,0 +1,167 @@
/*-
* 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 <stdlib.h>
#include <unistd.h>
#include "image.h"
#include "mkimg.h"
#define BUFFER_SIZE (1024*1024)
static char image_tmpfile[] = "/tmp/mkimg-XXXXXX";
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);
buffer = malloc(BUFFER_SIZE);
if (buffer == NULL)
return (errno);
if (lseek(image_fd, 0, SEEK_SET) != 0)
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);
ofs = lseek(fd, 0L, SEEK_CUR);
ftruncate(fd, ofs);
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)
{
if (atexit(cleanup) == -1)
return (errno);
image_fd = mkstemp(image_tmpfile);
if (image_fd == -1)
return (errno);
return (0);
}

41
usr.bin/mkimg/image.h Normal file
View File

@ -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_ */

View File

@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$");
#include <string.h>
#include <unistd.h>
#include "image.h"
#include "mkimg.h"
#include "scheme.h"
@ -68,7 +69,7 @@ mbr_chs(u_char *cyl, u_char *hd, u_char *sec, uint32_t lba __unused)
}
static int
mbr_write(int fd, lba_t imgsz __unused, void *bootcode)
mbr_write(lba_t imgsz __unused, void *bootcode)
{
u_char *mbr;
struct dos_partition *dpbase, *dp;
@ -96,7 +97,7 @@ mbr_write(int fd, lba_t imgsz __unused, void *bootcode)
le32enc(&dp->dp_start, part->block);
le32enc(&dp->dp_size, part->size);
}
error = mkimg_write(fd, 0, mbr, 1);
error = image_write(0, mbr, 1);
free(mbr);
return (error);
}

View File

@ -37,6 +37,7 @@
.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
@ -56,6 +57,10 @@ The disk image is written to
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
@ -106,8 +111,8 @@ option increases the level of output that the
.Nm
utility prints.
.Pp
For a complete list of supported partitioning schemes or for a detailed
description of how to specify partitions, run the
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 EXAMPLES
@ -121,6 +126,14 @@ utility as follows:
-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.

View File

@ -42,15 +42,11 @@ __FBSDID("$FreeBSD$");
#include <sysexits.h>
#include <unistd.h>
#include "image.h"
#include "format.h"
#include "mkimg.h"
#include "scheme.h"
#if !defined(SPARSE_WRITE)
#define sparse_write write
#endif
#define BUFFER_SIZE (1024*1024)
struct partlisthead partlist = STAILQ_HEAD_INITIALIZER(partlist);
u_int nparts = 0;
@ -62,31 +58,18 @@ u_int nsecs = 1;
u_int secsz = 512;
u_int blksz = 0;
static int bcfd = -1;
static int outfd = 0;
static int tmpfd = -1;
static char tmpfname[] = "/tmp/mkimg-XXXXXX";
static void
cleanup(void)
{
if (tmpfd != -1)
close(tmpfd);
unlink(tmpfname);
}
static void
usage(const char *why)
{
struct mkimg_scheme *s, **iter;
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");
@ -95,13 +78,19 @@ usage(const char *why)
fprintf(stderr, "\t-S <num>\t- logical sector size\n");
fprintf(stderr, "\t-T <num>\t- number of tracks to simulate\n");
fprintf(stderr, " schemes:\n");
SET_FOREACH(iter, schemes) {
s = *iter;
fprintf(stderr, "\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, " partition specification:\n");
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 "
@ -228,14 +217,15 @@ parse_part(const char *spec)
}
#if defined(SPARSE_WRITE)
static ssize_t
sparse_write(int fd, const char *buf, size_t sz)
ssize_t
sparse_write(int fd, const void *ptr, size_t sz)
{
const char *p;
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) {
@ -268,66 +258,8 @@ sparse_write(int fd, const char *buf, size_t sz)
}
#endif /* SPARSE_WRITE */
static int
fdcopy(int src, int dst, uint64_t *count)
{
char *buffer;
off_t ofs;
ssize_t rdsz, wrsz;
/* A return value of -1 means that we can't write a sparse file. */
ofs = lseek(dst, 0L, SEEK_CUR);
if (count != NULL)
*count = 0;
buffer = malloc(BUFFER_SIZE);
if (buffer == NULL)
return (errno);
while (1) {
rdsz = read(src, buffer, BUFFER_SIZE);
if (rdsz <= 0) {
free(buffer);
return ((rdsz < 0) ? errno : 0);
}
if (count != NULL)
*count += rdsz;
wrsz = (ofs == -1) ?
write(dst, buffer, rdsz) :
sparse_write(dst, buffer, rdsz);
if (wrsz < 0)
break;
}
free(buffer);
return (errno);
}
static int
mkimg_seek(int fd, lba_t blk)
{
off_t off;
off = blk * secsz;
if (lseek(fd, off, SEEK_SET) != off)
return (errno);
return (0);
}
int
mkimg_write(int fd, lba_t blk, void *buf, ssize_t len)
{
blk *= secsz;
if (lseek(fd, blk, SEEK_SET) != blk)
return (errno);
len *= secsz;
if (write(fd, buf, len) != len)
return (errno);
return (0);
}
static void
mkimg(int bfd)
mkimg(void)
{
FILE *fp;
struct part *part;
@ -335,10 +267,6 @@ mkimg(int bfd)
off_t bytesize;
int error, fd;
error = scheme_bootcode(bfd);
if (error)
errc(EX_DATAERR, error, "boot code");
/* First check partition information */
STAILQ_FOREACH(part, &partlist, link) {
error = scheme_check_part(part);
@ -353,7 +281,6 @@ mkimg(int bfd)
fprintf(stderr, "partition %d: starting block %llu "
"... ", part->index + 1, (long long)block);
part->block = block;
error = mkimg_seek(tmpfd, block);
switch (part->kind) {
case PART_KIND_SIZE:
if (expand_number(part->contents, &bytesize) == -1)
@ -362,7 +289,7 @@ mkimg(int bfd)
case PART_KIND_FILE:
fd = open(part->contents, O_RDONLY, 0);
if (fd != -1) {
error = fdcopy(fd, tmpfd, &bytesize);
error = image_copyin(block, fd, &bytesize);
close(fd);
} else
error = errno;
@ -370,7 +297,8 @@ mkimg(int bfd)
case PART_KIND_PIPE:
fp = popen(part->contents, "r");
if (fp != NULL) {
error = fdcopy(fileno(fp), tmpfd, &bytesize);
fd = fileno(fp);
error = image_copyin(block, fd, &bytesize);
pclose(fp);
} else
error = errno;
@ -389,15 +317,27 @@ mkimg(int bfd)
}
block = scheme_metadata(SCHEME_META_IMG_END, block);
error = (scheme_write(tmpfd, 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;
while ((c = getopt(argc, argv, "b:o:p:s:vH:P:S:T:")) != -1) {
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)
@ -406,8 +346,15 @@ main(int argc, char *argv[])
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 != 0)
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);
@ -480,35 +427,43 @@ main(int argc, char *argv[])
errx(EX_DATAERR, "%d partitions supported; %d given",
scheme_max_parts(), nparts);
if (outfd == 0) {
if (atexit(cleanup) == -1)
err(EX_OSERR, "cannot register cleanup function");
outfd = 1;
tmpfd = mkstemp(tmpfname);
if (tmpfd == -1)
err(EX_OSERR, "cannot create temporary file");
} else
tmpfd = outfd;
if (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);
}
mkimg(bcfd);
error = image_init();
if (error)
errc(EX_OSERR, error, "cannot initialize");
if (verbose)
mkimg();
if (verbose) {
fputc('\n', stderr);
fprintf(stderr, "Number of cylinders: %u\n", ncyls);
if (tmpfd != outfd) {
error = mkimg_seek(tmpfd, 0);
if (error == 0)
error = fdcopy(tmpfd, outfd, NULL);
if (error)
errc(EX_IOERR, error, "writing to stdout");
}
error = format_write(outfd);
if (error)
errc(EX_IOERR, error, "writing image");
return (0);
}

View File

@ -31,8 +31,6 @@
#include <sys/queue.h>
typedef int64_t lba_t;
struct part {
STAILQ_ENTRY(part) link;
char *alias; /* Partition type alias. */
@ -67,6 +65,10 @@ round_block(lba_t n)
return ((n + b - 1) & ~(b - 1));
}
int mkimg_write(int fd, lba_t blk, void *buf, ssize_t len);
#if !defined(SPARSE_WRITE)
#define sparse_write write
#else
ssize_t sparse_write(int, const void *, size_t);
#endif
#endif /* _MKIMG_MKIMG_H_ */

View File

@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$");
#include <string.h>
#include <unistd.h>
#include "image.h"
#include "mkimg.h"
#include "scheme.h"
@ -77,7 +78,7 @@ pc98_chs(u_short *cyl, u_char *hd, u_char *sec, uint32_t lba __unused)
}
static int
pc98_write(int fd, lba_t imgsz __unused, void *bootcode)
pc98_write(lba_t imgsz __unused, void *bootcode)
{
struct part *part;
struct pc98_partition *dpbase, *dp;
@ -106,7 +107,7 @@ pc98_write(int fd, lba_t imgsz __unused, void *bootcode)
if (part->label != NULL)
memcpy(dp->dp_name, part->label, strlen(part->label));
}
error = mkimg_write(fd, 0, buf, PC98_BOOTCODESZ / secsz);
error = image_write(0, buf, PC98_BOOTCODESZ / secsz);
free(buf);
return (error);
}

63
usr.bin/mkimg/raw.c Normal file
View File

@ -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);

View File

@ -38,6 +38,7 @@ __FBSDID("$FreeBSD$");
#include <string.h>
#include <unistd.h>
#include "image.h"
#include "mkimg.h"
#include "scheme.h"
@ -104,8 +105,6 @@ scheme_bootcode(int fd)
struct stat sb;
int error;
if (fd == -1)
return (0);
if (scheme->bootcode == 0)
return (ENXIO);
@ -181,17 +180,11 @@ scheme_metadata(u_int where, lba_t start)
}
int
scheme_write(int fd, lba_t end)
scheme_write(lba_t end)
{
u_int cylsz;
int error;
cylsz = nsecs * nheads;
ncyls = (end + cylsz - 1) / cylsz;
if (ftruncate(fd, end * secsz) == -1)
return (errno);
error = scheme->write(fd, end, bootcode);
end = image_get_size();
error = scheme->write(end, bootcode);
return (error);
}

View File

@ -67,7 +67,7 @@ struct mkimg_scheme {
#define SCHEME_META_IMG_END 2
#define SCHEME_META_PART_BEFORE 3
#define SCHEME_META_PART_AFTER 4
int (*write)(int, lba_t, void *);
int (*write)(lba_t, void *);
u_int nparts;
u_int labellen;
u_int bootcode;
@ -85,6 +85,6 @@ int scheme_check_part(struct part *);
u_int scheme_max_parts(void);
u_int scheme_max_secsz(void);
lba_t scheme_metadata(u_int, lba_t);
int scheme_write(int, lba_t);
int scheme_write(lba_t);
#endif /* _MKIMG_SCHEME_H_ */

226
usr.bin/mkimg/vmdk.c Normal file
View File

@ -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);

View File

@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$");
#include <string.h>
#include <unistd.h>
#include "image.h"
#include "mkimg.h"
#include "scheme.h"
@ -62,7 +63,7 @@ vtoc8_metadata(u_int where)
}
static int
vtoc8_write(int fd, lba_t imgsz, void *bootcode __unused)
vtoc8_write(lba_t imgsz, void *bootcode __unused)
{
struct vtoc8 vtoc8;
struct part *part;
@ -86,7 +87,9 @@ vtoc8_write(int fd, lba_t imgsz, void *bootcode __unused)
be16enc(&vtoc8.nsecs, nsecs);
be16enc(&vtoc8.magic, VTOC_MAGIC);
ftruncate(fd, imgsz * secsz);
error = image_set_size(imgsz);
if (error)
return (error);
be32enc(&vtoc8.map[VTOC_RAW_PART].nblks, imgsz);
STAILQ_FOREACH(part, &partlist, link) {
@ -103,7 +106,7 @@ vtoc8_write(int fd, lba_t imgsz, void *bootcode __unused)
sum ^= be16dec(p + ofs);
be16enc(&vtoc8.cksum, sum);
error = mkimg_write(fd, 0, &vtoc8, 1);
error = image_write(0, &vtoc8, 1);
return (error);
}