mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2025-02-25 15:10:48 +01:00
Merge remote-tracking branch 'ahf/bugs/21654'
This commit is contained in:
commit
85782e111a
11 changed files with 148 additions and 226 deletions
|
@ -1,4 +0,0 @@
|
||||||
o Minor bugfixes (portability):
|
|
||||||
- Add Tor compatibility function for fgets(3) due to inconsistency of
|
|
||||||
returned values in different supported C libraries. This fixes unit test
|
|
||||||
failures reported on FreeBSD. Fixes bug 20988.
|
|
4
changes/bug21654
Normal file
4
changes/bug21654
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
o Code simplifications and refactoring
|
||||||
|
- Use unbuffered I/O for utility functions around the process_handle_t
|
||||||
|
type. This fixes unit test failures reported on OpenBSD and FreeBSD.
|
||||||
|
Fixes bug 21654.
|
|
@ -3476,45 +3476,6 @@ tor_getpass(const char *prompt, char *output, size_t buflen)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Read at most one less than the number of characters specified by
|
|
||||||
* <b>size</b> from the given <b>stream</b> and store it in <b>str</b>.
|
|
||||||
*
|
|
||||||
* Reading stops when a newline character is found or at EOF or error. If any
|
|
||||||
* characters are read and there's no error, a trailing NUL byte is appended to
|
|
||||||
* the end of <b>str</b>.
|
|
||||||
*
|
|
||||||
* Upon successful completion, this function returns a pointer to the string
|
|
||||||
* <b>str</b>. If EOF occurs before any characters are read the function will
|
|
||||||
* return NULL and the content of <b>str</b> is unchanged. Upon error, the
|
|
||||||
* function returns NULL and the caller must check for error using foef(3) and
|
|
||||||
* ferror(3).
|
|
||||||
*/
|
|
||||||
char *
|
|
||||||
tor_fgets(char *str, int size, FILE *stream)
|
|
||||||
{
|
|
||||||
char *ret;
|
|
||||||
|
|
||||||
/* Reset errno before our call to fgets(3) to avoid a situation where the
|
|
||||||
* caller is calling us again because we just returned NULL and errno ==
|
|
||||||
* EAGAIN, but when they call us again we will always return NULL because the
|
|
||||||
* error flag on the file handler remains set and errno is set to EAGAIN.
|
|
||||||
*/
|
|
||||||
errno = 0;
|
|
||||||
|
|
||||||
ret = fgets(str, size, stream);
|
|
||||||
|
|
||||||
/* FreeBSD, OpenBSD, Linux (glibc), and Linux (musl) seem to disagree about
|
|
||||||
* what to do in the given situation. We check if the stream has been flagged
|
|
||||||
* with an error-bit and return NULL in that situation if errno is also set
|
|
||||||
* to EAGAIN.
|
|
||||||
*/
|
|
||||||
if (ferror(stream) && errno == EAGAIN) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Return the amount of free disk space we have permission to use, in
|
/** Return the amount of free disk space we have permission to use, in
|
||||||
* bytes. Return -1 if the amount of free space can't be determined. */
|
* bytes. Return -1 if the amount of free space can't be determined. */
|
||||||
int64_t
|
int64_t
|
||||||
|
|
|
@ -740,8 +740,6 @@ STATIC int tor_ersatz_socketpair(int family, int type, int protocol,
|
||||||
|
|
||||||
ssize_t tor_getpass(const char *prompt, char *output, size_t buflen);
|
ssize_t tor_getpass(const char *prompt, char *output, size_t buflen);
|
||||||
|
|
||||||
char *tor_fgets(char *str, int size, FILE *stream);
|
|
||||||
|
|
||||||
/* This needs some of the declarations above so we include it here. */
|
/* This needs some of the declarations above so we include it here. */
|
||||||
#include "compat_threads.h"
|
#include "compat_threads.h"
|
||||||
|
|
||||||
|
|
|
@ -2118,7 +2118,7 @@ read_all(tor_socket_t fd, char *buf, size_t count, int isSocket)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (numread != count) {
|
while (numread < count) {
|
||||||
if (isSocket)
|
if (isSocket)
|
||||||
result = tor_socket_recv(fd, buf+numread, count-numread, 0);
|
result = tor_socket_recv(fd, buf+numread, count-numread, 0);
|
||||||
else
|
else
|
||||||
|
@ -4175,10 +4175,10 @@ tor_process_get_stdout_pipe(process_handle_t *process_handle)
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
/* DOCDOC tor_process_get_stdout_pipe */
|
/* DOCDOC tor_process_get_stdout_pipe */
|
||||||
FILE *
|
int
|
||||||
tor_process_get_stdout_pipe(process_handle_t *process_handle)
|
tor_process_get_stdout_pipe(process_handle_t *process_handle)
|
||||||
{
|
{
|
||||||
return process_handle->stdout_handle;
|
return process_handle->stdout_pipe;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -4609,10 +4609,6 @@ tor_spawn_background(const char *const filename, const char **argv,
|
||||||
log_warn(LD_GENERAL, "Failed to set stderror/stdout/stdin pipes "
|
log_warn(LD_GENERAL, "Failed to set stderror/stdout/stdin pipes "
|
||||||
"nonblocking in parent process: %s", strerror(errno));
|
"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;
|
*process_handle_out = process_handle;
|
||||||
return process_handle->status;
|
return process_handle->status;
|
||||||
|
@ -4659,14 +4655,9 @@ tor_process_handle_destroy,(process_handle_t *process_handle,
|
||||||
if (process_handle->stdin_pipe)
|
if (process_handle->stdin_pipe)
|
||||||
CloseHandle(process_handle->stdin_pipe);
|
CloseHandle(process_handle->stdin_pipe);
|
||||||
#else
|
#else
|
||||||
if (process_handle->stdout_handle)
|
close(process_handle->stdout_pipe);
|
||||||
fclose(process_handle->stdout_handle);
|
close(process_handle->stderr_pipe);
|
||||||
|
close(process_handle->stdin_pipe);
|
||||||
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);
|
clear_waitpid_callback(process_handle->waitpid_cb);
|
||||||
#endif
|
#endif
|
||||||
|
@ -4952,7 +4943,7 @@ tor_read_all_handle(HANDLE h, char *buf, size_t count,
|
||||||
if (count > SIZE_T_CEILING || count > SSIZE_MAX)
|
if (count > SIZE_T_CEILING || count > SSIZE_MAX)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
while (numread != count) {
|
while (numread < count) {
|
||||||
/* Check if there is anything to read */
|
/* Check if there is anything to read */
|
||||||
retval = PeekNamedPipe(h, NULL, 0, NULL, &byte_count, NULL);
|
retval = PeekNamedPipe(h, NULL, 0, NULL, &byte_count, NULL);
|
||||||
if (!retval) {
|
if (!retval) {
|
||||||
|
@ -4998,19 +4989,19 @@ tor_read_all_handle(HANDLE h, char *buf, size_t count,
|
||||||
return (ssize_t)numread;
|
return (ssize_t)numread;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
/** Read from a handle <b>h</b> into <b>buf</b>, up to <b>count</b> bytes. If
|
/** Read from a handle <b>fd</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
|
* <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
|
* 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
|
* <b>count</b> bytes are read. Returns the number of bytes read, or -1 on
|
||||||
* error. Sets <b>eof</b> to true if <b>eof</b> is not NULL and the end of the
|
* error. Sets <b>eof</b> to true if <b>eof</b> is not NULL and the end of the
|
||||||
* file has been reached. */
|
* file has been reached. */
|
||||||
ssize_t
|
ssize_t
|
||||||
tor_read_all_handle(FILE *h, char *buf, size_t count,
|
tor_read_all_handle(int fd, char *buf, size_t count,
|
||||||
const process_handle_t *process,
|
const process_handle_t *process,
|
||||||
int *eof)
|
int *eof)
|
||||||
{
|
{
|
||||||
size_t numread = 0;
|
size_t numread = 0;
|
||||||
char *retval;
|
ssize_t result;
|
||||||
|
|
||||||
if (eof)
|
if (eof)
|
||||||
*eof = 0;
|
*eof = 0;
|
||||||
|
@ -5018,34 +5009,28 @@ tor_read_all_handle(FILE *h, char *buf, size_t count,
|
||||||
if (count > SIZE_T_CEILING || count > SSIZE_MAX)
|
if (count > SIZE_T_CEILING || count > SSIZE_MAX)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
while (numread != count) {
|
while (numread < count) {
|
||||||
/* Use fgets because that is what we use in log_from_pipe() */
|
result = read(fd, buf+numread, count-numread);
|
||||||
retval = tor_fgets(buf+numread, (int)(count-numread), h);
|
|
||||||
if (NULL == retval) {
|
if (result == 0) {
|
||||||
if (feof(h)) {
|
log_debug(LD_GENERAL, "read() reached end of file");
|
||||||
log_debug(LD_GENERAL, "fgets() reached end of file");
|
if (eof)
|
||||||
if (eof)
|
*eof = 1;
|
||||||
*eof = 1;
|
break;
|
||||||
|
} else if (result < 0 && errno == EAGAIN) {
|
||||||
|
if (process)
|
||||||
|
continue;
|
||||||
|
else
|
||||||
break;
|
break;
|
||||||
} else {
|
} else if (result < 0) {
|
||||||
if (EAGAIN == errno) {
|
log_warn(LD_GENERAL, "read() failed: %s", strerror(errno));
|
||||||
if (process)
|
return -1;
|
||||||
continue;
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
log_warn(LD_GENERAL, "fgets() from handle failed: %s",
|
|
||||||
strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
tor_assert(retval != NULL);
|
|
||||||
tor_assert(strlen(retval) + numread <= count);
|
numread += result;
|
||||||
numread += strlen(retval);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log_debug(LD_GENERAL, "fgets() read %d bytes from handle", (int)numread);
|
log_debug(LD_GENERAL, "read() read %d bytes from handle", (int)numread);
|
||||||
return (ssize_t)numread;
|
return (ssize_t)numread;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -5059,7 +5044,7 @@ tor_read_all_from_process_stdout(const process_handle_t *process_handle,
|
||||||
return tor_read_all_handle(process_handle->stdout_pipe, buf, count,
|
return tor_read_all_handle(process_handle->stdout_pipe, buf, count,
|
||||||
process_handle);
|
process_handle);
|
||||||
#else
|
#else
|
||||||
return tor_read_all_handle(process_handle->stdout_handle, buf, count,
|
return tor_read_all_handle(process_handle->stdout_pipe, buf, count,
|
||||||
process_handle, NULL);
|
process_handle, NULL);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -5073,7 +5058,7 @@ tor_read_all_from_process_stderr(const process_handle_t *process_handle,
|
||||||
return tor_read_all_handle(process_handle->stderr_pipe, buf, count,
|
return tor_read_all_handle(process_handle->stderr_pipe, buf, count,
|
||||||
process_handle);
|
process_handle);
|
||||||
#else
|
#else
|
||||||
return tor_read_all_handle(process_handle->stderr_handle, buf, count,
|
return tor_read_all_handle(process_handle->stderr_pipe, buf, count,
|
||||||
process_handle, NULL);
|
process_handle, NULL);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -5267,11 +5252,10 @@ log_from_handle(HANDLE *pipe, int severity)
|
||||||
#else
|
#else
|
||||||
|
|
||||||
/** Return a smartlist containing lines outputted from
|
/** Return a smartlist containing lines outputted from
|
||||||
* <b>handle</b>. Return NULL on error, and set
|
* <b>fd</b>. Return NULL on error, and set
|
||||||
* <b>stream_status_out</b> appropriately. */
|
* <b>stream_status_out</b> appropriately. */
|
||||||
MOCK_IMPL(smartlist_t *,
|
MOCK_IMPL(smartlist_t *,
|
||||||
tor_get_lines_from_handle, (FILE *handle,
|
tor_get_lines_from_handle, (int fd, enum stream_status *stream_status_out))
|
||||||
enum stream_status *stream_status_out))
|
|
||||||
{
|
{
|
||||||
enum stream_status stream_status;
|
enum stream_status stream_status;
|
||||||
char stdout_buf[400];
|
char stdout_buf[400];
|
||||||
|
@ -5280,7 +5264,7 @@ tor_get_lines_from_handle, (FILE *handle,
|
||||||
while (1) {
|
while (1) {
|
||||||
memset(stdout_buf, 0, sizeof(stdout_buf));
|
memset(stdout_buf, 0, sizeof(stdout_buf));
|
||||||
|
|
||||||
stream_status = get_string_from_pipe(handle,
|
stream_status = get_string_from_pipe(fd,
|
||||||
stdout_buf, sizeof(stdout_buf) - 1);
|
stdout_buf, sizeof(stdout_buf) - 1);
|
||||||
if (stream_status != IO_STREAM_OKAY)
|
if (stream_status != IO_STREAM_OKAY)
|
||||||
goto done;
|
goto done;
|
||||||
|
@ -5294,20 +5278,20 @@ tor_get_lines_from_handle, (FILE *handle,
|
||||||
return lines;
|
return lines;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Read from stream, and send lines to log at the specified log level.
|
/** Read from fd, and send lines to log at the specified log level.
|
||||||
* Returns 1 if stream is closed normally, -1 if there is a error reading, and
|
* Returns 1 if stream is closed normally, -1 if there is a error reading, and
|
||||||
* 0 otherwise. Handles lines from tor-fw-helper and
|
* 0 otherwise. Handles lines from tor-fw-helper and
|
||||||
* tor_spawn_background() specially.
|
* tor_spawn_background() specially.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
log_from_pipe(FILE *stream, int severity, const char *executable,
|
log_from_pipe(int fd, int severity, const char *executable,
|
||||||
int *child_status)
|
int *child_status)
|
||||||
{
|
{
|
||||||
char buf[256];
|
char buf[256];
|
||||||
enum stream_status r;
|
enum stream_status r;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
r = get_string_from_pipe(stream, buf, sizeof(buf) - 1);
|
r = get_string_from_pipe(fd, buf, sizeof(buf) - 1);
|
||||||
|
|
||||||
if (r == IO_STREAM_CLOSED) {
|
if (r == IO_STREAM_CLOSED) {
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -5332,7 +5316,7 @@ log_from_pipe(FILE *stream, int severity, const char *executable,
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/** Reads from <b>stream</b> and stores input in <b>buf_out</b> making
|
/** Reads from <b>fd</b> and stores input in <b>buf_out</b> making
|
||||||
* sure it's below <b>count</b> bytes.
|
* sure it's below <b>count</b> bytes.
|
||||||
* If the string has a trailing newline, we strip it off.
|
* If the string has a trailing newline, we strip it off.
|
||||||
*
|
*
|
||||||
|
@ -5348,52 +5332,28 @@ log_from_pipe(FILE *stream, int severity, const char *executable,
|
||||||
* IO_STREAM_OKAY: If everything went okay and we got a string
|
* IO_STREAM_OKAY: If everything went okay and we got a string
|
||||||
* in <b>buf_out</b>. */
|
* in <b>buf_out</b>. */
|
||||||
enum stream_status
|
enum stream_status
|
||||||
get_string_from_pipe(FILE *stream, char *buf_out, size_t count)
|
get_string_from_pipe(int fd, char *buf_out, size_t count)
|
||||||
{
|
{
|
||||||
char *retval;
|
ssize_t ret;
|
||||||
size_t len;
|
|
||||||
|
|
||||||
tor_assert(count <= INT_MAX);
|
tor_assert(count <= INT_MAX);
|
||||||
|
|
||||||
retval = tor_fgets(buf_out, (int)count, stream);
|
ret = read(fd, buf_out, count);
|
||||||
|
|
||||||
if (!retval) {
|
if (ret == 0)
|
||||||
if (feof(stream)) {
|
return IO_STREAM_CLOSED;
|
||||||
/* Program has closed stream (probably it exited) */
|
else if (ret < 0 && errno == EAGAIN)
|
||||||
/* TODO: check error */
|
return IO_STREAM_EAGAIN;
|
||||||
return IO_STREAM_CLOSED;
|
else if (ret < 0)
|
||||||
} else {
|
return IO_STREAM_TERM;
|
||||||
if (EAGAIN == errno) {
|
|
||||||
/* Nothing more to read, try again next time */
|
|
||||||
return IO_STREAM_EAGAIN;
|
|
||||||
} else {
|
|
||||||
/* There was a problem, abandon this child process */
|
|
||||||
return IO_STREAM_TERM;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
len = strlen(buf_out);
|
|
||||||
if (len == 0) {
|
|
||||||
/* this probably means we got a NUL at the start of the string. */
|
|
||||||
return IO_STREAM_EAGAIN;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (buf_out[len - 1] == '\n') {
|
if (buf_out[ret - 1] == '\n') {
|
||||||
/* Remove the trailing newline */
|
/* Remove the trailing newline */
|
||||||
buf_out[len - 1] = '\0';
|
buf_out[ret - 1] = '\0';
|
||||||
} else {
|
} else
|
||||||
/* No newline; check whether we overflowed the buffer */
|
buf_out[ret] = '\0';
|
||||||
if (!feof(stream))
|
|
||||||
log_info(LD_GENERAL,
|
|
||||||
"Line from stream was truncated: %s", buf_out);
|
|
||||||
/* TODO: What to do with this error? */
|
|
||||||
}
|
|
||||||
|
|
||||||
return IO_STREAM_OKAY;
|
return IO_STREAM_OKAY;
|
||||||
}
|
|
||||||
|
|
||||||
/* We should never get here */
|
|
||||||
return IO_STREAM_TERM;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Parse a <b>line</b> from tor-fw-helper and issue an appropriate
|
/** Parse a <b>line</b> from tor-fw-helper and issue an appropriate
|
||||||
|
@ -5630,7 +5590,7 @@ tor_check_port_forwarding(const char *filename,
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
stderr_status = log_from_handle(child_handle->stderr_pipe, LOG_INFO);
|
stderr_status = log_from_handle(child_handle->stderr_pipe, LOG_INFO);
|
||||||
#else
|
#else
|
||||||
stderr_status = log_from_pipe(child_handle->stderr_handle,
|
stderr_status = log_from_pipe(child_handle->stderr_pipe,
|
||||||
LOG_INFO, filename, &retval);
|
LOG_INFO, filename, &retval);
|
||||||
#endif
|
#endif
|
||||||
if (handle_fw_helper_output(filename, child_handle) < 0) {
|
if (handle_fw_helper_output(filename, child_handle) < 0) {
|
||||||
|
|
|
@ -322,7 +322,7 @@ enum stream_status {
|
||||||
|
|
||||||
const char *stream_status_to_string(enum stream_status stream_status);
|
const char *stream_status_to_string(enum stream_status stream_status);
|
||||||
|
|
||||||
enum stream_status get_string_from_pipe(FILE *stream, char *buf, size_t count);
|
enum stream_status get_string_from_pipe(int fd, char *buf, size_t count);
|
||||||
|
|
||||||
MOCK_DECL(int,tor_unlink,(const char *pathname));
|
MOCK_DECL(int,tor_unlink,(const char *pathname));
|
||||||
|
|
||||||
|
@ -463,9 +463,6 @@ struct process_handle_t {
|
||||||
int stdin_pipe;
|
int stdin_pipe;
|
||||||
int stdout_pipe;
|
int stdout_pipe;
|
||||||
int stderr_pipe;
|
int stderr_pipe;
|
||||||
FILE *stdin_handle;
|
|
||||||
FILE *stdout_handle;
|
|
||||||
FILE *stderr_handle;
|
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
/** If the process has not given us a SIGCHLD yet, this has the
|
/** If the process has not given us a SIGCHLD yet, this has the
|
||||||
* waitpid_callback_t that gets invoked once it has. Otherwise this
|
* waitpid_callback_t that gets invoked once it has. Otherwise this
|
||||||
|
@ -488,7 +485,7 @@ int tor_split_lines(struct smartlist_t *sl, char *buf, int len);
|
||||||
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,
|
||||||
const process_handle_t *process);
|
const process_handle_t *process);
|
||||||
#else
|
#else
|
||||||
ssize_t tor_read_all_handle(FILE *h, char *buf, size_t count,
|
ssize_t tor_read_all_handle(int fd, char *buf, size_t count,
|
||||||
const process_handle_t *process,
|
const process_handle_t *process,
|
||||||
int *eof);
|
int *eof);
|
||||||
#endif
|
#endif
|
||||||
|
@ -502,7 +499,7 @@ int tor_process_get_pid(process_handle_t *process_handle);
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
HANDLE tor_process_get_stdout_pipe(process_handle_t *process_handle);
|
HANDLE tor_process_get_stdout_pipe(process_handle_t *process_handle);
|
||||||
#else
|
#else
|
||||||
FILE *tor_process_get_stdout_pipe(process_handle_t *process_handle);
|
int tor_process_get_stdout_pipe(process_handle_t *process_handle);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
@ -511,7 +508,7 @@ tor_get_lines_from_handle,(HANDLE *handle,
|
||||||
enum stream_status *stream_status));
|
enum stream_status *stream_status));
|
||||||
#else
|
#else
|
||||||
MOCK_DECL(struct smartlist_t *,
|
MOCK_DECL(struct smartlist_t *,
|
||||||
tor_get_lines_from_handle,(FILE *handle,
|
tor_get_lines_from_handle,(int fd,
|
||||||
enum stream_status *stream_status));
|
enum stream_status *stream_status));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -2701,7 +2701,7 @@ dirserv_read_measured_bandwidths(const char *from_file,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!tor_fgets(line, sizeof(line), fp)
|
if (!fgets(line, sizeof(line), fp)
|
||||||
|| !strlen(line) || line[strlen(line)-1] != '\n') {
|
|| !strlen(line) || line[strlen(line)-1] != '\n') {
|
||||||
log_warn(LD_DIRSERV, "Long or truncated time in bandwidth file: %s",
|
log_warn(LD_DIRSERV, "Long or truncated time in bandwidth file: %s",
|
||||||
escaped(line));
|
escaped(line));
|
||||||
|
@ -2731,7 +2731,7 @@ dirserv_read_measured_bandwidths(const char *from_file,
|
||||||
|
|
||||||
while (!feof(fp)) {
|
while (!feof(fp)) {
|
||||||
measured_bw_line_t parsed_line;
|
measured_bw_line_t parsed_line;
|
||||||
if (tor_fgets(line, sizeof(line), fp) && strlen(line)) {
|
if (fgets(line, sizeof(line), fp) && strlen(line)) {
|
||||||
if (measured_bw_line_parse(&parsed_line, line) != -1) {
|
if (measured_bw_line_parse(&parsed_line, line) != -1) {
|
||||||
/* Also cache the line for dirserv_get_bandwidth_for_router() */
|
/* Also cache the line for dirserv_get_bandwidth_for_router() */
|
||||||
dirserv_cache_measured_bw(&parsed_line, file_time);
|
dirserv_cache_measured_bw(&parsed_line, file_time);
|
||||||
|
|
|
@ -346,7 +346,7 @@ geoip_load_file(sa_family_t family, const char *filename)
|
||||||
(family == AF_INET) ? "IPv4" : "IPv6", filename);
|
(family == AF_INET) ? "IPv4" : "IPv6", filename);
|
||||||
while (!feof(f)) {
|
while (!feof(f)) {
|
||||||
char buf[512];
|
char buf[512];
|
||||||
if (tor_fgets(buf, (int)sizeof(buf), f) == NULL)
|
if (fgets(buf, (int)sizeof(buf), f) == NULL)
|
||||||
break;
|
break;
|
||||||
crypto_digest_add_bytes(geoip_digest_env, buf, strlen(buf));
|
crypto_digest_add_bytes(geoip_digest_env, buf, strlen(buf));
|
||||||
/* FFFF track full country name. */
|
/* FFFF track full country name. */
|
||||||
|
|
|
@ -284,13 +284,13 @@ test_pt_get_extrainfo_string(void *arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#define STDIN_HANDLE HANDLE
|
#define STDIN_HANDLE HANDLE*
|
||||||
#else
|
#else
|
||||||
#define STDIN_HANDLE FILE
|
#define STDIN_HANDLE int
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static smartlist_t *
|
static smartlist_t *
|
||||||
tor_get_lines_from_handle_replacement(STDIN_HANDLE *handle,
|
tor_get_lines_from_handle_replacement(STDIN_HANDLE handle,
|
||||||
enum stream_status *stream_status_out)
|
enum stream_status *stream_status_out)
|
||||||
{
|
{
|
||||||
static int times_called = 0;
|
static int times_called = 0;
|
||||||
|
|
|
@ -3940,17 +3940,13 @@ test_util_exit_status(void *ptr)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
/* Check that fgets with a non-blocking pipe returns partial lines and sets
|
|
||||||
* EAGAIN, returns full lines and sets no error, and returns NULL on EOF and
|
|
||||||
* sets no error */
|
|
||||||
static void
|
static void
|
||||||
test_util_fgets_eagain(void *ptr)
|
test_util_string_from_pipe(void *ptr)
|
||||||
{
|
{
|
||||||
int test_pipe[2] = {-1, -1};
|
int test_pipe[2] = {-1, -1};
|
||||||
int retval;
|
int retval = 0;
|
||||||
|
enum stream_status status = IO_STREAM_TERM;
|
||||||
ssize_t retlen;
|
ssize_t retlen;
|
||||||
char *retptr;
|
|
||||||
FILE *test_stream = NULL;
|
|
||||||
char buf[4] = { 0 };
|
char buf[4] = { 0 };
|
||||||
|
|
||||||
(void)ptr;
|
(void)ptr;
|
||||||
|
@ -3961,95 +3957,105 @@ test_util_fgets_eagain(void *ptr)
|
||||||
retval = pipe(test_pipe);
|
retval = pipe(test_pipe);
|
||||||
tt_int_op(retval, OP_EQ, 0);
|
tt_int_op(retval, OP_EQ, 0);
|
||||||
|
|
||||||
/* Set up the read-end to be non-blocking */
|
/* Send in a string. */
|
||||||
retval = fcntl(test_pipe[0], F_SETFL, O_NONBLOCK);
|
retlen = write(test_pipe[1], "ABC", 3);
|
||||||
tt_int_op(retval, OP_EQ, 0);
|
|
||||||
|
|
||||||
/* Open it as a stdio stream */
|
|
||||||
test_stream = fdopen(test_pipe[0], "r");
|
|
||||||
tt_ptr_op(test_stream, OP_NE, NULL);
|
|
||||||
|
|
||||||
/* Send in a partial line */
|
|
||||||
retlen = write(test_pipe[1], "A", 1);
|
|
||||||
tt_int_op(retlen, OP_EQ, 1);
|
|
||||||
retptr = tor_fgets(buf, sizeof(buf), test_stream);
|
|
||||||
tt_int_op(errno, OP_EQ, EAGAIN);
|
|
||||||
tt_ptr_op(retptr, OP_EQ, NULL);
|
|
||||||
tt_str_op(buf, OP_EQ, "A");
|
|
||||||
errno = 0;
|
|
||||||
|
|
||||||
/* Send in the rest */
|
|
||||||
retlen = write(test_pipe[1], "B\n", 2);
|
|
||||||
tt_int_op(retlen, OP_EQ, 2);
|
|
||||||
retptr = tor_fgets(buf, sizeof(buf), test_stream);
|
|
||||||
tt_int_op(errno, OP_EQ, 0);
|
|
||||||
tt_ptr_op(retptr, OP_EQ, buf);
|
|
||||||
tt_str_op(buf, OP_EQ, "B\n");
|
|
||||||
errno = 0;
|
|
||||||
memset(buf, '\0', sizeof(buf));
|
|
||||||
|
|
||||||
/* Send in a full line */
|
|
||||||
retlen = write(test_pipe[1], "CD\n", 3);
|
|
||||||
tt_int_op(retlen, OP_EQ, 3);
|
tt_int_op(retlen, OP_EQ, 3);
|
||||||
retptr = tor_fgets(buf, sizeof(buf), test_stream);
|
|
||||||
tt_int_op(errno, OP_EQ, 0);
|
|
||||||
tt_ptr_op(retptr, OP_EQ, buf);
|
|
||||||
tt_str_op(buf, OP_EQ, "CD\n");
|
|
||||||
errno = 0;
|
|
||||||
memset(buf, '\0', sizeof(buf));
|
|
||||||
|
|
||||||
/* Send in a partial line */
|
status = get_string_from_pipe(test_pipe[0], buf, sizeof(buf)-1);
|
||||||
retlen = write(test_pipe[1], "E", 1);
|
tt_int_op(errno, OP_EQ, 0);
|
||||||
|
tt_int_op(status, OP_EQ, IO_STREAM_OKAY);
|
||||||
|
tt_str_op(buf, OP_EQ, "ABC");
|
||||||
|
errno = 0;
|
||||||
|
|
||||||
|
/* Send in a string that contains a nul. */
|
||||||
|
retlen = write(test_pipe[1], "AB\0", 3);
|
||||||
|
tt_int_op(retlen, OP_EQ, 3);
|
||||||
|
|
||||||
|
status = get_string_from_pipe(test_pipe[0], buf, sizeof(buf)-1);
|
||||||
|
tt_int_op(errno, OP_EQ, 0);
|
||||||
|
tt_int_op(status, OP_EQ, IO_STREAM_OKAY);
|
||||||
|
tt_str_op(buf, OP_EQ, "AB");
|
||||||
|
errno = 0;
|
||||||
|
|
||||||
|
/* Send in a string that contains a nul only. */
|
||||||
|
retlen = write(test_pipe[1], "\0", 1);
|
||||||
tt_int_op(retlen, OP_EQ, 1);
|
tt_int_op(retlen, OP_EQ, 1);
|
||||||
retptr = tor_fgets(buf, sizeof(buf), test_stream);
|
|
||||||
tt_int_op(errno, OP_EQ, EAGAIN);
|
|
||||||
tt_ptr_op(retptr, OP_EQ, NULL);
|
|
||||||
tt_str_op(buf, OP_EQ, "E");
|
|
||||||
errno = 0;
|
|
||||||
|
|
||||||
/* Send in the rest */
|
status = get_string_from_pipe(test_pipe[0], buf, sizeof(buf)-1);
|
||||||
retlen = write(test_pipe[1], "F\n", 2);
|
|
||||||
tt_int_op(retlen, OP_EQ, 2);
|
|
||||||
retptr = tor_fgets(buf, sizeof(buf), test_stream);
|
|
||||||
tt_int_op(errno, OP_EQ, 0);
|
tt_int_op(errno, OP_EQ, 0);
|
||||||
tt_ptr_op(retptr, OP_EQ, buf);
|
tt_int_op(status, OP_EQ, IO_STREAM_OKAY);
|
||||||
tt_str_op(buf, OP_EQ, "F\n");
|
tt_str_op(buf, OP_EQ, "");
|
||||||
errno = 0;
|
errno = 0;
|
||||||
memset(buf, '\0', sizeof(buf));
|
|
||||||
|
|
||||||
/* Send in a full line and close */
|
/* Send in a string that contains a trailing newline. */
|
||||||
retlen = write(test_pipe[1], "GH", 2);
|
retlen = write(test_pipe[1], "AB\n", 3);
|
||||||
|
tt_int_op(retlen, OP_EQ, 3);
|
||||||
|
|
||||||
|
status = get_string_from_pipe(test_pipe[0], buf, sizeof(buf)-1);
|
||||||
|
tt_int_op(errno, OP_EQ, 0);
|
||||||
|
tt_int_op(status, OP_EQ, IO_STREAM_OKAY);
|
||||||
|
tt_str_op(buf, OP_EQ, "AB");
|
||||||
|
errno = 0;
|
||||||
|
|
||||||
|
/* Send in a string that contains a newline only. */
|
||||||
|
retlen = write(test_pipe[1], "\n", 1);
|
||||||
|
tt_int_op(retlen, OP_EQ, 1);
|
||||||
|
|
||||||
|
status = get_string_from_pipe(test_pipe[0], buf, sizeof(buf)-1);
|
||||||
|
tt_int_op(errno, OP_EQ, 0);
|
||||||
|
tt_int_op(status, OP_EQ, IO_STREAM_OKAY);
|
||||||
|
tt_str_op(buf, OP_EQ, "");
|
||||||
|
errno = 0;
|
||||||
|
|
||||||
|
/* Send in a string and check that we nul terminate return values. */
|
||||||
|
retlen = write(test_pipe[1], "AAA", 3);
|
||||||
|
tt_int_op(retlen, OP_EQ, 3);
|
||||||
|
|
||||||
|
status = get_string_from_pipe(test_pipe[0], buf, sizeof(buf)-1);
|
||||||
|
tt_int_op(errno, OP_EQ, 0);
|
||||||
|
tt_int_op(status, OP_EQ, IO_STREAM_OKAY);
|
||||||
|
tt_str_op(buf, OP_EQ, "AAA");
|
||||||
|
tt_mem_op(buf, OP_EQ, "AAA\0", sizeof(buf));
|
||||||
|
errno = 0;
|
||||||
|
|
||||||
|
retlen = write(test_pipe[1], "B", 1);
|
||||||
|
tt_int_op(retlen, OP_EQ, 1);
|
||||||
|
|
||||||
|
memset(buf, '\xff', sizeof(buf));
|
||||||
|
status = get_string_from_pipe(test_pipe[0], buf, sizeof(buf)-1);
|
||||||
|
tt_int_op(errno, OP_EQ, 0);
|
||||||
|
tt_int_op(status, OP_EQ, IO_STREAM_OKAY);
|
||||||
|
tt_str_op(buf, OP_EQ, "B");
|
||||||
|
tt_mem_op(buf, OP_EQ, "B\0\xff\xff", sizeof(buf));
|
||||||
|
errno = 0;
|
||||||
|
|
||||||
|
/* Send in a line and close */
|
||||||
|
retlen = write(test_pipe[1], "AB", 2);
|
||||||
tt_int_op(retlen, OP_EQ, 2);
|
tt_int_op(retlen, OP_EQ, 2);
|
||||||
retval = close(test_pipe[1]);
|
retval = close(test_pipe[1]);
|
||||||
tt_int_op(retval, OP_EQ, 0);
|
tt_int_op(retval, OP_EQ, 0);
|
||||||
test_pipe[1] = -1;
|
test_pipe[1] = -1;
|
||||||
retptr = tor_fgets(buf, sizeof(buf), test_stream);
|
|
||||||
|
status = get_string_from_pipe(test_pipe[0], buf, sizeof(buf)-1);
|
||||||
tt_int_op(errno, OP_EQ, 0);
|
tt_int_op(errno, OP_EQ, 0);
|
||||||
tt_ptr_op(retptr, OP_EQ, buf);
|
tt_int_op(status, OP_EQ, IO_STREAM_OKAY);
|
||||||
tt_str_op(buf, OP_EQ, "GH");
|
tt_str_op(buf, OP_EQ, "AB");
|
||||||
errno = 0;
|
errno = 0;
|
||||||
|
|
||||||
/* Check for EOF */
|
/* Check for EOF */
|
||||||
retptr = tor_fgets(buf, sizeof(buf), test_stream);
|
status = get_string_from_pipe(test_pipe[0], buf, sizeof(buf)-1);
|
||||||
tt_int_op(errno, OP_EQ, 0);
|
tt_int_op(errno, OP_EQ, 0);
|
||||||
tt_ptr_op(retptr, OP_EQ, NULL);
|
tt_int_op(status, OP_EQ, IO_STREAM_CLOSED);
|
||||||
retval = feof(test_stream);
|
|
||||||
tt_int_op(retval, OP_NE, 0);
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
|
|
||||||
/* Check that buf is unchanged according to C99 and C11 */
|
|
||||||
tt_str_op(buf, OP_EQ, "GH");
|
|
||||||
memset(buf, '\0', sizeof(buf));
|
|
||||||
|
|
||||||
done:
|
done:
|
||||||
if (test_stream != NULL)
|
|
||||||
fclose(test_stream);
|
|
||||||
if (test_pipe[0] != -1)
|
if (test_pipe[0] != -1)
|
||||||
close(test_pipe[0]);
|
close(test_pipe[0]);
|
||||||
if (test_pipe[1] != -1)
|
if (test_pipe[1] != -1)
|
||||||
close(test_pipe[1]);
|
close(test_pipe[1]);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
#endif // _WIN32
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test for format_hex_number_sigsafe()
|
* Test for format_hex_number_sigsafe()
|
||||||
|
@ -5723,7 +5729,7 @@ struct testcase_t util_tests[] = {
|
||||||
UTIL_TEST(num_cpus, 0),
|
UTIL_TEST(num_cpus, 0),
|
||||||
UTIL_TEST_WIN_ONLY(load_win_lib, 0),
|
UTIL_TEST_WIN_ONLY(load_win_lib, 0),
|
||||||
UTIL_TEST_NO_WIN(exit_status, 0),
|
UTIL_TEST_NO_WIN(exit_status, 0),
|
||||||
UTIL_TEST_NO_WIN(fgets_eagain, 0),
|
UTIL_TEST_NO_WIN(string_from_pipe, 0),
|
||||||
UTIL_TEST(format_hex_number, 0),
|
UTIL_TEST(format_hex_number, 0),
|
||||||
UTIL_TEST(format_dec_number, 0),
|
UTIL_TEST(format_dec_number, 0),
|
||||||
UTIL_TEST(join_win_cmdline, 0),
|
UTIL_TEST(join_win_cmdline, 0),
|
||||||
|
|
|
@ -242,7 +242,7 @@ test_util_spawn_background_partial_read_impl(int exit_early)
|
||||||
#else
|
#else
|
||||||
/* Check that we didn't read the end of file last time */
|
/* Check that we didn't read the end of file last time */
|
||||||
tt_assert(!eof);
|
tt_assert(!eof);
|
||||||
pos = tor_read_all_handle(process_handle->stdout_handle, stdout_buf,
|
pos = tor_read_all_handle(process_handle->stdout_pipe, stdout_buf,
|
||||||
sizeof(stdout_buf) - 1, NULL, &eof);
|
sizeof(stdout_buf) - 1, NULL, &eof);
|
||||||
#endif
|
#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);
|
||||||
|
@ -273,7 +273,7 @@ test_util_spawn_background_partial_read_impl(int exit_early)
|
||||||
#else
|
#else
|
||||||
if (!eof) {
|
if (!eof) {
|
||||||
/* We should have got all the data, but maybe not the EOF flag */
|
/* We should have got all the data, but maybe not the EOF flag */
|
||||||
pos = tor_read_all_handle(process_handle->stdout_handle, stdout_buf,
|
pos = tor_read_all_handle(process_handle->stdout_pipe, stdout_buf,
|
||||||
sizeof(stdout_buf) - 1,
|
sizeof(stdout_buf) - 1,
|
||||||
process_handle, &eof);
|
process_handle, &eof);
|
||||||
tt_int_op(0,OP_EQ, pos);
|
tt_int_op(0,OP_EQ, pos);
|
||||||
|
|
Loading…
Add table
Reference in a new issue