/*
 *	Network Queueing System (NQS)
 *  This version of NQS is Copyright (C) 1992  John Roman
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 1, or (at your option)
 *  any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
/*
*  PROJECT:     Network Queueing System
*  AUTHOR:      John Roman
*
*  Modification history:
*
*       Version Who     When            Description
*       -------+-------+---------------+-------------------------
*       V01.10  JRR                     Initial version.
*       V01.20  JRR     16-Jan-1992	Added support for RS6000.
*	V01.3	JRR	17-Jun-1992	Added header.
*	V01.4	JRR			HPUX support.
*	V01.5	JRR	17-Mar-1993	Removed include of resource.h
*					for ULTRIX.
*	V01.6	JRR	17-Jul-1993	Fixed so SGI called quolimok.
*	V01.7	JRR	28-Feb-1994	Added support for SOLARIS.
*/
/*++ quolimok.c - Network Queueing System
 *
 * $Source: /usr2/jrroma/nqs/nqs-3.35.6/lib/RCS/quolimok.c,v $
 *
 * DESCRIPTION:
 *
 *	Given the numerical value of a resource limit, report whether
 *	that limit would be too high or too low to enforce on this
 *	machine.  If the limit would be out of bounds, suggest
 *	a value that would be in bounds.
 *
 *
 *	Author:
 *	-------
 *	Robert W. Sandstrom, Sterling Software Incorporated.
 *	January 22, 1986.
 *
 *
 * STANDARDS VIOLATIONS:
 *   None.
 *
 * REVISION HISTORY: ($Revision: 1.7 $ $Date: 1994/03/30 20:32:40 $ $State: Exp $)
 * $Log: quolimok.c,v $
 * Revision 1.7  1994/03/30  20:32:40  jrroma
 * Version 3.35.6
 *
 * Revision 1.6  93/09/10  13:55:19  jrroma
 * Version 3.35
 * 
 * Revision 1.5  93/07/13  21:31:34  jrroma
 * Version 3.34
 * 
 * Revision 1.4  92/11/06  13:53:50  jrroma
 * Added support for HPUX. 
 * 
 * Revision 1.3  92/06/18  13:24:29  jrroma
 * Added gnu header
 * 
 * Revision 1.2  92/01/16  17:08:38  jrroma
 * Added support for RS6000.
 * 
 * Revision 1.1  92/01/16  17:07:11  jrroma
 * Initial revision
 * 
 *
 */

#include "nqs.h"		/* for struct quotalimit, etc. */
#if	BSD43 | ULTRIX | DECOSF
#if	DECOSF
#if	RLIM_INFINITY != 0x7FFFFFFFFFFFFFFF
REWRITE THIS FILE
#endif
#else
#if	RLIM_INFINITY != 0x7FFFFFFF
REWRITE THIS FILE
#endif
#if	MEM_LIMIT_GRAN != 1	/* BSD4.2, BSD4.3, and ULTRIX code assumes */
				/* MEM_LIMIT_GRAN == 1 */
REWRITE THIS FILE
#endif
#endif
#if	DISK_LIMIT_GRAN != 1	/* BSD4.2, BSD4.3, and ULTRIX code assumes */
				/* DISK_LIMIT_GRAN == 1 */
REWRITE THIS FILE
#endif
#else
#if	SGI | SOLARIS | LINUX
#include <sys/resource.h>
#else
#if	HPUX | SYS52 | IBMRS 
#else
BAD SYSTEM TYPE
#endif
#endif
#endif

/*** cpulimhigh
 *
 *
 *	int cpulimhigh ():
 *
 *	Given a cpu time limit, report whether the implied limit
 *	could be enforced on this machine.  In determining whether
 *	the limit is too high, we must remember that some
 *	apparently finite limit values might have been usurped
 *	by the system call in question to mean "infinity".
 *
 *	If the limit is ok, return 0. If the limit is too big,
 *	return 1 and assign the largest enforceable limit 
 *	to the designated variables.
 */
