testlang_parse.y revision 1.3.2.1 1 %{
2 /* $NetBSD: testlang_parse.y,v 1.3.2.1 2011/06/23 14:20:40 cherry Exp $ */
3
4 /*-
5 * Copyright 2009 Brett Lymn <blymn (at) NetBSD.org>
6 *
7 * All rights reserved.
8 *
9 * This code has been donated to The NetBSD Foundation by the Author.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. The name of the author may not be used to endorse or promote products
17 * derived from this software withough specific prior written permission
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 *
31 */
32 #include <assert.h>
33 #include <errno.h>
34 #include <fcntl.h>
35 #include <err.h>
36 #include <unistd.h>
37 #include <poll.h>
38 #include <stdbool.h>
39 #include <stdio.h>
40 #include <string.h>
41 #include <sys/syslimits.h>
42 #include <time.h>
43 #include <vis.h>
44 #include "returns.h"
45
46 #define YYDEBUG 1
47
48 extern int verbose;
49 extern int cmdpipe[2];
50 extern int slvpipe[2];
51 extern int master;
52 extern struct pollfd readfd;
53 extern char *check_path;
54 extern char *cur_file; /* from director.c */
55
56 int yylex(void);
57
58 size_t line;
59
60 static int input_delay;
61
62 /* time delay between inputs chars - default to 0.1ms minimum to prevent
63 * problems with input tests
64 */
65 #define DELAY_MIN 0.1
66 static struct timespec delay_spec = {0, 1000 * DELAY_MIN};
67 static char *input_str; /* string to feed in as input */
68 static bool no_input; /* don't need more input */
69
70 #define READ_PIPE 0
71 #define WRITE_PIPE 1
72
73 const char *returns_enum_names[] = {
74 "unused", "numeric", "string", "byte", "ERR", "OK", "NULL", "not NULL",
75 "variable", "reference", "returns count", "slave error"
76 };
77
78 typedef enum {
79 arg_static,
80 arg_byte,
81 arg_var,
82 arg_null
83 } args_state_t;
84
85 static const char *args_enum_names[] = {
86 "static", "byte", "var", "NULL"
87 };
88
89 typedef struct {
90 args_state_t arg_type;
91 size_t arg_len;
92 char *arg_string;
93 int var_index;
94 } args_t;
95
96 typedef struct {
97 char *function;
98 int nrets; /* number of returns */
99 returns_t *returns; /* array of expected returns */
100 int nargs; /* number of arguments */
101 args_t *args; /* arguments for the call */
102 } cmd_line_t;
103
104 static cmd_line_t command;
105
106 typedef struct {
107 char *name;
108 size_t len;
109 returns_enum_t type;
110 void *value;
111 } var_t;
112
113 static size_t nvars; /* Number of declared variables */
114 static var_t *vars; /* Variables defined during the test. */
115
116 static int check_function_table(char *, const char *[], int);
117 static int find_var_index(const char *);
118 static void assign_arg(args_state_t, void *);
119 static int assign_var(char *);
120 void init_parse_variables(int);
121 static void validate(int, void *);
122 static void validate_return(const char *, const char *, int);
123 static void validate_variable(int, returns_enum_t, const void *, int, int);
124 static void validate_byte(returns_t *, returns_t *, int);
125 static void write_cmd_pipe(char *);
126 static void write_cmd_pipe_args(args_state_t, void *);
127 static void read_cmd_pipe(returns_t *);
128 static void write_func_and_args(void);
129 static void compare_streams(char *, bool);
130 static void do_function_call(size_t);
131 static void save_slave_output(bool);
132 static void validate_type(returns_enum_t, returns_t *, int);
133 static void set_var(returns_enum_t, char *, void *);
134 static void validate_reference(int, void *);
135 static char *numeric_or(char *, char *);
136 static char *get_numeric_var(const char *);
137
138 static const char *input_functions[] = {
139 "inch", "getch", "getnstr", "getstr", "innstr", "instr", "mvgetnstr",
140 "mvgetstr", "mvinchstr", "mvinchnstr", "mvgetnstr", "mvgetstr",
141 "mvinchstr", "mvinchnstr", "winch", "wgetch", "wgetnstr", "wgetstr",
142 "winchnstr", "winchstr", "winnstr", "winstr"
143 };
144
145 static const unsigned ninput_functions =
146 sizeof(input_functions) / sizeof(char *);
147
148 saved_data_t saved_output;
149
150 %}
151
152 %union {
153 char *string;
154 returns_t *retval;
155 }
156
157 %token <string> PATH
158 %token <string> STRING
159 %token <retval> BYTE
160 %token <string> VARNAME
161 %token <string> FILENAME
162 %token <string> VARIABLE
163 %token <string> REFERENCE
164 %token <string> NULL_RET
165 %token <string> NON_NULL
166 %token <string> ERR_RET
167 %token <string> OK_RET
168 %token <string> numeric
169 %token <string> DELAY
170 %token <string> INPUT
171 %token <string> COMPARE
172 %token <string> COMPAREND
173 %token <string> ASSIGN
174 %token EOL CALL CHECK NOINPUT OR LHB RHB
175 %token CALL2 CALL3 CALL4 DRAIN
176
177 %nonassoc OR
178
179 %%
180
181 statement : /* empty */
182 | assign statement
183 | call statement
184 | call2 statement
185 | call3 statement
186 | call4 statement
187 | check statement
188 | delay statement
189 | input statement
190 | noinput statement
191 | compare statement
192 | comparend statement
193 | eol statement
194 ;
195
196 assign : ASSIGN VARNAME numeric {set_var(ret_number, $2, $3);} eol
197 | ASSIGN VARNAME LHB expr RHB {set_var(ret_number, $2, $<string>4);} eol
198 | ASSIGN VARNAME STRING {set_var(ret_string, $2, $3);} eol
199 | ASSIGN VARNAME BYTE {set_var(ret_byte, $2, $3);} eol
200 ;
201
202 call : CALL result fn_name args eol {
203 do_function_call(1);
204 }
205 ;
206
207 call2 : CALL2 result result fn_name args eol {
208 do_function_call(2);
209 }
210 ;
211
212 call3 : CALL3 result result result fn_name args eol {
213 do_function_call(3);
214 }
215 ;
216
217 call4 : CALL4 result result result result fn_name args eol {
218 do_function_call(4);
219 }
220 ;
221
222 check : CHECK var returns eol {
223 returns_t retvar;
224 var_t *vptr;
225 if (command.returns[0].return_index == -1)
226 err(1, "Undefined variable in check statement, line %zu"
227 " of file %s", line, cur_file);
228
229 if (verbose)
230 fprintf(stderr, "Checking contents of variable %s for %s\n",
231 vars[command.returns[0].return_index].name,
232 returns_enum_names[command.returns[1].return_type]);
233
234 if (((command.returns[1].return_type == arg_byte) &&
235 (vars[command.returns[0].return_index].type != ret_byte)) ||
236 ((command.returns[1].return_type == arg_static) &&
237 (vars[command.returns[0].return_index].type != ret_string)))
238 err(1, "Var type %s (%d) does not match return type %s (%d)",
239 returns_enum_names[vars[command.returns[0].return_index].type],
240 vars[command.returns[0].return_index].type,
241 returns_enum_names[command.returns[1].return_type],
242 command.returns[1].return_type);
243
244 switch (command.returns[1].return_type) {
245 case ret_err:
246 validate_variable(0, ret_string, "ERR",
247 command.returns[0].return_index, 0);
248 break;
249
250 case ret_ok:
251 validate_variable(0, ret_string, "OK",
252 command.returns[0].return_index, 0);
253 break;
254
255 case ret_null:
256 validate_variable(0, ret_string, "NULL",
257 command.returns[0].return_index, 0);
258 break;
259
260 case ret_nonnull:
261 validate_variable(0, ret_string, "NULL",
262 command.returns[0].return_index, 1);
263 break;
264
265 case ret_string:
266 case ret_number:
267 if (verbose)
268 fprintf(stderr, " %s == returned %s\n",
269 (const char *)command.returns[1].return_value,
270 (const char *)
271 vars[command.returns[0].return_index].value);
272 validate_variable(0, ret_string,
273 command.returns[1].return_value,
274 command.returns[0].return_index, 0);
275 break;
276
277 case ret_byte:
278 vptr = &vars[command.returns[0].return_index];
279 retvar.return_len = vptr->len;
280 retvar.return_type = vptr->type;
281 retvar.return_value = vptr->value;
282 validate_byte(&retvar, &command.returns[1], 0);
283 break;
284
285 default:
286 err(1, "Malformed check statement at line %zu "
287 "of file %s", line, cur_file);
288 break;
289 }
290
291 init_parse_variables(0);
292 }
293 ;
294
295 delay : DELAY numeric eol {
296 /* set the inter-character delay */
297 if (sscanf($2, "%d", &input_delay) == 0)
298 err(1, "delay specification %s could not be converted to "
299 "numeric at line %zu of file %s", $2, line, cur_file);
300 if (verbose)
301 fprintf(stderr, "Set input delay to %d ms\n", input_delay);
302
303 if (input_delay < DELAY_MIN)
304 input_delay = 1000 * DELAY_MIN; /* ms to ns */
305 /*
306 * Fill in the timespec structure now ready for use later.
307 * The delay is specified in milliseconds so convert to timespec
308 * values
309 */
310 delay_spec.tv_sec = input_delay / 1000;
311 delay_spec.tv_nsec = (input_delay - 1000 * delay_spec.tv_sec) * 1000;
312
313 init_parse_variables(0);
314 }
315 ;
316
317 input : INPUT STRING eol {
318 if (input_str != NULL) {
319 warnx("%s, %zu: Discarding unused input string",
320 cur_file, line);
321 free(input_str);
322 }
323
324 if ((input_str = malloc(strlen($2) + 1)) == NULL)
325 err(2, "Cannot allocate memory for input string");
326
327 strlcpy(input_str, $2, strlen($2) + 1);
328 }
329 ;
330
331
332 noinput : NOINPUT eol {
333 if (input_str != NULL) {
334 warnx("%s, %zu: Discarding unused input string",
335 cur_file, line);
336 free(input_str);
337 }
338
339 no_input = true;
340 }
341
342 compare : COMPARE PATH eol
343 | COMPARE FILENAME eol
344 {
345 compare_streams($2, true);
346 }
347 ;
348
349
350 comparend : COMPAREND PATH eol
351 | COMPAREND FILENAME eol
352 {
353 compare_streams($2, false);
354 }
355 ;
356
357
358 result : returns
359 | var
360 | reference
361 ;
362
363 returns : numeric { assign_rets(ret_number, $1); }
364 | LHB expr RHB { assign_rets(ret_number, $<string>2); }
365 | STRING { assign_rets(ret_string, $1); }
366 | BYTE { assign_rets(ret_byte, (void *) $1); }
367 | ERR_RET { assign_rets(ret_err, NULL); }
368 | OK_RET { assign_rets(ret_ok, NULL); }
369 | NULL_RET { assign_rets(ret_null, NULL); }
370 | NON_NULL { assign_rets(ret_nonnull, NULL); }
371 ;
372
373 var : VARNAME {
374 assign_rets(ret_var, $1);
375 }
376 ;
377
378 reference : VARIABLE {
379 assign_rets(ret_ref, $1);
380 }
381
382 fn_name : VARNAME {
383 if (command.function != NULL)
384 free(command.function);
385
386 command.function = malloc(strlen($1) + 1);
387 if (command.function == NULL)
388 err(1, "Could not allocate memory for function name");
389 strcpy(command.function, $1);
390 }
391 ;
392
393 expr : numeric
394 | VARIABLE
395 { $<string>$ = get_numeric_var($1); }
396 | expr OR expr
397 { $<string>$ = numeric_or($<string>1, $<string>3); }
398 ;
399
400 args : /* empty */
401 | LHB expr RHB { assign_arg(arg_static, $<string>2); } args
402 | numeric { assign_arg(arg_static, $1); } args
403 | STRING { assign_arg(arg_static, $1); } args
404 | BYTE { assign_arg(arg_byte, $1); } args
405 | PATH { assign_arg(arg_static, $1); } args
406 | FILENAME { assign_arg(arg_static, $1); } args
407 | VARNAME { assign_arg(arg_static, $1); } args
408 | VARIABLE { assign_arg(arg_var, $1); } args
409 | NULL_RET { assign_arg(arg_null, $1); } args
410 ;
411
412 eol : EOL
413 ;
414
415 %%
416
417 static void
418 excess(const char *fname, size_t lineno, const char *func, const char *comment,
419 const void *data, size_t datalen)
420 {
421 size_t dstlen = datalen * 4 + 1;
422 char *dst = malloc(dstlen);
423
424 if (dst == NULL)
425 err(1, "malloc");
426
427 if (strnvisx(dst, dstlen, data, datalen, VIS_WHITE | VIS_OCTAL) == -1)
428 err(1, "strnvisx");
429
430 warnx("%s, %zu: [%s] Excess %zu bytes%s [%s]",
431 fname, lineno, func, datalen, comment, dst);
432 free(dst);
433 }
434
435 /*
436 * Get the value of a variable, error if the variable has not been set or
437 * is not a numeric type.
438 */
439 static char *
440 get_numeric_var(const char *var)
441 {
442 int i;
443
444 if ((i = find_var_index(var)) < 0)
445 err(1, "Variable %s is undefined", var);
446
447 if (vars[i].type != ret_number)
448 err(1, "Variable %s is not a numeric type", var);
449
450 return vars[i].value;
451 }
452
453 /*
454 * Perform a bitwise OR on two numbers and return the result.
455 */
456 static char *
457 numeric_or(char *n1, char *n2)
458 {
459 unsigned long i1, i2, result;
460 char *ret;
461
462 i1 = strtoul(n1, NULL, 10);
463 i2 = strtoul(n2, NULL, 10);
464
465 result = i1 | i2;
466 asprintf(&ret, "%lu", result);
467
468 if (verbose)
469 fprintf(stderr, "numeric or of 0x%lx (%s) and 0x%lx (%s)"
470 " results in 0x%lx (%s)\n",
471 i1, n1, i2, n2, result, ret);
472
473 return ret;
474 }
475
476 /*
477 * Assign the value given to the named variable.
478 */
479 static void
480 set_var(returns_enum_t type, char *name, void *value)
481 {
482 int i;
483 char *number;
484 returns_t *ret;
485
486 i = find_var_index(name);
487 if (i < 0)
488 i = assign_var(name);
489
490 vars[i].type = type;
491 if ((type == ret_number) || (type == ret_string)) {
492 number = value;
493 vars[i].len = strlen(number) + 1;
494 vars[i].value = malloc(vars[i].len + 1);
495 if (vars[i].value == NULL)
496 err(1, "Could not malloc memory for assign string");
497 strcpy(vars[i].value, number);
498 } else {
499 /* can only be a byte value */
500 ret = value;
501 vars[i].len = ret->return_len;
502 vars[i].value = malloc(vars[i].len);
503 if (vars[i].value == NULL)
504 err(1, "Could not malloc memory to assign byte string");
505 memcpy(vars[i].value, ret->return_value, vars[i].len);
506 }
507 }
508
509 /*
510 * Add a new variable to the vars array, the value will be assigned later,
511 * when a test function call returns.
512 */
513 static int
514 assign_var(char *varname)
515 {
516 var_t *temp;
517 char *name;
518
519 if ((name = malloc(strlen(varname) + 1)) == NULL)
520 err(1, "Alloc of varname failed");
521
522 if ((temp = (var_t *) realloc(vars, sizeof(var_t) * (nvars + 1)))
523 == NULL) {
524 free(name);
525 err(1, "Realloc of vars array failed");
526 }
527
528 strcpy(name, varname);
529 vars = temp;
530 vars[nvars].name = name;
531 vars[nvars].len = 0;
532 vars[nvars].value = NULL;
533 nvars++;
534
535 return (nvars - 1);
536 }
537
538 /*
539 * Allocate and assign a new argument of the given type.
540 */
541 static void
542 assign_arg(args_state_t arg_type, void *arg)
543 {
544 args_t *temp, cur;
545 char *str = arg;
546 returns_t *ret;
547
548 if (verbose)
549 printf("function is >%s<, adding arg >%s< type %s\n",
550 command.function, str, args_enum_names[arg_type]);
551
552 cur.arg_type = arg_type;
553 switch (arg_type) {
554 case arg_var:
555 cur.var_index = find_var_index(arg);
556 if (cur.var_index < 0)
557 err(1, "Invalid variable %s at line %zu of file %s",
558 str, line, cur_file);
559 cur.arg_type = ret_string;
560 break;
561
562 case arg_byte:
563 ret = arg;
564 cur.arg_len = ret->return_len;
565 cur.arg_string = malloc(cur.arg_len);
566 if (cur.arg_string == NULL)
567 err(1, "Could not malloc memory for arg bytes");
568 memcpy(cur.arg_string, ret->return_value, cur.arg_len);
569 break;
570
571 case arg_null:
572 cur.arg_len = 0;
573 cur.arg_string = NULL;
574 break;
575
576 default:
577 cur.arg_len = strlen(str);
578 cur.arg_string = malloc(cur.arg_len + 1);
579 if (cur.arg_string == NULL)
580 err(1, "Could not malloc memory for arg string");
581 strcpy(cur.arg_string, arg);
582 }
583
584 temp = realloc(command.args, sizeof(args_t) * (command.nargs + 1));
585 if (temp == NULL)
586 err(1, "Failed to reallocate args");
587 command.args = temp;
588 memcpy(&command.args[command.nargs], &cur, sizeof(args_t));
589 command.nargs++;
590 }
591
592 /*
593 * Allocate and assign a new return.
594 */
595 static void
596 assign_rets(returns_enum_t ret_type, void *ret)
597 {
598 returns_t *temp, cur;
599 char *ret_str;
600 returns_t *ret_ret;
601
602 cur.return_type = ret_type;
603 if (ret_type != ret_var) {
604 if ((ret_type == ret_number) || (ret_type == ret_string)) {
605 ret_str = ret;
606 cur.return_len = strlen(ret_str) + 1;
607 cur.return_value = malloc(cur.return_len + 1);
608 if (cur.return_value == NULL)
609 err(1,
610 "Could not malloc memory for arg string");
611 strcpy(cur.return_value, ret_str);
612 } else if (ret_type == ret_byte) {
613 ret_ret = ret;
614 cur.return_len = ret_ret->return_len;
615 cur.return_value = malloc(cur.return_len);
616 if (cur.return_value == NULL)
617 err(1,
618 "Could not malloc memory for byte string");
619 memcpy(cur.return_value, ret_ret->return_value,
620 cur.return_len);
621 } else if (ret_type == ret_ref) {
622 if ((cur.return_index = find_var_index(ret)) < 0)
623 err(1, "Undefined variable reference");
624 }
625 } else {
626 cur.return_index = find_var_index(ret);
627 if (cur.return_index < 0)
628 cur.return_index = assign_var(ret);
629 }
630
631 temp = realloc(command.returns,
632 sizeof(returns_t) * (command.nrets + 1));
633 if (temp == NULL)
634 err(1, "Failed to reallocate returns");
635 command.returns = temp;
636 memcpy(&command.returns[command.nrets], &cur, sizeof(returns_t));
637 command.nrets++;
638 }
639
640 /*
641 * Find the given variable name in the var array and return the i
642 * return -1 if var is not found.
643 */
644 static int
645 find_var_index(const char *var_name)
646 {
647 int result;
648 size_t i;
649
650 result = -1;
651
652 for (i = 0; i < nvars; i++) {
653 if (strcmp(var_name, vars[i].name) == 0) {
654 result = i;
655 break;
656 }
657 }
658
659 return result;
660 }
661
662 /*
663 * Check the given function name in the given table of names, return 1 if
664 * there is a match.
665 */
666 static int check_function_table(char *function, const char *table[],
667 int nfunctions)
668 {
669 int i;
670
671 for (i = 0; i < nfunctions; i++) {
672 if ((strlen(function) == strlen(table[i])) &&
673 (strcmp(function, table[i]) == 0))
674 return 1;
675 }
676
677 return 0;
678 }
679
680 /*
681 * Compare the output from the slave against the given file and report
682 * any differences.
683 */
684 static void
685 compare_streams(char *filename, bool discard)
686 {
687 char check_file[PATH_MAX], drain[100], ref, data;
688 struct pollfd fds[2];
689 int nfd, check_fd;
690 ssize_t result;
691
692 /*
693 * Don't prepend check path iff check file has an absolute
694 * path.
695 */
696 if (filename[0] != '/') {
697 if (strlcpy(check_file, check_path, sizeof(check_file))
698 >= sizeof(check_file))
699 err(2, "CHECK_PATH too long");
700
701 if (strlcat(check_file, "/", sizeof(check_file))
702 >= sizeof(check_file))
703 err(2, "Could not append / to check file path");
704 } else {
705 check_file[0] = '\0';
706 }
707
708 if (strlcat(check_file, filename, sizeof(check_file))
709 >= sizeof(check_file))
710 err(2, "Path to check file path overflowed");
711
712 if ((check_fd = open(check_file, O_RDONLY, 0)) < 0)
713 err(2, "failed to open file %s line %zu of file %s",
714 check_file, line, cur_file);
715
716 fds[0].fd = check_fd;
717 fds[0].events = POLLIN;
718 fds[0].revents = 0;
719 fds[1].fd = master;
720 fds[1].events = POLLIN;
721 fds[1].revents = 0;
722
723 nfd = 2;
724 /*
725 * if we have saved output then only check for data in the
726 * reference file since the slave data may already be drained.
727 */
728 if (saved_output.count > 0)
729 nfd = 1;
730
731 while (poll(&fds[0], nfd, 500) == nfd) {
732 if ((result = read(check_fd, &ref, 1)) < 1) {
733 if (result != 0) {
734 err(2, "Bad read on file %s", check_file);
735 } else {
736 break;
737 }
738 }
739
740 if (saved_output.count > 0) {
741 data = saved_output.data[saved_output.readp];
742 saved_output.count--;
743 saved_output.readp++;
744 /* run out of saved data, switch to file */
745 if (saved_output.count == 0)
746 nfd = 2;
747 } else {
748 if (read(master, &data, 1) < 1)
749 err(2, "Bad read on slave pty");
750 }
751
752 if (verbose) {
753 fprintf(stderr, "Comparing reference byte 0x%x (%c)"
754 " against slave byte 0x%x (%c)\n", ref,
755 (ref >= ' ')? ref : '-',
756 data, (data >= ' ')? data : '-');
757 }
758
759 if (ref != data) {
760 warnx("%s, %zu: refresh data from slave does "
761 "not match expected from file %s",
762 cur_file, line, check_file);
763
764 if (!verbose)
765 exit(2);
766 }
767
768 fds[0].revents = 0;
769 fds[1].revents = 0;
770 }
771
772
773 if (saved_output.count > 0)
774 excess(cur_file, line, __func__, " from slave",
775 &saved_output.data[saved_output.readp], saved_output.count);
776
777 /* discard any excess saved output if required */
778 if (discard) {
779 saved_output.count = 0;
780 saved_output.readp = 0;
781 }
782
783 fds[0].revents = 0;
784 fds[1].revents = 0;
785 if ((result = poll(&fds[0], 2, 0)) != 0) {
786 if (result == -1)
787 err(2, "poll of file descriptors failed");
788
789 if ((fds[1].revents & POLLIN) == POLLIN) {
790 save_slave_output(true);
791 } else {
792 /*
793 * handle excess in file if it exists. Poll
794 * says there is data until EOF is read.
795 * Check next read is EOF, if it is not then
796 * the file really has more data than the
797 * slave produced so flag this as a warning.
798 */
799 result = read(check_fd, drain, sizeof(drain));
800 if (result == -1)
801 err(1, "read of data file failed");
802
803 if (result > 0) {
804 excess(check_file, 0, __func__, "", drain,
805 result);
806 if (!verbose)
807 exit(2);
808 }
809 }
810 }
811
812 close(check_fd);
813 }
814
815 /*
816 * Pass a function call and arguments to the slave and wait for the
817 * results. The variable nresults determines how many returns we expect
818 * back from the slave. These results will be validated against the
819 * expected returns or assigned to variables.
820 */
821 static void
822 do_function_call(size_t nresults)
823 {
824 #define MAX_RESULTS 4
825 char *p;
826 int do_input;
827 size_t i;
828 struct pollfd fds[3];
829 returns_t response[MAX_RESULTS], returns_count;
830
831 assert(nresults <= MAX_RESULTS);
832
833 do_input = check_function_table(command.function, input_functions,
834 ninput_functions);
835
836 write_func_and_args();
837
838 /*
839 * We should get the number of returns back here, grab it before
840 * doing input otherwise it will confuse the input poll
841 */
842 read_cmd_pipe(&returns_count);
843 if (returns_count.return_type != ret_count)
844 err(2, "expected return type of ret_count but received %s",
845 returns_enum_names[returns_count.return_type]);
846
847 if (verbose)
848 fprintf(stderr, "Expect %zu results from slave, slave "
849 "reported %zu\n", nresults, returns_count.return_len);
850
851 if ((no_input == false) && (do_input == 1)) {
852 if (verbose)
853 fprintf(stderr, "doing input with inputstr >%s<\n",
854 input_str);
855
856 if (input_str == NULL)
857 errx(2, "%s, %zu: Call to input function "
858 "but no input defined", cur_file, line);
859
860 fds[0].fd = slvpipe[READ_PIPE];
861 fds[0].events = POLLIN;
862 p = input_str;
863 save_slave_output(false);
864 while(*p != '\0') {
865 if (verbose) {
866 fprintf(stderr, "Writing char >%c< to slave\n",
867 *p);
868 fflush(stderr);
869 }
870
871 nanosleep(&delay_spec, NULL);
872
873 write(master, p, 1);
874 save_slave_output(false);
875
876 p++;
877 fds[0].revents = 0;
878
879 /* check for slave function returning unexpectedly */
880 if ((poll(&fds[0], 1, 10) > 0) && (*p != '\0')) {
881 warnx("%s, %zu: Slave function "
882 "returned before end of input string",
883 cur_file, line);
884 break;
885 }
886 }
887
888 if (verbose) {
889 fprintf(stderr, "Input done.\n");
890 }
891
892 /* done with the input string, free the resources */
893 free(input_str);
894 input_str = NULL;
895 }
896
897 if (verbose) {
898 fds[0].fd = slvpipe[READ_PIPE];
899 fds[0].events = POLLIN;
900 fds[0].revents = 0;
901
902 fds[1].fd = slvpipe[WRITE_PIPE];
903 fds[1].events = POLLOUT;
904 fds[1].revents = 0;
905
906 fds[2].fd = master;
907 fds[2].events = POLLIN | POLLOUT;
908 fds[2].revents = 0;
909
910 i = poll(&fds[0], 3, 1000);
911 fprintf(stderr, "Poll returned %zu\n", i);
912 for (i = 0; i < 3; i++) {
913 fprintf(stderr, "revents for fd[%zu] = 0x%x\n",
914 i, fds[i].revents);
915 }
916 }
917
918 /* drain any trailing output */
919 save_slave_output(false);
920
921 for (i = 0; i < returns_count.return_len; i++) {
922 read_cmd_pipe(&response[i]);
923 }
924
925 /*
926 * Check for a slave error in the first return slot, if the
927 * slave errored then we may not have the number of returns we
928 * expect but in this case we should report the slave error
929 * instead of a return count mismatch.
930 */
931 if ((returns_count.return_len > 0) &&
932 (response[0].return_type == ret_slave_error))
933 err(2, "Slave returned error: %s",
934 (const char *)response[0].return_value);
935
936 if (returns_count.return_len != nresults)
937 err(2, "Incorrect number of returns from slave, expected %zu "
938 "but received %zu", nresults, returns_count.return_len);
939
940 if (verbose) {
941 for (i = 0; i < nresults; i++) {
942 if ((response[i].return_type != ret_byte) &&
943 (response[i].return_type != ret_err) &&
944 (response[i].return_type != ret_ok))
945 fprintf(stderr,
946 "received response >%s< "
947 "expected",
948 (const char *)response[i].return_value);
949 else
950 fprintf(stderr, "received");
951
952 fprintf(stderr, " return_type %s\n",
953 returns_enum_names[command.returns[i].return_type]);
954 }
955 }
956
957 for (i = 0; i < nresults; i++) {
958 if (command.returns[i].return_type != ret_var) {
959 validate(i, &response[i]);
960 } else {
961 vars[command.returns[i].return_index].len =
962 response[i].return_len;
963 vars[command.returns[i].return_index].value =
964 response[i].return_value;
965 vars[command.returns[i].return_index].type =
966 response[i].return_type;
967 }
968 }
969 #if 0
970 if (saved_output.count > 0)
971 excess(cur_file, line, __func__, " from slave",
972 &saved_output.data[saved_output.readp], saved_output.count);
973 #endif
974
975 init_parse_variables(0);
976 }
977
978 /*
979 * Write the function and command arguments to the command pipe.
980 */
981 static void
982 write_func_and_args(void)
983 {
984 int i;
985
986 if (verbose)
987 fprintf(stderr, "calling function >%s<\n", command.function);
988
989 write_cmd_pipe(command.function);
990 for (i = 0; i < command.nargs; i++) {
991 if (command.args[i].arg_type == arg_var)
992 write_cmd_pipe_args(command.args[i].arg_type,
993 &vars[command.args[i].var_index]);
994 else
995 write_cmd_pipe_args(command.args[i].arg_type,
996 &command.args[i]);
997 }
998
999 write_cmd_pipe(NULL); /* signal end of arguments */
1000 }
1001
1002 /*
1003 * Initialise the command structure - if initial is non-zero then just set
1004 * everything to sane values otherwise free any memory that was allocated
1005 * when building the structure.
1006 */
1007 void
1008 init_parse_variables(int initial)
1009 {
1010 int i, result;
1011 struct pollfd slave_pty;
1012
1013 if (initial == 0) {
1014 free(command.function);
1015 for (i = 0; i < command.nrets; i++) {
1016 if (command.returns[i].return_type == ret_number)
1017 free(command.returns[i].return_value);
1018 }
1019 free(command.returns);
1020
1021 for (i = 0; i < command.nargs; i++) {
1022 if (command.args[i].arg_type != arg_var)
1023 free(command.args[i].arg_string);
1024 }
1025 free(command.args);
1026 } else {
1027 line = 0;
1028 input_delay = 0;
1029 vars = NULL;
1030 nvars = 0;
1031 input_str = NULL;
1032 saved_output.allocated = 0;
1033 saved_output.count = 0;
1034 saved_output.readp = 0;
1035 saved_output.data = NULL;
1036 }
1037
1038 no_input = false;
1039 command.function = NULL;
1040 command.nargs = 0;
1041 command.args = NULL;
1042 command.nrets = 0;
1043 command.returns = NULL;
1044
1045 /*
1046 * Check the slave pty for stray output from the slave, at this
1047 * point we should not see any data as it should have been
1048 * consumed by the test functions. If we see data then we have
1049 * either a bug or are not handling an output generating function
1050 * correctly.
1051 */
1052 slave_pty.fd = master;
1053 slave_pty.events = POLLIN;
1054 slave_pty.revents = 0;
1055 result = poll(&slave_pty, 1, 0);
1056
1057 if (result < 0)
1058 err(2, "Poll of slave pty failed");
1059 else if (result > 0)
1060 warnx("%s, %zu: Unexpected data from slave", cur_file, line);
1061 }
1062
1063 /*
1064 * Validate the response against the expected return. The variable
1065 * i is the i into the rets array in command.
1066 */
1067 static void
1068 validate(int i, void *data)
1069 {
1070 char *response;
1071 returns_t *byte_response;
1072
1073 byte_response = data;
1074 if ((command.returns[i].return_type != ret_byte) &&
1075 (command.returns[i].return_type != ret_err) &&
1076 (command.returns[i].return_type != ret_ok))
1077 response = byte_response->return_value;
1078
1079 switch (command.returns[i].return_type) {
1080 case ret_err:
1081 validate_type(ret_err, byte_response, 0);
1082 break;
1083
1084 case ret_ok:
1085 validate_type(ret_ok, byte_response, 0);
1086 break;
1087
1088 case ret_null:
1089 validate_return("NULL", response, 0);
1090 break;
1091
1092 case ret_nonnull:
1093 validate_return("NULL", response, 1);
1094 break;
1095
1096 case ret_string:
1097 case ret_number:
1098 validate_return(command.returns[i].return_value,
1099 response, 0);
1100 break;
1101
1102 case ret_ref:
1103 validate_reference(i, response);
1104 break;
1105
1106 case ret_byte:
1107 validate_byte(&command.returns[i], byte_response, 0);
1108 break;
1109
1110 default:
1111 err(1, "Malformed statement at line %zu of file %s",
1112 line, cur_file);
1113 break;
1114 }
1115 }
1116
1117 /*
1118 * Validate the return against the contents of a variable.
1119 */
1120 static void
1121 validate_reference(int i, void *data)
1122 {
1123 char *response;
1124 returns_t *byte_response;
1125 var_t *varp;
1126
1127 varp = &vars[command.returns[i].return_index];
1128
1129 byte_response = data;
1130 if (command.returns[i].return_type != ret_byte)
1131 response = data;
1132
1133 if (verbose)
1134 fprintf(stderr,
1135 "validate_reference: return type of %s, value %s \n",
1136 returns_enum_names[varp->type],
1137 (const char *)varp->value);
1138
1139 switch (varp->type) {
1140 case ret_string:
1141 case ret_number:
1142 validate_return(varp->value, response, 0);
1143 break;
1144
1145 case ret_byte:
1146 validate_byte(varp->value, byte_response, 0);
1147 break;
1148
1149 default:
1150 err(1,
1151 "Invalid return type for reference at line %zu of file %s",
1152 line, cur_file);
1153 break;
1154 }
1155 }
1156
1157 /*
1158 * Validate the return type against the expected type, throw an error
1159 * if they don't match.
1160 */
1161 static void
1162 validate_type(returns_enum_t expected, returns_t *value, int check)
1163 {
1164 if (((check == 0) && (expected != value->return_type)) ||
1165 ((check == 1) && (expected == value->return_type)))
1166 err(1, "Validate expected type %s %s %s line %zu of file %s",
1167 returns_enum_names[expected],
1168 (check == 0)? "matching" : "not matching",
1169 returns_enum_names[value->return_type], line, cur_file);
1170
1171 if (verbose)
1172 fprintf(stderr, "Validate expected type %s %s %s line %zu"
1173 " of file %s\n",
1174 returns_enum_names[expected],
1175 (check == 0)? "matching" : "not matching",
1176 returns_enum_names[value->return_type], line, cur_file);
1177 }
1178
1179 /*
1180 * Validate the return value against the expected value, throw an error
1181 * if they don't match.
1182 */
1183 static void
1184 validate_return(const char *expected, const char *value, int check)
1185 {
1186 if (((check == 0) && strcmp(expected, value) != 0) ||
1187 ((check == 1) && strcmp(expected, value) == 0))
1188 err(1, "Validate expected %s %s %s line %zu of file %s",
1189 expected,
1190 (check == 0)? "matching" : "not matching", value,
1191 line, cur_file);
1192 if (verbose)
1193 fprintf(stderr, "Validated expected value %s %s %s "
1194 "at line %zu of file %s\n", expected,
1195 (check == 0)? "matches" : "does not match",
1196 value, line, cur_file);
1197 }
1198
1199 /*
1200 * Validate the return value against the expected value, throw an error
1201 * if they don't match expectations.
1202 */
1203 static void
1204 validate_byte(returns_t *expected, returns_t *value, int check)
1205 {
1206 /*
1207 * No chance of a match if lengths differ...
1208 */
1209 if ((check == 0) && (expected->return_len != value->return_len))
1210 err(1, "Byte validation failed, length mismatch");
1211
1212 /*
1213 * If check is 0 then we want to throw an error IFF the byte streams
1214 * do not match, if check is 1 then throw an error if the byte
1215 * streams match.
1216 */
1217 if (((check == 0) && memcmp(expected->return_value, value->return_value,
1218 value->return_len) != 0) ||
1219 ((check == 1) && (expected->return_len == value->return_len) &&
1220 memcmp(expected->return_value, value->return_value,
1221 value->return_len) == 0))
1222 err(1, "Validate expected %s byte stream at line %zu"
1223 "of file %s",
1224 (check == 0)? "matching" : "not matching", line, cur_file);
1225 if (verbose)
1226 fprintf(stderr, "Validated expected %s byte stream "
1227 "at line %zu of file %s\n",
1228 (check == 0)? "matching" : "not matching",
1229 line, cur_file);
1230 }
1231
1232 /*
1233 * Validate the variable at i against the expected value, throw an
1234 * error if they don't match, if check is non-zero then the match is
1235 * negated.
1236 */
1237 static void
1238 validate_variable(int ret, returns_enum_t type, const void *value, int i,
1239 int check)
1240 {
1241 returns_t *retval;
1242 var_t *varptr;
1243
1244 retval = &command.returns[ret];
1245 varptr = &vars[command.returns[ret].return_index];
1246
1247 if (varptr->value == NULL)
1248 err(1, "Variable %s has no value assigned to it", varptr->name);
1249
1250
1251 if (varptr->type != type)
1252 err(1, "Variable %s is not the expected type", varptr->name);
1253
1254 if (type != ret_byte) {
1255 if ((((check == 0) && strcmp(value, varptr->value) != 0))
1256 || ((check == 1) && strcmp(value, varptr->value) == 0))
1257 err(1, "Variable %s contains %s instead of %s"
1258 " value %s at line %zu of file %s",
1259 varptr->name, (const char *)varptr->value,
1260 (check == 0)? "expected" : "not matching",
1261 (const char *)value,
1262 line, cur_file);
1263 if (verbose)
1264 fprintf(stderr, "Variable %s contains %s value "
1265 "%s at line %zu of file %s\n",
1266 varptr->name,
1267 (check == 0)? "expected" : "not matching",
1268 (const char *)varptr->value, line, cur_file);
1269 } else {
1270 if ((check == 0) && (retval->return_len != varptr->len))
1271 err(1, "Byte validation failed, length mismatch");
1272
1273 /*
1274 * If check is 0 then we want to throw an error IFF
1275 * the byte streams do not match, if check is 1 then
1276 * throw an error if the byte streams match.
1277 */
1278 if (((check == 0) && memcmp(retval->return_value, varptr->value,
1279 varptr->len) != 0) ||
1280 ((check == 1) && (retval->return_len == varptr->len) &&
1281 memcmp(retval->return_value, varptr->value,
1282 varptr->len) == 0))
1283 err(1, "Validate expected %s byte stream at line %zu"
1284 " of file %s",
1285 (check == 0)? "matching" : "not matching",
1286 line, cur_file);
1287 if (verbose)
1288 fprintf(stderr, "Validated expected %s byte stream "
1289 "at line %zu of file %s\n",
1290 (check == 0)? "matching" : "not matching",
1291 line, cur_file);
1292 }
1293 }
1294
1295 /*
1296 * Write a string to the command pipe - we feed the number of bytes coming
1297 * down first to allow storage allocation and then follow up with the data.
1298 * If cmd is NULL then feed a -1 down the pipe to say the end of the args.
1299 */
1300 static void
1301 write_cmd_pipe(char *cmd)
1302 {
1303 args_t arg;
1304 size_t len;
1305
1306 if (cmd == NULL)
1307 len = 0;
1308 else
1309 len = strlen(cmd);
1310
1311 arg.arg_type = arg_static;
1312 arg.arg_len = len;
1313 arg.arg_string = cmd;
1314 write_cmd_pipe_args(arg.arg_type, &arg);
1315
1316 }
1317
1318 static void
1319 write_cmd_pipe_args(args_state_t type, void *data)
1320 {
1321 var_t *var_data;
1322 args_t *arg_data;
1323 int len, send_type;
1324 void *cmd;
1325
1326 arg_data = data;
1327 switch (type) {
1328 case arg_var:
1329 var_data = data;
1330 len = var_data->len;
1331 cmd = var_data->value;
1332 if (var_data->type == arg_byte)
1333 send_type = ret_byte;
1334 else
1335 send_type = ret_string;
1336 break;
1337
1338 case arg_null:
1339 send_type = ret_null;
1340 len = 0;
1341 break;
1342
1343 default:
1344 if ((arg_data->arg_len == 0) && (arg_data->arg_string == NULL))
1345 len = -1;
1346 else
1347 len = arg_data->arg_len;
1348 cmd = arg_data->arg_string;
1349 if (type == arg_byte)
1350 send_type = ret_byte;
1351 else
1352 send_type = ret_string;
1353 }
1354
1355 if (verbose)
1356 fprintf(stderr, "Writing type %s to command pipe\n",
1357 returns_enum_names[send_type]);
1358
1359 if (write(cmdpipe[WRITE_PIPE], &send_type, sizeof(int)) < 0)
1360 err(1, "command pipe write for type failed");
1361
1362 if (verbose)
1363 fprintf(stderr, "Writing length %d to command pipe\n", len);
1364
1365 if (write(cmdpipe[WRITE_PIPE], &len, sizeof(int)) < 0)
1366 err(1, "command pipe write for length failed");
1367
1368 if (len > 0) {
1369 if (verbose)
1370 fprintf(stderr, "Writing data >%s< to command pipe\n",
1371 (const char *)cmd);
1372 if (write(cmdpipe[WRITE_PIPE], cmd, len) < 0)
1373 err(1, "command pipe write of data failed");
1374 }
1375 }
1376
1377 /*
1378 * Read a response from the command pipe, first we will receive the
1379 * length of the response then the actual data.
1380 */
1381 static void
1382 read_cmd_pipe(returns_t *response)
1383 {
1384 int len, type;
1385 struct pollfd rfd[2];
1386 char *str;
1387
1388 /*
1389 * Check if there is data to read - just in case slave has died, we
1390 * don't want to block on the read and just hang. We also check
1391 * output from the slave because the slave may be blocked waiting
1392 * for a flush on its stdout.
1393 */
1394 rfd[0].fd = slvpipe[READ_PIPE];
1395 rfd[0].events = POLLIN;
1396 rfd[1].fd = master;
1397 rfd[1].events = POLLIN;
1398
1399 do {
1400 rfd[0].revents = 0;
1401 rfd[1].revents = 0;
1402
1403 if (poll(rfd, 2, 4000) == 0)
1404 errx(2, "%s, %zu: Command pipe read timeout",
1405 cur_file, line);
1406
1407 if ((rfd[1].revents & POLLIN) == POLLIN) {
1408 if (verbose)
1409 fprintf(stderr,
1410 "draining output from slave\n");
1411 save_slave_output(false);
1412 }
1413 }
1414 while((rfd[1].revents & POLLIN) == POLLIN);
1415
1416 if (read(slvpipe[READ_PIPE], &type, sizeof(int)) < 0)
1417 err(1, "command pipe read for type failed");
1418 response->return_type = type;
1419
1420 if ((type != ret_ok) && (type != ret_err) && (type != ret_count)) {
1421 if (read(slvpipe[READ_PIPE], &len, sizeof(int)) < 0)
1422 err(1, "command pipe read for length failed");
1423 response->return_len = len;
1424
1425 if (verbose)
1426 fprintf(stderr,
1427 "Reading %d bytes from command pipe\n", len);
1428
1429 if ((response->return_value = malloc(len + 1)) == NULL)
1430 err(1, "Failed to alloc memory for cmd pipe read");
1431
1432 if (read(slvpipe[READ_PIPE], response->return_value, len) < 0)
1433 err(1, "command pipe read of data failed");
1434
1435 if (response->return_type != ret_byte) {
1436 str = response->return_value;
1437 str[len] = '\0';
1438
1439 if (verbose)
1440 fprintf(stderr, "Read data >%s< from pipe\n",
1441 (const char *)response->return_value);
1442 }
1443 } else {
1444 response->return_value = NULL;
1445 if (type == ret_count) {
1446 if (read(slvpipe[READ_PIPE], &len, sizeof(int)) < 0)
1447 err(1, "command pipe read for number of "
1448 "returns failed");
1449 response->return_len = len;
1450 }
1451
1452 if (verbose)
1453 fprintf(stderr, "Read type %s from pipe\n",
1454 returns_enum_names[type]);
1455 }
1456 }
1457
1458 /*
1459 * Check for writes from the slave on the pty, save the output into a
1460 * buffer for later checking if discard is false.
1461 */
1462 #define MAX_DRAIN 256
1463
1464 static void
1465 save_slave_output(bool discard)
1466 {
1467 struct pollfd fd;
1468 char *new_data, drain[MAX_DRAIN];
1469 size_t to_allocate;
1470 ssize_t result;
1471 size_t i;
1472
1473 fd.fd = master;
1474 fd.events = POLLIN;
1475 fd.revents = 0;
1476
1477 result = 0;
1478 while (1) {
1479 if (result == -1)
1480 err(2, "poll of slave pty failed");
1481 result = MAX_DRAIN;
1482 if ((result = read(master, &drain, result)) < 0) {
1483 if (errno == EAGAIN)
1484 break;
1485 else
1486 err(2, "draining slave pty failed");
1487 }
1488
1489 fd.revents = 0;
1490 if (!discard) {
1491 if ((size_t)result >
1492 (saved_output.allocated - saved_output.count)) {
1493 to_allocate = 1024 * ((result / 1024) + 1);
1494
1495 if ((new_data = realloc(saved_output.data,
1496 saved_output.allocated + to_allocate))
1497 == NULL)
1498 err(2, "Realloc of saved_output failed");
1499 saved_output.data = new_data;
1500 saved_output.allocated += to_allocate;
1501 }
1502
1503 if (verbose) {
1504 fprintf(stderr, "count = %zu, "
1505 "allocated = %zu\n", saved_output.count,
1506 saved_output.allocated);
1507 for (i = 0; i < (size_t)result; i++) {
1508 fprintf(stderr, "Saving slave output "
1509 "0x%x (%c)\n", drain[i],
1510 (drain[i] >= ' ')? drain[i] : '-');
1511 }
1512 }
1513
1514 memcpy(&saved_output.data[saved_output.count], drain,
1515 result);
1516 saved_output.count += result;
1517
1518 if (verbose) {
1519 fprintf(stderr, "count = %zu, "
1520 "allocated = %zu\n", saved_output.count,
1521 saved_output.allocated);
1522 }
1523 } else {
1524 if (verbose) {
1525 for (i=0; i < (size_t)result; i++) {
1526 fprintf(stderr, "Discarding slave "
1527 "output 0x%x (%c)\n",
1528 drain[i],
1529 (drain[i] >= ' ')? drain[i] : '-');
1530 }
1531 }
1532 }
1533 }
1534 }
1535
1536 static void
1537 yyerror(const char *msg)
1538 {
1539 warnx("%s in line %zu of file %s", msg, line, cur_file);
1540 }
1541