/*
*         OpenPBS (Portable Batch System) v2.3 Software License
*
* Copyright (c) 1999-2000 Veridian Information Solutions, Inc.
* All rights reserved.
*
* ---------------------------------------------------------------------------
* For a license to use or redistribute the OpenPBS software under conditions
* other than those described below, or to purchase support for this software,
* please contact Veridian Systems, PBS Products Department ("Licensor") at:
*
*    www.OpenPBS.org  +1 650 967-4675                  sales@OpenPBS.org
*                        877 902-4PBS (US toll-free)
* ---------------------------------------------------------------------------
*
* This license covers use of the OpenPBS v2.3 software (the "Software") at
* your site or location, and, for certain users, redistribution of the
* Software to other sites and locations.  Use and redistribution of
* OpenPBS v2.3 in source and binary forms, with or without modification,
* are permitted provided that all of the following conditions are met.
* After December 31, 2001, only conditions 3-6 must be met:
*
* 1. Commercial and/or non-commercial use of the Software is permitted
*    provided a current software registration is on file at www.OpenPBS.org.
*    If use of this software contributes to a publication, product, or
*    service, proper attribution must be given; see www.OpenPBS.org/credit.html
*
* 2. Redistribution in any form is only permitted for non-commercial,
*    non-profit purposes.  There can be no charge for the Software or any
*    software incorporating the Software.  Further, there can be no
*    expectation of revenue generated as a consequence of redistributing
*    the Software.
*
* 3. Any Redistribution of source code must retain the above copyright notice
*    and the acknowledgment contained in paragraph 6, this list of conditions
*    and the disclaimer contained in paragraph 7.
*
* 4. Any Redistribution in binary form must reproduce the above copyright
*    notice and the acknowledgment contained in paragraph 6, this list of
*    conditions and the disclaimer contained in paragraph 7 in the
*    documentation and/or other materials provided with the distribution.
*
* 5. Redistributions in any form must be accompanied by information on how to
*    obtain complete source code for the OpenPBS software and any
*    modifications and/or additions to the OpenPBS software.  The source code
*    must either be included in the distribution or be available for no more
*    than the cost of distribution plus a nominal fee, and all modifications
*    and additions to the Software must be freely redistributable by any party
*    (including Licensor) without restriction.
*
* 6. All advertising materials mentioning features or use of the Software must
*    display the following acknowledgment:
*
*     "This product includes software developed by NASA Ames Research Center,
*     Lawrence Livermore National Laboratory, and Veridian Information
*     Solutions, Inc.
*     Visit www.OpenPBS.org for OpenPBS software support,
*     products, and information."
*
* 7. DISCLAIMER OF WARRANTY
*
* THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT
* ARE EXPRESSLY DISCLAIMED.
*
* IN NO EVENT SHALL VERIDIAN CORPORATION, ITS AFFILIATED COMPANIES, OR THE
* U.S. GOVERNMENT OR ANY OF ITS AGENCIES BE LIABLE FOR ANY DIRECT OR INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This license will be governed by the laws of the Commonwealth of Virginia,
* without reference to its choice of law rules.
*/

#include <pbs_config.h>   /* the master config generated by configure */

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>

/* local headers */
#include "portability.h"
#include "af.h"
#include "af_cnode.h"
#include "af_cnodemap.h"
#include "log.h"

/* Macros */
/* File Scope Variables */
static char ident[] = "@(#) $RCSfile$ $Revision$";

struct CNodeSortArgs
  {
  CNode    **array;
  SetCNode *set;
  union
    {
    int (*ifunc)();
    double(*ffunc)();
    char    *(*sfunc)();
    DateTime(*dfunc)();
    Size(*szfunc)();
    } key;
  enum { INTKEY, FLOATKEY, STRINGKEY, DATETIMEKEY, SIZEKEY } keytype;
  int  order;     /* ASC or DESC */
  };

/* External Variables */
/* External Functions */

/* Structures and Unions */
/* NONE */
/* Signal catching functions */
/* NONE */
/* Functions */

/* After calling this function, mallocTableAdd must be called */

static struct IODevice *IODeviceCreate(void)
  {
  Size sz;

  struct IODevice *iptr;

  iptr = (struct IODevice *) malloc(sizeof(struct IODevice));

  assert(iptr != NULL);

  sz = strToSize("-1b");
  iptr->name = NULL;
  iptr->spaceTotal = sz;      /* update it */
  iptr->spaceAvail = sz;
  iptr->spaceReserved = sz;
  iptr->inBw = -1;
  iptr->outBw = -1;

  return(iptr);
  }

static Size IODeviceSpaceTotalGet(iod_head, name)

struct IODevice *iod_head; /* ptr to the head of the list */
char  *name;
  {

  struct IODevice *iptr;

  for (iptr = iod_head; iptr; iptr = iptr->nextptr)
    {
    if (strcmp(iptr->name, name) == 0)    /* found a match */
      {
      return(iptr->spaceTotal);
      }
    }

  return(strToSize("-1b"));
  }

static Size IODeviceSpaceAvailGet(iod_head, name)

struct IODevice *iod_head; /* ptr to the head of the list */
char  *name;
  {

  struct IODevice *iptr;

  for (iptr = iod_head; iptr; iptr = iptr->nextptr)
    {
    if (strcmp(iptr->name, name) == 0)    /* found a match */
      {
      return(iptr->spaceAvail);
      }
    }

  return(strToSize("-1b"));
  }

static Size IODeviceSpaceReservedGet(iod_head, name)

struct IODevice *iod_head; /* ptr to the head of the list */
char  *name;
  {

  struct IODevice *iptr;

  for (iptr = iod_head; iptr; iptr = iptr->nextptr)
    {
    if (strcmp(iptr->name, name) == 0)    /* found a match */
      {
      return(iptr->spaceReserved);
      }
    }

  return(strToSize("-1b"));
  }

static int
IODeviceInBwGet(
  struct IODevice *iod_head, /* ptr to the head of the list */
  char *name
)
  {

  struct IODevice *iptr;

  for (iptr = iod_head; iptr; iptr = iptr->nextptr)
    {
    if (strcmp(iptr->name, name) == 0)    /* found a match */
      {
      return(iptr->inBw);
      }
    }

  return(-1);
  }

static int
IODeviceOutBwGet(
  struct IODevice *iod_head, /* ptr to the head of the list */
  char *name
)
  {

  struct IODevice *iptr;

  for (iptr = iod_head; iptr; iptr = iptr->nextptr)
    {
    if (strcmp(iptr->name, name) == 0)    /* found a match */
      {
      return(iptr->outBw);
      }
    }

  return(-1);
  }

static void
IODeviceListPrint(struct IODevice *iod_head, char *descr)
  {

  struct IODevice *iptr;

  for (iptr = iod_head; iptr; iptr = iptr->nextptr)
    {
    printf("\t\t\t    %s Device Name = %s:   ", descr, iptr->name);

    printf("Space Total = ");
    sizePrint(iptr->spaceTotal, 1);
    printf(", ");

    printf("Space Avail = ");
    sizePrint(iptr->spaceAvail, 1);
    printf(", ");

    printf("Space Reserved = ");
    sizePrint(iptr->spaceReserved, 1);
    printf(", ");

    printf("In Bw = %d", iptr->inBw);

    printf(", Out Bw = %d\n", iptr->outBw);
    }
  }

/* Returns the new head of list */

static struct IODevice *IODeviceSpaceTotalPut(iod_head, name, total, pptr)

      struct IODevice *iod_head; /* ptr to the head of the list */
char  *name;
Size  total;
void  *pptr;  /* parent ptr of anything that's been */
/* malloc-ed */
  {

  struct IODevice *iptr;

  for (iptr = iod_head; iptr; iptr = iptr->nextptr)
    {
    if (strcmp(iptr->name, name) == 0)    /* found a match */
      {
      iptr->spaceTotal = total;
      return(NULL);
      }
    }

  iptr = IODeviceCreate();

  mallocTableAdd(iptr, pptr, 0);

#ifdef DEBUG
  printf("Added IODevice ptr %x to mallocTable\n", iptr);
#endif

  dynamic_strcpy(&iptr->name, name);
  varstrModPptr(iptr->name, pptr);
  iptr->spaceTotal = total;
  iptr->nextptr = iod_head;
  return(iptr);
  }

static struct IODevice *IODeviceSpaceAvailPut(iod_head, name, avail, pptr)

      struct IODevice *iod_head; /* ptr to the head of the list */
