xref: /openbsd/usr.sbin/vmctl/vmctl.c (revision baf88fe3)
1 /*	$OpenBSD: vmctl.c,v 1.70 2019/08/14 07:34:49 anton Exp $	*/
2 
3 /*
4  * Copyright (c) 2014 Mike Larkin <mlarkin@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/queue.h>
20 #include <sys/uio.h>
21 #include <sys/stat.h>
22 #include <sys/socket.h>
23 #include <sys/un.h>
24 
25 #include <machine/vmmvar.h>
26 
27 #include <ctype.h>
28 #include <err.h>
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <imsg.h>
32 #include <limits.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <unistd.h>
37 #include <util.h>
38 #include <pwd.h>
39 #include <grp.h>
40 
41 #include "vmd.h"
42 #include "virtio.h"
43 #include "vmctl.h"
44 #include "atomicio.h"
45 
46 extern char *__progname;
47 uint32_t info_id;
48 char info_name[VMM_MAX_NAME_LEN];
49 enum actions info_action;
50 unsigned int info_flags;
51 
52 /*
53  * vm_start
54  *
55  * Request vmd to start the VM defined by the supplied parameters
56  *
57  * Parameters:
58  *  start_id: optional ID of the VM
59  *  name: optional name of the VM
60  *  memsize: memory size (MB) of the VM to create
61  *  nnics: number of vionet network interfaces to create
62  *  nics: switch names of the network interfaces to create
63  *  ndisks: number of disk images
64  *  disks: disk image file names
65  *  kernel: kernel image to load
66  *  iso: iso image file
67  *  instance: create instance from vm
68  *
69  * Return:
70  *  0 if the request to start the VM was sent successfully.
71  *  ENOMEM if a memory allocation failure occurred.
72  */
73 int
74 vm_start(uint32_t start_id, const char *name, int memsize, int nnics,
75     char **nics, int ndisks, char **disks, int *disktypes, char *kernel,
76     char *iso, char *instance, unsigned int bootdevice)
77 {
78 	struct vmop_create_params *vmc;
79 	struct vm_create_params *vcp;
80 	unsigned int flags = 0;
81 	int i;
82 	const char *s;
83 
84 	if (memsize)
85 		flags |= VMOP_CREATE_MEMORY;
86 	if (nnics)
87 		flags |= VMOP_CREATE_NETWORK;
88 	if (ndisks)
89 		flags |= VMOP_CREATE_DISK;
90 	if (kernel)
91 		flags |= VMOP_CREATE_KERNEL;
92 	if (iso)
93 		flags |= VMOP_CREATE_CDROM;
94 	if (instance)
95 		flags |= VMOP_CREATE_INSTANCE;
96 	else if (flags != 0) {
97 		if (memsize < 1)
98 			memsize = VM_DEFAULT_MEMORY;
99 		if (ndisks > VMM_MAX_DISKS_PER_VM)
100 			errx(1, "too many disks");
101 		else if (ndisks == 0)
102 			warnx("starting without disks");
103 		if (kernel == NULL && ndisks == 0 && !iso)
104 			errx(1, "no kernel or disk/cdrom specified");
105 		if (nnics == -1)
106 			nnics = 0;
107 		if (nnics > VMM_MAX_NICS_PER_VM)
108 			errx(1, "too many network interfaces");
109 		if (nnics == 0)
110 			warnx("starting without network interfaces");
111 	}
112 
113 	if ((vmc = calloc(1, sizeof(struct vmop_create_params))) == NULL)
114 		return (ENOMEM);
115 
116 	vmc->vmc_flags = flags;
117 
118 	/* vcp includes configuration that is shared with the kernel */
119 	vcp = &vmc->vmc_params;
120 
121 	/*
122 	 * XXX: vmd(8) fills in the actual memory ranges. vmctl(8)
123 	 * just passes in the actual memory size in MB here.
124 	 */
125 	vcp->vcp_nmemranges = 1;
126 	vcp->vcp_memranges[0].vmr_size = memsize;
127 
128 	vcp->vcp_ncpus = 1;
129 	vcp->vcp_ndisks = ndisks;
130 	vcp->vcp_nnics = nnics;
131 	vcp->vcp_id = start_id;
132 
133 	for (i = 0 ; i < ndisks; i++) {
134 		if (strlcpy(vcp->vcp_disks[i], disks[i],
135 		    sizeof(vcp->vcp_disks[i])) >=
136 		    sizeof(vcp->vcp_disks[i]))
137 			errx(1, "disk path too long");
138 		vmc->vmc_disktypes[i] = disktypes[i];
139 	}
140 	for (i = 0 ; i < nnics; i++) {
141 		vmc->vmc_ifflags[i] = VMIFF_UP;
142 
143 		if (strcmp(".", nics[i]) == 0) {
144 			/* Add a "local" interface */
145 			(void)strlcpy(vmc->vmc_ifswitch[i], "",
146 			    sizeof(vmc->vmc_ifswitch[i]));
147 			vmc->vmc_ifflags[i] |= VMIFF_LOCAL;
148 		} else {
149 			/* Add an interface to a switch */
150 			if (strlcpy(vmc->vmc_ifswitch[i], nics[i],
151 			    sizeof(vmc->vmc_ifswitch[i])) >=
152 			    sizeof(vmc->vmc_ifswitch[i]))
153 				errx(1, "interface name too long");
154 		}
155 	}
156 	if (name != NULL) {
157 		/*
158 		 * Allow VMs names with alphanumeric characters, dot, hyphen
159 		 * and underscore. But disallow dot, hyphen and underscore at
160 		 * the start.
161 		 */
162 		if (*name == '-' || *name == '.' || *name == '_')
163 			errx(1, "invalid VM name");
164 
165 		for (s = name; *s != '\0'; ++s) {
166 			if (!(isalnum(*s) || *s == '.' || *s == '-' ||
167 			    *s == '_'))
168 				errx(1, "invalid VM name");
169 		}
170 
171 		if (strlcpy(vcp->vcp_name, name,
172 		    sizeof(vcp->vcp_name)) >= sizeof(vcp->vcp_name))
173 			errx(1, "vm name too long");
174 	}
175 	if (kernel != NULL)
176 		if (strlcpy(vcp->vcp_kernel, kernel,
177 		    sizeof(vcp->vcp_kernel)) >= sizeof(vcp->vcp_kernel))
178 			errx(1, "kernel name too long");
179 	if (iso != NULL)
180 		if (strlcpy(vcp->vcp_cdrom, iso,
181 		    sizeof(vcp->vcp_cdrom)) >= sizeof(vcp->vcp_cdrom))
182 			errx(1, "cdrom name too long");
183 	if (instance != NULL)
184 		if (strlcpy(vmc->vmc_instance, instance,
185 		    sizeof(vmc->vmc_instance)) >= sizeof(vmc->vmc_instance))
186 			errx(1, "instance vm name too long");
187 	vmc->vmc_bootdevice = bootdevice;
188 
189 	imsg_compose(ibuf, IMSG_VMDOP_START_VM_REQUEST, 0, 0, -1,
190 	    vmc, sizeof(struct vmop_create_params));
191 
192 	free(vcp);
193 	return (0);
194 }
195 
196 /*
197  * vm_start_complete
198  *
199  * Callback function invoked when we are expecting an
200  * IMSG_VMDOP_START_VMM_RESPONSE message indicating the completion of
201  * a start vm operation.
202  *
203  * Parameters:
204  *  imsg : response imsg received from vmd
205  *  ret  : return value
206  *  autoconnect : open the console after startup
207  *
208  * Return:
209  *  Always 1 to indicate we have processed the return message (even if it
210  *  was an incorrect/failure message)
211  *
212  *  The function also sets 'ret' to the error code as follows:
213  *   0     : Message successfully processed
214  *   EINVAL: Invalid or unexpected response from vmd
215  *   EIO   : vm_start command failed
216  *   ENOENT: a specified component of the VM could not be found (disk image,
217  *    BIOS firmware image, etc)
218  */
219 int
220 vm_start_complete(struct imsg *imsg, int *ret, int autoconnect)
221 {
222 	struct vmop_result *vmr;
223 	int res;
224 
225 	if (imsg->hdr.type == IMSG_VMDOP_START_VM_RESPONSE) {
226 		vmr = (struct vmop_result *)imsg->data;
227 		res = vmr->vmr_result;
228 		if (res) {
229 			switch (res) {
230 			case VMD_BIOS_MISSING:
231 				warnx("vmm bios firmware file not found.");
232 				*ret = ENOENT;
233 				break;
234 			case VMD_DISK_MISSING:
235 				warnx("could not open disk image(s)");
236 				*ret = ENOENT;
237 				break;
238 			case VMD_DISK_INVALID:
239 				warnx("specified disk image(s) are "
240 				    "not regular files");
241 				*ret = ENOENT;
242 				break;
243 			case VMD_CDROM_MISSING:
244 				warnx("could not find specified iso image");
245 				*ret = ENOENT;
246 				break;
247 			case VMD_CDROM_INVALID:
248 				warnx("specified iso image is not a regular "
249 				    "file");
250 				*ret = ENOENT;
251 				break;
252 			case VMD_PARENT_INVALID:
253 				warnx("invalid template");
254 				*ret = EINVAL;
255 				break;
256 			default:
257 				errno = res;
258 				warn("start vm command failed");
259 				*ret = EIO;
260 			}
261 		} else if (autoconnect) {
262 			/* does not return */
263 			ctl_openconsole(vmr->vmr_ttyname);
264 		} else {
265 			warnx("started vm %d successfully, tty %s",
266 			    vmr->vmr_id, vmr->vmr_ttyname);
267 			*ret = 0;
268 		}
269 	} else {
270 		warnx("unexpected response received from vmd");
271 		*ret = EINVAL;
272 	}
273 
274 	return (1);
275 }
276 
277 void
278 send_vm(uint32_t id, const char *name)
279 {
280 	struct vmop_id vid;
281 	int fds[2], readn, writen;
282 	long pagesz;
283 	char *buf;
284 
285 	pagesz = getpagesize();
286 	buf = malloc(pagesz);
287 	if (buf == NULL)
288 		errx(1, "%s: memory allocation failure", __func__);
289 
290 	memset(&vid, 0, sizeof(vid));
291 	vid.vid_id = id;
292 	if (name != NULL)
293 		strlcpy(vid.vid_name, name, sizeof(vid.vid_name));
294 	if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, fds) == -1) {
295 		warnx("%s: socketpair creation failed", __func__);
296 	} else {
297 		imsg_compose(ibuf, IMSG_VMDOP_SEND_VM_REQUEST, 0, 0, fds[0],
298 				&vid, sizeof(vid));
299 		imsg_flush(ibuf);
300 		while (1) {
301 			readn = atomicio(read, fds[1], buf, pagesz);
302 			if (!readn)
303 				break;
304 			writen = atomicio(vwrite, STDOUT_FILENO, buf,
305 					readn);
306 			if (writen != readn)
307 				break;
308 		}
309 		if (vid.vid_id)
310 			warnx("sent vm %d successfully", vid.vid_id);
311 		else
312 			warnx("sent vm %s successfully", vid.vid_name);
313 	}
314 
315 	free(buf);
316 }
317 
318 void
319 vm_receive(uint32_t id, const char *name)
320 {
321 	struct vmop_id vid;
322 	int fds[2], readn, writen;
323 	long pagesz;
324 	char *buf;
325 
326 	pagesz = getpagesize();
327 	buf = malloc(pagesz);
328 	if (buf == NULL)
329 		errx(1, "%s: memory allocation failure", __func__);
330 
331 	memset(&vid, 0, sizeof(vid));
332 	if (name != NULL)
333 		strlcpy(vid.vid_name, name, sizeof(vid.vid_name));
334 	if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, fds) == -1) {
335 		warnx("%s: socketpair creation failed", __func__);
336 	} else {
337 		imsg_compose(ibuf, IMSG_VMDOP_RECEIVE_VM_REQUEST, 0, 0, fds[0],
338 		    &vid, sizeof(vid));
339 		imsg_flush(ibuf);
340 		while (1) {
341 			readn = atomicio(read, STDIN_FILENO, buf, pagesz);
342 			if (!readn) {
343 				close(fds[1]);
344 				break;
345 			}
346 			writen = atomicio(vwrite, fds[1], buf, readn);
347 			if (writen != readn)
348 				break;
349 		}
350 	}
351 
352 	free(buf);
353 }
354 
355 void
356 pause_vm(uint32_t pause_id, const char *name)
357 {
358 	struct vmop_id vid;
359 
360 	memset(&vid, 0, sizeof(vid));
361 	vid.vid_id = pause_id;
362 	if (name != NULL)
363 		(void)strlcpy(vid.vid_name, name, sizeof(vid.vid_name));
364 
365 	imsg_compose(ibuf, IMSG_VMDOP_PAUSE_VM, 0, 0, -1,
366 	    &vid, sizeof(vid));
367 }
368 
369 int
370 pause_vm_complete(struct imsg *imsg, int *ret)
371 {
372 	struct vmop_result *vmr;
373 	int res;
374 
375 	if (imsg->hdr.type == IMSG_VMDOP_PAUSE_VM_RESPONSE) {
376 		vmr = (struct vmop_result *)imsg->data;
377 		res = vmr->vmr_result;
378 		if (res) {
379 			errno = res;
380 			warn("pause vm command failed");
381 			*ret = EIO;
382 		} else {
383 			warnx("paused vm %d successfully", vmr->vmr_id);
384 			*ret = 0;
385 		}
386 	} else {
387 		warnx("unexpected response received from vmd");
388 		*ret = EINVAL;
389 	}
390 
391 	return (1);
392 }
393 
394 void
395 unpause_vm(uint32_t pause_id, const char *name)
396 {
397 	struct vmop_id vid;
398 
399 	memset(&vid, 0, sizeof(vid));
400 	vid.vid_id = pause_id;
401 	if (name != NULL)
402 		(void)strlcpy(vid.vid_name, name, sizeof(vid.vid_name));
403 
404 	imsg_compose(ibuf, IMSG_VMDOP_UNPAUSE_VM, 0, 0, -1,
405 	    &vid, sizeof(vid));
406 }
407 
408 int
409 unpause_vm_complete(struct imsg *imsg, int *ret)
410 {
411 	struct vmop_result *vmr;
412 	int res;
413 
414 	if (imsg->hdr.type == IMSG_VMDOP_UNPAUSE_VM_RESPONSE) {
415 		vmr = (struct vmop_result *)imsg->data;
416 		res = vmr->vmr_result;
417 		if (res) {
418 			errno = res;
419 			warn("unpause vm command failed");
420 			*ret = EIO;
421 		} else {
422 			warnx("unpaused vm %d successfully", vmr->vmr_id);
423 			*ret = 0;
424 		}
425 	} else {
426 		warnx("unexpected response received from vmd");
427 		*ret = EINVAL;
428 	}
429 
430 	return (1);
431 }
432 
433 /*
434  * terminate_vm
435  *
436  * Request vmd to stop the VM indicated
437  *
438  * Parameters:
439  *  terminate_id: ID of the vm to be terminated
440  *  name: optional name of the VM to be terminated
441  *  flags: VMOP_FORCE or VMOP_WAIT flags
442  */
443 void
444 terminate_vm(uint32_t terminate_id, const char *name, unsigned int flags)
445 {
446 	struct vmop_id vid;
447 
448 	memset(&vid, 0, sizeof(vid));
449 	vid.vid_id = terminate_id;
450 	if (name != NULL) {
451 		(void)strlcpy(vid.vid_name, name, sizeof(vid.vid_name));
452 		fprintf(stderr, "stopping vm %s: ", name);
453 	} else {
454 		fprintf(stderr, "stopping vm: ");
455 	}
456 
457 	vid.vid_flags = flags & (VMOP_FORCE|VMOP_WAIT);
458 
459 	imsg_compose(ibuf, IMSG_VMDOP_TERMINATE_VM_REQUEST,
460 	    0, 0, -1, &vid, sizeof(vid));
461 }
462 
463 /*
464  * terminate_vm_complete
465  *
466  * Callback function invoked when we are expecting an
467  * IMSG_VMDOP_TERMINATE_VMM_RESPONSE message indicating the completion of
468  * a terminate vm operation.
469  *
470  * Parameters:
471  *  imsg : response imsg received from vmd
472  *  ret  : return value
473  *  flags: VMOP_FORCE or VMOP_WAIT flags
474  *
475  * Return:
476  *  Always 1 to indicate we have processed the return message (even if it
477  *  was an incorrect/failure message)
478  *
479  *  The function also sets 'ret' to the error code as follows:
480  *   0     : Message successfully processed
481  *   EINVAL: Invalid or unexpected response from vmd
482  *   EIO   : terminate_vm command failed
483  */
484 int
485 terminate_vm_complete(struct imsg *imsg, int *ret, unsigned int flags)
486 {
487 	struct vmop_result *vmr;
488 	int res;
489 
490 	if (imsg->hdr.type == IMSG_VMDOP_TERMINATE_VM_RESPONSE) {
491 		vmr = (struct vmop_result *)imsg->data;
492 		res = vmr->vmr_result;
493 		if (res) {
494 			switch (res) {
495 			case VMD_VM_STOP_INVALID:
496 				fprintf(stderr,
497 				    "cannot stop vm that is not running\n");
498 				*ret = EINVAL;
499 				break;
500 			case ENOENT:
501 				fprintf(stderr, "vm not found\n");
502 				*ret = EIO;
503 				break;
504 			case EINTR:
505 				fprintf(stderr, "interrupted call\n");
506 				*ret = EIO;
507 				break;
508 			default:
509 				errno = res;
510 				fprintf(stderr, "failed: %s\n",
511 				    strerror(res));
512 				*ret = EIO;
513 			}
514 		} else if (flags & VMOP_WAIT) {
515 			fprintf(stderr, "terminated vm %d\n", vmr->vmr_id);
516 		} else if (flags & VMOP_FORCE) {
517 			fprintf(stderr, "forced to terminate vm %d\n",
518 			    vmr->vmr_id);
519 		} else {
520 			fprintf(stderr, "requested to shutdown vm %d\n",
521 			    vmr->vmr_id);
522 			*ret = 0;
523 		}
524 	} else {
525 		fprintf(stderr, "unexpected response received from vmd\n");
526 		*ret = EINVAL;
527 	}
528 	errno = *ret;
529 
530 	return (1);
531 }
532 
533 /*
534  * terminate_all
535  *
536  * Request to stop all VMs gracefully
537  *
538  * Parameters
539  *  list: the vm information (consolidated) returned from vmd via imsg
540  *  ct  : the size (number of elements in 'list') of the result
541  *  flags: VMOP_FORCE or VMOP_WAIT flags
542  */
543 void
544 terminate_all(struct vmop_info_result *list, size_t ct, unsigned int flags)
545 {
546 	struct vm_info_result *vir;
547 	struct vmop_info_result *vmi;
548 	struct parse_result res;
549 	size_t i;
550 
551 	for (i = 0; i < ct; i++) {
552 		vmi = &list[i];
553 		vir = &vmi->vir_info;
554 
555 		/* The VM is already stopped */
556 		if (vir->vir_creator_pid == 0 || vir->vir_id == 0)
557 			continue;
558 
559 		memset(&res, 0, sizeof(res));
560 		res.action = CMD_STOP;
561 		res.id = 0;
562 		res.flags = info_flags;
563 
564 		if ((res.name = strdup(vir->vir_name)) == NULL)
565 			errx(1, "strdup");
566 
567 		vmmaction(&res);
568 	}
569 }
570 
571 /*
572  * waitfor_vm
573  *
574  * Wait until vmd stopped the indicated VM
575  *
576  * Parameters:
577  *  terminate_id: ID of the vm to be terminated
578  *  name: optional name of the VM to be terminated
579  */
580 void
581 waitfor_vm(uint32_t terminate_id, const char *name)
582 {
583 	struct vmop_id vid;
584 
585 	memset(&vid, 0, sizeof(vid));
586 	vid.vid_id = terminate_id;
587 	if (name != NULL) {
588 		(void)strlcpy(vid.vid_name, name, sizeof(vid.vid_name));
589 		fprintf(stderr, "waiting for vm %s: ", name);
590 	} else {
591 		fprintf(stderr, "waiting for vm: ");
592 	}
593 
594 	imsg_compose(ibuf, IMSG_VMDOP_WAIT_VM_REQUEST,
595 	    0, 0, -1, &vid, sizeof(vid));
596 }
597 
598 /*
599  * get_info_vm
600  *
601  * Return the list of all running VMs or find a specific VM by ID or name.
602  *
603  * Parameters:
604  *  id: optional ID of a VM to list
605  *  name: optional name of a VM to list
606  *  action: if CMD_CONSOLE or CMD_STOP open a console or terminate the VM.
607  *  flags: optional flags used by the CMD_STOP action.
608  *
609  * Request a list of running VMs from vmd
610  */
611 void
612 get_info_vm(uint32_t id, const char *name, enum actions action,
613     unsigned int flags)
614 {
615 	info_id = id;
616 	if (name != NULL)
617 		(void)strlcpy(info_name, name, sizeof(info_name));
618 	info_action = action;
619 	info_flags = flags;
620 	imsg_compose(ibuf, IMSG_VMDOP_GET_INFO_VM_REQUEST, 0, 0, -1, NULL, 0);
621 }
622 
623 /*
624  * check_info_id
625  *
626  * Check if requested name or ID of a VM matches specified arguments
627  *
628  * Parameters:
629  *  name: name of the VM
630  *  id: ID of the VM
631  */
632 int
633 check_info_id(const char *name, uint32_t id)
634 {
635 	if (info_id == 0 && *info_name == '\0')
636 		return (-1);
637 	if (info_id != 0 && info_id == id)
638 		return (1);
639 	if (*info_name != '\0' && name && strcmp(info_name, name) == 0)
640 		return (1);
641 	return (0);
642 }
643 
644 /*
645  * add_info
646  *
647  * Callback function invoked when we are expecting an
648  * IMSG_VMDOP_GET_INFO_VM_DATA message indicating the receipt of additional
649  * "list vm" data, or an IMSG_VMDOP_GET_INFO_VM_END_DATA message indicating
650  * that no additional "list vm" data will be forthcoming.
651  *
652  * Parameters:
653  *  imsg : response imsg received from vmd
654  *  ret  : return value
655  *
656  * Return:
657  *  0     : the returned data was successfully added to the "list vm" data.
658  *          The caller can expect more data.
659  *  1     : IMSG_VMDOP_GET_INFO_VM_END_DATA received (caller should not call
660  *          add_info again), or an error occurred adding the returned data
661  *          to the "list vm" data. The caller should check the value of
662  *          'ret' to determine which case occurred.
663  *
664  * This function does not return if a VM is found and info_action is CMD_CONSOLE
665  *
666  *  The function also sets 'ret' to the error code as follows:
667  *   0     : Message successfully processed
668  *   EINVAL: Invalid or unexpected response from vmd
669  *   ENOMEM: memory allocation failure
670  */
671 int
672 add_info(struct imsg *imsg, int *ret)
673 {
674 	static size_t ct = 0;
675 	static struct vmop_info_result *vir = NULL;
676 
677 	if (imsg->hdr.type == IMSG_VMDOP_GET_INFO_VM_DATA) {
678 		vir = reallocarray(vir, ct + 1,
679 		    sizeof(struct vmop_info_result));
680 		if (vir == NULL) {
681 			*ret = ENOMEM;
682 			return (1);
683 		}
684 		memcpy(&vir[ct], imsg->data, sizeof(struct vmop_info_result));
685 		ct++;
686 		*ret = 0;
687 		return (0);
688 	} else if (imsg->hdr.type == IMSG_VMDOP_GET_INFO_VM_END_DATA) {
689 		switch (info_action) {
690 		case CMD_CONSOLE:
691 			vm_console(vir, ct);
692 			break;
693 		case CMD_STOPALL:
694 			terminate_all(vir, ct, info_flags);
695 			break;
696 		default:
697 			print_vm_info(vir, ct);
698 			break;
699 		}
700 		free(vir);
701 		*ret = 0;
702 		return (1);
703 	} else {
704 		*ret = EINVAL;
705 		return (1);
706 	}
707 }
708 
709 /*
710  * vm_state
711  *
712  * Returns a string representing the current VM state, note that the order
713  * matters. A paused VM does have the VM_STATE_RUNNING bit set, but
714  * VM_STATE_PAUSED is more significant to report.
715  *
716  * Parameters
717  *  vm_state: mask indicating the vm state
718  */
719 const char *
720 vm_state(unsigned int mask)
721 {
722 	if (mask & VM_STATE_PAUSED)
723 		return "paused";
724 	else if (mask & VM_STATE_RUNNING)
725 		return "running";
726 	else if (mask & VM_STATE_SHUTDOWN)
727 		return "stopping";
728 	/* Presence of absence of other flags */
729 	else if (!mask || (mask & VM_STATE_DISABLED))
730 		return "stopped";
731 
732 	return "unknown";
733 }
734 
735 /*
736  * print_vm_info
737  *
738  * Prints the vm information returned from vmd in 'list' to stdout.
739  *
740  * Parameters
741  *  list: the vm information (consolidated) returned from vmd via imsg
742  *  ct  : the size (number of elements in 'list') of the result
743  */
744 void
745 print_vm_info(struct vmop_info_result *list, size_t ct)
746 {
747 	struct vm_info_result *vir;
748 	struct vmop_info_result *vmi;
749 	size_t i;
750 	char *tty;
751 	char curmem[FMT_SCALED_STRSIZE];
752 	char maxmem[FMT_SCALED_STRSIZE];
753 	char user[16], group[16];
754 	const char *name;
755 	int running;
756 
757 	printf("%5s %5s %5s %7s %7s %7s %12s %8s %s\n", "ID", "PID", "VCPUS",
758 	    "MAXMEM", "CURMEM", "TTY", "OWNER", "STATE", "NAME");
759 
760 	for (i = 0; i < ct; i++) {
761 		vmi = &list[i];
762 		vir = &vmi->vir_info;
763 		running = (vir->vir_creator_pid != 0 && vir->vir_id != 0);
764 		if (check_info_id(vir->vir_name, vir->vir_id)) {
765 			/* get user name */
766 			name = user_from_uid(vmi->vir_uid, 1);
767 			if (name == NULL)
768 				(void)snprintf(user, sizeof(user),
769 				    "%d", vmi->vir_uid);
770 			else
771 				(void)strlcpy(user, name, sizeof(user));
772 			/* get group name */
773 			if (vmi->vir_gid != -1) {
774 				if (vmi->vir_uid == 0)
775 					*user = '\0';
776 				name = group_from_gid(vmi->vir_gid, 1);
777 				if (name == NULL)
778 					(void)snprintf(group, sizeof(group),
779 					    ":%lld", vmi->vir_gid);
780 				else
781 					(void)snprintf(group, sizeof(group),
782 					    ":%s", name);
783 				(void)strlcat(user, group, sizeof(user));
784 			}
785 
786 			(void)strlcpy(curmem, "-", sizeof(curmem));
787 			(void)strlcpy(maxmem, "-", sizeof(maxmem));
788 
789 			(void)fmt_scaled(vir->vir_memory_size * 1024 * 1024,
790 			    maxmem);
791 
792 			if (running) {
793 				if (*vmi->vir_ttyname == '\0')
794 					tty = "-";
795 				/* get tty - skip /dev/ path */
796 				else if ((tty = strrchr(vmi->vir_ttyname,
797 				    '/')) == NULL || ++tty == '\0')
798 					tty = list[i].vir_ttyname;
799 
800 				(void)fmt_scaled(vir->vir_used_size, curmem);
801 
802 				/* running vm */
803 				printf("%5u %5u %5zd %7s %7s %7s %12s %8s %s\n",
804 				    vir->vir_id, vir->vir_creator_pid,
805 				    vir->vir_ncpus, maxmem, curmem,
806 				    tty, user, vm_state(vmi->vir_state),
807 				    vir->vir_name);
808 			} else {
809 				/* disabled vm */
810 				printf("%5u %5s %5zd %7s %7s %7s %12s %8s %s\n",
811 				    vir->vir_id, "-",
812 				    vir->vir_ncpus, maxmem, curmem,
813 				    "-", user, vm_state(vmi->vir_state),
814 				    vir->vir_name);
815 			}
816 		}
817 	}
818 }
819 
820 /*
821  * vm_console
822  *
823  * Connects to the vm console returned from vmd in 'list'.
824  *
825  * Parameters
826  *  list: the vm information (consolidated) returned from vmd via imsg
827  *  ct  : the size (number of elements in 'list') of the result
828  */
829 __dead void
830 vm_console(struct vmop_info_result *list, size_t ct)
831 {
832 	struct vmop_info_result *vir;
833 	size_t i;
834 
835 	for (i = 0; i < ct; i++) {
836 		vir = &list[i];
837 		if ((check_info_id(vir->vir_info.vir_name,
838 		    vir->vir_info.vir_id) > 0) &&
839 			(vir->vir_ttyname[0] != '\0')) {
840 			/* does not return */
841 			ctl_openconsole(vir->vir_ttyname);
842 		}
843 	}
844 
845 	errx(1, "console not found");
846 }
847 
848 /*
849  * open_imagefile
850  *
851  * Open an imagefile with the specified type, path and size.
852  *
853  * Parameters:
854  *  type        : format of the image file
855  *  imgfile_path: path to the image file to create
856  *  flags       : flags for open(2), e.g. O_RDONLY
857  *  file        : file structure
858  *  sz		: size of the image file
859  *
860  * Return:
861  *  fd          : Returns file descriptor of the new image file
862  *  -1          : Operation failed.  errno is set.
863  */
864 int
865 open_imagefile(int type, const char *imgfile_path, int flags,
866     struct virtio_backing *file, off_t *sz)
867 {
868 	int	 fd, ret, basefd[VM_MAX_BASE_PER_DISK], nfd, i;
869 	char	 path[PATH_MAX];
870 
871 	*sz = 0;
872 	if ((fd = open(imgfile_path, flags)) == -1)
873 		return (-1);
874 
875 	basefd[0] = fd;
876 	nfd = 1;
877 
878 	errno = 0;
879 	switch (type) {
880 	case VMDF_QCOW2:
881 		if (strlcpy(path, imgfile_path, sizeof(path)) >= sizeof(path))
882 			return (-1);
883 		for (i = 0; i < VM_MAX_BASE_PER_DISK - 1; i++, nfd++) {
884 			if ((ret = virtio_qcow2_get_base(basefd[i],
885 			    path, sizeof(path), imgfile_path)) == -1) {
886 				log_debug("%s: failed to get base %d", __func__, i);
887 				return -1;
888 			} else if (ret == 0)
889 				break;
890 
891 			/*
892 			 * This might be called after unveil is already
893 			 * locked but it is save to ignore the EPERM error
894 			 * here as the subsequent open would fail as well.
895 			 */
896 			if ((ret = unveil(path, "r")) != 0 &&
897 			    (ret != EPERM))
898 				err(1, "unveil");
899 			if ((basefd[i + 1] = open(path, O_RDONLY)) == -1) {
900 				log_warn("%s: failed to open base %s",
901 				    __func__, path);
902 				return (-1);
903 			}
904 		}
905 		ret = virtio_qcow2_init(file, sz, basefd, nfd);
906 		break;
907 	default:
908 		ret = virtio_raw_init(file, sz, &fd, 1);
909 		break;
910 	}
911 
912 	if (ret == -1) {
913 		for (i = 0; i < nfd; i++)
914 			close(basefd[i]);
915 		return (-1);
916 	}
917 
918 	return (fd);
919 }
920 
921 /*
922  * create_imagefile
923  *
924  * Create an empty imagefile with the specified type, path and size.
925  *
926  * Parameters:
927  *  type        : format of the image file
928  *  imgfile_path: path to the image file to create
929  *  base_path   : path to the qcow2 base image
930  *  imgsize     : size of the image file to create (in MB)
931  *  format      : string identifying the format
932  *
933  * Return:
934  *  EEXIST: The requested image file already exists
935  *  0     : Image file successfully created
936  *  Exxxx : Various other Exxxx errno codes due to other I/O errors
937  */
938 int
939 create_imagefile(int type, const char *imgfile_path, const char *base_path,
940     long imgsize, const char **format)
941 {
942 	int	 ret;
943 
944 	switch (type) {
945 	case VMDF_QCOW2:
946 		*format = "qcow2";
947 		ret = virtio_qcow2_create(imgfile_path, base_path, imgsize);
948 		break;
949 	default:
950 		*format = "raw";
951 		ret = virtio_raw_create(imgfile_path, imgsize);
952 		break;
953 	}
954 
955 	return (ret);
956 }
957 
958