Logo Search packages:      
Sourcecode: man-db version File versions

popen.c

/* popen.c: pipe open and close functions.
 *
 * Copyright (C) 1994, 1995 Graeme W. Wilford. (Wilf.)
 *
 * This file is part of man-db.
 *
 * man-db is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * man-db is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with man-db; if not, write to the Free Software Foundation,
 * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * Originally by Wilf. (G.Wilford@ee.surrey.ac.uk)
 * Colin Watson moved this from src/man.c to a separate library file.
 */

#ifdef HAVE_CONFIG_H
#  include "config.h"
#endif /* HAVE_CONFIG_H */

#include <stdio.h>

#ifdef STDC_HEADERS
#  include <string.h>
#  include <stdlib.h>
#elif defined(HAVE_STRING_H)
#  include <string.h>
#elif defined(HAVE_STRINGS_H)
#  include <strings.h>
#endif /* STDC_HEADERS */
#ifdef HAVE_UNISTD_H
#  include <unistd.h>
#endif /* HAVE_UNISTD_H */

#include <errno.h>
#include <signal.h>
#include <sys/types.h>

#ifdef HAVE_SYS_WAIT_H
#  include <sys/wait.h>
#endif /* HAVE_SYS_WAIT_H */

/* Some pclose(), notably Ultrix's get confused if we use more than one
   concurrently, blech.  Define our own popen()/pclose() combo. */

static pid_t *fd2pid = NULL;  /* map fd to pid, unused entries are zero */
static int max_fd = -1;       /* max fd seen, fd2pid has max_fd+1 elements */

FILE *
popen (const char *cmd, const char *type)
{
      pid_t child;
      int for_reading;
      int pipe_fd[2];
      int fd;
      FILE *stream;

      /* check type */
      if (type && (type[0] == 'r'))
            for_reading = 1;
      else if (type && (type[0] == 'w'))
            for_reading = 0;
      else
            return NULL;

      if (pipe (pipe_fd))
            return NULL;

      child = vfork ();
      if (child == -1) {
            close (pipe_fd[0]);
            close (pipe_fd[1]);
            return NULL;
      } else if (child == 0) {
            /* if for_reading connect the writing end of pipe to stdout
               else the reading end to stdin */
            if (dup2 (pipe_fd[for_reading], for_reading) == -1)
                  _exit (127);

            /* close pipe fds */
            close (pipe_fd[0]);
            close (pipe_fd[1]);

            /* exec cmd in a shell */
            execl ("/bin/sh", "sh", "-c", cmd, NULL);
            /* if we hit this, execl() failed */
            _exit (127);
      }

      /* if for_reading make a stream from the reading end of pipe
         else from the writing end */
      fd = pipe_fd[!for_reading];
      close (pipe_fd[for_reading]);
      stream = fdopen (fd, type);

      /* extend fd2pid up to index fd if necessary */
      if (fd > max_fd) {
            pid_t *new = malloc ((fd + 1) * sizeof (pid_t));
            if (new) {
                  /* copy old entries */
                  memcpy (new, fd2pid, (max_fd + 1) * sizeof (pid_t));
                  /* zero new entries */
                  memset (new+max_fd+1, 0,
                        (fd - max_fd) * sizeof (pid_t));
                  fd2pid = new;
                  max_fd = fd;
            }
      }

      /* if we didn't get the stream or couldn't extend fd2pid, clean up & fail */
      if (!stream || (fd > max_fd)) {
            int res;
            int save = errno;

            kill (child, SIGKILL);

            if (stream)
                  fclose (stream);
            else
                  close (fd);

            do {        /* cope with non-restarting system calls */
                  res = waitpid (child, NULL, 0);
            } while ((res == -1) && (errno == EINTR));

            errno = save;
            return NULL;
      }

      fd2pid[fd] = child;           /* save pid for pclose() */
      return stream;
}


int
pclose (FILE *stream)
{
      int fd = fileno (stream);
      pid_t child;
      int status;
      int res;
      int save;

      if ((fd > max_fd) || !fd2pid[fd])
            return -1;
      child = fd2pid[fd];
      fd2pid[fd] = 0;

      if (fclose (stream))
            return -1;

      save = errno;
      do {              /* cope with non-restarting system calls */
            res = waitpid (child, &status, 0);
      } while ((res == -1) && (errno == EINTR));
      if (res != -1) errno = save;

      return status;
}

Generated by  Doxygen 1.6.0   Back to index