char  *name;
Size  avail;
void  *pptr;
  {

  struct IODevice *iptr;

  for (iptr = iod_head; iptr; iptr = iptr->nextptr)
    {
    if (strcmp(iptr->name, name) == 0)    /* found a match */
      {
      iptr->spaceAvail = avail;
      return(NULL);
      }
    }

  iptr = IODeviceCreate();

  mallocTableAdd(iptr, pptr, 0);
#ifdef DEBUG
  printf("Added IODevice ptr %x to mallocTable\n", iptr);
#endif

  dynamic_strcpy(&iptr->name, name);
  varstrModPptr(iptr->name, pptr);

  iptr->spaceAvail = avail;
  iptr->nextptr = iod_head;
  return(iptr);
  }

static struct IODevice *IODeviceSpaceReservedPut(iod_head, name, reserve, pptr)

      struct IODevice *iod_head; /* ptr to the head of the list */
char  *name;
Size  reserve;
void  *pptr;
  {

  struct IODevice *iptr;

  for (iptr = iod_head; iptr; iptr = iptr->nextptr)
    {
    if (strcmp(iptr->name, name) == 0)    /* found a match */
      {
      iptr->spaceReserved = reserve;
      return(NULL);
      }
    }

  iptr = IODeviceCreate();

  mallocTableAdd(iptr, pptr, 0);

#ifdef DEBUG
  printf("Added IODevice ptr %x to mallocTable\n", iptr);
#endif

  dynamic_strcpy(&iptr->name, name);
  varstrModPptr(iptr->name, pptr);

  iptr->spaceReserved = reserve;
  iptr->nextptr = iod_head;
  return(iptr);
  }

static struct IODevice *
      IODeviceInBwPut(
        struct IODevice *iod_head, /* ptr to the head of the list */
        char *name,
        int inBw,
        void *pptr
      )
  {

  struct IODevice *iptr;

  for (iptr = iod_head; iptr; iptr = iptr->nextptr)
    {
    if (strcmp(iptr->name, name) == 0)    /* found a match */
      {
      iptr->inBw = inBw;
      return(NULL);
      }
    }

  iptr = IODeviceCreate();

  mallocTableAdd(iptr, pptr, 0);

#ifdef DEBUG
  printf("Added IODevice ptr %x to mallocTable\n", iptr);
#endif

  dynamic_strcpy(&iptr->name, name);
  varstrModPptr(iptr->name, pptr);

  iptr->inBw = inBw;
  iptr->nextptr = iod_head;
  return(iptr);
  }

static struct IODevice *
      IODeviceOutBwPut(
        struct IODevice *iod_head, /* ptr to the head of the list */
        char *name,
        int outBw,
        void *pptr
      )
  {

  struct IODevice *iptr;

  for (iptr = iod_head; iptr; iptr = iptr->nextptr)
    {
    if (strcmp(iptr->name, name) == 0)    /* found a match */
      {
      iptr->outBw = outBw;
      return(NULL);
      }
    }

  iptr = IODeviceCreate();

  mallocTableAdd(iptr, pptr, 0);
#ifdef DEBUG
  printf("Added IODevice ptr %x to mallocTable\n", iptr);
#endif

  dynamic_strcpy(&iptr->name, name);
  varstrModPptr(iptr->name, pptr);

  iptr->outBw = outBw;
  iptr->nextptr = iod_head;
  return(iptr);
  }


/* Network stuff */

static struct Network *NetworkCreate(void)
  {

  struct Network *iptr;

  iptr = (struct Network *) malloc(sizeof(struct Network));

  assert(iptr != NULL);

  iptr->type = NULL;
  iptr->bw   = -1;

  return(iptr);
  }

static int
NetworkBwGet(
  struct Network *net_head, /* ptr to the head of the list */
  char *type
)
  {

  struct Network *iptr;

  for (iptr = net_head; iptr; iptr = iptr->nextptr)
    {
    if (strcmp(iptr->type, type) == 0)    /* found a match */
      {
      return(iptr->bw);
      }
    }

  return(-1);
  }

/* Returns the new head of list */

static struct Network *
      NetworkBwPut(
        struct Network *net_head, /* ptr to the head of the list */
        char *type,
        int bw,
        void *pptr
      )
  {

  struct Network *iptr;

  for (iptr = net_head; iptr; iptr = iptr->nextptr)
    {
    if (strcmp(iptr->type, type) == 0)    /* found a match */
      {
      iptr->bw = bw;
      return(NULL);
      }
    }

  iptr = NetworkCreate();

  mallocTableAdd(iptr, pptr, 0);

#ifdef DEBUG
  printf("Added Network ptr %x to mallocTable\n", iptr);
#endif

  dynamic_strcpy(&iptr->type, type);
  varstrModPptr(iptr->type, pptr);

  iptr->bw = bw;
  iptr->nextptr = net_head;
  return(iptr);
  }

static void
NetworkListPrint(struct Network *net_head)
  {

  struct Network *iptr;

  for (iptr = net_head; iptr; iptr = iptr->nextptr)
    {
    printf("\t\t\t    Network Type = %s: Bw = %d\n", iptr->type,
           iptr->bw);
    }
  }

/* Memory stuff */

static struct Memory *MemoryCreate(void)
  {
  Size   sz;

  struct Memory *iptr;

  iptr = (struct Memory *) malloc(sizeof(struct Memory));

  assert(iptr != NULL);

  iptr->type = NULL;
  sz = strToSize("-1b");
  iptr->total   = sz;
  iptr->avail   = sz;

  return(iptr);
  }

static Size MemoryTotalGet(mem_head, type)

struct Memory   *mem_head; /* ptr to the head of the list */
char  *type;
  {

  struct Memory *iptr;

  for (iptr = mem_head; iptr; iptr = iptr->nextptr)
    {
    if (strcmp(iptr->type, type) == 0)    /* found a match */
      {
      return(iptr->total);
      }
    }

  return(strToSize("-1b"));
  }

/* Returns the new head of list */

static struct Memory *MemoryTotalPut(mem_head, type, newTot, pptr)

      struct Memory   *mem_head; /* ptr to the head of the list */
char  *type;
Size  newTot;
void  *pptr;
  {

  struct Memory *iptr;

  for (iptr = mem_head; iptr; iptr = iptr->nextptr)
    {
    if (strcmp(iptr->type, type) == 0)    /* found a match */
      {
      iptr->total = newTot;
      return(NULL);  /* no new head */
      }
    }

  iptr = MemoryCreate();

  mallocTableAdd(iptr, pptr, 0);

#ifdef DEBUG
  printf("Added Memory ptr %x to mallocTable\n", iptr);
#endif

  dynamic_strcpy(&iptr->type, type);
  varstrModPptr(iptr->type, pptr);

  iptr->total = newTot;
  iptr->nextptr = mem_head;
  return(iptr);
  }

static Size MemoryAvailGet(mem_head, type)

struct Memory   *mem_head; /* ptr to the head of the list */
char  *type;
  {

  struct Memory *iptr;

  for (iptr = mem_head; iptr; iptr = iptr->nextptr)
    {
    if (strcmp(iptr->type, type) == 0)    /* found a match */
      {
      return(iptr->avail);
      }
    }

  return(strToSize("-1b"));
  }

/* Returns the new head of list */

static struct Memory *MemoryAvailPut(mem_head, type, newAvail, pptr)

      struct Memory   *mem_head; /* ptr to the head of the list */
char  *type;
Size  newAvail;
void  *pptr;
  {

  struct Memory *iptr;

  for (iptr = mem_head; iptr; iptr = iptr->nextptr)
    {
    if (strcmp(iptr->type, type) == 0)    /* found a match */
      {
      iptr->avail = newAvail;
      return(NULL);  /* no new head */
      }
    }

  iptr = MemoryCreate();

  mallocTableAdd(iptr, pptr, 0);

#ifdef DEBUG
  printf("Added Memory ptr %x to mallocTable\n", iptr);
#endif

  dynamic_strcpy(&iptr->type, type);
  varstrModPptr(iptr->type, pptr);

  iptr->avail = newAvail;
  iptr->nextptr = mem_head;
  return(iptr);
  }

static void
MemoryListPrint(struct Memory *mem_head)
  {

  struct Memory *iptr;

  for (iptr = mem_head; iptr; iptr = iptr->nextptr)
    {
    printf("\t\t\t    Memory Type = %s: ", iptr->type);

    printf("Total = ");
    sizePrint(iptr->total, 1);
    printf(", Avail = ");
    sizePrint(iptr->avail, 1);
    printf("\n");
    }
  }

ResMom *CNodeResMomGet(node)
CNode *node;
  {
  if (node == NOCNODE)
    return(NULL);

  return &node->mom;
  }

