sysctl.c revision 77928
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 * 3. All advertising materials mentioning features or use of this software 141553Srgrimes * must display the following acknowledgement: 151553Srgrimes * This product includes software developed by the University of 161553Srgrimes * California, Berkeley and its contributors. 171553Srgrimes * 4. Neither the name of the University nor the names of its contributors 181553Srgrimes * may be used to endorse or promote products derived from this software 191553Srgrimes * without specific prior written permission. 201553Srgrimes * 211553Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221553Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231553Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241553Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251553Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261553Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271553Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281553Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291553Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301553Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311553Srgrimes * SUCH DAMAGE. 321553Srgrimes */ 331553Srgrimes 341553Srgrimes#ifndef lint 3530602Scharnierstatic const char copyright[] = 361553Srgrimes"@(#) Copyright (c) 1993\n\ 371553Srgrimes The Regents of the University of California. All rights reserved.\n"; 381553Srgrimes#endif /* not lint */ 391553Srgrimes 401553Srgrimes#ifndef lint 4130602Scharnier#if 0 4230602Scharnierstatic char sccsid[] = "@(#)from: sysctl.c 8.1 (Berkeley) 6/6/93"; 4330602Scharnier#endif 446284Swollmanstatic const char rcsid[] = 4550476Speter "$FreeBSD: head/sbin/sysctl/sysctl.c 77928 2001-06-09 03:56:16Z dd $"; 461553Srgrimes#endif /* not lint */ 471553Srgrimes 4812946Sphk#include <sys/types.h> 491553Srgrimes#include <sys/stat.h> 501553Srgrimes#include <sys/sysctl.h> 5112946Sphk#include <sys/resource.h> 521553Srgrimes 5330602Scharnier#include <ctype.h> 5430602Scharnier#include <err.h> 551553Srgrimes#include <errno.h> 561553Srgrimes#include <stdio.h> 571553Srgrimes#include <stdlib.h> 581553Srgrimes#include <string.h> 5930602Scharnier#include <unistd.h> 601553Srgrimes 6177330Sdesstatic int aflag, bflag, Nflag, nflag, oflag, xflag; 621553Srgrimes 6312946Sphkstatic int oidfmt(int *, int, char *, u_int *); 6412946Sphkstatic void parse(char *); 6512946Sphkstatic int show_var(int *, int); 6612946Sphkstatic int sysctl_all (int *oid, int len); 6712946Sphkstatic int name2oid(char *, int *); 681553Srgrimes 6912946Sphkstatic void 7012946Sphkusage(void) 7112946Sphk{ 721553Srgrimes 7377330Sdes (void)fprintf(stderr, "%s\n%s\n", 7477330Sdes "usage: sysctl [-bNnox] variable[=value] ...", 7577330Sdes " sysctl [-bNnox] -a"); 7612946Sphk exit(1); 7712946Sphk} 781553Srgrimes 791553Srgrimesint 8012946Sphkmain(int argc, char **argv) 811553Srgrimes{ 8212946Sphk int ch; 8312946Sphk setbuf(stdout,0); 8412946Sphk setbuf(stderr,0); 851553Srgrimes 8677330Sdes while ((ch = getopt(argc, argv, "AabNnowxX")) != -1) { 871553Srgrimes switch (ch) { 8871034Sdes case 'A': 8977330Sdes /* compatibility */ 9077330Sdes aflag = oflag = 1; 9171034Sdes break; 9271034Sdes case 'a': 9371034Sdes aflag = 1; 9471034Sdes break; 9571034Sdes case 'b': 9671034Sdes bflag = 1; 9771034Sdes break; 9871034Sdes case 'N': 9971034Sdes Nflag = 1; 10071034Sdes break; 10171034Sdes case 'n': 10271034Sdes nflag = 1; 10371034Sdes break; 10477330Sdes case 'o': 10577330Sdes oflag = 1; 10677330Sdes break; 10771034Sdes case 'w': 10877330Sdes /* compatibility */ 10977330Sdes /* ignored */ 11071034Sdes break; 11171034Sdes case 'X': 11277330Sdes /* compatibility */ 11377330Sdes aflag = xflag = 1; 11471034Sdes break; 11577330Sdes case 'x': 11677330Sdes xflag = 1; 11777330Sdes break; 11871034Sdes default: 11971034Sdes usage(); 1201553Srgrimes } 1211553Srgrimes } 1221553Srgrimes argc -= optind; 1231553Srgrimes argv += optind; 1241553Srgrimes 12577330Sdes if (Nflag && nflag) 12642456Sdes usage(); 12777330Sdes if (aflag && argc == 0) 12877330Sdes exit(sysctl_all(0, 0)); 1291553Srgrimes if (argc == 0) 1301553Srgrimes usage(); 1311553Srgrimes while (argc-- > 0) 13212946Sphk parse(*argv++); 1331553Srgrimes exit(0); 1341553Srgrimes} 1351553Srgrimes 1361553Srgrimes/* 1371553Srgrimes * Parse a name into a MIB entry. 1381553Srgrimes * Lookup and print out the MIB entry if it exists. 1391553Srgrimes * Set a new value if requested. 1401553Srgrimes */ 14112946Sphkstatic void 14212946Sphkparse(char *string) 1431553Srgrimes{ 14412946Sphk int len, i, j; 1451553Srgrimes void *newval = 0; 1461553Srgrimes int intval, newsize = 0; 1471553Srgrimes quad_t quadval; 1481553Srgrimes int mib[CTL_MAXNAME]; 14912946Sphk char *cp, *bufp, buf[BUFSIZ]; 15012946Sphk u_int kind; 1511553Srgrimes 1521553Srgrimes bufp = buf; 1531553Srgrimes snprintf(buf, BUFSIZ, "%s", string); 1541553Srgrimes if ((cp = strchr(string, '=')) != NULL) { 1551553Srgrimes *strchr(buf, '=') = '\0'; 1561553Srgrimes *cp++ = '\0'; 1571553Srgrimes while (isspace(*cp)) 1581553Srgrimes cp++; 1591553Srgrimes newval = cp; 1601553Srgrimes newsize = strlen(cp); 1611553Srgrimes } 16212946Sphk len = name2oid(bufp, mib); 1631553Srgrimes 16412946Sphk if (len < 0) 16530602Scharnier errx(1, "unknown oid '%s'", bufp); 1661553Srgrimes 16712946Sphk if (oidfmt(mib, len, 0, &kind)) 16830602Scharnier err(1, "couldn't find format of oid '%s'", bufp); 1691553Srgrimes 17077330Sdes if (newval == NULL) { 17112946Sphk if ((kind & CTLTYPE) == CTLTYPE_NODE) { 17212946Sphk sysctl_all(mib, len); 17312946Sphk } else { 17412946Sphk i = show_var(mib, len); 17512946Sphk if (!i && !bflag) 17612946Sphk putchar('\n'); 1771553Srgrimes } 17812946Sphk } else { 17912946Sphk if ((kind & CTLTYPE) == CTLTYPE_NODE) 18012946Sphk errx(1, "oid '%s' isn't a leaf node", bufp); 1811553Srgrimes 18212946Sphk if (!(kind&CTLFLAG_WR)) 18312946Sphk errx(1, "oid '%s' is read only", bufp); 18412946Sphk 18512946Sphk switch (kind & CTLTYPE) { 18612946Sphk case CTLTYPE_INT: 18753317Sgrog intval = (int) strtol(newval, NULL, 0); 18812946Sphk newval = &intval; 18977928Sdd newsize = sizeof(intval); 1901553Srgrimes break; 19112946Sphk break; 19212946Sphk case CTLTYPE_STRING: 19312946Sphk break; 19412946Sphk case CTLTYPE_QUAD: 19512946Sphk break; 19612946Sphk sscanf(newval, "%qd", &quadval); 19712946Sphk newval = &quadval; 19877928Sdd newsize = sizeof(quadval); 19912946Sphk break; 20012946Sphk default: 20112946Sphk errx(1, "oid '%s' is type %d," 20231214Sjdp " cannot set that", bufp, 20331214Sjdp kind & CTLTYPE); 2041553Srgrimes } 2051553Srgrimes 20612946Sphk i = show_var(mib, len); 20712946Sphk if (sysctl(mib, len, 0, 0, newval, newsize) == -1) { 20812946Sphk if (!i && !bflag) 20912946Sphk putchar('\n'); 21012946Sphk switch (errno) { 21112946Sphk case EOPNOTSUPP: 21230602Scharnier errx(1, "%s: value is not available", 21312946Sphk string); 21412946Sphk case ENOTDIR: 21530602Scharnier errx(1, "%s: specification is incomplete", 21612946Sphk string); 21712946Sphk case ENOMEM: 21830602Scharnier errx(1, "%s: type is unknown to this program", 21912946Sphk string); 22012946Sphk default: 22130602Scharnier warn("%s", string); 22212946Sphk return; 22312946Sphk } 22412946Sphk } 22512946Sphk if (!bflag) 22612946Sphk printf(" -> "); 22712946Sphk i = nflag; 22812946Sphk nflag = 1; 22912946Sphk j = show_var(mib, len); 23012946Sphk if (!j && !bflag) 23112946Sphk putchar('\n'); 23212946Sphk nflag = i; 23312946Sphk } 23412946Sphk} 2351553Srgrimes 23612946Sphk/* These functions will dump out various interesting structures. */ 2371553Srgrimes 23812946Sphkstatic int 23912946SphkS_clockinfo(int l2, void *p) 24012946Sphk{ 24112946Sphk struct clockinfo *ci = (struct clockinfo*)p; 24277928Sdd if (l2 != sizeof(*ci)) 24377928Sdd err(1, "S_clockinfo %d != %d", l2, sizeof(*ci)); 24426899Sjhay printf("{ hz = %d, tick = %d, tickadj = %d, profhz = %d, stathz = %d }", 24526899Sjhay ci->hz, ci->tick, ci->tickadj, ci->profhz, ci->stathz); 24612946Sphk return (0); 24712946Sphk} 2481553Srgrimes 24912946Sphkstatic int 25012946SphkS_loadavg(int l2, void *p) 25112946Sphk{ 25212946Sphk struct loadavg *tv = (struct loadavg*)p; 2538857Srgrimes 25477928Sdd if (l2 != sizeof(*tv)) 25577928Sdd err(1, "S_loadavg %d != %d", l2, sizeof(*tv)); 2561553Srgrimes 25712946Sphk printf("{ %.2f %.2f %.2f }", 25812946Sphk (double)tv->ldavg[0]/(double)tv->fscale, 25912946Sphk (double)tv->ldavg[1]/(double)tv->fscale, 26012946Sphk (double)tv->ldavg[2]/(double)tv->fscale); 26112946Sphk return (0); 26212946Sphk} 2631553Srgrimes 26412946Sphkstatic int 26512946SphkS_timeval(int l2, void *p) 26612946Sphk{ 26712946Sphk struct timeval *tv = (struct timeval*)p; 26837266Sbde time_t tv_sec; 26912946Sphk char *p1, *p2; 2701553Srgrimes 27177928Sdd if (l2 != sizeof(*tv)) 27277928Sdd err(1, "S_timeval %d != %d", l2, sizeof(*tv)); 27312946Sphk printf("{ sec = %ld, usec = %ld } ", 27412946Sphk tv->tv_sec, tv->tv_usec); 27537266Sbde tv_sec = tv->tv_sec; 27637266Sbde p1 = strdup(ctime(&tv_sec)); 27712946Sphk for (p2=p1; *p2 ; p2++) 27812946Sphk if (*p2 == '\n') 27912946Sphk *p2 = '\0'; 28012946Sphk fputs(p1, stdout); 28112946Sphk return (0); 28212946Sphk} 2831553Srgrimes 28412946Sphkstatic int 28512946SphkT_dev_t(int l2, void *p) 28612946Sphk{ 28712946Sphk dev_t *d = (dev_t *)p; 28877928Sdd if (l2 != sizeof(*d)) 28977928Sdd err(1, "T_dev_T %d != %d", l2, sizeof(*d)); 29061514Sphk if ((int)(*d) != -1) { 29161514Sphk if (minor(*d) > 255 || minor(*d) < 0) 29261514Sphk printf("{ major = %d, minor = 0x%x }", 29361514Sphk major(*d), minor(*d)); 29461514Sphk else 29561514Sphk printf("{ major = %d, minor = %d }", 29661514Sphk major(*d), minor(*d)); 29761514Sphk } 29812946Sphk return (0); 29912946Sphk} 3001553Srgrimes 30112946Sphk/* 30212946Sphk * These functions uses a presently undocumented interface to the kernel 30312946Sphk * to walk the tree and get the type so it can print the value. 30412946Sphk * This interface is under work and consideration, and should probably 30512946Sphk * be killed with a big axe by the first person who can find the time. 30612946Sphk * (be aware though, that the proper interface isn't as obvious as it 30712946Sphk * may seem, there are various conflicting requirements. 30812946Sphk */ 3091553Srgrimes 31012946Sphkstatic int 31112946Sphkname2oid(char *name, int *oidp) 31212946Sphk{ 31312946Sphk int oid[2]; 31438533Sdfr int i; 31538533Sdfr size_t j; 3161553Srgrimes 31712946Sphk oid[0] = 0; 31812946Sphk oid[1] = 3; 3191553Srgrimes 32077928Sdd j = CTL_MAXNAME * sizeof(int); 32112946Sphk i = sysctl(oid, 2, oidp, &j, name, strlen(name)); 32212946Sphk if (i < 0) 32312946Sphk return i; 32477928Sdd j /= sizeof(int); 32512946Sphk return (j); 3261553Srgrimes} 3271553Srgrimes 32812946Sphkstatic int 32912946Sphkoidfmt(int *oid, int len, char *fmt, u_int *kind) 33012946Sphk{ 33112946Sphk int qoid[CTL_MAXNAME+2]; 33212946Sphk u_char buf[BUFSIZ]; 33338533Sdfr int i; 33438533Sdfr size_t j; 3351553Srgrimes 33612946Sphk qoid[0] = 0; 33712946Sphk qoid[1] = 4; 33812946Sphk memcpy(qoid + 2, oid, len * sizeof(int)); 3391553Srgrimes 34077928Sdd j = sizeof(buf); 34112946Sphk i = sysctl(qoid, len + 2, buf, &j, 0, 0); 34212946Sphk if (i) 34330602Scharnier err(1, "sysctl fmt %d %d %d", i, j, errno); 3441553Srgrimes 34512946Sphk if (kind) 34612946Sphk *kind = *(u_int *)buf; 34712946Sphk 34812946Sphk if (fmt) 34912946Sphk strcpy(fmt, (char *)(buf + sizeof(u_int))); 35012946Sphk return 0; 3511553Srgrimes} 3521553Srgrimes 3531553Srgrimes/* 35412946Sphk * This formats and outputs the value of one variable 35512946Sphk * 35612946Sphk * Returns zero if anything was actually output. 35712946Sphk * Returns one if didn't know what to do with this. 35812946Sphk * Return minus one if we had errors. 3591553Srgrimes */ 36012946Sphk 36112946Sphkstatic int 36212946Sphkshow_var(int *oid, int nlen) 3631553Srgrimes{ 36412946Sphk u_char buf[BUFSIZ], *val, *p; 36577567Sdd char name[BUFSIZ], *fmt; 36612946Sphk int qoid[CTL_MAXNAME+2]; 36738533Sdfr int i; 36838533Sdfr size_t j, len; 36912946Sphk u_int kind; 37077332Sdes int (*func)(int, void *); 3711553Srgrimes 37242456Sdes qoid[0] = 0; 37342456Sdes memcpy(qoid + 2, oid, nlen * sizeof(int)); 37442456Sdes 37542456Sdes qoid[1] = 1; 37677928Sdd j = sizeof(name); 37742456Sdes i = sysctl(qoid, nlen + 2, name, &j, 0, 0); 37842456Sdes if (i || !j) 37942456Sdes err(1, "sysctl name %d %d %d", i, j, errno); 38042456Sdes 38171034Sdes if (Nflag) { 38271034Sdes printf("%s", name); 38371034Sdes return (0); 38471034Sdes } 38571034Sdes 38612946Sphk /* find an estimate of how much we need for this var */ 38712946Sphk j = 0; 38812946Sphk i = sysctl(oid, nlen, 0, &j, 0, 0); 38912946Sphk j += j; /* we want to be sure :-) */ 39012946Sphk 39112946Sphk val = alloca(j); 39212946Sphk len = j; 39312946Sphk i = sysctl(oid, nlen, val, &len, 0, 0); 39412946Sphk if (i || !len) 39512946Sphk return (1); 39612946Sphk 39712946Sphk if (bflag) { 39812946Sphk fwrite(val, 1, len, stdout); 39912946Sphk return (0); 4001553Srgrimes } 40112946Sphk 40212946Sphk qoid[1] = 4; 40377928Sdd j = sizeof(buf); 40412946Sphk i = sysctl(qoid, nlen + 2, buf, &j, 0, 0); 40512946Sphk if (i || !j) 40630602Scharnier err(1, "sysctl fmt %d %d %d", i, j, errno); 40712946Sphk 40812946Sphk kind = *(u_int *)buf; 40912946Sphk 41012946Sphk fmt = (char *)(buf + sizeof(u_int)); 41112946Sphk 41212946Sphk p = val; 41312946Sphk switch (*fmt) { 41412946Sphk case 'A': 41512946Sphk if (!nflag) 41612946Sphk printf("%s: ", name); 41712946Sphk printf("%s", p); 41812946Sphk return (0); 41912946Sphk 42012946Sphk case 'I': 42112946Sphk if (!nflag) 42212946Sphk printf("%s: ", name); 42362622Sjhb fmt++; 42441019Sphk val = ""; 42541019Sphk while (len >= sizeof(int)) { 42662622Sjhb if(*fmt == 'U') 42762622Sjhb printf("%s%u", val, *(unsigned int *)p); 42862622Sjhb else 42962622Sjhb printf("%s%d", val, *(int *)p); 43041019Sphk val = " "; 43177332Sdes len -= sizeof(int); 43277332Sdes p += sizeof(int); 43341019Sphk } 43412946Sphk return (0); 43512946Sphk 43638533Sdfr case 'L': 43738533Sdfr if (!nflag) 43838533Sdfr printf("%s: ", name); 43962622Sjhb fmt++; 44062975Sphk val = ""; 44162975Sphk while (len >= sizeof(long)) { 44262975Sphk if(*fmt == 'U') 44362975Sphk printf("%s%lu", val, *(unsigned long *)p); 44462975Sphk else 44562975Sphk printf("%s%ld", val, *(long *)p); 44662975Sphk val = " "; 44777332Sdes len -= sizeof(long); 44877332Sdes p += sizeof(long); 44962975Sphk } 45038533Sdfr return (0); 45138533Sdfr 45238533Sdfr case 'P': 45338533Sdfr if (!nflag) 45438533Sdfr printf("%s: ", name); 45538533Sdfr printf("%p", *(void **)p); 45638533Sdfr return (0); 45738533Sdfr 45812946Sphk case 'T': 45912946Sphk case 'S': 46012946Sphk i = 0; 46177332Sdes if (strcmp(fmt, "S,clockinfo") == 0) 46277332Sdes func = S_clockinfo; 46377332Sdes else if (strcmp(fmt, "S,timeval") == 0) 46477332Sdes func = S_timeval; 46577332Sdes else if (strcmp(fmt, "S,loadavg") == 0) 46677332Sdes func = S_loadavg; 46777332Sdes else if (strcmp(fmt, "T,dev_t") == 0) 46877332Sdes func = T_dev_t; 46977332Sdes else 47077332Sdes func = NULL; 47112946Sphk if (func) { 47212946Sphk if (!nflag) 47312946Sphk printf("%s: ", name); 47412946Sphk return ((*func)(len, p)); 47512946Sphk } 47612946Sphk /* FALL THROUGH */ 47712946Sphk default: 47877330Sdes if (!oflag && !xflag) 47912946Sphk return (1); 48012946Sphk if (!nflag) 48112946Sphk printf("%s: ", name); 48212946Sphk printf("Format:%s Length:%d Dump:0x", fmt, len); 48377332Sdes while (len-- && (xflag || p < val + 16)) 48412946Sphk printf("%02x", *p++); 48577332Sdes if (!xflag && len > 16) 48612946Sphk printf("..."); 48712946Sphk return (0); 4881553Srgrimes } 48912946Sphk return (1); 4901553Srgrimes} 4911553Srgrimes 49212946Sphkstatic int 49312946Sphksysctl_all (int *oid, int len) 4941553Srgrimes{ 49512946Sphk int name1[22], name2[22]; 49638533Sdfr int i, j; 49738533Sdfr size_t l1, l2; 4981553Srgrimes 49912946Sphk name1[0] = 0; 50012946Sphk name1[1] = 2; 50112946Sphk l1 = 2; 50212946Sphk if (len) { 50377928Sdd memcpy(name1+2, oid, len * sizeof(int)); 50412946Sphk l1 += len; 50512946Sphk } else { 50612946Sphk name1[2] = 1; 50712946Sphk l1++; 50812946Sphk } 50977332Sdes for (;;) { 51077928Sdd l2 = sizeof(name2); 51112946Sphk j = sysctl(name1, l1, name2, &l2, 0, 0); 51248956Sbillf if (j < 0) { 51312946Sphk if (errno == ENOENT) 51412946Sphk return 0; 51512946Sphk else 51630602Scharnier err(1, "sysctl(getnext) %d %d", j, l2); 51748956Sbillf } 51812946Sphk 51977928Sdd l2 /= sizeof(int); 52012946Sphk 52112946Sphk if (l2 < len) 52212946Sphk return 0; 52312946Sphk 52412946Sphk for (i = 0; i < len; i++) 52512946Sphk if (name2[i] != oid[i]) 52612946Sphk return 0; 52712946Sphk 52812946Sphk i = show_var(name2, l2); 52912946Sphk if (!i && !bflag) 53012946Sphk putchar('\n'); 53112946Sphk 53277928Sdd memcpy(name1+2, name2, l2 * sizeof(int)); 53312946Sphk l1 = 2 + l2; 53412946Sphk } 5351553Srgrimes} 536