xref: /csrg-svn/sys/kern/kern_sysctl.c (revision 40206)
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.5 (Berkeley) 02/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();
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 		copysize, 	/* size copied */
46 		needed,	locked, (*server)(), error = 0;
47 
48 	if (error = copyin((caddr_t)uap->size,
49 				(caddr_t)&bufsize, sizeof (bufsize)))
50 		goto bad;
51 
52 	switch (ki_type(uap->op)) {
53 
54 	case KINFO_PROC:
55 		server = kinfo_doproc;
56 		break;
57 
58 	case KINFO_RT:
59 		server = kinfo_rtable;
60 		break;
61 
62 	default:
63 		error = EINVAL;
64 		goto bad;
65 	}
66 	while (kinfo_lock.kl_lock) {
67 		kinfo_lock.kl_want++;
68 		sleep(&kinfo_lock, PRIBIO+1);
69 		kinfo_lock.kl_want--;
70 		kinfo_lock.kl_locked++;
71 	}
72 	kinfo_lock.kl_lock++;
73 
74 	if (error = (*server)(uap->op, NULL, NULL, uap->arg, &needed))
75 		goto release;
76 	if (uap->where == NULL || uap->size == NULL)
77 		goto release;  /* only want estimate of bufsize */
78 	locked = copysize = MIN(needed, bufsize);
79 	if (!useracc(uap->where, copysize, B_WRITE))
80 		snderr(EFAULT);
81 	/*
82 	 * lock down target pages - NEED DEADLOCK AVOIDANCE
83 	 */
84 	if (copysize > ((int)ptob(freemem) - (20 * 1024))) 	/* XXX */
85 		snderr(ENOMEM);
86 	vslock(uap->where, copysize);
87 	error = (*server)(uap->op, uap->where, &copysize, uap->arg, &needed);
88 	vsunlock(uap->where, locked, B_WRITE);
89 	if (error)
90 		goto release;
91 	error = copyout((caddr_t)&copysize,
92 				(caddr_t)uap->size, sizeof (copysize));
93 
94 release:
95 	kinfo_lock.kl_lock--;
96 	if (kinfo_lock.kl_want)
97 		wakeup(&kinfo_lock);
98 bad:
99 	if (error)
100 		u.u_error = error;
101 	else
102 		u.u_r.r_val1 = needed;
103 }
104 
105 /*
106  * try over estimating by 5 procs
107  */
108 #define KINFO_PROCSLOP	(5 * sizeof (struct kinfo_proc))
109 
110 int kinfo_proc_userfailed;
111 int kinfo_proc_wefailed;
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 			eproc.e_paddr = p;
176 			eproc.e_sess = p->p_pgrp->pg_session;
177 			eproc.e_pgid = p->p_pgrp->pg_id;
178 			eproc.e_jobc = p->p_pgrp->pg_jobc;
179 			tp = p->p_pgrp->pg_session->s_ttyp;
180 			if ((p->p_flag&SCTTY) && tp != NULL) {
181 				eproc.e_tdev = tp->t_dev;
182 				eproc.e_tpgid = tp->t_pgrp ?
183 					tp->t_pgrp->pg_id : -1;
184 				eproc.e_tsess = tp->t_session;
185 			} else
186 				eproc.e_tdev = NODEV;
187 			if (p->p_wmesg)
188 				strncpy(eproc.e_wmesg, p->p_wmesg, WMESGLEN);
189 			if (txt = p->p_textp) {
190 				eproc.e_xsize = txt->x_size;
191 				eproc.e_xrssize = txt->x_rssize;
192 				eproc.e_xccount = txt->x_ccount;
193 				eproc.e_xswrss = txt->x_swrss;
194 			} else {
195 				eproc.e_xsize = eproc.e_xrssize =
196 				  eproc.e_xccount =  eproc.e_xswrss = 0;
197 			}
198 			if (error = copyout((caddr_t)&eproc, dp,
199 			    sizeof (eproc)))
200 				return (error);
201 			dp += sizeof (eproc);
202 			buflen -= sizeof (struct kinfo_proc);
203 		}
204 		needed += sizeof (struct kinfo_proc);
205 	}
206 	if (doingzomb == 0) {
207 		p = zombproc;
208 		doingzomb++;
209 		goto again;
210 	}
211 	if (where != NULL)
212 		*acopysize = dp - where;
213 	else
214 		needed += KINFO_PROCSLOP;
215 	*aneeded = needed;
216 
217 	return (0);
218 }
219