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