static char dqs_c_qmod_rcsid[]="$Id: dqs_c_qmod.c,v 1.1.1.1 1998/08/18 14:39:11 green Exp $";

/*----------------------------------------------------
 * dqs_c_qmod.c Tom Green Mon Jan 31 10:42:39 1994
 *
 * Copyright 1993
 *
 * SUPER COMPUTER COMPUTATIONS RESEARCH INSTITUTE
 *            FLORIDA STATE UNIVERSITY
 *
 *
 * SCRI representatives make no claims about the
 * suitability of this software for any purpose.
 * It is provided "as is" without express or
 * implied warranty.
 *
 * $Log: dqs_c_qmod.c,v $
 * Revision 1.1.1.1  1998/08/18 14:39:11  green
 * DQS 3.2.0.5 WIP Import
 *
 * Revision 1.1.1.1  1997/04/10 15:10:31  green
 * DQS 3.1.3.4.1 Distribution
 *
 * Revision 3.10  1996/11/20 23:03:24  nrl
 * Several fixes submitted by or as a result of investigations by
 * Ron Lee, Bodo Bechenback, Guntram Wolski and Frank Dwyyer.
 *
 * Revision 3.9  1996/06/27  01:55:45  nrl
 * changes to accomodate osf gcc
 *
 * Revision 3.8  1996/06/17  02:28:42  nrl
 * Updtaes from Guntram Wolski, Ron Lee, John Makosky and
 * Bodo Beckebach
 *
 * Revision 3.7  1996/03/22  04:20:05  nrl
 * Added error cataloguing number to all routines
 *
 * Revision 3.6  1996/03/14  03:16:10  nrl
 * merge in subordinate queues and consumable resource changes
 *
 * Revision 3.5  1996/01/27  18:08:40  nrl
 * ensured that "tagged" field is cleared before leaving routine.
 * this bug caused qmod to leave so,e queueu tagged if qmpd
 * sent an illegal requset.
 *
 * Revision 3.4  1996/01/19  20:58:39  nrl
 * merged SCRI code and new job and queue structure changes
 *
 * Revision 3.3  1995/01/17  16:32:03  nrl
 * completed mailer feature
 *
 * Revision 3.2  1994/06/16  10:44:37  green
 * modidied dqs_signal_queue() to allow the same routines to be used for
 * "qmod" and "qdel".
 *
 * Revision 3.1  1994/03/24  19:04:43  green
 * had some static holdovers of DQS_EXECD_SERVICE that in reality should
 * have been conf.dqs_execd_service.
 *
 * Revision 3.0  1994/03/07  04:13:26  green
 * 3.0 freeze
 *
 * Revision 1.1.1.1  1994/02/01  17:57:38  green
 * DQS 3.0 ALPHA
 *
 *--------------------------------------------------*/


#include "h.h"
#include "def.h"
#include "dqs.h"
#include "struct.h"
#include "func.h"
#include "globals.h"
#include "dqs_errno.h"

/************************************************************************/
void dqs_c_qmod(sfd,request_head)
     int           sfd;
     dqs_list_type **request_head;
     
     /*
       dqs_c_qmod is used solely by the qmaster and provides services
       to the qmod ancillary.
     */
     
