home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / gnu / glibc-1.06 / sysdeps / posix / pipestream.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-10-27  |  4.8 KB  |  185 lines

  1. /* Copyright (C) 1991, 1992 Free Software Foundation, Inc.
  2. This file is part of the GNU C Library.
  3.  
  4. The GNU C Library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Library General Public License as
  6. published by the Free Software Foundation; either version 2 of the
  7. License, or (at your option) any later version.
  8.  
  9. The GNU C Library is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  12. Library General Public License for more details.
  13.  
  14. You should have received a copy of the GNU Library General Public
  15. License along with the GNU C Library; see the file COPYING.LIB.  If
  16. not, write to the Free Software Foundation, Inc., 675 Mass Ave,
  17. Cambridge, MA 02139, USA.  */
  18.  
  19. #include <ansidecl.h>
  20. #include <errno.h>
  21. #include <stddef.h>
  22. #include <signal.h>
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <sys/types.h>
  26. #include <sys/wait.h>
  27. #include <unistd.h>
  28. #include <fcntl.h>
  29.  
  30. #define    SH_PATH    "/bin/sh"    /* Shell to run.  */
  31. #define    SH_NAME    "sh"        /* Name to give it.  */
  32.  
  33. /* Structure describing a popen child.  */
  34. struct child
  35.   {
  36.     /* It is important that the first member of this structure be an `int' that
  37.        is the file descriptor.  This is because the `fileno' function assumes
  38.        that __cookie(STREAM) points to the file descriptor.  */
  39.     int fd;
  40.     pid_t pid;
  41.   };
  42.  
  43. /* Open a new stream that is a one-way pipe to a
  44.    child process running the given shell command.  */
  45. FILE *
  46. DEFUN(popen, (command, mode), CONST char *command AND CONST char *mode)
  47. {
  48.   pid_t pid;
  49.   int pipedes[2];
  50.   FILE *stream;
  51.   struct child *child;
  52.  
  53.   if (command == NULL || mode == NULL || (*mode != 'r' && *mode != 'w'))
  54.     {
  55.       errno = EINVAL;
  56.       return NULL;
  57.     }
  58.  
  59.   /* Create the pipe.  */
  60.   if (pipe(pipedes) < 0)
  61.     return NULL;
  62.  
  63.   /* Fork off the child.  */
  64.   pid = __vfork ();
  65.   if (pid == (pid_t) -1)
  66.     {
  67.       /* The fork failed.  */
  68.       (void) close (pipedes[0]);
  69.       (void) close (pipedes[1]);
  70.       return NULL;
  71.     }
  72.   else if (pid == (pid_t) 0)
  73.     {
  74.       /* We are the child side.  Make the write side of
  75.      the pipe be stdin or the read side be stdout.  */
  76.  
  77.       CONST char *new_argv[4];
  78.  
  79.       if ((*mode == 'w' ? dup2(pipedes[STDIN_FILENO], STDIN_FILENO) :
  80.       dup2(pipedes[STDOUT_FILENO], STDOUT_FILENO)) < 0)
  81.     _exit(127);
  82.  
  83.       /* Close the pipe descriptors.  */
  84.       (void) close(pipedes[STDIN_FILENO]);
  85.       (void) close(pipedes[STDOUT_FILENO]);
  86.  
  87.       /* Exec the shell.  */
  88.       new_argv[0] = SH_NAME;
  89.       new_argv[1] = "-c";
  90.       new_argv[2] = command;
  91.       new_argv[3] = NULL;
  92.       (void) execve(SH_PATH, (char *CONST *) new_argv, environ);
  93.       /* Die if it failed.  */
  94.       _exit(127);
  95.     }
  96.  
  97.   /* We are the parent side.  */
  98.  
  99.   /* Close the irrelevant side of the pipe and open the relevant side as a
  100.      new stream.  Mark our side of the pipe to close on exec, so new children
  101.      won't see it.  */
  102.   if (*mode == 'r')
  103.     {
  104.       (void) close(pipedes[STDOUT_FILENO]);
  105.       (void) fcntl (pipedes[STDIN_FILENO], F_SETFD, FD_CLOEXEC);
  106.       stream = fdopen(pipedes[STDIN_FILENO], mode);
  107.     }
  108.   else
  109.     {
  110.       (void) close(pipedes[STDIN_FILENO]);
  111.       (void) fcntl (pipedes[STDOUT_FILENO], F_SETFD, FD_CLOEXEC);
  112.       stream = fdopen(pipedes[STDOUT_FILENO], mode);
  113.     }
  114.  
  115.   if (stream == NULL)
  116.     goto error;
  117.  
  118.   child = (struct child *) malloc(sizeof(struct child));
  119.   if (child == NULL)
  120.     goto error;
  121.   child->fd = fileno(stream);
  122.   child->pid = pid;
  123.   stream->__cookie = (PTR) child;
  124.   stream->__ispipe = 1;
  125.   return stream;
  126.  
  127.  error:;
  128.   {
  129.     /* The stream couldn't be opened or the child structure couldn't be
  130.        allocated.  Kill the child and close the other side of the pipe.  */
  131.     int save = errno;
  132.     (void) kill(pid, SIGKILL);
  133.     if (stream == NULL)
  134.       (void) close(pipedes[*mode == 'r' ? STDOUT_FILENO : STDIN_FILENO]);
  135.     else
  136.       (void) fclose(stream);
  137. #ifndef    NO_WAITPID
  138.     (void) waitpid(pid, (int *) NULL, 0);
  139. #else
  140.     {
  141.       pid_t dead;
  142.       do
  143.     dead = wait ((int *) NULL);
  144.       while (dead > 0 && dead != pid);
  145.     }
  146. #endif
  147.     errno = save;
  148.     return NULL;
  149.   }
  150. }
  151.  
  152. /* Close a stream opened by popen and return its status.
  153.    Returns -1 if the stream was not opened by popen.  */
  154. int
  155. DEFUN(pclose, (stream), register FILE *stream)
  156. {
  157.   pid_t pid, dead;
  158.   int status;
  159.  
  160.   if (!__validfp(stream) || !stream->__ispipe)
  161.     {
  162.       errno = EINVAL;
  163.       return -1;
  164.     }
  165.  
  166.   pid = ((struct child *) stream->__cookie)->pid;
  167.   free(stream->__cookie);
  168.   stream->__cookie = (PTR) &stream->__fileno;
  169.   stream->__ispipe = 0;
  170.   if (fclose(stream))
  171.     return -1;
  172.  
  173. #ifndef    NO_WAITPID
  174.   dead = waitpid (pid, &status, 0);
  175. #else
  176.   do
  177.     dead = wait (&status);
  178.   while (dead > 0 && dead != pid);
  179. #endif
  180.   if (dead != pid)
  181.     status = -1;
  182.  
  183.   return status;
  184. }
  185.