xref: /csrg-svn/sys/kern/kern_sysctl.c (revision 39963)
1*39963Smarc /*
2*39963Smarc  * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
3*39963Smarc  * All rights reserved.
4*39963Smarc  *
5*39963Smarc  * Redistribution and use in source and binary forms are permitted
6*39963Smarc  * provided that the above copyright notice and this paragraph are
7*39963Smarc  * duplicated in all such forms and that any documentation,
8*39963Smarc  * advertising materials, and other materials related to such
9*39963Smarc  * distribution and use acknowledge that the software was developed
10*39963Smarc  * by the University of California, Berkeley.  The name of the
11*39963Smarc  * University may not be used to endorse or promote products derived
12*39963Smarc  * from this software without specific prior written permission.
13*39963Smarc  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14*39963Smarc  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15*39963Smarc  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16*39963Smarc  *
17*39963Smarc  *	@(#)kern_sysctl.c	7.1 (Berkeley) 01/31/90
18*39963Smarc  */
19*39963Smarc 
20*39963Smarc #include "kinfo.h"
21*39963Smarc #include "vm.h"
22*39963Smarc #include "ioctl.h"
23*39963Smarc #include "tty.h"
24*39963Smarc #include "buf.h"
25*39963Smarc 
26*39963Smarc /* TODO - gather stats on average and max time spent */
27*39963Smarc getkinfo()
28*39963Smarc {
29*39963Smarc 	register struct a {
30*39963Smarc 		int	op;
31*39963Smarc 		char	*where;
32*39963Smarc 		int	*size;
33*39963Smarc 		int	arg;
34*39963Smarc 	} *uap = (struct a *)u.u_ap;
35*39963Smarc 	int wanted;
36*39963Smarc 
37*39963Smarc 	switch (ki_type(uap->op)) {
38*39963Smarc 
39*39963Smarc 	case KINFO_PROC:
40*39963Smarc 		u.u_error = kinfo_proc(uap->op, (char *)uap->where,
41*39963Smarc 				       (int *)uap->size, uap->arg, &wanted);
42*39963Smarc 		if (!u.u_error)
43*39963Smarc 			u.u_r.r_val1 = wanted;
44*39963Smarc 		break;
45*39963Smarc 
46*39963Smarc 	default:
47*39963Smarc 		u.u_error = EINVAL;
48*39963Smarc 	}
49*39963Smarc 
50*39963Smarc 	return;
51*39963Smarc }
52*39963Smarc 
53*39963Smarc /*
54*39963Smarc  * try over estimating by 5 procs
55*39963Smarc  */
56*39963Smarc #define KINFO_PROCSLOP	(5 * sizeof (struct kinfo_proc))
57*39963Smarc 
58*39963Smarc int kinfo_proc_userfailed;
59*39963Smarc int kinfo_proc_wefailed;
60*39963Smarc 
61*39963Smarc kinfo_proc(op, where, asize, arg, awanted)
62*39963Smarc 	char *where;
63*39963Smarc 	int *asize, *awanted;
64*39963Smarc {
65*39963Smarc 	int	bufsize,	/* max size of users buffer */
66*39963Smarc 		copysize, 	/* size copied */
67*39963Smarc 		needed;
68*39963Smarc 	int locked;
69*39963Smarc 	int error;
70*39963Smarc 
71*39963Smarc 	if (error = kinfo_doprocs(op, NULL, NULL, arg, &needed))
72*39963Smarc 		return (error);
73*39963Smarc 	if (where == NULL || asize == NULL) {
74*39963Smarc 		*awanted = needed;
75*39963Smarc 		return (0);
76*39963Smarc 	}
77*39963Smarc 	if (error = copyin((caddr_t)asize, (caddr_t)&bufsize, sizeof (bufsize)))
78*39963Smarc 		return (error);
79*39963Smarc 	needed += KINFO_PROCSLOP;
80*39963Smarc 	locked = copysize = MIN(needed, bufsize);
81*39963Smarc 	if (!useracc(where, copysize, B_WRITE))
82*39963Smarc 		return (EFAULT);
83*39963Smarc 	/*
84*39963Smarc 	 * lock down target pages - NEED DEADLOCK AVOIDANCE
85*39963Smarc 	 */
86*39963Smarc 	if (copysize > ((int)ptob(freemem) - (20 * 1024))) 	/* XXX */
87*39963Smarc 		return (ENOMEM);
88*39963Smarc 	vslock(where, copysize);
89*39963Smarc 	error = kinfo_doprocs(op, where, &copysize, arg, &needed);
90*39963Smarc 	vsunlock(where, locked, B_WRITE);
91*39963Smarc 	if (error)
92*39963Smarc 		return (error);
93*39963Smarc 	*awanted = needed;
94*39963Smarc 	if (error = copyout((caddr_t)&copysize, (caddr_t)asize,
95*39963Smarc 	    sizeof (copysize)))
96*39963Smarc 		return (error);
97*39963Smarc 
98*39963Smarc 	return (0);
99*39963Smarc }
100*39963Smarc 
101*39963Smarc kinfo_doprocs(op, where, acopysize, arg, aneeded)
102*39963Smarc 	char *where;
103*39963Smarc 	int *acopysize, *aneeded;
104*39963Smarc {
105*39963Smarc 	register struct proc *p;
106*39963Smarc 	register caddr_t dp = (caddr_t)where;
107*39963Smarc 	register needed = 0;
108*39963Smarc 	int buflen;
109*39963Smarc 	int doingzomb;
110*39963Smarc 	struct {
111*39963Smarc 		struct	proc *paddr;
112*39963Smarc 		struct	session *session;
113*39963Smarc 		pid_t	pgid;
114*39963Smarc 		short	jobc;
115*39963Smarc 		dev_t	ttydev;
116*39963Smarc 		pid_t	ttypgid;
117*39963Smarc 		struct	session *ttysession;
118*39963Smarc 	} extra;
119*39963Smarc 	struct tty *tp;
120*39963Smarc 	int error = 0;
121*39963Smarc 
122*39963Smarc 	if (where != NULL)
123*39963Smarc 		buflen = *acopysize;
124*39963Smarc 
125*39963Smarc 	p = allproc;
126*39963Smarc 	doingzomb = 0;
127*39963Smarc again:
128*39963Smarc 	for (; p != NULL; p = p->p_nxt) {
129*39963Smarc 		/*
130*39963Smarc 		 * TODO - make more efficient (see notes below).
131*39963Smarc 		 * do by session.
132*39963Smarc 		 */
133*39963Smarc 		switch (ki_op(op)) {
134*39963Smarc 
135*39963Smarc 		case KINFO_PROC_PID:
136*39963Smarc 			/* could do this with just a lookup */
137*39963Smarc 			if (p->p_pid != (pid_t)arg)
138*39963Smarc 				continue;
139*39963Smarc 			break;
140*39963Smarc 
141*39963Smarc 		case KINFO_PROC_PGRP:
142*39963Smarc 			/* could do this by traversing pgrp */
143*39963Smarc 			if (p->p_pgrp->pg_id != (pid_t)arg)
144*39963Smarc 				continue;
145*39963Smarc 			break;
146*39963Smarc 
147*39963Smarc 		case KINFO_PROC_TTY:
148*39963Smarc 			if ((p->p_flag&SCTTY) == 0 ||
149*39963Smarc 			    p->p_session->s_ttyp == NULL ||
150*39963Smarc 			    p->p_session->s_ttyp->t_dev != (dev_t)arg)
151*39963Smarc 				continue;
152*39963Smarc 			break;
153*39963Smarc 
154*39963Smarc 		case KINFO_PROC_UID:
155*39963Smarc 			if (p->p_uid != (uid_t)arg)
156*39963Smarc 				continue;
157*39963Smarc 			break;
158*39963Smarc 
159*39963Smarc 		case KINFO_PROC_RUID:
160*39963Smarc 			if (p->p_ruid != (uid_t)arg)
161*39963Smarc 				continue;
162*39963Smarc 			break;
163*39963Smarc 		}
164*39963Smarc 		if (where != NULL && buflen >= sizeof (struct kinfo_proc)) {
165*39963Smarc 			if (error = copyout((caddr_t)p, dp,
166*39963Smarc 			    sizeof (struct proc)))
167*39963Smarc 				return (error);
168*39963Smarc 			dp += sizeof (struct proc);
169*39963Smarc 			extra.paddr = p;
170*39963Smarc 			extra.session = p->p_pgrp->pg_session;
171*39963Smarc 			extra.pgid = p->p_pgrp->pg_id;
172*39963Smarc 			extra.jobc = p->p_pgrp->pg_jobc;
173*39963Smarc 			tp = p->p_pgrp->pg_session->s_ttyp;
174*39963Smarc 			if ((p->p_flag&SCTTY) && tp != NULL) {
175*39963Smarc 				extra.ttydev = tp->t_dev;
176*39963Smarc 				extra.ttypgid = tp->t_pgrp ?
177*39963Smarc 					tp->t_pgrp->pg_id : -1;
178*39963Smarc 				extra.ttysession = tp->t_session;
179*39963Smarc 			} else
180*39963Smarc 				extra.ttydev = NODEV;
181*39963Smarc 			if (error = copyout((caddr_t)&extra, dp,
182*39963Smarc 			    sizeof (extra)))
183*39963Smarc 				return (error);
184*39963Smarc 			dp += sizeof (extra);
185*39963Smarc 			buflen -= sizeof (struct kinfo_proc);
186*39963Smarc 		}
187*39963Smarc 		needed += sizeof (struct kinfo_proc);
188*39963Smarc 	}
189*39963Smarc 	if (doingzomb == 0) {
190*39963Smarc 		p = zombproc;
191*39963Smarc 		doingzomb++;
192*39963Smarc 		goto again;
193*39963Smarc 	}
194*39963Smarc 	if (where != NULL)
195*39963Smarc 		*acopysize = dp - where;
196*39963Smarc 	*aneeded = needed;
197*39963Smarc 
198*39963Smarc 	return (0);
199*39963Smarc }
200