/*
 * Copyright (C) 2000-2002 ASANO Masahiro
 */

#include <unistd.h>
#include "crash.h"

PRIVATE addr_t operations();
const commandtable_t command_operations =
        {"operations", operations, "-d|-f|-i|-s|-q address", "print dentry, file, inode, super or dquot operations"};

PRIVATE const char *file_op[] = {
	"FILE OPERATIONS",
	"lseek", "read", "write", "readdir", "poll", "ioctl", "mmap",
	"open", "flush", "release", "fsync", "fasync", "check_media_change",
	"revalidate", "lock",
	NULL
};

PRIVATE const char *inode_op[] = {
	"INODE OPERATIONS",
	"default_file_ops", "create", "lookup", "link", "unlink", "symlink",
	"mkdir", "rmdir", "mknod", "rename", "readlink", "follow_link",
	"readpage", "writepage", "bmap", "truncate", "permission",
	"smap","updatepage", "revalidate",
	NULL
};

PRIVATE const char *super_op[] = {
	"SUPER OPERATIONS",
	"read_inode", "write_inode", "put_inode", "delete_inode",
	"notify_change", "put_super", "write_super", "statfs", "remount_fs",
	"clear_inode", "umount_begin",
	NULL
};

PRIVATE const char *dquot_op[] = {
	"DQUOT OPERATIONS",
	"initialize", "drop", "alloc_block", "alloc_inode", "free_block",
	"free_inode", "transfer",
	NULL
};

PRIVATE const char *dentry_op[] = {
	"DENTRY OPERATIONS",
	"revalidate", "hash", "compare", "delete", "release", "iput",
	NULL
};

const char head_operations[] = "%20s:   ADDRESS  SYMBOL\n";

void
print_operations(addr, op)
	const char **op;
{
	addr_t buf[32];
	const char *p;
	int i;

	memread(addr, sizeof(buf), buf, "operations");
	mprintf(head_operations, op[0]);
	for (i = 1; op[i]; i++) {
		p = getsymstr(buf[i - 1]);
		mprintf("%20s:  %8lx  %s\n", op[i], buf[i - 1], p? p: "-");
	}
}

PRIVATE addr_t
operations()
{
	int i, c;
	const char **op = NULL;
	addr_t addr;

	while ((c = getopt(argcnt, args, "fisqd")) != EOF) {
		switch (c) {
		case 'f':
			op = file_op;
			break;
		case 'i':
			op = inode_op;
			break;
		case 's':
			op = super_op;
			break;
		case 'q':
			op = dquot_op;
			break;
		case 'd':
			op = dentry_op;
			break;
		default:
			THROW(usage);
		}
	}
	if (op == NULL || optind == argcnt) {
		THROW(usage);
	}

	for (i = optind; i < argcnt; i++) {
		addr = getaddr(args[i]);
		print_operations(addr, op);
	}
	return 0;
}