int cpulimhigh (
	unsigned long secs,		/* Seconds part */
	short ms,			/* Milliseconds part */
	short infinite,			/* Boolean */
	unsigned long *new_secsp,	/* Pointer to altered seconds value */
	short *new_msp)			/* Pointer to altered milliseconds */
{
#if	HPUX | SYS52 | IBMRS 
#else
#if	BSD43 | ULTRIX | DECOSF | SGI | SOLARIS | LINUX
 	if (infinite) return (0);
	if (secs >= (RLIM_INFINITY - ((ms * CPU_LIMIT_GRAN) / 1000))
			/ CPU_LIMIT_GRAN) {
		*new_secsp = (RLIM_INFINITY / CPU_LIMIT_GRAN) -1;
		*new_msp = 0;
		return (1);
	}
#else
BAD SYSTEM TYPE
#endif
#endif
	return (0);
}


/*** cpulimlow
 *
 *
 *	int cpulimlow ():
 *
 *	Given a cpu time limit, report whether the implied limit
 *	could be enforced on this machine.  In determining whether
 *	the limit is too low, we must remember that some
 *	apparently finite limit values might have been usurped
 *	by the system call in question to mean "infinity".
 *
 *	The limit shall be deemed to be too small if it is
 *	a small number and attempting to enforce it would
 *	result in an infinite limit.
 *
 *	If the limit is ok, return 0. If the limit is too small,
 *	return 1 and assign the smallest enforceable limit
 *	to the designated variables.
 */
int cpulimlow (
	unsigned long secs,		/* Seconds part */
	short ms,			/* Milliseconds part */
	unsigned long *new_secsp,	/* Pointer to altered seconds value */
	short *new_msp)			/* Pointer to altered milliseconds */
{
	return (0);
}


/*** quolimhigh
 *
 *
 *	int quolimhigh():
 *
 *	Given the coefficient and the units of a memory or disk
 *	resource limit, report whether the implied limit could be
 *	enforced on this machine. In determining whether the limit
 *	is too high, we must remember that some apparently finite
 *	limit values might have been usurped by the system call in
 *	question to mean "infinity". 
 *
 *	Presently, we assume that on BSD4.3, DECOSF, and ULTRIX, that
 *	MEM_LIMIT_GRAN and DISK_LIMIT_GRAN are 1.  If either is not, the
 *	code breaks.  We also pretend that for SYS52, SGI, & SOLARIS,  a limit
 *	is too high if the limit expressed in bytes doesn't fit in 31 bits.
 *	This treats some legal limits as illegal.
 *
 *	If the limit could be enforced, return 0.
 *	If the limit could not be enforced, return 1
 *	and assign the largest limit that could be enforced
 *	to the designated variables.
 *
 *	We assume that the actual parameter "coeff" < 2**31.
 *	This is in line with scanquolim().  Limit_type is kept as
 *	a formal parameter for two reasons:
 *	1) For symmetry with quolimlow().
 *	2) To remind porters to consider it.
 */
