#define	    IDENT	"1A01"
/*---------------------------------------------------------------------------*/
#ifdef __DECC
#pragma	    module	    SINQHM_BOOTUTIL_CLIENT	    IDENT
#endif
/*
** Link_options - Here is the Linker Option File
**!	sinqhm_bootutil_client
**!	tas_src:[lib]sinq_dbg/lib
**!	sys$share:decw$xlibshr/share
**!!
**!!	    To build SINQHM_BOOTUTIL_CLIENT on LNSA09
**!!
**!!	$ import tasmad
**!!	$ define/job deltat_c_tlb sinq_c_tlb
**!!	$ sss := tas_src:[sinqhm]
**!!	$ bui 'sss'sinqhm_bootutil_client debug
** Link_options_end
**
** +--------------------------------------------------------------+
** |                  Paul Scherrer Institute                     |
** |                     Computing Section                        |
** |                                                              |
** | 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_CLIENT.C
**
** Author   . . . . . . . . . . : D. Maden
** Date of creation . . . . . . : Aug 1999
**
**  SINQHM_BOOTUTIL_CLIENT is the main program of an Internet Client which
**  communicates with SINQHM_BOOTUTIL running on a SINQ Histogram Memory.
**  It allows the user to inspect and modify the boot parameters of the
**  histogram memory.
**
** Updates:
**  27-Aug-1999 1A01 DM.    Initial version.
**
**    The following logical name definitions are used ...
**
**	SINQHM_FRONTEND -
**	    "<hostname>, -  The host where SINQHM_BOOTUTIL is running.
**	     <port>"        TCP/IP port number of SINQHM_BOOTUTIL (dflt = 2300).
**====================================================================
*/

#include    <errno.h>
#include    <netdb.h>
#include    <stdio.h>
#include    <stdlib.h>
#include    <signal.h>
#include    <time.h>

#include    <netinet/in.h>

#include    <sys/types.h>
#include    <ctype.h>
#include    <arpa/inet.h>
#include    <math.h>
#include    <sys/socket.h>
#include    <string.h>
#include    <X11/Intrinsic.h>

#ifdef	__VMS
#include    <ucx$inetdef.h>
#include    <sys/unixio.h>
#include    <descrip>
#else
#include    <unistd.h>
#endif

#ifdef __VMS
#include    <sys/ssdef.h>
#include    <sys/starlet.h>
#else
#define	    SS$_NORMAL	    EXIT_SUCCESS
#define	    SS$_BADPARAM    EXIT_FAILURE
#define	    SS$_IVBUFLEN    EXIT_FAILURE
#define	    NO_MEMORY	    4
#endif
/*
**====================	Global Definitions =====================================
*/
#include    <sinq_prototypes.h>

#define	    DFLT_PORT	2300
#define	    NIL		'\0'
#define	    NL		'\n'
#define	    MAXARR	8192
#define	    MAXREC	 512
/*------------------------------------------------------------*/
	    /*
	    **			Define the Data Structures we need
	    */
/*
**====================	Global Variables ======================================
*/
  int			    My_errno, My_vaxc_errno;

  int		Verbose;
  int		Rmt_port;
  char		Rmt_host[32];
  static int	Cnct_skt = 0;	    /* Connect socket */
  static int	Ctrl_C_has_happened;

  static XrmOptionDescRec OpTable_0[] = {
      {"-name",	    ".name",		XrmoptionSepArg, (XPointer) NULL},
      {"-h",	    ".butilHelp",	XrmoptionNoArg,	 (XPointer) "1"},
      {"-he",	    ".butilHelp",	XrmoptionNoArg,	 (XPointer) "1"},
      {"-hel",	    ".butilHelp",	XrmoptionNoArg,	 (XPointer) "1"},
      {"-help",	    ".butilHelp",	XrmoptionNoArg,	 (XPointer) "1"},
      {"-ho",	    ".butilHost",	XrmoptionSepArg, (XPointer) NULL},
      {"-hos",	    ".butilHost",	XrmoptionSepArg, (XPointer) NULL},
      {"-host",	    ".butilHost",	XrmoptionSepArg, (XPointer) NULL},
      {"-port",	    ".butilPort",	XrmoptionSepArg, (XPointer) NULL},
      {"-v",	    ".butilVerbose",	XrmoptionNoArg,	 (XPointer) "1"},
      {"-?",	    ".butilHelpItem",	XrmoptionSepArg, (XPointer) NULL},
    };
/*
**=============================================================================
**  Local routines.
**
**  CtrlC_Handler	: Catch a Ctrl-C interrupt.
**  do_config		: Handle the CONFIG  command
**  do_reboot		: Handle the REBOOT  command
**  do_rundown		: Handle the RUNDOWN command
**  exit_handler	: Exit handler in case a forced exit is made.
**  get_SINQHM_FRONTEND	: Extract info from SINQHM_FRONTEND environment variable
**  openConnection	: Open connection to server.
**  show_help		: Display the help text.
**----------------------------------------------------------------------------
**							    Prototypes
*/
  void	    CtrlC_Handler (int sigint);
  int	    do_config (char *bootline);
  int	    do_reboot ();
  int	    do_rundown ();
  void	    exit_handler ();
  int	    get_check_resources (XrmDatabase *db,
				 char	     *appName,
				 int	     verbose);
  void	    get_SINQHM_FRONTEND (char *host, int host_l, char *host_dflt,
				 int  *port,		 int   port_dflt,
				 int  *pktlen,		 int   pktlen_dflt);
  int	    openConnection (char *host, int port);
  int	    read_boot_line (int skt, char *recd, int s_recd);
  int	    send_a_close (int skt);
  int	    setup_xrm_database (XrmDatabase	*db,
				char		*name[],
				int		*argc,
				char		*argv[],
				int		verbose);
  int	    show_boot_line (char *bootline);
  void	    show_help (char *token);
/*
**--------------------------------------------------------------------------
**		CtrlC_Handler:  Signal handler to detect <Ctrl-C> on keyboard.
*/
  void	CtrlC_Handler (int sigint) {
/*      =============
*/
    Ctrl_C_has_happened = 1;
  }
