libnet: Correctly re-initialize the "ip_version" variable each time
[SLOF.git] / tools / sloffs.c
1 /******************************************************************************
2 * Copyright (c) 2008, 2009 Adrian Reber
3 * All rights reserved.
4 * This program and the accompanying materials
5 * are made available under the terms of the BSD License
6 * which accompanies this distribution, and is available at
7 * http://www.opensource.org/licenses/bsd-license.php
8 *
9 * Contributors:
10 * Adrian Reber - initial implementation
11 *****************************************************************************/
12
13 #include <stdint.h>
14 #include <stdio.h>
15 #include <sys/types.h>
16 #include <sys/stat.h>
17 #include <unistd.h>
18 #include <sys/mman.h>
19 #include <fcntl.h>
20 #include <string.h>
21 #include <stdlib.h>
22 #include <byteswap.h>
23 #include <getopt.h>
24 #include <time.h>
25
26 #include <calculatecrc.h>
27 #include <crclib.h>
28
29 #define VERSION 1
30
31 #ifdef _BIG_ENDIAN
32 #define cpu_to_be64(x) (x)
33 #define be64_to_cpu(x) (x)
34 #define be16_to_cpu(x) (x)
35 #define be32_to_cpu(x) (x)
36 #else
37 #define cpu_to_be64(x) bswap_64(x)
38 #define be64_to_cpu(x) bswap_64(x)
39 #define be16_to_cpu(x) bswap_16(x)
40 #define be32_to_cpu(x) bswap_32(x)
41 #endif
42
43
44 /* no board dependencies wanted here, let's hardcode SLOF's
45 * magic strings here */
46
47 #define FLASHFS_MAGIC "magic123"
48 #define FLASHFS_PLATFORM_MAGIC "JS2XBlade"
49 #define FLASHFS_PLATFORM_REVISION "1"
50
51 /* there seems to be no structure defined anywhere in the code
52 * which resembles the actual sloffs/romfs file header;
53 * so defining it here for now */
54
55 struct sloffs {
56 uint64_t next;
57 uint64_t len;
58 uint64_t flags;
59 uint64_t data;
60 char *name;
61 };
62
63 /* sloffs metadata size:
64 * 4 * 8: 4 * uint64_t + (filename length) */
65 #define SLOFFS_META (4 * 8)
66 #define ALIGN64(x) (((x) + 7) & ~7)
67
68 static struct sloffs *
69 next_file_mm(struct sloffs *sloffs)
70 {
71 return (struct sloffs *)((unsigned char *)sloffs +
72 be64_to_cpu(sloffs->next));
73 }
74
75 static int
76 next_file(const int fd, struct sloffs *sloffs)
77 {
78 int ret;
79 uint64_t size;
80 uint64_t offset;
81 char *name;
82
83 offset = 0;
84
85 /* if sloffs is not all NULL we want the next file
86 * else we just take the first file */
87 if (sloffs->name && sloffs->len && sloffs->data) {
88 offset = be64_to_cpu(sloffs->next);
89 /* we already read over the header; skip it in the seek */
90 offset -= be64_to_cpu(sloffs->data);
91 free(sloffs->name);
92 sloffs->name = NULL;
93 lseek(fd, offset, SEEK_CUR);
94 } else {
95 lseek(fd, offset, SEEK_SET);
96 }
97
98 ret = read(fd, sloffs, SLOFFS_META);
99 if (ret == -1)
100 return -1;
101 /* read the size of the header */
102 size = be64_to_cpu(sloffs->data);
103 /* get the size of the filename */
104 size -= SLOFFS_META;
105 name = malloc(size);
106
107 ret = read(fd, name, size);
108 if (ret == -1) {
109 free(name);
110 return -1;
111 }
112 sloffs->name = name;
113 return 0;
114 }
115
116 static struct sloffs *
117 find_file_mm(const void *data, const char *name)
118 {
119 struct sloffs *sloffs = (struct sloffs *)data;
120
121 for (;;) {
122 if (!strcmp((char *)&sloffs->name, name))
123 return sloffs;
124
125 if (be64_to_cpu(sloffs->next) == 0)
126 break;
127 sloffs = next_file_mm(sloffs);
128 }
129 return NULL;
130 }
131
132 static struct sloffs *
133 find_file(const int fd, const char *name, struct sloffs *sloffs)
134 {
135 memset(sloffs, 0, sizeof(struct sloffs));
136
137 if (next_file(fd, sloffs))
138 return NULL;
139
140 for (;;) {
141 if (!strcmp(sloffs->name, name))
142 return sloffs;
143
144 if (be64_to_cpu(sloffs->next) == 0)
145 break;
146 if (next_file(fd, sloffs))
147 return NULL;
148 }
149
150 free(sloffs->name);
151 return NULL;
152 }
153
154 static struct stH *
155 sloffs_header_mm(const void *data)
156 {
157 struct sloffs *sloffs;
158 struct stH *header;
159
160 /* find the "header" file with all the information about
161 * the flash image */
162 sloffs = find_file_mm(data, "header");
163 if (!sloffs) {
164 printf("sloffs file \"header\" not found. aborting...\n");
165 return NULL;
166 }
167
168 header = (struct stH *)((unsigned char *)sloffs +
169 be64_to_cpu(sloffs->data));
170 return header;
171 }
172
173 static struct stH *
174 sloffs_header(const int fd)
175 {
176 struct sloffs file;
177 struct sloffs *sloffs;
178 struct stH *header;
179
180 header = (struct stH *)malloc(sizeof(struct stH));
181
182 /* find the "header" file with all the information about
183 * the flash image */
184 sloffs = find_file(fd, "header", &file);
185 if (!sloffs) {
186 printf("sloffs file \"header\" not found. aborting...\n");
187 return NULL;
188 }
189
190 read(fd, header, sizeof(struct stH));
191 free(sloffs->name);
192 return header;
193 }
194
195 static uint64_t
196 header_length_mm(const void *data)
197 {
198 struct sloffs *sloffs;
199
200 /* find the "header" file with all the information about
201 * the flash image */
202 sloffs = find_file_mm(data, "header");
203 if (!sloffs) {
204 printf("sloffs file \"header\" not found. aborting...\n");
205 return 0;
206 }
207 return be64_to_cpu(sloffs->len);
208 }
209
210 static uint64_t
211 header_length(const int fd)
212 {
213 struct sloffs file;
214 struct sloffs *sloffs;
215
216 /* find the "header" file with all the information about
217 * the flash image */
218 sloffs = find_file(fd, "header", &file);
219 if (!sloffs) {
220 printf("sloffs file \"header\" not found. aborting...\n");
221 return 0;
222 }
223
224 free(sloffs->name);
225 return be64_to_cpu(sloffs->len);
226 }
227
228 static void
229 update_modification_time(struct stH *header)
230 {
231 struct tm *tm;
232 time_t caltime;
233 char dastr[16] = { 0, };
234 uint64_t date;
235
236 /* update modification date
237 * copied from create_crc.c */
238 caltime = time(NULL);
239 tm = localtime(&caltime);
240 strftime(dastr, 15, "0x%Y%m%d%H%M", tm);
241 date = cpu_to_be64(strtoll(dastr, NULL, 16));
242
243 /* this does not match the definition from
244 * struct stH, but we immitate the bug from
245 * flash image creation in create_crc.c.
246 * The date is in mdate and time in padding2. */
247 memcpy(&(header->mdate), &date, 8);
248 }
249
250 static void
251 update_crc(void *data)
252 {
253 uint64_t crc;
254 struct stH *header = sloffs_header_mm(data);
255 uint64_t len = be64_to_cpu(header->flashlen);
256
257 /* calculate header CRC */
258 header->ui64CRC = 0;
259 crc = checkCRC(data, header_length_mm(data), 0);
260 header->ui64CRC = cpu_to_be64(crc);
261 /* calculate flash image CRC */
262 crc = checkCRC(data, len, 0);
263 *(uint64_t *)(data + len - 8) = cpu_to_be64(crc);
264 }
265
266 static uint64_t
267 check_image_crc(const int fd, uint64_t len)
268 {
269 uint64_t crc;
270 uint64_t i;
271 uint64_t read_bytes;
272 unsigned char buffer[4096];
273
274 lseek(fd, 0, SEEK_SET);
275 crc = 0;
276 read_bytes = 0;
277 while (read_bytes < len) {
278 i = read(fd, buffer, 4096);
279 read_bytes += i;
280 if (read_bytes > len)
281 i -= read_bytes - len;
282 crc = calCRCword(buffer, i, crc);
283 }
284 return crc;
285 }
286 static void
287 sloffs_append(const int file, const char *name, const char *dest)
288 {
289 void *append;
290 unsigned char *write_data;
291 void *write_start;
292 int fd;
293 int out;
294 struct stat stat;
295 struct stH *header;
296 uint64_t new_len;
297 struct sloffs *sloffs;
298 struct sloffs new_file;
299 uint64_t read_len;
300 int i;
301
302 fd = open(name, O_RDONLY);
303
304 if (fd == -1) {
305 perror(name);
306 exit(1);
307 }
308
309 fstat(fd, &stat);
310 append = mmap(NULL, stat.st_size, PROT_READ, MAP_SHARED, fd, 0);
311 header = sloffs_header(file);
312
313 if (!header)
314 return;
315
316 new_len = ALIGN64(stat.st_size) + be64_to_cpu(header->flashlen);
317 /* add the length of the sloffs file meta information */
318 new_len += SLOFFS_META;
319 /* add the length of the filename */
320 new_len += ALIGN64(strlen(name) + 1);
321
322 out = open(dest, O_CREAT | O_RDWR | O_TRUNC, 00666);
323
324 if (out == -1) {
325 perror(dest);
326 exit(1);
327 }
328
329 /* write byte at the end to be able to mmap it */
330 lseek(out, new_len - 1, SEEK_SET);
331 write(out, "", 1);
332 write_start = mmap(NULL, new_len, PROT_READ | PROT_WRITE,
333 MAP_SHARED, out, 0);
334
335 memset(write_start, 0, new_len);
336 memset(&new_file, 0, sizeof(struct sloffs));
337
338 new_file.len = cpu_to_be64(stat.st_size);
339 new_file.data = cpu_to_be64(SLOFFS_META + ALIGN64(strlen(name) + 1));
340
341 if (write_start == MAP_FAILED) {
342 perror("mmap");
343 exit(1);
344 }
345
346 lseek(file, 0, SEEK_SET);
347 write_data = write_start;
348 read_len = be64_to_cpu(header->flashlen);
349 for (;;) {
350 i = read(file, write_data, read_len);
351 if (i < 0) {
352 perror("read");
353 exit(1);
354 }
355 if (i == 0)
356 break;
357 write_data += i;
358 read_len -= i;
359 }
360 /* -8: overwrite old CRC */
361 write_data = write_start + be64_to_cpu(header->flashlen) - 8;
362 memcpy(write_data, &new_file, SLOFFS_META);
363 write_data += SLOFFS_META;
364 /* write the filename */
365 memcpy(write_data, name, strlen(name));
366 write_data += ALIGN64(strlen(name) + 1 );
367 memcpy(write_data, append, stat.st_size);
368
369 write_data = write_start;
370
371 /* find last file */
372 sloffs = (struct sloffs *)write_start;
373 for (;;) {
374 if (be64_to_cpu(sloffs->next) == 0)
375 break;
376 sloffs = next_file_mm(sloffs);
377 }
378 /* get the distance to the next file */
379 sloffs->next = ALIGN64(be64_to_cpu(sloffs->len));
380 /* and the offset were the data starts */
381 sloffs->next += be64_to_cpu(sloffs->data);
382 /* and we have to skip the end of file marker
383 * if one is there; if the last uint64_t is -1
384 * it is an end of file marker; this is a bit dangerous
385 * but there is no other way to detect the end of
386 * file marker */
387 if ((uint64_t)be64_to_cpu(*(uint64_t *)((unsigned char *)sloffs +
388 sloffs->next)) == (uint64_t)-1ULL)
389 sloffs->next += 8;
390
391 sloffs->next = cpu_to_be64(sloffs->next);
392
393 free(header);
394 /* update new length of flash image */
395 header = sloffs_header_mm(write_start);
396 header->flashlen = cpu_to_be64(new_len);
397
398 update_modification_time(header);
399
400 update_crc(write_start);
401
402 munmap(append, stat.st_size);
403 munmap(write_start, new_len);
404 close(fd);
405 close(out);
406 }
407
408 static void print_header_date(void *dptr)
409 {
410 uint8_t *date = dptr;
411
412 if (date[2] || date[3] || date[4] || date[5] || date[6] || date[7]) {
413 printf("%02x%02x-%02x-%02x %02x:%02x", date[2], date[3],
414 date[4], date[5], date[6], date[7]);
415 } else {
416 printf("N/A");
417 }
418
419 }
420
421 static void
422 sloffs_dump(const int fd)
423 {
424 void *data;
425 struct stH *header;
426 struct sloffs file;
427 int i;
428 uint64_t crc;
429 uint64_t header_len;
430
431 header = sloffs_header(fd);
432
433 if (!header)
434 return;
435
436 if (memcmp(FLASHFS_MAGIC, header->magic, strlen(FLASHFS_MAGIC))) {
437 printf("sloffs magic not found. "
438 "probably not a valid SLOF flash image. aborting...\n");
439 return;
440 }
441 printf(" Magic : %s\n", header->magic);
442 printf(" Platform : %s\n", header->platform_name);
443 printf(" Version : %s\n", header->version);
444 /* there is a bug in the date position;
445 * it should be at header->date, but it is at (header->date + 2) */
446 printf(" Build Date : ");
447 print_header_date(header->date);
448 printf("\n");
449 printf(" Modify Date : ");
450 print_header_date(header->mdate);
451 printf("\n");
452 printf(" Image Length: %ld", be64_to_cpu(header->flashlen));
453 printf(" (0x%lx) bytes\n", be64_to_cpu(header->flashlen));
454 printf(" Revision : %s\n", header->platform_revision);
455 crc = be64_to_cpu(header->ui64CRC);
456 printf(" Header CRC : 0x%016lx CRC check: ", crc);
457 /* to test the CRC of the header we need to know the actual
458 * size of the file and not just the size of the data
459 * which could be easily obtained with sizeof(struct stH);
460 * the actual size can only be obtained from the filesystem
461 * meta information */
462 header_len = header_length(fd);
463 /* no copy the header to memory to crc test it */
464 data = malloc(header_len);
465 lseek(fd, 0, SEEK_SET);
466 read(fd, data, header_len);
467 crc = calCRCword((unsigned char *)data, header_length(fd), 0);
468 free(data);
469 if (!crc)
470 printf("[OK]");
471 else
472 printf("[FAILED]");
473 printf("\n");
474
475 crc = be64_to_cpu(header->flashlen);
476 /* move to the CRC */
477 lseek(fd, crc - 8, SEEK_SET);
478 /* read it */
479 read(fd, &crc, 8);
480 crc = be64_to_cpu(crc);
481 printf(" Image CRC : 0x%016lx CRC check: ", crc);
482 crc = check_image_crc(fd, be64_to_cpu(header->flashlen));
483 if (!crc)
484 printf("[OK]");
485 else
486 printf("[FAILED]");
487 printf("\n");
488
489 /* count number of files */
490 i = 0;
491 memset(&file, 0, sizeof(struct sloffs));
492 if (next_file(fd, &file))
493 return;
494 for (;;) {
495 i++;
496
497 if (be64_to_cpu(file.next) == 0)
498 break;
499 if (next_file(fd, &file))
500 return;
501 }
502 free(file.name);
503 printf(" Files : %d\n", i);
504 free(header);
505 }
506
507 static void
508 sloffs_list(const int fd)
509 {
510 const char *name_header = "File Name";
511 unsigned int i;
512 unsigned int max;
513 unsigned int line;
514 struct sloffs file;
515 uint64_t offset = 0;
516
517 memset(&file, 0, sizeof(struct sloffs));
518
519 if (next_file(fd, &file))
520 return;
521
522 /* find largest name */
523 max = strlen(name_header);
524 for (;;) {
525 if (max < strlen((char *)file.name))
526 max = strlen((char *)file.name);
527
528 if (be64_to_cpu(file.next) == 0)
529 break;
530 if (next_file(fd, &file))
531 return;
532 }
533
534 free(file.name);
535
536
537 /* have at least two spaces between name and size column */
538 max += 2;
539
540 /* header for listing */
541 line = printf(" Offset ");
542 line += printf("%s", name_header);
543 for (i = 0; i < max - strlen(name_header); i++)
544 line += printf(" ");
545 line += printf("Size ");
546 line += printf("Flags\n");
547 printf(" ");
548 for (i = 0; i <= line; i++)
549 printf("=");
550 printf("\n");
551
552 memset(&file, 0, sizeof(struct sloffs));
553
554 if (next_file(fd, &file))
555 return;
556
557 for (;;) {
558 printf(" 0x%08lx", offset);
559 offset += be64_to_cpu(file.next);
560 printf(" %s", file.name);
561 for (i = 0; i < max - strlen(file.name); i++)
562 printf(" ");
563
564 printf("%07ld ", be64_to_cpu(file.len));
565 printf("(0x%06lx)", be64_to_cpu(file.len));
566 printf(" 0x%08lx\n", be64_to_cpu(file.flags));
567
568 if (be64_to_cpu(file.next) == 0)
569 break;
570 if (next_file(fd, &file))
571 return;
572 }
573 free(file.name);
574 }
575
576 static void
577 sloffs_copy(const int file, const char *name)
578 {
579 uint64_t len;
580 int out;
581 unsigned char *write_buf;
582 int i;
583 struct stH *header;
584
585 header = sloffs_header(file);
586
587 if (!header)
588 return;
589
590 len = be64_to_cpu(header->flashlen);
591 free(header);
592
593 out = open(name, O_CREAT | O_RDWR | O_TRUNC, 00666);
594
595 if (out == -1) {
596 perror(name);
597 exit(1);
598 }
599 /* write byte at the end to be able to mmap it */
600 lseek(out, len - 1, SEEK_SET);
601 write(out, "", 1);
602 write_buf = mmap(NULL, len, PROT_WRITE, MAP_SHARED, out, 0);
603
604 if (write_buf == MAP_FAILED) {
605 perror("mmap");
606 exit(1);
607 }
608
609 lseek(file, 0, SEEK_SET);
610
611 for (;;) {
612 i = read(file, write_buf, len);
613 if (i < 0) {
614 perror("read");
615 exit(1);
616 }
617 if (i == 0)
618 break;
619 write_buf += i;
620 len -= i;
621 }
622
623 munmap(write_buf, len);
624 close(out);
625 }
626
627 static void
628 usage(void)
629 {
630 printf("sloffs lists or changes a SLOF flash image\n\n");
631 printf("Usage:\n");
632 printf(" sloffs [OPTION]... [FILE]\n\n");
633 printf("Options:\n");
634 printf(" -h, --help show this help, then exit\n");
635 printf(" -l, --list list all files in the flash image\n");
636 printf(" -v, --version print the version, then exit\n");
637 printf(" -d, --dump dump the information from the header\n");
638 printf(" -a, --append=FILENAME append file at the end of\n");
639 printf(" the existing image\n");
640 printf(" -o, --output=FILENAME if appending a file this parameter\n");
641 printf(" is necessary to specify the name of\n");
642 printf(" the output file\n");
643 printf(" -c, --copy=FILENAME copy SLOF image to specified file\n");
644 printf(" this is especially useful if the\n");
645 printf(" source file is /dev/slof_flash\n");
646 printf("\n");
647 exit(1);
648 }
649
650 int
651 main(int argc, char *argv[])
652 {
653 int fd;
654 const struct option loption[] = {
655 { "help", 0, NULL, 'h' },
656 { "list", 0, NULL, 'l' },
657 { "version", 0, NULL, 'v' },
658 { "dump", 0, NULL, 'd' },
659 { "append", 1, NULL, 'a' },
660 { "output", 1, NULL, 'o' },
661 { "copy", 1, NULL, 'o' },
662 { 0, 0, 0, 0 }
663 };
664 const char *soption = "dhlva:o:c:";
665 int c;
666 char mode = 0;
667 char *append = NULL;
668 char *output = NULL;
669
670 for (;;) {
671 c = getopt_long(argc, argv, soption, loption, NULL);
672 if (c == -1)
673 break;
674 switch (c) {
675 case 'l':
676 mode = 'l';
677 break;
678 case 'v':
679 printf("sloffs (version %d)\n", VERSION);
680 exit(0);
681 case 'd':
682 mode = 'd';
683 break;
684 case 'a':
685 mode = 'a';
686 append = strdup(optarg);
687 break;
688 case 'o':
689 output = strdup(optarg);
690 break;
691 case 'c':
692 mode = 'c';
693 output = strdup(optarg);
694 break;
695 case 'h':
696 default:
697 usage();
698 }
699 }
700
701 if (optind >= argc)
702 usage();
703
704 fd = open(argv[optind], O_RDONLY);
705
706 if (fd == -1) {
707 perror(argv[optind]);
708 exit(1);
709 }
710
711 lseek(fd, 0, SEEK_SET);
712
713 switch (mode) {
714 case 'l':
715 sloffs_list(fd);
716 break;
717 case 'd':
718 sloffs_dump(fd);
719 break;
720 case 'a':
721 if (!output) {
722 printf("sloffs requires -o, --output=FILENAME"
723 " when in append mode\n\n");
724 usage();
725 }
726 sloffs_append(fd, append, output);
727 break;
728 case 'c':
729 sloffs_copy(fd, output);
730 break;
731 }
732
733 free(append);
734 free(output);
735 close(fd);
736 return 0;
737 }