helper_cmds.c 15 KB

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