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