Merge pull request #1056 from stefanrueger/dry-run
Implement a dry run for -U updates before opening the programmer
This commit is contained in:
commit
0987416387
33
src/fileio.c
33
src/fileio.c
|
@ -100,11 +100,8 @@ static int fileio_num(struct fioparms * fio,
|
||||||
char * filename, FILE * f, AVRMEM * mem, int size,
|
char * filename, FILE * f, AVRMEM * mem, int size,
|
||||||
FILEFMT fmt);
|
FILEFMT fmt);
|
||||||
|
|
||||||
static int fmt_autodetect(char * fname);
|
|
||||||
|
|
||||||
|
char * fileio_fmtstr(FILEFMT format)
|
||||||
|
|
||||||
char * fmtstr(FILEFMT format)
|
|
||||||
{
|
{
|
||||||
switch (format) {
|
switch (format) {
|
||||||
case FMT_AUTO : return "auto-detect"; break;
|
case FMT_AUTO : return "auto-detect"; break;
|
||||||
|
@ -349,7 +346,7 @@ static int ihex2b(char * infile, FILE * inf,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
nextaddr = ihex.loadofs + baseaddr - fileoffset;
|
nextaddr = ihex.loadofs + baseaddr - fileoffset;
|
||||||
if (nextaddr + ihex.reclen > bufsize) {
|
if (nextaddr + ihex.reclen > (unsigned) bufsize) {
|
||||||
avrdude_message(MSG_INFO, "%s: ERROR: address 0x%04x out of range at line %d of %s\n",
|
avrdude_message(MSG_INFO, "%s: ERROR: address 0x%04x out of range at line %d of %s\n",
|
||||||
progname, nextaddr+ihex.reclen, lineno, infile);
|
progname, nextaddr+ihex.reclen, lineno, infile);
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -415,7 +412,6 @@ static int b2srec(unsigned char * inbuf, int bufsize,
|
||||||
unsigned char * buf;
|
unsigned char * buf;
|
||||||
unsigned int nextaddr;
|
unsigned int nextaddr;
|
||||||
int n, nbytes, addr_width;
|
int n, nbytes, addr_width;
|
||||||
int i;
|
|
||||||
unsigned char cksum;
|
unsigned char cksum;
|
||||||
|
|
||||||
char * tmpl=0;
|
char * tmpl=0;
|
||||||
|
@ -463,10 +459,10 @@ static int b2srec(unsigned char * inbuf, int bufsize,
|
||||||
|
|
||||||
cksum += n + addr_width + 1;
|
cksum += n + addr_width + 1;
|
||||||
|
|
||||||
for (i=addr_width; i>0; i--)
|
for (int i=addr_width; i>0; i--)
|
||||||
cksum += (nextaddr >> (i-1) * 8) & 0xff;
|
cksum += (nextaddr >> (i-1) * 8) & 0xff;
|
||||||
|
|
||||||
for (i=nextaddr; i<nextaddr + n; i++) {
|
for (unsigned i=nextaddr; i<nextaddr + n; i++) {
|
||||||
fprintf(outf, "%02X", buf[i]);
|
fprintf(outf, "%02X", buf[i]);
|
||||||
cksum += buf[i];
|
cksum += buf[i];
|
||||||
}
|
}
|
||||||
|
@ -497,7 +493,7 @@ static int b2srec(unsigned char * inbuf, int bufsize,
|
||||||
addr_width = 3;
|
addr_width = 3;
|
||||||
tmpl="S9%02X%06X";
|
tmpl="S9%02X%06X";
|
||||||
}
|
}
|
||||||
else if (startaddr <= 0xffffffff) {
|
else if ((unsigned) startaddr <= 0xffffffff) {
|
||||||
addr_width = 4;
|
addr_width = 4;
|
||||||
tmpl="S9%02X%08X";
|
tmpl="S9%02X%08X";
|
||||||
}
|
}
|
||||||
|
@ -505,7 +501,7 @@ static int b2srec(unsigned char * inbuf, int bufsize,
|
||||||
fprintf(outf, tmpl, n + addr_width + 1, nextaddr);
|
fprintf(outf, tmpl, n + addr_width + 1, nextaddr);
|
||||||
|
|
||||||
cksum += n + addr_width +1;
|
cksum += n + addr_width +1;
|
||||||
for (i=addr_width; i>0; i--)
|
for (int i=addr_width; i>0; i--)
|
||||||
cksum += (nextaddr >> (i - 1) * 8) & 0xff;
|
cksum += (nextaddr >> (i - 1) * 8) & 0xff;
|
||||||
cksum = 0xff - cksum;
|
cksum = 0xff - cksum;
|
||||||
fprintf(outf, "%02X\n", cksum);
|
fprintf(outf, "%02X\n", cksum);
|
||||||
|
@ -600,7 +596,7 @@ static int srec2b(char * infile, FILE * inf,
|
||||||
int len;
|
int len;
|
||||||
struct ihexrec srec;
|
struct ihexrec srec;
|
||||||
int rc;
|
int rc;
|
||||||
int reccount;
|
unsigned int reccount;
|
||||||
unsigned char datarec;
|
unsigned char datarec;
|
||||||
|
|
||||||
char * msg = 0;
|
char * msg = 0;
|
||||||
|
@ -690,7 +686,7 @@ static int srec2b(char * infile, FILE * inf,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
nextaddr -= fileoffset;
|
nextaddr -= fileoffset;
|
||||||
if (nextaddr + srec.reclen > bufsize) {
|
if (nextaddr + srec.reclen > (unsigned) bufsize) {
|
||||||
avrdude_message(MSG_INFO, msg, progname, nextaddr+srec.reclen, "",
|
avrdude_message(MSG_INFO, msg, progname, nextaddr+srec.reclen, "",
|
||||||
lineno, infile);
|
lineno, infile);
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -1009,8 +1005,7 @@ static int elf2b(char * infile, FILE * inf,
|
||||||
* ELF file region for these, and extract the actual byte to write
|
* ELF file region for these, and extract the actual byte to write
|
||||||
* from it, using the "foff" offset obtained above.
|
* from it, using the "foff" offset obtained above.
|
||||||
*/
|
*/
|
||||||
if (mem->size != 1 &&
|
if (mem->size != 1 && sh->sh_size > (unsigned) mem->size) {
|
||||||
sh->sh_size > mem->size) {
|
|
||||||
avrdude_message(MSG_INFO, "%s: ERROR: section \"%s\" does not fit into \"%s\" memory:\n"
|
avrdude_message(MSG_INFO, "%s: ERROR: section \"%s\" does not fit into \"%s\" memory:\n"
|
||||||
" 0x%x + %u > %u\n",
|
" 0x%x + %u > %u\n",
|
||||||
progname, sname, mem->desc,
|
progname, sname, mem->desc,
|
||||||
|
@ -1402,7 +1397,7 @@ int fileio_setparms(int op, struct fioparms * fp,
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static int fmt_autodetect(char * fname)
|
int fileio_fmt_autodetect(const char * fname)
|
||||||
{
|
{
|
||||||
FILE * f;
|
FILE * f;
|
||||||
unsigned char buf[MAX_LINE_LEN];
|
unsigned char buf[MAX_LINE_LEN];
|
||||||
|
@ -1510,7 +1505,7 @@ int fileio(int oprwv, char * filename, FILEFMT format,
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (fio.op == FIO_READ)
|
if (size < 0 || fio.op == FIO_READ)
|
||||||
size = mem->size;
|
size = mem->size;
|
||||||
|
|
||||||
if (fio.op == FIO_READ) {
|
if (fio.op == FIO_READ) {
|
||||||
|
@ -1547,7 +1542,7 @@ int fileio(int oprwv, char * filename, FILEFMT format,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
format_detect = fmt_autodetect(fname);
|
format_detect = fileio_fmt_autodetect(fname);
|
||||||
if (format_detect < 0) {
|
if (format_detect < 0) {
|
||||||
avrdude_message(MSG_INFO, "%s: can't determine file format for %s, specify explicitly\n",
|
avrdude_message(MSG_INFO, "%s: can't determine file format for %s, specify explicitly\n",
|
||||||
progname, fname);
|
progname, fname);
|
||||||
|
@ -1556,8 +1551,8 @@ int fileio(int oprwv, char * filename, FILEFMT format,
|
||||||
format = format_detect;
|
format = format_detect;
|
||||||
|
|
||||||
if (quell_progress < 2) {
|
if (quell_progress < 2) {
|
||||||
avrdude_message(MSG_INFO, "%s: %s file %s auto detected as %s\n",
|
avrdude_message(MSG_NOTICE, "%s: %s file %s auto detected as %s\n",
|
||||||
progname, fio.iodesc, fname, fmtstr(format));
|
progname, fio.iodesc, fname, fileio_fmtstr(format));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -872,7 +872,9 @@ enum {
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
char * fmtstr(FILEFMT format);
|
char * fileio_fmtstr(FILEFMT format);
|
||||||
|
|
||||||
|
int fileio_fmt_autodetect(const char * fname);
|
||||||
|
|
||||||
int fileio(int oprwv, char * filename, FILEFMT format,
|
int fileio(int oprwv, char * filename, FILEFMT format,
|
||||||
struct avrpart * p, char * memtype, int size);
|
struct avrpart * p, char * memtype, int size);
|
||||||
|
@ -936,6 +938,14 @@ const char *update_inname(const char *fn);
|
||||||
const char *update_outname(const char *fn);
|
const char *update_outname(const char *fn);
|
||||||
const char *update_interval(int a, int b);
|
const char *update_interval(int a, int b);
|
||||||
|
|
||||||
|
// Helper functions for dry run to determine file access
|
||||||
|
int update_is_okfile(const char *fn);
|
||||||
|
int update_is_writeable(const char *fn);
|
||||||
|
int update_is_readable(const char *fn);
|
||||||
|
|
||||||
|
int update_dryrun(struct avrpart *p, UPDATE *upd);
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
20
src/main.c
20
src/main.c
|
@ -901,11 +901,13 @@ int main(int argc, char * argv [])
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now that we know which part we are going to program, locate any
|
* Now that we know which part we are going to program, locate any -U
|
||||||
* -U options using the default memory region, and fill in the
|
* options using the default memory region, fill in the device-dependent
|
||||||
* device-dependent default region name, either "application" (for
|
* default region name ("application" for Xmega parts or "flash" otherwise)
|
||||||
* Xmega devices), or "flash" (everything else).
|
* and check for basic problems with memory names or file access with a
|
||||||
|
* view to exit before programming.
|
||||||
*/
|
*/
|
||||||
|
int doexit = 0;
|
||||||
for (ln=lfirst(updates); ln; ln=lnext(ln)) {
|
for (ln=lfirst(updates); ln; ln=lnext(ln)) {
|
||||||
upd = ldata(ln);
|
upd = ldata(ln);
|
||||||
if (upd->memtype == NULL) {
|
if (upd->memtype == NULL) {
|
||||||
|
@ -920,12 +922,12 @@ int main(int argc, char * argv [])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!avr_mem_might_be_known(upd->memtype)) {
|
rc = update_dryrun(p, upd);
|
||||||
avrdude_message(MSG_INFO, "%s: unknown memory type %s\n", progname, upd->memtype);
|
if (rc && rc != LIBAVRDUDE_SOFTFAIL)
|
||||||
|
doexit = 1;
|
||||||
|
}
|
||||||
|
if(doexit)
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
|
||||||
// TODO: check whether filename other than "-" is readable/writable
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* open the programmer
|
* open the programmer
|
||||||
|
|
|
@ -28,6 +28,11 @@
|
||||||
#pragma comment(lib, "ws2_32.lib")
|
#pragma comment(lib, "ws2_32.lib")
|
||||||
#pragma comment(lib, "setupapi.lib")
|
#pragma comment(lib, "setupapi.lib")
|
||||||
|
|
||||||
|
#define strerror_r(errno,buf,len) strerror_s(buf,len,errno)
|
||||||
|
|
||||||
|
#define R_OK 4
|
||||||
|
#define W_OK 2
|
||||||
|
#define X_OK 1
|
||||||
#define F_OK 0
|
#define F_OK 0
|
||||||
|
|
||||||
#define PATH_MAX _MAX_PATH
|
#define PATH_MAX _MAX_PATH
|
||||||
|
|
150
src/update.c
150
src/update.c
|
@ -24,6 +24,9 @@
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
#include "ac_cfg.h"
|
#include "ac_cfg.h"
|
||||||
#include "avrdude.h"
|
#include "avrdude.h"
|
||||||
|
@ -319,6 +322,145 @@ const char *update_interval(int a, int b) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Helper functions for dry run to determine file access
|
||||||
|
|
||||||
|
int update_is_okfile(const char *fn) {
|
||||||
|
struct stat info;
|
||||||
|
|
||||||
|
// File exists and is a regular file or a character file, eg, /dev/urandom
|
||||||
|
return fn && *fn && stat(fn, &info) == 0 && !!(info.st_mode & (S_IFREG | S_IFCHR));
|
||||||
|
}
|
||||||
|
|
||||||
|
int update_is_writeable(const char *fn) {
|
||||||
|
if(!fn || !*fn)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Assume writing to stdout will be OK
|
||||||
|
if(!strcmp(fn, "-"))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
// File exists? If so return whether it's readable and an OK file type
|
||||||
|
if(access(fn, F_OK) == 0)
|
||||||
|
return access(fn, W_OK) == 0 && update_is_okfile(fn);
|
||||||
|
|
||||||
|
// File does not exist: try to create it
|
||||||
|
FILE *test = fopen(fn, "w");
|
||||||
|
if(test) {
|
||||||
|
unlink(fn);
|
||||||
|
fclose(test);
|
||||||
|
}
|
||||||
|
return !!test;
|
||||||
|
}
|
||||||
|
|
||||||
|
int update_is_readable(const char *fn) {
|
||||||
|
if(!fn || !*fn)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Assume reading from stdin will be OK
|
||||||
|
if(!strcmp(fn, "-"))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
// File exists, is readable by the process and an OK file type?
|
||||||
|
return access(fn, R_OK) == 0 && update_is_okfile(fn);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void ioerror(const char *iotype, UPDATE *upd) {
|
||||||
|
avrdude_message(MSG_INFO, "%s: file %s is not %s",
|
||||||
|
progname, update_outname(upd->filename), iotype);
|
||||||
|
if(errno)
|
||||||
|
avrdude_message(MSG_INFO, ". %s", strerror(errno));
|
||||||
|
else if(upd->filename && *upd->filename)
|
||||||
|
avrdude_message(MSG_INFO, " (not a regular or character file?)");
|
||||||
|
avrdude_message(MSG_INFO, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Basic checks to reveal serious failure before programming
|
||||||
|
int update_dryrun(struct avrpart *p, UPDATE *upd) {
|
||||||
|
static char **wrote;
|
||||||
|
static int nfwritten;
|
||||||
|
|
||||||
|
int known, format_detect, ret = LIBAVRDUDE_SUCCESS;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reject an update if memory name is not known amongst any part (suspect a typo)
|
||||||
|
* but accept when the specific part does not have it (allow unifying i/faces)
|
||||||
|
*/
|
||||||
|
if(!avr_mem_might_be_known(upd->memtype)) {
|
||||||
|
avrdude_message(MSG_INFO, "%s: unknown memory type %s\n", progname, upd->memtype);
|
||||||
|
ret = LIBAVRDUDE_GENERAL_FAILURE;
|
||||||
|
} else if(p && !avr_locate_mem(p, upd->memtype))
|
||||||
|
ret = LIBAVRDUDE_SOFTFAIL;
|
||||||
|
|
||||||
|
known = 0;
|
||||||
|
// Necessary to check whether the file is readable?
|
||||||
|
if(upd->op == DEVICE_VERIFY || upd->op == DEVICE_WRITE || upd->format == FMT_AUTO) {
|
||||||
|
if(upd->format != FMT_IMM) {
|
||||||
|
// Need to read the file: was it written before, so will be known?
|
||||||
|
for(int i = 0; i < nfwritten; i++)
|
||||||
|
if(!wrote || (upd->filename && !strcmp(wrote[i], upd->filename)))
|
||||||
|
known = 1;
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
if(!known && !update_is_readable(upd->filename)) {
|
||||||
|
ioerror("readable", upd);
|
||||||
|
ret = LIBAVRDUDE_GENERAL_FAILURE;
|
||||||
|
known = 1; // Pretend we know it, so no auto detect needed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!known && upd->format == FMT_AUTO) {
|
||||||
|
if(!strcmp(upd->filename, "-")) {
|
||||||
|
avrdude_message(MSG_INFO, "%s: can't auto detect file format for stdin/out, "
|
||||||
|
"specify explicitly\n", progname);
|
||||||
|
ret = LIBAVRDUDE_GENERAL_FAILURE;
|
||||||
|
} else if((format_detect = fileio_fmt_autodetect(upd->filename)) < 0) {
|
||||||
|
avrdude_message(MSG_INFO, "%s: can't determine file format for %s, specify explicitly\n",
|
||||||
|
progname, upd->filename);
|
||||||
|
ret = LIBAVRDUDE_GENERAL_FAILURE;
|
||||||
|
} else {
|
||||||
|
// Set format now, no need to repeat auto detection later
|
||||||
|
upd->format = format_detect;
|
||||||
|
if(quell_progress < 2)
|
||||||
|
avrdude_message(MSG_NOTICE, "%s: %s file %s auto detected as %s\n",
|
||||||
|
progname, upd->op == DEVICE_READ? "output": "input", upd->filename,
|
||||||
|
fileio_fmtstr(upd->format));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(upd->op) {
|
||||||
|
case DEVICE_READ:
|
||||||
|
if(upd->format == FMT_IMM) {
|
||||||
|
avrdude_message(MSG_INFO,
|
||||||
|
"%s: invalid file format 'immediate' for output\n", progname);
|
||||||
|
ret = LIBAVRDUDE_GENERAL_FAILURE;
|
||||||
|
} else {
|
||||||
|
errno = 0;
|
||||||
|
if(!update_is_writeable(upd->filename)) {
|
||||||
|
ioerror("writeable", upd);
|
||||||
|
ret = LIBAVRDUDE_GENERAL_FAILURE;
|
||||||
|
} else if(upd->filename) { // Record filename (other than stdout) is available for future reads
|
||||||
|
if(strcmp(upd->filename, "-") && (wrote = realloc(wrote, sizeof(*wrote) * (nfwritten+1))))
|
||||||
|
wrote[nfwritten++] = upd->filename;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DEVICE_VERIFY: // Already checked that file is readable
|
||||||
|
case DEVICE_WRITE:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
avrdude_message(MSG_INFO, "%s: invalid update operation (%d) requested\n",
|
||||||
|
progname, upd->op);
|
||||||
|
ret = LIBAVRDUDE_GENERAL_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int do_op(PROGRAMMER * pgm, struct avrpart * p, UPDATE * upd, enum updateflags flags)
|
int do_op(PROGRAMMER * pgm, struct avrpart * p, UPDATE * upd, enum updateflags flags)
|
||||||
{
|
{
|
||||||
struct avrpart * v;
|
struct avrpart * v;
|
||||||
|
@ -346,7 +488,7 @@ int do_op(PROGRAMMER * pgm, struct avrpart * p, UPDATE * upd, enum updateflags f
|
||||||
// Read out the specified device memory and write it to a file
|
// Read out the specified device memory and write it to a file
|
||||||
if (upd->format == FMT_IMM) {
|
if (upd->format == FMT_IMM) {
|
||||||
avrdude_message(MSG_INFO,
|
avrdude_message(MSG_INFO,
|
||||||
"%s: Invalid file format 'immediate' for output\n", progname);
|
"%s: invalid file format 'immediate' for output\n", progname);
|
||||||
return LIBAVRDUDE_GENERAL_FAILURE;
|
return LIBAVRDUDE_GENERAL_FAILURE;
|
||||||
}
|
}
|
||||||
if (quell_progress < 2)
|
if (quell_progress < 2)
|
||||||
|
@ -383,15 +525,15 @@ int do_op(PROGRAMMER * pgm, struct avrpart * p, UPDATE * upd, enum updateflags f
|
||||||
// Write the selected device memory using data from a file
|
// Write the selected device memory using data from a file
|
||||||
|
|
||||||
rc = fileio(FIO_READ, upd->filename, upd->format, p, upd->memtype, -1);
|
rc = fileio(FIO_READ, upd->filename, upd->format, p, upd->memtype, -1);
|
||||||
if (quell_progress < 2)
|
|
||||||
avrdude_message(MSG_INFO, "%s: reading input file %s for %s%s\n",
|
|
||||||
progname, update_inname(upd->filename), mem->desc, alias_mem_desc);
|
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
avrdude_message(MSG_INFO, "%s: read from file %s failed\n",
|
avrdude_message(MSG_INFO, "%s: read from file %s failed\n",
|
||||||
progname, update_inname(upd->filename));
|
progname, update_inname(upd->filename));
|
||||||
return LIBAVRDUDE_GENERAL_FAILURE;
|
return LIBAVRDUDE_GENERAL_FAILURE;
|
||||||
}
|
}
|
||||||
size = rc;
|
size = rc;
|
||||||
|
if (quell_progress < 2)
|
||||||
|
avrdude_message(MSG_INFO, "%s: reading input file %s for %s%s\n",
|
||||||
|
progname, update_inname(upd->filename), mem->desc, alias_mem_desc);
|
||||||
|
|
||||||
if(memstats(p, upd->memtype, size, &fs) < 0)
|
if(memstats(p, upd->memtype, size, &fs) < 0)
|
||||||
return LIBAVRDUDE_GENERAL_FAILURE;
|
return LIBAVRDUDE_GENERAL_FAILURE;
|
||||||
|
|
Loading…
Reference in New Issue