xref: /original-bsd/sys/kern/kern_sysctl.c (revision baf24c0d)
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.12 (Berkeley) 12/05/90
8  */
9 
10 #include "param.h"
11 #include "user.h"
12 #include "proc.h"
13 #include "kinfo.h"
14 #include "ioctl.h"
15 #include "tty.h"
16 #include "buf.h"
17 
18 #define snderr(e) { error = (e); goto release;}
19 extern int kinfo_doproc(), kinfo_rtable(), kinfo_vnode();
20 struct kinfo_lock kinfo_lock;
21 
22 /* ARGSUSED */
23 getkerninfo(p, uap, retval)
24 	struct proc *p;
25 	register struct args {
26 		int	op;
27 		char	*where;
28 		int	*size;
29 		int	arg;
30 	} *uap;
31 	int *retval;
32 {
33 
34 	int	bufsize,	/* max size of users buffer */
35 		needed,	locked, (*server)(), error = 0;
36 
37 	if (error = copyin((caddr_t)uap->size,
38 				(caddr_t)&bufsize, sizeof (bufsize)))
39 		goto done;
40 
41 	switch (ki_type(uap->op)) {
42 
43 	case KINFO_PROC:
44 		server = kinfo_doproc;
45 		break;
46 
47 	case KINFO_RT:
48 		server = kinfo_rtable;
49 		break;
50 
51 	case KINFO_VNODE:
52 		server = kinfo_vnode;
53 		break;
54 
55 	default:
56 		error = EINVAL;
57 		goto done;
58 	}
59 	if (uap->where == NULL || uap->size == NULL) {
60 		error = (*server)(uap->op, NULL, NULL, uap->arg, &needed);
61 		goto done;
62 	}
63 	while (kinfo_lock.kl_lock) {
64 		kinfo_lock.kl_want++;
65 		sleep(&kinfo_lock, PRIBIO+1);
66 		kinfo_lock.kl_want--;
67 		kinfo_lock.kl_locked++;
68 	}
69 	kinfo_lock.kl_lock++;
70 
71 	if (!useracc(uap->where, bufsize, B_WRITE))
72 		snderr(EFAULT);
73 	if (server != kinfo_vnode)	/* XXX */
74 		vslock(uap->where, bufsize);
75 	locked = bufsize;
76 	error = (*server)(uap->op, uap->where, &bufsize, uap->arg, &needed);
77 	if (server != kinfo_vnode)	/* XXX */
78 		vsunlock(uap->where, locked, B_WRITE);
79 	if (error == 0)
80 		error = copyout((caddr_t)&bufsize,
81 				(caddr_t)uap->size, sizeof (bufsize));
82 release:
83 	kinfo_lock.kl_lock--;
84 	if (kinfo_lock.kl_want)
85 		wakeup(&kinfo_lock);
86 done:
87 	if (!error)
88 		*retval = needed;
89 	return (error);
90 }
91 
92 /*
93  * try over estimating by 5 procs
94  */
95 #define KINFO_PROCSLOP	(5 * sizeof (struct kinfo_proc))
96 
97 kinfo_doproc(op, where, acopysize, arg, aneeded)
98 	char *where;
99 	int *acopysize, *aneeded;
100 {
101 	register struct proc *p;
102 	register struct kinfo_proc *dp = (struct kinfo_proc *)where;
103 	register needed = 0;
104 	int buflen;
105 	int doingzomb;
106 	struct eproc eproc;
107 	int error = 0;
108 
109 	if (where != NULL)
110 		buflen = *acopysize;
111 
112 	p = allproc;
113 	doingzomb = 0;
114 again:
115 	for (; p != NULL; p = p->p_nxt) {
116 		/*
117 		 * TODO - make more efficient (see notes below).
118 		 * do by session.
119 		 */
120 		switch (ki_op(op)) {
121 
122 		case KINFO_PROC_PID:
123 			/* could do this with just a lookup */
124 			if (p->p_pid != (pid_t)arg)
125 				continue;
126 			break;
127 
128 		case KINFO_PROC_PGRP:
129 			/* could do this by traversing pgrp */
130 			if (p->p_pgrp->pg_id != (pid_t)arg)
131 				continue;
132 			break;
133 
134 		case KINFO_PROC_TTY:
135 			if ((p->p_flag&SCTTY) == 0 ||
136 			    p->p_session->s_ttyp == NULL ||
137 			    p->p_session->s_ttyp->t_dev != (dev_t)arg)
138 				continue;
139 			break;
140 
141 		case KINFO_PROC_UID:
142 			if (p->p_uid != (uid_t)arg)
143 				continue;
144 			break;
145 
146 		case KINFO_PROC_RUID:
147 			if (p->p_ruid != (uid_t)arg)
148 				continue;
149 			break;
150 		}
151 		if (where != NULL && buflen >= sizeof (struct kinfo_proc)) {
152 			register struct tty *tp;
153 
154 			if (error = copyout((caddr_t)p, &dp->kp_proc,
155 			    sizeof (struct proc)))
156 				return (error);
157 			eproc.e_paddr = p;
158 			eproc.e_sess = p->p_pgrp->pg_session;
159 			eproc.e_pgid = p->p_pgrp->pg_id;
160 			eproc.e_jobc = p->p_pgrp->pg_jobc;
161 			if ((p->p_flag&SCTTY) &&
162 			     (tp = eproc.e_sess->s_ttyp)) {
163 				eproc.e_tdev = tp->t_dev;
164 				eproc.e_tpgid = tp->t_pgrp ?
165 					tp->t_pgrp->pg_id : -1;
166 				eproc.e_tsess = tp->t_session;
167 			} else
168 				eproc.e_tdev = NODEV;
169 			eproc.e_flag = eproc.e_sess->s_ttyvp ? EPROC_CTTY : 0;
170 			if (SESS_LEADER(p))
171 				eproc.e_flag |= EPROC_SLEADER;
172 			if (p->p_wmesg)
173 				strncpy(eproc.e_wmesg, p->p_wmesg, WMESGLEN);
174 			eproc.e_xsize = eproc.e_xrssize = 0;
175 			eproc.e_xccount =  eproc.e_xswrss = 0;
176 			if (error = copyout((caddr_t)&eproc, &dp->kp_eproc,
177 			    sizeof (eproc)))
178 				return (error);
179 			dp++;
180 			buflen -= sizeof (struct kinfo_proc);
181 		}
182 		needed += sizeof (struct kinfo_proc);
183 	}
184 	if (doingzomb == 0) {
185 		p = zombproc;
186 		doingzomb++;
187 		goto again;
188 	}
189 	if (where != NULL)
190 		*acopysize = (caddr_t)dp - where;
191 	else
192 		needed += KINFO_PROCSLOP;
193 	*aneeded = needed;
194 
195 	return (0);
196 }
197