fwtool: add support for extracting the truncated data part to stdout
[openwrt/openwrt.git] / package / system / fwtool / src / fwtool.c
index 505fafcf7a78b3110fc3d1d73c52d3f246893027..3adc1e02492ccea546761dd05c033c46c5925a37 100644 (file)
@@ -43,6 +43,7 @@ struct data_buf {
 static FILE *signature_file, *metadata_file, *firmware_file;
 static int file_mode = MODE_DEFAULT;
 static bool truncate_file;
+static bool write_truncated;
 static bool quiet = false;
 
 static uint32_t crc_table[256];
@@ -64,6 +65,7 @@ usage(const char *progname)
                "  -s <file>:           Extract signature file from firmware image\n"
                "  -i <file>:           Extract metadata file from firmware image\n"
                "  -t:                  Remove extracted chunks from firmare image (using -s, -i)\n"
+               "  -T:                  Output firmware image without extracted chunks to stdout (using -s, -i)\n"
                "  -q:                  Quiet (suppress error messages)\n"
                "\n", progname);
        return 1;
@@ -280,8 +282,10 @@ extract_data(const char *name)
        struct fwimage_trailer tr;
        struct data_buf dbuf = {};
        uint32_t crc32 = ~0;
+       int data_len = 0;
        int ret = 1;
        void *buf;
+       bool metadata_keep = false;
 
        firmware_file = open_file(name, false);
        if (!firmware_file) {
@@ -301,6 +305,9 @@ extract_data(const char *name)
        do {
                char *tmp = dbuf.cur;
 
+               if (write_truncated && dbuf.prev)
+                       fwrite(dbuf.prev, 1, BUFLEN, stdout);
+
                dbuf.cur = dbuf.prev;
                dbuf.prev = tmp;
 
@@ -317,7 +324,6 @@ extract_data(const char *name)
        } while (dbuf.cur_len == BUFLEN);
 
        while (1) {
-               int data_len;
 
                if (extract_tail(&dbuf, &tr, sizeof(tr)))
                        break;
@@ -349,6 +355,7 @@ extract_data(const char *name)
                } else if (tr.type == FWIMAGE_INFO) {
                        if (!metadata_file) {
                                dbuf.file_len += data_len + sizeof(tr);
+                               metadata_keep = true;
                                break;
                        }
 
@@ -368,6 +375,17 @@ extract_data(const char *name)
        if (!ret && truncate_file)
                ftruncate(fileno(firmware_file), dbuf.file_len);
 
+       if (write_truncated) {
+               if (dbuf.prev)
+                       fwrite(dbuf.prev, 1, BUFLEN, stdout);
+               if (dbuf.cur)
+                       fwrite(dbuf.cur, 1, dbuf.cur_len, stdout);
+               if (metadata_keep) {
+                       fwrite(buf, data_len, 1, stdout);
+                       fwrite(&tr, sizeof(tr), 1, stdout);
+               }
+       }
+
 out:
        free(buf);
        free(dbuf.cur);
@@ -392,7 +410,7 @@ int main(int argc, char **argv)
 
        crc32_filltable(crc_table);
 
-       while ((ch = getopt(argc, argv, "i:I:qs:S:t")) != -1) {
+       while ((ch = getopt(argc, argv, "i:I:qs:S:tT")) != -1) {
                ret = 0;
                switch(ch) {
                case 'S':
@@ -410,6 +428,9 @@ int main(int argc, char **argv)
                case 't':
                        truncate_file = true;
                        break;
+               case 'T':
+                       write_truncated = true;
+                       break;
                case 'q':
                        quiet = true;
                        break;