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