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:
commit
1e7c9712cd
@ -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 \
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
91
usr.bin/mkimg/format.c
Normal 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
49
usr.bin/mkimg/format.h
Normal 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_ */
|
@ -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
167
usr.bin/mkimg/image.c
Normal 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
41
usr.bin/mkimg/image.h
Normal 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_ */
|
@ -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);
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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_ */
|
||||
|
@ -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
63
usr.bin/mkimg/raw.c
Normal 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);
|
@ -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);
|
||||
}
|
||||
|
@ -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
226
usr.bin/mkimg/vmdk.c
Normal 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);
|
@ -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);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user