Postfix3.3.1
fifo_rdonly_bug.c
[詳解]
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 
41 static 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 
49 static void perrorcleanup(char *str)
50 {
51  perror(str);
52  cleanup();
53  exit(0);
54 }
55 
56 static 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 
72 int 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 }
int main(int unused_argc, char **unused_argv)
#define FIFO_PATH
#define perrorexit(s)