process: close stdio after dup2'ing it
Thus allow passing the same file descriptor as the source of multiple stdios. Committed with the help and code parts from: * Sam Roberts <sam@strongloop.com> fix #1074
This commit is contained in:
parent
8bc29b6f5f
commit
e403a2c486
@ -290,32 +290,41 @@ static void uv__process_child_init(uv_process_options_t options,
|
||||
close_fd = pipes[fd][0];
|
||||
use_fd = pipes[fd][1];
|
||||
|
||||
if (use_fd >= 0)
|
||||
close(close_fd);
|
||||
else if (fd >= 3)
|
||||
continue;
|
||||
else {
|
||||
/* redirect stdin, stdout and stderr to /dev/null even if UV_IGNORE is
|
||||
* set
|
||||
*/
|
||||
use_fd = open("/dev/null", fd == 0 ? O_RDONLY : O_RDWR);
|
||||
if (use_fd < 0) {
|
||||
if (fd >= 3)
|
||||
continue;
|
||||
else {
|
||||
/* redirect stdin, stdout and stderr to /dev/null even if UV_IGNORE is
|
||||
* set
|
||||
*/
|
||||
use_fd = open("/dev/null", fd == 0 ? O_RDONLY : O_RDWR);
|
||||
close_fd = use_fd;
|
||||
|
||||
if (use_fd == -1) {
|
||||
uv__write_int(error_fd, errno);
|
||||
perror("failed to open stdio");
|
||||
_exit(127);
|
||||
if (use_fd == -1) {
|
||||
uv__write_int(error_fd, errno);
|
||||
perror("failed to open stdio");
|
||||
_exit(127);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fd == use_fd)
|
||||
uv__cloexec(use_fd, 0);
|
||||
else {
|
||||
else
|
||||
dup2(use_fd, fd);
|
||||
close(use_fd);
|
||||
}
|
||||
|
||||
if (fd <= 2)
|
||||
uv__nonblock(fd, 0);
|
||||
|
||||
if (close_fd != -1)
|
||||
close(close_fd);
|
||||
}
|
||||
|
||||
for (fd = 0; fd < stdio_count; fd++) {
|
||||
use_fd = pipes[fd][1];
|
||||
|
||||
if (use_fd >= 0 && fd != use_fd)
|
||||
close(use_fd);
|
||||
}
|
||||
|
||||
if (options.cwd && chdir(options.cwd)) {
|
||||
|
||||
@ -160,6 +160,7 @@ TEST_DECLARE (spawn_preserve_env)
|
||||
TEST_DECLARE (spawn_setuid_fails)
|
||||
TEST_DECLARE (spawn_setgid_fails)
|
||||
TEST_DECLARE (spawn_stdout_to_file)
|
||||
TEST_DECLARE (spawn_stdout_and_stderr_to_file)
|
||||
TEST_DECLARE (spawn_auto_unref)
|
||||
TEST_DECLARE (fs_poll)
|
||||
TEST_DECLARE (kill)
|
||||
@ -435,6 +436,7 @@ TASK_LIST_START
|
||||
TEST_ENTRY (spawn_setuid_fails)
|
||||
TEST_ENTRY (spawn_setgid_fails)
|
||||
TEST_ENTRY (spawn_stdout_to_file)
|
||||
TEST_ENTRY (spawn_stdout_and_stderr_to_file)
|
||||
TEST_ENTRY (spawn_auto_unref)
|
||||
TEST_ENTRY (fs_poll)
|
||||
TEST_ENTRY (kill)
|
||||
|
||||
@ -263,6 +263,61 @@ TEST_IMPL(spawn_stdout_to_file) {
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(spawn_stdout_and_stderr_to_file) {
|
||||
int r;
|
||||
uv_file file;
|
||||
uv_fs_t fs_req;
|
||||
uv_stdio_container_t stdio[3];
|
||||
|
||||
/* Setup. */
|
||||
unlink("stdout_file");
|
||||
|
||||
init_process_options("spawn_helper6", exit_cb);
|
||||
|
||||
r = uv_fs_open(uv_default_loop(), &fs_req, "stdout_file", O_CREAT | O_RDWR,
|
||||
S_IREAD | S_IWRITE, NULL);
|
||||
ASSERT(r != -1);
|
||||
uv_fs_req_cleanup(&fs_req);
|
||||
|
||||
file = r;
|
||||
|
||||
options.stdio = stdio;
|
||||
options.stdio[0].flags = UV_IGNORE;
|
||||
options.stdio[1].flags = UV_INHERIT_FD;
|
||||
options.stdio[1].data.fd = file;
|
||||
options.stdio[2].flags = UV_INHERIT_FD;
|
||||
options.stdio[2].data.fd = file;
|
||||
options.stdio_count = 3;
|
||||
|
||||
r = uv_spawn(uv_default_loop(), &process, options);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
ASSERT(r == 0);
|
||||
|
||||
ASSERT(exit_cb_called == 1);
|
||||
ASSERT(close_cb_called == 1);
|
||||
|
||||
r = uv_fs_read(uv_default_loop(), &fs_req, file, output, sizeof(output),
|
||||
0, NULL);
|
||||
ASSERT(r == 27);
|
||||
uv_fs_req_cleanup(&fs_req);
|
||||
|
||||
r = uv_fs_close(uv_default_loop(), &fs_req, file, NULL);
|
||||
ASSERT(r == 0);
|
||||
uv_fs_req_cleanup(&fs_req);
|
||||
|
||||
printf("output is: %s", output);
|
||||
ASSERT(strcmp("hello world\nhello errworld\n", output) == 0);
|
||||
|
||||
/* Cleanup. */
|
||||
unlink("stdout_file");
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(spawn_stdin) {
|
||||
int r;
|
||||
uv_pipe_t out;
|
||||
@ -562,6 +617,53 @@ TEST_IMPL(spawn_and_ping) {
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(spawn_same_stdout_stderr) {
|
||||
uv_write_t write_req;
|
||||
uv_pipe_t in, out;
|
||||
uv_buf_t buf;
|
||||
uv_stdio_container_t stdio[3];
|
||||
int r;
|
||||
|
||||
init_process_options("spawn_helper3", exit_cb);
|
||||
buf = uv_buf_init("TEST", 4);
|
||||
|
||||
uv_pipe_init(uv_default_loop(), &out, 0);
|
||||
uv_pipe_init(uv_default_loop(), &in, 0);
|
||||
options.stdio = stdio;
|
||||
options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE;
|
||||
options.stdio[0].data.stream = (uv_stream_t*)∈
|
||||
options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
|
||||
options.stdio[1].data.stream = (uv_stream_t*)&out;
|
||||
options.stdio_count = 2;
|
||||
|
||||
r = uv_spawn(uv_default_loop(), &process, options);
|
||||
ASSERT(r == 0);
|
||||
|
||||
/* Sending signum == 0 should check if the
|
||||
* child process is still alive, not kill it.
|
||||
*/
|
||||
r = uv_process_kill(&process, 0);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_write(&write_req, (uv_stream_t*)&in, &buf, 1, write_cb);
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_read_start((uv_stream_t*)&out, on_alloc, on_read);
|
||||
ASSERT(r == 0);
|
||||
|
||||
ASSERT(exit_cb_called == 0);
|
||||
|
||||
r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
ASSERT(r == 0);
|
||||
|
||||
ASSERT(exit_cb_called == 1);
|
||||
ASSERT(strcmp(output, "TEST") == 0);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(kill) {
|
||||
int r;
|
||||
uv_err_t err;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user