1 /* $OpenBSD: parser.c,v 1.1 2017/04/10 13:35:42 florian Exp $ */ 2 3 /* 4 * Copyright (c) 2004 Esben Norby <norby@openbsd.org> 5 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <sys/types.h> 21 #include <sys/queue.h> 22 #include <sys/socket.h> 23 #include <netinet/in.h> 24 #include <arpa/inet.h> 25 26 #include <net/if.h> 27 #include <netinet/in.h> 28 #include <netinet/if_ether.h> 29 30 #include <err.h> 31 #include <errno.h> 32 #include <event.h> 33 #include <imsg.h> 34 #include <limits.h> 35 #include <stdio.h> 36 #include <stdlib.h> 37 #include <string.h> 38 39 #include "slaacd.h" 40 #include "parser.h" 41 42 enum token_type { 43 NOTOKEN, 44 ENDTOKEN, 45 INTERFACENAME, 46 KEYWORD 47 }; 48 49 struct token { 50 enum token_type type; 51 const char *keyword; 52 int value; 53 const struct token *next; 54 }; 55 56 static const struct token t_main[]; 57 static const struct token t_log[]; 58 static const struct token t_show[]; 59 static const struct token t_show_interface[]; 60 static const struct token t_send[]; 61 static const struct token t_send_sol[]; 62 63 static const struct token t_main[] = { 64 {KEYWORD, "show", SHOW, t_show}, 65 {KEYWORD, "log", NONE, t_log}, 66 {KEYWORD, "send", NONE, t_send}, 67 {ENDTOKEN, "", NONE, NULL} 68 }; 69 70 static const struct token t_log[] = { 71 {KEYWORD, "verbose", LOG_VERBOSE, NULL}, 72 {KEYWORD, "brief", LOG_BRIEF, NULL}, 73 {ENDTOKEN, "", NONE, NULL} 74 }; 75 76 static const struct token t_show[] = { 77 {KEYWORD, "interface", SHOW_INTERFACE, t_show_interface}, 78 {ENDTOKEN, "", NONE, NULL} 79 }; 80 81 static const struct token t_send[] = { 82 {KEYWORD, "solicitation", SEND_SOLICITATION, t_send_sol}, 83 {ENDTOKEN, "", NONE, NULL} 84 }; 85 static const struct token t_send_sol[] = { 86 {INTERFACENAME, "", SEND_SOLICITATION, NULL}, 87 {ENDTOKEN, "", NONE, NULL} 88 }; 89 90 static const struct token t_show_interface[] = { 91 {NOTOKEN, "", NONE, NULL}, 92 {INTERFACENAME, "", SHOW_INTERFACE, NULL}, 93 {ENDTOKEN, "", NONE, NULL} 94 }; 95 96 static const struct token *match_token(const char *, const struct token *, 97 struct parse_result *); 98 static void show_valid_args(const struct token *); 99 100 struct parse_result * 101 parse(int argc, char *argv[]) 102 { 103 static struct parse_result res; 104 const struct token *table = t_main; 105 const struct token *match; 106 107 memset(&res, 0, sizeof(res)); 108 109 while (argc >= 0) { 110 if ((match = match_token(argv[0], table, &res)) == NULL) { 111 fprintf(stderr, "valid commands/args:\n"); 112 show_valid_args(table); 113 return (NULL); 114 } 115 116 argc--; 117 argv++; 118 119 if (match->type == NOTOKEN || match->next == NULL) 120 break; 121 122 table = match->next; 123 } 124 125 if (argc > 0) { 126 fprintf(stderr, "superfluous argument: %s\n", argv[0]); 127 return (NULL); 128 } 129 130 return (&res); 131 } 132 133 static const struct token * 134 match_token(const char *word, const struct token *table, 135 struct parse_result *res) 136 { 137 u_int i, match; 138 const struct token *t = NULL; 139 140 match = 0; 141 142 for (i = 0; table[i].type != ENDTOKEN; i++) { 143 switch (table[i].type) { 144 case NOTOKEN: 145 if (word == NULL || strlen(word) == 0) { 146 match++; 147 t = &table[i]; 148 } 149 break; 150 case INTERFACENAME: 151 if (!match && word != NULL && strlen(word) > 0) { 152 if ((res->if_index = if_nametoindex(word)) == 0) 153 errx(1, "unknown interface"); 154 match++; 155 t = &table[i]; 156 if (t->value) 157 res->action = t->value; 158 } 159 break; 160 case KEYWORD: 161 if (word != NULL && strncmp(word, table[i].keyword, 162 strlen(word)) == 0) { 163 match++; 164 t = &table[i]; 165 if (t->value) 166 res->action = t->value; 167 } 168 break; 169 case ENDTOKEN: 170 break; 171 } 172 } 173 174 if (match != 1) { 175 if (word == NULL) 176 fprintf(stderr, "missing argument:\n"); 177 else if (match > 1) 178 fprintf(stderr, "ambiguous argument: %s\n", word); 179 else if (match < 1) 180 fprintf(stderr, "unknown argument: %s\n", word); 181 return (NULL); 182 } 183 184 return (t); 185 } 186 187 static void 188 show_valid_args(const struct token *table) 189 { 190 int i; 191 192 for (i = 0; table[i].type != ENDTOKEN; i++) { 193 switch (table[i].type) { 194 case NOTOKEN: 195 fprintf(stderr, " <cr>\n"); 196 break; 197 case INTERFACENAME: 198 fprintf(stderr, " <interface>\n"); 199 break; 200 case KEYWORD: 201 fprintf(stderr, " %s\n", table[i].keyword); 202 break; 203 case ENDTOKEN: 204 break; 205 } 206 } 207 } 208