static char dqs_add_del_rcsid[]="$Id: dqs_add_del.c,v 1.3 1998/08/21 13:26:03 green Exp $";

/*----------------------------------------------------
 * dqs_add_del.c Tom Green Mon Jan 31 10:42:36 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_add_del.c,v $
 * Revision 1.3  1998/08/21 13:26:03  green
 *
 * ignore
 *
 * Revision 1.2  1998/08/18 15:58:35  green
 * *** empty log message ***
 *
 * Revision 1.1.1.1  1998/08/18 14:39:10  green
 * DQS 3.2.0.5 WIP Import
 *
 * Revision 1.2  1997/06/13 14:44:27  green
 * added Doug Gibson's patch to dqs_add_consumable() - incorrectly
 * intializing Consumable_hash
 *
 * Revision 1.1.1.1  1997/04/10 15:10:31  green
 * DQS 3.1.3.4.1 Distribution
 *
 * Revision 3.21  1996/08/26 14:20:48  nrl
 * Incorporated SCRI scheduling changes
 *
 * Revision 3.20  1996/08/03  14:08:52  nrl
 * fixed problem in qconf -mq where several fields were not getting
 * updated
 *
 * Revision 3.19  1996/06/27  01:55:38  nrl
 * changes to accomodate osf gcc
 *
 * Revision 3.18  1996/03/22  04:19:43  nrl
 * Added error cataloguing number to all routines
 *
 * Revision 3.17  1996/03/19  23:27:05  nrl
 * added capability to clean up consumable resources whenthey
 * get out of sync with reality
 *
 * Revision 3.16  1996/03/14  03:16:00  nrl
 * merge in subordinate queues and consumable resource changes
 *
 * Revision 3.15  1996/03/12  17:11:49  nrl
 * removed aborts and replaced with an error messaging scheme
 * to send email to the dqs adminsitrator and wait for
 * actions by that administrator
 *
 * Revision 3.14  1996/01/08  15:08:40  nrl
 * ooops.. introduced syntax error in last fix..repaired
 *
 * Revision 3.13  1995/10/28  18:38:27  nrl
 * fixed segmentation fault on hosts table
 *
 * Revision 3.12  1995/07/12  18:47:49  nrl
 * Fixed numerous problmes with Irix 5.3 and 6.0 systems
 *
 * Revision 3.11  1995/05/03  16:01:24  nrl
 * Fixed hostname wipeout problem
 *
 * Revision 3.10  1995/03/22  20:18:12  nrl
 * Fixed problem where modify queue was clobbering tmpdir and shell
 * variables.
 *
 * Revision 3.9  1995/02/24  23:36:04  nrl
 * Changed all Host lookups to use dqs_locate_host subroutine,
 * and changed that routine to look for the "registered host name"
 *
 * Revision 3.8  1995/02/22  14:29:16  nrl
 * added "FREE" macro to make sure all freed pointers are NULL,
 * replaced all calls to free( ) with FREE.
 *
 * Revision 3.7  1995/02/15  23:23:34  nrl
 * The primary name used for hostname in all handshaking and
 * in the hostshash and queue stuff is now the "official"
 * name delivered by gethostbyname. This should eliminate name
 * confusion between queues and hosts reporting in
 *
 * Revision 3.6  1995/02/15  12:43:38  nrl
 * Include priority with job_number as criteria for positioning job
 * to job list... suggested by a.brandes@tu-bs.de
 *
 * Revision 3.5  1995/02/09  22:44:07  nrl
 * Added "-mq" modify queue option
 *
 * Revision 3.4  1995/02/09  12:49:00  nrl
 * Added "delete complex" and "modify complex"
 *
 * Revision 3.3  1995/01/24  21:04:50  nrl
 * made changes to plug memory leaks and to complete the suspend
 * on completion function.
 *
 * Revision 3.2  1994/06/14  19:16:59  green
 * timestamp Host_head->int0 with GMT everytime a host is added/deleted.
 *
 * Revision 3.1  1994/06/04  17:45:06  green
 * fixed bug in "qconf -dh host_list"
 *
 * added additional error logging
 *
 * Revision 3.0  1994/03/07  04:13:12  green
 * 3.0 freeze
 *
 * Revision 1.3  1994/02/27  14:25:56  green
 * relaxed restrictions for resolving hosts for ancillaries.
 *
 * only qmaster hashes aliases now.
 *
 * Revision 1.2  1994/02/25  02:54:30  green
 * modified dqs_add_del.c to correct job ordering problem
 *
 * modified dqs_list.c to support ASCENDING on DQS_INT2 DQS_INT3
 *
 * modified dqs_load_avg.c in an attempt to fix CDs on VAX Ultrix -
 * by commenting out the offending code - this needs to be fixed...
 *
 * Revision 1.1.1.1  1994/02/01  17:57:37  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"

/*********************************************************************/
int dqs_add_host(h)
     char *h; 
     
     /*
       dqs_add_host - adds a host to the Host_list and to Host_hash
       
       if the invoking process is the qmaster the host list is
       spooled to disk 
       
       returns
       -1 if host already exists or other error;
       0  if successfull;
       1  if invalid hostname. 
       
     */
     
