123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406 |
- #define PROGRAM_NAME "flashcp"
- #include <stdio.h>
- #include <stdarg.h>
- #include <string.h>
- #include <stdlib.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <sys/ioctl.h>
- #include <fcntl.h>
- #include <unistd.h>
- #include <mtd/mtd-user.h>
- #include <getopt.h>
- #include "common.h"
- #ifdef DEBUG
- #undef DEBUG
- #define DEBUG(fmt,args...) { log_printf (LOG_ERROR,"%d: ",__LINE__); log_printf (LOG_ERROR,fmt,## args); }
- #else
- #undef DEBUG
- #define DEBUG(fmt,args...)
- #endif
- #define KB(x) ((x) / 1024)
- #define PERCENTAGE(x,total) (((x) * 100) / (total))
- #define BUFSIZE (10 * 1024)
- #define FLAG_NONE 0x00
- #define FLAG_VERBOSE 0x01
- #define FLAG_HELP 0x02
- #define FLAG_FILENAME 0x04
- #define FLAG_DEVICE 0x08
- #define FLAG_ERASE_ALL 0x10
- #define LOG_NORMAL 1
- #define LOG_ERROR 2
- static void log_printf (int level,const char *fmt, ...)
- {
- FILE *fp = level == LOG_NORMAL ? stdout : stderr;
- va_list ap;
- va_start (ap,fmt);
- vfprintf (fp,fmt,ap);
- va_end (ap);
- fflush (fp);
- }
- static NORETURN void showusage(bool error)
- {
- int level = error ? LOG_ERROR : LOG_NORMAL;
- log_printf (level,
- "\n"
- "Flash Copy - Written by Abraham van der Merwe <abraham@2d3d.co.za>\n"
- "\n"
- "usage: %1$s [ -v | --verbose | -A | --erase-all ] <filename> <device>\n"
- " %1$s -h | --help\n"
- " %1$s -V | --version\n"
- "\n"
- " -h | --help Show this help message\n"
- " -v | --verbose Show progress reports\n"
- " -A | --erase-all Erases the whole device regardless of the image size\n"
- " -V | --version Show version information and exit\n"
- " <filename> File which you want to copy to flash\n"
- " <device> Flash device to write to (e.g. /dev/mtd0, /dev/mtd1, etc.)\n"
- "\n",
- PROGRAM_NAME);
- exit (error ? EXIT_FAILURE : EXIT_SUCCESS);
- }
- static int safe_open (const char *pathname,int flags)
- {
- int fd;
- fd = open (pathname,flags);
- if (fd < 0)
- {
- log_printf (LOG_ERROR,"While trying to open %s",pathname);
- if (flags & O_RDWR)
- log_printf (LOG_ERROR," for read/write access");
- else if (flags & O_RDONLY)
- log_printf (LOG_ERROR," for read access");
- else if (flags & O_WRONLY)
- log_printf (LOG_ERROR," for write access");
- log_printf (LOG_ERROR,": %m\n");
- exit (EXIT_FAILURE);
- }
- return (fd);
- }
- static void safe_read (int fd,const char *filename,void *buf,size_t count,bool verbose)
- {
- ssize_t result;
- result = read (fd,buf,count);
- if (count != result)
- {
- if (verbose) log_printf (LOG_NORMAL,"\n");
- if (result < 0)
- {
- log_printf (LOG_ERROR,"While reading data from %s: %m\n",filename);
- exit (EXIT_FAILURE);
- }
- log_printf (LOG_ERROR,"Short read count returned while reading from %s\n",filename);
- exit (EXIT_FAILURE);
- }
- }
- static void safe_rewind (int fd,const char *filename)
- {
- if (lseek (fd,0L,SEEK_SET) < 0)
- {
- log_printf (LOG_ERROR,"While seeking to start of %s: %m\n",filename);
- exit (EXIT_FAILURE);
- }
- }
- static int dev_fd = -1,fil_fd = -1;
- static void cleanup (void)
- {
- if (dev_fd > 0) close (dev_fd);
- if (fil_fd > 0) close (fil_fd);
- }
- int main (int argc,char *argv[])
- {
- const char *filename = NULL,*device = NULL;
- int i,flags = FLAG_NONE;
- ssize_t result;
- size_t size,written;
- struct mtd_info_user mtd;
- struct erase_info_user erase;
- struct stat filestat;
- unsigned char src[BUFSIZE],dest[BUFSIZE];
-
- for (;;) {
- int option_index = 0;
- static const char *short_options = "hvAV";
- static const struct option long_options[] = {
- {"help", no_argument, 0, 'h'},
- {"verbose", no_argument, 0, 'v'},
- {"erase-all", no_argument, 0, 'A'},
- {"version", no_argument, 0, 'V'},
- {0, 0, 0, 0},
- };
- int c = getopt_long(argc, argv, short_options,
- long_options, &option_index);
- if (c == EOF) {
- break;
- }
- switch (c) {
- case 'h':
- flags |= FLAG_HELP;
- DEBUG("Got FLAG_HELP\n");
- break;
- case 'v':
- flags |= FLAG_VERBOSE;
- DEBUG("Got FLAG_VERBOSE\n");
- break;
- case 'A':
- flags |= FLAG_ERASE_ALL;
- DEBUG("Got FLAG_ERASE_ALL\n");
- break;
- case 'V':
- common_print_version();
- exit(EXIT_SUCCESS);
- break;
- default:
- DEBUG("Unknown parameter: %s\n",argv[option_index]);
- showusage(true);
- }
- }
- if (optind+2 == argc) {
- flags |= FLAG_FILENAME;
- filename = argv[optind];
- DEBUG("Got filename: %s\n",filename);
- flags |= FLAG_DEVICE;
- device = argv[optind+1];
- DEBUG("Got device: %s\n",device);
- }
- if (flags & FLAG_HELP || device == NULL)
- showusage(flags != FLAG_HELP);
- atexit (cleanup);
-
- dev_fd = safe_open (device,O_SYNC | O_RDWR);
- if (ioctl (dev_fd,MEMGETINFO,&mtd) < 0)
- {
- DEBUG("ioctl(): %m\n");
- log_printf (LOG_ERROR,"This doesn't seem to be a valid MTD flash device!\n");
- exit (EXIT_FAILURE);
- }
-
- fil_fd = safe_open (filename,O_RDONLY);
- if (fstat (fil_fd,&filestat) < 0)
- {
- log_printf (LOG_ERROR,"While trying to get the file status of %s: %m\n",filename);
- exit (EXIT_FAILURE);
- }
-
- if (filestat.st_size > mtd.size)
- {
- log_printf (LOG_ERROR,"%s won't fit into %s!\n",filename,device);
- exit (EXIT_FAILURE);
- }
-
- #warning "Check for smaller erase regions"
- erase.start = 0;
- if (flags & FLAG_ERASE_ALL)
- {
- erase.length = mtd.size;
- }
- else
- {
- erase.length = (filestat.st_size + mtd.erasesize - 1) / mtd.erasesize;
- erase.length *= mtd.erasesize;
- }
- if (flags & FLAG_VERBOSE)
- {
-
- int blocks = erase.length / mtd.erasesize;
- erase.length = mtd.erasesize;
- log_printf (LOG_NORMAL,"Erasing blocks: 0/%d (0%%)",blocks);
- for (i = 1; i <= blocks; i++)
- {
- log_printf (LOG_NORMAL,"\rErasing blocks: %d/%d (%d%%)",i,blocks,PERCENTAGE (i,blocks));
- if (ioctl (dev_fd,MEMERASE,&erase) < 0)
- {
- log_printf (LOG_NORMAL,"\n");
- log_printf (LOG_ERROR,
- "While erasing blocks 0x%.8x-0x%.8x on %s: %m\n",
- (unsigned int) erase.start,(unsigned int) (erase.start + erase.length),device);
- exit (EXIT_FAILURE);
- }
- erase.start += mtd.erasesize;
- }
- log_printf (LOG_NORMAL,"\rErasing blocks: %d/%d (100%%)\n",blocks,blocks);
- }
- else
- {
-
- if (ioctl (dev_fd,MEMERASE,&erase) < 0)
- {
- log_printf (LOG_ERROR,
- "While erasing blocks from 0x%.8x-0x%.8x on %s: %m\n",
- (unsigned int) erase.start,(unsigned int) (erase.start + erase.length),device);
- exit (EXIT_FAILURE);
- }
- }
- DEBUG("Erased %u / %luk bytes\n",erase.length,filestat.st_size);
-
- if (flags & FLAG_VERBOSE) log_printf (LOG_NORMAL,"Writing data: 0k/%lluk (0%%)",KB ((unsigned long long)filestat.st_size));
- size = filestat.st_size;
- i = BUFSIZE;
- written = 0;
- while (size)
- {
- if (size < BUFSIZE) i = size;
- if (flags & FLAG_VERBOSE)
- log_printf (LOG_NORMAL,"\rWriting data: %dk/%lluk (%llu%%)",
- KB (written + i),
- KB ((unsigned long long)filestat.st_size),
- PERCENTAGE (written + i,(unsigned long long)filestat.st_size));
-
- safe_read (fil_fd,filename,src,i,flags & FLAG_VERBOSE);
-
- result = write (dev_fd,src,i);
- if (i != result)
- {
- if (flags & FLAG_VERBOSE) log_printf (LOG_NORMAL,"\n");
- if (result < 0)
- {
- log_printf (LOG_ERROR,
- "While writing data to 0x%.8lx-0x%.8lx on %s: %m\n",
- written,written + i,device);
- exit (EXIT_FAILURE);
- }
- log_printf (LOG_ERROR,
- "Short write count returned while writing to x%.8zx-0x%.8zx on %s: %zu/%llu bytes written to flash\n",
- written,written + i,device,written + result,(unsigned long long)filestat.st_size);
- exit (EXIT_FAILURE);
- }
- written += i;
- size -= i;
- }
- if (flags & FLAG_VERBOSE)
- log_printf (LOG_NORMAL,
- "\rWriting data: %lluk/%lluk (100%%)\n",
- KB ((unsigned long long)filestat.st_size),
- KB ((unsigned long long)filestat.st_size));
- DEBUG("Wrote %d / %lluk bytes\n",written,(unsigned long long)filestat.st_size);
-
- safe_rewind (fil_fd,filename);
- safe_rewind (dev_fd,device);
- size = filestat.st_size;
- i = BUFSIZE;
- written = 0;
- if (flags & FLAG_VERBOSE) log_printf (LOG_NORMAL,"Verifying data: 0k/%lluk (0%%)",KB ((unsigned long long)filestat.st_size));
- while (size)
- {
- if (size < BUFSIZE) i = size;
- if (flags & FLAG_VERBOSE)
- log_printf (LOG_NORMAL,
- "\rVerifying data: %luk/%lluk (%llu%%)",
- KB (written + i),
- KB ((unsigned long long)filestat.st_size),
- PERCENTAGE (written + i,(unsigned long long)filestat.st_size));
-
- safe_read (fil_fd,filename,src,i,flags & FLAG_VERBOSE);
-
- safe_read (dev_fd,device,dest,i,flags & FLAG_VERBOSE);
-
- if (memcmp (src,dest,i))
- {
- log_printf (LOG_ERROR,
- "File does not seem to match flash data. First mismatch at 0x%.8zx-0x%.8zx\n",
- written,written + i);
- exit (EXIT_FAILURE);
- }
- written += i;
- size -= i;
- }
- if (flags & FLAG_VERBOSE)
- log_printf (LOG_NORMAL,
- "\rVerifying data: %lluk/%lluk (100%%)\n",
- KB ((unsigned long long)filestat.st_size),
- KB ((unsigned long long)filestat.st_size));
- DEBUG("Verified %d / %lluk bytes\n",written,(unsigned long long)filestat.st_size);
- exit (EXIT_SUCCESS);
- }
|