diff options
Diffstat (limited to 'player')
-rw-r--r-- | player/lua.c | 83 |
1 files changed, 63 insertions, 20 deletions
diff --git a/player/lua.c b/player/lua.c index 260877732e..217e247f3c 100644 --- a/player/lua.c +++ b/player/lua.c @@ -1182,6 +1182,27 @@ static int script_join_path(lua_State *L) extern char **environ; #endif +// A silly helper: automatically skips entries with negative FDs +static int sparse_poll(struct pollfd *fds, int num_fds, int timeout) +{ + struct pollfd p_fds[10]; + int map[10]; + if (num_fds > MP_ARRAY_SIZE(p_fds)) + return -1; + int p_num_fds = 0; + for (int n = 0; n < num_fds; n++) { + map[n] = -1; + if (fds[n].fd < 0) + break; + map[n] = p_num_fds; + p_fds[p_num_fds++] = fds[n]; + } + int r = poll(p_fds, p_num_fds, timeout); + for (int n = 0; n < num_fds; n++) + fds[n].revents = (map[n] < 0 && r >= 0) ? 0 : p_fds[map[n]].revents; + return r; +} + static int script_subprocess(lua_State *L) { struct script_ctx *ctx = get_ctx(L); @@ -1223,19 +1244,22 @@ static int script_subprocess(lua_State *L) bool fa_destroy = false; bstr output = {0}; int status = -1; - int pipes[2] = {-1, -1}; + int p_stdout[2] = {-1, -1}; + int p_stderr[2] = {-1, -1}; pid_t pid = -1; - if (pipe(pipes)) + if (mp_make_cloexec_pipe(p_stdout) < 0) + goto done; + if (mp_make_cloexec_pipe(p_stderr) < 0) goto done; - mp_set_cloexec(pipes[0]); - mp_set_cloexec(pipes[1]); if (posix_spawn_file_actions_init(&fa)) goto done; fa_destroy = true; - // redirect stdout, but not stderr or stdin - if (posix_spawn_file_actions_adddup2(&fa, pipes[1], 1)) + // redirect stdout and stderr + if (posix_spawn_file_actions_adddup2(&fa, p_stdout[1], 1)) + goto done; + if (posix_spawn_file_actions_adddup2(&fa, p_stderr[1], 2)) goto done; if (posix_spawnp(&pid, args[0], &fa, NULL, args, environ)) { @@ -1243,29 +1267,46 @@ static int script_subprocess(lua_State *L) goto done; } - close(pipes[1]); - pipes[1] = -1; + close(p_stdout[1]); + p_stdout[1] = -1; + close(p_stderr[1]); + p_stderr[1] = -1; - while (1) { + while (p_stdout[0] >= 0 || p_stderr[0] >= 0) { struct pollfd fds[] = { - {.events = POLLIN, .fd = pipes[0]}, + {.events = POLLIN, .fd = p_stdout[0]}, + {.events = POLLIN, .fd = p_stderr[0]}, {.events = POLLIN, .fd = cancel ? mp_cancel_get_fd(cancel) : -1}, }; - if (poll(fds, fds[1].fd >= 0 ? 2 : 1, -1) < 0 && errno != EINTR) - break; - if (fds[1].revents) { - kill(pid, SIGKILL); + if (sparse_poll(fds, MP_ARRAY_SIZE(fds), -1) < 0 && errno != EINTR) break; - } if (fds[0].revents) { char buf[4096]; - ssize_t r = read(pipes[0], buf, sizeof(buf)); + ssize_t r = read(p_stdout[0], buf, sizeof(buf)); if (r < 0 && errno == EINTR) continue; if (r > 0) bstr_xappend(tmp, &output, (bstr){buf, r}); - if (r <= 0) - break; + if (r <= 0) { + close(p_stdout[0]); + p_stdout[0] = -1; + } + } + if (fds[1].revents) { + char buf[4096]; + ssize_t r = read(p_stderr[0], buf, sizeof(buf)); + if (r < 0 && errno == EINTR) + continue; + if (r > 0) + MP_INFO(ctx, "%.*s", (int)r, buf); + if (r <= 0) { + close(p_stderr[0]); + p_stderr[0] = -1; + } + } + if (fds[2].revents) { + kill(pid, SIGKILL); + break; } if (output.len >= max_size) break; @@ -1280,8 +1321,10 @@ static int script_subprocess(lua_State *L) done: if (fa_destroy) posix_spawn_file_actions_destroy(&fa); - close(pipes[0]); - close(pipes[1]); + close(p_stdout[0]); + close(p_stdout[1]); + close(p_stderr[0]); + close(p_stderr[1]); // --- Lua errors are ok again from here char *error = NULL; |