www.delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp-workers/2004/05/18/05:32:18

X-Authentication-Warning: delorie.com: mail set sender to djgpp-workers-bounces using -f
Date: Tue, 18 May 2004 12:30:45 +0300 (EET DST)
From: Esa A E Peuha <peuha AT cc DOT helsinki DOT fi>
Sender: peuha AT sirppi DOT helsinki DOT fi
To: djgpp-workers AT delorie DOT com
Subject: Re: Opening temporary files
In-Reply-To: <Pine.OSF.4.58.0404231046030.29213@sirppi.helsinki.fi>
Message-ID: <Pine.OSF.4.58.0405181213430.8274@sirppi.helsinki.fi>
References: <Pine DOT OSF DOT 4 DOT 58 DOT 0404231046030 DOT 29213 AT sirppi DOT helsinki DOT fi>
MIME-Version: 1.0
Reply-To: djgpp-workers AT delorie DOT com
Errors-To: nobody AT delorie DOT com
X-Mailing-List: djgpp-workers AT delorie DOT com
X-Unsubscribes-To: listserv AT delorie DOT com

On Fri, 23 Apr 2004, Esa A E Peuha wrote:

> The second is that popen should
> set the remove-on-close flag and filename on the files it opens, so that
> they will be removed even in case of abnormal exits.

Here's a patch to popen.c that will make its temporary files removed on
closing.  It actually restructures most of the file, because the old
code was pretty messy and hard to change (and it stored things in the
pipe_list structure for no reason):

Index: popen.c
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/posix/stdio/popen.c,v
retrieving revision 1.5
diff -u -r1.5 popen.c
--- popen.c	17 Oct 2002 23:00:25 -0000	1.5
+++ popen.c	18 May 2004 09:18:27 -0000
@@ -17,7 +17,7 @@
    I think I'm the first to give it away for free (no points?!).

    The functions simulate popen() and pclose() by redirecting stdin or
-   stdout, then spawning a child processes via system().
+   stdout, then spawning a child process via system().

    If you popen() for read, the stdout is redirected to a temporary
    file, and the child is spawned.  The stdout is reopened via dup2(), the
@@ -48,9 +48,6 @@
    Where command is a character string equivilant to a MSDOS command
    line, mode is "r" for read or "w" for write, and pp is a pointer to a
    file opened through popen().
-
-   A main() function has been included for testing purposes, to compile
-   it define the preprocessor token TEST at compile time.
  */

 #include <libc/stubs.h>
@@ -62,160 +59,188 @@
 #include <unistd.h>
 #include <libc/file.h>

-/* hold file pointer, descriptor, command, mode, temporary file name,
-   and the status of the command  */
+/* hold file pointer, command, mode, and the status of the command */
 struct pipe_list {
   FILE *fp;
-  int fd;
   int exit_status;
-  char *command, mode[10], temp_name[L_tmpnam];
+  char *command, mode[10];
   struct pipe_list *next;
 };

 /* static, global list pointer */
 static struct pipe_list *pl = NULL;

-FILE *
-popen (const char *cm, const char *md) /* program name, pipe mode */
+FILE *popen(const char *cm, const char *md) /* program name, pipe mode */
 {
   struct pipe_list *l1;
+  char *temp_name;

   /* make new node */
-  if ((l1 = (struct pipe_list *) malloc (sizeof (struct pipe_list))) == NULL)
+  if ((l1 = malloc(sizeof(*l1))) == NULL)
     return NULL;

-  /* zero out elements to we'll get here */
-  l1->fd = 0;
-  l1->fp = NULL;
-  l1->next = NULL;
-
   /* if empty list - just grab new node */
   l1->next = pl;
   pl = l1;

   /* stick in elements we know already */
-  l1->exit_status = -1;
-  strcpy (l1->mode, md);
-  if (tmpnam (l1->temp_name) == NULL)
-  {
-    pl = l1->next;
-    free (l1);
-    return NULL;
-  }
+  if ((temp_name = malloc(L_tmpnam)) == NULL)
+    goto error;
+
+  if (tmpnam(temp_name) == NULL)
+    goto error;
+
+  strcpy(l1->mode, md);

-  /* if can save the program name, build temp file */
-  if ((l1->command = malloc(strlen(cm)+1)))
+  if (l1->mode[0] == 'r')
+  /* caller wants to read */
   {
-    strcpy(l1->command, cm);
-    /* if caller wants to read */
-    if (l1->mode[0] == 'r')
-    {
-      /* dup stdout */
-      if ((l1->fd = dup (fileno (stdout))) == EOF)
-	l1->fp = NULL;
-      else if (!(l1->fp = freopen (l1->temp_name, "wb", stdout)))
-	l1->fp = NULL;
-      else
-	/* exec cmd */
-	if ((l1->exit_status = system (cm)) == EOF)
-	  l1->fp = NULL;
-      /* reopen real stdout */
-      if (dup2 (l1->fd, fileno (stdout)) == EOF)
-	l1->fp = NULL;
-      /* if cmd couldn't be run, make sure we return NULL */
-      else if (l1->exit_status != EOF)
-	/* open file for reader */
-	l1->fp = fopen (l1->temp_name, l1->mode);
-      close(l1->fd);
-    }
-    else
-      /* if caller wants to write */
-      if (l1->mode[0] == 'w')
-        /* open temp file */
-        l1->fp = fopen (l1->temp_name, l1->mode);
-      else
-        /* unknown mode */
-        l1->fp = NULL;
+    int fd;
+
+    /* dup stdout */
+    if ((fd = dup(fileno(stdout))) == -1)
+      goto error;
+
+    /* redirect stdout */
+    if (!(l1->fp = freopen(temp_name, "wb", stdout)))
+      goto error;
+
+    /* make sure file is removed on abnormal exit */
+    l1->fp->_flag |= _IORMONCL;
+    l1->fp->_name_to_remove = temp_name;

-    return l1->fp;
+    /* execute command */
+    l1->exit_status = system(cm);
+
+    /* don't remove file while closing */
+    l1->fp->_flag &= ~_IORMONCL;
+    l1->fp->_name_to_remove = NULL;
+
+    /* close file */
+    fclose(l1->fp);
+
+    /* reopen real stdout */
+    if (dup2(fd, fileno(stdout)) == -1)
+      goto error;
+
+    /* close duplicate stdout */
+    close(fd);
+
+    /* if cmd couldn't be run, make sure we return NULL */
+    if (l1->exit_status == -1)
+      goto error;
   }
-  else
+  else if (l1->mode[0] == 'w')
+  /* caller wants to write */
   {
-    pl = l1->next;
-    free (l1);
-    return NULL;
+    /* if can save the program name, build temp file */
+    if (!(l1->command = malloc(strlen(cm) + 1)))
+      goto error;
+
+    strcpy(l1->command, cm);
   }
+  else
+    /* unknown mode */
+    goto error;
+
+  /* open file for caller */
+  l1->fp = fopen(temp_name, l1->mode);
+
+  /* make sure file is removed on abnormal exit */
+  l1->fp->_flag |= _IORMONCL;
+  l1->fp->_name_to_remove = temp_name;
+
+  return l1->fp;
+
+ error:
+
+  if (l1->command)
+    free(l1->command);
+
+  if (temp_name)
+    free(temp_name);
+
+  pl = l1->next;
+  free(l1);
+
+  return NULL;
 }

