1 /* Copyright 2013-2014 IBM Corp.
2  *
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * 	http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12  * implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #define _GNU_SOURCE
17 #include <errno.h>
18 #include <inttypes.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <sys/ioctl.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <fcntl.h>
26 #include <unistd.h>
27 #include <limits.h>
28 
29 #include <ccan/container_of/container_of.h>
30 
31 #include <mtd/mtd-abi.h>
32 
33 #include "libflash.h"
34 #include "libflash/file.h"
35 #include "blocklevel.h"
36 
37 struct file_data {
38 	int fd;
39 	char *name;
40 	char *path;
41 	struct blocklevel_device bl;
42 };
43 
file_release(struct blocklevel_device * bl)44 static int file_release(struct blocklevel_device *bl)
45 {
46 	struct file_data *file_data = container_of(bl, struct file_data, bl);
47 	close(file_data->fd);
48 	file_data->fd = -1;
49 	return 0;
50 }
51 
file_reacquire(struct blocklevel_device * bl)52 static int file_reacquire(struct blocklevel_device *bl)
53 {
54 	struct file_data *file_data = container_of(bl, struct file_data, bl);
55 	int fd;
56 
57 	fd = open(file_data->path, O_RDWR);
58 	if (fd == -1)
59 		return FLASH_ERR_PARM_ERROR;
60 	file_data->fd = fd;
61 	return 0;
62 }
63 
file_read(struct blocklevel_device * bl,uint64_t pos,void * buf,uint64_t len)64 static int file_read(struct blocklevel_device *bl, uint64_t pos, void *buf, uint64_t len)
65 {
66 	struct file_data *file_data = container_of(bl, struct file_data, bl);
67 	int rc, count = 0;
68 
69 	rc = lseek(file_data->fd, pos, SEEK_SET);
70 	/* errno should remain set */
71 	if (rc != pos)
72 		return FLASH_ERR_PARM_ERROR;
73 
74 	while (count < len) {
75 		rc = read(file_data->fd, buf, len - count);
76 		/* errno should remain set */
77 		if (rc == -1 || rc == 0)
78 			return FLASH_ERR_BAD_READ;
79 
80 		buf += rc;
81 		count += rc;
82 	}
83 
84 	return 0;
85 }
86 
file_write(struct blocklevel_device * bl,uint64_t dst,const void * src,uint64_t len)87 static int file_write(struct blocklevel_device *bl, uint64_t dst, const void *src,
88 		uint64_t len)
89 {
90 	struct file_data *file_data = container_of(bl, struct file_data, bl);
91 	int rc, count = 0;
92 
93 	rc = lseek(file_data->fd, dst, SEEK_SET);
94 	/* errno should remain set */
95 	if (rc != dst)
96 		return FLASH_ERR_PARM_ERROR;
97 
98 	while (count < len) {
99 		rc = write(file_data->fd, src, len - count);
100 		/* errno should remain set */
101 		if (rc == -1)
102 			return FLASH_ERR_VERIFY_FAILURE;
103 
104 		src += rc;
105 		count += rc;
106 	}
107 
108 	return 0;
109 }
110 
111 /*
112  * Due to to the fact these interfaces are ultimately supposed to deal with
113  * flash, an erase function must be implemented even when the flash images
114  * are backed by regular files.
115  * Also, erasing flash leaves all the bits set to 1. This may be expected
116  * by higher level functions so this function should also emulate that
117  */
file_erase(struct blocklevel_device * bl,uint64_t dst,uint64_t len)118 static int file_erase(struct blocklevel_device *bl, uint64_t dst, uint64_t len)
119 {
120 	static char buf[4096];
121 	int i = 0;
122 	int rc;
123 
124 	memset(buf, ~0, sizeof(buf));
125 
126 	while (len - i > 0) {
127 		rc = file_write(bl, dst + i, buf, len - i > sizeof(buf) ? sizeof(buf) : len - i);
128 		if (rc)
129 			return rc;
130 		i += (len - i > sizeof(buf)) ? sizeof(buf) : len - i;
131 	}
132 
133 	return 0;
134 }
135 
mtd_erase(struct blocklevel_device * bl,uint64_t dst,uint64_t len)136 static int mtd_erase(struct blocklevel_device *bl, uint64_t dst, uint64_t len)
137 {
138 	struct file_data *file_data = container_of(bl, struct file_data, bl);
139 	int err;
140 
141 	FL_DBG("%s: dst: 0x%" PRIx64 ", len: 0x%" PRIx64 "\n", __func__, dst, len);
142 
143 	/*
144 	 * Some kernels that pflash supports do not know about the 64bit
145 	 * version of the ioctl() therefore we'll just use the 32bit (which
146 	 * should always be supported...) unless we MUST use the 64bit and
147 	 * then lets just hope the kernel knows how to deal with it. If it
148 	 * is unsupported the ioctl() will fail and we'll report that -
149 	 * there is no other option.
150 	 *
151 	 * Furthermore, even very recent MTD layers and drivers aren't
152 	 * particularly good at not blocking in the kernel. This creates
153 	 * unexpected behaviour in userspace tools using these functions.
154 	 * In the absence of significant work inside the kernel, we'll just
155 	 * split stuff up here for convenience.
156 	 * We can assume everything is aligned here.
157 	 */
158 	while (len) {
159 		if (dst > UINT_MAX || len > UINT_MAX) {
160 			struct erase_info_user64 erase_info = {
161 				.start = dst,
162 				.length = file_data->bl.erase_mask + 1
163 			};
164 
165 			if (ioctl(file_data->fd, MEMERASE64, &erase_info) == -1) {
166 				err = errno;
167 				if (err == 25) /* Kernel doesn't do 64bit MTD erase ioctl() */
168 					FL_DBG("Attempted a 64bit erase on a kernel which doesn't support it\n");
169 				FL_ERR("%s: IOCTL to kernel failed! %s\n", __func__, strerror(err));
170 				errno = err;
171 				return FLASH_ERR_PARM_ERROR;
172 			}
173 		} else {
174 			struct erase_info_user erase_info = {
175 				.start = dst,
176 				.length = file_data->bl.erase_mask + 1
177 			};
178 			if (ioctl(file_data->fd, MEMERASE, &erase_info) == -1) {
179 				err = errno;
180 				FL_ERR("%s: IOCTL to kernel failed! %s\n", __func__, strerror(err));
181 				errno = err;
182 				return FLASH_ERR_PARM_ERROR;
183 			}
184 		}
185 		dst += file_data->bl.erase_mask + 1;
186 		len -= file_data->bl.erase_mask + 1;
187 	}
188 	return 0;
189 }
190 
get_info_name(struct file_data * file_data,char ** name)191 static int get_info_name(struct file_data *file_data, char **name)
192 {
193 	char *path, *lpath;
194 	int len;
195 	struct stat st;
196 
197 	if (asprintf(&path, "/proc/self/fd/%d", file_data->fd) == -1)
198 		return FLASH_ERR_MALLOC_FAILED;
199 
200 	if (lstat(path, &st)) {
201 		free(path);
202 		return FLASH_ERR_PARM_ERROR;
203 	}
204 
205 	lpath = malloc(st.st_size + 1);
206 	if (!lpath) {
207 		free(path);
208 		return FLASH_ERR_MALLOC_FAILED;
209 	}
210 
211 	len = readlink(path, lpath, st.st_size +1);
212 	if (len == -1) {
213 		free(path);
214 		free(lpath);
215 		return FLASH_ERR_PARM_ERROR;
216 	}
217 	lpath[len] = '\0';
218 
219 	*name = lpath;
220 
221 	free(path);
222 	return 0;
223 }
224 
225 
mtd_get_info(struct blocklevel_device * bl,const char ** name,uint64_t * total_size,uint32_t * erase_granule)226 static int mtd_get_info(struct blocklevel_device *bl, const char **name,
227 		uint64_t *total_size, uint32_t *erase_granule)
228 {
229 	struct file_data *file_data = container_of(bl, struct file_data, bl);
230 	struct mtd_info_user mtd_info;
231 	int rc;
232 
233 	rc = ioctl(file_data->fd, MEMGETINFO, &mtd_info);
234 	if (rc == -1)
235 		return FLASH_ERR_BAD_READ;
236 
237 	if (total_size)
238 		*total_size = mtd_info.size;
239 
240 	if (erase_granule)
241 		*erase_granule = mtd_info.erasesize;
242 
243 	if (name) {
244 		rc = get_info_name(file_data, &(file_data->name));
245 		if (rc)
246 			return rc;
247 		*name = file_data->name;
248 	}
249 
250 	return 0;
251 }
252 
file_get_info(struct blocklevel_device * bl,const char ** name,uint64_t * total_size,uint32_t * erase_granule)253 static int file_get_info(struct blocklevel_device *bl, const char **name,
254 		uint64_t *total_size, uint32_t *erase_granule)
255 {
256 	struct file_data *file_data = container_of(bl, struct file_data, bl);
257 	struct stat st;
258 	int rc;
259 
260 	if (fstat(file_data->fd, &st))
261 		return FLASH_ERR_PARM_ERROR;
262 
263 	if (total_size)
264 		*total_size = st.st_size;
265 
266 	if (erase_granule)
267 		*erase_granule = 1;
268 
269 	if (name) {
270 		rc = get_info_name(file_data, &(file_data->name));
271 		if (rc)
272 			return rc;
273 		*name = file_data->name;
274 	}
275 
276 	return 0;
277 }
278 
file_init(int fd,struct blocklevel_device ** bl)279 int file_init(int fd, struct blocklevel_device **bl)
280 {
281 	struct file_data *file_data;
282 	struct stat sbuf;
283 
284 	if (!bl)
285 		return FLASH_ERR_PARM_ERROR;
286 
287 	*bl = NULL;
288 
289 	file_data = calloc(1, sizeof(struct file_data));
290 	if (!file_data)
291 		return FLASH_ERR_MALLOC_FAILED;
292 
293 	file_data->fd = fd;
294 	file_data->bl.reacquire = &file_reacquire;
295 	file_data->bl.release = &file_release;
296 	file_data->bl.read = &file_read;
297 	file_data->bl.write = &file_write;
298 	file_data->bl.erase = &file_erase;
299 	file_data->bl.get_info = &file_get_info;
300 	file_data->bl.erase_mask = 0;
301 
302 	/*
303 	 * If the blocklevel_device is only inited with file_init() then keep
304 	 * alive is assumed, as fd will change otherwise and this may break
305 	 * callers assumptions.
306 	 */
307 	file_data->bl.keep_alive = 1;
308 
309 	/*
310 	 * Unfortunately not all file descriptors are created equal...
311 	 * Here we check to see if the file descriptor is to an MTD device, in
312 	 * which case we have to erase and get the size of it differently.
313 	 */
314 	if (fstat(file_data->fd, &sbuf) == -1)
315 		goto out;
316 
317 	/* Won't be able to handle other than MTD devices for now */
318 	if (S_ISCHR(sbuf.st_mode)) {
319 		file_data->bl.erase = &mtd_erase;
320 		file_data->bl.get_info = &mtd_get_info;
321 		file_data->bl.flags = WRITE_NEED_ERASE;
322 		mtd_get_info(&file_data->bl, NULL, NULL, &(file_data->bl.erase_mask));
323 		file_data->bl.erase_mask--;
324 	} else if (!S_ISREG(sbuf.st_mode)) {
325 		/* If not a char device or a regular file something went wrong */
326 		goto out;
327 	}
328 
329 	*bl = &(file_data->bl);
330 	return 0;
331 out:
332 	free(file_data);
333 	return FLASH_ERR_PARM_ERROR;
334 }
335 
file_init_path(const char * path,int * r_fd,bool keep_alive,struct blocklevel_device ** bl)336 int file_init_path(const char *path, int *r_fd, bool keep_alive,
337 		struct blocklevel_device **bl)
338 {
339 	int fd, rc;
340 	char *path_ptr = NULL;
341 	struct file_data *file_data;
342 
343 	if (!path || !bl)
344 		return FLASH_ERR_PARM_ERROR;
345 
346 	fd = open(path, O_RDWR);
347 	if (fd == -1)
348 		return FLASH_ERR_PARM_ERROR;
349 
350 	/*
351 	 * strdup() first so don't have to deal with malloc failure after
352 	 * file_init()
353 	 */
354 	path_ptr = strdup(path);
355 	if (!path_ptr) {
356 		rc = FLASH_ERR_MALLOC_FAILED;
357 		goto out;
358 	}
359 
360 	rc = file_init(fd, bl);
361 	if (rc)
362 		goto out;
363 
364 	file_data = container_of(*bl, struct file_data, bl);
365 	file_data->bl.keep_alive = keep_alive;
366 	file_data->path = path_ptr;
367 
368 	if (r_fd)
369 		*r_fd = fd;
370 
371 	return rc;
372 out:
373 	free(path_ptr);
374 	close(fd);
375 	return rc;
376 }
377 
file_exit(struct blocklevel_device * bl)378 void file_exit(struct blocklevel_device *bl)
379 {
380 	struct file_data *file_data;
381 	if (bl) {
382 		free(bl->ecc_prot.prot);
383 		file_data = container_of(bl, struct file_data, bl);
384 		free(file_data->name);
385 		free(file_data->path);
386 		free(file_data);
387 	}
388 }
389 
file_exit_close(struct blocklevel_device * bl)390 void file_exit_close(struct blocklevel_device *bl)
391 {
392 	struct file_data *file_data;
393 	if (bl) {
394 		file_data = container_of(bl, struct file_data, bl);
395 		close(file_data->fd);
396 		file_exit(bl);
397 	}
398 }
399