firmware-utils: bcm4908img: support extracting image data
authorRafał Miłecki <rafal@milecki.pl>
Fri, 2 Apr 2021 14:31:43 +0000 (16:31 +0200)
committerRafał Miłecki <rafal@milecki.pl>
Mon, 5 Apr 2021 08:05:25 +0000 (10:05 +0200)
It's useful for upgrading cferom, firmware, etc.

Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
src/bcm4908img.c

index b04916443b6b980bf91d39b573a61cc3c5d330a1..7e9cba299d482f0316105266654a131a978384f4 100644 (file)
@@ -469,6 +469,86 @@ out:
        return err;
 }
 
+/**************************************************
+ * Extract
+ **************************************************/
+
+static int bcm4908img_extract(int argc, char **argv) {
+       struct bcm4908img_info info;
+       const char *pathname = NULL;
+       uint8_t buf[1024];
+       const char *type;
+       size_t offset;
+       size_t length;
+       size_t bytes;
+       FILE *fp;
+       int c;
+       int err = 0;
+
+       while ((c = getopt(argc, argv, "i:t:")) != -1) {
+               switch (c) {
+               case 'i':
+                       pathname = optarg;
+                       break;
+               case 't':
+                       type = optarg;
+                       break;
+               }
+       }
+
+       fp = bcm4908img_open(pathname, "r");
+       if (!fp) {
+               fprintf(stderr, "Failed to open BCM4908 image\n");
+               err = -EACCES;
+               goto err_out;
+       }
+
+       err = bcm4908img_parse(fp, &info);
+       if (err) {
+               fprintf(stderr, "Failed to parse BCM4908 image\n");
+               goto err_close;
+       }
+
+       if (!strcmp(type, "cferom")) {
+               offset = 0;
+               length = info.cferom_size;
+               if (!length) {
+                       err = -ENOENT;
+                       fprintf(stderr, "This BCM4908 image doesn't contain cferom\n");
+                       goto err_close;
+               }
+       } else if (!strcmp(type, "firmware")) {
+               offset = info.vendor_header_size + info.cferom_size;
+               length = info.file_size - offset - sizeof(struct bcm4908img_tail);
+       } else {
+               err = -EINVAL;
+               fprintf(stderr, "Unsupported extract type: %s\n", type);
+               goto err_close;
+       }
+
+       if (!length) {
+               err = -EINVAL;
+               fprintf(stderr, "No data to extract specified\n");
+               goto err_close;
+       }
+
+       fseek(fp, offset, SEEK_SET);
+       while (length && (bytes = fread(buf, 1, bcm4908img_min(sizeof(buf), length), fp)) > 0) {
+               fwrite(buf, bytes, 1, stdout);
+               length -= bytes;
+       }
+       if (length) {
+               err = -EIO;
+               fprintf(stderr, "Failed to read last %zd B of data\n", length);
+               goto err_close;
+       }
+
+err_close:
+       bcm4908img_close(fp);
+err_out:
+       return err;
+}
+
 /**************************************************
  * Start
  **************************************************/
@@ -485,6 +565,11 @@ static void usage() {
        printf("\t-f file\t\t\t\tadd data from specified file\n");
        printf("\t-a alignment\t\t\tpad image with zeros to specified alignment\n");
        printf("\t-A offset\t\t\t\tappend zeros until reaching specified offset\n");
+       printf("\n");
+       printf("Extracting from a BCM4908 image:\n");
+       printf("\tbcm4908img extract <options>\n");
+       printf("\t-i <file>\t\t\t\tinput BCM490 image\n");
+       printf("\t-t <type>\t\t\t\tone of: cferom, bootfs, rootfs, firmware\n");
 }
 
 int main(int argc, char **argv) {
@@ -494,6 +579,8 @@ int main(int argc, char **argv) {
                        return bcm4908img_info(argc, argv);
                else if (!strcmp(argv[1], "create"))
                        return bcm4908img_create(argc, argv);
+               else if (!strcmp(argv[1], "extract"))
+                       return bcm4908img_extract(argc, argv);
        }
 
        usage();