 /*
  * Khoros: $Id: distrib_util.c,v 1.4 1992/03/25 17:30:55 dkhoros Exp $
  */

#if !defined(lint) && !defined(SABER)
static char rcsid[] = "Khoros: $Id: distrib_util.c,v 1.4 1992/03/25 17:30:55 dkhoros Exp $";
#endif

 /*
  * $Log: distrib_util.c,v $
 * Revision 1.4  1992/03/25  17:30:55  dkhoros
 * VirtualPatch5
 *
  */ 


/*
 *----------------------------------------------------------------------
 *
 * Copyright 1990, University of New Mexico.  All rights reserved.
 * Permission to copy and modify this software and its documen-
 * tation only for internal use in your organization is hereby
 * granted, provided that this notice is retained thereon and
 * on all copies.  UNM makes no representations as too the sui-
 * tability and operability of this software for any purpose.
 * It is provided "as is" without express or implied warranty.
 * 
 * UNM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT-
 * NESS.  IN NO EVENT SHALL UNM BE LIABLE FOR ANY SPECIAL,
 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY OTHER DAMAGES WHAT-
 * SOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PER-
 * FORMANCE OF THIS SOFTWARE.
 * 
 * No other rights, including for example, the right to redis-
 * tribute this software and its documentation or the right to
 * prepare derivative works, are granted unless specifically
 * provided in a separate license agreement.
 *---------------------------------------------------------------------
 */

#include "unmcopyright.h"	 /* Copyright 1990 by UNM */
#include "transport.h"	
#include "daemon.h"	
#include "vsignal.h"	


/* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
   >>>>								<<<<
   >>>>	    file name: distrib_util.c				<<<<
   >>>>								<<<<
   >>>>   description: Distributed support utility		<<<<
   >>>>								<<<<
   >>>>      public routines:	   kcloseall			<<<<
   >>>>      			   ktransport_list		<<<<
   >>>>      			   khost_list			<<<<
   >>>>      			   khost_remote			<<<<
   >>>>      			   kmake_command		<<<<
   >>>>      			   ktransport_permanence	<<<<
   >>>>								<<<<
   >>>>      semi-public routines: kfile_free			<<<<
   >>>>      			   kfile_get_entry		<<<<
   >>>>      			   kfile_add_entry		<<<<
   >>>>      			   kfile_delete_entry		<<<<
   >>>>      			   kfile_delete_entry		<<<<
   >>>>								<<<<
   >>>>      private routines:	   transport_token		<<<<
   >>>>      			   transport_location		<<<<
   >>>>      			   transport_identifier		<<<<
   >>>>      			   transport_routines		<<<<
   >>>>      			   transport_machine		<<<<
   >>>>								<<<<
   >>>>								<<<<
   >>>>      			   fopen_flags			<<<<
   >>>>      			   open_flags			<<<<
   >>>>      			   command_args			<<<<
   >>>>      			   build_command		<<<<
   >>>>								<<<<
   >>>>      			   daemon_start			<<<<
   >>>>      			   daemon_routines		<<<<
   >>>>								<<<<
   >>>> modifications:						<<<<
   >>>>								<<<<
   >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */



#define ALLOCSIZE 100

static int    num_kfile_entries = 0;
static kfile  **kfile_entries = NULL;


/*
 *  The following are public routines that the user is allowed to call.
 *  Most of these utilities are used by routines that wish to do more than
 *  use the simple transport mechanisms.
 *
 *	routines:	kcloseall
 *			ktransport_list
 *			ktransport_permanence
 *			khost_list
 *			khost_remote
 *			kmake_command
 */



/**************************************************************
*
* MODULE NAME: kcloseall()
*
*     PURPOSE: This function is used to close all entries and
*	       remove the entries from the table.  A status
*	       of 0 or -1 will be returned indicating
*	       whether the all entries were successfully closed.
*	       If any entry could not be closed then a status
*	       of -1 is returned, otherwise if *all* entries
*	       were successfully closed then 0 is returned.
*
*
*       INPUT: entry - the entry from the table to be cleared
*
*      OUTPUT: returns the status of the closing of the open()
*	       files.
*
* CALLED FROM: various kfile utilities
*
*  WRITTEN BY:  Mark Young
*
**************************************************************/


