diff options
author | wm4 <wm4@nowhere> | 2020-08-16 02:54:44 +0200 |
---|---|---|
committer | wm4 <wm4@nowhere> | 2020-08-16 02:54:44 +0200 |
commit | e27c523a10708b7265c33a4bae631663df4bb297 (patch) | |
tree | 34bdcd1bc48a5311ec24181dec913768180ad851 /osdep | |
parent | d6bf3880d74459103a39426275837ec0a1d48e54 (diff) | |
download | mpv-e27c523a10708b7265c33a4bae631663df4bb297.tar.bz2 mpv-e27c523a10708b7265c33a4bae631663df4bb297.tar.xz |
command: extend subprocess command stdin, change behavior
Make it possible to feed a string to stdin of a subprocess. Out of
laziness, it can't be an arbitrary byte string. (Would require adding an
option type that takes in a Lua byte string.)
Do not set stdin of a subprocess to fd 0 (i.e. mpv's stdin) anymore,
because it makes things more consistent. Enabling stdin didn't make too
much sense in the first place, so this behavior change seems
justifiable.
win32 support missing.
Fixes: #8003
Diffstat (limited to 'osdep')
-rw-r--r-- | osdep/subprocess-posix.c | 41 | ||||
-rw-r--r-- | osdep/subprocess.h | 12 |
2 files changed, 49 insertions, 4 deletions
diff --git a/osdep/subprocess-posix.c b/osdep/subprocess-posix.c index e7af4663ea..bae0ca2c78 100644 --- a/osdep/subprocess-posix.c +++ b/osdep/subprocess-posix.c @@ -165,8 +165,21 @@ void mp_subprocess2(struct mp_subprocess_opts *opts, } for (int n = 0; n < opts->num_fds; n++) { + assert(!(opts->fds[n].on_read && opts->fds[n].on_write)); + if (opts->fds[n].on_read && mp_make_cloexec_pipe(comm_pipe[n]) < 0) goto done; + + if (opts->fds[n].on_write || opts->fds[n].write_buf) { + assert(opts->fds[n].on_write && opts->fds[n].write_buf); + if (mp_make_cloexec_pipe(comm_pipe[n]) < 0) + goto done; + MPSWAP(int, comm_pipe[n][0], comm_pipe[n][1]); + + struct sigaction sa = {.sa_handler = SIG_IGN, .sa_flags = SA_RESTART}; + sigfillset(&sa.sa_mask); + sigaction(SIGPIPE, &sa, NULL); + } } devnull = open("/dev/null", O_RDONLY | O_CLOEXEC); @@ -225,7 +238,7 @@ void mp_subprocess2(struct mp_subprocess_opts *opts, if (comm_pipe[n][0] >= 0) { map_fds[num_fds] = n; fds[num_fds++] = (struct pollfd){ - .events = POLLIN, + .events = opts->fds[n].on_read ? POLLIN : POLLOUT, .fd = comm_pipe[n][0], }; } @@ -249,15 +262,35 @@ void mp_subprocess2(struct mp_subprocess_opts *opts, kill(pid, SIGKILL); killed_by_us = true; break; - } else { + } + struct mp_subprocess_fd *fd = &opts->fds[n]; + if (fd->on_read) { char buf[4096]; ssize_t r = read(comm_pipe[n][0], buf, sizeof(buf)); if (r < 0 && errno == EINTR) continue; - if (r > 0 && opts->fds[n].on_read) - opts->fds[n].on_read(opts->fds[n].on_read_ctx, buf, r); + fd->on_read(fd->on_read_ctx, buf, MPMAX(r, 0)); if (r <= 0) SAFE_CLOSE(comm_pipe[n][0]); + } else if (fd->on_write) { + if (!fd->write_buf->len) { + fd->on_write(fd->on_write_ctx); + if (!fd->write_buf->len) { + SAFE_CLOSE(comm_pipe[n][0]); + continue; + } + } + ssize_t r = write(comm_pipe[n][0], fd->write_buf->start, + fd->write_buf->len); + if (r < 0 && errno == EINTR) + continue; + if (r < 0) { + // Let's not signal an error for now - caller can check + // whether all buffer was written. + SAFE_CLOSE(comm_pipe[n][0]); + continue; + } + *fd->write_buf = bstr_cut(*fd->write_buf, r); } } } diff --git a/osdep/subprocess.h b/osdep/subprocess.h index 14d4896c58..4bf2dc32dd 100644 --- a/osdep/subprocess.h +++ b/osdep/subprocess.h @@ -22,9 +22,18 @@ #include <stddef.h> #include <stdint.h> +#include "misc/bstr.h" + struct mp_cancel; +// Incrementally called with data that was read. Buffer valid only during call. +// size==0 means EOF. typedef void (*subprocess_read_cb)(void *ctx, char *data, size_t size); +// Incrementally called to refill *mp_subprocess_fd.write_buf, whenever write_buf +// has length 0 and the pipe is writable. While writing, *write_buf is adjusted +// to contain only the not yet written data. +// Not filling the buffer means EOF. +typedef void (*subprocess_write_cb)(void *ctx); void mp_devnull(void *ctx, char *data, size_t size); @@ -37,6 +46,9 @@ struct mp_subprocess_fd { // Note: "neutral" initialization requires setting src_fd=-1. subprocess_read_cb on_read; // if not NULL, serve reads void *on_read_ctx; // for on_read(on_read_ctx, ...) + subprocess_write_cb on_write; // if not NULL, serve writes + void *on_write_ctx; // for on_write(on_write_ctx, ...) + bstr *write_buf; // must be !=NULL if on_write is set int src_fd; // if >=0, dup this FD to target FD }; |