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