1/*
2 * Copyright 2008-2017, 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("%9" FSSH_B_PRIu64 " nodes processed\x1b[1A\n",
59				counter);
60		}
61
62		if (result.pass == BFS_CHECK_PASS_BITMAP) {
63			if (result.errors) {
64				fssh_dprintf("%s (inode = %" FSSH_B_PRIdINO ")", result.name,
65					result.inode);
66				if ((result.errors & BFS_MISSING_BLOCKS) != 0)
67					fssh_dprintf(", some blocks weren't allocated");
68				if ((result.errors & BFS_BLOCKS_ALREADY_SET) != 0)
69					fssh_dprintf(", has blocks already set");
70				if ((result.errors & BFS_INVALID_BLOCK_RUN) != 0)
71					fssh_dprintf(", has invalid block run(s)");
72				if ((result.errors & BFS_COULD_NOT_OPEN) != 0)
73					fssh_dprintf(", could not be opened");
74				if ((result.errors & BFS_WRONG_TYPE) != 0)
75					fssh_dprintf(", has wrong type");
76				if ((result.errors & BFS_NAMES_DONT_MATCH) != 0)
77					fssh_dprintf(", names don't match");
78				if ((result.errors & BFS_INVALID_BPLUSTREE) != 0)
79					fssh_dprintf(", invalid b+tree");
80				fssh_dprintf("\n");
81			}
82
83			if ((result.mode & (S_INDEX_DIR | 0777)) == S_INDEX_DIR)
84				indices++;
85			else if (result.mode & S_ATTR_DIR)
86				attributeDirectories++;
87			else if (result.mode & S_ATTR)
88				attributes++;
89			else if (S_ISDIR(result.mode))
90				directories++;
91			else
92				files++;
93		} else if (result.pass == BFS_CHECK_PASS_INDEX) {
94			if (previousPass != result.pass) {
95				fssh_dprintf("Recreating broken index b+trees...\n");
96				previousPass = result.pass;
97				counter = 0;
98			}
99		}
100	}
101
102	// stop checking
103	if (_kern_ioctl(rootDir, BFS_IOCTL_STOP_CHECKING, &result, sizeof(result))
104			!= B_OK) {
105		_kern_close(rootDir);
106		return errno;
107	}
108
109	_kern_close(rootDir);
110
111	fssh_dprintf("        %" FSSH_B_PRIu64 " nodes checked,\n\t%" FSSH_B_PRIu64
112		" blocks not allocated,\n\t%" FSSH_B_PRIu64 " blocks already set,\n\t%"
113		B_PRIu64 " blocks could be freed\n\n", counter, result.stats.missing,
114		result.stats.already_set, result.stats.freed);
115	fssh_dprintf("\tfiles\t\t%" FSSH_B_PRIu64 "\n\tdirectories\t%"
116		FSSH_B_PRIu64 "\n"
117		"\tattributes\t%" FSSH_B_PRIu64 "\n\tattr. dirs\t%" FSSH_B_PRIu64 "\n"
118		"\tindices\t\t%" FSSH_B_PRIu64 "\n", files, directories, attributes,
119		attributeDirectories, indices);
120
121	fssh_dprintf("\n\tdirect block runs\t\t%" FSSH_B_PRIu64 " (%" FSSH_B_PRIu64
122		")\n", result.stats.direct_block_runs,
123		result.stats.blocks_in_direct * result.stats.block_size);
124	fssh_dprintf("\tindirect block runs\t\t%" FSSH_B_PRIu64 " (in %"
125		FSSH_B_PRIu64 " array blocks, %" FSSH_B_PRIu64 ")\n",
126		result.stats.indirect_block_runs, result.stats.indirect_array_blocks,
127		result.stats.blocks_in_indirect * result.stats.block_size);
128	fssh_dprintf("\tdouble indirect block runs\t%" FSSH_B_PRIu64 " (in %"
129		FSSH_B_PRIu64 " array blocks, %" FSSH_B_PRIu64 ")\n",
130		result.stats.double_indirect_block_runs,
131		result.stats.double_indirect_array_blocks,
132		result.stats.blocks_in_double_indirect * result.stats.block_size);
133
134	if (result.status == B_ENTRY_NOT_FOUND)
135		result.status = B_OK;
136
137	return result.status;
138}
139
140
141}	// namespace FSShell
142