testlang_parse.y revision 1.29 1 %{
2 /* $NetBSD: testlang_parse.y,v 1.29 2021/02/07 18:14:43 rillig 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 <curses.h>
34 #include <errno.h>
35 #include <fcntl.h>
36 #include <err.h>
37 #include <unistd.h>
38 #include <poll.h>
39 #include <stdbool.h>
40 #include <stdio.h>
41 #include <string.h>
42 #include <stdlib.h>
43 #include <limits.h>
44 #include <time.h>
45 #include <vis.h>
46 #include <stdint.h>
47 #include "returns.h"
48 #include "director.h"
49
50 #define YYDEBUG 1
51
52 extern int verbose;
53 extern int check_file_flag;
54 extern int cmdpipe[2];
55 extern int slvpipe[2];
56 extern int master;
57 extern struct pollfd readfd;
58 extern char *check_path;
59 extern char *cur_file; /* from director.c */
60
61 int yylex(void);
62
63 size_t line;
64
65 static int input_delay;
66
67 /* time delay between inputs chars - default to 0.1ms minimum to prevent
68 * problems with input tests
69 */
70 #define DELAY_MIN 0.1
71
72 /* time delay after a function call - allows the slave time to
73 * run the function and output data before we do other actions.
74 * Set this to 50ms.
75 */
76 #define POST_CALL_DELAY 50
77
78 static struct timespec delay_spec = {0, 1000 * DELAY_MIN};
79 static struct timespec delay_post_call = {0, 1000 * POST_CALL_DELAY};
80
81 static char *input_str; /* string to feed in as input */
82 static bool no_input; /* don't need more input */
83
84 static wchar_t *vals = NULL; /* wchars to attach to a cchar type */
85 static unsigned nvals; /* number of wchars */
86
87 #define READ_PIPE 0
88 #define WRITE_PIPE 1
89
90 const char *enum_names[] = {
91 "unused", "static", "numeric", "string", "byte", "cchar", "wchar", "ERR",
92 "OK", "NULL", "not NULL", "variable", "reference", "returns count",
93 "slave error"
94 };
95
96 typedef struct {
97 data_enum_t arg_type;
98 size_t arg_len;
99 char *arg_string;
100 int var_index;
101 } args_t;
102
103 typedef struct {
104 char *function;
105 int nrets; /* number of returns */
106 ct_data_t *returns; /* array of expected returns */
107 int nargs; /* number of arguments */
108 args_t *args; /* arguments for the call */
109 } cmd_line_t;
110
111 static cmd_line_t command;
112
113 typedef struct {
114 char *name;
115 size_t len;
116 data_enum_t type;
117 void *value;
118 cchar_t cchar;
119 } var_t;
120
121 static size_t nvars; /* Number of declared variables */
122 static var_t *vars; /* Variables defined during the test. */
123
124 static int check_function_table(char *, const char *[], int);
125 static int find_var_index(const char *);
126 static void assign_arg(data_enum_t, void *);
127 static int assign_var(char *);
128 void init_parse_variables(int);
129 static void validate(int, void *);
130 static void validate_return(const char *, const char *, int);
131 static void validate_variable(int, data_enum_t, const void *, int, int);
132 static void validate_byte(ct_data_t *, ct_data_t *, int);
133 static void validate_cchar(cchar_t *, cchar_t *, int);
134 static void validate_wchar(wchar_t *, wchar_t *, int);
135 static void write_cmd_pipe(char *);
136 static void write_cmd_pipe_args(data_enum_t, void *);
137 static void read_cmd_pipe(ct_data_t *);
138 static void write_func_and_args(void);
139 static void compare_streams(char *, bool);
140 static void do_function_call(size_t);
141 static void save_slave_output(bool);
142 static void validate_type(data_enum_t, ct_data_t *, int);
143 static void set_var(data_enum_t, char *, void *);
144 static void validate_reference(int, void *);
145 static char * numeric_or(char *, char *);
146 static char * get_numeric_var(const char *);
147 static void perform_delay(struct timespec *);
148 static void set_cchar(char *, void *);
149 static void set_wchar(char *);
150 static wchar_t *add_to_vals(data_enum_t, void *);
151
152 static const char *input_functions[] = {
153 "getch", "mvgetch", "mvwgetch", "wgetch", "getnstr", "getstr", "mvgetnstr",
154 "mvgetstr", "mvwgetnstr", "mvwgetstr", "wgetnstr", "wgetstr", "mvscanw",
155 "mvwscanw", "scanw", "wscanw", "get_wch", "mvget_wch", "mvwget_wch",
156 "wget_wch", "getn_wstr", "get_wstr", "mvgetn_wstr", "mvget_wstr",
157 "mvwgetn_wstr","mvwget_wstr", "wgetn_wstr", "wget_wstr"
158 };
159
160 static const unsigned ninput_functions =
161 sizeof(input_functions) / sizeof(char *);
162
163 extern saved_data_t saved_output;
164
165 %}
166
167 %union {
168 char *string;
169 ct_data_t *retval;
170 wchar_t *vals;
171 }
172
173 %token <string> PATH
174 %token <string> STRING
175 %token <retval> BYTE
176 %token <string> VARNAME
177 %token <string> FILENAME
178 %token <string> VARIABLE
179 %token <string> REFERENCE
180 %token <string> NULL_RET
181 %token <string> NON_NULL
182 %token <string> ERR_RET
183 %token <string> OK_RET
184 %token <string> numeric
185 %token <string> DELAY
186 %token <string> INPUT
187 %token <string> COMPARE
188 %token <string> COMPAREND
189 %token <string> ASSIGN
190 %token <string> CCHAR
191 %token <string> WCHAR
192 %token EOL CALL CHECK NOINPUT OR MULTIPLIER LPAREN RPAREN LBRACK RBRACK
193 %token CALL2 CALL3 CALL4 DRAIN
194
195 %nonassoc OR
196
197 %%
198
199 statements : /* empty */
200 | statement eol statements
201 ;
202
203 statement : assign
204 | call
205 | call2
206 | call3
207 | call4
208 | check
209 | delay
210 | input
211 | noinput
212 | compare
213 | comparend
214 | cchar
215 | wchar
216 | /* empty */
217 ;
218
219 assign : ASSIGN VARNAME numeric {
220 set_var(data_number, $2, $3);
221 }
222 | ASSIGN VARNAME LPAREN expr RPAREN {
223 set_var(data_number, $2, $<string>4);
224 }
225 | ASSIGN VARNAME STRING {
226 set_var(data_string, $2, $3);
227 }
228 | ASSIGN VARNAME BYTE {
229 set_var(data_byte, $2, $3);
230 }
231 ;
232
233 cchar : CCHAR VARNAME attributes char_vals {
234 set_cchar($2, $<string>3);
235 }
236 ;
237
238 wchar : WCHAR VARNAME char_vals {
239 set_wchar($2);
240 }
241 ;
242
243 attributes : numeric
244 | LPAREN expr RPAREN {
245 $<string>$ = $<string>2;
246 }
247 | VARIABLE {
248 $<string>$ = get_numeric_var($1);
249 }
250 ;
251
252 char_vals : numeric {
253 add_to_vals(data_number, $1);
254 }
255 | LBRACK array RBRACK
256 | VARIABLE {
257 add_to_vals(data_var, $1);
258 }
259 | STRING {
260 add_to_vals(data_string, $1);
261 }
262 | BYTE {
263 add_to_vals(data_byte, $1);
264 }
265 ;
266
267 call : CALL result fn_name args {
268 do_function_call(1);
269 }
270 ;
271
272 call2 : CALL2 result result fn_name args {
273 do_function_call(2);
274 }
275 ;
276
277 call3 : CALL3 result result result fn_name args {
278 do_function_call(3);
279 }
280 ;
281
282 call4 : CALL4 result result result result fn_name args {
283 do_function_call(4);
284 }
285 ;
286
287 check : CHECK var returns {
288 ct_data_t retvar;
289 var_t *vptr;
290
291 if (command.returns[0].data_index == -1)
292 err(1, "Undefined variable in check statement, line %zu"
293 " of file %s", line, cur_file);
294
295 if (command.returns[1].data_type == data_var) {
296 vptr = &vars[command.returns[1].data_index];
297 command.returns[1].data_type = vptr->type;
298 command.returns[1].data_len = vptr->len;
299 if (vptr->type != data_cchar)
300 command.returns[1].data_value = vptr->value;
301 else
302 command.returns[1].data_value = &vptr->cchar;
303 }
304
305 if (verbose) {
306 fprintf(stderr, "Checking contents of variable %s for %s\n",
307 vars[command.returns[0].data_index].name,
308 enum_names[command.returns[1].data_type]);
309 }
310
311 /*
312 * Check if var and return have same data types
313 */
314 if (((command.returns[1].data_type == data_byte) &&
315 (vars[command.returns[0].data_index].type != data_byte)))
316 err(1, "Var type %s (%d) does not match return type %s (%d)",
317 enum_names[
318 vars[command.returns[0].data_index].type],
319 vars[command.returns[0].data_index].type,
320 enum_names[command.returns[1].data_type],
321 command.returns[1].data_type);
322
323 switch (command.returns[1].data_type) {
324 case data_err:
325 case data_ok:
326 validate_type(vars[command.returns[0].data_index].type,
327 &command.returns[1], 0);
328 break;
329
330 case data_null:
331 validate_variable(0, data_string, "NULL",
332 command.returns[0].data_index, 0);
333 break;
334
335 case data_nonnull:
336 validate_variable(0, data_string, "NULL",
337 command.returns[0].data_index, 1);
338 break;
339
340 case data_string:
341 case data_number:
342 if (verbose) {
343 fprintf(stderr, " %s == returned %s\n",
344 (const char *)command.returns[1].data_value,
345 (const char *)
346 vars[command.returns[0].data_index].value);
347 }
348 validate_variable(0, data_string,
349 command.returns[1].data_value,
350 command.returns[0].data_index, 0);
351 break;
352
353 case data_byte:
354 vptr = &vars[command.returns[0].data_index];
355 retvar.data_len = vptr->len;
356 retvar.data_type = vptr->type;
357 retvar.data_value = vptr->value;
358 validate_byte(&retvar, &command.returns[1], 0);
359 break;
360
361 case data_cchar:
362 validate_cchar(&vars[command.returns[0].data_index].cchar,
363 (cchar_t *) command.returns[1].data_value, 0);
364 break;
365
366 case data_wchar:
367 validate_wchar((wchar_t *) vars[command.returns[0].data_index].value,
368 (wchar_t *) command.returns[1].data_value, 0);
369 break;
370
371 default:
372 err(1, "Malformed check statement at line %zu "
373 "of file %s", line, cur_file);
374 break;
375 }
376
377 init_parse_variables(0);
378 }
379 ;
380
381 delay : DELAY numeric {
382 /* set the inter-character delay */
383 if (sscanf($2, "%d", &input_delay) == 0)
384 err(1, "delay specification %s could not be converted to "
385 "numeric at line %zu of file %s", $2, line, cur_file);
386 if (verbose) {
387 fprintf(stderr, "Set input delay to %d ms\n", input_delay);
388 }
389
390 if (input_delay < DELAY_MIN)
391 input_delay = DELAY_MIN;
392 /*
393 * Fill in the timespec structure now ready for use later.
394 * The delay is specified in milliseconds so convert to timespec
395 * values
396 */
397 delay_spec.tv_sec = input_delay / 1000;
398 delay_spec.tv_nsec = (input_delay - 1000 * delay_spec.tv_sec) * 1000;
399 if (verbose) {
400 fprintf(stderr, "set delay to %jd.%jd\n",
401 (intmax_t)delay_spec.tv_sec,
402 (intmax_t)delay_spec.tv_nsec);
403 }
404
405 init_parse_variables(0);
406 }
407 ;
408
409 input : INPUT STRING {
410 if (input_str != NULL) {
411 warnx("%s, %zu: Discarding unused input string",
412 cur_file, line);
413 free(input_str);
414 }
415
416 if ((input_str = malloc(strlen($2) + 1)) == NULL)
417 err(2, "Cannot allocate memory for input string");
418
419 strlcpy(input_str, $2, strlen($2) + 1);
420 }
421 ;
422
423
424 noinput : NOINPUT {
425 if (input_str != NULL) {
426 warnx("%s, %zu: Discarding unused input string",
427 cur_file, line);
428 free(input_str);
429 }
430
431 no_input = true;
432 }
433
434 compare : COMPARE PATH {
435 compare_streams($2, true);
436 }
437 | COMPARE FILENAME {
438 compare_streams($2, true);
439 }
440 ;
441
442 comparend : COMPAREND PATH {
443 compare_streams($2, false);
444 }
445 | COMPAREND FILENAME {
446 compare_streams($2, false);
447 }
448 ;
449
450
451 result : returns
452 | reference
453 ;
454
455 returns : numeric { assign_rets(data_number, $1); }
456 | LPAREN expr RPAREN { assign_rets(data_number, $<string>2); }
457 | STRING { assign_rets(data_string, $1); }
458 | BYTE { assign_rets(data_byte, (void *) $1); }
459 | ERR_RET { assign_rets(data_err, NULL); }
460 | OK_RET { assign_rets(data_ok, NULL); }
461 | NULL_RET { assign_rets(data_null, NULL); }
462 | NON_NULL { assign_rets(data_nonnull, NULL); }
463 | var
464 ;
465
466 var : VARNAME {
467 assign_rets(data_var, $1);
468 }
469 ;
470
471 reference : VARIABLE {
472 assign_rets(data_ref, $1);
473 }
474 /* XXX: missing semicolon; how does yacc interpret this? */
475
476 fn_name : VARNAME {
477 if (command.function != NULL)
478 free(command.function);
479
480 command.function = malloc(strlen($1) + 1);
481 if (command.function == NULL)
482 err(1, "Could not allocate memory for function name");
483 strcpy(command.function, $1);
484 }
485 ;
486
487 array : numeric {
488 $<vals>$ = add_to_vals(data_number, $1);
489 }
490 ; /* XXX: extra semicolon; yacc seems to ignore this. */
491 | VARIABLE {
492 $<vals>$ = add_to_vals(data_number,
493 get_numeric_var($1));
494 }
495 | BYTE {
496 $<vals>$ = add_to_vals(data_byte, (void *) $1);
497 }
498 | STRING {
499 $<vals>$ = add_to_vals(data_string, (void *) $1);
500 }
501 | numeric MULTIPLIER numeric {
502 unsigned long i;
503 unsigned long acount;
504
505 acount = strtoul($3, NULL, 10);
506 for (i = 0; i < acount; i++) {
507 $<vals>$ = add_to_vals(data_number, $1);
508 }
509 }
510 | VARIABLE MULTIPLIER numeric {
511 unsigned long i, acount;
512 char *val;
513
514 acount = strtoul($3, NULL, 10);
515 val = get_numeric_var($1);
516 for (i = 0; i < acount; i++) {
517 $<vals>$ = add_to_vals(data_number, val);
518 }
519 }
520 | BYTE MULTIPLIER numeric {
521 unsigned long i, acount;
522
523 acount = strtoul($3, NULL, 10);
524 for (i = 0; i < acount; i++) {
525 $<vals>$ = add_to_vals(data_byte, (void *) $1);
526 }
527 }
528 | STRING MULTIPLIER numeric {
529 unsigned long i, acount;
530
531 acount = strtoul($3, NULL, 10);
532 for (i = 0; i < acount; i++) {
533 $<vals>$ = add_to_vals(data_string,
534 (void *) $1);
535 }
536 }
537 | array array
538 ;
539
540 expr : numeric
541 | VARIABLE {
542 $<string>$ = get_numeric_var($1);
543 }
544 | expr OR expr {
545 $<string>$ = numeric_or($<string>1, $<string>3);
546 }
547 ;
548
549 args : /* empty */
550 | arg args
551 ;
552
553 arg : LPAREN expr RPAREN {
554 assign_arg(data_static, $<string>2);
555 }
556 | numeric {
557 assign_arg(data_static, $1);
558 }
559 | STRING {
560 assign_arg(data_static, $1);
561 }
562 | BYTE {
563 assign_arg(data_byte, $1);
564 }
565 | PATH {
566 assign_arg(data_static, $1);
567 }
568 | FILENAME {
569 assign_arg(data_static, $1);
570 }
571 | VARNAME {
572 assign_arg(data_static, $1);
573 }
574 | VARIABLE {
575 assign_arg(data_var, $1);
576 }
577 | NULL_RET {
578 assign_arg(data_null, $1);
579 }
580 ;
581
582 eol : EOL
583 ;
584
585 %%
586
587 static void
588 excess(const char *fname, size_t lineno, const char *func, const char *comment,
589 const void *data, size_t datalen)
590 {
591 size_t dstlen = datalen * 4 + 1;
592 char *dst = malloc(dstlen);
593
594 if (dst == NULL)
595 err(1, "malloc");
596
597 if (strnvisx(dst, dstlen, data, datalen, VIS_WHITE | VIS_OCTAL) == -1)
598 err(1, "strnvisx");
599
600 warnx("%s, %zu: [%s] Excess %zu bytes%s [%s]",
601 fname, lineno, func, datalen, comment, dst);
602 free(dst);
603 }
604
605 /*
606 * Get the value of a variable, error if the variable has not been set or
607 * is not a numeric type.
608 */
609 static char *
610 get_numeric_var(const char *var)
611 {
612 int i;
613
614 if ((i = find_var_index(var)) < 0)
615 err(1, "Variable %s is undefined", var);
616
617 if (vars[i].type != data_number)
618 err(1, "Variable %s is not a numeric type", var);
619
620 return vars[i].value;
621 }
622
623 /*
624 * Perform a bitwise OR on two numbers and return the result.
625 */
626 static char *
627 numeric_or(char *n1, char *n2)
628 {
629 unsigned long i1, i2, result;
630 char *ret;
631
632 i1 = strtoul(n1, NULL, 10);
633 i2 = strtoul(n2, NULL, 10);
634
635 result = i1 | i2;
636 asprintf(&ret, "%lu", result);
637
638 if (verbose) {
639 fprintf(stderr, "numeric or of 0x%lx (%s) and 0x%lx (%s)"
640 " results in 0x%lx (%s)\n",
641 i1, n1, i2, n2, result, ret);
642 }
643
644 return ret;
645 }
646
647 /*
648 * Sleep for the specified time, handle the sleep getting interrupted
649 * by a signal.
650 */
651 static void
652 perform_delay(struct timespec *ts)
653 {
654 struct timespec delay_copy, delay_remainder;
655
656 delay_copy = *ts;
657 while (nanosleep(&delay_copy, &delay_remainder) < 0) {
658 if (errno != EINTR)
659 err(2, "nanosleep returned error");
660 delay_copy = delay_remainder;
661 }
662 }
663
664 /*
665 * Add to temporary vals array
666 */
667 static wchar_t *add_to_vals(data_enum_t argtype, void *arg)
668 {
669 wchar_t *retval = NULL;
670 int have_malloced;
671 int i;
672 ct_data_t *ret;
673
674 have_malloced = 0;
675
676 if (nvals == 0) {
677 have_malloced = 1;
678 retval = malloc(sizeof(wchar_t));
679 } else {
680 retval = realloc(vals, (nvals + 1) * sizeof(wchar_t));
681 }
682
683 if (retval == NULL)
684 return retval;
685
686 vals = retval;
687
688 switch (argtype) {
689 case data_number:
690 vals[nvals++] = (wchar_t) strtoul((char *) arg, NULL, 10);
691 break;
692
693 case data_string:
694 vals[nvals++] = (wchar_t) ((char *)arg)[0];
695 break;
696
697 case data_byte:
698 ret = (ct_data_t *) arg;
699 vals[nvals++] = *((wchar_t *) ret->data_value);
700 break;
701
702 case data_var:
703 if ((i = find_var_index((char *) arg)) < 0)
704 err(1, "Variable %s is undefined at line %zu "
705 "of file %s", (char *) arg, line, cur_file);
706
707 switch (vars[i].type) {
708
709 case data_number:
710 case data_string:
711 case data_byte:
712 retval = add_to_vals(vars[i].type, vars[i].value);
713 break;
714
715 default:
716 err(1, "Variable %s is not a valid type for cchar"
717 " at line %zu of file %s", (char *) arg, line,
718 cur_file);
719 break;
720
721 }
722 break;
723
724 default:
725 err(1, "add_to_vals: Unhandled type for vals array "
726 "at line %zu of file %s", line, cur_file);
727
728 /* if we get here without a value then tidy up */
729 if ((nvals == 0) && (have_malloced == 1)) {
730 free(retval);
731 retval = vals;
732 }
733 break;
734
735 }
736
737 return retval;
738 }
739
740 /*
741 * Assign the value given to the named variable.
742 */
743 static void
744 set_var(data_enum_t type, char *name, void *value)
745 {
746 int i;
747 char *number;
748 ct_data_t *ret;
749
750 i = find_var_index(name);
751 if (i < 0)
752 i = assign_var(name);
753
754 vars[i].type = type;
755 if ((type == data_number) || (type == data_string)) {
756 number = value;
757 vars[i].len = strlen(number) + 1;
758 vars[i].value = malloc(vars[i].len + 1);
759 if (vars[i].value == NULL)
760 err(1, "Could not malloc memory for assign string");
761 strcpy(vars[i].value, number);
762 } else {
763 /* can only be a byte value */
764 ret = value;
765 vars[i].len = ret->data_len;
766 vars[i].value = malloc(vars[i].len);
767 if (vars[i].value == NULL)
768 err(1, "Could not malloc memory to assign byte string");
769 memcpy(vars[i].value, ret->data_value, vars[i].len);
770 }
771 }
772
773 /*
774 * Form up a complex character type from the given components.
775 */
776 static void
777 set_cchar(char *name, void *attributes)
778 {
779 int i;
780 unsigned j;
781 attr_t attribs;
782
783 if (nvals >= CURSES_CCHAR_MAX)
784 err(1, "%s: too many characters in complex char type at "
785 "line %zu of file %s", __func__, line, cur_file);
786
787 i = find_var_index(name);
788 if (i < 0)
789 i = assign_var(name);
790
791 if (sscanf((char *) attributes, "%d", &attribs) != 1)
792 err(1, "%s: conversion of attributes to integer failed at"
793 "line %zu of file %s", __func__, line, cur_file);
794
795 vars[i].type = data_cchar;
796 vars[i].cchar.attributes = attribs;
797 vars[i].cchar.elements = nvals;
798 for (j = 0; j < nvals; j++)
799 vars[i].cchar.vals[j] = vals[j];
800
801 nvals = 0;
802 vals = NULL;
803
804 }
805
806 /*
807 * Form up a wide character string type from the given components.
808 */
809 static void
810 set_wchar(char *name)
811 {
812 int i;
813 unsigned j;
814 wchar_t *wcval;
815
816 i = find_var_index(name);
817 if (i < 0)
818 i = assign_var(name);
819
820 vars[i].type = data_wchar;
821 vars[i].len = (nvals+1) * sizeof(wchar_t);
822 vars[i].value = malloc(vars[i].len);
823 if (vars[i].value == NULL)
824 err(1, "Could not malloc memory to assign wchar string");
825 wcval = vars[i].value;
826 for(j = 0; j < nvals; j++)
827 wcval[j] = vals[j];
828 wcval[nvals] = L'\0';
829 nvals = 0;
830 vals = NULL;
831
832 }
833
834 /*
835 * Add a new variable to the vars array, the value will be assigned later,
836 * when a test function call returns.
837 */
838 static int
839 assign_var(char *varname)
840 {
841 var_t *temp;
842 char *name;
843
844 if ((name = malloc(strlen(varname) + 1)) == NULL)
845 err(1, "Alloc of varname failed");
846
847 if ((temp = realloc(vars, sizeof(*temp) * (nvars + 1))) == NULL) {
848 free(name);
849 err(1, "Realloc of vars array failed");
850 }
851
852 strcpy(name, varname);
853 vars = temp;
854 vars[nvars].name = name;
855 vars[nvars].len = 0;
856 vars[nvars].value = NULL;
857 nvars++;
858
859 return (nvars - 1);
860 }
861
862 /*
863 * Allocate and assign a new argument of the given type.
864 */
865 static void
866 assign_arg(data_enum_t arg_type, void *arg)
867 {
868 args_t *temp, cur;
869 char *str = arg;
870 ct_data_t *ret;
871
872 if (verbose) {
873 fprintf(stderr, "function is >%s<, adding arg >%s< type %s (%d)\n",
874 command.function, str, enum_names[arg_type], arg_type);
875 }
876
877 cur.arg_type = arg_type;
878 if (cur.arg_type == data_var) {
879 cur.var_index = find_var_index(arg);
880 if (cur.var_index < 0)
881 err(1, "Invalid variable %s at line %zu of file %s",
882 str, line, cur_file);
883 } else if (cur.arg_type == data_byte) {
884 ret = arg;
885 cur.arg_len = ret->data_len;
886 cur.arg_string = malloc(cur.arg_len);
887 if (cur.arg_string == NULL)
888 err(1, "Could not malloc memory for arg bytes");
889 memcpy(cur.arg_string, ret->data_value, cur.arg_len);
890 } else if (cur.arg_type == data_null) {
891 cur.arg_len = 0;
892 cur.arg_string = NULL;
893 } else {
894 cur.arg_len = strlen(str);
895 cur.arg_string = malloc(cur.arg_len + 1);
896 if (cur.arg_string == NULL)
897 err(1, "Could not malloc memory for arg string");
898 strcpy(cur.arg_string, arg);
899 }
900
901 temp = realloc(command.args, sizeof(*temp) * (command.nargs + 1));
902 if (temp == NULL)
903 err(1, "Failed to reallocate args");
904 command.args = temp;
905 memcpy(&command.args[command.nargs], &cur, sizeof(args_t));
906 command.nargs++;
907 }
908
909 /*
910 * Allocate and assign a new return.
911 */
912 static void
913 assign_rets(data_enum_t ret_type, void *ret)
914 {
915 ct_data_t *temp, cur;
916 char *ret_str;
917 ct_data_t *ret_ret;
918
919 cur.data_type = ret_type;
920 if (ret_type != data_var) {
921 if ((ret_type == data_number) || (ret_type == data_string)) {
922 ret_str = ret;
923 cur.data_len = strlen(ret_str) + 1;
924 cur.data_value = malloc(cur.data_len + 1);
925 if (cur.data_value == NULL)
926 err(1,
927 "Could not malloc memory for arg string");
928 strcpy(cur.data_value, ret_str);
929 } else if (ret_type == data_byte) {
930 ret_ret = ret;
931 cur.data_len = ret_ret->data_len;
932 cur.data_value = malloc(cur.data_len);
933 if (cur.data_value == NULL)
934 err(1,
935 "Could not malloc memory for byte string");
936 memcpy(cur.data_value, ret_ret->data_value,
937 cur.data_len);
938 } else if (ret_type == data_ref) {
939 if ((cur.data_index = find_var_index(ret)) < 0)
940 err(1, "Undefined variable reference");
941 }
942 } else {
943 cur.data_index = find_var_index(ret);
944 if (cur.data_index < 0)
945 cur.data_index = assign_var(ret);
946 }
947
948 temp = realloc(command.returns, sizeof(*temp) * (command.nrets + 1));
949 if (temp == NULL)
950 err(1, "Failed to reallocate returns");
951 command.returns = temp;
952 memcpy(&command.returns[command.nrets], &cur, sizeof(ct_data_t));
953 command.nrets++;
954 }
955
956 /*
957 * Find the given variable name in the var array and return the i
958 * return -1 if var is not found.
959 */
960 static int
961 find_var_index(const char *var_name)
962 {
963 int result;
964 size_t i;
965
966 result = -1;
967
968 for (i = 0; i < nvars; i++) {
969 if (strcmp(var_name, vars[i].name) == 0) {
970 result = i;
971 break;
972 }
973 }
974
975 return result;
976 }
977
978 /*
979 * Check the given function name in the given table of names, return 1 if
980 * there is a match.
981 */
982 static int check_function_table(char *function, const char *table[],
983 int nfunctions)
984 {
985 int i;
986
987 for (i = 0; i < nfunctions; i++) {
988 if ((strlen(function) == strlen(table[i])) &&
989 (strcmp(function, table[i]) == 0))
990 return 1;
991 }
992
993 return 0;
994 }
995
996 /*
997 * Compare the output from the slave against the given file and report
998 * any differences.
999 */
1000 static void
1001 compare_streams(char *filename, bool discard)
1002 {
1003 char check_file[PATH_MAX], drain[100], ref, data;
1004 struct pollfd fds[2];
1005 int nfd, check_fd;
1006 ssize_t result;
1007 size_t offs;
1008
1009 /*
1010 * Don't prepend check path iff check file has an absolute
1011 * path.
1012 */
1013 if (filename[0] != '/') {
1014 if (strlcpy(check_file, check_path, sizeof(check_file))
1015 >= sizeof(check_file))
1016 err(2, "CHECK_PATH too long");
1017
1018 if (strlcat(check_file, "/", sizeof(check_file))
1019 >= sizeof(check_file))
1020 err(2, "Could not append / to check file path");
1021 } else {
1022 check_file[0] = '\0';
1023 }
1024
1025 if (strlcat(check_file, filename, sizeof(check_file))
1026 >= sizeof(check_file))
1027 err(2, "Path to check file path overflowed");
1028
1029 int create_check_file = 0;
1030
1031 if (check_file_flag == (GEN_CHECK_FILE | FORCE_GEN))
1032 create_check_file = 1;
1033 else if ((check_fd = open(check_file, O_RDONLY, 0)) < 0) {
1034 if (check_file_flag & GEN_CHECK_FILE)
1035 create_check_file = 1;
1036 else
1037 err(2, "failed to open file %s line %zu of file %s",
1038 check_file, line, cur_file);
1039 }
1040
1041 if (create_check_file) {
1042 check_fd = open(check_file, O_WRONLY | O_CREAT, 0644);
1043 if (check_fd < 0) {
1044 err(2, "failed to create file %s line %zu of file %s",
1045 check_file, line, cur_file);
1046 }
1047 }
1048
1049 fds[0].fd = check_fd;
1050 fds[0].events = create_check_file ? POLLOUT:POLLIN;
1051 fds[1].fd = master;
1052 fds[1].events = POLLIN;
1053
1054 nfd = 2;
1055 /*
1056 * if we have saved output then only check for data in the
1057 * reference file since the slave data may already be drained.
1058 */
1059 if (saved_output.count > 0)
1060 nfd = 1;
1061
1062 offs = 0;
1063 while (poll(fds, nfd, 500) == nfd) {
1064 /* Read from check file if doing comparison */
1065 if (!create_check_file) {
1066 if (fds[0].revents & POLLIN) {
1067 if ((result = read(check_fd, &ref, 1)) < 1) {
1068 if (result != 0) {
1069 err(2, "Bad read on file %s",
1070 check_file);
1071 } else {
1072 break;
1073 }
1074 }
1075 }
1076 }
1077
1078 if (saved_output.count > 0) {
1079 data = saved_output.data[saved_output.readp];
1080 saved_output.count--;
1081 saved_output.readp++;
1082 /* run out of saved data, switch to file */
1083 if (saved_output.count == 0)
1084 nfd = 2;
1085 } else {
1086 int revent = (create_check_file == 1) ? POLLOUT:POLLIN;
1087 if (fds[0].revents & revent) {
1088 if (read(master, &data, 1) < 1)
1089 err(2, "Bad read on slave pty");
1090 } else
1091 continue;
1092 }
1093
1094 if (create_check_file) {
1095 if ((result = write(check_fd, &data, 1)) < 1)
1096 err(2, "Bad write on file %s", check_file);
1097 ref = data;
1098 }
1099
1100 if (verbose) {
1101 if (create_check_file)
1102 fprintf(stderr, "Saving reference byte 0x%x (%c)"
1103 " against slave byte 0x%x (%c)\n",
1104 ref, (ref >= ' ') ? ref : '-',
1105 data, (data >= ' ' )? data : '-');
1106 else
1107 fprintf(stderr, "Comparing reference byte 0x%x (%c)"
1108 " against slave byte 0x%x (%c)\n",
1109 ref, (ref >= ' ') ? ref : '-',
1110 data, (data >= ' ' )? data : '-');
1111 }
1112
1113 if (!create_check_file && ref != data) {
1114 errx(2, "%s, %zu: refresh data from slave does "
1115 "not match expected from file %s offs %zu "
1116 "[reference 0x%x (%c) != slave 0x%x (%c)]",
1117 cur_file, line, check_file, offs,
1118 ref, (ref >= ' ') ? ref : '-',
1119 data, (data >= ' ') ? data : '-');
1120 }
1121
1122 offs++;
1123 }
1124
1125 /*
1126 * if creating a check file, there shouldn't be
1127 * anymore saved output
1128 */
1129 if (saved_output.count > 0) {
1130 if (create_check_file)
1131 err(2, "Slave output not flushed correctly");
1132 else
1133 excess(cur_file, line, __func__, " from slave",
1134 &saved_output.data[saved_output.readp], saved_output.count);
1135 }
1136
1137 /* discard any excess saved output if required */
1138 if (discard) {
1139 saved_output.count = 0;
1140 saved_output.readp = 0;
1141 }
1142
1143 if (!create_check_file && (result = poll(fds, 2, 0)) != 0) {
1144 if (result == -1)
1145 err(2, "poll of file descriptors failed");
1146
1147 if ((fds[1].revents & POLLIN) == POLLIN) {
1148 save_slave_output(true);
1149 } else if ((fds[0].revents & POLLIN) == POLLIN) {
1150 /*
1151 * handle excess in file if it exists. Poll
1152 * says there is data until EOF is read.
1153 * Check next read is EOF, if it is not then
1154 * the file really has more data than the
1155 * slave produced so flag this as a warning.
1156 */
1157 result = read(check_fd, drain, sizeof(drain));
1158 if (result == -1)
1159 err(1, "read of data file failed");
1160
1161 if (result > 0) {
1162 excess(check_file, 0, __func__, "", drain,
1163 result);
1164 }
1165 }
1166 }
1167
1168 close(check_fd);
1169 }
1170
1171 /*
1172 * Pass a function call and arguments to the slave and wait for the
1173 * results. The variable nresults determines how many returns we expect
1174 * back from the slave. These results will be validated against the
1175 * expected returns or assigned to variables.
1176 */
1177 static void
1178 do_function_call(size_t nresults)
1179 {
1180 #define MAX_RESULTS 4
1181 char *p;
1182 int do_input;
1183 size_t i;
1184 struct pollfd fds[3];
1185 ct_data_t response[MAX_RESULTS], returns_count;
1186 assert(nresults <= MAX_RESULTS);
1187
1188 do_input = check_function_table(command.function, input_functions,
1189 ninput_functions);
1190
1191 write_func_and_args();
1192
1193 /*
1194 * We should get the number of returns back here, grab it before
1195 * doing input otherwise it will confuse the input poll
1196 */
1197 read_cmd_pipe(&returns_count);
1198 if (returns_count.data_type != data_count)
1199 err(2, "expected return type of data_count but received %s",
1200 enum_names[returns_count.data_type]);
1201
1202 perform_delay(&delay_post_call); /* let slave catch up */
1203
1204 if (verbose) {
1205 fprintf(stderr, "Expect %zu results from slave, slave "
1206 "reported %zu\n", nresults, returns_count.data_len);
1207 }
1208
1209 if ((no_input == false) && (do_input == 1)) {
1210 if (verbose) {
1211 fprintf(stderr, "doing input with inputstr >%s<\n",
1212 input_str);
1213 }
1214
1215 if (input_str == NULL)
1216 errx(2, "%s, %zu: Call to input function "
1217 "but no input defined", cur_file, line);
1218
1219 fds[0].fd = slvpipe[READ_PIPE];
1220 fds[0].events = POLLIN;
1221 fds[1].fd = master;
1222 fds[1].events = POLLOUT;
1223 p = input_str;
1224 save_slave_output(false);
1225 while(*p != '\0') {
1226 perform_delay(&delay_spec);
1227
1228 if (poll(fds, 2, 0) < 0)
1229 err(2, "poll failed");
1230 if (fds[0].revents & POLLIN) {
1231 warnx("%s, %zu: Slave function "
1232 "returned before end of input string",
1233 cur_file, line);
1234 break;
1235 }
1236 if ((fds[1].revents & POLLOUT) == 0)
1237 continue;
1238 if (verbose) {
1239 fprintf(stderr, "Writing char >%c< to slave\n",
1240 *p);
1241 }
1242 if (write(master, p, 1) != 1) {
1243 warn("%s, %zu: Slave function write error",
1244 cur_file, line);
1245 break;
1246 }
1247 p++;
1248
1249 }
1250 save_slave_output(false);
1251
1252 if (verbose) {
1253 fprintf(stderr, "Input done.\n");
1254 }
1255
1256 /* done with the input string, free the resources */
1257 free(input_str);
1258 input_str = NULL;
1259 }
1260
1261 if (verbose) {
1262 fds[0].fd = slvpipe[READ_PIPE];
1263 fds[0].events = POLLIN;
1264
1265 fds[1].fd = slvpipe[WRITE_PIPE];
1266 fds[1].events = POLLOUT;
1267
1268 fds[2].fd = master;
1269 fds[2].events = POLLIN | POLLOUT;
1270
1271 i = poll(&fds[0], 3, 1000);
1272 fprintf(stderr, "Poll returned %zu\n", i);
1273 for (i = 0; i < 3; i++) {
1274 fprintf(stderr, "revents for fd[%zu] = 0x%x\n",
1275 i, fds[i].revents);
1276 }
1277 }
1278
1279 /* drain any trailing output */
1280 save_slave_output(false);
1281
1282 for (i = 0; i < returns_count.data_len; i++) {
1283 read_cmd_pipe(&response[i]);
1284 }
1285
1286 /*
1287 * Check for a slave error in the first return slot, if the
1288 * slave errored then we may not have the number of returns we
1289 * expect but in this case we should report the slave error
1290 * instead of a return count mismatch.
1291 */
1292 if ((returns_count.data_len > 0) &&
1293 (response[0].data_type == data_slave_error))
1294 err(2, "Slave returned error: %s",
1295 (const char *)response[0].data_value);
1296
1297 if (returns_count.data_len != nresults)
1298 err(2, "Incorrect number of returns from slave, expected %zu "
1299 "but received %zu", nresults, returns_count.data_len);
1300
1301 if (verbose) {
1302 for (i = 0; i < nresults; i++) {
1303 if ((response[i].data_type != data_byte) &&
1304 (response[i].data_type != data_err) &&
1305 (response[i].data_type != data_ok))
1306 fprintf(stderr,
1307 "received response >%s< "
1308 "expected",
1309 (const char *)response[i].data_value);
1310 else
1311 fprintf(stderr, "received");
1312
1313 fprintf(stderr, " data_type %s\n",
1314 enum_names[command.returns[i].data_type]);
1315 }
1316 }
1317
1318 for (i = 0; i < nresults; i++) {
1319 if (command.returns[i].data_type != data_var) {
1320 validate(i, &response[i]);
1321 } else {
1322 vars[command.returns[i].data_index].len =
1323 response[i].data_len;
1324
1325 if (response[i].data_type == data_cchar) {
1326 vars[command.returns[i].data_index].cchar =
1327 *((cchar_t *)response[i].data_value);
1328 } else {
1329 vars[command.returns[i].data_index].value =
1330 response[i].data_value;
1331 }
1332
1333 vars[command.returns[i].data_index].type =
1334 response[i].data_type;
1335 }
1336 }
1337
1338 if (verbose && (saved_output.count > 0))
1339 excess(cur_file, line, __func__, " from slave",
1340 &saved_output.data[saved_output.readp], saved_output.count);
1341
1342 init_parse_variables(0);
1343 }
1344
1345 /*
1346 * Write the function and command arguments to the command pipe.
1347 */
1348 static void
1349 write_func_and_args(void)
1350 {
1351 int i;
1352
1353 if (verbose) {
1354 fprintf(stderr, "calling function >%s<\n", command.function);
1355 }
1356
1357 write_cmd_pipe(command.function);
1358 for (i = 0; i < command.nargs; i++) {
1359 if (command.args[i].arg_type == data_var)
1360 write_cmd_pipe_args(command.args[i].arg_type,
1361 &vars[command.args[i].var_index]);
1362 else
1363 write_cmd_pipe_args(command.args[i].arg_type,
1364 &command.args[i]);
1365 }
1366
1367 write_cmd_pipe(NULL); /* signal end of arguments */
1368 }
1369
1370 /*
1371 * Initialise the command structure - if initial is non-zero then just set
1372 * everything to sane values otherwise free any memory that was allocated
1373 * when building the structure.
1374 */
1375 void
1376 init_parse_variables(int initial)
1377 {
1378 int i, result;
1379 struct pollfd slave_pty;
1380
1381 if (initial == 0) {
1382 free(command.function);
1383 for (i = 0; i < command.nrets; i++) {
1384 if (command.returns[i].data_type == data_number)
1385 free(command.returns[i].data_value);
1386 }
1387 free(command.returns);
1388
1389 for (i = 0; i < command.nargs; i++) {
1390 if (command.args[i].arg_type != data_var)
1391 free(command.args[i].arg_string);
1392 }
1393 free(command.args);
1394 } else {
1395 line = 0;
1396 input_delay = 0;
1397 vars = NULL;
1398 nvars = 0;
1399 input_str = NULL;
1400 saved_output.allocated = 0;
1401 saved_output.count = 0;
1402 saved_output.readp = 0;
1403 saved_output.data = NULL;
1404 }
1405
1406 no_input = false;
1407 command.function = NULL;
1408 command.nargs = 0;
1409 command.args = NULL;
1410 command.nrets = 0;
1411 command.returns = NULL;
1412
1413 /*
1414 * Check the slave pty for stray output from the slave, at this
1415 * point we should not see any data as it should have been
1416 * consumed by the test functions. If we see data then we have
1417 * either a bug or are not handling an output generating function
1418 * correctly.
1419 */
1420 slave_pty.fd = master;
1421 slave_pty.events = POLLIN;
1422 result = poll(&slave_pty, 1, 0);
1423
1424 if (result < 0)
1425 err(2, "Poll of slave pty failed");
1426 else if (result > 0)
1427 warnx("%s, %zu: Unexpected data from slave", cur_file, line);
1428 }
1429
1430 /*
1431 * Validate the response against the expected return. The variable
1432 * i is the i into the rets array in command.
1433 */
1434 static void
1435 validate(int i, void *data)
1436 {
1437 char *response;
1438 ct_data_t *byte_response;
1439
1440 byte_response = data;
1441 if ((command.returns[i].data_type != data_byte) &&
1442 (command.returns[i].data_type != data_err) &&
1443 (command.returns[i].data_type != data_ok)) {
1444 if ((byte_response->data_type == data_byte) ||
1445 (byte_response->data_type == data_err) ||
1446 (byte_response->data_type == data_ok))
1447 err(1, "%s: expecting type %s, received type %s"
1448 " at line %zu of file %s", __func__,
1449 enum_names[command.returns[i].data_type],
1450 enum_names[byte_response->data_type],
1451 line, cur_file);
1452
1453 response = byte_response->data_value;
1454 }
1455
1456 switch (command.returns[i].data_type) {
1457 case data_err:
1458 validate_type(data_err, byte_response, 0);
1459 break;
1460
1461 case data_ok:
1462 validate_type(data_ok, byte_response, 0);
1463 break;
1464
1465 case data_null:
1466 validate_return("NULL", response, 0);
1467 break;
1468
1469 case data_nonnull:
1470 validate_return("NULL", response, 1);
1471 break;
1472
1473 case data_string:
1474 case data_number:
1475 validate_return(command.returns[i].data_value,
1476 response, 0);
1477 break;
1478
1479 case data_ref:
1480 validate_reference(i, response);
1481 break;
1482
1483 case data_byte:
1484 validate_byte(&command.returns[i], byte_response, 0);
1485 break;
1486
1487 default:
1488 err(1, "Malformed statement at line %zu of file %s",
1489 line, cur_file);
1490 break;
1491 }
1492 }
1493
1494 /*
1495 * Validate the return against the contents of a variable.
1496 */
1497 static void
1498 validate_reference(int i, void *data)
1499 {
1500 char *response;
1501 ct_data_t *byte_response;
1502 var_t *varp;
1503
1504 varp = &vars[command.returns[i].data_index];
1505
1506 byte_response = data;
1507 if (command.returns[i].data_type != data_byte)
1508 response = data;
1509
1510 if (verbose) {
1511 fprintf(stderr,
1512 "%s: return type of %s, value %s \n", __func__,
1513 enum_names[varp->type],
1514 (varp->type != data_cchar && varp->type != data_wchar)
1515 ? (const char *)varp->value : "-");
1516 }
1517
1518 switch (varp->type) {
1519 case data_string:
1520 case data_number:
1521 validate_return(varp->value, response, 0);
1522 break;
1523
1524 case data_byte:
1525 validate_byte(varp->value, byte_response, 0);
1526 break;
1527
1528 case data_cchar:
1529 validate_cchar(&(varp->cchar), (cchar_t *) response, 0);
1530 break;
1531
1532 case data_wchar:
1533 validate_wchar((wchar_t *) varp->value, (wchar_t *) response, 0);
1534 break;
1535
1536 default:
1537 err(1,
1538 "Invalid return type for reference at line %zu of file %s",
1539 line, cur_file);
1540 break;
1541 }
1542 }
1543
1544 /*
1545 * Validate the return type against the expected type, throw an error
1546 * if they don't match.
1547 */
1548 static void
1549 validate_type(data_enum_t expected, ct_data_t *value, int check)
1550 {
1551 if (((check == 0) && (expected != value->data_type)) ||
1552 ((check == 1) && (expected == value->data_type)))
1553 err(1, "Validate expected type %s %s %s line %zu of file %s",
1554 enum_names[expected],
1555 (check == 0)? "matching" : "not matching",
1556 enum_names[value->data_type], line, cur_file);
1557
1558 if (verbose) {
1559 fprintf(stderr, "Validate expected type %s %s %s line %zu"
1560 " of file %s\n",
1561 enum_names[expected],
1562 (check == 0)? "matching" : "not matching",
1563 enum_names[value->data_type], line, cur_file);
1564 }
1565 }
1566
1567 /*
1568 * Validate the return value against the expected value, throw an error
1569 * if they don't match.
1570 */
1571 static void
1572 validate_return(const char *expected, const char *value, int check)
1573 {
1574 if (((check == 0) && strcmp(expected, value) != 0) ||
1575 ((check == 1) && strcmp(expected, value) == 0))
1576 errx(1, "Validate expected >%s< %s >%s< line %zu of file %s",
1577 expected,
1578 (check == 0)? "matching" : "not matching", value,
1579 line, cur_file);
1580 if (verbose) {
1581 fprintf(stderr, "Validated expected value >%s< %s >%s< "
1582 "at line %zu of file %s\n", expected,
1583 (check == 0)? "matches" : "does not match",
1584 value, line, cur_file);
1585 }
1586 }
1587
1588 /*
1589 * Validate the return value against the expected value, throw an error
1590 * if they don't match expectations.
1591 */
1592 static void
1593 validate_byte(ct_data_t *expected, ct_data_t *value, int check)
1594 {
1595 char *ch;
1596 size_t i;
1597
1598 if (verbose) {
1599 ch = value->data_value;
1600 fprintf(stderr, "checking returned byte stream: ");
1601 for (i = 0; i < value->data_len; i++)
1602 fprintf(stderr, "%s0x%x", (i != 0)? ", " : "", ch[i]);
1603 fprintf(stderr, "\n");
1604
1605 fprintf(stderr, "%s byte stream: ",
1606 (check == 0)? "matches" : "does not match");
1607 ch = (char *) expected->data_value;
1608 for (i = 0; i < expected->data_len; i++)
1609 fprintf(stderr, "%s0x%x", (i != 0)? ", " : "", ch[i]);
1610 fprintf(stderr, "\n");
1611 }
1612
1613 /*
1614 * No chance of a match if lengths differ...
1615 */
1616 if ((check == 0) && (expected->data_len != value->data_len))
1617 errx(1, "Byte validation failed, length mismatch, expected %zu,"
1618 "received %zu", expected->data_len, value->data_len);
1619
1620 /*
1621 * If check is 0 then we want to throw an error IFF the byte streams
1622 * do not match, if check is 1 then throw an error if the byte
1623 * streams match.
1624 */
1625 if (((check == 0) && memcmp(expected->data_value, value->data_value,
1626 value->data_len) != 0) ||
1627 ((check == 1) && (expected->data_len == value->data_len) &&
1628 memcmp(expected->data_value, value->data_value,
1629 value->data_len) == 0))
1630 errx(1, "Validate expected %s byte stream at line %zu"
1631 "of file %s",
1632 (check == 0)? "matching" : "not matching", line, cur_file);
1633 if (verbose) {
1634 fprintf(stderr, "Validated expected %s byte stream "
1635 "at line %zu of file %s\n",
1636 (check == 0)? "matching" : "not matching",
1637 line, cur_file);
1638 }
1639 }
1640
1641 /*
1642 * Validate the return cchar against the expected cchar, throw an error
1643 * if they don't match expectations.
1644 */
1645 static void
1646 validate_cchar(cchar_t *expected, cchar_t *value, int check)
1647 {
1648 unsigned j;
1649
1650 /*
1651 * No chance of a match if elements count differ...
1652 */
1653 if ((expected->elements != value->elements)) {
1654 if (check == 0)
1655 errx(1, "cchar validation failed, elements count mismatch, "
1656 "expected %d, received %d", expected->elements, value->elements);
1657 else {
1658 if (verbose)
1659 fprintf(stderr, "Validated expected %s cchar"
1660 "at line %zu of file %s\n", "not matching",
1661 line, cur_file);
1662 return;
1663 }
1664 }
1665
1666 /*
1667 * No chance of a match if attributes differ...
1668 */
1669
1670 if ((expected->attributes & WA_ATTRIBUTES) !=
1671 (value->attributes & WA_ATTRIBUTES )) {
1672 if (check == 0)
1673 errx(1, "cchar validation failed,attributes mismatch, expected "
1674 "0x%x, received 0x%x", expected->attributes & WA_ATTRIBUTES,
1675 value->attributes & WA_ATTRIBUTES);
1676 else {
1677 if (verbose)
1678 fprintf(stderr, "Validated expected %s cchar"
1679 "at line %zu of file %s\n", "not matching",
1680 line, cur_file);
1681 return;
1682 }
1683 }
1684
1685 /*
1686 * If check is 0 then we want to throw an error IFF the vals
1687 * do not match, if check is 1 then throw an error if the vals
1688 * streams match.
1689 */
1690 for(j = 0; j < expected->elements; j++) {
1691 if (expected->vals[j] != value->vals[j]) {
1692 if (check == 0)
1693 errx(1, "cchar validation failed, vals mismatch,expected 0x%x,"
1694 "received 0x%x", expected->vals[j], value->vals[j]);
1695 else {
1696 if (verbose)
1697 fprintf(stderr, "Validated expected %s cchar"
1698 "at line %zu of file %s\n", "not matching",
1699 line, cur_file);
1700 return;
1701 }
1702 }
1703 }
1704
1705 if (verbose) {
1706 fprintf(stderr, "Validated expected %s cchar "
1707 "at line %zu of file %s\n",
1708 (check == 0)? "matching" : "not matching",
1709 line, cur_file);
1710 }
1711 }
1712
1713 /*
1714 * Validate the return wchar string against the expected wchar, throw an
1715 * error if they don't match expectations.
1716 */
1717 static void
1718 validate_wchar(wchar_t *expected, wchar_t *value, int check)
1719 {
1720 unsigned j;
1721
1722 unsigned len1 = 0;
1723 unsigned len2 = 0;
1724 wchar_t *p;
1725
1726 p = expected;
1727 while(*p++ != L'\0')
1728 len1++;
1729
1730 p = value;
1731 while(*p++ != L'\0')
1732 len2++;
1733
1734 /*
1735 * No chance of a match if length differ...
1736 */
1737 if (len1 != len2) {
1738 if (check == 0)
1739 errx(1, "wchar string validation failed, length mismatch, "
1740 "expected %d, received %d", len1, len2);
1741 else {
1742 if (verbose)
1743 fprintf(stderr, "Validated expected %s wchar"
1744 "at line %zu of file %s\n", "not matching",
1745 line, cur_file);
1746 return;
1747 }
1748 }
1749
1750 /*
1751 * If check is 0 then we want to throw an error IFF the vals
1752 * do not match, if check is 1 then throw an error if the vals
1753 * streams match.
1754 */
1755 for(j = 0; j < len1; j++) {
1756 if (expected[j] != value[j]) {
1757 if (check == 0)
1758 errx(1, "wchar validation failed at index %d, expected %d,"
1759 "received %d", j, expected[j], value[j]);
1760 else {
1761 if (verbose)
1762 fprintf(stderr, "Validated expected %s wchar"
1763 "at line %zu of file %s\n", "not matching",
1764 line, cur_file);
1765 return;
1766 }
1767 }
1768 }
1769
1770 if (verbose) {
1771 fprintf(stderr, "Validated expected %s wchar "
1772 "at line %zu of file %s\n",
1773 (check == 0)? "matching" : "not matching",
1774 line, cur_file);
1775 }
1776 }
1777
1778 /*
1779 * Validate the variable at i against the expected value, throw an
1780 * error if they don't match, if check is non-zero then the match is
1781 * negated.
1782 */
1783 static void
1784 validate_variable(int ret, data_enum_t type, const void *value, int i,
1785 int check)
1786 {
1787 ct_data_t *retval;
1788 var_t *varptr;
1789
1790 retval = &command.returns[ret];
1791 varptr = &vars[command.returns[ret].data_index];
1792
1793 if (varptr->value == NULL)
1794 err(1, "Variable %s has no value assigned to it", varptr->name);
1795
1796
1797 if (varptr->type != type)
1798 err(1, "Variable %s is not the expected type", varptr->name);
1799
1800 if (type != data_byte) {
1801 if ((((check == 0) && strcmp(value, varptr->value) != 0))
1802 || ((check == 1) && strcmp(value, varptr->value) == 0))
1803 err(1, "Variable %s contains %s instead of %s"
1804 " value %s at line %zu of file %s",
1805 varptr->name, (const char *)varptr->value,
1806 (check == 0)? "expected" : "not matching",
1807 (const char *)value,
1808 line, cur_file);
1809 if (verbose) {
1810 fprintf(stderr, "Variable %s contains %s value "
1811 "%s at line %zu of file %s\n",
1812 varptr->name,
1813 (check == 0)? "expected" : "not matching",
1814 (const char *)varptr->value, line, cur_file);
1815 }
1816 } else {
1817 if ((check == 0) && (retval->data_len != varptr->len))
1818 err(1, "Byte validation failed, length mismatch");
1819
1820 /*
1821 * If check is 0 then we want to throw an error IFF
1822 * the byte streams do not match, if check is 1 then
1823 * throw an error if the byte streams match.
1824 */
1825 if (((check == 0) && memcmp(retval->data_value, varptr->value,
1826 varptr->len) != 0) ||
1827 ((check == 1) && (retval->data_len == varptr->len) &&
1828 memcmp(retval->data_value, varptr->value,
1829 varptr->len) == 0))
1830 err(1, "Validate expected %s byte stream at line %zu"
1831 " of file %s",
1832 (check == 0)? "matching" : "not matching",
1833 line, cur_file);
1834 if (verbose) {
1835 fprintf(stderr, "Validated expected %s byte stream "
1836 "at line %zu of file %s\n",
1837 (check == 0)? "matching" : "not matching",
1838 line, cur_file);
1839 }
1840 }
1841 }
1842
1843 /*
1844 * Write a string to the command pipe - we feed the number of bytes coming
1845 * down first to allow storage allocation and then follow up with the data.
1846 * If cmd is NULL then feed a -1 down the pipe to say the end of the args.
1847 */
1848 static void
1849 write_cmd_pipe(char *cmd)
1850 {
1851 args_t arg;
1852 size_t len;
1853
1854 if (cmd == NULL)
1855 len = 0;
1856 else
1857 len = strlen(cmd);
1858
1859 arg.arg_type = data_static;
1860 arg.arg_len = len;
1861 arg.arg_string = cmd;
1862 write_cmd_pipe_args(arg.arg_type, &arg);
1863
1864 }
1865
1866 static void
1867 write_cmd_pipe_args(data_enum_t type, void *data)
1868 {
1869 var_t *var_data;
1870 args_t *arg_data;
1871 int len, send_type;
1872 void *cmd;
1873
1874 arg_data = data;
1875 switch (type) {
1876 case data_var:
1877 var_data = data;
1878 len = var_data->len;
1879 cmd = var_data->value;
1880
1881 switch (var_data->type) {
1882 case data_byte:
1883 send_type = data_byte;
1884 break;
1885
1886 case data_cchar:
1887 send_type = data_cchar;
1888 cmd = (void *) &var_data->cchar;
1889 len = sizeof(cchar_t);
1890 break;
1891
1892 case data_wchar:
1893 send_type = data_wchar;
1894 break;
1895
1896 default:
1897 send_type = data_string;
1898 break;
1899 }
1900 break;
1901
1902 case data_null:
1903 send_type = data_null;
1904 len = 0;
1905 break;
1906
1907 default:
1908 if ((arg_data->arg_len == 0) && (arg_data->arg_string == NULL))
1909 len = -1;
1910 else
1911 len = arg_data->arg_len;
1912 cmd = arg_data->arg_string;
1913 if (type == data_byte)
1914 send_type = data_byte;
1915 else
1916 send_type = data_string;
1917 }
1918
1919 if (verbose) {
1920 fprintf(stderr, "Writing type %s to command pipe\n",
1921 enum_names[send_type]);
1922 }
1923
1924 if (write(cmdpipe[WRITE_PIPE], &send_type, sizeof(int)) < 0)
1925 err(1, "command pipe write for type failed");
1926
1927 if (verbose) {
1928 if (send_type == data_cchar)
1929 fprintf(stderr,
1930 "Writing cchar to command pipe\n");
1931 else if (send_type == data_wchar)
1932 fprintf(stderr,
1933 "Writing wchar(%d sized) to command pipe\n", len);
1934 else
1935 fprintf(stderr,
1936 "Writing length %d to command pipe\n", len);
1937 }
1938
1939 if (write(cmdpipe[WRITE_PIPE], &len, sizeof(int)) < 0)
1940 err(1, "command pipe write for length failed");
1941
1942 if (len > 0) {
1943 if (verbose) {
1944 fprintf(stderr, "Writing data >%s< to command pipe\n",
1945 (const char *)cmd);
1946 }
1947 if (write(cmdpipe[WRITE_PIPE], cmd, len) < 0)
1948 err(1, "command pipe write of data failed");
1949 }
1950 }
1951
1952 /*
1953 * Read a response from the command pipe, first we will receive the
1954 * length of the response then the actual data.
1955 */
1956 static void
1957 read_cmd_pipe(ct_data_t *response)
1958 {
1959 int len, type;
1960 struct pollfd rfd[2];
1961 char *str;
1962
1963 /*
1964 * Check if there is data to read - just in case slave has died, we
1965 * don't want to block on the read and just hang. We also check
1966 * output from the slave because the slave may be blocked waiting
1967 * for a flush on its stdout.
1968 */
1969 rfd[0].fd = slvpipe[READ_PIPE];
1970 rfd[0].events = POLLIN;
1971 rfd[1].fd = master;
1972 rfd[1].events = POLLIN;
1973
1974 do {
1975 if (poll(rfd, 2, 4000) == 0)
1976 errx(2, "%s, %zu: Command pipe read timeout",
1977 cur_file, line);
1978
1979 if ((rfd[1].revents & POLLIN) == POLLIN) {
1980 if (verbose) {
1981 fprintf(stderr,
1982 "draining output from slave\n");
1983 }
1984 save_slave_output(false);
1985 }
1986 }
1987 while((rfd[1].revents & POLLIN) == POLLIN);
1988
1989 if (read(slvpipe[READ_PIPE], &type, sizeof(int)) < 0)
1990 err(1, "command pipe read for type failed");
1991 response->data_type = type;
1992
1993 if ((type != data_ok) && (type != data_err) && (type != data_count)) {
1994 if (read(slvpipe[READ_PIPE], &len, sizeof(int)) < 0)
1995 err(1, "command pipe read for length failed");
1996 response->data_len = len;
1997
1998 if (verbose) {
1999 fprintf(stderr,
2000 "Reading %d bytes from command pipe\n", len);
2001 }
2002
2003 if ((response->data_value = malloc(len + 1)) == NULL)
2004 err(1, "Failed to alloc memory for cmd pipe read");
2005
2006 if (read(slvpipe[READ_PIPE], response->data_value, len) < 0)
2007 err(1, "command pipe read of data failed");
2008
2009 if (response->data_type != data_byte) {
2010 str = response->data_value;
2011 str[len] = '\0';
2012
2013 if (verbose) {
2014 fprintf(stderr, "Read data >%s< from pipe\n",
2015 (const char *)response->data_value);
2016 }
2017 }
2018 } else {
2019 response->data_value = NULL;
2020 if (type == data_count) {
2021 if (read(slvpipe[READ_PIPE], &len, sizeof(int)) < 0)
2022 err(1, "command pipe read for number of "
2023 "returns failed");
2024 response->data_len = len;
2025 }
2026
2027 if (verbose) {
2028 fprintf(stderr, "Read type %s from pipe\n",
2029 enum_names[type]);
2030 }
2031 }
2032 }
2033
2034 /*
2035 * Check for writes from the slave on the pty, save the output into a
2036 * buffer for later checking if discard is false.
2037 */
2038 #define MAX_DRAIN 256
2039
2040 static void
2041 save_slave_output(bool discard)
2042 {
2043 char *new_data, drain[MAX_DRAIN];
2044 size_t to_allocate;
2045 ssize_t result;
2046 size_t i;
2047
2048 result = 0;
2049 for (;;) {
2050 if (result == -1)
2051 err(2, "poll of slave pty failed");
2052 result = MAX_DRAIN;
2053 if ((result = read(master, drain, result)) < 0) {
2054 if (errno == EAGAIN)
2055 break;
2056 else
2057 err(2, "draining slave pty failed");
2058 }
2059 if (result == 0)
2060 abort();
2061
2062 if (!discard) {
2063 if ((size_t)result >
2064 (saved_output.allocated - saved_output.count)) {
2065 to_allocate = 1024 * ((result / 1024) + 1);
2066
2067 if ((new_data = realloc(saved_output.data,
2068 saved_output.allocated + to_allocate))
2069 == NULL)
2070 err(2, "Realloc of saved_output failed");
2071 saved_output.data = new_data;
2072 saved_output.allocated += to_allocate;
2073 }
2074
2075 if (verbose) {
2076 fprintf(stderr, "count = %zu, "
2077 "allocated = %zu\n", saved_output.count,
2078 saved_output.allocated);
2079 for (i = 0; i < (size_t)result; i++) {
2080 fprintf(stderr, "Saving slave output "
2081 "at %zu: 0x%x (%c)\n",
2082 saved_output.count + i, drain[i],
2083 (drain[i] >= ' ')? drain[i] : '-');
2084 }
2085 }
2086
2087 memcpy(&saved_output.data[saved_output.count], drain,
2088 result);
2089 saved_output.count += result;
2090
2091 if (verbose) {
2092 fprintf(stderr, "count = %zu, "
2093 "allocated = %zu\n", saved_output.count,
2094 saved_output.allocated);
2095 }
2096 } else {
2097 if (verbose) {
2098 for (i = 0; i < (size_t)result; i++) {
2099 fprintf(stderr, "Discarding slave "
2100 "output 0x%x (%c)\n",
2101 drain[i],
2102 (drain[i] >= ' ')? drain[i] : '-');
2103 }
2104 }
2105 }
2106 }
2107 }
2108
2109 static void
2110 yyerror(const char *msg)
2111 {
2112 errx(1, "%s in line %zu of file %s", msg, line, cur_file);
2113 }
2114