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