|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights ! 7: * Reserved. This file contains Original Code and/or Modifications of ! 8: * Original Code as defined in and that are subject to the Apple Public ! 9: * Source License Version 1.1 (the "License"). You may not use this file ! 10: * except in compliance with the License. Please obtain a copy of the ! 11: * License at http://www.apple.com/publicsource and read it before using ! 12: * this file. ! 13: * ! 14: * The Original Code and all software distributed under the License are ! 15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 19: * License for the specific language governing rights and limitations ! 20: * under the License. ! 21: * ! 22: * @APPLE_LICENSE_HEADER_END@ ! 23: */ ! 24: ! 25: /* ! 26: * Mach Operating System ! 27: * Copyright (c) 1987 Carnegie-Mellon University ! 28: * All rights reserved. The CMU software License Agreement specifies ! 29: * the terms and conditions for use and redistribution. ! 30: * ! 31: * HISTORY ! 32: * ! 33: * 27-Apr-97 A.Ramesh (aramesh) at Apple ! 34: * Added limited set for Rhapsody ! 35: * ! 36: */ ! 37: ! 38: #import <sys/param.h> ! 39: #import <sys/systm.h> ! 40: #import <sys/dir.h> ! 41: #import <sys/buf.h> ! 42: #import <sys/vnode.h> ! 43: #import <sys/file.h> ! 44: #import <sys/proc.h> ! 45: #import <sys/conf.h> ! 46: #import <sys/ioctl.h> ! 47: #import <sys/tty.h> ! 48: //#import <sys/vfs.h> ! 49: //#import <ufs/mount.h> ! 50: #import <sys/kernel.h> ! 51: #import <sys/table.h> ! 52: ! 53: #import <mach/mach_types.h> ! 54: ! 55: #import <vm/vm_user.h> ! 56: #import <vm/vm_map.h> ! 57: #import <vm/vm_kern.h> ! 58: #import <mach/vm_param.h> ! 59: #import <machine/vmparam.h> /* only way to find the user stack (argblock) */ ! 60: ! 61: #import <sys/vmmeter.h> ! 62: #import <sys/socket.h> ! 63: #import <net/if.h> ! 64: ! 65: #import <sys/version.h> ! 66: ! 67: struct vmmeter cnt; ! 68: ! 69: /* ! 70: * table - get/set element(s) from system table ! 71: * ! 72: * This call is intended as a general purpose mechanism for retrieving or ! 73: * updating individual or sequential elements of various system tables and ! 74: * data structures. ! 75: * ! 76: * One potential future use might be to make most of the standard system ! 77: * tables available via this mechanism so as to permit non-privileged programs ! 78: * to access these common SYSTAT types of data. ! 79: * ! 80: * Parameters: ! 81: * ! 82: * id = an identifer indicating the table in question ! 83: * index = an index into this table specifying the starting ! 84: * position at which to begin the data copy ! 85: * addr = address in user space to receive/supply the data ! 86: * nel = number of table elements to retrieve/update ! 87: * lel = expected size of a single element of the table. If this ! 88: * is smaller than the actual size, extra data will be ! 89: * truncated from the end. If it is larger, holes will be ! 90: * left between elements copied to/from the user address space. ! 91: * ! 92: * The intent of separately distinguishing these final two ! 93: * arguments is to insulate user programs as much as possible ! 94: * from the common change in the size of system data structures ! 95: * when a new field is added. This works so long as new fields ! 96: * are added only to the end, none are removed, and all fields ! 97: * remain a fixed size. ! 98: * ! 99: * Returns: ! 100: * ! 101: * val1 = number of elements retrieved/updated (this may be fewer than ! 102: * requested if more elements are requested than exist in ! 103: * the table from the specified index). ! 104: * ! 105: * Note: ! 106: * ! 107: * A call with lel == 0 and nel == MAXSHORT can be used to determine the ! 108: * length of a table (in elements) before actually requesting any of the ! 109: * data. ! 110: */ ! 111: ! 112: #define MAXLEL (sizeof(long)) /* maximum element length (for set) */ ! 113: ! 114: struct table_args { ! 115: int id; ! 116: int index; ! 117: caddr_t addr; ! 118: int nel; /* >0 ==> get, <0 ==> set */ ! 119: u_int lel; ! 120: }; ! 121: ! 122: table(p, uap, retval) ! 123: struct proc *p; ! 124: register struct table_args *uap; ! 125: int *retval; ! 126: { ! 127: caddr_t data; ! 128: unsigned size; ! 129: int error = 0; ! 130: int set; ! 131: vm_offset_t arg_addr; ! 132: vm_size_t arg_size; ! 133: int *ip; ! 134: struct proc *pp; ! 135: vm_offset_t copy_start, copy_end; ! 136: vm_map_t proc_map; ! 137: vm_offset_t dealloc_start; /* area to remove from kernel map */ ! 138: vm_offset_t dealloc_end; ! 139: struct tbl_procinfo tp; ! 140: struct tbl_cpuinfo tc; ! 141: struct tbl_loadavg tl; ! 142: int val1=0; ! 143: extern long avenrun[3], mach_factor[3]; ! 144: ! 145: /* ! 146: * Verify that any set request is appropriate. ! 147: */ ! 148: set = 0; ! 149: if (uap->nel < 0) { ! 150: /* ! 151: * Give the machine dependent code a crack at this first ! 152: */ ! 153: switch (machine_table_setokay(uap->id)) { ! 154: case TBL_MACHDEP_OKAY: ! 155: goto okay; ! 156: case TBL_MACHDEP_BAD: ! 157: *retval = val1; ! 158: return(EINVAL); ! 159: case TBL_MACHDEP_NONE: ! 160: default: ! 161: break; ! 162: } ! 163: switch (uap->id) { ! 164: default: ! 165: *retval = val1; ! 166: return(EINVAL); ! 167: } ! 168: okay: ! 169: set++; ! 170: uap->nel = -(uap->nel); ! 171: } ! 172: ! 173: val1 = 0; ! 174: ! 175: /* ! 176: * Main loop for each element. ! 177: */ ! 178: ! 179: while (uap->nel > 0) { ! 180: ! 181: dealloc_start = (vm_offset_t) 0; ! 182: dealloc_end = (vm_offset_t) 0; ! 183: ! 184: /* ! 185: * Give machine dependent code a chance ! 186: */ ! 187: switch (machine_table(uap->id, uap->index, uap->addr, ! 188: uap->nel, uap->lel, set)) ! 189: { ! 190: case TBL_MACHDEP_OKAY: ! 191: uap->addr += uap->lel; ! 192: uap->nel -= 1; ! 193: uap->index += 1; ! 194: val1 += 1; ! 195: continue; ! 196: case TBL_MACHDEP_NONE: ! 197: break; ! 198: case TBL_MACHDEP_BAD: ! 199: default: ! 200: goto bad; ! 201: } ! 202: ! 203: switch (uap->id) { ! 204: case TBL_ARGUMENTS: ! 205: /* ! 206: * Returns the top N bytes of the user stack, with ! 207: * everything below the first argument character ! 208: * zeroed for security reasons. ! 209: * Odd data structure is for compatibility. ! 210: */ ! 211: /* ! 212: * Lookup process by pid ! 213: */ ! 214: p = pfind(uap->index); ! 215: if (p == (struct proc *)0) { ! 216: /* ! 217: * No such process ! 218: */ ! 219: *retval = val1; ! 220: return(ESRCH); ! 221: } ! 222: /* ! 223: * Get map for process ! 224: */ ! 225: proc_map = ((task_t)p->task)->map; ! 226: ! 227: /* ! 228: * Copy the top N bytes of the stack. ! 229: * On all machines we have so far, the stack grows ! 230: * downwards. ! 231: * ! 232: * If the user expects no more than N bytes of ! 233: * argument list, use that as a guess for the ! 234: * size. ! 235: */ ! 236: if ((arg_size = uap->lel) == 0) { ! 237: error = EINVAL; ! 238: goto bad; ! 239: } ! 240: ! 241: if (!p->user_stack) ! 242: goto bad; /* kernel only proc */ ! 243: #if STACK_GROWTH_UP ! 244: arg_addr = p->user_stack; ! 245: #else STACK_GROWTH_UP ! 246: arg_addr = p->user_stack - arg_size; ! 247: #endif /* STACK_GROWTH_UP */ ! 248: ! 249: /* ! 250: * Before we can block (any VM code), make another ! 251: * reference to the map to keep it alive. ! 252: */ ! 253: vm_map_reference(proc_map); ! 254: ! 255: copy_start = kmem_alloc_wait(kernel_pageable_map, ! 256: round_page(arg_size)); ! 257: ! 258: copy_end = round_page(copy_start + arg_size); ! 259: ! 260: if (vm_map_copy(kernel_pageable_map, proc_map, copy_start, ! 261: round_page(arg_size), trunc_page(arg_addr), ! 262: FALSE, FALSE) != KERN_SUCCESS) { ! 263: kmem_free_wakeup(kernel_pageable_map, copy_start, ! 264: round_page(arg_size)); ! 265: vm_map_deallocate(proc_map); ! 266: goto bad; ! 267: } ! 268: ! 269: /* ! 270: * Now that we've done the copy, we can release ! 271: * the process' map. ! 272: */ ! 273: vm_map_deallocate(proc_map); ! 274: ! 275: #if STACK_GROWTH_UP ! 276: data = (caddr_t)copy_start; ! 277: ip = (int *) ((*(int *)copy_start) - arg_addr + data); ! 278: /* ! 279: * sanity check ip since it comes from user-accessible ! 280: * stack area ! 281: */ ! 282: if (((vm_offset_t)ip > copy_end) || ! 283: ((vm_offset_t)ip < copy_start)) ! 284: ip = (int *)copy_end; ! 285: /* ! 286: * relocate so that end of string area is at end ! 287: * of buffer. ! 288: */ ! 289: size = (unsigned) ((int)ip - (int)copy_start); ! 290: data = (caddr_t)(copy_end - size); ! 291: bcopy(copy_start, data, size); ! 292: /* ! 293: * now find beginning of string area so we can ! 294: * clear out data user should not see ! 295: */ ! 296: ip = (int *)copy_end; // start at new end ! 297: ip -= 2; /*skip trailing 0 word and assume at least one ! 298: argument. The last word of argN may be just ! 299: the trailing 0, in which case we'd stop ! 300: there */ ! 301: while (*--ip) ! 302: if (ip == (int *)data) ! 303: break; ! 304: bzero(copy_start, ! 305: (unsigned) ((int)ip - (int)copy_start)); ! 306: /* ! 307: * now prepare data/size for the copy's out of the ! 308: * switch. We copy the last arg_size bytes from ! 309: * our data. ! 310: */ ! 311: size = arg_size; ! 312: data = (caddr_t)(copy_end - size); ! 313: #else STACK_GROWTH_UP ! 314: #if ( defined(vax) || defined(romp) ) ! 315: data = (caddr_t) (copy_end-arg_size-SIGCODE_SIZE); ! 316: ip = (int *) (copy_end - SIGCODE_SIZE); ! 317: #else ( defined(vax) || defined(romp) ) ! 318: data = (caddr_t) (copy_end - arg_size); ! 319: ip = (int *) copy_end; ! 320: #endif /* ( defined(vax) || defined(romp) ) */ ! 321: size = arg_size; ! 322: ! 323: /* ! 324: * Now look down the stack for the bottom of the ! 325: * argument list. Since this call is otherwise ! 326: * unprotected, we can't let the nosy user see ! 327: * anything else on the stack. ! 328: * ! 329: * The arguments are pushed on the stack by ! 330: * execve() as: ! 331: * ! 332: * .long 0 ! 333: * arg 0 (null-terminated) ! 334: * arg 1 ! 335: * ... ! 336: * arg N ! 337: * .long 0 ! 338: * ! 339: */ ! 340: ! 341: ip -= 2; /*skip trailing 0 word and assume at least one ! 342: argument. The last word of argN may be just ! 343: the trailing 0, in which case we'd stop ! 344: there */ ! 345: while (*--ip) ! 346: if (ip == (int *)data) ! 347: break; ! 348: bzero(data, (unsigned) ((int)ip - (int)data)); ! 349: #endif /* STACK_GROWTH_UP */ ! 350: ! 351: dealloc_start = copy_start; ! 352: dealloc_end = copy_end; ! 353: break; ! 354: ! 355: case TBL_PROCINFO: ! 356: { ! 357: register struct proc *p; ! 358: ! 359: /* ! 360: * Index is entry number in proc table. ! 361: */ ! 362: /* transition, take negative numbers as pid for now */ ! 363: if (uap->index < 0) ! 364: uap->index = -uap->index; /* compatibility */ ! 365: p = pfind(uap->index); ! 366: if (p == (struct proc *)0) { ! 367: /* ! 368: * No such process ! 369: */ ! 370: return(ESRCH); ! 371: } ! 372: if (p->p_stat == 0) { ! 373: bzero((caddr_t)&tp, sizeof(tp)); ! 374: tp.pi_status = PI_EMPTY; ! 375: } ! 376: else { ! 377: tp.pi_uid = p->p_ucred->cr_uid; ! 378: tp.pi_pid = p->p_pid; ! 379: ! 380: if (p->p_pptr) ! 381: tp.pi_ppid = p->p_pptr->p_pid; ! 382: else ! 383: tp.pi_ppid = 0; ! 384: if (p->p_pgrp) ! 385: tp.pi_pgrp = p->p_pgrp->pg_id; ! 386: else ! 387: tp.pi_pgrp = 0; ! 388: tp.pi_flag = p->p_flag; ! 389: ! 390: if (p->task == TASK_NULL) { ! 391: tp.pi_status = PI_ZOMBIE; ! 392: } ! 393: else { ! 394: if (p->p_pgrp && p->p_pgrp->pg_session && p->p_pgrp->pg_session->s_ttyp ) ! 395: tp.pi_ttyd = p->p_pgrp->pg_session->s_ttyp->t_dev; ! 396: else ! 397: tp.pi_ttyd = -1; ! 398: bcopy(&p->p_comm[0], tp.pi_comm, ! 399: MAXCOMLEN); ! 400: tp.pi_comm[MAXCOMLEN] = '\0'; ! 401: ! 402: if (p->p_flag & P_WEXIT) ! 403: tp.pi_status = PI_EXITING; ! 404: else ! 405: tp.pi_status = PI_ACTIVE; ! 406: } ! 407: } ! 408: ! 409: data = (caddr_t)&tp; ! 410: size = sizeof(tp); ! 411: break; ! 412: } ! 413: ! 414: case TBL_CPUINFO: ! 415: if (uap->index != 0 || uap->nel != 1) ! 416: goto bad; ! 417: tc.ci_swtch = cnt.v_swtch; ! 418: tc.ci_intr = cnt.v_intr; ! 419: tc.ci_syscall = cnt.v_syscall; ! 420: tc.ci_traps = cnt.v_trap; ! 421: tc.ci_hz = hz; ! 422: tc.ci_phz = 0; ! 423: bcopy(cp_time, tc.ci_cptime, sizeof(cp_time)); ! 424: data = (caddr_t)&tc; ! 425: size = sizeof (tc); ! 426: break; ! 427: case TBL_LOADAVG: ! 428: if (uap->index != 0 || uap->nel != 1) ! 429: goto bad; ! 430: bcopy((caddr_t)&avenrun[0], (caddr_t)&tl.tl_avenrun[0], ! 431: sizeof(tl.tl_avenrun)); ! 432: tl.tl_lscale = LSCALE; ! 433: data = (caddr_t)&tl; ! 434: size = sizeof (tl); ! 435: break; ! 436: case TBL_MACHFACTOR: ! 437: if (uap->index != 0 || uap->nel != 1) ! 438: goto bad; ! 439: bcopy((caddr_t)&mach_factor[0], ! 440: (caddr_t)&tl.tl_avenrun[0], ! 441: sizeof(tl.tl_avenrun)); ! 442: tl.tl_lscale = LSCALE; ! 443: data = (caddr_t)&tl; ! 444: size = sizeof (tl); ! 445: break; ! 446: default: ! 447: bad: ! 448: /* ! 449: * Return error only if all indices ! 450: * are invalid. ! 451: */ ! 452: if (val1 == 0) ! 453: error = EINVAL; ! 454: *retval = val1; ! 455: return(error); ! 456: } ! 457: /* ! 458: * This code should be generalized if/when other tables ! 459: * are added to handle single element copies where the ! 460: * actual and expected sizes differ or the table entries ! 461: * are not contiguous in kernel memory (as with TTYLOC) ! 462: * and also efficiently copy multiple element ! 463: * tables when contiguous and the sizes match. ! 464: */ ! 465: size = MIN(size, uap->lel); ! 466: if (size) { ! 467: if (set) { ! 468: char buff[MAXLEL]; ! 469: ! 470: error = copyin(uap->addr, buff, size); ! 471: if (error == 0) ! 472: bcopy(buff, data, size); ! 473: } ! 474: else { ! 475: error = copyout(data, uap->addr, size); ! 476: } ! 477: } ! 478: if (dealloc_start != (vm_offset_t) 0) { ! 479: kmem_free_wakeup(kernel_pageable_map, dealloc_start, ! 480: dealloc_end - dealloc_start); ! 481: } ! 482: if (error) { ! 483: *retval = val1; ! 484: return(error); ! 485: } ! 486: uap->addr += uap->lel; ! 487: uap->nel -= 1; ! 488: uap->index += 1; ! 489: val1 += 1; ! 490: } ! 491: *retval = val1; ! 492: return(0); ! 493: } ! 494:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.