1 %{ 2 /* $NetBSD: testlang_parse.y,v 1.55 2024/07/18 22:10:51 blymn Exp $ */ 3 4 /*- 5 * Copyright 2009 Brett Lymn <blymn@NetBSD.org> 6 * Copyright 2021 Roland Illig <rillig@NetBSD.org> 7 * 8 * All rights reserved. 9 * 10 * This code has been donated to The NetBSD Foundation by the Author. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. The name of the author may not be used to endorse or promote products 18 * derived from this software without specific prior written permission 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <assert.h> 33 #include <curses.h> 34 #include <errno.h> 35 #include <fcntl.h> 36 #include <err.h> 37 #include <unistd.h> 38 #include <poll.h> 39 #include <stdbool.h> 40 #include <stdio.h> 41 #include <string.h> 42 #include <stdlib.h> 43 #include <limits.h> 44 #include <time.h> 45 #include <vis.h> 46 #include <stdint.h> 47 #include "returns.h" 48 #include "director.h" 49 50 #define YYDEBUG 1 51 52 extern int verbose; 53 extern int check_file_flag; 54 extern int master; 55 extern struct pollfd readfd; 56 extern char *check_path; 57 extern char *cur_file; /* from director.c */ 58 extern int nofail; /* from director.c */ 59 60 int yylex(void); 61 62 size_t line = 1; 63 64 static int input_delay; 65 66 /* time delay between inputs chars - default to 0.1ms minimum to prevent 67 * problems with input tests 68 */ 69 #define DELAY_MIN 0.1 70 71 /* time delay after a function call - allows the slave time to 72 * run the function and output data before we do other actions. 73 * Set this to 50ms. 74 */ 75 #define POST_CALL_DELAY 50 76 77 static struct timespec delay_spec = {0, 1000 * DELAY_MIN}; 78 static struct timespec delay_post_call = {0, 1000 * POST_CALL_DELAY}; 79 80 static char *input_str; /* string to feed in as input */ 81 static bool no_input; /* don't need more input */ 82 83 static wchar_t *vals = NULL; /* wchars to attach to a cchar type */ 84 static unsigned nvals; /* number of wchars */ 85 86 const char *const enum_names[] = { /* for data_enum_t */ 87 "unused", "numeric", "static", "string", "byte", "cchar", "wchar", "ERR", 88 "OK", "NULL", "not NULL", "variable", "reference", "return count", 89 "slave error" 90 }; 91 92 typedef struct { 93 data_enum_t arg_type; 94 size_t arg_len; 95 char *arg_string; 96 int var_index; 97 } args_t; 98 99 typedef struct { 100 char *function; 101 int nrets; /* number of returns */ 102 ct_data_t *returns; /* array of expected returns */ 103 int nargs; /* number of arguments */ 104 args_t *args; /* arguments for the call */ 105 } cmd_line_t; 106 107 static cmd_line_t command; 108 109 typedef struct { 110 char *name; 111 size_t len; 112 data_enum_t type; 113 void *value; 114 cchar_t cchar; 115 } var_t; 116 117 static size_t nvars; /* Number of declared variables */ 118 static var_t *vars; /* Variables defined during the test. */ 119 120 static int check_function_table(char *, const char *const[], int); 121 static int find_var_index(const char *); 122 static void assign_arg(data_enum_t, void *); 123 static int assign_var(const char *); 124 void init_parse_variables(int); 125 static void validate(int, void *); 126 static void validate_return(const char *, const char *, int); 127 static void validate_variable(int, data_enum_t, const void *, int, int); 128 static void validate_byte(ct_data_t *, ct_data_t *, int); 129 static void validate_cchar(cchar_t *, cchar_t *, int); 130 static void validate_wchar(wchar_t *, wchar_t *, int); 131 static void write_cmd_pipe(char *); 132 static void write_cmd_pipe_args(data_enum_t, void *); 133 static void read_cmd_pipe(ct_data_t *); 134 static void write_func_and_args(void); 135 static void compare_streams(const char *, bool); 136 static void do_function_call(size_t); 137 static void check(void); 138 static void delay_millis(const char *); 139 static void do_input(const char *); 140 static void do_noinput(void); 141 static void save_slave_output(bool); 142 static void validate_type(data_enum_t, ct_data_t *, int); 143 static void set_var(data_enum_t, const char *, void *); 144 static void validate_reference(int, void *); 145 static char * numeric_or(const char *, const char *); 146 static char * get_numeric_var(const char *); 147 static void perform_delay(struct timespec *); 148 static void set_cchar(char *, void *); 149 static void set_wchar(char *); 150 static wchar_t *add_to_vals(data_enum_t, void *); 151 152 #define variants(fn) "" fn, "mv" fn, "w" fn, "mvw" fn 153 static const char *const input_functions[] = { 154 variants("getch"), 155 variants("getnstr"), 156 variants("getstr"), 157 variants("getn_wstr"), 158 variants("get_wch"), 159 variants("get_wstr"), 160 variants("scanw"), 161 }; 162 #undef variants 163 164 static const unsigned ninput_functions = 165 sizeof(input_functions) / sizeof(input_functions[0]); 166 167 extern saved_data_t saved_output; 168 169 %} 170 171 %union { 172 char *string; 173 ct_data_t *retval; 174 wchar_t *vals; 175 } 176 177 %token <string> PATH 178 %token <string> STRING 179 %token <retval> BYTE 180 %token <string> VARNAME 181 %token <string> FILENAME 182 %token <string> VARIABLE 183 %token <string> REFERENCE 184 %token <string> NULL_RET 185 %token <string> NON_NULL 186 %token <string> ERR_RET 187 %token <string> OK_RET 188 %token <string> numeric 189 %token <string> DELAY 190 %token <string> INPUT 191 %token <string> COMPARE 192 %token <string> COMPAREND 193 %token <string> ASSIGN 194 %token <string> CCHAR 195 %token <string> WCHAR 196 %token EOL CALL CHECK NOINPUT OR MULTIPLIER LPAREN RPAREN LBRACK RBRACK 197 %token COMMA 198 %token CALL2 CALL3 CALL4 199 200 %type <string> attributes expr 201 %type <vals> array_elements array_element 202 203 %nonassoc OR 204 205 %% 206 207 statements : /* empty */ 208 | statement EOL statements 209 ; 210 211 statement : assign 212 | call 213 | call2 214 | call3 215 | call4 216 | check 217 | delay 218 | input 219 | noinput 220 | compare 221 | comparend 222 | cchar 223 | wchar 224 | /* empty */ 225 ; 226 227 assign : ASSIGN VARNAME numeric { 228 set_var(data_number, $2, $3); 229 } 230 | ASSIGN VARNAME LPAREN expr RPAREN { 231 set_var(data_number, $2, $4); 232 } 233 | ASSIGN VARNAME STRING { 234 set_var(data_string, $2, $3); 235 } 236 | ASSIGN VARNAME BYTE { 237 set_var(data_byte, $2, $3); 238 } 239 ; 240 241 cchar : CCHAR VARNAME attributes char_vals { 242 set_cchar($2, $3); 243 } 244 ; 245 246 wchar : WCHAR VARNAME char_vals { 247 set_wchar($2); 248 } 249 ; 250 251 attributes : numeric 252 | LPAREN expr RPAREN { 253 $$ = $2; 254 } 255 | VARIABLE { 256 $$ = get_numeric_var($1); 257 } 258 ; 259 260 char_vals : numeric { 261 add_to_vals(data_number, $1); 262 } 263 | LBRACK array_elements RBRACK 264 | VARIABLE { 265 add_to_vals(data_var, $1); 266 } 267 | STRING { 268 add_to_vals(data_string, $1); 269 } 270 | BYTE { 271 add_to_vals(data_byte, $1); 272 } 273 ; 274 275 call : CALL result fn_name args { 276 do_function_call(1); 277 } 278 ; 279 280 call2 : CALL2 result result fn_name args { 281 do_function_call(2); 282 } 283 ; 284 285 call3 : CALL3 result result result fn_name args { 286 do_function_call(3); 287 } 288 ; 289 290 call4 : CALL4 result result result result fn_name args { 291 do_function_call(4); 292 } 293 ; 294 295 check : CHECK var returns { 296 check(); 297 } 298 ; 299 300 delay : DELAY numeric { 301 delay_millis($2); 302 } 303 ; 304 305 input : INPUT STRING { 306 do_input($2); 307 } 308 ; 309 310 noinput : NOINPUT { 311 do_noinput(); 312 } 313 ; 314 315 compare : COMPARE PATH { 316 compare_streams($2, true); 317 } 318 | COMPARE FILENAME { 319 compare_streams($2, true); 320 } 321 ; 322 323 comparend : COMPAREND PATH { 324 compare_streams($2, false); 325 } 326 | COMPAREND FILENAME { 327 compare_streams($2, false); 328 } 329 ; 330 331 332 result : returns 333 | reference 334 ; 335 336 returns : numeric { 337 assign_rets(data_number, $1); 338 } 339 | LPAREN expr RPAREN { 340 assign_rets(data_number, $2); 341 } 342 | STRING { 343 assign_rets(data_string, $1); 344 } 345 | BYTE { 346 assign_rets(data_byte, (void *) $1); 347 } 348 | ERR_RET { 349 assign_rets(data_err, NULL); 350 } 351 | OK_RET { 352 assign_rets(data_ok, NULL); 353 } 354 | NULL_RET { 355 assign_rets(data_null, NULL); 356 } 357 | NON_NULL { 358 assign_rets(data_nonnull, NULL); 359 } 360 | var 361 ; 362 363 var : VARNAME { 364 assign_rets(data_var, $1); 365 } 366 ; 367 368 reference : VARIABLE { 369 assign_rets(data_ref, $1); 370 } 371 ; 372 373 fn_name : VARNAME { 374 if (command.function != NULL) 375 free(command.function); 376 377 command.function = malloc(strlen($1) + 1); 378 if (command.function == NULL) 379 err(1, "Could not allocate memory for function name"); 380 strcpy(command.function, $1); 381 } 382 ; 383 384 array_elements : array_element 385 | array_element COMMA array_elements 386 ; 387 388 array_element : numeric { 389 $$ = add_to_vals(data_number, $1); 390 } 391 | VARIABLE { 392 $$ = add_to_vals(data_number, get_numeric_var($1)); 393 } 394 | BYTE { 395 $$ = add_to_vals(data_byte, (void *) $1); 396 } 397 | STRING { 398 $$ = add_to_vals(data_string, (void *) $1); 399 } 400 | numeric MULTIPLIER numeric { 401 unsigned long i; 402 unsigned long acount; 403 404 acount = strtoul($3, NULL, 10); 405 for (i = 0; i < acount; i++) { 406 $$ = add_to_vals(data_number, $1); 407 } 408 } 409 | VARIABLE MULTIPLIER numeric { 410 unsigned long i, acount; 411 char *val; 412 413 acount = strtoul($3, NULL, 10); 414 val = get_numeric_var($1); 415 for (i = 0; i < acount; i++) { 416 $$ = add_to_vals(data_number, val); 417 } 418 } 419 | BYTE MULTIPLIER numeric { 420 unsigned long i, acount; 421 422 acount = strtoul($3, NULL, 10); 423 for (i = 0; i < acount; i++) { 424 $$ = add_to_vals(data_byte, (void *) $1); 425 } 426 } 427 | STRING MULTIPLIER numeric { 428 unsigned long i, acount; 429 430 acount = strtoul($3, NULL, 10); 431 for (i = 0; i < acount; i++) { 432 $$ = add_to_vals(data_string, (void *) $1); 433 } 434 } 435 ; 436 437 expr : numeric 438 | VARIABLE { 439 $$ = get_numeric_var($1); 440 } 441 | expr OR expr { 442 $$ = numeric_or($1, $3); 443 } 444 ; 445 446 args : /* empty */ 447 | arg args 448 ; 449 450 arg : LPAREN expr RPAREN { 451 assign_arg(data_static, $2); 452 } 453 | numeric { 454 assign_arg(data_static, $1); 455 } 456 | STRING { 457 assign_arg(data_static, $1); 458 } 459 | BYTE { 460 assign_arg(data_byte, $1); 461 } 462 | PATH { 463 assign_arg(data_static, $1); 464 } 465 | FILENAME { 466 assign_arg(data_static, $1); 467 } 468 | VARNAME { 469 assign_arg(data_static, $1); 470 } 471 | VARIABLE { 472 assign_arg(data_var, $1); 473 } 474 | NULL_RET { 475 assign_arg(data_null, $1); 476 } 477 ; 478 479 %% 480 481 static void 482 excess(const char *fname, size_t lineno, const char *func, const char *comment, 483 const void *data, size_t datalen) 484 { 485 size_t dstlen = datalen * 4 + 1; 486 char *dst = malloc(dstlen); 487 488 if (dst == NULL) 489 err(1, "malloc"); 490 491 if (strnvisx(dst, dstlen, data, datalen, VIS_WHITE | VIS_OCTAL) == -1) 492 err(1, "strnvisx"); 493 494 warnx("%s:%zu: [%s] Excess %zu bytes%s [%s]", 495 fname, lineno, func, datalen, comment, dst); 496 free(dst); 497 } 498 499 /* 500 * Get the value of a variable, error if the variable has not been set or 501 * is not a numeric type. 502 */ 503 static char * 504 get_numeric_var(const char *var) 505 { 506 int i; 507 508 if ((i = find_var_index(var)) < 0) 509 errx(1, "Variable %s is undefined", var); 510 511 if (vars[i].type != data_number) 512 errx(1, "Variable %s is not a numeric type", var); 513 514 return vars[i].value; 515 } 516 517 /* 518 * Perform a bitwise OR on two numbers and return the result. 519 */ 520 static char * 521 numeric_or(const char *n1, const char *n2) 522 { 523 unsigned long i1, i2, result; 524 char *ret; 525 526 i1 = strtoul(n1, NULL, 10); 527 i2 = strtoul(n2, NULL, 10); 528 529 result = i1 | i2; 530 asprintf(&ret, "%lu", result); 531 532 if (verbose) { 533 fprintf(stderr, "numeric or of 0x%lx (%s) and 0x%lx (%s)" 534 " results in 0x%lx (%s)\n", 535 i1, n1, i2, n2, result, ret); 536 } 537 538 return ret; 539 } 540 541 /* 542 * Sleep for the specified time, handle the sleep getting interrupted 543 * by a signal. 544 */ 545 static void 546 perform_delay(struct timespec *ts) 547 { 548 struct timespec delay_copy, delay_remainder; 549 550 delay_copy = *ts; 551 while (nanosleep(&delay_copy, &delay_remainder) < 0) { 552 if (errno != EINTR) 553 err(2, "nanosleep returned error"); 554 delay_copy = delay_remainder; 555 } 556 } 557 558 /* 559 * Add to temporary vals array 560 */ 561 static wchar_t * 562 add_to_vals(data_enum_t argtype, void *arg) 563 { 564 wchar_t *retval = NULL; 565 int have_malloced; 566 int i; 567 ct_data_t *ret; 568 569 have_malloced = 0; 570 571 if (nvals == 0) { 572 have_malloced = 1; 573 retval = malloc(sizeof(wchar_t)); 574 } else { 575 retval = realloc(vals, (nvals + 1) * sizeof(wchar_t)); 576 } 577 578 if (retval == NULL) 579 return retval; 580 581 vals = retval; 582 583 switch (argtype) { 584 case data_number: 585 vals[nvals++] = (wchar_t) strtoul((char *) arg, NULL, 10); 586 break; 587 588 case data_string: 589 vals[nvals++] = (wchar_t) ((char *)arg)[0]; 590 break; 591 592 case data_byte: 593 ret = (ct_data_t *) arg; 594 vals[nvals++] = *((wchar_t *) ret->data_value); 595 break; 596 597 case data_var: 598 if ((i = find_var_index((char *) arg)) < 0) 599 errx(1, "%s:%zu: Variable %s is undefined", 600 cur_file, line, (const char *) arg); 601 602 switch (vars[i].type) { 603 604 case data_number: 605 case data_string: 606 case data_byte: 607 retval = add_to_vals(vars[i].type, vars[i].value); 608 break; 609 610 default: 611 errx(1, 612 "%s:%zu: Variable %s has invalid type for cchar", 613 cur_file, line, (const char *) arg); 614 break; 615 616 } 617 break; 618 619 default: 620 errx(1, "%s:%zu: Internal error: Unhandled type for vals array", 621 cur_file, line); 622 623 /* if we get here without a value then tidy up */ 624 if ((nvals == 0) && (have_malloced == 1)) { 625 free(retval); 626 retval = vals; 627 } 628 break; 629 630 } 631 632 return retval; 633 } 634 635 /* 636 * Assign the value given to the named variable. 637 */ 638 static void 639 set_var(data_enum_t type, const char *name, void *value) 640 { 641 int i; 642 char *number; 643 ct_data_t *ret; 644 645 i = find_var_index(name); 646 if (i < 0) 647 i = assign_var(name); 648 649 vars[i].type = type; 650 if ((type == data_number) || (type == data_string)) { 651 number = value; 652 vars[i].len = strlen(number) + 1; 653 vars[i].value = malloc(vars[i].len + 1); 654 if (vars[i].value == NULL) 655 err(1, "Could not malloc memory for assign string"); 656 strcpy(vars[i].value, number); 657 } else { 658 /* can only be a byte value */ 659 ret = value; 660 vars[i].len = ret->data_len; 661 vars[i].value = malloc(vars[i].len); 662 if (vars[i].value == NULL) 663 err(1, "Could not malloc memory to assign byte string"); 664 memcpy(vars[i].value, ret->data_value, vars[i].len); 665 } 666 } 667 668 /* 669 * Form up a complex character type from the given components. 670 */ 671 static void 672 set_cchar(char *name, void *attributes) 673 { 674 int i; 675 unsigned j; 676 attr_t attribs; 677 678 if (nvals >= CURSES_CCHAR_MAX) 679 errx(1, "%s:%zu: %s: too many characters in complex char type", 680 cur_file, line, __func__); 681 682 i = find_var_index(name); 683 if (i < 0) 684 i = assign_var(name); 685 686 if (sscanf((char *) attributes, "%d", &attribs) != 1) 687 errx(1, 688 "%s:%zu: %s: conversion of attributes to integer failed", 689 cur_file, line, __func__); 690 691 vars[i].type = data_cchar; 692 vars[i].cchar.attributes = attribs; 693 vars[i].cchar.elements = nvals; 694 for (j = 0; j < nvals; j++) 695 vars[i].cchar.vals[j] = vals[j]; 696 697 nvals = 0; 698 vals = NULL; 699 700 } 701 702 /* 703 * Form up a wide character string type from the given components. 704 */ 705 static void 706 set_wchar(char *name) 707 { 708 int i; 709 unsigned j; 710 wchar_t *wcval; 711 712 i = find_var_index(name); 713 if (i < 0) 714 i = assign_var(name); 715 716 vars[i].type = data_wchar; 717 vars[i].len = (nvals+1) * sizeof(wchar_t); 718 vars[i].value = malloc(vars[i].len); 719 if (vars[i].value == NULL) 720 err(1, "Could not malloc memory to assign wchar string"); 721 wcval = vars[i].value; 722 for(j = 0; j < nvals; j++) 723 wcval[j] = vals[j]; 724 wcval[nvals] = L'\0'; 725 nvals = 0; 726 vals = NULL; 727 728 } 729 730 /* 731 * Add a new variable to the vars array, the value will be assigned later, 732 * when a test function call returns. 733 */ 734 static int 735 assign_var(const char *varname) 736 { 737 var_t *temp; 738 char *name; 739 740 if ((name = malloc(strlen(varname) + 1)) == NULL) 741 err(1, "Alloc of varname failed"); 742 743 if ((temp = realloc(vars, sizeof(*temp) * (nvars + 1))) == NULL) { 744 free(name); 745 err(1, "Realloc of vars array failed"); 746 } 747 748 strcpy(name, varname); 749 vars = temp; 750 vars[nvars].name = name; 751 vars[nvars].len = 0; 752 vars[nvars].value = NULL; 753 nvars++; 754 755 return (nvars - 1); 756 } 757 758 /* 759 * Allocate and assign a new argument of the given type. 760 */ 761 static void 762 assign_arg(data_enum_t arg_type, void *arg) 763 { 764 args_t *temp, cur; 765 char *str = arg; 766 ct_data_t *ret; 767 768 if (verbose) { 769 fprintf(stderr, "function is >%s<, adding arg >%s< type %s (%d)\n", 770 command.function, str, enum_names[arg_type], arg_type); 771 } 772 773 cur.arg_type = arg_type; 774 if (cur.arg_type == data_var) { 775 cur.var_index = find_var_index(arg); 776 if (cur.var_index < 0) 777 errx(1, "%s:%zu: Invalid variable %s", 778 cur_file, line, str); 779 } else if (cur.arg_type == data_byte) { 780 ret = arg; 781 cur.arg_len = ret->data_len; 782 cur.arg_string = malloc(cur.arg_len); 783 if (cur.arg_string == NULL) 784 err(1, "Could not malloc memory for arg bytes"); 785 memcpy(cur.arg_string, ret->data_value, cur.arg_len); 786 } else if (cur.arg_type == data_null) { 787 cur.arg_len = 0; 788 cur.arg_string = NULL; 789 } else { 790 cur.arg_len = strlen(str); 791 cur.arg_string = malloc(cur.arg_len + 1); 792 if (cur.arg_string == NULL) 793 err(1, "Could not malloc memory for arg string"); 794 strcpy(cur.arg_string, arg); 795 } 796 797 temp = realloc(command.args, sizeof(*temp) * (command.nargs + 1)); 798 if (temp == NULL) 799 err(1, "Failed to reallocate args"); 800 command.args = temp; 801 memcpy(&command.args[command.nargs], &cur, sizeof(args_t)); 802 command.nargs++; 803 } 804 805 /* 806 * Allocate and assign a new return. 807 */ 808 static void 809 assign_rets(data_enum_t ret_type, void *ret) 810 { 811 ct_data_t *temp, cur; 812 char *ret_str; 813 ct_data_t *ret_ret; 814 815 cur.data_type = ret_type; 816 if (ret_type != data_var) { 817 if ((ret_type == data_number) || (ret_type == data_string)) { 818 ret_str = ret; 819 cur.data_len = strlen(ret_str) + 1; 820 cur.data_value = malloc(cur.data_len + 1); 821 if (cur.data_value == NULL) 822 err(1, 823 "Could not malloc memory for arg string"); 824 strcpy(cur.data_value, ret_str); 825 } else if (ret_type == data_byte) { 826 ret_ret = ret; 827 cur.data_len = ret_ret->data_len; 828 cur.data_value = malloc(cur.data_len); 829 if (cur.data_value == NULL) 830 err(1, 831 "Could not malloc memory for byte string"); 832 memcpy(cur.data_value, ret_ret->data_value, 833 cur.data_len); 834 } else if (ret_type == data_ref) { 835 if ((cur.data_index = find_var_index(ret)) < 0) 836 errx(1, "Undefined variable reference"); 837 } 838 } else { 839 cur.data_index = find_var_index(ret); 840 if (cur.data_index < 0) 841 cur.data_index = assign_var(ret); 842 } 843 844 temp = realloc(command.returns, sizeof(*temp) * (command.nrets + 1)); 845 if (temp == NULL) 846 err(1, "Failed to reallocate returns"); 847 command.returns = temp; 848 memcpy(&command.returns[command.nrets], &cur, sizeof(ct_data_t)); 849 command.nrets++; 850 } 851 852 /* 853 * Find the given variable name in the var array and return the i 854 * return -1 if var is not found. 855 */ 856 static int 857 find_var_index(const char *var_name) 858 { 859 int result; 860 size_t i; 861 862 result = -1; 863 864 for (i = 0; i < nvars; i++) { 865 if (strcmp(var_name, vars[i].name) == 0) { 866 result = i; 867 break; 868 } 869 } 870 871 return result; 872 } 873 874 /* 875 * Check the given function name in the given table of names, return 1 if 876 * there is a match. 877 */ 878 static int 879 check_function_table(char *function, const char *const table[], int nfunctions) 880 { 881 int i; 882 883 for (i = 0; i < nfunctions; i++) { 884 if (strcmp(function, table[i]) == 0) 885 return 1; 886 } 887 888 return 0; 889 } 890 891 /* 892 * Compare the output from the slave against the given file and report 893 * any differences. 894 */ 895 static void 896 compare_streams(const char *filename, bool discard) 897 { 898 char check_file[PATH_MAX], drain[100], ref, data; 899 struct pollfd fds[2]; 900 int nfd, check_fd; 901 ssize_t result; 902 size_t offs; 903 904 /* 905 * Don't prepend check path iff check file has an absolute 906 * path. 907 */ 908 if (filename[0] != '/') { 909 if (strlcpy(check_file, check_path, sizeof(check_file)) 910 >= sizeof(check_file)) 911 errx(2, "CHECK_PATH too long"); 912 913 if (strlcat(check_file, "/", sizeof(check_file)) 914 >= sizeof(check_file)) 915 errx(2, "Could not append / to check file path"); 916 } else { 917 check_file[0] = '\0'; 918 } 919 920 if (strlcat(check_file, filename, sizeof(check_file)) 921 >= sizeof(check_file)) 922 errx(2, "Path to check file path overflowed"); 923 924 int create_check_file = 0; 925 926 if (check_file_flag == (GEN_CHECK_FILE | FORCE_GEN)) 927 create_check_file = 1; 928 else if ((check_fd = open(check_file, O_RDONLY, 0)) < 0) { 929 if (check_file_flag & GEN_CHECK_FILE) 930 create_check_file = 1; 931 else 932 err(2, "%s:%zu: failed to open file %s", 933 cur_file, line, check_file); 934 } 935 936 if (create_check_file) { 937 check_fd = open(check_file, O_WRONLY | O_CREAT, 0644); 938 if (check_fd < 0) { 939 err(2, "%s:%zu: failed to create file %s", 940 cur_file, line, check_file); 941 } 942 } 943 944 fds[0].fd = check_fd; 945 fds[0].events = create_check_file ? POLLOUT:POLLIN; 946 fds[1].fd = master; 947 fds[1].events = POLLIN; 948 949 nfd = 2; 950 /* 951 * if we have saved output then only check for data in the 952 * reference file since the slave data may already be drained. 953 */ 954 if (saved_output.count > 0) 955 nfd = 1; 956 957 offs = 0; 958 while (poll(fds, nfd, 500) == nfd) { 959 /* Read from check file if doing comparison */ 960 if (!create_check_file) { 961 if (fds[0].revents & POLLIN) { 962 if ((result = read(check_fd, &ref, 1)) < 1) { 963 if (result != 0) { 964 err(2, "Bad read on file %s", 965 check_file); 966 } else { 967 break; 968 } 969 } 970 } 971 } 972 973 if (saved_output.count > 0) { 974 data = saved_output.data[saved_output.readp]; 975 saved_output.count--; 976 saved_output.readp++; 977 /* run out of saved data, switch to file */ 978 if (saved_output.count == 0) 979 nfd = 2; 980 } else { 981 int revent = (create_check_file == 1) ? POLLOUT:POLLIN; 982 if (fds[0].revents & revent) { 983 if (read(master, &data, 1) < 1) 984 err(2, "Bad read on slave pty"); 985 } else 986 continue; 987 } 988 989 if (create_check_file) { 990 if ((result = write(check_fd, &data, 1)) < 1) 991 err(2, "Bad write on file %s", check_file); 992 ref = data; 993 } 994 995 if (verbose) { 996 if (create_check_file) 997 fprintf(stderr, "Saving reference byte 0x%x (%c)" 998 " against slave byte 0x%x (%c)\n", 999 ref, (ref >= ' ') ? ref : '-', 1000 data, (data >= ' ' )? data : '-'); 1001 else 1002 fprintf(stderr, "Comparing reference byte 0x%x (%c)" 1003 " against slave byte 0x%x (%c)\n", 1004 ref, (ref >= ' ') ? ref : '-', 1005 data, (data >= ' ' )? data : '-'); 1006 } 1007 1008 if (!nofail && !create_check_file && ref != data) { 1009 errx(2, "%s:%zu: refresh data from slave does " 1010 "not match expected from file %s offset %zu " 1011 "[reference 0x%02x (%c) != slave 0x%02x (%c)]", 1012 cur_file, line, check_file, offs, 1013 ref, (ref >= ' ') ? ref : '-', 1014 data, (data >= ' ') ? data : '-'); 1015 } 1016 1017 offs++; 1018 } 1019 1020 /* 1021 * if creating a check file, there shouldn't be 1022 * anymore saved output 1023 */ 1024 if (saved_output.count > 0) { 1025 if (create_check_file) 1026 errx(2, "Slave output not flushed correctly"); 1027 else 1028 excess(cur_file, line, __func__, " from slave", 1029 &saved_output.data[saved_output.readp], saved_output.count); 1030 } 1031 1032 /* discard any excess saved output if required */ 1033 if (discard || nofail) { 1034 saved_output.count = 0; 1035 saved_output.readp = 0; 1036 } 1037 1038 if (!create_check_file && (result = poll(fds, 2, 0)) != 0) { 1039 if (result == -1) 1040 err(2, "poll of file descriptors failed"); 1041 1042 if ((fds[1].revents & POLLIN) == POLLIN) { 1043 save_slave_output(true); 1044 } else if ((fds[0].revents & POLLIN) == POLLIN) { 1045 /* 1046 * handle excess in file if it exists. Poll 1047 * says there is data until EOF is read. 1048 * Check next read is EOF, if it is not then 1049 * the file really has more data than the 1050 * slave produced so flag this as a warning. 1051 */ 1052 result = read(check_fd, drain, sizeof(drain)); 1053 if (result == -1) 1054 err(1, "read of data file failed"); 1055 1056 if (result > 0) { 1057 excess(check_file, 0, __func__, "", drain, 1058 result); 1059 } 1060 } 1061 } 1062 1063 close(check_fd); 1064 } 1065 1066 /* 1067 * Pass a function call and arguments to the slave and wait for the 1068 * results. The variable nresults determines how many returns we expect 1069 * back from the slave. These results will be validated against the 1070 * expected returns or assigned to variables. 1071 */ 1072 static void 1073 do_function_call(size_t nresults) 1074 { 1075 #define MAX_RESULTS 4 1076 char *p; 1077 int do_input; 1078 size_t i; 1079 struct pollfd fds[3]; 1080 ct_data_t response[MAX_RESULTS], returns_count; 1081 assert(nresults <= MAX_RESULTS); 1082 1083 do_input = check_function_table(command.function, input_functions, 1084 ninput_functions); 1085 1086 write_func_and_args(); 1087 1088 /* 1089 * We should get the number of returns back here, grab it before 1090 * doing input otherwise it will confuse the input poll 1091 */ 1092 read_cmd_pipe(&returns_count); 1093 if (returns_count.data_type != data_count) 1094 errx(2, "expected return type of data_count but received %s", 1095 enum_names[returns_count.data_type]); 1096 1097 perform_delay(&delay_post_call); /* let slave catch up */ 1098 1099 if (verbose) { 1100 fprintf(stderr, "Expect %zu results from slave, slave " 1101 "reported %zu\n", nresults, returns_count.data_len); 1102 } 1103 1104 if ((no_input == false) && (do_input == 1)) { 1105 if (verbose) { 1106 fprintf(stderr, "doing input with inputstr >%s<\n", 1107 input_str); 1108 } 1109 1110 if (input_str == NULL) 1111 errx(2, "%s:%zu: Call to input function " 1112 "but no input defined", cur_file, line); 1113 1114 fds[0].fd = from_slave; 1115 fds[0].events = POLLIN; 1116 fds[1].fd = master; 1117 fds[1].events = POLLOUT; 1118 p = input_str; 1119 save_slave_output(false); 1120 while (*p != '\0') { 1121 perform_delay(&delay_spec); 1122 1123 if (poll(fds, 2, 0) < 0) 1124 err(2, "poll failed"); 1125 if (fds[0].revents & POLLIN) { 1126 warnx("%s:%zu: Slave function " 1127 "returned before end of input string", 1128 cur_file, line); 1129 break; 1130 } 1131 if ((fds[1].revents & POLLOUT) == 0) 1132 continue; 1133 if (verbose) { 1134 fprintf(stderr, "Writing char >%c< to slave\n", 1135 *p); 1136 } 1137 if (write(master, p, 1) != 1) { 1138 warn("%s:%zu: Slave function write error", 1139 cur_file, line); 1140 break; 1141 } 1142 p++; 1143 1144 } 1145 save_slave_output(false); 1146 1147 if (verbose) { 1148 fprintf(stderr, "Input done.\n"); 1149 } 1150 1151 /* done with the input string, free the resources */ 1152 free(input_str); 1153 input_str = NULL; 1154 } 1155 1156 if (verbose) { 1157 fds[0].fd = to_slave; 1158 fds[0].events = POLLIN; 1159 1160 fds[1].fd = from_slave; 1161 fds[1].events = POLLOUT; 1162 1163 fds[2].fd = master; 1164 fds[2].events = POLLIN | POLLOUT; 1165 1166 i = poll(&fds[0], 3, 1000); 1167 fprintf(stderr, "Poll returned %zu\n", i); 1168 for (i = 0; i < 3; i++) { 1169 fprintf(stderr, "revents for fd[%zu] = 0x%x\n", 1170 i, fds[i].revents); 1171 } 1172 } 1173 1174 /* drain any trailing output */ 1175 save_slave_output(false); 1176 1177 for (i = 0; i < returns_count.data_len; i++) { 1178 read_cmd_pipe(&response[i]); 1179 } 1180 1181 /* 1182 * Check for a slave error in the first return slot, if the 1183 * slave errored then we may not have the number of returns we 1184 * expect but in this case we should report the slave error 1185 * instead of a return count mismatch. 1186 */ 1187 if ((returns_count.data_len > 0) && 1188 (response[0].data_type == data_slave_error)) 1189 errx(2, "Slave returned error: %s", 1190 (const char *)response[0].data_value); 1191 1192 if (returns_count.data_len != nresults) 1193 errx(2, "Incorrect number of returns from slave, expected %zu " 1194 "but received %zu", nresults, returns_count.data_len); 1195 1196 if (verbose) { 1197 for (i = 0; i < nresults; i++) { 1198 if ((response[i].data_type != data_byte) && 1199 (response[i].data_type != data_err) && 1200 (response[i].data_type != data_ok)) 1201 fprintf(stderr, 1202 "received response >%s< " 1203 "expected", 1204 (const char *)response[i].data_value); 1205 else 1206 fprintf(stderr, "received"); 1207 1208 fprintf(stderr, " data_type %s\n", 1209 enum_names[command.returns[i].data_type]); 1210 } 1211 } 1212 1213 for (i = 0; i < nresults; i++) { 1214 if (command.returns[i].data_type != data_var) { 1215 validate(i, &response[i]); 1216 } else { 1217 vars[command.returns[i].data_index].len = 1218 response[i].data_len; 1219 1220 if (response[i].data_type == data_cchar) { 1221 vars[command.returns[i].data_index].cchar = 1222 *((cchar_t *)response[i].data_value); 1223 } else { 1224 vars[command.returns[i].data_index].value = 1225 response[i].data_value; 1226 } 1227 1228 vars[command.returns[i].data_index].type = 1229 response[i].data_type; 1230 } 1231 } 1232 1233 if (verbose && (saved_output.count > 0)) 1234 excess(cur_file, line, __func__, " from slave", 1235 &saved_output.data[saved_output.readp], saved_output.count); 1236 1237 init_parse_variables(0); 1238 } 1239 1240 /* 1241 * Write the function and command arguments to the command pipe. 1242 */ 1243 static void 1244 write_func_and_args(void) 1245 { 1246 int i; 1247 1248 if (verbose) { 1249 fprintf(stderr, "calling function >%s<\n", command.function); 1250 } 1251 1252 write_cmd_pipe(command.function); 1253 for (i = 0; i < command.nargs; i++) { 1254 if (command.args[i].arg_type == data_var) 1255 write_cmd_pipe_args(command.args[i].arg_type, 1256 &vars[command.args[i].var_index]); 1257 else 1258 write_cmd_pipe_args(command.args[i].arg_type, 1259 &command.args[i]); 1260 } 1261 1262 write_cmd_pipe(NULL); /* signal end of arguments */ 1263 } 1264 1265 static void 1266 check(void) 1267 { 1268 ct_data_t retvar; 1269 var_t *vptr; 1270 1271 if (command.returns[0].data_index == -1) 1272 errx(1, "%s:%zu: Undefined variable in check statement", 1273 cur_file, line); 1274 1275 if (command.returns[1].data_type == data_var) { 1276 vptr = &vars[command.returns[1].data_index]; 1277 command.returns[1].data_type = vptr->type; 1278 command.returns[1].data_len = vptr->len; 1279 if (vptr->type != data_cchar) 1280 command.returns[1].data_value = vptr->value; 1281 else 1282 command.returns[1].data_value = &vptr->cchar; 1283 } 1284 1285 if (verbose) { 1286 fprintf(stderr, "Checking contents of variable %s for %s\n", 1287 vars[command.returns[0].data_index].name, 1288 enum_names[command.returns[1].data_type]); 1289 } 1290 1291 /* 1292 * Check if var and return have same data types 1293 */ 1294 if (((command.returns[1].data_type == data_byte) && 1295 (vars[command.returns[0].data_index].type != data_byte))) 1296 errx(1, "Var type %s (%d) does not match return type %s (%d)", 1297 enum_names[vars[command.returns[0].data_index].type], 1298 vars[command.returns[0].data_index].type, 1299 enum_names[command.returns[1].data_type], 1300 command.returns[1].data_type); 1301 1302 switch (command.returns[1].data_type) { 1303 case data_err: 1304 case data_ok: 1305 validate_type(vars[command.returns[0].data_index].type, 1306 &command.returns[1], 0); 1307 break; 1308 1309 case data_null: 1310 validate_variable(0, data_string, "NULL", 1311 command.returns[0].data_index, 0); 1312 break; 1313 1314 case data_nonnull: 1315 validate_variable(0, data_string, "NULL", 1316 command.returns[0].data_index, 1); 1317 break; 1318 1319 case data_string: 1320 case data_number: 1321 if (verbose) { 1322 fprintf(stderr, " %s == returned %s\n", 1323 (const char *)command.returns[1].data_value, 1324 (const char *) 1325 vars[command.returns[0].data_index].value); 1326 } 1327 validate_variable(0, data_string, 1328 command.returns[1].data_value, 1329 command.returns[0].data_index, 0); 1330 break; 1331 1332 case data_byte: 1333 vptr = &vars[command.returns[0].data_index]; 1334 retvar.data_len = vptr->len; 1335 retvar.data_type = vptr->type; 1336 retvar.data_value = vptr->value; 1337 validate_byte(&retvar, &command.returns[1], 0); 1338 break; 1339 1340 case data_cchar: 1341 validate_cchar(&vars[command.returns[0].data_index].cchar, 1342 (cchar_t *) command.returns[1].data_value, 0); 1343 break; 1344 1345 case data_wchar: 1346 validate_wchar((wchar_t *) vars[command.returns[0].data_index].value, 1347 (wchar_t *) command.returns[1].data_value, 0); 1348 break; 1349 1350 default: 1351 errx(1, "%s:%zu: Malformed check statement", cur_file, line); 1352 break; 1353 } 1354 1355 init_parse_variables(0); 1356 } 1357 1358 static void 1359 delay_millis(const char *millis) 1360 { 1361 /* set the inter-character delay */ 1362 if (sscanf(millis, "%d", &input_delay) == 0) 1363 errx(1, "%s:%zu: Delay specification %s must be an int", 1364 cur_file, line, millis); 1365 if (verbose) { 1366 fprintf(stderr, "Set input delay to %d ms\n", input_delay); 1367 } 1368 1369 if (input_delay < DELAY_MIN) 1370 input_delay = DELAY_MIN; 1371 /* 1372 * Fill in the timespec structure now ready for use later. 1373 * The delay is specified in milliseconds so convert to timespec 1374 * values 1375 */ 1376 delay_spec.tv_sec = input_delay / 1000; 1377 delay_spec.tv_nsec = (input_delay - 1000 * delay_spec.tv_sec) * 1000; 1378 if (verbose) { 1379 fprintf(stderr, "set delay to %jd.%jd\n", 1380 (intmax_t)delay_spec.tv_sec, 1381 (intmax_t)delay_spec.tv_nsec); 1382 } 1383 1384 init_parse_variables(0); 1385 } 1386 1387 static void 1388 do_input(const char *s) 1389 { 1390 if (input_str != NULL) { 1391 warnx("%s:%zu: Discarding unused input string", cur_file, line); 1392 free(input_str); 1393 } 1394 1395 if ((input_str = strdup(s)) == NULL) 1396 err(2, "Cannot allocate memory for input string"); 1397 } 1398 1399 static void 1400 do_noinput(void) 1401 { 1402 if (input_str != NULL) { 1403 warnx("%s:%zu: Discarding unused input string", cur_file, line); 1404 free(input_str); 1405 } 1406 1407 no_input = true; 1408 } 1409 1410 /* 1411 * Initialise the command structure - if initial is non-zero then just set 1412 * everything to sane values otherwise free any memory that was allocated 1413 * when building the structure. 1414 */ 1415 void 1416 init_parse_variables(int initial) 1417 { 1418 int i, result; 1419 struct pollfd slave_pty; 1420 1421 if (initial == 0) { 1422 free(command.function); 1423 for (i = 0; i < command.nrets; i++) { 1424 if (command.returns[i].data_type == data_number) 1425 free(command.returns[i].data_value); 1426 } 1427 free(command.returns); 1428 1429 for (i = 0; i < command.nargs; i++) { 1430 if (command.args[i].arg_type != data_var) 1431 free(command.args[i].arg_string); 1432 } 1433 free(command.args); 1434 } else { 1435 line = 1; 1436 input_delay = 0; 1437 vars = NULL; 1438 nvars = 0; 1439 input_str = NULL; 1440 saved_output.allocated = 0; 1441 saved_output.count = 0; 1442 saved_output.readp = 0; 1443 saved_output.data = NULL; 1444 } 1445 1446 no_input = false; 1447 command.function = NULL; 1448 command.nargs = 0; 1449 command.args = NULL; 1450 command.nrets = 0; 1451 command.returns = NULL; 1452 1453 /* 1454 * Check the slave pty for stray output from the slave, at this 1455 * point we should not see any data as it should have been 1456 * consumed by the test functions. If we see data then we have 1457 * either a bug or are not handling an output generating function 1458 * correctly. 1459 */ 1460 slave_pty.fd = master; 1461 slave_pty.events = POLLIN; 1462 result = poll(&slave_pty, 1, 0); 1463 1464 if (result < 0) 1465 err(2, "Poll of slave pty failed"); 1466 else if (result > 0) 1467 warnx("%s:%zu: Unexpected data from slave", cur_file, line); 1468 } 1469 1470 /* 1471 * Validate the response against the expected return. The variable 1472 * i is the i into the rets array in command. 1473 */ 1474 static void 1475 validate(int i, void *data) 1476 { 1477 char *response; 1478 ct_data_t *byte_response; 1479 1480 byte_response = data; 1481 if ((command.returns[i].data_type != data_byte) && 1482 (command.returns[i].data_type != data_err) && 1483 (command.returns[i].data_type != data_ok)) { 1484 if ((byte_response->data_type == data_byte) || 1485 (byte_response->data_type == data_err) || 1486 (byte_response->data_type == data_ok)) 1487 errx(1, 1488 "%s:%zu: %s: expecting type %s, received type %s", 1489 cur_file, line, __func__, 1490 enum_names[command.returns[i].data_type], 1491 enum_names[byte_response->data_type]); 1492 1493 response = byte_response->data_value; 1494 } 1495 1496 switch (command.returns[i].data_type) { 1497 case data_err: 1498 validate_type(data_err, byte_response, 0); 1499 break; 1500 1501 case data_ok: 1502 validate_type(data_ok, byte_response, 0); 1503 break; 1504 1505 case data_null: 1506 validate_return("NULL", response, 0); 1507 break; 1508 1509 case data_nonnull: 1510 validate_return("NULL", response, 1); 1511 break; 1512 1513 case data_string: 1514 case data_number: 1515 validate_return(command.returns[i].data_value, 1516 response, 0); 1517 break; 1518 1519 case data_ref: 1520 validate_reference(i, response); 1521 break; 1522 1523 case data_byte: 1524 validate_byte(&command.returns[i], byte_response, 0); 1525 break; 1526 1527 default: 1528 errx(1, "%s:%zu: Malformed statement", cur_file, line); 1529 break; 1530 } 1531 } 1532 1533 /* 1534 * Validate the return against the contents of a variable. 1535 */ 1536 static void 1537 validate_reference(int i, void *data) 1538 { 1539 char *response; 1540 ct_data_t *byte_response; 1541 var_t *varp; 1542 1543 varp = &vars[command.returns[i].data_index]; 1544 1545 byte_response = data; 1546 if (command.returns[i].data_type != data_byte) 1547 response = data; 1548 1549 if (verbose) { 1550 fprintf(stderr, 1551 "%s: return type of %s, value %s \n", __func__, 1552 enum_names[varp->type], 1553 (varp->type != data_cchar && varp->type != data_wchar) 1554 ? (const char *)varp->value : "-"); 1555 } 1556 1557 switch (varp->type) { 1558 case data_string: 1559 case data_number: 1560 validate_return(varp->value, response, 0); 1561 break; 1562 1563 case data_byte: 1564 validate_byte(varp->value, byte_response, 0); 1565 break; 1566 1567 case data_cchar: 1568 validate_cchar(&(varp->cchar), (cchar_t *) response, 0); 1569 break; 1570 1571 case data_wchar: 1572 validate_wchar((wchar_t *) varp->value, (wchar_t *) response, 0); 1573 break; 1574 1575 default: 1576 errx(1, "%s:%zu: Invalid return type for reference", 1577 cur_file, line); 1578 break; 1579 } 1580 } 1581 1582 /* 1583 * Validate the return type against the expected type, throw an error 1584 * if they don't match. 1585 */ 1586 static void 1587 validate_type(data_enum_t expected, ct_data_t *value, int check) 1588 { 1589 if (((check == 0) && (expected != value->data_type)) || 1590 ((check == 1) && (expected == value->data_type))) 1591 errx(1, "%s:%zu: Validate expected type %s %s %s", 1592 cur_file, line, 1593 enum_names[expected], 1594 (check == 0)? "matching" : "not matching", 1595 enum_names[value->data_type]); 1596 1597 if (verbose) { 1598 fprintf(stderr, "%s:%zu: Validated expected type %s %s %s\n", 1599 cur_file, line, 1600 enum_names[expected], 1601 (check == 0)? "matching" : "not matching", 1602 enum_names[value->data_type]); 1603 } 1604 } 1605 1606 /* 1607 * Validate the return value against the expected value, throw an error 1608 * if they don't match. 1609 */ 1610 static void 1611 validate_return(const char *expected, const char *value, int check) 1612 { 1613 if (((check == 0) && strcmp(expected, value) != 0) || 1614 ((check == 1) && strcmp(expected, value) == 0)) 1615 errx(1, "%s:%zu: Validate expected >%s< %s >%s<", 1616 cur_file, line, 1617 expected, 1618 (check == 0)? "matching" : "not matching", 1619 value); 1620 if (verbose) { 1621 fprintf(stderr, 1622 "%s:%zu: Validated expected value >%s< %s >%s<\n", 1623 cur_file, line, 1624 expected, 1625 (check == 0)? "matches" : "does not match", 1626 value); 1627 } 1628 } 1629 1630 /* 1631 * Validate the return value against the expected value, throw an error 1632 * if they don't match expectations. 1633 */ 1634 static void 1635 validate_byte(ct_data_t *expected, ct_data_t *value, int check) 1636 { 1637 char *ch; 1638 size_t i; 1639 1640 if (verbose) { 1641 ch = value->data_value; 1642 fprintf(stderr, "checking returned byte stream: "); 1643 for (i = 0; i < value->data_len; i++) 1644 fprintf(stderr, "%s0x%x", (i != 0)? ", " : "", ch[i]); 1645 fprintf(stderr, "\n"); 1646 1647 fprintf(stderr, "%s byte stream: ", 1648 (check == 0)? "matches" : "does not match"); 1649 ch = (char *) expected->data_value; 1650 for (i = 0; i < expected->data_len; i++) 1651 fprintf(stderr, "%s0x%x", (i != 0)? ", " : "", ch[i]); 1652 fprintf(stderr, "\n"); 1653 } 1654 1655 /* 1656 * No chance of a match if lengths differ... 1657 */ 1658 if ((check == 0) && (expected->data_len != value->data_len)) 1659 errx(1, 1660 "Byte validation failed, length mismatch, " 1661 "expected %zu, received %zu", 1662 expected->data_len, value->data_len); 1663 1664 /* 1665 * If check is 0 then we want to throw an error IFF the byte streams 1666 * do not match, if check is 1 then throw an error if the byte 1667 * streams match. 1668 */ 1669 if (((check == 0) && memcmp(expected->data_value, value->data_value, 1670 value->data_len) != 0) || 1671 ((check == 1) && (expected->data_len == value->data_len) && 1672 memcmp(expected->data_value, value->data_value, 1673 value->data_len) == 0)) 1674 errx(1, "%s:%zu: Validate expected %s byte stream", 1675 cur_file, line, 1676 (check == 0)? "matching" : "not matching"); 1677 if (verbose) { 1678 fprintf(stderr, "%s:%zu: Validated expected %s byte stream\n", 1679 cur_file, line, 1680 (check == 0)? "matching" : "not matching"); 1681 } 1682 } 1683 1684 /* 1685 * Validate the return cchar against the expected cchar, throw an error 1686 * if they don't match expectations. 1687 */ 1688 static void 1689 validate_cchar(cchar_t *expected, cchar_t *value, int check) 1690 { 1691 unsigned j; 1692 1693 /* 1694 * No chance of a match if elements count differ... 1695 */ 1696 if ((expected->elements != value->elements)) { 1697 if (check == 0) 1698 errx(1, 1699 "cchar validation failed, elements count mismatch, " 1700 "expected %d, received %d", 1701 expected->elements, value->elements); 1702 else { 1703 if (verbose) 1704 fprintf(stderr, 1705 "%s:%zu: Validated expected %s cchar", 1706 cur_file, line, "not matching"); 1707 return; 1708 } 1709 } 1710 1711 /* 1712 * No chance of a match if attributes differ... 1713 */ 1714 1715 if ((expected->attributes & WA_ATTRIBUTES) != 1716 (value->attributes & WA_ATTRIBUTES )) { 1717 if (check == 0) 1718 errx(1, 1719 "cchar validation failed, attributes mismatch, " 1720 "expected 0x%x, received 0x%x", 1721 expected->attributes & WA_ATTRIBUTES, 1722 value->attributes & WA_ATTRIBUTES); 1723 else { 1724 if (verbose) 1725 fprintf(stderr, 1726 "%s:%zu: Validated expected %s cchar\n", 1727 cur_file, line, "not matching"); 1728 return; 1729 } 1730 } 1731 1732 /* 1733 * If check is 0 then we want to throw an error IFF the vals 1734 * do not match, if check is 1 then throw an error if the vals 1735 * streams match. 1736 */ 1737 for(j = 0; j < expected->elements; j++) { 1738 if (expected->vals[j] != value->vals[j]) { 1739 if (check == 0) 1740 errx(1, 1741 "cchar validation failed, vals mismatch, " 1742 "expected 0x%x, received 0x%x", 1743 expected->vals[j], value->vals[j]); 1744 else { 1745 if (verbose) 1746 fprintf(stderr, 1747 "%s:%zu: Validated expected %s " 1748 "cchar\n", 1749 cur_file, line, "not matching"); 1750 return; 1751 } 1752 } 1753 } 1754 1755 if (verbose) { 1756 fprintf(stderr, 1757 "%s:%zu: Validated expected %s cchar\n", 1758 cur_file, line, (check == 0)? "matching" : "not matching"); 1759 } 1760 } 1761 1762 /* 1763 * Validate the return wchar string against the expected wchar, throw an 1764 * error if they don't match expectations. 1765 */ 1766 static void 1767 validate_wchar(wchar_t *expected, wchar_t *value, int check) 1768 { 1769 unsigned j; 1770 1771 unsigned len1 = 0; 1772 unsigned len2 = 0; 1773 wchar_t *p; 1774 1775 p = expected; 1776 while (*p++ != L'\0') 1777 len1++; 1778 1779 p = value; 1780 while (*p++ != L'\0') 1781 len2++; 1782 1783 /* 1784 * No chance of a match if length differ... 1785 */ 1786 if (len1 != len2) { 1787 if (check == 0) 1788 errx(1, 1789 "wchar string validation failed, length mismatch, " 1790 "expected %d, received %d", 1791 len1, len2); 1792 else { 1793 if (verbose) 1794 fprintf(stderr, 1795 "%s:%zu: Validated expected %s wchar\n", 1796 cur_file, line, "not matching"); 1797 return; 1798 } 1799 } 1800 1801 /* 1802 * If check is 0 then we want to throw an error IFF the vals 1803 * do not match, if check is 1 then throw an error if the vals 1804 * streams match. 1805 */ 1806 for(j = 0; j < len1; j++) { 1807 if (expected[j] != value[j]) { 1808 if (check == 0) 1809 errx(1, "wchar validation failed at index %d, expected %d," 1810 "received %d", j, expected[j], value[j]); 1811 else { 1812 if (verbose) 1813 fprintf(stderr, 1814 "%s:%zu: Validated expected %s wchar\n", 1815 cur_file, line, "not matching"); 1816 return; 1817 } 1818 } 1819 } 1820 1821 if (verbose) { 1822 fprintf(stderr, 1823 "%s:%zu: Validated expected %s wchar\n", 1824 cur_file, line, 1825 (check == 0)? "matching" : "not matching"); 1826 } 1827 } 1828 1829 /* 1830 * Validate the variable at i against the expected value, throw an 1831 * error if they don't match, if check is non-zero then the match is 1832 * negated. 1833 */ 1834 static void 1835 validate_variable(int ret, data_enum_t type, const void *value, int i, 1836 int check) 1837 { 1838 ct_data_t *retval; 1839 var_t *varptr; 1840 1841 retval = &command.returns[ret]; 1842 varptr = &vars[command.returns[ret].data_index]; 1843 1844 if (varptr->value == NULL) 1845 errx(1, "Variable %s has no value assigned to it", varptr->name); 1846 1847 1848 if (varptr->type != type) 1849 errx(1, "Variable %s is not the expected type", varptr->name); 1850 1851 if (type != data_byte) { 1852 if ((((check == 0) && strcmp(value, varptr->value) != 0)) 1853 || ((check == 1) && strcmp(value, varptr->value) == 0)) 1854 errx(1, "%s:%zu: Variable %s contains %s instead of %s" 1855 " value %s", 1856 cur_file, line, 1857 varptr->name, (const char *)varptr->value, 1858 (check == 0)? "expected" : "not matching", 1859 (const char *)value); 1860 if (verbose) { 1861 fprintf(stderr, 1862 "%s:%zu: Variable %s contains %s value %s\n", 1863 cur_file, line, 1864 varptr->name, 1865 (check == 0)? "expected" : "not matching", 1866 (const char *)varptr->value); 1867 } 1868 } else { 1869 if ((check == 0) && (retval->data_len != varptr->len)) 1870 errx(1, "Byte validation failed, length mismatch"); 1871 1872 /* 1873 * If check is 0 then we want to throw an error IFF 1874 * the byte streams do not match, if check is 1 then 1875 * throw an error if the byte streams match. 1876 */ 1877 if (((check == 0) && memcmp(retval->data_value, varptr->value, 1878 varptr->len) != 0) || 1879 ((check == 1) && (retval->data_len == varptr->len) && 1880 memcmp(retval->data_value, varptr->value, 1881 varptr->len) == 0)) 1882 errx(1, "%s:%zu: Validate expected %s byte stream", 1883 cur_file, line, 1884 (check == 0)? "matching" : "not matching"); 1885 if (verbose) { 1886 fprintf(stderr, 1887 "%s:%zu: Validated expected %s byte stream\n", 1888 cur_file, line, 1889 (check == 0)? "matching" : "not matching"); 1890 } 1891 } 1892 } 1893 1894 /* 1895 * Write a string to the command pipe - we feed the number of bytes coming 1896 * down first to allow storage allocation and then follow up with the data. 1897 * If cmd is NULL then feed a -1 down the pipe to say the end of the args. 1898 */ 1899 static void 1900 write_cmd_pipe(char *cmd) 1901 { 1902 args_t arg; 1903 size_t len; 1904 1905 if (cmd == NULL) 1906 len = 0; 1907 else 1908 len = strlen(cmd); 1909 1910 arg.arg_type = data_static; 1911 arg.arg_len = len; 1912 arg.arg_string = cmd; 1913 write_cmd_pipe_args(arg.arg_type, &arg); 1914 1915 } 1916 1917 static void 1918 write_cmd_pipe_args(data_enum_t type, void *data) 1919 { 1920 var_t *var_data; 1921 args_t *arg_data; 1922 int len, send_type; 1923 void *cmd; 1924 1925 arg_data = data; 1926 switch (type) { 1927 case data_var: 1928 var_data = data; 1929 len = var_data->len; 1930 cmd = var_data->value; 1931 1932 switch (var_data->type) { 1933 case data_byte: 1934 send_type = data_byte; 1935 break; 1936 1937 case data_cchar: 1938 send_type = data_cchar; 1939 cmd = (void *) &var_data->cchar; 1940 len = sizeof(cchar_t); 1941 break; 1942 1943 case data_wchar: 1944 send_type = data_wchar; 1945 break; 1946 1947 default: 1948 send_type = data_string; 1949 break; 1950 } 1951 break; 1952 1953 case data_null: 1954 send_type = data_null; 1955 len = 0; 1956 break; 1957 1958 default: 1959 if ((arg_data->arg_len == 0) && (arg_data->arg_string == NULL)) 1960 len = -1; 1961 else 1962 len = arg_data->arg_len; 1963 cmd = arg_data->arg_string; 1964 if (type == data_byte) 1965 send_type = data_byte; 1966 else 1967 send_type = data_string; 1968 } 1969 1970 if (verbose) { 1971 fprintf(stderr, "Writing type %s to command pipe\n", 1972 enum_names[send_type]); 1973 } 1974 1975 if (write(to_slave, &send_type, sizeof(int)) < 0) 1976 err(1, "command pipe write for type failed"); 1977 1978 if (verbose) { 1979 if (send_type == data_cchar) 1980 fprintf(stderr, 1981 "Writing cchar to command pipe\n"); 1982 else if (send_type == data_wchar) 1983 fprintf(stderr, 1984 "Writing wchar(%d sized) to command pipe\n", len); 1985 else 1986 fprintf(stderr, 1987 "Writing length %d to command pipe\n", len); 1988 } 1989 1990 if (write(to_slave, &len, sizeof(int)) < 0) 1991 err(1, "command pipe write for length failed"); 1992 1993 if (len > 0) { 1994 if (verbose) { 1995 fprintf(stderr, "Writing data >%s< to command pipe\n", 1996 (const char *)cmd); 1997 } 1998 if (write(to_slave, cmd, len) < 0) 1999 err(1, "command pipe write of data failed"); 2000 } 2001 } 2002 2003 /* 2004 * Read a response from the command pipe, first we will receive the 2005 * length of the response then the actual data. 2006 */ 2007 static void 2008 read_cmd_pipe(ct_data_t *response) 2009 { 2010 int len, type; 2011 struct pollfd rfd[2]; 2012 char *str; 2013 2014 /* 2015 * Check if there is data to read - just in case slave has died, we 2016 * don't want to block on the read and just hang. We also check 2017 * output from the slave because the slave may be blocked waiting 2018 * for a flush on its stdout. 2019 */ 2020 rfd[0].fd = from_slave; 2021 rfd[0].events = POLLIN; 2022 rfd[1].fd = master; 2023 rfd[1].events = POLLIN; 2024 2025 do { 2026 if (poll(rfd, 2, 4000) == 0) 2027 errx(2, "%s:%zu: Command pipe read timeout", 2028 cur_file, line); 2029 2030 if ((rfd[1].revents & POLLIN) == POLLIN) { 2031 if (verbose) { 2032 fprintf(stderr, 2033 "draining output from slave\n"); 2034 } 2035 save_slave_output(false); 2036 } 2037 } 2038 while ((rfd[1].revents & POLLIN) == POLLIN); 2039 2040 if (read(from_slave, &type, sizeof(int)) < 0) 2041 err(1, "command pipe read for type failed"); 2042 response->data_type = type; 2043 2044 if ((type != data_ok) && (type != data_err) && (type != data_count)) { 2045 if (read(from_slave, &len, sizeof(int)) < 0) 2046 err(1, "command pipe read for length failed"); 2047 response->data_len = len; 2048 2049 if (verbose) { 2050 fprintf(stderr, 2051 "Reading %d bytes from command pipe\n", len); 2052 } 2053 2054 if ((response->data_value = malloc(len + 1)) == NULL) 2055 err(1, "Failed to alloc memory for cmd pipe read"); 2056 2057 if (read(from_slave, response->data_value, len) < 0) 2058 err(1, "command pipe read of data failed"); 2059 2060 if (response->data_type != data_byte) { 2061 str = response->data_value; 2062 str[len] = '\0'; 2063 2064 if (verbose) { 2065 fprintf(stderr, "Read data >%s< from pipe\n", 2066 (const char *)response->data_value); 2067 } 2068 } 2069 } else { 2070 response->data_value = NULL; 2071 if (type == data_count) { 2072 if (read(from_slave, &len, sizeof(int)) < 0) 2073 err(1, "command pipe read for number of " 2074 "returns failed"); 2075 response->data_len = len; 2076 } 2077 2078 if (verbose) { 2079 fprintf(stderr, "Read type %s from pipe\n", 2080 enum_names[type]); 2081 } 2082 } 2083 } 2084 2085 /* 2086 * Check for writes from the slave on the pty, save the output into a 2087 * buffer for later checking if discard is false. 2088 */ 2089 #define MAX_DRAIN 256 2090 2091 static void 2092 save_slave_output(bool discard) 2093 { 2094 char *new_data, drain[MAX_DRAIN]; 2095 size_t to_allocate; 2096 ssize_t result; 2097 size_t i; 2098 2099 result = 0; 2100 for (;;) { 2101 if (result == -1) 2102 err(2, "poll of slave pty failed"); 2103 result = MAX_DRAIN; 2104 if ((result = read(master, drain, result)) < 0) { 2105 if (errno == EAGAIN) 2106 break; 2107 else 2108 err(2, "draining slave pty failed"); 2109 } 2110 if (result == 0) 2111 abort(); 2112 2113 if (!discard) { 2114 if ((size_t)result > 2115 (saved_output.allocated - saved_output.count)) { 2116 to_allocate = 1024 * ((result / 1024) + 1); 2117 2118 if ((new_data = realloc(saved_output.data, 2119 saved_output.allocated + to_allocate)) 2120 == NULL) 2121 err(2, "Realloc of saved_output failed"); 2122 saved_output.data = new_data; 2123 saved_output.allocated += to_allocate; 2124 } 2125 2126 if (verbose) { 2127 fprintf(stderr, 2128 "count = %zu, allocated = %zu\n", 2129 saved_output.count, saved_output.allocated); 2130 for (i = 0; i < (size_t)result; i++) { 2131 fprintf(stderr, "Saving slave output " 2132 "at %zu: 0x%x (%c)\n", 2133 saved_output.count + i, drain[i], 2134 (drain[i] >= ' ')? drain[i] : '-'); 2135 } 2136 } 2137 2138 memcpy(&saved_output.data[saved_output.count], drain, 2139 result); 2140 saved_output.count += result; 2141 2142 if (verbose) { 2143 fprintf(stderr, 2144 "count = %zu, allocated = %zu\n", 2145 saved_output.count, saved_output.allocated); 2146 } 2147 } else { 2148 if (verbose) { 2149 for (i = 0; i < (size_t)result; i++) { 2150 fprintf(stderr, "Discarding slave " 2151 "output 0x%x (%c)\n", 2152 drain[i], 2153 (drain[i] >= ' ')? drain[i] : '-'); 2154 } 2155 } 2156 } 2157 } 2158 } 2159 2160 static void 2161 yyerror(const char *msg) 2162 { 2163 errx(1, "%s:%zu: %s", cur_file, line, msg); 2164 } 2165