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

#include <sys/stat.h>
#include <unistd.h>
#include "crash.h"

PRIVATE addr_t file();
const commandtable_t command_file =
	{"file", file, "[-f] [address]", "print file table\n  -f  print detail"};

PRIVATE addr_t files_stat();
const commandtable_t command_files_stat =
	{"files_stat", files_stat, "", "print files_stat_struct"};

PRIVATE addr_t file_lock();
const commandtable_t command_file_lock =
	{"file_lock", file_lock, "[-a] [-b] [-f] [address]", "print file_lock table\n  -a  follow link\n  -b  follow block link\n  -f  show detail"};

extern addr_t super_blocks_addr;
addr_t files_stat_addr;
addr_t file_lock_list_addr;

extern addr_t print_file();
extern addr_t print_super_block_filelist();
extern void print_files_stat();
extern addr_t print_file_lock();

PRIVATE addr_t
file()
{
	int i, c;
	int full = 0;
	addr_t addr;
	extern void prhead_file();

	while ((c = getopt(argcnt, args, "f")) != EOF) {
		switch (c) {
		case 'f':
			full = 1;
			break;
		default:
			THROW(usage);
		}
	}

	if (argcnt > optind) {
		if (!full) prhead_file();
		for (i = optind; i < argcnt; i++) {
			addr = getvalue(args[i]);
			if (full) prhead_file();
			addr = print_file(addr, full);
		}
	} else {
		struct list_head super_blocks;
		GETADDR(super_blocks);
		memread(super_blocks_addr, sizeof(super_blocks), &super_blocks,
			"super_blocks");
		prhead_file();
		for (addr = (addr_t)super_blocks.next; addr && addr != super_blocks_addr;) {
			addr = print_super_block_filelist(addr, full);
		}
		addr = 0;
	}
	return addr;
}

PRIVATE addr_t
files_stat()
{
	int c;

	while ((c = getopt(argcnt, args, "")) != EOF) {
		THROW(usage);
	}
	GETADDR(files_stat);
	print_files_stat(files_stat_addr);
	return 0;
}

PRIVATE addr_t
file_lock()
{
	int c, i, full = 0, follow = 0, block = 0;
	addr_t addr = 0;
	extern void prhead_file_lock();

	while ((c = getopt(argcnt, args, "abf")) != EOF) {
		switch (c) {
		case 'a':
			follow = 1;
			break;
		case 'b':
			block = 1;
			break;
		case 'f':
			full = 1;
			break;
		default:
			THROW(usage);
		}
	}

	if (follow && block) THROW(usage);

	if (argcnt > optind) {
		if (!full) prhead_file_lock();
		for (i = optind; i < argcnt; i++) {
			addr = getvalue(args[i]);
			if (full) prhead_file_lock();
			if (block) {
				addr_t start = addr;
				do {
					addr = print_file_lock(addr, full, 2);
				} while (addr && start != addr);
				mprintf("\n");
			} else {
				do {
					addr = print_file_lock(addr, full, 0);
				} while (follow && addr);
			}
		}
	} else {
		if (follow || block) THROW(usage);

		GETADDR(file_lock_list);
		memread(file_lock_list_addr, sizeof(addr), &addr, "file_lock_list");

		if (!full) prhead_file_lock();
		while (addr && file_lock_list_addr != addr) {
			if (full) prhead_file_lock();
			addr = print_file_lock(addr, full, 1);
		}
	}
	return addr;
}
