/*
 *	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.2   JRR     03-Mar-1992	Change mid_t to Mid_t.
*       V01.3   JRR     04-Mar-1992	Fix static references.
*       V01.4   JRR     17-Mar-1992	Fix known V2 problem.
*       V01.5   JRR     18-Mar-1992	Debug move request.
*	V01.6	JRR	17-Jun-1992	Added header.
*	V01.7	JRR	20-Nov-1992	Modified for C prototypes.
*/
/*++ mgr_movset.c - Network Queueing System
 *
 * $Source: /usr2/jrroma/nqs/nqs-3.30/src/RCS/mgr_movset.c,v $
 *
 * DESCRIPTION:
 *
 *	NQS manager "move set" execution module.
 *
 *	Author:
 *	------
 *	David G. Evans, Cray Research Inc.
 *	August 11th, 1986.
 *
 *
 * STANDARDS VIOLATIONS:
 *   None.
 *
 * REVISION HISTORY: ($Revision: 1.7 $ $Date: 1992/12/22 15:39:37 $ $State: Exp $)
 * $Log: mgr_movset.c,v $
 * Revision 1.7  1992/12/22  15:39:37  jrroma
 * Version 3.30
 *
 * Revision 1.6  92/06/18  17:30:40  jrroma
 * Added gnu header
 * 
 * Revision 1.5  92/03/20  10:57:59  jrroma
 * *** empty log message ***
 * 
 * Revision 1.4  92/03/17  13:21:38  jrroma
 * Fixed known V2 problem.
 * 
 * Revision 1.3  92/03/04  09:55:28  jrroma
 * Fixed static references.
 * 
 * Revision 1.2  92/03/03  17:17:16  jrroma
 * Changed mid_t to Mid_t.
 * 
 * Revision 1.1  92/03/03  17:15:27  jrroma
 * Initial revision
 * 
 * Revision 3.2  91/02/11  16:57:30  root
 * Version 2.0 Source
 * 
 * Revision 2.2  87/04/22  15:11:48  hender
 * Sterling version 4/22/87
 * 
 *
 */

#include "nqs.h"			/* NQS types and definitions */
#include "nqsmgr.h"			/* Token types and error messages */
#include "transactcc.h"			/* Transaction completion codes */

#ifndef __CEXTRACT__
#if __STDC__

static int cput_valid ( char *cput_string, long *cpu_secs, long *cpu_msecs, short *infinite );
static void modreq_problem ( int seq_num, Mid_t orig_hostid );
static void movreq_problem ( int seq_num, Mid_t orig_hostid, char *dest_qname );
static int quota_valid ( char *quota_string, long *quota_value1, long *quota_value2, short *infinite );

#else /* __STDC__ */

static int cput_valid (/* char *cput_string, long *cpu_secs, long *cpu_msecs, short *infinite */);
static void modreq_problem (/* int seq_num, Mid_t orig_hostid */);
static void movreq_problem (/* int seq_num, Mid_t orig_hostid, char *dest_qname */);
static int quota_valid (/* char *quota_string, long *quota_value1, long *quota_value2, short *infinite */);

#endif /* __STDC__ */
#endif /* __CEXTRACT__ */


/*** modreq_set
 *
 *
 *	void modreq_set():
 *
 *	Modfify a request identifier. The set of modifiers is defined
 *	by the scan_reqmodset() function which is used to scan/parse
 *	the qualifier set specification.
 */
void modreq_set(req_seqno, orig_hostid, whomuid)
int req_seqno;				/* Request sequence number */
Mid_t orig_hostid;			/* Originating machine identifier */
uid_t whomuid; 		                /* Calling user, else zero for */ 
                                        /*  NQS operator/manager call  */ 