/* CNodeNameGet: returns the official name of the node. */
char *CNodeNameGet(node)
CNode *node;
  {
  ResMom *mom;

  if (node == NOCNODE)
    return(NULLSTR);

  mom = CNodeResMomGet(node);

  if (mom == NULL)
    return(NULLSTR);

  return(mom->inetAddr);
  }

char *CNodePropertiesGet(node)
CNode *node;
  {
  if (node == NOCNODE)
    return(NULLSTR);

  return node->properties;
  }

/* CNodeVendorGet: returns the system name of the node. */
char *CNodeVendorGet(node)
CNode *node;
  {
  if (node == NOCNODE)
    return(NULLSTR);

  return node->vendor;
  }

/* CNodeOsGet:returns the OS version of the node */
char *CNodeOsGet(node)
CNode *node;
  {
  if (node == NOCNODE)
    return(NULLSTR);

  return node->os;
  }

/* CNodeNumCpusGet: returns the number of processors available */
int CNodeNumCpusGet(node)
CNode *node;
  {
  if (node == NOCNODE)
    return(-1);

  return node->numCpus;
  }

/* CNodeMemTotalGet: returns the total memory of type (phys or virtual). */
Size CNodeMemTotalGet(node, type)
CNode *node;
char  *type;
  {
  if (node == NOCNODE || type == NULLSTR)
    return(strToSize("-1b"));

  return(MemoryTotalGet(node->mem, type));
  }

/* CNodeMemAvailGet: returns the available memory of type (phys or virtual). */
Size CNodeMemAvailGet(node, type)
CNode *node;
char  *type;
  {
  if (node == NOCNODE || type == NULLSTR)
    return(strToSize("-1b"));

  return(MemoryAvailGet(node->mem, type));
  }

int CNodeQueryMomGet(node)
CNode *node;
  {
  if (node == NOCNODE)
    return(0);

  return node->queryMom;
  }

int CNodeMultiplicityGet(node)
CNode *node;
  {
  if (node == NOCNODE)
    return(0);

  return node->multiplicity;
  }

/* CNodeStateGet:returns the node state. */
int CNodeStateGet(node)
CNode *node;
  {
  if (node == NOCNODE)
    return(-1); /* unknown state */

  return node->state;
  }

/* CNodeTypeGet:returns the node type. */
int CNodeTypeGet(node)
CNode *node;
  {
  if (node == NOCNODE)
    return(-1); /* unknown state */

  return node->type;
  }

int CNodeIdletimeGet(node)
CNode *node;
  {
  if (node == NOCNODE)
    return(-1);

  return node->idletime;
  }

/* CNodeLoadAveGet: returns the load average of the system */
double CNodeLoadAveGet(node)
CNode *node;
  {
  if (node == NOCNODE)
    return(-1.0);

  return node->loadAve;
  }

/* CNodeNetworkBwGet: returns the network bandwith (bytes/secs) of node */
int CNodeNetworkBwGet(node, type)
CNode *node;
char  *type;
  {
  if (node == NOCNODE || type == NULLSTR)
    return(0);

  return(NetworkBwGet(node->network, type));
  }

/* CNodeDiskSpaceTotalGet: returns the total space on CNode disk */
Size CNodeDiskSpaceTotalGet(node, name)
CNode *node;
char  *name;
  {
  if (node == NOCNODE || name == NULLSTR)
    return(strToSize("-1b"));

  return(IODeviceSpaceTotalGet(node->disk, name));
  }

/* CNodeDiskSpaceAvailGet: returns the available space on CNode disk */
Size CNodeDiskSpaceAvailGet(node, name)
CNode *node;
char  *name;
  {
  if (node == NOCNODE || name == NULLSTR)
    return(strToSize("-1b"));

  return(IODeviceSpaceAvailGet(node->disk, name));
  }

/* CNodeDiskSpaceReservedGet: returns the available space on CNode disk */
Size CNodeDiskSpaceReservedGet(node, name)
CNode *node;
char  *name;
  {
  if (node == NOCNODE || name == NULLSTR)
    return(strToSize("-1b"));

  return(IODeviceSpaceReservedGet(node->disk, name));
  }

/* CNodeDiskInBwGet: returns the write bandwidth of the CNode disk */
int CNodeDiskInBwGet(node, name)
CNode *node;
char  *name;
  {
  if (node == NOCNODE || name == NULLSTR)
    return(0);

  return(IODeviceInBwGet(node->disk, name));
  }

/* CNodeDiskOutBwGet: returns the bandwidth of the largest CNode disk */
int CNodeDiskOutBwGet(node, name)
CNode *node;
char  *name;
  {
  if (node == NOCNODE || name == NULLSTR)
    return(0);

  return(IODeviceOutBwGet(node->disk, name));
  }

/* CNodeSwapSpaceTotalGet: returns the total space in the swap device */
Size CNodeSwapSpaceTotalGet(node, name)
CNode *node;
char  *name;
  {
  if (node == NOCNODE || name == NULLSTR)
    return(strToSize("-1b"));

  return(IODeviceSpaceTotalGet(node->swap, name));
  }

/* CNodeSwapSpaceAvailGet: returns the available space on swap device */
Size CNodeSwapSpaceAvailGet(node, name)
CNode *node;
char  *name;
  {
  if (node == NOCNODE || name == NULLSTR)
    return(strToSize("-1b"));

  return(IODeviceSpaceAvailGet(node->swap, name));
  }

Size CNodeSwapSpaceReservedGet(node, name)
CNode *node;
char  *name;
  {
  if (node == NOCNODE || name == NULLSTR)
    return(strToSize("-1b"));

  return(IODeviceSpaceReservedGet(node->swap, name));
  }


/* CNodeSwapInBwGet: returns the swapin rate of the swap device */
int CNodeSwapInBwGet(node, name)
CNode *node;
char  *name;
  {
  if (node == NOCNODE || name == NULLSTR)
    return(0);

  return(IODeviceInBwGet(node->swap, name));
  }

/* CNodeSwapOutBwGet: returns the swapout rate of the swap device */
int CNodeSwapOutBwGet(node, name)
CNode *node;
char  *name;
  {
  if (node == NOCNODE || name == NULLSTR)
    return(0);

  return(IODeviceOutBwGet(node->swap, name));
  }

/* CNodeTapeSpaceTotalGet: returns the total space on tape drive */
Size CNodeTapeSpaceTotalGet(node, name)
CNode *node;
char  *name;
  {
  if (node == NOCNODE || name == NULLSTR)
    return(strToSize("-1b"));

  return(IODeviceSpaceTotalGet(node->tape, name));
  }

/* CNodeTapeSpaceAvailGet: returns the available space on tape drive */
Size CNodeTapeSpaceAvailGet(node, name)
CNode *node;
char  *name;
  {
  if (node == NOCNODE || name == NULLSTR)
    return(strToSize("-1b"));


  return(IODeviceSpaceAvailGet(node->tape, name));
  }

/* CNodeTapeSpaceReservedGet: returns the reserved space on tape device */
Size CNodeTapeSpaceReservedGet(node, name)
CNode *node;
char  *name;
  {
  if (node == NOCNODE || name == NULLSTR)
    return(strToSize("-1b"));

  return(IODeviceSpaceReservedGet(node->tape, name));
  }

/* CNodeTapeInBwGet: returns the write bandwidth of the largest tape drive */
int CNodeTapeInBwGet(node, name)
CNode *node;
char  *name;
  {
  if (node == NOCNODE || name == NULLSTR)
    return(0);

  return(IODeviceInBwGet(node->tape, name));
  }

/* CNodeTapeOutBwGet: returns the read bandwidth of the largest tape drive */
int CNodeTapeOutBwGet(node, name)
CNode *node;
char  *name;
  {
  if (node == NOCNODE || name == NULLSTR)
    return(0);

  return(IODeviceOutBwGet(node->tape, name));
  }

/* CNodeSrfsSpaceTotalGet: returns the total bytes on the SRFS device */
Size CNodeSrfsSpaceTotalGet(node, name)
CNode *node;
char  *name;
  {
  if (node == NOCNODE || name == NULLSTR)
    return(strToSize("-1b"));

  return(IODeviceSpaceTotalGet(node->srfs, name));
  }

/* CNodeSrfsSpaceAvailGet: returns the space available on the SRFS device. */
Size CNodeSrfsSpaceAvailGet(node, name)
CNode *node;
char  *name;
  {
  if (node == NOCNODE || name == NULLSTR)
    return(strToSize("-1b"));

  return(IODeviceSpaceAvailGet(node->srfs, name));
  }

