firmware-utils: mksercommfw: overhaul image creation
Move the zip compression into a build recipe. Pad the image using the existing build recipes as well to remove duplicate functionality Change the code to append header and footer in two steps. Allow to use a fixed filename as the netgear update image does. Use a fixed timestamp within the zip archive to make the images reproducible. Due to the changes we are now compatible to the gnu89 c standard used by default on the buildbots and we don't need to force a more recent standard anymore. Beside all changes, the footer still looks wrong in compare to the netgear update image. Signed-off-by: Mathias Kresin <dev@kresin.me>
This commit is contained in:
		| @@ -168,6 +168,16 @@ define Build/gzip | |||||||
| 	@mv $@.new $@ | 	@mv $@.new $@ | ||||||
| endef | endef | ||||||
|  |  | ||||||
|  | define Build/zip | ||||||
|  | 	mkdir $@.tmp | ||||||
|  | 	mv $@ $@.tmp/$(1) | ||||||
|  |  | ||||||
|  | 	zip -j -X \ | ||||||
|  | 		$(if $(SOURCE_DATE_EPOCH),--mtime="$(SOURCE_DATE_EPOCH)") \ | ||||||
|  | 		$@ $@.tmp/$(if $(1),$(1),$@) | ||||||
|  | 	rm -rf $@.tmp | ||||||
|  | endef | ||||||
|  |  | ||||||
| define Build/jffs2 | define Build/jffs2 | ||||||
| 	rm -rf $(KDIR_TMP)/$(DEVICE_NAME)/jffs2 && \ | 	rm -rf $(KDIR_TMP)/$(DEVICE_NAME)/jffs2 && \ | ||||||
| 		mkdir -p $(KDIR_TMP)/$(DEVICE_NAME)/jffs2/$$(dirname $(1)) && \ | 		mkdir -p $(KDIR_TMP)/$(DEVICE_NAME)/jffs2/$$(dirname $(1)) && \ | ||||||
|   | |||||||
| @@ -2,17 +2,22 @@ | |||||||
| # MT76x8 Profiles | # MT76x8 Profiles | ||||||
| # | # | ||||||
|  |  | ||||||
| DEVICE_VARS += SERCOMM_KERNEL_OFFSET SERCOMM_HWID SERCOMM_HWVER SERCOMM_SWVER | DEVICE_VARS += SERCOMM_HWID SERCOMM_HWVER SERCOMM_SWVER | ||||||
|  |  | ||||||
| define Build/mksercommfw | define Build/sercom-seal | ||||||
| 	$(STAGING_DIR_HOST)/bin/mksercommfw \ | 	$(STAGING_DIR_HOST)/bin/mksercommfw \ | ||||||
| 		$@ \ | 		-i $@ \ | ||||||
| 		$(SERCOMM_KERNEL_OFFSET) \ | 		-b $(SERCOMM_HWID) \ | ||||||
| 		$(SERCOMM_HWID) \ | 		-r $(SERCOMM_HWVER) \ | ||||||
| 		$(SERCOMM_HWVER) \ | 		-v $(SERCOMM_SWVER) \ | ||||||
| 		$(SERCOMM_SWVER) | 		$(1) | ||||||
| endef | endef | ||||||
|  |  | ||||||
|  | define Build/sercom-footer | ||||||
|  | 	$(call Build/sercom-seal,-f) | ||||||
|  | endef | ||||||
|  |  | ||||||
|  |  | ||||||
| define Device/tplink | define Device/tplink | ||||||
|   TPLINK_FLASHLAYOUT := |   TPLINK_FLASHLAYOUT := | ||||||
|   TPLINK_HWID := |   TPLINK_HWID := | ||||||
| @@ -116,14 +121,14 @@ define Device/netgear_r6120 | |||||||
|   IMAGE_SIZE := $(ralink_default_fw_size_16M) |   IMAGE_SIZE := $(ralink_default_fw_size_16M) | ||||||
|   DEVICE_TITLE := Netgear AC1200 R6120 |   DEVICE_TITLE := Netgear AC1200 R6120 | ||||||
|   DEVICE_PACKAGES := kmod-mt76x2 kmod-usb2 kmod-usb-ohci |   DEVICE_PACKAGES := kmod-mt76x2 kmod-usb2 kmod-usb-ohci | ||||||
|   SERCOMM_KERNEL_OFFSET := 0x90000 |  | ||||||
|   SERCOMM_HWID := CGQ |   SERCOMM_HWID := CGQ | ||||||
|   SERCOMM_HWVER := A001 |   SERCOMM_HWVER := A001 | ||||||
|   SERCOMM_SWVER := 0x0040 |   SERCOMM_SWVER := 0x0040 | ||||||
|   IMAGES += factory.img |   IMAGES += factory.img | ||||||
|   IMAGE/default := append-kernel | pad-to $$$$(BLOCKSIZE)| append-rootfs | pad-rootfs |   IMAGE/default := append-kernel | pad-to $$$$(BLOCKSIZE)| append-rootfs | pad-rootfs | ||||||
|   IMAGE/sysupgrade.bin := $$(IMAGE/default) | append-metadata | check-size $$$$(IMAGE_SIZE) |   IMAGE/sysupgrade.bin := $$(IMAGE/default) | append-metadata | check-size $$$$(IMAGE_SIZE) | ||||||
|   IMAGE/factory.img := $$(IMAGE/default) | mksercommfw |   IMAGE/factory.img := pad-extra 576k | $$(IMAGE/default) | \ | ||||||
|  | 	sercom-footer | pad-to 128 | zip R6120.bin | sercom-seal | ||||||
| endef | endef | ||||||
| TARGET_DEVICES += netgear_r6120 | TARGET_DEVICES += netgear_r6120 | ||||||
|  |  | ||||||
|   | |||||||
| @@ -84,7 +84,7 @@ define Host/Compile | |||||||
| 	$(call cc,mkdhpimg buffalo-lib, -Wall) | 	$(call cc,mkdhpimg buffalo-lib, -Wall) | ||||||
| 	$(call cc,mkdlinkfw mkdlinkfw-lib, -lz -Wall --std=c99) | 	$(call cc,mkdlinkfw mkdlinkfw-lib, -lz -Wall --std=c99) | ||||||
| 	$(call cc,dns313-header, -Wall) | 	$(call cc,dns313-header, -Wall) | ||||||
| 	$(call cc,mksercommfw, -Wall --std=gnu99) | 	$(call cc,mksercommfw, -Wall) | ||||||
| endef | endef | ||||||
|  |  | ||||||
| define Host/Install | define Host/Install | ||||||
|   | |||||||
| @@ -5,6 +5,7 @@ | |||||||
| #include <unistd.h> | #include <unistd.h> | ||||||
| #include <byteswap.h> | #include <byteswap.h> | ||||||
| #include <endian.h> | #include <endian.h> | ||||||
|  | #include <getopt.h> | ||||||
|  |  | ||||||
| #if !defined(__BYTE_ORDER) | #if !defined(__BYTE_ORDER) | ||||||
| #error "Unknown byte order" | #error "Unknown byte order" | ||||||
| @@ -12,14 +13,8 @@ | |||||||
|  |  | ||||||
| #if __BYTE_ORDER == __BIG_ENDIAN | #if __BYTE_ORDER == __BIG_ENDIAN | ||||||
| #define cpu_to_be32(x)  (x) | #define cpu_to_be32(x)  (x) | ||||||
| #define be32_to_cpu(x)  (x) |  | ||||||
| #define cpu_to_be16(x)  (x) |  | ||||||
| #define be16_to_cpu(x)  (x) |  | ||||||
| #elif __BYTE_ORDER == __LITTLE_ENDIAN | #elif __BYTE_ORDER == __LITTLE_ENDIAN | ||||||
| #define cpu_to_be32(x)  bswap_32(x) | #define cpu_to_be32(x)  bswap_32(x) | ||||||
| #define be32_to_cpu(x)  bswap_32(x) |  | ||||||
| #define cpu_to_be16(x)  bswap_16(x) |  | ||||||
| #define be16_to_cpu(x)  bswap_16(x) |  | ||||||
| #else | #else | ||||||
| #error "Unsupported endianness" | #error "Unsupported endianness" | ||||||
| #endif | #endif | ||||||
| @@ -33,9 +28,6 @@ | |||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #define ERR(...) {printf(__VA_ARGS__); } | #define ERR(...) {printf(__VA_ARGS__); } | ||||||
| #define ALIGN(a,b) ((a) + ((b) - ((a) % (b)))) |  | ||||||
| #define ROOTFS_ALIGN 128 |  | ||||||
| #define HEADER_SIZE 71 |  | ||||||
|  |  | ||||||
| /* | /* | ||||||
|  * Fw Header Layout for Netgear / Sercomm devices (bytes) |  * Fw Header Layout for Netgear / Sercomm devices (bytes) | ||||||
| @@ -51,14 +43,12 @@ | |||||||
|  * magic  : 63-69  ASCII |  * magic  : 63-69  ASCII | ||||||
|  * ChkSum : 511    Inverse value of the full image checksum while this location is 0x00 |  * ChkSum : 511    Inverse value of the full image checksum while this location is 0x00 | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| static const char* magic = "sErCoMm"; /* 7 */ | static const char* magic = "sErCoMm"; /* 7 */ | ||||||
|  |  | ||||||
| /* 7-11: version control/download control ? */ |  | ||||||
| static const unsigned char version[4] = { 0x00, 0x01, 0x00, 0x00 }; | static const unsigned char version[4] = { 0x00, 0x01, 0x00, 0x00 }; | ||||||
|  | static const int header_sz = 512; | ||||||
|  | static const int footer_sz = 71; | ||||||
|  |  | ||||||
|  | static int is_header = 1; | ||||||
| /* 512 onwards -> ZIP containing rootfs with the same Header */ |  | ||||||
|  |  | ||||||
| struct file_info { | struct file_info { | ||||||
| 	char* file_name; /* name of the file */ | 	char* file_name; /* name of the file */ | ||||||
| @@ -68,23 +58,32 @@ struct file_info { | |||||||
|  |  | ||||||
| static u_int8_t getCheckSum(char* data, int len) { | static u_int8_t getCheckSum(char* data, int len) { | ||||||
| 	u_int8_t new = 0; | 	u_int8_t new = 0; | ||||||
|  | 	int i; | ||||||
|  |  | ||||||
| 	if (!data) { | 	if (!data) { | ||||||
| 		ERR("Invalid pointer provided!\n"); | 		ERR("Invalid pointer provided!\n"); | ||||||
| 		return 0; | 		return 0; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	for (int i = 0; i < len; i++) { | 	for (i = 0; i < len; i++) { | ||||||
| 		new += data[i]; | 		new += data[i]; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return new; | 	return new; | ||||||
| } | } | ||||||
|  |  | ||||||
| static int bufferFile(struct file_info* finfo) { | /* | ||||||
| 	int fs = 0; |  * read file into buffer | ||||||
|  |  * add space for header/footer | ||||||
|  |  */ | ||||||
|  | static int copyToOutputBuf(struct file_info* finfo) { | ||||||
| 	FILE* fp = NULL; | 	FILE* fp = NULL; | ||||||
|  |  | ||||||
|  | 	int file_sz = 0; | ||||||
|  | 	int extra_sz; | ||||||
|  | 	int hdr_pos; | ||||||
|  | 	int img_pos; | ||||||
|  |  | ||||||
| 	if (!finfo || !finfo->file_name) { | 	if (!finfo || !finfo->file_name) { | ||||||
| 		ERR("Invalid pointer provided!\n"); | 		ERR("Invalid pointer provided!\n"); | ||||||
| 		return -1; | 		return -1; | ||||||
| @@ -100,25 +99,39 @@ static int bufferFile(struct file_info* finfo) { | |||||||
| 	/* Get filesize */ | 	/* Get filesize */ | ||||||
| 	rewind(fp); | 	rewind(fp); | ||||||
| 	fseek(fp, 0L, SEEK_END); | 	fseek(fp, 0L, SEEK_END); | ||||||
| 	fs = ftell(fp); | 	file_sz = ftell(fp); | ||||||
| 	rewind(fp); | 	rewind(fp); | ||||||
|  |  | ||||||
| 	if (fs < 0) { | 	if (file_sz < 1) { | ||||||
| 		ERR("Error getting filesize: %s\n", finfo->file_name); | 		ERR("Error getting filesize: %s\n", finfo->file_name); | ||||||
| 		fclose(fp); | 		fclose(fp); | ||||||
| 		return -1; | 		return -1; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	DBG("Filesize: %i\n", fs); | 	if (is_header) { | ||||||
| 	finfo->file_size = fs; | 		extra_sz = header_sz; | ||||||
|  | 		hdr_pos = 0; | ||||||
|  | 		img_pos = header_sz; | ||||||
|  | 	} else { | ||||||
|  | 		extra_sz = footer_sz; | ||||||
|  | 		hdr_pos = file_sz; | ||||||
|  | 		img_pos = 0; | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	if (!(finfo->file_data = malloc(fs))) { | 	DBG("Filesize: %i\n", file_sz); | ||||||
|  | 	finfo->file_size = file_sz + extra_sz; | ||||||
|  |  | ||||||
|  | 	if (!(finfo->file_data = malloc(finfo->file_size))) { | ||||||
| 		ERR("Out of memory!\n"); | 		ERR("Out of memory!\n"); | ||||||
| 		fclose(fp); | 		fclose(fp); | ||||||
| 		return -1; | 		return -1; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if (fread(finfo->file_data, 1, fs, fp) != fs) { | 	/* init header/footer bytes */ | ||||||
|  | 	memset(finfo->file_data + hdr_pos, 0, extra_sz); | ||||||
|  |  | ||||||
|  | 	/* read file and take care of leading header if exists */ | ||||||
|  | 	if (fread(finfo->file_data + img_pos, 1, file_sz, fp) != file_sz) { | ||||||
| 		ERR("Error reading file %s\n", finfo->file_name); | 		ERR("Error reading file %s\n", finfo->file_name); | ||||||
| 		fclose(fp); | 		fclose(fp); | ||||||
| 		return -1; | 		return -1; | ||||||
| @@ -127,7 +140,7 @@ static int bufferFile(struct file_info* finfo) { | |||||||
| 	DBG("File: read successful\n"); | 	DBG("File: read successful\n"); | ||||||
| 	fclose(fp); | 	fclose(fp); | ||||||
|  |  | ||||||
| 	return 0; | 	return hdr_pos; | ||||||
| } | } | ||||||
|  |  | ||||||
| static int writeFile(struct file_info* finfo) { | static int writeFile(struct file_info* finfo) { | ||||||
| @@ -157,266 +170,92 @@ static int writeFile(struct file_info* finfo) { | |||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| static void fi_clean(struct file_info* finfo) { |  | ||||||
| 	if (!finfo) |  | ||||||
| 		return; |  | ||||||
|  |  | ||||||
| 	if (finfo->file_name) { |  | ||||||
| 		finfo->file_name = NULL; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if (finfo->file_data) { |  | ||||||
| 		free(finfo->file_data); |  | ||||||
| 		finfo->file_data = NULL; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	finfo->file_size = 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void usage(char* argv[]) { | static void usage(char* argv[]) { | ||||||
|     printf("Usage: %s <sysupgradefile> <kernel_offset> <HWID> <HWVER> <SWID>\n" | 	printf("Usage: %s [OPTIONS...]\n" | ||||||
|            "All are positional arguments ...	\n" | 	       "\n" | ||||||
|            "	sysupgradefile:     File with the kernel uimage at 0\n" | 	       "Options:\n" | ||||||
|            "	kernel_offset:      Offset where the kernel is located (decimal, hex or octal notation)\n" | 	       "  -f            add sercom footer (if absent, header)\n" | ||||||
|            "	HWID:               Hardware ID, ASCII\n" | 	       "  -b <hwid>     use hardware id specified with <hwid> (ASCII)\n" | ||||||
|            "	HWVER:              Hardware Version, ASCII\n" | 	       "  -r <hwrev>    use hardware revision specified with <hwrev> (ASCII)\n" | ||||||
|            "	SWID:               Software Version (decimal, hex or octal notation)\n" | 	       "  -v <version>  set image version to <version> (decimal, hex or octal notation)\n" | ||||||
|            "	\n" | 	       "  -i <file>     input file\n" | ||||||
| 	       , argv[0]); | 	       , argv[0]); | ||||||
| } | } | ||||||
|  |  | ||||||
| int main(int argc, char* argv[]) { | int main(int argc, char* argv[]) { | ||||||
| 	int ret = 1; |  | ||||||
| 	int rootfsname_sz; |  | ||||||
| 	int zipfsname_sz; |  | ||||||
| 	int zipcmd_sz; |  | ||||||
| 	u_int32_t kernel_offset = 0x90000; /* offset for the kernel inside the rootfs, default val */ |  | ||||||
| 	u_int32_t swVer = 0; |  | ||||||
| 	struct file_info sysupgrade = { 0 }; |  | ||||||
| 	struct file_info header = { 0 }; |  | ||||||
| 	struct file_info rootfs = { 0 }; |  | ||||||
| 	struct file_info zippedfs = { 0 }; |  | ||||||
| 	struct file_info image = { 0 }; | 	struct file_info image = { 0 }; | ||||||
|  |  | ||||||
| 	char* hwID = NULL; | 	char* hwID = NULL; | ||||||
| 	char* hwVer = NULL; | 	char* hwVer = NULL; | ||||||
| 	char* rootfsname = NULL; | 	u_int32_t swVer = 0; | ||||||
| 	char* zipfsname = NULL; |  | ||||||
| 	char* zipcmd = NULL; |  | ||||||
| 	u_int8_t chkSum; | 	u_int8_t chkSum; | ||||||
|  | 	int hdr_offset; | ||||||
|  |  | ||||||
| 	if (argc == 2) { | 	while ( 1 ) { | ||||||
| 		struct file_info myfile = { argv[1], 0, 0 }; | 		int c; | ||||||
|  |  | ||||||
| 		if (bufferFile(&myfile)) | 		c = getopt(argc, argv, "b:i:r:v:f"); | ||||||
| 			return 1; | 		if (c == -1) | ||||||
|  | 			break; | ||||||
|  |  | ||||||
| 		chkSum = getCheckSum(myfile.file_data, myfile.file_size); | 		switch (c) { | ||||||
| 		printf("Checksum for File: 0x%hhX\n", chkSum); | 		case 'b': | ||||||
|  | 			hwID = optarg; | ||||||
| 		return 0; | 			break; | ||||||
| 	} | 		case 'f': | ||||||
|  | 			is_header = 0; | ||||||
| 	if (argc != 6) { | 			break; | ||||||
| 		usage(argv); | 		case 'i': | ||||||
| 		return 1; | 			image.file_name = optarg; | ||||||
| 	} | 			break; | ||||||
|  | 		case 'r': | ||||||
| 	printf("Building fw image for sercomm devices ..\n"); | 			hwVer = optarg; | ||||||
|  | 			break; | ||||||
| 	/* process args */ | 		case 'v': | ||||||
| 	hwID = argv[3]; | 			swVer = (u_int32_t) strtol(optarg, NULL, 0); | ||||||
| 	hwVer = argv[4]; |  | ||||||
|  |  | ||||||
| 	sysupgrade.file_name = argv[1]; |  | ||||||
| 	image.file_name = argv[1]; |  | ||||||
| 	kernel_offset = (u_int32_t) strtol(argv[2], NULL, 0); |  | ||||||
| 	swVer = (u_int32_t) strtol(argv[5], NULL, 0); |  | ||||||
| 			swVer = cpu_to_be32(swVer); | 			swVer = cpu_to_be32(swVer); | ||||||
|  | 			break; | ||||||
| 	/* Check if files actually exist */ | 		default: | ||||||
| 	if (access(sysupgrade.file_name, (F_OK | R_OK))) { | 			usage(argv); | ||||||
| 		/* Error */ | 			return EXIT_FAILURE; | ||||||
| 		ERR("File not found: %s\n", sysupgrade.file_name); | 		} | ||||||
| 		goto cleanup; |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/* Calculate amount of required memory (incl. 0-term) */ | 	if (!hwID || !hwVer || !image.file_name) { | ||||||
| 	rootfsname_sz = strlen(sysupgrade.file_name) + 7 + 1; | 			usage(argv); | ||||||
| 	zipfsname_sz = strlen(sysupgrade.file_name) + 7 + 4 + 1; | 			return EXIT_FAILURE; | ||||||
|  |  | ||||||
| 	/* Allocate required memory */ |  | ||||||
| 	if (!(rootfsname = (char*) malloc(rootfsname_sz)) || !(zipfsname = |  | ||||||
| 			(char*) malloc(zipfsname_sz))) { |  | ||||||
| 		/* Error */ |  | ||||||
| 		ERR("Out of memory!\n"); |  | ||||||
| 		goto cleanup; |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/* Create filenames */ | 	/* | ||||||
| 	if (snprintf(rootfsname, rootfsname_sz, "%s.rootfs", sysupgrade.file_name) | 	 * copy input to buffer, add extra space for header/footer and return | ||||||
| 			>= rootfsname_sz | 	 * header position | ||||||
| 			|| snprintf(zipfsname, zipfsname_sz, "%s.rootfs.zip", | 	 */ | ||||||
| 					sysupgrade.file_name) >= zipfsname_sz) { | 	hdr_offset = copyToOutputBuf(&image); | ||||||
| 		/* Error */ | 	if (hdr_offset < 0) | ||||||
| 		ERR("Buffer too small!\n"); | 		return EXIT_FAILURE; | ||||||
| 		goto cleanup; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	/* Buffer all files */ | 	DBG("Filling header: %s %s %2X %s\n", hwID, hwVer, swVer, magic); | ||||||
| 	if (bufferFile(&sysupgrade)) { |  | ||||||
| 		/* Error */ |  | ||||||
| 		goto cleanup; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	DBG("Building header: %s %s %2X %s\n", hwID, hwVer, swVer, magic); | 	strncpy(image.file_data + hdr_offset + 0, magic, 7); | ||||||
|  | 	memcpy(image.file_data + hdr_offset + 7, version, sizeof(version)); | ||||||
|  | 	strncpy(image.file_data + hdr_offset + 11, hwID, 34); | ||||||
|  | 	strncpy(image.file_data + hdr_offset + 45, hwVer, 10); | ||||||
|  | 	memcpy(image.file_data + hdr_offset + 55, &swVer, sizeof(swVer)); | ||||||
|  | 	strncpy(image.file_data + hdr_offset + 63, magic, 7); | ||||||
|  |  | ||||||
| 	/* Construct the firmware header/magic */ | 	/* calculate checksum and invert checksum */ | ||||||
| 	header.file_name = NULL; | 	if (is_header) { | ||||||
| 	header.file_size = HEADER_SIZE; |  | ||||||
|  |  | ||||||
| 	if (!(header.file_data = (char*) calloc(1, HEADER_SIZE))) { |  | ||||||
| 		/* Error */ |  | ||||||
| 		ERR("Out of memory!\n"); |  | ||||||
| 		goto cleanup; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	strncpy(header.file_data + 0, magic, 7); |  | ||||||
| 	memcpy(header.file_data + 7, version, sizeof(version)); |  | ||||||
| 	strncpy(header.file_data + 11, hwID, 34); |  | ||||||
| 	strncpy(header.file_data + 45, hwVer, 10); |  | ||||||
| 	memcpy(header.file_data + 55, &swVer, sizeof(swVer)); |  | ||||||
| 	strncpy(header.file_data + 63, magic, 7); |  | ||||||
|  |  | ||||||
| 	DBG("Creating rootfs ..\n"); |  | ||||||
|  |  | ||||||
| 	/* Construct a rootfs */ |  | ||||||
| 	rootfs.file_name = rootfsname; |  | ||||||
| 	rootfs.file_size = ALIGN( |  | ||||||
| 			sysupgrade.file_size + kernel_offset + header.file_size, |  | ||||||
| 			ROOTFS_ALIGN); |  | ||||||
|  |  | ||||||
| 	if (!(rootfs.file_data = calloc(1, rootfs.file_size))) { |  | ||||||
| 		/* Error */ |  | ||||||
| 		ERR("Out of memory!\n"); |  | ||||||
| 		goto cleanup; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	/* copy Owrt image to kernel location */ |  | ||||||
| 	memcpy(rootfs.file_data + kernel_offset, sysupgrade.file_data, |  | ||||||
| 			sysupgrade.file_size); |  | ||||||
|  |  | ||||||
| 	/* Append header after the owrt image.  The updater searches for it */ |  | ||||||
| 	memcpy(rootfs.file_data + kernel_offset + sysupgrade.file_size, |  | ||||||
| 			header.file_data, header.file_size); |  | ||||||
|  |  | ||||||
| 	/* Write to file */ |  | ||||||
| 	if (writeFile(&rootfs)) { |  | ||||||
| 		/* Error */ |  | ||||||
| 		goto cleanup; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	/* Construct a zip */ |  | ||||||
| 	DBG("Preparing to zip ..\n"); |  | ||||||
|  |  | ||||||
| 	/* now that we got the rootfs, repeat the whole thing again(sorta): |  | ||||||
| 	 * 1. zip the rootfs */ |  | ||||||
| 	zipcmd_sz = 3 + 1 + strlen(zipfsname) + 1 + strlen(rootfs.file_name) + 1; |  | ||||||
|  |  | ||||||
| 	if (!(zipcmd = malloc(zipcmd_sz))) { |  | ||||||
| 		/* Error */ |  | ||||||
| 		ERR("Out of memory!\n"); |  | ||||||
| 		goto cleanup; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if (snprintf(zipcmd, zipcmd_sz, "%s %s %s", "zip", zipfsname, |  | ||||||
| 			rootfs.file_name) >= zipcmd_sz) { |  | ||||||
| 		/* Error */ |  | ||||||
| 		ERR("Buffer too small!\n"); |  | ||||||
| 		goto cleanup; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if (system(zipcmd)) { |  | ||||||
| 		/* Error */ |  | ||||||
| 		ERR("Error creating a zip file!\n"); |  | ||||||
| 		goto cleanup; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	/* and load zipped fs */ |  | ||||||
| 	zippedfs.file_name = zipfsname; |  | ||||||
|  |  | ||||||
| 	if (bufferFile(&zippedfs)) { |  | ||||||
| 		/* Error */ |  | ||||||
| 		goto cleanup; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	DBG("Creating Image.\n"); |  | ||||||
|  |  | ||||||
| 	/* 2. create new file 512 + rootfs size */ |  | ||||||
| 	image.file_size = zippedfs.file_size + 512; |  | ||||||
| 	if (!(image.file_data = malloc(zippedfs.file_size + 512))) { |  | ||||||
| 		/* Error */ |  | ||||||
| 		ERR("Out of memory!\n"); |  | ||||||
| 		goto cleanup; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	/* 3. add header to file */ |  | ||||||
| 	memcpy(image.file_data, header.file_data, header.file_size); |  | ||||||
|  |  | ||||||
| 	/* 4. clear remaining space */ |  | ||||||
| 	if (header.file_size < 512) |  | ||||||
| 		memset(image.file_data + header.file_size, 0, 512 - header.file_size); |  | ||||||
|  |  | ||||||
| 	/* 5. copy zipfile at loc 512 */ |  | ||||||
| 	memcpy(image.file_data + 512, zippedfs.file_data, zippedfs.file_size); |  | ||||||
|  |  | ||||||
| 	/* 6. do a checksum run, and compute checksum */ |  | ||||||
| 		chkSum = getCheckSum(image.file_data, image.file_size); | 		chkSum = getCheckSum(image.file_data, image.file_size); | ||||||
|  | 		chkSum = (chkSum ^ 0xFF) + 1; | ||||||
| 		DBG("Checksum for Image: %hhX\n", chkSum); | 		DBG("Checksum for Image: %hhX\n", chkSum); | ||||||
|  |  | ||||||
| 	/* 7. write the checksum inverted into byte 511 to bring it to 0 on verification */ | 		/* write checksum to header */ | ||||||
| 	chkSum = (chkSum ^ 0xFF) + 1; |  | ||||||
| 		image.file_data[511] = (char) chkSum; | 		image.file_data[511] = (char) chkSum; | ||||||
|  |  | ||||||
| 	chkSum = getCheckSum(image.file_data, image.file_size); |  | ||||||
| 	DBG("Checksum for after fix: %hhX\n", chkSum); |  | ||||||
|  |  | ||||||
| 	if (chkSum != 0) { |  | ||||||
| 		ERR("Invalid checksum!\n") |  | ||||||
| 		goto cleanup; |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/* 8. pray that the updater will accept the file */ | 	/* overwrite input file */ | ||||||
| 	if (writeFile(&image)) { | 	if (writeFile(&image)) | ||||||
| 		/* Error */ | 		return EXIT_FAILURE; | ||||||
| 		goto cleanup; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	/* All seems OK */ | 	return EXIT_SUCCESS; | ||||||
| 	ret = 0; |  | ||||||
|  |  | ||||||
| 	cleanup: |  | ||||||
|  |  | ||||||
| 	if (rootfs.file_name && !access(rootfs.file_name, F_OK | W_OK)) |  | ||||||
| 		remove(rootfs.file_name); |  | ||||||
|  |  | ||||||
| 	if (zippedfs.file_name && !access(zippedfs.file_name, F_OK | W_OK)) |  | ||||||
| 		remove(zippedfs.file_name); |  | ||||||
|  |  | ||||||
| 	fi_clean(&sysupgrade); |  | ||||||
| 	fi_clean(&header); |  | ||||||
| 	fi_clean(&rootfs); |  | ||||||
| 	fi_clean(&zippedfs); |  | ||||||
| 	fi_clean(&image); |  | ||||||
|  |  | ||||||
| 	if (rootfsname) |  | ||||||
| 		free(rootfsname); |  | ||||||
|  |  | ||||||
| 	if (zipfsname) |  | ||||||
| 		free(zipfsname); |  | ||||||
|  |  | ||||||
| 	if (zipcmd) |  | ||||||
| 		free(zipcmd); |  | ||||||
|  |  | ||||||
| 	return ret; |  | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Mathias Kresin
					Mathias Kresin