1 #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 #define BY_PARTLABEL_PATH "/dev/disk/by-partlabel"
15
16 #define MIN(x, y) ((x) < (y) ? (x) : (y))
17
18 struct partition {
19 const char *path;
20 const char *actual;
21 const char *partlabel;
22 };
23
24 struct 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
35 static const char *storage_dir = "/boot";
36 static int storage_read_only;
37 static int storage_use_partitions;
38
39 static 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
47 static struct rmtfd rmtfds[MAX_CALLERS];
48
49 static int storage_populate_shadow_buf(struct rmtfd *rmtfd, const char *file);
50
storage_init(const char * storage_root,bool read_only,bool use_partitions)51 int 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) {
59 if (!storage_root)
60 storage_dir = BY_PARTLABEL_PATH;
61 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
storage_open(unsigned node,const char * path)75 struct 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
95 found:
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
storage_close(struct rmtfd * rmtfd)151 void 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
storage_get(unsigned node,int caller_id)163 struct 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
storage_get_caller_id(const struct rmtfd * rmtfd)177 int storage_get_caller_id(const struct rmtfd *rmtfd)
178 {
179 return rmtfd->id;
180 }
181
storage_get_error(const struct rmtfd * rmtfd)182 int storage_get_error(const struct rmtfd *rmtfd)
183 {
184 return rmtfd->dev_error;
185 }
186
storage_exit(void)187 void 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
storage_pread(const struct rmtfd * rmtfd,void * buf,size_t nbyte,off_t offset)197 ssize_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, (char*)rmtfd->shadow_buf + offset, n);
207 else
208 n = 0;
209 }
210
211 if (n < nbyte)
212 memset((char*)buf + n, 0, nbyte - n);
213
214 return nbyte;
215 }
216
storage_pwrite(struct rmtfd * rmtfd,const void * buf,size_t nbyte,off_t offset)217 ssize_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((char*)rmtfd->shadow_buf + offset, buf, nbyte);
243
244 return nbyte;
245 }
246
storage_populate_shadow_buf(struct rmtfd * rmtfd,const char * file)247 static 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
284 err_close_fd:
285 close(fd);
286
287 return ret;
288 }
289