• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/firmware-utils/src/seama.c

  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