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