summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--usr.sbin/vmctl/Makefile7
-rw-r--r--usr.sbin/vmctl/main.c190
-rw-r--r--usr.sbin/vmctl/vmctl.8102
-rw-r--r--usr.sbin/vmctl/vmctl.c117
-rw-r--r--usr.sbin/vmctl/vmctl.h8
-rw-r--r--usr.sbin/vmd/config.c30
-rw-r--r--usr.sbin/vmd/vioqcow2.c51
-rw-r--r--usr.sbin/vmd/virtio.c6
-rw-r--r--usr.sbin/vmd/virtio.h4
-rw-r--r--usr.sbin/vmd/vmd.h4
10 files changed, 408 insertions, 111 deletions
diff --git a/usr.sbin/vmctl/Makefile b/usr.sbin/vmctl/Makefile
index 61b8ca7b262..6288d045110 100644
--- a/usr.sbin/vmctl/Makefile
+++ b/usr.sbin/vmctl/Makefile
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile,v 1.4 2017/07/15 05:05:36 pd Exp $
+# $OpenBSD: Makefile,v 1.5 2018/10/19 10:12:39 reyk Exp $
.if ${MACHINE} == "amd64" || ${MACHINE} == "i386"
@@ -6,14 +6,15 @@
PROG= vmctl
SRCS= vmctl.c main.c atomicio.c
+SRCS+= vioqcow2.c vioraw.c log.c
CFLAGS+= -Wall
CFLAGS+= -Wstrict-prototypes -Wmissing-prototypes
CFLAGS+= -Wmissing-declarations
CFLAGS+= -Wshadow -Wpointer-arith -Wcast-qual
CFLAGS+= -Wsign-compare
CFLAGS+= -I${.CURDIR} -I${.CURDIR}/../vmd
-LDADD+= -lutil
-DPADD+= ${LIBUTIL}
+LDADD+= -lutil -lpthread
+DPADD+= ${LIBUTIL} ${LIBPTHREAD}
PATH+=../vmd
.else
diff --git a/usr.sbin/vmctl/main.c b/usr.sbin/vmctl/main.c
index 45cd5cab753..da84b5d9e5a 100644
--- a/usr.sbin/vmctl/main.c
+++ b/usr.sbin/vmctl/main.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: main.c,v 1.46 2018/10/08 16:32:01 reyk Exp $ */
+/* $OpenBSD: main.c,v 1.47 2018/10/19 10:12:39 reyk Exp $ */
/*
* Copyright (c) 2015 Reyk Floeter <reyk@openbsd.org>
@@ -30,12 +30,14 @@
#include <stdint.h>
#include <limits.h>
#include <string.h>
+#include <syslog.h>
#include <unistd.h>
#include <fcntl.h>
#include <util.h>
#include <imsg.h>
#include "vmd.h"
+#include "virtio.h"
#include "proc.h"
#include "vmctl.h"
@@ -52,6 +54,7 @@ __dead void ctl_usage(struct ctl_command *);
int vmm_action(struct parse_result *);
int ctl_console(struct parse_result *, int, char *[]);
+int ctl_convert(const char *, const char *, int, size_t);
int ctl_create(struct parse_result *, int, char *[]);
int ctl_load(struct parse_result *, int, char *[]);
int ctl_log(struct parse_result *, int, char *[]);
@@ -68,7 +71,7 @@ int ctl_receive(struct parse_result *, int, char *[]);
struct ctl_command ctl_commands[] = {
{ "console", CMD_CONSOLE, ctl_console, "id" },
{ "create", CMD_CREATE, ctl_create,
- "\"path\" [-s size] [-b base]", 1 },
+ "\"path\" [-b base] [-i disk] [-s size]", 1 },
{ "load", CMD_LOAD, ctl_load, "\"path\"" },
{ "log", CMD_LOG, ctl_log, "[verbose|brief]" },
{ "reload", CMD_RELOAD, ctl_reload, "" },
@@ -92,7 +95,7 @@ usage(void)
extern char *__progname;
int i;
- fprintf(stderr, "usage:\t%s command [arg ...]\n",
+ fprintf(stderr, "usage:\t%s [-v] command [arg ...]\n",
__progname);
for (i = 0; ctl_commands[i].name != NULL; i++) {
fprintf(stderr, "\t%s %s %s\n", __progname,
@@ -106,7 +109,7 @@ ctl_usage(struct ctl_command *ctl)
{
extern char *__progname;
- fprintf(stderr, "usage:\t%s %s %s\n", __progname,
+ fprintf(stderr, "usage:\t%s [-v] %s %s\n", __progname,
ctl->name, ctl->usage);
exit(1);
}
@@ -114,10 +117,13 @@ ctl_usage(struct ctl_command *ctl)
int
main(int argc, char *argv[])
{
- int ch;
+ int ch, verbose = 1;
- while ((ch = getopt(argc, argv, "")) != -1) {
+ while ((ch = getopt(argc, argv, "v")) != -1) {
switch (ch) {
+ case 'v':
+ verbose = 2;
+ break;
default:
usage();
/* NOTREACHED */
@@ -131,6 +137,8 @@ main(int argc, char *argv[])
if (argc < 1)
usage();
+ log_init(verbose, LOG_DAEMON);
+
return (parse(argc, argv));
}
@@ -258,6 +266,8 @@ vmmaction(struct parse_result *res)
break;
case CMD_CREATE:
case NONE:
+ /* The action is not expected here */
+ errx(1, "invalid action %u", res->action);
break;
}
@@ -540,12 +550,12 @@ int
ctl_create(struct parse_result *res, int argc, char *argv[])
{
int ch, ret, type;
- const char *disk, *format, *base;
+ const char *disk, *format, *base, *input;
if (argc < 2)
ctl_usage(res->ctl);
- base = NULL;
+ base = input = NULL;
type = parse_disktype(argv[1], &disk);
if (pledge("stdio rpath wpath cpath unveil", NULL) == -1)
@@ -556,22 +566,34 @@ ctl_create(struct parse_result *res, int argc, char *argv[])
argc--;
argv++;
- while ((ch = getopt(argc, argv, "s:b:")) != -1) {
+ while ((ch = getopt(argc, argv, "b:i:s:")) != -1) {
switch (ch) {
- case 's':
- if (parse_size(res, optarg, 0) != 0)
- errx(1, "invalid size: %s", optarg);
- break;
case 'b':
base = optarg;
if (unveil(base, "r") == -1)
err(1, "unveil");
break;
+ case 'i':
+ input = optarg;
+ if (unveil(input, "r") == -1)
+ err(1, "unveil");
+ break;
+ case 's':
+ if (parse_size(res, optarg, 0) != 0)
+ errx(1, "invalid size: %s", optarg);
+ break;
default:
ctl_usage(res->ctl);
/* NOTREACHED */
}
}
+
+ if (input) {
+ if (base && input)
+ errx(1, "conflicting -b and -i arguments");
+ return ctl_convert(input, disk, type, res->size);
+ }
+
if (unveil(NULL, NULL))
err(1, "unveil");
@@ -583,15 +605,7 @@ ctl_create(struct parse_result *res, int argc, char *argv[])
ctl_usage(res->ctl);
}
- if (type == VMDF_QCOW2) {
- format = "qcow2";
- ret = create_qc2_imagefile(disk, base, res->size);
- } else {
- format = "raw";
- ret = create_raw_imagefile(disk, res->size);
- }
-
- if (ret != 0) {
+ if ((ret = create_imagefile(type, disk, base, res->size, &format)) != 0) {
errno = ret;
err(1, "create imagefile operation failed");
} else
@@ -601,6 +615,138 @@ ctl_create(struct parse_result *res, int argc, char *argv[])
}
int
+ctl_convert(const char *srcfile, const char *dstfile, int dsttype, size_t dstsize)
+{
+ struct {
+ int fd;
+ int type;
+ struct virtio_backing file;
+ const char *disk;
+ off_t size;
+ } src, dst;
+ int ret;
+ const char *format, *errstr = NULL;
+ uint8_t *buf = NULL, *zerobuf = NULL;
+ size_t buflen;
+ ssize_t len, rlen;
+ off_t off;
+
+ memset(&src, 0, sizeof(src));
+ memset(&dst, 0, sizeof(dst));
+
+ src.type = parse_disktype(srcfile, &src.disk);
+ dst.type = dsttype;
+ dst.disk = dstfile;
+
+ if ((src.fd = open_imagefile(src.type, src.disk, O_RDONLY,
+ &src.file, &src.size)) == -1) {
+ errstr = "failed to open source image file";
+ goto done;
+ }
+
+ /* We can only lock unveil after opening the disk and all base images */
+ if (unveil(NULL, NULL))
+ err(1, "unveil");
+
+ if (dstsize == 0)
+ dstsize = src.size;
+ else
+ dstsize *= 1048576;
+ if (dstsize < (size_t)src.size) {
+ errstr = "size cannot be smaller than input disk size";
+ goto done;
+ }
+
+ /* align to megabytes */
+ dst.size = ALIGN(dstsize, 1048576);
+
+ if ((ret = create_imagefile(dst.type, dst.disk, NULL,
+ dst.size / 1048576, &format)) != 0) {
+ errno = ret;
+ errstr = "failed to create destination image file";
+ goto done;
+ }
+
+ if ((dst.fd = open_imagefile(dst.type, dst.disk, O_RDWR,
+ &dst.file, &dst.size)) == -1) {
+ errstr = "failed to open destination image file";
+ goto done;
+ }
+
+ if (pledge("stdio", NULL) == -1)
+ err(1, "pledge");
+
+ /*
+ * Use 64k buffers by default. This could also be adjusted to
+ * the backend cluster size.
+ */
+ buflen = 1 << 16;
+ if ((buf = calloc(1, buflen)) == NULL ||
+ (zerobuf = calloc(1, buflen)) == NULL) {
+ errstr = "failed to allocated buffers";
+ goto done;
+ }
+
+ for (off = 0; off < dst.size; off += len) {
+ /* Read input from the source image */
+ if (off < src.size) {
+ len = MIN((off_t)buflen, src.size - off);
+ if ((rlen = src.file.pread(src.file.p,
+ buf, (size_t)len, off)) != len) {
+ errno = EIO;
+ errstr = "failed to read from source";
+ goto done;
+ }
+ } else
+ len = 0;
+
+ /* and pad the remaining bytes */
+ if (len < (ssize_t)buflen) {
+ log_debug("%s: padding %zd zero bytes at offset %lld",
+ format, buflen - len, off + len);
+ memset(buf + len, 0, buflen - len);
+ len = buflen;
+ }
+
+ /*
+ * No need to copy empty buffers. This allows the backend,
+ * sparse files or QCOW2 images, to save space in the
+ * destination file.
+ */
+ if (memcmp(buf, zerobuf, buflen) == 0)
+ continue;
+
+ log_debug("%s: writing %zd of %lld bytes at offset %lld",
+ format, len, dst.size, off);
+
+ if ((rlen = dst.file.pwrite(dst.file.p,
+ buf, (size_t)len, off)) != len) {
+ errno = EIO;
+ errstr = "failed to write to destination";
+ goto done;
+ }
+ }
+
+ if (dstsize < (size_t)dst.size)
+ warnx("destination size rounded to %lld megabytes",
+ dst.size / 1048576);
+
+ done:
+ free(buf);
+ free(zerobuf);
+ if (src.file.p != NULL)
+ src.file.close(src.file.p, 0);
+ if (dst.file.p != NULL)
+ dst.file.close(dst.file.p, 0);
+ if (errstr != NULL)
+ errx(1, "%s", errstr);
+ else
+ warnx("%s imagefile created", format);
+
+ return (0);
+}
+
+int
ctl_status(struct parse_result *res, int argc, char *argv[])
{
if (argc == 2) {
diff --git a/usr.sbin/vmctl/vmctl.8 b/usr.sbin/vmctl/vmctl.8
index f450ae49e11..f56a1dd892c 100644
--- a/usr.sbin/vmctl/vmctl.8
+++ b/usr.sbin/vmctl/vmctl.8
@@ -1,4 +1,4 @@
-.\" $OpenBSD: vmctl.8,v 1.51 2018/10/08 16:32:01 reyk Exp $
+.\" $OpenBSD: vmctl.8,v 1.52 2018/10/19 10:12:39 reyk Exp $
.\"
.\" Copyright (c) 2015 Mike Larkin <mlarkin@openbsd.org>
.\"
@@ -14,7 +14,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: October 8 2018 $
+.Dd $Mdocdate: October 19 2018 $
.Dt VMCTL 8
.Os
.Sh NAME
@@ -22,6 +22,7 @@
.Nd control the virtual machine daemon
.Sh SYNOPSIS
.Nm
+.Op Fl v
.Ar command
.Op Ar arg ...
.Sh DESCRIPTION
@@ -32,6 +33,9 @@ A VMM manages virtual machines (VMs) on a host.
The VMM subsystem is responsible for creating, destroying, and executing
VMs.
.Pp
+The
+.Fl v
+option enables verbose mode.
Within the commands,
the
.Ar size
@@ -43,6 +47,19 @@ The
argument can be either a numeric, non-zero identifier or alternatively
the name of a virtual machine.
.Pp
+The
+.Ar disk
+argument is used by commands that take a path to a disk image file.
+It may be prefixed with a format prefix
+.Pf ( raw Ns : Ns Ar disk
+or
+.Pf qcow2 Ns : Ns Ar disk )
+.Sm on
+in order to specify the disk image format.
+If left unspecified, the format defaults to
+.Sq raw
+if it cannot be derived automatically.
+.Pp
The commands are as follows:
.Bl -tag -width Ds
.It Cm console Ar id
@@ -50,31 +67,44 @@ Using
.Xr cu 1
connect to the console of the VM with the specified
.Ar id .
-.It Cm create Ar path Fl s Op Ar size Op Fl b Ar base
+.It Cm create Ar disk Oo Fl s Ar size Oc Op Fl b Ar base | Fl i Ar disk
Creates a VM disk image file with the specified
-.Ar path
-and
-.Ar size ,
-rounded to megabytes.
-The disk
-.Ar path
-may be prefixed with a format prefix
-.Pf ( Pa raw :
-or
-.Pa qcow2 : )
-in order to specify the disk format.
-If left unspecified, the format defaults to
-.Pa raw
-if it cannot be derived automatically.
-For qcow2, a
+.Ar disk
+path.
+.Bl -tag -width "-i input"
+.It Fl b Ar base
+For
+.Sq qcow2 ,
+a
.Ar base
image may be specified.
-The base image is not modified.
-The derived image contains only the changes written by the VM.
-When creating a derived image, the
+The base image is not modified and the derived image contains only the
+changes written by the VM.
+.It Fl i Ar disk
+Copy and convert the input
+.Ar disk
+to the newly created disk.
+This option conflicts with
+.Fl b Ar base .
+.It Fl s Ar size
+Specify the
.Ar size
-may be omitted, and probed from the base image.
-If it is provided, it must match the base image size.
+of the new disk image, rounded to megabytes.
+If the
+.Fl b
+option is specified, the size must match the size of the
+.Ar base
+image.
+For the
+.Fl i
+option, the size cannot be smaller than the input disk size.
+The size can be ommitted with the
+.Fl b
+and
+.Fl i
+options and will be obtained from the base or input image respectively.
+.El
+.Pp
.It Cm load Ar filename
Load additional configuration from the specified file.
.It Cm log brief
@@ -114,7 +144,7 @@ command.
.It Xo Cm start Ar name
.Op Fl cL
.Op Fl b Ar path
-.Op Fl d Ar path
+.Op Fl d Ar disk
.Op Fl i Ar count
.Op Fl m Ar size
.Op Fl n Ar switch
@@ -131,18 +161,10 @@ If not specified, the default is to boot using the BIOS image in
.Pa /etc/firmware/vmm-bios .
.It Fl c
Automatically connect to the VM console.
-.It Fl d Ar path
-Disk image file (may be specified multiple times to add multiple disk images).
-The disk
-.Ar path
-may be prefixed with a format prefix
-.Pf ( Pa raw :
-or
-.Pa qcow2 : )
-in order to specify the disk format.
-If left unspecified, the format defaults to
-.Pa raw
-if it cannot be derived automatically.
+.It Fl d Ar disk
+Use a disk image at the specified
+.Ar disk
+path (may be specified multiple times to add multiple disk images).
.It Fl i Ar count
Number of network interfaces to add to the VM.
.It Fl L
@@ -330,6 +352,14 @@ Create a 4.5 Gigabyte disk image, disk.img:
$ vmctl create disk.img -s 4.5G
.Ed
.Pp
+Convert a disk image from the
+.Sq raw
+format to
+.Sq qcow2 :
+.Bd -literal -offset indent
+$ vmctl create disk.qcow2 -i disk.img
+.Ed
+.Pp
Create a new VM with 1GB memory, one network interface, one disk image
('disk.img') and boot from kernel '/bsd':
.Bd -literal -offset indent
diff --git a/usr.sbin/vmctl/vmctl.c b/usr.sbin/vmctl/vmctl.c
index a311ed0a512..1feca4754d4 100644
--- a/usr.sbin/vmctl/vmctl.c
+++ b/usr.sbin/vmctl/vmctl.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vmctl.c,v 1.61 2018/10/08 16:32:01 reyk Exp $ */
+/* $OpenBSD: vmctl.c,v 1.62 2018/10/19 10:12:39 reyk Exp $ */
/*
* Copyright (c) 2014 Mike Larkin <mlarkin@openbsd.org>
@@ -39,6 +39,7 @@
#include <grp.h>
#include "vmd.h"
+#include "virtio.h"
#include "vmctl.h"
#include "atomicio.h"
@@ -794,6 +795,116 @@ vm_console(struct vmop_info_result *list, size_t ct)
}
/*
+ * open_imagefile
+ *
+ * Open an imagefile with the specified type, path and size.
+ *
+ * Parameters:
+ * type : format of the image file
+ * imgfile_path: path to the image file to create
+ * flags : flags for open(2), e.g. O_RDONLY
+ * file : file structure
+ * sz : size of the image file
+ *
+ * Return:
+ * fd : Returns file descriptor of the new image file
+ * -1 : Operation failed. errno is set.
+ */
+int
+open_imagefile(int type, const char *imgfile_path, int flags,
+ struct virtio_backing *file, off_t *sz)
+{
+ int fd, ret, basefd[VM_MAX_BASE_PER_DISK], nfd, i;
+ char path[PATH_MAX];
+
+ *sz = 0;
+ if ((fd = open(imgfile_path, flags)) == -1)
+ return (-1);
+
+ basefd[0] = fd;
+ nfd = 1;
+
+ errno = 0;
+ switch (type) {
+ case VMDF_QCOW2:
+ if (strlcpy(path, imgfile_path, sizeof(path)) >= sizeof(path))
+ return (-1);
+ for (i = 0; i < VM_MAX_BASE_PER_DISK - 1; i++, nfd++) {
+ if ((ret = virtio_qcow2_get_base(basefd[i],
+ path, sizeof(path), imgfile_path)) == -1) {
+ log_debug("%s: failed to get base %d", __func__, i);
+ return -1;
+ } else if (ret == 0)
+ break;
+
+ /*
+ * This might be called after unveil is already
+ * locked but it is save to ignore the EPERM error
+ * here as the subsequent open would fail as well.
+ */
+ if ((ret = unveil(path, "r")) != 0 &&
+ (ret != EPERM))
+ err(1, "unveil");
+ if ((basefd[i + 1] = open(path, O_RDONLY)) == -1) {
+ log_warn("%s: failed to open base %s",
+ __func__, path);
+ return (-1);
+ }
+ }
+ ret = virtio_init_qcow2(file, sz, basefd, nfd);
+ break;
+ default:
+ ret = virtio_init_raw(file, sz, &fd, 1);
+ break;
+ }
+
+ if (ret == -1) {
+ for (i = 0; i < nfd; i++)
+ close(basefd[i]);
+ return (-1);
+ }
+
+ return (fd);
+}
+
+/*
+ * create_imagefile
+ *
+ * Create an empty imagefile with the specified type, path and size.
+ *
+ * Parameters:
+ * type : format of the image file
+ * imgfile_path: path to the image file to create
+ * base_path : path to the qcow2 base image
+ * imgsize : size of the image file to create (in MB)
+ * format : string identifying the format
+ *
+ * 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
+ */
+int
+create_imagefile(int type, const char *imgfile_path, const char *base_path,
+ long imgsize, const char **format)
+{
+ int ret;
+
+ switch (type) {
+ case VMDF_QCOW2:
+ *format = "qcow2";
+ ret = create_qc2_imagefile(imgfile_path, base_path, imgsize);
+ break;
+ default:
+ *format = "raw";
+ ret = create_raw_imagefile(imgfile_path, imgsize);
+ break;
+ }
+
+ return (ret);
+}
+
+/*
* create_raw_imagefile
*
* Create an empty imagefile with the specified path and size.
@@ -831,7 +942,7 @@ create_raw_imagefile(const char *imgfile_path, long imgsize)
}
/*
- * create_imagefile
+ * create_qc2_imagefile
*
* Create an empty qcow2 imagefile with the specified path and size.
*
@@ -844,8 +955,6 @@ create_raw_imagefile(const char *imgfile_path, long imgsize)
* 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,
const char *base_path, long imgsize)
diff --git a/usr.sbin/vmctl/vmctl.h b/usr.sbin/vmctl/vmctl.h
index 5ae88268fd7..2948a4fc0ce 100644
--- a/usr.sbin/vmctl/vmctl.h
+++ b/usr.sbin/vmctl/vmctl.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: vmctl.h,v 1.26 2018/10/08 16:32:01 reyk Exp $ */
+/* $OpenBSD: vmctl.h,v 1.27 2018/10/19 10:12:39 reyk Exp $ */
/*
* Copyright (c) 2015 Reyk Floeter <reyk@openbsd.org>
@@ -71,6 +71,9 @@ struct ctl_command {
struct imsgbuf *ibuf;
+#define ALIGN(sz, align) ((sz + align - 1) & ~(align - 1))
+#define MIN(a,b) (((a)<(b))?(a):(b))
+
/* main.c */
int vmmaction(struct parse_result *);
int parse_ifs(struct parse_result *, char *, int);
@@ -86,6 +89,9 @@ __dead void
ctl_openconsole(const char *);
/* vmctl.c */
+int open_imagefile(int, const char *, int,
+ struct virtio_backing *, off_t *);
+int create_imagefile(int, const char *, const char *, long, const char **);
int create_raw_imagefile(const char *, long);
int create_qc2_imagefile(const char *, const char *, long);
int vm_start(uint32_t, const char *, int, int, char **, int,
diff --git a/usr.sbin/vmd/config.c b/usr.sbin/vmd/config.c
index 373e027b425..a749e3595b5 100644
--- a/usr.sbin/vmd/config.c
+++ b/usr.sbin/vmd/config.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: config.c,v 1.52 2018/10/15 10:35:41 reyk Exp $ */
+/* $OpenBSD: config.c,v 1.53 2018/10/19 10:12:39 reyk Exp $ */
/*
* Copyright (c) 2015 Reyk Floeter <reyk@openbsd.org>
@@ -35,7 +35,6 @@
#include <util.h>
#include <errno.h>
#include <imsg.h>
-#include <libgen.h>
#include "proc.h"
#include "vmd.h"
@@ -191,7 +190,6 @@ config_setvm(struct privsep *ps, struct vmd_vm *vm, uint32_t peerid, uid_t uid)
char ifname[IF_NAMESIZE], *s;
char path[PATH_MAX];
char base[PATH_MAX];
- char expanded[PATH_MAX];
unsigned int unit;
struct timeval tv, rate, since_last;
@@ -357,7 +355,7 @@ config_setvm(struct privsep *ps, struct vmd_vm *vm, uint32_t peerid, uid_t uid)
oflags = O_RDONLY|O_NONBLOCK;
aflags = R_OK;
n = virtio_get_base(diskfds[i][j], base, sizeof base,
- vmc->vmc_disktypes[i]);
+ vmc->vmc_disktypes[i], path);
if (n == 0)
break;
if (n == -1) {
@@ -366,30 +364,6 @@ config_setvm(struct privsep *ps, struct vmd_vm *vm, uint32_t peerid, uid_t uid)
base, vcp->vcp_disks[i]);
goto fail;
}
- /*
- * 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 (base[0] == '/') {
- if (realpath(base, path) == NULL) {
- log_warn("unable to resolve %s", base);
- goto fail;
- }
- } else {
- s = dirname(path);
- if (snprintf(expanded, sizeof(expanded),
- "%s/%s", s, base) >= (int)sizeof(expanded)) {
- log_warn("path too long: %s/%s",
- s, base);
- goto fail;
- }
- if (realpath(expanded, path) == NULL) {
- log_warn("unable to resolve %s", base);
- goto fail;
- }
- }
}
}
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
diff --git a/usr.sbin/vmd/virtio.c b/usr.sbin/vmd/virtio.c
index a0cb45aa8ad..4b84ae467fd 100644
--- a/usr.sbin/vmd/virtio.c
+++ b/usr.sbin/vmd/virtio.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: virtio.c,v 1.72 2018/10/08 16:32:01 reyk Exp $ */
+/* $OpenBSD: virtio.c,v 1.73 2018/10/19 10:12:39 reyk Exp $ */
/*
* Copyright (c) 2015 Mike Larkin <mlarkin@openbsd.org>
@@ -1746,13 +1746,13 @@ vmmci_io(int dir, uint16_t reg, uint32_t *data, uint8_t *intr,
}
int
-virtio_get_base(int fd, char *path, size_t npath ,int type)
+virtio_get_base(int fd, char *path, size_t npath, int type, const char *dpath)
{
switch (type) {
case VMDF_RAW:
return 0;
case VMDF_QCOW2:
- return virtio_qcow2_get_base(fd, path, npath);
+ return virtio_qcow2_get_base(fd, path, npath, dpath);
}
log_warnx("%s: invalid disk format", __func__);
return -1;
diff --git a/usr.sbin/vmd/virtio.h b/usr.sbin/vmd/virtio.h
index 354d0fdbce0..28aedc93e84 100644
--- a/usr.sbin/vmd/virtio.h
+++ b/usr.sbin/vmd/virtio.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: virtio.h,v 1.31 2018/10/08 16:32:01 reyk Exp $ */
+/* $OpenBSD: virtio.h,v 1.32 2018/10/19 10:12:39 reyk Exp $ */
/*
* Copyright (c) 2015 Mike Larkin <mlarkin@openbsd.org>
@@ -271,7 +271,7 @@ void viornd_update_qs(void);
void viornd_update_qa(void);
int viornd_notifyq(void);
-ssize_t virtio_qcow2_get_base(int, char *, size_t);
+ssize_t virtio_qcow2_get_base(int, char *, size_t, const char *);
int virtio_init_raw(struct virtio_backing *, off_t *, int*, size_t);
int virtio_init_qcow2(struct virtio_backing *, off_t *, int*, size_t);
diff --git a/usr.sbin/vmd/vmd.h b/usr.sbin/vmd/vmd.h
index 4d7b0380294..7ae4e4bd65e 100644
--- a/usr.sbin/vmd/vmd.h
+++ b/usr.sbin/vmd/vmd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: vmd.h,v 1.83 2018/10/15 10:35:41 reyk Exp $ */
+/* $OpenBSD: vmd.h,v 1.84 2018/10/19 10:12:39 reyk Exp $ */
/*
* Copyright (c) 2015 Mike Larkin <mlarkin@openbsd.org>
@@ -426,6 +426,6 @@ int cmdline_symset(char *);
int host(const char *, struct address *);
/* virtio.c */
-int virtio_get_base(int, char *, size_t, int);
+int virtio_get_base(int, char *, size_t, int, const char *);
#endif /* VMD_H */