aboutsummaryrefslogtreecommitdiff
path: root/src/common
diff options
context:
space:
mode:
Diffstat (limited to 'src/common')
-rw-r--r--src/common/util.c70
-rw-r--r--src/common/util.h2
2 files changed, 42 insertions, 30 deletions
diff --git a/src/common/util.c b/src/common/util.c
index 8b9979cc4..c18458355 100644
--- a/src/common/util.c
+++ b/src/common/util.c
@@ -3034,20 +3034,24 @@ format_helper_exit_status(unsigned char child_state, int saved_errno,
#define SPAWN_ERROR_MESSAGE "ERR: Failed to spawn background process - code "
-/** Start a program in the background. If <b>filename</b> contains a '/',
- * then it will be treated as an absolute or relative path. Otherwise the
- * system path will be searched for <b>filename</b>. The strings in
- * <b>argv</b> will be passed as the command line arguments of the child
- * program (following convention, argv[0] should normally be the filename of
- * the executable). The last element of argv must be NULL. If the child
- * program is launched, the PID will be returned and <b>stdout_read</b> and
- * <b>stdout_err</b> will be set to file descriptors from which the stdout
- * and stderr, respectively, output of the child program can be read, and the
- * stdin of the child process shall be set to /dev/null. Otherwise returns
- * -1. Some parts of this code are based on the POSIX subprocess module from
+/** Start a program in the background. If <b>filename</b> contains a '/', then
+ * it will be treated as an absolute or relative path. Otherwise, on
+ * non-Windows systems, the system path will be searched for <b>filename</b>.
+ * On Windows, only the current directory will be searched. Here, to search the
+ * system path (as well as the application directory, current working
+ * directory, and system directories), set filename to NULL.
+ *
+ * The strings in <b>argv</b> will be passed as the command line arguments of
+ * the child program (following convention, argv[0] should normally be the
+ * filename of the executable, and this must be the case if <b>filename</b> is
+ * NULL). The last element of argv must be NULL. If the child program is
+ * launched, a handle to it will be returned.
+ *
+ * Some parts of this code are based on the POSIX subprocess module from
* Python, and example code from
* http://msdn.microsoft.com/en-us/library/ms682499%28v=vs.85%29.aspx.
*/
+
process_handle_t
tor_spawn_background(const char *const filename, const char **argv)
{
@@ -3122,8 +3126,8 @@ tor_spawn_background(const char *const filename, const char **argv)
/* Create the child process */
- retval = CreateProcess(filename, // module name
- joined_argv, // command line
+ retval = CreateProcess(filename, // module name
+ joined_argv, // command line
NULL, // process security attributes
NULL, // primary thread security attributes
TRUE, // handles are inherited
@@ -3270,7 +3274,7 @@ tor_spawn_background(const char *const filename, const char **argv)
/* Write the error message. GCC requires that we check the return
value, but there is nothing we can do if it fails */
- // TODO: Don't use STDOUT, use a pipe set up just for this purpose
+ /* TODO: Don't use STDOUT, use a pipe set up just for this purpose */
nbytes = write(STDOUT_FILENO, error_message, error_message_length);
nbytes = write(STDOUT_FILENO, hex_errno, sizeof(hex_errno));
@@ -3291,7 +3295,9 @@ tor_spawn_background(const char *const filename, const char **argv)
return process_handle;
}
- // TODO: If the child process forked but failed to exec, waitpid it
+ process_handle.pid = pid;
+
+ /* TODO: If the child process forked but failed to exec, waitpid it */
/* Return read end of the pipes to caller, and close write end */
process_handle.stdout_pipe = stdout_pipe[0];
@@ -3301,8 +3307,6 @@ tor_spawn_background(const char *const filename, const char **argv)
log_warn(LD_GENERAL,
"Failed to close write end of stdout pipe in parent process: %s",
strerror(errno));
- /* Do not return -1, because the child is running, so the parent
- needs to know about the pid in order to reap it later */
}
process_handle.stderr_pipe = stderr_pipe[0];
@@ -3312,12 +3316,9 @@ tor_spawn_background(const char *const filename, const char **argv)
log_warn(LD_GENERAL,
"Failed to close write end of stderr pipe in parent process: %s",
strerror(errno));
- /* Do not return -1, because the child is running, so the parent
- needs to know about the pid in order to reap it later */
}
process_handle.status = 1;
- process_handle.pid = pid;
/* Set stdout/stderr pipes to be non-blocking */
fcntl(process_handle.stdout_pipe, F_SETFL, O_NONBLOCK);
fcntl(process_handle.stderr_pipe, F_SETFL, O_NONBLOCK);
@@ -3403,7 +3404,12 @@ tor_get_exit_code(const process_handle_t process_handle,
}
#ifdef MS_WINDOWS
-/* Windows equivalent of read_all */
+/** Read from a handle <b>h</b> into <b>buf</b>, up to <b>count</b> bytes. If
+ * <b>hProcess</b> is NULL, the function will return immediately if there is
+ * nothing more to read. Otherwise <b>hProcess</b> should be set to the handle
+ * to the process owning the <b>h</b>. In this case, the function will exit
+ * only once the process has exited, or <b>count</b> bytes are read. Returns
+ * the number of bytes read, or -1 on error. */
ssize_t
tor_read_all_handle(HANDLE h, char *buf, size_t count, HANDLE hProcess)
{
@@ -3416,6 +3422,7 @@ tor_read_all_handle(HANDLE h, char *buf, size_t count, HANDLE hProcess)
return -1;
while (numread != count) {
+ /* Check if there is anything to read */
retval = PeekNamedPipe(h, NULL, 0, NULL, &byte_count, NULL);
if (!retval) {
log_warn(LD_GENERAL,
@@ -3459,6 +3466,7 @@ tor_read_all_handle(HANDLE h, char *buf, size_t count, HANDLE hProcess)
}
#endif
+/* Read from stdout of a process until the process exits. */
ssize_t
tor_read_all_from_process_stdout(const process_handle_t process_handle,
char *buf, size_t count)
@@ -3471,6 +3479,7 @@ tor_read_all_from_process_stdout(const process_handle_t process_handle,
#endif
}
+/* Read from stdout of a process until the process exits. */
ssize_t
tor_read_all_from_process_stderr(const process_handle_t process_handle,
char *buf, size_t count)
@@ -3496,38 +3505,41 @@ log_from_handle(HANDLE *pipe, int severity)
pos = tor_read_all_handle(pipe, buf, sizeof(buf) - 1, NULL);
if (pos < 0) {
- // Error
+ /* Error */
log_warn(LD_GENERAL, "Failed to read data from subprocess");
return -1;
}
if (0 == pos) {
- // There's nothing to read (process is busy or has exited)
+ /* There's nothing to read (process is busy or has exited) */
log_debug(LD_GENERAL, "Subprocess had nothing to say");
return 0;
}
- // End with a null even if there isn't a \r\n at the end
- // TODO: What if this is a partial line?
+ /* End with a null even if there isn't a \r\n at the end */
+ /* TODO: What if this is a partial line? */
buf[pos] = '\0';
log_debug(LD_GENERAL, "Subprocess had %d bytes to say", pos);
+ /* Split buf into lines and log each one */
next = 0; // Start of the next line
while (next < pos) {
start = next; // Look for the end of this line
for (cur=start; cur<pos; cur++) {
+ /* On Windows \r means end of line */
if ('\r' == buf[cur]) {
buf[cur] = '\0';
next = cur + 1;
- if ((cur + 1) < pos && buf[cur+1] < pos) {
+ /* If \n follows, remove it too */
+ if ((cur + 1) < pos && '\n' == buf[cur+1]) {
buf[cur + 1] = '\0';
next = cur + 2;
}
- // Line starts at start and ends with a null (was \r\n)
+ /* Line starts at start and ends with a null (was \r\n) */
break;
}
- // Line starts at start and ends at the end of a string
- // but we already added a null in earlier
+ /* Line starts at start and ends at the end of a string
+ but we already added a null in earlier */
}
log_fn(severity, LD_GENERAL, "Port forwarding helper says: %s", buf+start);
}
diff --git a/src/common/util.h b/src/common/util.h
index b4ae3f858..2602628ab 100644
--- a/src/common/util.h
+++ b/src/common/util.h
@@ -366,7 +366,7 @@ typedef struct process_handle_s {
int stderr_pipe;
FILE *stdout_handle;
FILE *stderr_handle;
- int pid;
+ pid_t pid;
#endif // MS_WINDOWS
} process_handle_t;