|
|
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.