merge from gcc
[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., 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 }