Rev 1 | Rev 3 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 1 | Rev 2 | ||
---|---|---|---|
Line 1... | Line 1... | ||
1 | // ifstool.c -- portable reimplementation of QNX's mkifs by Pierre-Marie Baty <pm@pmbaty.com> |
1 | // ifstool.c -- portable reimplementation of QNX's mkifs by Pierre-Marie Baty <pm@pmbaty.com> |
2 | 2 | ||
3 | #include <stdint.h> |
3 | #include <stdint.h> |
4 | #include <stdbool.h> |
4 | #include <stdbool.h> |
5 | #include <stdlib.h> |
5 | #include <stdlib.h> |
- | 6 | #include <stdarg.h> |
|
6 | #include <stdio.h> |
7 | #include <stdio.h> |
7 | #include <string.h> |
8 | #include <string.h> |
8 | #include <errno.h> |
9 | #include <errno.h> |
9 | #include <sys/stat.h> |
10 | #include <sys/stat.h> |
10 | #include <ctype.h> |
11 | #include <ctype.h> |
Line 21... | Line 22... | ||
21 | #define S_IFLNK 0xa000 |
22 | #define S_IFLNK 0xa000 |
22 | #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) |
23 | #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) |
23 | #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) |
24 | #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) |
24 | #define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) |
25 | #define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) |
25 | #define strdup(s) _strdup ((s)) |
26 | #define strdup(s) _strdup ((s)) |
- | 27 | #define strcasecmp(s1,s2) _stricmp ((s1), (s2)) |
|
26 | #define fseek(fp,off,m) _fseeki64 ((fp), (off), (m)) |
28 | #define fseek(fp,off,m) _fseeki64 ((fp), (off), (m)) |
27 | #define access(p,m) _access ((p), (m)) |
29 | #define access(p,m) _access ((p), (m)) |
28 | #define MAXPATHLEN 1024 |
30 | #define MAXPATHLEN 1024 |
29 | #else // !_MSC_VER |
31 | #else // !_MSC_VER |
30 | #include <sys/param.h> |
32 | #include <sys/param.h> |
Line 192... | Line 194... | ||
192 | "\x88\x00" /*size*/ "\x00" /*type*/ "\x00" /*spare*/ "\x00" /*CPU mask*/ "\x00" /*flags*/ "\x00\x00" /*reserved*/ "\x00" /*policy*/ "\x00" /*priority*/ "\02" /*argc*/ "\x02" /*envc*/ "sh\0" /*executable*/ "sh\0" "/proc/boot/startup.sh\0" /*argv*/ "PATH=/sbin:/usr/sbin:/bin:/usr/bin:/proc/boot\0" "LD_LIBRARY_PATH=/proc/boot:/lib:/lib/dll:/usr/lib\0" /*envp*/ \ |
194 | "\x88\x00" /*size*/ "\x00" /*type*/ "\x00" /*spare*/ "\x00" /*CPU mask*/ "\x00" /*flags*/ "\x00\x00" /*reserved*/ "\x00" /*policy*/ "\x00" /*priority*/ "\02" /*argc*/ "\x02" /*envc*/ "sh\0" /*executable*/ "sh\0" "/proc/boot/startup.sh\0" /*argv*/ "PATH=/sbin:/usr/sbin:/bin:/usr/bin:/proc/boot\0" "LD_LIBRARY_PATH=/proc/boot:/lib:/lib/dll:/usr/lib\0" /*envp*/ \ |
193 | /* display_msg "Startup complete */ \ |
195 | /* display_msg "Startup complete */ \ |
194 | "\x18\x00" /*size*/ "\x03" /*type*/ "\x00" /*spare*/ "Startup complete\n\0" "\x00\00" /*padding*/ \ |
196 | "\x18\x00" /*size*/ "\x03" /*type*/ "\x00" /*spare*/ "Startup complete\n\0" "\x00\00" /*padding*/ \ |
195 | /* trailer */ \ |
197 | /* trailer */ \ |
196 | "\x00\x00\x00\x00" |
198 | "\x00\x00\x00\x00" |
197 | #define INITIAL_STARTUP_SCRIPT_LEN (sizeof (INITIAL_STARTUP_SCRIPT) - 1) |
- | |
198 | 199 | ||
199 | 200 | ||
200 | typedef struct fsentry_s |
201 | typedef struct __attribute__((packed)) fsentry_s |
201 | { |
202 | { |
202 | struct __attribute__((packed)) fsentry_header_s |
203 | struct __attribute__((packed)) fsentry_header_s |
203 | { |
204 | { |
204 | uint16_t size; // size of dirent |
205 | uint16_t size; // size of dirent |
205 | uint16_t extattr_offset; // if zero, no extattr data |
206 | uint16_t extattr_offset; // if zero, no extattr data |
Line 207... | Line 208... | ||
207 | uint32_t mode; // mode and perms of entry |
208 | uint32_t mode; // mode and perms of entry |
208 | uint32_t gid; |
209 | uint32_t gid; |
209 | uint32_t uid; |
210 | uint32_t uid; |
210 | uint32_t mtime; |
211 | uint32_t mtime; |
211 | } header; |
212 | } header; |
212 | union fsentry_specific_u |
213 | union __attribute__((packed)) fsentry_specific_u |
213 | { |
214 | { |
214 | struct fsentry_file_s // when (mode & S_IFMT) == S_IFREG |
215 | struct __attribute__((packed)) fsentry_file_s // when (mode & S_IFMT) == S_IFREG |
215 | { |
216 | { |
216 | uint32_t offset; // offset from header |
217 | uint32_t offset; // offset from header |
217 | uint32_t size; |
218 | uint32_t size; |
218 | char *path; // null terminated path (no leading slash) |
219 | char *path; // null terminated path (no leading slash) |
219 | char *UNSAVED_databuf; // file data blob buffer (NOT SAVED IN THE IFS) |
220 | char *UNSAVED_databuf; // file data blob buffer (NOT SAVED IN THE IFS) |
220 | } file; |
221 | } file; |
221 | struct fsentry_dir_s // when (mode & S_IFMT) == S_IFDIR |
222 | struct __attribute__((packed)) fsentry_dir_s // when (mode & S_IFMT) == S_IFDIR |
222 | { |
223 | { |
223 | char *path; // null terminated path (no leading slash) |
224 | char *path; // null terminated path (no leading slash) |
224 | } dir; |
225 | } dir; |
225 | struct fsentry_symlink_s // when (mode & S_IFMT) == S_IFLNK |
226 | struct __attribute__((packed)) fsentry_symlink_s // when (mode & S_IFMT) == S_IFLNK |
226 | { |
227 | { |
227 | uint16_t sym_offset; // offset to 'contents' from 'path' |
228 | uint16_t sym_offset; // offset to 'contents' from 'path' |
228 | uint16_t sym_size; // strlen (contents) |
229 | uint16_t sym_size; // strlen (contents) |
229 | char *path; // null terminated path (no leading slash) |
230 | char *path; // null terminated path (no leading slash) |
230 | char *contents; // null terminated symlink contents |
231 | char *contents; // null terminated symlink contents |
231 | } symlink; |
232 | } symlink; |
232 | struct fsentry_device_s // when (mode & S_IFMT) == S_IF<CHR|BLK|FIFO|NAM|SOCK> |
233 | struct __attribute__((packed)) fsentry_device_s // when (mode & S_IFMT) == S_IF<CHR|BLK|FIFO|NAM|SOCK> |
233 | { |
234 | { |
234 | uint32_t dev; |
235 | uint32_t dev; |
235 | uint32_t rdev; |
236 | uint32_t rdev; |
236 | char *path; // null terminated path (no leading slash) |
237 | char *path; // null terminated path (no leading slash) |
237 | } device; |
238 | } device; |
Line 268... | Line 269... | ||
268 | 269 | ||
269 | 270 | ||
270 | typedef struct __attribute__((packed)) startup_trailer_s |
271 | typedef struct __attribute__((packed)) startup_trailer_s |
271 | { |
272 | { |
272 | uint32_t cksum; // checksum from start of header to start of trailer |
273 | uint32_t cksum; // checksum from start of header to start of trailer |
273 | } |
274 | } startup_trailer_v1_t; |
274 | 275 | ||
275 | 276 | ||
276 | // NOTE: The checksums in this trailer will only be valid prior to entering startup. |
277 | // NOTE: The checksums in this trailer will only be valid prior to entering startup. |
277 | // Because the startup binary is executed in-place, its data segment will change once the program is running. |
278 | // Because the startup binary is executed in-place, its data segment will change once the program is running. |
278 | // Hence, any checksum validation would need to be done by the boot loader / IFS. |
279 | // Hence, any checksum validation would need to be done by the boot loader / IFS. |
Line 300... | Line 301... | ||
300 | 301 | ||
301 | 302 | ||
302 | typedef struct __attribute__((packed)) image_trailer_v1_s |
303 | typedef struct __attribute__((packed)) image_trailer_v1_s |
303 | { |
304 | { |
304 | uint32_t cksum; // checksum from start of header to start of trailer |
305 | uint32_t cksum; // checksum from start of header to start of trailer |
305 | } image_trailer_v1_t; |
306 | } image_trailer_v1_t; // NOTE: this is the same structure as startup_trailer_v1_t |
306 | 307 | ||
307 | 308 | ||
308 | // NOTE: the checksums in this trailer will only be valid until the first non-startup bootstrap binary (e.g., startup-verifier, procnto, ...) is invoked. |
309 | // NOTE: the checksums in this trailer will only be valid until the first non-startup bootstrap binary (e.g., startup-verifier, procnto, ...) is invoked. |
309 | // Because bootstrap binaries execute in-place, their data segments will change once the programs are running. |
310 | // Because bootstrap binaries execute in-place, their data segments will change once the programs are running. |
310 | // Hence, any checksum validation would need to be done either by the boot loader / IFS or by the startup. |
311 | // Hence, any checksum validation would need to be done either by the boot loader / IFS or by the startup. |
311 | typedef struct __attribute__((packed)) image_trailer_v2_s |
312 | typedef struct __attribute__((packed)) image_trailer_v2_s |
312 | { |
313 | { |
313 | uint8_t sha512[64]; // SHA512 from start of image header to start of trailer |
314 | uint8_t sha512[64]; // SHA512 from start of image header to start of trailer |
314 | uint32_t cksum; // checksum from start of header to start of this member |
315 | uint32_t cksum; // checksum from start of header to start of this member |
315 | } image_trailer_v2_t; |
316 | } image_trailer_v2_t; // NOTE: this is the same structure as startup_trailer_v2_t |
316 | 317 | ||
317 | 318 | ||
318 | #ifdef _MSC_VER |
319 | #ifdef _MSC_VER |
319 | #pragma pack(pop) |
320 | #pragma pack(pop) |
320 | #endif // _MSC_VER |
321 | #endif // _MSC_VER |
Line 326... | Line 327... | ||
326 | int perms; // file permissions (e.g. 0644) |
327 | int perms; // file permissions (e.g. 0644) |
327 | int uid; // owner user ID (e.g. 0 = root) |
328 | int uid; // owner user ID (e.g. 0 = root) |
328 | int gid; // owner group ID (e.g. 0 = root) |
329 | int gid; // owner group ID (e.g. 0 = root) |
329 | int st_mode; // entry type (e.g. S_IFREG for files) and permissions |
330 | int st_mode; // entry type (e.g. S_IFREG for files) and permissions |
330 | char prefix[MAXPATHLEN]; // install path (e.g. "proc/boot") |
331 | char prefix[MAXPATHLEN]; // install path (e.g. "proc/boot") |
331 | bool |
332 | bool is_compiled_bootscript; // entry has [+script] attribute |
332 | char search[10 * MAXPATHLEN]; // binary search path (the default one will be constructed at startup) |
333 | char search[10 * MAXPATHLEN]; // binary search path (the default one will be constructed at startup) |
- | 334 | ||
- | 335 | uint8_t *precompiled_data; |
|
- | 336 | size_t precompiled_datalen; |
|
333 | } parms_t; |
337 | } parms_t; |
334 | 338 | ||
335 | 339 | ||
336 | // global variables |
340 | // global variables |
337 | static char line_buffer[4096]; // scrap buffer for the IFS build file parser |
341 | static char line_buffer[4096]; // scrap buffer for the IFS build file parser |
Line 352... | Line 356... | ||
352 | static void sha512_private_transform (SHA512_CTX *context, const uint64_t *data); // used internally in SHA512_Update() and SHA512_Final() |
356 | static void sha512_private_transform (SHA512_CTX *context, const uint64_t *data); // used internally in SHA512_Update() and SHA512_Final() |
353 | static void SHA512_Init (SHA512_CTX *context); |
357 | static void SHA512_Init (SHA512_CTX *context); |
354 | static void SHA512_Update (SHA512_CTX *context, void *data, size_t len); |
358 | static void SHA512_Update (SHA512_CTX *context, void *data, size_t len); |
355 | static void SHA512_Final (uint8_t digest[SHA512_DIGEST_LENGTH], SHA512_CTX *context); |
359 | static void SHA512_Final (uint8_t digest[SHA512_DIGEST_LENGTH], SHA512_CTX *context); |
356 | static uint8_t *SHA512 (void *data, size_t data_len, uint8_t *digest); // computes a SHA-512 in one pass (shortcut for SHA512_Init(), SHA512_Update() N times and SHA512_Final()) |
360 | static uint8_t *SHA512 (void *data, size_t data_len, uint8_t *digest); // computes a SHA-512 in one pass (shortcut for SHA512_Init(), SHA512_Update() N times and SHA512_Final()) |
357 | static |
361 | static int32_t update_checksum32 (const int32_t start_value, const void *data, const size_t len); // update the sum of an array of 32-bit signed integers |
358 | static long long read_integer (const char *str); // reads an integer number for a string that may be specified in either hex, octal or decimal base, and may have an optional unit suffix (k, m, g, t) |
362 | static long long read_integer (const char *str); // reads an integer number for a string that may be specified in either hex, octal or decimal base, and may have an optional unit suffix (k, m, g, t) |
- | 363 | static void hex_fprintf (FILE *fp, const uint8_t *data, size_t data_size, int howmany_columns, const char *fmt, ...); // hexdump-style formatted output to a file stream (which may be stdout/stderr) |
|
- | 364 | static char *binary (const uint8_t x, char char_for_zero, char char_for_one); // returns the binary representation of byte 'x' as a string |
|
- | 365 | static char *describe_uint8 (const uint8_t x, const char *bitwise_stringdescs[8]); // returns the ORed description of byte 'x' according to the description strings for each bit |
|
359 | static int fwrite_filecontents (const char *pathname, FILE *fp); // dumps the contents of pathname into fp |
366 | static int fwrite_filecontents (const char *pathname, FILE *fp); // dumps the contents of pathname into fp |
360 | static size_t fwrite_fsentry (const fsentry_t *fsentry, FILE *fp); // writes the given filesystem entry into fp (without its contents) |
367 | static size_t fwrite_fsentry (const fsentry_t *fsentry, FILE *fp); // writes the given filesystem entry into fp (without its contents) |
361 | static size_t add_fsentry (fsentry_t **fsentries, size_t *fsentry_count, const char *stored_pathname, parms_t *entry_parms, const uint8_t *data, const size_t entry_datalen); // stack up a new filesystem entry |
368 | static size_t add_fsentry (fsentry_t **fsentries, size_t *fsentry_count, const char *stored_pathname, parms_t *entry_parms, const uint8_t *data, const size_t entry_datalen); // stack up a new filesystem entry |
362 | static int fsentry_compare_pathnames_cb (const void *a, const void *b); // qsort() comparison callback that sorts filesystem entries by pathnames |
369 | static int fsentry_compare_pathnames_cb (const void *a, const void *b); // qsort() comparison callback that sorts filesystem entries by pathnames |
363 | static int fsentry_compare_sizes_cb (const void *a, const void *b); // qsort() comparison callback that sorts filesystem entries by size |
370 | static int fsentry_compare_sizes_cb (const void *a, const void *b); // qsort() comparison callback that sorts filesystem entries by size |
- | 371 | static int dump_ifs_info (const char *ifs_pathname); // dumps detailed info about a particular IFS file on the standard output, returns 0 on success and >0 on error |
|
364 | 372 | ||
365 | 373 | ||
366 | static void sha512_private_transform (SHA512_CTX *context, const uint64_t *data) |
374 | static void sha512_private_transform (SHA512_CTX *context, const uint64_t *data) |
367 | { |
375 | { |
368 | // logical functions used in SHA-384 and SHA-512 |
376 | // logical functions used in SHA-384 and SHA-512 |
Line 584... | Line 592... | ||
584 | #undef SHA512_SHORT_BLOCK_LENGTH |
592 | #undef SHA512_SHORT_BLOCK_LENGTH |
585 | return; |
593 | return; |
586 | } |
594 | } |
587 | 595 | ||
588 | 596 | ||
589 | static uint8_t *SHA512 (void *data, size_t data_len, uint8_t * |
597 | static uint8_t *SHA512 (void *data, size_t data_len, uint8_t *digest_or_NULL) |
590 | { |
598 | { |
591 | // computes the SHA-512 hash of a block of data in one pass and write it to |
599 | // computes the SHA-512 hash of a block of data in one pass and write it to digest, or to a static buffer if NULL |
- | 600 | // returns the STRING REPRESENTATION of digest in a statically-allocated string |
|
- | 601 | ||
- | 602 | static uint8_t static_digest[SHA512_DIGEST_LENGTH] = ""; |
|
- | 603 | static char digest_as_string[2 * SHA512_DIGEST_LENGTH + 1] = ""; |
|
592 | 604 | ||
593 | SHA512_CTX ctx; |
605 | SHA512_CTX ctx; |
- | 606 | size_t byte_index; |
|
- | 607 | ||
594 | SHA512_Init (&ctx); |
608 | SHA512_Init (&ctx); |
595 | SHA512_Update (&ctx, data, data_len); |
609 | SHA512_Update (&ctx, data, data_len); |
- | 610 | if (digest_or_NULL == NULL) |
|
- | 611 | digest_or_NULL = static_digest; |
|
596 | SHA512_Final ( |
612 | SHA512_Final (digest_or_NULL, &ctx); |
- | 613 | ||
- | 614 | for (byte_index = 0; byte_index < SHA512_DIGEST_LENGTH; byte_index++) |
|
- | 615 | sprintf (&digest_as_string[2 * byte_index], "%02x", digest_or_NULL[byte_index]); |
|
597 | return ( |
616 | return (digest_as_string); |
598 | } |
617 | } |
599 | 618 | ||
600 | 619 | ||
601 | static |
620 | static int32_t update_checksum32 (const int32_t start_value, const void *data, const size_t len) |
602 | { |
621 | { |
603 | // compute the sum of an array of 32-bit signed integers |
622 | // compute the sum of an array of 32-bit signed integers |
604 | 623 | ||
605 |
|
624 | const int32_t *values_array = data; |
606 | int32_t sum = start_value; |
625 | int32_t sum = start_value; |
- | 626 | ||
607 | for ( |
627 | for (size_t value_index = 0; value_index < len / sizeof (int32_t); value_index++) |
608 | sum += |
628 | sum += values_array[value_index]; |
- | 629 | ||
609 | return (sum); |
630 | return (sum); |
610 | } |
631 | } |
611 | 632 | ||
612 | 633 | ||
613 | static long long read_integer (const char *str) |
634 | static long long read_integer (const char *str) |
Line 622... | Line 643... | ||
622 | else if ((*endptr == 'm') || (*endptr == 'M')) ret *= (size_t) 1024 * 1024; |
643 | else if ((*endptr == 'm') || (*endptr == 'M')) ret *= (size_t) 1024 * 1024; |
623 | else if ((*endptr == 'g') || (*endptr == 'G')) ret *= (size_t) 1024 * 1024 * 1024; |
644 | else if ((*endptr == 'g') || (*endptr == 'G')) ret *= (size_t) 1024 * 1024 * 1024; |
624 | else if ((*endptr == 't') || (*endptr == 'T')) ret *= (size_t) 1024 * 1024 * 1024 * 1024; // future-proof enough, I suppose? |
645 | else if ((*endptr == 't') || (*endptr == 'T')) ret *= (size_t) 1024 * 1024 * 1024 * 1024; // future-proof enough, I suppose? |
625 | } |
646 | } |
626 | return (ret); |
647 | return (ret); |
- | 648 | } |
|
- | 649 | ||
- | 650 | ||
- | 651 | static void hex_fprintf (FILE *fp, const uint8_t *data, size_t data_size, int howmany_columns, const char *fmt, ...) |
|
- | 652 | { |
|
- | 653 | // this function logs hexadecimal data to an opened file pointer (or to stdout/stderr) |
|
- | 654 | ||
- | 655 | va_list argptr; |
|
- | 656 | size_t index; |
|
- | 657 | int i; |
|
- | 658 | ||
- | 659 | // concatenate all the arguments in one string and write it to the file |
|
- | 660 | va_start (argptr, fmt); |
|
- | 661 | vfprintf (fp, fmt, argptr); |
|
- | 662 | va_end (argptr); |
|
- | 663 | ||
- | 664 | // for each row of howmany_columns bytes of data... |
|
- | 665 | for (index = 0; index < data_size; index += howmany_columns) |
|
- | 666 | { |
|
- | 667 | fprintf (fp, " %05zu ", index); // print array address of row |
|
- | 668 | for (i = 0; i < howmany_columns; i++) |
|
- | 669 | if (index + i < data_size) |
|
- | 670 | fprintf (fp, " %02X", data[index + i]); // if row contains data, print data as hex bytes |
|
- | 671 | else |
|
- | 672 | fprintf (fp, " "); // else fill the space with blanks |
|
- | 673 | fprintf (fp, " "); |
|
- | 674 | for (i = 0; i < howmany_columns; i++) |
|
- | 675 | if (index + i < data_size) |
|
- | 676 | fputc ((data[index + i] >= 32) && (data[index + i] < 127) ? data[index + i] : '.', fp); // now if row contains data, print data as ASCII |
|
- | 677 | else |
|
- | 678 | fputc (' ', fp); // else fill the space with blanks |
|
- | 679 | fputc ('\n', fp); |
|
- | 680 | } |
|
- | 681 | ||
- | 682 | return; // and return |
|
- | 683 | } |
|
- | 684 | ||
- | 685 | ||
- | 686 | static char *binary (const uint8_t x, char char_for_zero, char char_for_one) |
|
- | 687 | { |
|
- | 688 | // returns the binary representation of x as a string |
|
- | 689 | ||
- | 690 | static char outstr[9] = "00000000"; |
|
- | 691 | for (int i = 0; i < 8; i++) |
|
- | 692 | outstr[i] = (x & (0x80 >> i) ? char_for_one : char_for_zero); |
|
- | 693 | return (outstr); |
|
- | 694 | } |
|
- | 695 | ||
- | 696 | ||
- | 697 | static char *describe_uint8 (const uint8_t x, const char *bitwise_stringdescs[8]) |
|
- | 698 | { |
|
- | 699 | // returns the ORed description of byte 'x' according to the description strings for each bit |
|
- | 700 | ||
- | 701 | static char *default_bitstrings[8] = { "bit0", "bit1", "bit2", "bit3", "bit4", "bit5", "bit6", "bit7" }; |
|
- | 702 | static char outstr[8 * 64] = ""; |
|
- | 703 | ||
- | 704 | outstr[0] = 0; |
|
- | 705 | for (int i = 0; i < 8; i++) |
|
- | 706 | if (x & (1 << i)) |
|
- | 707 | { |
|
- | 708 | if (outstr[0] != 0) |
|
- | 709 | strcat (outstr, "|"); |
|
- | 710 | strcat (outstr, ((bitwise_stringdescs != NULL) && (*bitwise_stringdescs[i] != 0) ? bitwise_stringdescs[i] : default_bitstrings[i])); |
|
- | 711 | } |
|
- | 712 | return (outstr); |
|
627 | } |
713 | } |
628 | 714 | ||
629 | 715 | ||
630 | static int fwrite_filecontents (const char *pathname, FILE *fp) |
716 | static int fwrite_filecontents (const char *pathname, FILE *fp) |
631 | { |
717 | { |
Line 737... | Line 823... | ||
737 | void *reallocated_ptr; |
823 | void *reallocated_ptr; |
738 | char processor_base[16]; |
824 | char processor_base[16]; |
739 | struct stat stat_buf; |
825 | struct stat stat_buf; |
740 | uint8_t *data_buffer = NULL; |
826 | uint8_t *data_buffer = NULL; |
741 | size_t data_len = 0; |
827 | size_t data_len = 0; |
742 | uint32_t mtime = |
828 | uint32_t mtime = (uint32_t) time (NULL); |
743 | uint32_t extra_ino_flags = 0; |
829 | uint32_t extra_ino_flags = 0; |
744 | fsentry_t *fsentry; |
830 | fsentry_t *fsentry; |
745 | char *token; |
831 | char *token; |
746 | FILE *fp; |
832 | FILE *fp; |
747 | 833 | ||
Line 755... | Line 841... | ||
755 | { |
841 | { |
756 | if (strcmp (stored_pathname, "proc/boot/boot") == 0) // is it the kernel ? |
842 | if (strcmp (stored_pathname, "proc/boot/boot") == 0) // is it the kernel ? |
757 | { |
843 | { |
758 | // HACK: for now just consider the kernel as a binary blob |
844 | // HACK: for now just consider the kernel as a binary blob |
759 | // FIXME: reimplement properly |
845 | // FIXME: reimplement properly |
760 | if (stat ("procnto-smp-instr.bin", &stat_buf) != 0) |
- | |
761 | { |
- | |
762 | fprintf (stderr, "fatal error: unable to read procnto-smp-instr.bin\n"); |
- | |
763 | exit (1); |
- | |
764 | } |
- | |
765 | data_len = |
846 | data_len = entry_datalen; |
766 | mtime = (uint32_t) time (NULL); |
- | |
767 | data_buffer = malloc (data_len); |
847 | data_buffer = malloc (data_len); |
768 | if (data_buffer == NULL) |
848 | if (data_buffer == NULL) |
769 | { |
849 | { |
770 | fprintf (stderr, "fatal error: out of memory\n"); |
850 | fprintf (stderr, "fatal error: out of memory\n"); |
771 | exit (1); |
851 | exit (1); |
772 | } |
852 | } |
773 | fp = fopen ("procnto-smp-instr.bin", "rb"); |
- | |
774 |
|
853 | memcpy (data_buffer, entry_data, data_len); |
775 | fclose (fp); |
- | |
- | 854 | ||
776 | sprintf (candidate_pathname, "%s/procnto-smp-instr", entry_parms->prefix); |
855 | sprintf (candidate_pathname, "%s/procnto-smp-instr", entry_parms->prefix); // fix the entry name |
777 | stored_pathname = candidate_pathname; |
856 | stored_pathname = candidate_pathname; |
778 | extra_ino_flags = IFS_INO_PROCESSED_ELF | IFS_INO_BOOTSTRAP_EXE; |
857 | extra_ino_flags = IFS_INO_PROCESSED_ELF | IFS_INO_BOOTSTRAP_EXE; // procnto needs to have these flags stamped on the inode |
779 | image_kernel_ino = extra_ino_flags | (inode_count + 1); |
858 | image_kernel_ino = extra_ino_flags | (inode_count + 1); |
780 | } |
859 | } |
781 | else if (entry_parms-> |
860 | else if (entry_parms->is_compiled_bootscript) // else is it a startup script ? |
- | 861 | image_bootscript_ino = inode_count + 1; // save boot script inode number for image header |
|
- | 862 | ||
- | 863 | // should we substitute precompiled data to this data blob ? |
|
- | 864 | if ((entry_parms->precompiled_data != NULL) && (entry_parms->precompiled_datalen > 0)) |
|
782 | { |
865 | { |
783 |
|
866 | data_len = entry_parms->precompiled_datalen; |
784 | // FIXME: replace this with a true compilation with the rules defined above |
- | |
785 | data_buffer = malloc ( |
867 | data_buffer = malloc (data_len); |
786 | if (data_buffer == NULL) |
868 | if (data_buffer == NULL) |
787 | { |
869 | { |
788 | fprintf (stderr, "fatal error: out of memory\n"); |
870 | fprintf (stderr, "fatal error: out of memory\n"); |
789 | exit (1); |
871 | exit (1); |
790 | } |
872 | } |
791 | memcpy (data_buffer, |
873 | memcpy (data_buffer, entry_parms->precompiled_data, data_len); |
792 | data_len = INITIAL_STARTUP_SCRIPT_LEN; |
- | |
793 | image_bootscript_ino = inode_count + 1; // save boot script inode number for image header |
- | |
794 | } |
874 | } |
795 | else // else |
875 | else // else use the supplied data blob |
796 | { |
876 | { |
797 | data_len = entry_datalen; |
877 | data_len = entry_datalen; |
798 | mtime = (uint32_t) time (NULL); |
- | |
799 | - | ||
800 | data_buffer = malloc (data_len); |
878 | data_buffer = malloc (data_len); |
801 | if (data_buffer == NULL) |
879 | if (data_buffer == NULL) |
802 | { |
880 | { |
803 | fprintf (stderr, "fatal error: out of memory\n"); |
881 | fprintf (stderr, "fatal error: out of memory\n"); |
804 | exit (1); |
882 | exit (1); |
805 | } |
883 | } |
806 | memcpy (data_buffer, entry_data, data_len); |
884 | memcpy (data_buffer, entry_data, data_len); |
807 | } |
885 | } |
- | 886 | /* |
|
- | 887 | else if (entry_parms->should_compile_contents_as_startup_script) // should we compile this contents as a startup script ? |
|
- | 888 | { |
|
- | 889 | // HACK: for now just use a precompiled script |
|
- | 890 | // FIXME: replace this with a true compilation with the rules defined above |
|
- | 891 | data_buffer = malloc (INITIAL_STARTUP_SCRIPT_LEN); |
|
- | 892 | if (data_buffer == NULL) |
|
- | 893 | { |
|
- | 894 | fprintf (stderr, "fatal error: out of memory\n"); |
|
- | 895 | exit (1); |
|
- | 896 | } |
|
- | 897 | memcpy (data_buffer, INITIAL_STARTUP_SCRIPT, INITIAL_STARTUP_SCRIPT_LEN); |
|
- | 898 | data_len = INITIAL_STARTUP_SCRIPT_LEN; |
|
- | 899 | image_bootscript_ino = inode_count + 1; // save boot script inode number for image header |
|
- | 900 | }*/ |
|
808 | 901 | ||
809 | fprintf (stderr, "file: ino 0x%x uid %d gid %d mode 0%o path \"%s\" blob (len %zd)\n", extra_ino_flags | (inode_count + 1), entry_parms->uid, entry_parms->gid, entry_parms->st_mode, stored_pathname, data_len); |
902 | fprintf (stderr, "file: ino 0x%x uid %d gid %d mode 0%o path \"%s\" blob (len %zd)\n", extra_ino_flags | (inode_count + 1), entry_parms->uid, entry_parms->gid, entry_parms->st_mode, stored_pathname, data_len); |
810 | } |
903 | } |
811 | else if ((entry_data != NULL) && (entry_data[0] != 0)) // else entry_datalen == 0, was some sort of pathname supplied ? |
904 | else if ((entry_data != NULL) && (entry_data[0] != 0)) // else entry_datalen == 0, was some sort of pathname supplied ? |
812 | { |
905 | { |
Line 902... | Line 995... | ||
902 | } |
995 | } |
903 | } |
996 | } |
904 | else if (S_ISLNK (entry_parms->st_mode)) // else are we storing a symbolic link ? |
997 | else if (S_ISLNK (entry_parms->st_mode)) // else are we storing a symbolic link ? |
905 | { |
998 | { |
906 | data_len = strlen (entry_data); |
999 | data_len = strlen (entry_data); |
907 | mtime = (uint32_t) time (NULL); |
- | |
908 | 1000 | ||
909 | data_buffer = malloc (data_len + 1); |
1001 | data_buffer = malloc (data_len + 1); |
910 | if (data_buffer == NULL) |
1002 | if (data_buffer == NULL) |
911 | { |
1003 | { |
912 | fprintf (stderr, "fatal error: out of memory\n"); |
1004 | fprintf (stderr, "fatal error: out of memory\n"); |
Line 1008... | Line 1100... | ||
1008 | { |
1100 | { |
1009 | // program entrypoint |
1101 | // program entrypoint |
1010 | 1102 | ||
1011 | #define PAD_OUTFILE_TO(val) do { curr_offset = ftell (fp); while (curr_offset < (val)) { putc (0, fp); curr_offset++; } } while (0) |
1103 | #define PAD_OUTFILE_TO(val) do { curr_offset = ftell (fp); while (curr_offset < (val)) { putc (0, fp); curr_offset++; } } while (0) |
1012 | 1104 | ||
1013 | startup_header_t startup_header = { 0 }; // output IFS's startup header |
1105 | static startup_header_t startup_header = { 0 }; // output IFS's startup header |
1014 | startup_trailer_v2_t startup_trailer = { 0 }; // output IFS's startup trailer (version 2, with SHA-512 checksum and int32 checksum) |
1106 | static startup_trailer_v2_t startup_trailer = { 0 }; // output IFS's startup trailer (version 2, with SHA-512 checksum and int32 checksum) |
1015 | image_header_t image_header = { 0 }; // output IFS's imagefs header |
1107 | static image_header_t image_header = { 0 }; // output IFS's imagefs header |
1016 | image_trailer_v2_t image_trailer = { 0 }; // output IFS's imagefs trailer (version 2, with SHA-512 checksum and int32 checksum) |
1108 | static image_trailer_v2_t image_trailer = { 0 }; // output IFS's imagefs trailer (version 2, with SHA-512 checksum and int32 checksum) |
1017 | fsentry_t *fsentries = NULL; // output IFS's filesystem entries |
1109 | static fsentry_t *fsentries = NULL; // output IFS's filesystem entries |
1018 | size_t fsentry_count = 0; // number of entries in the IFS filesystem |
1110 | static size_t fsentry_count = 0; // number of entries in the IFS filesystem |
1019 | parms_t default_parms = { 0755, 0644, 0, 0, S_IFREG, "/proc/boot", false, "" }; // default parameters for a filesystem entry |
1111 | static parms_t default_parms = { 0755, 0644, 0, 0, S_IFREG, "/proc/boot", false, "", NULL, 0 }; // default parameters for a filesystem entry |
1020 | parms_t entry_parms = { 0 }; // current parameters for a filesystem entry (will be initialized to default_parms each time a new entry is parsed in the build file) |
1112 | static parms_t entry_parms = { 0 }; // current parameters for a filesystem entry (will be initialized to default_parms each time a new entry is parsed in the build file) |
1021 | 1113 | ||
1022 | // bootable IFS support |
1114 | // bootable IFS support |
1023 | char *bootfile_pathname = NULL; // HACK: pathname to bootcode binary blob file to put at the start of a bootable IFS |
1115 | char *bootfile_pathname = NULL; // HACK: pathname to bootcode binary blob file to put at the start of a bootable IFS |
- | 1116 | size_t bootfile_size = 0; // HACK: size of the bootcode binary blob file to put at the start of a bootable IFS |
|
1024 | char *startupfile_pathname = NULL; // HACK: pathname to precompiled startup file blob to put in the startup header of a bootable IFS |
1117 | char *startupfile_pathname = NULL; // HACK: pathname to precompiled startup file blob to put in the startup header of a bootable IFS |
1025 | size_t startupfile_ep_from_imagebase = 0; // HACK: startup code entrypoint offset from image base for a bootable IFS |
1118 | size_t startupfile_ep_from_imagebase = 0; // HACK: startup code entrypoint offset from image base for a bootable IFS |
1026 | char *kernelfile_pathname = NULL; // HACK: pathname to precompiled kernel file blob to put in a bootable IFS |
1119 | char *kernelfile_pathname = NULL; // HACK: pathname to precompiled kernel file blob to put in a bootable IFS |
1027 | size_t kernelfile_offset = 0; // HACK: kernel file offset in bootable IFS |
1120 | size_t kernelfile_offset = 0; // HACK: kernel file offset in bootable IFS |
1028 | 1121 | ||
1029 | char path_in_ifs[MAXPATHLEN]; |
1122 | char path_in_ifs[MAXPATHLEN]; |
1030 | char image_bootfile[MAXPATHLEN]; |
- | |
1031 | size_t image_bootfilesize = 0; |
- | |
1032 | char *ifs_pathname = NULL; |
1123 | char *ifs_pathname = NULL; |
1033 | void *reallocated_ptr; |
1124 | void *reallocated_ptr; |
1034 | struct stat stat_buf; |
1125 | struct stat stat_buf; |
1035 | size_t startuptrailer_offset; |
1126 | size_t startuptrailer_offset; |
1036 | size_t startupheader_offset; |
1127 | size_t startupheader_offset; |
Line 1099... | Line 1190... | ||
1099 | else if (ifs_pathname == NULL) |
1190 | else if (ifs_pathname == NULL) |
1100 | ifs_pathname = argv[arg_index]; |
1191 | ifs_pathname = argv[arg_index]; |
1101 | } |
1192 | } |
1102 | 1193 | ||
1103 | // do we not have enough information to run ? |
1194 | // do we not have enough information to run ? |
1104 | if (want_help || ( |
1195 | if (want_help || (buildfile_pathname == NULL) || (!want_info && (ifs_pathname == NULL))) |
1105 | { |
1196 | { |
1106 | if (want_help) |
1197 | if (want_help) |
1107 | fprintf (stdout, "ifstool - QNX in-kernel filesystem creation utility by Pierre-Marie Baty <pm@pmbaty.com>\n"); |
1198 | fprintf (stdout, "ifstool - QNX in-kernel filesystem creation utility by Pierre-Marie Baty <pm@pmbaty.com>\n"); |
1108 | else |
1199 | else |
1109 | fprintf (stderr, "error: missing parameters\n"); |
1200 | fprintf (stderr, "error: missing parameters\n"); |
Line 1111... | Line 1202... | ||
1111 | fprintf ((want_help ? stdout : stderr), " ifstool [--bootfile <pathname>] [--startupfile <pathname>@<EP_from_imgbase>] [--kernelfile <pathname>@<fileoffs>] <buildfile> <outfile>\n"); |
1202 | fprintf ((want_help ? stdout : stderr), " ifstool [--bootfile <pathname>] [--startupfile <pathname>@<EP_from_imgbase>] [--kernelfile <pathname>@<fileoffs>] <buildfile> <outfile>\n"); |
1112 | fprintf ((want_help ? stdout : stderr), " ifstool --info <ifs file>\n"); |
1203 | fprintf ((want_help ? stdout : stderr), " ifstool --info <ifs file>\n"); |
1113 | fprintf ((want_help ? stdout : stderr), " ifstool --help\n"); |
1204 | fprintf ((want_help ? stdout : stderr), " ifstool --help\n"); |
1114 | exit (want_help ? 0 : 1); |
1205 | exit (want_help ? 0 : 1); |
1115 | } |
1206 | } |
- | 1207 | ||
- | 1208 | // do we want info about a particular IFS ? if so, dump it |
|
- | 1209 | if (want_info) |
|
- | 1210 | exit (dump_ifs_info (buildfile_pathname)); // NOTE: the first argument after --info is actually the IFS file, not a build file, but the arguments are collected in this order |
|
1116 | 1211 | ||
1117 | // make sure we have ${QNX_TARGET} pointing somewhere |
1212 | // make sure we have ${QNX_TARGET} pointing somewhere |
1118 | QNX_TARGET = getenv ("QNX_TARGET"); |
1213 | QNX_TARGET = getenv ("QNX_TARGET"); |
1119 | if (QNX_TARGET == NULL) |
1214 | if (QNX_TARGET == NULL) |
1120 | { |
1215 | { |
Line 1214... | Line 1309... | ||
1214 | *sep = 0; |
1309 | *sep = 0; |
1215 | strcpy (image_processor, value); // save processor |
1310 | strcpy (image_processor, value); // save processor |
1216 | value = sep + 1; |
1311 | value = sep + 1; |
1217 | } |
1312 | } |
1218 | //sprintf (image_bootfile, "%s/%s/boot/sys/%s.boot", QNX_TARGET, image_processor, value); // save preboot file name (FIXME: we should search in MKIFS_PATH instead of this. Not important.) |
1313 | //sprintf (image_bootfile, "%s/%s/boot/sys/%s.boot", QNX_TARGET, image_processor, value); // save preboot file name (FIXME: we should search in MKIFS_PATH instead of this. Not important.) |
1219 |
|
1314 | //strcpy (image_bootfile, bootfile_pathname); // FIXME: HACK |
1220 | if (stat ( |
1315 | if (stat (bootfile_pathname, &stat_buf) != 0) |
1221 | { |
1316 | { |
1222 | fprintf (stderr, "error: unable to stat the boot file \"%s\" specified in \"%s\" line %d: %s\n", |
1317 | fprintf (stderr, "error: unable to stat the boot file \"%s\" specified in \"%s\" line %d: %s\n", bootfile_pathname, buildfile_pathname, lineno, strerror (errno)); |
1223 | exit (1); |
1318 | exit (1); |
1224 | } |
1319 | } |
1225 |
|
1320 | bootfile_size = stat_buf.st_size; // save preboot file size |
1226 | fprintf (stderr, "info: processor \"%s\" bootfile \"%s\"\n", image_processor, |
1321 | fprintf (stderr, "info: processor \"%s\" bootfile \"%s\"\n", image_processor, bootfile_pathname); |
- | 1322 | if (stat (kernelfile_pathname, &stat_buf) != 0) |
|
- | 1323 | { |
|
- | 1324 | fprintf (stderr, "fatal error: unable to read precompiled kernel file \"%s\" specified in --kernelfile argument\n", kernelfile_pathname); |
|
- | 1325 | exit (1); |
|
- | 1326 | } |
|
- | 1327 | entry_parms.precompiled_data = malloc (stat_buf.st_size); |
|
- | 1328 | if (entry_parms.precompiled_data == NULL) |
|
- | 1329 | { |
|
- | 1330 | fprintf (stderr, "fatal error: out of memory\n"); |
|
- | 1331 | exit (1); |
|
- | 1332 | } |
|
- | 1333 | fp = fopen ("procnto-smp-instr.bin", "rb"); |
|
- | 1334 | fread (entry_parms.precompiled_data, 1, stat_buf.st_size, fp); |
|
- | 1335 | fclose (fp); |
|
- | 1336 | entry_parms.precompiled_datalen = stat_buf.st_size; |
|
- | 1337 | } |
|
- | 1338 | else if (strcmp (token, "+script") == 0) { |
|
- | 1339 | entry_parms.is_compiled_bootscript = true; |
|
- | 1340 | entry_parms.precompiled_data = INITIAL_STARTUP_SCRIPT; // HACK until the script compiler is implemented |
|
- | 1341 | entry_parms.precompiled_datalen = sizeof (INITIAL_STARTUP_SCRIPT) - 1; |
|
1227 | } |
1342 | } |
1228 | else if (strcmp (token, "+script") == 0) entry_parms.should_compile_contents_as_startup_script = true; |
- | |
1229 | else fprintf (stderr, "warning: unimplemented attribute in \"%s\" line %d: '%s'\n", buildfile_pathname, lineno, token); |
1343 | else fprintf (stderr, "warning: unimplemented attribute in \"%s\" line %d: '%s'\n", buildfile_pathname, lineno, token); |
1230 | #undef REACH_TOKEN_VALUE |
1344 | #undef REACH_TOKEN_VALUE |
1231 | 1345 | ||
1232 | token = strtok (NULL, RECORD_SEP_STR); // proceed to next attribute token |
1346 | token = strtok (NULL, RECORD_SEP_STR); // proceed to next attribute token |
1233 | } |
1347 | } |
Line 1251... | Line 1365... | ||
1251 | APPLY_DEFAULT_ATTR_NUM (perms, "file permissions", "0%o"); |
1365 | APPLY_DEFAULT_ATTR_NUM (perms, "file permissions", "0%o"); |
1252 | APPLY_DEFAULT_ATTR_NUM (uid, "owner ID", "%d"); |
1366 | APPLY_DEFAULT_ATTR_NUM (uid, "owner ID", "%d"); |
1253 | APPLY_DEFAULT_ATTR_NUM (gid, "group ID", "%d"); |
1367 | APPLY_DEFAULT_ATTR_NUM (gid, "group ID", "%d"); |
1254 | APPLY_DEFAULT_ATTR_NUM (st_mode, "inode type", "0%o"); |
1368 | APPLY_DEFAULT_ATTR_NUM (st_mode, "inode type", "0%o"); |
1255 | APPLY_DEFAULT_ATTR_STR (prefix, "prefix", "\"%s\""); |
1369 | APPLY_DEFAULT_ATTR_STR (prefix, "prefix", "\"%s\""); |
1256 | APPLY_DEFAULT_ATTR_NUM ( |
1370 | APPLY_DEFAULT_ATTR_NUM (is_compiled_bootscript, "compiled script state", "%d"); |
1257 | #undef APPLY_DEFAULT_ATTR_STR |
1371 | #undef APPLY_DEFAULT_ATTR_STR |
1258 | #undef APPLY_DEFAULT_ATTR_NUM |
1372 | #undef APPLY_DEFAULT_ATTR_NUM |
1259 | continue; // end of line reached, proceed to the next line |
1373 | continue; // end of line reached, proceed to the next line |
1260 | } |
1374 | } |
1261 | // end of attributes parsing |
1375 | // end of attributes parsing |
Line 1387... | Line 1501... | ||
1387 | { |
1501 | { |
1388 | fprintf (stderr, "error: failed to open \"%s\" for writing (%s)\n", ifs_pathname, strerror (errno)); |
1502 | fprintf (stderr, "error: failed to open \"%s\" for writing (%s)\n", ifs_pathname, strerror (errno)); |
1389 | exit (1); |
1503 | exit (1); |
1390 | } |
1504 | } |
1391 | 1505 | ||
1392 | // do we have a |
1506 | // do we have a startup file ? if so, this is a bootable image |
1393 | if ( |
1507 | if (startupfile_pathname != NULL) |
1394 | { |
1508 | { |
1395 | // write boot prefix |
1509 | // write boot prefix |
1396 | fwrite_filecontents ( |
1510 | fwrite_filecontents (bootfile_pathname, fp); |
1397 | PAD_OUTFILE_TO (ROUND_TO_UPPER_MULTIPLE (ftell (fp), image_align)); // pad as necessary |
1511 | PAD_OUTFILE_TO (ROUND_TO_UPPER_MULTIPLE (ftell (fp), image_align)); // pad as necessary |
1398 | 1512 | ||
1399 | startupheader_offset = ftell (fp); // save startup header offset |
1513 | startupheader_offset = ftell (fp); // save startup header offset |
1400 | memset (&startup_header, 0, sizeof (startup_header)); // prepare startup header |
1514 | memset (&startup_header, 0, sizeof (startup_header)); // prepare startup header |
1401 | memcpy (startup_header.signature, "\xeb\x7e\xff\x00", 4); // startup header signature, i.e. 0xff7eeb |
1515 | memcpy (startup_header.signature, "\xeb\x7e\xff\x00", 4); // startup header signature, i.e. 0xff7eeb |
Line 1410... | Line 1524... | ||
1410 | { |
1524 | { |
1411 | fprintf (stderr, "fatal error: unsupported processor type '%s' found in build file \"%s\"\n", image_processor, buildfile_pathname); |
1525 | fprintf (stderr, "fatal error: unsupported processor type '%s' found in build file \"%s\"\n", image_processor, buildfile_pathname); |
1412 | exit (1); |
1526 | exit (1); |
1413 | } |
1527 | } |
1414 | startup_header.startup_vaddr = image_base + (uint32_t) startupfile_ep_from_imagebase; // [I ] Virtual Address to transfer to after IPL is done, here 0x01403008 (appears in "Entry" column for "startup.*") |
1528 | startup_header.startup_vaddr = image_base + (uint32_t) startupfile_ep_from_imagebase; // [I ] Virtual Address to transfer to after IPL is done, here 0x01403008 (appears in "Entry" column for "startup.*") |
1415 | startup_header.image_paddr = image_base + (uint32_t) |
1529 | startup_header.image_paddr = image_base + (uint32_t) bootfile_size; // F[IS] Physical address of image, here 0x01400f30 (appears in "Offset" column for "startup-header" which is the first entry/start of file) |
1416 | startup_header.ram_paddr = startup_header.image_paddr; // [IS] Physical address of RAM to copy image to (startup_size bytes copied), here 0x01400f30 (same as above) |
1530 | startup_header.ram_paddr = startup_header.image_paddr; // [IS] Physical address of RAM to copy image to (startup_size bytes copied), here 0x01400f30 (same as above) |
1417 | startup_header.ram_size = WILL_BE_FILLED_LATER; // [ S] Amount of RAM used by the startup program and executables contained in the file system, here 0x00cd6128 i.e. 13 459 752 dec. which is 13 Mb. i.e. IFS file size minus 0x9eee (40686) |
1531 | startup_header.ram_size = WILL_BE_FILLED_LATER; // [ S] Amount of RAM used by the startup program and executables contained in the file system, here 0x00cd6128 i.e. 13 459 752 dec. which is 13 Mb. i.e. IFS file size minus 0x9eee (40686) |
1418 | startup_header.startup_size = WILL_BE_FILLED_LATER; // [I ] Size of startup (never compressed), here 0x02f148 or 192 840 bytes |
1532 | startup_header.startup_size = WILL_BE_FILLED_LATER; // [I ] Size of startup (never compressed), here 0x02f148 or 192 840 bytes |
1419 | startup_header.stored_size = |
1533 | startup_header.stored_size = WILL_BE_FILLED_LATER; // [I ] Size of entire image, here 0x00cd6128 (same as ram_size) |
1420 | startup_header.imagefs_size = WILL_BE_FILLED_LATER; // [ S] Size of uncompressed imagefs, here 0x00ca6fe0 or 13 266 912 bytes |
1534 | startup_header.imagefs_size = WILL_BE_FILLED_LATER; // [ S] Size of uncompressed imagefs, here 0x00ca6fe0 or 13 266 912 bytes |
1421 | startup_header.preboot_size = (uint16_t) |
1535 | startup_header.preboot_size = (uint16_t) bootfile_size; // [I ] Size of loaded before header, here 0xf30 or 3888 bytes (size of "bios.boot" file)) |
1422 | fwrite (&startup_header, sizeof (startup_header), 1, fp); // write startup header |
1536 | fwrite (&startup_header, sizeof (startup_header), 1, fp); // write startup header |
1423 | PAD_OUTFILE_TO (ROUND_TO_UPPER_MULTIPLE (ftell (fp), image_align)); // pad as necessary |
1537 | PAD_OUTFILE_TO (ROUND_TO_UPPER_MULTIPLE (ftell (fp), image_align)); // pad as necessary |
1424 | 1538 | ||
1425 | // ###################################################################################################################################################################################################################################### |
1539 | // ###################################################################################################################################################################################################################################### |
1426 | // # FIXME: figure out how to re-create it: linker call involved |
1540 | // # FIXME: figure out how to re-create it: linker call involved |
Line 1452... | Line 1566... | ||
1452 | for (fsentry_index = 0; fsentry_index < fsentry_count; fsentry_index++) |
1566 | for (fsentry_index = 0; fsentry_index < fsentry_count; fsentry_index++) |
1453 | fwrite_fsentry (&fsentries[fsentry_index], fp); |
1567 | fwrite_fsentry (&fsentries[fsentry_index], fp); |
1454 | PAD_OUTFILE_TO (ROUND_TO_UPPER_MULTIPLE (ftell (fp), image_align)); // pad as necessary |
1568 | PAD_OUTFILE_TO (ROUND_TO_UPPER_MULTIPLE (ftell (fp), image_align)); // pad as necessary |
1455 | 1569 | ||
1456 | // is it a bootable image with a kernel file ? |
1570 | // is it a bootable image with a kernel file ? |
1457 | if (( |
1571 | if ((startupfile_pathname != NULL) && (kernelfile_pathname != NULL)) |
1458 | { |
1572 | { |
1459 | // sort the filesystem entries by sizes |
1573 | // sort the filesystem entries by sizes |
1460 | qsort (fsentries, fsentry_count, sizeof (fsentry_t), fsentry_compare_sizes_cb); |
1574 | qsort (fsentries, fsentry_count, sizeof (fsentry_t), fsentry_compare_sizes_cb); |
1461 | 1575 | ||
1462 | // write as many small files as we can before reaching the kernel offset |
1576 | // write as many small files as we can before reaching the kernel offset |
Line 1508... | Line 1622... | ||
1508 | { |
1622 | { |
1509 | fprintf (stderr, "error: image file \"%s\" size %zd exceeds max size (%zd)\n", ifs_pathname, final_size, (size_t) image_maxsize); |
1623 | fprintf (stderr, "error: image file \"%s\" size %zd exceeds max size (%zd)\n", ifs_pathname, final_size, (size_t) image_maxsize); |
1510 | exit (1); |
1624 | exit (1); |
1511 | } |
1625 | } |
1512 | 1626 | ||
1513 | // do we have a |
1627 | // do we have a startup file ? if so, this is a bootable image |
1514 | if ( |
1628 | if (startupfile_pathname != NULL) |
1515 | { |
1629 | { |
1516 | // rewrite startup header with final values |
1630 | // rewrite startup header with final values |
1517 | fseek (fp, startupheader_offset, SEEK_SET); |
1631 | fseek (fp, startupheader_offset, SEEK_SET); |
1518 | startup_header.startup_size = (uint32_t) (imgheader_offset - startupheader_offset); // size of startup header up to image header |
1632 | startup_header.startup_size = (uint32_t) (imgheader_offset - startupheader_offset); // size of startup header up to image header |
1519 | startup_header.imagefs_size = (uint32_t) (final_size - imgheader_offset); // size of uncompressed imagefs |
1633 | startup_header.imagefs_size = (uint32_t) (final_size - imgheader_offset); // size of uncompressed imagefs |
1520 | startup_header.ram_size = (uint32_t) final_size; // FIXME: this is necessarily a bit less, but should we really bother calculating the right size ? |
1634 | startup_header.ram_size = (uint32_t) final_size; // FIXME: this is necessarily a bit less, but should we really bother calculating the right size ? |
- | 1635 | startup_header.stored_size = startup_header.ram_size; |
|
1521 | fwrite (&startup_header, sizeof (startup_header), 1, fp); // write startup header |
1636 | fwrite (&startup_header, sizeof (startup_header), 1, fp); // write startup header |
1522 | 1637 | ||
1523 | // compute SHA-512 checksum and V1 checksum of startup block |
1638 | // compute SHA-512 checksum and V1 checksum of startup block |
1524 | blob_datasize = startuptrailer_offset - startupheader_offset; |
1639 | blob_datasize = startuptrailer_offset - startupheader_offset; |
1525 | blob_data = malloc (blob_datasize); |
1640 | blob_data = malloc (blob_datasize); |
Line 1530... | Line 1645... | ||
1530 | } |
1645 | } |
1531 | fseek (fp, startupheader_offset, SEEK_SET); |
1646 | fseek (fp, startupheader_offset, SEEK_SET); |
1532 | fread (blob_data, 1, blob_datasize, fp); |
1647 | fread (blob_data, 1, blob_datasize, fp); |
1533 | SHA512 (blob_data, blob_datasize, startup_trailer.sha512); // compute SHA512 checksum |
1648 | SHA512 (blob_data, blob_datasize, startup_trailer.sha512); // compute SHA512 checksum |
1534 | startup_trailer.cksum = 0; // compute old checksum |
1649 | startup_trailer.cksum = 0; // compute old checksum |
1535 | startup_trailer.cksum = |
1650 | startup_trailer.cksum = update_checksum32 (startup_trailer.cksum, (const uint32_t *) blob_data, blob_datasize); |
1536 | startup_trailer.cksum = |
1651 | startup_trailer.cksum = update_checksum32 (startup_trailer.cksum, (const uint32_t *) startup_trailer.sha512, sizeof (startup_trailer.sha512)); |
1537 | free (blob_data); |
1652 | free (blob_data); |
1538 | 1653 | ||
1539 | // rewrite startup trailer with final values |
1654 | // rewrite startup trailer with final values |
1540 | fseek (fp, startuptrailer_offset, SEEK_SET); |
1655 | fseek (fp, startuptrailer_offset, SEEK_SET); |
1541 | fwrite (&startup_trailer, sizeof (startup_trailer), 1, fp); // write startup trailer |
1656 | fwrite (&startup_trailer, sizeof (startup_trailer), 1, fp); // write startup trailer |
Line 1561... | Line 1676... | ||
1561 | } |
1676 | } |
1562 | fseek (fp, imgheader_offset, SEEK_SET); |
1677 | fseek (fp, imgheader_offset, SEEK_SET); |
1563 | fread (blob_data, 1, blob_datasize, fp); |
1678 | fread (blob_data, 1, blob_datasize, fp); |
1564 | SHA512 (blob_data, blob_datasize, image_trailer.sha512); // compute SHA512 checksum |
1679 | SHA512 (blob_data, blob_datasize, image_trailer.sha512); // compute SHA512 checksum |
1565 | image_trailer.cksum = 0; // compute old checksum |
1680 | image_trailer.cksum = 0; // compute old checksum |
1566 | image_trailer.cksum = |
1681 | image_trailer.cksum = update_checksum32 (image_trailer.cksum, (const uint32_t *) blob_data, blob_datasize); |
1567 | image_trailer.cksum = |
1682 | image_trailer.cksum = update_checksum32 (image_trailer.cksum, (const uint32_t *) image_trailer.sha512, sizeof (image_trailer.sha512)); |
1568 | free (blob_data); |
1683 | free (blob_data); |
1569 | 1684 | ||
1570 | // rewrite image trailer with final checksum values |
1685 | // rewrite image trailer with final checksum values |
1571 | fseek (fp, imgtrailer_offset, SEEK_SET); |
1686 | fseek (fp, imgtrailer_offset, SEEK_SET); |
1572 | fwrite (&image_trailer, sizeof (image_trailer), 1, fp); // write image trailer |
1687 | fwrite (&image_trailer, sizeof (image_trailer), 1, fp); // write image trailer |
1573 | 1688 | ||
1574 | // finished, close IFS file and exit with a success code |
1689 | // finished, close IFS file and exit with a success code |
1575 | fclose (fp); |
1690 | fclose (fp); |
1576 | fprintf (stdout, "Success\n"); |
1691 | fprintf (stdout, "Success\n"); |
1577 | exit (0); |
1692 | exit (0); |
- | 1693 | } |
|
- | 1694 | ||
- | 1695 | ||
- | 1696 | static int dump_ifs_info (const char *ifs_pathname) |
|
- | 1697 | { |
|
- | 1698 | #define hex_printf(buf,size,...) hex_fprintf (stdout, (buf), (size), 16, __VA_ARGS__) // use 16 columns in hex output to stdout |
|
- | 1699 | #define BINARY(x) binary ((x), '-', 'x') |
|
- | 1700 | ||
- | 1701 | static const char *startupheader_flags1_strings[8] = { |
|
- | 1702 | "VIRTUAL", // bit 0 |
|
- | 1703 | "BIGENDIAN", // bit 1 |
|
- | 1704 | "COMPRESS_BIT1", // bit 2 |
|
- | 1705 | "COMPRESS_BIT2", // bit 3 |
|
- | 1706 | "COMPRESS_BIT3", // bit 4 |
|
- | 1707 | "TRAILER_V2", // bit 5 |
|
- | 1708 | "", // bit 6 |
|
- | 1709 | "", // bit 7 |
|
- | 1710 | }; |
|
- | 1711 | static const char *imageheader_flags_strings[8] = { |
|
- | 1712 | "BIGENDIAN", // bit 0 |
|
- | 1713 | "READONLY", // bit 1 |
|
- | 1714 | "INO_BITS", // bit 2 |
|
- | 1715 | "SORTED", // bit 3 |
|
- | 1716 | "TRAILER_V2", // bit 4 |
|
- | 1717 | "", // bit 5 |
|
- | 1718 | "", // bit 6 |
|
- | 1719 | "", // bit 7 |
|
- | 1720 | }; |
|
- | 1721 | ||
- | 1722 | startup_header_t *startup_header = NULL; |
|
- | 1723 | startup_trailer_v1_t *startup_trailer_v1 = NULL; |
|
- | 1724 | startup_trailer_v2_t *startup_trailer_v2 = NULL; |
|
- | 1725 | image_header_t *image_header = NULL; |
|
- | 1726 | size_t imageheader_offset = 0; |
|
- | 1727 | image_trailer_v1_t *image_trailer_v1 = NULL; |
|
- | 1728 | image_trailer_v2_t *image_trailer_v2 = NULL; |
|
- | 1729 | fsentry_t *current_fsentry = NULL; |
|
- | 1730 | char recorded_sha512[2 * SHA512_DIGEST_LENGTH + 1] = ""; |
|
- | 1731 | char computed_sha512[2 * SHA512_DIGEST_LENGTH + 1] = ""; |
|
- | 1732 | size_t startupfile_blobsize = 0; |
|
- | 1733 | size_t bootfile_blobsize = 0; |
|
- | 1734 | size_t current_offset; |
|
- | 1735 | size_t byte_index; |
|
- | 1736 | uint32_t recorded_checksum; |
|
- | 1737 | uint32_t computed_checksum; |
|
- | 1738 | uint8_t *filedata; |
|
- | 1739 | size_t filesize; |
|
- | 1740 | time_t mtime; |
|
- | 1741 | FILE *fp; |
|
- | 1742 | ||
- | 1743 | // open and read IFS file |
|
- | 1744 | fp = fopen (ifs_pathname, "rb"); |
|
- | 1745 | if (fp == NULL) |
|
- | 1746 | { |
|
- | 1747 | fprintf (stderr, "error: can't open \"%s\" for reading: %s\n", ifs_pathname, strerror (errno)); |
|
- | 1748 | return (1); |
|
- | 1749 | } |
|
- | 1750 | fseek (fp, 0, SEEK_END); |
|
- | 1751 | filesize = ftell (fp); |
|
- | 1752 | filedata = malloc (filesize); |
|
- | 1753 | if (filedata == NULL) |
|
- | 1754 | { |
|
- | 1755 | fprintf (stderr, "fatal error: out of memory\n"); |
|
- | 1756 | exit (1); |
|
- | 1757 | } |
|
- | 1758 | fseek (fp, 0, SEEK_SET); |
|
- | 1759 | fread (filedata, 1, filesize, fp); |
|
- | 1760 | fclose (fp); |
|
- | 1761 | ||
- | 1762 | printf ("IFS file \"%s\" - size 0x%zx (%zd) bytes\n", ifs_pathname, filesize, filesize); |
|
- | 1763 | ||
- | 1764 | // parse file from start to end |
|
- | 1765 | current_offset = 0; |
|
- | 1766 | for (;;) |
|
- | 1767 | { |
|
- | 1768 | // does a startup header start here ? |
|
- | 1769 | if ((current_offset + sizeof (startup_header_t) < filesize) && (memcmp (&filedata[current_offset], "\xeb\x7e\xff\x00", 4) == 0)) |
|
- | 1770 | { |
|
- | 1771 | startup_header = (startup_header_t *) &filedata[current_offset]; |
|
- | 1772 | ||
- | 1773 | // layout: |
|
- | 1774 | // [STARTUP HEADER] |
|
- | 1775 | // (startup file blob) |
|
- | 1776 | // [STARTUP TRAILER v1 or v2] |
|
- | 1777 | ||
- | 1778 | printf ("\n"); |
|
- | 1779 | printf ("Startup header at offset 0x%zx (%zd):\n", current_offset, current_offset); |
|
- | 1780 | printf (" signature = %02x %02x %02x %02x - good\n", startup_header->signature[0], startup_header->signature[1], startup_header->signature[2], startup_header->signature[3]); |
|
- | 1781 | printf (" version = 0x%04x (%d) - %s\n", startup_header->version, startup_header->version, (startup_header->version == 1 ? "looks good" : "???")); |
|
- | 1782 | printf (" flags1 = 0x%02x (%s)\n", startup_header->flags1, describe_uint8 (startup_header->flags1, startupheader_flags1_strings)); |
|
- | 1783 | printf (" flags2 = 0x%02x (%s) - %s\n", startup_header->flags2, BINARY (startup_header->flags2), (startup_header->flags2 == 0 ? "looks good" : "???")); |
|
- | 1784 | printf (" header_size = 0x%04x (%d) - %s\n", startup_header->header_size, startup_header->header_size, (startup_header->header_size == sizeof (startup_header_t) ? "looks good" : "BAD")); |
|
- | 1785 | printf (" machine = 0x%04x (%d) - %s\n", startup_header->machine, startup_header->machine, (startup_header->machine == STARTUP_HDR_MACHINE_X86_64 ? "x86_64" : (startup_header->machine == STARTUP_HDR_MACHINE_AARCH64 ? "aarch64" : "unknown"))); |
|
- | 1786 | printf (" startup_vaddr = 0x%08x (%d) - virtual address to transfer to after IPL is done\n", startup_header->startup_vaddr, startup_header->startup_vaddr); |
|
- | 1787 | printf (" paddr_bias = 0x%08x (%d) - value to add to physical addresses to get an indirectable pointer value\n", startup_header->paddr_bias, startup_header->paddr_bias); |
|
- | 1788 | printf (" image_paddr = 0x%08x (%d) - physical address of image\n", startup_header->image_paddr, startup_header->image_paddr); |
|
- | 1789 | printf (" ram_paddr = 0x%08x (%d) - physical address of RAM to copy image to (startup_size bytes copied)\n", startup_header->ram_paddr, startup_header->ram_paddr); |
|
- | 1790 | printf (" ram_size = 0x%08x (%d) - amount of RAM used by the startup program and executables in the fs\n", startup_header->ram_size, startup_header->ram_size); |
|
- | 1791 | printf (" startup_size = 0x%08x (%d) - size of startup (never compressed) - %s\n", startup_header->startup_size, startup_header->startup_size, (current_offset + sizeof (image_header_t) + startup_header->startup_size + (startup_header->flags1 & STARTUP_HDR_FLAGS1_TRAILER_V2 ? sizeof (image_trailer_v2_t) : sizeof (image_trailer_v1_t)) < filesize ? "looks good" : "BAD (IFS file too short)")); |
|
- | 1792 | printf (" stored_size = 0x%08x (%d) - size of entire image - %s\n", startup_header->stored_size, startup_header->stored_size, (startup_header->stored_size == startup_header->ram_size ? "looks good" : "???")); |
|
- | 1793 | printf (" imagefs_paddr = 0x%08x (%d) - set by IPL when startup runs - %s\n", startup_header->imagefs_paddr, startup_header->imagefs_paddr, (startup_header->imagefs_paddr == 0 ? "looks good" : "??? should be zero")); |
|
- | 1794 | printf (" imagefs_size = 0x%08x (%d) - size of uncompressed imagefs\n", startup_header->imagefs_size, startup_header->imagefs_size); |
|
- | 1795 | printf (" preboot_size = 0x%04x (%d) - size of loaded before header - %s\n", startup_header->preboot_size, startup_header->preboot_size, (startup_header->preboot_size == current_offset ? "looks good" : "???")); |
|
- | 1796 | printf (" zero0 = 0x%04x (%d) - zeros - %s\n", startup_header->zero0, startup_header->zero0, (startup_header->zero0 == 0 ? "looks good" : "??? should be zero")); |
|
- | 1797 | printf (" zero[0] = 0x%08x (%d) - zeros - %s\n", startup_header->zero[0], startup_header->zero[0], (startup_header->zero[0] == 0 ? "looks good" : "??? should be zero")); |
|
- | 1798 | printf (" addr_off = 0x%016llx (%lld) - offset for startup_vaddr and [image|ram|imagefs]_paddr - %s\n", startup_header->addr_off, startup_header->addr_off, (startup_header->addr_off == 0 ? "looks good" : "??? should be zero")); |
|
- | 1799 | hex_printf ((uint8_t *) &startup_header->info[0], sizeof (startup_header->info), " info[48] =\n"); |
|
- | 1800 | ||
- | 1801 | // validate that the file can contain up to the startup trailer |
|
- | 1802 | if (current_offset + startup_header->startup_size > filesize) |
|
- | 1803 | { |
|
- | 1804 | fprintf (stderr, "WARNING: this IFS file is too short (startup trailer would be past end of file)\n"); |
|
- | 1805 | break; |
|
- | 1806 | } |
|
- | 1807 | ||
- | 1808 | // locate the right startup trailer at the right offset |
|
- | 1809 | if (startup_header->flags1 & STARTUP_HDR_FLAGS1_TRAILER_V2) |
|
- | 1810 | { |
|
- | 1811 | startup_trailer_v2 = (startup_trailer_v2_t *) &filedata[current_offset + startup_header->startup_size - sizeof (startup_trailer_v2_t)]; |
|
- | 1812 | startupfile_blobsize = startup_header->startup_size - sizeof (startup_header_t) - sizeof (startup_trailer_v2_t); |
|
- | 1813 | } |
|
- | 1814 | else // old V1 trailer |
|
- | 1815 | { |
|
- | 1816 | startup_trailer_v1 = (startup_trailer_v1_t *) &filedata[current_offset + startup_header->startup_size - sizeof (startup_trailer_v1_t)]; |
|
- | 1817 | startupfile_blobsize = startup_header->startup_size - sizeof (startup_header_t) - sizeof (startup_trailer_v1_t); |
|
- | 1818 | } |
|
- | 1819 | ||
- | 1820 | current_offset += sizeof (startup_header_t); // jump over the startup header and reach the startup blob |
|
- | 1821 | printf ("\n"); |
|
- | 1822 | printf ("Startup blob at offset 0x%zx (%zd):\n", current_offset, current_offset); |
|
- | 1823 | printf (" size 0x%zx (%zd) bytes\n", startupfile_blobsize, startupfile_blobsize); |
|
- | 1824 | printf (" checksum %d\n", update_checksum32 (0, (uint32_t *) &filedata[current_offset], startupfile_blobsize)); |
|
- | 1825 | ||
- | 1826 | current_offset += startupfile_blobsize; // jump over the startup blob and reach the startup trailer |
|
- | 1827 | printf ("\n"); |
|
- | 1828 | printf ("Startup trailer at offset 0x%zx (%zd) - version %d:\n", current_offset, current_offset, (startup_header->flags1 & STARTUP_HDR_FLAGS1_TRAILER_V2 ? 2 : 1)); |
|
- | 1829 | if (startup_header->flags1 & STARTUP_HDR_FLAGS1_TRAILER_V2) |
|
- | 1830 | { |
|
- | 1831 | for (byte_index = 0; byte_index < SHA512_DIGEST_LENGTH; byte_index++) |
|
- | 1832 | sprintf (&recorded_sha512[2 * byte_index], "%02x", startup_trailer_v2->sha512[byte_index]); |
|
- | 1833 | strcpy (computed_sha512, SHA512 (startup_header, (size_t) ((uint8_t *) startup_trailer_v2 - (uint8_t *) startup_header), NULL)); |
|
- | 1834 | recorded_checksum = startup_trailer_v2->cksum; |
|
- | 1835 | computed_checksum = update_checksum32 (0, (uint32_t *) startup_header, sizeof (startup_header) + startupfile_blobsize + SHA512_DIGEST_LENGTH); |
|
- | 1836 | printf (" sha512 = %s - %s\n", recorded_sha512, (strcasecmp (computed_sha512, recorded_sha512) == 0 ? "GOOD" : "BAD")); |
|
- | 1837 | printf (" cksum = 0x%08x (%d) - %s\n", recorded_checksum, recorded_checksum, (computed_checksum == recorded_checksum ? "GOOD" : "BAD")); |
|
- | 1838 | if (strcasecmp (computed_sha512, recorded_sha512) != 0) |
|
- | 1839 | printf ("Computed SHA-512: %s\n", computed_sha512); |
|
- | 1840 | if (computed_checksum != recorded_checksum) |
|
- | 1841 | printf ("Computed cksum: 0x%08x (%d)\n", computed_checksum, computed_checksum); |
|
- | 1842 | } |
|
- | 1843 | else // old v1 trailer |
|
- | 1844 | { |
|
- | 1845 | recorded_checksum = startup_trailer_v1->cksum; |
|
- | 1846 | computed_checksum = update_checksum32 (0, (uint32_t *) startup_header, sizeof (startup_header) + startupfile_blobsize); |
|
- | 1847 | printf (" cksum = 0x%08x (%d) - %s\n", recorded_checksum, recorded_checksum, (computed_checksum == recorded_checksum ? "GOOD" : "BAD")); |
|
- | 1848 | if (computed_checksum != recorded_checksum) |
|
- | 1849 | printf ("Computed cksum: 0x%08x (%d)\n", computed_checksum, computed_checksum); |
|
- | 1850 | } |
|
- | 1851 | ||
- | 1852 | current_offset += (startup_header->flags1 & STARTUP_HDR_FLAGS1_TRAILER_V2 ? sizeof (image_trailer_v2_t) : sizeof (image_trailer_v1_t)); // now reach the next segment |
|
- | 1853 | } |
|
- | 1854 | ||
- | 1855 | // else does an image header start here ? |
|
- | 1856 | else if ((current_offset + sizeof (image_header_t) < filesize) && (memcmp (&filedata[current_offset], "imagefs", 7) == 0)) |
|
- | 1857 | { |
|
- | 1858 | imageheader_offset = current_offset; |
|
- | 1859 | image_header = (image_header_t *) &filedata[imageheader_offset]; |
|
- | 1860 | ||
- | 1861 | // layout: |
|
- | 1862 | // [IMAGE HEADER] |
|
- | 1863 | // [image directory entries] |
|
- | 1864 | // [file blobs up to KERNEL] |
|
- | 1865 | // [padding] |
|
- | 1866 | // [KERNEL] |
|
- | 1867 | // [file blobs] |
|
- | 1868 | // [IMAGE FOOTER] |
|
- | 1869 | ||
- | 1870 | printf ("\n"); |
|
- | 1871 | printf ("Image header at offset %zx (%zd):\n", current_offset, current_offset); |
|
- | 1872 | printf (" signature = %02x %02x %02x %02x %02x %02x %02x (\"%.7s\") - good\n", image_header->signature[0], image_header->signature[1], image_header->signature[2], image_header->signature[3], image_header->signature[4], image_header->signature[5], image_header->signature[6], image_header->signature); |
|
- | 1873 | printf (" flags = 0x%02x (%s)\n", image_header->flags, describe_uint8 (image_header->flags, imageheader_flags_strings)); |
|
- | 1874 | printf (" image_size = 0x%08x (%d) - size from header to end of trailer - %s\n", image_header->image_size, image_header->image_size, (current_offset + image_header->image_size <= filesize ? "looks good" : "BAD (IFS file too short)")); |
|
- | 1875 | printf (" hdr_dir_size = 0x%08x (%d) - size from header to last dirent - %s\n", image_header->hdr_dir_size, image_header->hdr_dir_size, (current_offset + image_header->hdr_dir_size < filesize ? "looks good" : "BAD (IFS file too short)")); |
|
- | 1876 | printf (" dir_offset = 0x%08x (%d) - offset from header to first dirent - %s\n", image_header->dir_offset, image_header->dir_offset, (current_offset + image_header->dir_offset >= filesize ? "BAD (IFS file too short)" : (image_header->dir_offset > image_header->hdr_dir_size ? "BAD" : "looks good"))); |
|
- | 1877 | printf (" boot_ino[4] = { 0x%08x, 0x%08x, 0x%08x, 0x%08x }\n", image_header->boot_ino[0], image_header->boot_ino[1], image_header->boot_ino[2], image_header->boot_ino[3]); |
|
- | 1878 | printf (" script_ino = 0x%08x (%d) - inode of compiled bootscript\n", image_header->script_ino, image_header->script_ino); |
|
- | 1879 | printf (" chain_paddr = 0x%08x (%d) - offset to next fs signature\n", image_header->chain_paddr, image_header->chain_paddr); |
|
- | 1880 | hex_printf ((uint8_t *) &image_header->spare[0], sizeof (image_header->spare), " spare[10] =\n"); |
|
- | 1881 | printf (" mountflags = 0x%08x (%s %s %s %s)\n", image_header->mountflags, BINARY (((uint8_t *) &image_header->mountflags)[0]), BINARY (((uint8_t *) &image_header->mountflags)[1]), BINARY (((uint8_t *) &image_header->mountflags)[2]), BINARY (((uint8_t *) &image_header->mountflags)[3])); |
|
- | 1882 | printf (" mountpoint = \"%s\"\n", image_header->mountpoint); |
|
- | 1883 | ||
- | 1884 | // validate that the file can contain up to the image trailer |
|
- | 1885 | if (current_offset + image_header->image_size > filesize) |
|
- | 1886 | { |
|
- | 1887 | fprintf (stderr, "WARNING: this IFS file is too short (image trailer would be past end of file)\n"); |
|
- | 1888 | break; |
|
- | 1889 | } |
|
- | 1890 | ||
- | 1891 | // locate the image trailer at the right offset |
|
- | 1892 | if (image_header->flags & IMAGE_FLAGS_TRAILER_V2) |
|
- | 1893 | image_trailer_v2 = (image_trailer_v2_t *) &filedata[current_offset + image_header->image_size - sizeof (image_trailer_v2_t)]; |
|
- | 1894 | else // old V1 trailer |
|
- | 1895 | image_trailer_v1 = (image_trailer_v1_t *) &filedata[current_offset + image_header->image_size - sizeof (image_trailer_v1_t)]; |
|
- | 1896 | ||
- | 1897 | current_offset += sizeof (image_header_t); // jump over the image header and reach the first directory entry |
|
- | 1898 | if (image_header->dir_offset - sizeof (image_header_t) > 0) |
|
- | 1899 | { |
|
- | 1900 | hex_printf (&filedata[current_offset], image_header->dir_offset - sizeof (image_header_t), "\n%d extra bytes at offset 0x%zd (%zd):\n", image_header->dir_offset - sizeof (image_header_t), current_offset, current_offset); |
|
- | 1901 | current_offset += image_header->dir_offset - sizeof (image_header_t); |
|
- | 1902 | } |
|
- | 1903 | ||
- | 1904 | // dump all directory entries until the last one included |
|
- | 1905 | while (&filedata[current_offset] < (uint8_t *) image_header + image_header->hdr_dir_size) |
|
- | 1906 | { |
|
- | 1907 | current_fsentry = (fsentry_t *) &filedata[current_offset]; |
|
- | 1908 | ||
- | 1909 | if (imageheader_offset + image_header->hdr_dir_size - current_offset < sizeof (current_fsentry->header)) |
|
- | 1910 | break; // end padding reached |
|
- | 1911 | ||
- | 1912 | printf ("\n"); |
|
- | 1913 | printf ("Filesystem entry at offset 0x%zx (%zd) - last one at 0x%zd (%zd):\n", current_offset, current_offset, imageheader_offset + image_header->hdr_dir_size, imageheader_offset + image_header->hdr_dir_size); |
|
- | 1914 | printf (" size = 0x%04x (%d) - size of dirent - %s\n", current_fsentry->header.size, current_fsentry->header.size, (current_offset + current_fsentry->header.size < filesize ? "looks good" : "BAD")); |
|
- | 1915 | printf (" extattr_offset = 0x%04x (%d) - %s\n", current_fsentry->header.extattr_offset, current_fsentry->header.extattr_offset, (current_fsentry->header.extattr_offset == 0 ? "no extattr" : "has extattr")); |
|
- | 1916 | printf (" ino = 0x%08x (%d) - inode number (%s%s%s%s)\n", current_fsentry->header.ino, current_fsentry->header.ino, (current_fsentry->header.ino & 0xE0000000 ? "is" : "nothing special"), (current_fsentry->header.ino & IFS_INO_PROCESSED_ELF ? " PROCESSED_ELF" : ""), (current_fsentry->header.ino & IFS_INO_RUNONCE_ELF ? " RUNONCE_ELF" : ""), (current_fsentry->header.ino & IFS_INO_BOOTSTRAP_EXE ? " BOOTSTRAP_EXE" : "")); |
|
- | 1917 | printf (" mode = 0x%08x (%d) - %s (0%o), POSIX permissions 0%o\n", current_fsentry->header.mode, current_fsentry->header.mode, (S_ISDIR (current_fsentry->header.mode) ? "directory" : (S_ISREG (current_fsentry->header.mode) ? "file" : (S_ISLNK (current_fsentry->header.mode) ? "symlink" : "device"))), (current_fsentry->header.mode & 0xF000) >> 12, current_fsentry->header.mode & 0xFFF); |
|
- | 1918 | printf (" gid = 0x%08x (%d) - owner group ID%s\n", current_fsentry->header.gid, current_fsentry->header.gid, (current_fsentry->header.gid == 0 ? " (root)" : "")); |
|
- | 1919 | printf (" uid = 0x%08x (%d) - owner user ID%s\n", current_fsentry->header.uid, current_fsentry->header.uid, (current_fsentry->header.uid == 0 ? " (root)" : "")); |
|
- | 1920 | mtime = (time_t) current_fsentry->header.mtime; |
|
- | 1921 | printf (" mtime = 0x%08x (%d) - POSIX timestamp: %s", current_fsentry->header.mtime, current_fsentry->header.mtime, asctime (localtime (&mtime))); // NOTE: asctime() provides the newline |
|
- | 1922 | if (S_ISDIR (current_fsentry->header.mode)) |
|
- | 1923 | printf (" [DIRECTORY] path = \"%s\"\n", (char *) ¤t_fsentry->u.dir.path); // convert from pointer to char array |
|
- | 1924 | else if (S_ISREG (current_fsentry->header.mode)) |
|
- | 1925 | { |
|
- | 1926 | printf (" [FILE] offset = 0x%08x (%d) - %s\n", current_fsentry->u.file.offset, current_fsentry->u.file.offset, (imageheader_offset + current_fsentry->u.file.offset < filesize ? "looks good" : "BAD (IFS file too short)")); |
|
- | 1927 | printf (" [FILE] size = 0x%08x (%d) - %s\n", current_fsentry->u.file.offset, current_fsentry->u.file.offset, (imageheader_offset + current_fsentry->u.file.offset + current_fsentry->u.file.size < filesize ? "looks good" : "BAD (IFS file too short)")); |
|
- | 1928 | printf (" [FILE] path = \"%s\"\n", (char *) ¤t_fsentry->u.file.path); // convert from pointer to char array |
|
- | 1929 | } |
|
- | 1930 | else if (S_ISLNK (current_fsentry->header.mode)) |
|
- | 1931 | { |
|
- | 1932 | printf (" [SYMLINK] sym_offset = 0x%04x (%d) - %s\n", current_fsentry->u.symlink.sym_offset, current_fsentry->u.symlink.sym_offset, (sizeof (current_fsentry->header) + 2 * sizeof (uint16_t) + current_fsentry->u.symlink.sym_offset <= current_fsentry->header.size ? "looks good" : "BAD (dirent too short)")); |
|
- | 1933 | printf (" [SYMLINK] sym_size = 0x%04x (%d) - %s\n", current_fsentry->u.symlink.sym_offset, current_fsentry->u.symlink.sym_offset, (sizeof (current_fsentry->header) + 2 * sizeof (uint16_t) + current_fsentry->u.symlink.sym_offset + current_fsentry->u.symlink.sym_size <= current_fsentry->header.size ? "looks good" : "BAD (dirent too short)")); |
|
- | 1934 | printf (" [SYMLINK] path = \"%s\"\n", (char *) ¤t_fsentry->u.symlink.path); // convert from pointer to char array |
|
- | 1935 | printf (" [SYMLINK] contents = \"%s\"\n", ((char *) ¤t_fsentry->u.symlink.path) + current_fsentry->u.symlink.sym_offset); // convert from pointer to char array |
|
- | 1936 | } |
|
- | 1937 | else // can only be a device |
|
- | 1938 | { |
|
- | 1939 | printf (" [DEVICE] dev = 0x%08x (%d)\n", current_fsentry->u.device.dev, current_fsentry->u.device.dev); |
|
- | 1940 | printf (" [DEVICE] rdev = 0x%08x (%d)\n", current_fsentry->u.device.rdev, current_fsentry->u.device.rdev); |
|
- | 1941 | printf (" [DEVICE] path = \"%s\"\n", (char *) ¤t_fsentry->u.device.path); // convert from pointer to char array |
|
- | 1942 | } |
|
- | 1943 | ||
- | 1944 | current_offset += current_fsentry->header.size; |
|
- | 1945 | } |
|
- | 1946 | if (imageheader_offset + image_header->hdr_dir_size - current_offset < sizeof (current_fsentry->header)) |
|
- | 1947 | hex_printf (&filedata[current_offset], imageheader_offset + image_header->hdr_dir_size - current_offset, "\n%d padding bytes at offset 0x%zx (%zd):\n", imageheader_offset + image_header->hdr_dir_size - current_offset, current_offset, current_offset); |
|
- | 1948 | ||
- | 1949 | ||
- | 1950 | // now jump at the first |
|
- | 1951 | ||
- | 1952 | exit (0); |
|
- | 1953 | } |
|
- | 1954 | ||
- | 1955 | // else it has to be a boot blob, of which we don't know the size, except that it has to fit in 0xffff bytes and be immediately followed by a startup header |
|
- | 1956 | else |
|
- | 1957 | { |
|
- | 1958 | // so scan for the first startup header magic and version (which makes us 6 bytes to scan for, i.e. "\xeb\x7e\xff\x00" for the magic and "\x01\x00" (LSB) for the version 1) |
|
- | 1959 | for (byte_index = current_offset; byte_index < filesize - 6; byte_index++) |
|
- | 1960 | if (memcmp (&filedata[byte_index], "\xeb\x7e\xff\x00" "\x01\x00", 4 + 2) == 0) |
|
- | 1961 | break; // stop as soon as we find it |
|
- | 1962 | ||
- | 1963 | if (byte_index >= filesize - 6) |
|
- | 1964 | break; // if not found, stop scanning |
|
- | 1965 | ||
- | 1966 | bootfile_blobsize = byte_index - current_offset; |
|
- | 1967 | printf ("Boot blob at offset 0x%zx (%zd):\n", current_offset, current_offset); |
|
- | 1968 | printf (" size 0x%zx (%zd) bytes\n", bootfile_blobsize, bootfile_blobsize); |
|
- | 1969 | printf (" checksum %d\n", update_checksum32 (0, (uint32_t *) &filedata[current_offset], bootfile_blobsize)); |
|
- | 1970 | ||
- | 1971 | current_offset = byte_index; // now reach the next segment |
|
- | 1972 | } |
|
- | 1973 | } |
|
- | 1974 | ||
- | 1975 | printf ("End of identifiable data reached.\n"); |
|
- | 1976 | if (current_offset < filesize) |
|
- | 1977 | hex_printf (&filedata[current_offset], filesize - current_offset, "\n%d extra bytes at offset %zx (%zd):\n", filesize - current_offset, current_offset, current_offset); |
|
- | 1978 | printf ("End of file reached at offset 0x%zx (%zd).\n", filesize, filesize); |
|
- | 1979 | ||
- | 1980 | return (0); |
|
1578 | } |
1981 | } |