#define	    IDENT	"1A02"
/*
** +--------------------------------------------------------------+
** |                  Paul Scherrer Institute                     |
** |                     SINQ Division				  |
** |                                                              |
** | This software may be used freely by non-profit organizations.|
** | It may be copied provided that the name of P.S.I. and of the |
** | author is included. Neither P.S.I. nor the author assume any |
** | responsibility for the use of this software outside of P.S.I.|
** +--------------------------------------------------------------+
**
** Module Name  . . . . . . . . : [...SINQHM]SinqHM_bootUtil.c
**
** Author   . . . . . . . . . . : D. Maden
** Date of creation . . . . . . : Aug 1999
**
** Updates:
**  1A01 16-Aug-1999 DM	    Initial version.
**---------------------------------------------------------------------------
**  SinqHM_bootUtil.c is a simple TCP/IP server for VxWorks.
**  It obtains information about the VxWorks boot line.
*/
/*
**  To compile and link this program for VxWorks on PSS123, use:
**
	    set src = "lnsa09:tas_src:[sinqhm]"
	    rcp -p "${src}SinqHM_bootUtil.c" SinqHM_bootUtil.c
	    ccvx -I${WIND_BASE}/target/config/all SinqHM_bootUtil.c
** where
	    ccvx = ccppc -O0			\
		    -mcpu=603			\
		    -I${WIND_BASE}/target/h	\
		    -fno-builtin		\
		    -fno-for-scope		\
		    -nostdinc			\
		    -DCPU=PPC603		\
		    -D_GNU_TOOL			\
		    -gdwarf -c -Wimplicit

**  and, on the target,
**
**   -> ld < /home/pss123/aco/maden/wind/SinqHM/Dflt/SinqHM_srv.o
**   -> ld < /home/pss123/aco/maden/wind/SinqHM/SinqHM_bootUtil.o
**   -> taskSpawn "bootUtil", 100, 8, 20000, SinqHM_bootUtil, <port>
**								^
**								|
**   TCP/IP port number of the "bootUtil" service, dflt = 2300 -+
**
**====================================================================
*/
#include    "vxWorks.h"			/* always first */
#include    "taskLib.h"
#include    "sockLib.h"
#include    "bootLib.h"
#include    "rebootLib.h"
#include    "sysLib.h"
#include    "usrLib.h"
#include    "ioLib.h"

#ifdef MV2600
#include "../config/mv2604/config.h"
#else
#if (CPU == PPC603)
#include    "../config/mv1603/config.h"
#elif (CPU == PPC604)
#include    "../config/mv1604/config.h"
#endif
#endif

#include    <stdlib.h>
#include    <stdio.h>
#include    <string.h>
#include    <ctype.h>
#include    <unistd.h>
#include    <errno.h>
#include    <netinet/in.h>
#include    <arpa/inet.h>
#include    <sys/types.h>
#include    <sys/socket.h>
/*
**====================	Global Definitions =====================================
*/

#include    "SinqHM_def.h"

#define	    MAX_ACTIONS	    8
#define	    MAX_ARGS	   10
#define	    SBU_PORT_DFLT  2300	/* The Dflt Internet Port for Server Requests */
/*
**====================	Global Variables =====================================
*/
    uint    Sbu_port;	    /* The port number to use for the service */
    char    Sbu_name[20];   /* Our task name */
/*
**=============================================================================
**  Local routine prototypes.
*/
    int		sbu_doConfig (int skt);
    void	sbu_doReboot ();
    void	sbu_failInet (char *text);
    void	sbu_failInet_str (char *text, char *str);
    void	sbu_getErrno (int *his_errno);
    void	sbu_showHelp (char *errmsg);

    char       *StrJoin (
		    char    *result,
		    int	     result_size,
		    char    *str_a,
		    char    *str_b);
    int		sbu_doConfig (int skt);