{
  
  int                found;
  int                status;
  char               *cp;
  u_long32           i;
  string             str;
  dqs_list_type      *lp;
  dqs_list_type      *lp2;
  dqs_list_type      listel;
  dqs_list_type      *request_list;
  dqs_list_type      *reply_head=NULL;
  dqs_queue_type     *queue_ptr;
  struct sockaddr_in cli_addr;
  
  DENTER((DQS_EVENT,"dqs_c_qmod"));
  
  request_list= *request_head;
  
  if ((reply_head=dqs_locate_tid(request_list->tid)))
    {  /* this transaction has already occurred */ 
      INFO((DQS_EVENT,"DQS_ERROR_0149 TRANSACTION ALREADY OCCURRED"));
      *request_head=dqs_free_list(*request_head);
      if ((sfd=dqs_send_list(NULL,NULL,sfd,reply_head))<0)
	{
	  DEXITE;
	  return;
	}
      dqs_close_sfd(sfd);
      DEXIT;
      return;
    }
  
  DPRINTF((DQS_EVENT,"------------------------------------------------------"));
  
  switch(request_list->type)
    {
    case SIGNAL_QUEUE_REQUEST:
      DPRINTF((DQS_EVENT,"===>QMOD:"));
      
      /* first lets make sure they have permission IFF a force is involved */
      if (request_list->job->force)
	{
	  if (dqs_operator(request_list->user))
	    {
	      NAK((ACK_EVENT,"error: \"%s\" - forcing a queue state requires manager/operator privilages",
		   request_list->user));
	      ERROR((DQS_EVENT,"DQS_ERROR_0150 %s",ACK_EVENT));
	      goto dqs_c_qmod_end;
	      break;
	      
	    }
	}
      
      
      /* now lets build a list of all suitable queues */
      lp=request_list->job->destin_identifier_list;
      while (lp)
	{
	  found=FALSE;
	  lp2=Queue_head;
	  while (lp2)
	    {
	      if (dqs_wildmat(lp->str0,lp2->queue->qname))
		{
		  lp2->queue->tagged=TRUE;
		  found=TRUE;
		}
	      lp2=lp2->next;
	    }
	  if (!found)
	    {
	      NAK((ACK_EVENT,"error: invalid queue \"%s\"",lp->str0));
	    }
	  
	  lp=lp->next;
	}
      lp=request_list->job->hard_resource_list;
      while (lp)
	{
	  INFO((DQS_EVENT,"DQS_ERROR_0151 TRACE"));
	  dqs_select_queues(lp->chain, NULL);
	  i=dqs_length_of_list(lp->chain);
	  lp2=Queue_head;
	  while (lp2)
	    {
	      INFO((DQS_EVENT,"DQS_ERROR_0152 TRACE"));
	      if (lp2->queue->suitable>=i)
		lp2->queue->tagged=TRUE;
	      lp2=lp2->next;
	    }
	  dqs_clear_suitability();
	  lp=lp->next;
	}
      
      /* all suitable queues should be "tagged" now */
      bzero((char *)&listel,sizeof(listel));
      listel.type=TRUE;
      lp=Queue_head;
      
      while (lp)
	{
	  if (!lp->queue->tagged)
	    {
	      lp=lp->next;
	      continue;
	    }
	  lp->queue->tagged= FALSE;
	  if ((dqs_owner(request_list->user,lp->queue->owner_list) != 0)
	      && (dqs_owner("ALL",lp->queue->owner_list) != 0))
	    
	    {
	      NAK((ACK_EVENT,"error: \"%s\" - you do not have permission to modify the queue \"%s\"",
		   request_list->user,lp->queue->qname));
	      WARNING((DQS_EVENT,"DQS_ERROR_0153 %s",ACK_EVENT));
	      break;
	    }
	  
	  switch(request_list->job->suspend_enable)
	    {
	    case ENABLED: /* a qmaster "local" state */
	      if (dqs_operator(request_list->user))
		{
		  NAK((ACK_EVENT,"error: %s - you do not have permission to enable the queue \"%s\"",
		       request_list->user,lp->queue->qname));
		  WARNING((DQS_EVENT,"DQS_ERROR_0154 %s",ACK_EVENT));
		  break;
		}
	      
	      if (VALID(ENABLED,lp->queue->state))
		{
		  NAK((ACK_EVENT,"warning: %s the queue \"%s\" is already enabled",
		       request_list->user,lp->queue->qname));
		  WARNING((DQS_EVENT,"DQS_ERROR_0155 %s",ACK_EVENT));
		  break;
		}
	      
	      CLEARBIT(DISABLED,lp->queue->state);
	      SETBIT(ENABLED,lp->queue->state);
	      dqs_write_queue_to_disk(lp->queue);
	      
	      ACK((ACK_EVENT,"the queue \"%s\" has been enabled by %s",
		   lp->queue->qname,request_list->user));
	      INFO((DQS_EVENT,"DQS_ERROR_0156 %s",ACK_EVENT));
	      break;
	      
	    case DISABLED: /* a qmaster "local" state */
	      if (dqs_operator(request_list->user))
		{
		  NAK((ACK_EVENT,"error: %s - you do not have permission to disable the queue \"%s\"",
		       request_list->user,lp->queue->qname));
		  WARNING((DQS_EVENT,"DQS_ERROR_0157 %s",ACK_EVENT));
		  break;
		}
	      
	      if (VALID(DISABLED,lp->queue->state))
		{
		  NAK((ACK_EVENT,"warning: %s the queue \"%s\" is already disabled",
		       request_list->user,lp->queue->qname));
		  WARNING((DQS_EVENT,"DQS_ERROR_0158 %s",ACK_EVENT));
		  break;
		}
	      
	      CLEARBIT(ENABLED,lp->queue->state);
	      SETBIT(DISABLED,lp->queue->state);
	      dqs_write_queue_to_disk(lp->queue);
	      
	      ACK((ACK_EVENT,"the queue \"%s\" has been disabled by %s",
		   lp->queue->qname,request_list->user));
	      INFO((DQS_EVENT,"DQS_ERROR_0159 %s",ACK_EVENT));
	      break;
	      
	    case SUSPEND_ON_COMP: /* a qmaster "local" state */
	      
	      if ((dqs_owner(request_list->user,lp->queue->owner_list) != 0)
		  && (dqs_owner("ALL",lp->queue->owner_list) != 0))
		{
		  NAK((ACK_EVENT,"error: %s - you do not have permission to soc the queue \"%s\"",
		       request_list->user,lp->queue->qname));
		  WARNING((DQS_EVENT,"DQS_ERROR_0160 %s",ACK_EVENT));
		  break;
		}
	      
	      if (VALID(SUSPEND_ON_COMP,lp->queue->state))
		{
		  NAK((ACK_EVENT,"warning: %s the queue \"%s\" is already marked as soc",
		       request_list->user,lp->queue->qname));
		  WARNING((DQS_EVENT,"DQS_ERROR_0161 %s",ACK_EVENT));
		  break;
		}
	      
	      SETBIT(SUSPEND_ON_COMP,lp->queue->state);
	      dqs_write_queue_to_disk(lp->queue);
	      
	      ACK((ACK_EVENT,"the queue \"%s\" has been marked soc by %s",
		   lp->queue->qname,request_list->user));
	      INFO((DQS_EVENT,"DQS_ERROR_0162 %s",ACK_EVENT));
	      listel.str0=dqs_string_insert(NULL,str);
	      reply_head=dqs_insert(DQS_STR0,TAIL,reply_head,&listel);
	      break;
	      
	      
	    case XSUSPEND_ON_COMP: /* a qmaster "local" state */
	      
	      if ((dqs_owner(request_list->user,lp->queue->owner_list) != 0)
		  && (dqs_owner("ALL",lp->queue->owner_list) != 0))
		{
		  NAK((ACK_EVENT,"error: %s - you do not have permission to xsuspend_on_comp the queue \"%s\"",
		       request_list->user,lp->queue->qname));
		  WARNING((DQS_EVENT,"DQS_ERROR_0163 %s",ACK_EVENT));
		  break;
		}
	      
	      if (!VALID(SUSPEND_ON_COMP,lp->queue->state))
		{
		  NAK((ACK_EVENT,"warning: %s the queue \"%s\" is not masked as suspend_on_comp",
		       request_list->user,lp->queue->qname));
		  WARNING((DQS_EVENT,"DQS_ERROR_0164 %s",ACK_EVENT));
		  break;
		}
	      
	      CLEARBIT(SUSPEND_ON_COMP,lp->queue->state);
	      dqs_write_queue_to_disk(lp->queue);
	      
	      ACK((ACK_EVENT,"%s has cancelled suspend_on_comp on the queue \"%s\"",
		   request_list->user,lp->queue->qname));
	      INFO((DQS_EVENT,"DQS_ERROR_0165 %s",ACK_EVENT));
	      break;
	      
	    case SUSPENDED:
	      
	      if ((dqs_owner(request_list->user,lp->queue->owner_list) != 0)
		  && (dqs_owner("ALL",lp->queue->owner_list) != 0))
		{
		  NAK((ACK_EVENT,"error: %s - you do not have permission to suspend the queue \"%s\"",
		       request_list->user,lp->queue->qname));
		  WARNING((DQS_EVENT,"DQS_ERROR_0166 %s",ACK_EVENT));
		  break;
		}
	      
	      if (VALID(SUSPENDED,lp->queue->state))
		{
		  if (request_list->job->force)
		    {
		      if (dqs_signal_queue(DQS_SIGSTOP,lp->queue,0))
			{
			  NAK((ACK_EVENT,"warning: %s unable to force a SUSPENDED state remote sync of the queue \"%s\"",
			       request_list->user,lp->queue->qname));
			  WARNING((DQS_EVENT,"DQS_ERROR_0167 %s",ACK_EVENT));
			}
		      else
			{
			  NAK((ACK_EVENT,"warning: %s forced a SUSPENDED state remote sync of the queue \"%s\"",
			       request_list->user,lp->queue->qname));
			  WARNING((DQS_EVENT,"DQS_ERROR_0168 %s",ACK_EVENT));
			}
		    }
		  else 
		    {   
		      NAK((ACK_EVENT,"warning: %s the queue \"%s\" is already suspended",
			   request_list->user,lp->queue->qname));
		      WARNING((DQS_EVENT,"DQS_ERROR_0169 %s",ACK_EVENT));
		    }
		  CLEARBIT(RUNNING,lp->queue->state); /* JIC */
		  SETBIT(SUSPENDED,lp->queue->state);
		  dqs_write_queue_to_disk(lp->queue);
		}
	      else
		{
		  if (request_list->job->force)
		    {
		      if (dqs_signal_queue(DQS_SIGSTOP,lp->queue,0))
			{
			  NAK((ACK_EVENT,"warning: %s unable to force a SUSPENDED state remote sync of the queue \"%s\"",
			       request_list->user,lp->queue->qname));
			  WARNING((DQS_EVENT,"DQS_ERROR_0170 %s",ACK_EVENT));
			}
		      else
			{
			  NAK((ACK_EVENT,"warning: %s forced a SUSPENDED state remote sync of the queue \"%s\"",
			       request_list->user,lp->queue->qname));
			  INFO((DQS_EVENT,"DQS_ERROR_0171 %s",ACK_EVENT));
			}
		      CLEARBIT(RUNNING,lp->queue->state);
		      SETBIT(SUSPENDED,lp->queue->state);
		      dqs_write_queue_to_disk(lp->queue);
		    }
		  else
		    {
		      if (dqs_signal_queue(DQS_SIGSTOP,lp->queue,0))
			{
			  NAK((ACK_EVENT,"warning: %s unable to sync suspend of the queue \"%s\"",
			       request_list->user,lp->queue->qname));
			  WARNING((DQS_EVENT,"DQS_ERROR_0172 %s",ACK_EVENT));
			}
		      else
			{
			  ACK((ACK_EVENT,"%s has suspended the queue \"%s\"",
			       request_list->user,lp->queue->qname));
			  INFO((DQS_EVENT,"DQS_ERROR_0173 %s",ACK_EVENT));
			  CLEARBIT(RUNNING,lp->queue->state);
			  SETBIT(SUSPENDED,lp->queue->state);
			  dqs_write_queue_to_disk(lp->queue);
			}
		    }
		}
	      break;
	      
	      
	      
	    case RUNNING:
	      if ((dqs_owner(request_list->user,lp->queue->owner_list) != 0)
		  && (dqs_owner("ALL",lp->queue->owner_list) != 0))
		{
		  NAK((ACK_EVENT,"error: %s - you do not have permission to unsuspend the queue \"%s\"",
		       request_list->user,lp->queue->qname));
		  WARNING((DQS_EVENT,"DQS_ERROR_0174 %s",ACK_EVENT));
		  break;
		}
	      
	      if (VALID(RUNNING,lp->queue->state))
		{
		  if (request_list->job->force)
		    {
		      if (dqs_signal_queue(DQS_SIGCONT,lp->queue,0))
			{
			  NAK((ACK_EVENT,"warning: %s unable to force a RUNNING state remote sync of the queue \"%s\"",
			       request_list->user,lp->queue->qname));
			  WARNING((DQS_EVENT,"DQS_ERROR_0175 %s",ACK_EVENT));
			}
		      else
			{
			  NAK((ACK_EVENT,"warning: %s forced a RUNNING state remote sync of the queue \"%s\"",
			       request_list->user,lp->queue->qname));
			  WARNING((DQS_EVENT,"DQS_ERROR_0176 %s",ACK_EVENT));
			}
		    }
		  else 
		    {   
		      NAK((ACK_EVENT,"warning: %s the queue \"%s\" is already running",
			   request_list->user,lp->queue->qname));
		      WARNING((DQS_EVENT,"DQS_ERROR_0177 %s",ACK_EVENT));
		    }
		  CLEARBIT(SUSPENDED,lp->queue->state); /* JIC */
		  CLEARBIT(SUBORDINATED,lp->queue->state); /* JIC */                              
		  SETBIT(RUNNING,lp->queue->state);
		  dqs_write_queue_to_disk(lp->queue);
		}
	      else
		{
		  if (request_list->job->force)
		    {
		      if (dqs_signal_queue(DQS_SIGCONT,lp->queue,0))
			{
			  NAK((ACK_EVENT,"warning: %s unable to force a RUNNING state remote sync of the queue \"%s\"",
			       request_list->user,lp->queue->qname));
			  WARNING((DQS_EVENT,"DQS_ERROR_0178 %s",ACK_EVENT));
			}
		      else
			{
			  NAK((ACK_EVENT,"warning: %s forced a RUNNING state remote sync of the queue \"%s\"",
			       request_list->user,lp->queue->qname));
			  INFO((DQS_EVENT,"DQS_ERROR_0179 %s",ACK_EVENT));
			}
		      CLEARBIT(SUBORDINATED,lp->queue->state); 
		      CLEARBIT(SUSPENDED,lp->queue->state);
		      SETBIT(RUNNING,lp->queue->state);
		      dqs_write_queue_to_disk(lp->queue);
		    }
		  else
		    {
		      if (dqs_signal_queue(DQS_SIGCONT,lp->queue,0))
			{
			  NAK((ACK_EVENT,"warning: %s unable to sync unsuspended state of the queue \"%s\"",
			       request_list->user,lp->queue->qname));
			  WARNING((DQS_EVENT,"DQS_ERROR_0180 %s",ACK_EVENT));
			}
		      else
			{
			  ACK((ACK_EVENT,"%s has unsuspended the queue \"%s\"",
			       request_list->user,lp->queue->qname));
			  INFO((DQS_EVENT,"DQS_ERROR_0181 %s",ACK_EVENT));
			  CLEARBIT(SUBORDINATED,lp->queue->state);
			  CLEARBIT(SUSPENDED,lp->queue->state);
			  SETBIT(RUNNING,lp->queue->state);
			  dqs_write_queue_to_disk(lp->queue);
			}
		    }
		}
	      break;
	      
	    default:
	      NAK((ACK_EVENT,"error: unknown qmod action request %d",request_list->job->suspend_enable));
	      INFO((DQS_EVENT,"DQS_ERROR_0182 %s",ACK_EVENT));
	      break;
	      
	    }
	  lp->queue->tagged=FALSE;
	  lp=lp->next;
	}
      if (!reply_head)
	{
	  NAK((ACK_EVENT,"error: no suitable queues"));
	}
      break;
      
      /*------------------------------------------------------*/
    default:
      NAK((ACK_EVENT,"error: unknown list type %d",request_list->type));
      INFO((DQS_EVENT,"DQS_ERROR_0183 %s",ACK_EVENT));
      break;
    }
  
 dqs_c_qmod_end:
  
  reply_head->tid=request_list->tid;
  dqs_save_tid(reply_head,QMOD);
  request_list->tid=NULL;
  
  *request_head=dqs_free_list(*request_head);
  
  if ((sfd=dqs_send_list(NULL,NULL,sfd,reply_head))<0)
    {
      DEXITE;
      return;
    }
  
  dqs_close_sfd(sfd);
  
  DEXIT;
  return;
  
}

