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