]> git.proxmox.com Git - mirror_frr.git/blame - lib/command_parse.y
lib: Fix memory leak in ipv6_prefix_match
[mirror_frr.git] / lib / command_parse.y
CommitLineData
9d0662e0 1/*
1ab84bf3 2 * Command format string parser for CLI backend.
9d0662e0 3 *
1ab84bf3
QY
4 * --
5 * Copyright (C) 2015 Cumulus Networks, Inc.
9d0662e0 6 *
1ab84bf3
QY
7 * This file is part of GNU Zebra.
8 *
9 * GNU Zebra is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2, or (at your option) any
12 * later version.
13 *
14 * GNU Zebra is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with GNU Zebra; see the file COPYING. If not, write to the Free
21 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
22 * 02111-1307, USA.
9d0662e0
QY
23 */
24
92055a92 25%{
1ab84bf3
QY
26// compile with debugging facilities
27#define YYDEBUG 1
51fc9379 28%}
782d9789 29
51fc9379
QY
30/* names for generated header and parser files */
31%defines "command_parse.h"
32%output "command_parse.c"
5a8bbed0 33
51fc9379 34/* required external units */
eceb1066
QY
35%code requires {
36 #include "command.h"
7a6ded40 37 #include "graph.h"
5a5d576b 38 #include "memory.h"
1eb5e8dc 39 #include "grammar_sandbox.h"
51fc9379
QY
40
41 extern int
1ab84bf3 42 yylex (void);
51fc9379 43
eceb1066 44 extern void
4427e9b3
QY
45 set_lexer_string (const char *);
46
47 extern void
48 cleanup_lexer (void);
51fc9379
QY
49}
50
51/* functionality this unit exports */
52%code provides {
1eb5e8dc 53 void
7a6ded40 54 command_parse_format (struct graph *, struct cmd_element *);
92055a92 55
51fc9379
QY
56 /* maximum length of a number, lexer will not match anything longer */
57 #define DECIMAL_STRLEN_MAX 20
58}
eceb1066 59
51fc9379
QY
60/* valid semantic types for tokens and rules */
61%union {
62 long long number;
92055a92 63 char *string;
782d9789 64 struct graph_node *node;
92055a92
QY
65}
66
51fc9379 67/* union types for lexed tokens */
5a5d576b
QY
68%token <string> WORD
69%token <string> IPV4
70%token <string> IPV4_PREFIX
71%token <string> IPV6
72%token <string> IPV6_PREFIX
73%token <string> VARIABLE
74%token <string> RANGE
51fc9379 75%token <number> NUMBER
782d9789 76
51fc9379 77/* union types for parsed rules */
782d9789
QY
78%type <node> start
79%type <node> sentence_root
782d9789
QY
80%type <node> literal_token
81%type <node> placeholder_token
782d9789 82%type <node> option
478bdaeb
QY
83%type <node> option_token
84%type <node> option_token_seq
782d9789 85%type <node> selector
340a2b4a 86%type <node> selector_element_root
478bdaeb 87%type <node> selector_token
782d9789 88%type <node> selector_token_seq
782d9789 89
51fc9379
QY
90%code {
91 /* bison declarations */
92 void
1eb5e8dc 93 yyerror (struct graph *, struct cmd_element *el, char const *msg);
51fc9379
QY
94
95 /* state variables for a single parser run */
1eb5e8dc
QY
96 struct graph_node *startnode; // start node of DFA
97
51fc9379
QY
98 struct graph_node *currnode, // current position in DFA
99 *seqhead; // sequence head
100
101 struct graph_node *optnode_start, // start node for option set
102 *optnode_end; // end node for option set
103
104 struct graph_node *selnode_start, // start node for selector set
105 *selnode_end; // end node for selector set
106
107 char *docstr_start, *docstr; // pointers to copy of command docstring
108
109 /* helper functions for parser */
110 static char *
7a6ded40 111 doc_next (void);
51fc9379
QY
112
113 static struct graph_node *
1eb5e8dc 114 node_adjacent (struct graph_node *, struct graph_node *);
51fc9379
QY
115
116 static struct graph_node *
1eb5e8dc 117 add_edge_dedup (struct graph_node *, struct graph_node *);
51fc9379
QY
118
119 static int
1eb5e8dc
QY
120 cmp_token (struct cmd_token_t *, struct cmd_token_t *);
121
122 static struct graph_node *
123 new_token_node (struct graph *,
124 enum cmd_token_type_t type,
125 char *text, char *doc);
51fc9379
QY
126
127 static void
1eb5e8dc 128 terminate_graph (struct graph *,
51fc9379
QY
129 struct graph_node *,
130 struct cmd_element *);
131
132 static void
1ab84bf3 133 cleanup (void);
51fc9379
QY
134}
135
136/* yyparse parameters */
7a6ded40 137%parse-param { struct graph *graph }
1eb5e8dc 138%parse-param { struct cmd_element *element }
51fc9379
QY
139
140/* called automatically before yyparse */
141%initial-action {
1eb5e8dc
QY
142 startnode = vector_slot (graph->nodes, 0);
143
51fc9379
QY
144 /* clear state pointers */
145 seqhead = NULL;
146 currnode = NULL;
147 selnode_start = selnode_end = NULL;
148 optnode_start = optnode_end = NULL;
149
150 /* set string to parse */
4427e9b3 151 set_lexer_string (element->string);
51fc9379
QY
152
153 /* copy docstring and keep a pointer to the copy */
154 docstr = element->doc ? XSTRDUP(MTYPE_TMP, element->doc) : NULL;
155 docstr_start = docstr;
156}
92055a92 157
92055a92
QY
158%%
159
88255c7c
QY
160start:
161 sentence_root cmd_token_seq
880e24a1 162{
51fc9379 163 // tack on the command element
1eb5e8dc 164 terminate_graph (graph, currnode, element);
880e24a1 165}
88255c7c
QY
166| sentence_root cmd_token_seq '.' placeholder_token
167{
1eb5e8dc
QY
168 if ((currnode = add_edge_dedup (currnode, $4)) != $4)
169 graph_delete_node (graph, $4);
88255c7c 170
1ab84bf3
QY
171 // adding a node as a child of itself accepts any number
172 // of the same token, which is what we want for varags
1eb5e8dc 173 add_edge_dedup (currnode, currnode);
88255c7c 174
51fc9379 175 // tack on the command element
1eb5e8dc 176 terminate_graph (graph, currnode, element);
88255c7c 177}
92055a92 178
2a23ca6e 179sentence_root: WORD
478bdaeb 180{
7a6ded40 181 struct graph_node *root =
1eb5e8dc 182 new_token_node (graph, WORD_TKN, XSTRDUP(MTYPE_CMD_TOKENS, $1), doc_next());
5a5d576b 183
1eb5e8dc
QY
184 if ((currnode = add_edge_dedup (startnode, root)) != root)
185 graph_delete_node (graph, root);
4b0abf24 186
5a5d576b
QY
187 free ($1);
188 $$ = currnode;
478bdaeb 189};
92055a92 190
782d9789
QY
191cmd_token:
192 placeholder_token
5a5d576b 193{
1eb5e8dc
QY
194 if ((currnode = add_edge_dedup (currnode, $1)) != $1)
195 graph_delete_node (graph, $1);
5a5d576b 196}
782d9789 197| literal_token
5a5d576b 198{
1eb5e8dc
QY
199 if ((currnode = add_edge_dedup (currnode, $1)) != $1)
200 graph_delete_node (graph, $1);
5a5d576b 201}
478bdaeb 202/* selectors and options are subgraphs with start and end nodes */
782d9789 203| selector
478bdaeb 204{
7a6ded40 205 graph_add_edge (currnode, $1);
478bdaeb
QY
206 currnode = selnode_end;
207 selnode_start = selnode_end = NULL;
208}
782d9789 209| option
478bdaeb 210{
7a6ded40 211 graph_add_edge (currnode, $1);
478bdaeb
QY
212 currnode = optnode_end;
213 optnode_start = optnode_end = NULL;
214}
782d9789 215;
92055a92 216
782d9789
QY
217cmd_token_seq:
218 %empty
219| cmd_token_seq cmd_token
220;
221
222placeholder_token:
478bdaeb 223 IPV4
4b0abf24 224{
1eb5e8dc 225 $$ = new_token_node (graph, IPV4_TKN, XSTRDUP(MTYPE_CMD_TOKENS, $1), doc_next());
5a5d576b 226 free ($1);
4b0abf24 227}
478bdaeb 228| IPV4_PREFIX
340a2b4a 229{
1eb5e8dc 230 $$ = new_token_node (graph, IPV4_PREFIX_TKN, XSTRDUP(MTYPE_CMD_TOKENS, $1), doc_next());
5a5d576b 231 free ($1);
4b0abf24 232}
478bdaeb 233| IPV6
340a2b4a 234{
1eb5e8dc 235 $$ = new_token_node (graph, IPV6_TKN, XSTRDUP(MTYPE_CMD_TOKENS, $1), doc_next());
5a5d576b 236 free ($1);
4b0abf24 237}
478bdaeb 238| IPV6_PREFIX
340a2b4a 239{
1eb5e8dc 240 $$ = new_token_node (graph, IPV6_PREFIX_TKN, XSTRDUP(MTYPE_CMD_TOKENS, $1), doc_next());
5a5d576b 241 free ($1);
4b0abf24 242}
478bdaeb 243| VARIABLE
340a2b4a 244{
1eb5e8dc 245 $$ = new_token_node (graph, VARIABLE_TKN, XSTRDUP(MTYPE_CMD_TOKENS, $1), doc_next());
5a5d576b 246 free ($1);
4b0abf24 247}
478bdaeb
QY
248| RANGE
249{
1eb5e8dc
QY
250 $$ = new_token_node (graph, RANGE_TKN, XSTRDUP(MTYPE_CMD_TOKENS, $1), doc_next());
251 struct cmd_token_t *token = $$->data;
478bdaeb
QY
252
253 // get the numbers out
b3899769 254 yylval.string++;
7a6ded40 255 token->min = strtoll (yylval.string, &yylval.string, 10);
ef955a80 256 strsep (&yylval.string, "-");
7a6ded40 257 token->max = strtoll (yylval.string, &yylval.string, 10);
ef955a80
QY
258
259 // validate range
1eb5e8dc 260 if (token->min >= token->max) yyerror (graph, element, "Invalid range.");
5a5d576b
QY
261
262 free ($1);
478bdaeb 263}
782d9789
QY
264;
265
266literal_token:
478bdaeb
QY
267 WORD
268{
1eb5e8dc 269 $$ = new_token_node (graph, WORD_TKN, XSTRDUP(MTYPE_CMD_TOKENS, $1), doc_next());
5a5d576b 270 free ($1);
478bdaeb
QY
271}
272| NUMBER
273{
1eb5e8dc
QY
274 $$ = new_token_node (graph, NUMBER_TKN, NULL, doc_next());
275 struct cmd_token_t *token = $$->data;
7a6ded40
QY
276
277 token->value = yylval.number;
278 token->text = XCALLOC(MTYPE_CMD_TOKENS, DECIMAL_STRLEN_MAX+1);
279 snprintf(token->text, DECIMAL_STRLEN_MAX, "%lld", token->value);
478bdaeb 280}
782d9789 281;
92055a92 282
4b0abf24 283/* <selector|set> productions */
51fc9379 284selector: '<' selector_part '>'
2a23ca6e 285{
478bdaeb
QY
286 // all the graph building is done in selector_element,
287 // so just return the selector subgraph head
288 $$ = selnode_start;
2a23ca6e 289};
782d9789
QY
290
291selector_part:
2a23ca6e 292 selector_part '|' selector_element
f4b0c72e 293| selector_element '|' selector_element
782d9789
QY
294;
295
51fc9379 296selector_element: selector_element_root selector_token_seq
478bdaeb
QY
297{
298 // if the selector start and end do not exist, create them
7a6ded40
QY
299 if (!selnode_start || !selnode_end) {
300 assert(!selnode_start && !selnode_end);
1eb5e8dc
QY
301 selnode_start = new_token_node (graph, SELECTOR_TKN, NULL, NULL);
302 selnode_end = new_token_node (graph, NUL_TKN, NULL, NULL);
478bdaeb
QY
303 }
304
305 // add element head as a child of the selector
7a6ded40 306 graph_add_edge (selnode_start, $1);
478bdaeb 307
d8074cc0
QY
308 if ($2) {
309 graph_add_edge ($1, seqhead); // tack on selector_token_seq
310 graph_add_edge ($2, selnode_end); // $2 is the sequence tail
478bdaeb
QY
311 }
312 else
7a6ded40 313 graph_add_edge ($1, selnode_end);
478bdaeb
QY
314
315 seqhead = NULL;
316}
782d9789
QY
317
318selector_token_seq:
d8074cc0 319 %empty { $$ = NULL; }
2a23ca6e
QY
320| selector_token_seq selector_token
321{
1eb5e8dc 322 // if the sequence component is NUL_TKN, this is a sequence start
d8074cc0 323 if (!$1) {
1eb5e8dc 324 assert(!seqhead);
478bdaeb
QY
325 seqhead = $2;
326 }
327 else // chain on new node
7a6ded40 328 graph_add_edge ($1, $2);
478bdaeb
QY
329
330 $$ = $2;
2a23ca6e 331}
782d9789
QY
332;
333
340a2b4a 334selector_element_root:
782d9789
QY
335 literal_token
336| placeholder_token
478bdaeb
QY
337;
338
339selector_token:
340a2b4a 340 selector_element_root
782d9789 341;
92055a92
QY
342
343/* [option|set] productions */
2a23ca6e 344option: '[' option_part ']'
4b0abf24
QY
345{
346 // add null path
7a6ded40 347 graph_add_edge (optnode_start, optnode_end);
4b0abf24
QY
348 $$ = optnode_start;
349};
782d9789
QY
350
351option_part:
478bdaeb
QY
352 option_part '|' option_element
353| option_element
782d9789
QY
354;
355
478bdaeb
QY
356option_element:
357 option_token_seq
2a23ca6e 358{
478bdaeb
QY
359 if (!optnode_start || !optnode_end) {
360 assert(!optnode_start && !optnode_end);
1eb5e8dc
QY
361 optnode_start = new_token_node (graph, OPTION_TKN, NULL, NULL);
362 optnode_end = new_token_node (graph, NUL_TKN, NULL, NULL);
478bdaeb
QY
363 }
364
7a6ded40
QY
365 graph_add_edge (optnode_start, seqhead);
366 graph_add_edge ($1, optnode_end);
4427e9b3 367 seqhead = NULL;
2a23ca6e 368}
478bdaeb
QY
369
370option_token_seq:
371 option_token
372{ $$ = seqhead = $1; }
373| option_token_seq option_token
7a6ded40 374{ $$ = graph_add_edge ($1, $2); }
782d9789
QY
375;
376
377option_token:
378 literal_token
379| placeholder_token
380;
381
92055a92 382%%
4b0abf24 383
1eb5e8dc
QY
384void
385command_parse_format (struct graph *graph, struct cmd_element *cmd)
51fc9379 386{
1ab84bf3 387 // set to 1 to enable parser traces
51fc9379
QY
388 yydebug = 0;
389
390 // parse command into DFA
1eb5e8dc 391 yyparse (graph, cmd);
07079d78 392
7a6ded40 393 // cleanup
07079d78 394 cleanup ();
51fc9379
QY
395}
396
397/* parser helper functions */
398
399void
1eb5e8dc 400yyerror (struct graph *graph, struct cmd_element *el, char const *msg)
51fc9379 401{
1ab84bf3
QY
402 zlog_err ("%s: FATAL parse error: %s", __func__, msg);
403 zlog_err ("while parsing this command definition: \n\t%s\n", el->string);
5a8bbed0 404 exit(EXIT_FAILURE);
92055a92 405}
782d9789 406
51fc9379
QY
407static void
408cleanup()
782d9789 409{
51fc9379
QY
410 /* free resources */
411 free (docstr_start);
478bdaeb 412
4427e9b3 413 /* cleanup lexer */
07079d78 414 cleanup_lexer ();
4427e9b3 415
4b0abf24 416 /* clear state pointers */
51fc9379
QY
417 seqhead = NULL;
418 currnode = NULL;
419 docstr_start = docstr = NULL;
4b0abf24
QY
420 selnode_start = selnode_end = NULL;
421 optnode_start = optnode_end = NULL;
51fc9379 422}
4b0abf24 423
51fc9379 424static void
1eb5e8dc 425terminate_graph (struct graph *graph, struct graph_node *finalnode, struct cmd_element *element)
51fc9379 426{
1eb5e8dc
QY
427 // end of graph should look like this
428 // * -> finalnode -> END_TKN -> cmd_element
d8074cc0
QY
429 struct graph_node *end_token_node =
430 new_token_node (graph,
431 END_TKN,
432 XSTRDUP (MTYPE_CMD_TOKENS, CMD_CR_TEXT),
433 XSTRDUP (MTYPE_CMD_TOKENS, ""));
1eb5e8dc
QY
434 struct graph_node *end_element_node =
435 graph_new_node (graph, element, (void (*)(void *)) &del_cmd_element);
7a6ded40 436
1eb5e8dc
QY
437 if (node_adjacent (finalnode, end_token_node))
438 yyerror (graph, element, "Duplicate command.");
439
440 graph_add_edge (finalnode, end_token_node);
441 graph_add_edge (end_token_node, end_element_node);
782d9789 442}
f4b0c72e 443
51fc9379
QY
444static char *
445doc_next()
446{
447 char *piece = NULL;
1ab84bf3 448 if (!docstr || !(piece = strsep (&docstr, "\n")))
ee551f48 449 return XSTRDUP (MTYPE_CMD_TOKENS, "");
1eb5e8dc 450 return XSTRDUP (MTYPE_CMD_TOKENS, piece);
51fc9379
QY
451}
452
453static struct graph_node *
1eb5e8dc 454new_token_node (struct graph *graph, enum cmd_token_type_t type, char *text, char *doc)
7a6ded40 455{
fe2e10e8 456 struct cmd_token_t *token = new_cmd_token (type, text, doc);
1eb5e8dc 457 return graph_new_node (graph, token, (void (*)(void *)) &del_cmd_token);
7a6ded40
QY
458}
459
460/**
1eb5e8dc 461 * Determines if there is an out edge from the first node to the second
7a6ded40
QY
462 */
463static struct graph_node *
1eb5e8dc 464node_adjacent (struct graph_node *first, struct graph_node *second)
f4b0c72e 465{
7a6ded40 466 struct graph_node *adj;
1eb5e8dc 467 for (unsigned int i = 0; i < vector_active (first->to); i++)
1ab84bf3 468 {
1eb5e8dc 469 adj = vector_slot (first->to, i);
97f13f08 470 struct cmd_token_t *ftok = adj->data,
1eb5e8dc
QY
471 *stok = second->data;
472 if (cmp_token (ftok, stok))
7a6ded40 473 return adj;
1ab84bf3 474 }
f4b0c72e
QY
475 return NULL;
476}
477
1eb5e8dc
QY
478/**
479 * Creates an edge betwen two nodes, unless there is already an edge to an
480 * equivalent node.
481 *
482 * The first node's out edges are searched to see if any of them point to a
483 * node that is equivalent to the second node. If such a node exists, it is
484 * returned. Otherwise an edge is created from the first node to the second.
485 *
486 * @param from start node for edge
487 * @param to end node for edge
488 * @return the node which the new edge points to
489 */
51fc9379 490static struct graph_node *
1eb5e8dc 491add_edge_dedup (struct graph_node *from, struct graph_node *to)
f4b0c72e 492{
1eb5e8dc
QY
493 struct graph_node *existing = node_adjacent (from, to);
494 return existing ? existing : graph_add_edge (from, to);
f4b0c72e 495}
0aa2c2ff 496
1eb5e8dc
QY
497/**
498 * Compares two cmd_token's for equality,
499 *
500 * As such, this function is the working definition of token equality
501 * for parsing purposes and determines overall graph structure.
502 */
51fc9379 503static int
7a6ded40 504cmp_token (struct cmd_token_t *first, struct cmd_token_t *second)
0aa2c2ff 505{
51fc9379
QY
506 // compare types
507 if (first->type != second->type) return 0;
508
509 switch (first->type) {
1eb5e8dc
QY
510 case WORD_TKN:
511 case VARIABLE_TKN:
e52c05cd
QY
512 if (first->text && second->text)
513 {
514 if (strcmp (first->text, second->text))
97f13f08 515 return 0;
e52c05cd 516 }
51fc9379
QY
517 else if (first->text != second->text) return 0;
518 break;
1eb5e8dc 519 case RANGE_TKN:
51fc9379
QY
520 if (first->min != second->min || first->max != second->max)
521 return 0;
522 break;
1eb5e8dc 523 case NUMBER_TKN:
51fc9379
QY
524 if (first->value != second->value) return 0;
525 break;
1eb5e8dc 526
55589d30
QY
527 /* selectors and options should be equal if their subgraphs are equal,
528 * but the graph isomorphism problem is not known to be solvable in
529 * polynomial time so we consider selectors and options inequal in all
530 * cases; ultimately this forks the graph, but the matcher can handle
531 * this regardless
51fc9379 532 */
1eb5e8dc
QY
533 case SELECTOR_TKN:
534 case OPTION_TKN:
51fc9379 535 return 0;
1eb5e8dc 536
51fc9379 537 /* end nodes are always considered equal, since each node may only
1eb5e8dc 538 * have one END_TKN child at a time
51fc9379 539 */
1eb5e8dc
QY
540 case START_TKN:
541 case END_TKN:
542 case NUL_TKN:
51fc9379
QY
543 default:
544 break;
545 }
546 return 1;
0aa2c2ff 547}