sysctl.c revision 1.5
1/* $OpenBSD: sysctl.c,v 1.5 1997/01/15 23:44:22 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.5 1997/01/15 23:44:22 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 } 325 if (flags == 0) 326 return; 327 fprintf(stderr, 328 "Use vmstat or systat to view %s information\n", string); 329 return; 330 331 case CTL_NET: 332 if (mib[1] == PF_INET) { 333 len = sysctl_inet(string, &bufp, mib, flags, &type); 334 if (len >= 0) 335 break; 336 return; 337 } 338 if (mib[1] == PF_IPX) { 339 len = sysctl_ipx(string, &bufp, mib, flags, &type); 340 if (len >= 0) 341 break; 342 return; 343 } 344 if (flags == 0) 345 return; 346 fprintf(stderr, "Use netstat to view %s information\n", string); 347 return; 348 349 case CTL_DEBUG: 350 mib[2] = CTL_DEBUG_VALUE; 351 len = 3; 352 break; 353 354 case CTL_MACHDEP: 355#ifdef CPU_CONSDEV 356 if (mib[1] == CPU_CONSDEV) 357 special |= CONSDEV; 358#endif 359 break; 360 361 case CTL_FS: 362 len = sysctl_fs(string, &bufp, mib, flags, &type); 363 if (len >= 0) 364 break; 365 return; 366 367 case CTL_USER: 368 case CTL_DDB: 369 break; 370 371 default: 372 fprintf(stderr, "Illegal top level value: %d\n", mib[0]); 373 return; 374 375 } 376 if (bufp) { 377 fprintf(stderr, "name %s in %s is unknown\n", bufp, string); 378 return; 379 } 380 if (newsize > 0) { 381 switch (type) { 382 case CTLTYPE_INT: 383 intval = atoi(newval); 384 newval = &intval; 385 newsize = sizeof intval; 386 break; 387 388 case CTLTYPE_QUAD: 389 sscanf(newval, "%qd", &quadval); 390 newval = &quadval; 391 newsize = sizeof quadval; 392 break; 393 } 394 } 395 size = BUFSIZ; 396 if (sysctl(mib, len, buf, &size, newsize ? newval : 0, newsize) == -1) { 397 if (flags == 0) 398 return; 399 switch (errno) { 400 case EOPNOTSUPP: 401 fprintf(stderr, "%s: value is not available\n", string); 402 return; 403 case ENOTDIR: 404 fprintf(stderr, "%s: specification is incomplete\n", 405 string); 406 return; 407 case ENOMEM: 408 fprintf(stderr, "%s: type is unknown to this program\n", 409 string); 410 return; 411 default: 412 perror(string); 413 return; 414 } 415 } 416 if (special & CLOCK) { 417 struct clockinfo *clkp = (struct clockinfo *)buf; 418 419 if (!nflag) 420 fprintf(stdout, "%s: ", string); 421 fprintf(stdout, 422 "tick = %d, tickadj = %d, hz = %d, profhz = %d, stathz = %d\n", 423 clkp->tick, clkp->tickadj, clkp->hz, clkp->profhz, clkp->stathz); 424 return; 425 } 426 if (special & BOOTTIME) { 427 struct timeval *btp = (struct timeval *)buf; 428 time_t boottime; 429 430 if (!nflag) { 431 boottime = btp->tv_sec; 432 fprintf(stdout, "%s = %s\n", string, ctime(&boottime)); 433 } else 434 fprintf(stdout, "%ld\n", btp->tv_sec); 435 return; 436 } 437 if (special & CONSDEV) { 438 dev_t dev = *(dev_t *)buf; 439 440 if (!nflag) 441 fprintf(stdout, "%s = %s\n", string, 442 devname(dev, S_IFCHR)); 443 else 444 fprintf(stdout, "0x%x\n", dev); 445 return; 446 } 447 switch (type) { 448 case CTLTYPE_INT: 449 if (newsize == 0) { 450 if (!nflag) 451 fprintf(stdout, "%s = ", string); 452 fprintf(stdout, "%d\n", *(int *)buf); 453 } else { 454 if (!nflag) 455 fprintf(stdout, "%s: %d -> ", string, 456 *(int *)buf); 457 fprintf(stdout, "%d\n", *(int *)newval); 458 } 459 return; 460 461 case CTLTYPE_STRING: 462 if (newsize == 0) { 463 if (!nflag) 464 fprintf(stdout, "%s = ", string); 465 fprintf(stdout, "%s\n", buf); 466 } else { 467 if (!nflag) 468 fprintf(stdout, "%s: %s -> ", string, buf); 469 fprintf(stdout, "%s\n", (char *)newval); 470 } 471 return; 472 473 case CTLTYPE_QUAD: 474 if (newsize == 0) { 475 if (!nflag) 476 fprintf(stdout, "%s = ", string); 477 fprintf(stdout, "%qd\n", *(quad_t *)buf); 478 } else { 479 if (!nflag) 480 fprintf(stdout, "%s: %qd -> ", string, 481 *(quad_t *)buf); 482 fprintf(stdout, "%qd\n", *(quad_t *)newval); 483 } 484 return; 485 486 case CTLTYPE_STRUCT: 487 fprintf(stderr, "%s: unknown structure returned\n", 488 string); 489 return; 490 491 default: 492 case CTLTYPE_NODE: 493 fprintf(stderr, "%s: unknown type returned\n", 494 string); 495 return; 496 } 497} 498 499/* 500 * Initialize the set of debugging names 501 */ 502void 503debuginit() 504{ 505 int mib[3], loc, i; 506 size_t size; 507 508 if (secondlevel[CTL_DEBUG].list != 0) 509 return; 510 secondlevel[CTL_DEBUG].list = debugname; 511 mib[0] = CTL_DEBUG; 512 mib[2] = CTL_DEBUG_NAME; 513 for (loc = 0, i = 0; i < CTL_DEBUG_MAXID; i++) { 514 mib[1] = i; 515 size = BUFSIZ - loc; 516 if (sysctl(mib, 3, &names[loc], &size, NULL, 0) == -1) 517 continue; 518 debugname[i].ctl_name = &names[loc]; 519 debugname[i].ctl_type = CTLTYPE_INT; 520 loc += size; 521 } 522} 523 524struct ctlname posixname[] = CTL_FS_POSIX_NAMES; 525struct list fslist = { posixname, FS_POSIX_MAXID }; 526 527/* 528 * handle file system requests 529 */ 530int 531sysctl_fs(string, bufpp, mib, flags, typep) 532 char *string; 533 char **bufpp; 534 int mib[]; 535 int flags; 536 int *typep; 537{ 538 int indx; 539 540 if (*bufpp == NULL) { 541 listall(string, &fslist); 542 return (-1); 543 } 544 if ((indx = findname(string, "third", bufpp, &fslist)) == -1) 545 return (-1); 546 mib[2] = indx; 547 *typep = fslist.list[indx].ctl_type; 548 return (3); 549} 550 551struct ctlname inetname[] = CTL_IPPROTO_NAMES; 552struct ctlname ipname[] = IPCTL_NAMES; 553struct ctlname icmpname[] = ICMPCTL_NAMES; 554struct ctlname tcpname[] = TCPCTL_NAMES; 555struct ctlname udpname[] = UDPCTL_NAMES; 556struct list inetlist = { inetname, IPPROTO_MAXID }; 557struct list inetvars[] = { 558 { ipname, IPCTL_MAXID }, /* ip */ 559 { icmpname, ICMPCTL_MAXID }, /* icmp */ 560 { 0, 0 }, /* igmp */ 561 { 0, 0 }, /* ggmp */ 562 { 0, 0 }, 563 { 0, 0 }, 564 { tcpname, TCPCTL_MAXID }, /* tcp */ 565 { 0, 0 }, 566 { 0, 0 }, /* egp */ 567 { 0, 0 }, 568 { 0, 0 }, 569 { 0, 0 }, 570 { 0, 0 }, /* pup */ 571 { 0, 0 }, 572 { 0, 0 }, 573 { 0, 0 }, 574 { 0, 0 }, 575 { udpname, UDPCTL_MAXID }, /* udp */ 576}; 577 578/* 579 * handle internet requests 580 */ 581int 582sysctl_inet(string, bufpp, mib, flags, typep) 583 char *string; 584 char **bufpp; 585 int mib[]; 586 int flags; 587 int *typep; 588{ 589 struct list *lp; 590 int indx; 591 592 if (*bufpp == NULL) { 593 listall(string, &inetlist); 594 return (-1); 595 } 596 if ((indx = findname(string, "third", bufpp, &inetlist)) == -1) 597 return (-1); 598 mib[2] = indx; 599 if (indx <= IPPROTO_UDP && inetvars[indx].list != NULL) 600 lp = &inetvars[indx]; 601 else if (!flags) 602 return (-1); 603 else { 604 fprintf(stderr, "%s: no variables defined for this protocol\n", 605 string); 606 return (-1); 607 } 608 if (*bufpp == NULL) { 609 listall(string, lp); 610 return (-1); 611 } 612 if ((indx = findname(string, "fourth", bufpp, lp)) == -1) 613 return (-1); 614 mib[3] = indx; 615 *typep = lp->list[indx].ctl_type; 616 return (4); 617} 618 619struct ctlname ipxname[] = CTL_IPXPROTO_NAMES; 620struct ctlname ipxpname[] = IPXCTL_NAMES; 621struct ctlname spxpname[] = SPXCTL_NAMES; 622struct list ipxlist = { ipxname, IPXCTL_MAXID }; 623struct list ipxvars[] = { 624 { ipxpname, IPXCTL_MAXID }, /* ipx */ 625 { 0, 0 }, 626 { 0, 0 }, 627 { 0, 0 }, 628 { 0, 0 }, 629 { spxpname, SPXCTL_MAXID }, 630}; 631 632/* 633 * handle internet requests 634 */ 635int 636sysctl_ipx(string, bufpp, mib, flags, typep) 637 char *string; 638 char **bufpp; 639 int mib[]; 640 int flags; 641 int *typep; 642{ 643 struct list *lp; 644 int indx; 645 646 if (*bufpp == NULL) { 647 listall(string, &ipxlist); 648 return (-1); 649 } 650 if ((indx = findname(string, "third", bufpp, &ipxlist)) == -1) 651 return (-1); 652 mib[2] = indx; 653 if (indx <= IPXPROTO_SPX && ipxvars[indx].list != NULL) 654 lp = &ipxvars[indx]; 655 else if (!flags) 656 return (-1); 657 else { 658 fprintf(stderr, "%s: no variables defined for this protocol\n", 659 string); 660 return (-1); 661 } 662 if (*bufpp == NULL) { 663 listall(string, lp); 664 return (-1); 665 } 666 if ((indx = findname(string, "fourth", bufpp, lp)) == -1) 667 return (-1); 668 mib[3] = indx; 669 *typep = lp->list[indx].ctl_type; 670 return (4); 671} 672 673/* 674 * Scan a list of names searching for a particular name. 675 */ 676int 677findname(string, level, bufp, namelist) 678 char *string; 679 char *level; 680 char **bufp; 681 struct list *namelist; 682{ 683 char *name; 684 int i; 685 686 if (namelist->list == 0 || (name = strsep(bufp, ".")) == NULL) { 687 fprintf(stderr, "%s: incomplete specification\n", string); 688 return (-1); 689 } 690 for (i = 0; i < namelist->size; i++) 691 if (namelist->list[i].ctl_name != NULL && 692 strcmp(name, namelist->list[i].ctl_name) == 0) 693 break; 694 if (i == namelist->size) { 695 fprintf(stderr, "%s level name %s in %s is invalid\n", 696 level, name, string); 697 return (-1); 698 } 699 return (i); 700} 701 702void 703usage() 704{ 705 706 (void)fprintf(stderr, "usage:\t%s\n\t%s\n\t%s\n\t%s\n", 707 "sysctl [-n] variable ...", "sysctl [-n] -w variable=value ...", 708 "sysctl [-n] -a", "sysctl [-n] -A"); 709 exit(1); 710} 711