1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * 4 * Copyright (C) 2014 OpenWrt.org 5 * Copyright (C) 2014 Mikko Hissa <mikko.hissa@werzek.com> 6 */ 7 8 #include <errno.h> 9 #include <fcntl.h> 10 #include <stdio.h> 11 #include <stdlib.h> 12 #include <string.h> 13 #include <netinet/in.h> 14 #include <sys/mman.h> 15 #include <sys/stat.h> 16 #include <unistd.h> 17 #include <zlib.h> 18 19 #define IH_MAGIC 0x27051956 20 #define IH_NMLEN 32 21 #define IH_PRODLEN 23 22 23 #define IH_TYPE_INVALID 0 24 #define IH_TYPE_STANDALONE 1 25 #define IH_TYPE_KERNEL 2 26 #define IH_TYPE_RAMDISK 3 27 #define IH_TYPE_MULTI 4 28 #define IH_TYPE_FIRMWARE 5 29 #define IH_TYPE_SCRIPT 6 30 #define IH_TYPE_FILESYSTEM 7 31 32 /* 33 * Compression Types 34 */ 35 #define IH_COMP_NONE 0 36 #define IH_COMP_GZIP 1 37 #define IH_COMP_BZIP2 2 38 #define IH_COMP_LZMA 3 39 40 typedef struct { 41 uint8_t major; 42 uint8_t minor; 43 } version_t; 44 45 typedef struct { 46 version_t kernel; 47 version_t fs; 48 uint8_t productid[IH_PRODLEN]; 49 uint8_t sub_fs; 50 uint32_t ih_ksz; 51 } asus_t; 52 53 typedef struct image_header { 54 uint32_t ih_magic; 55 uint32_t ih_hcrc; 56 uint32_t ih_time; 57 uint32_t ih_size; 58 uint32_t ih_load; 59 uint32_t ih_ep; 60 uint32_t ih_dcrc; 61 uint8_t ih_os; 62 uint8_t ih_arch; 63 uint8_t ih_type; 64 uint8_t ih_comp; 65 union { 66 char ih_name[IH_NMLEN]; 67 asus_t asus; 68 } tail; 69 } image_header_t; 70 71 typedef struct squashfs_sb { 72 uint32_t s_magic; 73 uint32_t pad0[9]; 74 uint64_t bytes_used; 75 } squashfs_sb_t; 76 77 typedef enum { 78 NONE, FACTORY, SYSUPGRADE, 79 } op_mode_t; 80 81 void 82 calc_crc(image_header_t *hdr, void *data, uint32_t len) 83 { 84 /* 85 * Calculate payload checksum 86 */ 87 hdr->ih_dcrc = htonl(crc32(0, (Bytef *)data, len)); 88 hdr->ih_size = htonl(len); 89 /* 90 * Calculate header checksum 91 */ 92 hdr->ih_hcrc = 0; 93 hdr->ih_hcrc = htonl(crc32(0, (Bytef *)hdr, sizeof(image_header_t))); 94 } 95 96 97 static void 98 usage(const char *progname, int status) 99 { 100 FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout; 101 102 fprintf(stream, "Usage: %s [OPTIONS...]\n", progname); 103 fprintf(stream, "\n" 104 "Options:\n" 105 " -f <file> generate a factory flash image <file>\n" 106 " -s <file> generate a sysupgrade flash image <file>\n" 107 " -h show this screen\n"); 108 exit(status); 109 } 110 111 int 112 process_image(char *progname, char *filename, op_mode_t opmode) 113 { 114 int fd; 115 void *ptr; 116 char namebuf[IH_NMLEN]; 117 struct stat sbuf; 118 uint32_t offset_kernel, offset_sqfs, offset_end, 119 offset_sec_header, offset_eb, offset_image_end; 120 squashfs_sb_t *sqs; 121 image_header_t *hdr; 122 123 if ((fd = open(filename, O_RDWR, 0666)) < 0) { 124 fprintf (stderr, "%s: Can't open %s: %s\n", 125 progname, filename, strerror(errno)); 126 return (EXIT_FAILURE); 127 } 128 129 if (fstat(fd, &sbuf) < 0) { 130 fprintf (stderr, "%s: Can't stat %s: %s\n", 131 progname, filename, strerror(errno)); 132 return (EXIT_FAILURE); 133 } 134 135 if ((unsigned)sbuf.st_size < sizeof(image_header_t)) { 136 fprintf (stderr, 137 "%s: Bad size: \"%s\" is no valid image\n", 138 progname, filename); 139 return (EXIT_FAILURE); 140 } 141 142 ptr = (void *)mmap(0, sbuf.st_size, 143 PROT_READ | PROT_WRITE, 144 MAP_SHARED, 145 fd, 0); 146 147 if ((caddr_t)ptr == (caddr_t)-1) { 148 fprintf (stderr, "%s: Can't read %s: %s\n", 149 progname, filename, strerror(errno)); 150 return (EXIT_FAILURE); 151 } 152 153 hdr = ptr; 154 155 if (ntohl(hdr->ih_magic) != IH_MAGIC) { 156 fprintf (stderr, 157 "%s: Bad Magic Number: \"%s\" is no valid image\n", 158 progname, filename); 159 return (EXIT_FAILURE); 160 } 161 162 if (opmode == FACTORY) { 163 strncpy(namebuf, hdr->tail.ih_name, IH_NMLEN); 164 hdr->tail.asus.kernel.major = 0; 165 hdr->tail.asus.kernel.minor = 0; 166 hdr->tail.asus.fs.major = 0; 167 hdr->tail.asus.fs.minor = 0; 168 strncpy((char *)&hdr->tail.asus.productid, "RT-N56U", IH_PRODLEN); 169 } 170 171 if (hdr->tail.asus.ih_ksz == 0) 172 hdr->tail.asus.ih_ksz = htonl(ntohl(hdr->ih_size) + sizeof(image_header_t)); 173 174 offset_kernel = sizeof(image_header_t); 175 offset_sqfs = ntohl(hdr->tail.asus.ih_ksz); 176 sqs = ptr + offset_sqfs; 177 offset_sec_header = offset_sqfs + sqs->bytes_used; 178 179 /* 180 * Reserve space for the second header. 181 */ 182 offset_end = offset_sec_header + sizeof(image_header_t); 183 offset_eb = ((offset_end>>16)+1)<<16; 184 185 if (opmode == FACTORY) 186 offset_image_end = offset_eb + 4; 187 else 188 offset_image_end = sbuf.st_size; 189 /* 190 * Move the second header at the end of the image. 191 */ 192 offset_end = offset_sec_header; 193 offset_sec_header = offset_eb - sizeof(image_header_t); 194 195 /* 196 * Remove jffs2 markers between squashfs and eb boundary. 197 */ 198 if (opmode == FACTORY) 199 memset(ptr+offset_end, 0xff ,offset_eb - offset_end); 200 201 /* 202 * Grow the image if needed. 203 */ 204 if (offset_image_end > sbuf.st_size) { 205 (void) munmap((void *)ptr, sbuf.st_size); 206 ftruncate(fd, offset_image_end); 207 ptr = (void *)mmap(0, offset_image_end, 208 PROT_READ | PROT_WRITE, 209 MAP_SHARED, 210 fd, 0); 211 /* 212 * jffs2 marker 213 */ 214 if (opmode == FACTORY) { 215 *(uint8_t *)(ptr+offset_image_end-4) = 0xde; 216 *(uint8_t *)(ptr+offset_image_end-3) = 0xad; 217 *(uint8_t *)(ptr+offset_image_end-2) = 0xc0; 218 *(uint8_t *)(ptr+offset_image_end-1) = 0xde; 219 } 220 } 221 222 /* 223 * Calculate checksums for the second header to be used after flashing. 224 */ 225 if (opmode == FACTORY) { 226 hdr = ptr+offset_sec_header; 227 memcpy(hdr, ptr, sizeof(image_header_t)); 228 strncpy(hdr->tail.ih_name, namebuf, IH_NMLEN); 229 calc_crc(hdr, ptr+offset_kernel, offset_sqfs - offset_kernel); 230 calc_crc((image_header_t *)ptr, ptr+offset_kernel, offset_image_end - offset_kernel); 231 } else { 232 calc_crc((image_header_t *)ptr, ptr+offset_kernel, offset_sqfs - offset_kernel); 233 } 234 235 if (sbuf.st_size > offset_image_end) 236 (void) munmap((void *)ptr, sbuf.st_size); 237 else 238 (void) munmap((void *)ptr, offset_image_end); 239 240 ftruncate(fd, offset_image_end); 241 (void) close (fd); 242 243 return EXIT_SUCCESS; 244 } 245 246 int 247 main(int argc, char **argv) 248 { 249 int opt; 250 char *filename = NULL; 251 char *progname; 252 op_mode_t opmode = NONE; 253 254 progname = argv[0]; 255 256 while ((opt = getopt(argc, argv,":s:f:h?")) != -1) { 257 switch (opt) { 258 case 's': 259 opmode = SYSUPGRADE; 260 filename = optarg; 261 break; 262 case 'f': 263 opmode = FACTORY; 264 filename = optarg; 265 break; 266 case 'h': 267 opmode = NONE; 268 default: 269 usage(progname, EXIT_FAILURE); 270 opmode = NONE; 271 } 272 } 273 274 if(filename == NULL) 275 opmode = NONE; 276 277 switch (opmode) { 278 case NONE: 279 usage(progname, EXIT_FAILURE); 280 break; 281 case FACTORY: 282 case SYSUPGRADE: 283 return process_image(progname, filename, opmode); 284 break; 285 } 286 287 return EXIT_SUCCESS; 288 } 289 290
This page was automatically generated by LXR 0.3.1. • OpenWrt