xref: /original-bsd/sys/kern/kern_sysctl.c (revision c74f8e57)
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.7 (Berkeley) 04/10/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 		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 	default:
62 		error = EINVAL;
63 		goto done;
64 	}
65 	if (uap->where == NULL || uap->size == NULL) {
66 		error = (*server)(uap->op, NULL, NULL, uap->arg, &needed);
67 		goto done;
68 	}
69 	while (kinfo_lock.kl_lock) {
70 		kinfo_lock.kl_want++;
71 		sleep(&kinfo_lock, PRIBIO+1);
72 		kinfo_lock.kl_want--;
73 		kinfo_lock.kl_locked++;
74 	}
75 	kinfo_lock.kl_lock++;
76 
77 	if (!useracc(uap->where, bufsize, B_WRITE))
78 		snderr(EFAULT);
79 	/*
80 	 * lock down target pages - NEED DEADLOCK AVOIDANCE
81 	 */
82 	if (bufsize > ((int)ptob(freemem) - (20 * 1024))) 	/* XXX */
83 		snderr(ENOMEM);
84 	vslock(uap->where, bufsize);
85 	locked = bufsize;
86 	error = (*server)(uap->op, uap->where, &bufsize, uap->arg, &needed);
87 	vsunlock(uap->where, locked, B_WRITE);
88 	if (error == 0)
89 		error = copyout((caddr_t)&bufsize,
90 				(caddr_t)uap->size, sizeof (bufsize));
91 release:
92 	kinfo_lock.kl_lock--;
93 	if (kinfo_lock.kl_want)
94 		wakeup(&kinfo_lock);
95 done:
96 	if (error)
97 		u.u_error = error;
98 	else
99 		u.u_r.r_val1 = needed;
100 }
101 
102 /*
103  * try over estimating by 5 procs
104  */
105 #define KINFO_PROCSLOP	(5 * sizeof (struct kinfo_proc))
106 
107 kinfo_doproc(op, where, acopysize, arg, aneeded)
108 	char *where;
109 	int *acopysize, *aneeded;
110 {
111 	register struct proc *p;
112 	register caddr_t dp = (caddr_t)where;
113 	register needed = 0;
114 	int buflen;
115 	int doingzomb;
116 	struct eproc eproc;
117 	struct tty *tp;
118 	int error = 0;
119 
120 	if (where != NULL)
121 		buflen = *acopysize;
122 
123 	p = allproc;
124 	doingzomb = 0;
125 again:
126 	for (; p != NULL; p = p->p_nxt) {
127 		/*
128 		 * TODO - make more efficient (see notes below).
129 		 * do by session.
130 		 */
131 		switch (ki_op(op)) {
132 
133 		case KINFO_PROC_PID:
134 			/* could do this with just a lookup */
135 			if (p->p_pid != (pid_t)arg)
136 				continue;
137 			break;
138 
139 		case KINFO_PROC_PGRP:
140 			/* could do this by traversing pgrp */
141 			if (p->p_pgrp->pg_id != (pid_t)arg)
142 				continue;
143 			break;
144 
145 		case KINFO_PROC_TTY:
146 			if ((p->p_flag&SCTTY) == 0 ||
147 			    p->p_session->s_ttyp == NULL ||
148 			    p->p_session->s_ttyp->t_dev != (dev_t)arg)
149 				continue;
150 			break;
151 
152 		case KINFO_PROC_UID:
153 			if (p->p_uid != (uid_t)arg)
154 				continue;
155 			break;
156 
157 		case KINFO_PROC_RUID:
158 			if (p->p_ruid != (uid_t)arg)
159 				continue;
160 			break;
161 		}
162 		if (where != NULL && buflen >= sizeof (struct kinfo_proc)) {
163 			register struct text *txt;
164 
165 			if (error = copyout((caddr_t)p, dp,
166 			    sizeof (struct proc)))
167 				return (error);
168 			dp += sizeof (struct proc);
169 			/*
170 			 *	XXX NEED ALLIGNMENT
171 			 */
172 			eproc.e_paddr = p;
173 			eproc.e_sess = p->p_pgrp->pg_session;
174 			eproc.e_pgid = p->p_pgrp->pg_id;
175 			eproc.e_jobc = p->p_pgrp->pg_jobc;
176 			if (tp = p->p_pgrp->pg_session->s_ttyp) {
177 				/* up to caller to check for SCTTY */
178 				eproc.e_tdev = tp->t_dev;
179 				eproc.e_tpgid = tp->t_pgrp ?
180 					tp->t_pgrp->pg_id : -1;
181 				eproc.e_tsess = tp->t_session;
182 			} else
183 				eproc.e_tdev = NODEV;
184 			if (p->p_wmesg)
185 				strncpy(eproc.e_wmesg, p->p_wmesg, WMESGLEN);
186 			if (txt = p->p_textp) {
187 				eproc.e_xsize = txt->x_size;
188 				eproc.e_xrssize = txt->x_rssize;
189 				eproc.e_xccount = txt->x_ccount;
190 				eproc.e_xswrss = txt->x_swrss;
191 			} else {
192 				eproc.e_xsize = eproc.e_xrssize =
193 				  eproc.e_xccount =  eproc.e_xswrss = 0;
194 			}
195 			if (error = copyout((caddr_t)&eproc, dp,
196 			    sizeof (eproc)))
197 				return (error);
198 			dp += sizeof (eproc);
199 			buflen -= sizeof (struct kinfo_proc);
200 		}
201 		needed += sizeof (struct kinfo_proc);
202 	}
203 	if (doingzomb == 0) {
204 		p = zombproc;
205 		doingzomb++;
206 		goto again;
207 	}
208 	if (where != NULL)
209 		*acopysize = dp - where;
210 	else
211 		needed += KINFO_PROCSLOP;
212 	*aneeded = needed;
213 
214 	return (0);
215 }
216