/* CNodeSrfsSpaceReservedGet: returns the amount of space reserved on */
/*         the SRFS device. */
Size CNodeSrfsSpaceReservedGet(node, name)
CNode *node;
char  *name;
  {
  if (node == NOCNODE || name == NULLSTR)
    return(strToSize("-1b"));

  return(IODeviceSpaceReservedGet(node->srfs, name));
  }

/* CNodeSrfsInBwGet: returns the write bandwidth of the SRFS device */
int CNodeSrfsInBwGet(node, name)
CNode *node;
char  *name;
  {
  if (node == NOCNODE || name == NULLSTR)
    return(0);

  return(IODeviceInBwGet(node->srfs, name));
  }

/* CNodeSrfsOutBwGet: returns the read bandwidth of the SRFS device */
int CNodeSrfsOutBwGet(node, name)
CNode *node;
char  *name;
  {
  if (node == NOCNODE || name == NULLSTR)
    return(0);

  return(IODeviceOutBwGet(node->srfs, name));
  }

int CNodeCpuPercentIdleGet(node)
CNode *node;
  {
  if (node == NOCNODE)
    return(-1);

  return(node->cpuPercentIdle);
  }

int CNodeCpuPercentSysGet(node)
CNode *node;
  {
  if (node == NOCNODE)
    return(-1);

  return(node->cpuPercentSys);
  }

int CNodeCpuPercentUserGet(node)
CNode *node;
  {
  if (node == NOCNODE)
    return(-1);

  return(node->cpuPercentUser);
  }

int CNodeCpuPercentGuestGet(node)
CNode *node;
  {
  if (node == NOCNODE)
    return(-1);

  return(node->cpuPercentGuest);
  }

/* PUT FUNCTIONS */
void CNodeResMomPut(node, mom)
CNode  *node;
ResMom *mom;
  {
  assert(node != NOCNODE);

  node->mom = *mom;
  }

void CNodePropertiesPut(node, properties)
CNode  *node;
char   *properties;
  {
  assert(node != NOCNODE);

  dynamic_strcpy(&node->properties, properties);
  varstrModPptr(node->properties, node);
  }

void CNodeVendorPut(node, vendor)
CNode  *node;
char   *vendor;
  {
  assert(node != NOCNODE);

  dynamic_strcpy(&node->vendor, vendor);
  varstrModPptr(node->vendor, node);
  }

void CNodeOsPut(node, os)
CNode  *node;
char   *os;
  {
  assert(node != NOCNODE);

  dynamic_strcpy(&node->os, os);
  varstrModPptr(node->os, node);
  }

void CNodeNumCpusPut(node, ncpus)
CNode  *node;
int    ncpus;
  {
  assert(node != NOCNODE);

  node->numCpus = ncpus;
  }

void CNodeMemTotalPut(node, type, pmem)
CNode  *node;
char   *type;
Size   pmem;
  {

  struct Memory *m;
  assert(node != NOCNODE && type != NULLSTR);

  m = MemoryTotalPut(node->mem, type, pmem, node);

  if (m != NULL)
    node->mem = m;
  }

void CNodeMemAvailPut(node, type, pmem)
CNode  *node;
char   *type;
Size   pmem;
  {

  struct Memory *m;
  assert(node != NOCNODE && type != NULLSTR);

  m = MemoryAvailPut(node->mem, type, pmem, node);

  if (m != NULL)
    node->mem = m;
  }

void CNodeQueryMomPut(node, queryMom)
CNode  *node;
int    queryMom;
  {
  assert(node != NOCNODE);

  node->queryMom = queryMom;
  }

void CNodeMultiplicityPut(node, nodect)
CNode  *node;
int    nodect;
  {
  assert(node != NOCNODE);

  node->multiplicity = nodect;
  }

void CNodeStatePut(node, state)
CNode  *node;
int    state;
  {
  assert(node != NOCNODE);

  node->state = state;
  }

void CNodeTypePut(node, type)
CNode  *node;
int    type;
  {
  assert(node != NOCNODE);

  node->type = type;
  }

void CNodeIdletimePut(node, idletime)
CNode  *node;
int    idletime;
  {
  assert(node != NOCNODE);

  node->idletime = idletime;
  }

/* The function below was not explicitly declared in af_cnode.h because */
/* of problems with type promotion. */
void CNodeLoadAvePut(node, loadave)
CNode  *node;
double loadave;
  {
  assert(node != NOCNODE);

  node->loadAve = loadave;
  }

void CNodeNetworkBwPut(node, type, bw)
CNode  *node;
char   *type;
int    bw;
  {

  struct Network *network;
  assert(node != NOCNODE && type != NULLSTR);

  network = NetworkBwPut(node->network, type, bw, node);

  if (network != NULL)
    node->network = network;
  }

void CNodeDiskSpaceTotalPut(node, name, size)
CNode  *node;
char   *name;
Size   size;
  {

  struct IODevice *iod;
  assert(node != NOCNODE && name != NULLSTR);

  iod = IODeviceSpaceTotalPut(node->disk, name, size, node);

  if (iod != NULL)
    node->disk = iod;
  }

void CNodeDiskSpaceAvailPut(node, name, size)
CNode  *node;
char   *name;
Size   size;
  {

  struct IODevice *iod;
  assert(node != NOCNODE && name != NULLSTR);

  iod = IODeviceSpaceAvailPut(node->disk, name, size, node);

  if (iod != NULL)
    node->disk = iod;
  }

void CNodeDiskSpaceReservedPut(node, name, size)
CNode  *node;
char   *name;
Size   size;
  {

  struct IODevice *iod;
  assert(node != NOCNODE && name != NULLSTR);

  iod = IODeviceSpaceReservedPut(node->disk, name, size, node);

  if (iod != NULL)
    node->disk = iod;
  }

void CNodeDiskInBwPut(node, name, bw)
CNode  *node;
char   *name;
int    bw;
  {

  struct IODevice *iod;
  assert(node != NOCNODE && name != NULLSTR);

  iod = IODeviceInBwPut(node->disk, name, bw, node);

  if (iod != NULL)
    node->disk = iod;
  }

void CNodeDiskOutBwPut(node, name, bw)
CNode  *node;
char   *name;
int    bw;
  {

  struct IODevice *iod;
  assert(node != NOCNODE && name != NULLSTR);

  iod = IODeviceOutBwPut(node->disk, name, bw, node);

  if (iod != NULL)
    node->disk = iod;
  }

void CNodeSwapSpaceTotalPut(node, name, swaptot)
CNode  *node;
char   *name;
Size   swaptot;
  {

  struct IODevice *iod;
  assert(node != NOCNODE && name != NULLSTR);

  iod = IODeviceSpaceTotalPut(node->swap, name, swaptot, node);

  if (iod != NULL)
    node->swap = iod;

  }

void CNodeSwapSpaceAvailPut(node, name, swapavail)
CNode  *node;
char   *name;
Size   swapavail;
  {

  struct IODevice *iod;
  assert(node != NOCNODE && name != NULLSTR);

  iod = IODeviceSpaceAvailPut(node->swap, name, swapavail, node);

  if (iod != NULL)
    node->swap = iod;
  }

void CNodeSwapSpaceReservedPut(node, name, swapres)
CNode  *node;
char   *name;
Size   swapres;
  {

  struct IODevice *iod;
  assert(node != NOCNODE && name != NULLSTR);

  iod = IODeviceSpaceReservedPut(node->swap, name, swapres, node);

  if (iod != NULL)
    node->swap = iod;
  }

void CNodeSwapInBwPut(node, name, bw)
CNode  *node;
char   *name;
int    bw;
  {

  struct IODevice *iod;
  assert(node != NOCNODE && name != NULLSTR);

  iod = IODeviceInBwPut(node->swap, name, bw, node);

  if (iod != NULL)
    node->swap = iod;
  }

void CNodeSwapOutBwPut(node, name, bw)
CNode  *node;
char   *name;
int    bw;
  {

  struct IODevice *iod;
  assert(node != NOCNODE && name != NULLSTR);

  iod = IODeviceOutBwPut(node->swap, name, bw, node);

  if (iod != NULL)
    node->swap = iod;
  }

void CNodeTapeSpaceTotalPut(node, name, size)
CNode  *node;
char   *name;
Size   size;
  {

  struct IODevice *iod;
  assert(node != NOCNODE && name != NULLSTR);

  iod = IODeviceSpaceTotalPut(node->tape, name, size, node);

  if (iod != NULL)
    node->tape = iod;
  }

void CNodeTapeSpaceAvailPut(node, name, size)
CNode  *node;
char   *name;
Size   size;
  {

  struct IODevice *iod;
  assert(node != NOCNODE && name != NULLSTR);

  iod = IODeviceSpaceAvailPut(node->tape, name, size, node);

  if (iod != NULL)
    node->tape = iod;
  }

