/* input_avail.c -- check whether or not data is available for reading on a
specified file descriptor. */
-/* Copyright (C) 2008,2009 Free Software Foundation, Inc.
+/* Copyright (C) 2008,2009-2019 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
# include <sys/file.h>
#endif /* HAVE_SYS_FILE_H */
+#if defined (HAVE_PSELECT)
+# include <signal.h>
+#endif
+
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif /* HAVE_UNISTD_H */
timeout.tv_usec = 0;
result = select (fd + 1, &readfds, (fd_set *)NULL, &exceptfds, &timeout);
return ((result <= 0) ? 0 : 1);
-
#endif
- result = -1;
#if defined (FIONREAD)
errno = 0;
result = ioctl (fd, FIONREAD, &chars_avail);
return 0;
}
+
+/* Wait until NCHARS are available for reading on file descriptor FD.
+ This can wait indefinitely. Return -1 on error. */
+int
+nchars_avail (fd, nchars)
+ int fd;
+ int nchars;
+{
+ int result, chars_avail;
+#if defined(HAVE_SELECT)
+ fd_set readfds, exceptfds;
+#endif
+#if defined (HAVE_PSELECT)
+ sigset_t set, oset;
+#endif
+
+ if (fd < 0 || nchars < 0)
+ return -1;
+ if (nchars == 0)
+ return (input_avail (fd));
+
+ chars_avail = 0;
+
+#if defined (HAVE_SELECT)
+ FD_ZERO (&readfds);
+ FD_ZERO (&exceptfds);
+ FD_SET (fd, &readfds);
+ FD_SET (fd, &exceptfds);
+#endif
+#if defined (HAVE_SELECT) || defined (HAVE_PSELECT)
+ sigprocmask (SIG_BLOCK, (sigset_t *)NULL, &set);
+# ifdef SIGCHLD
+ sigaddset (&set, SIGCHLD);
+# endif
+ sigemptyset (&oset);
+#endif
+
+ while (1)
+ {
+ result = 0;
+#if defined (HAVE_PSELECT)
+ /* XXX - use pselect(2) to block SIGCHLD atomically */
+ result = pselect (fd + 1, &readfds, (fd_set *)NULL, &exceptfds, (struct timespec *)NULL, &set);
+#elif defined (HAVE_SELECT)
+ sigprocmask (SIG_BLOCK, &set, &oset);
+ result = select (fd + 1, &readfds, (fd_set *)NULL, &exceptfds, (struct timeval *)NULL);
+ sigprocmask (SIG_BLOCK, &oset, (sigset_t *)NULL);
+#endif
+ if (result < 0)
+ return -1;
+
+#if defined (FIONREAD)
+ errno = 0;
+ result = ioctl (fd, FIONREAD, &chars_avail);
+ if (result == -1 && errno == EIO)
+ return -1;
+ if (chars_avail >= nchars)
+ break;
+#else
+ break;
+#endif
+ }
+
+ return 0;
+}