/*
 *========================================================================
 * $Id: wulfhosts.c 96 2006-07-20 17:56:16Z rgb $
 *
 * See copyright in copyright.h and the accompanying file COPYING
 *========================================================================
 */

#include <wulfware/libwulf.h>

/*
 * Initialize hostlists.
 */
void allocate_hostlists()
{
 /*
  * create the primary linked lists: hosts, users, tasks to track.
  * They will be filled in, primarily in read_wulfhosts and later
  * via the config interface.
  */
 hostlist = newlist();
 hosttaglist = newlist();
 hostrangelist = newlist();
 iprangelist = newlist();
 userlist = newlist();
 tasklist = newlist();

}

/*
 *========================================================================
 * read_wulfhosts(char *wulfhosts)
 *
 *   a) Opens wulfhosts, parses its xml contents, and creates an xmlXPath
 * pointer that can be used to access them.
 *   b) calls routines that parse out toplevel host tags and their contents,
 * e.g. <host>, <hostrange>, <iprange>
 *   c) calls routines that generate and validate hosts to be monitored
 * and add them to the main host linked list.
 *   d) call routines that parse out other toplevel tags to add to lists
 * (userlist, tasklist) or to set variables from.  These may or may not
 * be validated, depending on how complex they are or whether they CAN
 * be validated (some mistakes are just mistakes!).
 *
 * We are going to TRY to to write this so it can be called interactively
 * anytime during execution to add new nodes to be monitored or change
 * displays.
 *========================================================================
 */

