diff options
Diffstat (limited to 'cpukit/libfs/src/rfs/rtems-rfs-shell.c')
-rw-r--r-- | cpukit/libfs/src/rfs/rtems-rfs-shell.c | 666 |
1 files changed, 666 insertions, 0 deletions
diff --git a/cpukit/libfs/src/rfs/rtems-rfs-shell.c b/cpukit/libfs/src/rfs/rtems-rfs-shell.c new file mode 100644 index 0000000000..b1d25c2c67 --- /dev/null +++ b/cpukit/libfs/src/rfs/rtems-rfs-shell.c @@ -0,0 +1,666 @@ +/* + * COPYRIGHT (c) 2010 Chris Johns <chrisj@rtems.org> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ +/** + * @file + * + * @ingroup rtems-rfs + * + * RTEMS File Systems Shell Commands Support + */ + +#include <string.h> + +#include <rtems/rfs/rtems-rfs-block.h> +#include <rtems/rfs/rtems-rfs-buffer.h> +#include <rtems/rfs/rtems-rfs-group.h> +#include <rtems/rfs/rtems-rfs-inode.h> +#include <rtems/rfs/rtems-rfs-dir.h> + +#include <sys/statvfs.h> + +#if __rtems__ +#include "rtems-rfs-rtems.h" +#endif + +/** + * The type of the shell handlers we have. + */ +typedef int (*rtems_rfs_shell_handler) (rtems_rfs_file_system* fs, int argc, char *argv[]); + +/** + * Table of handlers we parse to invoke the command. + */ +typedef struct rtems_rfs_shell_cmd_t +{ + const char* name; + rtems_rfs_shell_handler handler; + const char* help; +} rtems_rfs_shell_cmd; + +/** + * Lock the file system. + */ +static void +rtems_rfs_shell_lock_rfs (rtems_rfs_file_system* fs) +{ +#if __rtems__ + rtems_rfs_rtems_lock (fs); +#endif +} + +/** + * Unlock the file system. + */ +static void +rtems_rfs_shell_unlock_rfs (rtems_rfs_file_system* fs) +{ +#if __rtems__ + rtems_rfs_rtems_unlock (fs); +#endif +} + +/** + * Get the file system data from the specific path. Checks to make sure the path is + * pointing to a valid RFS file system. + */ +static int +rtems_rfs_get_fs (const char* path, rtems_rfs_file_system** fs) +{ + struct statvfs sb; + int rc; + + rc = statvfs (path, &sb); + if (rc < 0) + { + printf ("error: cannot statvfs path: %s: (%d) %s\n", + path, errno, strerror (errno)); + return -1; + } + + if (sb.f_fsid != RTEMS_RFS_SB_MAGIC) + { + printf ("error: path '%s' is not on an RFS file system\n", path); + return -1; + } + +#if __rtems__ + /* + * Now find the path location on the file system. This will give the file + * system data. + */ + { + rtems_filesystem_location_info_t pathloc; + rc = rtems_filesystem_evaluate_path (path, strlen (path), 0, &pathloc, true); + *fs = rtems_rfs_rtems_pathloc_dev (&pathloc); + rtems_filesystem_freenode (&pathloc); + } +#endif + + return rc; +} + +static int +rtems_rfs_shell_data (rtems_rfs_file_system* fs, int argc, char *argv[]) +{ + size_t blocks; + size_t inodes; + int bpcent; + int ipcent; + int g; + + printf ("RFS Filesystem Data\n"); + printf (" flags: %08lx\n", fs->flags); +#if 0 + printf (" device: %08lx\n", rtems_rfs_fs_device (fs)); +#endif + printf (" blocks: %lu\n", rtems_rfs_fs_blocks (fs)); + printf (" block size: %lu\n", rtems_rfs_fs_block_size (fs)); + printf (" size: %llu\n", rtems_rfs_fs_size (fs)); + printf (" media block size: %lu\n", rtems_rfs_fs_media_block_size (fs)); + printf (" media size: %llu\n", rtems_rfs_fs_media_size (fs)); + printf (" inodes: %lu\n", rtems_rfs_fs_inodes (fs)); + printf (" bad blocks: %lu\n", fs->bad_blocks); + printf (" max. name length: %lu\n", rtems_rfs_fs_max_name (fs)); + printf (" groups: %d\n", fs->group_count); + printf (" group blocks: %ld\n", fs->group_blocks); + printf (" group inodes: %ld\n", fs->group_inodes); + printf (" inodes per block: %ld\n", fs->inodes_per_block); + printf (" blocks per block: %ld\n", fs->blocks_per_block); + printf (" singly blocks: %ld\n", fs->block_map_singly_blocks); + printf (" doublly blocks: %ld\n", fs->block_map_doubly_blocks); + printf (" max. held buffers: %ld\n", fs->max_held_buffers); + + rtems_rfs_shell_lock_rfs (fs); + + blocks = 0; + inodes = 0; + + for (g = 0; g < fs->group_count; g++) + { + rtems_rfs_group* group = &fs->groups[g]; + blocks += + rtems_rfs_bitmap_map_size(&group->block_bitmap) - + rtems_rfs_bitmap_map_free (&group->block_bitmap); + inodes += + rtems_rfs_bitmap_map_size (&group->inode_bitmap) - + rtems_rfs_bitmap_map_free (&group->inode_bitmap); + } + + rtems_rfs_shell_unlock_rfs (fs); + + bpcent = (blocks * 1000) / rtems_rfs_fs_blocks (fs); + ipcent = (inodes * 1000) / rtems_rfs_fs_inodes (fs); + + printf (" blocks used: %ld (%d.%d%%)\n", + blocks, bpcent / 10, bpcent % 10); + printf (" inodes used: %ld (%d.%d%%)\n", + inodes, ipcent / 10, ipcent % 10); + + return 0; +} + +static int +rtems_rfs_shell_block (rtems_rfs_file_system* fs, int argc, char *argv[]) +{ + rtems_rfs_buffer_handle buffer; + rtems_rfs_block_no block; + uint8_t* data; + bool state; + int b; + int rc; + + if (argc <= 1) + { + printf ("error: no block number provided\n"); + return 1; + } + + block = strtoul (argv[1], 0, 0); + + rtems_rfs_shell_lock_rfs (fs); + + rc = rtems_rfs_group_bitmap_test (fs, false, block, &state); + if (rc > 0) + { + rtems_rfs_shell_unlock_rfs (fs); + printf ("error: testing block state: block=%lu: (%d) %s\n", + block, rc, strerror (rc)); + return 1; + } + + printf (" %5lu: block %s\n", block, state ? "allocated" : "free"); + + rc = rtems_rfs_buffer_handle_open (fs, &buffer); + if (rc > 0) + { + rtems_rfs_shell_unlock_rfs (fs); + printf ("error: opening buffer handle: block=%lu: (%d) %s\n", + block, rc, strerror (rc)); + return 1; + } + + rc = rtems_rfs_buffer_handle_request (fs, &buffer, block, true); + if (rc > 0) + { + rtems_rfs_buffer_handle_close (fs, &buffer); + rtems_rfs_shell_unlock_rfs (fs); + printf ("error: requesting buffer handle: block=%lu: (%d) %s\n", + block, rc, strerror (rc)); + return 1; + } + + for (b = 0, data = rtems_rfs_buffer_data (&buffer); + b < rtems_rfs_fs_block_size (fs); + b++, data++) + { + int mod = b % 16; + if (mod == 0) + { + if (b) + printf ("\n"); + printf ("%04x ", b); + } + if (mod == 8) + printf (" "); + printf ("%02x ", *data); + } + + printf ("\n"); + + rc = rtems_rfs_buffer_handle_close (fs, &buffer); + if (rc > 0) + { + rtems_rfs_shell_unlock_rfs (fs); + printf ("error: closing buffer handle: block=%lu: (%d) %s\n", + block, rc, strerror (rc)); + return 1; + } + + rtems_rfs_shell_unlock_rfs (fs); + + return 0; +} + +static int +rtems_rfs_shell_inode (rtems_rfs_file_system* fs, int argc, char *argv[]) +{ + rtems_rfs_ino start; + rtems_rfs_ino end; + rtems_rfs_ino total; + rtems_rfs_ino ino; + bool show_all; + bool error_check_only; + bool forced; + bool have_start; + bool have_end; + int arg; + int b; + int rc; + + total = fs->group_inodes * fs->group_count; + start = RTEMS_RFS_ROOT_INO; + end = total - 1; + show_all = false; + error_check_only = false; + forced = false; + have_start = have_end = false; + + for (arg = 1; arg < argc; arg++) + { + if (argv[arg][0] == '-') + { + switch (argv[arg][1]) + { + case 'a': + show_all = true; + break; + case 'e': + error_check_only = true; + break; + case 'f': + forced = true; + break; + default: + printf ("warning: option ignored: %s\n", argv[arg]); + break; + } + } + else + { + if (have_end && have_start) + printf ("warning: option ignored: %s\n", argv[arg]); + else if (!have_start) + { + start = end = strtoul (argv[arg], 0, 0); + have_start = true; + } + else + { + end = strtoul (argv[arg], 0, 0); + have_end = true; + } + } + } + + if ((start < 0) || (end < 0) || + (start >= total) || (end >= total)) + { + printf ("error: inode out of range (0->%ld).\n", total - 1); + return 1; + } + + rtems_rfs_shell_lock_rfs (fs); + + for (ino = start; ino <= end; ino++) + { + rtems_rfs_inode_handle inode; + bool allocated; + + rc = rtems_rfs_group_bitmap_test (fs, true, ino, &allocated); + if (rc > 0) + { + rtems_rfs_shell_unlock_rfs (fs); + printf ("error: testing inode state: ino=%lu: (%d) %s\n", + ino, rc, strerror (rc)); + return 1; + } + + if (show_all || allocated) + { + uint16_t mode; + bool error; + + rc = rtems_rfs_inode_open (fs, ino, &inode, true); + if (rc > 0) + { + rtems_rfs_shell_unlock_rfs (fs); + printf ("error: opening inode handle: ino=%lu: (%d) %s\n", + ino, rc, strerror (rc)); + return 1; + } + + error = false; + + mode = rtems_rfs_inode_get_mode (&inode); + + if (error_check_only) + { + if (!RTEMS_RFS_S_ISDIR (mode) && + !RTEMS_RFS_S_ISCHR (mode) && + !RTEMS_RFS_S_ISBLK (mode) && + !RTEMS_RFS_S_ISREG (mode) && + !RTEMS_RFS_S_ISLNK (mode)) + error = true; + else + { +#if NEED_TO_HANDLE_DIFFERENT_TYPES + int b; + for (b = 0; b < RTEMS_RFS_INODE_BLOCKS; b++) + { + uint32_t block; + block = rtems_rfs_inode_get_block (&inode, b); + if ((block <= RTEMS_RFS_SUPERBLOCK_SIZE) || + (block >= rtems_rfs_fs_blocks (fs))) + error = true; + } +#endif + } + } + + if (!error_check_only || error) + { + printf (" %5lu: pos=%06lu:%04lx %c ", + ino, rtems_rfs_buffer_bnum (&inode.buffer), + inode.offset * sizeof (rtems_rfs_inode), + allocated ? 'A' : 'F'); + + if (!allocated && !forced) + printf (" --\n"); + else + { + const char* type; + type = "UKN"; + if (RTEMS_RFS_S_ISDIR (mode)) + type = "DIR"; + else if (RTEMS_RFS_S_ISCHR (mode)) + type = "CHR"; + else if (RTEMS_RFS_S_ISBLK (mode)) + type = "BLK"; + else if (RTEMS_RFS_S_ISREG (mode)) + type = "REG"; + else if (RTEMS_RFS_S_ISLNK (mode)) + type = "LNK"; + printf ("links=%03i mode=%04x (%s/%03o) bo=%04u bc=%04lu b=[", + rtems_rfs_inode_get_links (&inode), + mode, type, mode & ((1 << 10) - 1), + rtems_rfs_inode_get_block_offset (&inode), + rtems_rfs_inode_get_block_count (&inode)); + for (b = 0; b < (RTEMS_RFS_INODE_BLOCKS - 1); b++) + printf ("%lu ", rtems_rfs_inode_get_block (&inode, b)); + printf ("%lu]\n", rtems_rfs_inode_get_block (&inode, b)); + } + } + + rc = rtems_rfs_inode_close (fs, &inode); + if (rc > 0) + { + rtems_rfs_shell_unlock_rfs (fs); + printf ("error: closing inode handle: ino=%lu: (%d) %s\n", + ino, rc, strerror (rc)); + return 1; + } + } + } + + rtems_rfs_shell_unlock_rfs (fs); + + return 0; +} + +static int +rtems_rfs_shell_dir (rtems_rfs_file_system* fs, int argc, char *argv[]) +{ + rtems_rfs_buffer_handle buffer; + rtems_rfs_block_no block; + uint8_t* data; + bool state; + int entry; + int b; + int rc; + + if (argc <= 1) + { + printf ("error: no block number provided\n"); + return 1; + } + + block = strtoul (argv[1], 0, 0); + + rtems_rfs_shell_lock_rfs (fs); + + rc = rtems_rfs_group_bitmap_test (fs, false, block, &state); + if (rc > 0) + { + rtems_rfs_shell_unlock_rfs (fs); + printf ("error: testing block state: block=%lu: (%d) %s\n", + block, rc, strerror (rc)); + return 1; + } + + printf (" %5lu: block %s\n", block, state ? "allocated" : "free"); + + rc = rtems_rfs_buffer_handle_open (fs, &buffer); + if (rc > 0) + { + rtems_rfs_shell_unlock_rfs (fs); + printf ("error: opening buffer handle: block=%lu: (%d) %s\n", + block, rc, strerror (rc)); + return 1; + } + + rc = rtems_rfs_buffer_handle_request (fs, &buffer, block, true); + if (rc > 0) + { + rtems_rfs_buffer_handle_close (fs, &buffer); + rtems_rfs_shell_unlock_rfs (fs); + printf ("error: requesting buffer handle: block=%lu: (%d) %s\n", + block, rc, strerror (rc)); + return 1; + } + + b = 0; + entry = 1; + data = rtems_rfs_buffer_data (&buffer); + + while (b < (rtems_rfs_fs_block_size (fs) - RTEMS_RFS_DIR_ENTRY_SIZE - 1)) + { + rtems_rfs_ino eino; + int elength; + int length; + int c; + + eino = rtems_rfs_dir_entry_ino (data); + elength = rtems_rfs_dir_entry_length (data); + + if (elength == RTEMS_RFS_DIR_ENTRY_EMPTY) + break; + + if ((elength < RTEMS_RFS_DIR_ENTRY_SIZE) || + (elength >= rtems_rfs_fs_max_name (fs))) + { + printf (" %5d: entry length appears corrupt: %d\n", entry, elength); + break; + } + + if ((eino < RTEMS_RFS_ROOT_INO) || (eino >= rtems_rfs_fs_inodes (fs))) + { + printf (" %5d: entry ino appears corrupt: ino=%ld\n", entry, eino); + break; + } + + length = elength - RTEMS_RFS_DIR_ENTRY_SIZE; + + printf (" %5d: %04x inode=%-6u hash=%08x name[%03u]=", + entry, b, + rtems_rfs_dir_entry_ino (data), + rtems_rfs_dir_entry_hash (data), + length); + + if (length > 50) + length = 50; + + for (c = 0; c < length; c++) + printf ("%c", data[RTEMS_RFS_DIR_ENTRY_SIZE + c]); + if (length < elength - RTEMS_RFS_DIR_ENTRY_SIZE) + printf ("..."); + printf ("\n"); + + b += elength; + data += elength; + entry++; + } + + rc = rtems_rfs_buffer_handle_close (fs, &buffer); + if (rc > 0) + { + rtems_rfs_shell_unlock_rfs (fs); + printf ("error: closing buffer handle: block=%lu: (%d) %s\n", + block, rc, strerror (rc)); + return 1; + } + + rtems_rfs_shell_unlock_rfs (fs); + + return 0; +} + +static int +rtems_rfs_shell_group (rtems_rfs_file_system* fs, int argc, char *argv[]) +{ + int start; + int end; + int g; + + start = 0; + end = fs->group_count - 1; + + switch (argc) + { + case 1: + break; + case 2: + start = end = strtoul (argv[1], 0, 0); + break; + case 3: + start = strtoul (argv[1], 0, 0); + end = strtoul (argv[2], 0, 0); + break; + default: + printf ("error: too many arguments.\n"); + return 1; + } + + if ((start < 0) || (end < 0) || + (start >= fs->group_count) || (end >= fs->group_count)) + { + printf ("error: group out of range (0->%d).\n", fs->group_count); + return 1; + } + + rtems_rfs_shell_lock_rfs (fs); + + for (g = start; g <= end; g++) + { + rtems_rfs_group* group = &fs->groups[g]; + size_t blocks; + size_t inodes; + blocks = group->size - rtems_rfs_bitmap_map_free (&group->block_bitmap); + inodes = fs->group_inodes - rtems_rfs_bitmap_map_free (&group->inode_bitmap); + printf (" %4d: base=%-7lu size=%-6lu blocks=%-5lu (%3lu%%) inode=%-5lu (%3lu%%)\n", + g, group->base, group->size, + blocks, (blocks * 100) / group->size, + inodes, (inodes * 100) / fs->group_inodes); + } + + rtems_rfs_shell_unlock_rfs (fs); + + return 0; +} + + +void +rtems_rfs_shell_usage (const char* arg) +{ + printf ("%s: RFS debugger\n", arg); + printf (" %s [-hl] <path> <command>\n", arg); + printf (" where:\n"); + printf (" path: Path to the mounted RFS file system\n"); + printf (" command: A debugger command. See -l for a list plus help.\n"); + printf (" -h: This help\n"); + printf (" -l: The debugger command list.\n"); +} + +int +rtems_rfs_shell_debugrfs (int argc, char *argv[]) +{ + const rtems_rfs_shell_cmd table[] = + { + { "block", rtems_rfs_shell_block, + "Display the contents of a block, block <bno>, block <bno>..<bno>" }, + { "data", rtems_rfs_shell_data, + "Display file system data, data" }, + { "dir", rtems_rfs_shell_dir, + "Display a block as a table for directory entrie, dir <bno>" }, + { "group", rtems_rfs_shell_group, + "Display the group data of a file system, group, group <group>, group <start> <end>" }, + { "inode", rtems_rfs_shell_inode, + "Display an inode, inode <ino>, inode> <ino>..<ino>" } + }; + + int arg; + int t; + + for (arg = 1; arg < argc; arg++) + { + if (argv[arg][0] != '-') + break; + + switch (argv[arg][1]) + { + case 'h': + rtems_rfs_shell_usage (argv[0]); + return 0; + case 'l': + printf ("%s: commands are:\n", argv[0]); + for (t = 0; t < (sizeof (table) / sizeof (const rtems_rfs_shell_cmd)); t++) + printf (" %s\t\t%s\n", table[t].name, table[t].help); + return 0; + default: + printf ("error: unknown option: %s\n", argv[arg]); + return 1; + } + } + + if ((argc - arg) < 2) + printf ("error: you need at least a path and command, try %s -h\n", argv[0]); + else + { + rtems_rfs_file_system* fs; + if (rtems_rfs_get_fs (argv[arg], &fs) == 0) + { + for (t = 0; t < (sizeof (table) / sizeof (const rtems_rfs_shell_cmd)); t++) + if (strcmp (argv[arg + 1], table[t].name) == 0) + return table[t].handler (fs, argc - 2, argv + 2); + printf ("error: command not found: %s\n", argv[arg + 1]); + } + } + + return 1; +} |