summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--usr.bin/mkimg/gpt.c2
-rw-r--r--usr.bin/mkimg/image.c12
-rw-r--r--usr.bin/mkimg/image.h1
-rw-r--r--usr.bin/mkimg/mbr.c1
-rw-r--r--usr.bin/mkimg/mkimg.187
-rw-r--r--usr.bin/mkimg/scheme.c1
-rw-r--r--usr.bin/mkimg/scheme.h1
-rw-r--r--usr.bin/mkimg/vhd.c92
8 files changed, 151 insertions, 46 deletions
diff --git a/usr.bin/mkimg/gpt.c b/usr.bin/mkimg/gpt.c
index 5773a6a..678e636 100644
--- a/usr.bin/mkimg/gpt.c
+++ b/usr.bin/mkimg/gpt.c
@@ -57,6 +57,7 @@ static uuid_t gpt_uuid_freebsd_ufs = GPT_ENT_TYPE_FREEBSD_UFS;
static uuid_t gpt_uuid_freebsd_vinum = GPT_ENT_TYPE_FREEBSD_VINUM;
static uuid_t gpt_uuid_freebsd_zfs = GPT_ENT_TYPE_FREEBSD_ZFS;
static uuid_t gpt_uuid_mbr = GPT_ENT_TYPE_MBR;
+static uuid_t gpt_uuid_ms_basic_data = GPT_ENT_TYPE_MS_BASIC_DATA;
static struct mkimg_alias gpt_aliases[] = {
{ ALIAS_EFI, ALIAS_PTR2TYPE(&gpt_uuid_efi) },
@@ -68,6 +69,7 @@ static struct mkimg_alias gpt_aliases[] = {
{ ALIAS_FREEBSD_VINUM, ALIAS_PTR2TYPE(&gpt_uuid_freebsd_vinum) },
{ ALIAS_FREEBSD_ZFS, ALIAS_PTR2TYPE(&gpt_uuid_freebsd_zfs) },
{ ALIAS_MBR, ALIAS_PTR2TYPE(&gpt_uuid_mbr) },
+ { ALIAS_NTFS, ALIAS_PTR2TYPE(&gpt_uuid_ms_basic_data) },
{ ALIAS_NONE, 0 } /* Keep last! */
};
diff --git a/usr.bin/mkimg/image.c b/usr.bin/mkimg/image.c
index be1c2e9..a3bec63 100644
--- a/usr.bin/mkimg/image.c
+++ b/usr.bin/mkimg/image.c
@@ -517,14 +517,14 @@ image_copyout_memory(int fd, size_t size, void *ptr)
return (0);
}
-static int
-image_copyout_zeroes(int fd, size_t size)
+int
+image_copyout_zeroes(int fd, size_t count)
{
static uint8_t *zeroes = NULL;
size_t sz;
int error;
- if (lseek(fd, (off_t)size, SEEK_CUR) != -1)
+ if (lseek(fd, (off_t)count, SEEK_CUR) != -1)
return (0);
/*
@@ -537,12 +537,12 @@ image_copyout_zeroes(int fd, size_t size)
return (ENOMEM);
}
- while (size > 0) {
- sz = (size > secsz) ? secsz : size;
+ while (count > 0) {
+ sz = (count > secsz) ? secsz : count;
error = image_copyout_memory(fd, sz, zeroes);
if (error)
return (error);
- size -= sz;
+ count -= sz;
}
return (0);
}
diff --git a/usr.bin/mkimg/image.h b/usr.bin/mkimg/image.h
index ce195d9..0405c5b 100644
--- a/usr.bin/mkimg/image.h
+++ b/usr.bin/mkimg/image.h
@@ -35,6 +35,7 @@ int image_copyin(lba_t blk, int fd, uint64_t *sizep);
int image_copyout(int fd);
int image_copyout_done(int fd);
int image_copyout_region(int fd, lba_t blk, lba_t size);
+int image_copyout_zeroes(int fd, size_t count);
int image_data(lba_t blk, lba_t size);
lba_t image_get_size(void);
int image_init(void);
diff --git a/usr.bin/mkimg/mbr.c b/usr.bin/mkimg/mbr.c
index 9d737a5..961ca45 100644
--- a/usr.bin/mkimg/mbr.c
+++ b/usr.bin/mkimg/mbr.c
@@ -51,6 +51,7 @@ static struct mkimg_alias mbr_aliases[] = {
{ ALIAS_EFI, ALIAS_INT2TYPE(DOSPTYP_EFI) },
{ ALIAS_FAT32, ALIAS_INT2TYPE(DOSPTYP_FAT32) },
{ ALIAS_FREEBSD, ALIAS_INT2TYPE(DOSPTYP_386BSD) },
+ { ALIAS_NTFS, ALIAS_INT2TYPE(DOSPTYP_NTFS) },
{ ALIAS_NONE, 0 } /* Keep last! */
};
diff --git a/usr.bin/mkimg/mkimg.1 b/usr.bin/mkimg/mkimg.1
index 3b1d63e..1fecdd2 100644
--- a/usr.bin/mkimg/mkimg.1
+++ b/usr.bin/mkimg/mkimg.1
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd February 22, 2015
+.Dd August 7, 2015
.Dt MKIMG 1
.Os
.Sh NAME
@@ -141,7 +141,7 @@ utility will create images that are identical.
.Pp
A set of long options exist to query about the
.Nm
-utilty itself.
+utility itself.
Options in this set should be given by themselves because the
.Nm
utility exits immediately after providing the requested information.
@@ -165,6 +165,85 @@ run the
.Nm
utility without any arguments.
This will print a usage message with all the necessary details.
+.Sh DISK FORMATS
+The
+.Nm
+utility supports a number of output file formats.
+A short description of these is given below.
+.Ss QCOW and QCOW2
+QCOW stands for "QEMU Copy On Write".
+It's a sparse file format akin to VHD and VMDK and QCOW represents the
+first version.
+QCOW2 represents version 2 of the file format.
+Version 2 is not backward compatible with version 1 and adds support for
+snapshots among other things.
+The QCOW file formats are natively supported by QEMU and Xen.
+To write QCOW, specify
+.Fl f Ar qcow
+on the command line.
+To write version 2 QCOW, specify
+.Fl f Ar qcow2
+on the command line.
+The preferred file extension is ".qcow" and ".qcow2" for QCOW and QCOW2
+(resp.), but ".qcow" is sometimes used for version 2 files as well.
+.Ss RAW file format
+This file format is a sector by sector representation of an actual disk.
+There is no extra information that describes or relates to the format
+itself. The size of the file is the size of the (virtual) disk.
+This file format is suitable for being copyied onto a disk with utilities
+like
+.Nm dd .
+To write a raw disk file, either omit the
+.Fl f
+option, or specify
+.Fl f Ar raw
+on the command line.
+The preferred file extension is one of ".img" or ".raw", but there's no
+real convention for it.
+.Ss Dynamic VHD and Fixed VHD
+Microsoft's "Virtual Hard Disk" file formats.
+The dynamic format is a sparse format akin to QCOW and VMDK.
+The fixed format is effectively a raw format with a footer appended to the
+file and as such it's often indistinguishable from the raw format.
+The fixed file format has been added to support Microsoft's Azure platform
+and due to inconsistencies in interpretation of the footer is not compatible
+with utilities like
+.Nm qemu
+when it is specifically instructed to interpreted the file as a VHD file.
+By default
+.Nm qemu
+will treat the file as a raw disk file, which mostly works fine.
+To have
+.Nm
+create a dynamic VHD file, specify
+.Fl f Ar vhd
+on the command line.
+To create a fixed VHD file for use by Azure, specify
+.Fl f Ar vhdf
+on the command line.
+The preferred file extension is ".vhd".
+.Ss VMDK
+VMware's "Virtual Machine Disk" file format.
+It's a sparse file format akin to QCOW and VHD and supported by many
+virtualization solutions.
+To create a VMDK file, specify
+.Fl f Ar vmdk
+on the command line.
+The preferred file extension is ".vmdk".
+.Pp
+Not all virtualization solutions support all file formats, but often those
+virtualization environments have utilities to convert from one format to
+another.
+Note however that conversion may require that the virtual disk size is
+changed to match the constraints of the output format and this may invalidate
+the contents of the disk image.
+For example, the GUID Partition Table (GPT) scheme has a header in the last
+sector on the disk.
+When changing the disk size, the GPT must be changed so that the last header
+is moved accordingly.
+This is typically not part of the conversion process.
+If possible, use an output format specifically for the environment in which
+the file is intended to be used.
.Sh ENVIRONMENT
.Bl -tag -width "TMPDIR" -compact
.It Ev TMPDIR
@@ -235,6 +314,7 @@ 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 dd 1 ,
.Xr gpart 8 ,
.Xr makefs 8 ,
.Xr mdconfig 8 ,
@@ -247,4 +327,5 @@ utility first appeared in
.Sh AUTHORS
The
.Nm
-utility and manpage were written by Marcel Moolenaar <marcelm@juniper.net>
+utility and manpage were written by
+.An Marcel Moolenaar Aq Mt marcelm@juniper.net .
diff --git a/usr.bin/mkimg/scheme.c b/usr.bin/mkimg/scheme.c
index 336f953..9bdf8a5 100644
--- a/usr.bin/mkimg/scheme.c
+++ b/usr.bin/mkimg/scheme.c
@@ -59,6 +59,7 @@ static struct {
{ "freebsd-vinum", ALIAS_FREEBSD_VINUM },
{ "freebsd-zfs", ALIAS_FREEBSD_ZFS },
{ "mbr", ALIAS_MBR },
+ { "ntfs", ALIAS_NTFS },
{ NULL, ALIAS_NONE } /* Keep last! */
};
diff --git a/usr.bin/mkimg/scheme.h b/usr.bin/mkimg/scheme.h
index d594a19..73b06eb 100644
--- a/usr.bin/mkimg/scheme.h
+++ b/usr.bin/mkimg/scheme.h
@@ -45,6 +45,7 @@ enum alias {
ALIAS_FREEBSD_VINUM,
ALIAS_FREEBSD_ZFS,
ALIAS_MBR,
+ ALIAS_NTFS,
/* end */
ALIAS_COUNT /* Keep last! */
};
diff --git a/usr.bin/mkimg/vhd.c b/usr.bin/mkimg/vhd.c
index eb93fac..c7d1f84 100644
--- a/usr.bin/mkimg/vhd.c
+++ b/usr.bin/mkimg/vhd.c
@@ -159,6 +159,34 @@ vhd_geometry(uint64_t image_size, struct vhd_geom *geom)
geom->cylinders = cth / geom->heads;
}
+static uint64_t
+vhd_resize(uint64_t origsz)
+{
+ struct vhd_geom geom;
+ uint64_t newsz;
+
+ /*
+ * Round the image size to the pre-determined geometry that
+ * matches the image size. This circular dependency implies
+ * that we need to loop to handle boundary conditions.
+ * The first time, newsz equals origsz and the geometry will
+ * typically yield a new size that's smaller. We keep adding
+ * cylinder's worth of sectors to the new size until its
+ * larger or equal or origsz. But during those iterations,
+ * the geometry can change, so we need to account for that.
+ */
+ newsz = origsz;
+ while (1) {
+ vhd_geometry(newsz, &geom);
+ newsz = (int64_t)geom.cylinders * geom.heads *
+ geom.sectors * VHD_SECTOR_SIZE;
+ if (newsz >= origsz)
+ break;
+ newsz += geom.heads * geom.sectors * VHD_SECTOR_SIZE;
+ }
+ return (newsz);
+}
+
static uint32_t
vhd_timestamp(void)
{
@@ -256,8 +284,7 @@ vhd_dyn_resize(lba_t imgsz)
{
uint64_t imagesz;
- imagesz = imgsz * secsz;
- imagesz = (imagesz + VHD_BLOCK_SIZE - 1) & ~(VHD_BLOCK_SIZE - 1);
+ imagesz = vhd_resize(imgsz * secsz);
return (image_set_size(imagesz / secsz));
}
@@ -266,7 +293,7 @@ vhd_dyn_write(int fd)
{
struct vhd_footer footer;
struct vhd_dyn_header header;
- uint64_t imgsz;
+ uint64_t imgsz, rawsz;
lba_t blk, blkcnt, nblks;
uint32_t *bat;
void *bitmap;
@@ -274,13 +301,14 @@ vhd_dyn_write(int fd)
uint32_t sector;
int bat_entries, error, entry;
- imgsz = image_get_size() * secsz;
- bat_entries = imgsz / VHD_BLOCK_SIZE;
+ rawsz = image_get_size() * secsz;
+ imgsz = (rawsz + VHD_BLOCK_SIZE - 1) & ~(VHD_BLOCK_SIZE - 1);
- vhd_make_footer(&footer, imgsz, VHD_DISK_TYPE_DYNAMIC, sizeof(footer));
+ vhd_make_footer(&footer, rawsz, VHD_DISK_TYPE_DYNAMIC, sizeof(footer));
if (sparse_write(fd, &footer, sizeof(footer)) < 0)
return (errno);
+ bat_entries = imgsz / VHD_BLOCK_SIZE;
memset(&header, 0, sizeof(header));
be64enc(&header.cookie, VHD_HEADER_COOKIE);
be64enc(&header.data_offset, ~0ULL);
@@ -321,7 +349,7 @@ vhd_dyn_write(int fd)
blk = 0;
blkcnt = VHD_BLOCK_SIZE / secsz;
error = 0;
- nblks = image_get_size();
+ nblks = rawsz / secsz;
while (blk < nblks) {
if (!image_data(blk, blkcnt)) {
blk += blkcnt;
@@ -331,15 +359,20 @@ vhd_dyn_write(int fd)
error = errno;
break;
}
+ /* Handle partial last block */
+ if (blk + blkcnt > nblks)
+ blkcnt = nblks - blk;
error = image_copyout_region(fd, blk, blkcnt);
if (error)
break;
blk += blkcnt;
}
free(bitmap);
- if (blk != nblks)
+ if (error)
+ return (error);
+ error = image_copyout_zeroes(fd, imgsz - rawsz);
+ if (error)
return (error);
-
if (sparse_write(fd, &footer, sizeof(footer)) < 0)
return (errno);
@@ -362,24 +395,9 @@ FORMAT_DEFINE(vhd_dyn_format);
static int
vhd_fix_resize(lba_t imgsz)
{
- struct vhd_geom geom;
- int64_t imagesz;
+ uint64_t imagesz;
- /*
- * Round the image size to the pre-determined geometry that
- * matches the image size. This circular dependency implies
- * that we need to loop to handle boundary conditions.
- */
- imgsz *= secsz;
- imagesz = imgsz;
- while (1) {
- vhd_geometry(imagesz, &geom);
- imagesz = (int64_t)geom.cylinders * geom.heads *
- geom.sectors * VHD_SECTOR_SIZE;
- if (imagesz >= imgsz)
- break;
- imagesz += geom.heads * geom.sectors * VHD_SECTOR_SIZE;
- }
+ imagesz = vhd_resize(imgsz * secsz);
/*
* Azure demands that images are a whole number of megabytes.
*/
@@ -391,24 +409,24 @@ static int
vhd_fix_write(int fd)
{
struct vhd_footer footer;
- uint64_t imgsz;
+ uint64_t imagesz;
int error;
error = image_copyout(fd);
- if (!error) {
- imgsz = image_get_size() * secsz;
- vhd_make_footer(&footer, imgsz, VHD_DISK_TYPE_FIXED, ~0ULL);
- if (sparse_write(fd, &footer, sizeof(footer)) < 0)
- error = errno;
- }
+ if (error)
+ return (error);
+
+ imagesz = image_get_size() * secsz;
+ vhd_make_footer(&footer, imagesz, VHD_DISK_TYPE_FIXED, ~0ULL);
+ error = (sparse_write(fd, &footer, sizeof(footer)) < 0) ? errno : 0;
return (error);
}
static struct mkimg_format vhd_fix_format = {
- .name = "vhdf",
- .description = "Fixed Virtual Hard Disk",
- .resize = vhd_fix_resize,
- .write = vhd_fix_write,
+ .name = "vhdf",
+ .description = "Fixed Virtual Hard Disk",
+ .resize = vhd_fix_resize,
+ .write = vhd_fix_write,
};
FORMAT_DEFINE(vhd_fix_format);
OpenPOWER on IntegriCloud