2007-07-16 Jakub Jelinek <jakub@redhat.com> * libio/iopopen.c (_IO_new_proc_open): Don't close child_std_end if one of proc_file_chain streams has that fileno. * stdio-common/Makefile (tests): Add tst-popen2. * stdio-common/tst-popen2.c: New test. --- libc/libio/iopopen.c 14 Sep 2004 04:24:45 -0000 1.33 +++ libc/libio/iopopen.c 19 Jul 2007 17:02:07 -0000 1.34 @@ -169,7 +170,15 @@ _IO_new_proc_open (fp, command, mode) popen() calls that remain open in the parent process are closed in the new child process." */ for (p = proc_file_chain; p; p = p->next) - _IO_close (_IO_fileno ((_IO_FILE *) p)); + { + int fd = _IO_fileno ((_IO_FILE *) p); + + /* If any stream from previous popen() calls has fileno + child_std_end, it has been already closed by the dup2 syscall + above. */ + if (fd != child_std_end) + _IO_close (fd); + } _IO_execl ("/bin/sh", "sh", "-c", command, (char *) 0); _IO__exit (127); --- libc/stdio-common/Makefile 8 Jul 2007 04:41:08 -0000 1.104 +++ libc/stdio-common/Makefile 19 Jul 2007 17:02:55 -0000 1.105 @@ -54,7 +54,8 @@ tests := tstscanf test_rdwr test-popen t tst-swprintf tst-fseek tst-fmemopen test-vfprintf tst-gets \ tst-perror tst-sprintf tst-rndseek tst-fdopen tst-fphex bug14 bug15 \ tst-popen tst-unlockedio tst-fmemopen2 tst-put-error tst-fgets \ - tst-fwrite bug16 bug17 tst-sprintf2 bug18 bug18a bug19 bug19a + tst-fwrite bug16 bug17 tst-sprintf2 bug18 bug18a bug19 bug19a \ + tst-popen2 test-srcs = tst-unbputc tst-printf --- libc/stdio-common/tst-popen2.c 1 Jan 1970 00:00:00 -0000 +++ libc/stdio-common/tst-popen2.c 19 Jul 2007 17:02:43 -0000 1.1 @@ -0,0 +1,92 @@ +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +static int +do_test (void) +{ + int fd = dup (fileno (stdout)); + if (fd <= 1) + { + puts ("dup failed"); + return 1; + } + + FILE *f1 = fdopen (fd, "w"); + if (f1 == NULL) + { + printf ("fdopen failed: %m\n"); + return 1; + } + + fclose (stdout); + + FILE *f2 = popen ("echo test1", "r"); + if (f2 == NULL) + { + fprintf (f1, "1st popen failed: %m\n"); + return 1; + } + FILE *f3 = popen ("echo test2", "r"); + if (f2 == NULL || f3 == NULL) + { + fprintf (f1, "2nd popen failed: %m\n"); + return 1; + } + + char *line = NULL; + size_t len = 0; + int result = 0; + if (getline (&line, &len, f2) != 6) + { + fputs ("could not read line from 1st popen\n", f1); + result = 1; + } + else if (strcmp (line, "test1\n") != 0) + { + fprintf (f1, "read \"%s\"\n", line); + result = 1; + } + + if (getline (&line, &len, f2) != -1) + { + fputs ("second getline did not return -1\n", f1); + result = 1; + } + + if (getline (&line, &len, f3) != 6) + { + fputs ("could not read line from 2nd popen\n", f1); + result = 1; + } + else if (strcmp (line, "test2\n") != 0) + { + fprintf (f1, "read \"%s\"\n", line); + result = 1; + } + + if (getline (&line, &len, f3) != -1) + { + fputs ("second getline did not return -1\n", f1); + result = 1; + } + + int ret = pclose (f2); + if (ret != 0) + { + fprintf (f1, "1st pclose returned %d\n", ret); + result = 1; + } + + ret = pclose (f3); + if (ret != 0) + { + fprintf (f1, "2nd pclose returned %d\n", ret); + result = 1; + } + + return result; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c"