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