static char dqs_c_qmod_rcsid[]="$Id: dqs_c_qmod.c,v 1.1.1.1 1997/04/10 15:10:31 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  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);

}
