From e93869ad4ae4ba81235a53857e5f2255f104adfb Mon Sep 17 00:00:00 2001 From: roland Date: Mon, 1 Jul 1991 22:30:15 +0000 Subject: [PATCH] Initial revision --- sysdeps/posix/pipestream.c | 171 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 171 insertions(+) create mode 100644 sysdeps/posix/pipestream.c diff --git a/sysdeps/posix/pipestream.c b/sysdeps/posix/pipestream.c new file mode 100644 index 0000000000..e5103cfbdf --- /dev/null +++ b/sysdeps/posix/pipestream.c @@ -0,0 +1,171 @@ +/* Copyright (C) 1991 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SH_PATH "/bin/sh" /* Shell to run. */ +#define SH_NAME "sh" /* Name to give it. */ + +/* Structure describing a popen child. */ +struct child + { + /* It is important that the first member of this structure be an `int' that + is the file descriptor. This is because the `fileno' function assumes + that __cookie(STREAM) points to the file descriptor. */ + int fd; + pid_t pid; + }; + +#ifndef FORK +#define FORK fork +#endif + +/* Open a new stream that is a one-way pipe to a + child process running the given shell command. */ +FILE * +DEFUN(popen, (command, mode), CONST char *command AND CONST char *mode) +{ + pid_t pid; + int pipedes[2]; + FILE *stream; + struct child *child; + + if (command == NULL || mode == NULL || (*mode != 'r' && *mode != 'w')) + { + errno = EINVAL; + return NULL; + } + + /* Create the pipe. */ + if (pipe(pipedes) < 0) + return NULL; + + /* Fork off the child. */ + pid = FORK(); + if (pid == (pid_t) -1) + { + /* The fork failed. */ + (void) close(pipedes[0]); + (void) close(pipedes[1]); + return NULL; + } + else if (pid == (pid_t) 0) + { + /* We are the child side. Make the write side of + the pipe be stdin or the read side be stdout. */ + + CONST char *new_argv[4]; + + if ((*mode == 'r' ? dup2(pipedes[STDIN_FILENO], STDOUT_FILENO) : + dup2(pipedes[STDOUT_FILENO], STDIN_FILENO)) < 0) + _exit(127); + + /* Close the pipe descriptors. */ + (void) close(pipedes[STDIN_FILENO]); + (void) close(pipedes[STDOUT_FILENO]); + + /* Exec the shell. */ + new_argv[0] = SH_NAME; + new_argv[1] = "-c"; + new_argv[2] = command; + new_argv[3] = NULL; + (void) execve(SH_PATH, (char *CONST *) new_argv, environ); + /* Die if it failed. */ + _exit(127); + } + + /* We are the parent side. */ + + /* Close the irrelevant side of the pipe and open the relevant side as a + new stream. Mark our side of the pipe to close on exec, so new popen + children won't see it. */ + if (*mode == 'r') + { + (void) close(pipedes[STDOUT_FILENO]); + (void) fcntl (pipedes[STDIN_FILENO], F_SETFD, FD_CLOEXEC); + stream = fdopen(pipedes[STDIN_FILENO], mode); + } + else + { + (void) close(pipedes[STDIN_FILENO]); + (void) fcntl (pipedes[STDOUT_FILENO], F_SETFD, FD_CLOEXEC); + stream = fdopen(pipedes[STDOUT_FILENO], mode); + } + + if (stream == NULL) + goto error; + + child = (struct child *) malloc(sizeof(struct child)); + if (child == NULL) + goto error; + child->fd = fileno(stream); + child->pid = pid; + stream->__cookie = (PTR) child; + stream->__ispipe = 1; + return stream; + + error:; + { + /* The stream couldn't be opened or the child structure couldn't be + allocated. Kill the child and close the other side of the pipe. */ + int save = errno; + (void) kill(pid, SIGKILL); + if (stream == NULL) + (void) close(pipedes[*mode == 'r' ? STDOUT_FILENO : STDIN_FILENO]); + else + (void) fclose(stream); + (void) waitpid(pid, (int *) NULL, 0); + errno = save; + return NULL; + } +} + +/* Close a stream opened by popen and return its status. + Returns -1 if the stream was not opened by popen. */ +int +DEFUN(pclose, (stream), register FILE *stream) +{ + pid_t pid; + int status; + + if (!__validfp(stream) || !stream->__ispipe) + { + errno = EINVAL; + return -1; + } + + pid = ((struct child *) stream->__cookie)->pid; + free(stream->__cookie); + stream->__cookie = (PTR) &stream->__fileno; + stream->__ispipe = 0; + if (fclose(stream)) + return -1; + + if (waitpid(pid, &status, 0) != pid) + status = -1; + return status; +} -- 2.11.0