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