/*
**--------------------------------------------------------------------------*/
  int	sbu_doConfig (int skt) {
/*	============
**			Configure the vxWorks boot information
*/
    char	    hdr_buff[8], *p_addr, recd[1024];
    int		    status, i, j, l_recd, bytes_to_come, toklen, changed;
    char	   *boot_line_addr, *b_status, *tok, *body;
    BOOT_PARAMS	    my_boot_params;

	    /*----------------------------------------
	    ** Get the new boot information over the network.
	    **
	    ** Get first 4 bytes which gives the length to follow
	    */
    status = recv (skt, hdr_buff, 4, 0);
    if (status != 4) sbu_failInet ("recv error on bootline header.\n");

    i = sscanf (hdr_buff, "%4d%n", &l_recd, &j);	/* Convert to binary */
    if ((i != 1) || (j != 4)) {
      sprintf (recd, "Header bytes are not ASCII coded decimal: 0x%x 0x%x 0x%x 0x%x\n",
		    hdr_buff[0], hdr_buff[1], hdr_buff[2], hdr_buff[3]);
      sbu_failInet (recd);
    }

    if (l_recd >= sizeof (recd)) {
      sprintf (recd, "Too long for buffer. Buffer length = %d\n", l_recd);
      sbu_failInet (recd);
    }

    bytes_to_come = l_recd;
    p_addr = recd;

    while (bytes_to_come > 0) {
      status = recv (skt, p_addr, bytes_to_come, 0);
      if (status <= 0) break;
      bytes_to_come -= status;
      p_addr += status;
    }
    if (bytes_to_come != 0) {
      if (status < 0) {
	sbu_failInet ("R/W-Socket recv error");
      }else if (status == 0) {
	sbu_failInet ("R/W-Socket recv error -- return code = 0");
      }
      sbu_failInet ("R/W-Socket recv error -- not enough data received");
    }
		    /*
		    ** Initialise the boot line structure with the existing
		    ** contents of the boot line.
		    */
    boot_line_addr = (char *) BOOT_LINE_ADRS; /* Get pointer to the boot line */
    b_status = bootStringToStruct (boot_line_addr, &my_boot_params);
    if (*b_status != EOS) {
      printf ("\n%s: Bad status from \"bootStringToStruct\": 0x%02x\n",
			Sbu_name, *b_status);
      return False;
    }
		    /*
		    ** Now scan through the new boot string replacing items in
		    ** the boot line structure as we find them.
		    */
    printf ("\nNew boot-line items are:\n");
    changed = False;
    tok = strtok (recd, ":\n");
    while (tok != NULL) {
      toklen = strlen (tok);
      if (tok[toklen+1] == '\n') {	/* Watch out for tokens with no body */
	tok = strtok (NULL, ":\n");	/* Skip an empty body */
      }else {
	body = strtok (NULL, "\n");
	if ((strcmp (tok, "bootDev") == 0) && (body != NULL)) {
	  if (strcmp (my_boot_params.bootDev, body) != 0) {
	    changed = True;
	    printf (" boot device          : %s\n", body);
	    strcpy (my_boot_params.bootDev, body);
	  }
	}else if ((strcmp (tok, "procNum") == 0) && (body != NULL)) {
	  status = sscanf (body, "%i%n", &i, &j);
	  if ((status != 1) || (j != strlen (body))) {
	    printf ("\n%s: Bad value found for procNum: \"%s\"\n", Sbu_name, body);
	    return False;
	  }
	  if (my_boot_params.procNum != i) {
	    changed = True;
	    printf (" processor number     : %s\n", body);
	    my_boot_params.procNum = i;
	  }
	}else if ((strcmp (tok, "hostName") == 0) && (body != NULL)) {
	  if (strcmp (my_boot_params.hostName, body) != 0) {
	    changed = True;
	    printf (" host name            : %s\n", body);
	    strcpy (my_boot_params.hostName, body);
	  }
	}else if ((strcmp (tok, "bootFile") == 0) && (body != NULL)) {
	  if (strcmp (my_boot_params.bootFile, body) != 0) {
	    changed = True;
	    printf (" file name            : %s\n", body);
	    strcpy (my_boot_params.bootFile, body);
	  }
	}else if ((strcmp (tok, "ead") == 0) && (body != NULL)) {
	  if (strcmp (my_boot_params.ead, body) != 0) {
	    changed = True;
	    printf (" inet on ethernet (e) : %s\n", body);
	    strcpy (my_boot_params.ead, body);
	  }
	}else if ((strcmp (tok, "bad") == 0) && (body != NULL)) {
	  if (strcmp (my_boot_params.bad, body) != 0) {
	    changed = True;
	    printf (" inet on backplane (b): %s\n", body);
	    strcpy (my_boot_params.bad, body);
	  }
	}else if ((strcmp (tok, "had") == 0) && (body != NULL)) {
	  if (strcmp (my_boot_params.had, body) != 0) {
	    changed = True;
	    printf (" host inet (h)        : %s\n", body);
	    strcpy (my_boot_params.had, body);
	  }
	}else if ((strcmp (tok, "gad") == 0) && (body != NULL)) {
	  if (strcmp (my_boot_params.gad, body) != 0) {
	    changed = True;
	    printf (" gateway inet (g)     : %s\n", body);
	    strcpy (my_boot_params.gad, body);
	  }
	}else if ((strcmp (tok, "usr") == 0) && (body != NULL)) {
	  if (strcmp (my_boot_params.usr, body) != 0) {
	    changed = True;
	    printf (" user (u)             : %s\n", body);
	    strcpy (my_boot_params.usr, body);
	  }
	}else if ((strcmp (tok, "passwd") == 0) && (body != NULL)) {
	  if (strcmp (my_boot_params.passwd, body) != 0) {
	    changed = True;
	    printf (" ftp password (pw)    : %s\n", body);
	    strcpy (my_boot_params.passwd, body);
	  }
	}else if ((strcmp (tok, "flags") == 0) && (body != NULL)) {
	  status = sscanf (body, "%i%n", &i, &j);
	  if ((status != 1) || (j != strlen (body))) {
	    printf ("\n%s: Bad value found for flags: \"%s\"\n", Sbu_name, body);
	    return False;
	  }
	  if (my_boot_params.flags != i) {
	    changed = True;
	    printf (" flags (f)            : %s\n", body);
	    my_boot_params.flags = i;
	  }
	}else if ((strcmp (tok, "targetName") == 0) && (body != NULL)) {
	  if (strcmp (my_boot_params.targetName, body) != 0) {
	    changed = True;
	    printf (" target name (tn)     : %s\n", body);
	    strcpy (my_boot_params.targetName, body);
	  }
	}else if ((strcmp (tok, "startupScript") == 0) && (body != NULL)) {
	  if (strcmp (my_boot_params.startupScript, body) != 0) {
	    changed = True;
	    printf (" startup script (s)   : %s\n", body);
	    strcpy (my_boot_params.startupScript, body);
	  }
	}else if ((strcmp (tok, "other") == 0) && (body != NULL)) {
	  if (strcmp (my_boot_params.other, body) != 0) {
	    changed = True;
	    printf (" other (o)            : %s\n", body);
	    strcpy (my_boot_params.other, body);
	  }
	}else {
	  if (body != NULL) {
	    printf ("\n%s: Bad token found in new boot string: \"%s\" \"%s\"\n",
		Sbu_name, tok, body);
	  }else {
	    printf ("\n%s: Token found with NULL body in new boot string: \"%s\"\n",
		Sbu_name, tok);
	  }
	  printf ("\n%s: Boot string has not been re-configured!\n", Sbu_name);
	  return False;
	}
	tok = strtok (NULL, ":");
      }
    }
    if (!changed) printf (" Nothing has been changed!\n");

    status = bootStructToString (boot_line_addr, &my_boot_params);
    if (status != OK) {
      printf ("\n%s: Bad status from \"bootStringToStruct\": 0x%02x\n", Sbu_name,
			status);
      return False;
    }
    b_status = bootStringToStruct (boot_line_addr, &my_boot_params);
    if (*b_status != EOS) {
      printf ("\n%s: Bad status from \"bootStringToStruct\": 0x%02x\n",
		Sbu_name, *b_status);
      return False;
    }
    printf ("\nResulting vxWorks Boot-Line is:\n"
	      "          =================\n");

    printf (" boot device          : %s\n", my_boot_params.bootDev);
    printf (" processor number     : %d\n", my_boot_params.procNum);
    printf (" host name            : %s\n", my_boot_params.hostName);
    printf (" file name            : %s\n", my_boot_params.bootFile);
    printf (" inet on ethernet (e) : %s\n", my_boot_params.ead);
    printf (" inet on backplane (b): %s\n", my_boot_params.bad);
    printf (" host inet (h)        : %s\n", my_boot_params.had);
    printf (" gateway inet (g)     : %s\n", my_boot_params.gad);
    printf (" user (u)             : %s\n", my_boot_params.usr);
    printf (" ftp password (pw)    : %s\n", my_boot_params.passwd);
    printf (" flags (f)            : 0x%x\n", my_boot_params.flags);
    printf (" target name (tn)     : %s\n", my_boot_params.targetName);
    printf (" startup script (s)   : %s\n", my_boot_params.startupScript);
    printf (" other (o)            : %s\n\n", my_boot_params.other);
		/*
		** Write to non-volatile RAM
		*/
    status = sysNvRamSet (BOOT_LINE_ADRS, strlen (BOOT_LINE_ADRS) + 1, 0);
    if (status != OK) {
      printf ("\n%s: Bad status from \"sysNvRamSet\": 0x%02x\n",
		Sbu_name, status);
      return False;
    }
    return True;
  }
