static char dqs_c_qalter_rcsid[]="$Id: dqs_c_qalter.c,v 1.1.1.1 1998/08/18 14:39:10 green Exp $";

/*----------------------------------------------------
 * dqs_c_qalter.c Tom Green Thu Mar 31 16:32:42 EST 1994
 *
 * Copyright 1994
 *
 * 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_qalter.c,v $
 * Revision 1.1.1.1  1998/08/18 14:39:10  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.15  1996/11/20 23:03:13  nrl
 * Several fixes submitted by or as a result of investigations by
 * Ron Lee, Bodo Bechenback, Guntram Wolski and Frank Dwyyer.
 *
 * Revision 3.14  1996/06/27  01:55:40  nrl
 * changes to accomodate osf gcc
 *
 * Revision 3.13  1996/03/22  04:19:48  nrl
 * Added error cataloguing number to all routines
 *
 * Revision 3.12  1996/03/17  00:57:31  nrl
 * merge in qsub prevalidation scheme and consumable restoration
 *
 * Revision 3.11  1996/02/19  19:01:53  nrl
 * added a separate subpriority field, pluys scheduling_flags and
 * job_seq_number to remove the 3.1.2.4 kludges , modified the
 * scheduling algorith once again
 *
 * Revision 3.10  1996/01/14  22:26:23  nrl
 * Added job_status_info to contain detailed information about
 * the job status
 *
 * Revision 3.9  1995/06/21  16:57:31  nrl
 * Major scheduling changes... added a subpriority field to manage
 * things within the user submitted priority. Added priority info to the
 * accounting file.
 *
 * Revision 3.8  1995/05/29  18:08:46  nrl
 * More solaris stuff GAGGHH had to differentiate more cases of
 * solaris2.3 and solaris2.4 stuff
 *
 * Revision 3.7  1995/03/05  03:47:01  nrl
 * Included Axel Brandes job scheduling mechanism to keep one
 * user from hawging the queue.
 *
 * Revision 3.6  1995/02/22  14:29:19  nrl
 * added "FREE" macro to make sure all freed pointers are NULL,
 * replaced all calls to free( ) with FREE.
 *
 * Revision 3.5  1995/02/05  00:51:03  nrl
 * Changed meaning of "-clean" option to mean cleanout all
 * options potentially resettable by qalter. Added interactive
 * prompting.
 *
 * Revision 3.4  1994/08/02  23:11:07  green
 * added support for a crude job staging mechanism
 *
 * Revision 3.3  1994/06/04  14:54:56  green
 * added the variable "job->parallel_package"
 *
 * Revision 3.2  1994/06/03  00:25:49  green
 * replaced "DQSX_STR12" with "master_queue_exec_str" in support of MPI
 * mods
 *
 * Revision 3.1  1994/04/01  02:58:18  green
 * added "qalter" support
 *
 *
 *--------------------------------------------------*/


#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_qalter(sfd,request_head)
     int           sfd;
     dqs_list_type **request_head;
     
     /*
       dqs_c_qalter - is used solely by the qmaster and provides services
       to the qalter ancillary.
     */
     
