sysctl.c revision 1.39
1/*	$OpenBSD: sysctl.c,v 1.39 1999/04/11 19:41:41 niklas Exp $	*/
2/*	$NetBSD: sysctl.c,v 1.9 1995/09/30 07:12:50 thorpej Exp $	*/
3
4/*
5 * Copyright (c) 1993
6 *	The Regents of the University of California.  All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 *    must display the following acknowledgement:
18 *	This product includes software developed by the University of
19 *	California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 *    may be used to endorse or promote products derived from this software
22 *    without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37#ifndef lint
38static char copyright[] =
39"@(#) Copyright (c) 1993\n\
40	The Regents of the University of California.  All rights reserved.\n";
41#endif /* not lint */
42
43#ifndef lint
44#if 0
45static char sccsid[] = "@(#)sysctl.c	8.5 (Berkeley) 5/9/95";
46#else
47static char *rcsid = "$OpenBSD: sysctl.c,v 1.39 1999/04/11 19:41:41 niklas Exp $";
48#endif
49#endif /* not lint */
50
51#include <sys/param.h>
52#include <sys/gmon.h>
53#include <sys/mount.h>
54#include <sys/stat.h>
55#include <sys/sysctl.h>
56#include <sys/socket.h>
57#include <vm/vm_param.h>
58#include <machine/cpu.h>
59#include <net/route.h>
60
61#include <netinet/in.h>
62#include <netinet/in_systm.h>
63#include <netinet/ip.h>
64#include <netinet/in_pcb.h>
65#include <netinet/ip_icmp.h>
66#include <netinet/ip_ip4.h>
67#include <netinet/ip_ah.h>
68#include <netinet/ip_esp.h>
69#include <netinet/icmp_var.h>
70#include <netinet/ip_var.h>
71#include <netinet/udp.h>
72#include <netinet/udp_var.h>
73#include <netinet/tcp.h>
74#include <netinet/tcp_timer.h>
75#include <netinet/tcp_var.h>
76
77#include <netipx/ipx.h>
78#include <netipx/ipx_var.h>
79#include <netipx/spx_var.h>
80#include <ddb/db_var.h>
81#include <dev/rndvar.h>
82
83#include <err.h>
84#include <errno.h>
85#include <stdio.h>
86#include <stdlib.h>
87#include <string.h>
88#include <ctype.h>
89
90#ifdef CPU_BIOS
91#include <machine/biosvar.h>
92#endif
93
94struct ctlname topname[] = CTL_NAMES;
95struct ctlname kernname[] = CTL_KERN_NAMES;
96struct ctlname vmname[] = CTL_VM_NAMES;
97struct ctlname fsname[] = CTL_FS_NAMES;
98struct ctlname netname[] = CTL_NET_NAMES;
99struct ctlname hwname[] = CTL_HW_NAMES;
100struct ctlname username[] = CTL_USER_NAMES;
101struct ctlname debugname[CTL_DEBUG_MAXID];
102struct ctlname *vfsname;
103#ifdef CTL_MACHDEP_NAMES
104struct ctlname machdepname[] = CTL_MACHDEP_NAMES;
105#endif
106struct ctlname ddbname[] = CTL_DDB_NAMES;
107char names[BUFSIZ];
108int lastused;
109
110struct list {
111	struct	ctlname *list;
112	int	size;
113};
114struct list toplist = { topname, CTL_MAXID };
115struct list secondlevel[] = {
116	{ 0, 0 },			/* CTL_UNSPEC */
117	{ kernname, KERN_MAXID },	/* CTL_KERN */
118	{ vmname, VM_MAXID },		/* CTL_VM */
119	{ fsname, FS_MAXID },		/* CTL_FS */
120	{ netname, NET_MAXID },		/* CTL_NET */
121	{ 0, CTL_DEBUG_MAXID },		/* CTL_DEBUG */
122	{ hwname, HW_MAXID },		/* CTL_HW */
123#ifdef CTL_MACHDEP_NAMES
124	{ machdepname, CPU_MAXID },	/* CTL_MACHDEP */
125#else
126	{ 0, 0 },			/* CTL_MACHDEP */
127#endif
128	{ username, USER_MAXID },	/* CTL_USER_NAMES */
129	{ ddbname, DBCTL_MAXID },	/* CTL_DDB_NAMES */
130	{ 0, 0 },			/* CTL_VFS */
131};
132
133int	Aflag, aflag, nflag, wflag;
134
135/*
136 * Variables requiring special processing.
137 */
138#define	CLOCK		0x00000001
139#define	BOOTTIME	0x00000002
140#define	CHRDEV		0x00000004
141#define	BLKDEV		0x00000008
142#define RNDSTATS	0x00000010
143#define BADDYNAMIC	0x00000020
144#define BIOSGEO		0x00000040
145#define BIOSDEV		0x00000080
146#define	MAJ2DEV		0x00000100
147
148/* prototypes */
149void debuginit __P((void));
150void listall __P((char *, struct list *));
151void parse __P((char *, int));
152void parse_baddynamic __P((int *, size_t, char *, void **, size_t *, int, int));
153void usage __P((void));
154int findname __P((char *, char *, char **, struct list *));
155int sysctl_inet __P((char *, char **, int *, int, int *));
156int sysctl_ipx __P((char *, char **, int *, int, int *));
157int sysctl_fs __P((char *, char **, int *, int, int *));
158int sysctl_bios __P((char *, char **, int *, int, int *));
159void vfsinit __P((void));
160
161int
162main(argc, argv)
163	int argc;
164	char *argv[];
165{
166	int ch, lvl1;
167
168	while ((ch = getopt(argc, argv, "Aanw")) != -1) {
169		switch (ch) {
170
171		case 'A':
172			Aflag = 1;
173			break;
174
175		case 'a':
176			aflag = 1;
177			break;
178
179		case 'n':
180			nflag = 1;
181			break;
182
183		case 'w':
184			wflag = 1;
185			break;
186
187		default:
188			usage();
189		}
190	}
191	argc -= optind;
192	argv += optind;
193
194	if (argc == 0 && (Aflag || aflag)) {
195		debuginit();
196		vfsinit();
197		for (lvl1 = 1; lvl1 < CTL_MAXID; lvl1++)
198			listall(topname[lvl1].ctl_name, &secondlevel[lvl1]);
199		exit(0);
200	}
201	if (argc == 0)
202		usage();
203	for (; *argv != NULL; ++argv)
204		parse(*argv, 1);
205	exit(0);
206}
207
208/*
209 * List all variables known to the system.
210 */
211void
212listall(prefix, lp)
213	char *prefix;
214	struct list *lp;
215{
216	int lvl2;
217	char *cp, name[BUFSIZ];
218
219	if (lp->list == NULL)
220		return;
221	(void)strncpy(name, prefix, BUFSIZ-1);
222	name[BUFSIZ-1] = '\0';
223	cp = &name[strlen(name)];
224	*cp++ = '.';
225	for (lvl2 = 0; lvl2 < lp->size; lvl2++) {
226		if (lp->list[lvl2].ctl_name == NULL)
227			continue;
228		(void)strcpy(cp, lp->list[lvl2].ctl_name);
229		parse(name, Aflag);
230	}
231}
232
233/*
234 * Parse a name into a MIB entry.
235 * Lookup and print out the MIB entry if it exists.
236 * Set a new value if requested.
237 */
238void
239parse(string, flags)
240	char *string;
241	int flags;
242{
243	int indx, type, state, intval;
244	size_t size, len,  newsize = 0;
245	int special = 0;
246	void *newval = 0;
247	quad_t quadval;
248	struct list *lp;
249	struct vfsconf vfc;
250	int mib[CTL_MAXNAME];
251	char *cp, *bufp, buf[BUFSIZ];
252
253	(void)strncpy(buf, string, sizeof(buf) - 1);
254	buf[sizeof(buf) - 1] = '\0';
255	bufp = buf;
256	if ((cp = strchr(string, '=')) != NULL) {
257		if (!wflag)
258			errx(2, "must specify -w to set variables");
259		*strchr(buf, '=') = '\0';
260		*cp++ = '\0';
261		while (isspace(*cp))
262			cp++;
263		newval = cp;
264		newsize = strlen(cp);
265	}
266	if ((indx = findname(string, "top", &bufp, &toplist)) == -1)
267		return;
268	mib[0] = indx;
269	if (indx == CTL_VFS)
270		vfsinit();
271	if (indx == CTL_DEBUG)
272		debuginit();
273	lp = &secondlevel[indx];
274	if (lp->list == 0) {
275		warnx("%s: class is not implemented", topname[indx].ctl_name);
276		return;
277	}
278	if (bufp == NULL) {
279		listall(topname[indx].ctl_name, lp);
280		return;
281	}
282	if ((indx = findname(string, "second", &bufp, lp)) == -1)
283		return;
284	mib[1] = indx;
285	type = lp->list[indx].ctl_type;
286	len = 2;
287	switch (mib[0]) {
288
289	case CTL_KERN:
290		switch (mib[1]) {
291		case KERN_PROF:
292			mib[2] = GPROF_STATE;
293			size = sizeof(state);
294			if (sysctl(mib, 3, &state, &size, NULL, 0) == -1) {
295				if (flags == 0)
296					return;
297				if (!nflag)
298					(void)printf("%s: ", string);
299				(void)puts("kernel is not compiled for profiling");
300				return;
301			}
302			if (!nflag)
303				(void)printf("%s = %s\n", string,
304				    state == GMON_PROF_OFF ? "off" : "running");
305			return;
306		case KERN_VNODE:
307		case KERN_FILE:
308			if (flags == 0)
309				return;
310			warnx("use pstat to view %s information", string);
311			return;
312		case KERN_PROC:
313			if (flags == 0)
314				return;
315			warnx("use ps to view %s information", string);
316			return;
317		case KERN_NTPTIME:
318			if (flags == 0)
319				return;
320			warnx("use xntpdc to view %s information", string);
321			return;
322		case KERN_CLOCKRATE:
323			special |= CLOCK;
324			break;
325		case KERN_BOOTTIME:
326			special |= BOOTTIME;
327			break;
328		case KERN_RND:
329			special |= RNDSTATS;
330			break;
331		}
332		break;
333
334	case CTL_HW:
335		break;
336
337	case CTL_VM:
338		if (mib[1] == VM_LOADAVG) {
339			double loads[3];
340
341			getloadavg(loads, 3);
342			if (!nflag)
343				(void)printf("%s = ", string);
344			(void)printf("%.2f %.2f %.2f\n", loads[0],
345			    loads[1], loads[2]);
346			return;
347		} else if (mib[1] == VM_PSSTRINGS) {
348			struct _ps_strings _ps;
349
350			len = sizeof(_ps);
351			if (sysctl(mib, 2, &_ps, &len, NULL, 0) == -1) {
352				if (flags == 0)
353					return;
354				if (!nflag)
355					(void)printf("%s: ", string);
356				(void)puts("can't find ps strings");
357				return;
358			}
359			if (!nflag)
360				(void)printf("%s = ", string);
361			(void)printf("%p\n", _ps.val);
362			return;
363		}
364		if (flags == 0)
365			return;
366		warnx("use vmstat or systat to view %s information", string);
367		return;
368
369	case CTL_NET:
370		if (mib[1] == PF_INET) {
371			len = sysctl_inet(string, &bufp, mib, flags, &type);
372			if (len < 0)
373				return;
374
375			if ((mib[2] == IPPROTO_TCP &&
376			     mib[3] == TCPCTL_BADDYNAMIC) ||
377			    (mib[2] == IPPROTO_UDP &&
378			     mib[3] == UDPCTL_BADDYNAMIC)) {
379
380				special |= BADDYNAMIC;
381
382				if (newval != NULL)
383					parse_baddynamic(mib, len, string,
384					    &newval, &newsize, flags, nflag);
385			}
386			break;
387		}
388		if (mib[1] == PF_IPX) {
389			len = sysctl_ipx(string, &bufp, mib, flags, &type);
390			if (len >= 0)
391				break;
392			return;
393		}
394		if (flags == 0)
395			return;
396		warnx("use netstat to view %s information", string);
397		return;
398
399	case CTL_DEBUG:
400		mib[2] = CTL_DEBUG_VALUE;
401		len = 3;
402		break;
403
404	case CTL_MACHDEP:
405#ifdef CPU_CONSDEV
406		if (mib[1] == CPU_CONSDEV)
407			special |= CHRDEV;
408#endif
409#ifdef CPU_BLK2CHR
410		if (mib[1] == CPU_BLK2CHR) {
411			if (bufp == NULL)
412				return;
413			mib[2] = makedev(atoi(bufp),0);
414			bufp = NULL;
415			len = 3;
416			special |= CHRDEV;
417			break;
418		}
419#endif
420#ifdef CPU_CHR2BLK
421		if (mib[1] == CPU_CHR2BLK) {
422			if (bufp == NULL)
423				return;
424			mib[2] = makedev(atoi(bufp),0);
425			bufp = NULL;
426			len = 3;
427			special |= BLKDEV;
428			break;
429		}
430#endif
431#ifdef CPU_BIOS
432		if (mib[1] == CPU_BIOS) {
433			len = sysctl_bios(string, &bufp, mib, flags, &type);
434			if (len < 0)
435				return;
436			if (mib[2] == BIOS_DEV)
437				special |= BIOSDEV;
438			if (mib[2] == BIOS_DISKINFO)
439				special |= BIOSGEO;
440			break;
441		}
442#endif
443		break;
444
445	case CTL_FS:
446		len = sysctl_fs(string, &bufp, mib, flags, &type);
447		if (len >= 0)
448			break;
449		return;
450
451	case CTL_VFS:
452		mib[3] = mib[1];
453		mib[1] = VFS_GENERIC;
454		mib[2] = VFS_CONF;
455		len = 4;
456		size = sizeof vfc;
457		if (sysctl(mib, 4, &vfc, &size, (void *)0, (size_t)0) < 0) {
458			if (errno != EOPNOTSUPP)
459				perror("vfs print");
460			return;
461		}
462		if (flags == 0 && vfc.vfc_refcount == 0)
463			return;
464		if (!nflag)
465			fprintf(stdout, "%s has %d mounted instance%s\n",
466			    string, vfc.vfc_refcount,
467			    vfc.vfc_refcount != 1 ? "s" : "");
468		else
469			fprintf(stdout, "%d\n", vfc.vfc_refcount);
470		return;
471
472	case CTL_USER:
473	case CTL_DDB:
474		break;
475
476	default:
477		warnx("illegal top level value: %d", mib[0]);
478		return;
479
480	}
481	if (bufp) {
482		warnx("name %s in %s is unknown", bufp, string);
483		return;
484	}
485	if (newsize > 0) {
486		switch (type) {
487		case CTLTYPE_INT:
488			intval = atoi(newval);
489			newval = &intval;
490			newsize = sizeof(intval);
491			break;
492
493		case CTLTYPE_QUAD:
494			(void)sscanf(newval, "%qd", &quadval);
495			newval = &quadval;
496			newsize = sizeof(quadval);
497			break;
498		}
499	}
500	size = BUFSIZ;
501	if (sysctl(mib, len, buf, &size, newsize ? newval : 0, newsize) == -1) {
502		if (flags == 0)
503			return;
504		switch (errno) {
505		case EOPNOTSUPP:
506			warnx("%s: value is not available", string);
507			return;
508		case ENOTDIR:
509			warnx("%s: specification is incomplete", string);
510			return;
511		case ENOMEM:
512			warnx("%s: type is unknown to this program", string);
513			return;
514		case ENXIO:
515			if (special & BIOSGEO)
516				return;
517		default:
518			warn(string);
519			return;
520		}
521	}
522	if (special & CLOCK) {
523		struct clockinfo *clkp = (struct clockinfo *)buf;
524
525		if (!nflag)
526			(void)printf("%s = ", string);
527		(void)printf(
528		    "tick = %d, tickadj = %d, hz = %d, profhz = %d, stathz = %d\n",
529		    clkp->tick, clkp->tickadj, clkp->hz, clkp->profhz, clkp->stathz);
530		return;
531	}
532	if (special & BOOTTIME) {
533		struct timeval *btp = (struct timeval *)buf;
534		time_t boottime;
535
536		if (!nflag) {
537			boottime = btp->tv_sec;
538			(void)printf("%s = %s", string, ctime(&boottime));
539		} else
540			(void)printf("%ld\n", btp->tv_sec);
541		return;
542	}
543	if (special & BLKDEV) {
544		dev_t dev = *(dev_t *)buf;
545
546		if (!nflag)
547			(void)printf("%s = %s\n", string,
548			    devname(dev, S_IFBLK));
549		else
550			(void)printf("0x%x\n", dev);
551		return;
552	}
553	if (special & CHRDEV) {
554		dev_t dev = *(dev_t *)buf;
555
556		if (!nflag)
557			(void)printf("%s = %s\n", string,
558			    devname(dev, S_IFCHR));
559		else
560			(void)printf("0x%x\n", dev);
561		return;
562	}
563#ifdef CPU_BIOS
564	if (special & BIOSGEO) {
565		bios_diskinfo_t *pdi = (bios_diskinfo_t *)buf;
566
567		if (!nflag)
568			(void)printf("%s = ", string);
569		(void)printf("bootdev = 0x%x, "
570			     "cylinders = %u, heads = %u, sectors = %u\n",
571			     pdi->bsd_dev, pdi->bios_cylinders, pdi->bios_heads,
572			     pdi->bios_sectors);
573		return;
574	}
575	if (special & BIOSDEV) {
576		int dev = *(int*)buf;
577
578		if (!nflag)
579			(void)printf("%s = ", string);
580		(void) printf("0x%02x\n", dev);
581		return;
582	}
583#endif
584	if (special & RNDSTATS) {
585		struct rndstats *rndstats = (struct rndstats *)buf;
586
587		if (!nflag)
588			(void)printf("%s = ", string);
589		(void)printf(
590		    "%u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u\n",
591		    rndstats->rnd_total, rndstats->rnd_used,
592		    rndstats->arc4_reads, rndstats->rnd_timer,
593		    rndstats->rnd_mouse, rndstats->rnd_tty,
594		    rndstats->rnd_disk, rndstats->rnd_net,
595		    rndstats->rnd_reads, rndstats->rnd_waits,
596		    rndstats->rnd_enqs, rndstats->rnd_deqs,
597		    rndstats->rnd_drops, rndstats->rnd_drople,
598		    rndstats->rnd_asleep, rndstats->rnd_queued);
599		return;
600	}
601	if (special & BADDYNAMIC) {
602		in_port_t port, lastport;
603		u_int32_t *baddynamic = (u_int32_t *)buf;
604
605		if (!nflag)
606			(void)printf("%s%s", string, newsize ? ": " : " = ");
607		lastport = 0;
608		for (port = IPPORT_RESERVED/2; port < IPPORT_RESERVED; port++)
609			if (DP_ISSET(baddynamic, port)) {
610				(void)printf("%s%hd", lastport ? "," : "",
611				    port);
612				lastport = port;
613			}
614		if (newsize != 0) {
615			if (!nflag)
616				fputs(" -> ", stdout);
617			baddynamic = (u_int32_t *)newval;
618			lastport = 0;
619			for (port = IPPORT_RESERVED/2; port < IPPORT_RESERVED;
620			    port++)
621				if (DP_ISSET(baddynamic, port)) {
622					(void)printf("%s%hd",
623					    lastport ? "," : "", port);
624					lastport = port;
625				}
626		}
627		(void)putchar('\n');
628		return;
629	}
630	switch (type) {
631	case CTLTYPE_INT:
632		if (newsize == 0) {
633			if (!nflag)
634				(void)printf("%s = ", string);
635			(void)printf("%d\n", *(int *)buf);
636		} else {
637			if (!nflag)
638				(void)printf("%s: %d -> ", string,
639				    *(int *)buf);
640			(void)printf("%d\n", *(int *)newval);
641		}
642		return;
643
644	case CTLTYPE_STRING:
645		if (newsize == 0) {
646			if (!nflag)
647				(void)printf("%s = ", string);
648			(void)puts(buf);
649		} else {
650			if (!nflag)
651				(void)printf("%s: %s -> ", string, buf);
652			(void)puts((char *)newval);
653		}
654		return;
655
656	case CTLTYPE_QUAD:
657		if (newsize == 0) {
658			if (!nflag)
659				(void)printf("%s = ", string);
660			(void)printf("%qd\n", *(quad_t *)buf);
661		} else {
662			if (!nflag)
663				(void)printf("%s: %qd -> ", string,
664				    *(quad_t *)buf);
665			(void)printf("%qd\n", *(quad_t *)newval);
666		}
667		return;
668
669	case CTLTYPE_STRUCT:
670		warnx("%s: unknown structure returned", string);
671		return;
672
673	default:
674	case CTLTYPE_NODE:
675		warnx("%s: unknown type returned", string);
676		return;
677	}
678}
679
680void
681parse_baddynamic(mib, len, string, newvalp, newsizep, flags, nflag)
682	int mib[];
683	size_t len;
684	char *string;
685	void **newvalp;
686	size_t *newsizep;
687	int flags;
688	int nflag;
689{
690	static u_int32_t newbaddynamic[DP_MAPSIZE];
691	in_port_t port;
692	size_t size;
693	char action, *cp;
694
695	if (strchr((char *)*newvalp, '+') || strchr((char *)*newvalp, '-')) {
696		size = sizeof(newbaddynamic);
697		if (sysctl(mib, len, newbaddynamic, &size, 0, 0) == -1) {
698			if (flags == 0)
699				return;
700			if (!nflag)
701				(void)printf("%s: ", string);
702			(void)puts("kernel does contain bad dynamic port tables");
703			return;
704		}
705
706		while (*newvalp && (cp = strsep((char **)newvalp, ", \t")) && *cp) {
707			if (*cp != '+' && *cp != '-')
708				errx(1, "cannot mix +/- with full list");
709			action = *cp++;
710			port = atoi(cp);
711			if (port < IPPORT_RESERVED/2 || port >= IPPORT_RESERVED)
712				errx(1, "invalid port, range is %d to %d",
713				    IPPORT_RESERVED/2, IPPORT_RESERVED-1);
714			if (action == '+')
715				DP_SET(newbaddynamic, port);
716			else
717				DP_CLR(newbaddynamic, port);
718		}
719	} else {
720		(void)memset((void *)newbaddynamic, 0, sizeof(newbaddynamic));
721		while (*newvalp && (cp = strsep((char **)newvalp, ", \t")) && *cp) {
722			port = atoi(cp);
723			if (port < IPPORT_RESERVED/2 || port >= IPPORT_RESERVED)
724				errx(1, "invalid port, range is %d to %d",
725				    IPPORT_RESERVED/2, IPPORT_RESERVED-1);
726			DP_SET(newbaddynamic, port);
727		}
728	}
729
730	*newvalp = (void *)newbaddynamic;
731	*newsizep = sizeof(newbaddynamic);
732}
733
734/*
735 * Initialize the set of debugging names
736 */
737void
738debuginit()
739{
740	int mib[3], loc, i;
741	size_t size;
742
743	if (secondlevel[CTL_DEBUG].list != 0)
744		return;
745	secondlevel[CTL_DEBUG].list = debugname;
746	mib[0] = CTL_DEBUG;
747	mib[2] = CTL_DEBUG_NAME;
748	for (loc = lastused, i = 0; i < CTL_DEBUG_MAXID; i++) {
749		mib[1] = i;
750		size = BUFSIZ - loc;
751		if (sysctl(mib, 3, &names[loc], &size, NULL, 0) == -1)
752			continue;
753		debugname[i].ctl_name = &names[loc];
754		debugname[i].ctl_type = CTLTYPE_INT;
755		loc += size;
756	}
757	lastused = loc;
758}
759
760/*
761 * Initialize the set of filesystem names
762 */
763void
764vfsinit()
765{
766	int mib[4], maxtypenum, cnt, loc, size;
767	struct vfsconf vfc;
768	size_t buflen;
769
770	if (secondlevel[CTL_VFS].list != 0)
771		return;
772	mib[0] = CTL_VFS;
773	mib[1] = VFS_GENERIC;
774	mib[2] = VFS_MAXTYPENUM;
775	buflen = 4;
776	if (sysctl(mib, 3, &maxtypenum, &buflen, (void *)0, (size_t)0) < 0)
777		return;
778	if ((vfsname = malloc(maxtypenum * sizeof(*vfsname))) == 0)
779		return;
780	memset(vfsname, 0, maxtypenum * sizeof(*vfsname));
781	mib[2] = VFS_CONF;
782	buflen = sizeof vfc;
783	for (loc = lastused, cnt = 0; cnt < maxtypenum; cnt++) {
784		mib[3] = cnt;
785		if (sysctl(mib, 4, &vfc, &buflen, (void *)0, (size_t)0) < 0) {
786			if (errno == EOPNOTSUPP)
787				continue;
788			perror("vfsinit");
789			free(vfsname);
790			return;
791		}
792		strcat(&names[loc], vfc.vfc_name);
793		vfsname[cnt].ctl_name = &names[loc];
794		vfsname[cnt].ctl_type = CTLTYPE_INT;
795		size = strlen(vfc.vfc_name) + 1;
796		loc += size;
797	}
798	lastused = loc;
799	secondlevel[CTL_VFS].list = vfsname;
800	secondlevel[CTL_VFS].size = maxtypenum;
801	return;
802}
803
804struct ctlname posixname[] = CTL_FS_POSIX_NAMES;
805struct list fslist = { posixname, FS_POSIX_MAXID };
806
807/*
808 * handle file system requests
809 */
810int
811sysctl_fs(string, bufpp, mib, flags, typep)
812	char *string;
813	char **bufpp;
814	int mib[];
815	int flags;
816	int *typep;
817{
818	int indx;
819
820	if (*bufpp == NULL) {
821		listall(string, &fslist);
822		return(-1);
823	}
824	if ((indx = findname(string, "third", bufpp, &fslist)) == -1)
825		return(-1);
826	mib[2] = indx;
827	*typep = fslist.list[indx].ctl_type;
828	return(3);
829}
830
831#ifdef CPU_BIOS
832struct ctlname biosname[] = CTL_BIOS_NAMES;
833struct list bioslist = { biosname, BIOS_MAXID };
834
835/*
836 * handle BIOS requests
837 */
838int
839sysctl_bios(string, bufpp, mib, flags, typep)
840	char *string;
841	char **bufpp;
842	int mib[];
843	int flags;
844	int *typep;
845{
846	char *name;
847	int indx;
848
849	if (*bufpp == NULL) {
850		listall(string, &bioslist);
851		return(-1);
852	}
853	if ((indx = findname(string, "third", bufpp, &bioslist)) == -1)
854		return(-1);
855	mib[2] = indx;
856	if (indx == BIOS_DISKINFO) {
857		if (*bufpp == NULL) {
858			char name[BUFSIZ];
859
860			/* scan all the bios devices */
861			for (indx = 0; indx < 256; indx++) {
862				snprintf(name, sizeof(name), "%s.%u",
863					 string, indx);
864				parse(name, 1);
865			}
866			return(-1);
867		}
868		if ((name = strsep(bufpp, ".")) == NULL) {
869			warnx("%s: incomplete specification", string);
870			return(-1);
871		}
872		mib[3] = atoi(name);
873		*typep = CTLTYPE_STRUCT;
874		return 4;
875	} else {
876		*typep = bioslist.list[indx].ctl_type;
877		return(3);
878	}
879}
880#endif
881
882struct ctlname inetname[] = CTL_IPPROTO_NAMES;
883struct ctlname ipname[] = IPCTL_NAMES;
884struct ctlname icmpname[] = ICMPCTL_NAMES;
885struct ctlname ip4name[] = IP4CTL_NAMES;
886struct ctlname tcpname[] = TCPCTL_NAMES;
887struct ctlname udpname[] = UDPCTL_NAMES;
888struct ctlname espname[] = ESPCTL_NAMES;
889struct ctlname ahname[] = AHCTL_NAMES;
890struct list inetlist = { inetname, IPPROTO_MAXID };
891struct list inetvars[] = {
892	{ ipname, IPCTL_MAXID },	/* ip */
893	{ icmpname, ICMPCTL_MAXID },	/* icmp */
894	{ 0, 0 },			/* igmp */
895	{ 0, 0 },			/* ggmp */
896	{ ip4name, IP4CTL_MAXID },	/* ipencap */
897	{ 0, 0 },
898	{ tcpname, TCPCTL_MAXID },	/* tcp */
899	{ 0, 0 },
900	{ 0, 0 },			/* egp */
901	{ 0, 0 },
902	{ 0, 0 },
903	{ 0, 0 },
904	{ 0, 0 },			/* pup */
905	{ 0, 0 },
906	{ 0, 0 },
907	{ 0, 0 },
908	{ 0, 0 },
909	{ udpname, UDPCTL_MAXID },	/* udp */
910	{ 0, 0 },
911	{ 0, 0 },
912	{ 0, 0 },
913	{ 0, 0 },
914	{ 0, 0 },
915	{ 0, 0 },
916	{ 0, 0 },
917	{ 0, 0 },
918	{ 0, 0 },
919	{ 0, 0 },
920	{ 0, 0 },
921	{ 0, 0 },
922	{ 0, 0 },
923	{ 0, 0 },
924	{ 0, 0 },
925	{ 0, 0 },
926	{ 0, 0 },
927	{ 0, 0 },
928	{ 0, 0 },
929	{ 0, 0 },
930	{ 0, 0 },
931	{ 0, 0 },
932	{ 0, 0 },
933	{ 0, 0 },
934	{ 0, 0 },
935	{ 0, 0 },
936	{ 0, 0 },
937	{ 0, 0 },
938	{ 0, 0 },
939	{ 0, 0 },
940	{ 0, 0 },
941	{ 0, 0 },
942	{ espname, ESPCTL_MAXID },	/* esp */
943	{ ahname, AHCTL_MAXID },	/* ah */
944};
945
946/*
947 * handle internet requests
948 */
949int
950sysctl_inet(string, bufpp, mib, flags, typep)
951	char *string;
952	char **bufpp;
953	int mib[];
954	int flags;
955	int *typep;
956{
957	struct list *lp;
958	int indx;
959
960	if (*bufpp == NULL) {
961		listall(string, &inetlist);
962		return(-1);
963	}
964	if ((indx = findname(string, "third", bufpp, &inetlist)) == -1)
965		return(-1);
966	mib[2] = indx;
967	if (indx < IPPROTO_MAXID && inetvars[indx].list != NULL)
968		lp = &inetvars[indx];
969	else if (!flags)
970		return(-1);
971	else {
972		warnx("%s: no variables defined for this protocol", string);
973		return(-1);
974	}
975	if (*bufpp == NULL) {
976		listall(string, lp);
977		return(-1);
978	}
979	if ((indx = findname(string, "fourth", bufpp, lp)) == -1)
980		return(-1);
981	mib[3] = indx;
982	*typep = lp->list[indx].ctl_type;
983	return(4);
984}
985
986struct ctlname ipxname[] = CTL_IPXPROTO_NAMES;
987struct ctlname ipxpname[] = IPXCTL_NAMES;
988struct ctlname spxpname[] = SPXCTL_NAMES;
989struct list ipxlist = { ipxname, IPXCTL_MAXID };
990struct list ipxvars[] = {
991	{ ipxpname, IPXCTL_MAXID },	/* ipx */
992	{ 0, 0 },
993	{ 0, 0 },
994	{ 0, 0 },
995	{ 0, 0 },
996	{ spxpname, SPXCTL_MAXID },
997};
998
999/*
1000 * Handle internet requests
1001 */
1002int
1003sysctl_ipx(string, bufpp, mib, flags, typep)
1004	char *string;
1005	char **bufpp;
1006	int mib[];
1007	int flags;
1008	int *typep;
1009{
1010	struct list *lp;
1011	int indx;
1012
1013	if (*bufpp == NULL) {
1014		listall(string, &ipxlist);
1015		return(-1);
1016	}
1017	if ((indx = findname(string, "third", bufpp, &ipxlist)) == -1)
1018		return(-1);
1019	mib[2] = indx;
1020	if (indx <= IPXPROTO_SPX && ipxvars[indx].list != NULL)
1021		lp = &ipxvars[indx];
1022	else if (!flags)
1023		return(-1);
1024	else {
1025		warnx("%s: no variables defined for this protocol", string);
1026		return(-1);
1027	}
1028	if (*bufpp == NULL) {
1029		listall(string, lp);
1030		return(-1);
1031	}
1032	if ((indx = findname(string, "fourth", bufpp, lp)) == -1)
1033		return(-1);
1034	mib[3] = indx;
1035	*typep = lp->list[indx].ctl_type;
1036	return(4);
1037}
1038
1039/*
1040 * Scan a list of names searching for a particular name.
1041 */
1042int
1043findname(string, level, bufp, namelist)
1044	char *string;
1045	char *level;
1046	char **bufp;
1047	struct list *namelist;
1048{
1049	char *name;
1050	int i;
1051
1052	if (namelist->list == 0 || (name = strsep(bufp, ".")) == NULL) {
1053		warnx("%s: incomplete specification", string);
1054		return(-1);
1055	}
1056	for (i = 0; i < namelist->size; i++)
1057		if (namelist->list[i].ctl_name != NULL &&
1058		    strcmp(name, namelist->list[i].ctl_name) == 0)
1059			break;
1060	if (i == namelist->size) {
1061		warnx("%s level name %s in %s is invalid", level, name, string);
1062		return(-1);
1063	}
1064	return(i);
1065}
1066
1067void
1068usage()
1069{
1070
1071	(void)fprintf(stderr, "usage:\t%s\n\t%s\n\t%s\n\t%s\n",
1072	    "sysctl [-n] variable ...", "sysctl [-n] -w variable=value ...",
1073	    "sysctl [-n] -a", "sysctl [-n] -A");
1074	exit(1);
1075}
1076