/*
**************************************************************************
*
* Boot-ROM-Code to load an operating system across a TCP/IP network.
*
* Module: menu.c
* Purpose: Display a menu of bootimage choices
* Entries: domenu
*
**************************************************************************
*
* Copyright (C) 1995-2003 Gero Kuhlmann <gero@gkminix.han.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: menu.c,v 1.5 2003/01/25 23:29:41 gkminix Exp $
*/
#include <general.h>
#include <memory.h>
#include <kernel/net.h>
#include <kernel/arpa.h>
#include <kernel/romlib.h>
#include "bootpriv.h"
#include "menu.h"
/*
**************************************************************************
*
* Internal representation of each bootimage description
*/
struct image {
int tagnum; /* image tag number */
int labellen; /* length of label */
int filenamelen; /* length of file name */
unsigned char *label; /* pointer to label */
unsigned char *filename; /* pointer to file name */
t_ipaddr server; /* server IP address */
t_ipaddr gateway; /* gateway IP address */
};
/*
**************************************************************************
*
* Global variables:
*/
static struct image imagelist[MENU_IMG_NUM]; /* list of menu items */
static t_ipaddr def_server; /* default server */
static t_ipaddr def_gateway; /* default gateway */
static int def_timeout; /* default keyboard timeout */
static int def_choice; /* default menu choice */
static int imagenum; /* number of menu items */
/*
**************************************************************************
*
* Get a numeric response from the user
*/
static int getselect()
{
int num;
int pos;
int i, ch;
/* Clear keyboard buffer */
while (chkkey() >= 0) ;
/* Main loop */
num = -1;
pos = 0;
while (TRUE) {
if ((ch = getkey(def_timeout)) < 0 || ch == CHR_CR)
return(num < 0 ? def_choice : num);
else if (ch == CHR_ESC)
return(-1);
else if (ch == CHR_BS) {
if (pos > 0) {
printf("\b \b");
num = num / 10;
pos--;
}
if (pos == 0)
num = -1;
continue;
} else if (ch < '0' || ch > '9')
continue;
i = ch - '0';
if (num >= 0)
i += num * 10;
if (i >= imagenum)
continue;
num = i;
printf("%c", ch);
pos++;
}
}
/*
**************************************************************************
*
* Decode image file description tag
*/
static int decode_image(tagstr, tagnum)
unsigned char *tagstr;
int tagnum;
{
register unsigned char *cp;
register unsigned char *bp;
struct image *ip;
int strlength;
int i;
/* Copy tag number */
ip = &(imagelist[imagenum]);
ip->tagnum = tagnum;
/* Decode label */
cp = tagstr;
strlength = *cp++;
ip->label = cp;
for (i = 0; *cp && *cp != ':' && strlength > 0; cp++, i++, strlength--) ;
ip->labellen = i;
/* Skip until next colon */
for ( ; *cp && *cp != ':' && strlength > 0; cp++, strlength--) ;
if (!*cp || strlength == 0)
return(FALSE);
cp++;
strlength--;
/* Decode server IP address */
bp = cp;
for ( ; *cp && *cp != ':' && strlength > 0; cp++, strlength--) ;
if (!*cp || strlength == 0)
return(FALSE);
if (*bp == ':')
ip->server = n_IP_ANY;
else if ((ip->server = resolve((char *)bp)) == n_IP_ANY)
return(FALSE);
cp++;
strlength--;
/* Decode gateway IP address */
bp = cp;
for ( ; *cp && *cp != ':' && strlength > 0; cp++, strlength--) ;
if (!*cp || strlength == 0)
return(FALSE);
if (*bp == ':')
ip->gateway = n_IP_ANY;
else if ((ip->gateway = resolve((char *)bp)) == n_IP_ANY)
return(FALSE);
cp++;
strlength--;
/* Decode filename */
ip->filename = cp;
for (i = 0;
*cp && i < MAX_FNAM_LEN - 1 && strlength > 0;
cp++, i++, strlength--)
;
if (*cp && strlength != 0)
return(FALSE);
ip->filenamelen = i;
imagenum++;
return(TRUE);
}
/*
**************************************************************************
*
* Decode default parameter tag
*/
static int decode_params(tagstr)
unsigned char *tagstr;
{
register unsigned char *cp;
int *resp;
int strlength;
int i, offs;
/* Decode the parameter tag string */
cp = tagstr;
strlength = *cp++;
while (*cp && strlength > 0) {
/* Check for valid strings */
if (!memcmp(cp, "timeout=", 8)) {
offs = 8;
resp = &def_timeout;
} else if (!memcmp(cp, "default=", 8)) {
offs = 8;
resp = &def_choice;
} else
return(FALSE);
/* Decode any number following the equal sign */
cp += offs;
strlength -= offs;
i = 0;
while (strlength > 0 && *cp >= '0' && *cp <= '9') {
i = i * 10 + (*cp++ - '0');
strlength--;
}
if ((*cp && *cp != ':') || strlength < 0)
return(FALSE);
*resp = i;
/* Skip colon */
cp++;
strlength--;
}
/* Adjust default choice */
if (def_choice >= MENU_IMG_FIRST) {
for (i = 0; i < imagenum; i++)
if (imagelist[i].tagnum == def_choice) {
def_choice = i;
break;
}
}
if (def_choice >= imagenum)
return(FALSE);
return(TRUE);
}
/*
**************************************************************************
*
* Display a menu of bootimage choices
*/
int domenu()
{
register unsigned char *cp;
struct bootp *bp;
struct image *ip;
int i;
/*
* Select BOOTP reply record for all further operations
*/
if ((bp = bootp_bufs[BOOTP_REPLY]) == NULL)
return(MENU_INVALID);
cur_bootp_buf = BOOTP_REPLY;
/*
* Check the menu magic number in the BOOTP parameter area, including
* the menu definition version number.
*/
if ((cp = get_vend(MENU_ID)) == NULL || *cp != 6 ||
*((unsigned long *)(cp + 1)) != MENU_MAGIC)
return(MENU_INVALID);
#if MENU_VER_MINOR > 0
if (*(cp + 5) != MENU_VER_MAJOR || *(cp + 6) > MENU_VER_MINOR) {
#else
if (*(cp + 5) != MENU_VER_MAJOR) {
#endif
printf("\nMENU: Invalid version number\n");
return(MENU_INVALID);
}
/*
* Initialize the name resolver to allow for symbolic names in BOOTP
* tags.
*/
res_config();
/*
* Initialize the default image description from the BOOTP block. This
* is necessary to be able to restore the BOOTP block with repetitive
* calls to this function.
*/
def_server = bp->bp_siaddr;
def_gateway = n_IP_ANY;
if((cp = get_vend(VEND_ROUTER)) != NULL)
def_gateway = *((t_ipaddr *)(cp + 1));
/* Decode the image file descriptions */
imagenum = 0;
for (i = MENU_IMG_FIRST; i <= MENU_IMG_LAST; i++)
if ((cp = get_vend(i)) != NULL && !decode_image(cp, i)) {
printf("\nMENU: Invalid image description %d\n", i);
return(MENU_INVALID);
}
/* Decode the default parameter tag */
if ((cp = get_vend(MENU_PARAMS)) != NULL && !decode_params(cp)) {
printf("\nMENU: Invalid TAG %d\n", MENU_PARAMS);
return(MENU_INVALID);
}
/* Print the message strings */
printf("\n\n");
for (i = MENU_DISP_FIRST; i <= MENU_DISP_LAST; i++)
if ((cp = get_vend(i)) != NULL) {
int len = *cp++;
printf("%ls\n", cp, len);
}
/* Print the menu and wait for a user keypress */
if (imagenum > 0) {
printf("\n\n");
for (i = 0; i < imagenum; i++)
printf("[%s%d]\t%ls\n", i < 10 ? " ":"", i,
imagelist[i].label, imagelist[i].labellen);
printf("\nSelect a choice: ");
i = getselect();
printf("\n\n");
/* If no filename specified for image, abort menu selection */
ip = &(imagelist[i]);
if (i < 0 || !ip->filenamelen)
return(MENU_ABORT);
/* Set bootimage file name */
memset(bp->bp_file, 0, sizeof(bp->bp_file));
memcpy(bp->bp_file, ip->filename, ip->filenamelen);
/* Set IP of tftp server */
memset(bp->bp_sname, 0, sizeof(bp->bp_sname));
if (ip->server != n_IP_ANY)
bp->bp_siaddr = ip->server;
else
bp->bp_siaddr = def_server;
/* Set gateway IP to reach the server */
if (ip->gateway != n_IP_ANY)
def_gateway = ip->gateway;
if ((cp = get_vend(VEND_ROUTER)) != NULL)
*((t_ipaddr *)(cp + 1)) = def_gateway;
else if ((cp = get_vend(VEND_END)) != NULL &&
(cp + IP_ALEN + 2) <= ((unsigned char *)bp) +
bootp_sizes[cur_bootp_buf]) {
*(cp - 1) = VEND_ROUTER;
*cp = IP_ALEN;
*((t_ipaddr *)(cp + 1)) = def_gateway;
*(cp + IP_ALEN + 1) = VEND_END;
}
printf("Selected %ls\n\n", ip->label, ip->labellen);
}
return(MENU_OK);
}
syntax highlighted by Code2HTML, v. 0.9.1