vmd.c revision 1.51
1/*	$OpenBSD: vmd.c,v 1.51 2017/02/27 14:37:58 reyk 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/param.h>	/* nitems */
20#include <sys/queue.h>
21#include <sys/wait.h>
22#include <sys/cdefs.h>
23#include <sys/tty.h>
24#include <sys/ioctl.h>
25
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29#include <termios.h>
30#include <errno.h>
31#include <event.h>
32#include <fcntl.h>
33#include <pwd.h>
34#include <signal.h>
35#include <syslog.h>
36#include <unistd.h>
37#include <ctype.h>
38
39#include "proc.h"
40#include "vmd.h"
41
42__dead void usage(void);
43
44int	 main(int, char **);
45int	 vmd_configure(void);
46void	 vmd_sighdlr(int sig, short event, void *arg);
47void	 vmd_shutdown(void);
48int	 vmd_control_run(void);
49int	 vmd_dispatch_control(int, struct privsep_proc *, struct imsg *);
50int	 vmd_dispatch_vmm(int, struct privsep_proc *, struct imsg *);
51
52struct vmd	*env;
53
54static struct privsep_proc procs[] = {
55	/* Keep "priv" on top as procs[0] */
56	{ "priv",	PROC_PRIV,	NULL, priv },
57	{ "control",	PROC_CONTROL,	vmd_dispatch_control, control },
58	{ "vmm",	PROC_VMM,	vmd_dispatch_vmm, vmm, vmm_shutdown },
59};
60
61/* For the privileged process */
62static struct privsep_proc *proc_priv = &procs[0];
63static struct passwd proc_privpw;
64
65int
66vmd_dispatch_control(int fd, struct privsep_proc *p, struct imsg *imsg)
67{
68	struct privsep			*ps = p->p_ps;
69	int				 res = 0, ret = 0, cmd = 0, verbose;
70	unsigned int			 v = 0;
71	struct vmop_create_params	 vmc;
72	struct vmop_id			 vid;
73	struct vm_terminate_params	 vtp;
74	struct vmop_result		 vmr;
75	struct vmd_vm			*vm = NULL;
76	char				*str = NULL;
77	uint32_t			 id = 0;
78
79	switch (imsg->hdr.type) {
80	case IMSG_VMDOP_START_VM_REQUEST:
81		IMSG_SIZE_CHECK(imsg, &vmc);
82		memcpy(&vmc, imsg->data, sizeof(vmc));
83		ret = vm_register(ps, &vmc, &vm, 0);
84		if (vmc.vmc_flags == 0) {
85			/* start an existing VM with pre-configured options */
86			if (!(ret == -1 && errno == EALREADY)) {
87				res = errno;
88				cmd = IMSG_VMDOP_START_VM_RESPONSE;
89			}
90		} else if (ret != 0) {
91			res = errno;
92			cmd = IMSG_VMDOP_START_VM_RESPONSE;
93		}
94		if (res == 0 &&
95		    config_setvm(ps, vm, imsg->hdr.peerid) == -1) {
96			res = errno;
97			cmd = IMSG_VMDOP_START_VM_RESPONSE;
98		}
99		break;
100	case IMSG_VMDOP_TERMINATE_VM_REQUEST:
101		IMSG_SIZE_CHECK(imsg, &vid);
102		memcpy(&vid, imsg->data, sizeof(vid));
103		if ((id = vid.vid_id) == 0) {
104			/* Lookup vm (id) by name */
105			if ((vm = vm_getbyname(vid.vid_name)) == NULL) {
106				res = ENOENT;
107				cmd = IMSG_VMDOP_TERMINATE_VM_RESPONSE;
108				break;
109			}
110			id = vm->vm_params.vmc_params.vcp_id;
111		}
112		memset(&vtp, 0, sizeof(vtp));
113		vtp.vtp_vm_id = id;
114		if (proc_compose_imsg(ps, PROC_VMM, -1, imsg->hdr.type,
115		    imsg->hdr.peerid, -1, &vtp, sizeof(vtp)) == -1)
116			return (-1);
117		break;
118	case IMSG_VMDOP_GET_INFO_VM_REQUEST:
119		proc_forward_imsg(ps, imsg, PROC_VMM, -1);
120		break;
121	case IMSG_VMDOP_LOAD:
122		IMSG_SIZE_CHECK(imsg, str); /* at least one byte for path */
123		str = get_string((uint8_t *)imsg->data,
124		    IMSG_DATA_SIZE(imsg));
125	case IMSG_VMDOP_RELOAD:
126		vmd_reload(0, str);
127		free(str);
128		break;
129	case IMSG_CTL_RESET:
130		IMSG_SIZE_CHECK(imsg, &v);
131		memcpy(&v, imsg->data, sizeof(v));
132		vmd_reload(v, str);
133		break;
134	case IMSG_CTL_VERBOSE:
135		IMSG_SIZE_CHECK(imsg, &verbose);
136		memcpy(&verbose, imsg->data, sizeof(verbose));
137		log_setverbose(verbose);
138
139		proc_forward_imsg(ps, imsg, PROC_VMM, -1);
140		proc_forward_imsg(ps, imsg, PROC_PRIV, -1);
141		break;
142	default:
143		return (-1);
144	}
145
146	switch (cmd) {
147	case 0:
148		break;
149	case IMSG_VMDOP_START_VM_RESPONSE:
150	case IMSG_VMDOP_TERMINATE_VM_RESPONSE:
151		memset(&vmr, 0, sizeof(vmr));
152		vmr.vmr_result = res;
153		vmr.vmr_id = id;
154		if (proc_compose_imsg(ps, PROC_CONTROL, -1, cmd,
155		    imsg->hdr.peerid, -1, &vmr, sizeof(vmr)) == -1)
156			return (-1);
157		break;
158	default:
159		if (proc_compose_imsg(ps, PROC_CONTROL, -1, cmd,
160		    imsg->hdr.peerid, -1, &res, sizeof(res)) == -1)
161			return (-1);
162		break;
163	}
164
165	return (0);
166}
167
168int
169vmd_dispatch_vmm(int fd, struct privsep_proc *p, struct imsg *imsg)
170{
171	struct vmop_result	 vmr;
172	struct privsep		*ps = p->p_ps;
173	int			 res = 0;
174	struct vmd_vm		*vm;
175	struct vm_create_params	*vcp;
176	struct vmop_info_result	 vir;
177
178	switch (imsg->hdr.type) {
179	case IMSG_VMDOP_START_VM_RESPONSE:
180		IMSG_SIZE_CHECK(imsg, &vmr);
181		memcpy(&vmr, imsg->data, sizeof(vmr));
182		if ((vm = vm_getbyvmid(imsg->hdr.peerid)) == NULL)
183			fatalx("%s: invalid vm response", __func__);
184		vm->vm_pid = vmr.vmr_pid;
185		vcp = &vm->vm_params.vmc_params;
186		vcp->vcp_id = vmr.vmr_id;
187
188		/*
189		 * If the peerid is not -1, forward the response back to the
190		 * the control socket.  If it is -1, the request originated
191		 * from the parent, not the control socket.
192		 */
193		if (vm->vm_peerid != (uint32_t)-1) {
194			vmr.vmr_result = res;
195			(void)strlcpy(vmr.vmr_ttyname, vm->vm_ttyname,
196			    sizeof(vmr.vmr_ttyname));
197			if (proc_compose_imsg(ps, PROC_CONTROL, -1,
198			    imsg->hdr.type, vm->vm_peerid, -1,
199			    &vmr, sizeof(vmr)) == -1) {
200				errno = vmr.vmr_result;
201				log_warn("%s: failed to foward vm result",
202				    vcp->vcp_name);
203				vm_remove(vm);
204				return (-1);
205			}
206		}
207
208		if (vmr.vmr_result) {
209			errno = vmr.vmr_result;
210			log_warn("%s: failed to start vm", vcp->vcp_name);
211			vm_remove(vm);
212			break;
213		}
214
215		/* Now configure all the interfaces */
216		if (vm_priv_ifconfig(ps, vm) == -1) {
217			log_warn("%s: failed to configure vm", vcp->vcp_name);
218			vm_remove(vm);
219			break;
220		}
221
222		log_info("%s: started vm %d successfully, tty %s",
223		    vcp->vcp_name, vcp->vcp_id, vm->vm_ttyname);
224		break;
225	case IMSG_VMDOP_TERMINATE_VM_RESPONSE:
226		IMSG_SIZE_CHECK(imsg, &vmr);
227		memcpy(&vmr, imsg->data, sizeof(vmr));
228		proc_forward_imsg(ps, imsg, PROC_CONTROL, -1);
229		if (vmr.vmr_result == 0) {
230			vm = vm_getbyid(vmr.vmr_id);
231			if (vm->vm_from_config)
232				vm->vm_running = 0;
233			else
234				vm_remove(vm);
235		}
236		break;
237	case IMSG_VMDOP_TERMINATE_VM_EVENT:
238		IMSG_SIZE_CHECK(imsg, &vmr);
239		memcpy(&vmr, imsg->data, sizeof(vmr));
240		if ((vm = vm_getbyid(vmr.vmr_id)) == NULL)
241			break;
242		if (vmr.vmr_result == 0) {
243			if (vm->vm_from_config)
244				vm->vm_running = 0;
245			else
246				vm_remove(vm);
247		} else if (vmr.vmr_result == EAGAIN) {
248			/* Stop VM instance but keep the tty open */
249			vm_stop(vm, 1);
250			config_setvm(ps, vm, (uint32_t)-1);
251		}
252		break;
253	case IMSG_VMDOP_GET_INFO_VM_DATA:
254		IMSG_SIZE_CHECK(imsg, &vir);
255		memcpy(&vir, imsg->data, sizeof(vir));
256		if ((vm = vm_getbyid(vir.vir_info.vir_id)) != NULL) {
257			(void)strlcpy(vir.vir_ttyname, vm->vm_ttyname,
258			    sizeof(vir.vir_ttyname));
259		}
260		if (proc_compose_imsg(ps, PROC_CONTROL, -1, imsg->hdr.type,
261		    imsg->hdr.peerid, -1, &vir, sizeof(vir)) == -1) {
262			vm_remove(vm);
263			return (-1);
264		}
265		break;
266	case IMSG_VMDOP_GET_INFO_VM_END_DATA:
267		/*
268		 * PROC_VMM has responded with the *running* VMs, now we
269		 * append the others. These use the special value 0 for their
270		 * kernel id to indicate that they are not running.
271		 */
272		TAILQ_FOREACH(vm, env->vmd_vms, vm_entry) {
273			if (!vm->vm_running) {
274				memset(&vir, 0, sizeof(vir));
275				vir.vir_info.vir_id = 0;
276				strlcpy(vir.vir_info.vir_name,
277				    vm->vm_params.vmc_params.vcp_name,
278				    VMM_MAX_NAME_LEN);
279				vir.vir_info.vir_memory_size =
280				    vm->vm_params.vmc_params.vcp_memranges[0].vmr_size;
281				vir.vir_info.vir_ncpus =
282				    vm->vm_params.vmc_params.vcp_ncpus;
283				if (proc_compose_imsg(ps, PROC_CONTROL, -1,
284				    IMSG_VMDOP_GET_INFO_VM_DATA,
285				    imsg->hdr.peerid, -1, &vir,
286				    sizeof(vir)) == -1) {
287					vm_remove(vm);
288					return (-1);
289				}
290			}
291		}
292		IMSG_SIZE_CHECK(imsg, &res);
293		proc_forward_imsg(ps, imsg, PROC_CONTROL, -1);
294		break;
295	default:
296		return (-1);
297	}
298
299	return (0);
300}
301
302void
303vmd_sighdlr(int sig, short event, void *arg)
304{
305	if (privsep_process != PROC_PARENT)
306		return;
307
308	switch (sig) {
309	case SIGHUP:
310		log_info("%s: reload requested with SIGHUP", __func__);
311
312		/*
313		 * This is safe because libevent uses async signal handlers
314		 * that run in the event loop and not in signal context.
315		 */
316		vmd_reload(0, NULL);
317		break;
318	case SIGPIPE:
319		log_info("%s: ignoring SIGPIPE", __func__);
320		break;
321	case SIGUSR1:
322		log_info("%s: ignoring SIGUSR1", __func__);
323		break;
324	case SIGTERM:
325	case SIGINT:
326		vmd_shutdown();
327		break;
328	default:
329		fatalx("unexpected signal");
330	}
331}
332
333__dead void
334usage(void)
335{
336	extern char *__progname;
337	fprintf(stderr, "usage: %s [-dnv] [-D macro=value] [-f file]\n",
338	    __progname);
339	exit(1);
340}
341
342int
343main(int argc, char **argv)
344{
345	struct privsep		*ps;
346	int			 ch;
347	const char		*conffile = VMD_CONF;
348	enum privsep_procid	 proc_id = PROC_PARENT;
349	int			 proc_instance = 0;
350	const char		*errp, *title = NULL;
351	int			 argc0 = argc;
352
353	/* log to stderr until daemonized */
354	log_init(1, LOG_DAEMON);
355
356	if ((env = calloc(1, sizeof(*env))) == NULL)
357		fatal("calloc: env");
358
359	while ((ch = getopt(argc, argv, "D:P:I:df:vn")) != -1) {
360		switch (ch) {
361		case 'D':
362			if (cmdline_symset(optarg) < 0)
363				log_warnx("could not parse macro definition %s",
364				    optarg);
365			break;
366		case 'd':
367			env->vmd_debug = 2;
368			break;
369		case 'f':
370			conffile = optarg;
371			break;
372		case 'v':
373			env->vmd_verbose++;
374			break;
375		case 'n':
376			env->vmd_noaction = 1;
377			break;
378		case 'P':
379			title = optarg;
380			proc_id = proc_getid(procs, nitems(procs), title);
381			if (proc_id == PROC_MAX)
382				fatalx("invalid process name");
383			break;
384		case 'I':
385			proc_instance = strtonum(optarg, 0,
386			    PROC_MAX_INSTANCES, &errp);
387			if (errp)
388				fatalx("invalid process instance");
389			break;
390		default:
391			usage();
392		}
393	}
394
395	argc -= optind;
396	if (argc > 0)
397		usage();
398
399	if (env->vmd_noaction && !env->vmd_debug)
400		env->vmd_debug = 1;
401
402	/* check for root privileges */
403	if (env->vmd_noaction == 0) {
404		if (geteuid())
405			fatalx("need root privileges");
406	}
407
408	ps = &env->vmd_ps;
409	ps->ps_env = env;
410	env->vmd_fd = -1;
411
412	if (config_init(env) == -1)
413		fatal("failed to initialize configuration");
414
415	if ((ps->ps_pw = getpwnam(VMD_USER)) == NULL)
416		fatal("unknown user %s", VMD_USER);
417
418	/* First proc runs as root without pledge but in default chroot */
419	proc_priv->p_pw = &proc_privpw; /* initialized to all 0 */
420	proc_priv->p_chroot = ps->ps_pw->pw_dir; /* from VMD_USER */
421
422	/* Open /dev/vmm */
423	if (env->vmd_noaction == 0) {
424		env->vmd_fd = open(VMM_NODE, O_RDWR);
425		if (env->vmd_fd == -1)
426			fatal("%s", VMM_NODE);
427	}
428
429	/* Configure the control socket */
430	ps->ps_csock.cs_name = SOCKET_NAME;
431	TAILQ_INIT(&ps->ps_rcsocks);
432
433	/* Configuration will be parsed after forking the children */
434	env->vmd_conffile = conffile;
435
436	log_init(env->vmd_debug, LOG_DAEMON);
437	log_setverbose(env->vmd_verbose);
438
439	if (env->vmd_noaction)
440		ps->ps_noaction = 1;
441	ps->ps_instance = proc_instance;
442	if (title != NULL)
443		ps->ps_title[proc_id] = title;
444
445	/* only the parent returns */
446	proc_init(ps, procs, nitems(procs), argc0, argv, proc_id);
447
448	log_procinit("parent");
449	if (!env->vmd_debug && daemon(0, 0) == -1)
450		fatal("can't daemonize");
451
452	if (ps->ps_noaction == 0)
453		log_info("startup");
454
455	event_init();
456
457	signal_set(&ps->ps_evsigint, SIGINT, vmd_sighdlr, ps);
458	signal_set(&ps->ps_evsigterm, SIGTERM, vmd_sighdlr, ps);
459	signal_set(&ps->ps_evsighup, SIGHUP, vmd_sighdlr, ps);
460	signal_set(&ps->ps_evsigpipe, SIGPIPE, vmd_sighdlr, ps);
461	signal_set(&ps->ps_evsigusr1, SIGUSR1, vmd_sighdlr, ps);
462
463	signal_add(&ps->ps_evsigint, NULL);
464	signal_add(&ps->ps_evsigterm, NULL);
465	signal_add(&ps->ps_evsighup, NULL);
466	signal_add(&ps->ps_evsigpipe, NULL);
467	signal_add(&ps->ps_evsigusr1, NULL);
468
469	if (!env->vmd_noaction)
470		proc_connect(ps);
471
472	if (vmd_configure() == -1)
473		fatalx("configuration failed");
474
475	event_dispatch();
476
477	log_debug("parent exiting");
478
479	return (0);
480}
481
482int
483vmd_configure(void)
484{
485	struct vmd_vm		*vm;
486	struct vmd_switch	*vsw;
487
488	if ((env->vmd_ptmfd = open(PATH_PTMDEV, O_RDWR|O_CLOEXEC)) == -1)
489		fatal("open %s", PATH_PTMDEV);
490
491	/*
492	 * pledge in the parent process:
493	 * stdio - for malloc and basic I/O including events.
494	 * rpath - for reload to open and read the configuration files.
495	 * wpath - for opening disk images and tap devices.
496	 * tty - for openpty.
497	 * proc - run kill to terminate its children safely.
498	 * sendfd - for disks, interfaces and other fds.
499	 */
500	if (pledge("stdio rpath wpath proc tty sendfd", NULL) == -1)
501		fatal("pledge");
502
503	if (parse_config(env->vmd_conffile) == -1) {
504		proc_kill(&env->vmd_ps);
505		exit(1);
506	}
507
508	if (env->vmd_noaction) {
509		fprintf(stderr, "configuration OK\n");
510		proc_kill(&env->vmd_ps);
511		exit(0);
512	}
513
514	TAILQ_FOREACH(vsw, env->vmd_switches, sw_entry) {
515		if (vsw->sw_running)
516			continue;
517		if (vm_priv_brconfig(&env->vmd_ps, vsw) == -1) {
518			log_warn("%s: failed to create switch %s",
519			    __func__, vsw->sw_name);
520			switch_remove(vsw);
521			return (-1);
522		}
523	}
524
525	TAILQ_FOREACH(vm, env->vmd_vms, vm_entry) {
526		if (vm->vm_disabled) {
527			log_debug("%s: not creating vm %s (disabled)",
528			    __func__,
529			    vm->vm_params.vmc_params.vcp_name);
530			continue;
531		}
532		if (config_setvm(&env->vmd_ps, vm, -1) == -1)
533			return (-1);
534	}
535
536	return (0);
537}
538
539void
540vmd_reload(unsigned int reset, const char *filename)
541{
542	struct vmd_vm		*vm, *next_vm;
543	struct vmd_switch	*vsw;
544	int			 reload = 0;
545
546	/* Switch back to the default config file */
547	if (filename == NULL || *filename == '\0') {
548		filename = env->vmd_conffile;
549		reload = 1;
550	}
551
552	log_debug("%s: level %d config file %s", __func__, reset, filename);
553
554	if (reset) {
555		/* Purge the configuration */
556		config_purge(env, reset);
557		config_setreset(env, reset);
558	} else {
559		/*
560		 * Load or reload the configuration.
561		 *
562		 * Reloading removes all non-running VMs before processing the
563		 * config file, whereas loading only adds to the existing list
564		 * of VMs.
565		 */
566
567		if (reload) {
568			TAILQ_FOREACH_SAFE(vm, env->vmd_vms, vm_entry, next_vm) {
569				if (vm->vm_running == 0)
570					vm_remove(vm);
571			}
572		}
573
574		if (parse_config(filename) == -1) {
575			log_debug("%s: failed to load config file %s",
576			    __func__, filename);
577		}
578
579		TAILQ_FOREACH(vsw, env->vmd_switches, sw_entry) {
580			if (vsw->sw_running)
581				continue;
582			if (vm_priv_brconfig(&env->vmd_ps, vsw) == -1) {
583				log_warn("%s: failed to create switch %s",
584				    __func__, vsw->sw_name);
585				switch_remove(vsw);
586				return;
587			}
588		}
589
590		TAILQ_FOREACH(vm, env->vmd_vms, vm_entry) {
591			if (vm->vm_running == 0) {
592				if (vm->vm_disabled) {
593					log_debug("%s: not creating vm %s"
594					    " (disabled)", __func__,
595					    vm->vm_params.vmc_params.vcp_name);
596					continue;
597				}
598				if (config_setvm(&env->vmd_ps, vm, -1) == -1)
599					return;
600			} else {
601				log_debug("%s: not creating vm \"%s\": "
602				    "(running)", __func__,
603				    vm->vm_params.vmc_params.vcp_name);
604			}
605		}
606	}
607}
608
609void
610vmd_shutdown(void)
611{
612	struct vmd_vm *vm, *vm_next;
613
614	TAILQ_FOREACH_SAFE(vm, env->vmd_vms, vm_entry, vm_next) {
615		vm_remove(vm);
616	}
617
618	proc_kill(&env->vmd_ps);
619	free(env);
620
621	log_warnx("parent terminating");
622	exit(0);
623}
624
625struct vmd_vm *
626vm_getbyvmid(uint32_t vmid)
627{
628	struct vmd_vm	*vm;
629
630	TAILQ_FOREACH(vm, env->vmd_vms, vm_entry) {
631		if (vm->vm_vmid == vmid)
632			return (vm);
633	}
634
635	return (NULL);
636}
637
638struct vmd_vm *
639vm_getbyid(uint32_t id)
640{
641	struct vmd_vm	*vm;
642
643	TAILQ_FOREACH(vm, env->vmd_vms, vm_entry) {
644		if (vm->vm_params.vmc_params.vcp_id == id)
645			return (vm);
646	}
647
648	return (NULL);
649}
650
651struct vmd_vm *
652vm_getbyname(const char *name)
653{
654	struct vmd_vm	*vm;
655
656	if (name == NULL)
657		return (NULL);
658	TAILQ_FOREACH(vm, env->vmd_vms, vm_entry) {
659		if (strcmp(vm->vm_params.vmc_params.vcp_name, name) == 0)
660			return (vm);
661	}
662
663	return (NULL);
664}
665
666struct vmd_vm *
667vm_getbypid(pid_t pid)
668{
669	struct vmd_vm	*vm;
670
671	TAILQ_FOREACH(vm, env->vmd_vms, vm_entry) {
672		if (vm->vm_pid == pid)
673			return (vm);
674	}
675
676	return (NULL);
677}
678
679void
680vm_stop(struct vmd_vm *vm, int keeptty)
681{
682	unsigned int	 i;
683
684	if (vm == NULL)
685		return;
686
687	vm->vm_running = 0;
688
689	if (vm->vm_iev.ibuf.fd != -1) {
690		event_del(&vm->vm_iev.ev);
691		close(vm->vm_iev.ibuf.fd);
692	}
693	for (i = 0; i < VMM_MAX_DISKS_PER_VM; i++) {
694		if (vm->vm_disks[i] != -1) {
695			close(vm->vm_disks[i]);
696			vm->vm_disks[i] = -1;
697		}
698	}
699	for (i = 0; i < VMM_MAX_NICS_PER_VM; i++) {
700		if (vm->vm_ifs[i].vif_fd != -1) {
701			close(vm->vm_ifs[i].vif_fd);
702			vm->vm_ifs[i].vif_fd = -1;
703		}
704		free(vm->vm_ifs[i].vif_name);
705		free(vm->vm_ifs[i].vif_switch);
706		free(vm->vm_ifs[i].vif_group);
707		vm->vm_ifs[i].vif_name = NULL;
708		vm->vm_ifs[i].vif_switch = NULL;
709		vm->vm_ifs[i].vif_group = NULL;
710	}
711	if (vm->vm_kernel != -1) {
712		close(vm->vm_kernel);
713		vm->vm_kernel = -1;
714	}
715	if (!keeptty)
716		vm_closetty(vm);
717}
718
719void
720vm_remove(struct vmd_vm *vm)
721{
722	if (vm == NULL)
723		return;
724
725	TAILQ_REMOVE(env->vmd_vms, vm, vm_entry);
726	vm_stop(vm, 0);
727	free(vm);
728}
729
730int
731vm_register(struct privsep *ps, struct vmop_create_params *vmc,
732    struct vmd_vm **ret_vm, uint32_t id)
733{
734	struct vmd_vm		*vm = NULL;
735	struct vm_create_params	*vcp = &vmc->vmc_params;
736	unsigned int		 i;
737
738	errno = 0;
739	*ret_vm = NULL;
740
741	if ((vm = vm_getbyname(vcp->vcp_name)) != NULL) {
742		*ret_vm = vm;
743		errno = EALREADY;
744		goto fail;
745	}
746
747	if (vmc->vmc_flags == 0) {
748		errno = ENOENT;
749		goto fail;
750	}
751	if (vcp->vcp_ncpus == 0)
752		vcp->vcp_ncpus = 1;
753	if (vcp->vcp_memranges[0].vmr_size == 0)
754		vcp->vcp_memranges[0].vmr_size = VM_DEFAULT_MEMORY;
755	if (vcp->vcp_ncpus > VMM_MAX_VCPUS_PER_VM) {
756		log_warnx("invalid number of CPUs");
757		goto fail;
758	} else if (vcp->vcp_ndisks > VMM_MAX_DISKS_PER_VM) {
759		log_warnx("invalid number of disks");
760		goto fail;
761	} else if (vcp->vcp_nnics > VMM_MAX_NICS_PER_VM) {
762		log_warnx("invalid number of interfaces");
763		goto fail;
764	} else if (strlen(vcp->vcp_kernel) == 0 && vcp->vcp_ndisks == 0) {
765		log_warnx("no kernel or disk specified");
766		goto fail;
767	}
768
769	if ((vm = calloc(1, sizeof(*vm))) == NULL)
770		goto fail;
771
772	memcpy(&vm->vm_params, vmc, sizeof(vm->vm_params));
773	vm->vm_pid = -1;
774	vm->vm_tty = -1;
775
776	for (i = 0; i < vcp->vcp_ndisks; i++)
777		vm->vm_disks[i] = -1;
778	for (i = 0; i < vcp->vcp_nnics; i++)
779		vm->vm_ifs[i].vif_fd = -1;
780	vm->vm_kernel = -1;
781	vm->vm_iev.ibuf.fd = -1;
782
783	if (++env->vmd_nvm == 0)
784		fatalx("too many vms");
785
786	/* Assign a new internal Id if not specified */
787	vm->vm_vmid = id == 0 ? env->vmd_nvm : id;
788
789	TAILQ_INSERT_TAIL(env->vmd_vms, vm, vm_entry);
790
791	*ret_vm = vm;
792	return (0);
793 fail:
794	if (errno == 0)
795		errno = EINVAL;
796	return (-1);
797}
798
799int
800vm_opentty(struct vmd_vm *vm)
801{
802	struct ptmget		 ptm;
803
804	/*
805	 * Open tty with pre-opened PTM fd
806	 */
807	if ((ioctl(env->vmd_ptmfd, PTMGET, &ptm) == -1))
808		return (-1);
809
810	vm->vm_tty = ptm.cfd;
811	close(ptm.sfd);
812	if ((vm->vm_ttyname = strdup(ptm.sn)) == NULL)
813		goto fail;
814
815	return (0);
816 fail:
817	vm_closetty(vm);
818	return (-1);
819}
820
821void
822vm_closetty(struct vmd_vm *vm)
823{
824	if (vm->vm_tty != -1) {
825		close(vm->vm_tty);
826		vm->vm_tty = -1;
827	}
828	free(vm->vm_ttyname);
829	vm->vm_ttyname = NULL;
830}
831
832void
833switch_remove(struct vmd_switch *vsw)
834{
835	struct vmd_if	*vif;
836
837	if (vsw == NULL)
838		return;
839
840	TAILQ_REMOVE(env->vmd_switches, vsw, sw_entry);
841
842	while ((vif = TAILQ_FIRST(&vsw->sw_ifs)) != NULL) {
843		free(vif->vif_name);
844		free(vif->vif_switch);
845		TAILQ_REMOVE(&vsw->sw_ifs, vif, vif_entry);
846		free(vif);
847	}
848
849	free(vsw->sw_group);
850	free(vsw->sw_name);
851	free(vsw);
852}
853
854struct vmd_switch *
855switch_getbyname(const char *name)
856{
857	struct vmd_switch	*vsw;
858
859	if (name == NULL)
860		return (NULL);
861	TAILQ_FOREACH(vsw, env->vmd_switches, sw_entry) {
862		if (strcmp(vsw->sw_name, name) == 0)
863			return (vsw);
864	}
865
866	return (NULL);
867}
868
869char *
870get_string(uint8_t *ptr, size_t len)
871{
872	size_t	 i;
873
874	for (i = 0; i < len; i++)
875		if (!isprint(ptr[i]))
876			break;
877
878	return strndup(ptr, i);
879}
880