1 /** 2 * main.c 3 * 4 * Copyright (c) 2013 Samsung Electronics Co., Ltd. 5 * http://www.samsung.com/ 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License version 2 as 9 * published by the Free Software Foundation. 10 */ 11 #include "fsck.h" 12 #include <libgen.h> 13 14 struct f2fs_fsck gfsck; 15 16 void fsck_usage() 17 { 18 MSG(0, "\nUsage: fsck.f2fs [options] device\n"); 19 MSG(0, "[options]:\n"); 20 MSG(0, " -a check/fix potential corruption, reported by f2fs\n"); 21 MSG(0, " -d debug level [default:0]\n"); 22 MSG(0, " -f check/fix entire partition\n"); 23 MSG(0, " -t show directory tree [-d -1]\n"); 24 exit(1); 25 } 26 27 void dump_usage() 28 { 29 MSG(0, "\nUsage: dump.f2fs [options] device\n"); 30 MSG(0, "[options]:\n"); 31 MSG(0, " -d debug level [default:0]\n"); 32 MSG(0, " -i inode no (hex)\n"); 33 MSG(0, " -s [SIT dump segno from #1~#2 (decimal), for all 0~-1]\n"); 34 MSG(0, " -a [SSA dump segno from #1~#2 (decimal), for all 0~-1]\n"); 35 MSG(0, " -b blk_addr (in 4KB)\n"); 36 37 exit(1); 38 } 39 40 void f2fs_parse_options(int argc, char *argv[]) 41 { 42 int option = 0; 43 char *prog = basename(argv[0]); 44 45 if (!strcmp("fsck.f2fs", prog)) { 46 const char *option_string = "ad:ft"; 47 48 config.func = FSCK; 49 while ((option = getopt(argc, argv, option_string)) != EOF) { 50 switch (option) { 51 case 'a': 52 config.auto_fix = 1; 53 MSG(0, "Info: Fix the reported corruption.\n"); 54 break; 55 case 'd': 56 config.dbg_lv = atoi(optarg); 57 MSG(0, "Info: Debug level = %d\n", 58 config.dbg_lv); 59 break; 60 case 'f': 61 config.fix_on = 1; 62 MSG(0, "Info: Force to fix corruption\n"); 63 break; 64 case 't': 65 config.dbg_lv = -1; 66 break; 67 default: 68 MSG(0, "\tError: Unknown option %c\n", option); 69 fsck_usage(); 70 break; 71 } 72 } 73 } else if (!strcmp("dump.f2fs", prog)) { 74 const char *option_string = "d:i:s:a:b:"; 75 static struct dump_option dump_opt = { 76 .nid = 3, /* default root ino */ 77 .start_sit = -1, 78 .end_sit = -1, 79 .start_ssa = -1, 80 .end_ssa = -1, 81 .blk_addr = -1, 82 }; 83 84 config.func = DUMP; 85 while ((option = getopt(argc, argv, option_string)) != EOF) { 86 int ret = 0; 87 88 switch (option) { 89 case 'd': 90 config.dbg_lv = atoi(optarg); 91 MSG(0, "Info: Debug level = %d\n", 92 config.dbg_lv); 93 break; 94 case 'i': 95 if (strncmp(optarg, "0x", 2)) 96 ret = sscanf(optarg, "%d", 97 &dump_opt.nid); 98 else 99 ret = sscanf(optarg, "%x", 100 &dump_opt.nid); 101 break; 102 case 's': 103 ret = sscanf(optarg, "%d~%d", 104 &dump_opt.start_sit, 105 &dump_opt.end_sit); 106 break; 107 case 'a': 108 ret = sscanf(optarg, "%d~%d", 109 &dump_opt.start_ssa, 110 &dump_opt.end_ssa); 111 break; 112 case 'b': 113 if (strncmp(optarg, "0x", 2)) 114 ret = sscanf(optarg, "%d", 115 &dump_opt.blk_addr); 116 else 117 ret = sscanf(optarg, "%x", 118 &dump_opt.blk_addr); 119 break; 120 default: 121 MSG(0, "\tError: Unknown option %c\n", option); 122 dump_usage(); 123 break; 124 } 125 ASSERT(ret >= 0); 126 } 127 128 config.private = &dump_opt; 129 } 130 131 if ((optind + 1) != argc) { 132 MSG(0, "\tError: Device not specified\n"); 133 if (config.func == FSCK) 134 fsck_usage(); 135 else if (config.func == DUMP) 136 dump_usage(); 137 } 138 config.device_name = argv[optind]; 139 } 140 141 static void do_fsck(struct f2fs_sb_info *sbi) 142 { 143 u32 blk_cnt; 144 145 fsck_init(sbi); 146 147 fsck_chk_orphan_node(sbi); 148 149 /* Traverse all block recursively from root inode */ 150 blk_cnt = 1; 151 fsck_chk_node_blk(sbi, NULL, sbi->root_ino_num, 152 F2FS_FT_DIR, TYPE_INODE, &blk_cnt); 153 fsck_verify(sbi); 154 fsck_free(sbi); 155 } 156 157 static void do_dump(struct f2fs_sb_info *sbi) 158 { 159 struct dump_option *opt = (struct dump_option *)config.private; 160 161 fsck_init(sbi); 162 163 if (opt->end_sit == -1) 164 opt->end_sit = SM_I(sbi)->main_segments; 165 if (opt->end_ssa == -1) 166 opt->end_ssa = SM_I(sbi)->main_segments; 167 if (opt->start_sit != -1) 168 sit_dump(sbi, opt->start_sit, opt->end_sit); 169 if (opt->start_ssa != -1) 170 ssa_dump(sbi, opt->start_ssa, opt->end_ssa); 171 if (opt->blk_addr != -1) { 172 dump_inode_from_blkaddr(sbi, opt->blk_addr); 173 goto cleanup; 174 } 175 dump_node(sbi, opt->nid); 176 cleanup: 177 fsck_free(sbi); 178 } 179 180 int main(int argc, char **argv) 181 { 182 struct f2fs_sb_info *sbi; 183 int ret = 0; 184 185 f2fs_init_configuration(&config); 186 187 f2fs_parse_options(argc, argv); 188 189 if (f2fs_dev_is_umounted(&config) < 0) 190 return -1; 191 192 /* Get device */ 193 if (f2fs_get_device_info(&config) < 0) 194 return -1; 195 fsck_again: 196 memset(&gfsck, 0, sizeof(gfsck)); 197 gfsck.sbi.fsck = &gfsck; 198 sbi = &gfsck.sbi; 199 200 ret = f2fs_do_mount(sbi); 201 if (ret == 1) { 202 free(sbi->ckpt); 203 free(sbi->raw_super); 204 goto out; 205 } else if (ret < 0) 206 return -1; 207 208 switch (config.func) { 209 case FSCK: 210 do_fsck(sbi); 211 break; 212 case DUMP: 213 do_dump(sbi); 214 break; 215 } 216 217 f2fs_do_umount(sbi); 218 out: 219 if (config.func == FSCK && config.bug_on) { 220 if (config.fix_on == 0 && config.auto_fix == 0) { 221 char ans[255] = {0}; 222 retry: 223 printf("Do you want to fix this partition? [Y/N] "); 224 ret = scanf("%s", ans); 225 ASSERT(ret >= 0); 226 if (!strcasecmp(ans, "y")) 227 config.fix_on = 1; 228 else if (!strcasecmp(ans, "n")) 229 config.fix_on = 0; 230 else 231 goto retry; 232 233 if (config.fix_on) 234 goto fsck_again; 235 } 236 } 237 f2fs_finalize_device(&config); 238 239 printf("\nDone.\n"); 240 return 0; 241 } 242