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.14 (Berkeley) 04/20/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 17 #include "vm/vm.h" 18 19 #include "kinfo_proc.h" 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 int needed, locked, (*server)(), error = 0; 39 40 if (error = copyin((caddr_t)uap->size, (caddr_t)&bufsize, 41 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 if (server != kinfo_vnode) /* XXX */ 77 vslock(uap->where, bufsize); 78 locked = bufsize; 79 error = (*server)(uap->op, uap->where, &bufsize, uap->arg, &needed); 80 if (server != kinfo_vnode) /* XXX */ 81 vsunlock(uap->where, locked, B_WRITE); 82 if (error == 0) 83 error = copyout((caddr_t)&bufsize, 84 (caddr_t)uap->size, sizeof (bufsize)); 85 release: 86 kinfo_lock.kl_lock--; 87 if (kinfo_lock.kl_want) 88 wakeup(&kinfo_lock); 89 done: 90 if (!error) 91 *retval = needed; 92 return (error); 93 } 94 95 /* 96 * try over estimating by 5 procs 97 */ 98 #define KINFO_PROCSLOP (5 * sizeof (struct kinfo_proc)) 99 100 kinfo_doproc(op, where, acopysize, arg, aneeded) 101 char *where; 102 int *acopysize, *aneeded; 103 { 104 register struct proc *p; 105 register struct kinfo_proc *dp = (struct kinfo_proc *)where; 106 register needed = 0; 107 int buflen; 108 int doingzomb; 109 struct eproc eproc; 110 int error = 0; 111 112 if (where != NULL) 113 buflen = *acopysize; 114 115 p = allproc; 116 doingzomb = 0; 117 again: 118 for (; p != NULL; p = p->p_nxt) { 119 /* 120 * TODO - make more efficient (see notes below). 121 * do by session. 122 */ 123 switch (ki_op(op)) { 124 125 case KINFO_PROC_PID: 126 /* could do this with just a lookup */ 127 if (p->p_pid != (pid_t)arg) 128 continue; 129 break; 130 131 case KINFO_PROC_PGRP: 132 /* could do this by traversing pgrp */ 133 if (p->p_pgrp->pg_id != (pid_t)arg) 134 continue; 135 break; 136 137 case KINFO_PROC_TTY: 138 if ((p->p_flag&SCTTY) == 0 || 139 p->p_session->s_ttyp == NULL || 140 p->p_session->s_ttyp->t_dev != (dev_t)arg) 141 continue; 142 break; 143 144 case KINFO_PROC_UID: 145 if (p->p_ucred->cr_uid != (uid_t)arg) 146 continue; 147 break; 148 149 case KINFO_PROC_RUID: 150 if (p->p_cred->p_ruid != (uid_t)arg) 151 continue; 152 break; 153 } 154 if (where != NULL && buflen >= sizeof (struct kinfo_proc)) { 155 fill_eproc(p, &eproc); 156 if (error = copyout((caddr_t)p, &dp->kp_proc, 157 sizeof (struct proc))) 158 return (error); 159 if (error = copyout((caddr_t)&eproc, &dp->kp_eproc, 160 sizeof (eproc))) 161 return (error); 162 dp++; 163 buflen -= sizeof (struct kinfo_proc); 164 } 165 needed += sizeof (struct kinfo_proc); 166 } 167 if (doingzomb == 0) { 168 p = zombproc; 169 doingzomb++; 170 goto again; 171 } 172 if (where != NULL) 173 *acopysize = (caddr_t)dp - where; 174 else 175 needed += KINFO_PROCSLOP; 176 *aneeded = needed; 177 178 return (0); 179 } 180 181 /* 182 * Fill in an eproc structure for the specified process. 183 */ 184 void 185 fill_eproc(p, ep) 186 register struct proc *p; 187 register struct eproc *ep; 188 { 189 register struct tty *tp; 190 191 ep->e_paddr = p; 192 ep->e_sess = p->p_pgrp->pg_session; 193 ep->e_pcred = *p->p_cred; 194 ep->e_ucred = *p->p_ucred; 195 ep->e_vm = *p->p_vmspace; 196 ep->e_ppid = p->p_pptr->p_pid; 197 ep->e_pgid = p->p_pgrp->pg_id; 198 ep->e_jobc = p->p_pgrp->pg_jobc; 199 if ((p->p_flag&SCTTY) && 200 (tp = ep->e_sess->s_ttyp)) { 201 ep->e_tdev = tp->t_dev; 202 ep->e_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : -1; 203 ep->e_tsess = tp->t_session; 204 } else 205 ep->e_tdev = NODEV; 206 ep->e_flag = ep->e_sess->s_ttyvp ? EPROC_CTTY : 0; 207 if (SESS_LEADER(p)) 208 ep->e_flag |= EPROC_SLEADER; 209 if (p->p_wmesg) 210 strncpy(ep->e_wmesg, p->p_wmesg, WMESGLEN); 211 ep->e_xsize = ep->e_xrssize = 0; 212 ep->e_xccount = ep->e_xswrss = 0; 213 } 214