keama.c revision 1.1 1 1.1 christos /* $NetBSD: keama.c,v 1.1 2020/08/03 21:09:08 christos Exp $ */
2 1.1 christos
3 1.1 christos /*
4 1.1 christos * Copyright(c) 2017-2019 by 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 christos * 950 Charter Street
20 1.1 christos * Redwood City, CA 94063
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 2020/08/03 21:09:08 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 christos int local_family = 0;
56 1.1 christos char *hook_library_path = NULL;
57 1.1 christos char *input_file = NULL;
58 1.1 christos char *output_file = NULL;
59 1.1 christos FILE *input = NULL;
60 1.1 christos FILE *output = NULL;
61 1.1 christos isc_boolean_t use_isc_lifetimes = ISC_FALSE;
62 1.1 christos isc_boolean_t global_hr = ISC_TRUE;
63 1.1 christos isc_boolean_t json = ISC_FALSE;
64 1.1 christos
65 1.1 christos static const char use_noarg[] = "No argument for command: %s";
66 1.1 christos static const char bad_resolve[] = "Bad -r argument: %s";
67 1.1 christos
68 1.1 christos int
69 1.1 christos main(int argc, char **argv) {
70 1.1 christos int i, fd;
71 1.1 christos char *inbuf = NULL;
72 1.1 christos size_t oldsize = 0;
73 1.1 christos size_t newsize = 0;
74 1.1 christos ssize_t cc;
75 1.1 christos struct parse *cfile;
76 1.1 christos size_t cnt = 0;
77 1.1 christos
78 1.1 christos for (i = 1; i < argc; i++) {
79 1.1 christos if (strcmp(argv[i], "-4") == 0)
80 1.1 christos local_family = AF_INET;
81 1.1 christos else if (strcmp(argv[i], "-6") == 0)
82 1.1 christos local_family = AF_INET6;
83 1.1 christos else if (strcmp(argv[i], "-D") == 0)
84 1.1 christos use_isc_lifetimes = ISC_TRUE;
85 1.1 christos else if (strcmp(argv[i], "-N") == 0)
86 1.1 christos global_hr = ISC_FALSE;
87 1.1 christos else if (strcmp(argv[i], "-T") == 0)
88 1.1 christos json = ISC_TRUE;
89 1.1 christos else if (strcmp(argv[i], "-r") == 0) {
90 1.1 christos if (++i == argc)
91 1.1 christos usage(use_noarg, argv[i - 1]);
92 1.1 christos if (strcmp(argv[i], "perform") == 0)
93 1.1 christos resolve = perform;
94 1.1 christos else if (strcmp(argv[i], "fatal") == 0)
95 1.1 christos resolve = fatal;
96 1.1 christos else if (strcmp(argv[i], "pass") == 0)
97 1.1 christos resolve = pass;
98 1.1 christos else
99 1.1 christos usage(bad_resolve, argv[i]);
100 1.1 christos } else if (strcmp(argv[i], "-l") == 0) {
101 1.1 christos if (++i == argc)
102 1.1 christos usage(use_noarg, argv[i - 1]);
103 1.1 christos hook_library_path = argv[i];
104 1.1 christos } else if (strcmp(argv[i], "-i") == 0) {
105 1.1 christos if (++i == argc)
106 1.1 christos usage(use_noarg, argv[i - 1]);
107 1.1 christos input_file = argv[i];
108 1.1 christos } else if (strcmp(argv[i], "-o") == 0) {
109 1.1 christos if (++i == argc)
110 1.1 christos usage(use_noarg, argv[i - 1]);
111 1.1 christos output_file = argv[i];
112 1.1 christos } else
113 1.1 christos usage("Unknown command: %s", argv[i]);
114 1.1 christos }
115 1.1 christos
116 1.1 christos if (!json && (local_family == 0))
117 1.1 christos usage("address family must be set using %s", "-4 or -6");
118 1.1 christos
119 1.1 christos if (input_file == NULL) {
120 1.1 christos input_file = "--stdin--";
121 1.1 christos fd = fileno(stdin);
122 1.1 christos for (;;) {
123 1.1 christos if (newsize == 0)
124 1.1 christos newsize = 1024;
125 1.1 christos else {
126 1.1 christos oldsize = newsize;
127 1.1 christos newsize *= 4;
128 1.1 christos }
129 1.1 christos inbuf = (char *)realloc(inbuf, newsize);
130 1.1 christos if (inbuf == 0)
131 1.1 christos usage("out of memory reading standard "
132 1.1 christos "input: %s", strerror(errno));
133 1.1 christos cc = read(fd, inbuf + oldsize, newsize - oldsize);
134 1.1 christos if (cc < 0)
135 1.1 christos usage("error reading standard input: %s",
136 1.1 christos strerror(errno));
137 1.1 christos if (cc + oldsize < newsize) {
138 1.1 christos newsize = cc + oldsize;
139 1.1 christos break;
140 1.1 christos }
141 1.1 christos }
142 1.1 christos } else {
143 1.1 christos fd = open(input_file, O_RDONLY);
144 1.1 christos if (fd < 0)
145 1.1 christos usage("Cannot open '%s' for reading", input_file);
146 1.1 christos }
147 1.1 christos
148 1.1 christos if (output_file) {
149 1.1 christos output = fopen(output_file, "w");
150 1.1 christos if (output == NULL)
151 1.1 christos usage("Cannot open '%s' for writing", output_file);
152 1.1 christos } else
153 1.1 christos output = stdout;
154 1.1 christos
155 1.1 christos TAILQ_INIT(&parses);
156 1.1 christos cfile = new_parse(fd, inbuf, newsize, input_file, 0);
157 1.1 christos assert(cfile != NULL);
158 1.1 christos
159 1.1 christos if (json) {
160 1.1 christos struct element *elem;
161 1.1 christos
162 1.1 christos elem = json_parse(cfile);
163 1.1 christos if (elem != NULL) {
164 1.1 christos print(output, elem, 0, 0);
165 1.1 christos fprintf(output, "\n");
166 1.1 christos }
167 1.1 christos } else {
168 1.1 christos spaces_init();
169 1.1 christos options_init();
170 1.1 christos cnt = conf_file_parse(cfile);
171 1.1 christos if (cfile->stack_top > 0) {
172 1.1 christos print(output, cfile->stack[0], 0, 0);
173 1.1 christos fprintf(output, "\n");
174 1.1 christos }
175 1.1 christos }
176 1.1 christos
177 1.1 christos end_parse(cfile);
178 1.1 christos
179 1.1 christos exit(cnt);
180 1.1 christos }
181 1.1 christos
182 1.1 christos void
183 1.1 christos stackPush(struct parse *pc, struct element *elem)
184 1.1 christos {
185 1.1 christos if (pc->stack_top + 2 >= pc->stack_size) {
186 1.1 christos size_t new_size = pc->stack_size + 10;
187 1.1 christos size_t amount = new_size * sizeof(struct element *);
188 1.1 christos
189 1.1 christos pc->stack = (struct element **)realloc(pc->stack, amount);
190 1.1 christos if (pc->stack == NULL)
191 1.1 christos parse_error(pc, "can't resize element stack");
192 1.1 christos pc->stack_size = new_size;
193 1.1 christos }
194 1.1 christos pc->stack_top++;
195 1.1 christos pc->stack[pc->stack_top] = elem;
196 1.1 christos }
197 1.1 christos
198 1.1 christos void
199 1.1 christos parse_error(struct parse *cfile, const char *fmt, ...)
200 1.1 christos {
201 1.1 christos va_list list;
202 1.1 christos char lexbuf[256];
203 1.1 christos char mbuf[1024];
204 1.1 christos char fbuf[1024];
205 1.1 christos unsigned i, lix;
206 1.1 christos
207 1.1 christos snprintf(fbuf, sizeof(fbuf), "%s line %d: %s",
208 1.1 christos cfile->tlname, cfile->lexline, fmt);
209 1.1 christos
210 1.1 christos va_start(list, fmt);
211 1.1 christos vsnprintf(mbuf, sizeof(mbuf), fbuf, list);
212 1.1 christos va_end(list);
213 1.1 christos
214 1.1 christos lix = 0;
215 1.1 christos for (i = 0;
216 1.1 christos cfile->token_line[i] && i < (cfile->lexchar - 1); i++) {
217 1.1 christos if (lix < sizeof(lexbuf) - 1)
218 1.1 christos lexbuf[lix++] = ' ';
219 1.1 christos if (cfile->token_line[i] == '\t') {
220 1.1 christos for (; lix < (sizeof lexbuf) - 1 && (lix & 7); lix++)
221 1.1 christos lexbuf[lix] = ' ';
222 1.1 christos }
223 1.1 christos }
224 1.1 christos lexbuf[lix] = 0;
225 1.1 christos
226 1.1 christos fprintf(stderr, "%s\n%s\n", mbuf, cfile->token_line);
227 1.1 christos if (cfile->lexchar < 81)
228 1.1 christos fprintf(stderr, "%s^\n", lexbuf);
229 1.1 christos exit(-1);
230 1.1 christos }
231