xref: /openbsd-src/usr.sbin/vmd/vm_agentx.c (revision 65bbee46cad7861cd5a570f338df9e976422e3ab)
1*65bbee46Sjsg /*	$OpenBSD: vm_agentx.c,v 1.3 2024/09/26 01:45:13 jsg Exp $ */
2f94ca20eSmartijn 
3f94ca20eSmartijn /*
4f94ca20eSmartijn  * Copyright (c) 2022 Martijn van Duren <martijn@openbsd.org>
5f94ca20eSmartijn  *
6f94ca20eSmartijn  * Permission to use, copy, modify, and distribute this software for any
7f94ca20eSmartijn  * purpose with or without fee is hereby granted, provided that the above
8f94ca20eSmartijn  * copyright notice and this permission notice appear in all copies.
9f94ca20eSmartijn  *
10f94ca20eSmartijn  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11f94ca20eSmartijn  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12f94ca20eSmartijn  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13f94ca20eSmartijn  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14f94ca20eSmartijn  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15f94ca20eSmartijn  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16f94ca20eSmartijn  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17f94ca20eSmartijn  */
18f94ca20eSmartijn 
19f94ca20eSmartijn #include <sys/types.h>
20f94ca20eSmartijn #include <sys/sysctl.h>
21f94ca20eSmartijn #include <sys/un.h>
22f94ca20eSmartijn 
23f94ca20eSmartijn #include <agentx.h>
24f94ca20eSmartijn #include <grp.h>
25f94ca20eSmartijn #include <pwd.h>
26f94ca20eSmartijn #include <stdlib.h>
27f94ca20eSmartijn #include <string.h>
28f94ca20eSmartijn #include <unistd.h>
29f94ca20eSmartijn 
30f94ca20eSmartijn #include "proc.h"
31f94ca20eSmartijn #include "vmd.h"
32f94ca20eSmartijn 
33f94ca20eSmartijn struct conn {
34f94ca20eSmartijn 	struct event ev;
35f94ca20eSmartijn 	struct agentx *agentx;
36f94ca20eSmartijn };
37f94ca20eSmartijn 
38f94ca20eSmartijn void vm_agentx_run(struct privsep *, struct privsep_proc *, void *);
39f94ca20eSmartijn int vm_agentx_dispatch_parent(int, struct privsep_proc *, struct imsg *);
40f94ca20eSmartijn void vm_agentx_configure(struct vmd_agentx *);
41f94ca20eSmartijn static void vm_agentx_nofd(struct agentx *, void *, int);
42f94ca20eSmartijn static void vm_agentx_tryconnect(int, short, void *);
43f94ca20eSmartijn static void vm_agentx_read(int, short, void *);
44f94ca20eSmartijn static void vm_agentx_flush_pending(void);
45f94ca20eSmartijn static int vm_agentx_sortvir(const void *, const void *);
46f94ca20eSmartijn static int vm_agentx_adminstate(int);
47f94ca20eSmartijn static int vm_agentx_operstate(int);
48f94ca20eSmartijn static void vm_agentx_vmHvSoftware(struct agentx_varbind *);
49f94ca20eSmartijn static void vm_agentx_vmHvVersion(struct agentx_varbind *);
50f94ca20eSmartijn static void vm_agentx_vmHvObjectID(struct agentx_varbind *);
51f94ca20eSmartijn static void vm_agentx_vminfo(struct agentx_varbind *);
52f94ca20eSmartijn 
53f94ca20eSmartijn static struct agentx_index *vmIndex;
54f94ca20eSmartijn static struct agentx_object *vmNumber, *vmName, *vmUUID, *vmOSType;
55f94ca20eSmartijn static struct agentx_object *vmAdminState, *vmOperState, *vmAutoStart;
56f94ca20eSmartijn static struct agentx_object *vmPersistent, *vmCurCpuNumber, *vmMinCpuNumber;
57f94ca20eSmartijn static struct agentx_object *vmMaxCpuNumber, *vmMemUnit, *vmCurMem, *vmMinMem;
58f94ca20eSmartijn static struct agentx_object *vmMaxMem;
59f94ca20eSmartijn 
60f94ca20eSmartijn static struct vmd_agentx *vmd_agentx;
61f94ca20eSmartijn 
62f94ca20eSmartijn static struct agentx_varbind **vminfo = NULL;
63f94ca20eSmartijn static size_t vminfolen = 0;
64f94ca20eSmartijn static size_t vminfosize = 0;
65f94ca20eSmartijn static int vmcollecting = 0;
66f94ca20eSmartijn 
67f94ca20eSmartijn #define VMMIB AGENTX_MIB2, 236
68f94ca20eSmartijn #define VMOBJECTS VMMIB, 1
69f94ca20eSmartijn #define VMHVSOFTWARE VMOBJECTS, 1, 1
70f94ca20eSmartijn #define VMHVVERSION VMOBJECTS, 1, 2
71f94ca20eSmartijn #define VMHVOBJECTID VMOBJECTS, 1, 3
72f94ca20eSmartijn #define VMNUMBER VMOBJECTS, 2
73f94ca20eSmartijn #define VMENTRY VMOBJECTS, 4, 1
74f94ca20eSmartijn #define VMINDEX VMENTRY, 1
75f94ca20eSmartijn #define VMNAME VMENTRY, 2
76f94ca20eSmartijn #define VMUUID VMENTRY, 3
77f94ca20eSmartijn #define VMOSTYPE VMENTRY, 4
78f94ca20eSmartijn #define VMADMINSTATE VMENTRY, 5
79f94ca20eSmartijn #define VMOPERSTATE VMENTRY, 6
80f94ca20eSmartijn #define VMAUTOSTART VMENTRY, 7
81f94ca20eSmartijn #define VMPERSISTENT VMENTRY, 8
82f94ca20eSmartijn #define VMCURCPUNUMBER VMENTRY, 9
83f94ca20eSmartijn #define VMMINCPUNUMBER VMENTRY, 10
84f94ca20eSmartijn #define VMMAXCPUNUMBER VMENTRY, 11
85f94ca20eSmartijn #define VMMEMUNIT VMENTRY, 12
86f94ca20eSmartijn #define VMCURMEM VMENTRY, 13
87f94ca20eSmartijn #define VMMINMEM VMENTRY, 14
88f94ca20eSmartijn #define VMMAXMEM VMENTRY, 15
89f94ca20eSmartijn 
90f94ca20eSmartijn #define AGENTX_GROUP "_agentx"
91f94ca20eSmartijn #define MEM_SCALE (1024 * 1024)
92f94ca20eSmartijn 
93f94ca20eSmartijn static struct privsep_proc procs[] = {
94f94ca20eSmartijn 	{ "parent",	PROC_PARENT,	vm_agentx_dispatch_parent  },
95f94ca20eSmartijn };
96f94ca20eSmartijn 
97f94ca20eSmartijn void
98f94ca20eSmartijn vm_agentx(struct privsep *ps, struct privsep_proc *p)
99f94ca20eSmartijn {
100f94ca20eSmartijn 	struct group *grp;
101f94ca20eSmartijn 
102f94ca20eSmartijn 	/*
103f94ca20eSmartijn 	 * Make sure we can connect to /var/agentx/master with the correct
104f94ca20eSmartijn 	 * group permissions.
105f94ca20eSmartijn 	 */
106f94ca20eSmartijn 	if ((grp = getgrnam(AGENTX_GROUP)) == NULL)
10768ff4442Sdv 		fatal("failed to get group: %s", AGENTX_GROUP);
108f94ca20eSmartijn 	ps->ps_pw->pw_gid = grp->gr_gid;
109f94ca20eSmartijn 
110f94ca20eSmartijn 	proc_run(ps, p, procs, nitems(procs), vm_agentx_run, NULL);
111f94ca20eSmartijn }
112f94ca20eSmartijn 
113f94ca20eSmartijn void
114f94ca20eSmartijn vm_agentx_shutdown(void)
115f94ca20eSmartijn {
116f94ca20eSmartijn }
117f94ca20eSmartijn 
118f94ca20eSmartijn void
119f94ca20eSmartijn vm_agentx_run(struct privsep *ps, struct privsep_proc *p, void *arg)
120f94ca20eSmartijn {
121f94ca20eSmartijn 	/*
122f94ca20eSmartijn 	 * pledge in agentx process
123f94ca20eSmartijn 	 * stdio - for malloc and basic I/O including events.
124f94ca20eSmartijn 	 * recvfd - for the proc fd exchange.
125f94ca20eSmartijn 	 * unix - for access to the agentx master socket.
126f94ca20eSmartijn 	 */
127f94ca20eSmartijn 	if (pledge("stdio recvfd unix", NULL) == -1)
128f94ca20eSmartijn 		fatal("pledge");
129f94ca20eSmartijn }
130f94ca20eSmartijn 
131f94ca20eSmartijn int
132f94ca20eSmartijn vm_agentx_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg)
133f94ca20eSmartijn {
134f94ca20eSmartijn 	static struct vmop_info_result *vir = NULL;
135f94ca20eSmartijn 	static struct vmop_info_result *mvir = NULL;
136f94ca20eSmartijn 	struct vmd *env = p->p_ps->ps_env;
137f94ca20eSmartijn 	struct vmop_info_result *tvir;
138f94ca20eSmartijn 	struct agentx_object *reqObject;
139f94ca20eSmartijn 	static size_t nvir = 0;
140f94ca20eSmartijn 	static size_t virlen = 0;
141f94ca20eSmartijn 	static int error = 0;
142f94ca20eSmartijn 	size_t i, j, index;
143f94ca20eSmartijn 	enum agentx_request_type rtype;
144f94ca20eSmartijn 
145f94ca20eSmartijn 	switch (imsg->hdr.type) {
146f94ca20eSmartijn 	case IMSG_VMDOP_GET_INFO_VM_DATA:
147f94ca20eSmartijn 		if (error)
148f94ca20eSmartijn 			break;
149f94ca20eSmartijn 		if (nvir + 1 > virlen) {
150f94ca20eSmartijn 			tvir = reallocarray(vir, virlen + 10, sizeof(*vir));
151f94ca20eSmartijn 			if (tvir == NULL) {
152f94ca20eSmartijn 				log_warn("%s: Couldn't dispatch vm information",
153f94ca20eSmartijn 				    __func__);
154f94ca20eSmartijn 				error = 1;
155f94ca20eSmartijn 				break;
156f94ca20eSmartijn 			}
157f94ca20eSmartijn 			virlen += 10;
158f94ca20eSmartijn 			vir = tvir;
159f94ca20eSmartijn 		}
160f94ca20eSmartijn                 memcpy(&(vir[nvir++]), imsg->data, sizeof(vir[nvir]));
161f94ca20eSmartijn 		break;
162f94ca20eSmartijn 	case IMSG_VMDOP_GET_INFO_VM_END_DATA:
163f94ca20eSmartijn 		vmcollecting = 0;
164f94ca20eSmartijn 		if (error) {
165f94ca20eSmartijn 			for (i = 0; i < vminfolen; i++)
166f94ca20eSmartijn 				agentx_varbind_error(vminfo[i]);
167f94ca20eSmartijn 			vminfolen = 0;
168f94ca20eSmartijn 			error = 0;
169f94ca20eSmartijn 			nvir = 0;
170f94ca20eSmartijn 			return (0);
171f94ca20eSmartijn 		}
172f94ca20eSmartijn 
173f94ca20eSmartijn 		qsort(vir, nvir, sizeof(*vir), vm_agentx_sortvir);
174f94ca20eSmartijn 		for (i = 0; i < vminfolen; i++) {
175f94ca20eSmartijn 			reqObject = agentx_varbind_get_object(vminfo[i]);
176f94ca20eSmartijn 			if (reqObject == vmNumber) {
177f94ca20eSmartijn 				agentx_varbind_integer(vminfo[i],
178f94ca20eSmartijn 				    (int32_t)nvir);
179f94ca20eSmartijn 				continue;
180f94ca20eSmartijn 			}
181f94ca20eSmartijn 			index = agentx_varbind_get_index_integer(vminfo[i],
182f94ca20eSmartijn 			    vmIndex);
183f94ca20eSmartijn 			rtype = agentx_varbind_request(vminfo[i]);
184f94ca20eSmartijn 			for (j = 0; j < nvir; j++) {
185f94ca20eSmartijn 				if (vir[j].vir_info.vir_id < index)
186f94ca20eSmartijn 					continue;
187f94ca20eSmartijn 				if (vir[j].vir_info.vir_id == index &&
188f94ca20eSmartijn 				    (rtype == AGENTX_REQUEST_TYPE_GET ||
189f94ca20eSmartijn 				    rtype ==
190f94ca20eSmartijn 				    AGENTX_REQUEST_TYPE_GETNEXTINCLUSIVE))
191f94ca20eSmartijn 					break;
192f94ca20eSmartijn 				if (vir[j].vir_info.vir_id > index &&
193f94ca20eSmartijn 				    (rtype == AGENTX_REQUEST_TYPE_GETNEXT ||
194f94ca20eSmartijn 				    rtype ==
195f94ca20eSmartijn 				    AGENTX_REQUEST_TYPE_GETNEXTINCLUSIVE))
196f94ca20eSmartijn 					break;
197f94ca20eSmartijn 			}
198f94ca20eSmartijn 			if (j == nvir) {
199f94ca20eSmartijn 				agentx_varbind_notfound(vminfo[i]);
200f94ca20eSmartijn 				continue;
201f94ca20eSmartijn 			}
202f94ca20eSmartijn 			mvir = &(vir[j]);
203f94ca20eSmartijn 			agentx_varbind_set_index_integer(vminfo[i], vmIndex,
204f94ca20eSmartijn 			    mvir->vir_info.vir_id);
205f94ca20eSmartijn 			if (reqObject == vmName)
206f94ca20eSmartijn 				agentx_varbind_string(vminfo[i],
207f94ca20eSmartijn 				    mvir->vir_info.vir_name);
208f94ca20eSmartijn 			else if (reqObject == vmUUID)
209f94ca20eSmartijn 				agentx_varbind_string(vminfo[i], "");
210f94ca20eSmartijn 			else if (reqObject == vmOSType)
211f94ca20eSmartijn 				agentx_varbind_string(vminfo[i], "");
212f94ca20eSmartijn 			else if (reqObject == vmAdminState)
213f94ca20eSmartijn 				agentx_varbind_integer(vminfo[i],
214f94ca20eSmartijn 				    vm_agentx_adminstate(mvir->vir_state));
215f94ca20eSmartijn 			else if (reqObject == vmOperState)
216f94ca20eSmartijn 				agentx_varbind_integer(vminfo[i],
217f94ca20eSmartijn 				    vm_agentx_operstate(mvir->vir_state));
218f94ca20eSmartijn 			else if (reqObject == vmAutoStart)
219f94ca20eSmartijn 				agentx_varbind_integer(vminfo[i],
220f94ca20eSmartijn 				    mvir->vir_state & VM_STATE_DISABLED ?
221f94ca20eSmartijn 				    3 : 2);
222f94ca20eSmartijn /* XXX We can dynamically create vm's but I don't know how to differentiate */
223f94ca20eSmartijn 			else if (reqObject == vmPersistent)
224f94ca20eSmartijn 				agentx_varbind_integer(vminfo[i], 1);
225f94ca20eSmartijn /* We currently only support a single CPU */
226f94ca20eSmartijn 			else if (reqObject == vmCurCpuNumber ||
227f94ca20eSmartijn 			    reqObject == vmMinCpuNumber ||
228f94ca20eSmartijn 			    reqObject == vmMaxCpuNumber)
229f94ca20eSmartijn 				agentx_varbind_integer(vminfo[i],
230f94ca20eSmartijn 				    mvir->vir_info.vir_ncpus);
231f94ca20eSmartijn 			else if (reqObject == vmMemUnit)
232f94ca20eSmartijn 				agentx_varbind_integer(vminfo[i], MEM_SCALE);
233f94ca20eSmartijn 			else if (reqObject == vmCurMem)
234f94ca20eSmartijn 				agentx_varbind_integer(vminfo[i],
235f94ca20eSmartijn 				    mvir->vir_info.vir_used_size / MEM_SCALE);
236f94ca20eSmartijn 			else if (reqObject == vmMinMem)
237f94ca20eSmartijn 				agentx_varbind_integer(vminfo[i], -1);
238f94ca20eSmartijn 			else if (reqObject == vmMaxMem)
239f94ca20eSmartijn 				agentx_varbind_integer(vminfo[i],
240f94ca20eSmartijn 				    mvir->vir_info.vir_memory_size / MEM_SCALE);
241f94ca20eSmartijn /* We probably had a reload */
242f94ca20eSmartijn 			else
243f94ca20eSmartijn 				agentx_varbind_notfound(vminfo[i]);
244f94ca20eSmartijn 		}
245f94ca20eSmartijn 		vminfolen = 0;
246f94ca20eSmartijn 		nvir = 0;
247f94ca20eSmartijn 		break;
248f94ca20eSmartijn 	case IMSG_VMDOP_CONFIG:
249f94ca20eSmartijn 		config_getconfig(env, imsg);
250f94ca20eSmartijn 		vm_agentx_configure(&env->vmd_cfg.cfg_agentx);
251f94ca20eSmartijn 		break;
252f94ca20eSmartijn 	default:
253f94ca20eSmartijn 		return (-1);
254f94ca20eSmartijn 	}
255f94ca20eSmartijn 	return (0);
256f94ca20eSmartijn }
257f94ca20eSmartijn 
258f94ca20eSmartijn void
259f94ca20eSmartijn vm_agentx_configure(struct vmd_agentx *env)
260f94ca20eSmartijn {
261f94ca20eSmartijn 	static char curpath[sizeof(env->ax_path)];
262f94ca20eSmartijn 	static char curcontext[sizeof(env->ax_context)];
263f94ca20eSmartijn 	static struct conn *conn;
264f94ca20eSmartijn 	static struct agentx_session *sess;
265f94ca20eSmartijn 	static struct agentx_context *ctx;
266f94ca20eSmartijn 	struct agentx_region *vmMIB;
267f94ca20eSmartijn 	char *context = env->ax_context[0] == '\0' ? NULL : env->ax_context;
268f94ca20eSmartijn 	int changed = 0;
269f94ca20eSmartijn 
270f94ca20eSmartijn 	vmd_agentx = env;
271f94ca20eSmartijn 
272f94ca20eSmartijn 	agentx_log_fatal = fatalx;
273f94ca20eSmartijn 	agentx_log_warn = log_warnx;
274f94ca20eSmartijn 	agentx_log_info = log_info;
275f94ca20eSmartijn 	agentx_log_debug = log_debug;
276f94ca20eSmartijn 
277f94ca20eSmartijn 	if (!vmd_agentx->ax_enabled) {
278f94ca20eSmartijn 		if (conn != NULL) {
279f94ca20eSmartijn 			agentx_free(conn->agentx);
280f94ca20eSmartijn 			conn = NULL;
281f94ca20eSmartijn 			sess = NULL;
282f94ca20eSmartijn 			ctx = NULL;
283f94ca20eSmartijn 			vm_agentx_flush_pending();
284f94ca20eSmartijn 		}
285f94ca20eSmartijn 		return;
286f94ca20eSmartijn 	}
287f94ca20eSmartijn 
288f94ca20eSmartijn 	if (strcmp(curpath, vmd_agentx->ax_path) != 0 || conn == NULL) {
289f94ca20eSmartijn 		if (conn != NULL) {
290f94ca20eSmartijn 			agentx_free(conn->agentx);
291f94ca20eSmartijn 			conn = NULL;
292f94ca20eSmartijn 			sess = NULL;
293f94ca20eSmartijn 			ctx = NULL;
294f94ca20eSmartijn 			vm_agentx_flush_pending();
295f94ca20eSmartijn 		}
296f94ca20eSmartijn 
297f94ca20eSmartijn 		if ((conn = malloc(sizeof(*conn))) == NULL)
298f94ca20eSmartijn 			fatal(NULL);
299f94ca20eSmartijn 		/* Set to something so we can safely event_del */
300f94ca20eSmartijn 		evtimer_set(&conn->ev, vm_agentx_tryconnect, conn);
301f94ca20eSmartijn 		/* result assigned in vm_agentx_nofd */
302f94ca20eSmartijn 		if (agentx(vm_agentx_nofd, conn) == NULL)
303f94ca20eSmartijn 			fatal("Can't setup agentx");
304f94ca20eSmartijn 		sess = agentx_session(conn->agentx, NULL, 0, "vmd", 0);
305f94ca20eSmartijn 		if (sess == NULL)
306f94ca20eSmartijn 			fatal("Can't setup agentx session");
307f94ca20eSmartijn 		(void) strlcpy(curpath, vmd_agentx->ax_path, sizeof(curpath));
308f94ca20eSmartijn 		changed = 1;
309f94ca20eSmartijn 	}
310f94ca20eSmartijn 
311f94ca20eSmartijn 	if (strcmp(curcontext, vmd_agentx->ax_context) != 0 || changed) {
312f94ca20eSmartijn 		if (!changed) {
313f94ca20eSmartijn 			agentx_context_free(ctx);
314f94ca20eSmartijn 			vm_agentx_flush_pending();
315f94ca20eSmartijn 		}
316f94ca20eSmartijn 		if ((ctx = agentx_context(sess, context)) == NULL)
317f94ca20eSmartijn 			fatal("Can't setup agentx context");
318f94ca20eSmartijn 		strlcpy(curcontext, vmd_agentx->ax_context, sizeof(curcontext));
319f94ca20eSmartijn 		changed = 1;
320f94ca20eSmartijn 	}
321f94ca20eSmartijn 
322f94ca20eSmartijn 	if (!changed)
323f94ca20eSmartijn 		return;
324f94ca20eSmartijn 
325f94ca20eSmartijn 	if ((vmMIB = agentx_region(ctx, AGENTX_OID(VMMIB), 1)) == NULL)
326f94ca20eSmartijn 		fatal("agentx_region vmMIB");
327f94ca20eSmartijn 
328f94ca20eSmartijn 	if ((vmIndex = agentx_index_integer_dynamic(vmMIB,
329f94ca20eSmartijn 	    AGENTX_OID(VMINDEX))) == NULL)
330f94ca20eSmartijn 		fatal("agentx_index_integer_dynamic");
331f94ca20eSmartijn         if ((agentx_object(vmMIB, AGENTX_OID(VMHVSOFTWARE), NULL, 0, 0,
332f94ca20eSmartijn 	    vm_agentx_vmHvSoftware)) == NULL ||
333f94ca20eSmartijn             (agentx_object(vmMIB, AGENTX_OID(VMHVVERSION), NULL, 0, 0,
334f94ca20eSmartijn 	    vm_agentx_vmHvVersion)) == NULL ||
335f94ca20eSmartijn             (agentx_object(vmMIB, AGENTX_OID(VMHVOBJECTID), NULL, 0, 0,
336f94ca20eSmartijn 	    vm_agentx_vmHvObjectID)) == NULL ||
337f94ca20eSmartijn             (vmNumber = agentx_object(vmMIB, AGENTX_OID(VMNUMBER), NULL, 0, 0,
338f94ca20eSmartijn 	    vm_agentx_vminfo)) == NULL ||
339f94ca20eSmartijn             (vmName = agentx_object(vmMIB, AGENTX_OID(VMNAME), &vmIndex, 1, 0,
340f94ca20eSmartijn 	    vm_agentx_vminfo)) == NULL ||
341f94ca20eSmartijn             (vmUUID = agentx_object(vmMIB, AGENTX_OID(VMUUID), &vmIndex, 1, 0,
342f94ca20eSmartijn 	    vm_agentx_vminfo)) == NULL ||
343f94ca20eSmartijn             (vmOSType = agentx_object(vmMIB, AGENTX_OID(VMOSTYPE), &vmIndex, 1,
344f94ca20eSmartijn 	    0, vm_agentx_vminfo)) == NULL ||
345f94ca20eSmartijn             (vmAdminState = agentx_object(vmMIB, AGENTX_OID(VMADMINSTATE),
346f94ca20eSmartijn 	    &vmIndex, 1, 0, vm_agentx_vminfo)) == NULL ||
347f94ca20eSmartijn             (vmOperState = agentx_object(vmMIB, AGENTX_OID(VMOPERSTATE),
348f94ca20eSmartijn 	    &vmIndex, 1, 0, vm_agentx_vminfo)) == NULL ||
349f94ca20eSmartijn             (vmAutoStart = agentx_object(vmMIB, AGENTX_OID(VMAUTOSTART),
350f94ca20eSmartijn 	    &vmIndex, 1, 0, vm_agentx_vminfo)) == NULL ||
351f94ca20eSmartijn             (vmPersistent = agentx_object(vmMIB, AGENTX_OID(VMPERSISTENT),
352f94ca20eSmartijn 	    &vmIndex, 1, 0, vm_agentx_vminfo)) == NULL ||
353f94ca20eSmartijn             (vmCurCpuNumber = agentx_object(vmMIB, AGENTX_OID(VMCURCPUNUMBER),
354f94ca20eSmartijn 	    &vmIndex, 1, 0, vm_agentx_vminfo)) == NULL ||
355f94ca20eSmartijn             (vmMinCpuNumber = agentx_object(vmMIB, AGENTX_OID(VMMINCPUNUMBER),
356f94ca20eSmartijn 	    &vmIndex, 1, 0, vm_agentx_vminfo)) == NULL ||
357f94ca20eSmartijn             (vmMaxCpuNumber = agentx_object(vmMIB, AGENTX_OID(VMMAXCPUNUMBER),
358f94ca20eSmartijn 	    &vmIndex, 1, 0, vm_agentx_vminfo)) == NULL ||
359f94ca20eSmartijn             (vmMemUnit = agentx_object(vmMIB, AGENTX_OID(VMMEMUNIT),
360f94ca20eSmartijn 	    &vmIndex, 1, 0, vm_agentx_vminfo)) == NULL ||
361f94ca20eSmartijn             (vmCurMem = agentx_object(vmMIB, AGENTX_OID(VMCURMEM),
362f94ca20eSmartijn 	    &vmIndex, 1, 0, vm_agentx_vminfo)) == NULL ||
363f94ca20eSmartijn             (vmMinMem = agentx_object(vmMIB, AGENTX_OID(VMMINMEM),
364f94ca20eSmartijn 	    &vmIndex, 1, 0, vm_agentx_vminfo)) == NULL ||
365f94ca20eSmartijn             (vmMaxMem = agentx_object(vmMIB, AGENTX_OID(VMMAXMEM),
366f94ca20eSmartijn 	    &vmIndex, 1, 0, vm_agentx_vminfo)) == NULL)
367f94ca20eSmartijn                 fatal("agentx_object_ro");
368f94ca20eSmartijn }
369f94ca20eSmartijn 
370f94ca20eSmartijn static void
371f94ca20eSmartijn vm_agentx_nofd(struct agentx *agentx, void *cookie, int close)
372f94ca20eSmartijn {
373f94ca20eSmartijn 	struct conn *conn = cookie;
374f94ca20eSmartijn 
375f94ca20eSmartijn 	conn->agentx = agentx;
376f94ca20eSmartijn 	event_del(&conn->ev);
377f94ca20eSmartijn 	if (close)
378f94ca20eSmartijn 		free(conn);
379f94ca20eSmartijn 	else
380f94ca20eSmartijn 		vm_agentx_tryconnect(-1, 0, conn);
381f94ca20eSmartijn }
382f94ca20eSmartijn 
383f94ca20eSmartijn static void
384f94ca20eSmartijn vm_agentx_tryconnect(int fd, short event, void *cookie)
385f94ca20eSmartijn {
386f94ca20eSmartijn 	struct sockaddr_un sun;
387f94ca20eSmartijn 	struct timeval timeout = {3, 0};
388f94ca20eSmartijn 	struct conn *conn = cookie;
389f94ca20eSmartijn 
390f94ca20eSmartijn 	sun.sun_len = sizeof(sun);
391f94ca20eSmartijn 	sun.sun_family = AF_UNIX;
392f94ca20eSmartijn 	strlcpy(sun.sun_path, vmd_agentx->ax_path, sizeof(sun.sun_path));
393f94ca20eSmartijn 	if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
394f94ca20eSmartijn 		log_warn("socket");
395f94ca20eSmartijn 		goto fail;
396f94ca20eSmartijn 	} else if (connect(fd, (struct sockaddr *)&sun, sun.sun_len) == -1) {
397f94ca20eSmartijn 		log_warn("connect");
398f94ca20eSmartijn 		close(fd);
399f94ca20eSmartijn 		goto fail;
400f94ca20eSmartijn 	}
401f94ca20eSmartijn 	agentx_connect(conn->agentx, fd);
402f94ca20eSmartijn 
403f94ca20eSmartijn 	event_set(&conn->ev, fd, EV_READ|EV_PERSIST, vm_agentx_read, conn);
404f94ca20eSmartijn 	event_add(&conn->ev, NULL);
405f94ca20eSmartijn 
406f94ca20eSmartijn 	return;
407f94ca20eSmartijn fail:
408f94ca20eSmartijn 	evtimer_set(&conn->ev, vm_agentx_tryconnect, conn);
409f94ca20eSmartijn 	evtimer_add(&conn->ev, &timeout);
410f94ca20eSmartijn }
411f94ca20eSmartijn 
412f94ca20eSmartijn static void
413f94ca20eSmartijn vm_agentx_read(int fd, short event, void *cookie)
414f94ca20eSmartijn {
415f94ca20eSmartijn 	struct conn *conn = cookie;
416f94ca20eSmartijn 
417f94ca20eSmartijn 	agentx_read(conn->agentx);
418f94ca20eSmartijn }
419f94ca20eSmartijn 
420f94ca20eSmartijn static void
421f94ca20eSmartijn vm_agentx_flush_pending(void)
422f94ca20eSmartijn {
423f94ca20eSmartijn 	size_t i;
424f94ca20eSmartijn 
425f94ca20eSmartijn 	for (i = 0; i < vminfolen; i++)
426f94ca20eSmartijn 		agentx_varbind_notfound(vminfo[i]);
427f94ca20eSmartijn 	vminfolen = 0;
428f94ca20eSmartijn }
429f94ca20eSmartijn 
430f94ca20eSmartijn static int
431f94ca20eSmartijn vm_agentx_sortvir(const void *c1, const void *c2)
432f94ca20eSmartijn {
433f94ca20eSmartijn 	const struct vmop_info_result *v1 = c1, *v2 = c2;
434f94ca20eSmartijn 
435f94ca20eSmartijn 	return (v1->vir_info.vir_id < v2->vir_info.vir_id ? -1 :
436f94ca20eSmartijn 	    v1->vir_info.vir_id > v2->vir_info.vir_id);
437f94ca20eSmartijn }
438f94ca20eSmartijn 
439f94ca20eSmartijn static int
440f94ca20eSmartijn vm_agentx_adminstate(int mask)
441f94ca20eSmartijn {
442f94ca20eSmartijn 	if (mask & VM_STATE_PAUSED)
443f94ca20eSmartijn                 return (3);
444f94ca20eSmartijn         else if (mask & VM_STATE_RUNNING)
445f94ca20eSmartijn                 return (1);
446f94ca20eSmartijn         else if (mask & VM_STATE_SHUTDOWN)
447f94ca20eSmartijn                 return (4);
448f94ca20eSmartijn         /* Presence of absence of other flags */
449f94ca20eSmartijn         else if (!mask || (mask & VM_STATE_DISABLED))
450f94ca20eSmartijn                 return (4);
451f94ca20eSmartijn 
452f94ca20eSmartijn         return 4;
453f94ca20eSmartijn }
454f94ca20eSmartijn 
455f94ca20eSmartijn static int
456f94ca20eSmartijn vm_agentx_operstate(int mask)
457f94ca20eSmartijn {
458f94ca20eSmartijn 	if (mask & VM_STATE_PAUSED)
459f94ca20eSmartijn                 return (8);
460f94ca20eSmartijn         else if (mask & VM_STATE_RUNNING)
461f94ca20eSmartijn                 return (4);
462f94ca20eSmartijn         else if (mask & VM_STATE_SHUTDOWN)
463f94ca20eSmartijn                 return (11);
464f94ca20eSmartijn         /* Presence of absence of other flags */
465f94ca20eSmartijn         else if (!mask || (mask & VM_STATE_DISABLED))
466f94ca20eSmartijn                 return (11);
467f94ca20eSmartijn 
468f94ca20eSmartijn         return (11);
469f94ca20eSmartijn }
470f94ca20eSmartijn 
471f94ca20eSmartijn static void
472f94ca20eSmartijn vm_agentx_vmHvSoftware(struct agentx_varbind *vb)
473f94ca20eSmartijn {
474f94ca20eSmartijn 	agentx_varbind_string(vb, "OpenBSD VMM");
475f94ca20eSmartijn }
476f94ca20eSmartijn 
477f94ca20eSmartijn static void
478f94ca20eSmartijn vm_agentx_vmHvVersion(struct agentx_varbind *vb)
479f94ca20eSmartijn {
480f94ca20eSmartijn 	int osversid[] = {CTL_KERN, KERN_OSRELEASE};
481f94ca20eSmartijn 	static char osvers[10] = "";
482f94ca20eSmartijn 	size_t osverslen;
483f94ca20eSmartijn 
484f94ca20eSmartijn 	if (osvers[0] == '\0') {
485f94ca20eSmartijn 		osverslen = sizeof(osvers);
486f94ca20eSmartijn 		if (sysctl(osversid, 2, osvers, &osverslen, NULL,
487f94ca20eSmartijn 		    0) == -1) {
488f94ca20eSmartijn 			log_warn("Failed vmHvVersion sysctl");
489f94ca20eSmartijn 			agentx_varbind_string(vb, "unknown");
490f94ca20eSmartijn 			return;
491f94ca20eSmartijn 		}
492f94ca20eSmartijn 		if (osverslen >= sizeof(osvers))
493f94ca20eSmartijn 			osverslen = sizeof(osvers) - 1;
494f94ca20eSmartijn 		osvers[osverslen] = '\0';
495f94ca20eSmartijn 	}
496f94ca20eSmartijn 	agentx_varbind_string(vb, osvers);
497f94ca20eSmartijn }
498f94ca20eSmartijn 
499f94ca20eSmartijn static void
500f94ca20eSmartijn vm_agentx_vmHvObjectID(struct agentx_varbind *vb)
501f94ca20eSmartijn {
502f94ca20eSmartijn 	agentx_varbind_oid(vb, AGENTX_OID(0, 0));
503f94ca20eSmartijn }
504f94ca20eSmartijn 
505f94ca20eSmartijn static void
506f94ca20eSmartijn vm_agentx_vminfo(struct agentx_varbind *vb)
507f94ca20eSmartijn {
508f94ca20eSmartijn 	extern struct vmd *env;
509f94ca20eSmartijn 	struct agentx_varbind **tvminfo;
510f94ca20eSmartijn 
511f94ca20eSmartijn 	if (vminfolen >= vminfosize) {
512f94ca20eSmartijn 		if ((tvminfo = reallocarray(vminfo, vminfosize + 10,
513f94ca20eSmartijn 		    sizeof(*vminfo))) == NULL) {
514f94ca20eSmartijn 			log_warn("%s: Couldn't retrieve vm information",
515f94ca20eSmartijn 			    __func__);
516f94ca20eSmartijn 			agentx_varbind_error(vb);
517f94ca20eSmartijn 			return;
518f94ca20eSmartijn 		}
519f94ca20eSmartijn 		vminfo = tvminfo;
520f94ca20eSmartijn 		vminfosize += 10;
521f94ca20eSmartijn 	}
522f94ca20eSmartijn 
523f94ca20eSmartijn 	if (!vmcollecting) {
524f94ca20eSmartijn 		if (proc_compose_imsg(&(env->vmd_ps), PROC_PARENT, -1,
525f94ca20eSmartijn 		    IMSG_VMDOP_GET_INFO_VM_REQUEST, IMSG_AGENTX_PEERID,
526f94ca20eSmartijn 		    -1, NULL, 0) == -1) {
527f94ca20eSmartijn 			log_warn("%s: Couldn't retrieve vm information",
528f94ca20eSmartijn 			    __func__);
529f94ca20eSmartijn 			agentx_varbind_error(vb);
530f94ca20eSmartijn 			return;
531f94ca20eSmartijn 		}
532f94ca20eSmartijn 		vmcollecting = 1;
533f94ca20eSmartijn 	}
534f94ca20eSmartijn 
535f94ca20eSmartijn 	vminfo[vminfolen++] = vb;
536f94ca20eSmartijn }
537