From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 22951 invoked by alias); 16 Jul 2007 09:42:38 -0000 Received: (qmail 22935 invoked by uid 22791); 16 Jul 2007 09:42:38 -0000 X-Spam-Check-By: sourceware.org Received: from sunsite.ms.mff.cuni.cz (HELO sunsite.mff.cuni.cz) (195.113.15.26) by sourceware.org (qpsmtpd/0.31) with ESMTP; Mon, 16 Jul 2007 09:42:35 +0000 Received: from sunsite.mff.cuni.cz (localhost.localdomain [127.0.0.1]) by sunsite.mff.cuni.cz (8.13.8/8.13.8) with ESMTP id l6G9juGF009995; Mon, 16 Jul 2007 11:45:56 +0200 Received: (from jakub@localhost) by sunsite.mff.cuni.cz (8.13.8/8.13.8/Submit) id l6G9juH9009986; Mon, 16 Jul 2007 11:45:56 +0200 Date: Mon, 16 Jul 2007 09:42:00 -0000 From: Jakub Jelinek To: Ulrich Drepper Cc: Glibc hackers Subject: [PATCH] Fix popen Message-ID: <20070716094556.GO4603@sunsite.mff.cuni.cz> Reply-To: Jakub Jelinek Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.4.2.2i Mailing-List: contact libc-hacker-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-hacker-owner@sourceware.org X-SW-Source: 2007-07/txt/msg00017.txt.bz2 Hi! http://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=248281 As the testcase below shows, if one of proc_file_chain streams has fileno () == 1 (for "r" popen, resp. 0 for "w" popen), we close that stream already in dup2 above this loop and the close in the loop closes not the previous popen's file descriptor, but stdout (resp. stdin) of the popen child. 2007-07-16 Jakub Jelinek * 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.jj 2004-09-14 06:24:45.000000000 +0200 +++ libc/libio/iopopen.c 2007-07-16 10:27:05.000000000 +0200 @@ -1,4 +1,5 @@ -/* Copyright (C) 1993, 1997-2002, 2003, 2004 Free Software Foundation, Inc. +/* Copyright (C) 1993, 1997-2002, 2003, 2004, 2007 + Free Software Foundation, Inc. This file is part of the GNU C Library. Written by Per Bothner . @@ -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.jj 2007-07-12 17:47:27.000000000 +0200 +++ libc/stdio-common/Makefile 2007-07-16 11:02:50.000000000 +0200 @@ -55,7 +55,7 @@ tests := tstscanf test_rdwr test-popen t 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-swscanf tst-sprintf2 bug18 bug18a \ - bug19 bug19a + bug19 bug19a tst-popen2 test-srcs = tst-unbputc tst-printf --- libc/stdio-common/tst-popen2.c.jj 2007-07-16 10:09:07.000000000 +0200 +++ libc/stdio-common/tst-popen2.c 2007-07-16 10:22:36.000000000 +0200 @@ -0,0 +1,92 @@ +#include +#include +#include + +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" Jakub