{
	
	char *param_string;		/* Dequeued parameter string */
	long lim_type;			/* Request limit type - LIM_xxx */
	long param_value1;
	long param_value2;
	short param_infinite;
 
	short mssgflag = 0;		/* BOOLEAN TRUE if a message has /*
					/* been delivered to the user */
	register short exitflag = 0;	/* Exit flag */
	int qual_token;			/* Qualifier token */
	int comcode;			/* Completion code */

	while ((param_string = deq_set()) != NULL && !exitflag) {
		/*
		 *	Get qualifier type
		 */	
		qual_token = (int) deq_qual_type();
		/*
		 *	Analyze parameter value 
		 */
		switch (qual_token) {
		case 1:			/* Nice Value */
			param_value1 = atol (param_string);	
			if (param_value1 < (long) MIN_REQNICE || 
				param_value1 > (long) MAX_REQNICE) {
				errormessage (EM_NICEOUTOFBOU);
				break;
				}
			param_value2 = 0L;
			param_infinite = 0;
			lim_type = (long) LIM_PPNICE;
			break;
		case 2:			/* CPU time limit */
			if (cput_valid (param_string, &param_value1,
				&param_value2, &param_infinite)
				 == -1) return;
			lim_type = (long) LIM_PRCPUT;
			break;
		case 3:			/* Memory Limit */	
			if (quota_valid (param_string, &param_value1,
				&param_value2, &param_infinite)
				 == -1) return;
			lim_type = (long) LIM_PRMEM;
			break;
		}	
		/*
		 *	Send packet to NQS daemon
		 */
		comcode = (int) (modreq ( whomuid, req_seqno, orig_hostid,
 			lim_type, param_value1, param_value2, param_infinite));
		switch (comcode) {
		case TCML_INTERNERR:
		case TCML_NOESTABLSH:
		case TCML_NOLOCALDAE:
		case TCML_PROTOFAIL:
			modreq_problem (req_seqno,orig_hostid);
			diagnose (comcode);
			mssgflag = 1;
			exitflag = 1;		/* Exit */
			break;
		case TCML_COMPLETE:
			break;
		case TCML_NOSUCHREQ:
		case TCML_REQRUNNING:
			modreq_problem (req_seqno,orig_hostid);
			diagnose (comcode);
			mssgflag = 1;
			exitflag = 1;		/* Exit */
			break;
		default:
			modreq_problem (req_seqno,orig_hostid);
			diagnose (TCML_UNDEFINED);
			mssgflag = 1;
			exitflag = 1;		/* Exit */
		}
	}
	if (!mssgflag) diagnose (TCML_COMPLETE);
}


/*** modreq_problem
 *
 *
 *	void movreq_problem()
 *	Indicate problem modifying a request.
 */
static void modreq_problem (seq_num, orig_hostid)
int seq_num;			/* Sequence number */
Mid_t orig_hostid;			/* Request host machine id */
{
	show_failed_prefix();
	printf ("Problem modifying request: %d.%d\n",
		seq_num, orig_hostid);
}


/*** movreq_set
 *
 *
 *	void movreq_set():
 *
 *	Move reqset.  The set of reqids  (request ids) to move is
 *      defined by the scan_reqset() function which is used to      
 *	scan/parse a reqid set specification.
 */
void movreq_set (dest_qname)
char *dest_qname;			/* Destination queue name */
{
	long comcode;			/* Completion code */
	register short exitflag;	/* Exit flag */
	register short mssgflag;	/* BOOLEAN TRUE if a message has */
					/* been delivered to the user */
	register Mid_t orig_hostid;	/* Host machine-id of request */
	long seq_num;			/* Sequence number of request */

	/*
	 *  Loop to move requests to a specified queue
	 */

	mssgflag = 0;
	exitflag = 0;
	while (deq_set() != NULL && !exitflag) {
		/*      
		 * Perform the operation
		 */
		seq_num = deq_uid_gid();		/* Get sequence no. */
		if ((orig_hostid = deq_mid()) == -1)
			 orig_hostid = (Mid_t) localmid;	/* Get host id */
		/*
		 *  The request exists, as far as we can tell ...
		 */
		comcode = movreq ( seq_num, orig_hostid, dest_qname);
		switch (comcode) {
		case TCML_INTERNERR:
		case TCML_NOESTABLSH:
		case TCML_NOLOCALDAE:
		case TCML_PROTOFAIL:
			movreq_problem (seq_num,orig_hostid,dest_qname);
			diagnose (comcode);
			mssgflag = 1;
			exitflag = 1;		/* Exit */
			break;
		case TCML_COMPLETE:
			break;
		case TCML_NOSUCHQUE:
		case TCML_NOSUCHREQ:
		case TCML_QUEDISABL:
		case TCML_REQRUNNING:
		case TCML_WROQUETYP:
			movreq_problem (seq_num,orig_hostid,dest_qname);
			diagnose (comcode);
			mssgflag = 1;
			exitflag = 1;		/* Exit */
			break;
		default:
			movreq_problem (seq_num,orig_hostid,dest_qname);
			diagnose (TCML_UNDEFINED);
			mssgflag = 1;
			exitflag = 1;		/* Exit */
		}
	}
	if (!mssgflag) diagnose (TCML_COMPLETE);
}


