xref: /csrg-svn/sys/kern/kern_sysctl.c (revision 40068)
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.4 (Berkeley) 02/14/90
18  */
19 
20 #include "param.h"
21 #include "user.h"
22 #include "proc.h"
23 #include "kinfo.h"
24 #include "vm.h"
25 #include "ioctl.h"
26 #include "tty.h"
27 #include "buf.h"
28 
29 
30 #define snderr(e) { error = (e); goto release;}
31 extern int kinfo_doproc(), kinfo_rtable();
32 struct kinfo_lock kinfo_lock;
33 
34 getkinfo()
35 {
36 	register struct a {
37 		int	op;
38 		char	*where;
39 		int	*size;
40 		int	arg;
41 	} *uap = (struct a *)u.u_ap;
42 	int wanted, (*server)(), error = 0;
43 	int	bufsize,	/* max size of users buffer */
44 		copysize, 	/* size copied */
45 		needed,
46 		locked;
47 
48 	while (kinfo_lock.kl_lock) {
49 		kinfo_lock.kl_want++;
50 		sleep(&kinfo_lock, PRIBIO+1);
51 		kinfo_lock.kl_want--;
52 		kinfo_lock.kl_locked++;
53 	}
54 	kinfo_lock.kl_lock++;
55 
56 	switch (ki_type(uap->op)) {
57 
58 	case KINFO_PROC:
59 		server = kinfo_doproc;
60 		break;
61 
62 	case KINFO_RT:
63 		server = kinfo_rtable;
64 		break;
65 
66 	default:
67 		snderr(EINVAL);
68 	}
69 	if (error = (*server)(uap->op, NULL, NULL, uap->arg, &needed))
70 		goto release;
71 	if (uap->where == NULL || uap->size == NULL)
72 		goto release;  /* only want estimate of bufsize */
73 	if (error = copyin((caddr_t)uap->size,
74 				(caddr_t)&bufsize, sizeof (bufsize)))
75 		goto release;
76 	locked = copysize = MIN(needed, bufsize);
77 	if (!useracc(uap->where, copysize, B_WRITE))
78 		snderr(EFAULT);
79 	/*
80 	 * lock down target pages - NEED DEADLOCK AVOIDANCE
81 	 */
82 	if (copysize > ((int)ptob(freemem) - (20 * 1024))) 	/* XXX */
83 		snderr(ENOMEM);
84 	vslock(uap->where, copysize);
85 	error = (*server)(uap->op, uap->where, &copysize, uap->arg, &needed);
86 	vsunlock(uap->where, locked, B_WRITE);
87 	if (error)
88 		goto release;
89 	error = copyout((caddr_t)&copysize,
90 				(caddr_t)uap->size, sizeof (copysize));
91 
92 release:
93 	kinfo_lock.kl_lock--;
94 	if (kinfo_lock.kl_want)
95 		wakeup(&kinfo_lock);
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 int kinfo_proc_userfailed;
108 int kinfo_proc_wefailed;
109 
110 kinfo_doprocs(op, where, acopysize, arg, aneeded)
111 	char *where;
112 	int *acopysize, *aneeded;
113 {
114 	register struct proc *p;
115 	register caddr_t dp = (caddr_t)where;
116 	register needed = 0;
117 	int buflen;
118 	int doingzomb;
119 	struct eproc eproc;
120 	struct tty *tp;
121 	int error = 0;
122 
123 	if (where != NULL)
124 		buflen = *acopysize;
125 
126 	p = allproc;
127 	doingzomb = 0;
128 again:
129 	for (; p != NULL; p = p->p_nxt) {
130 		/*
131 		 * TODO - make more efficient (see notes below).
132 		 * do by session.
133 		 */
134 		switch (ki_op(op)) {
135 
136 		case KINFO_PROC_PID:
137 			/* could do this with just a lookup */
138 			if (p->p_pid != (pid_t)arg)
139 				continue;
140 			break;
141 
142 		case KINFO_PROC_PGRP:
143 			/* could do this by traversing pgrp */
144 			if (p->p_pgrp->pg_id != (pid_t)arg)
145 				continue;
146 			break;
147 
148 		case KINFO_PROC_TTY:
149 			if ((p->p_flag&SCTTY) == 0 ||
150 			    p->p_session->s_ttyp == NULL ||
151 			    p->p_session->s_ttyp->t_dev != (dev_t)arg)
152 				continue;
153 			break;
154 
155 		case KINFO_PROC_UID:
156 			if (p->p_uid != (uid_t)arg)
157 				continue;
158 			break;
159 
160 		case KINFO_PROC_RUID:
161 			if (p->p_ruid != (uid_t)arg)
162 				continue;
163 			break;
164 		}
165 		if (where != NULL && buflen >= sizeof (struct kinfo_proc)) {
166 			if (error = copyout((caddr_t)p, dp,
167 			    sizeof (struct proc)))
168 				return (error);
169 			dp += sizeof (struct proc);
170 			eproc.kp_paddr = p;
171 			eproc.kp_sess = p->p_pgrp->pg_session;
172 			eproc.kp_pgid = p->p_pgrp->pg_id;
173 			eproc.kp_jobc = p->p_pgrp->pg_jobc;
174 			tp = p->p_pgrp->pg_session->s_ttyp;
175 			if ((p->p_flag&SCTTY) && tp != NULL) {
176 				eproc.kp_tdev = tp->t_dev;
177 				eproc.kp_tpgid = tp->t_pgrp ?
178 					tp->t_pgrp->pg_id : -1;
179 				eproc.kp_tsess = tp->t_session;
180 			} else
181 				eproc.kp_tdev = NODEV;
182 			if (error = copyout((caddr_t)&eproc, dp,
183 			    sizeof (eproc)))
184 				return (error);
185 			dp += sizeof (eproc);
186 			buflen -= sizeof (struct kinfo_proc);
187 		}
188 		needed += sizeof (struct kinfo_proc);
189 	}
190 	if (doingzomb == 0) {
191 		p = zombproc;
192 		doingzomb++;
193 		goto again;
194 	}
195 	if (where != NULL)
196 		*acopysize = dp - where;
197 	else
198 		needed += KINFO_PROCSLOP;
199 	*aneeded = needed;
200 
201 	return (0);
202 }
203