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 
    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