1 /* Pexecute test program,
2 Copyright (C) 2005-2024 Free Software Foundation, Inc.
3 Written by Ian Lance Taylor <ian@airs.com>.
5 This file is part of GNU libiberty.
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.
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.
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.
26 #include "libiberty.h"
33 #include <sys/types.h>
40 #ifdef HAVE_SYS_WAIT_H
43 #ifdef HAVE_SYS_TIME_H
46 #ifdef HAVE_SYS_RESOURCE_H
47 #include <sys/resource.h>
51 #define WIFSIGNALED(S) (((S) & 0xff) != 0 && ((S) & 0xff) != 0x7f)
54 #define WTERMSIG(S) ((S) & 0x7f)
57 #define WIFEXITED(S) (((S) & 0xff) == 0)
60 #define WEXITSTATUS(S) (((S) & 0xff00) >> 8)
63 #define WSTOPSIG WEXITSTATUS
66 #define WCOREDUMP(S) ((S) & WCOREFLG)
73 #define EXIT_SUCCESS 0
77 #define EXIT_FAILURE 1
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.
85 *empty string* Run tests, exit with success status
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
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
;
100 /* The number of errors we have seen. */
102 static int error_count
;
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. */
109 fatal_error (int line
, const char *errmsg
, int err
)
111 fprintf (stderr
, "test-pexecute:%d: %s", line
, errmsg
);
113 fprintf (stderr
, ": %s", xstrerror (err
));
114 fprintf (stderr
, "\n");
118 #define FATAL_ERROR(ERRMSG, ERR) fatal_error (__LINE__, ERRMSG, ERR)
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
125 error (int line
, const char *errmsg
)
127 fprintf (stderr
, "test-pexecute:%d: %s\n", line
, errmsg
);
131 #define ERROR(ERRMSG) error (__LINE__, ERRMSG)
133 /* Check a line in a file. */
136 check_line (int line
, FILE *e
, const char *str
)
151 snprintf (buf
, sizeof buf
, "got '%c' when expecting newline", c
);
152 fatal_error (line
, buf
, 0);
157 snprintf (buf
, sizeof buf
, "got '%c' when expecting EOF", c
);
158 fatal_error (line
, buf
, 0);
165 snprintf (buf
, sizeof buf
, "expected '%c', got '%c'", *p
, c
);
166 fatal_error (line
, buf
, 0);
173 #define CHECK_LINE(E, STR) check_line (__LINE__, E, STR)
175 /* Main function for the pexecute tester. Run the tests. */
178 main (int argc
, char **argv
)
181 struct pex_obj
*test_pex_tmp
;
184 struct pex_obj
*pex1
;
191 if (argc
> 1 && strcmp (argv
[1], "-t") == 0)
201 #define TEST_PEX_INIT(FLAGS, TEMPBASE) \
202 (((test_pex_tmp = pex_init (FLAGS, "test-pexecute", TEMPBASE)) \
205 : (FATAL_ERROR ("pex_init failed", 0), NULL))
207 #define TEST_PEX_RUN(PEXOBJ, FLAGS, EXECUTABLE, ARGV, OUTNAME, ERRNAME) \
211 const char *pex_run_err; \
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, \
217 if (pex_run_err != NULL) \
218 FATAL_ERROR (pex_run_err, err); \
222 #define TEST_PEX_GET_STATUS_1(PEXOBJ) \
223 (pex_get_status (PEXOBJ, 1, &test_pex_status) \
225 : (FATAL_ERROR ("pex_get_status failed", errno), 1))
227 #define TEST_PEX_GET_STATUS(PEXOBJ, COUNT, VECTOR) \
230 if (!pex_get_status (PEXOBJ, COUNT, VECTOR)) \
231 FATAL_ERROR ("pex_get_status failed", errno); \
235 #define TEST_PEX_READ_OUTPUT(PEXOBJ) \
236 ((test_pex_file = pex_read_output (PEXOBJ, 0)) != NULL \
238 : (FATAL_ERROR ("pex_read_output failed", errno), NULL))
243 memset (subargv
, 0, sizeof subargv
);
245 subargv
[0] = "./test-pexecute";
247 pex1
= TEST_PEX_INIT (PEX_USE_PIPES
, 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");
256 pex1
= TEST_PEX_INIT (PEX_USE_PIPES
, NULL
);
257 subargv
[1] = "error";
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");
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";
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");
277 pex1
= TEST_PEX_INIT (PEX_USE_PIPES
, "temp");
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");
288 /* Check empty parameters don't get lost. */
289 pex1
= TEST_PEX_INIT (PEX_USE_PIPES
, "temp");
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");
302 pex1
= TEST_PEX_INIT (PEX_USE_PIPES
, "temp");
306 TEST_PEX_RUN (pex1
, PEX_SUFFIX
, "./test-pexecute", subargv
, ".x", 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");
317 if (fopen ("temp.x", "r") != NULL
|| fopen ("temp.y", "r") != NULL
)
318 ERROR ("temporary files exist");
320 pex1
= TEST_PEX_INIT (0, "temp");
324 TEST_PEX_RUN (pex1
, PEX_SUFFIX
, "./test-pexecute", subargv
, ".x", 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");
335 if (fopen ("temp.x", "r") != NULL
|| fopen ("temp.y", "r") != NULL
)
336 ERROR ("temporary files exist");
338 pex1
= TEST_PEX_INIT (PEX_SAVE_TEMPS
, "temp");
342 TEST_PEX_RUN (pex1
, PEX_SUFFIX
, "./test-pexecute", subargv
, ".x", 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");
354 FATAL_ERROR ("fopen temp.x failed in copy temp", errno
);
355 CHECK_LINE (e
, "quux");
357 e
= fopen ("temp.y", "r");
359 FATAL_ERROR ("fopen temp.y failed in copy temp", errno
);
360 CHECK_LINE (e
, "quux");
366 pex1
= TEST_PEX_INIT (PEX_USE_PIPES
, "temp");
367 subargv
[1] = "echoerr";
371 TEST_PEX_RUN (pex1
, PEX_SUFFIX
, "./test-pexecute", subargv
, ".x", "temp2.x");
372 subargv
[1] = "write";
373 subargv
[2] = "temp2.y";
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");
381 if (fopen ("temp.x", "r") != NULL
|| fopen ("temp.y", "r") != NULL
)
382 ERROR ("temporary files exist");
383 e
= fopen ("temp2.x", "r");
385 FATAL_ERROR ("fopen temp2.x failed in echoerr", errno
);
386 CHECK_LINE (e
, "two");
388 e
= fopen ("temp2.y", "r");
390 FATAL_ERROR ("fopen temp2.y failed in echoerr", errno
);
391 CHECK_LINE (e
, "one");
396 /* Test the old pexecute interface. */
405 subargv
[2] = "oldpexecute";
407 pid1
= pexecute ("./test-pexecute", subargv
, "test-pexecute", "temp",
408 &errmsg_fmt
, &errmsg_arg
, PEXECUTE_FIRST
);
411 snprintf (errbuf1
, sizeof errbuf1
, errmsg_fmt
, errmsg_arg
);
412 snprintf (errbuf2
, sizeof errbuf2
, "pexecute 1 failed: %s", errbuf1
);
413 FATAL_ERROR (errbuf2
, 0);
416 subargv
[1] = "write";
417 subargv
[2] = "temp.y";
419 pid2
= pexecute ("./test-pexecute", subargv
, "test-pexecute", "temp",
420 &errmsg_fmt
, &errmsg_arg
, PEXECUTE_LAST
);
423 snprintf (errbuf1
, sizeof errbuf1
, errmsg_fmt
, errmsg_arg
);
424 snprintf (errbuf2
, sizeof errbuf2
, "pexecute 2 failed: %s", errbuf1
);
425 FATAL_ERROR (errbuf2
, 0);
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");
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");
438 e
= fopen ("temp.y", "r");
440 FATAL_ERROR ("fopen temp.y failed in copy temp", errno
);
441 CHECK_LINE (e
, "oldpexecute");
448 fprintf (stderr
, "Exiting with status %d\n", error_count
);
453 /* Execute one of the special testing commands. */
456 do_cmd (int argc
, char **argv
)
460 /* Try to prevent generating a core dump. */
467 setrlimit (RLIMIT_CORE
, &r
);
472 if (strcmp (s
, "exit") == 0)
474 else if (strcmp (s
, "echo") == 0)
478 for (i
= 2; i
< argc
; ++i
)
482 fputs (argv
[i
], stdout
);
487 else if (strcmp (s
, "echoerr") == 0)
491 for (i
= 2; i
< argc
; ++i
)
494 putc (' ', (i
& 1) == 0 ? stdout
: stderr
);
495 fputs (argv
[i
], (i
& 1) == 0 ? stdout
: stderr
);
501 else if (strcmp (s
, "error") == 0)
503 else if (strcmp (s
, "abort") == 0)
505 else if (strcmp (s
, "copy") == 0)
509 while ((c
= getchar ()) != EOF
)
513 else if (strcmp (s
, "write") == 0)
518 e
= fopen (argv
[2], "w");
520 FATAL_ERROR ("fopen for write failed", errno
);
521 while ((c
= getchar ()) != EOF
)
524 FATAL_ERROR ("fclose for write failed", errno
);
531 snprintf (buf
, sizeof buf
, "unrecognized command %s", argv
[1]);
532 FATAL_ERROR (buf
, 0);