1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* Copyright 2016, Richard Lowe. */ 13 14 #include <sys/select.h> 15 #include <sys/stat.h> 16 #include <sys/time.h> 17 #include <sys/types.h> 18 19 #include <err.h> 20 #include <errno.h> 21 #include <fcntl.h> 22 #include <stdio.h> 23 #include <stdlib.h> 24 #include <string.h> 25 #include <unistd.h> 26 27 void 28 diff_sets(fd_set *a, fd_set *b, size_t size) 29 { 30 for (int i = 0; i < size; i++) { 31 if (FD_ISSET(i, a) != FD_ISSET(i, b)) 32 printf("fd %d: %d should be %d\n", i, FD_ISSET(i, a), 33 FD_ISSET(i, b)); 34 } 35 } 36 37 void 38 print_set(fd_set *a, size_t size) 39 { 40 for (int i = 0; i < size; i++) { 41 if (FD_ISSET(i, a)) 42 (void) putc('1', stdout); 43 else 44 (void) putc('0', stdout); 45 } 46 47 (void) putc('\n', stdout); 48 } 49 50 int 51 main(int argc, char **argv) 52 { 53 struct timeval tv = {0, 0}; 54 fd_set check, proto; 55 fd_set *sread = NULL, *swrite = NULL, *serr = NULL; 56 int null, zero, maxfd = -1, nfds; 57 char buf[1]; 58 59 if (argc != 2) 60 errx(1, "usage: select_test <number of fds>"); 61 62 nfds = atoi(argv[1]); 63 if (errno != 0) 64 err(1, "couldn't convert %s to int", argv[1]); 65 66 if (nfds > FD_SETSIZE) 67 errx(1, "can't have more fds than FD_SETSIZE %d", FD_SETSIZE); 68 69 FD_ZERO(&proto); 70 FD_ZERO(&check); 71 72 switch (arc4random_uniform(3)) { 73 case 0: 74 sread = ✓ 75 break; 76 case 1: 77 swrite = ✓ 78 break; 79 case 2: 80 serr = ✓ 81 break; 82 } 83 84 closefrom(3); 85 86 if ((null = open("/dev/null", O_RDONLY)) == -1) 87 err(1, "couldn't open /dev/null"); 88 if (read(null, &buf, 1) < 0) 89 err(1, "failed to read fd"); 90 if (read(null, &buf, 1) < 0) 91 err(1, "failed to read fd"); 92 93 if ((zero = open("/dev/zero", O_RDWR)) == -1) 94 err(1, "couldn't open /dev/zero"); 95 96 for (int i = zero; i < (zero + nfds); i++) { 97 int fd = (serr != NULL) ? null : zero; 98 if (arc4random_uniform(100) > 90) { 99 FD_SET(i, &proto); 100 } 101 102 if (dup2(fd, i) == -1) 103 err(1, "couldn't dup fd to fd %d", i); 104 maxfd = i; 105 } 106 107 if (swrite != NULL) 108 (void) puts("write"); 109 else if (sread != NULL) 110 (void) puts("read"); 111 else if (serr != NULL) 112 (void) puts("err"); 113 114 print_set(&proto, 80); 115 116 memcpy(&check, &proto, sizeof (check)); 117 118 if (select(maxfd + 1, sread, swrite, serr, &tv) == -1) 119 err(1, "select failed"); 120 121 if (memcmp(&check, &proto, sizeof (check)) != 0) { 122 diff_sets(&check, &proto, sizeof (check)); 123 warnx("fd set mismatch: check: %p proto: %p", &check, &proto); 124 abort(); 125 } 126 127 return (0); 128 } 129