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