-int
-pclose (FILE *pp)
+int pclose(FILE *pp)
 {
-  struct pipe_list *l1, *l2;    /* list pointers */
-  int retval=0;			/* function return value */
+  struct pipe_list *l1, **l2;	/* list pointers */
+  char *temp_name;		/* file name */
+  int retval = -1;		/* function return value */
+
+  for (l2 = &pl; *l2; l2 = &(*l2)->next)
+    if ((*l2)->fp == pp)
+      break;

-  if (!pl)
+  if (!*l2)
     return -1;

-  /* if pointer is first node */
-  if (pl->fp == pp)
-  {
-    /* save node and take it out the list */
-    l1 = pl;
-    pl = l1->next;
-  }
-  else
-    /* if more than one node in list */
-    if (pl->next)
-    {
-      /* find right node */
-      for (l2 = pl, l1 = pl->next; l1; l2 = l1, l1 = l2->next)
-        if (l1->fp == pp)
-          break;
+  l1 = *l2;
+  *l2 = l1->next;

-      /* take node out of list */
-      l2->next = l1->next;
-    }
-    else
-      return -1;
+  if (!(l1->fp->_flag & _IORMONCL))
+    /* file wasn't popen()ed */
+    return -1;
+  else
+    temp_name = l1->fp->_name_to_remove;

-  /* if FILE not in list - return error */
-  if (l1->fp == pp)
+  /* if pipe was opened to write */
+  if (l1->mode[0] == 'w')
   {
+    int fd;
+
+    /* don't remove file while closing */
+    l1->fp->_flag &= ~_IORMONCL;
+    l1->fp->_name_to_remove = NULL;
+
     /* close the (hopefully) popen()ed file */
-    fclose (l1->fp);
+    fclose(l1->fp);
+
+    /* dup stdin */
+    if ((fd = dup(fileno(stdin))) == -1)
+      goto exit;
+
+    /* redirect stdin */
+    if (!(l1->fp = freopen(temp_name, "rb", stdin)))
+      goto exit;
+
+    /* make sure file is removed on abnormal exit */
+    l1->fp->_flag |= _IORMONCL;
+    l1->fp->_name_to_remove = temp_name;
+
+    /* execute command */
+    retval = system(l1->command);

-    /* if pipe was opened to write */
-    if (l1->mode[0] == 'w')
+    /* reopen stdin */
+    if (dup2(fd, fileno(stdin)) == -1)
     {
-      /* dup stdin */
-      if ((l1->fd = dup (fileno (stdin))) == EOF)
-	retval = -1;
-      else
-	/* open temp stdin */
-	if (!(l1->fp = freopen (l1->temp_name, "rb", stdin)))
-	  retval = -1;
-	else
-	  /* exec cmd */
-          if ((retval = system (l1->command)) != EOF)
-	  {
-            /* reopen stdin */
-	    if (dup2 (l1->fd, fileno (stdin)) == EOF)
-	      retval = -1;
-	  }
-      close(l1->fd);
+      retval = -1;
+      goto exit;
     }
-    else
-      /* if pipe was opened to read, return the exit status we saved */
-      if (l1->mode[0] == 'r')
-        retval = l1->exit_status;
-      else
-        /* invalid mode */
-        retval = -1;
+
+    /* close duplicate stdin */
+    close(fd);
   }
-  remove (l1->temp_name);       /* remove temporary file */
-  free (l1->command);           /* dealloc memory */
-  free (l1);                    /* dealloc memory */
-  l1 = NULL;                    /* make pointer bogus */
+  /* if pipe was opened to read, return the exit status we saved */
+  else if (l1->mode[0] == 'r')
+    retval = l1->exit_status;
+  else
+    /* invalid mode */
+    retval = -1;
+
+ exit:
+
+  /* close and remove file */
+  fclose(l1->fp);
+
+  if (l1->command)
+    free(l1->command);
+
+  free(l1);

-  return retval;              /* retval==0 ? OK : ERROR */
+  return retval;
 }

-- 
Esa Peuha
student of mathematics at the University of Helsinki
http://www.helsinki.fi/~peuha/

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019