int kcloseall()
{
	kfile	*file;
	int	i, status = TRUE;
	TransportInformation *routines;



	for (i = 3; i < num_kfile_entries; i++)
	{
	   /*
	    *  Retrieve the file entry from the table and then NULL the
	    *  entry out of the table.
	    */
	   if ((file = kfile_entries[i]) != NULL)
	   {
	      routines = file->routines;
	      kfile_entries[i] = NULL;

	      /*
	       *  Call the kfile "close()" routine to do the actual closing of
	       *  that transport.
	       */
	      status |= routines->close(file);
	      kfile_free(file);
	   }
	}
	return(status);
}



/**************************************************************
*
* MODULE NAME: ktransport_list()
*
*     PURPOSE: This function is used to return the list of transports
*	       identifiers.
*
*
*       INPUT: local  - a boolean indicating that local transports
*			should be listed
*              remote - a boolean indicating that only remote transports
*			should be listed
*              permanence - a boolean indicating that data paermanent
*			transports should be listed
*              permanence - a boolean indicating that stream based transports
*			should be listed
*
*      OUTPUT: num_entries - the number of entries returned
*
*	       returns the known transports (otherwise NULL)
*
* CALLED FROM: various kfile utilities
*
*  WRITTEN BY:  Mark Young
*
**************************************************************/

char **ktransport_list(local, remote, permanence, stream, num_entries)

int	local;
int	remote;
int	permanence;
int	stream;
int	*num_entries;
{
	int	i, j, num = ALLOCSIZE;
	char	**list, temp[LENGTH];


	if ((list = (char **) kmalloc(num * sizeof(char *))) == NULL)
	{
	   fprintf(stderr,"ktransport_list:  Not enough memory....\n\n");
	   fprintf(stderr,"  Unable to malloc (%d) bytes for the khoros \
transport list.\n", num*sizeof(char *));
	   return(NULL);
	}

	for (i = 0, j = 0; i < NumTransports; i++)
	{
	   if (((TRANSPORT(transports[i]) & LocalTransport && local == TRUE) ||
	       (TRANSPORT(transports[i]) & RemoteTransport && remote == TRUE))&&
	       ((transports[i]->data_permanence && permanence == TRUE) ||
	        (!transports[i]->data_permanence && stream == TRUE)))
	    {
	       if (j >= num)
	       {
	          num += ALLOCSIZE;
		  if ((list = (char **) krealloc(list, num * sizeof(char *))) ==
				NULL)
		  {
		     fprintf(stderr,"ktransport_list: Not enough memory..\n\n");
		     fprintf(stderr,"  Unable to malloc (%d) bytes for the \
khoros transport list.\n", num*sizeof(char *));
		     return(NULL);
		  }
	       }

	       if (transports[i]->label == NULL)
		  sprintf(temp, "%10s", transports[i]->identifier);
	       else
		  sprintf(temp, "%10s  (%s)", transports[i]->identifier,
			transports[i]->label);

	       list[j++] = VStrcpy(temp);
	    }
	}
	*num_entries = j;
	return(list);
}



/**************************************************************
*
* MODULE NAME: ktransport_permanence()
*
*     PURPOSE: This function is used to return whether a particular
*	       file or transport identifier is a permanent data
*	       transport (like shared memory) or a connection oriented
*	       protocol like (stream or sockets).
*
*
*       INPUT: path  - path of identifier to inquire about
*
*      OUTPUT: returns TRUE or FALSE depending whether the transport
*	       is known to support data permanence or -1 upon error
*
* CALLED FROM: various kfile utilities
*
*  WRITTEN BY:  Mark Young
*
**************************************************************/

int ktransport_permanence(path)