int quolimhigh (
	unsigned long coeff,		/* Coefficient of limit in question */
	short units,			/* Units of limit in question */
	short infinite,			/* Boolean */
	int limit_type,			/* One of LIM_??? */
	unsigned long *new_coeffp,	/* Pointer to altered coefficient */
	short *new_unitsp)		/* Pointer to altered units */
{
#if	BSD42 | BSD43 | ULTRIX | DECOSF
	/*
	 * If the limit would look like infinity to the system call,
	 * or if it is bigger than the number that would look like
	 * infinity, change it and return 1.
	 */
	if (infinite) return (0);
	switch (units) {
	case QLM_BYTES:
		if (coeff >= RLIM_INFINITY) {
			*new_coeffp = RLIM_INFINITY - 1;
			*new_unitsp = (short) QLM_BYTES;
			return (1);
		}
		return (0);
	case QLM_WORDS:
		if (coeff >= RLIM_INFINITY / (BYTES_PER_WORD)) {
			*new_coeffp = RLIM_INFINITY -1;
			*new_unitsp = (short) QLM_BYTES;
			return (1);
		}
		return (0);
	case QLM_KBYTES:
		if (coeff >= RLIM_INFINITY / (1<<10)) {
			*new_coeffp = RLIM_INFINITY - 1;
			*new_unitsp = (short) QLM_BYTES;
			return (1);
		}
		return (0);
	case QLM_KWORDS:
		if (coeff >= RLIM_INFINITY / ((1<<10) * BYTES_PER_WORD)) {
			*new_coeffp = RLIM_INFINITY -1;
			*new_unitsp = (short) QLM_BYTES;
			return (1);
		}
		return (0);
	case QLM_MBYTES:
		if (coeff >= RLIM_INFINITY / (1<<20)) {
			*new_coeffp = RLIM_INFINITY - 1;
			*new_unitsp = (short) QLM_BYTES;
			return (1);
		}
		return (0);
	case QLM_MWORDS:
		if (coeff >= RLIM_INFINITY / ((1<<20) * BYTES_PER_WORD)) {
			*new_coeffp = RLIM_INFINITY -1;
			*new_unitsp = (short) QLM_BYTES;
			return (1);
		}
		return (0);
	case QLM_GBYTES:
		if (coeff >= RLIM_INFINITY / (1<<30)) {
			*new_coeffp = RLIM_INFINITY - 1;
			*new_unitsp = (short) QLM_BYTES;
			return (1);
		}
		return (0);
	case QLM_GWORDS:
		/*
		 * Zero gigawords is an exception.
		 */
		if (coeff == 0) return (0);
		/*
		 * In the case of gigawords, we have to check
		 * for overflow.
		 */
		if (BYTES_PER_WORD > 1) {
			*new_coeffp = RLIM_INFINITY -1;
			*new_unitsp = (short) QLM_BYTES;
			return (1);
		}
		if (coeff >= (RLIM_INFINITY / (1<<30)) / BYTES_PER_WORD) {
			*new_coeffp = RLIM_INFINITY -1;
			*new_unitsp = (short) QLM_BYTES;
			return (1);
		}
		return (0);
	}
#else
#if	 HPUX | SGI | SOLARIS | SYS52 | IBMRS | LINUX
	/*
	 *  Unlike BSD4.3, DECOSF, and ULTRIX, we do not have to watch 
	 *  for infinity here.  However, if the limit, when expressed in bytes,
	 *  would be > 2**31 -1, then change it and return 1.
	 */
	if (infinite) {
		*new_coeffp = 2147483647L;
		*new_unitsp = (short) QLM_BYTES;
		return (1);
	}
	switch (units) {
	case QLM_BYTES:
		return (0);
	case QLM_WORDS:
		if (coeff > 2147483647L / BYTES_PER_WORD) {
			*new_coeffp = 2147483647L;
			*new_unitsp = (short) QLM_BYTES;
			return (1);
		}
		return (0);
	case QLM_KBYTES:
		if (coeff > 2147483647L / (1<<10)) {
			*new_coeffp = 2147483647L;
			*new_unitsp = (short) QLM_BYTES;
			return (1);
		}
		return (0);
	case QLM_KWORDS:
		if (coeff > 2147483647L / ((1<<10) * BYTES_PER_WORD)) {
			*new_coeffp = 2147483647L;
			*new_unitsp = (short) QLM_BYTES;
			return (1);
		}
		return (0);
	case QLM_MBYTES:
		if (coeff > 2147483647L / (1<<20)) {
			*new_coeffp = 2147483647L;
			*new_unitsp = (short) QLM_BYTES;
			return (1);
		}
		return (0);
	case QLM_MWORDS:
		if (coeff > 2147483647L / ((1<<20) * BYTES_PER_WORD)) {
			*new_coeffp = 2147483647L;
			*new_unitsp = (short) QLM_BYTES;
			return (1);
		}
		return (0);
	case QLM_GBYTES:
		if (coeff > 2147483647L / (1<<30)) {
			*new_coeffp = 2147483647L;
			*new_unitsp = (short) QLM_BYTES;
			return (1);
		}
		return (0);
	case QLM_GWORDS:
		if (coeff == 0) return (0);
		/*
		 * In the case of gigawords, we have to check
		 * for overflow.
		 */
		if (BYTES_PER_WORD > 1) {
			*new_coeffp = 2147483647L;
			*new_unitsp = (short) QLM_BYTES;
			return (1);
		}
		if (coeff > (2147483647L / (1<<30)) / BYTES_PER_WORD) {
			*new_coeffp = 2147483647L;
			*new_unitsp = (short) QLM_BYTES;
			return (1);
		}
		return (0);
	}
#else
BAD SYSTEM TYPE
#endif
#endif
}