/************************************************************************/
int dqs_signal_queue(how,queue,job_number)
     int            how;
     dqs_queue_type *queue;
     int            job_number;
{
  
  int              sfd=0;
  dqs_job_type     *job;
  dqs_list_type    listel;
  dqs_list_type    *lp;
  char dqs_mail_subj[1024];
  char dqs_mail_body[1024];
  dqs_list_type *mail_users;
  int            mail_options;
  
  DENTER((DQS_EVENT,"dqs_signal_queue"));
  
  if (!queue->qty_active)
    {
      DEXIT;
      return(0);
    }
  
  bzero((char *)&listel,sizeof(listel));
  listel.type=SIGNAL_QUEUE_REQUEST;
  listel.int0=how;
  listel.int1=job_number;
  listel.str0=queue->qname;
  
  if ((sfd=dqs_send_list(queue->qhostname,conf.dqs_execd_service,sfd,&listel))<0)
    {
      dqs_close_sfd(sfd);
      ERROR((DQS_EVENT,"DQS_ERROR_0184 error: unable to update remote queue state(%d) on queue \"%s\"",
	     how,queue->qname));
      DEXITE;
      return(-1);
    }
  
  if (dqs_get_list(sfd,&lp))
    {
      dqs_close_sfd(sfd);
      DPRINTF((DQS_EVENT,"lost connection - unable to obtain list"));
      DEXITE;
      return(-1);
    }
  
  dqs_close_sfd(sfd);
  
  lp=dqs_free_list(lp);
  
  lp=queue->job_list;
  while (lp)
    {
      job=dqs_locate_job(lp->str0);
      if (job)
	{
	  if (how==DQS_SIGCONT)
	    {
	      CLEARBIT(SUSPENDED,job->state);
	      SETBIT(RUNNING,job->state);
	    }
	  else if (how==DQS_SIGSTOP)
	    {
	      CLEARBIT(RUNNING,job->state);
	      SETBIT(SUSPENDED,job->state);
	      /*   send mail to users if requested                  */
	      mail_users= job->mail_list;
	      mail_options= job->mail_options;
              if ( VALID(MAIL_AT_SUSPENSION ,mail_options)){
              	sprintf(dqs_mail_subj,"Job %d Suspended",job->job_number);
		sprintf(dqs_mail_body,"Job %d Suspended",job->job_number);
		dqs_mail(mail_users,dqs_mail_subj, dqs_mail_body);
              }
	      
	    }
	  dqs_write_job_to_disk(job);
	}
      lp=lp->next;
    }
  
  DEXIT;
  return(0);
  
}
