xref: /csrg-svn/sys/kern/kern_sysctl.c (revision 50909)
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*50909Smckusick  *	@(#)kern_sysctl.c	7.18 (Berkeley) 08/28/91
839963Smarc  */
939963Smarc 
1039965Smckusick #include "param.h"
1139965Smckusick #include "proc.h"
1239963Smarc #include "kinfo.h"
1339963Smarc #include "ioctl.h"
1439963Smarc #include "tty.h"
1539963Smarc #include "buf.h"
1650149Smarc #include "file.h"
1739963Smarc 
1848407Skarels #include "vm/vm.h"
1948407Skarels 
2048407Skarels #include "kinfo_proc.h"
2148407Skarels 
2240068Smarc #define snderr(e) { error = (e); goto release;}
2350149Smarc extern int kinfo_doproc(), kinfo_rtable(), kinfo_vnode(), kinfo_file();
24*50909Smckusick extern int kinfo_meter();
2540068Smarc struct kinfo_lock kinfo_lock;
2640068Smarc 
2743444Smckusick /* ARGSUSED */
2843444Smckusick getkerninfo(p, uap, retval)
2943444Smckusick 	struct proc *p;
3043444Smckusick 	register struct args {
3139963Smarc 		int	op;
3239963Smarc 		char	*where;
3339963Smarc 		int	*size;
3439963Smarc 		int	arg;
3543444Smckusick 	} *uap;
3643444Smckusick 	int *retval;
3743444Smckusick {
3840206Smarc 
3947545Skarels 	int bufsize;		/* max size of users buffer */
4047545Skarels 	int needed, locked, (*server)(), error = 0;
4139963Smarc 
4247545Skarels 	if (error = copyin((caddr_t)uap->size, (caddr_t)&bufsize,
4347545Skarels 	    sizeof (bufsize)))
4440813Smarc 		goto done;
4540068Smarc 
4639963Smarc 	switch (ki_type(uap->op)) {
4739963Smarc 
4839963Smarc 	case KINFO_PROC:
4940068Smarc 		server = kinfo_doproc;
5039963Smarc 		break;
5139963Smarc 
5240068Smarc 	case KINFO_RT:
5340068Smarc 		server = kinfo_rtable;
5440068Smarc 		break;
5540068Smarc 
5641181Smarc 	case KINFO_VNODE:
5741181Smarc 		server = kinfo_vnode;
5841181Smarc 		break;
5941181Smarc 
6050149Smarc 	case KINFO_FILE:
6150149Smarc 		server = kinfo_file;
6250149Smarc 		break;
6350149Smarc 
64*50909Smckusick 	case KINFO_METER:
65*50909Smckusick 		server = kinfo_meter;
66*50909Smckusick 		break;
67*50909Smckusick 
6839963Smarc 	default:
6940206Smarc 		error = EINVAL;
7040813Smarc 		goto done;
7139963Smarc 	}
7240813Smarc 	if (uap->where == NULL || uap->size == NULL) {
7340813Smarc 		error = (*server)(uap->op, NULL, NULL, uap->arg, &needed);
7440813Smarc 		goto done;
7540813Smarc 	}
7640206Smarc 	while (kinfo_lock.kl_lock) {
7740206Smarc 		kinfo_lock.kl_want++;
7840206Smarc 		sleep(&kinfo_lock, PRIBIO+1);
7940206Smarc 		kinfo_lock.kl_want--;
8040206Smarc 		kinfo_lock.kl_locked++;
8140206Smarc 	}
8240206Smarc 	kinfo_lock.kl_lock++;
8340206Smarc 
8440813Smarc 	if (!useracc(uap->where, bufsize, B_WRITE))
8540068Smarc 		snderr(EFAULT);
8641181Smarc 	if (server != kinfo_vnode)	/* XXX */
8741181Smarc 		vslock(uap->where, bufsize);
8840813Smarc 	locked = bufsize;
8940813Smarc 	error = (*server)(uap->op, uap->where, &bufsize, uap->arg, &needed);
9041181Smarc 	if (server != kinfo_vnode)	/* XXX */
9141181Smarc 		vsunlock(uap->where, locked, B_WRITE);
9240813Smarc 	if (error == 0)
9340813Smarc 		error = copyout((caddr_t)&bufsize,
9440813Smarc 				(caddr_t)uap->size, sizeof (bufsize));
9540068Smarc release:
9640068Smarc 	kinfo_lock.kl_lock--;
9740068Smarc 	if (kinfo_lock.kl_want)
9840068Smarc 		wakeup(&kinfo_lock);
9940813Smarc done:
10043444Smckusick 	if (!error)
10143444Smckusick 		*retval = needed;
10243444Smckusick 	return (error);
10339963Smarc }
10439963Smarc 
10539963Smarc /*
10639963Smarc  * try over estimating by 5 procs
10739963Smarc  */
10839963Smarc #define KINFO_PROCSLOP	(5 * sizeof (struct kinfo_proc))
10939963Smarc 
11040206Smarc kinfo_doproc(op, where, acopysize, arg, aneeded)
11139963Smarc 	char *where;
11239963Smarc 	int *acopysize, *aneeded;
11339963Smarc {
11439963Smarc 	register struct proc *p;
11543419Smarc 	register struct kinfo_proc *dp = (struct kinfo_proc *)where;
11639963Smarc 	register needed = 0;
11739963Smarc 	int buflen;
11839963Smarc 	int doingzomb;
11940067Smarc 	struct eproc eproc;
12039963Smarc 	int error = 0;
12139963Smarc 
12239963Smarc 	if (where != NULL)
12339963Smarc 		buflen = *acopysize;
12439963Smarc 
12539963Smarc 	p = allproc;
12639963Smarc 	doingzomb = 0;
12739963Smarc again:
12839963Smarc 	for (; p != NULL; p = p->p_nxt) {
12939963Smarc 		/*
13039963Smarc 		 * TODO - make more efficient (see notes below).
13139963Smarc 		 * do by session.
13239963Smarc 		 */
13339963Smarc 		switch (ki_op(op)) {
13439963Smarc 
13539963Smarc 		case KINFO_PROC_PID:
13639963Smarc 			/* could do this with just a lookup */
13739963Smarc 			if (p->p_pid != (pid_t)arg)
13839963Smarc 				continue;
13939963Smarc 			break;
14039963Smarc 
14139963Smarc 		case KINFO_PROC_PGRP:
14239963Smarc 			/* could do this by traversing pgrp */
14339963Smarc 			if (p->p_pgrp->pg_id != (pid_t)arg)
14439963Smarc 				continue;
14539963Smarc 			break;
14639963Smarc 
14739963Smarc 		case KINFO_PROC_TTY:
14839963Smarc 			if ((p->p_flag&SCTTY) == 0 ||
14939963Smarc 			    p->p_session->s_ttyp == NULL ||
15039963Smarc 			    p->p_session->s_ttyp->t_dev != (dev_t)arg)
15139963Smarc 				continue;
15239963Smarc 			break;
15339963Smarc 
15439963Smarc 		case KINFO_PROC_UID:
15547545Skarels 			if (p->p_ucred->cr_uid != (uid_t)arg)
15639963Smarc 				continue;
15739963Smarc 			break;
15839963Smarc 
15939963Smarc 		case KINFO_PROC_RUID:
16047545Skarels 			if (p->p_cred->p_ruid != (uid_t)arg)
16139963Smarc 				continue;
16239963Smarc 			break;
16339963Smarc 		}
16439963Smarc 		if (where != NULL && buflen >= sizeof (struct kinfo_proc)) {
16548407Skarels 			fill_eproc(p, &eproc);
16643419Smarc 			if (error = copyout((caddr_t)p, &dp->kp_proc,
16739963Smarc 			    sizeof (struct proc)))
16839963Smarc 				return (error);
16943419Smarc 			if (error = copyout((caddr_t)&eproc, &dp->kp_eproc,
17040067Smarc 			    sizeof (eproc)))
17139963Smarc 				return (error);
17243419Smarc 			dp++;
17339963Smarc 			buflen -= sizeof (struct kinfo_proc);
17439963Smarc 		}
17539963Smarc 		needed += sizeof (struct kinfo_proc);
17639963Smarc 	}
17739963Smarc 	if (doingzomb == 0) {
17839963Smarc 		p = zombproc;
17939963Smarc 		doingzomb++;
18039963Smarc 		goto again;
18139963Smarc 	}
18239963Smarc 	if (where != NULL)
18343419Smarc 		*acopysize = (caddr_t)dp - where;
18440068Smarc 	else
18540068Smarc 		needed += KINFO_PROCSLOP;
18639963Smarc 	*aneeded = needed;
18739963Smarc 
18839963Smarc 	return (0);
18939963Smarc }
19048407Skarels 
19148407Skarels /*
19248407Skarels  * Fill in an eproc structure for the specified process.
19348407Skarels  */
19448407Skarels void
19548407Skarels fill_eproc(p, ep)
19648407Skarels 	register struct proc *p;
19748407Skarels 	register struct eproc *ep;
19848407Skarels {
19948407Skarels 	register struct tty *tp;
20048407Skarels 
20148407Skarels 	ep->e_paddr = p;
20248407Skarels 	ep->e_sess = p->p_pgrp->pg_session;
20348407Skarels 	ep->e_pcred = *p->p_cred;
20448407Skarels 	ep->e_ucred = *p->p_ucred;
20548407Skarels 	ep->e_vm = *p->p_vmspace;
20649141Skarels 	if (p->p_pptr)
20749141Skarels 		ep->e_ppid = p->p_pptr->p_pid;
20849141Skarels 	else
20949141Skarels 		ep->e_ppid = 0;
21048407Skarels 	ep->e_pgid = p->p_pgrp->pg_id;
21148407Skarels 	ep->e_jobc = p->p_pgrp->pg_jobc;
21248407Skarels 	if ((p->p_flag&SCTTY) &&
21348407Skarels 	     (tp = ep->e_sess->s_ttyp)) {
21448407Skarels 		ep->e_tdev = tp->t_dev;
21550022Skarels 		ep->e_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
21648407Skarels 		ep->e_tsess = tp->t_session;
21748407Skarels 	} else
21848407Skarels 		ep->e_tdev = NODEV;
21948407Skarels 	ep->e_flag = ep->e_sess->s_ttyvp ? EPROC_CTTY : 0;
22048407Skarels 	if (SESS_LEADER(p))
22148407Skarels 		ep->e_flag |= EPROC_SLEADER;
22248407Skarels 	if (p->p_wmesg)
22348407Skarels 		strncpy(ep->e_wmesg, p->p_wmesg, WMESGLEN);
22448407Skarels 	ep->e_xsize = ep->e_xrssize = 0;
22548407Skarels 	ep->e_xccount = ep->e_xswrss = 0;
22648407Skarels }
22750149Smarc 
22850149Smarc /*
22950149Smarc  * Get file structures.
23050149Smarc  */
23150149Smarc kinfo_file(op, where, acopysize, arg, aneeded)
23250149Smarc 	register char *where;
23350149Smarc 	int *acopysize, *aneeded;
23450149Smarc {
23550149Smarc 	int buflen, needed, error;
23650149Smarc 	struct file *fp;
23750149Smarc 	char *start = where;
23850149Smarc 
23950149Smarc 	if (where == NULL) {
24050149Smarc 		/*
24150149Smarc 		 * overestimate by 10 files
24250149Smarc 		 */
24350149Smarc 		*aneeded = sizeof (filehead) +
24450149Smarc 			(nfiles + 10) * sizeof (struct file);
24550149Smarc 		return (0);
24650149Smarc 	}
24750149Smarc 	buflen = *acopysize;
24850149Smarc 	needed = 0;
24950149Smarc 
25050149Smarc 	/*
25150149Smarc 	 * first copyout filehead
25250149Smarc 	 */
25350149Smarc 	if (buflen > sizeof (filehead)) {
25450149Smarc 		if (error = copyout((caddr_t)&filehead, where,
25550149Smarc 		    sizeof (filehead)))
25650149Smarc 			return (error);
25750149Smarc 		buflen -= sizeof (filehead);
25850149Smarc 		where += sizeof (filehead);
25950149Smarc 	}
26050149Smarc 	needed += sizeof (filehead);
26150149Smarc 
26250149Smarc 	/*
26350149Smarc 	 * followed by an array of file structures
26450149Smarc 	 */
26550149Smarc 	for (fp = filehead; fp != NULL; fp = fp->f_filef) {
26650149Smarc 		if (buflen > sizeof (struct file)) {
26750149Smarc 			if (error = copyout((caddr_t)fp, where,
26850149Smarc 			    sizeof (struct file)))
26950149Smarc 				return (error);
27050149Smarc 			buflen -= sizeof (struct file);
27150149Smarc 			where += sizeof (struct file);
27250149Smarc 		}
27350149Smarc 		needed += sizeof (struct file);
27450149Smarc 	}
27550149Smarc 	*acopysize = where - start;
27650149Smarc 	*aneeded = needed;
27750149Smarc 
27850149Smarc 	return (0);
27950149Smarc }
280