]>
Commit | Line | Data |
---|---|---|
9f95a23c TL |
1 | /* SPDX-License-Identifier: BSD-3-Clause |
2 | * Copyright(c) 2016 Intel Corporation | |
7c673cae FG |
3 | */ |
4 | #include <rte_common.h> | |
5 | #include <rte_crypto.h> | |
9f95a23c | 6 | #include <rte_string_fns.h> |
7c673cae FG |
7 | |
8 | #include <cmdline_parse_string.h> | |
9 | #include <cmdline_parse_num.h> | |
10 | #include <cmdline_parse_ipaddr.h> | |
11 | #include <cmdline_socket.h> | |
12 | #include <cmdline.h> | |
13 | ||
14 | #include "ipsec.h" | |
15 | #include "parser.h" | |
16 | ||
17 | #define PARSE_DELIMITER " \f\n\r\t\v" | |
18 | static int | |
19 | parse_tokenize_string(char *string, char *tokens[], uint32_t *n_tokens) | |
20 | { | |
21 | uint32_t i; | |
22 | ||
23 | if ((string == NULL) || | |
24 | (tokens == NULL) || | |
25 | (*n_tokens < 1)) | |
26 | return -EINVAL; | |
27 | ||
28 | for (i = 0; i < *n_tokens; i++) { | |
29 | tokens[i] = strtok_r(string, PARSE_DELIMITER, &string); | |
30 | if (tokens[i] == NULL) | |
31 | break; | |
32 | } | |
33 | ||
34 | if ((i == *n_tokens) && | |
35 | (NULL != strtok_r(string, PARSE_DELIMITER, &string))) | |
36 | return -E2BIG; | |
37 | ||
38 | *n_tokens = i; | |
39 | return 0; | |
40 | } | |
41 | ||
42 | #define INADDRSZ 4 | |
43 | #define IN6ADDRSZ 16 | |
44 | ||
45 | /* int | |
46 | * inet_pton4(src, dst) | |
47 | * like inet_aton() but without all the hexadecimal and shorthand. | |
48 | * return: | |
49 | * 1 if `src' is a valid dotted quad, else 0. | |
50 | * notice: | |
51 | * does not touch `dst' unless it's returning 1. | |
52 | * author: | |
53 | * Paul Vixie, 1996. | |
54 | */ | |
55 | static int | |
56 | inet_pton4(const char *src, unsigned char *dst) | |
57 | { | |
58 | static const char digits[] = "0123456789"; | |
59 | int saw_digit, octets, ch; | |
60 | unsigned char tmp[INADDRSZ], *tp; | |
61 | ||
62 | saw_digit = 0; | |
63 | octets = 0; | |
64 | *(tp = tmp) = 0; | |
65 | while ((ch = *src++) != '\0') { | |
66 | const char *pch; | |
67 | ||
68 | pch = strchr(digits, ch); | |
69 | if (pch != NULL) { | |
70 | unsigned int new = *tp * 10 + (pch - digits); | |
71 | ||
72 | if (new > 255) | |
73 | return 0; | |
74 | if (!saw_digit) { | |
75 | if (++octets > 4) | |
76 | return 0; | |
77 | saw_digit = 1; | |
78 | } | |
79 | *tp = (unsigned char)new; | |
80 | } else if (ch == '.' && saw_digit) { | |
81 | if (octets == 4) | |
82 | return 0; | |
83 | *++tp = 0; | |
84 | saw_digit = 0; | |
85 | } else | |
86 | return 0; | |
87 | } | |
88 | if (octets < 4) | |
89 | return 0; | |
90 | ||
91 | memcpy(dst, tmp, INADDRSZ); | |
92 | return 1; | |
93 | } | |
94 | ||
95 | /* int | |
96 | * inet_pton6(src, dst) | |
97 | * convert presentation level address to network order binary form. | |
98 | * return: | |
99 | * 1 if `src' is a valid [RFC1884 2.2] address, else 0. | |
100 | * notice: | |
101 | * (1) does not touch `dst' unless it's returning 1. | |
102 | * (2) :: in a full address is silently ignored. | |
103 | * credit: | |
104 | * inspired by Mark Andrews. | |
105 | * author: | |
106 | * Paul Vixie, 1996. | |
107 | */ | |
108 | static int | |
109 | inet_pton6(const char *src, unsigned char *dst) | |
110 | { | |
111 | static const char xdigits_l[] = "0123456789abcdef", | |
112 | xdigits_u[] = "0123456789ABCDEF"; | |
113 | unsigned char tmp[IN6ADDRSZ], *tp = 0, *endp = 0, *colonp = 0; | |
114 | const char *xdigits = 0, *curtok = 0; | |
115 | int ch = 0, saw_xdigit = 0, count_xdigit = 0; | |
116 | unsigned int val = 0; | |
117 | unsigned dbloct_count = 0; | |
118 | ||
119 | memset((tp = tmp), '\0', IN6ADDRSZ); | |
120 | endp = tp + IN6ADDRSZ; | |
121 | colonp = NULL; | |
122 | /* Leading :: requires some special handling. */ | |
123 | if (*src == ':') | |
124 | if (*++src != ':') | |
125 | return 0; | |
126 | curtok = src; | |
127 | saw_xdigit = count_xdigit = 0; | |
128 | val = 0; | |
129 | ||
130 | while ((ch = *src++) != '\0') { | |
131 | const char *pch; | |
132 | ||
133 | pch = strchr((xdigits = xdigits_l), ch); | |
134 | if (pch == NULL) | |
135 | pch = strchr((xdigits = xdigits_u), ch); | |
136 | if (pch != NULL) { | |
137 | if (count_xdigit >= 4) | |
138 | return 0; | |
139 | val <<= 4; | |
140 | val |= (pch - xdigits); | |
141 | if (val > 0xffff) | |
142 | return 0; | |
143 | saw_xdigit = 1; | |
144 | count_xdigit++; | |
145 | continue; | |
146 | } | |
147 | if (ch == ':') { | |
148 | curtok = src; | |
149 | if (!saw_xdigit) { | |
150 | if (colonp) | |
151 | return 0; | |
152 | colonp = tp; | |
153 | continue; | |
154 | } else if (*src == '\0') { | |
155 | return 0; | |
156 | } | |
157 | if (tp + sizeof(int16_t) > endp) | |
158 | return 0; | |
159 | *tp++ = (unsigned char) ((val >> 8) & 0xff); | |
160 | *tp++ = (unsigned char) (val & 0xff); | |
161 | saw_xdigit = 0; | |
162 | count_xdigit = 0; | |
163 | val = 0; | |
164 | dbloct_count++; | |
165 | continue; | |
166 | } | |
167 | if (ch == '.' && ((tp + INADDRSZ) <= endp) && | |
168 | inet_pton4(curtok, tp) > 0) { | |
169 | tp += INADDRSZ; | |
170 | saw_xdigit = 0; | |
171 | dbloct_count += 2; | |
172 | break; /* '\0' was seen by inet_pton4(). */ | |
173 | } | |
174 | return 0; | |
175 | } | |
176 | if (saw_xdigit) { | |
177 | if (tp + sizeof(int16_t) > endp) | |
178 | return 0; | |
179 | *tp++ = (unsigned char) ((val >> 8) & 0xff); | |
180 | *tp++ = (unsigned char) (val & 0xff); | |
181 | dbloct_count++; | |
182 | } | |
183 | if (colonp != NULL) { | |
184 | /* if we already have 8 double octets, having a colon | |
185 | * means error */ | |
186 | if (dbloct_count == 8) | |
187 | return 0; | |
188 | ||
189 | /* | |
190 | * Since some memmove()'s erroneously fail to handle | |
191 | * overlapping regions, we'll do the shift by hand. | |
192 | */ | |
193 | const int n = tp - colonp; | |
194 | int i; | |
195 | ||
196 | for (i = 1; i <= n; i++) { | |
197 | endp[-i] = colonp[n - i]; | |
198 | colonp[n - i] = 0; | |
199 | } | |
200 | tp = endp; | |
201 | } | |
202 | if (tp != endp) | |
203 | return 0; | |
204 | memcpy(dst, tmp, IN6ADDRSZ); | |
205 | return 1; | |
206 | } | |
207 | ||
208 | int | |
209 | parse_ipv4_addr(const char *token, struct in_addr *ipv4, uint32_t *mask) | |
210 | { | |
9f95a23c | 211 | char ip_str[INET_ADDRSTRLEN] = {0}; |
7c673cae FG |
212 | char *pch; |
213 | ||
214 | pch = strchr(token, '/'); | |
215 | if (pch != NULL) { | |
9f95a23c TL |
216 | strlcpy(ip_str, token, |
217 | RTE_MIN((unsigned int long)(pch - token + 1), | |
218 | sizeof(ip_str))); | |
7c673cae FG |
219 | pch += 1; |
220 | if (is_str_num(pch) != 0) | |
221 | return -EINVAL; | |
222 | if (mask) | |
223 | *mask = atoi(pch); | |
224 | } else { | |
9f95a23c | 225 | strlcpy(ip_str, token, sizeof(ip_str)); |
7c673cae FG |
226 | if (mask) |
227 | *mask = 0; | |
228 | } | |
7c673cae FG |
229 | if (strlen(ip_str) >= INET_ADDRSTRLEN) |
230 | return -EINVAL; | |
231 | ||
232 | if (inet_pton4(ip_str, (unsigned char *)ipv4) != 1) | |
233 | return -EINVAL; | |
234 | ||
235 | return 0; | |
236 | } | |
237 | ||
238 | int | |
239 | parse_ipv6_addr(const char *token, struct in6_addr *ipv6, uint32_t *mask) | |
240 | { | |
241 | char ip_str[256] = {0}; | |
242 | char *pch; | |
243 | ||
244 | pch = strchr(token, '/'); | |
245 | if (pch != NULL) { | |
9f95a23c TL |
246 | strlcpy(ip_str, token, |
247 | RTE_MIN((unsigned int long)(pch - token + 1), | |
248 | sizeof(ip_str))); | |
7c673cae FG |
249 | pch += 1; |
250 | if (is_str_num(pch) != 0) | |
251 | return -EINVAL; | |
252 | if (mask) | |
253 | *mask = atoi(pch); | |
254 | } else { | |
9f95a23c | 255 | strlcpy(ip_str, token, sizeof(ip_str)); |
7c673cae FG |
256 | if (mask) |
257 | *mask = 0; | |
258 | } | |
259 | ||
260 | if (strlen(ip_str) >= INET6_ADDRSTRLEN) | |
261 | return -EINVAL; | |
262 | ||
263 | if (inet_pton6(ip_str, (unsigned char *)ipv6) != 1) | |
264 | return -EINVAL; | |
265 | ||
266 | return 0; | |
267 | } | |
268 | ||
269 | int | |
270 | parse_range(const char *token, uint16_t *low, uint16_t *high) | |
271 | { | |
272 | char ch; | |
273 | char num_str[20]; | |
274 | uint32_t pos; | |
275 | int range_low = -1; | |
276 | int range_high = -1; | |
277 | ||
278 | if (!low || !high) | |
279 | return -1; | |
280 | ||
281 | memset(num_str, 0, 20); | |
282 | pos = 0; | |
283 | ||
284 | while ((ch = *token++) != '\0') { | |
285 | if (isdigit(ch)) { | |
286 | if (pos >= 19) | |
287 | return -1; | |
288 | num_str[pos++] = ch; | |
289 | } else if (ch == ':') { | |
290 | if (range_low != -1) | |
291 | return -1; | |
292 | range_low = atoi(num_str); | |
293 | memset(num_str, 0, 20); | |
294 | pos = 0; | |
295 | } | |
296 | } | |
297 | ||
298 | if (strlen(num_str) == 0) | |
299 | return -1; | |
300 | ||
301 | range_high = atoi(num_str); | |
302 | ||
303 | *low = (uint16_t)range_low; | |
304 | *high = (uint16_t)range_high; | |
305 | ||
306 | return 0; | |
307 | } | |
308 | ||
9f95a23c TL |
309 | /* |
310 | * helper function for parse_mac, parse one section of the ether addr. | |
311 | */ | |
312 | static const char * | |
313 | parse_uint8x16(const char *s, uint8_t *v, uint8_t ls) | |
314 | { | |
315 | char *end; | |
316 | unsigned long t; | |
317 | ||
318 | errno = 0; | |
319 | t = strtoul(s, &end, 16); | |
320 | if (errno != 0 || end[0] != ls || t > UINT8_MAX) | |
321 | return NULL; | |
322 | v[0] = t; | |
323 | return end + 1; | |
324 | } | |
325 | ||
326 | static int | |
327 | parse_mac(const char *str, struct ether_addr *addr) | |
328 | { | |
329 | uint32_t i; | |
330 | ||
331 | static const uint8_t stop_sym[RTE_DIM(addr->addr_bytes)] = { | |
332 | [0] = ':', | |
333 | [1] = ':', | |
334 | [2] = ':', | |
335 | [3] = ':', | |
336 | [4] = ':', | |
337 | [5] = 0, | |
338 | }; | |
339 | ||
340 | for (i = 0; i != RTE_DIM(addr->addr_bytes); i++) { | |
341 | str = parse_uint8x16(str, addr->addr_bytes + i, stop_sym[i]); | |
342 | if (str == NULL) | |
343 | return -EINVAL; | |
344 | } | |
345 | ||
346 | return 0; | |
347 | } | |
348 | ||
7c673cae FG |
349 | /** sp add parse */ |
350 | struct cfg_sp_add_cfg_item { | |
351 | cmdline_fixed_string_t sp_keyword; | |
352 | cmdline_multi_string_t multi_string; | |
353 | }; | |
354 | ||
355 | static void | |
356 | cfg_sp_add_cfg_item_parsed(void *parsed_result, | |
357 | __rte_unused struct cmdline *cl, void *data) | |
358 | { | |
359 | struct cfg_sp_add_cfg_item *params = parsed_result; | |
360 | char *tokens[32]; | |
361 | uint32_t n_tokens = RTE_DIM(tokens); | |
362 | struct parse_status *status = (struct parse_status *)data; | |
363 | ||
364 | APP_CHECK((parse_tokenize_string(params->multi_string, tokens, | |
365 | &n_tokens) == 0), status, "too many arguments"); | |
366 | ||
367 | if (status->status < 0) | |
368 | return; | |
369 | ||
370 | if (strcmp(tokens[0], "ipv4") == 0) { | |
371 | parse_sp4_tokens(tokens, n_tokens, status); | |
372 | if (status->status < 0) | |
373 | return; | |
374 | } else if (strcmp(tokens[0], "ipv6") == 0) { | |
375 | parse_sp6_tokens(tokens, n_tokens, status); | |
376 | if (status->status < 0) | |
377 | return; | |
378 | } else { | |
379 | APP_CHECK(0, status, "unrecognizable input %s\n", | |
380 | tokens[0]); | |
381 | return; | |
382 | } | |
383 | } | |
384 | ||
385 | static cmdline_parse_token_string_t cfg_sp_add_sp_str = | |
386 | TOKEN_STRING_INITIALIZER(struct cfg_sp_add_cfg_item, | |
387 | sp_keyword, "sp"); | |
388 | ||
389 | static cmdline_parse_token_string_t cfg_sp_add_multi_str = | |
390 | TOKEN_STRING_INITIALIZER(struct cfg_sp_add_cfg_item, multi_string, | |
391 | TOKEN_STRING_MULTI); | |
392 | ||
393 | cmdline_parse_inst_t cfg_sp_add_rule = { | |
394 | .f = cfg_sp_add_cfg_item_parsed, | |
395 | .data = NULL, | |
396 | .help_str = "", | |
397 | .tokens = { | |
398 | (void *) &cfg_sp_add_sp_str, | |
399 | (void *) &cfg_sp_add_multi_str, | |
400 | NULL, | |
401 | }, | |
402 | }; | |
403 | ||
404 | /* sa add parse */ | |
405 | struct cfg_sa_add_cfg_item { | |
406 | cmdline_fixed_string_t sa_keyword; | |
407 | cmdline_multi_string_t multi_string; | |
408 | }; | |
409 | ||
410 | static void | |
411 | cfg_sa_add_cfg_item_parsed(void *parsed_result, | |
412 | __rte_unused struct cmdline *cl, void *data) | |
413 | { | |
414 | struct cfg_sa_add_cfg_item *params = parsed_result; | |
415 | char *tokens[32]; | |
416 | uint32_t n_tokens = RTE_DIM(tokens); | |
417 | struct parse_status *status = (struct parse_status *)data; | |
418 | ||
419 | APP_CHECK(parse_tokenize_string(params->multi_string, tokens, | |
420 | &n_tokens) == 0, status, "too many arguments\n"); | |
421 | ||
422 | parse_sa_tokens(tokens, n_tokens, status); | |
423 | } | |
424 | ||
425 | static cmdline_parse_token_string_t cfg_sa_add_sa_str = | |
426 | TOKEN_STRING_INITIALIZER(struct cfg_sa_add_cfg_item, | |
427 | sa_keyword, "sa"); | |
428 | ||
429 | static cmdline_parse_token_string_t cfg_sa_add_multi_str = | |
430 | TOKEN_STRING_INITIALIZER(struct cfg_sa_add_cfg_item, multi_string, | |
431 | TOKEN_STRING_MULTI); | |
432 | ||
433 | cmdline_parse_inst_t cfg_sa_add_rule = { | |
434 | .f = cfg_sa_add_cfg_item_parsed, | |
435 | .data = NULL, | |
436 | .help_str = "", | |
437 | .tokens = { | |
438 | (void *) &cfg_sa_add_sa_str, | |
439 | (void *) &cfg_sa_add_multi_str, | |
440 | NULL, | |
441 | }, | |
442 | }; | |
443 | ||
444 | /* rt add parse */ | |
445 | struct cfg_rt_add_cfg_item { | |
446 | cmdline_fixed_string_t rt_keyword; | |
447 | cmdline_multi_string_t multi_string; | |
448 | }; | |
449 | ||
450 | static void | |
451 | cfg_rt_add_cfg_item_parsed(void *parsed_result, | |
452 | __rte_unused struct cmdline *cl, void *data) | |
453 | { | |
454 | struct cfg_rt_add_cfg_item *params = parsed_result; | |
455 | char *tokens[32]; | |
456 | uint32_t n_tokens = RTE_DIM(tokens); | |
457 | struct parse_status *status = (struct parse_status *)data; | |
458 | ||
459 | APP_CHECK(parse_tokenize_string( | |
460 | params->multi_string, tokens, &n_tokens) == 0, | |
461 | status, "too many arguments\n"); | |
462 | if (status->status < 0) | |
463 | return; | |
464 | ||
465 | parse_rt_tokens(tokens, n_tokens, status); | |
466 | } | |
467 | ||
468 | static cmdline_parse_token_string_t cfg_rt_add_rt_str = | |
469 | TOKEN_STRING_INITIALIZER(struct cfg_rt_add_cfg_item, | |
470 | rt_keyword, "rt"); | |
471 | ||
472 | static cmdline_parse_token_string_t cfg_rt_add_multi_str = | |
473 | TOKEN_STRING_INITIALIZER(struct cfg_rt_add_cfg_item, multi_string, | |
474 | TOKEN_STRING_MULTI); | |
475 | ||
476 | cmdline_parse_inst_t cfg_rt_add_rule = { | |
477 | .f = cfg_rt_add_cfg_item_parsed, | |
478 | .data = NULL, | |
479 | .help_str = "", | |
480 | .tokens = { | |
481 | (void *) &cfg_rt_add_rt_str, | |
482 | (void *) &cfg_rt_add_multi_str, | |
483 | NULL, | |
484 | }, | |
485 | }; | |
486 | ||
9f95a23c TL |
487 | /* neigh add parse */ |
488 | struct cfg_neigh_add_item { | |
489 | cmdline_fixed_string_t neigh; | |
490 | cmdline_fixed_string_t pstr; | |
491 | uint16_t port; | |
492 | cmdline_fixed_string_t mac; | |
493 | }; | |
494 | ||
495 | static void | |
496 | cfg_parse_neigh(void *parsed_result, __rte_unused struct cmdline *cl, | |
497 | void *data) | |
498 | { | |
499 | int32_t rc; | |
500 | struct cfg_neigh_add_item *res; | |
501 | struct parse_status *st; | |
502 | struct ether_addr mac; | |
503 | ||
504 | st = data; | |
505 | res = parsed_result; | |
506 | rc = parse_mac(res->mac, &mac); | |
507 | APP_CHECK(rc == 0, st, "invalid ether addr:%s", res->mac); | |
508 | rc = add_dst_ethaddr(res->port, &mac); | |
509 | APP_CHECK(rc == 0, st, "invalid port numer:%hu", res->port); | |
510 | if (st->status < 0) | |
511 | return; | |
512 | } | |
513 | ||
514 | cmdline_parse_token_string_t cfg_add_neigh_start = | |
515 | TOKEN_STRING_INITIALIZER(struct cfg_neigh_add_item, neigh, "neigh"); | |
516 | cmdline_parse_token_string_t cfg_add_neigh_pstr = | |
517 | TOKEN_STRING_INITIALIZER(struct cfg_neigh_add_item, pstr, "port"); | |
518 | cmdline_parse_token_num_t cfg_add_neigh_port = | |
519 | TOKEN_NUM_INITIALIZER(struct cfg_neigh_add_item, port, UINT16); | |
520 | cmdline_parse_token_string_t cfg_add_neigh_mac = | |
521 | TOKEN_STRING_INITIALIZER(struct cfg_neigh_add_item, mac, NULL); | |
522 | ||
523 | cmdline_parse_inst_t cfg_neigh_add_rule = { | |
524 | .f = cfg_parse_neigh, | |
525 | .data = NULL, | |
526 | .help_str = "", | |
527 | .tokens = { | |
528 | (void *)&cfg_add_neigh_start, | |
529 | (void *)&cfg_add_neigh_pstr, | |
530 | (void *)&cfg_add_neigh_port, | |
531 | (void *)&cfg_add_neigh_mac, | |
532 | NULL, | |
533 | }, | |
534 | }; | |
535 | ||
7c673cae FG |
536 | /** set of cfg items */ |
537 | cmdline_parse_ctx_t ipsec_ctx[] = { | |
538 | (cmdline_parse_inst_t *)&cfg_sp_add_rule, | |
539 | (cmdline_parse_inst_t *)&cfg_sa_add_rule, | |
540 | (cmdline_parse_inst_t *)&cfg_rt_add_rule, | |
9f95a23c | 541 | (cmdline_parse_inst_t *)&cfg_neigh_add_rule, |
7c673cae FG |
542 | NULL, |
543 | }; | |
544 | ||
545 | int | |
546 | parse_cfg_file(const char *cfg_filename) | |
547 | { | |
548 | struct cmdline *cl = cmdline_stdin_new(ipsec_ctx, ""); | |
549 | FILE *f = fopen(cfg_filename, "r"); | |
550 | char str[1024] = {0}, *get_s = NULL; | |
551 | uint32_t line_num = 0; | |
552 | struct parse_status status = {0}; | |
553 | ||
554 | if (f == NULL) { | |
555 | rte_panic("Error: invalid file descriptor %s\n", cfg_filename); | |
556 | goto error_exit; | |
557 | } | |
558 | ||
559 | if (cl == NULL) { | |
560 | rte_panic("Error: cannot create cmdline instance\n"); | |
561 | goto error_exit; | |
562 | } | |
563 | ||
564 | cfg_sp_add_rule.data = &status; | |
565 | cfg_sa_add_rule.data = &status; | |
566 | cfg_rt_add_rule.data = &status; | |
9f95a23c | 567 | cfg_neigh_add_rule.data = &status; |
7c673cae FG |
568 | |
569 | do { | |
570 | char oneline[1024]; | |
571 | char *pos; | |
572 | get_s = fgets(oneline, 1024, f); | |
573 | ||
574 | if (!get_s) | |
575 | break; | |
576 | ||
577 | line_num++; | |
578 | ||
579 | if (strlen(oneline) > 1022) { | |
580 | rte_panic("%s:%u: error: " | |
581 | "the line contains more characters the parser can handle\n", | |
582 | cfg_filename, line_num); | |
583 | goto error_exit; | |
584 | } | |
585 | ||
586 | /* process comment char '#' */ | |
587 | if (oneline[0] == '#') | |
588 | continue; | |
589 | ||
590 | pos = strchr(oneline, '#'); | |
591 | if (pos != NULL) | |
592 | *pos = '\0'; | |
593 | ||
594 | /* process line concatenator '\' */ | |
595 | pos = strchr(oneline, 92); | |
596 | if (pos != NULL) { | |
597 | if (pos != oneline+strlen(oneline) - 2) { | |
598 | rte_panic("%s:%u: error: " | |
599 | "no character should exist after '\\'\n", | |
600 | cfg_filename, line_num); | |
601 | goto error_exit; | |
602 | } | |
603 | ||
604 | *pos = '\0'; | |
605 | ||
606 | if (strlen(oneline) + strlen(str) > 1022) { | |
607 | rte_panic("%s:%u: error: " | |
608 | "the concatenated line contains more characters the parser can handle\n", | |
609 | cfg_filename, line_num); | |
610 | goto error_exit; | |
611 | } | |
612 | ||
9f95a23c | 613 | strcpy(str + strlen(str), oneline); |
7c673cae FG |
614 | continue; |
615 | } | |
616 | ||
617 | /* copy the line to str and process */ | |
618 | if (strlen(oneline) + strlen(str) > 1022) { | |
619 | rte_panic("%s:%u: error: " | |
620 | "the line contains more characters the parser can handle\n", | |
621 | cfg_filename, line_num); | |
622 | goto error_exit; | |
623 | } | |
9f95a23c | 624 | strcpy(str + strlen(str), oneline); |
7c673cae FG |
625 | |
626 | str[strlen(str)] = '\n'; | |
627 | if (cmdline_parse(cl, str) < 0) { | |
628 | rte_panic("%s:%u: error: parsing \"%s\" failed\n", | |
629 | cfg_filename, line_num, str); | |
630 | goto error_exit; | |
631 | } | |
632 | ||
633 | if (status.status < 0) { | |
634 | rte_panic("%s:%u: error: %s", cfg_filename, | |
635 | line_num, status.parse_msg); | |
636 | goto error_exit; | |
637 | } | |
638 | ||
639 | memset(str, 0, 1024); | |
640 | } while (1); | |
641 | ||
642 | cmdline_stdin_exit(cl); | |
643 | fclose(f); | |
644 | ||
645 | return 0; | |
646 | ||
647 | error_exit: | |
648 | if (cl) | |
649 | cmdline_stdin_exit(cl); | |
650 | if (f) | |
651 | fclose(f); | |
652 | ||
653 | return -1; | |
654 | } |