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*56517Sbostic * @(#)kern_sysctl.c 7.25 (Berkeley) 10/11/92 839963Smarc */ 939963Smarc 10*56517Sbostic #include <sys/param.h> 11*56517Sbostic #include <sys/proc.h> 12*56517Sbostic #include <sys/kinfo.h> 13*56517Sbostic #include <sys/ioctl.h> 14*56517Sbostic #include <sys/tty.h> 15*56517Sbostic #include <sys/buf.h> 16*56517Sbostic #include <sys/file.h> 1739963Smarc 18*56517Sbostic #include <vm/vm.h> 1948407Skarels 20*56517Sbostic #include <sys/kinfo_proc.h> 2148407Skarels 2240068Smarc #define snderr(e) { error = (e); goto release;} 2350149Smarc extern int kinfo_doproc(), kinfo_rtable(), kinfo_vnode(), kinfo_file(); 2452669Smckusick extern int kinfo_meter(), kinfo_loadavg(), kinfo_clockrate(); 2540068Smarc struct kinfo_lock kinfo_lock; 2640068Smarc 2754923Storek struct getkerninfo_args { 2854923Storek int op; 2954923Storek char *where; 3054923Storek int *size; 3154923Storek int arg; 3254923Storek }; 3343444Smckusick /* ARGSUSED */ 3443444Smckusick getkerninfo(p, uap, retval) 3543444Smckusick struct proc *p; 3654923Storek register struct getkerninfo_args *uap; 3743444Smckusick int *retval; 3843444Smckusick { 3947545Skarels int bufsize; /* max size of users buffer */ 4047545Skarels int needed, locked, (*server)(), error = 0; 4139963Smarc 4239963Smarc switch (ki_type(uap->op)) { 4339963Smarc 4439963Smarc case KINFO_PROC: 4540068Smarc server = kinfo_doproc; 4639963Smarc break; 4739963Smarc 4840068Smarc case KINFO_RT: 4940068Smarc server = kinfo_rtable; 5040068Smarc break; 5140068Smarc 5241181Smarc case KINFO_VNODE: 5341181Smarc server = kinfo_vnode; 5441181Smarc break; 5541181Smarc 5650149Smarc case KINFO_FILE: 5750149Smarc server = kinfo_file; 5850149Smarc break; 5950149Smarc 6050909Smckusick case KINFO_METER: 6150909Smckusick server = kinfo_meter; 6250909Smckusick break; 6350909Smckusick 6452669Smckusick case KINFO_LOADAVG: 6552669Smckusick server = kinfo_loadavg; 6652669Smckusick break; 6752669Smckusick 6852669Smckusick case KINFO_CLOCKRATE: 6952669Smckusick server = kinfo_clockrate; 7052669Smckusick break; 7152669Smckusick 7239963Smarc default: 7340206Smarc error = EINVAL; 7440813Smarc goto done; 7539963Smarc } 7640813Smarc if (uap->where == NULL || uap->size == NULL) { 7740813Smarc error = (*server)(uap->op, NULL, NULL, uap->arg, &needed); 7840813Smarc goto done; 7940813Smarc } 8051727Sralph if (error = copyin((caddr_t)uap->size, (caddr_t)&bufsize, 8151727Sralph sizeof (bufsize))) 8251727Sralph goto done; 8340206Smarc while (kinfo_lock.kl_lock) { 8452405Storek kinfo_lock.kl_want = 1; 8552405Storek sleep((caddr_t)&kinfo_lock, PRIBIO+1); 8640206Smarc kinfo_lock.kl_locked++; 8740206Smarc } 8852405Storek kinfo_lock.kl_lock = 1; 8940206Smarc 9040813Smarc if (!useracc(uap->where, bufsize, B_WRITE)) 9140068Smarc snderr(EFAULT); 9241181Smarc if (server != kinfo_vnode) /* XXX */ 9341181Smarc vslock(uap->where, bufsize); 9440813Smarc locked = bufsize; 9540813Smarc error = (*server)(uap->op, uap->where, &bufsize, uap->arg, &needed); 9641181Smarc if (server != kinfo_vnode) /* XXX */ 9741181Smarc vsunlock(uap->where, locked, B_WRITE); 9840813Smarc if (error == 0) 9940813Smarc error = copyout((caddr_t)&bufsize, 10040813Smarc (caddr_t)uap->size, sizeof (bufsize)); 10140068Smarc release: 10252405Storek kinfo_lock.kl_lock = 0; 10352405Storek if (kinfo_lock.kl_want) { 10452405Storek kinfo_lock.kl_want = 0; 10552405Storek wakeup((caddr_t)&kinfo_lock); 10652405Storek } 10740813Smarc done: 10843444Smckusick if (!error) 10943444Smckusick *retval = needed; 11043444Smckusick return (error); 11139963Smarc } 11239963Smarc 11339963Smarc /* 11439963Smarc * try over estimating by 5 procs 11539963Smarc */ 11639963Smarc #define KINFO_PROCSLOP (5 * sizeof (struct kinfo_proc)) 11739963Smarc 11840206Smarc kinfo_doproc(op, where, acopysize, arg, aneeded) 11952405Storek int op; 12039963Smarc char *where; 12152405Storek int *acopysize, arg, *aneeded; 12239963Smarc { 12339963Smarc register struct proc *p; 12443419Smarc register struct kinfo_proc *dp = (struct kinfo_proc *)where; 12539963Smarc register needed = 0; 12652405Storek int buflen = where != NULL ? *acopysize : 0; 12739963Smarc int doingzomb; 12840067Smarc struct eproc eproc; 12939963Smarc int error = 0; 13039963Smarc 13154755Storek p = (struct proc *)allproc; 13239963Smarc doingzomb = 0; 13339963Smarc again: 13439963Smarc for (; p != NULL; p = p->p_nxt) { 13553819Smckusick /* 13653819Smckusick * Skip embryonic processes. 13753819Smckusick */ 13853819Smckusick if (p->p_stat == SIDL) 13953819Smckusick continue; 14039963Smarc /* 14139963Smarc * TODO - make more efficient (see notes below). 14239963Smarc * do by session. 14339963Smarc */ 14439963Smarc switch (ki_op(op)) { 14539963Smarc 14639963Smarc case KINFO_PROC_PID: 14739963Smarc /* could do this with just a lookup */ 14839963Smarc if (p->p_pid != (pid_t)arg) 14939963Smarc continue; 15039963Smarc break; 15139963Smarc 15239963Smarc case KINFO_PROC_PGRP: 15339963Smarc /* could do this by traversing pgrp */ 15439963Smarc if (p->p_pgrp->pg_id != (pid_t)arg) 15539963Smarc continue; 15639963Smarc break; 15739963Smarc 15839963Smarc case KINFO_PROC_TTY: 15939963Smarc if ((p->p_flag&SCTTY) == 0 || 16039963Smarc p->p_session->s_ttyp == NULL || 16139963Smarc p->p_session->s_ttyp->t_dev != (dev_t)arg) 16239963Smarc continue; 16339963Smarc break; 16439963Smarc 16539963Smarc case KINFO_PROC_UID: 16647545Skarels if (p->p_ucred->cr_uid != (uid_t)arg) 16739963Smarc continue; 16839963Smarc break; 16939963Smarc 17039963Smarc case KINFO_PROC_RUID: 17147545Skarels if (p->p_cred->p_ruid != (uid_t)arg) 17239963Smarc continue; 17339963Smarc break; 17439963Smarc } 17552405Storek if (buflen >= sizeof (struct kinfo_proc)) { 17648407Skarels fill_eproc(p, &eproc); 17743419Smarc if (error = copyout((caddr_t)p, &dp->kp_proc, 17839963Smarc sizeof (struct proc))) 17939963Smarc return (error); 18043419Smarc if (error = copyout((caddr_t)&eproc, &dp->kp_eproc, 18140067Smarc sizeof (eproc))) 18239963Smarc return (error); 18343419Smarc dp++; 18439963Smarc buflen -= sizeof (struct kinfo_proc); 18539963Smarc } 18639963Smarc needed += sizeof (struct kinfo_proc); 18739963Smarc } 18839963Smarc if (doingzomb == 0) { 18939963Smarc p = zombproc; 19039963Smarc doingzomb++; 19139963Smarc goto again; 19239963Smarc } 19339963Smarc if (where != NULL) 19443419Smarc *acopysize = (caddr_t)dp - where; 19540068Smarc else 19640068Smarc needed += KINFO_PROCSLOP; 19739963Smarc *aneeded = needed; 19839963Smarc 19939963Smarc return (0); 20039963Smarc } 20148407Skarels 20248407Skarels /* 20348407Skarels * Fill in an eproc structure for the specified process. 20448407Skarels */ 20548407Skarels void 20648407Skarels fill_eproc(p, ep) 20748407Skarels register struct proc *p; 20848407Skarels register struct eproc *ep; 20948407Skarels { 21048407Skarels register struct tty *tp; 21148407Skarels 21248407Skarels ep->e_paddr = p; 21348407Skarels ep->e_sess = p->p_pgrp->pg_session; 21448407Skarels ep->e_pcred = *p->p_cred; 21548407Skarels ep->e_ucred = *p->p_ucred; 21652405Storek if (p->p_stat == SIDL || p->p_stat == SZOMB) { 21752405Storek ep->e_vm.vm_rssize = 0; 21852405Storek ep->e_vm.vm_tsize = 0; 21952405Storek ep->e_vm.vm_dsize = 0; 22052405Storek ep->e_vm.vm_ssize = 0; 22152405Storek #ifndef sparc 22252405Storek /* ep->e_vm.vm_pmap = XXX; */ 22352405Storek #endif 22452405Storek } else { 22552405Storek register struct vmspace *vm = p->p_vmspace; 22652405Storek 22752405Storek ep->e_vm.vm_rssize = vm->vm_rssize; 22852405Storek ep->e_vm.vm_tsize = vm->vm_tsize; 22952405Storek ep->e_vm.vm_dsize = vm->vm_dsize; 23052405Storek ep->e_vm.vm_ssize = vm->vm_ssize; 23152405Storek #ifndef sparc 23252405Storek ep->e_vm.vm_pmap = vm->vm_pmap; 23352405Storek #endif 23452405Storek } 23549141Skarels if (p->p_pptr) 23649141Skarels ep->e_ppid = p->p_pptr->p_pid; 23749141Skarels else 23849141Skarels ep->e_ppid = 0; 23948407Skarels ep->e_pgid = p->p_pgrp->pg_id; 24048407Skarels ep->e_jobc = p->p_pgrp->pg_jobc; 24148407Skarels if ((p->p_flag&SCTTY) && 24248407Skarels (tp = ep->e_sess->s_ttyp)) { 24348407Skarels ep->e_tdev = tp->t_dev; 24450022Skarels ep->e_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID; 24548407Skarels ep->e_tsess = tp->t_session; 24648407Skarels } else 24748407Skarels ep->e_tdev = NODEV; 24848407Skarels ep->e_flag = ep->e_sess->s_ttyvp ? EPROC_CTTY : 0; 24948407Skarels if (SESS_LEADER(p)) 25048407Skarels ep->e_flag |= EPROC_SLEADER; 25148407Skarels if (p->p_wmesg) 25248407Skarels strncpy(ep->e_wmesg, p->p_wmesg, WMESGLEN); 25348407Skarels ep->e_xsize = ep->e_xrssize = 0; 25448407Skarels ep->e_xccount = ep->e_xswrss = 0; 25548407Skarels } 25650149Smarc 25750149Smarc /* 25850149Smarc * Get file structures. 25950149Smarc */ 26050149Smarc kinfo_file(op, where, acopysize, arg, aneeded) 26152405Storek int op; 26250149Smarc register char *where; 26352405Storek int *acopysize, arg, *aneeded; 26450149Smarc { 26550149Smarc int buflen, needed, error; 26650149Smarc struct file *fp; 26750149Smarc char *start = where; 26850149Smarc 26950149Smarc if (where == NULL) { 27050149Smarc /* 27150149Smarc * overestimate by 10 files 27250149Smarc */ 27350149Smarc *aneeded = sizeof (filehead) + 27450149Smarc (nfiles + 10) * sizeof (struct file); 27550149Smarc return (0); 27650149Smarc } 27750149Smarc buflen = *acopysize; 27850149Smarc needed = 0; 27950149Smarc 28050149Smarc /* 28150149Smarc * first copyout filehead 28250149Smarc */ 28350149Smarc if (buflen > sizeof (filehead)) { 28450149Smarc if (error = copyout((caddr_t)&filehead, where, 28550149Smarc sizeof (filehead))) 28650149Smarc return (error); 28750149Smarc buflen -= sizeof (filehead); 28850149Smarc where += sizeof (filehead); 28950149Smarc } 29050149Smarc needed += sizeof (filehead); 29150149Smarc 29250149Smarc /* 29350149Smarc * followed by an array of file structures 29450149Smarc */ 29550149Smarc for (fp = filehead; fp != NULL; fp = fp->f_filef) { 29650149Smarc if (buflen > sizeof (struct file)) { 29750149Smarc if (error = copyout((caddr_t)fp, where, 29850149Smarc sizeof (struct file))) 29950149Smarc return (error); 30050149Smarc buflen -= sizeof (struct file); 30150149Smarc where += sizeof (struct file); 30250149Smarc } 30350149Smarc needed += sizeof (struct file); 30450149Smarc } 30550149Smarc *acopysize = where - start; 30650149Smarc *aneeded = needed; 30750149Smarc 30850149Smarc return (0); 30950149Smarc } 310