/*** quolimlow
 *
 *
 *	int quolimlow ():
 *
 *	Given the coefficient and the units of a memory or disk
 *	resource limit, report whether the implied limit could be
 *	enforced on this machine. In determining whether the limit
 *	is too low, we must remember that some apparently finite
 *	limit values might have been usurped by the system call in
 *	question to mean "infinity". 
 *
 *	The limit shall be deemed to be too small if it is
 *	a small number and attempting to enforce it would
 *	result in an infinite limit, or would cause a batch request
 *	to fail in a way inscrutable to the user.
 *
 *	If the limit is ok, return 0. If the limit is too small,
 *	return 1 and assign the smallest enforceable limit
 *	to the designated variables.
 *
 *	We assume that the actual parameter "coeff" < 2**31.
 *	This is in line with scanquolim().
 */
int quolimlow (
	unsigned long coeff,		/* Coefficient of limit in question */
	short units,			/* Units of limit in question */
	int limit_type,			/* One of LIM_??? */
	unsigned long *new_coeffp,	/* Pointer to altered coefficient */
	short *new_unitsp)		/* Pointer to altered units */
{
	if (limit_type == LIM_PPPFILE) {
		/*
		 * Ulimit(2) claims to support the setting of values
		 * as low as zero bytes.  Here, however, we prevent
		 * the setting of any limit lower than 2048 bytes.
		 * The child of the shepherd process writes to the
		 * shepherd AFTER the call to ulimit().  A ulimit
		 * of less than 2048 bytes might result in the
		 * shepherd failing to get a completion message,
		 * or mail failing to get through.
		 */
		switch (units) {
		case QLM_BYTES:
			if (coeff < 2048) {
				*new_coeffp = 2048;
				*new_unitsp = QLM_BYTES;
				return (1);
			}
			return (0);
		case QLM_WORDS:
			if ((coeff * BYTES_PER_WORD) < 2048) {
				*new_coeffp = 2048;
				*new_unitsp = QLM_BYTES;
				return (1);
			}
			return (0);
		case QLM_KBYTES:
			if (coeff < 2) {
				*new_coeffp = 2048;
				*new_unitsp = QLM_BYTES;
				return (1);
			}
			return (0);
		case QLM_KWORDS:
			if ((coeff * BYTES_PER_WORD) < 2) {
				*new_coeffp = 2048;
				*new_unitsp = QLM_BYTES;
				return (1);
			}
			return (0);
		case QLM_MBYTES:
		case QLM_MWORDS:
		case QLM_GBYTES:
		case QLM_GWORDS:
			if (coeff == 0) {
				*new_coeffp = 2048;
				*new_unitsp = QLM_BYTES;
				return (1);
			}
			return (0);
		}
	}
	/*
	 *  Below, we handle limits OTHER than LIM_PPPFILE.
	 */
	/*
	 *  No problem of zero meaning infinity here.
	 */
	return (0);
}
