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