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