summaryrefslogtreecommitdiff
path: root/qcom/rmtfs/storage.c
diff options
context:
space:
mode:
Diffstat (limited to 'qcom/rmtfs/storage.c')
-rw-r--r--qcom/rmtfs/storage.c288
1 files changed, 288 insertions, 0 deletions
diff --git a/qcom/rmtfs/storage.c b/qcom/rmtfs/storage.c
new file mode 100644
index 0000000..c8e69ed
--- /dev/null
+++ b/qcom/rmtfs/storage.c
@@ -0,0 +1,288 @@
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "rmtfs.h"
+
+#define MAX_CALLERS 10
+#define STORAGE_MAX_SIZE (16 * 1024 * 1024)
+
+#define BY_PARTLABEL_PATH "/dev/disk/by-partlabel"
+
+#define MIN(x, y) ((x) < (y) ? (x) : (y))
+
+struct partition {
+ const char *path;
+ const char *actual;
+ const char *partlabel;
+};
+
+struct rmtfd {
+ unsigned id;
+ unsigned node;
+ int fd;
+ unsigned dev_error;
+ const struct partition *partition;
+
+ void *shadow_buf;
+ size_t shadow_len;
+};
+
+static const char *storage_dir = "/boot";
+static int storage_read_only;
+static int storage_use_partitions;
+
+static const struct partition partition_table[] = {
+ { "/boot/modem_fs1", "modem_fs1", "modemst1" },
+ { "/boot/modem_fs2", "modem_fs2", "modemst2" },
+ { "/boot/modem_fsc", "modem_fsc", "fsc" },
+ { "/boot/modem_fsg", "modem_fsg", "fsg" },
+ {}
+};
+
+static struct rmtfd rmtfds[MAX_CALLERS];
+
+static int storage_populate_shadow_buf(struct rmtfd *rmtfd, const char *file);
+
+int storage_init(const char *storage_root, bool read_only, bool use_partitions)
+{
+ int i;
+
+ if (storage_root)
+ storage_dir = storage_root;
+
+ if (use_partitions) {
+ if (!storage_root)
+ storage_dir = BY_PARTLABEL_PATH;
+ storage_use_partitions = true;
+ }
+
+ storage_read_only = read_only;
+
+ for (i = 0; i < MAX_CALLERS; i++) {
+ rmtfds[i].id = i;
+ rmtfds[i].fd = -1;
+ rmtfds[i].shadow_buf = NULL;
+ }
+
+ return 0;
+}
+
+struct rmtfd *storage_open(unsigned node, const char *path)
+{
+ char *fspath;
+ const struct partition *part;
+ struct rmtfd *rmtfd = NULL;
+ const char *file;
+ size_t pathlen;
+ int saved_errno;
+ int ret;
+ int fd;
+ int i;
+
+ for (part = partition_table; part->path; part++) {
+ if (strcmp(part->path, path) == 0)
+ goto found;
+ }
+
+ fprintf(stderr, "[RMTFS storage] request for unknown partition '%s', rejecting\n", path);
+ return NULL;
+
+found:
+ /* Check if this node already has the requested path open */
+ for (i = 0; i < MAX_CALLERS; i++) {
+ if ((rmtfds[i].fd != -1 || rmtfds[i].shadow_buf) &&
+ rmtfds[i].node == node &&
+ rmtfds[i].partition == part)
+ return &rmtfds[i];
+ }
+
+ for (i = 0; i < MAX_CALLERS; i++) {
+ if (rmtfds[i].fd == -1 && !rmtfds[i].shadow_buf) {
+ rmtfd = &rmtfds[i];
+ break;
+ }
+ }
+ if (!rmtfd) {
+ fprintf(stderr, "[storage] out of free rmtfd handles\n");
+ return NULL;
+ }
+
+ if (storage_use_partitions)
+ file = part->partlabel;
+ else
+ file = part->actual;
+
+ pathlen = strlen(storage_dir) + strlen(file) + 2;
+ fspath = alloca(pathlen);
+ snprintf(fspath, pathlen, "%s/%s", storage_dir, file);
+ if (!storage_read_only) {
+ fd = open(fspath, O_RDWR);
+ if (fd < 0) {
+ saved_errno = errno;
+ fprintf(stderr, "[storage] failed to open '%s' (requested '%s'): %s\n",
+ fspath, part->path, strerror(saved_errno));
+ errno = saved_errno;
+ return NULL;
+ }
+ rmtfd->fd = fd;
+ rmtfd->shadow_len = 0;
+ } else {
+ ret = storage_populate_shadow_buf(rmtfd, fspath);
+ if (ret < 0) {
+ saved_errno = errno;
+ fprintf(stderr, "[storage] failed to open '%s' (requested '%s'): %s\n",
+ fspath, part->path, strerror(saved_errno));
+ errno = saved_errno;
+ return NULL;
+ }
+ }
+
+ rmtfd->node = node;
+ rmtfd->partition = part;
+
+ return rmtfd;
+}
+
+void storage_close(struct rmtfd *rmtfd)
+{
+ close(rmtfd->fd);
+ rmtfd->fd = -1;
+
+ free(rmtfd->shadow_buf);
+ rmtfd->shadow_buf = NULL;
+ rmtfd->shadow_len = 0;
+
+ rmtfd->partition = NULL;
+}
+
+struct rmtfd *storage_get(unsigned node, int caller_id)
+{
+ struct rmtfd *rmtfd;
+
+ if (caller_id >= MAX_CALLERS)
+ return NULL;
+
+ rmtfd = &rmtfds[caller_id];
+ if (rmtfd->node != node)
+ return NULL;
+
+ return rmtfd;
+}
+
+int storage_get_caller_id(const struct rmtfd *rmtfd)
+{
+ return rmtfd->id;
+}
+
+int storage_get_error(const struct rmtfd *rmtfd)
+{
+ return rmtfd->dev_error;
+}
+
+void storage_exit(void)
+{
+ int i;
+
+ for (i = 0; i < MAX_CALLERS; i++) {
+ if (rmtfds[i].fd >= 0)
+ close(rmtfds[i].fd);
+ }
+}
+
+ssize_t storage_pread(const struct rmtfd *rmtfd, void *buf, size_t nbyte, off_t offset)
+{
+ ssize_t n;
+
+ if (!storage_read_only) {
+ n = pread(rmtfd->fd, buf, nbyte, offset);
+ } else {
+ n = MIN(nbyte, rmtfd->shadow_len - offset);
+ if (n > 0)
+ memcpy(buf, (char*)rmtfd->shadow_buf + offset, n);
+ else
+ n = 0;
+ }
+
+ if (n < nbyte)
+ memset((char*)buf + n, 0, nbyte - n);
+
+ return nbyte;
+}
+
+ssize_t storage_pwrite(struct rmtfd *rmtfd, const void *buf, size_t nbyte, off_t offset)
+{
+ size_t new_len = offset + nbyte;
+ void *new_buf;
+
+ if (!storage_read_only)
+ return pwrite(rmtfd->fd, buf, nbyte, offset);
+
+ if (new_len >= STORAGE_MAX_SIZE) {
+ fprintf(stderr, "write to %zd bytes exceededs max size\n", new_len);
+ errno = -EINVAL;
+ return -1;
+ }
+
+ if (new_len > rmtfd->shadow_len) {
+ new_buf = realloc(rmtfd->shadow_buf, new_len);
+ if (!new_buf) {
+ errno = -ENOMEM;
+ return -1;
+ }
+
+ rmtfd->shadow_buf = new_buf;
+ rmtfd->shadow_len = new_len;
+ }
+
+ memcpy((char*)rmtfd->shadow_buf + offset, buf, nbyte);
+
+ return nbyte;
+}
+
+static int storage_populate_shadow_buf(struct rmtfd *rmtfd, const char *file)
+{
+ ssize_t len;
+ ssize_t n;
+ void *buf;
+ int ret;
+ int fd;
+
+ fd = open(file, O_RDONLY);
+ if (fd < 0)
+ return -1;
+
+ len = lseek(fd, 0, SEEK_END);
+ if (len < 0) {
+ ret = -1;
+ goto err_close_fd;
+ }
+
+ lseek(fd, 0, SEEK_SET);
+
+ buf = calloc(1, len);
+ if (!buf) {
+ ret = -1;
+ goto err_close_fd;
+ }
+
+ n = read(fd, buf, len);
+ if (n < 0) {
+ ret = -1;
+ goto err_close_fd;
+ }
+
+ rmtfd->shadow_buf = buf;
+ rmtfd->shadow_len = n;
+
+ ret = 0;
+
+err_close_fd:
+ close(fd);
+
+ return ret;
+}