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