/*** movreq_problem
 *
 *
 *	void movreq_problem()
 *	Indicate problem moving a request to another queue.
 */
static void movreq_problem (seq_num, orig_hostid, dest_qname)
int seq_num;			/* Sequence number */
Mid_t orig_hostid;		/* Request host machine id */
char *dest_qname;		/* Destination queue name */
{
	show_failed_prefix();
	printf ("Problem moving request: %d.%d; to queue %s.\n",
		seq_num, orig_hostid, dest_qname);
}
 

/*** cput_valid
 *
 *
 *	int cput_valid ():
 *
 *	Validate a CPU time limit quota.
 *
 *	Returns:
 *		 0: if scanning was successful.
 *		-1: otherwise.
 */
static int cput_valid (cput_string, cpu_secs, cpu_msecs, infinite)
register char *cput_string;
long *cpu_secs;
long *cpu_msecs;
short *infinite;
{
	struct cpulimit cpulim;
	struct cpulimit *cpulimit = &cpulim;

	*infinite = 0;					/* Finite value */
	if (*cput_string == 'u') {
		*cpu_secs = 0;			/* Give these fields */
		*cpu_msecs = 0;			/* values that will */
						/* pass integrity checks */
						/* checks */
		*infinite = 1;			/* Infinite */
	}
	else {
		switch (scancpulim (cput_string, cpulimit, 1)) {
		case 0:
			*cpu_secs = cpulimit->max_seconds;
			*cpu_msecs = cpulimit->max_ms;
			break;
		case -1:
			errormessage (EM_INVCPULIMSYN);
			return (-1);
		case -2:
			errormessage (EM_BADCPULIMVAL);
			return (-1);
		case -3:
			errormessage (EM_CPULIMEXP);
			return (-1);
		}
	}
	return(0);			/* Scanning successful */
}


/*** quota_valid
 *
 *
 *	int quota_valid
 *
 *	Validate a quota limit having nothing to do
 *		 with "nice" or cpu limits.
 *
 *	Returns:
 *		 0: if scanning was successful, and privileges are ok;
 *		-1: otherwise.
 */
static int quota_valid (quota_string, quota_value1, quota_value2, infinite)
register char *quota_string;
long *quota_value1;
long *quota_value2;
short *infinite;
{
	struct quotalimit quolim;
	struct quotalimit *quotalimit = &quolim;

	*infinite = 0;			/* Finite */
	if (*quota_string == 'u') {
		*quota_value1 = 0;		/* Give these fields */
		*quota_value2 = 0;		/* values that will */
						/* pass integrity */
						/* checks */
		*infinite = 1;			/* Infinite */
	}
	else {
		switch (scanquolim (quota_string, quotalimit, 1)) {
		case 0:
			*quota_value1 = quotalimit->max_quota;
			*quota_value2 = quotalimit->max_units;
			break;
		case -1:
			errormessage (EM_INVQUOLIMSYN);
			return (-1);
		case -2:
			errormessage (EM_BADQUOLIMVAL);
			return (-1);
		case -3:
			errormessage (EM_QUOLIMEXP);
			return (-1);
		}
	}
	return (0);			/* Scanning successful */
}				

