xref: /minix3/minix/usr.bin/trace/service/mib.c (revision 764cd267a7cfe0e8c19a3d97970ba520ca409f77)
1e4e21ee1SDavid van Moolenbroek 
2e4e21ee1SDavid van Moolenbroek #include "inc.h"
3e4e21ee1SDavid van Moolenbroek 
425d39513SDavid van Moolenbroek #include <sys/time.h>
5e4e21ee1SDavid van Moolenbroek #include <sys/sysctl.h>
625d39513SDavid van Moolenbroek #include <sys/sched.h>
725d39513SDavid van Moolenbroek #include <sys/resource.h>
8e4e21ee1SDavid van Moolenbroek 
9e4e21ee1SDavid van Moolenbroek struct sysctl_tab {
10e4e21ee1SDavid van Moolenbroek 	int id;
11e4e21ee1SDavid van Moolenbroek 	size_t size;
12e4e21ee1SDavid van Moolenbroek 	const struct sysctl_tab *tab;
13e4e21ee1SDavid van Moolenbroek 	int (*proc)(struct trace_proc *, const char *, int, const void *,
14e4e21ee1SDavid van Moolenbroek 	    vir_bytes, size_t);
15e4e21ee1SDavid van Moolenbroek };
16e4e21ee1SDavid van Moolenbroek #define NODE(i,t) { .id = i, .size = __arraycount(t), .tab = t }
17e4e21ee1SDavid van Moolenbroek #define PROC(i,s,p) { .id = i, .size = s, .proc = p }
18e4e21ee1SDavid van Moolenbroek 
1925d39513SDavid van Moolenbroek /*
2025d39513SDavid van Moolenbroek  * Print CTL_KERN KERN_CLOCKRATE.
2125d39513SDavid van Moolenbroek  */
2225d39513SDavid van Moolenbroek static int
put_kern_clockrate(struct trace_proc * proc,const char * name,int type __unused,const void * ptr,vir_bytes addr __unused,size_t size __unused)2325d39513SDavid van Moolenbroek put_kern_clockrate(struct trace_proc * proc, const char * name,
2425d39513SDavid van Moolenbroek 	int type __unused, const void * ptr, vir_bytes addr __unused,
2525d39513SDavid van Moolenbroek 	size_t size __unused)
2625d39513SDavid van Moolenbroek {
27b58e161cSDavid van Moolenbroek 	const struct clockinfo *ci;
2825d39513SDavid van Moolenbroek 
29b58e161cSDavid van Moolenbroek 	ci = (const struct clockinfo *)ptr;
3025d39513SDavid van Moolenbroek 
3125d39513SDavid van Moolenbroek 	put_value(proc, "hz", "%d", ci->hz);
3225d39513SDavid van Moolenbroek 	put_value(proc, "tick", "%d", ci->tick);
3325d39513SDavid van Moolenbroek 	if (verbose > 0) {
3425d39513SDavid van Moolenbroek 		put_value(proc, "tickadj", "%d", ci->tickadj);
3525d39513SDavid van Moolenbroek 		put_value(proc, "stathz", "%d", ci->stathz);
3625d39513SDavid van Moolenbroek 		put_value(proc, "profhz", "%d", ci->profhz);
3725d39513SDavid van Moolenbroek 		return TRUE;
3825d39513SDavid van Moolenbroek 	} else
3925d39513SDavid van Moolenbroek 		return FALSE;
4025d39513SDavid van Moolenbroek }
4125d39513SDavid van Moolenbroek 
4225d39513SDavid van Moolenbroek /*
4325d39513SDavid van Moolenbroek  * Print CTL_KERN KERN_PROC2.
4425d39513SDavid van Moolenbroek  */
4525d39513SDavid van Moolenbroek static int
put_kern_proc2(struct trace_proc * proc,const char * name,int type,const void * ptr,vir_bytes addr,size_t size)4625d39513SDavid van Moolenbroek put_kern_proc2(struct trace_proc * proc, const char * name, int type,
4725d39513SDavid van Moolenbroek 	const void * ptr, vir_bytes addr, size_t size)
4825d39513SDavid van Moolenbroek {
4925d39513SDavid van Moolenbroek 	const int *mib;
5025d39513SDavid van Moolenbroek 	const char *text;
51b58e161cSDavid van Moolenbroek 	unsigned int i;
5225d39513SDavid van Moolenbroek 
5325d39513SDavid van Moolenbroek 	if (type == ST_NAME) {
5425d39513SDavid van Moolenbroek 		mib = (const int *)ptr;
5525d39513SDavid van Moolenbroek 
5625d39513SDavid van Moolenbroek 		for (i = 0; i < size; i++) {
5725d39513SDavid van Moolenbroek 			text = NULL;
5825d39513SDavid van Moolenbroek 
5925d39513SDavid van Moolenbroek 			if (i == 0) {
6025d39513SDavid van Moolenbroek 				switch (mib[i]) {
6125d39513SDavid van Moolenbroek 				case KERN_PROC_ALL: text = "<all>"; break;
6225d39513SDavid van Moolenbroek 				case KERN_PROC_PID: text = "<pid>"; break;
6325d39513SDavid van Moolenbroek 				case KERN_PROC_PGRP: text = "<pgrp>"; break;
6425d39513SDavid van Moolenbroek 				case KERN_PROC_SESSION:
6525d39513SDavid van Moolenbroek 					text = "<session>"; break;
6625d39513SDavid van Moolenbroek 				case KERN_PROC_TTY: text = "<tty>"; break;
6725d39513SDavid van Moolenbroek 				case KERN_PROC_UID: text = "<uid>"; break;
6825d39513SDavid van Moolenbroek 				case KERN_PROC_RUID: text = "<ruid>"; break;
6925d39513SDavid van Moolenbroek 				case KERN_PROC_GID: text = "<gid>"; break;
7025d39513SDavid van Moolenbroek 				case KERN_PROC_RGID: text = "<rgid>"; break;
7125d39513SDavid van Moolenbroek 				}
7225d39513SDavid van Moolenbroek 			} else if (i == 1 && mib[0] == KERN_PROC_TTY) {
7325d39513SDavid van Moolenbroek 				switch ((dev_t)mib[i]) {
7425d39513SDavid van Moolenbroek 				case KERN_PROC_TTY_NODEV:
7525d39513SDavid van Moolenbroek 					text = "<nodev>"; break;
7625d39513SDavid van Moolenbroek 				case KERN_PROC_TTY_REVOKE:
7725d39513SDavid van Moolenbroek 					text = "<revoke>"; break;
7825d39513SDavid van Moolenbroek 				}
7925d39513SDavid van Moolenbroek 			}
8025d39513SDavid van Moolenbroek 
8125d39513SDavid van Moolenbroek 			if (!valuesonly && text != NULL)
8225d39513SDavid van Moolenbroek 				put_field(proc, NULL, text);
8325d39513SDavid van Moolenbroek 			else
8425d39513SDavid van Moolenbroek 				put_value(proc, NULL, "%d", mib[i]);
8525d39513SDavid van Moolenbroek 		}
8625d39513SDavid van Moolenbroek 
8725d39513SDavid van Moolenbroek 		/*
8825d39513SDavid van Moolenbroek 		 * Save the requested structure length, so that we can later
8925d39513SDavid van Moolenbroek 		 * determine how many elements were returned (see below).
9025d39513SDavid van Moolenbroek 		 */
9125d39513SDavid van Moolenbroek 		proc->sctl_arg = (size == 4) ? mib[2] : 0;
9225d39513SDavid van Moolenbroek 
9325d39513SDavid van Moolenbroek 		return 0;
9425d39513SDavid van Moolenbroek 	}
9525d39513SDavid van Moolenbroek 
9625d39513SDavid van Moolenbroek 	if (proc->sctl_arg > 0) {
9725d39513SDavid van Moolenbroek 		/* TODO: optionally dump struct kinfo_drivers array */
9825d39513SDavid van Moolenbroek 		put_open(proc, name, 0, "[", ", ");
9925d39513SDavid van Moolenbroek 		if (size > 0)
10025d39513SDavid van Moolenbroek 			put_tail(proc, size / proc->sctl_arg, 0);
10125d39513SDavid van Moolenbroek 		put_close(proc, "]");
10225d39513SDavid van Moolenbroek 	} else
10325d39513SDavid van Moolenbroek 		put_ptr(proc, name, addr);
10425d39513SDavid van Moolenbroek 
10525d39513SDavid van Moolenbroek 	return TRUE;
10625d39513SDavid van Moolenbroek }
10725d39513SDavid van Moolenbroek 
10825d39513SDavid van Moolenbroek /*
10925d39513SDavid van Moolenbroek  * Print CTL_KERN KERN_PROC_ARGS.
11025d39513SDavid van Moolenbroek  */
11125d39513SDavid van Moolenbroek static int
put_kern_proc_args(struct trace_proc * proc,const char * name,int type,const void * ptr,vir_bytes addr,size_t size)11225d39513SDavid van Moolenbroek put_kern_proc_args(struct trace_proc * proc, const char * name, int type,
11325d39513SDavid van Moolenbroek 	const void * ptr, vir_bytes addr, size_t size)
11425d39513SDavid van Moolenbroek {
11525d39513SDavid van Moolenbroek 	const int *mib;
11625d39513SDavid van Moolenbroek 	const char *text;
117b58e161cSDavid van Moolenbroek 	unsigned int i;
118b58e161cSDavid van Moolenbroek 	int v;
11925d39513SDavid van Moolenbroek 
12025d39513SDavid van Moolenbroek 	if (type == ST_NAME) {
12125d39513SDavid van Moolenbroek 		mib = (const int *)ptr;
12225d39513SDavid van Moolenbroek 
12325d39513SDavid van Moolenbroek 		for (i = 0; i < size; i++) {
12425d39513SDavid van Moolenbroek 			text = NULL;
12525d39513SDavid van Moolenbroek 
12625d39513SDavid van Moolenbroek 			if (i == 1) {
12725d39513SDavid van Moolenbroek 				switch (mib[i]) {
12825d39513SDavid van Moolenbroek 				case KERN_PROC_ARGV: text = "<argv>"; break;
12925d39513SDavid van Moolenbroek 				case KERN_PROC_ENV: text = "<env>"; break;
13025d39513SDavid van Moolenbroek 				case KERN_PROC_NARGV: text = "<nargv>"; break;
13125d39513SDavid van Moolenbroek 				case KERN_PROC_NENV: text = "<nenv>"; break;
13225d39513SDavid van Moolenbroek 				}
13325d39513SDavid van Moolenbroek 			}
13425d39513SDavid van Moolenbroek 
13525d39513SDavid van Moolenbroek 			if (!valuesonly && text != NULL)
13625d39513SDavid van Moolenbroek 				put_field(proc, NULL, text);
13725d39513SDavid van Moolenbroek 			else
13825d39513SDavid van Moolenbroek 				put_value(proc, NULL, "%d", mib[i]);
13925d39513SDavid van Moolenbroek 		}
14025d39513SDavid van Moolenbroek 
14125d39513SDavid van Moolenbroek 		/* Save the subrequest, so that we can later print data. */
14225d39513SDavid van Moolenbroek 		proc->sctl_arg = (size == 2) ? mib[1] : -999;
14325d39513SDavid van Moolenbroek 
14425d39513SDavid van Moolenbroek 		return 0;
14525d39513SDavid van Moolenbroek 	}
14625d39513SDavid van Moolenbroek 
14725d39513SDavid van Moolenbroek 	if ((proc->sctl_arg == KERN_PROC_NARGV ||
14825d39513SDavid van Moolenbroek 	    proc->sctl_arg == KERN_PROC_NENV) && size == sizeof(v) &&
14925d39513SDavid van Moolenbroek 	    mem_get_data(proc->pid, addr, &v, sizeof(v)) >= 0) {
15025d39513SDavid van Moolenbroek 		put_open(proc, name, PF_NONAME, "{", ", ");
15125d39513SDavid van Moolenbroek 
15225d39513SDavid van Moolenbroek 		put_value(proc, NULL, "%d", v);
15325d39513SDavid van Moolenbroek 
15425d39513SDavid van Moolenbroek 		put_close(proc, "}");
15525d39513SDavid van Moolenbroek 	} else
15625d39513SDavid van Moolenbroek 		put_ptr(proc, name, addr);
15725d39513SDavid van Moolenbroek 
15825d39513SDavid van Moolenbroek 	return TRUE;
15925d39513SDavid van Moolenbroek }
16025d39513SDavid van Moolenbroek 
16125d39513SDavid van Moolenbroek /*
16225d39513SDavid van Moolenbroek  * Print CTL_KERN KERN_CP_TIME.
16325d39513SDavid van Moolenbroek  */
16425d39513SDavid van Moolenbroek static int
put_kern_cp_time(struct trace_proc * proc,const char * name __unused,int type,const void * ptr,vir_bytes addr __unused,size_t size)16525d39513SDavid van Moolenbroek put_kern_cp_time(struct trace_proc * proc, const char * name __unused,
16625d39513SDavid van Moolenbroek 	int type, const void * ptr, vir_bytes addr __unused, size_t size)
16725d39513SDavid van Moolenbroek {
168b58e161cSDavid van Moolenbroek 	const uint64_t *p;
16925d39513SDavid van Moolenbroek 	unsigned int i;
17025d39513SDavid van Moolenbroek 	const int *mib;
17125d39513SDavid van Moolenbroek 
17225d39513SDavid van Moolenbroek 	if (type == ST_NAME) {
17325d39513SDavid van Moolenbroek 		mib = (const int *)ptr;
17425d39513SDavid van Moolenbroek 		for (i = 0; i < size; i++)
17525d39513SDavid van Moolenbroek 			put_value(proc, NULL, "%d", mib[i]);
17625d39513SDavid van Moolenbroek 
17725d39513SDavid van Moolenbroek 		return 0;
17825d39513SDavid van Moolenbroek 	}
17925d39513SDavid van Moolenbroek 
180b58e161cSDavid van Moolenbroek 	p = (const uint64_t *)ptr;
18125d39513SDavid van Moolenbroek 
18225d39513SDavid van Moolenbroek 	/* TODO: support for multi-CPU results */
18325d39513SDavid van Moolenbroek 	for (i = 0; i < CPUSTATES; i++)
18425d39513SDavid van Moolenbroek 		put_value(proc, NULL, "%"PRIu64, p[i]);
18525d39513SDavid van Moolenbroek 
18625d39513SDavid van Moolenbroek 	return TRUE;
18725d39513SDavid van Moolenbroek }
18825d39513SDavid van Moolenbroek 
18925d39513SDavid van Moolenbroek /*
19025d39513SDavid van Moolenbroek  * Print CTL_KERN KERN_CONSDEV.
19125d39513SDavid van Moolenbroek  */
19225d39513SDavid van Moolenbroek static int
put_kern_consdev(struct trace_proc * proc,const char * name,int type __unused,const void * ptr,vir_bytes addr __unused,size_t size __unused)19325d39513SDavid van Moolenbroek put_kern_consdev(struct trace_proc * proc, const char * name,
19425d39513SDavid van Moolenbroek 	int type __unused, const void * ptr, vir_bytes addr __unused,
19525d39513SDavid van Moolenbroek 	size_t size __unused)
19625d39513SDavid van Moolenbroek {
19725d39513SDavid van Moolenbroek 
198b58e161cSDavid van Moolenbroek 	put_dev(proc, NULL, *(const dev_t *)ptr);
19925d39513SDavid van Moolenbroek 
20025d39513SDavid van Moolenbroek 	return TRUE;
20125d39513SDavid van Moolenbroek }
20225d39513SDavid van Moolenbroek 
20325d39513SDavid van Moolenbroek /*
20425d39513SDavid van Moolenbroek  * Print CTL_KERN KERN_DRIVERS.
20525d39513SDavid van Moolenbroek  */
20625d39513SDavid van Moolenbroek static int
put_kern_drivers(struct trace_proc * proc,const char * name,int type __unused,const void * ptr __unused,vir_bytes addr __unused,size_t size)20725d39513SDavid van Moolenbroek put_kern_drivers(struct trace_proc * proc, const char * name,
20825d39513SDavid van Moolenbroek 	int type __unused, const void * ptr __unused, vir_bytes addr __unused,
20925d39513SDavid van Moolenbroek 	size_t size)
21025d39513SDavid van Moolenbroek {
21125d39513SDavid van Moolenbroek 
21225d39513SDavid van Moolenbroek 	/* TODO: optionally dump struct kinfo_drivers array */
21325d39513SDavid van Moolenbroek 	put_open(proc, name, 0, "[", ", ");
21425d39513SDavid van Moolenbroek 	if (size > 0)
21525d39513SDavid van Moolenbroek 		put_tail(proc, size / sizeof(struct kinfo_drivers), 0);
21625d39513SDavid van Moolenbroek 	put_close(proc, "]");
21725d39513SDavid van Moolenbroek 
21825d39513SDavid van Moolenbroek 	return TRUE;
21925d39513SDavid van Moolenbroek }
22025d39513SDavid van Moolenbroek 
22125d39513SDavid van Moolenbroek /*
22225d39513SDavid van Moolenbroek  * Print CTL_KERN KERN_BOOTTIME.
22325d39513SDavid van Moolenbroek  */
22425d39513SDavid van Moolenbroek static int
put_kern_boottime(struct trace_proc * proc,const char * name,int type __unused,const void * ptr __unused,vir_bytes addr,size_t size)22525d39513SDavid van Moolenbroek put_kern_boottime(struct trace_proc * proc, const char * name,
22625d39513SDavid van Moolenbroek 	int type __unused, const void * ptr __unused, vir_bytes addr,
22725d39513SDavid van Moolenbroek 	size_t size)
22825d39513SDavid van Moolenbroek {
22925d39513SDavid van Moolenbroek 
23025d39513SDavid van Moolenbroek 	if (size == sizeof(struct timeval))
23125d39513SDavid van Moolenbroek 		put_struct_timeval(proc, name, 0, addr);
23225d39513SDavid van Moolenbroek 	else
23325d39513SDavid van Moolenbroek 		put_ptr(proc, name, addr);
23425d39513SDavid van Moolenbroek 
23525d39513SDavid van Moolenbroek 	return TRUE;
23625d39513SDavid van Moolenbroek }
23725d39513SDavid van Moolenbroek 
2382f09e77bSDavid van Moolenbroek /*
2392f09e77bSDavid van Moolenbroek  * Print CTL_KERN KERN_SYSVIPC KERN_SYSVIPC_INFO.
2402f09e77bSDavid van Moolenbroek  */
2412f09e77bSDavid van Moolenbroek static int
put_kern_sysvipc_info(struct trace_proc * proc,const char * name,int type,const void * ptr,vir_bytes addr,size_t size)2422f09e77bSDavid van Moolenbroek put_kern_sysvipc_info(struct trace_proc * proc, const char * name,
243*764cd267SDavid van Moolenbroek 	int type, const void * ptr, vir_bytes addr, size_t size)
2442f09e77bSDavid van Moolenbroek {
2452f09e77bSDavid van Moolenbroek 	const int *mib;
2462f09e77bSDavid van Moolenbroek 	const char *text;
247b58e161cSDavid van Moolenbroek 	unsigned int i;
2482f09e77bSDavid van Moolenbroek 
2492f09e77bSDavid van Moolenbroek 	/*
2502f09e77bSDavid van Moolenbroek 	 * TODO: print the obtained structure(s).  For now we are just
2512f09e77bSDavid van Moolenbroek 	 * concerned with the name components.
2522f09e77bSDavid van Moolenbroek 	 */
2532f09e77bSDavid van Moolenbroek 	if (type != ST_NAME) {
2542f09e77bSDavid van Moolenbroek 		put_ptr(proc, name, addr);
2552f09e77bSDavid van Moolenbroek 
2562f09e77bSDavid van Moolenbroek 		return TRUE;
2572f09e77bSDavid van Moolenbroek 	}
2582f09e77bSDavid van Moolenbroek 
2592f09e77bSDavid van Moolenbroek 	mib = (const int *)ptr;
2602f09e77bSDavid van Moolenbroek 
2612f09e77bSDavid van Moolenbroek 	for (i = 0; i < size; i++) {
2622f09e77bSDavid van Moolenbroek 		text = NULL;
2632f09e77bSDavid van Moolenbroek 
2642f09e77bSDavid van Moolenbroek 		if (i == 0) {
2652f09e77bSDavid van Moolenbroek 			switch (mib[i]) {
2662f09e77bSDavid van Moolenbroek 			case KERN_SYSVIPC_SEM_INFO: text = "<sem>"; break;
2672f09e77bSDavid van Moolenbroek 			case KERN_SYSVIPC_SHM_INFO: text = "<shm>"; break;
2682f09e77bSDavid van Moolenbroek 			case KERN_SYSVIPC_MSG_INFO: text = "<msg>"; break;
2692f09e77bSDavid van Moolenbroek 			}
2702f09e77bSDavid van Moolenbroek 		}
2712f09e77bSDavid van Moolenbroek 
2722f09e77bSDavid van Moolenbroek 		if (!valuesonly && text != NULL)
2732f09e77bSDavid van Moolenbroek 			put_field(proc, NULL, text);
2742f09e77bSDavid van Moolenbroek 		else
2752f09e77bSDavid van Moolenbroek 			put_value(proc, NULL, "%d", mib[i]);
2762f09e77bSDavid van Moolenbroek 	}
2772f09e77bSDavid van Moolenbroek 
2782f09e77bSDavid van Moolenbroek 	return 0;
2792f09e77bSDavid van Moolenbroek }
2802f09e77bSDavid van Moolenbroek 
2812f09e77bSDavid van Moolenbroek /* The CTL_KERN KERN_SYSVIPC table. */
2822f09e77bSDavid van Moolenbroek static const struct sysctl_tab kern_sysvipc_tab[] = {
2832f09e77bSDavid van Moolenbroek 	PROC(KERN_SYSVIPC_INFO, 0, put_kern_sysvipc_info),
2842f09e77bSDavid van Moolenbroek };
2852f09e77bSDavid van Moolenbroek 
286e4e21ee1SDavid van Moolenbroek /* The CTL_KERN table. */
287e4e21ee1SDavid van Moolenbroek static const struct sysctl_tab kern_tab[] = {
28825d39513SDavid van Moolenbroek 	PROC(KERN_CLOCKRATE, sizeof(struct clockinfo), put_kern_clockrate),
28925d39513SDavid van Moolenbroek 	PROC(KERN_PROC2, 0, put_kern_proc2),
29025d39513SDavid van Moolenbroek 	PROC(KERN_PROC_ARGS, 0, put_kern_proc_args),
29125d39513SDavid van Moolenbroek 	PROC(KERN_CP_TIME, sizeof(uint64_t) * CPUSTATES, put_kern_cp_time),
29225d39513SDavid van Moolenbroek 	PROC(KERN_CONSDEV, sizeof(dev_t), put_kern_consdev),
29325d39513SDavid van Moolenbroek 	PROC(KERN_DRIVERS, 0, put_kern_drivers),
2942f09e77bSDavid van Moolenbroek 	NODE(KERN_SYSVIPC, kern_sysvipc_tab),
29525d39513SDavid van Moolenbroek 	PROC(KERN_BOOTTIME, 0, put_kern_boottime),
29625d39513SDavid van Moolenbroek };
29725d39513SDavid van Moolenbroek 
29825d39513SDavid van Moolenbroek /*
29925d39513SDavid van Moolenbroek  * Print CTL_VM VM_LOADAVG.
30025d39513SDavid van Moolenbroek  */
30125d39513SDavid van Moolenbroek static int
put_vm_loadavg(struct trace_proc * proc,const char * name __unused,int type __unused,const void * ptr,vir_bytes addr __unused,size_t size __unused)30225d39513SDavid van Moolenbroek put_vm_loadavg(struct trace_proc * proc, const char * name __unused,
30325d39513SDavid van Moolenbroek 	int type __unused, const void * ptr, vir_bytes addr __unused,
30425d39513SDavid van Moolenbroek 	size_t size __unused)
30525d39513SDavid van Moolenbroek {
306b58e161cSDavid van Moolenbroek 	const struct loadavg *loadavg;
30725d39513SDavid van Moolenbroek 	unsigned int i;
30825d39513SDavid van Moolenbroek 
309b58e161cSDavid van Moolenbroek 	loadavg = (const struct loadavg *)ptr;
31025d39513SDavid van Moolenbroek 
31125d39513SDavid van Moolenbroek 	put_open(proc, "ldavg", 0, "{", ", ");
31225d39513SDavid van Moolenbroek 
31325d39513SDavid van Moolenbroek 	for (i = 0; i < __arraycount(loadavg->ldavg); i++)
31425d39513SDavid van Moolenbroek 		put_value(proc, NULL, "%"PRIu32, loadavg->ldavg[i]);
31525d39513SDavid van Moolenbroek 
31625d39513SDavid van Moolenbroek 	put_close(proc, "}");
31725d39513SDavid van Moolenbroek 
31825d39513SDavid van Moolenbroek 	if (verbose > 0) {
31925d39513SDavid van Moolenbroek 		put_value(proc, "fscale", "%ld", loadavg->fscale);
32025d39513SDavid van Moolenbroek 
32125d39513SDavid van Moolenbroek 		return TRUE;
32225d39513SDavid van Moolenbroek 	} else
32325d39513SDavid van Moolenbroek 		return FALSE;
32425d39513SDavid van Moolenbroek }
32525d39513SDavid van Moolenbroek 
32625d39513SDavid van Moolenbroek /* The CTL_VM table. */
32725d39513SDavid van Moolenbroek static const struct sysctl_tab vm_tab[] = {
32825d39513SDavid van Moolenbroek 	PROC(VM_LOADAVG, sizeof(struct loadavg), put_vm_loadavg),
329e4e21ee1SDavid van Moolenbroek };
330e4e21ee1SDavid van Moolenbroek 
331*764cd267SDavid van Moolenbroek /*
332*764cd267SDavid van Moolenbroek  * Print CTL_NET PF_ROUTE 0.
333*764cd267SDavid van Moolenbroek  */
334*764cd267SDavid van Moolenbroek static int
put_net_route_rtable(struct trace_proc * proc,const char * name,int type,const void * ptr,vir_bytes addr,size_t size)335*764cd267SDavid van Moolenbroek put_net_route_rtable(struct trace_proc * proc, const char * name,
336*764cd267SDavid van Moolenbroek 	int type, const void * ptr, vir_bytes addr, size_t size)
337*764cd267SDavid van Moolenbroek {
338*764cd267SDavid van Moolenbroek 	const int *mib;
339*764cd267SDavid van Moolenbroek 	const char *text;
340*764cd267SDavid van Moolenbroek 	unsigned int i;
341*764cd267SDavid van Moolenbroek 
342*764cd267SDavid van Moolenbroek 	/*
343*764cd267SDavid van Moolenbroek 	 * TODO: print the obtained structure(s).  For now we are just
344*764cd267SDavid van Moolenbroek 	 * concerned with the name components.
345*764cd267SDavid van Moolenbroek 	 */
346*764cd267SDavid van Moolenbroek 	if (type != ST_NAME) {
347*764cd267SDavid van Moolenbroek 		put_ptr(proc, name, addr);
348*764cd267SDavid van Moolenbroek 
349*764cd267SDavid van Moolenbroek 		return TRUE;
350*764cd267SDavid van Moolenbroek 	}
351*764cd267SDavid van Moolenbroek 
352*764cd267SDavid van Moolenbroek 	mib = (const int *)ptr;
353*764cd267SDavid van Moolenbroek 
354*764cd267SDavid van Moolenbroek 	for (i = 0; i < size; i++) {
355*764cd267SDavid van Moolenbroek 		text = NULL;
356*764cd267SDavid van Moolenbroek 
357*764cd267SDavid van Moolenbroek 		switch (i) {
358*764cd267SDavid van Moolenbroek 		case 0:
359*764cd267SDavid van Moolenbroek 			switch (mib[i]) {
360*764cd267SDavid van Moolenbroek 			case AF_UNSPEC: text = "<all>"; break;
361*764cd267SDavid van Moolenbroek 			case AF_LINK: text = "<link>"; break;
362*764cd267SDavid van Moolenbroek 			case AF_INET: text = "<inet>"; break;
363*764cd267SDavid van Moolenbroek 			case AF_INET6: text = "<inet6>"; break;
364*764cd267SDavid van Moolenbroek 			/* TODO: add more address families here */
365*764cd267SDavid van Moolenbroek 			}
366*764cd267SDavid van Moolenbroek 			break;
367*764cd267SDavid van Moolenbroek 		case 1:
368*764cd267SDavid van Moolenbroek 			switch (mib[i]) {
369*764cd267SDavid van Moolenbroek 			case NET_RT_DUMP: text = "<dump>"; break;
370*764cd267SDavid van Moolenbroek 			case NET_RT_FLAGS: text = "<flags>"; break;
371*764cd267SDavid van Moolenbroek 			case NET_RT_IFLIST: text = "<iflist>"; break;
372*764cd267SDavid van Moolenbroek 			}
373*764cd267SDavid van Moolenbroek 			break;
374*764cd267SDavid van Moolenbroek 		case 2:
375*764cd267SDavid van Moolenbroek 			if (mib[1] == NET_RT_IFLIST && mib[i] == 0)
376*764cd267SDavid van Moolenbroek 				text = "<all>";
377*764cd267SDavid van Moolenbroek 		}
378*764cd267SDavid van Moolenbroek 
379*764cd267SDavid van Moolenbroek 		if (!valuesonly && text != NULL)
380*764cd267SDavid van Moolenbroek 			put_field(proc, NULL, text);
381*764cd267SDavid van Moolenbroek 		else
382*764cd267SDavid van Moolenbroek 			put_value(proc, NULL, "%d", mib[i]);
383*764cd267SDavid van Moolenbroek 	}
384*764cd267SDavid van Moolenbroek 
385*764cd267SDavid van Moolenbroek 	return 0;
386*764cd267SDavid van Moolenbroek }
387*764cd267SDavid van Moolenbroek 
388*764cd267SDavid van Moolenbroek /* The CTL_NET PF_ROUTE table. */
389*764cd267SDavid van Moolenbroek static const struct sysctl_tab net_route_tab[] = {
390*764cd267SDavid van Moolenbroek 	PROC(0, 0, put_net_route_rtable),
391*764cd267SDavid van Moolenbroek };
392*764cd267SDavid van Moolenbroek 
393*764cd267SDavid van Moolenbroek /* The CTL_NET table. */
394*764cd267SDavid van Moolenbroek static const struct sysctl_tab net_tab[] = {
395*764cd267SDavid van Moolenbroek 	NODE(PF_ROUTE, net_route_tab),
396*764cd267SDavid van Moolenbroek };
397*764cd267SDavid van Moolenbroek 
398e4e21ee1SDavid van Moolenbroek /* The top-level table, which is indexed by identifier. */
399e4e21ee1SDavid van Moolenbroek static const struct sysctl_tab root_tab[] = {
400e4e21ee1SDavid van Moolenbroek 	[CTL_KERN]	= NODE(0, kern_tab),
40125d39513SDavid van Moolenbroek 	[CTL_VM]	= NODE(0, vm_tab),
402*764cd267SDavid van Moolenbroek 	[CTL_NET]	= NODE(0, net_tab),
403e4e21ee1SDavid van Moolenbroek };
404e4e21ee1SDavid van Moolenbroek 
405e4e21ee1SDavid van Moolenbroek /*
406e4e21ee1SDavid van Moolenbroek  * This buffer should be large enough to avoid having to perform dynamic
407e4e21ee1SDavid van Moolenbroek  * allocation in all but highly exceptional cases.  The CTL_KERN subtree is
408e4e21ee1SDavid van Moolenbroek  * currently the largest, so we base the buffer size on its length.
409e4e21ee1SDavid van Moolenbroek  * TODO: merge this buffer with ioctlbuf.
410e4e21ee1SDavid van Moolenbroek  */
411e4e21ee1SDavid van Moolenbroek static char sysctlbuf[sizeof(struct sysctlnode) * KERN_MAXID];
412e4e21ee1SDavid van Moolenbroek 
413e4e21ee1SDavid van Moolenbroek static const struct flags sysctl_flags[] = {
414e4e21ee1SDavid van Moolenbroek 	FLAG_MASK(SYSCTL_VERS_MASK, SYSCTL_VERS_0),
415e4e21ee1SDavid van Moolenbroek 	FLAG_MASK(SYSCTL_VERS_MASK, SYSCTL_VERSION),
416e4e21ee1SDavid van Moolenbroek #define SYSCTL_VER_ENTRIES 2 /* the first N entries are for SYSCTL_VERS_MASK */
417e4e21ee1SDavid van Moolenbroek 	FLAG(CTLFLAG_UNSIGNED),
418e4e21ee1SDavid van Moolenbroek 	FLAG(CTLFLAG_OWNDESC),
419e4e21ee1SDavid van Moolenbroek 	FLAG(CTLFLAG_MMAP),
420e4e21ee1SDavid van Moolenbroek 	FLAG(CTLFLAG_ALIAS),
421e4e21ee1SDavid van Moolenbroek 	FLAG(CTLFLAG_ANYNUMBER),
422e4e21ee1SDavid van Moolenbroek 	FLAG(CTLFLAG_ROOT),
423e4e21ee1SDavid van Moolenbroek 	FLAG(CTLFLAG_HEX),
424e4e21ee1SDavid van Moolenbroek 	FLAG(CTLFLAG_IMMEDIATE),
425e4e21ee1SDavid van Moolenbroek 	FLAG(CTLFLAG_OWNDATA),
426e4e21ee1SDavid van Moolenbroek 	FLAG(CTLFLAG_HIDDEN),
427e4e21ee1SDavid van Moolenbroek 	FLAG(CTLFLAG_PERMANENT),
428e4e21ee1SDavid van Moolenbroek 	FLAG(CTLFLAG_PRIVATE),
429e4e21ee1SDavid van Moolenbroek 	FLAG(CTLFLAG_ANYWRITE),
430e4e21ee1SDavid van Moolenbroek 	FLAG_MASK(CTLFLAG_READWRITE, CTLFLAG_READONLY),
431e4e21ee1SDavid van Moolenbroek 	FLAG_MASK(CTLFLAG_READWRITE, CTLFLAG_READWRITE),
432e4e21ee1SDavid van Moolenbroek 	FLAG_MASK(SYSCTL_TYPEMASK, CTLTYPE_NODE),
433e4e21ee1SDavid van Moolenbroek 	FLAG_MASK(SYSCTL_TYPEMASK, CTLTYPE_INT),
434e4e21ee1SDavid van Moolenbroek 	FLAG_MASK(SYSCTL_TYPEMASK, CTLTYPE_STRING),
435e4e21ee1SDavid van Moolenbroek 	FLAG_MASK(SYSCTL_TYPEMASK, CTLTYPE_QUAD),
436e4e21ee1SDavid van Moolenbroek 	FLAG_MASK(SYSCTL_TYPEMASK, CTLTYPE_STRUCT),
437e4e21ee1SDavid van Moolenbroek 	FLAG_MASK(SYSCTL_TYPEMASK, CTLTYPE_BOOL),
438e4e21ee1SDavid van Moolenbroek };
439e4e21ee1SDavid van Moolenbroek 
440e4e21ee1SDavid van Moolenbroek /*
441e4e21ee1SDavid van Moolenbroek  * Print the immediate value of a sysctl node.
442e4e21ee1SDavid van Moolenbroek  */
443e4e21ee1SDavid van Moolenbroek static void
put_sysctl_imm(struct trace_proc * proc,struct sysctlnode * scn,int use_name)444e4e21ee1SDavid van Moolenbroek put_sysctl_imm(struct trace_proc * proc, struct sysctlnode * scn, int use_name)
445e4e21ee1SDavid van Moolenbroek {
446b58e161cSDavid van Moolenbroek 	const char *name;
447e4e21ee1SDavid van Moolenbroek 
448e4e21ee1SDavid van Moolenbroek 	name = NULL;
449e4e21ee1SDavid van Moolenbroek 
450e4e21ee1SDavid van Moolenbroek 	switch (SYSCTL_TYPE(scn->sysctl_flags)) {
451e4e21ee1SDavid van Moolenbroek 	case CTLTYPE_INT:
452e4e21ee1SDavid van Moolenbroek 		if (use_name)
453e4e21ee1SDavid van Moolenbroek 			name = "sysctl_idata";
454e4e21ee1SDavid van Moolenbroek 		if (scn->sysctl_flags & CTLFLAG_HEX)
455e4e21ee1SDavid van Moolenbroek 			put_value(proc, name, "0x%x", scn->sysctl_idata);
456e4e21ee1SDavid van Moolenbroek 		else if (scn->sysctl_flags & CTLFLAG_UNSIGNED)
457e4e21ee1SDavid van Moolenbroek 			put_value(proc, name, "%u", scn->sysctl_idata);
458e4e21ee1SDavid van Moolenbroek 		else
459e4e21ee1SDavid van Moolenbroek 			put_value(proc, name, "%d", scn->sysctl_idata);
460e4e21ee1SDavid van Moolenbroek 		break;
461e4e21ee1SDavid van Moolenbroek 	case CTLTYPE_BOOL:
462e4e21ee1SDavid van Moolenbroek 		if (use_name)
463e4e21ee1SDavid van Moolenbroek 			name = "sysctl_bdata";
464e4e21ee1SDavid van Moolenbroek 		put_field(proc, name, (scn->sysctl_bdata) ? "true" : "false");
465e4e21ee1SDavid van Moolenbroek 		break;
466e4e21ee1SDavid van Moolenbroek 	case CTLTYPE_QUAD:
467e4e21ee1SDavid van Moolenbroek 		if (use_name)
468e4e21ee1SDavid van Moolenbroek 			name = "sysctl_qdata";
469e4e21ee1SDavid van Moolenbroek 		if (scn->sysctl_flags & CTLFLAG_HEX)
470e4e21ee1SDavid van Moolenbroek 			put_value(proc, name, "0x%"PRIx64, scn->sysctl_qdata);
471e4e21ee1SDavid van Moolenbroek 		else
472e4e21ee1SDavid van Moolenbroek 			put_value(proc, name, "%"PRIu64, scn->sysctl_qdata);
473e4e21ee1SDavid van Moolenbroek 		break;
474e4e21ee1SDavid van Moolenbroek 	}
475e4e21ee1SDavid van Moolenbroek }
476e4e21ee1SDavid van Moolenbroek 
477e4e21ee1SDavid van Moolenbroek /*
478e4e21ee1SDavid van Moolenbroek  * Printer for CTL_QUERY data.
479e4e21ee1SDavid van Moolenbroek  */
480e4e21ee1SDavid van Moolenbroek static int
put_sysctl_query(struct trace_proc * proc,const char * name,int type,const void * data __unused,vir_bytes addr,size_t size)481e4e21ee1SDavid van Moolenbroek put_sysctl_query(struct trace_proc * proc, const char * name, int type,
482e4e21ee1SDavid van Moolenbroek 	const void * data __unused, vir_bytes addr, size_t size)
483e4e21ee1SDavid van Moolenbroek {
484e4e21ee1SDavid van Moolenbroek 	struct sysctlnode scn;
485e4e21ee1SDavid van Moolenbroek 
486e4e21ee1SDavid van Moolenbroek 	if (type == ST_NEWP) {
487e4e21ee1SDavid van Moolenbroek 		if (!put_open_struct(proc, name, 0, addr, &scn, sizeof(scn)))
488e4e21ee1SDavid van Moolenbroek 			return TRUE;
489e4e21ee1SDavid van Moolenbroek 
490e4e21ee1SDavid van Moolenbroek 		/* Print just the protocol version, that's all there is. */
491e4e21ee1SDavid van Moolenbroek 		if (verbose > 1)
492e4e21ee1SDavid van Moolenbroek 			put_flags(proc, "sysctl_flags", sysctl_flags,
493e4e21ee1SDavid van Moolenbroek 			    SYSCTL_VER_ENTRIES, "0x%x", scn.sysctl_flags);
494e4e21ee1SDavid van Moolenbroek 
495e4e21ee1SDavid van Moolenbroek 		put_close_struct(proc, FALSE /*all*/);
496e4e21ee1SDavid van Moolenbroek 	} else {
497e4e21ee1SDavid van Moolenbroek 		/* TODO: optionally dump struct sysctlnode array */
498e4e21ee1SDavid van Moolenbroek 		put_open(proc, name, 0, "[", ", ");
499e4e21ee1SDavid van Moolenbroek 		if (size > 0)
500e4e21ee1SDavid van Moolenbroek 			put_tail(proc, size / sizeof(scn), 0);
501e4e21ee1SDavid van Moolenbroek 		put_close(proc, "]");
502e4e21ee1SDavid van Moolenbroek 	}
503e4e21ee1SDavid van Moolenbroek 
504e4e21ee1SDavid van Moolenbroek 	return TRUE;
505e4e21ee1SDavid van Moolenbroek }
506e4e21ee1SDavid van Moolenbroek 
507e4e21ee1SDavid van Moolenbroek /*
508e4e21ee1SDavid van Moolenbroek  * Printer for CTL_CREATE data.
509e4e21ee1SDavid van Moolenbroek  */
510e4e21ee1SDavid van Moolenbroek static int
put_sysctl_create(struct trace_proc * proc,const char * name,int type,const void * data __unused,vir_bytes addr,size_t size)511e4e21ee1SDavid van Moolenbroek put_sysctl_create(struct trace_proc * proc, const char * name, int type,
512e4e21ee1SDavid van Moolenbroek 	const void * data __unused, vir_bytes addr, size_t size)
513e4e21ee1SDavid van Moolenbroek {
514e4e21ee1SDavid van Moolenbroek 	struct sysctlnode scn;
515e4e21ee1SDavid van Moolenbroek 
516e4e21ee1SDavid van Moolenbroek 	if (!put_open_struct(proc, name, 0, addr, &scn, sizeof(scn)))
517e4e21ee1SDavid van Moolenbroek 		return TRUE;
518e4e21ee1SDavid van Moolenbroek 
519e4e21ee1SDavid van Moolenbroek 	if (type == ST_NEWP)
520e4e21ee1SDavid van Moolenbroek 		put_flags(proc, "sysctl_flags", sysctl_flags,
521e4e21ee1SDavid van Moolenbroek 		    COUNT(sysctl_flags), "0x%x", scn.sysctl_flags);
522e4e21ee1SDavid van Moolenbroek 
523e4e21ee1SDavid van Moolenbroek 	if (scn.sysctl_num == CTL_CREATE && type == ST_NEWP && !valuesonly)
524e4e21ee1SDavid van Moolenbroek 		put_field(proc, "sysctl_num", "CTL_CREATE");
525e4e21ee1SDavid van Moolenbroek 	else
526e4e21ee1SDavid van Moolenbroek 		put_value(proc, "sysctl_num", "%d", scn.sysctl_num);
527e4e21ee1SDavid van Moolenbroek 
528e4e21ee1SDavid van Moolenbroek 	if (type == ST_NEWP) {
529e4e21ee1SDavid van Moolenbroek 		put_buf(proc, "sysctl_name", PF_LOCADDR | PF_STRING,
530e4e21ee1SDavid van Moolenbroek 		    (vir_bytes)scn.sysctl_name, sizeof(scn.sysctl_name));
531e4e21ee1SDavid van Moolenbroek 	}
532e4e21ee1SDavid van Moolenbroek 	if (scn.sysctl_ver != 0 && verbose > 0)
533e4e21ee1SDavid van Moolenbroek 		put_value(proc, "sysctl_ver", "%u", scn.sysctl_ver);
534e4e21ee1SDavid van Moolenbroek 
535e4e21ee1SDavid van Moolenbroek 	if (type == ST_NEWP) {
536e4e21ee1SDavid van Moolenbroek 		if (scn.sysctl_flags & CTLFLAG_IMMEDIATE)
537e4e21ee1SDavid van Moolenbroek 			put_sysctl_imm(proc, &scn, TRUE /*use_name*/);
538e4e21ee1SDavid van Moolenbroek 
539e4e21ee1SDavid van Moolenbroek 		switch (SYSCTL_TYPE(scn.sysctl_flags)) {
540e4e21ee1SDavid van Moolenbroek 		case CTLTYPE_NODE:
541e4e21ee1SDavid van Moolenbroek 			break;
542e4e21ee1SDavid van Moolenbroek 		case CTLTYPE_STRING:
543e4e21ee1SDavid van Moolenbroek 			if (scn.sysctl_data != NULL)
544e4e21ee1SDavid van Moolenbroek 				put_buf(proc, "sysctl_data", PF_STRING,
545e4e21ee1SDavid van Moolenbroek 				    (vir_bytes)scn.sysctl_data,
546e4e21ee1SDavid van Moolenbroek 				    (scn.sysctl_size > 0) ? scn.sysctl_size :
547e4e21ee1SDavid van Moolenbroek 				    SSIZE_MAX /* hopefully it stops early */);
548e4e21ee1SDavid van Moolenbroek 			if (scn.sysctl_data != NULL || verbose == 0)
549e4e21ee1SDavid van Moolenbroek 				break;
550e4e21ee1SDavid van Moolenbroek 			/* FALLTHROUGH */
551e4e21ee1SDavid van Moolenbroek 		default:
552e4e21ee1SDavid van Moolenbroek 			if (!(scn.sysctl_flags & CTLFLAG_IMMEDIATE) &&
553e4e21ee1SDavid van Moolenbroek 			    verbose > 0)
554e4e21ee1SDavid van Moolenbroek 				put_ptr(proc, "sysctl_data",
555e4e21ee1SDavid van Moolenbroek 				    (vir_bytes)scn.sysctl_data);
556e4e21ee1SDavid van Moolenbroek 			break;
557e4e21ee1SDavid van Moolenbroek 		}
558e4e21ee1SDavid van Moolenbroek 
559e4e21ee1SDavid van Moolenbroek 		if (SYSCTL_TYPE(scn.sysctl_flags) == CTLTYPE_STRUCT ||
560e4e21ee1SDavid van Moolenbroek 		    verbose > 0)
561e4e21ee1SDavid van Moolenbroek 			put_value(proc, "sysctl_size", "%zu", scn.sysctl_size);
562e4e21ee1SDavid van Moolenbroek 	}
563e4e21ee1SDavid van Moolenbroek 
564e4e21ee1SDavid van Moolenbroek 	put_close_struct(proc, FALSE /*all*/);
565e4e21ee1SDavid van Moolenbroek 
566e4e21ee1SDavid van Moolenbroek 	return TRUE;
567e4e21ee1SDavid van Moolenbroek }
568e4e21ee1SDavid van Moolenbroek 
569e4e21ee1SDavid van Moolenbroek /*
570e4e21ee1SDavid van Moolenbroek  * Printer for CTL_DESTROY data.
571e4e21ee1SDavid van Moolenbroek  */
572e4e21ee1SDavid van Moolenbroek static int
put_sysctl_destroy(struct trace_proc * proc,const char * name,int type,const void * data __unused,vir_bytes addr,size_t size)573e4e21ee1SDavid van Moolenbroek put_sysctl_destroy(struct trace_proc * proc, const char * name, int type,
574e4e21ee1SDavid van Moolenbroek 	const void * data __unused, vir_bytes addr, size_t size)
575e4e21ee1SDavid van Moolenbroek {
576e4e21ee1SDavid van Moolenbroek 	struct sysctlnode scn;
577e4e21ee1SDavid van Moolenbroek 
578e4e21ee1SDavid van Moolenbroek 	if (!put_open_struct(proc, name, 0, addr, &scn, sizeof(scn)))
579e4e21ee1SDavid van Moolenbroek 		return TRUE;
580e4e21ee1SDavid van Moolenbroek 
581e4e21ee1SDavid van Moolenbroek 	if (type == ST_NEWP) {
582e4e21ee1SDavid van Moolenbroek 		put_value(proc, "sysctl_num", "%d", scn.sysctl_num);
583e4e21ee1SDavid van Moolenbroek 		if (scn.sysctl_name[0] != '\0')
584e4e21ee1SDavid van Moolenbroek 			put_buf(proc, "sysctl_name", PF_LOCADDR | PF_STRING,
585e4e21ee1SDavid van Moolenbroek 			    (vir_bytes)scn.sysctl_name,
586e4e21ee1SDavid van Moolenbroek 			    sizeof(scn.sysctl_name));
587e4e21ee1SDavid van Moolenbroek 		if (scn.sysctl_ver != 0 && verbose > 0)
588e4e21ee1SDavid van Moolenbroek 			put_value(proc, "sysctl_ver", "%u", scn.sysctl_ver);
589e4e21ee1SDavid van Moolenbroek 	}
590e4e21ee1SDavid van Moolenbroek 
591e4e21ee1SDavid van Moolenbroek 	put_close_struct(proc, FALSE /*all*/);
592e4e21ee1SDavid van Moolenbroek 
593e4e21ee1SDavid van Moolenbroek 	return TRUE;
594e4e21ee1SDavid van Moolenbroek }
595e4e21ee1SDavid van Moolenbroek 
596e4e21ee1SDavid van Moolenbroek /*
597e4e21ee1SDavid van Moolenbroek  * Printer for CTL_CREATE data.
598e4e21ee1SDavid van Moolenbroek  */
599e4e21ee1SDavid van Moolenbroek static int
put_sysctl_describe(struct trace_proc * proc,const char * name,int type,const void * data __unused,vir_bytes addr,size_t size)600e4e21ee1SDavid van Moolenbroek put_sysctl_describe(struct trace_proc * proc, const char * name, int type,
601e4e21ee1SDavid van Moolenbroek 	const void * data __unused, vir_bytes addr, size_t size)
602e4e21ee1SDavid van Moolenbroek {
603e4e21ee1SDavid van Moolenbroek 	struct sysctlnode scn;
604e4e21ee1SDavid van Moolenbroek 
605e4e21ee1SDavid van Moolenbroek 	if (type == ST_NEWP) {
606e4e21ee1SDavid van Moolenbroek 		if (!put_open_struct(proc, name, 0, addr, &scn, sizeof(scn)))
607e4e21ee1SDavid van Moolenbroek 			return TRUE;
608e4e21ee1SDavid van Moolenbroek 
609e4e21ee1SDavid van Moolenbroek 		/* Print just the protocol version, that's all there is. */
610e4e21ee1SDavid van Moolenbroek 		if (verbose > 1)
611e4e21ee1SDavid van Moolenbroek 			put_flags(proc, "sysctl_flags", sysctl_flags,
612e4e21ee1SDavid van Moolenbroek 			    SYSCTL_VER_ENTRIES, "0x%x", scn.sysctl_flags);
613e4e21ee1SDavid van Moolenbroek 
614e4e21ee1SDavid van Moolenbroek 		put_value(proc, "sysctl_num", "%d", scn.sysctl_num);
615e4e21ee1SDavid van Moolenbroek 
616e4e21ee1SDavid van Moolenbroek 		if (scn.sysctl_desc != NULL)
617e4e21ee1SDavid van Moolenbroek 			put_buf(proc, "sysctl_desc", PF_STRING,
618e4e21ee1SDavid van Moolenbroek 			    (vir_bytes)scn.sysctl_desc, 1024 /*no constant!*/);
619e4e21ee1SDavid van Moolenbroek 		else if (verbose > 0)
620e4e21ee1SDavid van Moolenbroek 			put_ptr(proc, "sysctl_desc",
621e4e21ee1SDavid van Moolenbroek 			    (vir_bytes)scn.sysctl_desc);
622e4e21ee1SDavid van Moolenbroek 
623e4e21ee1SDavid van Moolenbroek 		put_close_struct(proc, FALSE /*all*/);
624e4e21ee1SDavid van Moolenbroek 	} else {
625e4e21ee1SDavid van Moolenbroek 		/* TODO: optionally dump struct sysctldesc array */
626e4e21ee1SDavid van Moolenbroek 		put_field(proc, name, (size == 0) ? "[]" : "[..]");
627e4e21ee1SDavid van Moolenbroek 	}
628e4e21ee1SDavid van Moolenbroek 
629e4e21ee1SDavid van Moolenbroek 	return TRUE;
630e4e21ee1SDavid van Moolenbroek }
631e4e21ee1SDavid van Moolenbroek 
632e4e21ee1SDavid van Moolenbroek /*
633e4e21ee1SDavid van Moolenbroek  * Printer for generic data, using the node flags stored in proc->sysctl_flags.
634e4e21ee1SDavid van Moolenbroek  */
635e4e21ee1SDavid van Moolenbroek static int
put_sysctl_generic(struct trace_proc * proc,const char * name,int type,const void * data __unused,vir_bytes addr,size_t size)636e4e21ee1SDavid van Moolenbroek put_sysctl_generic(struct trace_proc * proc, const char * name, int type,
637e4e21ee1SDavid van Moolenbroek 	const void * data __unused, vir_bytes addr, size_t size)
638e4e21ee1SDavid van Moolenbroek {
639e4e21ee1SDavid van Moolenbroek 	struct sysctlnode scn;
640e4e21ee1SDavid van Moolenbroek 	void *ptr;
641e4e21ee1SDavid van Moolenbroek 	size_t len;
642e4e21ee1SDavid van Moolenbroek 
643e4e21ee1SDavid van Moolenbroek 	switch (SYSCTL_TYPE(proc->sctl_flags)) {
644e4e21ee1SDavid van Moolenbroek 	case CTLTYPE_STRING:
645e4e21ee1SDavid van Moolenbroek 		put_buf(proc, name, PF_STRING, addr, size);
646e4e21ee1SDavid van Moolenbroek 		return TRUE;
647e4e21ee1SDavid van Moolenbroek 	case CTLTYPE_INT:
648e4e21ee1SDavid van Moolenbroek 		ptr = &scn.sysctl_idata;
649e4e21ee1SDavid van Moolenbroek 		len = sizeof(scn.sysctl_idata);
650e4e21ee1SDavid van Moolenbroek 		break;
651e4e21ee1SDavid van Moolenbroek 	case CTLTYPE_BOOL:
652e4e21ee1SDavid van Moolenbroek 		ptr = &scn.sysctl_bdata;
653e4e21ee1SDavid van Moolenbroek 		len = sizeof(scn.sysctl_bdata);
654e4e21ee1SDavid van Moolenbroek 		break;
655e4e21ee1SDavid van Moolenbroek 	case CTLTYPE_QUAD:
656e4e21ee1SDavid van Moolenbroek 		ptr = &scn.sysctl_qdata;
657e4e21ee1SDavid van Moolenbroek 		len = sizeof(scn.sysctl_qdata);
658e4e21ee1SDavid van Moolenbroek 		break;
659e4e21ee1SDavid van Moolenbroek 	case CTLTYPE_STRUCT:
660e4e21ee1SDavid van Moolenbroek 	default:
661e4e21ee1SDavid van Moolenbroek 		ptr = NULL;
662e4e21ee1SDavid van Moolenbroek 		len = 0;
663e4e21ee1SDavid van Moolenbroek 		break;
664e4e21ee1SDavid van Moolenbroek 	}
665e4e21ee1SDavid van Moolenbroek 
666e4e21ee1SDavid van Moolenbroek 	if (ptr == NULL || len != size ||
667e4e21ee1SDavid van Moolenbroek 	    mem_get_data(proc->pid, addr, ptr, len) < 0) {
668e4e21ee1SDavid van Moolenbroek 		put_ptr(proc, name, addr);
669e4e21ee1SDavid van Moolenbroek 		return TRUE;
670e4e21ee1SDavid van Moolenbroek 	}
671e4e21ee1SDavid van Moolenbroek 
672e4e21ee1SDavid van Moolenbroek 	put_open(proc, name, PF_NONAME, "{", ", ");
673e4e21ee1SDavid van Moolenbroek 
674e4e21ee1SDavid van Moolenbroek 	scn.sysctl_flags = proc->sctl_flags;
675e4e21ee1SDavid van Moolenbroek 
676e4e21ee1SDavid van Moolenbroek 	put_sysctl_imm(proc, &scn, FALSE);
677e4e21ee1SDavid van Moolenbroek 
678e4e21ee1SDavid van Moolenbroek 	put_close(proc, "}");
679e4e21ee1SDavid van Moolenbroek 
680e4e21ee1SDavid van Moolenbroek 	return TRUE;
681e4e21ee1SDavid van Moolenbroek }
682e4e21ee1SDavid van Moolenbroek 
683e4e21ee1SDavid van Moolenbroek /*
684e4e21ee1SDavid van Moolenbroek  * Obtain information about a particular node 'id' in the node directory
685e4e21ee1SDavid van Moolenbroek  * identified by the MIB path 'name' (length 'namelen').  Return TRUE if the
686e4e21ee1SDavid van Moolenbroek  * node was found, in which case it is copied into 'scnp'.  Return FALSE if the
687e4e21ee1SDavid van Moolenbroek  * node was not found or another error occurred.
688e4e21ee1SDavid van Moolenbroek  */
689e4e21ee1SDavid van Moolenbroek static int
get_sysctl_node(const int * name,unsigned int namelen,int id,struct sysctlnode * scnp)690e4e21ee1SDavid van Moolenbroek get_sysctl_node(const int * name, unsigned int namelen, int id,
691e4e21ee1SDavid van Moolenbroek 	struct sysctlnode * scnp)
692e4e21ee1SDavid van Moolenbroek {
693e4e21ee1SDavid van Moolenbroek 	struct sysctlnode *scn, *escn, *fscn;
694e4e21ee1SDavid van Moolenbroek 	char *buf;
695e4e21ee1SDavid van Moolenbroek 	size_t len, elen;
696e4e21ee1SDavid van Moolenbroek 	int r, mib[CTL_MAXNAME];
697e4e21ee1SDavid van Moolenbroek 
698e4e21ee1SDavid van Moolenbroek 	assert(namelen < CTL_MAXNAME);
699e4e21ee1SDavid van Moolenbroek 	assert(id >= 0);
700e4e21ee1SDavid van Moolenbroek 
701e4e21ee1SDavid van Moolenbroek 	/* Query the parent, first using our static buffer for the results. */
702e4e21ee1SDavid van Moolenbroek 	memcpy(mib, name, sizeof(mib[0]) * namelen);
703e4e21ee1SDavid van Moolenbroek 	mib[namelen] = CTL_QUERY;
704e4e21ee1SDavid van Moolenbroek 	len = sizeof(sysctlbuf);
705e4e21ee1SDavid van Moolenbroek 	r = sysctl(mib, namelen + 1, sysctlbuf, &len, NULL, 0);
706e4e21ee1SDavid van Moolenbroek 	if (r == -1 && (errno != ENOMEM || len == 0))
707e4e21ee1SDavid van Moolenbroek 		return FALSE;
708e4e21ee1SDavid van Moolenbroek 
709e4e21ee1SDavid van Moolenbroek 	/* Even with partial results, check if we already found the node. */
710e4e21ee1SDavid van Moolenbroek 	elen = MIN(len, sizeof(sysctlbuf));
711e4e21ee1SDavid van Moolenbroek 	scn = (struct sysctlnode *)sysctlbuf;
712e4e21ee1SDavid van Moolenbroek 	escn = (struct sysctlnode *)&sysctlbuf[elen];
713e4e21ee1SDavid van Moolenbroek 	fscn = NULL; /* pointer to the node once found, NULL until then */
714e4e21ee1SDavid van Moolenbroek 	for (; scn < escn && fscn == NULL; scn++)
715e4e21ee1SDavid van Moolenbroek 		if (scn->sysctl_num == id)
716e4e21ee1SDavid van Moolenbroek 			fscn = scn;
717e4e21ee1SDavid van Moolenbroek 
718e4e21ee1SDavid van Moolenbroek 	/* If our buffer was too small, use a temporary buffer. */
719e4e21ee1SDavid van Moolenbroek 	if (fscn == NULL && r == -1) {
720e4e21ee1SDavid van Moolenbroek 		if ((buf = malloc(len)) == NULL)
721e4e21ee1SDavid van Moolenbroek 			return FALSE;
722e4e21ee1SDavid van Moolenbroek 		if (sysctl(mib, namelen, buf, &len, NULL, 0) == 0) {
723e4e21ee1SDavid van Moolenbroek 			scn = (struct sysctlnode *)sysctlbuf;
724e4e21ee1SDavid van Moolenbroek 			escn = (struct sysctlnode *)&sysctlbuf[len];
725e4e21ee1SDavid van Moolenbroek 			for (; scn < escn && fscn != NULL; scn++)
726e4e21ee1SDavid van Moolenbroek 				if (scn->sysctl_num == id)
727e4e21ee1SDavid van Moolenbroek 					fscn = scn;
728e4e21ee1SDavid van Moolenbroek 		}
729e4e21ee1SDavid van Moolenbroek 		free(buf);
730e4e21ee1SDavid van Moolenbroek 	}
731e4e21ee1SDavid van Moolenbroek 
732e4e21ee1SDavid van Moolenbroek 	if (fscn != NULL) {
733e4e21ee1SDavid van Moolenbroek 		memcpy(scnp, fscn, sizeof(*scnp));
734e4e21ee1SDavid van Moolenbroek 		return TRUE;
735e4e21ee1SDavid van Moolenbroek 	} else
736e4e21ee1SDavid van Moolenbroek 		return FALSE;
737e4e21ee1SDavid van Moolenbroek }
738e4e21ee1SDavid van Moolenbroek 
739e4e21ee1SDavid van Moolenbroek /*
740e4e21ee1SDavid van Moolenbroek  * Print the name string of one level of a sysctl(2) name, while also gathering
741e4e21ee1SDavid van Moolenbroek  * information about the target node.  Return 1 if name interpretation should
742e4e21ee1SDavid van Moolenbroek  * continue as before, meaning this function will also be called for the next
743e4e21ee1SDavid van Moolenbroek  * name component (if any).  Return 0 if the rest of the name should be printed
744e4e21ee1SDavid van Moolenbroek  * as numbers, without interpretation.  Return -1 if printing the name is now
745e4e21ee1SDavid van Moolenbroek  * complete.
746e4e21ee1SDavid van Moolenbroek  */
747e4e21ee1SDavid van Moolenbroek static int
put_sysctl_namestr(struct trace_proc * proc,const int * name,unsigned int namelen,unsigned int n,int all,const struct sysctl_tab ** sctp)748e4e21ee1SDavid van Moolenbroek put_sysctl_namestr(struct trace_proc * proc, const int * name,
749e4e21ee1SDavid van Moolenbroek 	unsigned int namelen, unsigned int n, int all,
750e4e21ee1SDavid van Moolenbroek 	const struct sysctl_tab ** sctp)
751e4e21ee1SDavid van Moolenbroek {
752e4e21ee1SDavid van Moolenbroek 	const struct sysctl_tab *sct;
753e4e21ee1SDavid van Moolenbroek 	struct sysctlnode scn;
754e4e21ee1SDavid van Moolenbroek 	const char *namestr;
755e4e21ee1SDavid van Moolenbroek 	int i, r, id, is_last;
756e4e21ee1SDavid van Moolenbroek 
757e4e21ee1SDavid van Moolenbroek 	assert(n < namelen);
758e4e21ee1SDavid van Moolenbroek 
759e4e21ee1SDavid van Moolenbroek 	id = name[n];
760e4e21ee1SDavid van Moolenbroek 	is_last = (n == namelen - 1 && all);
761e4e21ee1SDavid van Moolenbroek 	namestr = NULL;
762e4e21ee1SDavid van Moolenbroek 
763e4e21ee1SDavid van Moolenbroek 	/* Negative identifiers are meta-identifiers. */
764e4e21ee1SDavid van Moolenbroek 	if (id < 0) {
765e4e21ee1SDavid van Moolenbroek 		switch (id) {
766e4e21ee1SDavid van Moolenbroek 		case CTL_EOL:		namestr = "<eol>";		break;
767e4e21ee1SDavid van Moolenbroek 		case CTL_QUERY:		namestr = "<query>";		break;
768e4e21ee1SDavid van Moolenbroek 		case CTL_CREATE:	namestr = "<create>";		break;
769e4e21ee1SDavid van Moolenbroek 		case CTL_CREATESYM:	namestr = "<createsym>";	break;
770e4e21ee1SDavid van Moolenbroek 		case CTL_DESTROY:	namestr = "<destroy>";		break;
771e4e21ee1SDavid van Moolenbroek 		case CTL_MMAP:		namestr = "<mmap>";		break;
772e4e21ee1SDavid van Moolenbroek 		case CTL_DESCRIBE:	namestr = "<describe>";		break;
773e4e21ee1SDavid van Moolenbroek 		}
774e4e21ee1SDavid van Moolenbroek 
775e4e21ee1SDavid van Moolenbroek 		/* For some of them, we can print their parameters. */
776e4e21ee1SDavid van Moolenbroek 		if (is_last) {
777e4e21ee1SDavid van Moolenbroek 			switch (id) {
778e4e21ee1SDavid van Moolenbroek 			case CTL_QUERY:
779e4e21ee1SDavid van Moolenbroek 				proc->sctl_proc = put_sysctl_query;
780e4e21ee1SDavid van Moolenbroek 				break;
781e4e21ee1SDavid van Moolenbroek 			case CTL_CREATE:
782e4e21ee1SDavid van Moolenbroek 				proc->sctl_proc = put_sysctl_create;
783e4e21ee1SDavid van Moolenbroek 				break;
784e4e21ee1SDavid van Moolenbroek 			case CTL_DESTROY:
785e4e21ee1SDavid van Moolenbroek 				proc->sctl_proc = put_sysctl_destroy;
786e4e21ee1SDavid van Moolenbroek 				break;
787e4e21ee1SDavid van Moolenbroek 			case CTL_DESCRIBE:
788e4e21ee1SDavid van Moolenbroek 				proc->sctl_proc = put_sysctl_describe;
789e4e21ee1SDavid van Moolenbroek 				break;
790e4e21ee1SDavid van Moolenbroek 			}
791e4e21ee1SDavid van Moolenbroek 		}
792e4e21ee1SDavid van Moolenbroek 
793e4e21ee1SDavid van Moolenbroek 		/*
794e4e21ee1SDavid van Moolenbroek 		 * Meta-identifiers are allowed only at the very end of a name,
795e4e21ee1SDavid van Moolenbroek 		 * so if anything follows a meta-identifier, there is no good
796e4e21ee1SDavid van Moolenbroek 		 * way to interpret it.  We just print numbers.
797e4e21ee1SDavid van Moolenbroek 		 */
798e4e21ee1SDavid van Moolenbroek 		r = 0;
799e4e21ee1SDavid van Moolenbroek 	} else if (get_sysctl_node(name, n, id, &scn)) {
800e4e21ee1SDavid van Moolenbroek 		/*
801e4e21ee1SDavid van Moolenbroek 		 * For regular identifiers, first see if we have a callback
802e4e21ee1SDavid van Moolenbroek 		 * function that does the interpretation.  The use of the
803e4e21ee1SDavid van Moolenbroek 		 * callback function depends on whether the current node is of
804e4e21ee1SDavid van Moolenbroek 		 * type CTLTYPE_NODE: if it is, the callback function is
805e4e21ee1SDavid van Moolenbroek 		 * responsible for printing the rest of the name (and we return
806e4e21ee1SDavid van Moolenbroek 		 * -1 here after we are done, #1); if it isn't, then we just
807e4e21ee1SDavid van Moolenbroek 		 * use the callback function to interpret the node value (#2).
808e4e21ee1SDavid van Moolenbroek 		 * If we do not have a callback function, but the current node
809e4e21ee1SDavid van Moolenbroek 		 * is of type CTLTYPE_NODE *and* has a non-NULL callback
810e4e21ee1SDavid van Moolenbroek 		 * function registered in the MIB service, the remote callback
811e4e21ee1SDavid van Moolenbroek 		 * function would interpret the rest of the name, so we simply
812e4e21ee1SDavid van Moolenbroek 		 * print the rest of the name as numbers (returning 0 once we
813e4e21ee1SDavid van Moolenbroek 		 * are done, #3).  Without a MIB-service callback function,
814e4e21ee1SDavid van Moolenbroek 		 * such nodes are just taken as path components and thus we
815e4e21ee1SDavid van Moolenbroek 		 * return 1 to continue resolution (#4).  Finally, if we do not
816e4e21ee1SDavid van Moolenbroek 		 * have a callback function, and the current node is a data
817e4e21ee1SDavid van Moolenbroek 		 * node (i.e., *not* of type CTLTYPE_NODE), we try to interpret
818e4e21ee1SDavid van Moolenbroek 		 * it generically if it is the last component (#5), or we give
819e4e21ee1SDavid van Moolenbroek 		 * up and just print numbers otherwise (#6).
820e4e21ee1SDavid van Moolenbroek 		 */
821e4e21ee1SDavid van Moolenbroek 
822e4e21ee1SDavid van Moolenbroek 		/* Okay, so start by looking up the node in our own tables. */
823e4e21ee1SDavid van Moolenbroek 		sct = NULL;
824e4e21ee1SDavid van Moolenbroek 		if (n == 0) {
825e4e21ee1SDavid van Moolenbroek 			/* The top level is ID-indexed for performance. */
826e4e21ee1SDavid van Moolenbroek 			if ((unsigned int)id < __arraycount(root_tab))
827e4e21ee1SDavid van Moolenbroek 				*sctp = &root_tab[id];
828e4e21ee1SDavid van Moolenbroek 			else
829e4e21ee1SDavid van Moolenbroek 				*sctp = NULL;
830e4e21ee1SDavid van Moolenbroek 		} else if (*sctp != NULL) {
831e4e21ee1SDavid van Moolenbroek 			/* Other levels are searched, because of sparseness. */
832e4e21ee1SDavid van Moolenbroek 			sct = (*sctp)->tab; /* NULL if missing or leaf */
833e4e21ee1SDavid van Moolenbroek 			for (i = (int)(*sctp)->size; sct != NULL && i > 0;
834e4e21ee1SDavid van Moolenbroek 			    i--, sct++)
835e4e21ee1SDavid van Moolenbroek 				if (sct->id == id)
836e4e21ee1SDavid van Moolenbroek 					break;
837e4e21ee1SDavid van Moolenbroek 			if (i == 0)
838e4e21ee1SDavid van Moolenbroek 				sct = NULL;
839e4e21ee1SDavid van Moolenbroek 			*sctp = sct;
840e4e21ee1SDavid van Moolenbroek 		}
841e4e21ee1SDavid van Moolenbroek 
842e4e21ee1SDavid van Moolenbroek 		/* Now determine what to do. */
843e4e21ee1SDavid van Moolenbroek 		if (SYSCTL_TYPE(scn.sysctl_flags) == CTLTYPE_NODE) {
844e4e21ee1SDavid van Moolenbroek 			if (sct != NULL && sct->proc != NULL) {
845e4e21ee1SDavid van Moolenbroek 				proc->sctl_size = sct->size;
846e4e21ee1SDavid van Moolenbroek 				proc->sctl_proc = sct->proc;
847e4e21ee1SDavid van Moolenbroek 				r = -1; /* #1 */
848e4e21ee1SDavid van Moolenbroek 			} else if (scn.sysctl_func != NULL)
849e4e21ee1SDavid van Moolenbroek 				r = 0; /* #3 */
850e4e21ee1SDavid van Moolenbroek 			else
851e4e21ee1SDavid van Moolenbroek 				r = 1; /* #4 */
852e4e21ee1SDavid van Moolenbroek 		} else {
853e4e21ee1SDavid van Moolenbroek 			if (!is_last)
854e4e21ee1SDavid van Moolenbroek 				r = 0; /* #6 */
855e4e21ee1SDavid van Moolenbroek 			else if (sct != NULL && sct->proc != NULL) {
856e4e21ee1SDavid van Moolenbroek 				/* A nonzero size must match the node size. */
857e4e21ee1SDavid van Moolenbroek 				if (sct->size == 0 ||
858e4e21ee1SDavid van Moolenbroek 				    sct->size == scn.sysctl_size) {
859e4e21ee1SDavid van Moolenbroek 					proc->sctl_size = sct->size;
860e4e21ee1SDavid van Moolenbroek 					proc->sctl_proc = sct->proc;
861e4e21ee1SDavid van Moolenbroek 				}
862e4e21ee1SDavid van Moolenbroek 				r = 0; /* #2 */
863e4e21ee1SDavid van Moolenbroek 			} else {
864e4e21ee1SDavid van Moolenbroek 				proc->sctl_flags = scn.sysctl_flags;
865e4e21ee1SDavid van Moolenbroek 				proc->sctl_proc = put_sysctl_generic;
866e4e21ee1SDavid van Moolenbroek 				r = 0; /* #5 */
867e4e21ee1SDavid van Moolenbroek 			}
868e4e21ee1SDavid van Moolenbroek 		}
869e4e21ee1SDavid van Moolenbroek 
870e4e21ee1SDavid van Moolenbroek 		namestr = scn.sysctl_name;
871e4e21ee1SDavid van Moolenbroek 	} else {
872e4e21ee1SDavid van Moolenbroek 		/*
873e4e21ee1SDavid van Moolenbroek 		 * The node was not found.  This basically means that we will
874e4e21ee1SDavid van Moolenbroek 		 * not be able to get any information about deeper nodes
875e4e21ee1SDavid van Moolenbroek 		 * either.  We do not even try: just print numbers.
876e4e21ee1SDavid van Moolenbroek 		 */
877e4e21ee1SDavid van Moolenbroek 		r = 0;
878e4e21ee1SDavid van Moolenbroek 	}
879e4e21ee1SDavid van Moolenbroek 
880e4e21ee1SDavid van Moolenbroek 	if (!valuesonly && namestr != NULL)
881e4e21ee1SDavid van Moolenbroek 		put_field(proc, NULL, namestr);
882e4e21ee1SDavid van Moolenbroek 	else
883e4e21ee1SDavid van Moolenbroek 		put_value(proc, NULL, "%d", id);
884e4e21ee1SDavid van Moolenbroek 
885e4e21ee1SDavid van Moolenbroek 	/*
886e4e21ee1SDavid van Moolenbroek 	 * Did we determine that the rest of the name should be printed by the
887e4e21ee1SDavid van Moolenbroek 	 * callback function?  Then we might as well make that happen.  The
888e4e21ee1SDavid van Moolenbroek 	 * abuse of the parameter types is not great, oh well.
889e4e21ee1SDavid van Moolenbroek 	 */
890e4e21ee1SDavid van Moolenbroek 	if (r == -1)
891e4e21ee1SDavid van Moolenbroek 		(void)proc->sctl_proc(proc, NULL, ST_NAME, &name[n + 1], 0,
892e4e21ee1SDavid van Moolenbroek 		    namelen - n - 1);
893e4e21ee1SDavid van Moolenbroek 
894e4e21ee1SDavid van Moolenbroek 	return r;
895e4e21ee1SDavid van Moolenbroek }
896e4e21ee1SDavid van Moolenbroek 
897e4e21ee1SDavid van Moolenbroek /*
898e4e21ee1SDavid van Moolenbroek  * Print the sysctl(2) name parameter, and gather information needed to print
899e4e21ee1SDavid van Moolenbroek  * the oldp and newp parameters later.
900e4e21ee1SDavid van Moolenbroek  */
901e4e21ee1SDavid van Moolenbroek static void
put_sysctl_name(struct trace_proc * proc,const char * name,int flags,vir_bytes addr,unsigned int namelen)902e4e21ee1SDavid van Moolenbroek put_sysctl_name(struct trace_proc * proc, const char * name, int flags,
903e4e21ee1SDavid van Moolenbroek 	vir_bytes addr, unsigned int namelen)
904e4e21ee1SDavid van Moolenbroek {
905e4e21ee1SDavid van Moolenbroek 	const struct sysctl_tab *sct = NULL;
906e4e21ee1SDavid van Moolenbroek 	int r, all, namebuf[CTL_MAXNAME];
907e4e21ee1SDavid van Moolenbroek 	unsigned int n;
908e4e21ee1SDavid van Moolenbroek 
909e4e21ee1SDavid van Moolenbroek 	if (namelen > CTL_MAXNAME) {
910e4e21ee1SDavid van Moolenbroek 		namelen = CTL_MAXNAME;
911e4e21ee1SDavid van Moolenbroek 		all = 0;
912e4e21ee1SDavid van Moolenbroek 	} else
913e4e21ee1SDavid van Moolenbroek 		all = 1;
914e4e21ee1SDavid van Moolenbroek 
915e4e21ee1SDavid van Moolenbroek 	if ((flags & PF_FAILED) || valuesonly > 1 || namelen > CTL_MAXNAME ||
916e4e21ee1SDavid van Moolenbroek 	    (namelen > 0 && !(flags & PF_LOCADDR) &&
917e4e21ee1SDavid van Moolenbroek 	    mem_get_data(proc->pid, addr, namebuf,
918e4e21ee1SDavid van Moolenbroek 	    namelen * sizeof(namebuf[0])) < 0)) {
919e4e21ee1SDavid van Moolenbroek 		if (flags & PF_LOCADDR)
920e4e21ee1SDavid van Moolenbroek 			put_field(proc, name, "&..");
921e4e21ee1SDavid van Moolenbroek 		else
922e4e21ee1SDavid van Moolenbroek 			put_ptr(proc, name, addr);
923e4e21ee1SDavid van Moolenbroek 		return;
924e4e21ee1SDavid van Moolenbroek 	} else if (namelen > 0 && (flags & PF_LOCADDR))
925e4e21ee1SDavid van Moolenbroek 		memcpy(namebuf, (void *)addr, sizeof(namebuf[0]) * namelen);
926e4e21ee1SDavid van Moolenbroek 
927e4e21ee1SDavid van Moolenbroek 	/*
928e4e21ee1SDavid van Moolenbroek 	 * Print the path name of the node as possible, and find information
929e4e21ee1SDavid van Moolenbroek 	 * about the target node as we go along.  See put_sysctl_namestr() for
930e4e21ee1SDavid van Moolenbroek 	 * the meaning of 'r'.
931e4e21ee1SDavid van Moolenbroek 	 */
932e4e21ee1SDavid van Moolenbroek 	put_open(proc, name, PF_NONAME, "[", ".");
933e4e21ee1SDavid van Moolenbroek 	for (n = 0, r = 1; n < namelen; n++) {
934e4e21ee1SDavid van Moolenbroek 		if (r == 1) {
935e4e21ee1SDavid van Moolenbroek 			if ((r = put_sysctl_namestr(proc, namebuf, namelen, n,
936e4e21ee1SDavid van Moolenbroek 			    all, &sct)) < 0)
937e4e21ee1SDavid van Moolenbroek 				break;
938e4e21ee1SDavid van Moolenbroek 		} else
939e4e21ee1SDavid van Moolenbroek 			put_value(proc, NULL, "%d", namebuf[n]);
940e4e21ee1SDavid van Moolenbroek 	}
941e4e21ee1SDavid van Moolenbroek 	if (!all)
942e4e21ee1SDavid van Moolenbroek 		put_field(proc, NULL, "..");
943e4e21ee1SDavid van Moolenbroek 	put_close(proc, "]");
944e4e21ee1SDavid van Moolenbroek }
945e4e21ee1SDavid van Moolenbroek 
946e4e21ee1SDavid van Moolenbroek /*
947e4e21ee1SDavid van Moolenbroek  * Print the sysctl(2) oldp or newp parameter.  PF_ALT means that the given
948e4e21ee1SDavid van Moolenbroek  * parameter is newp rather than oldp, in which case PF_FAILED will not be set.
949e4e21ee1SDavid van Moolenbroek  */
950e4e21ee1SDavid van Moolenbroek static void
put_sysctl_data(struct trace_proc * proc,const char * name,int flags,vir_bytes addr,size_t len)951e4e21ee1SDavid van Moolenbroek put_sysctl_data(struct trace_proc * proc, const char * name, int flags,
952e4e21ee1SDavid van Moolenbroek 	vir_bytes addr, size_t len)
953e4e21ee1SDavid van Moolenbroek {
954e4e21ee1SDavid van Moolenbroek 	char *ptr;
955e4e21ee1SDavid van Moolenbroek 	int type, all;
956e4e21ee1SDavid van Moolenbroek 
957e4e21ee1SDavid van Moolenbroek 	if ((flags & PF_FAILED) || addr == 0 || valuesonly > 1 ||
958e4e21ee1SDavid van Moolenbroek 	    proc->sctl_proc == NULL || proc->sctl_size > sizeof(sysctlbuf) ||
959e4e21ee1SDavid van Moolenbroek 	    (proc->sctl_size > 0 && (proc->sctl_size != len ||
960e4e21ee1SDavid van Moolenbroek 	    mem_get_data(proc->pid, addr, sysctlbuf, proc->sctl_size) < 0))) {
961e4e21ee1SDavid van Moolenbroek 		put_ptr(proc, name, addr);
962e4e21ee1SDavid van Moolenbroek 		return;
963e4e21ee1SDavid van Moolenbroek 	}
964e4e21ee1SDavid van Moolenbroek 
965e4e21ee1SDavid van Moolenbroek 	type = (flags & PF_ALT) ? ST_NEWP : ST_OLDP;
966e4e21ee1SDavid van Moolenbroek 	ptr = (proc->sctl_size > 0) ? sysctlbuf : NULL;
967e4e21ee1SDavid van Moolenbroek 
968e4e21ee1SDavid van Moolenbroek 	/*
969e4e21ee1SDavid van Moolenbroek 	 * The rough idea here: we have a "simple" mode and a "flexible" mode,
970e4e21ee1SDavid van Moolenbroek 	 * depending on whether a size was specified in our table.  For the
971e4e21ee1SDavid van Moolenbroek 	 * simple mode, we only call the callback function when we have been
972e4e21ee1SDavid van Moolenbroek 	 * able to copy in the data.  A surrounding {} block will be printed
973e4e21ee1SDavid van Moolenbroek 	 * automatically, the callback function only has to print the data
974e4e21ee1SDavid van Moolenbroek 	 * fields.  The simple mode is basically for structures.  In contrast,
975e4e21ee1SDavid van Moolenbroek 	 * the flexible mode leaves both the copying and the printing entirely
976e4e21ee1SDavid van Moolenbroek 	 * to the callback function, which thus may print the pointer on copy
977e4e21ee1SDavid van Moolenbroek 	 * failure (in which case the surrounding {}s would get in the way).
978e4e21ee1SDavid van Moolenbroek 	 */
979e4e21ee1SDavid van Moolenbroek 	if (ptr != NULL)
980e4e21ee1SDavid van Moolenbroek 		put_open(proc, name, 0, "{", ", ");
981e4e21ee1SDavid van Moolenbroek 
982e4e21ee1SDavid van Moolenbroek 	all = proc->sctl_proc(proc, name, type, ptr, addr, len);
983e4e21ee1SDavid van Moolenbroek 
984e4e21ee1SDavid van Moolenbroek 	if (ptr != NULL) {
985e4e21ee1SDavid van Moolenbroek 		if (all == FALSE)
986e4e21ee1SDavid van Moolenbroek 			put_field(proc, NULL, "..");
987e4e21ee1SDavid van Moolenbroek 		put_close(proc, "}");
988e4e21ee1SDavid van Moolenbroek 	}
989e4e21ee1SDavid van Moolenbroek }
990e4e21ee1SDavid van Moolenbroek 
991e4e21ee1SDavid van Moolenbroek static int
mib_sysctl_out(struct trace_proc * proc,const message * m_out)992e4e21ee1SDavid van Moolenbroek mib_sysctl_out(struct trace_proc * proc, const message * m_out)
993e4e21ee1SDavid van Moolenbroek {
994e4e21ee1SDavid van Moolenbroek 	unsigned int namelen;
995e4e21ee1SDavid van Moolenbroek 
996e4e21ee1SDavid van Moolenbroek 	/* Reset the sysctl-related state. */
997e4e21ee1SDavid van Moolenbroek 	proc->sctl_flags = 0;
998e4e21ee1SDavid van Moolenbroek 	proc->sctl_size = 0;
999e4e21ee1SDavid van Moolenbroek 	proc->sctl_proc = NULL;
1000e4e21ee1SDavid van Moolenbroek 	proc->sctl_arg = 0;
1001e4e21ee1SDavid van Moolenbroek 
1002e4e21ee1SDavid van Moolenbroek 	namelen = m_out->m_lc_mib_sysctl.namelen;
1003e4e21ee1SDavid van Moolenbroek 
1004e4e21ee1SDavid van Moolenbroek 	/* As part of processing the name, we initialize the state. */
1005e4e21ee1SDavid van Moolenbroek 	if (namelen <= CTL_SHORTNAME)
1006e4e21ee1SDavid van Moolenbroek 		put_sysctl_name(proc, "name", PF_LOCADDR,
1007e4e21ee1SDavid van Moolenbroek 		    (vir_bytes)&m_out->m_lc_mib_sysctl.name, namelen);
1008e4e21ee1SDavid van Moolenbroek 	else
1009e4e21ee1SDavid van Moolenbroek 		put_sysctl_name(proc, "name", 0, m_out->m_lc_mib_sysctl.namep,
1010e4e21ee1SDavid van Moolenbroek 		    namelen);
1011e4e21ee1SDavid van Moolenbroek 
1012e4e21ee1SDavid van Moolenbroek 	put_value(proc, "namelen", "%u", namelen);
1013e4e21ee1SDavid van Moolenbroek 
1014e4e21ee1SDavid van Moolenbroek 	if (m_out->m_lc_mib_sysctl.oldp == 0 || valuesonly > 1) {
1015e4e21ee1SDavid van Moolenbroek 		put_sysctl_data(proc, "oldp", 0,
1016e4e21ee1SDavid van Moolenbroek 		    m_out->m_lc_mib_sysctl.oldp,
1017e4e21ee1SDavid van Moolenbroek 		    m_out->m_lc_mib_sysctl.oldlen);
1018e4e21ee1SDavid van Moolenbroek 		/* If oldp is NULL, oldlen may contain garbage; don't print. */
1019e4e21ee1SDavid van Moolenbroek 		if (m_out->m_lc_mib_sysctl.oldp != 0)
1020e4e21ee1SDavid van Moolenbroek 			put_value(proc, "oldlen", "%zu",    /* {%zu} is more */
1021e4e21ee1SDavid van Moolenbroek 			    m_out->m_lc_mib_sysctl.oldlen); /* correct..     */
1022e4e21ee1SDavid van Moolenbroek 		else
1023e4e21ee1SDavid van Moolenbroek 			put_value(proc, "oldlen", "%d", 0);
1024e4e21ee1SDavid van Moolenbroek 		put_sysctl_data(proc, "newp", PF_ALT,
1025e4e21ee1SDavid van Moolenbroek 		    m_out->m_lc_mib_sysctl.newp,
1026e4e21ee1SDavid van Moolenbroek 		    m_out->m_lc_mib_sysctl.newlen);
1027e4e21ee1SDavid van Moolenbroek 		put_value(proc, "newlen", "%zu",
1028e4e21ee1SDavid van Moolenbroek 		    m_out->m_lc_mib_sysctl.newlen);
1029e4e21ee1SDavid van Moolenbroek 		return CT_DONE;
1030e4e21ee1SDavid van Moolenbroek 	} else
1031e4e21ee1SDavid van Moolenbroek 		return CT_NOTDONE;
1032e4e21ee1SDavid van Moolenbroek }
1033e4e21ee1SDavid van Moolenbroek 
1034e4e21ee1SDavid van Moolenbroek static void
mib_sysctl_in(struct trace_proc * proc,const message * m_out,const message * m_in,int failed)1035e4e21ee1SDavid van Moolenbroek mib_sysctl_in(struct trace_proc * proc, const message * m_out,
1036e4e21ee1SDavid van Moolenbroek 	const message * m_in, int failed)
1037e4e21ee1SDavid van Moolenbroek {
1038e4e21ee1SDavid van Moolenbroek 	int err;
1039e4e21ee1SDavid van Moolenbroek 
1040e4e21ee1SDavid van Moolenbroek 	if (m_out->m_lc_mib_sysctl.oldp != 0 && valuesonly <= 1) {
1041e4e21ee1SDavid van Moolenbroek 		put_sysctl_data(proc, "oldp", failed,
1042e4e21ee1SDavid van Moolenbroek 		    m_out->m_lc_mib_sysctl.oldp,
1043e4e21ee1SDavid van Moolenbroek 		    m_in->m_mib_lc_sysctl.oldlen /* the returned length */);
1044e4e21ee1SDavid van Moolenbroek 		put_value(proc, "oldlen", "%zu", /* {%zu} is more correct.. */
1045e4e21ee1SDavid van Moolenbroek 		    m_out->m_lc_mib_sysctl.oldlen);
1046e4e21ee1SDavid van Moolenbroek 		put_sysctl_data(proc, "newp", PF_ALT,
1047e4e21ee1SDavid van Moolenbroek 		    m_out->m_lc_mib_sysctl.newp,
1048e4e21ee1SDavid van Moolenbroek 		    m_out->m_lc_mib_sysctl.newlen);
1049e4e21ee1SDavid van Moolenbroek 		put_value(proc, "newlen", "%zu",
1050e4e21ee1SDavid van Moolenbroek 		    m_out->m_lc_mib_sysctl.newlen);
1051e4e21ee1SDavid van Moolenbroek 		put_equals(proc);
1052e4e21ee1SDavid van Moolenbroek 	}
1053e4e21ee1SDavid van Moolenbroek 
1054e4e21ee1SDavid van Moolenbroek 	put_result(proc);
1055e4e21ee1SDavid van Moolenbroek 
1056e4e21ee1SDavid van Moolenbroek 	/*
1057e4e21ee1SDavid van Moolenbroek 	 * We want to print the returned old length in the following cases:
1058e4e21ee1SDavid van Moolenbroek 	 * 1. the call succeeded, the old pointer was NULL, and no new data was
1059e4e21ee1SDavid van Moolenbroek 	 *    supplied;
1060e4e21ee1SDavid van Moolenbroek 	 * 2. the call succeeded, the old pointer was not NULL, and the
1061e4e21ee1SDavid van Moolenbroek 	 *    returned old length is different from the supplied old length.
1062e4e21ee1SDavid van Moolenbroek 	 * 3. the call failed with ENOMEM or EEXIST, and the old pointer was
1063e4e21ee1SDavid van Moolenbroek 	 *    not NULL (an undocumented NetBSD feature, used by sysctl(8)).
1064e4e21ee1SDavid van Moolenbroek 	 */
1065e4e21ee1SDavid van Moolenbroek 	if (/*#1*/ (!failed && m_out->m_lc_mib_sysctl.oldp == 0 &&
1066e4e21ee1SDavid van Moolenbroek 	    (m_out->m_lc_mib_sysctl.newp == 0 ||
1067e4e21ee1SDavid van Moolenbroek 	    m_out->m_lc_mib_sysctl.newlen == 0)) ||
1068e4e21ee1SDavid van Moolenbroek 	    /*#2*/ (!failed && m_out->m_lc_mib_sysctl.oldp != 0 &&
1069e4e21ee1SDavid van Moolenbroek 	    m_out->m_lc_mib_sysctl.oldlen != m_in->m_mib_lc_sysctl.oldlen) ||
1070e4e21ee1SDavid van Moolenbroek 	    /*#3*/ (failed && call_errno(proc, &err) &&
1071e4e21ee1SDavid van Moolenbroek 	    (err == ENOMEM || err == EEXIST) &&
1072e4e21ee1SDavid van Moolenbroek 	    m_out->m_lc_mib_sysctl.oldp != 0)) {
1073e4e21ee1SDavid van Moolenbroek 		put_open(proc, NULL, 0, "(", ", ");
1074e4e21ee1SDavid van Moolenbroek 		put_value(proc, "oldlen", "%zu", m_in->m_mib_lc_sysctl.oldlen);
1075e4e21ee1SDavid van Moolenbroek 		put_close(proc, ")");
1076e4e21ee1SDavid van Moolenbroek 	}
1077e4e21ee1SDavid van Moolenbroek }
1078e4e21ee1SDavid van Moolenbroek 
1079e4e21ee1SDavid van Moolenbroek #define MIB_CALL(c) [((MIB_ ## c) - MIB_BASE)]
1080e4e21ee1SDavid van Moolenbroek 
1081e4e21ee1SDavid van Moolenbroek static const struct call_handler mib_map[] = {
1082e4e21ee1SDavid van Moolenbroek 	MIB_CALL(SYSCTL) = HANDLER("sysctl", mib_sysctl_out, mib_sysctl_in),
1083e4e21ee1SDavid van Moolenbroek };
1084e4e21ee1SDavid van Moolenbroek 
1085e4e21ee1SDavid van Moolenbroek const struct calls mib_calls = {
1086e4e21ee1SDavid van Moolenbroek 	.endpt = MIB_PROC_NR,
1087e4e21ee1SDavid van Moolenbroek 	.base = MIB_BASE,
1088e4e21ee1SDavid van Moolenbroek 	.map = mib_map,
1089e4e21ee1SDavid van Moolenbroek 	.count = COUNT(mib_map)
1090e4e21ee1SDavid van Moolenbroek };
1091