From e6a61b2283f5f30ca3c772899fffee62eaccd077 Mon Sep 17 00:00:00 2001 From: cvs Date: Tue, 24 Oct 2000 11:39:14 +0000 Subject: [PATCH] Boot utility client --- sinqhm/sinqhm_bootutil_client.c | 1311 +++++++++++++++++++++++++++++++ 1 file changed, 1311 insertions(+) create mode 100755 sinqhm/sinqhm_bootutil_client.c diff --git a/sinqhm/sinqhm_bootutil_client.c b/sinqhm/sinqhm_bootutil_client.c new file mode 100755 index 00000000..bdb4cede --- /dev/null +++ b/sinqhm/sinqhm_bootutil_client.c @@ -0,0 +1,1311 @@ +#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 - +** ", - The host where SINQHM_BOOTUTIL is running. +** " TCP/IP port number of SINQHM_BOOTUTIL (dflt = 2300). +**==================================================================== +*/ + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#ifdef __VMS +#include +#include +#include +#else +#include +#endif + +#ifdef __VMS +#include +#include +#else +#define SS$_NORMAL EXIT_SUCCESS +#define SS$_BADPARAM EXIT_FAILURE +#define SS$_IVBUFLEN EXIT_FAILURE +#define NO_MEMORY 4 +#endif +/* +**==================== Global Definitions ===================================== +*/ +#include + +#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 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 \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 -port \n" + "\n" + " on the command line. There is no default for " + "whereas\n" + " , 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 \" \"\n" + "\n" + " On VMS systems, logical names are used instead, e.g.\n" + "\n" + " define/job sinqhm_frontend \" \"\n" + "\n" + " It is also possible to specify and 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 ======*/