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