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>] */
cmd_format(int argc,char * argv[])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> */
cmd_mkf(int argc,char * argv[])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> */
cmd_mkdir(int argc,char * argv[])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
CountObjectUnder(const char * dir)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
cmd_pwd(int argc,char * argv[])154 static int cmd_pwd(int argc, char *argv[])
155 {
156 MSGLN("not supported.");
157 return 0;
158 }
159
cmd_cd(int argc,char * argv[])160 static int cmd_cd(int argc, char *argv[])
161 {
162 MSGLN("Not supported");
163 return 0;
164 }
165
166 /** ls [<dir>] */
cmd_ls(int argc,char * argv[])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> */
cmd_rm(int argc,char * argv[])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> */
cmd_ren(int argc,char * argv[])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
dump_msg_to_stdout(struct uffs_DeviceSt * dev,const char * fmt,...)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>] */
cmd_dump(int argc,char * argv[])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>] */
cmd_st(int argc,char * argv[])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> */
cmd_cp(int argc,char * argv[])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>] */
cmd_cat(int argc,char * argv[])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 */
cmd_mount(int argc,char * argv[])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 */
cmd_unmount(int argc,char * argv[])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 */
cmd_inspb(int argc,char * argv[])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 */
cmd_wl(int argc,char * argv[])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
get_helper_cmds()691 struct cli_commandset * get_helper_cmds()
692 {
693 return &helper_cmdset;
694 };
695