1 /* $NetBSD: fifo_rdonly_bug.c,v 1.1.1.1 2009/06/23 10:08:59 tron Exp $ */ 2 3 /*++ 4 /* NAME 5 /* fifo_rdonly_bug 1 6 /* SUMMARY 7 /* fifo server test program 8 /* SYNOPSIS 9 /* fifo_rdonly_bug 10 /* DESCRIPTION 11 /* fifo_rdonly_bug creates a FIFO and opens it read only. It 12 /* then opens the FIFO for writing, writes one byte, and closes 13 /* the writing end. On Linux Redhat 4.2 and 5.0, and HP-UX 9.05 14 /* and 10.20, select() will report that the FIFO remains readable 15 /* even after multiple read operations. 16 /* DIAGNOSTICS 17 /* Problems are reported to the standard error stream. 18 /* LICENSE 19 /* .ad 20 /* .fi 21 /* The Secure Mailer license must be distributed with this software. 22 /* AUTHOR(S) 23 /* Wietse Venema 24 /* IBM T.J. Watson Research 25 /* P.O. Box 704 26 /* Yorktown Heights, NY 10598, USA 27 /*--*/ 28 29 #include <sys_defs.h> 30 #include <sys/stat.h> 31 #include <sys/time.h> 32 #include <stdio.h> 33 #include <unistd.h> 34 #include <stdlib.h> 35 #include <fcntl.h> 36 #include <string.h> 37 38 #define FIFO_PATH "test-fifo" 39 #define TRIGGER_DELAY 5 40 41 #define perrorexit(s) { perror(s); exit(1); } 42 43 static void cleanup(void) 44 { 45 printf("Removing fifo %s...\n", FIFO_PATH); 46 if (unlink(FIFO_PATH)) 47 perrorexit("unlink"); 48 printf("Done.\n"); 49 } 50 51 static void perrorcleanup(char *str) 52 { 53 perror(str); 54 cleanup(); 55 exit(0); 56 } 57 58 static void readable_event(int fd) 59 { 60 char ch; 61 static int count = 0; 62 63 if (read(fd, &ch, 1) < 0) { 64 perror("read"); 65 sleep(1); 66 } 67 if (count++ > 5) { 68 printf("FIFO remains readable after multiple reads.\n"); 69 cleanup(); 70 exit(1); 71 } 72 } 73 74 int main(int unused_argc, char **unused_argv) 75 { 76 struct timeval tv; 77 fd_set read_fds; 78 fd_set except_fds; 79 int fd; 80 int fd2; 81 82 (void) unlink(FIFO_PATH); 83 84 printf("Create fifo %s...\n", FIFO_PATH); 85 if (mkfifo(FIFO_PATH, 0600) < 0) 86 perrorexit("mkfifo"); 87 88 printf("Open fifo %s, read-only mode...\n", FIFO_PATH); 89 if ((fd = open(FIFO_PATH, O_RDONLY | O_NONBLOCK, 0)) < 0) 90 perrorcleanup("open"); 91 92 printf("Write one byte to the fifo, then close it...\n"); 93 if ((fd2 = open(FIFO_PATH, O_WRONLY, 0)) < 0) 94 perrorcleanup("open fifo O_WRONLY"); 95 if (write(fd2, "", 1) < 1) 96 perrorcleanup("write one byte to fifo"); 97 if (close(fd2) < 0) 98 perrorcleanup("close fifo"); 99 100 printf("Selecting the fifo for readability...\n"); 101 102 for (;;) { 103 FD_ZERO(&read_fds); 104 FD_SET(fd, &read_fds); 105 FD_ZERO(&except_fds); 106 FD_SET(fd, &except_fds); 107 tv.tv_sec = 1; 108 tv.tv_usec = 0; 109 110 switch (select(fd + 1, &read_fds, (fd_set *) 0, &except_fds, &tv)) { 111 case -1: 112 perrorexit("select"); 113 default: 114 if (FD_ISSET(fd, &except_fds)) { 115 printf("Exceptional fifo condition! You are not normal!\n"); 116 readable_event(fd); 117 } else if (FD_ISSET(fd, &read_fds)) { 118 printf("Readable fifo condition\n"); 119 readable_event(fd); 120 } 121 break; 122 case 0: 123 printf("The fifo is not readable. You're normal.\n"); 124 cleanup(); 125 exit(0); 126 break; 127 } 128 } 129 } 130