1/*	$NetBSD$	*/
2
3/*++
4/* NAME
5/*	readable 3
6/* SUMMARY
7/*	test if descriptor is readable
8/* SYNOPSIS
9/*	#include <iostuff.h>
10/*
11/*	int	readable(fd)
12/*	int	fd;
13/* DESCRIPTION
14/*	readable() asks the kernel if the specified file descriptor
15/*	is readable, i.e. a read operation would not block.
16/*
17/*	Arguments:
18/* .IP fd
19/*	File descriptor in the range 0..FD_SETSIZE.
20/* DIAGNOSTICS
21/*	All system call errors are fatal.
22/* LICENSE
23/* .ad
24/* .fi
25/*	The Secure Mailer license must be distributed with this software.
26/* AUTHOR(S)
27/*	Wietse Venema
28/*	IBM T.J. Watson Research
29/*	P.O. Box 704
30/*	Yorktown Heights, NY 10598, USA
31/*--*/
32
33/* System library. */
34
35#include <sys_defs.h>
36#include <sys/time.h>
37#include <signal.h>
38#include <errno.h>
39#include <unistd.h>
40#include <string.h>
41
42#ifdef USE_SYSV_POLL
43#include <poll.h>
44#endif
45
46#ifdef USE_SYS_SELECT_H
47#include <sys/select.h>
48#endif
49
50/* Utility library. */
51
52#include <msg.h>
53#include <iostuff.h>
54
55/* readable - see if file descriptor is readable */
56
57int     readable(int fd)
58{
59#ifndef USE_SYSV_POLL
60    struct timeval tv;
61    fd_set  read_fds;
62    fd_set  except_fds;
63
64    /*
65     * Sanity checks.
66     */
67    if (fd >= FD_SETSIZE)
68	msg_fatal("fd %d does not fit in FD_SETSIZE", fd);
69
70    /*
71     * Initialize.
72     */
73    FD_ZERO(&read_fds);
74    FD_SET(fd, &read_fds);
75    FD_ZERO(&except_fds);
76    FD_SET(fd, &except_fds);
77    tv.tv_sec = 0;
78    tv.tv_usec = 0;
79
80    /*
81     * Loop until we have an authoritative answer.
82     */
83    for (;;) {
84	switch (select(fd + 1, &read_fds, (fd_set *) 0, &except_fds, &tv)) {
85	case -1:
86	    if (errno != EINTR)
87		msg_fatal("select: %m");
88	    continue;
89	default:
90	    return (FD_ISSET(fd, &read_fds));
91	case 0:
92	    return (0);
93	}
94    }
95#else
96
97    /*
98     * System-V poll() is optimal for polling a few descriptors.
99     */
100    struct pollfd pollfd;
101
102#define DONT_WAIT_FOR_EVENT	0
103
104    pollfd.fd = fd;
105    pollfd.events = POLLIN;
106    for (;;) {
107	switch (poll(&pollfd, 1, DONT_WAIT_FOR_EVENT)) {
108	case -1:
109	    if (errno != EINTR)
110		msg_fatal("poll: %m");
111	    continue;
112	case 0:
113	    return (0);
114	default:
115	    if (pollfd.revents & POLLNVAL)
116		msg_fatal("poll: %m");
117	    return (1);
118	}
119    }
120#endif
121}
122