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 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