Hello community, here is the log from the commit of package conmon for openSUSE:Factory checked in at 2020-03-25 23:44:47 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/conmon (Old) and /work/SRC/openSUSE:Factory/.conmon.new.3160 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "conmon" Wed Mar 25 23:44:47 2020 rev:11 rq:788098 version:2.0.14 Changes: -------- --- /work/SRC/openSUSE:Factory/conmon/conmon.changes 2020-03-19 19:49:09.056144337 +0100 +++ /work/SRC/openSUSE:Factory/.conmon.new.3160/conmon.changes 2020-03-25 23:45:55.504045192 +0100 @@ -1,0 +2,9 @@ +Wed Mar 25 08:55:06 UTC 2020 - Sascha Grunert <[email protected]> + +- Update to v2.0.14 + - drop usage of splice(2) + - avoid hanging on stdin + - stdio: sometimes quit main loop after io is done + - ignore sigpipe + +------------------------------------------------------------------- Old: ---- conmon-2.0.12.tar.xz New: ---- conmon-2.0.14.tar.xz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ conmon.spec ++++++ --- /var/tmp/diff_new_pack.Cn9jgI/_old 2020-03-25 23:45:57.508045848 +0100 +++ /var/tmp/diff_new_pack.Cn9jgI/_new 2020-03-25 23:45:57.532045855 +0100 @@ -17,7 +17,7 @@ Name: conmon -Version: 2.0.12 +Version: 2.0.14 Release: 0 Summary: An OCI container runtime monitor License: Apache-2.0 ++++++ _service ++++++ --- /var/tmp/diff_new_pack.Cn9jgI/_old 2020-03-25 23:45:57.608045880 +0100 +++ /var/tmp/diff_new_pack.Cn9jgI/_new 2020-03-25 23:45:57.608045880 +0100 @@ -2,8 +2,8 @@ <service name="tar_scm" mode="disabled"> <param name="url">https://github.com/containers/conmon</param> <param name="scm">git</param> -<param name="versionformat">2.0.12</param> -<param name="revision">v2.0.12</param> +<param name="versionformat">2.0.14</param> +<param name="revision">v2.0.14</param> </service> <service name="recompress" mode="disabled"> <param name="file">conmon-*.tar</param> ++++++ conmon-2.0.12.tar.xz -> conmon-2.0.14.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/conmon-2.0.12/.dir-locals.el new/conmon-2.0.14/.dir-locals.el --- old/conmon-2.0.12/.dir-locals.el 1970-01-01 01:00:00.000000000 +0100 +++ new/conmon-2.0.14/.dir-locals.el 2020-03-20 16:44:25.000000000 +0100 @@ -0,0 +1,3 @@ +((c-mode . ((fill-column . 109) + (c-basic-offset . 8) + (indent-tabs-mode t)))) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/conmon-2.0.12/VERSION new/conmon-2.0.14/VERSION --- old/conmon-2.0.12/VERSION 2020-03-16 17:55:00.000000000 +0100 +++ new/conmon-2.0.14/VERSION 2020-03-20 16:44:25.000000000 +0100 @@ -1 +1 @@ -2.0.12 +2.0.14 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/conmon-2.0.12/src/conmon.c new/conmon-2.0.14/src/conmon.c --- old/conmon-2.0.12/src/conmon.c 2020-03-16 17:55:00.000000000 +0100 +++ new/conmon-2.0.14/src/conmon.c 2020-03-20 16:44:25.000000000 +0100 @@ -284,8 +284,12 @@ /* Used for attach */ struct conn_sock_s { int fd; + gboolean data_ready; gboolean readable; gboolean writable; + size_t remaining; + size_t off; + char buf[CONN_SOCK_BUF_SIZE]; }; GPtrArray *conn_socks = NULL; @@ -489,12 +493,28 @@ return G_SOURCE_REMOVE; } + /* End of input */ if (read_eof || (has_hup && !has_input)) { - /* End of input */ - if (pipe == STDOUT_PIPE) + /* There exists a case that the process has already exited + * and we know about it (because we checked our child processes) + * but we needed to run the main_loop to catch all the rest of the output + * (specifically, when we are exec, but not terminal) + * In this case, after both the stderr and stdout pipes have closed + * we should quit the loop. Otherwise, conmon will hang forever + * waiting for container_exit_cb that will never be called. + */ + if (pipe == STDOUT_PIPE) { masterfd_stdout = -1; - if (pipe == STDERR_PIPE) + if (container_status >= 0 && masterfd_stderr < 0) { + g_main_loop_quit(main_loop); + } + } + if (pipe == STDERR_PIPE) { masterfd_stderr = -1; + if (container_status >= 0 && masterfd_stdout < 0) { + g_main_loop_quit(main_loop); + } + } close(fd); return G_SOURCE_REMOVE; @@ -667,39 +687,8 @@ return ret; } -static gboolean conn_sock_cb(int fd, GIOCondition condition, gpointer user_data) +static gboolean terminate_conn_sock(struct conn_sock_s *sock) { - struct conn_sock_s *sock = (struct conn_sock_s *)user_data; - ssize_t num_read = 0; - - if ((condition & G_IO_IN) != 0) { - num_read = splice(fd, NULL, masterfd_stdin, NULL, 1 << 20, 0); - if (num_read > 0) - return G_SOURCE_CONTINUE; - - if (num_read < 0) { - if (errno != ESPIPE && errno != EINVAL) { - nwarn("Failed to write to container stdin"); - } else { - /* Fallback to read-write. This may lock if the consumer - doesn't read all the data. */ - char buf[CONN_SOCK_BUF_SIZE]; - - num_read = read(fd, buf, CONN_SOCK_BUF_SIZE); - if (num_read < 0) - return G_SOURCE_CONTINUE; - - if (num_read > 0 && masterfd_stdin >= 0) { - if (write_all(masterfd_stdin, buf, num_read) < 0) { - nwarn("Failed to write to container stdin"); - } - return G_SOURCE_CONTINUE; - } - } - } - } - - /* End of input */ conn_sock_shutdown(sock, SHUT_RD); if (masterfd_stdin >= 0 && opt_stdin) { if (!opt_leave_stdin_open) { @@ -712,6 +701,90 @@ return G_SOURCE_REMOVE; } +static gboolean conn_sock_cb(G_GNUC_UNUSED int fd, GIOCondition condition, gpointer user_data); + +static void sock_try_write_to_masterfd_stdin(struct conn_sock_s *sock) +{ + if (!sock->remaining) + return; + + ssize_t w = write(masterfd_stdin, sock->buf + sock->off, sock->remaining); + if (w < 0) { + nwarn("Failed to write to container stdin"); + } else { + sock->off += w; + sock->remaining -= w; + } +} + +static void write_to_masterfd_stdin(gpointer data, gpointer user_data) +{ + struct conn_sock_s *sock = (struct conn_sock_s *)data; + bool *has_data = user_data; + + sock_try_write_to_masterfd_stdin(sock); + + if (sock->remaining) + *has_data = true; + else if (sock->data_ready) { + sock->data_ready = false; + g_unix_fd_add(sock->fd, G_IO_IN | G_IO_HUP | G_IO_ERR, conn_sock_cb, sock); + } +} + +static gboolean masterfd_write_cb(G_GNUC_UNUSED int fd, G_GNUC_UNUSED GIOCondition condition, G_GNUC_UNUSED gpointer user_data) +{ + bool has_data = FALSE; + + if (masterfd_stdin < 0) + return G_SOURCE_REMOVE; + + g_ptr_array_foreach(conn_socks, write_to_masterfd_stdin, &has_data); + if (has_data) + return G_SOURCE_CONTINUE; + return G_SOURCE_REMOVE; +} + +static gboolean read_conn_sock(struct conn_sock_s *sock) +{ + ssize_t num_read; + + /* There is still data in the buffer. */ + if (sock->remaining) { + sock->data_ready = true; + return G_SOURCE_REMOVE; + } + + num_read = read(sock->fd, sock->buf, CONN_SOCK_BUF_SIZE); + if (num_read < 0) + return G_SOURCE_CONTINUE; + + if (num_read == 0) + return terminate_conn_sock(sock); + + /* num_read > 0 */ + sock->remaining = num_read; + sock->off = 0; + + sock_try_write_to_masterfd_stdin(sock); + + /* Not everything was written to stdin, let's wait for the fd to be ready. */ + if (sock->remaining) + g_unix_fd_add(masterfd_stdin, G_IO_OUT, masterfd_write_cb, NULL); + + return G_SOURCE_CONTINUE; +} + +static gboolean conn_sock_cb(G_GNUC_UNUSED int fd, GIOCondition condition, gpointer user_data) +{ + struct conn_sock_s *sock = (struct conn_sock_s *)user_data; + + if (condition & G_IO_IN) + return read_conn_sock(sock); + + return terminate_conn_sock(sock); +} + static gboolean attach_cb(int fd, G_GNUC_UNUSED GIOCondition condition, G_GNUC_UNUSED gpointer user_data) { int conn_fd = accept(fd, NULL, NULL); @@ -730,6 +803,9 @@ conn_sock->fd = conn_fd; conn_sock->readable = true; conn_sock->writable = true; + conn_sock->off = 0; + conn_sock->remaining = 0; + conn_sock->data_ready = false; g_unix_fd_add(conn_sock->fd, G_IO_IN | G_IO_HUP | G_IO_ERR, conn_sock_cb, conn_sock); g_ptr_array_add(conn_socks, conn_sock); ninfof("Accepted connection %d", conn_sock->fd); @@ -1329,6 +1405,8 @@ close(oom_score_fd); } + /* ignoring SIGPIPE prevents conmon from being spuriously killed */ + signal(SIGPIPE, SIG_IGN); main_loop = g_main_loop_new(NULL, FALSE); @@ -1460,6 +1538,9 @@ masterfd_stdin = fds[1]; slavefd_stdin = fds[0]; + + if (g_unix_set_fd_nonblocking(masterfd_stdin, TRUE, NULL) == FALSE) + nwarn("Failed to set masterfd_stdin to non blocking"); } if (pipe2(fds, O_CLOEXEC) < 0) @@ -1772,6 +1853,9 @@ specifically, the check child processes call above could set the container status if it is a quickly exiting command. We only want to run the loop if this hasn't happened yet. + Note: there exists a chance that we have the container_status, are exec, and api>=1, + but are not terminal. In this case, we still want to run to process all of the output, + but will need to exit once all the i/o is read. This will be handled in stdio_cb above. */ if (opt_api_version < 1 || !opt_exec || !opt_terminal || container_status < 0) g_main_loop_run(main_loop);
