diff options
Diffstat (limited to 'osi')
-rw-r--r-- | osi/src/config.c | 91 | ||||
-rw-r--r-- | osi/src/eager_reader.c | 4 | ||||
-rw-r--r-- | osi/src/reactor.c | 2 | ||||
-rw-r--r-- | osi/src/semaphore.c | 6 | ||||
-rw-r--r-- | osi/src/socket.c | 10 | ||||
-rw-r--r-- | osi/test/alarm_test.cpp | 2 | ||||
-rw-r--r-- | osi/test/atomic_test.cpp | 6 | ||||
-rw-r--r-- | osi/test/eager_reader_test.cpp | 4 | ||||
-rw-r--r-- | osi/test/reactor_test.cpp | 4 |
9 files changed, 95 insertions, 34 deletions
diff --git a/osi/src/config.c b/osi/src/config.c index b342a2e9b..63a43f810 100644 --- a/osi/src/config.c +++ b/osi/src/config.c @@ -21,11 +21,13 @@ #include <assert.h> #include <ctype.h> #include <errno.h> +#include <fcntl.h> +#include <libgen.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/stat.h> -#include <fcntl.h> +#include <sys/types.h> #include "osi/include/allocator.h" #include "osi/include/config.h" @@ -282,16 +284,39 @@ bool config_save(const config_t *config, const char *filename) { assert(filename != NULL); assert(*filename != '\0'); - char *temp_filename = osi_calloc(strlen(filename) + 5); - if (!temp_filename) { - LOG_ERROR("%s unable to allocate memory for filename.", __func__); - return false; + // Steps to ensure content of config file gets to disk: + // + // 1) Open and write to temp file (e.g. bt_config.conf.new). + // 2) Sync the temp file to disk with fsync(). + // 3) Rename temp file to actual config file (e.g. bt_config.conf). + // This ensures atomic update. + // 4) Sync directory that has the conf file with fsync(). + // This ensures directory entries are up-to-date. + int dir_fd = -1; + FILE *fp = NULL; + + // Build temp config file based on config file (e.g. bt_config.conf.new). + static const char *temp_file_ext = ".new"; + const int filename_len = strlen(filename); + const int temp_filename_len = filename_len + strlen(temp_file_ext) + 1; + char *temp_filename = osi_calloc(temp_filename_len); + snprintf(temp_filename, temp_filename_len, "%s%s", filename, temp_file_ext); + + // Extract directory from file path (e.g. /data/misc/bluedroid). + char *temp_dirname = osi_strdup(filename); + const char *directoryname = dirname(temp_dirname); + if (!directoryname) { + LOG_ERROR("%s error extracting directory from '%s': %s", __func__, filename, strerror(errno)); + goto error; } - strcpy(temp_filename, filename); - strcat(temp_filename, ".new"); + dir_fd = TEMP_FAILURE_RETRY(open(directoryname, O_RDONLY)); + if (dir_fd < 0) { + LOG_ERROR("%s unable to open dir '%s': %s", __func__, directoryname, strerror(errno)); + goto error; + } - FILE *fp = fopen(temp_filename, "wt"); + fp = fopen(temp_filename, "wt"); if (!fp) { LOG_ERROR("%s unable to write file '%s': %s", __func__, temp_filename, strerror(errno)); goto error; @@ -299,20 +324,38 @@ bool config_save(const config_t *config, const char *filename) { for (const list_node_t *node = list_begin(config->sections); node != list_end(config->sections); node = list_next(node)) { const section_t *section = (const section_t *)list_node(node); - fprintf(fp, "[%s]\n", section->name); + if (fprintf(fp, "[%s]\n", section->name) < 0) { + LOG_ERROR("%s unable to write to file '%s': %s", __func__, temp_filename, strerror(errno)); + goto error; + } for (const list_node_t *enode = list_begin(section->entries); enode != list_end(section->entries); enode = list_next(enode)) { const entry_t *entry = (const entry_t *)list_node(enode); - fprintf(fp, "%s = %s\n", entry->key, entry->value); + if (fprintf(fp, "%s = %s\n", entry->key, entry->value) < 0) { + LOG_ERROR("%s unable to write to file '%s': %s", __func__, temp_filename, strerror(errno)); + goto error; + } } // Only add a separating newline if there are more sections. - if (list_next(node) != list_end(config->sections)) - fputc('\n', fp); + if (list_next(node) != list_end(config->sections)) { + if (fputc('\n', fp) == EOF) { + LOG_ERROR("%s unable to write to file '%s': %s", __func__, temp_filename, strerror(errno)); + goto error; + } + } } - fflush(fp); - fclose(fp); + // Sync written temp file out to disk. fsync() is blocking until data makes it to disk. + if (fsync(fileno(fp)) < 0) { + LOG_WARN("%s unable to fsync file '%s': %s", __func__, temp_filename, strerror(errno)); + } + + if (fclose(fp) == EOF) { + LOG_ERROR("%s unable to close file '%s': %s", __func__, temp_filename, strerror(errno)); + goto error; + } + fp = NULL; // Change the file's permissions to Read/Write by User and Group if (chmod(temp_filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP) == -1) { @@ -320,17 +363,35 @@ bool config_save(const config_t *config, const char *filename) { goto error; } + // Rename written temp file to the actual config file. if (rename(temp_filename, filename) == -1) { LOG_ERROR("%s unable to commit file '%s': %s", __func__, filename, strerror(errno)); goto error; } + // This should ensure the directory is updated as well. + if (fsync(dir_fd) < 0) { + LOG_WARN("%s unable to fsync dir '%s': %s", __func__, directoryname, strerror(errno)); + } + + if (close(dir_fd) < 0) { + LOG_ERROR("%s unable to close dir '%s': %s", __func__, directoryname, strerror(errno)); + goto error; + } + osi_free(temp_filename); + osi_free(temp_dirname); return true; -error:; +error: + // This indicates there is a write issue. Unlink as partial data is not acceptable. unlink(temp_filename); + if (fp) + fclose(fp); + if (dir_fd != -1) + close(dir_fd); osi_free(temp_filename); + osi_free(temp_dirname); return false; } diff --git a/osi/src/eager_reader.c b/osi/src/eager_reader.c index 3ca8ad13c..e93947d51 100644 --- a/osi/src/eager_reader.c +++ b/osi/src/eager_reader.c @@ -228,7 +228,7 @@ static bool has_byte(const eager_reader_t *reader) { timeout.tv_sec = 0; timeout.tv_usec = 0; - select(reader->bytes_available_fd + 1, &read_fds, NULL, NULL, &timeout); + TEMP_FAILURE_RETRY(select(reader->bytes_available_fd + 1, &read_fds, NULL, NULL, &timeout)); return FD_ISSET(reader->bytes_available_fd, &read_fds); } @@ -244,7 +244,7 @@ static void inbound_data_waiting(void *context) { buffer->length = 0; buffer->offset = 0; - int bytes_read = read(reader->inbound_fd, buffer->data, reader->buffer_size); + int bytes_read = TEMP_FAILURE_RETRY(read(reader->inbound_fd, buffer->data, reader->buffer_size)); if (bytes_read > 0) { // Save the data for later buffer->length = bytes_read; diff --git a/osi/src/reactor.c b/osi/src/reactor.c index c3d54c111..1650c1d7b 100644 --- a/osi/src/reactor.c +++ b/osi/src/reactor.c @@ -259,7 +259,7 @@ static reactor_status_t run_reactor(reactor_t *reactor, int iterations) { int ret; do { - ret = epoll_wait(reactor->epoll_fd, events, MAX_EVENTS, -1); + ret = TEMP_FAILURE_RETRY(epoll_wait(reactor->epoll_fd, events, MAX_EVENTS, -1)); } while (ret == -1 && errno == EINTR); if (ret == -1) { diff --git a/osi/src/semaphore.c b/osi/src/semaphore.c index 5ee992649..76fba0d55 100644 --- a/osi/src/semaphore.c +++ b/osi/src/semaphore.c @@ -73,12 +73,12 @@ bool semaphore_try_wait(semaphore_t *semaphore) { assert(semaphore != NULL); assert(semaphore->fd != INVALID_FD); - int flags = fcntl(semaphore->fd, F_GETFL); + int flags = TEMP_FAILURE_RETRY(fcntl(semaphore->fd, F_GETFL)); if (flags == -1) { LOG_ERROR("%s unable to get flags for semaphore fd: %s", __func__, strerror(errno)); return false; } - if (fcntl(semaphore->fd, F_SETFL, flags | O_NONBLOCK) == -1) { + if (TEMP_FAILURE_RETRY(fcntl(semaphore->fd, F_SETFL, flags | O_NONBLOCK)) == -1) { LOG_ERROR("%s unable to set O_NONBLOCK for semaphore fd: %s", __func__, strerror(errno)); return false; } @@ -87,7 +87,7 @@ bool semaphore_try_wait(semaphore_t *semaphore) { if (eventfd_read(semaphore->fd, &value) == -1) return false; - if (fcntl(semaphore->fd, F_SETFL, flags) == -1) + if (TEMP_FAILURE_RETRY(fcntl(semaphore->fd, F_SETFL, flags)) == -1) LOG_ERROR("%s unable to resetore flags for semaphore fd: %s", __func__, strerror(errno)); return true; } diff --git a/osi/src/socket.c b/osi/src/socket.c index 91f084e79..9905ae300 100644 --- a/osi/src/socket.c +++ b/osi/src/socket.c @@ -121,7 +121,7 @@ bool socket_listen(const socket_t *socket, port_t port) { socket_t *socket_accept(const socket_t *socket) { assert(socket != NULL); - int fd = accept(socket->fd, NULL, NULL); + int fd = TEMP_FAILURE_RETRY(accept(socket->fd, NULL, NULL)); if (fd == INVALID_FD) { LOG_ERROR("%s unable to accept socket: %s", __func__, strerror(errno)); return NULL; @@ -142,14 +142,14 @@ ssize_t socket_read(const socket_t *socket, void *buf, size_t count) { assert(socket != NULL); assert(buf != NULL); - return recv(socket->fd, buf, count, MSG_DONTWAIT); + return TEMP_FAILURE_RETRY(recv(socket->fd, buf, count, MSG_DONTWAIT)); } ssize_t socket_write(const socket_t *socket, const void *buf, size_t count) { assert(socket != NULL); assert(buf != NULL); - return send(socket->fd, buf, count, MSG_DONTWAIT); + return TEMP_FAILURE_RETRY(send(socket->fd, buf, count, MSG_DONTWAIT)); } ssize_t socket_write_and_transfer_fd(const socket_t *socket, const void *buf, size_t count, int fd) { @@ -179,7 +179,7 @@ ssize_t socket_write_and_transfer_fd(const socket_t *socket, const void *buf, si header->cmsg_len = CMSG_LEN(sizeof(int)); *(int *)CMSG_DATA(header) = fd; - ssize_t ret = sendmsg(socket->fd, &msg, MSG_DONTWAIT); + ssize_t ret = TEMP_FAILURE_RETRY(sendmsg(socket->fd, &msg, MSG_DONTWAIT)); close(fd); return ret; } @@ -188,7 +188,7 @@ ssize_t socket_bytes_available(const socket_t *socket) { assert(socket != NULL); int size = 0; - if (ioctl(socket->fd, FIONREAD, &size) == -1) + if (TEMP_FAILURE_RETRY(ioctl(socket->fd, FIONREAD, &size)) == -1) return -1; return size; } diff --git a/osi/test/alarm_test.cpp b/osi/test/alarm_test.cpp index 287d40812..fec828f90 100644 --- a/osi/test/alarm_test.cpp +++ b/osi/test/alarm_test.cpp @@ -32,7 +32,7 @@ static int cb_counter; static const uint64_t EPSILON_MS = 5; static void msleep(uint64_t ms) { - usleep(ms * 1000); + TEMP_FAILURE_RETRY(usleep(ms * 1000)); } class AlarmTest : public AlarmTestHarness { diff --git a/osi/test/atomic_test.cpp b/osi/test/atomic_test.cpp index b0039ab3f..6cde546e5 100644 --- a/osi/test/atomic_test.cpp +++ b/osi/test/atomic_test.cpp @@ -17,7 +17,7 @@ struct atomic_test_s32_s { void *atomic_thread(void *context) { struct atomic_test_s32_s *at = (struct atomic_test_s32_s *)context; for (int i = 0; i < at->max_val; i++) { - usleep(1); + TEMP_FAILURE_RETRY(usleep(1)); atomic_inc_prefix_s32(&at->data[i]); } return NULL; @@ -26,9 +26,9 @@ void *atomic_thread(void *context) { void *atomic_thread_inc_dec(void *context) { struct atomic_test_s32_s *at = (struct atomic_test_s32_s *)context; for (int i = 0; i < at->max_val; i++) { - usleep(1); + TEMP_FAILURE_RETRY(usleep(1)); atomic_inc_prefix_s32(&at->data[i]); - usleep(1); + TEMP_FAILURE_RETRY(usleep(1)); atomic_dec_prefix_s32(&at->data[i]); } return NULL; diff --git a/osi/test/eager_reader_test.cpp b/osi/test/eager_reader_test.cpp index ad00e17b0..d979f42a6 100644 --- a/osi/test/eager_reader_test.cpp +++ b/osi/test/eager_reader_test.cpp @@ -126,7 +126,7 @@ TEST_F(EagerReaderTest, test_small_data) { thread_t *read_thread = thread_new("read_thread"); eager_reader_register(reader, thread_get_reactor(read_thread), expect_data, (void *)small_data); - write(pipefd[1], small_data, strlen(small_data)); + TEMP_FAILURE_RETRY(write(pipefd[1], small_data, strlen(small_data))); semaphore_wait(done); eager_reader_free(reader); @@ -139,7 +139,7 @@ TEST_F(EagerReaderTest, test_large_data_multibyte) { thread_t *read_thread = thread_new("read_thread"); eager_reader_register(reader, thread_get_reactor(read_thread), expect_data_multibyte, (void *)large_data); - write(pipefd[1], large_data, strlen(large_data)); + TEMP_FAILURE_RETRY(write(pipefd[1], large_data, strlen(large_data))); semaphore_wait(done); eager_reader_free(reader); diff --git a/osi/test/reactor_test.cpp b/osi/test/reactor_test.cpp index 6e3a0092a..73a6ae07b 100644 --- a/osi/test/reactor_test.cpp +++ b/osi/test/reactor_test.cpp @@ -64,7 +64,7 @@ TEST_F(ReactorTest, reactor_start_wait_stop) { reactor_t *reactor = reactor_new(); spawn_reactor_thread(reactor); - usleep(50 * 1000); + TEMP_FAILURE_RETRY(usleep(50 * 1000)); EXPECT_TRUE(thread_running); reactor_stop(reactor); @@ -108,7 +108,7 @@ TEST_F(ReactorTest, reactor_unregister_from_separate_thread) { reactor_object_t *object = reactor_register(reactor, fd, NULL, NULL, NULL); spawn_reactor_thread(reactor); - usleep(50 * 1000); + TEMP_FAILURE_RETRY(usleep(50 * 1000)); reactor_unregister(object); reactor_stop(reactor); |