/*
* getdb.c - Read system definitions from database file
*
* Copyright (C) 1998-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: getdb.c,v 1.6 2003/03/09 00:43:08 gkminix Exp $
*/
#include <common.h>
#include <nblib.h>
#include "makerom.h"
#include "doconfig.h"
#include "protini.h"
/* Variables private to this module */
static struct bootdef bootd; /* boot definition record */
static char *protini = NULL; /* protocol.ini contents */
/*
* Table containing option names for "ldoptsX" parameters.
*/
static struct {
char *name;
int boolval;
int intmin, intmax;
int *optptr[MAXLOADERS];
} opttbl[] = {
{ "useint18", TRUE, 0, 0,
{&bootd.loaders[0].useint18,
&bootd.loaders[1].useint18,
&bootd.loaders[2].useint18}},
{ "cardinst", TRUE, 0, 0,
{&bootd.loaders[0].cardinst,
&bootd.loaders[1].cardinst,
&bootd.loaders[2].cardinst}},
{ "bootask", TRUE, 0, 0,
{&bootd.loaders[0].bootask,
&bootd.loaders[1].bootask,
&bootd.loaders[2].bootask}},
{ "asktime", FALSE, 0, 31,
{&bootd.loaders[0].asktime,
&bootd.loaders[0].asktime,
&bootd.loaders[0].asktime}},
{NULL, FALSE, 0, 0, {NULL, NULL, NULL}}
};
/*
* Read bootrom loader options. This routine gets called everytime
* a "ldoptsX" parameter is found in the database file.
*/
static char *readopts(name, arg)
char *name;
char *arg;
{
char *tok, *val, *cp;
int i, num;
long l;
/* Isolate loader number from parameter name */
assert(strlen(name) == 7 && isdigit(name[6]));
num = name[6] - '1';
assert(num >= 0 && num < MAXLOADERS);
/* Find each option in the list */
tok = strtok(arg, ",");
while (tok) {
/* Skip leading blanks */
while (*tok && (*tok == ' ' || *tok == '\t'))
tok++;
cp = tok;
/* Find end of option name */
while (*cp && (*cp != ' ' && *cp != '\t'))
cp++;
if (*cp) {
/* Skip trailing blanks */
while (*cp && (*cp == ' ' || *cp == '\t'))
*(cp++) = '\0';
if (*cp && *(cp++) != '=')
return("invalid characters following option name");
}
/* Find option value */
val = NULL;
if (*cp == '=') {
/* Skip leading blanks of option value */
while (*cp && (*cp == ' ' || *cp == '\t'))
cp++;
if (!*cp)
return("missing option value");
val = cp;
/* Find end of option value */
while (*cp && (*cp != ' ' && *cp != '\t')) {
*cp = toupper(*cp);
cp++;
}
if (*cp) {
/* Skip trailing blanks */
while (*cp && (*cp == ' ' || *cp == '\t'))
*(cp++) = '\0';
if (*cp)
return("invalid characters following option value");
}
}
/* Find option name in list */
for (i = 0; opttbl[i].name != NULL; i++)
if (!strcmp(tok, opttbl[i].name))
break;
if (opttbl[i].name == NULL)
return("invalid option");
/* Set option value */
if (opttbl[i].boolval) {
if (!strcmp(val, "TRUE"))
*opttbl[i].optptr[num] = TRUE;
else if (!strcmp(val, "FALSE"))
*opttbl[i].optptr[num] = FALSE;
else
return("invalid boolean option value");
} else {
l = strtol(val, &cp, 10);
if (cp != NULL && *cp)
return("invalid integer option value");
if (l < opttbl[i].intmin || l > opttbl[i].intmax)
return("integer option value out of range");
*opttbl[i].optptr[num] = l;
}
/* Proceed with next option */
tok = strtok(NULL, ",");
}
return(NULL);
}
/* Available network driver interface types */
static char *dtypes[] = {
"packet driver", "ndis driver", "undi driver", NULL
};
/* Available bus types */
static char *btypes[] = {
"ISA", "EISA", "MCA", "PCI", NULL
};
/* Available types for output file */
static char *ftypes[] = {
"binary",
"intel hex",
"motorola hex",
"tektronix hex",
"flashcard",
"flash",
NULL
};
/* Parameters in each bootrom section of database file */
static struct paramdef dbparams[] = {
/* General bootrom parameters */
{ "kernel", par_string, NULL, {&bootd.kernelname}},
{ "bustype", par_enum, btypes, {(char **)&bootd.bus_type}},
{ "pcivendor", par_int, NULL, {(char **)&bootd.pci_vendid}},
{ "pcidevice", par_int, NULL, {(char **)&bootd.pci_devid}},
{ "pnpdevid", par_string, NULL, {&bootd.pnp_devid}},
{ "netdriver", par_string, NULL, {&bootd.netdrv.name}},
{ "netdrvtype", par_enum, dtypes, {(char **)&bootd.netdrv.drivertype}},
#if MAXLOADERS < 3
#error Invalid number of loaders
#endif
/* Parameters for defining loaders */
{ "loader1", par_string, NULL, {&bootd.loaders[0].name}},
{ "loader2", par_string, NULL, {&bootd.loaders[1].name}},
{ "loader3", par_string, NULL, {&bootd.loaders[2].name}},
{ "outname1", par_string, NULL, {&bootd.loaders[0].outname}},
{ "outname2", par_string, NULL, {&bootd.loaders[1].outname}},
{ "outname3", par_string, NULL, {&bootd.loaders[2].outname}},
{ "outsize1", par_int, NULL, {(char **)&bootd.loaders[0].outsize}},
{ "outsize2", par_int, NULL, {(char **)&bootd.loaders[1].outsize}},
{ "outsize3", par_int, NULL, {(char **)&bootd.loaders[2].outsize}},
{ "outtype1", par_enum, ftypes, {(char **)&bootd.loaders[0].outtype}},
{ "outtype2", par_enum, ftypes, {(char **)&bootd.loaders[1].outtype}},
{ "outtype3", par_enum, ftypes, {(char **)&bootd.loaders[2].outtype}},
{ "ldopts1", par_proc, NULL, {(char **)&readopts}},
{ "ldopts2", par_proc, NULL, {(char **)&readopts}},
{ "ldopts3", par_proc, NULL, {(char **)&readopts}},
#if MAXPROGS < 8
#error Invalid number of drivers
#endif
/* Parameters for packet driver interface */
{ "pktdrvidx", par_int, NULL, {(char **)&bootd.netdrv.driverdefs.pd.drvindex}},
{ "pdprog0", par_string, NULL, {&bootd.netdrv.driverdefs.pd.progs.prognames[0]}},
{ "pdprog1", par_string, NULL, {&bootd.netdrv.driverdefs.pd.progs.prognames[1]}},
{ "pdprog2", par_string, NULL, {&bootd.netdrv.driverdefs.pd.progs.prognames[2]}},
{ "pdprog3", par_string, NULL, {&bootd.netdrv.driverdefs.pd.progs.prognames[3]}},
{ "pdprog4", par_string, NULL, {&bootd.netdrv.driverdefs.pd.progs.prognames[4]}},
{ "pdprog5", par_string, NULL, {&bootd.netdrv.driverdefs.pd.progs.prognames[5]}},
{ "pdprog6", par_string, NULL, {&bootd.netdrv.driverdefs.pd.progs.prognames[6]}},
{ "pdprog7", par_string, NULL, {&bootd.netdrv.driverdefs.pd.progs.prognames[7]}},
{ "pdargs0", par_string, NULL, {&bootd.netdrv.driverdefs.pd.progs.progargs[0]}},
{ "pdargs1", par_string, NULL, {&bootd.netdrv.driverdefs.pd.progs.progargs[1]}},
{ "pdargs2", par_string, NULL, {&bootd.netdrv.driverdefs.pd.progs.progargs[2]}},
{ "pdargs3", par_string, NULL, {&bootd.netdrv.driverdefs.pd.progs.progargs[3]}},
{ "pdargs4", par_string, NULL, {&bootd.netdrv.driverdefs.pd.progs.progargs[4]}},
{ "pdargs5", par_string, NULL, {&bootd.netdrv.driverdefs.pd.progs.progargs[5]}},
{ "pdargs6", par_string, NULL, {&bootd.netdrv.driverdefs.pd.progs.progargs[6]}},
{ "pdargs7", par_string, NULL, {&bootd.netdrv.driverdefs.pd.progs.progargs[7]}},
{ "pdminsize0", par_long, NULL, {(char **)&bootd.netdrv.driverdefs.pd.progs.minsizes[0]}},
{ "pdminsize1", par_long, NULL, {(char **)&bootd.netdrv.driverdefs.pd.progs.minsizes[1]}},
{ "pdminsize2", par_long, NULL, {(char **)&bootd.netdrv.driverdefs.pd.progs.minsizes[2]}},
{ "pdminsize3", par_long, NULL, {(char **)&bootd.netdrv.driverdefs.pd.progs.minsizes[3]}},
{ "pdminsize4", par_long, NULL, {(char **)&bootd.netdrv.driverdefs.pd.progs.minsizes[4]}},
{ "pdminsize5", par_long, NULL, {(char **)&bootd.netdrv.driverdefs.pd.progs.minsizes[5]}},
{ "pdminsize6", par_long, NULL, {(char **)&bootd.netdrv.driverdefs.pd.progs.minsizes[6]}},
{ "pdminsize7", par_long, NULL, {(char **)&bootd.netdrv.driverdefs.pd.progs.minsizes[7]}},
{ "pdmaxsize0", par_long, NULL, {(char **)&bootd.netdrv.driverdefs.pd.progs.maxsizes[0]}},
{ "pdmaxsize1", par_long, NULL, {(char **)&bootd.netdrv.driverdefs.pd.progs.maxsizes[1]}},
{ "pdmaxsize2", par_long, NULL, {(char **)&bootd.netdrv.driverdefs.pd.progs.maxsizes[2]}},
{ "pdmaxsize3", par_long, NULL, {(char **)&bootd.netdrv.driverdefs.pd.progs.maxsizes[3]}},
{ "pdmaxsize4", par_long, NULL, {(char **)&bootd.netdrv.driverdefs.pd.progs.maxsizes[4]}},
{ "pdmaxsize5", par_long, NULL, {(char **)&bootd.netdrv.driverdefs.pd.progs.maxsizes[5]}},
{ "pdmaxsize6", par_long, NULL, {(char **)&bootd.netdrv.driverdefs.pd.progs.maxsizes[6]}},
{ "pdmaxsize7", par_long, NULL, {(char **)&bootd.netdrv.driverdefs.pd.progs.maxsizes[7]}},
/* Parameters for NDIS interface */
{ "protini", par_string, NULL, {&protini}},
{ "ndisdrvidx", par_int, NULL, {(char **)&bootd.netdrv.driverdefs.ndis.drvindex}},
{ "ndprog0", par_string, NULL, {&bootd.netdrv.driverdefs.ndis.progs.prognames[0]}},
{ "ndprog1", par_string, NULL, {&bootd.netdrv.driverdefs.ndis.progs.prognames[1]}},
{ "ndprog2", par_string, NULL, {&bootd.netdrv.driverdefs.ndis.progs.prognames[2]}},
{ "ndprog3", par_string, NULL, {&bootd.netdrv.driverdefs.ndis.progs.prognames[3]}},
{ "ndprog4", par_string, NULL, {&bootd.netdrv.driverdefs.ndis.progs.prognames[4]}},
{ "ndprog5", par_string, NULL, {&bootd.netdrv.driverdefs.ndis.progs.prognames[5]}},
{ "ndprog6", par_string, NULL, {&bootd.netdrv.driverdefs.ndis.progs.prognames[6]}},
{ "ndprog7", par_string, NULL, {&bootd.netdrv.driverdefs.ndis.progs.prognames[7]}},
{ "ndargs0", par_string, NULL, {&bootd.netdrv.driverdefs.ndis.progs.progargs[0]}},
{ "ndargs1", par_string, NULL, {&bootd.netdrv.driverdefs.ndis.progs.progargs[1]}},
{ "ndargs2", par_string, NULL, {&bootd.netdrv.driverdefs.ndis.progs.progargs[2]}},
{ "ndargs3", par_string, NULL, {&bootd.netdrv.driverdefs.ndis.progs.progargs[3]}},
{ "ndargs4", par_string, NULL, {&bootd.netdrv.driverdefs.ndis.progs.progargs[4]}},
{ "ndargs5", par_string, NULL, {&bootd.netdrv.driverdefs.ndis.progs.progargs[5]}},
{ "ndargs6", par_string, NULL, {&bootd.netdrv.driverdefs.ndis.progs.progargs[6]}},
{ "ndargs7", par_string, NULL, {&bootd.netdrv.driverdefs.ndis.progs.progargs[7]}},
{ "ndminsize0", par_long, NULL, {(char **)&bootd.netdrv.driverdefs.ndis.progs.minsizes[0]}},
{ "ndminsize1", par_long, NULL, {(char **)&bootd.netdrv.driverdefs.ndis.progs.minsizes[1]}},
{ "ndminsize2", par_long, NULL, {(char **)&bootd.netdrv.driverdefs.ndis.progs.minsizes[2]}},
{ "ndminsize3", par_long, NULL, {(char **)&bootd.netdrv.driverdefs.ndis.progs.minsizes[3]}},
{ "ndminsize4", par_long, NULL, {(char **)&bootd.netdrv.driverdefs.ndis.progs.minsizes[4]}},
{ "ndminsize5", par_long, NULL, {(char **)&bootd.netdrv.driverdefs.ndis.progs.minsizes[5]}},
{ "ndminsize6", par_long, NULL, {(char **)&bootd.netdrv.driverdefs.ndis.progs.minsizes[6]}},
{ "ndminsize7", par_long, NULL, {(char **)&bootd.netdrv.driverdefs.ndis.progs.minsizes[7]}},
{ "ndmaxsize0", par_long, NULL, {(char **)&bootd.netdrv.driverdefs.ndis.progs.maxsizes[0]}},
{ "ndmaxsize1", par_long, NULL, {(char **)&bootd.netdrv.driverdefs.ndis.progs.maxsizes[1]}},
{ "ndmaxsize2", par_long, NULL, {(char **)&bootd.netdrv.driverdefs.ndis.progs.maxsizes[2]}},
{ "ndmaxsize3", par_long, NULL, {(char **)&bootd.netdrv.driverdefs.ndis.progs.maxsizes[3]}},
{ "ndmaxsize4", par_long, NULL, {(char **)&bootd.netdrv.driverdefs.ndis.progs.maxsizes[4]}},
{ "ndmaxsize5", par_long, NULL, {(char **)&bootd.netdrv.driverdefs.ndis.progs.maxsizes[5]}},
{ "ndmaxsize6", par_long, NULL, {(char **)&bootd.netdrv.driverdefs.ndis.progs.maxsizes[6]}},
{ "ndmaxsize7", par_long, NULL, {(char **)&bootd.netdrv.driverdefs.ndis.progs.maxsizes[7]}},
/* Parameters for UNDI interface */
{ "undiprog", par_string, NULL, {&bootd.netdrv.driverdefs.undi.name}},
{ NULL, par_null, NULL, {NULL}}
};
/*
* Check and reorder a list of DOS programs
*/
static void checkprogs(pdp, drvindex, namebuf)
struct progdef *pdp;
int *drvindex;
char *namebuf;
{
int i, j;
char *configdir;
pdp->prognum = 0;
for (i = 0, j = -1; i < MAXPROGS; i++) {
if (pdp->prognames[i] != NULL) {
if (i == *drvindex)
configdir = config.netdrvdir;
else
configdir = config.utilsdir;
checkaccess(&(pdp->prognames[i]), configdir);
if (pdp->prognames[i] == NULL) {
prnerr2("program %d invalid in section <%s>",
i, namebuf);
exit(EXIT_DB);
}
}
if (pdp->prognames[i] == NULL) {
if (pdp->progargs[i] != NULL) {
free(pdp->progargs[i]);
pdp->progargs[i] = NULL;
}
if (j < 0)
j = i;
} else if (j >= 0) {
if (i == *drvindex)
*drvindex = j;
pdp->prognames[j] = pdp->prognames[i];
pdp->progargs[j] = pdp->progargs[i];
pdp->minsizes[j] = pdp->minsizes[i];
pdp->maxsizes[j] = pdp->maxsizes[i];
pdp->prognames[i] = NULL;
pdp->progargs[i] = NULL;
pdp->minsizes[i] = -1L;
pdp->maxsizes[i] = -1L;
pdp->prognum++;
i = j;
j = -1;
} else
pdp->prognum++;
}
if (*drvindex < 0 || *drvindex >= pdp->prognum) {
prnerr2("network driver index %d invalid in section <%s>",
*drvindex, namebuf);
exit(EXIT_DB);
}
for (i = 0; i < pdp->prognum; i++) {
if (pdp->minsizes[i] < 0L)
pdp->minsizes[i] = -1L;
if (pdp->maxsizes[i] < 0L)
pdp->maxsizes[i] = -1L;
if (pdp->maxsizes[i] == 0L ||
(i == 0 && pdp->minsizes[i] == 0L) ||
(pdp->minsizes[i] > 0L && pdp->maxsizes[i] > 0L &&
pdp->minsizes[i] > pdp->maxsizes[i])) {
prnerr2("invalid execution size for program %d in section <%s>",
i, namebuf);
exit(EXIT_DB);
}
}
}
/*
* Read one entry from the database file
*/
struct bootdef *getdb(name)
char *name;
{
struct sectdef sect;
char *namebuf, *cp;
int i, j;
/* Generate section record */
namebuf = (char *)nbmalloc(strlen(name) + 9);
sprintf(namebuf, "%s:makerom", name);
sect.name = namebuf;
sect.params = dbparams;
sect.startsect = NULL;
sect.endsect = NULL;
/* Get entry from database */
memset(&bootd, 0, sizeof(bootd));
for (i = 0; i < MAXPROGS; i++) {
bootd.netdrv.driverdefs.pd.progs.minsizes[i] = -1L;
bootd.netdrv.driverdefs.pd.progs.maxsizes[i] = -1L;
bootd.netdrv.driverdefs.ndis.progs.minsizes[i] = -1L;
bootd.netdrv.driverdefs.ndis.progs.maxsizes[i] = -1L;
}
readdb(§, dbname);
/* Check for correct and missing values */
copystr(&bootd.name, name);
checkaccess(&bootd.kernelname, config.bindir);
if (!bootd.kernelname) {
prnerr1("no or invalid kernel file name given in section <%s>",
namebuf);
exit(EXIT_DB);
}
if (bootd.pnp_devid != NULL && strlen(bootd.pnp_devid) == 0) {
free(bootd.pnp_devid);
bootd.pnp_devid = NULL;
}
if (bootd.bus_type == BUSTYPE_NONE)
bootd.bus_type = BUSTYPE_ISA;
if (bootd.bus_type == BUSTYPE_PCI) {
if (bootd.pci_vendid == 0 || bootd.pci_devid == 0) {
prnerr1("missing PCI vendor/device ID in section <%s>", namebuf);
exit(EXIT_DB);
}
if (bootd.pnp_devid != NULL) {
prnerr1("PnP device ID for PCI network card in section <%s>",
namebuf);
exit(EXIT_DB);
}
} else if (bootd.pci_vendid != 0 || bootd.pci_devid != 0) {
prnerr1("PCI vendor/device ID specified for non-PCI device in section <%s>",
namebuf);
exit(EXIT_DB);
}
if (bootd.pnp_devid != NULL) {
if (strlen(bootd.pnp_devid) != PNPIDLEN ||
!isalpha(bootd.pnp_devid[0]) ||
!isalpha(bootd.pnp_devid[1]) ||
!isalpha(bootd.pnp_devid[2]) ||
!isxdigit(bootd.pnp_devid[3]) ||
!isxdigit(bootd.pnp_devid[4]) ||
!isxdigit(bootd.pnp_devid[5]) ||
!isxdigit(bootd.pnp_devid[6])) {
prnerr1("invalid PnP device ID in section <%s>", namebuf);
exit(EXIT_DB);
}
}
bootd.canflash = checkflash(&bootd);
checkaccess(&bootd.netdrv.name, config.bindir);
if (!bootd.netdrv.name) {
prnerr1("no or invalid network driver name given in section <%s>",
namebuf);
exit(EXIT_DB);
}
if (bootd.netdrv.drivertype == DRVTYPE_NONE) {
prnerr1("missing driver type in section <%s>", namebuf);
exit(EXIT_DB);
}
/* Reorder the loader list and check for correct values */
bootd.loadernum = 0;
for (i = 0, j = -1; i < MAXLOADERS; i++) {
if (bootd.loaders[i].name != NULL) {
checkaccess(&bootd.loaders[i].name, config.bindir);
if (bootd.loaders[i].name == NULL) {
prnerr2("loader %d invalid in section <%s>",
i, namebuf);
exit(EXIT_DB);
}
}
if (bootd.loaders[i].name == NULL) {
if (bootd.loaders[i].outname != NULL) {
free(bootd.loaders[i].outname);
bootd.loaders[i].outname = NULL;
}
if (j < 0)
j = i;
} else {
if (bootd.loaders[i].outname == NULL) {
prnerr2("no output file given for loader %d in section <%s>",
i, namebuf);
exit(EXIT_DB);
}
if (bootd.loaders[i].outtype == OUT_NONE)
bootd.loaders[i].outtype = OUT_BINARY;
if (bootd.loaders[i].outtype == OUT_FLASH && !bootd.canflash) {
prnerr2("flash output type unsupported for loader %d in section <%s>",
i, namebuf);
exit(EXIT_DB);
}
bootd.loadernum++;
if (j >= 0) {
bootd.loaders[j] = bootd.loaders[i];
bootd.loaders[i].name = NULL;
i = j;
j = -1;
}
}
}
if (bootd.loadernum == 0) {
prnerr1("no bootrom loader specified in section <%s>", namebuf);
exit(EXIT_DB);
}
/* Check for correct values for the different network driver types */
if (bootd.netdrv.drivertype == DRVTYPE_PD) {
struct pktdrvdef *pdp = &(bootd.netdrv.driverdefs.pd);
checkprogs(&(pdp->progs), &(pdp->drvindex), namebuf);
if (pdp->progs.prognum == 0) {
prnerr1("no or invalid packet driver specified in section <%s>",
namebuf);
exit(EXIT_DB);
}
} else if (bootd.netdrv.drivertype == DRVTYPE_NDIS) {
struct ndisdef *np = &(bootd.netdrv.driverdefs.ndis);
checkprogs(&(np->progs), &(np->drvindex), namebuf);
if (np->progs.prognum == 0) {
prnerr1("no or invalid NDIS driver specified in section <%s>",
namebuf);
exit(EXIT_DB);
}
if (np->progs.progargs[np->drvindex] != NULL) {
free(np->progs.progargs[np->drvindex]);
np->progs.progargs[np->drvindex] = NULL;
}
if (protini == NULL) {
prnerr1("missing \'protini\' entry in section <%s>\n",
namebuf);
exit(EXIT_DB);
}
if (!strncmp(protini, "file:", 5)) {
cp = readprotini(&protini[5]);
parseprotini(cp, &(np->protocolini), &(np->protinisize));
free(cp);
} else
parseprotini(protini, &(np->protocolini), &(np->protinisize));
} else if (bootd.netdrv.drivertype == DRVTYPE_UNDI) {
checkaccess(&bootd.netdrv.driverdefs.undi.name, config.netdrvdir);
if (bootd.netdrv.driverdefs.undi.name == NULL) {
prnerr1("missing or invalid UNDI driver name in section <%s>",
namebuf);
exit(EXIT_DB);
}
}
free(namebuf);
return(&bootd);
}
syntax highlighted by Code2HTML, v. 0.9.1