/*
 * libnqs/unwelcome/quolimok.c
 * 
 * WARNING:
 * 	Unless I get run over by a bus or something, I'll be shaking
 * 	my big stick at this code as the NEXT thing I do to Generic NQS,
 * 	and hopefully blowing this code away.
 * 
 * 	It pains me that I must leave this code as-is until 3.41.0 is
 * 	out as a working first pre-release.
 * 
 * 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.
 */

#include <libnqs/license.h>
#include <libnqs/proto.h>

#include <libsal/license.h>
#include <libsal/proto.h>
#include <libsal/defines.h>

/*** 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 */
	unsigned short ms,		/* Milliseconds part */
	unsigned short infinite,	/* Boolean */
	unsigned long *new_secsp,	/* Pointer to altered seconds value */
	unsigned short *new_msp)	/* Pointer to altered milliseconds */
{
 	if (infinite) return (0);
  
#if	SAL_LIMIT_GTIALLOWED
  	if (secs == ((SAL_LIMIT_INFINITY / SAL_CPU_DIVTOSEC)))
  	{
    	  *new_secsp = ((unsigned long) (SAL_LIMIT_INFINITY / SAL_CPU_DIVTOSEC)) + 1;
	  *new_msp   = 0;
#else
  	if (secs >= ((SAL_LIMIT_INFINITY / SAL_CPU_DIVTOSEC)))
  	{
	  *new_secsp = (SAL_LIMIT_INFINITY / SAL_CPU_DIVTOSEC) - 1;
	  *new_msp   = 0;
#endif
	  return 1;
	}
	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 */
	unsigned short ms,		/* Milliseconds part */
	unsigned long *new_secsp,	/* Pointer to altered seconds value */
	unsigned 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 */
{
  	unsigned long ulLimitValue;

  	/* if the number is infinity, nothing to do */
	if (infinite)
          return (0);

  	/* next step - convert the value to bytes */
	switch (units) 
  	{
	 case QLM_BYTES:
	  ulLimitValue = coeff;
	  break;
	 case QLM_WORDS:
	  /* not supported */
	  break;
	 case QLM_KBYTES:
	  ulLimitValue = coeff * 1024;
	  break;
	 case QLM_KWORDS:
	  /* not supported */
	  break;
	 case QLM_MBYTES:
	  ulLimitValue = coeff * 1024 * 1024;
	  break;
	 case QLM_MWORDS:
	  /* not supported */
	 case QLM_GBYTES:
	  ulLimitValue = coeff * 1024 * 1024 * 1024;
	  break;
	 default:
	  NEVER;
	}
  
  	/* 
	 * if the number equals infinity, we modify it to be slightly
	 * larger. We assume here that values greater than the infinity
	 * value are permitted.  This is the case for setrlimit() limits.
	 */
  
#if	SAL_LIMIT_GTIALLOWED
  	if (coeff == (SAL_LIMIT_INFINITY / SAL_BLOCK_DIVTOBYTE))
  	{
	  *new_coeffp = coeff+1;
	  *new_unitsp = QLM_BYTES;
#else
  	if (coeff >= (SAL_LIMIT_INFINITY / SAL_BLOCK_DIVTOBYTE))
  	{
	  *new_coeffp = (SAL_LIMIT_INFINITY / SAL_BLOCK_DIVTOBYTE);
	  *new_unitsp = QLM_BYTES;
#endif
	  return 1;
	}
  	return 0;
}


/*** 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:
		  	/* not supported */
			return (0);
		case QLM_KBYTES:
			if (coeff < 2) {
				*new_coeffp = 2048;
				*new_unitsp = QLM_BYTES;
				return (1);
			}
			return (0);
		case QLM_KWORDS:
		  	/* not supported */
			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);
}
