e8c3dc4041e6351b7265c919a9bc78dacf44960d
[platform/upstream/f2fs-tools.git] / fsck / main.c
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  * Copyright (c) 2019 Google Inc.
14  *   Robin Hsu <robinhsu@google.com>
15  *  : add cache layer
16  * Copyright (c) 2020 Google Inc.
17  *   Robin Hsu <robinhsu@google.com>
18  *  : add sload compression support
19  *
20  * This program is free software; you can redistribute it and/or modify
21  * it under the terms of the GNU General Public License version 2 as
22  * published by the Free Software Foundation.
23  */
24 #include "fsck.h"
25 #include <libgen.h>
26 #include <ctype.h>
27 #include <time.h>
28 #include <getopt.h>
29 #include <stdbool.h>
30 #include "quotaio.h"
31 #include "compress.h"
32
33 struct f2fs_fsck gfsck;
34
35 INIT_FEATURE_TABLE;
36
37 #ifdef WITH_SLOAD
38 static char *absolute_path(const char *file)
39 {
40         char *ret;
41         char cwd[PATH_MAX];
42
43         if (file[0] != '/') {
44                 if (getcwd(cwd, PATH_MAX) == NULL) {
45                         fprintf(stderr, "Failed to getcwd\n");
46                         exit(EXIT_FAILURE);
47                 }
48                 ret = malloc(strlen(cwd) + 1 + strlen(file) + 1);
49                 if (ret)
50                         sprintf(ret, "%s/%s", cwd, file);
51         } else
52                 ret = strdup(file);
53         return ret;
54 }
55 #endif
56
57 void fsck_usage()
58 {
59         MSG(0, "\nUsage: fsck.f2fs [options] device\n");
60         MSG(0, "[options]:\n");
61         MSG(0, "  -a check/fix potential corruption, reported by f2fs\n");
62         MSG(0, "  -c <num-cache-entry>  set number of cache entries"
63                         " (default 0)\n");
64         MSG(0, "  -m <max-hash-collision>  set max cache hash collision"
65                         " (default 16)\n");
66         MSG(0, "  -C encoding[:flag1,flag2] Set options for enabling"
67                         " casefolding\n");
68         MSG(0, "  -d debug level [default:0]\n");
69         MSG(0, "  -f check/fix entire partition\n");
70         MSG(0, "  -g add default options\n");
71         MSG(0, "  -l show superblock/checkpoint\n");
72         MSG(0, "  -M show a file map\n");
73         MSG(0, "  -O feature1[feature2,feature3,...] e.g. \"encrypt\"\n");
74         MSG(0, "  -p preen mode [default:0 the same as -a [0|1|2]]\n");
75         MSG(0, "  -S sparse_mode\n");
76         MSG(0, "  -t show directory tree\n");
77         MSG(0, "  -q preserve quota limits\n");
78         MSG(0, "  -y fix all the time\n");
79         MSG(0, "  -V print the version number and exit\n");
80         MSG(0, "  --dry-run do not really fix corruptions\n");
81         MSG(0, "  --no-kernel-check skips detecting kernel change\n");
82         MSG(0, "  --kernel-check checks kernel change\n");
83         MSG(0, "  --debug-cache to debug cache when -c is used\n");
84         exit(1);
85 }
86
87 void dump_usage()
88 {
89         MSG(0, "\nUsage: dump.f2fs [options] device\n");
90         MSG(0, "[options]:\n");
91         MSG(0, "  -d debug level [default:0]\n");
92         MSG(0, "  -i inode no (hex)\n");
93         MSG(0, "  -I inode no (hex) scan full disk\n");
94         MSG(0, "  -n [NAT dump nid from #1~#2 (decimal), for all 0~-1]\n");
95         MSG(0, "  -M show a block map\n");
96         MSG(0, "  -s [SIT dump segno from #1~#2 (decimal), for all 0~-1]\n");
97         MSG(0, "  -S sparse_mode\n");
98         MSG(0, "  -a [SSA dump segno from #1~#2 (decimal), for all 0~-1]\n");
99         MSG(0, "  -b blk_addr (in 4KB)\n");
100         MSG(0, "  -V print the version number and exit\n");
101
102         exit(1);
103 }
104
105 void defrag_usage()
106 {
107         MSG(0, "\nUsage: defrag.f2fs [options] device\n");
108         MSG(0, "[options]:\n");
109         MSG(0, "  -d debug level [default:0]\n");
110         MSG(0, "  -s start block address [default: main_blkaddr]\n");
111         MSG(0, "  -S sparse_mode\n");
112         MSG(0, "  -l length [default:512 (2MB)]\n");
113         MSG(0, "  -t target block address [default: main_blkaddr + 2MB]\n");
114         MSG(0, "  -i set direction as shrink [default: expand]\n");
115         MSG(0, "  -V print the version number and exit\n");
116         exit(1);
117 }
118
119 void resize_usage()
120 {
121         MSG(0, "\nUsage: resize.f2fs [options] device\n");
122         MSG(0, "[options]:\n");
123         MSG(0, "  -d debug level [default:0]\n");
124         MSG(0, "  -i extended node bitmap, node ratio is 20%% by default\n");
125         MSG(0, "  -o overprovision percentage [default:auto]\n");
126         MSG(0, "  -s safe resize (Does not resize metadata)\n");
127         MSG(0, "  -t target sectors [default: device size]\n");
128         MSG(0, "  -V print the version number and exit\n");
129         exit(1);
130 }
131
132 void sload_usage()
133 {
134         MSG(0, "\nUsage: sload.f2fs [options] device\n");
135         MSG(0, "[options]:\n");
136         MSG(0, "  -C fs_config\n");
137         MSG(0, "  -f source directory [path of the source directory]\n");
138         MSG(0, "  -p product out directory\n");
139         MSG(0, "  -s file_contexts\n");
140         MSG(0, "  -S sparse_mode\n");
141         MSG(0, "  -t mount point [prefix of target fs path, default:/]\n");
142         MSG(0, "  -T timestamp\n");
143         MSG(0, "  -P preserve owner: user and group\n");
144         MSG(0, "  -c enable compression (default allow policy)\n");
145         MSG(0, "    ------------ Compression sub-options -----------------\n");
146         MSG(0, "    -L <log-of-blocks-per-cluster>, default 2\n");
147         MSG(0, "    -a <algorithm> compression algorithm, default LZ4\n");
148         MSG(0, "    -x <ext> compress files except for these extensions.\n");
149         MSG(0, "    -i <ext> compress files with these extensions only.\n");
150         MSG(0, "    * -i or -x: use it many times for multiple extensions.\n");
151         MSG(0, "    * -i and -x cannot be used together..\n");
152         MSG(0, "    -m <num> min compressed blocks per cluster\n");
153         MSG(0, "    -r read only (to release unused blocks) for compressed "
154                         "files\n");
155         MSG(0, "    ------------------------------------------------------\n");
156         MSG(0, "  -d debug level [default:0]\n");
157         MSG(0, "  -V print the version number and exit\n");
158         exit(1);
159 }
160
161 void label_usage()
162 {
163         MSG(0, "\nUsage: f2fslabel [options] device [volume-label]\n");
164         MSG(0, "[options]:\n");
165         MSG(0, "  -V print the version number and exit\n");
166         exit(1);
167 }
168
169 static int is_digits(char *optarg)
170 {
171         unsigned int i;
172
173         for (i = 0; i < strlen(optarg); i++)
174                 if (!isdigit(optarg[i]))
175                         break;
176         return i == strlen(optarg);
177 }
178
179 static void error_out(char *prog)
180 {
181         if (!strcmp("fsck.f2fs", prog))
182                 fsck_usage();
183         else if (!strcmp("dump.f2fs", prog))
184                 dump_usage();
185         else if (!strcmp("defrag.f2fs", prog))
186                 defrag_usage();
187         else if (!strcmp("resize.f2fs", prog))
188                 resize_usage();
189         else if (!strcmp("sload.f2fs", prog))
190                 sload_usage();
191         else if (!strcmp("f2fslabel", prog))
192                 label_usage();
193         else
194                 MSG(0, "\nWrong program.\n");
195 }
196
197 static void __add_fsck_options(void)
198 {
199         /* -a */
200         c.auto_fix = 1;
201 }
202
203 static void add_default_options(void)
204 {
205         switch (c.defset) {
206         case CONF_ANDROID:
207                 __add_fsck_options();
208         }
209         c.quota_fix = 1;
210 }
211
212 void f2fs_parse_options(int argc, char *argv[])
213 {
214         int option = 0;
215         char *prog = basename(argv[0]);
216         int err = NOERROR;
217 #ifdef WITH_ANDROID
218         int i;
219
220         /* Allow prog names (e.g, sload_f2fs, fsck_f2fs, etc) */
221         for (i = 0; i < strlen(prog); i++) {
222                 if (prog[i] == '_')
223                         prog[i] = '.';
224         }
225 #endif
226         if (argc < 2) {
227                 MSG(0, "\tError: Device not specified\n");
228                 error_out(prog);
229         }
230
231         if (!strcmp("fsck.f2fs", prog)) {
232                 const char *option_string = ":aC:c:m:Md:fg:lO:p:q:StyV";
233                 int opt = 0, val;
234                 char *token;
235                 struct option long_opt[] = {
236                         {"dry-run", no_argument, 0, 1},
237                         {"no-kernel-check", no_argument, 0, 2},
238                         {"kernel-check", no_argument, 0, 3},
239                         {"debug-cache", no_argument, 0, 4},
240                         {0, 0, 0, 0}
241                 };
242
243                 c.func = FSCK;
244                 c.cache_config.max_hash_collision = 16;
245                 c.cache_config.dbg_en = false;
246                 while ((option = getopt_long(argc, argv, option_string,
247                                                 long_opt, &opt)) != EOF) {
248                         switch (option) {
249                         case 1:
250                                 c.dry_run = 1;
251                                 MSG(0, "Info: Dry run\n");
252                                 break;
253                         case 2:
254                                 c.no_kernel_check = 1;
255                                 MSG(0, "Info: No Kernel Check\n");
256                                 break;
257                         case 3:
258                                 c.no_kernel_check = 0;
259                                 MSG(0, "Info: Do Kernel Check\n");
260                                 break;
261                         case 4:
262                                 c.cache_config.dbg_en = true;
263                                 break;
264                         case 'a':
265                                 c.auto_fix = 1;
266                                 MSG(0, "Info: Fix the reported corruption.\n");
267                                 break;
268                         case 'c':
269                                 c.cache_config.num_cache_entry = atoi(optarg);
270                                 break;
271                         case 'm':
272                                 c.cache_config.max_hash_collision =
273                                                 atoi(optarg);
274                                 break;
275                         case 'g':
276                                 if (!strcmp(optarg, "android")) {
277                                         c.defset = CONF_ANDROID;
278                                         MSG(0, "Info: Set conf for android\n");
279                                 }
280                                 break;
281                         case 'l':
282                                 c.layout = 1;
283                                 break;
284                         case 'M':
285                                 c.show_file_map = 1;
286                                 break;
287                         case 'O':
288                                 if (parse_feature(feature_table, optarg))
289                                         fsck_usage();
290                                 break;
291                         case 'p':
292                                 /* preen mode has different levels:
293                                  *  0: default level, the same as -a
294                                  *  1: check meta
295                                  *  2: same as 0, but will skip some
296                                  *     check for old kernel
297                                  */
298                                 if (optarg[0] == '-' || !is_digits(optarg) ||
299                                                         optind == argc) {
300                                         MSG(0, "Info: Use default preen mode\n");
301                                         c.preen_mode = PREEN_MODE_0;
302                                         c.auto_fix = 1;
303                                         optind--;
304                                         break;
305                                 }
306                                 c.preen_mode = atoi(optarg);
307                                 if (c.preen_mode < 0)
308                                         c.preen_mode = PREEN_MODE_0;
309                                 else if (c.preen_mode >= PREEN_MODE_MAX)
310                                         c.preen_mode = PREEN_MODE_MAX - 1;
311                                 if (c.preen_mode == PREEN_MODE_0 ||
312                                         c.preen_mode == PREEN_MODE_2)
313                                         c.auto_fix = 1;
314                                 MSG(0, "Info: Fix the reported corruption in "
315                                         "preen mode %d\n", c.preen_mode);
316                                 break;
317                         case 'd':
318                                 if (optarg[0] == '-') {
319                                         err = ENEED_ARG;
320                                         break;
321                                 } else if (!is_digits(optarg)) {
322                                         err = EWRONG_OPT;
323                                         break;
324                                 }
325                                 c.dbg_lv = atoi(optarg);
326                                 MSG(0, "Info: Debug level = %d\n", c.dbg_lv);
327                                 break;
328                         case 'f':
329                         case 'y':
330                                 c.fix_on = 1;
331                                 c.force = 1;
332                                 MSG(0, "Info: Force to fix corruption\n");
333                                 break;
334                         case 'q':
335                                 c.preserve_limits = atoi(optarg);
336                                 MSG(0, "Info: Preserve quota limits = %d\n",
337                                         c.preserve_limits);
338                                 break;
339                         case 'S':
340                                 c.sparse_mode = 1;
341                                 break;
342                         case 't':
343                                 c.show_dentry = 1;
344                                 break;
345                         case ':':
346                                 if (optopt == 'p') {
347                                         MSG(0, "Info: Use default preen mode\n");
348                                         c.preen_mode = PREEN_MODE_0;
349                                         c.auto_fix = 1;
350                                 } else {
351                                         option = optopt;
352                                         err = ENEED_ARG;
353                                         break;
354                                 }
355                                 break;
356                         case 'C':
357                                 token = strtok(optarg, ":");
358                                 val = f2fs_str2encoding(token);
359                                 if (val < 0) {
360                                         MSG(0, "\tError: Unknown encoding %s\n", token);
361                                         fsck_usage();
362                                 }
363                                 c.s_encoding = val;
364                                 token = strtok(NULL, "");
365                                 val = f2fs_str2encoding_flags(&token, &c.s_encoding_flags);
366                                 if (val) {
367                                         MSG(0, "\tError: Unknown flag %s\n", token);
368                                         fsck_usage();
369                                 }
370                                 c.feature |= cpu_to_le32(F2FS_FEATURE_CASEFOLD);
371                                 break;
372                         case 'V':
373                                 show_version(prog);
374                                 exit(0);
375                         case '?':
376                                 option = optopt;
377                                 fallthrough;
378                         default:
379                                 err = EUNKNOWN_OPT;
380                                 break;
381                         }
382                         if (err != NOERROR)
383                                 break;
384                 }
385         } else if (!strcmp("dump.f2fs", prog)) {
386 #ifdef WITH_DUMP
387                 const char *option_string = "d:i:I:n:Ms:Sa:b:V";
388                 static struct dump_option dump_opt = {
389                         .nid = 0,       /* default root ino */
390                         .start_nat = -1,
391                         .end_nat = -1,
392                         .start_sit = -1,
393                         .end_sit = -1,
394                         .start_ssa = -1,
395                         .end_ssa = -1,
396                         .blk_addr = -1,
397                         .scan_nid = 0,
398                 };
399
400                 c.func = DUMP;
401                 while ((option = getopt(argc, argv, option_string)) != EOF) {
402                         int ret = 0;
403
404                         switch (option) {
405                         case 'd':
406                                 if (!is_digits(optarg)) {
407                                         err = EWRONG_OPT;
408                                         break;
409                                 }
410                                 c.dbg_lv = atoi(optarg);
411                                 MSG(0, "Info: Debug level = %d\n",
412                                                         c.dbg_lv);
413                                 break;
414                         case 'i':
415                                 if (strncmp(optarg, "0x", 2))
416                                         ret = sscanf(optarg, "%d",
417                                                         &dump_opt.nid);
418                                 else
419                                         ret = sscanf(optarg, "%x",
420                                                         &dump_opt.nid);
421                                 break;
422                         case 'I':
423                                 if (strncmp(optarg, "0x", 2))
424                                         ret = sscanf(optarg, "%d",
425                                                         &dump_opt.scan_nid);
426                                 else
427                                         ret = sscanf(optarg, "%x",
428                                                         &dump_opt.scan_nid);
429                                 break;
430                         case 'n':
431                                 ret = sscanf(optarg, "%d~%d",
432                                                         &dump_opt.start_nat,
433                                                         &dump_opt.end_nat);
434                                 break;
435                         case 'M':
436                                 c.show_file_map = 1;
437                                 break;
438                         case 's':
439                                 ret = sscanf(optarg, "%d~%d",
440                                                         &dump_opt.start_sit,
441                                                         &dump_opt.end_sit);
442                                 break;
443                         case 'S':
444                                 c.sparse_mode = 1;
445                                 break;
446                         case 'a':
447                                 ret = sscanf(optarg, "%d~%d",
448                                                         &dump_opt.start_ssa,
449                                                         &dump_opt.end_ssa);
450                                 break;
451                         case 'b':
452                                 if (strncmp(optarg, "0x", 2))
453                                         ret = sscanf(optarg, "%d",
454                                                         &dump_opt.blk_addr);
455                                 else
456                                         ret = sscanf(optarg, "%x",
457                                                         &dump_opt.blk_addr);
458                                 break;
459                         case 'V':
460                                 show_version(prog);
461                                 exit(0);
462                         default:
463                                 err = EUNKNOWN_OPT;
464                                 break;
465                         }
466                         ASSERT(ret >= 0);
467                         if (err != NOERROR)
468                                 break;
469                 }
470
471                 c.private = &dump_opt;
472 #endif
473         } else if (!strcmp("defrag.f2fs", prog)) {
474 #ifdef WITH_DEFRAG
475                 const char *option_string = "d:s:Sl:t:iV";
476
477                 c.func = DEFRAG;
478                 while ((option = getopt(argc, argv, option_string)) != EOF) {
479                         int ret = 0;
480
481                         switch (option) {
482                         case 'd':
483                                 if (!is_digits(optarg)) {
484                                         err = EWRONG_OPT;
485                                         break;
486                                 }
487                                 c.dbg_lv = atoi(optarg);
488                                 MSG(0, "Info: Debug level = %d\n",
489                                                         c.dbg_lv);
490                                 break;
491                         case 's':
492                                 if (strncmp(optarg, "0x", 2))
493                                         ret = sscanf(optarg, "%"PRIu64"",
494                                                         &c.defrag_start);
495                                 else
496                                         ret = sscanf(optarg, "%"PRIx64"",
497                                                         &c.defrag_start);
498                                 break;
499                         case 'S':
500                                 c.sparse_mode = 1;
501                                 break;
502                         case 'l':
503                                 if (strncmp(optarg, "0x", 2))
504                                         ret = sscanf(optarg, "%"PRIu64"",
505                                                         &c.defrag_len);
506                                 else
507                                         ret = sscanf(optarg, "%"PRIx64"",
508                                                         &c.defrag_len);
509                                 break;
510                         case 't':
511                                 if (strncmp(optarg, "0x", 2))
512                                         ret = sscanf(optarg, "%"PRIu64"",
513                                                         &c.defrag_target);
514                                 else
515                                         ret = sscanf(optarg, "%"PRIx64"",
516                                                         &c.defrag_target);
517                                 break;
518                         case 'i':
519                                 c.defrag_shrink = 1;
520                                 break;
521                         case 'V':
522                                 show_version(prog);
523                                 exit(0);
524                         default:
525                                 err = EUNKNOWN_OPT;
526                                 break;
527                         }
528                         ASSERT(ret >= 0);
529                         if (err != NOERROR)
530                                 break;
531                 }
532 #endif
533         } else if (!strcmp("resize.f2fs", prog)) {
534 #ifdef WITH_RESIZE
535                 const char *option_string = "d:fst:io:V";
536
537                 c.func = RESIZE;
538                 while ((option = getopt(argc, argv, option_string)) != EOF) {
539                         int ret = 0;
540
541                         switch (option) {
542                         case 'd':
543                                 if (!is_digits(optarg)) {
544                                         err = EWRONG_OPT;
545                                         break;
546                                 }
547                                 c.dbg_lv = atoi(optarg);
548                                 MSG(0, "Info: Debug level = %d\n",
549                                                         c.dbg_lv);
550                                 break;
551                         case 'f':
552                                 c.force = 1;
553                                 MSG(0, "Info: Force to resize\n");
554                                 break;
555                         case 's':
556                                 c.safe_resize = 1;
557                                 break;
558                         case 't':
559                                 if (strncmp(optarg, "0x", 2))
560                                         ret = sscanf(optarg, "%"PRIu64"",
561                                                         &c.target_sectors);
562                                 else
563                                         ret = sscanf(optarg, "%"PRIx64"",
564                                                         &c.target_sectors);
565                                 break;
566                         case 'i':
567                                 c.large_nat_bitmap = 1;
568                                 break;
569                         case 'o':
570                                 c.new_overprovision = atof(optarg);
571                                 break;
572                         case 'V':
573                                 show_version(prog);
574                                 exit(0);
575                         default:
576                                 err = EUNKNOWN_OPT;
577                                 break;
578                         }
579                         ASSERT(ret >= 0);
580                         if (err != NOERROR)
581                                 break;
582                 }
583 #endif
584         } else if (!strcmp("sload.f2fs", prog)) {
585 #ifdef WITH_SLOAD
586                 const char *option_string = "cL:a:i:x:m:rC:d:f:p:s:St:T:VP";
587 #ifdef HAVE_LIBSELINUX
588                 int max_nr_opt = (int)sizeof(c.seopt_file) /
589                         sizeof(c.seopt_file[0]);
590                 char *token;
591 #endif
592                 char *p;
593
594                 c.func = SLOAD;
595                 c.compress.cc.log_cluster_size = 2;
596                 c.compress.alg = COMPR_LZ4;
597                 c.compress.min_blocks = 1;
598                 c.compress.filter_ops = &ext_filter;
599                 while ((option = getopt(argc, argv, option_string)) != EOF) {
600                         unsigned int i;
601                         int val;
602
603                         switch (option) {
604                         case 'c': /* compression support */
605                                 c.compress.enabled = true;
606                                 break;
607                         case 'L': /* compression: log of blocks-per-cluster */
608                                 c.compress.required = true;
609                                 val = atoi(optarg);
610                                 if (val < MIN_COMPRESS_LOG_SIZE ||
611                                                 val > MAX_COMPRESS_LOG_SIZE) {
612                                         MSG(0, "\tError: log of blocks per"
613                                                 " cluster must be in the range"
614                                                 " of %d .. %d.\n",
615                                                 MIN_COMPRESS_LOG_SIZE,
616                                                 MAX_COMPRESS_LOG_SIZE);
617                                         error_out(prog);
618                                 }
619                                 c.compress.cc.log_cluster_size = val;
620                                 break;
621                         case 'a': /* compression: choose algorithm */
622                                 c.compress.required = true;
623                                 c.compress.alg = MAX_COMPRESS_ALGS;
624                                 for (i = 0; i < MAX_COMPRESS_ALGS; i++) {
625                                         if (!strcmp(supported_comp_names[i],
626                                                                 optarg)) {
627                                                 c.compress.alg = i;
628                                                 break;
629                                         }
630                                 }
631                                 if (c.compress.alg == MAX_COMPRESS_ALGS) {
632                                         MSG(0, "\tError: Unknown compression"
633                                                 " algorithm %s\n", optarg);
634                                         error_out(prog);
635                                 }
636                                 break;
637                         case 'i': /* compress only these extensions */
638                                 c.compress.required = true;
639                                 if (c.compress.filter == COMPR_FILTER_ALLOW) {
640                                         MSG(0, "\tError: could not mix option"
641                                                         " -i and -x\n");
642                                         error_out(prog);
643                                 }
644                                 c.compress.filter = COMPR_FILTER_DENY;
645                                 c.compress.filter_ops->add(optarg);
646                                 break;
647                         case 'x': /* compress except for these extensions */
648                                 c.compress.required = true;
649                                 if (c.compress.filter == COMPR_FILTER_DENY) {
650                                         MSG(0, "\tError: could not mix option"
651                                                         " -i and -x\n");
652                                         error_out(prog);
653                                 }
654                                 c.compress.filter = COMPR_FILTER_ALLOW;
655                                 c.compress.filter_ops->add(optarg);
656                                 break;
657                         case 'm': /* minimum compressed blocks per cluster */
658                                 c.compress.required = true;
659                                 val = atoi(optarg);
660                                 if (val <= 0) {
661                                         MSG(0, "\tError: minimum compressed"
662                                                 " blocks per cluster must be"
663                                                 " positive.\n");
664                                         error_out(prog);
665                                 }
666                                 c.compress.min_blocks = val;
667                                 break;
668                         case 'r': /* for setting FI_COMPRESS_RELEASED */
669                                 c.compress.required = true;
670                                 c.compress.readonly = true;
671                                 break;
672                         case 'C':
673                                 c.fs_config_file = absolute_path(optarg);
674                                 break;
675                         case 'd':
676                                 if (!is_digits(optarg)) {
677                                         err = EWRONG_OPT;
678                                         break;
679                                 }
680                                 c.dbg_lv = atoi(optarg);
681                                 MSG(0, "Info: Debug level = %d\n",
682                                                 c.dbg_lv);
683                                 break;
684                         case 'f':
685                                 c.from_dir = absolute_path(optarg);
686                                 break;
687                         case 'p':
688                                 c.target_out_dir = absolute_path(optarg);
689                                 break;
690                         case 's':
691 #ifdef HAVE_LIBSELINUX
692                                 token = strtok(optarg, ",");
693                                 while (token) {
694                                         if (c.nr_opt == max_nr_opt) {
695                                                 MSG(0, "\tError: Expected at most %d selinux opts\n",
696                                                                                 max_nr_opt);
697                                                 error_out(prog);
698                                         }
699                                         c.seopt_file[c.nr_opt].type =
700                                                                 SELABEL_OPT_PATH;
701                                         c.seopt_file[c.nr_opt].value =
702                                                                 absolute_path(token);
703                                         c.nr_opt++;
704                                         token = strtok(NULL, ",");
705                                 }
706 #else
707                                 MSG(0, "Info: Not support selinux opts\n");
708 #endif
709                                 break;
710                         case 'S':
711                                 c.sparse_mode = 1;
712                                 break;
713                         case 't':
714                                 c.mount_point = (char *)optarg;
715                                 break;
716                         case 'T':
717                                 c.fixed_time = strtoul(optarg, &p, 0);
718                                 break;
719                         case 'V':
720                                 show_version(prog);
721                                 exit(0);
722                         case 'P':
723                                 c.preserve_perms = 1;
724                                 break;
725                         default:
726                                 err = EUNKNOWN_OPT;
727                                 break;
728                         }
729                         if (err != NOERROR)
730                                 break;
731                 }
732                 if (c.compress.required && !c.compress.enabled) {
733                         MSG(0, "\tError: compression sub-options are used"
734                                 " without the compression enable (-c) option\n"
735                         );
736                         error_out(prog);
737                 }
738                 if (err == NOERROR && c.compress.enabled) {
739                         c.compress.cc.cluster_size = 1
740                                 << c.compress.cc.log_cluster_size;
741                         if (c.compress.filter == COMPR_FILTER_UNASSIGNED)
742                                 c.compress.filter = COMPR_FILTER_ALLOW;
743                         if (c.compress.min_blocks >=
744                                         c.compress.cc.cluster_size) {
745                                 MSG(0, "\tError: minimum reduced blocks by"
746                                         " compression per cluster must be at"
747                                         " most one less than blocks per"
748                                         " cluster, i.e. %d\n",
749                                         c.compress.cc.cluster_size - 1);
750                                 error_out(prog);
751                         }
752                 }
753 #endif /* WITH_SLOAD */
754         } else if (!strcmp("f2fslabel", prog)) {
755 #ifdef WITH_LABEL
756                 const char *option_string = "V";
757
758                 c.func = LABEL;
759                 while ((option = getopt(argc, argv, option_string)) != EOF) {
760                         switch (option) {
761                         case 'V':
762                                 show_version(prog);
763                                 exit(0);
764                         default:
765                                 err = EUNKNOWN_OPT;
766                                 break;
767                         }
768                         if (err != NOERROR)
769                                 break;
770                 }
771
772                 if (argc > (optind + 2)) { /* unknown argument(s) is(are) passed */
773                         optind += 2;
774                         err = EUNKNOWN_ARG;
775                 } else if (argc == (optind + 2)) { /* change label */
776                         c.vol_label = argv[optind + 1];
777                         argc--;
778                 } else { /* print label */
779                         /*
780                          * Since vol_label was initialized as "", in order to
781                          * distinguish between clear label and print, set
782                          * vol_label as NULL for print case
783                          */
784                         c.vol_label = NULL;
785                 }
786 #endif /* WITH_LABEL */
787         }
788
789         if (err == NOERROR) {
790                 add_default_options();
791
792                 if (optind >= argc) {
793                         MSG(0, "\tError: Device not specified\n");
794                         error_out(prog);
795                 }
796
797                 c.devices[0].path = strdup(argv[optind]);
798                 if (argc > (optind + 1)) {
799                         c.dbg_lv = 0;
800                         err = EUNKNOWN_ARG;
801                 }
802                 if (err == NOERROR)
803                         return;
804         }
805
806         /* print out error */
807         switch (err) {
808         case EWRONG_OPT:
809                 MSG(0, "\tError: Wrong option -%c %s\n", option, optarg);
810                 break;
811         case ENEED_ARG:
812                 MSG(0, "\tError: Need argument for -%c\n", option);
813                 break;
814         case EUNKNOWN_OPT:
815                 MSG(0, "\tError: Unknown option %c\n", option);
816                 break;
817         case EUNKNOWN_ARG:
818                 MSG(0, "\tError: Unknown argument %s\n", argv[optind]);
819                 break;
820         }
821         error_out(prog);
822 }
823
824 static int do_fsck(struct f2fs_sb_info *sbi)
825 {
826         struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
827         u32 flag = le32_to_cpu(ckpt->ckpt_flags);
828         u32 blk_cnt;
829         struct f2fs_compr_blk_cnt cbc;
830         errcode_t ret;
831
832         fsck_init(sbi);
833
834         print_cp_state(flag);
835
836         fsck_chk_and_fix_write_pointers(sbi);
837
838         fsck_chk_curseg_info(sbi);
839
840         if (!c.fix_on && !c.bug_on) {
841                 switch (c.preen_mode) {
842                 case PREEN_MODE_1:
843                         if (fsck_chk_meta(sbi)) {
844                                 MSG(0, "[FSCK] F2FS metadata   [Fail]");
845                                 MSG(0, "\tError: meta does not match, "
846                                         "force check all\n");
847                         } else {
848                                 MSG(0, "[FSCK] F2FS metadata   [Ok..]");
849                                 fsck_free(sbi);
850                                 return FSCK_SUCCESS;
851                         }
852
853                         if (!c.ro)
854                                 c.fix_on = 1;
855                         break;
856                 }
857         } else if (c.preen_mode) {
858                 /*
859                  * we can hit this in 3 situations:
860                  *  1. fsck -f, fix_on has already been set to 1 when
861                  *     parsing options;
862                  *  2. fsck -a && CP_FSCK_FLAG is set, fix_on has already
863                  *     been set to 1 when checking CP_FSCK_FLAG;
864                  *  3. fsck -p 1 && error is detected, then bug_on is set,
865                  *     we set fix_on = 1 here, so that fsck can fix errors
866                  *     automatically
867                 */
868                 c.fix_on = 1;
869         }
870
871         fsck_chk_checkpoint(sbi);
872
873         fsck_chk_quota_node(sbi);
874
875         /* Traverse all block recursively from root inode */
876         blk_cnt = 1;
877         cbc.cnt = 0;
878         cbc.cheader_pgofs = CHEADER_PGOFS_NONE;
879
880         if (c.feature & cpu_to_le32(F2FS_FEATURE_QUOTA_INO)) {
881                 ret = quota_init_context(sbi);
882                 if (ret) {
883                         ASSERT_MSG("quota_init_context failure: %d", ret);
884                         return FSCK_OPERATIONAL_ERROR;
885                 }
886         }
887         fsck_chk_orphan_node(sbi);
888
889         if (fsck_sanity_check_nat(sbi, sbi->root_ino_num))
890                 fsck_chk_root_inode(sbi);
891
892         fsck_chk_node_blk(sbi, NULL, sbi->root_ino_num,
893                         F2FS_FT_DIR, TYPE_INODE, &blk_cnt, &cbc, NULL);
894         fsck_chk_quota_files(sbi);
895
896         ret = fsck_verify(sbi);
897         fsck_free(sbi);
898
899         if (!c.bug_on)
900                 return FSCK_SUCCESS;
901         if (!ret)
902                 return FSCK_ERROR_CORRECTED;
903         return FSCK_ERRORS_LEFT_UNCORRECTED;
904 }
905
906 #ifdef WITH_DUMP
907 static void do_dump(struct f2fs_sb_info *sbi)
908 {
909         struct dump_option *opt = (struct dump_option *)c.private;
910         struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
911         u32 flag = le32_to_cpu(ckpt->ckpt_flags);
912
913         if (opt->end_nat == -1)
914                 opt->end_nat = NM_I(sbi)->max_nid;
915         if (opt->end_sit == -1)
916                 opt->end_sit = SM_I(sbi)->main_segments;
917         if (opt->end_ssa == -1)
918                 opt->end_ssa = SM_I(sbi)->main_segments;
919         if (opt->start_nat != -1)
920                 nat_dump(sbi, opt->start_nat, opt->end_nat);
921         if (opt->start_sit != -1)
922                 sit_dump(sbi, opt->start_sit, opt->end_sit);
923         if (opt->start_ssa != -1)
924                 ssa_dump(sbi, opt->start_ssa, opt->end_ssa);
925         if (opt->blk_addr != -1)
926                 dump_info_from_blkaddr(sbi, opt->blk_addr);
927         if (opt->nid)
928                 dump_node(sbi, opt->nid, 0);
929         if (opt->scan_nid)
930                 dump_node_scan_disk(sbi, opt->scan_nid);
931
932         print_cp_state(flag);
933
934 }
935 #endif
936
937 #ifdef WITH_DEFRAG
938 static int do_defrag(struct f2fs_sb_info *sbi)
939 {
940         struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi);
941
942         if (get_sb(feature) & cpu_to_le32(F2FS_FEATURE_RO)) {
943                 MSG(0, "Not support on readonly image.\n");
944                 return -1;
945         }
946
947         if (c.defrag_start > get_sb(block_count))
948                 goto out_range;
949         if (c.defrag_start < SM_I(sbi)->main_blkaddr)
950                 c.defrag_start = SM_I(sbi)->main_blkaddr;
951
952         if (c.defrag_len == 0)
953                 c.defrag_len = sbi->blocks_per_seg;
954
955         if (c.defrag_start + c.defrag_len > get_sb(block_count))
956                 c.defrag_len = get_sb(block_count) - c.defrag_start;
957
958         if (c.defrag_target == 0) {
959                 c.defrag_target = c.defrag_start - 1;
960                 if (!c.defrag_shrink)
961                         c.defrag_target += c.defrag_len + 1;
962         }
963
964         if (c.defrag_target < SM_I(sbi)->main_blkaddr ||
965                         c.defrag_target > get_sb(block_count))
966                 goto out_range;
967         if (c.defrag_target >= c.defrag_start &&
968                 c.defrag_target < c.defrag_start + c.defrag_len)
969                 goto out_range;
970
971         if (c.defrag_start > c.defrag_target)
972                 MSG(0, "Info: Move 0x%"PRIx64" <- [0x%"PRIx64"-0x%"PRIx64"]\n",
973                                 c.defrag_target,
974                                 c.defrag_start,
975                                 c.defrag_start + c.defrag_len - 1);
976         else
977                 MSG(0, "Info: Move [0x%"PRIx64"-0x%"PRIx64"] -> 0x%"PRIx64"\n",
978                                 c.defrag_start,
979                                 c.defrag_start + c.defrag_len - 1,
980                                 c.defrag_target);
981
982         return f2fs_defragment(sbi, c.defrag_start, c.defrag_len,
983                         c.defrag_target, c.defrag_shrink);
984 out_range:
985         ASSERT_MSG("Out-of-range [0x%"PRIx64" ~ 0x%"PRIx64"] to 0x%"PRIx64"",
986                                 c.defrag_start,
987                                 c.defrag_start + c.defrag_len - 1,
988                                 c.defrag_target);
989         return -1;
990 }
991 #endif
992
993 #ifdef WITH_RESIZE
994 static int do_resize(struct f2fs_sb_info *sbi)
995 {
996         if (!c.target_sectors)
997                 c.target_sectors = c.total_sectors;
998
999         if (c.target_sectors > c.total_sectors) {
1000                 ASSERT_MSG("Out-of-range Target=0x%"PRIx64" / 0x%"PRIx64"",
1001                                 c.target_sectors, c.total_sectors);
1002                 return -1;
1003         }
1004
1005         return f2fs_resize(sbi);
1006 }
1007 #endif
1008
1009 #ifdef WITH_SLOAD
1010 static int init_compr(struct f2fs_sb_info *sbi)
1011 {
1012         if (!c.compress.enabled)
1013                 return 0;
1014
1015         if (!(sbi->raw_super->feature
1016                         & cpu_to_le32(F2FS_FEATURE_COMPRESSION))) {
1017                 MSG(0, "Error: Compression (-c) was requested "
1018                         "but the file system is not created "
1019                         "with such feature.\n");
1020                 return -1;
1021         }
1022         if (!supported_comp_ops[c.compress.alg].init) {
1023                 MSG(0, "Error: The selected compression algorithm is not"
1024                                 " supported\n");
1025                 return -1;
1026         }
1027         c.compress.ops = supported_comp_ops + c.compress.alg;
1028         c.compress.ops->init(&c.compress.cc);
1029         c.compress.ops->reset(&c.compress.cc);
1030         c.compress.cc.rlen = c.compress.cc.cluster_size * F2FS_BLKSIZE;
1031         return 0;
1032 }
1033
1034 static int do_sload(struct f2fs_sb_info *sbi)
1035 {
1036         if (!c.from_dir) {
1037                 MSG(0, "Info: No source directory, but it's okay.\n");
1038                 return 0;
1039         }
1040         if (!c.mount_point)
1041                 c.mount_point = "/";
1042
1043         if (init_compr(sbi))
1044                 return -1;
1045
1046         return f2fs_sload(sbi);
1047 }
1048 #endif
1049
1050 #ifdef WITH_LABEL
1051 static int do_label(struct f2fs_sb_info *sbi)
1052 {
1053         struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi);
1054
1055         if (!c.vol_label) {
1056                 char label[MAX_VOLUME_NAME];
1057
1058                 utf16_to_utf8(label, (const char *)sb->volume_name,
1059                               MAX_VOLUME_NAME, MAX_VOLUME_NAME);
1060                 MSG(0, "Info: volume label = %s\n", label);
1061                 return 0;
1062         }
1063
1064         if (strlen(c.vol_label) > MAX_VOLUME_NAME) {
1065                 ERR_MSG("Label should not exceed %d characters\n", MAX_VOLUME_NAME);
1066                 return -1;
1067         }
1068
1069         utf8_to_utf16((char *)sb->volume_name, (const char *)c.vol_label,
1070                       MAX_VOLUME_NAME, strlen(c.vol_label));
1071
1072         update_superblock(sb, SB_MASK_ALL);
1073
1074         MSG(0, "Info: volume label is changed to %s\n", c.vol_label);
1075
1076         return 0;
1077 }
1078 #endif
1079
1080 #ifdef HAVE_MACH_TIME_H
1081 static u64 get_boottime_ns()
1082 {
1083         return mach_absolute_time();
1084 }
1085 #elif defined(HAVE_CLOCK_GETTIME) && defined(HAVE_CLOCK_BOOTTIME)
1086 static u64 get_boottime_ns()
1087 {
1088         struct timespec t;
1089         t.tv_sec = t.tv_nsec = 0;
1090         clock_gettime(CLOCK_BOOTTIME, &t);
1091         return (u64)t.tv_sec * 1000000000LL + t.tv_nsec;
1092 }
1093 #else
1094 static u64 get_boottime_ns()
1095 {
1096         return 0;
1097 }
1098 #endif
1099
1100 int main(int argc, char **argv)
1101 {
1102         struct f2fs_sb_info *sbi;
1103         int ret = 0, ret2;
1104         u64 start = get_boottime_ns();
1105
1106         f2fs_init_configuration();
1107
1108         f2fs_parse_options(argc, argv);
1109
1110         if (c.func != DUMP && f2fs_devs_are_umounted() < 0) {
1111                 if (errno == EBUSY) {
1112                         ret = -1;
1113                         if (c.func == FSCK)
1114                                 ret = FSCK_OPERATIONAL_ERROR;
1115                         goto quick_err;
1116                 }
1117                 if (!c.ro || c.func == DEFRAG) {
1118                         MSG(0, "\tError: Not available on mounted device!\n");
1119                         ret = -1;
1120                         if (c.func == FSCK)
1121                                 ret = FSCK_OPERATIONAL_ERROR;
1122                         goto quick_err;
1123                 }
1124
1125                 /* allow ro-mounted partition */
1126                 if (c.force) {
1127                         MSG(0, "Info: Force to check/repair FS on RO mounted device\n");
1128                 } else {
1129                         MSG(0, "Info: Check FS only on RO mounted device\n");
1130                         c.fix_on = 0;
1131                         c.auto_fix = 0;
1132                 }
1133         }
1134
1135         /* Get device */
1136         if (f2fs_get_device_info() < 0 || f2fs_get_f2fs_info() < 0) {
1137                 ret = -1;
1138                 if (c.func == FSCK)
1139                         ret = FSCK_OPERATIONAL_ERROR;
1140                 goto quick_err;
1141         }
1142
1143 fsck_again:
1144         memset(&gfsck, 0, sizeof(gfsck));
1145         gfsck.sbi.fsck = &gfsck;
1146         sbi = &gfsck.sbi;
1147
1148         ret = f2fs_do_mount(sbi);
1149         if (ret != 0) {
1150                 if (ret == 1) {
1151                         MSG(0, "Info: No error was reported\n");
1152                         ret = 0;
1153                 }
1154                 goto out_err;
1155         }
1156
1157         switch (c.func) {
1158         case FSCK:
1159                 ret = do_fsck(sbi);
1160                 break;
1161 #ifdef WITH_DUMP
1162         case DUMP:
1163                 do_dump(sbi);
1164                 break;
1165 #endif
1166 #ifdef WITH_DEFRAG
1167         case DEFRAG:
1168                 ret = do_defrag(sbi);
1169                 if (ret)
1170                         goto out_err;
1171                 break;
1172 #endif
1173 #ifdef WITH_RESIZE
1174         case RESIZE:
1175                 if (do_resize(sbi))
1176                         goto out_err;
1177                 break;
1178 #endif
1179 #ifdef WITH_SLOAD
1180         case SLOAD:
1181                 if (do_sload(sbi))
1182                         goto out_err;
1183
1184                 ret = f2fs_sparse_initialize_meta(sbi);
1185                 if (ret < 0)
1186                         goto out_err;
1187
1188                 f2fs_do_umount(sbi);
1189
1190                 /* fsck to fix missing quota */
1191                 c.func = FSCK;
1192                 c.fix_on = 1;
1193                 goto fsck_again;
1194 #endif
1195 #ifdef WITH_LABEL
1196         case LABEL:
1197                 if (do_label(sbi))
1198                         goto out_err;
1199                 break;
1200 #endif
1201         default:
1202                 ERR_MSG("Wrong program name\n");
1203                 ASSERT(0);
1204         }
1205
1206         f2fs_do_umount(sbi);
1207
1208         if (c.func == FSCK && c.bug_on) {
1209                 if (!c.ro && c.fix_on == 0 && c.auto_fix == 0 && !c.dry_run) {
1210                         char ans[255] = {0};
1211 retry:
1212                         printf("Do you want to fix this partition? [Y/N] ");
1213                         ret2 = scanf("%s", ans);
1214                         ASSERT(ret2 >= 0);
1215                         if (!strcasecmp(ans, "y"))
1216                                 c.fix_on = 1;
1217                         else if (!strcasecmp(ans, "n"))
1218                                 c.fix_on = 0;
1219                         else
1220                                 goto retry;
1221
1222                         if (c.fix_on)
1223                                 goto fsck_again;
1224                 }
1225         }
1226         ret2 = f2fs_finalize_device();
1227         if (ret2) {
1228                 if (c.func == FSCK)
1229                         return FSCK_OPERATIONAL_ERROR;
1230                 return ret2;
1231         }
1232
1233         if (c.func == SLOAD)
1234                 c.compress.filter_ops->destroy();
1235
1236         if (!c.show_file_map)
1237                 printf("\nDone: %lf secs\n", (get_boottime_ns() - start) / 1000000000.0);
1238         return ret;
1239
1240 out_err:
1241         if (sbi->ckpt)
1242                 free(sbi->ckpt);
1243         if (sbi->raw_super)
1244                 free(sbi->raw_super);
1245 quick_err:
1246         f2fs_release_sparse_resource();
1247         return ret;
1248 }