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