summaryrefslogtreecommitdiffstats
path: root/player
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2014-10-26 01:39:01 +0200
committerwm4 <wm4@nowhere>2014-10-26 01:40:36 +0200
commitd0643fa02d1608b096315cf7243b9188d6211699 (patch)
tree5d38c7f20541d953b4d20f5d611021470ea01e7c /player
parent6f88bc77617dbf8a919830ae070e5ca926755587 (diff)
downloadmpv-d0643fa02d1608b096315cf7243b9188d6211699.tar.bz2
mpv-d0643fa02d1608b096315cf7243b9188d6211699.tar.xz
lua: subprocess: tunnel stderr through mp_log
Pretty much a fringe-feature, but also it's awkward if something appears on the terminal with no indication for the source. This is made quite awkward by the fact that stderr and stdout could be closed at different times, and that poll() doesn't accept "holes" in its FD list. Invalid (.e.g negative) FDs just make it return immediately, as required by the standard. So sparse_poll() takes care of the messy details.
Diffstat (limited to 'player')
-rw-r--r--player/lua.c83
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;