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