Mail Archives: djgpp-workers/1997/11/21/08:05:48
Hi Workers!
It's time to update popen()/pclose() again :-) I've found a bug in
pclose: if you write something like this: pclose (stdin), you will
get a SIGSEGV. After looking at the code, I decided to reimplement
the whole stuff, because the original code seems too unsafe for me.
I added a new feature too, popen-ed but not pclose-d files are
removed when the program exits.
However I have a question: if you look at the line with '!!!' in
pclose, could you tell me why I have to include that line? I don't
understand why fflush is not enough. Any idea?
Laszlo
ps: I don't use diff because I changed every line :) but the
copyright message.
[Here is the original copyright stuff]
#include <libc/stubs.h>
#include <io.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <libc/file.h>
/* hold file pointer, command, mode, and the status of the command */
struct pipe_list {
FILE *fp;
int exit_status;
struct pipe_list *next;
char *command, mode;
};
/* static, global list pointer */
static struct pipe_list *pl = NULL;
FILE *
popen (const char *cm, const char *md) /* program name, pipe mode */
{
struct pipe_list *l1;
int fd;
char *temp_name=NULL;
/* make new node */
if ((l1 = (struct pipe_list *) malloc (sizeof (*l1)))
&& (temp_name = strdup (tmpnam (0))))
{
l1->fp = NULL;
l1->command = NULL;
l1->next = pl;
l1->exit_status = -1;
l1->mode = md[0];
/* if caller wants to read */
if (md[0] == 'r' && (fd = dup (fileno (stdout))) >= 0)
{
if ((l1->fp = freopen (temp_name, "wb", stdout)))
{
l1->exit_status = system (cm);
if (dup2 (fd, fileno (stdout)) >= 0)
l1->fp = fopen (temp_name, md);
}
close (fd);
}
/* if caller wants to write */
else if (md[0] == 'w' && (l1->command = strdup (cm)))
l1->fp = fopen (temp_name, md);
if (l1->fp)
{
l1->fp->_flag |= _IORMONCL; /* remove on close */
l1->fp->_name_to_remove = temp_name;
return (pl = l1)->fp;
}
free (l1->command);
}
free (temp_name);
free (l1);
return NULL;
}
int
pclose (FILE *pp)
{
struct pipe_list *l1, **l2; /* list pointers */
int retval=-1; /* function return value */
for (l2 = &pl; *l2 && (*l2)->fp != pp; l2 = &((*l2)->next))
;
if (!(l1 = *l2))
return retval;
*l2 = l1->next;
/* if pipe was opened to write */
if (l1->mode == 'w')
{
int fd;
fflush (l1->fp);
close (fileno (l1->fp)); /* !!! Ugly, but needed !!! */
if ((fd = dup (fileno (stdin))) >= 0
&& (freopen (l1->fp->_name_to_remove, "rb", stdin)))
{
retval = system (l1->command);
dup2 (fd, fileno (stdin));
}
close (fd);
free (l1->command);
}
else
/* if pipe was opened to read, return the exit status we saved */
retval = l1->exit_status;
fclose (l1->fp); /* this removes the temp file */
free (l1);
return retval; /* retval==0 ? OK : ERROR */
}
- Raw text -