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