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*52669Smckusick * @(#)kern_sysctl.c 7.21 (Berkeley) 02/25/92 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*52669Smckusick extern int kinfo_meter(), kinfo_loadavg(), kinfo_clockrate(); 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 { 3847545Skarels int bufsize; /* max size of users buffer */ 3947545Skarels int needed, locked, (*server)(), error = 0; 4039963Smarc 4139963Smarc switch (ki_type(uap->op)) { 4239963Smarc 4339963Smarc case KINFO_PROC: 4440068Smarc server = kinfo_doproc; 4539963Smarc break; 4639963Smarc 4740068Smarc case KINFO_RT: 4840068Smarc server = kinfo_rtable; 4940068Smarc break; 5040068Smarc 5141181Smarc case KINFO_VNODE: 5241181Smarc server = kinfo_vnode; 5341181Smarc break; 5441181Smarc 5550149Smarc case KINFO_FILE: 5650149Smarc server = kinfo_file; 5750149Smarc break; 5850149Smarc 5950909Smckusick case KINFO_METER: 6050909Smckusick server = kinfo_meter; 6150909Smckusick break; 6250909Smckusick 63*52669Smckusick case KINFO_LOADAVG: 64*52669Smckusick server = kinfo_loadavg; 65*52669Smckusick break; 66*52669Smckusick 67*52669Smckusick case KINFO_CLOCKRATE: 68*52669Smckusick server = kinfo_clockrate; 69*52669Smckusick break; 70*52669Smckusick 7139963Smarc default: 7240206Smarc error = EINVAL; 7340813Smarc goto done; 7439963Smarc } 7540813Smarc if (uap->where == NULL || uap->size == NULL) { 7640813Smarc error = (*server)(uap->op, NULL, NULL, uap->arg, &needed); 7740813Smarc goto done; 7840813Smarc } 7951727Sralph if (error = copyin((caddr_t)uap->size, (caddr_t)&bufsize, 8051727Sralph sizeof (bufsize))) 8151727Sralph goto done; 8240206Smarc while (kinfo_lock.kl_lock) { 8352405Storek kinfo_lock.kl_want = 1; 8452405Storek sleep((caddr_t)&kinfo_lock, PRIBIO+1); 8540206Smarc kinfo_lock.kl_locked++; 8640206Smarc } 8752405Storek kinfo_lock.kl_lock = 1; 8840206Smarc 8940813Smarc if (!useracc(uap->where, bufsize, B_WRITE)) 9040068Smarc snderr(EFAULT); 9141181Smarc if (server != kinfo_vnode) /* XXX */ 9241181Smarc vslock(uap->where, bufsize); 9340813Smarc locked = bufsize; 9440813Smarc error = (*server)(uap->op, uap->where, &bufsize, uap->arg, &needed); 9541181Smarc if (server != kinfo_vnode) /* XXX */ 9641181Smarc vsunlock(uap->where, locked, B_WRITE); 9740813Smarc if (error == 0) 9840813Smarc error = copyout((caddr_t)&bufsize, 9940813Smarc (caddr_t)uap->size, sizeof (bufsize)); 10040068Smarc release: 10152405Storek kinfo_lock.kl_lock = 0; 10252405Storek if (kinfo_lock.kl_want) { 10352405Storek kinfo_lock.kl_want = 0; 10452405Storek wakeup((caddr_t)&kinfo_lock); 10552405Storek } 10640813Smarc done: 10743444Smckusick if (!error) 10843444Smckusick *retval = needed; 10943444Smckusick return (error); 11039963Smarc } 11139963Smarc 11239963Smarc /* 11339963Smarc * try over estimating by 5 procs 11439963Smarc */ 11539963Smarc #define KINFO_PROCSLOP (5 * sizeof (struct kinfo_proc)) 11639963Smarc 11740206Smarc kinfo_doproc(op, where, acopysize, arg, aneeded) 11852405Storek int op; 11939963Smarc char *where; 12052405Storek int *acopysize, arg, *aneeded; 12139963Smarc { 12239963Smarc register struct proc *p; 12343419Smarc register struct kinfo_proc *dp = (struct kinfo_proc *)where; 12439963Smarc register needed = 0; 12552405Storek int buflen = where != NULL ? *acopysize : 0; 12639963Smarc int doingzomb; 12740067Smarc struct eproc eproc; 12839963Smarc int error = 0; 12939963Smarc 13039963Smarc p = allproc; 13139963Smarc doingzomb = 0; 13239963Smarc again: 13339963Smarc for (; p != NULL; p = p->p_nxt) { 13439963Smarc /* 13539963Smarc * TODO - make more efficient (see notes below). 13639963Smarc * do by session. 13739963Smarc */ 13839963Smarc switch (ki_op(op)) { 13939963Smarc 14039963Smarc case KINFO_PROC_PID: 14139963Smarc /* could do this with just a lookup */ 14239963Smarc if (p->p_pid != (pid_t)arg) 14339963Smarc continue; 14439963Smarc break; 14539963Smarc 14639963Smarc case KINFO_PROC_PGRP: 14739963Smarc /* could do this by traversing pgrp */ 14839963Smarc if (p->p_pgrp->pg_id != (pid_t)arg) 14939963Smarc continue; 15039963Smarc break; 15139963Smarc 15239963Smarc case KINFO_PROC_TTY: 15339963Smarc if ((p->p_flag&SCTTY) == 0 || 15439963Smarc p->p_session->s_ttyp == NULL || 15539963Smarc p->p_session->s_ttyp->t_dev != (dev_t)arg) 15639963Smarc continue; 15739963Smarc break; 15839963Smarc 15939963Smarc case KINFO_PROC_UID: 16047545Skarels if (p->p_ucred->cr_uid != (uid_t)arg) 16139963Smarc continue; 16239963Smarc break; 16339963Smarc 16439963Smarc case KINFO_PROC_RUID: 16547545Skarels if (p->p_cred->p_ruid != (uid_t)arg) 16639963Smarc continue; 16739963Smarc break; 16839963Smarc } 16952405Storek if (buflen >= sizeof (struct kinfo_proc)) { 17048407Skarels fill_eproc(p, &eproc); 17143419Smarc if (error = copyout((caddr_t)p, &dp->kp_proc, 17239963Smarc sizeof (struct proc))) 17339963Smarc return (error); 17443419Smarc if (error = copyout((caddr_t)&eproc, &dp->kp_eproc, 17540067Smarc sizeof (eproc))) 17639963Smarc return (error); 17743419Smarc dp++; 17839963Smarc buflen -= sizeof (struct kinfo_proc); 17939963Smarc } 18039963Smarc needed += sizeof (struct kinfo_proc); 18139963Smarc } 18239963Smarc if (doingzomb == 0) { 18339963Smarc p = zombproc; 18439963Smarc doingzomb++; 18539963Smarc goto again; 18639963Smarc } 18739963Smarc if (where != NULL) 18843419Smarc *acopysize = (caddr_t)dp - where; 18940068Smarc else 19040068Smarc needed += KINFO_PROCSLOP; 19139963Smarc *aneeded = needed; 19239963Smarc 19339963Smarc return (0); 19439963Smarc } 19548407Skarels 19648407Skarels /* 19748407Skarels * Fill in an eproc structure for the specified process. 19848407Skarels */ 19948407Skarels void 20048407Skarels fill_eproc(p, ep) 20148407Skarels register struct proc *p; 20248407Skarels register struct eproc *ep; 20348407Skarels { 20448407Skarels register struct tty *tp; 20548407Skarels 20648407Skarels ep->e_paddr = p; 20748407Skarels ep->e_sess = p->p_pgrp->pg_session; 20848407Skarels ep->e_pcred = *p->p_cred; 20948407Skarels ep->e_ucred = *p->p_ucred; 21052405Storek if (p->p_stat == SIDL || p->p_stat == SZOMB) { 21152405Storek ep->e_vm.vm_rssize = 0; 21252405Storek ep->e_vm.vm_tsize = 0; 21352405Storek ep->e_vm.vm_dsize = 0; 21452405Storek ep->e_vm.vm_ssize = 0; 21552405Storek #ifndef sparc 21652405Storek /* ep->e_vm.vm_pmap = XXX; */ 21752405Storek #endif 21852405Storek } else { 21952405Storek register struct vmspace *vm = p->p_vmspace; 22052405Storek 22152405Storek ep->e_vm.vm_rssize = vm->vm_rssize; 22252405Storek ep->e_vm.vm_tsize = vm->vm_tsize; 22352405Storek ep->e_vm.vm_dsize = vm->vm_dsize; 22452405Storek ep->e_vm.vm_ssize = vm->vm_ssize; 22552405Storek #ifndef sparc 22652405Storek ep->e_vm.vm_pmap = vm->vm_pmap; 22752405Storek #endif 22852405Storek } 22949141Skarels if (p->p_pptr) 23049141Skarels ep->e_ppid = p->p_pptr->p_pid; 23149141Skarels else 23249141Skarels ep->e_ppid = 0; 23348407Skarels ep->e_pgid = p->p_pgrp->pg_id; 23448407Skarels ep->e_jobc = p->p_pgrp->pg_jobc; 23548407Skarels if ((p->p_flag&SCTTY) && 23648407Skarels (tp = ep->e_sess->s_ttyp)) { 23748407Skarels ep->e_tdev = tp->t_dev; 23850022Skarels ep->e_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID; 23948407Skarels ep->e_tsess = tp->t_session; 24048407Skarels } else 24148407Skarels ep->e_tdev = NODEV; 24248407Skarels ep->e_flag = ep->e_sess->s_ttyvp ? EPROC_CTTY : 0; 24348407Skarels if (SESS_LEADER(p)) 24448407Skarels ep->e_flag |= EPROC_SLEADER; 24548407Skarels if (p->p_wmesg) 24648407Skarels strncpy(ep->e_wmesg, p->p_wmesg, WMESGLEN); 24748407Skarels ep->e_xsize = ep->e_xrssize = 0; 24848407Skarels ep->e_xccount = ep->e_xswrss = 0; 24948407Skarels } 25050149Smarc 25150149Smarc /* 25250149Smarc * Get file structures. 25350149Smarc */ 25450149Smarc kinfo_file(op, where, acopysize, arg, aneeded) 25552405Storek int op; 25650149Smarc register char *where; 25752405Storek int *acopysize, arg, *aneeded; 25850149Smarc { 25950149Smarc int buflen, needed, error; 26050149Smarc struct file *fp; 26150149Smarc char *start = where; 26250149Smarc 26350149Smarc if (where == NULL) { 26450149Smarc /* 26550149Smarc * overestimate by 10 files 26650149Smarc */ 26750149Smarc *aneeded = sizeof (filehead) + 26850149Smarc (nfiles + 10) * sizeof (struct file); 26950149Smarc return (0); 27050149Smarc } 27150149Smarc buflen = *acopysize; 27250149Smarc needed = 0; 27350149Smarc 27450149Smarc /* 27550149Smarc * first copyout filehead 27650149Smarc */ 27750149Smarc if (buflen > sizeof (filehead)) { 27850149Smarc if (error = copyout((caddr_t)&filehead, where, 27950149Smarc sizeof (filehead))) 28050149Smarc return (error); 28150149Smarc buflen -= sizeof (filehead); 28250149Smarc where += sizeof (filehead); 28350149Smarc } 28450149Smarc needed += sizeof (filehead); 28550149Smarc 28650149Smarc /* 28750149Smarc * followed by an array of file structures 28850149Smarc */ 28950149Smarc for (fp = filehead; fp != NULL; fp = fp->f_filef) { 29050149Smarc if (buflen > sizeof (struct file)) { 29150149Smarc if (error = copyout((caddr_t)fp, where, 29250149Smarc sizeof (struct file))) 29350149Smarc return (error); 29450149Smarc buflen -= sizeof (struct file); 29550149Smarc where += sizeof (struct file); 29650149Smarc } 29750149Smarc needed += sizeof (struct file); 29850149Smarc } 29950149Smarc *acopysize = where - start; 30050149Smarc *aneeded = needed; 30150149Smarc 30250149Smarc return (0); 30350149Smarc } 304