1 // SPDX-License-Identifier: BSD-3-Clause 2 /* vi: set sw=4 ts=4: */ 3 /* 4 * Copyright (C) 2008, Alpha Networks, Inc. 5 * Created by David Hsieh <david_hsieh@alphanetworks.com> 6 * All right reserved. 7 * 8 * (SEA)ttle i(MA)ge is the image which used in project seattle. 9 */ 10 11 #include <stdio.h> 12 #include <stdint.h> 13 #include <stdlib.h> 14 #include <stdarg.h> 15 #include <sys/types.h> 16 #include <sys/stat.h> 17 #include <unistd.h> 18 #include <string.h> 19 #include <arpa/inet.h> 20 21 #include "md5.h" 22 #include "seama.h" 23 24 #define PROGNAME "seama" 25 #define VERSION "0.20" 26 #define MAX_SEAMA_META_SIZE 1024 27 #define MAX_META 128 28 #define MAX_IMAGE 128 29 30 extern int optind; 31 extern char * optarg; 32 33 static int o_verbose = 0; /* verbose mode. */ 34 static char * o_dump = NULL; /* Seama file to dump. */ 35 static char * o_seal = NULL; /* Seal the input images when file name exist. */ 36 static char * o_extract = NULL; /* Extract the seama file. */ 37 static char * o_images[MAX_IMAGE];/* The image files to pack or seal */ 38 static int o_isize = 0; /* number of images */ 39 static char * o_meta[MAX_META]; /* meta data array */ 40 static int o_msize = 0; /* size of meta array */ 41 42 static void verbose(const char * format, ...) 43 { 44 va_list marker; 45 if (o_verbose) 46 { 47 va_start(marker, format); 48 vfprintf(stdout, format, marker); 49 va_end(marker); 50 } 51 } 52 53 static void cleanup_exit(int exit_code) 54 { 55 verbose("%s: exit with code %d\n", PROGNAME, exit_code); 56 exit(exit_code); 57 } 58 59 static void show_usage(int exit_code) 60 { 61 printf( PROGNAME " version " VERSION "\n" 62 "usage: " PROGNAME " [OPTIONS]\n" 63 " -h show this help message.\n" 64 " -v verbose mode.\n" 65 " -m {META data} META data.\n" 66 " -d {file} dump the info of the seama file.\n" 67 " -i {input file} image file name.\n" 68 " -s {file} Seal the images to the seama file.\n" 69 " -x {seama file} Extract the seama file.\n" 70 "\n" 71 " SEAMA can pack the input file (with -i) into a seama file.\n" 72 " ex: seama -i target.file\n" 73 " SEAMA can also seal multiple seama files into a single seama file.\n" 74 " ex: seama -s final.file -i taget1.seama -i target2.seama\n" 75 " To extract the raw image from SEAMA, you need to specify the meta.\n" 76 " The first image match the specified meta will be extract to\n" 77 " the output file which was specified with '-x'.\n" 78 " ex: seama -x output -i seama.image -m file=sealpac\n" 79 ); 80 cleanup_exit(exit_code); 81 } 82 83 static int parse_args(int argc, char * argv[]) 84 { 85 int opt; 86 87 while ((opt = getopt(argc, argv, "hvd:s:i:m:x:")) > 0) 88 { 89 switch (opt) 90 { 91 default: show_usage(-1); break; 92 case 'h': show_usage(0); break; 93 case 'v': o_verbose++; break; 94 case 'd': o_dump = optarg; break; 95 case 's': o_seal = optarg; break; 96 case 'x': o_extract = optarg; break; 97 case 'i': 98 if (o_isize < MAX_IMAGE) o_images[o_isize++] = optarg; 99 else printf("Exceed the maximum acceptable image files.!\n"); 100 break; 101 case 'm': 102 if (o_msize < MAX_META) o_meta[o_msize++] = optarg; 103 else printf("Exceed the maximum acceptable META data.!\n"); 104 break; 105 } 106 } 107 return 0; 108 } 109 110 /*******************************************************************/ 111 112 static size_t calculate_digest(FILE * fh, size_t size, uint8_t * digest) 113 { 114 MD5_CTX ctx; 115 size_t bytes_left, bytes_read, i; 116 uint8_t buf[MAX_SEAMA_META_SIZE]; 117 118 bytes_left = size ? size : sizeof(buf); 119 bytes_read = 0; 120 121 MD5_Init(&ctx); 122 while (!feof(fh) && !ferror(fh) && bytes_left > 0) 123 { 124 i = bytes_left < sizeof(buf) ? bytes_left : sizeof(buf); 125 i = fread(buf, sizeof(char), i, fh); 126 if (i > 0) 127 { 128 MD5_Update(&ctx, buf, i); 129 bytes_read += i; 130 } 131 if (size) bytes_left -= i; 132 } 133 MD5_Final(digest, &ctx); 134 return bytes_read; 135 } 136 137 #define READ_BUFF_SIZE 8*1024 138 static size_t copy_file(FILE * to, FILE * from) 139 { 140 size_t i, fsize = 0; 141 uint8_t buf[READ_BUFF_SIZE]; 142 143 while (!feof(from) && !ferror(from)) 144 { 145 i = fread(buf, sizeof(uint8_t), READ_BUFF_SIZE, from); 146 if (i > 0) 147 { 148 fsize += i; 149 fwrite(buf, sizeof(uint8_t), i, to); 150 } 151 } 152 return fsize; 153 } 154 155 static int verify_seama(const char * fname, int msg) 156 { 157 FILE * fh = NULL; 158 struct stat st; 159 seamahdr_t shdr; 160 uint8_t checksum[16]; 161 uint8_t digest[16]; 162 uint8_t buf[MAX_SEAMA_META_SIZE]; 163 size_t msize, isize, i; 164 int ret = -1; 165 166 #define ERRBREAK(fmt, args...) { if (msg) printf(fmt, ##args); break; } 167 168 do 169 { 170 if (stat(fname, &st) < 0) ERRBREAK("Unable to get the info of '%s'\n",fname); 171 if ((fh = fopen(fname, "r+"))==NULL) ERRBREAK("Unable to open '%s' for reading!\n",fname); 172 173 /* Dump SEAMA header */ 174 if (msg) printf("FILE - %s (%d bytes)\n", fname, (int)st.st_size); 175 176 /* SEAMA */ 177 while (!feof(fh) && !ferror(fh)) 178 { 179 /* read header */ 180 if (fread(&shdr, sizeof(shdr), 1, fh) != 1) break; 181 182 /* Check the magic number */ 183 if (shdr.magic != htonl(SEAMA_MAGIC)) ERRBREAK("Invalid SEAMA magic. Probably no more SEAMA!\n"); 184 185 /* Get the size */ 186 isize = ntohl(shdr.size); 187 msize = ntohs(shdr.metasize); 188 189 /* The checksum exist only if size is greater than zero. */ 190 if (isize > 0) 191 { 192 if (fread(checksum, sizeof(checksum), 1, fh) != 1) 193 ERRBREAK("Error reading checksum !\n"); 194 } 195 196 /* Check the META size. */ 197 if (msize > sizeof(buf)) ERRBREAK("META data in SEAMA header is too large!\n"); 198 199 /* Read META data. */ 200 if (fread(buf, sizeof(char), msize, fh) != msize) 201 ERRBREAK("Unable to read SEAMA META data!\n"); 202 203 /* dump header */ 204 if (msg) 205 { 206 printf("SEAMA ==========================================\n"); 207 printf(" magic : %08x\n", ntohl(shdr.magic)); 208 printf(" meta size : %zu bytes\n", msize); 209 for (i=0; i<msize; i+=(strlen((const char *)&buf[i])+1)) 210 printf(" meta data : %s\n", &buf[i]); 211 printf(" image size : %zu bytes\n", isize); 212 } 213 214 /* verify checksum */ 215 if (isize > 0) 216 { 217 if (msg) 218 { 219 printf(" checksum : "); 220 for (i=0; i<16; i++) printf("%02X", checksum[i]); 221 printf("\n"); 222 } 223 224 /* Calculate the checksum */ 225 calculate_digest(fh, isize, digest); 226 if (msg) 227 { 228 printf(" digest : "); 229 for (i=0; i<16; i++) printf("%02X", digest[i]); 230 printf("\n"); 231 } 232 233 if (memcmp(checksum, digest, 16)!=0) ERRBREAK("!!ERROR!! checksum error !!\n"); 234 ret = 0; 235 } 236 } 237 if (msg) printf("================================================\n"); 238 } while (0); 239 if (fh) fclose(fh); 240 return ret; 241 } 242 243 static size_t write_seama_header(FILE * fh, char * meta[], size_t msize, size_t size) 244 { 245 seamahdr_t shdr; 246 size_t i; 247 uint16_t metasize = 0; 248 249 /* Calculate the META size */ 250 for (i=0; i<msize; i++) metasize += (strlen(meta[i]) + 1); 251 //+++ let meta data end on 4 alignment by siyou. 2010/3/1 03:58pm 252 metasize = ((metasize+3)/4)*4; 253 verbose("SEAMA META : %d bytes\n", metasize); 254 255 /* Fill up the header, all the data endian should be network byte order. */ 256 shdr.magic = htonl(SEAMA_MAGIC); 257 shdr.reserved = 0; 258 shdr.metasize = htons(metasize); 259 shdr.size = htonl(size); 260 261 /* Write the header */ 262 return fwrite(&shdr, sizeof(seamahdr_t), 1, fh); 263 } 264 265 static size_t write_checksum(FILE * fh, uint8_t * checksum) 266 { 267 return fwrite(checksum, sizeof(uint8_t), 16, fh); 268 } 269 270 static size_t write_meta_data(FILE * fh, char * meta[], size_t size) 271 { 272 size_t i,j; 273 size_t ret = 0; 274 275 for (i=0; i<size; i++) 276 { 277 verbose("SEAMA META data : %s\n", meta[i]); 278 j = fwrite(meta[i], sizeof(char), strlen(meta[i])+1, fh); 279 if (j != strlen(meta[i])+1) return 0; 280 ret += j; 281 } 282 //+++ let meta data end on 4 alignment by siyou. 2010/3/1 03:58pm 283 j = ((ret+3)/4)*4; 284 for ( ; ret < j; ret++) 285 fwrite("", sizeof(char), 1, fh); 286 287 return ret; 288 } 289 290 /*******************************************************************/ 291 292 static void dump_seama(const char * fname) 293 { 294 verify_seama(fname, 1); 295 } 296 297 static void seal_files(const char * file) 298 { 299 FILE * fh; 300 FILE * ifh; 301 size_t i; 302 303 /* Each image should be seama. */ 304 for (i = 0; i < o_isize; i++) 305 { 306 if (verify_seama(o_images[i], 0) < 0) 307 { 308 printf("'%s' is not a seama file !\n",o_images[i]); 309 return; 310 } 311 } 312 313 /* Open file for write */ 314 fh = fopen(file, "w+"); 315 if (fh) 316 { 317 /* Write the header. */ 318 write_seama_header(fh, o_meta, o_msize, 0); 319 write_meta_data(fh, o_meta, o_msize); 320 321 /* Write image files */ 322 for (i=0; i<o_isize; i++) 323 { 324 ifh = fopen(o_images[i], "r+"); 325 if (ifh) 326 { 327 copy_file(fh, ifh); 328 fclose(ifh); 329 } 330 } 331 332 fclose(fh); 333 } 334 } 335 336 static void pack_files(void) 337 { 338 FILE * fh; 339 FILE * ifh; 340 size_t i, fsize; 341 char filename[512]; 342 uint8_t digest[16]; 343 344 for (i=0; i<o_isize; i++) 345 { 346 /* Open the input file. */ 347 ifh = fopen(o_images[i], "r+"); 348 if (ifh) 349 { 350 fsize = calculate_digest(ifh, 0, digest); 351 verbose("file size (%s) : %d\n", o_images[i], fsize); 352 rewind(ifh); 353 354 /* Open the output file. */ 355 sprintf(filename, "%s.seama", o_images[i]); 356 fh = fopen(filename, "w+"); 357 if (fh) 358 { 359 write_seama_header(fh, o_meta, o_msize, fsize); 360 write_checksum(fh, digest); 361 write_meta_data(fh, o_meta, o_msize); 362 copy_file(fh, ifh); 363 fclose(fh); 364 } 365 fclose(ifh); 366 } 367 else 368 { 369 printf("Unable to open image file '%s'\n",o_images[i]); 370 } 371 } 372 } 373 374 /**************************************************************************/ 375 376 static int match_meta(const char * meta, size_t size) 377 { 378 size_t i, j; 379 int match; 380 381 for (i = 0; i < o_msize; i++) 382 { 383 for (match = 0, j = 0; j < size; j += (strlen(&meta[j])+1)) 384 if (strcmp(&meta[j], o_meta[i])==0) { match++; break; } 385 if (!match) return 0; 386 } 387 return 1; 388 } 389 390 391 static void extract_file(const char * output) 392 { 393 FILE * ifh = NULL; 394 FILE * ofh = NULL; 395 size_t msize, isize, i, m; 396 seamahdr_t shdr; 397 uint8_t buf[MAX_SEAMA_META_SIZE]; 398 int done = 0; 399 400 /* We need meta for searching the target image. */ 401 if (o_msize == 0) 402 { 403 printf("SEAMA: need meta for searching image.\n"); 404 return; 405 } 406 407 /* Walk through each input file */ 408 for (i = 0; i < o_isize; i++) 409 { 410 /* verify the input file */ 411 if (verify_seama(o_images[i], 0) < 0) 412 { 413 printf("SEAMA: '%s' is not a seama file !\n", o_images[i]); 414 continue; 415 } 416 /* open the input file */ 417 ifh = fopen(o_images[i], "r"); 418 if (!ifh) continue; 419 /* read file */ 420 while (!feof(ifh) && !ferror(ifh)) 421 { 422 /* read header */ 423 fread(&shdr, sizeof(shdr), 1, ifh); 424 if (shdr.magic != htonl(SEAMA_MAGIC)) break; 425 /* Get the size */ 426 isize = ntohl(shdr.size); 427 msize = ntohs(shdr.metasize); 428 if (isize == 0) 429 { 430 while (msize > 0) 431 { 432 m = fread(buf, sizeof(char), (msize < MAX_SEAMA_META_SIZE) ? msize : MAX_SEAMA_META_SIZE, ifh); 433 if (m <= 0) break; 434 msize -= m; 435 } 436 continue; 437 } 438 /* read checksum */ 439 fread(buf, sizeof(char), 16, ifh); 440 if (msize > 0) 441 { 442 /* read META */ 443 fread(buf, sizeof(char), msize, ifh); 444 if (match_meta((const char *)buf, msize)) 445 { 446 printf("SEAMA: found image @ '%s', image size: %zu\n", o_images[i], isize); 447 /* open output file */ 448 ofh = fopen(output, "w"); 449 if (!ofh) printf("SEAMA: unable to open '%s' for writting.\n",output); 450 else 451 { 452 while (isize > 0) 453 { 454 m = fread(buf, sizeof(char), (isize < MAX_SEAMA_META_SIZE) ? isize : MAX_SEAMA_META_SIZE, ifh); 455 if (m <= 0) break; 456 fwrite(buf, sizeof(char), m, ofh); 457 isize -= m; 458 } 459 fclose(ofh); 460 } 461 done++; 462 break; 463 } 464 } 465 while (isize > 0) 466 { 467 m = fread(buf, sizeof(char), (isize < MAX_SEAMA_META_SIZE) ? isize : MAX_SEAMA_META_SIZE, ifh); 468 if (m <= 0) break; 469 isize -= m; 470 } 471 } 472 /* close the file. */ 473 fclose(ifh); 474 if (done) break; 475 } 476 return; 477 } 478 479 /*******************************************************************/ 480 #ifdef RGBIN_BOX 481 int seama_main(int argc, char * argv[], char * env[]) 482 #else 483 int main(int argc, char * argv[], char * env[]) 484 #endif 485 { 486 verbose("SEAMA version " VERSION "\n"); 487 488 /* parse the arguments */ 489 if (parse_args(argc, argv) < 0) show_usage(9); 490 491 /* Do the works */ 492 if (o_dump) dump_seama(o_dump); 493 else if (o_seal) seal_files(o_seal); 494 else if (o_extract) extract_file(o_extract); 495 else pack_files(); 496 497 cleanup_exit(0); 498 return 0; 499 } 500
This page was automatically generated by LXR 0.3.1. • OpenWrt