xref: /openbsd/usr.bin/dig/lib/dns/gen.c (revision 6bae335d)
1 /*
2  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
9  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
11  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
13  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14  * PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 /*! \file */
18 
19 #include <sys/types.h>
20 
21 #include <ctype.h>
22 #include <dirent.h>
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <time.h>
27 #include <unistd.h>
28 
29 #define INSIST(cond) \
30 	if (!(cond)) { \
31 		fprintf(stderr, "%s:%d: INSIST(%s)\n", \
32 			 __FILE__, __LINE__, #cond); \
33 		abort(); \
34 	}
35 
36 #define TOTEXTARGS "rdata, tctx, target"
37 #define TOTEXTCLASS "rdata->rdclass"
38 #define TOTEXTTYPE "rdata->type"
39 #define TOTEXTDEF "use_default = 1"
40 
41 #define FROMWIREARGS "rdclass, type, source, dctx, options, target"
42 #define FROMWIRECLASS "rdclass"
43 #define FROMWIRETYPE "type"
44 #define FROMWIREDEF "use_default = 1"
45 
46 #define TOWIREARGS "rdata, cctx, target"
47 #define TOWIRECLASS "rdata->rdclass"
48 #define TOWIRETYPE "rdata->type"
49 #define TOWIREDEF "use_default = 1"
50 
51 static const char copyright[] =
52 "/*\n"
53 " * Copyright (C) 2004%s Internet Systems Consortium, Inc. (\"ISC\")\n"
54 " * Copyright (C) 1998-2003 Internet Software Consortium.\n"
55 " *\n"
56 " * Permission to use, copy, modify, and distribute this software for any\n"
57 " * purpose with or without fee is hereby granted, provided that the above\n"
58 " * copyright notice and this permission notice appear in all copies.\n"
59 " *\n"
60 " * THE SOFTWARE IS PROVIDED \"AS IS\" AND ISC DISCLAIMS ALL WARRANTIES WITH\n"
61 " * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\n"
62 " * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,\n"
63 " * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\n"
64 " * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE\n"
65 " * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\n"
66 " * PERFORMANCE OF THIS SOFTWARE.\n"
67 " */\n"
68 "\n"
69 "/***************\n"
70 " ***************\n"
71 " ***************   THIS FILE IS AUTOMATICALLY GENERATED BY gen.c.\n"
72 " ***************   DO NOT EDIT!\n"
73 " ***************\n"
74 " ***************/\n"
75 "\n"
76 "/*! \\file */\n"
77 "\n";
78 
79 #define STR_EXPAND(tok) #tok
80 #define STR(tok) STR_EXPAND(tok)
81 
82 #define TYPECLASSLEN 20		/* DNS mnemonic size. Must be less than 100. */
83 #define TYPECLASSBUF (TYPECLASSLEN + 1)
84 #define TYPECLASSFMT "%" STR(TYPECLASSLEN) "[-0-9a-z]_%d"
85 #define DIRNAMESIZE 256
86 
87 static struct cc {
88 	struct cc *next;
89 	int rdclass;
90 	char classname[TYPECLASSBUF];
91 } *classes;
92 
93 static struct tt {
94 	struct tt *next;
95 	int rdclass;
96 	int type;
97 	char classname[TYPECLASSBUF];
98 	char typename[TYPECLASSBUF];
99 	char dirname[DIRNAMESIZE];	/* XXX Should be max path length */
100 } *types;
101 
102 static char *
103 funname(const char *, char *);
104 static void
105 doswitch(const char *, const char *, const char *, const char *,
106 	 const char *, const char *);
107 static void
108 add(int, const char *, int, const char *, const char *);
109 static void
110 sd(int, const char *, const char *, char);
111 
112 
113 static char *
funname(const char * s,char * buf)114 funname(const char *s, char *buf) {
115 	char *b = buf;
116 	char c;
117 
118 	INSIST(strlen(s) < TYPECLASSBUF);
119 	while ((c = *s++)) {
120 		*b++ = (c == '-') ? '_' : c;
121 	}
122 	*b = '\0';
123 	return (buf);
124 }
125 
126 static void
doswitch(const char * name,const char * function,const char * args,const char * tsw,const char * csw,const char * res)127 doswitch(const char *name, const char *function, const char *args,
128 	 const char *tsw, const char *csw, const char *res)
129 {
130 	struct tt *tt;
131 	int first = 1;
132 	int lasttype = 0;
133 	int subswitch = 0;
134 	char buf1[TYPECLASSBUF], buf2[TYPECLASSBUF];
135 	const char *result = " result =";
136 
137 	if (res == NULL)
138 		result = "";
139 
140 	for (tt = types; tt != NULL; tt = tt->next) {
141 		if (first) {
142 			fprintf(stdout, "\n#define %s \\\n", name);
143 			fprintf(stdout, "\tswitch (%s) { \\\n" /*}*/, tsw);
144 			first = 0;
145 		}
146 		if (tt->type != lasttype && subswitch) {
147 			if (res == NULL)
148 				fprintf(stdout, "\t\tdefault: break; \\\n");
149 			else
150 				fprintf(stdout,
151 					"\t\tdefault: %s; break; \\\n", res);
152 			fputs(/*{*/ "\t\t} \\\n", stdout);
153 			fputs("\t\tbreak; \\\n", stdout);
154 			subswitch = 0;
155 		}
156 		if (tt->rdclass && tt->type != lasttype) {
157 			fprintf(stdout, "\tcase %d: switch (%s) { \\\n" /*}*/,
158 				tt->type, csw);
159 			subswitch = 1;
160 		}
161 		if (tt->rdclass == 0)
162 			fprintf(stdout,
163 				"\tcase %d:%s %s_%s(%s); break;",
164 				tt->type, result, function,
165 				funname(tt->typename, buf1), args);
166 		else
167 			fprintf(stdout,
168 				"\t\tcase %d:%s %s_%s_%s(%s); break;",
169 				tt->rdclass, result, function,
170 				funname(tt->classname, buf1),
171 				funname(tt->typename, buf2), args);
172 		fputs(" \\\n", stdout);
173 		lasttype = tt->type;
174 	}
175 	if (subswitch) {
176 		if (res == NULL)
177 			fprintf(stdout, "\t\tdefault: break; \\\n");
178 		else
179 			fprintf(stdout, "\t\tdefault: %s; break; \\\n", res);
180 		fputs(/*{*/ "\t\t} \\\n", stdout);
181 		fputs("\t\tbreak; \\\n", stdout);
182 	}
183 	if (first) {
184 		if (res == NULL)
185 			fprintf(stdout, "\n#define %s\n", name);
186 		else
187 			fprintf(stdout, "\n#define %s %s;\n", name, res);
188 	} else {
189 		if (res == NULL)
190 			fprintf(stdout, "\tdefault: break; \\\n");
191 		else
192 			fprintf(stdout, "\tdefault: %s; break; \\\n", res);
193 		fputs(/*{*/ "\t}\n", stdout);
194 	}
195 }
196 
197 static void
add(int rdclass,const char * classname,int type,const char * typename,const char * dirname)198 add(int rdclass, const char *classname, int type, const char *typename,
199     const char *dirname)
200 {
201 	struct tt *newtt = (struct tt *)malloc(sizeof(*newtt));
202 	struct tt *tt, *oldtt;
203 	struct cc *newcc;
204 	struct cc *cc, *oldcc;
205 
206 	INSIST(strlen(typename) < TYPECLASSBUF);
207 	INSIST(strlen(classname) < TYPECLASSBUF);
208 	INSIST(strlen(dirname) < DIRNAMESIZE);
209 
210 	if (newtt == NULL) {
211 		fprintf(stderr, "malloc() failed\n");
212 		exit(1);
213 	}
214 
215 	newtt->next = NULL;
216 	newtt->rdclass = rdclass;
217 	newtt->type = type;
218 
219 	strncpy(newtt->classname, classname, sizeof(newtt->classname));
220 	newtt->classname[sizeof(newtt->classname) - 1] = '\0';
221 
222 	strncpy(newtt->typename, typename, sizeof(newtt->typename));
223 	newtt->typename[sizeof(newtt->typename) - 1] = '\0';
224 
225 	if (strncmp(dirname, "./", 2) == 0)
226 		dirname += 2;
227 	strncpy(newtt->dirname, dirname, sizeof(newtt->dirname));
228 	newtt->dirname[sizeof(newtt->dirname) - 1] = '\0';
229 
230 	tt = types;
231 	oldtt = NULL;
232 
233 	while ((tt != NULL) && (tt->type < type)) {
234 		oldtt = tt;
235 		tt = tt->next;
236 	}
237 
238 	while ((tt != NULL) && (tt->type == type) && (tt->rdclass < rdclass)) {
239 		if (strcmp(tt->typename, typename) != 0)
240 			exit(1);
241 		oldtt = tt;
242 		tt = tt->next;
243 	}
244 
245 	if ((tt != NULL) && (tt->type == type) && (tt->rdclass == rdclass))
246 		exit(1);
247 
248 	newtt->next = tt;
249 	if (oldtt != NULL)
250 		oldtt->next = newtt;
251 	else
252 		types = newtt;
253 
254 	/*
255 	 * Do a class switch for this type.
256 	 */
257 	if (rdclass == 0)
258 		return;
259 
260 	newcc = (struct cc *)malloc(sizeof(*newcc));
261 	if (newcc == NULL) {
262 		fprintf(stderr, "malloc() failed\n");
263 		exit(1);
264 	}
265 	newcc->rdclass = rdclass;
266 	strncpy(newcc->classname, classname, sizeof(newcc->classname));
267 	newcc->classname[sizeof(newcc->classname) - 1] = '\0';
268 	cc = classes;
269 	oldcc = NULL;
270 
271 	while ((cc != NULL) && (cc->rdclass < rdclass)) {
272 		oldcc = cc;
273 		cc = cc->next;
274 	}
275 
276 	if ((cc != NULL) && cc->rdclass == rdclass) {
277 		free((char *)newcc);
278 		return;
279 	}
280 
281 	newcc->next = cc;
282 	if (oldcc != NULL)
283 		oldcc->next = newcc;
284 	else
285 		classes = newcc;
286 }
287 
288 static void
sd(int rdclass,const char * classname,const char * dirname,char filetype)289 sd(int rdclass, const char *classname, const char *dirname, char filetype) {
290 	DIR *dirp;
291 	struct dirent *dp;
292 	char buf[TYPECLASSLEN + sizeof("_65535.h")];
293 	char typename[TYPECLASSBUF];
294 	int type, n;
295 
296 	if ((dirp = opendir(dirname)) == NULL)
297 		return;
298 
299 	while ((dp = readdir(dirp)) != NULL) {
300 		if (sscanf(dp->d_name, TYPECLASSFMT, typename, &type) != 2)
301 			continue;
302 		if ((type > 65535) || (type < 0))
303 			continue;
304 
305 		n = snprintf(buf, sizeof(buf), "%s_%d.%c", typename,
306 			     type, filetype);
307 		INSIST(n > 0 && (unsigned)n < sizeof(buf));
308 		if (strcmp(buf, dp->d_name) != 0)
309 			continue;
310 		add(rdclass, classname, type, typename, dirname);
311 	}
312 
313 	closedir(dirp);
314 }
315 
316 int
main(int argc,char ** argv)317 main(int argc, char **argv) {
318 	DIR *dirp;
319 	struct dirent *dp;
320 	char buf[DIRNAMESIZE];		/* XXX Should be max path length */
321 	char srcdir[DIRNAMESIZE];	/* XXX Should be max path length */
322 	int rdclass;
323 	char classname[TYPECLASSBUF];
324 	struct tt *tt;
325 	struct cc *cc;
326 	struct tm *tm;
327 	time_t now;
328 	char year[11];
329 	int lasttype;
330 	int code = 1;
331 	int class_enum = 0;
332 	int type_enum = 0;
333 	int structs = 0;
334 	int depend = 0;
335 	int c, n;
336 	char buf1[TYPECLASSBUF];
337 	char filetype = 'c';
338 	FILE *fd;
339 	char *prefix = NULL;
340 	char *suffix = NULL;
341 	char *file = NULL;
342 
343 	srcdir[0] = '\0';
344 	while ((c = getopt(argc, argv, "cdits:F:P:S:")) != -1)
345 		switch (c) {
346 		case 'c':
347 			code = 0;
348 			depend = 0;
349 			type_enum = 0;
350 			class_enum = 1;
351 			filetype = 'c';
352 			structs = 0;
353 			break;
354 		case 'd':
355 			code = 0;
356 			depend = 1;
357 			class_enum = 0;
358 			type_enum = 0;
359 			structs = 0;
360 			filetype = 'h';
361 			break;
362 		case 't':
363 			code = 0;
364 			depend = 0;
365 			class_enum = 0;
366 			type_enum = 1;
367 			filetype = 'c';
368 			structs = 0;
369 			break;
370 		case 'i':
371 			code = 0;
372 			depend = 0;
373 			class_enum = 0;
374 			type_enum = 0;
375 			structs = 1;
376 			filetype = 'h';
377 			break;
378 		case 's':
379 			if (strlen(optarg) >
380 			    DIRNAMESIZE - 2 * TYPECLASSLEN  -
381 			    sizeof("/rdata/_65535_65535")) {
382 				fprintf(stderr, "\"%s\" too long\n",
383 					optarg);
384 				exit(1);
385 			}
386 			n = snprintf(srcdir, sizeof(srcdir), "%s/",
387 				     optarg);
388 			INSIST(n > 0 && (unsigned)n < sizeof(srcdir));
389 			break;
390 		case 'F':
391 			file = optarg;
392 			break;
393 		case 'P':
394 			prefix = optarg;
395 			break;
396 		case 'S':
397 			suffix = optarg;
398 			break;
399 		case '?':
400 			exit(1);
401 		}
402 
403 	n = snprintf(buf, sizeof(buf), "%srdata", srcdir);
404 	INSIST(n > 0 && (unsigned)n < sizeof(srcdir));
405 
406 	if ((dirp = opendir(buf)) == NULL)
407 		exit(1);
408 
409 	while ((dp = readdir(dirp)) != NULL) {
410 		if (sscanf(dp->d_name, TYPECLASSFMT, classname,
411 			   &rdclass) != 2)
412 			continue;
413 		if ((rdclass > 65535) || (rdclass < 0))
414 			continue;
415 
416 		n = snprintf(buf, sizeof(buf), "%srdata/%s_%d",
417 			     srcdir, classname, rdclass);
418 		INSIST(n > 0 && (unsigned)n < sizeof(buf));
419 		if (strcmp(buf + 6 + strlen(srcdir), dp->d_name) != 0)
420 			continue;
421 		sd(rdclass, classname, buf, filetype);
422 	}
423 	closedir(dirp);
424 
425 	n = snprintf(buf, sizeof(buf), "%srdata/generic", srcdir);
426 	INSIST(n > 0 && (unsigned)n < sizeof(srcdir));
427 	sd(0, "", buf, filetype);
428 
429 	if (time(&now) != -1) {
430 		if ((tm = localtime(&now)) != NULL && tm->tm_year > 104) {
431 			n = snprintf(year, sizeof(year), "-%d",
432 				     tm->tm_year + 1900);
433 			INSIST(n > 0 && (unsigned)n < sizeof(year));
434 		} else
435 			year[0] = 0;
436 	} else
437 		year[0] = 0;
438 
439 	if (!depend)
440 		fprintf(stdout, copyright, year);
441 
442 	if (code) {
443 		fputs("#ifndef DNS_CODE_H\n", stdout);
444 		fputs("#define DNS_CODE_H 1\n\n", stdout);
445 
446 		fputs("#include <isc/result.h>\n\n", stdout);
447 		fputs("#include <dns/name.h>\n\n", stdout);
448 
449 		for (tt = types; tt != NULL; tt = tt->next)
450 			fprintf(stdout, "#include \"%s/%s_%d.c\"\n",
451 				tt->dirname, tt->typename, tt->type);
452 
453 		fputs("\n\n", stdout);
454 
455 		doswitch("TOTEXTSWITCH", "totext", TOTEXTARGS,
456 			 TOTEXTTYPE, TOTEXTCLASS, TOTEXTDEF);
457 		doswitch("FROMWIRESWITCH", "fromwire", FROMWIREARGS,
458 			 FROMWIRETYPE, FROMWIRECLASS, FROMWIREDEF);
459 		doswitch("TOWIRESWITCH", "towire", TOWIREARGS,
460 			 TOWIRETYPE, TOWIRECLASS, TOWIREDEF);
461 
462 		fputs("#endif /* DNS_CODE_H */\n", stdout);
463 	} else if (type_enum) {
464 		char *s;
465 
466 		fprintf(stdout, "#ifndef DNS_ENUMTYPE_H\n");
467 		fprintf(stdout, "#define DNS_ENUMTYPE_H 1\n\n");
468 
469 		fprintf(stdout, "enum {\n");
470 		fprintf(stdout, "\tdns_rdatatype_none = 0,\n");
471 
472 		lasttype = 0;
473 		for (tt = types; tt != NULL; tt = tt->next)
474 			if (tt->type != lasttype)
475 				fprintf(stdout,
476 					"\tdns_rdatatype_%s = %d,\n",
477 					funname(tt->typename, buf1),
478 					lasttype = tt->type);
479 
480 		fprintf(stdout, "\tdns_rdatatype_ixfr = 251,\n");
481 		fprintf(stdout, "\tdns_rdatatype_axfr = 252,\n");
482 		fprintf(stdout, "\tdns_rdatatype_mailb = 253,\n");
483 		fprintf(stdout, "\tdns_rdatatype_maila = 254,\n");
484 		fprintf(stdout, "\tdns_rdatatype_any = 255\n");
485 
486 		fprintf(stdout, "};\n\n");
487 
488 		fprintf(stdout, "#define dns_rdatatype_none\t"
489 			"((dns_rdatatype_t)dns_rdatatype_none)\n");
490 
491 		for (tt = types; tt != NULL; tt = tt->next)
492 			if (tt->type != lasttype) {
493 				s = funname(tt->typename, buf1);
494 				fprintf(stdout,
495 					"#define dns_rdatatype_%s\t%s"
496 					"((dns_rdatatype_t)dns_rdatatype_%s)"
497 					"\n",
498 					s, strlen(s) < 2U ? "\t" : "", s);
499 				lasttype = tt->type;
500 			}
501 
502 		fprintf(stdout, "#define dns_rdatatype_ixfr\t"
503 			"((dns_rdatatype_t)dns_rdatatype_ixfr)\n");
504 		fprintf(stdout, "#define dns_rdatatype_axfr\t"
505 			"((dns_rdatatype_t)dns_rdatatype_axfr)\n");
506 		fprintf(stdout, "#define dns_rdatatype_mailb\t"
507 			"((dns_rdatatype_t)dns_rdatatype_mailb)\n");
508 		fprintf(stdout, "#define dns_rdatatype_maila\t"
509 			"((dns_rdatatype_t)dns_rdatatype_maila)\n");
510 		fprintf(stdout, "#define dns_rdatatype_any\t"
511 			"((dns_rdatatype_t)dns_rdatatype_any)\n");
512 
513 		fprintf(stdout, "\n#endif /* DNS_ENUMTYPE_H */\n");
514 
515 	} else if (class_enum) {
516 		char *s;
517 		int classnum;
518 
519 		fprintf(stdout, "#ifndef DNS_ENUMCLASS_H\n");
520 		fprintf(stdout, "#define DNS_ENUMCLASS_H 1\n\n");
521 
522 		fprintf(stdout, "enum {\n");
523 
524 		fprintf(stdout, "\tdns_rdataclass_reserved0 = 0,\n");
525 		fprintf(stdout, "#define dns_rdataclass_reserved0 \\\n\t\t\t\t"
526 			"((dns_rdataclass_t)dns_rdataclass_reserved0)\n");
527 
528 #define PRINTCLASS(name, num) \
529 	do { \
530 		s = funname(name, buf1); \
531 		classnum = num; \
532 		fprintf(stdout, "\tdns_rdataclass_%s = %d%s\n", s, classnum, \
533 		       classnum != 255 ? "," : ""); \
534 		fprintf(stdout, "#define dns_rdataclass_%s\t" \
535 		       "((dns_rdataclass_t)dns_rdataclass_%s)\n", s, s); \
536 	} while (0)
537 
538 		for (cc = classes; cc != NULL; cc = cc->next) {
539 			if (cc->rdclass == 3)
540 				PRINTCLASS("chaos", 3);
541 			else if (cc->rdclass == 255)
542 				PRINTCLASS("none", 254);
543 			PRINTCLASS(cc->classname, cc->rdclass);
544 		}
545 
546 #undef PRINTCLASS
547 
548 		fprintf(stdout, "};\n\n");
549 		fprintf(stdout, "#endif /* DNS_ENUMCLASS_H */\n");
550 	} else if (structs) {
551 		if (prefix != NULL) {
552 			if ((fd = fopen(prefix,"r")) != NULL) {
553 				while (fgets(buf, sizeof(buf), fd) != NULL)
554 					fputs(buf, stdout);
555 				fclose(fd);
556 			}
557 		}
558 		for (tt = types; tt != NULL; tt = tt->next) {
559 			snprintf(buf, sizeof(buf), "%s/%s_%d.h",
560 				tt->dirname, tt->typename, tt->type);
561 			if ((fd = fopen(buf,"r")) != NULL) {
562 				while (fgets(buf, sizeof(buf), fd) != NULL)
563 					fputs(buf, stdout);
564 				fclose(fd);
565 			}
566 		}
567 		if (suffix != NULL) {
568 			if ((fd = fopen(suffix,"r")) != NULL) {
569 				while (fgets(buf, sizeof(buf), fd) != NULL)
570 					fputs(buf, stdout);
571 				fclose(fd);
572 			}
573 		}
574 	} else if (depend) {
575 		for (tt = types; tt != NULL; tt = tt->next)
576 			fprintf(stdout, "%s:\t%s/%s_%d.h\n", file,
577 				tt->dirname, tt->typename, tt->type);
578 	}
579 
580 	if (ferror(stdout) != 0)
581 		exit(1);
582 
583 	return (0);
584 }
585