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