1030 lines
26 KiB
C
1030 lines
26 KiB
C
/*
|
|
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
|
*
|
|
* SPDX-License-Identifier: MPL-2.0
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
|
*
|
|
* See the COPYRIGHT file distributed with this work for additional
|
|
* information regarding copyright ownership.
|
|
*/
|
|
|
|
/*! \file */
|
|
|
|
#include <ctype.h>
|
|
#include <dirent.h>
|
|
#include <errno.h>
|
|
#include <limits.h>
|
|
#include <stdbool.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/types.h>
|
|
#include <time.h>
|
|
#include <unistd.h>
|
|
|
|
#ifndef PATH_MAX
|
|
#define PATH_MAX 1024
|
|
#endif /* ifndef PATH_MAX */
|
|
|
|
#ifndef ULLONG_MAX
|
|
#define ULLONG_MAX (~0ULL)
|
|
#endif /* ifndef ULLONG_MAX */
|
|
|
|
#define INSIST(cond) \
|
|
if (!(cond)) { \
|
|
fprintf(stderr, "%s:%d: INSIST(%s)\n", __FILE__, __LINE__, \
|
|
#cond); \
|
|
abort(); \
|
|
}
|
|
|
|
#define FROMTEXTARGS "rdclass, type, lexer, origin, options, target, callbacks"
|
|
#define FROMTEXTCLASS "rdclass"
|
|
#define FROMTEXTTYPE "type"
|
|
#define FROMTEXTDEF "result = DNS_R_UNKNOWN"
|
|
|
|
#define TOTEXTARGS "rdata, tctx, target"
|
|
#define TOTEXTCLASS "rdata->rdclass"
|
|
#define TOTEXTTYPE "rdata->type"
|
|
#define TOTEXTDEF "use_default = true"
|
|
|
|
#define FROMWIREARGS "rdclass, type, source, dctx, target"
|
|
#define FROMWIRECLASS "rdclass"
|
|
#define FROMWIRETYPE "type"
|
|
#define FROMWIREDEF "use_default = true"
|
|
|
|
#define TOWIREARGS "rdata, cctx, target"
|
|
#define TOWIRECLASS "rdata->rdclass"
|
|
#define TOWIRETYPE "rdata->type"
|
|
#define TOWIREDEF "use_default = true"
|
|
|
|
#define FROMSTRUCTARGS "rdclass, type, source, target"
|
|
#define FROMSTRUCTCLASS "rdclass"
|
|
#define FROMSTRUCTTYPE "type"
|
|
#define FROMSTRUCTDEF "use_default = true"
|
|
|
|
#define TOSTRUCTARGS "rdata, target, mctx"
|
|
#define TOSTRUCTCLASS "rdata->rdclass"
|
|
#define TOSTRUCTTYPE "rdata->type"
|
|
#define TOSTRUCTDEF "use_default = true"
|
|
|
|
#define FREESTRUCTARGS "source"
|
|
#define FREESTRUCTCLASS "common->rdclass"
|
|
#define FREESTRUCTTYPE "common->rdtype"
|
|
#define FREESTRUCTDEF NULL
|
|
|
|
#define COMPAREARGS "rdata1, rdata2"
|
|
#define COMPARECLASS "rdata1->rdclass"
|
|
#define COMPARETYPE "rdata1->type"
|
|
#define COMPAREDEF "use_default = true"
|
|
|
|
#define ADDITIONALDATAARGS "rdata, owner, add, arg"
|
|
#define ADDITIONALDATACLASS "rdata->rdclass"
|
|
#define ADDITIONALDATATYPE "rdata->type"
|
|
#define ADDITIONALDATADEF "use_default = true"
|
|
|
|
#define DIGESTARGS "rdata, digest, arg"
|
|
#define DIGESTCLASS "rdata->rdclass"
|
|
#define DIGESTTYPE "rdata->type"
|
|
#define DIGESTDEF "use_default = true"
|
|
|
|
#define CHECKOWNERARGS "name, rdclass, type, wildcard"
|
|
#define CHECKOWNERCLASS "rdclass"
|
|
#define CHECKOWNERTYPE "type"
|
|
#define CHECKOWNERDEF "result = true"
|
|
|
|
#define CHECKNAMESARGS "rdata, owner, bad"
|
|
#define CHECKNAMESCLASS "rdata->rdclass"
|
|
#define CHECKNAMESTYPE "rdata->type"
|
|
#define CHECKNAMESDEF "result = true"
|
|
|
|
static const char copyright[] = "/*\n"
|
|
" * Copyright (C) 1998%s Internet Systems "
|
|
"Consortium, Inc. (\"ISC\")\n"
|
|
" *\n"
|
|
" * This Source Code Form is subject to the "
|
|
"terms of the Mozilla Public\n"
|
|
" * License, v. 2.0. If a copy of the MPL was "
|
|
"not distributed with this\n"
|
|
" * file, you can obtain one at "
|
|
"https://mozilla.org/MPL/2.0/.\n"
|
|
" */\n"
|
|
"\n"
|
|
"/***************\n"
|
|
" ***************\n"
|
|
" *************** THIS FILE IS AUTOMATICALLY "
|
|
"GENERATED BY gen.c.\n"
|
|
" *************** DO NOT EDIT!\n"
|
|
" ***************\n"
|
|
" ***************/\n"
|
|
"\n"
|
|
"/*! \\file */\n"
|
|
"\n";
|
|
|
|
#define STR_EXPAND(tok) #tok
|
|
#define STR(tok) STR_EXPAND(tok)
|
|
|
|
#define TYPENAMES 256
|
|
#define TYPECLASSLEN 20 /* DNS mnemonic size. Must be less than 100. */
|
|
#define TYPECLASSBUF (TYPECLASSLEN + 1)
|
|
#define TYPECLASSFMT "%" STR(TYPECLASSLEN) "[-0-9a-z]_%u"
|
|
#define ATTRIBUTESIZE 256
|
|
|
|
static struct cc {
|
|
struct cc *next;
|
|
uint16_t rdclass;
|
|
char classbuf[TYPECLASSBUF];
|
|
} *classes;
|
|
|
|
static struct tt {
|
|
struct tt *next;
|
|
uint16_t rdclass;
|
|
uint16_t type;
|
|
char classbuf[TYPECLASSBUF];
|
|
char typebuf[TYPECLASSBUF];
|
|
char dirbuf[PATH_MAX - 30];
|
|
} *types;
|
|
|
|
static struct ttnam {
|
|
char typebuf[TYPECLASSBUF];
|
|
char macroname[TYPECLASSBUF];
|
|
char attr[ATTRIBUTESIZE];
|
|
bool todo;
|
|
uint8_t hash;
|
|
uint16_t type;
|
|
} typenames[TYPENAMES];
|
|
|
|
static int ttnam_count;
|
|
|
|
typedef struct {
|
|
DIR *handle;
|
|
char *filename;
|
|
} isc_dir_t;
|
|
|
|
static char *
|
|
upper(char *);
|
|
static char *
|
|
funname(const char *, char *);
|
|
static void
|
|
doswitch(const char *, const char *, const char *, const char *, const char *,
|
|
const char *);
|
|
static void
|
|
add(unsigned int, const char *, int, const char *, const char *);
|
|
static void
|
|
sd(unsigned int, const char *, const char *, char);
|
|
static void
|
|
insert_into_typenames(int, const char *, const char *);
|
|
|
|
static uint8_t
|
|
HASH(char *string) {
|
|
size_t n;
|
|
unsigned char a, b;
|
|
|
|
n = strlen(string);
|
|
INSIST(n > 0);
|
|
a = tolower((unsigned char)string[0]);
|
|
b = tolower((unsigned char)string[n - 1]);
|
|
|
|
return ((a + n) * b) % 256;
|
|
}
|
|
|
|
static bool
|
|
start_directory(const char *path, isc_dir_t *dir) {
|
|
dir->handle = opendir(path);
|
|
|
|
if (dir->handle != NULL) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static bool
|
|
next_file(isc_dir_t *dir) {
|
|
struct dirent *dirent;
|
|
|
|
dir->filename = NULL;
|
|
|
|
if (dir->handle != NULL) {
|
|
errno = 0;
|
|
dirent = readdir(dir->handle);
|
|
if (dirent != NULL) {
|
|
dir->filename = dirent->d_name;
|
|
} else {
|
|
if (errno != 0) {
|
|
fprintf(stderr,
|
|
"Error: reading directory: %s\n",
|
|
strerror(errno));
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (dir->filename != NULL) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static void
|
|
end_directory(isc_dir_t *dir) {
|
|
if (dir->handle != NULL) {
|
|
(void)closedir(dir->handle);
|
|
}
|
|
|
|
dir->handle = NULL;
|
|
}
|
|
|
|
/*%
|
|
* If you use more than 10 of these in, say, a printf(), you'll have problems.
|
|
*/
|
|
static char *
|
|
upper(char *s) {
|
|
static int buf_to_use = 0;
|
|
static char buf[10][256];
|
|
char *b;
|
|
int c;
|
|
|
|
buf_to_use++;
|
|
if (buf_to_use > 9) {
|
|
buf_to_use = 0;
|
|
}
|
|
|
|
b = buf[buf_to_use];
|
|
memset(b, 0, 256);
|
|
|
|
while ((c = (*s++) & 0xff)) {
|
|
*b++ = islower(c) ? toupper(c) : c;
|
|
}
|
|
*b = '\0';
|
|
return buf[buf_to_use];
|
|
}
|
|
|
|
static char *
|
|
funname(const char *s, char *buf) {
|
|
char *b = buf;
|
|
char c;
|
|
|
|
INSIST(strlen(s) < TYPECLASSBUF);
|
|
while ((c = *s++)) {
|
|
*b++ = (c == '-') ? '_' : c;
|
|
}
|
|
*b = '\0';
|
|
return buf;
|
|
}
|
|
|
|
static void
|
|
doswitch(const char *name, const char *function, const char *args,
|
|
const char *tsw, const char *csw, const char *res) {
|
|
struct tt *tt;
|
|
int first = 1;
|
|
int lasttype = 0;
|
|
int subswitch = 0;
|
|
char buf1[TYPECLASSBUF], buf2[TYPECLASSBUF];
|
|
const char *result = " result =";
|
|
|
|
if (res == NULL) {
|
|
result = "";
|
|
}
|
|
|
|
for (tt = types; tt != NULL; tt = tt->next) {
|
|
if (first) {
|
|
printf("\n#define %s \\\n", name);
|
|
printf("\tswitch (%s) { \\\n" /*}*/, tsw);
|
|
first = 0;
|
|
}
|
|
if (tt->type != lasttype && subswitch) {
|
|
if (res == NULL) {
|
|
printf("\t\tdefault: break; \\\n");
|
|
} else {
|
|
printf("\t\tdefault: %s; break; \\\n", res);
|
|
}
|
|
printf("\t\t} \\\n");
|
|
printf("\t\tbreak; \\\n");
|
|
subswitch = 0;
|
|
}
|
|
if (tt->rdclass && tt->type != lasttype) {
|
|
printf("\tcase %d: switch (%s) { \\\n" /*}*/, tt->type,
|
|
csw);
|
|
subswitch = 1;
|
|
}
|
|
if (tt->rdclass == 0) {
|
|
printf("\tcase %d:%s %s_%s(%s); break;", tt->type,
|
|
result, function, funname(tt->typebuf, buf1),
|
|
args);
|
|
} else {
|
|
printf("\t\tcase %d:%s %s_%s_%s(%s); break;",
|
|
tt->rdclass, result, function,
|
|
funname(tt->classbuf, buf1),
|
|
funname(tt->typebuf, buf2), args);
|
|
}
|
|
printf(" \\\n");
|
|
lasttype = tt->type;
|
|
}
|
|
if (subswitch) {
|
|
if (res == NULL) {
|
|
printf("\t\tdefault: break; \\\n");
|
|
} else {
|
|
printf("\t\tdefault: %s; break; \\\n", res);
|
|
}
|
|
printf("\t\t} \\\n");
|
|
printf("\t\tbreak; \\\n");
|
|
}
|
|
if (first) {
|
|
if (res == NULL) {
|
|
printf("\n#define %s\n", name);
|
|
} else {
|
|
printf("\n#define %s %s;\n", name, res);
|
|
}
|
|
} else {
|
|
if (res == NULL) {
|
|
printf("\tdefault: break; \\\n");
|
|
} else {
|
|
printf("\tdefault: %s; break; \\\n", res);
|
|
}
|
|
printf("\t}\n");
|
|
}
|
|
}
|
|
|
|
static void
|
|
insert_into_typenames(int type, const char *typebuf, const char *attr) {
|
|
struct ttnam *ttn = NULL;
|
|
size_t c;
|
|
int i, n;
|
|
char tmp[256];
|
|
|
|
INSIST(strlen(typebuf) < TYPECLASSBUF);
|
|
for (i = 0; i < TYPENAMES && typenames[i].typebuf[0] != 0; i++) {
|
|
if (typenames[i].type != type) {
|
|
continue;
|
|
}
|
|
if (strcmp(typebuf, typenames[i].typebuf) != 0) {
|
|
fprintf(stderr,
|
|
"Error: type %d has two names: %s, %s\n", type,
|
|
typenames[i].typebuf, typebuf);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
ttn = &typenames[i];
|
|
}
|
|
/* Subtract one to leave an empty sentinel entry at the end */
|
|
if (i >= TYPENAMES - 1) {
|
|
fprintf(stderr, "Error: typenames array too small\n");
|
|
exit(EXIT_FAILURE);
|
|
} else if (ttn == NULL) {
|
|
ttn = &typenames[i];
|
|
ttnam_count = i + 1;
|
|
}
|
|
|
|
/* XXXMUKS: This is redundant due to the INSIST above. */
|
|
if (strlen(typebuf) > sizeof(ttn->typebuf) - 1) {
|
|
fprintf(stderr, "Error: type name %s is too long\n", typebuf);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
strncpy(ttn->typebuf, typebuf, sizeof(ttn->typebuf));
|
|
ttn->typebuf[sizeof(ttn->typebuf) - 1] = '\0';
|
|
|
|
strncpy(ttn->macroname, ttn->typebuf, sizeof(ttn->macroname));
|
|
ttn->macroname[sizeof(ttn->macroname) - 1] = '\0';
|
|
|
|
ttn->type = type;
|
|
c = strlen(ttn->macroname);
|
|
while (c > 0) {
|
|
if (ttn->macroname[c - 1] == '-') {
|
|
ttn->macroname[c - 1] = '_';
|
|
}
|
|
c--;
|
|
}
|
|
|
|
if (attr == NULL) {
|
|
n = snprintf(tmp, sizeof(tmp), "RRTYPE_%s_ATTRIBUTES",
|
|
upper(ttn->macroname));
|
|
INSIST(n > 0 && (unsigned int)n < sizeof(tmp));
|
|
attr = tmp;
|
|
}
|
|
|
|
if (ttn->attr[0] != 0 && strcmp(attr, ttn->attr) != 0) {
|
|
fprintf(stderr,
|
|
"Error: type %d has different attributes: "
|
|
"%s, %s\n",
|
|
type, ttn->attr, attr);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
if (strlen(attr) > sizeof(ttn->attr) - 1) {
|
|
fprintf(stderr, "Error: attr (%s) [name %s] is too long\n",
|
|
attr, typebuf);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
strncpy(ttn->attr, attr, sizeof(ttn->attr));
|
|
ttn->attr[sizeof(ttn->attr) - 1] = '\0';
|
|
|
|
ttn->hash = HASH(ttn->typebuf);
|
|
ttn->todo = true;
|
|
}
|
|
|
|
static void
|
|
add(unsigned int rdclass, const char *classbuf, int type, const char *typebuf,
|
|
const char *dirbuf) {
|
|
struct tt *newtt = (struct tt *)malloc(sizeof(*newtt));
|
|
struct tt *tt, *oldtt;
|
|
struct cc *newcc;
|
|
struct cc *cc, *oldcc;
|
|
|
|
INSIST(strlen(typebuf) < TYPECLASSBUF);
|
|
INSIST(strlen(classbuf) < TYPECLASSBUF);
|
|
INSIST(strlen(dirbuf) < PATH_MAX);
|
|
|
|
insert_into_typenames(type, typebuf, NULL);
|
|
|
|
if (newtt == NULL) {
|
|
fprintf(stderr, "malloc() failed\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
newtt->next = NULL;
|
|
newtt->rdclass = rdclass;
|
|
newtt->type = type;
|
|
|
|
strncpy(newtt->classbuf, classbuf, sizeof(newtt->classbuf));
|
|
newtt->classbuf[sizeof(newtt->classbuf) - 1] = '\0';
|
|
|
|
strncpy(newtt->typebuf, typebuf, sizeof(newtt->typebuf));
|
|
newtt->typebuf[sizeof(newtt->typebuf) - 1] = '\0';
|
|
|
|
if (strncmp(dirbuf, "./", 2) == 0) {
|
|
dirbuf += 2;
|
|
}
|
|
strncpy(newtt->dirbuf, dirbuf, sizeof(newtt->dirbuf));
|
|
newtt->dirbuf[sizeof(newtt->dirbuf) - 1] = '\0';
|
|
|
|
tt = types;
|
|
oldtt = NULL;
|
|
|
|
while ((tt != NULL) && (tt->type < type)) {
|
|
oldtt = tt;
|
|
tt = tt->next;
|
|
}
|
|
|
|
while ((tt != NULL) && (tt->type == type) && (tt->rdclass < rdclass)) {
|
|
INSIST(strcmp(tt->typebuf, typebuf) == 0);
|
|
oldtt = tt;
|
|
tt = tt->next;
|
|
}
|
|
|
|
INSIST(tt == NULL || tt->type != type || tt->rdclass != rdclass);
|
|
|
|
newtt->next = tt;
|
|
if (oldtt != NULL) {
|
|
oldtt->next = newtt;
|
|
} else {
|
|
types = newtt;
|
|
}
|
|
|
|
/*
|
|
* Do a class switch for this type.
|
|
*/
|
|
if (rdclass == 0) {
|
|
return;
|
|
}
|
|
|
|
newcc = (struct cc *)malloc(sizeof(*newcc));
|
|
if (newcc == NULL) {
|
|
fprintf(stderr, "malloc() failed\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
newcc->rdclass = rdclass;
|
|
strncpy(newcc->classbuf, classbuf, sizeof(newcc->classbuf));
|
|
newcc->classbuf[sizeof(newcc->classbuf) - 1] = '\0';
|
|
cc = classes;
|
|
oldcc = NULL;
|
|
|
|
while ((cc != NULL) && (cc->rdclass < rdclass)) {
|
|
oldcc = cc;
|
|
cc = cc->next;
|
|
}
|
|
|
|
if ((cc != NULL) && cc->rdclass == rdclass) {
|
|
free((char *)newcc);
|
|
return;
|
|
}
|
|
|
|
newcc->next = cc;
|
|
if (oldcc != NULL) {
|
|
oldcc->next = newcc;
|
|
} else {
|
|
classes = newcc;
|
|
}
|
|
}
|
|
|
|
static void
|
|
sd(unsigned int rdclass, const char *classbuf, const char *dirbuf,
|
|
char filetype) {
|
|
char buf[TYPECLASSLEN + sizeof("_4294967295.h")];
|
|
char typebuf[TYPECLASSBUF];
|
|
unsigned int type;
|
|
int n;
|
|
isc_dir_t dir;
|
|
|
|
if (!start_directory(dirbuf, &dir)) {
|
|
return;
|
|
}
|
|
|
|
while (next_file(&dir)) {
|
|
if (sscanf(dir.filename, TYPECLASSFMT, typebuf, &type) != 2) {
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
* sscanf accepts leading sign and zeros before type so
|
|
* compare the scanned items against the filename. Filter
|
|
* out mismatches. Also filter out bad file extensions.
|
|
*/
|
|
n = snprintf(buf, sizeof(buf), "%s_%u.%c", typebuf, type,
|
|
filetype);
|
|
INSIST(n > 0 && (unsigned int)n < sizeof(buf));
|
|
if (strcmp(buf, dir.filename) != 0) {
|
|
continue;
|
|
}
|
|
if (type > 65535) {
|
|
fprintf(stderr, "Error: type value > 65535 (%s)\n",
|
|
dir.filename);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
add(rdclass, classbuf, type, typebuf, dirbuf);
|
|
}
|
|
|
|
end_directory(&dir);
|
|
}
|
|
|
|
static int
|
|
ttnam_cmp(const void *va, const void *vb) {
|
|
const struct ttnam *ttna = va, *ttnb = vb;
|
|
return ttna->type - ttnb->type;
|
|
}
|
|
|
|
int
|
|
main(int argc, char **argv) {
|
|
char buf[PATH_MAX];
|
|
char srcdir[PATH_MAX];
|
|
unsigned int rdclass;
|
|
char classbuf[TYPECLASSBUF];
|
|
struct tt *tt;
|
|
struct cc *cc;
|
|
struct ttnam *ttn, *ttn2;
|
|
time_t now;
|
|
char year[11];
|
|
int lasttype;
|
|
int code = 1;
|
|
int class_enum = 0;
|
|
int type_enum = 0;
|
|
int structs = 0;
|
|
int depend = 0;
|
|
int c, n;
|
|
char buf1[TYPECLASSBUF];
|
|
char filetype = 'c';
|
|
FILE *fd;
|
|
char *prefix = NULL;
|
|
char *suffix = NULL;
|
|
char *file = NULL;
|
|
char *source_date_epoch;
|
|
unsigned long long epoch;
|
|
char *endptr;
|
|
isc_dir_t dir;
|
|
|
|
srcdir[0] = '\0';
|
|
while ((c = getopt(argc, argv, "cdits:F:P:S:")) != -1) {
|
|
switch (c) {
|
|
case 'c':
|
|
code = 0;
|
|
depend = 0;
|
|
type_enum = 0;
|
|
class_enum = 1;
|
|
filetype = 'c';
|
|
structs = 0;
|
|
break;
|
|
case 'd':
|
|
code = 0;
|
|
depend = 1;
|
|
class_enum = 0;
|
|
type_enum = 0;
|
|
structs = 0;
|
|
filetype = 'h';
|
|
break;
|
|
case 't':
|
|
code = 0;
|
|
depend = 0;
|
|
class_enum = 0;
|
|
type_enum = 1;
|
|
filetype = 'c';
|
|
structs = 0;
|
|
break;
|
|
case 'i':
|
|
code = 0;
|
|
depend = 0;
|
|
class_enum = 0;
|
|
type_enum = 0;
|
|
structs = 1;
|
|
filetype = 'h';
|
|
break;
|
|
case 's':
|
|
if (strlen(optarg) >
|
|
PATH_MAX - 2 * TYPECLASSLEN -
|
|
sizeof("/rdata/_65535_65535"))
|
|
{
|
|
fprintf(stderr, "\"%s\" too long\n", optarg);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
n = snprintf(srcdir, sizeof(srcdir), "%s/", optarg);
|
|
INSIST(n > 0 && (unsigned int)n < sizeof(srcdir));
|
|
break;
|
|
case 'F':
|
|
file = optarg;
|
|
break;
|
|
case 'P':
|
|
prefix = optarg;
|
|
break;
|
|
case 'S':
|
|
suffix = optarg;
|
|
break;
|
|
case '?':
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
}
|
|
|
|
n = snprintf(buf, sizeof(buf), "%srdata", srcdir);
|
|
INSIST(n > 0 && (unsigned int)n < sizeof(srcdir));
|
|
|
|
INSIST(start_directory(buf, &dir));
|
|
|
|
while (next_file(&dir)) {
|
|
if (sscanf(dir.filename, TYPECLASSFMT, classbuf, &rdclass) != 2)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
* sscanf accepts leading sign and zeros before type so
|
|
* compare the scanned items against the filename. Filter
|
|
* out mismatches.
|
|
*/
|
|
n = snprintf(buf, sizeof(buf), "%srdata/%s_%u", srcdir,
|
|
classbuf, rdclass);
|
|
INSIST(n > 0 && (unsigned int)n < sizeof(buf));
|
|
if (strcmp(buf + 6 + strlen(srcdir), dir.filename) != 0) {
|
|
continue;
|
|
}
|
|
if (rdclass > 65535) {
|
|
fprintf(stderr, "Error: class value > 65535 (%s)\n",
|
|
dir.filename);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
sd(rdclass, classbuf, buf, filetype);
|
|
}
|
|
end_directory(&dir);
|
|
n = snprintf(buf, sizeof(buf), "%srdata/generic", srcdir);
|
|
INSIST(n > 0 && (unsigned int)n < sizeof(srcdir));
|
|
sd(0, "", buf, filetype);
|
|
|
|
source_date_epoch = getenv("SOURCE_DATE_EPOCH");
|
|
if (source_date_epoch) {
|
|
errno = 0;
|
|
epoch = strtoull(source_date_epoch, &endptr, 10);
|
|
if ((errno == ERANGE && (epoch == ULLONG_MAX || epoch == 0)) ||
|
|
(errno != 0 && epoch == 0))
|
|
{
|
|
fprintf(stderr,
|
|
"Environment variable "
|
|
"$SOURCE_DATE_EPOCH: strtoull: %s\n",
|
|
strerror(errno));
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
if (endptr == source_date_epoch) {
|
|
fprintf(stderr,
|
|
"Environment variable "
|
|
"$SOURCE_DATE_EPOCH: "
|
|
"No digits were found: %s\n",
|
|
endptr);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
if (*endptr != '\0') {
|
|
fprintf(stderr,
|
|
"Environment variable "
|
|
"$SOURCE_DATE_EPOCH: Trailing garbage: %s\n",
|
|
endptr);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
if (epoch > ULONG_MAX) {
|
|
fprintf(stderr,
|
|
"Environment variable "
|
|
"$SOURCE_DATE_EPOCH: value must be "
|
|
"smaller than or equal to: %lu but "
|
|
"was found to be: %llu \n",
|
|
ULONG_MAX, epoch);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
now = epoch;
|
|
} else {
|
|
time(&now);
|
|
}
|
|
|
|
if (now != -1) {
|
|
struct tm t, *tm = gmtime_r(&now, &t);
|
|
|
|
if (tm != NULL && tm->tm_year > 104) {
|
|
n = snprintf(year, sizeof(year), "-%d",
|
|
tm->tm_year + 1900);
|
|
INSIST(n > 0 && (unsigned int)n < sizeof(year));
|
|
} else {
|
|
snprintf(year, sizeof(year), "-2016");
|
|
}
|
|
} else {
|
|
snprintf(year, sizeof(year), "-2016");
|
|
}
|
|
|
|
if (!depend) {
|
|
printf(copyright, year);
|
|
}
|
|
|
|
if (code) {
|
|
printf("#pragma once\n");
|
|
|
|
printf("#include <stdbool.h>\n");
|
|
printf("#include <isc/result.h>\n\n");
|
|
printf("#include <dns/name.h>\n\n");
|
|
|
|
for (tt = types; tt != NULL; tt = tt->next) {
|
|
printf("#include \"%s/%s_%d.c\"\n", tt->dirbuf,
|
|
tt->typebuf, tt->type);
|
|
}
|
|
|
|
printf("\n\n");
|
|
|
|
doswitch("FROMTEXTSWITCH", "fromtext", FROMTEXTARGS,
|
|
FROMTEXTTYPE, FROMTEXTCLASS, FROMTEXTDEF);
|
|
doswitch("TOTEXTSWITCH", "totext", TOTEXTARGS, TOTEXTTYPE,
|
|
TOTEXTCLASS, TOTEXTDEF);
|
|
doswitch("FROMWIRESWITCH", "fromwire", FROMWIREARGS,
|
|
FROMWIRETYPE, FROMWIRECLASS, FROMWIREDEF);
|
|
doswitch("TOWIRESWITCH", "towire", TOWIREARGS, TOWIRETYPE,
|
|
TOWIRECLASS, TOWIREDEF);
|
|
doswitch("COMPARESWITCH", "compare", COMPAREARGS, COMPARETYPE,
|
|
COMPARECLASS, COMPAREDEF);
|
|
doswitch("CASECOMPARESWITCH", "casecompare", COMPAREARGS,
|
|
COMPARETYPE, COMPARECLASS, COMPAREDEF);
|
|
doswitch("FROMSTRUCTSWITCH", "fromstruct", FROMSTRUCTARGS,
|
|
FROMSTRUCTTYPE, FROMSTRUCTCLASS, FROMSTRUCTDEF);
|
|
doswitch("TOSTRUCTSWITCH", "tostruct", TOSTRUCTARGS,
|
|
TOSTRUCTTYPE, TOSTRUCTCLASS, TOSTRUCTDEF);
|
|
doswitch("FREESTRUCTSWITCH", "freestruct", FREESTRUCTARGS,
|
|
FREESTRUCTTYPE, FREESTRUCTCLASS, FREESTRUCTDEF);
|
|
doswitch("ADDITIONALDATASWITCH", "additionaldata",
|
|
ADDITIONALDATAARGS, ADDITIONALDATATYPE,
|
|
ADDITIONALDATACLASS, ADDITIONALDATADEF);
|
|
doswitch("DIGESTSWITCH", "digest", DIGESTARGS, DIGESTTYPE,
|
|
DIGESTCLASS, DIGESTDEF);
|
|
doswitch("CHECKOWNERSWITCH", "checkowner", CHECKOWNERARGS,
|
|
CHECKOWNERTYPE, CHECKOWNERCLASS, CHECKOWNERDEF);
|
|
doswitch("CHECKNAMESSWITCH", "checknames", CHECKNAMESARGS,
|
|
CHECKNAMESTYPE, CHECKNAMESCLASS, CHECKNAMESDEF);
|
|
|
|
/*
|
|
* From here down, we are processing the rdata names and
|
|
* attributes.
|
|
*/
|
|
|
|
#define METANOTQUESTION \
|
|
"DNS_RDATATYPEATTR_META | " \
|
|
"DNS_RDATATYPEATTR_NOTQUESTION"
|
|
#define METAQUESTIONONLY \
|
|
"DNS_RDATATYPEATTR_META | " \
|
|
"DNS_RDATATYPEATTR_QUESTIONONLY"
|
|
#define RESERVEDNAME "0"
|
|
#define RESERVED "DNS_RDATATYPEATTR_RESERVED"
|
|
|
|
/*
|
|
* Add in reserved/special types. This will let us
|
|
* sort them without special cases.
|
|
*/
|
|
insert_into_typenames(100, "uinfo", RESERVEDNAME);
|
|
insert_into_typenames(101, "uid", RESERVEDNAME);
|
|
insert_into_typenames(102, "gid", RESERVEDNAME);
|
|
insert_into_typenames(103, "unspec", RESERVEDNAME);
|
|
insert_into_typenames(251, "ixfr", METAQUESTIONONLY);
|
|
insert_into_typenames(252, "axfr", METAQUESTIONONLY);
|
|
insert_into_typenames(253, "mailb", METAQUESTIONONLY);
|
|
insert_into_typenames(254, "maila", METAQUESTIONONLY);
|
|
insert_into_typenames(255, "any", METAQUESTIONONLY);
|
|
|
|
/*
|
|
* For reproducible builds, ensure the directory read
|
|
* order does not affect the order of switch cases.
|
|
*/
|
|
qsort(typenames, ttnam_count, sizeof(struct ttnam), ttnam_cmp);
|
|
|
|
/*
|
|
* Spit out a quick and dirty hash function. Here,
|
|
* we walk through the list of type names, and calculate
|
|
* a hash. This isn't perfect, but it will generate "pretty
|
|
* good" estimates. Lowercase the characters before
|
|
* computing in all cases.
|
|
*
|
|
* Here, walk the list from top to bottom, calculating
|
|
* the hash (mod 256) for each name.
|
|
*/
|
|
printf("#define RDATATYPE_COMPARE(_s, _d, _tn, _n, _tp) \\\n");
|
|
printf("\tdo { \\\n");
|
|
printf("\t\tif (sizeof(_s) - 1 == _n && \\\n"
|
|
"\t\t strncasecmp(_s,(_tn),"
|
|
"(sizeof(_s) - 1)) == 0) { \\\n");
|
|
printf("\t\t\tif ((dns_rdatatype_attributes(_d) & "
|
|
"DNS_RDATATYPEATTR_RESERVED) != 0) \\\n");
|
|
printf("\t\t\t\treturn (ISC_R_NOTIMPLEMENTED); \\\n");
|
|
printf("\t\t\t*(_tp) = _d; \\\n");
|
|
printf("\t\t\treturn (ISC_R_SUCCESS); \\\n");
|
|
printf("\t\t} \\\n");
|
|
printf("\t} while (0)\n\n");
|
|
|
|
printf("#define RDATATYPE_FROMTEXT_SW(_hash,"
|
|
"_typename,_length,_typep) \\\n");
|
|
printf("\tswitch (_hash) { \\\n");
|
|
for (ttn = typenames; ttn->typebuf[0] != 0; ttn++) {
|
|
/*
|
|
* Skip entries we already processed.
|
|
*/
|
|
if (!ttn->todo) {
|
|
continue;
|
|
}
|
|
|
|
printf("\t\tcase %u: \\\n", ttn->hash);
|
|
|
|
/*
|
|
* Find all other entries that happen to match
|
|
* this hash.
|
|
*/
|
|
for (ttn2 = typenames; ttn2->typebuf[0] != 0; ttn2++) {
|
|
if (ttn2->todo && ttn2->hash == ttn->hash) {
|
|
printf("\t\t\tRDATATYPE_COMPARE"
|
|
"(\"%s\", %d, _typename, "
|
|
" _length, _typep); \\\n",
|
|
ttn2->typebuf, ttn2->type);
|
|
ttn2->todo = false;
|
|
}
|
|
}
|
|
printf("\t\t\tbreak; \\\n");
|
|
}
|
|
printf("\t}\n");
|
|
|
|
printf("#define RDATATYPE_ATTRIBUTE_SW \\\n");
|
|
printf("\tswitch (type) { \\\n");
|
|
for (ttn = typenames; ttn->typebuf[0] != 0; ttn++) {
|
|
printf("\tcase %d: return (%s); \\\n", ttn->type,
|
|
upper(ttn->attr));
|
|
}
|
|
printf("\t}\n");
|
|
|
|
printf("#define RDATATYPE_TOTEXT_SW \\\n");
|
|
printf("\tswitch (type) { \\\n");
|
|
for (ttn = typenames; ttn->typebuf[0] != 0; ttn++) {
|
|
/*
|
|
* Remove KEYDATA (65533) from the type to memonic
|
|
* translation as it is internal use only. This
|
|
* stops the tools from displaying KEYDATA instead
|
|
* of TYPE65533.
|
|
*/
|
|
if (ttn->type == 65533U) {
|
|
continue;
|
|
}
|
|
printf("\tcase %d: return "
|
|
"(str_totext(\"%s\", target)); \\\n",
|
|
ttn->type, upper(ttn->typebuf));
|
|
}
|
|
printf("\t}\n");
|
|
} else if (type_enum) {
|
|
char *s;
|
|
|
|
printf("#pragma once\n");
|
|
|
|
printf("enum {\n");
|
|
printf("\tdns_rdatatype_none = 0,\n");
|
|
|
|
lasttype = 0;
|
|
for (tt = types; tt != NULL; tt = tt->next) {
|
|
if (tt->type != lasttype) {
|
|
printf("\tdns_rdatatype_%s = %d,\n",
|
|
funname(tt->typebuf, buf1),
|
|
lasttype = tt->type);
|
|
}
|
|
}
|
|
|
|
printf("\tdns_rdatatype_ixfr = 251,\n");
|
|
printf("\tdns_rdatatype_axfr = 252,\n");
|
|
printf("\tdns_rdatatype_mailb = 253,\n");
|
|
printf("\tdns_rdatatype_maila = 254,\n");
|
|
printf("\tdns_rdatatype_any = 255\n");
|
|
|
|
printf("};\n\n");
|
|
|
|
printf("#define dns_rdatatype_none\t"
|
|
"((dns_rdatatype_t)dns_rdatatype_none)\n");
|
|
|
|
for (tt = types; tt != NULL; tt = tt->next) {
|
|
if (tt->type != lasttype) {
|
|
s = funname(tt->typebuf, buf1);
|
|
printf("#define dns_rdatatype_%s\t%s"
|
|
"((dns_rdatatype_t)dns_rdatatype_%s)\n",
|
|
s, strlen(s) < 2U ? "\t" : "", s);
|
|
lasttype = tt->type;
|
|
}
|
|
}
|
|
|
|
printf("#define dns_rdatatype_ixfr\t"
|
|
"((dns_rdatatype_t)dns_rdatatype_ixfr)\n");
|
|
printf("#define dns_rdatatype_axfr\t"
|
|
"((dns_rdatatype_t)dns_rdatatype_axfr)\n");
|
|
printf("#define dns_rdatatype_mailb\t"
|
|
"((dns_rdatatype_t)dns_rdatatype_mailb)\n");
|
|
printf("#define dns_rdatatype_maila\t"
|
|
"((dns_rdatatype_t)dns_rdatatype_maila)\n");
|
|
printf("#define dns_rdatatype_any\t"
|
|
"((dns_rdatatype_t)dns_rdatatype_any)\n");
|
|
} else if (class_enum) {
|
|
char *s;
|
|
int classnum;
|
|
|
|
printf("#pragma once\n");
|
|
|
|
printf("enum {\n");
|
|
|
|
printf("\tdns_rdataclass_reserved0 = 0,\n");
|
|
printf("#define dns_rdataclass_reserved0 \\\n\t\t\t\t"
|
|
"((dns_rdataclass_t)dns_rdataclass_reserved0)\n");
|
|
|
|
#define PRINTCLASS(name, num) \
|
|
do { \
|
|
s = funname(name, buf1); \
|
|
classnum = num; \
|
|
printf("\tdns_rdataclass_%s = %d%s\n", s, classnum, \
|
|
classnum != 255 ? "," : ""); \
|
|
printf("#define dns_rdataclass_%s\t" \
|
|
"((dns_rdataclass_t)dns_rdataclass_%s)\n", \
|
|
s, s); \
|
|
} while (0)
|
|
|
|
for (cc = classes; cc != NULL; cc = cc->next) {
|
|
if (cc->rdclass == 3) {
|
|
PRINTCLASS("chaos", 3);
|
|
} else if (cc->rdclass == 255) {
|
|
PRINTCLASS("none", 254);
|
|
}
|
|
PRINTCLASS(cc->classbuf, cc->rdclass);
|
|
}
|
|
|
|
#undef PRINTCLASS
|
|
|
|
printf("};\n\n");
|
|
} else if (structs) {
|
|
if (prefix != NULL) {
|
|
if ((fd = fopen(prefix, "r")) != NULL) {
|
|
while (fgets(buf, sizeof(buf), fd) != NULL) {
|
|
printf("%s", buf);
|
|
}
|
|
fclose(fd);
|
|
}
|
|
}
|
|
for (tt = types; tt != NULL; tt = tt->next) {
|
|
snprintf(buf, sizeof(buf), "%s/%s_%d.h", tt->dirbuf,
|
|
tt->typebuf, tt->type);
|
|
if ((fd = fopen(buf, "r")) != NULL) {
|
|
while (fgets(buf, sizeof(buf), fd) != NULL) {
|
|
printf("%s", buf);
|
|
}
|
|
fclose(fd);
|
|
}
|
|
}
|
|
if (suffix != NULL) {
|
|
if ((fd = fopen(suffix, "r")) != NULL) {
|
|
while (fgets(buf, sizeof(buf), fd) != NULL) {
|
|
printf("%s", buf);
|
|
}
|
|
fclose(fd);
|
|
}
|
|
}
|
|
} else if (depend) {
|
|
for (tt = types; tt != NULL; tt = tt->next) {
|
|
printf("%s:\t%s/%s_%d.h\n", file, tt->dirbuf,
|
|
tt->typebuf, tt->type);
|
|
}
|
|
}
|
|
|
|
if (ferror(stdout) != 0) {
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
return 0;
|
|
}
|