libiberty:
[external/binutils.git] / libiberty / testsuite / test-pexecute.c
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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       if (trace)                                                        \
212         fprintf (stderr, "Line %d: running %s %s\n",                    \
213                  __LINE__, EXECUTABLE, ARGV[0]);                        \
214       const char *pex_run_err = pex_run (PEXOBJ, FLAGS, EXECUTABLE,     \
215                                          ARGV, OUTNAME, ERRNAME, &err); \
216       if (pex_run_err != NULL)                                          \
217         FATAL_ERROR (pex_run_err, err);                                 \
218     }                                                                   \
219   while (0)
220
221 #define TEST_PEX_GET_STATUS_1(PEXOBJ)                                   \
222   (pex_get_status (PEXOBJ, 1, &test_pex_status)                         \
223    ? test_pex_status                                                    \
224    : (FATAL_ERROR ("pex_get_status failed", errno), 1))
225
226 #define TEST_PEX_GET_STATUS(PEXOBJ, COUNT, VECTOR)                      \
227   do                                                                    \
228     {                                                                   \
229       if (!pex_get_status (PEXOBJ, COUNT, VECTOR))                      \
230         FATAL_ERROR ("pex_get_status failed", errno);                   \
231     }                                                                   \
232   while (0)
233
234 #define TEST_PEX_READ_OUTPUT(PEXOBJ)                                    \
235   ((test_pex_file = pex_read_output (PEXOBJ, 0)) != NULL                \
236    ? test_pex_file                                                      \
237    : (FATAL_ERROR ("pex_read_output failed", errno), NULL))
238
239   remove ("temp.x");
240   remove ("temp.y");
241
242   memset (subargv, 0, sizeof subargv);
243
244   subargv[0] = "./test-pexecute";
245
246   pex1 = TEST_PEX_INIT (PEX_USE_PIPES, NULL);
247   subargv[1] = "exit";
248   subargv[2] = NULL;
249   TEST_PEX_RUN (pex1, PEX_LAST, "./test-pexecute", subargv, NULL, NULL);
250   status = TEST_PEX_GET_STATUS_1 (pex1);
251   if (!WIFEXITED (status) || WEXITSTATUS (status) != EXIT_SUCCESS)
252     ERROR ("exit failed");
253   pex_free (pex1);
254
255   pex1 = TEST_PEX_INIT (PEX_USE_PIPES, NULL);
256   subargv[1] = "error";
257   subargv[2] = NULL;
258   TEST_PEX_RUN (pex1, PEX_LAST, "./test-pexecute", subargv, NULL, NULL);
259   status = TEST_PEX_GET_STATUS_1 (pex1);
260   if (!WIFEXITED (status) || WEXITSTATUS (status) != EXIT_FAILURE)
261     ERROR ("error test failed");
262   pex_free (pex1);
263
264   /* We redirect stderr to a file to avoid an error message which is
265      printed on mingw32 when the child calls abort.  */
266   pex1 = TEST_PEX_INIT (PEX_USE_PIPES, NULL);
267   subargv[1] = "abort";
268   subargv[2] = NULL;
269   TEST_PEX_RUN (pex1, PEX_LAST, "./test-pexecute", subargv, NULL, "temp.z");
270   status = TEST_PEX_GET_STATUS_1 (pex1);
271   if (!WIFSIGNALED (status) || WTERMSIG (status) != SIGABRT)
272     ERROR ("abort failed");
273   pex_free (pex1);
274   remove ("temp.z");
275
276   pex1 = TEST_PEX_INIT (PEX_USE_PIPES, "temp");
277   subargv[1] = "echo";
278   subargv[2] = "foo";
279   subargv[3] = NULL;
280   TEST_PEX_RUN (pex1, 0, "./test-pexecute", subargv, NULL, NULL);
281   e = TEST_PEX_READ_OUTPUT (pex1);
282   CHECK_LINE (e, "foo");
283   if (TEST_PEX_GET_STATUS_1 (pex1) != 0)
284     ERROR ("echo exit status failed");
285   pex_free (pex1);
286
287   pex1 = TEST_PEX_INIT (PEX_USE_PIPES, "temp");
288   subargv[1] = "echo";
289   subargv[2] = "bar";
290   subargv[3] = NULL;
291   TEST_PEX_RUN (pex1, PEX_SUFFIX, "./test-pexecute", subargv, ".x", NULL);
292   subargv[1] = "copy";
293   subargv[2] = NULL;
294   TEST_PEX_RUN (pex1, PEX_SUFFIX, "./test-pexecute", subargv, ".y", NULL);
295   e = TEST_PEX_READ_OUTPUT (pex1);
296   CHECK_LINE (e, "bar");
297   TEST_PEX_GET_STATUS (pex1, 2, statuses);
298   if (!WIFEXITED (statuses[0]) || WEXITSTATUS (statuses[0]) != EXIT_SUCCESS
299       || !WIFEXITED (statuses[1]) || WEXITSTATUS (statuses[1]) != EXIT_SUCCESS)
300     ERROR ("copy exit status failed");
301   pex_free (pex1);
302   if (fopen ("temp.x", "r") != NULL || fopen ("temp.y", "r") != NULL)
303     ERROR ("temporary files exist");
304
305   pex1 = TEST_PEX_INIT (0, "temp");
306   subargv[1] = "echo";
307   subargv[2] = "bar";
308   subargv[3] = NULL;
309   TEST_PEX_RUN (pex1, PEX_SUFFIX, "./test-pexecute", subargv, ".x", NULL);
310   subargv[1] = "copy";
311   subargv[2] = NULL;
312   TEST_PEX_RUN (pex1, PEX_SUFFIX, "./test-pexecute", subargv, ".y", NULL);
313   e = TEST_PEX_READ_OUTPUT (pex1);
314   CHECK_LINE (e, "bar");
315   TEST_PEX_GET_STATUS (pex1, 2, statuses);
316   if (!WIFEXITED (statuses[0]) || WEXITSTATUS (statuses[0]) != EXIT_SUCCESS
317       || !WIFEXITED (statuses[1]) || WEXITSTATUS (statuses[1]) != EXIT_SUCCESS)
318     ERROR ("copy exit status failed");
319   pex_free (pex1);
320   if (fopen ("temp.x", "r") != NULL || fopen ("temp.y", "r") != NULL)
321     ERROR ("temporary files exist");
322
323   pex1 = TEST_PEX_INIT (PEX_SAVE_TEMPS, "temp");
324   subargv[1] = "echo";
325   subargv[2] = "quux";
326   subargv[3] = NULL;
327   TEST_PEX_RUN (pex1, PEX_SUFFIX, "./test-pexecute", subargv, ".x", NULL);
328   subargv[1] = "copy";
329   subargv[2] = NULL;
330   TEST_PEX_RUN (pex1, PEX_SUFFIX, "./test-pexecute", subargv, ".y", NULL);
331   e = TEST_PEX_READ_OUTPUT (pex1);
332   CHECK_LINE (e, "quux");
333   TEST_PEX_GET_STATUS (pex1, 2, statuses);
334   if (!WIFEXITED (statuses[0]) || WEXITSTATUS (statuses[0]) != EXIT_SUCCESS
335       || !WIFEXITED (statuses[1]) || WEXITSTATUS (statuses[1]) != EXIT_SUCCESS)
336     ERROR ("copy temp exit status failed");
337   e = fopen ("temp.x", "r");
338   if (e == NULL)
339     FATAL_ERROR ("fopen temp.x failed in copy temp", errno);
340   CHECK_LINE (e, "quux");
341   fclose (e);
342   e = fopen ("temp.y", "r");
343   if (e == NULL)
344     FATAL_ERROR ("fopen temp.y failed in copy temp", errno);
345   CHECK_LINE (e, "quux");
346   fclose (e);
347   pex_free (pex1);
348   remove ("temp.x");
349   remove ("temp.y");
350
351   pex1 = TEST_PEX_INIT (PEX_USE_PIPES, "temp");
352   subargv[1] = "echoerr";
353   subargv[2] = "one";
354   subargv[3] = "two";
355   subargv[4] = NULL;
356   TEST_PEX_RUN (pex1, PEX_SUFFIX, "./test-pexecute", subargv, ".x", "temp2.x");
357   subargv[1] = "write";
358   subargv[2] = "temp2.y";
359   subargv[3] = NULL;
360   TEST_PEX_RUN (pex1, PEX_SUFFIX, "./test-pexecute", subargv, ".y", NULL);
361   TEST_PEX_GET_STATUS (pex1, 2, statuses);
362   if (!WIFEXITED (statuses[0]) || WEXITSTATUS (statuses[0]) != EXIT_SUCCESS
363       || !WIFEXITED (statuses[1]) || WEXITSTATUS (statuses[1]) != EXIT_SUCCESS)
364     ERROR ("echoerr exit status failed");
365   pex_free (pex1);
366   if (fopen ("temp.x", "r") != NULL || fopen ("temp.y", "r") != NULL)
367     ERROR ("temporary files exist");
368   e = fopen ("temp2.x", "r");
369   if (e == NULL)
370     FATAL_ERROR ("fopen temp2.x failed in echoerr", errno);
371   CHECK_LINE (e, "two");
372   fclose (e);
373   e = fopen ("temp2.y", "r");
374   if (e == NULL)
375     FATAL_ERROR ("fopen temp2.y failed in echoerr", errno);
376   CHECK_LINE (e, "one");
377   fclose (e);
378   remove ("temp2.x");
379   remove ("temp2.y");
380
381   /* Test the old pexecute interface.  */
382   {
383     int pid1, pid2;
384     char *errmsg_fmt;
385     char *errmsg_arg;
386     char errbuf1[1000];
387     char errbuf2[1000];
388
389     subargv[1] = "echo";
390     subargv[2] = "oldpexecute";
391     subargv[3] = NULL;
392     pid1 = pexecute ("./test-pexecute", subargv, "test-pexecute", "temp",
393                      &errmsg_fmt, &errmsg_arg, PEXECUTE_FIRST);
394     if (pid1 < 0)
395       {
396         snprintf (errbuf1, sizeof errbuf1, errmsg_fmt, errmsg_arg);
397         snprintf (errbuf2, sizeof errbuf2, "pexecute 1 failed: %s", errbuf1);
398         FATAL_ERROR (errbuf2, 0);
399       }
400
401     subargv[1] = "write";
402     subargv[2] = "temp.y";
403     subargv[3] = NULL;
404     pid2 = pexecute ("./test-pexecute", subargv, "test-pexecute", "temp",
405                      &errmsg_fmt, &errmsg_arg, PEXECUTE_LAST);
406     if (pid2 < 0)
407       {
408         snprintf (errbuf1, sizeof errbuf1, errmsg_fmt, errmsg_arg);
409         snprintf (errbuf2, sizeof errbuf2, "pexecute 2 failed: %s", errbuf1);
410         FATAL_ERROR (errbuf2, 0);
411       }
412
413     if (pwait (pid1, &status, 0) < 0)
414       FATAL_ERROR ("write pwait 1 failed", errno);
415     if (!WIFEXITED (status) || WEXITSTATUS (status) != EXIT_SUCCESS)
416       ERROR ("write exit status 1 failed");
417
418     if (pwait (pid2, &status, 0) < 0)
419       FATAL_ERROR ("write pwait 1 failed", errno);
420     if (!WIFEXITED (status) || WEXITSTATUS (status) != EXIT_SUCCESS)
421       ERROR ("write exit status 2 failed");
422
423     e = fopen ("temp.y", "r");
424     if (e == NULL)
425       FATAL_ERROR ("fopen temp.y failed in copy temp", errno);
426     CHECK_LINE (e, "oldpexecute");
427     fclose (e);
428
429     remove ("temp.y");
430   }
431
432   if (trace)
433     fprintf (stderr, "Exiting with status %d\n", error_count);
434
435   return error_count;
436 }
437
438 /* Execute one of the special testing commands.  */
439
440 static void
441 do_cmd (int argc, char **argv)
442 {
443   const char *s;
444
445   /* Try to prevent generating a core dump.  */
446 #ifdef RLIMIT_CORE
447  {
448    struct rlimit r;
449
450    r.rlim_cur = 0;
451    r.rlim_max = 0;
452    setrlimit (RLIMIT_CORE, &r);
453  }
454 #endif
455
456   s = argv[1];
457   if (strcmp (s, "exit") == 0)
458     exit (EXIT_SUCCESS);
459   else if (strcmp (s, "echo") == 0)
460     {
461       int i;
462
463       for (i = 2; i < argc; ++i)
464         {
465           if (i > 2)
466             putchar (' ');
467           fputs (argv[i], stdout);
468         }
469       putchar ('\n');
470       exit (EXIT_SUCCESS);
471     }
472   else if (strcmp (s, "echoerr") == 0)
473     {
474       int i;
475
476       for (i = 2; i < argc; ++i)
477         {
478           if (i > 3)
479             putc (' ', (i & 1) == 0 ? stdout : stderr);
480           fputs (argv[i], (i & 1) == 0 ? stdout : stderr);
481         }
482       putc ('\n', stdout);
483       putc ('\n', stderr);
484       exit (EXIT_SUCCESS);
485     }
486   else if (strcmp (s, "error") == 0)
487     exit (EXIT_FAILURE);
488   else if (strcmp (s, "abort") == 0)
489     abort ();
490   else if (strcmp (s, "copy") == 0)
491     {
492       int c;
493
494       while ((c = getchar ()) != EOF)
495         putchar (c);
496       exit (EXIT_SUCCESS);
497     }
498   else if (strcmp (s, "write") == 0)
499     {
500       FILE *e;
501       int c;
502
503       e = fopen (argv[2], "w");
504       if (e == NULL)
505         FATAL_ERROR ("fopen for write failed", errno);
506       while ((c = getchar ()) != EOF)
507         putc (c, e);
508       if (fclose (e) != 0)
509         FATAL_ERROR ("fclose for write failed", errno);
510       exit (EXIT_SUCCESS);
511     }
512   else
513     {
514       char buf[1000];
515
516       snprintf (buf, sizeof buf, "unrecognized command %s", argv[1]);
517       FATAL_ERROR (buf, 0);
518     }
519
520   exit (EXIT_FAILURE);
521 }