char	*path;
{
	TransportInformation *routines;
	char	*identifier, temp[LENGTH];


	/*
	 *  According to the transport routines
	 */
	if ((identifier = transport_identifier(path, temp)) == NULL)
	{
	   if ((routines = transport_routines(path)) == NULL)
	      routines = transport_routines(identifier);
	}
	else
	   routines = transport_routines(identifier);

	if (routines == NULL)
	   return(-1);
	else
	   return(routines->data_permanence);
}



/**************************************************************
*
* MODULE NAME: khost_list()
*
*     PURPOSE: This function is used to return the list of initial
*	       machines to try using.  They are gotten via the user
*	       specified file and also by broadcasting to see if any
*	       khoros daemons are available (Not Available as of yet).
*
*
*       INPUT: none
*
*      OUTPUT: 
*	       num_entries - the number of entries returned
*
*	       returns list of machines (otherwise NULL)
*
* CALLED FROM: various kfile utilities
*
*  WRITTEN BY:  Mark Young
*
**************************************************************/

char **khost_list(num_entries)

int	*num_entries;
{
	static  char **list;
	static  int num, initialized = FALSE;


	if (initialized == FALSE)
	{
	   initialized = TRUE;
	   if (khoros_hosts_file != NULL)
	      list = vlistfile(khoros_hosts_file, "$USER", TRUE, &num);
	   else
	   {
	      list = NULL;
	      num = 0;
	   }
	}
	*num_entries = num;
	return(list);
}



/**************************************************************
*
* MODULE NAME: khost_remote(machine)
*
*     PURPOSE: This function is used to see if a host is remote or
*	       not. 
*
*
*       INPUT: machine - the machine which we wish to find out about
*
*      OUTPUT: none
*
* CALLED FROM: various kfile utilities
*
*  WRITTEN BY:  Mark Young
*
**************************************************************/


int khost_remote(machine)

char	*machine;
{
	char *temp, value[LENGTH], temp2[LENGTH];


	if (machine == NULL)
	   return(NULL);

	strcpy(value, machine);
	if ((temp = (char *) vcleanup_string(value, temp2)) == NULL)
	   return(NULL);
	if ((temp = (char *) vlower_string(temp, value)) == NULL)
	   return(NULL);

	if (strcmp(temp, "localhost") == 0)
	   return(FALSE);
	else if (kgethostname(NULL, temp2, LENGTH) != NULL)
	{
	   if (strcmp(temp, temp2) == 0)
	      return(TRUE);
	   else
	      return(FALSE);
	}
	return(TRUE);
}



/**************************************************************
*
* MODULE NAME: kmake_command(machine, command)
*
*     PURPOSE: This function make a proper command that the transport
*	       mechanisms will interpet as command@machine.  If a
*	       command of "ls -al" is given and they wish to execute
*	       that command on the machine "borris".  Then a new string
*	       will that looks like "ls@borris -al" will be returned.
*
*
*       INPUT: machine - the machine which we wish to find out about
*
*	       command - the command to be executed
*
*      OUTPUT: returns a malloc'ed string containing the proper form
*	       of the command@machine syntax
*
* CALLED FROM: various kfile utilities (public)
*
*  WRITTEN BY:  Mark Young & Becky Bishop
*
**************************************************************/


char *kmake_command(machine, command)

char	*machine;
char	*command;
{
	int  indx;
	char *temp, *mtemp, *ctemp, string[LENGTH];


	if (machine == NULL)
	   mtemp = NULL;
	else
	   mtemp = vcleanup_string(machine, NULL);

	if (command == NULL)
	   ctemp = NULL;
	else
	   ctemp = vcleanup_string(command, NULL);

	if (mtemp == NULL)
	   return(VStrcpy(ctemp));
	else if (ctemp == NULL)
	   return(NULL);

	if ((temp = strchr(ctemp, ' ')) != NULL)
	{
	   indx = temp - ctemp;
	   strncpy(string, ctemp, indx);
	   string[indx] = '@';
	   string[indx+1] = '\0';
	   temp = VStr3cat(string, mtemp, temp);
	}
	else if ((temp = strchr(ctemp, '\t')) != NULL)
	{
	   indx = temp - ctemp;
	   strncpy(string, ctemp, indx);
	   string[indx] = '@';
	   string[indx+1] = '\0';
	   temp = VStr3cat(string, mtemp, temp);
	}
	else
	{
	   temp = VStr3cat(command, "@", mtemp);
	}
	free(mtemp);
	free(ctemp);
	return(temp);
}



