sysctl.c revision 48956
195584Sanholt/* 2152909Sanholt * Copyright (c) 1993 3152909Sanholt * The Regents of the University of California. All rights reserved. 495584Sanholt * 595584Sanholt * Redistribution and use in source and binary forms, with or without 695584Sanholt * modification, are permitted provided that the following conditions 795584Sanholt * are met: 895584Sanholt * 1. Redistributions of source code must retain the above copyright 995584Sanholt * notice, this list of conditions and the following disclaimer. 1095584Sanholt * 2. Redistributions in binary form must reproduce the above copyright 1195584Sanholt * notice, this list of conditions and the following disclaimer in the 1295584Sanholt * documentation and/or other materials provided with the distribution. 1395584Sanholt * 3. All advertising materials mentioning features or use of this software 1495584Sanholt * must display the following acknowledgement: 1595584Sanholt * This product includes software developed by the University of 1695584Sanholt * California, Berkeley and its contributors. 1795584Sanholt * 4. Neither the name of the University nor the names of its contributors 1895584Sanholt * may be used to endorse or promote products derived from this software 1995584Sanholt * without specific prior written permission. 2095584Sanholt * 2195584Sanholt * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2295584Sanholt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2395584Sanholt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2495584Sanholt * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2595584Sanholt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2695584Sanholt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2795584Sanholt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2895584Sanholt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29112015Sanholt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3095584Sanholt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3195584Sanholt * SUCH DAMAGE. 3295584Sanholt */ 3395584Sanholt 3495584Sanholt#ifndef lint 35152909Sanholtstatic const char copyright[] = 36152909Sanholt"@(#) Copyright (c) 1993\n\ 37152909Sanholt The Regents of the University of California. All rights reserved.\n"; 3895584Sanholt#endif /* not lint */ 3995584Sanholt 4095584Sanholt#ifndef lint 4195584Sanholt#if 0 4295584Sanholtstatic char sccsid[] = "@(#)from: sysctl.c 8.1 (Berkeley) 6/6/93"; 4395584Sanholt#endif 44112015Sanholtstatic const char rcsid[] = 4595584Sanholt "$Id: sysctl.c,v 1.20 1999/01/10 02:10:08 des Exp $"; 4695584Sanholt#endif /* not lint */ 4795584Sanholt 4895584Sanholt#include <sys/types.h> 4995584Sanholt#include <sys/stat.h> 50145132Sanholt#include <sys/sysctl.h> 51145132Sanholt#include <sys/resource.h> 52145132Sanholt 53145132Sanholt#include <ctype.h> 5495584Sanholt#include <err.h> 5595584Sanholt#include <errno.h> 5695584Sanholt#include <stdio.h> 5795584Sanholt#include <stdlib.h> 5895584Sanholt#include <string.h> 5995584Sanholt#include <unistd.h> 6095584Sanholt 6195584Sanholtstatic int Aflag, aflag, bflag, dflag, nflag, wflag, Xflag; 6295584Sanholt 6395584Sanholtstatic int oidfmt(int *, int, char *, u_int *); 6495584Sanholtstatic void parse(char *); 6595584Sanholtstatic int show_var(int *, int); 6695584Sanholtstatic int sysctl_all (int *oid, int len); 6795584Sanholtstatic int name2oid(char *, int *); 6895584Sanholt 6995584Sanholtstatic void 7095584Sanholtusage(void) 7195584Sanholt{ 72145132Sanholt 7395584Sanholt (void)fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n", 7495584Sanholt "usage: sysctl [-bdn] variable ...", 75145132Sanholt " sysctl [-bn] -w variable=value ...", 7695584Sanholt " sysctl [-bdn] -a", 7795584Sanholt " sysctl [-bdn] -A", 7895584Sanholt " sysctl [-bdn] -X"); 79152909Sanholt exit(1); 80152909Sanholt} 8195584Sanholt 8295584Sanholtint 8395584Sanholtmain(int argc, char **argv) 8495584Sanholt{ 8595584Sanholt int ch; 8695584Sanholt setbuf(stdout,0); 8795584Sanholt setbuf(stderr,0); 8895584Sanholt 8995584Sanholt while ((ch = getopt(argc, argv, "AabdnwX")) != -1) { 9095584Sanholt switch (ch) { 9195584Sanholt case 'A': Aflag = 1; break; 92145132Sanholt case 'a': aflag = 1; break; 93145132Sanholt case 'b': bflag = 1; break; 9495584Sanholt case 'd': dflag = 1; break; 95145132Sanholt case 'n': nflag = 1; break; 96145132Sanholt case 'w': wflag = 1; break; 9795584Sanholt case 'X': Xflag = Aflag = 1; break; 98145132Sanholt default: usage(); 99145132Sanholt } 10095584Sanholt } 10195584Sanholt argc -= optind; 10295584Sanholt argv += optind; 10395584Sanholt 10495584Sanholt if (wflag && (Aflag || aflag || dflag)) 10595584Sanholt usage(); 10695584Sanholt if (Aflag || aflag) 10795584Sanholt exit (sysctl_all(0, 0)); 10895584Sanholt if (argc == 0) 10995584Sanholt usage(); 11095584Sanholt while (argc-- > 0) 111298955Spfg parse(*argv++); 11295584Sanholt exit(0); 11395584Sanholt} 11495584Sanholt 11595584Sanholt/* 11695584Sanholt * Parse a name into a MIB entry. 11795584Sanholt * Lookup and print out the MIB entry if it exists. 11895584Sanholt * Set a new value if requested. 11995584Sanholt */ 12095584Sanholtstatic void 12195584Sanholtparse(char *string) 12295584Sanholt{ 12395584Sanholt int len, i, j; 124130331Sanholt void *newval = 0; 125130331Sanholt int intval, newsize = 0; 126145132Sanholt quad_t quadval; 12795584Sanholt int mib[CTL_MAXNAME]; 12895584Sanholt char *cp, *bufp, buf[BUFSIZ]; 12995584Sanholt u_int kind; 13095584Sanholt 13195584Sanholt bufp = buf; 13295584Sanholt snprintf(buf, BUFSIZ, "%s", string); 13395584Sanholt if ((cp = strchr(string, '=')) != NULL) { 13495584Sanholt if (!wflag) 13595584Sanholt errx(2, "must specify -w to set variables"); 13695584Sanholt *strchr(buf, '=') = '\0'; 13795584Sanholt *cp++ = '\0'; 13895584Sanholt while (isspace(*cp)) 13995584Sanholt cp++; 14095584Sanholt newval = cp; 14195584Sanholt newsize = strlen(cp); 14295584Sanholt } else { 14395584Sanholt if (wflag) 14495584Sanholt usage(); 14595584Sanholt } 14695584Sanholt len = name2oid(bufp, mib); 14795584Sanholt 14895584Sanholt if (len < 0) 14995584Sanholt errx(1, "unknown oid '%s'", bufp); 15095584Sanholt 15195584Sanholt if (oidfmt(mib, len, 0, &kind)) 15295584Sanholt err(1, "couldn't find format of oid '%s'", bufp); 15395584Sanholt 15495584Sanholt if (!wflag) { 15595584Sanholt if ((kind & CTLTYPE) == CTLTYPE_NODE) { 15695584Sanholt sysctl_all(mib, len); 15795584Sanholt } else { 15895584Sanholt i = show_var(mib, len); 15995584Sanholt if (!i && !bflag) 16095584Sanholt putchar('\n'); 16195584Sanholt } 16295584Sanholt } else { 16395584Sanholt if ((kind & CTLTYPE) == CTLTYPE_NODE) 16495584Sanholt errx(1, "oid '%s' isn't a leaf node", bufp); 16595584Sanholt 16695584Sanholt if (!(kind&CTLFLAG_WR)) 16795584Sanholt errx(1, "oid '%s' is read only", bufp); 16895584Sanholt 16995584Sanholt switch (kind & CTLTYPE) { 170145132Sanholt case CTLTYPE_INT: 171145132Sanholt intval = atoi(newval); 17295584Sanholt newval = &intval; 17395584Sanholt newsize = sizeof intval; 17495584Sanholt break; 17595584Sanholt break; 17695584Sanholt case CTLTYPE_STRING: 17795584Sanholt break; 178145132Sanholt case CTLTYPE_QUAD: 179145132Sanholt break; 180145132Sanholt sscanf(newval, "%qd", &quadval); 181145132Sanholt newval = &quadval; 182145132Sanholt newsize = sizeof quadval; 183145132Sanholt break; 18495584Sanholt default: 18595584Sanholt errx(1, "oid '%s' is type %d," 18695584Sanholt " cannot set that", bufp, 187182080Srnoland kind & CTLTYPE); 188145132Sanholt } 18995584Sanholt 19095584Sanholt i = show_var(mib, len); 19195584Sanholt if (sysctl(mib, len, 0, 0, newval, newsize) == -1) { 19295584Sanholt if (!i && !bflag) 19395584Sanholt putchar('\n'); 19495584Sanholt switch (errno) { 19595584Sanholt case EOPNOTSUPP: 19695584Sanholt errx(1, "%s: value is not available", 197145132Sanholt string); 198145132Sanholt case ENOTDIR: 19995584Sanholt errx(1, "%s: specification is incomplete", 200145132Sanholt string); 20195584Sanholt case ENOMEM: 202145132Sanholt errx(1, "%s: type is unknown to this program", 203145132Sanholt string); 204145132Sanholt default: 205145132Sanholt warn("%s", string); 20695584Sanholt return; 20795584Sanholt } 208182080Srnoland } 20995584Sanholt if (!bflag) 21095584Sanholt printf(" -> "); 21195584Sanholt i = nflag; 21295584Sanholt nflag = 1; 21395584Sanholt j = show_var(mib, len); 21495584Sanholt if (!j && !bflag) 21595584Sanholt putchar('\n'); 216145132Sanholt nflag = i; 21795584Sanholt } 218145132Sanholt} 21995584Sanholt 22095584Sanholt/* These functions will dump out various interesting structures. */ 22195584Sanholt 222182080Srnolandstatic int 22395584SanholtS_clockinfo(int l2, void *p) 22495584Sanholt{ 22595584Sanholt struct clockinfo *ci = (struct clockinfo*)p; 22695584Sanholt if (l2 != sizeof *ci) 227145132Sanholt err(1, "S_clockinfo %d != %d", l2, sizeof *ci); 22895584Sanholt printf("{ hz = %d, tick = %d, tickadj = %d, profhz = %d, stathz = %d }", 22995584Sanholt ci->hz, ci->tick, ci->tickadj, ci->profhz, ci->stathz); 230112015Sanholt return (0); 231112015Sanholt} 232112015Sanholt 233112015Sanholtstatic int 234130331SanholtS_loadavg(int l2, void *p) 235130331Sanholt{ 236130331Sanholt struct loadavg *tv = (struct loadavg*)p; 237130331Sanholt 238130331Sanholt if (l2 != sizeof *tv) 239130331Sanholt err(1, "S_loadavg %d != %d", l2, sizeof *tv); 240130331Sanholt 241130331Sanholt printf("{ %.2f %.2f %.2f }", 242130331Sanholt (double)tv->ldavg[0]/(double)tv->fscale, 243130331Sanholt (double)tv->ldavg[1]/(double)tv->fscale, 24495584Sanholt (double)tv->ldavg[2]/(double)tv->fscale); 245152909Sanholt return (0); 246152909Sanholt} 247152909Sanholt 248152909Sanholtstatic int 249152909SanholtS_timeval(int l2, void *p) 250152909Sanholt{ 251152909Sanholt struct timeval *tv = (struct timeval*)p; 252152909Sanholt time_t tv_sec; 253130331Sanholt char *p1, *p2; 254130331Sanholt 255130331Sanholt if (l2 != sizeof *tv) 256130331Sanholt err(1, "S_timeval %d != %d", l2, sizeof *tv); 257130331Sanholt printf("{ sec = %ld, usec = %ld } ", 258130331Sanholt tv->tv_sec, tv->tv_usec); 259130331Sanholt tv_sec = tv->tv_sec; 260130331Sanholt p1 = strdup(ctime(&tv_sec)); 261130331Sanholt for (p2=p1; *p2 ; p2++) 262130331Sanholt if (*p2 == '\n') 263152909Sanholt *p2 = '\0'; 264152909Sanholt fputs(p1, stdout); 265152909Sanholt return (0); 266130331Sanholt} 26795584Sanholt 268145132Sanholtstatic int 269145132SanholtT_dev_t(int l2, void *p) 270145132Sanholt{ 27195584Sanholt dev_t *d = (dev_t *)p; 27295584Sanholt if (l2 != sizeof *d) 27395584Sanholt err(1, "T_dev_T %d != %d", l2, sizeof *d); 274145132Sanholt printf("{ major = %d, minor = %d }", 275145132Sanholt major(*d), minor(*d)); 276145132Sanholt return (0); 27795584Sanholt} 27895584Sanholt 279145132Sanholt/* 28095584Sanholt * These functions uses a presently undocumented interface to the kernel 28195584Sanholt * to walk the tree and get the type so it can print the value. 282145132Sanholt * This interface is under work and consideration, and should probably 28395584Sanholt * be killed with a big axe by the first person who can find the time. 28495584Sanholt * (be aware though, that the proper interface isn't as obvious as it 28595584Sanholt * may seem, there are various conflicting requirements. 286145132Sanholt */ 28795584Sanholt 288145132Sanholtstatic int 28995584Sanholtname2oid(char *name, int *oidp) 290145132Sanholt{ 291145132Sanholt int oid[2]; 29295584Sanholt int i; 293145132Sanholt size_t j; 294145132Sanholt 29595584Sanholt oid[0] = 0; 29695584Sanholt oid[1] = 3; 29795584Sanholt 29895584Sanholt j = CTL_MAXNAME * sizeof (int); 29995584Sanholt i = sysctl(oid, 2, oidp, &j, name, strlen(name)); 30095584Sanholt if (i < 0) 30195584Sanholt return i; 30295584Sanholt j /= sizeof (int); 30395584Sanholt return (j); 30495584Sanholt} 305152909Sanholt 306152909Sanholtstatic int 307152909Sanholtoidfmt(int *oid, int len, char *fmt, u_int *kind) 308182080Srnoland{ 309152909Sanholt int qoid[CTL_MAXNAME+2]; 310152909Sanholt u_char buf[BUFSIZ]; 311182080Srnoland int i; 312152909Sanholt size_t j; 313152909Sanholt 314152909Sanholt qoid[0] = 0; 315152909Sanholt qoid[1] = 4; 316152909Sanholt memcpy(qoid + 2, oid, len * sizeof(int)); 317152909Sanholt 318152909Sanholt j = sizeof buf; 319152909Sanholt i = sysctl(qoid, len + 2, buf, &j, 0, 0); 320152909Sanholt if (i) 321152909Sanholt err(1, "sysctl fmt %d %d %d", i, j, errno); 322152909Sanholt 323152909Sanholt if (kind) 324152909Sanholt *kind = *(u_int *)buf; 325182080Srnoland 326152909Sanholt if (fmt) 327152909Sanholt strcpy(fmt, (char *)(buf + sizeof(u_int))); 328152909Sanholt return 0; 329152909Sanholt} 330152909Sanholt 331152909Sanholt/* 332152909Sanholt * This formats and outputs the value of one variable 333152909Sanholt * 334182080Srnoland * Returns zero if anything was actually output. 335152909Sanholt * Returns one if didn't know what to do with this. 336152909Sanholt * Return minus one if we had errors. 337152909Sanholt */ 338152909Sanholt 339152909Sanholtstatic int 340152909Sanholtshow_var(int *oid, int nlen) 341182080Srnoland{ 342182080Srnoland u_char buf[BUFSIZ], *val, *p; 343152909Sanholt char name[BUFSIZ], descr[BUFSIZ], *fmt; 344152909Sanholt int qoid[CTL_MAXNAME+2]; 345182080Srnoland int i; 346152909Sanholt size_t j, len; 347152909Sanholt u_int kind; 348152909Sanholt int (*func)(int, void *) = 0; 349152909Sanholt 350152909Sanholt qoid[0] = 0; 351152909Sanholt memcpy(qoid + 2, oid, nlen * sizeof(int)); 352152909Sanholt 353152909Sanholt qoid[1] = 1; 354152909Sanholt j = sizeof name; 355152909Sanholt i = sysctl(qoid, nlen + 2, name, &j, 0, 0); 356152909Sanholt if (i || !j) 357152909Sanholt err(1, "sysctl name %d %d %d", i, j, errno); 358182080Srnoland 359152909Sanholt if (dflag) { 360152909Sanholt qoid[1] = 5; 361152909Sanholt j = sizeof descr; 362152909Sanholt i = sysctl(qoid, nlen + 2, descr, &j, 0, 0); 363152909Sanholt if (i || !j) 364152909Sanholt err(1, "sysctl name %d %d %d", i, j, errno); 365152909Sanholt if (!nflag) 366152909Sanholt printf("%s: ", name); 367152909Sanholt printf("%s", descr[0] ? descr : "[no description]"); 368152909Sanholt return (0); 369152909Sanholt } 370152909Sanholt 371152909Sanholt /* find an estimate of how much we need for this var */ 37295584Sanholt j = 0; 37395584Sanholt i = sysctl(oid, nlen, 0, &j, 0, 0); 37495584Sanholt j += j; /* we want to be sure :-) */ 37595584Sanholt 37695584Sanholt val = alloca(j); 37795584Sanholt len = j; 37895584Sanholt i = sysctl(oid, nlen, val, &len, 0, 0); 37995584Sanholt if (i || !len) 38095584Sanholt return (1); 381145132Sanholt 382145132Sanholt if (bflag) { 383145132Sanholt fwrite(val, 1, len, stdout); 38495584Sanholt return (0); 38595584Sanholt } 38695584Sanholt 387145132Sanholt qoid[1] = 4; 38895584Sanholt j = sizeof buf; 38995584Sanholt i = sysctl(qoid, nlen + 2, buf, &j, 0, 0); 390145132Sanholt if (i || !j) 39195584Sanholt err(1, "sysctl fmt %d %d %d", i, j, errno); 39295584Sanholt 39395584Sanholt kind = *(u_int *)buf; 39495584Sanholt 39595584Sanholt fmt = (char *)(buf + sizeof(u_int)); 39695584Sanholt 39795584Sanholt p = val; 39895584Sanholt switch (*fmt) { 39995584Sanholt case 'A': 40095584Sanholt if (!nflag) 40195584Sanholt printf("%s: ", name); 40295584Sanholt printf("%s", p); 40395584Sanholt return (0); 40495584Sanholt 40595584Sanholt case 'I': 406145132Sanholt if (!nflag) 40795584Sanholt printf("%s: ", name); 40895584Sanholt val = ""; 40995584Sanholt while (len >= sizeof(int)) { 410112015Sanholt printf("%s%d", val, *(int *)p); 411145132Sanholt val = " "; 412112015Sanholt len -= sizeof (int); 413112015Sanholt p += sizeof (int); 414112015Sanholt } 415152909Sanholt return (0); 416152909Sanholt 417152909Sanholt case 'L': 418152909Sanholt if (!nflag) 419152909Sanholt printf("%s: ", name); 420152909Sanholt printf("%ld", *(long *)p); 421152909Sanholt return (0); 422152909Sanholt 423112015Sanholt case 'P': 424112015Sanholt if (!nflag) 425145132Sanholt printf("%s: ", name); 426112015Sanholt printf("%p", *(void **)p); 427112015Sanholt return (0); 42895584Sanholt 429 case 'T': 430 case 'S': 431 i = 0; 432 if (!strcmp(fmt, "S,clockinfo")) func = S_clockinfo; 433 else if (!strcmp(fmt, "S,timeval")) func = S_timeval; 434 else if (!strcmp(fmt, "S,loadavg")) func = S_loadavg; 435 else if (!strcmp(fmt, "T,dev_t")) func = T_dev_t; 436 if (func) { 437 if (!nflag) 438 printf("%s: ", name); 439 return ((*func)(len, p)); 440 } 441 /* FALL THROUGH */ 442 default: 443 if (!Aflag) 444 return (1); 445 if (!nflag) 446 printf("%s: ", name); 447 printf("Format:%s Length:%d Dump:0x", fmt, len); 448 while (len--) { 449 printf("%02x", *p++); 450 if (Xflag || p < val+16) 451 continue; 452 printf("..."); 453 break; 454 } 455 return (0); 456 } 457 return (1); 458} 459 460static int 461sysctl_all (int *oid, int len) 462{ 463 int name1[22], name2[22]; 464 int i, j; 465 size_t l1, l2; 466 467 name1[0] = 0; 468 name1[1] = 2; 469 l1 = 2; 470 if (len) { 471 memcpy(name1+2, oid, len*sizeof (int)); 472 l1 += len; 473 } else { 474 name1[2] = 1; 475 l1++; 476 } 477 while (1) { 478 l2 = sizeof name2; 479 j = sysctl(name1, l1, name2, &l2, 0, 0); 480 if (j < 0) { 481 if (errno == ENOENT) 482 return 0; 483 else 484 err(1, "sysctl(getnext) %d %d", j, l2); 485 } 486 487 l2 /= sizeof (int); 488 489 if (l2 < len) 490 return 0; 491 492 for (i = 0; i < len; i++) 493 if (name2[i] != oid[i]) 494 return 0; 495 496 i = show_var(name2, l2); 497 if (!i && !bflag) 498 putchar('\n'); 499 500 memcpy(name1+2, name2, l2*sizeof (int)); 501 l1 = 2 + l2; 502 } 503} 504