Skip to content

Instantly share code, notes, and snippets.

@rdnajac
Created February 9, 2024 20:39
Show Gist options
  • Save rdnajac/cc327902deb54098dd474076c60e16cc to your computer and use it in GitHub Desktop.
Save rdnajac/cc327902deb54098dd474076c60e16cc to your computer and use it in GitHub Desktop.
debugging tool for EZFS
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>
#include <fcntl.h>
#define timespec64 timespec
#include "../ezfs.h"
static void print_sb(struct ezfs_super_block *sb);
static void print_inode(struct ezfs_inode *inode);
static void print_inode_store(struct ezfs_super_block *sb, struct ezfs_inode *inode_store, int inode_n);
static void print_dentries(struct ezfs_dir_entry *dentries);
static void usage_and_exit(const char *argv0)
{
fprintf(stderr, "Usage: %s [-s | -i [<inode_number>] | -d <inode_number> | [-b | -n] <block_number>] [DEVICE_NAME]\n", argv0);
exit(EXIT_FAILURE);
}
static void die(const char *s)
{
perror(s);
exit(EXIT_FAILURE);
}
void *read_block(int fd)
{
void *block = malloc(EZFS_BLOCK_SIZE);
if (block == NULL || read(fd, block, EZFS_BLOCK_SIZE) == -1) {
free(block);
die(__func__);
}
return block;
}
static void print_help(const char *argv0)
{
printf("Usage: %s [-s | -i [<inode_number>] | -d <inode_number> | -b <block_number>] [DEVICE_NAME]\n", argv0);
printf("Options:\n");
printf(" -s Print super block information\n");
printf(" -i [<inode_number>] Print information for a specific inode number (default: prints all)\n");
printf(" -d <inode_number> Print directory entries at a specific inode number\n");
printf(" -b <block_number> Print data block data for a specific block number\n");
printf(" -n <block_number> Print list of blocks in indirect_blk_n");
printf(" -h Print this help message\n");
printf("DEVICE_NAME Optional device name (default: /dev/loop0)\n");
exit(EXIT_SUCCESS);
}
int main(int argc, char *argv[])
{
int option, print_super = 0, inode_n = 0, dir_inode = 0, blk_n = 0, iblk_n = 0;
uint64_t offset = 0, blk_data = 0;
while ((option = getopt(argc, argv, "si::d:b:n:h")) != -1) {
switch (option) {
case 's':
print_super = 1;
break;
case 'i':
inode_n = (optarg != NULL) ? atoi(optarg) : -1;
break;
case 'd':
dir_inode = atoi(optarg);
break;
case 'b':
blk_n = atoi(optarg);
break;
case 'n':
iblk_n = atoi(optarg);
break;
case 'h':
print_help(argv[0]);
default:
usage_and_exit(argv[0]);
}
}
const char *filename = (optind < argc) ? argv[optind] : "/dev/loop0";
int fd = open(filename, O_RDONLY);
if (fd == -1)
die("Error opening the device");
struct ezfs_super_block *sb = read_block(fd);
struct ezfs_inode *inode_store = read_block(fd);
if (print_super)
print_sb(sb);
if (inode_n)
print_inode_store(sb, inode_store, inode_n);
if (dir_inode) {
if (IS_SET(sb->free_inodes, dir_inode - 1)) {
offset = EZFS_BLOCK_SIZE * (inode_store[dir_inode - 1].direct_blk_n - 2);
lseek(fd, offset, SEEK_CUR);
struct ezfs_dir_entry *dentries = read_block(fd);
printf("Directory Entries for Inode %d:\n", dir_inode);
print_dentries(dentries);
free(dentries);
} else {
die("Invalid or unused directory inode number");
}
}
if (blk_n >= 2) {
offset = (blk_n - 2) * EZFS_BLOCK_SIZE;
lseek(fd, offset, SEEK_CUR);
printf("Data at blk_n = %d (offset = %lu);\n", blk_n, offset);
for (uint64_t bytes = 0; bytes < EZFS_BLOCK_SIZE; ) {
bytes += read(fd, &blk_data, sizeof(blk_data));
if (!((bytes / sizeof(uint64_t)) % 8))
printf("\n0x%03lx\t", bytes);
printf("%016lx ", blk_data);
}
printf("\n");
}
if (iblk_n >= 2) {
offset = (iblk_n - 2) * EZFS_BLOCK_SIZE;
lseek(fd, offset, SEEK_CUR);
printf("Data at indirect_blk_n = %d (offset = %lu):\n", iblk_n, offset);
for (uint64_t bytes = 0; bytes < EZFS_BLOCK_SIZE; ) {
bytes += read(fd, &blk_data, sizeof(blk_data));
if (!blk_data)
break;
printf("%lu\n", blk_data);
}
printf("\n");
}
free(sb);
free(inode_store);
close(fd);
return EXIT_SUCCESS;
}
static void print_sb(struct ezfs_super_block *sb)
{
int count = 0;
printf("ezfs_super_block info:\n");
printf("version: %lu\n", sb->version);
printf("magic: 0x%lx\n", sb->magic);
printf("disk_blks: %lu\n", sb->disk_blks);
printf("EZFS_BLOCK_SIZE: %d\n", EZFS_BLOCK_SIZE);
printf("EZFS_MAX_INODES = EZFS_BLOCK_SIZE / sizeof(struct ezfs_inode) = %d / %lu = %lu\n",
EZFS_BLOCK_SIZE, sizeof(struct ezfs_inode), EZFS_MAX_INODES);
printf("EZFS_MAX_CHILDREN = EZFS_BLOCK_SIZE / sizeof(struct ezfs_dir_entry) = %d / %lu = %lu\n",
EZFS_BLOCK_SIZE, sizeof(struct ezfs_dir_entry), EZFS_MAX_CHILDREN);
printf("EZFS_MAX_DATA_BLKS: %lu\n", EZFS_MAX_DATA_BLKS);
printf("\ninode bit vector: ");
for (size_t i = 0; i < EZFS_MAX_INODES; i++) {
if (IS_SET(sb->free_inodes, i)) {
printf("1");
count++;
} else {
printf("0");
}
}
printf("\t %d/%ld free", count, EZFS_MAX_INODES);
printf("\n\ndata block bit vector:\n");
for (size_t i = 0; i < sb->disk_blks; ++i) {
if (i % 64 == 0)
printf("\n0x%03lx\t", i);
printf("%d", IS_SET(sb->free_data_blocks, i) ? 1 : 0);
if (i % 32 == 31)
printf(" ");
}
printf("\n");
}
static void print_inode_store(struct ezfs_super_block *sb,
struct ezfs_inode *inode_store, int inode_n)
{
if (inode_n > 0) {
if (IS_SET(sb->free_inodes, inode_n - 1)) {
printf("Inode %d:\n", inode_n);
print_inode(&inode_store[inode_n - 1]);
} else {
die("Invalid or unused inode number");
}
}
if (inode_n == -1) {
for (int i = 0; i < EZFS_MAX_INODES; ++i) {
if (IS_SET(sb->free_inodes, i)) {
printf("Inode %d:\n", i + 1);
print_inode(&inode_store[i]);
}
}
}
}
static void print_inode(struct ezfs_inode *inode)
{
printf("Mode: %o\n", inode->mode);
printf("UID: %u\n", inode->uid);
printf("GID: %u\n", inode->gid);
printf("Access Time: %ld\n", inode->i_atime.tv_sec);
printf("Modified Time: %ld\n", inode->i_mtime.tv_sec);
printf("Change Time: %ld\n", inode->i_ctime.tv_sec);
printf("Number of Links: %u\n", inode->nlink);
printf("Direct Block Number: %lu\n", inode->direct_blk_n);
printf("Indirect Block Number: %lu\n", inode->indirect_blk_n);
printf("File Size: %lu\n", inode->file_size);
printf("Number of Blocks: %lu\n", inode->nblocks);
printf("\n");
}
static void print_dentries(struct ezfs_dir_entry *dentry)
{
for (int i = 0; i < EZFS_MAX_CHILDREN; i++)
printf("%d:\tinode_no: %lu\tfilename: %s\t%s\n",
i, dentry[i].inode_no, dentry[i].filename,
dentry[i].active ? "active" : "inactive");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment