4 * Copyright (C) 2005 Sean Young <sean@mess.org>
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.
12 #define PROGRAM_NAME "rfddump"
13 #define VERSION "$Revision 1.0 $"
15 #define _XOPEN_SOURCE 500 /* For pread */
19 #include <sys/types.h>
21 #include <sys/ioctl.h>
27 #include <mtd/mtd-user.h>
28 #include <linux/types.h>
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
38 #define SECTOR_SIZE 512
40 #define SECTORS_PER_TRACK 63
52 const char *mtd_filename;
53 const char *out_filename;
57 void display_help(void)
59 printf("Usage: %s [OPTIONS] MTD-device filename\n"
60 "Dumps the contents of a resident flash disk\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",
70 void display_version(void)
72 printf("%s " VERSION "\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",
81 void process_options(int argc, char *argv[], struct rfd *rfd)
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' },
99 int c = getopt_long(argc, argv, short_options,
100 long_options, &option_index);
115 rfd->block_size = atoi(optarg);
123 if ((argc - optind) != 2 || error)
126 rfd->mtd_filename = argv[optind];
127 rfd->out_filename = argv[optind + 1];
130 int build_block_map(struct rfd *rfd, int fd, int block)
135 if (pread(fd, rfd->header, rfd->header_size, block * rfd->block_size)
136 != rfd->header_size) {
140 if (le16_to_cpu(rfd->header[0]) != RFD_MAGIC) {
142 printf("Block #%02d: Magic missing\n", block);
148 for (i=0; i<rfd->data_sectors; i++) {
149 uint16_t entry = le16_to_cpu(rfd->header[i + HEADER_MAP_OFFSET]);
151 if (entry == SECTOR_FREE || entry == SECTOR_DELETED)
154 if (entry == SECTOR_ZERO)
157 if (entry >= rfd->sector_count) {
158 fprintf(stderr, "%s: warning: sector %d out of range\n",
159 rfd->mtd_filename, entry);
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);
169 rfd->sector_map[entry] = rfd->block_size * block +
170 (i + rfd->header_sectors) * SECTOR_SIZE;
175 printf("Block #%02d: %d sectors\n", block, sectors);
180 int main(int argc, char *argv[])
182 int fd, sectors_per_block;
188 int blank, rc, cylinders;
190 process_options(argc, argv, &rfd);
192 fd = open(rfd.mtd_filename, O_RDONLY);
194 perror(rfd.mtd_filename);
198 if (rfd.block_size == 0) {
199 if (ioctl(fd, MEMGETINFO, &mtd_info)) {
200 perror(rfd.mtd_filename);
205 if (mtd_info.type != MTD_NORFLASH) {
206 fprintf(stderr, "%s: wrong type\n", rfd.mtd_filename);
211 sectors_per_block = mtd_info.erasesize / SECTOR_SIZE;
213 rfd.block_size = mtd_info.erasesize;
214 rfd.block_count = mtd_info.size / mtd_info.erasesize;
218 if (fstat(fd, &st) == -1) {
219 perror(rfd.mtd_filename);
224 if (st.st_size % SECTOR_SIZE)
225 fprintf(stderr, "%s: warning: not a multiple of sectors (512 bytes)\n", rfd.mtd_filename);
227 sectors_per_block = rfd.block_size / SECTOR_SIZE;
229 if (st.st_size % rfd.block_size)
230 fprintf(stderr, "%s: warning: not a multiple of block size\n", rfd.mtd_filename);
232 rfd.block_count = st.st_size / rfd.block_size;
234 if (!rfd.block_count) {
235 fprintf(stderr, "%s: not large enough for one block\n", rfd.mtd_filename);
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)
247 rfd.sector_count = cylinders * SECTORS_PER_TRACK;
249 (HEADER_MAP_OFFSET + rfd.data_sectors) * sizeof(uint16_t);
251 rfd.header = malloc(rfd.header_size);
253 perror(PROGRAM_NAME);
257 rfd.sector_map = malloc(rfd.sector_count * sizeof(int));
258 if (!rfd.sector_map) {
259 perror(PROGRAM_NAME);
261 free(rfd.sector_map);
265 rfd.mtd_filename = rfd.mtd_filename;
267 for (i=0; i<rfd.sector_count; i++)
268 rfd.sector_map[i] = -1;
270 for (blocks_found=i=0; i<rfd.block_count; i++) {
271 rc = build_block_map(&rfd, fd, i);
279 fprintf(stderr, "%s: no RFD blocks found\n", rfd.mtd_filename);
283 for (i=0; i<rfd.sector_count; i++) {
284 if (rfd.sector_map[i] != -1)
288 if (i == rfd.sector_count) {
289 fprintf(stderr, "%s: no sectors found\n", rfd.mtd_filename);
293 out_fd = open(rfd.out_filename, O_WRONLY | O_TRUNC | O_CREAT, 0666);
295 perror(rfd.out_filename);
300 for (i=0; i<rfd.sector_count; i++) {
301 if (rfd.sector_map[i] == -1) {
302 memset(sector, 0, SECTOR_SIZE);
305 if (pread(fd, sector, SECTOR_SIZE, rfd.sector_map[i])
307 perror(rfd.mtd_filename);
312 if (write(out_fd, sector, SECTOR_SIZE) != SECTOR_SIZE) {
313 perror(rfd.out_filename);
319 printf("Copied %d sectors (%d blank)\n", rfd.sector_count, blank);
324 free(rfd.sector_map);
334 free(rfd.sector_map);