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