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