summaryrefslogtreecommitdiff
path: root/src/common/util.c
diff options
context:
space:
mode:
authorYawning Angel <yawning@schwanenlied.me>2015-03-26 12:55:12 +0000
committerYawning Angel <yawning@schwanenlied.me>2015-03-26 12:55:12 +0000
commitfda61e030e12cbd66a2be9905e6855ec6c6a3c63 (patch)
treeb0b7f8188707e73e788b33181c796c73106998d3 /src/common/util.c
parent732322b710d515a55ebbaa984fa12f19ccb333e8 (diff)
downloadtor-fda61e030e12cbd66a2be9905e6855ec6c6a3c63.tar.gz
tor-fda61e030e12cbd66a2be9905e6855ec6c6a3c63.zip
Implement "TOR_PT_EXIT_ON_STDIN_CLOSE".
Background processes spawned by Tor now will have a valid stdin. Pluggable transports can detect this behavior with the aformentioned enviornment variable, and exit if stdin ever gets closed.
Diffstat (limited to 'src/common/util.c')
-rw-r--r--src/common/util.c81
1 files changed, 67 insertions, 14 deletions
diff --git a/src/common/util.c b/src/common/util.c
index 2c3a1a1019..7096e24bcc 100644
--- a/src/common/util.c
+++ b/src/common/util.c
@@ -3939,9 +3939,11 @@ process_handle_new(void)
process_handle_t *out = tor_malloc_zero(sizeof(process_handle_t));
#ifdef _WIN32
+ out->stdin_pipe = INVALID_HANDLE_VALUE;
out->stdout_pipe = INVALID_HANDLE_VALUE;
out->stderr_pipe = INVALID_HANDLE_VALUE;
#else
+ out->stdin_pipe = -1;
out->stdout_pipe = -1;
out->stderr_pipe = -1;
#endif
@@ -3981,7 +3983,7 @@ process_handle_waitpid_cb(int status, void *arg)
#define CHILD_STATE_FORK 3
#define CHILD_STATE_DUPOUT 4
#define CHILD_STATE_DUPERR 5
-#define CHILD_STATE_REDIRECT 6
+#define CHILD_STATE_DUPIN 6
#define CHILD_STATE_CLOSEFD 7
#define CHILD_STATE_EXEC 8
#define CHILD_STATE_FAILEXEC 9
@@ -4015,6 +4017,8 @@ tor_spawn_background(const char *const filename, const char **argv,
HANDLE stdout_pipe_write = NULL;
HANDLE stderr_pipe_read = NULL;
HANDLE stderr_pipe_write = NULL;
+ HANDLE stdin_pipe_read = NULL;
+ HANDLE stdin_pipe_write = NULL;
process_handle_t *process_handle;
int status;
@@ -4060,6 +4064,20 @@ tor_spawn_background(const char *const filename, const char **argv,
return status;
}
+ /* Set up pipe for stdin */
+ if (!CreatePipe(&stdin_pipe_read, &stdin_pipe_write, &saAttr, 0)) {
+ log_warn(LD_GENERAL,
+ "Failed to create pipe for stdin communication with child process: %s",
+ format_win32_error(GetLastError()));
+ return status;
+ }
+ if (!SetHandleInformation(stderr_pipe_write, HANDLE_FLAG_INHERIT, 0)) {
+ log_warn(LD_GENERAL,
+ "Failed to configure pipe for stdin communication with child "
+ "process: %s", format_win32_error(GetLastError()));
+ return status;
+ }
+
/* Create the child process */
/* Windows expects argv to be a whitespace delimited string, so join argv up
@@ -4074,7 +4092,7 @@ tor_spawn_background(const char *const filename, const char **argv,
siStartInfo.cb = sizeof(STARTUPINFO);
siStartInfo.hStdError = stderr_pipe_write;
siStartInfo.hStdOutput = stdout_pipe_write;
- siStartInfo.hStdInput = NULL;
+ siStartInfo.hStdInput = stdin_pipe_read;
siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
/* Create the child process */
@@ -4104,6 +4122,7 @@ tor_spawn_background(const char *const filename, const char **argv,
/* TODO: Close hProcess and hThread in process_handle->pid? */
process_handle->stdout_pipe = stdout_pipe_read;
process_handle->stderr_pipe = stderr_pipe_read;
+ process_handle->stdin_pipe = stdin_pipe_write;
status = process_handle->status = PROCESS_STATUS_RUNNING;
}
@@ -4114,6 +4133,7 @@ tor_spawn_background(const char *const filename, const char **argv,
pid_t pid;
int stdout_pipe[2];
int stderr_pipe[2];
+ int stdin_pipe[2];
int fd, retval;
ssize_t nbytes;
process_handle_t *process_handle;
@@ -4138,7 +4158,7 @@ tor_spawn_background(const char *const filename, const char **argv,
child_state = CHILD_STATE_PIPE;
- /* Set up pipe for redirecting stdout and stderr of child */
+ /* Set up pipe for redirecting stdout, stderr, and stdin of child */
retval = pipe(stdout_pipe);
if (-1 == retval) {
log_warn(LD_GENERAL,
@@ -4159,6 +4179,20 @@ tor_spawn_background(const char *const filename, const char **argv,
return status;
}
+ retval = pipe(stdin_pipe);
+ if (-1 == retval) {
+ log_warn(LD_GENERAL,
+ "Failed to set up pipe for stdin communication with child process: %s",
+ strerror(errno));
+
+ close(stdout_pipe[0]);
+ close(stdout_pipe[1]);
+ close(stderr_pipe[0]);
+ close(stderr_pipe[1]);
+
+ return status;
+ }
+
child_state = CHILD_STATE_MAXFD;
#ifdef _SC_OPEN_MAX
@@ -4194,13 +4228,11 @@ tor_spawn_background(const char *const filename, const char **argv,
if (-1 == retval)
goto error;
- child_state = CHILD_STATE_REDIRECT;
+ child_state = CHILD_STATE_DUPIN;
- /* Link stdin to /dev/null */
- fd = open("/dev/null", O_RDONLY); /* NOT cloexec, obviously. */
- if (fd != -1)
- dup2(fd, STDIN_FILENO);
- else
+ /* Link child stdin to the read end of the pipe */
+ retval = dup2(stdin_pipe[0], STDIN_FILENO);
+ if (-1 == retval)
goto error;
child_state = CHILD_STATE_CLOSEFD;
@@ -4209,7 +4241,8 @@ tor_spawn_background(const char *const filename, const char **argv,
close(stderr_pipe[1]);
close(stdout_pipe[0]);
close(stdout_pipe[1]);
- close(fd);
+ close(stdin_pipe[0]);
+ close(stdin_pipe[1]);
/* Close all other fds, including the read end of the pipe */
/* XXX: We should now be doing enough FD_CLOEXEC setting to make
@@ -4259,6 +4292,8 @@ tor_spawn_background(const char *const filename, const char **argv,
if (-1 == pid) {
log_warn(LD_GENERAL, "Failed to fork child process: %s", strerror(errno));
+ close(stdin_pipe[0]);
+ close(stdin_pipe[1]);
close(stdout_pipe[0]);
close(stdout_pipe[1]);
close(stderr_pipe[0]);
@@ -4295,16 +4330,28 @@ tor_spawn_background(const char *const filename, const char **argv,
strerror(errno));
}
+ /* Return write end of the stdin pipe to caller, and close the read end */
+ process_handle->stdin_pipe = stdin_pipe[1];
+ retval = close(stdin_pipe[0]);
+
+ if (-1 == retval) {
+ log_warn(LD_GENERAL,
+ "Failed to close read end of stdin pipe in parent process: %s",
+ strerror(errno));
+ }
+
status = process_handle->status = PROCESS_STATUS_RUNNING;
- /* Set stdout/stderr pipes to be non-blocking */
+ /* Set stdin/stdout/stderr pipes to be non-blocking */
if (fcntl(process_handle->stdout_pipe, F_SETFL, O_NONBLOCK) < 0 ||
- fcntl(process_handle->stderr_pipe, F_SETFL, O_NONBLOCK) < 0) {
- log_warn(LD_GENERAL, "Failed to set stderror/stdout pipes nonblocking "
- "in parent process: %s", strerror(errno));
+ fcntl(process_handle->stderr_pipe, F_SETFL, O_NONBLOCK) < 0 ||
+ fcntl(process_handle->stdin_pipe, F_SETFL, O_NONBLOCK) < 0) {
+ log_warn(LD_GENERAL, "Failed to set stderror/stdout/stdin pipes "
+ "nonblocking in parent process: %s", strerror(errno));
}
/* Open the buffered IO streams */
process_handle->stdout_handle = fdopen(process_handle->stdout_pipe, "r");
process_handle->stderr_handle = fdopen(process_handle->stderr_pipe, "r");
+ process_handle->stdin_handle = fdopen(process_handle->stdin_pipe, "r");
*process_handle_out = process_handle;
return process_handle->status;
@@ -4347,6 +4394,9 @@ tor_process_handle_destroy,(process_handle_t *process_handle,
if (process_handle->stderr_pipe)
CloseHandle(process_handle->stderr_pipe);
+
+ if (process_handle->stdin_pipe)
+ CloseHandle(process_handle->stdin_pipe);
#else
if (process_handle->stdout_handle)
fclose(process_handle->stdout_handle);
@@ -4354,6 +4404,9 @@ tor_process_handle_destroy,(process_handle_t *process_handle,
if (process_handle->stderr_handle)
fclose(process_handle->stderr_handle);
+ if (process_handle->stdin_handle)
+ fclose(process_handle->stdin_handle);
+
clear_waitpid_callback(process_handle->waitpid_cb);
#endif