/*
- * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
- * The contents of this file constitute Original Code as defined in and
- * are subject to the Apple Public Source License Version 1.1 (the
- * "License"). You may not use this file except in compliance with the
- * License. Please obtain a copy of the License at
- * http://www.apple.com/publicsource and read it before using this file.
+ * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
*
- * This Original Code and all software distributed under the License are
- * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
- * License for the specific language governing rights and limitations
- * under the License.
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
#include <sys/disklabel.h>
#include <sys/vm.h>
#include <sys/sysctl.h>
+#include <sys/user.h>
#include <mach/machine.h>
#include <mach/mach_types.h>
#include <mach/vm_param.h>
#include <pexpert/pexpert.h>
#if __ppc__
-#include <osfmk/ppc/machine_routines.h>
+#include <ppc/machine_routines.h>
#endif
sysctlfn kern_sysctl;
-sysctlfn hw_sysctl;
#ifdef DEBUG
sysctlfn debug_sysctl;
#endif
/*
* temporary location for vm_sysctl. This should be machine independant
*/
+int
vm_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
int *name;
u_int namelen;
size_t newlen;
struct proc *p;
{
- int error, level, inthostid;
- extern long avenrun[3], mach_factor[3];
+ extern uint32_t mach_factor[3];
struct loadavg loadinfo;
- //if (namelen != 1 && !(name[0] == VM_LOADAVG))
- //return (ENOTDIR); /* overloaded */
-
switch (name[0]) {
case VM_LOADAVG:
- loadinfo.ldavg[0] = avenrun[0];
- loadinfo.ldavg[1] = avenrun[1];
- loadinfo.ldavg[2] = avenrun[2];
- loadinfo.fscale = LSCALE;
- return (sysctl_struct(oldp, oldlenp, newp, newlen, &loadinfo, sizeof(struct loadavg)));
+ return (sysctl_struct(oldp, oldlenp, newp, newlen,
+ &averunnable, sizeof(struct loadavg)));
case VM_MACHFACTOR:
loadinfo.ldavg[0] = mach_factor[0];
loadinfo.ldavg[1] = mach_factor[1];
loadinfo.ldavg[2] = mach_factor[2];
loadinfo.fscale = LSCALE;
- return (sysctl_struct(oldp, oldlenp, newp, newlen, &loadinfo, sizeof(struct loadavg)));
+ return (sysctl_struct(oldp, oldlenp, newp, newlen,
+ &loadinfo, sizeof(struct loadavg)));
case VM_METER:
return (EOPNOTSUPP);
case VM_MAXID:
sysctlfn *fn;
int name[CTL_MAXNAME];
int i;
+ int error1;
/*
* all top-level sysctl names are non-terminal
return (error);
/* CTL_UNSPEC is used to get oid to AUTO_OID */
- if (uap->new != NULL &&
- (((name[0] == CTL_KERN) && (name[1] != KERN_IPC)) ||
- (name[0] == CTL_HW) || (name[0] == CTL_VM) ||
- (name[0] == CTL_VFS)) &&
- (error = suser(p->p_ucred, &p->p_acflag)))
+ if (uap->new != NULL
+ && ((name[0] == CTL_KERN
+ && !(name[1] == KERN_IPC || name[1] == KERN_PANICINFO))
+ || (name[0] == CTL_HW)
+ || (name[0] == CTL_VM)
+ || (name[0] == CTL_VFS))
+ && (error = suser(p->p_ucred, &p->p_acflag)))
return (error);
switch (name[0]) {
case CTL_KERN:
fn = kern_sysctl;
- if (name[1] != KERN_VNODE) /* XXX */
+ if ((name[1] != KERN_VNODE) && (name[1] != KERN_FILE)
+ && (name[1] != KERN_PROC))
dolock = 0;
break;
- case CTL_HW:
- fn = hw_sysctl;
- break;
case CTL_VM:
fn = vm_sysctl;
break;
case CTL_VFS:
fn = vfs_sysctl;
break;
-#if FIXME /* [ */
- case CTL_MACHDEP:
- fn = cpu_sysctl;
- break;
-#endif /* FIXME ] */
#ifdef DEBUG
case CTL_DEBUG:
fn = debug_sysctl;
return (EFAULT);
/* The pc sampling mechanism does not need to take this lock */
- if (name[1] != KERN_PCSAMPLES) {
+ if ((name[1] != KERN_PCSAMPLES) &&
+ (!((name[1] == KERN_KDEBUG) && (name[2] == KERN_KDGETENTROPY)))) {
while (memlock.sl_lock) {
memlock.sl_want = 1;
sleep((caddr_t)&memlock, PRIBIO+1);
memlock.sl_lock = 1;
}
- if (dolock)
- vslock(uap->old, oldlen);
+ if (dolock && oldlen && (error = vslock(uap->old, oldlen))) {
+ if ((name[1] != KERN_PCSAMPLES) &&
+ (! ((name[1] == KERN_KDEBUG) && (name[2] == KERN_KDGETENTROPY)))) {
+ memlock.sl_lock = 0;
+ if (memlock.sl_want) {
+ memlock.sl_want = 0;
+ wakeup((caddr_t)&memlock);
+ }
+ }
+ return(error);
+ }
savelen = oldlen;
}
uap->new, uap->newlen, &oldlen);
if (uap->old != NULL) {
- if (dolock)
- vsunlock(uap->old, savelen, B_WRITE);
+ if (dolock && savelen) {
+ error1 = vsunlock(uap->old, savelen, B_WRITE);
+ if (!error && error1)
+ error = error1;
+ }
if (name[1] != KERN_PCSAMPLES) {
memlock.sl_lock = 0;
if (memlock.sl_want) {
int securelevel;
#endif
-int get_kernel_symfile( struct proc *p, char **symfile );
+extern int get_kernel_symfile( struct proc *, char **);
+extern int sysctl_dopanicinfo(int *, u_int, void *, size_t *,
+ void *, size_t, struct proc *);
/*
* kernel related system variables.
*/
+int
kern_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
int *name;
u_int namelen;
{
int error, level, inthostid;
unsigned int oldval=0;
+ char *str;
extern char ostype[], osrelease[], version[];
-
- /* all sysctl names at this level are terminal */
- if (namelen != 1 && !(name[0] == KERN_PROC || name[0] == KERN_PROF
- || name[0] == KERN_KDEBUG
- || name[0] == KERN_PROCARGS
- || name[0] == KERN_PCSAMPLES
- || name[0] == KERN_IPC
- ))
+ extern int netboot_root();
+
+ /* all sysctl names not listed below are terminal at this level */
+ if (namelen != 1
+ && !(name[0] == KERN_PROC
+ || name[0] == KERN_PROF
+ || name[0] == KERN_KDEBUG
+ || name[0] == KERN_PROCARGS
+ || name[0] == KERN_PCSAMPLES
+ || name[0] == KERN_IPC
+ || name[0] == KERN_SYSV
+ || name[0] == KERN_PANICINFO)
+ )
return (ENOTDIR); /* overloaded */
switch (name[0]) {
#else
return (sysctl_rdint(oldp, oldlenp, newp, 0));
#endif
-#if FIXME /* [ */
- case KERN_MAXPARTITIONS:
- return (sysctl_rdint(oldp, oldlenp, newp, MAXPARTITIONS));
-#endif /* FIXME ] */
case KERN_KDEBUG:
return (kdebug_ops(name + 1, namelen - 1, oldp, oldlenp, p));
case KERN_PCSAMPLES:
return (pcsamples_ops(name + 1, namelen - 1, oldp, oldlenp, p));
case KERN_PROCARGS:
/* new one as it does not use kinfo_proc */
- return (sysctl_procargs(name + 1, namelen - 1, oldp, oldlenp));
- case KERN_SYMFILE:
- {
- char *str;
- error = get_kernel_symfile( p, &str );
- if ( error ) return error;
- return (sysctl_rdstring(oldp, oldlenp, newp, str));
- }
+ return (sysctl_procargs(name + 1, namelen - 1, oldp, oldlenp, p));
+ case KERN_SYMFILE:
+ error = get_kernel_symfile( p, &str );
+ if ( error )
+ return error;
+ return (sysctl_rdstring(oldp, oldlenp, newp, str));
+ case KERN_NETBOOT:
+ return (sysctl_rdint(oldp, oldlenp, newp, netboot_root()));
+ case KERN_PANICINFO:
+ return(sysctl_dopanicinfo(name + 1, namelen - 1, oldp, oldlenp,
+ newp, newlen, p));
default:
return (EOPNOTSUPP);
}
/* NOTREACHED */
}
-/*
- * hardware related system variables.
- */
-hw_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
- int *name;
- u_int namelen;
- void *oldp;
- size_t *oldlenp;
- void *newp;
- size_t newlen;
- struct proc *p;
-{
- char dummy[65];
- int epochTemp;
- extern int vm_page_wire_count;
-#if __ppc__
- ml_ppc_cpu_info_t cpu_info;
-
- ml_ppc_get_info(&cpu_info);
-#endif
-
- /* all sysctl names at this level are terminal */
- if (namelen != 1)
- return (ENOTDIR); /* overloaded */
-
- switch (name[0]) {
- case HW_MACHINE:
- if(!PEGetMachineName(dummy,64))
- return(EINVAL);
- return (sysctl_rdstring(oldp, oldlenp, newp, dummy));
- case HW_MODEL:
- if(!PEGetModelName(dummy,64))
- return(EINVAL);
- return (sysctl_rdstring(oldp, oldlenp, newp, dummy));
- case HW_NCPU: {
- int numcpus=1;
- host_basic_info_data_t hinfo;
- kern_return_t kret;
- int count= HOST_BASIC_INFO_COUNT;
-#define BSD_HOST 1
-
- kret = host_info(BSD_HOST, HOST_BASIC_INFO, &hinfo, &count);
- if (kret == KERN_SUCCESS) {
- numcpus = hinfo.avail_cpus;
- return (sysctl_rdint(oldp, oldlenp, newp, numcpus));
- } else {
- return(EINVAL);
- }
- }
- case HW_BYTEORDER:
- return (sysctl_rdint(oldp, oldlenp, newp, BYTE_ORDER));
- case HW_PHYSMEM:
- return (sysctl_rdint(oldp, oldlenp, newp, mem_size));
- case HW_USERMEM:
- return (sysctl_rdint(oldp, oldlenp, newp,
- (mem_size - vm_page_wire_count * page_size)));
- case HW_PAGESIZE:
- return (sysctl_rdint(oldp, oldlenp, newp, page_size));
- case HW_EPOCH:
- epochTemp = PEGetPlatformEpoch();
- if (epochTemp == -1) return(EINVAL);
- return (sysctl_rdint(oldp, oldlenp, newp, epochTemp));
- case HW_BUS_FREQ:
- return (sysctl_rdint(oldp, oldlenp, newp, gPEClockFrequencyInfo.bus_clock_rate_hz));
- case HW_CPU_FREQ:
- return (sysctl_rdint(oldp, oldlenp, newp, gPEClockFrequencyInfo.cpu_clock_rate_hz));
-#if __ppc__
- case HW_VECTORUNIT:
- return (sysctl_rdint(oldp, oldlenp, newp, cpu_info.vector_unit));
- case HW_CACHELINE:
- return (sysctl_rdint(oldp, oldlenp, newp, cpu_info.cache_line_size));
- case HW_L1ICACHESIZE:
- return (sysctl_rdint(oldp, oldlenp, newp, cpu_info.l1_icache_size));
- case HW_L1DCACHESIZE:
- return (sysctl_rdint(oldp, oldlenp, newp, cpu_info.l1_dcache_size));
- case HW_L2SETTINGS:
- if (cpu_info.l2_cache_size == 0xFFFFFFFF) return(EINVAL);
- return (sysctl_rdint(oldp, oldlenp, newp, cpu_info.l2_settings));
- case HW_L2CACHESIZE:
- if (cpu_info.l2_cache_size == 0xFFFFFFFF) return(EINVAL);
- return (sysctl_rdint(oldp, oldlenp, newp, cpu_info.l2_cache_size));
- case HW_L3SETTINGS:
- if (cpu_info.l3_cache_size == 0xFFFFFFFF) return(EINVAL);
- return (sysctl_rdint(oldp, oldlenp, newp, cpu_info.l3_settings));
- case HW_L3CACHESIZE:
- if (cpu_info.l3_cache_size == 0xFFFFFFFF) return(EINVAL);
- return (sysctl_rdint(oldp, oldlenp, newp, cpu_info.l3_cache_size));
-#endif
- default:
- return (EOPNOTSUPP);
- }
-}
-
#ifdef DEBUG
/*
* Debugging related system variables.
* Validate parameters and get old / set new parameters
* for an integer-valued sysctl function.
*/
+int
sysctl_int(oldp, oldlenp, newp, newlen, valp)
void *oldp;
size_t *oldlenp;
/*
* As above, but read-only.
*/
+int
sysctl_rdint(oldp, oldlenp, newp, val)
void *oldp;
size_t *oldlenp;
return (error);
}
+/*
+ * Validate parameters and get old / set new parameters
+ * for an quad(64bit)-valued sysctl function.
+ */
+int
+sysctl_quad(oldp, oldlenp, newp, newlen, valp)
+ void *oldp;
+ size_t *oldlenp;
+ void *newp;
+ size_t newlen;
+ quad_t *valp;
+{
+ int error = 0;
+
+ if (oldp && *oldlenp < sizeof(quad_t))
+ return (ENOMEM);
+ if (newp && newlen != sizeof(quad_t))
+ return (EINVAL);
+ *oldlenp = sizeof(quad_t);
+ if (oldp)
+ error = copyout(valp, oldp, sizeof(quad_t));
+ if (error == 0 && newp)
+ error = copyin(newp, valp, sizeof(quad_t));
+ return (error);
+}
+
+/*
+ * As above, but read-only.
+ */
+int
+sysctl_rdquad(oldp, oldlenp, newp, val)
+ void *oldp;
+ size_t *oldlenp;
+ void *newp;
+ quad_t val;
+{
+ int error = 0;
+
+ if (oldp && *oldlenp < sizeof(quad_t))
+ return (ENOMEM);
+ if (newp)
+ return (EPERM);
+ *oldlenp = sizeof(quad_t);
+ if (oldp)
+ error = copyout((caddr_t)&val, oldp, sizeof(quad_t));
+ return (error);
+}
+
/*
* Validate parameters and get old / set new parameters
* for a string-valued sysctl function.
*/
+int
sysctl_string(oldp, oldlenp, newp, newlen, str, maxlen)
void *oldp;
size_t *oldlenp;
return (ENOMEM);
if (newp && newlen >= maxlen)
return (EINVAL);
+ *oldlenp = len -1; /* deal with NULL strings correctly */
if (oldp) {
- *oldlenp = len;
error = copyout(str, oldp, len);
}
if (error == 0 && newp) {
/*
* As above, but read-only.
*/
+int
sysctl_rdstring(oldp, oldlenp, newp, str)
void *oldp;
size_t *oldlenp;
* Validate parameters and get old / set new parameters
* for a structure oriented sysctl function.
*/
+int
sysctl_struct(oldp, oldlenp, newp, newlen, sp, len)
void *oldp;
size_t *oldlenp;
* Validate parameters and get old parameters
* for a structure oriented sysctl function.
*/
+int
sysctl_rdstruct(oldp, oldlenp, newp, sp, len)
void *oldp;
size_t *oldlenp;
/*
* Get file structures.
*/
+int
sysctl_file(where, sizep)
char *where;
size_t *sizep;
*/
#define KERN_PROCSLOP (5 * sizeof (struct kinfo_proc))
+int
sysctl_doproc(name, namelen, where, sizep)
int *name;
u_int namelen;
break;
}
if (buflen >= sizeof(struct kinfo_proc)) {
+ bzero(&kproc, sizeof(struct kinfo_proc));
fill_proc(p, &kproc, doingzomb);
if (error = copyout((caddr_t)&kproc, &dp->kp_proc,
sizeof(struct kinfo_proc)))
{
register struct tty *tp;
+ /*
+ * Skip zombie processes.
+ */
+ if (p->p_stat == SZOMB)
+ return;
+
ep->e_paddr = p;
ep->e_sess = p->p_pgrp->pg_session;
ep->e_pcred = *p->p_cred;
ep->e_ucred = *p->p_ucred;
if (p->p_stat == SIDL || p->p_stat == SZOMB) {
- ep->e_vm.vm_rssize = 0;
ep->e_vm.vm_tsize = 0;
ep->e_vm.vm_dsize = 0;
ep->e_vm.vm_ssize = 0;
- /* ep->e_vm.vm_pmap = XXX; */
- } else {
-#if FIXME /* [ */
- register vm_map_t vm = ((task_t)p->task)->map;
-
- ep->e_vm.vm_rssize = pmap_resident_count(vm->pmap); /*XXX*/
-// ep->e_vm.vm_tsize = vm->vm_tsize;
-// ep->e_vm.vm_dsize = vm->vm_dsize;
-// ep->e_vm.vm_ssize = vm->vm_ssize;
-#else /* FIXME ][ */
- ep->e_vm.vm_rssize = 0; /*XXX*/
-#endif /* FIXME ] */
}
+ ep->e_vm.vm_rssize = 0;
if (p->p_pptr)
ep->e_ppid = p->p_pptr->p_pid;
else
register struct extern_proc *exp;
{
exp->p_forw = exp->p_back = NULL;
+ if (p->p_stats)
+ exp->p_starttime = p->p_stats->p_start;
exp->p_vmspace = NULL;
exp->p_sigacts = p->p_sigacts;
exp->p_flag = p->p_flag;
exp->p_iticks = p->p_iticks ;
exp->p_traceflag = p->p_traceflag ;
exp->p_tracep = p->p_tracep ;
- exp->p_siglist = p->p_siglist ;
+ exp->p_siglist = 0 ; /* No longer relevant */
exp->p_textvp = p->p_textvp ;
exp->p_holdcnt = 0 ;
- exp->p_sigmask = p->p_sigmask ;
+ exp->p_sigmask = 0 ; /* no longer avaialable */
exp->p_sigignore = p->p_sigignore ;
exp->p_sigcatch = p->p_sigcatch ;
exp->p_priority = p->p_priority ;
exp->p_ru = p->p_ru ;
}
+int
kdebug_ops(name, namelen, where, sizep, p)
int *name;
u_int namelen;
size_t *sizep;
struct proc *p;
{
-int size=*sizep;
-int ret=0;
-extern int kdbg_control(int *name, u_int namelen, char * where,size_t * sizep);
+ int size=*sizep;
+ int ret=0;
+ extern int kdbg_control(int *name, u_int namelen,
+ char * where,size_t * sizep);
- if (ret = suser(p->p_ucred, &p->p_acflag))
- return(ret);
+ if (ret = suser(p->p_ucred, &p->p_acflag))
+ return(ret);
switch(name[0]) {
case KERN_KDEFLAGS:
case KERN_KDPIDEX:
case KERN_KDSETRTCDEC:
case KERN_KDSETBUF:
+ case KERN_KDGETENTROPY:
ret = kdbg_control(name, namelen, where, sizep);
break;
default:
return(ret);
}
+int
pcsamples_ops(name, namelen, where, sizep, p)
int *name;
u_int namelen;
size_t *sizep;
struct proc *p;
{
-int ret=0;
-extern int pcsamples_control(int *name, u_int namelen, char * where,size_t * sizep);
+ int ret=0;
+ extern int pcsamples_control(int *name, u_int namelen,
+ char * where,size_t * sizep);
- if (ret = suser(p->p_ucred, &p->p_acflag))
- return(ret);
+ if (ret = suser(p->p_ucred, &p->p_acflag))
+ return(ret);
switch(name[0]) {
case KERN_PCDISABLE:
* zeroed for security reasons.
* Odd data structure is for compatibility.
*/
-sysctl_procargs(name, namelen, where, sizep)
+int
+sysctl_procargs(name, namelen, where, sizep, cur_proc)
int *name;
u_int namelen;
char *where;
size_t *sizep;
+ struct proc *cur_proc;
{
register struct proc *p;
register int needed = 0;
*/
pid = name[0];
+ restart:
p = pfind(pid);
if (p == NULL) {
return(EINVAL);
if (!p->user_stack)
return(EINVAL);
+ if ((p->p_ucred->cr_uid != cur_proc->p_ucred->cr_uid)
+ && suser(cur_proc->p_ucred, &cur_proc->p_acflag))
+ return (EINVAL);
arg_addr = (vm_offset_t)(p->user_stack - arg_size);
if (task == NULL)
return(EINVAL);
- task_reference(task);
+ /*
+ * A regular task_reference call can block, causing the funnel
+ * to be dropped and allowing the proc/task to get freed.
+ * Instead, we issue a non-blocking attempt at the task reference,
+ * and look up the proc/task all over again if that fails.
+ */
+ if (!task_reference_try(task)) {
+ mutex_pause();
+ goto restart;
+ }
ret = kmem_alloc(kernel_map, ©_start, round_page(arg_size));
if (ret != KERN_SUCCESS) {