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.9 (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 getkerninfo() 36 { 37 register struct a { 38 int op; 39 char *where; 40 int *size; 41 int arg; 42 } *uap = (struct a *)u.u_ap; 43 44 int bufsize, /* max size of users buffer */ 45 needed, locked, (*server)(), error = 0; 46 47 if (error = copyin((caddr_t)uap->size, 48 (caddr_t)&bufsize, sizeof (bufsize))) 49 goto done; 50 51 switch (ki_type(uap->op)) { 52 53 case KINFO_PROC: 54 server = kinfo_doproc; 55 break; 56 57 case KINFO_RT: 58 server = kinfo_rtable; 59 break; 60 61 case KINFO_VNODE: 62 server = kinfo_vnode; 63 break; 64 65 default: 66 error = EINVAL; 67 goto done; 68 } 69 if (uap->where == NULL || uap->size == NULL) { 70 error = (*server)(uap->op, NULL, NULL, uap->arg, &needed); 71 goto done; 72 } 73 while (kinfo_lock.kl_lock) { 74 kinfo_lock.kl_want++; 75 sleep(&kinfo_lock, PRIBIO+1); 76 kinfo_lock.kl_want--; 77 kinfo_lock.kl_locked++; 78 } 79 kinfo_lock.kl_lock++; 80 81 if (!useracc(uap->where, bufsize, B_WRITE)) 82 snderr(EFAULT); 83 /* 84 * lock down target pages - NEED DEADLOCK AVOIDANCE 85 */ 86 if (bufsize > ((int)ptob(freemem) - (20 * 1024))) /* XXX */ 87 snderr(ENOMEM); 88 if (server != kinfo_vnode) /* XXX */ 89 vslock(uap->where, bufsize); 90 locked = bufsize; 91 error = (*server)(uap->op, uap->where, &bufsize, uap->arg, &needed); 92 if (server != kinfo_vnode) /* XXX */ 93 vsunlock(uap->where, locked, B_WRITE); 94 if (error == 0) 95 error = copyout((caddr_t)&bufsize, 96 (caddr_t)uap->size, sizeof (bufsize)); 97 release: 98 kinfo_lock.kl_lock--; 99 if (kinfo_lock.kl_want) 100 wakeup(&kinfo_lock); 101 done: 102 if (error) 103 u.u_error = error; 104 else 105 u.u_r.r_val1 = needed; 106 } 107 108 /* 109 * try over estimating by 5 procs 110 */ 111 #define KINFO_PROCSLOP (5 * sizeof (struct kinfo_proc)) 112 113 kinfo_doproc(op, where, acopysize, arg, aneeded) 114 char *where; 115 int *acopysize, *aneeded; 116 { 117 register struct proc *p; 118 register struct kinfo_proc *dp = (struct kinfo_proc *)where; 119 register needed = 0; 120 int buflen; 121 int doingzomb; 122 struct eproc eproc; 123 int error = 0; 124 125 if (where != NULL) 126 buflen = *acopysize; 127 128 p = allproc; 129 doingzomb = 0; 130 again: 131 for (; p != NULL; p = p->p_nxt) { 132 /* 133 * TODO - make more efficient (see notes below). 134 * do by session. 135 */ 136 switch (ki_op(op)) { 137 138 case KINFO_PROC_PID: 139 /* could do this with just a lookup */ 140 if (p->p_pid != (pid_t)arg) 141 continue; 142 break; 143 144 case KINFO_PROC_PGRP: 145 /* could do this by traversing pgrp */ 146 if (p->p_pgrp->pg_id != (pid_t)arg) 147 continue; 148 break; 149 150 case KINFO_PROC_TTY: 151 if ((p->p_flag&SCTTY) == 0 || 152 p->p_session->s_ttyp == NULL || 153 p->p_session->s_ttyp->t_dev != (dev_t)arg) 154 continue; 155 break; 156 157 case KINFO_PROC_UID: 158 if (p->p_uid != (uid_t)arg) 159 continue; 160 break; 161 162 case KINFO_PROC_RUID: 163 if (p->p_ruid != (uid_t)arg) 164 continue; 165 break; 166 } 167 if (where != NULL && buflen >= sizeof (struct kinfo_proc)) { 168 register struct text *txt; 169 register struct tty *tp; 170 171 if (error = copyout((caddr_t)p, &dp->kp_proc, 172 sizeof (struct proc))) 173 return (error); 174 eproc.e_paddr = p; 175 eproc.e_sess = p->p_pgrp->pg_session; 176 eproc.e_pgid = p->p_pgrp->pg_id; 177 eproc.e_jobc = p->p_pgrp->pg_jobc; 178 if ((p->p_flag&SCTTY) && 179 (tp = eproc.e_sess->s_ttyp)) { 180 eproc.e_tdev = tp->t_dev; 181 eproc.e_tpgid = tp->t_pgrp ? 182 tp->t_pgrp->pg_id : -1; 183 eproc.e_tsess = tp->t_session; 184 } else 185 eproc.e_tdev = NODEV; 186 eproc.e_flag = eproc.e_sess->s_ttyvp ? EPROC_CTTY : 0; 187 if (SESS_LEADER(p)) 188 eproc.e_flag |= EPROC_SLEADER; 189 if (p->p_wmesg) 190 strncpy(eproc.e_wmesg, p->p_wmesg, WMESGLEN); 191 if (txt = p->p_textp) { 192 eproc.e_xsize = txt->x_size; 193 eproc.e_xrssize = txt->x_rssize; 194 eproc.e_xccount = txt->x_ccount; 195 eproc.e_xswrss = txt->x_swrss; 196 } else { 197 eproc.e_xsize = eproc.e_xrssize = 198 eproc.e_xccount = eproc.e_xswrss = 0; 199 } 200 if (error = copyout((caddr_t)&eproc, &dp->kp_eproc, 201 sizeof (eproc))) 202 return (error); 203 dp++; 204 buflen -= sizeof (struct kinfo_proc); 205 } 206 needed += sizeof (struct kinfo_proc); 207 } 208 if (doingzomb == 0) { 209 p = zombproc; 210 doingzomb++; 211 goto again; 212 } 213 if (where != NULL) 214 *acopysize = (caddr_t)dp - where; 215 else 216 needed += KINFO_PROCSLOP; 217 *aneeded = needed; 218 219 return (0); 220 } 221