1/* 2 * Copyright (C) Bull S.A. 1996 3 * Copyright (c) International Business Machines Corp., 2001 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 13 * the GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 */ 19/*---------------------------------------------------------------------+ 20| pipe_test_01 | 21| ==================================================================== | 22| | 23| Description: Simplistic test to verify the pipe system function | 24| calls | 25| | 26| Algorithm: o Create a pipe | 27| o Spawn a child process & exec cat on a file. | 28| Redirect the command output to the write end of the | 29| pipe. | 30| o Spawn another child, redirect the read end of the | 31| pipe to stdin & exec wc. | 32| | 33| Equivalent to following shell command: | 34| cat /etc/rc | wc -c | 35| | 36| System calls: The following system calls are tested: | 37| | 38| pipe () - Creates an interprocess channel | 39| fork () - Creates a new process | 40| dup2 () - Controls open file descriptors | 41| execl () - Executes a file | 42| waitpid () - Waits for a child process to stop or | 43| terminate | 44| | 45| Usage: pipe_test_01 | 46| | 47| To compile: cc -o pipe_test_01 pipe_test_01.c | 48| | 49| Last update: Ver. 1.2, 2/13/94 22:42:00 | 50| | 51| Change Activity | 52| | 53| Version Date Name Reason | 54| 0.1 032289 CTU Initial version | 55| 0.2 010393 DJK Rewrite for AIX version 4.1 | 56| 1.2 021394 DJK Move to prod directory | 57| | 58+---------------------------------------------------------------------*/ 59 60#include <unistd.h> 61#include <stdio.h> 62#include <stdlib.h> 63#include <string.h> 64#include <errno.h> 65#include <signal.h> 66#include <sys/wait.h> 67 68/* Function prototypes */ 69void sys_error(const char *, int); /* System error message function */ 70void error(const char *, int); /* Error message function */ 71void setup_handler(); /* Sets up signal catching function */ 72void handler(int, int, struct sigcontext *); /* Signal catching function */ 73 74/*---------------------------------------------------------------------+ 75| main () | 76| ==================================================================== | 77| | 78| Function: Main program (see prolog for more details) | 79| | 80+---------------------------------------------------------------------*/ 81int main(int argc, char **argv) 82{ 83 int pid[2]; /* Child process ids */ 84 int fd[2]; /* Pipe file descriptors */ 85 int status; /* Child's exit status */ 86 87 enum { READ, WRITE }; /* Constants */ 88 enum { childA, childB }; 89 90 /* 91 * Setup signal catching function for SIGPIPE in case an 92 * error occurs 93 */ 94 setup_handler(); 95 96 /* 97 * Create a Pipe for data transfer between the two child 98 * processes. 99 */ 100 if (pipe(fd) < 0) 101 sys_error("pipe failed", __LINE__); 102 103 /* 104 * Create child process, run command and write info into pipe. 105 * 106 * Close the read end of the pipe and dup the stdout to the write 107 * end of the pipe, so the the output of the exec'd command will 108 * be written into the pipe. Then exec the cat command. 109 */ 110 if ((pid[childA] = fork()) < 0) 111 sys_error("fork failed", __LINE__); 112 113 if (pid[childA] == 0) { 114 /* Child process */ 115 116 close(fd[READ]); 117 118 /* Redirect STDOUT to fd [WRITE] */ 119 if (fd[WRITE] != STDOUT_FILENO) { 120 if (dup2(fd[WRITE], STDOUT_FILENO) != STDOUT_FILENO) 121 sys_error("dup2 failed", __LINE__); 122 } 123 close(fd[WRITE]); 124 125/* Vernon Mauery 6/1/2001 changed path and file to work will more flavors of unix */ 126 execl("/bin/cat", "cat", "/etc/inittab", NULL); 127 sys_error("execl failed (should not reach this line) ", 128 __LINE__); 129 } 130 131 /* 132 * Create another child process and run command on data passed though 133 * the pipe. 134 * 135 * Close the write end of the pipe and dup the read end of the pipe 136 * to stdin, so that the input of the exec'd command will come 137 * from the pipe. Then exec the wc command. 138 */ 139 if ((pid[childB] = fork()) < 0) 140 sys_error("fork failed", __LINE__); 141 142 if (pid[childB] == 0) { 143 /* Child process */ 144 close(fd[WRITE]); 145 146 if (fd[READ] != STDIN_FILENO) { 147 if (dup2(fd[READ], STDIN_FILENO) != STDIN_FILENO) 148 sys_error("dup2 failed", __LINE__); 149 } 150 close(fd[READ]); 151 152 execl("/usr/bin/wc", "wc", "-c", NULL); 153 sys_error("execl failed (should not reach this line) ", 154 __LINE__); 155 } 156 157 /* 158 * Close both ends of the pipe and wait for the child processes 159 * to complete. 160 */ 161 close(fd[READ]); 162 close(fd[WRITE]); 163 164 waitpid(pid[childA], &status, 0); 165 if (!WIFEXITED(status)) 166 sys_error("child process A terminated abnormally", __LINE__); 167 168 waitpid(pid[childB], &status, 0); 169 if (!WIFEXITED(status)) 170 sys_error("child process B terminated abnormally", __LINE__); 171 172 /* Program completed successfully -- exit */ 173 return (0); 174} 175 176/*---------------------------------------------------------------------+ 177| setup_handler () | 178| ==================================================================== | 179| | 180| Function: Setup the signal handler for SIGPIPE. | 181| | 182+---------------------------------------------------------------------*/ 183void setup_handler() 184{ 185 struct sigaction invec; 186 187 invec.sa_handler = (void (*)(int))handler; 188 sigemptyset(&invec.sa_mask); 189 invec.sa_flags = 0; 190 191 if (sigaction(SIGPIPE, &invec, NULL) < 0) 192 sys_error("sigaction failed", __LINE__); 193} 194 195/*---------------------------------------------------------------------+ 196| handler () | 197| ==================================================================== | 198| | 199| Function: Signal catching function for SIGPIPE signal. | 200| | 201| Returns: Aborts program & prints message upon receiving signal. | 202| | 203+---------------------------------------------------------------------*/ 204void handler(int sig, int code, struct sigcontext *scp) 205{ 206 error("wrote to pipe with closed read end", __LINE__); 207} 208 209/*---------------------------------------------------------------------+ 210| sys_error () | 211| ==================================================================== | 212| | 213| Function: Creates system error message and calls error () | 214| | 215+---------------------------------------------------------------------*/ 216void sys_error(const char *msg, int line) 217{ 218 char syserr_msg[256]; 219 220 sprintf(syserr_msg, "%s: %s\n", msg, strerror(errno)); 221 error(syserr_msg, line); 222} 223 224/*---------------------------------------------------------------------+ 225| error () | 226| ==================================================================== | 227| | 228| Function: Prints out message and exits... | 229| | 230+---------------------------------------------------------------------*/ 231void error(const char *msg, int line) 232{ 233 fprintf(stderr, "ERROR [line: %d] %s\n", line, msg); 234 exit(-1); 235} 236