/*
 *  The following are semiprivate routines and should *usually* not be called
 *  by the application programmer.  These routines are available for the
 *  more sophisticated application.  These routines are used as utilities
 *  by the public routines found in "transport.c".  The reason why they are
 *  semi-public is that there maybe an occasion when the user needs a
 *  "transport" routine like kopen(), but slightly different.  In which case
 *  may find these routines helpful.
 *
 *	routines:
 *			kfile_free
 *			kfile_get_entry
 *			kfile_add_entry
 *			kfile_delete_entry
 */


/**************************************************************
*
* MODULE NAME: kfile_get_entry(entry)
*
*     PURPOSE: This function is used to retrieve a kfile structure
*	       from 
*	       with the kfile structure.
*
*
*       INPUT: file - the kfile structure to be freed.
*
*      OUTPUT: none
*
* CALLED FROM: various kfile utilities
*
*  WRITTEN BY:  Mark Young
*
**************************************************************/


kfile *kfile_get_entry(entry)

int	entry;
{
	if (entry >= num_kfile_entries || kfile_entries == NULL)
	   return(NULL);
	else
	   return(kfile_entries[entry]);
}



/**************************************************************
*
* MODULE NAME: kfile_add_entry(entry)
*
*     PURPOSE: This function is used to retrieve a kfile structure
*	       from 
*	       with the kfile structure.
*
*
*       INPUT: file - the kfile structure to be freed.
*
*      OUTPUT: none
*
* CALLED FROM: various kfile utilities
*
*  WRITTEN BY:  Mark Young
*
**************************************************************/

int kfile_add_entry(file)

kfile	*file;
{
	int	id, size, num_bytes, old_num_bytes;


	if (kfile_entries == NULL)
	{
	   num_kfile_entries = ALLOCSIZE;

	   kfile_entries = (kfile **) calloc(num_kfile_entries,sizeof(kfile *));
	   if (kfile_entries == NULL)
	   {
	      num_bytes = num_kfile_entries*sizeof(kfile *);
	      (void) fprintf(stderr,"kfile_add_entry: Not enough memory..\n\n");
	      (void) fprintf(stderr,"  Unable to malloc (%d) bytes for kfile \
entry table structure.\n", num_bytes);
	      return(-1);
	   }
	   (void) kopen("-", O_RDONLY, 0); /* stdin  */
	   (void) kopen("-", O_WRONLY, 0); /* stdout */
	   (void) kopen("#", O_WRONLY, 0); /* stderr */
	}

	/*
	 *  See if there are any free entries in the current table
	 *  before allocating any more space for new entries.
	 */
	for (id = 0; id < num_kfile_entries; id++)
	{
	   if (kfile_entries[id] == NULL)
	   {
	      file->id = id;
	      kfile_entries[id] = file;
	      return(id);
	   }
	}

	size = num_kfile_entries + ALLOCSIZE;
	num_bytes = size*sizeof(kfile *);
	kfile_entries = (kfile **) realloc(kfile_entries, num_bytes);
	if (kfile_entries == NULL)
	{
	   (void) fprintf(stderr,"kfile_add_entry: Not enough memory..\n\n");
	   (void) fprintf(stderr,"  Unable to malloc (%d) bytes for kfile \
entry table structure.\n", num_bytes);
	   return(-1);
	}

	/*
	 *  Need to zero out the new entries so that they indicate empty
	 *  table entries.
	 */
	old_num_bytes = num_kfile_entries*sizeof(kfile *);
	bzero(&kfile_entries[num_kfile_entries], num_bytes-old_num_bytes);

	/*
	 *  Assign the kfile structure to the first new entry and then update
	 *  the "num_kfile_entries" to the new table size.
	 */
	id = num_kfile_entries;
	num_kfile_entries = size;

	kfile_entries[id] = file;
	return(id);
}



