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*50909Smckusick * @(#)kern_sysctl.c 7.18 (Berkeley) 08/28/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" 1650149Smarc #include "file.h" 1739963Smarc 1848407Skarels #include "vm/vm.h" 1948407Skarels 2048407Skarels #include "kinfo_proc.h" 2148407Skarels 2240068Smarc #define snderr(e) { error = (e); goto release;} 2350149Smarc extern int kinfo_doproc(), kinfo_rtable(), kinfo_vnode(), kinfo_file(); 24*50909Smckusick extern int kinfo_meter(); 2540068Smarc struct kinfo_lock kinfo_lock; 2640068Smarc 2743444Smckusick /* ARGSUSED */ 2843444Smckusick getkerninfo(p, uap, retval) 2943444Smckusick struct proc *p; 3043444Smckusick register struct args { 3139963Smarc int op; 3239963Smarc char *where; 3339963Smarc int *size; 3439963Smarc int arg; 3543444Smckusick } *uap; 3643444Smckusick int *retval; 3743444Smckusick { 3840206Smarc 3947545Skarels int bufsize; /* max size of users buffer */ 4047545Skarels int needed, locked, (*server)(), error = 0; 4139963Smarc 4247545Skarels if (error = copyin((caddr_t)uap->size, (caddr_t)&bufsize, 4347545Skarels sizeof (bufsize))) 4440813Smarc goto done; 4540068Smarc 4639963Smarc switch (ki_type(uap->op)) { 4739963Smarc 4839963Smarc case KINFO_PROC: 4940068Smarc server = kinfo_doproc; 5039963Smarc break; 5139963Smarc 5240068Smarc case KINFO_RT: 5340068Smarc server = kinfo_rtable; 5440068Smarc break; 5540068Smarc 5641181Smarc case KINFO_VNODE: 5741181Smarc server = kinfo_vnode; 5841181Smarc break; 5941181Smarc 6050149Smarc case KINFO_FILE: 6150149Smarc server = kinfo_file; 6250149Smarc break; 6350149Smarc 64*50909Smckusick case KINFO_METER: 65*50909Smckusick server = kinfo_meter; 66*50909Smckusick break; 67*50909Smckusick 6839963Smarc default: 6940206Smarc error = EINVAL; 7040813Smarc goto done; 7139963Smarc } 7240813Smarc if (uap->where == NULL || uap->size == NULL) { 7340813Smarc error = (*server)(uap->op, NULL, NULL, uap->arg, &needed); 7440813Smarc goto done; 7540813Smarc } 7640206Smarc while (kinfo_lock.kl_lock) { 7740206Smarc kinfo_lock.kl_want++; 7840206Smarc sleep(&kinfo_lock, PRIBIO+1); 7940206Smarc kinfo_lock.kl_want--; 8040206Smarc kinfo_lock.kl_locked++; 8140206Smarc } 8240206Smarc kinfo_lock.kl_lock++; 8340206Smarc 8440813Smarc if (!useracc(uap->where, bufsize, B_WRITE)) 8540068Smarc snderr(EFAULT); 8641181Smarc if (server != kinfo_vnode) /* XXX */ 8741181Smarc vslock(uap->where, bufsize); 8840813Smarc locked = bufsize; 8940813Smarc error = (*server)(uap->op, uap->where, &bufsize, uap->arg, &needed); 9041181Smarc if (server != kinfo_vnode) /* XXX */ 9141181Smarc vsunlock(uap->where, locked, B_WRITE); 9240813Smarc if (error == 0) 9340813Smarc error = copyout((caddr_t)&bufsize, 9440813Smarc (caddr_t)uap->size, sizeof (bufsize)); 9540068Smarc release: 9640068Smarc kinfo_lock.kl_lock--; 9740068Smarc if (kinfo_lock.kl_want) 9840068Smarc wakeup(&kinfo_lock); 9940813Smarc done: 10043444Smckusick if (!error) 10143444Smckusick *retval = needed; 10243444Smckusick return (error); 10339963Smarc } 10439963Smarc 10539963Smarc /* 10639963Smarc * try over estimating by 5 procs 10739963Smarc */ 10839963Smarc #define KINFO_PROCSLOP (5 * sizeof (struct kinfo_proc)) 10939963Smarc 11040206Smarc kinfo_doproc(op, where, acopysize, arg, aneeded) 11139963Smarc char *where; 11239963Smarc int *acopysize, *aneeded; 11339963Smarc { 11439963Smarc register struct proc *p; 11543419Smarc register struct kinfo_proc *dp = (struct kinfo_proc *)where; 11639963Smarc register needed = 0; 11739963Smarc int buflen; 11839963Smarc int doingzomb; 11940067Smarc struct eproc eproc; 12039963Smarc int error = 0; 12139963Smarc 12239963Smarc if (where != NULL) 12339963Smarc buflen = *acopysize; 12439963Smarc 12539963Smarc p = allproc; 12639963Smarc doingzomb = 0; 12739963Smarc again: 12839963Smarc for (; p != NULL; p = p->p_nxt) { 12939963Smarc /* 13039963Smarc * TODO - make more efficient (see notes below). 13139963Smarc * do by session. 13239963Smarc */ 13339963Smarc switch (ki_op(op)) { 13439963Smarc 13539963Smarc case KINFO_PROC_PID: 13639963Smarc /* could do this with just a lookup */ 13739963Smarc if (p->p_pid != (pid_t)arg) 13839963Smarc continue; 13939963Smarc break; 14039963Smarc 14139963Smarc case KINFO_PROC_PGRP: 14239963Smarc /* could do this by traversing pgrp */ 14339963Smarc if (p->p_pgrp->pg_id != (pid_t)arg) 14439963Smarc continue; 14539963Smarc break; 14639963Smarc 14739963Smarc case KINFO_PROC_TTY: 14839963Smarc if ((p->p_flag&SCTTY) == 0 || 14939963Smarc p->p_session->s_ttyp == NULL || 15039963Smarc p->p_session->s_ttyp->t_dev != (dev_t)arg) 15139963Smarc continue; 15239963Smarc break; 15339963Smarc 15439963Smarc case KINFO_PROC_UID: 15547545Skarels if (p->p_ucred->cr_uid != (uid_t)arg) 15639963Smarc continue; 15739963Smarc break; 15839963Smarc 15939963Smarc case KINFO_PROC_RUID: 16047545Skarels if (p->p_cred->p_ruid != (uid_t)arg) 16139963Smarc continue; 16239963Smarc break; 16339963Smarc } 16439963Smarc if (where != NULL && buflen >= sizeof (struct kinfo_proc)) { 16548407Skarels fill_eproc(p, &eproc); 16643419Smarc if (error = copyout((caddr_t)p, &dp->kp_proc, 16739963Smarc sizeof (struct proc))) 16839963Smarc return (error); 16943419Smarc if (error = copyout((caddr_t)&eproc, &dp->kp_eproc, 17040067Smarc sizeof (eproc))) 17139963Smarc return (error); 17243419Smarc dp++; 17339963Smarc buflen -= sizeof (struct kinfo_proc); 17439963Smarc } 17539963Smarc needed += sizeof (struct kinfo_proc); 17639963Smarc } 17739963Smarc if (doingzomb == 0) { 17839963Smarc p = zombproc; 17939963Smarc doingzomb++; 18039963Smarc goto again; 18139963Smarc } 18239963Smarc if (where != NULL) 18343419Smarc *acopysize = (caddr_t)dp - where; 18440068Smarc else 18540068Smarc needed += KINFO_PROCSLOP; 18639963Smarc *aneeded = needed; 18739963Smarc 18839963Smarc return (0); 18939963Smarc } 19048407Skarels 19148407Skarels /* 19248407Skarels * Fill in an eproc structure for the specified process. 19348407Skarels */ 19448407Skarels void 19548407Skarels fill_eproc(p, ep) 19648407Skarels register struct proc *p; 19748407Skarels register struct eproc *ep; 19848407Skarels { 19948407Skarels register struct tty *tp; 20048407Skarels 20148407Skarels ep->e_paddr = p; 20248407Skarels ep->e_sess = p->p_pgrp->pg_session; 20348407Skarels ep->e_pcred = *p->p_cred; 20448407Skarels ep->e_ucred = *p->p_ucred; 20548407Skarels ep->e_vm = *p->p_vmspace; 20649141Skarels if (p->p_pptr) 20749141Skarels ep->e_ppid = p->p_pptr->p_pid; 20849141Skarels else 20949141Skarels ep->e_ppid = 0; 21048407Skarels ep->e_pgid = p->p_pgrp->pg_id; 21148407Skarels ep->e_jobc = p->p_pgrp->pg_jobc; 21248407Skarels if ((p->p_flag&SCTTY) && 21348407Skarels (tp = ep->e_sess->s_ttyp)) { 21448407Skarels ep->e_tdev = tp->t_dev; 21550022Skarels ep->e_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID; 21648407Skarels ep->e_tsess = tp->t_session; 21748407Skarels } else 21848407Skarels ep->e_tdev = NODEV; 21948407Skarels ep->e_flag = ep->e_sess->s_ttyvp ? EPROC_CTTY : 0; 22048407Skarels if (SESS_LEADER(p)) 22148407Skarels ep->e_flag |= EPROC_SLEADER; 22248407Skarels if (p->p_wmesg) 22348407Skarels strncpy(ep->e_wmesg, p->p_wmesg, WMESGLEN); 22448407Skarels ep->e_xsize = ep->e_xrssize = 0; 22548407Skarels ep->e_xccount = ep->e_xswrss = 0; 22648407Skarels } 22750149Smarc 22850149Smarc /* 22950149Smarc * Get file structures. 23050149Smarc */ 23150149Smarc kinfo_file(op, where, acopysize, arg, aneeded) 23250149Smarc register char *where; 23350149Smarc int *acopysize, *aneeded; 23450149Smarc { 23550149Smarc int buflen, needed, error; 23650149Smarc struct file *fp; 23750149Smarc char *start = where; 23850149Smarc 23950149Smarc if (where == NULL) { 24050149Smarc /* 24150149Smarc * overestimate by 10 files 24250149Smarc */ 24350149Smarc *aneeded = sizeof (filehead) + 24450149Smarc (nfiles + 10) * sizeof (struct file); 24550149Smarc return (0); 24650149Smarc } 24750149Smarc buflen = *acopysize; 24850149Smarc needed = 0; 24950149Smarc 25050149Smarc /* 25150149Smarc * first copyout filehead 25250149Smarc */ 25350149Smarc if (buflen > sizeof (filehead)) { 25450149Smarc if (error = copyout((caddr_t)&filehead, where, 25550149Smarc sizeof (filehead))) 25650149Smarc return (error); 25750149Smarc buflen -= sizeof (filehead); 25850149Smarc where += sizeof (filehead); 25950149Smarc } 26050149Smarc needed += sizeof (filehead); 26150149Smarc 26250149Smarc /* 26350149Smarc * followed by an array of file structures 26450149Smarc */ 26550149Smarc for (fp = filehead; fp != NULL; fp = fp->f_filef) { 26650149Smarc if (buflen > sizeof (struct file)) { 26750149Smarc if (error = copyout((caddr_t)fp, where, 26850149Smarc sizeof (struct file))) 26950149Smarc return (error); 27050149Smarc buflen -= sizeof (struct file); 27150149Smarc where += sizeof (struct file); 27250149Smarc } 27350149Smarc needed += sizeof (struct file); 27450149Smarc } 27550149Smarc *acopysize = where - start; 27650149Smarc *aneeded = needed; 27750149Smarc 27850149Smarc return (0); 27950149Smarc } 280