split: be more careful about buffer sizes
[coreutils.git] / src / iopoll.c
bloba73ce05bfc3096e207c16dd29ed0f684512da3e6
1 /* iopoll.c -- broken pipe detection (while waiting for input)
2 Copyright (C) 1989-2022 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>.
17 Written by Carl Edquist in collaboration with Arsen Arsenović. */
19 #include <config.h>
21 #include <assert.h>
23 /* poll(2) is needed on AIX (where 'select' gives a readable
24 event immediately) and Solaris (where 'select' never gave
25 a readable event). Also use poll(2) on systems we know work
26 and/or are already using poll (linux). */
28 #if defined _AIX || defined __sun || defined __APPLE__ || \
29 defined __linux__ || defined __ANDROID__
30 # define IOPOLL_USES_POLL 1
31 /* Check we've not enabled gnulib's poll module
32 as that will emulate poll() in a way not
33 currently compatible with our usage. */
34 # if defined HAVE_POLL
35 # error "gnulib's poll() replacement is currently incompatible"
36 # endif
37 #endif
39 #if IOPOLL_USES_POLL
40 # include <poll.h>
41 #else
42 # include <sys/select.h>
43 #endif
45 #include "system.h"
46 #include "iopoll.h"
47 #include "isapipe.h"
50 /* Wait for FDIN to become ready for reading or FDOUT to become a broken pipe.
51 If either of those are -1, then they're not checked. Set BLOCK to true
52 to wait for an event, otherwise return the status immediately.
53 Return 0 if not BLOCKing and there is no event on the requested descriptors.
54 Return 0 if FDIN can be read() without blocking, or IOPOLL_BROKEN_OUTPUT if
55 FDOUT becomes a broken pipe, otherwise IOPOLL_ERROR if there is a poll()
56 or select() error. */
58 extern int
59 iopoll (int fdin, int fdout, bool block)
61 #if IOPOLL_USES_POLL
63 struct pollfd pfds[2] = { /* POLLRDBAND needed for illumos, macOS. */
64 { .fd = fdin, .events = POLLIN | POLLRDBAND, .revents = 0 },
65 { .fd = fdout, .events = POLLRDBAND, .revents = 0 },
67 int ret = 0;
69 while (0 <= ret || errno == EINTR)
71 ret = poll (pfds, 2, block ? -1 : 0);
73 if (ret < 0)
74 continue;
75 if (ret == 0 && ! block)
76 return 0;
77 assert (0 < ret);
78 if (pfds[0].revents) /* input available or pipe closed indicating EOF; */
79 return 0; /* should now be able to read() without blocking */
80 if (pfds[1].revents) /* POLLERR, POLLHUP (or POLLNVAL) */
81 return IOPOLL_BROKEN_OUTPUT; /* output error or broken pipe */
84 #else /* fall back to select()-based implementation */
86 int nfds = (fdin > fdout ? fdin : fdout) + 1;
87 int ret = 0;
89 /* If fdout has an error condition (like a broken pipe) it will be seen
90 as ready for reading. Assumes fdout is not actually readable. */
91 while (0 <= ret || errno == EINTR)
93 fd_set rfds;
94 FD_ZERO (&rfds);
95 if (0 <= fdin)
96 FD_SET (fdin, &rfds);
97 if (0 <= fdout)
98 FD_SET (fdout, &rfds);
100 struct timeval delay = { .tv_sec = 0, .tv_usec = 0 };
101 ret = select (nfds, &rfds, NULL, NULL, block ? NULL : &delay);
103 if (ret < 0)
104 continue;
105 if (ret == 0 && ! block)
106 return 0;
107 assert (0 < ret);
108 if (0 <= fdin && FD_ISSET (fdin, &rfds)) /* input available or EOF; */
109 return 0; /* should now be able to read() without blocking */
110 if (0 <= fdout && FD_ISSET (fdout, &rfds)) /* equiv to POLLERR */
111 return IOPOLL_BROKEN_OUTPUT; /* output error or broken pipe */
114 #endif
115 return IOPOLL_ERROR;
120 /* Return true if fdin is relevant for iopoll().
121 An fd is not relevant for iopoll() if it is always ready for reading,
122 which is the case for a regular file or block device. */
124 extern bool
125 iopoll_input_ok (int fdin)
127 struct stat st;
128 bool always_ready = fstat (fdin, &st) == 0
129 && (S_ISREG (st.st_mode)
130 || S_ISBLK (st.st_mode));
131 return ! always_ready;
134 /* Return true if fdout is suitable for iopoll().
135 Namely, fdout refers to a pipe. */
137 extern bool
138 iopoll_output_ok (int fdout)
140 return isapipe (fdout) > 0;