xref: /original-bsd/sys/kern/kern_sysctl.c (revision de3f5c4e)
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.15 (Berkeley) 05/05/91
8  */
9 
10 #include "param.h"
11 #include "proc.h"
12 #include "kinfo.h"
13 #include "ioctl.h"
14 #include "tty.h"
15 #include "buf.h"
16 
17 #include "vm/vm.h"
18 
19 #include "kinfo_proc.h"
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 	int needed, locked, (*server)(), error = 0;
39 
40 	if (error = copyin((caddr_t)uap->size, (caddr_t)&bufsize,
41 	    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 	if (server != kinfo_vnode)	/* XXX */
77 		vslock(uap->where, bufsize);
78 	locked = bufsize;
79 	error = (*server)(uap->op, uap->where, &bufsize, uap->arg, &needed);
80 	if (server != kinfo_vnode)	/* XXX */
81 		vsunlock(uap->where, locked, B_WRITE);
82 	if (error == 0)
83 		error = copyout((caddr_t)&bufsize,
84 				(caddr_t)uap->size, sizeof (bufsize));
85 release:
86 	kinfo_lock.kl_lock--;
87 	if (kinfo_lock.kl_want)
88 		wakeup(&kinfo_lock);
89 done:
90 	if (!error)
91 		*retval = needed;
92 	return (error);
93 }
94 
95 /*
96  * try over estimating by 5 procs
97  */
98 #define KINFO_PROCSLOP	(5 * sizeof (struct kinfo_proc))
99 
100 kinfo_doproc(op, where, acopysize, arg, aneeded)
101 	char *where;
102 	int *acopysize, *aneeded;
103 {
104 	register struct proc *p;
105 	register struct kinfo_proc *dp = (struct kinfo_proc *)where;
106 	register needed = 0;
107 	int buflen;
108 	int doingzomb;
109 	struct eproc eproc;
110 	int error = 0;
111 
112 	if (where != NULL)
113 		buflen = *acopysize;
114 
115 	p = allproc;
116 	doingzomb = 0;
117 again:
118 	for (; p != NULL; p = p->p_nxt) {
119 		/*
120 		 * TODO - make more efficient (see notes below).
121 		 * do by session.
122 		 */
123 		switch (ki_op(op)) {
124 
125 		case KINFO_PROC_PID:
126 			/* could do this with just a lookup */
127 			if (p->p_pid != (pid_t)arg)
128 				continue;
129 			break;
130 
131 		case KINFO_PROC_PGRP:
132 			/* could do this by traversing pgrp */
133 			if (p->p_pgrp->pg_id != (pid_t)arg)
134 				continue;
135 			break;
136 
137 		case KINFO_PROC_TTY:
138 			if ((p->p_flag&SCTTY) == 0 ||
139 			    p->p_session->s_ttyp == NULL ||
140 			    p->p_session->s_ttyp->t_dev != (dev_t)arg)
141 				continue;
142 			break;
143 
144 		case KINFO_PROC_UID:
145 			if (p->p_ucred->cr_uid != (uid_t)arg)
146 				continue;
147 			break;
148 
149 		case KINFO_PROC_RUID:
150 			if (p->p_cred->p_ruid != (uid_t)arg)
151 				continue;
152 			break;
153 		}
154 		if (where != NULL && buflen >= sizeof (struct kinfo_proc)) {
155 			fill_eproc(p, &eproc);
156 			if (error = copyout((caddr_t)p, &dp->kp_proc,
157 			    sizeof (struct proc)))
158 				return (error);
159 			if (error = copyout((caddr_t)&eproc, &dp->kp_eproc,
160 			    sizeof (eproc)))
161 				return (error);
162 			dp++;
163 			buflen -= sizeof (struct kinfo_proc);
164 		}
165 		needed += sizeof (struct kinfo_proc);
166 	}
167 	if (doingzomb == 0) {
168 		p = zombproc;
169 		doingzomb++;
170 		goto again;
171 	}
172 	if (where != NULL)
173 		*acopysize = (caddr_t)dp - where;
174 	else
175 		needed += KINFO_PROCSLOP;
176 	*aneeded = needed;
177 
178 	return (0);
179 }
180 
181 /*
182  * Fill in an eproc structure for the specified process.
183  */
184 void
185 fill_eproc(p, ep)
186 	register struct proc *p;
187 	register struct eproc *ep;
188 {
189 	register struct tty *tp;
190 
191 	ep->e_paddr = p;
192 	ep->e_sess = p->p_pgrp->pg_session;
193 	ep->e_pcred = *p->p_cred;
194 	ep->e_ucred = *p->p_ucred;
195 	ep->e_vm = *p->p_vmspace;
196 	if (p->p_pptr)
197 		ep->e_ppid = p->p_pptr->p_pid;
198 	else
199 		ep->e_ppid = 0;
200 	ep->e_pgid = p->p_pgrp->pg_id;
201 	ep->e_jobc = p->p_pgrp->pg_jobc;
202 	if ((p->p_flag&SCTTY) &&
203 	     (tp = ep->e_sess->s_ttyp)) {
204 		ep->e_tdev = tp->t_dev;
205 		ep->e_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : -1;
206 		ep->e_tsess = tp->t_session;
207 	} else
208 		ep->e_tdev = NODEV;
209 	ep->e_flag = ep->e_sess->s_ttyvp ? EPROC_CTTY : 0;
210 	if (SESS_LEADER(p))
211 		ep->e_flag |= EPROC_SLEADER;
212 	if (p->p_wmesg)
213 		strncpy(ep->e_wmesg, p->p_wmesg, WMESGLEN);
214 	ep->e_xsize = ep->e_xrssize = 0;
215 	ep->e_xccount = ep->e_xswrss = 0;
216 }
217