/*
* Copyright (c) 2000-2014 University of Utah and the Flux Group.
*
* {{{EMULAB-LICENSE
*
* This file is part of the Emulab network testbed software.
*
* This file is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* This file 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 Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this file. If not, see .
*
* }}}
*/
#include
#include
#include
#include
#include
#include
#include
#include "log.h"
#include "bootwhat.h"
#include "bootinfo.h"
/*
* Trivial config file format.
* Swiped from proxydhcp.c.
*/
#ifdef USE_CFILE_DB
#define CFILE "bootinfo.conf"
struct config {
struct in_addr client;
int bootinfolen;
boot_what_t bootinfo;
/* bootinfo is variable length */
};
#define MAX_CONFIGS 256
static int numconfigs;
static struct config *configurations[MAX_CONFIGS];
static struct config *find_config(struct in_addr addr);
static int parse_configs(char *filename);
#ifdef TEST
static void print_bootwhat(boot_what_t *bootinfo);
#endif
int
open_bootinfo_db(void)
{
char cfile[BUFSIZ];
#ifdef TEST
strcpy(cfile, CFILE);
#else
strcpy(cfile, CONFPATH);
strcat(cfile, CFILE);
#endif
return parse_configs(cfile);
}
int
query_bootinfo_db(struct in_addr ipaddr, int version, boot_what_t *info, char *key)
{
struct config *configp;
if ((configp = find_config(ipaddr)) == 0)
return 1;
memcpy(info, &configp->bootinfo, configp->bootinfolen);
return 0;
}
int
close_bootinfo_db(void)
{
int i;
for (i = 0; i < numconfigs; i++)
if (configurations[i])
free(configurations[i]);
numconfigs = 0;
return 0;
}
static int
parse_host(char *name)
{
struct hostent *he;
if (!isdigit(name[0])) {
he = gethostbyname(name);
if (he == 0) {
error("%s: unknown host\n", name);
return 0;
}
return *(int *)he->h_addr;
}
return inet_addr(name);
}
static int
parse_configs(char *filename)
{
FILE *fp;
int i;
char buf[BUFSIZ], *bp, *cix, client[256], action[256];
struct config *configp;
int ipaddr;
if ((fp = fopen(filename, "r")) == NULL) {
error("%s: cannot open\n", filename);
return 1;
}
while (1) {
if ((bp = fgets(buf, BUFSIZ, fp)) == NULL)
break;
if (*bp == '\n' || *bp == '#')
continue;
if (numconfigs >= MAX_CONFIGS) {
error("%s: too many lines\n", filename);
fclose(fp);
return 1;
}
sscanf(bp, "%s %s\n", client, action);
configp = (struct config *) calloc(sizeof *configp, 1);
if (!configp) {
bad:
error("%s: parse error\n", filename);
fclose(fp);
close_bootinfo_db();
return 1;
}
configurations[numconfigs++] = configp;
if ((ipaddr = parse_host(client)) == 0)
goto bad;
configp->client.s_addr = ipaddr;
configp->bootinfolen = sizeof *configp;
configp->bootinfo.flags = 0;
if (strncmp(action, "sysid=", 6) == 0) {
configp->bootinfo.type = BIBOOTWHAT_TYPE_SYSID;
configp->bootinfo.what.sysid = atoi(&action[6]);
} else if (strncmp(action, "part=", 5) == 0) {
configp->bootinfo.type = BIBOOTWHAT_TYPE_PART;
configp->bootinfo.what.partition = atoi(&action[5]);
} else if (strncmp(action, "file=", 5) == 0) {
if ((cix = index(action, ':')) == 0)
goto bad;
configp->bootinfo.type = BIBOOTWHAT_TYPE_MB;
*cix++ = 0;
if ((ipaddr = parse_host(&action[5])) == 0)
goto bad;
configp->bootinfo.what.mb.tftp_ip.s_addr = ipaddr;
configp = realloc(configp,
sizeof *configp + strlen(cix) + 1);
if (configp == 0)
goto bad;
configurations[numconfigs-1] = configp;
configp->bootinfolen += strlen(cix) + 1;
strcpy(configp->bootinfo.what.mb.filename, cix);
} else
goto bad;
}
fclose(fp);
#ifdef TEST
printf("==== %s ====\n", filename);
for (i = 0; i < numconfigs; i++) {
configp = configurations[i];
printf("%s: ", inet_ntoa(configp->client));
print_bootwhat(&configp->bootinfo);
}
printf("====\n\n");
#endif
return 0;
}
static struct config *
find_config(struct in_addr addr)
{
int i;
struct config *configp;
for (i = 0; i < numconfigs; i++)
if ((configp = configurations[i]) != NULL &&
addr.s_addr == configp->client.s_addr)
return configp;
return 0;
}
#ifdef TEST
#include
static void
print_bootwhat(boot_what_t *bootinfo)
{
switch (bootinfo->type) {
case BIBOOTWHAT_TYPE_PART:
printf("boot from partition %d\n",
bootinfo->what.partition);
break;
case BIBOOTWHAT_TYPE_SYSID:
printf("boot from partition with sysid %d\n",
bootinfo->what.sysid);
break;
case BIBOOTWHAT_TYPE_MB:
printf("boot multiboot image %s:%s\n",
inet_ntoa(bootinfo->what.mb.tftp_ip),
bootinfo->what.mb.filename);
break;
}
}
main(int argc, char **argv)
{
struct in_addr ipaddr;
boot_info_t boot_info;
boot_what_t *boot_whatp = (boot_what_t *)&boot_info.data;
if (open_bootinfo_db() != 0) {
printf("bad config file\n");
exit(1);
}
while (--argc > 0) {
if (inet_aton(*++argv, &ipaddr)) {
if (query_bootinfo_db(ipaddr, boot_whatp) == 0) {
printf("%s: ", *argv);
print_bootwhat(boot_whatp);
} else
printf("failed\n");
} else
printf("bogus IP address `%s'\n", *argv);
}
close_bootinfo_db();
exit(0);
}
#endif
#endif