/* * Copyright (C) Bull S.A. 1996 * Copyright (c) International Business Machines Corp., 2001 * * This program 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. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /*---------------------------------------------------------------------+ | pipe_test_01 | | ==================================================================== | | | | Description: Simplistic test to verify the pipe system function | | calls | | | | Algorithm: o Create a pipe | | o Spawn a child process & exec cat on a file. | | Redirect the command output to the write end of the | | pipe. | | o Spawn another child, redirect the read end of the | | pipe to stdin & exec wc. | | | | Equivalent to following shell command: | | cat /etc/rc | wc -c | | | | System calls: The following system calls are tested: | | | | pipe () - Creates an interprocess channel | | fork () - Creates a new process | | dup2 () - Controls open file descriptors | | execl () - Executes a file | | waitpid () - Waits for a child process to stop or | | terminate | | | | Usage: pipe_test_01 | | | | To compile: cc -o pipe_test_01 pipe_test_01.c | | | | Last update: Ver. 1.2, 2/13/94 22:42:00 | | | | Change Activity | | | | Version Date Name Reason | | 0.1 032289 CTU Initial version | | 0.2 010393 DJK Rewrite for AIX version 4.1 | | 1.2 021394 DJK Move to prod directory | | | +---------------------------------------------------------------------*/ #include #include #include #include #include #include #include /* Function prototypes */ void sys_error(const char *, int); /* System error message function */ void error(const char *, int); /* Error message function */ void setup_handler(); /* Sets up signal catching function */ void handler(int, int, struct sigcontext *); /* Signal catching function */ /*---------------------------------------------------------------------+ | main () | | ==================================================================== | | | | Function: Main program (see prolog for more details) | | | +---------------------------------------------------------------------*/ int main(int argc, char **argv) { int pid[2]; /* Child process ids */ int fd[2]; /* Pipe file descriptors */ int status; /* Child's exit status */ enum { READ, WRITE }; /* Constants */ enum { childA, childB }; /* * Setup signal catching function for SIGPIPE in case an * error occurs */ setup_handler(); /* * Create a Pipe for data transfer between the two child * processes. */ if (pipe(fd) < 0) sys_error("pipe failed", __LINE__); /* * Create child process, run command and write info into pipe. * * Close the read end of the pipe and dup the stdout to the write * end of the pipe, so the the output of the exec'd command will * be written into the pipe. Then exec the cat command. */ if ((pid[childA] = fork()) < 0) sys_error("fork failed", __LINE__); if (pid[childA] == 0) { /* Child process */ close(fd[READ]); /* Redirect STDOUT to fd [WRITE] */ if (fd[WRITE] != STDOUT_FILENO) { if (dup2(fd[WRITE], STDOUT_FILENO) != STDOUT_FILENO) sys_error("dup2 failed", __LINE__); } close(fd[WRITE]); /* Vernon Mauery 6/1/2001 changed path and file to work will more flavors of unix */ execl("/bin/cat", "cat", "/etc/inittab", NULL); sys_error("execl failed (should not reach this line) ", __LINE__); } /* * Create another child process and run command on data passed though * the pipe. * * Close the write end of the pipe and dup the read end of the pipe * to stdin, so that the input of the exec'd command will come * from the pipe. Then exec the wc command. */ if ((pid[childB] = fork()) < 0) sys_error("fork failed", __LINE__); if (pid[childB] == 0) { /* Child process */ close(fd[WRITE]); if (fd[READ] != STDIN_FILENO) { if (dup2(fd[READ], STDIN_FILENO) != STDIN_FILENO) sys_error("dup2 failed", __LINE__); } close(fd[READ]); execl("/usr/bin/wc", "wc", "-c", NULL); sys_error("execl failed (should not reach this line) ", __LINE__); } /* * Close both ends of the pipe and wait for the child processes * to complete. */ close(fd[READ]); close(fd[WRITE]); waitpid(pid[childA], &status, 0); if (!WIFEXITED(status)) sys_error("child process A terminated abnormally", __LINE__); waitpid(pid[childB], &status, 0); if (!WIFEXITED(status)) sys_error("child process B terminated abnormally", __LINE__); /* Program completed successfully -- exit */ return (0); } /*---------------------------------------------------------------------+ | setup_handler () | | ==================================================================== | | | | Function: Setup the signal handler for SIGPIPE. | | | +---------------------------------------------------------------------*/ void setup_handler() { struct sigaction invec; invec.sa_handler = (void (*)(int))handler; sigemptyset(&invec.sa_mask); invec.sa_flags = 0; if (sigaction(SIGPIPE, &invec, NULL) < 0) sys_error("sigaction failed", __LINE__); } /*---------------------------------------------------------------------+ | handler () | | ==================================================================== | | | | Function: Signal catching function for SIGPIPE signal. | | | | Returns: Aborts program & prints message upon receiving signal. | | | +---------------------------------------------------------------------*/ void handler(int sig, int code, struct sigcontext *scp) { error("wrote to pipe with closed read end", __LINE__); } /*---------------------------------------------------------------------+ | sys_error () | | ==================================================================== | | | | Function: Creates system error message and calls error () | | | +---------------------------------------------------------------------*/ void sys_error(const char *msg, int line) { char syserr_msg[256]; sprintf(syserr_msg, "%s: %s\n", msg, strerror(errno)); error(syserr_msg, line); } /*---------------------------------------------------------------------+ | error () | | ==================================================================== | | | | Function: Prints out message and exits... | | | +---------------------------------------------------------------------*/ void error(const char *msg, int line) { fprintf(stderr, "ERROR [line: %d] %s\n", line, msg); exit(-1); }