void CNodeTapeSpaceReservedPut(node, name, size)
CNode  *node;
char   *name;
Size   size;
  {

  struct IODevice *iod;
  assert(node != NOCNODE && name != NULLSTR);

  iod = IODeviceSpaceReservedPut(node->tape, name, size, node);

  if (iod != NULL)
    node->tape = iod;
  }

void CNodeTapeInBwPut(node, name, bw)
CNode  *node;
char   *name;
int    bw;
  {

  struct IODevice *iod;
  assert(node != NOCNODE && name != NULLSTR);

  iod = IODeviceInBwPut(node->tape, name, bw, node);

  if (iod != NULL)
    node->tape = iod;
  }

void CNodeTapeOutBwPut(node, name, bw)
CNode  *node;
char   *name;
int    bw;
  {

  struct IODevice *iod;
  assert(node != NOCNODE && name != NULLSTR);

  iod = IODeviceOutBwPut(node->tape, name, bw, node);

  if (iod != NULL)
    node->tape = iod;
  }

void CNodeSrfsSpaceTotalPut(node, name, size)
CNode *node;
char  *name;
Size  size;
  {

  struct IODevice *iod;
  assert(node != NOCNODE && name != NULLSTR);

  iod = IODeviceSpaceTotalPut(node->srfs, name, size, node);

  if (iod != NULL)
    node->srfs = iod;
  }

void CNodeSrfsSpaceAvailPut(node, name, size)
CNode *node;
char  *name;
Size  size;
  {

  struct IODevice *iod;
  assert(node != NOCNODE && name != NULLSTR);

  iod = IODeviceSpaceAvailPut(node->srfs, name, size, node);

  if (iod != NULL)
    node->srfs = iod;
  }

void CNodeSrfsSpaceReservedPut(node, name, size)
CNode *node;
char  *name;
Size  size;
  {

  struct IODevice *iod;
  assert(node != NOCNODE && name != NULLSTR);

  iod = IODeviceSpaceReservedPut(node->srfs, name, size, node);

  if (iod != NULL)
    node->srfs = iod;
  }

void CNodeSrfsInBwPut(node, name, bw)
CNode *node;
char  *name;
int   bw;
  {

  struct IODevice *iod;
  assert(node != NOCNODE && name != NULLSTR);

  iod = IODeviceInBwPut(node->srfs, name, bw, node);

  if (iod != NULL)
    node->srfs = iod;
  }


void CNodeSrfsOutBwPut(node, name, bw)
CNode *node;
char  *name;
int   bw;
  {

  struct IODevice *iod;
  assert(node != NOCNODE && name != NULLSTR);

  iod = IODeviceOutBwPut(node->srfs, name, bw, node);

  if (iod != NULL)
    node->srfs = iod;
  }

void CNodeCpuPercentIdlePut(node, percent)
CNode *node;
int   percent;
  {
  assert(node != NOCNODE);

  node->cpuPercentIdle = percent;
  }

void CNodeCpuPercentSysPut(node, percent)
CNode *node;
int   percent;
  {
  assert(node != NOCNODE);

  node->cpuPercentSys = percent;
  }

void CNodeCpuPercentUserPut(node, percent)
CNode *node;
int   percent;
  {
  assert(node != NOCNODE);

  node->cpuPercentUser = percent;
  }

void CNodeCpuPercentGuestPut(node, percent)
CNode *node;
int   percent;
  {
  assert(node != NOCNODE);

  node->cpuPercentGuest = percent;
  }

/* Memory management */
/* Frees up malloc-ed elements of a CNode */
void CNodeFree(node)
CNode *node;
  {
  if (node == NOCNODE)
    return;

  /* deallocate all dynamic strings */
  varstrFreeByPptr(node);

  /* deallocate all lists of IODevices, and Networks */
  mallocTableFreeByPptr(node);

  /* to force all dynamic strings to be initialized to NULL and
     all device, network lists to be initialized to NULL in case of reuse */

  ResMomFree(&node->mom);

  node->properties = NULLSTR;

  node->vendor = NULLSTR;

  node->os = NULLSTR;

  node->network = NULL;

  node->disk = NULL;

  node->swap = NULL;

  node->tape = NULL;

  node->srfs = NULL;
  }

void  CNodeInit(node)
CNode *node;
  {
  assert(node != NOCNODE);


  ResMomInit(CNodeResMomGet(node));
  node->properties = NULLSTR;
  node->vendor = NULLSTR;
  node->os = NULLSTR;
  CNodeNumCpusPut(node, -1);
  CNodeQueryMomPut(node, 0);
  CNodeMultiplicityPut(node, 1);
  CNodeStatePut(node, CNODE_DOWN);
  CNodeTypePut(node, CNODE_UNKNOWN);
  CNodeIdletimePut(node, -1);
  CNodeLoadAvePut(node, -1.0);

  CNodeCpuPercentIdlePut(node, -1);
  CNodeCpuPercentSysPut(node, -1);
  CNodeCpuPercentUserPut(node, -1);
  CNodeCpuPercentGuestPut(node, -1);

  node->mem = NULL;
  node->network = NULL;
  node->disk = NULL;
  node->swap = NULL;
  node->tape = NULL;
  node->srfs = NULL;

  node->nextptr = NULL;
  }

void CNodePrint(node)
CNode *node;
  {
  if (node == NOCNODE)
    return;

  assert(node != NOCNODE);

  (void)printf("\t\t\t  Node Name = %s\n",
               CNodeNameGet(node) ? CNodeNameGet(node) : "null");

  (void)printf("\t\t\t    Properties = %s\n",
               CNodePropertiesGet(node) ? CNodePropertiesGet(node) : "null");

  (void)printf("\t\t\t    Vendor = %s\n",
               CNodeVendorGet(node) ? CNodeVendorGet(node) : "null");

  (void)printf("\t\t\t    OS Version = %s\n",
               CNodeOsGet(node) ? CNodeOsGet(node) : "null");

  switch (CNodeStateGet(node))
    {

    case CNODE_OFFLINE:
      (void)printf("\t\t\t    Node State = OFFLINE\n");
      break;

    case CNODE_DOWN:
      (void)printf("\t\t\t    Node State = DOWN\n");
      break;

    case CNODE_FREE:
      (void)printf("\t\t\t    Node State = FREE\n");
      break;

    case CNODE_RESERVE:
      (void)printf("\t\t\t    Node State = RESERVED\n");
      break;

    case CNODE_INUSE_EXCLUSIVE:
      (void)printf("\t\t\t    Node State = INUSE-EXCLUSIVE\n");
      break;

    case CNODE_INUSE_SHARED:
      (void)printf("\t\t\t    Node State = INUSE-SHARED\n");
      break;

    case CNODE_UNKNOWN:
      (void)printf("\t\t\t    Node State = UNKNOWN\n");
      break;

    default:
      (void)printf("\t\t\t    Node State = %d\n", CNodeStateGet(node));
    }

  switch (CNodeTypeGet(node))
    {

    case CNODE_TIMESHARED:
      (void)printf("\t\t\t    Node Type = TIMESHARED\n");
      break;

    case CNODE_CLUSTER:
      (void)printf("\t\t\t    Node Type = CLUSTER\n");
      break;

    case CNODE_UNKNOWN:
      (void)printf("\t\t\t    Node Type = UNKNOWN\n");
      break;

    default:
      (void)printf("\t\t\t    Node Type = %d\n", CNodeTypeGet(node));
    }


  (void)printf("\t\t\t    IdleTime = %d\n", CNodeIdletimeGet(node));
  (void)printf("\t\t\t    # of Processors = %d\n", CNodeNumCpusGet(node));

  (void)printf("\t\t\t    Query MOM ? = %d\n", CNodeQueryMomGet(node));
  (void)printf("\t\t\t    Multiplicity = %d\n", CNodeMultiplicityGet(node));
  (void)printf("\t\t\t    Load Avg. = %2.2f\n", CNodeLoadAveGet(node));
  (void)printf("\t\t\t    All Cpus %%Idle = %d\n",
               CNodeCpuPercentIdleGet(node));
  (void)printf("\t\t\t    All Cpus %%Sys = %d\n",
               CNodeCpuPercentSysGet(node));
  (void)printf("\t\t\t    All Cpus %%User = %d\n",
               CNodeCpuPercentUserGet(node));
  (void)printf("\t\t\t    All Cpus %%Guest = %d\n",
               CNodeCpuPercentGuestGet(node));

  MemoryListPrint(node->mem);
  NetworkListPrint(node->network);
  IODeviceListPrint(node->disk, "Disk");
  IODeviceListPrint(node->swap, "Swap");
  IODeviceListPrint(node->tape, "Tape");
  IODeviceListPrint(node->srfs, "Srfs");

  }

