From 1a6825758cdef038cc17f0fbc70a247c7e4e21be Mon Sep 17 00:00:00 2001 From: Mrunal Patel Date: Tue, 30 May 2017 15:14:44 -0700 Subject: [PATCH] conmon: Add control fifo for terminal resize handling Signed-off-by: Mrunal Patel --- conmon/conmon.c | 101 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/conmon/conmon.c b/conmon/conmon.c index 3e814c81..f766f609 100644 --- a/conmon/conmon.c +++ b/conmon/conmon.c @@ -12,10 +12,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include @@ -439,6 +441,7 @@ int main(int argc, char *argv[]) char cwd[PATH_MAX]; char default_pid_file[PATH_MAX]; char attach_sock_path[PATH_MAX]; + char ctl_fifo_path[PATH_MAX]; GError *err = NULL; _cleanup_free_ char *contents; int cpid = -1; @@ -798,6 +801,40 @@ int main(int argc, char *argv[]) pexit("Failed to listen on attach socket: %s", attach_sock_path); } + /* Setup fifo for reading in terminal resize and other stdio control messages */ + _cleanup_close_ int ctlfd = -1; + _cleanup_close_ int dummyfd = -1; + int ctl_msg_type = -1; + int height = -1; + int width = -1; + struct winsize ws; + #define CTLBUFSZ 200 + char ctlbuf[CTLBUFSZ]; + char *readptr = ctlbuf; + int readsz = CTLBUFSZ - 1; + int cp_rem = 0; + if (!exec) { + snprintf(ctl_fifo_path, PATH_MAX, "%s/ctl", bundle_path); + ninfo("ctl fifo path: %s", ctl_fifo_path); + + if (mkfifo(ctl_fifo_path, 0666) == -1) + pexit("Failed to mkfifo at %s", ctl_fifo_path); + + ctlfd = open(ctl_fifo_path, O_RDONLY|O_NONBLOCK|O_CLOEXEC); + if (ctlfd == -1) + pexit("Failed to open control fifo"); + + /* + * Open a dummy writer to prevent getting flood of POLLHUPs when + * last writer closes. + */ + dummyfd = open(ctl_fifo_path, O_WRONLY|O_CLOEXEC); + if (dummyfd == -1) + pexit("Failed to open dummy writer for fifo"); + + ninfo("ctlfd: %d", ctlfd); + } + /* Send the container pid back to parent */ if (sync_pipe_fd > 0 && !exec) { len = snprintf(buf, BUF_SIZE, "{\"pid\": %d}\n", cpid); @@ -870,6 +907,13 @@ int main(int argc, char *argv[]) pexit("Failed to add attach socket fd to epoll"); } + /* Add control fifo fd to epoll */ + if (ctlfd > 0) { + ev.data.fd = ctlfd; + if (epoll_ctl(epfd, EPOLL_CTL_ADD, ev.data.fd, &ev) < 0) + pexit("Failed to add control fifo fd to epoll"); + } + /* Log all of the container's output. */ while (num_stdio_fds > 0) { int ready = epoll_wait(epfd, evlist, MAX_EVENTS, -1); @@ -903,6 +947,59 @@ int main(int argc, char *argv[]) pexit("Failed to add client socket fd to epoll"); } ninfo("Accepted connection"); + } else if (!exec && evlist[i].data.fd == ctlfd) { + num_read = read(ctlfd, readptr, readsz); + if (num_read <= 0) { + nwarn("Failed to read from control fd"); + continue; + } + readptr[num_read] = '\0'; + ninfo("Got ctl message: %s\n", ctlbuf); + + char *beg = ctlbuf; + char *newline = strchrnul(beg, '\n'); + /* Process each message which ends with a line */ + while (*newline != '\0') { + ret = sscanf(ctlbuf, "%d %d %d\n", &ctl_msg_type, &height, &width); + if (ret != 3) { + nwarn("Failed to sscanf message"); + continue; + } + ninfo("Message type: %d, Height: %d, Width: %d", ctl_msg_type, height, width); + ret = ioctl(masterfd_stdout, TIOCGWINSZ, &ws); + ninfo("Existing size: %d %d", ws.ws_row, ws.ws_col); + ws.ws_row = height; + ws.ws_col = width; + ret = ioctl(masterfd_stdout, TIOCSWINSZ, &ws); + if (ret == -1) { + nwarn("Failed to set process pty terminal size"); + } + beg = newline + 1; + newline = strchrnul(beg, '\n'); + } + if (num_read == (CTLBUFSZ - 1) && beg == ctlbuf) { + /* + * We did not find a newline in the entire buffer. + * This shouldn't happen as our buffer is larger than + * the message that we expect to receive. + */ + nwarn("Could not find newline in entire buffer\n"); + } else if (*beg == '\0') { + /* We exhausted all messages that were complete */ + readptr = ctlbuf; + readsz = CTLBUFSZ - 1; + } else { + /* + * We copy remaining data to beginning of buffer + * and advance readptr after that. + */ + cp_rem = 0; + do { + ctlbuf[cp_rem++] = *beg++; + } while (*beg != '\0'); + readptr = ctlbuf + cp_rem; + readsz = CTLBUFSZ - 1 - cp_rem; + } } else { num_read = read(masterfd, buf, BUF_SIZE); if (num_read <= 0) @@ -932,6 +1029,10 @@ int main(int argc, char *argv[]) } } } else if (evlist[i].events & (EPOLLHUP | EPOLLERR)) { + if (!exec && evlist[i].data.fd == ctlfd) { + ninfo("Remote writer to control fd closed"); + continue; + } printf("closing fd %d\n", evlist[i].data.fd); if (close(evlist[i].data.fd) < 0) pexit("close");