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
14 namespace FSShell {
15
16
17 fssh_status_t
command_checkfs(int argc,const char * const * argv)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 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