]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/kern_sysctl.c
xnu-344.26.tar.gz
[apple/xnu.git] / bsd / kern / kern_sysctl.c
CommitLineData
1c79356b 1/*
9bccf70c 2 * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
1c79356b
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
de355530
A
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.
1c79356b 11 *
de355530
A
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
1c79356b
A
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
de355530
A
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.
1c79356b
A
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>
9bccf70c 79#include <sys/user.h>
1c79356b
A
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__
9bccf70c 96#include <ppc/machine_routines.h>
1c79356b
A
97#endif
98
99sysctlfn kern_sysctl;
de355530 100sysctlfn hw_sysctl;
1c79356b
A
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 */
9bccf70c 125int
1c79356b
A
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{
9bccf70c 135 extern uint32_t mach_factor[3];
1c79356b
A
136 struct loadavg loadinfo;
137
1c79356b
A
138 switch (name[0]) {
139 case VM_LOADAVG:
9bccf70c
A
140 return (sysctl_struct(oldp, oldlenp, newp, newlen,
141 &averunnable, sizeof(struct loadavg)));
1c79356b
A
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;
9bccf70c
A
147 return (sysctl_struct(oldp, oldlenp, newp, newlen,
148 &loadinfo, sizeof(struct loadavg)));
1c79356b
A
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;
0b4e3aa0 188 int error1;
1c79356b
A
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 */
9bccf70c
A
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)))
1c79356b
A
207 return (error);
208
209 switch (name[0]) {
210 case CTL_KERN:
211 fn = kern_sysctl;
0b4e3aa0
A
212 if ((name[1] != KERN_VNODE) && (name[1] != KERN_FILE)
213 && (name[1] != KERN_PROC))
1c79356b
A
214 dolock = 0;
215 break;
de355530
A
216 case CTL_HW:
217 fn = hw_sysctl;
218 break;
1c79356b
A
219 case CTL_VM:
220 fn = vm_sysctl;
221 break;
222
223 case CTL_VFS:
224 fn = vfs_sysctl;
225 break;
1c79356b
A
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 */
9bccf70c
A
244 if ((name[1] != KERN_PCSAMPLES) &&
245 (!((name[1] == KERN_KDEBUG) && (name[2] == KERN_KDGETENTROPY)))) {
1c79356b
A
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
0b4e3aa0 254 if (dolock && oldlen && (error = vslock(uap->old, oldlen))) {
9bccf70c
A
255 if ((name[1] != KERN_PCSAMPLES) &&
256 (! ((name[1] == KERN_KDEBUG) && (name[2] == KERN_KDGETENTROPY)))) {
0b4e3aa0
A
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 }
1c79356b
A
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) {
0b4e3aa0
A
280 if (dolock && savelen) {
281 error1 = vsunlock(uap->old, savelen, B_WRITE);
282 if (!error && error1)
283 error = error1;
284 }
1c79356b
A
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
9bccf70c
A
319extern int get_kernel_symfile( struct proc *, char **);
320extern int sysctl_dopanicinfo(int *, u_int, void *, size_t *,
321 void *, size_t, struct proc *);
1c79356b
A
322
323/*
324 * kernel related system variables.
325 */
9bccf70c 326int
1c79356b
A
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;
9bccf70c 338 char *str;
1c79356b 339 extern char ostype[], osrelease[], version[];
9bccf70c
A
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 )
1c79356b
A
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
1c79356b
A
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 */
9bccf70c
A
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));
1c79356b
A
447 default:
448 return (EOPNOTSUPP);
449 }
450 /* NOTREACHED */
451}
452
de355530
A
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));
90556fb8
A
520 case HW_TB_FREQ:
521 return (sysctl_rdint(oldp, oldlenp, newp, gPEClockFrequencyInfo.timebase_frequency_hz));
de355530
A
522#if __ppc__
523 case HW_VECTORUNIT:
524 return (sysctl_rdint(oldp, oldlenp, newp, cpu_info.vector_unit));
525 case HW_CACHELINE:
526 return (sysctl_rdint(oldp, oldlenp, newp, cpu_info.cache_line_size));
527 case HW_L1ICACHESIZE:
528 return (sysctl_rdint(oldp, oldlenp, newp, cpu_info.l1_icache_size));
529 case HW_L1DCACHESIZE:
530 return (sysctl_rdint(oldp, oldlenp, newp, cpu_info.l1_dcache_size));
531 case HW_L2SETTINGS:
532 if (cpu_info.l2_cache_size == 0xFFFFFFFF) return(EINVAL);
533 return (sysctl_rdint(oldp, oldlenp, newp, cpu_info.l2_settings));
534 case HW_L2CACHESIZE:
535 if (cpu_info.l2_cache_size == 0xFFFFFFFF) return(EINVAL);
536 return (sysctl_rdint(oldp, oldlenp, newp, cpu_info.l2_cache_size));
537 case HW_L3SETTINGS:
538 if (cpu_info.l3_cache_size == 0xFFFFFFFF) return(EINVAL);
539 return (sysctl_rdint(oldp, oldlenp, newp, cpu_info.l3_settings));
540 case HW_L3CACHESIZE:
541 if (cpu_info.l3_cache_size == 0xFFFFFFFF) return(EINVAL);
542 return (sysctl_rdint(oldp, oldlenp, newp, cpu_info.l3_cache_size));
543#endif
544 default:
545 return (EOPNOTSUPP);
546 }
547}
548
1c79356b
A
549#ifdef DEBUG
550/*
551 * Debugging related system variables.
552 */
553#if DIAGNOSTIC
554extern
555#endif /* DIAGNOSTIC */
556struct ctldebug debug0, debug1;
557struct ctldebug debug2, debug3, debug4;
558struct ctldebug debug5, debug6, debug7, debug8, debug9;
559struct ctldebug debug10, debug11, debug12, debug13, debug14;
560struct ctldebug debug15, debug16, debug17, debug18, debug19;
561static struct ctldebug *debugvars[CTL_DEBUG_MAXID] = {
562 &debug0, &debug1, &debug2, &debug3, &debug4,
563 &debug5, &debug6, &debug7, &debug8, &debug9,
564 &debug10, &debug11, &debug12, &debug13, &debug14,
565 &debug15, &debug16, &debug17, &debug18, &debug19,
566};
567int
568debug_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
569 int *name;
570 u_int namelen;
571 void *oldp;
572 size_t *oldlenp;
573 void *newp;
574 size_t newlen;
575 struct proc *p;
576{
577 struct ctldebug *cdp;
578
579 /* all sysctl names at this level are name and field */
580 if (namelen != 2)
581 return (ENOTDIR); /* overloaded */
582 cdp = debugvars[name[0]];
583 if (cdp->debugname == 0)
584 return (EOPNOTSUPP);
585 switch (name[1]) {
586 case CTL_DEBUG_NAME:
587 return (sysctl_rdstring(oldp, oldlenp, newp, cdp->debugname));
588 case CTL_DEBUG_VALUE:
589 return (sysctl_int(oldp, oldlenp, newp, newlen, cdp->debugvar));
590 default:
591 return (EOPNOTSUPP);
592 }
593 /* NOTREACHED */
594}
595#endif /* DEBUG */
596
597/*
598 * Validate parameters and get old / set new parameters
599 * for an integer-valued sysctl function.
600 */
9bccf70c 601int
1c79356b
A
602sysctl_int(oldp, oldlenp, newp, newlen, valp)
603 void *oldp;
604 size_t *oldlenp;
605 void *newp;
606 size_t newlen;
607 int *valp;
608{
609 int error = 0;
610
611 if (oldp && *oldlenp < sizeof(int))
612 return (ENOMEM);
613 if (newp && newlen != sizeof(int))
614 return (EINVAL);
615 *oldlenp = sizeof(int);
616 if (oldp)
617 error = copyout(valp, oldp, sizeof(int));
618 if (error == 0 && newp)
619 error = copyin(newp, valp, sizeof(int));
620 return (error);
621}
622
623/*
624 * As above, but read-only.
625 */
9bccf70c 626int
1c79356b
A
627sysctl_rdint(oldp, oldlenp, newp, val)
628 void *oldp;
629 size_t *oldlenp;
630 void *newp;
631 int val;
632{
633 int error = 0;
634
635 if (oldp && *oldlenp < sizeof(int))
636 return (ENOMEM);
637 if (newp)
638 return (EPERM);
639 *oldlenp = sizeof(int);
640 if (oldp)
641 error = copyout((caddr_t)&val, oldp, sizeof(int));
642 return (error);
643}
644
9bccf70c
A
645/*
646 * Validate parameters and get old / set new parameters
647 * for an quad(64bit)-valued sysctl function.
648 */
649int
650sysctl_quad(oldp, oldlenp, newp, newlen, valp)
651 void *oldp;
652 size_t *oldlenp;
653 void *newp;
654 size_t newlen;
655 quad_t *valp;
656{
657 int error = 0;
658
659 if (oldp && *oldlenp < sizeof(quad_t))
660 return (ENOMEM);
661 if (newp && newlen != sizeof(quad_t))
662 return (EINVAL);
663 *oldlenp = sizeof(quad_t);
664 if (oldp)
665 error = copyout(valp, oldp, sizeof(quad_t));
666 if (error == 0 && newp)
667 error = copyin(newp, valp, sizeof(quad_t));
668 return (error);
669}
670
671/*
672 * As above, but read-only.
673 */
674int
675sysctl_rdquad(oldp, oldlenp, newp, val)
676 void *oldp;
677 size_t *oldlenp;
678 void *newp;
679 quad_t val;
680{
681 int error = 0;
682
683 if (oldp && *oldlenp < sizeof(quad_t))
684 return (ENOMEM);
685 if (newp)
686 return (EPERM);
687 *oldlenp = sizeof(quad_t);
688 if (oldp)
689 error = copyout((caddr_t)&val, oldp, sizeof(quad_t));
690 return (error);
691}
692
1c79356b
A
693/*
694 * Validate parameters and get old / set new parameters
695 * for a string-valued sysctl function.
696 */
9bccf70c 697int
1c79356b
A
698sysctl_string(oldp, oldlenp, newp, newlen, str, maxlen)
699 void *oldp;
700 size_t *oldlenp;
701 void *newp;
702 size_t newlen;
703 char *str;
704 int maxlen;
705{
706 int len, error = 0;
707
708 len = strlen(str) + 1;
709 if (oldp && *oldlenp < len)
710 return (ENOMEM);
711 if (newp && newlen >= maxlen)
712 return (EINVAL);
9bccf70c 713 *oldlenp = len -1; /* deal with NULL strings correctly */
1c79356b 714 if (oldp) {
1c79356b
A
715 error = copyout(str, oldp, len);
716 }
717 if (error == 0 && newp) {
718 error = copyin(newp, str, newlen);
719 str[newlen] = 0;
720 }
721 return (error);
722}
723
724/*
725 * As above, but read-only.
726 */
9bccf70c 727int
1c79356b
A
728sysctl_rdstring(oldp, oldlenp, newp, str)
729 void *oldp;
730 size_t *oldlenp;
731 void *newp;
732 char *str;
733{
734 int len, error = 0;
735
736 len = strlen(str) + 1;
737 if (oldp && *oldlenp < len)
738 return (ENOMEM);
739 if (newp)
740 return (EPERM);
741 *oldlenp = len;
742 if (oldp)
743 error = copyout(str, oldp, len);
744 return (error);
745}
746
747/*
748 * Validate parameters and get old / set new parameters
749 * for a structure oriented sysctl function.
750 */
9bccf70c 751int
1c79356b
A
752sysctl_struct(oldp, oldlenp, newp, newlen, sp, len)
753 void *oldp;
754 size_t *oldlenp;
755 void *newp;
756 size_t newlen;
757 void *sp;
758 int len;
759{
760 int error = 0;
761
762 if (oldp && *oldlenp < len)
763 return (ENOMEM);
764 if (newp && newlen > len)
765 return (EINVAL);
766 if (oldp) {
767 *oldlenp = len;
768 error = copyout(sp, oldp, len);
769 }
770 if (error == 0 && newp)
771 error = copyin(newp, sp, len);
772 return (error);
773}
774
775/*
776 * Validate parameters and get old parameters
777 * for a structure oriented sysctl function.
778 */
9bccf70c 779int
1c79356b
A
780sysctl_rdstruct(oldp, oldlenp, newp, sp, len)
781 void *oldp;
782 size_t *oldlenp;
783 void *newp, *sp;
784 int len;
785{
786 int error = 0;
787
788 if (oldp && *oldlenp < len)
789 return (ENOMEM);
790 if (newp)
791 return (EPERM);
792 *oldlenp = len;
793 if (oldp)
794 error = copyout(sp, oldp, len);
795 return (error);
796}
797
798/*
799 * Get file structures.
800 */
9bccf70c 801int
1c79356b
A
802sysctl_file(where, sizep)
803 char *where;
804 size_t *sizep;
805{
806 int buflen, error;
807 struct file *fp;
808 char *start = where;
809
810 buflen = *sizep;
811 if (where == NULL) {
812 /*
813 * overestimate by 10 files
814 */
815 *sizep = sizeof(filehead) + (nfiles + 10) * sizeof(struct file);
816 return (0);
817 }
818
819 /*
820 * first copyout filehead
821 */
822 if (buflen < sizeof(filehead)) {
823 *sizep = 0;
824 return (0);
825 }
826 if (error = copyout((caddr_t)&filehead, where, sizeof(filehead)))
827 return (error);
828 buflen -= sizeof(filehead);
829 where += sizeof(filehead);
830
831 /*
832 * followed by an array of file structures
833 */
834 for (fp = filehead.lh_first; fp != 0; fp = fp->f_list.le_next) {
835 if (buflen < sizeof(struct file)) {
836 *sizep = where - start;
837 return (ENOMEM);
838 }
839 if (error = copyout((caddr_t)fp, where, sizeof (struct file)))
840 return (error);
841 buflen -= sizeof(struct file);
842 where += sizeof(struct file);
843 }
844 *sizep = where - start;
845 return (0);
846}
847
848/*
849 * try over estimating by 5 procs
850 */
851#define KERN_PROCSLOP (5 * sizeof (struct kinfo_proc))
852
9bccf70c 853int
1c79356b
A
854sysctl_doproc(name, namelen, where, sizep)
855 int *name;
856 u_int namelen;
857 char *where;
858 size_t *sizep;
859{
860 register struct proc *p;
861 register struct kinfo_proc *dp = (struct kinfo_proc *)where;
862 register int needed = 0;
863 int buflen = where != NULL ? *sizep : 0;
864 int doingzomb;
865 struct kinfo_proc kproc;
866 int error = 0;
867
868 if (namelen != 2 && !(namelen == 1 && name[0] == KERN_PROC_ALL))
869 return (EINVAL);
870 p = allproc.lh_first;
871 doingzomb = 0;
872again:
873 for (; p != 0; p = p->p_list.le_next) {
874 /*
875 * Skip embryonic processes.
876 */
877 if (p->p_stat == SIDL)
878 continue;
879 /*
880 * TODO - make more efficient (see notes below).
881 * do by session.
882 */
883 switch (name[0]) {
884
885 case KERN_PROC_PID:
886 /* could do this with just a lookup */
887 if (p->p_pid != (pid_t)name[1])
888 continue;
889 break;
890
891 case KERN_PROC_PGRP:
892 /* could do this by traversing pgrp */
893 if (p->p_pgrp->pg_id != (pid_t)name[1])
894 continue;
895 break;
896
897 case KERN_PROC_TTY:
898 if ( doingzomb || (p->p_flag & P_CONTROLT) == 0 ||
899 p->p_session->s_ttyp == NULL ||
900 p->p_session->s_ttyp->t_dev != (dev_t)name[1])
901 continue;
902 break;
903
904 case KERN_PROC_UID:
905 if (doingzomb || (p->p_ucred->cr_uid != (uid_t)name[1]))
906 continue;
907 break;
908
909 case KERN_PROC_RUID:
910 if ( doingzomb || (p->p_cred->p_ruid != (uid_t)name[1]))
911 continue;
912 break;
913 }
914 if (buflen >= sizeof(struct kinfo_proc)) {
e7c99d92 915 bzero(&kproc, sizeof(struct kinfo_proc));
1c79356b
A
916 fill_proc(p, &kproc, doingzomb);
917 if (error = copyout((caddr_t)&kproc, &dp->kp_proc,
918 sizeof(struct kinfo_proc)))
919 return (error);
920 dp++;
921 buflen -= sizeof(struct kinfo_proc);
922 }
923 needed += sizeof(struct kinfo_proc);
924 }
925 if (doingzomb == 0) {
926 p = zombproc.lh_first;
927 doingzomb++;
928 goto again;
929 }
930 if (where != NULL) {
931 *sizep = (caddr_t)dp - where;
932 if (needed > *sizep)
933 return (ENOMEM);
934 } else {
935 needed += KERN_PROCSLOP;
936 *sizep = needed;
937 }
938 return (0);
939}
940
941void
942fill_proc(p,kp, doingzomb)
943 register struct proc *p;
944 register struct kinfo_proc *kp;
945 int doingzomb;
946{
947 fill_externproc(p, &kp->kp_proc);
948 if (!doingzomb)
949 fill_eproc(p, &kp->kp_eproc);
950}
951/*
952 * Fill in an eproc structure for the specified process.
953 */
954void
955fill_eproc(p, ep)
956 register struct proc *p;
957 register struct eproc *ep;
958{
959 register struct tty *tp;
960
e7c99d92
A
961 /*
962 * Skip zombie processes.
963 */
964 if (p->p_stat == SZOMB)
965 return;
966
1c79356b
A
967 ep->e_paddr = p;
968 ep->e_sess = p->p_pgrp->pg_session;
969 ep->e_pcred = *p->p_cred;
970 ep->e_ucred = *p->p_ucred;
971 if (p->p_stat == SIDL || p->p_stat == SZOMB) {
1c79356b
A
972 ep->e_vm.vm_tsize = 0;
973 ep->e_vm.vm_dsize = 0;
974 ep->e_vm.vm_ssize = 0;
1c79356b 975 }
9bccf70c 976 ep->e_vm.vm_rssize = 0;
1c79356b
A
977 if (p->p_pptr)
978 ep->e_ppid = p->p_pptr->p_pid;
979 else
980 ep->e_ppid = 0;
981 ep->e_pgid = p->p_pgrp->pg_id;
982 ep->e_jobc = p->p_pgrp->pg_jobc;
983 if ((p->p_flag & P_CONTROLT) &&
984 (tp = ep->e_sess->s_ttyp)) {
985 ep->e_tdev = tp->t_dev;
986 ep->e_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
987 ep->e_tsess = tp->t_session;
988 } else
989 ep->e_tdev = NODEV;
990 ep->e_flag = ep->e_sess->s_ttyvp ? EPROC_CTTY : 0;
991 if (SESS_LEADER(p))
992 ep->e_flag |= EPROC_SLEADER;
993 if (p->p_wmesg)
994 strncpy(ep->e_wmesg, p->p_wmesg, WMESGLEN);
995 ep->e_xsize = ep->e_xrssize = 0;
996 ep->e_xccount = ep->e_xswrss = 0;
997}
998/*
999 * Fill in an eproc structure for the specified process.
1000 */
1001void
1002fill_externproc(p, exp)
1003 register struct proc *p;
1004 register struct extern_proc *exp;
1005{
1006 exp->p_forw = exp->p_back = NULL;
9bccf70c
A
1007 if (p->p_stats)
1008 exp->p_starttime = p->p_stats->p_start;
1c79356b
A
1009 exp->p_vmspace = NULL;
1010 exp->p_sigacts = p->p_sigacts;
1011 exp->p_flag = p->p_flag;
1012 exp->p_stat = p->p_stat ;
1013 exp->p_pid = p->p_pid ;
1014 exp->p_oppid = p->p_oppid ;
1015 exp->p_dupfd = p->p_dupfd ;
1016 /* Mach related */
1017 exp->user_stack = p->user_stack ;
1018 exp->exit_thread = p->exit_thread ;
1019 exp->p_debugger = p->p_debugger ;
1020 exp->sigwait = p->sigwait ;
1021 /* scheduling */
1022 exp->p_estcpu = p->p_estcpu ;
1023 exp->p_cpticks = p->p_cpticks ;
1024 exp->p_pctcpu = p->p_pctcpu ;
1025 exp->p_wchan = p->p_wchan ;
1026 exp->p_wmesg = p->p_wmesg ;
1027 exp->p_swtime = p->p_swtime ;
1028 exp->p_slptime = p->p_slptime ;
1029 bcopy(&p->p_realtimer, &exp->p_realtimer,sizeof(struct itimerval));
1030 bcopy(&p->p_rtime, &exp->p_rtime,sizeof(struct timeval));
1031 exp->p_uticks = p->p_uticks ;
1032 exp->p_sticks = p->p_sticks ;
1033 exp->p_iticks = p->p_iticks ;
1034 exp->p_traceflag = p->p_traceflag ;
1035 exp->p_tracep = p->p_tracep ;
9bccf70c 1036 exp->p_siglist = 0 ; /* No longer relevant */
1c79356b
A
1037 exp->p_textvp = p->p_textvp ;
1038 exp->p_holdcnt = 0 ;
9bccf70c 1039 exp->p_sigmask = 0 ; /* no longer avaialable */
1c79356b
A
1040 exp->p_sigignore = p->p_sigignore ;
1041 exp->p_sigcatch = p->p_sigcatch ;
1042 exp->p_priority = p->p_priority ;
1043 exp->p_usrpri = p->p_usrpri ;
1044 exp->p_nice = p->p_nice ;
1045 bcopy(&p->p_comm, &exp->p_comm,MAXCOMLEN);
1046 exp->p_comm[MAXCOMLEN] = '\0';
1047 exp->p_pgrp = p->p_pgrp ;
1048 exp->p_addr = NULL;
1049 exp->p_xstat = p->p_xstat ;
1050 exp->p_acflag = p->p_acflag ;
1051 exp->p_ru = p->p_ru ;
1052}
1053
9bccf70c 1054int
1c79356b
A
1055kdebug_ops(name, namelen, where, sizep, p)
1056int *name;
1057u_int namelen;
1058char *where;
1059size_t *sizep;
1060struct proc *p;
1061{
9bccf70c
A
1062 int size=*sizep;
1063 int ret=0;
1064 extern int kdbg_control(int *name, u_int namelen,
1065 char * where,size_t * sizep);
1c79356b 1066
9bccf70c
A
1067 if (ret = suser(p->p_ucred, &p->p_acflag))
1068 return(ret);
1c79356b
A
1069
1070 switch(name[0]) {
1071 case KERN_KDEFLAGS:
1072 case KERN_KDDFLAGS:
1073 case KERN_KDENABLE:
1074 case KERN_KDGETBUF:
1075 case KERN_KDSETUP:
1076 case KERN_KDREMOVE:
1077 case KERN_KDSETREG:
1078 case KERN_KDGETREG:
1079 case KERN_KDREADTR:
1080 case KERN_KDPIDTR:
1081 case KERN_KDTHRMAP:
1082 case KERN_KDPIDEX:
1083 case KERN_KDSETRTCDEC:
1084 case KERN_KDSETBUF:
9bccf70c 1085 case KERN_KDGETENTROPY:
1c79356b
A
1086 ret = kdbg_control(name, namelen, where, sizep);
1087 break;
1088 default:
1089 ret= EOPNOTSUPP;
1090 break;
1091 }
1092 return(ret);
1093}
1094
9bccf70c 1095int
1c79356b
A
1096pcsamples_ops(name, namelen, where, sizep, p)
1097int *name;
1098u_int namelen;
1099char *where;
1100size_t *sizep;
1101struct proc *p;
1102{
9bccf70c
A
1103 int ret=0;
1104 extern int pcsamples_control(int *name, u_int namelen,
1105 char * where,size_t * sizep);
1c79356b 1106
9bccf70c
A
1107 if (ret = suser(p->p_ucred, &p->p_acflag))
1108 return(ret);
1c79356b
A
1109
1110 switch(name[0]) {
1111 case KERN_PCDISABLE:
1112 case KERN_PCGETBUF:
1113 case KERN_PCSETUP:
1114 case KERN_PCREMOVE:
1115 case KERN_PCREADBUF:
1116 case KERN_PCSETREG:
1117 case KERN_PCSETBUF:
1118 case KERN_PCCOMM:
1119 ret = pcsamples_control(name, namelen, where, sizep);
1120 break;
1121 default:
1122 ret= EOPNOTSUPP;
1123 break;
1124 }
1125 return(ret);
1126}
1127
1128/*
1129 * Returns the top N bytes of the user stack, with
1130 * everything below the first argument character
1131 * zeroed for security reasons.
1132 * Odd data structure is for compatibility.
1133 */
9bccf70c
A
1134int
1135sysctl_procargs(name, namelen, where, sizep, cur_proc)
1c79356b
A
1136 int *name;
1137 u_int namelen;
1138 char *where;
1139 size_t *sizep;
9bccf70c 1140 struct proc *cur_proc;
1c79356b
A
1141{
1142 register struct proc *p;
1143 register int needed = 0;
1144 int buflen = where != NULL ? *sizep : 0;
1145 int error = 0;
1146 struct vm_map *proc_map;
1147 struct task * task;
1148 vm_map_copy_t tmp;
1149 vm_offset_t arg_addr;
1150 vm_size_t arg_size;
1151 caddr_t data;
1152 unsigned size;
1153 vm_offset_t copy_start, copy_end;
1154 vm_offset_t dealloc_start; /* area to remove from kernel map */
1155 vm_offset_t dealloc_end;
1156 int *ip;
1157 kern_return_t ret;
1158 int pid;
1159
1160
1161 if ((buflen <= 0) || (buflen > (PAGE_SIZE << 1))) {
1162 return(EINVAL);
1163 }
1164 arg_size = buflen;
1165
1166 /*
1167 * Lookup process by pid
1168 */
1169 pid = name[0];
1170
0b4e3aa0 1171 restart:
1c79356b
A
1172 p = pfind(pid);
1173 if (p == NULL) {
1174 return(EINVAL);
1175 }
1176
1177 /*
1178 * Copy the top N bytes of the stack.
1179 * On all machines we have so far, the stack grows
1180 * downwards.
1181 *
1182 * If the user expects no more than N bytes of
1183 * argument list, use that as a guess for the
1184 * size.
1185 */
1186
1187 if (!p->user_stack)
1188 return(EINVAL);
1189
9bccf70c
A
1190 if ((p->p_ucred->cr_uid != cur_proc->p_ucred->cr_uid)
1191 && suser(cur_proc->p_ucred, &cur_proc->p_acflag))
1192 return (EINVAL);
1c79356b
A
1193 arg_addr = (vm_offset_t)(p->user_stack - arg_size);
1194
1195
1196 /*
1197 * Before we can block (any VM code), make another
1198 * reference to the map to keep it alive. We do
1199 * that by getting a reference on the task itself.
1200 */
1201 task = p->task;
1202 if (task == NULL)
1203 return(EINVAL);
1204
0b4e3aa0
A
1205 /*
1206 * A regular task_reference call can block, causing the funnel
1207 * to be dropped and allowing the proc/task to get freed.
1208 * Instead, we issue a non-blocking attempt at the task reference,
1209 * and look up the proc/task all over again if that fails.
1210 */
1211 if (!task_reference_try(task)) {
1212 mutex_pause();
1213 goto restart;
1214 }
1c79356b 1215
de355530 1216 ret = kmem_alloc(kernel_map, &copy_start, round_page(arg_size));
1c79356b
A
1217 if (ret != KERN_SUCCESS) {
1218 task_deallocate(task);
1219 return(ENOMEM);
1220 }
1221
1222 proc_map = get_task_map(task);
de355530 1223 copy_end = round_page(copy_start + arg_size);
1c79356b 1224
de355530 1225 if( vm_map_copyin(proc_map, trunc_page(arg_addr), round_page(arg_size),
1c79356b
A
1226 FALSE, &tmp) != KERN_SUCCESS) {
1227 task_deallocate(task);
1228 kmem_free(kernel_map, copy_start,
de355530 1229 round_page(arg_size));
1c79356b
A
1230 return (EIO);
1231 }
1232
1233 /*
1234 * Now that we've done the copyin from the process'
1235 * map, we can release the reference to it.
1236 */
1237 task_deallocate(task);
1238
1239 if( vm_map_copy_overwrite(kernel_map, copy_start,
1240 tmp, FALSE) != KERN_SUCCESS) {
1241 kmem_free(kernel_map, copy_start,
de355530 1242 round_page(arg_size));
1c79356b
A
1243 return (EIO);
1244 }
1245
1246 data = (caddr_t) (copy_end - arg_size);
1247 ip = (int *) copy_end;
1248 size = arg_size;
1249
1250 /*
1251 * Now look down the stack for the bottom of the
1252 * argument list. Since this call is otherwise
1253 * unprotected, we can't let the nosy user see
1254 * anything else on the stack.
1255 *
1256 * The arguments are pushed on the stack by
1257 * execve() as:
1258 *
1259 * .long 0
1260 * arg 0 (null-terminated)
1261 * arg 1
1262 * ...
1263 * arg N
1264 * .long 0
1265 *
1266 */
1267
1268 ip -= 2; /*skip trailing 0 word and assume at least one
1269 argument. The last word of argN may be just
1270 the trailing 0, in which case we'd stop
1271 there */
1272 while (*--ip)
1273 if (ip == (int *)data)
1274 break;
1275 /*
1276 * To account for saved path name and not having a null after that
1277 * Run the sweep again. If we have already sweeped entire range skip this
1278 */
1279 if (ip != (int *)data) {
1280 while (*--ip)
1281 if (ip == (int *)data)
1282 break;
1283 }
1284
1285 bzero(data, (unsigned) ((int)ip - (int)data));
1286
1287 dealloc_start = copy_start;
1288 dealloc_end = copy_end;
1289
1290
1291 size = MIN(size, buflen);
1292 error = copyout(data, where, size);
1293
1294 if (dealloc_start != (vm_offset_t) 0) {
1295 kmem_free(kernel_map, dealloc_start,
1296 dealloc_end - dealloc_start);
1297 }
1298 if (error) {
1299 return(error);
1300 }
1301
1302 if (where != NULL)
1303 *sizep = size;
1304 return (0);
1305}