diff options
Diffstat (limited to 'osi/src')
-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 |
5 files changed, 87 insertions, 26 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; } |