{
  
  int            i;
  struct hostent *hp;
  dqs_list_type  listel;
  string tmp_host;
  
  DENTER((DQS_EVENT,"dqs_add_host"));
  
  if (!Host_hash)
    Host_hash=dqs_hash_init();
  
  if (!h)
    {
      ERROR((DQS_EVENT,"DQS_ERROR_0002 error: NULL ptr passed to dqs_add_queue()"));
      DEXITE;
      return(-1);
    }
  
  
  hp=gethostbyname(h);          /* get official name   */
  if (!hp)
    {
      ERROR((DQS_EVENT,"DQS_ERROR_0003 error: invalid hostname \"%s\"",h));
      DEXITE;
      return(1);
    }
  
  strcpy(tmp_host,hp->h_name);
  if (!dqs_locate_host(tmp_host))
    {
      hp=gethostbyname(h);          /* get official name  AGAIN ! */
      
      dqs_hash_add(hp->h_name,Host_hash); /* register official name */
      if (me.who==QMASTER)
	{
	  if (hp->h_aliases)
	    for(i=0;hp->h_aliases[i];i++) 
	      {
		INFO((DQS_EVENT,"DQS_ERROR_0004 adding \"%s\" to Host_has as an alias for \"%s\"",hp->h_aliases[i],h));
		dqs_hash_add(hp->h_aliases[i],Host_hash);
	      }
	}
      
      bzero((char *)&listel,sizeof(listel));
      listel.str0=dqs_string_insert(NULL,h);
      Host_head=dqs_insert(DQS_STR0,ASCENDING,Host_head,&listel);
      if (me.who==QMASTER)
	dqs_write_list_to_disk(NULL,HOST_FILE,Host_head,ALL);
    }
  else
    {
      DEXITE;
      return(-1);
    }
  
  Host_head->int0=dqs_get_gmt();
  
  DEXIT;
  return(0);
  
}

/*********************************************************************/
int dqs_add_queue(q)
     dqs_queue_type *q; 
     
     /*
       dqs_add_queue - adds a queue to the Queue_list and to Queue_hash.
       
       if the respective host is not in Host_list/Host_hash calls dqs_add_host()
       
       if the invoking process is the qmaster the queue is spooled to disk.
       
       returns:
       -1 if queue already exists or other error;
       0 if successful;
       1 if invalid host associated with queue.
     */
     
