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