1/*
2 * Copyright 2008-2012, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include "fssh_stdio.h"
8#include "syscalls.h"
9
10#include "bfs.h"
11#include "bfs_control.h"
12
13
14namespace FSShell {
15
16
17fssh_status_t
18command_checkfs(int argc, const char* const* argv)
19{
20	if (argc == 2 && !strcmp(argv[1], "--help")) {
21		fssh_dprintf("Usage: %s [-c]\n"
22			"  -c  Check only; don't perform any changes\n", argv[0]);
23		return B_OK;
24	}
25
26	bool checkOnly = false;
27	if (argc == 2 && !strcmp(argv[1], "-c"))
28		checkOnly = true;
29
30	int rootDir = _kern_open_dir(-1, "/myfs");
31	if (rootDir < 0)
32		return rootDir;
33
34	struct check_control result;
35	memset(&result, 0, sizeof(result));
36	result.magic = BFS_IOCTL_CHECK_MAGIC;
37	result.flags = 0;
38	if (!checkOnly) {
39		result.flags |= BFS_FIX_BITMAP_ERRORS | BFS_REMOVE_WRONG_TYPES
40			| BFS_REMOVE_INVALID | BFS_FIX_NAME_MISMATCHES | BFS_FIX_BPLUSTREES;
41	}
42
43	// start checking
44	fssh_status_t status = _kern_ioctl(rootDir, BFS_IOCTL_START_CHECKING,
45		&result, sizeof(result));
46	if (status != B_OK)
47	    return status;
48
49	uint64 attributeDirectories = 0, attributes = 0;
50	uint64 files = 0, directories = 0, indices = 0;
51	uint64 counter = 0;
52	uint32 previousPass = result.pass;
53
54	// check all files and report errors
55	while (_kern_ioctl(rootDir, BFS_IOCTL_CHECK_NEXT_NODE, &result,
56			sizeof(result)) == B_OK) {
57		if (++counter % 50 == 0)
58			fssh_dprintf("%9Ld nodes processed\x1b[1A\n", counter);
59
60		if (result.pass == BFS_CHECK_PASS_BITMAP) {
61			if (result.errors) {
62				fssh_dprintf("%s (inode = %lld)", result.name, result.inode);
63				if ((result.errors & BFS_MISSING_BLOCKS) != 0)
64					fssh_dprintf(", some blocks weren't allocated");
65				if ((result.errors & BFS_BLOCKS_ALREADY_SET) != 0)
66					fssh_dprintf(", has blocks already set");
67				if ((result.errors & BFS_INVALID_BLOCK_RUN) != 0)
68					fssh_dprintf(", has invalid block run(s)");
69				if ((result.errors & BFS_COULD_NOT_OPEN) != 0)
70					fssh_dprintf(", could not be opened");
71				if ((result.errors & BFS_WRONG_TYPE) != 0)
72					fssh_dprintf(", has wrong type");
73				if ((result.errors & BFS_NAMES_DONT_MATCH) != 0)
74					fssh_dprintf(", names don't match");
75				if ((result.errors & BFS_INVALID_BPLUSTREE) != 0)
76					fssh_dprintf(", invalid b+tree");
77				fssh_dprintf("\n");
78			}
79
80			if ((result.mode & (S_INDEX_DIR | 0777)) == S_INDEX_DIR)
81				indices++;
82			else if (result.mode & S_ATTR_DIR)
83				attributeDirectories++;
84			else if (result.mode & S_ATTR)
85				attributes++;
86			else if (S_ISDIR(result.mode))
87				directories++;
88			else
89				files++;
90		} else if (result.pass == BFS_CHECK_PASS_INDEX) {
91			if (previousPass != result.pass) {
92				fssh_dprintf("Recreating broken index b+trees...\n");
93				previousPass = result.pass;
94				counter = 0;
95			}
96		}
97	}
98
99	// stop checking
100	if (_kern_ioctl(rootDir, BFS_IOCTL_STOP_CHECKING, &result, sizeof(result))
101			!= B_OK) {
102		_kern_close(rootDir);
103		return errno;
104	}
105
106	_kern_close(rootDir);
107
108	fssh_dprintf("        %" B_PRIu64 " nodes checked,\n\t%" B_PRIu64 " blocks "
109		"not allocated,\n\t%" B_PRIu64 " blocks already set,\n\t%" B_PRIu64
110		" blocks could be freed\n\n", counter, result.stats.missing,
111		result.stats.already_set, result.stats.freed);
112	fssh_dprintf("\tfiles\t\t%" B_PRIu64 "\n\tdirectories\t%" B_PRIu64 "\n"
113		"\tattributes\t%" B_PRIu64 "\n\tattr. dirs\t%" B_PRIu64 "\n"
114		"\tindices\t\t%" B_PRIu64 "\n", files, directories, attributes,
115		attributeDirectories, indices);
116
117	fssh_dprintf("\n\tdirect block runs\t\t%" B_PRIu64 " (%lld)\n",
118		result.stats.direct_block_runs,
119		result.stats.blocks_in_direct * result.stats.block_size);
120	fssh_dprintf("\tindirect block runs\t\t%" B_PRIu64 " (in %" B_PRIu64
121		" array blocks, %lld)\n", result.stats.indirect_block_runs,
122		result.stats.indirect_array_blocks,
123		result.stats.blocks_in_indirect * result.stats.block_size);
124	fssh_dprintf("\tdouble indirect block runs\t%" B_PRIu64 " (in %" B_PRIu64
125		" array blocks, %lld)\n", result.stats.double_indirect_block_runs,
126		result.stats.double_indirect_array_blocks,
127		result.stats.blocks_in_double_indirect * result.stats.block_size);
128
129	if (result.status == B_ENTRY_NOT_FOUND)
130		result.status = B_OK;
131
132	return result.status;
133}
134
135
136}	// namespace FSShell
137