#include <stdarg.h>
#include <sys/types.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#ifndef NO_UNISTD
#include <unistd.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>
#include <syslog.h>
#include "bootp.h"
#include "hash.h"
#include "hwaddr.h"
#include "bootpd.h"
#include "dovend.h"
#include "readfile.h"
#include "report.h"
#include "tzone.h"
#include "patchlevel.h"
#define BUFFERSIZE 0x4000
#ifndef CONFIG_FILE
#define CONFIG_FILE "/etc/bootptab"
#endif
static void mktagfile(struct host *);
static void usage(void) __dead2;
char *progname;
char *chdir_path;
int debug = 0;
byte *buffer;
char *bootptab = CONFIG_FILE;
static void
usage(void)
{
fprintf(stderr,
"usage: $s [ -c chdir ] [-d level] [-f configfile] [host...]\n");
fprintf(stderr, "\t -c n\tset current directory\n");
fprintf(stderr, "\t -d n\tset debug level\n");
fprintf(stderr, "\t -f n\tconfig file name\n");
exit(1);
}
int
main(int argc, char **argv)
{
struct host *hp;
char *stmp;
int n;
progname = strrchr(argv[0], '/');
if (progname) progname++;
else progname = argv[0];
buffer = (byte *) malloc(BUFFERSIZE);
if (!buffer) {
report(LOG_ERR, "malloc failed");
exit(1);
}
stmp = NULL;
for (argc--, argv++; argc > 0; argc--, argv++) {
if (argv[0][0] != '-')
break;
switch (argv[0][1]) {
case 'c':
if (argv[0][2]) {
stmp = &(argv[0][2]);
} else {
argc--;
argv++;
stmp = argv[0];
}
if (!stmp || (stmp[0] != '/')) {
fprintf(stderr,
"bootpd: invalid chdir specification\n");
break;
}
chdir_path = stmp;
break;
case 'd':
if (argv[0][2]) {
stmp = &(argv[0][2]);
} else if (argv[1] && argv[1][0] == '-') {
debug++;
break;
} else {
argc--;
argv++;
stmp = argv[0];
}
if (!stmp || (sscanf(stmp, "%d", &n) != 1) || (n < 0)) {
fprintf(stderr,
"bootpd: invalid debug level\n");
break;
}
debug = n;
break;
case 'f':
if (argv[0][2]) {
stmp = &(argv[0][2]);
} else {
argc--;
argv++;
stmp = argv[0];
}
bootptab = stmp;
break;
default:
fprintf(stderr, "bootpd: unknown switch: -%c\n",
argv[0][1]);
usage();
break;
}
}
tzone_init();
rdtab_init();
readtab(1);
if (chdir_path) {
if (chdir(chdir_path) < 0)
report(LOG_ERR, "%s: chdir failed", chdir_path);
}
if (argc > 0) {
unsigned int tlen, hashcode;
while (argc) {
tlen = strlen(argv[0]);
hashcode = hash_HashFunction((u_char *)argv[0], tlen);
hp = (struct host *) hash_Lookup(nmhashtable,
hashcode,
nmcmp, argv[0]);
if (!hp) {
printf("%s: no matching entry\n", argv[0]);
exit(1);
}
if (!hp->flags.exten_file) {
printf("%s: no extension file\n", argv[0]);
exit(1);
}
mktagfile(hp);
argv++;
argc--;
}
exit(0);
}
hp = (struct host *) hash_FirstEntry(nmhashtable);
while (hp != NULL) {
mktagfile(hp);
hp = (struct host *) hash_NextEntry(nmhashtable);
}
return (0);
}
static void
mktagfile(struct host *hp)
{
FILE *fp;
int bytesleft, len;
byte *vp;
if (!hp->flags.exten_file)
return;
vp = buffer;
bytesleft = BUFFERSIZE;
bcopy(vm_rfc1048, vp, 4);
vp += 4;
bytesleft -= 4;
len = dovend_rfc1497(hp, vp, bytesleft);
vp += len;
bytesleft -= len;
if (bytesleft < 1) {
report(LOG_ERR, "%s: too much option data",
hp->exten_file->string);
return;
}
*vp++ = TAG_END;
bytesleft--;
printf("Updating \"%s\"\n", hp->exten_file->string);
if ((fp = fopen(hp->exten_file->string, "w")) == NULL) {
report(LOG_ERR, "error opening \"%s\": %s",
hp->exten_file->string, get_errmsg());
return;
}
len = vp - buffer;
if (len != fwrite(buffer, 1, len, fp)) {
report(LOG_ERR, "write failed on \"%s\" : %s",
hp->exten_file->string, get_errmsg());
}
fclose(fp);
}