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*40068Smarc * @(#)kern_sysctl.c 7.4 (Berkeley) 02/14/90 1839963Smarc */ 1939963Smarc 2039965Smckusick #include "param.h" 2139965Smckusick #include "user.h" 2239965Smckusick #include "proc.h" 2339963Smarc #include "kinfo.h" 2439963Smarc #include "vm.h" 2539963Smarc #include "ioctl.h" 2639963Smarc #include "tty.h" 2739963Smarc #include "buf.h" 2839963Smarc 29*40068Smarc 30*40068Smarc #define snderr(e) { error = (e); goto release;} 31*40068Smarc extern int kinfo_doproc(), kinfo_rtable(); 32*40068Smarc struct kinfo_lock kinfo_lock; 33*40068Smarc 3439963Smarc getkinfo() 3539963Smarc { 3639963Smarc register struct a { 3739963Smarc int op; 3839963Smarc char *where; 3939963Smarc int *size; 4039963Smarc int arg; 4139963Smarc } *uap = (struct a *)u.u_ap; 42*40068Smarc int wanted, (*server)(), error = 0; 43*40068Smarc int bufsize, /* max size of users buffer */ 44*40068Smarc copysize, /* size copied */ 45*40068Smarc needed, 46*40068Smarc locked; 4739963Smarc 48*40068Smarc while (kinfo_lock.kl_lock) { 49*40068Smarc kinfo_lock.kl_want++; 50*40068Smarc sleep(&kinfo_lock, PRIBIO+1); 51*40068Smarc kinfo_lock.kl_want--; 52*40068Smarc kinfo_lock.kl_locked++; 53*40068Smarc } 54*40068Smarc kinfo_lock.kl_lock++; 55*40068Smarc 5639963Smarc switch (ki_type(uap->op)) { 5739963Smarc 5839963Smarc case KINFO_PROC: 59*40068Smarc server = kinfo_doproc; 6039963Smarc break; 6139963Smarc 62*40068Smarc case KINFO_RT: 63*40068Smarc server = kinfo_rtable; 64*40068Smarc break; 65*40068Smarc 6639963Smarc default: 67*40068Smarc snderr(EINVAL); 6839963Smarc } 69*40068Smarc if (error = (*server)(uap->op, NULL, NULL, uap->arg, &needed)) 70*40068Smarc goto release; 71*40068Smarc if (uap->where == NULL || uap->size == NULL) 72*40068Smarc goto release; /* only want estimate of bufsize */ 73*40068Smarc if (error = copyin((caddr_t)uap->size, 74*40068Smarc (caddr_t)&bufsize, sizeof (bufsize))) 75*40068Smarc goto release; 76*40068Smarc locked = copysize = MIN(needed, bufsize); 77*40068Smarc if (!useracc(uap->where, copysize, B_WRITE)) 78*40068Smarc snderr(EFAULT); 79*40068Smarc /* 80*40068Smarc * lock down target pages - NEED DEADLOCK AVOIDANCE 81*40068Smarc */ 82*40068Smarc if (copysize > ((int)ptob(freemem) - (20 * 1024))) /* XXX */ 83*40068Smarc snderr(ENOMEM); 84*40068Smarc vslock(uap->where, copysize); 85*40068Smarc error = (*server)(uap->op, uap->where, ©size, uap->arg, &needed); 86*40068Smarc vsunlock(uap->where, locked, B_WRITE); 87*40068Smarc if (error) 88*40068Smarc goto release; 89*40068Smarc error = copyout((caddr_t)©size, 90*40068Smarc (caddr_t)uap->size, sizeof (copysize)); 9139963Smarc 92*40068Smarc release: 93*40068Smarc kinfo_lock.kl_lock--; 94*40068Smarc if (kinfo_lock.kl_want) 95*40068Smarc wakeup(&kinfo_lock); 96*40068Smarc if (error) 97*40068Smarc u.u_error = error; 98*40068Smarc else 99*40068Smarc u.u_r.r_val1 = needed; 10039963Smarc } 10139963Smarc 10239963Smarc /* 10339963Smarc * try over estimating by 5 procs 10439963Smarc */ 10539963Smarc #define KINFO_PROCSLOP (5 * sizeof (struct kinfo_proc)) 10639963Smarc 10739963Smarc int kinfo_proc_userfailed; 10839963Smarc int kinfo_proc_wefailed; 10939963Smarc 11039963Smarc kinfo_doprocs(op, where, acopysize, arg, aneeded) 11139963Smarc char *where; 11239963Smarc int *acopysize, *aneeded; 11339963Smarc { 11439963Smarc register struct proc *p; 11539963Smarc register caddr_t dp = (caddr_t)where; 11639963Smarc register needed = 0; 11739963Smarc int buflen; 11839963Smarc int doingzomb; 11940067Smarc struct eproc eproc; 12039963Smarc struct tty *tp; 12139963Smarc int error = 0; 12239963Smarc 12339963Smarc if (where != NULL) 12439963Smarc buflen = *acopysize; 12539963Smarc 12639963Smarc p = allproc; 12739963Smarc doingzomb = 0; 12839963Smarc again: 12939963Smarc for (; p != NULL; p = p->p_nxt) { 13039963Smarc /* 13139963Smarc * TODO - make more efficient (see notes below). 13239963Smarc * do by session. 13339963Smarc */ 13439963Smarc switch (ki_op(op)) { 13539963Smarc 13639963Smarc case KINFO_PROC_PID: 13739963Smarc /* could do this with just a lookup */ 13839963Smarc if (p->p_pid != (pid_t)arg) 13939963Smarc continue; 14039963Smarc break; 14139963Smarc 14239963Smarc case KINFO_PROC_PGRP: 14339963Smarc /* could do this by traversing pgrp */ 14439963Smarc if (p->p_pgrp->pg_id != (pid_t)arg) 14539963Smarc continue; 14639963Smarc break; 14739963Smarc 14839963Smarc case KINFO_PROC_TTY: 14939963Smarc if ((p->p_flag&SCTTY) == 0 || 15039963Smarc p->p_session->s_ttyp == NULL || 15139963Smarc p->p_session->s_ttyp->t_dev != (dev_t)arg) 15239963Smarc continue; 15339963Smarc break; 15439963Smarc 15539963Smarc case KINFO_PROC_UID: 15639963Smarc if (p->p_uid != (uid_t)arg) 15739963Smarc continue; 15839963Smarc break; 15939963Smarc 16039963Smarc case KINFO_PROC_RUID: 16139963Smarc if (p->p_ruid != (uid_t)arg) 16239963Smarc continue; 16339963Smarc break; 16439963Smarc } 16539963Smarc if (where != NULL && buflen >= sizeof (struct kinfo_proc)) { 16639963Smarc if (error = copyout((caddr_t)p, dp, 16739963Smarc sizeof (struct proc))) 16839963Smarc return (error); 16939963Smarc dp += sizeof (struct proc); 17040067Smarc eproc.kp_paddr = p; 17140067Smarc eproc.kp_sess = p->p_pgrp->pg_session; 17240067Smarc eproc.kp_pgid = p->p_pgrp->pg_id; 17340067Smarc eproc.kp_jobc = p->p_pgrp->pg_jobc; 17439963Smarc tp = p->p_pgrp->pg_session->s_ttyp; 17539963Smarc if ((p->p_flag&SCTTY) && tp != NULL) { 17640067Smarc eproc.kp_tdev = tp->t_dev; 17740067Smarc eproc.kp_tpgid = tp->t_pgrp ? 17839963Smarc tp->t_pgrp->pg_id : -1; 17940067Smarc eproc.kp_tsess = tp->t_session; 18039963Smarc } else 18140067Smarc eproc.kp_tdev = NODEV; 18240067Smarc if (error = copyout((caddr_t)&eproc, dp, 18340067Smarc sizeof (eproc))) 18439963Smarc return (error); 18540067Smarc dp += sizeof (eproc); 18639963Smarc buflen -= sizeof (struct kinfo_proc); 18739963Smarc } 18839963Smarc needed += sizeof (struct kinfo_proc); 18939963Smarc } 19039963Smarc if (doingzomb == 0) { 19139963Smarc p = zombproc; 19239963Smarc doingzomb++; 19339963Smarc goto again; 19439963Smarc } 19539963Smarc if (where != NULL) 19639963Smarc *acopysize = dp - where; 197*40068Smarc else 198*40068Smarc needed += KINFO_PROCSLOP; 19939963Smarc *aneeded = needed; 20039963Smarc 20139963Smarc return (0); 20239963Smarc } 203