sysctl.c revision 1.3
1/* $NetBSD: sysctl.c,v 1.9 1995/09/30 07:12:50 thorpej Exp $ */ 2 3/* 4 * Copyright (c) 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36#ifndef lint 37static char copyright[] = 38"@(#) Copyright (c) 1993\n\ 39 The Regents of the University of California. All rights reserved.\n"; 40#endif /* not lint */ 41 42#ifndef lint 43#if 0 44static char sccsid[] = "@(#)sysctl.c 8.1 (Berkeley) 6/6/93"; 45#else 46static char *rcsid = "$NetBSD: sysctl.c,v 1.9 1995/09/30 07:12:50 thorpej Exp $"; 47#endif 48#endif /* not lint */ 49 50#include <sys/param.h> 51#include <sys/gmon.h> 52#include <sys/stat.h> 53#include <sys/sysctl.h> 54#include <sys/socket.h> 55#include <vm/vm_param.h> 56#include <machine/cpu.h> 57 58#include <netinet/in.h> 59#include <netinet/in_systm.h> 60#include <netinet/ip.h> 61#include <netinet/ip_icmp.h> 62#include <netinet/icmp_var.h> 63#include <netinet/ip_var.h> 64#include <netinet/udp.h> 65#include <netinet/udp_var.h> 66#include <netinet/tcp.h> 67#include <netinet/tcp_timer.h> 68#include <netinet/tcp_var.h> 69#include <ddb/db_var.h> 70 71#include <errno.h> 72#include <stdio.h> 73#include <stdlib.h> 74#include <string.h> 75 76struct ctlname topname[] = CTL_NAMES; 77struct ctlname kernname[] = CTL_KERN_NAMES; 78struct ctlname vmname[] = CTL_VM_NAMES; 79struct ctlname fsname[] = CTL_FS_NAMES; 80struct ctlname netname[] = CTL_NET_NAMES; 81struct ctlname hwname[] = CTL_HW_NAMES; 82struct ctlname username[] = CTL_USER_NAMES; 83struct ctlname debugname[CTL_DEBUG_MAXID]; 84#ifdef CTL_MACHDEP_NAMES 85struct ctlname machdepname[] = CTL_MACHDEP_NAMES; 86#endif 87struct ctlname ddbname[] = CTL_DDB_NAMES; 88char names[BUFSIZ]; 89 90struct list { 91 struct ctlname *list; 92 int size; 93}; 94struct list toplist = { topname, CTL_MAXID }; 95struct list secondlevel[] = { 96 { 0, 0 }, /* CTL_UNSPEC */ 97 { kernname, KERN_MAXID }, /* CTL_KERN */ 98 { vmname, VM_MAXID }, /* CTL_VM */ 99 { fsname, FS_MAXID }, /* CTL_FS */ 100 { netname, NET_MAXID }, /* CTL_NET */ 101 { 0, CTL_DEBUG_MAXID }, /* CTL_DEBUG */ 102 { hwname, HW_MAXID }, /* CTL_HW */ 103#ifdef CTL_MACHDEP_NAMES 104 { machdepname, CPU_MAXID }, /* CTL_MACHDEP */ 105#else 106 { 0, 0 }, /* CTL_MACHDEP */ 107#endif 108 { username, USER_MAXID }, /* CTL_USER_NAMES */ 109 { ddbname, DBCTL_MAXID }, /* CTL_DDB_NAMES */ 110}; 111 112int Aflag, aflag, nflag, wflag; 113 114/* 115 * Variables requiring special processing. 116 */ 117#define CLOCK 0x00000001 118#define BOOTTIME 0x00000002 119#define CONSDEV 0x00000004 120 121int 122main(argc, argv) 123 int argc; 124 char *argv[]; 125{ 126 extern char *optarg; 127 extern int optind; 128 int ch, lvl1; 129 130 while ((ch = getopt(argc, argv, "Aanw")) != EOF) { 131 switch (ch) { 132 133 case 'A': 134 Aflag = 1; 135 break; 136 137 case 'a': 138 aflag = 1; 139 break; 140 141 case 'n': 142 nflag = 1; 143 break; 144 145 case 'w': 146 wflag = 1; 147 break; 148 149 default: 150 usage(); 151 } 152 } 153 argc -= optind; 154 argv += optind; 155 156 if (Aflag || aflag) { 157 debuginit(); 158 for (lvl1 = 1; lvl1 < CTL_MAXID; lvl1++) 159 listall(topname[lvl1].ctl_name, &secondlevel[lvl1]); 160 exit(0); 161 } 162 if (argc == 0) 163 usage(); 164 while (argc-- > 0) 165 parse(*argv++, 1); 166 exit(0); 167} 168 169/* 170 * List all variables known to the system. 171 */ 172listall(prefix, lp) 173 char *prefix; 174 struct list *lp; 175{ 176 int lvl2; 177 char *cp, name[BUFSIZ]; 178 179 if (lp->list == 0) 180 return; 181 strcpy(name, prefix); 182 cp = &name[strlen(name)]; 183 *cp++ = '.'; 184 for (lvl2 = 0; lvl2 < lp->size; lvl2++) { 185 if (lp->list[lvl2].ctl_name == 0) 186 continue; 187 strcpy(cp, lp->list[lvl2].ctl_name); 188 parse(name, Aflag); 189 } 190} 191 192/* 193 * Parse a name into a MIB entry. 194 * Lookup and print out the MIB entry if it exists. 195 * Set a new value if requested. 196 */ 197parse(string, flags) 198 char *string; 199 int flags; 200{ 201 int indx, type, state, len; 202 int special = 0; 203 void *newval = 0; 204 int intval, newsize = 0; 205 quad_t quadval; 206 size_t size; 207 struct list *lp; 208 int mib[CTL_MAXNAME]; 209 char *cp, *bufp, buf[BUFSIZ], strval[BUFSIZ]; 210 211 bufp = buf; 212 snprintf(buf, BUFSIZ, "%s", string); 213 if ((cp = strchr(string, '=')) != NULL) { 214 if (!wflag) { 215 fprintf(stderr, "Must specify -w to set variables\n"); 216 exit(2); 217 } 218 *strchr(buf, '=') = '\0'; 219 *cp++ = '\0'; 220 while (isspace(*cp)) 221 cp++; 222 newval = cp; 223 newsize = strlen(cp); 224 } 225 if ((indx = findname(string, "top", &bufp, &toplist)) == -1) 226 return; 227 mib[0] = indx; 228 if (indx == CTL_DEBUG) 229 debuginit(); 230 lp = &secondlevel[indx]; 231 if (lp->list == 0) { 232 fprintf(stderr, "%s: class is not implemented\n", 233 topname[indx]); 234 return; 235 } 236 if (bufp == NULL) { 237 listall(topname[indx].ctl_name, lp); 238 return; 239 } 240 if ((indx = findname(string, "second", &bufp, lp)) == -1) 241 return; 242 mib[1] = indx; 243 type = lp->list[indx].ctl_type; 244 len = 2; 245 switch (mib[0]) { 246 247 case CTL_KERN: 248 switch (mib[1]) { 249 case KERN_PROF: 250 mib[2] = GPROF_STATE; 251 size = sizeof state; 252 if (sysctl(mib, 3, &state, &size, NULL, 0) < 0) { 253 if (flags == 0) 254 return; 255 if (!nflag) 256 fprintf(stdout, "%s: ", string); 257 fprintf(stderr, 258 "kernel is not compiled for profiling\n"); 259 return; 260 } 261 if (!nflag) 262 fprintf(stdout, "%s: %s\n", string, 263 state == GMON_PROF_OFF ? "off" : "running"); 264 return; 265 case KERN_VNODE: 266 case KERN_FILE: 267 if (flags == 0) 268 return; 269 fprintf(stderr, 270 "Use pstat to view %s information\n", string); 271 return; 272 case KERN_PROC: 273 if (flags == 0) 274 return; 275 fprintf(stderr, 276 "Use ps to view %s information\n", string); 277 return; 278 case KERN_NTPTIME: 279 if (flags == 0) 280 return; 281 fprintf(stderr, 282 "Use xntpd to view %s information\n", string); 283 return; 284 case KERN_CLOCKRATE: 285 special |= CLOCK; 286 break; 287 case KERN_BOOTTIME: 288 special |= BOOTTIME; 289 break; 290 } 291 break; 292 293 case CTL_HW: 294 break; 295 296 case CTL_VM: 297 if (mib[1] == VM_LOADAVG) { 298 double loads[3]; 299 300 getloadavg(loads, 3); 301 if (!nflag) 302 fprintf(stdout, "%s: ", string); 303 fprintf(stdout, "%.2f %.2f %.2f\n", 304 loads[0], loads[1], loads[2]); 305 return; 306 } 307 if (flags == 0) 308 return; 309 fprintf(stderr, 310 "Use vmstat or systat to view %s information\n", string); 311 return; 312 313 case CTL_NET: 314 if (mib[1] == PF_INET) { 315 len = sysctl_inet(string, &bufp, mib, flags, &type); 316 if (len >= 0) 317 break; 318 return; 319 } 320 if (flags == 0) 321 return; 322 fprintf(stderr, "Use netstat to view %s information\n", string); 323 return; 324 325 case CTL_DEBUG: 326 mib[2] = CTL_DEBUG_VALUE; 327 len = 3; 328 break; 329 330 case CTL_MACHDEP: 331#ifdef CPU_CONSDEV 332 if (mib[1] == CPU_CONSDEV) 333 special |= CONSDEV; 334#endif 335 break; 336 337 case CTL_FS: 338 len = sysctl_fs(string, &bufp, mib, flags, &type); 339 if (len >= 0) 340 break; 341 return; 342 343 case CTL_USER: 344 case CTL_DDB: 345 break; 346 347 default: 348 fprintf(stderr, "Illegal top level value: %d\n", mib[0]); 349 return; 350 351 } 352 if (bufp) { 353 fprintf(stderr, "name %s in %s is unknown\n", bufp, string); 354 return; 355 } 356 if (newsize > 0) { 357 switch (type) { 358 case CTLTYPE_INT: 359 intval = atoi(newval); 360 newval = &intval; 361 newsize = sizeof intval; 362 break; 363 364 case CTLTYPE_QUAD: 365 sscanf(newval, "%qd", &quadval); 366 newval = &quadval; 367 newsize = sizeof quadval; 368 break; 369 } 370 } 371 size = BUFSIZ; 372 if (sysctl(mib, len, buf, &size, newsize ? newval : 0, newsize) == -1) { 373 if (flags == 0) 374 return; 375 switch (errno) { 376 case EOPNOTSUPP: 377 fprintf(stderr, "%s: value is not available\n", string); 378 return; 379 case ENOTDIR: 380 fprintf(stderr, "%s: specification is incomplete\n", 381 string); 382 return; 383 case ENOMEM: 384 fprintf(stderr, "%s: type is unknown to this program\n", 385 string); 386 return; 387 default: 388 perror(string); 389 return; 390 } 391 } 392 if (special & CLOCK) { 393 struct clockinfo *clkp = (struct clockinfo *)buf; 394 395 if (!nflag) 396 fprintf(stdout, "%s: ", string); 397 fprintf(stdout, 398 "tick = %d, tickadj = %d, hz = %d, profhz = %d, stathz = %d\n", 399 clkp->tick, clkp->tickadj, clkp->hz, clkp->profhz, clkp->stathz); 400 return; 401 } 402 if (special & BOOTTIME) { 403 struct timeval *btp = (struct timeval *)buf; 404 time_t boottime; 405 406 if (!nflag) { 407 boottime = btp->tv_sec; 408 fprintf(stdout, "%s = %s\n", string, ctime(&boottime)); 409 } else 410 fprintf(stdout, "%d\n", btp->tv_sec); 411 return; 412 } 413 if (special & CONSDEV) { 414 dev_t dev = *(dev_t *)buf; 415 416 if (!nflag) 417 fprintf(stdout, "%s = %s\n", string, 418 devname(dev, S_IFCHR)); 419 else 420 fprintf(stdout, "0x%x\n", dev); 421 return; 422 } 423 switch (type) { 424 case CTLTYPE_INT: 425 if (newsize == 0) { 426 if (!nflag) 427 fprintf(stdout, "%s = ", string); 428 fprintf(stdout, "%d\n", *(int *)buf); 429 } else { 430 if (!nflag) 431 fprintf(stdout, "%s: %d -> ", string, 432 *(int *)buf); 433 fprintf(stdout, "%d\n", *(int *)newval); 434 } 435 return; 436 437 case CTLTYPE_STRING: 438 if (newsize == 0) { 439 if (!nflag) 440 fprintf(stdout, "%s = ", string); 441 fprintf(stdout, "%s\n", buf); 442 } else { 443 if (!nflag) 444 fprintf(stdout, "%s: %s -> ", string, buf); 445 fprintf(stdout, "%s\n", newval); 446 } 447 return; 448 449 case CTLTYPE_QUAD: 450 if (newsize == 0) { 451 if (!nflag) 452 fprintf(stdout, "%s = ", string); 453 fprintf(stdout, "%qd\n", *(quad_t *)buf); 454 } else { 455 if (!nflag) 456 fprintf(stdout, "%s: %qd -> ", string, 457 *(quad_t *)buf); 458 fprintf(stdout, "%qd\n", *(quad_t *)newval); 459 } 460 return; 461 462 case CTLTYPE_STRUCT: 463 fprintf(stderr, "%s: unknown structure returned\n", 464 string); 465 return; 466 467 default: 468 case CTLTYPE_NODE: 469 fprintf(stderr, "%s: unknown type returned\n", 470 string); 471 return; 472 } 473} 474 475/* 476 * Initialize the set of debugging names 477 */ 478debuginit() 479{ 480 int mib[3], loc, i; 481 size_t size; 482 483 if (secondlevel[CTL_DEBUG].list != 0) 484 return; 485 secondlevel[CTL_DEBUG].list = debugname; 486 mib[0] = CTL_DEBUG; 487 mib[2] = CTL_DEBUG_NAME; 488 for (loc = 0, i = 0; i < CTL_DEBUG_MAXID; i++) { 489 mib[1] = i; 490 size = BUFSIZ - loc; 491 if (sysctl(mib, 3, &names[loc], &size, NULL, 0) == -1) 492 continue; 493 debugname[i].ctl_name = &names[loc]; 494 debugname[i].ctl_type = CTLTYPE_INT; 495 loc += size; 496 } 497} 498 499struct ctlname posixname[] = CTL_FS_POSIX_NAMES; 500struct list fslist = { posixname, FS_POSIX_MAXID }; 501 502/* 503 * handle file system requests 504 */ 505sysctl_fs(string, bufpp, mib, flags, typep) 506 char *string; 507 char **bufpp; 508 int mib[]; 509 int flags; 510 int *typep; 511{ 512 struct list *lp; 513 int indx; 514 515 if (*bufpp == NULL) { 516 listall(string, &fslist); 517 return (-1); 518 } 519 if ((indx = findname(string, "third", bufpp, &fslist)) == -1) 520 return (-1); 521 mib[2] = indx; 522 *typep = fslist.list[indx].ctl_type; 523 return (3); 524} 525 526struct ctlname inetname[] = CTL_IPPROTO_NAMES; 527struct ctlname ipname[] = IPCTL_NAMES; 528struct ctlname icmpname[] = ICMPCTL_NAMES; 529struct ctlname tcpname[] = TCPCTL_NAMES; 530struct ctlname udpname[] = UDPCTL_NAMES; 531struct list inetlist = { inetname, IPPROTO_MAXID }; 532struct list inetvars[] = { 533 { ipname, IPCTL_MAXID }, /* ip */ 534 { icmpname, ICMPCTL_MAXID }, /* icmp */ 535 { 0, 0 }, /* igmp */ 536 { 0, 0 }, /* ggmp */ 537 { 0, 0 }, 538 { 0, 0 }, 539 { tcpname, TCPCTL_MAXID }, /* tcp */ 540 { 0, 0 }, 541 { 0, 0 }, /* egp */ 542 { 0, 0 }, 543 { 0, 0 }, 544 { 0, 0 }, 545 { 0, 0 }, /* pup */ 546 { 0, 0 }, 547 { 0, 0 }, 548 { 0, 0 }, 549 { 0, 0 }, 550 { udpname, UDPCTL_MAXID }, /* udp */ 551}; 552 553/* 554 * handle internet requests 555 */ 556sysctl_inet(string, bufpp, mib, flags, typep) 557 char *string; 558 char **bufpp; 559 int mib[]; 560 int flags; 561 int *typep; 562{ 563 struct list *lp; 564 int indx; 565 566 if (*bufpp == NULL) { 567 listall(string, &inetlist); 568 return (-1); 569 } 570 if ((indx = findname(string, "third", bufpp, &inetlist)) == -1) 571 return (-1); 572 mib[2] = indx; 573 if (indx <= IPPROTO_UDP && inetvars[indx].list != NULL) 574 lp = &inetvars[indx]; 575 else if (!flags) 576 return (-1); 577 else { 578 fprintf(stderr, "%s: no variables defined for this protocol\n", 579 string); 580 return (-1); 581 } 582 if (*bufpp == NULL) { 583 listall(string, lp); 584 return (-1); 585 } 586 if ((indx = findname(string, "fourth", bufpp, lp)) == -1) 587 return (-1); 588 mib[3] = indx; 589 *typep = lp->list[indx].ctl_type; 590 return (4); 591} 592 593/* 594 * Scan a list of names searching for a particular name. 595 */ 596findname(string, level, bufp, namelist) 597 char *string; 598 char *level; 599 char **bufp; 600 struct list *namelist; 601{ 602 char *name; 603 int i; 604 605 if (namelist->list == 0 || (name = strsep(bufp, ".")) == NULL) { 606 fprintf(stderr, "%s: incomplete specification\n", string); 607 return (-1); 608 } 609 for (i = 0; i < namelist->size; i++) 610 if (namelist->list[i].ctl_name != NULL && 611 strcmp(name, namelist->list[i].ctl_name) == 0) 612 break; 613 if (i == namelist->size) { 614 fprintf(stderr, "%s level name %s in %s is invalid\n", 615 level, name, string); 616 return (-1); 617 } 618 return (i); 619} 620 621usage() 622{ 623 624 (void)fprintf(stderr, "usage:\t%s\n\t%s\n\t%s\n\t%s\n", 625 "sysctl [-n] variable ...", "sysctl [-n] -w variable=value ...", 626 "sysctl [-n] -a", "sysctl [-n] -A"); 627 exit(1); 628} 629