]> git.ipfire.org Git - thirdparty/gcc.git/blame - libiberty/testsuite/test-pexecute.c
Update copyright years.
[thirdparty/gcc.git] / libiberty / testsuite / test-pexecute.c
CommitLineData
a584cf65 1/* Pexecute test program,
a945c346 2 Copyright (C) 2005-2024 Free Software Foundation, Inc.
a584cf65
ILT
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
0cbe2a68 19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
a584cf65
ILT
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
95static void fatal_error (int, const char *, int) ATTRIBUTE_NORETURN;
96static void error (int, const char *);
97static void check_line (int, FILE *, const char *);
98static void do_cmd (int, char **) ATTRIBUTE_NORETURN;
99
100/* The number of errors we have seen. */
101
102static 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
108static void
109fatal_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
124static void
125error (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
135static void
136check_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
177int
178main (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; \
2f84c996 211 const char *pex_run_err; \
a584cf65
ILT
212 if (trace) \
213 fprintf (stderr, "Line %d: running %s %s\n", \
214 __LINE__, EXECUTABLE, ARGV[0]); \
2f84c996
ILT
215 pex_run_err = pex_run (PEXOBJ, FLAGS, EXECUTABLE, ARGV, OUTNAME, \
216 ERRNAME, &err); \
a584cf65
ILT
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
471a0d47
AS
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
a584cf65
ILT
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
455static void
456do_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}