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