/**************************************************************
*
* MODULE NAME: kfile_delete_entry(entry)
*
*     PURPOSE: This function is used to remove a kfile entry
*	       from the entry table.
*
*
*       INPUT: entry - the entry from the table to be cleared
*
*      OUTPUT:  returns 0 or -1 if an error occurs
*
* CALLED FROM: various kfile utilities
*
*  WRITTEN BY:  Mark Young
*
**************************************************************/


int kfile_delete_entry(entry)

int	entry;
{
	if (entry >= num_kfile_entries || kfile_entries == NULL)
	   return(-1);
	else
	   kfile_entries[entry] = NULL;

	return(0);
}



/**************************************************************
*
* MODULE NAME: kfile_free(file)
*
*     PURPOSE: This function is used to free the resources associated
*	       with the kfile structure.
*
*
*       INPUT: file - the kfile structure to be freed.
*
*      OUTPUT: none
*
* CALLED FROM: various kfile utilities
*
*  WRITTEN BY:  Mark Young
*
**************************************************************/

kfile_free(file)

kfile *file;
{
	if (file->path != NULL)
	   free(file->path);

	if (file->resources != NULL)
	   free(file->resources);

	free(file);
}



/*
 *  The following are private routines and should not be called by the
 *  application programmer.
 *
 *	routines:
 *			transport_routines
 *			transport_identifier
 *			transport_location
 *			transport_token
 *			transport_machine
 *			daemon_start
 *			daemon_routines
 */

/**************************************************************
*
* MODULE NAME: transport_routines(identifier)
*
*     PURPOSE: This function is used to find the appropriate transport
*	       information
*
*
*       INPUT: identifier - the transport identifier string
*
*      OUTPUT: none
*
* CALLED FROM: various kfile utilities
*
*  WRITTEN BY:  Mark Young
*
**************************************************************/


TransportInformation *transport_routines(identifier)

char	*identifier;
{
	int	i;


	if (identifier == NULL)
	   return(DefaultTransport);

	for (i = 0; i < NumTransports; i++)
	{
	   if (transports[i] != NULL)
	   {
	      if (transports[i]->identifier == NULL)
		 continue;
	      else if (strcmp(identifier, transports[i]->identifier) == 0)
		 return(transports[i]);
	   }
	}
	return(NULL);
}



/**************************************************************
*
* MODULE NAME: transport_identifier(name, identifier)
*
*     PURPOSE: This function is used to find the transport identifier
*
*
*       INPUT: name - the transport string
*
*      OUTPUT: none
*
* CALLED FROM: various kfile utilities
*
*  WRITTEN BY:  Mark Young
*
**************************************************************/


char *transport_identifier(name, identifier)

char	*name, *identifier;
{
	int  i, num;
	char *temp, value[LENGTH];


	if (name == NULL)
	   return(NULL);

	if ((temp = strrchr(name, '@')) != NULL)
	{
	   for (i = 0; i < NumTransports; i++)
	   {
	      if (transports[i] != NULL)
	      {
	         if (transports[i]->identifier == NULL ||
		     transports[i]->remote == NULL)
		 {
		    continue;
		 }
	         else if (transports[i]->remote != NULL)
		 {
		    return(transports[i]->identifier);
		 }
	      }
	   }
	   return("@");
	}
	else if ((temp = strchr(name, '=')) != NULL)
	{
	   num = (temp-name);
	   strncpy(value, name, num);
	   value[num] = '\0';
	   identifier = (char *) vcleanup_string(value, identifier);
	}
	else
	   identifier = NULL;

	return(identifier);
}



/**************************************************************
*
* MODULE NAME: transport_token(name, identifier)
*
*     PURPOSE: This function is used to find the token part of
*	       the transport
*
*
*       INPUT: name - the transport string
*
*      OUTPUT: none
*
* CALLED FROM: various kfile utilities
*
*  WRITTEN BY:  Mark Young
*
**************************************************************/