/*
**--------------------------------------------------------------------------*/
  int	do_config (
/*	=========
**			    Interact with user to get modified config data.
**			    Then send CONFIG command to the target.
*/
		char    *bootline) {	/* The current boot-line */

#define	    MAXP    32

    char    my_bootline[1024], old_bootline[1024];
    char    buff[132], *tok, *nxttok, *body;
    char    prefix[MAXP][64];
    char    prompt[MAXP][64];
    char    bodies[MAXP][128];
    int	    is_numeric[MAXP], is_hex[MAXP];
    int	    i, j, k, status, n_toks, toklen, bootlen;

    StrJoin (my_bootline, sizeof (my_bootline), bootline, "");
    for (i = 0; i < MAXP; i++) is_numeric[i] = is_hex[i] = False;
		    /*
		    ** Scan through the boot-line setting up a table of prompts
		    */
    n_toks = 0;
    tok = strtok (my_bootline, ":\n");
    while ((tok != NULL) && (n_toks < MAXP)) {
      StrJoin (prefix[n_toks], sizeof (prefix[0]), tok, ":");
      toklen = strlen (tok);
      if (tok[toklen+1] == '\n') {	/* Watch out for tokens with no body */
	body = "";
	bodies[n_toks][0] = NIL;
	nxttok = strtok (NULL, ":\n");	/* Skip an empty body */
      }else {
	body = strtok (NULL, "\n");
	if (body == NULL) body = "";
	StrJoin (bodies[n_toks], sizeof (bodies[0]), body, "");
	nxttok = strtok (NULL, ":");
      }
      if ((strcmp (tok, "bootDev") == 0) && (body != NULL)) {
	strcpy (prompt[n_toks], "boot device          : ");
      }else if ((strcmp (tok, "procNum") == 0) && (body != NULL)) {
	strcpy (prompt[n_toks], "processor number     : ");
	is_numeric[n_toks] = True;
	status = sscanf (body, "%i%n", &i, &j);
	if ((status != 1) || (j != strlen (body))) {
	  printf ("do_config: Bad value found for procNum: \"%s\"\n", body);
	  return False;
	}
      }else if ((strcmp (tok, "hostName") == 0) && (body != NULL)) {
	strcpy (prompt[n_toks], "host name            : ");
      }else if ((strcmp (tok, "bootFile") == 0) && (body != NULL)) {
	strcpy (prompt[n_toks], "file name            : ");
      }else if ((strcmp (tok, "ead") == 0) && (body != NULL)) {
	strcpy (prompt[n_toks], "inet on ethernet (e) : ");
      }else if ((strcmp (tok, "bad") == 0) && (body != NULL)) {
	strcpy (prompt[n_toks], "inet on backplane (b): ");
      }else if ((strcmp (tok, "had") == 0) && (body != NULL)) {
	strcpy (prompt[n_toks], "host inet (h)        : ");
      }else if ((strcmp (tok, "gad") == 0) && (body != NULL)) {
	strcpy (prompt[n_toks], "gateway inet (g)     : ");
      }else if ((strcmp (tok, "usr") == 0) && (body != NULL)) {
	strcpy (prompt[n_toks], "user (u)             : ");
      }else if ((strcmp (tok, "passwd") == 0) && (body != NULL)) {
	strcpy (prompt[n_toks], "ftp password (pw)    : ");
      }else if ((strcmp (tok, "flags") == 0) && (body != NULL)) {
	strcpy (prompt[n_toks], "flags (f)            : ");
	is_numeric[n_toks] = True;
	is_hex[n_toks] = True;
	status = sscanf (body, "%i%n", &i, &j);
	if ((status != 1) || (j != strlen (body))) {
	  printf ("do_config: Bad value found for flags: \"%s\"\n", body);
	  return False;
	}
      }else if ((strcmp (tok, "targetName") == 0) && (body != NULL)) {
	strcpy (prompt[n_toks], "target name (tn)     : ");
      }else if ((strcmp (tok, "startupScript") == 0) && (body != NULL)) {
	strcpy (prompt[n_toks], "startup script (s)   : ");
      }else if ((strcmp (tok, "other") == 0) && (body != NULL)) {
	strcpy (prompt[n_toks], "other (o)            : ");
      }else {
	printf ("do_config: Bad token found in boot-line: "
			    "\"%s\" \"%s\"\n", tok, body);
	return False;
      }
      n_toks++;
      tok = nxttok;
    }
    if (tok != NULL) {
      printf ("\007Too many tokens in the boot-line!\n");
      return False;
    }
    if (n_toks <= 0) {
      printf ("\007No tokens in the boot-line!\n");
      return False;
    }
  re_edit:
/*=======
*/  printf ("\n'.' = clear field;  '-' = go to previous field;  ");
#ifdef	__VMS
    printf ("^Z = quit\n\n");
#else
    printf ("^D = quit\n\n");
#endif
    i = 0;
    while (i < n_toks) {
      printf ("%s%s ", prompt[i], bodies[i]);
      if (fgets (buff, sizeof (buff), stdin) == NULL) break;
      if (strlen (buff) == (sizeof (buff) - 1)) {
	printf ("\n\007Input buffer overflow, try again!\n");
	i--;
	return False;
      }
      j = sizeof (buff); StrEdit (buff, buff, "trim compress", &j);
      if (j == 0) {
				/* Empty input -- leave the field unchanged */
      }else if (StrMatch (buff, ".", 1)) {
	bodies[i][0] = NIL;	/* "." -- clear the field */
      }else if (StrMatch (buff, "-", 1)) {
	i -= 2;			/* "-" -- go to previous field */
	if (i < 0) i = -1;
      }else if (j >= sizeof (bodies[0])) {
	printf ("\007Input too long, try again!\n");
	i--;
      }else {
	if (is_numeric[i]) {
	  status = sscanf (buff, "%i%n", &k, &j);
	  if ((status != 1) || (j != strlen (buff))) {
	    printf ("\007Value must be an integer, \"%s\" is invalid. "
			    "Try again!\n", buff);
	    i--;
	  }else {
	    if (is_hex[i]) {
	      sprintf (bodies[i], "0x%x", k);
	    }else {
	      sprintf (bodies[i], "%d", k);
	    }
	  }
	}else {
	  StrJoin (bodies[i], sizeof (bodies[0]), buff, "");
	}
      }
      i++;
    }

    i = printf ("\n\nNew boot-line for %s is:\n", Rmt_host);
    for (j = 3; j < i; j++) printf ("="); printf ("\n");
    my_bootline[0] = NIL;
    for (i = 0; i < n_toks; i++) {
      if (bodies[i][0] != NIL) printf ("%s%s\n", prompt[i], bodies[i]);
      StrJoin (my_bootline, sizeof (my_bootline), my_bootline, prefix[i]);
      StrJoin (my_bootline, sizeof (my_bootline), my_bootline, bodies[i]);
      StrJoin (my_bootline, sizeof (my_bootline), my_bootline, "\n");
    }

    printf ("\nType \"Yes\" to configure, ");
#ifdef	__VMS
    printf ("^Z");
#else
    printf ("^D");
#endif
    printf (" to abandon and anything else to re-edit: ");

    if (fgets (buff, sizeof (buff), stdin) == NULL) return False;
    if (strlen (buff) == (sizeof (buff) - 1)) {
      printf ("\n\007Input buffer overflow, no config performed!\n");
      return False;
    }
    i = sizeof (buff); StrEdit (buff, buff, "trim compress lowercase", &i);
    if (!StrMatch (buff, "yes", 3)) goto re_edit;

    Cnct_skt = openConnection (Rmt_host, Rmt_port);
    read_boot_line (Cnct_skt, old_bootline, sizeof (old_bootline));

    strcpy (buff, "CONFIG");
    bootlen = strlen (my_bootline) + 1;	      /* Get string length */
    bootlen = (bootlen + 3) & (~3);	      /* Round up to a multiple of 4 */
    i = sprintf (&buff[8], "%04.4d", bootlen);  /* Convert to ASCII */
    if (i != 4) {
      printf ("\007The new boot line is too long! CONFIG has not "
				"been performed.\n");
      return False;
    }
    status = send (Cnct_skt, buff, 12, 0);
    if (status != 12) FailInet ("do_config - bad send");
    status = send (Cnct_skt, my_bootline, bootlen, 0);
    if (status != bootlen) FailInet ("do_config - bad send");
    status = recv (Cnct_skt, buff, 4, 0);	    /* Await the response */
    close (Cnct_skt);
    Cnct_skt = 0;
    if (status != 4) {
      FailInet ("do_config - bad recv");
      return False;
    }
    if (!StrMatch (buff, "OK", 2)) {
      printf ("\007Config command rejected by target!\n");
      return False;
    }
    printf ("The boot-line of %s has been re-configured successfully.\n",
			Rmt_host);
    return True;
  }
