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