/*
**--------------------------------------------------------------------------*/
  void	sbu_doReboot () {
/*	============
**		    Re-boot the vxWorks system by calling reboot.
*/
    printf ("This processor is about to be re-booted ...\n");
    taskDelay (sysClkRateGet ()/4);
    reboot (BOOT_CLEAR);
    exit (EXIT_SUCCESS);    /* Should not get here! */
  }
/*
**--------------------------------------------------------------------------*/
  void sbu_failInet (char *text) {
/*     =============
**		    Output the given text and exit the process.
*/
    int    my_errno;

    sbu_getErrno (&my_errno);
    printf ("\n### Internet Error ###\n");
    printf (  "                   ### errno = %d.\n", my_errno);
    perror (text);
    exit (EXIT_FAILURE);
  }
/*--------------------------------------------------------------------------*/
  void sbu_failInet_str (char *fmt, char *str) {
/*     ================
**			    Call to failInet with an extra parameter.
*/
    char    my_buff[132];

    sprintf (my_buff, fmt, str);
    sbu_failInet (my_buff);
    /* No return */
  }
/*--------------------------------------------------------------------------*/
  void	sbu_getErrno (int *his_errno) {
/*      =============
*/
    *his_errno = errno;	    /* Make copy of errno   */
    return;
  }
