bootLib.c
上传用户:nvosite88
上传日期:2007-01-17
资源大小:4983k
文件大小:38k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* bootLib.c - boot ROM subroutine library */
  2. /* Copyright 1995-2002 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 02v,13mar02,jkf  Fixing SPR#74251, using bootLib.h macros for array sizes 
  8.                  instead of numeric constants.  Changed copyright to 2002.
  9. 02u,30mar99,jdi  doc: corrected misspelling of NOMANUAL which caused
  10.     bootScanNum() to publish.
  11. 02t,28mar99,jdi  doc: fixed tiny formatting errors in .iP section.
  12. 02s,14mar99,jdi  doc: removed refs to config.h and/or configAll.h (SPR 25663).
  13. 02r,04feb99,dbt  when bootParamsShow() routine is called without any
  14.                  parameter, print an error message (Fixed SPR #24885).
  15. 02q,26aug97,spm  modified bootLeaseExtract to allow improved treatment of DHCP 
  16.                  address information by startup routines
  17. 02p,27nov96,spm  added DHCP client and support for network device unit numbers.
  18. 02p,12sep97,dgp  doc: fix SPR 5330 boot line has required parameters
  19. 02o,19jun96,dbt  fixed spr 6691. Modified function promptParamString in order
  20.  to take into account the size of the field to read
  21.  Modified promptRead to read the entire string even if it is 
  22.  too long. This is to empty the reception buffer of the
  23.  standard input.
  24.  Update copyright.
  25. 02n,14oct95,jdi  doc: revised pathnames for Tornado.
  26. 02m,16feb95,jdi  doc format corrections.
  27. 02l,12jan93,jdi  fixed poor style in bootParamsPrompt().
  28. 02k,20jan93,jdi  documentation cleanup for 5.1.
  29. 02j,28jul92,rdc  made bootStructToString write enable memory before writing.
  30. 02i,26may92,rrr  the tree shuffle
  31. 02h,01mar92,elh  changed printParamNum to take an int param (instead of char).
  32. 02g,05dec91,rrr  shut up some ansi warnings.
  33. 02f,19nov91,rrr  shut up some ansi warnings.
  34. 02e,04oct91,rrr  passed through the ansification filter
  35.                   -changed functions to ansi style
  36.   -changed includes to have absolute path from h/
  37.   -changed VOID to void
  38.   -changed copyright notice
  39. 02d,30apr91,jdi  documentation tweak.
  40. 02c,05apr91,jdi  documentation -- removed header parens and x-ref numbers;
  41.  doc review by dnw.
  42. 02b,24mar91,jaa  documentation.
  43. 02a,15jul90,dnw  added "targetName", "startupScript", and "other" fields
  44.  replaced bootParamsToString() with bootStructToString()
  45.  replaced bootStringToParams() with bootStringToStruct()
  46.  changed to initialize procNum to 0 instead of NONE
  47.  routines accept and generate boot strings w/o host & filename
  48.    (required for bootp)
  49.  removed clearFlag from promptParamString - now all fields
  50.    can be cleared
  51.  promptParamNum now accepts "." to be clear (0)
  52.  added bootParamsErrorPrint
  53. 01r,10jul90,dnw  lint clean-up, esp to allow void to be void one day
  54.  fixed incorrect declaration of promptParamString() &
  55.    promptParamNum(); was void, now int
  56.    declared to return int instead of void
  57.  changed name of scanNum() to bootScanNum() to not conflict
  58.    with routine in fioLib.c
  59. 01q,02jan90,dab  fixed bootStringsToParams() bug in parsing vbnum value.
  60.  disabled clearing of boot device, host name, or boot file
  61.    fields.
  62. 01p,23may89,dnw  made promptRead be LOCAL.
  63. 01o,20aug88,gae  documentation
  64. 01n,30may88,dnw  changed to v4 names.
  65. 01m,29may88,dnw  changed calls to atoi() to sscanf().
  66. 01l,28may88,dnw  moved skipSpace here from fioLib.
  67.  changed calls to fioStdIn to STD_IN.
  68.  made promptParam...() LOCAL again (copies in nfsLib now).
  69. 01k,19apr88,llk  made promptParamNum and promptParamString global routines.
  70. 01j,19feb88,dnw  added bootExtractNetmask().
  71. 01i,18nov87,ecs  lint.
  72.  added include of strLib.h.
  73.  documentation.
  74. 01h,15nov87,dnw  changed to print '?' for unprintable chars in parameters.
  75. 01g,06nov87,jlf  documentation
  76. 01f,13oct87,dnw  added flags field to boot line encoding and decoding.
  77. 01e,09oct87,jlf  changed to deal with new ISI boot format with ethernet adrs.
  78. 01d,14may87,rdc  procnum can now be defined by a line VBNUM=n or VB=n for
  79.    +dnw    compatability with isi bootproms.
  80.  changed prompt to indicate password is for ftp only.
  81.  fixed bootEncodeParams() to add EOS.
  82. 01c,23mar87,jlf  documentation.
  83.  changed routine names to meet naming conventions.
  84. 01b,20dec86,dnw  added promptBootParams().
  85.  changed to not get include files from default directories.
  86. 01a,18dec86,llk  created.
  87. */
  88. /*
  89. DESCRIPTION
  90. This library contains routines for manipulating a boot line.
  91. Routines are provided to interpret, construct, print, and prompt for
  92. a boot line.
  93. When VxWorks is first booted, certain parameters can be specified,
  94. such as network addresses, boot device, host, and start-up file.
  95. This information is encoded into a single ASCII string known as the boot line.
  96. The boot line is placed at a known address (specified in config.h)
  97. by the boot ROMs so that the system being booted can discover the parameters
  98. that were used to boot the system.
  99. The boot line is the only means of communication from the boot ROMs to
  100. the booted system.
  101. The boot line is of the form:
  102. .CS
  103. bootdev(unitnum,procnum)hostname:filename e=# b=# h=# g=# u=userid pw=passwd f=#
  104. tn=targetname s=startupscript o=other
  105. .CE
  106. where:
  107. .iP <bootdev> 12
  108. the boot device (required); for example, "ex" for Excelan Ethernet, "bp" for 
  109. backplane.  For the backplane, this field can have an optional anchor
  110. address specification of the form "bp=<adrs>" (see bootBpAnchorExtract()).
  111. .iP <unitnum>
  112. the unit number of the boot device (0..n).
  113. .iP <procnum>
  114. the processor number on the backplane, 0..n (required for VME boards).
  115. .iP <hostname>
  116. the name of the boot host (required).
  117. .iP <filename>
  118. the file to be booted (required).
  119. .iP "e" "" 3
  120. the Internet address of the Ethernet interface.
  121. This field can have an optional subnet mask
  122. of the form <inet_adrs>:<subnet_mask>. If DHCP
  123. is used to obtain the configuration parameters,
  124. lease timing information may also be present.
  125. This information takes the form <lease_duration>:<lease_origin>
  126. and is appended to the end of the field.
  127. (see bootNetmaskExtract() and bootLeaseExtract()).
  128. .iP "b"
  129. the Internet address of the backplane interface.
  130. This field can have an optional subnet mask
  131. and/or lease timing information as "e".
  132. .iP "h"
  133. the Internet address of the boot host.
  134. .iP "g"
  135. the Internet address of the gateway to the boot host.
  136. Leave this parameter blank if the host is on same network.
  137. .iP "u"
  138. a valid user name on the boot host.
  139. .iP "pw"
  140. the password for the user on the host.
  141. This parameter is usually left blank.
  142. If specified, FTP is used for file transfers.
  143. .iP "f"
  144. the system-dependent configuration flags.
  145. This parameter contains an `or' of option bits defined in
  146. sysLib.h.
  147. .iP "tn"
  148. the name of the system being booted
  149. .iP "s"
  150. the name of a file to be executed as a start-up script.
  151. .iP "o"
  152. "other" string for use by the application.
  153. .LP
  154. The Internet addresses are specified in "dot" notation (e.g., 90.0.0.2).
  155. The order of assigned values is arbitrary.
  156. EXAMPLE
  157. .CS
  158. enp(0,0)host:/usr/wpwr/target/config/mz7122/vxWorks e=90.0.0.2 b=91.0.0.2
  159.  h=100.0.0.4    g=90.0.0.3 u=bob pw=realtime f=2 tn=target
  160.  s=host:/usr/bob/startup o=any_string
  161. .CE
  162. INCLUDE FILES: bootLib.h
  163. SEE ALSO: bootConfig
  164. */
  165. /* LINTLIBRARY */
  166. #include "vxWorks.h"
  167. #include "ctype.h"
  168. #include "string.h"
  169. #include "sysLib.h"
  170. #include "bootLib.h"
  171. #include "stdio.h"
  172. #include "fioLib.h"
  173. #include "private/vmLibP.h"
  174. #include "taskLib.h"
  175. /* macros that fill in size parameter */
  176. #define GET_WORD(pp, field, delims)
  177. getWord (pp, field, sizeof (field), delims)
  178. #define GET_ASSIGN(pp, name, field)
  179. getAssign (pp, name, field, sizeof (field))
  180. #define PARAM_PRINT_WIDTH 21
  181. LOCAL char strBootDevice [] = "boot device";
  182. LOCAL char strHostName [] = "host name";
  183. LOCAL char strTargetName [] = "target name (tn)";
  184. LOCAL char strFileName [] = "file name";
  185. LOCAL char strInetOnEthernet [] = "inet on ethernet (e)";
  186. LOCAL char strInetOnBackplane [] = "inet on backplane (b)";
  187. LOCAL char strHostInet [] = "host inet (h)";
  188. LOCAL char strGatewayInet [] = "gateway inet (g)";
  189. LOCAL char strUser [] = "user (u)";
  190. LOCAL char strFtpPw [] = "ftp password (pw)";
  191. LOCAL char strFtpPwLong [] = "ftp password (pw) (blank = use rsh)";
  192. LOCAL char strUnitNum []                = "unit number";
  193. LOCAL char strProcNum [] = "processor number";
  194. LOCAL char strFlags [] = "flags (f)";
  195. LOCAL char strStartup [] = "startup script (s)";
  196. LOCAL char strOther [] = "other (o)";
  197. /* forward static functions */
  198. static STATUS bootSubfieldExtract (char *string, int *pValue, char
  199. delimeter);
  200. static void addAssignNum (char *string, char *code, int value);
  201. static void addAssignString (char *string, char *code, char *value);
  202. static BOOL getWord (char ** ppString, char *pWord, int length, char *delim);
  203. static BOOL getConst (char ** ppString, char *pConst);
  204. static BOOL getNum (char ** ppString, int *pNum);
  205. static BOOL getAssign (char ** ppString, char *valName, char *pVal, int
  206. maxLen);
  207. static BOOL getAssignNum (char ** ppString, char *valName, int *pVal);
  208. static void printClear (char *param);
  209. static void printParamNum (char *paramName, int value, BOOL hex);
  210. static void printParamString (char *paramName, char *param);
  211. static int promptParamBootDevice (char *paramName, char *param, int *pValue, 
  212.                              int sizeParamName);
  213. static int promptParamString (char *paramName, char *param, int sizeParamName);
  214. static int promptParamNum (char *paramName, int *pValue, BOOL hex);
  215. static int promptRead (char *buf, int bufLen);
  216. static void skipSpace (char ** strptr);
  217. /*******************************************************************************
  218. *
  219. * bootStringToStruct - interpret the boot parameters from the boot line
  220. *
  221. * This routine parses the ASCII string and returns the values into
  222. * the provided parameters.
  223. *
  224. * For a description of the format of the boot line, see the manual entry 
  225. * for bootLib 
  226. *
  227. * RETURNS:
  228. * A pointer to the last character successfully parsed plus one
  229. * (points to EOS, if OK).  The entire boot line is parsed.
  230. */
  231. char *bootStringToStruct
  232.     (
  233.     char *bootString,    /* boot line to be parsed */
  234.     FAST BOOT_PARAMS *pBootParams /* where to return parsed boot line */
  235.     )
  236.     {
  237.     char *p1 = bootString;
  238.     char *p1Save;
  239.     char *p2;
  240.     char hostAndFile [BOOT_HOST_LEN + BOOT_FILE_LEN];
  241.     /* initialize boot parameters */
  242.     bzero ((char *) pBootParams, sizeof (*pBootParams));
  243.     /* get boot device and proc num */
  244.     if (!GET_WORD  (&p1, pBootParams->bootDev, " t(") ||
  245. !getConst (&p1, "(") ||
  246. !getNum   (&p1, &pBootParams->unitNum) ||
  247. !getConst (&p1, ",") ||
  248. !getNum   (&p1, &pBootParams->procNum) ||
  249. !getConst (&p1, ")"))
  250. {
  251. return (p1);
  252. }
  253.     /* get host name and boot file, if present */
  254.     p1Save = p1;
  255.     GET_WORD  (&p1, hostAndFile, " t");
  256.     if (index (hostAndFile, ':') != NULL)
  257. {
  258. p2 = hostAndFile;
  259. GET_WORD  (&p2, pBootParams->hostName, ":");
  260. getConst (&p2, ":");
  261. GET_WORD  (&p2, pBootParams->bootFile, " t");
  262. }
  263.     else
  264. p1 = p1Save;
  265.     /* get optional assignments */
  266.     while (skipSpace (&p1), (*p1 != EOS))
  267. {
  268. if (!GET_ASSIGN (&p1, "ead", pBootParams->ead) &&
  269.     !GET_ASSIGN (&p1, "e",   pBootParams->ead) &&
  270.     !GET_ASSIGN (&p1, "bad", pBootParams->bad) &&
  271.     !GET_ASSIGN (&p1, "b",   pBootParams->bad) &&
  272.     !GET_ASSIGN (&p1, "had", pBootParams->had) &&
  273.     !GET_ASSIGN (&p1, "h",   pBootParams->had) &&
  274.     !GET_ASSIGN (&p1, "gad", pBootParams->gad) &&
  275.     !GET_ASSIGN (&p1, "g",   pBootParams->gad) &&
  276.     !GET_ASSIGN (&p1, "usr", pBootParams->usr) &&
  277.     !GET_ASSIGN (&p1, "u",   pBootParams->usr) &&
  278.     !GET_ASSIGN (&p1, "pw",  pBootParams->passwd) &&
  279.     !GET_ASSIGN (&p1, "o",   pBootParams->other) &&
  280.     !GET_ASSIGN (&p1, "tn",  pBootParams->targetName) &&
  281.     !GET_ASSIGN (&p1, "hn",  pBootParams->hostName) &&
  282.     !GET_ASSIGN (&p1, "fn",  pBootParams->bootFile) &&
  283.     !GET_ASSIGN (&p1, "s",  pBootParams->startupScript) &&
  284.     !getAssignNum (&p1, "n", &pBootParams->procNum) &&
  285.     !getAssignNum (&p1, "f", &pBootParams->flags))
  286.     {
  287.     break;
  288.     }
  289. }
  290.     return (p1);
  291.     }
  292. /*******************************************************************************
  293. *
  294. * bootStructToString - construct a boot line
  295. *
  296. * This routine encodes a boot line using the specified boot parameters.
  297. *
  298. * For a description of the format of the boot line, see the manual 
  299. * entry for bootLib.
  300. *
  301. * RETURNS: OK.
  302. */
  303. STATUS bootStructToString
  304.     (
  305.     char *paramString,         /* where to return the encoded boot line */
  306.     FAST BOOT_PARAMS *pBootParams   /* boot line structure to be encoded */
  307.     )
  308.     {
  309.     UINT state;
  310.     BOOL writeProtected = FALSE;
  311.     int pageSize = 0;
  312.     char *pageAddr = NULL;
  313.     /* see if we need to write enable the memory */
  314.     if (vmLibInfo.vmLibInstalled)
  315. {
  316. pageSize = VM_PAGE_SIZE_GET();
  317. pageAddr = (char *) ((UINT) paramString / pageSize * pageSize);
  318. if (VM_STATE_GET (NULL, (void *) pageAddr, &state) != ERROR)
  319.     if ((state & VM_STATE_MASK_WRITABLE) == VM_STATE_WRITABLE_NOT)
  320. {
  321. writeProtected = TRUE;
  322. TASK_SAFE();
  323. VM_STATE_SET (NULL, pageAddr, pageSize, VM_STATE_MASK_WRITABLE,
  324.       VM_STATE_WRITABLE);
  325. }
  326. }
  327.     if ((pBootParams->hostName[0] == EOS) && (pBootParams->bootFile[0] == EOS))
  328. sprintf (paramString, "%s(%d,%d)", pBootParams->bootDev,
  329.  pBootParams->unitNum, pBootParams->procNum);
  330.     else
  331. sprintf (paramString, "%s(%d,%d)%s:%s", pBootParams->bootDev,
  332.  pBootParams->unitNum, pBootParams->procNum, 
  333.                  pBootParams->hostName, pBootParams->bootFile);
  334.     addAssignString (paramString, "e", pBootParams->ead);
  335.     addAssignString (paramString, "b", pBootParams->bad);
  336.     addAssignString (paramString, "h", pBootParams->had);
  337.     addAssignString (paramString, "g", pBootParams->gad);
  338.     addAssignString (paramString, "u", pBootParams->usr);
  339.     addAssignString (paramString, "pw", pBootParams->passwd);
  340.     addAssignNum (paramString, "f", pBootParams->flags);
  341.     addAssignString (paramString, "tn", pBootParams->targetName);
  342.     addAssignString (paramString, "s", pBootParams->startupScript);
  343.     addAssignString (paramString, "o", pBootParams->other);
  344.     if (writeProtected)
  345. {
  346. VM_STATE_SET (NULL, pageAddr, pageSize, 
  347.       VM_STATE_MASK_WRITABLE, VM_STATE_WRITABLE_NOT);
  348. TASK_UNSAFE();
  349. }
  350.     return (OK);
  351.     }
  352. /*******************************************************************************
  353. *
  354. * bootParamsShow - display boot line parameters
  355. *
  356. * This routine displays the boot parameters in the specified boot string
  357. * one parameter per line.
  358. *
  359. * RETURNS: N/A
  360. */
  361. void bootParamsShow
  362.     (
  363.     char *paramString           /* boot parameter string */
  364.     )
  365.     {
  366.     BOOT_PARAMS bootParams;
  367.     char *pS;
  368.     if (paramString == NULL)
  369.      {
  370. printf ("No boot parameter string specified.n");
  371. return;
  372. }
  373.     pS = bootStringToStruct (paramString, &bootParams);
  374.     if (*pS != EOS)
  375. {
  376. bootParamsErrorPrint (paramString, pS);
  377. return;
  378. }
  379.     printf ("n");
  380.     printParamString (strBootDevice, bootParams.bootDev);
  381.     printParamNum (strUnitNum, bootParams.unitNum, FALSE);
  382.     printParamNum (strProcNum, bootParams.procNum, FALSE);
  383.     printParamString (strHostName, bootParams.hostName);
  384.     printParamString (strFileName, bootParams.bootFile);
  385.     printParamString (strInetOnEthernet, bootParams.ead);
  386.     printParamString (strInetOnBackplane, bootParams.bad);
  387.     printParamString (strHostInet, bootParams.had);
  388.     printParamString (strGatewayInet, bootParams.gad);
  389.     printParamString (strUser, bootParams.usr);
  390.     printParamString (strFtpPw, bootParams.passwd);
  391.     printParamNum (strFlags, bootParams.flags, TRUE);
  392.     printParamString (strTargetName, bootParams.targetName);
  393.     printParamString (strStartup, bootParams.startupScript);
  394.     printParamString (strOther, bootParams.other);
  395.     printf ("n");
  396.     }
  397. /*******************************************************************************
  398. *
  399. * bootParamsPrompt - prompt for boot line parameters
  400. *
  401. * This routine displays the current value of each boot parameter and prompts
  402. * the user for a new value.  Typing a RETURN leaves the parameter unchanged.
  403. * Typing a period (.) clears the parameter.
  404. *
  405. * The parameter <string> holds the initial values.  The new boot line is
  406. * copied over <string>.  If there are no initial values, <string> is
  407. * empty on entry.
  408. *
  409. * RETURNS: N/A
  410. */
  411. void bootParamsPrompt
  412.     (
  413.     char *string        /* default boot line */
  414.     )
  415.     {
  416.     BOOT_PARAMS bp;
  417.     FAST int n = 0;
  418.     FAST int i;
  419.     /* interpret the boot parameters */
  420.     (void) bootStringToStruct (string, &bp);
  421.     printf ("n'.' = clear field;  '-' = go to previous field;  ^D = quitnn");
  422.     /* prompt the user for each item;
  423.      *   i:  0 = same field, 1 = next field, -1 = previous field,
  424.      *     -98 = error, -99 = quit
  425.      */
  426.     FOREVER
  427. {
  428. switch (n)
  429.     {
  430.     case 0:  i = promptParamBootDevice (strBootDevice, bp.bootDev, 
  431.                                 &bp.unitNum, sizeof (bp.bootDev));  break; 
  432.     case 1:  i = promptParamNum (strProcNum, &bp.procNum, FALSE);break;
  433.     case 2:  i = promptParamString (strHostName, bp.hostName,
  434. sizeof (bp.hostName)); break;
  435.     case 3:  i = promptParamString (strFileName, bp.bootFile,
  436. sizeof (bp.bootFile)); break;
  437.     case 4:  i = promptParamString (strInetOnEthernet, bp.ead,
  438. sizeof (bp.ead)); break;
  439.     case 5:  i = promptParamString (strInetOnBackplane, bp.bad,
  440. sizeof (bp.bad));break;
  441.     case 6:  i = promptParamString (strHostInet, bp.had,
  442. sizeof (bp.had)); break;
  443.     case 7:  i = promptParamString (strGatewayInet, bp.gad,
  444. sizeof (bp.gad)); break;
  445.     case 8:  i = promptParamString (strUser, bp.usr,
  446. sizeof (bp.usr)); break;
  447.     case 9:  i = promptParamString (strFtpPwLong, bp.passwd,
  448. sizeof (bp.passwd)); break;
  449.     case 10: i = promptParamNum (strFlags, &bp.flags, TRUE); break;
  450.     case 11: i = promptParamString (strTargetName, bp.targetName,
  451. sizeof (bp.targetName));break;
  452.     case 12: i = promptParamString (strStartup, bp.startupScript,
  453. sizeof (bp.startupScript));break;
  454.     case 13: i = promptParamString (strOther, bp.other,
  455. sizeof (bp.other)); break;
  456.     default: i = -99; break;
  457.     }
  458. /* check for QUIT */
  459. if (i == -99)
  460.     {
  461.     printf ("n");
  462.     break;
  463.     }
  464. /* move to new field */
  465. if (i != -98)
  466.     n += i;
  467. }
  468.     (void) bootStructToString (string, &bp);
  469.     }
  470. /******************************************************************************
  471. *
  472. * bootParamsErrorPrint - print boot string error indicator
  473. *
  474. * print error msg with '^' where parse failed
  475. *
  476. * NOMANUAL
  477. */
  478. void bootParamsErrorPrint
  479.     (
  480.     char *bootString,
  481.     char *pError
  482.     )
  483.     {
  484.     printf ("Error in boot line:n%sn%*cn", bootString,
  485.     (int) (pError - bootString + 1), '^');
  486.     }
  487. /*******************************************************************************
  488. *
  489. * bootLeaseExtract - extract the lease information from an Internet address
  490. *
  491. * This routine extracts the optional lease duration and lease origin fields 
  492. * from an Internet address field for use with DHCP.  The lease duration can be 
  493. * specified by appending a colon and the lease duration to the netmask field.
  494. * For example, the "inet on ethernet" field of the boot parameters could be 
  495. * specified as:
  496. * .CS
  497. *     inet on ethernet: 90.1.0.1:ffff0000:1000
  498. * .CE
  499. *
  500. * If no netmask is specified, the contents of the field could be:
  501. * .CS
  502. *     inet on ethernet: 90.1.0.1::ffffffff
  503. * .CE
  504. *
  505. * In the first case, the lease duration for the address is 1000 seconds. The 
  506. * second case indicates an infinite lease, and does not specify a netmask for
  507. * the address. At the beginning of the boot process, the value of the lease
  508. * duration field is used to specify the requested lease duration. If the field 
  509. * not included, the value of DHCP_DEFAULT_LEASE is used
  510. * instead.
  511. * The lease origin is specified with the same format as the lease duration,
  512. * but is added during the boot process. The presence of the lease origin
  513. * field distinguishes addresses assigned by a DHCP server from addresses
  514. * entered manually. Addresses assigned by a DHCP server may be replaced
  515. * if the bootstrap loader uses DHCP to obtain configuration parameters.
  516. * The value of the lease origin field at the beginning of the boot process
  517. * is ignored.
  518. *
  519. * This routine extracts the optional lease duration by replacing the preceding 
  520. * colon in the specified string with an EOS and then scanning the remainder as 
  521. * a number.  The lease duration and lease origin values are returned via
  522. * the <pLeaseLen> and <pLeaseStart> pointers, if those parameters are not NULL.
  523. *
  524. * RETURNS:
  525. *   2 if both lease values are specified correctly in <string>, or 
  526. *  -2 if one of the two values is specified incorrectly.
  527. * If only the lease duration is found, it returns:
  528. *   1 if the lease duration in <string> is specified correctly,
  529. *   0 if the lease duration is not specified in <string>, or
  530. *  -1 if an invalid lease duration is specified in <string>.
  531. */
  532. int bootLeaseExtract
  533.     (
  534.     char *string,       /* string containing addr field */
  535.     u_long *pLeaseLen,  /* pointer to storage for lease duration */
  536.     u_long *pLeaseStart /* pointer to storage for lease origin */
  537.     )
  538.     {
  539.     FAST char *pDelim;
  540.     FAST char *offset;
  541.     int result;
  542.     int status = 0;
  543.     int start;
  544.     int length;
  545.     /* find delimeter for netmask */
  546.     offset = index (string, ':');
  547.     if (offset == NULL)
  548. return (0); /* no subfield specified */
  549.     /* Start search after netmask field. */
  550.     pDelim = offset + 1;
  551.     /* Search for lease duration field. */
  552.     offset = index (pDelim, ':');
  553.     if (offset == NULL)         /* No lease duration tag. */
  554.         return (0);
  555.     /* Start search after duration. */
  556.     pDelim = offset + 1;
  557.     status = bootSubfieldExtract (pDelim, &start, ':');
  558.     if (status == 1 && pLeaseStart != NULL)
  559.         *pLeaseStart = start;
  560.     /* Reset search pointer to obtain lease duration. */
  561.     offset = index (string, ':');
  562.     if (offset == NULL)      /* Sanity check - should not occur. */
  563.         return (0);
  564.    /* Lease duration follows netmask. */
  565.     pDelim = offset + 1;
  566.     /* Store lease duration if found. */
  567.     result = bootSubfieldExtract (pDelim, &length, ':');
  568.     if (result == 1 && pLeaseLen != NULL)
  569.         *pLeaseLen = length;
  570.     if (status != 0)    /* Both lease values were present. */
  571.         {
  572.         if (status < 0 || result < 0)    /* Error reading one of the values. */
  573.             return (-2);
  574.         else
  575.             return (2);     /* Both lease values read successfully. */
  576.         }
  577.     return (result);
  578.     }
  579. /*******************************************************************************
  580. *
  581. * bootNetmaskExtract - extract the net mask field from an Internet address
  582. *
  583. * This routine extracts the optional subnet mask field from an Internet address
  584. * field.  Subnet masks can be specified for an Internet interface by appending
  585. * to the Internet address a colon and the net mask in hexadecimal.  
  586. * For example, the "inet on ethernet" field of the boot parameters could 
  587. * be specified as:
  588. * .CS
  589. *     inet on ethernet: 90.1.0.1:ffff0000
  590. * .CE
  591. * In this case, the network portion of the address (normally just 90)
  592. * is extended by the subnet mask (to 90.1).  This routine extracts the
  593. * optional trailing subnet mask by replacing the colon in the specified
  594. * string with an EOS and then scanning the remainder as a hex number.
  595. * This number, the net mask, is returned via the <pNetmask> pointer.
  596. * This routine also handles an empty netmask field used as a placeholder
  597. * for the lease duration field (see bootLeaseExtract() ). In that case,
  598. * the colon separator is replaced with an EOS and the value of netmask is
  599. * set to 0. 
  600. *
  601. * RETURNS:
  602. *   1 if the subnet mask in <string> is specified correctly,
  603. *   0 if the subnet mask in <string> is not specified, or
  604. *  -1 if an invalid subnet mask is specified in <string>.
  605. */
  606. STATUS bootNetmaskExtract
  607.     (
  608.     char *string,       /* string containing addr field */
  609.     int *pNetmask       /* pointer where to return net mask */
  610.     )
  611.     {
  612.     FAST char *pDelim;
  613.     char *offset;
  614.     /* find delimeter */
  615.     pDelim = index (string, ':');
  616.     if (pDelim == NULL)
  617. return (0); /* no subfield specified */
  618.     /* Check if netmask field precedes timeout field. */
  619.     offset = pDelim + 1;
  620.     skipSpace(&offset);
  621.     if (*offset == ':' || *offset == EOS)  /* Netmask field is placeholder. */
  622.         {
  623.          *pDelim = EOS;
  624.          *pNetmask = 0;
  625.          return (1);
  626.         }
  627.          
  628.     return (bootSubfieldExtract (string, pNetmask, ':'));
  629.     }
  630. /******************************************************************************
  631. *
  632. * bootBpAnchorExtract - extract a backplane address from a device field
  633. *
  634. * This routine extracts the optional backplane anchor address field from a
  635. * boot device field.  The anchor can be specified for the backplane
  636. * driver by appending to the device name (i.e., "bp") an equal sign (=) and the
  637. * address in hexadecimal.  For example, the "boot device" field of the boot
  638. * parameters could be specified as:
  639. * .CS
  640. *     boot device: bp=800000
  641. * .CE
  642. * In this case, the backplane anchor address would be at address 0x800000,
  643. * instead of the default specified in config.h.
  644. *
  645. * This routine picks off the optional trailing anchor address by replacing
  646. * the equal sign (=) in the specified string with an EOS and then scanning the
  647. * remainder as a hex number.
  648. * This number, the anchor address, is returned via the <pAnchorAdrs> pointer.
  649. *
  650. * RETURNS:
  651. *   1 if the anchor address in <string> is specified correctly,
  652. *   0 if the anchor address in <string> is not specified, or
  653. *  -1 if an invalid anchor address is specified in <string>.
  654. */
  655. STATUS bootBpAnchorExtract
  656.     (
  657.     char *string,       /* string containing adrs field */
  658.     char **pAnchorAdrs  /* pointer where to return anchor address */
  659.     )
  660.     {
  661.     return (bootSubfieldExtract (string, (int *) pAnchorAdrs, '='));
  662.     }
  663. /******************************************************************************
  664. *
  665. * bootSubfieldExtract - extract a numeric subfield from a boot field
  666. *
  667. * Extracts subfields in fields of the form "<field><delimeter><subfield>".
  668. * i.e. <inet>:<netmask> and bp=<anchor>
  669. */
  670. LOCAL STATUS bootSubfieldExtract
  671.     (
  672.     char *string,       /* string containing field to be extracted */
  673.     int *pValue,        /* pointer where to return value */
  674.     char delimeter      /* character delimeter */
  675.     )
  676.     {
  677.     FAST char *pDelim;
  678.     int value;
  679.     /* find delimeter */
  680.     pDelim = index (string, delimeter);
  681.     if (pDelim == NULL)
  682. return (0); /* no subfield specified */
  683.     /* scan remainder for numeric subfield */
  684.     string = pDelim + 1;
  685.     if (bootScanNum (&string, &value, TRUE) != OK)
  686. return (-1); /* invalid subfield specified */
  687.     *pDelim = EOS; /* terminate string at the delimeter */
  688.     *pValue = value; /* return value */
  689.     return (1); /* valid subfield specified */
  690.     }
  691. /*******************************************************************************
  692. *
  693. * addAssignNum - add a numeric value assignment to a string
  694. */
  695. LOCAL void addAssignNum
  696.     (
  697.     FAST char *string,
  698.     char *code,
  699.     int value
  700.     )
  701.     {
  702.     if (value != 0)
  703. {
  704. string += strlen (string);
  705. sprintf (string, (value <= 7) ? " %s=%d" : " %s=0x%x", code, value);
  706. }
  707.     }
  708. /*******************************************************************************
  709. *
  710. * addAssignString - add a string assignment to a string
  711. */
  712. LOCAL void addAssignString
  713.     (
  714.     FAST char *string,
  715.     char *code,
  716.     char *value
  717.     )
  718.     {
  719.     if (value[0] != EOS)
  720. {
  721. string += strlen (string);
  722. sprintf (string, " %s=%s", code, value);
  723. }
  724.     }
  725. /*******************************************************************************
  726. *
  727. * getWord - get a word out of a string
  728. *
  729. * Words longer than the specified max length are truncated.
  730. *
  731. * RETURNS: TRUE if word is successfully extracted from string, FALSE otherwise;
  732. * Also updates ppString to point to next character following extracted word.
  733. */
  734. LOCAL BOOL getWord
  735.     (
  736.     char **ppString,    /* ptr to ptr to string from which to get word */
  737.     FAST char *pWord,   /* where to return word */
  738.     int length,         /* max length of word to get including EOS */
  739.     char *delim         /* string of delimiters that can terminate word */
  740.     )
  741.     {
  742.     FAST char *pStr;
  743.     skipSpace (ppString);
  744.     /* copy up to any specified delimeter, EOS, or max length */
  745.     pStr = *ppString;
  746.     while ((--length > 0) && (*pStr != EOS) && (index (delim, *pStr) == 0))
  747. *(pWord++) = *(pStr++);
  748.     *pWord = EOS;
  749.     /* if we copied anything at all, update pointer and return TRUE */
  750.     if (pStr != *ppString)
  751. {
  752. *ppString = pStr;
  753. return (TRUE);
  754. }
  755.     /* no word to get */
  756.     return (FALSE);
  757.     }
  758. /*******************************************************************************
  759. *
  760. * getConst - get a constant string out of a string
  761. *
  762. * case insensitive compare for identical strings
  763. */
  764. LOCAL BOOL getConst
  765.     (
  766.     char **ppString,
  767.     FAST char *pConst
  768.     )
  769.     {
  770.     FAST int ch1;
  771.     FAST int ch2;
  772.     FAST char *pString;
  773.     skipSpace (ppString);
  774.     for (pString = *ppString; *pConst != EOS; ++pString, ++pConst)
  775. {
  776. ch1 = *pString;
  777. ch1 = (isascii (ch1) && isupper (ch1)) ? tolower (ch1) : ch1;
  778. ch2 = *pConst;
  779. ch2 = (isascii (ch2) && isupper (ch2)) ? tolower (ch2) : ch2;
  780. if (ch1 != ch2)
  781.     return (FALSE);
  782. }
  783.     /* strings match */
  784.     *ppString = pString;
  785.     return (TRUE);
  786.     }
  787. /*******************************************************************************
  788. *
  789. * getNum - get a numeric value from a string
  790. */
  791. LOCAL BOOL getNum
  792.     (
  793.     FAST char **ppString,
  794.     int *pNum
  795.     )
  796.     {
  797.     skipSpace (ppString);
  798.     if (sscanf (*ppString, "%d", pNum) != 1)
  799. return (FALSE);
  800.     /* skip over number */
  801.     while (isdigit (**ppString))
  802. (*ppString)++;
  803.     return (TRUE);
  804.     }
  805. /*******************************************************************************
  806. *
  807. * getAssign - get an assignment out of a string
  808. */
  809. LOCAL BOOL getAssign
  810.     (
  811.     FAST char **ppString,
  812.     char *valName,
  813.     char *pVal,
  814.     int maxLen
  815.     )
  816.     {
  817.     skipSpace (ppString);
  818.     if (!getConst (ppString, valName))
  819. return (FALSE);
  820.     skipSpace (ppString);
  821.     if (!getConst (ppString, "="))
  822. return (FALSE);
  823.     return (getWord (ppString, pVal, maxLen, " t"));
  824.     }
  825. /*******************************************************************************
  826. *
  827. * getAssignNum - get a numeric assignment out of a string
  828. */
  829. LOCAL BOOL getAssignNum
  830.     (
  831.     FAST char **ppString,
  832.     char *valName,
  833.     int *pVal
  834.     )
  835.     {
  836.     char buf [BOOT_FIELD_LEN];
  837.     char *pBuf = buf;
  838.     char *pTempString;
  839.     int tempVal;
  840.     /* we don't modify *ppString or *pVal until we know we have a good scan */
  841.     /* first pick up next field into buf */
  842.     pTempString = *ppString;
  843.     if (!getAssign (&pTempString, valName, buf, sizeof (buf)))
  844. return (FALSE);
  845.     /* now scan buf for a valid number */
  846.     if ((bootScanNum (&pBuf, &tempVal, FALSE) != OK) || (*pBuf != EOS))
  847. return (FALSE);
  848.     /* update string pointer and return value */
  849.     *ppString = pTempString;
  850.     *pVal = tempVal;
  851.     return (TRUE);
  852.     }
  853. /*******************************************************************************
  854. *
  855. * printClear - print string with '?' for unprintable characters
  856. */
  857. LOCAL void printClear
  858.     (
  859.     FAST char *param
  860.     )
  861.     {
  862.     FAST char ch;
  863.     while ((ch = *(param++)) != EOS)
  864. printf ("%c", (isascii (ch) && isprint (ch)) ? ch : '?');
  865.     }
  866. /*******************************************************************************
  867. *
  868. * printParamNum - print number parameter
  869. */
  870. LOCAL void printParamNum
  871.     (
  872.     char *paramName,
  873.     int  value,
  874.     BOOL hex
  875.     )
  876.     {
  877.     printf (hex ? "%-*s: 0x%x n" : "%-*s: %d n", PARAM_PRINT_WIDTH,
  878.     paramName, value);
  879.     }
  880. /*******************************************************************************
  881. *
  882. * printParamString - print string parameter
  883. */
  884. LOCAL void printParamString
  885.     (
  886.     char *paramName,
  887.     char *param
  888.     )
  889.     {
  890.     if (param [0] != EOS)
  891. {
  892. printf ("%-*s: ", PARAM_PRINT_WIDTH, paramName);
  893. printClear (param);
  894. printf ("n");
  895. }
  896.     }
  897. /*******************************************************************************
  898. *
  899. * promptParamBootDevice - prompt the user for the boot device
  900. *
  901. * This routine reads the boot device name, and an optional unit number.
  902. * If the unit number is not supplied, it defaults to 0.
  903. *
  904. * - carriage return leaves the parameter unmodified;
  905. * - "." clears the parameter (null boot device and 0 unit number).
  906. */
  907. LOCAL int promptParamBootDevice
  908.     (
  909.     char *paramName,
  910.     FAST char *param,
  911.     int *pValue,
  912.     int sizeParamName
  913.     )
  914.     {
  915.     FAST int i;
  916.     int value;
  917.     char buf[BOOT_FIELD_LEN];
  918.     char *pBuf;
  919.     sprintf(buf, "%s%d", param, *pValue);
  920.     printf ("%-*s: ", PARAM_PRINT_WIDTH, strBootDevice);
  921.     printClear (buf);
  922.     if (*buf != EOS)
  923. printf (" ");
  924.     if ((i = promptRead (buf, sizeParamName)) != 0)
  925. return (i);
  926.     if (buf[0] == '.')
  927. {
  928. param[0] = EOS;               /* just '.'; make empty fields */
  929.         *pValue = 0;
  930. return (1);
  931. }
  932.     i = 0;
  933.     /* Extract first part of name of boot device. */
  934.     while (!isdigit(buf[i]) && buf[i] != '=' && buf[i] != EOS)
  935.        {
  936.         param[i] = buf[i];
  937.         i++;
  938.        }
  939.     param[i] = EOS;
  940.     /* Extract unit number, if specified. */
  941.     if (isdigit(buf[i]))     /* Digit before equal sign is unit number. */
  942.       {
  943.        pBuf = &buf[i];
  944.        if (bootScanNum (&pBuf, &value, FALSE) != OK)
  945.           {
  946.   printf ("invalid unit number.n");
  947.           return (-98);
  948.           }
  949.        strcat(param, pBuf);
  950.       }
  951.    else                          /* No unit number specified. */
  952.       {
  953.        value = 0;
  954.        if (buf[i] == '=')
  955.           strcat(param, &buf[i]);    /* Append remaining boot device name. */
  956.       }
  957.     *pValue = value; 
  958.     return (1);
  959.     }
  960. /*******************************************************************************
  961. *
  962. * promptParamString - prompt the user for a string parameter
  963. *
  964. * - carriage return leaves the parameter unmodified;
  965. * - "." clears the parameter (null string).
  966. */
  967. LOCAL int promptParamString
  968.     (
  969.     char *paramName,
  970.     FAST char *param,
  971.     int sizeParamName
  972.     )
  973.     {
  974.     FAST int i;
  975.     char buf [BOOT_FIELD_LEN];
  976.     printf ("%-*s: ", PARAM_PRINT_WIDTH, paramName);
  977.     printClear (param);
  978.     if (*param != EOS)
  979. printf (" ");
  980.     if ((i = promptRead (buf, sizeParamName)) != 0)
  981. return (i);
  982.     if (buf[0] == '.')
  983. {
  984. param [0] = EOS; /* just '.'; make empty field */
  985. return (1);
  986. }
  987.     strcpy (param, buf); /* update parameter */
  988.     return (1);
  989.     }
  990. /*******************************************************************************
  991. *
  992. * promptParamNum - prompt the user for a parameter
  993. *
  994. * - carriage return leaves the parameter unmodified;
  995. * - "." clears the parameter (0)
  996. */
  997. LOCAL int promptParamNum
  998.     (
  999.     char *paramName,
  1000.     int *pValue,
  1001.     BOOL hex
  1002.     )
  1003.     {
  1004.     char buf [BOOT_FIELD_LEN];
  1005.     char *pBuf;
  1006.     int value;
  1007.     int i;
  1008.     printf (hex ? "%-*s: 0x%x " : "%-*s: %d ", PARAM_PRINT_WIDTH, paramName,
  1009.     *pValue);
  1010.     if ((i = promptRead (buf, sizeof (buf))) != 0)
  1011. return (i);
  1012.     if (buf[0] == '.')
  1013. {
  1014. *pValue = 0; /* just '.'; make empty field (0) */
  1015. return (1);
  1016. }
  1017.     /* scan for number */
  1018.     pBuf = buf;
  1019.     if ((bootScanNum (&pBuf, &value, FALSE) != OK) || (*pBuf != EOS))
  1020. {
  1021. printf ("invalid number.n");
  1022. return (-98);
  1023. }
  1024.     *pValue = value;
  1025.     return (1);
  1026.     }
  1027. /*******************************************************************************
  1028. *
  1029. * promptRead - read the result of a prompt and check for special cases
  1030. *
  1031. * Special cases:
  1032. *    '-'  = previous field
  1033. *    '^D' = quit
  1034. *    CR   = leave field unchanged
  1035. *    too many characters = error
  1036. *
  1037. * RETURNS:
  1038. *    0 = OK
  1039. *    1 = skip this field
  1040. *   -1 = go to previous field
  1041. *  -98 = ERROR
  1042. *  -99 = quit
  1043. */
  1044. LOCAL int promptRead
  1045.     (
  1046.     char *buf,
  1047.     int bufLen
  1048.     )
  1049.     {
  1050.     FAST int i;
  1051.     i = fioRdString (STD_IN, buf, bufLen);
  1052.     if (i == EOF)
  1053. return (-99); /* EOF; quit */
  1054.     if (i == 1)
  1055. return (1); /* just CR; leave field unchanged */
  1056.     if ((i == 2) && (buf[0] == '-'))
  1057. return (-1); /* '-'; go back up */
  1058.     if (i >= bufLen)
  1059. {
  1060. printf ("too big - maximum field width = %d.n", bufLen);
  1061. /* We mustn't take into account the end of the string */ 
  1062. while((i = fioRdString(STD_IN, buf, bufLen)) >= bufLen);
  1063. return (-98);
  1064. }
  1065.     return (0);
  1066.     }
  1067. /*******************************************************************************
  1068. *
  1069. * skipSpace - advance pointer past white space
  1070. *
  1071. * Increments the string pointer passed as a parameter to the next
  1072. * non-white-space character in the string.
  1073. */
  1074. LOCAL void skipSpace
  1075.     (
  1076.     FAST char **strptr  /* pointer to pointer to string */
  1077.     )
  1078.     {
  1079.     while (isspace (**strptr))
  1080. ++*strptr;
  1081.     }
  1082. /******************************************************************************
  1083. *
  1084. * bootScanNum - scan string for numeric value
  1085. *
  1086. * This routine scans the specified string for a numeric value.  The string
  1087. * pointer is updated to reflect where the scan stopped, and the value is
  1088. * returned via pValue.  The value will be scanned by default in decimal unless
  1089. * hex==TRUE.  In either case, preceding the value with "0x" or "$" forces
  1090. * hex.  Spaces before and after number are skipped.
  1091. *
  1092. * RETURNS: OK if value scanned successfully, otherwise ERROR.
  1093. *
  1094. * EXAMPLES:
  1095. * bootScanNum (&string, &value, FALSE);
  1096. *    with:
  1097. * string = "   0xf34  ";
  1098. *     returns OK, string points to EOS, value=0xf34
  1099. * string = "   0xf34r  ";
  1100. *     returns OK, string points to 'r', value=0xf34
  1101. * string = "   r0xf34  ";
  1102. *     returns ERROR, string points to 'r', value unchanged
  1103. *
  1104. * NOMANUAL
  1105. */
  1106. STATUS bootScanNum
  1107.     (
  1108.     FAST char **ppString,
  1109.     int *pValue,
  1110.     FAST BOOL hex
  1111.     )
  1112.     {
  1113.     FAST char *pStr;
  1114.     FAST char ch;
  1115.     FAST int n;
  1116.     FAST int value = 0;
  1117.     skipSpace (ppString);
  1118.     /* pick base */
  1119.     if (**ppString == '$')
  1120. {
  1121. ++*ppString;
  1122. hex = TRUE;
  1123. }
  1124.     else if (strncmp (*ppString, "0x", 2) == 0)
  1125. {
  1126. *ppString += 2;
  1127. hex = TRUE;
  1128. }
  1129.     /* scan string */
  1130.     pStr = *ppString;
  1131.     FOREVER
  1132. {
  1133. ch = *pStr;
  1134. if (!isascii (ch))
  1135.     break;
  1136. if (isdigit (ch))
  1137.     n = ch - '0';
  1138. else
  1139.     {
  1140.     if (!hex)
  1141. break;
  1142.     if (isupper (ch))
  1143. ch = tolower (ch);
  1144.     if ((ch < 'a') || (ch > 'f'))
  1145. break;
  1146.     n = ch - 'a' + 10;
  1147.     }
  1148. value = (value * (hex ? 16 : 10)) + n;
  1149. ++pStr;
  1150. }
  1151.     /* error if we didn't scan any characters */
  1152.     if (pStr == *ppString)
  1153. return (ERROR);
  1154.     /* update users string ptr to point to character that stopped the scan */
  1155.     *ppString = pStr;
  1156.     skipSpace (ppString);
  1157.     *pValue = value;
  1158.     return (OK);
  1159.     }