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 
fsck_usage()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 
dump_usage()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 
f2fs_parse_options(int argc,char * argv[])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 
do_fsck(struct f2fs_sb_info * sbi)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 
do_dump(struct f2fs_sb_info * sbi)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 
main(int argc,char ** argv)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