xref: /csrg-svn/sys/kern/kern_sysctl.c (revision 43444)
139963Smarc /*
239963Smarc  * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
339963Smarc  * All rights reserved.
439963Smarc  *
539963Smarc  * Redistribution and use in source and binary forms are permitted
639963Smarc  * provided that the above copyright notice and this paragraph are
739963Smarc  * duplicated in all such forms and that any documentation,
839963Smarc  * advertising materials, and other materials related to such
939963Smarc  * distribution and use acknowledge that the software was developed
1039963Smarc  * by the University of California, Berkeley.  The name of the
1139963Smarc  * University may not be used to endorse or promote products derived
1239963Smarc  * from this software without specific prior written permission.
1339963Smarc  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1439963Smarc  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1539963Smarc  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1639963Smarc  *
17*43444Smckusick  *	@(#)kern_sysctl.c	7.10 (Berkeley) 06/22/90
1839963Smarc  */
1939963Smarc 
2039965Smckusick #include "param.h"
2139965Smckusick #include "user.h"
2239965Smckusick #include "proc.h"
2340206Smarc #include "text.h"
2439963Smarc #include "kinfo.h"
2539963Smarc #include "vm.h"
2639963Smarc #include "ioctl.h"
2739963Smarc #include "tty.h"
2839963Smarc #include "buf.h"
2939963Smarc 
3040068Smarc 
3140068Smarc #define snderr(e) { error = (e); goto release;}
3241181Smarc extern int kinfo_doproc(), kinfo_rtable(), kinfo_vnode();
3340068Smarc struct kinfo_lock kinfo_lock;
3440068Smarc 
35*43444Smckusick /* ARGSUSED */
36*43444Smckusick getkerninfo(p, uap, retval)
37*43444Smckusick 	struct proc *p;
38*43444Smckusick 	register struct args {
3939963Smarc 		int	op;
4039963Smarc 		char	*where;
4139963Smarc 		int	*size;
4239963Smarc 		int	arg;
43*43444Smckusick 	} *uap;
44*43444Smckusick 	int *retval;
45*43444Smckusick {
4640206Smarc 
4740068Smarc 	int	bufsize,	/* max size of users buffer */
4840206Smarc 		needed,	locked, (*server)(), error = 0;
4939963Smarc 
5040206Smarc 	if (error = copyin((caddr_t)uap->size,
5140206Smarc 				(caddr_t)&bufsize, sizeof (bufsize)))
5240813Smarc 		goto done;
5340068Smarc 
5439963Smarc 	switch (ki_type(uap->op)) {
5539963Smarc 
5639963Smarc 	case KINFO_PROC:
5740068Smarc 		server = kinfo_doproc;
5839963Smarc 		break;
5939963Smarc 
6040068Smarc 	case KINFO_RT:
6140068Smarc 		server = kinfo_rtable;
6240068Smarc 		break;
6340068Smarc 
6441181Smarc 	case KINFO_VNODE:
6541181Smarc 		server = kinfo_vnode;
6641181Smarc 		break;
6741181Smarc 
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);
8640068Smarc 	/*
8740068Smarc 	 * lock down target pages - NEED DEADLOCK AVOIDANCE
8840068Smarc 	 */
8940813Smarc 	if (bufsize > ((int)ptob(freemem) - (20 * 1024))) 	/* XXX */
9040068Smarc 		snderr(ENOMEM);
9141181Smarc 	if (server != kinfo_vnode)	/* XXX */
9241181Smarc 		vslock(uap->where, bufsize);
9340813Smarc 	locked = bufsize;
9440813Smarc 	error = (*server)(uap->op, uap->where, &bufsize, uap->arg, &needed);
9541181Smarc 	if (server != kinfo_vnode)	/* XXX */
9641181Smarc 		vsunlock(uap->where, locked, B_WRITE);
9740813Smarc 	if (error == 0)
9840813Smarc 		error = copyout((caddr_t)&bufsize,
9940813Smarc 				(caddr_t)uap->size, sizeof (bufsize));
10040068Smarc release:
10140068Smarc 	kinfo_lock.kl_lock--;
10240068Smarc 	if (kinfo_lock.kl_want)
10340068Smarc 		wakeup(&kinfo_lock);
10440813Smarc done:
105*43444Smckusick 	if (!error)
106*43444Smckusick 		*retval = needed;
107*43444Smckusick 	return (error);
10839963Smarc }
10939963Smarc 
11039963Smarc /*
11139963Smarc  * try over estimating by 5 procs
11239963Smarc  */
11339963Smarc #define KINFO_PROCSLOP	(5 * sizeof (struct kinfo_proc))
11439963Smarc 
11540206Smarc kinfo_doproc(op, where, acopysize, arg, aneeded)
11639963Smarc 	char *where;
11739963Smarc 	int *acopysize, *aneeded;
11839963Smarc {
11939963Smarc 	register struct proc *p;
12043419Smarc 	register struct kinfo_proc *dp = (struct kinfo_proc *)where;
12139963Smarc 	register needed = 0;
12239963Smarc 	int buflen;
12339963Smarc 	int doingzomb;
12440067Smarc 	struct eproc eproc;
12539963Smarc 	int error = 0;
12639963Smarc 
12739963Smarc 	if (where != NULL)
12839963Smarc 		buflen = *acopysize;
12939963Smarc 
13039963Smarc 	p = allproc;
13139963Smarc 	doingzomb = 0;
13239963Smarc again:
13339963Smarc 	for (; p != NULL; p = p->p_nxt) {
13439963Smarc 		/*
13539963Smarc 		 * TODO - make more efficient (see notes below).
13639963Smarc 		 * do by session.
13739963Smarc 		 */
13839963Smarc 		switch (ki_op(op)) {
13939963Smarc 
14039963Smarc 		case KINFO_PROC_PID:
14139963Smarc 			/* could do this with just a lookup */
14239963Smarc 			if (p->p_pid != (pid_t)arg)
14339963Smarc 				continue;
14439963Smarc 			break;
14539963Smarc 
14639963Smarc 		case KINFO_PROC_PGRP:
14739963Smarc 			/* could do this by traversing pgrp */
14839963Smarc 			if (p->p_pgrp->pg_id != (pid_t)arg)
14939963Smarc 				continue;
15039963Smarc 			break;
15139963Smarc 
15239963Smarc 		case KINFO_PROC_TTY:
15339963Smarc 			if ((p->p_flag&SCTTY) == 0 ||
15439963Smarc 			    p->p_session->s_ttyp == NULL ||
15539963Smarc 			    p->p_session->s_ttyp->t_dev != (dev_t)arg)
15639963Smarc 				continue;
15739963Smarc 			break;
15839963Smarc 
15939963Smarc 		case KINFO_PROC_UID:
16039963Smarc 			if (p->p_uid != (uid_t)arg)
16139963Smarc 				continue;
16239963Smarc 			break;
16339963Smarc 
16439963Smarc 		case KINFO_PROC_RUID:
16539963Smarc 			if (p->p_ruid != (uid_t)arg)
16639963Smarc 				continue;
16739963Smarc 			break;
16839963Smarc 		}
16939963Smarc 		if (where != NULL && buflen >= sizeof (struct kinfo_proc)) {
17040206Smarc 			register struct text *txt;
17143419Smarc 			register struct tty *tp;
17240206Smarc 
17343419Smarc 			if (error = copyout((caddr_t)p, &dp->kp_proc,
17439963Smarc 			    sizeof (struct proc)))
17539963Smarc 				return (error);
17640206Smarc 			eproc.e_paddr = p;
17740206Smarc 			eproc.e_sess = p->p_pgrp->pg_session;
17840206Smarc 			eproc.e_pgid = p->p_pgrp->pg_id;
17940206Smarc 			eproc.e_jobc = p->p_pgrp->pg_jobc;
18043419Smarc 			if ((p->p_flag&SCTTY) &&
18143419Smarc 			     (tp = eproc.e_sess->s_ttyp)) {
18240206Smarc 				eproc.e_tdev = tp->t_dev;
18340206Smarc 				eproc.e_tpgid = tp->t_pgrp ?
18439963Smarc 					tp->t_pgrp->pg_id : -1;
18540206Smarc 				eproc.e_tsess = tp->t_session;
18639963Smarc 			} else
18740206Smarc 				eproc.e_tdev = NODEV;
18843419Smarc 			eproc.e_flag = eproc.e_sess->s_ttyvp ? EPROC_CTTY : 0;
18943419Smarc 			if (SESS_LEADER(p))
19043419Smarc 				eproc.e_flag |= EPROC_SLEADER;
19140206Smarc 			if (p->p_wmesg)
19240206Smarc 				strncpy(eproc.e_wmesg, p->p_wmesg, WMESGLEN);
19340206Smarc 			if (txt = p->p_textp) {
19440206Smarc 				eproc.e_xsize = txt->x_size;
19540206Smarc 				eproc.e_xrssize = txt->x_rssize;
19640206Smarc 				eproc.e_xccount = txt->x_ccount;
19740206Smarc 				eproc.e_xswrss = txt->x_swrss;
19840206Smarc 			} else {
19940206Smarc 				eproc.e_xsize = eproc.e_xrssize =
20040206Smarc 				  eproc.e_xccount =  eproc.e_xswrss = 0;
20140206Smarc 			}
20243419Smarc 			if (error = copyout((caddr_t)&eproc, &dp->kp_eproc,
20340067Smarc 			    sizeof (eproc)))
20439963Smarc 				return (error);
20543419Smarc 			dp++;
20639963Smarc 			buflen -= sizeof (struct kinfo_proc);
20739963Smarc 		}
20839963Smarc 		needed += sizeof (struct kinfo_proc);
20939963Smarc 	}
21039963Smarc 	if (doingzomb == 0) {
21139963Smarc 		p = zombproc;
21239963Smarc 		doingzomb++;
21339963Smarc 		goto again;
21439963Smarc 	}
21539963Smarc 	if (where != NULL)
21643419Smarc 		*acopysize = (caddr_t)dp - where;
21740068Smarc 	else
21840068Smarc 		needed += KINFO_PROCSLOP;
21939963Smarc 	*aneeded = needed;
22039963Smarc 
22139963Smarc 	return (0);
22239963Smarc }
223