summaryrefslogtreecommitdiffstats
path: root/usr.sbin/vmctl/vmctl.c
diff options
context:
space:
mode:
authorccardenas <ccardenas@openbsd.org>2018-09-11 04:03:16 +0000
committerccardenas <ccardenas@openbsd.org>2018-09-11 04:03:16 +0000
commit5f3f415247a8769e6002228a2b7734779914a408 (patch)
tree3ad1c66815029403ff63410f9204f7b42e8f2609 /usr.sbin/vmctl/vmctl.c
parentRemove useless INPCBHASH() macros. Just expand them. (diff)
downloadwireguard-openbsd-5f3f415247a8769e6002228a2b7734779914a408.tar.xz
wireguard-openbsd-5f3f415247a8769e6002228a2b7734779914a408.zip
Add ability to create qcow2 disk.
vmctl create now takes an optional disk format parameter: raw or qcow2. If format is omitted, raw is used. Many thanks to Ori Bernstein.
Diffstat (limited to 'usr.sbin/vmctl/vmctl.c')
-rw-r--r--usr.sbin/vmctl/vmctl.c126
1 files changed, 123 insertions, 3 deletions
diff --git a/usr.sbin/vmctl/vmctl.c b/usr.sbin/vmctl/vmctl.c
index 3810bd778d1..0ef71a55890 100644
--- a/usr.sbin/vmctl/vmctl.c
+++ b/usr.sbin/vmctl/vmctl.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vmctl.c,v 1.56 2018/09/09 04:09:32 ccardenas Exp $ */
+/* $OpenBSD: vmctl.c,v 1.57 2018/09/11 04:03:16 ccardenas Exp $ */
/*
* Copyright (c) 2014 Mike Larkin <mlarkin@openbsd.org>
@@ -737,7 +737,7 @@ vm_console(struct vmop_info_result *list, size_t ct)
}
/*
- * create_imagefile
+ * create_raw_imagefile
*
* Create an empty imagefile with the specified path and size.
*
@@ -751,7 +751,7 @@ vm_console(struct vmop_info_result *list, size_t ct)
* Exxxx : Various other Exxxx errno codes due to other I/O errors
*/
int
-create_imagefile(const char *imgfile_path, long imgsize)
+create_raw_imagefile(const char *imgfile_path, long imgsize)
{
int fd, ret;
@@ -772,3 +772,123 @@ create_imagefile(const char *imgfile_path, long imgsize)
ret = close(fd);
return (ret);
}
+
+/*
+ * create_imagefile
+ *
+ * Create an empty qcow2 imagefile with the specified path and size.
+ *
+ * Parameters:
+ * imgfile_path: path to the image file to create
+ * imgsize : size of the image file to create (in MB)
+ *
+ * Return:
+ * EEXIST: The requested image file already exists
+ * 0 : Image file successfully created
+ * Exxxx : Various other Exxxx errno codes due to other I/O errors
+ */
+#define ALIGN(sz, align) \
+ ((sz + align - 1) & ~(align - 1))
+int
+create_qc2_imagefile(const char *imgfile_path, long imgsize)
+{
+ struct qcheader {
+ char magic[4];
+ uint32_t version;
+ uint64_t backingoff;
+ uint32_t backingsz;
+ uint32_t clustershift;
+ uint64_t disksz;
+ uint32_t cryptmethod;
+ uint32_t l1sz;
+ uint64_t l1off;
+ uint64_t refoff;
+ uint32_t refsz;
+ uint32_t snapcount;
+ uint64_t snapsz;
+ /* v3 additions */
+ uint64_t incompatfeatures;
+ uint64_t compatfeatures;
+ uint64_t autoclearfeatures;
+ uint32_t reforder;
+ uint32_t headersz;
+ } __packed hdr;
+ int fd, ret;
+ uint64_t l1sz, refsz, disksz, initsz, clustersz;
+ uint64_t l1off, refoff, v, i;
+ uint16_t refs;
+
+ disksz = 1024*1024*imgsize;
+ clustersz = (1<<16);
+ l1off = ALIGN(sizeof hdr, clustersz);
+ l1sz = disksz / (clustersz*clustersz/8);
+ if (l1sz == 0)
+ l1sz = 1;
+
+ refoff = ALIGN(l1off + 8*l1sz, clustersz);
+ refsz = disksz / (clustersz*clustersz*clustersz/2);
+ if (refsz == 0)
+ refsz = 1;
+
+ initsz = ALIGN(refoff + refsz*clustersz, clustersz);
+
+ memcpy(hdr.magic, "QFI\xfb", 4);
+ hdr.version = htobe32(3);
+ hdr.backingoff = htobe64(0);
+ hdr.backingsz = htobe32(0);
+ hdr.clustershift = htobe32(16);
+ hdr.disksz = htobe64(disksz);
+ hdr.cryptmethod = htobe32(0);
+ hdr.l1sz = htobe32(l1sz);
+ hdr.l1off = htobe64(l1off);
+ hdr.refoff = htobe64(refoff);
+ hdr.refsz = htobe32(refsz);
+ hdr.snapcount = htobe32(0);
+ hdr.snapsz = htobe64(0);
+ hdr.incompatfeatures = htobe64(0);
+ hdr.compatfeatures = htobe64(0);
+ hdr.autoclearfeatures = htobe64(0);
+ hdr.reforder = htobe32(4);
+ hdr.headersz = htobe32(sizeof hdr);
+
+ /* Refuse to overwrite an existing image */
+ fd = open(imgfile_path, O_RDWR | O_CREAT | O_TRUNC | O_EXCL,
+ S_IRUSR | S_IWUSR);
+ if (fd == -1)
+ return (errno);
+
+ /* Write out the header */
+ if (write(fd, &hdr, sizeof hdr) != sizeof hdr)
+ goto error;
+
+ /* Extend to desired size, and add one refcount cluster */
+ if (ftruncate(fd, (off_t)initsz + clustersz) == -1)
+ goto error;
+
+ /*
+ * Paranoia: if our disk image takes more than one cluster
+ * to refcount the initial image, fail.
+ */
+ if (initsz/clustersz > clustersz/2) {
+ errno = ERANGE;
+ goto error;
+ }
+
+ /* Add a refcount block, and refcount ourselves. */
+ v = htobe64(initsz);
+ if (pwrite(fd, &v, 8, refoff) != 8)
+ goto error;
+ for (i = 0; i < initsz/clustersz + 1; i++) {
+ refs = htobe16(1);
+ if (pwrite(fd, &refs, 2, initsz + 2*i) != 2)
+ goto error;
+ }
+
+ ret = close(fd);
+ return (ret);
+error:
+ ret = errno;
+ close(fd);
+ unlink(imgfile_path);
+ return (errno);
+}