| /* |
| * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 <unistd.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <errno.h> |
| #include <signal.h> |
| #include <sys/wait.h> |
| |
| /* 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, (struct sigaction *) 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); |
| } |