]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/kern_sysctl.c
xnu-201.tar.gz
[apple/xnu.git] / bsd / kern / kern_sysctl.c
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/machine.h>
80 #include <mach/mach_types.h>
81 #include <mach/vm_param.h>
82 #include <kern/task.h>
83 #include <vm/vm_kern.h>
84 #include <mach/host_info.h>
85
86 extern vm_map_t bsd_pageable_map;
87
88 #include <sys/mount.h>
89 #include <sys/kdebug.h>
90
91 #include <IOKit/IOPlatformExpert.h>
92 #include <pexpert/pexpert.h>
93
94 #if __ppc__
95 #include <osfmk/ppc/machine_routines.h>
96 #endif
97
98 sysctlfn kern_sysctl;
99 sysctlfn hw_sysctl;
100 #ifdef DEBUG
101 sysctlfn debug_sysctl;
102 #endif
103 extern sysctlfn vm_sysctl;
104 extern sysctlfn vfs_sysctl;
105 extern sysctlfn net_sysctl;
106 extern sysctlfn cpu_sysctl;
107
108
109 int
110 userland_sysctl(struct proc *p, int *name, u_int namelen, void *old, size_t
111 *oldlenp, int inkernel, void *new, size_t newlen, size_t *retval);
112
113 void
114 fill_proc(struct proc *p,struct kinfo_proc *kp, int doingzomb);
115
116 void
117 fill_externproc(struct proc *p, struct extern_proc *exp);
118
119
120
121 /*
122 * temporary location for vm_sysctl. This should be machine independant
123 */
124 vm_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
125 int *name;
126 u_int namelen;
127 void *oldp;
128 size_t *oldlenp;
129 void *newp;
130 size_t newlen;
131 struct proc *p;
132 {
133 int error, level, inthostid;
134 extern long avenrun[3], mach_factor[3];
135 struct loadavg loadinfo;
136
137 //if (namelen != 1 && !(name[0] == VM_LOADAVG))
138 //return (ENOTDIR); /* overloaded */
139
140 switch (name[0]) {
141 case VM_LOADAVG:
142 loadinfo.ldavg[0] = avenrun[0];
143 loadinfo.ldavg[1] = avenrun[1];
144 loadinfo.ldavg[2] = avenrun[2];
145 loadinfo.fscale = LSCALE;
146 return (sysctl_struct(oldp, oldlenp, newp, newlen, &loadinfo, sizeof(struct loadavg)));
147 case VM_MACHFACTOR:
148 loadinfo.ldavg[0] = mach_factor[0];
149 loadinfo.ldavg[1] = mach_factor[1];
150 loadinfo.ldavg[2] = mach_factor[2];
151 loadinfo.fscale = LSCALE;
152 return (sysctl_struct(oldp, oldlenp, newp, newlen, &loadinfo, sizeof(struct loadavg)));
153 case VM_METER:
154 return (EOPNOTSUPP);
155 case VM_MAXID:
156 return (EOPNOTSUPP);
157 default:
158 return (EOPNOTSUPP);
159 }
160 /* NOTREACHED */
161 return (EOPNOTSUPP);
162 }
163
164 /*
165 * Locking and stats
166 */
167 static struct sysctl_lock {
168 int sl_lock;
169 int sl_want;
170 int sl_locked;
171 } memlock;
172
173 struct __sysctl_args {
174 int *name;
175 u_int namelen;
176 void *old;
177 size_t *oldlenp;
178 void *new;
179 size_t newlen;
180 };
181 int
182 __sysctl(p, uap, retval)
183 struct proc *p;
184 register struct __sysctl_args *uap;
185 register_t *retval;
186 {
187 int error, dolock = 1;
188 size_t savelen, oldlen = 0;
189 sysctlfn *fn;
190 int name[CTL_MAXNAME];
191 int i;
192 int error1;
193
194 /*
195 * all top-level sysctl names are non-terminal
196 */
197 if (uap->namelen > CTL_MAXNAME || uap->namelen < 2)
198 return (EINVAL);
199 if (error =
200 copyin(uap->name, &name, uap->namelen * sizeof(int)))
201 return (error);
202
203 /* CTL_UNSPEC is used to get oid to AUTO_OID */
204 if (uap->new != NULL &&
205 (((name[0] == CTL_KERN) && (name[1] != KERN_IPC)) ||
206 (name[0] == CTL_HW) || (name[0] == CTL_VM) ||
207 (name[0] == CTL_VFS)) &&
208 (error = suser(p->p_ucred, &p->p_acflag)))
209 return (error);
210
211 switch (name[0]) {
212 case CTL_KERN:
213 fn = kern_sysctl;
214 if ((name[1] != KERN_VNODE) && (name[1] != KERN_FILE)
215 && (name[1] != KERN_PROC))
216 dolock = 0;
217 break;
218 case CTL_HW:
219 fn = hw_sysctl;
220 break;
221 case CTL_VM:
222 fn = vm_sysctl;
223 break;
224
225 case CTL_VFS:
226 fn = vfs_sysctl;
227 break;
228 #if FIXME /* [ */
229 case CTL_MACHDEP:
230 fn = cpu_sysctl;
231 break;
232 #endif /* FIXME ] */
233 #ifdef DEBUG
234 case CTL_DEBUG:
235 fn = debug_sysctl;
236 break;
237 #endif
238 default:
239 fn = 0;
240 }
241
242 if (uap->oldlenp &&
243 (error = copyin(uap->oldlenp, &oldlen, sizeof(oldlen))))
244 return (error);
245
246 if (uap->old != NULL) {
247 if (!useracc(uap->old, oldlen, B_WRITE))
248 return (EFAULT);
249
250 /* The pc sampling mechanism does not need to take this lock */
251 if (name[1] != KERN_PCSAMPLES) {
252 while (memlock.sl_lock) {
253 memlock.sl_want = 1;
254 sleep((caddr_t)&memlock, PRIBIO+1);
255 memlock.sl_locked++;
256 }
257 memlock.sl_lock = 1;
258 }
259
260 if (dolock && oldlen && (error = vslock(uap->old, oldlen))) {
261 if (name[1] != KERN_PCSAMPLES) {
262 memlock.sl_lock = 0;
263 if (memlock.sl_want) {
264 memlock.sl_want = 0;
265 wakeup((caddr_t)&memlock);
266 }
267 }
268 return(error);
269 }
270 savelen = oldlen;
271 }
272
273 if (fn)
274 error = (*fn)(name + 1, uap->namelen - 1, uap->old,
275 &oldlen, uap->new, uap->newlen, p);
276 else
277 error = EOPNOTSUPP;
278
279 if ( (name[0] != CTL_VFS) && (error == EOPNOTSUPP))
280 error = userland_sysctl(p, name, uap->namelen,
281 uap->old, uap->oldlenp, 0,
282 uap->new, uap->newlen, &oldlen);
283
284 if (uap->old != NULL) {
285 if (dolock && savelen) {
286 error1 = vsunlock(uap->old, savelen, B_WRITE);
287 if (!error && error1)
288 error = error1;
289 }
290 if (name[1] != KERN_PCSAMPLES) {
291 memlock.sl_lock = 0;
292 if (memlock.sl_want) {
293 memlock.sl_want = 0;
294 wakeup((caddr_t)&memlock);
295 }
296 }
297 }
298 if ((error) && (error != ENOMEM))
299 return (error);
300
301 if (uap->oldlenp) {
302 i = copyout(&oldlen, uap->oldlenp, sizeof(oldlen));
303 if (i)
304 return i;
305 }
306
307 return (error);
308 }
309
310 /*
311 * Attributes stored in the kernel.
312 */
313 extern char hostname[MAXHOSTNAMELEN]; /* defined in bsd/kern/init_main.c */
314 extern int hostnamelen;
315 extern char domainname[MAXHOSTNAMELEN];
316 extern int domainnamelen;
317 extern long hostid;
318 #ifdef INSECURE
319 int securelevel = -1;
320 #else
321 int securelevel;
322 #endif
323
324 int get_kernel_symfile( struct proc *p, char **symfile );
325
326 /*
327 * kernel related system variables.
328 */
329 kern_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
330 int *name;
331 u_int namelen;
332 void *oldp;
333 size_t *oldlenp;
334 void *newp;
335 size_t newlen;
336 struct proc *p;
337 {
338 int error, level, inthostid;
339 unsigned int oldval=0;
340 extern char ostype[], osrelease[], version[];
341
342 /* all sysctl names at this level are terminal */
343 if (namelen != 1 && !(name[0] == KERN_PROC || name[0] == KERN_PROF
344 || name[0] == KERN_KDEBUG
345 || name[0] == KERN_PROCARGS
346 || name[0] == KERN_PCSAMPLES
347 || name[0] == KERN_IPC
348 ))
349 return (ENOTDIR); /* overloaded */
350
351 switch (name[0]) {
352 case KERN_OSTYPE:
353 return (sysctl_rdstring(oldp, oldlenp, newp, ostype));
354 case KERN_OSRELEASE:
355 return (sysctl_rdstring(oldp, oldlenp, newp, osrelease));
356 case KERN_OSREV:
357 return (sysctl_rdint(oldp, oldlenp, newp, BSD));
358 case KERN_VERSION:
359 return (sysctl_rdstring(oldp, oldlenp, newp, version));
360 case KERN_MAXVNODES:
361 oldval = desiredvnodes;
362 error = sysctl_int(oldp, oldlenp, newp,
363 newlen, &desiredvnodes);
364 reset_vmobjectcache(oldval, desiredvnodes);
365 return(error);
366 case KERN_MAXPROC:
367 return (sysctl_int(oldp, oldlenp, newp, newlen, &maxproc));
368 case KERN_MAXFILES:
369 return (sysctl_int(oldp, oldlenp, newp, newlen, &maxfiles));
370 case KERN_ARGMAX:
371 return (sysctl_rdint(oldp, oldlenp, newp, ARG_MAX));
372 case KERN_SECURELVL:
373 level = securelevel;
374 if ((error = sysctl_int(oldp, oldlenp, newp, newlen, &level)) ||
375 newp == NULL)
376 return (error);
377 if (level < securelevel && p->p_pid != 1)
378 return (EPERM);
379 securelevel = level;
380 return (0);
381 case KERN_HOSTNAME:
382 error = sysctl_string(oldp, oldlenp, newp, newlen,
383 hostname, sizeof(hostname));
384 if (newp && !error)
385 hostnamelen = newlen;
386 return (error);
387 case KERN_DOMAINNAME:
388 error = sysctl_string(oldp, oldlenp, newp, newlen,
389 domainname, sizeof(domainname));
390 if (newp && !error)
391 domainnamelen = newlen;
392 return (error);
393 case KERN_HOSTID:
394 inthostid = hostid; /* XXX assumes sizeof long <= sizeof int */
395 error = sysctl_int(oldp, oldlenp, newp, newlen, &inthostid);
396 hostid = inthostid;
397 return (error);
398 case KERN_CLOCKRATE:
399 return (sysctl_clockrate(oldp, oldlenp));
400 case KERN_BOOTTIME:
401 return (sysctl_rdstruct(oldp, oldlenp, newp, &boottime,
402 sizeof(struct timeval)));
403 case KERN_VNODE:
404 return (sysctl_vnode(oldp, oldlenp));
405 case KERN_PROC:
406 return (sysctl_doproc(name + 1, namelen - 1, oldp, oldlenp));
407 case KERN_FILE:
408 return (sysctl_file(oldp, oldlenp));
409 #ifdef GPROF
410 case KERN_PROF:
411 return (sysctl_doprof(name + 1, namelen - 1, oldp, oldlenp,
412 newp, newlen));
413 #endif
414 case KERN_POSIX1:
415 return (sysctl_rdint(oldp, oldlenp, newp, _POSIX_VERSION));
416 case KERN_NGROUPS:
417 return (sysctl_rdint(oldp, oldlenp, newp, NGROUPS_MAX));
418 case KERN_JOB_CONTROL:
419 return (sysctl_rdint(oldp, oldlenp, newp, 1));
420 case KERN_SAVED_IDS:
421 #ifdef _POSIX_SAVED_IDS
422 return (sysctl_rdint(oldp, oldlenp, newp, 1));
423 #else
424 return (sysctl_rdint(oldp, oldlenp, newp, 0));
425 #endif
426 #if FIXME /* [ */
427 case KERN_MAXPARTITIONS:
428 return (sysctl_rdint(oldp, oldlenp, newp, MAXPARTITIONS));
429 #endif /* FIXME ] */
430 case KERN_KDEBUG:
431 return (kdebug_ops(name + 1, namelen - 1, oldp, oldlenp, p));
432 case KERN_PCSAMPLES:
433 return (pcsamples_ops(name + 1, namelen - 1, oldp, oldlenp, p));
434 case KERN_PROCARGS:
435 /* new one as it does not use kinfo_proc */
436 return (sysctl_procargs(name + 1, namelen - 1, oldp, oldlenp));
437 case KERN_SYMFILE:
438 {
439 char *str;
440 error = get_kernel_symfile( p, &str );
441 if ( error ) return error;
442 return (sysctl_rdstring(oldp, oldlenp, newp, str));
443 }
444 default:
445 return (EOPNOTSUPP);
446 }
447 /* NOTREACHED */
448 }
449
450 /*
451 * hardware related system variables.
452 */
453 hw_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
454 int *name;
455 u_int namelen;
456 void *oldp;
457 size_t *oldlenp;
458 void *newp;
459 size_t newlen;
460 struct proc *p;
461 {
462 char dummy[65];
463 int epochTemp;
464 extern int vm_page_wire_count;
465 #if __ppc__
466 ml_ppc_cpu_info_t cpu_info;
467
468 ml_ppc_get_info(&cpu_info);
469 #endif
470
471 /* all sysctl names at this level are terminal */
472 if (namelen != 1)
473 return (ENOTDIR); /* overloaded */
474
475 switch (name[0]) {
476 case HW_MACHINE:
477 if(!PEGetMachineName(dummy,64))
478 return(EINVAL);
479 return (sysctl_rdstring(oldp, oldlenp, newp, dummy));
480 case HW_MODEL:
481 if(!PEGetModelName(dummy,64))
482 return(EINVAL);
483 return (sysctl_rdstring(oldp, oldlenp, newp, dummy));
484 case HW_NCPU: {
485 int numcpus=1;
486 host_basic_info_data_t hinfo;
487 kern_return_t kret;
488 int count= HOST_BASIC_INFO_COUNT;
489 #define BSD_HOST 1
490
491 kret = host_info(BSD_HOST, HOST_BASIC_INFO, &hinfo, &count);
492 if (kret == KERN_SUCCESS) {
493 numcpus = hinfo.avail_cpus;
494 return (sysctl_rdint(oldp, oldlenp, newp, numcpus));
495 } else {
496 return(EINVAL);
497 }
498 }
499 case HW_BYTEORDER:
500 return (sysctl_rdint(oldp, oldlenp, newp, BYTE_ORDER));
501 case HW_PHYSMEM:
502 return (sysctl_rdint(oldp, oldlenp, newp, mem_size));
503 case HW_USERMEM:
504 return (sysctl_rdint(oldp, oldlenp, newp,
505 (mem_size - vm_page_wire_count * page_size)));
506 case HW_PAGESIZE:
507 return (sysctl_rdint(oldp, oldlenp, newp, page_size));
508 case HW_EPOCH:
509 epochTemp = PEGetPlatformEpoch();
510 if (epochTemp == -1) return(EINVAL);
511 return (sysctl_rdint(oldp, oldlenp, newp, epochTemp));
512 case HW_BUS_FREQ:
513 return (sysctl_rdint(oldp, oldlenp, newp, gPEClockFrequencyInfo.bus_clock_rate_hz));
514 case HW_CPU_FREQ:
515 return (sysctl_rdint(oldp, oldlenp, newp, gPEClockFrequencyInfo.cpu_clock_rate_hz));
516 #if __ppc__
517 case HW_VECTORUNIT:
518 return (sysctl_rdint(oldp, oldlenp, newp, cpu_info.vector_unit));
519 case HW_CACHELINE:
520 return (sysctl_rdint(oldp, oldlenp, newp, cpu_info.cache_line_size));
521 case HW_L1ICACHESIZE:
522 return (sysctl_rdint(oldp, oldlenp, newp, cpu_info.l1_icache_size));
523 case HW_L1DCACHESIZE:
524 return (sysctl_rdint(oldp, oldlenp, newp, cpu_info.l1_dcache_size));
525 case HW_L2SETTINGS:
526 if (cpu_info.l2_cache_size == 0xFFFFFFFF) return(EINVAL);
527 return (sysctl_rdint(oldp, oldlenp, newp, cpu_info.l2_settings));
528 case HW_L2CACHESIZE:
529 if (cpu_info.l2_cache_size == 0xFFFFFFFF) return(EINVAL);
530 return (sysctl_rdint(oldp, oldlenp, newp, cpu_info.l2_cache_size));
531 case HW_L3SETTINGS:
532 if (cpu_info.l3_cache_size == 0xFFFFFFFF) return(EINVAL);
533 return (sysctl_rdint(oldp, oldlenp, newp, cpu_info.l3_settings));
534 case HW_L3CACHESIZE:
535 if (cpu_info.l3_cache_size == 0xFFFFFFFF) return(EINVAL);
536 return (sysctl_rdint(oldp, oldlenp, newp, cpu_info.l3_cache_size));
537 #endif
538 default:
539 return (EOPNOTSUPP);
540 }
541 }
542
543 #ifdef DEBUG
544 /*
545 * Debugging related system variables.
546 */
547 #if DIAGNOSTIC
548 extern
549 #endif /* DIAGNOSTIC */
550 struct ctldebug debug0, debug1;
551 struct ctldebug debug2, debug3, debug4;
552 struct ctldebug debug5, debug6, debug7, debug8, debug9;
553 struct ctldebug debug10, debug11, debug12, debug13, debug14;
554 struct ctldebug debug15, debug16, debug17, debug18, debug19;
555 static struct ctldebug *debugvars[CTL_DEBUG_MAXID] = {
556 &debug0, &debug1, &debug2, &debug3, &debug4,
557 &debug5, &debug6, &debug7, &debug8, &debug9,
558 &debug10, &debug11, &debug12, &debug13, &debug14,
559 &debug15, &debug16, &debug17, &debug18, &debug19,
560 };
561 int
562 debug_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
563 int *name;
564 u_int namelen;
565 void *oldp;
566 size_t *oldlenp;
567 void *newp;
568 size_t newlen;
569 struct proc *p;
570 {
571 struct ctldebug *cdp;
572
573 /* all sysctl names at this level are name and field */
574 if (namelen != 2)
575 return (ENOTDIR); /* overloaded */
576 cdp = debugvars[name[0]];
577 if (cdp->debugname == 0)
578 return (EOPNOTSUPP);
579 switch (name[1]) {
580 case CTL_DEBUG_NAME:
581 return (sysctl_rdstring(oldp, oldlenp, newp, cdp->debugname));
582 case CTL_DEBUG_VALUE:
583 return (sysctl_int(oldp, oldlenp, newp, newlen, cdp->debugvar));
584 default:
585 return (EOPNOTSUPP);
586 }
587 /* NOTREACHED */
588 }
589 #endif /* DEBUG */
590
591 /*
592 * Validate parameters and get old / set new parameters
593 * for an integer-valued sysctl function.
594 */
595 sysctl_int(oldp, oldlenp, newp, newlen, valp)
596 void *oldp;
597 size_t *oldlenp;
598 void *newp;
599 size_t newlen;
600 int *valp;
601 {
602 int error = 0;
603
604 if (oldp && *oldlenp < sizeof(int))
605 return (ENOMEM);
606 if (newp && newlen != sizeof(int))
607 return (EINVAL);
608 *oldlenp = sizeof(int);
609 if (oldp)
610 error = copyout(valp, oldp, sizeof(int));
611 if (error == 0 && newp)
612 error = copyin(newp, valp, sizeof(int));
613 return (error);
614 }
615
616 /*
617 * As above, but read-only.
618 */
619 sysctl_rdint(oldp, oldlenp, newp, val)
620 void *oldp;
621 size_t *oldlenp;
622 void *newp;
623 int val;
624 {
625 int error = 0;
626
627 if (oldp && *oldlenp < sizeof(int))
628 return (ENOMEM);
629 if (newp)
630 return (EPERM);
631 *oldlenp = sizeof(int);
632 if (oldp)
633 error = copyout((caddr_t)&val, oldp, sizeof(int));
634 return (error);
635 }
636
637 /*
638 * Validate parameters and get old / set new parameters
639 * for a string-valued sysctl function.
640 */
641 sysctl_string(oldp, oldlenp, newp, newlen, str, maxlen)
642 void *oldp;
643 size_t *oldlenp;
644 void *newp;
645 size_t newlen;
646 char *str;
647 int maxlen;
648 {
649 int len, error = 0;
650
651 len = strlen(str) + 1;
652 if (oldp && *oldlenp < len)
653 return (ENOMEM);
654 if (newp && newlen >= maxlen)
655 return (EINVAL);
656 if (oldp) {
657 *oldlenp = len;
658 error = copyout(str, oldp, len);
659 }
660 if (error == 0 && newp) {
661 error = copyin(newp, str, newlen);
662 str[newlen] = 0;
663 }
664 return (error);
665 }
666
667 /*
668 * As above, but read-only.
669 */
670 sysctl_rdstring(oldp, oldlenp, newp, str)
671 void *oldp;
672 size_t *oldlenp;
673 void *newp;
674 char *str;
675 {
676 int len, error = 0;
677
678 len = strlen(str) + 1;
679 if (oldp && *oldlenp < len)
680 return (ENOMEM);
681 if (newp)
682 return (EPERM);
683 *oldlenp = len;
684 if (oldp)
685 error = copyout(str, oldp, len);
686 return (error);
687 }
688
689 /*
690 * Validate parameters and get old / set new parameters
691 * for a structure oriented sysctl function.
692 */
693 sysctl_struct(oldp, oldlenp, newp, newlen, sp, len)
694 void *oldp;
695 size_t *oldlenp;
696 void *newp;
697 size_t newlen;
698 void *sp;
699 int len;
700 {
701 int error = 0;
702
703 if (oldp && *oldlenp < len)
704 return (ENOMEM);
705 if (newp && newlen > len)
706 return (EINVAL);
707 if (oldp) {
708 *oldlenp = len;
709 error = copyout(sp, oldp, len);
710 }
711 if (error == 0 && newp)
712 error = copyin(newp, sp, len);
713 return (error);
714 }
715
716 /*
717 * Validate parameters and get old parameters
718 * for a structure oriented sysctl function.
719 */
720 sysctl_rdstruct(oldp, oldlenp, newp, sp, len)
721 void *oldp;
722 size_t *oldlenp;
723 void *newp, *sp;
724 int len;
725 {
726 int error = 0;
727
728 if (oldp && *oldlenp < len)
729 return (ENOMEM);
730 if (newp)
731 return (EPERM);
732 *oldlenp = len;
733 if (oldp)
734 error = copyout(sp, oldp, len);
735 return (error);
736 }
737
738 /*
739 * Get file structures.
740 */
741 sysctl_file(where, sizep)
742 char *where;
743 size_t *sizep;
744 {
745 int buflen, error;
746 struct file *fp;
747 char *start = where;
748
749 buflen = *sizep;
750 if (where == NULL) {
751 /*
752 * overestimate by 10 files
753 */
754 *sizep = sizeof(filehead) + (nfiles + 10) * sizeof(struct file);
755 return (0);
756 }
757
758 /*
759 * first copyout filehead
760 */
761 if (buflen < sizeof(filehead)) {
762 *sizep = 0;
763 return (0);
764 }
765 if (error = copyout((caddr_t)&filehead, where, sizeof(filehead)))
766 return (error);
767 buflen -= sizeof(filehead);
768 where += sizeof(filehead);
769
770 /*
771 * followed by an array of file structures
772 */
773 for (fp = filehead.lh_first; fp != 0; fp = fp->f_list.le_next) {
774 if (buflen < sizeof(struct file)) {
775 *sizep = where - start;
776 return (ENOMEM);
777 }
778 if (error = copyout((caddr_t)fp, where, sizeof (struct file)))
779 return (error);
780 buflen -= sizeof(struct file);
781 where += sizeof(struct file);
782 }
783 *sizep = where - start;
784 return (0);
785 }
786
787 /*
788 * try over estimating by 5 procs
789 */
790 #define KERN_PROCSLOP (5 * sizeof (struct kinfo_proc))
791
792 sysctl_doproc(name, namelen, where, sizep)
793 int *name;
794 u_int namelen;
795 char *where;
796 size_t *sizep;
797 {
798 register struct proc *p;
799 register struct kinfo_proc *dp = (struct kinfo_proc *)where;
800 register int needed = 0;
801 int buflen = where != NULL ? *sizep : 0;
802 int doingzomb;
803 struct kinfo_proc kproc;
804 int error = 0;
805
806 if (namelen != 2 && !(namelen == 1 && name[0] == KERN_PROC_ALL))
807 return (EINVAL);
808 p = allproc.lh_first;
809 doingzomb = 0;
810 again:
811 for (; p != 0; p = p->p_list.le_next) {
812 /*
813 * Skip embryonic processes.
814 */
815 if (p->p_stat == SIDL)
816 continue;
817 /*
818 * TODO - make more efficient (see notes below).
819 * do by session.
820 */
821 switch (name[0]) {
822
823 case KERN_PROC_PID:
824 /* could do this with just a lookup */
825 if (p->p_pid != (pid_t)name[1])
826 continue;
827 break;
828
829 case KERN_PROC_PGRP:
830 /* could do this by traversing pgrp */
831 if (p->p_pgrp->pg_id != (pid_t)name[1])
832 continue;
833 break;
834
835 case KERN_PROC_TTY:
836 if ( doingzomb || (p->p_flag & P_CONTROLT) == 0 ||
837 p->p_session->s_ttyp == NULL ||
838 p->p_session->s_ttyp->t_dev != (dev_t)name[1])
839 continue;
840 break;
841
842 case KERN_PROC_UID:
843 if (doingzomb || (p->p_ucred->cr_uid != (uid_t)name[1]))
844 continue;
845 break;
846
847 case KERN_PROC_RUID:
848 if ( doingzomb || (p->p_cred->p_ruid != (uid_t)name[1]))
849 continue;
850 break;
851 }
852 if (buflen >= sizeof(struct kinfo_proc)) {
853 bzero(&kproc, sizeof(struct kinfo_proc));
854 fill_proc(p, &kproc, doingzomb);
855 if (error = copyout((caddr_t)&kproc, &dp->kp_proc,
856 sizeof(struct kinfo_proc)))
857 return (error);
858 dp++;
859 buflen -= sizeof(struct kinfo_proc);
860 }
861 needed += sizeof(struct kinfo_proc);
862 }
863 if (doingzomb == 0) {
864 p = zombproc.lh_first;
865 doingzomb++;
866 goto again;
867 }
868 if (where != NULL) {
869 *sizep = (caddr_t)dp - where;
870 if (needed > *sizep)
871 return (ENOMEM);
872 } else {
873 needed += KERN_PROCSLOP;
874 *sizep = needed;
875 }
876 return (0);
877 }
878
879 void
880 fill_proc(p,kp, doingzomb)
881 register struct proc *p;
882 register struct kinfo_proc *kp;
883 int doingzomb;
884 {
885 fill_externproc(p, &kp->kp_proc);
886 if (!doingzomb)
887 fill_eproc(p, &kp->kp_eproc);
888 }
889 /*
890 * Fill in an eproc structure for the specified process.
891 */
892 void
893 fill_eproc(p, ep)
894 register struct proc *p;
895 register struct eproc *ep;
896 {
897 register struct tty *tp;
898
899 /*
900 * Skip zombie processes.
901 */
902 if (p->p_stat == SZOMB)
903 return;
904
905 ep->e_paddr = p;
906 ep->e_sess = p->p_pgrp->pg_session;
907 ep->e_pcred = *p->p_cred;
908 ep->e_ucred = *p->p_ucred;
909 if (p->p_stat == SIDL || p->p_stat == SZOMB) {
910 ep->e_vm.vm_rssize = 0;
911 ep->e_vm.vm_tsize = 0;
912 ep->e_vm.vm_dsize = 0;
913 ep->e_vm.vm_ssize = 0;
914 /* ep->e_vm.vm_pmap = XXX; */
915 } else {
916 #if FIXME /* [ */
917 register vm_map_t vm = ((task_t)p->task)->map;
918
919 ep->e_vm.vm_rssize = pmap_resident_count(vm->pmap); /*XXX*/
920 // ep->e_vm.vm_tsize = vm->vm_tsize;
921 // ep->e_vm.vm_dsize = vm->vm_dsize;
922 // ep->e_vm.vm_ssize = vm->vm_ssize;
923 #else /* FIXME ][ */
924 ep->e_vm.vm_rssize = 0; /*XXX*/
925 #endif /* FIXME ] */
926 }
927 if (p->p_pptr)
928 ep->e_ppid = p->p_pptr->p_pid;
929 else
930 ep->e_ppid = 0;
931 ep->e_pgid = p->p_pgrp->pg_id;
932 ep->e_jobc = p->p_pgrp->pg_jobc;
933 if ((p->p_flag & P_CONTROLT) &&
934 (tp = ep->e_sess->s_ttyp)) {
935 ep->e_tdev = tp->t_dev;
936 ep->e_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
937 ep->e_tsess = tp->t_session;
938 } else
939 ep->e_tdev = NODEV;
940 ep->e_flag = ep->e_sess->s_ttyvp ? EPROC_CTTY : 0;
941 if (SESS_LEADER(p))
942 ep->e_flag |= EPROC_SLEADER;
943 if (p->p_wmesg)
944 strncpy(ep->e_wmesg, p->p_wmesg, WMESGLEN);
945 ep->e_xsize = ep->e_xrssize = 0;
946 ep->e_xccount = ep->e_xswrss = 0;
947 }
948 /*
949 * Fill in an eproc structure for the specified process.
950 */
951 void
952 fill_externproc(p, exp)
953 register struct proc *p;
954 register struct extern_proc *exp;
955 {
956 exp->p_forw = exp->p_back = NULL;
957 exp->p_vmspace = NULL;
958 exp->p_sigacts = p->p_sigacts;
959 exp->p_flag = p->p_flag;
960 exp->p_stat = p->p_stat ;
961 exp->p_pid = p->p_pid ;
962 exp->p_oppid = p->p_oppid ;
963 exp->p_dupfd = p->p_dupfd ;
964 /* Mach related */
965 exp->user_stack = p->user_stack ;
966 exp->exit_thread = p->exit_thread ;
967 exp->p_debugger = p->p_debugger ;
968 exp->sigwait = p->sigwait ;
969 /* scheduling */
970 exp->p_estcpu = p->p_estcpu ;
971 exp->p_cpticks = p->p_cpticks ;
972 exp->p_pctcpu = p->p_pctcpu ;
973 exp->p_wchan = p->p_wchan ;
974 exp->p_wmesg = p->p_wmesg ;
975 exp->p_swtime = p->p_swtime ;
976 exp->p_slptime = p->p_slptime ;
977 bcopy(&p->p_realtimer, &exp->p_realtimer,sizeof(struct itimerval));
978 bcopy(&p->p_rtime, &exp->p_rtime,sizeof(struct timeval));
979 exp->p_uticks = p->p_uticks ;
980 exp->p_sticks = p->p_sticks ;
981 exp->p_iticks = p->p_iticks ;
982 exp->p_traceflag = p->p_traceflag ;
983 exp->p_tracep = p->p_tracep ;
984 exp->p_siglist = p->p_siglist ;
985 exp->p_textvp = p->p_textvp ;
986 exp->p_holdcnt = 0 ;
987 exp->p_sigmask = p->p_sigmask ;
988 exp->p_sigignore = p->p_sigignore ;
989 exp->p_sigcatch = p->p_sigcatch ;
990 exp->p_priority = p->p_priority ;
991 exp->p_usrpri = p->p_usrpri ;
992 exp->p_nice = p->p_nice ;
993 bcopy(&p->p_comm, &exp->p_comm,MAXCOMLEN);
994 exp->p_comm[MAXCOMLEN] = '\0';
995 exp->p_pgrp = p->p_pgrp ;
996 exp->p_addr = NULL;
997 exp->p_xstat = p->p_xstat ;
998 exp->p_acflag = p->p_acflag ;
999 exp->p_ru = p->p_ru ;
1000 }
1001
1002 kdebug_ops(name, namelen, where, sizep, p)
1003 int *name;
1004 u_int namelen;
1005 char *where;
1006 size_t *sizep;
1007 struct proc *p;
1008 {
1009 int size=*sizep;
1010 int ret=0;
1011 extern int kdbg_control(int *name, u_int namelen, char * where,size_t * sizep);
1012
1013 if (ret = suser(p->p_ucred, &p->p_acflag))
1014 return(ret);
1015
1016 switch(name[0]) {
1017 case KERN_KDEFLAGS:
1018 case KERN_KDDFLAGS:
1019 case KERN_KDENABLE:
1020 case KERN_KDGETBUF:
1021 case KERN_KDSETUP:
1022 case KERN_KDREMOVE:
1023 case KERN_KDSETREG:
1024 case KERN_KDGETREG:
1025 case KERN_KDREADTR:
1026 case KERN_KDPIDTR:
1027 case KERN_KDTHRMAP:
1028 case KERN_KDPIDEX:
1029 case KERN_KDSETRTCDEC:
1030 case KERN_KDSETBUF:
1031 ret = kdbg_control(name, namelen, where, sizep);
1032 break;
1033 default:
1034 ret= EOPNOTSUPP;
1035 break;
1036 }
1037 return(ret);
1038 }
1039
1040 pcsamples_ops(name, namelen, where, sizep, p)
1041 int *name;
1042 u_int namelen;
1043 char *where;
1044 size_t *sizep;
1045 struct proc *p;
1046 {
1047 int ret=0;
1048 extern int pcsamples_control(int *name, u_int namelen, char * where,size_t * sizep);
1049
1050 if (ret = suser(p->p_ucred, &p->p_acflag))
1051 return(ret);
1052
1053 switch(name[0]) {
1054 case KERN_PCDISABLE:
1055 case KERN_PCGETBUF:
1056 case KERN_PCSETUP:
1057 case KERN_PCREMOVE:
1058 case KERN_PCREADBUF:
1059 case KERN_PCSETREG:
1060 case KERN_PCSETBUF:
1061 case KERN_PCCOMM:
1062 ret = pcsamples_control(name, namelen, where, sizep);
1063 break;
1064 default:
1065 ret= EOPNOTSUPP;
1066 break;
1067 }
1068 return(ret);
1069 }
1070
1071 /*
1072 * Returns the top N bytes of the user stack, with
1073 * everything below the first argument character
1074 * zeroed for security reasons.
1075 * Odd data structure is for compatibility.
1076 */
1077 sysctl_procargs(name, namelen, where, sizep)
1078 int *name;
1079 u_int namelen;
1080 char *where;
1081 size_t *sizep;
1082 {
1083 register struct proc *p;
1084 register int needed = 0;
1085 int buflen = where != NULL ? *sizep : 0;
1086 int error = 0;
1087 struct vm_map *proc_map;
1088 struct task * task;
1089 vm_map_copy_t tmp;
1090 vm_offset_t arg_addr;
1091 vm_size_t arg_size;
1092 caddr_t data;
1093 unsigned size;
1094 vm_offset_t copy_start, copy_end;
1095 vm_offset_t dealloc_start; /* area to remove from kernel map */
1096 vm_offset_t dealloc_end;
1097 int *ip;
1098 kern_return_t ret;
1099 int pid;
1100
1101
1102 if ((buflen <= 0) || (buflen > (PAGE_SIZE << 1))) {
1103 return(EINVAL);
1104 }
1105 arg_size = buflen;
1106
1107 /*
1108 * Lookup process by pid
1109 */
1110 pid = name[0];
1111
1112 restart:
1113 p = pfind(pid);
1114 if (p == NULL) {
1115 return(EINVAL);
1116 }
1117
1118 /*
1119 * Copy the top N bytes of the stack.
1120 * On all machines we have so far, the stack grows
1121 * downwards.
1122 *
1123 * If the user expects no more than N bytes of
1124 * argument list, use that as a guess for the
1125 * size.
1126 */
1127
1128 if (!p->user_stack)
1129 return(EINVAL);
1130
1131 arg_addr = (vm_offset_t)(p->user_stack - arg_size);
1132
1133
1134 /*
1135 * Before we can block (any VM code), make another
1136 * reference to the map to keep it alive. We do
1137 * that by getting a reference on the task itself.
1138 */
1139 task = p->task;
1140 if (task == NULL)
1141 return(EINVAL);
1142
1143 /*
1144 * A regular task_reference call can block, causing the funnel
1145 * to be dropped and allowing the proc/task to get freed.
1146 * Instead, we issue a non-blocking attempt at the task reference,
1147 * and look up the proc/task all over again if that fails.
1148 */
1149 if (!task_reference_try(task)) {
1150 mutex_pause();
1151 goto restart;
1152 }
1153
1154 ret = kmem_alloc(kernel_map, &copy_start, round_page(arg_size));
1155 if (ret != KERN_SUCCESS) {
1156 task_deallocate(task);
1157 return(ENOMEM);
1158 }
1159
1160 proc_map = get_task_map(task);
1161 copy_end = round_page(copy_start + arg_size);
1162
1163 if( vm_map_copyin(proc_map, trunc_page(arg_addr), round_page(arg_size),
1164 FALSE, &tmp) != KERN_SUCCESS) {
1165 task_deallocate(task);
1166 kmem_free(kernel_map, copy_start,
1167 round_page(arg_size));
1168 return (EIO);
1169 }
1170
1171 /*
1172 * Now that we've done the copyin from the process'
1173 * map, we can release the reference to it.
1174 */
1175 task_deallocate(task);
1176
1177 if( vm_map_copy_overwrite(kernel_map, copy_start,
1178 tmp, FALSE) != KERN_SUCCESS) {
1179 kmem_free(kernel_map, copy_start,
1180 round_page(arg_size));
1181 return (EIO);
1182 }
1183
1184 data = (caddr_t) (copy_end - arg_size);
1185 ip = (int *) copy_end;
1186 size = arg_size;
1187
1188 /*
1189 * Now look down the stack for the bottom of the
1190 * argument list. Since this call is otherwise
1191 * unprotected, we can't let the nosy user see
1192 * anything else on the stack.
1193 *
1194 * The arguments are pushed on the stack by
1195 * execve() as:
1196 *
1197 * .long 0
1198 * arg 0 (null-terminated)
1199 * arg 1
1200 * ...
1201 * arg N
1202 * .long 0
1203 *
1204 */
1205
1206 ip -= 2; /*skip trailing 0 word and assume at least one
1207 argument. The last word of argN may be just
1208 the trailing 0, in which case we'd stop
1209 there */
1210 while (*--ip)
1211 if (ip == (int *)data)
1212 break;
1213 /*
1214 * To account for saved path name and not having a null after that
1215 * Run the sweep again. If we have already sweeped entire range skip this
1216 */
1217 if (ip != (int *)data) {
1218 while (*--ip)
1219 if (ip == (int *)data)
1220 break;
1221 }
1222
1223 bzero(data, (unsigned) ((int)ip - (int)data));
1224
1225 dealloc_start = copy_start;
1226 dealloc_end = copy_end;
1227
1228
1229 size = MIN(size, buflen);
1230 error = copyout(data, where, size);
1231
1232 if (dealloc_start != (vm_offset_t) 0) {
1233 kmem_free(kernel_map, dealloc_start,
1234 dealloc_end - dealloc_start);
1235 }
1236 if (error) {
1237 return(error);
1238 }
1239
1240 if (where != NULL)
1241 *sizep = size;
1242 return (0);
1243 }