157718be8SEnji Cooper %{
2*640235e2SEnji Cooper /* $NetBSD: testlang_parse.y,v 1.14 2015/01/04 20:19:46 christos Exp $ */
357718be8SEnji Cooper
457718be8SEnji Cooper /*-
557718be8SEnji Cooper * Copyright 2009 Brett Lymn <blymn@NetBSD.org>
657718be8SEnji Cooper *
757718be8SEnji Cooper * All rights reserved.
857718be8SEnji Cooper *
957718be8SEnji Cooper * This code has been donated to The NetBSD Foundation by the Author.
1057718be8SEnji Cooper *
1157718be8SEnji Cooper * Redistribution and use in source and binary forms, with or without
1257718be8SEnji Cooper * modification, are permitted provided that the following conditions
1357718be8SEnji Cooper * are met:
1457718be8SEnji Cooper * 1. Redistributions of source code must retain the above copyright
1557718be8SEnji Cooper * notice, this list of conditions and the following disclaimer.
1657718be8SEnji Cooper * 2. The name of the author may not be used to endorse or promote products
1757718be8SEnji Cooper * derived from this software withough specific prior written permission
1857718be8SEnji Cooper *
1957718be8SEnji Cooper * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2057718be8SEnji Cooper * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2157718be8SEnji Cooper * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2257718be8SEnji Cooper * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2357718be8SEnji Cooper * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2457718be8SEnji Cooper * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2557718be8SEnji Cooper * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2657718be8SEnji Cooper * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2757718be8SEnji Cooper * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2857718be8SEnji Cooper * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2957718be8SEnji Cooper *
3057718be8SEnji Cooper *
3157718be8SEnji Cooper */
3257718be8SEnji Cooper #include <assert.h>
3357718be8SEnji Cooper #include <curses.h>
3457718be8SEnji Cooper #include <errno.h>
3557718be8SEnji Cooper #include <fcntl.h>
3657718be8SEnji Cooper #include <err.h>
3757718be8SEnji Cooper #include <unistd.h>
3857718be8SEnji Cooper #include <poll.h>
3957718be8SEnji Cooper #include <stdbool.h>
4057718be8SEnji Cooper #include <stdio.h>
4157718be8SEnji Cooper #include <string.h>
42*640235e2SEnji Cooper #include <stdlib.h>
43*640235e2SEnji Cooper #include <limits.h>
4457718be8SEnji Cooper #include <time.h>
4557718be8SEnji Cooper #include <vis.h>
4657718be8SEnji Cooper #include <stdint.h>
4757718be8SEnji Cooper #include "returns.h"
4857718be8SEnji Cooper
4957718be8SEnji Cooper #define YYDEBUG 1
5057718be8SEnji Cooper
5157718be8SEnji Cooper extern int verbose;
5257718be8SEnji Cooper extern int cmdpipe[2];
5357718be8SEnji Cooper extern int slvpipe[2];
5457718be8SEnji Cooper extern int master;
5557718be8SEnji Cooper extern struct pollfd readfd;
5657718be8SEnji Cooper extern char *check_path;
5757718be8SEnji Cooper extern char *cur_file; /* from director.c */
5857718be8SEnji Cooper
5957718be8SEnji Cooper int yylex(void);
6057718be8SEnji Cooper
6157718be8SEnji Cooper size_t line;
6257718be8SEnji Cooper
6357718be8SEnji Cooper static int input_delay;
6457718be8SEnji Cooper
6557718be8SEnji Cooper /* time delay between inputs chars - default to 0.1ms minimum to prevent
6657718be8SEnji Cooper * problems with input tests
6757718be8SEnji Cooper */
6857718be8SEnji Cooper #define DELAY_MIN 0.1
6957718be8SEnji Cooper
7057718be8SEnji Cooper /* time delay after a function call - allows the slave time to
7157718be8SEnji Cooper * run the function and output data before we do other actions.
7257718be8SEnji Cooper * Set this to 50ms.
7357718be8SEnji Cooper */
7457718be8SEnji Cooper #define POST_CALL_DELAY 50
7557718be8SEnji Cooper
7657718be8SEnji Cooper static struct timespec delay_spec = {0, 1000 * DELAY_MIN};
7757718be8SEnji Cooper static struct timespec delay_post_call = {0, 1000 * POST_CALL_DELAY};
7857718be8SEnji Cooper
7957718be8SEnji Cooper static char *input_str; /* string to feed in as input */
8057718be8SEnji Cooper static bool no_input; /* don't need more input */
8157718be8SEnji Cooper
8257718be8SEnji Cooper #define READ_PIPE 0
8357718be8SEnji Cooper #define WRITE_PIPE 1
8457718be8SEnji Cooper
8557718be8SEnji Cooper const char *returns_enum_names[] = {
8657718be8SEnji Cooper "unused", "numeric", "string", "byte", "ERR", "OK", "NULL", "not NULL",
8757718be8SEnji Cooper "variable", "reference", "returns count", "slave error"
8857718be8SEnji Cooper };
8957718be8SEnji Cooper
9057718be8SEnji Cooper typedef enum {
9157718be8SEnji Cooper arg_static,
9257718be8SEnji Cooper arg_byte,
9357718be8SEnji Cooper arg_var,
9457718be8SEnji Cooper arg_null
9557718be8SEnji Cooper } args_state_t;
9657718be8SEnji Cooper
9757718be8SEnji Cooper static const char *args_enum_names[] = {
9857718be8SEnji Cooper "static", "byte", "var", "NULL"
9957718be8SEnji Cooper };
10057718be8SEnji Cooper
10157718be8SEnji Cooper typedef struct {
10257718be8SEnji Cooper args_state_t arg_type;
10357718be8SEnji Cooper size_t arg_len;
10457718be8SEnji Cooper char *arg_string;
10557718be8SEnji Cooper int var_index;
10657718be8SEnji Cooper } args_t;
10757718be8SEnji Cooper
10857718be8SEnji Cooper typedef struct {
10957718be8SEnji Cooper char *function;
11057718be8SEnji Cooper int nrets; /* number of returns */
11157718be8SEnji Cooper returns_t *returns; /* array of expected returns */
11257718be8SEnji Cooper int nargs; /* number of arguments */
11357718be8SEnji Cooper args_t *args; /* arguments for the call */
11457718be8SEnji Cooper } cmd_line_t;
11557718be8SEnji Cooper
11657718be8SEnji Cooper static cmd_line_t command;
11757718be8SEnji Cooper
11857718be8SEnji Cooper typedef struct {
11957718be8SEnji Cooper char *name;
12057718be8SEnji Cooper size_t len;
12157718be8SEnji Cooper returns_enum_t type;
12257718be8SEnji Cooper void *value;
12357718be8SEnji Cooper } var_t;
12457718be8SEnji Cooper
12557718be8SEnji Cooper static size_t nvars; /* Number of declared variables */
12657718be8SEnji Cooper static var_t *vars; /* Variables defined during the test. */
12757718be8SEnji Cooper
12857718be8SEnji Cooper static int check_function_table(char *, const char *[], int);
12957718be8SEnji Cooper static int find_var_index(const char *);
13057718be8SEnji Cooper static void assign_arg(args_state_t, void *);
13157718be8SEnji Cooper static int assign_var(char *);
13257718be8SEnji Cooper void init_parse_variables(int);
13357718be8SEnji Cooper static void validate(int, void *);
13457718be8SEnji Cooper static void validate_return(const char *, const char *, int);
13557718be8SEnji Cooper static void validate_variable(int, returns_enum_t, const void *, int, int);
13657718be8SEnji Cooper static void validate_byte(returns_t *, returns_t *, int);
13757718be8SEnji Cooper static void write_cmd_pipe(char *);
13857718be8SEnji Cooper static void write_cmd_pipe_args(args_state_t, void *);
13957718be8SEnji Cooper static void read_cmd_pipe(returns_t *);
14057718be8SEnji Cooper static void write_func_and_args(void);
14157718be8SEnji Cooper static void compare_streams(char *, bool);
14257718be8SEnji Cooper static void do_function_call(size_t);
14357718be8SEnji Cooper static void save_slave_output(bool);
14457718be8SEnji Cooper static void validate_type(returns_enum_t, returns_t *, int);
14557718be8SEnji Cooper static void set_var(returns_enum_t, char *, void *);
14657718be8SEnji Cooper static void validate_reference(int, void *);
14757718be8SEnji Cooper static char *numeric_or(char *, char *);
14857718be8SEnji Cooper static char *get_numeric_var(const char *);
14957718be8SEnji Cooper static void perform_delay(struct timespec *);
15057718be8SEnji Cooper
15157718be8SEnji Cooper static const char *input_functions[] = {
15257718be8SEnji Cooper "getch", "getnstr", "getstr", "mvgetnstr", "mvgetstr", "mvgetnstr",
15357718be8SEnji Cooper "mvgetstr", "mvscanw", "mvwscanw", "scanw", "wgetch", "wgetnstr",
15457718be8SEnji Cooper "wgetstr"
15557718be8SEnji Cooper };
15657718be8SEnji Cooper
15757718be8SEnji Cooper static const unsigned ninput_functions =
15857718be8SEnji Cooper sizeof(input_functions) / sizeof(char *);
15957718be8SEnji Cooper
16057718be8SEnji Cooper saved_data_t saved_output;
16157718be8SEnji Cooper
16257718be8SEnji Cooper %}
16357718be8SEnji Cooper
16457718be8SEnji Cooper %union {
16557718be8SEnji Cooper char *string;
16657718be8SEnji Cooper returns_t *retval;
16757718be8SEnji Cooper }
16857718be8SEnji Cooper
16957718be8SEnji Cooper %token <string> PATH
17057718be8SEnji Cooper %token <string> STRING
17157718be8SEnji Cooper %token <retval> BYTE
17257718be8SEnji Cooper %token <string> VARNAME
17357718be8SEnji Cooper %token <string> FILENAME
17457718be8SEnji Cooper %token <string> VARIABLE
17557718be8SEnji Cooper %token <string> REFERENCE
17657718be8SEnji Cooper %token <string> NULL_RET
17757718be8SEnji Cooper %token <string> NON_NULL
17857718be8SEnji Cooper %token <string> ERR_RET
17957718be8SEnji Cooper %token <string> OK_RET
18057718be8SEnji Cooper %token <string> numeric
18157718be8SEnji Cooper %token <string> DELAY
18257718be8SEnji Cooper %token <string> INPUT
18357718be8SEnji Cooper %token <string> COMPARE
18457718be8SEnji Cooper %token <string> COMPAREND
18557718be8SEnji Cooper %token <string> ASSIGN
18657718be8SEnji Cooper %token EOL CALL CHECK NOINPUT OR LHB RHB
18757718be8SEnji Cooper %token CALL2 CALL3 CALL4 DRAIN
18857718be8SEnji Cooper
18957718be8SEnji Cooper %nonassoc OR
19057718be8SEnji Cooper
19157718be8SEnji Cooper %%
19257718be8SEnji Cooper
19357718be8SEnji Cooper statement : /* empty */
19457718be8SEnji Cooper | assign statement
19557718be8SEnji Cooper | call statement
19657718be8SEnji Cooper | call2 statement
19757718be8SEnji Cooper | call3 statement
19857718be8SEnji Cooper | call4 statement
19957718be8SEnji Cooper | check statement
20057718be8SEnji Cooper | delay statement
20157718be8SEnji Cooper | input statement
20257718be8SEnji Cooper | noinput statement
20357718be8SEnji Cooper | compare statement
20457718be8SEnji Cooper | comparend statement
20557718be8SEnji Cooper | eol statement
20657718be8SEnji Cooper ;
20757718be8SEnji Cooper
20857718be8SEnji Cooper assign : ASSIGN VARNAME numeric {set_var(ret_number, $2, $3);} eol
20957718be8SEnji Cooper | ASSIGN VARNAME LHB expr RHB {set_var(ret_number, $2, $<string>4);} eol
21057718be8SEnji Cooper | ASSIGN VARNAME STRING {set_var(ret_string, $2, $3);} eol
21157718be8SEnji Cooper | ASSIGN VARNAME BYTE {set_var(ret_byte, $2, $3);} eol
21257718be8SEnji Cooper ;
21357718be8SEnji Cooper
21457718be8SEnji Cooper call : CALL result fn_name args eol {
21557718be8SEnji Cooper do_function_call(1);
21657718be8SEnji Cooper }
21757718be8SEnji Cooper ;
21857718be8SEnji Cooper
21957718be8SEnji Cooper call2 : CALL2 result result fn_name args eol {
22057718be8SEnji Cooper do_function_call(2);
22157718be8SEnji Cooper }
22257718be8SEnji Cooper ;
22357718be8SEnji Cooper
22457718be8SEnji Cooper call3 : CALL3 result result result fn_name args eol {
22557718be8SEnji Cooper do_function_call(3);
22657718be8SEnji Cooper }
22757718be8SEnji Cooper ;
22857718be8SEnji Cooper
22957718be8SEnji Cooper call4 : CALL4 result result result result fn_name args eol {
23057718be8SEnji Cooper do_function_call(4);
23157718be8SEnji Cooper }
23257718be8SEnji Cooper ;
23357718be8SEnji Cooper
23457718be8SEnji Cooper check : CHECK var returns eol {
23557718be8SEnji Cooper returns_t retvar;
23657718be8SEnji Cooper var_t *vptr;
23757718be8SEnji Cooper if (command.returns[0].return_index == -1)
23857718be8SEnji Cooper err(1, "Undefined variable in check statement, line %zu"
23957718be8SEnji Cooper " of file %s", line, cur_file);
24057718be8SEnji Cooper
24157718be8SEnji Cooper if (verbose) {
24257718be8SEnji Cooper fprintf(stderr, "Checking contents of variable %s for %s\n",
24357718be8SEnji Cooper vars[command.returns[0].return_index].name,
24457718be8SEnji Cooper returns_enum_names[command.returns[1].return_type]);
24557718be8SEnji Cooper }
24657718be8SEnji Cooper
24757718be8SEnji Cooper if (((command.returns[1].return_type == ret_byte) &&
24857718be8SEnji Cooper (vars[command.returns[0].return_index].type != ret_byte)) ||
24957718be8SEnji Cooper vars[command.returns[0].return_index].type != ret_string)
25057718be8SEnji Cooper err(1, "Var type %s (%d) does not match return type %s (%d)",
25157718be8SEnji Cooper returns_enum_names[
25257718be8SEnji Cooper vars[command.returns[0].return_index].type],
25357718be8SEnji Cooper vars[command.returns[0].return_index].type,
25457718be8SEnji Cooper returns_enum_names[command.returns[1].return_type],
25557718be8SEnji Cooper command.returns[1].return_type);
25657718be8SEnji Cooper
25757718be8SEnji Cooper switch (command.returns[1].return_type) {
25857718be8SEnji Cooper case ret_err:
25957718be8SEnji Cooper validate_variable(0, ret_string, "ERR",
26057718be8SEnji Cooper command.returns[0].return_index, 0);
26157718be8SEnji Cooper break;
26257718be8SEnji Cooper
26357718be8SEnji Cooper case ret_ok:
26457718be8SEnji Cooper validate_variable(0, ret_string, "OK",
26557718be8SEnji Cooper command.returns[0].return_index, 0);
26657718be8SEnji Cooper break;
26757718be8SEnji Cooper
26857718be8SEnji Cooper case ret_null:
26957718be8SEnji Cooper validate_variable(0, ret_string, "NULL",
27057718be8SEnji Cooper command.returns[0].return_index, 0);
27157718be8SEnji Cooper break;
27257718be8SEnji Cooper
27357718be8SEnji Cooper case ret_nonnull:
27457718be8SEnji Cooper validate_variable(0, ret_string, "NULL",
27557718be8SEnji Cooper command.returns[0].return_index, 1);
27657718be8SEnji Cooper break;
27757718be8SEnji Cooper
27857718be8SEnji Cooper case ret_string:
27957718be8SEnji Cooper case ret_number:
28057718be8SEnji Cooper if (verbose) {
28157718be8SEnji Cooper fprintf(stderr, " %s == returned %s\n",
28257718be8SEnji Cooper (const char *)command.returns[1].return_value,
28357718be8SEnji Cooper (const char *)
28457718be8SEnji Cooper vars[command.returns[0].return_index].value);
28557718be8SEnji Cooper }
28657718be8SEnji Cooper validate_variable(0, ret_string,
28757718be8SEnji Cooper command.returns[1].return_value,
28857718be8SEnji Cooper command.returns[0].return_index, 0);
28957718be8SEnji Cooper break;
29057718be8SEnji Cooper
29157718be8SEnji Cooper case ret_byte:
29257718be8SEnji Cooper vptr = &vars[command.returns[0].return_index];
29357718be8SEnji Cooper retvar.return_len = vptr->len;
29457718be8SEnji Cooper retvar.return_type = vptr->type;
29557718be8SEnji Cooper retvar.return_value = vptr->value;
29657718be8SEnji Cooper validate_byte(&retvar, &command.returns[1], 0);
29757718be8SEnji Cooper break;
29857718be8SEnji Cooper
29957718be8SEnji Cooper default:
30057718be8SEnji Cooper err(1, "Malformed check statement at line %zu "
30157718be8SEnji Cooper "of file %s", line, cur_file);
30257718be8SEnji Cooper break;
30357718be8SEnji Cooper }
30457718be8SEnji Cooper
30557718be8SEnji Cooper init_parse_variables(0);
30657718be8SEnji Cooper }
30757718be8SEnji Cooper ;
30857718be8SEnji Cooper
30957718be8SEnji Cooper delay : DELAY numeric eol {
31057718be8SEnji Cooper /* set the inter-character delay */
31157718be8SEnji Cooper if (sscanf($2, "%d", &input_delay) == 0)
31257718be8SEnji Cooper err(1, "delay specification %s could not be converted to "
31357718be8SEnji Cooper "numeric at line %zu of file %s", $2, line, cur_file);
31457718be8SEnji Cooper if (verbose) {
31557718be8SEnji Cooper fprintf(stderr, "Set input delay to %d ms\n", input_delay);
31657718be8SEnji Cooper }
31757718be8SEnji Cooper
31857718be8SEnji Cooper if (input_delay < DELAY_MIN)
31957718be8SEnji Cooper input_delay = DELAY_MIN;
32057718be8SEnji Cooper /*
32157718be8SEnji Cooper * Fill in the timespec structure now ready for use later.
32257718be8SEnji Cooper * The delay is specified in milliseconds so convert to timespec
32357718be8SEnji Cooper * values
32457718be8SEnji Cooper */
32557718be8SEnji Cooper delay_spec.tv_sec = input_delay / 1000;
32657718be8SEnji Cooper delay_spec.tv_nsec = (input_delay - 1000 * delay_spec.tv_sec) * 1000;
32757718be8SEnji Cooper if (verbose) {
32857718be8SEnji Cooper fprintf(stderr, "set delay to %jd.%jd\n",
32957718be8SEnji Cooper (intmax_t)delay_spec.tv_sec,
33057718be8SEnji Cooper (intmax_t)delay_spec.tv_nsec);
33157718be8SEnji Cooper }
33257718be8SEnji Cooper
33357718be8SEnji Cooper init_parse_variables(0);
33457718be8SEnji Cooper }
33557718be8SEnji Cooper ;
33657718be8SEnji Cooper
33757718be8SEnji Cooper input : INPUT STRING eol {
33857718be8SEnji Cooper if (input_str != NULL) {
33957718be8SEnji Cooper warnx("%s, %zu: Discarding unused input string",
34057718be8SEnji Cooper cur_file, line);
34157718be8SEnji Cooper free(input_str);
34257718be8SEnji Cooper }
34357718be8SEnji Cooper
34457718be8SEnji Cooper if ((input_str = malloc(strlen($2) + 1)) == NULL)
34557718be8SEnji Cooper err(2, "Cannot allocate memory for input string");
34657718be8SEnji Cooper
34757718be8SEnji Cooper strlcpy(input_str, $2, strlen($2) + 1);
34857718be8SEnji Cooper }
34957718be8SEnji Cooper ;
35057718be8SEnji Cooper
35157718be8SEnji Cooper
35257718be8SEnji Cooper noinput : NOINPUT eol {
35357718be8SEnji Cooper if (input_str != NULL) {
35457718be8SEnji Cooper warnx("%s, %zu: Discarding unused input string",
35557718be8SEnji Cooper cur_file, line);
35657718be8SEnji Cooper free(input_str);
35757718be8SEnji Cooper }
35857718be8SEnji Cooper
35957718be8SEnji Cooper no_input = true;
36057718be8SEnji Cooper }
36157718be8SEnji Cooper
36257718be8SEnji Cooper compare : COMPARE PATH eol
36357718be8SEnji Cooper | COMPARE FILENAME eol
36457718be8SEnji Cooper {
36557718be8SEnji Cooper compare_streams($2, true);
36657718be8SEnji Cooper }
36757718be8SEnji Cooper ;
36857718be8SEnji Cooper
36957718be8SEnji Cooper
37057718be8SEnji Cooper comparend : COMPAREND PATH eol
37157718be8SEnji Cooper | COMPAREND FILENAME eol
37257718be8SEnji Cooper {
37357718be8SEnji Cooper compare_streams($2, false);
37457718be8SEnji Cooper }
37557718be8SEnji Cooper ;
37657718be8SEnji Cooper
37757718be8SEnji Cooper
37857718be8SEnji Cooper result : returns
37957718be8SEnji Cooper | var
38057718be8SEnji Cooper | reference
38157718be8SEnji Cooper ;
38257718be8SEnji Cooper
38357718be8SEnji Cooper returns : numeric { assign_rets(ret_number, $1); }
38457718be8SEnji Cooper | LHB expr RHB { assign_rets(ret_number, $<string>2); }
38557718be8SEnji Cooper | STRING { assign_rets(ret_string, $1); }
38657718be8SEnji Cooper | BYTE { assign_rets(ret_byte, (void *) $1); }
38757718be8SEnji Cooper | ERR_RET { assign_rets(ret_err, NULL); }
38857718be8SEnji Cooper | OK_RET { assign_rets(ret_ok, NULL); }
38957718be8SEnji Cooper | NULL_RET { assign_rets(ret_null, NULL); }
39057718be8SEnji Cooper | NON_NULL { assign_rets(ret_nonnull, NULL); }
39157718be8SEnji Cooper ;
39257718be8SEnji Cooper
39357718be8SEnji Cooper var : VARNAME {
39457718be8SEnji Cooper assign_rets(ret_var, $1);
39557718be8SEnji Cooper }
39657718be8SEnji Cooper ;
39757718be8SEnji Cooper
39857718be8SEnji Cooper reference : VARIABLE {
39957718be8SEnji Cooper assign_rets(ret_ref, $1);
40057718be8SEnji Cooper }
40157718be8SEnji Cooper
40257718be8SEnji Cooper fn_name : VARNAME {
40357718be8SEnji Cooper if (command.function != NULL)
40457718be8SEnji Cooper free(command.function);
40557718be8SEnji Cooper
40657718be8SEnji Cooper command.function = malloc(strlen($1) + 1);
40757718be8SEnji Cooper if (command.function == NULL)
40857718be8SEnji Cooper err(1, "Could not allocate memory for function name");
40957718be8SEnji Cooper strcpy(command.function, $1);
41057718be8SEnji Cooper }
41157718be8SEnji Cooper ;
41257718be8SEnji Cooper
41357718be8SEnji Cooper expr : numeric
41457718be8SEnji Cooper | VARIABLE
41557718be8SEnji Cooper { $<string>$ = get_numeric_var($1); }
41657718be8SEnji Cooper | expr OR expr
41757718be8SEnji Cooper { $<string>$ = numeric_or($<string>1, $<string>3); }
41857718be8SEnji Cooper ;
41957718be8SEnji Cooper
42057718be8SEnji Cooper args : /* empty */
42157718be8SEnji Cooper | LHB expr RHB { assign_arg(arg_static, $<string>2); } args
42257718be8SEnji Cooper | numeric { assign_arg(arg_static, $1); } args
42357718be8SEnji Cooper | STRING { assign_arg(arg_static, $1); } args
42457718be8SEnji Cooper | BYTE { assign_arg(arg_byte, $1); } args
42557718be8SEnji Cooper | PATH { assign_arg(arg_static, $1); } args
42657718be8SEnji Cooper | FILENAME { assign_arg(arg_static, $1); } args
42757718be8SEnji Cooper | VARNAME { assign_arg(arg_static, $1); } args
42857718be8SEnji Cooper | VARIABLE { assign_arg(arg_var, $1); } args
42957718be8SEnji Cooper | NULL_RET { assign_arg(arg_null, $1); } args
43057718be8SEnji Cooper ;
43157718be8SEnji Cooper
43257718be8SEnji Cooper eol : EOL
43357718be8SEnji Cooper ;
43457718be8SEnji Cooper
43557718be8SEnji Cooper %%
43657718be8SEnji Cooper
43757718be8SEnji Cooper static void
43857718be8SEnji Cooper excess(const char *fname, size_t lineno, const char *func, const char *comment,
43957718be8SEnji Cooper const void *data, size_t datalen)
44057718be8SEnji Cooper {
44157718be8SEnji Cooper size_t dstlen = datalen * 4 + 1;
44257718be8SEnji Cooper char *dst = malloc(dstlen);
44357718be8SEnji Cooper
44457718be8SEnji Cooper if (dst == NULL)
44557718be8SEnji Cooper err(1, "malloc");
44657718be8SEnji Cooper
44757718be8SEnji Cooper if (strnvisx(dst, dstlen, data, datalen, VIS_WHITE | VIS_OCTAL) == -1)
44857718be8SEnji Cooper err(1, "strnvisx");
44957718be8SEnji Cooper
45057718be8SEnji Cooper warnx("%s, %zu: [%s] Excess %zu bytes%s [%s]",
45157718be8SEnji Cooper fname, lineno, func, datalen, comment, dst);
45257718be8SEnji Cooper free(dst);
45357718be8SEnji Cooper }
45457718be8SEnji Cooper
45557718be8SEnji Cooper /*
45657718be8SEnji Cooper * Get the value of a variable, error if the variable has not been set or
45757718be8SEnji Cooper * is not a numeric type.
45857718be8SEnji Cooper */
45957718be8SEnji Cooper static char *
get_numeric_var(const char * var)46057718be8SEnji Cooper get_numeric_var(const char *var)
46157718be8SEnji Cooper {
46257718be8SEnji Cooper int i;
46357718be8SEnji Cooper
46457718be8SEnji Cooper if ((i = find_var_index(var)) < 0)
46557718be8SEnji Cooper err(1, "Variable %s is undefined", var);
46657718be8SEnji Cooper
46757718be8SEnji Cooper if (vars[i].type != ret_number)
46857718be8SEnji Cooper err(1, "Variable %s is not a numeric type", var);
46957718be8SEnji Cooper
47057718be8SEnji Cooper return vars[i].value;
47157718be8SEnji Cooper }
47257718be8SEnji Cooper
47357718be8SEnji Cooper /*
47457718be8SEnji Cooper * Perform a bitwise OR on two numbers and return the result.
47557718be8SEnji Cooper */
47657718be8SEnji Cooper static char *
numeric_or(char * n1,char * n2)47757718be8SEnji Cooper numeric_or(char *n1, char *n2)
47857718be8SEnji Cooper {
47957718be8SEnji Cooper unsigned long i1, i2, result;
48057718be8SEnji Cooper char *ret;
48157718be8SEnji Cooper
48257718be8SEnji Cooper i1 = strtoul(n1, NULL, 10);
48357718be8SEnji Cooper i2 = strtoul(n2, NULL, 10);
48457718be8SEnji Cooper
48557718be8SEnji Cooper result = i1 | i2;
48657718be8SEnji Cooper asprintf(&ret, "%lu", result);
48757718be8SEnji Cooper
48857718be8SEnji Cooper if (verbose) {
48957718be8SEnji Cooper fprintf(stderr, "numeric or of 0x%lx (%s) and 0x%lx (%s)"
49057718be8SEnji Cooper " results in 0x%lx (%s)\n",
49157718be8SEnji Cooper i1, n1, i2, n2, result, ret);
49257718be8SEnji Cooper }
49357718be8SEnji Cooper
49457718be8SEnji Cooper return ret;
49557718be8SEnji Cooper }
49657718be8SEnji Cooper
49757718be8SEnji Cooper /*
49857718be8SEnji Cooper * Sleep for the specified time, handle the sleep getting interrupted
49957718be8SEnji Cooper * by a signal.
50057718be8SEnji Cooper */
50157718be8SEnji Cooper static void
perform_delay(struct timespec * ts)50257718be8SEnji Cooper perform_delay(struct timespec *ts)
50357718be8SEnji Cooper {
50457718be8SEnji Cooper struct timespec delay_copy, delay_remainder;
50557718be8SEnji Cooper
50657718be8SEnji Cooper delay_copy = *ts;
50757718be8SEnji Cooper while (nanosleep(&delay_copy, &delay_remainder) < 0) {
50857718be8SEnji Cooper if (errno != EINTR)
50957718be8SEnji Cooper err(2, "nanosleep returned error");
51057718be8SEnji Cooper delay_copy = delay_remainder;
51157718be8SEnji Cooper }
51257718be8SEnji Cooper }
51357718be8SEnji Cooper
51457718be8SEnji Cooper /*
51557718be8SEnji Cooper * Assign the value given to the named variable.
51657718be8SEnji Cooper */
51757718be8SEnji Cooper static void
set_var(returns_enum_t type,char * name,void * value)51857718be8SEnji Cooper set_var(returns_enum_t type, char *name, void *value)
51957718be8SEnji Cooper {
52057718be8SEnji Cooper int i;
52157718be8SEnji Cooper char *number;
52257718be8SEnji Cooper returns_t *ret;
52357718be8SEnji Cooper
52457718be8SEnji Cooper i = find_var_index(name);
52557718be8SEnji Cooper if (i < 0)
52657718be8SEnji Cooper i = assign_var(name);
52757718be8SEnji Cooper
52857718be8SEnji Cooper vars[i].type = type;
52957718be8SEnji Cooper if ((type == ret_number) || (type == ret_string)) {
53057718be8SEnji Cooper number = value;
53157718be8SEnji Cooper vars[i].len = strlen(number) + 1;
53257718be8SEnji Cooper vars[i].value = malloc(vars[i].len + 1);
53357718be8SEnji Cooper if (vars[i].value == NULL)
53457718be8SEnji Cooper err(1, "Could not malloc memory for assign string");
53557718be8SEnji Cooper strcpy(vars[i].value, number);
53657718be8SEnji Cooper } else {
53757718be8SEnji Cooper /* can only be a byte value */
53857718be8SEnji Cooper ret = value;
53957718be8SEnji Cooper vars[i].len = ret->return_len;
54057718be8SEnji Cooper vars[i].value = malloc(vars[i].len);
54157718be8SEnji Cooper if (vars[i].value == NULL)
54257718be8SEnji Cooper err(1, "Could not malloc memory to assign byte string");
54357718be8SEnji Cooper memcpy(vars[i].value, ret->return_value, vars[i].len);
54457718be8SEnji Cooper }
54557718be8SEnji Cooper }
54657718be8SEnji Cooper
54757718be8SEnji Cooper /*
54857718be8SEnji Cooper * Add a new variable to the vars array, the value will be assigned later,
54957718be8SEnji Cooper * when a test function call returns.
55057718be8SEnji Cooper */
55157718be8SEnji Cooper static int
assign_var(char * varname)55257718be8SEnji Cooper assign_var(char *varname)
55357718be8SEnji Cooper {
55457718be8SEnji Cooper var_t *temp;
55557718be8SEnji Cooper char *name;
55657718be8SEnji Cooper
55757718be8SEnji Cooper if ((name = malloc(strlen(varname) + 1)) == NULL)
55857718be8SEnji Cooper err(1, "Alloc of varname failed");
55957718be8SEnji Cooper
56057718be8SEnji Cooper if ((temp = realloc(vars, sizeof(*temp) * (nvars + 1))) == NULL) {
56157718be8SEnji Cooper free(name);
56257718be8SEnji Cooper err(1, "Realloc of vars array failed");
56357718be8SEnji Cooper }
56457718be8SEnji Cooper
56557718be8SEnji Cooper strcpy(name, varname);
56657718be8SEnji Cooper vars = temp;
56757718be8SEnji Cooper vars[nvars].name = name;
56857718be8SEnji Cooper vars[nvars].len = 0;
56957718be8SEnji Cooper vars[nvars].value = NULL;
57057718be8SEnji Cooper nvars++;
57157718be8SEnji Cooper
57257718be8SEnji Cooper return (nvars - 1);
57357718be8SEnji Cooper }
57457718be8SEnji Cooper
57557718be8SEnji Cooper /*
57657718be8SEnji Cooper * Allocate and assign a new argument of the given type.
57757718be8SEnji Cooper */
57857718be8SEnji Cooper static void
assign_arg(args_state_t arg_type,void * arg)57957718be8SEnji Cooper assign_arg(args_state_t arg_type, void *arg)
58057718be8SEnji Cooper {
58157718be8SEnji Cooper args_t *temp, cur;
58257718be8SEnji Cooper char *str = arg;
58357718be8SEnji Cooper returns_t *ret;
58457718be8SEnji Cooper
58557718be8SEnji Cooper if (verbose) {
58657718be8SEnji Cooper fprintf(stderr, "function is >%s<, adding arg >%s< type %s\n",
58757718be8SEnji Cooper command.function, str, args_enum_names[arg_type]);
58857718be8SEnji Cooper }
58957718be8SEnji Cooper
59057718be8SEnji Cooper cur.arg_type = arg_type;
59157718be8SEnji Cooper switch (arg_type) {
59257718be8SEnji Cooper case arg_var:
59357718be8SEnji Cooper cur.var_index = find_var_index(arg);
59457718be8SEnji Cooper if (cur.var_index < 0)
59557718be8SEnji Cooper err(1, "Invalid variable %s at line %zu of file %s",
59657718be8SEnji Cooper str, line, cur_file);
59757718be8SEnji Cooper cur.arg_type = ret_string;
59857718be8SEnji Cooper break;
59957718be8SEnji Cooper
60057718be8SEnji Cooper case arg_byte:
60157718be8SEnji Cooper ret = arg;
60257718be8SEnji Cooper cur.arg_len = ret->return_len;
60357718be8SEnji Cooper cur.arg_string = malloc(cur.arg_len);
60457718be8SEnji Cooper if (cur.arg_string == NULL)
60557718be8SEnji Cooper err(1, "Could not malloc memory for arg bytes");
60657718be8SEnji Cooper memcpy(cur.arg_string, ret->return_value, cur.arg_len);
60757718be8SEnji Cooper break;
60857718be8SEnji Cooper
60957718be8SEnji Cooper case arg_null:
61057718be8SEnji Cooper cur.arg_len = 0;
61157718be8SEnji Cooper cur.arg_string = NULL;
61257718be8SEnji Cooper break;
61357718be8SEnji Cooper
61457718be8SEnji Cooper default:
61557718be8SEnji Cooper cur.arg_len = strlen(str);
61657718be8SEnji Cooper cur.arg_string = malloc(cur.arg_len + 1);
61757718be8SEnji Cooper if (cur.arg_string == NULL)
61857718be8SEnji Cooper err(1, "Could not malloc memory for arg string");
61957718be8SEnji Cooper strcpy(cur.arg_string, arg);
62057718be8SEnji Cooper }
62157718be8SEnji Cooper
62257718be8SEnji Cooper temp = realloc(command.args, sizeof(*temp) * (command.nargs + 1));
62357718be8SEnji Cooper if (temp == NULL)
62457718be8SEnji Cooper err(1, "Failed to reallocate args");
62557718be8SEnji Cooper command.args = temp;
62657718be8SEnji Cooper memcpy(&command.args[command.nargs], &cur, sizeof(args_t));
62757718be8SEnji Cooper command.nargs++;
62857718be8SEnji Cooper }
62957718be8SEnji Cooper
63057718be8SEnji Cooper /*
63157718be8SEnji Cooper * Allocate and assign a new return.
63257718be8SEnji Cooper */
63357718be8SEnji Cooper static void
assign_rets(returns_enum_t ret_type,void * ret)63457718be8SEnji Cooper assign_rets(returns_enum_t ret_type, void *ret)
63557718be8SEnji Cooper {
63657718be8SEnji Cooper returns_t *temp, cur;
63757718be8SEnji Cooper char *ret_str;
63857718be8SEnji Cooper returns_t *ret_ret;
63957718be8SEnji Cooper
64057718be8SEnji Cooper cur.return_type = ret_type;
64157718be8SEnji Cooper if (ret_type != ret_var) {
64257718be8SEnji Cooper if ((ret_type == ret_number) || (ret_type == ret_string)) {
64357718be8SEnji Cooper ret_str = ret;
64457718be8SEnji Cooper cur.return_len = strlen(ret_str) + 1;
64557718be8SEnji Cooper cur.return_value = malloc(cur.return_len + 1);
64657718be8SEnji Cooper if (cur.return_value == NULL)
64757718be8SEnji Cooper err(1,
64857718be8SEnji Cooper "Could not malloc memory for arg string");
64957718be8SEnji Cooper strcpy(cur.return_value, ret_str);
65057718be8SEnji Cooper } else if (ret_type == ret_byte) {
65157718be8SEnji Cooper ret_ret = ret;
65257718be8SEnji Cooper cur.return_len = ret_ret->return_len;
65357718be8SEnji Cooper cur.return_value = malloc(cur.return_len);
65457718be8SEnji Cooper if (cur.return_value == NULL)
65557718be8SEnji Cooper err(1,
65657718be8SEnji Cooper "Could not malloc memory for byte string");
65757718be8SEnji Cooper memcpy(cur.return_value, ret_ret->return_value,
65857718be8SEnji Cooper cur.return_len);
65957718be8SEnji Cooper } else if (ret_type == ret_ref) {
66057718be8SEnji Cooper if ((cur.return_index = find_var_index(ret)) < 0)
66157718be8SEnji Cooper err(1, "Undefined variable reference");
66257718be8SEnji Cooper }
66357718be8SEnji Cooper } else {
66457718be8SEnji Cooper cur.return_index = find_var_index(ret);
66557718be8SEnji Cooper if (cur.return_index < 0)
66657718be8SEnji Cooper cur.return_index = assign_var(ret);
66757718be8SEnji Cooper }
66857718be8SEnji Cooper
66957718be8SEnji Cooper temp = realloc(command.returns, sizeof(*temp) * (command.nrets + 1));
67057718be8SEnji Cooper if (temp == NULL)
67157718be8SEnji Cooper err(1, "Failed to reallocate returns");
67257718be8SEnji Cooper command.returns = temp;
67357718be8SEnji Cooper memcpy(&command.returns[command.nrets], &cur, sizeof(returns_t));
67457718be8SEnji Cooper command.nrets++;
67557718be8SEnji Cooper }
67657718be8SEnji Cooper
67757718be8SEnji Cooper /*
67857718be8SEnji Cooper * Find the given variable name in the var array and return the i
67957718be8SEnji Cooper * return -1 if var is not found.
68057718be8SEnji Cooper */
68157718be8SEnji Cooper static int
find_var_index(const char * var_name)68257718be8SEnji Cooper find_var_index(const char *var_name)
68357718be8SEnji Cooper {
68457718be8SEnji Cooper int result;
68557718be8SEnji Cooper size_t i;
68657718be8SEnji Cooper
68757718be8SEnji Cooper result = -1;
68857718be8SEnji Cooper
68957718be8SEnji Cooper for (i = 0; i < nvars; i++) {
69057718be8SEnji Cooper if (strcmp(var_name, vars[i].name) == 0) {
69157718be8SEnji Cooper result = i;
69257718be8SEnji Cooper break;
69357718be8SEnji Cooper }
69457718be8SEnji Cooper }
69557718be8SEnji Cooper
69657718be8SEnji Cooper return result;
69757718be8SEnji Cooper }
69857718be8SEnji Cooper
69957718be8SEnji Cooper /*
70057718be8SEnji Cooper * Check the given function name in the given table of names, return 1 if
70157718be8SEnji Cooper * there is a match.
70257718be8SEnji Cooper */
check_function_table(char * function,const char * table[],int nfunctions)70357718be8SEnji Cooper static int check_function_table(char *function, const char *table[],
70457718be8SEnji Cooper int nfunctions)
70557718be8SEnji Cooper {
70657718be8SEnji Cooper int i;
70757718be8SEnji Cooper
70857718be8SEnji Cooper for (i = 0; i < nfunctions; i++) {
70957718be8SEnji Cooper if ((strlen(function) == strlen(table[i])) &&
71057718be8SEnji Cooper (strcmp(function, table[i]) == 0))
71157718be8SEnji Cooper return 1;
71257718be8SEnji Cooper }
71357718be8SEnji Cooper
71457718be8SEnji Cooper return 0;
71557718be8SEnji Cooper }
71657718be8SEnji Cooper
71757718be8SEnji Cooper /*
71857718be8SEnji Cooper * Compare the output from the slave against the given file and report
71957718be8SEnji Cooper * any differences.
72057718be8SEnji Cooper */
72157718be8SEnji Cooper static void
compare_streams(char * filename,bool discard)72257718be8SEnji Cooper compare_streams(char *filename, bool discard)
72357718be8SEnji Cooper {
72457718be8SEnji Cooper char check_file[PATH_MAX], drain[100], ref, data;
72557718be8SEnji Cooper struct pollfd fds[2];
72657718be8SEnji Cooper int nfd, check_fd;
72757718be8SEnji Cooper ssize_t result;
72857718be8SEnji Cooper size_t offs;
72957718be8SEnji Cooper
73057718be8SEnji Cooper /*
73157718be8SEnji Cooper * Don't prepend check path iff check file has an absolute
73257718be8SEnji Cooper * path.
73357718be8SEnji Cooper */
73457718be8SEnji Cooper if (filename[0] != '/') {
73557718be8SEnji Cooper if (strlcpy(check_file, check_path, sizeof(check_file))
73657718be8SEnji Cooper >= sizeof(check_file))
73757718be8SEnji Cooper err(2, "CHECK_PATH too long");
73857718be8SEnji Cooper
73957718be8SEnji Cooper if (strlcat(check_file, "/", sizeof(check_file))
74057718be8SEnji Cooper >= sizeof(check_file))
74157718be8SEnji Cooper err(2, "Could not append / to check file path");
74257718be8SEnji Cooper } else {
74357718be8SEnji Cooper check_file[0] = '\0';
74457718be8SEnji Cooper }
74557718be8SEnji Cooper
74657718be8SEnji Cooper if (strlcat(check_file, filename, sizeof(check_file))
74757718be8SEnji Cooper >= sizeof(check_file))
74857718be8SEnji Cooper err(2, "Path to check file path overflowed");
74957718be8SEnji Cooper
75057718be8SEnji Cooper if ((check_fd = open(check_file, O_RDONLY, 0)) < 0)
75157718be8SEnji Cooper err(2, "failed to open file %s line %zu of file %s",
75257718be8SEnji Cooper check_file, line, cur_file);
75357718be8SEnji Cooper
75457718be8SEnji Cooper fds[0].fd = check_fd;
75557718be8SEnji Cooper fds[0].events = POLLIN;
75657718be8SEnji Cooper fds[1].fd = master;
75757718be8SEnji Cooper fds[1].events = POLLIN;
75857718be8SEnji Cooper
75957718be8SEnji Cooper nfd = 2;
76057718be8SEnji Cooper /*
76157718be8SEnji Cooper * if we have saved output then only check for data in the
76257718be8SEnji Cooper * reference file since the slave data may already be drained.
76357718be8SEnji Cooper */
76457718be8SEnji Cooper if (saved_output.count > 0)
76557718be8SEnji Cooper nfd = 1;
76657718be8SEnji Cooper
76757718be8SEnji Cooper offs = 0;
76857718be8SEnji Cooper while (poll(fds, nfd, 500) == nfd) {
76957718be8SEnji Cooper if (fds[0].revents & POLLIN) {
77057718be8SEnji Cooper if ((result = read(check_fd, &ref, 1)) < 1) {
77157718be8SEnji Cooper if (result != 0) {
77257718be8SEnji Cooper err(2,
77357718be8SEnji Cooper "Bad read on file %s", check_file);
77457718be8SEnji Cooper } else {
77557718be8SEnji Cooper break;
77657718be8SEnji Cooper }
77757718be8SEnji Cooper }
77857718be8SEnji Cooper }
77957718be8SEnji Cooper
78057718be8SEnji Cooper if (saved_output.count > 0) {
78157718be8SEnji Cooper data = saved_output.data[saved_output.readp];
78257718be8SEnji Cooper saved_output.count--;
78357718be8SEnji Cooper saved_output.readp++;
78457718be8SEnji Cooper /* run out of saved data, switch to file */
78557718be8SEnji Cooper if (saved_output.count == 0)
78657718be8SEnji Cooper nfd = 2;
78757718be8SEnji Cooper } else {
78857718be8SEnji Cooper if (fds[0].revents & POLLIN) {
78957718be8SEnji Cooper if (read(master, &data, 1) < 1)
79057718be8SEnji Cooper err(2, "Bad read on slave pty");
79157718be8SEnji Cooper } else
79257718be8SEnji Cooper continue;
79357718be8SEnji Cooper }
79457718be8SEnji Cooper
79557718be8SEnji Cooper if (verbose) {
79657718be8SEnji Cooper fprintf(stderr, "Comparing reference byte 0x%x (%c)"
79757718be8SEnji Cooper " against slave byte 0x%x (%c)\n",
79857718be8SEnji Cooper ref, (ref >= ' ') ? ref : '-',
79957718be8SEnji Cooper data, (data >= ' ' )? data : '-');
80057718be8SEnji Cooper }
80157718be8SEnji Cooper
80257718be8SEnji Cooper if (ref != data) {
80357718be8SEnji Cooper errx(2, "%s, %zu: refresh data from slave does "
80457718be8SEnji Cooper "not match expected from file %s offs %zu "
80557718be8SEnji Cooper "[reference 0x%x (%c) != slave 0x%x (%c)]",
80657718be8SEnji Cooper cur_file, line, check_file, offs,
80757718be8SEnji Cooper ref, (ref >= ' ') ? ref : '-',
80857718be8SEnji Cooper data, (data >= ' ') ? data : '-');
80957718be8SEnji Cooper }
81057718be8SEnji Cooper
81157718be8SEnji Cooper offs++;
81257718be8SEnji Cooper }
81357718be8SEnji Cooper
81457718be8SEnji Cooper
81557718be8SEnji Cooper if (saved_output.count > 0)
81657718be8SEnji Cooper excess(cur_file, line, __func__, " from slave",
81757718be8SEnji Cooper &saved_output.data[saved_output.readp], saved_output.count);
81857718be8SEnji Cooper
81957718be8SEnji Cooper /* discard any excess saved output if required */
82057718be8SEnji Cooper if (discard) {
82157718be8SEnji Cooper saved_output.count = 0;
82257718be8SEnji Cooper saved_output.readp = 0;
82357718be8SEnji Cooper }
82457718be8SEnji Cooper
82557718be8SEnji Cooper if ((result = poll(&fds[0], 2, 0)) != 0) {
82657718be8SEnji Cooper if (result == -1)
82757718be8SEnji Cooper err(2, "poll of file descriptors failed");
82857718be8SEnji Cooper
82957718be8SEnji Cooper if ((fds[1].revents & POLLIN) == POLLIN) {
83057718be8SEnji Cooper save_slave_output(true);
83157718be8SEnji Cooper } else if ((fds[0].revents & POLLIN) == POLLIN) {
83257718be8SEnji Cooper /*
83357718be8SEnji Cooper * handle excess in file if it exists. Poll
83457718be8SEnji Cooper * says there is data until EOF is read.
83557718be8SEnji Cooper * Check next read is EOF, if it is not then
83657718be8SEnji Cooper * the file really has more data than the
83757718be8SEnji Cooper * slave produced so flag this as a warning.
83857718be8SEnji Cooper */
83957718be8SEnji Cooper result = read(check_fd, drain, sizeof(drain));
84057718be8SEnji Cooper if (result == -1)
84157718be8SEnji Cooper err(1, "read of data file failed");
84257718be8SEnji Cooper
84357718be8SEnji Cooper if (result > 0) {
84457718be8SEnji Cooper excess(check_file, 0, __func__, "", drain,
84557718be8SEnji Cooper result);
84657718be8SEnji Cooper }
84757718be8SEnji Cooper }
84857718be8SEnji Cooper }
84957718be8SEnji Cooper
85057718be8SEnji Cooper close(check_fd);
85157718be8SEnji Cooper }
85257718be8SEnji Cooper
85357718be8SEnji Cooper /*
85457718be8SEnji Cooper * Pass a function call and arguments to the slave and wait for the
85557718be8SEnji Cooper * results. The variable nresults determines how many returns we expect
85657718be8SEnji Cooper * back from the slave. These results will be validated against the
85757718be8SEnji Cooper * expected returns or assigned to variables.
85857718be8SEnji Cooper */
85957718be8SEnji Cooper static void
do_function_call(size_t nresults)86057718be8SEnji Cooper do_function_call(size_t nresults)
86157718be8SEnji Cooper {
86257718be8SEnji Cooper #define MAX_RESULTS 4
86357718be8SEnji Cooper char *p;
86457718be8SEnji Cooper int do_input;
86557718be8SEnji Cooper size_t i;
86657718be8SEnji Cooper struct pollfd fds[3];
86757718be8SEnji Cooper returns_t response[MAX_RESULTS], returns_count;
86857718be8SEnji Cooper assert(nresults <= MAX_RESULTS);
86957718be8SEnji Cooper
87057718be8SEnji Cooper do_input = check_function_table(command.function, input_functions,
87157718be8SEnji Cooper ninput_functions);
87257718be8SEnji Cooper
87357718be8SEnji Cooper write_func_and_args();
87457718be8SEnji Cooper
87557718be8SEnji Cooper /*
87657718be8SEnji Cooper * We should get the number of returns back here, grab it before
87757718be8SEnji Cooper * doing input otherwise it will confuse the input poll
87857718be8SEnji Cooper */
87957718be8SEnji Cooper read_cmd_pipe(&returns_count);
88057718be8SEnji Cooper if (returns_count.return_type != ret_count)
88157718be8SEnji Cooper err(2, "expected return type of ret_count but received %s",
88257718be8SEnji Cooper returns_enum_names[returns_count.return_type]);
88357718be8SEnji Cooper
88457718be8SEnji Cooper perform_delay(&delay_post_call); /* let slave catch up */
88557718be8SEnji Cooper
88657718be8SEnji Cooper if (verbose) {
88757718be8SEnji Cooper fprintf(stderr, "Expect %zu results from slave, slave "
88857718be8SEnji Cooper "reported %zu\n", nresults, returns_count.return_len);
88957718be8SEnji Cooper }
89057718be8SEnji Cooper
89157718be8SEnji Cooper if ((no_input == false) && (do_input == 1)) {
89257718be8SEnji Cooper if (verbose) {
89357718be8SEnji Cooper fprintf(stderr, "doing input with inputstr >%s<\n",
89457718be8SEnji Cooper input_str);
89557718be8SEnji Cooper }
89657718be8SEnji Cooper
89757718be8SEnji Cooper if (input_str == NULL)
89857718be8SEnji Cooper errx(2, "%s, %zu: Call to input function "
89957718be8SEnji Cooper "but no input defined", cur_file, line);
90057718be8SEnji Cooper
90157718be8SEnji Cooper fds[0].fd = slvpipe[READ_PIPE];
90257718be8SEnji Cooper fds[0].events = POLLIN;
90357718be8SEnji Cooper fds[1].fd = master;
90457718be8SEnji Cooper fds[1].events = POLLOUT;
90557718be8SEnji Cooper p = input_str;
90657718be8SEnji Cooper save_slave_output(false);
90757718be8SEnji Cooper while(*p != '\0') {
90857718be8SEnji Cooper perform_delay(&delay_spec);
90957718be8SEnji Cooper
91057718be8SEnji Cooper if (poll(fds, 2, 0) < 0)
91157718be8SEnji Cooper err(2, "poll failed");
91257718be8SEnji Cooper if (fds[0].revents & POLLIN) {
91357718be8SEnji Cooper warnx("%s, %zu: Slave function "
91457718be8SEnji Cooper "returned before end of input string",
91557718be8SEnji Cooper cur_file, line);
91657718be8SEnji Cooper break;
91757718be8SEnji Cooper }
91857718be8SEnji Cooper if ((fds[1].revents & POLLOUT) == 0)
91957718be8SEnji Cooper continue;
92057718be8SEnji Cooper if (verbose) {
92157718be8SEnji Cooper fprintf(stderr, "Writing char >%c< to slave\n",
92257718be8SEnji Cooper *p);
92357718be8SEnji Cooper }
92457718be8SEnji Cooper if (write(master, p, 1) != 1) {
92557718be8SEnji Cooper warn("%s, %zu: Slave function write error",
92657718be8SEnji Cooper cur_file, line);
92757718be8SEnji Cooper break;
92857718be8SEnji Cooper }
92957718be8SEnji Cooper p++;
93057718be8SEnji Cooper
93157718be8SEnji Cooper }
93257718be8SEnji Cooper save_slave_output(false);
93357718be8SEnji Cooper
93457718be8SEnji Cooper if (verbose) {
93557718be8SEnji Cooper fprintf(stderr, "Input done.\n");
93657718be8SEnji Cooper }
93757718be8SEnji Cooper
93857718be8SEnji Cooper /* done with the input string, free the resources */
93957718be8SEnji Cooper free(input_str);
94057718be8SEnji Cooper input_str = NULL;
94157718be8SEnji Cooper }
94257718be8SEnji Cooper
94357718be8SEnji Cooper if (verbose) {
94457718be8SEnji Cooper fds[0].fd = slvpipe[READ_PIPE];
94557718be8SEnji Cooper fds[0].events = POLLIN;
94657718be8SEnji Cooper
94757718be8SEnji Cooper fds[1].fd = slvpipe[WRITE_PIPE];
94857718be8SEnji Cooper fds[1].events = POLLOUT;
94957718be8SEnji Cooper
95057718be8SEnji Cooper fds[2].fd = master;
95157718be8SEnji Cooper fds[2].events = POLLIN | POLLOUT;
95257718be8SEnji Cooper
95357718be8SEnji Cooper i = poll(&fds[0], 3, 1000);
95457718be8SEnji Cooper fprintf(stderr, "Poll returned %zu\n", i);
95557718be8SEnji Cooper for (i = 0; i < 3; i++) {
95657718be8SEnji Cooper fprintf(stderr, "revents for fd[%zu] = 0x%x\n",
95757718be8SEnji Cooper i, fds[i].revents);
95857718be8SEnji Cooper }
95957718be8SEnji Cooper }
96057718be8SEnji Cooper
96157718be8SEnji Cooper /* drain any trailing output */
96257718be8SEnji Cooper save_slave_output(false);
96357718be8SEnji Cooper
96457718be8SEnji Cooper for (i = 0; i < returns_count.return_len; i++) {
96557718be8SEnji Cooper read_cmd_pipe(&response[i]);
96657718be8SEnji Cooper }
96757718be8SEnji Cooper
96857718be8SEnji Cooper /*
96957718be8SEnji Cooper * Check for a slave error in the first return slot, if the
97057718be8SEnji Cooper * slave errored then we may not have the number of returns we
97157718be8SEnji Cooper * expect but in this case we should report the slave error
97257718be8SEnji Cooper * instead of a return count mismatch.
97357718be8SEnji Cooper */
97457718be8SEnji Cooper if ((returns_count.return_len > 0) &&
97557718be8SEnji Cooper (response[0].return_type == ret_slave_error))
97657718be8SEnji Cooper err(2, "Slave returned error: %s",
97757718be8SEnji Cooper (const char *)response[0].return_value);
97857718be8SEnji Cooper
97957718be8SEnji Cooper if (returns_count.return_len != nresults)
98057718be8SEnji Cooper err(2, "Incorrect number of returns from slave, expected %zu "
98157718be8SEnji Cooper "but received %zu", nresults, returns_count.return_len);
98257718be8SEnji Cooper
98357718be8SEnji Cooper if (verbose) {
98457718be8SEnji Cooper for (i = 0; i < nresults; i++) {
98557718be8SEnji Cooper if ((response[i].return_type != ret_byte) &&
98657718be8SEnji Cooper (response[i].return_type != ret_err) &&
98757718be8SEnji Cooper (response[i].return_type != ret_ok))
98857718be8SEnji Cooper fprintf(stderr,
98957718be8SEnji Cooper "received response >%s< "
99057718be8SEnji Cooper "expected",
99157718be8SEnji Cooper (const char *)response[i].return_value);
99257718be8SEnji Cooper else
99357718be8SEnji Cooper fprintf(stderr, "received");
99457718be8SEnji Cooper
99557718be8SEnji Cooper fprintf(stderr, " return_type %s\n",
99657718be8SEnji Cooper returns_enum_names[command.returns[i].return_type]);
99757718be8SEnji Cooper }
99857718be8SEnji Cooper }
99957718be8SEnji Cooper
100057718be8SEnji Cooper for (i = 0; i < nresults; i++) {
100157718be8SEnji Cooper if (command.returns[i].return_type != ret_var) {
100257718be8SEnji Cooper validate(i, &response[i]);
100357718be8SEnji Cooper } else {
100457718be8SEnji Cooper vars[command.returns[i].return_index].len =
100557718be8SEnji Cooper response[i].return_len;
100657718be8SEnji Cooper vars[command.returns[i].return_index].value =
100757718be8SEnji Cooper response[i].return_value;
100857718be8SEnji Cooper vars[command.returns[i].return_index].type =
100957718be8SEnji Cooper response[i].return_type;
101057718be8SEnji Cooper }
101157718be8SEnji Cooper }
101257718be8SEnji Cooper
101357718be8SEnji Cooper if (verbose && (saved_output.count > 0))
101457718be8SEnji Cooper excess(cur_file, line, __func__, " from slave",
101557718be8SEnji Cooper &saved_output.data[saved_output.readp], saved_output.count);
101657718be8SEnji Cooper
101757718be8SEnji Cooper init_parse_variables(0);
101857718be8SEnji Cooper }
101957718be8SEnji Cooper
102057718be8SEnji Cooper /*
102157718be8SEnji Cooper * Write the function and command arguments to the command pipe.
102257718be8SEnji Cooper */
102357718be8SEnji Cooper static void
write_func_and_args(void)102457718be8SEnji Cooper write_func_and_args(void)
102557718be8SEnji Cooper {
102657718be8SEnji Cooper int i;
102757718be8SEnji Cooper
102857718be8SEnji Cooper if (verbose) {
102957718be8SEnji Cooper fprintf(stderr, "calling function >%s<\n", command.function);
103057718be8SEnji Cooper }
103157718be8SEnji Cooper
103257718be8SEnji Cooper write_cmd_pipe(command.function);
103357718be8SEnji Cooper for (i = 0; i < command.nargs; i++) {
103457718be8SEnji Cooper if (command.args[i].arg_type == arg_var)
103557718be8SEnji Cooper write_cmd_pipe_args(command.args[i].arg_type,
103657718be8SEnji Cooper &vars[command.args[i].var_index]);
103757718be8SEnji Cooper else
103857718be8SEnji Cooper write_cmd_pipe_args(command.args[i].arg_type,
103957718be8SEnji Cooper &command.args[i]);
104057718be8SEnji Cooper }
104157718be8SEnji Cooper
104257718be8SEnji Cooper write_cmd_pipe(NULL); /* signal end of arguments */
104357718be8SEnji Cooper }
104457718be8SEnji Cooper
104557718be8SEnji Cooper /*
104657718be8SEnji Cooper * Initialise the command structure - if initial is non-zero then just set
104757718be8SEnji Cooper * everything to sane values otherwise free any memory that was allocated
104857718be8SEnji Cooper * when building the structure.
104957718be8SEnji Cooper */
105057718be8SEnji Cooper void
init_parse_variables(int initial)105157718be8SEnji Cooper init_parse_variables(int initial)
105257718be8SEnji Cooper {
105357718be8SEnji Cooper int i, result;
105457718be8SEnji Cooper struct pollfd slave_pty;
105557718be8SEnji Cooper
105657718be8SEnji Cooper if (initial == 0) {
105757718be8SEnji Cooper free(command.function);
105857718be8SEnji Cooper for (i = 0; i < command.nrets; i++) {
105957718be8SEnji Cooper if (command.returns[i].return_type == ret_number)
106057718be8SEnji Cooper free(command.returns[i].return_value);
106157718be8SEnji Cooper }
106257718be8SEnji Cooper free(command.returns);
106357718be8SEnji Cooper
106457718be8SEnji Cooper for (i = 0; i < command.nargs; i++) {
106557718be8SEnji Cooper if (command.args[i].arg_type != arg_var)
106657718be8SEnji Cooper free(command.args[i].arg_string);
106757718be8SEnji Cooper }
106857718be8SEnji Cooper free(command.args);
106957718be8SEnji Cooper } else {
107057718be8SEnji Cooper line = 0;
107157718be8SEnji Cooper input_delay = 0;
107257718be8SEnji Cooper vars = NULL;
107357718be8SEnji Cooper nvars = 0;
107457718be8SEnji Cooper input_str = NULL;
107557718be8SEnji Cooper saved_output.allocated = 0;
107657718be8SEnji Cooper saved_output.count = 0;
107757718be8SEnji Cooper saved_output.readp = 0;
107857718be8SEnji Cooper saved_output.data = NULL;
107957718be8SEnji Cooper }
108057718be8SEnji Cooper
108157718be8SEnji Cooper no_input = false;
108257718be8SEnji Cooper command.function = NULL;
108357718be8SEnji Cooper command.nargs = 0;
108457718be8SEnji Cooper command.args = NULL;
108557718be8SEnji Cooper command.nrets = 0;
108657718be8SEnji Cooper command.returns = NULL;
108757718be8SEnji Cooper
108857718be8SEnji Cooper /*
108957718be8SEnji Cooper * Check the slave pty for stray output from the slave, at this
109057718be8SEnji Cooper * point we should not see any data as it should have been
109157718be8SEnji Cooper * consumed by the test functions. If we see data then we have
109257718be8SEnji Cooper * either a bug or are not handling an output generating function
109357718be8SEnji Cooper * correctly.
109457718be8SEnji Cooper */
109557718be8SEnji Cooper slave_pty.fd = master;
109657718be8SEnji Cooper slave_pty.events = POLLIN;
109757718be8SEnji Cooper result = poll(&slave_pty, 1, 0);
109857718be8SEnji Cooper
109957718be8SEnji Cooper if (result < 0)
110057718be8SEnji Cooper err(2, "Poll of slave pty failed");
110157718be8SEnji Cooper else if (result > 0)
110257718be8SEnji Cooper warnx("%s, %zu: Unexpected data from slave", cur_file, line);
110357718be8SEnji Cooper }
110457718be8SEnji Cooper
110557718be8SEnji Cooper /*
110657718be8SEnji Cooper * Validate the response against the expected return. The variable
110757718be8SEnji Cooper * i is the i into the rets array in command.
110857718be8SEnji Cooper */
110957718be8SEnji Cooper static void
validate(int i,void * data)111057718be8SEnji Cooper validate(int i, void *data)
111157718be8SEnji Cooper {
111257718be8SEnji Cooper char *response;
111357718be8SEnji Cooper returns_t *byte_response;
111457718be8SEnji Cooper
111557718be8SEnji Cooper byte_response = data;
111657718be8SEnji Cooper if ((command.returns[i].return_type != ret_byte) &&
111757718be8SEnji Cooper (command.returns[i].return_type != ret_err) &&
111857718be8SEnji Cooper (command.returns[i].return_type != ret_ok)) {
111957718be8SEnji Cooper if ((byte_response->return_type == ret_byte) ||
112057718be8SEnji Cooper (byte_response->return_type == ret_err) ||
112157718be8SEnji Cooper (byte_response->return_type == ret_ok))
112257718be8SEnji Cooper err(1, "%s: expecting type %s, received type %s"
112357718be8SEnji Cooper " at line %zu of file %s", __func__,
112457718be8SEnji Cooper returns_enum_names[command.returns[i].return_type],
112557718be8SEnji Cooper returns_enum_names[byte_response->return_type],
112657718be8SEnji Cooper line, cur_file);
112757718be8SEnji Cooper
112857718be8SEnji Cooper response = byte_response->return_value;
112957718be8SEnji Cooper }
113057718be8SEnji Cooper
113157718be8SEnji Cooper switch (command.returns[i].return_type) {
113257718be8SEnji Cooper case ret_err:
113357718be8SEnji Cooper validate_type(ret_err, byte_response, 0);
113457718be8SEnji Cooper break;
113557718be8SEnji Cooper
113657718be8SEnji Cooper case ret_ok:
113757718be8SEnji Cooper validate_type(ret_ok, byte_response, 0);
113857718be8SEnji Cooper break;
113957718be8SEnji Cooper
114057718be8SEnji Cooper case ret_null:
114157718be8SEnji Cooper validate_return("NULL", response, 0);
114257718be8SEnji Cooper break;
114357718be8SEnji Cooper
114457718be8SEnji Cooper case ret_nonnull:
114557718be8SEnji Cooper validate_return("NULL", response, 1);
114657718be8SEnji Cooper break;
114757718be8SEnji Cooper
114857718be8SEnji Cooper case ret_string:
114957718be8SEnji Cooper case ret_number:
115057718be8SEnji Cooper validate_return(command.returns[i].return_value,
115157718be8SEnji Cooper response, 0);
115257718be8SEnji Cooper break;
115357718be8SEnji Cooper
115457718be8SEnji Cooper case ret_ref:
115557718be8SEnji Cooper validate_reference(i, response);
115657718be8SEnji Cooper break;
115757718be8SEnji Cooper
115857718be8SEnji Cooper case ret_byte:
115957718be8SEnji Cooper validate_byte(&command.returns[i], byte_response, 0);
116057718be8SEnji Cooper break;
116157718be8SEnji Cooper
116257718be8SEnji Cooper default:
116357718be8SEnji Cooper err(1, "Malformed statement at line %zu of file %s",
116457718be8SEnji Cooper line, cur_file);
116557718be8SEnji Cooper break;
116657718be8SEnji Cooper }
116757718be8SEnji Cooper }
116857718be8SEnji Cooper
116957718be8SEnji Cooper /*
117057718be8SEnji Cooper * Validate the return against the contents of a variable.
117157718be8SEnji Cooper */
117257718be8SEnji Cooper static void
validate_reference(int i,void * data)117357718be8SEnji Cooper validate_reference(int i, void *data)
117457718be8SEnji Cooper {
117557718be8SEnji Cooper char *response;
117657718be8SEnji Cooper returns_t *byte_response;
117757718be8SEnji Cooper var_t *varp;
117857718be8SEnji Cooper
117957718be8SEnji Cooper varp = &vars[command.returns[i].return_index];
118057718be8SEnji Cooper
118157718be8SEnji Cooper byte_response = data;
118257718be8SEnji Cooper if (command.returns[i].return_type != ret_byte)
118357718be8SEnji Cooper response = data;
118457718be8SEnji Cooper
118557718be8SEnji Cooper if (verbose) {
118657718be8SEnji Cooper fprintf(stderr,
118757718be8SEnji Cooper "%s: return type of %s, value %s \n", __func__,
118857718be8SEnji Cooper returns_enum_names[varp->type],
118957718be8SEnji Cooper (const char *)varp->value);
119057718be8SEnji Cooper }
119157718be8SEnji Cooper
119257718be8SEnji Cooper switch (varp->type) {
119357718be8SEnji Cooper case ret_string:
119457718be8SEnji Cooper case ret_number:
119557718be8SEnji Cooper validate_return(varp->value, response, 0);
119657718be8SEnji Cooper break;
119757718be8SEnji Cooper
119857718be8SEnji Cooper case ret_byte:
119957718be8SEnji Cooper validate_byte(varp->value, byte_response, 0);
120057718be8SEnji Cooper break;
120157718be8SEnji Cooper
120257718be8SEnji Cooper default:
120357718be8SEnji Cooper err(1,
120457718be8SEnji Cooper "Invalid return type for reference at line %zu of file %s",
120557718be8SEnji Cooper line, cur_file);
120657718be8SEnji Cooper break;
120757718be8SEnji Cooper }
120857718be8SEnji Cooper }
120957718be8SEnji Cooper
121057718be8SEnji Cooper /*
121157718be8SEnji Cooper * Validate the return type against the expected type, throw an error
121257718be8SEnji Cooper * if they don't match.
121357718be8SEnji Cooper */
121457718be8SEnji Cooper static void
validate_type(returns_enum_t expected,returns_t * value,int check)121557718be8SEnji Cooper validate_type(returns_enum_t expected, returns_t *value, int check)
121657718be8SEnji Cooper {
121757718be8SEnji Cooper if (((check == 0) && (expected != value->return_type)) ||
121857718be8SEnji Cooper ((check == 1) && (expected == value->return_type)))
121957718be8SEnji Cooper err(1, "Validate expected type %s %s %s line %zu of file %s",
122057718be8SEnji Cooper returns_enum_names[expected],
122157718be8SEnji Cooper (check == 0)? "matching" : "not matching",
122257718be8SEnji Cooper returns_enum_names[value->return_type], line, cur_file);
122357718be8SEnji Cooper
122457718be8SEnji Cooper if (verbose) {
122557718be8SEnji Cooper fprintf(stderr, "Validate expected type %s %s %s line %zu"
122657718be8SEnji Cooper " of file %s\n",
122757718be8SEnji Cooper returns_enum_names[expected],
122857718be8SEnji Cooper (check == 0)? "matching" : "not matching",
122957718be8SEnji Cooper returns_enum_names[value->return_type], line, cur_file);
123057718be8SEnji Cooper }
123157718be8SEnji Cooper }
123257718be8SEnji Cooper
123357718be8SEnji Cooper /*
123457718be8SEnji Cooper * Validate the return value against the expected value, throw an error
123557718be8SEnji Cooper * if they don't match.
123657718be8SEnji Cooper */
123757718be8SEnji Cooper static void
validate_return(const char * expected,const char * value,int check)123857718be8SEnji Cooper validate_return(const char *expected, const char *value, int check)
123957718be8SEnji Cooper {
124057718be8SEnji Cooper if (((check == 0) && strcmp(expected, value) != 0) ||
124157718be8SEnji Cooper ((check == 1) && strcmp(expected, value) == 0))
124257718be8SEnji Cooper errx(1, "Validate expected %s %s %s line %zu of file %s",
124357718be8SEnji Cooper expected,
124457718be8SEnji Cooper (check == 0)? "matching" : "not matching", value,
124557718be8SEnji Cooper line, cur_file);
124657718be8SEnji Cooper if (verbose) {
124757718be8SEnji Cooper fprintf(stderr, "Validated expected value %s %s %s "
124857718be8SEnji Cooper "at line %zu of file %s\n", expected,
124957718be8SEnji Cooper (check == 0)? "matches" : "does not match",
125057718be8SEnji Cooper value, line, cur_file);
125157718be8SEnji Cooper }
125257718be8SEnji Cooper }
125357718be8SEnji Cooper
125457718be8SEnji Cooper /*
125557718be8SEnji Cooper * Validate the return value against the expected value, throw an error
125657718be8SEnji Cooper * if they don't match expectations.
125757718be8SEnji Cooper */
125857718be8SEnji Cooper static void
validate_byte(returns_t * expected,returns_t * value,int check)125957718be8SEnji Cooper validate_byte(returns_t *expected, returns_t *value, int check)
126057718be8SEnji Cooper {
126157718be8SEnji Cooper char *ch;
126257718be8SEnji Cooper size_t i;
126357718be8SEnji Cooper
126457718be8SEnji Cooper if (verbose) {
126557718be8SEnji Cooper ch = value->return_value;
126657718be8SEnji Cooper fprintf(stderr, "checking returned byte stream: ");
126757718be8SEnji Cooper for (i = 0; i < value->return_len; i++)
126857718be8SEnji Cooper fprintf(stderr, "%s0x%x", (i != 0)? ", " : "", ch[i]);
126957718be8SEnji Cooper fprintf(stderr, "\n");
127057718be8SEnji Cooper
127157718be8SEnji Cooper fprintf(stderr, "%s byte stream: ",
127257718be8SEnji Cooper (check == 0)? "matches" : "does not match");
127357718be8SEnji Cooper ch = (char *) expected->return_value;
127457718be8SEnji Cooper for (i = 0; i < expected->return_len; i++)
127557718be8SEnji Cooper fprintf(stderr, "%s0x%x", (i != 0)? ", " : "", ch[i]);
127657718be8SEnji Cooper fprintf(stderr, "\n");
127757718be8SEnji Cooper }
127857718be8SEnji Cooper
127957718be8SEnji Cooper /*
128057718be8SEnji Cooper * No chance of a match if lengths differ...
128157718be8SEnji Cooper */
128257718be8SEnji Cooper if ((check == 0) && (expected->return_len != value->return_len))
128357718be8SEnji Cooper errx(1, "Byte validation failed, length mismatch, expected %zu,"
128457718be8SEnji Cooper "received %zu", expected->return_len, value->return_len);
128557718be8SEnji Cooper
128657718be8SEnji Cooper /*
128757718be8SEnji Cooper * If check is 0 then we want to throw an error IFF the byte streams
128857718be8SEnji Cooper * do not match, if check is 1 then throw an error if the byte
128957718be8SEnji Cooper * streams match.
129057718be8SEnji Cooper */
129157718be8SEnji Cooper if (((check == 0) && memcmp(expected->return_value, value->return_value,
129257718be8SEnji Cooper value->return_len) != 0) ||
129357718be8SEnji Cooper ((check == 1) && (expected->return_len == value->return_len) &&
129457718be8SEnji Cooper memcmp(expected->return_value, value->return_value,
129557718be8SEnji Cooper value->return_len) == 0))
129657718be8SEnji Cooper errx(1, "Validate expected %s byte stream at line %zu"
129757718be8SEnji Cooper "of file %s",
129857718be8SEnji Cooper (check == 0)? "matching" : "not matching", line, cur_file);
129957718be8SEnji Cooper if (verbose) {
130057718be8SEnji Cooper fprintf(stderr, "Validated expected %s byte stream "
130157718be8SEnji Cooper "at line %zu of file %s\n",
130257718be8SEnji Cooper (check == 0)? "matching" : "not matching",
130357718be8SEnji Cooper line, cur_file);
130457718be8SEnji Cooper }
130557718be8SEnji Cooper }
130657718be8SEnji Cooper
130757718be8SEnji Cooper /*
130857718be8SEnji Cooper * Validate the variable at i against the expected value, throw an
130957718be8SEnji Cooper * error if they don't match, if check is non-zero then the match is
131057718be8SEnji Cooper * negated.
131157718be8SEnji Cooper */
131257718be8SEnji Cooper static void
validate_variable(int ret,returns_enum_t type,const void * value,int i,int check)131357718be8SEnji Cooper validate_variable(int ret, returns_enum_t type, const void *value, int i,
131457718be8SEnji Cooper int check)
131557718be8SEnji Cooper {
131657718be8SEnji Cooper returns_t *retval;
131757718be8SEnji Cooper var_t *varptr;
131857718be8SEnji Cooper
131957718be8SEnji Cooper retval = &command.returns[ret];
132057718be8SEnji Cooper varptr = &vars[command.returns[ret].return_index];
132157718be8SEnji Cooper
132257718be8SEnji Cooper if (varptr->value == NULL)
132357718be8SEnji Cooper err(1, "Variable %s has no value assigned to it", varptr->name);
132457718be8SEnji Cooper
132557718be8SEnji Cooper
132657718be8SEnji Cooper if (varptr->type != type)
132757718be8SEnji Cooper err(1, "Variable %s is not the expected type", varptr->name);
132857718be8SEnji Cooper
132957718be8SEnji Cooper if (type != ret_byte) {
133057718be8SEnji Cooper if ((((check == 0) && strcmp(value, varptr->value) != 0))
133157718be8SEnji Cooper || ((check == 1) && strcmp(value, varptr->value) == 0))
133257718be8SEnji Cooper err(1, "Variable %s contains %s instead of %s"
133357718be8SEnji Cooper " value %s at line %zu of file %s",
133457718be8SEnji Cooper varptr->name, (const char *)varptr->value,
133557718be8SEnji Cooper (check == 0)? "expected" : "not matching",
133657718be8SEnji Cooper (const char *)value,
133757718be8SEnji Cooper line, cur_file);
133857718be8SEnji Cooper if (verbose) {
133957718be8SEnji Cooper fprintf(stderr, "Variable %s contains %s value "
134057718be8SEnji Cooper "%s at line %zu of file %s\n",
134157718be8SEnji Cooper varptr->name,
134257718be8SEnji Cooper (check == 0)? "expected" : "not matching",
134357718be8SEnji Cooper (const char *)varptr->value, line, cur_file);
134457718be8SEnji Cooper }
134557718be8SEnji Cooper } else {
134657718be8SEnji Cooper if ((check == 0) && (retval->return_len != varptr->len))
134757718be8SEnji Cooper err(1, "Byte validation failed, length mismatch");
134857718be8SEnji Cooper
134957718be8SEnji Cooper /*
135057718be8SEnji Cooper * If check is 0 then we want to throw an error IFF
135157718be8SEnji Cooper * the byte streams do not match, if check is 1 then
135257718be8SEnji Cooper * throw an error if the byte streams match.
135357718be8SEnji Cooper */
135457718be8SEnji Cooper if (((check == 0) && memcmp(retval->return_value, varptr->value,
135557718be8SEnji Cooper varptr->len) != 0) ||
135657718be8SEnji Cooper ((check == 1) && (retval->return_len == varptr->len) &&
135757718be8SEnji Cooper memcmp(retval->return_value, varptr->value,
135857718be8SEnji Cooper varptr->len) == 0))
135957718be8SEnji Cooper err(1, "Validate expected %s byte stream at line %zu"
136057718be8SEnji Cooper " of file %s",
136157718be8SEnji Cooper (check == 0)? "matching" : "not matching",
136257718be8SEnji Cooper line, cur_file);
136357718be8SEnji Cooper if (verbose) {
136457718be8SEnji Cooper fprintf(stderr, "Validated expected %s byte stream "
136557718be8SEnji Cooper "at line %zu of file %s\n",
136657718be8SEnji Cooper (check == 0)? "matching" : "not matching",
136757718be8SEnji Cooper line, cur_file);
136857718be8SEnji Cooper }
136957718be8SEnji Cooper }
137057718be8SEnji Cooper }
137157718be8SEnji Cooper
137257718be8SEnji Cooper /*
137357718be8SEnji Cooper * Write a string to the command pipe - we feed the number of bytes coming
137457718be8SEnji Cooper * down first to allow storage allocation and then follow up with the data.
137557718be8SEnji Cooper * If cmd is NULL then feed a -1 down the pipe to say the end of the args.
137657718be8SEnji Cooper */
137757718be8SEnji Cooper static void
write_cmd_pipe(char * cmd)137857718be8SEnji Cooper write_cmd_pipe(char *cmd)
137957718be8SEnji Cooper {
138057718be8SEnji Cooper args_t arg;
138157718be8SEnji Cooper size_t len;
138257718be8SEnji Cooper
138357718be8SEnji Cooper if (cmd == NULL)
138457718be8SEnji Cooper len = 0;
138557718be8SEnji Cooper else
138657718be8SEnji Cooper len = strlen(cmd);
138757718be8SEnji Cooper
138857718be8SEnji Cooper arg.arg_type = arg_static;
138957718be8SEnji Cooper arg.arg_len = len;
139057718be8SEnji Cooper arg.arg_string = cmd;
139157718be8SEnji Cooper write_cmd_pipe_args(arg.arg_type, &arg);
139257718be8SEnji Cooper
139357718be8SEnji Cooper }
139457718be8SEnji Cooper
139557718be8SEnji Cooper static void
write_cmd_pipe_args(args_state_t type,void * data)139657718be8SEnji Cooper write_cmd_pipe_args(args_state_t type, void *data)
139757718be8SEnji Cooper {
139857718be8SEnji Cooper var_t *var_data;
139957718be8SEnji Cooper args_t *arg_data;
140057718be8SEnji Cooper int len, send_type;
140157718be8SEnji Cooper void *cmd;
140257718be8SEnji Cooper
140357718be8SEnji Cooper arg_data = data;
140457718be8SEnji Cooper switch (type) {
140557718be8SEnji Cooper case arg_var:
140657718be8SEnji Cooper var_data = data;
140757718be8SEnji Cooper len = var_data->len;
140857718be8SEnji Cooper cmd = var_data->value;
140957718be8SEnji Cooper if (type == arg_byte)
141057718be8SEnji Cooper send_type = ret_byte;
141157718be8SEnji Cooper else
141257718be8SEnji Cooper send_type = ret_string;
141357718be8SEnji Cooper break;
141457718be8SEnji Cooper
141557718be8SEnji Cooper case arg_null:
141657718be8SEnji Cooper send_type = ret_null;
141757718be8SEnji Cooper len = 0;
141857718be8SEnji Cooper break;
141957718be8SEnji Cooper
142057718be8SEnji Cooper default:
142157718be8SEnji Cooper if ((arg_data->arg_len == 0) && (arg_data->arg_string == NULL))
142257718be8SEnji Cooper len = -1;
142357718be8SEnji Cooper else
142457718be8SEnji Cooper len = arg_data->arg_len;
142557718be8SEnji Cooper cmd = arg_data->arg_string;
142657718be8SEnji Cooper if (type == arg_byte)
142757718be8SEnji Cooper send_type = ret_byte;
142857718be8SEnji Cooper else
142957718be8SEnji Cooper send_type = ret_string;
143057718be8SEnji Cooper }
143157718be8SEnji Cooper
143257718be8SEnji Cooper if (verbose) {
143357718be8SEnji Cooper fprintf(stderr, "Writing type %s to command pipe\n",
143457718be8SEnji Cooper returns_enum_names[send_type]);
143557718be8SEnji Cooper }
143657718be8SEnji Cooper
143757718be8SEnji Cooper if (write(cmdpipe[WRITE_PIPE], &send_type, sizeof(int)) < 0)
143857718be8SEnji Cooper err(1, "command pipe write for type failed");
143957718be8SEnji Cooper
144057718be8SEnji Cooper if (verbose) {
144157718be8SEnji Cooper fprintf(stderr, "Writing length %d to command pipe\n", len);
144257718be8SEnji Cooper }
144357718be8SEnji Cooper
144457718be8SEnji Cooper if (write(cmdpipe[WRITE_PIPE], &len, sizeof(int)) < 0)
144557718be8SEnji Cooper err(1, "command pipe write for length failed");
144657718be8SEnji Cooper
144757718be8SEnji Cooper if (len > 0) {
144857718be8SEnji Cooper if (verbose) {
144957718be8SEnji Cooper fprintf(stderr, "Writing data >%s< to command pipe\n",
145057718be8SEnji Cooper (const char *)cmd);
145157718be8SEnji Cooper }
145257718be8SEnji Cooper if (write(cmdpipe[WRITE_PIPE], cmd, len) < 0)
145357718be8SEnji Cooper err(1, "command pipe write of data failed");
145457718be8SEnji Cooper }
145557718be8SEnji Cooper }
145657718be8SEnji Cooper
145757718be8SEnji Cooper /*
145857718be8SEnji Cooper * Read a response from the command pipe, first we will receive the
145957718be8SEnji Cooper * length of the response then the actual data.
146057718be8SEnji Cooper */
146157718be8SEnji Cooper static void
read_cmd_pipe(returns_t * response)146257718be8SEnji Cooper read_cmd_pipe(returns_t *response)
146357718be8SEnji Cooper {
146457718be8SEnji Cooper int len, type;
146557718be8SEnji Cooper struct pollfd rfd[2];
146657718be8SEnji Cooper char *str;
146757718be8SEnji Cooper
146857718be8SEnji Cooper /*
146957718be8SEnji Cooper * Check if there is data to read - just in case slave has died, we
147057718be8SEnji Cooper * don't want to block on the read and just hang. We also check
147157718be8SEnji Cooper * output from the slave because the slave may be blocked waiting
147257718be8SEnji Cooper * for a flush on its stdout.
147357718be8SEnji Cooper */
147457718be8SEnji Cooper rfd[0].fd = slvpipe[READ_PIPE];
147557718be8SEnji Cooper rfd[0].events = POLLIN;
147657718be8SEnji Cooper rfd[1].fd = master;
147757718be8SEnji Cooper rfd[1].events = POLLIN;
147857718be8SEnji Cooper
147957718be8SEnji Cooper do {
148057718be8SEnji Cooper if (poll(rfd, 2, 4000) == 0)
148157718be8SEnji Cooper errx(2, "%s, %zu: Command pipe read timeout",
148257718be8SEnji Cooper cur_file, line);
148357718be8SEnji Cooper
148457718be8SEnji Cooper if ((rfd[1].revents & POLLIN) == POLLIN) {
148557718be8SEnji Cooper if (verbose) {
148657718be8SEnji Cooper fprintf(stderr,
148757718be8SEnji Cooper "draining output from slave\n");
148857718be8SEnji Cooper }
148957718be8SEnji Cooper save_slave_output(false);
149057718be8SEnji Cooper }
149157718be8SEnji Cooper }
149257718be8SEnji Cooper while((rfd[1].revents & POLLIN) == POLLIN);
149357718be8SEnji Cooper
149457718be8SEnji Cooper if (read(slvpipe[READ_PIPE], &type, sizeof(int)) < 0)
149557718be8SEnji Cooper err(1, "command pipe read for type failed");
149657718be8SEnji Cooper response->return_type = type;
149757718be8SEnji Cooper
149857718be8SEnji Cooper if ((type != ret_ok) && (type != ret_err) && (type != ret_count)) {
149957718be8SEnji Cooper if (read(slvpipe[READ_PIPE], &len, sizeof(int)) < 0)
150057718be8SEnji Cooper err(1, "command pipe read for length failed");
150157718be8SEnji Cooper response->return_len = len;
150257718be8SEnji Cooper
150357718be8SEnji Cooper if (verbose) {
150457718be8SEnji Cooper fprintf(stderr,
150557718be8SEnji Cooper "Reading %d bytes from command pipe\n", len);
150657718be8SEnji Cooper }
150757718be8SEnji Cooper
150857718be8SEnji Cooper if ((response->return_value = malloc(len + 1)) == NULL)
150957718be8SEnji Cooper err(1, "Failed to alloc memory for cmd pipe read");
151057718be8SEnji Cooper
151157718be8SEnji Cooper if (read(slvpipe[READ_PIPE], response->return_value, len) < 0)
151257718be8SEnji Cooper err(1, "command pipe read of data failed");
151357718be8SEnji Cooper
151457718be8SEnji Cooper if (response->return_type != ret_byte) {
151557718be8SEnji Cooper str = response->return_value;
151657718be8SEnji Cooper str[len] = '\0';
151757718be8SEnji Cooper
151857718be8SEnji Cooper if (verbose) {
151957718be8SEnji Cooper fprintf(stderr, "Read data >%s< from pipe\n",
152057718be8SEnji Cooper (const char *)response->return_value);
152157718be8SEnji Cooper }
152257718be8SEnji Cooper }
152357718be8SEnji Cooper } else {
152457718be8SEnji Cooper response->return_value = NULL;
152557718be8SEnji Cooper if (type == ret_count) {
152657718be8SEnji Cooper if (read(slvpipe[READ_PIPE], &len, sizeof(int)) < 0)
152757718be8SEnji Cooper err(1, "command pipe read for number of "
152857718be8SEnji Cooper "returns failed");
152957718be8SEnji Cooper response->return_len = len;
153057718be8SEnji Cooper }
153157718be8SEnji Cooper
153257718be8SEnji Cooper if (verbose) {
153357718be8SEnji Cooper fprintf(stderr, "Read type %s from pipe\n",
153457718be8SEnji Cooper returns_enum_names[type]);
153557718be8SEnji Cooper }
153657718be8SEnji Cooper }
153757718be8SEnji Cooper }
153857718be8SEnji Cooper
153957718be8SEnji Cooper /*
154057718be8SEnji Cooper * Check for writes from the slave on the pty, save the output into a
154157718be8SEnji Cooper * buffer for later checking if discard is false.
154257718be8SEnji Cooper */
154357718be8SEnji Cooper #define MAX_DRAIN 256
154457718be8SEnji Cooper
154557718be8SEnji Cooper static void
save_slave_output(bool discard)154657718be8SEnji Cooper save_slave_output(bool discard)
154757718be8SEnji Cooper {
154857718be8SEnji Cooper char *new_data, drain[MAX_DRAIN];
154957718be8SEnji Cooper size_t to_allocate;
155057718be8SEnji Cooper ssize_t result;
155157718be8SEnji Cooper size_t i;
155257718be8SEnji Cooper
155357718be8SEnji Cooper result = 0;
155457718be8SEnji Cooper for (;;) {
155557718be8SEnji Cooper if (result == -1)
155657718be8SEnji Cooper err(2, "poll of slave pty failed");
155757718be8SEnji Cooper result = MAX_DRAIN;
155857718be8SEnji Cooper if ((result = read(master, drain, result)) < 0) {
155957718be8SEnji Cooper if (errno == EAGAIN)
156057718be8SEnji Cooper break;
156157718be8SEnji Cooper else
156257718be8SEnji Cooper err(2, "draining slave pty failed");
156357718be8SEnji Cooper }
156457718be8SEnji Cooper if (result == 0)
156557718be8SEnji Cooper abort();
156657718be8SEnji Cooper
156757718be8SEnji Cooper if (!discard) {
156857718be8SEnji Cooper if ((size_t)result >
156957718be8SEnji Cooper (saved_output.allocated - saved_output.count)) {
157057718be8SEnji Cooper to_allocate = 1024 * ((result / 1024) + 1);
157157718be8SEnji Cooper
157257718be8SEnji Cooper if ((new_data = realloc(saved_output.data,
157357718be8SEnji Cooper saved_output.allocated + to_allocate))
157457718be8SEnji Cooper == NULL)
157557718be8SEnji Cooper err(2, "Realloc of saved_output failed");
157657718be8SEnji Cooper saved_output.data = new_data;
157757718be8SEnji Cooper saved_output.allocated += to_allocate;
157857718be8SEnji Cooper }
157957718be8SEnji Cooper
158057718be8SEnji Cooper if (verbose) {
158157718be8SEnji Cooper fprintf(stderr, "count = %zu, "
158257718be8SEnji Cooper "allocated = %zu\n", saved_output.count,
158357718be8SEnji Cooper saved_output.allocated);
158457718be8SEnji Cooper for (i = 0; i < (size_t)result; i++) {
158557718be8SEnji Cooper fprintf(stderr, "Saving slave output "
158657718be8SEnji Cooper "at %zu: 0x%x (%c)\n",
158757718be8SEnji Cooper saved_output.count + i, drain[i],
158857718be8SEnji Cooper (drain[i] >= ' ')? drain[i] : '-');
158957718be8SEnji Cooper }
159057718be8SEnji Cooper }
159157718be8SEnji Cooper
159257718be8SEnji Cooper memcpy(&saved_output.data[saved_output.count], drain,
159357718be8SEnji Cooper result);
159457718be8SEnji Cooper saved_output.count += result;
159557718be8SEnji Cooper
159657718be8SEnji Cooper if (verbose) {
159757718be8SEnji Cooper fprintf(stderr, "count = %zu, "
159857718be8SEnji Cooper "allocated = %zu\n", saved_output.count,
159957718be8SEnji Cooper saved_output.allocated);
160057718be8SEnji Cooper }
160157718be8SEnji Cooper } else {
160257718be8SEnji Cooper if (verbose) {
160357718be8SEnji Cooper for (i = 0; i < (size_t)result; i++) {
160457718be8SEnji Cooper fprintf(stderr, "Discarding slave "
160557718be8SEnji Cooper "output 0x%x (%c)\n",
160657718be8SEnji Cooper drain[i],
160757718be8SEnji Cooper (drain[i] >= ' ')? drain[i] : '-');
160857718be8SEnji Cooper }
160957718be8SEnji Cooper }
161057718be8SEnji Cooper }
161157718be8SEnji Cooper }
161257718be8SEnji Cooper }
161357718be8SEnji Cooper
161457718be8SEnji Cooper static void
yyerror(const char * msg)161557718be8SEnji Cooper yyerror(const char *msg)
161657718be8SEnji Cooper {
161757718be8SEnji Cooper warnx("%s in line %zu of file %s", msg, line, cur_file);
161857718be8SEnji Cooper }
1619