diff --git a/sinqhm/sinqhm_bootutil.c b/sinqhm/sinqhm_bootutil.c new file mode 100755 index 00000000..420fb07a --- /dev/null +++ b/sinqhm/sinqhm_bootutil.c @@ -0,0 +1,627 @@ +#define IDENT "1A02" +/* +** +--------------------------------------------------------------+ +** | Paul Scherrer Institute | +** | SINQ Division | +** | | +** | This software may be used freely by non-profit organizations.| +** | It may be copied provided that the name of P.S.I. and of the | +** | author is included. Neither P.S.I. nor the author assume any | +** | responsibility for the use of this software outside of P.S.I.| +** +--------------------------------------------------------------+ +** +** Module Name . . . . . . . . : [...SINQHM]SinqHM_bootUtil.c +** +** Author . . . . . . . . . . : D. Maden +** Date of creation . . . . . . : Aug 1999 +** +** Updates: +** 1A01 16-Aug-1999 DM Initial version. +**--------------------------------------------------------------------------- +** SinqHM_bootUtil.c is a simple TCP/IP server for VxWorks. +** It obtains information about the VxWorks boot line. +*/ +/* +** To compile and link this program for VxWorks on PSS123, use: +** + set src = "lnsa09:tas_src:[sinqhm]" + rcp -p "${src}SinqHM_bootUtil.c" SinqHM_bootUtil.c + ccvx -I${WIND_BASE}/target/config/all SinqHM_bootUtil.c +** where + ccvx = ccppc -O0 \ + -mcpu=603 \ + -I${WIND_BASE}/target/h \ + -fno-builtin \ + -fno-for-scope \ + -nostdinc \ + -DCPU=PPC603 \ + -D_GNU_TOOL \ + -gdwarf -c -Wimplicit + +** and, on the target, +** +** -> ld < /home/pss123/aco/maden/wind/SinqHM/Dflt/SinqHM_srv.o +** -> ld < /home/pss123/aco/maden/wind/SinqHM/SinqHM_bootUtil.o +** -> taskSpawn "bootUtil", 100, 8, 20000, SinqHM_bootUtil, +** ^ +** | +** TCP/IP port number of the "bootUtil" service, dflt = 2300 -+ +** +**==================================================================== +*/ +#include "vxWorks.h" /* always first */ +#include "taskLib.h" +#include "sockLib.h" +#include "bootLib.h" +#include "rebootLib.h" +#include "sysLib.h" +#include "usrLib.h" +#include "ioLib.h" + +#if (CPU == PPC603) +#include "../config/mv1603/config.h" +#elif (CPU == PPC604) +#include "../config/mv1604/config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +/* +**==================== Global Definitions ===================================== +*/ + +#include "SinqHM_def.h" + +#define MAX_ACTIONS 8 +#define MAX_ARGS 10 +#define SBU_PORT_DFLT 2300 /* The Dflt Internet Port for Server Requests */ +/* +**==================== Global Variables ===================================== +*/ + uint Sbu_port; /* The port number to use for the service */ + char Sbu_name[20]; /* Our task name */ +/* +**============================================================================= +** Local routine prototypes. +*/ + int sbu_doConfig (int skt); + void sbu_doReboot (); + void sbu_failInet (char *text); + void sbu_failInet_str (char *text, char *str); + void sbu_getErrno (int *his_errno); + void sbu_showHelp (char *errmsg); + + char *StrJoin ( + char *result, + int result_size, + char *str_a, + char *str_b); + int sbu_doConfig (int skt); +/* +**--------------------------------------------------------------------------*/ + int sbu_doConfig (int skt) { +/* ============ +** Configure the vxWorks boot information +*/ + char hdr_buff[8], *p_addr, recd[1024]; + int status, i, j, l_recd, bytes_to_come, toklen, changed; + char *boot_line_addr, *b_status, *tok, *body; + BOOT_PARAMS my_boot_params; + + /*---------------------------------------- + ** Get the new boot information over the network. + ** + ** Get first 4 bytes which gives the length to follow + */ + status = recv (skt, hdr_buff, 4, 0); + if (status != 4) sbu_failInet ("recv error on bootline header.\n"); + + i = sscanf (hdr_buff, "%4d%n", &l_recd, &j); /* Convert to binary */ + if ((i != 1) || (j != 4)) { + sprintf (recd, "Header bytes are not ASCII coded decimal: 0x%x 0x%x 0x%x 0x%x\n", + hdr_buff[0], hdr_buff[1], hdr_buff[2], hdr_buff[3]); + sbu_failInet (recd); + } + + if (l_recd >= sizeof (recd)) { + sprintf (recd, "Too long for buffer. Buffer length = %d\n", l_recd); + sbu_failInet (recd); + } + + bytes_to_come = l_recd; + p_addr = recd; + + while (bytes_to_come > 0) { + status = recv (skt, p_addr, bytes_to_come, 0); + if (status <= 0) break; + bytes_to_come -= status; + p_addr += status; + } + if (bytes_to_come != 0) { + if (status < 0) { + sbu_failInet ("R/W-Socket recv error"); + }else if (status == 0) { + sbu_failInet ("R/W-Socket recv error -- return code = 0"); + } + sbu_failInet ("R/W-Socket recv error -- not enough data received"); + } + /* + ** Initialise the boot line structure with the existing + ** contents of the boot line. + */ + boot_line_addr = (char *) BOOT_LINE_ADRS; /* Get pointer to the boot line */ + b_status = bootStringToStruct (boot_line_addr, &my_boot_params); + if (*b_status != EOS) { + printf ("\n%s: Bad status from \"bootStringToStruct\": 0x%02x\n", + Sbu_name, *b_status); + return False; + } + /* + ** Now scan through the new boot string replacing items in + ** the boot line structure as we find them. + */ + printf ("\nNew boot-line items are:\n"); + changed = False; + tok = strtok (recd, ":\n"); + while (tok != NULL) { + toklen = strlen (tok); + if (tok[toklen+1] == '\n') { /* Watch out for tokens with no body */ + tok = strtok (NULL, ":\n"); /* Skip an empty body */ + }else { + body = strtok (NULL, "\n"); + if ((strcmp (tok, "bootDev") == 0) && (body != NULL)) { + if (strcmp (my_boot_params.bootDev, body) != 0) { + changed = True; + printf (" boot device : %s\n", body); + strcpy (my_boot_params.bootDev, body); + } + }else if ((strcmp (tok, "procNum") == 0) && (body != NULL)) { + status = sscanf (body, "%i%n", &i, &j); + if ((status != 1) || (j != strlen (body))) { + printf ("\n%s: Bad value found for procNum: \"%s\"\n", Sbu_name, body); + return False; + } + if (my_boot_params.procNum != i) { + changed = True; + printf (" processor number : %s\n", body); + my_boot_params.procNum = i; + } + }else if ((strcmp (tok, "hostName") == 0) && (body != NULL)) { + if (strcmp (my_boot_params.hostName, body) != 0) { + changed = True; + printf (" host name : %s\n", body); + strcpy (my_boot_params.hostName, body); + } + }else if ((strcmp (tok, "bootFile") == 0) && (body != NULL)) { + if (strcmp (my_boot_params.bootFile, body) != 0) { + changed = True; + printf (" file name : %s\n", body); + strcpy (my_boot_params.bootFile, body); + } + }else if ((strcmp (tok, "ead") == 0) && (body != NULL)) { + if (strcmp (my_boot_params.ead, body) != 0) { + changed = True; + printf (" inet on ethernet (e) : %s\n", body); + strcpy (my_boot_params.ead, body); + } + }else if ((strcmp (tok, "bad") == 0) && (body != NULL)) { + if (strcmp (my_boot_params.bad, body) != 0) { + changed = True; + printf (" inet on backplane (b): %s\n", body); + strcpy (my_boot_params.bad, body); + } + }else if ((strcmp (tok, "had") == 0) && (body != NULL)) { + if (strcmp (my_boot_params.had, body) != 0) { + changed = True; + printf (" host inet (h) : %s\n", body); + strcpy (my_boot_params.had, body); + } + }else if ((strcmp (tok, "gad") == 0) && (body != NULL)) { + if (strcmp (my_boot_params.gad, body) != 0) { + changed = True; + printf (" gateway inet (g) : %s\n", body); + strcpy (my_boot_params.gad, body); + } + }else if ((strcmp (tok, "usr") == 0) && (body != NULL)) { + if (strcmp (my_boot_params.usr, body) != 0) { + changed = True; + printf (" user (u) : %s\n", body); + strcpy (my_boot_params.usr, body); + } + }else if ((strcmp (tok, "passwd") == 0) && (body != NULL)) { + if (strcmp (my_boot_params.passwd, body) != 0) { + changed = True; + printf (" ftp password (pw) : %s\n", body); + strcpy (my_boot_params.passwd, body); + } + }else if ((strcmp (tok, "flags") == 0) && (body != NULL)) { + status = sscanf (body, "%i%n", &i, &j); + if ((status != 1) || (j != strlen (body))) { + printf ("\n%s: Bad value found for flags: \"%s\"\n", Sbu_name, body); + return False; + } + if (my_boot_params.flags != i) { + changed = True; + printf (" flags (f) : %s\n", body); + my_boot_params.flags = i; + } + }else if ((strcmp (tok, "targetName") == 0) && (body != NULL)) { + if (strcmp (my_boot_params.targetName, body) != 0) { + changed = True; + printf (" target name (tn) : %s\n", body); + strcpy (my_boot_params.targetName, body); + } + }else if ((strcmp (tok, "startupScript") == 0) && (body != NULL)) { + if (strcmp (my_boot_params.startupScript, body) != 0) { + changed = True; + printf (" startup script (s) : %s\n", body); + strcpy (my_boot_params.startupScript, body); + } + }else if ((strcmp (tok, "other") == 0) && (body != NULL)) { + if (strcmp (my_boot_params.other, body) != 0) { + changed = True; + printf (" other (o) : %s\n", body); + strcpy (my_boot_params.other, body); + } + }else { + if (body != NULL) { + printf ("\n%s: Bad token found in new boot string: \"%s\" \"%s\"\n", + Sbu_name, tok, body); + }else { + printf ("\n%s: Token found with NULL body in new boot string: \"%s\"\n", + Sbu_name, tok); + } + printf ("\n%s: Boot string has not been re-configured!\n", Sbu_name); + return False; + } + tok = strtok (NULL, ":"); + } + } + if (!changed) printf (" Nothing has been changed!\n"); + + status = bootStructToString (boot_line_addr, &my_boot_params); + if (status != OK) { + printf ("\n%s: Bad status from \"bootStringToStruct\": 0x%02x\n", Sbu_name, + status); + return False; + } + b_status = bootStringToStruct (boot_line_addr, &my_boot_params); + if (*b_status != EOS) { + printf ("\n%s: Bad status from \"bootStringToStruct\": 0x%02x\n", + Sbu_name, *b_status); + return False; + } + printf ("\nResulting vxWorks Boot-Line is:\n" + " =================\n"); + + printf (" boot device : %s\n", my_boot_params.bootDev); + printf (" processor number : %d\n", my_boot_params.procNum); + printf (" host name : %s\n", my_boot_params.hostName); + printf (" file name : %s\n", my_boot_params.bootFile); + printf (" inet on ethernet (e) : %s\n", my_boot_params.ead); + printf (" inet on backplane (b): %s\n", my_boot_params.bad); + printf (" host inet (h) : %s\n", my_boot_params.had); + printf (" gateway inet (g) : %s\n", my_boot_params.gad); + printf (" user (u) : %s\n", my_boot_params.usr); + printf (" ftp password (pw) : %s\n", my_boot_params.passwd); + printf (" flags (f) : 0x%x\n", my_boot_params.flags); + printf (" target name (tn) : %s\n", my_boot_params.targetName); + printf (" startup script (s) : %s\n", my_boot_params.startupScript); + printf (" other (o) : %s\n\n", my_boot_params.other); + /* + ** Write to non-volatile RAM + */ + status = sysNvRamSet (BOOT_LINE_ADRS, strlen (BOOT_LINE_ADRS) + 1, 0); + if (status != OK) { + printf ("\n%s: Bad status from \"sysNvRamSet\": 0x%02x\n", + Sbu_name, status); + return False; + } + return True; + } +/* +**--------------------------------------------------------------------------*/ + void sbu_doReboot () { +/* ============ +** Re-boot the vxWorks system by calling reboot. +*/ + printf ("This processor is about to be re-booted ...\n"); + taskDelay (sysClkRateGet ()/4); + reboot (BOOT_CLEAR); + exit (EXIT_SUCCESS); /* Should not get here! */ + } +/* +**--------------------------------------------------------------------------*/ + void sbu_failInet (char *text) { +/* ============= +** Output the given text and exit the process. +*/ + int my_errno; + + sbu_getErrno (&my_errno); + printf ("\n### Internet Error ###\n"); + printf ( " ### errno = %d.\n", my_errno); + perror (text); + exit (EXIT_FAILURE); + } +/*--------------------------------------------------------------------------*/ + void sbu_failInet_str (char *fmt, char *str) { +/* ================ +** Call to failInet with an extra parameter. +*/ + char my_buff[132]; + + sprintf (my_buff, fmt, str); + sbu_failInet (my_buff); + /* No return */ + } +/*--------------------------------------------------------------------------*/ + void sbu_getErrno (int *his_errno) { +/* ============= +*/ + *his_errno = errno; /* Make copy of errno */ + return; + } +/* +**--------------------------------------------------------------------------*/ + void sbu_showHelp (char *errmsg) { +/* ============= +*/ + if (errmsg != NULL) { + printf ("\007\n%s\n", errmsg); + taskDelay (5 * sysClkRateGet ()); /* Give user time to read message */ + } + printf ("\n" + "The \"other\" field may be specified as follows:\n" + "\n" + " =,..,/=...\n" + "\n" + "There must be no white space characters in the string. The string may\n" + "be specified in upper or lower case.\n" + "\n" + " may be \"sp\" for \"spawn a task\" or\n" + " \"cfg\" for \"configure SinqHM_srv\"\n" + "\n" + "The following \"sp\" commands are available:\n" + "\n" + " a) sp=SinqHM,,,\n" + " where\n" + " = TCP/IP port number for server. Dflt=2400.\n" + " = flag to indicate if timing levels should be\n" + " generated via a VMIO10 module. If non-zero,\n" + " timing levels are generated. Dflt=0.\n" + " = base address of VMIO10 level-generator\n" + " module. Dflt=0x1900.\n" + " This action spawns the SinqHM histogram memory server task.\n" + "\n" + " b) sp=lwl,,,\n" + " where\n" + " = TCP/IP port number for server. Dflt=3501.\n" + " = base address of VMIO10 test-generator\n" + " module. Dflt=0x1800.\n" + " = verbosity flag. If non-zero, the program is\n" + " verbose. Dflt=0.\n" + " This action spawns the lwl_server task which can be used to feed\n" + " data packets into the hist memory fibre-optic (Licht-Wellen-Leiter)\n" + " link via a VMIO10 test-generator. If the test generator is absent,\n" + " the action can be omitted to avoid a boot-time error message.\n" + "\n" + "The following \"cfg\" commands are available:\n" + "\n" + " a) cfg=HM_DIG,<#-bins>,<#-hists>,,,\n" + " where\n" + " <#-bins> = number of bins per histogram. No default.\n" + " <#-hists> = number of defined histograms. Dflt=1.\n" + " = Number of bytes per bin. Dflt=4.\n" + " = Bin compression factor. Dflt=1.\n" + " = First bin. Dflt=0.\n" + "\n" + " b) cfg=TOF,<#-bins>,<#-cntrs>,,,\n" + " where\n" + " <#-bins> = number of bins per histogram. No default.\n" + " <#-cntrs> = number of neutron counters. No default.\n" + " = Number of bytes per bin. Dflt=4.\n" + " = Bin compression factor. Dflt=1.\n" + " = # of first counter. Dflt=0.\n" + "\n" + " c) cfg=HM_PSD,... same arguments as HM_DIG (for now).\n" + "\n" + "For example:\n" + " other=\"sp=SinqHM/cfg=HM_DIG,400\"\n" + "\n"); + } +/* +**============================================================================== +** +** Main line program +** +**============================================================================*/ + + int SinqHM_bootUtil (int port, int arg2, int arg3, int arg4, +/* =============== +*/ int arg5, int arg6, int arg7, int arg8, int arg9, + int suspend) { +/* +** Arguments: +** port the TCP/IP port number to use. If 0, use default. +** suspend sunspend ourself immediately if non-zero. +*/ + char *local_mem, boot_line[1024], buff[128], cmnd[8]; + char *my_task_name; + BOOT_PARAMS my_params; + + int status, keep_going, cl_port, my_errno, bl_len; + char *b_status, *p_host; + + int my_skt; /* Connection socket */ + int rw_skt; /* Read/write socket */ + struct sockaddr_in lcl_sockname; + struct sockaddr_in rmt_sockname; + int rmt_sockname_len; +/*============================================================================ +*/ + my_task_name = taskName (taskIdSelf()); + if (suspend != 0) { + printf ("\n%s: Suspending ...\n", my_task_name); + taskSuspend (0); /* We've been told to suspend ourself, .. + ** .. presumably for debug reasons. + */ + printf ("\n%s: ... suspension ended!\n", my_task_name); + } +/*============================================================================ +** Perform the initialisation of variables ... +*/ + StrJoin (Sbu_name, sizeof (Sbu_name), taskName (taskIdSelf ()), ""); + printf ("\n%s: Started -- program ident = \"%s\".\n", Sbu_name, IDENT); + + local_mem = (char *) BOOT_LINE_ADRS; /* Get pointer to the boot line */ +/*============================================================================ +*/ + b_status = bootStringToStruct (local_mem, &my_params); /* Parse boot line */ + if (*b_status != EOS) { + printf ("\n%s: Bad status from \"bootStringToStruct\": 0x%02x\n", + Sbu_name, *b_status); + return False; + } + + Sbu_port = SBU_PORT_DFLT; + if ((port >= 128) && (port < 32768)) Sbu_port = port; + +/*============================================================================ +** Create a TCP/IP socket for receiving connection requests, bind it and +** set it to listen. +*/ + my_skt = socket (AF_INET, SOCK_STREAM, 0); + if (my_skt == -1) + sbu_failInet_str ("\n%s: socket error", Sbu_name); + lcl_sockname.sin_family = AF_INET; + lcl_sockname.sin_port = htons (Sbu_port); + lcl_sockname.sin_addr.s_addr = 0; + status = bind (my_skt, (struct sockaddr *) &lcl_sockname, + sizeof (lcl_sockname)); + if (status != 0) sbu_failInet_str ("\n%s: bind error", Sbu_name); + + status = listen (my_skt, 5); + if (status != 0) sbu_failInet_str ("\n%s: listen error", Sbu_name); + +/* +** Clients must now connect to us. +** +** When a connection arrives, the boot line is sent to the client. +*/ + printf ("\n%s: waiting for connections on Port %d\n", Sbu_name, Sbu_port); + keep_going = True; + while (keep_going) { + rmt_sockname_len = sizeof (rmt_sockname); + rw_skt = accept (my_skt, (struct sockaddr *) &rmt_sockname, + &rmt_sockname_len); + if (rw_skt == -1) { + sbu_getErrno (&my_errno); + sbu_failInet_str ("\n%s: accept error", Sbu_name); + /* No return */ + } + p_host = inet_ntoa (rmt_sockname.sin_addr); + cl_port = ntohs (rmt_sockname.sin_port); + + b_status = bootStringToStruct (local_mem, &my_params); /* Parse boot line */ + if (*b_status != EOS) { + printf ("\n%s: Bad status from \"bootStringToStruct\": 0x%02x\n", Sbu_name, + *b_status); + return False; + } + StrJoin (boot_line, sizeof (boot_line), "bootDev:", my_params.bootDev); + StrJoin (boot_line, sizeof (boot_line), boot_line, "\nprocNum:"); + sprintf (buff, "%d", my_params.procNum); + StrJoin (boot_line, sizeof (boot_line), boot_line, buff); + StrJoin (boot_line, sizeof (boot_line), boot_line, "\nhostName:"); + StrJoin (boot_line, sizeof (boot_line), boot_line, my_params.hostName); + StrJoin (boot_line, sizeof (boot_line), boot_line, "\nbootFile:"); + StrJoin (boot_line, sizeof (boot_line), boot_line, my_params.bootFile); + StrJoin (boot_line, sizeof (boot_line), boot_line, "\nead:"); + StrJoin (boot_line, sizeof (boot_line), boot_line, my_params.ead); + StrJoin (boot_line, sizeof (boot_line), boot_line, "\nbad:"); + StrJoin (boot_line, sizeof (boot_line), boot_line, my_params.bad); + StrJoin (boot_line, sizeof (boot_line), boot_line, "\nhad:"); + StrJoin (boot_line, sizeof (boot_line), boot_line, my_params.had); + StrJoin (boot_line, sizeof (boot_line), boot_line, "\ngad:"); + StrJoin (boot_line, sizeof (boot_line), boot_line, my_params.gad); + StrJoin (boot_line, sizeof (boot_line), boot_line, "\nusr:"); + StrJoin (boot_line, sizeof (boot_line), boot_line, my_params.usr); + StrJoin (boot_line, sizeof (boot_line), boot_line, "\npasswd:"); + StrJoin (boot_line, sizeof (boot_line), boot_line, my_params.passwd); + StrJoin (boot_line, sizeof (boot_line), boot_line, "\nflags:"); + sprintf (buff, "0x%x", my_params.flags); + StrJoin (boot_line, sizeof (boot_line), boot_line, buff); + StrJoin (boot_line, sizeof (boot_line), boot_line, "\ntargetName:"); + StrJoin (boot_line, sizeof (boot_line), boot_line, my_params.targetName); + StrJoin (boot_line, sizeof (boot_line), boot_line, "\nstartupScript:"); + StrJoin (boot_line, sizeof (boot_line), boot_line, my_params.startupScript); + StrJoin (boot_line, sizeof (boot_line), boot_line, "\nother:"); + StrJoin (boot_line, sizeof (boot_line), boot_line, my_params.other); + + bl_len = strlen (boot_line) + 1; /* Get len of line (including term'r) */ + bl_len = (bl_len + 3) & (~3); /* Round up to a multiple of 4 */ + sprintf (buff, "%04.4d", bl_len); + status = send (rw_skt, buff, 4, 0); + if (status != 4) { + sbu_getErrno (&my_errno); + sbu_failInet_str ("\n%s: send error on boot-line header", Sbu_name); + /* No return */ + } + status = send (rw_skt, boot_line, bl_len, 0); + if (status != bl_len) { + sbu_getErrno (&my_errno); + sbu_failInet_str ("\n%s: send error on boot-line body", Sbu_name); + /* No return */ + } + /* + ** Now get a command from the client + */ + status = recv (rw_skt, cmnd, 8, 0); + if (status != 8) { + sbu_getErrno (&my_errno); + sprintf (buff, "\n%s: send error on boot-line body", Sbu_name); + perror (buff); + }else if (strcmp (cmnd, "CLOSE") == 0) { + send (rw_skt, "OK\0\0", 4, 0); /* Acknowledge the command */ + }else if (strcmp (cmnd, "CONFIG") == 0) { + printf ("\n%s: CONFIG command received from Host %s, Port %d ...\n", + Sbu_name, p_host, cl_port); + status = sbu_doConfig (rw_skt); + if (status) { + send (rw_skt, "OK\0\0", 4, 0); + }else { + send (rw_skt, "Err", 4, 0); + } + }else if (strcmp (cmnd, "REBOOT") == 0) { + printf ("\n%s: REBOOT command received from Host %s, Port %d ...\n", + Sbu_name, p_host, cl_port); + send (rw_skt, "OK\0\0", 4, 0); /* Acknowledge the command */ + status = close (rw_skt); + status = close (my_skt); + sbu_doReboot (); /* There is no return from this call! */ + }else if (strcmp (cmnd, "RUNDOWN") == 0) { + printf ("\n%s: RUNDOWN command received from Host %s, Port %d ...\n", + Sbu_name, p_host, cl_port); + send (rw_skt, "OK\0\0", 4, 0); /* Acknowledge the command */ + keep_going = False; + }else { + printf ("\n%s: unrecognised command received from Host %s, Port %d:" + "\"%s\"\n", Sbu_name, p_host, cl_port, cmnd); + send (rw_skt, "Err", 4, 0); + } + status = close (rw_skt); + } + status = close (my_skt); + + return True; + } +/*================================= End of SinqHM_bootUtil.c ========*/