xref: /haiku/src/tools/bfs_shell/command_checkfs.cpp (revision e9091262c5c012254c4f2cb1ff8a604cfdaddf5e)
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 
14 namespace FSShell {
15 
16 
17 fssh_status_t
18 command_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 
53 	// check all files and report errors
54 	while (_kern_ioctl(rootDir, BFS_IOCTL_CHECK_NEXT_NODE, &result,
55 			sizeof(result)) == B_OK) {
56 		if (++counter % 50 == 0)
57 			fssh_dprintf("%9Ld nodes processed\x1b[1A\n", counter);
58 
59 		if (result.errors) {
60 			fssh_dprintf("%s (inode = %lld)", result.name, result.inode);
61 			if ((result.errors & BFS_MISSING_BLOCKS) != 0)
62 				fssh_dprintf(", some blocks weren't allocated");
63 			if ((result.errors & BFS_BLOCKS_ALREADY_SET) != 0)
64 				fssh_dprintf(", has blocks already set");
65 			if ((result.errors & BFS_INVALID_BLOCK_RUN) != 0)
66 				fssh_dprintf(", has invalid block run(s)");
67 			if ((result.errors & BFS_COULD_NOT_OPEN) != 0)
68 				fssh_dprintf(", could not be opened");
69 			if ((result.errors & BFS_WRONG_TYPE) != 0)
70 				fssh_dprintf(", has wrong type");
71 			if ((result.errors & BFS_NAMES_DONT_MATCH) != 0)
72 				fssh_dprintf(", names don't match");
73 			if ((result.errors & BFS_INVALID_BPLUSTREE) != 0)
74 				fssh_dprintf(", invalid b+tree");
75 			fssh_dprintf("\n");
76 		}
77 		if ((result.mode & (S_INDEX_DIR | 0777)) == S_INDEX_DIR)
78 			indices++;
79 		else if (result.mode & S_ATTR_DIR)
80 			attributeDirectories++;
81 		else if (result.mode & S_ATTR)
82 			attributes++;
83 		else if (S_ISDIR(result.mode))
84 			directories++;
85 		else
86 			files++;
87 	}
88 
89 	// stop checking
90 	if (_kern_ioctl(rootDir, BFS_IOCTL_STOP_CHECKING, &result, sizeof(result))
91 			!= B_OK) {
92 		_kern_close(rootDir);
93 		return errno;
94 	}
95 
96 	_kern_close(rootDir);
97 
98 	fssh_dprintf("\t%" B_PRIu64 " nodes checked,\n\t%" B_PRIu64 " blocks not "
99 		"allocated,\n\t%" B_PRIu64 " blocks already set,\n\t%" B_PRIu64
100 		" blocks could be freed\n\n", counter, result.stats.missing,
101 		result.stats.already_set, result.stats.freed);
102 	fssh_dprintf("\tfiles\t\t%" B_PRIu64 "\n\tdirectories\t%" B_PRIu64 "\n"
103 		"\tattributes\t%" B_PRIu64 "\n\tattr. dirs\t%" B_PRIu64 "\n"
104 		"\tindices\t\t%" B_PRIu64 "\n", files, directories, attributes,
105 		attributeDirectories, indices);
106 
107 	fssh_dprintf("\n\tdirect block runs\t\t%" B_PRIu64 " (%lld)\n",
108 		result.stats.direct_block_runs,
109 		result.stats.blocks_in_direct * result.stats.block_size);
110 	fssh_dprintf("\tindirect block runs\t\t%" B_PRIu64 " (in %" B_PRIu64
111 		" array blocks, %lld)\n", result.stats.indirect_block_runs,
112 		result.stats.indirect_array_blocks,
113 		result.stats.blocks_in_indirect * result.stats.block_size);
114 	fssh_dprintf("\tdouble indirect block runs\t%" B_PRIu64 " (in %" B_PRIu64
115 		" array blocks, %lld)\n", result.stats.double_indirect_block_runs,
116 		result.stats.double_indirect_array_blocks,
117 		result.stats.blocks_in_double_indirect * result.stats.block_size);
118 
119 	if (result.status == B_ENTRY_NOT_FOUND)
120 		result.status = B_OK;
121 
122 	return result.status;
123 }
124 
125 
126 }	// namespace FSShell
127