xref: /csrg-svn/sys/kern/kern_sysctl.c (revision 44435)
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.11 (Berkeley) 06/28/90
8  */
9 
10 #include "param.h"
11 #include "user.h"
12 #include "proc.h"
13 #include "text.h"
14 #include "kinfo.h"
15 #include "vm.h"
16 #include "ioctl.h"
17 #include "tty.h"
18 #include "buf.h"
19 
20 
21 #define snderr(e) { error = (e); goto release;}
22 extern int kinfo_doproc(), kinfo_rtable(), kinfo_vnode();
23 struct kinfo_lock kinfo_lock;
24 
25 /* ARGSUSED */
26 getkerninfo(p, uap, retval)
27 	struct proc *p;
28 	register struct args {
29 		int	op;
30 		char	*where;
31 		int	*size;
32 		int	arg;
33 	} *uap;
34 	int *retval;
35 {
36 
37 	int	bufsize,	/* max size of users buffer */
38 		needed,	locked, (*server)(), error = 0;
39 
40 	if (error = copyin((caddr_t)uap->size,
41 				(caddr_t)&bufsize, sizeof (bufsize)))
42 		goto done;
43 
44 	switch (ki_type(uap->op)) {
45 
46 	case KINFO_PROC:
47 		server = kinfo_doproc;
48 		break;
49 
50 	case KINFO_RT:
51 		server = kinfo_rtable;
52 		break;
53 
54 	case KINFO_VNODE:
55 		server = kinfo_vnode;
56 		break;
57 
58 	default:
59 		error = EINVAL;
60 		goto done;
61 	}
62 	if (uap->where == NULL || uap->size == NULL) {
63 		error = (*server)(uap->op, NULL, NULL, uap->arg, &needed);
64 		goto done;
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 (!useracc(uap->where, bufsize, B_WRITE))
75 		snderr(EFAULT);
76 	/*
77 	 * lock down target pages - NEED DEADLOCK AVOIDANCE
78 	 */
79 	if (bufsize > ((int)ptob(freemem) - (20 * 1024))) 	/* XXX */
80 		snderr(ENOMEM);
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_uid != (uid_t)arg)
151 				continue;
152 			break;
153 
154 		case KINFO_PROC_RUID:
155 			if (p->p_ruid != (uid_t)arg)
156 				continue;
157 			break;
158 		}
159 		if (where != NULL && buflen >= sizeof (struct kinfo_proc)) {
160 			register struct text *txt;
161 			register struct tty *tp;
162 
163 			if (error = copyout((caddr_t)p, &dp->kp_proc,
164 			    sizeof (struct proc)))
165 				return (error);
166 			eproc.e_paddr = p;
167 			eproc.e_sess = p->p_pgrp->pg_session;
168 			eproc.e_pgid = p->p_pgrp->pg_id;
169 			eproc.e_jobc = p->p_pgrp->pg_jobc;
170 			if ((p->p_flag&SCTTY) &&
171 			     (tp = eproc.e_sess->s_ttyp)) {
172 				eproc.e_tdev = tp->t_dev;
173 				eproc.e_tpgid = tp->t_pgrp ?
174 					tp->t_pgrp->pg_id : -1;
175 				eproc.e_tsess = tp->t_session;
176 			} else
177 				eproc.e_tdev = NODEV;
178 			eproc.e_flag = eproc.e_sess->s_ttyvp ? EPROC_CTTY : 0;
179 			if (SESS_LEADER(p))
180 				eproc.e_flag |= EPROC_SLEADER;
181 			if (p->p_wmesg)
182 				strncpy(eproc.e_wmesg, p->p_wmesg, WMESGLEN);
183 			if (txt = p->p_textp) {
184 				eproc.e_xsize = txt->x_size;
185 				eproc.e_xrssize = txt->x_rssize;
186 				eproc.e_xccount = txt->x_ccount;
187 				eproc.e_xswrss = txt->x_swrss;
188 			} else {
189 				eproc.e_xsize = eproc.e_xrssize =
190 				  eproc.e_xccount =  eproc.e_xswrss = 0;
191 			}
192 			if (error = copyout((caddr_t)&eproc, &dp->kp_eproc,
193 			    sizeof (eproc)))
194 				return (error);
195 			dp++;
196 			buflen -= sizeof (struct kinfo_proc);
197 		}
198 		needed += sizeof (struct kinfo_proc);
199 	}
200 	if (doingzomb == 0) {
201 		p = zombproc;
202 		doingzomb++;
203 		goto again;
204 	}
205 	if (where != NULL)
206 		*acopysize = (caddr_t)dp - where;
207 	else
208 		needed += KINFO_PROCSLOP;
209 	*aneeded = needed;
210 
211 	return (0);
212 }
213