#ifndef lint
static char     sccsid[] = "@(#)sys_util.c";
static char     Creator[] = "C 1991 G. Sxoinas csi.forth.gr \n";
static char     Mail[] = "sxoinas@ariadne.bitnet or sxoinas@csi.forth.gr";
#endif

/*
 * This file is part of the POSYBL (PrOgramming SYstem for distriButed
 * appLications, a free Linda implementation for Unix Networks) and contains
 * the various 'system' utility functions such as loading a network file, a
 * node file, e.t.c.
 * 
 * There are no restrictions on this code; however, if you make any changes, I
 * request that you document them so that I do not get credit or blame for your
 * modifications.
 * 
 * Written by Ioannis Schoinas (sxoinas@csd.uch.gr or sxoinas@csi.forth.gr),
 * Computer Science Department, University of Crete, Heraclion, Crete, Greece.
 * 
 * Note: Linda is a trademark of SCA, Inc.
 * 
 */
#include	<stdio.h>
#include	<sys/file.h>
#include	<sys/types.h>
#include	<sys/socket.h>
#include	<sys/un.h>

#include	"linda_defs.h"

void
LoadNodes(filename, NodesInfoBuffer, NodesNumber)	/* Load the nodefile
							 * info */
  char           *filename;
  NODEINFO        NodesInfoBuffer[];
int            *NodesNumber;
{
  FILE           *nodefile;
  register int    cnt = -1;

  if (filename == NULL)
  {
    char            buffer[256];

    strcpy(buffer, getenv("HOME"));
    strcat(buffer, "/.nodefile");
    if (access("./.nodefile", F_OK) == 0)
      nodefile = fopen("./.nodefile", "r");
    else if (access(buffer, F_OK) == 0)
      nodefile = fopen(buffer, "r");
    else
    {
      fprintf(stderr, "LoadNodes: cannot find init file '.nodefile'\n");
      exit(1);
    }
  }
  else if (access(filename, F_OK) == 0)
    nodefile = fopen(filename, "r");
  else
  {
    fprintf(stderr, "LoadNodes: cannot find init file '%s'\n", filename);
    exit(1);
  }
  {
    char            buffer[256];
    char           *ptr;
    int             nodefound = FALSE, number;
    while (!feof(nodefile))
    {
      fgets(buffer, 256, nodefile);
      ptr = buffer;
      while (*ptr == ' ')
	ptr++;
      if (*ptr == '\0')
	continue;
      if (*ptr == '!')
	continue;
      if (*ptr == '#')
      {
	if (nodefound)
	{
	  ptr++;
	  number = *ptr - '0';
	  if (number < 0 || number > 9)
	    fprintf(stderr, "Error in Nodefile\n"), exit(1);
	  ptr++;
	  sscanf(ptr, "%s", NodesInfoBuffer[cnt].Naliases[number]);
	}
	else
	  fprintf(stderr, "No host decleared\n"), exit(1);
      }
      else
      {

	cnt++;
	sscanf(ptr, "%s %f\n", NodesInfoBuffer[cnt].name, &NodesInfoBuffer[cnt].arch);
	NodesInfoBuffer[cnt].arch = -NodesInfoBuffer[cnt].arch;
	nodefound = TRUE;
      }
    }
  }
  if (cnt == -1)
  {
    if (filename == NULL)
      fprintf(stderr,
	      "LoadNodes: could not load any nodes from default nodefile\n");
    else
      fprintf(stderr, "LoadNodes: could not load any nodes from '%s'\n", filename);
    exit(1);
  }
  *NodesNumber = cnt + 1;
  fclose(nodefile);
}

/*
 * Some words about what the network stuff is:
 * 
 * During the first days of this system, I thought to add the ability to be used
 * even if the nodes we wish to run our system are not connected on the same
 * physical network. Some experiments, probably wrong, showed me that I could
 * broadcast from a node of one Ethernet to another Ethernet. But I can't seem
 * to make it work. The only solution that I know to work is to specify
 * different netfiles for every network and inside each one will be the nodes
 * of all the other networks and the address of this network. Of course, this
 * means that the Tuple Manager will have to reach, the machines on the other
 * networks by doing as many calls as the machines on the other network are.
 */

