/* $Copyright:	$
 * Copyright (c) 1984, 1985, 1986, 1987, 1988, 1989, 1990 
 * Sequent Computer Systems, Inc.   All rights reserved.
 *  
 * This software is furnished under a license and may be used
 * only in accordance with the terms of that license and with the
 * inclusion of the above copyright notice.   This software may not
 * be provided or otherwise made available to, or used by, any
 * other person.  No title to or ownership of the software is
 * hereby transferred.
 */

#ident	"$Header: kern_resrc.c 1.21 89/08/07 $"

/*
 * kern_resource.c
 * 	Resource controls and accounting.
 */

/* $Log:	kern_resrc.c,v $
 */

#include "sys/types.h"
#include "sys/devsw.h"
#include "sys/param.h"
#include "sys/debug.h"
#include "sys/signal.h"
#include "sys/mutex.h"
#include "sys/systm.h"
#include "sys/user.h"
#include "sys/errno.h"
#include "sys/timer.h"
#include "sys/proc.h"
#include "sys/seg.h"
#include "sys/uio.h"
#include "sys/vm.h"
#include "sys/var.h"

#include "sys/intctl.h"

nice()
{
	register struct a {
		int	niceness;
	} *uap = (struct a *)u.u_ap;

	donice(u.u_procp, uap->niceness);
	u.u_r.r_val1 = u.u_procp->p_nice - NZERO;
}

donice(p, n)
	register struct proc *p;
	register int n;
{

	if ((n < 0 || n > 2*NZERO) && !suser())
		n = 0;
	n += p->p_nice;
	if (n >= 2*NZERO)
		n = 2*NZERO - 1;
	if (n < 0)
		n = 0;
	p->p_nice = n;
}


get_process_stats()
{
	register struct a {
		timeval_t *st;
		int	 pid;
		struct	process_stats *pst;
		struct	process_stats *cpst;
	} *uap = (struct a *)u.u_ap;


	timeval_t stime;
	struct process_stats ps;
	struct process_stats cs;
	struct	proc *p;
	int error = 0;

	if (uap->pid == PS_SELF) {
		(void)splhi();
		ps = u.u_pst;
		cs = u.u_cpst;
		stime =  time;
		(void)spl0();
	} else {
		p = pfind((pid_t)uap->pid);
		if ( p != NULL) {
			if ((u.u_uid == 0) || (u.u_ruid == 0) ||
		   	(u.u_uid == p->p_uid) || (u.u_ruid == p->p_uid) ||
		    	(u.u_uid == p->p_suid) || (u.u_ruid == p->p_suid)){
				if ((p->p_stat != SZOMB) &&
				   (p->p_stat != SIDL) &&
				   (p->p_flag & SLOAD)) {
					ps = p->p_uarea->u_pst;
					cs = p->p_uarea->u_cpst;
					stime = time;
				} else {
					error = EAGAIN;
				}
			} else {
				error = EPERM;
			}
			v_lock(&p->p_state, SPL0);
		} else {
			error = ESRCH;
		}
	}
	if ((error == 0) && uap->st)
		error = copyout(&stime, uap->st, sizeof(timeval_t));
	if ((error == 0) && uap->pst)
		error = copyout(&ps, uap->pst, sizeof(struct process_stats));
	if ((error == 0) && uap->cpst)
		error = copyout(&cs, uap->cpst, sizeof(struct process_stats));
	u.u_error = error;
}

pstadd(ps, ps2)
	register struct process_stats *ps;
	struct process_stats *ps2;
{
	register ulong *ip;
	register ulong *ip2;

	timevaladd(&ps->ps_utime, &ps2->ps_utime);
	timevaladd(&ps->ps_stime, &ps2->ps_stime);
	if (ps->ps_maxrss < ps2->ps_maxrss)
		ps->ps_maxrss = ps2->ps_maxrss;
	ip = &ps->ps_first; ip2 = &ps2->ps_first;
	for (; ip <= &ps->ps_last; ip++, ip2++)
		*ip += *ip2;
}

/*
 * System V ulimit.
 */

ulimit()
{
	register struct a {
		int	cmd;
		long	arg;
	} *uap;

	uap = (struct a *)u.u_ap;
	switch (uap->cmd) {

	case 2:	/* Set new file size limit. */
		if (uap->arg > u.u_limit && !suser())
			return;
		u.u_limit = uap->arg;

	case 1:	/* Return current file size limit. */
		u.u_r.r_val1 = u.u_limit;
		break;

	case 3:	/* Return maximum possible break value. */
		{
		register struct mmap *um, *um1 = NULL;

		for (um = u.u_mmap; um < u.u_mmapmax; um++) {
			if (um->mm_pgcnt == 0 || um->mm_1stpg < u.u_dsegsz)
				continue;
			 if (um1 == NULL || um->mm_1stpg < um1->mm_1stpg)
				um1 = um;
		}
		if (um1)
			u.u_r.r_val1 = ctob(um1->mm_1stpg);
		else
			u.u_r.r_val1 = ctob(MAXDSIZ);
		break;
		}

	case 4:	/* Return configured value of NOFILES. */
		/*
		 * We return the max number of files a process can open
		 * without having to do a setdtablesize().
		 */
		getdtablesize();
		break;

	default:
		u.u_error = EINVAL;
	}
}
