1 1.1 christos /* $NetBSD: keama.c,v 1.3 2022/04/03 01:10:59 christos Exp $ */ 2 1.1 christos 3 1.1 christos /* 4 1.3 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.3 christos * PO Box 360 20 1.3 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.3 2022/04/03 01:10:59 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.3 christos enum resolve resolve; 56 1.3 christos struct parses parses; 57 1.3 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.3 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.3 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.3 christos 210 1.1 christos snprintf(fbuf, sizeof(fbuf), "%s line %d: %s", 211 1.1 christos cfile->tlname, cfile->lexline, fmt); 212 1.3 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