OSDN Git Service

Add MS7619SE
[uclinux-h8/uClinux-dist.git] / user / mtd-utils / rfddump.c
1 /*
2  * rfddump.c
3  *
4  * Copyright (C) 2005 Sean Young <sean@mess.org>
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  */
11
12 #define PROGRAM_NAME "rfddump"
13 #define VERSION "$Revision 1.0 $"
14
15 #define _XOPEN_SOURCE 500 /* For pread */
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <sys/ioctl.h>
22 #include <string.h>
23 #include <fcntl.h>
24 #include <unistd.h>
25 #include <getopt.h>
26
27 #include <mtd/mtd-user.h>
28 #include <linux/types.h>
29 #include <mtd_swab.h>
30
31 /* next is an array of mapping for each corresponding sector */
32 #define RFD_MAGIC               0x9193
33 #define HEADER_MAP_OFFSET       3
34 #define SECTOR_DELETED          0x0000
35 #define SECTOR_ZERO             0xfffe
36 #define SECTOR_FREE             0xffff
37
38 #define SECTOR_SIZE             512
39
40 #define SECTORS_PER_TRACK       63
41
42
43 struct rfd {
44         int block_size;
45         int block_count;
46         int header_sectors;
47         int data_sectors;
48         int header_size;
49         uint16_t *header;
50         int sector_count;
51         int *sector_map;
52         const char *mtd_filename;
53         const char *out_filename;
54         int verbose;
55 };
56
57 void display_help(void)
58 {
59         printf("Usage: %s [OPTIONS] MTD-device filename\n"
60                         "Dumps the contents of a resident flash disk\n"
61                         "\n"
62                         "-h         --help               display this help and exit\n"
63                         "-V         --version            output version information and exit\n"
64                         "-v         --verbose           Be verbose\n"
65                         "-b size    --blocksize          Block size (defaults to erase unit)\n",
66                         PROGRAM_NAME);
67         exit(0);
68 }
69
70 void display_version(void)
71 {
72         printf("%s " VERSION "\n"
73                         "\n"
74                         "This is free software; see the source for copying conditions.  There is NO\n"
75                         "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n",
76                         PROGRAM_NAME);
77
78         exit(0);
79 }
80
81 void process_options(int argc, char *argv[], struct rfd *rfd)
82 {
83         int error = 0;
84
85         rfd->block_size = 0;
86         rfd->verbose = 0;
87
88         for (;;) {
89                 int option_index = 0;
90                 static const char *short_options = "hvVb:";
91                 static const struct option long_options[] = {
92                         { "help", no_argument, 0, 'h' },
93                         { "version", no_argument, 0, 'V', },
94                         { "blocksize", required_argument, 0, 'b' },
95                         { "verbose", no_argument, 0, 'v' },
96                         { NULL, 0, 0, 0 }
97                 };
98
99                 int c = getopt_long(argc, argv, short_options,
100                                 long_options, &option_index);
101                 if (c == EOF)
102                         break;
103
104                 switch (c) {
105                         case 'h':
106                                 display_help();
107                                 break;
108                         case 'V':
109                                 display_version();
110                                 break;
111                         case 'v':
112                                 rfd->verbose = 1;
113                                 break;
114                         case 'b':
115                                 rfd->block_size = atoi(optarg);
116                                 break;
117                         case '?':
118                                 error = 1;
119                                 break;
120                 }
121         }
122
123         if ((argc - optind) != 2 || error)
124                 display_help();
125
126         rfd->mtd_filename = argv[optind];
127         rfd->out_filename = argv[optind + 1];
128 }
129
130 int build_block_map(struct rfd *rfd, int fd, int block)
131 {
132         int  i;
133         int sectors;
134
135         if (pread(fd, rfd->header, rfd->header_size, block * rfd->block_size)
136                         != rfd->header_size) {
137                 return -1;
138         }
139
140         if (le16_to_cpu(rfd->header[0]) != RFD_MAGIC) {
141                 if (rfd->verbose)
142                         printf("Block #%02d: Magic missing\n", block);
143
144                 return 0;
145         }
146
147         sectors =  0;
148         for (i=0; i<rfd->data_sectors; i++) {
149                 uint16_t entry = le16_to_cpu(rfd->header[i + HEADER_MAP_OFFSET]);
150
151                 if (entry == SECTOR_FREE || entry == SECTOR_DELETED)
152                         continue;
153
154                 if (entry == SECTOR_ZERO)
155                         entry = 0;
156
157                 if (entry >= rfd->sector_count) {
158                         fprintf(stderr, "%s: warning: sector %d out of range\n",
159                                         rfd->mtd_filename, entry);
160                         continue;
161                 }
162
163                 if (rfd->sector_map[entry] != -1) {
164                         fprintf(stderr, "%s: warning: more than one entry "
165                                         "for sector %d\n", rfd->mtd_filename, entry);
166                         continue;
167                 }
168
169                 rfd->sector_map[entry] = rfd->block_size * block +
170                         (i + rfd->header_sectors) * SECTOR_SIZE;
171                 sectors++;
172         }
173
174         if (rfd->verbose)
175                 printf("Block #%02d: %d sectors\n", block, sectors);
176
177         return 1;
178 }
179
180 int main(int argc, char *argv[])
181 {
182         int fd, sectors_per_block;
183         mtd_info_t mtd_info;
184         struct rfd rfd;
185         int i, blocks_found;
186         int out_fd = 0;
187         uint8_t sector[512];
188         int blank, rc, cylinders;
189
190         process_options(argc, argv, &rfd);
191
192         fd = open(rfd.mtd_filename, O_RDONLY);
193         if (fd == -1) {
194                 perror(rfd.mtd_filename);
195                 return 1;
196         }
197
198         if (rfd.block_size == 0) {
199                 if (ioctl(fd, MEMGETINFO, &mtd_info)) {
200                         perror(rfd.mtd_filename);
201                         close(fd);
202                         return 1;
203                 }
204
205                 if (mtd_info.type != MTD_NORFLASH) {
206                         fprintf(stderr, "%s: wrong type\n", rfd.mtd_filename);
207                         close(fd);
208                         return 2;
209                 }
210
211                 sectors_per_block = mtd_info.erasesize / SECTOR_SIZE;
212
213                 rfd.block_size = mtd_info.erasesize;
214                 rfd.block_count = mtd_info.size / mtd_info.erasesize;
215         } else {
216                 struct stat st;
217
218                 if (fstat(fd, &st) == -1) {
219                         perror(rfd.mtd_filename);
220                         close(fd);
221                         return 1;
222                 }
223
224                 if (st.st_size % SECTOR_SIZE)
225                         fprintf(stderr, "%s: warning: not a multiple of sectors (512 bytes)\n", rfd.mtd_filename);
226
227                 sectors_per_block = rfd.block_size / SECTOR_SIZE;
228
229                 if (st.st_size % rfd.block_size)
230                         fprintf(stderr, "%s: warning: not a multiple of block size\n", rfd.mtd_filename);
231
232                 rfd.block_count = st.st_size / rfd.block_size;
233
234                 if (!rfd.block_count) {
235                         fprintf(stderr, "%s: not large enough for one block\n", rfd.mtd_filename);
236                         close(fd);
237                         return 2;
238                 }
239         }
240
241         rfd.header_sectors =
242                 ((HEADER_MAP_OFFSET + sectors_per_block) *
243                  sizeof(uint16_t) + SECTOR_SIZE - 1) / SECTOR_SIZE;
244         rfd.data_sectors = sectors_per_block - rfd.header_sectors;
245         cylinders = ((rfd.block_count - 1) * rfd.data_sectors - 1)
246                 / SECTORS_PER_TRACK;
247         rfd.sector_count = cylinders * SECTORS_PER_TRACK;
248         rfd.header_size =
249                 (HEADER_MAP_OFFSET + rfd.data_sectors) * sizeof(uint16_t);
250
251         rfd.header = malloc(rfd.header_size);
252         if (!rfd.header) {
253                 perror(PROGRAM_NAME);
254                 close(fd);
255                 return 2;
256         }
257         rfd.sector_map = malloc(rfd.sector_count * sizeof(int));
258         if (!rfd.sector_map) {
259                 perror(PROGRAM_NAME);
260                 close(fd);
261                 free(rfd.sector_map);
262                 return 2;
263         }
264
265         rfd.mtd_filename = rfd.mtd_filename;
266
267         for (i=0; i<rfd.sector_count; i++)
268                 rfd.sector_map[i] = -1;
269
270         for (blocks_found=i=0; i<rfd.block_count; i++) {
271                 rc = build_block_map(&rfd, fd, i);
272                 if (rc > 0)
273                         blocks_found++;
274                 if (rc < 0)
275                         goto err;
276         }
277
278         if (!blocks_found) {
279                 fprintf(stderr, "%s: no RFD blocks found\n", rfd.mtd_filename);
280                 goto err;
281         }
282
283         for (i=0; i<rfd.sector_count; i++) {
284                 if (rfd.sector_map[i] != -1)
285                         break;
286         }
287
288         if (i == rfd.sector_count) {
289                 fprintf(stderr, "%s: no sectors found\n", rfd.mtd_filename);
290                 goto err;
291         }
292
293         out_fd = open(rfd.out_filename, O_WRONLY | O_TRUNC | O_CREAT, 0666);
294         if (out_fd == -1) {
295                 perror(rfd.out_filename);
296                 goto err;
297         }
298
299         blank = 0;
300         for (i=0; i<rfd.sector_count; i++) {
301                 if (rfd.sector_map[i] == -1) {
302                         memset(sector, 0, SECTOR_SIZE);
303                         blank++;
304                 } else {
305                         if (pread(fd, sector, SECTOR_SIZE, rfd.sector_map[i])
306                                         != SECTOR_SIZE) {
307                                 perror(rfd.mtd_filename);
308                                 goto err;
309                         }
310                 }
311
312                 if (write(out_fd, sector, SECTOR_SIZE) != SECTOR_SIZE) {
313                         perror(rfd.out_filename);
314                         goto err;
315                 }
316         }
317
318         if (rfd.verbose)
319                 printf("Copied %d sectors (%d blank)\n", rfd.sector_count, blank);
320
321         close(out_fd);
322         close(fd);
323         free(rfd.header);
324         free(rfd.sector_map);
325
326         return 0;
327
328 err:
329         if (out_fd)
330                 close(out_fd);
331
332         close(fd);
333         free(rfd.header);
334         free(rfd.sector_map);
335
336         return 2;
337 }
338