(root)/
binutils-2.41/
libiberty/
testsuite/
test-pexecute.c
       1  /* Pexecute test program,
       2     Copyright (C) 2005-2023 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  #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  }