1 /* fsck.fat.c - User interface
3 Copyright (C) 1993 Werner Almesberger <werner.almesberger@lrc.di.epfl.ch>
4 Copyright (C) 1998 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
5 Copyright (C) 2008-2014 Daniel Baumann <mail@daniel-baumann.ch>
6 Copyright (C) 2018-2021 Pali Rohár <pali.rohar@gmail.com>
8 This program is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 The complete text of the GNU General Public License
22 can be found in /usr/share/common-licenses/GPL-3 file.
25 /* FAT32, VFAT, Atari format support, and various fixes additions May 1998
26 * by Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> */
50 int rw = 0, list = 0, test = 0, verbose = 0;
52 int no_spaces_in_sfns = 0;
53 int only_uppercase_label = 0;
56 void *mem_queue = NULL;
58 static struct termios original_termios;
61 static void restore_termios(void)
63 tcsetattr(0, TCSAFLUSH, &original_termios);
67 static void usage(char *name, int exitval)
69 fprintf(stderr, "Usage: %s [OPTIONS] DEVICE\n", name);
70 fprintf(stderr, "Check FAT filesystem on DEVICE for errors.\n");
71 fprintf(stderr, "\n");
72 fprintf(stderr, "Options:\n");
73 fprintf(stderr, " -a automatically repair the filesystem\n");
74 fprintf(stderr, " -A toggle Atari variant of the FAT filesystem\n");
75 fprintf(stderr, " -b make read-only boot sector check\n");
76 fprintf(stderr, " -c N use DOS codepage N to decode short file names (default: %d)\n",
77 DEFAULT_DOS_CODEPAGE);
78 fprintf(stderr, " -d PATH drop file with name PATH (can be given multiple times)\n");
79 fprintf(stderr, " -f salvage unused chains to files\n");
80 fprintf(stderr, " -F NUM specify FAT table NUM used for filesystem access\n");
81 fprintf(stderr, " -l list path names\n");
82 fprintf(stderr, " -n no-op, check non-interactively without changing\n");
83 fprintf(stderr, " -p same as -a, for compat with other *fsck\n");
84 fprintf(stderr, " -r interactively repair the filesystem (default)\n");
85 fprintf(stderr, " -S disallow spaces in the middle of short file names\n");
86 fprintf(stderr, " -t test for bad clusters\n");
87 fprintf(stderr, " -u PATH try to undelete (non-directory) file that was named PATH (can be\n");
88 fprintf(stderr, " given multiple times)\n");
89 fprintf(stderr, " -U allow only uppercase characters in volume and boot label\n");
90 fprintf(stderr, " -v verbose mode\n");
91 fprintf(stderr, " -V perform a verification pass\n");
92 fprintf(stderr, " --variant=TYPE handle variant TYPE of the filesystem\n");
93 fprintf(stderr, " -w write changes to disk immediately\n");
94 fprintf(stderr, " -y same as -a, for compat with other *fsck\n");
95 fprintf(stderr, " --help print this message\n");
99 int main(int argc, char **argv)
102 int salvage_files, verify, c;
103 uint32_t free_clusters = 0;
108 enum {OPT_HELP=1000, OPT_VARIANT};
109 const struct option long_options[] = {
110 {"variant", required_argument, NULL, OPT_VARIANT},
111 {"help", no_argument, NULL, OPT_HELP},
115 if (!tcgetattr(0, &original_termios)) {
116 tio = original_termios;
117 tio.c_lflag &= ~(ICANON | ECHO);
118 tcsetattr(0, TCSAFLUSH, &tio);
119 atexit(restore_termios);
122 memset(&fs, 0, sizeof(fs));
123 salvage_files = verify = 0;
124 rw = interactive = 1;
127 while ((c = getopt_long(argc, argv, "Aac:d:bfF:lnprStu:UvVwy",
128 long_options, NULL)) != -1)
130 case 'A': /* toggle Atari format */
131 atari_format = !atari_format;
147 codepage = strtol(optarg, &tmp, 10);
148 if (!*optarg || isspace(*optarg) || *tmp || errno || codepage < 0 || codepage > INT_MAX) {
149 fprintf(stderr, "Invalid codepage : %s\n", optarg);
152 if (!set_dos_codepage(codepage))
156 file_add(optarg, fdt_drop);
163 fat_table = strtol(optarg, &tmp, 10);
164 if (!*optarg || isspace(*optarg) || *tmp || errno || fat_table < 0 || fat_table > 255) {
165 fprintf(stderr, "Invalid FAT table : %s\n", optarg);
181 no_spaces_in_sfns = 1;
187 file_add(optarg, fdt_undelete);
190 only_uppercase_label = 1;
199 if (!strcasecmp(optarg, "standard")) {
201 } else if (!strcasecmp(optarg, "atari")) {
204 fprintf(stderr, "Unknown variant: %s\n", optarg);
219 "Internal error: getopt_long() returned unexpected value %d\n", c);
222 if (!set_dos_codepage(-1)) /* set default codepage if none was given in command line */
224 if ((test || write_immed) && !rw) {
225 fprintf(stderr, "-t and -w can not be used in read only mode\n");
228 if (optind != argc - 1)
231 printf("fsck.fat " VERSION " (" VERSION_DATE ")\n");
232 fs_open(argv[optind], rw);
239 printf("Starting check/repair pass.\n");
240 while (read_fat(&fs, 2), scan_root(&fs))
250 check_dirty_bits(&fs);
251 free_clusters = update_free(&fs);
256 printf("Starting verification pass.\n");
262 check_dirty_bits(&fs);
268 if (!write_immed && fs_changed()) {
270 printf("\n*** Filesystem was changed ***\n");
272 printf("The changes have not yet been written, you can still choose to leave the\n"
273 "filesystem unmodified:\n");
275 rw = get_choice(1, "Writing changes.",
278 2, "Leave filesystem unchanged") == 1;
280 printf("\nLeaving filesystem unchanged.\n");
284 printf("%s: %u files, %lu/%lu clusters\n", argv[optind],
285 n_files, (unsigned long)fs.data_clusters - free_clusters,
286 (unsigned long)fs.data_clusters);
288 return fs_close(rw) ? 1 : 0;