1: /*- 2: * Copyright (c) 1982, 1986, 1989, 1993 3: * The Regents of the University of California. All rights reserved. 4: * 5: * This code is derived from software contributed to Berkeley by 6: * Mike Karels at Berkeley Software Design, Inc. 7: * 8: * Redistribution and use in source and binary forms, with or without 9: * modification, are permitted provided that the following conditions 10: * are met: 11: * 1. Redistributions of source code must retain the above copyright 12: * notice, this list of conditions and the following disclaimer. 13: * 2. Redistributions in binary form must reproduce the above copyright 14: * notice, this list of conditions and the following disclaimer in the 15: * documentation and/or other materials provided with the distribution. 16: * 3. All advertising materials mentioning features or use of this software 17: * must display the following acknowledgement: 18: * This product includes software developed by the University of 19: * California, Berkeley and its contributors. 20: * 4. Neither the name of the University nor the names of its contributors 21: * may be used to endorse or promote products derived from this software 22: * without specific prior written permission. 23: * 24: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34: * SUCH DAMAGE. 35: * 36: * @(#)kern_sysctl.c 8.4.11 (2.11BSD) 1999/8/11 37: */ 38: 39: /* 40: * sysctl system call. 41: */ 42: 43: #include <sys/param.h> 44: #include <sys/user.h> 45: #include <sys/systm.h> 46: #include <sys/proc.h> 47: #include <sys/buf.h> 48: #include <sys/kernel.h> 49: #include <sys/file.h> 50: #include <sys/inode.h> 51: #include <sys/ioctl.h> 52: #include <sys/text.h> 53: #include <sys/tty.h> 54: #include <sys/vm.h> 55: #include <sys/map.h> 56: #include <machine/seg.h> 57: #include <sys/sysctl.h> 58: #include <machine/cpu.h> 59: #include <conf.h> 60: 61: sysctlfn kern_sysctl; 62: sysctlfn hw_sysctl; 63: #ifdef DEBUG 64: sysctlfn debug_sysctl; 65: #endif 66: sysctlfn vm_sysctl; 67: sysctlfn fs_sysctl; 68: #ifdef INET 69: sysctlfn NET_SYSCTL; 70: extern int net_sysctl(); /* In supervisor space */ 71: #endif 72: sysctlfn cpu_sysctl; 73: 74: /* 75: * Locking and stats 76: */ 77: static struct sysctl_lock { 78: int sl_lock; 79: int sl_want; 80: int sl_locked; 81: } memlock; 82: 83: struct sysctl_args { 84: int *name; 85: u_int namelen; 86: void *old; 87: size_t *oldlenp; 88: void *new; 89: size_t newlen; 90: }; 91: 92: int 93: __sysctl() 94: { 95: register struct sysctl_args *uap = (struct sysctl_args *)u.u_ap; 96: int error; 97: u_int savelen, oldlen = 0; 98: sysctlfn *fn; 99: int name[CTL_MAXNAME]; 100: 101: if (uap->new != NULL && !suser()) 102: return (u.u_error); /* XXX */ 103: /* 104: * all top-level sysctl names are non-terminal 105: */ 106: if (uap->namelen > CTL_MAXNAME || uap->namelen < 2) 107: return (u.u_error = EINVAL); 108: if (error = copyin(uap->name, &name, uap->namelen * sizeof(int))) 109: return (u.u_error = error); 110: 111: switch (name[0]) { 112: case CTL_KERN: 113: fn = kern_sysctl; 114: break; 115: case CTL_HW: 116: fn = hw_sysctl; 117: break; 118: case CTL_VM: 119: fn = vm_sysctl; 120: break; 121: #ifdef INET 122: case CTL_NET: 123: fn = NET_SYSCTL; 124: break; 125: #endif 126: #ifdef notyet 127: case CTL_FS: 128: fn = fs_sysctl; 129: break; 130: #endif 131: case CTL_MACHDEP: 132: fn = cpu_sysctl; 133: break; 134: #ifdef DEBUG 135: case CTL_DEBUG: 136: fn = debug_sysctl; 137: break; 138: #endif 139: default: 140: return (u.u_error = EOPNOTSUPP); 141: } 142: 143: if (uap->oldlenp && 144: (error = copyin(uap->oldlenp, &oldlen, sizeof(oldlen)))) 145: return (u.u_error = error); 146: if (uap->old != NULL) { 147: while (memlock.sl_lock) { 148: memlock.sl_want = 1; 149: sleep((caddr_t)&memlock, PRIBIO+1); 150: memlock.sl_locked++; 151: } 152: memlock.sl_lock = 1; 153: savelen = oldlen; 154: } 155: error = (*fn)(name + 1, uap->namelen - 1, uap->old, &oldlen, 156: uap->new, uap->newlen); 157: if (uap->old != NULL) { 158: memlock.sl_lock = 0; 159: if (memlock.sl_want) { 160: memlock.sl_want = 0; 161: wakeup((caddr_t)&memlock); 162: } 163: } 164: if (error) 165: return (u.u_error = error); 166: if (uap->oldlenp) { 167: error = copyout(&oldlen, uap->oldlenp, sizeof(oldlen)); 168: if (error) 169: return(u.u_error = error); 170: } 171: u.u_r.r_val1 = oldlen; 172: return (0); 173: } 174: 175: /* 176: * kernel related system variables. 177: */ 178: kern_sysctl(name, namelen, oldp, oldlenp, newp, newlen) 179: int *name; 180: u_int namelen; 181: void *oldp; 182: size_t *oldlenp; 183: void *newp; 184: size_t newlen; 185: { 186: int error, level; 187: u_long longhostid; 188: char bsd[10]; 189: extern int Acctthresh; /* kern_acct.c */ 190: extern char version[]; 191: 192: /* all sysctl names at this level are terminal */ 193: if (namelen != 1 && !(name[0] == KERN_PROC || name[0] == KERN_PROF)) 194: return (ENOTDIR); /* overloaded */ 195: 196: switch (name[0]) { 197: case KERN_OSTYPE: 198: case KERN_OSRELEASE: 199: /* code is cheaper than D space */ 200: bsd[0]='2';bsd[1]='.';bsd[2]='1';bsd[3]='1';bsd[4]='B'; 201: bsd[5]='S';bsd[6]='D';bsd[7]='\0'; 202: return (sysctl_rdstring(oldp, oldlenp, newp, bsd)); 203: case KERN_ACCTTHRESH: 204: level = Acctthresh; 205: error = sysctl_int(oldp, oldlenp, newp, newlen, &level); 206: if (newp && !error) 207: { 208: if (level < 0 || level > 128) 209: error = EINVAL; 210: else 211: Acctthresh = level; 212: } 213: return(error); 214: case KERN_OSREV: 215: return (sysctl_rdlong(oldp, oldlenp, newp, (long)BSD)); 216: case KERN_VERSION: 217: return (sysctl_rdstring(oldp, oldlenp, newp, version)); 218: case KERN_MAXINODES: 219: return(sysctl_rdint(oldp, oldlenp, newp, ninode)); 220: case KERN_MAXPROC: 221: return (sysctl_rdint(oldp, oldlenp, newp, nproc)); 222: case KERN_MAXFILES: 223: return (sysctl_rdint(oldp, oldlenp, newp, nfile)); 224: case KERN_MAXTEXTS: 225: return (sysctl_rdint(oldp, oldlenp, newp, ntext)); 226: case KERN_ARGMAX: 227: return (sysctl_rdint(oldp, oldlenp, newp, NCARGS)); 228: case KERN_SECURELVL: 229: level = securelevel; 230: if ((error = sysctl_int(oldp, oldlenp, newp, newlen, &level)) || 231: newp == NULL) 232: return (error); 233: if (level < securelevel && u.u_procp->p_pid != 1) 234: return (EPERM); 235: securelevel = level; 236: return (0); 237: case KERN_HOSTNAME: 238: error = sysctl_string(oldp, oldlenp, newp, newlen, 239: hostname, sizeof(hostname)); 240: if (newp && !error) 241: hostnamelen = newlen; 242: return (error); 243: case KERN_HOSTID: 244: longhostid = hostid; 245: error = sysctl_long(oldp, oldlenp, newp, newlen, &longhostid); 246: hostid = longhostid; 247: return (error); 248: case KERN_CLOCKRATE: 249: return (sysctl_clockrate(oldp, oldlenp)); 250: case KERN_BOOTTIME: 251: return (sysctl_rdstruct(oldp, oldlenp, newp, &boottime, 252: sizeof(struct timeval))); 253: case KERN_INODE: 254: return (sysctl_inode(oldp, oldlenp)); 255: case KERN_PROC: 256: return (sysctl_doproc(name + 1, namelen - 1, oldp, oldlenp)); 257: case KERN_FILE: 258: return (sysctl_file(oldp, oldlenp)); 259: case KERN_TEXT: 260: return (sysctl_text(oldp, oldlenp)); 261: #ifdef GPROF 262: case KERN_PROF: 263: return (sysctl_doprof(name + 1, namelen - 1, oldp, oldlenp, 264: newp, newlen)); 265: #endif 266: case KERN_NGROUPS: 267: return (sysctl_rdint(oldp, oldlenp, newp, NGROUPS)); 268: case KERN_JOB_CONTROL: 269: return (sysctl_rdint(oldp, oldlenp, newp, 1)); 270: case KERN_POSIX1: 271: case KERN_SAVED_IDS: 272: return (sysctl_rdint(oldp, oldlenp, newp, 0)); 273: default: 274: return (EOPNOTSUPP); 275: } 276: /* NOTREACHED */ 277: } 278: 279: /* 280: * hardware related system variables. 281: */ 282: hw_sysctl(name, namelen, oldp, oldlenp, newp, newlen) 283: int *name; 284: u_int namelen; 285: void *oldp; 286: size_t *oldlenp; 287: void *newp; 288: size_t newlen; 289: { 290: char c[10]; 291: char *cpu2str(); 292: extern size_t physmem; /* machdep2.c */ 293: 294: /* all sysctl names at this level are terminal */ 295: if (namelen != 1) 296: return (ENOTDIR); /* overloaded */ 297: 298: switch (name[0]) { 299: case HW_MACHINE: 300: return (sysctl_rdstring(oldp, oldlenp, newp, "pdp11")); 301: case HW_MODEL: 302: return (sysctl_rdstring(oldp, oldlenp, newp, 303: cpu2str(c,sizeof (c)))); 304: case HW_NCPU: 305: return (sysctl_rdint(oldp, oldlenp, newp, 1)); /* XXX */ 306: case HW_BYTEORDER: 307: return (sysctl_rdint(oldp, oldlenp, newp, ENDIAN)); 308: case HW_PHYSMEM: 309: return (sysctl_rdlong(oldp, oldlenp, newp,ctob((long)physmem))); 310: case HW_USERMEM: 311: return (sysctl_rdlong(oldp, oldlenp, newp,ctob((long)freemem))); 312: case HW_PAGESIZE: 313: return (sysctl_rdint(oldp, oldlenp, newp, NBPG*CLSIZE)); 314: default: 315: return (EOPNOTSUPP); 316: } 317: /* NOTREACHED */ 318: } 319: 320: static char * 321: cpu2str(buf, len) 322: char *buf; 323: int len; 324: { 325: register char *cp = buf + len; 326: register int i = cputype; 327: 328: *--cp = '\0'; 329: do 330: { 331: *--cp = (i % 10) + '0'; 332: } while (i /= 10); 333: return(cp); 334: } 335: 336: #ifdef DEBUG 337: /* 338: * Debugging related system variables. 339: */ 340: struct ctldebug debug0, debug1, debug2, debug3, debug4; 341: struct ctldebug debug5, debug6, debug7, debug8, debug9; 342: struct ctldebug debug10, debug11, debug12, debug13, debug14; 343: struct ctldebug debug15, debug16, debug17, debug18, debug19; 344: static struct ctldebug *debugvars[CTL_DEBUG_MAXID] = { 345: &debug0, &debug1, &debug2, &debug3, &debug4, 346: &debug5, &debug6, &debug7, &debug8, &debug9, 347: &debug10, &debug11, &debug12, &debug13, &debug14, 348: &debug15, &debug16, &debug17, &debug18, &debug19, 349: }; 350: int 351: debug_sysctl(name, namelen, oldp, oldlenp, newp, newlen) 352: int *name; 353: u_int namelen; 354: void *oldp; 355: size_t *oldlenp; 356: void *newp; 357: size_t newlen; 358: { 359: struct ctldebug *cdp; 360: 361: /* all sysctl names at this level are name and field */ 362: if (namelen != 2) 363: return (ENOTDIR); /* overloaded */ 364: cdp = debugvars[name[0]]; 365: if (cdp->debugname == 0) 366: return (EOPNOTSUPP); 367: switch (name[1]) { 368: case CTL_DEBUG_NAME: 369: return (sysctl_rdstring(oldp, oldlenp, newp, cdp->debugname)); 370: case CTL_DEBUG_VALUE: 371: return (sysctl_int(oldp, oldlenp, newp, newlen, cdp->debugvar)); 372: default: 373: return (EOPNOTSUPP); 374: } 375: /* NOTREACHED */ 376: } 377: #endif /* DEBUG */ 378: 379: #ifdef INET 380: /* 381: * In 4.4BSD-Lite these functions were scattered amoungst the various 382: * subsystems they dealt with. 383: * 384: * In 2.11BSD the kernel is overlaid and adding code to multiple 385: * files would have caused existing overlay structures to break. 386: * This module will be large enough that it will end up in an overlay 387: * by itself. Thus centralizing all sysctl handling in one place makes 388: * a lot of sense. The one exception is the networking related syctl 389: * functions. Because the networking code is not overlaid and runs 390: * in supervisor mode the sysctl handling can not be done here and 391: * will be implemented in the 4.4BSD manner (by modifying the networking 392: * modules). 393: */ 394: 395: int 396: NET_SYSCTL(name, namelen, oldp, oldlenp, newp, newlen) 397: int *name; 398: u_int namelen; 399: void *oldp; 400: size_t *oldlenp; 401: void *newp; 402: size_t newlen; 403: { 404: return(KScall(net_sysctl, 6 * sizeof (int), 405: name, namelen, oldp, oldlenp, newp, newlen)); 406: } 407: #endif 408: 409: /* 410: * Bit of a hack. 2.11 currently uses 'short avenrun[3]' and a fixed scale 411: * of 256. In order not to break all the applications which nlist() for 412: * 'avenrun' we build a local 'averunnable' structure here to return to the 413: * user. Eventually (after all applications which look up the load average 414: * the old way) have been converted we can change things. 415: * 416: * We do not call vmtotal(), that could get rather expensive, rather we rely 417: * on the 5 second update. 418: * 419: * The coremap and swapmap cases are 2.11BSD extensions. 420: */ 421: 422: int 423: vm_sysctl(name, namelen, oldp, oldlenp, newp, newlen) 424: int *name; 425: u_int namelen; 426: void *oldp; 427: size_t *oldlenp; 428: void *newp; 429: size_t newlen; 430: { 431: struct loadavg averunnable; /* loadavg in resource.h */ 432: 433: /* all sysctl names at this level are terminal */ 434: if (namelen != 1) 435: return (ENOTDIR); /* overloaded */ 436: 437: switch (name[0]) { 438: case VM_LOADAVG: 439: averunnable.fscale = 256; 440: averunnable.ldavg[0] = avenrun[0]; 441: averunnable.ldavg[1] = avenrun[1]; 442: averunnable.ldavg[2] = avenrun[2]; 443: return (sysctl_rdstruct(oldp, oldlenp, newp, &averunnable, 444: sizeof(averunnable))); 445: case VM_METER: 446: #ifdef notsure 447: vmtotal(); /* could be expensive to do this every time */ 448: #endif 449: return (sysctl_rdstruct(oldp, oldlenp, newp, &total, 450: sizeof(total))); 451: case VM_SWAPMAP: 452: if (oldp == NULL) { 453: *oldlenp = (char *)swapmap[0].m_limit - 454: (char *)swapmap[0].m_map; 455: return(0); 456: } 457: return (sysctl_rdstruct(oldp, oldlenp, newp, swapmap, 458: (int)swapmap[0].m_limit - (int)swapmap[0].m_map)); 459: case VM_COREMAP: 460: if (oldp == NULL) { 461: *oldlenp = (char *)coremap[0].m_limit - 462: (char *)coremap[0].m_map; 463: return(0); 464: } 465: return (sysctl_rdstruct(oldp, oldlenp, newp, coremap, 466: (int)coremap[0].m_limit - (int)coremap[0].m_map)); 467: default: 468: return (EOPNOTSUPP); 469: } 470: /* NOTREACHED */ 471: } 472: 473: /* 474: * Validate parameters and get old / set new parameters 475: * for an integer-valued sysctl function. 476: */ 477: sysctl_int(oldp, oldlenp, newp, newlen, valp) 478: void *oldp; 479: size_t *oldlenp; 480: void *newp; 481: size_t newlen; 482: int *valp; 483: { 484: int error = 0; 485: 486: if (oldp && *oldlenp < sizeof(int)) 487: return (ENOMEM); 488: if (newp && newlen != sizeof(int)) 489: return (EINVAL); 490: *oldlenp = sizeof(int); 491: if (oldp) 492: error = copyout(valp, oldp, sizeof(int)); 493: if (error == 0 && newp) 494: error = copyin(newp, valp, sizeof(int)); 495: return (error); 496: } 497: 498: /* 499: * As above, but read-only. 500: */ 501: sysctl_rdint(oldp, oldlenp, newp, val) 502: void *oldp; 503: size_t *oldlenp; 504: void *newp; 505: int val; 506: { 507: int error = 0; 508: 509: if (oldp && *oldlenp < sizeof(int)) 510: return (ENOMEM); 511: if (newp) 512: return (EPERM); 513: *oldlenp = sizeof(int); 514: if (oldp) 515: error = copyout((caddr_t)&val, oldp, sizeof(int)); 516: return (error); 517: } 518: 519: /* 520: * Validate parameters and get old / set new parameters 521: * for an long-valued sysctl function. 522: */ 523: sysctl_long(oldp, oldlenp, newp, newlen, valp) 524: void *oldp; 525: size_t *oldlenp; 526: void *newp; 527: size_t newlen; 528: long *valp; 529: { 530: int error = 0; 531: 532: if (oldp && *oldlenp < sizeof(long)) 533: return (ENOMEM); 534: if (newp && newlen != sizeof(long)) 535: return (EINVAL); 536: *oldlenp = sizeof(long); 537: if (oldp) 538: error = copyout(valp, oldp, sizeof(long)); 539: if (error == 0 && newp) 540: error = copyin(newp, valp, sizeof(long)); 541: return (error); 542: } 543: 544: /* 545: * As above, but read-only. 546: */ 547: sysctl_rdlong(oldp, oldlenp, newp, val) 548: void *oldp; 549: size_t *oldlenp; 550: void *newp; 551: long val; 552: { 553: int error = 0; 554: 555: if (oldp && *oldlenp < sizeof(long)) 556: return (ENOMEM); 557: if (newp) 558: return (EPERM); 559: *oldlenp = sizeof(long); 560: if (oldp) 561: error = copyout((caddr_t)&val, oldp, sizeof(long)); 562: return (error); 563: } 564: 565: /* 566: * Validate parameters and get old / set new parameters 567: * for a string-valued sysctl function. 568: */ 569: sysctl_string(oldp, oldlenp, newp, newlen, str, maxlen) 570: void *oldp; 571: size_t *oldlenp; 572: void *newp; 573: size_t newlen; 574: char *str; 575: int maxlen; 576: { 577: int len, error = 0; 578: 579: len = strlen(str) + 1; 580: if (oldp && *oldlenp < len) 581: return (ENOMEM); 582: if (newp && newlen >= maxlen) 583: return (EINVAL); 584: if (oldp) { 585: *oldlenp = len; 586: error = vcopyout(str, oldp, len); 587: } 588: if (error == 0 && newp) { 589: error = vcopyin(newp, str, newlen); 590: str[newlen] = 0; 591: } 592: return (error); 593: } 594: 595: /* 596: * As above, but read-only. 597: */ 598: sysctl_rdstring(oldp, oldlenp, newp, str) 599: void *oldp; 600: size_t *oldlenp; 601: void *newp; 602: char *str; 603: { 604: int len, error = 0; 605: 606: len = strlen(str) + 1; 607: if (oldp && *oldlenp < len) 608: return (ENOMEM); 609: if (newp) 610: return (EPERM); 611: *oldlenp = len; 612: if (oldp) 613: error = vcopyout(str, oldp, len); 614: return (error); 615: } 616: 617: /* 618: * Validate parameters and get old / set new parameters 619: * for a structure oriented sysctl function. 620: */ 621: sysctl_struct(oldp, oldlenp, newp, newlen, sp, len) 622: void *oldp; 623: size_t *oldlenp; 624: void *newp; 625: size_t newlen; 626: void *sp; 627: int len; 628: { 629: int error = 0; 630: 631: if (oldp && *oldlenp < len) 632: return (ENOMEM); 633: if (newp && newlen > len) 634: return (EINVAL); 635: if (oldp) { 636: *oldlenp = len; 637: error = copyout(sp, oldp, len); 638: } 639: if (error == 0 && newp) 640: error = copyin(newp, sp, len); 641: return (error); 642: } 643: 644: /* 645: * Validate parameters and get old parameters 646: * for a structure oriented sysctl function. 647: */ 648: sysctl_rdstruct(oldp, oldlenp, newp, sp, len) 649: void *oldp; 650: size_t *oldlenp; 651: void *newp, *sp; 652: int len; 653: { 654: int error = 0; 655: 656: if (oldp && *oldlenp < len) 657: return (ENOMEM); 658: if (newp) 659: return (EPERM); 660: *oldlenp = len; 661: if (oldp) 662: error = copyout(sp, oldp, len); 663: return (error); 664: } 665: 666: /* 667: * Get file structures. 668: */ 669: sysctl_file(where, sizep) 670: char *where; 671: size_t *sizep; 672: { 673: int buflen, error; 674: register struct file *fp; 675: struct file *fpp; 676: char *start = where; 677: register int i; 678: 679: buflen = *sizep; 680: if (where == NULL) { 681: for (i = 0, fp = file; fp < fileNFILE; fp++) 682: if (fp->f_count) i++; 683: 684: #define FPTRSZ sizeof (struct file *) 685: #define FILESZ sizeof (struct file) 686: /* 687: * overestimate by 5 files 688: */ 689: *sizep = (i + 5) * (FILESZ + FPTRSZ); 690: return (0); 691: } 692: 693: /* 694: * array of extended file structures: first the address then the 695: * file structure. 696: */ 697: for (fp = file; fp < fileNFILE; fp++) { 698: if (fp->f_count == 0) 699: continue; 700: if (buflen < (FPTRSZ + FILESZ)) { 701: *sizep = where - start; 702: return (ENOMEM); 703: } 704: fpp = fp; 705: if ((error = copyout(&fpp, where, FPTRSZ)) || 706: (error = copyout(fp, where + FPTRSZ, FILESZ))) 707: return (error); 708: buflen -= (FPTRSZ + FILESZ); 709: where += (FPTRSZ + FILESZ); 710: } 711: *sizep = where - start; 712: return (0); 713: } 714: 715: /* 716: * This one is in kern_clock.c in 4.4 but placed here for the reasons 717: * given earlier (back around line 367). 718: */ 719: 720: int 721: sysctl_clockrate(where, sizep) 722: char *where; 723: size_t *sizep; 724: { 725: struct clockinfo clkinfo; 726: 727: /* 728: * Construct clockinfo structure. 729: */ 730: clkinfo.hz = hz; 731: clkinfo.tick = mshz; 732: clkinfo.profhz = 0; 733: clkinfo.stathz = hz; 734: return(sysctl_rdstruct(where, sizep, NULL, &clkinfo, sizeof (clkinfo))); 735: } 736: 737: /* 738: * Dump inode list (via sysctl). 739: * Copyout address of inode followed by inode. 740: */ 741: /* ARGSUSED */ 742: sysctl_inode(where, sizep) 743: char *where; 744: size_t *sizep; 745: { 746: register struct inode *ip; 747: register char *bp = where; 748: struct inode *ipp; 749: char *ewhere; 750: int error, numi; 751: 752: for (numi = 0, ip = inode; ip < inodeNINODE; ip++) 753: if (ip->i_count) numi++; 754: 755: #define IPTRSZ sizeof (struct inode *) 756: #define INODESZ sizeof (struct inode) 757: if (where == NULL) { 758: *sizep = (numi + 5) * (IPTRSZ + INODESZ); 759: return (0); 760: } 761: ewhere = where + *sizep; 762: 763: for (ip = inode; ip < inodeNINODE; ip++) { 764: if (ip->i_count == 0) 765: continue; 766: if (bp + IPTRSZ + INODESZ > ewhere) { 767: *sizep = bp - where; 768: return (ENOMEM); 769: } 770: ipp = ip; 771: if ((error = copyout((caddr_t)&ipp, bp, IPTRSZ)) || 772: (error = copyout((caddr_t)ip, bp + IPTRSZ, INODESZ))) 773: return (error); 774: bp += IPTRSZ + INODESZ; 775: } 776: 777: *sizep = bp - where; 778: return (0); 779: } 780: 781: /* 782: * Get text structures. This is a 2.11BSD extension. sysctl() is supposed 783: * to be extensible... 784: */ 785: sysctl_text(where, sizep) 786: char *where; 787: size_t *sizep; 788: { 789: int buflen, error; 790: register struct text *xp; 791: struct text *xpp; 792: char *start = where; 793: register int i; 794: 795: buflen = *sizep; 796: if (where == NULL) { 797: for (i = 0, xp = text; xp < textNTEXT; xp++) 798: if (xp->x_count) i++; 799: 800: #define TPTRSZ sizeof (struct text *) 801: #define TEXTSZ sizeof (struct text) 802: /* 803: * overestimate by 3 text structures 804: */ 805: *sizep = (i + 3) * (TEXTSZ + TPTRSZ); 806: return (0); 807: } 808: 809: /* 810: * array of extended file structures: first the address then the 811: * file structure. 812: */ 813: for (xp = text; xp < textNTEXT; xp++) { 814: if (xp->x_count == 0) 815: continue; 816: if (buflen < (TPTRSZ + TEXTSZ)) { 817: *sizep = where - start; 818: return (ENOMEM); 819: } 820: xpp = xp; 821: if ((error = copyout(&xpp, where, TPTRSZ)) || 822: (error = copyout(xp, where + TPTRSZ, TEXTSZ))) 823: return (error); 824: buflen -= (TPTRSZ + TEXTSZ); 825: where += (TPTRSZ + TEXTSZ); 826: } 827: *sizep = where - start; 828: return (0); 829: } 830: 831: /* 832: * try over estimating by 5 procs 833: */ 834: #define KERN_PROCSLOP (5 * sizeof (struct kinfo_proc)) 835: 836: sysctl_doproc(name, namelen, where, sizep) 837: int *name; 838: u_int namelen; 839: char *where; 840: size_t *sizep; 841: { 842: register struct proc *p; 843: register struct kinfo_proc *dp = (struct kinfo_proc *)where; 844: int needed = 0; 845: int buflen = where != NULL ? *sizep : 0; 846: int doingzomb; 847: struct eproc eproc; 848: int error = 0; 849: dev_t ttyd; 850: uid_t ruid; 851: struct tty *ttyp; 852: 853: if (namelen != 2 && !(namelen == 1 && name[0] == KERN_PROC_ALL)) 854: return (EINVAL); 855: p = (struct proc *)allproc; 856: doingzomb = 0; 857: again: 858: for (; p != NULL; p = p->p_nxt) { 859: /* 860: * Skip embryonic processes. 861: */ 862: if (p->p_stat == SIDL) 863: continue; 864: /* 865: * TODO - make more efficient (see notes below). 866: * do by session. 867: */ 868: switch (name[0]) { 869: 870: case KERN_PROC_PID: 871: /* could do this with just a lookup */ 872: if (p->p_pid != (pid_t)name[1]) 873: continue; 874: break; 875: 876: case KERN_PROC_PGRP: 877: /* could do this by traversing pgrp */ 878: if (p->p_pgrp != (pid_t)name[1]) 879: continue; 880: break; 881: 882: case KERN_PROC_TTY: 883: fill_from_u(p, &ruid, &ttyp, &ttyd); 884: if (!ttyp || ttyd != (dev_t)name[1]) 885: continue; 886: break; 887: 888: case KERN_PROC_UID: 889: if (p->p_uid != (uid_t)name[1]) 890: continue; 891: break; 892: 893: case KERN_PROC_RUID: 894: fill_from_u(p, &ruid, &ttyp, &ttyd); 895: if (ruid != (uid_t)name[1]) 896: continue; 897: break; 898: 899: case KERN_PROC_ALL: 900: break; 901: default: 902: return(EINVAL); 903: } 904: if (buflen >= sizeof(struct kinfo_proc)) { 905: fill_eproc(p, &eproc); 906: if (error = copyout((caddr_t)p, &dp->kp_proc, 907: sizeof(struct proc))) 908: return (error); 909: if (error = copyout((caddr_t)&eproc, &dp->kp_eproc, 910: sizeof(eproc))) 911: return (error); 912: dp++; 913: buflen -= sizeof(struct kinfo_proc); 914: } 915: needed += sizeof(struct kinfo_proc); 916: } 917: if (doingzomb == 0) { 918: p = zombproc; 919: doingzomb++; 920: goto again; 921: } 922: if (where != NULL) { 923: *sizep = (caddr_t)dp - where; 924: if (needed > *sizep) 925: return (ENOMEM); 926: } else { 927: needed += KERN_PROCSLOP; 928: *sizep = needed; 929: } 930: return (0); 931: } 932: 933: /* 934: * Fill in an eproc structure for the specified process. Slightly 935: * inefficient because we have to access the u area again for the 936: * information not kept in the proc structure itself. Can't afford 937: * to expand the proc struct so we take a slight speed hit here. 938: */ 939: void 940: fill_eproc(p, ep) 941: register struct proc *p; 942: register struct eproc *ep; 943: { 944: struct tty *ttyp; 945: 946: ep->e_paddr = p; 947: fill_from_u(p, &ep->e_ruid, &ttyp, &ep->e_tdev); 948: if (ttyp) 949: ep->e_tpgid = ttyp->t_pgrp; 950: else 951: ep->e_tpgid = 0; 952: } 953: 954: /* 955: * Three pieces of information we need about a process are not kept in 956: * the proc table: real uid, controlling terminal device, and controlling 957: * terminal tty struct pointer. For these we must look in either the u 958: * area or the swap area. If the process is still in memory this is 959: * easy but if the process has been swapped out we have to read in the 960: * u area. 961: * 962: * XXX - We rely on the fact that u_ttyp, u_ttyd, and u_ruid are all within 963: * XXX - the first 1kb of the u area. If this ever changes the logic below 964: * XXX - will break (and badly). At the present time (97/9/2) the u area 965: * XXX - is 856 bytes long. 966: */ 967: 968: fill_from_u(p, rup, ttp, tdp) 969: struct proc *p; 970: uid_t *rup; 971: struct tty **ttp; 972: dev_t *tdp; 973: { 974: register struct buf *bp; 975: dev_t ttyd; 976: uid_t ruid; 977: struct tty *ttyp; 978: struct user *up; 979: 980: if (p->p_stat == SZOMB) 981: { 982: ruid = (uid_t)-2; 983: ttyp = NULL; 984: ttyd = NODEV; 985: goto out; 986: } 987: if (p->p_flag & SLOAD) 988: { 989: mapseg5(p->p_addr, (((USIZE - 1) << 8) | RO)); 990: ttyd = ((struct user *)SEG5)->u_ttyd; 991: ttyp = ((struct user *)SEG5)->u_ttyp; 992: ruid = ((struct user *)SEG5)->u_ruid; 993: normalseg5(); 994: } 995: else 996: { 997: bp = geteblk(); 998: bp->b_dev = swapdev; 999: bp->b_blkno = (daddr_t)p->p_addr; 1000: bp->b_bcount = DEV_BSIZE; /* XXX */ 1001: bp->b_flags = B_READ; 1002: 1003: (*bdevsw[major(swapdev)].d_strategy)(bp); 1004: biowait(bp); 1005: 1006: if (u.u_error) 1007: { 1008: ttyd = NODEV; 1009: ttyp = NULL; 1010: ruid = (uid_t)-2; 1011: } 1012: else 1013: { 1014: up = (struct user *)mapin(bp); 1015: ruid = up->u_ruid; /* u_ruid = offset 164 */ 1016: ttyd = up->u_ttyd; /* u_ttyd = offset 654 */ 1017: ttyp = up->u_ttyp; /* u_ttyp = offset 652 */ 1018: mapout(bp); 1019: } 1020: bp->b_flags |= B_AGE; 1021: brelse(bp); 1022: u.u_error = 0; /* XXX */ 1023: } 1024: out: 1025: if (rup) 1026: *rup = ruid; 1027: if (ttp) 1028: *ttp = ttyp; 1029: if (tdp) 1030: *tdp = ttyd; 1031: }