From f06471cb31f58de928f541287ee4a2154ae79a09 Mon Sep 17 00:00:00 2001 From: ~locpyl-tidnyd Date: Thu, 1 Apr 2021 13:18:38 +0000 Subject: [PATCH] vere: pipe serf stderr back to lord When uv_spawn creates a process and any standard fds are set to UV_INHERIT_FD, it ignores UV_PROCESS_WINDOWS_HIDE flags, and worker console pops up in -d mode. --- pkg/urbit/include/vere/vere.h | 1 + pkg/urbit/vere/lord.c | 47 +++++++++++++++++++++++++++++++++-- pkg/urbit/worker/main.c | 5 ++++ 3 files changed, 51 insertions(+), 2 deletions(-) diff --git a/pkg/urbit/include/vere/vere.h b/pkg/urbit/include/vere/vere.h index f17fd12ad..2bc7d26c1 100644 --- a/pkg/urbit/include/vere/vere.h +++ b/pkg/urbit/include/vere/vere.h @@ -461,6 +461,7 @@ time_t wen_t; // process creation time u3_mojo inn_u; // client's stdin u3_moat out_u; // client's stdout + uv_pipe_t err_u; // client's stderr c3_w wag_w; // config flags c3_c* bin_c; // binary path c3_c* pax_c; // directory diff --git a/pkg/urbit/vere/lord.c b/pkg/urbit/vere/lord.c index 20fa660e5..6a81de2ab 100644 --- a/pkg/urbit/vere/lord.c +++ b/pkg/urbit/vere/lord.c @@ -157,6 +157,8 @@ _lord_stop(u3_lord* god_u) u3_newt_moat_stop(&god_u->out_u, _lord_stop_cb); u3_newt_mojo_stop(&god_u->inn_u, _lord_bail_noop); + uv_read_stop((uv_stream_t*)&(god_u->err_u)); + uv_close((uv_handle_t*)&god_u->cub_u, 0); #if defined(LORD_TRACE_JAM) || defined(LORD_TRACE_CUE) @@ -1044,6 +1046,42 @@ u3_lord_halt(u3_lord* god_u) _lord_stop(god_u); } +/* _lord_serf_err_alloc(): libuv buffer allocator. +*/ +static void +_lord_serf_err_alloc(uv_handle_t* had_u, size_t len_i, uv_buf_t* buf) +{ + // error/info messages as a rule don't exceed one line + // + *buf = uv_buf_init(c3_malloc(80), 80); +} + +/* _lord_on_serf_err_cb(): subprocess stderr callback. +*/ +static void +_lord_on_serf_err_cb(uv_stream_t* pyp_u, + ssize_t siz_i, + const uv_buf_t* buf_u) +{ + if ( siz_i >= 0 ) { + // serf used to write to 2 directly + // this can't be any worse than that + // + u3_write_fd(2, buf_u->base, siz_i); + } else { + uv_read_stop(pyp_u); + + if ( siz_i != UV_EOF ) { + u3l_log("lord: serf stderr: %s\r\n", uv_strerror(siz_i)); + } + } + + if ( buf_u->base != NULL ) { + c3_free(buf_u->base); + } +} + + /* _lord_on_serf_exit(): handle subprocess exit. */ static void @@ -1156,6 +1194,7 @@ u3_lord_init(c3_c* pax_c, c3_w wag_w, c3_d key_d[4], u3_lord_cb cb_u) uv_pipe_init(u3L, &god_u->inn_u.pyp_u, 0); uv_timer_init(u3L, &god_u->out_u.tim_u); uv_pipe_init(u3L, &god_u->out_u.pyp_u, 0); + uv_pipe_init(u3L, &god_u->err_u, 0); god_u->cod_u[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE; god_u->cod_u[0].data.stream = (uv_stream_t *)&god_u->inn_u; @@ -1163,12 +1202,14 @@ u3_lord_init(c3_c* pax_c, c3_w wag_w, c3_d key_d[4], u3_lord_cb cb_u) god_u->cod_u[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; god_u->cod_u[1].data.stream = (uv_stream_t *)&god_u->out_u; - god_u->cod_u[2].flags = UV_INHERIT_FD; - god_u->cod_u[2].data.fd = 2; + god_u->cod_u[2].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; + god_u->cod_u[2].data.stream = (uv_stream_t *)&god_u->err_u; god_u->ops_u.stdio = god_u->cod_u; god_u->ops_u.stdio_count = 3; + // if any fds are inherited, libuv ignores UV_PROCESS_WINDOWS_HIDE* + god_u->ops_u.flags = UV_PROCESS_WINDOWS_HIDE; god_u->ops_u.exit_cb = _lord_on_serf_exit; god_u->ops_u.file = arg_c[0]; god_u->ops_u.args = arg_c; @@ -1178,6 +1219,8 @@ u3_lord_init(c3_c* pax_c, c3_w wag_w, c3_d key_d[4], u3_lord_cb cb_u) return 0; } + + uv_read_start((uv_stream_t *)&god_u->err_u, _lord_serf_err_alloc, _lord_on_serf_err_cb); } #if defined(LORD_TRACE_JAM) || defined(LORD_TRACE_CUE) diff --git a/pkg/urbit/worker/main.c b/pkg/urbit/worker/main.c index 46895f093..9c37fd5d3 100644 --- a/pkg/urbit/worker/main.c +++ b/pkg/urbit/worker/main.c @@ -155,6 +155,11 @@ _cw_serf_stdio(c3_i* inn_i, c3_i* out_i) dup2(2, 1); close(nul_i); + + // set stream I/O to unbuffered because it's now a pipe not a console + // + setvbuf(stdout, NULL, _IONBF, 0); + setvbuf(stderr, NULL, _IONBF, 0); } /* _cw_serf_stdio(): cleanup on serf exit.