blob: e1dcdfa0f5af5074561f7d63a91f0871c6c264a3 [file] [log] [blame]
Alistair Delvabeaee832021-02-24 11:27:23 -08001/* Copyright 1995-1999,2001-2003,2007,2009,2011 Alain Knaff.
2 * This file is part of mtools.
3 *
4 * Mtools is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * Mtools is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with Mtools. If not, see <http://www.gnu.org/licenses/>.
16 *
17 * mbadblocks.c
18 * Mark bad blocks on disk
19 *
20 */
21
22#include "sysincludes.h"
23#include "msdos.h"
24#include "mtools.h"
25#include "mainloop.h"
26#include "fsP.h"
27
28#define N_PATTERN 311
29
30static void usage(int ret) NORETURN;
31static void usage(int ret)
32{
33 fprintf(stderr, "Mtools version %s, dated %s\n",
34 mversion, mdate);
35 fprintf(stderr, "Usage: %s: [-c clusterList] [-s sectorList] [-c] [-V] device\n",
36 progname);
37 exit(ret);
38}
39
40static void checkListTwice(char *filename) {
41 if(filename != NULL) {
42 fprintf(stderr, "Only one of the -c or -s options may be given\n");
43 exit(1);
44 }
45}
46
47/**
48 * Marks given cluster as bad, but prints error instead if cluster already used
49 */
Yi Kong39bbd962022-01-09 19:41:38 +080050static void mark(Fs_t *Fs, uint32_t offset, uint32_t badClus) {
51 uint32_t old = Fs->fat_decode((Fs_t*)Fs, offset);
Alistair Delvabeaee832021-02-24 11:27:23 -080052 if(old == 0) {
53 fatEncode((Fs_t*)Fs, offset, badClus);
54 return;
55 }
56 if(old == badClus) {
Yi Kong39bbd962022-01-09 19:41:38 +080057 fprintf(stderr, "Cluster %d already marked\n", offset);
Alistair Delvabeaee832021-02-24 11:27:23 -080058 } else {
Yi Kong39bbd962022-01-09 19:41:38 +080059 fprintf(stderr, "Cluster %d is busy\n", offset);
Alistair Delvabeaee832021-02-24 11:27:23 -080060 }
61}
62
63static char *in_buf;
64static char *pat_buf;
65static size_t in_len;
66
67
68static void progress(unsigned int i, unsigned int total) {
69 if(i % 10 == 0)
70 fprintf(stderr, " \r%d/%d\r", i, total);
71}
72
73static int scan(Fs_t *Fs, Stream_t *dev,
Yi Kong39bbd962022-01-09 19:41:38 +080074 uint32_t cluster, uint32_t badClus,
Alistair Delvabeaee832021-02-24 11:27:23 -080075 char *buffer, int doWrite) {
Yi Kong39bbd962022-01-09 19:41:38 +080076 uint32_t start;
Alistair Delvabeaee832021-02-24 11:27:23 -080077 off_t ret;
Yi Kong39bbd962022-01-09 19:41:38 +080078 mt_off_t pos;
Alistair Delvabeaee832021-02-24 11:27:23 -080079 int bad=0;
80
81 if(Fs->fat_decode((Fs_t*)Fs, cluster))
82 /* cluster busy, or already marked */
83 return 0;
84 start = (cluster - 2) * Fs->cluster_size + Fs->clus_start;
Yi Kong39bbd962022-01-09 19:41:38 +080085 pos = sectorsToBytes(Fs, start);
Alistair Delvabeaee832021-02-24 11:27:23 -080086 if(doWrite) {
Yi Kong39bbd962022-01-09 19:41:38 +080087 ret = force_pwrite(dev, buffer, pos, in_len);
88 if(ret < 0 || (size_t) ret < in_len )
Alistair Delvabeaee832021-02-24 11:27:23 -080089 bad = 1;
90 } else {
Yi Kong39bbd962022-01-09 19:41:38 +080091 ret = force_pread(dev, in_buf, pos, in_len);
Alistair Delvabeaee832021-02-24 11:27:23 -080092 if(ret < (off_t) in_len )
93 bad = 1;
94 else if(buffer) {
95 size_t i;
96 for(i=0; i<in_len; i++)
97 if(in_buf[i] != buffer[i]) {
98 bad = 1;
99 break;
100 }
101 }
102 }
103
104 if(bad) {
Yi Kong39bbd962022-01-09 19:41:38 +0800105 printf("Bad cluster %d found\n", cluster);
Alistair Delvabeaee832021-02-24 11:27:23 -0800106 fatEncode((Fs_t*)Fs, cluster, badClus);
107 return 1;
108 }
109 return 0;
110}
111
112void mbadblocks(int argc, char **argv, int type UNUSEDP) NORETURN;
113void mbadblocks(int argc, char **argv, int type UNUSEDP)
114{
115 unsigned int i;
116 unsigned int startSector=2;
117 unsigned int endSector=0;
118 struct MainParam_t mp;
119 Fs_t *Fs;
120 Stream_t *Dir;
121 int ret;
122 char *filename = NULL;
123 int c;
124 unsigned int badClus;
125 int sectorMode=0;
126 int writeMode=0;
127
128 while ((c = getopt(argc, argv, "i:s:cwS:E:")) != EOF) {
129 switch(c) {
130 case 'i':
131 set_cmd_line_image(optarg);
132 break;
133 case 'c':
134 checkListTwice(filename);
135 filename = strdup(optarg);
136 break;
137 case 's':
138 checkListTwice(filename);
139 filename = strdup(optarg);
140 sectorMode = 1;
141 break;
142 case 'S':
Yi Kong39bbd962022-01-09 19:41:38 +0800143 startSector = atoui(optarg);
Alistair Delvabeaee832021-02-24 11:27:23 -0800144 break;
145 case 'E':
Yi Kong39bbd962022-01-09 19:41:38 +0800146 endSector = atoui(optarg);
Alistair Delvabeaee832021-02-24 11:27:23 -0800147 break;
148 case 'w':
149 writeMode = 1;
150 break;
151 case 'h':
152 usage(0);
153 default:
154 usage(1);
155 }
156 }
157
158 if (argc != optind+1 ||
159 !argv[optind][0] || argv[optind][1] != ':' || argv[optind][2]) {
160 usage(1);
161 }
162
163 init_mp(&mp);
164
165 Dir = open_root_dir(argv[optind][0], O_RDWR, NULL);
166 if (!Dir) {
167 fprintf(stderr,"%s: Cannot initialize drive\n", argv[0]);
168 exit(1);
169 }
170
171 Fs = (Fs_t *)GetFs(Dir);
172 in_len = Fs->cluster_size * Fs->sector_size;
173 in_buf = malloc(in_len);
174 if(!in_buf) {
175 printOom();
176 ret = 1;
177 goto exit_0;
178 }
179 if(writeMode) {
180 pat_buf=malloc(in_len * N_PATTERN);
181 if(!pat_buf) {
182 printOom();
183 ret = 1;
184 goto exit_0;
185 }
186 init_random();
187 for(i=0; i < in_len * N_PATTERN; i++) {
Yi Kong39bbd962022-01-09 19:41:38 +0800188 pat_buf[i] = (char) random();
Alistair Delvabeaee832021-02-24 11:27:23 -0800189 }
190 }
191 for(i=0; i < Fs->clus_start; i++ ){
Yi Kong39bbd962022-01-09 19:41:38 +0800192 ssize_t r;
193 r = PREADS(Fs->head.Next, in_buf,
194 sectorsToBytes(Fs, i), Fs->sector_size);
195 if( r < 0 ){
Alistair Delvabeaee832021-02-24 11:27:23 -0800196 perror("early error");
Yi Kong39bbd962022-01-09 19:41:38 +0800197 ret = -1;
Alistair Delvabeaee832021-02-24 11:27:23 -0800198 goto exit_0;
199 }
Yi Kong39bbd962022-01-09 19:41:38 +0800200 if((size_t) r < Fs->sector_size){
Alistair Delvabeaee832021-02-24 11:27:23 -0800201 fprintf(stderr,"end of file in file_read\n");
202 ret = 1;
203 goto exit_0;
204 }
205 }
206 ret = 0;
207
208 badClus = Fs->last_fat + 1;
209
210 if(startSector < 2)
211 startSector = 2;
Yi Kong39bbd962022-01-09 19:41:38 +0800212 if(endSector > Fs->num_clus + 2 || endSector <= 0)
Alistair Delvabeaee832021-02-24 11:27:23 -0800213 endSector = Fs->num_clus + 2;
214
215 if(filename) {
216 char line[80];
217
218 FILE *f = fopen(filename, "r");
219 if(f == NULL) {
220 fprintf(stderr, "Could not open %s (%s)\n",
221 filename, strerror(errno));
222 ret = 1;
223 goto exit_0;
224 }
225 while(fgets(line, sizeof(line), f)) {
226 char *ptr = line + strspn(line, " \t");
Yi Kong39bbd962022-01-09 19:41:38 +0800227 uint32_t offset = strtou32(ptr, 0, 0);
Alistair Delvabeaee832021-02-24 11:27:23 -0800228 if(sectorMode)
229 offset = (offset-Fs->clus_start)/Fs->cluster_size + 2;
230 if(offset < 2) {
231 fprintf(stderr, "Sector before start\n");
232 } else if(offset >= Fs->num_clus) {
233 fprintf(stderr, "Sector beyond end\n");
234 } else {
235 mark(Fs, offset, badClus);
236 ret = 1;
237 }
238 }
239 } else {
240 Stream_t *dev;
Yi Kong39bbd962022-01-09 19:41:38 +0800241 dev = Fs->head.Next;
Alistair Delvabeaee832021-02-24 11:27:23 -0800242 if(dev->Next)
243 dev = dev->Next;
244
245 in_len = Fs->cluster_size * Fs->sector_size;
246 if(writeMode) {
247 /* Write pattern */
248 for(i=startSector; i< endSector; i++){
249 if(got_signal)
250 break;
251 progress(i, Fs->num_clus);
Yi Kong39bbd962022-01-09 19:41:38 +0800252 ret |= scan(Fs, dev, i, badClus,
Alistair Delvabeaee832021-02-24 11:27:23 -0800253 pat_buf + in_len * (i % N_PATTERN),
254 1);
255 }
256
257 /* Flush cache, so that we are sure we read the data
258 back from disk, rather than from the cache */
259 if(!got_signal)
260 DISCARD(dev);
261
262 /* Read data back, and compare to pattern */
263 for(i=startSector; i< endSector; i++){
264 if(got_signal)
265 break;
266 progress(i, Fs->num_clus);
Yi Kong39bbd962022-01-09 19:41:38 +0800267 ret |= scan(Fs, dev, i, badClus,
Alistair Delvabeaee832021-02-24 11:27:23 -0800268 pat_buf + in_len * (i % N_PATTERN),
269 0);
270 }
271
272 } else {
273
274 for(i=startSector; i< endSector; i++){
275 if(got_signal)
276 break;
277 progress(i, Fs->num_clus);
278 ret |= scan(Fs, dev, i, badClus, NULL, 0);
279 }
280 }
281 }
282 exit_0:
283 FREE(&Dir);
284 exit(ret);
285}