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 #include <string.h>
31 #include <sys/types.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <sys/wait.h>
35 #include <sys/time.h>
36 #include <sys/resource.h>
37
38 extern const char *pex_run (struct pex_obj *obj, int flags,
39 const char *executable, char * const *argv,
40 const char *outname, const char *errname,
41 int *err);
42 extern FILE *pex_read_output (struct pex_obj *, int binary);
43 extern int pex_get_status (struct pex_obj *, int count, int *vector);
44 extern void pex_free (struct pex_obj *);
45
46 #ifndef WIFSIGNALED
47 #define WIFSIGNALED(S) (((S) & 0xff) != 0 && ((S) & 0xff) != 0x7f)
48 #endif
49 #ifndef WTERMSIG
50 #define WTERMSIG(S) ((S) & 0x7f)
51 #endif
52 #ifndef WIFEXITED
53 #define WIFEXITED(S) (((S) & 0xff) == 0)
54 #endif
55 #ifndef WEXITSTATUS
56 #define WEXITSTATUS(S) (((S) & 0xff00) >> 8)
57 #endif
58 #ifndef WSTOPSIG
59 #define WSTOPSIG WEXITSTATUS
60 #endif
61 #ifndef WCOREDUMP
62 #define WCOREDUMP(S) ((S) & WCOREFLG)
63 #endif
64 #ifndef WCOREFLG
65 #define WCOREFLG 0200
66 #endif
67
68 #ifndef EXIT_SUCCESS
69 #define EXIT_SUCCESS 0
70 #endif
71
72 #ifndef EXIT_FAILURE
73 #define EXIT_FAILURE 1
74 #endif
75
76 /* When this program is run with no arguments, it runs some tests of
77 the libiberty pexecute functions. As a test program, it simply
78 invokes itself with various arguments.
79
80 argv[1]:
81 *empty string* Run tests, exit with success status
82 exit Exit success
83 error Exit error
84 abort Abort
85 echo Echo remaining arguments, exit success
86 echoerr Echo next arg to stdout, next to stderr, repeat
87 copy Copy stdin to stdout
88 write Write stdin to file named in next argument
89 */
90
91 static void fatal_error (int, const char *, int) ATTRIBUTE_NORETURN;
92 static void error (int, const char *);
93 static void check_line (int, FILE *, const char *);
94 static void do_cmd (int, char **) ATTRIBUTE_NORETURN;
95
96 /* The number of errors we have seen. */
97
98 static int error_count;
99
100 /* Print a fatal error and exit. LINE is the line number where we
101 detected the error, ERRMSG is the error message to print, and ERR
102 is 0 or an errno value to print. */
103
104 static void
fatal_error(int line,const char * errmsg,int err)105 fatal_error (int line, const char *errmsg, int err)
106 {
107 fprintf (stderr, "test-pexecute:%d: %s", line, errmsg);
108 if (errno != 0)
109 fprintf (stderr, ": %s", xstrerror (err));
110 fprintf (stderr, "\n");
111 exit (EXIT_FAILURE);
112 }
113
114 #define FATAL_ERROR(ERRMSG, ERR) fatal_error (__LINE__, ERRMSG, ERR)
115
116 /* Print an error message and bump the error count. LINE is the line
117 number where we detected the error, ERRMSG is the error to
118 print. */
119
120 static void
error(int line,const char * errmsg)121 error (int line, const char *errmsg)
122 {
123 fprintf (stderr, "test-pexecute:%d: %s\n", line, errmsg);
124 ++error_count;
125 }
126
127 #define ERROR(ERRMSG) error (__LINE__, ERRMSG)
128
129 /* Check a line in a file. */
130
131 static void
check_line(int line,FILE * e,const char * str)132 check_line (int line, FILE *e, const char *str)
133 {
134 const char *p;
135 int c;
136 char buf[1000];
137
138 p = str;
139 while (1)
140 {
141 c = getc (e);
142
143 if (*p == '\0')
144 {
145 if (c != '\n')
146 {
147 snprintf (buf, sizeof buf, "got '%c' when expecting newline", c);
148 fatal_error (line, buf, 0);
149 }
150 c = getc (e);
151 if (c != EOF)
152 {
153 snprintf (buf, sizeof buf, "got '%c' when expecting EOF", c);
154 fatal_error (line, buf, 0);
155 }
156 return;
157 }
158
159 if (c != *p)
160 {
161 snprintf (buf, sizeof buf, "expected '%c', got '%c'", *p, c);
162 fatal_error (line, buf, 0);
163 }
164
165 ++p;
166 }
167 }
168
169 #define CHECK_LINE(E, STR) check_line (__LINE__, E, STR)
170
171 /* Main function for the pexecute tester. Run the tests. */
172
173 int
main(int argc,char ** argv)174 main (int argc, char **argv)
175 {
176 int trace;
177 struct pex_obj *test_pex_tmp;
178 int test_pex_status;
179 FILE *test_pex_file;
180 struct pex_obj *pex1;
181 char *subargv[10];
182 int status;
183 FILE *e;
184 int statuses[10];
185
186 trace = 0;
187 if (argc > 1 && strcmp (argv[1], "-t") == 0)
188 {
189 trace = 1;
190 --argc;
191 ++argv;
192 }
193
194 if (argc > 1)
195 do_cmd (argc, argv);
196
197 #define TEST_PEX_INIT(FLAGS, TEMPBASE) \
198 (((test_pex_tmp = pex_init (FLAGS, "test-pexecute", TEMPBASE)) \
199 != NULL) \
200 ? test_pex_tmp \
201 : (FATAL_ERROR ("pex_init failed", 0), NULL))
202
203 #define TEST_PEX_RUN(PEXOBJ, FLAGS, EXECUTABLE, ARGV, OUTNAME, ERRNAME) \
204 do \
205 { \
206 int err; \
207 const char *pex_run_err; \
208 if (trace) \
209 fprintf (stderr, "Line %d: running %s %s\n", \
210 __LINE__, EXECUTABLE, ARGV[0]); \
211 pex_run_err = pex_run (PEXOBJ, FLAGS, EXECUTABLE, ARGV, OUTNAME, \
212 ERRNAME, &err); \
213 if (pex_run_err != NULL) \
214 FATAL_ERROR (pex_run_err, err); \
215 } \
216 while (0)
217
218 #define TEST_PEX_GET_STATUS_1(PEXOBJ) \
219 (pex_get_status (PEXOBJ, 1, &test_pex_status) \
220 ? test_pex_status \
221 : (FATAL_ERROR ("pex_get_status failed", errno), 1))
222
223 #define TEST_PEX_GET_STATUS(PEXOBJ, COUNT, VECTOR) \
224 do \
225 { \
226 if (!pex_get_status (PEXOBJ, COUNT, VECTOR)) \
227 FATAL_ERROR ("pex_get_status failed", errno); \
228 } \
229 while (0)
230
231 #define TEST_PEX_READ_OUTPUT(PEXOBJ) \
232 ((test_pex_file = pex_read_output (PEXOBJ, 0)) != NULL \
233 ? test_pex_file \
234 : (FATAL_ERROR ("pex_read_output failed", errno), NULL))
235
236 remove ("temp.x");
237 remove ("temp.y");
238
239 memset (subargv, 0, sizeof subargv);
240
241 subargv[0] = "./test-pexecute";
242
243 pex1 = TEST_PEX_INIT (PEX_USE_PIPES, NULL);
244 subargv[1] = "exit";
245 subargv[2] = NULL;
246 TEST_PEX_RUN (pex1, PEX_LAST, "./test-pexecute", subargv, NULL, NULL);
247 status = TEST_PEX_GET_STATUS_1 (pex1);
248 if (!WIFEXITED (status) || WEXITSTATUS (status) != EXIT_SUCCESS)
249 ERROR ("exit failed");
250 pex_free (pex1);
251
252 pex1 = TEST_PEX_INIT (PEX_USE_PIPES, NULL);
253 subargv[1] = "error";
254 subargv[2] = NULL;
255 TEST_PEX_RUN (pex1, PEX_LAST, "./test-pexecute", subargv, NULL, NULL);
256 status = TEST_PEX_GET_STATUS_1 (pex1);
257 if (!WIFEXITED (status) || WEXITSTATUS (status) != EXIT_FAILURE)
258 ERROR ("error test failed");
259 pex_free (pex1);
260
261 /* We redirect stderr to a file to avoid an error message which is
262 printed on mingw32 when the child calls abort. */
263 pex1 = TEST_PEX_INIT (PEX_USE_PIPES, NULL);
264 subargv[1] = "abort";
265 subargv[2] = NULL;
266 TEST_PEX_RUN (pex1, PEX_LAST, "./test-pexecute", subargv, NULL, "temp.z");
267 status = TEST_PEX_GET_STATUS_1 (pex1);
268 if (!WIFSIGNALED (status) || WTERMSIG (status) != SIGABRT)
269 ERROR ("abort failed");
270 pex_free (pex1);
271 remove ("temp.z");
272
273 pex1 = TEST_PEX_INIT (PEX_USE_PIPES, "temp");
274 subargv[1] = "echo";
275 subargv[2] = "foo";
276 subargv[3] = NULL;
277 TEST_PEX_RUN (pex1, 0, "./test-pexecute", subargv, NULL, NULL);
278 e = TEST_PEX_READ_OUTPUT (pex1);
279 CHECK_LINE (e, "foo");
280 if (TEST_PEX_GET_STATUS_1 (pex1) != 0)
281 ERROR ("echo exit status failed");
282 pex_free (pex1);
283
284 pex1 = TEST_PEX_INIT (PEX_USE_PIPES, "temp");
285 subargv[1] = "echo";
286 subargv[2] = "bar";
287 subargv[3] = NULL;
288 TEST_PEX_RUN (pex1, PEX_SUFFIX, "./test-pexecute", subargv, ".x", NULL);
289 subargv[1] = "copy";
290 subargv[2] = NULL;
291 TEST_PEX_RUN (pex1, PEX_SUFFIX, "./test-pexecute", subargv, ".y", NULL);
292 e = TEST_PEX_READ_OUTPUT (pex1);
293 CHECK_LINE (e, "bar");
294 TEST_PEX_GET_STATUS (pex1, 2, statuses);
295 if (!WIFEXITED (statuses[0]) || WEXITSTATUS (statuses[0]) != EXIT_SUCCESS
296 || !WIFEXITED (statuses[1]) || WEXITSTATUS (statuses[1]) != EXIT_SUCCESS)
297 ERROR ("copy exit status failed");
298 pex_free (pex1);
299 if (fopen ("temp.x", "r") != NULL || fopen ("temp.y", "r") != NULL)
300 ERROR ("temporary files exist");
301
302 pex1 = TEST_PEX_INIT (0, "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 (PEX_SAVE_TEMPS, "temp");
321 subargv[1] = "echo";
322 subargv[2] = "quux";
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, "quux");
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 temp exit status failed");
334 e = fopen ("temp.x", "r");
335 if (e == NULL)
336 FATAL_ERROR ("fopen temp.x failed in copy temp", errno);
337 CHECK_LINE (e, "quux");
338 fclose (e);
339 e = fopen ("temp.y", "r");
340 if (e == NULL)
341 FATAL_ERROR ("fopen temp.y failed in copy temp", errno);
342 CHECK_LINE (e, "quux");
343 fclose (e);
344 pex_free (pex1);
345 remove ("temp.x");
346 remove ("temp.y");
347
348 pex1 = TEST_PEX_INIT (PEX_USE_PIPES, "temp");
349 subargv[1] = "echoerr";
350 subargv[2] = "one";
351 subargv[3] = "two";
352 subargv[4] = NULL;
353 TEST_PEX_RUN (pex1, PEX_SUFFIX, "./test-pexecute", subargv, ".x", "temp2.x");
354 subargv[1] = "write";
355 subargv[2] = "temp2.y";
356 subargv[3] = NULL;
357 TEST_PEX_RUN (pex1, PEX_SUFFIX, "./test-pexecute", subargv, ".y", NULL);
358 TEST_PEX_GET_STATUS (pex1, 2, statuses);
359 if (!WIFEXITED (statuses[0]) || WEXITSTATUS (statuses[0]) != EXIT_SUCCESS
360 || !WIFEXITED (statuses[1]) || WEXITSTATUS (statuses[1]) != EXIT_SUCCESS)
361 ERROR ("echoerr exit status failed");
362 pex_free (pex1);
363 if (fopen ("temp.x", "r") != NULL || fopen ("temp.y", "r") != NULL)
364 ERROR ("temporary files exist");
365 e = fopen ("temp2.x", "r");
366 if (e == NULL)
367 FATAL_ERROR ("fopen temp2.x failed in echoerr", errno);
368 CHECK_LINE (e, "two");
369 fclose (e);
370 e = fopen ("temp2.y", "r");
371 if (e == NULL)
372 FATAL_ERROR ("fopen temp2.y failed in echoerr", errno);
373 CHECK_LINE (e, "one");
374 fclose (e);
375 remove ("temp2.x");
376 remove ("temp2.y");
377
378 /* Test the old pexecute interface. */
379 {
380 int pid1, pid2;
381 char *errmsg_fmt;
382 char *errmsg_arg;
383 char errbuf1[1000];
384 char errbuf2[1000];
385
386 subargv[1] = "echo";
387 subargv[2] = "oldpexecute";
388 subargv[3] = NULL;
389 pid1 = pexecute ("./test-pexecute", subargv, "test-pexecute", "temp",
390 &errmsg_fmt, &errmsg_arg, PEXECUTE_FIRST);
391 if (pid1 < 0)
392 {
393 snprintf (errbuf1, sizeof errbuf1, errmsg_fmt, errmsg_arg);
394 snprintf (errbuf2, sizeof errbuf2, "pexecute 1 failed: %s", errbuf1);
395 FATAL_ERROR (errbuf2, 0);
396 }
397
398 subargv[1] = "write";
399 subargv[2] = "temp.y";
400 subargv[3] = NULL;
401 pid2 = pexecute ("./test-pexecute", subargv, "test-pexecute", "temp",
402 &errmsg_fmt, &errmsg_arg, PEXECUTE_LAST);
403 if (pid2 < 0)
404 {
405 snprintf (errbuf1, sizeof errbuf1, errmsg_fmt, errmsg_arg);
406 snprintf (errbuf2, sizeof errbuf2, "pexecute 2 failed: %s", errbuf1);
407 FATAL_ERROR (errbuf2, 0);
408 }
409
410 if (pwait (pid1, &status, 0) < 0)
411 FATAL_ERROR ("write pwait 1 failed", errno);
412 if (!WIFEXITED (status) || WEXITSTATUS (status) != EXIT_SUCCESS)
413 ERROR ("write exit status 1 failed");
414
415 if (pwait (pid2, &status, 0) < 0)
416 FATAL_ERROR ("write pwait 1 failed", errno);
417 if (!WIFEXITED (status) || WEXITSTATUS (status) != EXIT_SUCCESS)
418 ERROR ("write exit status 2 failed");
419
420 e = fopen ("temp.y", "r");
421 if (e == NULL)
422 FATAL_ERROR ("fopen temp.y failed in copy temp", errno);
423 CHECK_LINE (e, "oldpexecute");
424 fclose (e);
425
426 remove ("temp.y");
427 }
428
429 if (trace)
430 fprintf (stderr, "Exiting with status %d\n", error_count);
431
432 return error_count;
433 }
434
435 /* Execute one of the special testing commands. */
436
437 static void
do_cmd(int argc,char ** argv)438 do_cmd (int argc, char **argv)
439 {
440 const char *s;
441
442 /* Try to prevent generating a core dump. */
443 #ifdef RLIMIT_CORE
444 {
445 struct rlimit r;
446
447 r.rlim_cur = 0;
448 r.rlim_max = 0;
449 setrlimit (RLIMIT_CORE, &r);
450 }
451 #endif
452
453 s = argv[1];
454 if (strcmp (s, "exit") == 0)
455 exit (EXIT_SUCCESS);
456 else if (strcmp (s, "echo") == 0)
457 {
458 int i;
459
460 for (i = 2; i < argc; ++i)
461 {
462 if (i > 2)
463 putchar (' ');
464 fputs (argv[i], stdout);
465 }
466 putchar ('\n');
467 exit (EXIT_SUCCESS);
468 }
469 else if (strcmp (s, "echoerr") == 0)
470 {
471 int i;
472
473 for (i = 2; i < argc; ++i)
474 {
475 if (i > 3)
476 putc (' ', (i & 1) == 0 ? stdout : stderr);
477 fputs (argv[i], (i & 1) == 0 ? stdout : stderr);
478 }
479 putc ('\n', stdout);
480 putc ('\n', stderr);
481 exit (EXIT_SUCCESS);
482 }
483 else if (strcmp (s, "error") == 0)
484 exit (EXIT_FAILURE);
485 else if (strcmp (s, "abort") == 0)
486 abort ();
487 else if (strcmp (s, "copy") == 0)
488 {
489 int c;
490
491 while ((c = getchar ()) != EOF)
492 putchar (c);
493 exit (EXIT_SUCCESS);
494 }
495 else if (strcmp (s, "write") == 0)
496 {
497 FILE *e;
498 int c;
499
500 e = fopen (argv[2], "w");
501 if (e == NULL)
502 FATAL_ERROR ("fopen for write failed", errno);
503 while ((c = getchar ()) != EOF)
504 putc (c, e);
505 if (fclose (e) != 0)
506 FATAL_ERROR ("fclose for write failed", errno);
507 exit (EXIT_SUCCESS);
508 }
509 else
510 {
511 char buf[1000];
512
513 snprintf (buf, sizeof buf, "unrecognized command %s", argv[1]);
514 FATAL_ERROR (buf, 0);
515 }
516
517 exit (EXIT_FAILURE);
518 }
519