/*
**--------------------------------------------------------------------------*/
  int	do_reboot (
/*	=========
**			    Send REBOOT command to the target.
*/
		) {

    char    ist_bootline[1024], buff[128];
    int	    i, status;

    printf ("Type \"Yes\" to re-boot %s: ", Rmt_host);
    if (fgets (buff, sizeof (buff), stdin) == NULL) exit (EXIT_FAILURE);
    if (strlen (buff) == (sizeof (buff) - 1)) {
      printf ("\n\007Input buffer overflow, no re-boot performed!\n");
      exit (EXIT_FAILURE);
    }
    i = sizeof (buff); StrEdit (buff, buff, "trim compress lowercase", &i);
    if (!StrMatch (buff, "yes", 3)) {
      printf ("No re-boot performed!\n");
      exit (EXIT_FAILURE);
    }

    Cnct_skt = openConnection (Rmt_host, Rmt_port);
    read_boot_line (Cnct_skt, ist_bootline, sizeof (ist_bootline));

    strcpy (buff, "REBOOT");
    status = send (Cnct_skt, buff, 8, 0);
    if (status != 8) FailInet ("do_reboot - bad send");

    status = recv (Cnct_skt, buff, 4, 0);	    /* Await the response */
    close (Cnct_skt);
    Cnct_skt = 0;
    if (status != 4) {
      FailInet ("do_reboot - bad recv");
      return False;
    }
    if (!StrMatch (buff, "OK", 2)) {
      printf ("\007Reboot command rejected by target!\n");
      return False;
    }
    printf ("%s is rebooting.\n", Rmt_host);
    return True;
  }
/*
**--------------------------------------------------------------------------*/
  int	do_rundown (
/*	==========
**			    Send RUNDOWN command to the target.
*/
		) {

    char    ist_bootline[1024], buff[128];
    int	    i, status;

    printf ("Type \"Yes\" to rundown bootUtil on %s: ", Rmt_host);
    if (fgets (buff, sizeof (buff), stdin) == NULL) exit (EXIT_FAILURE);
    if (strlen (buff) == (sizeof (buff) - 1)) {
      printf ("\n\007Input buffer overflow, no rundown performed!\n");
      exit (EXIT_FAILURE);
    }
    i = sizeof (buff); StrEdit (buff, buff, "trim compress lowercase", &i);
    if (!StrMatch (buff, "yes", 3)) {
      printf ("No rundown performed!\n");
      exit (EXIT_FAILURE);
    }

    Cnct_skt = openConnection (Rmt_host, Rmt_port);
    read_boot_line (Cnct_skt, ist_bootline, sizeof (ist_bootline));

    strcpy (buff, "RUNDOWN");
    status = send (Cnct_skt, buff, 8, 0);
    if (status != 8) FailInet ("do_rundown - bad send");

    status = recv (Cnct_skt, buff, 4, 0);	    /* Await the response */
    close (Cnct_skt);
    Cnct_skt = 0;
    if (status != 4) {
      FailInet ("do_rundown - bad recv");
      return False;
    }
    if (!StrMatch (buff, "OK", 2)) {
      printf ("\007Rundown command rejected by target!\n");
      return False;
    }
    printf ("The bootUtil server on %s is running down.\n", Rmt_host);
    return True;
  }
/*
**---------------------------------------------------------------------------*/
  void exit_handler () {
/*     ============
**                  We must exit. Tidy up first.
**		    Close TCP/IP link to front-end.
*/
    int	    status;
    char    buff[16];
/*
**			Tell server we're quitting.
*/
    if (Cnct_skt != 0) {
      printf ("Closing connection to %s ...\n", Rmt_host);
      status = send (Cnct_skt, "-001", 4, 0);
      status = close (Cnct_skt);
      Cnct_skt = 0;
      if (status != 0) FailInet ("EXIT_HANDLER -- R/W-Socket close error\n");
    }
  }
