mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-29 00:23:30 +01:00
Generalize process spawning so its test compiles (but fails) in Windows
- pid, stdout/stderr_pipe now encapsulated in process_handle - read_all replaced by tor_read_all_from_process_stdin/stderr - waitpid replaced by tor_get_exit_code Untested on *nix
This commit is contained in:
parent
2002d4acdf
commit
35c89be02b
@ -2978,14 +2978,15 @@ format_helper_exit_status(unsigned char child_state, int saved_errno,
|
|||||||
* -1. Some parts of this code are based on the POSIX subprocess module from
|
* -1. Some parts of this code are based on the POSIX subprocess module from
|
||||||
* Python.
|
* Python.
|
||||||
*/
|
*/
|
||||||
int
|
process_handle_t
|
||||||
tor_spawn_background(const char *const filename, int *stdout_read,
|
tor_spawn_background(const char *const filename, const char **argv)
|
||||||
int *stderr_read, const char **argv)
|
|
||||||
{
|
{
|
||||||
|
process_handle_t process_handle;
|
||||||
#ifdef MS_WINDOWS
|
#ifdef MS_WINDOWS
|
||||||
(void) filename; (void) stdout_read; (void) stderr_read; (void) argv;
|
(void) filename; (void) argv;
|
||||||
log_warn(LD_BUG, "not yet implemented on Windows.");
|
log_warn(LD_BUG, "not yet implemented on Windows.");
|
||||||
return -1;
|
process_handle.status = -1;
|
||||||
|
return process_handle;
|
||||||
#else
|
#else
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
int stdout_pipe[2];
|
int stdout_pipe[2];
|
||||||
@ -3016,7 +3017,8 @@ tor_spawn_background(const char *const filename, int *stdout_read,
|
|||||||
log_warn(LD_GENERAL,
|
log_warn(LD_GENERAL,
|
||||||
"Failed to set up pipe for stdout communication with child process: %s",
|
"Failed to set up pipe for stdout communication with child process: %s",
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
return -1;
|
process_handle.status = -1;
|
||||||
|
return process_handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
retval = pipe(stderr_pipe);
|
retval = pipe(stderr_pipe);
|
||||||
@ -3024,7 +3026,8 @@ tor_spawn_background(const char *const filename, int *stdout_read,
|
|||||||
log_warn(LD_GENERAL,
|
log_warn(LD_GENERAL,
|
||||||
"Failed to set up pipe for stderr communication with child process: %s",
|
"Failed to set up pipe for stderr communication with child process: %s",
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
return -1;
|
process_handle.status = -1;
|
||||||
|
return process_handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
child_state = CHILD_STATE_MAXFD;
|
child_state = CHILD_STATE_MAXFD;
|
||||||
@ -3109,7 +3112,8 @@ tor_spawn_background(const char *const filename, int *stdout_read,
|
|||||||
(void) nbytes;
|
(void) nbytes;
|
||||||
|
|
||||||
_exit(255);
|
_exit(255);
|
||||||
return -1; /* Never reached, but avoids compiler warning */
|
process_handle.status = -1;
|
||||||
|
return process_handle; /* Never reached, but avoids compiler warning */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* In parent */
|
/* In parent */
|
||||||
@ -3120,11 +3124,12 @@ tor_spawn_background(const char *const filename, int *stdout_read,
|
|||||||
close(stdout_pipe[1]);
|
close(stdout_pipe[1]);
|
||||||
close(stderr_pipe[0]);
|
close(stderr_pipe[0]);
|
||||||
close(stderr_pipe[1]);
|
close(stderr_pipe[1]);
|
||||||
return -1;
|
process_handle.status = -1;
|
||||||
|
return process_handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return read end of the pipes to caller, and close write end */
|
/* Return read end of the pipes to caller, and close write end */
|
||||||
*stdout_read = stdout_pipe[0];
|
process_handle.stdout_pipe = stdout_pipe[0];
|
||||||
retval = close(stdout_pipe[1]);
|
retval = close(stdout_pipe[1]);
|
||||||
|
|
||||||
if (-1 == retval) {
|
if (-1 == retval) {
|
||||||
@ -3135,7 +3140,7 @@ tor_spawn_background(const char *const filename, int *stdout_read,
|
|||||||
needs to know about the pid in order to reap it later */
|
needs to know about the pid in order to reap it later */
|
||||||
}
|
}
|
||||||
|
|
||||||
*stderr_read = stderr_pipe[0];
|
process_handle.stderr_pipe = stderr_pipe[0];
|
||||||
retval = close(stderr_pipe[1]);
|
retval = close(stderr_pipe[1]);
|
||||||
|
|
||||||
if (-1 == retval) {
|
if (-1 == retval) {
|
||||||
@ -3146,7 +3151,56 @@ tor_spawn_background(const char *const filename, int *stdout_read,
|
|||||||
needs to know about the pid in order to reap it later */
|
needs to know about the pid in order to reap it later */
|
||||||
}
|
}
|
||||||
|
|
||||||
return pid;
|
process_handle.status = 0;
|
||||||
|
process_handle.pid = pid;
|
||||||
|
return process_handle;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
tor_get_exit_code(const process_handle_t process_handle)
|
||||||
|
{
|
||||||
|
#ifdef MS_WINDOWS
|
||||||
|
log_warn(LD_BUG, "not yet implemented on Windows.");
|
||||||
|
return -1;
|
||||||
|
#else
|
||||||
|
int stat_loc;
|
||||||
|
|
||||||
|
retval = waitpid(process_handle.pid, &stat_loc, 0);
|
||||||
|
if (retval != process_handle.pid) {
|
||||||
|
log_warn(LD_GENERAL, "waitpid() failed for PID %d: %s", process_handle.pid,
|
||||||
|
sterror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!WIFEXITED(stat_loc)) {
|
||||||
|
log_warn(LD_GENERAL, "Process %d did not exit normally", process_handle.pid);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return WEXITSTATUS(stat_loc);
|
||||||
|
#endif // MS_WINDOWS
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t
|
||||||
|
tor_read_all_from_process_stdin(const process_handle_t process_handle,
|
||||||
|
char *buf, size_t count)
|
||||||
|
{
|
||||||
|
#ifdef MS_WINDOWS
|
||||||
|
return -1;
|
||||||
|
#else
|
||||||
|
return read_all(process_handle.stdin_pipe, buf, count, 0);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t
|
||||||
|
tor_read_all_from_process_stderr(const process_handle_t process_handle,
|
||||||
|
char *buf, size_t count)
|
||||||
|
{
|
||||||
|
#ifdef MS_WINDOWS
|
||||||
|
return -1;
|
||||||
|
#else
|
||||||
|
return read_all(process_handle.stderr_pipe, buf, count, 0);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -347,8 +347,27 @@ HANDLE load_windows_system_library(const TCHAR *library_name);
|
|||||||
|
|
||||||
#ifdef UTIL_PRIVATE
|
#ifdef UTIL_PRIVATE
|
||||||
/* Prototypes for private functions only used by util.c (and unit tests) */
|
/* Prototypes for private functions only used by util.c (and unit tests) */
|
||||||
int tor_spawn_background(const char *const filename, int *stdout_read,
|
|
||||||
int *stderr_read, const char **argv);
|
typedef struct process_handle_s {
|
||||||
|
int status;
|
||||||
|
#ifdef MS_WINDOWS
|
||||||
|
HANDLE stdout_pipe;
|
||||||
|
HANDLE stderr_pipe;
|
||||||
|
HANDLE pid;
|
||||||
|
#else
|
||||||
|
int stdout_pipe;
|
||||||
|
int stderr_pipe;
|
||||||
|
int pid;
|
||||||
|
#endif // MS_WINDOWS
|
||||||
|
} process_handle_t;
|
||||||
|
|
||||||
|
process_handle_t tor_spawn_background(const char *const filename,
|
||||||
|
const char **argv);
|
||||||
|
int tor_get_exit_code(const process_handle_t pid);
|
||||||
|
ssize_t tor_read_all_from_process_stdin(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,
|
||||||
|
char *buf, size_t count);
|
||||||
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);
|
||||||
|
|
||||||
|
@ -1376,42 +1376,38 @@ test_util_fgets_eagain(void *ptr)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef MS_WINDOWS
|
|
||||||
/** Helper function for testing tor_spawn_background */
|
/** Helper function for testing tor_spawn_background */
|
||||||
static void
|
static void
|
||||||
run_util_spawn_background(const char *argv[], const char *expected_out,
|
run_util_spawn_background(const char *argv[], const char *expected_out,
|
||||||
const char *expected_err, int expected_exit)
|
const char *expected_err, int expected_exit)
|
||||||
{
|
{
|
||||||
int stdout_pipe=-1, stderr_pipe=-1;
|
int retval;
|
||||||
int retval, stat_loc;
|
|
||||||
pid_t pid;
|
|
||||||
ssize_t pos;
|
ssize_t pos;
|
||||||
|
process_handle_t process_handle;
|
||||||
char stdout_buf[100], stderr_buf[100];
|
char stdout_buf[100], stderr_buf[100];
|
||||||
|
|
||||||
/* Start the program */
|
/* Start the program */
|
||||||
retval = tor_spawn_background(argv[0], &stdout_pipe, &stderr_pipe, argv);
|
process_handle = tor_spawn_background(argv[0], argv);
|
||||||
tt_int_op(retval, >, 0);
|
|
||||||
tt_int_op(stdout_pipe, >, 0);
|
tt_int_op(process_handle.status, ==, 0);
|
||||||
tt_int_op(stderr_pipe, >, 0);
|
tt_int_op(process_handle.stdout_pipe, >, 0);
|
||||||
pid = retval;
|
tt_int_op(process_handle.stderr_pipe, >, 0);
|
||||||
|
|
||||||
/* Check stdout */
|
/* Check stdout */
|
||||||
pos = read_all(stdout_pipe, stdout_buf, sizeof(stdout_buf) - 1, 0);
|
pos = tor_read_all_from_process_stdin(process_handle, stdout_buf,
|
||||||
|
sizeof(stdout_buf) - 1);
|
||||||
tt_assert(pos >= 0);
|
tt_assert(pos >= 0);
|
||||||
stdout_buf[pos] = '\0';
|
stdout_buf[pos] = '\0';
|
||||||
tt_int_op(pos, ==, strlen(expected_out));
|
tt_int_op(pos, ==, strlen(expected_out));
|
||||||
tt_str_op(stdout_buf, ==, expected_out);
|
tt_str_op(stdout_buf, ==, expected_out);
|
||||||
|
|
||||||
/* Check it terminated correctly */
|
/* Check it terminated correctly */
|
||||||
retval = waitpid(pid, &stat_loc, 0);
|
retval = tor_get_exit_code(process_handle);
|
||||||
tt_int_op(retval, ==, pid);
|
tt_int_op(retval, ==, expected_exit);
|
||||||
tt_assert(WIFEXITED(stat_loc));
|
|
||||||
tt_int_op(WEXITSTATUS(stat_loc), ==, expected_exit);
|
|
||||||
tt_assert(!WIFSIGNALED(stat_loc));
|
|
||||||
tt_assert(!WIFSTOPPED(stat_loc));
|
|
||||||
|
|
||||||
/* Check stderr */
|
/* Check stderr */
|
||||||
pos = read_all(stderr_pipe, stderr_buf, sizeof(stderr_buf) - 1, 0);
|
pos = tor_read_all_from_process_stderr(process_handle, stderr_buf,
|
||||||
|
sizeof(stderr_buf) - 1);
|
||||||
tt_assert(pos >= 0);
|
tt_assert(pos >= 0);
|
||||||
stderr_buf[pos] = '\0';
|
stderr_buf[pos] = '\0';
|
||||||
tt_int_op(pos, ==, strlen(expected_err));
|
tt_int_op(pos, ==, strlen(expected_err));
|
||||||
@ -1447,7 +1443,6 @@ test_util_spawn_background_fail(void *ptr)
|
|||||||
|
|
||||||
run_util_spawn_background(argv, expected_out, expected_err, 255);
|
run_util_spawn_background(argv, expected_out, expected_err, 255);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
test_util_di_ops(void)
|
test_util_di_ops(void)
|
||||||
@ -1533,9 +1528,9 @@ struct testcase_t util_tests[] = {
|
|||||||
UTIL_TEST(exit_status, 0),
|
UTIL_TEST(exit_status, 0),
|
||||||
#ifndef MS_WINDOWS
|
#ifndef MS_WINDOWS
|
||||||
UTIL_TEST(fgets_eagain, TT_SKIP),
|
UTIL_TEST(fgets_eagain, TT_SKIP),
|
||||||
|
#endif
|
||||||
UTIL_TEST(spawn_background_ok, 0),
|
UTIL_TEST(spawn_background_ok, 0),
|
||||||
UTIL_TEST(spawn_background_fail, 0),
|
UTIL_TEST(spawn_background_fail, 0),
|
||||||
#endif
|
|
||||||
END_OF_TESTCASES
|
END_OF_TESTCASES
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user