/*
 *	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.1   JRR     21-Oct-1993     Initial version.
*	V01.2	JRR	01-Mar-1994	Added support for SOLARIS.
*/
/*++ nqs_mov.c - Network Queueing System
 *
 * $Source: /usr2/jrroma/nqs/nqs-3.35.6/src/RCS/nqs_alterreq.c,v $
 *
 * DESCRIPTION:
 *
 *	Modify a non-running request.
 *
 *
 *	Author:
 *	-------
 *	John Roman,  Monsanto Company
 *	October 21, 1993.
 *
 *
 * STANDARDS VIOLATIONS:
 *   None.
 *
 * REVISION HISTORY: ($Revision: 1.2 $ $Date: 1994/03/30 20:36:27 $ $State: Exp $)
 * $Log: nqs_alterreq.c,v $
 * Revision 1.2  1994/03/30  20:36:27  jrroma
 * Version 3.35.6
 *
 * Revision 1.1  94/02/24  21:30:34  jrroma
 * Version 3.35.3
 * 
 * 
 *
 */

#include "nqs.h"			/* NQS constants and data types */
#include <string.h>
#include <time.h>
#include <errno.h>
#include "transactcc.h"			/* Transaction completion codes */
#include "nqsxvars.h"			/* Global vars */
#include "informcc.h"			/* NQS information completion */
					/* codes and masks */

/*** nqs_alterreq
 *
 *
 *	long nqs_alterreq():
 *	Modify a non-running NQS request.
 *
 *	Returns:
 *		TCML_COMPLETE:	 if the request was successfully
 *				 modified.
 *		TCML_NOSUCHQUE:	 if the specified queue does not
 *				 exist on this machine.
 *		TCML_NOSUCHREQ:	 if the specified request does not
 *				 exist on this machine.
 *		TCML_REQRUNNING: if the specified request is running.
 */
