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*40206Smarc * @(#)kern_sysctl.c 7.5 (Berkeley) 02/22/90 1839963Smarc */ 1939963Smarc 2039965Smckusick #include "param.h" 2139965Smckusick #include "user.h" 2239965Smckusick #include "proc.h" 23*40206Smarc #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;} 3240068Smarc extern int kinfo_doproc(), kinfo_rtable(); 3340068Smarc struct kinfo_lock kinfo_lock; 3440068Smarc 35*40206Smarc getkerninfo() 3639963Smarc { 3739963Smarc register struct a { 3839963Smarc int op; 3939963Smarc char *where; 4039963Smarc int *size; 4139963Smarc int arg; 4239963Smarc } *uap = (struct a *)u.u_ap; 43*40206Smarc 4440068Smarc int bufsize, /* max size of users buffer */ 4540068Smarc copysize, /* size copied */ 46*40206Smarc needed, locked, (*server)(), error = 0; 4739963Smarc 48*40206Smarc if (error = copyin((caddr_t)uap->size, 49*40206Smarc (caddr_t)&bufsize, sizeof (bufsize))) 50*40206Smarc goto bad; 5140068Smarc 5239963Smarc switch (ki_type(uap->op)) { 5339963Smarc 5439963Smarc case KINFO_PROC: 5540068Smarc server = kinfo_doproc; 5639963Smarc break; 5739963Smarc 5840068Smarc case KINFO_RT: 5940068Smarc server = kinfo_rtable; 6040068Smarc break; 6140068Smarc 6239963Smarc default: 63*40206Smarc error = EINVAL; 64*40206Smarc goto bad; 6539963Smarc } 66*40206Smarc while (kinfo_lock.kl_lock) { 67*40206Smarc kinfo_lock.kl_want++; 68*40206Smarc sleep(&kinfo_lock, PRIBIO+1); 69*40206Smarc kinfo_lock.kl_want--; 70*40206Smarc kinfo_lock.kl_locked++; 71*40206Smarc } 72*40206Smarc kinfo_lock.kl_lock++; 73*40206Smarc 7440068Smarc if (error = (*server)(uap->op, NULL, NULL, uap->arg, &needed)) 7540068Smarc goto release; 7640068Smarc if (uap->where == NULL || uap->size == NULL) 7740068Smarc goto release; /* only want estimate of bufsize */ 7840068Smarc locked = copysize = MIN(needed, bufsize); 7940068Smarc if (!useracc(uap->where, copysize, B_WRITE)) 8040068Smarc snderr(EFAULT); 8140068Smarc /* 8240068Smarc * lock down target pages - NEED DEADLOCK AVOIDANCE 8340068Smarc */ 8440068Smarc if (copysize > ((int)ptob(freemem) - (20 * 1024))) /* XXX */ 8540068Smarc snderr(ENOMEM); 8640068Smarc vslock(uap->where, copysize); 8740068Smarc error = (*server)(uap->op, uap->where, ©size, uap->arg, &needed); 8840068Smarc vsunlock(uap->where, locked, B_WRITE); 8940068Smarc if (error) 9040068Smarc goto release; 9140068Smarc error = copyout((caddr_t)©size, 9240068Smarc (caddr_t)uap->size, sizeof (copysize)); 9339963Smarc 9440068Smarc release: 9540068Smarc kinfo_lock.kl_lock--; 9640068Smarc if (kinfo_lock.kl_want) 9740068Smarc wakeup(&kinfo_lock); 98*40206Smarc bad: 9940068Smarc if (error) 10040068Smarc u.u_error = error; 10140068Smarc else 10240068Smarc u.u_r.r_val1 = needed; 10339963Smarc } 10439963Smarc 10539963Smarc /* 10639963Smarc * try over estimating by 5 procs 10739963Smarc */ 10839963Smarc #define KINFO_PROCSLOP (5 * sizeof (struct kinfo_proc)) 10939963Smarc 11039963Smarc int kinfo_proc_userfailed; 11139963Smarc int kinfo_proc_wefailed; 11239963Smarc 113*40206Smarc kinfo_doproc(op, where, acopysize, arg, aneeded) 11439963Smarc char *where; 11539963Smarc int *acopysize, *aneeded; 11639963Smarc { 11739963Smarc register struct proc *p; 11839963Smarc register caddr_t dp = (caddr_t)where; 11939963Smarc register needed = 0; 12039963Smarc int buflen; 12139963Smarc int doingzomb; 12240067Smarc struct eproc eproc; 12339963Smarc struct tty *tp; 12439963Smarc int error = 0; 12539963Smarc 12639963Smarc if (where != NULL) 12739963Smarc buflen = *acopysize; 12839963Smarc 12939963Smarc p = allproc; 13039963Smarc doingzomb = 0; 13139963Smarc again: 13239963Smarc for (; p != NULL; p = p->p_nxt) { 13339963Smarc /* 13439963Smarc * TODO - make more efficient (see notes below). 13539963Smarc * do by session. 13639963Smarc */ 13739963Smarc switch (ki_op(op)) { 13839963Smarc 13939963Smarc case KINFO_PROC_PID: 14039963Smarc /* could do this with just a lookup */ 14139963Smarc if (p->p_pid != (pid_t)arg) 14239963Smarc continue; 14339963Smarc break; 14439963Smarc 14539963Smarc case KINFO_PROC_PGRP: 14639963Smarc /* could do this by traversing pgrp */ 14739963Smarc if (p->p_pgrp->pg_id != (pid_t)arg) 14839963Smarc continue; 14939963Smarc break; 15039963Smarc 15139963Smarc case KINFO_PROC_TTY: 15239963Smarc if ((p->p_flag&SCTTY) == 0 || 15339963Smarc p->p_session->s_ttyp == NULL || 15439963Smarc p->p_session->s_ttyp->t_dev != (dev_t)arg) 15539963Smarc continue; 15639963Smarc break; 15739963Smarc 15839963Smarc case KINFO_PROC_UID: 15939963Smarc if (p->p_uid != (uid_t)arg) 16039963Smarc continue; 16139963Smarc break; 16239963Smarc 16339963Smarc case KINFO_PROC_RUID: 16439963Smarc if (p->p_ruid != (uid_t)arg) 16539963Smarc continue; 16639963Smarc break; 16739963Smarc } 16839963Smarc if (where != NULL && buflen >= sizeof (struct kinfo_proc)) { 169*40206Smarc register struct text *txt; 170*40206Smarc 17139963Smarc if (error = copyout((caddr_t)p, dp, 17239963Smarc sizeof (struct proc))) 17339963Smarc return (error); 17439963Smarc dp += sizeof (struct proc); 175*40206Smarc eproc.e_paddr = p; 176*40206Smarc eproc.e_sess = p->p_pgrp->pg_session; 177*40206Smarc eproc.e_pgid = p->p_pgrp->pg_id; 178*40206Smarc eproc.e_jobc = p->p_pgrp->pg_jobc; 17939963Smarc tp = p->p_pgrp->pg_session->s_ttyp; 18039963Smarc if ((p->p_flag&SCTTY) && tp != NULL) { 181*40206Smarc eproc.e_tdev = tp->t_dev; 182*40206Smarc eproc.e_tpgid = tp->t_pgrp ? 18339963Smarc tp->t_pgrp->pg_id : -1; 184*40206Smarc eproc.e_tsess = tp->t_session; 18539963Smarc } else 186*40206Smarc eproc.e_tdev = NODEV; 187*40206Smarc if (p->p_wmesg) 188*40206Smarc strncpy(eproc.e_wmesg, p->p_wmesg, WMESGLEN); 189*40206Smarc if (txt = p->p_textp) { 190*40206Smarc eproc.e_xsize = txt->x_size; 191*40206Smarc eproc.e_xrssize = txt->x_rssize; 192*40206Smarc eproc.e_xccount = txt->x_ccount; 193*40206Smarc eproc.e_xswrss = txt->x_swrss; 194*40206Smarc } else { 195*40206Smarc eproc.e_xsize = eproc.e_xrssize = 196*40206Smarc eproc.e_xccount = eproc.e_xswrss = 0; 197*40206Smarc } 19840067Smarc if (error = copyout((caddr_t)&eproc, dp, 19940067Smarc sizeof (eproc))) 20039963Smarc return (error); 20140067Smarc dp += sizeof (eproc); 20239963Smarc buflen -= sizeof (struct kinfo_proc); 20339963Smarc } 20439963Smarc needed += sizeof (struct kinfo_proc); 20539963Smarc } 20639963Smarc if (doingzomb == 0) { 20739963Smarc p = zombproc; 20839963Smarc doingzomb++; 20939963Smarc goto again; 21039963Smarc } 21139963Smarc if (where != NULL) 21239963Smarc *acopysize = dp - where; 21340068Smarc else 21440068Smarc needed += KINFO_PROCSLOP; 21539963Smarc *aneeded = needed; 21639963Smarc 21739963Smarc return (0); 21839963Smarc } 219