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