/*
 *========================================================================
 * $Id: update.c 88 2004-09-28 22:49:38Z rgb $
 *
 * See copyright in copyright.h and the accompanying file COPYING
 *========================================================================
 */

#include <wulfware/libwulf.h>

/*
 *========================================================================
 * This library routine does the following:
 *
 * For the host pointed to by hostptr, it
 *   a) Reads an xmlsysd return (initiated in the work loop) and
 * converts it into a newly created xmldoc and xpath.
 *
 *   b) Runs through all the possible state flags and read/parse out
 * the associated values for initialization or update/display.  All
 * the libwulf-based clients programs can operate parsimoniously in
 * terms of memory and network and processing requirements by
 * throttling xmlsysd and processing only tag sets that contain
 * variables actually needed for the current client display.
 *
 *   c) Destroys the xmldoc and xpath so we don't leak memory.
 *
 * Nuttin' to it.  Be sure to call init_values before update_values
 * on a newly connected hosts (and delay a hair) in order to get good
 * rates.
 *========================================================================
 */
void update_values(Host *hostptr)
{

 /* Loop indices */
 int i;

 if((verbose == D_ALL) || (verbose == D_UPDATE_VALUES)){
   fprintf(OUTFP,"D_UPDATE_VALUES: Starting update_values().  Use -v %d to focus.\n",D_UPDATE_VALUES);
   fprintf(OUTFP,"D_UPDATE_VALUES: host %s connected = %d fd = %ul\n",
     hostptr->hostname,hostptr->connected,hostptr->client_fd);
 }

 /* 
  * This won't exist if the host isn't connected, and there is no point
  * in doing ANYTHING with a disconnected host.  In many cases it will be
  * a redundant check as we try to call init_values only if a host is
  * known to be connected in the first place.
  *
  * Note that update_values() is typically called right AFTER a
  * send_command_to_all(commands[SEND]) command.  So we don't need to
  * do this here.
  */
 if( hostptr->connected == 2 && hostptr->client_fd ){

   /*
    * Receive the xmlsysd return, process it until we have a working
    * xpath entry for the remaining parsing.
    */
   create_xmlsysd_xpath(hostptr,update_buf);

   /*
    * IF we failed to get a functional xpath document for ANY REASON,
    * we MUST NOT EXECUTE THE FOLLOWING.  It kinda works, until is
    * returns a segment violation and dies horribly.  Like that.
    *
    * Note that we really do have to check twice -- once to see if it is
    * OK to even TRY to get the document and again to see if the
    * connection failed for any reason while getting the document.
    */
   if(hostptr->connected != 2) return;

   /*
    * EACH hostptr->dctl.flag corresponds to a throttleable xmlsysd tag and gets
    * a (possibly empty) section here.  We only update what we need, according
    * to EACH host's dctl state.  This is really boring code, but oh so
    * easy to understand and control and even extend with future tags.
    */

   /*
    * <identity> derived values
    */
   if(hostptr->dctl.identity){
     update_identity(hostptr);
   }

   /*
    * <time> derived values
    */
   if(hostptr->dctl.time){
     update_time(hostptr);
   }
      
   /*
    * <users> derived values
    */
   if(hostptr->dctl.users){
     update_users(hostptr);
   }
      
   /*
    * <cpuinfo> derived values
    */
   if(hostptr->dctl.cpuinfo){
     update_cpuinfo(hostptr);
   }

   /*
    * <loadavg> derived values
    */
   if(hostptr->dctl.loadavg){
     update_loadavg(hostptr);
   }

   /*
    * <meminfo> derived values
    */
   if(hostptr->dctl.meminfo){
     update_meminfo(hostptr);
   }

   /*
    * <net> derived values
    */
   if(hostptr->dctl.net){
     update_net(hostptr);
   }
      
   /*
    * <stat> derived values
    */
   if(hostptr->dctl.stat){
     update_stat(hostptr);
   }
      
   /*
    * <sysvipc> derived values (nothing to do)
    */
   if(hostptr->dctl.sysvipc){
     update_sysvipc(hostptr);
   }

   /*
    * <uptime> derived values
    */
   if(hostptr->dctl.uptime){
     update_uptime(hostptr);
   }

   /*
    * <version> derived values
    */
   if(hostptr->dctl.version){
     update_version(hostptr);
   }

   /*
    * <pids> derived values (in a linked list).
    */
   if(hostptr->dctl.pids){
     update_pids(hostptr);
   }

   /*
    * The very LAST thing we have to do is free the xpath context and 
    * xml doc for the host.  Otherwise this code will leak memory 
    * sieve-like.  Or worse, die horribly and without explanation.
    */
   if((verbose == D_ALL) || (verbose == D_UPDATE_VALUES)){
     fprintf(OUTFP,"D_UPDATE_VALUES: Freeing context %d\n",(int) hostptr->xp_doc);
   }
   /*
    * Receive the xmlsysd return, process it until we have a working
    * xpath entry for the remaining parsing.
    */
   destroy_xmlsysd_xpath(hostptr);

 } else {

   if((verbose == D_ALL) || (verbose == D_UPDATE_VALUES)){
     fprintf(OUTFP,"D_UPDATE_VALUES: Skipping host %s with connected = %d.\n",
       hostptr->hostname,hostptr->connected);
   }

 }

 if((verbose == D_ALL) || (verbose == D_UPDATE_VALUES)){
   fprintf(OUTFP,"D_UPDATE_VALUES: All done, exiting.\n");
 }

}


/*
 * Rewriting to use linked lists instead.
 */
void update_host_values(List *hostlist)
{

 Host *hostptr;
 ListElement *element;

 /*
  * Clear all host values (not really necessary here).
  */
 if((verbose == D_ALL) || (verbose == D_UPDATE_VALUES)){
   fprintf(OUTFP,"D_UPDATE_VALUES: Starting update_host_values().  Use -v %d to focus.\n",D_UPDATE_VALUES);
 }
 element = hostlist->head;
 while(element != NULL){
   hostptr = element->data;
   if(hostptr->client_fd && hostptr->connected == 2){
     if((verbose == D_ALL) || (verbose == D_UPDATE_VALUES)){
       fprintf(OUTFP,"D_UPDATE_VALUES: Updating values for host %s\n",hostptr->hostname);
     }
     update_values(hostptr);
   } else {
     if((verbose == D_ALL) || (verbose == D_UPDATE_VALUES)){
       fprintf(OUTFP,"D_UPDATE_VALUES: Skipping host %s, status = %d\n",hostptr->hostname,hostptr->connected);
     }
   }
   element = element->next;
 }
 if((verbose == D_ALL) || (verbose == D_UPDATE_VALUES)){
   fprintf(OUTFP,"D_UPDATE_VALUES: Finished.\n");
 }

}