/*
**--------------------------------------------------------------------------*/
  void	sbu_showHelp (char *errmsg) {
/*      =============
*/
    if (errmsg != NULL) {
      printf ("\007\n%s\n", errmsg);
      taskDelay (5 * sysClkRateGet ());	    /* Give user time to read message */
    }
    printf ("\n"
 "The \"other\" field may be specified as follows:\n"
 "\n"
 "        <action>=<arg0>,..,<argn>/<action>=...\n"
 "\n"
 "There must be no white space characters in the string. The string may\n"
 "be specified in upper or lower case.\n"
 "\n"
 "<action> may be \"sp\"  for \"spawn a task\" or\n"
 "                \"cfg\" for \"configure SinqHM_srv\"\n"
 "\n"
 "The following \"sp\" commands are available:\n"
 "\n"
 "  a)        sp=SinqHM,<port>,<use-lev-gen>,<VMIO10-base>\n"
 "     where\n"
 "          <port>        = TCP/IP port number for server. Dflt=2400.\n"
 "          <use-lev-gen> = flag to indicate if timing levels should be\n"
 "                            generated via a VMIO10 module. If non-zero,\n"
 "                            timing levels are generated. Dflt=0.\n"
 "          <VMIO10-base> = base address of VMIO10 level-generator\n"
 "                            module. Dflt=0x1900.\n"
 "     This action spawns the SinqHM histogram memory server task.\n"
 "\n"
 "  b)        sp=lwl,<port>,<VMIO10-base>,<verbosity>\n"
 "     where\n"
 "          <port>        = TCP/IP port number for server. Dflt=3501.\n"
 "          <VMIO10-base> = base address of VMIO10 test-generator\n"
 "                            module. Dflt=0x1800.\n"
 "          <verbosity>   = verbosity flag. If non-zero, the program is\n"
 "                            verbose. Dflt=0.\n"
 "     This action spawns the lwl_server task which can be used to feed\n"
 "     data packets into the hist memory fibre-optic (Licht-Wellen-Leiter)\n"
 "     link via a VMIO10 test-generator. If the test generator is absent,\n"
 "     the action can be omitted to avoid a boot-time error message.\n"
 "\n"
 "The following \"cfg\" commands are available:\n"
 "\n"
 "  a)        cfg=HM_DIG,<#-bins>,<#-hists>,<bin-width>,<compress>,<lo-bin>\n"
 "     where\n"
 "          <#-bins>    = number of bins per histogram. No default.\n"
 "          <#-hists>   = number of defined histograms. Dflt=1.\n"
 "          <bin-width> = Number of bytes per bin. Dflt=4.\n"
 "          <compress>  = Bin compression factor. Dflt=1.\n"
 "          <lo-bin>    = First bin. Dflt=0.\n"
 "\n"
 "  b)        cfg=TOF,<#-bins>,<#-cntrs>,<bin-width>,<compress>,<lo-cntr>\n"
 "     where\n"
 "          <#-bins>    = number of bins per histogram. No default.\n"
 "          <#-cntrs>   = number of neutron counters. No default.\n"
 "          <bin-width> = Number of bytes per bin. Dflt=4.\n"
 "          <compress>  = Bin compression factor. Dflt=1.\n"
 "          <lo-cntr>   = # of first counter. Dflt=0.\n"
 "\n"
 "  c)        cfg=HM_PSD,... same arguments as HM_DIG (for now).\n"
 "\n"
 "For example:\n"
 "       other=\"sp=SinqHM/cfg=HM_DIG,400\"\n"
 "\n");
  }
