Home | History | Annotate | Line # | Download | only in director
testlang_parse.y revision 1.3
      1  1.1     blymn %{
      2  1.3  christos /*	$NetBSD: testlang_parse.y,v 1.3 2011/05/15 23:56:28 christos Exp $	*/
      3  1.1     blymn 
      4  1.1     blymn /*-
      5  1.1     blymn  * Copyright 2009 Brett Lymn <blymn (at) NetBSD.org>
      6  1.1     blymn  *
      7  1.1     blymn  * All rights reserved.
      8  1.1     blymn  *
      9  1.1     blymn  * This code has been donated to The NetBSD Foundation by the Author.
     10  1.1     blymn  *
     11  1.1     blymn  * Redistribution and use in source and binary forms, with or without
     12  1.1     blymn  * modification, are permitted provided that the following conditions
     13  1.1     blymn  * are met:
     14  1.1     blymn  * 1. Redistributions of source code must retain the above copyright
     15  1.1     blymn  *    notice, this list of conditions and the following disclaimer.
     16  1.1     blymn  * 2. The name of the author may not be used to endorse or promote products
     17  1.1     blymn  *    derived from this software withough specific prior written permission
     18  1.1     blymn  *
     19  1.1     blymn  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     20  1.1     blymn  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     21  1.1     blymn  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     22  1.1     blymn  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     23  1.1     blymn  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     24  1.1     blymn  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  1.1     blymn  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  1.1     blymn  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  1.1     blymn  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     28  1.1     blymn  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  1.1     blymn  *
     30  1.1     blymn  *
     31  1.1     blymn  */
     32  1.1     blymn #include <assert.h>
     33  1.1     blymn #include <errno.h>
     34  1.1     blymn #include <fcntl.h>
     35  1.3  christos #include <err.h>
     36  1.3  christos #include <unistd.h>
     37  1.1     blymn #include <poll.h>
     38  1.1     blymn #include <stdbool.h>
     39  1.1     blymn #include <stdio.h>
     40  1.1     blymn #include <string.h>
     41  1.1     blymn #include <sys/syslimits.h>
     42  1.1     blymn #include <time.h>
     43  1.1     blymn #include "returns.h"
     44  1.1     blymn 
     45  1.1     blymn #define YYDEBUG 1
     46  1.1     blymn 
     47  1.1     blymn extern int verbose;
     48  1.1     blymn extern int cmdpipe[2];
     49  1.1     blymn extern int slvpipe[2];
     50  1.1     blymn extern int master;
     51  1.1     blymn extern struct pollfd readfd;
     52  1.1     blymn extern char *check_path;
     53  1.1     blymn extern char *cur_file;		/* from director.c */
     54  1.1     blymn 
     55  1.3  christos int yylex(void);
     56  1.3  christos 
     57  1.1     blymn size_t line;
     58  1.1     blymn 
     59  1.1     blymn static int input_delay;
     60  1.1     blymn 
     61  1.1     blymn /* time delay between inputs chars - default to 0.1ms minimum to prevent
     62  1.1     blymn  * problems with input tests
     63  1.1     blymn  */
     64  1.1     blymn #define DELAY_MIN 0.1
     65  1.1     blymn static struct timespec delay_spec = {0, 1000 * DELAY_MIN};
     66  1.1     blymn static char *input_str;	/* string to feed in as input */
     67  1.1     blymn static bool no_input;	/* don't need more input */
     68  1.1     blymn 
     69  1.1     blymn #define READ_PIPE  0
     70  1.1     blymn #define WRITE_PIPE 1
     71  1.1     blymn 
     72  1.1     blymn char *returns_enum_names[] = {
     73  1.1     blymn 	"unused", "numeric", "string", "byte", "ERR", "OK", "NULL", "not NULL",
     74  1.1     blymn 	"variable", "reference", "returns count", "slave error"
     75  1.1     blymn };
     76  1.1     blymn 
     77  1.1     blymn typedef enum {
     78  1.1     blymn 	arg_static,
     79  1.1     blymn 	arg_byte,
     80  1.2     blymn 	arg_var,
     81  1.2     blymn 	arg_null
     82  1.1     blymn } args_state_t;
     83  1.1     blymn 
     84  1.1     blymn static char *args_enum_names[] = {
     85  1.2     blymn 	"static", "byte", "var", "NULL"
     86  1.1     blymn };
     87  1.1     blymn 
     88  1.1     blymn typedef struct {
     89  1.1     blymn 	args_state_t	arg_type;
     90  1.1     blymn 	size_t		arg_len;
     91  1.1     blymn 	char		*arg_string;
     92  1.1     blymn 	int		var_index;
     93  1.1     blymn } args_t;
     94  1.1     blymn 
     95  1.1     blymn typedef struct {
     96  1.1     blymn 	char		*function;
     97  1.1     blymn 	int		nrets;		/* number of returns */
     98  1.1     blymn 	returns_t	*returns;	/* array of expected returns */
     99  1.1     blymn 	int		nargs;		/* number of arguments */
    100  1.1     blymn 	args_t		*args;		/* arguments for the call */
    101  1.1     blymn } cmd_line_t;
    102  1.1     blymn 
    103  1.1     blymn static cmd_line_t	command;
    104  1.1     blymn 
    105  1.1     blymn typedef struct {
    106  1.1     blymn 	char *name;
    107  1.1     blymn 	size_t len;
    108  1.1     blymn 	returns_enum_t type;
    109  1.1     blymn 	void *value;
    110  1.1     blymn } var_t;
    111  1.1     blymn 
    112  1.1     blymn static size_t nvars; 		/* Number of declared variables */
    113  1.1     blymn static var_t *vars; 		/* Variables defined during the test. */
    114  1.1     blymn 
    115  1.1     blymn static int	check_function_table(char *, const char *[], int);
    116  1.1     blymn static int	find_var_index(char *);
    117  1.1     blymn static void 	assign_arg(args_state_t, void *);
    118  1.1     blymn static int	assign_var(char *);
    119  1.1     blymn void		init_parse_variables(int);
    120  1.1     blymn static void	validate(int, void *);
    121  1.1     blymn static void	validate_return(char *, char *, int);
    122  1.1     blymn static void	validate_variable(int, returns_enum_t, void *, int, int);
    123  1.1     blymn static void	validate_byte(returns_t *, returns_t *, int);
    124  1.1     blymn static void	write_cmd_pipe(char *);
    125  1.1     blymn static void	write_cmd_pipe_args(args_state_t, void *);
    126  1.1     blymn static void	read_cmd_pipe(returns_t *);
    127  1.1     blymn static void	write_func_and_args();
    128  1.1     blymn static void	compare_streams(char *, bool);
    129  1.1     blymn static void	do_function_call(int);
    130  1.1     blymn static void	save_slave_output(bool);
    131  1.1     blymn static void	validate_type(returns_enum_t, returns_t *, int);
    132  1.1     blymn static void	set_var(returns_enum_t, char *, void *);
    133  1.1     blymn static void	validate_reference(int, void *);
    134  1.1     blymn static char	*numeric_or(char *, char *);
    135  1.1     blymn static char	*get_numeric_var(char *);
    136  1.1     blymn 
    137  1.1     blymn static const char *input_functions[] = {
    138  1.1     blymn 	"inch", "getch", "getnstr", "getstr", "innstr", "instr", "mvgetnstr",
    139  1.1     blymn 	"mvgetstr", "mvinchstr", "mvinchnstr", "mvgetnstr", "mvgetstr",
    140  1.1     blymn 	"mvinchstr", "mvinchnstr", "winch", "wgetch", "wgetnstr", "wgetstr",
    141  1.1     blymn 	"winchnstr", "winchstr", "winnstr", "winstr"
    142  1.1     blymn };
    143  1.1     blymn 
    144  1.1     blymn static const unsigned ninput_functions =
    145  1.1     blymn 	sizeof(input_functions) / sizeof(char *);
    146  1.1     blymn 
    147  1.1     blymn saved_data_t saved_output;
    148  1.1     blymn 
    149  1.1     blymn %}
    150  1.1     blymn 
    151  1.1     blymn %union {
    152  1.1     blymn 	char *string;
    153  1.1     blymn 	returns_t *retval;
    154  1.1     blymn }
    155  1.1     blymn 
    156  1.1     blymn %token <string> PATH
    157  1.1     blymn %token <string> STRING
    158  1.1     blymn %token <retval> BYTE
    159  1.1     blymn %token <string> VARNAME
    160  1.1     blymn %token <string> FILENAME
    161  1.1     blymn %token <string> VARIABLE
    162  1.1     blymn %token <string> REFERENCE
    163  1.1     blymn %token <string> NULL_RET
    164  1.1     blymn %token <string> NON_NULL
    165  1.1     blymn %token <string> ERR_RET
    166  1.1     blymn %token <string> OK_RET
    167  1.1     blymn %token <string> numeric
    168  1.1     blymn %token <string> DELAY
    169  1.1     blymn %token <string> INPUT
    170  1.1     blymn %token <string> COMPARE
    171  1.1     blymn %token <string> COMPAREND
    172  1.1     blymn %token <string> ASSIGN
    173  1.1     blymn %token EOL CALL CHECK NOINPUT OR LHB RHB
    174  1.1     blymn %token CALL2 CALL3 CALL4 DRAIN
    175  1.1     blymn 
    176  1.1     blymn %nonassoc OR
    177  1.1     blymn 
    178  1.1     blymn %%
    179  1.1     blymn 
    180  1.1     blymn statement	:	/* empty */
    181  1.1     blymn 		| assign statement
    182  1.1     blymn 		| call statement
    183  1.1     blymn 		| call2 statement
    184  1.1     blymn 		| call3 statement
    185  1.1     blymn 		| call4 statement
    186  1.1     blymn 		| check statement
    187  1.1     blymn 		| delay statement
    188  1.1     blymn 		| input statement
    189  1.1     blymn 		| noinput statement
    190  1.1     blymn 		| compare statement
    191  1.1     blymn 		| comparend statement
    192  1.1     blymn 		| eol statement
    193  1.1     blymn 		;
    194  1.1     blymn 
    195  1.1     blymn assign		: ASSIGN VARNAME numeric {set_var(ret_number, $2, $3);} eol
    196  1.1     blymn 		| ASSIGN VARNAME LHB expr RHB {set_var(ret_number, $2, $<string>4);} eol
    197  1.1     blymn 		| ASSIGN VARNAME STRING {set_var(ret_string, $2, $3);} eol
    198  1.1     blymn 		| ASSIGN VARNAME BYTE {set_var(ret_byte, $2, $3);} eol
    199  1.1     blymn 		;
    200  1.1     blymn 
    201  1.1     blymn call		: CALL result fn_name args eol {
    202  1.1     blymn 	do_function_call(1);
    203  1.1     blymn }
    204  1.1     blymn 		;
    205  1.1     blymn 
    206  1.1     blymn call2		: CALL2 result result fn_name args eol {
    207  1.1     blymn 	do_function_call(2);
    208  1.1     blymn }
    209  1.1     blymn 		;
    210  1.1     blymn 
    211  1.1     blymn call3		: CALL3 result result result fn_name args eol {
    212  1.1     blymn 	do_function_call(3);
    213  1.1     blymn }
    214  1.1     blymn 		;
    215  1.1     blymn 
    216  1.1     blymn call4		: CALL4 result result result result fn_name args eol {
    217  1.1     blymn 	do_function_call(4);
    218  1.1     blymn  }
    219  1.1     blymn 		;
    220  1.1     blymn 
    221  1.1     blymn check		: CHECK var returns eol {
    222  1.1     blymn 	returns_t ret_var;
    223  1.1     blymn 	var_t *vptr;
    224  1.1     blymn 	if (command.returns[0].return_index == -1)
    225  1.1     blymn 		err(1, "Undefined variable in check statement, line %d"
    226  1.1     blymn 		    " of file %s", line, cur_file);
    227  1.1     blymn 
    228  1.1     blymn 	if (verbose)
    229  1.1     blymn 		fprintf(stderr, "Checking contents of variable %s for %s\n",
    230  1.1     blymn 			vars[command.returns[0].return_index].name,
    231  1.1     blymn 			returns_enum_names[command.returns[1].return_type]);
    232  1.1     blymn 
    233  1.1     blymn 	if (((command.returns[1].return_type == arg_byte) &&
    234  1.1     blymn 	     (vars[command.returns[0].return_index].type != ret_byte)) ||
    235  1.1     blymn 	    ((command.returns[1].return_type == arg_static) &&
    236  1.1     blymn 	     (vars[command.returns[0].return_index].type != ret_string)))
    237  1.1     blymn 		err(1, "Var type %s (%d) does not match return type %s (%d)",
    238  1.1     blymn 		    returns_enum_names[vars[command.returns[0].return_index].type],
    239  1.1     blymn 		    vars[command.returns[0].return_index].type,
    240  1.1     blymn 		    returns_enum_names[command.returns[1].return_type],
    241  1.1     blymn 		    command.returns[1].return_type);
    242  1.1     blymn 
    243  1.1     blymn 	switch (command.returns[1].return_type) {
    244  1.1     blymn 	case ret_err:
    245  1.1     blymn 		validate_variable(0, ret_string, "ERR",
    246  1.1     blymn 				  command.returns[0].return_index, 0);
    247  1.1     blymn 		break;
    248  1.1     blymn 
    249  1.1     blymn 	case ret_ok:
    250  1.1     blymn 		validate_variable(0, ret_string, "OK",
    251  1.1     blymn 				  command.returns[0].return_index, 0);
    252  1.1     blymn 		break;
    253  1.1     blymn 
    254  1.1     blymn 	case ret_null:
    255  1.1     blymn 		validate_variable(0, ret_string, "NULL",
    256  1.1     blymn 				  command.returns[0].return_index, 0);
    257  1.1     blymn 		break;
    258  1.1     blymn 
    259  1.1     blymn 	case ret_nonnull:
    260  1.1     blymn 		validate_variable(0, ret_string, "NULL",
    261  1.1     blymn 				  command.returns[0].return_index, 1);
    262  1.1     blymn 		break;
    263  1.1     blymn 
    264  1.1     blymn 	case ret_string:
    265  1.1     blymn 	case ret_number:
    266  1.1     blymn 		if (verbose)
    267  1.1     blymn 			fprintf(stderr, " %s == returned %s\n",
    268  1.1     blymn 				command.returns[1].return_value,
    269  1.1     blymn 				vars[command.returns[0].return_index].value);
    270  1.1     blymn 		validate_variable(0, ret_string,
    271  1.1     blymn 				  command.returns[1].return_value,
    272  1.1     blymn 				  command.returns[0].return_index, 0);
    273  1.1     blymn 		break;
    274  1.1     blymn 
    275  1.1     blymn 	case ret_byte:
    276  1.1     blymn 		vptr = &vars[command.returns[0].return_index];
    277  1.1     blymn 		ret_var.return_len = vptr->len;
    278  1.1     blymn 		ret_var.return_type = vptr->type;
    279  1.1     blymn 		ret_var.return_value = vptr->value;
    280  1.1     blymn 		validate_byte(&ret_var, &command.returns[1], 0);
    281  1.1     blymn 		break;
    282  1.1     blymn 
    283  1.1     blymn 	default:
    284  1.1     blymn 		err(1, "Malformed check statement at line %d "
    285  1.1     blymn 		    "of file %s", line, cur_file);
    286  1.1     blymn 		break;
    287  1.1     blymn 	}
    288  1.1     blymn 
    289  1.1     blymn 	init_parse_variables(0);
    290  1.1     blymn  }
    291  1.1     blymn 		;
    292  1.1     blymn 
    293  1.1     blymn delay		: DELAY numeric eol {
    294  1.1     blymn 	/* set the inter-character delay */
    295  1.1     blymn 	if (sscanf($2, "%d", &input_delay) == 0)
    296  1.1     blymn 		err(1, "delay specification %s could not be converted to "
    297  1.1     blymn 		    "numeric at line %d of file %s", $2, line, cur_file);
    298  1.1     blymn 	if (verbose)
    299  1.1     blymn 		fprintf(stderr, "Set input delay to %d ms\n", input_delay);
    300  1.1     blymn 
    301  1.1     blymn 	if (input_delay < DELAY_MIN)
    302  1.1     blymn 		input_delay = 1000 * DELAY_MIN; /* ms to ns */
    303  1.1     blymn 	/*
    304  1.1     blymn 	 * Fill in the timespec structure now ready for use later.
    305  1.1     blymn 	 * The delay is specified in milliseconds so convert to timespec
    306  1.1     blymn 	 * values
    307  1.1     blymn 	 */
    308  1.1     blymn 	delay_spec.tv_sec = input_delay / 1000;
    309  1.1     blymn 	delay_spec.tv_nsec = (input_delay - 1000 * delay_spec.tv_sec) * 1000;
    310  1.1     blymn 
    311  1.1     blymn 	init_parse_variables(0);
    312  1.1     blymn  }
    313  1.1     blymn 	;
    314  1.1     blymn 
    315  1.1     blymn input		: INPUT STRING eol {
    316  1.1     blymn 	if (input_str != NULL) {
    317  1.1     blymn 		fprintf(stderr, "WARNING: Discarding unused input string at "
    318  1.1     blymn 			"line %d of file %s\n", line, cur_file);
    319  1.1     blymn 		free(input_str);
    320  1.1     blymn 	}
    321  1.1     blymn 
    322  1.1     blymn 	if ((input_str = malloc(strlen($2) + 1)) == NULL)
    323  1.1     blymn 		err(2, "Cannot allocate memory for input string");
    324  1.1     blymn 
    325  1.1     blymn 	strlcpy(input_str, $2, strlen($2) + 1);
    326  1.1     blymn }
    327  1.1     blymn 	;
    328  1.1     blymn 
    329  1.1     blymn 
    330  1.1     blymn noinput		: NOINPUT eol {
    331  1.1     blymn 	if (input_str != NULL) {
    332  1.1     blymn 		fprintf(stderr, "WARNING: Discarding unused input string at "
    333  1.1     blymn 			"line %d of file %s\n", line, cur_file);
    334  1.1     blymn 		free(input_str);
    335  1.1     blymn 	}
    336  1.1     blymn 
    337  1.1     blymn 	no_input = true;
    338  1.1     blymn  }
    339  1.1     blymn 
    340  1.1     blymn compare		: COMPARE PATH eol
    341  1.1     blymn 		| COMPARE FILENAME eol
    342  1.1     blymn {
    343  1.1     blymn 	compare_streams($2, true);
    344  1.1     blymn }
    345  1.1     blymn 	;
    346  1.1     blymn 
    347  1.1     blymn 
    348  1.1     blymn comparend	: COMPAREND PATH eol
    349  1.1     blymn 		| COMPAREND FILENAME eol
    350  1.1     blymn {
    351  1.1     blymn 	compare_streams($2, false);
    352  1.1     blymn }
    353  1.1     blymn 	;
    354  1.1     blymn 
    355  1.1     blymn 
    356  1.1     blymn result		: returns
    357  1.1     blymn 		| var
    358  1.1     blymn 		| reference
    359  1.1     blymn 		;
    360  1.1     blymn 
    361  1.1     blymn returns		: numeric { assign_rets(ret_number, $1); }
    362  1.1     blymn 		| LHB expr RHB { assign_rets(ret_number, $<string>2); }
    363  1.1     blymn 		| STRING { assign_rets(ret_string, $1); }
    364  1.1     blymn 		| BYTE { assign_rets(ret_byte, (void *) $1); }
    365  1.1     blymn 		| ERR_RET { assign_rets(ret_err, NULL); }
    366  1.1     blymn 		| OK_RET { assign_rets(ret_ok, NULL); }
    367  1.1     blymn 		| NULL_RET { assign_rets(ret_null, NULL); }
    368  1.1     blymn 		| NON_NULL { assign_rets(ret_nonnull, NULL); }
    369  1.1     blymn 		;
    370  1.1     blymn 
    371  1.1     blymn var		: VARNAME {
    372  1.1     blymn 	assign_rets(ret_var, $1);
    373  1.1     blymn  }
    374  1.1     blymn 		;
    375  1.1     blymn 
    376  1.1     blymn reference	: VARIABLE {
    377  1.1     blymn 	assign_rets(ret_ref, $1);
    378  1.1     blymn  }
    379  1.1     blymn 
    380  1.1     blymn fn_name		: VARNAME {
    381  1.1     blymn 	if (command.function != NULL)
    382  1.1     blymn 		free(command.function);
    383  1.1     blymn 
    384  1.1     blymn 	command.function = malloc(strlen($1) + 1);
    385  1.1     blymn 	if (command.function == NULL)
    386  1.1     blymn 		err(1, "Could not allocate memory for function name");
    387  1.1     blymn 	strcpy(command.function, $1);
    388  1.1     blymn  }
    389  1.1     blymn 		;
    390  1.1     blymn 
    391  1.1     blymn expr		: numeric
    392  1.1     blymn 		| VARIABLE
    393  1.1     blymn 			{ $<string>$ = get_numeric_var($1); }
    394  1.1     blymn 		| expr OR expr
    395  1.1     blymn 			{ $<string>$ = numeric_or($<string>1, $<string>3); }
    396  1.1     blymn 		;
    397  1.1     blymn 
    398  1.1     blymn args		: /* empty */
    399  1.1     blymn 		| LHB expr RHB { assign_arg(arg_static, $<string>2); } args
    400  1.1     blymn 		| numeric { assign_arg(arg_static, $1); } args
    401  1.1     blymn 		| STRING { assign_arg(arg_static, $1); } args
    402  1.1     blymn 		| BYTE { assign_arg(arg_byte, $1); } args
    403  1.1     blymn 		| PATH { assign_arg(arg_static, $1); } args
    404  1.1     blymn 		| FILENAME { assign_arg(arg_static, $1); } args
    405  1.1     blymn 		| VARNAME { assign_arg(arg_static, $1); } args
    406  1.1     blymn 		| VARIABLE  { assign_arg(arg_var, $1); } args
    407  1.2     blymn 		| NULL_RET { assign_arg(arg_null, $1); } args
    408  1.1     blymn 		;
    409  1.1     blymn 
    410  1.1     blymn eol		: EOL
    411  1.1     blymn 		;
    412  1.1     blymn 
    413  1.1     blymn %%
    414  1.1     blymn 
    415  1.1     blymn /*
    416  1.1     blymn  * Get the value of a variable, error if the variable has not been set or
    417  1.1     blymn  * is not a numeric type.
    418  1.1     blymn  */
    419  1.1     blymn static char *
    420  1.1     blymn get_numeric_var(char *var)
    421  1.1     blymn {
    422  1.1     blymn 	int index;
    423  1.1     blymn 
    424  1.1     blymn 	if ((index = find_var_index(var)) < 0)
    425  1.1     blymn 		err(1, "Variable %s is undefined", var);
    426  1.1     blymn 
    427  1.1     blymn 	if (vars[index].type != ret_number)
    428  1.1     blymn 		err(1, "Variable %s is not a numeric type");
    429  1.1     blymn 
    430  1.1     blymn 	return vars[index].value;
    431  1.1     blymn }
    432  1.1     blymn 
    433  1.1     blymn /*
    434  1.1     blymn  * Perform a bitwise OR on two numbers and return the result.
    435  1.1     blymn  */
    436  1.1     blymn static char *
    437  1.1     blymn numeric_or(char *n1, char *n2)
    438  1.1     blymn {
    439  1.1     blymn 	unsigned long i1, i2, result;
    440  1.1     blymn 	char *ret;
    441  1.1     blymn 
    442  1.1     blymn 	i1 = strtoul(n1, NULL, 10);
    443  1.1     blymn 	i2 = strtoul(n2, NULL, 10);
    444  1.1     blymn 
    445  1.1     blymn 	result = i1 | i2;
    446  1.1     blymn 	asprintf(&ret, "%lu", result);
    447  1.1     blymn 
    448  1.1     blymn 	if (verbose)
    449  1.1     blymn 		fprintf(stderr,
    450  1.1     blymn 			"numeric or of 0x%lx (%s) and 0x%lx (%s) results"
    451  1.1     blymn 			" in 0x%lx (%s)\n",
    452  1.1     blymn 			i1, n1, i2, n2, result, ret);
    453  1.1     blymn 
    454  1.1     blymn 	return ret;
    455  1.1     blymn }
    456  1.1     blymn 
    457  1.1     blymn /*
    458  1.1     blymn  * Assign the value given to the named variable.
    459  1.1     blymn  */
    460  1.1     blymn static void
    461  1.1     blymn set_var(returns_enum_t type, char *name, void *value)
    462  1.1     blymn {
    463  1.1     blymn 	int index;
    464  1.1     blymn 	char *number;
    465  1.1     blymn 	returns_t *ret;
    466  1.1     blymn 
    467  1.1     blymn 	index = find_var_index(name);
    468  1.1     blymn 	if (index < 0)
    469  1.1     blymn 		index = assign_var(name);
    470  1.1     blymn 
    471  1.1     blymn 	vars[index].type = type;
    472  1.1     blymn 	if ((type == ret_number) || (type == ret_string)) {
    473  1.1     blymn 		number = value;
    474  1.1     blymn 		vars[index].len = strlen(number) + 1;
    475  1.1     blymn 		vars[index].value = malloc(vars[index].len + 1);
    476  1.1     blymn 		if (vars[index].value == NULL)
    477  1.1     blymn 			err(1, "Could not malloc memory for assign string");
    478  1.1     blymn 		strcpy(vars[index].value, number);
    479  1.1     blymn 	} else {
    480  1.1     blymn 		/* can only be a byte value */
    481  1.1     blymn 		ret = value;
    482  1.1     blymn 		vars[index].len = ret->return_len;
    483  1.1     blymn 		vars[index].value = malloc(vars[index].len);
    484  1.1     blymn 		if (vars[index].value == NULL)
    485  1.1     blymn 			err(1, "Could not malloc memory to assign byte string");
    486  1.1     blymn 		memcpy(vars[index].value, ret->return_value, vars[index].len);
    487  1.1     blymn 	}
    488  1.1     blymn }
    489  1.1     blymn 
    490  1.1     blymn /*
    491  1.1     blymn  * Add a new variable to the vars array, the value will be assigned later,
    492  1.1     blymn  * when a test function call returns.
    493  1.1     blymn  */
    494  1.1     blymn static int
    495  1.1     blymn assign_var(char *varname)
    496  1.1     blymn {
    497  1.1     blymn 	var_t *temp;
    498  1.1     blymn 	char *name;
    499  1.1     blymn 
    500  1.1     blymn 	if ((name = malloc(strlen(varname) + 1)) == NULL)
    501  1.1     blymn 		err(1, "Alloc of varname failed");
    502  1.1     blymn 
    503  1.1     blymn 	if ((temp = (var_t *) realloc(vars, sizeof(var_t) * (nvars + 1)))
    504  1.1     blymn 	    == NULL) {
    505  1.1     blymn 		free(name);
    506  1.1     blymn 		err(1, "Realloc of vars array failed");
    507  1.1     blymn 	}
    508  1.1     blymn 
    509  1.1     blymn 	strcpy(name, varname);
    510  1.1     blymn 	vars = temp;
    511  1.1     blymn 	vars[nvars].name = name;
    512  1.1     blymn 	vars[nvars].len = 0;
    513  1.1     blymn 	vars[nvars].value = NULL;
    514  1.1     blymn 	nvars++;
    515  1.1     blymn 
    516  1.1     blymn 	return (nvars - 1);
    517  1.1     blymn }
    518  1.1     blymn 
    519  1.1     blymn /*
    520  1.1     blymn  * Allocate and assign a new argument of the given type.
    521  1.1     blymn  */
    522  1.1     blymn static void
    523  1.1     blymn assign_arg(args_state_t arg_type, void *arg)
    524  1.1     blymn {
    525  1.1     blymn 	args_t *temp, cur;
    526  1.1     blymn 	char *str;
    527  1.1     blymn 	returns_t *ret;
    528  1.1     blymn 
    529  1.1     blymn 	if (verbose)
    530  1.1     blymn 		printf("function is >%s<, adding arg >%s< type %s\n",
    531  1.1     blymn 		       command.function, arg, args_enum_names[arg_type]);
    532  1.1     blymn 
    533  1.1     blymn 	cur.arg_type = arg_type;
    534  1.2     blymn 	switch (arg_type) {
    535  1.2     blymn 	case arg_var:
    536  1.1     blymn 		cur.var_index = find_var_index(arg);
    537  1.1     blymn 		if (cur.var_index < 0)
    538  1.1     blymn 			err(1, "Invalid variable %s at line %d of file %s",
    539  1.1     blymn 			    arg, line, cur_file);
    540  1.1     blymn 		cur.arg_type = ret_string;
    541  1.2     blymn 		break;
    542  1.2     blymn 
    543  1.2     blymn 	case arg_byte:
    544  1.2     blymn 		ret = arg;
    545  1.2     blymn 		cur.arg_len = ret->return_len;
    546  1.2     blymn 		cur.arg_string = malloc(cur.arg_len);
    547  1.2     blymn 		if (cur.arg_string == NULL)
    548  1.2     blymn 			err(1, "Could not malloc memory for arg bytes");
    549  1.2     blymn 		memcpy(cur.arg_string, ret->return_value, cur.arg_len);
    550  1.2     blymn 		break;
    551  1.2     blymn 
    552  1.2     blymn 	case arg_null:
    553  1.2     blymn 		cur.arg_len = 0;
    554  1.2     blymn 		cur.arg_string = NULL;
    555  1.2     blymn 		break;
    556  1.2     blymn 
    557  1.2     blymn 	default:
    558  1.2     blymn 		str = arg;
    559  1.2     blymn 		cur.arg_len = strlen(str);
    560  1.2     blymn 		cur.arg_string = malloc(cur.arg_len + 1);
    561  1.2     blymn 		if (cur.arg_string == NULL)
    562  1.2     blymn 			err(1, "Could not malloc memory for arg string");
    563  1.2     blymn 		strcpy(cur.arg_string, arg);
    564  1.1     blymn 	}
    565  1.1     blymn 
    566  1.1     blymn 	temp = realloc(command.args, sizeof(args_t) * (command.nargs + 1));
    567  1.1     blymn 	if (temp == NULL)
    568  1.1     blymn 		err(1, "Failed to reallocate args");
    569  1.1     blymn 	command.args = temp;
    570  1.1     blymn 	memcpy(&command.args[command.nargs], &cur, sizeof(args_t));
    571  1.1     blymn 	command.nargs++;
    572  1.1     blymn }
    573  1.1     blymn 
    574  1.1     blymn /*
    575  1.1     blymn  * Allocate and assign a new return.
    576  1.1     blymn  */
    577  1.1     blymn static void
    578  1.1     blymn assign_rets(returns_enum_t ret_type, void *ret)
    579  1.1     blymn {
    580  1.1     blymn 	returns_t *temp, cur;
    581  1.1     blymn 	char *ret_str;
    582  1.1     blymn 	returns_t *ret_ret;
    583  1.1     blymn 
    584  1.1     blymn 	cur.return_type = ret_type;
    585  1.1     blymn 	if (ret_type != ret_var) {
    586  1.1     blymn 		if ((ret_type == ret_number) || (ret_type == ret_string)) {
    587  1.1     blymn 			ret_str = ret;
    588  1.1     blymn 			cur.return_len = strlen(ret_str) + 1;
    589  1.1     blymn 			cur.return_value = malloc(cur.return_len + 1);
    590  1.1     blymn 			if (cur.return_value == NULL)
    591  1.1     blymn 				err(1,
    592  1.1     blymn 				    "Could not malloc memory for arg string");
    593  1.1     blymn 			strcpy(cur.return_value, ret_str);
    594  1.1     blymn 		} else if (ret_type == ret_byte) {
    595  1.1     blymn 			ret_ret = ret;
    596  1.1     blymn 			cur.return_len = ret_ret->return_len;
    597  1.1     blymn 			cur.return_value = malloc(cur.return_len);
    598  1.1     blymn 			if (cur.return_value == NULL)
    599  1.1     blymn 				err(1,
    600  1.1     blymn 				    "Could not malloc memory for byte string");
    601  1.1     blymn 			memcpy(cur.return_value, ret_ret->return_value,
    602  1.1     blymn 			       cur.return_len);
    603  1.1     blymn 		} else if (ret_type == ret_ref) {
    604  1.1     blymn 			if ((cur.return_index = find_var_index(ret)) < 0)
    605  1.1     blymn 				err(1, "Undefined variable reference");
    606  1.1     blymn 		}
    607  1.1     blymn 	} else {
    608  1.1     blymn 		cur.return_index = find_var_index(ret);
    609  1.1     blymn 		if (cur.return_index < 0)
    610  1.1     blymn 			cur.return_index = assign_var(ret);
    611  1.1     blymn 	}
    612  1.1     blymn 
    613  1.1     blymn 	temp = realloc(command.returns,
    614  1.1     blymn 		       sizeof(returns_t) * (command.nrets + 1));
    615  1.1     blymn 	if (temp == NULL)
    616  1.1     blymn 		err(1, "Failed to reallocate returns");
    617  1.1     blymn 	command.returns = temp;
    618  1.1     blymn 	memcpy(&command.returns[command.nrets], &cur, sizeof(returns_t));
    619  1.1     blymn 	command.nrets++;
    620  1.1     blymn }
    621  1.1     blymn 
    622  1.1     blymn /*
    623  1.1     blymn  * Find the given variable name in the var array and return the index
    624  1.1     blymn  * return -1 if var is not found.
    625  1.1     blymn  */
    626  1.1     blymn static int
    627  1.1     blymn find_var_index(char *var_name)
    628  1.1     blymn {
    629  1.1     blymn 	int result, i;
    630  1.1     blymn 
    631  1.1     blymn 	result = -1;
    632  1.1     blymn 
    633  1.1     blymn 	for (i = 0; i < nvars; i++) {
    634  1.1     blymn 		if (strcmp(var_name, vars[i].name) == 0) {
    635  1.1     blymn 			result = i;
    636  1.1     blymn 			break;
    637  1.1     blymn 		}
    638  1.1     blymn 	}
    639  1.1     blymn 
    640  1.1     blymn 	return result;
    641  1.1     blymn }
    642  1.1     blymn 
    643  1.1     blymn /*
    644  1.1     blymn  * Check the given function name in the given table of names, return 1 if
    645  1.1     blymn  * there is a match.
    646  1.1     blymn  */
    647  1.1     blymn static int check_function_table(char *function, const char *table[],
    648  1.1     blymn 				int nfunctions)
    649  1.1     blymn {
    650  1.1     blymn 	int i;
    651  1.1     blymn 
    652  1.1     blymn 	for (i = 0; i < nfunctions; i++) {
    653  1.1     blymn 		if ((strlen(function) == strlen(table[i])) &&
    654  1.1     blymn 		    (strcmp(function, table[i]) == 0))
    655  1.1     blymn 			return 1;
    656  1.1     blymn 	}
    657  1.1     blymn 
    658  1.1     blymn 	return 0;
    659  1.1     blymn }
    660  1.1     blymn 
    661  1.1     blymn /*
    662  1.1     blymn  * Compare the output from the slave against the given file and report
    663  1.1     blymn  * any differences.
    664  1.1     blymn  */
    665  1.1     blymn static void
    666  1.1     blymn compare_streams(char *filename, bool discard)
    667  1.1     blymn {
    668  1.1     blymn 	char check_file[PATH_MAX], drain, ref, data;
    669  1.1     blymn 	struct pollfd fds[2];
    670  1.1     blymn 	int nfd, check_fd, result;
    671  1.1     blymn 
    672  1.1     blymn 	/*
    673  1.1     blymn 	 * Don't prepend check path iff check file has an absolute
    674  1.1     blymn 	 * path.
    675  1.1     blymn 	 */
    676  1.1     blymn 	if (filename[0] != '/') {
    677  1.1     blymn 		if (strlcpy(check_file, check_path, sizeof(check_file))
    678  1.1     blymn 		    >= sizeof(check_file))
    679  1.1     blymn 			err(2, "CHECK_PATH too long");
    680  1.1     blymn 
    681  1.1     blymn 		if (strlcat(check_file, "/", sizeof(check_file))
    682  1.1     blymn 		    >= sizeof(check_file))
    683  1.1     blymn 			err(2, "Could not append / to check file path");
    684  1.1     blymn 	} else {
    685  1.1     blymn 		check_file[0] = '\0';
    686  1.1     blymn 	}
    687  1.1     blymn 
    688  1.1     blymn 	if (strlcat(check_file, filename, sizeof(check_file))
    689  1.1     blymn 	    >= sizeof(check_file))
    690  1.1     blymn 		err(2, "Path to check file path overflowed");
    691  1.1     blymn 
    692  1.1     blymn 	if ((check_fd = open(check_file, O_RDONLY, 0)) < 0)
    693  1.1     blymn 		err(2, "failed to open file %s line %d of file %s",
    694  1.1     blymn 		    check_file, line, cur_file);
    695  1.1     blymn 
    696  1.1     blymn 	fds[0].fd = check_fd;
    697  1.1     blymn 	fds[0].events = POLLIN;
    698  1.1     blymn 	fds[0].revents = 0;
    699  1.1     blymn 	fds[1].fd = master;
    700  1.1     blymn 	fds[1].events = POLLIN;
    701  1.1     blymn 	fds[1].revents = 0;
    702  1.1     blymn 
    703  1.1     blymn 	nfd = 2;
    704  1.1     blymn 	/*
    705  1.1     blymn 	 * if we have saved output then only check for data in the
    706  1.1     blymn 	 * reference file since the slave data may already be drained.
    707  1.1     blymn 	 */
    708  1.1     blymn 	if (saved_output.count > 0)
    709  1.1     blymn 		nfd = 1;
    710  1.1     blymn 
    711  1.1     blymn 	while (poll(&fds[0], nfd, 500) == nfd) {
    712  1.1     blymn 		if ((result = read(check_fd, &ref, 1)) < 1) {
    713  1.1     blymn 			if (result != 0) {
    714  1.1     blymn 				fprintf(stderr, "Bad read on file %s\n",
    715  1.1     blymn 					check_file);
    716  1.1     blymn 				exit(2);
    717  1.1     blymn 			} else {
    718  1.1     blymn 				break;
    719  1.1     blymn 			}
    720  1.1     blymn 		}
    721  1.1     blymn 
    722  1.1     blymn 		if (saved_output.count > 0) {
    723  1.1     blymn 			data = saved_output.data[saved_output.readp];
    724  1.1     blymn 			saved_output.count--;
    725  1.1     blymn 			saved_output.readp++;
    726  1.1     blymn 			/* run out of saved data, switch to file */
    727  1.1     blymn 			if (saved_output.count == 0)
    728  1.1     blymn 				nfd = 2;
    729  1.1     blymn 		} else {
    730  1.1     blymn 			if (read(master, &data, 1) < 1)
    731  1.1     blymn 				err(2, "Bad read on slave pty");
    732  1.1     blymn 		}
    733  1.1     blymn 
    734  1.1     blymn 		if (verbose) {
    735  1.1     blymn 			fprintf(stderr, "Comparing reference byte 0x%x (%c)"
    736  1.1     blymn 				" against slave byte 0x%x (%c)\n", ref,
    737  1.1     blymn 				(ref >= ' ')? ref : '-',
    738  1.1     blymn 				data, (data >= ' ')? data : '-');
    739  1.1     blymn 		}
    740  1.1     blymn 
    741  1.1     blymn 		if (ref != data) {
    742  1.1     blymn 			fprintf(stderr, "refresh data from slave does "
    743  1.1     blymn 				"not match expected from file %s, "
    744  1.1     blymn 				"line %d of file %s\n",
    745  1.1     blymn 				check_file, line, cur_file);
    746  1.1     blymn 
    747  1.1     blymn 			if (!verbose)
    748  1.1     blymn 				exit(2);
    749  1.1     blymn 		}
    750  1.1     blymn 
    751  1.1     blymn 		fds[0].revents = 0;
    752  1.1     blymn 		fds[1].revents = 0;
    753  1.1     blymn 	}
    754  1.1     blymn 
    755  1.1     blymn 
    756  1.1     blymn 	if (saved_output.count > 0)
    757  1.1     blymn 		fprintf(stderr, "Warning: excess saved data from "
    758  1.1     blymn 			"slave at line %d of file %s\n", line, cur_file);
    759  1.1     blymn 
    760  1.1     blymn 	/* discard any excess saved output if required */
    761  1.1     blymn 	if (discard) {
    762  1.1     blymn 		saved_output.count = 0;
    763  1.1     blymn 		saved_output.readp = 0;
    764  1.1     blymn 	}
    765  1.1     blymn 
    766  1.1     blymn 	fds[0].revents = 0;
    767  1.1     blymn 	fds[1].revents = 0;
    768  1.1     blymn 	if ((result = poll(&fds[0], 2, 0)) != 0) {
    769  1.1     blymn 		if (result == -1)
    770  1.1     blymn 			err(2, "poll of file descriptors failed");
    771  1.1     blymn 
    772  1.1     blymn 		if ((fds[1].revents && POLLIN) == POLLIN) {
    773  1.1     blymn 			save_slave_output(true);
    774  1.1     blymn 		} else {
    775  1.1     blymn 			/*
    776  1.1     blymn 			 * handle excess in file if it exists.  Poll
    777  1.1     blymn 			 * says there is data until EOF is read.
    778  1.1     blymn 			 * Check next read is EOF, if it is not then
    779  1.1     blymn 			 * the file really has more data than the
    780  1.1     blymn 			 * slave produced so flag this as a warning.
    781  1.1     blymn 			 */
    782  1.1     blymn 			result = read(check_fd, &drain, 1);
    783  1.1     blymn 			if (result == -1)
    784  1.3  christos 				err(1, "read of data file failed");
    785  1.1     blymn 
    786  1.1     blymn 			if (result > 0) {
    787  1.1     blymn 				fprintf(stderr, "Error: excess data "
    788  1.1     blymn 					"in file %s\n", check_file);
    789  1.1     blymn 				if (!verbose)
    790  1.1     blymn 					exit(2);
    791  1.1     blymn 			}
    792  1.1     blymn 		}
    793  1.1     blymn 	}
    794  1.1     blymn 
    795  1.1     blymn 	close(check_fd);
    796  1.1     blymn }
    797  1.1     blymn 
    798  1.1     blymn /*
    799  1.1     blymn  * Pass a function call and arguments to the slave and wait for the
    800  1.1     blymn  * results.  The variable nresults determines how many returns we expect
    801  1.1     blymn  * back from the slave.  These results will be validated against the
    802  1.1     blymn  * expected returns or assigned to variables.
    803  1.1     blymn  */
    804  1.1     blymn static void
    805  1.1     blymn do_function_call(int nresults)
    806  1.1     blymn {
    807  1.1     blymn #define MAX_RESULTS 4
    808  1.1     blymn 	char *p;
    809  1.1     blymn 	int i, do_input, nfd;
    810  1.1     blymn 	struct pollfd fds[3];
    811  1.1     blymn 	returns_t response[MAX_RESULTS], returns_count;
    812  1.1     blymn 
    813  1.1     blymn 	assert(nresults <= MAX_RESULTS);
    814  1.1     blymn 
    815  1.1     blymn 	do_input = check_function_table(command.function, input_functions,
    816  1.1     blymn 					ninput_functions);
    817  1.1     blymn 
    818  1.1     blymn 	write_func_and_args();
    819  1.1     blymn 
    820  1.1     blymn 	/*
    821  1.1     blymn 	 * We should get the number of returns back here, grab it before
    822  1.1     blymn 	 * doing input otherwise it will confuse the input poll
    823  1.1     blymn 	 */
    824  1.1     blymn 	read_cmd_pipe(&returns_count);
    825  1.1     blymn 	if (returns_count.return_type != ret_count )
    826  1.1     blymn 		err(2, "expected return type of ret_count but received %s",
    827  1.1     blymn 		    returns_enum_names[returns_count.return_type]);
    828  1.1     blymn 
    829  1.1     blymn 	if (verbose)
    830  1.1     blymn 		fprintf(stderr, "Expect %d results from slave, slave "
    831  1.1     blymn 			"reported %d\n", nresults, returns_count.return_len);
    832  1.1     blymn 
    833  1.1     blymn 	if ((no_input == false) && (do_input == 1)) {
    834  1.1     blymn 		if (verbose)
    835  1.1     blymn 			fprintf(stderr, "doing input with inputstr >%s<\n",
    836  1.1     blymn 				input_str);
    837  1.1     blymn 
    838  1.1     blymn 		if (input_str == NULL) {
    839  1.1     blymn 			fprintf(stderr, "Error: Call to input function at "
    840  1.1     blymn 				" line %d of file %s but no input defined",
    841  1.1     blymn 				line, cur_file);
    842  1.1     blymn 			exit(2);
    843  1.1     blymn 		}
    844  1.1     blymn 
    845  1.1     blymn 		fds[0].fd = slvpipe[READ_PIPE];
    846  1.1     blymn 		fds[0].events = POLLIN;
    847  1.1     blymn  		p = input_str;
    848  1.1     blymn 		save_slave_output(false);
    849  1.1     blymn 		while(*p != '\0') {
    850  1.1     blymn 			if (verbose) {
    851  1.1     blymn 				fprintf(stderr, "Writing char >%c< to slave\n",
    852  1.1     blymn 					*p);
    853  1.1     blymn 				fflush(stderr);
    854  1.1     blymn 			}
    855  1.1     blymn 
    856  1.1     blymn 			nanosleep(&delay_spec, NULL);
    857  1.1     blymn 
    858  1.1     blymn 			write(master, p, 1);
    859  1.1     blymn 			save_slave_output(false);
    860  1.1     blymn 
    861  1.1     blymn 			p++;
    862  1.1     blymn 			fds[0].revents = 0;
    863  1.1     blymn 
    864  1.1     blymn 			/* check for slave function returning unexpectedly */
    865  1.1     blymn 			if ((poll(&fds[0], 1, 10) > 0) && (*p != '\0')) {
    866  1.1     blymn 				fprintf(stderr, "Warning: slave function "
    867  1.1     blymn 					"returned before end of input string"
    868  1.1     blymn 					" at line %d of file %s\n",
    869  1.1     blymn 					line, cur_file);
    870  1.1     blymn 				break;
    871  1.1     blymn 			}
    872  1.1     blymn 		}
    873  1.1     blymn 
    874  1.1     blymn 		if (verbose) {
    875  1.1     blymn 			fprintf(stderr, "Input done.\n");
    876  1.1     blymn 		}
    877  1.1     blymn 
    878  1.1     blymn 		/* done with the input string, free the resources */
    879  1.1     blymn 		free(input_str);
    880  1.1     blymn 		input_str = NULL;
    881  1.1     blymn 	}
    882  1.1     blymn 
    883  1.1     blymn 	if (verbose) {
    884  1.1     blymn 		fds[0].fd = slvpipe[READ_PIPE];
    885  1.1     blymn 		fds[0].events = POLLIN;
    886  1.1     blymn 		fds[0].revents = 0;
    887  1.1     blymn 
    888  1.1     blymn 		fds[1].fd = slvpipe[WRITE_PIPE];
    889  1.1     blymn 		fds[1].events = POLLOUT;
    890  1.1     blymn 		fds[1].revents = 0;
    891  1.1     blymn 
    892  1.1     blymn 		fds[2].fd = master;
    893  1.1     blymn 		fds[2].events = POLLIN | POLLOUT;
    894  1.1     blymn 		fds[2].revents = 0;
    895  1.1     blymn 
    896  1.1     blymn 		i = poll(&fds[0], 3, 1000);
    897  1.1     blymn 		fprintf(stderr, "Poll returned %d\n", i);
    898  1.1     blymn 		for (i = 0; i < 3; i++) {
    899  1.1     blymn 			fprintf(stderr, "revents for fd[%d] = 0x%x\n",
    900  1.1     blymn 				i, fds[i].revents);
    901  1.1     blymn 		}
    902  1.1     blymn 	}
    903  1.1     blymn 
    904  1.1     blymn 	/* drain any trailing output */
    905  1.1     blymn 	save_slave_output(false);
    906  1.1     blymn 
    907  1.1     blymn 	for (i = 0; i < returns_count.return_len; i++) {
    908  1.1     blymn 		read_cmd_pipe(&response[i]);
    909  1.1     blymn 	}
    910  1.1     blymn 
    911  1.1     blymn 	/*
    912  1.1     blymn 	 * Check for a slave error in the first return slot, if the
    913  1.1     blymn 	 * slave errored then we may not have the number of returns we
    914  1.1     blymn 	 * expect but in this case we should report the slave error
    915  1.1     blymn 	 * instead of a return count mismatch.
    916  1.1     blymn 	 */
    917  1.1     blymn 	if ((returns_count.return_len > 0) &&
    918  1.1     blymn 	    (response[0].return_type == ret_slave_error))
    919  1.1     blymn 		err(2, "Slave returned error: %s", response[0].return_value);
    920  1.1     blymn 
    921  1.1     blymn 	if (returns_count.return_len != nresults)
    922  1.1     blymn 		err(2, "Incorrect number of returns from slave, expected %d "
    923  1.1     blymn 		    "but received %d", nresults, returns_count.return_len);
    924  1.1     blymn 
    925  1.1     blymn 	if (verbose) {
    926  1.1     blymn 		for (i = 0; i < nresults; i++) {
    927  1.1     blymn 			if ((response[i].return_type != ret_byte) &&
    928  1.1     blymn 			    (response[i].return_type != ret_err) &&
    929  1.1     blymn 			    (response[i].return_type != ret_ok))
    930  1.1     blymn 				fprintf(stderr,
    931  1.1     blymn 					"received response >%s< "
    932  1.1     blymn 					"expected", response[i].return_value);
    933  1.1     blymn 			else
    934  1.1     blymn 				fprintf(stderr, "received");
    935  1.1     blymn 
    936  1.1     blymn 			fprintf(stderr, " return_type %s\n",
    937  1.1     blymn 				returns_enum_names[command.returns[i].return_type]);
    938  1.1     blymn 		}
    939  1.1     blymn 	}
    940  1.1     blymn 
    941  1.1     blymn 	for (i = 0; i < nresults; i++) {
    942  1.1     blymn 		if (command.returns[i].return_type != ret_var) {
    943  1.1     blymn 			validate(i, &response[i]);
    944  1.1     blymn 		} else {
    945  1.1     blymn 			vars[command.returns[i].return_index].len =
    946  1.1     blymn 				response[i].return_len;
    947  1.1     blymn 			vars[command.returns[i].return_index].value =
    948  1.1     blymn 				response[i].return_value;
    949  1.1     blymn 			vars[command.returns[i].return_index].type =
    950  1.1     blymn 				response[i].return_type;
    951  1.1     blymn 		}
    952  1.1     blymn 	}
    953  1.1     blymn 
    954  1.1     blymn 	if (saved_output.count > 0)
    955  1.1     blymn 		fprintf(stderr, "Warning: excess data from slave at line %d"
    956  1.1     blymn 			" of file %s\n", line, cur_file);
    957  1.1     blymn 
    958  1.1     blymn 	init_parse_variables(0);
    959  1.1     blymn }
    960  1.1     blymn 
    961  1.1     blymn /*
    962  1.1     blymn  * Write the function and command arguments to the command pipe.
    963  1.1     blymn  */
    964  1.1     blymn static void
    965  1.1     blymn write_func_and_args()
    966  1.1     blymn {
    967  1.1     blymn 	int i;
    968  1.1     blymn 
    969  1.1     blymn 	if (verbose)
    970  1.1     blymn 		fprintf(stderr, "calling function >%s<\n", command.function);
    971  1.1     blymn 
    972  1.1     blymn 	write_cmd_pipe(command.function);
    973  1.1     blymn 	for (i = 0; i < command.nargs; i++) {
    974  1.1     blymn 		if (command.args[i].arg_type == arg_var)
    975  1.1     blymn 			write_cmd_pipe_args(command.args[i].arg_type,
    976  1.1     blymn 					    &vars[command.args[i].var_index]);
    977  1.1     blymn 		else
    978  1.1     blymn 			write_cmd_pipe_args(command.args[i].arg_type,
    979  1.1     blymn 					    &command.args[i]);
    980  1.1     blymn 	}
    981  1.1     blymn 
    982  1.1     blymn 	write_cmd_pipe(NULL); /* signal end of arguments */
    983  1.1     blymn }
    984  1.1     blymn 
    985  1.1     blymn /*
    986  1.1     blymn  * Initialise the command structure - if initial is non-zero then just set
    987  1.1     blymn  * everything to sane values otherwise free any memory that was allocated
    988  1.1     blymn  * when building the structure.
    989  1.1     blymn  */
    990  1.1     blymn void
    991  1.1     blymn init_parse_variables(int initial)
    992  1.1     blymn {
    993  1.1     blymn 	int i, result;
    994  1.1     blymn 	struct pollfd slave_pty;
    995  1.1     blymn 
    996  1.1     blymn 	if (initial == 0) {
    997  1.1     blymn 		free(command.function);
    998  1.1     blymn 		for (i = 0; i < command.nrets; i++) {
    999  1.1     blymn 			if (command.returns[i].return_type == ret_number)
   1000  1.1     blymn 				free(command.returns[i].return_value);
   1001  1.1     blymn 		}
   1002  1.1     blymn 		free(command.returns);
   1003  1.1     blymn 
   1004  1.1     blymn 		for (i = 0; i < command.nargs; i++) {
   1005  1.1     blymn 			if (command.args[i].arg_type != arg_var)
   1006  1.1     blymn 				free(command.args[i].arg_string);
   1007  1.1     blymn 		}
   1008  1.1     blymn 		free(command.args);
   1009  1.1     blymn 	} else {
   1010  1.1     blymn 		line = 0;
   1011  1.1     blymn 		input_delay = 0;
   1012  1.1     blymn 		vars = NULL;
   1013  1.1     blymn 		nvars = 0;
   1014  1.1     blymn 		input_str = NULL;
   1015  1.1     blymn 		saved_output.allocated = 0;
   1016  1.1     blymn 		saved_output.count = 0;
   1017  1.1     blymn 		saved_output.readp = 0;
   1018  1.1     blymn 		saved_output.data = NULL;
   1019  1.1     blymn 	}
   1020  1.1     blymn 
   1021  1.1     blymn 	no_input = false;
   1022  1.1     blymn 	command.function = NULL;
   1023  1.1     blymn 	command.nargs = 0;
   1024  1.1     blymn 	command.args = NULL;
   1025  1.1     blymn 	command.nrets = 0;
   1026  1.1     blymn 	command.returns = NULL;
   1027  1.1     blymn 
   1028  1.1     blymn 	/*
   1029  1.1     blymn 	 * Check the slave pty for stray output from the slave, at this
   1030  1.1     blymn 	 * point we should not see any data as it should have been
   1031  1.1     blymn 	 * consumed by the test functions.  If we see data then we have
   1032  1.1     blymn 	 * either a bug or are not handling an output generating function
   1033  1.1     blymn 	 * correctly.
   1034  1.1     blymn 	 */
   1035  1.1     blymn 	slave_pty.fd = master;
   1036  1.1     blymn 	slave_pty.events = POLLIN;
   1037  1.1     blymn 	slave_pty.revents = 0;
   1038  1.1     blymn 	result = poll(&slave_pty, 1, 0);
   1039  1.1     blymn 
   1040  1.1     blymn 	if (result < 0)
   1041  1.1     blymn 		err(2, "Poll of slave pty failed");
   1042  1.1     blymn 	else if (result > 0)
   1043  1.1     blymn 		fprintf(stderr,
   1044  1.1     blymn 			"Warning: unexpected data from slave at line %d"
   1045  1.1     blymn 			" of file %s\n",
   1046  1.1     blymn 			line, cur_file);
   1047  1.1     blymn }
   1048  1.1     blymn 
   1049  1.1     blymn /*
   1050  1.1     blymn  * Validate the response against the expected return.  The variable
   1051  1.1     blymn  * index is the index into the rets array in command.
   1052  1.1     blymn  */
   1053  1.1     blymn static void
   1054  1.1     blymn validate(int index, void *data)
   1055  1.1     blymn {
   1056  1.1     blymn 	char *response;
   1057  1.1     blymn 	returns_t *byte_response;
   1058  1.1     blymn 
   1059  1.1     blymn 	byte_response = data;
   1060  1.1     blymn 	if ((command.returns[index].return_type != ret_byte) &&
   1061  1.1     blymn 	    (command.returns[index].return_type != ret_err) &&
   1062  1.1     blymn 	    (command.returns[index].return_type != ret_ok))
   1063  1.1     blymn 		response = byte_response->return_value;
   1064  1.1     blymn 
   1065  1.1     blymn 	switch (command.returns[index].return_type) {
   1066  1.1     blymn 	case ret_err:
   1067  1.1     blymn 		validate_type(ret_err, byte_response, 0);
   1068  1.1     blymn 		break;
   1069  1.1     blymn 
   1070  1.1     blymn 	case ret_ok:
   1071  1.1     blymn 		validate_type(ret_ok, byte_response, 0);
   1072  1.1     blymn 		break;
   1073  1.1     blymn 
   1074  1.1     blymn 	case ret_null:
   1075  1.1     blymn 		validate_return("NULL", response, 0);
   1076  1.1     blymn 		break;
   1077  1.1     blymn 
   1078  1.1     blymn 	case ret_nonnull:
   1079  1.1     blymn 		validate_return("NULL", response, 1);
   1080  1.1     blymn 		break;
   1081  1.1     blymn 
   1082  1.1     blymn 	case ret_string:
   1083  1.1     blymn 	case ret_number:
   1084  1.1     blymn 		validate_return(command.returns[index].return_value,
   1085  1.1     blymn 				response, 0);
   1086  1.1     blymn 		break;
   1087  1.1     blymn 
   1088  1.1     blymn 	case ret_ref:
   1089  1.1     blymn 		validate_reference(index, response);
   1090  1.1     blymn 		break;
   1091  1.1     blymn 
   1092  1.1     blymn 	case ret_byte:
   1093  1.1     blymn 		validate_byte(&command.returns[index], byte_response, 0);
   1094  1.1     blymn 		break;
   1095  1.1     blymn 
   1096  1.1     blymn 	default:
   1097  1.1     blymn 		err(1, "Malformed statement at line %d of file %s",
   1098  1.1     blymn 		    line, cur_file);
   1099  1.1     blymn 		break;
   1100  1.1     blymn 	}
   1101  1.1     blymn }
   1102  1.1     blymn 
   1103  1.1     blymn /*
   1104  1.1     blymn  * Validate the return against the contents of a variable.
   1105  1.1     blymn  */
   1106  1.1     blymn static void
   1107  1.1     blymn validate_reference(int index, void *data)
   1108  1.1     blymn {
   1109  1.1     blymn 	char *response;
   1110  1.1     blymn 	returns_t *byte_response;
   1111  1.1     blymn 	var_t *varp;
   1112  1.1     blymn 
   1113  1.1     blymn 	varp = &vars[command.returns[index].return_index];
   1114  1.1     blymn 
   1115  1.1     blymn 	byte_response = data;
   1116  1.1     blymn 	if (command.returns[index].return_type != ret_byte)
   1117  1.1     blymn 		response = data;
   1118  1.1     blymn 
   1119  1.1     blymn 	if (verbose)
   1120  1.1     blymn 		fprintf(stderr,
   1121  1.1     blymn 			"validate_reference: return type of %s, value %s \n",
   1122  1.1     blymn 			returns_enum_names[varp->type], varp->value);
   1123  1.1     blymn 
   1124  1.1     blymn 	switch (varp->type) {
   1125  1.1     blymn 	case ret_string:
   1126  1.1     blymn 	case ret_number:
   1127  1.1     blymn 		validate_return(varp->value, response, 0);
   1128  1.1     blymn 		break;
   1129  1.1     blymn 
   1130  1.1     blymn 	case ret_byte:
   1131  1.1     blymn 		validate_byte(varp->value, byte_response, 0);
   1132  1.1     blymn 		break;
   1133  1.1     blymn 
   1134  1.1     blymn 	default:
   1135  1.1     blymn 		err(1,
   1136  1.1     blymn 		    "Invalid return type for reference at line %d of file %s",
   1137  1.1     blymn 		    line, cur_file);
   1138  1.1     blymn 		break;
   1139  1.1     blymn 	}
   1140  1.1     blymn }
   1141  1.1     blymn 
   1142  1.1     blymn /*
   1143  1.1     blymn  * Validate the return type against the expected type, throw an error
   1144  1.1     blymn  * if they don't match.
   1145  1.1     blymn  */
   1146  1.1     blymn static void
   1147  1.1     blymn validate_type(returns_enum_t expected, returns_t *value, int check)
   1148  1.1     blymn {
   1149  1.1     blymn 	if (((check == 0) && (expected != value->return_type)) ||
   1150  1.1     blymn 	    ((check == 1) && (expected == value->return_type)))
   1151  1.1     blymn 		err(1, "Validate expected type %s %s %s line %d of file %s",
   1152  1.1     blymn 		    returns_enum_names[expected],
   1153  1.1     blymn 		    (check == 0)? "matching" : "not matching",
   1154  1.1     blymn 		    returns_enum_names[value->return_type], line, cur_file);
   1155  1.1     blymn 
   1156  1.1     blymn 	if (verbose)
   1157  1.1     blymn 		fprintf(stderr, "Validate expected type %s %s %s line %d"
   1158  1.1     blymn 			" of file %s\n",
   1159  1.1     blymn 			returns_enum_names[expected],
   1160  1.1     blymn 			(check == 0)? "matching" : "not matching",
   1161  1.1     blymn 			returns_enum_names[value->return_type], line, cur_file);
   1162  1.1     blymn }
   1163  1.1     blymn 
   1164  1.1     blymn /*
   1165  1.1     blymn  * Validate the return value against the expected value, throw an error
   1166  1.1     blymn  * if they don't match.
   1167  1.1     blymn  */
   1168  1.1     blymn static void
   1169  1.1     blymn validate_return(char *expected, char *value, int check)
   1170  1.1     blymn {
   1171  1.1     blymn 	if (((check == 0) && strcmp(expected, value) != 0) ||
   1172  1.1     blymn 	    ((check == 1) && strcmp(expected, value) == 0))
   1173  1.1     blymn 		err(1, "Validate expected %s %s %s line %d of file %s",
   1174  1.1     blymn 		    expected,
   1175  1.1     blymn 		    (check == 0)? "matching" : "not matching", value,
   1176  1.1     blymn 		    line, cur_file);
   1177  1.1     blymn 	if (verbose)
   1178  1.1     blymn 		fprintf(stderr, "Validated expected value %s %s %s "
   1179  1.1     blymn 			"at line %d of file %s\n", expected,
   1180  1.1     blymn 			(check == 0)? "matches" : "does not match",
   1181  1.1     blymn 			value, line, cur_file);
   1182  1.1     blymn }
   1183  1.1     blymn 
   1184  1.1     blymn /*
   1185  1.1     blymn  * Validate the return value against the expected value, throw an error
   1186  1.1     blymn  * if they don't match expectations.
   1187  1.1     blymn  */
   1188  1.1     blymn static void
   1189  1.1     blymn validate_byte(returns_t *expected, returns_t *value, int check)
   1190  1.1     blymn {
   1191  1.1     blymn 	/*
   1192  1.1     blymn 	 * No chance of a match if lengths differ...
   1193  1.1     blymn 	 */
   1194  1.1     blymn 	if ((check == 0) && (expected->return_len != value->return_len))
   1195  1.1     blymn 	    err(1, "Byte validation failed, length mismatch");
   1196  1.1     blymn 
   1197  1.1     blymn 	/*
   1198  1.1     blymn 	 * If check is 0 then we want to throw an error IFF the byte streams
   1199  1.1     blymn 	 * do not match, if check is 1 then throw an error if the byte
   1200  1.1     blymn 	 * streams match.
   1201  1.1     blymn 	 */
   1202  1.1     blymn 	if (((check == 0) && memcmp(expected->return_value, value->return_value,
   1203  1.1     blymn 				    value->return_len) != 0) ||
   1204  1.1     blymn 	    ((check == 1) && (expected->return_len == value->return_len) &&
   1205  1.1     blymn 	     memcmp(expected->return_value, value->return_value,
   1206  1.1     blymn 		    value->return_len) == 0))
   1207  1.1     blymn 		err(1, "Validate expected %s byte stream at line %d"
   1208  1.1     blymn 		    "of file %s",
   1209  1.1     blymn 		    (check == 0)? "matching" : "not matching", line, cur_file);
   1210  1.1     blymn 	if (verbose)
   1211  1.1     blymn 		fprintf(stderr, "Validated expected %s byte stream "
   1212  1.1     blymn 			"at line %d of file %s\n",
   1213  1.1     blymn 			(check == 0)? "matching" : "not matching",
   1214  1.1     blymn 			line, cur_file);
   1215  1.1     blymn }
   1216  1.1     blymn 
   1217  1.1     blymn /*
   1218  1.1     blymn  * Validate the variable at index against the expected value, throw an
   1219  1.1     blymn  * error if they don't match, if check is non-zero then the match is
   1220  1.1     blymn  * negated.
   1221  1.1     blymn  */
   1222  1.1     blymn static void
   1223  1.1     blymn validate_variable(int ret, returns_enum_t type, void *value, int index, int check)
   1224  1.1     blymn {
   1225  1.1     blymn 	char *str;
   1226  1.1     blymn 	returns_t *retval;
   1227  1.1     blymn 	var_t *varptr;
   1228  1.1     blymn 
   1229  1.1     blymn 	varptr = &vars[command.returns[ret].return_index];
   1230  1.1     blymn 
   1231  1.1     blymn 	if (varptr->value == NULL)
   1232  1.1     blymn 		err(1, "Variable %s has no value assigned to it");
   1233  1.1     blymn 
   1234  1.1     blymn 
   1235  1.1     blymn 	if (varptr->type != type)
   1236  1.1     blymn 		err(1, "Variable %s is not the expected type");
   1237  1.1     blymn 
   1238  1.1     blymn 	if (type != ret_byte) {
   1239  1.1     blymn 		if ((((check == 0) && strcmp(value, varptr->value) != 0))
   1240  1.1     blymn 		    || ((check == 1) && strcmp(value, varptr->value) == 0))
   1241  1.1     blymn 			err(1, "Variable %s contains %s instead of %s"
   1242  1.1     blymn 			    " value %s at line %d of file %s",
   1243  1.1     blymn 			    varptr->name,varptr->value,
   1244  1.1     blymn 			    (check == 0)? "expected" : "not matching", value,
   1245  1.1     blymn 			    line, cur_file);
   1246  1.1     blymn 		if (verbose)
   1247  1.1     blymn 			fprintf(stderr, "Variable %s contains %s value "
   1248  1.1     blymn 				"%s at line %d of file %s\n",
   1249  1.1     blymn 				varptr->name,
   1250  1.1     blymn 				(check == 0)? "expected" : "not matching",
   1251  1.1     blymn 				varptr->value, line, cur_file);
   1252  1.1     blymn 	} else {
   1253  1.1     blymn 		if ((check == 0) && (retval->return_len != varptr->len))
   1254  1.1     blymn 			err(1, "Byte validation failed, length mismatch");
   1255  1.1     blymn 
   1256  1.1     blymn 		/*
   1257  1.1     blymn 		 * If check is 0 then we want to throw an error IFF
   1258  1.1     blymn 		 * the byte streams do not match, if check is 1 then
   1259  1.1     blymn 		 * throw an error if the byte streams match.
   1260  1.1     blymn 		 */
   1261  1.1     blymn 		if (((check == 0) && memcmp(retval->return_value, varptr->value,
   1262  1.1     blymn 					    varptr->len) != 0) ||
   1263  1.1     blymn 		    ((check == 1) && (retval->return_len == varptr->len) &&
   1264  1.1     blymn 		     memcmp(retval->return_value, varptr->value,
   1265  1.1     blymn 			    varptr->len) == 0))
   1266  1.1     blymn 			err(1, "Validate expected %s byte stream at line %d"
   1267  1.1     blymn 			    " of file %s",
   1268  1.1     blymn 			    (check == 0)? "matching" : "not matching",
   1269  1.1     blymn 			    line, cur_file);
   1270  1.1     blymn 		if (verbose)
   1271  1.1     blymn 			fprintf(stderr, "Validated expected %s byte stream "
   1272  1.1     blymn 				"at line %d of file %s\n",
   1273  1.1     blymn 				(check == 0)? "matching" : "not matching",
   1274  1.1     blymn 				line, cur_file);
   1275  1.1     blymn 	}
   1276  1.1     blymn }
   1277  1.1     blymn 
   1278  1.1     blymn /*
   1279  1.1     blymn  * Write a string to the command pipe - we feed the number of bytes coming
   1280  1.1     blymn  * down first to allow storage allocation and then follow up with the data.
   1281  1.1     blymn  * If cmd is NULL then feed a -1 down the pipe to say the end of the args.
   1282  1.1     blymn  */
   1283  1.1     blymn static void
   1284  1.1     blymn write_cmd_pipe(char *cmd)
   1285  1.1     blymn {
   1286  1.1     blymn 	args_t arg;
   1287  1.1     blymn 	size_t len;
   1288  1.1     blymn 
   1289  1.1     blymn 	if (cmd == NULL)
   1290  1.1     blymn 		len = 0;
   1291  1.1     blymn 	else
   1292  1.1     blymn 		len = strlen(cmd);
   1293  1.1     blymn 
   1294  1.1     blymn 	arg.arg_type = arg_static;
   1295  1.1     blymn 	arg.arg_len = len;
   1296  1.1     blymn 	arg.arg_string = cmd;
   1297  1.1     blymn 	write_cmd_pipe_args(arg.arg_type, &arg);
   1298  1.1     blymn 
   1299  1.1     blymn }
   1300  1.1     blymn 
   1301  1.1     blymn static void
   1302  1.1     blymn write_cmd_pipe_args(args_state_t type, void *data)
   1303  1.1     blymn {
   1304  1.1     blymn 	var_t *var_data;
   1305  1.1     blymn 	args_t *arg_data;
   1306  1.1     blymn 	int len, send_type;
   1307  1.1     blymn 	void *cmd;
   1308  1.1     blymn 
   1309  1.1     blymn 	arg_data = data;
   1310  1.2     blymn 	switch (type) {
   1311  1.2     blymn 	case arg_var:
   1312  1.2     blymn 		var_data = data;
   1313  1.2     blymn 		len = var_data->len;
   1314  1.2     blymn 		cmd = var_data->value;
   1315  1.2     blymn 		if (var_data->type == arg_byte)
   1316  1.2     blymn 			send_type = ret_byte;
   1317  1.2     blymn 		else
   1318  1.2     blymn 			send_type = ret_string;
   1319  1.2     blymn 		break;
   1320  1.2     blymn 
   1321  1.2     blymn 	case arg_null:
   1322  1.2     blymn 		send_type = ret_null;
   1323  1.2     blymn 		len = 0;
   1324  1.2     blymn 		break;
   1325  1.2     blymn 
   1326  1.2     blymn 	default:
   1327  1.1     blymn 		if ((arg_data->arg_len == 0) && (arg_data->arg_string == NULL))
   1328  1.1     blymn 			len = -1;
   1329  1.1     blymn 		else
   1330  1.1     blymn 			len = arg_data->arg_len;
   1331  1.1     blymn 		cmd = arg_data->arg_string;
   1332  1.1     blymn 		if (type == arg_byte)
   1333  1.1     blymn 			send_type = ret_byte;
   1334  1.1     blymn 		else
   1335  1.1     blymn 			send_type = ret_string;
   1336  1.1     blymn 	}
   1337  1.1     blymn 
   1338  1.1     blymn 	if (verbose)
   1339  1.1     blymn 		fprintf(stderr, "Writing type %s to command pipe\n",
   1340  1.1     blymn 			returns_enum_names[send_type]);
   1341  1.1     blymn 
   1342  1.1     blymn 	if (write(cmdpipe[WRITE_PIPE], &send_type, sizeof(int)) < 0) {
   1343  1.1     blymn 		perror("command pipe write for type failed");
   1344  1.1     blymn 		exit(1);
   1345  1.1     blymn 	}
   1346  1.1     blymn 
   1347  1.1     blymn 	if (verbose)
   1348  1.1     blymn 		fprintf(stderr, "Writing length %d to command pipe\n", len);
   1349  1.1     blymn 
   1350  1.1     blymn 	if (write(cmdpipe[WRITE_PIPE], &len, sizeof(int)) < 0) {
   1351  1.1     blymn 		perror("command pipe write for length failed");
   1352  1.1     blymn 		exit(1);
   1353  1.1     blymn 	}
   1354  1.1     blymn 
   1355  1.1     blymn 	if (len > 0) {
   1356  1.1     blymn 		if (verbose)
   1357  1.1     blymn 			fprintf(stderr, "Writing data >%s< to command pipe\n",
   1358  1.1     blymn 				cmd);
   1359  1.1     blymn 		if (write(cmdpipe[WRITE_PIPE], cmd, len) < 0) {
   1360  1.1     blymn 			perror("command pipe write of data failed");
   1361  1.1     blymn 			exit(1);
   1362  1.1     blymn 		}
   1363  1.1     blymn 	}
   1364  1.1     blymn }
   1365  1.1     blymn 
   1366  1.1     blymn /*
   1367  1.1     blymn  * Read a response from the command pipe, first we will receive the
   1368  1.1     blymn  * length of the response then the actual data.
   1369  1.1     blymn  */
   1370  1.1     blymn static void
   1371  1.1     blymn read_cmd_pipe(returns_t *response)
   1372  1.1     blymn {
   1373  1.1     blymn 	int len, type;
   1374  1.1     blymn 	struct pollfd readfd[2];
   1375  1.1     blymn 	char *str;
   1376  1.1     blymn 
   1377  1.1     blymn 	/*
   1378  1.1     blymn 	 * Check if there is data to read - just in case slave has died, we
   1379  1.1     blymn 	 * don't want to block on the read and just hang.  We also check
   1380  1.1     blymn 	 * output from the slave because the slave may be blocked waiting
   1381  1.1     blymn 	 * for a flush on its stdout.
   1382  1.1     blymn 	 */
   1383  1.1     blymn 	readfd[0].fd = slvpipe[READ_PIPE];
   1384  1.1     blymn 	readfd[0].events = POLLIN;
   1385  1.1     blymn 	readfd[1].fd = master;
   1386  1.1     blymn 	readfd[1].events = POLLIN;
   1387  1.1     blymn 
   1388  1.1     blymn 	do {
   1389  1.1     blymn 		readfd[0].revents = 0;
   1390  1.1     blymn 		readfd[1].revents = 0;
   1391  1.1     blymn 
   1392  1.1     blymn 		if (poll(readfd, 2, 4000) == 0) {
   1393  1.1     blymn 			fprintf(stderr,
   1394  1.1     blymn 				"command pipe read timeout on line %d"
   1395  1.1     blymn 				" of file %s\n",
   1396  1.1     blymn 				line, cur_file);
   1397  1.1     blymn 			exit(2);
   1398  1.1     blymn 		}
   1399  1.1     blymn 
   1400  1.1     blymn 		if ((readfd[1].revents & POLLIN) == POLLIN) {
   1401  1.1     blymn 			if (verbose)
   1402  1.1     blymn 				fprintf(stderr,
   1403  1.1     blymn 					"draining output from slave\n");
   1404  1.1     blymn 			save_slave_output(false);
   1405  1.1     blymn 		}
   1406  1.1     blymn 	}
   1407  1.1     blymn 	while((readfd[1].revents & POLLIN) == POLLIN);
   1408  1.1     blymn 
   1409  1.1     blymn 	if (read(slvpipe[READ_PIPE], &type, sizeof(int)) < 0) {
   1410  1.1     blymn 		perror("command pipe read for type failed");
   1411  1.1     blymn 		exit(1);
   1412  1.1     blymn 	}
   1413  1.1     blymn 	response->return_type = type;
   1414  1.1     blymn 
   1415  1.1     blymn 	if ((type != ret_ok) && (type != ret_err) && (type != ret_count)) {
   1416  1.1     blymn 		if (read(slvpipe[READ_PIPE], &len, sizeof(int)) < 0) {
   1417  1.1     blymn 			perror("command pipe read for length failed");
   1418  1.1     blymn 			exit(1);
   1419  1.1     blymn 		}
   1420  1.1     blymn 		response->return_len = len;
   1421  1.1     blymn 
   1422  1.1     blymn 		if (verbose)
   1423  1.1     blymn 			fprintf(stderr,
   1424  1.1     blymn 				"Reading %d bytes from command pipe\n", len);
   1425  1.1     blymn 
   1426  1.1     blymn 		if ((response->return_value = malloc(len + 1)) == NULL)
   1427  1.1     blymn 			err(1, "Failed to alloc memory for cmd pipe read");
   1428  1.1     blymn 
   1429  1.1     blymn 		if (read(slvpipe[READ_PIPE], response->return_value, len) < 0) {
   1430  1.1     blymn 			perror("command pipe read of data failed");
   1431  1.1     blymn 			exit(1);
   1432  1.1     blymn 		}
   1433  1.1     blymn 
   1434  1.1     blymn 		if (response->return_type != ret_byte) {
   1435  1.1     blymn 			str = response->return_value;
   1436  1.1     blymn 			str[len] = '\0';
   1437  1.1     blymn 
   1438  1.1     blymn 			if (verbose)
   1439  1.1     blymn 				fprintf(stderr, "Read data >%s< from pipe\n",
   1440  1.1     blymn 					response->return_value);
   1441  1.1     blymn 		}
   1442  1.1     blymn 	} else {
   1443  1.1     blymn 		response->return_value = NULL;
   1444  1.1     blymn 		if (type == ret_count) {
   1445  1.1     blymn 			if (read(slvpipe[READ_PIPE], &len, sizeof(int)) < 0) {
   1446  1.1     blymn 				perror("command pipe read for number of "
   1447  1.1     blymn 				       "returns failed");
   1448  1.1     blymn 				exit(1);
   1449  1.1     blymn 			}
   1450  1.1     blymn 			response->return_len = len;
   1451  1.1     blymn 		}
   1452  1.1     blymn 
   1453  1.1     blymn 		if (verbose)
   1454  1.1     blymn 			fprintf(stderr, "Read type %s from pipe\n",
   1455  1.1     blymn 				returns_enum_names[type]);
   1456  1.1     blymn 	}
   1457  1.1     blymn }
   1458  1.1     blymn 
   1459  1.1     blymn /*
   1460  1.1     blymn  * Check for writes from the slave on the pty, save the output into a
   1461  1.1     blymn  * buffer for later checking if discard is false.
   1462  1.1     blymn  */
   1463  1.1     blymn #define MAX_DRAIN 256
   1464  1.1     blymn 
   1465  1.1     blymn static void
   1466  1.1     blymn save_slave_output(bool discard)
   1467  1.1     blymn {
   1468  1.1     blymn 	struct pollfd fd;
   1469  1.1     blymn 	char *new_data, drain[MAX_DRAIN];
   1470  1.1     blymn 	size_t to_allocate;
   1471  1.1     blymn 	int result, i;
   1472  1.1     blymn 
   1473  1.1     blymn 	fd.fd = master;
   1474  1.1     blymn 	fd.events = POLLIN;
   1475  1.1     blymn 	fd.revents = 0;
   1476  1.1     blymn 
   1477  1.1     blymn 	result = 0;
   1478  1.1     blymn 	while (1) {
   1479  1.1     blymn 		if (result == -1)
   1480  1.1     blymn 			err(2, "poll of slave pty failed");
   1481  1.1     blymn 		result = MAX_DRAIN;
   1482  1.1     blymn 		if ((result = read(master, &drain, result)) < 0) {
   1483  1.1     blymn 			if (errno == EAGAIN)
   1484  1.1     blymn 				break;
   1485  1.1     blymn 			else
   1486  1.1     blymn 				err(2, "draining slave pty failed");
   1487  1.1     blymn 		}
   1488  1.1     blymn 
   1489  1.1     blymn 		fd.revents = 0;
   1490  1.1     blymn 		if (discard != true) {
   1491  1.1     blymn 			if (result >
   1492  1.1     blymn 			    (saved_output.allocated - saved_output.count)) {
   1493  1.1     blymn 				to_allocate = 1024 * ((result / 1024) + 1);
   1494  1.1     blymn 
   1495  1.1     blymn 				if ((new_data = realloc(saved_output.data,
   1496  1.1     blymn 					saved_output.allocated + to_allocate))
   1497  1.1     blymn 				    == NULL)
   1498  1.1     blymn 					err(2, "Realloc of saved_output failed");
   1499  1.1     blymn 				saved_output.data = new_data;
   1500  1.1     blymn 				saved_output.allocated += to_allocate;
   1501  1.1     blymn 			}
   1502  1.1     blymn 
   1503  1.1     blymn 			if (verbose) {
   1504  1.1     blymn 				fprintf(stderr, "count = %d, allocated = %d\n",
   1505  1.1     blymn 					saved_output.count,
   1506  1.1     blymn 					saved_output.allocated);
   1507  1.1     blymn 				for (i = 0; i < result; i++) {
   1508  1.1     blymn 					fprintf(stderr, "Saving slave output "
   1509  1.1     blymn 						"0x%x (%c)\n", drain[i],
   1510  1.1     blymn 						(drain[i] >= ' ')? drain[i] : '-');
   1511  1.1     blymn 				}
   1512  1.1     blymn 			}
   1513  1.1     blymn 
   1514  1.1     blymn 			memcpy(&saved_output.data[saved_output.count], drain,
   1515  1.1     blymn 			       result);
   1516  1.1     blymn 			saved_output.count += result;
   1517  1.1     blymn 
   1518  1.1     blymn 			if (verbose) {
   1519  1.1     blymn 				fprintf(stderr, "count = %d, allocated = %d\n",
   1520  1.1     blymn 					saved_output.count,
   1521  1.1     blymn 					saved_output.allocated);
   1522  1.1     blymn 			}
   1523  1.1     blymn 		} else {
   1524  1.1     blymn 			if (verbose) {
   1525  1.1     blymn 				for (i=0; i < result; i++) {
   1526  1.1     blymn 					fprintf(stderr, "Discarding slave "
   1527  1.1     blymn 						"output 0x%x (%c)\n",
   1528  1.1     blymn 						drain[i],
   1529  1.1     blymn 						(drain[i] >= ' ')? drain[i] : '-');
   1530  1.1     blymn 				}
   1531  1.1     blymn 			}
   1532  1.1     blymn 		}
   1533  1.1     blymn 	}
   1534  1.1     blymn }
   1535  1.1     blymn 
   1536  1.1     blymn static void
   1537  1.1     blymn yyerror(const char *msg)
   1538  1.1     blymn {
   1539  1.1     blymn 	warnx("%s in line %zu of file %s", msg, line, cur_file);
   1540  1.1     blymn }
   1541