{
  int i;
  dqs_list_type listel;
  dqs_list_type *err_rpt;
  dqs_list_type *lp;
  dqs_hash_type *hp;
  struct hostent *hent;     
  
  DENTER_EXT((DQS_EVENT,"dqs_add_queue"));
  
  if (!Queue_hash)
    Queue_hash=dqs_hash_init();
  
  if (!q)
    {
      ERROR((DQS_EVENT,"DQS_ERROR_0005 error: NULL ptr passed to dqs_add_queue()"));
      DEXITE;
      return(-1);
    }
  
  if (!q->state)
    { /* must be just adding queue */
      SETBIT(RUNNING,q->state);
      SETBIT(UNKNOWN,q->state);
    }
  
  if (dqs_add_host(q->qhostname)>0)
    {
      ERROR((DQS_EVENT,"DQS_ERROR_0006 error: invalid hostname associated with queue \"%s\"",
	     q->qname));
      DEXITE;
      return(1);
    }
  
  DTRACE;
  hp=dqs_hash_lookup(q->qname,Queue_hash);
  DTRACE;
  if (hp)
    {
      ERROR((DQS_EVENT,"DQS_ERROR_0007 error: the queue \"%s\" already exists",
	     q->qname));
      DEXITE;
      return(-1);
    }
  
  dqs_hash_add(q->qname,Queue_hash);
  
  bzero((char *)&listel,sizeof(listel));
  listel.str0=dqs_string_insert(NULL,q->qname);
  listel.queue=q;
  Queue_head=dqs_insert(DQS_STR0,ASCENDING,Queue_head,&listel);
  
  hent =gethostbyname(q->qhostname);
  if ((!hent)&&(me.who==QMASTER))
    {
      ERROR((DQS_EVENT,"DQS_ERROR_0008 error: invalid hostname \"%s\"",q->qhostname));
      DEXITE;
      return(1);
    }
  
  
  hp=dqs_hash_lookup(hent->h_name,Host_hash);
  /* last heard from always based on official host name */
  if (!hp)
    {
      CRITICAL((DQS_EVENT,"DQS_ERROR_0009 error: Host_hash is screwed"));
      DEXITE;
      err_rpt=(dqs_list_type *)dqs_malloc(sizeof(dqs_list_type));
      bzero((char *)&err_rpt,sizeof(err_rpt));
      err_rpt->next= &listel;
      err_rpt->str1= dqs_string_insert(NULL,
				       "host_hash is screwed ");
      dqs_report_problem(err_rpt, TRUE);      
      
      return (-1);
    }
  FREE(q->load_avg_ptr);
  q->load_avg_ptr=hp->load_avg_ptr;
  FREE(q->lt_heard_from_ptr);
  q->lt_heard_from_ptr=hp->lt_heard_from_ptr;
  
  hp=dqs_hash_lookup(q->qname,Queue_hash);
  if (!hp)
    {
      CRITICAL((DQS_EVENT,"DQS_ERROR_0010 error: Queue_hash is screwed"));
      DEXITE;
      err_rpt=(dqs_list_type *)dqs_malloc(sizeof(dqs_list_type));
      bzero((char *)&err_rpt,sizeof(err_rpt));
      err_rpt->next = &listel;
      err_rpt->str1= dqs_string_insert(NULL,
				       "queue hash is screwed ");
      dqs_report_problem(err_rpt, TRUE);      
      
      return(-1);
    }
  FREE(hp->vp);
  hp->vp=(char *)q;
  
  if (me.who==QMASTER)
    dqs_write_queue_to_disk(q);
  
  DEXIT;
  return(0);
  
}

/*********************************************************************/
/*********************************************************************/
int dqs_modify_queue(q)
     dqs_queue_type *q; 
     
     /*
       dqs_modify_queue - modify elements of the queue structure
       
       returns:
       -1 if  error;
       0 if successful;
       
     */
     
{
  int i;
  dqs_list_type listel;
  dqs_list_type *lp;
  dqs_queue_type *oq; 
  
  
  DENTER((DQS_EVENT,"dqs_modify_queue"));
  
  
  
  
  if (!q)
    {
      ERROR((DQS_EVENT,"DQS_ERROR_0011 error: NULL ptr passed to dqs_modify_queue()"));
      DEXITE;
      return(-1);
    }
  oq=dqs_locate_queue( q->qname);
  
  if(!oq){
    ERROR((DQS_EVENT,"DQS_ERROR_0012 error: cannot locate queue %s",q->qname));
    DEXITE;
    return(-1);
  }
  
  /* queue name and queue host will not be modified    */     
  
  oq->seq_no= q->seq_no;
  oq->load_massage= q->load_massage;
  oq->load_alarm= q->load_alarm;
  oq->priority= q->priority;
  oq->qtype= q->qtype;
  oq->rerun= q->rerun;
  oq->qty= q->qty;
  oq->tmpdir= dqs_string_insert(oq->tmpdir,q->tmpdir);
  oq->shell= dqs_string_insert(oq->shell,q->shell);
  oq->klog= dqs_string_insert(oq->klog,q->klog);
  oq->reauth_time= q->reauth_time;
  oq->notify= q->notify;
  oq->last_user_delay= q->last_user_delay;
  oq->max_user_jobs= q->max_user_jobs;
  
  oq->owner_list= dqs_free_list(oq->owner_list);
  oq->owner_list= dqs_replicate_list(q->owner_list,ALL);
  oq->acl= dqs_free_list(oq->acl);
  oq->acl= dqs_replicate_list(q->acl,ALL);
  oq->xacl= dqs_free_list(oq->xacl);
  oq->xacl= dqs_replicate_list(q->xacl,ALL);
  oq->subordinate_list= dqs_free_list(oq->subordinate_list);
  oq->subordinate_list= dqs_replicate_list(q->subordinate_list,ALL);
  oq->complex_list= dqs_free_list(oq->complex_list);
  oq->complex_list= dqs_replicate_list(q->complex_list,ALL);
  oq->consumables= dqs_free_list(oq->consumables);
  oq->consumables= dqs_replicate_list(q->consumables,ALL);
  
  oq->s_rt= q->s_rt;
  oq->h_rt= q->h_rt;
  oq->s_cpu= q->s_cpu;
  oq->h_cpu= q->h_cpu;
  oq->s_fsize= q->s_fsize;
  oq->h_fsize= q->h_fsize;
  oq->s_data= q->s_data;
  oq->h_data= q->h_data;
  oq->s_stack= q->s_stack;
  oq->h_stack= q->h_stack;
  oq->s_core= q->s_core;
  oq->h_core= q->h_core;
  oq->s_rss= q->s_rss;
  oq->h_rss= q->h_rss;
  
  
  
  
  if (me.who==QMASTER)
    dqs_write_queue_to_disk(oq);
  
  DEXIT;
  return(0);
  
}

