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