char *transport_token(name, token)

char	*name, *token;
{
	char *temp, value[LENGTH];


	if (name == NULL)
	   return(NULL);

	if ((temp = strrchr(name, '@')) != NULL)
	{
	   token = (char *) vcleanup_string(name, token);
	}
	else if ((temp = strchr(name, '=')) != NULL)
	{
	   strcpy(value, temp+1);
	   token = (char *) vcleanup_string(value, token);
	}
	else
	{
	   token = (char *) vcleanup_string(name, token);
	}
	return(token);
}



/**************************************************************
*
* MODULE NAME: transport_location(name, location)
*
*     PURPOSE: This function is used to find the location or
*	       machine in which the user wants to re-direct to
*	       via some transport.
*
*
*       INPUT: string - the transport string
*
*      OUTPUT: location - the location to execute the command
*	       string   - the string will be modified to hold the
*			  original string minus the machine in
*			  which we will executing.
*
* CALLED FROM: various kfile utilities
*
*  WRITTEN BY:  Mark Young
*
**************************************************************/


char *transport_location(string, location)

char	*string, *location;
{
	char *temp, *term, value[5*LENGTH];


	if (string == NULL)
	   return(NULL);

	/*
	 *  Copy the name into the location and then terminate the
	 *  string after finding the first available space or tab.
	 */
	strcpy(value, string);
	if ((term = strchr(value,' ')) || (term = strchr(value,'\t')))
	   *term++ = '\0';

	if ((temp = strrchr(value,'@')) != NULL)
	{
	   location = (char *) vcleanup_string(temp+1, location);
	   strncpy(string, value, temp-value); string[temp-value] = '\0';
	   strcat(string, " "); strcat(string, term);
	}
	else
	   location = NULL;

	return(location);
}



/**************************************************************
*
* MODULE NAME: transport_machine(machine, identifier)
*
*     PURPOSE: This function is used to find the type of transport
*	       identifier necessary in  or
*	       machine in which the user wants to re-direct to
*	       via some transport.
*
*
*       INPUT: machine - the machine which we wish to find
*
*      OUTPUT: none
*
* CALLED FROM: various kfile utilities
*
*  WRITTEN BY:  Mark Young
*
**************************************************************/


char *transport_machine(machine, identifier)

char	*machine, *identifier;
{
	char *temp, value[LENGTH], temp2[LENGTH];


	if (machine == NULL)
	   return(NULL);

	strcpy(value, machine);
	if ((temp = transport_identifier(value, identifier)) != NULL)
	   return(temp);
	else
	{
	   if ((temp = (char *) vcleanup_string(value, temp2)) == NULL)
	      return(NULL);
	   if ((temp = (char *) vlower_string(temp, value)) == NULL)
	      return(NULL);

	   if (strcmp(temp, "localhost") == 0)
	      temp = NULL;
	   else if (kgethostname(NULL, temp2, LENGTH) != NULL)
	   {
	      if (strcmp(temp, temp2) == 0)
		 temp = NULL;
	      else
		 temp = transport_identifier("@", identifier);
	   }
	   else
	      temp = transport_identifier("@", identifier);
	}
	return(temp);
}



/**************************************************************
*
* MODULE NAME: fopen_flags(oflags, type)
*
*     PURPOSE: This function is used to convert 
*
*
*       INPUT: oflags - the machine which we wish to find
*
*      OUTPUT: type - the fopen type field (NULL upon failure)
*
* CALLED FROM: various kfile utilities
*
*  WRITTEN BY:  Mark Young
*
**************************************************************/


char *fopen_flags(oflags, type)

