139963Smarc /* 239963Smarc * Copyright (c) 1982, 1986, 1989 Regents of the University of California. 339963Smarc * All rights reserved. 439963Smarc * 544435Sbostic * %sccs.include.redist.c% 639963Smarc * 7*48407Skarels * @(#)kern_sysctl.c 7.14 (Berkeley) 04/20/91 839963Smarc */ 939963Smarc 1039965Smckusick #include "param.h" 1139965Smckusick #include "proc.h" 1239963Smarc #include "kinfo.h" 1339963Smarc #include "ioctl.h" 1439963Smarc #include "tty.h" 1539963Smarc #include "buf.h" 1639963Smarc 17*48407Skarels #include "vm/vm.h" 18*48407Skarels 19*48407Skarels #include "kinfo_proc.h" 20*48407Skarels 2140068Smarc #define snderr(e) { error = (e); goto release;} 2241181Smarc extern int kinfo_doproc(), kinfo_rtable(), kinfo_vnode(); 2340068Smarc struct kinfo_lock kinfo_lock; 2440068Smarc 2543444Smckusick /* ARGSUSED */ 2643444Smckusick getkerninfo(p, uap, retval) 2743444Smckusick struct proc *p; 2843444Smckusick register struct args { 2939963Smarc int op; 3039963Smarc char *where; 3139963Smarc int *size; 3239963Smarc int arg; 3343444Smckusick } *uap; 3443444Smckusick int *retval; 3543444Smckusick { 3640206Smarc 3747545Skarels int bufsize; /* max size of users buffer */ 3847545Skarels int needed, locked, (*server)(), error = 0; 3939963Smarc 4047545Skarels if (error = copyin((caddr_t)uap->size, (caddr_t)&bufsize, 4147545Skarels sizeof (bufsize))) 4240813Smarc goto done; 4340068Smarc 4439963Smarc switch (ki_type(uap->op)) { 4539963Smarc 4639963Smarc case KINFO_PROC: 4740068Smarc server = kinfo_doproc; 4839963Smarc break; 4939963Smarc 5040068Smarc case KINFO_RT: 5140068Smarc server = kinfo_rtable; 5240068Smarc break; 5340068Smarc 5441181Smarc case KINFO_VNODE: 5541181Smarc server = kinfo_vnode; 5641181Smarc break; 5741181Smarc 5839963Smarc default: 5940206Smarc error = EINVAL; 6040813Smarc goto done; 6139963Smarc } 6240813Smarc if (uap->where == NULL || uap->size == NULL) { 6340813Smarc error = (*server)(uap->op, NULL, NULL, uap->arg, &needed); 6440813Smarc goto done; 6540813Smarc } 6640206Smarc while (kinfo_lock.kl_lock) { 6740206Smarc kinfo_lock.kl_want++; 6840206Smarc sleep(&kinfo_lock, PRIBIO+1); 6940206Smarc kinfo_lock.kl_want--; 7040206Smarc kinfo_lock.kl_locked++; 7140206Smarc } 7240206Smarc kinfo_lock.kl_lock++; 7340206Smarc 7440813Smarc if (!useracc(uap->where, bufsize, B_WRITE)) 7540068Smarc snderr(EFAULT); 7641181Smarc if (server != kinfo_vnode) /* XXX */ 7741181Smarc vslock(uap->where, bufsize); 7840813Smarc locked = bufsize; 7940813Smarc error = (*server)(uap->op, uap->where, &bufsize, uap->arg, &needed); 8041181Smarc if (server != kinfo_vnode) /* XXX */ 8141181Smarc vsunlock(uap->where, locked, B_WRITE); 8240813Smarc if (error == 0) 8340813Smarc error = copyout((caddr_t)&bufsize, 8440813Smarc (caddr_t)uap->size, sizeof (bufsize)); 8540068Smarc release: 8640068Smarc kinfo_lock.kl_lock--; 8740068Smarc if (kinfo_lock.kl_want) 8840068Smarc wakeup(&kinfo_lock); 8940813Smarc done: 9043444Smckusick if (!error) 9143444Smckusick *retval = needed; 9243444Smckusick return (error); 9339963Smarc } 9439963Smarc 9539963Smarc /* 9639963Smarc * try over estimating by 5 procs 9739963Smarc */ 9839963Smarc #define KINFO_PROCSLOP (5 * sizeof (struct kinfo_proc)) 9939963Smarc 10040206Smarc kinfo_doproc(op, where, acopysize, arg, aneeded) 10139963Smarc char *where; 10239963Smarc int *acopysize, *aneeded; 10339963Smarc { 10439963Smarc register struct proc *p; 10543419Smarc register struct kinfo_proc *dp = (struct kinfo_proc *)where; 10639963Smarc register needed = 0; 10739963Smarc int buflen; 10839963Smarc int doingzomb; 10940067Smarc struct eproc eproc; 11039963Smarc int error = 0; 11139963Smarc 11239963Smarc if (where != NULL) 11339963Smarc buflen = *acopysize; 11439963Smarc 11539963Smarc p = allproc; 11639963Smarc doingzomb = 0; 11739963Smarc again: 11839963Smarc for (; p != NULL; p = p->p_nxt) { 11939963Smarc /* 12039963Smarc * TODO - make more efficient (see notes below). 12139963Smarc * do by session. 12239963Smarc */ 12339963Smarc switch (ki_op(op)) { 12439963Smarc 12539963Smarc case KINFO_PROC_PID: 12639963Smarc /* could do this with just a lookup */ 12739963Smarc if (p->p_pid != (pid_t)arg) 12839963Smarc continue; 12939963Smarc break; 13039963Smarc 13139963Smarc case KINFO_PROC_PGRP: 13239963Smarc /* could do this by traversing pgrp */ 13339963Smarc if (p->p_pgrp->pg_id != (pid_t)arg) 13439963Smarc continue; 13539963Smarc break; 13639963Smarc 13739963Smarc case KINFO_PROC_TTY: 13839963Smarc if ((p->p_flag&SCTTY) == 0 || 13939963Smarc p->p_session->s_ttyp == NULL || 14039963Smarc p->p_session->s_ttyp->t_dev != (dev_t)arg) 14139963Smarc continue; 14239963Smarc break; 14339963Smarc 14439963Smarc case KINFO_PROC_UID: 14547545Skarels if (p->p_ucred->cr_uid != (uid_t)arg) 14639963Smarc continue; 14739963Smarc break; 14839963Smarc 14939963Smarc case KINFO_PROC_RUID: 15047545Skarels if (p->p_cred->p_ruid != (uid_t)arg) 15139963Smarc continue; 15239963Smarc break; 15339963Smarc } 15439963Smarc if (where != NULL && buflen >= sizeof (struct kinfo_proc)) { 155*48407Skarels fill_eproc(p, &eproc); 15643419Smarc if (error = copyout((caddr_t)p, &dp->kp_proc, 15739963Smarc sizeof (struct proc))) 15839963Smarc return (error); 15943419Smarc if (error = copyout((caddr_t)&eproc, &dp->kp_eproc, 16040067Smarc sizeof (eproc))) 16139963Smarc return (error); 16243419Smarc dp++; 16339963Smarc buflen -= sizeof (struct kinfo_proc); 16439963Smarc } 16539963Smarc needed += sizeof (struct kinfo_proc); 16639963Smarc } 16739963Smarc if (doingzomb == 0) { 16839963Smarc p = zombproc; 16939963Smarc doingzomb++; 17039963Smarc goto again; 17139963Smarc } 17239963Smarc if (where != NULL) 17343419Smarc *acopysize = (caddr_t)dp - where; 17440068Smarc else 17540068Smarc needed += KINFO_PROCSLOP; 17639963Smarc *aneeded = needed; 17739963Smarc 17839963Smarc return (0); 17939963Smarc } 180*48407Skarels 181*48407Skarels /* 182*48407Skarels * Fill in an eproc structure for the specified process. 183*48407Skarels */ 184*48407Skarels void 185*48407Skarels fill_eproc(p, ep) 186*48407Skarels register struct proc *p; 187*48407Skarels register struct eproc *ep; 188*48407Skarels { 189*48407Skarels register struct tty *tp; 190*48407Skarels 191*48407Skarels ep->e_paddr = p; 192*48407Skarels ep->e_sess = p->p_pgrp->pg_session; 193*48407Skarels ep->e_pcred = *p->p_cred; 194*48407Skarels ep->e_ucred = *p->p_ucred; 195*48407Skarels ep->e_vm = *p->p_vmspace; 196*48407Skarels ep->e_ppid = p->p_pptr->p_pid; 197*48407Skarels ep->e_pgid = p->p_pgrp->pg_id; 198*48407Skarels ep->e_jobc = p->p_pgrp->pg_jobc; 199*48407Skarels if ((p->p_flag&SCTTY) && 200*48407Skarels (tp = ep->e_sess->s_ttyp)) { 201*48407Skarels ep->e_tdev = tp->t_dev; 202*48407Skarels ep->e_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : -1; 203*48407Skarels ep->e_tsess = tp->t_session; 204*48407Skarels } else 205*48407Skarels ep->e_tdev = NODEV; 206*48407Skarels ep->e_flag = ep->e_sess->s_ttyvp ? EPROC_CTTY : 0; 207*48407Skarels if (SESS_LEADER(p)) 208*48407Skarels ep->e_flag |= EPROC_SLEADER; 209*48407Skarels if (p->p_wmesg) 210*48407Skarels strncpy(ep->e_wmesg, p->p_wmesg, WMESGLEN); 211*48407Skarels ep->e_xsize = ep->e_xrssize = 0; 212*48407Skarels ep->e_xccount = ep->e_xswrss = 0; 213*48407Skarels } 214