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
58 void alarm_handler();
59 void setup();
60 void cleanup();
61
62 char *TCID = "write04";
63 int TST_TOTAL = 1;
64
65 char fifo[100] = "fifo";
66 static sigjmp_buf jmp;
67 int rfd, wfd;
68
main(int argc,char ** argv)69 int 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
alarm_handler(void)202 void alarm_handler(void)
203 {
204 siglongjmp(jmp, 1);
205 }
206
207 /*
208 * setup()
209 * performs all ONE TIME setup for this test
210 */
setup(void)211 void 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
cleanup(void)231 void cleanup(void)
232 {
233
234 close(rfd);
235 close(wfd);
236 unlink(fifo);
237 tst_rmdir();
238
239 }
240