Files
sicspsi/sinqhm/sinqhm_bootutil_client.c
cvs 064ec37e9a - Rearranged directory structure for forking out ANSTO
- Refactored site specific stuff into a site module
- PSI specific stuff is now in the PSI directory.
- The old version has been tagged with pre-ansto
2003-06-20 10:18:47 +00:00

1312 lines
44 KiB
C
Executable File
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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 ======*/