xref: /csrg-svn/sys/kern/kern_sysctl.c (revision 47545)
139963Smarc /*
239963Smarc  * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
339963Smarc  * All rights reserved.
439963Smarc  *
544435Sbostic  * %sccs.include.redist.c%
639963Smarc  *
7*47545Skarels  *	@(#)kern_sysctl.c	7.13 (Berkeley) 03/17/91
839963Smarc  */
939963Smarc 
1039965Smckusick #include "param.h"
1139965Smckusick #include "user.h"
1239965Smckusick #include "proc.h"
1339963Smarc #include "kinfo.h"
1439963Smarc #include "ioctl.h"
1539963Smarc #include "tty.h"
1639963Smarc #include "buf.h"
1739963Smarc 
1840068Smarc #define snderr(e) { error = (e); goto release;}
1941181Smarc extern int kinfo_doproc(), kinfo_rtable(), kinfo_vnode();
2040068Smarc struct kinfo_lock kinfo_lock;
2140068Smarc 
2243444Smckusick /* ARGSUSED */
2343444Smckusick getkerninfo(p, uap, retval)
2443444Smckusick 	struct proc *p;
2543444Smckusick 	register struct args {
2639963Smarc 		int	op;
2739963Smarc 		char	*where;
2839963Smarc 		int	*size;
2939963Smarc 		int	arg;
3043444Smckusick 	} *uap;
3143444Smckusick 	int *retval;
3243444Smckusick {
3340206Smarc 
34*47545Skarels 	int bufsize;		/* max size of users buffer */
35*47545Skarels 	int needed, locked, (*server)(), error = 0;
3639963Smarc 
37*47545Skarels 	if (error = copyin((caddr_t)uap->size, (caddr_t)&bufsize,
38*47545Skarels 	    sizeof (bufsize)))
3940813Smarc 		goto done;
4040068Smarc 
4139963Smarc 	switch (ki_type(uap->op)) {
4239963Smarc 
4339963Smarc 	case KINFO_PROC:
4440068Smarc 		server = kinfo_doproc;
4539963Smarc 		break;
4639963Smarc 
4740068Smarc 	case KINFO_RT:
4840068Smarc 		server = kinfo_rtable;
4940068Smarc 		break;
5040068Smarc 
5141181Smarc 	case KINFO_VNODE:
5241181Smarc 		server = kinfo_vnode;
5341181Smarc 		break;
5441181Smarc 
5539963Smarc 	default:
5640206Smarc 		error = EINVAL;
5740813Smarc 		goto done;
5839963Smarc 	}
5940813Smarc 	if (uap->where == NULL || uap->size == NULL) {
6040813Smarc 		error = (*server)(uap->op, NULL, NULL, uap->arg, &needed);
6140813Smarc 		goto done;
6240813Smarc 	}
6340206Smarc 	while (kinfo_lock.kl_lock) {
6440206Smarc 		kinfo_lock.kl_want++;
6540206Smarc 		sleep(&kinfo_lock, PRIBIO+1);
6640206Smarc 		kinfo_lock.kl_want--;
6740206Smarc 		kinfo_lock.kl_locked++;
6840206Smarc 	}
6940206Smarc 	kinfo_lock.kl_lock++;
7040206Smarc 
7140813Smarc 	if (!useracc(uap->where, bufsize, B_WRITE))
7240068Smarc 		snderr(EFAULT);
7341181Smarc 	if (server != kinfo_vnode)	/* XXX */
7441181Smarc 		vslock(uap->where, bufsize);
7540813Smarc 	locked = bufsize;
7640813Smarc 	error = (*server)(uap->op, uap->where, &bufsize, uap->arg, &needed);
7741181Smarc 	if (server != kinfo_vnode)	/* XXX */
7841181Smarc 		vsunlock(uap->where, locked, B_WRITE);
7940813Smarc 	if (error == 0)
8040813Smarc 		error = copyout((caddr_t)&bufsize,
8140813Smarc 				(caddr_t)uap->size, sizeof (bufsize));
8240068Smarc release:
8340068Smarc 	kinfo_lock.kl_lock--;
8440068Smarc 	if (kinfo_lock.kl_want)
8540068Smarc 		wakeup(&kinfo_lock);
8640813Smarc done:
8743444Smckusick 	if (!error)
8843444Smckusick 		*retval = needed;
8943444Smckusick 	return (error);
9039963Smarc }
9139963Smarc 
9239963Smarc /*
9339963Smarc  * try over estimating by 5 procs
9439963Smarc  */
9539963Smarc #define KINFO_PROCSLOP	(5 * sizeof (struct kinfo_proc))
9639963Smarc 
9740206Smarc kinfo_doproc(op, where, acopysize, arg, aneeded)
9839963Smarc 	char *where;
9939963Smarc 	int *acopysize, *aneeded;
10039963Smarc {
10139963Smarc 	register struct proc *p;
10243419Smarc 	register struct kinfo_proc *dp = (struct kinfo_proc *)where;
10339963Smarc 	register needed = 0;
10439963Smarc 	int buflen;
10539963Smarc 	int doingzomb;
10640067Smarc 	struct eproc eproc;
10739963Smarc 	int error = 0;
10839963Smarc 
10939963Smarc 	if (where != NULL)
11039963Smarc 		buflen = *acopysize;
11139963Smarc 
11239963Smarc 	p = allproc;
11339963Smarc 	doingzomb = 0;
11439963Smarc again:
11539963Smarc 	for (; p != NULL; p = p->p_nxt) {
11639963Smarc 		/*
11739963Smarc 		 * TODO - make more efficient (see notes below).
11839963Smarc 		 * do by session.
11939963Smarc 		 */
12039963Smarc 		switch (ki_op(op)) {
12139963Smarc 
12239963Smarc 		case KINFO_PROC_PID:
12339963Smarc 			/* could do this with just a lookup */
12439963Smarc 			if (p->p_pid != (pid_t)arg)
12539963Smarc 				continue;
12639963Smarc 			break;
12739963Smarc 
12839963Smarc 		case KINFO_PROC_PGRP:
12939963Smarc 			/* could do this by traversing pgrp */
13039963Smarc 			if (p->p_pgrp->pg_id != (pid_t)arg)
13139963Smarc 				continue;
13239963Smarc 			break;
13339963Smarc 
13439963Smarc 		case KINFO_PROC_TTY:
13539963Smarc 			if ((p->p_flag&SCTTY) == 0 ||
13639963Smarc 			    p->p_session->s_ttyp == NULL ||
13739963Smarc 			    p->p_session->s_ttyp->t_dev != (dev_t)arg)
13839963Smarc 				continue;
13939963Smarc 			break;
14039963Smarc 
14139963Smarc 		case KINFO_PROC_UID:
142*47545Skarels 			if (p->p_ucred->cr_uid != (uid_t)arg)
14339963Smarc 				continue;
14439963Smarc 			break;
14539963Smarc 
14639963Smarc 		case KINFO_PROC_RUID:
147*47545Skarels 			if (p->p_cred->p_ruid != (uid_t)arg)
14839963Smarc 				continue;
14939963Smarc 			break;
15039963Smarc 		}
15139963Smarc 		if (where != NULL && buflen >= sizeof (struct kinfo_proc)) {
15243419Smarc 			register struct tty *tp;
15340206Smarc 
15443419Smarc 			if (error = copyout((caddr_t)p, &dp->kp_proc,
15539963Smarc 			    sizeof (struct proc)))
15639963Smarc 				return (error);
15740206Smarc 			eproc.e_paddr = p;
15840206Smarc 			eproc.e_sess = p->p_pgrp->pg_session;
159*47545Skarels 			eproc.e_pcred = *p->p_cred;
160*47545Skarels 			eproc.e_ucred = *p->p_ucred;
161*47545Skarels 			eproc.e_vm = *p->p_vmspace;
16240206Smarc 			eproc.e_pgid = p->p_pgrp->pg_id;
16340206Smarc 			eproc.e_jobc = p->p_pgrp->pg_jobc;
16443419Smarc 			if ((p->p_flag&SCTTY) &&
16543419Smarc 			     (tp = eproc.e_sess->s_ttyp)) {
16640206Smarc 				eproc.e_tdev = tp->t_dev;
16740206Smarc 				eproc.e_tpgid = tp->t_pgrp ?
16839963Smarc 					tp->t_pgrp->pg_id : -1;
16940206Smarc 				eproc.e_tsess = tp->t_session;
17039963Smarc 			} else
17140206Smarc 				eproc.e_tdev = NODEV;
17243419Smarc 			eproc.e_flag = eproc.e_sess->s_ttyvp ? EPROC_CTTY : 0;
17343419Smarc 			if (SESS_LEADER(p))
17443419Smarc 				eproc.e_flag |= EPROC_SLEADER;
17540206Smarc 			if (p->p_wmesg)
17640206Smarc 				strncpy(eproc.e_wmesg, p->p_wmesg, WMESGLEN);
17745728Smckusick 			eproc.e_xsize = eproc.e_xrssize = 0;
17845728Smckusick 			eproc.e_xccount =  eproc.e_xswrss = 0;
17943419Smarc 			if (error = copyout((caddr_t)&eproc, &dp->kp_eproc,
18040067Smarc 			    sizeof (eproc)))
18139963Smarc 				return (error);
18243419Smarc 			dp++;
18339963Smarc 			buflen -= sizeof (struct kinfo_proc);
18439963Smarc 		}
18539963Smarc 		needed += sizeof (struct kinfo_proc);
18639963Smarc 	}
18739963Smarc 	if (doingzomb == 0) {
18839963Smarc 		p = zombproc;
18939963Smarc 		doingzomb++;
19039963Smarc 		goto again;
19139963Smarc 	}
19239963Smarc 	if (where != NULL)
19343419Smarc 		*acopysize = (caddr_t)dp - where;
19440068Smarc 	else
19540068Smarc 		needed += KINFO_PROCSLOP;
19639963Smarc 	*aneeded = needed;
19739963Smarc 
19839963Smarc 	return (0);
19939963Smarc }
200