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