1 /* $NetBSD: keama.c,v 1.3 2022/04/03 01:10:59 christos Exp $ */
2
3 /*
4 * Copyright(C) 2017-2022 Internet Systems Consortium, Inc.("ISC")
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
16 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 *
18 * Internet Systems Consortium, Inc.
19 * PO Box 360
20 * Newmarket, NH 03857 USA
21 * <info@isc.org>
22 * https://www.isc.org/
23 *
24 */
25
26 #include <sys/cdefs.h>
27 __RCSID("$NetBSD: keama.c,v 1.3 2022/04/03 01:10:59 christos Exp $");
28
29 #include <sys/errno.h>
30 #include <arpa/inet.h>
31 #include <assert.h>
32 #include <fcntl.h>
33 #include <stdarg.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <unistd.h>
37
38 #include "keama.h"
39
40 #define KEAMA_USAGE "Usage: keama [-4|-6] [-D] [-N]" \
41 " [-r {perform|fatal|pass}\\n" \
42 " [-l hook-library-path]" \
43 " [-i input-file] [-o output-file]\n"
44
45 static void
usage(const char * sfmt,const char * sarg)46 usage(const char *sfmt, const char *sarg) {
47 if (sfmt != NULL) {
48 fprintf(stderr, sfmt, sarg);
49 fprintf(stderr, "\n");
50 }
51 fputs(KEAMA_USAGE, stderr);
52 exit(1);
53 }
54
55 enum resolve resolve;
56 struct parses parses;
57
58 int local_family = 0;
59 char *hook_library_path = NULL;
60 char *input_file = NULL;
61 char *output_file = NULL;
62 FILE *input = NULL;
63 FILE *output = NULL;
64 isc_boolean_t use_isc_lifetimes = ISC_FALSE;
65 isc_boolean_t global_hr = ISC_TRUE;
66 isc_boolean_t json = ISC_FALSE;
67
68 static const char use_noarg[] = "No argument for command: %s";
69 static const char bad_resolve[] = "Bad -r argument: %s";
70
71 int
main(int argc,char ** argv)72 main(int argc, char **argv) {
73 int i, fd;
74 char *inbuf = NULL;
75 size_t oldsize = 0;
76 size_t newsize = 0;
77 ssize_t cc;
78 struct parse *cfile;
79 size_t cnt = 0;
80
81 for (i = 1; i < argc; i++) {
82 if (strcmp(argv[i], "-4") == 0)
83 local_family = AF_INET;
84 else if (strcmp(argv[i], "-6") == 0)
85 local_family = AF_INET6;
86 else if (strcmp(argv[i], "-D") == 0)
87 use_isc_lifetimes = ISC_TRUE;
88 else if (strcmp(argv[i], "-N") == 0)
89 global_hr = ISC_FALSE;
90 else if (strcmp(argv[i], "-T") == 0)
91 json = ISC_TRUE;
92 else if (strcmp(argv[i], "-r") == 0) {
93 if (++i == argc)
94 usage(use_noarg, argv[i - 1]);
95 if (strcmp(argv[i], "perform") == 0)
96 resolve = perform;
97 else if (strcmp(argv[i], "fatal") == 0)
98 resolve = fatal;
99 else if (strcmp(argv[i], "pass") == 0)
100 resolve = pass;
101 else
102 usage(bad_resolve, argv[i]);
103 } else if (strcmp(argv[i], "-l") == 0) {
104 if (++i == argc)
105 usage(use_noarg, argv[i - 1]);
106 hook_library_path = argv[i];
107 } else if (strcmp(argv[i], "-i") == 0) {
108 if (++i == argc)
109 usage(use_noarg, argv[i - 1]);
110 input_file = argv[i];
111 } else if (strcmp(argv[i], "-o") == 0) {
112 if (++i == argc)
113 usage(use_noarg, argv[i - 1]);
114 output_file = argv[i];
115 } else
116 usage("Unknown command: %s", argv[i]);
117 }
118
119 if (!json && (local_family == 0))
120 usage("address family must be set using %s", "-4 or -6");
121
122 if (input_file == NULL) {
123 input_file = "--stdin--";
124 fd = fileno(stdin);
125 for (;;) {
126 if (newsize == 0)
127 newsize = 1024;
128 else {
129 oldsize = newsize;
130 newsize *= 4;
131 }
132 inbuf = (char *)realloc(inbuf, newsize);
133 if (inbuf == 0)
134 usage("out of memory reading standard "
135 "input: %s", strerror(errno));
136 cc = read(fd, inbuf + oldsize, newsize - oldsize);
137 if (cc < 0)
138 usage("error reading standard input: %s",
139 strerror(errno));
140 if (cc + oldsize < newsize) {
141 newsize = cc + oldsize;
142 break;
143 }
144 }
145 } else {
146 fd = open(input_file, O_RDONLY);
147 if (fd < 0)
148 usage("Cannot open '%s' for reading", input_file);
149 }
150
151 if (output_file) {
152 output = fopen(output_file, "w");
153 if (output == NULL)
154 usage("Cannot open '%s' for writing", output_file);
155 } else
156 output = stdout;
157
158 TAILQ_INIT(&parses);
159 cfile = new_parse(fd, inbuf, newsize, input_file, 0);
160 assert(cfile != NULL);
161
162 if (json) {
163 struct element *elem;
164
165 elem = json_parse(cfile);
166 if (elem != NULL) {
167 print(output, elem, 0, 0);
168 fprintf(output, "\n");
169 }
170 } else {
171 spaces_init();
172 options_init();
173 cnt = conf_file_parse(cfile);
174 if (cfile->stack_top > 0) {
175 print(output, cfile->stack[0], 0, 0);
176 fprintf(output, "\n");
177 }
178 }
179
180 end_parse(cfile);
181
182 exit(cnt);
183 }
184
185 void
stackPush(struct parse * pc,struct element * elem)186 stackPush(struct parse *pc, struct element *elem)
187 {
188 if (pc->stack_top + 2 >= pc->stack_size) {
189 size_t new_size = pc->stack_size + 10;
190 size_t amount = new_size * sizeof(struct element *);
191
192 pc->stack = (struct element **)realloc(pc->stack, amount);
193 if (pc->stack == NULL)
194 parse_error(pc, "can't resize element stack");
195 pc->stack_size = new_size;
196 }
197 pc->stack_top++;
198 pc->stack[pc->stack_top] = elem;
199 }
200
201 void
parse_error(struct parse * cfile,const char * fmt,...)202 parse_error(struct parse *cfile, const char *fmt, ...)
203 {
204 va_list list;
205 char lexbuf[256];
206 char mbuf[1024];
207 char fbuf[1024];
208 unsigned i, lix;
209
210 snprintf(fbuf, sizeof(fbuf), "%s line %d: %s",
211 cfile->tlname, cfile->lexline, fmt);
212
213 va_start(list, fmt);
214 vsnprintf(mbuf, sizeof(mbuf), fbuf, list);
215 va_end(list);
216
217 lix = 0;
218 for (i = 0;
219 cfile->token_line[i] && i < (cfile->lexchar - 1); i++) {
220 if (lix < sizeof(lexbuf) - 1)
221 lexbuf[lix++] = ' ';
222 if (cfile->token_line[i] == '\t') {
223 for (; lix < (sizeof lexbuf) - 1 && (lix & 7); lix++)
224 lexbuf[lix] = ' ';
225 }
226 }
227 lexbuf[lix] = 0;
228
229 fprintf(stderr, "%s\n%s\n", mbuf, cfile->token_line);
230 if (cfile->lexchar < 81)
231 fprintf(stderr, "%s^\n", lexbuf);
232 exit(-1);
233 }
234