#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" #ifdef MV2600 #include "../config/mv2604/config.h" #else #if (CPU == PPC603) #include "../config/mv1603/config.h" #elif (CPU == PPC604) #include "../config/mv1604/config.h" #endif #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 ========*/