1 /* 2 * Copyright (c) 1982, 1986, 1989 Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 * 7 * @(#)kern_sysctl.c 7.11 (Berkeley) 06/28/90 8 */ 9 10 #include "param.h" 11 #include "user.h" 12 #include "proc.h" 13 #include "text.h" 14 #include "kinfo.h" 15 #include "vm.h" 16 #include "ioctl.h" 17 #include "tty.h" 18 #include "buf.h" 19 20 21 #define snderr(e) { error = (e); goto release;} 22 extern int kinfo_doproc(), kinfo_rtable(), kinfo_vnode(); 23 struct kinfo_lock kinfo_lock; 24 25 /* ARGSUSED */ 26 getkerninfo(p, uap, retval) 27 struct proc *p; 28 register struct args { 29 int op; 30 char *where; 31 int *size; 32 int arg; 33 } *uap; 34 int *retval; 35 { 36 37 int bufsize, /* max size of users buffer */ 38 needed, locked, (*server)(), error = 0; 39 40 if (error = copyin((caddr_t)uap->size, 41 (caddr_t)&bufsize, sizeof (bufsize))) 42 goto done; 43 44 switch (ki_type(uap->op)) { 45 46 case KINFO_PROC: 47 server = kinfo_doproc; 48 break; 49 50 case KINFO_RT: 51 server = kinfo_rtable; 52 break; 53 54 case KINFO_VNODE: 55 server = kinfo_vnode; 56 break; 57 58 default: 59 error = EINVAL; 60 goto done; 61 } 62 if (uap->where == NULL || uap->size == NULL) { 63 error = (*server)(uap->op, NULL, NULL, uap->arg, &needed); 64 goto done; 65 } 66 while (kinfo_lock.kl_lock) { 67 kinfo_lock.kl_want++; 68 sleep(&kinfo_lock, PRIBIO+1); 69 kinfo_lock.kl_want--; 70 kinfo_lock.kl_locked++; 71 } 72 kinfo_lock.kl_lock++; 73 74 if (!useracc(uap->where, bufsize, B_WRITE)) 75 snderr(EFAULT); 76 /* 77 * lock down target pages - NEED DEADLOCK AVOIDANCE 78 */ 79 if (bufsize > ((int)ptob(freemem) - (20 * 1024))) /* XXX */ 80 snderr(ENOMEM); 81 if (server != kinfo_vnode) /* XXX */ 82 vslock(uap->where, bufsize); 83 locked = bufsize; 84 error = (*server)(uap->op, uap->where, &bufsize, uap->arg, &needed); 85 if (server != kinfo_vnode) /* XXX */ 86 vsunlock(uap->where, locked, B_WRITE); 87 if (error == 0) 88 error = copyout((caddr_t)&bufsize, 89 (caddr_t)uap->size, sizeof (bufsize)); 90 release: 91 kinfo_lock.kl_lock--; 92 if (kinfo_lock.kl_want) 93 wakeup(&kinfo_lock); 94 done: 95 if (!error) 96 *retval = needed; 97 return (error); 98 } 99 100 /* 101 * try over estimating by 5 procs 102 */ 103 #define KINFO_PROCSLOP (5 * sizeof (struct kinfo_proc)) 104 105 kinfo_doproc(op, where, acopysize, arg, aneeded) 106 char *where; 107 int *acopysize, *aneeded; 108 { 109 register struct proc *p; 110 register struct kinfo_proc *dp = (struct kinfo_proc *)where; 111 register needed = 0; 112 int buflen; 113 int doingzomb; 114 struct eproc eproc; 115 int error = 0; 116 117 if (where != NULL) 118 buflen = *acopysize; 119 120 p = allproc; 121 doingzomb = 0; 122 again: 123 for (; p != NULL; p = p->p_nxt) { 124 /* 125 * TODO - make more efficient (see notes below). 126 * do by session. 127 */ 128 switch (ki_op(op)) { 129 130 case KINFO_PROC_PID: 131 /* could do this with just a lookup */ 132 if (p->p_pid != (pid_t)arg) 133 continue; 134 break; 135 136 case KINFO_PROC_PGRP: 137 /* could do this by traversing pgrp */ 138 if (p->p_pgrp->pg_id != (pid_t)arg) 139 continue; 140 break; 141 142 case KINFO_PROC_TTY: 143 if ((p->p_flag&SCTTY) == 0 || 144 p->p_session->s_ttyp == NULL || 145 p->p_session->s_ttyp->t_dev != (dev_t)arg) 146 continue; 147 break; 148 149 case KINFO_PROC_UID: 150 if (p->p_uid != (uid_t)arg) 151 continue; 152 break; 153 154 case KINFO_PROC_RUID: 155 if (p->p_ruid != (uid_t)arg) 156 continue; 157 break; 158 } 159 if (where != NULL && buflen >= sizeof (struct kinfo_proc)) { 160 register struct text *txt; 161 register struct tty *tp; 162 163 if (error = copyout((caddr_t)p, &dp->kp_proc, 164 sizeof (struct proc))) 165 return (error); 166 eproc.e_paddr = p; 167 eproc.e_sess = p->p_pgrp->pg_session; 168 eproc.e_pgid = p->p_pgrp->pg_id; 169 eproc.e_jobc = p->p_pgrp->pg_jobc; 170 if ((p->p_flag&SCTTY) && 171 (tp = eproc.e_sess->s_ttyp)) { 172 eproc.e_tdev = tp->t_dev; 173 eproc.e_tpgid = tp->t_pgrp ? 174 tp->t_pgrp->pg_id : -1; 175 eproc.e_tsess = tp->t_session; 176 } else 177 eproc.e_tdev = NODEV; 178 eproc.e_flag = eproc.e_sess->s_ttyvp ? EPROC_CTTY : 0; 179 if (SESS_LEADER(p)) 180 eproc.e_flag |= EPROC_SLEADER; 181 if (p->p_wmesg) 182 strncpy(eproc.e_wmesg, p->p_wmesg, WMESGLEN); 183 if (txt = p->p_textp) { 184 eproc.e_xsize = txt->x_size; 185 eproc.e_xrssize = txt->x_rssize; 186 eproc.e_xccount = txt->x_ccount; 187 eproc.e_xswrss = txt->x_swrss; 188 } else { 189 eproc.e_xsize = eproc.e_xrssize = 190 eproc.e_xccount = eproc.e_xswrss = 0; 191 } 192 if (error = copyout((caddr_t)&eproc, &dp->kp_eproc, 193 sizeof (eproc))) 194 return (error); 195 dp++; 196 buflen -= sizeof (struct kinfo_proc); 197 } 198 needed += sizeof (struct kinfo_proc); 199 } 200 if (doingzomb == 0) { 201 p = zombproc; 202 doingzomb++; 203 goto again; 204 } 205 if (where != NULL) 206 *acopysize = (caddr_t)dp - where; 207 else 208 needed += KINFO_PROCSLOP; 209 *aneeded = needed; 210 211 return (0); 212 } 213