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.4 (Berkeley) 02/14/90 18 */ 19 20 #include "param.h" 21 #include "user.h" 22 #include "proc.h" 23 #include "kinfo.h" 24 #include "vm.h" 25 #include "ioctl.h" 26 #include "tty.h" 27 #include "buf.h" 28 29 30 #define snderr(e) { error = (e); goto release;} 31 extern int kinfo_doproc(), kinfo_rtable(); 32 struct kinfo_lock kinfo_lock; 33 34 getkinfo() 35 { 36 register struct a { 37 int op; 38 char *where; 39 int *size; 40 int arg; 41 } *uap = (struct a *)u.u_ap; 42 int wanted, (*server)(), error = 0; 43 int bufsize, /* max size of users buffer */ 44 copysize, /* size copied */ 45 needed, 46 locked; 47 48 while (kinfo_lock.kl_lock) { 49 kinfo_lock.kl_want++; 50 sleep(&kinfo_lock, PRIBIO+1); 51 kinfo_lock.kl_want--; 52 kinfo_lock.kl_locked++; 53 } 54 kinfo_lock.kl_lock++; 55 56 switch (ki_type(uap->op)) { 57 58 case KINFO_PROC: 59 server = kinfo_doproc; 60 break; 61 62 case KINFO_RT: 63 server = kinfo_rtable; 64 break; 65 66 default: 67 snderr(EINVAL); 68 } 69 if (error = (*server)(uap->op, NULL, NULL, uap->arg, &needed)) 70 goto release; 71 if (uap->where == NULL || uap->size == NULL) 72 goto release; /* only want estimate of bufsize */ 73 if (error = copyin((caddr_t)uap->size, 74 (caddr_t)&bufsize, sizeof (bufsize))) 75 goto release; 76 locked = copysize = MIN(needed, bufsize); 77 if (!useracc(uap->where, copysize, B_WRITE)) 78 snderr(EFAULT); 79 /* 80 * lock down target pages - NEED DEADLOCK AVOIDANCE 81 */ 82 if (copysize > ((int)ptob(freemem) - (20 * 1024))) /* XXX */ 83 snderr(ENOMEM); 84 vslock(uap->where, copysize); 85 error = (*server)(uap->op, uap->where, ©size, uap->arg, &needed); 86 vsunlock(uap->where, locked, B_WRITE); 87 if (error) 88 goto release; 89 error = copyout((caddr_t)©size, 90 (caddr_t)uap->size, sizeof (copysize)); 91 92 release: 93 kinfo_lock.kl_lock--; 94 if (kinfo_lock.kl_want) 95 wakeup(&kinfo_lock); 96 if (error) 97 u.u_error = error; 98 else 99 u.u_r.r_val1 = needed; 100 } 101 102 /* 103 * try over estimating by 5 procs 104 */ 105 #define KINFO_PROCSLOP (5 * sizeof (struct kinfo_proc)) 106 107 int kinfo_proc_userfailed; 108 int kinfo_proc_wefailed; 109 110 kinfo_doprocs(op, where, acopysize, arg, aneeded) 111 char *where; 112 int *acopysize, *aneeded; 113 { 114 register struct proc *p; 115 register caddr_t dp = (caddr_t)where; 116 register needed = 0; 117 int buflen; 118 int doingzomb; 119 struct eproc eproc; 120 struct tty *tp; 121 int error = 0; 122 123 if (where != NULL) 124 buflen = *acopysize; 125 126 p = allproc; 127 doingzomb = 0; 128 again: 129 for (; p != NULL; p = p->p_nxt) { 130 /* 131 * TODO - make more efficient (see notes below). 132 * do by session. 133 */ 134 switch (ki_op(op)) { 135 136 case KINFO_PROC_PID: 137 /* could do this with just a lookup */ 138 if (p->p_pid != (pid_t)arg) 139 continue; 140 break; 141 142 case KINFO_PROC_PGRP: 143 /* could do this by traversing pgrp */ 144 if (p->p_pgrp->pg_id != (pid_t)arg) 145 continue; 146 break; 147 148 case KINFO_PROC_TTY: 149 if ((p->p_flag&SCTTY) == 0 || 150 p->p_session->s_ttyp == NULL || 151 p->p_session->s_ttyp->t_dev != (dev_t)arg) 152 continue; 153 break; 154 155 case KINFO_PROC_UID: 156 if (p->p_uid != (uid_t)arg) 157 continue; 158 break; 159 160 case KINFO_PROC_RUID: 161 if (p->p_ruid != (uid_t)arg) 162 continue; 163 break; 164 } 165 if (where != NULL && buflen >= sizeof (struct kinfo_proc)) { 166 if (error = copyout((caddr_t)p, dp, 167 sizeof (struct proc))) 168 return (error); 169 dp += sizeof (struct proc); 170 eproc.kp_paddr = p; 171 eproc.kp_sess = p->p_pgrp->pg_session; 172 eproc.kp_pgid = p->p_pgrp->pg_id; 173 eproc.kp_jobc = p->p_pgrp->pg_jobc; 174 tp = p->p_pgrp->pg_session->s_ttyp; 175 if ((p->p_flag&SCTTY) && tp != NULL) { 176 eproc.kp_tdev = tp->t_dev; 177 eproc.kp_tpgid = tp->t_pgrp ? 178 tp->t_pgrp->pg_id : -1; 179 eproc.kp_tsess = tp->t_session; 180 } else 181 eproc.kp_tdev = NODEV; 182 if (error = copyout((caddr_t)&eproc, dp, 183 sizeof (eproc))) 184 return (error); 185 dp += sizeof (eproc); 186 buflen -= sizeof (struct kinfo_proc); 187 } 188 needed += sizeof (struct kinfo_proc); 189 } 190 if (doingzomb == 0) { 191 p = zombproc; 192 doingzomb++; 193 goto again; 194 } 195 if (where != NULL) 196 *acopysize = dp - where; 197 else 198 needed += KINFO_PROCSLOP; 199 *aneeded = needed; 200 201 return (0); 202 } 203