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