/* * COPYRIGHT (c) 2010 Chris Johns * * 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 #include #include #include #include #include #include #include #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; 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: %zu\n", rtems_rfs_fs_blocks (fs)); printf (" block size: %zu\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: %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: %ld\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=%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:%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=%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=%-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] \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 , block .." }, { "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 " }, { "group", rtems_rfs_shell_group, "Display the group data of a file system, group, group , group " }, { "inode", rtems_rfs_shell_inode, "Display an inode, inode , inode> .." } }; 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 (rtems_rfs_format (driver, &config) < 0) { printf ("error: format of %s failed: %s\n", driver, strerror (errno)); return 1; } return 0; }