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