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