1 /* Pexecute test program, 2 Copyright (C) 2005 Free Software Foundation, Inc. 3 Written by Ian Lance Taylor <ian (at) airs.com>. 4 5 This file is part of GNU libiberty. 6 7 This program is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 2 of the License, or 10 (at your option) any later version. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this program; if not, write to the Free Software 19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 */ 21 22 #ifdef HAVE_CONFIG_H 23 #include "config.h" 24 #endif 25 #include "ansidecl.h" 26 #include "libiberty.h" 27 #include <stdio.h> 28 #include <signal.h> 29 #include <errno.h> 30 #ifdef HAVE_STRING_H 31 #include <string.h> 32 #endif 33 #include <sys/types.h> 34 #ifdef HAVE_STDLIB_H 35 #include <stdlib.h> 36 #endif 37 #ifdef HAVE_UNISTD_H 38 #include <unistd.h> 39 #endif 40 #ifdef HAVE_SYS_WAIT_H 41 #include <sys/wait.h> 42 #endif 43 #ifdef HAVE_SYS_TIME_H 44 #include <sys/time.h> 45 #endif 46 #ifdef HAVE_SYS_RESOURCE_H 47 #include <sys/resource.h> 48 #endif 49 50 #ifndef WIFSIGNALED 51 #define WIFSIGNALED(S) (((S) & 0xff) != 0 && ((S) & 0xff) != 0x7f) 52 #endif 53 #ifndef WTERMSIG 54 #define WTERMSIG(S) ((S) & 0x7f) 55 #endif 56 #ifndef WIFEXITED 57 #define WIFEXITED(S) (((S) & 0xff) == 0) 58 #endif 59 #ifndef WEXITSTATUS 60 #define WEXITSTATUS(S) (((S) & 0xff00) >> 8) 61 #endif 62 #ifndef WSTOPSIG 63 #define WSTOPSIG WEXITSTATUS 64 #endif 65 #ifndef WCOREDUMP 66 #define WCOREDUMP(S) ((S) & WCOREFLG) 67 #endif 68 #ifndef WCOREFLG 69 #define WCOREFLG 0200 70 #endif 71 72 #ifndef EXIT_SUCCESS 73 #define EXIT_SUCCESS 0 74 #endif 75 76 #ifndef EXIT_FAILURE 77 #define EXIT_FAILURE 1 78 #endif 79 80 /* When this program is run with no arguments, it runs some tests of 81 the libiberty pexecute functions. As a test program, it simply 82 invokes itself with various arguments. 83 84 argv[1]: 85 *empty string* Run tests, exit with success status 86 exit Exit success 87 error Exit error 88 abort Abort 89 echo Echo remaining arguments, exit success 90 echoerr Echo next arg to stdout, next to stderr, repeat 91 copy Copy stdin to stdout 92 write Write stdin to file named in next argument 93 */ 94 95 static void fatal_error (int, const char *, int) ATTRIBUTE_NORETURN; 96 static void error (int, const char *); 97 static void check_line (int, FILE *, const char *); 98 static void do_cmd (int, char **) ATTRIBUTE_NORETURN; 99 100 /* The number of errors we have seen. */ 101 102 static int error_count; 103 104 /* Print a fatal error and exit. LINE is the line number where we 105 detected the error, ERRMSG is the error message to print, and ERR 106 is 0 or an errno value to print. */ 107 108 static void 109 fatal_error (int line, const char *errmsg, int err) 110 { 111 fprintf (stderr, "test-pexecute:%d: %s", line, errmsg); 112 if (errno != 0) 113 fprintf (stderr, ": %s", xstrerror (err)); 114 fprintf (stderr, "\n"); 115 exit (EXIT_FAILURE); 116 } 117 118 #define FATAL_ERROR(ERRMSG, ERR) fatal_error (__LINE__, ERRMSG, ERR) 119 120 /* Print an error message and bump the error count. LINE is the line 121 number where we detected the error, ERRMSG is the error to 122 print. */ 123 124 static void 125 error (int line, const char *errmsg) 126 { 127 fprintf (stderr, "test-pexecute:%d: %s\n", line, errmsg); 128 ++error_count; 129 } 130 131 #define ERROR(ERRMSG) error (__LINE__, ERRMSG) 132 133 /* Check a line in a file. */ 134 135 static void 136 check_line (int line, FILE *e, const char *str) 137 { 138 const char *p; 139 int c; 140 char buf[1000]; 141 142 p = str; 143 while (1) 144 { 145 c = getc (e); 146 147 if (*p == '\0') 148 { 149 if (c != '\n') 150 { 151 snprintf (buf, sizeof buf, "got '%c' when expecting newline", c); 152 fatal_error (line, buf, 0); 153 } 154 c = getc (e); 155 if (c != EOF) 156 { 157 snprintf (buf, sizeof buf, "got '%c' when expecting EOF", c); 158 fatal_error (line, buf, 0); 159 } 160 return; 161 } 162 163 if (c != *p) 164 { 165 snprintf (buf, sizeof buf, "expected '%c', got '%c'", *p, c); 166 fatal_error (line, buf, 0); 167 } 168 169 ++p; 170 } 171 } 172 173 #define CHECK_LINE(E, STR) check_line (__LINE__, E, STR) 174 175 /* Main function for the pexecute tester. Run the tests. */ 176 177 int 178 main (int argc, char **argv) 179 { 180 int trace; 181 struct pex_obj *test_pex_tmp; 182 int test_pex_status; 183 FILE *test_pex_file; 184 struct pex_obj *pex1; 185 char *subargv[10]; 186 int status; 187 FILE *e; 188 int statuses[10]; 189 190 trace = 0; 191 if (argc > 1 && strcmp (argv[1], "-t") == 0) 192 { 193 trace = 1; 194 --argc; 195 ++argv; 196 } 197 198 if (argc > 1) 199 do_cmd (argc, argv); 200 201 #define TEST_PEX_INIT(FLAGS, TEMPBASE) \ 202 (((test_pex_tmp = pex_init (FLAGS, "test-pexecute", TEMPBASE)) \ 203 != NULL) \ 204 ? test_pex_tmp \ 205 : (FATAL_ERROR ("pex_init failed", 0), NULL)) 206 207 #define TEST_PEX_RUN(PEXOBJ, FLAGS, EXECUTABLE, ARGV, OUTNAME, ERRNAME) \ 208 do \ 209 { \ 210 int err; \ 211 const char *pex_run_err; \ 212 if (trace) \ 213 fprintf (stderr, "Line %d: running %s %s\n", \ 214 __LINE__, EXECUTABLE, ARGV[0]); \ 215 pex_run_err = pex_run (PEXOBJ, FLAGS, EXECUTABLE, ARGV, OUTNAME, \ 216 ERRNAME, &err); \ 217 if (pex_run_err != NULL) \ 218 FATAL_ERROR (pex_run_err, err); \ 219 } \ 220 while (0) 221 222 #define TEST_PEX_GET_STATUS_1(PEXOBJ) \ 223 (pex_get_status (PEXOBJ, 1, &test_pex_status) \ 224 ? test_pex_status \ 225 : (FATAL_ERROR ("pex_get_status failed", errno), 1)) 226 227 #define TEST_PEX_GET_STATUS(PEXOBJ, COUNT, VECTOR) \ 228 do \ 229 { \ 230 if (!pex_get_status (PEXOBJ, COUNT, VECTOR)) \ 231 FATAL_ERROR ("pex_get_status failed", errno); \ 232 } \ 233 while (0) 234 235 #define TEST_PEX_READ_OUTPUT(PEXOBJ) \ 236 ((test_pex_file = pex_read_output (PEXOBJ, 0)) != NULL \ 237 ? test_pex_file \ 238 : (FATAL_ERROR ("pex_read_output failed", errno), NULL)) 239 240 remove ("temp.x"); 241 remove ("temp.y"); 242 243 memset (subargv, 0, sizeof subargv); 244 245 subargv[0] = "./test-pexecute"; 246 247 pex1 = TEST_PEX_INIT (PEX_USE_PIPES, NULL); 248 subargv[1] = "exit"; 249 subargv[2] = NULL; 250 TEST_PEX_RUN (pex1, PEX_LAST, "./test-pexecute", subargv, NULL, NULL); 251 status = TEST_PEX_GET_STATUS_1 (pex1); 252 if (!WIFEXITED (status) || WEXITSTATUS (status) != EXIT_SUCCESS) 253 ERROR ("exit failed"); 254 pex_free (pex1); 255 256 pex1 = TEST_PEX_INIT (PEX_USE_PIPES, NULL); 257 subargv[1] = "error"; 258 subargv[2] = NULL; 259 TEST_PEX_RUN (pex1, PEX_LAST, "./test-pexecute", subargv, NULL, NULL); 260 status = TEST_PEX_GET_STATUS_1 (pex1); 261 if (!WIFEXITED (status) || WEXITSTATUS (status) != EXIT_FAILURE) 262 ERROR ("error test failed"); 263 pex_free (pex1); 264 265 /* We redirect stderr to a file to avoid an error message which is 266 printed on mingw32 when the child calls abort. */ 267 pex1 = TEST_PEX_INIT (PEX_USE_PIPES, NULL); 268 subargv[1] = "abort"; 269 subargv[2] = NULL; 270 TEST_PEX_RUN (pex1, PEX_LAST, "./test-pexecute", subargv, NULL, "temp.z"); 271 status = TEST_PEX_GET_STATUS_1 (pex1); 272 if (!WIFSIGNALED (status) || WTERMSIG (status) != SIGABRT) 273 ERROR ("abort failed"); 274 pex_free (pex1); 275 remove ("temp.z"); 276 277 pex1 = TEST_PEX_INIT (PEX_USE_PIPES, "temp"); 278 subargv[1] = "echo"; 279 subargv[2] = "foo"; 280 subargv[3] = NULL; 281 TEST_PEX_RUN (pex1, 0, "./test-pexecute", subargv, NULL, NULL); 282 e = TEST_PEX_READ_OUTPUT (pex1); 283 CHECK_LINE (e, "foo"); 284 if (TEST_PEX_GET_STATUS_1 (pex1) != 0) 285 ERROR ("echo exit status failed"); 286 pex_free (pex1); 287 288 pex1 = TEST_PEX_INIT (PEX_USE_PIPES, "temp"); 289 subargv[1] = "echo"; 290 subargv[2] = "bar"; 291 subargv[3] = NULL; 292 TEST_PEX_RUN (pex1, PEX_SUFFIX, "./test-pexecute", subargv, ".x", NULL); 293 subargv[1] = "copy"; 294 subargv[2] = NULL; 295 TEST_PEX_RUN (pex1, PEX_SUFFIX, "./test-pexecute", subargv, ".y", NULL); 296 e = TEST_PEX_READ_OUTPUT (pex1); 297 CHECK_LINE (e, "bar"); 298 TEST_PEX_GET_STATUS (pex1, 2, statuses); 299 if (!WIFEXITED (statuses[0]) || WEXITSTATUS (statuses[0]) != EXIT_SUCCESS 300 || !WIFEXITED (statuses[1]) || WEXITSTATUS (statuses[1]) != EXIT_SUCCESS) 301 ERROR ("copy exit status failed"); 302 pex_free (pex1); 303 if (fopen ("temp.x", "r") != NULL || fopen ("temp.y", "r") != NULL) 304 ERROR ("temporary files exist"); 305 306 pex1 = TEST_PEX_INIT (0, "temp"); 307 subargv[1] = "echo"; 308 subargv[2] = "bar"; 309 subargv[3] = NULL; 310 TEST_PEX_RUN (pex1, PEX_SUFFIX, "./test-pexecute", subargv, ".x", NULL); 311 subargv[1] = "copy"; 312 subargv[2] = NULL; 313 TEST_PEX_RUN (pex1, PEX_SUFFIX, "./test-pexecute", subargv, ".y", NULL); 314 e = TEST_PEX_READ_OUTPUT (pex1); 315 CHECK_LINE (e, "bar"); 316 TEST_PEX_GET_STATUS (pex1, 2, statuses); 317 if (!WIFEXITED (statuses[0]) || WEXITSTATUS (statuses[0]) != EXIT_SUCCESS 318 || !WIFEXITED (statuses[1]) || WEXITSTATUS (statuses[1]) != EXIT_SUCCESS) 319 ERROR ("copy exit status failed"); 320 pex_free (pex1); 321 if (fopen ("temp.x", "r") != NULL || fopen ("temp.y", "r") != NULL) 322 ERROR ("temporary files exist"); 323 324 pex1 = TEST_PEX_INIT (PEX_SAVE_TEMPS, "temp"); 325 subargv[1] = "echo"; 326 subargv[2] = "quux"; 327 subargv[3] = NULL; 328 TEST_PEX_RUN (pex1, PEX_SUFFIX, "./test-pexecute", subargv, ".x", NULL); 329 subargv[1] = "copy"; 330 subargv[2] = NULL; 331 TEST_PEX_RUN (pex1, PEX_SUFFIX, "./test-pexecute", subargv, ".y", NULL); 332 e = TEST_PEX_READ_OUTPUT (pex1); 333 CHECK_LINE (e, "quux"); 334 TEST_PEX_GET_STATUS (pex1, 2, statuses); 335 if (!WIFEXITED (statuses[0]) || WEXITSTATUS (statuses[0]) != EXIT_SUCCESS 336 || !WIFEXITED (statuses[1]) || WEXITSTATUS (statuses[1]) != EXIT_SUCCESS) 337 ERROR ("copy temp exit status failed"); 338 e = fopen ("temp.x", "r"); 339 if (e == NULL) 340 FATAL_ERROR ("fopen temp.x failed in copy temp", errno); 341 CHECK_LINE (e, "quux"); 342 fclose (e); 343 e = fopen ("temp.y", "r"); 344 if (e == NULL) 345 FATAL_ERROR ("fopen temp.y failed in copy temp", errno); 346 CHECK_LINE (e, "quux"); 347 fclose (e); 348 pex_free (pex1); 349 remove ("temp.x"); 350 remove ("temp.y"); 351 352 pex1 = TEST_PEX_INIT (PEX_USE_PIPES, "temp"); 353 subargv[1] = "echoerr"; 354 subargv[2] = "one"; 355 subargv[3] = "two"; 356 subargv[4] = NULL; 357 TEST_PEX_RUN (pex1, PEX_SUFFIX, "./test-pexecute", subargv, ".x", "temp2.x"); 358 subargv[1] = "write"; 359 subargv[2] = "temp2.y"; 360 subargv[3] = NULL; 361 TEST_PEX_RUN (pex1, PEX_SUFFIX, "./test-pexecute", subargv, ".y", NULL); 362 TEST_PEX_GET_STATUS (pex1, 2, statuses); 363 if (!WIFEXITED (statuses[0]) || WEXITSTATUS (statuses[0]) != EXIT_SUCCESS 364 || !WIFEXITED (statuses[1]) || WEXITSTATUS (statuses[1]) != EXIT_SUCCESS) 365 ERROR ("echoerr exit status failed"); 366 pex_free (pex1); 367 if (fopen ("temp.x", "r") != NULL || fopen ("temp.y", "r") != NULL) 368 ERROR ("temporary files exist"); 369 e = fopen ("temp2.x", "r"); 370 if (e == NULL) 371 FATAL_ERROR ("fopen temp2.x failed in echoerr", errno); 372 CHECK_LINE (e, "two"); 373 fclose (e); 374 e = fopen ("temp2.y", "r"); 375 if (e == NULL) 376 FATAL_ERROR ("fopen temp2.y failed in echoerr", errno); 377 CHECK_LINE (e, "one"); 378 fclose (e); 379 remove ("temp2.x"); 380 remove ("temp2.y"); 381 382 /* Test the old pexecute interface. */ 383 { 384 int pid1, pid2; 385 char *errmsg_fmt; 386 char *errmsg_arg; 387 char errbuf1[1000]; 388 char errbuf2[1000]; 389 390 subargv[1] = "echo"; 391 subargv[2] = "oldpexecute"; 392 subargv[3] = NULL; 393 pid1 = pexecute ("./test-pexecute", subargv, "test-pexecute", "temp", 394 &errmsg_fmt, &errmsg_arg, PEXECUTE_FIRST); 395 if (pid1 < 0) 396 { 397 snprintf (errbuf1, sizeof errbuf1, errmsg_fmt, errmsg_arg); 398 snprintf (errbuf2, sizeof errbuf2, "pexecute 1 failed: %s", errbuf1); 399 FATAL_ERROR (errbuf2, 0); 400 } 401 402 subargv[1] = "write"; 403 subargv[2] = "temp.y"; 404 subargv[3] = NULL; 405 pid2 = pexecute ("./test-pexecute", subargv, "test-pexecute", "temp", 406 &errmsg_fmt, &errmsg_arg, PEXECUTE_LAST); 407 if (pid2 < 0) 408 { 409 snprintf (errbuf1, sizeof errbuf1, errmsg_fmt, errmsg_arg); 410 snprintf (errbuf2, sizeof errbuf2, "pexecute 2 failed: %s", errbuf1); 411 FATAL_ERROR (errbuf2, 0); 412 } 413 414 if (pwait (pid1, &status, 0) < 0) 415 FATAL_ERROR ("write pwait 1 failed", errno); 416 if (!WIFEXITED (status) || WEXITSTATUS (status) != EXIT_SUCCESS) 417 ERROR ("write exit status 1 failed"); 418 419 if (pwait (pid2, &status, 0) < 0) 420 FATAL_ERROR ("write pwait 1 failed", errno); 421 if (!WIFEXITED (status) || WEXITSTATUS (status) != EXIT_SUCCESS) 422 ERROR ("write exit status 2 failed"); 423 424 e = fopen ("temp.y", "r"); 425 if (e == NULL) 426 FATAL_ERROR ("fopen temp.y failed in copy temp", errno); 427 CHECK_LINE (e, "oldpexecute"); 428 fclose (e); 429 430 remove ("temp.y"); 431 } 432 433 if (trace) 434 fprintf (stderr, "Exiting with status %d\n", error_count); 435 436 return error_count; 437 } 438 439 /* Execute one of the special testing commands. */ 440 441 static void 442 do_cmd (int argc, char **argv) 443 { 444 const char *s; 445 446 /* Try to prevent generating a core dump. */ 447 #ifdef RLIMIT_CORE 448 { 449 struct rlimit r; 450 451 r.rlim_cur = 0; 452 r.rlim_max = 0; 453 setrlimit (RLIMIT_CORE, &r); 454 } 455 #endif 456 457 s = argv[1]; 458 if (strcmp (s, "exit") == 0) 459 exit (EXIT_SUCCESS); 460 else if (strcmp (s, "echo") == 0) 461 { 462 int i; 463 464 for (i = 2; i < argc; ++i) 465 { 466 if (i > 2) 467 putchar (' '); 468 fputs (argv[i], stdout); 469 } 470 putchar ('\n'); 471 exit (EXIT_SUCCESS); 472 } 473 else if (strcmp (s, "echoerr") == 0) 474 { 475 int i; 476 477 for (i = 2; i < argc; ++i) 478 { 479 if (i > 3) 480 putc (' ', (i & 1) == 0 ? stdout : stderr); 481 fputs (argv[i], (i & 1) == 0 ? stdout : stderr); 482 } 483 putc ('\n', stdout); 484 putc ('\n', stderr); 485 exit (EXIT_SUCCESS); 486 } 487 else if (strcmp (s, "error") == 0) 488 exit (EXIT_FAILURE); 489 else if (strcmp (s, "abort") == 0) 490 abort (); 491 else if (strcmp (s, "copy") == 0) 492 { 493 int c; 494 495 while ((c = getchar ()) != EOF) 496 putchar (c); 497 exit (EXIT_SUCCESS); 498 } 499 else if (strcmp (s, "write") == 0) 500 { 501 FILE *e; 502 int c; 503 504 e = fopen (argv[2], "w"); 505 if (e == NULL) 506 FATAL_ERROR ("fopen for write failed", errno); 507 while ((c = getchar ()) != EOF) 508 putc (c, e); 509 if (fclose (e) != 0) 510 FATAL_ERROR ("fclose for write failed", errno); 511 exit (EXIT_SUCCESS); 512 } 513 else 514 { 515 char buf[1000]; 516 517 snprintf (buf, sizeof buf, "unrecognized command %s", argv[1]); 518 FATAL_ERROR (buf, 0); 519 } 520 521 exit (EXIT_FAILURE); 522 } 523