Add macro make_build in spec file
[platform/upstream/dosfstools.git] / src / fsck.fat.c
1 /* fsck.fat.c - User interface
2
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>
7
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.
12
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.
17
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/>.
20
21    The complete text of the GNU General Public License
22    can be found in /usr/share/common-licenses/GPL-3 file.
23 */
24
25 /* FAT32, VFAT, Atari format support, and various fixes additions May 1998
26  * by Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> */
27
28 #include "version.h"
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <stdlib.h>
34 #include <errno.h>
35 #include <ctype.h>
36 #include <limits.h>
37 #include <unistd.h>
38 #include <termios.h>
39 #include <getopt.h>
40
41 #include "common.h"
42 #include "fsck.fat.h"
43 #include "io.h"
44 #include "boot.h"
45 #include "fat.h"
46 #include "file.h"
47 #include "check.h"
48 #include "charconv.h"
49
50 int rw = 0, list = 0, test = 0, verbose = 0;
51 long fat_table = 0;
52 int no_spaces_in_sfns = 0;
53 int only_uppercase_label = 0;
54 int boot_only = 0;
55 unsigned n_files = 0;
56 void *mem_queue = NULL;
57
58 static struct termios original_termios;
59
60
61 static void restore_termios(void)
62 {
63     tcsetattr(0, TCSAFLUSH, &original_termios);
64 }
65
66
67 static void usage(char *name, int exitval)
68 {
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");
96     exit(exitval);
97 }
98
99 int main(int argc, char **argv)
100 {
101     DOS_FS fs;
102     int salvage_files, verify, c;
103     uint32_t free_clusters = 0;
104     struct termios tio;
105     char *tmp;
106     long codepage;
107
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},
112             {0,}
113     };
114
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);
120     }
121
122     memset(&fs, 0, sizeof(fs));
123     salvage_files = verify = 0;
124     rw = interactive = 1;
125     check_atari();
126
127     while ((c = getopt_long(argc, argv, "Aac:d:bfF:lnprStu:UvVwy",
128                                     long_options, NULL)) != -1)
129         switch (c) {
130         case 'A':               /* toggle Atari format */
131             atari_format = !atari_format;
132             break;
133         case 'a':
134         case 'p':
135         case 'y':
136             rw = 1;
137             interactive = 0;
138             salvage_files = 1;
139             break;
140         case 'b':
141             rw = 0;
142             interactive = 0;
143             boot_only = 1;
144             break;
145         case 'c':
146             errno = 0;
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);
150                 usage(argv[0], 2);
151             }
152             if (!set_dos_codepage(codepage))
153                 usage(argv[0], 2);
154             break;
155         case 'd':
156             file_add(optarg, fdt_drop);
157             break;
158         case 'f':
159             salvage_files = 1;
160             break;
161         case 'F':
162             errno = 0;
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);
166                 usage(argv[0], 2);
167             }
168             break;
169         case 'l':
170             list = 1;
171             break;
172         case 'n':
173             rw = 0;
174             interactive = 0;
175             break;
176         case 'r':
177             rw = 1;
178             interactive = 1;
179             break;
180         case 'S':
181             no_spaces_in_sfns = 1;
182             break;
183         case 't':
184             test = 1;
185             break;
186         case 'u':
187             file_add(optarg, fdt_undelete);
188             break;
189         case 'U':
190             only_uppercase_label = 1;
191             break;
192         case 'v':
193             verbose = 1;
194             break;
195         case 'V':
196             verify = 1;
197             break;
198         case OPT_VARIANT:
199             if (!strcasecmp(optarg, "standard")) {
200                     atari_format = 0;
201             } else if (!strcasecmp(optarg, "atari")) {
202                     atari_format = 1;
203             } else {
204                     fprintf(stderr, "Unknown variant: %s\n", optarg);
205                     usage(argv[0], 2);
206             }
207             break;
208         case 'w':
209             write_immed = 1;
210             break;
211         case OPT_HELP:
212             usage(argv[0], 0);
213             break;
214         case '?':
215             usage(argv[0], 2);
216             break;
217         default:
218             fprintf(stderr,
219                     "Internal error: getopt_long() returned unexpected value %d\n", c);
220             exit(3);
221         }
222     if (!set_dos_codepage(-1))  /* set default codepage if none was given in command line */
223         exit(2);
224     if ((test || write_immed) && !rw) {
225         fprintf(stderr, "-t and -w can not be used in read only mode\n");
226         exit(2);
227     }
228     if (optind != argc - 1)
229         usage(argv[0], 2);
230
231     printf("fsck.fat " VERSION " (" VERSION_DATE ")\n");
232     fs_open(argv[optind], rw);
233
234     read_boot(&fs);
235     if (boot_only)
236         goto exit;
237
238     if (verify)
239         printf("Starting check/repair pass.\n");
240     while (read_fat(&fs, 2), scan_root(&fs))
241         qfree(&mem_queue);
242     check_label(&fs);
243     if (test)
244         fix_bad(&fs);
245     if (salvage_files)
246         reclaim_file(&fs);
247     else
248         reclaim_free(&fs);
249     if (!atari_format)
250         check_dirty_bits(&fs);
251     free_clusters = update_free(&fs);
252     file_unused();
253     qfree(&mem_queue);
254     if (verify) {
255         n_files = 0;
256         printf("Starting verification pass.\n");
257         read_fat(&fs, 2);
258         scan_root(&fs);
259         check_label(&fs);
260         reclaim_free(&fs);
261         if (!atari_format)
262             check_dirty_bits(&fs);
263         qfree(&mem_queue);
264     }
265     release_fat(&fs);
266
267 exit:
268     if (!write_immed && fs_changed()) {
269         if (rw) {
270             printf("\n*** Filesystem was changed ***\n");
271             if (interactive)
272                 printf("The changes have not yet been written, you can still choose to leave the\n"
273                        "filesystem unmodified:\n");
274
275             rw = get_choice(1, "Writing changes.",
276                             2,
277                             1, "Write changes",
278                             2, "Leave filesystem unchanged") == 1;
279         } else
280             printf("\nLeaving filesystem unchanged.\n");
281     }
282
283     if (!boot_only)
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);
287
288     return fs_close(rw) ? 1 : 0;
289 }