Home | History | Annotate | Download | only in fsck
      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