/*
**--------------------------------------------------------------------------*/
  void	flushNet (
/*	========
**			    Flush bytes from the server.
**
*/		int	nbytes) {	/* Number of bytes to flush */

    char    buff[256];
    int	    i, status, bytes_to_come, bytes_to_get;

    bytes_to_come = nbytes;

    while (bytes_to_come > 0) {
      bytes_to_get = (bytes_to_come > sizeof (buff)) ?
			sizeof (buff) : bytes_to_get;
      status = recv (Cnct_skt, buff, bytes_to_get, 0);
      if (status <= 0) break;
      bytes_to_come -= status;
    }
    if (bytes_to_come != 0) {
      if (status < 0) {
	FailInet ("R/W-Socket recv error in flushNet");
      }else if (status == 0) {
	FailInet ("R/W-Socket recv error in flushNet -- return code = 0");
      }
      exit (EXIT_FAILURE);
    }
  }
/*
**---------------------------------------------------------------------------
**			get_check_resources - get and check our resources
*/
  int	get_check_resources (
/*	===================
*/			    XrmDatabase	*db,
			    char	*appName,
			    int		verbose) {

    int			status, len, do_help;
    char		buff[80];
    char		*type;
    XrmValue		value;
    time_t		time_now;
    float		tmp_secs;
/*----------------------------------------------------------	-help	*/
    status = XrmGetResource (*db,
			     StrJoin (buff, sizeof (buff),
				      appName, ".butilHelp"),
			     "ProgramName.Values",
			     &type, &value);
    do_help = (status) ? True : False;
    if (do_help) {
      show_help (NULL);
      exit (EXIT_SUCCESS);
    }
/*----------------------------------------------------------	-?	*/
    status = XrmGetResource (*db,
			     StrJoin (buff, sizeof (buff),
				      appName, ".butilHelpItem"),
			     "ProgramName.Values",
			     &type, &value);
    do_help = (status) ? True : False;
    if (do_help) {
      len = sizeof (buff);
      StrEdit (buff, value.addr, "trim lowercase", &len);
      show_help (buff);
      exit (EXIT_SUCCESS);
    }
/*----------------------------------------------------------	-verbose */
    status = XrmGetResource (*db,
			     StrJoin (buff, sizeof (buff),
				      appName, ".butilVerbose"),
			     "ProgramName.Values",
			     &type, &value);
    Verbose = verbose = (status) ? True : False;
/*----------------------------------------------------------	-host	*/
    status = XrmGetResource (*db,
			     StrJoin (buff, sizeof (buff),
				      appName, ".butilHost"),
			     "ProgramName.Values",
			     &type, &value);
    if (!status) {
      Rmt_host[0] = NIL;
    }else {
      StrJoin (Rmt_host, sizeof (Rmt_host), value.addr, "");
      if (verbose) printf ("Target processor is \"%s\".\n", Rmt_host);
    }
/*----------------------------------------------------------	-port	*/
    status = XrmGetResource (*db,
			     StrJoin (buff, sizeof (buff),
				      appName, ".butilPort"),
			     "ProgramName.Values",
			     &type, &value);
    if (!status || (sscanf (value.addr, "%d", &Rmt_port) != 1)) {
      Rmt_port = DFLT_PORT;
      if (verbose) printf ("Using the default TCP/IP port number of ");
    }else {
      if (verbose) printf ("TCP/IP  port  number = ");
    }
    if (verbose) printf ("%d\n", Rmt_port);
/*----------------------------------------------------------*/
    return True;
  }
/*
**--------------------------------------------------------------------------*/
  void get_SINQHM_FRONTEND (
/*     ===================
**			    Extract info from the SINQHM_FRONTEND
**			    environment variable.
*/
		char	 *host, int host_l, char *host_dflt,
		int	 *port,		    int	  port_dflt,
		int	 *pktlen,	    int	  pktlen_dflt) {

    int	  env_len;
    char *p_env, *token;
    char  my_env[100];

    p_env = getenv ("SINQHM_FRONTEND");    /* Get pointer to env var */
    if (p_env == NULL) {
			    /* Env. var. not found, prompt the user ... */
      printf ("\n"
	    " The name of the Histogram Memory is defined neither as part of "
							"the command,\n"
	    " nor via the environment variable SINQHM_FRONTEND nor in the "
							"resource data\n"
	    " base. You must therefore specify the details of the Hist Mem "
							"interactively.\n"
	    "\n"
	    " Please specify the following on a single line:\n");
      if ((host_dflt == NULL) || (host_dflt[0] == NIL)) {
	printf ("\n"
	    "    Name of Histogram Memory (no default)\n"
	    "    TCP/IP port number of HM server (default = %d)\n"
	    "    Max send/rcve packet size (default = %d)\n",
	    port_dflt, pktlen_dflt);
      }else {
	printf ("\n"
	    "    Name of Histogram Memory (default = \"%s\")\n"
	    "    TCP/IP port number of HM server (default = %d)\n"
	    "    Max send/rcve packet size (default = %d)\n",
	    host_dflt, port_dflt, pktlen_dflt);
      }
      printf ("\n"
	    "Specify Hist Mem information> ");
      if (fgets (my_env, sizeof (my_env), stdin) == NULL) exit (EXIT_SUCCESS);
      env_len = strlen (my_env);
      if (my_env[env_len-1] != '\n') {
        printf ("Name is too long!\n");
	exit (EXIT_FAILURE);
      }
      env_len = sizeof (my_env);
      StrEdit (my_env, my_env, "uncomment compress trim", &env_len);
    }else {	    /* Make a local copy of it in case the original is in ..
		    ** .. read-protected memory (strtok needs to be able to ..
		    ** .. modify it */
      env_len = sizeof (my_env);
      StrEdit (my_env, p_env, "uncomment compress trim", &env_len);
    }
    token = (env_len == 0) ? NULL : strtok (my_env, " \t\n,"); /* Get host token */
    if ((token == NULL) || (token[0] == ' ')) {
			    /* Host token not found, return defaults */
      StrJoin (host, host_l, host_dflt, "");
      *port	= port_dflt;
      *pktlen	= pktlen_dflt;
    }else {
      StrJoin (host, host_l, token, "");
      token = strtok (NULL, " \t\n,");	/* Get port token */
      if (token == NULL) {
	  *port   = port_dflt;	/* Port token not found, return defaults */
	  *pktlen = pktlen_dflt;
      }else {
	if (sscanf (token, "%d", port) != 1) {
	  *port   = port_dflt;    /* Port token illegal, return defaults */
	  *pktlen = pktlen_dflt;
	}else {
	  token = strtok (NULL, " \t,");    /* Get packet-size token */
	  if (token == NULL) {
	    *pktlen = pktlen_dflt; /* Packet-size token not found, use dflt */
	  }else {
	    if (sscanf (token, "%d", pktlen) != 1) {
	      *pktlen = pktlen_dflt;	/* Packet-size token illegal, use dflt */
	    }
	  }
	}
      }
    }
  }
/*
**--------------------------------------------------------------------------*/
  int	openConnection (
/*	==============
**			Open connection to histogram memory front-end.
*/
	    char	*host,
	    int		 port) {

    int			i, status, my_skt;
    struct sockaddr_in	lcl_sockname;
    struct sockaddr_in	rmt_sockname;
    int			rmt_inet_addr;
    struct in_addr	*rmt_inet_addr_pntr;
    struct hostent	*rmt_hostent;
    int			rmt_sockname_len;
    unsigned int	oto_len, oto_status;
    char		old_time_out[4];
    union {
      char  chars[4];
      int   val;
    } time_out;
		/*
		** Get Internet address of the front-end.
		*/
    for (i=0; i < strlen (host); i++) host[i] = tolower (host[i]);
    rmt_hostent = gethostbyname (host);
    if (rmt_hostent == NULL) {
		/*
		** The following code is to handle hosts which are not yet
		** in the BIND data base.
		*/
      if (strcmp (host, "sqfe01") == 0) {
        rmt_inet_addr_pntr = (struct in_addr *) &rmt_inet_addr;
	rmt_inet_addr = inet_addr ("129.129.56.181");
      }else {
	printf ("Target processor is %s.\n", host);
        FailInet ("\nGethostbyname error.");
      }
    }else {
      rmt_inet_addr_pntr = (struct in_addr *) rmt_hostent->h_addr_list[0];
    }
    printf (" Target processor is %s ", host);
    printf ("(%s)\n", inet_ntoa (*rmt_inet_addr_pntr));
    printf (" Server Port %d\n", port);
/*
**	    Create a TCP/IP socket for prelim. connect to server and bind it.
*/
    my_skt = socket (AF_INET, SOCK_STREAM, 0);
    if (my_skt == -1) FailInet ("Socket error.\n");

    lcl_sockname.sin_family = AF_INET;
    lcl_sockname.sin_port   = htons (0);
    lcl_sockname.sin_addr.s_addr = 0;
    status = bind (my_skt, (struct sockaddr *) &lcl_sockname,
				    sizeof (lcl_sockname));
    if (status == -1) FailInet ("Bind error.\n");
	    /*---------------------------
	    ** Set short time-out (VMS systems only)
	    */
#ifdef	__VMS
    oto_len = sizeof (old_time_out);	/* Save current time-out first */
    oto_status = getsockopt (my_skt, IPPROTO_TCP, UCX$C_TCP_PROBE_IDLE,
			    old_time_out, &oto_len);
    if (oto_status == 0) {
      time_out.val = 5;		    /* Set new time-out */
      status = setsockopt (my_skt, IPPROTO_TCP, UCX$C_TCP_PROBE_IDLE,
			    time_out.chars, sizeof (time_out));
    }
#endif
/*
**=========================================  Now connect to the server.
*/
    rmt_sockname_len = sizeof (rmt_sockname);
    rmt_sockname.sin_family	 = AF_INET;
    rmt_sockname.sin_port	 = htons (port);
    rmt_sockname.sin_addr.s_addr = rmt_inet_addr_pntr->s_addr;
    status = connect (my_skt, (struct sockaddr *) &rmt_sockname,
				    sizeof (rmt_sockname));
    if (status == -1) {
      GetErrno (&My_errno, &My_vaxc_errno);
      FailInet ("Connect error\n");
    }
		/*---------------------------
		** Restore time-out (VMS only)
		*/
#ifdef	__VMS
    if (oto_status == 0) {
      setsockopt (my_skt, IPPROTO_TCP, UCX$C_TCP_PROBE_IDLE,
			    old_time_out, oto_len);
    }
#endif
    return my_skt;
  }
/*
**--------------------------------------------------------------------------*/
  int	read_boot_line (
/*	==============
**			    Get the boot line from the server.
*/
		int	 skt,		/* The socket to read from */
		char	*recd,		/* Buffer to receive the boot line */
		int	 s_recd) {	/* Size of buffer */

    char    hdr_buff[8], *p_addr;
    int	    i, j, len, status, bytes_to_come;
	    /*----------------------------------------
	    ** Get first 4 bytes which gives the length to follow
	    */
    status = recv (skt, hdr_buff, 4, 0);
    if (status != 4) FailInet ("recv error on bootline header.\n");

    i = sscanf (hdr_buff, "%4d%n", &len, &j);	/* Convert to binary */
    if ((i != 1) || (j != 4)) {
      printf ("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]);
      exit (EXIT_FAILURE);
    }

    if (len >= s_recd) {
      printf (" Boot-line length is %d\n", len);
      printf ("Too long for buffer. Buffer length = %d\n", s_recd);
      flushNet (len);
      exit (EXIT_FAILURE);
    }

    bytes_to_come = len;
    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) {
	FailInet ("R/W-Socket recv error");
      }else if (status == 0) {
	FailInet ("R/W-Socket recv error -- return code = 0");
      }
      exit (EXIT_FAILURE);
    }
    i = strlen (recd);
    if (i > len) {
      printf (" Length of boot-line buffer read from target = %d.\n", len);
      printf (" String length of boot-line = %d.\n", i);
      printf (" It appears as though the boot-line is not null terminated!");
      exit (EXIT_FAILURE);
    }
    return True;
  }
/*
**--------------------------------------------------------------------------*/
  int	send_a_close (
/*	============
**			    Send a "CLOSE" message to the target host.
*/
		int	 skt) {		/* The socket to send to. */

    char    cmnd_buff[32], buff[32];
    int	    status, i, bootlen;

    strcpy (cmnd_buff, "CLOSE");
    status = send (skt, cmnd_buff, 8, 0);
    if (status != 8) FailInet ("send_a_close - bad send");

    status = recv (skt, buff, 4, 0);	    /* Await the response */
					    /* But do not check it */
    return True;
  }
/*
**---------------------------------------------------------------------------*/
  int	setup_xrm_database (
/*	==================
**				Setup Resource Manager Database
*/
			XrmDatabase	*db,
			char		*name[],
			int		*argc,
			char		*argv[],
			int		verbose) {

    static char	our_name[80]  = "Unknown";  /* This holds the program name */
    static char lkup_name[80] = "Unknown";  /* Name for looking in database */

    int		status, i, first = True;
    char	text[80];
    char	full_nm0[80];
    char	full_nm1[80];
    char	*p_fil[] = {0,0,0,0,0,0,0,0,0,0};
    char	*my_name;
    char	*my_name_last;

    char	*name_type;
    XrmValue	name_value;

    XrmDatabase cmnd_line_db = NULL;
    XrmDatabase	lcl_db	     = NULL;
  /*-----------------------------------------------------
  ** This routine merges some resource databases with options specified on
  ** the command line. Resources can then be looked up using XrmGetResource.
  ** This is a bit like the X-toolkit routine XtAppInitialize does for the
  ** extraction of resources by XtGetApplicationResources.
  ** 
  ** I can't help but think that there's a simpler way of doing this but I
  ** can't find it in the X manuals. Basically, the problem arises with wanting
  ** to avoid the calling program being associated with an X-display, i.e. it
  ** is intended for use by "command-line oriented" programs. All the nice,
  ** easy-to-use resource/command-line setup routines in Xlib or Xtlib seem to
  ** assume one is going to use a display -- not surprising, I suppose,
  ** since the concept of Xlib is for writing window based applications!
  **
  ** Anyway, the point is that the following way turns out to be lacking
  ** when it gets tested in anger.
  */
    status = True;		/* Assume success	*/

    our_name[0] = NIL;
	/*
	** Make a list of the databases to be merged, highest priority first.
	*/
#ifdef  __VMS
    p_fil[0] = "decw$user_defaults:SinQ_rc.dat";
    p_fil[1] = "decw$group_defaults:SinQ_rc.dat";
    p_fil[2] = "decw$system_defaults:SinQ_rc.dat";
    p_fil[3] = "decw$user_defaults:decw$xdefaults.dat";
    p_fil[4] = "decw$group_defaults:decw$xdefaults.dat";
    p_fil[5] = "decw$system_defaults:decw$xdefaults.dat";
    p_fil[6] = NULL;
    if (*argc > 0) {	     /* Find out what we are called - parse file nm */
      my_name = strstr (argv[0], "]");	/* Find end of directory, i.e. "]" */
      my_name++;			/* Skip over "]" */
      if (my_name[0] == '[') {		/* Handle possible concealed device */
        my_name = strstr (my_name, "]");
	my_name++;
      }
      i = sizeof (our_name);
      StrEdit (our_name, my_name, "lowercase", &i);	    /* Copy the rest */
      strtok (our_name, ".");		/* Close it off at "." */
    }
#else
    p_fil[0] = StrJoin (full_nm0, sizeof (full_nm0),
			    getenv ("HOME"), "/SinQ_rc");
    p_fil[1] = "/usr/lib/X11/app-defaults/SinQ_rc";
    p_fil[2] = StrJoin (full_nm1, sizeof (full_nm1),
			    getenv ("HOME"), "/.Xdefaults");
    p_fil[3] = "/usr/lib/X11/app-defaults/Xdefaults";
    p_fil[4] = NULL;
    if (*argc > 0) {	      /* Find out what we are called - parse file nm  */
			      /* Find end of directories */
      my_name = argv[0] - 1;
      while (my_name != NULL) {
        my_name_last = my_name;
	my_name_last++;
	my_name = strstr (my_name_last, "/");
      }
      StrJoin (our_name, sizeof (our_name), my_name_last, "");
    }
#endif
    if (verbose) printf ("My name is \"%s\"\n", our_name);
	/*
	**  Initialise and combine all databases
	*/
    XrmInitialize ();
    for (i = 0; i < XtNumber (p_fil); i++) {
      if (p_fil[i] == NULL) break;
      status = XrmCombineFileDatabase (p_fil[i], &lcl_db, False);
      if ((status != 0) && verbose) {
	if (first)
	  printf ("Resource database created from file %s.\n", p_fil[i]);
	if (!first)
	  printf ("File %s merged into resource database.\n", p_fil[i]);
	first = False;
      }
    }
	/*----------------------------------------------------------------
	**  See if there's anything specified on cmnd line, incl "name".
	*/
    XrmParseCommand (&cmnd_line_db,
			OpTable_0, XtNumber(OpTable_0), our_name, argc, argv);
    if (cmnd_line_db != NULL) {
	    /*
	    ** There was at least 1 item on cmnd line. Process the line.
	    ** If -name was specified, adopt it.
	    */
      status = XrmGetResource (cmnd_line_db,  /* See if a name was specified  */
			    StrJoin (text, sizeof (text), our_name, ".name"),
			    "ProgramName.Values",
			    &name_type, &name_value);
      if (status) {
	i = sizeof (lkup_name);
	StrEdit (lkup_name, name_value.addr, "lowercase", &i);
	printf ("Option list name is \"%s\"\n", lkup_name);
      }else {
        strcpy (lkup_name, our_name);
      }
	    /*
	    ** Loop over all items in OpTable_0 and merge them into database,
	    ** taking care of any possible name changes.
	    */
      for (i = 0; i < XtNumber (OpTable_0); i++) {
	if (strcmp (OpTable_0[i].option, "-name") == 0) continue;
        status = XrmGetResource (cmnd_line_db,
				StrJoin (text, sizeof (text),
				    our_name, OpTable_0[i].specifier),
				"ProgramName.Values",
				&name_type, &name_value);
	if (status) {
	  StrJoin (text, sizeof (text), lkup_name, OpTable_0[i].specifier);
	  XrmPutResource (&lcl_db, text, "String", &name_value);
	}
      }
    }
/*----------------------------------------------------------------
*/
    *name = lkup_name;
    *db = lcl_db;
    if ((lcl_db == NULL) && verbose)
      printf ("\007Warning -- no resource database found.\n");

    XrmDestroyDatabase (cmnd_line_db);
/*
**    XrmPutFileDatabase (lcl_db, "sinqhm_client.db");
*/
    return status;
  }