/* getMachType: get the machine type of mom representing the node, filling
   appropriate information in the Os attribute of the corresponding node
   Returns:     0 if successful; non-zero otherwise. */
static void getMachType(node)
CNode *node;
  {
  static  char  id[] = "getMachType";
  char    *retval;
  char    *res;
  char    *val;
  ResMom *mom;

  assert(node != NOCNODE);

  mom = CNodeResMomGet(node);
  assert(mom != NULL);

  if (ResMomWrite(mom, "arch"))
    {
    retval = ResMomRead(mom);
    res    = retval;
    val    = NULLSTR;

    if (res != NULLSTR)
      {
      val    = strrchr(retval, '=');  /* locates ptr to last = */

      if (val != NULLSTR)
        {
        *val = '\0'; /* end the resource portion */
        val++;  /* point to the value portion */
        }
      }

    if (res != NULLSTR && val != NULLSTR && *val != '?' && \
        *val != '\0')
      {
      CNodeOsPut(node, val);
      }
    else
      {
      (void)sprintf(log_buffer, "%s: unknown mach type!\n",
                    ResMomInetAddrGet(mom));
      log_err(-1, id, log_buffer);
      CNodeOsPut(node, NULLSTR);
      }
    }

  varstrFree(retval);

  }

static int put_default_val(node, attrib, type, putfunc)
CNode *node;
char *attrib;
int type;
void (*putfunc)();
  {

  static char id[] = "put_default_val";
  char *tag;
  Size sizeval;

  tag = parseAttrForTag(attrib);

  switch (type)
    {

    case INT_TYPE:

      if (tag == NULLSTR)    /* non-array attribute */
        {
        putfunc(node, -1);
        }
      else    /* array attribute */
        {
        putfunc(node, tag, -1);
        }

      break;

    case SIZE_TYPE:
      sizeval.num = -1;
      sizeval.shift = 0;
      sizeval.units = BYTES;

      if (tag == NULLSTR)    /* non-array attribute */
        {
        putfunc(node, sizeval);
        }
      else    /* array attribute */
        {
        putfunc(node, tag, sizeval);
        }

      break;

    case FLT_TYPE:

      if (tag == NULLSTR)    /* non-array attribute */
        {
        putfunc(node, -1.0);
        }
      else    /* array attribute */
        {
        putfunc(node, tag, -1.0);
        }

      break;

    case STR_TYPE:

      if (tag == NULLSTR)    /* non-array attribute */
        {
        putfunc(node, NULLSTR);
        }
      else    /* array attribute */
        {
        putfunc(node, tag, NULLSTR);
        }

      break;

    default:
      (void)sprintf(log_buffer,
                    "attribute %s unknown type",
                    attrib);
      log_err(-1, id, log_buffer);

    }
  }

/* send_queries: Send 'node''s MOM of type 'arch' a list of 'typeOfData'
  resource queries with each query information stored in
  'buf'.
   Returns:      # of queries successfully sent */
static int send_queries(node, arch, typeOfData, buf)
CNode  *node;
char   *arch;
int    typeOfData;

struct CNodeAttrInfo **buf;
  {
  ResMom  *mom;
  int   numSends = 0;

  struct  Resource **query;
  /* actually a dynamic array of resource queries */
  int    type;
  void (*putfunc)();

  int    i, cnt;
  char   *attrib;

  assert(node != NOCNODE);
  mom = CNodeResMomGet(node);
  assert(mom != NULL);

  switch (typeOfData)
    {

    case STATIC_RESOURCE:
      cnt = 0;

      while ((attrib = getStaticAttrAtIndex(cnt, &type, &putfunc)) != NULLSTR)
        {
        query = getResPtr(arch, attrib);

        for (i = 0; i < dynamicArraySize(query); i++)
          {
          *buf = extendDynamicArray(*buf, (size_t) numSends + 1,
                                    sizeof(struct CNodeAttrInfo));
          (*buf)[numSends].name = NULLSTR;
          dynamic_strcpy(&((*buf)[numSends].name), getNodeAttrGivenResPtr(query[i]));
          varstrModPptr((*buf)[numSends].name, mom);
          (*buf)[numSends].type = type;
          (*buf)[numSends].attrPutFunc = putfunc;
          (void)ResMomWrite(mom,
                            getHostQueryKeywordGivenResPtr(query[i]));
          put_default_val(node, (*buf)[numSends].name,
                          (*buf)[numSends].type,
                          (*buf)[numSends].attrPutFunc);
          numSends++;
          }

        freeDynamicArray(query);

        cnt++;
        }

      break;

    case DYNAMIC_RESOURCE:
      cnt = 0;

      while ((attrib = getDynamicAttrAtIndex(cnt, &type, &putfunc)) != NULLSTR)
        {
        query = getResPtr(arch, attrib);

        for (i = 0; i < dynamicArraySize(query); i++)
          {
          *buf = extendDynamicArray(*buf, (size_t)numSends + 1,
                                    sizeof(struct CNodeAttrInfo));
          (*buf)[numSends].name = NULLSTR;
          dynamic_strcpy(&((*buf)[numSends].name), getNodeAttrGivenResPtr(query[i]));
          varstrModPptr((*buf)[numSends].name, mom);
          (*buf)[numSends].type = type;
          (*buf)[numSends].attrPutFunc = putfunc;
          (void)ResMomWrite(mom,
                            getHostQueryKeywordGivenResPtr(query[i]));
          put_default_val(node, (*buf)[numSends].name,
                          (*buf)[numSends].type,
                          (*buf)[numSends].attrPutFunc);
          numSends++;
          }

        freeDynamicArray(query);

        cnt++;
        }
    }

  /* buf will be freed in recv_responses */

  return(numSends);
  }

/* recv_responses: get all responses from 'node's mom regarding previously
     sent resource queries. CNode information for queries are
     obtained from 'buf'. Based on responses, fill in the
     values for 'node's members.
   Returns:        # of responses received. */
static int recv_responses(node, buf)
CNode  *node;

struct CNodeAttrInfo buf[];
  {
  static      char id[] = "recv_responses";
  int         numRecvs = 0;
  char        *retval;
  char        *res;
  char        *val;
  int         intval;
  double      fltval;
  Size sizeval;
  char        *attrib;
  void (*putfunc)();
  int         type;
  char *tag;
  ResMom  *mom;

  assert(node != NOCNODE);

  mom = CNodeResMomGet(node);

  ResMomPrint(mom);

  while ((retval = ResMomRead(mom)) != NULLSTR)
    {
    res    = retval;
    val    = NULLSTR;

    if (res != NULLSTR)
      {
      val    = strrchr(retval, '=');  /* locates ptr to last = */

      if (val != NULLSTR)
        {
        *val = '\0';  /* end the resource portion */
        val++;   /* point to the value portion */
        }
      }

    attrib   = buf[numRecvs].name;

    type     = buf[numRecvs].type;
    putfunc  = buf[numRecvs].attrPutFunc;
    tag     = parseAttrForTag(attrib);
    varstrModPptr(tag, mom);

    switch (type)
      {

      case INT_TYPE:

        if (val == NULLSTR || *val == '?' || *val == '\0')
          {
          intval = -1;
          }
        else
          {
          intval = strToInt(val);
          }

        if (tag == NULLSTR)    /* non-array attribute */
          {
          putfunc(node, intval);
          }
        else    /* array attribute */
          {
          putfunc(node, tag, intval);
          }

        break;

      case SIZE_TYPE:

        if (val == NULLSTR || *val == '?' || *val == '\0')
          {
          sizeval.num = -1;
          sizeval.shift = 0;
          sizeval.units = BYTES;
          }
        else
          {
          sizeval = strToSize(val);
          }

        if (tag == NULLSTR)    /* non-array attribute */
          {
          putfunc(node, sizeval);
          }
        else    /* array attribute */
          {
          putfunc(node, tag, sizeval);
          }

        break;

      case FLT_TYPE:

        if (val == NULLSTR || *val == '?' || *val == '\0')
          fltval = -1.0;
        else
          fltval = strToFloat(val);

        if (tag == NULLSTR)    /* non-array attribute */
          {
          putfunc(node, fltval);
          }
        else    /* array attribute */
          {
          putfunc(node, tag, fltval);
          }

        break;

      case STR_TYPE:

        if (tag == NULLSTR)    /* non-array attribute */
          {

          if (val == NULLSTR || *val == '?' || \
              *val == '\0')
            putfunc(node, NULLSTR);
          else
            putfunc(node, val);

          }
        else    /* array attribute */
          {

          if (val == NULLSTR || *val == '?' || \
              *val == '\0')
            putfunc(node, tag, NULLSTR);
          else
            putfunc(node, tag, val);

          }

        break;

      default:
        (void)sprintf(log_buffer,
                      "attribute %s unknown type",
                      attrib);
        log_err(-1, id, log_buffer);
      };

    numRecvs++;
    }

  /* clean up anything malloc-ed */
  varstrFreeByPptr(mom);

  return(numRecvs);
  }