void
LoadNetworks(filename, BroadcastAddress, NetworksNumber, UdpPort)	/* Load the networkfile
									 * info */
  char           *filename;
  struct sockaddr_in BroadcastAddress[];
int            *NetworksNumber, UdpPort;
{
  FILE           *netfile = NULL;
  char            net[32], num[32];

  *NetworksNumber = 0;
  if (filename == NULL)
  {
    char            buffer[256];
    strcpy(buffer, getenv("HOME"));
    strcat(buffer, "/.networks");

    if (access("./.networks", F_OK) == 0)
      netfile = fopen("./.networks", "r");
    else if (access(buffer, F_OK) == 0)
      netfile = fopen(buffer, "r");
    else
    {
      BroadcastAddress[0].sin_family = AF_INET;
      BroadcastAddress[0].sin_port = htons(UdpPort);
      BroadcastAddress[0].sin_addr.s_addr = htonl(INADDR_ANY);
      *NetworksNumber = 1;
    }
  }
  else if (access(filename, F_OK) == 0)
    netfile = fopen(filename, "r");
  else
  {
    fprintf(stderr, "LoadNetworks: cannot find init file '%s'\n", filename);
    exit(1);
  }
  if (netfile != NULL)
  {
    while (!feof(netfile))
    {
      fscanf(netfile, "%s %s\n", net, num);
      if (strcmp(net, "") != 0 && net[0] != '!')
      {
	BroadcastAddress[*NetworksNumber].sin_family = AF_INET;
	BroadcastAddress[*NetworksNumber].sin_port = htons(UdpPort);
	BroadcastAddress[*NetworksNumber].sin_addr.s_addr = inet_addr(num);
	*NetworksNumber += 1;
      }
    }
    fclose(netfile);
  }
}

char           *
FindLocalName(prefix)
  char           *prefix;
{
  static char     buf[128];

  struct sockaddr_in LocalAddress;

  get_myaddress(&LocalAddress);

  /* Reason for modification by NM:  It turns out that there was 
     another problem with having everyone run their own invocation of 
     the tuple manager:  It uses a UNIX-domain socket, which sets its 
     i.d. via a file name.  POSYBL chose to hard-code the file name, 
     as /tmp/.TMANAGER<machine IP address>, which means that after 
     one invocation of tmanager is running on a given machine, no 
     other invocation could do so, as they would use the same file 
     name for the i.d.  So, I've made another change to the POSYBL 
     source code, in the file---I've used getuid() to add your own 
     user i.d. to the end of that file name, thus making it distinct. */

  /* this line modified by NM: */
  sprintf(buf, "%s%08X%d", prefix, LocalAddress.sin_addr.s_addr, getuid()); 

  return (buf);
}

char           *
FixName(node, str, NodesInfoBuffer, NodesNumber)	/* Fixes a string by
							 * replaces the node
							 * variables with their
							 * content */
  register char  *node, *str;
  NODEINFO       *NodesInfoBuffer;
  register int    NodesNumber;
{
  register int    i, n;
  char           *result = (char *) malloc(256);
  char           *ptr = result;
  int             a = strlen(node), number;

  for (i = 0; i < NodesNumber; i++)
  {
    n = strlen(NodesInfoBuffer[i].name);
    if (n > a)
      n = a;
    if (strncmp(node, NodesInfoBuffer[i].name, n) == 0)
      break;
  }
  if (i == NodesNumber)
    strcpy(result, str);
  while (*str != '\0')
  {
    while (*str != '\0' && *str != '#')
      *result++ = *str++;
    if (*str == '#')
    {
      str++;
      number = *str - '0';
      if (number < 0 || number > 9)
	fprintf(stderr, "Error in expanding a # variable\n"), exit(1);
      str++;
      *result = '\0';
      strcpy(result, NodesInfoBuffer[i].Naliases[number]);
      result += strlen(NodesInfoBuffer[i].Naliases[number]);
    }
    else
      *result = '\0';
  }
  return (ptr);
}
