blob: d31f7572de584e3a64b1589c781dccb0938f228a [file] [log] [blame]
Amit Pundird477f822020-02-07 22:26:08 +05301#include <sys/stat.h>
2#include <sys/types.h>
3#include <errno.h>
4#include <fcntl.h>
5#include <stdio.h>
6#include <stdlib.h>
7#include <string.h>
8#include <unistd.h>
9#include "rmtfs.h"
10
11#define MAX_CALLERS 10
12#define STORAGE_MAX_SIZE (16 * 1024 * 1024)
13
14#ifndef ANDROID
15#define BY_PARTLABEL_PATH "/dev/disk/by-partlabel"
16#else
17#define BY_PARTLABEL_PATH "/dev/block/by-name"
18#endif
19
20#define MIN(x, y) ((x) < (y) ? (x) : (y))
21
22struct partition {
23 const char *path;
24 const char *actual;
25 const char *partlabel;
26};
27
28struct rmtfd {
29 unsigned id;
30 unsigned node;
31 int fd;
32 unsigned dev_error;
33 const struct partition *partition;
34
35 void *shadow_buf;
36 size_t shadow_len;
37};
38
39static const char *storage_dir = "/boot";
40static int storage_read_only;
41static int storage_use_partitions;
42
43static const struct partition partition_table[] = {
44 { "/boot/modem_fs1", "modem_fs1", "modemst1" },
45 { "/boot/modem_fs2", "modem_fs2", "modemst2" },
46 { "/boot/modem_fsc", "modem_fsc", "fsc" },
47 { "/boot/modem_fsg", "modem_fsg", "fsg" },
48 {}
49};
50
51static struct rmtfd rmtfds[MAX_CALLERS];
52
53static int storage_populate_shadow_buf(struct rmtfd *rmtfd, const char *file);
54
55int storage_init(const char *storage_root, bool read_only, bool use_partitions)
56{
57 int i;
58
59 if (storage_root)
60 storage_dir = storage_root;
61
62 if (use_partitions) {
63 storage_dir = BY_PARTLABEL_PATH;
64 storage_use_partitions = true;
65 }
66
67 storage_read_only = read_only;
68
69 for (i = 0; i < MAX_CALLERS; i++) {
70 rmtfds[i].id = i;
71 rmtfds[i].fd = -1;
72 rmtfds[i].shadow_buf = NULL;
73 }
74
75 return 0;
76}
77
78struct rmtfd *storage_open(unsigned node, const char *path)
79{
80 char *fspath;
81 const struct partition *part;
82 struct rmtfd *rmtfd = NULL;
83 const char *file;
84 size_t pathlen;
85 int saved_errno;
86 int ret;
87 int fd;
88 int i;
89
90 for (part = partition_table; part->path; part++) {
91 if (strcmp(part->path, path) == 0)
92 goto found;
93 }
94
95 fprintf(stderr, "[RMTFS storage] request for unknown partition '%s', rejecting\n", path);
96 return NULL;
97
98found:
99 /* Check if this node already has the requested path open */
100 for (i = 0; i < MAX_CALLERS; i++) {
101 if ((rmtfds[i].fd != -1 || rmtfds[i].shadow_buf) &&
102 rmtfds[i].node == node &&
103 rmtfds[i].partition == part)
104 return &rmtfds[i];
105 }
106
107 for (i = 0; i < MAX_CALLERS; i++) {
108 if (rmtfds[i].fd == -1 && !rmtfds[i].shadow_buf) {
109 rmtfd = &rmtfds[i];
110 break;
111 }
112 }
113 if (!rmtfd) {
114 fprintf(stderr, "[storage] out of free rmtfd handles\n");
115 return NULL;
116 }
117
118 if (storage_use_partitions)
119 file = part->partlabel;
120 else
121 file = part->actual;
122
123 pathlen = strlen(storage_dir) + strlen(file) + 2;
124 fspath = alloca(pathlen);
125 snprintf(fspath, pathlen, "%s/%s", storage_dir, file);
126 if (!storage_read_only) {
127 fd = open(fspath, O_RDWR);
128 if (fd < 0) {
129 saved_errno = errno;
130 fprintf(stderr, "[storage] failed to open '%s' (requested '%s'): %s\n",
131 fspath, part->path, strerror(saved_errno));
132 errno = saved_errno;
133 return NULL;
134 }
135 rmtfd->fd = fd;
136 rmtfd->shadow_len = 0;
137 } else {
138 ret = storage_populate_shadow_buf(rmtfd, fspath);
139 if (ret < 0) {
140 saved_errno = errno;
141 fprintf(stderr, "[storage] failed to open '%s' (requested '%s'): %s\n",
142 fspath, part->path, strerror(saved_errno));
143 errno = saved_errno;
144 return NULL;
145 }
146 }
147
148 rmtfd->node = node;
149 rmtfd->partition = part;
150
151 return rmtfd;
152}
153
154void storage_close(struct rmtfd *rmtfd)
155{
156 close(rmtfd->fd);
157 rmtfd->fd = -1;
158
159 free(rmtfd->shadow_buf);
160 rmtfd->shadow_buf = NULL;
161 rmtfd->shadow_len = 0;
162
163 rmtfd->partition = NULL;
164}
165
166struct rmtfd *storage_get(unsigned node, int caller_id)
167{
168 struct rmtfd *rmtfd;
169
170 if (caller_id >= MAX_CALLERS)
171 return NULL;
172
173 rmtfd = &rmtfds[caller_id];
174 if (rmtfd->node != node)
175 return NULL;
176
177 return rmtfd;
178}
179
180int storage_get_caller_id(const struct rmtfd *rmtfd)
181{
182 return rmtfd->id;
183}
184
185int storage_get_error(const struct rmtfd *rmtfd)
186{
187 return rmtfd->dev_error;
188}
189
190void storage_exit(void)
191{
192 int i;
193
194 for (i = 0; i < MAX_CALLERS; i++) {
195 if (rmtfds[i].fd >= 0)
196 close(rmtfds[i].fd);
197 }
198}
199
200ssize_t storage_pread(const struct rmtfd *rmtfd, void *buf, size_t nbyte, off_t offset)
201{
202 ssize_t n;
203
204 if (!storage_read_only) {
205 n = pread(rmtfd->fd, buf, nbyte, offset);
206 } else {
207 n = MIN(nbyte, rmtfd->shadow_len - offset);
208 if (n > 0)
209 memcpy(buf, rmtfd->shadow_buf + offset, n);
210 else
211 n = 0;
212 }
213
214 if (n < nbyte)
215 memset(buf + n, 0, nbyte - n);
216
217 return nbyte;
218}
219
220ssize_t storage_pwrite(struct rmtfd *rmtfd, const void *buf, size_t nbyte, off_t offset)
221{
222 size_t new_len = offset + nbyte;
223 void *new_buf;
224
225 if (!storage_read_only)
226 return pwrite(rmtfd->fd, buf, nbyte, offset);
227
228 if (new_len >= STORAGE_MAX_SIZE) {
229 fprintf(stderr, "write to %zd bytes exceededs max size\n", new_len);
230 errno = -EINVAL;
231 return -1;
232 }
233
234 if (new_len > rmtfd->shadow_len) {
235 new_buf = realloc(rmtfd->shadow_buf, new_len);
236 if (!new_buf) {
237 errno = -ENOMEM;
238 return -1;
239 }
240
241 rmtfd->shadow_buf = new_buf;
242 rmtfd->shadow_len = new_len;
243 }
244
245 memcpy(rmtfd->shadow_buf + offset, buf, nbyte);
246
247 return nbyte;
248}
249
250static int storage_populate_shadow_buf(struct rmtfd *rmtfd, const char *file)
251{
252 ssize_t len;
253 ssize_t n;
254 void *buf;
255 int ret;
256 int fd;
257
258 fd = open(file, O_RDONLY);
259 if (fd < 0)
260 return -1;
261
262 len = lseek(fd, 0, SEEK_END);
263 if (len < 0) {
264 ret = -1;
265 goto err_close_fd;
266 }
267
268 lseek(fd, 0, SEEK_SET);
269
270 buf = calloc(1, len);
271 if (!buf) {
272 ret = -1;
273 goto err_close_fd;
274 }
275
276 n = read(fd, buf, len);
277 if (n < 0) {
278 ret = -1;
279 goto err_close_fd;
280 }
281
282 rmtfd->shadow_buf = buf;
283 rmtfd->shadow_len = n;
284
285 ret = 0;
286
287err_close_fd:
288 close(fd);
289
290 return ret;
291}