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 14struct f2fs_fsck gfsck; 15 16void 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 27void 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 40void 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 141static 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 157static void do_dump(struct f2fs_sb_info *sbi) 158{ 159 struct dump_option *opt = (struct dump_option *)config.private; 160 struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); 161 u32 flag = le32_to_cpu(ckpt->ckpt_flags); 162 163 fsck_init(sbi); 164 165 if (opt->end_sit == -1) 166 opt->end_sit = SM_I(sbi)->main_segments; 167 if (opt->end_ssa == -1) 168 opt->end_ssa = SM_I(sbi)->main_segments; 169 if (opt->start_sit != -1) 170 sit_dump(sbi, opt->start_sit, opt->end_sit); 171 if (opt->start_ssa != -1) 172 ssa_dump(sbi, opt->start_ssa, opt->end_ssa); 173 if (opt->blk_addr != -1) { 174 dump_info_from_blkaddr(sbi, opt->blk_addr); 175 goto cleanup; 176 } 177 178 MSG(0, "Info: checkpoint state = %x : ", flag); 179 if (flag & CP_FSCK_FLAG) 180 MSG(0, "%s", " fsck"); 181 if (flag & CP_ERROR_FLAG) 182 MSG(0, "%s", " error"); 183 if (flag & CP_COMPACT_SUM_FLAG) 184 MSG(0, "%s", " compacted_summary"); 185 if (flag & CP_ORPHAN_PRESENT_FLAG) 186 MSG(0, "%s", " orphan_inodes"); 187 if (flag & CP_FASTBOOT_FLAG) 188 MSG(0, "%s", " fastboot"); 189 if (flag & CP_UMOUNT_FLAG) 190 MSG(0, "%s", " unmount"); 191 else 192 MSG(0, "%s", " sudden-power-off"); 193 MSG(0, "\n"); 194 195 dump_node(sbi, opt->nid); 196cleanup: 197 fsck_free(sbi); 198} 199 200int main(int argc, char **argv) 201{ 202 struct f2fs_sb_info *sbi; 203 int ret = 0; 204 205 f2fs_init_configuration(&config); 206 207 f2fs_parse_options(argc, argv); 208 209 if (f2fs_dev_is_umounted(&config) < 0) 210 return -1; 211 212 /* Get device */ 213 if (f2fs_get_device_info(&config) < 0) 214 return -1; 215fsck_again: 216 memset(&gfsck, 0, sizeof(gfsck)); 217 gfsck.sbi.fsck = &gfsck; 218 sbi = &gfsck.sbi; 219 220 ret = f2fs_do_mount(sbi); 221 if (ret == 1) { 222 free(sbi->ckpt); 223 free(sbi->raw_super); 224 goto out; 225 } else if (ret < 0) 226 return -1; 227 228 switch (config.func) { 229 case FSCK: 230 do_fsck(sbi); 231 break; 232 case DUMP: 233 do_dump(sbi); 234 break; 235 } 236 237 f2fs_do_umount(sbi); 238out: 239 if (config.func == FSCK && config.bug_on) { 240 if (config.fix_on == 0 && config.auto_fix == 0) { 241 char ans[255] = {0}; 242retry: 243 printf("Do you want to fix this partition? [Y/N] "); 244 ret = scanf("%s", ans); 245 ASSERT(ret >= 0); 246 if (!strcasecmp(ans, "y")) 247 config.fix_on = 1; 248 else if (!strcasecmp(ans, "n")) 249 config.fix_on = 0; 250 else 251 goto retry; 252 253 if (config.fix_on) 254 goto fsck_again; 255 } 256 } 257 f2fs_finalize_device(&config); 258 259 printf("\nDone.\n"); 260 return 0; 261} 262