1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2012 Gabor Juhos <juhosg@openwrt.org> 4 */ 5 6 #include <stdio.h> 7 #include <stdlib.h> 8 #include <stdint.h> 9 #include <string.h> 10 #include <unistd.h> /* for unlink() */ 11 #include <libgen.h> 12 #include <getopt.h> /* for getopt() */ 13 #include <stdarg.h> 14 #include <errno.h> 15 #include <sys/stat.h> 16 17 #include <arpa/inet.h> 18 #include <netinet/in.h> 19 20 #define MAX_MODEL_LEN 20 21 #define MAX_SIGNATURE_LEN 30 22 #define MAX_REGION_LEN 4 23 #define MAX_VERSION_LEN 12 24 25 #define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f)) 26 27 struct file_info { 28 char *file_name; /* name of the file */ 29 uint32_t file_size; /* length of the file */ 30 uint32_t write_size; 31 }; 32 33 struct img_header { 34 uint32_t checksum; 35 uint32_t image_size; 36 uint32_t kernel_size; 37 char model[MAX_MODEL_LEN]; 38 char signature[MAX_SIGNATURE_LEN]; 39 char region[MAX_REGION_LEN]; 40 char version[MAX_VERSION_LEN]; 41 unsigned char header_len; 42 unsigned char is_tgz; 43 unsigned char pad[4]; 44 } __attribute__ ((packed)); 45 46 /* 47 * Globals 48 */ 49 static char *ofname; 50 static char *progname; 51 52 static char *model; 53 static char *signature; 54 static char *region = "DEF"; 55 static char *version; 56 static struct file_info kernel_info; 57 static struct file_info rootfs_info; 58 static uint32_t kernel_size; 59 static uint32_t image_size; 60 static int combined; 61 62 /* 63 * Message macros 64 */ 65 #define ERR(fmt, ...) do { \ 66 fflush(0); \ 67 fprintf(stderr, "[%s] *** error: " fmt "\n", \ 68 progname, ## __VA_ARGS__ ); \ 69 } while (0) 70 71 #define ERRS(fmt, ...) do { \ 72 int save = errno; \ 73 fflush(0); \ 74 fprintf(stderr, "[%s] *** error: " fmt " (%s)\n", \ 75 progname, ## __VA_ARGS__, strerror(save)); \ 76 } while (0) 77 78 #define DBG(fmt, ...) do { \ 79 fprintf(stderr, "[%s] " fmt "\n", progname, ## __VA_ARGS__ ); \ 80 } while (0) 81 82 static void usage(int status) 83 { 84 FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout; 85 86 fprintf(stream, "Usage: %s [OPTIONS...]\n", progname); 87 fprintf(stream, 88 "\n" 89 "Options:\n" 90 " -k <file> read kernel image from the file <file>\n" 91 " -c use the kernel image as a combined image\n" 92 " -M <model> set model to <model>\n" 93 " -o <file> write output to the file <file>\n" 94 " -r <file> read rootfs image from the file <file>\n" 95 " -S <signature> set image signature to <signature>\n" 96 " -R <region> set image region to <region>\n" 97 " -V <version> set image version to <version>\n" 98 " -I <size> set image size to <size>\n" 99 " -K <size> set kernel size to <size>\n" 100 " -h show this screen\n" 101 ); 102 103 exit(status); 104 } 105 106 int 107 str2u32(char *arg, uint32_t *val) 108 { 109 char *err = NULL; 110 uint32_t t; 111 112 errno=0; 113 t = strtoul(arg, &err, 0); 114 if (errno || (err==arg) || ((err != NULL) && *err)) { 115 return -1; 116 } 117 118 *val = t; 119 return 0; 120 } 121 122 static int get_file_stat(struct file_info *fdata) 123 { 124 struct stat st; 125 int res; 126 127 if (fdata->file_name == NULL) 128 return 0; 129 130 res = stat(fdata->file_name, &st); 131 if (res){ 132 ERRS("stat failed on %s", fdata->file_name); 133 return res; 134 } 135 136 fdata->file_size = st.st_size; 137 fdata->write_size = fdata->file_size; 138 return 0; 139 } 140 141 static int read_to_buf(struct file_info *fdata, char *buf) 142 { 143 FILE *f; 144 int ret = EXIT_FAILURE; 145 146 f = fopen(fdata->file_name, "r"); 147 if (f == NULL) { 148 ERRS("could not open \"%s\" for reading", fdata->file_name); 149 goto out; 150 } 151 152 errno = 0; 153 fread(buf, fdata->file_size, 1, f); 154 if (errno != 0) { 155 ERRS("unable to read from file \"%s\"", fdata->file_name); 156 goto out_close; 157 } 158 159 ret = EXIT_SUCCESS; 160 161 out_close: 162 fclose(f); 163 out: 164 return ret; 165 } 166 167 static int check_options(void) 168 { 169 int ret; 170 171 #define CHKSTR(_name, _msg) \ 172 do { \ 173 if (_name == NULL) { \ 174 ERR("no %s specified", _msg); \ 175 return -1; \ 176 } \ 177 } while (0) 178 179 #define CHKSTRLEN(_name, _msg) \ 180 do { \ 181 int field_len; \ 182 CHKSTR(_name, _msg); \ 183 field_len = FIELD_SIZEOF(struct img_header, _name) - 1; \ 184 if (strlen(_name) > field_len) { \ 185 ERR("%s is too long, max length is %d", \ 186 _msg, field_len); \ 187 return -1; \ 188 } \ 189 } while (0) 190 191 CHKSTRLEN(model, "model"); 192 CHKSTRLEN(signature, "signature"); 193 CHKSTRLEN(region, "region"); 194 CHKSTRLEN(version, "version"); 195 CHKSTR(ofname, "output file"); 196 CHKSTR(kernel_info.file_name, "kernel image"); 197 198 ret = get_file_stat(&kernel_info); 199 if (ret) 200 return ret; 201 202 if (combined) { 203 if (!kernel_size) { 204 ERR("kernel size must be specified for combined images"); 205 return -1; \ 206 } 207 208 if (!image_size) 209 image_size = kernel_info.file_size; 210 211 if (kernel_info.file_size > image_size) { 212 ERR("kernel image is too big"); 213 return -1; 214 } 215 216 kernel_info.write_size = image_size; 217 } else { 218 CHKSTR(rootfs_info.file_name, "rootfs image"); 219 220 ret = get_file_stat(&rootfs_info); 221 if (ret) 222 return ret; 223 224 if (kernel_size) { 225 /* override kernel size */ 226 kernel_info.write_size = kernel_size; 227 } 228 229 if (image_size) { 230 if (image_size < kernel_info.write_size) 231 kernel_info.write_size = image_size; 232 233 /* override rootfs size */ 234 rootfs_info.write_size = image_size - kernel_info.write_size; 235 } 236 237 if (kernel_info.file_size > kernel_info.write_size) { 238 ERR("kernel image is too big"); 239 return -1; 240 } 241 242 if (rootfs_info.file_size > rootfs_info.write_size) { 243 ERR("rootfs image is too big"); 244 return -1; 245 } 246 } 247 248 return 0; 249 } 250 251 static int write_fw(char *data, int len) 252 { 253 FILE *f; 254 int ret = EXIT_FAILURE; 255 256 f = fopen(ofname, "w"); 257 if (f == NULL) { 258 ERRS("could not open \"%s\" for writing", ofname); 259 goto out; 260 } 261 262 errno = 0; 263 fwrite(data, len, 1, f); 264 if (errno) { 265 ERRS("unable to write output file"); 266 goto out_flush; 267 } 268 269 DBG("firmware file \"%s\" completed", ofname); 270 271 ret = EXIT_SUCCESS; 272 273 out_flush: 274 fflush(f); 275 fclose(f); 276 if (ret != EXIT_SUCCESS) { 277 unlink(ofname); 278 } 279 out: 280 return ret; 281 } 282 283 static uint32_t get_csum(unsigned char *p, uint32_t len) 284 { 285 uint32_t csum = 0; 286 287 while (len--) 288 csum += *p++; 289 290 return csum; 291 } 292 293 static int build_fw(void) 294 { 295 int buflen; 296 char *buf; 297 char *p; 298 uint32_t csum; 299 struct img_header *hdr; 300 int ret = EXIT_FAILURE; 301 302 buflen = sizeof(struct img_header) + 303 kernel_info.write_size + rootfs_info.write_size; 304 305 buf = malloc(buflen); 306 if (!buf) { 307 ERR("no memory for buffer\n"); 308 goto out; 309 } 310 311 memset(buf, 0, buflen); 312 313 p = buf + sizeof(struct img_header); 314 315 /* read kernel data */ 316 ret = read_to_buf(&kernel_info, p); 317 if (ret) 318 goto out_free_buf; 319 320 if (!combined) { 321 p += kernel_info.write_size; 322 323 /* read rootfs data */ 324 ret = read_to_buf(&rootfs_info, p); 325 if (ret) 326 goto out_free_buf; 327 } 328 329 csum = get_csum((unsigned char *)(buf + sizeof(struct img_header)), 330 buflen - sizeof(struct img_header)); 331 332 /* fill firmware header */ 333 hdr = (struct img_header *) buf; 334 335 hdr->checksum = htonl(csum); 336 hdr->image_size = htonl(buflen - sizeof(struct img_header)); 337 if (!combined) 338 hdr->kernel_size = htonl(kernel_info.write_size); 339 else 340 hdr->kernel_size = htonl(kernel_size); 341 hdr->header_len = sizeof(struct img_header); 342 strncpy(hdr->model, model, sizeof(hdr->model)); 343 strncpy(hdr->signature, signature, sizeof(hdr->signature)); 344 strncpy(hdr->version, version, sizeof(hdr->version)); 345 strncpy(hdr->region, region, sizeof(hdr->region)); 346 347 ret = write_fw(buf, buflen); 348 if (ret) 349 goto out_free_buf; 350 351 ret = EXIT_SUCCESS; 352 353 out_free_buf: 354 free(buf); 355 out: 356 return ret; 357 } 358 359 int main(int argc, char *argv[]) 360 { 361 int ret = EXIT_FAILURE; 362 363 progname = basename(argv[0]); 364 365 while (1) { 366 int c; 367 368 c = getopt(argc, argv, "M:S:V:R:k:K:I:r:o:hc"); 369 if (c == -1) 370 break; 371 372 switch (c) { 373 case 'M': 374 model = optarg; 375 break; 376 case 'S': 377 signature = optarg; 378 break; 379 case 'V': 380 version = optarg; 381 break; 382 case 'R': 383 region = optarg; 384 break; 385 case 'k': 386 kernel_info.file_name = optarg; 387 break; 388 case 'K': 389 if (str2u32(optarg, &kernel_size)) { 390 ERR("%s is invalid '%s'", 391 "kernel size", optarg); 392 goto out; 393 } 394 break; 395 case 'I': 396 if (str2u32(optarg, &image_size)) { 397 ERR("%s is invalid '%s'", 398 "image size", optarg); 399 goto out; 400 } 401 break; 402 case 'r': 403 rootfs_info.file_name = optarg; 404 break; 405 case 'c': 406 combined = 1; 407 break; 408 case 'o': 409 ofname = optarg; 410 break; 411 case 'h': 412 usage(EXIT_SUCCESS); 413 break; 414 default: 415 usage(EXIT_FAILURE); 416 break; 417 } 418 } 419 420 ret = check_options(); 421 if (ret) 422 goto out; 423 424 ret = build_fw(); 425 426 out: 427 return ret; 428 } 429 430
This page was automatically generated by LXR 0.3.1. • OpenWrt