Home | History | Annotate | Download | only in testsuite
      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