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