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

Sources/firmware-utils/src/oseama.c

  1 // SPDX-License-Identifier: GPL-2.0-or-later
  2 /*
  3  * oseama
  4  *
  5  * Copyright (C) 2016 Rafał Miłecki <zajec5@gmail.com>
  6  */
  7 
  8 #include <byteswap.h>
  9 #include <endian.h>
 10 #include <errno.h>
 11 #include <stdint.h>
 12 #include <stdio.h>
 13 #include <stdlib.h>
 14 #include <string.h>
 15 #include <unistd.h>
 16 
 17 #include "md5.h"
 18 
 19 #if !defined(__BYTE_ORDER)
 20 #error "Unknown byte order"
 21 #endif
 22 
 23 #if __BYTE_ORDER == __BIG_ENDIAN
 24 #define cpu_to_be32(x)  (x)
 25 #define be32_to_cpu(x)  (x)
 26 #define cpu_to_be16(x)  (x)
 27 #define be16_to_cpu(x)  (x)
 28 #elif __BYTE_ORDER == __LITTLE_ENDIAN
 29 #define cpu_to_be32(x)  bswap_32(x)
 30 #define be32_to_cpu(x)  bswap_32(x)
 31 #define cpu_to_be16(x)  bswap_16(x)
 32 #define be16_to_cpu(x)  bswap_16(x)
 33 #else
 34 #error "Unsupported endianness"
 35 #endif
 36 
 37 #define SEAMA_MAGIC                     0x5ea3a417
 38 
 39 struct seama_seal_header {
 40         uint32_t magic;
 41         uint16_t reserved;
 42         uint16_t metasize;
 43         uint32_t imagesize;
 44 } __attribute__ ((packed));
 45 
 46 struct seama_entity_header {
 47         uint32_t magic;
 48         uint16_t reserved;
 49         uint16_t metasize;
 50         uint32_t imagesize;
 51         uint8_t md5[16];
 52 } __attribute__ ((packed));
 53 
 54 char *seama_path;
 55 int entity_idx = -1;
 56 char *out_path;
 57 
 58 static inline size_t oseama_min(size_t x, size_t y) {
 59         return x < y ? x : y;
 60 }
 61 
 62 /**************************************************
 63  * Helpers
 64  **************************************************/
 65 
 66 static FILE *oseama_open(const char *pathname, const char *mode) {
 67         if (strcmp(pathname, "-"))
 68                 return fopen(pathname, mode);
 69 
 70         if (isatty(fileno(stdin))) {
 71                 fprintf(stderr, "Reading from TTY stdin is unsupported\n");
 72                 return NULL;
 73         }
 74 
 75         return stdin;
 76 }
 77 
 78 static int oseama_skip(FILE *fp, size_t length)
 79 {
 80         if (fseek(fp, length, SEEK_CUR)) {
 81                 uint8_t buf[1024];
 82                 size_t bytes;
 83 
 84                 do {
 85                         bytes = fread(buf, 1, oseama_min(sizeof(buf), length), fp);
 86                         if (bytes <= 0)
 87                                 return -EIO;
 88                         length -= bytes;
 89                 } while (length);
 90         }
 91 
 92         return 0;
 93 }
 94 
 95 static void oseama_close(FILE *fp) {
 96         if (fp != stdin)
 97                 fclose(fp);
 98 }
 99 