/*
**--------------------------------------------------------------------------*/
  int	show_boot_line (
/*	==============
**			    Display the boot line.
**
*/		char	*recd) {    /* The boot-line as received from serever */

    char    *tok, *body;
    int	    i, j, status, toklen, empty;

		    /*
		    ** Scan through the boot-line printing non-null items.
		    */
    empty = True;
    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)) {
	  empty = False;
	  printf (" boot device          : %s\n", body);
	}else if ((strcmp (tok, "procNum") == 0) && (body != NULL)) {
	  status = sscanf (body, "%i%n", &i, &j);
	  if ((status != 1) || (j != strlen (body))) {
	    printf ("show_boot_line: Bad value found for procNum: \"%s\"\n", body);
	  }else {
	    empty = False;
	    printf (" processor number     : %s\n", body);
	  }
	}else if ((strcmp (tok, "hostName") == 0) && (body != NULL)) {
	  empty = False;
	  printf (" host name            : %s\n", body);
	}else if ((strcmp (tok, "bootFile") == 0) && (body != NULL)) {
	  empty = False;
	  printf (" file name            : %s\n", body);
	}else if ((strcmp (tok, "ead") == 0) && (body != NULL)) {
	  empty = False;
	  printf (" inet on ethernet (e) : %s\n", body);
	}else if ((strcmp (tok, "bad") == 0) && (body != NULL)) {
	  empty = False;
	  printf (" inet on backplane (b): %s\n", body);
	}else if ((strcmp (tok, "had") == 0) && (body != NULL)) {
	  empty = False;
	  printf (" host inet (h)        : %s\n", body);
	}else if ((strcmp (tok, "gad") == 0) && (body != NULL)) {
	  empty = False;
	  printf (" gateway inet (g)     : %s\n", body);
	}else if ((strcmp (tok, "usr") == 0) && (body != NULL)) {
	  empty = False;
	  printf (" user (u)             : %s\n", body);
	}else if ((strcmp (tok, "passwd") == 0) && (body != NULL)) {
	  empty = False;
	  printf (" ftp password (pw)    : %s\n", body);
	}else if ((strcmp (tok, "flags") == 0) && (body != NULL)) {
	  status = sscanf (body, "%i%n", &i, &j);
	  if ((status != 1) || (j != strlen (body))) {
	    printf ("show_boot_line: Bad value found for flags: \"%s\"\n", body);
	  }else {
	    empty = False;
	    printf (" flags (f)            : %s\n", body);
	  }
	}else if ((strcmp (tok, "targetName") == 0) && (body != NULL)) {
	  empty = False;
	  printf (" target name (tn)     : %s\n", body);
	}else if ((strcmp (tok, "startupScript") == 0) && (body != NULL)) {
	  empty = False;
	  printf (" startup script (s)   : %s\n", body);
	}else if ((strcmp (tok, "other") == 0) && (body != NULL)) {
	  empty = False;
	  printf (" other (o)            : %s\n", body);
	}else {
	  if (body != NULL) {
	    printf ("show_boot_line: Bad token found in boot-line: "
			    "\"%s\" \"%s\"\n", tok, body);
	  }else {
	    printf ("show_boot_line: Token found with NULL body in boot-line: "
			    "\"%s\"\n", tok);
	  }
	}
	tok = strtok (NULL, ":");
      }
    }
    if (empty) printf (" The boot-line was empty!\n");
    return EXIT_SUCCESS;
  }
/*
**--------------------------------------------------------------------------*/
  void show_help (char *token) {
/*     =========
**		    Display help text
*/
    int	    len;

    if ((token == NULL) || (token[0] == NIL)) {
      printf ("\n"
	" The following commands are recognised by SINQHM_BOOTUTIL_CLIENT:\n"
	"\n"
	"    help or ?  - generate this help text.\n"
	"    config     - interactive configuration of target boot-line.\n"
	"    reboot     - reboot the target.\n"
	"    rundown    - cause the bootUtil server on the target to exit.\n"
	"    show       - display the boot-line of the target.\n"
	"\n"
	" To get more detailed help on a specific command, specify:\n"
	"\n"
	"               HELP <cmnd>\n"
	"\n"
	" on the command line. For information on the environment setup "
							    "for the\n"
	" program, specify:\n"
	"\n"
	"               HELP SETUP\n"
	"\n"
	" on the command line.\n"
	"\n");
    } else if (StrMatch ("CONFIG", token, 1) == 0) {
      printf ("\n"
	    " Config:\n"
	    "   The current boot-line information will be displayed. The "
							    "user will then\n"
	    "   be prompted for new settings for each field of the boot-"
							"line. The modified\n"
	    "   boot-line will then be displayed and the user asked whether "
							    "it should be\n"
	    "   written to the non-volatile memory of the target or not.\n"
	    "\n");
    }else if (StrMatch ("REBOOT", token, 2) == 0) {
      printf ("\n"
	    " Reboot\n"
	    "   The target processor will be rebooted.\n"
	    "\n");
    }else if (StrMatch ("RUNDOWN", token, 2) == 0) {
      printf ("\n"
	    " Rundown\n"
	    "   The bootUtil server on the target processor will be "
						    "requested to exit.\n"
	    "   Manual intervention on the target will then be necessary "
						    "before this program\n"
	    "   can be used again.\n"
	    "\n");
    }else if (StrMatch ("SHOW", token, 1) == 0) {
      printf ("\n"
	    " Show:\n"
	    "   The current boot-line information of the target will be "
							"displayed.\n"
	    "\n");
    }else if (StrMatch ("SETUP", token, 2) == 0) {
      printf ("\n"
	    " Setup:\n"
	    "   The target host with which SinqHM_bootUtil_Client is to "
								"communicate\n"
	    "   can most easily be specified via options of the form:\n"
	    "\n"
	    "         -host <target-name> -port <port>\n"
	    "\n"
	    "   on the command line. There is no default for <target-name> "
								"whereas\n"
	    "   <port>, which specifies the TCP/IP port number at which "
							"the SinqHM_bootUtil\n"
	    "   server is accepting connections on the target, defaults "
								"to 2300.\n"
	    "\n"
	    "   Alternatively, the environment variable SINQHM_FRONTEND "
							"may be defined.\n"
	    "   On Unix systems this is done thus:\n"
	    "\n"
	    "         setenv SINQHM_FRONTEND \"<target-name> <port>\"\n"
	    "\n"
	    "   On VMS systems, logical names are used instead, e.g.\n"
	    "\n"
	    "         define/job sinqhm_frontend \"<target-name> <port>\"\n"
	    "\n"
	    "   It is also possible to specify <target-name> and <port> in "
							"an X-resources\n"
	    "   data base. The resource names are \"butilHost\" and "
							"\"butilPort\".\n"
	    "\n");
    }else {
      printf ("Sorry, no help available for \"%s\"!\n", token);
    }
  }