{
  
  char               *cp;
  u_long32           i;
  string             str;
  int                cleanout;
  
  dqs_hash_type      *hashel_ptr;
  dqs_list_type      *listel_ptr;
  dqs_list_type      listel;
  dqs_list_type      *request_list;
  dqs_list_type      *reply_head=NULL;
  dqs_list_type      *lp;
  dqs_job_type       *job;
  dqs_job_type       *rjob;
  dqs_queue_type     *queue_ptr;
  struct sockaddr_in cli_addr;
  
  DENTER((DQS_EVENT,"dqs_c_qalter"));
  
  request_list= *request_head;
  
  if ((reply_head=dqs_locate_tid(request_list->tid)))
    {  /* this transaction has already occurred */ 
      INFO((DQS_EVENT,"DQS_ERROR_0034 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,"------------------------------------------------------"));
  bzero((char *)&listel,sizeof(listel));
  
  switch(request_list->int0)
    {
    case QALTER:
      DPRINTF((DQS_EVENT,"===>QALTER:"));
      job=dqs_locate_job(request_list->job->job_identifier_list->str0);
      if (!job) 
	{
	  sprintf(str,"error: %s could not locate jid \"%s\"",
		  request_list->user,request_list->job->job_identifier_list->str0);
	  ERROR((DQS_EVENT,"DQS_ERROR_0035 %s",str));
	  bzero((char *)&listel,sizeof(listel));
	  listel.status=DQS_NAK;
	  listel.str0=dqs_string_insert(NULL,str);
	  reply_head=dqs_insert(DQS_STR0,TAIL,reply_head,&listel);
	  reply_head->tid=request_list->tid;
	  request_list->tid=NULL;
	  break;
	}
      
      if (dqs_job_owner(request_list->user,request_list->job->job_identifier_list->str0))
	{
	  sprintf(str,"error: %s you are not the owner of \"%s\"",
		  request_list->user,request_list->job->job_identifier_list->str0);
	  ERROR((DQS_EVENT,"DQS_ERROR_0036 %s",str));
	  bzero((char *)&listel,sizeof(listel));
	  listel.status=DQS_NAK;
	  listel.str0=dqs_string_insert(NULL,str);
	  reply_head=dqs_insert(DQS_STR0,TAIL,reply_head,&listel);
	  reply_head->tid=request_list->tid;
	  request_list->tid=NULL;
	  break;
	}
      
      if (job->status==RUNNING)
	{
	  /* special case */
	  if(job->consumable_resources_used){
	    dqs_return_consumable(job,
				  job->consumable_resources_used->str0,
				  job->consumable_resources_used->int3);
	    break;
	    /* and may gawd have mercy on our cheatin' soul  */
	  }
	  
	  
	  sprintf(str,"error: %s you cannot alter a running job \"%s\"",
		  request_list->user,request_list->job->job_identifier_list->str0);
	  ERROR((DQS_EVENT,"DQS_ERROR_0037 %s",str));
	  bzero((char *)&listel,sizeof(listel));
	  listel.status=DQS_NAK;
	  listel.str0=dqs_string_insert(NULL,str);
	  reply_head=dqs_insert(DQS_STR0,TAIL,reply_head,&listel);
	  reply_head->tid=request_list->tid;
	  request_list->tid=NULL;
	  break;
	}
      
      if (request_list->job->clean) cleanout=1;
      else cleanout= 0;
      
      rjob=request_list->job;
      
      /*****************  Always provided by parse-job ************************/
      
      if (rjob->dqs_o_home)
        {
          job->dqs_o_home=dqs_string_insert(job->dqs_o_home,rjob->dqs_o_home);
        }
      if (rjob->dqs_o_log_name)
        {
          job->dqs_o_log_name=dqs_string_insert(job->dqs_o_log_name,rjob->dqs_o_log_name);
        }
      
      if (rjob->dqs_o_path)
        {
          job->dqs_o_path=dqs_string_insert(job->dqs_o_path,rjob->dqs_o_path);
        }
      
      if (rjob->dqs_o_mail)
        {
          job->dqs_o_mail=dqs_string_insert(job->dqs_o_mail,rjob->dqs_o_mail);
        }
      
      if (rjob->dqs_o_shell)
        {
          job->dqs_o_shell=dqs_string_insert(job->dqs_o_shell,rjob->dqs_o_shell);
        }
      
      if (rjob->dqs_o_tz)
        {
          job->dqs_o_tz=dqs_string_insert(job->dqs_o_tz,rjob->dqs_o_tz);
        }
      
      if (rjob->dqs_o_workdir)
        {
          job->dqs_o_workdir=dqs_string_insert(job->dqs_o_workdir,rjob->dqs_o_workdir);
        }
      
      if (rjob->dqs_o_host)
        {
          job->dqs_o_host=dqs_string_insert(job->dqs_o_host,rjob->dqs_o_host);
        }
      
      if (rjob->cell)
        {
          job->cell=dqs_string_insert(job->cell,rjob->cell);
	}
      
      
      /**********************************************************************/
      /**********   If clean flag then cleanout each item    ****************/
      /**********    based on type an relevancy to clean op  ****************/
      /**********************************************************************/
      
      if(cleanout) job->cwd= NULL;
      if (rjob->cwd)
        {
          job->cwd=dqs_string_insert(job->cwd,rjob->cwd);
        }
      
      if(cleanout) job->directive_prefix=dqs_string_insert(NULL,"#$");
      if (rjob->directive_prefix)
        {
	  job->directive_prefix=dqs_string_insert(job->directive_prefix,rjob->directive_prefix);
        }
      
      if(cleanout)
	job->stderr_path_list=dqs_free_list(job->stderr_path_list);
      if (rjob->stderr_path_list)
        {
          job->stderr_path_list=dqs_free_list(job->stderr_path_list);
	  job->stderr_path_list=rjob->stderr_path_list;
	  rjob->stderr_path_list=NULL;
        }
      
      if(cleanout) job->exec_list=dqs_free_list(job->exec_list);
      if (rjob->exec_list)
        {
          job->exec_list=dqs_free_list(job->exec_list);
          job->exec_list=rjob->exec_list;
          rjob->exec_list=NULL;
        }
      
      if(cleanout) job->send_msg_to_stderr= FALSE;  /*  qmsg only  */
      if (rjob->send_msg_to_stderr)
        {
          job->send_msg_to_stderr=rjob->send_msg_to_stderr;
        }
      
      if(cleanout) job->group_list=dqs_free_list(job->group_list);
      if (rjob->group_list)
        {
          job->group_list=dqs_free_list(job->group_list);
          job->group_list=rjob->group_list;
          rjob->group_list=NULL;
        }
      
      if(cleanout) CLEARBIT(HELD,job->state);
      if (rjob->hold)
        {
          SETBIT(HELD,job->state);
        }
      
      if(cleanout) job->merge_stderr=FALSE;
      if (rjob->merge_stderr)
        {
          job->merge_stderr=rjob->merge_stderr;
        }
      
      if(cleanout) KEEP_NONE;
      if (rjob->maint_local_output)
        {
          job->maint_local_output=rjob->maint_local_output;
        }
      
      /*****   Parse Job ensures that there is             *****************/
      /*****     least one hard or soft resource spcified  ****************/
      
      if(cleanout)
	job->hard_resource_list=dqs_free_list(job->hard_resource_list);
      if (rjob->hard_resource_list)
        {
          job->hard_resource_list=dqs_free_list(job->hard_resource_list);
          job->hard_resource_list=rjob->hard_resource_list;
          rjob->hard_resource_list=NULL;
        }
      
      if(cleanout)
	job->soft_resource_list=dqs_free_list(job->soft_resource_list);
      if (rjob->soft_resource_list)
        {
          job->soft_resource_list=dqs_free_list(job->soft_resource_list);
          job->soft_resource_list=rjob->soft_resource_list;
          rjob->soft_resource_list=NULL;
        }
      
      if(cleanout) job->mail_list=dqs_free_list(job->mail_list);
      if (rjob->mail_list)
        {
          job->mail_list=dqs_free_list(job->mail_list);
          job->mail_list=rjob->mail_list;
          rjob->mail_list=NULL;
        }
      
      if(cleanout) job->notify=FALSE;	       
      if (rjob->notify)
	{
          job->notify=rjob->notify;
        }
      
      /******    leave default job name alone  if cleaning house *************/
      if (rjob->job_name)
        {
          job->job_name=dqs_string_insert(job->job_name,rjob->job_name);
	}
      
      if(cleanout)
	job->stdout_path_list=dqs_free_list(job->stdout_path_list);
      if (rjob->stdout_path_list)
	{
          job->stdout_path_list=dqs_free_list(job->stdout_path_list);
          job->stdout_path_list=rjob->stdout_path_list;
          rjob->stdout_path_list=NULL;
	}
      
      if(cleanout) job->send_msg_to_stdout= FALSE;
      if (rjob->send_msg_to_stdout)
        {
          job->send_msg_to_stdout=rjob->send_msg_to_stdout;
        }
      
      if(cleanout) {
	job->priority=0;
	job->subpriority=0;
      }
      if (rjob->priority)
        {
          job->priority=rjob->priority ;
        }
      
      if(cleanout) job->priority_op=0;   /* unknown operation */
      if (rjob->priority_op)
        {
          job->priority_op=rjob->priority_op;
        }
      
      if(cleanout) job->passwd=0;
      if (rjob->passwd)
        {
          job->passwd=rjob->passwd;
        }
      
      if(cleanout) job->passwd_list=dqs_free_list(job->passwd_list);
      if (rjob->passwd_list)
        {
          job->passwd_list=dqs_free_list(job->passwd_list);
          job->passwd_list=rjob->passwd_list;
          rjob->passwd_list=NULL;
        }
      
      if(cleanout){
	FREE(job->Passwd);
      }
      if (rjob->Passwd)
        {
          job->Passwd=dqs_string_insert(job->Passwd,rjob->Passwd);
        }
      
      if(cleanout)job->hard_queue_list=dqs_free_list(job->hard_queue_list);
      if (rjob->hard_queue_list)
        {
          job->hard_queue_list=dqs_free_list(job->hard_queue_list);
          job->hard_queue_list=rjob->hard_queue_list;
          rjob->hard_queue_list=NULL;
	}
      
      if(cleanout)job->soft_queue_list=dqs_free_list(job->soft_queue_list);
      if (rjob->soft_queue_list)
	{
	  job->soft_queue_list=dqs_free_list(job->soft_queue_list);
	  job->soft_queue_list=rjob->soft_queue_list;
	  rjob->soft_queue_list=NULL;
	}
      
      if(cleanout)job->op_is_destin_id=0;   /* currently unused */
      if (rjob->op_is_destin_id)
	{
	  job->op_is_destin_id=rjob->op_is_destin_id;
	}
      
      if(cleanout)job->reauth_time=0;
      if (rjob->reauth_time)
	{
	  job->reauth_time=rjob->reauth_time;
	}
      
      if(cleanout)job->restart=FALSE;
      if (rjob->restart)
	{
	  job->restart=rjob->restart;
	}
      
      if(cleanout)job->states=0;        /* currently unused */
      if (rjob->states)
	{
	  job->states=rjob->states;
	}
      
      if(cleanout) job->signal= 0;
      if (rjob->signal)
	{
	  job->signal=rjob->signal;
	}
      
      if(cleanout)job->shell_list=dqs_free_list(job->shell_list);
      if (rjob->shell_list)
	{
	  job->shell_list=dqs_free_list(job->shell_list);
	  job->shell_list=rjob->shell_list;
	  rjob->shell_list=NULL;
	}
      
      if(cleanout)job->user_list=dqs_free_list(job->user_list);
      if (rjob->user_list)
	{
	  job->user_list=dqs_free_list(job->user_list);
	  job->user_list=rjob->user_list;
	  rjob->user_list=NULL;
	}
      
      if(cleanout)job->unlog=FALSE;
      if (rjob->unlog)
	{
	  job->unlog=rjob->unlog;
	}
      
      if(cleanout)job->variable_list=dqs_free_list(job->variable_list);
      if (rjob->variable_list)
	{
	  job->variable_list=dqs_free_list(job->variable_list);
	  job->variable_list=rjob->variable_list;
	  rjob->variable_list=NULL;
	}
      
      if(cleanout)job-> verify=FALSE;
      if (rjob->verify)
	{
	  job->verify=rjob->verify;
	}
      
      if(cleanout)job->env_list=dqs_free_list(job->env_list);        
      if (rjob->env_list)
	{
	  job->env_list=dqs_free_list(job->env_list);
	  job->env_list=rjob->env_list;
	  rjob->env_list=NULL;
	}
      
      if(cleanout) job->silent=FALSE;  
      if (rjob->silent)
	{
	  job->silent=rjob->silent;
	}
      
      if(cleanout)job->job_identifier_list=dqs_free_list(job->job_identifier_list);
      if (rjob->job_identifier_list)
	{
	  job->job_identifier_list=dqs_free_list(job->job_identifier_list);
	  job->job_identifier_list=rjob->job_identifier_list;
	  rjob->job_identifier_list=NULL;
	}
      
      if(cleanout) {
	job->script_size=0;
	job->script_ptr=dqs_free(job->script_ptr);
      }
      if (rjob->script_size)
	{
	  job->script_size=rjob->script_size;
	  job->script_ptr=dqs_free(job->script_ptr);
	  job->script_ptr=rjob->script_ptr;
	  rjob->script_ptr=NULL;
	}
      
      
      if(cleanout)job->srvr_nm_list=dqs_free_list(job->srvr_nm_list);  /* currently unused */
      if (rjob->srvr_nm_list)
	{
	  job->srvr_nm_list=dqs_free_list(job->srvr_nm_list);
	  job->srvr_nm_list=rjob->srvr_nm_list;
	  rjob->srvr_nm_list=NULL;
	}
      
      /* do not cleanout master queue name unless explicitly called out   */
      if (rjob->master_queue)
	{
	  job->master_queue=dqs_string_insert(job->master_queue,rjob->master_queue);
	}
      
      /* do not cleanout master queue name unless explicitly called out   */
      if (rjob->master_queue_exec_str)
	{
	  job->master_queue_exec_str=dqs_string_insert(job->master_queue_exec_str,rjob->master_queue_exec_str);
	}
      
      if(cleanout){
	FREE(job->DQSX_STR13);
      }
      if (rjob->DQSX_STR13)
	{
	  job->DQSX_STR13=dqs_string_insert(job->DQSX_STR13,rjob->DQSX_STR13);
	}
      
      if(cleanout){
	if(job->DQSX_STR14)free(job->DQSX_STR14);
	job->DQSX_STR14=NULL;
      }
      
      if (rjob->DQSX_STR14)
        {
	  job->DQSX_STR14=dqs_string_insert(job->DQSX_STR14,rjob->DQSX_STR14);
        }
      
      if(cleanout){
	if(job->DQSX_STR15)free(job->DQSX_STR15);
	job->DQSX_STR15=NULL;
      }
      if (rjob->DQSX_STR15)
	{
	  job->DQSX_STR15=dqs_string_insert(job->DQSX_STR15,rjob->DQSX_STR15);
	}
      
      if(cleanout)job->ext=FALSE;
      if (rjob->ext)
	{
	  job->ext=rjob->ext;
	}
      
      if (rjob->clean)
	{
	  job->clean=0;  /* used only to trigger QALTER clean  */
	}
      
      if(cleanout)job->parallel_package=0;
      if (rjob->parallel_package)
	{
	  job->parallel_package=rjob->parallel_package;
	}
      
      if(cleanout)job->scheduling_flags=0;
      if (rjob->scheduling_flags)
	{
	  job->scheduling_flags=rjob->scheduling_flags;
	}
      
      if(cleanout)job->schedule_seq_num=0;
      if (rjob->schedule_seq_num)
	{
	  job->scheduling_flags=rjob->schedule_seq_num;
	}
      
      if(cleanout)job->jid_hold_list=dqs_free_list(job->jid_hold_list);
      if (rjob->jid_hold_list)
	{
	  job->jid_hold_list=dqs_free_list(job->jid_hold_list);
	  job->jid_hold_list=rjob->jid_hold_list;
	  rjob->jid_hold_list=NULL;
	}
      
      if(cleanout)job->job_status_info=dqs_free_list(job->job_status_info);
      if (rjob->job_status_info)
	{
	  job->job_status_info=dqs_free_list(job->job_status_info);
	  job->job_status_info=rjob->job_status_info;
	  rjob->job_status_info=NULL;
	}
      
      if(cleanout)job->DQSX_L13=dqs_free_list(job->DQSX_L13);
      if (rjob->DQSX_L13)
	{
	  job->DQSX_L13=dqs_free_list(job->DQSX_L13);
	  job->DQSX_L13=rjob->DQSX_L13;
	  rjob->DQSX_L13=NULL;
	}
      
      if(cleanout)job->DQSX_L14=dqs_free_list(job->DQSX_L14);
      if (rjob->DQSX_L14)
	{
	  job->DQSX_L14=dqs_free_list(job->DQSX_L14);
	  job->DQSX_L14=rjob->DQSX_L14;
	  rjob->DQSX_L14=NULL;
	}
      
      if(cleanout)job->DQSX_L15=dqs_free_list(job->DQSX_L15);
      if (rjob->DQSX_L15)
	{
          job->DQSX_L15=dqs_free_list(job->DQSX_L15);
          job->DQSX_L15=rjob->DQSX_L15;
          rjob->DQSX_L15=NULL;
	}
      
      if(cleanout)job->invalid_destin_identifier_list=dqs_free_list(job->invalid_destin_identifier_list);
      if (rjob->invalid_destin_identifier_list)
	{
	  job->invalid_destin_identifier_list=dqs_free_list(job->invalid_destin_identifier_list);
	  job->invalid_destin_identifier_list=rjob->invalid_destin_identifier_list;
	  rjob->invalid_destin_identifier_list=NULL;
	}
      
      if(cleanout){
	FREE(job->machine);
      }
      if (rjob->machine)
	{
	  job->machine=dqs_string_insert(job->machine,rjob->machine);
	}
      INFO((DQS_EVENT,"DQS_ERROR_0038 %s just qaltered \"%s\"",
	    request_list->user,job->dqs_job_name));
      bzero((char *)&listel,sizeof(listel));
      listel.status=DQS_ACK;
      sprintf(str,"your job %d has been altered",job->job_number);
      listel.str0=dqs_string_insert(NULL,str);
      reply_head=dqs_insert(DQS_STR0,TAIL,reply_head,&listel);
      reply_head->tid=request_list->tid;
      request_list->tid=NULL;
      
      
      lp=dqs_locate_str0(Job_head,job->dqs_job_name);
      if (!lp)
	{
	  CRITICAL((DQS_EVENT,"DQS_ERROR_0039 error: botched tables"));
	  abort();
	}
      dqs_write_list_to_disk(JOB_DIR,lp->str0,lp,1);
      jobs_to_start=TRUE;
      break;
      
      /*------------------------------------------------------*/
    default:
      INFO((DQS_EVENT,"DQS_ERROR_0040 CASE unknown list type %d",request_list->type));
      listel.status=DQS_NAK;
      sprintf(str,"error: unknown list type %d",request_list->type);
      DPRINTF((DQS_EVENT,"%s",str));
      listel.str0=dqs_string_insert(NULL,str);
      reply_head=dqs_insert(DQS_STR0,TAIL,reply_head,&listel);
      
      *request_head=dqs_free_list(*request_head);
      dqs_save_tid(reply_head,QSUB);
      
      if ((sfd=dqs_send_list(NULL,NULL,sfd,reply_head))<0)
	{
	  DEXITE;
	  return;
	}
      
      dqs_close_sfd(sfd);
      
      DEXIT;
      return;
      break;
    }
}
