|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */ ! 23: /*- ! 24: * Copyright (c) 1982, 1986, 1989, 1993 ! 25: * The Regents of the University of California. All rights reserved. ! 26: * ! 27: * This code is derived from software contributed to Berkeley by ! 28: * Mike Karels at Berkeley Software Design, Inc. ! 29: * ! 30: * Redistribution and use in source and binary forms, with or without ! 31: * modification, are permitted provided that the following conditions ! 32: * are met: ! 33: * 1. Redistributions of source code must retain the above copyright ! 34: * notice, this list of conditions and the following disclaimer. ! 35: * 2. Redistributions in binary form must reproduce the above copyright ! 36: * notice, this list of conditions and the following disclaimer in the ! 37: * documentation and/or other materials provided with the distribution. ! 38: * 3. All advertising materials mentioning features or use of this software ! 39: * must display the following acknowledgement: ! 40: * This product includes software developed by the University of ! 41: * California, Berkeley and its contributors. ! 42: * 4. Neither the name of the University nor the names of its contributors ! 43: * may be used to endorse or promote products derived from this software ! 44: * without specific prior written permission. ! 45: * ! 46: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 47: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 48: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 49: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 50: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 51: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 52: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 53: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 54: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 55: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 56: * SUCH DAMAGE. ! 57: * ! 58: * @(#)kern_sysctl.c 8.4 (Berkeley) 4/14/94 ! 59: */ ! 60: ! 61: /* ! 62: * sysctl system call. ! 63: */ ! 64: ! 65: #include <sys/param.h> ! 66: #include <sys/systm.h> ! 67: #include <sys/kernel.h> ! 68: #include <sys/malloc.h> ! 69: #include <sys/proc.h> ! 70: #include <sys/file.h> ! 71: #include <sys/vnode.h> ! 72: #include <sys/unistd.h> ! 73: #include <sys/buf.h> ! 74: #include <sys/ioctl.h> ! 75: #include <sys/tty.h> ! 76: #include <sys/disklabel.h> ! 77: #include <sys/vm.h> ! 78: #include <sys/sysctl.h> ! 79: #include <mach/mach_types.h> ! 80: #include <mach/vm_param.h> ! 81: #include <kern/task.h> ! 82: #include <vm/vm_kern.h> ! 83: ! 84: extern vm_map_t bsd_pageable_map; ! 85: ! 86: #include <sys/mount.h> ! 87: #import <sys/kdebug.h> ! 88: ! 89: #include <IOKit/IOPlatformExpert.h> ! 90: ! 91: sysctlfn kern_sysctl; ! 92: sysctlfn hw_sysctl; ! 93: #ifdef DEBUG ! 94: sysctlfn debug_sysctl; ! 95: #endif ! 96: extern sysctlfn vm_sysctl; ! 97: extern sysctlfn vfs_sysctl; ! 98: extern sysctlfn net_sysctl; ! 99: extern sysctlfn cpu_sysctl; ! 100: ! 101: ! 102: int ! 103: userland_sysctl(struct proc *p, int *name, u_int namelen, void *old, size_t ! 104: *oldlenp, int inkernel, void *new, size_t newlen, size_t *retval); ! 105: ! 106: ! 107: /* ! 108: * temporary location for vm_sysctl. This should be machine independant ! 109: */ ! 110: vm_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) ! 111: int *name; ! 112: u_int namelen; ! 113: void *oldp; ! 114: size_t *oldlenp; ! 115: void *newp; ! 116: size_t newlen; ! 117: struct proc *p; ! 118: { ! 119: int error, level, inthostid; ! 120: extern long avenrun[3], mach_factor[3]; ! 121: struct loadavg loadinfo; ! 122: ! 123: //if (namelen != 1 && !(name[0] == VM_LOADAVG)) ! 124: //return (ENOTDIR); /* overloaded */ ! 125: ! 126: switch (name[0]) { ! 127: case VM_LOADAVG: ! 128: loadinfo.ldavg[0] = avenrun[0]; ! 129: loadinfo.ldavg[1] = avenrun[1]; ! 130: loadinfo.ldavg[2] = avenrun[2]; ! 131: loadinfo.fscale = LSCALE; ! 132: return (sysctl_struct(oldp, oldlenp, newp, newlen, &loadinfo, sizeof(struct loadavg))); ! 133: case VM_MACHFACTOR: ! 134: loadinfo.ldavg[0] = mach_factor[0]; ! 135: loadinfo.ldavg[1] = mach_factor[1]; ! 136: loadinfo.ldavg[2] = mach_factor[2]; ! 137: loadinfo.fscale = LSCALE; ! 138: return (sysctl_struct(oldp, oldlenp, newp, newlen, &loadinfo, sizeof(struct loadavg))); ! 139: case VM_METER: ! 140: return (EOPNOTSUPP); ! 141: case VM_MAXID: ! 142: return (EOPNOTSUPP); ! 143: default: ! 144: return (EOPNOTSUPP); ! 145: } ! 146: /* NOTREACHED */ ! 147: return (EOPNOTSUPP); ! 148: } ! 149: ! 150: /* ! 151: * Locking and stats ! 152: */ ! 153: static struct sysctl_lock { ! 154: int sl_lock; ! 155: int sl_want; ! 156: int sl_locked; ! 157: } memlock; ! 158: ! 159: struct __sysctl_args { ! 160: int *name; ! 161: u_int namelen; ! 162: void *old; ! 163: size_t *oldlenp; ! 164: void *new; ! 165: size_t newlen; ! 166: }; ! 167: int ! 168: __sysctl(p, uap, retval) ! 169: struct proc *p; ! 170: register struct __sysctl_args *uap; ! 171: register_t *retval; ! 172: { ! 173: int error, dolock = 1; ! 174: size_t savelen, oldlen = 0; ! 175: sysctlfn *fn; ! 176: int name[CTL_MAXNAME]; ! 177: int i; ! 178: ! 179: if (uap->new != NULL && ! 180: (error = suser(p->p_ucred, &p->p_acflag))) ! 181: return (error); ! 182: /* ! 183: * all top-level sysctl names are non-terminal ! 184: */ ! 185: if (uap->namelen > CTL_MAXNAME || uap->namelen < 2) ! 186: return (EINVAL); ! 187: if (error = ! 188: copyin(uap->name, &name, uap->namelen * sizeof(int))) ! 189: return (error); ! 190: ! 191: switch (name[0]) { ! 192: case CTL_KERN: ! 193: fn = kern_sysctl; ! 194: if (name[2] != KERN_VNODE) /* XXX */ ! 195: dolock = 0; ! 196: break; ! 197: case CTL_HW: ! 198: fn = hw_sysctl; ! 199: break; ! 200: case CTL_VM: ! 201: fn = vm_sysctl; ! 202: break; ! 203: case CTL_NET: ! 204: fn = net_sysctl; ! 205: break; ! 206: case CTL_VFS: ! 207: fn = vfs_sysctl; ! 208: break; ! 209: #if FIXME /* [ */ ! 210: case CTL_MACHDEP: ! 211: fn = cpu_sysctl; ! 212: break; ! 213: #endif /* FIXME ] */ ! 214: #ifdef DEBUG ! 215: case CTL_DEBUG: ! 216: fn = debug_sysctl; ! 217: break; ! 218: #endif ! 219: default: ! 220: fn = 0; ! 221: } ! 222: ! 223: if (uap->oldlenp && ! 224: (error = copyin(uap->oldlenp, &oldlen, sizeof(oldlen)))) ! 225: return (error); ! 226: ! 227: if (uap->old != NULL) { ! 228: if (!useracc(uap->old, oldlen, B_WRITE)) ! 229: return (EFAULT); ! 230: while (memlock.sl_lock) { ! 231: memlock.sl_want = 1; ! 232: sleep((caddr_t)&memlock, PRIBIO+1); ! 233: memlock.sl_locked++; ! 234: } ! 235: memlock.sl_lock = 1; ! 236: if (dolock) ! 237: vslock(uap->old, oldlen); ! 238: savelen = oldlen; ! 239: } ! 240: ! 241: if (fn) ! 242: error = (*fn)(name + 1, uap->namelen - 1, uap->old, ! 243: &oldlen, uap->new, uap->newlen, p); ! 244: else ! 245: error = 1; ! 246: ! 247: if (error) ! 248: error = userland_sysctl(p, name, uap->namelen, ! 249: uap->old, uap->oldlenp, 0, ! 250: uap->new, uap->newlen, &oldlen); ! 251: ! 252: if (uap->old != NULL) { ! 253: if (dolock) ! 254: vsunlock(uap->old, savelen, B_WRITE); ! 255: memlock.sl_lock = 0; ! 256: if (memlock.sl_want) { ! 257: memlock.sl_want = 0; ! 258: wakeup((caddr_t)&memlock); ! 259: } ! 260: } ! 261: if ((error) && (error != ENOMEM)) ! 262: return (error); ! 263: ! 264: if (uap->oldlenp) { ! 265: i = copyout(&oldlen, uap->oldlenp, sizeof(oldlen)); ! 266: if (i) ! 267: return i; ! 268: } ! 269: ! 270: return (error); ! 271: } ! 272: ! 273: /* ! 274: * Attributes stored in the kernel. ! 275: */ ! 276: extern char hostname[MAXHOSTNAMELEN]; /* defined in bsd/kern/init_main.c */ ! 277: extern int hostnamelen; ! 278: extern char domainname[MAXHOSTNAMELEN]; ! 279: extern int domainnamelen; ! 280: extern long hostid; ! 281: #ifdef INSECURE ! 282: int securelevel = -1; ! 283: #else ! 284: int securelevel; ! 285: #endif ! 286: ! 287: int get_kernel_symfile( struct proc *p, char **symfile ); ! 288: ! 289: /* ! 290: * kernel related system variables. ! 291: */ ! 292: kern_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) ! 293: int *name; ! 294: u_int namelen; ! 295: void *oldp; ! 296: size_t *oldlenp; ! 297: void *newp; ! 298: size_t newlen; ! 299: struct proc *p; ! 300: { ! 301: int error, level, inthostid; ! 302: unsigned int oldval=0; ! 303: extern char ostype[], osrelease[], version[]; ! 304: ! 305: /* all sysctl names at this level are terminal */ ! 306: if (namelen != 1 && !(name[0] == KERN_PROC || name[0] == KERN_PROF ! 307: || name[0] == KERN_KDEBUG ! 308: || name[0] == KERN_PROCARGS ! 309: || name[0] == KERN_PCSAMPLES ! 310: )) ! 311: return (ENOTDIR); /* overloaded */ ! 312: ! 313: switch (name[0]) { ! 314: case KERN_OSTYPE: ! 315: return (sysctl_rdstring(oldp, oldlenp, newp, ostype)); ! 316: case KERN_OSRELEASE: ! 317: return (sysctl_rdstring(oldp, oldlenp, newp, osrelease)); ! 318: case KERN_OSREV: ! 319: return (sysctl_rdint(oldp, oldlenp, newp, BSD)); ! 320: case KERN_VERSION: ! 321: return (sysctl_rdstring(oldp, oldlenp, newp, version)); ! 322: case KERN_MAXVNODES: ! 323: oldval = desiredvnodes; ! 324: error = sysctl_int(oldp, oldlenp, newp, ! 325: newlen, &desiredvnodes); ! 326: reset_vmobjectcache(oldval, desiredvnodes); ! 327: return(error); ! 328: case KERN_MAXPROC: ! 329: return (sysctl_int(oldp, oldlenp, newp, newlen, &maxproc)); ! 330: case KERN_MAXFILES: ! 331: return (sysctl_int(oldp, oldlenp, newp, newlen, &maxfiles)); ! 332: case KERN_ARGMAX: ! 333: return (sysctl_rdint(oldp, oldlenp, newp, ARG_MAX)); ! 334: case KERN_SECURELVL: ! 335: level = securelevel; ! 336: if ((error = sysctl_int(oldp, oldlenp, newp, newlen, &level)) || ! 337: newp == NULL) ! 338: return (error); ! 339: if (level < securelevel && p->p_pid != 1) ! 340: return (EPERM); ! 341: securelevel = level; ! 342: return (0); ! 343: case KERN_HOSTNAME: ! 344: error = sysctl_string(oldp, oldlenp, newp, newlen, ! 345: hostname, sizeof(hostname)); ! 346: if (newp && !error) ! 347: hostnamelen = newlen; ! 348: return (error); ! 349: case KERN_DOMAINNAME: ! 350: error = sysctl_string(oldp, oldlenp, newp, newlen, ! 351: domainname, sizeof(domainname)); ! 352: if (newp && !error) ! 353: domainnamelen = newlen; ! 354: return (error); ! 355: case KERN_HOSTID: ! 356: inthostid = hostid; /* XXX assumes sizeof long <= sizeof int */ ! 357: error = sysctl_int(oldp, oldlenp, newp, newlen, &inthostid); ! 358: hostid = inthostid; ! 359: return (error); ! 360: case KERN_CLOCKRATE: ! 361: return (sysctl_clockrate(oldp, oldlenp)); ! 362: #if FIXME /* [ */ ! 363: case KERN_BOOTTIME: ! 364: return (sysctl_rdstruct(oldp, oldlenp, newp, &boottime, ! 365: sizeof(struct timeval))); ! 366: #endif /* FIXME ] */ ! 367: case KERN_VNODE: ! 368: return (sysctl_vnode(oldp, oldlenp)); ! 369: case KERN_PROC: ! 370: return (sysctl_doproc(name + 1, namelen - 1, oldp, oldlenp)); ! 371: case KERN_FILE: ! 372: return (sysctl_file(oldp, oldlenp)); ! 373: #ifdef GPROF ! 374: case KERN_PROF: ! 375: return (sysctl_doprof(name + 1, namelen - 1, oldp, oldlenp, ! 376: newp, newlen)); ! 377: #endif ! 378: case KERN_POSIX1: ! 379: return (sysctl_rdint(oldp, oldlenp, newp, _POSIX_VERSION)); ! 380: case KERN_NGROUPS: ! 381: return (sysctl_rdint(oldp, oldlenp, newp, NGROUPS_MAX)); ! 382: case KERN_JOB_CONTROL: ! 383: return (sysctl_rdint(oldp, oldlenp, newp, 1)); ! 384: case KERN_SAVED_IDS: ! 385: #ifdef _POSIX_SAVED_IDS ! 386: return (sysctl_rdint(oldp, oldlenp, newp, 1)); ! 387: #else ! 388: return (sysctl_rdint(oldp, oldlenp, newp, 0)); ! 389: #endif ! 390: #if FIXME /* [ */ ! 391: case KERN_MAXPARTITIONS: ! 392: return (sysctl_rdint(oldp, oldlenp, newp, MAXPARTITIONS)); ! 393: #endif /* FIXME ] */ ! 394: case KERN_KDEBUG: ! 395: return (kdebug_ops(name + 1, namelen - 1, oldp, oldlenp, p)); ! 396: case KERN_PCSAMPLES: ! 397: return (pcsamples_control(name+1, namelen-1, oldp, oldlenp)); ! 398: case KERN_PROCARGS: ! 399: /* new one as it does not use kinfo_proc */ ! 400: return (sysctl_procargs(name + 1, namelen - 1, oldp, oldlenp)); ! 401: case KERN_SYMFILE: ! 402: { ! 403: char *str; ! 404: error = get_kernel_symfile( p, &str ); ! 405: if ( error ) return error; ! 406: return (sysctl_rdstring(oldp, oldlenp, newp, str)); ! 407: } ! 408: default: ! 409: return (EOPNOTSUPP); ! 410: } ! 411: /* NOTREACHED */ ! 412: } ! 413: ! 414: /* ! 415: * hardware related system variables. ! 416: */ ! 417: hw_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) ! 418: int *name; ! 419: u_int namelen; ! 420: void *oldp; ! 421: size_t *oldlenp; ! 422: void *newp; ! 423: size_t newlen; ! 424: struct proc *p; ! 425: { ! 426: char dummy[65]; ! 427: int epochTemp; ! 428: extern int vm_page_wire_count; ! 429: ! 430: ! 431: /* all sysctl names at this level are terminal */ ! 432: if (namelen != 1) ! 433: return (ENOTDIR); /* overloaded */ ! 434: ! 435: switch (name[0]) { ! 436: case HW_MACHINE: ! 437: if(!PEGetMachineName(dummy,64)) ! 438: return(EINVAL); ! 439: return (sysctl_rdstring(oldp, oldlenp, newp, dummy)); ! 440: case HW_MODEL: ! 441: if(!PEGetModelName(dummy,64)) ! 442: return(EINVAL); ! 443: return (sysctl_rdstring(oldp, oldlenp, newp, dummy)); ! 444: case HW_NCPU: ! 445: return (sysctl_rdint(oldp, oldlenp, newp, 1)); /* XXX */ ! 446: case HW_BYTEORDER: ! 447: return (sysctl_rdint(oldp, oldlenp, newp, BYTE_ORDER)); ! 448: case HW_PHYSMEM: ! 449: return (sysctl_rdint(oldp, oldlenp, newp, mem_size)); ! 450: case HW_USERMEM: ! 451: return (sysctl_rdint(oldp, oldlenp, newp, ! 452: (mem_size - vm_page_wire_count * page_size))); ! 453: case HW_PAGESIZE: ! 454: return (sysctl_rdint(oldp, oldlenp, newp, page_size)); ! 455: case HW_EPOCH: ! 456: epochTemp = PEGetPlatformEpoch(); ! 457: if (epochTemp == -1) return(EINVAL); ! 458: return (sysctl_rdint(oldp, oldlenp, newp, epochTemp)); ! 459: default: ! 460: return (EOPNOTSUPP); ! 461: } ! 462: } ! 463: ! 464: #ifdef DEBUG ! 465: /* ! 466: * Debugging related system variables. ! 467: */ ! 468: #if DIAGNOSTIC ! 469: extern ! 470: #endif /* DIAGNOSTIC */ ! 471: struct ctldebug debug0, debug1; ! 472: struct ctldebug debug2, debug3, debug4; ! 473: struct ctldebug debug5, debug6, debug7, debug8, debug9; ! 474: struct ctldebug debug10, debug11, debug12, debug13, debug14; ! 475: struct ctldebug debug15, debug16, debug17, debug18, debug19; ! 476: static struct ctldebug *debugvars[CTL_DEBUG_MAXID] = { ! 477: &debug0, &debug1, &debug2, &debug3, &debug4, ! 478: &debug5, &debug6, &debug7, &debug8, &debug9, ! 479: &debug10, &debug11, &debug12, &debug13, &debug14, ! 480: &debug15, &debug16, &debug17, &debug18, &debug19, ! 481: }; ! 482: int ! 483: debug_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) ! 484: int *name; ! 485: u_int namelen; ! 486: void *oldp; ! 487: size_t *oldlenp; ! 488: void *newp; ! 489: size_t newlen; ! 490: struct proc *p; ! 491: { ! 492: struct ctldebug *cdp; ! 493: ! 494: /* all sysctl names at this level are name and field */ ! 495: if (namelen != 2) ! 496: return (ENOTDIR); /* overloaded */ ! 497: cdp = debugvars[name[0]]; ! 498: if (cdp->debugname == 0) ! 499: return (EOPNOTSUPP); ! 500: switch (name[1]) { ! 501: case CTL_DEBUG_NAME: ! 502: return (sysctl_rdstring(oldp, oldlenp, newp, cdp->debugname)); ! 503: case CTL_DEBUG_VALUE: ! 504: return (sysctl_int(oldp, oldlenp, newp, newlen, cdp->debugvar)); ! 505: default: ! 506: return (EOPNOTSUPP); ! 507: } ! 508: /* NOTREACHED */ ! 509: } ! 510: #endif /* DEBUG */ ! 511: ! 512: /* ! 513: * Validate parameters and get old / set new parameters ! 514: * for an integer-valued sysctl function. ! 515: */ ! 516: sysctl_int(oldp, oldlenp, newp, newlen, valp) ! 517: void *oldp; ! 518: size_t *oldlenp; ! 519: void *newp; ! 520: size_t newlen; ! 521: int *valp; ! 522: { ! 523: int error = 0; ! 524: ! 525: if (oldp && *oldlenp < sizeof(int)) ! 526: return (ENOMEM); ! 527: if (newp && newlen != sizeof(int)) ! 528: return (EINVAL); ! 529: *oldlenp = sizeof(int); ! 530: if (oldp) ! 531: error = copyout(valp, oldp, sizeof(int)); ! 532: if (error == 0 && newp) ! 533: error = copyin(newp, valp, sizeof(int)); ! 534: return (error); ! 535: } ! 536: ! 537: /* ! 538: * As above, but read-only. ! 539: */ ! 540: sysctl_rdint(oldp, oldlenp, newp, val) ! 541: void *oldp; ! 542: size_t *oldlenp; ! 543: void *newp; ! 544: int val; ! 545: { ! 546: int error = 0; ! 547: ! 548: if (oldp && *oldlenp < sizeof(int)) ! 549: return (ENOMEM); ! 550: if (newp) ! 551: return (EPERM); ! 552: *oldlenp = sizeof(int); ! 553: if (oldp) ! 554: error = copyout((caddr_t)&val, oldp, sizeof(int)); ! 555: return (error); ! 556: } ! 557: ! 558: /* ! 559: * Validate parameters and get old / set new parameters ! 560: * for a string-valued sysctl function. ! 561: */ ! 562: sysctl_string(oldp, oldlenp, newp, newlen, str, maxlen) ! 563: void *oldp; ! 564: size_t *oldlenp; ! 565: void *newp; ! 566: size_t newlen; ! 567: char *str; ! 568: int maxlen; ! 569: { ! 570: int len, error = 0; ! 571: ! 572: len = strlen(str) + 1; ! 573: if (oldp && *oldlenp < len) ! 574: return (ENOMEM); ! 575: if (newp && newlen >= maxlen) ! 576: return (EINVAL); ! 577: if (oldp) { ! 578: *oldlenp = len; ! 579: error = copyout(str, oldp, len); ! 580: } ! 581: if (error == 0 && newp) { ! 582: error = copyin(newp, str, newlen); ! 583: str[newlen] = 0; ! 584: } ! 585: return (error); ! 586: } ! 587: ! 588: /* ! 589: * As above, but read-only. ! 590: */ ! 591: sysctl_rdstring(oldp, oldlenp, newp, str) ! 592: void *oldp; ! 593: size_t *oldlenp; ! 594: void *newp; ! 595: char *str; ! 596: { ! 597: int len, error = 0; ! 598: ! 599: len = strlen(str) + 1; ! 600: if (oldp && *oldlenp < len) ! 601: return (ENOMEM); ! 602: if (newp) ! 603: return (EPERM); ! 604: *oldlenp = len; ! 605: if (oldp) ! 606: error = copyout(str, oldp, len); ! 607: return (error); ! 608: } ! 609: ! 610: /* ! 611: * Validate parameters and get old / set new parameters ! 612: * for a structure oriented sysctl function. ! 613: */ ! 614: sysctl_struct(oldp, oldlenp, newp, newlen, sp, len) ! 615: void *oldp; ! 616: size_t *oldlenp; ! 617: void *newp; ! 618: size_t newlen; ! 619: void *sp; ! 620: int len; ! 621: { ! 622: int error = 0; ! 623: ! 624: if (oldp && *oldlenp < len) ! 625: return (ENOMEM); ! 626: if (newp && newlen > len) ! 627: return (EINVAL); ! 628: if (oldp) { ! 629: *oldlenp = len; ! 630: error = copyout(sp, oldp, len); ! 631: } ! 632: if (error == 0 && newp) ! 633: error = copyin(newp, sp, len); ! 634: return (error); ! 635: } ! 636: ! 637: /* ! 638: * Validate parameters and get old parameters ! 639: * for a structure oriented sysctl function. ! 640: */ ! 641: sysctl_rdstruct(oldp, oldlenp, newp, sp, len) ! 642: void *oldp; ! 643: size_t *oldlenp; ! 644: void *newp, *sp; ! 645: int len; ! 646: { ! 647: int error = 0; ! 648: ! 649: if (oldp && *oldlenp < len) ! 650: return (ENOMEM); ! 651: if (newp) ! 652: return (EPERM); ! 653: *oldlenp = len; ! 654: if (oldp) ! 655: error = copyout(sp, oldp, len); ! 656: return (error); ! 657: } ! 658: ! 659: /* ! 660: * Get file structures. ! 661: */ ! 662: sysctl_file(where, sizep) ! 663: char *where; ! 664: size_t *sizep; ! 665: { ! 666: int buflen, error; ! 667: struct file *fp; ! 668: char *start = where; ! 669: ! 670: buflen = *sizep; ! 671: if (where == NULL) { ! 672: /* ! 673: * overestimate by 10 files ! 674: */ ! 675: *sizep = sizeof(filehead) + (nfiles + 10) * sizeof(struct file); ! 676: return (0); ! 677: } ! 678: ! 679: /* ! 680: * first copyout filehead ! 681: */ ! 682: if (buflen < sizeof(filehead)) { ! 683: *sizep = 0; ! 684: return (0); ! 685: } ! 686: if (error = copyout((caddr_t)&filehead, where, sizeof(filehead))) ! 687: return (error); ! 688: buflen -= sizeof(filehead); ! 689: where += sizeof(filehead); ! 690: ! 691: /* ! 692: * followed by an array of file structures ! 693: */ ! 694: for (fp = filehead.lh_first; fp != 0; fp = fp->f_list.le_next) { ! 695: if (buflen < sizeof(struct file)) { ! 696: *sizep = where - start; ! 697: return (ENOMEM); ! 698: } ! 699: if (error = copyout((caddr_t)fp, where, sizeof (struct file))) ! 700: return (error); ! 701: buflen -= sizeof(struct file); ! 702: where += sizeof(struct file); ! 703: } ! 704: *sizep = where - start; ! 705: return (0); ! 706: } ! 707: ! 708: /* ! 709: * try over estimating by 5 procs ! 710: */ ! 711: #define KERN_PROCSLOP (5 * sizeof (struct kinfo_proc)) ! 712: ! 713: sysctl_doproc(name, namelen, where, sizep) ! 714: int *name; ! 715: u_int namelen; ! 716: char *where; ! 717: size_t *sizep; ! 718: { ! 719: register struct proc *p; ! 720: register struct kinfo_proc *dp = (struct kinfo_proc *)where; ! 721: register int needed = 0; ! 722: int buflen = where != NULL ? *sizep : 0; ! 723: int doingzomb; ! 724: struct kinfo_proc kproc; ! 725: int error = 0; ! 726: ! 727: if (namelen != 2 && !(namelen == 1 && name[0] == KERN_PROC_ALL)) ! 728: return (EINVAL); ! 729: p = allproc.lh_first; ! 730: doingzomb = 0; ! 731: again: ! 732: for (; p != 0; p = p->p_list.le_next) { ! 733: /* ! 734: * Skip embryonic processes. ! 735: */ ! 736: if (p->p_stat == SIDL) ! 737: continue; ! 738: /* ! 739: * TODO - make more efficient (see notes below). ! 740: * do by session. ! 741: */ ! 742: switch (name[0]) { ! 743: ! 744: case KERN_PROC_PID: ! 745: /* could do this with just a lookup */ ! 746: if (p->p_pid != (pid_t)name[1]) ! 747: continue; ! 748: break; ! 749: ! 750: case KERN_PROC_PGRP: ! 751: /* could do this by traversing pgrp */ ! 752: if (p->p_pgrp->pg_id != (pid_t)name[1]) ! 753: continue; ! 754: break; ! 755: ! 756: case KERN_PROC_TTY: ! 757: if ((p->p_flag & P_CONTROLT) == 0 || ! 758: p->p_session->s_ttyp == NULL || ! 759: p->p_session->s_ttyp->t_dev != (dev_t)name[1]) ! 760: continue; ! 761: break; ! 762: ! 763: case KERN_PROC_UID: ! 764: if (p->p_ucred->cr_uid != (uid_t)name[1]) ! 765: continue; ! 766: break; ! 767: ! 768: case KERN_PROC_RUID: ! 769: if (p->p_cred->p_ruid != (uid_t)name[1]) ! 770: continue; ! 771: break; ! 772: } ! 773: if (buflen >= sizeof(struct kinfo_proc)) { ! 774: fill_proc(p, &kproc); ! 775: if (error = copyout((caddr_t)&kproc, &dp->kp_proc, ! 776: sizeof(struct kinfo_proc))) ! 777: return (error); ! 778: dp++; ! 779: buflen -= sizeof(struct kinfo_proc); ! 780: } ! 781: needed += sizeof(struct kinfo_proc); ! 782: } ! 783: if (doingzomb == 0) { ! 784: p = zombproc.lh_first; ! 785: doingzomb++; ! 786: goto again; ! 787: } ! 788: if (where != NULL) { ! 789: *sizep = (caddr_t)dp - where; ! 790: if (needed > *sizep) ! 791: return (ENOMEM); ! 792: } else { ! 793: needed += KERN_PROCSLOP; ! 794: *sizep = needed; ! 795: } ! 796: return (0); ! 797: } ! 798: ! 799: void ! 800: fill_proc(p,kp) ! 801: register struct proc *p; ! 802: register struct kinfo_proc *kp; ! 803: { ! 804: fill_externproc(p, &kp->kp_proc); ! 805: fill_eproc(p, &kp->kp_eproc); ! 806: } ! 807: /* ! 808: * Fill in an eproc structure for the specified process. ! 809: */ ! 810: void ! 811: fill_eproc(p, ep) ! 812: register struct proc *p; ! 813: register struct eproc *ep; ! 814: { ! 815: register struct tty *tp; ! 816: ! 817: ep->e_paddr = p; ! 818: ep->e_sess = p->p_pgrp->pg_session; ! 819: ep->e_pcred = *p->p_cred; ! 820: ep->e_ucred = *p->p_ucred; ! 821: if (p->p_stat == SIDL || p->p_stat == SZOMB) { ! 822: ep->e_vm.vm_rssize = 0; ! 823: ep->e_vm.vm_tsize = 0; ! 824: ep->e_vm.vm_dsize = 0; ! 825: ep->e_vm.vm_ssize = 0; ! 826: /* ep->e_vm.vm_pmap = XXX; */ ! 827: } else { ! 828: #if FIXME /* [ */ ! 829: register vm_map_t vm = ((task_t)p->task)->map; ! 830: ! 831: ep->e_vm.vm_rssize = pmap_resident_count(vm->pmap); /*XXX*/ ! 832: // ep->e_vm.vm_tsize = vm->vm_tsize; ! 833: // ep->e_vm.vm_dsize = vm->vm_dsize; ! 834: // ep->e_vm.vm_ssize = vm->vm_ssize; ! 835: #else /* FIXME ][ */ ! 836: ep->e_vm.vm_rssize = 0; /*XXX*/ ! 837: #endif /* FIXME ] */ ! 838: } ! 839: if (p->p_pptr) ! 840: ep->e_ppid = p->p_pptr->p_pid; ! 841: else ! 842: ep->e_ppid = 0; ! 843: ep->e_pgid = p->p_pgrp->pg_id; ! 844: ep->e_jobc = p->p_pgrp->pg_jobc; ! 845: if ((p->p_flag & P_CONTROLT) && ! 846: (tp = ep->e_sess->s_ttyp)) { ! 847: ep->e_tdev = tp->t_dev; ! 848: ep->e_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID; ! 849: ep->e_tsess = tp->t_session; ! 850: } else ! 851: ep->e_tdev = NODEV; ! 852: ep->e_flag = ep->e_sess->s_ttyvp ? EPROC_CTTY : 0; ! 853: if (SESS_LEADER(p)) ! 854: ep->e_flag |= EPROC_SLEADER; ! 855: if (p->p_wmesg) ! 856: strncpy(ep->e_wmesg, p->p_wmesg, WMESGLEN); ! 857: ep->e_xsize = ep->e_xrssize = 0; ! 858: ep->e_xccount = ep->e_xswrss = 0; ! 859: } ! 860: /* ! 861: * Fill in an eproc structure for the specified process. ! 862: */ ! 863: void ! 864: fill_externproc(p, exp) ! 865: register struct proc *p; ! 866: register struct extern_proc *exp; ! 867: { ! 868: exp->p_forw = exp->p_back = NULL; ! 869: exp->p_vmspace = NULL; ! 870: exp->p_sigacts = p->p_sigacts; ! 871: exp->p_flag = p->p_flag; ! 872: exp->p_stat = p->p_stat ; ! 873: exp->p_pid = p->p_pid ; ! 874: exp->p_oppid = p->p_oppid ; ! 875: exp->p_dupfd = p->p_dupfd ; ! 876: /* Mach related */ ! 877: exp->user_stack = p->user_stack ; ! 878: exp->exit_thread = p->exit_thread ; ! 879: exp->p_debugger = p->p_debugger ; ! 880: exp->sigwait = p->sigwait ; ! 881: /* scheduling */ ! 882: exp->p_estcpu = p->p_estcpu ; ! 883: exp->p_cpticks = p->p_cpticks ; ! 884: exp->p_pctcpu = p->p_pctcpu ; ! 885: exp->p_wchan = p->p_wchan ; ! 886: exp->p_wmesg = p->p_wmesg ; ! 887: exp->p_swtime = p->p_swtime ; ! 888: exp->p_slptime = p->p_slptime ; ! 889: bcopy(&p->p_realtimer, &exp->p_realtimer,sizeof(struct itimerval)); ! 890: bcopy(&p->p_rtime, &exp->p_rtime,sizeof(struct timeval)); ! 891: exp->p_uticks = p->p_uticks ; ! 892: exp->p_sticks = p->p_sticks ; ! 893: exp->p_iticks = p->p_iticks ; ! 894: exp->p_traceflag = p->p_traceflag ; ! 895: exp->p_tracep = p->p_tracep ; ! 896: exp->p_siglist = p->p_siglist ; ! 897: exp->p_textvp = p->p_textvp ; ! 898: exp->p_holdcnt = 0 ; ! 899: exp->p_sigmask = p->p_sigmask ; ! 900: exp->p_sigignore = p->p_sigignore ; ! 901: exp->p_sigcatch = p->p_sigcatch ; ! 902: exp->p_priority = p->p_priority ; ! 903: exp->p_usrpri = p->p_usrpri ; ! 904: exp->p_nice = p->p_nice ; ! 905: bcopy(&p->p_comm, &exp->p_comm,MAXCOMLEN); ! 906: exp->p_comm[MAXCOMLEN] = '\0'; ! 907: exp->p_pgrp = p->p_pgrp ; ! 908: exp->p_addr = NULL; ! 909: exp->p_xstat = p->p_xstat ; ! 910: exp->p_acflag = p->p_acflag ; ! 911: exp->p_ru = p->p_ru ; ! 912: } ! 913: ! 914: kdebug_ops(name, namelen, where, sizep, p) ! 915: int *name; ! 916: u_int namelen; ! 917: char *where; ! 918: size_t *sizep; ! 919: struct proc *p; ! 920: { ! 921: int size=*sizep; ! 922: int ret=0; ! 923: extern int kdbg_control(int *name, u_int namelen, char * where,size_t * sizep); ! 924: ! 925: switch(name[0]) { ! 926: case KERN_KDEFLAGS: ! 927: case KERN_KDDFLAGS: ! 928: case KERN_KDENABLE: ! 929: case KERN_KDGETBUF: ! 930: case KERN_KDSETUP: ! 931: case KERN_KDREMOVE: ! 932: case KERN_KDSETREG: ! 933: case KERN_KDGETREG: ! 934: case KERN_KDREADTR: ! 935: case KERN_KDPIDTR: ! 936: case KERN_KDTHRMAP: ! 937: case KERN_KDPIDEX: ! 938: ret = kdbg_control(name, namelen, where, sizep); ! 939: break; ! 940: case KERN_KDSETRTCDEC: ! 941: case KERN_KDSETBUF: ! 942: if (ret = suser(p->p_ucred, &p->p_acflag)) ! 943: return(ret); ! 944: else ! 945: ret = kdbg_control(name, namelen, where, sizep); ! 946: break; ! 947: default: ! 948: ret= EOPNOTSUPP; ! 949: break; ! 950: } ! 951: return(ret); ! 952: } ! 953: ! 954: /* ! 955: * try over estimating by 5 procs ! 956: */ ! 957: #define KERN_PROCSLOP (5 * sizeof (struct kinfo_proc)) ! 958: ! 959: sysctl_procargs(name, namelen, where, sizep) ! 960: int *name; ! 961: u_int namelen; ! 962: char *where; ! 963: size_t *sizep; ! 964: { ! 965: register struct proc *p; ! 966: register int needed = 0; ! 967: int buflen = where != NULL ? *sizep : 0; ! 968: int error = 0; ! 969: struct vm_map *proc_map; ! 970: struct task * task; ! 971: vm_map_copy_t tmp; ! 972: vm_offset_t arg_addr; ! 973: vm_size_t arg_size; ! 974: caddr_t data; ! 975: unsigned size; ! 976: vm_offset_t copy_start, copy_end; ! 977: vm_offset_t dealloc_start; /* area to remove from kernel map */ ! 978: vm_offset_t dealloc_end; ! 979: int *ip; ! 980: kern_return_t ret; ! 981: int pid; ! 982: ! 983: ! 984: pid = name[0]; ! 985: ! 986: p = pfind(pid); ! 987: if (p == NULL) { ! 988: return(EINVAL); ! 989: } ! 990: ! 991: if (p->task == NULL) ! 992: return(EINVAL); ! 993: ! 994: arg_size = buflen; ! 995: /* ! 996: * Returns the top N bytes of the user stack, with ! 997: * everything below the first argument character ! 998: * zeroed for security reasons. ! 999: * Odd data structure is for compatibility. ! 1000: */ ! 1001: /* ! 1002: * Lookup process by pid ! 1003: */ ! 1004: /* ! 1005: * Get map for process ! 1006: */ ! 1007: proc_map = get_task_map((task_t)p->task); ! 1008: ! 1009: /* ! 1010: * Copy the top N bytes of the stack. ! 1011: * On all machines we have so far, the stack grows ! 1012: * downwards. ! 1013: * ! 1014: * If the user expects no more than N bytes of ! 1015: * argument list, use that as a guess for the ! 1016: * size. ! 1017: */ ! 1018: ! 1019: if (buflen == 0) { ! 1020: return(EINVAL); ! 1021: } ! 1022: ! 1023: if (!p->user_stack) ! 1024: return(EINVAL); ! 1025: ! 1026: #if STACK_GROWTH_UP ! 1027: arg_addr = p->user_stack; ! 1028: #else STACK_GROWTH_UP ! 1029: arg_addr = p->user_stack - arg_size; ! 1030: #endif /* STACK_GROWTH_UP */ ! 1031: ! 1032: /* ! 1033: * Before we can block (any VM code), make another ! 1034: * reference to the map to keep it alive. ! 1035: */ ! 1036: ! 1037: ret = kmem_alloc_pageable(bsd_pageable_map, ©_start, ! 1038: round_page(arg_size)); ! 1039: if (ret != KERN_SUCCESS) ! 1040: return(ENOMEM); ! 1041: ! 1042: copy_end = round_page(copy_start + arg_size); ! 1043: ! 1044: /* vm_map_reference(proc_map); */ ! 1045: ! 1046: if( vm_map_copyin(proc_map, trunc_page(arg_addr), round_page(arg_size), ! 1047: FALSE, &tmp) != KERN_SUCCESS) { ! 1048: kmem_free(bsd_pageable_map, copy_start, ! 1049: round_page(arg_size)); ! 1050: /* vm_map_deallocate(proc_map); */ ! 1051: return (EIO); ! 1052: } ! 1053: if( vm_map_copy_overwrite(bsd_pageable_map, copy_start, ! 1054: tmp, FALSE) != KERN_SUCCESS) { ! 1055: kmem_free(bsd_pageable_map, copy_start, ! 1056: round_page(arg_size)); ! 1057: /* vm_map_deallocate(proc_map); */ ! 1058: return (EIO); ! 1059: } ! 1060: ! 1061: /* ! 1062: * Now that we've done the copy, we can release ! 1063: * the process' map. ! 1064: */ ! 1065: /* vm_map_deallocate(proc_map); */ ! 1066: ! 1067: #if STACK_GROWTH_UP ! 1068: data = (caddr_t)copy_start; ! 1069: ip = (int *) ((*(int *)copy_start) - arg_addr + data); ! 1070: /* ! 1071: * sanity check ip since it comes from user-accessible ! 1072: * stack area ! 1073: */ ! 1074: if (((vm_offset_t)ip > copy_end) || ! 1075: ((vm_offset_t)ip < copy_start)) ! 1076: ip = (int *)copy_end; ! 1077: /* ! 1078: * relocate so that end of string area is at end ! 1079: * of buffer. ! 1080: */ ! 1081: size = (unsigned) ((int)ip - (int)copy_start); ! 1082: data = (caddr_t)(copy_end - size); ! 1083: bcopy(copy_start, data, size); ! 1084: /* ! 1085: * now find beginning of string area so we can ! 1086: * clear out data user should not see ! 1087: */ ! 1088: ip = (int *)copy_end; // start at new end ! 1089: ip -= 2; /*skip trailing 0 word and assume at least one ! 1090: argument. The last word of argN may be just ! 1091: the trailing 0, in which case we'd stop ! 1092: there */ ! 1093: while (*--ip) ! 1094: if (ip == (int *)data) ! 1095: break; ! 1096: bzero(copy_start, ! 1097: (unsigned) ((int)ip - (int)copy_start)); ! 1098: /* ! 1099: * now prepare data/size for the copy's out of the ! 1100: * switch. We copy the last arg_size bytes from ! 1101: * our data. ! 1102: */ ! 1103: size = arg_size; ! 1104: data = (caddr_t)(copy_end - size); ! 1105: #else STACK_GROWTH_UP ! 1106: data = (caddr_t) (copy_end - arg_size); ! 1107: ip = (int *) copy_end; ! 1108: size = arg_size; ! 1109: ! 1110: /* ! 1111: * Now look down the stack for the bottom of the ! 1112: * argument list. Since this call is otherwise ! 1113: * unprotected, we can't let the nosy user see ! 1114: * anything else on the stack. ! 1115: * ! 1116: * The arguments are pushed on the stack by ! 1117: * execve() as: ! 1118: * ! 1119: * .long 0 ! 1120: * arg 0 (null-terminated) ! 1121: * arg 1 ! 1122: * ... ! 1123: * arg N ! 1124: * .long 0 ! 1125: * ! 1126: */ ! 1127: ! 1128: ip -= 2; /*skip trailing 0 word and assume at least one ! 1129: argument. The last word of argN may be just ! 1130: the trailing 0, in which case we'd stop ! 1131: there */ ! 1132: while (*--ip) ! 1133: if (ip == (int *)data) ! 1134: break; ! 1135: bzero(data, (unsigned) ((int)ip - (int)data)); ! 1136: #endif /* STACK_GROWTH_UP */ ! 1137: ! 1138: dealloc_start = copy_start; ! 1139: dealloc_end = copy_end; ! 1140: ! 1141: ! 1142: size = MIN(size, buflen); ! 1143: error = copyout(data, where, size); ! 1144: ! 1145: if (dealloc_start != (vm_offset_t) 0) { ! 1146: kmem_free(bsd_pageable_map, dealloc_start, ! 1147: dealloc_end - dealloc_start); ! 1148: } ! 1149: if (error) { ! 1150: return(error); ! 1151: } ! 1152: ! 1153: if (where != NULL) ! 1154: *sizep = size; ! 1155: return (0); ! 1156: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.