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