Home | History | Annotate | Download | only in fsck
      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 	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);
    196 cleanup:
    197 	fsck_free(sbi);
    198 }
    199 
    200 int 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;
    215 fsck_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);
    238 out:
    239 	if (config.func == FSCK && config.bug_on) {
    240 		if (config.fix_on == 0 && config.auto_fix == 0) {
    241 			char ans[255] = {0};
    242 retry:
    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