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