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