Bump to 4.0.43
[platform/upstream/mtools.git] / mbadblocks.c
1 /*  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 "mtools.h"
24 #include "fsP.h"
25
26 #define N_PATTERN 311
27
28 static void usage(int ret) NORETURN;
29 static void usage(int ret)
30 {
31         fprintf(stderr, "Mtools version %s, dated %s\n",
32                 mversion, mdate);
33         fprintf(stderr, "Usage: %s: [-c clusterList] [-s sectorList] [-c] [-V] device\n",
34                 progname);
35         exit(ret);
36 }
37
38 static void checkListTwice(char *filename) {
39         if(filename != NULL) {
40                 fprintf(stderr, "Only one of the -c or -s options may be given\n");
41                 exit(1);
42         }
43 }
44
45 /**
46  * Marks given cluster as bad, but prints error instead if cluster already used
47  */
48 static void mark(Fs_t *Fs, uint32_t offset, uint32_t badClus) {
49         uint32_t old = Fs->fat_decode((Fs_t*)Fs, offset);
50         if(old == 0) {
51                 fatEncode((Fs_t*)Fs, offset, badClus);
52                 return;
53         }
54         if(old == badClus) {
55                 fprintf(stderr, "Cluster %d already marked\n", offset);
56         } else {
57                 fprintf(stderr, "Cluster %d is busy\n", offset);
58         }
59 }
60
61 static char *in_buf;
62 static char *pat_buf;
63 static size_t in_len;
64
65
66 static void progress(unsigned int i, unsigned int total) {
67         if(i % 10 == 0)
68                 fprintf(stderr, "                     \r%d/%d\r", i, total);
69 }
70
71 static int scan(Fs_t *Fs, Stream_t *dev,
72                 uint32_t cluster, uint32_t badClus,
73                 char *buffer, int doWrite) {
74         uint32_t start;
75         off_t ret;
76         mt_off_t pos;
77         int bad=0;
78
79         if(Fs->fat_decode((Fs_t*)Fs, cluster))
80                 /* cluster busy, or already marked */
81                 return 0;
82         start = (cluster - 2) * Fs->cluster_size + Fs->clus_start;
83         pos = sectorsToBytes(Fs, start);
84         if(doWrite) {
85                 ret = force_pwrite(dev, buffer, pos, in_len);
86                 if(ret < 0 || (size_t) ret < in_len )
87                         bad = 1;
88         } else {
89                 ret = force_pread(dev, in_buf, pos, in_len);
90                 if(ret < (off_t) in_len )
91                         bad = 1;
92                 else if(buffer) {
93                         size_t i;
94                         for(i=0; i<in_len; i++)
95                                 if(in_buf[i] != buffer[i]) {
96                                         bad = 1;
97                                         break;
98                                 }
99                 }
100         }
101
102         if(bad) {
103                 printf("Bad cluster %d found\n", cluster);
104                 fatEncode((Fs_t*)Fs, cluster, badClus);
105                 return 1;
106         }
107         return 0;
108 }
109
110 void mbadblocks(int argc, char **argv, int type UNUSEDP) NORETURN;
111 void mbadblocks(int argc, char **argv, int type UNUSEDP)
112 {
113         unsigned int i;
114         unsigned int startSector=2;
115         unsigned int endSector=0;
116         Fs_t *Fs;
117         Stream_t *Dir;
118         int ret;
119         char *filename = NULL;
120         int c;
121         unsigned int badClus;
122         int sectorMode=0;
123         int writeMode=0;
124
125         while ((c = getopt(argc, argv, "i:s:cwS:E:")) != EOF) {
126                 switch(c) {
127                 case 'i':
128                         set_cmd_line_image(optarg);
129                         break;
130                 case 'c':
131                         checkListTwice(filename);
132                         filename = strdup(optarg);
133                         break;
134                 case 's':
135                         checkListTwice(filename);
136                         filename = strdup(optarg);
137                         sectorMode = 1;
138                         break;
139                 case 'S':
140                         startSector = atoui(optarg);
141                         break;
142                 case 'E':
143                         endSector = atoui(optarg);
144                         break;
145                 case 'w':
146                         writeMode = 1;
147                         break;
148                 case 'h':
149                         usage(0);
150                 default:
151                         usage(1);
152                 }
153         }
154
155         if (argc != optind+1 ||
156             !argv[optind][0] || argv[optind][1] != ':' || argv[optind][2]) {
157                 usage(1);
158         }
159
160         Dir = open_root_dir(argv[optind][0], O_RDWR, NULL);
161         if (!Dir) {
162                 fprintf(stderr,"%s: Cannot initialize drive\n", argv[0]);
163                 exit(1);
164         }
165
166         Fs = (Fs_t *)GetFs(Dir);
167         in_len = Fs->cluster_size * Fs->sector_size;
168         in_buf = malloc(in_len);
169         if(!in_buf) {
170                 printOom();
171                 ret = 1;
172                 goto exit_0;
173         }
174         if(writeMode) {
175                 pat_buf=malloc(in_len * N_PATTERN);
176                 if(!pat_buf) {
177                         printOom();
178                         ret = 1;
179                         goto exit_0;
180                 }
181                 init_random();
182                 for(i=0; i < in_len * N_PATTERN; i++) {
183                         pat_buf[i] = (char) random();
184                 }
185         }
186         for(i=0; i < Fs->clus_start; i++ ){
187                 ssize_t r;
188                 r = PREADS(Fs->head.Next, in_buf,
189                            sectorsToBytes(Fs, i), Fs->sector_size);
190                 if( r < 0 ){
191                         perror("early error");
192                         ret = -1;
193                         goto exit_0;
194                 }
195                 if((size_t) r < Fs->sector_size){
196                         fprintf(stderr,"end of file in file_read\n");
197                         ret = 1;
198                         goto exit_0;
199                 }
200         }
201         ret = 0;
202
203         badClus = Fs->last_fat + 1;
204
205         if(startSector < 2)
206                 startSector = 2;
207         if(endSector > Fs->num_clus + 2 || endSector <= 0)
208                 endSector = Fs->num_clus + 2;
209
210         if(filename) {
211                 char line[80];
212
213                 FILE *f = fopen(filename, "r");
214                 if(f == NULL) {
215                         fprintf(stderr, "Could not open %s (%s)\n",
216                                 filename, strerror(errno));
217                         ret = 1;
218                         goto exit_0;
219                 }
220                 while(fgets(line, sizeof(line), f)) {
221                         char *ptr = line + strspn(line, " \t");
222                         uint32_t offset = strtou32(ptr, 0, 0);
223                         if(sectorMode)
224                                 offset = (offset-Fs->clus_start)/Fs->cluster_size + 2;
225                         if(offset < 2) {
226                                 fprintf(stderr, "Sector before start\n");
227                         } else if(offset >= Fs->num_clus) {
228                                 fprintf(stderr, "Sector beyond end\n");
229                         } else {
230                                 mark(Fs, offset, badClus);
231                                 ret = 1;
232                         }
233                 }
234         } else {
235                 Stream_t *dev;
236                 dev = Fs->head.Next;
237                 if(dev->Next)
238                         dev = dev->Next;
239
240                 in_len = Fs->cluster_size * Fs->sector_size;
241                 if(writeMode) {
242                         /* Write pattern */
243                         for(i=startSector; i< endSector; i++){
244                                 if(got_signal)
245                                         break;
246                                 progress(i, Fs->num_clus);
247                                 ret |= scan(Fs, dev, i, badClus,
248                                             pat_buf + in_len * (i % N_PATTERN),
249                                             1);
250                         }
251
252                         /* Flush cache, so that we are sure we read the data
253                            back from disk, rather than from the cache */
254                         if(!got_signal)
255                                 DISCARD(dev);
256
257                         /* Read data back, and compare to pattern */
258                         for(i=startSector; i< endSector; i++){
259                                 if(got_signal)
260                                         break;
261                                 progress(i, Fs->num_clus);
262                                 ret |= scan(Fs, dev, i, badClus,
263                                             pat_buf + in_len * (i % N_PATTERN),
264                                             0);
265                         }
266
267                 } else {
268
269                         for(i=startSector; i< endSector; i++){
270                                 if(got_signal)
271                                         break;
272                                 progress(i, Fs->num_clus);
273                                 ret |= scan(Fs, dev, i, badClus, NULL, 0);
274                         }
275                 }
276         }
277  exit_0:
278         FREE(&Dir);
279         exit(ret);
280 }