sysctl.c revision 1.2
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 netname[] = CTL_NET_NAMES; 80struct ctlname hwname[] = CTL_HW_NAMES; 81struct ctlname username[] = CTL_USER_NAMES; 82struct ctlname debugname[CTL_DEBUG_MAXID]; 83#ifdef CTL_MACHDEP_NAMES 84struct ctlname machdepname[] = CTL_MACHDEP_NAMES; 85#endif 86struct ctlname ddbname[] = CTL_DDB_NAMES; 87char names[BUFSIZ]; 88 89struct list { 90 struct ctlname *list; 91 int size; 92}; 93struct list toplist = { topname, CTL_MAXID }; 94struct list secondlevel[] = { 95 { 0, 0 }, /* CTL_UNSPEC */ 96 { kernname, KERN_MAXID }, /* CTL_KERN */ 97 { vmname, VM_MAXID }, /* CTL_VM */ 98 { 0, 0 }, /* CTL_FS */ 99 { netname, NET_MAXID }, /* CTL_NET */ 100 { 0, CTL_DEBUG_MAXID }, /* CTL_DEBUG */ 101 { hwname, HW_MAXID }, /* CTL_HW */ 102#ifdef CTL_MACHDEP_NAMES 103 { machdepname, CPU_MAXID }, /* CTL_MACHDEP */ 104#else 105 { 0, 0 }, /* CTL_MACHDEP */ 106#endif 107 { username, USER_MAXID }, /* CTL_USER_NAMES */ 108 { ddbname, DBCTL_MAXID }, /* CTL_DDB_NAMES */ 109}; 110 111int Aflag, aflag, nflag, wflag; 112 113/* 114 * Variables requiring special processing. 115 */ 116#define CLOCK 0x00000001 117#define BOOTTIME 0x00000002 118#define CONSDEV 0x00000004 119 120int 121main(argc, argv) 122 int argc; 123 char *argv[]; 124{ 125 extern char *optarg; 126 extern int optind; 127 int ch, lvl1; 128 129 while ((ch = getopt(argc, argv, "Aanw")) != EOF) { 130 switch (ch) { 131 132 case 'A': 133 Aflag = 1; 134 break; 135 136 case 'a': 137 aflag = 1; 138 break; 139 140 case 'n': 141 nflag = 1; 142 break; 143 144 case 'w': 145 wflag = 1; 146 break; 147 148 default: 149 usage(); 150 } 151 } 152 argc -= optind; 153 argv += optind; 154 155 if (Aflag || aflag) { 156 debuginit(); 157 for (lvl1 = 1; lvl1 < CTL_MAXID; lvl1++) 158 listall(topname[lvl1].ctl_name, &secondlevel[lvl1]); 159 exit(0); 160 } 161 if (argc == 0) 162 usage(); 163 while (argc-- > 0) 164 parse(*argv++, 1); 165 exit(0); 166} 167 168/* 169 * List all variables known to the system. 170 */ 171listall(prefix, lp) 172 char *prefix; 173 struct list *lp; 174{ 175 int lvl2; 176 char *cp, name[BUFSIZ]; 177 178 if (lp->list == 0) 179 return; 180 strcpy(name, prefix); 181 cp = &name[strlen(name)]; 182 *cp++ = '.'; 183 for (lvl2 = 0; lvl2 < lp->size; lvl2++) { 184 if (lp->list[lvl2].ctl_name == 0) 185 continue; 186 strcpy(cp, lp->list[lvl2].ctl_name); 187 parse(name, Aflag); 188 } 189} 190 191/* 192 * Parse a name into a MIB entry. 193 * Lookup and print out the MIB entry if it exists. 194 * Set a new value if requested. 195 */ 196parse(string, flags) 197 char *string; 198 int flags; 199{ 200 int indx, type, state, len; 201 int special = 0; 202 void *newval = 0; 203 int intval, newsize = 0; 204 quad_t quadval; 205 size_t size; 206 struct list *lp; 207 int mib[CTL_MAXNAME]; 208 char *cp, *bufp, buf[BUFSIZ], strval[BUFSIZ]; 209 210 bufp = buf; 211 snprintf(buf, BUFSIZ, "%s", string); 212 if ((cp = strchr(string, '=')) != NULL) { 213 if (!wflag) { 214 fprintf(stderr, "Must specify -w to set variables\n"); 215 exit(2); 216 } 217 *strchr(buf, '=') = '\0'; 218 *cp++ = '\0'; 219 while (isspace(*cp)) 220 cp++; 221 newval = cp; 222 newsize = strlen(cp); 223 } 224 if ((indx = findname(string, "top", &bufp, &toplist)) == -1) 225 return; 226 mib[0] = indx; 227 if (indx == CTL_DEBUG) 228 debuginit(); 229 lp = &secondlevel[indx]; 230 if (lp->list == 0) { 231 fprintf(stderr, "%s: class is not implemented\n", 232 topname[indx]); 233 return; 234 } 235 if (bufp == NULL) { 236 listall(topname[indx].ctl_name, lp); 237 return; 238 } 239 if ((indx = findname(string, "second", &bufp, lp)) == -1) 240 return; 241 mib[1] = indx; 242 type = lp->list[indx].ctl_type; 243 len = 2; 244 switch (mib[0]) { 245 246 case CTL_KERN: 247 switch (mib[1]) { 248 case KERN_PROF: 249 mib[2] = GPROF_STATE; 250 size = sizeof state; 251 if (sysctl(mib, 3, &state, &size, NULL, 0) < 0) { 252 if (flags == 0) 253 return; 254 if (!nflag) 255 fprintf(stdout, "%s: ", string); 256 fprintf(stderr, 257 "kernel is not compiled for profiling\n"); 258 return; 259 } 260 if (!nflag) 261 fprintf(stdout, "%s: %s\n", string, 262 state == GMON_PROF_OFF ? "off" : "running"); 263 return; 264 case KERN_VNODE: 265 case KERN_FILE: 266 if (flags == 0) 267 return; 268 fprintf(stderr, 269 "Use pstat to view %s information\n", string); 270 return; 271 case KERN_PROC: 272 if (flags == 0) 273 return; 274 fprintf(stderr, 275 "Use ps to view %s information\n", string); 276 return; 277 case KERN_CLOCKRATE: 278 special |= CLOCK; 279 break; 280 case KERN_BOOTTIME: 281 special |= BOOTTIME; 282 break; 283 } 284 break; 285 286 case CTL_HW: 287 break; 288 289 case CTL_VM: 290 if (mib[1] == VM_LOADAVG) { 291 double loads[3]; 292 293 getloadavg(loads, 3); 294 if (!nflag) 295 fprintf(stdout, "%s: ", string); 296 fprintf(stdout, "%.2f %.2f %.2f\n", 297 loads[0], loads[1], loads[2]); 298 return; 299 } 300 if (flags == 0) 301 return; 302 fprintf(stderr, 303 "Use vmstat or systat to view %s information\n", string); 304 return; 305 306 case CTL_NET: 307 if (mib[1] == PF_INET) { 308 len = sysctl_inet(string, &bufp, mib, flags, &type); 309 if (len >= 0) 310 break; 311 return; 312 } 313 if (flags == 0) 314 return; 315 fprintf(stderr, "Use netstat to view %s information\n", string); 316 return; 317 318 case CTL_DEBUG: 319 mib[2] = CTL_DEBUG_VALUE; 320 len = 3; 321 break; 322 323 case CTL_MACHDEP: 324#ifdef CPU_CONSDEV 325 if (mib[1] == CPU_CONSDEV) 326 special |= CONSDEV; 327#endif 328 break; 329 330 case CTL_FS: 331 case CTL_USER: 332 case CTL_DDB: 333 break; 334 335 default: 336 fprintf(stderr, "Illegal top level value: %d\n", mib[0]); 337 return; 338 339 } 340 if (bufp) { 341 fprintf(stderr, "name %s in %s is unknown\n", bufp, string); 342 return; 343 } 344 if (newsize > 0) { 345 switch (type) { 346 case CTLTYPE_INT: 347 intval = atoi(newval); 348 newval = &intval; 349 newsize = sizeof intval; 350 break; 351 352 case CTLTYPE_QUAD: 353 sscanf(newval, "%qd", &quadval); 354 newval = &quadval; 355 newsize = sizeof quadval; 356 break; 357 } 358 } 359 size = BUFSIZ; 360 if (sysctl(mib, len, buf, &size, newsize ? newval : 0, newsize) == -1) { 361 if (flags == 0) 362 return; 363 switch (errno) { 364 case EOPNOTSUPP: 365 fprintf(stderr, "%s: value is not available\n", string); 366 return; 367 case ENOTDIR: 368 fprintf(stderr, "%s: specification is incomplete\n", 369 string); 370 return; 371 case ENOMEM: 372 fprintf(stderr, "%s: type is unknown to this program\n", 373 string); 374 return; 375 default: 376 perror(string); 377 return; 378 } 379 } 380 if (special & CLOCK) { 381 struct clockinfo *clkp = (struct clockinfo *)buf; 382 383 if (!nflag) 384 fprintf(stdout, "%s: ", string); 385 fprintf(stdout, 386 "tick = %d, tickadj = %d, hz = %d, profhz = %d, stathz = %d\n", 387 clkp->tick, clkp->tickadj, clkp->hz, clkp->profhz, clkp->stathz); 388 return; 389 } 390 if (special & BOOTTIME) { 391 struct timeval *btp = (struct timeval *)buf; 392 time_t boottime; 393 394 if (!nflag) { 395 boottime = btp->tv_sec; 396 fprintf(stdout, "%s = %s\n", string, ctime(&boottime)); 397 } else 398 fprintf(stdout, "%d\n", btp->tv_sec); 399 return; 400 } 401 if (special & CONSDEV) { 402 dev_t dev = *(dev_t *)buf; 403 404 if (!nflag) 405 fprintf(stdout, "%s = %s\n", string, 406 devname(dev, S_IFCHR)); 407 else 408 fprintf(stdout, "0x%x\n", dev); 409 return; 410 } 411 switch (type) { 412 case CTLTYPE_INT: 413 if (newsize == 0) { 414 if (!nflag) 415 fprintf(stdout, "%s = ", string); 416 fprintf(stdout, "%d\n", *(int *)buf); 417 } else { 418 if (!nflag) 419 fprintf(stdout, "%s: %d -> ", string, 420 *(int *)buf); 421 fprintf(stdout, "%d\n", *(int *)newval); 422 } 423 return; 424 425 case CTLTYPE_STRING: 426 if (newsize == 0) { 427 if (!nflag) 428 fprintf(stdout, "%s = ", string); 429 fprintf(stdout, "%s\n", buf); 430 } else { 431 if (!nflag) 432 fprintf(stdout, "%s: %s -> ", string, buf); 433 fprintf(stdout, "%s\n", newval); 434 } 435 return; 436 437 case CTLTYPE_QUAD: 438 if (newsize == 0) { 439 if (!nflag) 440 fprintf(stdout, "%s = ", string); 441 fprintf(stdout, "%qd\n", *(quad_t *)buf); 442 } else { 443 if (!nflag) 444 fprintf(stdout, "%s: %qd -> ", string, 445 *(quad_t *)buf); 446 fprintf(stdout, "%qd\n", *(quad_t *)newval); 447 } 448 return; 449 450 case CTLTYPE_STRUCT: 451 fprintf(stderr, "%s: unknown structure returned\n", 452 string); 453 return; 454 455 default: 456 case CTLTYPE_NODE: 457 fprintf(stderr, "%s: unknown type returned\n", 458 string); 459 return; 460 } 461} 462 463/* 464 * Initialize the set of debugging names 465 */ 466debuginit() 467{ 468 int mib[3], loc, i; 469 size_t size; 470 471 if (secondlevel[CTL_DEBUG].list != 0) 472 return; 473 secondlevel[CTL_DEBUG].list = debugname; 474 mib[0] = CTL_DEBUG; 475 mib[2] = CTL_DEBUG_NAME; 476 for (loc = 0, i = 0; i < CTL_DEBUG_MAXID; i++) { 477 mib[1] = i; 478 size = BUFSIZ - loc; 479 if (sysctl(mib, 3, &names[loc], &size, NULL, 0) == -1) 480 continue; 481 debugname[i].ctl_name = &names[loc]; 482 debugname[i].ctl_type = CTLTYPE_INT; 483 loc += size; 484 } 485} 486 487struct ctlname inetname[] = CTL_IPPROTO_NAMES; 488struct ctlname ipname[] = IPCTL_NAMES; 489struct ctlname icmpname[] = ICMPCTL_NAMES; 490struct ctlname tcpname[] = TCPCTL_NAMES; 491struct ctlname udpname[] = UDPCTL_NAMES; 492struct list inetlist = { inetname, IPPROTO_MAXID }; 493struct list inetvars[] = { 494 { ipname, IPCTL_MAXID }, /* ip */ 495 { icmpname, ICMPCTL_MAXID }, /* icmp */ 496 { 0, 0 }, /* igmp */ 497 { 0, 0 }, /* ggmp */ 498 { 0, 0 }, 499 { 0, 0 }, 500 { tcpname, TCPCTL_MAXID }, /* tcp */ 501 { 0, 0 }, 502 { 0, 0 }, /* egp */ 503 { 0, 0 }, 504 { 0, 0 }, 505 { 0, 0 }, 506 { 0, 0 }, /* pup */ 507 { 0, 0 }, 508 { 0, 0 }, 509 { 0, 0 }, 510 { 0, 0 }, 511 { udpname, UDPCTL_MAXID }, /* udp */ 512}; 513 514/* 515 * handle internet requests 516 */ 517sysctl_inet(string, bufpp, mib, flags, typep) 518 char *string; 519 char **bufpp; 520 int mib[]; 521 int flags; 522 int *typep; 523{ 524 struct list *lp; 525 int indx; 526 527 if (*bufpp == NULL) { 528 listall(string, &inetlist); 529 return (-1); 530 } 531 if ((indx = findname(string, "third", bufpp, &inetlist)) == -1) 532 return (-1); 533 mib[2] = indx; 534 if (indx <= IPPROTO_UDP && inetvars[indx].list != NULL) 535 lp = &inetvars[indx]; 536 else if (!flags) 537 return (-1); 538 else { 539 fprintf(stderr, "%s: no variables defined for this protocol\n", 540 string); 541 return (-1); 542 } 543 if (*bufpp == NULL) { 544 listall(string, lp); 545 return (-1); 546 } 547 if ((indx = findname(string, "fourth", bufpp, lp)) == -1) 548 return (-1); 549 mib[3] = indx; 550 *typep = lp->list[indx].ctl_type; 551 return (4); 552} 553 554/* 555 * Scan a list of names searching for a particular name. 556 */ 557findname(string, level, bufp, namelist) 558 char *string; 559 char *level; 560 char **bufp; 561 struct list *namelist; 562{ 563 char *name; 564 int i; 565 566 if (namelist->list == 0 || (name = strsep(bufp, ".")) == NULL) { 567 fprintf(stderr, "%s: incomplete specification\n", string); 568 return (-1); 569 } 570 for (i = 0; i < namelist->size; i++) 571 if (namelist->list[i].ctl_name != NULL && 572 strcmp(name, namelist->list[i].ctl_name) == 0) 573 break; 574 if (i == namelist->size) { 575 fprintf(stderr, "%s level name %s in %s is invalid\n", 576 level, name, string); 577 return (-1); 578 } 579 return (i); 580} 581 582usage() 583{ 584 585 (void)fprintf(stderr, "usage:\t%s\n\t%s\n\t%s\n\t%s\n", 586 "sysctl [-n] variable ...", "sysctl [-n] -w variable=value ...", 587 "sysctl [-n] -a", "sysctl [-n] -A"); 588 exit(1); 589} 590