sysctl.c revision 77928
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 77928 2001-06-09 03:56:16Z dd $"; 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 53#include <ctype.h> 54#include <err.h> 55#include <errno.h> 56#include <stdio.h> 57#include <stdlib.h> 58#include <string.h> 59#include <unistd.h> 60 61static int aflag, bflag, Nflag, nflag, oflag, xflag; 62 63static int oidfmt(int *, int, char *, u_int *); 64static void parse(char *); 65static int show_var(int *, int); 66static int sysctl_all (int *oid, int len); 67static int name2oid(char *, int *); 68 69static void 70usage(void) 71{ 72 73 (void)fprintf(stderr, "%s\n%s\n", 74 "usage: sysctl [-bNnox] variable[=value] ...", 75 " sysctl [-bNnox] -a"); 76 exit(1); 77} 78 79int 80main(int argc, char **argv) 81{ 82 int ch; 83 setbuf(stdout,0); 84 setbuf(stderr,0); 85 86 while ((ch = getopt(argc, argv, "AabNnowxX")) != -1) { 87 switch (ch) { 88 case 'A': 89 /* compatibility */ 90 aflag = oflag = 1; 91 break; 92 case 'a': 93 aflag = 1; 94 break; 95 case 'b': 96 bflag = 1; 97 break; 98 case 'N': 99 Nflag = 1; 100 break; 101 case 'n': 102 nflag = 1; 103 break; 104 case 'o': 105 oflag = 1; 106 break; 107 case 'w': 108 /* compatibility */ 109 /* ignored */ 110 break; 111 case 'X': 112 /* compatibility */ 113 aflag = xflag = 1; 114 break; 115 case 'x': 116 xflag = 1; 117 break; 118 default: 119 usage(); 120 } 121 } 122 argc -= optind; 123 argv += optind; 124 125 if (Nflag && nflag) 126 usage(); 127 if (aflag && argc == 0) 128 exit(sysctl_all(0, 0)); 129 if (argc == 0) 130 usage(); 131 while (argc-- > 0) 132 parse(*argv++); 133 exit(0); 134} 135 136/* 137 * Parse a name into a MIB entry. 138 * Lookup and print out the MIB entry if it exists. 139 * Set a new value if requested. 140 */ 141static void 142parse(char *string) 143{ 144 int len, i, j; 145 void *newval = 0; 146 int intval, newsize = 0; 147 quad_t quadval; 148 int mib[CTL_MAXNAME]; 149 char *cp, *bufp, buf[BUFSIZ]; 150 u_int kind; 151 152 bufp = buf; 153 snprintf(buf, BUFSIZ, "%s", string); 154 if ((cp = strchr(string, '=')) != NULL) { 155 *strchr(buf, '=') = '\0'; 156 *cp++ = '\0'; 157 while (isspace(*cp)) 158 cp++; 159 newval = cp; 160 newsize = strlen(cp); 161 } 162 len = name2oid(bufp, mib); 163 164 if (len < 0) 165 errx(1, "unknown oid '%s'", bufp); 166 167 if (oidfmt(mib, len, 0, &kind)) 168 err(1, "couldn't find format of oid '%s'", bufp); 169 170 if (newval == NULL) { 171 if ((kind & CTLTYPE) == CTLTYPE_NODE) { 172 sysctl_all(mib, len); 173 } else { 174 i = show_var(mib, len); 175 if (!i && !bflag) 176 putchar('\n'); 177 } 178 } else { 179 if ((kind & CTLTYPE) == CTLTYPE_NODE) 180 errx(1, "oid '%s' isn't a leaf node", bufp); 181 182 if (!(kind&CTLFLAG_WR)) 183 errx(1, "oid '%s' is read only", bufp); 184 185 switch (kind & CTLTYPE) { 186 case CTLTYPE_INT: 187 intval = (int) strtol(newval, NULL, 0); 188 newval = &intval; 189 newsize = sizeof(intval); 190 break; 191 break; 192 case CTLTYPE_STRING: 193 break; 194 case CTLTYPE_QUAD: 195 break; 196 sscanf(newval, "%qd", &quadval); 197 newval = &quadval; 198 newsize = sizeof(quadval); 199 break; 200 default: 201 errx(1, "oid '%s' is type %d," 202 " cannot set that", bufp, 203 kind & CTLTYPE); 204 } 205 206 i = show_var(mib, len); 207 if (sysctl(mib, len, 0, 0, newval, newsize) == -1) { 208 if (!i && !bflag) 209 putchar('\n'); 210 switch (errno) { 211 case EOPNOTSUPP: 212 errx(1, "%s: value is not available", 213 string); 214 case ENOTDIR: 215 errx(1, "%s: specification is incomplete", 216 string); 217 case ENOMEM: 218 errx(1, "%s: type is unknown to this program", 219 string); 220 default: 221 warn("%s", string); 222 return; 223 } 224 } 225 if (!bflag) 226 printf(" -> "); 227 i = nflag; 228 nflag = 1; 229 j = show_var(mib, len); 230 if (!j && !bflag) 231 putchar('\n'); 232 nflag = i; 233 } 234} 235 236/* These functions will dump out various interesting structures. */ 237 238static int 239S_clockinfo(int l2, void *p) 240{ 241 struct clockinfo *ci = (struct clockinfo*)p; 242 if (l2 != sizeof(*ci)) 243 err(1, "S_clockinfo %d != %d", l2, sizeof(*ci)); 244 printf("{ hz = %d, tick = %d, tickadj = %d, profhz = %d, stathz = %d }", 245 ci->hz, ci->tick, ci->tickadj, ci->profhz, ci->stathz); 246 return (0); 247} 248 249static int 250S_loadavg(int l2, void *p) 251{ 252 struct loadavg *tv = (struct loadavg*)p; 253 254 if (l2 != sizeof(*tv)) 255 err(1, "S_loadavg %d != %d", l2, sizeof(*tv)); 256 257 printf("{ %.2f %.2f %.2f }", 258 (double)tv->ldavg[0]/(double)tv->fscale, 259 (double)tv->ldavg[1]/(double)tv->fscale, 260 (double)tv->ldavg[2]/(double)tv->fscale); 261 return (0); 262} 263 264static int 265S_timeval(int l2, void *p) 266{ 267 struct timeval *tv = (struct timeval*)p; 268 time_t tv_sec; 269 char *p1, *p2; 270 271 if (l2 != sizeof(*tv)) 272 err(1, "S_timeval %d != %d", l2, sizeof(*tv)); 273 printf("{ sec = %ld, usec = %ld } ", 274 tv->tv_sec, tv->tv_usec); 275 tv_sec = tv->tv_sec; 276 p1 = strdup(ctime(&tv_sec)); 277 for (p2=p1; *p2 ; p2++) 278 if (*p2 == '\n') 279 *p2 = '\0'; 280 fputs(p1, stdout); 281 return (0); 282} 283 284static int 285T_dev_t(int l2, void *p) 286{ 287 dev_t *d = (dev_t *)p; 288 if (l2 != sizeof(*d)) 289 err(1, "T_dev_T %d != %d", l2, sizeof(*d)); 290 if ((int)(*d) != -1) { 291 if (minor(*d) > 255 || minor(*d) < 0) 292 printf("{ major = %d, minor = 0x%x }", 293 major(*d), minor(*d)); 294 else 295 printf("{ major = %d, minor = %d }", 296 major(*d), minor(*d)); 297 } 298 return (0); 299} 300 301/* 302 * These functions uses a presently undocumented interface to the kernel 303 * to walk the tree and get the type so it can print the value. 304 * This interface is under work and consideration, and should probably 305 * be killed with a big axe by the first person who can find the time. 306 * (be aware though, that the proper interface isn't as obvious as it 307 * may seem, there are various conflicting requirements. 308 */ 309 310static int 311name2oid(char *name, int *oidp) 312{ 313 int oid[2]; 314 int i; 315 size_t j; 316 317 oid[0] = 0; 318 oid[1] = 3; 319 320 j = CTL_MAXNAME * sizeof(int); 321 i = sysctl(oid, 2, oidp, &j, name, strlen(name)); 322 if (i < 0) 323 return i; 324 j /= sizeof(int); 325 return (j); 326} 327 328static int 329oidfmt(int *oid, int len, char *fmt, u_int *kind) 330{ 331 int qoid[CTL_MAXNAME+2]; 332 u_char buf[BUFSIZ]; 333 int i; 334 size_t j; 335 336 qoid[0] = 0; 337 qoid[1] = 4; 338 memcpy(qoid + 2, oid, len * sizeof(int)); 339 340 j = sizeof(buf); 341 i = sysctl(qoid, len + 2, buf, &j, 0, 0); 342 if (i) 343 err(1, "sysctl fmt %d %d %d", i, j, errno); 344 345 if (kind) 346 *kind = *(u_int *)buf; 347 348 if (fmt) 349 strcpy(fmt, (char *)(buf + sizeof(u_int))); 350 return 0; 351} 352 353/* 354 * This formats and outputs the value of one variable 355 * 356 * Returns zero if anything was actually output. 357 * Returns one if didn't know what to do with this. 358 * Return minus one if we had errors. 359 */ 360 361static int 362show_var(int *oid, int nlen) 363{ 364 u_char buf[BUFSIZ], *val, *p; 365 char name[BUFSIZ], *fmt; 366 int qoid[CTL_MAXNAME+2]; 367 int i; 368 size_t j, len; 369 u_int kind; 370 int (*func)(int, void *); 371 372 qoid[0] = 0; 373 memcpy(qoid + 2, oid, nlen * sizeof(int)); 374 375 qoid[1] = 1; 376 j = sizeof(name); 377 i = sysctl(qoid, nlen + 2, name, &j, 0, 0); 378 if (i || !j) 379 err(1, "sysctl name %d %d %d", i, j, errno); 380 381 if (Nflag) { 382 printf("%s", name); 383 return (0); 384 } 385 386 /* find an estimate of how much we need for this var */ 387 j = 0; 388 i = sysctl(oid, nlen, 0, &j, 0, 0); 389 j += j; /* we want to be sure :-) */ 390 391 val = alloca(j); 392 len = j; 393 i = sysctl(oid, nlen, val, &len, 0, 0); 394 if (i || !len) 395 return (1); 396 397 if (bflag) { 398 fwrite(val, 1, len, stdout); 399 return (0); 400 } 401 402 qoid[1] = 4; 403 j = sizeof(buf); 404 i = sysctl(qoid, nlen + 2, buf, &j, 0, 0); 405 if (i || !j) 406 err(1, "sysctl fmt %d %d %d", i, j, errno); 407 408 kind = *(u_int *)buf; 409 410 fmt = (char *)(buf + sizeof(u_int)); 411 412 p = val; 413 switch (*fmt) { 414 case 'A': 415 if (!nflag) 416 printf("%s: ", name); 417 printf("%s", p); 418 return (0); 419 420 case 'I': 421 if (!nflag) 422 printf("%s: ", name); 423 fmt++; 424 val = ""; 425 while (len >= sizeof(int)) { 426 if(*fmt == 'U') 427 printf("%s%u", val, *(unsigned int *)p); 428 else 429 printf("%s%d", val, *(int *)p); 430 val = " "; 431 len -= sizeof(int); 432 p += sizeof(int); 433 } 434 return (0); 435 436 case 'L': 437 if (!nflag) 438 printf("%s: ", name); 439 fmt++; 440 val = ""; 441 while (len >= sizeof(long)) { 442 if(*fmt == 'U') 443 printf("%s%lu", val, *(unsigned long *)p); 444 else 445 printf("%s%ld", val, *(long *)p); 446 val = " "; 447 len -= sizeof(long); 448 p += sizeof(long); 449 } 450 return (0); 451 452 case 'P': 453 if (!nflag) 454 printf("%s: ", name); 455 printf("%p", *(void **)p); 456 return (0); 457 458 case 'T': 459 case 'S': 460 i = 0; 461 if (strcmp(fmt, "S,clockinfo") == 0) 462 func = S_clockinfo; 463 else if (strcmp(fmt, "S,timeval") == 0) 464 func = S_timeval; 465 else if (strcmp(fmt, "S,loadavg") == 0) 466 func = S_loadavg; 467 else if (strcmp(fmt, "T,dev_t") == 0) 468 func = T_dev_t; 469 else 470 func = NULL; 471 if (func) { 472 if (!nflag) 473 printf("%s: ", name); 474 return ((*func)(len, p)); 475 } 476 /* FALL THROUGH */ 477 default: 478 if (!oflag && !xflag) 479 return (1); 480 if (!nflag) 481 printf("%s: ", name); 482 printf("Format:%s Length:%d Dump:0x", fmt, len); 483 while (len-- && (xflag || p < val + 16)) 484 printf("%02x", *p++); 485 if (!xflag && len > 16) 486 printf("..."); 487 return (0); 488 } 489 return (1); 490} 491 492static int 493sysctl_all (int *oid, int len) 494{ 495 int name1[22], name2[22]; 496 int i, j; 497 size_t l1, l2; 498 499 name1[0] = 0; 500 name1[1] = 2; 501 l1 = 2; 502 if (len) { 503 memcpy(name1+2, oid, len * sizeof(int)); 504 l1 += len; 505 } else { 506 name1[2] = 1; 507 l1++; 508 } 509 for (;;) { 510 l2 = sizeof(name2); 511 j = sysctl(name1, l1, name2, &l2, 0, 0); 512 if (j < 0) { 513 if (errno == ENOENT) 514 return 0; 515 else 516 err(1, "sysctl(getnext) %d %d", j, l2); 517 } 518 519 l2 /= sizeof(int); 520 521 if (l2 < len) 522 return 0; 523 524 for (i = 0; i < len; i++) 525 if (name2[i] != oid[i]) 526 return 0; 527 528 i = show_var(name2, l2); 529 if (!i && !bflag) 530 putchar('\n'); 531 532 memcpy(name1+2, name2, l2 * sizeof(int)); 533 l1 = 2 + l2; 534 } 535} 536