/* CNodeStateRead: gets node property from its mom. Property can be of
     typeOfData */
/*     which currently valid is STATIC_RESOUCE, DYNAMIC_RESOURCE */

void CNodeStateRead(node, typeOfData)
CNode *node;
int typeOfData;
  {
  char *arch;
  int numSends, numRecvs;

  struct  CNodeAttrInfo *buf = NULL;
  int nodeType;
  ResMom  *mom;

  mom = CNodeResMomGet(node);

  if (!CNodeQueryMomGet(node))
    {
    return;
    }

  if (ResMomOpen(mom) < 0)
    {
    CNodeStatePut(node, CNODE_DOWN);
    return;
    }

#ifdef DEBUG
  printf("BEGIN of CNodeStateRead(%s)################################\n",
         ResMomInetAddrGet(mom));

  printDynamicArrayTable();

  okClientPrint();

  mallocTablePrint();

  ResPrint();

  varstrPrint();

#endif

  arch = ResMomInetAddrGet(mom);

  numSends = send_queries(node, arch, typeOfData, &buf);

  /*  Get responses. Assume we get responses in order */
  numRecvs = recv_responses(node, buf);

  nodeType = CNodeTypeGet(node);

#ifdef DEBUG
  printf("CNodeStateRead(%s) NUMSENDS: %d, NUMRECVS: %d\n",
         ResMomInetAddrGet(mom), numSends, numRecvs);

#endif

  if (nodeType == CNODE_UNKNOWN)
    {

    if (numSends == numRecvs)    /* ok */
      {
      CNodeStatePut(node, CNODE_FREE);
      }
    else   /* not ok */
      {
      CNodeStatePut(node, CNODE_DOWN);
      }
    }

  (void)ResMomClose(mom);
  freeDynamicArray((struct CNodeAttrInfo *) buf);

#ifdef DEBUG
  printf("END of CNodeStateRead(%s)##################################\n",
         ResMomInetAddrGet(mom));
  printDynamicArrayTable();
  okClientPrint();
  ResPrint();
  mallocTablePrint();
  varstrPrint();
#endif
  }

/* Set of CNode abstraction */
void SetCNodeInit(scn)
SetCNode  *scn;
  {
  scn->head = NOCNODE;
  scn->tail = NOCNODE;
  scn->numAvail = -1;
  scn->numAlloc = -1;
  scn->numRsvd  = -1;
  scn->numDown  = -1;
  }

/* adds to the end of the list */
void SetCNodeAdd(scn, cn)
SetCNode  *scn;
CNode     *cn;
  {
  assert(scn != EMPTYSETCNODE);

  assert(scn->head == NOCNODE && scn->tail == NOCNODE || \
         scn->head != NOCNODE && scn->tail != NOCNODE);

  assert(cn != NOCNODE);

  mallocTableAdd(cn, scn, 0);

#ifdef DEBUG
  printf("Added CNode %x to SetCNode %x\n", cn, scn);
  CNodePrint(cn);
#endif
  cn->nextptr = NOCNODE;

  if (scn->head == NOCNODE && scn->tail == NOCNODE)
    {
    scn->head = cn;
    scn->tail = cn;
    }
  else
    {
    scn->tail->nextptr = cn;
    scn->tail = cn;
    }

  }

void SetCNodeFree(scn)
SetCNode  *scn;
  {
  CNode     *cn, *cntmp;

  if (scn == EMPTYSETCNODE)
    return; /* ignore */

  for (cn = scn->head; cn; cn = cntmp)
    {
    cntmp = cn->nextptr;
    /* free up dynamic strings, and device, network lists */
    /* attached to cn */
    CNodeFree(cn);
    }

  /* Free up the all dynamically allocated CNodes themselves */
  /* CNodes */
  mallocTableFreeByPptr(scn);

  /* Assuming of course that scn is non-malloced! */
  /* Give CNode a reasonable starting point */
  SetCNodeInit(scn);
  }

/* finds a CNode in the set of CNodes by matching the "node_name". */
CNode *SetCNodeFindCNodeByName(scn, node_name)
SetCNode *scn;
char   *node_name;
  {
  CNode *cn;

  if (scn == EMPTYSETCNODE)
    return(NOCNODE);

  for (cn = scn->head; cn; cn = cn->nextptr)
    {
    if (STRCMP(CNodeNameGet(cn) , == , node_name))
      return(cn);

    }

  return(NOCNODE);
  }

void SetCNodePrint(scn)
SetCNode  *scn;
  {
  CNode     *cn;

  for (cn = scn->head; cn; cn = cn->nextptr)
    CNodePrint(cn);
  }

int inSetCNode(cn, scn)
CNode     *cn;
SetCNode  *scn;
  {
  CNode     *c;

  if (scn == EMPTYSETCNODE)
    return(0);

  for (c = scn->head; c; c = c->nextptr)
    {
    if (c == cn)
      return(1);
    }

  return(0);
  }

static int
CNodePartition(struct CNodeSortArgs *A, int p, int r)
  {

  CNode                   *temptr;
  CNode                   *temptr2;
  int                   i, j;
  int                     k;

  assert(A->keytype == INTKEY || A->keytype == STRINGKEY || \
         A->keytype == DATETIMEKEY || A->keytype == SIZEKEY || \
         A->keytype == FLOATKEY);

  i = p - 1;
  j = r + 1;

  while (TRUE)
    {

    switch (A->keytype)
      {

      case INTKEY:

        do
          {
          j--;
          }
        while ((A->order == ASC  && A->key.ifunc(A->array[j]) > \
                A->key.ifunc(A->array[p])) ||  \
               (A->order == DESC && A->key.ifunc(A->array[j]) < \
                A->key.ifunc(A->array[p])));

        do
          {
          i++;
          }
        while ((A->order == ASC  && A->key.ifunc(A->array[i]) < \
                A->key.ifunc(A->array[p])) ||  \
               (A->order == DESC && A->key.ifunc(A->array[i]) > \
                A->key.ifunc(A->array[p])));

        break;

      case FLOATKEY:
        do
          {
          j--;
          }
        while ((A->order == ASC  && A->key.ffunc(A->array[j]) > \
                A->key.ffunc(A->array[p])) ||  \
               (A->order == DESC && A->key.ffunc(A->array[j]) < \
                A->key.ffunc(A->array[p])));

        do
          {
          i++;
          }
        while ((A->order == ASC  && A->key.ffunc(A->array[i]) < \
                A->key.ffunc(A->array[p])) ||  \
               (A->order == DESC && A->key.ffunc(A->array[i]) > \
                A->key.ffunc(A->array[p])));

        break;

      case STRINGKEY:
        do
          {
          j--;
          }
        while ((A->order == ASC && \
                STRCMP(A->key.sfunc(A->array[j]),
                       > , A->key.sfunc(A->array[p]))) || \
               (A->order == DESC && \
                STRCMP(A->key.sfunc(A->array[j]),
                       < , A->key.sfunc(A->array[p]))));

        do
          {
          i++;
          }
        while ((A->order == ASC && \
                STRCMP(A->key.sfunc(A->array[i]),
                       < , A->key.sfunc(A->array[p]))) || \
               (A->order == DESC && \
                STRCMP(A->key.sfunc(A->array[i]),
                       > , A->key.sfunc(A->array[p]))));

        break;

      case DATETIMEKEY:
        do
          {
          j--;
          }
        while ((A->order == ASC && \
                DATETIMECMP(A->key.dfunc(A->array[j]),
                            > , A->key.dfunc(A->array[p]))) || \
               (A->order == DESC && \
                DATETIMECMP(A->key.dfunc(A->array[j]),
                            < , A->key.dfunc(A->array[p]))));

        do
          {
          i++;
          }
        while ((A->order == ASC && \
                DATETIMECMP(A->key.dfunc(A->array[i]),
                            < , A->key.dfunc(A->array[p]))) || \
               (A->order == DESC && \
                DATETIMECMP(A->key.dfunc(A->array[i]),
                            > , A->key.dfunc(A->array[p]))));

        break;

      case SIZEKEY:
        do
          {
          j--;
          }
        while ((A->order == ASC && \
                SIZECMP(A->key.szfunc(A->array[j]),
                        > , A->key.szfunc(A->array[p]))) || \
               (A->order == DESC && \
                SIZECMP(A->key.szfunc(A->array[j]),
                        < , A->key.szfunc(A->array[p]))));

        do
          {
          i++;
          }
        while ((A->order == ASC && \
                SIZECMP(A->key.szfunc(A->array[i]),
                        < , A->key.szfunc(A->array[p]))) || \
               (A->order == DESC && \
                SIZECMP(A->key.szfunc(A->array[i]),
                        > , A->key.szfunc(A->array[p]))));

        break;
      }


    if (i < j)
      {
      /* move the pointers around */
      if (i + 1 == j)
        {
        temptr2 = A->array[i];
        }
      else
        {
        temptr2 = A->array[i]->nextptr;
        }

      A->array[i]->nextptr = A->array[j]->nextptr;

      A->array[j]->nextptr = temptr2;


      if (i - 1 >= 0 && i - 1 < dynamicArraySize(A->array))
        {
        A->array[i-1]->nextptr = A->array[j];
        }

      if (j - 1 != i && j - 1 >= 0 && j - 1 < dynamicArraySize(A->array))
        {
        A->array[j-1]->nextptr = A->array[i];
        }

      if (A->set->head == A->array[i])
        {
        A->set->head = A->array[j];
        }

      if (A->set->tail == A->array[j])
        {
        A->set->tail = A->array[i];
        }

      /* update the entries on the array */
      temptr = A->array[j];

      A->array[j] = A->array[i];

      A->array[i] = temptr;


      }
    else
      {
      return(j);
      }

    } /* while */
  }

