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.19 (Berkeley) 11/16/91 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++; 76 sleep(&kinfo_lock, PRIBIO+1); 77 kinfo_lock.kl_want--; 78 kinfo_lock.kl_locked++; 79 } 80 kinfo_lock.kl_lock++; 81 82 if (!useracc(uap->where, bufsize, B_WRITE)) 83 snderr(EFAULT); 84 if (server != kinfo_vnode) /* XXX */ 85 vslock(uap->where, bufsize); 86 locked = bufsize; 87 error = (*server)(uap->op, uap->where, &bufsize, uap->arg, &needed); 88 if (server != kinfo_vnode) /* XXX */ 89 vsunlock(uap->where, locked, B_WRITE); 90 if (error == 0) 91 error = copyout((caddr_t)&bufsize, 92 (caddr_t)uap->size, sizeof (bufsize)); 93 release: 94 kinfo_lock.kl_lock--; 95 if (kinfo_lock.kl_want) 96 wakeup(&kinfo_lock); 97 done: 98 if (!error) 99 *retval = needed; 100 return (error); 101 } 102 103 /* 104 * try over estimating by 5 procs 105 */ 106 #define KINFO_PROCSLOP (5 * sizeof (struct kinfo_proc)) 107 108 kinfo_doproc(op, where, acopysize, arg, aneeded) 109 char *where; 110 int *acopysize, *aneeded; 111 { 112 register struct proc *p; 113 register struct kinfo_proc *dp = (struct kinfo_proc *)where; 114 register needed = 0; 115 int buflen; 116 int doingzomb; 117 struct eproc eproc; 118 int error = 0; 119 120 if (where != NULL) 121 buflen = *acopysize; 122 123 p = allproc; 124 doingzomb = 0; 125 again: 126 for (; p != NULL; p = p->p_nxt) { 127 /* 128 * TODO - make more efficient (see notes below). 129 * do by session. 130 */ 131 switch (ki_op(op)) { 132 133 case KINFO_PROC_PID: 134 /* could do this with just a lookup */ 135 if (p->p_pid != (pid_t)arg) 136 continue; 137 break; 138 139 case KINFO_PROC_PGRP: 140 /* could do this by traversing pgrp */ 141 if (p->p_pgrp->pg_id != (pid_t)arg) 142 continue; 143 break; 144 145 case KINFO_PROC_TTY: 146 if ((p->p_flag&SCTTY) == 0 || 147 p->p_session->s_ttyp == NULL || 148 p->p_session->s_ttyp->t_dev != (dev_t)arg) 149 continue; 150 break; 151 152 case KINFO_PROC_UID: 153 if (p->p_ucred->cr_uid != (uid_t)arg) 154 continue; 155 break; 156 157 case KINFO_PROC_RUID: 158 if (p->p_cred->p_ruid != (uid_t)arg) 159 continue; 160 break; 161 } 162 if (where != NULL && buflen >= sizeof (struct kinfo_proc)) { 163 fill_eproc(p, &eproc); 164 if (error = copyout((caddr_t)p, &dp->kp_proc, 165 sizeof (struct proc))) 166 return (error); 167 if (error = copyout((caddr_t)&eproc, &dp->kp_eproc, 168 sizeof (eproc))) 169 return (error); 170 dp++; 171 buflen -= sizeof (struct kinfo_proc); 172 } 173 needed += sizeof (struct kinfo_proc); 174 } 175 if (doingzomb == 0) { 176 p = zombproc; 177 doingzomb++; 178 goto again; 179 } 180 if (where != NULL) 181 *acopysize = (caddr_t)dp - where; 182 else 183 needed += KINFO_PROCSLOP; 184 *aneeded = needed; 185 186 return (0); 187 } 188 189 /* 190 * Fill in an eproc structure for the specified process. 191 */ 192 void 193 fill_eproc(p, ep) 194 register struct proc *p; 195 register struct eproc *ep; 196 { 197 register struct tty *tp; 198 199 ep->e_paddr = p; 200 ep->e_sess = p->p_pgrp->pg_session; 201 ep->e_pcred = *p->p_cred; 202 ep->e_ucred = *p->p_ucred; 203 ep->e_vm = *p->p_vmspace; 204 if (p->p_pptr) 205 ep->e_ppid = p->p_pptr->p_pid; 206 else 207 ep->e_ppid = 0; 208 ep->e_pgid = p->p_pgrp->pg_id; 209 ep->e_jobc = p->p_pgrp->pg_jobc; 210 if ((p->p_flag&SCTTY) && 211 (tp = ep->e_sess->s_ttyp)) { 212 ep->e_tdev = tp->t_dev; 213 ep->e_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID; 214 ep->e_tsess = tp->t_session; 215 } else 216 ep->e_tdev = NODEV; 217 ep->e_flag = ep->e_sess->s_ttyvp ? EPROC_CTTY : 0; 218 if (SESS_LEADER(p)) 219 ep->e_flag |= EPROC_SLEADER; 220 if (p->p_wmesg) 221 strncpy(ep->e_wmesg, p->p_wmesg, WMESGLEN); 222 ep->e_xsize = ep->e_xrssize = 0; 223 ep->e_xccount = ep->e_xswrss = 0; 224 } 225 226 /* 227 * Get file structures. 228 */ 229 kinfo_file(op, where, acopysize, arg, aneeded) 230 register char *where; 231 int *acopysize, *aneeded; 232 { 233 int buflen, needed, error; 234 struct file *fp; 235 char *start = where; 236 237 if (where == NULL) { 238 /* 239 * overestimate by 10 files 240 */ 241 *aneeded = sizeof (filehead) + 242 (nfiles + 10) * sizeof (struct file); 243 return (0); 244 } 245 buflen = *acopysize; 246 needed = 0; 247 248 /* 249 * first copyout filehead 250 */ 251 if (buflen > sizeof (filehead)) { 252 if (error = copyout((caddr_t)&filehead, where, 253 sizeof (filehead))) 254 return (error); 255 buflen -= sizeof (filehead); 256 where += sizeof (filehead); 257 } 258 needed += sizeof (filehead); 259 260 /* 261 * followed by an array of file structures 262 */ 263 for (fp = filehead; fp != NULL; fp = fp->f_filef) { 264 if (buflen > sizeof (struct file)) { 265 if (error = copyout((caddr_t)fp, where, 266 sizeof (struct file))) 267 return (error); 268 buflen -= sizeof (struct file); 269 where += sizeof (struct file); 270 } 271 needed += sizeof (struct file); 272 } 273 *acopysize = where - start; 274 *aneeded = needed; 275 276 return (0); 277 } 278