123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335 |
- /*
- * rfddump.c
- *
- * Copyright (C) 2005 Sean Young <sean@mess.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
- #define PROGRAM_NAME "rfddump"
- #define _XOPEN_SOURCE 500 /* For pread */
- #include <stdio.h>
- #include <stdlib.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <sys/ioctl.h>
- #include <string.h>
- #include <fcntl.h>
- #include <unistd.h>
- #include <getopt.h>
- #include <mtd/mtd-user.h>
- #include <linux/types.h>
- #include <mtd_swab.h>
- #include "common.h"
- /* next is an array of mapping for each corresponding sector */
- #define RFD_MAGIC 0x9193
- #define HEADER_MAP_OFFSET 3
- #define SECTOR_DELETED 0x0000
- #define SECTOR_ZERO 0xfffe
- #define SECTOR_FREE 0xffff
- #define SECTOR_SIZE 512
- #define SECTORS_PER_TRACK 63
- struct rfd {
- int block_size;
- int block_count;
- int header_sectors;
- int data_sectors;
- int header_size;
- uint16_t *header;
- int sector_count;
- int *sector_map;
- const char *mtd_filename;
- const char *out_filename;
- int verbose;
- };
- static void display_help(int status)
- {
- printf("Usage: %s [OPTIONS] MTD-device filename\n"
- "Dumps the contents of a resident flash disk\n"
- "\n"
- "-h --help display this help and exit\n"
- "-V --version output version information and exit\n"
- "-v --verbose Be verbose\n"
- "-b size --blocksize Block size (defaults to erase unit)\n",
- PROGRAM_NAME);
- exit(status);
- }
- static void display_version(void)
- {
- common_print_version();
- printf("This is free software; see the source for copying conditions. There is NO\n"
- "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n");
- exit(0);
- }
- static void process_options(int argc, char *argv[], struct rfd *rfd)
- {
- int error = 0;
- rfd->block_size = 0;
- rfd->verbose = 0;
- for (;;) {
- int option_index = 0;
- static const char *short_options = "hvVb:";
- static const struct option long_options[] = {
- { "help", no_argument, 0, 'h' },
- { "version", no_argument, 0, 'V', },
- { "blocksize", required_argument, 0, 'b' },
- { "verbose", no_argument, 0, 'v' },
- { NULL, 0, 0, 0 }
- };
- int c = getopt_long(argc, argv, short_options,
- long_options, &option_index);
- if (c == EOF)
- break;
- switch (c) {
- case 'h':
- display_help(EXIT_SUCCESS);
- break;
- case 'V':
- display_version();
- break;
- case 'v':
- rfd->verbose = 1;
- break;
- case 'b':
- rfd->block_size = atoi(optarg);
- break;
- case '?':
- error = 1;
- break;
- }
- }
- if ((argc - optind) != 2 || error)
- display_help(EXIT_FAILURE);
- rfd->mtd_filename = argv[optind];
- rfd->out_filename = argv[optind + 1];
- }
- static int build_block_map(struct rfd *rfd, int fd, int block)
- {
- int i;
- int sectors;
- if (pread(fd, rfd->header, rfd->header_size, block * rfd->block_size)
- != rfd->header_size) {
- return -1;
- }
- if (le16_to_cpu(rfd->header[0]) != RFD_MAGIC) {
- if (rfd->verbose)
- printf("Block #%02d: Magic missing\n", block);
- return 0;
- }
- sectors = 0;
- for (i=0; i<rfd->data_sectors; i++) {
- uint16_t entry = le16_to_cpu(rfd->header[i + HEADER_MAP_OFFSET]);
- if (entry == SECTOR_FREE || entry == SECTOR_DELETED)
- continue;
- if (entry == SECTOR_ZERO)
- entry = 0;
- if (entry >= rfd->sector_count) {
- fprintf(stderr, "%s: warning: sector %d out of range\n",
- rfd->mtd_filename, entry);
- continue;
- }
- if (rfd->sector_map[entry] != -1) {
- fprintf(stderr, "%s: warning: more than one entry "
- "for sector %d\n", rfd->mtd_filename, entry);
- continue;
- }
- rfd->sector_map[entry] = rfd->block_size * block +
- (i + rfd->header_sectors) * SECTOR_SIZE;
- sectors++;
- }
- if (rfd->verbose)
- printf("Block #%02d: %d sectors\n", block, sectors);
- return 1;
- }
- int main(int argc, char *argv[])
- {
- int fd, sectors_per_block;
- mtd_info_t mtd_info;
- struct rfd rfd;
- int i, blocks_found;
- int out_fd = 0;
- uint8_t sector[512];
- int blank, rc, cylinders;
- process_options(argc, argv, &rfd);
- fd = open(rfd.mtd_filename, O_RDONLY);
- if (fd == -1) {
- perror(rfd.mtd_filename);
- return 1;
- }
- if (rfd.block_size == 0) {
- if (ioctl(fd, MEMGETINFO, &mtd_info)) {
- perror(rfd.mtd_filename);
- close(fd);
- return 1;
- }
- if (mtd_info.type != MTD_NORFLASH) {
- fprintf(stderr, "%s: wrong type\n", rfd.mtd_filename);
- close(fd);
- return 2;
- }
- sectors_per_block = mtd_info.erasesize / SECTOR_SIZE;
- rfd.block_size = mtd_info.erasesize;
- rfd.block_count = mtd_info.size / mtd_info.erasesize;
- } else {
- struct stat st;
- if (fstat(fd, &st) == -1) {
- perror(rfd.mtd_filename);
- close(fd);
- return 1;
- }
- if (st.st_size % SECTOR_SIZE)
- fprintf(stderr, "%s: warning: not a multiple of sectors (512 bytes)\n", rfd.mtd_filename);
- sectors_per_block = rfd.block_size / SECTOR_SIZE;
- if (st.st_size % rfd.block_size)
- fprintf(stderr, "%s: warning: not a multiple of block size\n", rfd.mtd_filename);
- rfd.block_count = st.st_size / rfd.block_size;
- if (!rfd.block_count) {
- fprintf(stderr, "%s: not large enough for one block\n", rfd.mtd_filename);
- close(fd);
- return 2;
- }
- }
- rfd.header_sectors =
- ((HEADER_MAP_OFFSET + sectors_per_block) *
- sizeof(uint16_t) + SECTOR_SIZE - 1) / SECTOR_SIZE;
- rfd.data_sectors = sectors_per_block - rfd.header_sectors;
- cylinders = ((rfd.block_count - 1) * rfd.data_sectors - 1)
- / SECTORS_PER_TRACK;
- rfd.sector_count = cylinders * SECTORS_PER_TRACK;
- rfd.header_size =
- (HEADER_MAP_OFFSET + rfd.data_sectors) * sizeof(uint16_t);
- rfd.header = malloc(rfd.header_size);
- if (!rfd.header) {
- perror(PROGRAM_NAME);
- close(fd);
- return 2;
- }
- rfd.sector_map = malloc(rfd.sector_count * sizeof(int));
- if (!rfd.sector_map) {
- perror(PROGRAM_NAME);
- close(fd);
- free(rfd.sector_map);
- return 2;
- }
- rfd.mtd_filename = rfd.mtd_filename;
- for (i=0; i<rfd.sector_count; i++)
- rfd.sector_map[i] = -1;
- for (blocks_found=i=0; i<rfd.block_count; i++) {
- rc = build_block_map(&rfd, fd, i);
- if (rc > 0)
- blocks_found++;
- if (rc < 0)
- goto err;
- }
- if (!blocks_found) {
- fprintf(stderr, "%s: no RFD blocks found\n", rfd.mtd_filename);
- goto err;
- }
- for (i=0; i<rfd.sector_count; i++) {
- if (rfd.sector_map[i] != -1)
- break;
- }
- if (i == rfd.sector_count) {
- fprintf(stderr, "%s: no sectors found\n", rfd.mtd_filename);
- goto err;
- }
- out_fd = open(rfd.out_filename, O_WRONLY | O_TRUNC | O_CREAT, 0666);
- if (out_fd == -1) {
- perror(rfd.out_filename);
- goto err;
- }
- blank = 0;
- for (i=0; i<rfd.sector_count; i++) {
- if (rfd.sector_map[i] == -1) {
- memset(sector, 0, SECTOR_SIZE);
- blank++;
- } else {
- if (pread(fd, sector, SECTOR_SIZE, rfd.sector_map[i])
- != SECTOR_SIZE) {
- perror(rfd.mtd_filename);
- goto err;
- }
- }
- if (write(out_fd, sector, SECTOR_SIZE) != SECTOR_SIZE) {
- perror(rfd.out_filename);
- goto err;
- }
- }
- if (rfd.verbose)
- printf("Copied %d sectors (%d blank)\n", rfd.sector_count, blank);
- close(out_fd);
- close(fd);
- free(rfd.header);
- free(rfd.sector_map);
- return 0;
- err:
- if (out_fd > 0)
- close(out_fd);
- close(fd);
- free(rfd.header);
- free(rfd.sector_map);
- return 2;
- }
|