xref: /minix/minix/usr.bin/trace/service/mib.c (revision fb4fbf7a)
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 __unused, 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 /* The top-level table, which is indexed by identifier. */
332 static const struct sysctl_tab root_tab[] = {
333 	[CTL_KERN]	= NODE(0, kern_tab),
334 	[CTL_VM]	= NODE(0, vm_tab),
335 };
336 
337 /*
338  * This buffer should be large enough to avoid having to perform dynamic
339  * allocation in all but highly exceptional cases.  The CTL_KERN subtree is
340  * currently the largest, so we base the buffer size on its length.
341  * TODO: merge this buffer with ioctlbuf.
342  */
343 static char sysctlbuf[sizeof(struct sysctlnode) * KERN_MAXID];
344 
345 static const struct flags sysctl_flags[] = {
346 	FLAG_MASK(SYSCTL_VERS_MASK, SYSCTL_VERS_0),
347 	FLAG_MASK(SYSCTL_VERS_MASK, SYSCTL_VERSION),
348 #define SYSCTL_VER_ENTRIES 2 /* the first N entries are for SYSCTL_VERS_MASK */
349 	FLAG(CTLFLAG_UNSIGNED),
350 	FLAG(CTLFLAG_OWNDESC),
351 	FLAG(CTLFLAG_MMAP),
352 	FLAG(CTLFLAG_ALIAS),
353 	FLAG(CTLFLAG_ANYNUMBER),
354 	FLAG(CTLFLAG_ROOT),
355 	FLAG(CTLFLAG_HEX),
356 	FLAG(CTLFLAG_IMMEDIATE),
357 	FLAG(CTLFLAG_OWNDATA),
358 	FLAG(CTLFLAG_HIDDEN),
359 	FLAG(CTLFLAG_PERMANENT),
360 	FLAG(CTLFLAG_PRIVATE),
361 	FLAG(CTLFLAG_ANYWRITE),
362 	FLAG_MASK(CTLFLAG_READWRITE, CTLFLAG_READONLY),
363 	FLAG_MASK(CTLFLAG_READWRITE, CTLFLAG_READWRITE),
364 	FLAG_MASK(SYSCTL_TYPEMASK, CTLTYPE_NODE),
365 	FLAG_MASK(SYSCTL_TYPEMASK, CTLTYPE_INT),
366 	FLAG_MASK(SYSCTL_TYPEMASK, CTLTYPE_STRING),
367 	FLAG_MASK(SYSCTL_TYPEMASK, CTLTYPE_QUAD),
368 	FLAG_MASK(SYSCTL_TYPEMASK, CTLTYPE_STRUCT),
369 	FLAG_MASK(SYSCTL_TYPEMASK, CTLTYPE_BOOL),
370 };
371 
372 /*
373  * Print the immediate value of a sysctl node.
374  */
375 static void
376 put_sysctl_imm(struct trace_proc * proc, struct sysctlnode * scn, int use_name)
377 {
378 	const char *name;
379 
380 	name = NULL;
381 
382 	switch (SYSCTL_TYPE(scn->sysctl_flags)) {
383 	case CTLTYPE_INT:
384 		if (use_name)
385 			name = "sysctl_idata";
386 		if (scn->sysctl_flags & CTLFLAG_HEX)
387 			put_value(proc, name, "0x%x", scn->sysctl_idata);
388 		else if (scn->sysctl_flags & CTLFLAG_UNSIGNED)
389 			put_value(proc, name, "%u", scn->sysctl_idata);
390 		else
391 			put_value(proc, name, "%d", scn->sysctl_idata);
392 		break;
393 	case CTLTYPE_BOOL:
394 		if (use_name)
395 			name = "sysctl_bdata";
396 		put_field(proc, name, (scn->sysctl_bdata) ? "true" : "false");
397 		break;
398 	case CTLTYPE_QUAD:
399 		if (use_name)
400 			name = "sysctl_qdata";
401 		if (scn->sysctl_flags & CTLFLAG_HEX)
402 			put_value(proc, name, "0x%"PRIx64, scn->sysctl_qdata);
403 		else
404 			put_value(proc, name, "%"PRIu64, scn->sysctl_qdata);
405 		break;
406 	}
407 }
408 
409 /*
410  * Printer for CTL_QUERY data.
411  */
412 static int
413 put_sysctl_query(struct trace_proc * proc, const char * name, int type,
414 	const void * data __unused, vir_bytes addr, size_t size)
415 {
416 	struct sysctlnode scn;
417 
418 	if (type == ST_NEWP) {
419 		if (!put_open_struct(proc, name, 0, addr, &scn, sizeof(scn)))
420 			return TRUE;
421 
422 		/* Print just the protocol version, that's all there is. */
423 		if (verbose > 1)
424 			put_flags(proc, "sysctl_flags", sysctl_flags,
425 			    SYSCTL_VER_ENTRIES, "0x%x", scn.sysctl_flags);
426 
427 		put_close_struct(proc, FALSE /*all*/);
428 	} else {
429 		/* TODO: optionally dump struct sysctlnode array */
430 		put_open(proc, name, 0, "[", ", ");
431 		if (size > 0)
432 			put_tail(proc, size / sizeof(scn), 0);
433 		put_close(proc, "]");
434 	}
435 
436 	return TRUE;
437 }
438 
439 /*
440  * Printer for CTL_CREATE data.
441  */
442 static int
443 put_sysctl_create(struct trace_proc * proc, const char * name, int type,
444 	const void * data __unused, vir_bytes addr, size_t size)
445 {
446 	struct sysctlnode scn;
447 
448 	if (!put_open_struct(proc, name, 0, addr, &scn, sizeof(scn)))
449 		return TRUE;
450 
451 	if (type == ST_NEWP)
452 		put_flags(proc, "sysctl_flags", sysctl_flags,
453 		    COUNT(sysctl_flags), "0x%x", scn.sysctl_flags);
454 
455 	if (scn.sysctl_num == CTL_CREATE && type == ST_NEWP && !valuesonly)
456 		put_field(proc, "sysctl_num", "CTL_CREATE");
457 	else
458 		put_value(proc, "sysctl_num", "%d", scn.sysctl_num);
459 
460 	if (type == ST_NEWP) {
461 		put_buf(proc, "sysctl_name", PF_LOCADDR | PF_STRING,
462 		    (vir_bytes)scn.sysctl_name, sizeof(scn.sysctl_name));
463 	}
464 	if (scn.sysctl_ver != 0 && verbose > 0)
465 		put_value(proc, "sysctl_ver", "%u", scn.sysctl_ver);
466 
467 	if (type == ST_NEWP) {
468 		if (scn.sysctl_flags & CTLFLAG_IMMEDIATE)
469 			put_sysctl_imm(proc, &scn, TRUE /*use_name*/);
470 
471 		switch (SYSCTL_TYPE(scn.sysctl_flags)) {
472 		case CTLTYPE_NODE:
473 			break;
474 		case CTLTYPE_STRING:
475 			if (scn.sysctl_data != NULL)
476 				put_buf(proc, "sysctl_data", PF_STRING,
477 				    (vir_bytes)scn.sysctl_data,
478 				    (scn.sysctl_size > 0) ? scn.sysctl_size :
479 				    SSIZE_MAX /* hopefully it stops early */);
480 			if (scn.sysctl_data != NULL || verbose == 0)
481 				break;
482 			/* FALLTHROUGH */
483 		default:
484 			if (!(scn.sysctl_flags & CTLFLAG_IMMEDIATE) &&
485 			    verbose > 0)
486 				put_ptr(proc, "sysctl_data",
487 				    (vir_bytes)scn.sysctl_data);
488 			break;
489 		}
490 
491 		if (SYSCTL_TYPE(scn.sysctl_flags) == CTLTYPE_STRUCT ||
492 		    verbose > 0)
493 			put_value(proc, "sysctl_size", "%zu", scn.sysctl_size);
494 	}
495 
496 	put_close_struct(proc, FALSE /*all*/);
497 
498 	return TRUE;
499 }
500 
501 /*
502  * Printer for CTL_DESTROY data.
503  */
504 static int
505 put_sysctl_destroy(struct trace_proc * proc, const char * name, int type,
506 	const void * data __unused, vir_bytes addr, size_t size)
507 {
508 	struct sysctlnode scn;
509 
510 	if (!put_open_struct(proc, name, 0, addr, &scn, sizeof(scn)))
511 		return TRUE;
512 
513 	if (type == ST_NEWP) {
514 		put_value(proc, "sysctl_num", "%d", scn.sysctl_num);
515 		if (scn.sysctl_name[0] != '\0')
516 			put_buf(proc, "sysctl_name", PF_LOCADDR | PF_STRING,
517 			    (vir_bytes)scn.sysctl_name,
518 			    sizeof(scn.sysctl_name));
519 		if (scn.sysctl_ver != 0 && verbose > 0)
520 			put_value(proc, "sysctl_ver", "%u", scn.sysctl_ver);
521 	}
522 
523 	put_close_struct(proc, FALSE /*all*/);
524 
525 	return TRUE;
526 }
527 
528 /*
529  * Printer for CTL_CREATE data.
530  */
531 static int
532 put_sysctl_describe(struct trace_proc * proc, const char * name, int type,
533 	const void * data __unused, vir_bytes addr, size_t size)
534 {
535 	struct sysctlnode scn;
536 
537 	if (type == ST_NEWP) {
538 		if (!put_open_struct(proc, name, 0, addr, &scn, sizeof(scn)))
539 			return TRUE;
540 
541 		/* Print just the protocol version, that's all there is. */
542 		if (verbose > 1)
543 			put_flags(proc, "sysctl_flags", sysctl_flags,
544 			    SYSCTL_VER_ENTRIES, "0x%x", scn.sysctl_flags);
545 
546 		put_value(proc, "sysctl_num", "%d", scn.sysctl_num);
547 
548 		if (scn.sysctl_desc != NULL)
549 			put_buf(proc, "sysctl_desc", PF_STRING,
550 			    (vir_bytes)scn.sysctl_desc, 1024 /*no constant!*/);
551 		else if (verbose > 0)
552 			put_ptr(proc, "sysctl_desc",
553 			    (vir_bytes)scn.sysctl_desc);
554 
555 		put_close_struct(proc, FALSE /*all*/);
556 	} else {
557 		/* TODO: optionally dump struct sysctldesc array */
558 		put_field(proc, name, (size == 0) ? "[]" : "[..]");
559 	}
560 
561 	return TRUE;
562 }
563 
564 /*
565  * Printer for generic data, using the node flags stored in proc->sysctl_flags.
566  */
567 static int
568 put_sysctl_generic(struct trace_proc * proc, const char * name, int type,
569 	const void * data __unused, vir_bytes addr, size_t size)
570 {
571 	struct sysctlnode scn;
572 	void *ptr;
573 	size_t len;
574 
575 	switch (SYSCTL_TYPE(proc->sctl_flags)) {
576 	case CTLTYPE_STRING:
577 		put_buf(proc, name, PF_STRING, addr, size);
578 		return TRUE;
579 	case CTLTYPE_INT:
580 		ptr = &scn.sysctl_idata;
581 		len = sizeof(scn.sysctl_idata);
582 		break;
583 	case CTLTYPE_BOOL:
584 		ptr = &scn.sysctl_bdata;
585 		len = sizeof(scn.sysctl_bdata);
586 		break;
587 	case CTLTYPE_QUAD:
588 		ptr = &scn.sysctl_qdata;
589 		len = sizeof(scn.sysctl_qdata);
590 		break;
591 	case CTLTYPE_STRUCT:
592 	default:
593 		ptr = NULL;
594 		len = 0;
595 		break;
596 	}
597 
598 	if (ptr == NULL || len != size ||
599 	    mem_get_data(proc->pid, addr, ptr, len) < 0) {
600 		put_ptr(proc, name, addr);
601 		return TRUE;
602 	}
603 
604 	put_open(proc, name, PF_NONAME, "{", ", ");
605 
606 	scn.sysctl_flags = proc->sctl_flags;
607 
608 	put_sysctl_imm(proc, &scn, FALSE);
609 
610 	put_close(proc, "}");
611 
612 	return TRUE;
613 }
614 
615 /*
616  * Obtain information about a particular node 'id' in the node directory
617  * identified by the MIB path 'name' (length 'namelen').  Return TRUE if the
618  * node was found, in which case it is copied into 'scnp'.  Return FALSE if the
619  * node was not found or another error occurred.
620  */
621 static int
622 get_sysctl_node(const int * name, unsigned int namelen, int id,
623 	struct sysctlnode * scnp)
624 {
625 	struct sysctlnode *scn, *escn, *fscn;
626 	char *buf;
627 	size_t len, elen;
628 	int r, mib[CTL_MAXNAME];
629 
630 	assert(namelen < CTL_MAXNAME);
631 	assert(id >= 0);
632 
633 	/* Query the parent, first using our static buffer for the results. */
634 	memcpy(mib, name, sizeof(mib[0]) * namelen);
635 	mib[namelen] = CTL_QUERY;
636 	len = sizeof(sysctlbuf);
637 	r = sysctl(mib, namelen + 1, sysctlbuf, &len, NULL, 0);
638 	if (r == -1 && (errno != ENOMEM || len == 0))
639 		return FALSE;
640 
641 	/* Even with partial results, check if we already found the node. */
642 	elen = MIN(len, sizeof(sysctlbuf));
643 	scn = (struct sysctlnode *)sysctlbuf;
644 	escn = (struct sysctlnode *)&sysctlbuf[elen];
645 	fscn = NULL; /* pointer to the node once found, NULL until then */
646 	for (; scn < escn && fscn == NULL; scn++)
647 		if (scn->sysctl_num == id)
648 			fscn = scn;
649 
650 	/* If our buffer was too small, use a temporary buffer. */
651 	if (fscn == NULL && r == -1) {
652 		if ((buf = malloc(len)) == NULL)
653 			return FALSE;
654 		if (sysctl(mib, namelen, buf, &len, NULL, 0) == 0) {
655 			scn = (struct sysctlnode *)sysctlbuf;
656 			escn = (struct sysctlnode *)&sysctlbuf[len];
657 			for (; scn < escn && fscn != NULL; scn++)
658 				if (scn->sysctl_num == id)
659 					fscn = scn;
660 		}
661 		free(buf);
662 	}
663 
664 	if (fscn != NULL) {
665 		memcpy(scnp, fscn, sizeof(*scnp));
666 		return TRUE;
667 	} else
668 		return FALSE;
669 }
670 
671 /*
672  * Print the name string of one level of a sysctl(2) name, while also gathering
673  * information about the target node.  Return 1 if name interpretation should
674  * continue as before, meaning this function will also be called for the next
675  * name component (if any).  Return 0 if the rest of the name should be printed
676  * as numbers, without interpretation.  Return -1 if printing the name is now
677  * complete.
678  */
679 static int
680 put_sysctl_namestr(struct trace_proc * proc, const int * name,
681 	unsigned int namelen, unsigned int n, int all,
682 	const struct sysctl_tab ** sctp)
683 {
684 	const struct sysctl_tab *sct;
685 	struct sysctlnode scn;
686 	const char *namestr;
687 	int i, r, id, is_last;
688 
689 	assert(n < namelen);
690 
691 	id = name[n];
692 	is_last = (n == namelen - 1 && all);
693 	namestr = NULL;
694 
695 	/* Negative identifiers are meta-identifiers. */
696 	if (id < 0) {
697 		switch (id) {
698 		case CTL_EOL:		namestr = "<eol>";		break;
699 		case CTL_QUERY:		namestr = "<query>";		break;
700 		case CTL_CREATE:	namestr = "<create>";		break;
701 		case CTL_CREATESYM:	namestr = "<createsym>";	break;
702 		case CTL_DESTROY:	namestr = "<destroy>";		break;
703 		case CTL_MMAP:		namestr = "<mmap>";		break;
704 		case CTL_DESCRIBE:	namestr = "<describe>";		break;
705 		}
706 
707 		/* For some of them, we can print their parameters. */
708 		if (is_last) {
709 			switch (id) {
710 			case CTL_QUERY:
711 				proc->sctl_proc = put_sysctl_query;
712 				break;
713 			case CTL_CREATE:
714 				proc->sctl_proc = put_sysctl_create;
715 				break;
716 			case CTL_DESTROY:
717 				proc->sctl_proc = put_sysctl_destroy;
718 				break;
719 			case CTL_DESCRIBE:
720 				proc->sctl_proc = put_sysctl_describe;
721 				break;
722 			}
723 		}
724 
725 		/*
726 		 * Meta-identifiers are allowed only at the very end of a name,
727 		 * so if anything follows a meta-identifier, there is no good
728 		 * way to interpret it.  We just print numbers.
729 		 */
730 		r = 0;
731 	} else if (get_sysctl_node(name, n, id, &scn)) {
732 		/*
733 		 * For regular identifiers, first see if we have a callback
734 		 * function that does the interpretation.  The use of the
735 		 * callback function depends on whether the current node is of
736 		 * type CTLTYPE_NODE: if it is, the callback function is
737 		 * responsible for printing the rest of the name (and we return
738 		 * -1 here after we are done, #1); if it isn't, then we just
739 		 * use the callback function to interpret the node value (#2).
740 		 * If we do not have a callback function, but the current node
741 		 * is of type CTLTYPE_NODE *and* has a non-NULL callback
742 		 * function registered in the MIB service, the remote callback
743 		 * function would interpret the rest of the name, so we simply
744 		 * print the rest of the name as numbers (returning 0 once we
745 		 * are done, #3).  Without a MIB-service callback function,
746 		 * such nodes are just taken as path components and thus we
747 		 * return 1 to continue resolution (#4).  Finally, if we do not
748 		 * have a callback function, and the current node is a data
749 		 * node (i.e., *not* of type CTLTYPE_NODE), we try to interpret
750 		 * it generically if it is the last component (#5), or we give
751 		 * up and just print numbers otherwise (#6).
752 		 */
753 
754 		/* Okay, so start by looking up the node in our own tables. */
755 		sct = NULL;
756 		if (n == 0) {
757 			/* The top level is ID-indexed for performance. */
758 			if ((unsigned int)id < __arraycount(root_tab))
759 				*sctp = &root_tab[id];
760 			else
761 				*sctp = NULL;
762 		} else if (*sctp != NULL) {
763 			/* Other levels are searched, because of sparseness. */
764 			sct = (*sctp)->tab; /* NULL if missing or leaf */
765 			for (i = (int)(*sctp)->size; sct != NULL && i > 0;
766 			    i--, sct++)
767 				if (sct->id == id)
768 					break;
769 			if (i == 0)
770 				sct = NULL;
771 			*sctp = sct;
772 		}
773 
774 		/* Now determine what to do. */
775 		if (SYSCTL_TYPE(scn.sysctl_flags) == CTLTYPE_NODE) {
776 			if (sct != NULL && sct->proc != NULL) {
777 				proc->sctl_size = sct->size;
778 				proc->sctl_proc = sct->proc;
779 				r = -1; /* #1 */
780 			} else if (scn.sysctl_func != NULL)
781 				r = 0; /* #3 */
782 			else
783 				r = 1; /* #4 */
784 		} else {
785 			if (!is_last)
786 				r = 0; /* #6 */
787 			else if (sct != NULL && sct->proc != NULL) {
788 				/* A nonzero size must match the node size. */
789 				if (sct->size == 0 ||
790 				    sct->size == scn.sysctl_size) {
791 					proc->sctl_size = sct->size;
792 					proc->sctl_proc = sct->proc;
793 				}
794 				r = 0; /* #2 */
795 			} else {
796 				proc->sctl_flags = scn.sysctl_flags;
797 				proc->sctl_proc = put_sysctl_generic;
798 				r = 0; /* #5 */
799 			}
800 		}
801 
802 		namestr = scn.sysctl_name;
803 	} else {
804 		/*
805 		 * The node was not found.  This basically means that we will
806 		 * not be able to get any information about deeper nodes
807 		 * either.  We do not even try: just print numbers.
808 		 */
809 		r = 0;
810 	}
811 
812 	if (!valuesonly && namestr != NULL)
813 		put_field(proc, NULL, namestr);
814 	else
815 		put_value(proc, NULL, "%d", id);
816 
817 	/*
818 	 * Did we determine that the rest of the name should be printed by the
819 	 * callback function?  Then we might as well make that happen.  The
820 	 * abuse of the parameter types is not great, oh well.
821 	 */
822 	if (r == -1)
823 		(void)proc->sctl_proc(proc, NULL, ST_NAME, &name[n + 1], 0,
824 		    namelen - n - 1);
825 
826 	return r;
827 }
828 
829 /*
830  * Print the sysctl(2) name parameter, and gather information needed to print
831  * the oldp and newp parameters later.
832  */
833 static void
834 put_sysctl_name(struct trace_proc * proc, const char * name, int flags,
835 	vir_bytes addr, unsigned int namelen)
836 {
837 	const struct sysctl_tab *sct = NULL;
838 	int r, all, namebuf[CTL_MAXNAME];
839 	unsigned int n;
840 
841 	if (namelen > CTL_MAXNAME) {
842 		namelen = CTL_MAXNAME;
843 		all = 0;
844 	} else
845 		all = 1;
846 
847 	if ((flags & PF_FAILED) || valuesonly > 1 || namelen > CTL_MAXNAME ||
848 	    (namelen > 0 && !(flags & PF_LOCADDR) &&
849 	    mem_get_data(proc->pid, addr, namebuf,
850 	    namelen * sizeof(namebuf[0])) < 0)) {
851 		if (flags & PF_LOCADDR)
852 			put_field(proc, name, "&..");
853 		else
854 			put_ptr(proc, name, addr);
855 		return;
856 	} else if (namelen > 0 && (flags & PF_LOCADDR))
857 		memcpy(namebuf, (void *)addr, sizeof(namebuf[0]) * namelen);
858 
859 	/*
860 	 * Print the path name of the node as possible, and find information
861 	 * about the target node as we go along.  See put_sysctl_namestr() for
862 	 * the meaning of 'r'.
863 	 */
864 	put_open(proc, name, PF_NONAME, "[", ".");
865 	for (n = 0, r = 1; n < namelen; n++) {
866 		if (r == 1) {
867 			if ((r = put_sysctl_namestr(proc, namebuf, namelen, n,
868 			    all, &sct)) < 0)
869 				break;
870 		} else
871 			put_value(proc, NULL, "%d", namebuf[n]);
872 	}
873 	if (!all)
874 		put_field(proc, NULL, "..");
875 	put_close(proc, "]");
876 }
877 
878 /*
879  * Print the sysctl(2) oldp or newp parameter.  PF_ALT means that the given
880  * parameter is newp rather than oldp, in which case PF_FAILED will not be set.
881  */
882 static void
883 put_sysctl_data(struct trace_proc * proc, const char * name, int flags,
884 	vir_bytes addr, size_t len)
885 {
886 	char *ptr;
887 	int type, all;
888 
889 	if ((flags & PF_FAILED) || addr == 0 || valuesonly > 1 ||
890 	    proc->sctl_proc == NULL || proc->sctl_size > sizeof(sysctlbuf) ||
891 	    (proc->sctl_size > 0 && (proc->sctl_size != len ||
892 	    mem_get_data(proc->pid, addr, sysctlbuf, proc->sctl_size) < 0))) {
893 		put_ptr(proc, name, addr);
894 		return;
895 	}
896 
897 	type = (flags & PF_ALT) ? ST_NEWP : ST_OLDP;
898 	ptr = (proc->sctl_size > 0) ? sysctlbuf : NULL;
899 
900 	/*
901 	 * The rough idea here: we have a "simple" mode and a "flexible" mode,
902 	 * depending on whether a size was specified in our table.  For the
903 	 * simple mode, we only call the callback function when we have been
904 	 * able to copy in the data.  A surrounding {} block will be printed
905 	 * automatically, the callback function only has to print the data
906 	 * fields.  The simple mode is basically for structures.  In contrast,
907 	 * the flexible mode leaves both the copying and the printing entirely
908 	 * to the callback function, which thus may print the pointer on copy
909 	 * failure (in which case the surrounding {}s would get in the way).
910 	 */
911 	if (ptr != NULL)
912 		put_open(proc, name, 0, "{", ", ");
913 
914 	all = proc->sctl_proc(proc, name, type, ptr, addr, len);
915 
916 	if (ptr != NULL) {
917 		if (all == FALSE)
918 			put_field(proc, NULL, "..");
919 		put_close(proc, "}");
920 	}
921 }
922 
923 static int
924 mib_sysctl_out(struct trace_proc * proc, const message * m_out)
925 {
926 	unsigned int namelen;
927 
928 	/* Reset the sysctl-related state. */
929 	proc->sctl_flags = 0;
930 	proc->sctl_size = 0;
931 	proc->sctl_proc = NULL;
932 	proc->sctl_arg = 0;
933 
934 	namelen = m_out->m_lc_mib_sysctl.namelen;
935 
936 	/* As part of processing the name, we initialize the state. */
937 	if (namelen <= CTL_SHORTNAME)
938 		put_sysctl_name(proc, "name", PF_LOCADDR,
939 		    (vir_bytes)&m_out->m_lc_mib_sysctl.name, namelen);
940 	else
941 		put_sysctl_name(proc, "name", 0, m_out->m_lc_mib_sysctl.namep,
942 		    namelen);
943 
944 	put_value(proc, "namelen", "%u", namelen);
945 
946 	if (m_out->m_lc_mib_sysctl.oldp == 0 || valuesonly > 1) {
947 		put_sysctl_data(proc, "oldp", 0,
948 		    m_out->m_lc_mib_sysctl.oldp,
949 		    m_out->m_lc_mib_sysctl.oldlen);
950 		/* If oldp is NULL, oldlen may contain garbage; don't print. */
951 		if (m_out->m_lc_mib_sysctl.oldp != 0)
952 			put_value(proc, "oldlen", "%zu",    /* {%zu} is more */
953 			    m_out->m_lc_mib_sysctl.oldlen); /* correct..     */
954 		else
955 			put_value(proc, "oldlen", "%d", 0);
956 		put_sysctl_data(proc, "newp", PF_ALT,
957 		    m_out->m_lc_mib_sysctl.newp,
958 		    m_out->m_lc_mib_sysctl.newlen);
959 		put_value(proc, "newlen", "%zu",
960 		    m_out->m_lc_mib_sysctl.newlen);
961 		return CT_DONE;
962 	} else
963 		return CT_NOTDONE;
964 }
965 
966 static void
967 mib_sysctl_in(struct trace_proc * proc, const message * m_out,
968 	const message * m_in, int failed)
969 {
970 	int err;
971 
972 	if (m_out->m_lc_mib_sysctl.oldp != 0 && valuesonly <= 1) {
973 		put_sysctl_data(proc, "oldp", failed,
974 		    m_out->m_lc_mib_sysctl.oldp,
975 		    m_in->m_mib_lc_sysctl.oldlen /* the returned length */);
976 		put_value(proc, "oldlen", "%zu", /* {%zu} is more correct.. */
977 		    m_out->m_lc_mib_sysctl.oldlen);
978 		put_sysctl_data(proc, "newp", PF_ALT,
979 		    m_out->m_lc_mib_sysctl.newp,
980 		    m_out->m_lc_mib_sysctl.newlen);
981 		put_value(proc, "newlen", "%zu",
982 		    m_out->m_lc_mib_sysctl.newlen);
983 		put_equals(proc);
984 	}
985 
986 	put_result(proc);
987 
988 	/*
989 	 * We want to print the returned old length in the following cases:
990 	 * 1. the call succeeded, the old pointer was NULL, and no new data was
991 	 *    supplied;
992 	 * 2. the call succeeded, the old pointer was not NULL, and the
993 	 *    returned old length is different from the supplied old length.
994 	 * 3. the call failed with ENOMEM or EEXIST, and the old pointer was
995 	 *    not NULL (an undocumented NetBSD feature, used by sysctl(8)).
996 	 */
997 	if (/*#1*/ (!failed && m_out->m_lc_mib_sysctl.oldp == 0 &&
998 	    (m_out->m_lc_mib_sysctl.newp == 0 ||
999 	    m_out->m_lc_mib_sysctl.newlen == 0)) ||
1000 	    /*#2*/ (!failed && m_out->m_lc_mib_sysctl.oldp != 0 &&
1001 	    m_out->m_lc_mib_sysctl.oldlen != m_in->m_mib_lc_sysctl.oldlen) ||
1002 	    /*#3*/ (failed && call_errno(proc, &err) &&
1003 	    (err == ENOMEM || err == EEXIST) &&
1004 	    m_out->m_lc_mib_sysctl.oldp != 0)) {
1005 		put_open(proc, NULL, 0, "(", ", ");
1006 		put_value(proc, "oldlen", "%zu", m_in->m_mib_lc_sysctl.oldlen);
1007 		put_close(proc, ")");
1008 	}
1009 }
1010 
1011 #define MIB_CALL(c) [((MIB_ ## c) - MIB_BASE)]
1012 
1013 static const struct call_handler mib_map[] = {
1014 	MIB_CALL(SYSCTL) = HANDLER("sysctl", mib_sysctl_out, mib_sysctl_in),
1015 };
1016 
1017 const struct calls mib_calls = {
1018 	.endpt = MIB_PROC_NR,
1019 	.base = MIB_BASE,
1020 	.map = mib_map,
1021 	.count = COUNT(mib_map)
1022 };
1023