xref: /minix3/minix/tests/t40d.c (revision 433d6423c39e34ec4b79c950597bb2d236f886be)
1*433d6423SLionel Sambuc /* t40d.c
2*433d6423SLionel Sambuc  *
3*433d6423SLionel Sambuc  * Test FIFOs and pipes
4*433d6423SLionel Sambuc  *
5*433d6423SLionel Sambuc  * Select works on regular files, (pseudo) terminal devices, streams-based
6*433d6423SLionel Sambuc  * files, FIFOs, pipes, and sockets. This test verifies selecting for FIFOs
7*433d6423SLionel Sambuc  * (named pipes) and pipes (anonymous pipes). This test will not verify most
8*433d6423SLionel Sambuc  * error file descriptors, as the setting of this fdset in the face of an error
9*433d6423SLionel Sambuc  * condition is implementation-specific (except for regular files (alway set)
10*433d6423SLionel Sambuc  * and sockets (protocol-specific or OOB data received), but those file types
11*433d6423SLionel Sambuc  * are not being tested in this specific test).
12*433d6423SLionel Sambuc  *
13*433d6423SLionel Sambuc  * This test is part of a bigger select test. It expects as argument which sub-
14*433d6423SLionel Sambuc  * test it is.
15*433d6423SLionel Sambuc  *
16*433d6423SLionel Sambuc  * [1] If a socket has a pending error, it shall be considered to have an
17*433d6423SLionel Sambuc  * exceptional condition pending. Otherwise, what constitutes an exceptional
18*433d6423SLionel Sambuc  * condition is file type-specific. For a file descriptor for use with a
19*433d6423SLionel Sambuc  * socket, it is protocol-specific except as noted below. For other file types
20*433d6423SLionel Sambuc  * it is implementation-defined. If the operation is meaningless for a
21*433d6423SLionel Sambuc  * particular file type, pselect() or select() shall indicate that the
22*433d6423SLionel Sambuc  * descriptor is ready for read or write operations, and shall indicate that
23*433d6423SLionel Sambuc  * the descriptor has no exceptional condition pending.
24*433d6423SLionel Sambuc  */
25*433d6423SLionel Sambuc 
26*433d6423SLionel Sambuc #include <stdio.h>
27*433d6423SLionel Sambuc #include <stdlib.h>
28*433d6423SLionel Sambuc #include <unistd.h>
29*433d6423SLionel Sambuc #include <sys/types.h>
30*433d6423SLionel Sambuc #include <sys/stat.h>
31*433d6423SLionel Sambuc #include <fcntl.h>
32*433d6423SLionel Sambuc #include <sys/select.h>
33*433d6423SLionel Sambuc #include <errno.h>
34*433d6423SLionel Sambuc #include <sys/wait.h>
35*433d6423SLionel Sambuc #include <string.h>
36*433d6423SLionel Sambuc #include <time.h>
37*433d6423SLionel Sambuc #include <assert.h>
38*433d6423SLionel Sambuc 
39*433d6423SLionel Sambuc #define NAMEDPIPE1 "selecttestd-1"
40*433d6423SLionel Sambuc #define NAMEDPIPE2 "selecttestd-2"
41*433d6423SLionel Sambuc #define SENDSTRING "minixrocks"
42*433d6423SLionel Sambuc #define DO_HANDLEDATA 1
43*433d6423SLionel Sambuc #define DO_PAUSE 3
44*433d6423SLionel Sambuc #define DO_TIMEOUT 7
45*433d6423SLionel Sambuc #define MAX_ERROR 5
46*433d6423SLionel Sambuc 
47*433d6423SLionel Sambuc #include "common.h"
48*433d6423SLionel Sambuc 
49*433d6423SLionel Sambuc char errbuf[1000];
50*433d6423SLionel Sambuc int fd_ap[2]; /* Anonymous pipe; read from fd_ap[0], write to fd_ap[1] */
51*433d6423SLionel Sambuc int fd_np1; /* Named pipe */
52*433d6423SLionel Sambuc int fd_np2; /* Named pipe */
53*433d6423SLionel Sambuc 
do_child(void)54*433d6423SLionel Sambuc static void do_child(void) {
55*433d6423SLionel Sambuc   struct timeval tv;
56*433d6423SLionel Sambuc 
57*433d6423SLionel Sambuc   /* Open named pipe for writing. This will block until a reader arrives. */
58*433d6423SLionel Sambuc   if((fd_np1 = open(NAMEDPIPE1, O_WRONLY)) == -1) {
59*433d6423SLionel Sambuc     printf("Error opening %s for writing, signalling parent to quit\n",
60*433d6423SLionel Sambuc 	   NAMEDPIPE1);
61*433d6423SLionel Sambuc     perror(NULL);
62*433d6423SLionel Sambuc     printf("Please make sure that %s is not in use while running this test\n",
63*433d6423SLionel Sambuc 	   NAMEDPIPE1);
64*433d6423SLionel Sambuc     exit(-1);
65*433d6423SLionel Sambuc   }
66*433d6423SLionel Sambuc 
67*433d6423SLionel Sambuc   /* Going to sleep for three seconds to allow the parent proc to get ready */
68*433d6423SLionel Sambuc   tv.tv_sec = DO_HANDLEDATA;
69*433d6423SLionel Sambuc   tv.tv_usec = 0;
70*433d6423SLionel Sambuc   select(0, NULL, NULL, NULL, &tv);
71*433d6423SLionel Sambuc 
72*433d6423SLionel Sambuc   /* Try to write. Doesn't matter how many bytes we actually send. */
73*433d6423SLionel Sambuc   (void) write(fd_np1, SENDSTRING, strlen(SENDSTRING));
74*433d6423SLionel Sambuc 
75*433d6423SLionel Sambuc   /* Wait for another second to allow the parent to process incoming data */
76*433d6423SLionel Sambuc   tv.tv_sec = DO_HANDLEDATA;
77*433d6423SLionel Sambuc   tv.tv_usec = 0;
78*433d6423SLionel Sambuc   (void) select(0,NULL, NULL, NULL, &tv);
79*433d6423SLionel Sambuc 
80*433d6423SLionel Sambuc   close(fd_np1);
81*433d6423SLionel Sambuc 
82*433d6423SLionel Sambuc   /* Wait for another second to allow the parent to process incoming data */
83*433d6423SLionel Sambuc   tv.tv_sec = DO_HANDLEDATA;
84*433d6423SLionel Sambuc   tv.tv_usec = 0;
85*433d6423SLionel Sambuc   (void) select(0,NULL, NULL, NULL, &tv);
86*433d6423SLionel Sambuc 
87*433d6423SLionel Sambuc   /* Open named pipe for reading. This will block until a writer arrives. */
88*433d6423SLionel Sambuc   if((fd_np2 = open(NAMEDPIPE2, O_RDONLY)) == -1) {
89*433d6423SLionel Sambuc     printf("Error opening %s for reading, signalling parent to quit\n",
90*433d6423SLionel Sambuc 	   NAMEDPIPE2);
91*433d6423SLionel Sambuc     perror(NULL);
92*433d6423SLionel Sambuc     printf("Please make sure that %s is not in use while running this test\n",
93*433d6423SLionel Sambuc 	   NAMEDPIPE2);
94*433d6423SLionel Sambuc     exit(-1);
95*433d6423SLionel Sambuc   }
96*433d6423SLionel Sambuc 
97*433d6423SLionel Sambuc   /* Wait for another second to allow the parent to run some tests. */
98*433d6423SLionel Sambuc   tv.tv_sec = DO_HANDLEDATA;
99*433d6423SLionel Sambuc   tv.tv_usec = 0;
100*433d6423SLionel Sambuc   (void) select(0, NULL, NULL, NULL, &tv);
101*433d6423SLionel Sambuc 
102*433d6423SLionel Sambuc   close(fd_np2);
103*433d6423SLionel Sambuc 
104*433d6423SLionel Sambuc   /*                             Anonymous pipe                              */
105*433d6423SLionel Sambuc 
106*433d6423SLionel Sambuc   /* Let the parent do initial read and write tests from and to the pipe. */
107*433d6423SLionel Sambuc   tv.tv_sec = DO_PAUSE;
108*433d6423SLionel Sambuc   tv.tv_usec = 0;
109*433d6423SLionel Sambuc   (void) select(0, NULL, NULL, NULL, &tv);
110*433d6423SLionel Sambuc 
111*433d6423SLionel Sambuc   /* Unblock blocking read select by writing data */
112*433d6423SLionel Sambuc   if(write(fd_ap[1], SENDSTRING, strlen(SENDSTRING)) < 0) {
113*433d6423SLionel Sambuc     perror("Could not write to anonymous pipe");
114*433d6423SLionel Sambuc     exit(-1);
115*433d6423SLionel Sambuc   }
116*433d6423SLionel Sambuc 
117*433d6423SLionel Sambuc   exit(0);
118*433d6423SLionel Sambuc }
119*433d6423SLionel Sambuc 
120*433d6423SLionel Sambuc #if 0
121*433d6423SLionel Sambuc static int count_fds(int nfds, fd_set *fds) {
122*433d6423SLionel Sambuc   /* Return number of bits set in fds */
123*433d6423SLionel Sambuc   int i, result = 0;
124*433d6423SLionel Sambuc   assert(fds != NULL && nfds > 0);
125*433d6423SLionel Sambuc   for(i = 0; i < nfds; i++) {
126*433d6423SLionel Sambuc     if(FD_ISSET(i, fds)) result++;
127*433d6423SLionel Sambuc   }
128*433d6423SLionel Sambuc   return result;
129*433d6423SLionel Sambuc }
130*433d6423SLionel Sambuc #endif
131*433d6423SLionel Sambuc 
empty_fds(int nfds,fd_set * fds)132*433d6423SLionel Sambuc static int empty_fds(int nfds, fd_set *fds) {
133*433d6423SLionel Sambuc   /* Returns nonzero if the first bits up to nfds in fds are not set */
134*433d6423SLionel Sambuc   int i;
135*433d6423SLionel Sambuc   assert(fds != NULL && nfds > 0);
136*433d6423SLionel Sambuc   for(i = 0; i < nfds; i++) if(FD_ISSET(i, fds)) return 0;
137*433d6423SLionel Sambuc   return 1;
138*433d6423SLionel Sambuc }
139*433d6423SLionel Sambuc 
compare_fds(int nfds,fd_set * lh,fd_set * rh)140*433d6423SLionel Sambuc static int compare_fds(int nfds, fd_set *lh, fd_set *rh) {
141*433d6423SLionel Sambuc   /* Returns nonzero if lh equals rh up to nfds bits */
142*433d6423SLionel Sambuc   int i;
143*433d6423SLionel Sambuc   assert(lh != NULL && rh != NULL && nfds > 0);
144*433d6423SLionel Sambuc   for(i = 0; i < nfds; i++) {
145*433d6423SLionel Sambuc     if((FD_ISSET(i, lh) && !FD_ISSET(i, rh)) ||
146*433d6423SLionel Sambuc        (!FD_ISSET(i, lh) && FD_ISSET(i, rh))) {
147*433d6423SLionel Sambuc       return 0;
148*433d6423SLionel Sambuc     }
149*433d6423SLionel Sambuc   }
150*433d6423SLionel Sambuc   return 1;
151*433d6423SLionel Sambuc }
152*433d6423SLionel Sambuc 
153*433d6423SLionel Sambuc #if 0
154*433d6423SLionel Sambuc static void dump_fds(int nfds, fd_set *fds) {
155*433d6423SLionel Sambuc   /* Print a graphical representation of bits in fds */
156*433d6423SLionel Sambuc   int i;
157*433d6423SLionel Sambuc   if(fds != NULL && nfds > 0) {
158*433d6423SLionel Sambuc     for(i = 0; i < nfds; i++) printf("%d ", (FD_ISSET(i, fds) ? 1 : 0));
159*433d6423SLionel Sambuc     printf("\n");
160*433d6423SLionel Sambuc   }
161*433d6423SLionel Sambuc }
162*433d6423SLionel Sambuc #endif
163*433d6423SLionel Sambuc 
do_parent(int child)164*433d6423SLionel Sambuc static void do_parent(int child) {
165*433d6423SLionel Sambuc   fd_set fds_read, fds_write, fds_error;
166*433d6423SLionel Sambuc   fd_set fds_compare_read, fds_compare_write;
167*433d6423SLionel Sambuc   struct timeval tv;
168*433d6423SLionel Sambuc   time_t start, end;
169*433d6423SLionel Sambuc   int retval;
170*433d6423SLionel Sambuc   char buf[20];
171*433d6423SLionel Sambuc 
172*433d6423SLionel Sambuc   /* Open named pipe for reading. This will block until a writer arrives. */
173*433d6423SLionel Sambuc   if((fd_np1 = open(NAMEDPIPE1, O_RDONLY)) == -1) {
174*433d6423SLionel Sambuc     printf("Error opening %s for reading\n", NAMEDPIPE1);
175*433d6423SLionel Sambuc     perror(NULL);
176*433d6423SLionel Sambuc     printf("Please make sure that %s is not in use while running this test.\n",
177*433d6423SLionel Sambuc 	   NAMEDPIPE1);
178*433d6423SLionel Sambuc     waitpid(child, &retval, 0);
179*433d6423SLionel Sambuc     exit(-1);
180*433d6423SLionel Sambuc   }
181*433d6423SLionel Sambuc 
182*433d6423SLionel Sambuc   /* Clear bit masks */
183*433d6423SLionel Sambuc   FD_ZERO(&fds_read); FD_ZERO(&fds_write);
184*433d6423SLionel Sambuc   /* Set read and write bits */
185*433d6423SLionel Sambuc   FD_SET(fd_np1, &fds_read);
186*433d6423SLionel Sambuc   FD_SET(fd_np1, &fds_write);
187*433d6423SLionel Sambuc   tv.tv_sec = DO_TIMEOUT;
188*433d6423SLionel Sambuc   tv.tv_usec = 0;
189*433d6423SLionel Sambuc 
190*433d6423SLionel Sambuc   /* Test if we can read or write from/to fd_np1. As fd_np1 is opened read only
191*433d6423SLionel Sambuc    * we cannot actually write, so the select should return immediately [1] and
192*433d6423SLionel Sambuc    * the offending bit set in the fd set. We read from a pipe that is opened
193*433d6423SLionel Sambuc    * with O_NONBLOCKING cleared, so it is guaranteed we can read.
194*433d6423SLionel Sambuc    * However, at this moment the writer is sleeping, so the pipe is empty and
195*433d6423SLionel Sambuc    * read is supposed to block. Therefore, only 1 file descriptor should be
196*433d6423SLionel Sambuc    * ready. A timeout value is still set in case an error occurs in a faulty
197*433d6423SLionel Sambuc    * implementation. */
198*433d6423SLionel Sambuc   retval = select(fd_np1+1, &fds_read, &fds_write, NULL, &tv);
199*433d6423SLionel Sambuc 
200*433d6423SLionel Sambuc   /* Did we receive an error? */
201*433d6423SLionel Sambuc   if(retval <= 0) {
202*433d6423SLionel Sambuc     snprintf(errbuf, sizeof(errbuf),
203*433d6423SLionel Sambuc 	     "one fd should be set%s", (retval == 0 ? " (TIMEOUT)" : ""));
204*433d6423SLionel Sambuc     em(1, errbuf);
205*433d6423SLionel Sambuc   }
206*433d6423SLionel Sambuc 
207*433d6423SLionel Sambuc   if(!empty_fds(fd_np1+1,&fds_read)) em(2, "no read bits should be set");
208*433d6423SLionel Sambuc 
209*433d6423SLionel Sambuc 
210*433d6423SLionel Sambuc   /* Make sure the write bit is set (and just 1 bit) */
211*433d6423SLionel Sambuc   FD_ZERO(&fds_compare_write); FD_SET(fd_np1, &fds_compare_write);
212*433d6423SLionel Sambuc   if(!compare_fds(fd_np1+1, &fds_compare_write, &fds_write))
213*433d6423SLionel Sambuc     em(3, "write should be set");
214*433d6423SLionel Sambuc 
215*433d6423SLionel Sambuc   /* Clear sets and set up new bit masks */
216*433d6423SLionel Sambuc   FD_ZERO(&fds_read); FD_ZERO(&fds_write);
217*433d6423SLionel Sambuc   FD_SET(fd_np1, &fds_read);
218*433d6423SLionel Sambuc   tv.tv_sec = DO_TIMEOUT; /* To make sure we get to see some error messages
219*433d6423SLionel Sambuc 			     instead of blocking forever when the
220*433d6423SLionel Sambuc 			     implementation is faulty. A timeout causes retval
221*433d6423SLionel Sambuc 			     to be 0. */
222*433d6423SLionel Sambuc   tv.tv_usec = 0;
223*433d6423SLionel Sambuc   /* The sleeping writer is about to wake up and write data to the pipe. */
224*433d6423SLionel Sambuc   retval = select(fd_np1+1, &fds_read, &fds_write, NULL, &tv);
225*433d6423SLionel Sambuc 
226*433d6423SLionel Sambuc   /* Correct amount of ready file descriptors? Just 1 read */
227*433d6423SLionel Sambuc   if(retval != 1) {
228*433d6423SLionel Sambuc     snprintf(errbuf, sizeof(errbuf),
229*433d6423SLionel Sambuc 	     "one fd should be set%s", (retval == 0 ? " (TIMEOUT)" : ""));
230*433d6423SLionel Sambuc     em(4, errbuf);
231*433d6423SLionel Sambuc   }
232*433d6423SLionel Sambuc 
233*433d6423SLionel Sambuc   if(!FD_ISSET(fd_np1, &fds_read)) em(5, "read should be set");
234*433d6423SLionel Sambuc 
235*433d6423SLionel Sambuc   /* Note that we left the write set empty. This should be equivalent to
236*433d6423SLionel Sambuc    * setting this parameter to NULL. */
237*433d6423SLionel Sambuc   if(!empty_fds(fd_np1+1, &fds_write)) em(6, "write should NOT be set");
238*433d6423SLionel Sambuc 
239*433d6423SLionel Sambuc   /* In case something went wrong above, we might end up with a child process
240*433d6423SLionel Sambuc    * blocking on a write call we close the file descriptor now. Synchronize on
241*433d6423SLionel Sambuc    * a read. */
242*433d6423SLionel Sambuc   if(read(fd_np1, buf, sizeof(SENDSTRING)) < 0) perror("Read error");
243*433d6423SLionel Sambuc 
244*433d6423SLionel Sambuc   /* Close file descriptor. We're going to reverse the test */
245*433d6423SLionel Sambuc   close(fd_np1);
246*433d6423SLionel Sambuc 
247*433d6423SLionel Sambuc   /* Wait for a second to allow the child to close the pipe as well */
248*433d6423SLionel Sambuc   tv.tv_sec = DO_HANDLEDATA;
249*433d6423SLionel Sambuc   tv.tv_usec = 0;
250*433d6423SLionel Sambuc   retval = select(0,NULL, NULL, NULL, &tv);
251*433d6423SLionel Sambuc 
252*433d6423SLionel Sambuc   /* Open named pipe for writing. This call blocks until a reader arrives. */
253*433d6423SLionel Sambuc   if((fd_np2 = open(NAMEDPIPE2, O_WRONLY)) == -1) {
254*433d6423SLionel Sambuc     printf("Error opening %s for writing\n",
255*433d6423SLionel Sambuc 	   NAMEDPIPE2);
256*433d6423SLionel Sambuc     perror(NULL);
257*433d6423SLionel Sambuc     printf("Please make sure that %s is not in use while running this test\n",
258*433d6423SLionel Sambuc 	   NAMEDPIPE2);
259*433d6423SLionel Sambuc     exit(-1);
260*433d6423SLionel Sambuc   }
261*433d6423SLionel Sambuc 
262*433d6423SLionel Sambuc   /* At this moment the child process has opened the named pipe for reading and
263*433d6423SLionel Sambuc    * we have opened it for writing. We're now going to reverse some of the
264*433d6423SLionel Sambuc    * tests we've done earlier. */
265*433d6423SLionel Sambuc 
266*433d6423SLionel Sambuc   /* Clear sets and set up bit masks */
267*433d6423SLionel Sambuc   FD_ZERO(&fds_read); FD_ZERO(&fds_write); FD_ZERO(&fds_error);
268*433d6423SLionel Sambuc   FD_SET(fd_np2, &fds_read);
269*433d6423SLionel Sambuc   FD_SET(fd_np2, &fds_write);
270*433d6423SLionel Sambuc   tv.tv_sec = DO_TIMEOUT;
271*433d6423SLionel Sambuc   tv.tv_usec = 0;
272*433d6423SLionel Sambuc   /* Select for reading from an fd opened O_WRONLY. This should return
273*433d6423SLionel Sambuc    * immediately as it is not a meaningful operation [1] and is therefore not
274*433d6423SLionel Sambuc    * blocking. The select should return two file descriptors are ready (the
275*433d6423SLionel Sambuc    * failing read and valid write). */
276*433d6423SLionel Sambuc 
277*433d6423SLionel Sambuc   retval = select(fd_np2+1, &fds_read, &fds_write, &fds_error, &tv);
278*433d6423SLionel Sambuc 
279*433d6423SLionel Sambuc   /* Did we receive an error? */
280*433d6423SLionel Sambuc   if(retval <= 0) {
281*433d6423SLionel Sambuc     snprintf(errbuf, sizeof(errbuf),
282*433d6423SLionel Sambuc 	     "two fds should be set%s", (retval == 0 ? " (TIMEOUT)" : ""));
283*433d6423SLionel Sambuc     em(7, errbuf);
284*433d6423SLionel Sambuc   }
285*433d6423SLionel Sambuc 
286*433d6423SLionel Sambuc   /* Make sure read bit is set (and just 1 bit) */
287*433d6423SLionel Sambuc   FD_ZERO(&fds_compare_read); FD_SET(fd_np2, &fds_compare_read);
288*433d6423SLionel Sambuc   if(!compare_fds(fd_np2+1, &fds_compare_read, &fds_read))
289*433d6423SLionel Sambuc     em(8, "read should be set");
290*433d6423SLionel Sambuc 
291*433d6423SLionel Sambuc   /* Write bit should be set (and just 1 bit) */
292*433d6423SLionel Sambuc   FD_ZERO(&fds_compare_write); FD_SET(fd_np2, &fds_compare_write);
293*433d6423SLionel Sambuc   if(!compare_fds(fd_np2+1, &fds_compare_write, &fds_write))
294*433d6423SLionel Sambuc     em(9, "write should be set");
295*433d6423SLionel Sambuc 
296*433d6423SLionel Sambuc   if(!empty_fds(fd_np2+1, &fds_error))
297*433d6423SLionel Sambuc     em(10, "Error should NOT be set");
298*433d6423SLionel Sambuc 
299*433d6423SLionel Sambuc   FD_ZERO(&fds_read); FD_ZERO(&fds_write);
300*433d6423SLionel Sambuc   FD_SET(fd_np2, &fds_write);
301*433d6423SLionel Sambuc   tv.tv_sec = DO_TIMEOUT;
302*433d6423SLionel Sambuc   tv.tv_usec = 0;
303*433d6423SLionel Sambuc   retval = select(fd_np2+1, &fds_read, &fds_write, NULL, &tv);
304*433d6423SLionel Sambuc 
305*433d6423SLionel Sambuc   /* Correct amount of ready file descriptors? Just 1 write */
306*433d6423SLionel Sambuc   if(retval != 1) {
307*433d6423SLionel Sambuc     snprintf(errbuf, sizeof(errbuf),
308*433d6423SLionel Sambuc 	     "one fd should be set%s", (retval == 0 ? " (TIMEOUT)" : ""));
309*433d6423SLionel Sambuc     em(11, errbuf);
310*433d6423SLionel Sambuc   }
311*433d6423SLionel Sambuc 
312*433d6423SLionel Sambuc   if(!empty_fds(fd_np2+1, &fds_read)) em(12, "read should NOT be set");
313*433d6423SLionel Sambuc 
314*433d6423SLionel Sambuc   /*                             Anonymous pipe                              */
315*433d6423SLionel Sambuc 
316*433d6423SLionel Sambuc   /* Check if we can write to the pipe */
317*433d6423SLionel Sambuc   FD_ZERO(&fds_read); FD_ZERO(&fds_write);
318*433d6423SLionel Sambuc   FD_SET(fd_ap[1], &fds_write);
319*433d6423SLionel Sambuc   tv.tv_sec = DO_TIMEOUT;
320*433d6423SLionel Sambuc   tv.tv_usec = 0;
321*433d6423SLionel Sambuc   retval = select(fd_ap[1]+1, NULL, &fds_write, NULL, &tv);
322*433d6423SLionel Sambuc 
323*433d6423SLionel Sambuc   /* Correct amount of ready file descriptors? Just 1 write */
324*433d6423SLionel Sambuc   if(retval != 1) {
325*433d6423SLionel Sambuc     snprintf(errbuf, sizeof(errbuf),
326*433d6423SLionel Sambuc 	     "one fd should be set%s", (retval == 0 ? " (TIMEOUT)" : ""));
327*433d6423SLionel Sambuc     em(13, errbuf);
328*433d6423SLionel Sambuc   }
329*433d6423SLionel Sambuc 
330*433d6423SLionel Sambuc   /* Make sure write bit is set (and just 1 bit) */
331*433d6423SLionel Sambuc   FD_ZERO(&fds_compare_write); FD_SET(fd_ap[1], &fds_compare_write);
332*433d6423SLionel Sambuc   if(!compare_fds(fd_ap[1]+1, &fds_compare_write, &fds_write))
333*433d6423SLionel Sambuc     em(14, "write should be set");
334*433d6423SLionel Sambuc 
335*433d6423SLionel Sambuc   /* Intentionally test reading from pipe and letting it time out. */
336*433d6423SLionel Sambuc   FD_SET(fd_ap[0], &fds_read);
337*433d6423SLionel Sambuc   tv.tv_sec = 1;
338*433d6423SLionel Sambuc   tv.tv_usec = 0;
339*433d6423SLionel Sambuc   start = time(NULL);
340*433d6423SLionel Sambuc   retval = select(fd_ap[0]+1, &fds_read, NULL, NULL, &tv);
341*433d6423SLionel Sambuc   end = time(NULL);
342*433d6423SLionel Sambuc 
343*433d6423SLionel Sambuc   /* Did we time out? */
344*433d6423SLionel Sambuc   if(retval != 0) em(15, "we should have timed out");
345*433d6423SLionel Sambuc 
346*433d6423SLionel Sambuc   /* Did it take us approximately 1 second? */
347*433d6423SLionel Sambuc   if((int) (end - start) != 1) {
348*433d6423SLionel Sambuc     snprintf(errbuf, sizeof(errbuf),
349*433d6423SLionel Sambuc 	     "time out is not 1 second (instead, it is %ld)",
350*433d6423SLionel Sambuc 	     (long int) (end - start));
351*433d6423SLionel Sambuc     em(16, errbuf);
352*433d6423SLionel Sambuc   }
353*433d6423SLionel Sambuc 
354*433d6423SLionel Sambuc   /* Do another read, but this time we expect incoming data from child. */
355*433d6423SLionel Sambuc   FD_ZERO(&fds_read);
356*433d6423SLionel Sambuc   FD_SET(fd_ap[0], &fds_read);
357*433d6423SLionel Sambuc   tv.tv_sec = DO_TIMEOUT;
358*433d6423SLionel Sambuc   tv.tv_usec = 0;
359*433d6423SLionel Sambuc   retval = select(fd_ap[0]+1, &fds_read, NULL, NULL, &tv);
360*433d6423SLionel Sambuc 
361*433d6423SLionel Sambuc   /* Correct amount of ready file descriptors? Just 1 read. */
362*433d6423SLionel Sambuc   if(retval != 1) em(17, "one fd should be set");
363*433d6423SLionel Sambuc 
364*433d6423SLionel Sambuc   /* Is the read bit set? And just 1 bit. */
365*433d6423SLionel Sambuc   FD_ZERO(&fds_compare_read); FD_SET(fd_ap[0], &fds_compare_read);
366*433d6423SLionel Sambuc   if(!compare_fds(fd_ap[0]+1, &fds_compare_read, &fds_read))
367*433d6423SLionel Sambuc     em(18, "read should be set.");
368*433d6423SLionel Sambuc 
369*433d6423SLionel Sambuc   /* By convention fd_ap[0] is meant to be used for reading from the pipe and
370*433d6423SLionel Sambuc    * fd_ap[1] is meant for writing, where fd_ap is a an anonymous pipe.
371*433d6423SLionel Sambuc    * However, it is unspecified what happens when fd_ap[0] is used for writing
372*433d6423SLionel Sambuc    * and fd_ap[1] for reading. (It is unsupported on Minix.) As such, it is not
373*433d6423SLionel Sambuc    * necessary to make test cases for wrong pipe file descriptors using select.
374*433d6423SLionel Sambuc    */
375*433d6423SLionel Sambuc 
376*433d6423SLionel Sambuc   waitpid(child, &retval, 0);
377*433d6423SLionel Sambuc   unlink(NAMEDPIPE2);
378*433d6423SLionel Sambuc   unlink(NAMEDPIPE1);
379*433d6423SLionel Sambuc   exit(errct);
380*433d6423SLionel Sambuc }
381*433d6423SLionel Sambuc 
main(int argc,char ** argv)382*433d6423SLionel Sambuc int main(int argc, char **argv) {
383*433d6423SLionel Sambuc   int forkres;
384*433d6423SLionel Sambuc 
385*433d6423SLionel Sambuc   /* Get subtest number */
386*433d6423SLionel Sambuc   if(argc != 2) {
387*433d6423SLionel Sambuc     printf("Usage: %s subtest_no\n", argv[0]);
388*433d6423SLionel Sambuc     exit(-2);
389*433d6423SLionel Sambuc   } else if(sscanf(argv[1], "%d", &subtest) != 1) {
390*433d6423SLionel Sambuc     printf("Usage: %s subtest_no\n", argv[0]);
391*433d6423SLionel Sambuc     exit(-2);
392*433d6423SLionel Sambuc   }
393*433d6423SLionel Sambuc 
394*433d6423SLionel Sambuc   /* Set up anonymous pipe */
395*433d6423SLionel Sambuc   if(pipe(fd_ap) < 0) {
396*433d6423SLionel Sambuc     perror("Could not create anonymous pipe");
397*433d6423SLionel Sambuc     exit(-1);
398*433d6423SLionel Sambuc   }
399*433d6423SLionel Sambuc 
400*433d6423SLionel Sambuc   /* Create named pipe2. It is unlinked by do_parent. */
401*433d6423SLionel Sambuc   if(mkfifo(NAMEDPIPE1, 0600) < 0) {
402*433d6423SLionel Sambuc     printf("Could not create named pipe %s", NAMEDPIPE1);
403*433d6423SLionel Sambuc     perror(NULL);
404*433d6423SLionel Sambuc     exit(-1);
405*433d6423SLionel Sambuc   }
406*433d6423SLionel Sambuc 
407*433d6423SLionel Sambuc   if(mkfifo(NAMEDPIPE2, 0600) < 0) {
408*433d6423SLionel Sambuc     printf("Could not create named pipe %s", NAMEDPIPE2);
409*433d6423SLionel Sambuc     perror(NULL);
410*433d6423SLionel Sambuc     exit(-1);
411*433d6423SLionel Sambuc   }
412*433d6423SLionel Sambuc 
413*433d6423SLionel Sambuc   forkres = fork();
414*433d6423SLionel Sambuc   if(forkres == 0) do_child();
415*433d6423SLionel Sambuc   else if(forkres > 0)  do_parent(forkres);
416*433d6423SLionel Sambuc   else { /* Fork failed */
417*433d6423SLionel Sambuc     perror("Unable to fork");
418*433d6423SLionel Sambuc     exit(-1);
419*433d6423SLionel Sambuc   }
420*433d6423SLionel Sambuc 
421*433d6423SLionel Sambuc   exit(-2); /* We're not supposed to get here. Both do_* routines should exit*/
422*433d6423SLionel Sambuc 
423*433d6423SLionel Sambuc }
424