static void
CNodeQuickSort(struct CNodeSortArgs *A, int p, int r)
  {
  int     q;

  if (p < r)
    {

    q = CNodePartition(A, p, r);
    CNodeQuickSort(A, p, q);
    CNodeQuickSort(A, q + 1, r);
    }
  }

int SetCNodeSortInt(s, key, order)
SetCNode             *s;
int (*key)();
int                  order;
  {

  CNode  **s_ptrs = NULL;
  int    beforecnt, aftercnt;

  struct CNodeSortArgs A;
  CNode  *q;

  if (order != ASC && order != DESC)
    {
    fprintf(stderr,
            "SetCNodeSortInt: order != ASC and order !=DESC\n");
    return(FAIL);
    }

  beforecnt = 0;

  for (q = s->head; q; q = q->nextptr)
    {
    s_ptrs = (CNode **)extendDynamicArray(s_ptrs,
                                          beforecnt + 1, sizeof(CNode *));

    aftercnt = dynamicArraySize(s_ptrs);

    if (beforecnt == aftercnt)
      {
      fprintf(stderr,
              "SetCNodeSortInt: Unable to realloc s_ptrs");

      if (aftercnt > 0)
        {
        freeDynamicArray(s_ptrs);
        }

      return(FAIL);
      }

    s_ptrs[beforecnt] = q;

    beforecnt++;
    }

  A.array = s_ptrs;

  A.set = s;
  A.key.ifunc = key;
  A.keytype = INTKEY;
  A.order   = order;

  CNodeQuickSort(&A, 0, beforecnt - 1);

  freeDynamicArray(s_ptrs);
  return(SUCCESS);
  }

int SetCNodeSortStr(s, key, order)
SetCNode             *s;
char                 *(*key)();
int                  order;
  {

  CNode  **s_ptrs = NULL;
  int    beforecnt, aftercnt;

  struct CNodeSortArgs A;
  CNode  *q;

  if (order != ASC && order != DESC)
    {
    fprintf(stderr,
            "SetCNodeSortStr: order != ASC and order !=DESC\n");
    return(FAIL);
    }

  beforecnt = 0;

  for (q = s->head; q; q = q->nextptr)
    {
    s_ptrs = (CNode **)extendDynamicArray(s_ptrs,
                                          beforecnt + 1, sizeof(CNode *));

    aftercnt = dynamicArraySize(s_ptrs);

    if (beforecnt == aftercnt)
      {
      fprintf(stderr,
              "SetCNodeSortStr: Unable to realloc s_ptrs");

      if (aftercnt > 0)
        {
        freeDynamicArray(s_ptrs);
        }

      return(FAIL);
      }

    s_ptrs[beforecnt] = q;

    beforecnt++;
    }

  A.array = s_ptrs;

  A.set = s;
  A.key.sfunc = key;
  A.keytype = STRINGKEY;
  A.order   = order;

  CNodeQuickSort(&A, 0, beforecnt - 1);

  freeDynamicArray(s_ptrs);
  return(SUCCESS);
  }

int SetCNodeSortDateTime(s, key, order)
SetCNode             *s;
DateTime(*key)();
int                  order;
  {

  CNode  **s_ptrs = NULL;
  int    beforecnt, aftercnt;

  struct CNodeSortArgs A;
  CNode  *q;

  if (order != ASC && order != DESC)
    {
    fprintf(stderr,
            "SetCNodeSortDateTime: order != ASC and order !=DESC\n");
    return(FAIL);
    }

  beforecnt = 0;

  for (q = s->head; q; q = q->nextptr)
    {
    s_ptrs = (CNode **)extendDynamicArray(s_ptrs,
                                          beforecnt + 1, sizeof(CNode *));

    aftercnt = dynamicArraySize(s_ptrs);

    if (beforecnt == aftercnt)
      {
      fprintf(stderr,
              "SetCNodeSortDateTime: Unable to realloc s_ptrs");

      if (aftercnt > 0)
        {
        freeDynamicArray(s_ptrs);
        }

      return(FAIL);
      }

    s_ptrs[beforecnt] = q;

    beforecnt++;
    }

  A.array = s_ptrs;

  A.set = s;
  A.key.dfunc = key;
  A.keytype = DATETIMEKEY;
  A.order   = order;

  CNodeQuickSort(&A, 0, beforecnt - 1);

  freeDynamicArray(s_ptrs);
  return(SUCCESS);
  }

int SetCNodeSortSize(s, key, order)
SetCNode             *s;
Size(*key)();
int                  order;
  {

  CNode  **s_ptrs = NULL;
  int    beforecnt, aftercnt;

  struct CNodeSortArgs A;
  CNode  *q;

  if (order != ASC && order != DESC)
    {
    fprintf(stderr,
            "SetCNodeSortSize: order != ASC and order !=DESC\n");
    return(FAIL);
    }

  beforecnt = 0;

  for (q = s->head; q; q = q->nextptr)
    {
    s_ptrs = (CNode **)extendDynamicArray(s_ptrs,
                                          beforecnt + 1, sizeof(CNode *));

    aftercnt = dynamicArraySize(s_ptrs);

    if (beforecnt == aftercnt)
      {
      fprintf(stderr,
              "SetCNodeSortSize: Unable to realloc s_ptrs");

      if (aftercnt > 0)
        {
        freeDynamicArray(s_ptrs);
        }

      return(FAIL);
      }

    s_ptrs[beforecnt] = q;

    beforecnt++;
    }

  A.array = s_ptrs;

  A.set = s;
  A.key.szfunc = key;
  A.keytype = SIZEKEY;
  A.order   = order;

  CNodeQuickSort(&A, 0, beforecnt - 1);

  freeDynamicArray(s_ptrs);
  return(SUCCESS);
  }

int SetCNodeSortFloat(s, key, order)
SetCNode             *s;
double(*key)();
int                  order;
  {

  CNode  **s_ptrs = NULL;
  int    beforecnt, aftercnt;

  struct CNodeSortArgs A;
  CNode  *q;

  if (order != ASC && order != DESC)
    {
    fprintf(stderr,
            "SetCNodeSortSize: order != ASC and order !=DESC\n");
    return(FAIL);
    }

  beforecnt = 0;

  for (q = s->head; q; q = q->nextptr)
    {
    s_ptrs = (CNode **)extendDynamicArray(s_ptrs,
                                          beforecnt + 1, sizeof(CNode *));

    aftercnt = dynamicArraySize(s_ptrs);

    if (beforecnt == aftercnt)
      {
      fprintf(stderr,
              "SetCNodeSortSize: Unable to realloc s_ptrs");

      if (aftercnt > 0)
        {
        freeDynamicArray(s_ptrs);
        }

      return(FAIL);
      }

    s_ptrs[beforecnt] = q;

    beforecnt++;
    }

  A.array = s_ptrs;

  A.set = s;
  A.key.ffunc = key;
  A.keytype = FLOATKEY;
  A.order   = order;

  CNodeQuickSort(&A, 0, beforecnt - 1);

  freeDynamicArray(s_ptrs);
  return(SUCCESS);
  }
