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