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.20 (Berkeley) 02/05/92 8 */ 9 10 #include "param.h" 11 #include "proc.h" 12 #include "kinfo.h" 13 #include "ioctl.h" 14 #include "tty.h" 15 #include "buf.h" 16 #include "file.h" 17 18 #include "vm/vm.h" 19 20 #include "kinfo_proc.h" 21 22 #define snderr(e) { error = (e); goto release;} 23 extern int kinfo_doproc(), kinfo_rtable(), kinfo_vnode(), kinfo_file(); 24 extern int kinfo_meter(); 25 struct kinfo_lock kinfo_lock; 26 27 /* ARGSUSED */ 28 getkerninfo(p, uap, retval) 29 struct proc *p; 30 register struct args { 31 int op; 32 char *where; 33 int *size; 34 int arg; 35 } *uap; 36 int *retval; 37 { 38 int bufsize; /* max size of users buffer */ 39 int needed, locked, (*server)(), error = 0; 40 41 switch (ki_type(uap->op)) { 42 43 case KINFO_PROC: 44 server = kinfo_doproc; 45 break; 46 47 case KINFO_RT: 48 server = kinfo_rtable; 49 break; 50 51 case KINFO_VNODE: 52 server = kinfo_vnode; 53 break; 54 55 case KINFO_FILE: 56 server = kinfo_file; 57 break; 58 59 case KINFO_METER: 60 server = kinfo_meter; 61 break; 62 63 default: 64 error = EINVAL; 65 goto done; 66 } 67 if (uap->where == NULL || uap->size == NULL) { 68 error = (*server)(uap->op, NULL, NULL, uap->arg, &needed); 69 goto done; 70 } 71 if (error = copyin((caddr_t)uap->size, (caddr_t)&bufsize, 72 sizeof (bufsize))) 73 goto done; 74 while (kinfo_lock.kl_lock) { 75 kinfo_lock.kl_want = 1; 76 sleep((caddr_t)&kinfo_lock, PRIBIO+1); 77 kinfo_lock.kl_locked++; 78 } 79 kinfo_lock.kl_lock = 1; 80 81 if (!useracc(uap->where, bufsize, B_WRITE)) 82 snderr(EFAULT); 83 if (server != kinfo_vnode) /* XXX */ 84 vslock(uap->where, bufsize); 85 locked = bufsize; 86 error = (*server)(uap->op, uap->where, &bufsize, uap->arg, &needed); 87 if (server != kinfo_vnode) /* XXX */ 88 vsunlock(uap->where, locked, B_WRITE); 89 if (error == 0) 90 error = copyout((caddr_t)&bufsize, 91 (caddr_t)uap->size, sizeof (bufsize)); 92 release: 93 kinfo_lock.kl_lock = 0; 94 if (kinfo_lock.kl_want) { 95 kinfo_lock.kl_want = 0; 96 wakeup((caddr_t)&kinfo_lock); 97 } 98 done: 99 if (!error) 100 *retval = needed; 101 return (error); 102 } 103 104 /* 105 * try over estimating by 5 procs 106 */ 107 #define KINFO_PROCSLOP (5 * sizeof (struct kinfo_proc)) 108 109 kinfo_doproc(op, where, acopysize, arg, aneeded) 110 int op; 111 char *where; 112 int *acopysize, arg, *aneeded; 113 { 114 register struct proc *p; 115 register struct kinfo_proc *dp = (struct kinfo_proc *)where; 116 register needed = 0; 117 int buflen = where != NULL ? *acopysize : 0; 118 int doingzomb; 119 struct eproc eproc; 120 int error = 0; 121 122 p = allproc; 123 doingzomb = 0; 124 again: 125 for (; p != NULL; p = p->p_nxt) { 126 /* 127 * TODO - make more efficient (see notes below). 128 * do by session. 129 */ 130 switch (ki_op(op)) { 131 132 case KINFO_PROC_PID: 133 /* could do this with just a lookup */ 134 if (p->p_pid != (pid_t)arg) 135 continue; 136 break; 137 138 case KINFO_PROC_PGRP: 139 /* could do this by traversing pgrp */ 140 if (p->p_pgrp->pg_id != (pid_t)arg) 141 continue; 142 break; 143 144 case KINFO_PROC_TTY: 145 if ((p->p_flag&SCTTY) == 0 || 146 p->p_session->s_ttyp == NULL || 147 p->p_session->s_ttyp->t_dev != (dev_t)arg) 148 continue; 149 break; 150 151 case KINFO_PROC_UID: 152 if (p->p_ucred->cr_uid != (uid_t)arg) 153 continue; 154 break; 155 156 case KINFO_PROC_RUID: 157 if (p->p_cred->p_ruid != (uid_t)arg) 158 continue; 159 break; 160 } 161 if (buflen >= sizeof (struct kinfo_proc)) { 162 fill_eproc(p, &eproc); 163 if (error = copyout((caddr_t)p, &dp->kp_proc, 164 sizeof (struct proc))) 165 return (error); 166 if (error = copyout((caddr_t)&eproc, &dp->kp_eproc, 167 sizeof (eproc))) 168 return (error); 169 dp++; 170 buflen -= sizeof (struct kinfo_proc); 171 } 172 needed += sizeof (struct kinfo_proc); 173 } 174 if (doingzomb == 0) { 175 p = zombproc; 176 doingzomb++; 177 goto again; 178 } 179 if (where != NULL) 180 *acopysize = (caddr_t)dp - where; 181 else 182 needed += KINFO_PROCSLOP; 183 *aneeded = needed; 184 185 return (0); 186 } 187 188 /* 189 * Fill in an eproc structure for the specified process. 190 */ 191 void 192 fill_eproc(p, ep) 193 register struct proc *p; 194 register struct eproc *ep; 195 { 196 register struct tty *tp; 197 198 ep->e_paddr = p; 199 ep->e_sess = p->p_pgrp->pg_session; 200 ep->e_pcred = *p->p_cred; 201 ep->e_ucred = *p->p_ucred; 202 if (p->p_stat == SIDL || p->p_stat == SZOMB) { 203 ep->e_vm.vm_rssize = 0; 204 ep->e_vm.vm_tsize = 0; 205 ep->e_vm.vm_dsize = 0; 206 ep->e_vm.vm_ssize = 0; 207 #ifndef sparc 208 /* ep->e_vm.vm_pmap = XXX; */ 209 #endif 210 } else { 211 register struct vmspace *vm = p->p_vmspace; 212 213 ep->e_vm.vm_rssize = vm->vm_rssize; 214 ep->e_vm.vm_tsize = vm->vm_tsize; 215 ep->e_vm.vm_dsize = vm->vm_dsize; 216 ep->e_vm.vm_ssize = vm->vm_ssize; 217 #ifndef sparc 218 ep->e_vm.vm_pmap = vm->vm_pmap; 219 #endif 220 } 221 if (p->p_pptr) 222 ep->e_ppid = p->p_pptr->p_pid; 223 else 224 ep->e_ppid = 0; 225 ep->e_pgid = p->p_pgrp->pg_id; 226 ep->e_jobc = p->p_pgrp->pg_jobc; 227 if ((p->p_flag&SCTTY) && 228 (tp = ep->e_sess->s_ttyp)) { 229 ep->e_tdev = tp->t_dev; 230 ep->e_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID; 231 ep->e_tsess = tp->t_session; 232 } else 233 ep->e_tdev = NODEV; 234 ep->e_flag = ep->e_sess->s_ttyvp ? EPROC_CTTY : 0; 235 if (SESS_LEADER(p)) 236 ep->e_flag |= EPROC_SLEADER; 237 if (p->p_wmesg) 238 strncpy(ep->e_wmesg, p->p_wmesg, WMESGLEN); 239 ep->e_xsize = ep->e_xrssize = 0; 240 ep->e_xccount = ep->e_xswrss = 0; 241 } 242 243 /* 244 * Get file structures. 245 */ 246 kinfo_file(op, where, acopysize, arg, aneeded) 247 int op; 248 register char *where; 249 int *acopysize, arg, *aneeded; 250 { 251 int buflen, needed, error; 252 struct file *fp; 253 char *start = where; 254 255 if (where == NULL) { 256 /* 257 * overestimate by 10 files 258 */ 259 *aneeded = sizeof (filehead) + 260 (nfiles + 10) * sizeof (struct file); 261 return (0); 262 } 263 buflen = *acopysize; 264 needed = 0; 265 266 /* 267 * first copyout filehead 268 */ 269 if (buflen > sizeof (filehead)) { 270 if (error = copyout((caddr_t)&filehead, where, 271 sizeof (filehead))) 272 return (error); 273 buflen -= sizeof (filehead); 274 where += sizeof (filehead); 275 } 276 needed += sizeof (filehead); 277 278 /* 279 * followed by an array of file structures 280 */ 281 for (fp = filehead; fp != NULL; fp = fp->f_filef) { 282 if (buflen > sizeof (struct file)) { 283 if (error = copyout((caddr_t)fp, where, 284 sizeof (struct file))) 285 return (error); 286 buflen -= sizeof (struct file); 287 where += sizeof (struct file); 288 } 289 needed += sizeof (struct file); 290 } 291 *acopysize = where - start; 292 *aneeded = needed; 293 294 return (0); 295 } 296