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*50149Smarc * @(#)kern_sysctl.c 7.17 (Berkeley) 06/26/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" 16*50149Smarc #include "file.h" 1739963Smarc 1848407Skarels #include "vm/vm.h" 1948407Skarels 2048407Skarels #include "kinfo_proc.h" 2148407Skarels 2240068Smarc #define snderr(e) { error = (e); goto release;} 23*50149Smarc extern int kinfo_doproc(), kinfo_rtable(), kinfo_vnode(), kinfo_file(); 2440068Smarc struct kinfo_lock kinfo_lock; 2540068Smarc 2643444Smckusick /* ARGSUSED */ 2743444Smckusick getkerninfo(p, uap, retval) 2843444Smckusick struct proc *p; 2943444Smckusick register struct args { 3039963Smarc int op; 3139963Smarc char *where; 3239963Smarc int *size; 3339963Smarc int arg; 3443444Smckusick } *uap; 3543444Smckusick int *retval; 3643444Smckusick { 3740206Smarc 3847545Skarels int bufsize; /* max size of users buffer */ 3947545Skarels int needed, locked, (*server)(), error = 0; 4039963Smarc 4147545Skarels if (error = copyin((caddr_t)uap->size, (caddr_t)&bufsize, 4247545Skarels sizeof (bufsize))) 4340813Smarc goto done; 4440068Smarc 4539963Smarc switch (ki_type(uap->op)) { 4639963Smarc 4739963Smarc case KINFO_PROC: 4840068Smarc server = kinfo_doproc; 4939963Smarc break; 5039963Smarc 5140068Smarc case KINFO_RT: 5240068Smarc server = kinfo_rtable; 5340068Smarc break; 5440068Smarc 5541181Smarc case KINFO_VNODE: 5641181Smarc server = kinfo_vnode; 5741181Smarc break; 5841181Smarc 59*50149Smarc case KINFO_FILE: 60*50149Smarc server = kinfo_file; 61*50149Smarc break; 62*50149Smarc 6339963Smarc default: 6440206Smarc error = EINVAL; 6540813Smarc goto done; 6639963Smarc } 6740813Smarc if (uap->where == NULL || uap->size == NULL) { 6840813Smarc error = (*server)(uap->op, NULL, NULL, uap->arg, &needed); 6940813Smarc goto done; 7040813Smarc } 7140206Smarc while (kinfo_lock.kl_lock) { 7240206Smarc kinfo_lock.kl_want++; 7340206Smarc sleep(&kinfo_lock, PRIBIO+1); 7440206Smarc kinfo_lock.kl_want--; 7540206Smarc kinfo_lock.kl_locked++; 7640206Smarc } 7740206Smarc kinfo_lock.kl_lock++; 7840206Smarc 7940813Smarc if (!useracc(uap->where, bufsize, B_WRITE)) 8040068Smarc snderr(EFAULT); 8141181Smarc if (server != kinfo_vnode) /* XXX */ 8241181Smarc vslock(uap->where, bufsize); 8340813Smarc locked = bufsize; 8440813Smarc error = (*server)(uap->op, uap->where, &bufsize, uap->arg, &needed); 8541181Smarc if (server != kinfo_vnode) /* XXX */ 8641181Smarc vsunlock(uap->where, locked, B_WRITE); 8740813Smarc if (error == 0) 8840813Smarc error = copyout((caddr_t)&bufsize, 8940813Smarc (caddr_t)uap->size, sizeof (bufsize)); 9040068Smarc release: 9140068Smarc kinfo_lock.kl_lock--; 9240068Smarc if (kinfo_lock.kl_want) 9340068Smarc wakeup(&kinfo_lock); 9440813Smarc done: 9543444Smckusick if (!error) 9643444Smckusick *retval = needed; 9743444Smckusick return (error); 9839963Smarc } 9939963Smarc 10039963Smarc /* 10139963Smarc * try over estimating by 5 procs 10239963Smarc */ 10339963Smarc #define KINFO_PROCSLOP (5 * sizeof (struct kinfo_proc)) 10439963Smarc 10540206Smarc kinfo_doproc(op, where, acopysize, arg, aneeded) 10639963Smarc char *where; 10739963Smarc int *acopysize, *aneeded; 10839963Smarc { 10939963Smarc register struct proc *p; 11043419Smarc register struct kinfo_proc *dp = (struct kinfo_proc *)where; 11139963Smarc register needed = 0; 11239963Smarc int buflen; 11339963Smarc int doingzomb; 11440067Smarc struct eproc eproc; 11539963Smarc int error = 0; 11639963Smarc 11739963Smarc if (where != NULL) 11839963Smarc buflen = *acopysize; 11939963Smarc 12039963Smarc p = allproc; 12139963Smarc doingzomb = 0; 12239963Smarc again: 12339963Smarc for (; p != NULL; p = p->p_nxt) { 12439963Smarc /* 12539963Smarc * TODO - make more efficient (see notes below). 12639963Smarc * do by session. 12739963Smarc */ 12839963Smarc switch (ki_op(op)) { 12939963Smarc 13039963Smarc case KINFO_PROC_PID: 13139963Smarc /* could do this with just a lookup */ 13239963Smarc if (p->p_pid != (pid_t)arg) 13339963Smarc continue; 13439963Smarc break; 13539963Smarc 13639963Smarc case KINFO_PROC_PGRP: 13739963Smarc /* could do this by traversing pgrp */ 13839963Smarc if (p->p_pgrp->pg_id != (pid_t)arg) 13939963Smarc continue; 14039963Smarc break; 14139963Smarc 14239963Smarc case KINFO_PROC_TTY: 14339963Smarc if ((p->p_flag&SCTTY) == 0 || 14439963Smarc p->p_session->s_ttyp == NULL || 14539963Smarc p->p_session->s_ttyp->t_dev != (dev_t)arg) 14639963Smarc continue; 14739963Smarc break; 14839963Smarc 14939963Smarc case KINFO_PROC_UID: 15047545Skarels if (p->p_ucred->cr_uid != (uid_t)arg) 15139963Smarc continue; 15239963Smarc break; 15339963Smarc 15439963Smarc case KINFO_PROC_RUID: 15547545Skarels if (p->p_cred->p_ruid != (uid_t)arg) 15639963Smarc continue; 15739963Smarc break; 15839963Smarc } 15939963Smarc if (where != NULL && buflen >= sizeof (struct kinfo_proc)) { 16048407Skarels fill_eproc(p, &eproc); 16143419Smarc if (error = copyout((caddr_t)p, &dp->kp_proc, 16239963Smarc sizeof (struct proc))) 16339963Smarc return (error); 16443419Smarc if (error = copyout((caddr_t)&eproc, &dp->kp_eproc, 16540067Smarc sizeof (eproc))) 16639963Smarc return (error); 16743419Smarc dp++; 16839963Smarc buflen -= sizeof (struct kinfo_proc); 16939963Smarc } 17039963Smarc needed += sizeof (struct kinfo_proc); 17139963Smarc } 17239963Smarc if (doingzomb == 0) { 17339963Smarc p = zombproc; 17439963Smarc doingzomb++; 17539963Smarc goto again; 17639963Smarc } 17739963Smarc if (where != NULL) 17843419Smarc *acopysize = (caddr_t)dp - where; 17940068Smarc else 18040068Smarc needed += KINFO_PROCSLOP; 18139963Smarc *aneeded = needed; 18239963Smarc 18339963Smarc return (0); 18439963Smarc } 18548407Skarels 18648407Skarels /* 18748407Skarels * Fill in an eproc structure for the specified process. 18848407Skarels */ 18948407Skarels void 19048407Skarels fill_eproc(p, ep) 19148407Skarels register struct proc *p; 19248407Skarels register struct eproc *ep; 19348407Skarels { 19448407Skarels register struct tty *tp; 19548407Skarels 19648407Skarels ep->e_paddr = p; 19748407Skarels ep->e_sess = p->p_pgrp->pg_session; 19848407Skarels ep->e_pcred = *p->p_cred; 19948407Skarels ep->e_ucred = *p->p_ucred; 20048407Skarels ep->e_vm = *p->p_vmspace; 20149141Skarels if (p->p_pptr) 20249141Skarels ep->e_ppid = p->p_pptr->p_pid; 20349141Skarels else 20449141Skarels ep->e_ppid = 0; 20548407Skarels ep->e_pgid = p->p_pgrp->pg_id; 20648407Skarels ep->e_jobc = p->p_pgrp->pg_jobc; 20748407Skarels if ((p->p_flag&SCTTY) && 20848407Skarels (tp = ep->e_sess->s_ttyp)) { 20948407Skarels ep->e_tdev = tp->t_dev; 21050022Skarels ep->e_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID; 21148407Skarels ep->e_tsess = tp->t_session; 21248407Skarels } else 21348407Skarels ep->e_tdev = NODEV; 21448407Skarels ep->e_flag = ep->e_sess->s_ttyvp ? EPROC_CTTY : 0; 21548407Skarels if (SESS_LEADER(p)) 21648407Skarels ep->e_flag |= EPROC_SLEADER; 21748407Skarels if (p->p_wmesg) 21848407Skarels strncpy(ep->e_wmesg, p->p_wmesg, WMESGLEN); 21948407Skarels ep->e_xsize = ep->e_xrssize = 0; 22048407Skarels ep->e_xccount = ep->e_xswrss = 0; 22148407Skarels } 222*50149Smarc 223*50149Smarc /* 224*50149Smarc * Get file structures. 225*50149Smarc */ 226*50149Smarc kinfo_file(op, where, acopysize, arg, aneeded) 227*50149Smarc register char *where; 228*50149Smarc int *acopysize, *aneeded; 229*50149Smarc { 230*50149Smarc int buflen, needed, error; 231*50149Smarc struct file *fp; 232*50149Smarc char *start = where; 233*50149Smarc 234*50149Smarc if (where == NULL) { 235*50149Smarc /* 236*50149Smarc * overestimate by 10 files 237*50149Smarc */ 238*50149Smarc *aneeded = sizeof (filehead) + 239*50149Smarc (nfiles + 10) * sizeof (struct file); 240*50149Smarc return (0); 241*50149Smarc } 242*50149Smarc buflen = *acopysize; 243*50149Smarc needed = 0; 244*50149Smarc 245*50149Smarc /* 246*50149Smarc * first copyout filehead 247*50149Smarc */ 248*50149Smarc if (buflen > sizeof (filehead)) { 249*50149Smarc if (error = copyout((caddr_t)&filehead, where, 250*50149Smarc sizeof (filehead))) 251*50149Smarc return (error); 252*50149Smarc buflen -= sizeof (filehead); 253*50149Smarc where += sizeof (filehead); 254*50149Smarc } 255*50149Smarc needed += sizeof (filehead); 256*50149Smarc 257*50149Smarc /* 258*50149Smarc * followed by an array of file structures 259*50149Smarc */ 260*50149Smarc for (fp = filehead; fp != NULL; fp = fp->f_filef) { 261*50149Smarc if (buflen > sizeof (struct file)) { 262*50149Smarc if (error = copyout((caddr_t)fp, where, 263*50149Smarc sizeof (struct file))) 264*50149Smarc return (error); 265*50149Smarc buflen -= sizeof (struct file); 266*50149Smarc where += sizeof (struct file); 267*50149Smarc } 268*50149Smarc needed += sizeof (struct file); 269*50149Smarc } 270*50149Smarc *acopysize = where - start; 271*50149Smarc *aneeded = needed; 272*50149Smarc 273*50149Smarc return (0); 274*50149Smarc } 275