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