xref: /csrg-svn/sys/kern/kern_sysctl.c (revision 41181)
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.8 (Berkeley) 05/01/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 caddr_t dp = (caddr_t)where;
119 	register needed = 0;
120 	int buflen;
121 	int doingzomb;
122 	struct eproc eproc;
123 	struct tty *tp;
124 	int error = 0;
125 
126 	if (where != NULL)
127 		buflen = *acopysize;
128 
129 	p = allproc;
130 	doingzomb = 0;
131 again:
132 	for (; p != NULL; p = p->p_nxt) {
133 		/*
134 		 * TODO - make more efficient (see notes below).
135 		 * do by session.
136 		 */
137 		switch (ki_op(op)) {
138 
139 		case KINFO_PROC_PID:
140 			/* could do this with just a lookup */
141 			if (p->p_pid != (pid_t)arg)
142 				continue;
143 			break;
144 
145 		case KINFO_PROC_PGRP:
146 			/* could do this by traversing pgrp */
147 			if (p->p_pgrp->pg_id != (pid_t)arg)
148 				continue;
149 			break;
150 
151 		case KINFO_PROC_TTY:
152 			if ((p->p_flag&SCTTY) == 0 ||
153 			    p->p_session->s_ttyp == NULL ||
154 			    p->p_session->s_ttyp->t_dev != (dev_t)arg)
155 				continue;
156 			break;
157 
158 		case KINFO_PROC_UID:
159 			if (p->p_uid != (uid_t)arg)
160 				continue;
161 			break;
162 
163 		case KINFO_PROC_RUID:
164 			if (p->p_ruid != (uid_t)arg)
165 				continue;
166 			break;
167 		}
168 		if (where != NULL && buflen >= sizeof (struct kinfo_proc)) {
169 			register struct text *txt;
170 
171 			if (error = copyout((caddr_t)p, dp,
172 			    sizeof (struct proc)))
173 				return (error);
174 			dp += sizeof (struct proc);
175 			/*
176 			 *	XXX NEED ALLIGNMENT
177 			 */
178 			eproc.e_paddr = p;
179 			eproc.e_sess = p->p_pgrp->pg_session;
180 			eproc.e_pgid = p->p_pgrp->pg_id;
181 			eproc.e_jobc = p->p_pgrp->pg_jobc;
182 			if (tp = p->p_pgrp->pg_session->s_ttyp) {
183 				/* up to caller to check for SCTTY */
184 				eproc.e_tdev = tp->t_dev;
185 				eproc.e_tpgid = tp->t_pgrp ?
186 					tp->t_pgrp->pg_id : -1;
187 				eproc.e_tsess = tp->t_session;
188 			} else
189 				eproc.e_tdev = NODEV;
190 			if (p->p_wmesg)
191 				strncpy(eproc.e_wmesg, p->p_wmesg, WMESGLEN);
192 			if (txt = p->p_textp) {
193 				eproc.e_xsize = txt->x_size;
194 				eproc.e_xrssize = txt->x_rssize;
195 				eproc.e_xccount = txt->x_ccount;
196 				eproc.e_xswrss = txt->x_swrss;
197 			} else {
198 				eproc.e_xsize = eproc.e_xrssize =
199 				  eproc.e_xccount =  eproc.e_xswrss = 0;
200 			}
201 			if (error = copyout((caddr_t)&eproc, dp,
202 			    sizeof (eproc)))
203 				return (error);
204 			dp += sizeof (eproc);
205 			buflen -= sizeof (struct kinfo_proc);
206 		}
207 		needed += sizeof (struct kinfo_proc);
208 	}
209 	if (doingzomb == 0) {
210 		p = zombproc;
211 		doingzomb++;
212 		goto again;
213 	}
214 	if (where != NULL)
215 		*acopysize = dp - where;
216 	else
217 		needed += KINFO_PROCSLOP;
218 	*aneeded = needed;
219 
220 	return (0);
221 }
222