1 /* 2 * Copyright (c) 1982, 1986, 1989 Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that the above copyright notice and this paragraph are 7 * duplicated in all such forms and that any documentation, 8 * advertising materials, and other materials related to such 9 * distribution and use acknowledge that the software was developed 10 * by the University of California, Berkeley. The name of the 11 * University may not be used to endorse or promote products derived 12 * from this software without specific prior written permission. 13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16 * 17 * @(#)kern_sysctl.c 7.10 (Berkeley) 06/22/90 18 */ 19 20 #include "param.h" 21 #include "user.h" 22 #include "proc.h" 23 #include "text.h" 24 #include "kinfo.h" 25 #include "vm.h" 26 #include "ioctl.h" 27 #include "tty.h" 28 #include "buf.h" 29 30 31 #define snderr(e) { error = (e); goto release;} 32 extern int kinfo_doproc(), kinfo_rtable(), kinfo_vnode(); 33 struct kinfo_lock kinfo_lock; 34 35 /* ARGSUSED */ 36 getkerninfo(p, uap, retval) 37 struct proc *p; 38 register struct args { 39 int op; 40 char *where; 41 int *size; 42 int arg; 43 } *uap; 44 int *retval; 45 { 46 47 int bufsize, /* max size of users buffer */ 48 needed, locked, (*server)(), error = 0; 49 50 if (error = copyin((caddr_t)uap->size, 51 (caddr_t)&bufsize, sizeof (bufsize))) 52 goto done; 53 54 switch (ki_type(uap->op)) { 55 56 case KINFO_PROC: 57 server = kinfo_doproc; 58 break; 59 60 case KINFO_RT: 61 server = kinfo_rtable; 62 break; 63 64 case KINFO_VNODE: 65 server = kinfo_vnode; 66 break; 67 68 default: 69 error = EINVAL; 70 goto done; 71 } 72 if (uap->where == NULL || uap->size == NULL) { 73 error = (*server)(uap->op, NULL, NULL, uap->arg, &needed); 74 goto done; 75 } 76 while (kinfo_lock.kl_lock) { 77 kinfo_lock.kl_want++; 78 sleep(&kinfo_lock, PRIBIO+1); 79 kinfo_lock.kl_want--; 80 kinfo_lock.kl_locked++; 81 } 82 kinfo_lock.kl_lock++; 83 84 if (!useracc(uap->where, bufsize, B_WRITE)) 85 snderr(EFAULT); 86 /* 87 * lock down target pages - NEED DEADLOCK AVOIDANCE 88 */ 89 if (bufsize > ((int)ptob(freemem) - (20 * 1024))) /* XXX */ 90 snderr(ENOMEM); 91 if (server != kinfo_vnode) /* XXX */ 92 vslock(uap->where, bufsize); 93 locked = bufsize; 94 error = (*server)(uap->op, uap->where, &bufsize, uap->arg, &needed); 95 if (server != kinfo_vnode) /* XXX */ 96 vsunlock(uap->where, locked, B_WRITE); 97 if (error == 0) 98 error = copyout((caddr_t)&bufsize, 99 (caddr_t)uap->size, sizeof (bufsize)); 100 release: 101 kinfo_lock.kl_lock--; 102 if (kinfo_lock.kl_want) 103 wakeup(&kinfo_lock); 104 done: 105 if (!error) 106 *retval = needed; 107 return (error); 108 } 109 110 /* 111 * try over estimating by 5 procs 112 */ 113 #define KINFO_PROCSLOP (5 * sizeof (struct kinfo_proc)) 114 115 kinfo_doproc(op, where, acopysize, arg, aneeded) 116 char *where; 117 int *acopysize, *aneeded; 118 { 119 register struct proc *p; 120 register struct kinfo_proc *dp = (struct kinfo_proc *)where; 121 register needed = 0; 122 int buflen; 123 int doingzomb; 124 struct eproc eproc; 125 int error = 0; 126 127 if (where != NULL) 128 buflen = *acopysize; 129 130 p = allproc; 131 doingzomb = 0; 132 again: 133 for (; p != NULL; p = p->p_nxt) { 134 /* 135 * TODO - make more efficient (see notes below). 136 * do by session. 137 */ 138 switch (ki_op(op)) { 139 140 case KINFO_PROC_PID: 141 /* could do this with just a lookup */ 142 if (p->p_pid != (pid_t)arg) 143 continue; 144 break; 145 146 case KINFO_PROC_PGRP: 147 /* could do this by traversing pgrp */ 148 if (p->p_pgrp->pg_id != (pid_t)arg) 149 continue; 150 break; 151 152 case KINFO_PROC_TTY: 153 if ((p->p_flag&SCTTY) == 0 || 154 p->p_session->s_ttyp == NULL || 155 p->p_session->s_ttyp->t_dev != (dev_t)arg) 156 continue; 157 break; 158 159 case KINFO_PROC_UID: 160 if (p->p_uid != (uid_t)arg) 161 continue; 162 break; 163 164 case KINFO_PROC_RUID: 165 if (p->p_ruid != (uid_t)arg) 166 continue; 167 break; 168 } 169 if (where != NULL && buflen >= sizeof (struct kinfo_proc)) { 170 register struct text *txt; 171 register struct tty *tp; 172 173 if (error = copyout((caddr_t)p, &dp->kp_proc, 174 sizeof (struct proc))) 175 return (error); 176 eproc.e_paddr = p; 177 eproc.e_sess = p->p_pgrp->pg_session; 178 eproc.e_pgid = p->p_pgrp->pg_id; 179 eproc.e_jobc = p->p_pgrp->pg_jobc; 180 if ((p->p_flag&SCTTY) && 181 (tp = eproc.e_sess->s_ttyp)) { 182 eproc.e_tdev = tp->t_dev; 183 eproc.e_tpgid = tp->t_pgrp ? 184 tp->t_pgrp->pg_id : -1; 185 eproc.e_tsess = tp->t_session; 186 } else 187 eproc.e_tdev = NODEV; 188 eproc.e_flag = eproc.e_sess->s_ttyvp ? EPROC_CTTY : 0; 189 if (SESS_LEADER(p)) 190 eproc.e_flag |= EPROC_SLEADER; 191 if (p->p_wmesg) 192 strncpy(eproc.e_wmesg, p->p_wmesg, WMESGLEN); 193 if (txt = p->p_textp) { 194 eproc.e_xsize = txt->x_size; 195 eproc.e_xrssize = txt->x_rssize; 196 eproc.e_xccount = txt->x_ccount; 197 eproc.e_xswrss = txt->x_swrss; 198 } else { 199 eproc.e_xsize = eproc.e_xrssize = 200 eproc.e_xccount = eproc.e_xswrss = 0; 201 } 202 if (error = copyout((caddr_t)&eproc, &dp->kp_eproc, 203 sizeof (eproc))) 204 return (error); 205 dp++; 206 buflen -= sizeof (struct kinfo_proc); 207 } 208 needed += sizeof (struct kinfo_proc); 209 } 210 if (doingzomb == 0) { 211 p = zombproc; 212 doingzomb++; 213 goto again; 214 } 215 if (where != NULL) 216 *acopysize = (caddr_t)dp - where; 217 else 218 needed += KINFO_PROCSLOP; 219 *aneeded = needed; 220 221 return (0); 222 } 223