1 /* $OpenBSD: parser.c,v 1.2 2004/01/29 12:02:13 henning Exp $ */ 2 3 /* 4 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> 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 THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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 OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <stdio.h> 20 #include <string.h> 21 22 #include "parser.h" 23 24 enum token_type { 25 NOTOKEN, 26 ENDTOKEN, 27 KEYWORD, 28 ADDRESS, 29 FLAG 30 }; 31 32 struct token { 33 enum token_type type; 34 const char *keyword; 35 int value; 36 const struct token *next; 37 }; 38 39 static const struct token t_main[]; 40 static const struct token t_show[]; 41 static const struct token t_show_fib[]; 42 static const struct token t_show_neighbor[]; 43 static const struct token t_show_neighbor_modifiers[]; 44 static const struct token t_fib[]; 45 static const struct token t_neighbor[]; 46 static const struct token t_neighbor_modifiers[]; 47 48 static const struct token t_main[] = { 49 { KEYWORD, "reload", RELOAD, NULL}, 50 { KEYWORD, "show", SHOW, t_show}, 51 { KEYWORD, "fib", FIB, t_fib}, 52 { KEYWORD, "neighbor", NEIGHBOR, t_neighbor}, 53 { ENDTOKEN, "", NONE, NULL} 54 }; 55 56 static const struct token t_show[] = { 57 { NOTOKEN, "", NONE, NULL}, 58 { KEYWORD, "fib", SHOW_FIB, t_show_fib}, 59 { KEYWORD, "interfaces", SHOW_INTERFACE, NULL}, 60 { KEYWORD, "neighbor", SHOW_NEIGHBOR, t_show_neighbor}, 61 { KEYWORD, "nexthop", SHOW_NEXTHOP, NULL}, 62 { KEYWORD, "summary", SHOW_SUMMARY, NULL}, 63 { ENDTOKEN, "", NONE, NULL} 64 }; 65 66 static const struct token t_show_fib[] = { 67 { NOTOKEN, "", NONE, NULL}, 68 { FLAG, "connected", F_CONNECTED, t_show_fib}, 69 { FLAG, "static", F_STATIC, t_show_fib}, 70 { FLAG, "bgp", F_BGPD_INSERTED, t_show_fib}, 71 { FLAG, "nexthop", F_NEXTHOP, t_show_fib}, 72 { ADDRESS, "", NONE, NULL}, 73 { ENDTOKEN, "", NONE, NULL} 74 }; 75 76 static const struct token t_show_neighbor[] = { 77 { NOTOKEN, "", NONE, NULL}, 78 { ADDRESS, "", NONE, t_show_neighbor_modifiers}, 79 { ENDTOKEN, "", NONE, NULL} 80 }; 81 82 static const struct token t_show_neighbor_modifiers[] = { 83 { NOTOKEN, "", NONE, NULL}, 84 { KEYWORD, "timers", SHOW_NEIGHBOR_TIMERS, NULL}, 85 { KEYWORD, "messages", SHOW_NEIGHBOR, NULL}, 86 { ENDTOKEN, "", NONE, NULL} 87 }; 88 89 static const struct token t_fib[] = { 90 { KEYWORD, "couple", FIB_COUPLE, NULL}, 91 { KEYWORD, "decouple", FIB_DECOUPLE, NULL}, 92 { ENDTOKEN, "", NONE, NULL} 93 }; 94 95 static const struct token t_neighbor[] = { 96 { ADDRESS, "", NONE, t_neighbor_modifiers}, 97 { ENDTOKEN, "", NONE, NULL} 98 }; 99 100 static const struct token t_neighbor_modifiers[] = { 101 { KEYWORD, "up", NEIGHBOR_UP, NULL}, 102 { KEYWORD, "down", NEIGHBOR_DOWN, NULL}, 103 { ENDTOKEN, "", NONE, NULL} 104 }; 105 106 static struct parse_result res; 107 108 const struct token *match_token(const char *, const struct token []); 109 void show_valid_args(const struct token []); 110 int parse_addr(const char *, struct bgpd_addr *); 111 112 struct parse_result * 113 parse(int argc, char *argv[]) 114 { 115 int curarg = 1; 116 const struct token *table = t_main; 117 const struct token *match; 118 char *word; 119 120 bzero(&res, sizeof(res)); 121 if (argc == 1) 122 return (&res); 123 124 for (;;) { 125 if (argc > curarg) 126 word = argv[curarg]; 127 else 128 word = NULL; 129 130 if ((match = match_token(word, table)) == NULL) { 131 fprintf(stderr, "valid commands/args:\n"); 132 show_valid_args(table); 133 return (NULL); 134 } 135 136 curarg++; 137 138 if (match->type == NOTOKEN) 139 break; 140 141 if (match->next == NULL) 142 break; 143 144 table = match->next; 145 } 146 147 if (curarg < argc) { 148 fprintf(stderr, "superflous argument: %s\n", argv[curarg]); 149 return (NULL); 150 } 151 152 return (&res); 153 } 154 155 const struct token * 156 match_token(const char *word, const struct token table[]) 157 { 158 u_int i, match; 159 const struct token *t = NULL; 160 161 match = 0; 162 163 for (i = 0; table[i].type != ENDTOKEN; i++) { 164 switch (table[i].type) { 165 case NOTOKEN: 166 if (word == NULL || strlen(word) == 0) { 167 match++; 168 t = &table[i]; 169 } 170 break; 171 case KEYWORD: 172 if (word != NULL && strncmp(word, table[i].keyword, 173 strlen(word)) == 0) { 174 match++; 175 t = &table[i]; 176 if (t->value) 177 res.action = t->value; 178 } 179 break; 180 case FLAG: 181 if (word != NULL && strncmp(word, table[i].keyword, 182 strlen(word)) == 0) { 183 match++; 184 t = &table[i]; 185 res.flags |= t->value; 186 } 187 break; 188 case ADDRESS: 189 if (parse_addr(word, &res.addr)) { 190 match++; 191 t = &table[i]; 192 if (t->value) 193 res.action = t->value; 194 } 195 break; 196 case ENDTOKEN: 197 break; 198 } 199 } 200 201 if (match != 1) { 202 if (match > 1) 203 fprintf(stderr, "ambiguous argument: %s\n", word); 204 if (match < 1) 205 fprintf(stderr, "unknown argument: %s\n", word); 206 return (NULL); 207 } 208 209 return (t); 210 } 211 212 void 213 show_valid_args(const struct token table[]) 214 { 215 int i; 216 217 for (i = 0; table[i].type != ENDTOKEN; i++) { 218 switch (table[i].type) { 219 case NONE: 220 fprintf(stderr, " (nothing)\n"); 221 break; 222 case KEYWORD: 223 case FLAG: 224 fprintf(stderr, " %s\n", table[i].keyword); 225 break; 226 case ADDRESS: 227 fprintf(stderr, " <address>\n"); 228 break; 229 case ENDTOKEN: 230 break; 231 } 232 } 233 } 234 235 int 236 parse_addr(const char *word, struct bgpd_addr *addr) 237 { 238 struct in_addr ina; 239 240 if (word == NULL) 241 return (0); 242 243 bzero(addr, sizeof(struct bgpd_addr)); 244 bzero(&ina, sizeof(ina)); 245 246 if (inet_pton(AF_INET, word, &ina)) { 247 addr->af = AF_INET; 248 addr->v4 = ina; 249 return (1); 250 } 251 252 return (0); 253 } 254