1 /**
2 * main.c
3 *
4 * Copyright (c) 2013 Samsung Electronics Co., Ltd.
5 * http://www.samsung.com/
6 * Copyright (c) 2015 Jaegeuk Kim <jaegeuk@kernel.org>
7 * : implement defrag.f2fs
8 * Copyright (C) 2015 Huawei Ltd.
9 * Hou Pengyang <houpengyang@huawei.com>
10 * Liu Shuoran <liushuoran@huawei.com>
11 * Jaegeuk Kim <jaegeuk@kernel.org>
12 * : add sload.f2fs
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License version 2 as
16 * published by the Free Software Foundation.
17 */
18 #include "fsck.h"
19 #include <libgen.h>
20 #include <ctype.h>
21 #include <getopt.h>
22 #include "quotaio.h"
23
24 struct f2fs_fsck gfsck;
25
26 #ifdef WITH_ANDROID
27 #include <sparse/sparse.h>
28 extern struct sparse_file *f2fs_sparse_file;
29 #endif
30
31 INIT_FEATURE_TABLE;
32
absolute_path(const char * file)33 static char *absolute_path(const char *file)
34 {
35 char *ret;
36 char cwd[PATH_MAX];
37
38 if (file[0] != '/') {
39 if (getcwd(cwd, PATH_MAX) == NULL) {
40 fprintf(stderr, "Failed to getcwd\n");
41 exit(EXIT_FAILURE);
42 }
43 ret = malloc(strlen(cwd) + 1 + strlen(file) + 1);
44 if (ret)
45 sprintf(ret, "%s/%s", cwd, file);
46 } else
47 ret = strdup(file);
48 return ret;
49 }
50
fsck_usage()51 void fsck_usage()
52 {
53 MSG(0, "\nUsage: fsck.f2fs [options] device\n");
54 MSG(0, "[options]:\n");
55 MSG(0, " -a check/fix potential corruption, reported by f2fs\n");
56 MSG(0, " -d debug level [default:0]\n");
57 MSG(0, " -f check/fix entire partition\n");
58 MSG(0, " -g add default options\n");
59 MSG(0, " -O feature1[feature2,feature3,...] e.g. \"encrypt\"\n");
60 MSG(0, " -p preen mode [default:0 the same as -a [0|1]]\n");
61 MSG(0, " -S sparse_mode\n");
62 MSG(0, " -t show directory tree\n");
63 MSG(0, " -q preserve quota limits\n");
64 MSG(0, " -y fix all the time\n");
65 MSG(0, " -V print the version number and exit\n");
66 MSG(0, " --dry-run do not really fix corruptions\n");
67 exit(1);
68 }
69
dump_usage()70 void dump_usage()
71 {
72 MSG(0, "\nUsage: dump.f2fs [options] device\n");
73 MSG(0, "[options]:\n");
74 MSG(0, " -d debug level [default:0]\n");
75 MSG(0, " -i inode no (hex)\n");
76 MSG(0, " -n [NAT dump nid from #1~#2 (decimal), for all 0~-1]\n");
77 MSG(0, " -s [SIT dump segno from #1~#2 (decimal), for all 0~-1]\n");
78 MSG(0, " -S sparse_mode\n");
79 MSG(0, " -a [SSA dump segno from #1~#2 (decimal), for all 0~-1]\n");
80 MSG(0, " -b blk_addr (in 4KB)\n");
81 MSG(0, " -V print the version number and exit\n");
82
83 exit(1);
84 }
85
defrag_usage()86 void defrag_usage()
87 {
88 MSG(0, "\nUsage: defrag.f2fs [options] device\n");
89 MSG(0, "[options]:\n");
90 MSG(0, " -d debug level [default:0]\n");
91 MSG(0, " -s start block address [default: main_blkaddr]\n");
92 MSG(0, " -S sparse_mode\n");
93 MSG(0, " -l length [default:512 (2MB)]\n");
94 MSG(0, " -t target block address [default: main_blkaddr + 2MB]\n");
95 MSG(0, " -i set direction as shrink [default: expand]\n");
96 MSG(0, " -V print the version number and exit\n");
97 exit(1);
98 }
99
resize_usage()100 void resize_usage()
101 {
102 MSG(0, "\nUsage: resize.f2fs [options] device\n");
103 MSG(0, "[options]:\n");
104 MSG(0, " -d debug level [default:0]\n");
105 MSG(0, " -s safe resize (Does not resize metadata)");
106 MSG(0, " -t target sectors [default: device size]\n");
107 MSG(0, " -V print the version number and exit\n");
108 exit(1);
109 }
110
sload_usage()111 void sload_usage()
112 {
113 MSG(0, "\nUsage: sload.f2fs [options] device\n");
114 MSG(0, "[options]:\n");
115 MSG(0, " -C fs_config\n");
116 MSG(0, " -f source directory [path of the source directory]\n");
117 MSG(0, " -p product out directory\n");
118 MSG(0, " -s file_contexts\n");
119 MSG(0, " -S sparse_mode\n");
120 MSG(0, " -t mount point [prefix of target fs path, default:/]\n");
121 MSG(0, " -T timestamp\n");
122 MSG(0, " -d debug level [default:0]\n");
123 MSG(0, " -V print the version number and exit\n");
124 exit(1);
125 }
126
is_digits(char * optarg)127 static int is_digits(char *optarg)
128 {
129 unsigned int i;
130
131 for (i = 0; i < strlen(optarg); i++)
132 if (!isdigit(optarg[i]))
133 break;
134 return i == strlen(optarg);
135 }
136
error_out(char * prog)137 static void error_out(char *prog)
138 {
139 if (!strcmp("fsck.f2fs", prog))
140 fsck_usage();
141 else if (!strcmp("dump.f2fs", prog))
142 dump_usage();
143 else if (!strcmp("defrag.f2fs", prog))
144 defrag_usage();
145 else if (!strcmp("resize.f2fs", prog))
146 resize_usage();
147 else if (!strcmp("sload.f2fs", prog))
148 sload_usage();
149 else
150 MSG(0, "\nWrong program.\n");
151 }
152
__add_fsck_options(void)153 static void __add_fsck_options(void)
154 {
155 /* -a */
156 c.auto_fix = 1;
157 }
158
add_default_options(void)159 static void add_default_options(void)
160 {
161 switch (c.defset) {
162 case CONF_ANDROID:
163 __add_fsck_options();
164 }
165 c.quota_fix = 1;
166 }
167
f2fs_parse_options(int argc,char * argv[])168 void f2fs_parse_options(int argc, char *argv[])
169 {
170 int option = 0;
171 char *prog = basename(argv[0]);
172 int err = NOERROR;
173 #ifdef WITH_ANDROID
174 int i;
175
176 /* Allow prog names (e.g, sload_f2fs, fsck_f2fs, etc) */
177 for (i = 0; i < strlen(prog); i++) {
178 if (prog[i] == '_')
179 prog[i] = '.';
180 }
181 #endif
182 if (argc < 2) {
183 MSG(0, "\tError: Device not specified\n");
184 error_out(prog);
185 }
186
187 if (!strcmp("fsck.f2fs", prog)) {
188 const char *option_string = ":ad:fg:O:p:q:StyV";
189 int opt = 0;
190 struct option long_opt[] = {
191 {"dry-run", no_argument, 0, 1},
192 {0, 0, 0, 0}
193 };
194
195 c.func = FSCK;
196 while ((option = getopt_long(argc, argv, option_string,
197 long_opt, &opt)) != EOF) {
198 switch (option) {
199 case 1:
200 c.dry_run = 1;
201 MSG(0, "Info: Dry run\n");
202 break;
203 case 'a':
204 c.auto_fix = 1;
205 MSG(0, "Info: Fix the reported corruption.\n");
206 break;
207 case 'g':
208 if (!strcmp(optarg, "android"))
209 c.defset = CONF_ANDROID;
210 break;
211 case 'O':
212 if (parse_feature(feature_table, optarg))
213 fsck_usage();
214 break;
215 case 'p':
216 /* preen mode has different levels:
217 * 0: default level, the same as -a
218 * 1: check meta
219 * 2: same as 0, but will skip some
220 * check for old kernel
221 */
222 if (optarg[0] == '-' || !is_digits(optarg) ||
223 optind == argc) {
224 MSG(0, "Info: Use default preen mode\n");
225 c.preen_mode = PREEN_MODE_0;
226 c.auto_fix = 1;
227 optind--;
228 break;
229 }
230 c.preen_mode = atoi(optarg);
231 if (c.preen_mode < 0)
232 c.preen_mode = PREEN_MODE_0;
233 else if (c.preen_mode >= PREEN_MODE_MAX)
234 c.preen_mode = PREEN_MODE_MAX - 1;
235 if (c.preen_mode == PREEN_MODE_0 ||
236 c.preen_mode == PREEN_MODE_2)
237 c.auto_fix = 1;
238 MSG(0, "Info: Fix the reported corruption in "
239 "preen mode %d\n", c.preen_mode);
240 break;
241 case 'd':
242 if (optarg[0] == '-') {
243 err = ENEED_ARG;
244 break;
245 } else if (!is_digits(optarg)) {
246 err = EWRONG_OPT;
247 break;
248 }
249 c.dbg_lv = atoi(optarg);
250 MSG(0, "Info: Debug level = %d\n", c.dbg_lv);
251 break;
252 case 'f':
253 case 'y':
254 c.fix_on = 1;
255 c.force = 1;
256 MSG(0, "Info: Force to fix corruption\n");
257 break;
258 case 'q':
259 c.preserve_limits = atoi(optarg);
260 MSG(0, "Info: Preserve quota limits = %d\n",
261 c.preserve_limits);
262 break;
263 case 'S':
264 c.sparse_mode = 1;
265 break;
266 case 't':
267 c.show_dentry = 1;
268 break;
269 case ':':
270 if (optopt == 'p') {
271 MSG(0, "Info: Use default preen mode\n");
272 c.preen_mode = PREEN_MODE_0;
273 c.auto_fix = 1;
274 } else {
275 option = optopt;
276 err = ENEED_ARG;
277 break;
278 }
279 break;
280 case 'V':
281 show_version(prog);
282 exit(0);
283 case '?':
284 option = optopt;
285 default:
286 err = EUNKNOWN_OPT;
287 break;
288 }
289 if (err != NOERROR)
290 break;
291 }
292 } else if (!strcmp("dump.f2fs", prog)) {
293 const char *option_string = "d:i:n:s:Sa:b:V";
294 static struct dump_option dump_opt = {
295 .nid = 0, /* default root ino */
296 .start_nat = -1,
297 .end_nat = -1,
298 .start_sit = -1,
299 .end_sit = -1,
300 .start_ssa = -1,
301 .end_ssa = -1,
302 .blk_addr = -1,
303 };
304
305 c.func = DUMP;
306 while ((option = getopt(argc, argv, option_string)) != EOF) {
307 int ret = 0;
308
309 switch (option) {
310 case 'd':
311 if (!is_digits(optarg)) {
312 err = EWRONG_OPT;
313 break;
314 }
315 c.dbg_lv = atoi(optarg);
316 MSG(0, "Info: Debug level = %d\n",
317 c.dbg_lv);
318 break;
319 case 'g':
320 if (!strcmp(optarg, "android")) {
321 c.defset = CONF_ANDROID;
322 MSG(0, "Info: Set conf for android\n");
323 break;
324 }
325 err = EWRONG_OPT;
326 break;
327 case 'i':
328 if (strncmp(optarg, "0x", 2))
329 ret = sscanf(optarg, "%d",
330 &dump_opt.nid);
331 else
332 ret = sscanf(optarg, "%x",
333 &dump_opt.nid);
334 break;
335 case 'n':
336 ret = sscanf(optarg, "%d~%d",
337 &dump_opt.start_nat,
338 &dump_opt.end_nat);
339 break;
340 case 's':
341 ret = sscanf(optarg, "%d~%d",
342 &dump_opt.start_sit,
343 &dump_opt.end_sit);
344 break;
345 case 'S':
346 c.sparse_mode = 1;
347 break;
348 case 'a':
349 ret = sscanf(optarg, "%d~%d",
350 &dump_opt.start_ssa,
351 &dump_opt.end_ssa);
352 break;
353 case 'b':
354 if (strncmp(optarg, "0x", 2))
355 ret = sscanf(optarg, "%d",
356 &dump_opt.blk_addr);
357 else
358 ret = sscanf(optarg, "%x",
359 &dump_opt.blk_addr);
360 break;
361 case 'V':
362 show_version(prog);
363 exit(0);
364 default:
365 err = EUNKNOWN_OPT;
366 break;
367 }
368 ASSERT(ret >= 0);
369 if (err != NOERROR)
370 break;
371 }
372
373 c.private = &dump_opt;
374 } else if (!strcmp("defrag.f2fs", prog)) {
375 const char *option_string = "d:s:Sl:t:iV";
376
377 c.func = DEFRAG;
378 while ((option = getopt(argc, argv, option_string)) != EOF) {
379 int ret = 0;
380
381 switch (option) {
382 case 'd':
383 if (!is_digits(optarg)) {
384 err = EWRONG_OPT;
385 break;
386 }
387 c.dbg_lv = atoi(optarg);
388 MSG(0, "Info: Debug level = %d\n",
389 c.dbg_lv);
390 break;
391 case 's':
392 if (strncmp(optarg, "0x", 2))
393 ret = sscanf(optarg, "%"PRIu64"",
394 &c.defrag_start);
395 else
396 ret = sscanf(optarg, "%"PRIx64"",
397 &c.defrag_start);
398 break;
399 case 'S':
400 c.sparse_mode = 1;
401 break;
402 case 'l':
403 if (strncmp(optarg, "0x", 2))
404 ret = sscanf(optarg, "%"PRIu64"",
405 &c.defrag_len);
406 else
407 ret = sscanf(optarg, "%"PRIx64"",
408 &c.defrag_len);
409 break;
410 case 't':
411 if (strncmp(optarg, "0x", 2))
412 ret = sscanf(optarg, "%"PRIu64"",
413 &c.defrag_target);
414 else
415 ret = sscanf(optarg, "%"PRIx64"",
416 &c.defrag_target);
417 break;
418 case 'i':
419 c.defrag_shrink = 1;
420 break;
421 case 'V':
422 show_version(prog);
423 exit(0);
424 default:
425 err = EUNKNOWN_OPT;
426 break;
427 }
428 ASSERT(ret >= 0);
429 if (err != NOERROR)
430 break;
431 }
432 } else if (!strcmp("resize.f2fs", prog)) {
433 const char *option_string = "d:st:V";
434
435 c.func = RESIZE;
436 while ((option = getopt(argc, argv, option_string)) != EOF) {
437 int ret = 0;
438
439 switch (option) {
440 case 'd':
441 if (!is_digits(optarg)) {
442 err = EWRONG_OPT;
443 break;
444 }
445 c.dbg_lv = atoi(optarg);
446 MSG(0, "Info: Debug level = %d\n",
447 c.dbg_lv);
448 break;
449 case 's':
450 c.safe_resize = 1;
451 break;
452 case 't':
453 if (strncmp(optarg, "0x", 2))
454 ret = sscanf(optarg, "%"PRIu64"",
455 &c.target_sectors);
456 else
457 ret = sscanf(optarg, "%"PRIx64"",
458 &c.target_sectors);
459 break;
460 case 'V':
461 show_version(prog);
462 exit(0);
463 default:
464 err = EUNKNOWN_OPT;
465 break;
466 }
467 ASSERT(ret >= 0);
468 if (err != NOERROR)
469 break;
470 }
471 } else if (!strcmp("sload.f2fs", prog)) {
472 const char *option_string = "C:d:f:p:s:St:T:V";
473 #ifdef HAVE_LIBSELINUX
474 int max_nr_opt = (int)sizeof(c.seopt_file) /
475 sizeof(c.seopt_file[0]);
476 char *token;
477 #endif
478 char *p;
479
480 c.func = SLOAD;
481 while ((option = getopt(argc, argv, option_string)) != EOF) {
482 switch (option) {
483 case 'C':
484 c.fs_config_file = absolute_path(optarg);
485 break;
486 case 'd':
487 if (!is_digits(optarg)) {
488 err = EWRONG_OPT;
489 break;
490 }
491 c.dbg_lv = atoi(optarg);
492 MSG(0, "Info: Debug level = %d\n",
493 c.dbg_lv);
494 break;
495 case 'f':
496 c.from_dir = absolute_path(optarg);
497 break;
498 case 'p':
499 c.target_out_dir = absolute_path(optarg);
500 break;
501 case 's':
502 #ifdef HAVE_LIBSELINUX
503 token = strtok(optarg, ",");
504 while (token) {
505 if (c.nr_opt == max_nr_opt) {
506 MSG(0, "\tError: Expected at most %d selinux opts\n",
507 max_nr_opt);
508 error_out(prog);
509 }
510 c.seopt_file[c.nr_opt].type =
511 SELABEL_OPT_PATH;
512 c.seopt_file[c.nr_opt].value =
513 absolute_path(token);
514 c.nr_opt++;
515 token = strtok(NULL, ",");
516 }
517 #else
518 MSG(0, "Info: Not support selinux opts\n");
519 #endif
520 break;
521 case 'S':
522 c.sparse_mode = 1;
523 break;
524 case 't':
525 c.mount_point = (char *)optarg;
526 break;
527 case 'T':
528 c.fixed_time = strtoul(optarg, &p, 0);
529 break;
530 case 'V':
531 show_version(prog);
532 exit(0);
533 default:
534 err = EUNKNOWN_OPT;
535 break;
536 }
537 if (err != NOERROR)
538 break;
539 }
540 }
541
542 add_default_options();
543
544 if (optind >= argc) {
545 MSG(0, "\tError: Device not specified\n");
546 error_out(prog);
547 }
548
549 c.devices[0].path = strdup(argv[optind]);
550 if (argc > (optind + 1)) {
551 c.dbg_lv = 0;
552 err = EUNKNOWN_ARG;
553 }
554 if (err == NOERROR)
555 return;
556
557 /* print out error */
558 switch (err) {
559 case EWRONG_OPT:
560 MSG(0, "\tError: Wrong option -%c %s\n", option, optarg);
561 break;
562 case ENEED_ARG:
563 MSG(0, "\tError: Need argument for -%c\n", option);
564 break;
565 case EUNKNOWN_OPT:
566 MSG(0, "\tError: Unknown option %c\n", option);
567 break;
568 case EUNKNOWN_ARG:
569 MSG(0, "\tError: Unknown argument %s\n", argv[optind]);
570 break;
571 }
572 error_out(prog);
573 }
574
do_fsck(struct f2fs_sb_info * sbi)575 static void do_fsck(struct f2fs_sb_info *sbi)
576 {
577 struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
578 u32 flag = le32_to_cpu(ckpt->ckpt_flags);
579 u32 blk_cnt;
580 errcode_t ret;
581
582 fsck_init(sbi);
583
584 print_cp_state(flag);
585
586 fsck_chk_curseg_info(sbi);
587
588 if (!c.fix_on && !c.bug_on) {
589 switch (c.preen_mode) {
590 case PREEN_MODE_1:
591 if (fsck_chk_meta(sbi)) {
592 MSG(0, "[FSCK] F2FS metadata [Fail]");
593 MSG(0, "\tError: meta does not match, "
594 "force check all\n");
595 } else {
596 MSG(0, "[FSCK] F2FS metadata [Ok..]");
597 fsck_free(sbi);
598 return;
599 }
600
601 if (!c.ro)
602 c.fix_on = 1;
603 break;
604 }
605 } else if (c.preen_mode) {
606 /*
607 * we can hit this in 3 situations:
608 * 1. fsck -f, fix_on has already been set to 1 when
609 * parsing options;
610 * 2. fsck -a && CP_FSCK_FLAG is set, fix_on has already
611 * been set to 1 when checking CP_FSCK_FLAG;
612 * 3. fsck -p 1 && error is detected, then bug_on is set,
613 * we set fix_on = 1 here, so that fsck can fix errors
614 * automatically
615 */
616 c.fix_on = 1;
617 }
618
619 fsck_chk_quota_node(sbi);
620
621 /* Traverse all block recursively from root inode */
622 blk_cnt = 1;
623
624 if (c.feature & cpu_to_le32(F2FS_FEATURE_QUOTA_INO)) {
625 ret = quota_init_context(sbi);
626 if (ret) {
627 ASSERT_MSG("quota_init_context failure: %d", ret);
628 return;
629 }
630 }
631 fsck_chk_orphan_node(sbi);
632 fsck_chk_node_blk(sbi, NULL, sbi->root_ino_num,
633 F2FS_FT_DIR, TYPE_INODE, &blk_cnt, NULL);
634 fsck_chk_quota_files(sbi);
635
636 fsck_verify(sbi);
637 fsck_free(sbi);
638 }
639
do_dump(struct f2fs_sb_info * sbi)640 static void do_dump(struct f2fs_sb_info *sbi)
641 {
642 struct dump_option *opt = (struct dump_option *)c.private;
643 struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
644 u32 flag = le32_to_cpu(ckpt->ckpt_flags);
645
646 if (opt->end_nat == -1)
647 opt->end_nat = NM_I(sbi)->max_nid;
648 if (opt->end_sit == -1)
649 opt->end_sit = SM_I(sbi)->main_segments;
650 if (opt->end_ssa == -1)
651 opt->end_ssa = SM_I(sbi)->main_segments;
652 if (opt->start_nat != -1)
653 nat_dump(sbi, opt->start_nat, opt->end_nat);
654 if (opt->start_sit != -1)
655 sit_dump(sbi, opt->start_sit, opt->end_sit);
656 if (opt->start_ssa != -1)
657 ssa_dump(sbi, opt->start_ssa, opt->end_ssa);
658 if (opt->blk_addr != -1)
659 dump_info_from_blkaddr(sbi, opt->blk_addr);
660 if (opt->nid)
661 dump_node(sbi, opt->nid, 0);
662
663 print_cp_state(flag);
664
665 }
666
do_defrag(struct f2fs_sb_info * sbi)667 static int do_defrag(struct f2fs_sb_info *sbi)
668 {
669 struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi);
670
671 if (c.defrag_start > get_sb(block_count))
672 goto out_range;
673 if (c.defrag_start < SM_I(sbi)->main_blkaddr)
674 c.defrag_start = SM_I(sbi)->main_blkaddr;
675
676 if (c.defrag_len == 0)
677 c.defrag_len = sbi->blocks_per_seg;
678
679 if (c.defrag_start + c.defrag_len > get_sb(block_count))
680 c.defrag_len = get_sb(block_count) - c.defrag_start;
681
682 if (c.defrag_target == 0) {
683 c.defrag_target = c.defrag_start - 1;
684 if (!c.defrag_shrink)
685 c.defrag_target += c.defrag_len + 1;
686 }
687
688 if (c.defrag_target < SM_I(sbi)->main_blkaddr ||
689 c.defrag_target > get_sb(block_count))
690 goto out_range;
691 if (c.defrag_target >= c.defrag_start &&
692 c.defrag_target < c.defrag_start + c.defrag_len)
693 goto out_range;
694
695 if (c.defrag_start > c.defrag_target)
696 MSG(0, "Info: Move 0x%"PRIx64" <- [0x%"PRIx64"-0x%"PRIx64"]\n",
697 c.defrag_target,
698 c.defrag_start,
699 c.defrag_start + c.defrag_len - 1);
700 else
701 MSG(0, "Info: Move [0x%"PRIx64"-0x%"PRIx64"] -> 0x%"PRIx64"\n",
702 c.defrag_start,
703 c.defrag_start + c.defrag_len - 1,
704 c.defrag_target);
705
706 return f2fs_defragment(sbi, c.defrag_start, c.defrag_len,
707 c.defrag_target, c.defrag_shrink);
708 out_range:
709 ASSERT_MSG("Out-of-range [0x%"PRIx64" ~ 0x%"PRIx64"] to 0x%"PRIx64"",
710 c.defrag_start,
711 c.defrag_start + c.defrag_len - 1,
712 c.defrag_target);
713 return -1;
714 }
715
do_resize(struct f2fs_sb_info * sbi)716 static int do_resize(struct f2fs_sb_info *sbi)
717 {
718 if (!c.target_sectors)
719 c.target_sectors = c.total_sectors;
720
721 if (c.target_sectors > c.total_sectors) {
722 ASSERT_MSG("Out-of-range Target=0x%"PRIx64" / 0x%"PRIx64"",
723 c.target_sectors, c.total_sectors);
724 return -1;
725 }
726
727 return f2fs_resize(sbi);
728 }
729
do_sload(struct f2fs_sb_info * sbi)730 static int do_sload(struct f2fs_sb_info *sbi)
731 {
732 if (!c.from_dir) {
733 MSG(0, "Info: No source directory, but it's okay.\n");
734 return 0;
735 }
736 if (!c.mount_point)
737 c.mount_point = "/";
738
739 return f2fs_sload(sbi);
740 }
741
main(int argc,char ** argv)742 int main(int argc, char **argv)
743 {
744 struct f2fs_sb_info *sbi;
745 int ret = 0;
746
747 f2fs_init_configuration();
748
749 f2fs_parse_options(argc, argv);
750
751 if (c.func != DUMP && f2fs_devs_are_umounted() < 0) {
752 if (errno == EBUSY)
753 return -1;
754 if (!c.ro || c.func == DEFRAG) {
755 MSG(0, "\tError: Not available on mounted device!\n");
756 return -1;
757 }
758
759 /* allow ro-mounted partition */
760 MSG(0, "Info: Check FS only due to RO\n");
761 c.fix_on = 0;
762 c.auto_fix = 0;
763 }
764
765 /* Get device */
766 if (f2fs_get_device_info() < 0)
767 return -1;
768
769 fsck_again:
770 memset(&gfsck, 0, sizeof(gfsck));
771 gfsck.sbi.fsck = &gfsck;
772 sbi = &gfsck.sbi;
773
774 ret = f2fs_do_mount(sbi);
775 if (ret != 0) {
776 if (ret == 1) {
777 MSG(0, "Info: No error was reported\n");
778 ret = 0;
779 }
780 goto out_err;
781 }
782
783 switch (c.func) {
784 case FSCK:
785 do_fsck(sbi);
786 break;
787 #ifdef WITH_DUMP
788 case DUMP:
789 do_dump(sbi);
790 break;
791 #endif
792 #ifdef WITH_DEFRAG
793 case DEFRAG:
794 ret = do_defrag(sbi);
795 if (ret)
796 goto out_err;
797 break;
798 #endif
799 #ifdef WITH_RESIZE
800 case RESIZE:
801 if (do_resize(sbi))
802 goto out_err;
803 break;
804 #endif
805 #ifdef WITH_SLOAD
806 case SLOAD:
807 if (do_sload(sbi))
808 goto out_err;
809
810 f2fs_do_umount(sbi);
811
812 /* fsck to fix missing quota */
813 c.func = FSCK;
814 c.fix_on = 1;
815 goto fsck_again;
816 #endif
817 default:
818 ERR_MSG("Wrong program name\n");
819 ASSERT(0);
820 }
821
822 f2fs_do_umount(sbi);
823
824 if (c.func == FSCK && c.bug_on) {
825 if (!c.ro && c.fix_on == 0 && c.auto_fix == 0 && !c.dry_run) {
826 char ans[255] = {0};
827 retry:
828 printf("Do you want to fix this partition? [Y/N] ");
829 ret = scanf("%s", ans);
830 ASSERT(ret >= 0);
831 if (!strcasecmp(ans, "y"))
832 c.fix_on = 1;
833 else if (!strcasecmp(ans, "n"))
834 c.fix_on = 0;
835 else
836 goto retry;
837
838 if (c.fix_on)
839 goto fsck_again;
840 }
841 }
842 ret = f2fs_finalize_device();
843 if (ret < 0)
844 return ret;
845
846 printf("\nDone.\n");
847 return 0;
848
849 out_err:
850 if (sbi->ckpt)
851 free(sbi->ckpt);
852 if (sbi->raw_super)
853 free(sbi->raw_super);
854 return ret;
855 }
856