--- src/pty.cc.orig 2026-04-27 01:38:36.332495159 +0000 +++ src/pty.cc 2026-04-27 01:39:38.062129905 +0000 @@ -5,11 +5,11 @@ #include #include +#include #include #include #include #include -#include class FdWrapper { public: @@ -134,34 +134,49 @@ return Expect::New(string("")); } - pollfd poll_master; - poll_master.fd = m_master; - poll_master.events = POLLIN; - poll_master.revents = 0; + // Use select() instead of poll() for compatibility with older macOS (10.6 and earlier) + // where poll() has known issues with PTYs + fd_set read_fds; + fd_set except_fds; + FD_ZERO(&read_fds); + FD_ZERO(&except_fds); + FD_SET(m_master, &read_fds); + FD_SET(m_master, &except_fds); fflush(stdout); - int polled = poll(&poll_master, 1, -1); - if (polled == -1) { + int selected = select(m_master + 1, &read_fds, nullptr, &except_fds, nullptr); + + if (selected == -1) { if (errno == EINTR) { return Expect::New(string("")); } else { - return Expect::New(Error::Errno().Extend("polling master PTY")); + return Expect::New(Error::Errno().Extend("select on master PTY")); } - } else if (poll_master.revents & POLLIN) { + } else if (selected == 0) { + // Timeout (shouldn't happen with NULL timeout, but handle gracefully) + return Expect::New(string("")); + } else if (FD_ISSET(m_master, &except_fds)) { + *eof = true; + return Expect::New(string("")); + } else if (FD_ISSET(m_master, &read_fds)) { fflush(stdout); char buf[4096]; int sz = read(m_master, buf, sizeof(buf)); if (sz == -1) { + if (errno == EAGAIN || errno == EWOULDBLOCK) { + return Expect::New(string("")); + } return Expect::New(Error::Errno().Extend("reading master PTY")); + } else if (sz == 0) { + *eof = true; + return Expect::New(string("")); } return Expect::New(string(buf, sz)); - } else if (poll_master.revents & (POLLERR | POLLHUP)) { - *eof = true; - return Expect::New(string("")); } else { - return Expect::WithError("unknown error occurred in NonblockingRead"); + // Shouldn't reach here, but return empty to retry + return Expect::New(string("")); } }