/*********************************************************************/
int dqs_add_job(j)
     dqs_job_type *j;  
     
     /*
       
       dqs_add_job - adds a job to the Job_list and to Job_hash
       
       if the invoking process is the qmaster the job is spooled
       to disk.
       
       returns:
       -1 if job already exist;
       0  if successful
       1  on error
     */
     
{
  
  dqs_list_type *lp;
  dqs_list_type listel;
  dqs_list_type *err_rpt;
  dqs_hash_type *hp;
  
  DENTER_EXT((DQS_EVENT,"dqs_add_job"));
  
  if (!Job_hash)
    Job_hash=dqs_hash_init();
  
  if (!j)
    {
      ERROR((DQS_EVENT,"DQS_ERROR_0013 error: NULL ptr passed to dqs_add_job()"));
      DEXITE;
      return(1);
    }
  
  hp=dqs_hash_lookup(j->dqs_job_name,Job_hash);
  
  if (hp)
    {
      ERROR((DQS_EVENT,"DQS_ERROR_0014 error: the job \"%s\" already exists",
	     j->dqs_job_name));
      DEXITE;
      return(-1);
    }
  
  dqs_hash_add(j->dqs_job_name,Job_hash);
  bzero((char *)&listel,sizeof(listel));
  listel.str0=dqs_string_insert(NULL,j->dqs_job_name);
  if (me.who == QSTAT) {
    listel.int2 = (j->priority << 20) +
      (j->job_number & 0xfffff);
  } else {
    listel.int2=j->job_number;
  }               
  listel.int2=j->job_number;
  listel.job=j;
  Job_head=dqs_insert(DQS_INT2,ASCENDING,Job_head,&listel);
  
  hp=dqs_hash_lookup(j->dqs_job_name,Job_hash);
  if (!hp)
    {
      CRITICAL((DQS_EVENT,"DQS_ERROR_0015 error: Job_hash is screwed"));
      err_rpt=(dqs_list_type *)dqs_malloc(sizeof(dqs_list_type));
      bzero((char *)&err_rpt,sizeof(err_rpt));
      err_rpt->next= &listel;
      err_rpt->str1= dqs_string_insert(NULL,
				       "job hash is screwed ");
      dqs_report_problem(err_rpt, TRUE);      
      
      return(-1);
    }
  FREE( hp->vp);     
  hp->vp=(char *)j;
  
  if (me.who==QMASTER)
    dqs_write_list_to_disk(JOB_DIR,listel.str0,&listel,1);
  
  DEXIT;
  return(0);
  
}

/*********************************************************************/
int dqs_add_complex(c)
     dqs_list_type *c; 
     
     /*
       
       dqs_add_complex - adds an entry to the Complex_list and to Complex_hash
       
       if the invoking process is the qmaster the complex list is spooled
       to disk.
       
       returns:
       -1 if complex already exists;
       0  if successful
       1  on error
       
     */
     
