sysctl.c revision 1.6
1/* $OpenBSD: sysctl.c,v 1.6 1997/01/16 03:57:31 millert 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.6 1997/01/16 03:57:31 millert 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 <netinet/in.h> 60#include <netinet/in_systm.h> 61#include <netinet/ip.h> 62#include <netinet/ip_icmp.h> 63#include <netinet/icmp_var.h> 64#include <netinet/ip_var.h> 65#include <netinet/udp.h> 66#include <netinet/udp_var.h> 67#include <netinet/tcp.h> 68#include <netinet/tcp_timer.h> 69#include <netinet/tcp_var.h> 70 71#include <netipx/ipx.h> 72#include <netipx/ipx_var.h> 73#include <netipx/spx_var.h> 74#include <ddb/db_var.h> 75 76#include <errno.h> 77#include <stdio.h> 78#include <stdlib.h> 79#include <string.h> 80#include <ctype.h> 81 82struct ctlname topname[] = CTL_NAMES; 83struct ctlname kernname[] = CTL_KERN_NAMES; 84struct ctlname vmname[] = CTL_VM_NAMES; 85struct ctlname fsname[] = CTL_FS_NAMES; 86struct ctlname netname[] = CTL_NET_NAMES; 87struct ctlname hwname[] = CTL_HW_NAMES; 88struct ctlname username[] = CTL_USER_NAMES; 89struct ctlname debugname[CTL_DEBUG_MAXID]; 90#ifdef CTL_MACHDEP_NAMES 91struct ctlname machdepname[] = CTL_MACHDEP_NAMES; 92#endif 93struct ctlname ddbname[] = CTL_DDB_NAMES; 94char names[BUFSIZ]; 95 96struct list { 97 struct ctlname *list; 98 int size; 99}; 100struct list toplist = { topname, CTL_MAXID }; 101struct list secondlevel[] = { 102 { 0, 0 }, /* CTL_UNSPEC */ 103 { kernname, KERN_MAXID }, /* CTL_KERN */ 104 { vmname, VM_MAXID }, /* CTL_VM */ 105 { fsname, FS_MAXID }, /* CTL_FS */ 106 { netname, NET_MAXID }, /* CTL_NET */ 107 { 0, CTL_DEBUG_MAXID }, /* CTL_DEBUG */ 108 { hwname, HW_MAXID }, /* CTL_HW */ 109#ifdef CTL_MACHDEP_NAMES 110 { machdepname, CPU_MAXID }, /* CTL_MACHDEP */ 111#else 112 { 0, 0 }, /* CTL_MACHDEP */ 113#endif 114 { username, USER_MAXID }, /* CTL_USER_NAMES */ 115 { ddbname, DBCTL_MAXID }, /* CTL_DDB_NAMES */ 116}; 117 118int Aflag, aflag, nflag, wflag; 119 120/* 121 * Variables requiring special processing. 122 */ 123#define CLOCK 0x00000001 124#define BOOTTIME 0x00000002 125#define CONSDEV 0x00000004 126 127/* prototypes */ 128void usage(); 129void debuginit(); 130void parse __P(( char *string, int flags)); 131void listall __P((char *prefix, struct list *lp)); 132int findname __P((char *string, char *level, char **bufp, struct list *namelist)); 133int sysctl_inet __P((char *string, char **bufpp, int mib[], int flags, int *typep)); 134int sysctl_ipx __P((char *string, char **bufpp, int mib[], int flags, int *typep)); 135int sysctl_fs __P((char *string, char **bufpp, int mib[], int flags, int *typep)); 136 137int 138main(argc, argv) 139 int argc; 140 char *argv[]; 141{ 142 extern char *optarg; 143 extern int optind; 144 int ch, lvl1; 145 146 while ((ch = getopt(argc, argv, "Aanw")) != -1) { 147 switch (ch) { 148 149 case 'A': 150 Aflag = 1; 151 break; 152 153 case 'a': 154 aflag = 1; 155 break; 156 157 case 'n': 158 nflag = 1; 159 break; 160 161 case 'w': 162 wflag = 1; 163 break; 164 165 default: 166 usage(); 167 } 168 } 169 argc -= optind; 170 argv += optind; 171 172 if (Aflag || aflag) { 173 debuginit(); 174 for (lvl1 = 1; lvl1 < CTL_MAXID; lvl1++) 175 listall(topname[lvl1].ctl_name, &secondlevel[lvl1]); 176 exit(0); 177 } 178 if (argc == 0) 179 usage(); 180 while (argc-- > 0) 181 parse(*argv++, 1); 182 exit(0); 183} 184 185/* 186 * List all variables known to the system. 187 */ 188void 189listall(prefix, lp) 190 char *prefix; 191 struct list *lp; 192{ 193 int lvl2; 194 char *cp, name[BUFSIZ]; 195 196 if (lp->list == 0) 197 return; 198 strncpy(name, prefix, BUFSIZ-1); 199 cp = &name[strlen(name)]; 200 *cp++ = '.'; 201 for (lvl2 = 0; lvl2 < lp->size; lvl2++) { 202 if (lp->list[lvl2].ctl_name == 0) 203 continue; 204 strcpy(cp, lp->list[lvl2].ctl_name); 205 parse(name, Aflag); 206 } 207} 208 209/* 210 * Parse a name into a MIB entry. 211 * Lookup and print out the MIB entry if it exists. 212 * Set a new value if requested. 213 */ 214void 215parse(string, flags) 216 char *string; 217 int flags; 218{ 219 int indx, type, state, len; 220 int special = 0; 221 void *newval = 0; 222 int intval, newsize = 0; 223 quad_t quadval; 224 size_t size; 225 struct list *lp; 226 int mib[CTL_MAXNAME]; 227 char *cp, *bufp, buf[BUFSIZ]; 228 229 bufp = buf; 230 snprintf(buf, BUFSIZ, "%s", string); 231 if ((cp = strchr(string, '=')) != NULL) { 232 if (!wflag) { 233 fprintf(stderr, "Must specify -w to set variables\n"); 234 exit(2); 235 } 236 *strchr(buf, '=') = '\0'; 237 *cp++ = '\0'; 238 while (isspace(*cp)) 239 cp++; 240 newval = cp; 241 newsize = strlen(cp); 242 } 243 if ((indx = findname(string, "top", &bufp, &toplist)) == -1) 244 return; 245 mib[0] = indx; 246 if (indx == CTL_DEBUG) 247 debuginit(); 248 lp = &secondlevel[indx]; 249 if (lp->list == 0) { 250 fprintf(stderr, "%s: class is not implemented\n", 251 topname[indx].ctl_name); 252 return; 253 } 254 if (bufp == NULL) { 255 listall(topname[indx].ctl_name, lp); 256 return; 257 } 258 if ((indx = findname(string, "second", &bufp, lp)) == -1) 259 return; 260 mib[1] = indx; 261 type = lp->list[indx].ctl_type; 262 len = 2; 263 switch (mib[0]) { 264 265 case CTL_KERN: 266 switch (mib[1]) { 267 case KERN_PROF: 268 mib[2] = GPROF_STATE; 269 size = sizeof state; 270 if (sysctl(mib, 3, &state, &size, NULL, 0) < 0) { 271 if (flags == 0) 272 return; 273 if (!nflag) 274 fprintf(stdout, "%s: ", string); 275 fprintf(stderr, 276 "kernel is not compiled for profiling\n"); 277 return; 278 } 279 if (!nflag) 280 fprintf(stdout, "%s: %s\n", string, 281 state == GMON_PROF_OFF ? "off" : "running"); 282 return; 283 case KERN_VNODE: 284 case KERN_FILE: 285 if (flags == 0) 286 return; 287 fprintf(stderr, 288 "Use pstat to view %s information\n", string); 289 return; 290 case KERN_PROC: 291 if (flags == 0) 292 return; 293 fprintf(stderr, 294 "Use ps to view %s information\n", string); 295 return; 296 case KERN_NTPTIME: 297 if (flags == 0) 298 return; 299 fprintf(stderr, 300 "Use xntpd to view %s information\n", string); 301 return; 302 case KERN_CLOCKRATE: 303 special |= CLOCK; 304 break; 305 case KERN_BOOTTIME: 306 special |= BOOTTIME; 307 break; 308 } 309 break; 310 311 case CTL_HW: 312 break; 313 314 case CTL_VM: 315 if (mib[1] == VM_LOADAVG) { 316 double loads[3]; 317 318 getloadavg(loads, 3); 319 if (!nflag) 320 fprintf(stdout, "%s: ", string); 321 fprintf(stdout, "%.2f %.2f %.2f\n", 322 loads[0], loads[1], loads[2]); 323 return; 324 } else if (mib[1] == VM_PSSTRINGS) { 325 struct _ps_strings _ps; 326 327 len = sizeof(_ps); 328 sysctl(mib, 2, &_ps, &len, NULL, 0); 329 if (!nflag) 330 fprintf(stdout, "%s: ", string); 331 fprintf(stdout, "%ld\n", _ps.val); 332 return; 333 } 334 if (flags == 0) 335 return; 336 fprintf(stderr, 337 "Use vmstat or systat to view %s information\n", string); 338 return; 339 340 case CTL_NET: 341 if (mib[1] == PF_INET) { 342 len = sysctl_inet(string, &bufp, mib, flags, &type); 343 if (len >= 0) 344 break; 345 return; 346 } 347 if (mib[1] == PF_IPX) { 348 len = sysctl_ipx(string, &bufp, mib, flags, &type); 349 if (len >= 0) 350 break; 351 return; 352 } 353 if (flags == 0) 354 return; 355 fprintf(stderr, "Use netstat to view %s information\n", string); 356 return; 357 358 case CTL_DEBUG: 359 mib[2] = CTL_DEBUG_VALUE; 360 len = 3; 361 break; 362 363 case CTL_MACHDEP: 364#ifdef CPU_CONSDEV 365 if (mib[1] == CPU_CONSDEV) 366 special |= CONSDEV; 367#endif 368 break; 369 370 case CTL_FS: 371 len = sysctl_fs(string, &bufp, mib, flags, &type); 372 if (len >= 0) 373 break; 374 return; 375 376 case CTL_USER: 377 case CTL_DDB: 378 break; 379 380 default: 381 fprintf(stderr, "Illegal top level value: %d\n", mib[0]); 382 return; 383 384 } 385 if (bufp) { 386 fprintf(stderr, "name %s in %s is unknown\n", bufp, string); 387 return; 388 } 389 if (newsize > 0) { 390 switch (type) { 391 case CTLTYPE_INT: 392 intval = atoi(newval); 393 newval = &intval; 394 newsize = sizeof intval; 395 break; 396 397 case CTLTYPE_QUAD: 398 sscanf(newval, "%qd", &quadval); 399 newval = &quadval; 400 newsize = sizeof quadval; 401 break; 402 } 403 } 404 size = BUFSIZ; 405 if (sysctl(mib, len, buf, &size, newsize ? newval : 0, newsize) == -1) { 406 if (flags == 0) 407 return; 408 switch (errno) { 409 case EOPNOTSUPP: 410 fprintf(stderr, "%s: value is not available\n", string); 411 return; 412 case ENOTDIR: 413 fprintf(stderr, "%s: specification is incomplete\n", 414 string); 415 return; 416 case ENOMEM: 417 fprintf(stderr, "%s: type is unknown to this program\n", 418 string); 419 return; 420 default: 421 perror(string); 422 return; 423 } 424 } 425 if (special & CLOCK) { 426 struct clockinfo *clkp = (struct clockinfo *)buf; 427 428 if (!nflag) 429 fprintf(stdout, "%s: ", string); 430 fprintf(stdout, 431 "tick = %d, tickadj = %d, hz = %d, profhz = %d, stathz = %d\n", 432 clkp->tick, clkp->tickadj, clkp->hz, clkp->profhz, clkp->stathz); 433 return; 434 } 435 if (special & BOOTTIME) { 436 struct timeval *btp = (struct timeval *)buf; 437 time_t boottime; 438 439 if (!nflag) { 440 boottime = btp->tv_sec; 441 fprintf(stdout, "%s = %s\n", string, ctime(&boottime)); 442 } else 443 fprintf(stdout, "%ld\n", btp->tv_sec); 444 return; 445 } 446 if (special & CONSDEV) { 447 dev_t dev = *(dev_t *)buf; 448 449 if (!nflag) 450 fprintf(stdout, "%s = %s\n", string, 451 devname(dev, S_IFCHR)); 452 else 453 fprintf(stdout, "0x%x\n", dev); 454 return; 455 } 456 switch (type) { 457 case CTLTYPE_INT: 458 if (newsize == 0) { 459 if (!nflag) 460 fprintf(stdout, "%s = ", string); 461 fprintf(stdout, "%d\n", *(int *)buf); 462 } else { 463 if (!nflag) 464 fprintf(stdout, "%s: %d -> ", string, 465 *(int *)buf); 466 fprintf(stdout, "%d\n", *(int *)newval); 467 } 468 return; 469 470 case CTLTYPE_STRING: 471 if (newsize == 0) { 472 if (!nflag) 473 fprintf(stdout, "%s = ", string); 474 fprintf(stdout, "%s\n", buf); 475 } else { 476 if (!nflag) 477 fprintf(stdout, "%s: %s -> ", string, buf); 478 fprintf(stdout, "%s\n", (char *)newval); 479 } 480 return; 481 482 case CTLTYPE_QUAD: 483 if (newsize == 0) { 484 if (!nflag) 485 fprintf(stdout, "%s = ", string); 486 fprintf(stdout, "%qd\n", *(quad_t *)buf); 487 } else { 488 if (!nflag) 489 fprintf(stdout, "%s: %qd -> ", string, 490 *(quad_t *)buf); 491 fprintf(stdout, "%qd\n", *(quad_t *)newval); 492 } 493 return; 494 495 case CTLTYPE_STRUCT: 496 fprintf(stderr, "%s: unknown structure returned\n", 497 string); 498 return; 499 500 default: 501 case CTLTYPE_NODE: 502 fprintf(stderr, "%s: unknown type returned\n", 503 string); 504 return; 505 } 506} 507 508/* 509 * Initialize the set of debugging names 510 */ 511void 512debuginit() 513{ 514 int mib[3], loc, i; 515 size_t size; 516 517 if (secondlevel[CTL_DEBUG].list != 0) 518 return; 519 secondlevel[CTL_DEBUG].list = debugname; 520 mib[0] = CTL_DEBUG; 521 mib[2] = CTL_DEBUG_NAME; 522 for (loc = 0, i = 0; i < CTL_DEBUG_MAXID; i++) { 523 mib[1] = i; 524 size = BUFSIZ - loc; 525 if (sysctl(mib, 3, &names[loc], &size, NULL, 0) == -1) 526 continue; 527 debugname[i].ctl_name = &names[loc]; 528 debugname[i].ctl_type = CTLTYPE_INT; 529 loc += size; 530 } 531} 532 533struct ctlname posixname[] = CTL_FS_POSIX_NAMES; 534struct list fslist = { posixname, FS_POSIX_MAXID }; 535 536/* 537 * handle file system requests 538 */ 539int 540sysctl_fs(string, bufpp, mib, flags, typep) 541 char *string; 542 char **bufpp; 543 int mib[]; 544 int flags; 545 int *typep; 546{ 547 int indx; 548 549 if (*bufpp == NULL) { 550 listall(string, &fslist); 551 return (-1); 552 } 553 if ((indx = findname(string, "third", bufpp, &fslist)) == -1) 554 return (-1); 555 mib[2] = indx; 556 *typep = fslist.list[indx].ctl_type; 557 return (3); 558} 559 560struct ctlname inetname[] = CTL_IPPROTO_NAMES; 561struct ctlname ipname[] = IPCTL_NAMES; 562struct ctlname icmpname[] = ICMPCTL_NAMES; 563struct ctlname tcpname[] = TCPCTL_NAMES; 564struct ctlname udpname[] = UDPCTL_NAMES; 565struct list inetlist = { inetname, IPPROTO_MAXID }; 566struct list inetvars[] = { 567 { ipname, IPCTL_MAXID }, /* ip */ 568 { icmpname, ICMPCTL_MAXID }, /* icmp */ 569 { 0, 0 }, /* igmp */ 570 { 0, 0 }, /* ggmp */ 571 { 0, 0 }, 572 { 0, 0 }, 573 { tcpname, TCPCTL_MAXID }, /* tcp */ 574 { 0, 0 }, 575 { 0, 0 }, /* egp */ 576 { 0, 0 }, 577 { 0, 0 }, 578 { 0, 0 }, 579 { 0, 0 }, /* pup */ 580 { 0, 0 }, 581 { 0, 0 }, 582 { 0, 0 }, 583 { 0, 0 }, 584 { udpname, UDPCTL_MAXID }, /* udp */ 585}; 586 587/* 588 * handle internet requests 589 */ 590int 591sysctl_inet(string, bufpp, mib, flags, typep) 592 char *string; 593 char **bufpp; 594 int mib[]; 595 int flags; 596 int *typep; 597{ 598 struct list *lp; 599 int indx; 600 601 if (*bufpp == NULL) { 602 listall(string, &inetlist); 603 return (-1); 604 } 605 if ((indx = findname(string, "third", bufpp, &inetlist)) == -1) 606 return (-1); 607 mib[2] = indx; 608 if (indx <= IPPROTO_UDP && inetvars[indx].list != NULL) 609 lp = &inetvars[indx]; 610 else if (!flags) 611 return (-1); 612 else { 613 fprintf(stderr, "%s: no variables defined for this protocol\n", 614 string); 615 return (-1); 616 } 617 if (*bufpp == NULL) { 618 listall(string, lp); 619 return (-1); 620 } 621 if ((indx = findname(string, "fourth", bufpp, lp)) == -1) 622 return (-1); 623 mib[3] = indx; 624 *typep = lp->list[indx].ctl_type; 625 return (4); 626} 627 628struct ctlname ipxname[] = CTL_IPXPROTO_NAMES; 629struct ctlname ipxpname[] = IPXCTL_NAMES; 630struct ctlname spxpname[] = SPXCTL_NAMES; 631struct list ipxlist = { ipxname, IPXCTL_MAXID }; 632struct list ipxvars[] = { 633 { ipxpname, IPXCTL_MAXID }, /* ipx */ 634 { 0, 0 }, 635 { 0, 0 }, 636 { 0, 0 }, 637 { 0, 0 }, 638 { spxpname, SPXCTL_MAXID }, 639}; 640 641/* 642 * handle internet requests 643 */ 644int 645sysctl_ipx(string, bufpp, mib, flags, typep) 646 char *string; 647 char **bufpp; 648 int mib[]; 649 int flags; 650 int *typep; 651{ 652 struct list *lp; 653 int indx; 654 655 if (*bufpp == NULL) { 656 listall(string, &ipxlist); 657 return (-1); 658 } 659 if ((indx = findname(string, "third", bufpp, &ipxlist)) == -1) 660 return (-1); 661 mib[2] = indx; 662 if (indx <= IPXPROTO_SPX && ipxvars[indx].list != NULL) 663 lp = &ipxvars[indx]; 664 else if (!flags) 665 return (-1); 666 else { 667 fprintf(stderr, "%s: no variables defined for this protocol\n", 668 string); 669 return (-1); 670 } 671 if (*bufpp == NULL) { 672 listall(string, lp); 673 return (-1); 674 } 675 if ((indx = findname(string, "fourth", bufpp, lp)) == -1) 676 return (-1); 677 mib[3] = indx; 678 *typep = lp->list[indx].ctl_type; 679 return (4); 680} 681 682/* 683 * Scan a list of names searching for a particular name. 684 */ 685int 686findname(string, level, bufp, namelist) 687 char *string; 688 char *level; 689 char **bufp; 690 struct list *namelist; 691{ 692 char *name; 693 int i; 694 695 if (namelist->list == 0 || (name = strsep(bufp, ".")) == NULL) { 696 fprintf(stderr, "%s: incomplete specification\n", string); 697 return (-1); 698 } 699 for (i = 0; i < namelist->size; i++) 700 if (namelist->list[i].ctl_name != NULL && 701 strcmp(name, namelist->list[i].ctl_name) == 0) 702 break; 703 if (i == namelist->size) { 704 fprintf(stderr, "%s level name %s in %s is invalid\n", 705 level, name, string); 706 return (-1); 707 } 708 return (i); 709} 710 711void 712usage() 713{ 714 715 (void)fprintf(stderr, "usage:\t%s\n\t%s\n\t%s\n\t%s\n", 716 "sysctl [-n] variable ...", "sysctl [-n] -w variable=value ...", 717 "sysctl [-n] -a", "sysctl [-n] -A"); 718 exit(1); 719} 720