11553Srgrimes/*
21553Srgrimes * Copyright (c) 1993
31553Srgrimes *	The Regents of the University of California.  All rights reserved.
41553Srgrimes *
51553Srgrimes * Redistribution and use in source and binary forms, with or without
61553Srgrimes * modification, are permitted provided that the following conditions
71553Srgrimes * are met:
81553Srgrimes * 1. Redistributions of source code must retain the above copyright
91553Srgrimes *    notice, this list of conditions and the following disclaimer.
101553Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111553Srgrimes *    notice, this list of conditions and the following disclaimer in the
121553Srgrimes *    documentation and/or other materials provided with the distribution.
131553Srgrimes * 4. Neither the name of the University nor the names of its contributors
141553Srgrimes *    may be used to endorse or promote products derived from this software
151553Srgrimes *    without specific prior written permission.
161553Srgrimes *
171553Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
181553Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
191553Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
201553Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
211553Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
221553Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
231553Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
241553Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
251553Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
261553Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
271553Srgrimes * SUCH DAMAGE.
281553Srgrimes */
291553Srgrimes
301553Srgrimes#ifndef lint
3130602Scharnierstatic const char copyright[] =
321553Srgrimes"@(#) Copyright (c) 1993\n\
331553Srgrimes	The Regents of the University of California.  All rights reserved.\n";
341553Srgrimes#endif /* not lint */
351553Srgrimes
361553Srgrimes#ifndef lint
3730602Scharnier#if 0
3830602Scharnierstatic char sccsid[] = "@(#)from: sysctl.c	8.1 (Berkeley) 6/6/93";
3930602Scharnier#endif
406284Swollmanstatic const char rcsid[] =
4150476Speter  "$FreeBSD$";
421553Srgrimes#endif /* not lint */
431553Srgrimes
4491217Sbde#include <sys/param.h>
4591217Sbde#include <sys/time.h>
4691217Sbde#include <sys/resource.h>
471553Srgrimes#include <sys/stat.h>
481553Srgrimes#include <sys/sysctl.h>
49109097Sdillon#include <sys/vmmeter.h>
501553Srgrimes
5130602Scharnier#include <ctype.h>
5230602Scharnier#include <err.h>
531553Srgrimes#include <errno.h>
54170287Sdwmalone#include <inttypes.h>
55122233Sdes#include <locale.h>
561553Srgrimes#include <stdio.h>
571553Srgrimes#include <stdlib.h>
581553Srgrimes#include <string.h>
59244198Sdelphij#include <sysexits.h>
6030602Scharnier#include <unistd.h>
611553Srgrimes
62244198Sdelphijstatic const char *conffile;
63244198Sdelphij
64203310Sgavinstatic int	aflag, bflag, dflag, eflag, hflag, iflag;
65244198Sdelphijstatic int	Nflag, nflag, oflag, qflag, Tflag, Wflag, xflag;
661553Srgrimes
6712946Sphkstatic int	oidfmt(int *, int, char *, u_int *);
68244198Sdelphijstatic int	parsefile(const char *);
69244198Sdelphijstatic int	parse(const char *, int);
7012946Sphkstatic int	show_var(int *, int);
71170512Sdwmalonestatic int	sysctl_all(int *oid, int len);
7212946Sphkstatic int	name2oid(char *, int *);
731553Srgrimes
74198340Sedstatic int	set_IK(const char *, int *);
7588696Sphk
7612946Sphkstatic void
7712946Sphkusage(void)
7812946Sphk{
791553Srgrimes
8077330Sdes	(void)fprintf(stderr, "%s\n%s\n",
81244198Sdelphij	    "usage: sysctl [-bdehiNnoqTWx] [-f filename] name[=value] ...",
82244106Salfred	    "       sysctl [-bdehNnoqTWx] -a");
8312946Sphk	exit(1);
8412946Sphk}
851553Srgrimes
861553Srgrimesint
8712946Sphkmain(int argc, char **argv)
881553Srgrimes{
8912946Sphk	int ch;
90244198Sdelphij	int warncount = 0;
91122233Sdes
92122233Sdes	setlocale(LC_NUMERIC, "");
9312946Sphk	setbuf(stdout,0);
9412946Sphk	setbuf(stderr,0);
951553Srgrimes
96244198Sdelphij	while ((ch = getopt(argc, argv, "Aabdef:hiNnoqTwWxX")) != -1) {
971553Srgrimes		switch (ch) {
9871034Sdes		case 'A':
9977330Sdes			/* compatibility */
10077330Sdes			aflag = oflag = 1;
10171034Sdes			break;
10271034Sdes		case 'a':
10371034Sdes			aflag = 1;
10471034Sdes			break;
10571034Sdes		case 'b':
10671034Sdes			bflag = 1;
10771034Sdes			break;
10888006Sluigi		case 'd':
10988006Sluigi			dflag = 1;
11088006Sluigi			break;
11185747Stobez		case 'e':
11285747Stobez			eflag = 1;
11385747Stobez			break;
114244198Sdelphij		case 'f':
115244198Sdelphij			conffile = optarg;
116244198Sdelphij			break;
117122233Sdes		case 'h':
118122233Sdes			hflag = 1;
119122233Sdes			break;
120203310Sgavin		case 'i':
121203310Sgavin			iflag = 1;
122203310Sgavin			break;
12371034Sdes		case 'N':
12471034Sdes			Nflag = 1;
12571034Sdes			break;
12671034Sdes		case 'n':
12771034Sdes			nflag = 1;
12871034Sdes			break;
12977330Sdes		case 'o':
13077330Sdes			oflag = 1;
13177330Sdes			break;
132150167Srwatson		case 'q':
133150167Srwatson			qflag = 1;
134150167Srwatson			break;
135244106Salfred		case 'T':
136244106Salfred			Tflag = 1;
137244106Salfred			break;
13871034Sdes		case 'w':
13977330Sdes			/* compatibility */
14077330Sdes			/* ignored */
14171034Sdes			break;
142244106Salfred		case 'W':
143244106Salfred			Wflag = 1;
144244106Salfred			break;
14571034Sdes		case 'X':
14677330Sdes			/* compatibility */
14777330Sdes			aflag = xflag = 1;
14871034Sdes			break;
14977330Sdes		case 'x':
15077330Sdes			xflag = 1;
15177330Sdes			break;
15271034Sdes		default:
15371034Sdes			usage();
1541553Srgrimes		}
1551553Srgrimes	}
1561553Srgrimes	argc -= optind;
1571553Srgrimes	argv += optind;
1581553Srgrimes
15977330Sdes	if (Nflag && nflag)
16042456Sdes		usage();
16177330Sdes	if (aflag && argc == 0)
16277330Sdes		exit(sysctl_all(0, 0));
163244198Sdelphij	if (argc == 0 && conffile == NULL)
1641553Srgrimes		usage();
165179965Smtm
166179965Smtm	warncount = 0;
167244198Sdelphij	if (conffile != NULL)
168244198Sdelphij		warncount += parsefile(conffile);
169244198Sdelphij
1701553Srgrimes	while (argc-- > 0)
171244198Sdelphij		warncount += parse(*argv++, 0);
172244198Sdelphij
173244198Sdelphij	return (warncount);
1741553Srgrimes}
1751553Srgrimes
1761553Srgrimes/*
1771553Srgrimes * Parse a name into a MIB entry.
1781553Srgrimes * Lookup and print out the MIB entry if it exists.
1791553Srgrimes * Set a new value if requested.
1801553Srgrimes */
181244198Sdelphijstatic int
182244198Sdelphijparse(const char *string, int lineno)
1831553Srgrimes{
18412946Sphk	int len, i, j;
1851553Srgrimes	void *newval = 0;
18678434Spirzyk	int intval;
18778434Spirzyk	unsigned int uintval;
18878434Spirzyk	long longval;
18978434Spirzyk	unsigned long ulongval;
19078434Spirzyk	size_t newsize = 0;
191217616Smdf	int64_t i64val;
192217616Smdf	uint64_t u64val;
1931553Srgrimes	int mib[CTL_MAXNAME];
194244198Sdelphij	char *cp, *bufp, buf[BUFSIZ], *endptr, fmt[BUFSIZ], line[BUFSIZ];
19512946Sphk	u_int kind;
1961553Srgrimes
197244198Sdelphij	if (lineno)
198244198Sdelphij		snprintf(line, sizeof(line), " at line %d", lineno);
199244198Sdelphij	else
200244198Sdelphij		line[0] = '\0';
201244198Sdelphij
202244104Sdelphij	cp = buf;
203244198Sdelphij	if (snprintf(buf, BUFSIZ, "%s", string) >= BUFSIZ) {
204260193Strasz		warnx("oid too long: '%s'%s", string, line);
205244198Sdelphij		return (1);
206244198Sdelphij	}
207244198Sdelphij	bufp = strsep(&cp, "=:");
208244104Sdelphij	if (cp != NULL) {
209244106Salfred		/* Tflag just lists tunables, do not allow assignment */
210244106Salfred		if (Tflag || Wflag) {
211244106Salfred			warnx("Can't set variables when using -T or -W");
212244106Salfred			usage();
213244106Salfred		}
2141553Srgrimes		while (isspace(*cp))
2151553Srgrimes			cp++;
216244198Sdelphij		/* Strip a pair of " or ' if any. */
217244198Sdelphij		switch (*cp) {
218244198Sdelphij		case '\"':
219244198Sdelphij		case '\'':
220244198Sdelphij			if (cp[strlen(cp) - 1] == *cp)
221244198Sdelphij				cp[strlen(cp) - 1] = '\0';
222244198Sdelphij			cp++;
223244198Sdelphij		}
2241553Srgrimes		newval = cp;
2251553Srgrimes		newsize = strlen(cp);
2261553Srgrimes	}
22712946Sphk	len = name2oid(bufp, mib);
2281553Srgrimes
229150167Srwatson	if (len < 0) {
230203310Sgavin		if (iflag)
231244198Sdelphij			return (0);
232150167Srwatson		if (qflag)
233244198Sdelphij			return (1);
234244198Sdelphij		else {
235244198Sdelphij			warn("unknown oid '%s'%s", bufp, line);
236244198Sdelphij			return (1);
237244198Sdelphij		}
238244198Sdelphij	}
239244198Sdelphij
240244198Sdelphij	if (oidfmt(mib, len, fmt, &kind)) {
241244198Sdelphij		warn("couldn't find format of oid '%s'%s", bufp, line);
242244198Sdelphij		if (iflag)
243244198Sdelphij			return (1);
244244198Sdelphij		else
245150167Srwatson			exit(1);
246150167Srwatson	}
2471553Srgrimes
248228181Sjhb	if (newval == NULL || dflag) {
24912946Sphk		if ((kind & CTLTYPE) == CTLTYPE_NODE) {
250144998Smdodd			if (dflag) {
251144998Smdodd				i = show_var(mib, len);
252144998Smdodd				if (!i && !bflag)
253144998Smdodd					putchar('\n');
254144998Smdodd			}
25512946Sphk			sysctl_all(mib, len);
25612946Sphk		} else {
25712946Sphk			i = show_var(mib, len);
25812946Sphk			if (!i && !bflag)
25912946Sphk				putchar('\n');
2601553Srgrimes		}
26112946Sphk	} else {
262244198Sdelphij		if ((kind & CTLTYPE) == CTLTYPE_NODE) {
263260193Strasz			warnx("oid '%s' isn't a leaf node%s", bufp, line);
264244198Sdelphij			return (1);
265244198Sdelphij		}
2661553Srgrimes
267121849Ssilby		if (!(kind & CTLFLAG_WR)) {
268121306Ssilby			if (kind & CTLFLAG_TUN) {
269245361Sdelphij				warnx("oid '%s' is a read only tunable%s", bufp, line);
270244198Sdelphij				warnx("Tunable values are set in /boot/loader.conf");
271244198Sdelphij			} else
272244198Sdelphij				warnx("oid '%s' is read only%s", bufp, line);
273244198Sdelphij			return (1);
274121306Ssilby		}
275116383Srwatson
276116383Srwatson		if ((kind & CTLTYPE) == CTLTYPE_INT ||
277116383Srwatson		    (kind & CTLTYPE) == CTLTYPE_UINT ||
278116383Srwatson		    (kind & CTLTYPE) == CTLTYPE_LONG ||
279126472Sdd		    (kind & CTLTYPE) == CTLTYPE_ULONG ||
280217616Smdf		    (kind & CTLTYPE) == CTLTYPE_S64 ||
281217616Smdf		    (kind & CTLTYPE) == CTLTYPE_U64) {
282244198Sdelphij			if (strlen(newval) == 0) {
283244198Sdelphij				warnx("empty numeric value");
284244198Sdelphij				return (1);
285244198Sdelphij			}
286116383Srwatson		}
287122234Sdes
28812946Sphk		switch (kind & CTLTYPE) {
28912946Sphk			case CTLTYPE_INT:
290161951Sume				if (strcmp(fmt, "IK") == 0) {
291244198Sdelphij					if (!set_IK(newval, &intval)) {
292244198Sdelphij						warnx("invalid value '%s'%s",
293244198Sdelphij						    (char *)newval, line);
294244198Sdelphij						return (1);
295244198Sdelphij					}
296161951Sume 				} else {
297161951Sume					intval = (int)strtol(newval, &endptr,
298161951Sume					    0);
299244198Sdelphij					if (endptr == newval || *endptr != '\0') {
300244198Sdelphij						warnx("invalid integer '%s'%s",
301244198Sdelphij						    (char *)newval, line);
302244198Sdelphij						return (1);
303244198Sdelphij					}
304161951Sume				}
30512946Sphk				newval = &intval;
30677928Sdd				newsize = sizeof(intval);
3071553Srgrimes				break;
30878434Spirzyk			case CTLTYPE_UINT:
309116383Srwatson				uintval = (int) strtoul(newval, &endptr, 0);
310244198Sdelphij				if (endptr == newval || *endptr != '\0') {
311244198Sdelphij					warnx("invalid unsigned integer '%s'%s",
312244198Sdelphij					    (char *)newval, line);
313244198Sdelphij					return (1);
314244198Sdelphij				}
31578434Spirzyk				newval = &uintval;
316170512Sdwmalone				newsize = sizeof(uintval);
31712946Sphk				break;
31878434Spirzyk			case CTLTYPE_LONG:
319116383Srwatson				longval = strtol(newval, &endptr, 0);
320244198Sdelphij				if (endptr == newval || *endptr != '\0') {
321244198Sdelphij					warnx("invalid long integer '%s'%s",
322244198Sdelphij					    (char *)newval, line);
323244198Sdelphij					return (1);
324244198Sdelphij				}
32578434Spirzyk				newval = &longval;
326170512Sdwmalone				newsize = sizeof(longval);
32778434Spirzyk				break;
32878434Spirzyk			case CTLTYPE_ULONG:
329116383Srwatson				ulongval = strtoul(newval, &endptr, 0);
330244198Sdelphij				if (endptr == newval || *endptr != '\0') {
331244198Sdelphij					warnx("invalid unsigned long integer"
332244198Sdelphij					    " '%s'%s", (char *)newval, line);
333244198Sdelphij					return (1);
334244198Sdelphij				}
33578434Spirzyk				newval = &ulongval;
336170512Sdwmalone				newsize = sizeof(ulongval);
33778434Spirzyk				break;
33812946Sphk			case CTLTYPE_STRING:
33912946Sphk				break;
340217616Smdf			case CTLTYPE_S64:
341217616Smdf				i64val = strtoimax(newval, &endptr, 0);
342244198Sdelphij				if (endptr == newval || *endptr != '\0') {
343244198Sdelphij					warnx("invalid int64_t '%s'%s",
344244198Sdelphij					    (char *)newval, line);
345244198Sdelphij					return (1);
346244198Sdelphij				}
347217616Smdf				newval = &i64val;
348217616Smdf				newsize = sizeof(i64val);
34912946Sphk				break;
350217616Smdf			case CTLTYPE_U64:
351217616Smdf				u64val = strtoumax(newval, &endptr, 0);
352244198Sdelphij				if (endptr == newval || *endptr != '\0') {
353244198Sdelphij					warnx("invalid uint64_t '%s'%s",
354244198Sdelphij					    (char *)newval, line);
355244198Sdelphij					return (1);
356244198Sdelphij				}
357217616Smdf				newval = &u64val;
358217616Smdf				newsize = sizeof(u64val);
359217616Smdf				break;
36088696Sphk			case CTLTYPE_OPAQUE:
36188696Sphk				/* FALLTHROUGH */
36212946Sphk			default:
363244198Sdelphij				warnx("oid '%s' is type %d,"
364244198Sdelphij					" cannot set that%s", bufp,
365244198Sdelphij					kind & CTLTYPE, line);
366244198Sdelphij				return (1);
3671553Srgrimes		}
3681553Srgrimes
36912946Sphk		i = show_var(mib, len);
37012946Sphk		if (sysctl(mib, len, 0, 0, newval, newsize) == -1) {
37112946Sphk			if (!i && !bflag)
37212946Sphk				putchar('\n');
37312946Sphk			switch (errno) {
37412946Sphk			case EOPNOTSUPP:
375244198Sdelphij				warnx("%s: value is not available%s",
376244198Sdelphij					string, line);
377244198Sdelphij				return (1);
37812946Sphk			case ENOTDIR:
379244198Sdelphij				warnx("%s: specification is incomplete%s",
380244198Sdelphij					string, line);
381244198Sdelphij				return (1);
38212946Sphk			case ENOMEM:
383244198Sdelphij				warnx("%s: type is unknown to this program%s",
384244198Sdelphij					string, line);
385244198Sdelphij				return (1);
38612946Sphk			default:
387244198Sdelphij				warn("%s%s", string, line);
388244198Sdelphij				return (1);
38912946Sphk			}
39012946Sphk		}
39112946Sphk		if (!bflag)
39212946Sphk			printf(" -> ");
39312946Sphk		i = nflag;
39412946Sphk		nflag = 1;
39512946Sphk		j = show_var(mib, len);
39612946Sphk		if (!j && !bflag)
39712946Sphk			putchar('\n');
39812946Sphk		nflag = i;
39912946Sphk	}
400244198Sdelphij
401244198Sdelphij	return (0);
40212946Sphk}
4031553Srgrimes
404244198Sdelphijstatic int
405244198Sdelphijparsefile(const char *filename)
406244198Sdelphij{
407244198Sdelphij	FILE *file;
408244198Sdelphij	char line[BUFSIZ], *p, *pq, *pdq;
409244198Sdelphij	int warncount = 0, lineno = 0;
410244198Sdelphij
411244198Sdelphij	file = fopen(filename, "r");
412244198Sdelphij	if (file == NULL)
413244198Sdelphij		err(EX_NOINPUT, "%s", filename);
414244198Sdelphij	while (fgets(line, sizeof(line), file) != NULL) {
415244198Sdelphij		lineno++;
416244198Sdelphij		p = line;
417244198Sdelphij		pq = strchr(line, '\'');
418244198Sdelphij		pdq = strchr(line, '\"');
419244198Sdelphij		/* Replace the first # with \0. */
420244198Sdelphij		while((p = strchr(p, '#')) != NULL) {
421244198Sdelphij			if (pq != NULL && p > pq) {
422244198Sdelphij				if ((p = strchr(pq+1, '\'')) != NULL)
423244198Sdelphij					*(++p) = '\0';
424244198Sdelphij				break;
425244198Sdelphij			} else if (pdq != NULL && p > pdq) {
426244198Sdelphij				if ((p = strchr(pdq+1, '\"')) != NULL)
427244198Sdelphij					*(++p) = '\0';
428244198Sdelphij				break;
429244198Sdelphij			} else if (p == line || *(p-1) != '\\') {
430244198Sdelphij				*p = '\0';
431244198Sdelphij				break;
432244198Sdelphij			}
433244198Sdelphij			p++;
434244198Sdelphij		}
435244198Sdelphij		/* Trim spaces */
436244198Sdelphij		p = line + strlen(line) - 1;
437244198Sdelphij		while (p >= line && isspace((int)*p)) {
438244198Sdelphij			*p = '\0';
439244198Sdelphij			p--;
440244198Sdelphij		}
441244198Sdelphij		p = line;
442244198Sdelphij		while (isspace((int)*p))
443244198Sdelphij			p++;
444244198Sdelphij		if (*p == '\0')
445244198Sdelphij			continue;
446244198Sdelphij		else
447244198Sdelphij			warncount += parse(p, lineno);
448244198Sdelphij	}
449244198Sdelphij	fclose(file);
450244198Sdelphij
451244198Sdelphij	return (warncount);
452244198Sdelphij}
453244198Sdelphij
45412946Sphk/* These functions will dump out various interesting structures. */
4551553Srgrimes
45612946Sphkstatic int
45712946SphkS_clockinfo(int l2, void *p)
45812946Sphk{
45912946Sphk	struct clockinfo *ci = (struct clockinfo*)p;
460170512Sdwmalone
46197232Salfred	if (l2 != sizeof(*ci)) {
462203917Suqs		warnx("S_clockinfo %d != %zu", l2, sizeof(*ci));
463170558Sbde		return (1);
46497232Salfred	}
465122233Sdes	printf(hflag ? "{ hz = %'d, tick = %'d, profhz = %'d, stathz = %'d }" :
466122233Sdes		"{ hz = %d, tick = %d, profhz = %d, stathz = %d }",
46794752Sphk		ci->hz, ci->tick, ci->profhz, ci->stathz);
46812946Sphk	return (0);
46912946Sphk}
4701553Srgrimes
47112946Sphkstatic int
47212946SphkS_loadavg(int l2, void *p)
47312946Sphk{
47412946Sphk	struct loadavg *tv = (struct loadavg*)p;
4758857Srgrimes
47697232Salfred	if (l2 != sizeof(*tv)) {
477203917Suqs		warnx("S_loadavg %d != %zu", l2, sizeof(*tv));
478170558Sbde		return (1);
47997232Salfred	}
480122233Sdes	printf(hflag ? "{ %'.2f %'.2f %'.2f }" : "{ %.2f %.2f %.2f }",
48112946Sphk		(double)tv->ldavg[0]/(double)tv->fscale,
48212946Sphk		(double)tv->ldavg[1]/(double)tv->fscale,
48312946Sphk		(double)tv->ldavg[2]/(double)tv->fscale);
48412946Sphk	return (0);
48512946Sphk}
4861553Srgrimes
48712946Sphkstatic int
48812946SphkS_timeval(int l2, void *p)
48912946Sphk{
49012946Sphk	struct timeval *tv = (struct timeval*)p;
49137266Sbde	time_t tv_sec;
49212946Sphk	char *p1, *p2;
4931553Srgrimes
49497232Salfred	if (l2 != sizeof(*tv)) {
495203917Suqs		warnx("S_timeval %d != %zu", l2, sizeof(*tv));
496170558Sbde		return (1);
49797232Salfred	}
498194684Sjhay	printf(hflag ? "{ sec = %'jd, usec = %'ld } " :
499194684Sjhay		"{ sec = %jd, usec = %ld } ",
500194684Sjhay		(intmax_t)tv->tv_sec, tv->tv_usec);
50137266Sbde	tv_sec = tv->tv_sec;
50237266Sbde	p1 = strdup(ctime(&tv_sec));
50312946Sphk	for (p2=p1; *p2 ; p2++)
50412946Sphk		if (*p2 == '\n')
50512946Sphk			*p2 = '\0';
50612946Sphk	fputs(p1, stdout);
507205118Sbrucec	free(p1);
50812946Sphk	return (0);
50912946Sphk}
5101553Srgrimes
51112946Sphkstatic int
512109097SdillonS_vmtotal(int l2, void *p)
513109097Sdillon{
514109097Sdillon	struct vmtotal *v = (struct vmtotal *)p;
515109113Sdillon	int pageKilo = getpagesize() / 1024;
516109097Sdillon
517109097Sdillon	if (l2 != sizeof(*v)) {
518203917Suqs		warnx("S_vmtotal %d != %zu", l2, sizeof(*v));
519170558Sbde		return (1);
520109097Sdillon	}
521109097Sdillon
522109113Sdillon	printf(
523109113Sdillon	    "\nSystem wide totals computed every five seconds:"
524109113Sdillon	    " (values in kilobytes)\n");
525109097Sdillon	printf("===============================================\n");
526109113Sdillon	printf(
527164718Sru	    "Processes:\t\t(RUNQ: %hd Disk Wait: %hd Page Wait: "
528164718Sru	    "%hd Sleep: %hd)\n",
529109113Sdillon	    v->t_rq, v->t_dw, v->t_pw, v->t_sl);
530109113Sdillon	printf(
531212726Szec	    "Virtual Memory:\t\t(Total: %dK Active: %dK)\n",
532164718Sru	    v->t_vm * pageKilo, v->t_avm * pageKilo);
533212726Szec	printf("Real Memory:\t\t(Total: %dK Active: %dK)\n",
534164718Sru	    v->t_rm * pageKilo, v->t_arm * pageKilo);
535164718Sru	printf("Shared Virtual Memory:\t(Total: %dK Active: %dK)\n",
536164718Sru	    v->t_vmshr * pageKilo, v->t_avmshr * pageKilo);
537164718Sru	printf("Shared Real Memory:\t(Total: %dK Active: %dK)\n",
538164718Sru	    v->t_rmshr * pageKilo, v->t_armshr * pageKilo);
539234134Seadler	printf("Free Memory:\t%dK\n", v->t_free * pageKilo);
540122234Sdes
541109097Sdillon	return (0);
542109097Sdillon}
543109097Sdillon
544109097Sdillonstatic int
545198340Sedset_IK(const char *str, int *val)
546161951Sume{
547161951Sume	float temp;
548161951Sume	int len, kelv;
549198340Sed	const char *p;
550198340Sed	char *endptr;
551161951Sume
552161951Sume	if ((len = strlen(str)) == 0)
553161951Sume		return (0);
554161951Sume	p = &str[len - 1];
555161951Sume	if (*p == 'C' || *p == 'F') {
556161951Sume		temp = strtof(str, &endptr);
557198340Sed		if (endptr == str || endptr != p)
558161951Sume			return (0);
559161951Sume		if (*p == 'F')
560161951Sume			temp = (temp - 32) * 5 / 9;
561161951Sume		kelv = temp * 10 + 2732;
562161951Sume	} else {
563161951Sume		kelv = (int)strtol(str, &endptr, 10);
564161951Sume		if (endptr == str || *endptr != '\0')
565161951Sume			return (0);
566161951Sume	}
567161951Sume	*val = kelv;
568161951Sume	return (1);
569161951Sume}
570161951Sume
57112946Sphk/*
57212946Sphk * These functions uses a presently undocumented interface to the kernel
57312946Sphk * to walk the tree and get the type so it can print the value.
57412946Sphk * This interface is under work and consideration, and should probably
57512946Sphk * be killed with a big axe by the first person who can find the time.
57612946Sphk * (be aware though, that the proper interface isn't as obvious as it
57712946Sphk * may seem, there are various conflicting requirements.
57812946Sphk */
5791553Srgrimes
58012946Sphkstatic int
58112946Sphkname2oid(char *name, int *oidp)
58212946Sphk{
58312946Sphk	int oid[2];
58438533Sdfr	int i;
58538533Sdfr	size_t j;
5861553Srgrimes
58712946Sphk	oid[0] = 0;
58812946Sphk	oid[1] = 3;
5891553Srgrimes
59077928Sdd	j = CTL_MAXNAME * sizeof(int);
59112946Sphk	i = sysctl(oid, 2, oidp, &j, name, strlen(name));
592122234Sdes	if (i < 0)
593170512Sdwmalone		return (i);
59477928Sdd	j /= sizeof(int);
59512946Sphk	return (j);
5961553Srgrimes}
5971553Srgrimes
59812946Sphkstatic int
59912946Sphkoidfmt(int *oid, int len, char *fmt, u_int *kind)
60012946Sphk{
60112946Sphk	int qoid[CTL_MAXNAME+2];
60212946Sphk	u_char buf[BUFSIZ];
60338533Sdfr	int i;
60438533Sdfr	size_t j;
6051553Srgrimes
60612946Sphk	qoid[0] = 0;
60712946Sphk	qoid[1] = 4;
60812946Sphk	memcpy(qoid + 2, oid, len * sizeof(int));
6091553Srgrimes
61077928Sdd	j = sizeof(buf);
61112946Sphk	i = sysctl(qoid, len + 2, buf, &j, 0, 0);
61212946Sphk	if (i)
613203917Suqs		err(1, "sysctl fmt %d %zu %d", i, j, errno);
6141553Srgrimes
61512946Sphk	if (kind)
61612946Sphk		*kind = *(u_int *)buf;
61712946Sphk
61812946Sphk	if (fmt)
61912946Sphk		strcpy(fmt, (char *)(buf + sizeof(u_int)));
620170512Sdwmalone	return (0);
6211553Srgrimes}
6221553Srgrimes
623217616Smdfstatic int ctl_sign[CTLTYPE+1] = {
624217616Smdf	[CTLTYPE_INT] = 1,
625217616Smdf	[CTLTYPE_LONG] = 1,
626217616Smdf	[CTLTYPE_S64] = 1,
627217616Smdf};
628217616Smdf
629217616Smdfstatic int ctl_size[CTLTYPE+1] = {
630217616Smdf	[CTLTYPE_INT] = sizeof(int),
631217616Smdf	[CTLTYPE_UINT] = sizeof(u_int),
632217616Smdf	[CTLTYPE_LONG] = sizeof(long),
633217616Smdf	[CTLTYPE_ULONG] = sizeof(u_long),
634217616Smdf	[CTLTYPE_S64] = sizeof(int64_t),
635217616Smdf	[CTLTYPE_U64] = sizeof(int64_t),
636217616Smdf};
637217616Smdf
6381553Srgrimes/*
63912946Sphk * This formats and outputs the value of one variable
64012946Sphk *
64112946Sphk * Returns zero if anything was actually output.
64212946Sphk * Returns one if didn't know what to do with this.
64312946Sphk * Return minus one if we had errors.
6441553Srgrimes */
64512946Sphkstatic int
64612946Sphkshow_var(int *oid, int nlen)
6471553Srgrimes{
648162073Sru	u_char buf[BUFSIZ], *val, *oval, *p;
649244133Salfred	char name[BUFSIZ], fmt[BUFSIZ];
650170513Sdwmalone	const char *sep, *sep1;
65112946Sphk	int qoid[CTL_MAXNAME+2];
652170512Sdwmalone	uintmax_t umv;
653170512Sdwmalone	intmax_t mv;
654217586Smdf	int i, hexlen, sign, ctltype;
655170287Sdwmalone	size_t intlen;
65638533Sdfr	size_t j, len;
65712946Sphk	u_int kind;
65877332Sdes	int (*func)(int, void *);
6591553Srgrimes
660203917Suqs	/* Silence GCC. */
661203917Suqs	umv = mv = intlen = 0;
662203917Suqs
663144997Smdodd	bzero(buf, BUFSIZ);
664244133Salfred	bzero(fmt, BUFSIZ);
665144997Smdodd	bzero(name, BUFSIZ);
66642456Sdes	qoid[0] = 0;
66742456Sdes	memcpy(qoid + 2, oid, nlen * sizeof(int));
66842456Sdes
66942456Sdes	qoid[1] = 1;
67077928Sdd	j = sizeof(name);
67142456Sdes	i = sysctl(qoid, nlen + 2, name, &j, 0, 0);
67242456Sdes	if (i || !j)
673203917Suqs		err(1, "sysctl name %d %zu %d", i, j, errno);
67442456Sdes
675244133Salfred	oidfmt(oid, nlen, fmt, &kind);
676244133Salfred	/* if Wflag then only list sysctls that are writeable and not stats. */
677244133Salfred	if (Wflag && ((kind & CTLFLAG_WR) == 0 || (kind & CTLFLAG_STATS) != 0))
678244133Salfred		return 1;
679244133Salfred
680244133Salfred	/* if Tflag then only list sysctls that are tuneables. */
681244133Salfred	if (Tflag && (kind & CTLFLAG_TUN) == 0)
682244133Salfred		return 1;
683244133Salfred
68471034Sdes	if (Nflag) {
68571034Sdes		printf("%s", name);
68671034Sdes		return (0);
68771034Sdes	}
68871034Sdes
68985747Stobez	if (eflag)
69085747Stobez		sep = "=";
69185747Stobez	else
69285747Stobez		sep = ": ";
69385747Stobez
69488006Sluigi	if (dflag) {	/* just print description */
69588006Sluigi		qoid[1] = 5;
69688006Sluigi		j = sizeof(buf);
69788006Sluigi		i = sysctl(qoid, nlen + 2, buf, &j, 0, 0);
69888006Sluigi		if (!nflag)
69988006Sluigi			printf("%s%s", name, sep);
70088006Sluigi		printf("%s", buf);
70188006Sluigi		return (0);
70288006Sluigi	}
70312946Sphk	/* find an estimate of how much we need for this var */
70412946Sphk	j = 0;
70512946Sphk	i = sysctl(oid, nlen, 0, &j, 0, 0);
70612946Sphk	j += j; /* we want to be sure :-) */
70712946Sphk
708162073Sru	val = oval = malloc(j + 1);
709162073Sru	if (val == NULL) {
710162073Sru		warnx("malloc failed");
711170558Sbde		return (1);
712162073Sru	}
713268243Shselasky	ctltype = (kind & CTLTYPE);
71412946Sphk	len = j;
71512946Sphk	i = sysctl(oid, nlen, val, &len, 0, 0);
716268243Shselasky	if (i != 0 || (len == 0 && ctltype != CTLTYPE_STRING)) {
717162073Sru		free(oval);
71812946Sphk		return (1);
719162073Sru	}
72012946Sphk
72112946Sphk	if (bflag) {
72212946Sphk		fwrite(val, 1, len, stdout);
723162073Sru		free(oval);
72412946Sphk		return (0);
7251553Srgrimes	}
72696234Sache	val[len] = '\0';
72712946Sphk	p = val;
728217616Smdf	sign = ctl_sign[ctltype];
729217616Smdf	intlen = ctl_size[ctltype];
730217616Smdf
731217586Smdf	switch (ctltype) {
732217586Smdf	case CTLTYPE_STRING:
73312946Sphk		if (!nflag)
73485747Stobez			printf("%s%s", name, sep);
735203917Suqs		printf("%.*s", (int)len, p);
736162073Sru		free(oval);
73712946Sphk		return (0);
738122234Sdes
739217586Smdf	case CTLTYPE_INT:
740217586Smdf	case CTLTYPE_UINT:
741217586Smdf	case CTLTYPE_LONG:
742217586Smdf	case CTLTYPE_ULONG:
743217616Smdf	case CTLTYPE_S64:
744217616Smdf	case CTLTYPE_U64:
74512946Sphk		if (!nflag)
74685747Stobez			printf("%s%s", name, sep);
747170514Sdwmalone		hexlen = 2 + (intlen * CHAR_BIT + 3) / 4;
748170513Sdwmalone		sep1 = "";
749170287Sdwmalone		while (len >= intlen) {
750217586Smdf			switch (kind & CTLTYPE) {
751217586Smdf			case CTLTYPE_INT:
752217586Smdf			case CTLTYPE_UINT:
753170514Sdwmalone				umv = *(u_int *)p;
754170514Sdwmalone				mv = *(int *)p;
755170287Sdwmalone				break;
756217586Smdf			case CTLTYPE_LONG:
757217586Smdf			case CTLTYPE_ULONG:
758170514Sdwmalone				umv = *(u_long *)p;
759170514Sdwmalone				mv = *(long *)p;
760170287Sdwmalone				break;
761217616Smdf			case CTLTYPE_S64:
762217616Smdf			case CTLTYPE_U64:
763217616Smdf				umv = *(uint64_t *)p;
764217616Smdf				mv = *(int64_t *)p;
765170287Sdwmalone				break;
766170287Sdwmalone			}
767170513Sdwmalone			fputs(sep1, stdout);
768217586Smdf			if (xflag)
769217586Smdf				printf("%#0*jx", hexlen, umv);
770217586Smdf			else if (!sign)
771170512Sdwmalone				printf(hflag ? "%'ju" : "%ju", umv);
772170287Sdwmalone			else if (fmt[1] == 'K') {
773170514Sdwmalone				if (mv < 0)
774170512Sdwmalone					printf("%jd", mv);
775134541Speter				else
776170512Sdwmalone					printf("%.1fC", (mv - 2732.0) / 10);
777134541Speter			} else
778170513Sdwmalone				printf(hflag ? "%'jd" : "%jd", mv);
779170513Sdwmalone			sep1 = " ";
780170287Sdwmalone			len -= intlen;
781170287Sdwmalone			p += intlen;
78241019Sphk		}
783162073Sru		free(oval);
78412946Sphk		return (0);
78512946Sphk
786217586Smdf	case CTLTYPE_OPAQUE:
78712946Sphk		i = 0;
78877332Sdes		if (strcmp(fmt, "S,clockinfo") == 0)
78977332Sdes			func = S_clockinfo;
79077332Sdes		else if (strcmp(fmt, "S,timeval") == 0)
79177332Sdes			func = S_timeval;
79277332Sdes		else if (strcmp(fmt, "S,loadavg") == 0)
79377332Sdes			func = S_loadavg;
794109097Sdillon		else if (strcmp(fmt, "S,vmtotal") == 0)
795109097Sdillon			func = S_vmtotal;
79677332Sdes		else
79777332Sdes			func = NULL;
79812946Sphk		if (func) {
79912946Sphk			if (!nflag)
80085747Stobez				printf("%s%s", name, sep);
801163275Sharti			i = (*func)(len, p);
802162073Sru			free(oval);
803163275Sharti			return (i);
80412946Sphk		}
805102411Scharnier		/* FALLTHROUGH */
80612946Sphk	default:
807162073Sru		if (!oflag && !xflag) {
808162073Sru			free(oval);
80912946Sphk			return (1);
810162073Sru		}
81112946Sphk		if (!nflag)
81285747Stobez			printf("%s%s", name, sep);
813203917Suqs		printf("Format:%s Length:%zu Dump:0x", fmt, len);
81477332Sdes		while (len-- && (xflag || p < val + 16))
81512946Sphk			printf("%02x", *p++);
81677332Sdes		if (!xflag && len > 16)
81712946Sphk			printf("...");
818162073Sru		free(oval);
81912946Sphk		return (0);
8201553Srgrimes	}
821162073Sru	free(oval);
82212946Sphk	return (1);
8231553Srgrimes}
8241553Srgrimes
82512946Sphkstatic int
826170512Sdwmalonesysctl_all(int *oid, int len)
8271553Srgrimes{
82812946Sphk	int name1[22], name2[22];
82938533Sdfr	int i, j;
83038533Sdfr	size_t l1, l2;
8311553Srgrimes
83212946Sphk	name1[0] = 0;
83312946Sphk	name1[1] = 2;
83412946Sphk	l1 = 2;
83512946Sphk	if (len) {
83677928Sdd		memcpy(name1+2, oid, len * sizeof(int));
83712946Sphk		l1 += len;
83812946Sphk	} else {
83912946Sphk		name1[2] = 1;
84012946Sphk		l1++;
84112946Sphk	}
84277332Sdes	for (;;) {
84377928Sdd		l2 = sizeof(name2);
84412946Sphk		j = sysctl(name1, l1, name2, &l2, 0, 0);
84548956Sbillf		if (j < 0) {
84612946Sphk			if (errno == ENOENT)
847170512Sdwmalone				return (0);
84812946Sphk			else
849203917Suqs				err(1, "sysctl(getnext) %d %zu", j, l2);
85048956Sbillf		}
85112946Sphk
85277928Sdd		l2 /= sizeof(int);
85312946Sphk
854170513Sdwmalone		if (len < 0 || l2 < (unsigned int)len)
855170512Sdwmalone			return (0);
85612946Sphk
85712946Sphk		for (i = 0; i < len; i++)
85812946Sphk			if (name2[i] != oid[i])
859170512Sdwmalone				return (0);
86012946Sphk
86112946Sphk		i = show_var(name2, l2);
86212946Sphk		if (!i && !bflag)
86312946Sphk			putchar('\n');
86412946Sphk
86577928Sdd		memcpy(name1+2, name2, l2 * sizeof(int));
86612946Sphk		l1 = 2 + l2;
86712946Sphk	}
8681553Srgrimes}
869