xref: /csrg-svn/sys/kern/kern_sysctl.c (revision 56517)
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*56517Sbostic  *	@(#)kern_sysctl.c	7.25 (Berkeley) 10/11/92
839963Smarc  */
939963Smarc 
10*56517Sbostic #include <sys/param.h>
11*56517Sbostic #include <sys/proc.h>
12*56517Sbostic #include <sys/kinfo.h>
13*56517Sbostic #include <sys/ioctl.h>
14*56517Sbostic #include <sys/tty.h>
15*56517Sbostic #include <sys/buf.h>
16*56517Sbostic #include <sys/file.h>
1739963Smarc 
18*56517Sbostic #include <vm/vm.h>
1948407Skarels 
20*56517Sbostic #include <sys/kinfo_proc.h>
2148407Skarels 
2240068Smarc #define snderr(e) { error = (e); goto release;}
2350149Smarc extern int kinfo_doproc(), kinfo_rtable(), kinfo_vnode(), kinfo_file();
2452669Smckusick extern int kinfo_meter(), kinfo_loadavg(), kinfo_clockrate();
2540068Smarc struct kinfo_lock kinfo_lock;
2640068Smarc 
2754923Storek struct getkerninfo_args {
2854923Storek 	int	op;
2954923Storek 	char	*where;
3054923Storek 	int	*size;
3154923Storek 	int	arg;
3254923Storek };
3343444Smckusick /* ARGSUSED */
3443444Smckusick getkerninfo(p, uap, retval)
3543444Smckusick 	struct proc *p;
3654923Storek 	register struct getkerninfo_args *uap;
3743444Smckusick 	int *retval;
3843444Smckusick {
3947545Skarels 	int bufsize;		/* max size of users buffer */
4047545Skarels 	int needed, locked, (*server)(), error = 0;
4139963Smarc 
4239963Smarc 	switch (ki_type(uap->op)) {
4339963Smarc 
4439963Smarc 	case KINFO_PROC:
4540068Smarc 		server = kinfo_doproc;
4639963Smarc 		break;
4739963Smarc 
4840068Smarc 	case KINFO_RT:
4940068Smarc 		server = kinfo_rtable;
5040068Smarc 		break;
5140068Smarc 
5241181Smarc 	case KINFO_VNODE:
5341181Smarc 		server = kinfo_vnode;
5441181Smarc 		break;
5541181Smarc 
5650149Smarc 	case KINFO_FILE:
5750149Smarc 		server = kinfo_file;
5850149Smarc 		break;
5950149Smarc 
6050909Smckusick 	case KINFO_METER:
6150909Smckusick 		server = kinfo_meter;
6250909Smckusick 		break;
6350909Smckusick 
6452669Smckusick 	case KINFO_LOADAVG:
6552669Smckusick 		server = kinfo_loadavg;
6652669Smckusick 		break;
6752669Smckusick 
6852669Smckusick 	case KINFO_CLOCKRATE:
6952669Smckusick 		server = kinfo_clockrate;
7052669Smckusick 		break;
7152669Smckusick 
7239963Smarc 	default:
7340206Smarc 		error = EINVAL;
7440813Smarc 		goto done;
7539963Smarc 	}
7640813Smarc 	if (uap->where == NULL || uap->size == NULL) {
7740813Smarc 		error = (*server)(uap->op, NULL, NULL, uap->arg, &needed);
7840813Smarc 		goto done;
7940813Smarc 	}
8051727Sralph 	if (error = copyin((caddr_t)uap->size, (caddr_t)&bufsize,
8151727Sralph 	    sizeof (bufsize)))
8251727Sralph 		goto done;
8340206Smarc 	while (kinfo_lock.kl_lock) {
8452405Storek 		kinfo_lock.kl_want = 1;
8552405Storek 		sleep((caddr_t)&kinfo_lock, PRIBIO+1);
8640206Smarc 		kinfo_lock.kl_locked++;
8740206Smarc 	}
8852405Storek 	kinfo_lock.kl_lock = 1;
8940206Smarc 
9040813Smarc 	if (!useracc(uap->where, bufsize, B_WRITE))
9140068Smarc 		snderr(EFAULT);
9241181Smarc 	if (server != kinfo_vnode)	/* XXX */
9341181Smarc 		vslock(uap->where, bufsize);
9440813Smarc 	locked = bufsize;
9540813Smarc 	error = (*server)(uap->op, uap->where, &bufsize, uap->arg, &needed);
9641181Smarc 	if (server != kinfo_vnode)	/* XXX */
9741181Smarc 		vsunlock(uap->where, locked, B_WRITE);
9840813Smarc 	if (error == 0)
9940813Smarc 		error = copyout((caddr_t)&bufsize,
10040813Smarc 				(caddr_t)uap->size, sizeof (bufsize));
10140068Smarc release:
10252405Storek 	kinfo_lock.kl_lock = 0;
10352405Storek 	if (kinfo_lock.kl_want) {
10452405Storek 		kinfo_lock.kl_want = 0;
10552405Storek 		wakeup((caddr_t)&kinfo_lock);
10652405Storek 	}
10740813Smarc done:
10843444Smckusick 	if (!error)
10943444Smckusick 		*retval = needed;
11043444Smckusick 	return (error);
11139963Smarc }
11239963Smarc 
11339963Smarc /*
11439963Smarc  * try over estimating by 5 procs
11539963Smarc  */
11639963Smarc #define KINFO_PROCSLOP	(5 * sizeof (struct kinfo_proc))
11739963Smarc 
11840206Smarc kinfo_doproc(op, where, acopysize, arg, aneeded)
11952405Storek 	int op;
12039963Smarc 	char *where;
12152405Storek 	int *acopysize, arg, *aneeded;
12239963Smarc {
12339963Smarc 	register struct proc *p;
12443419Smarc 	register struct kinfo_proc *dp = (struct kinfo_proc *)where;
12539963Smarc 	register needed = 0;
12652405Storek 	int buflen = where != NULL ? *acopysize : 0;
12739963Smarc 	int doingzomb;
12840067Smarc 	struct eproc eproc;
12939963Smarc 	int error = 0;
13039963Smarc 
13154755Storek 	p = (struct proc *)allproc;
13239963Smarc 	doingzomb = 0;
13339963Smarc again:
13439963Smarc 	for (; p != NULL; p = p->p_nxt) {
13553819Smckusick 		/*
13653819Smckusick 		 * Skip embryonic processes.
13753819Smckusick 		 */
13853819Smckusick 		if (p->p_stat == SIDL)
13953819Smckusick 			continue;
14039963Smarc 		/*
14139963Smarc 		 * TODO - make more efficient (see notes below).
14239963Smarc 		 * do by session.
14339963Smarc 		 */
14439963Smarc 		switch (ki_op(op)) {
14539963Smarc 
14639963Smarc 		case KINFO_PROC_PID:
14739963Smarc 			/* could do this with just a lookup */
14839963Smarc 			if (p->p_pid != (pid_t)arg)
14939963Smarc 				continue;
15039963Smarc 			break;
15139963Smarc 
15239963Smarc 		case KINFO_PROC_PGRP:
15339963Smarc 			/* could do this by traversing pgrp */
15439963Smarc 			if (p->p_pgrp->pg_id != (pid_t)arg)
15539963Smarc 				continue;
15639963Smarc 			break;
15739963Smarc 
15839963Smarc 		case KINFO_PROC_TTY:
15939963Smarc 			if ((p->p_flag&SCTTY) == 0 ||
16039963Smarc 			    p->p_session->s_ttyp == NULL ||
16139963Smarc 			    p->p_session->s_ttyp->t_dev != (dev_t)arg)
16239963Smarc 				continue;
16339963Smarc 			break;
16439963Smarc 
16539963Smarc 		case KINFO_PROC_UID:
16647545Skarels 			if (p->p_ucred->cr_uid != (uid_t)arg)
16739963Smarc 				continue;
16839963Smarc 			break;
16939963Smarc 
17039963Smarc 		case KINFO_PROC_RUID:
17147545Skarels 			if (p->p_cred->p_ruid != (uid_t)arg)
17239963Smarc 				continue;
17339963Smarc 			break;
17439963Smarc 		}
17552405Storek 		if (buflen >= sizeof (struct kinfo_proc)) {
17648407Skarels 			fill_eproc(p, &eproc);
17743419Smarc 			if (error = copyout((caddr_t)p, &dp->kp_proc,
17839963Smarc 			    sizeof (struct proc)))
17939963Smarc 				return (error);
18043419Smarc 			if (error = copyout((caddr_t)&eproc, &dp->kp_eproc,
18140067Smarc 			    sizeof (eproc)))
18239963Smarc 				return (error);
18343419Smarc 			dp++;
18439963Smarc 			buflen -= sizeof (struct kinfo_proc);
18539963Smarc 		}
18639963Smarc 		needed += sizeof (struct kinfo_proc);
18739963Smarc 	}
18839963Smarc 	if (doingzomb == 0) {
18939963Smarc 		p = zombproc;
19039963Smarc 		doingzomb++;
19139963Smarc 		goto again;
19239963Smarc 	}
19339963Smarc 	if (where != NULL)
19443419Smarc 		*acopysize = (caddr_t)dp - where;
19540068Smarc 	else
19640068Smarc 		needed += KINFO_PROCSLOP;
19739963Smarc 	*aneeded = needed;
19839963Smarc 
19939963Smarc 	return (0);
20039963Smarc }
20148407Skarels 
20248407Skarels /*
20348407Skarels  * Fill in an eproc structure for the specified process.
20448407Skarels  */
20548407Skarels void
20648407Skarels fill_eproc(p, ep)
20748407Skarels 	register struct proc *p;
20848407Skarels 	register struct eproc *ep;
20948407Skarels {
21048407Skarels 	register struct tty *tp;
21148407Skarels 
21248407Skarels 	ep->e_paddr = p;
21348407Skarels 	ep->e_sess = p->p_pgrp->pg_session;
21448407Skarels 	ep->e_pcred = *p->p_cred;
21548407Skarels 	ep->e_ucred = *p->p_ucred;
21652405Storek 	if (p->p_stat == SIDL || p->p_stat == SZOMB) {
21752405Storek 		ep->e_vm.vm_rssize = 0;
21852405Storek 		ep->e_vm.vm_tsize = 0;
21952405Storek 		ep->e_vm.vm_dsize = 0;
22052405Storek 		ep->e_vm.vm_ssize = 0;
22152405Storek #ifndef sparc
22252405Storek 		/* ep->e_vm.vm_pmap = XXX; */
22352405Storek #endif
22452405Storek 	} else {
22552405Storek 		register struct vmspace *vm = p->p_vmspace;
22652405Storek 
22752405Storek 		ep->e_vm.vm_rssize = vm->vm_rssize;
22852405Storek 		ep->e_vm.vm_tsize = vm->vm_tsize;
22952405Storek 		ep->e_vm.vm_dsize = vm->vm_dsize;
23052405Storek 		ep->e_vm.vm_ssize = vm->vm_ssize;
23152405Storek #ifndef sparc
23252405Storek 		ep->e_vm.vm_pmap = vm->vm_pmap;
23352405Storek #endif
23452405Storek 	}
23549141Skarels 	if (p->p_pptr)
23649141Skarels 		ep->e_ppid = p->p_pptr->p_pid;
23749141Skarels 	else
23849141Skarels 		ep->e_ppid = 0;
23948407Skarels 	ep->e_pgid = p->p_pgrp->pg_id;
24048407Skarels 	ep->e_jobc = p->p_pgrp->pg_jobc;
24148407Skarels 	if ((p->p_flag&SCTTY) &&
24248407Skarels 	     (tp = ep->e_sess->s_ttyp)) {
24348407Skarels 		ep->e_tdev = tp->t_dev;
24450022Skarels 		ep->e_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
24548407Skarels 		ep->e_tsess = tp->t_session;
24648407Skarels 	} else
24748407Skarels 		ep->e_tdev = NODEV;
24848407Skarels 	ep->e_flag = ep->e_sess->s_ttyvp ? EPROC_CTTY : 0;
24948407Skarels 	if (SESS_LEADER(p))
25048407Skarels 		ep->e_flag |= EPROC_SLEADER;
25148407Skarels 	if (p->p_wmesg)
25248407Skarels 		strncpy(ep->e_wmesg, p->p_wmesg, WMESGLEN);
25348407Skarels 	ep->e_xsize = ep->e_xrssize = 0;
25448407Skarels 	ep->e_xccount = ep->e_xswrss = 0;
25548407Skarels }
25650149Smarc 
25750149Smarc /*
25850149Smarc  * Get file structures.
25950149Smarc  */
26050149Smarc kinfo_file(op, where, acopysize, arg, aneeded)
26152405Storek 	int op;
26250149Smarc 	register char *where;
26352405Storek 	int *acopysize, arg, *aneeded;
26450149Smarc {
26550149Smarc 	int buflen, needed, error;
26650149Smarc 	struct file *fp;
26750149Smarc 	char *start = where;
26850149Smarc 
26950149Smarc 	if (where == NULL) {
27050149Smarc 		/*
27150149Smarc 		 * overestimate by 10 files
27250149Smarc 		 */
27350149Smarc 		*aneeded = sizeof (filehead) +
27450149Smarc 			(nfiles + 10) * sizeof (struct file);
27550149Smarc 		return (0);
27650149Smarc 	}
27750149Smarc 	buflen = *acopysize;
27850149Smarc 	needed = 0;
27950149Smarc 
28050149Smarc 	/*
28150149Smarc 	 * first copyout filehead
28250149Smarc 	 */
28350149Smarc 	if (buflen > sizeof (filehead)) {
28450149Smarc 		if (error = copyout((caddr_t)&filehead, where,
28550149Smarc 		    sizeof (filehead)))
28650149Smarc 			return (error);
28750149Smarc 		buflen -= sizeof (filehead);
28850149Smarc 		where += sizeof (filehead);
28950149Smarc 	}
29050149Smarc 	needed += sizeof (filehead);
29150149Smarc 
29250149Smarc 	/*
29350149Smarc 	 * followed by an array of file structures
29450149Smarc 	 */
29550149Smarc 	for (fp = filehead; fp != NULL; fp = fp->f_filef) {
29650149Smarc 		if (buflen > sizeof (struct file)) {
29750149Smarc 			if (error = copyout((caddr_t)fp, where,
29850149Smarc 			    sizeof (struct file)))
29950149Smarc 				return (error);
30050149Smarc 			buflen -= sizeof (struct file);
30150149Smarc 			where += sizeof (struct file);
30250149Smarc 		}
30350149Smarc 		needed += sizeof (struct file);
30450149Smarc 	}
30550149Smarc 	*acopysize = where - start;
30650149Smarc 	*aneeded = needed;
30750149Smarc 
30850149Smarc 	return (0);
30950149Smarc }
310