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 */
69 void sys_error(const char *, int); /* System error message function */
70 void error(const char *, int); /* Error message function */
71 void setup_handler(); /* Sets up signal catching function */
72 void 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 +---------------------------------------------------------------------*/
main(int argc,char ** argv)81 int 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 +---------------------------------------------------------------------*/
setup_handler()183 void 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 +---------------------------------------------------------------------*/
handler(int sig,int code,struct sigcontext * scp)204 void 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 +---------------------------------------------------------------------*/
sys_error(const char * msg,int line)216 void 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 +---------------------------------------------------------------------*/
error(const char * msg,int line)231 void error(const char *msg, int line)
232 {
233 fprintf(stderr, "ERROR [line: %d] %s\n", line, msg);
234 exit(-1);
235 }
236