xref: /openbsd/regress/sys/fifofs/fifotest.c (revision 3d8817e4)
1 /*
2  * Copyright (c) 2004 Todd C. Miller <Todd.Miller@courtesan.com>
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/poll.h>
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <signal.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27 
28 #ifndef INFTIM
29 #define	INFTIM	-1
30 #endif
31 
32 void usage(void);
33 void sigalrm(int);
34 void dopoll(int, int, char *, int);
35 void doselect(int, int, int);
36 void runtest(char *, int, int);
37 
38 #if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || \
39     defined(__linux__)
40 extern char *__progname;
41 #else
42 char *__progname;
43 #endif
44 
45 /*
46  * Test FIFOs and poll(2) both with an emtpy and full FIFO.
47  */
48 int
49 main(int argc, char **argv)
50 {
51 #if !defined(__OpenBSD__) && !defined(__FreeBSD__) && !defined(__NetBSD__) && \
52     !defined(__linux__)
53 	__progname = argv[0];
54 #endif
55 	if (argc != 2)
56 		usage();
57 
58 	runtest(argv[1], 0, 0);
59 	runtest(argv[1], 0, INFTIM);
60 	runtest(argv[1], O_NONBLOCK, 0);
61 	runtest(argv[1], O_NONBLOCK, INFTIM);
62 
63 	exit(0);
64 }
65 
66 void
67 runtest(char *fifo, int flags, int timeout)
68 {
69 	struct sigaction sa;
70 	ssize_t nread;
71 	int fd;
72 	char buf[BUFSIZ];
73 
74 	(void)unlink(fifo);
75 	if (mkfifo(fifo, 0644) != 0) {
76 		printf("mkfifo %s: %s\n", fifo, strerror(errno));
77 		exit(1);
78 	}
79 
80 	sigemptyset(&sa.sa_mask);
81 	sa.sa_flags = 0;
82 	sa.sa_handler = sigalrm;
83 	sigaction(SIGALRM, &sa, NULL);
84 
85 	alarm(2);
86 	if ((fd = open(fifo, O_RDWR | flags, 0644)) == -1) {
87 		printf("open %s: %s\n", fifo, strerror(errno));
88 		exit(1);
89 	}
90 	alarm(0);
91 	(void)unlink(fifo);
92 	printf("\nOpened fifo %s%s\n", fifo,
93 	    (flags & O_NONBLOCK) ? " (nonblocking)" : "");
94 
95 	printf("\nTesting empty FIFO:\n");
96 	dopoll(fd, POLLIN|POLLOUT, "POLLIN|POLLOUT", timeout);
97 	dopoll(fd, POLLIN, "POLLIN", timeout);
98 	dopoll(fd, POLLOUT, "POLLOUT", timeout);
99 	doselect(fd, fd, timeout);
100 	doselect(fd, -1, timeout);
101 	doselect(-1, fd, timeout);
102 
103 	if (write(fd, "test", 4) != 4) {
104 		printf("write error: %s\n", strerror(errno));
105 		exit(1);
106 	}
107 
108 	printf("\nTesting full FIFO:\n");
109 	dopoll(fd, POLLIN|POLLOUT, "POLLIN|POLLOUT", timeout);
110 	dopoll(fd, POLLIN, "POLLIN", timeout);
111 	dopoll(fd, POLLOUT, "POLLOUT", timeout);
112 	doselect(fd, fd, timeout);
113 	doselect(fd, -1, timeout);
114 	doselect(-1, fd, timeout);
115 
116 	if ((nread = read(fd, buf, sizeof(buf))) <= 0) {
117 		printf("read error: %s\n", (nread == 0) ? "EOF" : strerror(errno));
118 		exit(1);
119 	}
120 	buf[nread] = '\0';
121 	printf("\treceived '%s' from FIFO\n", buf);
122 }
123 
124 void
125 dopoll(int fd, int events, char *str, int timeout)
126 {
127 	struct pollfd pfd;
128 	int nready;
129 
130 	pfd.fd = fd;
131 	pfd.events = events;
132 
133 	printf("\tpoll %s, timeout=%d\n", str, timeout);
134 	pfd.events = events;
135 	alarm(2);
136 	nready = poll(&pfd, 1, timeout);
137 	alarm(0);
138 	if (nready < 0) {
139 		printf("poll: %s\n", strerror(errno));
140 		return;
141 	}
142 	printf("\t\t%d fd(s) ready%s", nready, nready ? ", revents ==" : "");
143 	if (pfd.revents & POLLIN)
144 		printf(" POLLIN");
145 	if (pfd.revents & POLLOUT)
146 		printf(" POLLOUT");
147 	if (pfd.revents & POLLERR)
148 		printf(" POLLERR");
149 	if (pfd.revents & POLLHUP)
150 		printf(" POLLHUP");
151 	if (pfd.revents & POLLNVAL)
152 		printf(" POLLNVAL");
153 	printf("\n");
154 }
155 
156 void
157 doselect(int rfd, int wfd, int timeout)
158 {
159 	struct timeval tv, *tvp;
160 	fd_set *rfds = NULL, *wfds = NULL;
161 	int nready, maxfd;
162 
163 	if (timeout == INFTIM)
164 		tvp = NULL;
165 	else {
166 		tv.tv_sec = timeout / 1000;
167 		tv.tv_usec = (timeout % 1000) * 1000;
168 		tvp = &tv;
169 	}
170 	tv.tv_sec = tv.tv_usec = 0;
171 	maxfd = rfd > wfd ? rfd : wfd;
172 	if (rfd != -1) {
173 		rfds = calloc(howmany(maxfd + 1, NFDBITS), sizeof(fd_mask));
174 		if (rfds == NULL) {
175 			printf("unable to allocate memory\n");
176 			exit(1);
177 		}
178 		FD_SET(rfd, rfds);
179 	}
180 	if (wfd != -1) {
181 		wfds = calloc(howmany(maxfd + 1, NFDBITS), sizeof(fd_mask));
182 		if (wfds == NULL) {
183 			printf("unable to allocate memory\n");
184 			exit(1);
185 		}
186 		FD_SET(wfd, wfds);
187 	}
188 
189 	printf("\tselect%s%s\n", rfds ? " read" : "",
190 	    wfds ? " write" : "");
191 
192 	alarm(2);
193 	nready = select(maxfd + 1, rfds, wfds, NULL, &tv);
194 	alarm(0);
195 	if (nready < 0) {
196 		printf("select: %s\n", strerror(errno));
197 		goto cleanup;
198 	}
199 	printf("\t\t%d fd(s) ready", nready);
200 	if (rfds != NULL && FD_ISSET(rfd, rfds))
201 		printf(", readable");
202 	if (wfds != NULL && FD_ISSET(wfd, wfds))
203 		printf(", writeable");
204 	printf("\n");
205 cleanup:
206 	free(rfds);
207 	free(wfds);
208 }
209 
210 void
211 sigalrm(int dummy)
212 {
213 	/* Just cause EINTR */
214 	return;
215 }
216 
217 void
218 usage(void)
219 {
220 	fprintf(stderr, "usage: %s fifoname\n", __progname);
221 	exit(1);
222 }
223