1*39963Smarc /* 2*39963Smarc * Copyright (c) 1982, 1986, 1989 Regents of the University of California. 3*39963Smarc * All rights reserved. 4*39963Smarc * 5*39963Smarc * Redistribution and use in source and binary forms are permitted 6*39963Smarc * provided that the above copyright notice and this paragraph are 7*39963Smarc * duplicated in all such forms and that any documentation, 8*39963Smarc * advertising materials, and other materials related to such 9*39963Smarc * distribution and use acknowledge that the software was developed 10*39963Smarc * by the University of California, Berkeley. The name of the 11*39963Smarc * University may not be used to endorse or promote products derived 12*39963Smarc * from this software without specific prior written permission. 13*39963Smarc * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14*39963Smarc * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15*39963Smarc * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16*39963Smarc * 17*39963Smarc * @(#)kern_sysctl.c 7.1 (Berkeley) 01/31/90 18*39963Smarc */ 19*39963Smarc 20*39963Smarc #include "kinfo.h" 21*39963Smarc #include "vm.h" 22*39963Smarc #include "ioctl.h" 23*39963Smarc #include "tty.h" 24*39963Smarc #include "buf.h" 25*39963Smarc 26*39963Smarc /* TODO - gather stats on average and max time spent */ 27*39963Smarc getkinfo() 28*39963Smarc { 29*39963Smarc register struct a { 30*39963Smarc int op; 31*39963Smarc char *where; 32*39963Smarc int *size; 33*39963Smarc int arg; 34*39963Smarc } *uap = (struct a *)u.u_ap; 35*39963Smarc int wanted; 36*39963Smarc 37*39963Smarc switch (ki_type(uap->op)) { 38*39963Smarc 39*39963Smarc case KINFO_PROC: 40*39963Smarc u.u_error = kinfo_proc(uap->op, (char *)uap->where, 41*39963Smarc (int *)uap->size, uap->arg, &wanted); 42*39963Smarc if (!u.u_error) 43*39963Smarc u.u_r.r_val1 = wanted; 44*39963Smarc break; 45*39963Smarc 46*39963Smarc default: 47*39963Smarc u.u_error = EINVAL; 48*39963Smarc } 49*39963Smarc 50*39963Smarc return; 51*39963Smarc } 52*39963Smarc 53*39963Smarc /* 54*39963Smarc * try over estimating by 5 procs 55*39963Smarc */ 56*39963Smarc #define KINFO_PROCSLOP (5 * sizeof (struct kinfo_proc)) 57*39963Smarc 58*39963Smarc int kinfo_proc_userfailed; 59*39963Smarc int kinfo_proc_wefailed; 60*39963Smarc 61*39963Smarc kinfo_proc(op, where, asize, arg, awanted) 62*39963Smarc char *where; 63*39963Smarc int *asize, *awanted; 64*39963Smarc { 65*39963Smarc int bufsize, /* max size of users buffer */ 66*39963Smarc copysize, /* size copied */ 67*39963Smarc needed; 68*39963Smarc int locked; 69*39963Smarc int error; 70*39963Smarc 71*39963Smarc if (error = kinfo_doprocs(op, NULL, NULL, arg, &needed)) 72*39963Smarc return (error); 73*39963Smarc if (where == NULL || asize == NULL) { 74*39963Smarc *awanted = needed; 75*39963Smarc return (0); 76*39963Smarc } 77*39963Smarc if (error = copyin((caddr_t)asize, (caddr_t)&bufsize, sizeof (bufsize))) 78*39963Smarc return (error); 79*39963Smarc needed += KINFO_PROCSLOP; 80*39963Smarc locked = copysize = MIN(needed, bufsize); 81*39963Smarc if (!useracc(where, copysize, B_WRITE)) 82*39963Smarc return (EFAULT); 83*39963Smarc /* 84*39963Smarc * lock down target pages - NEED DEADLOCK AVOIDANCE 85*39963Smarc */ 86*39963Smarc if (copysize > ((int)ptob(freemem) - (20 * 1024))) /* XXX */ 87*39963Smarc return (ENOMEM); 88*39963Smarc vslock(where, copysize); 89*39963Smarc error = kinfo_doprocs(op, where, ©size, arg, &needed); 90*39963Smarc vsunlock(where, locked, B_WRITE); 91*39963Smarc if (error) 92*39963Smarc return (error); 93*39963Smarc *awanted = needed; 94*39963Smarc if (error = copyout((caddr_t)©size, (caddr_t)asize, 95*39963Smarc sizeof (copysize))) 96*39963Smarc return (error); 97*39963Smarc 98*39963Smarc return (0); 99*39963Smarc } 100*39963Smarc 101*39963Smarc kinfo_doprocs(op, where, acopysize, arg, aneeded) 102*39963Smarc char *where; 103*39963Smarc int *acopysize, *aneeded; 104*39963Smarc { 105*39963Smarc register struct proc *p; 106*39963Smarc register caddr_t dp = (caddr_t)where; 107*39963Smarc register needed = 0; 108*39963Smarc int buflen; 109*39963Smarc int doingzomb; 110*39963Smarc struct { 111*39963Smarc struct proc *paddr; 112*39963Smarc struct session *session; 113*39963Smarc pid_t pgid; 114*39963Smarc short jobc; 115*39963Smarc dev_t ttydev; 116*39963Smarc pid_t ttypgid; 117*39963Smarc struct session *ttysession; 118*39963Smarc } extra; 119*39963Smarc struct tty *tp; 120*39963Smarc int error = 0; 121*39963Smarc 122*39963Smarc if (where != NULL) 123*39963Smarc buflen = *acopysize; 124*39963Smarc 125*39963Smarc p = allproc; 126*39963Smarc doingzomb = 0; 127*39963Smarc again: 128*39963Smarc for (; p != NULL; p = p->p_nxt) { 129*39963Smarc /* 130*39963Smarc * TODO - make more efficient (see notes below). 131*39963Smarc * do by session. 132*39963Smarc */ 133*39963Smarc switch (ki_op(op)) { 134*39963Smarc 135*39963Smarc case KINFO_PROC_PID: 136*39963Smarc /* could do this with just a lookup */ 137*39963Smarc if (p->p_pid != (pid_t)arg) 138*39963Smarc continue; 139*39963Smarc break; 140*39963Smarc 141*39963Smarc case KINFO_PROC_PGRP: 142*39963Smarc /* could do this by traversing pgrp */ 143*39963Smarc if (p->p_pgrp->pg_id != (pid_t)arg) 144*39963Smarc continue; 145*39963Smarc break; 146*39963Smarc 147*39963Smarc case KINFO_PROC_TTY: 148*39963Smarc if ((p->p_flag&SCTTY) == 0 || 149*39963Smarc p->p_session->s_ttyp == NULL || 150*39963Smarc p->p_session->s_ttyp->t_dev != (dev_t)arg) 151*39963Smarc continue; 152*39963Smarc break; 153*39963Smarc 154*39963Smarc case KINFO_PROC_UID: 155*39963Smarc if (p->p_uid != (uid_t)arg) 156*39963Smarc continue; 157*39963Smarc break; 158*39963Smarc 159*39963Smarc case KINFO_PROC_RUID: 160*39963Smarc if (p->p_ruid != (uid_t)arg) 161*39963Smarc continue; 162*39963Smarc break; 163*39963Smarc } 164*39963Smarc if (where != NULL && buflen >= sizeof (struct kinfo_proc)) { 165*39963Smarc if (error = copyout((caddr_t)p, dp, 166*39963Smarc sizeof (struct proc))) 167*39963Smarc return (error); 168*39963Smarc dp += sizeof (struct proc); 169*39963Smarc extra.paddr = p; 170*39963Smarc extra.session = p->p_pgrp->pg_session; 171*39963Smarc extra.pgid = p->p_pgrp->pg_id; 172*39963Smarc extra.jobc = p->p_pgrp->pg_jobc; 173*39963Smarc tp = p->p_pgrp->pg_session->s_ttyp; 174*39963Smarc if ((p->p_flag&SCTTY) && tp != NULL) { 175*39963Smarc extra.ttydev = tp->t_dev; 176*39963Smarc extra.ttypgid = tp->t_pgrp ? 177*39963Smarc tp->t_pgrp->pg_id : -1; 178*39963Smarc extra.ttysession = tp->t_session; 179*39963Smarc } else 180*39963Smarc extra.ttydev = NODEV; 181*39963Smarc if (error = copyout((caddr_t)&extra, dp, 182*39963Smarc sizeof (extra))) 183*39963Smarc return (error); 184*39963Smarc dp += sizeof (extra); 185*39963Smarc buflen -= sizeof (struct kinfo_proc); 186*39963Smarc } 187*39963Smarc needed += sizeof (struct kinfo_proc); 188*39963Smarc } 189*39963Smarc if (doingzomb == 0) { 190*39963Smarc p = zombproc; 191*39963Smarc doingzomb++; 192*39963Smarc goto again; 193*39963Smarc } 194*39963Smarc if (where != NULL) 195*39963Smarc *acopysize = dp - where; 196*39963Smarc *aneeded = needed; 197*39963Smarc 198*39963Smarc return (0); 199*39963Smarc } 200