summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTodd C. Miller <Todd.Miller@sudo.ws>2022-06-07 12:40:00 -0600
committerTodd C. Miller <Todd.Miller@sudo.ws>2022-06-07 12:40:00 -0600
commitb13c8d47935e5fd5548fefbd25acad17f98cf00e (patch)
tree766d43860c66720525d84686ed30f399d6d35db3
parent1e31f3a22a9535ba61dfd5f0aa33789b2f09aed9 (diff)
downloadsudo-b13c8d47935e5fd5548fefbd25acad17f98cf00e.tar.gz
Make read and write events persistent and disable as needed.
For the read callback, disable reader when the buffer is full. For the write callback, disable writer when the buffer is consumed.
-rw-r--r--src/exec_pty.c34
1 files changed, 13 insertions, 21 deletions
diff --git a/src/exec_pty.c b/src/exec_pty.c
index d2fc1ce5c..e2fd9c60e 100644
--- a/src/exec_pty.c
+++ b/src/exec_pty.c
@@ -677,12 +677,10 @@ read_callback(int fd, int what, void *v)
schedule_signal(iob->ec, SIGTTIN);
}
if (errno == EAGAIN || errno == EINTR) {
- /* Re-enable reader. */
- if (sudo_ev_add(evbase, iob->revent, NULL, false) == -1)
- sudo_fatal("%s", U_("unable to add event to queue"));
+ /* Not an error, retry later. */
break;
}
- /* treat read error as fatal and close the fd */
+ /* Treat read error as fatal and close the fd. */
sudo_debug_printf(SUDO_DEBUG_ERROR,
"error reading fd %d: %s", fd, strerror(errno));
FALLTHROUGH;
@@ -709,16 +707,14 @@ read_callback(int fd, int what, void *v)
iob->ec->cmnd_pid = -1;
}
iob->len += n;
- /* Enable writer now that there is data in the buffer. */
+ /* Disable reader if buffer is full. */
+ if (iob->len == sizeof(iob->buf))
+ sudo_ev_del(evbase, iob->revent);
+ /* Enable writer now that there is new data in the buffer. */
if (iob->wevent != NULL) {
if (sudo_ev_add(evbase, iob->wevent, NULL, false) == -1)
sudo_fatal("%s", U_("unable to add event to queue"));
}
- /* Re-enable reader if buffer is not full. */
- if (iob->len != sizeof(iob->buf)) {
- if (sudo_ev_add(evbase, iob->revent, NULL, false) == -1)
- sudo_fatal("%s", U_("unable to add event to queue"));
- }
break;
}
@@ -789,9 +785,7 @@ write_callback(int fd, int what, void *v)
}
FALLTHROUGH;
case EAGAIN:
- /* Not an error, re-enable writer. */
- if (sudo_ev_add(evbase, iob->wevent, NULL, false) == -1)
- sudo_fatal("%s", U_("unable to add event to queue"));
+ /* Not an error, retry later. */
break;
default:
/* XXX - need a way to distinguish non-exec error. */
@@ -806,20 +800,16 @@ write_callback(int fd, int what, void *v)
sudo_debug_printf(SUDO_DEBUG_INFO,
"wrote %zd bytes to fd %d", n, fd);
iob->off += n;
- /* Reset buffer if fully consumed. */
+ /* Disable writer and reset the buffer if fully consumed. */
if (iob->off == iob->len) {
iob->off = iob->len = 0;
+ sudo_ev_del(evbase, iob->wevent);
/* Forward the EOF from reader to writer. */
if (iob->revent == NULL) {
safe_close(fd);
ev_free_by_fd(evbase, fd);
}
}
- /* Re-enable writer if buffer is not empty. */
- if (iob->len > iob->off) {
- if (sudo_ev_add(evbase, iob->wevent, NULL, false) == -1)
- sudo_fatal("%s", U_("unable to add event to queue"));
- }
/* Enable reader if buffer is not full. */
if (iob->revent != NULL &&
(ttymode == TERM_RAW || !USERTTY_EVENT(iob->revent))) {
@@ -854,8 +844,10 @@ io_buf_new(int rfd, int wfd,
if ((iob = malloc(sizeof(*iob))) == NULL)
sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
iob->ec = ec;
- iob->revent = sudo_ev_alloc(rfd, SUDO_EV_READ, read_callback, iob);
- iob->wevent = sudo_ev_alloc(wfd, SUDO_EV_WRITE, write_callback, iob);
+ iob->revent = sudo_ev_alloc(rfd, SUDO_EV_READ|SUDO_EV_PERSIST,
+ read_callback, iob);
+ iob->wevent = sudo_ev_alloc(wfd, SUDO_EV_WRITE|SUDO_EV_PERSIST,
+ write_callback, iob);
iob->len = 0;
iob->off = 0;
iob->action = action;