1/*
2 *
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/*
21 * NAME
22 *	write04.c
23 *
24 * DESCRIPTION
25 *	Testcase to check that write() sets errno to EAGAIN
26 *
27 * ALGORITHM
28 *	Create a named pipe (fifo), open it in O_NONBLOCK mode, and
29 *	attempt to write to it when it is full, write(2) should fail
30 *	with EAGAIN.
31 *
32 * USAGE:  <for command-line>
33 *      write04 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
34 *      where,  -c n : Run n copies concurrently.
35 *              -e   : Turn on errno logging.
36 *              -i n : Execute test n times.
37 *              -I x : Execute test for x seconds.
38 *              -P x : Pause for x seconds between iterations.
39 *              -t   : Turn on syscall timing.
40 *
41 * HISTORY
42 *      ??/???? someone made this testcase but didn't add HISTORY
43 *
44 * RESTRICTIONS
45 *	NONE
46 */
47
48#include <sys/stat.h>
49#include <fcntl.h>
50#include <signal.h>
51#include <setjmp.h>
52#include <errno.h>
53#include <string.h>
54#include "test.h"
55
56#define PIPE_SIZE_TEST getpagesize()
57
58void alarm_handler();
59void setup();
60void cleanup();
61
62char *TCID = "write04";
63int TST_TOTAL = 1;
64
65char fifo[100] = "fifo";
66static sigjmp_buf jmp;
67int rfd, wfd;
68
69int main(int argc, char **argv)
70{
71	int lc;
72
73	struct stat buf;
74	int fail;
75	int cnt;
76	char wbuf[17 * PIPE_SIZE_TEST];
77	struct sigaction sigptr;	/* set up signal handler */
78
79	tst_parse_opts(argc, argv, NULL, NULL);
80
81	/* global setup */
82	setup();
83
84	/*
85	 * The following loop checks looping state if -i option given
86	 */
87	for (lc = 0; TEST_LOOPING(lc); lc++) {
88		/* reset tst_count in case we are looping */
89		tst_count = 0;
90
91		if (mknod(fifo, S_IFIFO | 0777, 0) < 0) {
92			tst_resm(TBROK, "mknod() failed, errno: %d", errno);
93			cleanup();
94		}
95		if (stat(fifo, &buf) != 0) {
96			tst_resm(TBROK, "stat() failed, errno: %d", errno);
97			cleanup();
98		}
99		if ((buf.st_mode & S_IFIFO) == 0) {
100			tst_resm(TBROK, "Mode does not indicate fifo file");
101			cleanup();
102		}
103#if 0
104		sigset(SIGALRM, alarm_handler);
105#endif
106		sigptr.sa_handler = (void (*)(int signal))alarm_handler;
107		sigfillset(&sigptr.sa_mask);
108		sigptr.sa_flags = 0;
109		sigaddset(&sigptr.sa_mask, SIGALRM);
110		if (sigaction(SIGALRM, &sigptr, NULL) == -1) {
111			tst_resm(TBROK, "sigaction(): Failed");
112			cleanup();
113		}
114//block1:
115		tst_resm(TINFO, "Enter block 1: test for EAGAIN in write()");
116		fail = 0;
117
118		(void)memset((void *)wbuf, 'A', 17 * PIPE_SIZE_TEST);
119
120		/*
121		 * open the read end of the pipe
122		 */
123		if (sigsetjmp(jmp, 1)) {
124			tst_resm(TBROK, "Error reading fifo, read blocked");
125			fail = 1;
126		}
127		(void)alarm(10);	/* set alarm for 10 seconds */
128		rfd = open(fifo, O_RDONLY | O_NONBLOCK);
129		(void)alarm(0);
130		if (rfd < 0) {
131			tst_resm(TBROK, "open() for reading the pipe failed");
132			fail = 1;
133		}
134
135		/*
136		 * open the write end of the pipe
137		 */
138		if (sigsetjmp(jmp, 1)) {
139			tst_resm(TBROK, "setjmp() failed");
140			cleanup();
141		}
142		(void)alarm(10);	/* set alarm for 10 seconds */
143		wfd = open(fifo, O_WRONLY | O_NONBLOCK);
144		(void)alarm(0);
145		if (wfd < 0) {
146			tst_resm(TBROK, "open() for writing the pipe failed");
147			fail = 1;
148		}
149
150		/*
151		 * attempt to fill the pipe with some data
152		 */
153		if (sigsetjmp(jmp, 1)) {
154			tst_resm(TBROK, "sigsetjmp() failed");
155			fail = 1;
156		}
157		(void)alarm(10);
158		cnt = write(wfd, wbuf, 17 * PIPE_SIZE_TEST);
159		(void)alarm(0);
160		if (cnt == 17 * PIPE_SIZE_TEST) {
161			tst_resm(TBROK, "Error reading fifo, nozero read");
162			fail = 1;
163		}
164
165		/*
166		 * Now that the fifo is full try and send some more
167		 */
168		if (sigsetjmp(jmp, 1)) {
169			tst_resm(TBROK, "sigsetjmp() failed");
170			fail = 1;
171		}
172		(void)alarm(10);
173		cnt = write(wfd, wbuf, 8 * PIPE_SIZE_TEST);
174		(void)alarm(0);
175		if (cnt != -1) {
176			tst_resm(TBROK, "write() failed to fail when pipe "
177				 "is full");
178			fail = 1;
179		} else {
180			if (errno != EAGAIN) {
181				tst_resm(TBROK, "write set bad errno, expected "
182					 "EAGAIN, got %d", errno);
183				fail = 1;
184			}
185			tst_resm(TINFO, "read() succeded in setting errno to "
186				 "EAGAIN");
187		}
188		if (fail) {
189			tst_resm(TFAIL, "Block 1 FAILED");
190		} else {
191			tst_resm(TPASS, "Block 1 PASSED");
192		}
193		tst_resm(TINFO, "Exit block 1");
194
195		/* unlink fifo in case we are looping. */
196		unlink(fifo);
197	}
198	cleanup();
199	tst_exit();
200}
201
202void alarm_handler(void)
203{
204	siglongjmp(jmp, 1);
205}
206
207/*
208 * setup()
209 *	performs all ONE TIME setup for this test
210 */
211void setup(void)
212{
213
214	tst_sig(FORK, DEF_HANDLER, cleanup);
215
216	/* Pause if that option was specified
217	 * TEST_PAUSE contains the code to fork the test with the -i option.
218	 * You want to make sure you do this before you create your temporary
219	 * directory.
220	 */
221	TEST_PAUSE;
222
223	/* Create a unique temporary directory and chdir() to it. */
224	tst_tmpdir();
225
226	/* create a temporary filename */
227	sprintf(fifo, "%s.%d", fifo, getpid());
228
229}
230
231void cleanup(void)
232{
233
234	close(rfd);
235	close(wfd);
236	unlink(fifo);
237	tst_rmdir();
238
239}
240