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