int	oflags;
char	*type;
{
	char	temp[LENGTH];


	if (O_RDWR & oflags)
	{
	   strcpy(temp, "r+");
	}
	else if (O_WRONLY & oflags)
	{
	   if (O_TRUNC & oflags || O_CREAT & oflags)
	      strcpy(temp, "w+");
	   else
	      strcpy(temp, "w");
	}
	else if (O_APPEND & oflags)
	{
	   if (O_CREAT & oflags)
	      strcpy(temp, "a+");
	   else
	      strcpy(temp, "a");
	}
	else
	   strcpy(temp, " ");

	if (type == NULL)
	   type = VStrcpy(temp);
	else
	   strcpy(type, temp);

	return(type);
}



/**************************************************************
*
* MODULE NAME: open_flags(type)
*
*     PURPOSE: This function is used to convert 
*
*
*       INPUT: type - the fopen flags
*
*      OUTPUT: returns open flags or -1 upon failure
*
* CALLED FROM: various kfile utilities
*
*  WRITTEN BY:  Mark Young
*
**************************************************************/


int open_flags(type)

char	*type;
{
	int	i, oflags = 0;


	switch (type[0])
	{
	   case 'r':
	   case 'R':
		oflags = ((type[1] == '+') ? O_RDWR : O_RDONLY);
		if (type[0] == 'R') oflags |= (O_NONBLOCK | O_NDELAY);
	 	break;

	   case 'w':
	   case 'W':
	   case 'a':
	   case 'A':
		oflags = ((type[1] == '+') ? O_RDWR : O_WRONLY) | O_CREAT;
		if (type[0] == 'W' || type[0] == 'A')
		   oflags |= (O_NONBLOCK | O_NDELAY);

		if (type[0] == 'a' || type[0] == 'A')
		   oflags |= O_APPEND;
		else
		   oflags |= O_TRUNC;
	 	break;
	}
	return(oflags);
}



/**************************************************************
*
* MODULE NAME: daemon_start(identifier, machine)
*
*     PURPOSE: This function is used to start the appropriate daemon
*	       on the remote machine.  Both the identifier and the
*	       machine are optional.  This routine is called by the
*	       different remote transport if they are unable to contact
*	       the remote machine.  The routine will exec "locally" a
*	       program identified by PhantomExec.  This is usually a
*	       the shell script "phantom" which in turns tries to start
*	       the phantomd program on the remote machine.  The reason
*	       why we say usually is because we want to be flexible and
*	       let each site customize the transport & daemon
*	       mechanisms.
*
*	       If the identifier is NULL then the daemon should use a
*	       default transport.  If the machine is NULL then the
*	       daemon should start the daemon locally.
*
*       INPUT: identifier - the transport identifier string
*              machine    - the machine to start the daemon
*
*      OUTPUT: returns the exit status...
*
* CALLED FROM: various kfile utilities
*
*  WRITTEN BY:  Mark Young
*
**************************************************************/


int daemon_start(identifier, machine)

char	*identifier, *machine;
{
	vstatus status;
	vsignal (*handler)();
	int	stat, pid;
	char	command[LENGTH], temp[LENGTH], *args[10];


	strcpy(command, PhantomExec);

	if (machine != NULL)
	{
	   (void) sprintf(temp," %s", machine);
	   (void) strcat(command, temp);
	}

	if (identifier != NULL)
	{
	   (void) sprintf(temp," -transport %s", identifier);
	   (void) strcat(command, temp);
	}
#ifdef VFORK
	pid = vfork();
#else
	pid = fork();
#endif
	if (pid == 0)
	{
	   command_args(command, args);
	   execvp(args[0], args);
	}
	else if (pid > 0)
	{
	   /*
	    *  This entire section of code could be replaced by a single call
	    *  to waitpid() or wait4() call, but since neither of these calls
	    *  seem to be very prolific i guess we will have to wait ;-(.
	    *
	    *  note: we need to cast the compares to int since certain
	    *	     compiliers barf doing void function compares.
	    */
	   handler = signal(SIGCHLD, SIG_DFL);
	   if (((int) handler) == ((int) SIG_DFL) ||
	       ((int) handler) == ((int) SIG_IGN))
	   {
	      /*
	       *  Wait until the process is done
	       */
	      do
	      {
		 stat = vwait3(&status, 0, NULL);
	      }
	      while (stat != pid);

	      stat = WEXITSTATUS(status);
	      (void) signal(SIGCHLD, handler);
	   }
	   else if (((int) handler) != -1)
	   {
	      (void) signal(SIGCHLD, handler);
	      while (kill(pid, SIGCONT) == 0)
	         sleep(1);
	   }
	}
	return(stat);
}