{
  
  dqs_list_type *lp;
  dqs_list_type listel;
  dqs_list_type *err_rpt;
  dqs_hash_type *hp;
  
  DENTER((DQS_EVENT,"dqs_add_complex"));
  
  if (!Complex_hash)
    Complex_hash=dqs_hash_init();
  
  if (!c)
    {
      ERROR((DQS_EVENT,"DQS_ERROR_0016 error: NULL ptr passed to dqs_add_complex()"));
      DEXITE;
      return(1);
    }
  
  hp=dqs_hash_lookup(c->str0,Complex_hash);
  
  if (hp)
    {
      ERROR((DQS_EVENT,"DQS_ERROR_0017 error: the complex \"%s\" already exists",
	     c->str0));
      DEXITE;
      return(-1);
    }
  
  dqs_hash_add(c->str0,Complex_hash);
  
  bzero((char *)&listel,sizeof(listel));
  listel.str0=dqs_string_insert(NULL,c->str0);
  listel.chain=c->chain;
  c->chain=NULL;
  Complex_head=dqs_insert(DQS_STR0,ASCENDING,Complex_head,&listel);
  
  
  hp=dqs_hash_lookup(c->str0,Complex_hash);
  if (!hp)
    {
      CRITICAL((DQS_EVENT,"DQS_ERROR_0018 error: Complex_hash is screwed"));
      err_rpt=(dqs_list_type *)dqs_malloc(sizeof(dqs_list_type));
      bzero((char *)&err_rpt,sizeof(err_rpt));
      err_rpt->next= &listel;
      err_rpt->str1= dqs_string_insert(NULL,
				       "Complex Hash is screwed ");
      dqs_report_problem(err_rpt, TRUE);      
      
      return (-1);
    }
  
  lp=dqs_locate_str0(Complex_head,c->str0);
  hp->vp=(char *)lp;
  
  if (me.who==QMASTER)
    dqs_write_list_to_disk(NULL,COMPLEX_FILE,Complex_head,ALL);
  
  /*dqs_show_complex_list(Complex_head);*/
  
  DEXIT;
  return(0);
  
}

/*********************************************************************/
int dqs_replace_complex(c)
     dqs_list_type *c; 
     
     /*
       
       dqs_replace_complex - replaces modified Complex_list and in  Complex_hash
       
       if the invoking process is the qmaster the complex list is spooled
       to disk.
       
       returns:
       0  if successful
       1  on error
       
     */
     
{
  
  dqs_list_type *lp;
  dqs_list_type listel;
  dqs_hash_type *hp;
  
  DENTER((DQS_EVENT,"dqs_replace_complex"));
  
  
  if (!Complex_hash)
    Complex_hash=dqs_hash_init();
  
  if (!c)
    {
      ERROR((DQS_EVENT,"DQS_ERROR_0019 error: NULL ptr passed to dqs_modify_complex()"));
      DEXITE;
      return(1);
    }
  
  hp=dqs_hash_lookup(c->str0,Complex_hash);
  
  if (!hp)
    {
      ERROR((DQS_EVENT,"DQS_ERROR_0020 error: the complex \"%s\" doesn't exist",
	     c->str0));
      DEXITE;
      return(1);
    }
  
  bzero((char *)&listel,sizeof(listel));
  listel.str0=dqs_string_insert(NULL,c->str0);
  listel.chain=c->chain;
  c->chain=NULL;
  
  if( (Complex_head=dqs_del_str0(Complex_head, c->str0) )==NULL){
    DPRINTF((DQS_EVENT,"error: NULL ptr passed as Complex_head->str0()"));
    dqs_free_list(Complex_head);   /* try and start over   */
  }
  
  
  Complex_head=dqs_insert(DQS_STR0,ASCENDING,Complex_head,&listel);
  
  
  lp=dqs_locate_str0(Complex_head,c->str0);
  hp->vp=(char *)lp;                   /* replace hash pointer */
  
  if (me.who==QMASTER)
    dqs_write_list_to_disk(NULL,COMPLEX_FILE,Complex_head,ALL);
  
  /*dqs_show_complex_list(Complex_head);*/
  
  DEXIT;
  return(0);
  
}

/*********************************************************************/
int dqs_del_job(job_name)
     char *job_name;
     
     /*
       
       dqs_del_job - deletes a job from the Job_list and Job_hash
       and unlinks associated files.
       
       returns:
       -1 on error;
       0 if successful;
       
     */
     
{
  
  dqs_job_type *job;
  
  DENTER_EXT((DQS_EVENT,"dqs_del_job"));
  
  job=dqs_locate_job(job_name);
  if (!job)
    {
      ERROR((DQS_EVENT,"DQS_ERROR_0021 error: couldn't locate job \"%s\"",job_name));
      DEXITE;
      return(-1);
    }
  
  dqs_clear_granted_resources(job);
  unlink(job->job_file);
  unlink(job->exec_file);
  dqs_hash_del(job_name,Job_hash);
  Job_head=dqs_del_str0(Job_head,job_name);
  
  DEXIT;
  return(0);
  
}
/*********************************************************************/
int dqs_add_consumable(c)
     dqs_list_type *c; 
     
     /*
       
       dqs_add_consumable - adds an entry to the Consumable_list and to Consumable_hash
       
       if the invoking process is the qmaster the consumable list is spooled
       to disk.
       
       returns:
       -1 if consumable already exists;
       0  if successful
       1  on error
       
     */
     
