Date: Wed, 14 Oct 1998 07:25:14 -0700 From: Wayne Scott <wscott@ichips.intel.com> To: current@FreeBSD.ORG Subject: simple popen() bug and solution (PATCH) Message-ID: <199810141425.HAA26802@pdxcs565.pdx.intel.com>
next in thread | raw e-mail | index | archive | help
This is a restatement of PR misc/7810. Since that PR is making NO progress I thought I would restate the problem in terms everyone can understand. The Problem ----------- The following program hangs on all current versions of FreeBSD, but works on Linux, AIX, and HPUX. #include <stdio.h> #include <fcntl.h> main() { FILE *file1; FILE *file2; file1 = popen("gzip > file1.gz", "w"); file2 = popen("gzip > file2.gz", "w"); fprintf(file1, "This is a test\n"); fprintf(file2, "This is also a test\n"); pclose(file1); pclose(file2); } The Cause --------- When popen exec's the second gzip process, that process inherits the open filehandle 'file1'. When 'pclose(file1)' is executed the first gzip does not exit because the second gzip is still holding an open handle for its input. The Workaround -------------- If you reverse the order of the 'pclose()' calls then the program works correctly, but this is not possible in the big program I am really trying to get work. The other Workaround -------------------- If you set the 'close_on_exec' flag on the 'file1' then the second gzip will not inheret open file handle. ex. fcntl(fileno(file1), F_SETFD, 1) This works, but is changes the semantics of popen(). What POSIX says --------------- /* Posix.2: "popen() shall ensure that any streams from previous popen() calls that remain open in the parent process are closed in the new child process." */ The Solution ------------ popen() already maintains a list of filehandles that have be previously returned. We just need to walk that list and close all the files. No need to deallocate the list because we are just about the exec() anyway. Index: popen.c =================================================================== RCS file: /home/ncvs/src/lib/libc/gen/popen.c,v retrieving revision 1.9 diff -u -r1.9 popen.c --- popen.c 1997/04/22 09:44:06 1.9 +++ popen.c 1998/09/02 18:47:49 @@ -62,6 +62,7 @@ struct pid *cur; FILE *iop; int pdes[2], pid, twoway; + struct pid *p; /* * Lite2 introduced two-way popen() pipes using socketpair(). @@ -115,6 +116,9 @@ (void)close(pdes[0]); } (void)close(pdes[1]); + } + for (p = pidlist; p; p = p->next) { + close(fileno(p->fp)); } execl(_PATH_BSHELL, "sh", "-c", command, NULL); I would love to have this fixed in the 3.0 release of FreeBSD. Note I sent the PR with the patch in plenty of time... Wayne Scott MD6 Architecture - Intel Corp. wscott@ichips.intel.com Work #: (503) 613-5063 Disclaimer: All views expressed are my own opinions, and not necessarily those of Intel Corporation. To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-current" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199810141425.HAA26802>