#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/proc.h>
#include <sys/file.h>
#include <sys/vnode.h>
#include <sys/unistd.h>
#include <sys/buf.h>
#include <sys/ioctl.h>
#include <sys/tty.h>
#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 <kern/task.h>
#include <vm/vm_kern.h>
#include <mach/host_info.h>
extern vm_map_t bsd_pageable_map;
#include <sys/mount.h>
#include <sys/kdebug.h>
#include <IOKit/IOPlatformExpert.h>
#include <pexpert/pexpert.h>
#if __ppc__
#include <ppc/machine_routines.h>
#endif
sysctlfn kern_sysctl;
#ifdef DEBUG
sysctlfn debug_sysctl;
#endif
extern sysctlfn vm_sysctl;
extern sysctlfn vfs_sysctl;
extern sysctlfn net_sysctl;
extern sysctlfn cpu_sysctl;
int
userland_sysctl(struct proc *p, int *name, u_int namelen, void *old, size_t
*oldlenp, int inkernel, void *new, size_t newlen, size_t *retval);
void
fill_proc(struct proc *p,struct kinfo_proc *kp, int doingzomb);
void
fill_externproc(struct proc *p, struct extern_proc *exp);
int
vm_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;
{
extern uint32_t mach_factor[3];
struct loadavg loadinfo;
switch (name[0]) {
case VM_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)));
case VM_METER:
return (EOPNOTSUPP);
case VM_MAXID:
return (EOPNOTSUPP);
default:
return (EOPNOTSUPP);
}
return (EOPNOTSUPP);
}
static struct sysctl_lock {
int sl_lock;
int sl_want;
int sl_locked;
} memlock;
struct __sysctl_args {
int *name;
u_int namelen;
void *old;
size_t *oldlenp;
void *new;
size_t newlen;
};
int
__sysctl(p, uap, retval)
struct proc *p;
register struct __sysctl_args *uap;
register_t *retval;
{
int error, dolock = 1;
size_t savelen, oldlen = 0;
sysctlfn *fn;
int name[CTL_MAXNAME];
int i;
int error1;
if (uap->namelen > CTL_MAXNAME || uap->namelen < 2)
return (EINVAL);
if (error =
copyin(uap->name, &name, uap->namelen * sizeof(int)))
return (error);
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) && (name[1] != KERN_FILE)
&& (name[1] != KERN_PROC))
dolock = 0;
break;
case CTL_VM:
fn = vm_sysctl;
break;
case CTL_VFS:
fn = vfs_sysctl;
break;
#ifdef DEBUG
case CTL_DEBUG:
fn = debug_sysctl;
break;
#endif
default:
fn = 0;
}
if (uap->oldlenp &&
(error = copyin(uap->oldlenp, &oldlen, sizeof(oldlen))))
return (error);
if (uap->old != NULL) {
if (!useracc(uap->old, oldlen, B_WRITE))
return (EFAULT);
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_locked++;
}
memlock.sl_lock = 1;
}
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;
}
if (fn)
error = (*fn)(name + 1, uap->namelen - 1, uap->old,
&oldlen, uap->new, uap->newlen, p);
else
error = EOPNOTSUPP;
if ( (name[0] != CTL_VFS) && (error == EOPNOTSUPP))
error = userland_sysctl(p, name, uap->namelen,
uap->old, uap->oldlenp, 0,
uap->new, uap->newlen, &oldlen);
if (uap->old != NULL) {
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) {
memlock.sl_want = 0;
wakeup((caddr_t)&memlock);
}
}
}
if ((error) && (error != ENOMEM))
return (error);
if (uap->oldlenp) {
i = copyout(&oldlen, uap->oldlenp, sizeof(oldlen));
if (i)
return i;
}
return (error);
}
extern char hostname[MAXHOSTNAMELEN];
extern int hostnamelen;
extern char domainname[MAXHOSTNAMELEN];
extern int domainnamelen;
extern long hostid;
#ifdef INSECURE
int securelevel = -1;
#else
int securelevel;
#endif
extern int get_kernel_symfile( struct proc *, char **);
extern int sysctl_dopanicinfo(int *, u_int, void *, size_t *,
void *, size_t, struct proc *);
int
kern_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;
{
int error, level, inthostid;
unsigned int oldval=0;
char *str;
extern char ostype[], osrelease[], version[];
extern int netboot_root();
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);
switch (name[0]) {
case KERN_OSTYPE:
return (sysctl_rdstring(oldp, oldlenp, newp, ostype));
case KERN_OSRELEASE:
return (sysctl_rdstring(oldp, oldlenp, newp, osrelease));
case KERN_OSREV:
return (sysctl_rdint(oldp, oldlenp, newp, BSD));
case KERN_VERSION:
return (sysctl_rdstring(oldp, oldlenp, newp, version));
case KERN_MAXVNODES:
oldval = desiredvnodes;
error = sysctl_int(oldp, oldlenp, newp,
newlen, &desiredvnodes);
reset_vmobjectcache(oldval, desiredvnodes);
return(error);
case KERN_MAXPROC:
return (sysctl_int(oldp, oldlenp, newp, newlen, &maxproc));
case KERN_MAXFILES:
return (sysctl_int(oldp, oldlenp, newp, newlen, &maxfiles));
case KERN_ARGMAX:
return (sysctl_rdint(oldp, oldlenp, newp, ARG_MAX));
case KERN_SECURELVL:
level = securelevel;
if ((error = sysctl_int(oldp, oldlenp, newp, newlen, &level)) ||
newp == NULL)
return (error);
if (level < securelevel && p->p_pid != 1)
return (EPERM);
securelevel = level;
return (0);
case KERN_HOSTNAME:
error = sysctl_string(oldp, oldlenp, newp, newlen,
hostname, sizeof(hostname));
if (newp && !error)
hostnamelen = newlen;
return (error);
case KERN_DOMAINNAME:
error = sysctl_string(oldp, oldlenp, newp, newlen,
domainname, sizeof(domainname));
if (newp && !error)
domainnamelen = newlen;
return (error);
case KERN_HOSTID:
inthostid = hostid;
error = sysctl_int(oldp, oldlenp, newp, newlen, &inthostid);
hostid = inthostid;
return (error);
case KERN_CLOCKRATE:
return (sysctl_clockrate(oldp, oldlenp));
case KERN_BOOTTIME:
return (sysctl_rdstruct(oldp, oldlenp, newp, &boottime,
sizeof(struct timeval)));
case KERN_VNODE:
return (sysctl_vnode(oldp, oldlenp));
case KERN_PROC:
return (sysctl_doproc(name + 1, namelen - 1, oldp, oldlenp));
case KERN_FILE:
return (sysctl_file(oldp, oldlenp));
#ifdef GPROF
case KERN_PROF:
return (sysctl_doprof(name + 1, namelen - 1, oldp, oldlenp,
newp, newlen));
#endif
case KERN_POSIX1:
return (sysctl_rdint(oldp, oldlenp, newp, _POSIX_VERSION));
case KERN_NGROUPS:
return (sysctl_rdint(oldp, oldlenp, newp, NGROUPS_MAX));
case KERN_JOB_CONTROL:
return (sysctl_rdint(oldp, oldlenp, newp, 1));
case KERN_SAVED_IDS:
#ifdef _POSIX_SAVED_IDS
return (sysctl_rdint(oldp, oldlenp, newp, 1));
#else
return (sysctl_rdint(oldp, oldlenp, newp, 0));
#endif
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:
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);
}
}
#ifdef DEBUG
#if DIAGNOSTIC
extern
#endif
struct ctldebug debug0, debug1;
struct ctldebug debug2, debug3, debug4;
struct ctldebug debug5, debug6, debug7, debug8, debug9;
struct ctldebug debug10, debug11, debug12, debug13, debug14;
struct ctldebug debug15, debug16, debug17, debug18, debug19;
static struct ctldebug *debugvars[CTL_DEBUG_MAXID] = {
&debug0, &debug1, &debug2, &debug3, &debug4,
&debug5, &debug6, &debug7, &debug8, &debug9,
&debug10, &debug11, &debug12, &debug13, &debug14,
&debug15, &debug16, &debug17, &debug18, &debug19,
};
int
debug_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;
{
struct ctldebug *cdp;
if (namelen != 2)
return (ENOTDIR);
cdp = debugvars[name[0]];
if (cdp->debugname == 0)
return (EOPNOTSUPP);
switch (name[1]) {
case CTL_DEBUG_NAME:
return (sysctl_rdstring(oldp, oldlenp, newp, cdp->debugname));
case CTL_DEBUG_VALUE:
return (sysctl_int(oldp, oldlenp, newp, newlen, cdp->debugvar));
default:
return (EOPNOTSUPP);
}
}
#endif
int
sysctl_int(oldp, oldlenp, newp, newlen, valp)
void *oldp;
size_t *oldlenp;
void *newp;
size_t newlen;
int *valp;
{
int error = 0;
if (oldp && *oldlenp < sizeof(int))
return (ENOMEM);
if (newp && newlen != sizeof(int))
return (EINVAL);
*oldlenp = sizeof(int);
if (oldp)
error = copyout(valp, oldp, sizeof(int));
if (error == 0 && newp)
error = copyin(newp, valp, sizeof(int));
return (error);
}
int
sysctl_rdint(oldp, oldlenp, newp, val)
void *oldp;
size_t *oldlenp;
void *newp;
int val;
{
int error = 0;
if (oldp && *oldlenp < sizeof(int))
return (ENOMEM);
if (newp)
return (EPERM);
*oldlenp = sizeof(int);
if (oldp)
error = copyout((caddr_t)&val, oldp, sizeof(int));
return (error);
}
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);
}
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);
}
int
sysctl_string(oldp, oldlenp, newp, newlen, str, maxlen)
void *oldp;
size_t *oldlenp;
void *newp;
size_t newlen;
char *str;
int maxlen;
{
int len, error = 0;
len = strlen(str) + 1;
if (oldp && *oldlenp < len)
return (ENOMEM);
if (newp && newlen >= maxlen)
return (EINVAL);
*oldlenp = len -1;
if (oldp) {
error = copyout(str, oldp, len);
}
if (error == 0 && newp) {
error = copyin(newp, str, newlen);
str[newlen] = 0;
}
return (error);
}
int
sysctl_rdstring(oldp, oldlenp, newp, str)
void *oldp;
size_t *oldlenp;
void *newp;
char *str;
{
int len, error = 0;
len = strlen(str) + 1;
if (oldp && *oldlenp < len)
return (ENOMEM);
if (newp)
return (EPERM);
*oldlenp = len;
if (oldp)
error = copyout(str, oldp, len);
return (error);
}
int
sysctl_struct(oldp, oldlenp, newp, newlen, sp, len)
void *oldp;
size_t *oldlenp;
void *newp;
size_t newlen;
void *sp;
int len;
{
int error = 0;
if (oldp && *oldlenp < len)
return (ENOMEM);
if (newp && newlen > len)
return (EINVAL);
if (oldp) {
*oldlenp = len;
error = copyout(sp, oldp, len);
}
if (error == 0 && newp)
error = copyin(newp, sp, len);
return (error);
}
int
sysctl_rdstruct(oldp, oldlenp, newp, sp, len)
void *oldp;
size_t *oldlenp;
void *newp, *sp;
int len;
{
int error = 0;
if (oldp && *oldlenp < len)
return (ENOMEM);
if (newp)
return (EPERM);
*oldlenp = len;
if (oldp)
error = copyout(sp, oldp, len);
return (error);
}
int
sysctl_file(where, sizep)
char *where;
size_t *sizep;
{
int buflen, error;
struct file *fp;
char *start = where;
buflen = *sizep;
if (where == NULL) {
*sizep = sizeof(filehead) + (nfiles + 10) * sizeof(struct file);
return (0);
}
if (buflen < sizeof(filehead)) {
*sizep = 0;
return (0);
}
if (error = copyout((caddr_t)&filehead, where, sizeof(filehead)))
return (error);
buflen -= sizeof(filehead);
where += sizeof(filehead);
for (fp = filehead.lh_first; fp != 0; fp = fp->f_list.le_next) {
if (buflen < sizeof(struct file)) {
*sizep = where - start;
return (ENOMEM);
}
if (error = copyout((caddr_t)fp, where, sizeof (struct file)))
return (error);
buflen -= sizeof(struct file);
where += sizeof(struct file);
}
*sizep = where - start;
return (0);
}
#define KERN_PROCSLOP (5 * sizeof (struct kinfo_proc))
int
sysctl_doproc(name, namelen, where, sizep)
int *name;
u_int namelen;
char *where;
size_t *sizep;
{
register struct proc *p;
register struct kinfo_proc *dp = (struct kinfo_proc *)where;
register int needed = 0;
int buflen = where != NULL ? *sizep : 0;
int doingzomb;
struct kinfo_proc kproc;
int error = 0;
if (namelen != 2 && !(namelen == 1 && name[0] == KERN_PROC_ALL))
return (EINVAL);
p = allproc.lh_first;
doingzomb = 0;
again:
for (; p != 0; p = p->p_list.le_next) {
if (p->p_stat == SIDL)
continue;
switch (name[0]) {
case KERN_PROC_PID:
if (p->p_pid != (pid_t)name[1])
continue;
break;
case KERN_PROC_PGRP:
if (p->p_pgrp->pg_id != (pid_t)name[1])
continue;
break;
case KERN_PROC_TTY:
if ( doingzomb || (p->p_flag & P_CONTROLT) == 0 ||
p->p_session->s_ttyp == NULL ||
p->p_session->s_ttyp->t_dev != (dev_t)name[1])
continue;
break;
case KERN_PROC_UID:
if (doingzomb || (p->p_ucred->cr_uid != (uid_t)name[1]))
continue;
break;
case KERN_PROC_RUID:
if ( doingzomb || (p->p_cred->p_ruid != (uid_t)name[1]))
continue;
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)))
return (error);
dp++;
buflen -= sizeof(struct kinfo_proc);
}
needed += sizeof(struct kinfo_proc);
}
if (doingzomb == 0) {
p = zombproc.lh_first;
doingzomb++;
goto again;
}
if (where != NULL) {
*sizep = (caddr_t)dp - where;
if (needed > *sizep)
return (ENOMEM);
} else {
needed += KERN_PROCSLOP;
*sizep = needed;
}
return (0);
}
void
fill_proc(p,kp, doingzomb)
register struct proc *p;
register struct kinfo_proc *kp;
int doingzomb;
{
fill_externproc(p, &kp->kp_proc);
if (!doingzomb)
fill_eproc(p, &kp->kp_eproc);
}
void
fill_eproc(p, ep)
register struct proc *p;
register struct eproc *ep;
{
register struct tty *tp;
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_tsize = 0;
ep->e_vm.vm_dsize = 0;
ep->e_vm.vm_ssize = 0;
}
ep->e_vm.vm_rssize = 0;
if (p->p_pptr)
ep->e_ppid = p->p_pptr->p_pid;
else
ep->e_ppid = 0;
ep->e_pgid = p->p_pgrp->pg_id;
ep->e_jobc = p->p_pgrp->pg_jobc;
if ((p->p_flag & P_CONTROLT) &&
(tp = ep->e_sess->s_ttyp)) {
ep->e_tdev = tp->t_dev;
ep->e_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
ep->e_tsess = tp->t_session;
} else
ep->e_tdev = NODEV;
ep->e_flag = ep->e_sess->s_ttyvp ? EPROC_CTTY : 0;
if (SESS_LEADER(p))
ep->e_flag |= EPROC_SLEADER;
if (p->p_wmesg)
strncpy(ep->e_wmesg, p->p_wmesg, WMESGLEN);
ep->e_xsize = ep->e_xrssize = 0;
ep->e_xccount = ep->e_xswrss = 0;
}
void
fill_externproc(p, exp)
register struct proc *p;
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_stat = p->p_stat ;
exp->p_pid = p->p_pid ;
exp->p_oppid = p->p_oppid ;
exp->p_dupfd = p->p_dupfd ;
exp->user_stack = p->user_stack ;
exp->exit_thread = p->exit_thread ;
exp->p_debugger = p->p_debugger ;
exp->sigwait = p->sigwait ;
exp->p_estcpu = p->p_estcpu ;
exp->p_cpticks = p->p_cpticks ;
exp->p_pctcpu = p->p_pctcpu ;
exp->p_wchan = p->p_wchan ;
exp->p_wmesg = p->p_wmesg ;
exp->p_swtime = p->p_swtime ;
exp->p_slptime = p->p_slptime ;
bcopy(&p->p_realtimer, &exp->p_realtimer,sizeof(struct itimerval));
bcopy(&p->p_rtime, &exp->p_rtime,sizeof(struct timeval));
exp->p_uticks = p->p_uticks ;
exp->p_sticks = p->p_sticks ;
exp->p_iticks = p->p_iticks ;
exp->p_traceflag = p->p_traceflag ;
exp->p_tracep = p->p_tracep ;
exp->p_siglist = 0 ;
exp->p_textvp = p->p_textvp ;
exp->p_holdcnt = 0 ;
exp->p_sigmask = 0 ;
exp->p_sigignore = p->p_sigignore ;
exp->p_sigcatch = p->p_sigcatch ;
exp->p_priority = p->p_priority ;
exp->p_usrpri = p->p_usrpri ;
exp->p_nice = p->p_nice ;
bcopy(&p->p_comm, &exp->p_comm,MAXCOMLEN);
exp->p_comm[MAXCOMLEN] = '\0';
exp->p_pgrp = p->p_pgrp ;
exp->p_addr = NULL;
exp->p_xstat = p->p_xstat ;
exp->p_acflag = p->p_acflag ;
exp->p_ru = p->p_ru ;
}
int
kdebug_ops(name, namelen, where, sizep, p)
int *name;
u_int namelen;
char *where;
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);
if (ret = suser(p->p_ucred, &p->p_acflag))
return(ret);
switch(name[0]) {
case KERN_KDEFLAGS:
case KERN_KDDFLAGS:
case KERN_KDENABLE:
case KERN_KDGETBUF:
case KERN_KDSETUP:
case KERN_KDREMOVE:
case KERN_KDSETREG:
case KERN_KDGETREG:
case KERN_KDREADTR:
case KERN_KDPIDTR:
case KERN_KDTHRMAP:
case KERN_KDPIDEX:
case KERN_KDSETRTCDEC:
case KERN_KDSETBUF:
case KERN_KDGETENTROPY:
ret = kdbg_control(name, namelen, where, sizep);
break;
default:
ret= EOPNOTSUPP;
break;
}
return(ret);
}
int
pcsamples_ops(name, namelen, where, sizep, p)
int *name;
u_int namelen;
char *where;
size_t *sizep;
struct proc *p;
{
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);
switch(name[0]) {
case KERN_PCDISABLE:
case KERN_PCGETBUF:
case KERN_PCSETUP:
case KERN_PCREMOVE:
case KERN_PCREADBUF:
case KERN_PCSETREG:
case KERN_PCSETBUF:
case KERN_PCCOMM:
ret = pcsamples_control(name, namelen, where, sizep);
break;
default:
ret= EOPNOTSUPP;
break;
}
return(ret);
}
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;
int buflen = where != NULL ? *sizep : 0;
int error = 0;
struct vm_map *proc_map;
struct task * task;
vm_map_copy_t tmp;
vm_offset_t arg_addr;
vm_size_t arg_size;
caddr_t data;
unsigned size;
vm_offset_t copy_start, copy_end;
vm_offset_t dealloc_start;
vm_offset_t dealloc_end;
int *ip;
kern_return_t ret;
int pid;
if ((buflen <= 0) || (buflen > (PAGE_SIZE << 1))) {
return(EINVAL);
}
arg_size = buflen;
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);
task = p->task;
if (task == NULL)
return(EINVAL);
if (!task_reference_try(task)) {
mutex_pause();
goto restart;
}
ret = kmem_alloc(kernel_map, ©_start, round_page_32(arg_size));
if (ret != KERN_SUCCESS) {
task_deallocate(task);
return(ENOMEM);
}
proc_map = get_task_map(task);
copy_end = round_page_32(copy_start + arg_size);
if( vm_map_copyin(proc_map, trunc_page(arg_addr), round_page_32(arg_size),
FALSE, &tmp) != KERN_SUCCESS) {
task_deallocate(task);
kmem_free(kernel_map, copy_start,
round_page_32(arg_size));
return (EIO);
}
task_deallocate(task);
if( vm_map_copy_overwrite(kernel_map, copy_start,
tmp, FALSE) != KERN_SUCCESS) {
kmem_free(kernel_map, copy_start,
round_page_32(arg_size));
return (EIO);
}
data = (caddr_t) (copy_end - arg_size);
ip = (int *) copy_end;
size = arg_size;
ip -= 2;
while (*--ip)
if (ip == (int *)data)
break;
if (ip != (int *)data) {
while (*--ip)
if (ip == (int *)data)
break;
}
bzero(data, (unsigned) ((int)ip - (int)data));
dealloc_start = copy_start;
dealloc_end = copy_end;
size = MIN(size, buflen);
error = copyout(data, where, size);
if (dealloc_start != (vm_offset_t) 0) {
kmem_free(kernel_map, dealloc_start,
dealloc_end - dealloc_start);
}
if (error) {
return(error);
}
if (where != NULL)
*sizep = size;
return (0);
}