/*
**==========================================================================
**
**  Main line program
**  ------------------
**==========================================================================*/
  int	main (int argc, char *argv[]) {
/*	====
*/
    int	    i, j, k, status, is, dummy, cmnd_len;

    char    cmnd[16], ist_bootline[1024], new_bootline[1024], buff[1024];
    int	    boot_line_changed;

    char    recd[256], recd1[256];
    char    last_recd[256] = {NIL};
    char    *verb;
    int	    l_recd;
    XrmDatabase		my_db;
    char		*appName;
/*============================================================================
*/
    printf ("SinqHM_bootUtil_Client Ident \"%s\" started.\n", IDENT);
/*============================================================================
**	    Declare an exit handler to tidy up if we get forced to exit.
*/
    is = atexit (exit_handler);
    if (is != 0) {
      printf ("SINQHM_BOOTUTIL_CLIENT -- error setting up exit handler.");
      return EXIT_FAILURE;
    }
	/*-------------------------------------------------------------
	**	Setup the resource database and look up the resources.
	*/
    Verbose = False;
    for (i = 1; i < argc; i++) if (strcmp ("-v", argv[i]) == 0) Verbose = True;

    setup_xrm_database (&my_db, &appName, &argc, argv, Verbose);
    status = get_check_resources (&my_db, appName, Verbose);
    if (!status) return False;
/*============================================================================
**	    Analyse the arguments to see what has to be done.
*/
    if (argc > 1) {	/* There should just be at least one argument remaining.
			*/
      StrJoin (cmnd, sizeof (cmnd), argv[1], "");
      cmnd_len = sizeof (cmnd);
      StrEdit (cmnd, argv[1], "upcase", &cmnd_len);	/* Cvt to upper case */
      if (cmnd[0] == '-')			      /* Ignore a leading "-" */
	StrJoin (cmnd, sizeof (cmnd), &cmnd[1], "");
    }else {
      printf ("\n  No command was specified on the command line, "
						"default is \"SHOW\".\n"
		"  Specify \"HELP\" for help.\n\n");
      strcpy (cmnd, "SHOW");
    }
    if (StrMatch (cmnd, "HELP", 1) || StrMatch (cmnd, "?", 1)) {
      if (argc > 2) show_help (argv[2]); else show_help (NULL);
      return EXIT_SUCCESS;
    }

    if (!StrMatch (cmnd, "CONFIG", 1)   &&
	!StrMatch (cmnd, "REBOOT", 6)   &&
	!StrMatch (cmnd, "RUNDOWN", 7)	&&
	!StrMatch (cmnd, "SHOW", 1)) {
      printf ("\n\"%s\" is not a recognised command.\n\n", cmnd);
      show_help (NULL);
      return EXIT_FAILURE;
    }
/*============================================================================
**	    Find out the location of the bootUtil Server and make
**	    a connection to it. Any errors during this phase cause the program
**	    to exit with an error status.
*/
    if (Rmt_host[0] == NIL) {
      get_SINQHM_FRONTEND (Rmt_host, sizeof (Rmt_host), "",
			 &Rmt_port, DFLT_PORT,
			 &dummy, 0);
      if (Rmt_host[0] == NIL) {
	printf ("\n"
	    " No target processor has been specified!\n"
	    "\n");
	show_help ("setup");
	return EXIT_FAILURE;
      }
    }
/*============================================================================*/
    Cnct_skt = openConnection (Rmt_host, Rmt_port);
    status = read_boot_line (Cnct_skt, ist_bootline, sizeof (ist_bootline));
    status = send_a_close (Cnct_skt);
    close (Cnct_skt);
    Cnct_skt = 0;

    strcpy (new_bootline, ist_bootline);
    boot_line_changed = False;

    i = printf ("\nCurrent boot-line of %s is:\n", Rmt_host);
    for (j = 3; j < i; j++) printf ("="); printf ("\n");
    status = show_boot_line (ist_bootline);
/*
**=========================================== Carry out the command =========
*/
    if (StrMatch (cmnd, "CONFIG", 1)) {		/* Modify the configuration? */
      status = do_config (new_bootline);
      if (status) {
	Cnct_skt = openConnection (Rmt_host, Rmt_port);
	status = read_boot_line (Cnct_skt, ist_bootline, sizeof (ist_bootline));
	status = send_a_close (Cnct_skt);
	close (Cnct_skt);
	Cnct_skt = 0;
	if (status) {
	  i = printf ("\nNew boot-line of %s is:\n", Rmt_host);
	  for (j = 3; j < i; j++) printf ("="); printf ("\n");
	  status = show_boot_line (ist_bootline);
	  printf ("\n");
	}else {
	  printf ("\007Error getting new boot-line information!\n");
	}
      }
    }else if (StrMatch (cmnd, "REBOOT", 2)) {	/* Reboot? */
      status = do_reboot ();
    }else if (StrMatch (cmnd, "RUNDOWN", 2)) {	/* Rundown? */
      status = do_rundown ();
    }else if (StrMatch (cmnd, "SHOW", 1)) {	/* Show? */
		/* Already done! */
    }else {
      printf ("\n Illegal command - try \"HELP\".\n");
      status = EXIT_FAILURE;
    }

    return status;
  }
/*==================================== End of SINQHM_BOOTUTIL_CLIENT.C ======*/
