diff options
author | Reyk Floeter <reyk@cvs.openbsd.org> | 2018-10-19 10:12:40 +0000 |
---|---|---|
committer | Reyk Floeter <reyk@cvs.openbsd.org> | 2018-10-19 10:12:40 +0000 |
commit | e014ce92dbc428864aef9723a6d3bde4319f06bc (patch) | |
tree | 72a90057790b5a8544c1402e812405577dfbe64f /usr.sbin/vmd/vioqcow2.c | |
parent | dc388d4163b5f0cf447d8f1d605a6b3bd1da6346 (diff) |
Add support to create and convert disk images from existing images
The -i option to vmctl create (eg. vmctl create output.qcow2 -i input.img)
lets you create a new image from an input file and convert it if it is a
different format. This allows to convert qcow2 images from raw images,
raw from qcow2, or even qcow2 from qcow2 and raw from raw to re-optimize
the disk.
This re-uses Ori's vioqcow2.c from vmd by reaching into it and
compiling it in. The API has been adjust to be used from both vmctl
and vmd accordingly.
OK mlarkin@
Diffstat (limited to 'usr.sbin/vmd/vioqcow2.c')
-rw-r--r-- | usr.sbin/vmd/vioqcow2.c | 51 |
1 files changed, 41 insertions, 10 deletions
diff --git a/usr.sbin/vmd/vioqcow2.c b/usr.sbin/vmd/vioqcow2.c index 8f56d2172d4..3a215599d49 100644 --- a/usr.sbin/vmd/vioqcow2.c +++ b/usr.sbin/vmd/vioqcow2.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vioqcow2.c,v 1.8 2018/10/08 16:32:01 reyk Exp $ */ +/* $OpenBSD: vioqcow2.c,v 1.9 2018/10/19 10:12:39 reyk Exp $ */ /* * Copyright (c) 2018 Ori Bernstein <ori@eigenstate.org> @@ -27,6 +27,7 @@ #include <unistd.h> #include <fcntl.h> #include <assert.h> +#include <libgen.h> #include <err.h> #include "vmd.h" @@ -137,11 +138,13 @@ virtio_init_qcow2(struct virtio_backing *file, off_t *szp, int *fd, size_t nfd) } ssize_t -virtio_qcow2_get_base(int fd, char *path, size_t npath) +virtio_qcow2_get_base(int fd, char *path, size_t npath, const char *dpath) { + char expanded[PATH_MAX]; struct qcheader header; uint64_t backingoff; uint32_t backingsz; + char *s = NULL; if (pread(fd, &header, sizeof(header), 0) != sizeof(header)) { log_warnx("%s: short read on header", __func__); @@ -153,19 +156,47 @@ virtio_qcow2_get_base(int fd, char *path, size_t npath) } backingoff = be64toh(header.backingoff); backingsz = be32toh(header.backingsz); - if (backingsz != 0) { - if (backingsz >= npath - 1) { - log_warn("%s: snapshot path too long", __func__); + if (backingsz == 0) + return 0; + + if (backingsz >= npath - 1) { + log_warn("%s: snapshot path too long", __func__); + return -1; + } + if (pread(fd, path, backingsz, backingoff) != backingsz) { + log_warnx("%s: could not read snapshot base name", + __func__); + return -1; + } + path[backingsz] = '\0'; + + /* + * Relative paths should be interpreted relative to the disk image, + * rather than relative to the directory vmd happens to be running in, + * since this is the only userful interpretation. + */ + if (path[0] == '/') { + if (realpath(path, expanded) == NULL || + strlcpy(path, expanded, npath) >= npath) { + log_warn("unable to resolve %s", path); return -1; } - if (pread(fd, path, backingsz, backingoff) != backingsz) { - log_warnx("%s: could not read snapshot base name", - __func__); + } else { + s = dirname(dpath); + if (snprintf(expanded, sizeof(expanded), + "%s/%s", s, path) >= (int)sizeof(expanded)) { + log_warn("path too long: %s/%s", + s, path); + return -1; + } + if (npath < PATH_MAX || + realpath(expanded, path) == NULL) { + log_warn("unable to resolve %s", path); return -1; } - path[backingsz] = '\0'; } - return backingsz; + + return strlen(path); } static int |