xref: /csrg-svn/sys/kern/kern_sysctl.c (revision 52405)
1 /*
2  * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  *
7  *	@(#)kern_sysctl.c	7.20 (Berkeley) 02/05/92
8  */
9 
10 #include "param.h"
11 #include "proc.h"
12 #include "kinfo.h"
13 #include "ioctl.h"
14 #include "tty.h"
15 #include "buf.h"
16 #include "file.h"
17 
18 #include "vm/vm.h"
19 
20 #include "kinfo_proc.h"
21 
22 #define snderr(e) { error = (e); goto release;}
23 extern int kinfo_doproc(), kinfo_rtable(), kinfo_vnode(), kinfo_file();
24 extern int kinfo_meter();
25 struct kinfo_lock kinfo_lock;
26 
27 /* ARGSUSED */
28 getkerninfo(p, uap, retval)
29 	struct proc *p;
30 	register struct args {
31 		int	op;
32 		char	*where;
33 		int	*size;
34 		int	arg;
35 	} *uap;
36 	int *retval;
37 {
38 	int bufsize;		/* max size of users buffer */
39 	int needed, locked, (*server)(), error = 0;
40 
41 	switch (ki_type(uap->op)) {
42 
43 	case KINFO_PROC:
44 		server = kinfo_doproc;
45 		break;
46 
47 	case KINFO_RT:
48 		server = kinfo_rtable;
49 		break;
50 
51 	case KINFO_VNODE:
52 		server = kinfo_vnode;
53 		break;
54 
55 	case KINFO_FILE:
56 		server = kinfo_file;
57 		break;
58 
59 	case KINFO_METER:
60 		server = kinfo_meter;
61 		break;
62 
63 	default:
64 		error = EINVAL;
65 		goto done;
66 	}
67 	if (uap->where == NULL || uap->size == NULL) {
68 		error = (*server)(uap->op, NULL, NULL, uap->arg, &needed);
69 		goto done;
70 	}
71 	if (error = copyin((caddr_t)uap->size, (caddr_t)&bufsize,
72 	    sizeof (bufsize)))
73 		goto done;
74 	while (kinfo_lock.kl_lock) {
75 		kinfo_lock.kl_want = 1;
76 		sleep((caddr_t)&kinfo_lock, PRIBIO+1);
77 		kinfo_lock.kl_locked++;
78 	}
79 	kinfo_lock.kl_lock = 1;
80 
81 	if (!useracc(uap->where, bufsize, B_WRITE))
82 		snderr(EFAULT);
83 	if (server != kinfo_vnode)	/* XXX */
84 		vslock(uap->where, bufsize);
85 	locked = bufsize;
86 	error = (*server)(uap->op, uap->where, &bufsize, uap->arg, &needed);
87 	if (server != kinfo_vnode)	/* XXX */
88 		vsunlock(uap->where, locked, B_WRITE);
89 	if (error == 0)
90 		error = copyout((caddr_t)&bufsize,
91 				(caddr_t)uap->size, sizeof (bufsize));
92 release:
93 	kinfo_lock.kl_lock = 0;
94 	if (kinfo_lock.kl_want) {
95 		kinfo_lock.kl_want = 0;
96 		wakeup((caddr_t)&kinfo_lock);
97 	}
98 done:
99 	if (!error)
100 		*retval = needed;
101 	return (error);
102 }
103 
104 /*
105  * try over estimating by 5 procs
106  */
107 #define KINFO_PROCSLOP	(5 * sizeof (struct kinfo_proc))
108 
109 kinfo_doproc(op, where, acopysize, arg, aneeded)
110 	int op;
111 	char *where;
112 	int *acopysize, arg, *aneeded;
113 {
114 	register struct proc *p;
115 	register struct kinfo_proc *dp = (struct kinfo_proc *)where;
116 	register needed = 0;
117 	int buflen = where != NULL ? *acopysize : 0;
118 	int doingzomb;
119 	struct eproc eproc;
120 	int error = 0;
121 
122 	p = allproc;
123 	doingzomb = 0;
124 again:
125 	for (; p != NULL; p = p->p_nxt) {
126 		/*
127 		 * TODO - make more efficient (see notes below).
128 		 * do by session.
129 		 */
130 		switch (ki_op(op)) {
131 
132 		case KINFO_PROC_PID:
133 			/* could do this with just a lookup */
134 			if (p->p_pid != (pid_t)arg)
135 				continue;
136 			break;
137 
138 		case KINFO_PROC_PGRP:
139 			/* could do this by traversing pgrp */
140 			if (p->p_pgrp->pg_id != (pid_t)arg)
141 				continue;
142 			break;
143 
144 		case KINFO_PROC_TTY:
145 			if ((p->p_flag&SCTTY) == 0 ||
146 			    p->p_session->s_ttyp == NULL ||
147 			    p->p_session->s_ttyp->t_dev != (dev_t)arg)
148 				continue;
149 			break;
150 
151 		case KINFO_PROC_UID:
152 			if (p->p_ucred->cr_uid != (uid_t)arg)
153 				continue;
154 			break;
155 
156 		case KINFO_PROC_RUID:
157 			if (p->p_cred->p_ruid != (uid_t)arg)
158 				continue;
159 			break;
160 		}
161 		if (buflen >= sizeof (struct kinfo_proc)) {
162 			fill_eproc(p, &eproc);
163 			if (error = copyout((caddr_t)p, &dp->kp_proc,
164 			    sizeof (struct proc)))
165 				return (error);
166 			if (error = copyout((caddr_t)&eproc, &dp->kp_eproc,
167 			    sizeof (eproc)))
168 				return (error);
169 			dp++;
170 			buflen -= sizeof (struct kinfo_proc);
171 		}
172 		needed += sizeof (struct kinfo_proc);
173 	}
174 	if (doingzomb == 0) {
175 		p = zombproc;
176 		doingzomb++;
177 		goto again;
178 	}
179 	if (where != NULL)
180 		*acopysize = (caddr_t)dp - where;
181 	else
182 		needed += KINFO_PROCSLOP;
183 	*aneeded = needed;
184 
185 	return (0);
186 }
187 
188 /*
189  * Fill in an eproc structure for the specified process.
190  */
191 void
192 fill_eproc(p, ep)
193 	register struct proc *p;
194 	register struct eproc *ep;
195 {
196 	register struct tty *tp;
197 
198 	ep->e_paddr = p;
199 	ep->e_sess = p->p_pgrp->pg_session;
200 	ep->e_pcred = *p->p_cred;
201 	ep->e_ucred = *p->p_ucred;
202 	if (p->p_stat == SIDL || p->p_stat == SZOMB) {
203 		ep->e_vm.vm_rssize = 0;
204 		ep->e_vm.vm_tsize = 0;
205 		ep->e_vm.vm_dsize = 0;
206 		ep->e_vm.vm_ssize = 0;
207 #ifndef sparc
208 		/* ep->e_vm.vm_pmap = XXX; */
209 #endif
210 	} else {
211 		register struct vmspace *vm = p->p_vmspace;
212 
213 		ep->e_vm.vm_rssize = vm->vm_rssize;
214 		ep->e_vm.vm_tsize = vm->vm_tsize;
215 		ep->e_vm.vm_dsize = vm->vm_dsize;
216 		ep->e_vm.vm_ssize = vm->vm_ssize;
217 #ifndef sparc
218 		ep->e_vm.vm_pmap = vm->vm_pmap;
219 #endif
220 	}
221 	if (p->p_pptr)
222 		ep->e_ppid = p->p_pptr->p_pid;
223 	else
224 		ep->e_ppid = 0;
225 	ep->e_pgid = p->p_pgrp->pg_id;
226 	ep->e_jobc = p->p_pgrp->pg_jobc;
227 	if ((p->p_flag&SCTTY) &&
228 	     (tp = ep->e_sess->s_ttyp)) {
229 		ep->e_tdev = tp->t_dev;
230 		ep->e_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
231 		ep->e_tsess = tp->t_session;
232 	} else
233 		ep->e_tdev = NODEV;
234 	ep->e_flag = ep->e_sess->s_ttyvp ? EPROC_CTTY : 0;
235 	if (SESS_LEADER(p))
236 		ep->e_flag |= EPROC_SLEADER;
237 	if (p->p_wmesg)
238 		strncpy(ep->e_wmesg, p->p_wmesg, WMESGLEN);
239 	ep->e_xsize = ep->e_xrssize = 0;
240 	ep->e_xccount = ep->e_xswrss = 0;
241 }
242 
243 /*
244  * Get file structures.
245  */
246 kinfo_file(op, where, acopysize, arg, aneeded)
247 	int op;
248 	register char *where;
249 	int *acopysize, arg, *aneeded;
250 {
251 	int buflen, needed, error;
252 	struct file *fp;
253 	char *start = where;
254 
255 	if (where == NULL) {
256 		/*
257 		 * overestimate by 10 files
258 		 */
259 		*aneeded = sizeof (filehead) +
260 			(nfiles + 10) * sizeof (struct file);
261 		return (0);
262 	}
263 	buflen = *acopysize;
264 	needed = 0;
265 
266 	/*
267 	 * first copyout filehead
268 	 */
269 	if (buflen > sizeof (filehead)) {
270 		if (error = copyout((caddr_t)&filehead, where,
271 		    sizeof (filehead)))
272 			return (error);
273 		buflen -= sizeof (filehead);
274 		where += sizeof (filehead);
275 	}
276 	needed += sizeof (filehead);
277 
278 	/*
279 	 * followed by an array of file structures
280 	 */
281 	for (fp = filehead; fp != NULL; fp = fp->f_filef) {
282 		if (buflen > sizeof (struct file)) {
283 			if (error = copyout((caddr_t)fp, where,
284 			    sizeof (struct file)))
285 				return (error);
286 			buflen -= sizeof (struct file);
287 			where += sizeof (struct file);
288 		}
289 		needed += sizeof (struct file);
290 	}
291 	*acopysize = where - start;
292 	*aneeded = needed;
293 
294 	return (0);
295 }
296