Commit e67bd2b2 authored by Mike Hibler's avatar Mike Hibler

use syslog instead of printf/fprintf

add HUPing of daemon to reread any config info
parent c8001159
INSTALL_BINDIR = /usr/testbed/bin
INSTALL_DIR = /usr/testbed
INSTALL_BINDIR = $(INSTALL_DIR)/bin
INSTALL = /usr/bin/install -c
DBFLAG = -DUSE_CFILE_DB #-DUSE_MYSQL_DB #-DUSE_NULL_DB
DBSRC = bootinfo_null.c bootinfo_cfile.c bootinfo_mysql.c
CFLAGS = -g -DSOLARIS -DHAVE_SOCKADDR_SA_LEN -DUSE_RECVMSG
CFLAGS += -DUSE_NULL_DB
INCS = -I/n/moab/z/mike/flux/install.debug/include
all: proxydhcp bootinfo
......@@ -11,12 +13,19 @@ all: proxydhcp bootinfo
proxydhcp: proxydhcp.c
cc $(CFLAGS) -o proxydhcp proxydhcp.c $(LFLAGS)
bootinfo: bootinfo.c bootinfo_null.c bootinfo_mysql.c
cc $(CFLAGS) $(INCS) -I/usr/local/include -o bootinfo $? \
bootinfo: bootinfo.c $(DBSRC) bootinfo_mysql.c
cc $(CFLAGS) $(DBFLAG) $(INCS) -I/usr/local/include \
-o bootinfo bootinfo.c $(DBSRC) \
$(LFLAGS) -L/usr/local/lib/mysql -lmysqlclient
testmysql: bootinfo_mysql.c
cc $(CFLAGS) -DTEST $(INCS) -o testmysql bootinfo_mysql.c $(LFLAGS)
cc $(CFLAGS) -DUSE_MYSQL_DB -DTEST $(INCS) -I/usr/local/include \
-o testmysql bootinfo_mysql.c \
$(LFLAGS) -L/usr/local/lib/mysql -lmysqlclient
testcfile: bootinfo_cfile.c
cc $(CFLAGS) -DUSE_CFILE_DB -DTEST $(INCS) -o testcfile bootinfo_cfile.c \
$(LFLAGS)
install: all
-mkdir $(INSTALL_BINDIR)
......@@ -26,6 +35,7 @@ install: all
$(INSTALL) -m 755 proxydhcp.restart $(INSTALL_BINDIR)/pxe
$(INSTALL) bootinfo $(INSTALL_BINDIR)/pxe
$(INSTALL) -m 755 bootinfo.restart $(INSTALL_BINDIR)/pxe
$(INSTALL) -m 444 bootinfo.conf $(INSTALL_DIR)/etc/bootinfo.conf
clean:
rm -f proxydhcp bootinfo testmysql
......
This directory contains support for remote booting of PCs via Intel's PXE
(Preboot eXecution Environment) which is supported on ethernet cards like
the eepro100.
A client PC equipped with such a card and configured to boot from the network
first does the following:
1. the LAN card uses DHCP to get its IP info from a standard DHCP server
2. as PXE requires DHCP extensions, and thus cannot use may standard DHCP
servers, so it gets redirected to a Proxy DHCP server (proxydhcp* in
this directory)
3. This server tells the client which boot program to download via TFTP
and the client does so.
The above steps are not specific to the testbed. Starting with the execution
of the downloaded boot program, a testbed specific protocol takes over:
4. The PXE-loaded boot program (pxeboot from the OSKit) speaks a custom hack
UDP protocol ("defined" in oskit/boot/bootwhat.h) with yet another server.
5. This server (bootinfo* in this directory) is responsible for determining,
in a testbed-specific way, what action should be performed by the client.
This action is either boot from a specific partition on the hard disk
or download (via TFTP) a particular multiboot OSKit kernel (e.g., netboot)
6. Finally, pxeboot transfers control either to the first-level boot code
in the indicated hard disk partition or to the OSKit kernel it has just
downloaded.
If you are interested in more general remote booting mechanisms see:
www.bpbatch.org.
\ No newline at end of file
......@@ -2,13 +2,14 @@
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <syslog.h>
#include <signal.h>
#include <oskit/boot/bootwhat.h>
/*
* For now, hardwired.
*/
#define NETBOOT "/tftpboot/netboot"
static void log_bootwhat(struct in_addr ipaddr, boot_what_t *bootinfo);
static void onhup(int sig);
static int version = 1;
main()
{
......@@ -17,17 +18,22 @@ main()
boot_info_t boot_info;
boot_what_t *boot_whatp = (boot_what_t *) &boot_info.data;
openlog("bootinfo", LOG_PID, LOG_USER);
syslog(LOG_NOTICE, "daemon starting (version %d)", version);
(void)daemon(0, 0);
/* Initialize data base */
err = open_bootinfo_db();
if (err) {
fprintf(stderr, "Could not open database\n");
syslog(LOG_ERR, "could not open database");
exit(1);
}
/* Create socket from which to read. */
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
perror("opening datagram socket");
syslog(LOG_ERR, "opening datagram socket: %m");
exit(1);
}
......@@ -36,46 +42,89 @@ main()
name.sin_addr.s_addr = INADDR_ANY;
name.sin_port = htons(BOOTWHAT_DSTPORT);
if (bind(sock, (struct sockaddr *) &name, sizeof(name))) {
perror("binding datagram socket");
syslog(LOG_ERR, "binding datagram socket: %m");
exit(1);
}
/* Find assigned port value and print it out. */
length = sizeof(name);
if (getsockname(sock, (struct sockaddr *) &name, &length)) {
perror("getting socket name");
syslog(LOG_ERR, "getting socket name: %m");
exit(1);
}
printf("Socket has port #%d\n", ntohs(name.sin_port));
syslog(LOG_NOTICE, "listening on port %d", ntohs(name.sin_port));
signal(SIGHUP, onhup);
while (1) {
if ((mlen = recvfrom(sock, &boot_info, sizeof(boot_info),
0, (struct sockaddr *)&client, &length))
< 0) {
perror("receiving datagram packet");
syslog(LOG_ERR, "receiving datagram packet: %m");
exit(1);
}
printf("Datagram of %d bytes received from %s\n",
mlen, inet_ntoa(client.sin_addr));
if (boot_info.opcode != BIOPCODE_BOOTWHAT_REQUEST) {
printf("Throwing away invalid packet\n");
syslog(LOG_INFO, "%s: invalid packet",
inet_ntoa(client.sin_addr));
continue;
}
syslog(LOG_INFO, "%s: REQUEST", inet_ntoa(client.sin_addr));
boot_info.opcode = BIOPCODE_BOOTWHAT_REPLY;
err = query_bootinfo_db(client.sin_addr, boot_whatp);
if (err)
if (err) {
syslog(LOG_INFO, "%s: FAIL: no valid entry",
inet_ntoa(client.sin_addr));
boot_info.status = BISTAT_FAIL;
else
} else {
log_bootwhat(client.sin_addr, boot_whatp);
boot_info.status = BISTAT_SUCCESS;
}
client.sin_family = AF_INET;
client.sin_port = htons(BOOTWHAT_SRCPORT);
if (sendto(sock, (char *)&boot_info, sizeof(boot_info), 0,
(struct sockaddr *)&client, sizeof(client)) < 0)
perror("sendto");
syslog(LOG_ERR, "sendto: %m");
}
close(sock);
close_bootinfo_db();
syslog(LOG_NOTICE, "daemon terminating");
exit(0);
}
static void
onhup(int sig)
{
int err;
syslog(LOG_NOTICE, "re-initializing configuration database");
close_bootinfo_db();
err = open_bootinfo_db();
if (err) {
syslog(LOG_ERR, "Could not open database");
exit(1);
}
}
static void
log_bootwhat(struct in_addr ipaddr, boot_what_t *bootinfo)
{
char ipstr[32];
strncpy(ipstr, inet_ntoa(ipaddr), sizeof ipstr);
switch (bootinfo->type) {
case BIBOOTWHAT_TYPE_PART:
syslog(LOG_INFO, "%s: REPLY: boot from partition %d",
ipstr, bootinfo->what.partition);
break;
case BIBOOTWHAT_TYPE_SYSID:
syslog(LOG_INFO, "%s: REPLY: boot from partition with sysid %d",
ipstr, bootinfo->what.sysid);
break;
case BIBOOTWHAT_TYPE_MB:
syslog(LOG_INFO, "%s: REPLY: boot multiboot image %s:%s\n",
ipstr,
inet_ntoa(bootinfo->what.mb.tftp_ip),
bootinfo->what.mb.filename);
break;
}
}
#
# For the testbed machines:
#
# part 1: FreeBSD (sysid 165)
# part 2: Linux (sysid 131)
# part 3,4: not bootable
#
# plastic.cs.utah.edu (155.99.212.74, also 155.99.214.74) is the server
# and /tftpboot is the TFTP directory.
#
# Format of this file is:
#
# IP address Action
#
155.99.214.101 part=2
155.99.214.102 part=2
155.99.214.103 file=155.99.214.74:/tftpboot/netboot
155.99.214.104 part=2
155.99.214.105 part=2
155.99.214.106 part=2
155.99.214.107 part=2
155.99.214.108 part=2
155.99.214.109 part=1
155.99.214.110 part=2
155.99.214.111 part=2
155.99.214.112 part=2
155.99.214.113 part=2
155.99.214.114 part=2
155.99.214.115 part=2
155.99.214.116 part=2
155.99.214.117 part=2
155.99.214.118 part=2
155.99.214.119 part=2
155.99.214.120 part=2
155.99.214.121 part=2
155.99.214.122 part=2
155.99.214.123 part=2
155.99.214.124 part=2
155.99.214.125 part=2
155.99.214.126 part=2
155.99.214.127 part=2
155.99.214.128 part=2
155.99.214.129 part=2
155.99.214.130 part=2
155.99.214.131 part=2
155.99.214.132 part=2
155.99.214.133 part=2
155.99.214.134 part=2
155.99.214.135 part=2
155.99.214.136 part=2
155.99.214.137 part=2
155.99.214.138 part=2
155.99.214.139 part=2
155.99.214.140 part=2
#include <sys/types.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <syslog.h>
#include <oskit/boot/bootwhat.h>
/*
* Trivial config file format.
* Swiped from proxydhcp.c.
*/
#ifdef USE_CFILE_DB
#ifdef TEST
#define CFILE "bootinfo.conf"
#else
#define CFILE "/usr/testbed/etc/bootinfo.conf"
#endif
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)
{
return parse_configs(CFILE);
}
int
query_bootinfo_db(struct in_addr ipaddr, boot_what_t *info)
{
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) {
syslog(LOG_ERR, "%s: unknown host", 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) {
syslog(LOG_ERR, "%s: cannot open", filename);
return 1;
}
while (1) {
if ((bp = fgets(buf, BUFSIZ, fp)) == NULL)
break;
if (*bp == '\n' || *bp == '#')
continue;
if (numconfigs >= MAX_CONFIGS) {
syslog(LOG_ERR, "%s: too many lines", filename);
fclose(fp);
return 1;
}
sscanf(bp, "%s %s\n", client, action);
configp = (struct config *) calloc(sizeof *configp, 1);
if (!configp) {
bad:
syslog(LOG_ERR, "%s: parse error", 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;
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 <stdarg.h>
void
syslog(int prio, const char *msg, ...)
{
va_list ap;
va_start(ap, msg);
vfprintf(stderr, msg, ap);
va_end(ap);
fprintf(stderr, "\n");
}
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
#include <sys/types.h>
#include <netinet/in.h>
#include <stdio.h>
#include <syslog.h>
#include <oskit/boot/bootwhat.h>
#include <mysql/mysql.h>
......@@ -31,19 +32,19 @@ query_bootinfo_db(struct in_addr ipaddr, boot_what_t *info)
n = snprintf(querybuf, sizeof querybuf, dbquery, inet_ntoa(ipaddr));
if (n > sizeof querybuf) {
fprintf(stderr, "query too long for buffer\n");
syslog(LOG_ERR, "query too long for buffer");
return 1;
}
mysql_init(&db);
if (mysql_real_connect(&db, 0, 0, 0, dbname, 0, 0, 0) == 0) {
fprintf(stderr, "%s: connect failed: %s\n",
syslog(LOG_ERR, "%s: connect failed: %s",
dbname, mysql_error(&db));
return 1;
}
if (mysql_real_query(&db, querybuf, n) != 0) {
fprintf(stderr, "%s: query failed: %s\n",
syslog(LOG_ERR, "%s: query failed: %s",
dbname, mysql_error(&db));
mysql_close(&db);
return 1;
......@@ -51,7 +52,7 @@ query_bootinfo_db(struct in_addr ipaddr, boot_what_t *info)
res = mysql_store_result(&db);
if (res == 0) {
fprintf(stderr, "%s: store_result failed: %s\n",
syslog(LOG_ERR, "%s: store_result failed: %s",
dbname, mysql_error(&db));
mysql_close(&db);
return 1;
......@@ -62,14 +63,14 @@ query_bootinfo_db(struct in_addr ipaddr, boot_what_t *info)
nrows = (int)mysql_num_rows(res);
switch (nrows) {
case 0:
fprintf(stderr, "%s: no entry for host %s\n",
syslog(LOG_ERR, "%s: no entry for host %s",
dbname, inet_ntoa(ipaddr));
mysql_free_result(res);
return 1;
case 1:
break;
default:
fprintf(stderr, "%s: %d entries for IP %s, using first\n",
syslog(LOG_ERR, "%s: %d entries for IP %s, using first",
dbname, nrows, inet_ntoa(ipaddr));
break;
}
......@@ -79,7 +80,7 @@ query_bootinfo_db(struct in_addr ipaddr, boot_what_t *info)
case 1:
break;
default:
fprintf(stderr, "%s: %d fields in query for IP %s!\n",
syslog(LOG_ERR, "%s: %d fields in query for IP %s!",
dbname, ncols, inet_ntoa(ipaddr));
mysql_free_result(res);
return 1;
......@@ -87,7 +88,7 @@ query_bootinfo_db(struct in_addr ipaddr, boot_what_t *info)
row = mysql_fetch_row(res);
if (row[0] == 0 || row[0] == '\0') {
fprintf(stderr, "%s: null query result for IP %s!\n",
syslog(LOG_ERR, "%s: null query result for IP %s!",
dbname, inet_ntoa(ipaddr));
mysql_free_result(res);
return 1;
......@@ -112,22 +113,37 @@ close_bootinfo_db(void)
}
#ifdef TEST
#include <stdarg.h>
void
syslog(int prio, const char *msg, ...)
{
va_list ap;
va_start(ap, msg);
vfprintf(stderr, msg, ap);
va_end(ap);
fprintf(stderr, "\n");
}
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;
open_bootinfo_db();
while (--argc > 0) {
if (inet_aton(*++argv, &ipaddr))
if (query_bootinfo_db(ipaddr, boot_whatp) == 0)
printf("returned partition %d\n",
boot_whatp->what.partition);
printf("%s: returned partition %d\n",
*argv, boot_whatp->what.partition);
else
printf("failed\n");
printf("%s: failed\n", *argv);
else
printf("bogus IP address `%s'\n", *argv);
}
close_bootinfo_db();
exit(0);
}
#endif
......
......@@ -5,6 +5,12 @@
#include <oskit/boot/bootwhat.h>
#ifdef USE_NULL_DB
/*
* For now, hardwired.
*/
#define NETBOOT "/tftpboot/netboot"
int
open_bootinfo_db(void)
{
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment