Home | History | Annotate | Line # | Download | only in testsuite
test-pexecute.c revision 1.1.1.2
      1 /* Pexecute test program,
      2    Copyright (C) 2005-2017 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   /* Check empty parameters don't get lost.  */
    289   pex1 = TEST_PEX_INIT (PEX_USE_PIPES, "temp");
    290   subargv[1] = "echo";
    291   subargv[2] = "foo";
    292   subargv[3] = "";
    293   subargv[4] = "bar";
    294   subargv[5] = NULL;
    295   TEST_PEX_RUN (pex1, 0, "./test-pexecute", subargv, NULL, NULL);
    296   e = TEST_PEX_READ_OUTPUT (pex1);
    297   CHECK_LINE (e, "foo  bar");  /* Two spaces!  */
    298   if (TEST_PEX_GET_STATUS_1 (pex1) != 0)
    299     ERROR ("echo exit status failed");
    300   pex_free (pex1);
    301 
    302   pex1 = TEST_PEX_INIT (PEX_USE_PIPES, "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 (0, "temp");
    321   subargv[1] = "echo";
    322   subargv[2] = "bar";
    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, "bar");
    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 exit status failed");
    334   pex_free (pex1);
    335   if (fopen ("temp.x", "r") != NULL || fopen ("temp.y", "r") != NULL)
    336     ERROR ("temporary files exist");
    337 
    338   pex1 = TEST_PEX_INIT (PEX_SAVE_TEMPS, "temp");
    339   subargv[1] = "echo";
    340   subargv[2] = "quux";
    341   subargv[3] = NULL;
    342   TEST_PEX_RUN (pex1, PEX_SUFFIX, "./test-pexecute", subargv, ".x", NULL);
    343   subargv[1] = "copy";
    344   subargv[2] = NULL;
    345   TEST_PEX_RUN (pex1, PEX_SUFFIX, "./test-pexecute", subargv, ".y", NULL);
    346   e = TEST_PEX_READ_OUTPUT (pex1);
    347   CHECK_LINE (e, "quux");
    348   TEST_PEX_GET_STATUS (pex1, 2, statuses);
    349   if (!WIFEXITED (statuses[0]) || WEXITSTATUS (statuses[0]) != EXIT_SUCCESS
    350       || !WIFEXITED (statuses[1]) || WEXITSTATUS (statuses[1]) != EXIT_SUCCESS)
    351     ERROR ("copy temp exit status failed");
    352   e = fopen ("temp.x", "r");
    353   if (e == NULL)
    354     FATAL_ERROR ("fopen temp.x failed in copy temp", errno);
    355   CHECK_LINE (e, "quux");
    356   fclose (e);
    357   e = fopen ("temp.y", "r");
    358   if (e == NULL)
    359     FATAL_ERROR ("fopen temp.y failed in copy temp", errno);
    360   CHECK_LINE (e, "quux");
    361   fclose (e);
    362   pex_free (pex1);
    363   remove ("temp.x");
    364   remove ("temp.y");
    365 
    366   pex1 = TEST_PEX_INIT (PEX_USE_PIPES, "temp");
    367   subargv[1] = "echoerr";
    368   subargv[2] = "one";
    369   subargv[3] = "two";
    370   subargv[4] = NULL;
    371   TEST_PEX_RUN (pex1, PEX_SUFFIX, "./test-pexecute", subargv, ".x", "temp2.x");
    372   subargv[1] = "write";
    373   subargv[2] = "temp2.y";
    374   subargv[3] = NULL;
    375   TEST_PEX_RUN (pex1, PEX_SUFFIX, "./test-pexecute", subargv, ".y", NULL);
    376   TEST_PEX_GET_STATUS (pex1, 2, statuses);
    377   if (!WIFEXITED (statuses[0]) || WEXITSTATUS (statuses[0]) != EXIT_SUCCESS
    378       || !WIFEXITED (statuses[1]) || WEXITSTATUS (statuses[1]) != EXIT_SUCCESS)
    379     ERROR ("echoerr exit status failed");
    380   pex_free (pex1);
    381   if (fopen ("temp.x", "r") != NULL || fopen ("temp.y", "r") != NULL)
    382     ERROR ("temporary files exist");
    383   e = fopen ("temp2.x", "r");
    384   if (e == NULL)
    385     FATAL_ERROR ("fopen temp2.x failed in echoerr", errno);
    386   CHECK_LINE (e, "two");
    387   fclose (e);
    388   e = fopen ("temp2.y", "r");
    389   if (e == NULL)
    390     FATAL_ERROR ("fopen temp2.y failed in echoerr", errno);
    391   CHECK_LINE (e, "one");
    392   fclose (e);
    393   remove ("temp2.x");
    394   remove ("temp2.y");
    395 
    396   /* Test the old pexecute interface.  */
    397   {
    398     int pid1, pid2;
    399     char *errmsg_fmt;
    400     char *errmsg_arg;
    401     char errbuf1[1000];
    402     char errbuf2[1000];
    403 
    404     subargv[1] = "echo";
    405     subargv[2] = "oldpexecute";
    406     subargv[3] = NULL;
    407     pid1 = pexecute ("./test-pexecute", subargv, "test-pexecute", "temp",
    408 		     &errmsg_fmt, &errmsg_arg, PEXECUTE_FIRST);
    409     if (pid1 < 0)
    410       {
    411 	snprintf (errbuf1, sizeof errbuf1, errmsg_fmt, errmsg_arg);
    412 	snprintf (errbuf2, sizeof errbuf2, "pexecute 1 failed: %s", errbuf1);
    413 	FATAL_ERROR (errbuf2, 0);
    414       }
    415 
    416     subargv[1] = "write";
    417     subargv[2] = "temp.y";
    418     subargv[3] = NULL;
    419     pid2 = pexecute ("./test-pexecute", subargv, "test-pexecute", "temp",
    420 		     &errmsg_fmt, &errmsg_arg, PEXECUTE_LAST);
    421     if (pid2 < 0)
    422       {
    423 	snprintf (errbuf1, sizeof errbuf1, errmsg_fmt, errmsg_arg);
    424 	snprintf (errbuf2, sizeof errbuf2, "pexecute 2 failed: %s", errbuf1);
    425 	FATAL_ERROR (errbuf2, 0);
    426       }
    427 
    428     if (pwait (pid1, &status, 0) < 0)
    429       FATAL_ERROR ("write pwait 1 failed", errno);
    430     if (!WIFEXITED (status) || WEXITSTATUS (status) != EXIT_SUCCESS)
    431       ERROR ("write exit status 1 failed");
    432 
    433     if (pwait (pid2, &status, 0) < 0)
    434       FATAL_ERROR ("write pwait 1 failed", errno);
    435     if (!WIFEXITED (status) || WEXITSTATUS (status) != EXIT_SUCCESS)
    436       ERROR ("write exit status 2 failed");
    437 
    438     e = fopen ("temp.y", "r");
    439     if (e == NULL)
    440       FATAL_ERROR ("fopen temp.y failed in copy temp", errno);
    441     CHECK_LINE (e, "oldpexecute");
    442     fclose (e);
    443 
    444     remove ("temp.y");
    445   }
    446 
    447   if (trace)
    448     fprintf (stderr, "Exiting with status %d\n", error_count);
    449 
    450   return error_count;
    451 }
    452 
    453 /* Execute one of the special testing commands.  */
    454 
    455 static void
    456 do_cmd (int argc, char **argv)
    457 {
    458   const char *s;
    459 
    460   /* Try to prevent generating a core dump.  */
    461 #ifdef RLIMIT_CORE
    462  {
    463    struct rlimit r;
    464 
    465    r.rlim_cur = 0;
    466    r.rlim_max = 0;
    467    setrlimit (RLIMIT_CORE, &r);
    468  }
    469 #endif
    470 
    471   s = argv[1];
    472   if (strcmp (s, "exit") == 0)
    473     exit (EXIT_SUCCESS);
    474   else if (strcmp (s, "echo") == 0)
    475     {
    476       int i;
    477 
    478       for (i = 2; i < argc; ++i)
    479 	{
    480 	  if (i > 2)
    481 	    putchar (' ');
    482 	  fputs (argv[i], stdout);
    483 	}
    484       putchar ('\n');
    485       exit (EXIT_SUCCESS);
    486     }
    487   else if (strcmp (s, "echoerr") == 0)
    488     {
    489       int i;
    490 
    491       for (i = 2; i < argc; ++i)
    492 	{
    493 	  if (i > 3)
    494 	    putc (' ', (i & 1) == 0 ? stdout : stderr);
    495 	  fputs (argv[i], (i & 1) == 0 ? stdout : stderr);
    496 	}
    497       putc ('\n', stdout);
    498       putc ('\n', stderr);
    499       exit (EXIT_SUCCESS);
    500     }
    501   else if (strcmp (s, "error") == 0)
    502     exit (EXIT_FAILURE);
    503   else if (strcmp (s, "abort") == 0)
    504     abort ();
    505   else if (strcmp (s, "copy") == 0)
    506     {
    507       int c;
    508 
    509       while ((c = getchar ()) != EOF)
    510 	putchar (c);
    511       exit (EXIT_SUCCESS);
    512     }
    513   else if (strcmp (s, "write") == 0)
    514     {
    515       FILE *e;
    516       int c;
    517 
    518       e = fopen (argv[2], "w");
    519       if (e == NULL)
    520 	FATAL_ERROR ("fopen for write failed", errno);
    521       while ((c = getchar ()) != EOF)
    522 	putc (c, e);
    523       if (fclose (e) != 0)
    524 	FATAL_ERROR ("fclose for write failed", errno);
    525       exit (EXIT_SUCCESS);
    526     }
    527   else
    528     {
    529       char buf[1000];
    530 
    531       snprintf (buf, sizeof buf, "unrecognized command %s", argv[1]);
    532       FATAL_ERROR (buf, 0);
    533     }
    534 
    535   exit (EXIT_FAILURE);
    536 }
    537