/*
**==============================================================================
**
**  Main line program
**
**============================================================================*/

  int    SinqHM_bootUtil (int port, int arg2, int arg3, int arg4,
/*	 ===============
*/			  int arg5, int arg6, int arg7, int arg8, int arg9,
			  int suspend) {
/*
**  Arguments:
**	port	    the TCP/IP port number to use. If 0, use default.
**	suspend	    sunspend ourself immediately if non-zero.
*/
    char	       *local_mem, boot_line[1024], buff[128], cmnd[8];
    char	       *my_task_name;
    BOOT_PARAMS		my_params;

    int			status, keep_going, cl_port, my_errno, bl_len;
    char	       *b_status, *p_host;

    int			my_skt;		/* Connection socket */
    int			rw_skt;		/* Read/write socket */
    struct sockaddr_in	lcl_sockname;
    struct sockaddr_in	rmt_sockname;
    int			rmt_sockname_len;
/*============================================================================
*/
    my_task_name = taskName (taskIdSelf());
    if (suspend != 0) {
      printf ("\n%s: Suspending ...\n", my_task_name);
      taskSuspend (0);	    /* We've been told to suspend ourself, ..
			    **  .. presumably for debug reasons.
			    */
      printf ("\n%s:   ... suspension ended!\n", my_task_name);
    }
/*============================================================================
**	Perform the initialisation of variables ...
*/
    StrJoin (Sbu_name, sizeof (Sbu_name), taskName (taskIdSelf ()), "");
    printf ("\n%s: Started -- program ident = \"%s\".\n", Sbu_name, IDENT);

    local_mem = (char *) BOOT_LINE_ADRS;    /* Get pointer to the boot line */
/*============================================================================
*/
    b_status = bootStringToStruct (local_mem, &my_params);    /* Parse boot line */
    if (*b_status != EOS) {
      printf ("\n%s: Bad status from \"bootStringToStruct\": 0x%02x\n",
		Sbu_name, *b_status);
      return False;
    }

    Sbu_port = SBU_PORT_DFLT;
    if ((port >= 128) && (port < 32768)) Sbu_port = port;

/*============================================================================
**	Create a TCP/IP socket for receiving connection requests, bind it and
**	set it to listen.
*/
    my_skt = socket (AF_INET, SOCK_STREAM, 0);
    if (my_skt == -1)
      sbu_failInet_str ("\n%s: socket error", Sbu_name);
    lcl_sockname.sin_family = AF_INET;
    lcl_sockname.sin_port   = htons (Sbu_port);
    lcl_sockname.sin_addr.s_addr = 0;
    status = bind (my_skt, (struct sockaddr *) &lcl_sockname,
					  sizeof (lcl_sockname));
    if (status != 0) sbu_failInet_str ("\n%s: bind error", Sbu_name);

    status = listen (my_skt, 5);
    if (status != 0) sbu_failInet_str ("\n%s: listen error", Sbu_name);

/*
**	    Clients must now connect to us.
**
**	    When a connection arrives, the boot line is sent to the client.
*/
    printf ("\n%s: waiting for connections on Port %d\n", Sbu_name, Sbu_port);
    keep_going = True;
    while (keep_going) {
      rmt_sockname_len = sizeof (rmt_sockname);
      rw_skt = accept (my_skt, (struct sockaddr *) &rmt_sockname,
			    &rmt_sockname_len);
      if (rw_skt == -1) {
	sbu_getErrno (&my_errno);
	sbu_failInet_str ("\n%s: accept error", Sbu_name);
	/* No return */
      }
      p_host = inet_ntoa (rmt_sockname.sin_addr);
      cl_port = ntohs (rmt_sockname.sin_port);

      b_status = bootStringToStruct (local_mem, &my_params); /* Parse boot line */
      if (*b_status != EOS) {
	printf ("\n%s: Bad status from \"bootStringToStruct\": 0x%02x\n", Sbu_name,
		*b_status);
	return False;
      }
      StrJoin (boot_line, sizeof (boot_line), "bootDev:", my_params.bootDev);
      StrJoin (boot_line, sizeof (boot_line), boot_line, "\nprocNum:");
      sprintf (buff, "%d", my_params.procNum);
      StrJoin (boot_line, sizeof (boot_line), boot_line, buff);
      StrJoin (boot_line, sizeof (boot_line), boot_line, "\nhostName:");
      StrJoin (boot_line, sizeof (boot_line), boot_line, my_params.hostName);
      StrJoin (boot_line, sizeof (boot_line), boot_line, "\nbootFile:");
      StrJoin (boot_line, sizeof (boot_line), boot_line, my_params.bootFile);
      StrJoin (boot_line, sizeof (boot_line), boot_line, "\nead:");
      StrJoin (boot_line, sizeof (boot_line), boot_line, my_params.ead);
      StrJoin (boot_line, sizeof (boot_line), boot_line, "\nbad:");
      StrJoin (boot_line, sizeof (boot_line), boot_line, my_params.bad);
      StrJoin (boot_line, sizeof (boot_line), boot_line, "\nhad:");
      StrJoin (boot_line, sizeof (boot_line), boot_line, my_params.had);
      StrJoin (boot_line, sizeof (boot_line), boot_line, "\ngad:");
      StrJoin (boot_line, sizeof (boot_line), boot_line, my_params.gad);
      StrJoin (boot_line, sizeof (boot_line), boot_line, "\nusr:");
      StrJoin (boot_line, sizeof (boot_line), boot_line, my_params.usr);
      StrJoin (boot_line, sizeof (boot_line), boot_line, "\npasswd:");
      StrJoin (boot_line, sizeof (boot_line), boot_line, my_params.passwd);
      StrJoin (boot_line, sizeof (boot_line), boot_line, "\nflags:");
      sprintf (buff, "0x%x", my_params.flags);
      StrJoin (boot_line, sizeof (boot_line), boot_line, buff);
      StrJoin (boot_line, sizeof (boot_line), boot_line, "\ntargetName:");
      StrJoin (boot_line, sizeof (boot_line), boot_line, my_params.targetName);
      StrJoin (boot_line, sizeof (boot_line), boot_line, "\nstartupScript:");
      StrJoin (boot_line, sizeof (boot_line), boot_line, my_params.startupScript);
      StrJoin (boot_line, sizeof (boot_line), boot_line, "\nother:");
      StrJoin (boot_line, sizeof (boot_line), boot_line, my_params.other);

      bl_len = strlen (boot_line) + 1;	/* Get len of line (including term'r) */
      bl_len = (bl_len + 3) & (~3);	/* Round up to a multiple of 4 */
      sprintf (buff, "%04.4d", bl_len);
      status = send (rw_skt, buff, 4, 0);
      if (status != 4) {
	sbu_getErrno (&my_errno);
	sbu_failInet_str ("\n%s: send error on boot-line header", Sbu_name);
	/* No return */
      }
      status = send (rw_skt, boot_line, bl_len, 0);
      if (status != bl_len) {
	sbu_getErrno (&my_errno);
	sbu_failInet_str ("\n%s: send error on boot-line body", Sbu_name);
	/* No return */
      }
	    /*
	    ** Now get a command from the client
	    */
      status = recv (rw_skt, cmnd, 8, 0);
      if (status != 8) {
	sbu_getErrno (&my_errno);
	sprintf (buff, "\n%s: send error on boot-line body", Sbu_name);
	perror (buff);
      }else if (strcmp (cmnd, "CLOSE") == 0) {
	send (rw_skt, "OK\0\0", 4, 0);	/* Acknowledge the command */
      }else if (strcmp (cmnd, "CONFIG") == 0) {
	printf ("\n%s: CONFIG command received from Host %s, Port %d ...\n",
				    Sbu_name, p_host, cl_port);
	status = sbu_doConfig (rw_skt);
	if (status) {
	  send (rw_skt, "OK\0\0", 4, 0);
	}else {
	  send (rw_skt, "Err", 4, 0);
	}
      }else if (strcmp (cmnd, "REBOOT") == 0) {
	printf ("\n%s: REBOOT command received from Host %s, Port %d ...\n",
				    Sbu_name, p_host, cl_port);
	send (rw_skt, "OK\0\0", 4, 0);	/* Acknowledge the command */
	status = close (rw_skt);
	status = close (my_skt);
	sbu_doReboot ();	    /* There is no return from this call! */
      }else if (strcmp (cmnd, "RUNDOWN") == 0) {
	printf ("\n%s: RUNDOWN command received from Host %s, Port %d ...\n",
				    Sbu_name, p_host, cl_port);
	send (rw_skt, "OK\0\0", 4, 0);	/* Acknowledge the command */
	keep_going = False;
      }else {
	printf ("\n%s: unrecognised command received from Host %s, Port %d:"
			"\"%s\"\n", Sbu_name, p_host, cl_port, cmnd);
	send (rw_skt, "Err", 4, 0);
      }
      status = close (rw_skt);
    }
    status = close (my_skt);

    return True;
  }
/*================================= End of SinqHM_bootUtil.c ========*/
