/*
 * nqsd/nqs_modreq.c
 * 
 * DESCRIPTION:
 *
 *	Modify a queued NQS request.
 *
 *	Original Author:
 *	-------
 *	Brent A. Kingsbury, Sterling Software Incorporated.
 *	October 8, 1985.
 */

#include <libnqs/license.h>
#include <libnqs/proto.h>
#include <errno.h>
#include <libnqs/transactcc.h>		/* Transaction completion codes */
#include <libnqs/nqsxvars.h>	        /* Global vars */

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

/*** nqs_modreq
 *
 *
 *	long nqs_modreq():
 *	Modify a queued NQS request.
 *
 *	Returns:
 *		TCML_COMPLETE:	 if the request was successfully
 *				 modified.
 *		TCML_NOSUCHREQ:	 if the specified request does not
 *				 exist on this machine.
 *		TCML_NOTREQOWN:	 if the mapped user-id does not
 *				 match the current mapped user-id
 *				 of the request owner.
 *		TCML_REQRUNNING: if the specified request is running.
 */
long nqs_modreq (
	uid_t mapped_uid,           /* Mapped owner user-id */
	long orig_seqno,            /* Original request sequence# */
	Mid_t orig_mid,             /* Original machine-id of req */
	long modtype,               /* Type of modification */
	long param1,                /* First modification parameter */
	long param2,                /* Second modification parameter */
	int inf)                    /* Set to infinite flag */
{
	struct request *predecessor;	/* Predecessor in req set in queue */
	int state;			/* Request queue state: RQS_ */
	struct request *req;		/* Ptr to request structure for */
					/* located req, if found */
        char path[MAX_PATHNAME+1];      /* pathname of control file */
        int cfd;                        /* file descriptor for control file */
        struct rawreq rawreq;           /* raw request structure */
        long    lim;                    /* New limit */


	/*
	 *  Locate the request.
	 */
	state = RQS_STAGING | RQS_QUEUED | RQS_WAITING | RQS_HOLDING
	      | RQS_ARRIVING | RQS_RUNNING;
        predecessor = (struct request *) 0;
	if ((req = nqs_fndreq (orig_seqno, orig_mid, &predecessor,
			       &state)) == (struct request *) 0) {
		/*
		 *  The request was not found in any of the local queues.
		 */
		return (TCML_NOSUCHREQ);
	}
        if (mapped_uid && req->v1.req.uid != mapped_uid) {
		/*
		 *  This request cannot be affected by the client.
		 */
		return (TCML_NOTREQOWN);
	}
        if (state == RQS_RUNNING) {
                return (TCML_REQRUNNING);
        }

        /*
         *  Make the requested modification.
         */
        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) {
                sal_dprintf(SAL_DEBUG_INFO, SAL_DEBUG_MSG_WARNING, "nqs_modreq(): Unable to open control file (%s). Errno = %d\n", path, errno);
                return (TCML_UNAFAILURE);
        }
        if (readreq(cfd, &rawreq) < 0) {
                close(cfd);
                sal_dprintf(SAL_DEBUG_INFO, SAL_DEBUG_MSG_WARNING, "nqs_modreq(): Read of request header failed.  Errno = %d\n", errno);
                return (TCML_UNAFAILURE);
        }

        /*
         *  Set the new limits.
         */
        rawreq.v.bat.infinite &= ~modtype;
        rawreq.v.bat.explicit |= modtype;
        if (inf) {                              /* if infinite flag set */
                rawreq.v.bat.infinite |= modtype;
        } else {
                switch (modtype) {
/* added cases for PPDATA and PPCPUT. Bruno Wolff 12/21/93 */
                case LIM_PPDATA:
                        rawreq.v.bat.ppdatasize.max_quota = param1;
                        rawreq.v.bat.ppdatasize.warn_quota = param1;
                        rawreq.v.bat.ppdatasize.max_units = param2;
                        rawreq.v.bat.ppdatasize.warn_units = param2;
                      break;
                case LIM_PPCPUT:
                        rawreq.v.bat.ppcputime.max_seconds = param1;
                        rawreq.v.bat.ppcputime.warn_seconds = param1;
                        rawreq.v.bat.ppcputime.max_ms = param2;
                        rawreq.v.bat.ppcputime.warn_ms = param2;
                      break;
                case LIM_PRMEM:
                        rawreq.v.bat.prmemsize.max_quota = param1;
                        rawreq.v.bat.prmemsize.warn_quota = param1;
                        rawreq.v.bat.prmemsize.max_units = param2;
                        rawreq.v.bat.prmemsize.warn_units = param2;
                        break;
                case LIM_PPNICE:
                        lim = rawreq.v.bat.ppnice;      /* get previous value */
                        rawreq.v.bat.ppnice = param1;
                        break;
                case LIM_PRCPUT:
                        rawreq.v.bat.prcputime.max_seconds = param1;
                        rawreq.v.bat.prcputime.warn_seconds = param1;
                        rawreq.v.bat.prcputime.max_ms = param2;
                        rawreq.v.bat.prcputime.warn_ms = param2;
                        break;
                default:
                        close(cfd);
                        return (TCML_NOSUCHQUO);
                }
        }
        if (writereq(cfd, &rawreq) < 0) {
                sal_dprintf(SAL_DEBUG_INFO, SAL_DEBUG_MSG_WARNING, "nqs_modreq(): Write of request header failed. Errno = %d\n", errno);
                close(cfd);
                return (TCML_UNAFAILURE);
        }
        close(cfd);

        return (TCML_COMPLETE);
}