{
  
  dqs_list_type *lp;
  dqs_list_type listel;
  dqs_list_type *err_rpt;
  dqs_hash_type *hp;
  
  DENTER((DQS_EVENT,"dqs_add_consumable"));
  
  if (!Consumable_hash)
    Consumable_hash=dqs_hash_init();
  
  if (!c)
    {
      ERROR((DQS_EVENT,"DQS_ERROR_0022 error: NULL ptr passed to dqs_add_complex()"));
      DEXITE;
      return(1);
    }
  
  hp=dqs_hash_lookup(c->str0,Consumable_hash);
  
  if (hp)
    {
      ERROR((DQS_EVENT,"DQS_ERROR_0023 error: the consumable \"%s\" already exists",
	     c->str0));
      DEXITE;
      return(-1);
    }
  
  dqs_hash_add(c->str0,Consumable_hash);
  
  bzero((char *)&listel,sizeof(listel));
  listel.str0=dqs_string_insert(NULL,c->str0);
  listel.chain=c->chain;
  c->chain=NULL;
  Consumable_head=dqs_insert(DQS_STR0,ASCENDING,Consumable_head,&listel);
  
  
  hp=dqs_hash_lookup(c->str0,Consumable_hash);
  if (!hp)
    {
      CRITICAL((DQS_EVENT,"DQS_ERROR_0024 error: Consumable_hash is screwed"));
      err_rpt=(dqs_list_type *)dqs_malloc(sizeof(dqs_list_type));
      bzero((char *)&err_rpt,sizeof(err_rpt));
      err_rpt->next= &listel;
      err_rpt->str1= dqs_string_insert(NULL,
				       "Consumable Hash is screwed ");
      dqs_report_problem(err_rpt, TRUE);      
      
      return (-1);
    }
  
  lp=dqs_locate_str0(Consumable_head,c->str0);
  hp->vp=(char *)lp;
  
  if (me.who==QMASTER)
    dqs_write_list_to_disk(NULL,CONSUMABLE_FILE,Consumable_head,ALL);
  
  DEXIT;
  return(0);
  
}

/*********************************************************************/
int dqs_replace_consumable(c)
     dqs_list_type *c; 
     
     /*
       
       dqs_replace_consumable - replaces modified Consuable_list and in  Consumable_hash
       
       if the invoking process is the qmaster the complex list is spooled
       to disk.
       
       returns:
       0  if successful
       1  on error
       
     */
     
{
  
  dqs_list_type *lp;
  dqs_list_type listel;
  dqs_hash_type *hp;
  string tstr;
  char *tptr;
  
  DENTER((DQS_EVENT,"dqs_replace_consumable"));
  
  
  if (!Consumable_hash)
    Consumable_hash=dqs_hash_init();
  
  if (!c)
    {
      ERROR((DQS_EVENT,"DQS_ERROR_0025 error: NULL ptr passed to dqs_modify_consumable()"));
      DEXITE;
      return(1);
    }
  strcpy(tstr,c->str0);
  tptr= strtok(tstr," \n");
  hp=dqs_hash_lookup(tstr,Consumable_hash);
  
  if (!hp)
    {
      ERROR((DQS_EVENT,"DQS_ERROR_0026 error: the consumable \"%s\" doesn't exist", tstr));
      DEXITE;
      return(1);
    }
  
  bzero((char *)&listel,sizeof(listel));
  listel.str0=dqs_string_insert(NULL,tstr);
  listel.chain=c->chain;
  c->chain=NULL;
  
  if( (Consumable_head=dqs_del_str0(Consumable_head, tstr) )==NULL){
    DPRINTF((DQS_EVENT,"error: NULL ptr passed as Consumable_head->str0()"));
    dqs_free_list(Consumable_head);   /* try and start over   */
  }
  
  
  Consumable_head=dqs_insert(DQS_STR0,ASCENDING,Consumable_head,&listel);
  
  
  lp=dqs_locate_str0(Consumable_head,tstr);
  hp->vp=(char *)lp;                   /* replace hash pointer */
  
  if (me.who==QMASTER)
    dqs_write_list_to_disk(NULL,CONSUMABLE_FILE,Consumable_head,ALL);
  DEXIT;
  return(0);
  
}

