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 (at) kernel.org> 7 * : implement defrag.f2fs 8 * Copyright (C) 2015 Huawei Ltd. 9 * Hou Pengyang <houpengyang (at) huawei.com> 10 * Liu Shuoran <liushuoran (at) huawei.com> 11 * Jaegeuk Kim <jaegeuk (at) 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 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 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 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 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 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 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 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 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 153 static void __add_fsck_options(void) 154 { 155 /* -a */ 156 c.auto_fix = 1; 157 } 158 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 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 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 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 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 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 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 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