139963Smarc /* 239963Smarc * Copyright (c) 1982, 1986, 1989 Regents of the University of California. 339963Smarc * All rights reserved. 439963Smarc * 539963Smarc * Redistribution and use in source and binary forms are permitted 639963Smarc * provided that the above copyright notice and this paragraph are 739963Smarc * duplicated in all such forms and that any documentation, 839963Smarc * advertising materials, and other materials related to such 939963Smarc * distribution and use acknowledge that the software was developed 1039963Smarc * by the University of California, Berkeley. The name of the 1139963Smarc * University may not be used to endorse or promote products derived 1239963Smarc * from this software without specific prior written permission. 1339963Smarc * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1439963Smarc * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1539963Smarc * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1639963Smarc * 17*43444Smckusick * @(#)kern_sysctl.c 7.10 (Berkeley) 06/22/90 1839963Smarc */ 1939963Smarc 2039965Smckusick #include "param.h" 2139965Smckusick #include "user.h" 2239965Smckusick #include "proc.h" 2340206Smarc #include "text.h" 2439963Smarc #include "kinfo.h" 2539963Smarc #include "vm.h" 2639963Smarc #include "ioctl.h" 2739963Smarc #include "tty.h" 2839963Smarc #include "buf.h" 2939963Smarc 3040068Smarc 3140068Smarc #define snderr(e) { error = (e); goto release;} 3241181Smarc extern int kinfo_doproc(), kinfo_rtable(), kinfo_vnode(); 3340068Smarc struct kinfo_lock kinfo_lock; 3440068Smarc 35*43444Smckusick /* ARGSUSED */ 36*43444Smckusick getkerninfo(p, uap, retval) 37*43444Smckusick struct proc *p; 38*43444Smckusick register struct args { 3939963Smarc int op; 4039963Smarc char *where; 4139963Smarc int *size; 4239963Smarc int arg; 43*43444Smckusick } *uap; 44*43444Smckusick int *retval; 45*43444Smckusick { 4640206Smarc 4740068Smarc int bufsize, /* max size of users buffer */ 4840206Smarc needed, locked, (*server)(), error = 0; 4939963Smarc 5040206Smarc if (error = copyin((caddr_t)uap->size, 5140206Smarc (caddr_t)&bufsize, sizeof (bufsize))) 5240813Smarc goto done; 5340068Smarc 5439963Smarc switch (ki_type(uap->op)) { 5539963Smarc 5639963Smarc case KINFO_PROC: 5740068Smarc server = kinfo_doproc; 5839963Smarc break; 5939963Smarc 6040068Smarc case KINFO_RT: 6140068Smarc server = kinfo_rtable; 6240068Smarc break; 6340068Smarc 6441181Smarc case KINFO_VNODE: 6541181Smarc server = kinfo_vnode; 6641181Smarc break; 6741181Smarc 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); 8640068Smarc /* 8740068Smarc * lock down target pages - NEED DEADLOCK AVOIDANCE 8840068Smarc */ 8940813Smarc if (bufsize > ((int)ptob(freemem) - (20 * 1024))) /* XXX */ 9040068Smarc snderr(ENOMEM); 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: 10140068Smarc kinfo_lock.kl_lock--; 10240068Smarc if (kinfo_lock.kl_want) 10340068Smarc wakeup(&kinfo_lock); 10440813Smarc done: 105*43444Smckusick if (!error) 106*43444Smckusick *retval = needed; 107*43444Smckusick return (error); 10839963Smarc } 10939963Smarc 11039963Smarc /* 11139963Smarc * try over estimating by 5 procs 11239963Smarc */ 11339963Smarc #define KINFO_PROCSLOP (5 * sizeof (struct kinfo_proc)) 11439963Smarc 11540206Smarc kinfo_doproc(op, where, acopysize, arg, aneeded) 11639963Smarc char *where; 11739963Smarc int *acopysize, *aneeded; 11839963Smarc { 11939963Smarc register struct proc *p; 12043419Smarc register struct kinfo_proc *dp = (struct kinfo_proc *)where; 12139963Smarc register needed = 0; 12239963Smarc int buflen; 12339963Smarc int doingzomb; 12440067Smarc struct eproc eproc; 12539963Smarc int error = 0; 12639963Smarc 12739963Smarc if (where != NULL) 12839963Smarc buflen = *acopysize; 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: 16039963Smarc if (p->p_uid != (uid_t)arg) 16139963Smarc continue; 16239963Smarc break; 16339963Smarc 16439963Smarc case KINFO_PROC_RUID: 16539963Smarc if (p->p_ruid != (uid_t)arg) 16639963Smarc continue; 16739963Smarc break; 16839963Smarc } 16939963Smarc if (where != NULL && buflen >= sizeof (struct kinfo_proc)) { 17040206Smarc register struct text *txt; 17143419Smarc register struct tty *tp; 17240206Smarc 17343419Smarc if (error = copyout((caddr_t)p, &dp->kp_proc, 17439963Smarc sizeof (struct proc))) 17539963Smarc return (error); 17640206Smarc eproc.e_paddr = p; 17740206Smarc eproc.e_sess = p->p_pgrp->pg_session; 17840206Smarc eproc.e_pgid = p->p_pgrp->pg_id; 17940206Smarc eproc.e_jobc = p->p_pgrp->pg_jobc; 18043419Smarc if ((p->p_flag&SCTTY) && 18143419Smarc (tp = eproc.e_sess->s_ttyp)) { 18240206Smarc eproc.e_tdev = tp->t_dev; 18340206Smarc eproc.e_tpgid = tp->t_pgrp ? 18439963Smarc tp->t_pgrp->pg_id : -1; 18540206Smarc eproc.e_tsess = tp->t_session; 18639963Smarc } else 18740206Smarc eproc.e_tdev = NODEV; 18843419Smarc eproc.e_flag = eproc.e_sess->s_ttyvp ? EPROC_CTTY : 0; 18943419Smarc if (SESS_LEADER(p)) 19043419Smarc eproc.e_flag |= EPROC_SLEADER; 19140206Smarc if (p->p_wmesg) 19240206Smarc strncpy(eproc.e_wmesg, p->p_wmesg, WMESGLEN); 19340206Smarc if (txt = p->p_textp) { 19440206Smarc eproc.e_xsize = txt->x_size; 19540206Smarc eproc.e_xrssize = txt->x_rssize; 19640206Smarc eproc.e_xccount = txt->x_ccount; 19740206Smarc eproc.e_xswrss = txt->x_swrss; 19840206Smarc } else { 19940206Smarc eproc.e_xsize = eproc.e_xrssize = 20040206Smarc eproc.e_xccount = eproc.e_xswrss = 0; 20140206Smarc } 20243419Smarc if (error = copyout((caddr_t)&eproc, &dp->kp_eproc, 20340067Smarc sizeof (eproc))) 20439963Smarc return (error); 20543419Smarc dp++; 20639963Smarc buflen -= sizeof (struct kinfo_proc); 20739963Smarc } 20839963Smarc needed += sizeof (struct kinfo_proc); 20939963Smarc } 21039963Smarc if (doingzomb == 0) { 21139963Smarc p = zombproc; 21239963Smarc doingzomb++; 21339963Smarc goto again; 21439963Smarc } 21539963Smarc if (where != NULL) 21643419Smarc *acopysize = (caddr_t)dp - where; 21740068Smarc else 21840068Smarc needed += KINFO_PROCSLOP; 21939963Smarc *aneeded = needed; 22039963Smarc 22139963Smarc return (0); 22239963Smarc } 223