12209d3c8SRichard Lowe /*
22209d3c8SRichard Lowe  * This file and its contents are supplied under the terms of the
32209d3c8SRichard Lowe  * Common Development and Distribution License ("CDDL"), version 1.0.
42209d3c8SRichard Lowe  * You may only use this file in accordance with the terms of version
52209d3c8SRichard Lowe  * 1.0 of the CDDL.
62209d3c8SRichard Lowe  *
72209d3c8SRichard Lowe  * A full copy of the text of the CDDL should have accompanied this
82209d3c8SRichard Lowe  * source.  A copy of the CDDL is also available via the Internet at
92209d3c8SRichard Lowe  * http://www.illumos.org/license/CDDL.
102209d3c8SRichard Lowe  */
112209d3c8SRichard Lowe 
122209d3c8SRichard Lowe /* Copyright 2016, Richard Lowe. */
132209d3c8SRichard Lowe 
142209d3c8SRichard Lowe #include <sys/select.h>
152209d3c8SRichard Lowe #include <sys/stat.h>
162209d3c8SRichard Lowe #include <sys/time.h>
172209d3c8SRichard Lowe #include <sys/types.h>
182209d3c8SRichard Lowe 
192209d3c8SRichard Lowe #include <err.h>
202209d3c8SRichard Lowe #include <errno.h>
212209d3c8SRichard Lowe #include <fcntl.h>
222209d3c8SRichard Lowe #include <stdio.h>
232209d3c8SRichard Lowe #include <stdlib.h>
242209d3c8SRichard Lowe #include <string.h>
252209d3c8SRichard Lowe #include <unistd.h>
262209d3c8SRichard Lowe 
272209d3c8SRichard Lowe void
diff_sets(fd_set * a,fd_set * b,size_t size)282209d3c8SRichard Lowe diff_sets(fd_set *a, fd_set *b, size_t size)
292209d3c8SRichard Lowe {
302209d3c8SRichard Lowe 	for (int i = 0; i < size; i++) {
312209d3c8SRichard Lowe 		if (FD_ISSET(i, a) != FD_ISSET(i, b))
322209d3c8SRichard Lowe 			printf("fd %d: %d should be %d\n", i, FD_ISSET(i, a),
332209d3c8SRichard Lowe 			    FD_ISSET(i, b));
342209d3c8SRichard Lowe 	}
352209d3c8SRichard Lowe }
362209d3c8SRichard Lowe 
372209d3c8SRichard Lowe void
print_set(fd_set * a,size_t size)382209d3c8SRichard Lowe print_set(fd_set *a, size_t size)
392209d3c8SRichard Lowe {
402209d3c8SRichard Lowe 	for (int i = 0; i < size; i++) {
412209d3c8SRichard Lowe 		if (FD_ISSET(i, a))
42*b36afad7SRobert Mustacchi 			(void) putc('1', stdout);
432209d3c8SRichard Lowe 		else
44*b36afad7SRobert Mustacchi 			(void) putc('0', stdout);
452209d3c8SRichard Lowe 	}
462209d3c8SRichard Lowe 
47*b36afad7SRobert Mustacchi 	(void) putc('\n', stdout);
482209d3c8SRichard Lowe }
492209d3c8SRichard Lowe 
502209d3c8SRichard Lowe int
main(int argc,char ** argv)512209d3c8SRichard Lowe main(int argc, char **argv)
522209d3c8SRichard Lowe {
532209d3c8SRichard Lowe 	struct timeval tv = {0, 0};
542209d3c8SRichard Lowe 	fd_set check, proto;
552209d3c8SRichard Lowe 	fd_set *sread = NULL, *swrite = NULL, *serr = NULL;
562209d3c8SRichard Lowe 	int null, zero, maxfd = -1, nfds;
572209d3c8SRichard Lowe 	char buf[1];
582209d3c8SRichard Lowe 
592209d3c8SRichard Lowe 	if (argc != 2)
602209d3c8SRichard Lowe 		errx(1, "usage: select_test <number of fds>");
612209d3c8SRichard Lowe 
622209d3c8SRichard Lowe 	nfds = atoi(argv[1]);
632209d3c8SRichard Lowe 	if (errno != 0)
642209d3c8SRichard Lowe 		err(1, "couldn't convert %s to int", argv[1]);
652209d3c8SRichard Lowe 
662209d3c8SRichard Lowe 	if (nfds > FD_SETSIZE)
672209d3c8SRichard Lowe 		errx(1, "can't have more fds than FD_SETSIZE %d", FD_SETSIZE);
682209d3c8SRichard Lowe 
692209d3c8SRichard Lowe 	FD_ZERO(&proto);
702209d3c8SRichard Lowe 	FD_ZERO(&check);
712209d3c8SRichard Lowe 
722209d3c8SRichard Lowe 	switch (arc4random_uniform(3)) {
732209d3c8SRichard Lowe 	case 0:
742209d3c8SRichard Lowe 		sread = &check;
752209d3c8SRichard Lowe 		break;
762209d3c8SRichard Lowe 	case 1:
772209d3c8SRichard Lowe 		swrite = &check;
782209d3c8SRichard Lowe 		break;
792209d3c8SRichard Lowe 	case 2:
802209d3c8SRichard Lowe 		serr = &check;
812209d3c8SRichard Lowe 		break;
822209d3c8SRichard Lowe 	}
832209d3c8SRichard Lowe 
842209d3c8SRichard Lowe 	closefrom(3);
852209d3c8SRichard Lowe 
862209d3c8SRichard Lowe 	if ((null = open("/dev/null", O_RDONLY)) == -1)
872209d3c8SRichard Lowe 		err(1, "couldn't open /dev/null");
88*b36afad7SRobert Mustacchi 	if (read(null, &buf, 1) < 0)
89*b36afad7SRobert Mustacchi 		err(1, "failed to read fd");
90*b36afad7SRobert Mustacchi 	if (read(null, &buf, 1) < 0)
91*b36afad7SRobert Mustacchi 		err(1, "failed to read fd");
922209d3c8SRichard Lowe 
932209d3c8SRichard Lowe 	if ((zero = open("/dev/zero", O_RDWR)) == -1)
942209d3c8SRichard Lowe 		err(1, "couldn't open /dev/zero");
952209d3c8SRichard Lowe 
962209d3c8SRichard Lowe 	for (int i = zero; i < (zero + nfds); i++) {
972209d3c8SRichard Lowe 		int fd = (serr != NULL) ? null : zero;
982209d3c8SRichard Lowe 		if (arc4random_uniform(100) > 90) {
992209d3c8SRichard Lowe 			FD_SET(i, &proto);
1002209d3c8SRichard Lowe 		}
1012209d3c8SRichard Lowe 
1022209d3c8SRichard Lowe 		if (dup2(fd, i) == -1)
1032209d3c8SRichard Lowe 			err(1, "couldn't dup fd to fd %d", i);
1042209d3c8SRichard Lowe 		maxfd = i;
1052209d3c8SRichard Lowe 	}
1062209d3c8SRichard Lowe 
1072209d3c8SRichard Lowe 	if (swrite != NULL)
108*b36afad7SRobert Mustacchi 		(void) puts("write");
1092209d3c8SRichard Lowe 	else if (sread != NULL)
110*b36afad7SRobert Mustacchi 		(void) puts("read");
1112209d3c8SRichard Lowe 	else if (serr != NULL)
112*b36afad7SRobert Mustacchi 		(void) puts("err");
1132209d3c8SRichard Lowe 
1142209d3c8SRichard Lowe 	print_set(&proto, 80);
1152209d3c8SRichard Lowe 
1162209d3c8SRichard Lowe 	memcpy(&check, &proto, sizeof (check));
1172209d3c8SRichard Lowe 
1182209d3c8SRichard Lowe 	if (select(maxfd + 1, sread, swrite, serr, &tv) == -1)
1192209d3c8SRichard Lowe 		err(1, "select failed");
1202209d3c8SRichard Lowe 
1212209d3c8SRichard Lowe 	if (memcmp(&check, &proto, sizeof (check)) != 0) {
1222209d3c8SRichard Lowe 		diff_sets(&check, &proto, sizeof (check));
1232209d3c8SRichard Lowe 		warnx("fd set mismatch: check: %p  proto: %p", &check, &proto);
1242209d3c8SRichard Lowe 		abort();
1252209d3c8SRichard Lowe 	}
1262209d3c8SRichard Lowe 
1272209d3c8SRichard Lowe 	return (0);
1282209d3c8SRichard Lowe }
129