1 /* 2 * Copyright (c) 1999-2010 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23/* 24 * Copyright (c) 1993 25 * The Regents of the University of California. All rights reserved. 26 * 27 * Redistribution and use in source and binary forms, with or without 28 * modification, are permitted provided that the following conditions 29 * are met: 30 * 1. Redistributions of source code must retain the above copyright 31 * notice, this list of conditions and the following disclaimer. 32 * 2. Redistributions in binary form must reproduce the above copyright 33 * notice, this list of conditions and the following disclaimer in the 34 * documentation and/or other materials provided with the distribution. 35 * 4. Neither the name of the University nor the names of its contributors 36 * may be used to endorse or promote products derived from this software 37 * without specific prior written permission. 38 * 39 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 40 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 41 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 42 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 43 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 44 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 45 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 46 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 47 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 48 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 49 * SUCH DAMAGE. 50 */ 51 52 /* 53 Modified November 1, 2000, by Ryan Rempel, ryan.rempel@utoronto.ca 54 55 The Darwin sysctl mechanism is in a state of flux. Parts of the kernel use the old 56 style of BSD sysctl definition, and other parts use the new style. The sysctl (8) 57 command that shipped with Darwin 1.2 (OS X PB) did not allow you to access 58 all possible sysctl values. In particular, it did not permit access to sysctl values 59 created by kernel extensions--hence my particular interest. The freeBSD sysctl (8) 60 command compiled and ran under Darwin 1.2, and it did permit access to 61 sysctl values created by kernel extensions, as well as several others. However, it 62 did not permit access to many other values which the Darwin 1.2 sysctl could access. 63 64 What I have done is merge the Darwin 1.2 sysctl and the freeBSD sysctl. Essentially, 65 there are two points of merger. When showing all values (i.e. -a, -A, or -X), sysctl now 66 runs the Darwin 1.2 routine to show all values, and then the freeBSD routine. This does 67 result in some duplication. When getting or setting a particular value, sysctl now tries 68 the freeBSD way first. If it cannot find the value, then it tries the Darwin 1.2 way. 69 70 There are a few oddities which this creates (aside from some duplication with -a, -A, 71 and -X). The freeBSD version of sysctl now supports two extra options, -b and -X. 72 In this syctl, those options are supported where the value is retrieved by the freeBSD 73 routine, and have no effect where the value is retrieved by the Darwin 1.2 routine. 74 The freeBSD sysctl uses a ':' to separate the name and the value, whereas Darwin 1.2's 75 sysctl uses a '='. I have left this way, as it lets you know which routine was used, 76 should it matter. 77 78 I have also fixed several lines which gave warnings previously, one of which appears 79 to have been an actual bug (bufp was dereferenced when it shouldn't have been). 80 I have also incoporated my previous patch to permit setting kern.hostid as an unsigned 81 integer. In the freeBSD side of the code, I have incorporated a general fix for 82 setting values where the format is specified as unsigned integer. 83 */ 84 85#include <sys/cdefs.h> 86#ifndef lint 87__unused static char copyright[] = 88"@(#) Copyright (c) 1993\n\ 89 The Regents of the University of California. All rights reserved.\n"; 90#endif /* not lint */ 91 92#ifndef lint 93__unused static char sccsid[] = "@(#)sysctl.c 8.5 (Berkeley) 5/9/95"; 94#endif /* not lint */ 95 96#include <sys/param.h> 97#include <sys/gmon.h> 98#include <sys/mount.h> 99#include <sys/stat.h> 100#include <sys/sysctl.h> 101#include <sys/socket.h> 102#ifdef __APPLE__ 103#include <mach/machine/vm_param.h> 104#include <mach/machine/vm_types.h> 105#include <mach/mach_types.h> 106#else 107#include <vm/vm_param.h> 108#endif /* __APPLE__ */ 109 110#include <errno.h> 111#include <ctype.h> 112#include <unistd.h> 113#include <stdio.h> 114#include <stdlib.h> 115#include <string.h> 116 117#include <sys/types.h> 118#include <sys/resource.h> 119#include <err.h> 120 121struct ctlname topname[] = CTL_NAMES; 122struct ctlname kernname[] = CTL_KERN_NAMES; 123struct ctlname vmname[] = CTL_VM_NAMES; 124struct ctlname hwname[] = CTL_HW_NAMES; 125struct ctlname username[] = CTL_USER_NAMES; 126struct ctlname debugname[CTL_DEBUG_MAXID]; 127struct ctlname *vfsname; 128#ifdef CTL_MACHDEP_NAMES 129struct ctlname machdepname[] = CTL_MACHDEP_NAMES; 130#endif 131char names[BUFSIZ]; 132int lastused; 133 134struct list { 135 struct ctlname *list; 136 int size; 137}; 138struct list toplist = { topname, CTL_MAXID }; 139struct list secondlevel[] = { 140 { 0, 0 }, /* CTL_UNSPEC */ 141 { kernname, KERN_MAXID }, /* CTL_KERN */ 142 { vmname, VM_MAXID }, /* CTL_VM */ 143 { 0, 0 }, /* CTL_VFS */ 144 { 0, 0 }, /* CTL_NET */ 145 { 0, CTL_DEBUG_MAXID }, /* CTL_DEBUG */ 146 { hwname, HW_MAXID }, /* CTL_HW */ 147#ifdef CTL_MACHDEP_NAMES 148 { machdepname, CPU_MAXID }, /* CTL_MACHDEP */ 149#else 150 { 0, 0 }, /* CTL_MACHDEP */ 151#endif 152 { username, USER_MAXID }, /* CTL_USER_NAMES */ 153}; 154 155static int Aflag, aflag, bflag, hflag, nflag, wflag, Xflag; 156static int foundSome = 0; 157static int invalid_name_used = 0; 158 159void listall(char *prefix, struct list *lp); 160void old_parse(char *string, int flags); 161void debuginit(); 162void vfsinit(); 163int findname(char *string, char *level, char **bufp, struct list *namelist); 164void usage(); 165 166static void parse(char *string, int flags); 167static int oidfmt(int *, int, char *, u_int *); 168static int show_var(int *, int, int); 169static int sysctl_all (int *oid, int len); 170static int name2oid(char *, int *); 171 172/* 173 * Variables requiring special processing. 174 */ 175#define CLOCK 0x00000001 176#define BOOTTIME 0x00000002 177#define CONSDEV 0x00000004 178 179int 180main(argc, argv) 181 int argc; 182 char *argv[]; 183{ 184// extern char *optarg; // unused 185 extern int optind; 186 int ch, lvl1; 187 188 while ((ch = getopt(argc, argv, "AabnwX")) != EOF) { 189 switch (ch) { 190 case 'A': Aflag = 1; break; 191 case 'a': aflag = 1; break; 192 case 'b': bflag = 1; break; 193 case 'h': hflag = 1; break; 194 case 'n': nflag = 1; break; 195 case 'w': wflag = 1; break; 196 case 'X': Xflag = Aflag = 1; break; 197 default: usage(); 198 } 199 } 200 argc -= optind; 201 argv += optind; 202 203 if (argc == 0 && (Aflag || aflag)) { 204 debuginit(); 205 vfsinit(); 206 for (lvl1 = 1; lvl1 < CTL_MAXID; lvl1++) 207 listall(topname[lvl1].ctl_name, &secondlevel[lvl1]); 208 exit (sysctl_all(0, 0)); 209 } 210 if (argc == 0) 211 usage(); 212 for (; *argv != NULL; ++argv) 213 parse(*argv, 1); 214 exit(invalid_name_used ? 1 : 0); 215} 216 217/* 218 * List all variables known to the system. 219 */ 220void 221listall(prefix, lp) 222 char *prefix; 223 struct list *lp; 224{ 225 int lvl2; 226 char *cp, name[BUFSIZ]; 227 228 if (lp->list == 0) 229 return; 230 strcpy(name, prefix); 231 cp = &name[strlen(name)]; 232 *cp++ = '.'; 233 for (lvl2 = 0; lvl2 < lp->size; lvl2++) { 234 if (lp->list[lvl2].ctl_name == 0) 235 continue; 236 strcpy(cp, lp->list[lvl2].ctl_name); 237 old_parse(name, Aflag); 238 } 239} 240 241/* 242 * Parse a name into a MIB entry. 243 * Lookup and print out the MIB entry if it exists. 244 * Set a new value if requested. 245 */ 246void 247old_parse(string, flags) 248 char *string; 249 int flags; 250{ 251 int indx, type, state, len; 252 size_t size; 253 int special = 0; 254 void *newval = 0; 255 int intval, newsize = 0; 256 unsigned int uintval; 257 int useUnsignedInt = 0; 258 quad_t quadval; 259 struct list *lp; 260 struct vfsconf vfc; 261 int mib[CTL_MAXNAME]; 262 char *cp, *bufp, buf[BUFSIZ] /*, strval[BUFSIZ] */ ; 263 264 bufp = buf; 265 snprintf(buf, BUFSIZ, "%s", string); 266 if ((cp = strchr(string, '=')) != NULL) { 267 if (!wflag) { 268 fprintf(stderr, "Must specify -w to set variables\n"); 269 exit(2); 270 } 271 *strchr(buf, '=') = '\0'; 272 *cp++ = '\0'; 273 while (isspace(*cp)) 274 cp++; 275 newval = cp; 276 newsize = strlen(cp); 277 } 278 if ((indx = findname(string, "top", &bufp, &toplist)) == -1) 279 return; 280 mib[0] = indx; 281 if (indx == CTL_VFS) 282 vfsinit(); 283 if (indx == CTL_DEBUG) 284 debuginit(); 285 lp = &secondlevel[indx]; 286 if (lp->list == 0) { 287 if (!foundSome) fprintf(stderr, "%s: class is not implemented\n", 288 topname[indx].ctl_name); 289 return; 290 } 291 if (bufp == NULL) { 292 listall(topname[indx].ctl_name, lp); 293 return; 294 } 295 if ((indx = findname(string, "second", &bufp, lp)) == -1) 296 return; 297 mib[1] = indx; 298 type = lp->list[indx].ctl_type; 299 len = 2; 300 switch (mib[0]) { 301 302 case CTL_KERN: 303 switch (mib[1]) { 304 case KERN_PROF: 305 mib[2] = GPROF_STATE; 306 size = sizeof state; 307 if (sysctl(mib, 3, &state, &size, NULL, 0) < 0) { 308 if (flags == 0) 309 return; 310 if (!nflag) 311 fprintf(stdout, "%s: ", string); 312 fprintf(stderr, 313 "kernel is not compiled for profiling\n"); 314 return; 315 } 316 if (!nflag) 317 fprintf(stdout, "%s: %s\n", string, 318 state == GMON_PROF_OFF ? "off" : "running"); 319 return; 320 case KERN_VNODE: 321 case KERN_FILE: 322 if (flags == 0) 323 return; 324 fprintf(stderr, 325 "Use pstat to view %s information\n", string); 326 return; 327 case KERN_PROC: 328 if (flags == 0) 329 return; 330 fprintf(stderr, 331 "Use ps to view %s information\n", string); 332 return; 333 case KERN_CLOCKRATE: 334 special |= CLOCK; 335 break; 336 case KERN_BOOTTIME: 337 special |= BOOTTIME; 338 break; 339 case KERN_HOSTID: 340 useUnsignedInt = 1; 341 break; 342 } 343 break; 344 345 case CTL_HW: 346 useUnsignedInt = 1; 347 break; 348 349 case CTL_VM: break; 350#if 0 /* XXX Handled by the new sysctl mechanism */ 351 switch (mib[1]) { 352 case VM_LOADAVG: { /* XXX this is bogus */ 353 double loads[3]; 354 355 getloadavg(loads, 3); 356 if (!nflag) 357 fprintf(stdout, "%s: ", string); 358 fprintf(stdout, "%.2f %.2f %.2f\n", 359 loads[0], loads[1], loads[2]); 360 return; 361 } 362 case VM_SWAPUSAGE: { 363 struct xsw_usage xsu; 364 int saved_errno; 365 366 size = sizeof (xsu); 367 if (sysctl(mib, 2, &xsu, &size, NULL, 0) != 0) { 368 if (flags == 0) 369 return; 370 saved_errno = errno; 371 if (!nflag) 372 fprintf(stderr, "%s: ", string); 373 fprintf(stderr, "sysctl(VM_SWAPUSAGE): %s\n", 374 strerror(saved_errno)); 375 return; 376 } 377 378 if (!nflag) 379 fprintf(stdout, "%s: ", string); 380 fprintf(stdout, 381 "total = %.2fM used = %.2fM free = %.2fM %s\n", 382 ((double) xsu.xsu_total) / (1024.0 * 1024.0), 383 ((double) xsu.xsu_used) / (1024.0 * 1024.0), 384 ((double) xsu.xsu_avail) / (1024.0 * 1024.0), 385 xsu.xsu_encrypted ? "(encrypted)" : ""); 386 return; 387 } 388 } 389 if (flags == 0) 390 return; 391 fprintf(stderr, 392 "Use vmstat or systat to view %s information\n", string); 393 return; 394#endif 395 396 case CTL_DEBUG: 397 mib[2] = CTL_DEBUG_VALUE; 398 len = 3; 399 break; 400 401 case CTL_MACHDEP: 402#ifdef CPU_CONSDEV 403 if (mib[1] == CPU_CONSDEV) 404 special |= CONSDEV; 405#endif 406 break; 407 408 case CTL_VFS: 409 mib[3] = mib[1]; 410 mib[1] = VFS_GENERIC; 411 mib[2] = VFS_CONF; 412 len = 4; 413 size = sizeof vfc; 414 if (sysctl(mib, 4, &vfc, &size, (void *)0, (size_t)0) < 0) { 415 perror("vfs print"); 416 return; 417 } 418 if (flags == 0 && vfc.vfc_refcount == 0) 419 return; 420 if (!nflag) 421 fprintf(stdout, "%s has %d mounted instance%s\n", 422 string, vfc.vfc_refcount, 423 vfc.vfc_refcount != 1 ? "s" : ""); 424 else 425 fprintf(stdout, "%d\n", vfc.vfc_refcount); 426 return; 427 428 case CTL_USER: 429 break; 430 431 default: 432 fprintf(stderr, "Illegal top level value: %d\n", mib[0]); 433 return; 434 435 } 436 if (bufp) { 437 fprintf(stderr, "name %s in %s is unknown\n", bufp, string); 438 return; 439 } 440 if (newsize > 0) { 441 switch (type) { 442 case CTLTYPE_INT: 443 if (useUnsignedInt) { 444 uintval = strtoul(newval, NULL, 0); 445 if ((uintval == 0) && (errno == EINVAL)) { 446 fprintf(stderr, "invalid argument: %s\n", 447 (char *)newval); 448 return; 449 } 450 newval = &uintval; 451 newsize = sizeof uintval; 452 } else { 453 intval = strtol(newval, NULL, 0); 454 if ((intval == 0) && (errno == EINVAL)) { 455 fprintf(stderr, "invalid argument: %s\n", 456 (char *)newval); 457 return; 458 } 459 newval = &intval; 460 newsize = sizeof intval; 461 } 462 break; 463 464 case CTLTYPE_QUAD: 465 quadval = strtoq(newval, NULL, 0); 466 if ((quadval == 0) && (errno == EINVAL)) { 467 fprintf(stderr, "invalid argument: %s\n", 468 (char *)newval); 469 return; 470 } 471 newval = &quadval; 472 newsize = sizeof quadval; 473 break; 474 } 475 } 476 size = BUFSIZ; 477 if (sysctl(mib, len, buf, &size, newsize ? newval : 0, newsize) == -1) { 478 if (flags == 0) 479 return; 480 switch (errno) { 481 case ENOTSUP: 482 fprintf(stderr, "%s: value is not available\n", string); 483 return; 484 case ENOTDIR: 485 fprintf(stderr, "%s: specification is incomplete\n", 486 string); 487 return; 488 case ENOMEM: 489 fprintf(stderr, "%s: type is unknown to this program\n", 490 string); 491 return; 492 case ENOENT: 493 fprintf(stderr, "%s: no such MIB\n", 494 string); 495 return; 496 default: 497 perror(string); 498 return; 499 } 500 } 501 if (special & CLOCK) { 502 struct clockinfo *clkp = (struct clockinfo *)buf; 503 504 if (!nflag) 505 fprintf(stdout, "%s: ", string); 506 fprintf(stdout, 507 "hz = %d, tick = %d, profhz = %d, stathz = %d\n", 508 clkp->hz, clkp->tick, clkp->profhz, clkp->stathz); 509 return; 510 } 511 if (special & BOOTTIME) { 512 struct timeval *btp = (struct timeval *)buf; 513 514 if (!nflag) 515 fprintf(stdout, "%s = %s\n", string, 516 ctime((time_t *) &btp->tv_sec)); 517 else 518 fprintf(stdout, "%ld\n", btp->tv_sec); 519 return; 520 } 521 if (special & CONSDEV) { 522 dev_t dev = *(dev_t *)buf; 523 524 if (!nflag) 525 fprintf(stdout, "%s = %s\n", string, 526 devname(dev, S_IFCHR)); 527 else 528 fprintf(stdout, "0x%x\n", dev); 529 return; 530 } 531 switch (type) { 532 case CTLTYPE_INT: 533 if (newsize == 0) { 534 if (!nflag) 535 fprintf(stdout, "%s = ", string); 536 fprintf(stdout, useUnsignedInt ? "%u\n" : "%d\n", *(int *)buf); 537 } else { 538 if (!nflag) 539 fprintf(stdout, useUnsignedInt ? "%s: %u -> " : "%s: %d -> ", 540 string, *(int *)buf); 541 fprintf(stdout, useUnsignedInt ? "%u\n" : "%d\n", *(int *)newval); 542 } 543 return; 544 545 case CTLTYPE_STRING: 546 if (newsize == 0) { 547 if (!nflag) 548 fprintf(stdout, "%s = ", string); 549 fprintf(stdout, "%s\n", buf); 550 } else { 551 if (!nflag) 552 fprintf(stdout, "%s: %s -> ", string, buf); 553 fprintf(stdout, "%s\n", (char *) newval); 554 } 555 return; 556 557 case CTLTYPE_QUAD: 558 if (newsize == 0) { 559 if (!nflag) 560 fprintf(stdout, "%s = ", string); 561 fprintf(stdout, "%qd\n", *(quad_t *)buf); 562 } else { 563 if (!nflag) 564 fprintf(stdout, "%s: %qd -> ", string, 565 *(quad_t *)buf); 566 fprintf(stdout, "%qd\n", *(quad_t *)newval); 567 } 568 return; 569 570 case CTLTYPE_NODE: 571 case CTLTYPE_STRUCT: 572 return; 573 574 default: 575 fprintf(stderr, "%s: unknown type returned\n", 576 string); 577 return; 578 } 579} 580 581/* 582 * Initialize the set of debugging names 583 */ 584void debuginit() 585{ 586 int mib[3], loc, i; 587 size_t size; 588 589 if (secondlevel[CTL_DEBUG].list != 0) 590 return; 591 secondlevel[CTL_DEBUG].list = debugname; 592 mib[0] = CTL_DEBUG; 593 mib[2] = CTL_DEBUG_NAME; 594 for (loc = lastused, i = 0; i < CTL_DEBUG_MAXID; i++) { 595 mib[1] = i; 596 size = BUFSIZ - loc; 597 if (sysctl(mib, 3, &names[loc], &size, NULL, 0) == -1) 598 continue; 599 debugname[i].ctl_name = &names[loc]; 600 debugname[i].ctl_type = CTLTYPE_INT; 601 loc += size; 602 } 603 lastused = loc; 604} 605 606/* 607 * Initialize the set of filesystem names 608 */ 609void vfsinit() 610{ 611 int mib[4], maxtypenum, cnt, loc, size; 612 struct vfsconf vfc; 613 size_t buflen; 614 615 if (secondlevel[CTL_VFS].list != 0) 616 return; 617 mib[0] = CTL_VFS; 618 mib[1] = VFS_GENERIC; 619 mib[2] = VFS_MAXTYPENUM; 620 buflen = 4; 621 if (sysctl(mib, 3, &maxtypenum, &buflen, (void *)0, (size_t)0) < 0) 622 return; 623 if ((vfsname = malloc(maxtypenum * sizeof(*vfsname))) == 0) 624 return; 625 memset(vfsname, 0, maxtypenum * sizeof(*vfsname)); 626 mib[2] = VFS_CONF; 627 buflen = sizeof vfc; 628 for (loc = lastused, cnt = 0; cnt < maxtypenum; cnt++) { 629 mib[3] = cnt; 630 if (sysctl(mib, 4, &vfc, &buflen, (void *)0, (size_t)0) < 0) { 631 if (errno == ENOTSUP) 632 continue; 633 perror("vfsinit"); 634 free(vfsname); 635 return; 636 } 637 strcat(&names[loc], vfc.vfc_name); 638 vfsname[cnt].ctl_name = &names[loc]; 639 vfsname[cnt].ctl_type = CTLTYPE_INT; 640 size = strlen(vfc.vfc_name) + 1; 641 loc += size; 642 } 643 lastused = loc; 644 secondlevel[CTL_VFS].list = vfsname; 645 secondlevel[CTL_VFS].size = maxtypenum; 646 return; 647} 648 649/* 650 * Scan a list of names searching for a particular name. 651 */ 652int 653findname(string, level, bufp, namelist) 654 char *string; 655 char *level; 656 char **bufp; 657 struct list *namelist; 658{ 659 char *name; 660 int i; 661 662 /* Make 'sysctl kern.' style behave the same as 'sysctl kern' 3360872*/ 663 if (bufp[0][strlen(*bufp)-1] == '.') 664 bufp[0][strlen(*bufp)-1]='\0'; 665 if (namelist->list == 0 || (name = strsep(bufp, ".")) == NULL) { 666 if (!foundSome) { 667 fprintf(stderr, "%s: incomplete specification\n", string); 668 invalid_name_used = 1; 669 } 670 return (-1); 671 } 672 for (i = 0; i < namelist->size; i++) 673 if (namelist->list[i].ctl_name != NULL && 674 strcmp(name, namelist->list[i].ctl_name) == 0) 675 break; 676 if (i == namelist->size) { 677 if (!foundSome) { 678 fprintf(stderr, "%s level name %s in %s is invalid\n", 679 level, name, string); 680 invalid_name_used = 1; 681 } 682 return (-1); 683 } 684 return (i); 685} 686 687void usage() 688{ 689 690 (void)fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n", 691 "usage: sysctl [-bn] variable ...", 692 " sysctl [-bn] -w variable=value ...", 693 " sysctl [-bn] -a", 694 " sysctl [-bn] -A", 695 " sysctl [-bn] -X"); 696 exit(1); 697} 698 699/* 700 * Parse a name into a MIB entry. 701 * Lookup and print out the MIB entry if it exists. 702 * Set a new value if requested. 703 */ 704static void 705parse(char *string, int flags) 706{ 707 int len, i, j; 708 void *newval = 0; 709 int intval, newsize = 0; 710 unsigned int uintval; 711 quad_t quadval; 712 int mib[CTL_MAXNAME]; 713 char *cp, *bufp, buf[BUFSIZ], fmt[BUFSIZ]; 714 u_int kind; 715 716 bufp = buf; 717 if (snprintf(buf, BUFSIZ, "%s", string) >= BUFSIZ) 718 errx(1, "MIB too long"); 719 snprintf(buf, BUFSIZ, "%s", string); 720 if ((cp = strchr(string, '=')) != NULL) { 721 if (!wflag) 722 errx(2, "must specify -w to set variables"); 723 *strchr(buf, '=') = '\0'; 724 *cp++ = '\0'; 725 while (isspace(*cp)) 726 cp++; 727 newval = cp; 728 newsize = strlen(cp); 729 } else { 730 if (wflag) 731 usage(); 732 } 733 len = name2oid(bufp, mib); 734 735 if (len < 0) { 736 if (cp != NULL) { 737 while (*cp != '\0') cp--; 738 *cp = '='; 739 } 740 old_parse (string, flags); 741 return; 742 } 743 744 /* 745 * An non-zero return here is an OID space containing parameters which 746 * needs to be ignored in the interests of backward compatibility with 747 * pre-newsysctl sysctls. 748 */ 749 if (oidfmt(mib, len, fmt, &kind)) 750 return; 751 752 if (!wflag) { 753 if ((kind & CTLTYPE) == CTLTYPE_NODE) { 754 sysctl_all(mib, len); 755 foundSome = 1; 756 old_parse (string, flags); 757 } else { 758 i = show_var(mib, len, 1); 759 if (!i && !bflag) 760 putchar('\n'); 761 } 762 } else { 763 if ((kind & CTLTYPE) == CTLTYPE_NODE) 764 errx(1, "oid '%s' isn't a leaf node", bufp); 765 766 if (!(kind&CTLFLAG_WR)) 767 errx(1, "oid '%s' is read only", bufp); 768 769 switch (kind & CTLTYPE) { 770 case CTLTYPE_INT: 771 if ((*fmt == 'I') && (*(fmt + 1) == 'U')) { 772 uintval = (unsigned int) strtoul (newval, NULL, 0); 773 if ((uintval == 0) && 774 (errno == EINVAL)) { 775 errx(1, "invalid argument: %s", 776 (char *)newval); 777 return; 778 } 779 newval = &uintval; 780 newsize = sizeof uintval; 781 } else { 782 intval = (int) strtol(newval, NULL, 0); 783 if ((intval == 0) && 784 (errno == EINVAL)) { 785 errx(1, "invalid argument: %s", 786 (char *)newval); 787 return; 788 } 789 newval = &intval; 790 newsize = sizeof intval; 791 } 792 break; 793 case CTLTYPE_STRING: 794 break; 795 case CTLTYPE_QUAD: 796 quadval = strtoq(newval, NULL, 0); 797 if ((quadval == 0) && (errno == EINVAL)) { 798 errx(1, "invalid argument %s", (char *)newval); 799 return; 800 } 801 newval = &quadval; 802 newsize = sizeof(quadval); 803 break; 804 default: 805 errx(1, "oid '%s' is type %d," 806 " cannot set that", bufp, 807 kind & CTLTYPE); 808 } 809 810 i = show_var(mib, len, 1); 811 if (sysctl(mib, len, 0, 0, newval, newsize) == -1) { 812 if (!i && !bflag) 813 putchar('\n'); 814 switch (errno) { 815 case ENOTSUP: 816 errx(1, "%s: value is not available", 817 string); 818 case ENOTDIR: 819 errx(1, "%s: specification is incomplete", 820 string); 821 case ENOMEM: 822 errx(1, "%s: type is unknown to this program", 823 string); 824 default: 825 warn("%s", string); 826 return; 827 } 828 } 829 if (!bflag) 830 printf(" -> "); 831 i = nflag; 832 nflag = 1; 833 j = show_var(mib, len, 1); 834 if (!j && !bflag) 835 putchar('\n'); 836 nflag = i; 837 } 838} 839 840/* These functions will dump out various interesting structures. */ 841 842static int 843S_clockinfo(int l2, void *p) 844{ 845 struct clockinfo *ci = (struct clockinfo*)p; 846 847 if (l2 != sizeof(*ci)) { 848 warnx("S_clockinfo %d != %ld", l2, sizeof(*ci)); 849 return (1); 850 } 851 printf(hflag ? "{ hz = %'d, tick = %'d, tickadj = %'d, profhz = %'d, stathz = %'d }" : 852 "{ hz = %d, tick = %d, tickadj = %d, profhz = %d, stathz = %d }", 853 ci->hz, ci->tick, ci->tickadj, ci->profhz, ci->stathz); 854 return (0); 855} 856 857static int 858S_loadavg(int l2, void *p) 859{ 860 struct loadavg *tv = (struct loadavg*)p; 861 862 if (l2 != sizeof(*tv)) { 863 warnx("S_loadavg %d != %ld", l2, sizeof(*tv)); 864 return (1); 865 } 866 printf(hflag ? "{ %'.2f %'.2f %'.2f }" : "{ %.2f %.2f %.2f }", 867 (double)tv->ldavg[0]/(double)tv->fscale, 868 (double)tv->ldavg[1]/(double)tv->fscale, 869 (double)tv->ldavg[2]/(double)tv->fscale); 870 return (0); 871} 872 873static int 874S_timeval(int l2, void *p) 875{ 876 struct timeval *tv = (struct timeval*)p; 877 time_t tv_sec; 878 char *p1, *p2; 879 880 if (l2 != sizeof(*tv)) { 881 warnx("S_timeval %d != %ld", l2, sizeof(*tv)); 882 return (1); 883 } 884 printf(hflag ? "{ sec = %'jd, usec = %'ld } " : 885 "{ sec = %jd, usec = %ld } ", 886 (intmax_t)tv->tv_sec, (long)tv->tv_usec); 887 tv_sec = tv->tv_sec; 888 p1 = strdup(ctime(&tv_sec)); 889 for (p2=p1; *p2 ; p2++) 890 if (*p2 == '\n') 891 *p2 = '\0'; 892 fputs(p1, stdout); 893 free(p1); 894 return (0); 895} 896 897static int 898S_xswusage(int l2, void *p) 899{ 900 struct xsw_usage *xsu = (struct xsw_usage *)p; 901 902 if (l2 != sizeof(*xsu)) { 903 warnx("S_xswusage %d != %ld", l2, sizeof(*xsu)); 904 return (1); 905 } 906 fprintf(stdout, 907 "total = %.2fM used = %.2fM free = %.2fM %s", 908 ((double)xsu->xsu_total) / (1024.0 * 1024.0), 909 ((double)xsu->xsu_used) / (1024.0 * 1024.0), 910 ((double)xsu->xsu_avail) / (1024.0 * 1024.0), 911 xsu->xsu_encrypted ? "(encrypted)" : ""); 912 return (0); 913} 914 915static int 916T_dev_t(int l2, void *p) 917{ 918 dev_t *d = (dev_t *)p; 919 920 if (l2 != sizeof(*d)) { 921 warnx("T_dev_T %d != %ld", l2, sizeof(*d)); 922 return (1); 923 } 924 if ((int)(*d) != -1) { 925 if (minor(*d) > 255 || minor(*d) < 0) 926 printf("{ major = %d, minor = 0x%x }", 927 major(*d), minor(*d)); 928 else 929 printf("{ major = %d, minor = %d }", 930 major(*d), minor(*d)); 931 } 932 return (0); 933} 934 935/* 936 * These functions uses a presently undocumented interface to the kernel 937 * to walk the tree and get the type so it can print the value. 938 * This interface is under work and consideration, and should probably 939 * be killed with a big axe by the first person who can find the time. 940 * (be aware though, that the proper interface isn't as obvious as it 941 * may seem, there are various conflicting requirements. 942 */ 943 944static int 945name2oid(char *name, int *oidp) 946{ 947 int oid[2]; 948 int i; 949 size_t j; 950 951 oid[0] = 0; 952 oid[1] = 3; 953 954 j = CTL_MAXNAME * sizeof (int); 955 i = sysctl(oid, 2, oidp, &j, name, strlen(name)); 956 if (i < 0) 957 return i; 958 j /= sizeof (int); 959 return (j); 960} 961 962static int 963oidfmt(int *oid, int len, char *fmt, u_int *kind) 964{ 965 int qoid[CTL_MAXNAME+2]; 966 u_char buf[BUFSIZ]; 967 int i; 968 size_t j; 969 970 qoid[0] = 0; 971 qoid[1] = 4; 972 memcpy(qoid + 2, oid, len * sizeof(int)); 973 974 j = sizeof(buf); 975 i = sysctl(qoid, len + 2, buf, &j, 0, 0); 976 if (i) { 977 /* 978 * An ENOENT error return indicates that the OID in question 979 * is a node OID followed not by additional OID elements, but 980 * by integer parameters. We really do not want to support 981 * this type of thing going forward, but we alow it here for 982 * historical compatibility. Eventually, this will go away. 983 */ 984 if (errno == ENOENT) 985 return ENOENT; 986 err(1, "sysctl fmt %d %ld %d", i, j, errno); 987 } 988 989 if (kind) 990 *kind = *(u_int *)buf; 991 992 if (fmt) 993 strcpy(fmt, (char *)(buf + sizeof(u_int))); 994 return (0); 995} 996 997/* 998 * This formats and outputs the value of one variable 999 * 1000 * Returns zero if anything was actually output. 1001 * Returns one if didn't know what to do with this. 1002 * Return minus one if we had errors. 1003 */ 1004 1005static int 1006show_var(int *oid, int nlen, int show_masked) 1007{ 1008 u_char buf[BUFSIZ], *val, *mval, *p; 1009 char name[BUFSIZ], /* descr[BUFSIZ], */ *fmt; 1010 int qoid[CTL_MAXNAME+2]; 1011 int i; 1012 int retval; 1013 size_t j, len; 1014 u_int kind; 1015 int (*func)(int, void *) = 0; 1016 1017 qoid[0] = 0; 1018 memcpy(qoid + 2, oid, nlen * sizeof(int)); 1019 1020 qoid[1] = 1; 1021 j = sizeof name; 1022 i = sysctl(qoid, nlen + 2, name, &j, 0, 0); 1023 if (i || !j) 1024 err(1, "sysctl name %d %ld %d", i, j, errno); 1025 1026 /* find an estimate of how much we need for this var */ 1027 j = 0; 1028 i = sysctl(oid, nlen, 0, &j, 0, 0); 1029 j += j; /* we want to be sure :-) */ 1030 1031 val = mval = malloc(j); 1032 len = j; 1033 i = sysctl(oid, nlen, val, &len, 0, 0); 1034 if (i || !len) { 1035 retval = 1; 1036 goto RETURN; 1037 } 1038 1039 if (bflag) { 1040 fwrite(val, 1, len, stdout); 1041 retval = 0; 1042 goto RETURN; 1043 } 1044 1045 qoid[1] = 4; 1046 j = sizeof buf; 1047 i = sysctl(qoid, nlen + 2, buf, &j, 0, 0); 1048 /* 1049 * An ENOENT error return indicates that the OID in question 1050 * is a node OID followed not by additional OID elements, but 1051 * by integer parameters. We really do not want to support 1052 * this type of thing going forward, but we alow it here for 1053 * historical compatibility. Eventially, this will go away. 1054 */ 1055 if (i && errno == ENOENT) { 1056 retval = 1; 1057 goto RETURN; 1058 } 1059 1060 if (i || !j) 1061 err(1, "sysctl fmt %d %ld %d", i, j, errno); 1062 1063 kind = *(u_int *)buf; 1064 if (!show_masked && (kind & CTLFLAG_MASKED)) { 1065 retval = 1; 1066 goto RETURN; 1067 } 1068 1069 fmt = (char *)(buf + sizeof(u_int)); 1070 1071 p = val; 1072 switch (*fmt) { 1073 case '-': 1074 /* deprecated, do not print */ 1075 retval = 0; 1076 goto RETURN; 1077 1078 1079 case 'A': 1080 if (!nflag) 1081 printf("%s: ", name); 1082 printf("%s", p); 1083 retval = 0; 1084 goto RETURN; 1085 1086 case 'I': 1087 if (!nflag) 1088 printf("%s: ", name); 1089 fmt++; 1090 val = (unsigned char *)""; 1091 while (len >= sizeof(int)) { 1092 if(*fmt == 'U') 1093 printf("%s%u", val, *(unsigned int *)p); 1094 else 1095 printf("%s%d", val, *(int *)p); 1096 val = (unsigned char *)" "; 1097 len -= sizeof (int); 1098 p += sizeof (int); 1099 } 1100 retval = 0; 1101 goto RETURN; 1102 1103 case 'L': 1104 if (!nflag) 1105 printf("%s: ", name); 1106 fmt++; 1107 val = (unsigned char *)""; 1108 while (len >= sizeof(long)) { 1109 if(*fmt == 'U') 1110 printf("%s%lu", val, *(unsigned long *)p); 1111 else 1112 printf("%s%ld", val, *(long *)p); 1113 val = (unsigned char *)" "; 1114 len -= sizeof (long); 1115 p += sizeof (long); 1116 } 1117 retval = 0; 1118 goto RETURN; 1119 1120 case 'P': 1121 if (!nflag) 1122 printf("%s: ", name); 1123 printf("%p", *(void **)p); 1124 retval = 0; 1125 goto RETURN; 1126 1127 case 'Q': 1128 if (!nflag) 1129 printf("%s: ", name); 1130 fmt++; 1131 val = (unsigned char *)""; 1132 while (len >= sizeof(long long)) { 1133 if(*fmt == 'U') 1134 printf("%s%llu", val, *(unsigned long long *)p); 1135 else 1136 printf("%s%lld", val, *(long long *)p); 1137 val = (unsigned char *)" "; 1138 len -= sizeof (long long); 1139 p += sizeof (long long); 1140 } 1141 retval = 0; 1142 goto RETURN; 1143 1144 1145 case 'T': 1146 case 'S': 1147 i = 0; 1148 if (!strcmp(fmt, "S,clockinfo")) func = S_clockinfo; 1149 else if (!strcmp(fmt, "S,timeval")) func = S_timeval; 1150 else if (!strcmp(fmt, "S,loadavg")) func = S_loadavg; 1151 else if (!strcmp(fmt, "S,xsw_usage")) func = S_xswusage; 1152 else if (!strcmp(fmt, "T,dev_t")) func = T_dev_t; 1153 if (func) { 1154 if (!nflag) 1155 printf("%s: ", name); 1156 retval = (*func)(len, p); 1157 goto RETURN; 1158 } 1159 /* FALL THROUGH */ 1160 default: 1161 if (!Aflag) { 1162 retval = 1; 1163 goto RETURN; 1164 } 1165 if (!nflag) 1166 printf("%s: ", name); 1167 printf("Format:%s Length:%ld Dump:0x", fmt, len); 1168 while (len--) { 1169 printf("%02x", *p++); 1170 if (Xflag || p < val+16) 1171 continue; 1172 printf("..."); 1173 break; 1174 } 1175 retval = 0; 1176 goto RETURN; 1177 } 1178 1179 retval = 1; 1180 RETURN: 1181 free(mval); 1182 return (retval); 1183} 1184 1185static int 1186sysctl_all (int *oid, int len) 1187{ 1188 int name1[22], name2[22]; 1189 int i, j; 1190 size_t l1, l2; 1191 1192 name1[0] = 0; 1193 name1[1] = 2; 1194 l1 = 2; 1195 if (len) { 1196 memcpy(name1+2, oid, len*sizeof (int)); 1197 l1 += len; 1198 } else { 1199 name1[2] = 1; 1200 l1++; 1201 } 1202 while (1) { 1203 l2 = sizeof name2; 1204 j = sysctl(name1, l1, name2, &l2, 0, 0); 1205 if (j < 0) { 1206 if (errno == ENOENT) 1207 return 0; 1208 else 1209 err(1, "sysctl(getnext) %d %ld", j, l2); 1210 } 1211 1212 l2 /= sizeof (int); 1213 1214 if (l2 < len) 1215 return 0; 1216 1217 for (i = 0; i < len; i++) 1218 if (name2[i] != oid[i]) 1219 return 0; 1220 1221 i = show_var(name2, l2, 0); 1222 if (!i && !bflag) 1223 putchar('\n'); 1224 1225 memcpy(name1+2, name2, l2*sizeof (int)); 1226 l1 = 2 + l2; 1227 } 1228} 1229