sysctl.c revision 88696
1/* 2 * Copyright (c) 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34#ifndef lint 35static const char copyright[] = 36"@(#) Copyright (c) 1993\n\ 37 The Regents of the University of California. All rights reserved.\n"; 38#endif /* not lint */ 39 40#ifndef lint 41#if 0 42static char sccsid[] = "@(#)from: sysctl.c 8.1 (Berkeley) 6/6/93"; 43#endif 44static const char rcsid[] = 45 "$FreeBSD: head/sbin/sysctl/sysctl.c 88696 2001-12-30 10:33:34Z phk $"; 46#endif /* not lint */ 47 48#include <sys/types.h> 49#include <sys/stat.h> 50#include <sys/sysctl.h> 51#include <sys/resource.h> 52#include <sys/param.h> 53 54#include <ctype.h> 55#include <err.h> 56#include <errno.h> 57#include <stdio.h> 58#include <stdlib.h> 59#include <string.h> 60#include <unistd.h> 61 62static int aflag, bflag, dflag, eflag, Nflag, nflag, oflag, xflag; 63 64static int oidfmt(int *, int, char *, u_int *); 65static void parse(char *); 66static int show_var(int *, int); 67static int sysctl_all (int *oid, int len); 68static int name2oid(char *, int *); 69 70static void set_T_dev_t (char *, void **, int *); 71 72static void 73usage(void) 74{ 75 76 (void)fprintf(stderr, "%s\n%s\n", 77 "usage: sysctl [-bdeNnox] variable[=value] ...", 78 " sysctl [-bdeNnox] -a"); 79 exit(1); 80} 81 82int 83main(int argc, char **argv) 84{ 85 int ch; 86 setbuf(stdout,0); 87 setbuf(stderr,0); 88 89 while ((ch = getopt(argc, argv, "AabdeNnowxX")) != -1) { 90 switch (ch) { 91 case 'A': 92 /* compatibility */ 93 aflag = oflag = 1; 94 break; 95 case 'a': 96 aflag = 1; 97 break; 98 case 'b': 99 bflag = 1; 100 break; 101 case 'd': 102 dflag = 1; 103 break; 104 case 'e': 105 eflag = 1; 106 break; 107 case 'N': 108 Nflag = 1; 109 break; 110 case 'n': 111 nflag = 1; 112 break; 113 case 'o': 114 oflag = 1; 115 break; 116 case 'w': 117 /* compatibility */ 118 /* ignored */ 119 break; 120 case 'X': 121 /* compatibility */ 122 aflag = xflag = 1; 123 break; 124 case 'x': 125 xflag = 1; 126 break; 127 default: 128 usage(); 129 } 130 } 131 argc -= optind; 132 argv += optind; 133 134 if (Nflag && nflag) 135 usage(); 136 if (aflag && argc == 0) 137 exit(sysctl_all(0, 0)); 138 if (argc == 0) 139 usage(); 140 while (argc-- > 0) 141 parse(*argv++); 142 exit(0); 143} 144 145/* 146 * Parse a name into a MIB entry. 147 * Lookup and print out the MIB entry if it exists. 148 * Set a new value if requested. 149 */ 150static void 151parse(char *string) 152{ 153 int len, i, j; 154 void *newval = 0; 155 int intval; 156 unsigned int uintval; 157 long longval; 158 unsigned long ulongval; 159 size_t newsize = 0; 160 quad_t quadval; 161 int mib[CTL_MAXNAME]; 162 char *cp, *bufp, buf[BUFSIZ], fmt[BUFSIZ]; 163 u_int kind; 164 165 bufp = buf; 166 snprintf(buf, BUFSIZ, "%s", string); 167 if ((cp = strchr(string, '=')) != NULL) { 168 *strchr(buf, '=') = '\0'; 169 *cp++ = '\0'; 170 while (isspace(*cp)) 171 cp++; 172 newval = cp; 173 newsize = strlen(cp); 174 } 175 len = name2oid(bufp, mib); 176 177 if (len < 0) 178 errx(1, "unknown oid '%s'", bufp); 179 180 if (oidfmt(mib, len, fmt, &kind)) 181 err(1, "couldn't find format of oid '%s'", bufp); 182 183 if (newval == NULL) { 184 if ((kind & CTLTYPE) == CTLTYPE_NODE) { 185 sysctl_all(mib, len); 186 } else { 187 i = show_var(mib, len); 188 if (!i && !bflag) 189 putchar('\n'); 190 } 191 } else { 192 if ((kind & CTLTYPE) == CTLTYPE_NODE) 193 errx(1, "oid '%s' isn't a leaf node", bufp); 194 195 if (!(kind&CTLFLAG_WR)) 196 errx(1, "oid '%s' is read only", bufp); 197 198 switch (kind & CTLTYPE) { 199 case CTLTYPE_INT: 200 intval = (int) strtol(newval, NULL, 0); 201 newval = &intval; 202 newsize = sizeof(intval); 203 break; 204 case CTLTYPE_UINT: 205 uintval = (int) strtoul(newval, NULL, 0); 206 newval = &uintval; 207 newsize = sizeof uintval; 208 break; 209 case CTLTYPE_LONG: 210 longval = strtol(newval, NULL, 0); 211 newval = &longval; 212 newsize = sizeof longval; 213 break; 214 case CTLTYPE_ULONG: 215 ulongval = strtoul(newval, NULL, 0); 216 newval = &ulongval; 217 newsize = sizeof ulongval; 218 break; 219 case CTLTYPE_STRING: 220 break; 221 case CTLTYPE_QUAD: 222 sscanf(newval, "%qd", &quadval); 223 newval = &quadval; 224 newsize = sizeof(quadval); 225 break; 226 case CTLTYPE_OPAQUE: 227 if (strcmp(fmt, "T,dev_t") == 0) { 228 set_T_dev_t ((char*)newval, &newval, &newsize); 229 break; 230 } 231 /* FALLTHROUGH */ 232 default: 233 errx(1, "oid '%s' is type %d," 234 " cannot set that", bufp, 235 kind & CTLTYPE); 236 } 237 238 i = show_var(mib, len); 239 if (sysctl(mib, len, 0, 0, newval, newsize) == -1) { 240 if (!i && !bflag) 241 putchar('\n'); 242 switch (errno) { 243 case EOPNOTSUPP: 244 errx(1, "%s: value is not available", 245 string); 246 case ENOTDIR: 247 errx(1, "%s: specification is incomplete", 248 string); 249 case ENOMEM: 250 errx(1, "%s: type is unknown to this program", 251 string); 252 default: 253 warn("%s", string); 254 return; 255 } 256 } 257 if (!bflag) 258 printf(" -> "); 259 i = nflag; 260 nflag = 1; 261 j = show_var(mib, len); 262 if (!j && !bflag) 263 putchar('\n'); 264 nflag = i; 265 } 266} 267 268/* These functions will dump out various interesting structures. */ 269 270static int 271S_clockinfo(int l2, void *p) 272{ 273 struct clockinfo *ci = (struct clockinfo*)p; 274 if (l2 != sizeof(*ci)) 275 err(1, "S_clockinfo %d != %d", l2, sizeof(*ci)); 276 printf("{ hz = %d, tick = %d, tickadj = %d, profhz = %d, stathz = %d }", 277 ci->hz, ci->tick, ci->tickadj, ci->profhz, ci->stathz); 278 return (0); 279} 280 281static int 282S_loadavg(int l2, void *p) 283{ 284 struct loadavg *tv = (struct loadavg*)p; 285 286 if (l2 != sizeof(*tv)) 287 err(1, "S_loadavg %d != %d", l2, sizeof(*tv)); 288 289 printf("{ %.2f %.2f %.2f }", 290 (double)tv->ldavg[0]/(double)tv->fscale, 291 (double)tv->ldavg[1]/(double)tv->fscale, 292 (double)tv->ldavg[2]/(double)tv->fscale); 293 return (0); 294} 295 296static int 297S_timeval(int l2, void *p) 298{ 299 struct timeval *tv = (struct timeval*)p; 300 time_t tv_sec; 301 char *p1, *p2; 302 303 if (l2 != sizeof(*tv)) 304 err(1, "S_timeval %d != %d", l2, sizeof(*tv)); 305 printf("{ sec = %ld, usec = %ld } ", 306 tv->tv_sec, tv->tv_usec); 307 tv_sec = tv->tv_sec; 308 p1 = strdup(ctime(&tv_sec)); 309 for (p2=p1; *p2 ; p2++) 310 if (*p2 == '\n') 311 *p2 = '\0'; 312 fputs(p1, stdout); 313 return (0); 314} 315 316static int 317T_dev_t(int l2, void *p) 318{ 319 dev_t *d = (dev_t *)p; 320 if (l2 != sizeof(*d)) 321 err(1, "T_dev_T %d != %d", l2, sizeof(*d)); 322 if ((int)(*d) != -1) { 323 if (minor(*d) > 255 || minor(*d) < 0) 324 printf("{ major = %d, minor = 0x%x }", 325 major(*d), minor(*d)); 326 else 327 printf("{ major = %d, minor = %d }", 328 major(*d), minor(*d)); 329 } 330 return (0); 331} 332 333static void 334set_T_dev_t (char *path, void **val, int *size) 335{ 336 static struct stat statb; 337 338 if (strcmp(path, "none") && strcmp(path, "off")) { 339 int rc = stat (path, &statb); 340 if (rc) { 341 err(1, "cannot stat %s", path); 342 } 343 344 if (!S_ISCHR(statb.st_mode)) { 345 errx(1, "must specify a device special file."); 346 } 347 } else { 348 statb.st_rdev = NODEV; 349 } 350 *val = (char*) &statb.st_rdev; 351 *size = sizeof statb.st_rdev; 352} 353 354/* 355 * These functions uses a presently undocumented interface to the kernel 356 * to walk the tree and get the type so it can print the value. 357 * This interface is under work and consideration, and should probably 358 * be killed with a big axe by the first person who can find the time. 359 * (be aware though, that the proper interface isn't as obvious as it 360 * may seem, there are various conflicting requirements. 361 */ 362 363static int 364name2oid(char *name, int *oidp) 365{ 366 int oid[2]; 367 int i; 368 size_t j; 369 370 oid[0] = 0; 371 oid[1] = 3; 372 373 j = CTL_MAXNAME * sizeof(int); 374 i = sysctl(oid, 2, oidp, &j, name, strlen(name)); 375 if (i < 0) 376 return i; 377 j /= sizeof(int); 378 return (j); 379} 380 381static int 382oidfmt(int *oid, int len, char *fmt, u_int *kind) 383{ 384 int qoid[CTL_MAXNAME+2]; 385 u_char buf[BUFSIZ]; 386 int i; 387 size_t j; 388 389 qoid[0] = 0; 390 qoid[1] = 4; 391 memcpy(qoid + 2, oid, len * sizeof(int)); 392 393 j = sizeof(buf); 394 i = sysctl(qoid, len + 2, buf, &j, 0, 0); 395 if (i) 396 err(1, "sysctl fmt %d %d %d", i, j, errno); 397 398 if (kind) 399 *kind = *(u_int *)buf; 400 401 if (fmt) 402 strcpy(fmt, (char *)(buf + sizeof(u_int))); 403 return 0; 404} 405 406/* 407 * This formats and outputs the value of one variable 408 * 409 * Returns zero if anything was actually output. 410 * Returns one if didn't know what to do with this. 411 * Return minus one if we had errors. 412 */ 413 414static int 415show_var(int *oid, int nlen) 416{ 417 u_char buf[BUFSIZ], *val, *p; 418 char name[BUFSIZ], *fmt, *sep; 419 int qoid[CTL_MAXNAME+2]; 420 int i; 421 size_t j, len; 422 u_int kind; 423 int (*func)(int, void *); 424 425 qoid[0] = 0; 426 memcpy(qoid + 2, oid, nlen * sizeof(int)); 427 428 qoid[1] = 1; 429 j = sizeof(name); 430 i = sysctl(qoid, nlen + 2, name, &j, 0, 0); 431 if (i || !j) 432 err(1, "sysctl name %d %d %d", i, j, errno); 433 434 if (Nflag) { 435 printf("%s", name); 436 return (0); 437 } 438 439 if (eflag) 440 sep = "="; 441 else 442 sep = ": "; 443 444 if (dflag) { /* just print description */ 445 qoid[1] = 5; 446 j = sizeof(buf); 447 i = sysctl(qoid, nlen + 2, buf, &j, 0, 0); 448 if (!nflag) 449 printf("%s%s", name, sep); 450 printf("%s", buf); 451 return (0); 452 } 453 /* find an estimate of how much we need for this var */ 454 j = 0; 455 i = sysctl(oid, nlen, 0, &j, 0, 0); 456 j += j; /* we want to be sure :-) */ 457 458 val = alloca(j); 459 len = j; 460 i = sysctl(oid, nlen, val, &len, 0, 0); 461 if (i || !len) 462 return (1); 463 464 if (bflag) { 465 fwrite(val, 1, len, stdout); 466 return (0); 467 } 468 469 fmt = buf; 470 oidfmt(oid, nlen, fmt, &kind); 471 p = val; 472 switch (*fmt) { 473 case 'A': 474 if (!nflag) 475 printf("%s%s", name, sep); 476 printf("%s", p); 477 return (0); 478 479 case 'I': 480 if (!nflag) 481 printf("%s%s", name, sep); 482 fmt++; 483 val = ""; 484 while (len >= sizeof(int)) { 485 if(*fmt == 'U') 486 printf("%s%u", val, *(unsigned int *)p); 487 else 488 printf("%s%d", val, *(int *)p); 489 val = " "; 490 len -= sizeof(int); 491 p += sizeof(int); 492 } 493 return (0); 494 495 case 'L': 496 if (!nflag) 497 printf("%s%s", name, sep); 498 fmt++; 499 val = ""; 500 while (len >= sizeof(long)) { 501 if(*fmt == 'U') 502 printf("%s%lu", val, *(unsigned long *)p); 503 else 504 printf("%s%ld", val, *(long *)p); 505 val = " "; 506 len -= sizeof(long); 507 p += sizeof(long); 508 } 509 return (0); 510 511 case 'P': 512 if (!nflag) 513 printf("%s%s", name, sep); 514 printf("%p", *(void **)p); 515 return (0); 516 517 case 'T': 518 case 'S': 519 i = 0; 520 if (strcmp(fmt, "S,clockinfo") == 0) 521 func = S_clockinfo; 522 else if (strcmp(fmt, "S,timeval") == 0) 523 func = S_timeval; 524 else if (strcmp(fmt, "S,loadavg") == 0) 525 func = S_loadavg; 526 else if (strcmp(fmt, "T,dev_t") == 0) 527 func = T_dev_t; 528 else 529 func = NULL; 530 if (func) { 531 if (!nflag) 532 printf("%s%s", name, sep); 533 return ((*func)(len, p)); 534 } 535 /* FALL THROUGH */ 536 default: 537 if (!oflag && !xflag) 538 return (1); 539 if (!nflag) 540 printf("%s%s", name, sep); 541 printf("Format:%s Length:%d Dump:0x", fmt, len); 542 while (len-- && (xflag || p < val + 16)) 543 printf("%02x", *p++); 544 if (!xflag && len > 16) 545 printf("..."); 546 return (0); 547 } 548 return (1); 549} 550 551static int 552sysctl_all (int *oid, int len) 553{ 554 int name1[22], name2[22]; 555 int i, j; 556 size_t l1, l2; 557 558 name1[0] = 0; 559 name1[1] = 2; 560 l1 = 2; 561 if (len) { 562 memcpy(name1+2, oid, len * sizeof(int)); 563 l1 += len; 564 } else { 565 name1[2] = 1; 566 l1++; 567 } 568 for (;;) { 569 l2 = sizeof(name2); 570 j = sysctl(name1, l1, name2, &l2, 0, 0); 571 if (j < 0) { 572 if (errno == ENOENT) 573 return 0; 574 else 575 err(1, "sysctl(getnext) %d %d", j, l2); 576 } 577 578 l2 /= sizeof(int); 579 580 if (l2 < len) 581 return 0; 582 583 for (i = 0; i < len; i++) 584 if (name2[i] != oid[i]) 585 return 0; 586 587 i = show_var(name2, l2); 588 if (!i && !bflag) 589 putchar('\n'); 590 591 memcpy(name1+2, name2, l2 * sizeof(int)); 592 l1 = 2 + l2; 593 } 594} 595