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