100 /**************************************************
101  * Info
102  **************************************************/
103 
104 static void oseama_info_parse_options(int argc, char **argv) {
105         int c;
106 
107         while ((c = getopt(argc, argv, "e:")) != -1) {
108                 switch (c) {
109                 case 'e':
110                         entity_idx = atoi(optarg);
111                         break;
112                 }
113         }
114 }
115 
116 static int oseama_info_entities(FILE *seama, size_t *pos) {
117         struct seama_entity_header hdr;
118         size_t bytes, metasize, imagesize;
119         uint8_t buf[1024];
120         char *end, *tmp;
121         int i = 0;
122         int err = 0;
123 
124         while ((bytes = fread(&hdr, 1, sizeof(hdr), seama)) == sizeof(hdr)) {
125                 *pos += bytes;
126 
127                 if (be32_to_cpu(hdr.magic) != SEAMA_MAGIC) {
128                         fprintf(stderr, "Invalid Seama magic: 0x%08x\n", be32_to_cpu(hdr.magic));
129                         err =  -EINVAL;
130                         goto err_out;
131                 }
132                 metasize = be16_to_cpu(hdr.metasize);
133                 imagesize = be32_to_cpu(hdr.imagesize);
134 
135                 if (entity_idx >= 0 && i != entity_idx) {
136                         oseama_skip(seama, metasize + imagesize);
137                         *pos += metasize + imagesize;
138                         i++;
139                         continue;
140                 }
141 
142                 if (metasize >= sizeof(buf)) {
143                         fprintf(stderr, "Too small buffer (%zu B) to read all meta info (%zd B)\n", sizeof(buf), metasize);
144                         err =  -EINVAL;
145                         goto err_out;
146                 }
147 
148                 if (entity_idx < 0)
149                         printf("\n");
150                 printf("Entity offset:\t%ld\n", *pos - sizeof(hdr));
151                 printf("Entity size:\t%zd\n", sizeof(hdr) + metasize + imagesize);
152                 printf("Meta size:\t%zd\n", metasize);
153                 printf("Image size:\t%zd\n", imagesize);
154 
155                 bytes = fread(buf, 1, metasize, seama);
156                 if (bytes != metasize) {
157                         fprintf(stderr, "Couldn't read %zd B of meta\n", metasize);
158                         err =  -EIO;
159                         goto err_out;
160                 }
161                 *pos += bytes;
162 
163                 end = (char *)&buf[metasize - 1];
164                 *end = '\0';
165                 for (tmp = (char *)buf; tmp < end && strlen(tmp); tmp += strlen(tmp) + 1) {
166                         printf("Meta entry:\t%s\n", tmp);
167                 }
168 
169                 oseama_skip(seama, imagesize);
170                 *pos += imagesize;
171                 i++;
172         }
173 
174 err_out:
175         return err;
176 }
177 
178 static int oseama_info(int argc, char **argv) {
179         FILE *seama;
180         struct seama_seal_header hdr;
181         size_t bytes;
182         uint16_t metasize;
183         uint32_t imagesize;
184         uint8_t buf[1024];
185         size_t pos = 0;
186         int err = 0;
187 
188         if (argc < 3) {
189                 fprintf(stderr, "No Seama file passed\n");
190                 err = -EINVAL;
191                 goto out;
192         }
193         seama_path = argv[2];
194 
195         optind = 3;
196         oseama_info_parse_options(argc, argv);
197 
198         seama = oseama_open(seama_path, "r");
199         if (!seama) {
200                 fprintf(stderr, "Couldn't open %s\n", seama_path);
201                 err = -EACCES;
202                 goto out;
203         }
204 
205         bytes = fread(&hdr, 1, sizeof(hdr), seama);
206         if (bytes != sizeof(hdr)) {
207                 fprintf(stderr, "Couldn't read %s header\n", seama_path);
208                 err =  -EIO;
209                 goto err_close;
210         }
211         pos += bytes;
212 
213         metasize = be16_to_cpu(hdr.metasize);
214         imagesize = be32_to_cpu(hdr.imagesize);
215 
216         if (be32_to_cpu(hdr.magic) != SEAMA_MAGIC) {
217                 fprintf(stderr, "Invalid Seama magic: 0x%08x\n", be32_to_cpu(hdr.magic));
218                 err =  -EINVAL;
219                 goto err_close;
220         }
221 
222         if (metasize >= sizeof(buf)) {
223                 fprintf(stderr, "Too small buffer (%zu B) to read all meta info (%d B)\n", sizeof(buf), metasize);
224                 err =  -EINVAL;
225                 goto err_close;
226         }
227 
228         if (imagesize) {
229                 fprintf(stderr, "Invalid Seama image size: 0x%08x (should be 0)\n", imagesize);
230                 err =  -EINVAL;
231                 goto err_close;
232         }
233 
234         bytes = fread(buf, 1, metasize, seama);
235         if (bytes != metasize) {
236                 fprintf(stderr, "Couldn't read %d B of meta\n", metasize);
237                 err =  -EIO;
238                 goto err_close;
239         }
240         pos += bytes;
241 
242         if (entity_idx < 0) {
243                 char *end, *tmp;
244 
245                 printf("Meta size:\t%d\n", metasize);
246                 printf("Image size:\t%d\n", imagesize);
247 
248                 end = (char *)&buf[metasize - 1];
249                 *end = '\0';
250                 for (tmp = (char *)buf; tmp < end && strlen(tmp); tmp += strlen(tmp) + 1) {
251                         printf("Meta entry:\t%s\n", tmp);
252                 }
253         }
254 
255         oseama_info_entities(seama, &pos);
256 
257 err_close:
258         oseama_close(seama);
259 out:
260         return err;
261 }
262 
263 /**************************************************
264  * Create
265  **************************************************/
266 
267 static ssize_t oseama_entity_append_file(FILE *seama, const char *in_path) {
268         FILE *in;
269         size_t bytes;
270         ssize_t length = 0;
271         uint8_t buf[128];
272 
273         in = fopen(in_path, "r");
274         if (!in) {
275                 fprintf(stderr, "Couldn't open %s\n", in_path);
276                 return -EACCES;
277         }
278 
279         while ((bytes = fread(buf, 1, sizeof(buf), in)) > 0) {
280                 if (fwrite(buf, 1, bytes, seama) != bytes) {
281                         fprintf(stderr, "Couldn't write %zu B to %s\n", bytes, seama_path);
282                         length = -EIO;
283                         break;
284                 }
285                 length += bytes;
286         }
287 
288         fclose(in);
289 
290         return length;
291 }
292 
293 static ssize_t oseama_entity_append_zeros(FILE *seama, size_t length) {
294         uint8_t *buf;
295 
296         buf = malloc(length);
297         if (!buf)
298                 return -ENOMEM;
299         memset(buf, 0, length);
300 
301         if (fwrite(buf, 1, length, seama) != length) {
302                 fprintf(stderr, "Couldn't write %zu B to %s\n", length, seama_path);
303                 return -EIO;
304         }
305 
306         return length;
307 }
308 
309 static ssize_t oseama_entity_align(FILE *seama, size_t curr_offset, size_t alignment) {
310         if (curr_offset & (alignment - 1)) {
311                 size_t length = alignment - (curr_offset % alignment);
312 
313                 return oseama_entity_append_zeros(seama, length);
314         }
315 
316         return 0;
317 }
318 
319 static int oseama_entity_write_hdr(FILE *seama, size_t metasize, size_t imagesize) {
320         struct seama_entity_header hdr = {};
321         uint8_t buf[128];
322         size_t length = imagesize;
323         size_t bytes;
324         MD5_CTX ctx;
325 
326         fseek(seama, sizeof(hdr) + metasize, SEEK_SET);
327         MD5_Init(&ctx);
328         while ((bytes = fread(buf, 1, oseama_min(sizeof(buf), length), seama)) > 0) {
329                 MD5_Update(&ctx, buf, bytes);
330                 length -= bytes;
331         }
332         MD5_Final(hdr.md5, &ctx);
333 
334         hdr.magic = cpu_to_be32(SEAMA_MAGIC);
335         hdr.metasize = cpu_to_be16(metasize);
336         hdr.imagesize = cpu_to_be32(imagesize);
337 
338         fseek(seama, 0, SEEK_SET);
339         bytes = fwrite(&hdr, 1, sizeof(hdr), seama);
340         if (bytes != sizeof(hdr)) {
341                 fprintf(stderr, "Couldn't write Seama entity header to %s\n", seama_path);
342                 return -EIO;
343         }
344 
345         return 0;
346 }
347 
348 static int oseama_entity(int argc, char **argv) {
349         FILE *seama;
350         ssize_t sbytes;
351         size_t curr_offset = sizeof(struct seama_entity_header);
352         size_t metasize = 0, imagesize = 0;
353         int c;
354         int err = 0;
355 
356         if (argc < 3) {
357                 fprintf(stderr, "No Seama file passed\n");
358                 err = -EINVAL;
359                 goto out;
360         }
361         seama_path = argv[2];
362 
363         seama = fopen(seama_path, "w+");
364         if (!seama) {
365                 fprintf(stderr, "Couldn't open %s\n", seama_path);
366                 err = -EACCES;
367                 goto out;
368         }
369         fseek(seama, curr_offset, SEEK_SET);
370 
371         optind = 3;
372         while ((c = getopt(argc, argv, "m:f:b:")) != -1) {
373                 switch (c) {
374                 case 'm':
375                         sbytes = fwrite(optarg, 1, strlen(optarg) + 1, seama);
376                         if (sbytes < 0) {
377                                 fprintf(stderr, "Failed to write meta %s\n", optarg);
378                         } else {
379                                 curr_offset += sbytes;
380                                 metasize += sbytes;
381                         }
382 
383                         sbytes = oseama_entity_align(seama, curr_offset, 4);
384                         if (sbytes < 0) {
385                                 fprintf(stderr, "Failed to append zeros\n");
386                         } else {
387                                 curr_offset += sbytes;
388                                 metasize += sbytes;
389                         }
390 
391                         break;
392                 case 'f':
393                 case 'b':
394                         break;
395                 }
396         }
397 
398         optind = 3;
399         while ((c = getopt(argc, argv, "m:f:b:")) != -1) {
400                 switch (c) {
401                 case 'm':
402                         break;
403                 case 'f':
404                         sbytes = oseama_entity_append_file(seama, optarg);
405                         if (sbytes < 0) {
406                                 fprintf(stderr, "Failed to append file %s\n", optarg);
407                         } else {
408                                 curr_offset += sbytes;
409                                 imagesize += sbytes;
410                         }
411                         break;
412                 case 'b':
413                         sbytes = strtol(optarg, NULL, 0) - curr_offset;
414                         if (sbytes < 0) {
415                                 fprintf(stderr, "Current Seama entity length is 0x%zx, can't pad it with zeros to 0x%lx\n", curr_offset, strtol(optarg, NULL, 0));
416                         } else {
417                                 sbytes = oseama_entity_append_zeros(seama, sbytes);
418                                 if (sbytes < 0) {
419                                         fprintf(stderr, "Failed to append zeros\n");
420                                 } else {
421                                         curr_offset += sbytes;
422                                         imagesize += sbytes;
423                                 }
424                         }
425                         break;
426                 }
427                 if (err)
428                         break;
429         }
430 
431         oseama_entity_write_hdr(seama, metasize, imagesize);
432 
433         fclose(seama);
434 out:
435         return err;
436 }
437 
438 /**************************************************
439  * Extract
440  **************************************************/
441 
442 static void oseama_extract_parse_options(int argc, char **argv) {
443         int c;
444 
445         while ((c = getopt(argc, argv, "e:o:")) != -1) {
446                 switch (c) {
447                 case 'e':
448                         entity_idx = atoi(optarg);
449                         break;
450                 case 'o':
451                         out_path = optarg;
452                         break;
453                 }
454         }
455 }
456 
457 static int oseama_extract_entity(FILE *seama, FILE *out) {
458         struct seama_entity_header hdr;
459         size_t bytes, metasize, imagesize, length;
460         uint8_t buf[1024];
461         int i = 0;
462         int err = 0;
463 
464         while ((bytes = fread(&hdr, 1, sizeof(hdr), seama)) == sizeof(hdr)) {
465                 if (be32_to_cpu(hdr.magic) != SEAMA_MAGIC) {
466                         fprintf(stderr, "Invalid Seama magic: 0x%08x\n", be32_to_cpu(hdr.magic));
467                         err =  -EINVAL;
468                         break;
469                 }
470                 metasize = be16_to_cpu(hdr.metasize);
471                 imagesize = be32_to_cpu(hdr.imagesize);
472 
473                 if (i != entity_idx) {
474                         oseama_skip(seama, metasize + imagesize);
475                         i++;
476                         continue;
477                 }
478 
479                 if (fwrite(&hdr, 1, sizeof(hdr), out) != sizeof(hdr)) {
480                         fprintf(stderr, "Couldn't write %zu B to %s\n", sizeof(hdr), out_path);
481                         err = -EIO;
482                         break;
483                 }
484 
485                 length = metasize + imagesize;
486                 while ((bytes = fread(buf, 1, oseama_min(sizeof(buf), length), seama)) > 0) {
487                         if (fwrite(buf, 1, bytes, out) != bytes) {
488                                 fprintf(stderr, "Couldn't write %zu B to %s\n", bytes, out_path);
489                                 err = -EIO;
490                                 break;
491                         }
492                         length -= bytes;
493                 }
494 
495                 if (length) {
496                         fprintf(stderr, "Couldn't extract whole entity %d from %s (%zu B left)\n", entity_idx, seama_path, length);
497                         err = -EIO;
498                         break;
499                 }
500 
501                 break;
502         }
503 
504         return err;
505 }
506 
507 static int oseama_extract(int argc, char **argv) {
508         FILE *seama;
509         FILE *out;
510         struct seama_seal_header hdr;
511         size_t bytes;
512         uint16_t metasize;
513         int err = 0;
514 
515         if (argc < 3) {
516                 fprintf(stderr, "No Seama file passed\n");
517                 err = -EINVAL;
518                 goto out;
519         }
520         seama_path = argv[2];
521 
522         optind = 3;
523         oseama_extract_parse_options(argc, argv);
524         if (entity_idx < 0) {
525                 fprintf(stderr, "No entity specified\n");
526                 err = -EINVAL;
527                 goto out;
528         }
529 
530         seama = oseama_open(seama_path, "r");
531         if (!seama) {
532                 fprintf(stderr, "Couldn't open %s\n", seama_path);
533                 err = -EACCES;
534                 goto out;
535         }
536 
537         if (out_path) {
538                 out = fopen(out_path, "w");
539                 if (!out) {
540                         fprintf(stderr, "Couldn't open %s\n", out_path);
541                         err = -EACCES;
542                         goto err_close_seama;
543                 }
544         } else {
545                 out = stdout;
546         }
547 
548         bytes = fread(&hdr, 1, sizeof(hdr), seama);
549         if (bytes != sizeof(hdr)) {
550                 fprintf(stderr, "Couldn't read %s header\n", seama_path);
551                 err =  -EIO;
552                 goto err_close_out;
553         }
554         metasize = be16_to_cpu(hdr.metasize);
555 
556         oseama_skip(seama, metasize);
557 
558         oseama_extract_entity(seama, out);
559 
560 err_close_out:
561         if (out != stdout)
562                 fclose(out);
563 err_close_seama:
564         oseama_close(seama);
565 out:
566         return err;
567 }
568 
569 /**************************************************
570  * Start
571  **************************************************/
572 
573 static void usage() {
574         printf("Usage:\n");
575         printf("\n");
576         printf("Info about Seama seal (container):\n");
577         printf("\toseama info <file> [options]\n");
578         printf("\t-e\t\t\t\tprint info about specified entity only\n");
579         printf("\n");
580         printf("Create Seama entity:\n");
581         printf("\toseama entity <file> [options]\n");
582         printf("\t-m meta\t\t\t\tmeta into to put in header\n");
583         printf("\t-f file\t\t\t\tappend content from file\n");
584         printf("\t-b offset\t\t\tappend zeros till reaching absolute offset\n");
585         printf("\n");
586         printf("Extract from Seama seal (container):\n");
587         printf("\toseama extract <file> [options]\n");
588         printf("\t-e\t\t\t\tindex of entity to extract\n");
589         printf("\t-o file\t\t\t\toutput file\n");
590 }
591 
592 int main(int argc, char **argv) {
593         if (argc > 1) {
594                 if (!strcmp(argv[1], "info"))
595                         return oseama_info(argc, argv);
596                 else if (!strcmp(argv[1], "entity"))
597                         return oseama_entity(argc, argv);
598                 else if (!strcmp(argv[1], "extract"))
599                         return oseama_extract(argc, argv);
600         }
601 
602         usage();
603         return 0;
604 }
605 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt