Loading changes/bug20988deleted 100644 → 0 +0 −4 Original line number Diff line number Diff line 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. changes/bug21654 0 → 100644 +4 −0 Original line number Diff line number Diff line 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. src/common/compat.c +0 −39 Original line number Diff line number Diff line Loading @@ -3476,45 +3476,6 @@ tor_getpass(const char *prompt, char *output, size_t buflen) #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 * bytes. Return -1 if the amount of free space can't be determined. */ int64_t Loading src/common/compat.h +0 −2 Original line number Diff line number Diff line Loading @@ -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); char *tor_fgets(char *str, int size, FILE *stream); /* This needs some of the declarations above so we include it here. */ #include "compat_threads.h" Loading src/common/util.c +53 −93 Original line number Diff line number Diff line Loading @@ -2118,7 +2118,7 @@ read_all(tor_socket_t fd, char *buf, size_t count, int isSocket) return -1; } while (numread != count) { while (numread < count) { if (isSocket) result = tor_socket_recv(fd, buf+numread, count-numread, 0); else Loading Loading @@ -4175,10 +4175,10 @@ tor_process_get_stdout_pipe(process_handle_t *process_handle) } #else /* DOCDOC tor_process_get_stdout_pipe */ FILE * int tor_process_get_stdout_pipe(process_handle_t *process_handle) { return process_handle->stdout_handle; return process_handle->stdout_pipe; } #endif Loading Loading @@ -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 " "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; Loading Loading @@ -4659,14 +4655,9 @@ tor_process_handle_destroy,(process_handle_t *process_handle, if (process_handle->stdin_pipe) CloseHandle(process_handle->stdin_pipe); #else if (process_handle->stdout_handle) fclose(process_handle->stdout_handle); if (process_handle->stderr_handle) fclose(process_handle->stderr_handle); if (process_handle->stdin_handle) fclose(process_handle->stdin_handle); close(process_handle->stdout_pipe); close(process_handle->stderr_pipe); close(process_handle->stdin_pipe); clear_waitpid_callback(process_handle->waitpid_cb); #endif Loading Loading @@ -4952,7 +4943,7 @@ tor_read_all_handle(HANDLE h, char *buf, size_t count, if (count > SIZE_T_CEILING || count > SSIZE_MAX) return -1; while (numread != count) { while (numread < count) { /* Check if there is anything to read */ retval = PeekNamedPipe(h, NULL, 0, NULL, &byte_count, NULL); if (!retval) { Loading Loading @@ -4998,19 +4989,19 @@ tor_read_all_handle(HANDLE h, char *buf, size_t count, return (ssize_t)numread; } #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 * 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. Sets <b>eof</b> to true if <b>eof</b> is not NULL and the end of the * file has been reached. */ 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, int *eof) { size_t numread = 0; char *retval; ssize_t result; if (eof) *eof = 0; Loading @@ -5018,34 +5009,28 @@ tor_read_all_handle(FILE *h, char *buf, size_t count, if (count > SIZE_T_CEILING || count > SSIZE_MAX) return -1; while (numread != count) { /* Use fgets because that is what we use in log_from_pipe() */ retval = tor_fgets(buf+numread, (int)(count-numread), h); if (NULL == retval) { if (feof(h)) { log_debug(LD_GENERAL, "fgets() reached end of file"); while (numread < count) { result = read(fd, buf+numread, count-numread); if (result == 0) { log_debug(LD_GENERAL, "read() reached end of file"); if (eof) *eof = 1; break; } else { if (EAGAIN == errno) { } else if (result < 0 && errno == EAGAIN) { if (process) continue; else break; } else { log_warn(LD_GENERAL, "fgets() from handle failed: %s", strerror(errno)); } else if (result < 0) { log_warn(LD_GENERAL, "read() failed: %s", strerror(errno)); return -1; } } } tor_assert(retval != NULL); tor_assert(strlen(retval) + numread <= count); numread += strlen(retval); numread += result; } 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; } #endif Loading @@ -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, process_handle); #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); #endif } Loading @@ -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, process_handle); #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); #endif } Loading Loading @@ -5267,11 +5252,10 @@ log_from_handle(HANDLE *pipe, int severity) #else /** 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. */ MOCK_IMPL(smartlist_t *, tor_get_lines_from_handle, (FILE *handle, enum stream_status *stream_status_out)) tor_get_lines_from_handle, (int fd, enum stream_status *stream_status_out)) { enum stream_status stream_status; char stdout_buf[400]; Loading @@ -5280,7 +5264,7 @@ tor_get_lines_from_handle, (FILE *handle, while (1) { 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); if (stream_status != IO_STREAM_OKAY) goto done; Loading @@ -5294,20 +5278,20 @@ tor_get_lines_from_handle, (FILE *handle, 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 * 0 otherwise. Handles lines from tor-fw-helper and * tor_spawn_background() specially. */ 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) { char buf[256]; enum stream_status r; 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) { return 1; Loading @@ -5332,7 +5316,7 @@ log_from_pipe(FILE *stream, int severity, const char *executable, } #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. * If the string has a trailing newline, we strip it off. * Loading @@ -5348,54 +5332,30 @@ log_from_pipe(FILE *stream, int severity, const char *executable, * IO_STREAM_OKAY: If everything went okay and we got a string * in <b>buf_out</b>. */ 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; size_t len; ssize_t ret; tor_assert(count <= INT_MAX); retval = tor_fgets(buf_out, (int)count, stream); ret = read(fd, buf_out, count); if (!retval) { if (feof(stream)) { /* Program has closed stream (probably it exited) */ /* TODO: check error */ if (ret == 0) return IO_STREAM_CLOSED; } else { if (EAGAIN == errno) { /* Nothing more to read, try again next time */ else if (ret < 0 && errno == EAGAIN) return IO_STREAM_EAGAIN; } else { /* There was a problem, abandon this child process */ else if (ret < 0) 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 */ buf_out[len - 1] = '\0'; } else { /* No newline; check whether we overflowed the buffer */ if (!feof(stream)) log_info(LD_GENERAL, "Line from stream was truncated: %s", buf_out); /* TODO: What to do with this error? */ } buf_out[ret - 1] = '\0'; } else buf_out[ret] = '\0'; 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 * log message to our user. */ static void Loading Loading @@ -5630,7 +5590,7 @@ tor_check_port_forwarding(const char *filename, #ifdef _WIN32 stderr_status = log_from_handle(child_handle->stderr_pipe, LOG_INFO); #else stderr_status = log_from_pipe(child_handle->stderr_handle, stderr_status = log_from_pipe(child_handle->stderr_pipe, LOG_INFO, filename, &retval); #endif if (handle_fw_helper_output(filename, child_handle) < 0) { Loading Loading
changes/bug20988deleted 100644 → 0 +0 −4 Original line number Diff line number Diff line 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.
changes/bug21654 0 → 100644 +4 −0 Original line number Diff line number Diff line 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.
src/common/compat.c +0 −39 Original line number Diff line number Diff line Loading @@ -3476,45 +3476,6 @@ tor_getpass(const char *prompt, char *output, size_t buflen) #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 * bytes. Return -1 if the amount of free space can't be determined. */ int64_t Loading
src/common/compat.h +0 −2 Original line number Diff line number Diff line Loading @@ -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); char *tor_fgets(char *str, int size, FILE *stream); /* This needs some of the declarations above so we include it here. */ #include "compat_threads.h" Loading
src/common/util.c +53 −93 Original line number Diff line number Diff line Loading @@ -2118,7 +2118,7 @@ read_all(tor_socket_t fd, char *buf, size_t count, int isSocket) return -1; } while (numread != count) { while (numread < count) { if (isSocket) result = tor_socket_recv(fd, buf+numread, count-numread, 0); else Loading Loading @@ -4175,10 +4175,10 @@ tor_process_get_stdout_pipe(process_handle_t *process_handle) } #else /* DOCDOC tor_process_get_stdout_pipe */ FILE * int tor_process_get_stdout_pipe(process_handle_t *process_handle) { return process_handle->stdout_handle; return process_handle->stdout_pipe; } #endif Loading Loading @@ -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 " "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; Loading Loading @@ -4659,14 +4655,9 @@ tor_process_handle_destroy,(process_handle_t *process_handle, if (process_handle->stdin_pipe) CloseHandle(process_handle->stdin_pipe); #else if (process_handle->stdout_handle) fclose(process_handle->stdout_handle); if (process_handle->stderr_handle) fclose(process_handle->stderr_handle); if (process_handle->stdin_handle) fclose(process_handle->stdin_handle); close(process_handle->stdout_pipe); close(process_handle->stderr_pipe); close(process_handle->stdin_pipe); clear_waitpid_callback(process_handle->waitpid_cb); #endif Loading Loading @@ -4952,7 +4943,7 @@ tor_read_all_handle(HANDLE h, char *buf, size_t count, if (count > SIZE_T_CEILING || count > SSIZE_MAX) return -1; while (numread != count) { while (numread < count) { /* Check if there is anything to read */ retval = PeekNamedPipe(h, NULL, 0, NULL, &byte_count, NULL); if (!retval) { Loading Loading @@ -4998,19 +4989,19 @@ tor_read_all_handle(HANDLE h, char *buf, size_t count, return (ssize_t)numread; } #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 * 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. Sets <b>eof</b> to true if <b>eof</b> is not NULL and the end of the * file has been reached. */ 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, int *eof) { size_t numread = 0; char *retval; ssize_t result; if (eof) *eof = 0; Loading @@ -5018,34 +5009,28 @@ tor_read_all_handle(FILE *h, char *buf, size_t count, if (count > SIZE_T_CEILING || count > SSIZE_MAX) return -1; while (numread != count) { /* Use fgets because that is what we use in log_from_pipe() */ retval = tor_fgets(buf+numread, (int)(count-numread), h); if (NULL == retval) { if (feof(h)) { log_debug(LD_GENERAL, "fgets() reached end of file"); while (numread < count) { result = read(fd, buf+numread, count-numread); if (result == 0) { log_debug(LD_GENERAL, "read() reached end of file"); if (eof) *eof = 1; break; } else { if (EAGAIN == errno) { } else if (result < 0 && errno == EAGAIN) { if (process) continue; else break; } else { log_warn(LD_GENERAL, "fgets() from handle failed: %s", strerror(errno)); } else if (result < 0) { log_warn(LD_GENERAL, "read() failed: %s", strerror(errno)); return -1; } } } tor_assert(retval != NULL); tor_assert(strlen(retval) + numread <= count); numread += strlen(retval); numread += result; } 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; } #endif Loading @@ -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, process_handle); #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); #endif } Loading @@ -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, process_handle); #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); #endif } Loading Loading @@ -5267,11 +5252,10 @@ log_from_handle(HANDLE *pipe, int severity) #else /** 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. */ MOCK_IMPL(smartlist_t *, tor_get_lines_from_handle, (FILE *handle, enum stream_status *stream_status_out)) tor_get_lines_from_handle, (int fd, enum stream_status *stream_status_out)) { enum stream_status stream_status; char stdout_buf[400]; Loading @@ -5280,7 +5264,7 @@ tor_get_lines_from_handle, (FILE *handle, while (1) { 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); if (stream_status != IO_STREAM_OKAY) goto done; Loading @@ -5294,20 +5278,20 @@ tor_get_lines_from_handle, (FILE *handle, 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 * 0 otherwise. Handles lines from tor-fw-helper and * tor_spawn_background() specially. */ 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) { char buf[256]; enum stream_status r; 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) { return 1; Loading @@ -5332,7 +5316,7 @@ log_from_pipe(FILE *stream, int severity, const char *executable, } #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. * If the string has a trailing newline, we strip it off. * Loading @@ -5348,54 +5332,30 @@ log_from_pipe(FILE *stream, int severity, const char *executable, * IO_STREAM_OKAY: If everything went okay and we got a string * in <b>buf_out</b>. */ 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; size_t len; ssize_t ret; tor_assert(count <= INT_MAX); retval = tor_fgets(buf_out, (int)count, stream); ret = read(fd, buf_out, count); if (!retval) { if (feof(stream)) { /* Program has closed stream (probably it exited) */ /* TODO: check error */ if (ret == 0) return IO_STREAM_CLOSED; } else { if (EAGAIN == errno) { /* Nothing more to read, try again next time */ else if (ret < 0 && errno == EAGAIN) return IO_STREAM_EAGAIN; } else { /* There was a problem, abandon this child process */ else if (ret < 0) 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 */ buf_out[len - 1] = '\0'; } else { /* No newline; check whether we overflowed the buffer */ if (!feof(stream)) log_info(LD_GENERAL, "Line from stream was truncated: %s", buf_out); /* TODO: What to do with this error? */ } buf_out[ret - 1] = '\0'; } else buf_out[ret] = '\0'; 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 * log message to our user. */ static void Loading Loading @@ -5630,7 +5590,7 @@ tor_check_port_forwarding(const char *filename, #ifdef _WIN32 stderr_status = log_from_handle(child_handle->stderr_pipe, LOG_INFO); #else stderr_status = log_from_pipe(child_handle->stderr_handle, stderr_status = log_from_pipe(child_handle->stderr_pipe, LOG_INFO, filename, &retval); #endif if (handle_fw_helper_output(filename, child_handle) < 0) { Loading