summaryrefslogtreecommitdiffstats
path: root/cpukit/libfs/src/rfs/rtems-rfs-shell.c
diff options
context:
space:
mode:
Diffstat (limited to 'cpukit/libfs/src/rfs/rtems-rfs-shell.c')
-rw-r--r--cpukit/libfs/src/rfs/rtems-rfs-shell.c753
1 files changed, 753 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..63931752cf
--- /dev/null
+++ b/cpukit/libfs/src/rfs/rtems-rfs-shell.c
@@ -0,0 +1,753 @@
+/*
+ * 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
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <inttypes.h>
+#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 <rtems/rtems-rfs-format.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
+{
+ 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;
+
+ printf ("RFS Filesystem Data\n");
+ printf (" flags: %08" PRIx32 "\n", fs->flags);
+#if 0
+ printf (" device: %08lx\n", rtems_rfs_fs_device (fs));
+#endif
+ printf (" blocks: %zu\n", rtems_rfs_fs_blocks (fs));
+ printf (" block size: %zu\n", rtems_rfs_fs_block_size (fs));
+ printf (" size: %" PRIu64 "\n", rtems_rfs_fs_size (fs));
+ printf (" media block size: %" PRIu32 "\n", rtems_rfs_fs_media_block_size (fs));
+ printf (" media size: %" PRIu64 "\n", rtems_rfs_fs_media_size (fs));
+ printf (" inodes: %" PRIu32 "\n", rtems_rfs_fs_inodes (fs));
+ printf (" bad blocks: %" PRIu32 "\n", fs->bad_blocks);
+ printf (" max. name length: %" PRIu32 "\n", rtems_rfs_fs_max_name (fs));
+ printf (" groups: %d\n", fs->group_count);
+ printf (" group blocks: %zd\n", fs->group_blocks);
+ printf (" group inodes: %zd\n", fs->group_inodes);
+ printf (" inodes per block: %zd\n", fs->inodes_per_block);
+ printf (" blocks per block: %zd\n", fs->blocks_per_block);
+ printf (" singly blocks: %zd\n", fs->block_map_singly_blocks);
+ printf (" doublly blocks: %zd\n", fs->block_map_doubly_blocks);
+ printf (" max. held buffers: %" PRId32 "\n", fs->max_held_buffers);
+
+ rtems_rfs_shell_lock_rfs (fs);
+
+ rtems_rfs_group_usage (fs, &blocks, &inodes);
+
+ 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: %zd (%d.%d%%)\n",
+ blocks, bpcent / 10, bpcent % 10);
+ printf (" inodes used: %zd (%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=%" PRIu32 ": (%d) %s\n",
+ block, rc, strerror (rc));
+ return 1;
+ }
+
+ printf (" %5" PRIu32 ": 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=%" PRIu32 ": (%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=%" PRIu32 ": (%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=%" PRIu32 ": (%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 >= total) || (end >= total))
+ {
+ printf ("error: inode out of range (0->%" PRId32 ").\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=%" PRIu32 ": (%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=%" PRIu32 ": (%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 (" %5" PRIu32 ": pos=%06" PRIu32 ":%04zx %c ",
+ ino, rtems_rfs_buffer_bnum (&inode.buffer),
+ inode.offset * RTEMS_RFS_INODE_SIZE,
+ 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=%04" PRIu32 " 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 ("%" PRIu32 " ", rtems_rfs_inode_get_block (&inode, b));
+ printf ("%" PRIu32 "]\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=%" PRIu32 ": (%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=%" PRIu32 ": (%d) %s\n",
+ block, rc, strerror (rc));
+ return 1;
+ }
+
+ printf (" %5" PRIu32 ": 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=%" PRIu32 ": (%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=%" PRIu32 ": (%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=%" PRId32 "\n", entry, eino);
+ break;
+ }
+
+ length = elength - RTEMS_RFS_DIR_ENTRY_SIZE;
+
+ printf (" %5d: %04x inode=%-6" PRIu32 " hash=%08" PRIx32 " 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=%" PRIu32 ": (%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=%-7" PRIu32 " size=%-6zu blocks=%-5zu (%3zu%%) inode=%-5zu (%3zu%%)\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_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;
+}
+
+int
+rtems_shell_rfs_format (int argc, char* argv[])
+{
+ rtems_rfs_format_config config;
+ const char* driver = NULL;
+ int arg;
+
+ memset (&config, 0, sizeof (rtems_rfs_format_config));
+
+ for (arg = 1; arg < argc; arg++)
+ {
+ if (argv[arg][0] == '-')
+ {
+ switch (argv[arg][1])
+ {
+ case 'v':
+ config.verbose = true;
+ break;
+
+ case 's':
+ arg++;
+ if (arg >= argc)
+ {
+ printf ("error: block size needs an argument\n");
+ return 1;
+ }
+ config.block_size = strtoul (argv[arg], 0, 0);
+ break;
+
+ case 'b':
+ arg++;
+ if (arg >= argc)
+ {
+ printf ("error: group block count needs an argument\n");
+ return 1;
+ }
+ config.group_blocks = strtoul (argv[arg], 0, 0);
+ break;
+
+ case 'i':
+ arg++;
+ if (arg >= argc)
+ {
+ printf ("error: group inode count needs an argument\n");
+ return 1;
+ }
+ config.group_inodes = strtoul (argv[arg], 0, 0);
+ break;
+
+ case 'I':
+ config.initialise_inodes = true;
+ break;
+
+ case 'o':
+ arg++;
+ if (arg >= argc)
+ {
+ printf ("error: inode percentage overhead needs an argument\n");
+ return 1;
+ }
+ config.inode_overhead = strtoul (argv[arg], 0, 0);
+ break;
+
+ default:
+ printf ("error: invalid option: %s\n", argv[arg]);
+ return 1;
+ }
+ }
+ else
+ {
+ if (!driver)
+ driver = argv[arg];
+ else
+ {
+ printf ("error: only one driver name allowed: %s\n", argv[arg]);
+ return 1;
+ }
+ }
+ }
+
+ if (!driver) {
+ printf ("error: no driver name provided\n");
+ return 1;
+ }
+
+ if (rtems_rfs_format (driver, &config) < 0)
+ {
+ printf ("error: format of %s failed: %s\n",
+ driver, strerror (errno));
+ return 1;
+ }
+
+ return 0;
+}