xref: /nrf52832-nimble/rt-thread/components/dfs/filesystems/uffs/src/emu/helper_cmds.c (revision 042d53a763ad75cb1465103098bb88c245d95138)
1 /*
2   This file is part of UFFS, the Ultra-low-cost Flash File System.
3 
4   Copyright (C) 2005-2009 Ricky Zheng <[email protected]>
5 
6   UFFS is free software; you can redistribute it and/or modify it under
7   the GNU Library General Public License as published by the Free Software
8   Foundation; either version 2 of the License, or (at your option) any
9   later version.
10 
11   UFFS is distributed in the hope that it will be useful, but WITHOUT
12   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   or GNU Library General Public License, as applicable, for more details.
15 
16   You should have received a copy of the GNU General Public License
17   and GNU Library General Public License along with UFFS; if not, write
18   to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19   Boston, MA  02110-1301, USA.
20 
21   As a special exception, if other files instantiate templates or use
22   macros or inline functions from this file, or you compile this file
23   and link it with other works to produce a work based on this file,
24   this file does not by itself cause the resulting work to be covered
25   by the GNU General Public License. However the source code for this
26   file must still be made available in accordance with section (3) of
27   the GNU General Public License v2.
28 
29   This exception does not invalidate any other reasons why a work based
30   on this file might be covered by the GNU General Public License.
31 */
32 
33 /**
34  * \file helper_cmds.c
35  * \brief helper commands for test uffs
36  * \author Ricky Zheng
37  */
38 #include <stdio.h>
39 #include <string.h>
40 #include <stdarg.h>
41 #include <stdlib.h>
42 #include "uffs_config.h"
43 #include "uffs/uffs_public.h"
44 #include "uffs/uffs_fs.h"
45 #include "uffs/uffs_utils.h"
46 #include "uffs/uffs_core.h"
47 #include "uffs/uffs_mtb.h"
48 #include "uffs/uffs_find.h"
49 #include "cmdline.h"
50 #include "uffs/uffs_fd.h"
51 #include "uffs/uffs_mtb.h"
52 #include "uffs_fileem.h"
53 
54 #define PFX "cmd : "
55 
56 #define MAX_PATH_LENGTH 128
57 
58 #define MSGLN(msg,...) uffs_Perror(UFFS_MSG_NORMAL, msg, ## __VA_ARGS__)
59 #define MSG(msg,...) uffs_PerrorRaw(UFFS_MSG_NORMAL, msg, ## __VA_ARGS__)
60 
61 /** format [<mount>] */
62 static int cmd_format(int argc, char *argv[])
63 {
64 	URET ret;
65 	const char *mount = "/";
66 	uffs_Device *dev;
67 	UBOOL force = U_FALSE;
68 
69 	if (argc > 1) {
70 		mount = argv[1];
71 		if (argc > 2 && strcmp(argv[2], "-f") == 0)
72 			force = U_TRUE;
73 	}
74 	MSGLN("Formating %s ... ", mount);
75 
76 	dev = uffs_GetDeviceFromMountPoint(mount);
77 	if (dev == NULL) {
78 		MSGLN("Can't get device from mount point.");
79 		return -1;
80 	}
81 	else {
82 		ret = uffs_FormatDevice(dev, force);
83 		if (ret != U_SUCC) {
84 			MSGLN("Format fail.");
85 			return -1;
86 		}
87 		else {
88 			MSGLN("Format succ.");
89 		}
90 		uffs_PutDevice(dev);
91 	}
92 
93 	return 0;
94 }
95 
96 /** mkf <file> */
97 static int cmd_mkf(int argc, char *argv[])
98 {
99 	int fd;
100 	const char *name;
101 	int oflags = UO_RDWR | UO_CREATE;
102 
103 	CHK_ARGC(2, 2);
104 
105 	name = argv[1];
106 	fd = uffs_open(name, oflags);
107 	if (fd < 0) {
108 		MSGLN("Create %s fail, err: %d", name, uffs_get_error());
109 		return -1;
110 	}
111 	else {
112 		MSGLN("Create %s succ.", name);
113 		uffs_close(fd);
114 	}
115 
116 	return 0;
117 }
118 
119 /** mkdir <dir> */
120 static int cmd_mkdir(int argc, char *argv[])
121 {
122 	const char *name;
123 
124 	CHK_ARGC(2, 0);
125 
126 	name = argv[1];
127 
128 	if (uffs_mkdir(name) < 0) {
129 		MSGLN("Create %s fail, err: %d", name, uffs_get_error());
130 		return -1;
131 	}
132 	else {
133 		MSGLN("Create %s succ.", name);
134 	}
135 
136 	return 0;
137 }
138 
139 
140 static int CountObjectUnder(const char *dir)
141 {
142 	int count = 0;
143 	uffs_DIR *dirp;
144 
145 	dirp = uffs_opendir(dir);
146 	if (dirp) {
147 		while (uffs_readdir(dirp) != NULL)
148 			count++;
149 		uffs_closedir(dirp);
150 	}
151 	return count;
152 }
153 
154 static int cmd_pwd(int argc, char *argv[])
155 {
156 	MSGLN("not supported.");
157 	return 0;
158 }
159 
160 static int cmd_cd(int argc, char *argv[])
161 {
162 	MSGLN("Not supported");
163 	return 0;
164 }
165 
166 /** ls [<dir>] */
167 static int cmd_ls(int argc, char *argv[])
168 {
169 	uffs_DIR *dirp;
170 	struct uffs_dirent *ent;
171 	struct uffs_stat stat_buf;
172 	int count = 0;
173 	char buf[MAX_PATH_LENGTH+2];
174 	const char *name = "/";
175 	char *sub;
176 	int ret = 0;
177 
178 	CHK_ARGC(1, 2);
179 
180 	if (argc > 1)
181 		name = argv[1];
182 
183 	dirp = uffs_opendir(name);
184 	if (dirp == NULL) {
185 		MSGLN("Can't open '%s' for list", name);
186 		ret = -1;
187 	}
188 	else {
189 		MSG("------name-----------size---------serial-----" TENDSTR);
190 		ent = uffs_readdir(dirp);
191 		while (ent) {
192 			MSG("%9s", ent->d_name);
193 			strcpy(buf, name);
194 			sub = buf;
195 			if (name[strlen(name)-1] != '/')
196 				sub = strcat(buf, "/");
197 			sub = strcat(sub, ent->d_name);
198 			if (ent->d_type & FILE_ATTR_DIR) {
199 				sub = strcat(sub, "/");
200 				MSG("/  \t<%8d>", CountObjectUnder(sub));
201 			}
202 			else {
203 				uffs_stat(sub, &stat_buf);
204 				MSG("   \t %8d ", stat_buf.st_size);
205 			}
206 			MSG("\t%6d" TENDSTR, ent->d_ino);
207 			count++;
208 			ent = uffs_readdir(dirp);
209 		}
210 
211 		uffs_closedir(dirp);
212 
213 		MSG("Total: %d objects." TENDSTR, count);
214 	}
215 
216 	return ret;
217 }
218 
219 /** rm <obj> */
220 static int cmd_rm(int argc, char *argv[])
221 {
222 	const char *name = NULL;
223 	int ret = 0;
224 	struct uffs_stat st;
225 
226 	CHK_ARGC(2, 2);
227 
228 	name = argv[1];
229 
230 	ret = uffs_stat(name, &st);
231 	if (ret < 0) {
232 		MSGLN("Can't stat '%s'", name);
233 		return ret;
234 	}
235 
236 	if (st.st_mode & US_IFDIR) {
237 		ret = uffs_rmdir(name);
238 	}
239 	else {
240 		ret = uffs_remove(name);
241 	}
242 
243 	if (ret == 0)
244 		MSGLN("Delete '%s' succ.", name);
245 	else
246 		MSGLN("Delete '%s' fail!", name);
247 
248 	return ret;
249 }
250 
251 /** ren|mv <old> <new> */
252 static int cmd_ren(int argc, char *argv[])
253 {
254 	const char *oldname;
255 	const char *newname;
256 	int ret;
257 
258 	CHK_ARGC(3, 3);
259 
260 	oldname = argv[1];
261 	newname = argv[2];
262 
263 	if ((ret = uffs_rename(oldname, newname)) == 0) {
264 		MSGLN("Rename from '%s' to '%s' succ.", oldname, newname);
265 	}
266 	else {
267 		MSGLN("Rename from '%s' to '%s' fail!", oldname, newname);
268 	}
269 
270 	return ret;
271 }
272 
273 static void dump_msg_to_stdout(struct uffs_DeviceSt *dev, const char *fmt, ...)
274 {
275 	uffs_FileEmu *emu = (uffs_FileEmu *)(dev->attr->_private);
276 	va_list args;
277 
278 	va_start(args, fmt);
279 	//vprintf(fmt, args);
280 	if (emu && emu->dump_fp)
281 		vfprintf(emu->dump_fp, fmt, args);
282 	va_end(args);
283 }
284 
285 /** dump [<mount>] */
286 static int cmd_dump(int argc, char *argv[])
287 {
288 	uffs_Device *dev;
289 	uffs_FileEmu *emu;
290 	const char *mount = "/";
291 	const char *dump_file = "dump.txt";
292 
293 	if (argc > 1) {
294 		mount = argv[1];
295 		if (argc > 2)
296 			dump_file = argv[2];
297 	}
298 
299 	dev = uffs_GetDeviceFromMountPoint(mount);
300 	if (dev == NULL) {
301 		MSGLN("Can't get device from mount point %s", mount);
302 		return -1;
303 	}
304 
305 	emu = (uffs_FileEmu *)(dev->attr->_private);
306 	emu->dump_fp = fopen(dump_file, "w");
307 
308 	uffs_DumpDevice(dev, dump_msg_to_stdout);
309 
310 	if (emu->dump_fp)
311 		fclose(emu->dump_fp);
312 
313 	uffs_PutDevice(dev);
314 
315 	return 0;
316 }
317 
318 /** st [<mount>] */
319 static int cmd_st(int argc, char *argv[])
320 {
321 	uffs_Device *dev;
322 	const char *mount = "/";
323 	uffs_FlashStat *s;
324 	TreeNode *node;
325 
326 	if (argc > 1) {
327 		mount = argv[1];
328 	}
329 
330 	dev = uffs_GetDeviceFromMountPoint(mount);
331 	if (dev == NULL) {
332 		MSGLN("Can't get device from mount point %s", mount);
333 		return -1;
334 	}
335 
336 	s = &(dev->st);
337 
338 	MSG("----------- basic info -----------" TENDSTR);
339 	MSG("TreeNode size:         %d" TENDSTR, sizeof(TreeNode));
340 	MSG("TagStore size:         %d" TENDSTR, sizeof(struct uffs_TagStoreSt));
341 	MSG("MaxCachedBlockInfo:    %d" TENDSTR, dev->cfg.bc_caches);
342 	MSG("MaxPageBuffers:        %d" TENDSTR, dev->cfg.page_buffers);
343 	MSG("MaxDirtyPagesPerBlock: %d" TENDSTR, dev->cfg.dirty_pages);
344 	MSG("MaxPathLength:         %d" TENDSTR, MAX_PATH_LENGTH);
345 	MSG("MaxObjectHandles:      %d" TENDSTR, MAX_OBJECT_HANDLE);
346 	MSG("FreeObjectHandles:     %d" TENDSTR, uffs_GetFreeObjectHandlers());
347 	MSG("MaxDirHandles:         %d" TENDSTR, MAX_DIR_HANDLE);
348 	MSG("FreeDirHandles:        %d" TENDSTR, uffs_PoolGetFreeCount(uffs_DirEntryBufGetPool()));
349 
350 	MSG("----------- statistics for '%s' -----------" TENDSTR, mount);
351 	MSG("Device Ref:            %d" TENDSTR, dev->ref_count);
352 	MSG("Block Erased:          %d" TENDSTR, s->block_erase_count);
353 	MSG("Write Page:            %d" TENDSTR, s->page_write_count);
354 	MSG("Write Spare:           %d" TENDSTR, s->spare_write_count);
355 	MSG("Read Page:             %d" TENDSTR, s->page_read_count - s->page_header_read_count);
356 	MSG("Read Header:           %d" TENDSTR, s->page_header_read_count);
357 	MSG("Read Spare:            %d" TENDSTR, s->spare_read_count);
358 	MSG("I/O Read:              %lu" TENDSTR, s->io_read);
359 	MSG("I/O Write:             %lu" TENDSTR, s->io_write);
360 
361 	MSG("--------- partition info for '%s' ---------" TENDSTR, mount);
362 	MSG("Space total:           %d" TENDSTR, uffs_GetDeviceTotal(dev));
363 	MSG("Space used:            %d" TENDSTR, uffs_GetDeviceUsed(dev));
364 	MSG("Space free:            %d" TENDSTR, uffs_GetDeviceFree(dev));
365 	MSG("Page Size:             %d" TENDSTR, dev->attr->page_data_size);
366 	MSG("Spare Size:            %d" TENDSTR, dev->attr->spare_size);
367 	MSG("Pages Per Block:       %d" TENDSTR, dev->attr->pages_per_block);
368 	MSG("Block size:            %d" TENDSTR, dev->attr->page_data_size * dev->attr->pages_per_block);
369 	MSG("Total blocks:          %d of %d" TENDSTR, (dev->par.end - dev->par.start + 1), dev->attr->total_blocks);
370 	if (dev->tree.bad) {
371 		MSG("Bad blocks: ");
372 		node = dev->tree.bad;
373 		while(node) {
374 			MSG("%d, ", node->u.list.block);
375 			node = node->u.list.next;
376 		}
377 		MSG(TENDSTR);
378 	}
379 
380 	uffs_PutDevice(dev);
381 
382 	return 0;
383 
384 }
385 
386 /** cp <src> <des> */
387 static int cmd_cp(int argc, char *argv[])
388 {
389 	const char *src;
390 	const char *des;
391 	char buf[100];
392 	int fd1 = -1, fd2 = -1;
393 	int len;
394 	BOOL src_local = FALSE, des_local = FALSE;
395 	FILE *fp1 = NULL, *fp2 = NULL;
396 	int ret = -1;
397 
398 	CHK_ARGC(3, 3);
399 
400 	src = argv[1];
401 	des = argv[2];
402 
403 	if (memcmp(src, "::", 2) == 0) {
404 		src += 2;
405 		src_local = TRUE;
406 	}
407 	if (memcmp(des, "::", 2) == 0) {
408 		des += 2;
409 		des_local = TRUE;
410 	}
411 
412 	if (src_local) {
413 		if ((fp1 = fopen(src, "rb")) == NULL) {
414 			MSGLN("Can't open %s for copy.", src);
415 			goto fail_ext;
416 		}
417 	}
418 	else {
419 		if ((fd1 = uffs_open(src, UO_RDONLY)) < 0) {
420 			MSGLN("Can't open %s for copy.", src);
421 			goto fail_ext;
422 		}
423 	}
424 
425 	if (des_local) {
426 		if ((fp2 = fopen(des, "wb")) == NULL) {
427 			MSGLN("Can't open %s for copy.", des);
428 			goto fail_ext;
429 		}
430 	}
431 	else {
432 		if ((fd2 = uffs_open(des, UO_RDWR|UO_CREATE|UO_TRUNC)) < 0) {
433 			MSGLN("Can't open %s for copy.", des);
434 			goto fail_ext;
435 		}
436 	}
437 
438 	ret = 0;
439 	while (	(src_local ? (feof(fp1) == 0) : (uffs_eof(fd1) == 0)) ) {
440 		ret = -1;
441 		if (src_local) {
442 			len = fread(buf, 1, sizeof(buf), fp1);
443 		}
444 		else {
445 			len = uffs_read(fd1, buf, sizeof(buf));
446 		}
447 		if (len == 0) {
448 			ret = -1;
449 			break;
450 		}
451 		if (len < 0) {
452 			MSGLN("read file %s fail ?", src);
453 			break;
454 		}
455 		if (des_local) {
456 			if ((int)fwrite(buf, 1, len, fp2) != len) {
457 				MSGLN("write file %s fail ? ", des);
458 				break;
459 			}
460 		}
461 		else {
462 			if (uffs_write(fd2, buf, len) != len) {
463 				MSGLN("write file %s fail ? ", des);
464 				break;
465 			}
466 		}
467 		ret = 0;
468 	}
469 
470 fail_ext:
471 	if (fd1 > 0)
472 		uffs_close(fd1);
473 	if (fd2 > 0)
474 		uffs_close(fd2);
475 	if (fp1)
476 		fclose(fp1);
477 	if (fp2)
478 		fclose(fp2);
479 
480 	return ret;
481 }
482 
483 /** cat <file> [<offset>] [<size>] */
484 static int cmd_cat(int argc, char *argv[])
485 {
486 	int fd;
487 	const char *name = NULL;
488 	char buf[100];
489 	int start = 0, size = 0, printed = 0, n, len;
490 	int ret = -1;
491 
492 	CHK_ARGC(2, 4);
493 
494 	name = argv[1];
495 
496 	if ((fd = uffs_open(name, UO_RDONLY)) < 0) {
497 		MSGLN("Can't open %s", name);
498 		goto fail;
499 	}
500 
501 	if (argc > 2) {
502 		start = strtol(argv[2], NULL, 10);
503 		if (argc > 3) size = strtol(argv[3], NULL, 10);
504 	}
505 
506 	if (start >= 0)
507 		uffs_seek(fd, start, USEEK_SET);
508 	else
509 		uffs_seek(fd, -start, USEEK_END);
510 
511 	while (uffs_eof(fd) == 0) {
512 		len = uffs_read(fd, buf, sizeof(buf) - 1);
513 		if (len == 0)
514 			break;
515 		if (len > 0) {
516 			if (size == 0 || printed < size) {
517 				n = (size == 0 ? len : (size - printed > len ? len : size - printed));
518 				buf[n] = 0;
519 				MSG("%s", buf);
520 				printed += n;
521 			}
522 			else {
523 				break;
524 			}
525 		}
526 	}
527 	MSG(TENDSTR);
528 	uffs_close(fd);
529 
530 	ret = 0;
531 fail:
532 
533 	return ret;
534 }
535 
536 /** mount partition or show mounted partitions
537  *		mount [<mount>]
538  */
539 static int cmd_mount(int argc, char *argv[])
540 {
541 	uffs_MountTable *tab;
542 	const char *mount = NULL;
543 
544 	if (argc == 1) {
545 		tab = uffs_MtbGetMounted();
546 		while (tab) {
547 			MSG(" %s : (%d) ~ (%d)\n", tab->mount, tab->start_block, tab->end_block);
548 			tab = tab->next;
549 		}
550 	}
551 	else {
552 		mount = argv[1];
553 		if (uffs_Mount(mount) < 0) {
554 			MSGLN("Can't mount %s", mount);
555 			return -1;
556 		}
557 	}
558 	return 0;
559 }
560 
561 /** unmount parition or show unmounted partitions
562  *		umount [<mount>]
563  */
564 static int cmd_unmount(int argc, char *argv[])
565 {
566 	uffs_MountTable *tab;
567 	const char *mount = NULL;
568 
569 	if (argc == 1) {
570 		tab = uffs_MtbGetUnMounted();
571 		while (tab) {
572 			MSG(" %s : (%d) ~ (%d)\n", tab->mount, tab->start_block, tab->end_block);
573 			tab = tab->next;
574 		}
575 	}
576 	else {
577 		mount = argv[1];
578 		if (uffs_UnMount(mount) < 0) {
579 			MSGLN("Can't unmount %s", mount);
580 			return -1;
581 		}
582 	}
583 
584 	return 0;
585 }
586 
587 /** inspect buffers
588  *		inspb [<mount>]
589  */
590 static int cmd_inspb(int argc, char *argv[])
591 {
592 	uffs_Device *dev;
593 	const char *mount = "/";
594 
595 	CHK_ARGC(1, 2);
596 
597 	dev = uffs_GetDeviceFromMountPoint(mount);
598 	if (dev == NULL) {
599 		MSGLN("Can't get device from mount point %s", mount);
600 		return -1;
601 	}
602 	uffs_BufInspect(dev);
603 	uffs_PutDevice(dev);
604 
605 	return 0;
606 
607 }
608 
609 /** print block wear-leveling information
610  *		wl [<mount>]
611  */
612 static int cmd_wl(int argc, char *argv[])
613 {
614 	const char *mount = "/";
615 	uffs_Device *dev;
616 	struct uffs_PartitionSt *par;
617 	uffs_FileEmu *emu;
618 	int i, max;
619 	u32 n;
620 
621 #define NUM_PER_LINE	10
622 
623 	CHK_ARGC(1, 2);
624 
625 	if (argc > 1) {
626 		mount = argv[1];
627 	}
628 
629 	dev = uffs_GetDeviceFromMountPoint(mount);
630 	if (dev == NULL) {
631 		MSGLN("Can't get device from mount point %s", mount);
632 		return -1;
633 	}
634 
635 	par = &dev->par;
636 	emu = (uffs_FileEmu *)(dev->attr->_private);
637 	max = -1;
638 
639 	for (i = 0; i < par->end - par->start; i++) {
640 		if ((i % NUM_PER_LINE) == 0) {
641 			MSG("%04d:", i + par->start);
642 		}
643 		n = i + par->start;
644 		max = (max == -1 ? n :
645 				(emu->em_monitor_block[n] > emu->em_monitor_block[max] ? n : max)
646 			   );
647 		MSG(" %4d", emu->em_monitor_block[n]);
648 		if (uffs_TreeFindBadNodeByBlock(dev, n))
649 			MSG("%c", 'x');
650 		else if (uffs_TreeFindErasedNodeByBlock(dev, n))
651 			MSG("%c", ' ');
652 		else
653 			MSG("%c", '.');
654 		if (((i + 1) % NUM_PER_LINE) == 0)
655 			MSG("\n");
656 	}
657 	MSG("\n");
658 	MSG("Total blocks %d, peak erase count %d at block %d\n",
659 		par->end - par->start, max == -1 ? 0 : emu->em_monitor_block[max], max);
660 
661 	uffs_PutDevice(dev);
662 
663 	return 0;
664 }
665 
666 static const struct cli_command helper_cmds[] =
667 {
668     { cmd_format,	"format",		"[<mount>]",		"Format device" },
669     { cmd_mkf,		"mkfile",		"<name>",			"create a new file" },
670     { cmd_mkdir,	"mkdir",		"<name>",			"create a new directory" },
671     { cmd_rm,		"rm",			"<name>",			"delete file/directory" },
672     { cmd_ren,		"mv|ren",		"<old> <new>",		"rename file/directory" },
673     { cmd_ls,		"ls",			"<dir>",			"list dirs and files" },
674     { cmd_st,		"info|st",		"<mount>",			"show statistic infomation" },
675     { cmd_cp,		"cp",			"<src> <des>",		"copy files. the local file name start with '::'" },
676     { cmd_cat,		"cat",			"<name>",			"show file content" },
677     { cmd_pwd,		"pwd",			NULL,				"show current dir" },
678     { cmd_cd,		"cd",			"<path>",			"change current dir" },
679     { cmd_mount,	"mount",		"[<mount>]",		"mount partition or list mounted partitions" },
680     { cmd_unmount,	"umount",		"[<mount>]",		"unmount partition" },
681 	{ cmd_dump,		"dump",			"[<mount>]",		"dump file system", },
682 	{ cmd_wl,		"wl",			"[<mount>]",		"show block wear-leveling info", },
683 	{ cmd_inspb,	"inspb",		"[<mount>]",		"inspect buffer", },
684     { NULL, NULL, NULL, NULL }
685 };
686 
687 static struct cli_commandset helper_cmdset = {
688 	helper_cmds,
689 };
690 
691 struct cli_commandset * get_helper_cmds()
692 {
693 	return &helper_cmdset;
694 };
695