diff --git a/icemulti/icemulti.cc b/icemulti/icemulti.cc index 637c3830472..da90da3f42e 100644 --- a/icemulti/icemulti.cc +++ b/icemulti/icemulti.cc @@ -19,12 +19,16 @@ #include #include +#include #include #include +#include #define log(...) fprintf(stderr, __VA_ARGS__); #define info(...) do { if (log_level > 0) fprintf(stderr, __VA_ARGS__); } while (0) -#define error(...) do { fprintf(stderr, "Error: " __VA_ARGS__); exit(1); } while (0) +#define error(...) do { fprintf(stderr, "%s: ", program_short_name); fprintf(stderr, __VA_ARGS__); exit(EXIT_FAILURE); } while (0) + +static char *program_short_name; int log_level = 0; @@ -55,7 +59,7 @@ static void write_bytes(std::ostream &ofs, uint32_t &file_offset, } static void write_file(std::ostream &ofs, uint32_t &file_offset, - std::istream &ifs) + std::istream &ifs, const char *filename) { const size_t bufsize = 8192; uint8_t *buffer = new uint8_t[bufsize]; @@ -63,7 +67,7 @@ static void write_file(std::ostream &ofs, uint32_t &file_offset, while(!ifs.eof()) { ifs.read(reinterpret_cast(buffer), bufsize); if (ifs.bad()) - error("Read error on input image"); + error("can't read input image `%s': %s\n", filename, strerror(errno)); write_bytes(ofs, file_offset, buffer, ifs.gcount()); } @@ -79,29 +83,42 @@ static void pad_to(std::ostream &ofs, uint32_t &file_offset, uint32_t target) } class Image { + const char *filename; std::ifstream ifs; uint32_t offs; public: - Image(const char *filename) : ifs(filename, std::ifstream::binary) {} - + Image(const char *filename); size_t size(); void write(std::ostream &ofs, uint32_t &file_offset); void place(uint32_t o) { offs = o; } uint32_t offset() const { return offs; } }; +Image::Image(const char *filename) : filename(filename), ifs(filename, std::ifstream::binary) +{ + if (ifs.fail()) + error("can't open input image `%s': %s\n", filename, strerror(errno)); +} + size_t Image::size() { ifs.seekg (0, ifs.end); + if (ifs.fail()) + error("can't seek on input image `%s': %s\n", filename, strerror(errno)); size_t length = ifs.tellg(); ifs.seekg (0, ifs.beg); + if (ifs.fail()) + error("can't seek on input image `%s': %s\n", filename, strerror(errno)); + + if (length == 0) + error("input image `%s' doesn't contain any data\n", filename); return length; } void Image::write(std::ostream &ofs, uint32_t &file_offset) { - write_file(ofs, file_offset, ifs); + write_file(ofs, file_offset, ifs, filename); } class Header { @@ -173,11 +190,13 @@ void usage() log(" -v\n"); log(" verbose (repeat to increase verbosity)\n"); log("\n"); - exit(1); + exit(EXIT_FAILURE); } int main(int argc, char **argv) { + int c; + char *endptr = NULL; bool coldboot = false; int por_image = 0; int image_count = 0; @@ -187,46 +206,65 @@ int main(int argc, char **argv) std::unique_ptr images[NUM_IMAGES]; const char *outfile_name = NULL; - for (int i = 1; i < argc; i++) - { - if (argv[i][0] == '-' && argv[i][1]) { - for (int j = 1; argv[i][j]; j++) - if (argv[i][j] == 'c') { - coldboot = true; - } else if (argv[i][j] == 'p' && argv[i][j+1]) { - por_image = argv[i][++j] - '0'; - } else if (argv[i][j] == 'a' || argv[i][j] == 'A') { - align_first = argv[i][j] == 'A'; - if (argv[i][j+1]) - align_bits = atoi(&argv[i][j+1]); - else if(i+1 < argc) - align_bits = atoi(argv[++i]); - else - usage(); - break; - } else if (argv[i][j] == 'o') { - if (argv[i][j+1]) - outfile_name = &argv[i][j+1]; - else if(i+1 < argc) - outfile_name = argv[++i]; - else - usage(); - break; - } else if (argv[i][j] == 'v') { - log_level++; - } else - usage(); - continue; + static struct option long_options[] = { + {NULL, 0, NULL, 0} + }; + + program_short_name = strrchr(argv[0], '/'); + if (program_short_name == NULL) + program_short_name = argv[0]; + else + program_short_name++; + + while ((c = getopt_long(argc, argv, "cp:a:A:o:v", + long_options, NULL)) != -1) + switch (c) { + case 'c': + coldboot = true; + break; + case 'p': + if (optarg[0] == '0' && optarg[1] == '\0') + por_image = 0; + else if (optarg[0] == '1' && optarg[1] == '\0') + por_image = 1; + else if (optarg[0] == '2' && optarg[1] == '\0') + por_image = 2; + else if (optarg[0] == '3' && optarg[1] == '\0') + por_image = 3; + else + error("`%s' is not a valid power-on/reset image (must be 0, 1, 2, or 3)\n", optarg); + break; + case 'A': + align_first = true; + /* fallthrough */ + case 'a': + align_bits = strtol(optarg, &endptr, 0); + if (*endptr != '\0') + error("`%s' is not a valid number\n", optarg); + if (align_bits < 0) + error("argument to `-%c' must be non-negative\n", c); + break; + case 'o': + outfile_name = optarg; + break; + case 'v': + log_level++; + break; + default: + usage(); } + if (optind == argc) { + fprintf(stderr, "%s: missing argument\n", program_short_name); + usage(); + } + + while (optind != argc) { if (image_count >= NUM_IMAGES) error("Too many images supplied\n"); - images[image_count++].reset(new Image(argv[i])); + images[image_count++].reset(new Image(argv[optind++])); } - if (!image_count) - usage(); - if (coldboot && por_image != 0) error("Can't select power on reset boot image in cold boot mode\n"); @@ -259,7 +297,7 @@ int main(int argc, char **argv) if (outfile_name != NULL) { ofs.open(outfile_name, std::ofstream::binary); if (!ofs.is_open()) - error("Failed to open output file.\n"); + error("can't open output file `%s': %s\n", outfile_name, strerror(errno)); osp = &ofs; } else { osp = &std::cout; @@ -278,5 +316,5 @@ int main(int argc, char **argv) } info("Done.\n"); - return 0; + return EXIT_SUCCESS; }