Back to index

cell-binutils  2.17cvs20070401
test-pexecute.c
Go to the documentation of this file.
00001 /* Pexecute test program,
00002    Copyright (C) 2005 Free Software Foundation, Inc.
00003    Written by Ian Lance Taylor <ian@airs.com>.
00004 
00005    This file is part of GNU libiberty.
00006 
00007    This program is free software; you can redistribute it and/or modify
00008    it under the terms of the GNU General Public License as published by
00009    the Free Software Foundation; either version 2 of the License, or
00010    (at your option) any later version.
00011 
00012    This program is distributed in the hope that it will be useful,
00013    but WITHOUT ANY WARRANTY; without even the implied warranty of
00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015    GNU General Public License for more details.
00016 
00017    You should have received a copy of the GNU General Public License
00018    along with this program; if not, write to the Free Software
00019    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 
00020 */
00021 
00022 #ifdef HAVE_CONFIG_H
00023 #include "config.h"
00024 #endif
00025 #include "ansidecl.h"
00026 #include "libiberty.h"
00027 #include <stdio.h>
00028 #include <signal.h>
00029 #include <errno.h>
00030 #ifdef HAVE_STRING_H
00031 #include <string.h>
00032 #endif
00033 #include <sys/types.h>
00034 #ifdef HAVE_STDLIB_H
00035 #include <stdlib.h>
00036 #endif
00037 #ifdef HAVE_UNISTD_H
00038 #include <unistd.h>
00039 #endif
00040 #ifdef HAVE_SYS_WAIT_H
00041 #include <sys/wait.h>
00042 #endif
00043 #ifdef HAVE_SYS_TIME_H
00044 #include <sys/time.h>
00045 #endif
00046 #ifdef HAVE_SYS_RESOURCE_H
00047 #include <sys/resource.h>
00048 #endif
00049 
00050 #ifndef WIFSIGNALED
00051 #define WIFSIGNALED(S) (((S) & 0xff) != 0 && ((S) & 0xff) != 0x7f)
00052 #endif
00053 #ifndef WTERMSIG
00054 #define WTERMSIG(S) ((S) & 0x7f)
00055 #endif
00056 #ifndef WIFEXITED
00057 #define WIFEXITED(S) (((S) & 0xff) == 0)
00058 #endif
00059 #ifndef WEXITSTATUS
00060 #define WEXITSTATUS(S) (((S) & 0xff00) >> 8)
00061 #endif
00062 #ifndef WSTOPSIG
00063 #define WSTOPSIG WEXITSTATUS
00064 #endif
00065 #ifndef WCOREDUMP
00066 #define WCOREDUMP(S) ((S) & WCOREFLG)
00067 #endif
00068 #ifndef WCOREFLG
00069 #define WCOREFLG 0200
00070 #endif
00071 
00072 #ifndef EXIT_SUCCESS
00073 #define EXIT_SUCCESS 0
00074 #endif
00075 
00076 #ifndef EXIT_FAILURE
00077 #define EXIT_FAILURE 1
00078 #endif
00079 
00080 /* When this program is run with no arguments, it runs some tests of
00081    the libiberty pexecute functions.  As a test program, it simply
00082    invokes itself with various arguments.
00083 
00084    argv[1]:
00085      *empty string*      Run tests, exit with success status
00086      exit                Exit success
00087      error               Exit error
00088      abort               Abort
00089      echo                Echo remaining arguments, exit success
00090      echoerr             Echo next arg to stdout, next to stderr, repeat
00091      copy                Copy stdin to stdout
00092      write               Write stdin to file named in next argument
00093 */
00094 
00095 static void fatal_error (int, const char *, int) ATTRIBUTE_NORETURN;
00096 static void error (int, const char *);
00097 static void check_line (int, FILE *, const char *);
00098 static void do_cmd (int, char **) ATTRIBUTE_NORETURN;
00099 
00100 /* The number of errors we have seen.  */
00101 
00102 static int error_count;
00103 
00104 /* Print a fatal error and exit.  LINE is the line number where we
00105    detected the error, ERRMSG is the error message to print, and ERR
00106    is 0 or an errno value to print.  */
00107 
00108 static void
00109 fatal_error (int line, const char *errmsg, int err)
00110 {
00111   fprintf (stderr, "test-pexecute:%d: %s", line, errmsg);
00112   if (errno != 0)
00113     fprintf (stderr, ": %s", xstrerror (err));
00114   fprintf (stderr, "\n");
00115   exit (EXIT_FAILURE);
00116 }
00117 
00118 #define FATAL_ERROR(ERRMSG, ERR) fatal_error (__LINE__, ERRMSG, ERR)
00119 
00120 /* Print an error message and bump the error count.  LINE is the line
00121    number where we detected the error, ERRMSG is the error to
00122    print.  */
00123 
00124 static void
00125 error (int line, const char *errmsg)
00126 {
00127   fprintf (stderr, "test-pexecute:%d: %s\n", line, errmsg);
00128   ++error_count;
00129 }
00130 
00131 #define ERROR(ERRMSG) error (__LINE__, ERRMSG)
00132 
00133 /* Check a line in a file.  */
00134 
00135 static void
00136 check_line (int line, FILE *e, const char *str)
00137 {
00138   const char *p;
00139   int c;
00140   char buf[1000];
00141 
00142   p = str;
00143   while (1)
00144     {
00145       c = getc (e);
00146 
00147       if (*p == '\0')
00148        {
00149          if (c != '\n')
00150            {
00151              snprintf (buf, sizeof buf, "got '%c' when expecting newline", c);
00152              fatal_error (line, buf, 0);
00153            }
00154          c = getc (e);
00155          if (c != EOF)
00156            {
00157              snprintf (buf, sizeof buf, "got '%c' when expecting EOF", c);
00158              fatal_error (line, buf, 0);
00159            }
00160          return;
00161        }
00162 
00163       if (c != *p)
00164        {
00165          snprintf (buf, sizeof buf, "expected '%c', got '%c'", *p, c);
00166          fatal_error (line, buf, 0);
00167        }
00168 
00169       ++p;
00170     }
00171 }
00172 
00173 #define CHECK_LINE(E, STR) check_line (__LINE__, E, STR)
00174 
00175 /* Main function for the pexecute tester.  Run the tests.  */
00176 
00177 int
00178 main (int argc, char **argv)
00179 {
00180   int trace;
00181   struct pex_obj *test_pex_tmp;
00182   int test_pex_status;
00183   FILE *test_pex_file;
00184   struct pex_obj *pex1;
00185   char *subargv[10];
00186   int status;
00187   FILE *e;
00188   int statuses[10];
00189 
00190   trace = 0;
00191   if (argc > 1 && strcmp (argv[1], "-t") == 0)
00192     {
00193       trace = 1;
00194       --argc;
00195       ++argv;
00196     }
00197 
00198   if (argc > 1)
00199     do_cmd (argc, argv);
00200 
00201 #define TEST_PEX_INIT(FLAGS, TEMPBASE)                                \
00202   (((test_pex_tmp = pex_init (FLAGS, "test-pexecute", TEMPBASE))      \
00203     != NULL)                                                   \
00204    ? test_pex_tmp                                              \
00205    : (FATAL_ERROR ("pex_init failed", 0), NULL))
00206 
00207 #define TEST_PEX_RUN(PEXOBJ, FLAGS, EXECUTABLE, ARGV, OUTNAME, ERRNAME)      \
00208   do                                                           \
00209     {                                                          \
00210       int err;                                                        \
00211       const char *pex_run_err;                                        \
00212       if (trace)                                               \
00213        fprintf (stderr, "Line %d: running %s %s\n",                   \
00214                __LINE__, EXECUTABLE, ARGV[0]);                 \
00215       pex_run_err = pex_run (PEXOBJ, FLAGS, EXECUTABLE, ARGV, OUTNAME,       \
00216                           ERRNAME, &err);                      \
00217       if (pex_run_err != NULL)                                        \
00218        FATAL_ERROR (pex_run_err, err);                                \
00219     }                                                          \
00220   while (0)
00221 
00222 #define TEST_PEX_GET_STATUS_1(PEXOBJ)                                 \
00223   (pex_get_status (PEXOBJ, 1, &test_pex_status)                       \
00224    ? test_pex_status                                           \
00225    : (FATAL_ERROR ("pex_get_status failed", errno), 1))
00226 
00227 #define TEST_PEX_GET_STATUS(PEXOBJ, COUNT, VECTOR)                    \
00228   do                                                           \
00229     {                                                          \
00230       if (!pex_get_status (PEXOBJ, COUNT, VECTOR))                    \
00231        FATAL_ERROR ("pex_get_status failed", errno);                  \
00232     }                                                          \
00233   while (0)
00234 
00235 #define TEST_PEX_READ_OUTPUT(PEXOBJ)                                  \
00236   ((test_pex_file = pex_read_output (PEXOBJ, 0)) != NULL              \
00237    ? test_pex_file                                             \
00238    : (FATAL_ERROR ("pex_read_output failed", errno), NULL))
00239 
00240   remove ("temp.x");
00241   remove ("temp.y");
00242 
00243   memset (subargv, 0, sizeof subargv);
00244 
00245   subargv[0] = "./test-pexecute";
00246 
00247   pex1 = TEST_PEX_INIT (PEX_USE_PIPES, NULL);
00248   subargv[1] = "exit";
00249   subargv[2] = NULL;
00250   TEST_PEX_RUN (pex1, PEX_LAST, "./test-pexecute", subargv, NULL, NULL);
00251   status = TEST_PEX_GET_STATUS_1 (pex1);
00252   if (!WIFEXITED (status) || WEXITSTATUS (status) != EXIT_SUCCESS)
00253     ERROR ("exit failed");
00254   pex_free (pex1);
00255 
00256   pex1 = TEST_PEX_INIT (PEX_USE_PIPES, NULL);
00257   subargv[1] = "error";
00258   subargv[2] = NULL;
00259   TEST_PEX_RUN (pex1, PEX_LAST, "./test-pexecute", subargv, NULL, NULL);
00260   status = TEST_PEX_GET_STATUS_1 (pex1);
00261   if (!WIFEXITED (status) || WEXITSTATUS (status) != EXIT_FAILURE)
00262     ERROR ("error test failed");
00263   pex_free (pex1);
00264 
00265   /* We redirect stderr to a file to avoid an error message which is
00266      printed on mingw32 when the child calls abort.  */
00267   pex1 = TEST_PEX_INIT (PEX_USE_PIPES, NULL);
00268   subargv[1] = "abort";
00269   subargv[2] = NULL;
00270   TEST_PEX_RUN (pex1, PEX_LAST, "./test-pexecute", subargv, NULL, "temp.z");
00271   status = TEST_PEX_GET_STATUS_1 (pex1);
00272   if (!WIFSIGNALED (status) || WTERMSIG (status) != SIGABRT)
00273     ERROR ("abort failed");
00274   pex_free (pex1);
00275   remove ("temp.z");
00276 
00277   pex1 = TEST_PEX_INIT (PEX_USE_PIPES, "temp");
00278   subargv[1] = "echo";
00279   subargv[2] = "foo";
00280   subargv[3] = NULL;
00281   TEST_PEX_RUN (pex1, 0, "./test-pexecute", subargv, NULL, NULL);
00282   e = TEST_PEX_READ_OUTPUT (pex1);
00283   CHECK_LINE (e, "foo");
00284   if (TEST_PEX_GET_STATUS_1 (pex1) != 0)
00285     ERROR ("echo exit status failed");
00286   pex_free (pex1);
00287 
00288   pex1 = TEST_PEX_INIT (PEX_USE_PIPES, "temp");
00289   subargv[1] = "echo";
00290   subargv[2] = "bar";
00291   subargv[3] = NULL;
00292   TEST_PEX_RUN (pex1, PEX_SUFFIX, "./test-pexecute", subargv, ".x", NULL);
00293   subargv[1] = "copy";
00294   subargv[2] = NULL;
00295   TEST_PEX_RUN (pex1, PEX_SUFFIX, "./test-pexecute", subargv, ".y", NULL);
00296   e = TEST_PEX_READ_OUTPUT (pex1);
00297   CHECK_LINE (e, "bar");
00298   TEST_PEX_GET_STATUS (pex1, 2, statuses);
00299   if (!WIFEXITED (statuses[0]) || WEXITSTATUS (statuses[0]) != EXIT_SUCCESS
00300       || !WIFEXITED (statuses[1]) || WEXITSTATUS (statuses[1]) != EXIT_SUCCESS)
00301     ERROR ("copy exit status failed");
00302   pex_free (pex1);
00303   if (fopen ("temp.x", "r") != NULL || fopen ("temp.y", "r") != NULL)
00304     ERROR ("temporary files exist");
00305 
00306   pex1 = TEST_PEX_INIT (0, "temp");
00307   subargv[1] = "echo";
00308   subargv[2] = "bar";
00309   subargv[3] = NULL;
00310   TEST_PEX_RUN (pex1, PEX_SUFFIX, "./test-pexecute", subargv, ".x", NULL);
00311   subargv[1] = "copy";
00312   subargv[2] = NULL;
00313   TEST_PEX_RUN (pex1, PEX_SUFFIX, "./test-pexecute", subargv, ".y", NULL);
00314   e = TEST_PEX_READ_OUTPUT (pex1);
00315   CHECK_LINE (e, "bar");
00316   TEST_PEX_GET_STATUS (pex1, 2, statuses);
00317   if (!WIFEXITED (statuses[0]) || WEXITSTATUS (statuses[0]) != EXIT_SUCCESS
00318       || !WIFEXITED (statuses[1]) || WEXITSTATUS (statuses[1]) != EXIT_SUCCESS)
00319     ERROR ("copy exit status failed");
00320   pex_free (pex1);
00321   if (fopen ("temp.x", "r") != NULL || fopen ("temp.y", "r") != NULL)
00322     ERROR ("temporary files exist");
00323 
00324   pex1 = TEST_PEX_INIT (PEX_SAVE_TEMPS, "temp");
00325   subargv[1] = "echo";
00326   subargv[2] = "quux";
00327   subargv[3] = NULL;
00328   TEST_PEX_RUN (pex1, PEX_SUFFIX, "./test-pexecute", subargv, ".x", NULL);
00329   subargv[1] = "copy";
00330   subargv[2] = NULL;
00331   TEST_PEX_RUN (pex1, PEX_SUFFIX, "./test-pexecute", subargv, ".y", NULL);
00332   e = TEST_PEX_READ_OUTPUT (pex1);
00333   CHECK_LINE (e, "quux");
00334   TEST_PEX_GET_STATUS (pex1, 2, statuses);
00335   if (!WIFEXITED (statuses[0]) || WEXITSTATUS (statuses[0]) != EXIT_SUCCESS
00336       || !WIFEXITED (statuses[1]) || WEXITSTATUS (statuses[1]) != EXIT_SUCCESS)
00337     ERROR ("copy temp exit status failed");
00338   e = fopen ("temp.x", "r");
00339   if (e == NULL)
00340     FATAL_ERROR ("fopen temp.x failed in copy temp", errno);
00341   CHECK_LINE (e, "quux");
00342   fclose (e);
00343   e = fopen ("temp.y", "r");
00344   if (e == NULL)
00345     FATAL_ERROR ("fopen temp.y failed in copy temp", errno);
00346   CHECK_LINE (e, "quux");
00347   fclose (e);
00348   pex_free (pex1);
00349   remove ("temp.x");
00350   remove ("temp.y");
00351 
00352   pex1 = TEST_PEX_INIT (PEX_USE_PIPES, "temp");
00353   subargv[1] = "echoerr";
00354   subargv[2] = "one";
00355   subargv[3] = "two";
00356   subargv[4] = NULL;
00357   TEST_PEX_RUN (pex1, PEX_SUFFIX, "./test-pexecute", subargv, ".x", "temp2.x");
00358   subargv[1] = "write";
00359   subargv[2] = "temp2.y";
00360   subargv[3] = NULL;
00361   TEST_PEX_RUN (pex1, PEX_SUFFIX, "./test-pexecute", subargv, ".y", NULL);
00362   TEST_PEX_GET_STATUS (pex1, 2, statuses);
00363   if (!WIFEXITED (statuses[0]) || WEXITSTATUS (statuses[0]) != EXIT_SUCCESS
00364       || !WIFEXITED (statuses[1]) || WEXITSTATUS (statuses[1]) != EXIT_SUCCESS)
00365     ERROR ("echoerr exit status failed");
00366   pex_free (pex1);
00367   if (fopen ("temp.x", "r") != NULL || fopen ("temp.y", "r") != NULL)
00368     ERROR ("temporary files exist");
00369   e = fopen ("temp2.x", "r");
00370   if (e == NULL)
00371     FATAL_ERROR ("fopen temp2.x failed in echoerr", errno);
00372   CHECK_LINE (e, "two");
00373   fclose (e);
00374   e = fopen ("temp2.y", "r");
00375   if (e == NULL)
00376     FATAL_ERROR ("fopen temp2.y failed in echoerr", errno);
00377   CHECK_LINE (e, "one");
00378   fclose (e);
00379   remove ("temp2.x");
00380   remove ("temp2.y");
00381 
00382   /* Test the old pexecute interface.  */
00383   {
00384     int pid1, pid2;
00385     char *errmsg_fmt;
00386     char *errmsg_arg;
00387     char errbuf1[1000];
00388     char errbuf2[1000];
00389 
00390     subargv[1] = "echo";
00391     subargv[2] = "oldpexecute";
00392     subargv[3] = NULL;
00393     pid1 = pexecute ("./test-pexecute", subargv, "test-pexecute", "temp",
00394                    &errmsg_fmt, &errmsg_arg, PEXECUTE_FIRST);
00395     if (pid1 < 0)
00396       {
00397        snprintf (errbuf1, sizeof errbuf1, errmsg_fmt, errmsg_arg);
00398        snprintf (errbuf2, sizeof errbuf2, "pexecute 1 failed: %s", errbuf1);
00399        FATAL_ERROR (errbuf2, 0);
00400       }
00401 
00402     subargv[1] = "write";
00403     subargv[2] = "temp.y";
00404     subargv[3] = NULL;
00405     pid2 = pexecute ("./test-pexecute", subargv, "test-pexecute", "temp",
00406                    &errmsg_fmt, &errmsg_arg, PEXECUTE_LAST);
00407     if (pid2 < 0)
00408       {
00409        snprintf (errbuf1, sizeof errbuf1, errmsg_fmt, errmsg_arg);
00410        snprintf (errbuf2, sizeof errbuf2, "pexecute 2 failed: %s", errbuf1);
00411        FATAL_ERROR (errbuf2, 0);
00412       }
00413 
00414     if (pwait (pid1, &status, 0) < 0)
00415       FATAL_ERROR ("write pwait 1 failed", errno);
00416     if (!WIFEXITED (status) || WEXITSTATUS (status) != EXIT_SUCCESS)
00417       ERROR ("write exit status 1 failed");
00418 
00419     if (pwait (pid2, &status, 0) < 0)
00420       FATAL_ERROR ("write pwait 1 failed", errno);
00421     if (!WIFEXITED (status) || WEXITSTATUS (status) != EXIT_SUCCESS)
00422       ERROR ("write exit status 2 failed");
00423 
00424     e = fopen ("temp.y", "r");
00425     if (e == NULL)
00426       FATAL_ERROR ("fopen temp.y failed in copy temp", errno);
00427     CHECK_LINE (e, "oldpexecute");
00428     fclose (e);
00429 
00430     remove ("temp.y");
00431   }
00432 
00433   if (trace)
00434     fprintf (stderr, "Exiting with status %d\n", error_count);
00435 
00436   return error_count;
00437 }
00438 
00439 /* Execute one of the special testing commands.  */
00440 
00441 static void
00442 do_cmd (int argc, char **argv)
00443 {
00444   const char *s;
00445 
00446   /* Try to prevent generating a core dump.  */
00447 #ifdef RLIMIT_CORE
00448  {
00449    struct rlimit r;
00450 
00451    r.rlim_cur = 0;
00452    r.rlim_max = 0;
00453    setrlimit (RLIMIT_CORE, &r);
00454  }
00455 #endif
00456 
00457   s = argv[1];
00458   if (strcmp (s, "exit") == 0)
00459     exit (EXIT_SUCCESS);
00460   else if (strcmp (s, "echo") == 0)
00461     {
00462       int i;
00463 
00464       for (i = 2; i < argc; ++i)
00465        {
00466          if (i > 2)
00467            putchar (' ');
00468          fputs (argv[i], stdout);
00469        }
00470       putchar ('\n');
00471       exit (EXIT_SUCCESS);
00472     }
00473   else if (strcmp (s, "echoerr") == 0)
00474     {
00475       int i;
00476 
00477       for (i = 2; i < argc; ++i)
00478        {
00479          if (i > 3)
00480            putc (' ', (i & 1) == 0 ? stdout : stderr);
00481          fputs (argv[i], (i & 1) == 0 ? stdout : stderr);
00482        }
00483       putc ('\n', stdout);
00484       putc ('\n', stderr);
00485       exit (EXIT_SUCCESS);
00486     }
00487   else if (strcmp (s, "error") == 0)
00488     exit (EXIT_FAILURE);
00489   else if (strcmp (s, "abort") == 0)
00490     abort ();
00491   else if (strcmp (s, "copy") == 0)
00492     {
00493       int c;
00494 
00495       while ((c = getchar ()) != EOF)
00496        putchar (c);
00497       exit (EXIT_SUCCESS);
00498     }
00499   else if (strcmp (s, "write") == 0)
00500     {
00501       FILE *e;
00502       int c;
00503 
00504       e = fopen (argv[2], "w");
00505       if (e == NULL)
00506        FATAL_ERROR ("fopen for write failed", errno);
00507       while ((c = getchar ()) != EOF)
00508        putc (c, e);
00509       if (fclose (e) != 0)
00510        FATAL_ERROR ("fclose for write failed", errno);
00511       exit (EXIT_SUCCESS);
00512     }
00513   else
00514     {
00515       char buf[1000];
00516 
00517       snprintf (buf, sizeof buf, "unrecognized command %s", argv[1]);
00518       FATAL_ERROR (buf, 0);
00519     }
00520 
00521   exit (EXIT_FAILURE);
00522 }