For improved reusability, testing etc.
Signed-off-by: Petr Štetiar <ynezz@true.cz>
+++ /dev/null
-#
-# Copyright (C) Felix Fietkau <nbd@nbd.name>
-#
-# This is free software, licensed under the GNU General Public License v2.
-# See /LICENSE for more information.
-#
-
-include $(TOPDIR)/rules.mk
-
-PKG_NAME:=fwtool
-PKG_RELEASE:=2
-
-PKG_FLAGS:=nonshared
-
-PKG_MAINTAINER := Felix Fietkau <nbd@nbd.name>
-PKG_BUILD_DEPENDS := fwtool/host
-
-include $(INCLUDE_DIR)/package.mk
-include $(INCLUDE_DIR)/host-build.mk
-
-HOST_BUILD_PREFIX:=$(STAGING_DIR_HOST)
-
-define Package/fwtool
- SECTION:=utils
- CATEGORY:=Base system
- TITLE:=Utility for appending and extracting firmware metadata and signatures
-endef
-
-define Host/Compile
- $(HOSTCC) $(HOST_CFLAGS) $(HOST_LDFLAGS) -o $(HOST_BUILD_DIR)/fwtool ./src/fwtool.c
-endef
-
-define Host/Install
- $(INSTALL_BIN) $(HOST_BUILD_DIR)/fwtool $(1)/bin/
-endef
-
-define Build/Compile
- $(TARGET_CC) $(TARGET_CFLAGS) $(TARGET_LDFLAGS) -o $(PKG_BUILD_DIR)/fwtool ./src/fwtool.c
-endef
-
-define Package/fwtool/install
- $(INSTALL_DIR) $(1)/usr/bin
- $(INSTALL_BIN) $(PKG_BUILD_DIR)/fwtool $(1)/usr/bin/
-endef
-
-$(eval $(call HostBuild))
-$(eval $(call BuildPackage,fwtool))
--- /dev/null
+/*
+ * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
+ *
+ * Based on busybox code:
+ * CRC32 table fill function
+ * Copyright (C) 2006 by Rob Sullivan <cogito.ergo.cogito@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef __BB_CRC32_H
+#define __BB_CRC32_H
+
+static inline void
+crc32_filltable(uint32_t *crc_table)
+{
+ uint32_t polynomial = 0xedb88320;
+ uint32_t c;
+ int i, j;
+
+ for (i = 0; i < 256; i++) {
+ c = i;
+ for (j = 8; j; j--)
+ c = (c&1) ? ((c >> 1) ^ polynomial) : (c >> 1);
+
+ *crc_table++ = c;
+ }
+}
+
+static inline uint32_t
+crc32_block(uint32_t val, const void *buf, unsigned len, uint32_t *crc_table)
+{
+ const void *end = (uint8_t*)buf + len;
+
+ while (buf != end) {
+ val = crc_table[(uint8_t)val ^ *(uint8_t*)buf] ^ (val >> 8);
+ buf = (uint8_t*)buf + 1;
+ }
+ return val;
+}
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef __FWIMAGE_H
+#define __FWIMAGE_H
+
+#include <stdint.h>
+
+#define FWIMAGE_MAGIC 0x46577830 /* FWx0 */
+
+struct fwimage_header {
+ uint32_t version;
+ uint32_t flags;
+ char data[];
+};
+
+struct fwimage_trailer {
+ uint32_t magic;
+ uint32_t crc32;
+ uint8_t type;
+ uint8_t __pad[3];
+ uint32_t size;
+};
+
+enum fwimage_type {
+ FWIMAGE_SIGNATURE,
+ FWIMAGE_INFO,
+};
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <sys/types.h>
+#include <stdio.h>
+#include <getopt.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "fwimage.h"
+#include "utils.h"
+#include "crc32.h"
+
+#define METADATA_MAXLEN 30 * 1024
+#define SIGNATURE_MAXLEN 1 * 1024
+
+#define BUFLEN (METADATA_MAXLEN + SIGNATURE_MAXLEN + 1024)
+
+enum {
+ MODE_DEFAULT = -1,
+ MODE_EXTRACT = 0,
+ MODE_APPEND = 1,
+};
+
+struct data_buf {
+ char *cur;
+ char *prev;
+ int cur_len;
+ int file_len;
+};
+
+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];
+
+#define msg(...) \
+ do { \
+ if (!quiet) \
+ fprintf(stderr, __VA_ARGS__); \
+ } while (0)
+
+static int
+usage(const char *progname)
+{
+ fprintf(stderr, "Usage: %s <options> <firmware>\n"
+ "\n"
+ "Options:\n"
+ " -S <file>: Append signature file to firmware image\n"
+ " -I <file>: Append metadata file to firmware image\n"
+ " -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;
+}
+
+static FILE *
+open_file(const char *name, bool write)
+{
+ FILE *ret;
+
+ if (!strcmp(name, "-"))
+ return write ? stdout : stdin;
+
+ ret = fopen(name, write ? "w" : "r+");
+ if (!ret && !write)
+ ret = fopen(name, "r");
+
+ return ret;
+}
+
+static int
+set_file(FILE **file, const char *name, int mode)
+{
+ if (file_mode < 0)
+ file_mode = mode;
+ else if (file_mode != mode) {
+ msg("Error: mixing appending and extracting data is not supported\n");
+ return 1;
+ }
+
+ if (*file) {
+ msg("Error: the same append/extract option cannot be used multiple times\n");
+ return 1;
+ }
+
+ *file = open_file(name, mode == MODE_EXTRACT);
+ return !*file;
+}
+
+static void
+trailer_update_crc(struct fwimage_trailer *tr, void *buf, int len)
+{
+ tr->crc32 = cpu_to_be32(crc32_block(be32_to_cpu(tr->crc32), buf, len, crc_table));
+}
+
+static int
+append_data(FILE *in, FILE *out, struct fwimage_trailer *tr, int maxlen)
+{
+ while (1) {
+ char buf[512];
+ int len;
+
+ len = fread(buf, 1, sizeof(buf), in);
+ if (!len)
+ break;
+
+ maxlen -= len;
+ if (maxlen < 0)
+ return 1;
+
+ tr->size += len;
+ trailer_update_crc(tr, buf, len);
+ fwrite(buf, len, 1, out);
+ }
+
+ return 0;
+}
+
+static void
+append_trailer(FILE *out, struct fwimage_trailer *tr)
+{
+ tr->size = cpu_to_be32(tr->size);
+ fwrite(tr, sizeof(*tr), 1, out);
+ trailer_update_crc(tr, tr, sizeof(*tr));
+}
+
+static int
+add_metadata(struct fwimage_trailer *tr)
+{
+ struct fwimage_header hdr = {};
+
+ tr->type = FWIMAGE_INFO;
+ tr->size = sizeof(hdr) + sizeof(*tr);
+
+ trailer_update_crc(tr, &hdr, sizeof(hdr));
+ fwrite(&hdr, sizeof(hdr), 1, firmware_file);
+
+ if (append_data(metadata_file, firmware_file, tr, METADATA_MAXLEN))
+ return 1;
+
+ append_trailer(firmware_file, tr);
+
+ return 0;
+}
+
+static int
+add_signature(struct fwimage_trailer *tr)
+{
+ if (!signature_file)
+ return 0;
+
+ tr->type = FWIMAGE_SIGNATURE;
+ tr->size = sizeof(*tr);
+
+ if (append_data(signature_file, firmware_file, tr, SIGNATURE_MAXLEN))
+ return 1;
+
+ append_trailer(firmware_file, tr);
+
+ return 0;
+}
+
+static int
+add_data(const char *name)
+{
+ struct fwimage_trailer tr = {
+ .magic = cpu_to_be32(FWIMAGE_MAGIC),
+ .crc32 = ~0,
+ };
+ int file_len = 0;
+ int ret = 0;
+
+ firmware_file = fopen(name, "r+");
+ if (!firmware_file) {
+ msg("Failed to open firmware file\n");
+ return 1;
+ }
+
+ while (1) {
+ char buf[512];
+ int len;
+
+ len = fread(buf, 1, sizeof(buf), firmware_file);
+ if (!len)
+ break;
+
+ file_len += len;
+ trailer_update_crc(&tr, buf, len);
+ }
+
+ if (metadata_file)
+ ret = add_metadata(&tr);
+ else if (signature_file)
+ ret = add_signature(&tr);
+
+ if (ret) {
+ fflush(firmware_file);
+ ftruncate(fileno(firmware_file), file_len);
+ }
+
+ return ret;
+}
+
+static void
+remove_tail(struct data_buf *dbuf, int len)
+{
+ dbuf->cur_len -= len;
+ dbuf->file_len -= len;
+
+ if (dbuf->cur_len)
+ return;
+
+ free(dbuf->cur);
+ dbuf->cur = dbuf->prev;
+ dbuf->prev = NULL;
+ dbuf->cur_len = BUFLEN;
+}
+
+static int
+extract_tail(struct data_buf *dbuf, void *dest, int len)
+{
+ int cur_len = dbuf->cur_len;
+
+ if (!dbuf->cur)
+ return 1;
+
+ if (cur_len >= len)
+ cur_len = len;
+
+ memcpy(dest + (len - cur_len), dbuf->cur + dbuf->cur_len - cur_len, cur_len);
+ remove_tail(dbuf, cur_len);
+
+ cur_len = len - cur_len;
+ if (cur_len && !dbuf->cur)
+ return 1;
+
+ memcpy(dest, dbuf->cur + dbuf->cur_len - cur_len, cur_len);
+ remove_tail(dbuf, cur_len);
+
+ return 0;
+}
+
+static uint32_t
+tail_crc32(struct data_buf *dbuf, uint32_t crc32)
+{
+ if (dbuf->prev)
+ crc32 = crc32_block(crc32, dbuf->prev, BUFLEN, crc_table);
+
+ return crc32_block(crc32, dbuf->cur, dbuf->cur_len, crc_table);
+}
+
+static int
+validate_metadata(struct fwimage_header *hdr, int data_len)
+{
+ if (hdr->version != 0)
+ return 1;
+ return 0;
+}
+
+static int
+extract_data(const char *name)
+{
+ struct fwimage_header *hdr;
+ 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) {
+ msg("Failed to open firmware file\n");
+ return 1;
+ }
+
+ if (truncate_file && firmware_file == stdin) {
+ msg("Cannot truncate file when reading from stdin\n");
+ return 1;
+ }
+
+ buf = malloc(BUFLEN);
+ if (!buf)
+ return 1;
+
+ do {
+ char *tmp = dbuf.cur;
+
+ if (write_truncated && dbuf.prev)
+ fwrite(dbuf.prev, 1, BUFLEN, stdout);
+
+ dbuf.cur = dbuf.prev;
+ dbuf.prev = tmp;
+
+ if (dbuf.cur)
+ crc32 = crc32_block(crc32, dbuf.cur, BUFLEN, crc_table);
+ else
+ dbuf.cur = malloc(BUFLEN);
+
+ if (!dbuf.cur)
+ goto out;
+
+ dbuf.cur_len = fread(dbuf.cur, 1, BUFLEN, firmware_file);
+ dbuf.file_len += dbuf.cur_len;
+ } while (dbuf.cur_len == BUFLEN);
+
+ while (1) {
+
+ if (extract_tail(&dbuf, &tr, sizeof(tr)))
+ break;
+
+ if (tr.magic != cpu_to_be32(FWIMAGE_MAGIC)) {
+ msg("Data not found\n");
+ metadata_keep = true;
+ break;
+ }
+
+ data_len = be32_to_cpu(tr.size) - sizeof(tr);
+
+ if (be32_to_cpu(tr.crc32) != tail_crc32(&dbuf, crc32)) {
+ msg("CRC error\n");
+ break;
+ }
+
+ if (data_len > BUFLEN) {
+ msg("Size error\n");
+ break;
+ }
+
+ extract_tail(&dbuf, buf, data_len);
+
+ if (tr.type == FWIMAGE_SIGNATURE) {
+ if (!signature_file)
+ continue;
+ fwrite(buf, data_len, 1, signature_file);
+ ret = 0;
+ break;
+ } else if (tr.type == FWIMAGE_INFO) {
+ if (!metadata_file) {
+ dbuf.file_len += data_len + sizeof(tr);
+ metadata_keep = true;
+ break;
+ }
+
+ hdr = buf;
+ data_len -= sizeof(*hdr);
+ if (validate_metadata(hdr, data_len))
+ continue;
+
+ fwrite(hdr + 1, data_len, 1, metadata_file);
+ ret = 0;
+ break;
+ } else {
+ continue;
+ }
+ }
+
+ 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);
+ free(dbuf.prev);
+ return ret;
+}
+
+static void cleanup(void)
+{
+ if (signature_file)
+ fclose(signature_file);
+ if (metadata_file)
+ fclose(metadata_file);
+ if (firmware_file)
+ fclose(firmware_file);
+}
+
+int main(int argc, char **argv)
+{
+ const char *progname = argv[0];
+ int ret, ch;
+
+ crc32_filltable(crc_table);
+
+ while ((ch = getopt(argc, argv, "i:I:qs:S:tT")) != -1) {
+ ret = 0;
+ switch(ch) {
+ case 'S':
+ ret = set_file(&signature_file, optarg, MODE_APPEND);
+ break;
+ case 'I':
+ ret = set_file(&metadata_file, optarg, MODE_APPEND);
+ break;
+ case 's':
+ ret = set_file(&signature_file, optarg, MODE_EXTRACT);
+ break;
+ case 'i':
+ ret = set_file(&metadata_file, optarg, MODE_EXTRACT);
+ break;
+ case 't':
+ truncate_file = true;
+ break;
+ case 'T':
+ write_truncated = true;
+ break;
+ case 'q':
+ quiet = true;
+ break;
+ }
+
+ if (ret)
+ goto out;
+ }
+
+ if (optind >= argc) {
+ ret = usage(progname);
+ goto out;
+ }
+
+ if (file_mode == MODE_DEFAULT) {
+ ret = usage(progname);
+ goto out;
+ }
+
+ if (signature_file && metadata_file) {
+ msg("Cannot append/extract metadata and signature in one run\n");
+ return 1;
+ }
+
+ if (file_mode)
+ ret = add_data(argv[optind]);
+ else
+ ret = extract_data(argv[optind]);
+
+out:
+ cleanup();
+ return ret;
+}
+++ /dev/null
-/*
- * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
- *
- * Based on busybox code:
- * CRC32 table fill function
- * Copyright (C) 2006 by Rob Sullivan <cogito.ergo.cogito@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-#ifndef __BB_CRC32_H
-#define __BB_CRC32_H
-
-static inline void
-crc32_filltable(uint32_t *crc_table)
-{
- uint32_t polynomial = 0xedb88320;
- uint32_t c;
- int i, j;
-
- for (i = 0; i < 256; i++) {
- c = i;
- for (j = 8; j; j--)
- c = (c&1) ? ((c >> 1) ^ polynomial) : (c >> 1);
-
- *crc_table++ = c;
- }
-}
-
-static inline uint32_t
-crc32_block(uint32_t val, const void *buf, unsigned len, uint32_t *crc_table)
-{
- const void *end = (uint8_t*)buf + len;
-
- while (buf != end) {
- val = crc_table[(uint8_t)val ^ *(uint8_t*)buf] ^ (val >> 8);
- buf = (uint8_t*)buf + 1;
- }
- return val;
-}
-
-#endif
+++ /dev/null
-/*
- * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-#ifndef __FWIMAGE_H
-#define __FWIMAGE_H
-
-#include <stdint.h>
-
-#define FWIMAGE_MAGIC 0x46577830 /* FWx0 */
-
-struct fwimage_header {
- uint32_t version;
- uint32_t flags;
- char data[];
-};
-
-struct fwimage_trailer {
- uint32_t magic;
- uint32_t crc32;
- uint8_t type;
- uint8_t __pad[3];
- uint32_t size;
-};
-
-enum fwimage_type {
- FWIMAGE_SIGNATURE,
- FWIMAGE_INFO,
-};
-
-#endif
+++ /dev/null
-/*
- * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-#include <sys/types.h>
-#include <stdio.h>
-#include <getopt.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "fwimage.h"
-#include "utils.h"
-#include "crc32.h"
-
-#define METADATA_MAXLEN 30 * 1024
-#define SIGNATURE_MAXLEN 1 * 1024
-
-#define BUFLEN (METADATA_MAXLEN + SIGNATURE_MAXLEN + 1024)
-
-enum {
- MODE_DEFAULT = -1,
- MODE_EXTRACT = 0,
- MODE_APPEND = 1,
-};
-
-struct data_buf {
- char *cur;
- char *prev;
- int cur_len;
- int file_len;
-};
-
-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];
-
-#define msg(...) \
- do { \
- if (!quiet) \
- fprintf(stderr, __VA_ARGS__); \
- } while (0)
-
-static int
-usage(const char *progname)
-{
- fprintf(stderr, "Usage: %s <options> <firmware>\n"
- "\n"
- "Options:\n"
- " -S <file>: Append signature file to firmware image\n"
- " -I <file>: Append metadata file to firmware image\n"
- " -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;
-}
-
-static FILE *
-open_file(const char *name, bool write)
-{
- FILE *ret;
-
- if (!strcmp(name, "-"))
- return write ? stdout : stdin;
-
- ret = fopen(name, write ? "w" : "r+");
- if (!ret && !write)
- ret = fopen(name, "r");
-
- return ret;
-}
-
-static int
-set_file(FILE **file, const char *name, int mode)
-{
- if (file_mode < 0)
- file_mode = mode;
- else if (file_mode != mode) {
- msg("Error: mixing appending and extracting data is not supported\n");
- return 1;
- }
-
- if (*file) {
- msg("Error: the same append/extract option cannot be used multiple times\n");
- return 1;
- }
-
- *file = open_file(name, mode == MODE_EXTRACT);
- return !*file;
-}
-
-static void
-trailer_update_crc(struct fwimage_trailer *tr, void *buf, int len)
-{
- tr->crc32 = cpu_to_be32(crc32_block(be32_to_cpu(tr->crc32), buf, len, crc_table));
-}
-
-static int
-append_data(FILE *in, FILE *out, struct fwimage_trailer *tr, int maxlen)
-{
- while (1) {
- char buf[512];
- int len;
-
- len = fread(buf, 1, sizeof(buf), in);
- if (!len)
- break;
-
- maxlen -= len;
- if (maxlen < 0)
- return 1;
-
- tr->size += len;
- trailer_update_crc(tr, buf, len);
- fwrite(buf, len, 1, out);
- }
-
- return 0;
-}
-
-static void
-append_trailer(FILE *out, struct fwimage_trailer *tr)
-{
- tr->size = cpu_to_be32(tr->size);
- fwrite(tr, sizeof(*tr), 1, out);
- trailer_update_crc(tr, tr, sizeof(*tr));
-}
-
-static int
-add_metadata(struct fwimage_trailer *tr)
-{
- struct fwimage_header hdr = {};
-
- tr->type = FWIMAGE_INFO;
- tr->size = sizeof(hdr) + sizeof(*tr);
-
- trailer_update_crc(tr, &hdr, sizeof(hdr));
- fwrite(&hdr, sizeof(hdr), 1, firmware_file);
-
- if (append_data(metadata_file, firmware_file, tr, METADATA_MAXLEN))
- return 1;
-
- append_trailer(firmware_file, tr);
-
- return 0;
-}
-
-static int
-add_signature(struct fwimage_trailer *tr)
-{
- if (!signature_file)
- return 0;
-
- tr->type = FWIMAGE_SIGNATURE;
- tr->size = sizeof(*tr);
-
- if (append_data(signature_file, firmware_file, tr, SIGNATURE_MAXLEN))
- return 1;
-
- append_trailer(firmware_file, tr);
-
- return 0;
-}
-
-static int
-add_data(const char *name)
-{
- struct fwimage_trailer tr = {
- .magic = cpu_to_be32(FWIMAGE_MAGIC),
- .crc32 = ~0,
- };
- int file_len = 0;
- int ret = 0;
-
- firmware_file = fopen(name, "r+");
- if (!firmware_file) {
- msg("Failed to open firmware file\n");
- return 1;
- }
-
- while (1) {
- char buf[512];
- int len;
-
- len = fread(buf, 1, sizeof(buf), firmware_file);
- if (!len)
- break;
-
- file_len += len;
- trailer_update_crc(&tr, buf, len);
- }
-
- if (metadata_file)
- ret = add_metadata(&tr);
- else if (signature_file)
- ret = add_signature(&tr);
-
- if (ret) {
- fflush(firmware_file);
- ftruncate(fileno(firmware_file), file_len);
- }
-
- return ret;
-}
-
-static void
-remove_tail(struct data_buf *dbuf, int len)
-{
- dbuf->cur_len -= len;
- dbuf->file_len -= len;
-
- if (dbuf->cur_len)
- return;
-
- free(dbuf->cur);
- dbuf->cur = dbuf->prev;
- dbuf->prev = NULL;
- dbuf->cur_len = BUFLEN;
-}
-
-static int
-extract_tail(struct data_buf *dbuf, void *dest, int len)
-{
- int cur_len = dbuf->cur_len;
-
- if (!dbuf->cur)
- return 1;
-
- if (cur_len >= len)
- cur_len = len;
-
- memcpy(dest + (len - cur_len), dbuf->cur + dbuf->cur_len - cur_len, cur_len);
- remove_tail(dbuf, cur_len);
-
- cur_len = len - cur_len;
- if (cur_len && !dbuf->cur)
- return 1;
-
- memcpy(dest, dbuf->cur + dbuf->cur_len - cur_len, cur_len);
- remove_tail(dbuf, cur_len);
-
- return 0;
-}
-
-static uint32_t
-tail_crc32(struct data_buf *dbuf, uint32_t crc32)
-{
- if (dbuf->prev)
- crc32 = crc32_block(crc32, dbuf->prev, BUFLEN, crc_table);
-
- return crc32_block(crc32, dbuf->cur, dbuf->cur_len, crc_table);
-}
-
-static int
-validate_metadata(struct fwimage_header *hdr, int data_len)
-{
- if (hdr->version != 0)
- return 1;
- return 0;
-}
-
-static int
-extract_data(const char *name)
-{
- struct fwimage_header *hdr;
- 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) {
- msg("Failed to open firmware file\n");
- return 1;
- }
-
- if (truncate_file && firmware_file == stdin) {
- msg("Cannot truncate file when reading from stdin\n");
- return 1;
- }
-
- buf = malloc(BUFLEN);
- if (!buf)
- return 1;
-
- do {
- char *tmp = dbuf.cur;
-
- if (write_truncated && dbuf.prev)
- fwrite(dbuf.prev, 1, BUFLEN, stdout);
-
- dbuf.cur = dbuf.prev;
- dbuf.prev = tmp;
-
- if (dbuf.cur)
- crc32 = crc32_block(crc32, dbuf.cur, BUFLEN, crc_table);
- else
- dbuf.cur = malloc(BUFLEN);
-
- if (!dbuf.cur)
- goto out;
-
- dbuf.cur_len = fread(dbuf.cur, 1, BUFLEN, firmware_file);
- dbuf.file_len += dbuf.cur_len;
- } while (dbuf.cur_len == BUFLEN);
-
- while (1) {
-
- if (extract_tail(&dbuf, &tr, sizeof(tr)))
- break;
-
- if (tr.magic != cpu_to_be32(FWIMAGE_MAGIC)) {
- msg("Data not found\n");
- metadata_keep = true;
- break;
- }
-
- data_len = be32_to_cpu(tr.size) - sizeof(tr);
-
- if (be32_to_cpu(tr.crc32) != tail_crc32(&dbuf, crc32)) {
- msg("CRC error\n");
- break;
- }
-
- if (data_len > BUFLEN) {
- msg("Size error\n");
- break;
- }
-
- extract_tail(&dbuf, buf, data_len);
-
- if (tr.type == FWIMAGE_SIGNATURE) {
- if (!signature_file)
- continue;
- fwrite(buf, data_len, 1, signature_file);
- ret = 0;
- break;
- } else if (tr.type == FWIMAGE_INFO) {
- if (!metadata_file) {
- dbuf.file_len += data_len + sizeof(tr);
- metadata_keep = true;
- break;
- }
-
- hdr = buf;
- data_len -= sizeof(*hdr);
- if (validate_metadata(hdr, data_len))
- continue;
-
- fwrite(hdr + 1, data_len, 1, metadata_file);
- ret = 0;
- break;
- } else {
- continue;
- }
- }
-
- 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);
- free(dbuf.prev);
- return ret;
-}
-
-static void cleanup(void)
-{
- if (signature_file)
- fclose(signature_file);
- if (metadata_file)
- fclose(metadata_file);
- if (firmware_file)
- fclose(firmware_file);
-}
-
-int main(int argc, char **argv)
-{
- const char *progname = argv[0];
- int ret, ch;
-
- crc32_filltable(crc_table);
-
- while ((ch = getopt(argc, argv, "i:I:qs:S:tT")) != -1) {
- ret = 0;
- switch(ch) {
- case 'S':
- ret = set_file(&signature_file, optarg, MODE_APPEND);
- break;
- case 'I':
- ret = set_file(&metadata_file, optarg, MODE_APPEND);
- break;
- case 's':
- ret = set_file(&signature_file, optarg, MODE_EXTRACT);
- break;
- case 'i':
- ret = set_file(&metadata_file, optarg, MODE_EXTRACT);
- break;
- case 't':
- truncate_file = true;
- break;
- case 'T':
- write_truncated = true;
- break;
- case 'q':
- quiet = true;
- break;
- }
-
- if (ret)
- goto out;
- }
-
- if (optind >= argc) {
- ret = usage(progname);
- goto out;
- }
-
- if (file_mode == MODE_DEFAULT) {
- ret = usage(progname);
- goto out;
- }
-
- if (signature_file && metadata_file) {
- msg("Cannot append/extract metadata and signature in one run\n");
- return 1;
- }
-
- if (file_mode)
- ret = add_data(argv[optind]);
- else
- ret = extract_data(argv[optind]);
-
-out:
- cleanup();
- return ret;
-}
+++ /dev/null
-/*
- * utils - misc libubox utility functions
- *
- * Copyright (C) 2012 Felix Fietkau <nbd@openwrt.org>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef __LIBUBOX_UTILS_H
-#define __LIBUBOX_UTILS_H
-
-#include <sys/types.h>
-#include <stdint.h>
-#include <stdbool.h>
-
-#ifndef ARRAY_SIZE
-#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
-#endif
-
-#ifdef __GNUC__
-#define _GNUC_MIN_VER(maj, min) (((__GNUC__ << 8) + __GNUC_MINOR__) >= (((maj) << 8) + (min)))
-#else
-#define _GNUC_MIN_VER(maj, min) 0
-#endif
-
-#if defined(__linux__) || defined(__CYGWIN__)
-#include <byteswap.h>
-#include <endian.h>
-
-#elif defined(__APPLE__)
-#include <machine/endian.h>
-#include <machine/byte_order.h>
-#define bswap_32(x) OSSwapInt32(x)
-#define bswap_64(x) OSSwapInt64(x)
-#elif defined(__FreeBSD__)
-#include <sys/endian.h>
-#define bswap_32(x) bswap32(x)
-#define bswap_64(x) bswap64(x)
-#else
-#include <machine/endian.h>
-#define bswap_32(x) swap32(x)
-#define bswap_64(x) swap64(x)
-#endif
-
-#ifndef __BYTE_ORDER
-#define __BYTE_ORDER BYTE_ORDER
-#endif
-#ifndef __BIG_ENDIAN
-#define __BIG_ENDIAN BIG_ENDIAN
-#endif
-#ifndef __LITTLE_ENDIAN
-#define __LITTLE_ENDIAN LITTLE_ENDIAN
-#endif
-
-static inline uint16_t __u_bswap16(uint16_t val)
-{
- return ((val >> 8) & 0xffu) | ((val & 0xffu) << 8);
-}
-
-#if _GNUC_MIN_VER(4, 2)
-#define __u_bswap32(x) __builtin_bswap32(x)
-#define __u_bswap64(x) __builtin_bswap64(x)
-#else
-#define __u_bswap32(x) bswap_32(x)
-#define __u_bswap64(x) bswap_64(x)
-#endif
-
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-
-#define cpu_to_be64(x) __u_bswap64(x)
-#define cpu_to_be32(x) __u_bswap32(x)
-#define cpu_to_be16(x) __u_bswap16((uint16_t) (x))
-
-#define be64_to_cpu(x) __u_bswap64(x)
-#define be32_to_cpu(x) __u_bswap32(x)
-#define be16_to_cpu(x) __u_bswap16((uint16_t) (x))
-
-#define cpu_to_le64(x) (x)
-#define cpu_to_le32(x) (x)
-#define cpu_to_le16(x) (x)
-
-#define le64_to_cpu(x) (x)
-#define le32_to_cpu(x) (x)
-#define le16_to_cpu(x) (x)
-
-#else /* __BYTE_ORDER == __LITTLE_ENDIAN */
-
-#define cpu_to_le64(x) __u_bswap64(x)
-#define cpu_to_le32(x) __u_bswap32(x)
-#define cpu_to_le16(x) __u_bswap16((uint16_t) (x))
-
-#define le64_to_cpu(x) __u_bswap64(x)
-#define le32_to_cpu(x) __u_bswap32(x)
-#define le16_to_cpu(x) __u_bswap16((uint16_t) (x))
-
-#define cpu_to_be64(x) (x)
-#define cpu_to_be32(x) (x)
-#define cpu_to_be16(x) (x)
-
-#define be64_to_cpu(x) (x)
-#define be32_to_cpu(x) (x)
-#define be16_to_cpu(x) (x)
-
-#endif
-
-#endif
--- /dev/null
+/*
+ * utils - misc libubox utility functions
+ *
+ * Copyright (C) 2012 Felix Fietkau <nbd@openwrt.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __LIBUBOX_UTILS_H
+#define __LIBUBOX_UTILS_H
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+#endif
+
+#ifdef __GNUC__
+#define _GNUC_MIN_VER(maj, min) (((__GNUC__ << 8) + __GNUC_MINOR__) >= (((maj) << 8) + (min)))
+#else
+#define _GNUC_MIN_VER(maj, min) 0
+#endif
+
+#if defined(__linux__) || defined(__CYGWIN__)
+#include <byteswap.h>
+#include <endian.h>
+
+#elif defined(__APPLE__)
+#include <machine/endian.h>
+#include <machine/byte_order.h>
+#define bswap_32(x) OSSwapInt32(x)
+#define bswap_64(x) OSSwapInt64(x)
+#elif defined(__FreeBSD__)
+#include <sys/endian.h>
+#define bswap_32(x) bswap32(x)
+#define bswap_64(x) bswap64(x)
+#else
+#include <machine/endian.h>
+#define bswap_32(x) swap32(x)
+#define bswap_64(x) swap64(x)
+#endif
+
+#ifndef __BYTE_ORDER
+#define __BYTE_ORDER BYTE_ORDER
+#endif
+#ifndef __BIG_ENDIAN
+#define __BIG_ENDIAN BIG_ENDIAN
+#endif
+#ifndef __LITTLE_ENDIAN
+#define __LITTLE_ENDIAN LITTLE_ENDIAN
+#endif
+
+static inline uint16_t __u_bswap16(uint16_t val)
+{
+ return ((val >> 8) & 0xffu) | ((val & 0xffu) << 8);
+}
+
+#if _GNUC_MIN_VER(4, 2)
+#define __u_bswap32(x) __builtin_bswap32(x)
+#define __u_bswap64(x) __builtin_bswap64(x)
+#else
+#define __u_bswap32(x) bswap_32(x)
+#define __u_bswap64(x) bswap_64(x)
+#endif
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+
+#define cpu_to_be64(x) __u_bswap64(x)
+#define cpu_to_be32(x) __u_bswap32(x)
+#define cpu_to_be16(x) __u_bswap16((uint16_t) (x))
+
+#define be64_to_cpu(x) __u_bswap64(x)
+#define be32_to_cpu(x) __u_bswap32(x)
+#define be16_to_cpu(x) __u_bswap16((uint16_t) (x))
+
+#define cpu_to_le64(x) (x)
+#define cpu_to_le32(x) (x)
+#define cpu_to_le16(x) (x)
+
+#define le64_to_cpu(x) (x)
+#define le32_to_cpu(x) (x)
+#define le16_to_cpu(x) (x)
+
+#else /* __BYTE_ORDER == __LITTLE_ENDIAN */
+
+#define cpu_to_le64(x) __u_bswap64(x)
+#define cpu_to_le32(x) __u_bswap32(x)
+#define cpu_to_le16(x) __u_bswap16((uint16_t) (x))
+
+#define le64_to_cpu(x) __u_bswap64(x)
+#define le32_to_cpu(x) __u_bswap32(x)
+#define le16_to_cpu(x) __u_bswap16((uint16_t) (x))
+
+#define cpu_to_be64(x) (x)
+#define cpu_to_be32(x) (x)
+#define cpu_to_be16(x) (x)
+
+#define be64_to_cpu(x) (x)
+#define be32_to_cpu(x) (x)
+#define be16_to_cpu(x) (x)
+
+#endif
+
+#endif