1f08c3bdfSopenharmony_ci/*
2f08c3bdfSopenharmony_ci *
3f08c3bdfSopenharmony_ci *   Copyright (c) International Business Machines  Corp., 2002
4f08c3bdfSopenharmony_ci *
5f08c3bdfSopenharmony_ci *   This program is free software;  you can redistribute it and/or modify
6f08c3bdfSopenharmony_ci *   it under the terms of the GNU General Public License as published by
7f08c3bdfSopenharmony_ci *   the Free Software Foundation; either version 2 of the License, or
8f08c3bdfSopenharmony_ci *   (at your option) any later version.
9f08c3bdfSopenharmony_ci *
10f08c3bdfSopenharmony_ci *   This program is distributed in the hope that it will be useful,
11f08c3bdfSopenharmony_ci *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
12f08c3bdfSopenharmony_ci *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
13f08c3bdfSopenharmony_ci *   the GNU General Public License for more details.
14f08c3bdfSopenharmony_ci *
15f08c3bdfSopenharmony_ci *   You should have received a copy of the GNU General Public License
16f08c3bdfSopenharmony_ci *   along with this program;  if not, write to the Free Software
17f08c3bdfSopenharmony_ci *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18f08c3bdfSopenharmony_ci */
19f08c3bdfSopenharmony_ci
20f08c3bdfSopenharmony_ci/*
21f08c3bdfSopenharmony_ci * NAME
22f08c3bdfSopenharmony_ci *	pipe04.c
23f08c3bdfSopenharmony_ci *
24f08c3bdfSopenharmony_ci * DESCRIPTION
25f08c3bdfSopenharmony_ci * 	Check that processes are killable, even when they are still writing
26f08c3bdfSopenharmony_ci * 	data to a pipe.
27f08c3bdfSopenharmony_ci *
28f08c3bdfSopenharmony_ci * ALGORITHM
29f08c3bdfSopenharmony_ci * 	1. Open a pipe
30f08c3bdfSopenharmony_ci * 	2. fork a two children that will write to the pipe
31f08c3bdfSopenharmony_ci * 	3. read a bit from both children
32f08c3bdfSopenharmony_ci * 	3. kill both children and wait to make sure they die
33f08c3bdfSopenharmony_ci *
34f08c3bdfSopenharmony_ci * USAGE:  <for command-line>
35f08c3bdfSopenharmony_ci *  pipe04 [-c n] [-f] [-i n] [-I x] [-P x] [-t]
36f08c3bdfSopenharmony_ci *     where,  -c n : Run n copies concurrently.
37f08c3bdfSopenharmony_ci *             -f   : Turn off functionality Testing.
38f08c3bdfSopenharmony_ci *             -i n : Execute test n times.
39f08c3bdfSopenharmony_ci *             -I x : Execute test for x seconds.
40f08c3bdfSopenharmony_ci *             -P x : Pause for x seconds between iterations.
41f08c3bdfSopenharmony_ci *             -t   : Turn on syscall timing.
42f08c3bdfSopenharmony_ci *
43f08c3bdfSopenharmony_ci * HISTORY
44f08c3bdfSopenharmony_ci *	11/2002 Ported by Paul Larson
45f08c3bdfSopenharmony_ci */
46f08c3bdfSopenharmony_ci#include <unistd.h>
47f08c3bdfSopenharmony_ci#include <errno.h>
48f08c3bdfSopenharmony_ci#include <signal.h>
49f08c3bdfSopenharmony_ci#include <sys/types.h>
50f08c3bdfSopenharmony_ci#include <sys/wait.h>
51f08c3bdfSopenharmony_ci#include "test.h"
52f08c3bdfSopenharmony_ci#include "safe_macros.h"
53f08c3bdfSopenharmony_ci
54f08c3bdfSopenharmony_cichar *TCID = "pipe04";
55f08c3bdfSopenharmony_ciint TST_TOTAL = 1;
56f08c3bdfSopenharmony_ci
57f08c3bdfSopenharmony_ciint fildes[2];			/* fds for pipe read and write */
58f08c3bdfSopenharmony_ci
59f08c3bdfSopenharmony_civoid setup(void);
60f08c3bdfSopenharmony_civoid cleanup(void);
61f08c3bdfSopenharmony_civoid c1func(void);
62f08c3bdfSopenharmony_civoid c2func(void);
63f08c3bdfSopenharmony_civoid alarmfunc(int);
64f08c3bdfSopenharmony_ci
65f08c3bdfSopenharmony_cissize_t do_read(int fd, void *buf, size_t count)
66f08c3bdfSopenharmony_ci{
67f08c3bdfSopenharmony_ci	ssize_t n;
68f08c3bdfSopenharmony_ci
69f08c3bdfSopenharmony_ci	do {
70f08c3bdfSopenharmony_ci		n = read(fd, buf, count);
71f08c3bdfSopenharmony_ci	} while (n < 0 && errno == EINTR);
72f08c3bdfSopenharmony_ci
73f08c3bdfSopenharmony_ci	return n;
74f08c3bdfSopenharmony_ci}
75f08c3bdfSopenharmony_ci
76f08c3bdfSopenharmony_ciint main(int ac, char **av)
77f08c3bdfSopenharmony_ci{
78f08c3bdfSopenharmony_ci	int lc;
79f08c3bdfSopenharmony_ci	pid_t c1pid, c2pid;
80f08c3bdfSopenharmony_ci	int wtstatus;
81f08c3bdfSopenharmony_ci	int bytesread;
82f08c3bdfSopenharmony_ci	int acnt = 0, bcnt = 0;
83f08c3bdfSopenharmony_ci
84f08c3bdfSopenharmony_ci	char rbuf[BUFSIZ];
85f08c3bdfSopenharmony_ci
86f08c3bdfSopenharmony_ci	tst_parse_opts(ac, av, NULL, NULL);
87f08c3bdfSopenharmony_ci#ifdef UCLINUX
88f08c3bdfSopenharmony_ci	maybe_run_child(&c1func, "ndd", 1, &fildes[0], &fildes[1]);
89f08c3bdfSopenharmony_ci	maybe_run_child(&c2func, "ndd", 2, &fildes[0], &fildes[1]);
90f08c3bdfSopenharmony_ci#endif
91f08c3bdfSopenharmony_ci
92f08c3bdfSopenharmony_ci	setup();
93f08c3bdfSopenharmony_ci
94f08c3bdfSopenharmony_ci	for (lc = 0; TEST_LOOPING(lc); lc++) {
95f08c3bdfSopenharmony_ci
96f08c3bdfSopenharmony_ci		/* reset tst_count in case we are looping */
97f08c3bdfSopenharmony_ci		tst_count = 0;
98f08c3bdfSopenharmony_ci
99f08c3bdfSopenharmony_ci		SAFE_PIPE(cleanup, fildes);
100f08c3bdfSopenharmony_ci
101f08c3bdfSopenharmony_ci		if ((c1pid = FORK_OR_VFORK()) == -1)
102f08c3bdfSopenharmony_ci			tst_brkm(TBROK, cleanup, "fork() failed - "
103f08c3bdfSopenharmony_ci				 "errno %d", errno);
104f08c3bdfSopenharmony_ci		if (c1pid == 0)
105f08c3bdfSopenharmony_ci#ifdef UCLINUX
106f08c3bdfSopenharmony_ci			if (self_exec(av[0], "ndd", 1, fildes[0], fildes[1]) <
107f08c3bdfSopenharmony_ci			    0) {
108f08c3bdfSopenharmony_ci				tst_brkm(TBROK, cleanup, "self_exec failed");
109f08c3bdfSopenharmony_ci			}
110f08c3bdfSopenharmony_ci#else
111f08c3bdfSopenharmony_ci			c1func();
112f08c3bdfSopenharmony_ci#endif
113f08c3bdfSopenharmony_ci		if ((c2pid = FORK_OR_VFORK()) == -1)
114f08c3bdfSopenharmony_ci			tst_brkm(TBROK, cleanup, "fork() failed - "
115f08c3bdfSopenharmony_ci				 "errno %d", errno);
116f08c3bdfSopenharmony_ci		if (c2pid == 0)
117f08c3bdfSopenharmony_ci#ifdef UCLINUX
118f08c3bdfSopenharmony_ci			if (self_exec(av[0], "ndd", 2, fildes[0], fildes[1]) <
119f08c3bdfSopenharmony_ci			    0) {
120f08c3bdfSopenharmony_ci				tst_brkm(TBROK, cleanup, "self_exec failed");
121f08c3bdfSopenharmony_ci			}
122f08c3bdfSopenharmony_ci#else
123f08c3bdfSopenharmony_ci			c2func();
124f08c3bdfSopenharmony_ci#endif
125f08c3bdfSopenharmony_ci
126f08c3bdfSopenharmony_ci		/* PARENT */
127f08c3bdfSopenharmony_ci		if (close(fildes[1]) == -1)
128f08c3bdfSopenharmony_ci			tst_resm(TWARN, "Could not close fildes[1] - errno %d",
129f08c3bdfSopenharmony_ci				 errno);
130f08c3bdfSopenharmony_ci		/*
131f08c3bdfSopenharmony_ci		 * Read a bit from the children first
132f08c3bdfSopenharmony_ci		 */
133f08c3bdfSopenharmony_ci		while ((acnt < 100) && (bcnt < 100)) {
134f08c3bdfSopenharmony_ci			bytesread = do_read(fildes[0], rbuf, sizeof(rbuf));
135f08c3bdfSopenharmony_ci			if (bytesread < 0) {
136f08c3bdfSopenharmony_ci				tst_resm(TFAIL, "Unable to read from pipe, "
137f08c3bdfSopenharmony_ci					 "errno=%d", errno);
138f08c3bdfSopenharmony_ci				break;
139f08c3bdfSopenharmony_ci			}
140f08c3bdfSopenharmony_ci			switch (rbuf[1]) {
141f08c3bdfSopenharmony_ci			case 'A':
142f08c3bdfSopenharmony_ci				acnt++;
143f08c3bdfSopenharmony_ci				break;
144f08c3bdfSopenharmony_ci			case 'b':
145f08c3bdfSopenharmony_ci				bcnt++;
146f08c3bdfSopenharmony_ci				break;
147f08c3bdfSopenharmony_ci			default:
148f08c3bdfSopenharmony_ci				tst_resm(TFAIL, "Got bogus '%c' "
149f08c3bdfSopenharmony_ci					 "character", rbuf[1]);
150f08c3bdfSopenharmony_ci				break;
151f08c3bdfSopenharmony_ci			}
152f08c3bdfSopenharmony_ci		}
153f08c3bdfSopenharmony_ci
154f08c3bdfSopenharmony_ci		/*
155f08c3bdfSopenharmony_ci		 * Try to kill the children
156f08c3bdfSopenharmony_ci		 */
157f08c3bdfSopenharmony_ci		if (kill(c1pid, SIGKILL) == -1)
158f08c3bdfSopenharmony_ci			tst_resm(TFAIL, "failed to kill child 1, errno=%d",
159f08c3bdfSopenharmony_ci				 errno);
160f08c3bdfSopenharmony_ci		if (kill(c2pid, SIGKILL) == -1)
161f08c3bdfSopenharmony_ci			tst_resm(TFAIL, "failed to kill child 1, errno=%d",
162f08c3bdfSopenharmony_ci				 errno);
163f08c3bdfSopenharmony_ci
164f08c3bdfSopenharmony_ci		/*
165f08c3bdfSopenharmony_ci		 * Set action for the alarm
166f08c3bdfSopenharmony_ci		 */
167f08c3bdfSopenharmony_ci		if (signal(SIGALRM, alarmfunc) == SIG_ERR)
168f08c3bdfSopenharmony_ci			tst_resm(TWARN | TERRNO, "call to signal failed");
169f08c3bdfSopenharmony_ci		/*
170f08c3bdfSopenharmony_ci		 * Set an alarm for 60 seconds just in case the child
171f08c3bdfSopenharmony_ci		 * processes don't die
172f08c3bdfSopenharmony_ci		 */
173f08c3bdfSopenharmony_ci		alarm(60);
174f08c3bdfSopenharmony_ci		if (waitpid(c1pid, &wtstatus, 0) != -1) {
175f08c3bdfSopenharmony_ci			if (wtstatus != SIGKILL)
176f08c3bdfSopenharmony_ci				tst_resm(TFAIL | TERRNO,
177f08c3bdfSopenharmony_ci					 "unexpected wait status " "%d",
178f08c3bdfSopenharmony_ci					 wtstatus);
179f08c3bdfSopenharmony_ci			else
180f08c3bdfSopenharmony_ci				tst_resm(TPASS, "Child 1 killed while "
181f08c3bdfSopenharmony_ci					 "writing to a pipe");
182f08c3bdfSopenharmony_ci		}
183f08c3bdfSopenharmony_ci		if (waitpid(c2pid, &wtstatus, 0) != -1) {
184f08c3bdfSopenharmony_ci			if (!WIFSIGNALED(wtstatus) ||
185f08c3bdfSopenharmony_ci			    WTERMSIG(wtstatus) != SIGKILL)
186f08c3bdfSopenharmony_ci				tst_resm(TFAIL | TERRNO,
187f08c3bdfSopenharmony_ci					 "unexpected wait status " "%d",
188f08c3bdfSopenharmony_ci					 wtstatus);
189f08c3bdfSopenharmony_ci			else
190f08c3bdfSopenharmony_ci				tst_resm(TPASS, "Child 2 killed while "
191f08c3bdfSopenharmony_ci					 "writing to a pipe");
192f08c3bdfSopenharmony_ci		}
193f08c3bdfSopenharmony_ci		if (alarm(0) <= 0)
194f08c3bdfSopenharmony_ci			tst_resm(TWARN, "call to alarm(0) failed");
195f08c3bdfSopenharmony_ci	}
196f08c3bdfSopenharmony_ci	cleanup();
197f08c3bdfSopenharmony_ci
198f08c3bdfSopenharmony_ci	tst_exit();
199f08c3bdfSopenharmony_ci}
200f08c3bdfSopenharmony_ci
201f08c3bdfSopenharmony_ci/*
202f08c3bdfSopenharmony_ci * setup() - performs all ONE TIME setup for this test.
203f08c3bdfSopenharmony_ci */
204f08c3bdfSopenharmony_civoid setup(void)
205f08c3bdfSopenharmony_ci{
206f08c3bdfSopenharmony_ci
207f08c3bdfSopenharmony_ci	tst_sig(FORK, DEF_HANDLER, cleanup);
208f08c3bdfSopenharmony_ci
209f08c3bdfSopenharmony_ci	TEST_PAUSE;
210f08c3bdfSopenharmony_ci}
211f08c3bdfSopenharmony_ci
212f08c3bdfSopenharmony_ci/*
213f08c3bdfSopenharmony_ci * cleanup() - performs all ONE TIME cleanup for this test at
214f08c3bdfSopenharmony_ci *	       completion or premature exit.
215f08c3bdfSopenharmony_ci */
216f08c3bdfSopenharmony_civoid cleanup(void)
217f08c3bdfSopenharmony_ci{
218f08c3bdfSopenharmony_ci}
219f08c3bdfSopenharmony_ci
220f08c3bdfSopenharmony_civoid c1func(void)
221f08c3bdfSopenharmony_ci{
222f08c3bdfSopenharmony_ci	if (close(fildes[0]) == -1)
223f08c3bdfSopenharmony_ci		tst_resm(TWARN, "Could not close fildes[0] - errno %d", errno);
224f08c3bdfSopenharmony_ci	while (1)
225f08c3bdfSopenharmony_ci		if (write(fildes[1], "bbbbbbbbbbbbbbbbbbbbbbbbb", 25) == -1)
226f08c3bdfSopenharmony_ci			tst_resm(TBROK | TERRNO, "[child 1] pipe write failed");
227f08c3bdfSopenharmony_ci}
228f08c3bdfSopenharmony_ci
229f08c3bdfSopenharmony_civoid c2func(void)
230f08c3bdfSopenharmony_ci{
231f08c3bdfSopenharmony_ci	if (close(fildes[0]) == -1)
232f08c3bdfSopenharmony_ci		tst_resm(TWARN, "Could not close fildes[0] - errno %d", errno);
233f08c3bdfSopenharmony_ci	while (1)
234f08c3bdfSopenharmony_ci		if (write(fildes[1], "AAAAAAAAAAAAAAAAAAAAAAAAA", 25) == -1)
235f08c3bdfSopenharmony_ci			tst_resm(TBROK | TERRNO, "[child 2] pipe write failed");
236f08c3bdfSopenharmony_ci}
237f08c3bdfSopenharmony_ci
238f08c3bdfSopenharmony_civoid alarmfunc(int sig LTP_ATTRIBUTE_UNUSED)
239f08c3bdfSopenharmony_ci{
240f08c3bdfSopenharmony_ci	/* for some reason tst_brkm doesn't seem to work in a signal handler */
241f08c3bdfSopenharmony_ci	tst_brkm(TFAIL, cleanup, "one or more children did't die in 60 second "
242f08c3bdfSopenharmony_ci		 "time limit");
243f08c3bdfSopenharmony_ci}
244