1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2015 Garrett D'Amore <garrett@damore.org> 14 * Copyright 2018 Joyent, Inc. 15 */ 16 17 /* 18 * This program tests symbol visibility in different compilation environments. 19 */ 20 21 #include <stdio.h> 22 #include <stdlib.h> 23 #include <string.h> 24 #include <errno.h> 25 #include <err.h> 26 #include <unistd.h> 27 #include <sys/types.h> 28 #include <sys/stat.h> 29 #include <note.h> 30 #include <libcustr.h> 31 #include <sys/wait.h> 32 #include "test_common.h" 33 34 char *dname; 35 char *cfile; 36 char *ofile; 37 char *lfile; 38 char *efile; 39 40 const char *sym = NULL; 41 42 static int good_count = 0; 43 static int fail_count = 0; 44 static int full_count = 0; 45 static int extra_debug = 0; 46 static char *compilation = "compilation.cfg"; 47 48 #if defined(_LP64) 49 #define MFLAG "-m64" 50 #elif defined(_ILP32) 51 #define MFLAG "-m32" 52 #endif 53 54 const char *compilers[] = { 55 "cc", 56 "gcc", 57 "/opt/SUNWspro/bin/cc", 58 "/opt/gcc/4.4.4/bin/gcc", 59 "/opt/sunstudio12.1/bin/cc", 60 "/opt/sfw/bin/gcc", 61 "/usr/local/bin/gcc", 62 NULL 63 }; 64 65 char *compiler = NULL; 66 const char *c89flags = NULL; 67 const char *c99flags = NULL; 68 const char *c11flags = NULL; 69 70 #define MAXENV 64 /* maximum number of environments (bitmask width) */ 71 #define MAXHDR 10 /* maximum # headers to require to access symbol */ 72 #define MAXARG 20 /* maximum # of arguments */ 73 74 #define WS " \t" 75 76 static int next_env = 0; 77 78 struct compile_env { 79 char *ce_name; 80 char *ce_lang; 81 char *ce_defs; 82 int ce_index; 83 }; 84 85 static struct compile_env compile_env[MAXENV]; 86 87 struct env_group { 88 char *eg_name; 89 uint64_t eg_mask; 90 struct env_group *eg_next; 91 }; 92 93 typedef enum { 94 SYM_TYPE, 95 SYM_VALUE, 96 SYM_DEFINE, 97 SYM_FUNC 98 } sym_type_t; 99 100 struct sym_test { 101 char *st_name; 102 sym_type_t st_type; 103 char *st_hdrs[MAXHDR]; 104 char *st_rtype; 105 char *st_atypes[MAXARG]; 106 char *st_defval; 107 uint64_t st_test_mask; 108 uint64_t st_need_mask; 109 const char *st_prog; 110 struct sym_test *st_next; 111 }; 112 113 struct env_group *env_groups = NULL; 114 115 struct sym_test *sym_tests = NULL; 116 struct sym_test **sym_insert = &sym_tests; 117 118 static char * 119 mystrdup(const char *s) 120 { 121 char *r; 122 if ((r = strdup(s)) == NULL) { 123 perror("strdup"); 124 exit(1); 125 } 126 return (r); 127 } 128 129 static void * 130 myzalloc(size_t sz) 131 { 132 void *buf; 133 if ((buf = calloc(1, sz)) == NULL) { 134 perror("calloc"); 135 exit(1); 136 } 137 return (buf); 138 } 139 140 static void 141 myasprintf(char **buf, const char *fmt, ...) 142 { 143 int rv; 144 va_list va; 145 va_start(va, fmt); 146 rv = vasprintf(buf, fmt, va); 147 va_end(va); 148 if (rv < 0) { 149 perror("vasprintf"); 150 exit(1); 151 } 152 } 153 154 static void 155 append_sym_test(struct sym_test *st) 156 { 157 *sym_insert = st; 158 sym_insert = &st->st_next; 159 } 160 161 static int 162 find_env_mask(const char *name, uint64_t *mask) 163 { 164 for (int i = 0; i < MAXENV; i++) { 165 if (compile_env[i].ce_name != NULL && 166 strcmp(compile_env[i].ce_name, name) == 0) { 167 *mask |= (1ULL << i); 168 return (0); 169 } 170 } 171 172 for (struct env_group *eg = env_groups; eg != NULL; eg = eg->eg_next) { 173 if (strcmp(name, eg->eg_name) == 0) { 174 *mask |= eg->eg_mask; 175 return (0); 176 } 177 } 178 return (-1); 179 } 180 181 182 static int 183 expand_env(char *list, uint64_t *mask, char **erritem) 184 { 185 char *item; 186 for (item = strtok(list, WS); item != NULL; item = strtok(NULL, WS)) { 187 if (find_env_mask(item, mask) < 0) { 188 if (erritem != NULL) { 189 *erritem = item; 190 } 191 return (-1); 192 } 193 } 194 return (0); 195 } 196 197 static int 198 expand_env_list(char *list, uint64_t *test, uint64_t *need, char **erritem) 199 { 200 uint64_t mask = 0; 201 int act; 202 char *item; 203 for (item = strtok(list, WS); item != NULL; item = strtok(NULL, WS)) { 204 switch (item[0]) { 205 case '+': 206 act = 1; 207 item++; 208 break; 209 case '-': 210 act = 0; 211 item++; 212 break; 213 default: 214 act = 1; 215 break; 216 } 217 218 mask = 0; 219 if (find_env_mask(item, &mask) < 0) { 220 if (erritem != NULL) { 221 *erritem = item; 222 } 223 return (-1); 224 } 225 *test |= mask; 226 if (act) { 227 *need |= mask; 228 } else { 229 *need &= ~(mask); 230 } 231 } 232 return (0); 233 } 234 235 static int 236 do_env(char **fields, int nfields, char **err) 237 { 238 char *name; 239 char *lang; 240 char *defs; 241 242 if (nfields != 3) { 243 myasprintf(err, "number of fields (%d) != 3", nfields); 244 return (-1); 245 } 246 247 if (next_env >= MAXENV) { 248 myasprintf(err, "too many environments"); 249 return (-1); 250 } 251 252 name = fields[0]; 253 lang = fields[1]; 254 defs = fields[2]; 255 256 compile_env[next_env].ce_name = mystrdup(name); 257 compile_env[next_env].ce_lang = mystrdup(lang); 258 compile_env[next_env].ce_defs = mystrdup(defs); 259 compile_env[next_env].ce_index = next_env; 260 next_env++; 261 return (0); 262 } 263 264 static int 265 do_env_group(char **fields, int nfields, char **err) 266 { 267 char *name; 268 char *list; 269 struct env_group *eg; 270 uint64_t mask; 271 char *item; 272 273 if (nfields != 2) { 274 myasprintf(err, "number of fields (%d) != 2", nfields); 275 return (-1); 276 } 277 278 name = fields[0]; 279 list = fields[1]; 280 mask = 0; 281 282 if (expand_env(list, &mask, &item) < 0) { 283 myasprintf(err, "reference to undefined env %s", item); 284 return (-1); 285 } 286 287 eg = myzalloc(sizeof (*eg)); 288 eg->eg_name = mystrdup(name); 289 eg->eg_mask = mask; 290 eg->eg_next = env_groups; 291 env_groups = eg; 292 return (0); 293 } 294 295 static custr_t *st_custr; 296 297 static void 298 addprogch(char c) 299 { 300 if (custr_appendc(st_custr, c) == -1) { 301 perror("custr_appendc"); 302 exit(1); 303 } 304 } 305 306 static void 307 addprogstr(char *s) 308 { 309 if (custr_append(st_custr, s) == -1) { 310 perror("custr_append"); 311 exit(1); 312 } 313 } 314 315 static void 316 addprogfmt(const char *fmt, ...) 317 { 318 va_list va; 319 va_start(va, fmt); 320 if (custr_append_vprintf(st_custr, fmt, va) == -1) { 321 perror("custr_append_vprintf"); 322 exit(1); 323 } 324 va_end(va); 325 } 326 327 static void 328 mkprog(struct sym_test *st) 329 { 330 char *s = NULL; 331 332 custr_reset(st_custr); 333 334 for (int i = 0; i < MAXHDR && st->st_hdrs[i] != NULL; i++) { 335 addprogfmt("#include <%s>\n", st->st_hdrs[i]); 336 } 337 338 if (st->st_rtype != NULL) { 339 for (s = st->st_rtype; *s; s++) { 340 addprogch(*s); 341 if (*s == '(') { 342 s++; 343 addprogch(*s); 344 s++; 345 break; 346 } 347 } 348 addprogch(' '); 349 } 350 351 /* for function pointers, s is closing suffix, otherwise empty */ 352 353 switch (st->st_type) { 354 case SYM_TYPE: 355 addprogstr("test_type;"); 356 break; 357 358 case SYM_VALUE: 359 addprogfmt("test_value%s;\n", s); /* s usually empty */ 360 addprogstr("void\ntest_func(void)\n{\n"); 361 addprogfmt("\ttest_value = %s;\n}", st->st_name); 362 break; 363 364 case SYM_DEFINE: 365 addprogfmt("#if !defined(%s)", st->st_name); 366 if (st->st_defval != NULL) 367 addprogfmt("|| %s != %s", st->st_name, st->st_defval); 368 addprogfmt("\n#error %s is not defined or has the wrong value", 369 st->st_name); 370 addprogfmt("\n#endif\n"); 371 break; 372 373 case SYM_FUNC: 374 addprogstr("\ntest_func("); 375 for (int i = 0; i < MAXARG && st->st_atypes[i] != NULL; i++) { 376 int didname = 0; 377 if (i > 0) { 378 addprogstr(", "); 379 } 380 if (strcmp(st->st_atypes[i], "void") == 0) { 381 didname = 1; 382 } 383 if (strcmp(st->st_atypes[i], "") == 0) { 384 didname = 1; 385 addprogstr("void"); 386 } 387 388 /* print the argument list */ 389 for (char *a = st->st_atypes[i]; *a; a++) { 390 if (*a == '(' && a[1] == '*' && !didname) { 391 addprogfmt("(*a%d", i); 392 didname = 1; 393 a++; 394 } else if (*a == '[' && !didname) { 395 addprogfmt("a%d[", i); 396 didname = 1; 397 } else { 398 addprogch(*a); 399 } 400 } 401 if (!didname) { 402 addprogfmt(" a%d", i); 403 } 404 } 405 406 if (st->st_atypes[0] == NULL) { 407 addprogstr("void"); 408 } 409 410 /* 411 * Close argument list, and closing ")" for func ptrs. 412 * Note that for non-function pointers, s will be empty 413 * below, otherwise it points to the trailing argument 414 * list. 415 */ 416 addprogfmt(")%s\n{\n\t", s); 417 418 if (strcmp(st->st_rtype, "") != 0 && 419 strcmp(st->st_rtype, "void") != 0) { 420 addprogstr("return "); 421 } 422 423 /* add the function call */ 424 addprogfmt("%s(", st->st_name); 425 for (int i = 0; i < MAXARG && st->st_atypes[i] != NULL; i++) { 426 if (strcmp(st->st_atypes[i], "") != 0 && 427 strcmp(st->st_atypes[i], "void") != 0) { 428 addprogfmt("%sa%d", i > 0 ? ", " : "", i); 429 } 430 } 431 432 addprogstr(");\n}"); 433 break; 434 } 435 436 addprogch('\n'); 437 438 st->st_prog = custr_cstr(st_custr); 439 } 440 441 static int 442 add_envs(struct sym_test *st, char *envs, char **err) 443 { 444 char *item; 445 if (expand_env_list(envs, &st->st_test_mask, &st->st_need_mask, 446 &item) < 0) { 447 myasprintf(err, "bad env action %s", item); 448 return (-1); 449 } 450 return (0); 451 } 452 453 static int 454 add_headers(struct sym_test *st, char *hdrs, char **err) 455 { 456 int i = 0; 457 458 for (char *h = strsep(&hdrs, ";"); h != NULL; h = strsep(&hdrs, ";")) { 459 if (i >= MAXHDR) { 460 myasprintf(err, "too many headers"); 461 return (-1); 462 } 463 test_trim(&h); 464 st->st_hdrs[i++] = mystrdup(h); 465 } 466 467 return (0); 468 } 469 470 static int 471 add_arg_types(struct sym_test *st, char *atype, char **err) 472 { 473 int i = 0; 474 char *a; 475 for (a = strsep(&atype, ";"); a != NULL; a = strsep(&atype, ";")) { 476 if (i >= MAXARG) { 477 myasprintf(err, "too many arguments"); 478 return (-1); 479 } 480 test_trim(&a); 481 st->st_atypes[i++] = mystrdup(a); 482 } 483 484 return (0); 485 } 486 487 static int 488 do_type(char **fields, int nfields, char **err) 489 { 490 char *decl; 491 char *hdrs; 492 char *envs; 493 struct sym_test *st; 494 495 if (nfields != 3) { 496 myasprintf(err, "number of fields (%d) != 3", nfields); 497 return (-1); 498 } 499 decl = fields[0]; 500 hdrs = fields[1]; 501 envs = fields[2]; 502 503 st = myzalloc(sizeof (*st)); 504 st->st_type = SYM_TYPE; 505 st->st_name = mystrdup(decl); 506 st->st_rtype = mystrdup(decl); 507 508 if ((add_envs(st, envs, err) < 0) || 509 (add_headers(st, hdrs, err) < 0)) { 510 return (-1); 511 } 512 append_sym_test(st); 513 514 return (0); 515 } 516 517 static int 518 do_value(char **fields, int nfields, char **err) 519 { 520 char *name; 521 char *type; 522 char *hdrs; 523 char *envs; 524 struct sym_test *st; 525 526 if (nfields != 4) { 527 myasprintf(err, "number of fields (%d) != 4", nfields); 528 return (-1); 529 } 530 name = fields[0]; 531 type = fields[1]; 532 hdrs = fields[2]; 533 envs = fields[3]; 534 535 st = myzalloc(sizeof (*st)); 536 st->st_type = SYM_VALUE; 537 st->st_name = mystrdup(name); 538 st->st_rtype = mystrdup(type); 539 540 if ((add_envs(st, envs, err) < 0) || 541 (add_headers(st, hdrs, err) < 0)) { 542 return (-1); 543 } 544 append_sym_test(st); 545 546 return (0); 547 } 548 549 static int 550 do_define(char **fields, int nfields, char **err) 551 { 552 char *name, *value, *hdrs, *envs; 553 struct sym_test *st; 554 555 if (nfields != 4) { 556 myasprintf(err, "number of fields (%d) != 4", nfields); 557 return (-1); 558 } 559 560 name = fields[0]; 561 value = fields[1]; 562 hdrs = fields[2]; 563 envs = fields[3]; 564 565 st = myzalloc(sizeof (*st)); 566 st->st_type = SYM_DEFINE; 567 st->st_name = mystrdup(name); 568 569 /* 570 * A value to compare against is optional. trim will leave it as a null 571 * pointer if there's nothing there. 572 */ 573 test_trim(&value); 574 if (*value != '\0') 575 st->st_defval = mystrdup(value); 576 577 if ((add_envs(st, envs, err) < 0) || 578 (add_headers(st, hdrs, err) < 0)) { 579 return (-1); 580 } 581 582 append_sym_test(st); 583 584 return (0); 585 } 586 587 static int 588 do_func(char **fields, int nfields, char **err) 589 { 590 char *name; 591 char *rtype; 592 char *atype; 593 char *hdrs; 594 char *envs; 595 struct sym_test *st; 596 597 if (nfields != 5) { 598 myasprintf(err, "number of fields (%d) != 5", nfields); 599 return (-1); 600 } 601 name = fields[0]; 602 rtype = fields[1]; 603 atype = fields[2]; 604 hdrs = fields[3]; 605 envs = fields[4]; 606 607 st = myzalloc(sizeof (*st)); 608 st->st_type = SYM_FUNC; 609 st->st_name = mystrdup(name); 610 st->st_rtype = mystrdup(rtype); 611 612 if ((add_envs(st, envs, err) < 0) || 613 (add_headers(st, hdrs, err) < 0) || 614 (add_arg_types(st, atype, err) < 0)) { 615 return (-1); 616 } 617 append_sym_test(st); 618 619 return (0); 620 } 621 622 struct sym_test * 623 next_sym_test(struct sym_test *st) 624 { 625 return (st == NULL ? sym_tests : st->st_next); 626 } 627 628 const char * 629 sym_test_prog(struct sym_test *st) 630 { 631 if (st->st_prog == NULL) { 632 mkprog(st); 633 } 634 return (st->st_prog); 635 } 636 637 const char * 638 sym_test_name(struct sym_test *st) 639 { 640 return (st->st_name); 641 } 642 643 /* 644 * Iterate through tests. Pass in NULL for cenv to begin the iteration. For 645 * subsequent iterations, use the return value from the previous iteration. 646 * Returns NULL when there are no more environments. 647 */ 648 struct compile_env * 649 sym_test_env(struct sym_test *st, struct compile_env *cenv, int *need) 650 { 651 int i = cenv ? cenv->ce_index + 1: 0; 652 uint64_t b = 1ULL << i; 653 654 while ((i < MAXENV) && (b != 0)) { 655 cenv = &compile_env[i]; 656 if (b & st->st_test_mask) { 657 *need = (st->st_need_mask & b) ? 1 : 0; 658 return (cenv); 659 } 660 b <<= 1; 661 i++; 662 } 663 return (NULL); 664 } 665 666 const char * 667 env_name(struct compile_env *cenv) 668 { 669 return (cenv->ce_name); 670 } 671 672 const char * 673 env_lang(struct compile_env *cenv) 674 { 675 return (cenv->ce_lang); 676 } 677 678 const char * 679 env_defs(struct compile_env *cenv) 680 { 681 return (cenv->ce_defs); 682 } 683 684 static void 685 show_file(test_t t, const char *path) 686 { 687 FILE *f; 688 char *buf = NULL; 689 size_t cap = 0; 690 int line = 1; 691 692 f = fopen(path, "r"); 693 if (f == NULL) { 694 test_debugf(t, "fopen(%s): %s", path, strerror(errno)); 695 return; 696 } 697 698 test_debugf(t, "----->> begin (%s) <<------", path); 699 while (getline(&buf, &cap, f) >= 0) { 700 (void) strtok(buf, "\r\n"); 701 test_debugf(t, "%d: %s", line, buf); 702 line++; 703 } 704 test_debugf(t, "----->> end (%s) <<------", path); 705 (void) fclose(f); 706 } 707 708 static void 709 cleanup(void) 710 { 711 if (ofile != NULL) { 712 (void) unlink(ofile); 713 free(ofile); 714 ofile = NULL; 715 } 716 if (lfile != NULL) { 717 (void) unlink(lfile); 718 free(lfile); 719 lfile = NULL; 720 } 721 if (cfile != NULL) { 722 (void) unlink(cfile); 723 free(cfile); 724 cfile = NULL; 725 } 726 if (efile != NULL) { 727 (void) unlink(efile); 728 free(efile); 729 efile = NULL; 730 } 731 if (dname) { 732 (void) rmdir(dname); 733 free(dname); 734 dname = NULL; 735 } 736 } 737 738 static int 739 mkworkdir(void) 740 { 741 char b[32]; 742 char *d; 743 744 cleanup(); 745 746 (void) strlcpy(b, "/tmp/symbols_testXXXXXX", sizeof (b)); 747 if ((d = mkdtemp(b)) == NULL) { 748 perror("mkdtemp"); 749 return (-1); 750 } 751 dname = mystrdup(d); 752 myasprintf(&cfile, "%s/compile_test.c", d); 753 myasprintf(&ofile, "%s/compile_test.o", d); 754 myasprintf(&lfile, "%s/compile_test.log", d); 755 myasprintf(&efile, "%s/compile_test.exe", d); 756 return (0); 757 } 758 759 void 760 find_compiler(void) 761 { 762 test_t t; 763 int i; 764 FILE *cf; 765 766 t = test_start("finding compiler"); 767 768 if ((cf = fopen(cfile, "w+")) == NULL) { 769 test_failed(t, "Unable to open %s for write: %s", cfile, 770 strerror(errno)); 771 return; 772 } 773 (void) fprintf(cf, "#include <stdio.h>\n"); 774 (void) fprintf(cf, "int main(int argc, char **argv) {\n"); 775 (void) fprintf(cf, "#if defined(__SUNPRO_C)\n"); 776 (void) fprintf(cf, "exit(51);\n"); 777 (void) fprintf(cf, "#elif defined(__GNUC__)\n"); 778 (void) fprintf(cf, "exit(52);\n"); 779 (void) fprintf(cf, "#else\n"); 780 (void) fprintf(cf, "exit(99)\n"); 781 (void) fprintf(cf, "#endif\n}\n"); 782 (void) fclose(cf); 783 784 for (i = 0; compilers[i] != NULL; i++) { 785 char cmd[256]; 786 int rv; 787 788 (void) snprintf(cmd, sizeof (cmd), 789 "%s %s %s -o %s >/dev/null 2>&1", 790 compilers[i], MFLAG, cfile, efile); 791 test_debugf(t, "trying %s", cmd); 792 rv = system(cmd); 793 794 test_debugf(t, "result: %d", rv); 795 796 if ((rv < 0) || !WIFEXITED(rv) || WEXITSTATUS(rv) != 0) 797 continue; 798 799 rv = system(efile); 800 if (rv >= 0 && WIFEXITED(rv)) { 801 rv = WEXITSTATUS(rv); 802 } else { 803 rv = -1; 804 } 805 806 switch (rv) { 807 case 51: /* STUDIO */ 808 test_debugf(t, "Found Studio C"); 809 c89flags = "-Xc -errwarn=%all -v -xc99=%none " MFLAG; 810 c99flags = "-Xc -errwarn=%all -v -xc99=%all " MFLAG; 811 c11flags = NULL; 812 if (extra_debug) { 813 test_debugf(t, "c89flags: %s", c89flags); 814 test_debugf(t, "c99flags: %s", c99flags); 815 } 816 test_passed(t); 817 break; 818 case 52: /* GCC */ 819 test_debugf(t, "Found GNU C"); 820 c89flags = "-Wall -Werror -std=c89 -nostdinc " 821 "-isystem /usr/include " MFLAG; 822 c99flags = "-Wall -Werror -std=c99 -nostdinc " 823 "-isystem /usr/include " MFLAG; 824 c11flags = "-Wall -Werror -std=c11 -nostdinc " 825 "-isystem /usr/include " MFLAG; 826 if (extra_debug) { 827 test_debugf(t, "c89flags: %s", c89flags); 828 test_debugf(t, "c99flags: %s", c99flags); 829 } 830 test_passed(t); 831 break; 832 case 99: 833 test_debugf(t, "Found unknown (unsupported) compiler"); 834 continue; 835 default: 836 continue; 837 } 838 myasprintf(&compiler, "%s", compilers[i]); 839 test_debugf(t, "compiler: %s", compiler); 840 return; 841 } 842 test_failed(t, "No compiler found."); 843 } 844 845 int 846 do_compile(test_t t, struct sym_test *st, struct compile_env *cenv, int need) 847 { 848 char *cmd; 849 FILE *logf; 850 FILE *dotc; 851 const char *prog, *cflags, *lang; 852 853 full_count++; 854 855 if ((dotc = fopen(cfile, "w+")) == NULL) { 856 test_failed(t, "fopen(%s): %s", cfile, strerror(errno)); 857 return (-1); 858 } 859 prog = sym_test_prog(st); 860 if (fwrite(prog, 1, strlen(prog), dotc) < strlen(prog)) { 861 test_failed(t, "fwrite: %s", strerror(errno)); 862 (void) fclose(dotc); 863 return (-1); 864 } 865 if (fclose(dotc) < 0) { 866 test_failed(t, "fclose: %s", strerror(errno)); 867 return (-1); 868 } 869 870 (void) unlink(ofile); 871 872 if (strcmp(env_lang(cenv), "c99") == 0) { 873 lang = "c99"; 874 cflags = c99flags; 875 } else if (strcmp(env_lang(cenv), "c11") == 0) { 876 lang = "c11"; 877 cflags = c11flags; 878 } else { 879 lang = "c89"; 880 cflags = c89flags; 881 } 882 883 if (cflags == NULL) { 884 test_failed(t, "compiler %s does not support %s", compiler, 885 lang); 886 return (-1); 887 } 888 889 myasprintf(&cmd, "%s %s %s -c %s -o %s >>%s 2>&1", 890 compiler, cflags, env_defs(cenv), cfile, ofile, lfile); 891 892 if (extra_debug) { 893 test_debugf(t, "command: %s", cmd); 894 } 895 896 if ((logf = fopen(lfile, "w+")) == NULL) { 897 test_failed(t, "fopen: %s", strerror(errno)); 898 return (-1); 899 } 900 (void) fprintf(logf, "===================\n"); 901 (void) fprintf(logf, "PROGRAM:\n%s\n", sym_test_prog(st)); 902 (void) fprintf(logf, "COMMAND: %s\n", cmd); 903 (void) fprintf(logf, "EXPECT: %s\n", need ? "OK" : "FAIL"); 904 (void) fclose(logf); 905 906 switch (system(cmd)) { 907 case -1: 908 test_failed(t, "error compiling in %s: %s", env_name(cenv), 909 strerror(errno)); 910 return (-1); 911 case 0: 912 if (!need) { 913 fail_count++; 914 show_file(t, lfile); 915 test_failed(t, "symbol visible in %s", env_name(cenv)); 916 return (-1); 917 } 918 break; 919 default: 920 if (need) { 921 fail_count++; 922 show_file(t, lfile); 923 test_failed(t, "error compiling in %s", env_name(cenv)); 924 return (-1); 925 } 926 break; 927 } 928 good_count++; 929 return (0); 930 } 931 932 void 933 test_compile(void) 934 { 935 struct sym_test *st; 936 struct compile_env *cenv; 937 test_t t; 938 int need; 939 940 for (st = next_sym_test(NULL); st; st = next_sym_test(st)) { 941 if ((sym != NULL) && strcmp(sym, sym_test_name(st))) { 942 continue; 943 } 944 /* XXX: we really want a sym_test_desc() */ 945 for (cenv = sym_test_env(st, NULL, &need); 946 cenv != NULL; 947 cenv = sym_test_env(st, cenv, &need)) { 948 t = test_start("%s : %c%s", sym_test_name(st), 949 need ? '+' : '-', env_name(cenv)); 950 if (do_compile(t, st, cenv, need) == 0) { 951 test_passed(t); 952 } 953 } 954 } 955 956 if (full_count > 0) { 957 test_summary(); 958 } 959 } 960 961 int 962 main(int argc, char **argv) 963 { 964 int optc; 965 int optC = 0; 966 967 while ((optc = getopt(argc, argv, "DdfCs:c:")) != EOF) { 968 switch (optc) { 969 case 'd': 970 test_set_debug(); 971 break; 972 case 'f': 973 test_set_force(); 974 break; 975 case 'D': 976 test_set_debug(); 977 extra_debug++; 978 break; 979 case 'c': 980 compilation = optarg; 981 break; 982 case 'C': 983 optC++; 984 break; 985 case 's': 986 sym = optarg; 987 break; 988 default: 989 (void) fprintf(stderr, "Usage: %s [-df]\n", argv[0]); 990 exit(1); 991 } 992 } 993 994 if (test_load_config(NULL, compilation, 995 "env", do_env, "env_group", do_env_group, NULL) < 0) { 996 exit(1); 997 } 998 999 while (optind < argc) { 1000 if (test_load_config(NULL, argv[optind++], 1001 "type", do_type, 1002 "value", do_value, 1003 "define", do_define, 1004 "func", do_func, 1005 NULL) < 0) { 1006 exit(1); 1007 } 1008 } 1009 1010 if (atexit(cleanup) != 0) { 1011 perror("atexit"); 1012 exit(1); 1013 } 1014 1015 if (custr_alloc(&st_custr) == -1) { 1016 perror("custr"); 1017 exit(1); 1018 } 1019 1020 if (mkworkdir() < 0) { 1021 perror("mkdir"); 1022 exit(1); 1023 } 1024 1025 find_compiler(); 1026 if (!optC) 1027 test_compile(); 1028 1029 exit(0); 1030 } 1031