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