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