[Python-bugs-list] [Bug #110702] closing a popen file descriptor (PR#33)
noreply@sourceforge.net
noreply@sourceforge.net
Fri, 25 Aug 2000 15:35:53 -0700
Bug #110702, was updated on 2000-Jul-31 14:29
Here is a current snapshot of the bug.
Project: Python
Category: Modules
Status: Open
Resolution: None
Bug Group: Platform-specific
Priority: 5
Summary: closing a popen file descriptor (PR#33)
Details: Jitterbug-Id: 33
Submitted-By: laik@cs.stanford.edu
Date: Tue, 20 Jul 1999 14:00:11 -0400 (EDT)
Version: 1.5.2
OS: Linux 2.2.10
I can't close a pipe's file descriptor without an error:
>>> import os
>>> p1 = os.popen("cat dummy1", "r")
>>> p2 = os.popen("cat dummy2", "r")
>>> p1.close()
Traceback (innermost last):
File "<stdin>", line 1, in ?
IOError: (0, 'Error')
It only happens if I do two or more popens. If I try to close any file
descriptor
but the last one I opened, I get this mysterious IOError. It happens regardless
of the order I try to close the descriptors.
====================================================================
Audit trail:
Sat Jul 24 17:02:54 1999 guido sent reply 1
Sat Jul 24 17:03:22 1999 guido changed notes
Sat Jul 24 17:03:22 1999 guido moved from incoming to open
Sat Jul 24 17:05:25 1999 guido moved from open to platformbug
Follow-Ups:
Date: 2000-Aug-01 14:03
By: none
Comment:
From: Guido van Rossum <bugs-py@python.org>
Subject: Re: closing a popen file descriptor (PR#33)
Date: Sat Jul 24 17:02:54 1999
> Full_Name: Kevin Lai
> Version: 1.5.2
> OS: Linux 2.2.10
> Submission from: (NULL) (192.25.214.6)
>
>
> I can't close a pipe's file descriptor without an error:
>
>>>> import os
>>>> p1 = os.popen("cat dummy1", "r")
>>>> p2 = os.popen("cat dummy2", "r")
>>>> p1.close()
> Traceback (innermost last):
> File "<stdin>", line 1, in ?
> IOError: (0, 'Error')
>
> It only happens if I do two or more popens. If I try to close any file
> descriptor
> but the last one I opened, I get this mysterious IOError. It happens
regardless
> of the order I try to close the descriptors.
Kevin, this works on other platforms I can try (Solaris 2.6, linux 2.0.34).
One possibility is that the C library in the Linux version you are using
has changed; the IOError means that its pclose() returns an error indicator.
The (0, 'Error') message means that pclose() didn't set the errno variable.
It could be a bug in the Linux C library, or a change in interface that
requires Python to interpret the error return differently.
Can you help us discover which is the case? Does the man page for pclose()
say anything about this? Does this fail in an equivalent C program?
--Guido van Rossum
-------------------------------------------------------
Date: 2000-Aug-01 14:03
By: none
Comment:
From: laik@tnt.Stanford.EDU
Subject: Re: closing a popen file descriptor (PR#33)
Date: Tue, 27 Jul 1999 01:41:15 -0700
Guido,
Thanks for your quick reply. As far as I can tell, the man page for
pclose() doesn't mention any API changes. I have included the popen()
and wait4() man pages for the system I am using (PII 300, Linux
2.2.10, glibc 2.1.1).
I have written a short C program which tries to exercise the bug. On my
system, it gives these results:
[laik@nebraska]~>gcc popen.c
[laik@nebraska]~>a.out
pclose(p1): 0, WIFEXITED: 1, WEXITSTATUS:0, WIFSIGNALED:0
pclose(p2): 0, WIFEXITED: 1, WEXITSTATUS:0, WIFSIGNALED:0
pclose(p3): 0, WIFEXITED: 1, WEXITSTATUS:0, WIFSIGNALED:0
On a Linux 2.0.33, glibc 2.0.7 system, it gives the same
results. However, my system exhibits the problem under Python, while
the other does not. I conclude that my C program doesn't mimic the
Python program well enough to trigger the bug, but I don't know how to
fix that.
#include <stdio.h>
#define _USE_BSD
#include <sys/types.h>
#include <sys/resource.h>
#include <sys/wait.h>
main()
{
FILE *p1, *p2, *p3;
int pc1, pc2, pc3;
p1 = popen("ls", "r");
p2 = popen("ls", "r");
p3 = popen("ls", "r");
sleep(1);
pc1 = pclose(p1);
printf("pclose(p1): %d, WIFEXITED: %d, WEXITSTATUS:%d, WIFSIGNALED:%d\n",
pc1, WIFEXITED(pc1), WEXITSTATUS(pc1), WIFSIGNALED(pc1));
pc2 = pclose(p2);
printf("pclose(p2): %d, WIFEXITED: %d, WEXITSTATUS:%d, WIFSIGNALED:%d\n",
pc1, WIFEXITED(pc2), WEXITSTATUS(pc2), WIFSIGNALED(pc2));
pc3 = pclose(p3);
printf("pclose(p3): %d, WIFEXITED: %d, WEXITSTATUS:%d, WIFSIGNALED:%d\n",
pc3, WIFEXITED(pc3), WEXITSTATUS(pc3), WIFSIGNALED(pc3));
}
POPEN(3) Linux Programmer's Manual POPEN(3)
NAME
popen, pclose - process I/O
SYNOPSIS
#include <stdio.h>
FILE *popen(const char *command, const char *type);
int pclose(FILE *stream);
DESCRIPTION
The popen() function opens a process by creating a pipe,
forking, and invoking the shell. Since a pipe is by defi-
nition unidirectional, the type argument may specify only
reading or writing, not both; the resulting stream is cor-
respondingly read-only or write-only.
The command argument is a pointer to a null-terminated
string containing a shell command line. This command is
passed to /bin/sh using the -c flag; interpretation, if
any, is performed by the shell. The mode argument is a
pointer to a null-terminated string which must be either
`r' for reading or `w' for writing.
The return value from popen() is a normal standard I/O
stream in all respects save that it must be closed with
pclose() rather than fclose(). Writing to such a stream
writes to the standard input of the command; the command's
standard output is the same as that of the process that
called popen(), unless this is altered by the command
itself. Conversely, reading from a ``popened'' stream
reads the command's standard output, and the command's
standard input is the same as that of the process that
called popen.
Note that output popen streams are fully buffered by
default.
The pclose function waits for the associated process to
terminate and returns the exit status of the command as
returned by wait4.
RETURN VALUE
The popen function returns NULL if the fork(2) or pipe(2)
calls fail, or if it cannot allocate memory.
The pclose function returns -1 if wait4 returns an error,
or some other error is detected.
ERRORS
The popen function does not set errno if memory allocation
fails. If the underlying fork() or pipe() fails, errno is
set appropriately. If the mode argument is invalid, and
this condition is detected, errno is set to EINVAL.
If pclose() cannot obtain the child status, errno is set
to ECHILD.
CONFORMING TO
POSIX.2
BUGS
Since the standard input of a command opened for reading
shares its seek offset with the process that called
popen(), if the original process has done a buffered read,
the command's input position may not be as expected. Sim-
ilarly, the output from a command opened for writing may
become intermingled with that of the original process.
The latter can be avoided by calling fflush(3) before
popen.
Failure to execute the shell is indistinguishable from the
shell's failure to execute command, or an immediate exit
of the command. The only hint is an exit status of 127.
HISTORY
A popen() and a pclose() function appeared in Version 7
AT&T UNIX.
SEE ALSO
fork(2), sh(1), pipe(2), wait4(2), fflush(3), fclose(3),
fopen(3), stdio(3), system(3).
BSD MANPAGE 7 May 1998 1
WAIT4(2) Linux Programmer's Manual WAIT4(2)
NAME
wait3, wait4 - wait for process termination, BSD style
SYNOPSIS
#define _USE_BSD
#include <sys/types.h>
#include <sys/resource.h>
#include <sys/wait.h>
pid_t wait3(int *status, int options,
struct rusage *rusage)
pid_t wait4(pid_t pid, int *status, int options,
struct rusage *rusage)
DESCRIPTION
The wait3 function suspends execution of the current pro-
cess until a child has exited, or until a signal is deliv-
ered whose action is to terminate the current process or
to call a signal handling function. If a child has
already exited by the time of the call (a so-called "zom-
bie" process), the function returns immediately. Any sys-
tem resources used by the child are freed.
The wait4 function suspends execution of the current pro-
cess until a child as specified by the pid argument has
exited, or until a signal is delivered whose action is to
terminate the current process or to call a signal handling
function. If a child as requested by pid has already
exited by the time of the call (a so-called "zombie" pro-
cess), the function returns immediately. Any system
resources used by the child are freed.
The value of pid can be one of:
< -1 which means to wait for any child process whose
process group ID is equal to the absolute value of
pid.
-1 which means to wait for any child process; this is
equivalent to calling wait3.
0 which means to wait for any child process whose
process group ID is equal to that of the calling
process.
> 0 which means to wait for the child whose process ID
is equal to the value of pid.
The value of options is a bitwise OR of zero or more of
the following constants:
WNOHANG which means to return immediately if no child is
there to be waited for.
WUNTRACED
which means to also return for children which are
stopped, and whose status has not been reported.
If status is not NULL, wait3 or wait4 store status infor-
mation in the location pointed to by status.
This status can be evaluated with the following macros
(these macros take the stat buffer (an int) as an argument
-- not a pointer to the buffer!):
WIFEXITED(status)
is non-zero if the child exited normally.
WEXITSTATUS(status)
evaluates to the least significant eight bits of
the return code of the child which terminated,
which may have been set as the argument to a call
to exit() or as the argument for a return state-
ment in the main program. This macro can only be
evaluated if WIFEXITED returned non-zero.
WIFSIGNALED(status)
returns true if the child process exited because
of a signal which was not caught.
WTERMSIG(status)
returns the number of the signal that caused the
child process to terminate. This macro can only be
evaluated if WIFSIGNALED returned non-zero.
WIFSTOPPED(status)
returns true if the child process which caused the
return is currently stopped; this is only possible
if the call was done using WUNTRACED.
WSTOPSIG(status)
returns the number of the signal which caused the
child to stop. This macro can only be evaluated
if WIFSTOPPED returned non-zero.
If rusage is not NULL, the struct rusage as
defined in <sys/resource.h> it points to will be
filled with accounting information. See
getrusage(2) for details.
RETURN VALUE
The process ID of the child which exited, -1 on error (in
particular, when no unwaited-for child processes of the
specified kind exist) or zero if WNOHANG was used and no
child was available yet. In the latter two cases errno
will be set appropriately.
ERRORS
ECHILD No unwaited-for child process as specified does
exist.
ERESTARTSYS
if WNOHANG was not set and an unblocked signal or a
SIGCHLD was caught. This error is returned by the
system call. The library interface is not allowed
to return ERESTARTSYS, but will return EINTR.
CONFORMING TO
SVr4, POSIX.1
SEE ALSO
signal(2), getrusage(2), wait(2), signal(7)
Linux 23 June 1997 1
-------------------------------------------------------
Date: 2000-Aug-01 14:03
By: none
Comment:
Perhaps a bug or interface change in Linux popen()?
-------------------------------------------------------
For detailed info, follow this link:
http://sourceforge.net/bugs/?func=detailbug&bug_id=110702&group_id=5470