/**************************************************************
*
* MODULE NAME: daemon_routines(identifier)
*
*     PURPOSE: This function is used to find the appropriate daemon
*	       information
*
*
*       INPUT: identifier - the transport identifier string
*
*      OUTPUT: none
*
* CALLED FROM: various kfile utilities
*
*  WRITTEN BY:  Mark Young
*
**************************************************************/


DaemonInformation *daemon_routines(identifier)

char	*identifier;
{
	int	i;


	for (i = 0; i < NumDaemons; i++)
	{
	   if (daemons[i] != NULL)
	   {
	      if (daemons[i]->identifier == NULL)
		 continue;
	      else if (identifier == NULL)
		 return(daemons[i]);
	      else if (strcmp(identifier, daemons[i]->identifier) == 0)
		 return(daemons[i]);
	   }
	}
	return(NULL);
}



/**************************************************************
*
* MODULE NAME: command_args(command, args)
*
*     PURPOSE: This function is used to find the appropriate daemon
*	       information
*
*
*       INPUT: command - the command to parse
*
*      OUTPUT: args - the args structure
*
* CALLED FROM: various kfile utilities
*
*  WRITTEN BY:  Mark Young
*
**************************************************************/


command_args(command, args)

char	*command;
char	*args[];
{
	int     i = 0;
	char	*location, temp[LENGTH], temp2[LENGTH], echar;


	/*
	 *  Parse the command string into seperate arguments tokens...
	 */
	if (strchr(command,'|') || strchr(command,';') || strchr(command,'>') ||
	    strchr(command,'<') || strchr(command,'~'))
	{
	   /*
	    *  Get the machine in which to execute this system.  If the
	    *  location is NULL then we are expected to execute it locally.
	    */
	   if ((location = transport_location(command, temp2)) != NULL)
	   {
	      (void) sprintf(temp, "/bin/csh@%s", location);
	      args[i++] = temp;
	   }
	   else
	      args[i++] = "/bin/csh";

	   args[i++] = "-cf";
	   args[i++] = command;
	}
	else
	{
	   while (*command != '\0' && i < MAX_ARGS)
	   {
	      while (isspace(*command) && *command != '\0')
	         command++;

	      if (*command != '\0')
	      {
	         if (*command == '\'' || *command == '"')
	         {
		    echar = *command++;
		    args[i++] = command;
		    while ((echar != *command) && (*command != '\0'))
		    {
		       if (*command == '\\' && *(command+1) != '\0')
		          command += 2;
		       else
		          command++;
		    }

		    if (*command != '\0')
		       *command = ' ';
	         }
		 else
		    args[i++] = command;

	         while (!isspace(*command) && *command != '\0')
	            command++;

	         if (*command != '\0')
	         {
	            *command = '\0';
	            command++;
	         }
	      }
	   }
	}
	args[i] = NULL;
}



/**************************************************************
*
* MODULE NAME: build_command(args, command)
*
*     PURPOSE: This function is used to build an appropriate command
*	       from an array of arguments.
*
*
*       INPUT: args - the arguments to parse
*
*      OUTPUT: command - the command to build
*
* CALLED FROM: various kfile utilities
*
*  WRITTEN BY:  Mark Young
*
**************************************************************/


build_command(args, command)

char	*args[];
char	*command;
{
	command[0] = '\0';
	while (*args != NULL)
	{
	   if (strchr(*args, ' ') || strchr(*args, '\t'))
	   {
	      strcat(command,"\'");
	      strcat(command, *args);
	      strcat(command,"\'");
	   }
	   else
	      strcat(command, *args);

	   args++;
	   if (*args != NULL) strcat(command," ");
	}
}
