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