xref: /original-bsd/sys/kern/kern_sysctl.c (revision 608e088d)
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.10 (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 /* ARGSUSED */
36 getkerninfo(p, uap, retval)
37 	struct proc *p;
38 	register struct args {
39 		int	op;
40 		char	*where;
41 		int	*size;
42 		int	arg;
43 	} *uap;
44 	int *retval;
45 {
46 
47 	int	bufsize,	/* max size of users buffer */
48 		needed,	locked, (*server)(), error = 0;
49 
50 	if (error = copyin((caddr_t)uap->size,
51 				(caddr_t)&bufsize, sizeof (bufsize)))
52 		goto done;
53 
54 	switch (ki_type(uap->op)) {
55 
56 	case KINFO_PROC:
57 		server = kinfo_doproc;
58 		break;
59 
60 	case KINFO_RT:
61 		server = kinfo_rtable;
62 		break;
63 
64 	case KINFO_VNODE:
65 		server = kinfo_vnode;
66 		break;
67 
68 	default:
69 		error = EINVAL;
70 		goto done;
71 	}
72 	if (uap->where == NULL || uap->size == NULL) {
73 		error = (*server)(uap->op, NULL, NULL, uap->arg, &needed);
74 		goto done;
75 	}
76 	while (kinfo_lock.kl_lock) {
77 		kinfo_lock.kl_want++;
78 		sleep(&kinfo_lock, PRIBIO+1);
79 		kinfo_lock.kl_want--;
80 		kinfo_lock.kl_locked++;
81 	}
82 	kinfo_lock.kl_lock++;
83 
84 	if (!useracc(uap->where, bufsize, B_WRITE))
85 		snderr(EFAULT);
86 	/*
87 	 * lock down target pages - NEED DEADLOCK AVOIDANCE
88 	 */
89 	if (bufsize > ((int)ptob(freemem) - (20 * 1024))) 	/* XXX */
90 		snderr(ENOMEM);
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--;
102 	if (kinfo_lock.kl_want)
103 		wakeup(&kinfo_lock);
104 done:
105 	if (!error)
106 		*retval = needed;
107 	return (error);
108 }
109 
110 /*
111  * try over estimating by 5 procs
112  */
113 #define KINFO_PROCSLOP	(5 * sizeof (struct kinfo_proc))
114 
115 kinfo_doproc(op, where, acopysize, arg, aneeded)
116 	char *where;
117 	int *acopysize, *aneeded;
118 {
119 	register struct proc *p;
120 	register struct kinfo_proc *dp = (struct kinfo_proc *)where;
121 	register needed = 0;
122 	int buflen;
123 	int doingzomb;
124 	struct eproc eproc;
125 	int error = 0;
126 
127 	if (where != NULL)
128 		buflen = *acopysize;
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_uid != (uid_t)arg)
161 				continue;
162 			break;
163 
164 		case KINFO_PROC_RUID:
165 			if (p->p_ruid != (uid_t)arg)
166 				continue;
167 			break;
168 		}
169 		if (where != NULL && buflen >= sizeof (struct kinfo_proc)) {
170 			register struct text *txt;
171 			register struct tty *tp;
172 
173 			if (error = copyout((caddr_t)p, &dp->kp_proc,
174 			    sizeof (struct proc)))
175 				return (error);
176 			eproc.e_paddr = p;
177 			eproc.e_sess = p->p_pgrp->pg_session;
178 			eproc.e_pgid = p->p_pgrp->pg_id;
179 			eproc.e_jobc = p->p_pgrp->pg_jobc;
180 			if ((p->p_flag&SCTTY) &&
181 			     (tp = eproc.e_sess->s_ttyp)) {
182 				eproc.e_tdev = tp->t_dev;
183 				eproc.e_tpgid = tp->t_pgrp ?
184 					tp->t_pgrp->pg_id : -1;
185 				eproc.e_tsess = tp->t_session;
186 			} else
187 				eproc.e_tdev = NODEV;
188 			eproc.e_flag = eproc.e_sess->s_ttyvp ? EPROC_CTTY : 0;
189 			if (SESS_LEADER(p))
190 				eproc.e_flag |= EPROC_SLEADER;
191 			if (p->p_wmesg)
192 				strncpy(eproc.e_wmesg, p->p_wmesg, WMESGLEN);
193 			if (txt = p->p_textp) {
194 				eproc.e_xsize = txt->x_size;
195 				eproc.e_xrssize = txt->x_rssize;
196 				eproc.e_xccount = txt->x_ccount;
197 				eproc.e_xswrss = txt->x_swrss;
198 			} else {
199 				eproc.e_xsize = eproc.e_xrssize =
200 				  eproc.e_xccount =  eproc.e_xswrss = 0;
201 			}
202 			if (error = copyout((caddr_t)&eproc, &dp->kp_eproc,
203 			    sizeof (eproc)))
204 				return (error);
205 			dp++;
206 			buflen -= sizeof (struct kinfo_proc);
207 		}
208 		needed += sizeof (struct kinfo_proc);
209 	}
210 	if (doingzomb == 0) {
211 		p = zombproc;
212 		doingzomb++;
213 		goto again;
214 	}
215 	if (where != NULL)
216 		*acopysize = (caddr_t)dp - where;
217 	else
218 		needed += KINFO_PROCSLOP;
219 	*aneeded = needed;
220 
221 	return (0);
222 }
223