]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/kern_sysctl.c
xnu-124.8.tar.gz
[apple/xnu.git] / bsd / kern / kern_sysctl.c
CommitLineData
1c79356b
A
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
86extern 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
98sysctlfn kern_sysctl;
99sysctlfn hw_sysctl;
100#ifdef DEBUG
101sysctlfn debug_sysctl;
102#endif
103extern sysctlfn vm_sysctl;
104extern sysctlfn vfs_sysctl;
105extern sysctlfn net_sysctl;
106extern sysctlfn cpu_sysctl;
107
108
109int
110userland_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
113void
114fill_proc(struct proc *p,struct kinfo_proc *kp, int doingzomb);
115
116void
117fill_externproc(struct proc *p, struct extern_proc *exp);
118
119
120
121/*
122 * temporary location for vm_sysctl. This should be machine independant
123 */
124vm_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 */
167static struct sysctl_lock {
168 int sl_lock;
169 int sl_want;
170 int sl_locked;
171} memlock;
172
173struct __sysctl_args {
174 int *name;
175 u_int namelen;
176 void *old;
177 size_t *oldlenp;
178 void *new;
179 size_t newlen;
180};
181int
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 */
300extern char hostname[MAXHOSTNAMELEN]; /* defined in bsd/kern/init_main.c */
301extern int hostnamelen;
302extern char domainname[MAXHOSTNAMELEN];
303extern int domainnamelen;
304extern long hostid;
305#ifdef INSECURE
306int securelevel = -1;
307#else
308int securelevel;
309#endif
310
311int get_kernel_symfile( struct proc *p, char **symfile );
312
313/*
314 * kernel related system variables.
315 */
316kern_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 */
440hw_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
535extern
536#endif /* DIAGNOSTIC */
537struct ctldebug debug0, debug1;
538struct ctldebug debug2, debug3, debug4;
539struct ctldebug debug5, debug6, debug7, debug8, debug9;
540struct ctldebug debug10, debug11, debug12, debug13, debug14;
541struct ctldebug debug15, debug16, debug17, debug18, debug19;
542static 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};
548int
549debug_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 */
582sysctl_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 */
606sysctl_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 */
628sysctl_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 */
657sysctl_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 */
680sysctl_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 */
707sysctl_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 */
728sysctl_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
779sysctl_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;
797again:
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)) {
e7c99d92 840 bzero(&kproc, sizeof(struct kinfo_proc));
1c79356b
A
841 fill_proc(p, &kproc, doingzomb);
842 if (error = copyout((caddr_t)&kproc, &dp->kp_proc,
843 sizeof(struct kinfo_proc)))
844 return (error);
845 dp++;
846 buflen -= sizeof(struct kinfo_proc);
847 }
848 needed += sizeof(struct kinfo_proc);
849 }
850 if (doingzomb == 0) {
851 p = zombproc.lh_first;
852 doingzomb++;
853 goto again;
854 }
855 if (where != NULL) {
856 *sizep = (caddr_t)dp - where;
857 if (needed > *sizep)
858 return (ENOMEM);
859 } else {
860 needed += KERN_PROCSLOP;
861 *sizep = needed;
862 }
863 return (0);
864}
865
866void
867fill_proc(p,kp, doingzomb)
868 register struct proc *p;
869 register struct kinfo_proc *kp;
870 int doingzomb;
871{
872 fill_externproc(p, &kp->kp_proc);
873 if (!doingzomb)
874 fill_eproc(p, &kp->kp_eproc);
875}
876/*
877 * Fill in an eproc structure for the specified process.
878 */
879void
880fill_eproc(p, ep)
881 register struct proc *p;
882 register struct eproc *ep;
883{
884 register struct tty *tp;
885
e7c99d92
A
886 /*
887 * Skip zombie processes.
888 */
889 if (p->p_stat == SZOMB)
890 return;
891
1c79356b
A
892 ep->e_paddr = p;
893 ep->e_sess = p->p_pgrp->pg_session;
894 ep->e_pcred = *p->p_cred;
895 ep->e_ucred = *p->p_ucred;
896 if (p->p_stat == SIDL || p->p_stat == SZOMB) {
897 ep->e_vm.vm_rssize = 0;
898 ep->e_vm.vm_tsize = 0;
899 ep->e_vm.vm_dsize = 0;
900 ep->e_vm.vm_ssize = 0;
901 /* ep->e_vm.vm_pmap = XXX; */
902 } else {
903#if FIXME /* [ */
904 register vm_map_t vm = ((task_t)p->task)->map;
905
906 ep->e_vm.vm_rssize = pmap_resident_count(vm->pmap); /*XXX*/
907// ep->e_vm.vm_tsize = vm->vm_tsize;
908// ep->e_vm.vm_dsize = vm->vm_dsize;
909// ep->e_vm.vm_ssize = vm->vm_ssize;
910#else /* FIXME ][ */
911 ep->e_vm.vm_rssize = 0; /*XXX*/
912#endif /* FIXME ] */
913 }
914 if (p->p_pptr)
915 ep->e_ppid = p->p_pptr->p_pid;
916 else
917 ep->e_ppid = 0;
918 ep->e_pgid = p->p_pgrp->pg_id;
919 ep->e_jobc = p->p_pgrp->pg_jobc;
920 if ((p->p_flag & P_CONTROLT) &&
921 (tp = ep->e_sess->s_ttyp)) {
922 ep->e_tdev = tp->t_dev;
923 ep->e_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
924 ep->e_tsess = tp->t_session;
925 } else
926 ep->e_tdev = NODEV;
927 ep->e_flag = ep->e_sess->s_ttyvp ? EPROC_CTTY : 0;
928 if (SESS_LEADER(p))
929 ep->e_flag |= EPROC_SLEADER;
930 if (p->p_wmesg)
931 strncpy(ep->e_wmesg, p->p_wmesg, WMESGLEN);
932 ep->e_xsize = ep->e_xrssize = 0;
933 ep->e_xccount = ep->e_xswrss = 0;
934}
935/*
936 * Fill in an eproc structure for the specified process.
937 */
938void
939fill_externproc(p, exp)
940 register struct proc *p;
941 register struct extern_proc *exp;
942{
943 exp->p_forw = exp->p_back = NULL;
944 exp->p_vmspace = NULL;
945 exp->p_sigacts = p->p_sigacts;
946 exp->p_flag = p->p_flag;
947 exp->p_stat = p->p_stat ;
948 exp->p_pid = p->p_pid ;
949 exp->p_oppid = p->p_oppid ;
950 exp->p_dupfd = p->p_dupfd ;
951 /* Mach related */
952 exp->user_stack = p->user_stack ;
953 exp->exit_thread = p->exit_thread ;
954 exp->p_debugger = p->p_debugger ;
955 exp->sigwait = p->sigwait ;
956 /* scheduling */
957 exp->p_estcpu = p->p_estcpu ;
958 exp->p_cpticks = p->p_cpticks ;
959 exp->p_pctcpu = p->p_pctcpu ;
960 exp->p_wchan = p->p_wchan ;
961 exp->p_wmesg = p->p_wmesg ;
962 exp->p_swtime = p->p_swtime ;
963 exp->p_slptime = p->p_slptime ;
964 bcopy(&p->p_realtimer, &exp->p_realtimer,sizeof(struct itimerval));
965 bcopy(&p->p_rtime, &exp->p_rtime,sizeof(struct timeval));
966 exp->p_uticks = p->p_uticks ;
967 exp->p_sticks = p->p_sticks ;
968 exp->p_iticks = p->p_iticks ;
969 exp->p_traceflag = p->p_traceflag ;
970 exp->p_tracep = p->p_tracep ;
971 exp->p_siglist = p->p_siglist ;
972 exp->p_textvp = p->p_textvp ;
973 exp->p_holdcnt = 0 ;
974 exp->p_sigmask = p->p_sigmask ;
975 exp->p_sigignore = p->p_sigignore ;
976 exp->p_sigcatch = p->p_sigcatch ;
977 exp->p_priority = p->p_priority ;
978 exp->p_usrpri = p->p_usrpri ;
979 exp->p_nice = p->p_nice ;
980 bcopy(&p->p_comm, &exp->p_comm,MAXCOMLEN);
981 exp->p_comm[MAXCOMLEN] = '\0';
982 exp->p_pgrp = p->p_pgrp ;
983 exp->p_addr = NULL;
984 exp->p_xstat = p->p_xstat ;
985 exp->p_acflag = p->p_acflag ;
986 exp->p_ru = p->p_ru ;
987}
988
989kdebug_ops(name, namelen, where, sizep, p)
990int *name;
991u_int namelen;
992char *where;
993size_t *sizep;
994struct proc *p;
995{
996int size=*sizep;
997int ret=0;
998extern int kdbg_control(int *name, u_int namelen, char * where,size_t * sizep);
999
1000 if (ret = suser(p->p_ucred, &p->p_acflag))
1001 return(ret);
1002
1003 switch(name[0]) {
1004 case KERN_KDEFLAGS:
1005 case KERN_KDDFLAGS:
1006 case KERN_KDENABLE:
1007 case KERN_KDGETBUF:
1008 case KERN_KDSETUP:
1009 case KERN_KDREMOVE:
1010 case KERN_KDSETREG:
1011 case KERN_KDGETREG:
1012 case KERN_KDREADTR:
1013 case KERN_KDPIDTR:
1014 case KERN_KDTHRMAP:
1015 case KERN_KDPIDEX:
1016 case KERN_KDSETRTCDEC:
1017 case KERN_KDSETBUF:
1018 ret = kdbg_control(name, namelen, where, sizep);
1019 break;
1020 default:
1021 ret= EOPNOTSUPP;
1022 break;
1023 }
1024 return(ret);
1025}
1026
1027pcsamples_ops(name, namelen, where, sizep, p)
1028int *name;
1029u_int namelen;
1030char *where;
1031size_t *sizep;
1032struct proc *p;
1033{
1034int ret=0;
1035extern int pcsamples_control(int *name, u_int namelen, char * where,size_t * sizep);
1036
1037 if (ret = suser(p->p_ucred, &p->p_acflag))
1038 return(ret);
1039
1040 switch(name[0]) {
1041 case KERN_PCDISABLE:
1042 case KERN_PCGETBUF:
1043 case KERN_PCSETUP:
1044 case KERN_PCREMOVE:
1045 case KERN_PCREADBUF:
1046 case KERN_PCSETREG:
1047 case KERN_PCSETBUF:
1048 case KERN_PCCOMM:
1049 ret = pcsamples_control(name, namelen, where, sizep);
1050 break;
1051 default:
1052 ret= EOPNOTSUPP;
1053 break;
1054 }
1055 return(ret);
1056}
1057
1058/*
1059 * Returns the top N bytes of the user stack, with
1060 * everything below the first argument character
1061 * zeroed for security reasons.
1062 * Odd data structure is for compatibility.
1063 */
1064sysctl_procargs(name, namelen, where, sizep)
1065 int *name;
1066 u_int namelen;
1067 char *where;
1068 size_t *sizep;
1069{
1070 register struct proc *p;
1071 register int needed = 0;
1072 int buflen = where != NULL ? *sizep : 0;
1073 int error = 0;
1074 struct vm_map *proc_map;
1075 struct task * task;
1076 vm_map_copy_t tmp;
1077 vm_offset_t arg_addr;
1078 vm_size_t arg_size;
1079 caddr_t data;
1080 unsigned size;
1081 vm_offset_t copy_start, copy_end;
1082 vm_offset_t dealloc_start; /* area to remove from kernel map */
1083 vm_offset_t dealloc_end;
1084 int *ip;
1085 kern_return_t ret;
1086 int pid;
1087
1088
1089 if ((buflen <= 0) || (buflen > (PAGE_SIZE << 1))) {
1090 return(EINVAL);
1091 }
1092 arg_size = buflen;
1093
1094 /*
1095 * Lookup process by pid
1096 */
1097 pid = name[0];
1098
1099 p = pfind(pid);
1100 if (p == NULL) {
1101 return(EINVAL);
1102 }
1103
1104 /*
1105 * Copy the top N bytes of the stack.
1106 * On all machines we have so far, the stack grows
1107 * downwards.
1108 *
1109 * If the user expects no more than N bytes of
1110 * argument list, use that as a guess for the
1111 * size.
1112 */
1113
1114 if (!p->user_stack)
1115 return(EINVAL);
1116
1117 arg_addr = (vm_offset_t)(p->user_stack - arg_size);
1118
1119
1120 /*
1121 * Before we can block (any VM code), make another
1122 * reference to the map to keep it alive. We do
1123 * that by getting a reference on the task itself.
1124 */
1125 task = p->task;
1126 if (task == NULL)
1127 return(EINVAL);
1128
1129 task_reference(task);
1130
1131 ret = kmem_alloc(kernel_map, &copy_start, round_page(arg_size));
1132 if (ret != KERN_SUCCESS) {
1133 task_deallocate(task);
1134 return(ENOMEM);
1135 }
1136
1137 proc_map = get_task_map(task);
1138 copy_end = round_page(copy_start + arg_size);
1139
1140 if( vm_map_copyin(proc_map, trunc_page(arg_addr), round_page(arg_size),
1141 FALSE, &tmp) != KERN_SUCCESS) {
1142 task_deallocate(task);
1143 kmem_free(kernel_map, copy_start,
1144 round_page(arg_size));
1145 return (EIO);
1146 }
1147
1148 /*
1149 * Now that we've done the copyin from the process'
1150 * map, we can release the reference to it.
1151 */
1152 task_deallocate(task);
1153
1154 if( vm_map_copy_overwrite(kernel_map, copy_start,
1155 tmp, FALSE) != KERN_SUCCESS) {
1156 kmem_free(kernel_map, copy_start,
1157 round_page(arg_size));
1158 return (EIO);
1159 }
1160
1161 data = (caddr_t) (copy_end - arg_size);
1162 ip = (int *) copy_end;
1163 size = arg_size;
1164
1165 /*
1166 * Now look down the stack for the bottom of the
1167 * argument list. Since this call is otherwise
1168 * unprotected, we can't let the nosy user see
1169 * anything else on the stack.
1170 *
1171 * The arguments are pushed on the stack by
1172 * execve() as:
1173 *
1174 * .long 0
1175 * arg 0 (null-terminated)
1176 * arg 1
1177 * ...
1178 * arg N
1179 * .long 0
1180 *
1181 */
1182
1183 ip -= 2; /*skip trailing 0 word and assume at least one
1184 argument. The last word of argN may be just
1185 the trailing 0, in which case we'd stop
1186 there */
1187 while (*--ip)
1188 if (ip == (int *)data)
1189 break;
1190 /*
1191 * To account for saved path name and not having a null after that
1192 * Run the sweep again. If we have already sweeped entire range skip this
1193 */
1194 if (ip != (int *)data) {
1195 while (*--ip)
1196 if (ip == (int *)data)
1197 break;
1198 }
1199
1200 bzero(data, (unsigned) ((int)ip - (int)data));
1201
1202 dealloc_start = copy_start;
1203 dealloc_end = copy_end;
1204
1205
1206 size = MIN(size, buflen);
1207 error = copyout(data, where, size);
1208
1209 if (dealloc_start != (vm_offset_t) 0) {
1210 kmem_free(kernel_map, dealloc_start,
1211 dealloc_end - dealloc_start);
1212 }
1213 if (error) {
1214 return(error);
1215 }
1216
1217 if (where != NULL)
1218 *sizep = size;
1219 return (0);
1220}