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