int read_wulfhosts(char *hostfile)
{

 /* Generic loop indices, and node limit */
 int i,j,k,numnodes;

 /* xml (tree) objects */
 xmlDocPtr hostdoc;
 xmlNodePtr cur = NULL,root = NULL;
 /* xml (path) objects) */
 xmlXPathContextPtr xp_hostdoc = NULL;
 xmlXPathObjectPtr xp_op = NULL;

 /* To help decide if hostfile is goot */
 struct stat statbuf;

 /* To facilitate addition of hosts */
 Host *hostptr;
 Hosttag *hosttagptr;
 ListElement *element;

 if((verbose == D_ALL) || (verbose == D_READHOST)){
   fprintf(OUTFP,"D_READHOST: Starting read_wulfhosts().  Use -v %d to focus.\n",D_READHOST);
 }

 /*
  * This is an example of all the tags (and their required nesting)
  * that can occur in a wulfhosts file.  Note that tag VALUES can be
  * inconsistent (e.g. hostname may not correspond to hostip) in which
  * case unexpected things may happen.  Be warned.
  *
  * (Note:  Some of these are not yet supported in this development
  * version.  Ones that are should be transferred to the man page,
  * as a proper documentation of what works in the given snapshot.)
  *
  * <?xml version="1.0"?>
  * <wulfstat>
  *   <delay>5</delay>
  *   <pids all=1>
  *     <user>rgb</user>
  *     <user>bass</user>
  *     <task>On_spin3d</task>
  *     <uid>7887</uid>
  *   </pids>
  *   <iprange>
  *     <ipmin>192.168.1.129</ipmin>
  *     <ipmax>192.168.1.192</ipmax>
  *     <port>7882</port>
  *   </iprange>
  *   <hostrange>
  *     <hostfmt>b%02d</hostfmt>
  *     <imin>0</imin>
  *     <imax>15</imax>
  *     <port>7885</port>
  *   </hostrange>
  *   <host>
  *     <name>localhost</name>
  *     <ip>127.0.0.1</ip>
  *     <port>7887</port>
  *   </host>
  *   <host>
  *     <name>ganesh</name>
  *      ...
  *   </host>
  *   ...
  * </wulfstat>
  *
  */
 if(stat(hostfile,&statbuf) || localhosts_only){
   hostdoc = NULL;
   if((verbose == D_ALL) || (verbose == D_READHOST)){
     fprintf(OUTFP,"D_READHOST: Couldn't stat %s!\n",hostfile);
   }
   add_localhost();
   validate_hosttag(hosttaglist);
   return(1);
 } else {
   hostdoc = xmlParseFile(hostfile);
   if((verbose == D_ALL) || (verbose == D_READHOST)){
     fprintf(OUTFP,"D_READHOST: read and parsed %s.  About to extract root element.\n",hostfile);
   }
 }

 if((verbose == D_ALL) || (verbose == D_READHOST)){
   fprintf(OUTFP,"D_READHOST: Hostdoc is %x.\n",hostdoc);
 }
 /* in case something went wrong with read or parse */
 if(hostdoc == NULL){
   fprintf(OUTFP,"Warning: xml hostfile %s bad. Using localhost.\n",hostfile);
   add_localhost();
   validate_hosttag(hosttaglist);
   return(1);
 } else {
   root = xmlDocGetRootElement(hostdoc);
   /* if there is no root element */   
   if(root == NULL) {
     fprintf(OUTFP,"Warning: xml hostfile empty (no root element). Using localhost\n");
   } 
   /* if there is no root element */   
   if( strcasecmp((char*) root->name,"wulfstat") != 0 ) {
     fprintf(OUTFP,"Warning: hostfile root name = %s instead of wulfstat. Using localhost.\n",root->name);
   }
   /* So what did we get? */
   if((verbose == D_ALL) || (verbose == D_READHOST)){
     fprintf(OUTFP,"D_READHOST: Root element appears to be %s\n", root->name);
   }
 }


 /* 
  * If we get here, we have a valid xmlDoc parsed from the input hostfile.
  * We now need to extract its contents very much like we extract the
  * contents of the xml in the xmlsysd messages.  In some cases, we'll use
  * library routines from xml_xtract.c.  In others, we'll have to walk
  * the document to iteratively pull out a list of e.g. hosts.  Each host
  * must be validated and inserted into the linked list of hosts; each
  * other value (set) must be parsed and appropriate action taken (such
  * as building and validating a whole list of hosts at once and adding
  * them to the llist of hosts or just setting a control variable).
  *
  * To facilitate this, we break out separate routines to "validate" a
  * hostname/ip mapping and (maybe) ensure that it is unique (cannot enter 
  * hosts more than once).
  */

 if((verbose == D_ALL) || (verbose == D_READHOST)){
   fprintf(OUTFP,"D_READHOST: xmlParseFile imported %s from %s\n",root->name,hostfile);
   fprintf(OUTFP,"D_READHOST: Now to create a context for the xmlDoc.\n");
 }
 xp_hostdoc = xmlXPathNewContext(hostdoc);


 /*
  * parse out all <host> tags and add to hosttaglist (linked list)
  */
 parse_hosttag(xp_hostdoc);

 /*
  * parse out all <hostrange> tags and add to hostrangelist (linked list)
  */
 parse_hostrange(xp_hostdoc);

 /*
  * parse out all <iprange> tags and add to iprangelist (linked list)
  */
 parse_iprange(xp_hostdoc);

 /*
  * parse out all <task> tags and add them to tasklist (linked list)
  */
 parse_tasktag(xp_hostdoc);

 /*
  * parse out all <task> tags and add them to tasklist (linked list)
  */
 parse_usertag(xp_hostdoc);

 /*
  * parse out the <root> tag, if present, and if so turn on root_flag.
  */
 parse_roottag(xp_hostdoc);

 /*
  * validate and add all hosts defined by host tags in hosttaglist
  */
 validate_hosttag(hosttaglist);

 /*
  * validate and add all hosts defined by hostranges in hostrangelist
  */
 validate_hostrange(hostrangelist);

 /*
  * validate and add all hosts defined by ipranges in iprangelist
  */
 validate_iprange(iprangelist);

 /*
  * The hosts to be monitored should now be read in, validated, and 
  * inserted in the linked list of hosts.  
  *
  * We are done (we hope) with the xml
  * structs and don't want to needlessly leak memory.
  */
 if((verbose == D_ALL) || (verbose == D_READHOST)){
   fprintf(OUTFP,"D_READHOST: Free xp_op = %x\n",xp_op);
 }
 xmlXPathFreeObject(xp_op);
 if((verbose == D_ALL) || (verbose == D_READHOST)){
   fprintf(OUTFP,"D_READHOST: Free xp_hostdoc = %x\n",xp_hostdoc);
 }
 xmlXPathFreeContext(xp_hostdoc);
 if((verbose == D_ALL) || (verbose == D_READHOST)){
   fprintf(OUTFP,"D_READHOST: Free hostdoc = %x\n",hostdoc);
 }
 xmlFreeDoc(hostdoc);

 /*
  * At this point, all the hosts should be read in, parsed, and cleaned.
  * We print out the list for the sake of final debugging.  Note that this
  * one is accessible for either verbose == 11 or verbose == 12.
  */

 if((verbose == D_ALL) || (verbose == D_READHOST)){
   fprintf(OUTFP,"D_READHOST: Final version of hosts table:\n\n");
   fprintf(OUTFP,"D_READHOST:%5s  %-20s  %-16s %-8s  %-4s\n",
    "Host","hostname","host ip","binary ip","port");
   fprintf(OUTFP,"D_READHOST: ============================================================\n");
 }
 i = 0;
 element = hostlist->head;
 while(element != NULL){
   hostptr = element->data;
   if((verbose == D_ALL) || (verbose == D_READHOST)){
     fprintf(OUTFP,"D_READHOST:%5d  %-20s  %-16s  %08x  %4d\n",
       i,hostptr->hostname,hostptr->hostip,hostptr->inetaddress,hostptr->port);
   }
   i++;
   element = element->next;
 }
 return(i);

}

