1 /* 2 * Copyright (c) 2004, 2014-2015 Todd C. Miller <millert@openbsd.org> 3 * 4 * Permission to use, copy, modify, and distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17 #include <sys/param.h> 18 #include <sys/stat.h> 19 #include <sys/wait.h> 20 #include <errno.h> 21 #include <fcntl.h> 22 #include <poll.h> 23 #include <signal.h> 24 #include <stdio.h> 25 #include <stdlib.h> 26 #include <string.h> 27 #include <unistd.h> 28 29 #ifndef INFTIM 30 #define INFTIM -1 31 #endif 32 33 void usage(void); 34 void sigalrm(int); 35 void sigusr1(int); 36 void dopoll(pid_t, int, int, char *, int); 37 void doselect(pid_t, int, int, int); 38 void runtest(char *, int, int); 39 void eoftest(char *, int, int); 40 41 #if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || \ 42 defined(__linux__) 43 extern char *__progname; 44 #else 45 char *__progname; 46 #endif 47 48 /* 49 * Test FIFOs and poll(2) both with an emtpy and full FIFO. 50 */ 51 int 52 main(int argc, char **argv) 53 { 54 struct sigaction sa; 55 #if !defined(__OpenBSD__) && !defined(__FreeBSD__) && !defined(__NetBSD__) && \ 56 !defined(__linux__) 57 __progname = argv[0]; 58 #endif 59 if (argc != 2) 60 usage(); 61 62 /* Just want EINTR from SIGALRM */ 63 sigemptyset(&sa.sa_mask); 64 sa.sa_flags = 0; 65 sa.sa_handler = sigalrm; 66 sigaction(SIGALRM, &sa, NULL); 67 68 /* SIGUSR1 is used for synchronization only. */ 69 sa.sa_flags = SA_RESTART; 70 sa.sa_handler = sigusr1; 71 sigaction(SIGUSR1, &sa, NULL); 72 73 runtest(argv[1], 0, 0); 74 runtest(argv[1], 0, INFTIM); 75 runtest(argv[1], O_NONBLOCK, 0); 76 runtest(argv[1], O_NONBLOCK, INFTIM); 77 eoftest(argv[1], O_NONBLOCK, INFTIM); 78 79 exit(0); 80 } 81 82 void 83 runtest(char *fifo, int flags, int timeout) 84 { 85 ssize_t nread; 86 int fd; 87 char buf[BUFSIZ]; 88 89 (void)unlink(fifo); 90 if (mkfifo(fifo, 0644) != 0) { 91 printf("mkfifo %s: %s\n", fifo, strerror(errno)); 92 exit(1); 93 } 94 95 /* Note: O_RDWR not required by POSIX */ 96 alarm(2); 97 if ((fd = open(fifo, O_RDWR | flags, 0644)) == -1) { 98 printf("open %s: %s\n", fifo, strerror(errno)); 99 exit(1); 100 } 101 alarm(0); 102 (void)unlink(fifo); 103 printf("\nOpened fifo %s%s\n", fifo, 104 (flags & O_NONBLOCK) ? " (nonblocking)" : ""); 105 106 printf("\nTesting empty FIFO:\n"); 107 dopoll(-1, fd, POLLIN|POLLOUT, "POLLIN|POLLOUT", timeout); 108 dopoll(-1, fd, POLLIN, "POLLIN", timeout); 109 dopoll(-1, fd, POLLOUT, "POLLOUT", timeout); 110 dopoll(-1, fd, 0, "(none)", timeout); 111 doselect(-1, fd, fd, timeout); 112 doselect(-1, fd, -1, timeout); 113 doselect(-1, -1, fd, timeout); 114 doselect(-1, -1, -1, timeout); 115 116 if (write(fd, "test", 4) != 4) { 117 printf("write error: %s\n", strerror(errno)); 118 exit(1); 119 } 120 121 printf("\nTesting full FIFO:\n"); 122 dopoll(-1, fd, POLLIN|POLLOUT, "POLLIN|POLLOUT", timeout); 123 dopoll(-1, fd, POLLIN, "POLLIN", timeout); 124 dopoll(-1, fd, POLLOUT, "POLLOUT", timeout); 125 dopoll(-1, fd, 0, "(none)", timeout); 126 doselect(-1, fd, fd, timeout); 127 doselect(-1, fd, -1, timeout); 128 doselect(-1, -1, fd, timeout); 129 doselect(-1, -1, -1, timeout); 130 131 if ((nread = read(fd, buf, sizeof(buf))) <= 0) { 132 printf("read error: %s\n", (nread == 0) ? "EOF" : strerror(errno)); 133 exit(1); 134 } 135 buf[nread] = '\0'; 136 printf("\treceived '%s' from FIFO\n", buf); 137 } 138 139 pid_t 140 eof_writer(const char *fifo, int flags) 141 { 142 int fd; 143 pid_t pid; 144 sigset_t mask, omask; 145 146 /* Block SIGUSR1 (in child). */ 147 sigemptyset(&mask); 148 sigaddset(&mask, SIGUSR1); 149 sigprocmask(SIG_BLOCK, &mask, &omask); 150 151 switch ((pid = fork())) { 152 case -1: 153 printf("fork: %s\n", strerror(errno)); 154 return -1; 155 case 0: 156 /* child */ 157 break; 158 default: 159 /* parent */ 160 sigprocmask(SIG_SETMASK, &omask, NULL); 161 return pid; 162 } 163 164 /* Wait for reader. */ 165 sigemptyset(&mask); 166 sigsuspend(&mask); 167 sigprocmask(SIG_SETMASK, &omask, NULL); 168 169 /* connect to FIFO. */ 170 alarm(2); 171 fd = open(fifo, O_WRONLY | flags, 0644); 172 alarm(0); 173 if (fd == -1) { 174 printf("open %s O_WRONLY: %s\n", fifo, strerror(errno)); 175 return -1; 176 } 177 178 /* 179 * We need to give the reader time to call poll() or select() 180 * before we close the fd. This is racey... 181 */ 182 usleep(100000); 183 close(fd); 184 _exit(0); 185 } 186 187 void 188 eoftest(char *fifo, int flags, int timeout) 189 { 190 ssize_t nread; 191 int fd = -1, pass, status; 192 pid_t writer; 193 char buf[BUFSIZ]; 194 195 /* 196 * Test all combinations of select and poll. 197 */ 198 for (pass = 0; pass < 16; pass++) { 199 /* 200 * We run each test twice, once with a fresh fifo, 201 * and once with a reused one. 202 */ 203 if ((pass & 1) == 0) { 204 if (fd != -1) 205 close(fd); 206 (void)unlink(fifo); 207 if (mkfifo(fifo, 0644) != 0) { 208 printf("mkfifo %s: %s\n", fifo, strerror(errno)); 209 exit(1); 210 } 211 212 /* XXX - also verify that we get alarm for O_RDWR */ 213 alarm(2); 214 if ((fd = open(fifo, O_RDONLY | flags, 0644)) == -1) { 215 printf("open %s: %s\n", fifo, strerror(errno)); 216 exit(1); 217 } 218 alarm(0); 219 220 printf("\nOpened fifo for reading %s%s\n", fifo, 221 (flags & O_NONBLOCK) ? " (nonblocking)" : ""); 222 } 223 224 printf("\nTesting EOF FIFO behavior (pass %d):\n", pass); 225 226 /* 227 * The writer will sleep for a bit to give the reader time 228 * to call select() before anything has been written. 229 */ 230 writer = eof_writer(fifo, flags); 231 if (writer == -1) 232 exit(1); 233 234 switch (pass) { 235 case 0: 236 case 1: 237 dopoll(writer, fd, POLLIN|POLLOUT, "POLLIN|POLLOUT", timeout); 238 break; 239 case 2: 240 case 3: 241 dopoll(writer, fd, POLLIN, "POLLIN", timeout); 242 break; 243 case 4: 244 case 5: 245 dopoll(writer, fd, POLLOUT, "POLLOUT", timeout); 246 break; 247 case 6: 248 case 7: 249 dopoll(writer, fd, 0, "(none)", timeout); 250 break; 251 case 8: 252 case 9: 253 doselect(writer, fd, fd, timeout); 254 break; 255 case 10: 256 case 11: 257 doselect(writer, fd, -1, timeout); 258 break; 259 case 12: 260 case 13: 261 doselect(writer, -1, fd, timeout); 262 break; 263 case 14: 264 case 15: 265 doselect(writer, -1, -1, timeout); 266 break; 267 } 268 wait(&status); 269 if ((nread = read(fd, buf, sizeof(buf))) < 0) { 270 printf("read error: %s\n", strerror(errno)); 271 exit(1); 272 } 273 buf[nread] = '\0'; 274 printf("\treceived %s%s%s from FIFO\n", nread ? "'" : "", 275 nread ? buf : "EOF", nread ? "'" : ""); 276 } 277 close(fd); 278 (void)unlink(fifo); 279 } 280 281 void 282 dopoll(pid_t writer, int fd, int events, char *str, int timeout) 283 { 284 struct pollfd pfd; 285 int nready; 286 287 pfd.fd = fd; 288 pfd.events = events; 289 290 printf("\tpoll %s, timeout=%d\n", str, timeout); 291 pfd.events = events; 292 if (writer != -1) 293 kill(writer, SIGUSR1); 294 alarm(2); 295 nready = poll(&pfd, 1, timeout); 296 alarm(0); 297 if (nready < 0) { 298 printf("poll: %s\n", strerror(errno)); 299 return; 300 } 301 printf("\t\t%d fd(s) ready%s", nready, nready ? ", revents ==" : ""); 302 if (pfd.revents & POLLIN) 303 printf(" POLLIN"); 304 if (pfd.revents & POLLOUT) 305 printf(" POLLOUT"); 306 if (pfd.revents & POLLERR) 307 printf(" POLLERR"); 308 if (pfd.revents & POLLHUP) 309 printf(" POLLHUP"); 310 if (pfd.revents & POLLNVAL) 311 printf(" POLLNVAL"); 312 printf("\n"); 313 } 314 315 void 316 doselect(pid_t writer, int rfd, int wfd, int timeout) 317 { 318 struct timeval tv, *tvp; 319 fd_set *rfds = NULL, *wfds = NULL; 320 int nready, maxfd; 321 322 if (timeout == INFTIM) 323 tvp = NULL; 324 else { 325 tv.tv_sec = timeout / 1000; 326 tv.tv_usec = (timeout % 1000) * 1000; 327 tvp = &tv; 328 } 329 maxfd = rfd > wfd ? rfd : wfd; 330 if (rfd != -1) { 331 rfds = calloc(howmany(maxfd + 1, NFDBITS), sizeof(fd_mask)); 332 if (rfds == NULL) { 333 printf("unable to allocate memory\n"); 334 exit(1); 335 } 336 FD_SET(rfd, rfds); 337 } 338 if (wfd != -1) { 339 wfds = calloc(howmany(maxfd + 1, NFDBITS), sizeof(fd_mask)); 340 if (wfds == NULL) { 341 printf("unable to allocate memory\n"); 342 exit(1); 343 } 344 FD_SET(wfd, wfds); 345 } 346 347 printf("\tselect%s%s, timeout=%d\n", rfds ? " read" : "", 348 wfds ? " write" : rfds ? "" : " (none)", timeout); 349 if (writer != -1) 350 kill(writer, SIGUSR1); 351 alarm(2); 352 nready = select(maxfd + 1, rfds, wfds, NULL, tvp); 353 alarm(0); 354 if (nready < 0) { 355 printf("select: %s\n", strerror(errno)); 356 goto cleanup; 357 } 358 printf("\t\t%d fd(s) ready", nready); 359 if (rfds != NULL && FD_ISSET(rfd, rfds)) 360 printf(", readable"); 361 if (wfds != NULL && FD_ISSET(wfd, wfds)) 362 printf(", writeable"); 363 printf("\n"); 364 cleanup: 365 free(rfds); 366 free(wfds); 367 } 368 369 void 370 sigalrm(int dummy) 371 { 372 /* Just cause EINTR */ 373 return; 374 } 375 376 void 377 sigusr1(int dummy) 378 { 379 return; 380 } 381 382 void 383 usage(void) 384 { 385 fprintf(stderr, "usage: %s fifoname\n", __progname); 386 exit(1); 387 } 388