xref: /original-bsd/sys/kern/kern_sysctl.c (revision 753853ba)
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.21 (Berkeley) 02/25/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(), kinfo_loadavg(), kinfo_clockrate();
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 	case KINFO_LOADAVG:
64 		server = kinfo_loadavg;
65 		break;
66 
67 	case KINFO_CLOCKRATE:
68 		server = kinfo_clockrate;
69 		break;
70 
71 	default:
72 		error = EINVAL;
73 		goto done;
74 	}
75 	if (uap->where == NULL || uap->size == NULL) {
76 		error = (*server)(uap->op, NULL, NULL, uap->arg, &needed);
77 		goto done;
78 	}
79 	if (error = copyin((caddr_t)uap->size, (caddr_t)&bufsize,
80 	    sizeof (bufsize)))
81 		goto done;
82 	while (kinfo_lock.kl_lock) {
83 		kinfo_lock.kl_want = 1;
84 		sleep((caddr_t)&kinfo_lock, PRIBIO+1);
85 		kinfo_lock.kl_locked++;
86 	}
87 	kinfo_lock.kl_lock = 1;
88 
89 	if (!useracc(uap->where, bufsize, B_WRITE))
90 		snderr(EFAULT);
91 	if (server != kinfo_vnode)	/* XXX */
92 		vslock(uap->where, bufsize);
93 	locked = bufsize;
94 	error = (*server)(uap->op, uap->where, &bufsize, uap->arg, &needed);
95 	if (server != kinfo_vnode)	/* XXX */
96 		vsunlock(uap->where, locked, B_WRITE);
97 	if (error == 0)
98 		error = copyout((caddr_t)&bufsize,
99 				(caddr_t)uap->size, sizeof (bufsize));
100 release:
101 	kinfo_lock.kl_lock = 0;
102 	if (kinfo_lock.kl_want) {
103 		kinfo_lock.kl_want = 0;
104 		wakeup((caddr_t)&kinfo_lock);
105 	}
106 done:
107 	if (!error)
108 		*retval = needed;
109 	return (error);
110 }
111 
112 /*
113  * try over estimating by 5 procs
114  */
115 #define KINFO_PROCSLOP	(5 * sizeof (struct kinfo_proc))
116 
117 kinfo_doproc(op, where, acopysize, arg, aneeded)
118 	int op;
119 	char *where;
120 	int *acopysize, arg, *aneeded;
121 {
122 	register struct proc *p;
123 	register struct kinfo_proc *dp = (struct kinfo_proc *)where;
124 	register needed = 0;
125 	int buflen = where != NULL ? *acopysize : 0;
126 	int doingzomb;
127 	struct eproc eproc;
128 	int error = 0;
129 
130 	p = allproc;
131 	doingzomb = 0;
132 again:
133 	for (; p != NULL; p = p->p_nxt) {
134 		/*
135 		 * TODO - make more efficient (see notes below).
136 		 * do by session.
137 		 */
138 		switch (ki_op(op)) {
139 
140 		case KINFO_PROC_PID:
141 			/* could do this with just a lookup */
142 			if (p->p_pid != (pid_t)arg)
143 				continue;
144 			break;
145 
146 		case KINFO_PROC_PGRP:
147 			/* could do this by traversing pgrp */
148 			if (p->p_pgrp->pg_id != (pid_t)arg)
149 				continue;
150 			break;
151 
152 		case KINFO_PROC_TTY:
153 			if ((p->p_flag&SCTTY) == 0 ||
154 			    p->p_session->s_ttyp == NULL ||
155 			    p->p_session->s_ttyp->t_dev != (dev_t)arg)
156 				continue;
157 			break;
158 
159 		case KINFO_PROC_UID:
160 			if (p->p_ucred->cr_uid != (uid_t)arg)
161 				continue;
162 			break;
163 
164 		case KINFO_PROC_RUID:
165 			if (p->p_cred->p_ruid != (uid_t)arg)
166 				continue;
167 			break;
168 		}
169 		if (buflen >= sizeof (struct kinfo_proc)) {
170 			fill_eproc(p, &eproc);
171 			if (error = copyout((caddr_t)p, &dp->kp_proc,
172 			    sizeof (struct proc)))
173 				return (error);
174 			if (error = copyout((caddr_t)&eproc, &dp->kp_eproc,
175 			    sizeof (eproc)))
176 				return (error);
177 			dp++;
178 			buflen -= sizeof (struct kinfo_proc);
179 		}
180 		needed += sizeof (struct kinfo_proc);
181 	}
182 	if (doingzomb == 0) {
183 		p = zombproc;
184 		doingzomb++;
185 		goto again;
186 	}
187 	if (where != NULL)
188 		*acopysize = (caddr_t)dp - where;
189 	else
190 		needed += KINFO_PROCSLOP;
191 	*aneeded = needed;
192 
193 	return (0);
194 }
195 
196 /*
197  * Fill in an eproc structure for the specified process.
198  */
199 void
200 fill_eproc(p, ep)
201 	register struct proc *p;
202 	register struct eproc *ep;
203 {
204 	register struct tty *tp;
205 
206 	ep->e_paddr = p;
207 	ep->e_sess = p->p_pgrp->pg_session;
208 	ep->e_pcred = *p->p_cred;
209 	ep->e_ucred = *p->p_ucred;
210 	if (p->p_stat == SIDL || p->p_stat == SZOMB) {
211 		ep->e_vm.vm_rssize = 0;
212 		ep->e_vm.vm_tsize = 0;
213 		ep->e_vm.vm_dsize = 0;
214 		ep->e_vm.vm_ssize = 0;
215 #ifndef sparc
216 		/* ep->e_vm.vm_pmap = XXX; */
217 #endif
218 	} else {
219 		register struct vmspace *vm = p->p_vmspace;
220 
221 		ep->e_vm.vm_rssize = vm->vm_rssize;
222 		ep->e_vm.vm_tsize = vm->vm_tsize;
223 		ep->e_vm.vm_dsize = vm->vm_dsize;
224 		ep->e_vm.vm_ssize = vm->vm_ssize;
225 #ifndef sparc
226 		ep->e_vm.vm_pmap = vm->vm_pmap;
227 #endif
228 	}
229 	if (p->p_pptr)
230 		ep->e_ppid = p->p_pptr->p_pid;
231 	else
232 		ep->e_ppid = 0;
233 	ep->e_pgid = p->p_pgrp->pg_id;
234 	ep->e_jobc = p->p_pgrp->pg_jobc;
235 	if ((p->p_flag&SCTTY) &&
236 	     (tp = ep->e_sess->s_ttyp)) {
237 		ep->e_tdev = tp->t_dev;
238 		ep->e_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
239 		ep->e_tsess = tp->t_session;
240 	} else
241 		ep->e_tdev = NODEV;
242 	ep->e_flag = ep->e_sess->s_ttyvp ? EPROC_CTTY : 0;
243 	if (SESS_LEADER(p))
244 		ep->e_flag |= EPROC_SLEADER;
245 	if (p->p_wmesg)
246 		strncpy(ep->e_wmesg, p->p_wmesg, WMESGLEN);
247 	ep->e_xsize = ep->e_xrssize = 0;
248 	ep->e_xccount = ep->e_xswrss = 0;
249 }
250 
251 /*
252  * Get file structures.
253  */
254 kinfo_file(op, where, acopysize, arg, aneeded)
255 	int op;
256 	register char *where;
257 	int *acopysize, arg, *aneeded;
258 {
259 	int buflen, needed, error;
260 	struct file *fp;
261 	char *start = where;
262 
263 	if (where == NULL) {
264 		/*
265 		 * overestimate by 10 files
266 		 */
267 		*aneeded = sizeof (filehead) +
268 			(nfiles + 10) * sizeof (struct file);
269 		return (0);
270 	}
271 	buflen = *acopysize;
272 	needed = 0;
273 
274 	/*
275 	 * first copyout filehead
276 	 */
277 	if (buflen > sizeof (filehead)) {
278 		if (error = copyout((caddr_t)&filehead, where,
279 		    sizeof (filehead)))
280 			return (error);
281 		buflen -= sizeof (filehead);
282 		where += sizeof (filehead);
283 	}
284 	needed += sizeof (filehead);
285 
286 	/*
287 	 * followed by an array of file structures
288 	 */
289 	for (fp = filehead; fp != NULL; fp = fp->f_filef) {
290 		if (buflen > sizeof (struct file)) {
291 			if (error = copyout((caddr_t)fp, where,
292 			    sizeof (struct file)))
293 				return (error);
294 			buflen -= sizeof (struct file);
295 			where += sizeof (struct file);
296 		}
297 		needed += sizeof (struct file);
298 	}
299 	*acopysize = where - start;
300 	*aneeded = needed;
301 
302 	return (0);
303 }
304