xref: /openbsd-src/usr.sbin/vmctl/main.c (revision 4e1ee0786f11cc571bd0be17d38e46f635c719fc)
1 /*	$OpenBSD: main.c,v 1.68 2021/07/12 15:09:22 beck Exp $	*/
2 
3 /*
4  * Copyright (c) 2015 Reyk Floeter <reyk@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/types.h>
20 #include <sys/socket.h>
21 #include <sys/queue.h>
22 #include <sys/un.h>
23 
24 #include <machine/vmmvar.h>
25 
26 #include <err.h>
27 #include <errno.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <stdint.h>
31 #include <limits.h>
32 #include <string.h>
33 #include <syslog.h>
34 #include <unistd.h>
35 #include <fcntl.h>
36 #include <util.h>
37 #include <imsg.h>
38 
39 #include "vmd.h"
40 #include "virtio.h"
41 #include "proc.h"
42 #include "vmctl.h"
43 
44 #define RAW_FMT		"raw"
45 #define QCOW2_FMT	"qcow2"
46 
47 static const char	*socket_name = SOCKET_NAME;
48 static int		 ctl_sock = -1;
49 static int		 tty_autoconnect = 0;
50 
51 __dead void	 usage(void);
52 __dead void	 ctl_usage(struct ctl_command *);
53 
54 int		 vmm_action(struct parse_result *);
55 
56 int		 ctl_console(struct parse_result *, int, char *[]);
57 int		 ctl_convert(const char *, const char *, int, size_t);
58 int		 ctl_create(struct parse_result *, int, char *[]);
59 int		 ctl_load(struct parse_result *, int, char *[]);
60 int		 ctl_log(struct parse_result *, int, char *[]);
61 int		 ctl_reload(struct parse_result *, int, char *[]);
62 int		 ctl_reset(struct parse_result *, int, char *[]);
63 int		 ctl_start(struct parse_result *, int, char *[]);
64 int		 ctl_status(struct parse_result *, int, char *[]);
65 int		 ctl_stop(struct parse_result *, int, char *[]);
66 int		 ctl_waitfor(struct parse_result *, int, char *[]);
67 int		 ctl_pause(struct parse_result *, int, char *[]);
68 int		 ctl_unpause(struct parse_result *, int, char *[]);
69 int		 ctl_send(struct parse_result *, int, char *[]);
70 int		 ctl_receive(struct parse_result *, int, char *[]);
71 
72 struct ctl_command ctl_commands[] = {
73 	{ "console",	CMD_CONSOLE,	ctl_console,	"id" },
74 	{ "create",	CMD_CREATE,	ctl_create,
75 		"[-b base | -i disk] [-s size] disk", 1 },
76 	{ "load",	CMD_LOAD,	ctl_load,	"filename" },
77 	{ "log",	CMD_LOG,	ctl_log,	"[brief | verbose]" },
78 	{ "pause",	CMD_PAUSE,	ctl_pause,	"id" },
79 	{ "receive",	CMD_RECEIVE,	ctl_receive,	"name" ,	1},
80 	{ "reload",	CMD_RELOAD,	ctl_reload,	"" },
81 	{ "reset",	CMD_RESET,	ctl_reset,	"[all | switches | vms]" },
82 	{ "send",	CMD_SEND,	ctl_send,	"id",	1},
83 	{ "show",	CMD_STATUS,	ctl_status,	"[id]" },
84 	{ "start",	CMD_START,	ctl_start,
85 	    "[-cL] [-B device] [-b path] [-d disk] [-i count]\n"
86 	    "\t\t[-m size] [-n switch] [-r path] [-t name] id | name" },
87 	{ "status",	CMD_STATUS,	ctl_status,	"[id]" },
88 	{ "stop",	CMD_STOP,	ctl_stop,	"[-fw] [id | -a]" },
89 	{ "unpause",	CMD_UNPAUSE,	ctl_unpause,	"id" },
90 	{ "wait",	CMD_WAITFOR,	ctl_waitfor,	"id" },
91 	{ NULL }
92 };
93 
94 __dead void
95 usage(void)
96 {
97 	extern char	*__progname;
98 
99 	fprintf(stderr, "usage:\t%s [-v] command [arg ...]\n", __progname);
100 
101 	exit(1);
102 }
103 
104 __dead void
105 ctl_usage(struct ctl_command *ctl)
106 {
107 	extern char	*__progname;
108 
109 	fprintf(stderr, "usage:\t%s [-v] %s %s\n", __progname,
110 	    ctl->name, ctl->usage);
111 	exit(1);
112 }
113 
114 int
115 main(int argc, char *argv[])
116 {
117 	int	 ch, verbose = 1;
118 
119 	while ((ch = getopt(argc, argv, "v")) != -1) {
120 		switch (ch) {
121 		case 'v':
122 			verbose = 2;
123 			break;
124 		default:
125 			usage();
126 			/* NOTREACHED */
127 		}
128 	}
129 	argc -= optind;
130 	argv += optind;
131 	optreset = 1;
132 	optind = 1;
133 
134 	if (argc < 1)
135 		usage();
136 
137 	log_init(verbose, LOG_DAEMON);
138 
139 	return (parse(argc, argv));
140 }
141 
142 int
143 parse(int argc, char *argv[])
144 {
145 	struct ctl_command	*ctl = NULL;
146 	struct parse_result	 res;
147 	int			 i;
148 
149 	memset(&res, 0, sizeof(res));
150 	res.nifs = -1;
151 
152 	for (i = 0; ctl_commands[i].name != NULL; i++) {
153 		if (strncmp(ctl_commands[i].name,
154 		    argv[0], strlen(argv[0])) == 0) {
155 			if (ctl != NULL) {
156 				fprintf(stderr,
157 				    "ambiguous argument: %s\n", argv[0]);
158 				usage();
159 			}
160 			ctl = &ctl_commands[i];
161 		}
162 	}
163 
164 	if (ctl == NULL) {
165 		fprintf(stderr, "unknown argument: %s\n", argv[0]);
166 		usage();
167 	}
168 
169 	res.action = ctl->action;
170 	res.ctl = ctl;
171 
172 	if (!ctl->has_pledge) {
173 		/* pledge(2) default if command doesn't have its own pledge */
174 		if (pledge("stdio rpath exec unix getpw unveil", NULL) == -1)
175 			err(1, "pledge");
176 	}
177 	if (ctl->main(&res, argc, argv) != 0)
178 		exit(1);
179 
180 	if (ctl_sock != -1) {
181 		close(ibuf->fd);
182 		free(ibuf);
183 	}
184 
185 	return (0);
186 }
187 
188 int
189 vmmaction(struct parse_result *res)
190 {
191 	struct sockaddr_un	 sun;
192 	struct imsg		 imsg;
193 	int			 done = 0;
194 	int			 n;
195 	int			 ret, action;
196 	unsigned int		 flags;
197 
198 	if (ctl_sock == -1) {
199 		if (unveil(SOCKET_NAME, "r") == -1)
200 			err(1, "unveil %s", SOCKET_NAME);
201 		if ((ctl_sock = socket(AF_UNIX,
202 		    SOCK_STREAM|SOCK_CLOEXEC, 0)) == -1)
203 			err(1, "socket");
204 
205 		memset(&sun, 0, sizeof(sun));
206 		sun.sun_family = AF_UNIX;
207 		strlcpy(sun.sun_path, socket_name, sizeof(sun.sun_path));
208 
209 		if (connect(ctl_sock,
210 		    (struct sockaddr *)&sun, sizeof(sun)) == -1)
211 			err(1, "connect: %s", socket_name);
212 
213 		if ((ibuf = malloc(sizeof(struct imsgbuf))) == NULL)
214 			err(1, "malloc");
215 		imsg_init(ibuf, ctl_sock);
216 	}
217 
218 	switch (res->action) {
219 	case CMD_START:
220 		ret = vm_start(res->id, res->name, res->size, res->nifs,
221 		    res->nets, res->ndisks, res->disks, res->disktypes,
222 		    res->path, res->isopath, res->instance, res->bootdevice);
223 		if (ret) {
224 			errno = ret;
225 			err(1, "start VM operation failed");
226 		}
227 		break;
228 	case CMD_STOP:
229 		terminate_vm(res->id, res->name, res->flags);
230 		break;
231 	case CMD_STATUS:
232 	case CMD_CONSOLE:
233 	case CMD_STOPALL:
234 		get_info_vm(res->id, res->name, res->action, res->flags);
235 		break;
236 	case CMD_LOAD:
237 		imsg_compose(ibuf, IMSG_VMDOP_LOAD, 0, 0, -1,
238 		    res->path, strlen(res->path) + 1);
239 		break;
240 	case CMD_LOG:
241 		imsg_compose(ibuf, IMSG_CTL_VERBOSE, 0, 0, -1,
242 		    &res->verbose, sizeof(res->verbose));
243 		break;
244 	case CMD_RELOAD:
245 		imsg_compose(ibuf, IMSG_VMDOP_RELOAD, 0, 0, -1, NULL, 0);
246 		break;
247 	case CMD_RESET:
248 		imsg_compose(ibuf, IMSG_CTL_RESET, 0, 0, -1,
249 		    &res->mode, sizeof(res->mode));
250 		break;
251 	case CMD_WAITFOR:
252 		waitfor_vm(res->id, res->name);
253 		break;
254 	case CMD_PAUSE:
255 		pause_vm(res->id, res->name);
256 		break;
257 	case CMD_UNPAUSE:
258 		unpause_vm(res->id, res->name);
259 		break;
260 	case CMD_SEND:
261 		send_vm(res->id, res->name);
262 		done = 1;
263 		ret = 0;
264 		break;
265 	case CMD_RECEIVE:
266 		vm_receive(res->id, res->name);
267 		break;
268 	case CMD_CREATE:
269 	case NONE:
270 		/* The action is not expected here */
271 		errx(1, "invalid action %u", res->action);
272 		break;
273 	}
274 
275 	action = res->action;
276 	flags = res->flags;
277 	parse_free(res);
278 
279 	while (ibuf->w.queued)
280 		if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN)
281 			err(1, "write error");
282 
283 	while (!done) {
284 		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
285 			errx(1, "imsg_read error");
286 		if (n == 0)
287 			errx(1, "pipe closed");
288 
289 		while (!done) {
290 			if ((n = imsg_get(ibuf, &imsg)) == -1)
291 				errx(1, "imsg_get error");
292 			if (n == 0)
293 				break;
294 
295 			if (imsg.hdr.type == IMSG_CTL_FAIL) {
296 				if (IMSG_DATA_SIZE(&imsg) == sizeof(ret))
297 					memcpy(&ret, imsg.data, sizeof(ret));
298 				else
299 					ret = 0;
300 				if (ret != 0) {
301 					errno = ret;
302 					err(1, "command failed");
303 				} else
304 					errx(1, "command failed");
305 			}
306 
307 			ret = 0;
308 			switch (action) {
309 			case CMD_START:
310 				done = vm_start_complete(&imsg, &ret,
311 				    tty_autoconnect);
312 				break;
313 			case CMD_WAITFOR:
314 				flags = VMOP_WAIT;
315 				/* FALLTHROUGH */
316 			case CMD_STOP:
317 				done = terminate_vm_complete(&imsg, &ret,
318 				    flags);
319 				break;
320 			case CMD_CONSOLE:
321 			case CMD_STATUS:
322 			case CMD_STOPALL:
323 				done = add_info(&imsg, &ret);
324 				break;
325 			case CMD_PAUSE:
326 				done = pause_vm_complete(&imsg, &ret);
327 				break;
328 			case CMD_RECEIVE:
329 				done = vm_start_complete(&imsg, &ret, 0);
330 				break;
331 			case CMD_UNPAUSE:
332 				done = unpause_vm_complete(&imsg, &ret);
333 				break;
334 			default:
335 				done = 1;
336 				break;
337 			}
338 
339 			imsg_free(&imsg);
340 		}
341 	}
342 
343 	if (ret)
344 		return (1);
345 	else
346 		return (0);
347 }
348 
349 void
350 parse_free(struct parse_result *res)
351 {
352 	size_t	 i;
353 
354 	free(res->name);
355 	free(res->path);
356 	free(res->isopath);
357 	free(res->instance);
358 	for (i = 0; i < res->ndisks; i++)
359 		free(res->disks[i]);
360 	free(res->disks);
361 	free(res->disktypes);
362 	memset(res, 0, sizeof(*res));
363 }
364 
365 int
366 parse_ifs(struct parse_result *res, char *word, int val)
367 {
368 	const char	*error;
369 
370 	if (word != NULL) {
371 		val = strtonum(word, 1, INT_MAX, &error);
372 		if (error != NULL)  {
373 			warnx("count is %s: %s", error, word);
374 			return (-1);
375 		}
376 	}
377 	res->nifs = val;
378 
379 	return (0);
380 }
381 
382 int
383 parse_network(struct parse_result *res, char *word)
384 {
385 	char		**nets;
386 	char		*s;
387 
388 	if ((nets = reallocarray(res->nets, res->nnets + 1,
389 	    sizeof(char *))) == NULL) {
390 		warn("reallocarray");
391 		return (-1);
392 	}
393 	if ((s = strdup(word)) == NULL) {
394 		warn("strdup");
395 		return (-1);
396 	}
397 	nets[res->nnets] = s;
398 	res->nets = nets;
399 	res->nnets++;
400 
401 	return (0);
402 }
403 
404 int
405 parse_size(struct parse_result *res, char *word)
406 {
407 	long long val = 0;
408 
409 	if (word != NULL) {
410 		if (scan_scaled(word, &val) != 0) {
411 			warn("invalid size: %s", word);
412 			return (-1);
413 		}
414 	}
415 
416 	if (val < (1024 * 1024)) {
417 		warnx("size must be at least one megabyte");
418 		return (-1);
419 	} else
420 		res->size = val / 1024 / 1024;
421 
422 	if ((res->size * 1024 * 1024) != val)
423 		warnx("size rounded to %lld megabytes", res->size);
424 
425 	return (0);
426 }
427 
428 int
429 parse_disktype(const char *s, const char **ret)
430 {
431 	char		 buf[BUFSIZ];
432 	const char	*ext;
433 	int		 fd;
434 	ssize_t		 len;
435 
436 	*ret = s;
437 
438 	/* Try to parse the explicit format (qcow2:disk.qc2) */
439 	if (strstr(s, RAW_FMT) == s && *(s + strlen(RAW_FMT)) == ':') {
440 		*ret = s + strlen(RAW_FMT) + 1;
441 		return (VMDF_RAW);
442 	}
443 	if (strstr(s, QCOW2_FMT) == s && *(s + strlen(QCOW2_FMT)) == ':') {
444 		*ret = s + strlen(QCOW2_FMT) + 1;
445 		return (VMDF_QCOW2);
446 	}
447 
448 	/* Or try to derive the format from the file signature */
449 	if ((fd = open(s, O_RDONLY)) != -1) {
450 		len = read(fd, buf, sizeof(buf));
451 		close(fd);
452 
453 		if (len >= (ssize_t)strlen(VM_MAGIC_QCOW) &&
454 		    strncmp(buf, VM_MAGIC_QCOW,
455 		    strlen(VM_MAGIC_QCOW)) == 0) {
456 			/* Return qcow2, the version will be checked later */
457 			return (VMDF_QCOW2);
458 		}
459 	}
460 
461 	/*
462 	 * Use the extension as a last option.  This is needed for
463 	 * 'vmctl create' as the file, and the signature, doesn't
464 	 * exist yet.
465 	 */
466 	if ((ext = strrchr(s, '.')) != NULL && *(++ext) != '\0') {
467 		if (strcasecmp(ext, RAW_FMT) == 0)
468 			return (VMDF_RAW);
469 		else if (strcasecmp(ext, QCOW2_FMT) == 0)
470 			return (VMDF_QCOW2);
471 	}
472 
473 	/* Fallback to raw */
474 	return (VMDF_RAW);
475 }
476 
477 int
478 parse_disk(struct parse_result *res, char *word, int type)
479 {
480 	char		**disks;
481 	int		*disktypes;
482 	char		*s;
483 
484 	if ((disks = reallocarray(res->disks, res->ndisks + 1,
485 	    sizeof(char *))) == NULL) {
486 		warn("reallocarray");
487 		return (-1);
488 	}
489 	if ((disktypes = reallocarray(res->disktypes, res->ndisks + 1,
490 	    sizeof(int))) == NULL) {
491 		warn("reallocarray");
492 		return -1;
493 	}
494 	if ((s = strdup(word)) == NULL) {
495 		warn("strdup");
496 		return (-1);
497 	}
498 	disks[res->ndisks] = s;
499 	disktypes[res->ndisks] = type;
500 	res->disks = disks;
501 	res->disktypes = disktypes;
502 	res->ndisks++;
503 
504 	return (0);
505 }
506 
507 int
508 parse_vmid(struct parse_result *res, char *word, int needname)
509 {
510 	const char	*error;
511 	uint32_t	 id;
512 
513 	if (word == NULL) {
514 		warnx("missing vmid argument");
515 		return (-1);
516 	}
517 	if (*word == '-') {
518 		/* don't print a warning to allow command line options */
519 		return (-1);
520 	}
521 	id = strtonum(word, 0, UINT32_MAX, &error);
522 	if (error == NULL) {
523 		if (needname) {
524 			warnx("invalid vm name");
525 			return (-1);
526 		} else {
527 			res->id = id;
528 			res->name = NULL;
529 		}
530 	} else {
531 		if (strlen(word) >= VMM_MAX_NAME_LEN) {
532 			warnx("name too long");
533 			return (-1);
534 		}
535 		res->id = 0;
536 		if ((res->name = strdup(word)) == NULL)
537 			errx(1, "strdup");
538 	}
539 
540 	return (0);
541 }
542 
543 int
544 parse_instance(struct parse_result *res, char *word)
545 {
546 	if (strlen(word) >= VMM_MAX_NAME_LEN) {
547 		warnx("instance vm name too long");
548 		return (-1);
549 	}
550 	res->id = 0;
551 	if ((res->instance = strdup(word)) == NULL)
552 		errx(1, "strdup");
553 
554 	return (0);
555 }
556 
557 int
558 ctl_create(struct parse_result *res, int argc, char *argv[])
559 {
560 	int		 ch, ret, type;
561 	const char	*disk, *format, *base = NULL, *input = NULL;
562 
563 	while ((ch = getopt(argc, argv, "b:i:s:")) != -1) {
564 		switch (ch) {
565 		case 'b':
566 			base = optarg;
567 			break;
568 		case 'i':
569 			input = optarg;
570 			break;
571 		case 's':
572 			if (parse_size(res, optarg) != 0)
573 				errx(1, "invalid size: %s", optarg);
574 			break;
575 		default:
576 			ctl_usage(res->ctl);
577 			/* NOTREACHED */
578 		}
579 	}
580 	argc -= optind;
581 	argv += optind;
582 
583 	if (argc < 1)
584 		ctl_usage(res->ctl);
585 
586 	type = parse_disktype(argv[0], &disk);
587 
588 	if (pledge("stdio rpath wpath cpath", NULL) == -1)
589 		err(1, "pledge");
590 
591 	if (input) {
592 		if (base && input)
593 			errx(1, "conflicting -b and -i arguments");
594 		return ctl_convert(input, disk, type, res->size);
595 	}
596 
597 	if (base && type != VMDF_QCOW2)
598 		errx(1, "base images require qcow2 disk format");
599 	if (res->size == 0 && !base) {
600 		fprintf(stderr, "could not create %s: missing size argument\n",
601 		    disk);
602 		ctl_usage(res->ctl);
603 	}
604 
605 	if ((ret = create_imagefile(type, disk, base, res->size, &format)) != 0) {
606 		errno = ret;
607 		err(1, "create imagefile operation failed");
608 	} else
609 		warnx("%s imagefile created", format);
610 
611 	return (0);
612 }
613 
614 int
615 ctl_convert(const char *srcfile, const char *dstfile, int dsttype, size_t dstsize)
616 {
617 	struct {
618 		int			 fd;
619 		int			 type;
620 		struct virtio_backing	 file;
621 		const char		*disk;
622 		off_t			 size;
623 	}	 src, dst;
624 	int		 ret;
625 	const char	*format, *errstr = NULL;
626 	uint8_t		*buf = NULL, *zerobuf = NULL;
627 	size_t		 buflen;
628 	ssize_t		 len, rlen;
629 	off_t		 off;
630 
631 	memset(&src, 0, sizeof(src));
632 	memset(&dst, 0, sizeof(dst));
633 
634 	src.type = parse_disktype(srcfile, &src.disk);
635 	dst.type = dsttype;
636 	dst.disk = dstfile;
637 
638 	if ((src.fd = open_imagefile(src.type, src.disk, O_RDONLY,
639 	    &src.file, &src.size)) == -1) {
640 		errstr = "failed to open source image file";
641 		goto done;
642 	}
643 
644 	if (dstsize == 0)
645 		dstsize = src.size;
646 	else
647 		dstsize *= 1048576;
648 	if (dstsize < (size_t)src.size) {
649 		errstr = "size cannot be smaller than input disk size";
650 		goto done;
651 	}
652 
653 	/* align to megabytes */
654 	dst.size = ALIGNSZ(dstsize, 1048576);
655 
656 	if ((ret = create_imagefile(dst.type, dst.disk, NULL,
657 	   dst.size / 1048576, &format)) != 0) {
658 		errno = ret;
659 		errstr = "failed to create destination image file";
660 		goto done;
661 	}
662 
663 	if ((dst.fd = open_imagefile(dst.type, dst.disk, O_RDWR,
664 	    &dst.file, &dst.size)) == -1) {
665 		errstr = "failed to open destination image file";
666 		goto done;
667 	}
668 
669 	if (pledge("stdio", NULL) == -1)
670 		err(1, "pledge");
671 
672 	/*
673 	 * Use 64k buffers by default.  This could also be adjusted to
674 	 * the backend cluster size.
675 	 */
676 	buflen = 1 << 16;
677 	if ((buf = calloc(1, buflen)) == NULL ||
678 	    (zerobuf = calloc(1, buflen)) == NULL) {
679 		errstr = "failed to allocated buffers";
680 		goto done;
681 	}
682 
683 	for (off = 0; off < dst.size; off += len) {
684 		/* Read input from the source image */
685 		if (off < src.size) {
686 			len = MIN((off_t)buflen, src.size - off);
687 			if ((rlen = src.file.pread(src.file.p,
688 			    buf, (size_t)len, off)) != len) {
689 				errno = EIO;
690 				errstr = "failed to read from source";
691 				goto done;
692 			}
693 		} else
694 			len = 0;
695 
696 		/* and pad the remaining bytes */
697 		if (len < (ssize_t)buflen) {
698 			log_debug("%s: padding %zd zero bytes at offset %lld",
699 			    format, buflen - len, off + len);
700 			memset(buf + len, 0, buflen - len);
701 			len = buflen;
702 		}
703 
704 		/*
705 		 * No need to copy empty buffers.  This allows the backend,
706 		 * sparse files or QCOW2 images, to save space in the
707 		 * destination file.
708 		 */
709 		if (memcmp(buf, zerobuf, buflen) == 0)
710 			continue;
711 
712 		log_debug("%s: writing %zd of %lld bytes at offset %lld",
713 		    format, len, dst.size, off);
714 
715 		if ((rlen = dst.file.pwrite(dst.file.p,
716 		    buf, (size_t)len, off)) != len) {
717 			errno = EIO;
718 			errstr = "failed to write to destination";
719 			goto done;
720 		}
721 	}
722 
723 	if (dstsize < (size_t)dst.size)
724 		warnx("destination size rounded to %lld megabytes",
725 		    dst.size / 1048576);
726 
727  done:
728 	free(buf);
729 	free(zerobuf);
730 	if (src.file.p != NULL)
731 		src.file.close(src.file.p, 0);
732 	if (dst.file.p != NULL)
733 		dst.file.close(dst.file.p, 0);
734 	if (errstr != NULL)
735 		errx(1, "%s", errstr);
736 	else
737 		warnx("%s imagefile created", format);
738 
739 	return (0);
740 }
741 
742 int
743 ctl_status(struct parse_result *res, int argc, char *argv[])
744 {
745 	if (argc == 2) {
746 		if (parse_vmid(res, argv[1], 0) == -1)
747 			errx(1, "invalid id: %s", argv[1]);
748 	} else if (argc > 2)
749 		ctl_usage(res->ctl);
750 
751 	return (vmmaction(res));
752 }
753 
754 int
755 ctl_load(struct parse_result *res, int argc, char *argv[])
756 {
757 	if (argc != 2)
758 		ctl_usage(res->ctl);
759 
760 	if ((res->path = strdup(argv[1])) == NULL)
761 		err(1, "strdup");
762 
763 	return (vmmaction(res));
764 }
765 
766 int
767 ctl_log(struct parse_result *res, int argc, char *argv[])
768 {
769 	if (argc != 2)
770 		ctl_usage(res->ctl);
771 
772 	if (strncasecmp("brief", argv[1], strlen(argv[1])) == 0)
773 		res->verbose = 0;
774 	else if (strncasecmp("verbose", argv[1], strlen(argv[1])) == 0)
775 		res->verbose = 2;
776 	else
777 		ctl_usage(res->ctl);
778 
779 	return (vmmaction(res));
780 }
781 
782 int
783 ctl_reload(struct parse_result *res, int argc, char *argv[])
784 {
785 	if (argc != 1)
786 		ctl_usage(res->ctl);
787 
788 	return (vmmaction(res));
789 }
790 
791 int
792 ctl_reset(struct parse_result *res, int argc, char *argv[])
793 {
794 	if (argc == 2) {
795 		if (strcasecmp("all", argv[1]) == 0)
796 			res->mode = CONFIG_ALL;
797 		else if (strcasecmp("vms", argv[1]) == 0)
798 			res->mode = CONFIG_VMS;
799 		else if (strcasecmp("switches", argv[1]) == 0)
800 			res->mode = CONFIG_SWITCHES;
801 		else
802 			ctl_usage(res->ctl);
803 	} else if (argc > 2)
804 		ctl_usage(res->ctl);
805 
806 	if (res->mode == 0)
807 		res->mode = CONFIG_ALL;
808 
809 	return (vmmaction(res));
810 }
811 
812 int
813 ctl_start(struct parse_result *res, int argc, char *argv[])
814 {
815 	int		 ch, i, type;
816 	char		 path[PATH_MAX];
817 	const char	*s;
818 
819 	while ((ch = getopt(argc, argv, "b:B:cd:i:Lm:n:r:t:")) != -1) {
820 		switch (ch) {
821 		case 'b':
822 			if (res->path)
823 				errx(1, "boot image specified multiple times");
824 			if (realpath(optarg, path) == NULL)
825 				err(1, "invalid boot image path");
826 			if ((res->path = strdup(path)) == NULL)
827 				errx(1, "strdup");
828 			break;
829 		case 'B':
830 			if (res->bootdevice)
831 				errx(1, "boot device specified multiple times");
832 			if (strcmp("disk", optarg) == 0)
833 				res->bootdevice = VMBOOTDEV_DISK;
834 			else if (strcmp("cdrom", optarg) == 0)
835 				res->bootdevice = VMBOOTDEV_CDROM;
836 			else if (strcmp("net", optarg) == 0)
837 				res->bootdevice = VMBOOTDEV_NET;
838 			else
839 				errx(1, "unknown boot device %s", optarg);
840 			break;
841 		case 'r':
842 			if (res->isopath)
843 				errx(1, "iso image specified multiple times");
844 			if (realpath(optarg, path) == NULL)
845 				err(1, "invalid iso image path");
846 			if ((res->isopath = strdup(path)) == NULL)
847 				errx(1, "strdup");
848 			break;
849 		case 'c':
850 			tty_autoconnect = 1;
851 			break;
852 		case 'L':
853 			if (parse_network(res, ".") != 0)
854 				errx(1, "invalid network: %s", optarg);
855 			break;
856 		case 'm':
857 			if (res->size)
858 				errx(1, "memory specified multiple times");
859 			if (parse_size(res, optarg) != 0)
860 				errx(1, "invalid memory size: %s", optarg);
861 			break;
862 		case 'n':
863 			if (parse_network(res, optarg) != 0)
864 				errx(1, "invalid network: %s", optarg);
865 			break;
866 		case 'd':
867 			type = parse_disktype(optarg, &s);
868 			if (realpath(s, path) == NULL)
869 				err(1, "invalid disk path");
870 			if (parse_disk(res, path, type) != 0)
871 				errx(1, "invalid disk: %s", optarg);
872 			break;
873 		case 'i':
874 			if (res->nifs != -1)
875 				errx(1, "interfaces specified multiple times");
876 			if (parse_ifs(res, optarg, 0) != 0)
877 				errx(1, "invalid interface count: %s", optarg);
878 			break;
879 		case 't':
880 			if (parse_instance(res, optarg) == -1)
881 				errx(1, "invalid name: %s", optarg);
882 			break;
883 		default:
884 			ctl_usage(res->ctl);
885 			/* NOTREACHED */
886 		}
887 	}
888 	argc -= optind;
889 	argv += optind;
890 
891 	if (argc != 1)
892 		ctl_usage(res->ctl);
893 
894 	if (parse_vmid(res, argv[0], 0) == -1)
895 		errx(1, "invalid id: %s", argv[0]);
896 
897 	for (i = res->nnets; i < res->nifs; i++) {
898 		/* Add interface that is not attached to a switch */
899 		if (parse_network(res, "") == -1)
900 			return (-1);
901 	}
902 	if (res->nnets > res->nifs)
903 		res->nifs = res->nnets;
904 
905 	return (vmmaction(res));
906 }
907 
908 int
909 ctl_stop(struct parse_result *res, int argc, char *argv[])
910 {
911 	int		 ch;
912 
913 	while ((ch = getopt(argc, argv, "afw")) != -1) {
914 		switch (ch) {
915 		case 'f':
916 			res->flags |= VMOP_FORCE;
917 			break;
918 		case 'w':
919 			res->flags |= VMOP_WAIT;
920 			break;
921 		case 'a':
922 			res->action = CMD_STOPALL;
923 			break;
924 		default:
925 			ctl_usage(res->ctl);
926 			/* NOTREACHED */
927 		}
928 	}
929 	argc -= optind;
930 	argv += optind;
931 
932 	if (res->action == CMD_STOPALL) {
933 		if (argc != 0)
934 			ctl_usage(res->ctl);
935 	} else {
936 		if (argc != 1)
937 			ctl_usage(res->ctl);
938 		if (parse_vmid(res, argv[0], 0) == -1)
939 			errx(1, "invalid id: %s", argv[0]);
940 	}
941 
942 	return (vmmaction(res));
943 }
944 
945 int
946 ctl_console(struct parse_result *res, int argc, char *argv[])
947 {
948 	if (argc == 2) {
949 		if (parse_vmid(res, argv[1], 0) == -1)
950 			errx(1, "invalid id: %s", argv[1]);
951 	} else if (argc != 2)
952 		ctl_usage(res->ctl);
953 
954 	return (vmmaction(res));
955 }
956 
957 int
958 ctl_waitfor(struct parse_result *res, int argc, char *argv[])
959 {
960 	if (argc == 2) {
961 		if (parse_vmid(res, argv[1], 0) == -1)
962 			errx(1, "invalid id: %s", argv[1]);
963 	} else if (argc != 2)
964 		ctl_usage(res->ctl);
965 
966 	return (vmmaction(res));
967 }
968 
969 int
970 ctl_pause(struct parse_result *res, int argc, char *argv[])
971 {
972 	if (argc == 2) {
973 		if (parse_vmid(res, argv[1], 0) == -1)
974 			errx(1, "invalid id: %s", argv[1]);
975 	} else if (argc != 2)
976 		ctl_usage(res->ctl);
977 
978 	return (vmmaction(res));
979 }
980 
981 int
982 ctl_unpause(struct parse_result *res, int argc, char *argv[])
983 {
984 	if (argc == 2) {
985 		if (parse_vmid(res, argv[1], 0) == -1)
986 			errx(1, "invalid id: %s", argv[1]);
987 	} else if (argc != 2)
988 		ctl_usage(res->ctl);
989 
990 	return (vmmaction(res));
991 }
992 
993 int
994 ctl_send(struct parse_result *res, int argc, char *argv[])
995 {
996 	if (pledge("stdio unix sendfd unveil", NULL) == -1)
997 		err(1, "pledge");
998 	if (argc == 2) {
999 		if (parse_vmid(res, argv[1], 0) == -1)
1000 			errx(1, "invalid id: %s", argv[1]);
1001 	} else if (argc != 2)
1002 		ctl_usage(res->ctl);
1003 
1004 	return (vmmaction(res));
1005 }
1006 
1007 int
1008 ctl_receive(struct parse_result *res, int argc, char *argv[])
1009 {
1010 	if (pledge("stdio unix sendfd unveil", NULL) == -1)
1011 		err(1, "pledge");
1012 	if (argc == 2) {
1013 		if (parse_vmid(res, argv[1], 1) == -1)
1014 			errx(1, "invalid id: %s", argv[1]);
1015 	} else if (argc != 2)
1016 		ctl_usage(res->ctl);
1017 
1018 	return (vmmaction(res));
1019 }
1020 
1021 __dead void
1022 ctl_openconsole(const char *name)
1023 {
1024 	closefrom(STDERR_FILENO + 1);
1025 	if (unveil(VMCTL_CU, "x") == -1)
1026 		err(1, "unveil %s", VMCTL_CU);
1027 	execl(VMCTL_CU, VMCTL_CU, "-r", "-l", name, "-s", "115200",
1028 	    (char *)NULL);
1029 	err(1, "failed to open the console");
1030 }
1031