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