xref: /csrg-svn/sys/kern/kern_sysctl.c (revision 40067)
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*40067Smarc  *	@(#)kern_sysctl.c	7.3 (Berkeley) 02/14/90
1839963Smarc  */
1939963Smarc 
2039965Smckusick #include "param.h"
2139965Smckusick #include "user.h"
2239965Smckusick #include "proc.h"
2339963Smarc #include "kinfo.h"
2439963Smarc #include "vm.h"
2539963Smarc #include "ioctl.h"
2639963Smarc #include "tty.h"
2739963Smarc #include "buf.h"
2839963Smarc 
2939963Smarc /* TODO - gather stats on average and max time spent */
3039963Smarc getkinfo()
3139963Smarc {
3239963Smarc 	register struct a {
3339963Smarc 		int	op;
3439963Smarc 		char	*where;
3539963Smarc 		int	*size;
3639963Smarc 		int	arg;
3739963Smarc 	} *uap = (struct a *)u.u_ap;
3839963Smarc 	int wanted;
3939963Smarc 
4039963Smarc 	switch (ki_type(uap->op)) {
4139963Smarc 
4239963Smarc 	case KINFO_PROC:
4339963Smarc 		u.u_error = kinfo_proc(uap->op, (char *)uap->where,
4439963Smarc 				       (int *)uap->size, uap->arg, &wanted);
4539963Smarc 		if (!u.u_error)
4639963Smarc 			u.u_r.r_val1 = wanted;
4739963Smarc 		break;
4839963Smarc 
4939963Smarc 	default:
5039963Smarc 		u.u_error = EINVAL;
5139963Smarc 	}
5239963Smarc 
5339963Smarc 	return;
5439963Smarc }
5539963Smarc 
5639963Smarc /*
5739963Smarc  * try over estimating by 5 procs
5839963Smarc  */
5939963Smarc #define KINFO_PROCSLOP	(5 * sizeof (struct kinfo_proc))
6039963Smarc 
6139963Smarc int kinfo_proc_userfailed;
6239963Smarc int kinfo_proc_wefailed;
6339963Smarc 
6439963Smarc kinfo_proc(op, where, asize, arg, awanted)
6539963Smarc 	char *where;
6639963Smarc 	int *asize, *awanted;
6739963Smarc {
6839963Smarc 	int	bufsize,	/* max size of users buffer */
6939963Smarc 		copysize, 	/* size copied */
7039963Smarc 		needed;
7139963Smarc 	int locked;
7239963Smarc 	int error;
7339963Smarc 
7439963Smarc 	if (error = kinfo_doprocs(op, NULL, NULL, arg, &needed))
7539963Smarc 		return (error);
7639963Smarc 	if (where == NULL || asize == NULL) {
7739963Smarc 		*awanted = needed;
7839963Smarc 		return (0);
7939963Smarc 	}
8039963Smarc 	if (error = copyin((caddr_t)asize, (caddr_t)&bufsize, sizeof (bufsize)))
8139963Smarc 		return (error);
8239963Smarc 	needed += KINFO_PROCSLOP;
8339963Smarc 	locked = copysize = MIN(needed, bufsize);
8439963Smarc 	if (!useracc(where, copysize, B_WRITE))
8539963Smarc 		return (EFAULT);
8639963Smarc 	/*
8739963Smarc 	 * lock down target pages - NEED DEADLOCK AVOIDANCE
8839963Smarc 	 */
8939963Smarc 	if (copysize > ((int)ptob(freemem) - (20 * 1024))) 	/* XXX */
9039963Smarc 		return (ENOMEM);
9139963Smarc 	vslock(where, copysize);
9239963Smarc 	error = kinfo_doprocs(op, where, &copysize, arg, &needed);
9339963Smarc 	vsunlock(where, locked, B_WRITE);
9439963Smarc 	if (error)
9539963Smarc 		return (error);
9639963Smarc 	*awanted = needed;
9739963Smarc 	if (error = copyout((caddr_t)&copysize, (caddr_t)asize,
9839963Smarc 	    sizeof (copysize)))
9939963Smarc 		return (error);
10039963Smarc 
10139963Smarc 	return (0);
10239963Smarc }
10339963Smarc 
10439963Smarc kinfo_doprocs(op, where, acopysize, arg, aneeded)
10539963Smarc 	char *where;
10639963Smarc 	int *acopysize, *aneeded;
10739963Smarc {
10839963Smarc 	register struct proc *p;
10939963Smarc 	register caddr_t dp = (caddr_t)where;
11039963Smarc 	register needed = 0;
11139963Smarc 	int buflen;
11239963Smarc 	int doingzomb;
113*40067Smarc 	struct eproc eproc;
11439963Smarc 	struct tty *tp;
11539963Smarc 	int error = 0;
11639963Smarc 
11739963Smarc 	if (where != NULL)
11839963Smarc 		buflen = *acopysize;
11939963Smarc 
12039963Smarc 	p = allproc;
12139963Smarc 	doingzomb = 0;
12239963Smarc again:
12339963Smarc 	for (; p != NULL; p = p->p_nxt) {
12439963Smarc 		/*
12539963Smarc 		 * TODO - make more efficient (see notes below).
12639963Smarc 		 * do by session.
12739963Smarc 		 */
12839963Smarc 		switch (ki_op(op)) {
12939963Smarc 
13039963Smarc 		case KINFO_PROC_PID:
13139963Smarc 			/* could do this with just a lookup */
13239963Smarc 			if (p->p_pid != (pid_t)arg)
13339963Smarc 				continue;
13439963Smarc 			break;
13539963Smarc 
13639963Smarc 		case KINFO_PROC_PGRP:
13739963Smarc 			/* could do this by traversing pgrp */
13839963Smarc 			if (p->p_pgrp->pg_id != (pid_t)arg)
13939963Smarc 				continue;
14039963Smarc 			break;
14139963Smarc 
14239963Smarc 		case KINFO_PROC_TTY:
14339963Smarc 			if ((p->p_flag&SCTTY) == 0 ||
14439963Smarc 			    p->p_session->s_ttyp == NULL ||
14539963Smarc 			    p->p_session->s_ttyp->t_dev != (dev_t)arg)
14639963Smarc 				continue;
14739963Smarc 			break;
14839963Smarc 
14939963Smarc 		case KINFO_PROC_UID:
15039963Smarc 			if (p->p_uid != (uid_t)arg)
15139963Smarc 				continue;
15239963Smarc 			break;
15339963Smarc 
15439963Smarc 		case KINFO_PROC_RUID:
15539963Smarc 			if (p->p_ruid != (uid_t)arg)
15639963Smarc 				continue;
15739963Smarc 			break;
15839963Smarc 		}
15939963Smarc 		if (where != NULL && buflen >= sizeof (struct kinfo_proc)) {
16039963Smarc 			if (error = copyout((caddr_t)p, dp,
16139963Smarc 			    sizeof (struct proc)))
16239963Smarc 				return (error);
16339963Smarc 			dp += sizeof (struct proc);
164*40067Smarc 			eproc.kp_paddr = p;
165*40067Smarc 			eproc.kp_sess = p->p_pgrp->pg_session;
166*40067Smarc 			eproc.kp_pgid = p->p_pgrp->pg_id;
167*40067Smarc 			eproc.kp_jobc = p->p_pgrp->pg_jobc;
16839963Smarc 			tp = p->p_pgrp->pg_session->s_ttyp;
16939963Smarc 			if ((p->p_flag&SCTTY) && tp != NULL) {
170*40067Smarc 				eproc.kp_tdev = tp->t_dev;
171*40067Smarc 				eproc.kp_tpgid = tp->t_pgrp ?
17239963Smarc 					tp->t_pgrp->pg_id : -1;
173*40067Smarc 				eproc.kp_tsess = tp->t_session;
17439963Smarc 			} else
175*40067Smarc 				eproc.kp_tdev = NODEV;
176*40067Smarc 			if (error = copyout((caddr_t)&eproc, dp,
177*40067Smarc 			    sizeof (eproc)))
17839963Smarc 				return (error);
179*40067Smarc 			dp += sizeof (eproc);
18039963Smarc 			buflen -= sizeof (struct kinfo_proc);
18139963Smarc 		}
18239963Smarc 		needed += sizeof (struct kinfo_proc);
18339963Smarc 	}
18439963Smarc 	if (doingzomb == 0) {
18539963Smarc 		p = zombproc;
18639963Smarc 		doingzomb++;
18739963Smarc 		goto again;
18839963Smarc 	}
18939963Smarc 	if (where != NULL)
19039963Smarc 		*acopysize = dp - where;
19139963Smarc 	*aneeded = needed;
19239963Smarc 
19339963Smarc 	return (0);
19439963Smarc }
195