Make a version of tor_read_all_handle() for non-Windows platforms

Mainly used for testing reading from subprocesses. To be more generic
we now pass in a pointer to a process_handle_t rather than a Windows-
specific HANDLE.
This commit is contained in:
Steven Murdoch 2011-09-01 01:06:12 +01:00
parent 76fde28475
commit 5b8a20ed44
3 changed files with 94 additions and 34 deletions

View File

@ -3522,7 +3522,8 @@ tor_get_exit_code(const process_handle_t process_handle,
* only once the process has exited, or <b>count</b> bytes are read. Returns * only once the process has exited, or <b>count</b> bytes are read. Returns
* the number of bytes read, or -1 on error. */ * the number of bytes read, or -1 on error. */
ssize_t ssize_t
tor_read_all_handle(HANDLE h, char *buf, size_t count, HANDLE hProcess) tor_read_all_handle(HANDLE h, char *buf, size_t count,
const process_handle_t *process)
{ {
size_t numread = 0; size_t numread = 0;
BOOL retval; BOOL retval;
@ -3544,7 +3545,7 @@ tor_read_all_handle(HANDLE h, char *buf, size_t count, HANDLE hProcess)
/* Nothing available: process exited or it is busy */ /* Nothing available: process exited or it is busy */
/* Exit if we don't know whether the process is running */ /* Exit if we don't know whether the process is running */
if (NULL == hProcess) if (NULL == process)
break; break;
/* The process exited and there's nothing left to read from it */ /* The process exited and there's nothing left to read from it */
@ -3554,7 +3555,8 @@ tor_read_all_handle(HANDLE h, char *buf, size_t count, HANDLE hProcess)
/* If process is not running, check for output one more time in case /* If process is not running, check for output one more time in case
it wrote something after the peek was performed. Otherwise keep on it wrote something after the peek was performed. Otherwise keep on
waiting for output */ waiting for output */
byte_count = WaitForSingleObject(hProcess, 0); tor_assert(process != NULL);
byte_count = WaitForSingleObject(process->pid.hProcess, 0);
if (WAIT_TIMEOUT != byte_count) if (WAIT_TIMEOUT != byte_count)
process_exited = TRUE; process_exited = TRUE;
@ -3576,31 +3578,77 @@ tor_read_all_handle(HANDLE h, char *buf, size_t count, HANDLE hProcess)
} }
return (ssize_t)numread; return (ssize_t)numread;
} }
#else
/** Read from a handle <b>h</b> into <b>buf</b>, up to <b>count</b> bytes. If
* <b>process</b> is NULL, the function will return immediately if there is
* nothing more to read. Otherwise data will be read until end of file, or
* <b>count</b> bytes are read. Returns the number of bytes read, or -1 on
* error. */
ssize_t
tor_read_all_handle(FILE *h, char *buf, size_t count,
const process_handle_t *process)
{
size_t numread = 0;
char *retval;
if (count > SIZE_T_CEILING || count > SSIZE_T_MAX)
return -1;
while (numread != count) {
/* Use fgets because that is what we use in log_from_pipe() */
retval = fgets(buf+numread, (int)(count-numread), h);
if (NULL == retval) {
if (feof(h)) {
fclose(h);
break;
} else {
if (EAGAIN == errno) {
if (process)
continue;
else
break;
} else {
log_warn(LD_GENERAL, "fgets() from handle failed: %s",
strerror(errno));
fclose(h);
return -1;
}
}
}
tor_assert(retval != NULL);
numread += strlen(retval);
}
log_debug(LD_GENERAL, "fgets read %d bytes from handle", (int)numread);
return (ssize_t)numread;
}
#endif #endif
/** Read from stdout of a process until the process exits. */ /** Read from stdout of a process until the process exits. */
ssize_t ssize_t
tor_read_all_from_process_stdout(const process_handle_t process_handle, tor_read_all_from_process_stdout(const process_handle_t *process_handle,
char *buf, size_t count) char *buf, size_t count)
{ {
#ifdef MS_WINDOWS #ifdef MS_WINDOWS
return tor_read_all_handle(process_handle.stdout_pipe, buf, count, return tor_read_all_handle(process_handle->stdout_pipe, buf, count,
process_handle.pid.hProcess); process_handle);
#else #else
return read_all(process_handle.stdout_pipe, buf, count, 0); return tor_read_all_handle(process_handle->stdout_handle, buf, count,
process_handle);
#endif #endif
} }
/** Read from stdout of a process until the process exits. */ /** Read from stdout of a process until the process exits. */
ssize_t ssize_t
tor_read_all_from_process_stderr(const process_handle_t process_handle, tor_read_all_from_process_stderr(const process_handle_t *process_handle,
char *buf, size_t count) char *buf, size_t count)
{ {
#ifdef MS_WINDOWS #ifdef MS_WINDOWS
return tor_read_all_handle(process_handle.stderr_pipe, buf, count, return tor_read_all_handle(process_handle->stderr_pipe, buf, count,
process_handle.pid.hProcess); process_handle);
#else #else
return read_all(process_handle.stderr_pipe, buf, count, 0); return tor_read_all_handle(process_handle->stderr_handle, buf, count,
process_handle);
#endif #endif
} }

View File

@ -388,12 +388,15 @@ int tor_get_exit_code(const process_handle_t process_handle,
int tor_split_lines(struct smartlist_t *sl, char *buf, int len); int tor_split_lines(struct smartlist_t *sl, char *buf, int len);
#ifdef MS_WINDOWS #ifdef MS_WINDOWS
ssize_t tor_read_all_handle(HANDLE h, char *buf, size_t count, ssize_t tor_read_all_handle(HANDLE h, char *buf, size_t count,
HANDLE hProcess); const process_handle_t *process);
#else
ssize_t tor_read_all_handle(FILE *h, char *buf, size_t count,
const process_handle_t *process);
#endif #endif
ssize_t tor_read_all_from_process_stdout(const process_handle_t process_handle, ssize_t tor_read_all_from_process_stdout(
char *buf, size_t count); const process_handle_t *process_handle, char *buf, size_t count);
ssize_t tor_read_all_from_process_stderr(const process_handle_t process_handle, ssize_t tor_read_all_from_process_stderr(
char *buf, size_t count); const process_handle_t *process_handle, char *buf, size_t count);
char *tor_join_win_cmdline(const char *argv[]); char *tor_join_win_cmdline(const char *argv[]);
void format_helper_exit_status(unsigned char child_state, void format_helper_exit_status(unsigned char child_state,
int saved_errno, char *hex_errno); int saved_errno, char *hex_errno);

View File

@ -1404,8 +1404,8 @@ run_util_spawn_background(const char *argv[], const char *expected_out,
tt_int_op(process_handle.stderr_pipe, >, 0); tt_int_op(process_handle.stderr_pipe, >, 0);
/* Check stdout */ /* Check stdout */
pos = tor_read_all_from_process_stdout(process_handle, stdout_buf, pos = tor_read_all_from_process_stdout(&process_handle, stdout_buf,
sizeof(stdout_buf) - 1); sizeof(stdout_buf) - 1);
tt_assert(pos >= 0); tt_assert(pos >= 0);
stdout_buf[pos] = '\0'; stdout_buf[pos] = '\0';
tt_str_op(stdout_buf, ==, expected_out); tt_str_op(stdout_buf, ==, expected_out);
@ -1418,7 +1418,7 @@ run_util_spawn_background(const char *argv[], const char *expected_out,
// TODO: Make test-child exit with something other than 0 // TODO: Make test-child exit with something other than 0
/* Check stderr */ /* Check stderr */
pos = tor_read_all_from_process_stderr(process_handle, stderr_buf, pos = tor_read_all_from_process_stderr(&process_handle, stderr_buf,
sizeof(stderr_buf) - 1); sizeof(stderr_buf) - 1);
tt_assert(pos >= 0); tt_assert(pos >= 0);
stderr_buf[pos] = '\0'; stderr_buf[pos] = '\0';
@ -1493,57 +1493,66 @@ test_util_spawn_background_partial_read(void *ptr)
"DONE\r\n", "DONE\r\n",
NULL }; NULL };
const char *expected_err = "ERR\r\n"; const char *expected_err = "ERR\r\n";
int expected_out_ctr;
#else #else
const char *argv[] = {BUILDDIR "/src/test/test-child", "--test", NULL}; const char *argv[] = {BUILDDIR "/src/test/test-child", "--test", NULL};
const char *expected_out = "OUT\n--test\nSLEEPING\nDONE\n"; const char *expected_out[] = { "OUT\n--test\nSLEEPING\n",
const char *expected_err = "ERR\r\n"; "DONE\n",
NULL };
const char *expected_err = "ERR\n";
#endif #endif
int expected_out_ctr;
(void)ptr; (void)ptr;
/* Start the program */ /* Start the program */
#ifdef MS_WINDOWS
tor_spawn_background(NULL, argv, &process_handle); tor_spawn_background(NULL, argv, &process_handle);
#else
tor_spawn_background(argv[0], argv, &process_handle);
#endif
tt_int_op(process_handle.status, ==, expected_status); tt_int_op(process_handle.status, ==, expected_status);
/* Check stdout */ /* Check stdout */
#ifdef MS_WINDOWS
for (expected_out_ctr =0; expected_out[expected_out_ctr] != NULL;) { for (expected_out_ctr =0; expected_out[expected_out_ctr] != NULL;) {
#ifdef MS_WINDOWS
pos = tor_read_all_handle(process_handle.stdout_pipe, stdout_buf, pos = tor_read_all_handle(process_handle.stdout_pipe, stdout_buf,
sizeof(stdout_buf) - 1, NULL); sizeof(stdout_buf) - 1, NULL);
#else
pos = tor_read_all_handle(process_handle.stdout_handle, stdout_buf,
sizeof(stdout_buf) - 1, NULL);
#endif
log_info(LD_GENERAL, "tor_read_all_handle() returned %d", (int)pos); log_info(LD_GENERAL, "tor_read_all_handle() returned %d", (int)pos);
/* We would have blocked, keep on trying */ /* We would have blocked, keep on trying */
if (0 == pos) if (0 == pos)
continue; continue;
tt_assert(pos >= 0); tt_int_op(pos, >=, 0);
stdout_buf[pos] = '\0'; stdout_buf[pos] = '\0';
tt_str_op(stdout_buf, ==, expected_out[expected_out_ctr]); tt_str_op(stdout_buf, ==, expected_out[expected_out_ctr]);
tt_int_op(pos, ==, strlen(expected_out[expected_out_ctr])); tt_int_op(pos, ==, strlen(expected_out[expected_out_ctr]));
expected_out_ctr++; expected_out_ctr++;
} }
/* The process should have exited without writing more */ /* The process should have exited without writing more */
#ifdef MS_WINDOWS
pos = tor_read_all_handle(process_handle.stdout_pipe, stdout_buf, pos = tor_read_all_handle(process_handle.stdout_pipe, stdout_buf,
sizeof(stdout_buf) - 1, sizeof(stdout_buf) - 1,
process_handle.pid.hProcess); &process_handle);
tt_int_op(pos, ==, 0);
#else #else
pos = tor_read_all_from_process_stdout(process_handle, stdout_buf, pos = tor_read_all_handle(process_handle.stdout_handle, stdout_buf,
sizeof(stdout_buf) - 1); sizeof(stdout_buf) - 1,
tt_assert(pos >= 0); &process_handle);
stdout_buf[pos] = '\0';
tt_str_op(stdout_buf, ==, expected_out);
tt_int_op(pos, ==, strlen(expected_out));
#endif #endif
/* Check it terminated correctly */ /* Check it terminated correctly */
retval = tor_get_exit_code(process_handle, 1, &exit_code); retval = tor_get_exit_code(process_handle, 1, &exit_code);
tt_int_op(retval, ==, PROCESS_EXIT_EXITED); tt_int_op(retval, ==, PROCESS_EXIT_EXITED);
tt_int_op(exit_code, ==, expected_exit); tt_int_op(exit_code, ==, expected_exit);
// TODO: Make test-child exit with something other than 0 // TODO: Make test-child exit with something other than 0
/* Check stderr */ /* Check stderr */
pos = tor_read_all_from_process_stderr(process_handle, stderr_buf, pos = tor_read_all_from_process_stderr(&process_handle, stderr_buf,
sizeof(stderr_buf) - 1); sizeof(stderr_buf) - 1);
tt_assert(pos >= 0); tt_assert(pos >= 0);
stderr_buf[pos] = '\0'; stderr_buf[pos] = '\0';