xref: /minix/minix/usr.bin/trace/service/mib.c (revision 045e0ed3)
1 
2 #include "inc.h"
3 
4 #include <sys/time.h>
5 #include <sys/sysctl.h>
6 #include <sys/sched.h>
7 #include <sys/resource.h>
8 
9 struct sysctl_tab {
10 	int id;
11 	size_t size;
12 	const struct sysctl_tab *tab;
13 	int (*proc)(struct trace_proc *, const char *, int, const void *,
14 	    vir_bytes, size_t);
15 };
16 #define NODE(i,t) { .id = i, .size = __arraycount(t), .tab = t }
17 #define PROC(i,s,p) { .id = i, .size = s, .proc = p }
18 
19 /*
20  * Print CTL_KERN KERN_CLOCKRATE.
21  */
22 static int
23 put_kern_clockrate(struct trace_proc * proc, const char * name,
24 	int type __unused, const void * ptr, vir_bytes addr __unused,
25 	size_t size __unused)
26 {
27 	const struct clockinfo *ci;
28 
29 	ci = (const struct clockinfo *)ptr;
30 
31 	put_value(proc, "hz", "%d", ci->hz);
32 	put_value(proc, "tick", "%d", ci->tick);
33 	if (verbose > 0) {
34 		put_value(proc, "tickadj", "%d", ci->tickadj);
35 		put_value(proc, "stathz", "%d", ci->stathz);
36 		put_value(proc, "profhz", "%d", ci->profhz);
37 		return TRUE;
38 	} else
39 		return FALSE;
40 }
41 
42 /*
43  * Print CTL_KERN KERN_PROC2.
44  */
45 static int
46 put_kern_proc2(struct trace_proc * proc, const char * name, int type,
47 	const void * ptr, vir_bytes addr, size_t size)
48 {
49 	const int *mib;
50 	const char *text;
51 	unsigned int i;
52 
53 	if (type == ST_NAME) {
54 		mib = (const int *)ptr;
55 
56 		for (i = 0; i < size; i++) {
57 			text = NULL;
58 
59 			if (i == 0) {
60 				switch (mib[i]) {
61 				case KERN_PROC_ALL: text = "<all>"; break;
62 				case KERN_PROC_PID: text = "<pid>"; break;
63 				case KERN_PROC_PGRP: text = "<pgrp>"; break;
64 				case KERN_PROC_SESSION:
65 					text = "<session>"; break;
66 				case KERN_PROC_TTY: text = "<tty>"; break;
67 				case KERN_PROC_UID: text = "<uid>"; break;
68 				case KERN_PROC_RUID: text = "<ruid>"; break;
69 				case KERN_PROC_GID: text = "<gid>"; break;
70 				case KERN_PROC_RGID: text = "<rgid>"; break;
71 				}
72 			} else if (i == 1 && mib[0] == KERN_PROC_TTY) {
73 				switch ((dev_t)mib[i]) {
74 				case KERN_PROC_TTY_NODEV:
75 					text = "<nodev>"; break;
76 				case KERN_PROC_TTY_REVOKE:
77 					text = "<revoke>"; break;
78 				}
79 			}
80 
81 			if (!valuesonly && text != NULL)
82 				put_field(proc, NULL, text);
83 			else
84 				put_value(proc, NULL, "%d", mib[i]);
85 		}
86 
87 		/*
88 		 * Save the requested structure length, so that we can later
89 		 * determine how many elements were returned (see below).
90 		 */
91 		proc->sctl_arg = (size == 4) ? mib[2] : 0;
92 
93 		return 0;
94 	}
95 
96 	if (proc->sctl_arg > 0) {
97 		/* TODO: optionally dump struct kinfo_drivers array */
98 		put_open(proc, name, 0, "[", ", ");
99 		if (size > 0)
100 			put_tail(proc, size / proc->sctl_arg, 0);
101 		put_close(proc, "]");
102 	} else
103 		put_ptr(proc, name, addr);
104 
105 	return TRUE;
106 }
107 
108 /*
109  * Print CTL_KERN KERN_PROC_ARGS.
110  */
111 static int
112 put_kern_proc_args(struct trace_proc * proc, const char * name, int type,
113 	const void * ptr, vir_bytes addr, size_t size)
114 {
115 	const int *mib;
116 	const char *text;
117 	unsigned int i;
118 	int v;
119 
120 	if (type == ST_NAME) {
121 		mib = (const int *)ptr;
122 
123 		for (i = 0; i < size; i++) {
124 			text = NULL;
125 
126 			if (i == 1) {
127 				switch (mib[i]) {
128 				case KERN_PROC_ARGV: text = "<argv>"; break;
129 				case KERN_PROC_ENV: text = "<env>"; break;
130 				case KERN_PROC_NARGV: text = "<nargv>"; break;
131 				case KERN_PROC_NENV: text = "<nenv>"; break;
132 				}
133 			}
134 
135 			if (!valuesonly && text != NULL)
136 				put_field(proc, NULL, text);
137 			else
138 				put_value(proc, NULL, "%d", mib[i]);
139 		}
140 
141 		/* Save the subrequest, so that we can later print data. */
142 		proc->sctl_arg = (size == 2) ? mib[1] : -999;
143 
144 		return 0;
145 	}
146 
147 	if ((proc->sctl_arg == KERN_PROC_NARGV ||
148 	    proc->sctl_arg == KERN_PROC_NENV) && size == sizeof(v) &&
149 	    mem_get_data(proc->pid, addr, &v, sizeof(v)) >= 0) {
150 		put_open(proc, name, PF_NONAME, "{", ", ");
151 
152 		put_value(proc, NULL, "%d", v);
153 
154 		put_close(proc, "}");
155 	} else
156 		put_ptr(proc, name, addr);
157 
158 	return TRUE;
159 }
160 
161 /*
162  * Print CTL_KERN KERN_CP_TIME.
163  */
164 static int
165 put_kern_cp_time(struct trace_proc * proc, const char * name __unused,
166 	int type, const void * ptr, vir_bytes addr __unused, size_t size)
167 {
168 	const uint64_t *p;
169 	unsigned int i;
170 	const int *mib;
171 
172 	if (type == ST_NAME) {
173 		mib = (const int *)ptr;
174 		for (i = 0; i < size; i++)
175 			put_value(proc, NULL, "%d", mib[i]);
176 
177 		return 0;
178 	}
179 
180 	p = (const uint64_t *)ptr;
181 
182 	/* TODO: support for multi-CPU results */
183 	for (i = 0; i < CPUSTATES; i++)
184 		put_value(proc, NULL, "%"PRIu64, p[i]);
185 
186 	return TRUE;
187 }
188 
189 /*
190  * Print CTL_KERN KERN_CONSDEV.
191  */
192 static int
193 put_kern_consdev(struct trace_proc * proc, const char * name,
194 	int type __unused, const void * ptr, vir_bytes addr __unused,
195 	size_t size __unused)
196 {
197 
198 	put_dev(proc, NULL, *(const dev_t *)ptr);
199 
200 	return TRUE;
201 }
202 
203 /*
204  * Print CTL_KERN KERN_DRIVERS.
205  */
206 static int
207 put_kern_drivers(struct trace_proc * proc, const char * name,
208 	int type __unused, const void * ptr __unused, vir_bytes addr __unused,
209 	size_t size)
210 {
211 
212 	/* TODO: optionally dump struct kinfo_drivers array */
213 	put_open(proc, name, 0, "[", ", ");
214 	if (size > 0)
215 		put_tail(proc, size / sizeof(struct kinfo_drivers), 0);
216 	put_close(proc, "]");
217 
218 	return TRUE;
219 }
220 
221 /*
222  * Print CTL_KERN KERN_BOOTTIME.
223  */
224 static int
225 put_kern_boottime(struct trace_proc * proc, const char * name,
226 	int type __unused, const void * ptr __unused, vir_bytes addr,
227 	size_t size)
228 {
229 
230 	if (size == sizeof(struct timeval))
231 		put_struct_timeval(proc, name, 0, addr);
232 	else
233 		put_ptr(proc, name, addr);
234 
235 	return TRUE;
236 }
237 
238 /*
239  * Print CTL_KERN KERN_SYSVIPC KERN_SYSVIPC_INFO.
240  */
241 static int
242 put_kern_sysvipc_info(struct trace_proc * proc, const char * name,
243 	int type, const void * ptr, vir_bytes addr, size_t size)
244 {
245 	const int *mib;
246 	const char *text;
247 	unsigned int i;
248 
249 	/*
250 	 * TODO: print the obtained structure(s).  For now we are just
251 	 * concerned with the name components.
252 	 */
253 	if (type != ST_NAME) {
254 		put_ptr(proc, name, addr);
255 
256 		return TRUE;
257 	}
258 
259 	mib = (const int *)ptr;
260 
261 	for (i = 0; i < size; i++) {
262 		text = NULL;
263 
264 		if (i == 0) {
265 			switch (mib[i]) {
266 			case KERN_SYSVIPC_SEM_INFO: text = "<sem>"; break;
267 			case KERN_SYSVIPC_SHM_INFO: text = "<shm>"; break;
268 			case KERN_SYSVIPC_MSG_INFO: text = "<msg>"; break;
269 			}
270 		}
271 
272 		if (!valuesonly && text != NULL)
273 			put_field(proc, NULL, text);
274 		else
275 			put_value(proc, NULL, "%d", mib[i]);
276 	}
277 
278 	return 0;
279 }
280 
281 /* The CTL_KERN KERN_SYSVIPC table. */
282 static const struct sysctl_tab kern_sysvipc_tab[] = {
283 	PROC(KERN_SYSVIPC_INFO, 0, put_kern_sysvipc_info),
284 };
285 
286 /* The CTL_KERN table. */
287 static const struct sysctl_tab kern_tab[] = {
288 	PROC(KERN_CLOCKRATE, sizeof(struct clockinfo), put_kern_clockrate),
289 	PROC(KERN_PROC2, 0, put_kern_proc2),
290 	PROC(KERN_PROC_ARGS, 0, put_kern_proc_args),
291 	PROC(KERN_CP_TIME, sizeof(uint64_t) * CPUSTATES, put_kern_cp_time),
292 	PROC(KERN_CONSDEV, sizeof(dev_t), put_kern_consdev),
293 	PROC(KERN_DRIVERS, 0, put_kern_drivers),
294 	NODE(KERN_SYSVIPC, kern_sysvipc_tab),
295 	PROC(KERN_BOOTTIME, 0, put_kern_boottime),
296 };
297 
298 /*
299  * Print CTL_VM VM_LOADAVG.
300  */
301 static int
302 put_vm_loadavg(struct trace_proc * proc, const char * name __unused,
303 	int type __unused, const void * ptr, vir_bytes addr __unused,
304 	size_t size __unused)
305 {
306 	const struct loadavg *loadavg;
307 	unsigned int i;
308 
309 	loadavg = (const struct loadavg *)ptr;
310 
311 	put_open(proc, "ldavg", 0, "{", ", ");
312 
313 	for (i = 0; i < __arraycount(loadavg->ldavg); i++)
314 		put_value(proc, NULL, "%"PRIu32, loadavg->ldavg[i]);
315 
316 	put_close(proc, "}");
317 
318 	if (verbose > 0) {
319 		put_value(proc, "fscale", "%ld", loadavg->fscale);
320 
321 		return TRUE;
322 	} else
323 		return FALSE;
324 }
325 
326 /* The CTL_VM table. */
327 static const struct sysctl_tab vm_tab[] = {
328 	PROC(VM_LOADAVG, sizeof(struct loadavg), put_vm_loadavg),
329 };
330 
331 /*
332  * Print CTL_NET PF_ROUTE 0.
333  */
334 static int
335 put_net_route_rtable(struct trace_proc * proc, const char * name,
336 	int type, const void * ptr, vir_bytes addr, size_t size)
337 {
338 	const int *mib;
339 	const char *text;
340 	unsigned int i;
341 
342 	/*
343 	 * TODO: print the obtained structure(s).  For now we are just
344 	 * concerned with the name components.
345 	 */
346 	if (type != ST_NAME) {
347 		put_ptr(proc, name, addr);
348 
349 		return TRUE;
350 	}
351 
352 	mib = (const int *)ptr;
353 
354 	for (i = 0; i < size; i++) {
355 		text = NULL;
356 
357 		switch (i) {
358 		case 0:
359 			switch (mib[i]) {
360 			case AF_UNSPEC: text = "<all>"; break;
361 			case AF_LINK: text = "<link>"; break;
362 			case AF_INET: text = "<inet>"; break;
363 			case AF_INET6: text = "<inet6>"; break;
364 			/* TODO: add more address families here */
365 			}
366 			break;
367 		case 1:
368 			switch (mib[i]) {
369 			case NET_RT_DUMP: text = "<dump>"; break;
370 			case NET_RT_FLAGS: text = "<flags>"; break;
371 			case NET_RT_IFLIST: text = "<iflist>"; break;
372 			}
373 			break;
374 		case 2:
375 			if (mib[1] == NET_RT_IFLIST && mib[i] == 0)
376 				text = "<all>";
377 		}
378 
379 		if (!valuesonly && text != NULL)
380 			put_field(proc, NULL, text);
381 		else
382 			put_value(proc, NULL, "%d", mib[i]);
383 	}
384 
385 	return 0;
386 }
387 
388 /* The CTL_NET PF_ROUTE table. */
389 static const struct sysctl_tab net_route_tab[] = {
390 	PROC(0, 0, put_net_route_rtable),
391 };
392 
393 /* The CTL_NET table. */
394 static const struct sysctl_tab net_tab[] = {
395 	NODE(PF_ROUTE, net_route_tab),
396 };
397 
398 /* The top-level table, which is indexed by identifier. */
399 static const struct sysctl_tab root_tab[] = {
400 	[CTL_KERN]	= NODE(0, kern_tab),
401 	[CTL_VM]	= NODE(0, vm_tab),
402 	[CTL_NET]	= NODE(0, net_tab),
403 };
404 
405 /*
406  * This buffer should be large enough to avoid having to perform dynamic
407  * allocation in all but highly exceptional cases.  The CTL_KERN subtree is
408  * currently the largest, so we base the buffer size on its length.
409  * TODO: merge this buffer with ioctlbuf.
410  */
411 static char sysctlbuf[sizeof(struct sysctlnode) * KERN_MAXID];
412 
413 static const struct flags sysctl_flags[] = {
414 	FLAG_MASK(SYSCTL_VERS_MASK, SYSCTL_VERS_0),
415 	FLAG_MASK(SYSCTL_VERS_MASK, SYSCTL_VERSION),
416 #define SYSCTL_VER_ENTRIES 2 /* the first N entries are for SYSCTL_VERS_MASK */
417 	FLAG(CTLFLAG_UNSIGNED),
418 	FLAG(CTLFLAG_OWNDESC),
419 	FLAG(CTLFLAG_MMAP),
420 	FLAG(CTLFLAG_ALIAS),
421 	FLAG(CTLFLAG_ANYNUMBER),
422 	FLAG(CTLFLAG_ROOT),
423 	FLAG(CTLFLAG_HEX),
424 	FLAG(CTLFLAG_IMMEDIATE),
425 	FLAG(CTLFLAG_OWNDATA),
426 	FLAG(CTLFLAG_HIDDEN),
427 	FLAG(CTLFLAG_PERMANENT),
428 	FLAG(CTLFLAG_PRIVATE),
429 	FLAG(CTLFLAG_ANYWRITE),
430 	FLAG_MASK(CTLFLAG_READWRITE, CTLFLAG_READONLY),
431 	FLAG_MASK(CTLFLAG_READWRITE, CTLFLAG_READWRITE),
432 	FLAG_MASK(SYSCTL_TYPEMASK, CTLTYPE_NODE),
433 	FLAG_MASK(SYSCTL_TYPEMASK, CTLTYPE_INT),
434 	FLAG_MASK(SYSCTL_TYPEMASK, CTLTYPE_STRING),
435 	FLAG_MASK(SYSCTL_TYPEMASK, CTLTYPE_QUAD),
436 	FLAG_MASK(SYSCTL_TYPEMASK, CTLTYPE_STRUCT),
437 	FLAG_MASK(SYSCTL_TYPEMASK, CTLTYPE_BOOL),
438 };
439 
440 /*
441  * Print the immediate value of a sysctl node.
442  */
443 static void
444 put_sysctl_imm(struct trace_proc * proc, struct sysctlnode * scn, int use_name)
445 {
446 	const char *name;
447 
448 	name = NULL;
449 
450 	switch (SYSCTL_TYPE(scn->sysctl_flags)) {
451 	case CTLTYPE_INT:
452 		if (use_name)
453 			name = "sysctl_idata";
454 		if (scn->sysctl_flags & CTLFLAG_HEX)
455 			put_value(proc, name, "0x%x", scn->sysctl_idata);
456 		else if (scn->sysctl_flags & CTLFLAG_UNSIGNED)
457 			put_value(proc, name, "%u", scn->sysctl_idata);
458 		else
459 			put_value(proc, name, "%d", scn->sysctl_idata);
460 		break;
461 	case CTLTYPE_BOOL:
462 		if (use_name)
463 			name = "sysctl_bdata";
464 		put_field(proc, name, (scn->sysctl_bdata) ? "true" : "false");
465 		break;
466 	case CTLTYPE_QUAD:
467 		if (use_name)
468 			name = "sysctl_qdata";
469 		if (scn->sysctl_flags & CTLFLAG_HEX)
470 			put_value(proc, name, "0x%"PRIx64, scn->sysctl_qdata);
471 		else
472 			put_value(proc, name, "%"PRIu64, scn->sysctl_qdata);
473 		break;
474 	}
475 }
476 
477 /*
478  * Printer for CTL_QUERY data.
479  */
480 static int
481 put_sysctl_query(struct trace_proc * proc, const char * name, int type,
482 	const void * data __unused, vir_bytes addr, size_t size)
483 {
484 	struct sysctlnode scn;
485 
486 	if (type == ST_NEWP) {
487 		if (!put_open_struct(proc, name, 0, addr, &scn, sizeof(scn)))
488 			return TRUE;
489 
490 		/* Print just the protocol version, that's all there is. */
491 		if (verbose > 1)
492 			put_flags(proc, "sysctl_flags", sysctl_flags,
493 			    SYSCTL_VER_ENTRIES, "0x%x", scn.sysctl_flags);
494 
495 		put_close_struct(proc, FALSE /*all*/);
496 	} else {
497 		/* TODO: optionally dump struct sysctlnode array */
498 		put_open(proc, name, 0, "[", ", ");
499 		if (size > 0)
500 			put_tail(proc, size / sizeof(scn), 0);
501 		put_close(proc, "]");
502 	}
503 
504 	return TRUE;
505 }
506 
507 /*
508  * Printer for CTL_CREATE data.
509  */
510 static int
511 put_sysctl_create(struct trace_proc * proc, const char * name, int type,
512 	const void * data __unused, vir_bytes addr, size_t size)
513 {
514 	struct sysctlnode scn;
515 
516 	if (!put_open_struct(proc, name, 0, addr, &scn, sizeof(scn)))
517 		return TRUE;
518 
519 	if (type == ST_NEWP)
520 		put_flags(proc, "sysctl_flags", sysctl_flags,
521 		    COUNT(sysctl_flags), "0x%x", scn.sysctl_flags);
522 
523 	if (scn.sysctl_num == CTL_CREATE && type == ST_NEWP && !valuesonly)
524 		put_field(proc, "sysctl_num", "CTL_CREATE");
525 	else
526 		put_value(proc, "sysctl_num", "%d", scn.sysctl_num);
527 
528 	if (type == ST_NEWP) {
529 		put_buf(proc, "sysctl_name", PF_LOCADDR | PF_STRING,
530 		    (vir_bytes)scn.sysctl_name, sizeof(scn.sysctl_name));
531 	}
532 	if (scn.sysctl_ver != 0 && verbose > 0)
533 		put_value(proc, "sysctl_ver", "%u", scn.sysctl_ver);
534 
535 	if (type == ST_NEWP) {
536 		if (scn.sysctl_flags & CTLFLAG_IMMEDIATE)
537 			put_sysctl_imm(proc, &scn, TRUE /*use_name*/);
538 
539 		switch (SYSCTL_TYPE(scn.sysctl_flags)) {
540 		case CTLTYPE_NODE:
541 			break;
542 		case CTLTYPE_STRING:
543 			if (scn.sysctl_data != NULL)
544 				put_buf(proc, "sysctl_data", PF_STRING,
545 				    (vir_bytes)scn.sysctl_data,
546 				    (scn.sysctl_size > 0) ? scn.sysctl_size :
547 				    SSIZE_MAX /* hopefully it stops early */);
548 			if (scn.sysctl_data != NULL || verbose == 0)
549 				break;
550 			/* FALLTHROUGH */
551 		default:
552 			if (!(scn.sysctl_flags & CTLFLAG_IMMEDIATE) &&
553 			    verbose > 0)
554 				put_ptr(proc, "sysctl_data",
555 				    (vir_bytes)scn.sysctl_data);
556 			break;
557 		}
558 
559 		if (SYSCTL_TYPE(scn.sysctl_flags) == CTLTYPE_STRUCT ||
560 		    verbose > 0)
561 			put_value(proc, "sysctl_size", "%zu", scn.sysctl_size);
562 	}
563 
564 	put_close_struct(proc, FALSE /*all*/);
565 
566 	return TRUE;
567 }
568 
569 /*
570  * Printer for CTL_DESTROY data.
571  */
572 static int
573 put_sysctl_destroy(struct trace_proc * proc, const char * name, int type,
574 	const void * data __unused, vir_bytes addr, size_t size)
575 {
576 	struct sysctlnode scn;
577 
578 	if (!put_open_struct(proc, name, 0, addr, &scn, sizeof(scn)))
579 		return TRUE;
580 
581 	if (type == ST_NEWP) {
582 		put_value(proc, "sysctl_num", "%d", scn.sysctl_num);
583 		if (scn.sysctl_name[0] != '\0')
584 			put_buf(proc, "sysctl_name", PF_LOCADDR | PF_STRING,
585 			    (vir_bytes)scn.sysctl_name,
586 			    sizeof(scn.sysctl_name));
587 		if (scn.sysctl_ver != 0 && verbose > 0)
588 			put_value(proc, "sysctl_ver", "%u", scn.sysctl_ver);
589 	}
590 
591 	put_close_struct(proc, FALSE /*all*/);
592 
593 	return TRUE;
594 }
595 
596 /*
597  * Printer for CTL_CREATE data.
598  */
599 static int
600 put_sysctl_describe(struct trace_proc * proc, const char * name, int type,
601 	const void * data __unused, vir_bytes addr, size_t size)
602 {
603 	struct sysctlnode scn;
604 
605 	if (type == ST_NEWP) {
606 		if (!put_open_struct(proc, name, 0, addr, &scn, sizeof(scn)))
607 			return TRUE;
608 
609 		/* Print just the protocol version, that's all there is. */
610 		if (verbose > 1)
611 			put_flags(proc, "sysctl_flags", sysctl_flags,
612 			    SYSCTL_VER_ENTRIES, "0x%x", scn.sysctl_flags);
613 
614 		put_value(proc, "sysctl_num", "%d", scn.sysctl_num);
615 
616 		if (scn.sysctl_desc != NULL)
617 			put_buf(proc, "sysctl_desc", PF_STRING,
618 			    (vir_bytes)scn.sysctl_desc, 1024 /*no constant!*/);
619 		else if (verbose > 0)
620 			put_ptr(proc, "sysctl_desc",
621 			    (vir_bytes)scn.sysctl_desc);
622 
623 		put_close_struct(proc, FALSE /*all*/);
624 	} else {
625 		/* TODO: optionally dump struct sysctldesc array */
626 		put_field(proc, name, (size == 0) ? "[]" : "[..]");
627 	}
628 
629 	return TRUE;
630 }
631 
632 /*
633  * Printer for generic data, using the node flags stored in proc->sysctl_flags.
634  */
635 static int
636 put_sysctl_generic(struct trace_proc * proc, const char * name, int type,
637 	const void * data __unused, vir_bytes addr, size_t size)
638 {
639 	struct sysctlnode scn;
640 	void *ptr;
641 	size_t len;
642 
643 	switch (SYSCTL_TYPE(proc->sctl_flags)) {
644 	case CTLTYPE_STRING:
645 		put_buf(proc, name, PF_STRING, addr, size);
646 		return TRUE;
647 	case CTLTYPE_INT:
648 		ptr = &scn.sysctl_idata;
649 		len = sizeof(scn.sysctl_idata);
650 		break;
651 	case CTLTYPE_BOOL:
652 		ptr = &scn.sysctl_bdata;
653 		len = sizeof(scn.sysctl_bdata);
654 		break;
655 	case CTLTYPE_QUAD:
656 		ptr = &scn.sysctl_qdata;
657 		len = sizeof(scn.sysctl_qdata);
658 		break;
659 	case CTLTYPE_STRUCT:
660 	default:
661 		ptr = NULL;
662 		len = 0;
663 		break;
664 	}
665 
666 	if (ptr == NULL || len != size ||
667 	    mem_get_data(proc->pid, addr, ptr, len) < 0) {
668 		put_ptr(proc, name, addr);
669 		return TRUE;
670 	}
671 
672 	put_open(proc, name, PF_NONAME, "{", ", ");
673 
674 	scn.sysctl_flags = proc->sctl_flags;
675 
676 	put_sysctl_imm(proc, &scn, FALSE);
677 
678 	put_close(proc, "}");
679 
680 	return TRUE;
681 }
682 
683 /*
684  * Obtain information about a particular node 'id' in the node directory
685  * identified by the MIB path 'name' (length 'namelen').  Return TRUE if the
686  * node was found, in which case it is copied into 'scnp'.  Return FALSE if the
687  * node was not found or another error occurred.
688  */
689 static int
690 get_sysctl_node(const int * name, unsigned int namelen, int id,
691 	struct sysctlnode * scnp)
692 {
693 	struct sysctlnode *scn, *escn, *fscn;
694 	char *buf;
695 	size_t len, elen;
696 	int r, mib[CTL_MAXNAME];
697 
698 	assert(namelen < CTL_MAXNAME);
699 	assert(id >= 0);
700 
701 	/* Query the parent, first using our static buffer for the results. */
702 	memcpy(mib, name, sizeof(mib[0]) * namelen);
703 	mib[namelen] = CTL_QUERY;
704 	len = sizeof(sysctlbuf);
705 	r = sysctl(mib, namelen + 1, sysctlbuf, &len, NULL, 0);
706 	if (r == -1 && (errno != ENOMEM || len == 0))
707 		return FALSE;
708 
709 	/* Even with partial results, check if we already found the node. */
710 	elen = MIN(len, sizeof(sysctlbuf));
711 	scn = (struct sysctlnode *)sysctlbuf;
712 	escn = (struct sysctlnode *)&sysctlbuf[elen];
713 	fscn = NULL; /* pointer to the node once found, NULL until then */
714 	for (; scn < escn && fscn == NULL; scn++)
715 		if (scn->sysctl_num == id)
716 			fscn = scn;
717 
718 	/* If our buffer was too small, use a temporary buffer. */
719 	if (fscn == NULL && r == -1) {
720 		if ((buf = malloc(len)) == NULL)
721 			return FALSE;
722 		if (sysctl(mib, namelen, buf, &len, NULL, 0) == 0) {
723 			scn = (struct sysctlnode *)sysctlbuf;
724 			escn = (struct sysctlnode *)&sysctlbuf[len];
725 			for (; scn < escn && fscn != NULL; scn++)
726 				if (scn->sysctl_num == id)
727 					fscn = scn;
728 		}
729 		free(buf);
730 	}
731 
732 	if (fscn != NULL) {
733 		memcpy(scnp, fscn, sizeof(*scnp));
734 		return TRUE;
735 	} else
736 		return FALSE;
737 }
738 
739 /*
740  * Print the name string of one level of a sysctl(2) name, while also gathering
741  * information about the target node.  Return 1 if name interpretation should
742  * continue as before, meaning this function will also be called for the next
743  * name component (if any).  Return 0 if the rest of the name should be printed
744  * as numbers, without interpretation.  Return -1 if printing the name is now
745  * complete.
746  */
747 static int
748 put_sysctl_namestr(struct trace_proc * proc, const int * name,
749 	unsigned int namelen, unsigned int n, int all,
750 	const struct sysctl_tab ** sctp)
751 {
752 	const struct sysctl_tab *sct;
753 	struct sysctlnode scn;
754 	const char *namestr;
755 	int i, r, id, is_last;
756 
757 	assert(n < namelen);
758 
759 	id = name[n];
760 	is_last = (n == namelen - 1 && all);
761 	namestr = NULL;
762 
763 	/* Negative identifiers are meta-identifiers. */
764 	if (id < 0) {
765 		switch (id) {
766 		case CTL_EOL:		namestr = "<eol>";		break;
767 		case CTL_QUERY:		namestr = "<query>";		break;
768 		case CTL_CREATE:	namestr = "<create>";		break;
769 		case CTL_CREATESYM:	namestr = "<createsym>";	break;
770 		case CTL_DESTROY:	namestr = "<destroy>";		break;
771 		case CTL_MMAP:		namestr = "<mmap>";		break;
772 		case CTL_DESCRIBE:	namestr = "<describe>";		break;
773 		}
774 
775 		/* For some of them, we can print their parameters. */
776 		if (is_last) {
777 			switch (id) {
778 			case CTL_QUERY:
779 				proc->sctl_proc = put_sysctl_query;
780 				break;
781 			case CTL_CREATE:
782 				proc->sctl_proc = put_sysctl_create;
783 				break;
784 			case CTL_DESTROY:
785 				proc->sctl_proc = put_sysctl_destroy;
786 				break;
787 			case CTL_DESCRIBE:
788 				proc->sctl_proc = put_sysctl_describe;
789 				break;
790 			}
791 		}
792 
793 		/*
794 		 * Meta-identifiers are allowed only at the very end of a name,
795 		 * so if anything follows a meta-identifier, there is no good
796 		 * way to interpret it.  We just print numbers.
797 		 */
798 		r = 0;
799 	} else if (get_sysctl_node(name, n, id, &scn)) {
800 		/*
801 		 * For regular identifiers, first see if we have a callback
802 		 * function that does the interpretation.  The use of the
803 		 * callback function depends on whether the current node is of
804 		 * type CTLTYPE_NODE: if it is, the callback function is
805 		 * responsible for printing the rest of the name (and we return
806 		 * -1 here after we are done, #1); if it isn't, then we just
807 		 * use the callback function to interpret the node value (#2).
808 		 * If we do not have a callback function, but the current node
809 		 * is of type CTLTYPE_NODE *and* has a non-NULL callback
810 		 * function registered in the MIB service, the remote callback
811 		 * function would interpret the rest of the name, so we simply
812 		 * print the rest of the name as numbers (returning 0 once we
813 		 * are done, #3).  Without a MIB-service callback function,
814 		 * such nodes are just taken as path components and thus we
815 		 * return 1 to continue resolution (#4).  Finally, if we do not
816 		 * have a callback function, and the current node is a data
817 		 * node (i.e., *not* of type CTLTYPE_NODE), we try to interpret
818 		 * it generically if it is the last component (#5), or we give
819 		 * up and just print numbers otherwise (#6).
820 		 */
821 
822 		/* Okay, so start by looking up the node in our own tables. */
823 		sct = NULL;
824 		if (n == 0) {
825 			/* The top level is ID-indexed for performance. */
826 			if ((unsigned int)id < __arraycount(root_tab))
827 				*sctp = &root_tab[id];
828 			else
829 				*sctp = NULL;
830 		} else if (*sctp != NULL) {
831 			/* Other levels are searched, because of sparseness. */
832 			sct = (*sctp)->tab; /* NULL if missing or leaf */
833 			for (i = (int)(*sctp)->size; sct != NULL && i > 0;
834 			    i--, sct++)
835 				if (sct->id == id)
836 					break;
837 			if (i == 0)
838 				sct = NULL;
839 			*sctp = sct;
840 		}
841 
842 		/* Now determine what to do. */
843 		if (SYSCTL_TYPE(scn.sysctl_flags) == CTLTYPE_NODE) {
844 			if (sct != NULL && sct->proc != NULL) {
845 				proc->sctl_size = sct->size;
846 				proc->sctl_proc = sct->proc;
847 				r = -1; /* #1 */
848 			} else if (scn.sysctl_func != NULL)
849 				r = 0; /* #3 */
850 			else
851 				r = 1; /* #4 */
852 		} else {
853 			if (!is_last)
854 				r = 0; /* #6 */
855 			else if (sct != NULL && sct->proc != NULL) {
856 				/* A nonzero size must match the node size. */
857 				if (sct->size == 0 ||
858 				    sct->size == scn.sysctl_size) {
859 					proc->sctl_size = sct->size;
860 					proc->sctl_proc = sct->proc;
861 				}
862 				r = 0; /* #2 */
863 			} else {
864 				proc->sctl_flags = scn.sysctl_flags;
865 				proc->sctl_proc = put_sysctl_generic;
866 				r = 0; /* #5 */
867 			}
868 		}
869 
870 		namestr = scn.sysctl_name;
871 	} else {
872 		/*
873 		 * The node was not found.  This basically means that we will
874 		 * not be able to get any information about deeper nodes
875 		 * either.  We do not even try: just print numbers.
876 		 */
877 		r = 0;
878 	}
879 
880 	if (!valuesonly && namestr != NULL)
881 		put_field(proc, NULL, namestr);
882 	else
883 		put_value(proc, NULL, "%d", id);
884 
885 	/*
886 	 * Did we determine that the rest of the name should be printed by the
887 	 * callback function?  Then we might as well make that happen.  The
888 	 * abuse of the parameter types is not great, oh well.
889 	 */
890 	if (r == -1)
891 		(void)proc->sctl_proc(proc, NULL, ST_NAME, &name[n + 1], 0,
892 		    namelen - n - 1);
893 
894 	return r;
895 }
896 
897 /*
898  * Print the sysctl(2) name parameter, and gather information needed to print
899  * the oldp and newp parameters later.
900  */
901 static void
902 put_sysctl_name(struct trace_proc * proc, const char * name, int flags,
903 	vir_bytes addr, unsigned int namelen)
904 {
905 	const struct sysctl_tab *sct = NULL;
906 	int r, all, namebuf[CTL_MAXNAME];
907 	unsigned int n;
908 
909 	if (namelen > CTL_MAXNAME) {
910 		namelen = CTL_MAXNAME;
911 		all = 0;
912 	} else
913 		all = 1;
914 
915 	if ((flags & PF_FAILED) || valuesonly > 1 || namelen > CTL_MAXNAME ||
916 	    (namelen > 0 && !(flags & PF_LOCADDR) &&
917 	    mem_get_data(proc->pid, addr, namebuf,
918 	    namelen * sizeof(namebuf[0])) < 0)) {
919 		if (flags & PF_LOCADDR)
920 			put_field(proc, name, "&..");
921 		else
922 			put_ptr(proc, name, addr);
923 		return;
924 	} else if (namelen > 0 && (flags & PF_LOCADDR))
925 		memcpy(namebuf, (void *)addr, sizeof(namebuf[0]) * namelen);
926 
927 	/*
928 	 * Print the path name of the node as possible, and find information
929 	 * about the target node as we go along.  See put_sysctl_namestr() for
930 	 * the meaning of 'r'.
931 	 */
932 	put_open(proc, name, PF_NONAME, "[", ".");
933 	for (n = 0, r = 1; n < namelen; n++) {
934 		if (r == 1) {
935 			if ((r = put_sysctl_namestr(proc, namebuf, namelen, n,
936 			    all, &sct)) < 0)
937 				break;
938 		} else
939 			put_value(proc, NULL, "%d", namebuf[n]);
940 	}
941 	if (!all)
942 		put_field(proc, NULL, "..");
943 	put_close(proc, "]");
944 }
945 
946 /*
947  * Print the sysctl(2) oldp or newp parameter.  PF_ALT means that the given
948  * parameter is newp rather than oldp, in which case PF_FAILED will not be set.
949  */
950 static void
951 put_sysctl_data(struct trace_proc * proc, const char * name, int flags,
952 	vir_bytes addr, size_t len)
953 {
954 	char *ptr;
955 	int type, all;
956 
957 	if ((flags & PF_FAILED) || addr == 0 || valuesonly > 1 ||
958 	    proc->sctl_proc == NULL || proc->sctl_size > sizeof(sysctlbuf) ||
959 	    (proc->sctl_size > 0 && (proc->sctl_size != len ||
960 	    mem_get_data(proc->pid, addr, sysctlbuf, proc->sctl_size) < 0))) {
961 		put_ptr(proc, name, addr);
962 		return;
963 	}
964 
965 	type = (flags & PF_ALT) ? ST_NEWP : ST_OLDP;
966 	ptr = (proc->sctl_size > 0) ? sysctlbuf : NULL;
967 
968 	/*
969 	 * The rough idea here: we have a "simple" mode and a "flexible" mode,
970 	 * depending on whether a size was specified in our table.  For the
971 	 * simple mode, we only call the callback function when we have been
972 	 * able to copy in the data.  A surrounding {} block will be printed
973 	 * automatically, the callback function only has to print the data
974 	 * fields.  The simple mode is basically for structures.  In contrast,
975 	 * the flexible mode leaves both the copying and the printing entirely
976 	 * to the callback function, which thus may print the pointer on copy
977 	 * failure (in which case the surrounding {}s would get in the way).
978 	 */
979 	if (ptr != NULL)
980 		put_open(proc, name, 0, "{", ", ");
981 
982 	all = proc->sctl_proc(proc, name, type, ptr, addr, len);
983 
984 	if (ptr != NULL) {
985 		if (all == FALSE)
986 			put_field(proc, NULL, "..");
987 		put_close(proc, "}");
988 	}
989 }
990 
991 static int
992 mib_sysctl_out(struct trace_proc * proc, const message * m_out)
993 {
994 	unsigned int namelen;
995 
996 	/* Reset the sysctl-related state. */
997 	proc->sctl_flags = 0;
998 	proc->sctl_size = 0;
999 	proc->sctl_proc = NULL;
1000 	proc->sctl_arg = 0;
1001 
1002 	namelen = m_out->m_lc_mib_sysctl.namelen;
1003 
1004 	/* As part of processing the name, we initialize the state. */
1005 	if (namelen <= CTL_SHORTNAME)
1006 		put_sysctl_name(proc, "name", PF_LOCADDR,
1007 		    (vir_bytes)&m_out->m_lc_mib_sysctl.name, namelen);
1008 	else
1009 		put_sysctl_name(proc, "name", 0, m_out->m_lc_mib_sysctl.namep,
1010 		    namelen);
1011 
1012 	put_value(proc, "namelen", "%u", namelen);
1013 
1014 	if (m_out->m_lc_mib_sysctl.oldp == 0 || valuesonly > 1) {
1015 		put_sysctl_data(proc, "oldp", 0,
1016 		    m_out->m_lc_mib_sysctl.oldp,
1017 		    m_out->m_lc_mib_sysctl.oldlen);
1018 		/* If oldp is NULL, oldlen may contain garbage; don't print. */
1019 		if (m_out->m_lc_mib_sysctl.oldp != 0)
1020 			put_value(proc, "oldlen", "%zu",    /* {%zu} is more */
1021 			    m_out->m_lc_mib_sysctl.oldlen); /* correct..     */
1022 		else
1023 			put_value(proc, "oldlen", "%d", 0);
1024 		put_sysctl_data(proc, "newp", PF_ALT,
1025 		    m_out->m_lc_mib_sysctl.newp,
1026 		    m_out->m_lc_mib_sysctl.newlen);
1027 		put_value(proc, "newlen", "%zu",
1028 		    m_out->m_lc_mib_sysctl.newlen);
1029 		return CT_DONE;
1030 	} else
1031 		return CT_NOTDONE;
1032 }
1033 
1034 static void
1035 mib_sysctl_in(struct trace_proc * proc, const message * m_out,
1036 	const message * m_in, int failed)
1037 {
1038 	int err;
1039 
1040 	if (m_out->m_lc_mib_sysctl.oldp != 0 && valuesonly <= 1) {
1041 		put_sysctl_data(proc, "oldp", failed,
1042 		    m_out->m_lc_mib_sysctl.oldp,
1043 		    m_in->m_mib_lc_sysctl.oldlen /* the returned length */);
1044 		put_value(proc, "oldlen", "%zu", /* {%zu} is more correct.. */
1045 		    m_out->m_lc_mib_sysctl.oldlen);
1046 		put_sysctl_data(proc, "newp", PF_ALT,
1047 		    m_out->m_lc_mib_sysctl.newp,
1048 		    m_out->m_lc_mib_sysctl.newlen);
1049 		put_value(proc, "newlen", "%zu",
1050 		    m_out->m_lc_mib_sysctl.newlen);
1051 		put_equals(proc);
1052 	}
1053 
1054 	put_result(proc);
1055 
1056 	/*
1057 	 * We want to print the returned old length in the following cases:
1058 	 * 1. the call succeeded, the old pointer was NULL, and no new data was
1059 	 *    supplied;
1060 	 * 2. the call succeeded, the old pointer was not NULL, and the
1061 	 *    returned old length is different from the supplied old length.
1062 	 * 3. the call failed with ENOMEM or EEXIST, and the old pointer was
1063 	 *    not NULL (an undocumented NetBSD feature, used by sysctl(8)).
1064 	 */
1065 	if (/*#1*/ (!failed && m_out->m_lc_mib_sysctl.oldp == 0 &&
1066 	    (m_out->m_lc_mib_sysctl.newp == 0 ||
1067 	    m_out->m_lc_mib_sysctl.newlen == 0)) ||
1068 	    /*#2*/ (!failed && m_out->m_lc_mib_sysctl.oldp != 0 &&
1069 	    m_out->m_lc_mib_sysctl.oldlen != m_in->m_mib_lc_sysctl.oldlen) ||
1070 	    /*#3*/ (failed && call_errno(proc, &err) &&
1071 	    (err == ENOMEM || err == EEXIST) &&
1072 	    m_out->m_lc_mib_sysctl.oldp != 0)) {
1073 		put_open(proc, NULL, 0, "(", ", ");
1074 		put_value(proc, "oldlen", "%zu", m_in->m_mib_lc_sysctl.oldlen);
1075 		put_close(proc, ")");
1076 	}
1077 }
1078 
1079 #define MIB_CALL(c) [((MIB_ ## c) - MIB_BASE)]
1080 
1081 static const struct call_handler mib_map[] = {
1082 	MIB_CALL(SYSCTL) = HANDLER("sysctl", mib_sysctl_out, mib_sysctl_in),
1083 };
1084 
1085 const struct calls mib_calls = {
1086 	.endpt = MIB_PROC_NR,
1087 	.base = MIB_BASE,
1088 	.map = mib_map,
1089 	.count = COUNT(mib_map)
1090 };
1091