long nqs_alterreq (
	uid_t whomuid,		/* Calling user, else zero for */
				/* NQS operator/manager call  */
	int orig_seqno,		/* Request sequence number */
	Mid_t orig_mid,		/* Request machine id */
	int priority)		/* Priority to change request to */
{
	struct request *predecessor;	/* Predecessor in req set in queue */
	int state;			/* Request queue state: RQS_ */
	char path [MAX_PATHNAME+1];	/* Control file pathname */
	struct rawreq rawreq;		/* Raw request structure */
	int cfd;			/* Control file file-descriptor */
	struct request *req;		/* Request struct allocated for req */
	struct nqsqueue *queue;		/* The queue the request is in */
	int status;			/* Status from writereq */


	if (Debug > 2) {
	    printf ("D$nqs_alterreq().  whomuid=%d; seqno=%d; mid=%u; pri=%d\n",
			whomuid, orig_seqno, orig_mid, priority);
	    fflush (stdout);
	}
	/*
	 *  Locate the request.
	 */
	state = RQS_STAGING | RQS_QUEUED | RQS_WAITING | RQS_HOLDING
		| RQS_ARRIVING | RQS_DEPARTING | RQS_RUNNING;
	if ((req = nqs_fndreq (orig_seqno, orig_mid, &predecessor, &state)) ==
		    (struct request *) 0) {
	    return (TCML_NOSUCHREQ);	/* Request not found */
	}
	if ( (state == RQS_STAGING) || (state == RQS_HOLDING) ||
	    (state == RQS_ARRIVING) || (state == RQS_DEPARTING) || 
	    (state == RQS_RUNNING) ) {
				    /* if request not queued or waiting */
	    /*
	     *  The request is departing, staging output files,
	     *  running, or routing.  For now, we return TCML_REQRUNNING.
	     */
	    return (TCML_REQRUNNING);
	}
	queue = req->queue;
	/*
	 *  Build the control file name and open it.
	 */
	pack6name (path, Nqs_control,
		  (int) (orig_seqno % MAX_CTRLSUBDIRS), (char *) 0,
		  (long) orig_seqno, 5, (long) orig_mid, 6, 0, 0);
	if ((cfd = open (path, O_RDWR)) < 0) {
	    return (TCML_UNAFAILURE);
	}
	/*
	 *  Read the request header.
	 */
	if (Debug > 2) {
	    printf ("D$nqs_alterreq(): Read request (%s).\n", path);
	    fflush (stdout);
	}
	if (readreq (cfd, &rawreq) == -1) {
	    close (cfd);			/* Close request file */
	    return (TCML_UNAFAILURE);		/* Failure */
	}
	/*
	 *  The request has been located.  Remove the request from the
	 *  the containing queue and set the QUE_UPDATE bit.
	 */
	if (state == RQS_QUEUED) {
	    if (predecessor == (struct request *) 0) {
		req->queue->queuedset = req->next;
	    } else {
		predecessor->next = req->next;
	    }
	    req->queue->q.queuedcount--;
	    /*
	     * If this count is < 0 we have serious problems!
	     */
	    if (req->queue->q.queuedcount < 0) {
		close (cfd);
		printf("F$nqs_alterreq: Extraction caused queuedcount to go negative!\n");
		fflush(stdout);
		return(TCML_UNAFAILURE);
	    }
	} else {				 /* state = RQS_WAITING */
	    if (predecessor == (struct request *) 0) {
		req->queue->waitset = req->next;
	    } else {
		predecessor->next = req->next;
	    }
	    req->queue->q.waitcount--;
	    /*
	     * If this count is < 0 we have serious problems!
	     */
	    if (req->queue->q.waitcount < 0) {
		close (cfd);
		printf("F$nqs_alterreq: Extraction caused waitcount to go negative!\n");
		fflush(stdout);
		return(TCML_UNAFAILURE);
	    }
	}	
	req->next = (struct request *)0;	/* No more requests */
	req->queue->q.status |= QUE_UPDATE;
	req->v1.req.priority = (short) priority;
	rawreq.rpriority = (short) priority;
	status = writereq (cfd, &rawreq);
	if (status == -1) {
	    printf("I$nqs_alterreq: writereq failed with errno %d\n", errno);
	    fflush (stdout);
	}
	close (cfd);				/* Close request file */
	/*
	 *  Place the prioritized request back into the queue.
	 */
	if ((rawreq.flags & RQF_OPERHOLD) ||
	    (rawreq.flags & RQF_USERHOLD)) {
	    /*
	     *  Add the request to the hold set for this queue.
	     *  The QUE_UPDATE bit is set by a2s_a2hset().
	     */
	    a2s_a2hset (req, queue);/* Add to hold set */
	} else if (rawreq.start_time > time ((time_t *) 0)) {
	    /*
	     *  The request has a start time in the future.
	     *  The QUE_UPDATE bit is set by a2s_a2wset().
	     */
	    a2s_a2wset (req, queue);/* Add to wait set */
	} else {
	    /*
	     *  Place the request in the eligible to run set.
	     *  The QUE_UPDATE bit is set by a2s_a2qset().
	     */
	    a2s_a2qset (req, queue);/* Add to queued set */
	}
	switch (queue->q.type) {
	case QUE_BATCH:
	    bsc_spawn();		/* Maybe spawn some batch reqs */
	    break;
	case QUE_DEVICE:
	    dsc_spawn();		/* Maybe spawn some device reqs */
	    break;
	case QUE_PIPE:
	    psc_spawn();		/* Maybe spawn some pipe reqs */
	    break;
	}
	if (queue->q.status & QUE_UPDATE) {
	    /*
	     *  No requests were spawned from the queue in which
	     *  the most recent request was placed.
	     */
	    udb_qorder (queue);	/* Update and clear QUE_UPDATE bit */
	}
	return (TCML_COMPLETE);		/* Return transaction code */
}
