Rev 6 | Rev 8 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 6 | Rev 7 | ||
---|---|---|---|
Line 12... | Line 12... | ||
12 | #include <time.h> |
12 | #include <time.h> |
13 | 13 | ||
14 | 14 | ||
15 | #ifdef _MSC_VER |
15 | #ifdef _MSC_VER |
16 | #include <io.h> |
16 | #include <io.h> |
- | 17 | #define __x86_64__ 1 |
|
17 | #define __ORDER_BIG_ENDIAN__ 4321 |
18 | #define __ORDER_BIG_ENDIAN__ 4321 |
18 | #define __ORDER_LITTLE_ENDIAN__ 1234 |
19 | #define __ORDER_LITTLE_ENDIAN__ 1234 |
19 | #define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__ |
20 | #define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__ |
20 | #define __attribute__(x) |
21 | #define __attribute__(x) |
- | 22 | #define __builtin_bswap16(x) _byteswap_ushort ((unsigned short) (x)) |
|
21 | #define __builtin_bswap32(x) _byteswap_ulong ((unsigned long) (x)) |
23 | #define __builtin_bswap32(x) _byteswap_ulong ((unsigned long) (x)) |
22 | #define __builtin_bswap64(x) _byteswap_uint64 ((unsigned long long) (x)) |
24 | #define __builtin_bswap64(x) _byteswap_uint64 ((unsigned long long) (x)) |
23 | #define S_IFIFO 0x1000 |
25 | #define S_IFIFO 0x1000 |
24 | #define S_IFLNK 0xa000 |
26 | #define S_IFLNK 0xa000 |
25 | #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) |
27 | #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) |
Line 31... | Line 33... | ||
31 | #define access(p,m) _access ((p), (m)) |
33 | #define access(p,m) _access ((p), (m)) |
32 | #define MAXPATHLEN 1024 |
34 | #define MAXPATHLEN 1024 |
33 | #else // !_MSC_VER |
35 | #else // !_MSC_VER |
34 | #include <sys/param.h> |
36 | #include <sys/param.h> |
35 | #include <unistd.h> |
37 | #include <unistd.h> |
36 | #endif // _MSC_VER |
- | |
37 | - | ||
38 | #ifdef _MSC_VER |
- | |
39 | #pragma pack(push) |
- | |
40 | #pragma pack(1) |
- | |
41 | #endif // _MSC_VER |
38 | #endif // _MSC_VER |
42 | 39 | ||
43 | 40 | ||
44 | // handy macros that generate a version number in the format "YYYYMMDD" corresponding to the build date. Usage: printf ("version " VERSION_FMT_YYYYMMDD "\n", VERSION_ARG_YYYYMMDD); |
41 | // handy macros that generate a version number in the format "YYYYMMDD" corresponding to the build date. Usage: printf ("version " VERSION_FMT_YYYYMMDD "\n", VERSION_ARG_YYYYMMDD); |
- | 42 | #ifndef VERSION_ARG_YYYYMMDD |
|
45 | #define BUILDDATE_YEAR (&__DATE__[7]) // compiler will optimize this into a const string, e.g. "2021" |
43 | #define BUILDDATE_YEAR (&__DATE__[7]) // compiler will optimize this into a const string, e.g. "2021" |
46 | #define BUILDDATE_MONTH (*((uint32_t |
44 | #define BUILDDATE_MONTH (*((uint32_t *) __DATE__) == *((uint32_t *) "Jan ") ? "01" : \ |
47 | (*((uint32_t |
45 | (*((uint32_t *) __DATE__) == *((uint32_t *) "Feb ") ? "02" : \ |
48 | (*((uint32_t |
46 | (*((uint32_t *) __DATE__) == *((uint32_t *) "Mar ") ? "03" : \ |
49 | (*((uint32_t |
47 | (*((uint32_t *) __DATE__) == *((uint32_t *) "Apr ") ? "04" : \ |
50 | (*((uint32_t |
48 | (*((uint32_t *) __DATE__) == *((uint32_t *) "May ") ? "05" : \ |
51 | (*((uint32_t |
49 | (*((uint32_t *) __DATE__) == *((uint32_t *) "Jun ") ? "06" : \ |
52 | (*((uint32_t |
50 | (*((uint32_t *) __DATE__) == *((uint32_t *) "Jul ") ? "07" : \ |
53 | (*((uint32_t |
51 | (*((uint32_t *) __DATE__) == *((uint32_t *) "Aug ") ? "08" : \ |
54 | (*((uint32_t |
52 | (*((uint32_t *) __DATE__) == *((uint32_t *) "Sep ") ? "09" : \ |
55 | (*((uint32_t |
53 | (*((uint32_t *) __DATE__) == *((uint32_t *) "Oct ") ? "10" : \ |
56 | (*((uint32_t |
54 | (*((uint32_t *) __DATE__) == *((uint32_t *) "Nov ") ? "11" : \ |
57 | (*((uint32_t |
55 | (*((uint32_t *) __DATE__) == *((uint32_t *) "Dec ") ? "12" : "XX")))))))))))) // compiler will optimize this into a const string, e.g. "11" |
58 | #define BUILDDATE_DAY (*(( |
56 | #define BUILDDATE_DAY (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 1 ") ? "01" : \ |
59 | (*(( |
57 | (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 2 ") ? "02" : \ |
60 | (*(( |
58 | (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 3 ") ? "03" : \ |
61 | (*(( |
59 | (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 4 ") ? "04" : \ |
62 | (*(( |
60 | (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 5 ") ? "05" : \ |
63 | (*(( |
61 | (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 6 ") ? "06" : \ |
64 | (*(( |
62 | (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 7 ") ? "07" : \ |
65 | (*(( |
63 | (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 8 ") ? "08" : \ |
66 | (*(( |
64 | (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 9 ") ? "09" : \ |
67 | (*(( |
65 | (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 10 ") ? "10" : \ |
68 | (*(( |
66 | (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 11 ") ? "11" : \ |
69 | (*(( |
67 | (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 12 ") ? "12" : \ |
70 | (*(( |
68 | (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 13 ") ? "13" : \ |
71 | (*(( |
69 | (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 14 ") ? "14" : \ |
72 | (*(( |
70 | (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 15 ") ? "15" : \ |
73 | (*(( |
71 | (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 16 ") ? "16" : \ |
74 | (*(( |
72 | (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 17 ") ? "17" : \ |
75 | (*(( |
73 | (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 18 ") ? "18" : \ |
76 | (*(( |
74 | (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 19 ") ? "19" : \ |
77 | (*(( |
75 | (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 20 ") ? "20" : \ |
78 | (*(( |
76 | (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 21 ") ? "21" : \ |
79 | (*(( |
77 | (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 22 ") ? "22" : \ |
80 | (*(( |
78 | (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 23 ") ? "23" : \ |
81 | (*(( |
79 | (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 24 ") ? "24" : \ |
82 | (*(( |
80 | (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 25 ") ? "25" : \ |
83 | (*(( |
81 | (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 26 ") ? "26" : \ |
84 | (*(( |
82 | (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 27 ") ? "27" : \ |
85 | (*(( |
83 | (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 28 ") ? "28" : \ |
86 | (*(( |
84 | (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 29 ") ? "29" : \ |
87 | (*(( |
85 | (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 30 ") ? "30" : \ |
88 | (*(( |
86 | (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 31 ") ? "31" : "XX"))))))))))))))))))))))))))))))) // compiler will optimize this into a const string, e.g. "14" |
89 | #define VERSION_FMT_YYYYMMDD "%04s%02s%02s" |
87 | #define VERSION_FMT_YYYYMMDD "%04s%02s%02s" |
90 | #define VERSION_ARG_YYYYMMDD BUILDDATE_YEAR, BUILDDATE_MONTH, BUILDDATE_DAY |
88 | #define VERSION_ARG_YYYYMMDD BUILDDATE_YEAR, BUILDDATE_MONTH, BUILDDATE_DAY |
- | 89 | #endif // !VERSION_ARG_YYYYMMDD |
|
91 | 90 | ||
92 | 91 | ||
93 | #define ROUND_TO_UPPER_MULTIPLE(val,multiple) ((((val) + (size_t) (multiple) - 1) / (multiple)) * (multiple)) // note that val is being evaluated once, so it can be the result of a function call |
92 | #define ROUND_TO_UPPER_MULTIPLE(val,multiple) ((((val) + (size_t) (multiple) - 1) / (multiple)) * (multiple)) // note that val is being evaluated once, so it can be the result of a function call |
94 | #ifdef _WIN32 |
93 | #ifdef _WIN32 |
95 | #define IS_DIRSEP(c) (((c) == '/') || ((c) == '\\')) |
94 | #define IS_DIRSEP(c) (((c) == '/') || ((c) == '\\')) |
96 | #define PATH_SEP ';' |
95 | #define PATH_SEP ';' |
- | 96 | #define PATH_SEP_STR ";" |
|
97 | #else // !_WIN32, thus POSIX |
97 | #else // !_WIN32, thus POSIX |
98 | #define IS_DIRSEP(c) ((c) == '/') |
98 | #define IS_DIRSEP(c) ((c) == '/') |
99 | #define PATH_SEP ':' |
99 | #define PATH_SEP ':' |
- | 100 | #define PATH_SEP_STR ":" |
|
100 | #endif // _WIN32 |
101 | #endif // _WIN32 |
101 | #define RECORD_SEP '\x1e' // ASCII record separator |
102 | #define RECORD_SEP '\x1e' // ASCII record separator |
102 | #define RECORD_SEP_STR "\x1e" // ASCII record separator (as string) |
103 | #define RECORD_SEP_STR "\x1e" // ASCII record separator (as string) |
- | 104 | ||
- | 105 | #define ELF_MAGIC_STR "\x7f" "ELF" |
|
- | 106 | #define ELF_ENDIAN_LITTLE 1 // ELF file is little endian |
|
- | 107 | #define ELF_ENDIAN_BIG 2 // ELF file is big endian |
|
- | 108 | #define ELF_DT_NULL 0 // marks end of dynamic section |
|
- | 109 | #define ELF_DT_SONAME 14 // canonical name of shared object |
|
- | 110 | #define ELF_HDR_MEMBER(hdr,member) ((hdr)->u.elf.platform_size == 2 ? (hdr)->u.elf64.member : (hdr)->u.elf32.member) // this macro supports 32- and 64-bit ELF files transparently (FIXME: support foreign endianness as well) |
|
- | 111 | #define ELF_STRUCT_MEMBER(hdr,structure,member) ((hdr)->u.elf.platform_size == 2 ? (structure)->u.elf64.member : (structure)->u.elf32.member) // this macro supports 32- and 64-bit ELF files transparently (FIXME: support foreign endianness as well) |
|
- | 112 | #define ELF_STRUCT_SIZE(hdr,structure) ((hdr)->u.elf.platform_size == 2 ? sizeof ((structure)->u.elf64) : sizeof ((structure)->u.elf32)) // this macro supports 32- and 64-bit ELF files transparently (FIXME: support foreign endianness as well) |
|
103 | 113 | ||
104 | #define WILL_BE_FILLED_LATER 0xbaadf00d |
114 | #define WILL_BE_FILLED_LATER 0xbaadf00d |
105 | 115 | ||
106 | 116 | ||
107 | // bitmapped flags used in the flags1 member of the startup header |
117 | // bitmapped flags used in the flags1 member of the startup header |
Line 144... | Line 154... | ||
144 | { |
154 | { |
145 | uint64_t state[8]; |
155 | uint64_t state[8]; |
146 | uint64_t bitcount[2]; |
156 | uint64_t bitcount[2]; |
147 | uint8_t buffer[SHA512_BLOCK_LENGTH]; |
157 | uint8_t buffer[SHA512_BLOCK_LENGTH]; |
148 | } SHA512_CTX; |
158 | } SHA512_CTX; |
- | 159 | ||
- | 160 | ||
- | 161 | #ifdef _MSC_VER |
|
- | 162 | #pragma pack(push) |
|
- | 163 | #pragma pack(1) |
|
- | 164 | #endif // _MSC_VER |
|
149 | 165 | ||
150 | 166 | ||
151 | #if 0 // TODO: startup script compiler. Someday. |
167 | #if 0 // TODO: startup script compiler. Someday. |
152 | #define SCRIPT_FLAGS_EXTSCHED 0x01 |
168 | #define SCRIPT_FLAGS_EXTSCHED 0x01 |
153 | #define SCRIPT_FLAGS_SESSION 0x02 |
169 | #define SCRIPT_FLAGS_SESSION 0x02 |
Line 238... | Line 254... | ||
238 | #endif // 0 |
254 | #endif // 0 |
239 | 255 | ||
240 | 256 | ||
241 | #define INITIAL_STARTUP_SCRIPT \ |
257 | #define INITIAL_STARTUP_SCRIPT \ |
242 | /* procmgr_symlink /proc/boot/ldqnx-64.so.2 /usr/lib/ldqnx-64.so.2 */ \ |
258 | /* procmgr_symlink /proc/boot/ldqnx-64.so.2 /usr/lib/ldqnx-64.so.2 */ \ |
243 | "\x34\x00" /*size*/ "\x04" /*type*/ "\x00" /*spare*/ "/proc/boot/ldqnx-64. |
259 | "\x34\x00" /*size*/ "\x04" /*type*/ "\x00" /*spare*/ "/proc/boot/ldqnx-64.so.2\0" "/usr/lib/ldqnx-64.so.2\0" \ |
244 | /* sh /proc/boot/startup.sh */ \ |
260 | /* sh /proc/boot/startup.sh */ \ |
245 | "\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*/ \ |
261 | "\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*/ \ |
246 | /* display_msg "Startup complete */ \ |
262 | /* display_msg "Startup complete */ \ |
247 | "\x18\x00" /*size*/ "\x03" /*type*/ "\x00" /*spare*/ "Startup complete\n\0" "\x00\00" /*padding*/ \ |
263 | "\x18\x00" /*size*/ "\x03" /*type*/ "\x00" /*spare*/ "Startup complete\n\0" "\x00\00" /*padding*/ \ |
248 | /* trailer */ \ |
264 | /* trailer */ \ |
Line 363... | Line 379... | ||
363 | typedef struct __attribute__((packed)) image_trailer_v2_s |
379 | typedef struct __attribute__((packed)) image_trailer_v2_s |
364 | { |
380 | { |
365 | uint8_t sha512[64]; // SHA512 from start of image header to start of trailer |
381 | uint8_t sha512[64]; // SHA512 from start of image header to start of trailer |
366 | uint32_t cksum; // checksum from start of header to start of this member |
382 | uint32_t cksum; // checksum from start of header to start of this member |
367 | } image_trailer_v2_t; // NOTE: this is the same structure as startup_trailer_v2_t |
383 | } image_trailer_v2_t; // NOTE: this is the same structure as startup_trailer_v2_t |
- | 384 | ||
- | 385 | ||
- | 386 | // Executable and Linkable Format master header structure type definition |
|
- | 387 | typedef struct __attribute__((packed)) elf_header_s |
|
- | 388 | { |
|
- | 389 | union __attribute__((packed)) |
|
- | 390 | { |
|
- | 391 | struct __attribute__((packed)) |
|
- | 392 | { |
|
- | 393 | uint8_t magic[4]; // offset 0: "\x07" + "ELF" |
|
- | 394 | uint8_t platform_size; // offset 4: 1 = 32-bit, 2 = 64-bit |
|
- | 395 | uint8_t endianness; // offset 5: 1 = little endian, 2 = big endian |
|
- | 396 | uint8_t header_version; // offset 6: typically 1 |
|
- | 397 | uint8_t os_abi; // offset 7: 0 = SysV, 1 = HP/UX, 2 = NetBSD, 3 = Linux, 4 = GNU/Hurd, 6 = Solaris, 7 = AIX, 8 = IRIX, 9 = FreeBSD, 10 = Tru64, 11 = Novell, 12 = OpenBSD, 13 = OpenVMS, 14 = NonStop kernel, 15 = AROS, 16 = FenixOS, 17 = Nuxi CloudABI, 18 = OpenVOS |
|
- | 398 | uint8_t spare[8]; // offset 8: zeroes |
|
- | 399 | uint16_t type; // offset 16: 1 = relocatable, 2 = executable, 3 = shared, 4 = core dump |
|
- | 400 | uint16_t instruction_set; // offset 18: 2 = Sparc, 3 = i386, 8 = MIPS, 20 = PowerPC, 40 = ARM, 42 = SuperH, 50 = IA-64, 62 = x86_64, 183 = AArch64, 243 = RISC-V |
|
- | 401 | uint32_t elf_version; // offset 20: typically 1 |
|
- | 402 | } elf; |
|
- | 403 | struct __attribute__((packed)) |
|
- | 404 | { |
|
- | 405 | uint8_t magic[4]; // offset 0: "\x07" + "ELF" |
|
- | 406 | uint8_t platform_size; // offset 4: 1 = 32-bit, 2 = 64-bit |
|
- | 407 | uint8_t endianness; // offset 5: 1 = little endian, 2 = big endian |
|
- | 408 | uint8_t header_version; // offset 6: typically 1 |
|
- | 409 | uint8_t os_abi; // offset 7: 0 = SysV, 1 = HP/UX, 2 = NetBSD, 3 = Linux, 4 = GNU/Hurd, 6 = Solaris, 7 = AIX, 8 = IRIX, 9 = FreeBSD, 10 = Tru64, 11 = Novell, 12 = OpenBSD, 13 = OpenVMS, 14 = NonStop kernel, 15 = AROS, 16 = FenixOS, 17 = Nuxi CloudABI, 18 = OpenVOS |
|
- | 410 | uint8_t spare[8]; // offset 8: zeroes |
|
- | 411 | uint16_t type; // offset 16: 1 = relocatable, 2 = executable, 3 = shared, 4 = core dump |
|
- | 412 | uint16_t instruction_set; // offset 18: 2 = Sparc, 3 = i386, 8 = MIPS, 20 = PowerPC, 40 = ARM, 42 = SuperH, 50 = IA-64, 62 = x86_64, 183 = AArch64, 243 = RISC-V |
|
- | 413 | uint32_t elf_version; // offset 20: typically 1 |
|
- | 414 | uint32_t entrypoint_offset; // offset 24: offset to program entrypoint |
|
- | 415 | uint32_t program_header_table_offset; // offset 28: offset to program header table |
|
- | 416 | uint32_t section_header_table_offset; // offset 32: offset to section header table |
|
- | 417 | uint32_t flags; // offset 36: flags (architecture-dependent, none for x86) |
|
- | 418 | uint16_t header_size; // offset 40: size of ELF header, 52 for 32-bit ELF and 64 for 64-bit ELF -- DO NOT USE sizeof() ON THE elf_header_s STRUCT BECAUSE OF THE UNION! WRITE THE CORRECT SIZE YOURSELF! |
|
- | 419 | uint16_t program_header_item_size; // offset 42: size of an entry in the program header table |
|
- | 420 | uint16_t program_header_table_len; // offset 44: number of entries in the program header table |
|
- | 421 | uint16_t section_header_item_size; // offset 46: size of an entry in the section header table |
|
- | 422 | uint16_t section_header_table_len; // offset 48: number of entries in the section header table |
|
- | 423 | uint16_t section_header_names_idx; // offset 50: index of the entry in the section header table that contains the section names |
|
- | 424 | } elf32; |
|
- | 425 | struct __attribute__((packed)) |
|
- | 426 | { |
|
- | 427 | uint8_t magic[4]; // offset 0: "\x07" + "ELF" |
|
- | 428 | uint8_t platform_size; // offset 4: 1 = 32-bit, 2 = 64-bit |
|
- | 429 | uint8_t endianness; // offset 5: 1 = little endian, 2 = big endian |
|
- | 430 | uint8_t header_version; // offset 6: typically 1 |
|
- | 431 | uint8_t os_abi; // offset 7: 0 = SysV, 1 = HP/UX, 2 = NetBSD, 3 = Linux, 4 = GNU/Hurd, 6 = Solaris, 7 = AIX, 8 = IRIX, 9 = FreeBSD, 10 = Tru64, 11 = Novell, 12 = OpenBSD, 13 = OpenVMS, 14 = NonStop kernel, 15 = AROS, 16 = FenixOS, 17 = Nuxi CloudABI, 18 = OpenVOS |
|
- | 432 | uint8_t spare[8]; // offset 8: zeroes |
|
- | 433 | uint16_t type; // offset 16: 1 = relocatable, 2 = executable, 3 = shared, 4 = core dump |
|
- | 434 | uint16_t instruction_set; // offset 18: 2 = Sparc, 3 = i386, 8 = MIPS, 20 = PowerPC, 40 = ARM, 42 = SuperH, 50 = IA-64, 62 = x86_64, 183 = AArch64, 243 = RISC-V |
|
- | 435 | uint32_t elf_version; // offset 20: typically 1 |
|
- | 436 | uint64_t entrypoint_offset; // offset 24: program entry offset |
|
- | 437 | uint64_t program_header_table_offset; // offset 32: offset to program header table |
|
- | 438 | uint64_t section_header_table_offset; // offset 40: offset to section header table |
|
- | 439 | uint32_t flags; // offset 48: flags (architecture-dependent, none for x86) |
|
- | 440 | uint16_t header_size; // offset 52: size of ELF header, 52 for 32-bit ELF and 64 for 64-bit ELF |
|
- | 441 | uint16_t program_header_item_size; // offset 54: size of an entry in the program header table |
|
- | 442 | uint16_t program_header_table_len; // offset 56: number of entries in the program header table |
|
- | 443 | uint16_t section_header_item_size; // offset 58: size of an entry in the section header table |
|
- | 444 | uint16_t section_header_table_len; // offset 60: number of entries in the section header table |
|
- | 445 | uint16_t section_header_names_idx; // offset 62: index of the entry in the section header table that contains the section names |
|
- | 446 | } elf64; |
|
- | 447 | } u; |
|
- | 448 | } elf_header_t; |
|
- | 449 | ||
- | 450 | ||
- | 451 | // Executable and Linkable Format section header structure type definition |
|
- | 452 | typedef struct __attribute__((packed)) elf_section_header_s |
|
- | 453 | { |
|
- | 454 | union __attribute__((packed)) |
|
- | 455 | { |
|
- | 456 | struct __attribute__((packed)) |
|
- | 457 | { |
|
- | 458 | uint32_t name_offset; // offset 0: offset in the string table of the name of this section |
|
- | 459 | uint32_t type; // offset 4: |
|
- | 460 | uint32_t flags; // offset 8: |
|
- | 461 | uint32_t virtual_addr; // offset 12: address in virtual memory where this section may be loaded |
|
- | 462 | uint32_t file_offset; // offset 16: offset of this section in the ELF file |
|
- | 463 | uint32_t size; // offset 20: size of this section |
|
- | 464 | uint32_t linked_index; // offset 24: optional section index of an associated section |
|
- | 465 | uint32_t info; // offset 28: optional extra information |
|
- | 466 | uint32_t alignment; // offset 32: required memory alignment (must be a power of 2) |
|
- | 467 | uint32_t entry_size; // offset 36: for table-like sections, size of an element in the table |
|
- | 468 | } elf32; |
|
- | 469 | struct __attribute__((packed)) |
|
- | 470 | { |
|
- | 471 | uint32_t name_offset; // offset 0: offset in the string table of the name of this section |
|
- | 472 | uint32_t type; // offset 4: |
|
- | 473 | uint64_t flags; // offset 8: |
|
- | 474 | uint64_t virtual_addr; // offset 16: address in virtual memory where this section may be loaded |
|
- | 475 | uint64_t file_offset; // offset 24: offset of this section in the ELF file |
|
- | 476 | uint64_t size; // offset 32: size of this section |
|
- | 477 | uint32_t linked_index; // offset 40: optional section index of an associated section |
|
- | 478 | uint32_t info; // offset 44: optional extra information |
|
- | 479 | uint64_t alignment; // offset 48: required memory alignment (must be a power of 2) |
|
- | 480 | uint64_t entry_size; // offset 56: for table-like sections, size of an element in the table |
|
- | 481 | } elf64; |
|
- | 482 | } u; |
|
- | 483 | } elf_section_header_t; |
|
- | 484 | ||
- | 485 | ||
- | 486 | // Executable and Linkable Format dynamic section entry structure type definition |
|
- | 487 | typedef struct __attribute__((packed)) elf_dynamic_section_entry_s |
|
- | 488 | { |
|
- | 489 | union __attribute__((packed)) |
|
- | 490 | { |
|
- | 491 | struct __attribute__((packet)) |
|
- | 492 | { |
|
- | 493 | int32_t tag; // dynamic entry type (one of ELF_DT_xxx #defines) |
|
- | 494 | union |
|
- | 495 | { |
|
- | 496 | uint32_t as_integer; // value as integer |
|
- | 497 | uint32_t as_pointer; // value as address |
|
- | 498 | } value; |
|
- | 499 | } elf32; |
|
- | 500 | struct __attribute__((packed)) |
|
- | 501 | { |
|
- | 502 | int64_t tag; // dynamic entry type (one of ELF_DT_xxx #defines) |
|
- | 503 | union |
|
- | 504 | { |
|
- | 505 | uint64_t as_integer; // value as intege |
|
- | 506 | uint64_t as_pointer; // value as address |
|
- | 507 | } value; |
|
- | 508 | } elf64; |
|
- | 509 | } u; |
|
- | 510 | } elf_dynamic_section_entry_t; |
|
368 | 511 | ||
369 | 512 | ||
370 | #ifdef _MSC_VER |
513 | #ifdef _MSC_VER |
371 | #pragma pack(pop) |
514 | #pragma pack(pop) |
372 | #endif // _MSC_VER |
515 | #endif // _MSC_VER |
Line 377... | Line 520... | ||
377 | int dperms; // directory permissions (e.g. 0755) |
520 | int dperms; // directory permissions (e.g. 0755) |
378 | int perms; // file permissions (e.g. 0644) |
521 | int perms; // file permissions (e.g. 0644) |
379 | int uid; // owner user ID (e.g. 0 = root) |
522 | int uid; // owner user ID (e.g. 0 = root) |
380 | int gid; // owner group ID (e.g. 0 = root) |
523 | int gid; // owner group ID (e.g. 0 = root) |
381 | int st_mode; // entry type (e.g. S_IFREG for files) and permissions |
524 | int st_mode; // entry type (e.g. S_IFREG for files) and permissions |
- | 525 | uint32_t mtime; // entry's modification time POSIX timestamp - set to UINT32_MAX to use the concerned files' mtime on the build host |
|
- | 526 | uint32_t mtime_for_inline_files; // same as above but only for files that don't exist on the build host (i.e. files with an explicit content blob) |
|
382 | char prefix[MAXPATHLEN]; // install path (e.g. "proc/boot") |
527 | char prefix[MAXPATHLEN]; // install path (e.g. "proc/boot") |
- | 528 | bool should_follow_symlinks; // follow symlinks |
|
- | 529 | bool should_autosymlink_dylib; // dynamic libraries should be written under their official SONAME and a named symlink be created pointing at them |
|
383 | bool is_compiled_bootscript; // entry has [+script] attribute |
530 | bool is_compiled_bootscript; // entry has [+script] attribute |
384 | char search[10 * MAXPATHLEN]; // binary search path (the default one will be constructed at startup) |
531 | char search[10 * MAXPATHLEN]; // binary search path (the default one will be constructed at startup) |
385 | 532 | ||
386 | uint8_t * |
533 | uint8_t *data; |
387 | size_t |
534 | size_t datalen; |
388 | } parms_t; |
535 | } parms_t; |
389 | 536 | ||
390 | 537 | ||
391 | // global variables |
538 | // global variables |
392 | static char line_buffer[4096]; // scrap buffer for the IFS build file parser |
539 | static char line_buffer[4096]; // scrap buffer for the IFS build file parser |
Line 395... | Line 542... | ||
395 | static uint32_t image_maxsize = UINT32_MAX; // default image max size (no limit) |
542 | static uint32_t image_maxsize = UINT32_MAX; // default image max size (no limit) |
396 | static uint32_t image_totalsize = 0; // image total size, measured once all the blocks have been written to the output IFS file |
543 | static uint32_t image_totalsize = 0; // image total size, measured once all the blocks have been written to the output IFS file |
397 | static uint32_t image_align = 4; // default image alignment, as per QNX docs |
544 | static uint32_t image_align = 4; // default image alignment, as per QNX docs |
398 | static uint32_t image_kernel_ino = 0; |
545 | static uint32_t image_kernel_ino = 0; |
399 | static uint32_t image_bootscript_ino = 0; |
546 | static uint32_t image_bootscript_ino = 0; |
- | 547 | #if defined(__x86_64__) |
|
400 | static char image_processor[16] = "x86_64"; // default CPU type for which this image is built, either "x86_64" or "aarch64le" (will be used to find out the right include paths under $QNX_TARGET) |
548 | static char image_processor[16] = "x86_64"; // default CPU type for which this image is built, either "x86_64" or "aarch64le" (will be used to find out the right include paths under $QNX_TARGET) |
- | 549 | #elif defined(__aarch64__) |
|
- | 550 | static char image_processor[16] = "aarch64le"; // default CPU type for which this image is built, either "x86_64" or "aarch64le" (will be used to find out the right include paths under $QNX_TARGET) |
|
- | 551 | #else // unknown platform |
|
- | 552 | #error Please port ifstool to this platform |
|
- | 553 | #endif |
|
401 | static char *buildfile_pathname = NULL; // pathname of IFS build file |
554 | static char *buildfile_pathname = NULL; // pathname of IFS build file |
- | 555 | static char *current_line = NULL; // copy of current line in IFS build file |
|
402 | static int lineno = 0; // current line number in IFS build file |
556 | static int lineno = 0; // current line number in IFS build file |
403 | static char *QNX_TARGET = NULL; // value of the $QNX_TARGET environment variable |
557 | static char *QNX_TARGET = NULL; // value of the $QNX_TARGET environment variable |
- | 558 | static char *MKIFS_PATH = NULL; // value of the $MKIFS_PATH environment variable (may contain references to $QNX_TARGET). Initialized by this program if empty. |
|
404 | 559 | ||
405 | 560 | ||
406 | // prototypes of local functions |
561 | // prototypes of local functions |
407 | static void sha512_private_transform (SHA512_CTX *context, const uint64_t *data); // used internally in SHA512_Update() and SHA512_Final() |
562 | static void sha512_private_transform (SHA512_CTX *context, const uint64_t *data); // used internally in SHA512_Update() and SHA512_Final() |
408 | static void SHA512_Init (SHA512_CTX *context); |
563 | static void SHA512_Init (SHA512_CTX *context); |
409 | static void SHA512_Update (SHA512_CTX *context, void *data, size_t len); |
564 | static void SHA512_Update (SHA512_CTX *context, void *data, size_t len); |
410 | static void SHA512_Final (uint8_t digest[SHA512_DIGEST_LENGTH], SHA512_CTX *context); |
565 | static void SHA512_Final (uint8_t digest[SHA512_DIGEST_LENGTH], SHA512_CTX *context); |
411 | 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()) |
566 | 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()) |
412 | static int32_t update_checksum ( |
567 | static int32_t update_checksum (const void *data, const size_t data_len, const bool is_foreign_endianness); // compute an IFS image or startup checksum to store in the trailer |
413 | 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) |
568 | 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) |
414 | 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) |
569 | 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) |
415 | 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 |
570 | 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 |
416 | 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 |
571 | 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 |
- | 572 | static char *read_filecontents (const char *pathname, const char *search_path, uint8_t **databuf, size_t *datalen); // locates pathname among MKIFS_PATH, reads it, places its contents in a buffer (caller frees) and returns a pointer to the resolved pathname (static string) |
|
417 | static int fwrite_filecontents (const char *pathname, FILE *fp); // dumps the contents of pathname into fp |
573 | static int fwrite_filecontents (const char *pathname, FILE *fp); // dumps the contents of pathname into fp |
418 | static size_t fwrite_fsentry (const fsentry_t *fsentry, FILE *fp); // writes the given filesystem entry into fp (without its contents) |
574 | static size_t fwrite_fsentry (const fsentry_t *fsentry, FILE *fp); // writes the given filesystem entry into fp (without its contents) |
419 | static size_t add_fsentry (fsentry_t **fsentries, size_t *fsentry_count |
575 | static size_t add_fsentry (fsentry_t **fsentries, size_t *fsentry_count, parms_t *entry_parms, const char *stored_pathname, const char *buildhost_pathname); // stack up a new filesystem entry |
420 | static int fsentry_compare_pathnames_cb (const void *a, const void *b); // qsort() comparison callback that sorts filesystem entries by pathnames |
576 | static int fsentry_compare_pathnames_cb (const void *a, const void *b); // qsort() comparison callback that sorts filesystem entries by pathnames |
421 | static |
577 | static void update_MKIFS_PATH (const char *processor); |
422 | 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 |
578 | 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 |
423 | 579 | ||
424 | 580 | ||
425 | static void sha512_private_transform (SHA512_CTX *context, const uint64_t *data) |
581 | static void sha512_private_transform (SHA512_CTX *context, const uint64_t *data) |
426 | { |
582 | { |
Line 666... | Line 822... | ||
666 | sprintf (&digest_as_string[2 * byte_index], "%02x", digest_or_NULL[byte_index]); |
822 | sprintf (&digest_as_string[2 * byte_index], "%02x", digest_or_NULL[byte_index]); |
667 | return (digest_as_string); |
823 | return (digest_as_string); |
668 | } |
824 | } |
669 | 825 | ||
670 | 826 | ||
671 | static int32_t update_checksum ( |
827 | static int32_t update_checksum (const void *data, const size_t data_len, const bool is_foreign_endianness) |
672 | { |
828 | { |
673 | // computes the checksum of an IFS image or startup section, i.e. from the start of the header to the end of the trailer minus the last 4 bytes where the checksum is stored |
829 | // computes the checksum of an IFS image or startup section, i.e. from the start of the header to the end of the trailer minus the last 4 bytes where the checksum is stored |
674 | 830 | ||
675 | uint8_t accumulator[4] = { 0, 0, 0, 0 }; |
831 | uint8_t accumulator[4] = { 0, 0, 0, 0 }; |
676 |
|
832 | const char *current_char_ptr; |
677 |
|
833 | int32_t image_cksum; |
678 | size_t i; |
834 | size_t i; |
679 | 835 | ||
- | 836 | image_cksum = 0; |
|
- | 837 | current_char_ptr = data; |
|
680 | for (i = 0; i < data_len; i++) |
838 | for (i = 0; i < data_len; i++) |
681 | { |
839 | { |
682 | accumulator[i % 4] = *current_char_ptr; |
840 | accumulator[i % 4] = *current_char_ptr; |
683 | if (i % 4 == 3) |
841 | if (i % 4 == 3) |
684 | if (is_foreign_endianness) |
842 | if (is_foreign_endianness) |
Line 769... | Line 927... | ||
769 | if (outstr[0] != 0) |
927 | if (outstr[0] != 0) |
770 | strcat (outstr, "|"); |
928 | strcat (outstr, "|"); |
771 | strcat (outstr, ((bitwise_stringdescs != NULL) && (*bitwise_stringdescs[i] != 0) ? bitwise_stringdescs[i] : default_bitstrings[i])); |
929 | strcat (outstr, ((bitwise_stringdescs != NULL) && (*bitwise_stringdescs[i] != 0) ? bitwise_stringdescs[i] : default_bitstrings[i])); |
772 | } |
930 | } |
773 | return (outstr); |
931 | return (outstr); |
- | 932 | } |
|
- | 933 | ||
- | 934 | ||
- | 935 | static char *read_filecontents (const char *pathname, const char *search_path, uint8_t **databuf, size_t *datalen) |
|
- | 936 | { |
|
- | 937 | // locates pathname among MKIFS_PATH, and places its contents in a buffer (caller frees). Returns resolved pathname (static buffer) or NULL. |
|
- | 938 | ||
- | 939 | /*thread_local*/ static char final_pathname[MAXPATHLEN]; |
|
- | 940 | ||
- | 941 | const char *nextsep; |
|
- | 942 | const char *token; |
|
- | 943 | FILE *fp; |
|
- | 944 | ||
- | 945 | // is it an absolute pathname (POSIX and Windows variants) ? |
|
- | 946 | if (IS_DIRSEP (pathname[0]) || (isalpha (pathname[0]) && (pathname[1] == ':') && IS_DIRSEP (pathname[2]))) |
|
- | 947 | strcpy (final_pathname, pathname); // in this case, it MUST exist at its designated location (either absolute or relative to the current working directory) |
|
- | 948 | else // the path is relative, search it among the search paths we have |
|
- | 949 | { |
|
- | 950 | // construct a potential final path using each element of the search path |
|
- | 951 | token = search_path; |
|
- | 952 | nextsep = &token[strcspn (token, PATH_SEP_STR)]; |
|
- | 953 | while (token != NULL) |
|
- | 954 | { |
|
- | 955 | sprintf (final_pathname, "%.*s/%s", (int) (nextsep - token), token, pathname); |
|
- | 956 | if (access (final_pathname, 0) == 0) |
|
- | 957 | break; // if a file can indeed be found at this location, stop searching |
|
- | 958 | ||
- | 959 | token = (*nextsep != 0 ? nextsep + 1 : NULL); |
|
- | 960 | nextsep = (token != NULL ? &token[strcspn (token, PATH_SEP_STR)] : NULL); |
|
- | 961 | } |
|
- | 962 | ||
- | 963 | // have we exhausted all possibilities ? |
|
- | 964 | if (token == NULL) |
|
- | 965 | { |
|
- | 966 | errno = ENOENT; |
|
- | 967 | return (NULL); // file not found, return with ENOENT |
|
- | 968 | } |
|
- | 969 | } |
|
- | 970 | ||
- | 971 | // now open and read the file |
|
- | 972 | fp = fopen (final_pathname, "rb"); |
|
- | 973 | if (fp == NULL) |
|
- | 974 | return (NULL); // unexistent file (errno is set to ENOENT) |
|
- | 975 | ||
- | 976 | fseek (fp, 0, SEEK_END); |
|
- | 977 | *datalen = ftell (fp); // measure file length |
|
- | 978 | fseek (fp, 0, SEEK_SET); |
|
- | 979 | *databuf = malloc (*datalen); |
|
- | 980 | if (*databuf == NULL) |
|
- | 981 | { |
|
- | 982 | fclose (fp); |
|
- | 983 | *datalen = 0; |
|
- | 984 | return (NULL); // out of memory (errno is set to ENOMEM) |
|
- | 985 | } |
|
- | 986 | if (fread (*databuf, 1, *datalen, fp) != *datalen) // read the file in whole |
|
- | 987 | { |
|
- | 988 | fclose (fp); |
|
- | 989 | *datalen = 0; |
|
- | 990 | return (NULL); // short read (errno is set) |
|
- | 991 | } |
|
- | 992 | fclose (fp); // close the file |
|
- | 993 | ||
- | 994 | return (final_pathname); // file was read successfully and its content put in databuf with size datalen |
|
774 | } |
995 | } |
775 | 996 | ||
776 | 997 | ||
777 | static int fwrite_filecontents (const char *pathname, FILE *fp) |
998 | static int fwrite_filecontents (const char *pathname, FILE *fp) |
778 | { |
999 | { |
Line 805... | Line 1026... | ||
805 | } |
1026 | } |
806 | 1027 | ||
807 | 1028 | ||
808 | static size_t fwrite_fsentry (const fsentry_t *fsentry, FILE *fp) |
1029 | static size_t fwrite_fsentry (const fsentry_t *fsentry, FILE *fp) |
809 | { |
1030 | { |
- | 1031 | // writes a directory entry in the image filesystem file pointed to by fp (or fakes so if fp is NULL) |
|
- | 1032 | // and return the number of bytes written (or that would have been written) |
|
- | 1033 | ||
810 | static const uint8_t zeropad_buffer[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; |
1034 | static const uint8_t zeropad_buffer[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; |
811 | 1035 | ||
812 | size_t datalen; |
1036 | size_t datalen; |
813 | size_t count; |
1037 | size_t count; |
814 | 1038 | ||
Line 865... | Line 1089... | ||
865 | if (fp != NULL) |
1089 | if (fp != NULL) |
866 | fwrite (fsentry->u.device.path, (size_t) datalen, 1, fp); // write null-terminated path (no leading slash) |
1090 | fwrite (fsentry->u.device.path, (size_t) datalen, 1, fp); // write null-terminated path (no leading slash) |
867 | count += datalen; |
1091 | count += datalen; |
868 | } |
1092 | } |
869 | 1093 | ||
870 | if |
1094 | if (count < fsentry->header.size) |
- | 1095 | { |
|
- | 1096 | if (fp != NULL) |
|
871 | fwrite (zeropad_buffer, |
1097 | fwrite (zeropad_buffer, fsentry->header.size - count, 1, fp); // pad as necessary |
872 | count = |
1098 | count += fsentry->header.size - count; |
- | 1099 | } |
|
- | 1100 | else if (count > fsentry->header.size) |
|
- | 1101 | { |
|
- | 1102 | fprintf (stderr, "ERROR: attempt to write invalid dirent (claimed size %zd, written size %zd). Aborting.\n", (size_t) fsentry->header.size, count); |
|
- | 1103 | exit (1); |
|
- | 1104 | } |
|
873 | 1105 | ||
874 | return (count); |
1106 | return (count); |
875 | } |
1107 | } |
876 | 1108 | ||
877 | 1109 | ||
878 | static size_t add_fsentry (fsentry_t **fsentries, size_t *fsentry_count |
1110 | static size_t add_fsentry (fsentry_t **fsentries, size_t *fsentry_count, parms_t *entry_parms, const char *stored_pathname, const char *buildhost_pathname) |
879 | { |
1111 | { |
880 | static char candidate_pathname[1024]; |
1112 | static char candidate_pathname[1024]; |
881 | static char *MKIFS_PATH = NULL; |
- | |
882 | static int inode_count = 0; // will be preincremented each time this function is called |
1113 | static int inode_count = 0; // will be preincremented each time this function is called |
883 | 1114 | ||
- | 1115 | const char *original_stored_pathname = NULL; |
|
- | 1116 | const elf_dynamic_section_entry_t *dynamic_entry; // dynamic section entry |
|
- | 1117 | const elf_section_header_t *shdr_shstr; // section headers strings (containing ELF sections names) |
|
- | 1118 | const elf_section_header_t *shdr_dynstr; // dynamic strings |
|
- | 1119 | const elf_section_header_t *shdr_dynamic; // dynamic section |
|
- | 1120 | const elf_section_header_t *shdr; |
|
- | 1121 | const char *canonical_dylib_name; |
|
- | 1122 | const char *elf_section_name; |
|
- | 1123 | const char *dynamic_strings; // strings table of the ".dynamic" section |
|
- | 1124 | const char *shtable_strings; // strings table of the section headers table |
|
- | 1125 | const char *last_dirsep; |
|
- | 1126 | const elf_header_t *elf; |
|
- | 1127 | char *resolved_pathname; |
|
884 | void *reallocated_ptr; |
1128 | void *reallocated_ptr; |
885 |
|
1129 | void *old_data; |
886 | struct stat stat_buf; |
1130 | struct stat stat_buf; |
887 |
|
1131 | size_t table_index; |
888 | size_t |
1132 | size_t table_count; |
889 |
|
1133 | //uint32_t mtime = (entry_parms->m(uint32_t) time (NULL); |
890 | uint32_t extra_ino_flags = 0; |
1134 | uint32_t extra_ino_flags = 0; |
891 | fsentry_t *fsentry; |
1135 | fsentry_t *fsentry; |
892 | char *token; |
- | |
893 | FILE *fp; |
- | |
894 | 1136 | ||
895 | if (S_ISDIR (entry_parms->st_mode)) // are we storing a directory ? |
1137 | if (S_ISDIR (entry_parms->st_mode)) // are we storing a directory ? |
896 | { |
1138 | { |
897 | fprintf (stderr, "directory: ino 0x%x uid %d gid %d mode 0%o path \"%s\"\n", inode_count + 1, entry_parms->uid, entry_parms->gid, entry_parms->st_mode, stored_pathname); |
1139 | fprintf (stderr, "directory: ino 0x%x uid %d gid %d mode 0%o path \"%s\"\n", inode_count + 1, entry_parms->uid, entry_parms->gid, entry_parms->st_mode, stored_pathname); |
898 | } |
1140 | } |
899 | else if (S_ISREG (entry_parms->st_mode)) // else are we storing a regular file ? |
1141 | else if (S_ISREG (entry_parms->st_mode)) // else are we storing a regular file ? |
900 | { |
1142 | { |
901 | if ( |
1143 | if (strcmp (stored_pathname, "/proc/boot/boot") == 0) // is it the kernel ? |
902 | { |
1144 | { |
903 | if (strcmp (stored_pathname, "proc/boot/boot") == 0) // is it the kernel ? |
- | |
904 | { |
- | |
905 |
|
1145 | // HACK: for now just consider the kernel as a binary blob |
906 |
|
1146 | // FIXME: reimplement properly |
907 |
|
1147 | sprintf (candidate_pathname, "%s/procnto-smp-instr", entry_parms->prefix); // fix the entry name |
908 |
|
1148 | stored_pathname = candidate_pathname; |
- | 1149 | extra_ino_flags = IFS_INO_PROCESSED_ELF | IFS_INO_BOOTSTRAP_EXE; // procnto needs to have these flags stamped on the inode |
|
909 |
|
1150 | image_kernel_ino = extra_ino_flags | (inode_count + 1); |
910 |
|
1151 | } |
911 |
|
1152 | else if (entry_parms->is_compiled_bootscript) // else is it a startup script ? |
912 | exit (1); |
- | |
913 | } |
- | |
914 |
|
1153 | image_bootscript_ino = inode_count + 1; // save boot script inode number for image header |
915 | 1154 | ||
916 | sprintf (candidate_pathname, "%s/procnto-smp-instr", entry_parms->prefix); // fix the entry name |
- | |
917 | stored_pathname = candidate_pathname; |
- | |
918 | extra_ino_flags = IFS_INO_PROCESSED_ELF | IFS_INO_BOOTSTRAP_EXE; // procnto needs to have these flags stamped on the inode |
- | |
919 | image_kernel_ino = extra_ino_flags | (inode_count + 1); |
- | |
920 | } |
- | |
921 | else if (entry_parms->is_compiled_bootscript) // else is it a startup script ? |
- | |
922 | image_bootscript_ino = inode_count + 1; // save boot script inode number for image header |
- | |
923 | - | ||
924 |
|
1155 | // do we already know the data for this data blob ? |
925 |
|
1156 | if (entry_parms->data != NULL) |
926 |
|
1157 | { |
927 |
|
1158 | entry_parms->mtime = entry_parms->mtime_for_inline_files; |
928 | data_buffer = malloc (data_len); |
- | |
929 | if (data_buffer == NULL) |
- | |
930 | { |
- | |
931 | fprintf (stderr, "fatal error: out of memory\n"); |
- | |
932 | exit (1); |
- | |
933 | } |
- | |
934 |
|
1159 | 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, entry_parms->datalen); |
935 | } |
- | |
936 | else // else use the supplied data blob |
- | |
937 | { |
- | |
938 | data_len = entry_datalen; |
- | |
939 | data_buffer = malloc (data_len); |
- | |
940 | if (data_buffer == NULL) |
- | |
941 | { |
- | |
942 | fprintf (stderr, "fatal error: out of memory\n"); |
- | |
943 | exit (1); |
- | |
944 | } |
- | |
945 | memcpy (data_buffer, entry_data, data_len); |
- | |
946 |
|
1160 | } |
947 | /* |
1161 | /* |
948 | else if (entry_parms->should_compile_contents_as_startup_script) // should we compile this contents as a startup script ? |
1162 | else if (entry_parms->should_compile_contents_as_startup_script) // should we compile this contents as a startup script ? |
949 | { |
1163 | { |
950 | // HACK: for now just use a precompiled script |
1164 | // HACK: for now just use a precompiled script |
951 | // FIXME: replace this with a true compilation with the rules defined above |
1165 | // FIXME: replace this with a true compilation with the rules defined above |
Line 958... | Line 1172... | ||
958 | memcpy (data_buffer, INITIAL_STARTUP_SCRIPT, INITIAL_STARTUP_SCRIPT_LEN); |
1172 | memcpy (data_buffer, INITIAL_STARTUP_SCRIPT, INITIAL_STARTUP_SCRIPT_LEN); |
959 | data_len = INITIAL_STARTUP_SCRIPT_LEN; |
1173 | data_len = INITIAL_STARTUP_SCRIPT_LEN; |
960 | image_bootscript_ino = inode_count + 1; // save boot script inode number for image header |
1174 | image_bootscript_ino = inode_count + 1; // save boot script inode number for image header |
961 | }*/ |
1175 | }*/ |
962 | 1176 | ||
963 | 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); |
- | |
964 | } |
- | |
965 | else if ( |
1177 | else if (buildhost_pathname != NULL) // else entry_datalen == 0, was some sort of pathname supplied ? |
966 | { |
1178 | { |
967 | // is it an absolute pathname ? |
- | |
968 | if (IS_DIRSEP (entry_data[0]) |
- | |
969 |
|
1179 | resolved_pathname = read_filecontents (buildhost_pathname, (entry_parms->search[0] != 0 ? entry_parms->search : MKIFS_PATH), &entry_parms->data, &entry_parms->datalen); |
970 |
|
1180 | if (resolved_pathname == NULL) |
971 | && IS_DIRSEP (entry_data[2]))) |
- | |
972 | { |
1181 | { |
973 |
|
1182 | fprintf (stderr, "fatal error: filesystem entry \"%s\" specified in \"%s\" line %d not found on build host: %s\n", buildhost_pathname, buildfile_pathname, lineno, strerror (errno)); |
974 |
|
1183 | fprintf (stderr, " v\n"); |
975 |
|
1184 | fprintf (stderr, "%s", current_line); |
976 | { |
- | |
977 |
|
1185 | fprintf (stderr, " ^\n"); |
978 |
|
1186 | exit (1); |
979 | } |
- | |
980 | } |
1187 | } |
981 | else // the path is relative, search it among the search paths we have |
- | |
982 | { |
- | |
983 |
|
1188 | stat (resolved_pathname, &stat_buf); // can't fail |
984 |
|
1189 | if (entry_parms->mtime == UINT32_MAX) |
985 | { |
- | |
986 |
|
1190 | entry_parms->mtime = (uint32_t) stat_buf.st_mtime; |
987 | if (MKIFS_PATH == NULL) |
- | |
988 | { |
- | |
989 |
|
1191 | fprintf (stderr, "file: ino 0x%x uid %d gid %d mode 0%o path \"%s\" buildhost_file \"%s\" (len %zd)\n", inode_count + 1, entry_parms->uid, entry_parms->gid, entry_parms->st_mode, stored_pathname, buildhost_pathname, entry_parms->datalen); |
990 | if (MKIFS_PATH == NULL) |
- | |
991 | { |
- | |
992 | strcpy (processor_base, image_processor); // construct PROCESSOR_BASE |
- | |
993 | token = strchr (processor_base, '-'); |
- | |
994 |
|
1192 | } // end if "was pathname supplied" |
995 | *token = 0; // split anything from the first dash onwards |
- | |
996 | data_len = strlen (processor_base); |
- | |
997 | if ((data_len > 2) && ((processor_base[data_len - 2] == 'b') || (processor_base[data_len - 2] == 'l')) && (processor_base[data_len - 1] == 'e')) |
- | |
998 | processor_base[data_len - 2] = 0; // if it ends with "le" or "be", strip that too |
- | |
999 | 1193 | ||
1000 | MKIFS_PATH = malloc (10 * MAXPATHLEN); // construct a default MKIFS_PATH now |
- | |
1001 | if (MKIFS_PATH == NULL) |
- | |
1002 | { |
- | |
1003 | fprintf (stderr, "fatal error: out of memory\n"); |
- | |
1004 | exit (1); |
- | |
1005 | } |
- | |
1006 |
|
1194 | // is the file we're storing a dylib and should we check for its canonical name ? FIXME: support for big endian is wrong. We should swap only if endianness is foreign, and also swap all ELF struct members below. |
1007 | QNX_TARGET, image_processor, |
- | |
1008 | QNX_TARGET, image_processor, |
- | |
1009 |
|
1195 | if ((entry_parms->datalen > 52) // file is big enough to contain an ELF header |
1010 |
|
1196 | && ((elf = (elf_header_t *) entry_parms->data) != NULL) // cast (necessary true) |
1011 | QNX_TARGET, image_processor, |
- | |
1012 |
|
1197 | && (memcmp (ELF_HDR_MEMBER (elf, magic), ELF_MAGIC_STR, 4) == 0) // file starts with the ELF magic |
1013 |
|
1198 | && ( ((ELF_HDR_MEMBER (elf, endianness) == ELF_ENDIAN_LITTLE) && (ELF_HDR_MEMBER (elf, type) == 3)) // file is little endian (offset 5) AND relocatable executable (i.e. a dynamic library) |
1014 |
|
1199 | || ((ELF_HDR_MEMBER (elf, endianness) == ELF_ENDIAN_BIG) && (__builtin_bswap16 (ELF_HDR_MEMBER (elf, type)) == 3))) // file is big endian (offset 5) AND relocatable executable (i.e. a dynamic library) |
1015 |
|
1200 | && entry_parms->should_autosymlink_dylib) // we should store it under its official .so name |
1016 |
|
1201 | { |
1017 |
|
1202 | // we need to find the SONAME of this library |
- | 1203 | canonical_dylib_name = NULL; |
|
1018 | 1204 | ||
1019 | strcpy (entry_parms->search, MKIFS_PATH); // if entry search path is not defined, use the contents of MKIFS_PATH |
- | |
1020 |
|
1205 | shdr_shstr = (elf_section_header_t *) &entry_parms->data[ELF_HDR_MEMBER (elf, section_header_table_offset) + (size_t) ELF_HDR_MEMBER (elf, section_header_item_size) * ELF_HDR_MEMBER (elf, section_header_names_idx)]; // quick access to section header for the section that contains the section names |
- | 1206 | shtable_strings = &entry_parms->data[ELF_STRUCT_MEMBER (elf, shdr_shstr, file_offset)]; // locate the start of the strings table that contains the section names |
|
1021 | 1207 | ||
1022 |
|
1208 | // locate the sections we need (the dynamic section and its strings table) |
- | 1209 | table_count = ELF_HDR_MEMBER (elf, section_header_table_len); |
|
- | 1210 | shdr_dynamic = NULL; |
|
- | 1211 | shdr_dynstr = NULL; |
|
1023 |
|
1212 | for (table_index = 0; table_index < table_count; table_index++) |
- | 1213 | { |
|
- | 1214 | shdr = (elf_section_header_t *) &entry_parms->data[ELF_HDR_MEMBER (elf, section_header_table_offset) + (size_t) ELF_HDR_MEMBER (elf, section_header_item_size) * table_index]; // quick access to section header |
|
- | 1215 | elf_section_name = &shtable_strings[ELF_STRUCT_MEMBER (elf, shdr, name_offset)]; |
|
- | 1216 | if (strcmp (elf_section_name, ".dynamic") == 0) |
|
1024 |
|
1217 | shdr_dynamic = shdr; |
- | 1218 | else if (strcmp (elf_section_name, ".dynstr") == 0) |
|
1025 |
|
1219 | shdr_dynstr = shdr; |
- | 1220 | } |
|
1026 | 1221 | ||
1027 |
|
1222 | // make sure we have both the dynamic section header and its own strings table header |
1028 |
|
1223 | if ((shdr_dynamic != NULL) && (shdr_dynstr != NULL)) |
1029 |
|
1224 | { |
- | 1225 | dynamic_strings = (char *) &entry_parms->data[ELF_STRUCT_MEMBER (elf, shdr_dynstr, file_offset)]; // quick access to dynamic sections strings table |
|
- | 1226 | ||
- | 1227 | // walk through the dynamic section, look for the DT_SONAME entry |
|
- | 1228 | for (dynamic_entry = (elf_dynamic_section_entry_t *) &entry_parms->data[ELF_STRUCT_MEMBER (elf, shdr_dynamic, file_offset)]; |
|
1030 |
|
1229 | (ELF_STRUCT_MEMBER (elf, dynamic_entry, tag) != ELF_DT_NULL); |
- | 1230 | dynamic_entry = (elf_dynamic_section_entry_t *) ((uint8_t *) dynamic_entry + ELF_STRUCT_SIZE (elf, dynamic_entry))) |
|
1031 | if ( |
1231 | if (ELF_STRUCT_MEMBER (elf, dynamic_entry, tag) == ELF_DT_SONAME) |
- | 1232 | { |
|
- | 1233 | canonical_dylib_name = dynamic_strings + ELF_STRUCT_MEMBER (elf, dynamic_entry, value.as_integer); |
|
1032 | break; |
1234 | break; |
1033 | token = strtok (NULL, "|"); |
- | |
1034 | } |
1235 | } |
- | 1236 | ||
1035 |
|
1237 | // do we have it ? |
- | 1238 | if ((canonical_dylib_name != NULL) && (canonical_dylib_name[0] != 0)) |
|
1036 | { |
1239 | { |
- | 1240 | sprintf (candidate_pathname, "%s/%s", entry_parms->prefix, canonical_dylib_name); |
|
1037 |
|
1241 | if (strcmp (candidate_pathname, stored_pathname) != 0) // claimed dylib name differs from passed name ? |
1038 |
|
1242 | { |
- | 1243 | original_stored_pathname = stored_pathname; // if so, remember to create a symlink here |
|
- | 1244 | stored_pathname = candidate_pathname; |
|
- | 1245 | } |
|
1039 | } |
1246 | } |
1040 | } |
1247 | } |
1041 | - | ||
1042 | data_len = stat_buf.st_size; |
- | |
1043 | mtime = (uint32_t) stat_buf.st_mtime; |
- | |
1044 | - | ||
1045 | data_buffer = malloc (data_len); |
- | |
1046 | if (data_buffer == NULL) |
- | |
1047 | { |
- | |
1048 | fprintf (stderr, "fatal error: out of memory\n"); |
- | |
1049 | exit (1); |
- | |
1050 | } |
- | |
1051 | fp = fopen (candidate_pathname, "rb"); |
- | |
1052 | fread (data_buffer, 1, data_len, fp); |
- | |
1053 | fclose (fp); |
- | |
1054 | - | ||
1055 | fprintf (stderr, "file: ino 0x%x uid %d gid %d mode 0%o path \"%s\" buildhost_file \"%s\" (len %zd)\n", inode_count + 1, entry_parms->uid, entry_parms->gid, entry_parms->st_mode, stored_pathname, entry_data, data_len); |
- | |
1056 | } |
1248 | } |
1057 | } |
1249 | } |
1058 | else if (S_ISLNK (entry_parms->st_mode)) // else are we storing a symbolic link ? |
1250 | else if (S_ISLNK (entry_parms->st_mode)) // else are we storing a symbolic link ? |
1059 | { |
- | |
1060 | data_len = strlen (entry_data); |
- | |
1061 | - | ||
1062 | data_buffer = malloc (data_len + 1); |
- | |
1063 | if (data_buffer == NULL) |
- | |
1064 | { |
- | |
1065 | fprintf (stderr, "fatal error: out of memory\n"); |
- | |
1066 | exit (1); |
- | |
1067 | } |
- | |
1068 | memcpy (data_buffer, entry_data, data_len + 1); // copy including null terminator |
- | |
1069 | - | ||
1070 | fprintf (stderr, "symlink: ino 0x%x uid %d gid %d mode 0%o path \"%s\" -> \"%s\"\n", inode_count + 1, entry_parms->uid, entry_parms->gid, entry_parms->st_mode, stored_pathname, |
1251 | fprintf (stderr, "symlink: ino 0x%x uid %d gid %d mode 0%o path \"%s\" -> \"%s\"\n", inode_count + 1, entry_parms->uid, entry_parms->gid, entry_parms->st_mode, stored_pathname, entry_parms->data); |
1071 | } |
- | |
1072 | else // we must be storing a FIFO |
1252 | else // we must be storing a FIFO |
1073 | { |
1253 | { |
1074 | if (strchr ( |
1254 | if (strchr (entry_parms->data, ':') == NULL) |
1075 | { |
1255 | { |
1076 | fprintf (stderr, "fatal error: device entry \"%s\" malformed (no 'dev:rdev' pair)\n", stored_pathname); |
1256 | fprintf (stderr, "fatal error: device entry \"%s\" malformed (no 'dev:rdev' pair)\n", stored_pathname); |
1077 | exit (1); |
1257 | exit (1); |
1078 | } |
1258 | } |
1079 | - | ||
1080 | fprintf (stderr, "fifo: ino 0x%x uid %d gid %d mode 0%o path \"%s\" dev rdev %s)\n", inode_count + 1, entry_parms->uid, entry_parms->gid, entry_parms->st_mode, stored_pathname, |
1259 | fprintf (stderr, "fifo: ino 0x%x uid %d gid %d mode 0%o path \"%s\" dev rdev %s)\n", inode_count + 1, entry_parms->uid, entry_parms->gid, entry_parms->st_mode, stored_pathname, entry_parms->data); |
1081 | } |
1260 | } |
1082 | 1261 | ||
1083 | // |
1262 | // grow filesystem entries array to hold one more slot |
1084 | reallocated_ptr = realloc (*fsentries, (*fsentry_count + 1) * sizeof (fsentry_t)); // attempt to reallocate |
1263 | reallocated_ptr = realloc (*fsentries, (*fsentry_count + 1) * sizeof (fsentry_t)); // attempt to reallocate |
1085 | if (reallocated_ptr == NULL) |
1264 | if (reallocated_ptr == NULL) |
1086 | { |
1265 | { |
1087 | fprintf (stderr, "fatal error: out of memory\n"); |
1266 | fprintf (stderr, "fatal error: out of memory\n"); |
1088 | exit (1); |
1267 | exit (1); |
Line 1093... | Line 1272... | ||
1093 | fsentry->header.extattr_offset = 0; |
1272 | fsentry->header.extattr_offset = 0; |
1094 | fsentry->header.ino = extra_ino_flags | (++inode_count); |
1273 | fsentry->header.ino = extra_ino_flags | (++inode_count); |
1095 | fsentry->header.mode = entry_parms->st_mode; |
1274 | fsentry->header.mode = entry_parms->st_mode; |
1096 | fsentry->header.gid = entry_parms->gid; |
1275 | fsentry->header.gid = entry_parms->gid; |
1097 | fsentry->header.uid = entry_parms->uid; |
1276 | fsentry->header.uid = entry_parms->uid; |
1098 | fsentry->header.mtime = mtime; |
1277 | fsentry->header.mtime = (entry_parms->mtime == UINT32_MAX ? (uint32_t) time (NULL) : entry_parms->mtime); |
1099 | if (S_ISDIR (entry_parms->st_mode)) |
1278 | if (S_ISDIR (entry_parms->st_mode)) |
1100 | { |
1279 | { |
1101 | fsentry->u.dir.path = strdup (stored_pathname); |
1280 | fsentry->u.dir.path = strdup (stored_pathname[0] == '/' ? &stored_pathname[1] : stored_pathname); |
1102 | fsentry->header.size = (uint16_t) (sizeof (fsentry->header) + |
1281 | fsentry->header.size = (uint16_t) ROUND_TO_UPPER_MULTIPLE (sizeof (fsentry->header) + strlen (fsentry->u.dir.path) + 1, image_align); // now we can set the size |
1103 | fsentry->UNSAVED_was_data_written = true; // no data to save |
1282 | fsentry->UNSAVED_was_data_written = true; // no data to save |
1104 | } |
1283 | } |
1105 | else if (S_ISREG (entry_parms->st_mode)) |
1284 | else if (S_ISREG (entry_parms->st_mode)) |
1106 | { |
1285 | { |
1107 | fsentry->u.file.offset = WILL_BE_FILLED_LATER; // will be filled later in main() when the file's data blob will be written to the output file |
1286 | fsentry->u.file.offset = WILL_BE_FILLED_LATER; // will be filled later in main() when the file's data blob will be written to the output file |
1108 | fsentry->u.file.size = (uint32_t) |
1287 | fsentry->u.file.size = (uint32_t) entry_parms->datalen; |
- | 1288 | fsentry->u.file.path = strdup (stored_pathname[0] == '/' ? &stored_pathname[1] : stored_pathname); |
|
1109 | fsentry->u.file. |
1289 | fsentry->u.file.UNSAVED_databuf = malloc (entry_parms->datalen); |
1110 | fsentry->u.file.UNSAVED_databuf |
1290 | if (fsentry->u.file.UNSAVED_databuf == NULL) |
- | 1291 | { |
|
- | 1292 | fprintf (stderr, "fatal error: out of memory\n"); |
|
- | 1293 | exit (1); |
|
- | 1294 | } |
|
- | 1295 | memcpy (fsentry->u.file.UNSAVED_databuf, entry_parms->data, entry_parms->datalen); |
|
1111 | fsentry->header.size = (uint16_t) (sizeof (fsentry->header) + |
1296 | fsentry->header.size = (uint16_t) ROUND_TO_UPPER_MULTIPLE (sizeof (fsentry->header) + sizeof (uint32_t) + sizeof (uint32_t) + strlen (fsentry->u.file.path) + 1, image_align); // now we can set the size |
1112 | fsentry->UNSAVED_was_data_written = false; // there *IS* data to save |
1297 | fsentry->UNSAVED_was_data_written = false; // there *IS* data to save |
1113 | } |
1298 | } |
1114 | else if (S_ISLNK (entry_parms->st_mode)) |
1299 | else if (S_ISLNK (entry_parms->st_mode)) |
1115 | { |
1300 | { |
1116 | fsentry->u.symlink.sym_offset = (uint16_t) (strlen (stored_pathname) + 1); |
1301 | fsentry->u.symlink.sym_offset = (uint16_t) (strlen (stored_pathname[0] == '/' ? &stored_pathname[1] : stored_pathname) + 1); |
1117 | fsentry->u.symlink.sym_size = (uint16_t) |
1302 | fsentry->u.symlink.sym_size = (uint16_t) entry_parms->datalen; |
- | 1303 | fsentry->u.symlink.path = strdup (stored_pathname[0] == '/' ? &stored_pathname[1] : stored_pathname); |
|
1118 | fsentry->u.symlink. |
1304 | fsentry->u.symlink.contents = strdup (entry_parms->data); |
1119 | fsentry->u.symlink.contents |
1305 | if (fsentry->u.symlink.contents == NULL) |
- | 1306 | { |
|
- | 1307 | fprintf (stderr, "fatal error: out of memory\n"); |
|
- | 1308 | exit (1); |
|
- | 1309 | } |
|
1120 | fsentry->header.size = (uint16_t) (sizeof (fsentry->header) + |
1310 | fsentry->header.size = (uint16_t) ROUND_TO_UPPER_MULTIPLE (sizeof (fsentry->header) + sizeof (uint16_t) + sizeof (uint16_t) + (size_t) fsentry->u.symlink.sym_offset + fsentry->u.symlink.sym_size + 1, image_align); // now we can set the size |
1121 | fsentry->UNSAVED_was_data_written = true; // no data to save |
1311 | fsentry->UNSAVED_was_data_written = true; // no data to save |
1122 | } |
1312 | } |
1123 | else |
1313 | else // necessarily a device node |
1124 | { |
1314 | { |
1125 | fsentry->u.device.dev = strtol ( |
1315 | fsentry->u.device.dev = strtol (entry_parms->data, NULL, 0); // use strtol() to parse decimal (...), hexadecimal (0x...) and octal (0...) numbers |
1126 | fsentry->u.device.rdev = strtol (strchr ( |
1316 | fsentry->u.device.rdev = strtol (strchr (entry_parms->data, ':') + 1, NULL, 0); // use strtol() to parse decimal (...), hexadecimal (0x...) and octal (0...) numbers |
1127 | fsentry->u.device.path = strdup (stored_pathname); |
1317 | fsentry->u.device.path = strdup (stored_pathname[0] == '/' ? &stored_pathname[1] : stored_pathname); |
1128 | fsentry->header.size = (uint16_t) (sizeof (fsentry->header) + |
1318 | fsentry->header.size = (uint16_t) ROUND_TO_UPPER_MULTIPLE (sizeof (fsentry->header) + sizeof (uint32_t) + sizeof (uint32_t) + strlen (fsentry->u.device.path), image_align); // now we can set the size |
1129 | fsentry->UNSAVED_was_data_written = true; // no data to save |
1319 | fsentry->UNSAVED_was_data_written = true; // no data to save |
1130 | } |
1320 | } |
1131 | (*fsentry_count)++; |
1321 | (*fsentry_count)++; |
- | 1322 | ||
- | 1323 | // should we also add a symlink to this entry ? (in case we stored a dylib file under its canonical name) |
|
- | 1324 | if (original_stored_pathname != NULL) |
|
- | 1325 | { |
|
- | 1326 | entry_parms->is_compiled_bootscript = false; |
|
- | 1327 | entry_parms->should_autosymlink_dylib = false; |
|
- | 1328 | entry_parms->should_follow_symlinks = false; |
|
- | 1329 | entry_parms->st_mode = S_IFLNK | 0777; // NOTE: mkifs stores symlink permissions as rwxrwxrwx ! |
|
- | 1330 | last_dirsep = strrchr (stored_pathname, '/'); |
|
- | 1331 | old_data = entry_parms->data; // backup previous data pointer |
|
- | 1332 | entry_parms->data = (uint8_t *) (last_dirsep == NULL ? stored_pathname : last_dirsep + 1); // store symlink target in dirent data |
|
- | 1333 | entry_parms->datalen = strlen (entry_parms->data); |
|
- | 1334 | add_fsentry (fsentries, fsentry_count, entry_parms, original_stored_pathname, NULL); |
|
- | 1335 | entry_parms->data = old_data; // restore previous data pointer so that it can be freed normally |
|
- | 1336 | } |
|
- | 1337 | ||
1132 | return (*fsentry_count); |
1338 | return (*fsentry_count); |
1133 | } |
1339 | } |
1134 | 1340 | ||
1135 | 1341 | ||
1136 | static int fsentry_compare_pathnames_cb (const void *a, const void *b) |
1342 | static int fsentry_compare_pathnames_cb (const void *a, const void *b) |
Line 1143... | Line 1349... | ||
1143 | const char *pathname_b = (S_ISDIR (entry_b->header.mode) ? entry_b->u.dir.path : (S_ISREG (entry_b->header.mode) ? entry_b->u.file.path : (S_ISLNK (entry_b->header.mode) ? entry_b->u.symlink.path : entry_b->u.device.path))); |
1349 | const char *pathname_b = (S_ISDIR (entry_b->header.mode) ? entry_b->u.dir.path : (S_ISREG (entry_b->header.mode) ? entry_b->u.file.path : (S_ISLNK (entry_b->header.mode) ? entry_b->u.symlink.path : entry_b->u.device.path))); |
1144 | return (strcmp (pathname_a, pathname_b)); |
1350 | return (strcmp (pathname_a, pathname_b)); |
1145 | } |
1351 | } |
1146 | 1352 | ||
1147 | 1353 | ||
1148 | static |
1354 | static void update_MKIFS_PATH (const char *processor) |
1149 | { |
1355 | { |
1150 | // |
1356 | // updates the value of MKIFS_PATH according to the passed processor name string, unless an environment variable already defines it |
1151 | 1357 | ||
- | 1358 | char processor_base[16]; |
|
- | 1359 | size_t data_len; |
|
- | 1360 | char *envvar; |
|
- | 1361 | char *token; |
|
- | 1362 | ||
- | 1363 | envvar = getenv ("MKIFS_PATH"); // look in the environment first, and construct a default one if not supplied |
|
- | 1364 | if (envvar != NULL) |
|
- | 1365 | MKIFS_PATH = envvar; // if envvar is present, set MKIFS_PATH to point to it |
|
- | 1366 | else // envvar not present |
|
- | 1367 | { |
|
- | 1368 | if (MKIFS_PATH != NULL) |
|
- | 1369 | free (MKIFS_PATH); // free any MKIFS_PATH that we constructed earlier |
|
- | 1370 | ||
- | 1371 | strcpy (processor_base, processor); // construct PROCESSOR_BASE |
|
1152 |
|
1372 | token = strchr (processor_base, '-'); |
- | 1373 | if (token != NULL) |
|
- | 1374 | *token = 0; // split anything from the first dash onwards |
|
1153 |
|
1375 | data_len = strlen (processor_base); |
1154 |
|
1376 | if ((data_len > 2) && ((processor_base[data_len - 2] == 'b') || (processor_base[data_len - 2] == 'l')) && (processor_base[data_len - 1] == 'e')) |
- | 1377 | processor_base[data_len - 2] = 0; // if it ends with "le" or "be", strip that too |
|
- | 1378 | ||
- | 1379 | MKIFS_PATH = malloc (10 * MAXPATHLEN); // construct a default MKIFS_PATH now |
|
- | 1380 | if (MKIFS_PATH == NULL) |
|
- | 1381 | { |
|
- | 1382 | fprintf (stderr, "fatal error: out of memory\n"); |
|
- | 1383 | exit (1); |
|
- | 1384 | } |
|
1155 |
|
1385 | sprintf (MKIFS_PATH, "." PATH_SEP_STR "%s/%s/sbin" PATH_SEP_STR "%s/%s/usr/sbin" PATH_SEP_STR "%s/%s/boot/sys" PATH_SEP_STR "%s/%s/boot/sys" PATH_SEP_STR "%s/%s/bin" PATH_SEP_STR "%s/%s/usr/bin" PATH_SEP_STR "%s/%s/lib" PATH_SEP_STR "%s/%s/lib/dll" PATH_SEP_STR "%s/%s/usr/lib", // use a platform-specific character as path separator |
- | 1386 | QNX_TARGET, processor, |
|
- | 1387 | QNX_TARGET, processor, |
|
- | 1388 | QNX_TARGET, processor, |
|
- | 1389 | QNX_TARGET, processor_base, |
|
- | 1390 | QNX_TARGET, processor, |
|
- | 1391 | QNX_TARGET, processor, |
|
- | 1392 | QNX_TARGET, processor, |
|
- | 1393 | QNX_TARGET, processor, |
|
1156 |
|
1394 | QNX_TARGET, processor); |
- | 1395 | } |
|
- | 1396 | ||
- | 1397 | return; |
|
1157 | } |
1398 | } |
1158 | 1399 | ||
1159 | 1400 | ||
1160 | int main (int argc, char **argv) |
1401 | int main (int argc, char **argv) |
1161 | { |
1402 | { |
Line 1167... | Line 1408... | ||
1167 | static startup_trailer_v2_t startup_trailer = { 0 }; // output IFS's startup trailer (version 2, with SHA-512 checksum and int32 checksum) |
1408 | static startup_trailer_v2_t startup_trailer = { 0 }; // output IFS's startup trailer (version 2, with SHA-512 checksum and int32 checksum) |
1168 | static image_header_t image_header = { 0 }; // output IFS's imagefs header |
1409 | static image_header_t image_header = { 0 }; // output IFS's imagefs header |
1169 | static image_trailer_v2_t image_trailer = { 0 }; // output IFS's imagefs trailer (version 2, with SHA-512 checksum and int32 checksum) |
1410 | static image_trailer_v2_t image_trailer = { 0 }; // output IFS's imagefs trailer (version 2, with SHA-512 checksum and int32 checksum) |
1170 | static fsentry_t *fsentries = NULL; // output IFS's filesystem entries |
1411 | static fsentry_t *fsentries = NULL; // output IFS's filesystem entries |
1171 | static size_t fsentry_count = 0; // number of entries in the IFS filesystem |
1412 | static size_t fsentry_count = 0; // number of entries in the IFS filesystem |
1172 | static parms_t default_parms = { |
1413 | static parms_t default_parms = { // default parameters for a filesystem entry |
- | 1414 | .dperms = 0755, |
|
- | 1415 | .perms = 0644, |
|
- | 1416 | .uid = 0, |
|
- | 1417 | .gid = 0, |
|
- | 1418 | .st_mode = S_IFREG, |
|
- | 1419 | .mtime = UINT32_MAX, |
|
- | 1420 | .mtime_for_inline_files = UINT32_MAX, |
|
- | 1421 | .prefix = "/proc/boot", |
|
- | 1422 | .should_follow_symlinks = true, // [+|-followlink] |
|
- | 1423 | .should_autosymlink_dylib = true, // [+|-autolink] |
|
- | 1424 | .is_compiled_bootscript = false, // [+|-script] |
|
- | 1425 | .search = "", |
|
- | 1426 | .data = NULL, |
|
- | 1427 | .datalen = 0 |
|
- | 1428 | }; |
|
1173 | 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) |
1429 | 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) |
1174 | 1430 | ||
1175 | // bootable IFS support |
1431 | // bootable IFS support |
1176 | char *bootfile_pathname = NULL; // HACK: pathname to bootcode binary blob file to put at the start of a bootable IFS |
1432 | char *bootfile_pathname = NULL; // HACK: pathname to bootcode binary blob file to put at the start of a bootable IFS |
1177 | size_t bootfile_size = 0; // HACK: size of the bootcode binary blob file to put at the start of a bootable IFS |
1433 | size_t bootfile_size = 0; // HACK: size of the bootcode binary blob file to put at the start of a bootable IFS |
1178 | char *startupfile_pathname = NULL; // HACK: pathname to precompiled startup file blob to put in the startup header of a bootable IFS |
1434 | char *startupfile_pathname = NULL; // HACK: pathname to precompiled startup file blob to put in the startup header of a bootable IFS |
1179 | size_t startupfile_ep_from_imagebase = 0; // HACK: startup code entrypoint offset from image base for a bootable IFS |
1435 | size_t startupfile_ep_from_imagebase = 0; // HACK: startup code entrypoint offset from image base for a bootable IFS |
1180 | char *kernelfile_pathname = NULL; // HACK: pathname to precompiled kernel file blob to put in a bootable IFS |
1436 | char *kernelfile_pathname = NULL; // HACK: pathname to precompiled kernel file blob to put in a bootable IFS |
1181 | size_t kernelfile_offset = 0; // HACK: kernel file offset in bootable IFS |
1437 | size_t kernelfile_offset = 0; // HACK: kernel file offset in bootable IFS |
1182 | 1438 | ||
- | 1439 | char path_on_buildhost[MAXPATHLEN] = ""; |
|
1183 | char path_in_ifs[MAXPATHLEN]; |
1440 | char path_in_ifs[MAXPATHLEN] = ""; |
1184 | char *ifs_pathname = NULL; |
1441 | char *ifs_pathname = NULL; |
1185 | void *reallocated_ptr; |
1442 | void *reallocated_ptr; |
- | 1443 | struct tm utc_time; |
|
1186 | struct stat stat_buf; |
1444 | struct stat stat_buf; |
1187 | size_t startuptrailer_offset; |
1445 | size_t startuptrailer_offset; |
1188 | size_t startupheader_offset; |
1446 | size_t startupheader_offset; |
1189 | size_t imgtrailer_offset; |
1447 | size_t imgtrailer_offset; |
1190 | size_t imgheader_offset; |
1448 | size_t imgheader_offset; |
1191 | size_t imgdir_offset; |
1449 | size_t imgdir_offset; |
1192 | size_t imgdir_size; |
1450 | size_t imgdir_size; |
1193 | size_t final_size; |
1451 | size_t final_size; |
- | 1452 | size_t blob_size; |
|
- | 1453 | size_t available_space; |
|
- | 1454 | size_t allocated_size; |
|
1194 | size_t fsentry_index; |
1455 | size_t fsentry_index; |
- | 1456 | size_t largest_index; |
|
- | 1457 | size_t largest_size; |
|
1195 | size_t curr_offset; |
1458 | size_t curr_offset; |
1196 | size_t blob_datasize; // mallocated size |
- | |
1197 | size_t blob_datalen; // used size |
- | |
1198 | uint8_t *blob_data = NULL; // mallocated |
- | |
1199 | char * |
1459 | char *specifiedpathname_start; |
1200 | char *directiveblock_start; |
1460 | char *directiveblock_start; |
- | 1461 | char *blob_data; |
|
1201 | char *write_ptr; |
1462 | char *write_ptr; |
- | 1463 | char *line_ptr; |
|
1202 | char *token; |
1464 | char *token; |
1203 | char *value; |
1465 | char *value; |
1204 | char *sep; |
1466 | char *sep; |
1205 | //char *ctx; |
1467 | //char *ctx; |
1206 | int arg_index; |
1468 | int arg_index; |
Line 1240... | Line 1502... | ||
1240 | exit (1); |
1502 | exit (1); |
1241 | } |
1503 | } |
1242 | *sep = 0; |
1504 | *sep = 0; |
1243 | kernelfile_pathname = argv[arg_index]; |
1505 | kernelfile_pathname = argv[arg_index]; |
1244 | kernelfile_offset = (size_t) read_integer (sep + 1); |
1506 | kernelfile_offset = (size_t) read_integer (sep + 1); |
- | 1507 | } |
|
- | 1508 | else if (strcmp (argv[arg_index], "-n") == 0) |
|
- | 1509 | default_parms.mtime_for_inline_files = 0; // inline files should have a mtime set to zero |
|
- | 1510 | else if (strcmp (argv[arg_index], "-nn") == 0) |
|
- | 1511 | { |
|
- | 1512 | default_parms.mtime = 0; // all files should have a mtime set to zero |
|
- | 1513 | default_parms.mtime_for_inline_files = 0; |
|
1245 | } |
1514 | } |
1246 | else if (strcmp (argv[arg_index], "--info") == 0) |
1515 | else if (strcmp (argv[arg_index], "--info") == 0) |
1247 | want_info = true; |
1516 | want_info = true; |
1248 | else if ((strcmp (argv[arg_index], "-?") == 0) || (strcmp (argv[arg_index], "--help") == 0)) |
1517 | else if ((strcmp (argv[arg_index], "-?") == 0) || (strcmp (argv[arg_index], "--help") == 0)) |
1249 | want_help = true; |
1518 | want_help = true; |
Line 1259... | Line 1528... | ||
1259 | fprintf ((want_help ? stdout : stderr), "ifstool - QNX in-kernel filesystem creation utility by Pierre-Marie Baty <pm@pmbaty.com>\n"); |
1528 | fprintf ((want_help ? stdout : stderr), "ifstool - QNX in-kernel filesystem creation utility by Pierre-Marie Baty <pm@pmbaty.com>\n"); |
1260 | fprintf ((want_help ? stdout : stderr), " version " VERSION_FMT_YYYYMMDD "\n", VERSION_ARG_YYYYMMDD); |
1529 | fprintf ((want_help ? stdout : stderr), " version " VERSION_FMT_YYYYMMDD "\n", VERSION_ARG_YYYYMMDD); |
1261 | if (!want_help) |
1530 | if (!want_help) |
1262 | fprintf (stderr, "error: missing parameters\n"); |
1531 | fprintf (stderr, "error: missing parameters\n"); |
1263 | fprintf ((want_help ? stdout : stderr), "usage:\n"); |
1532 | fprintf ((want_help ? stdout : stderr), "usage:\n"); |
1264 | fprintf ((want_help ? stdout : stderr), " ifstool [--bootfile <pathname>] [--startupfile <pathname>@<EP_from_imgbase>] [--kernelfile <pathname>@<fileoffs>] <buildfile> <outfile>\n"); |
1533 | fprintf ((want_help ? stdout : stderr), " ifstool [--bootfile <pathname>] [--startupfile <pathname>@<EP_from_imgbase>] [--kernelfile <pathname>@<fileoffs>] [-n[n]] <buildfile> <outfile>\n"); |
1265 | fprintf ((want_help ? stdout : stderr), " ifstool --info <ifs file>\n"); |
1534 | fprintf ((want_help ? stdout : stderr), " ifstool --info <ifs file>\n"); |
1266 | fprintf ((want_help ? stdout : stderr), " ifstool --help\n"); |
1535 | fprintf ((want_help ? stdout : stderr), " ifstool --help\n"); |
- | 1536 | fprintf ((want_help ? stdout : stderr), "WARNING: the compilation feature is currently a work in progress (broken). Only the --info mode is usable at the moment.\n"); |
|
1267 | exit (want_help ? 0 : 1); |
1537 | exit (want_help ? 0 : 1); |
1268 | } |
1538 | } |
1269 | 1539 | ||
1270 | // do we want info about a particular IFS ? if so, dump it |
1540 | // do we want info about a particular IFS ? if so, dump it |
1271 | if (want_info) |
1541 | if (want_info) |
Line 1281... | Line 1551... | ||
1281 | else if (access (QNX_TARGET, 0) != 0) |
1551 | else if (access (QNX_TARGET, 0) != 0) |
1282 | { |
1552 | { |
1283 | fprintf (stderr, "error: the QNX_TARGET environment variable doesn't point to an existing directory\n"); |
1553 | fprintf (stderr, "error: the QNX_TARGET environment variable doesn't point to an existing directory\n"); |
1284 | exit (1); |
1554 | exit (1); |
1285 | } |
1555 | } |
- | 1556 | ||
- | 1557 | // prepare a default MKIFS_PATH assuming the host processor |
|
- | 1558 | update_MKIFS_PATH (image_processor); |
|
1286 | 1559 | ||
1287 | // open build file |
1560 | // open build file |
1288 | buildfile_fp = fopen (buildfile_pathname, "rb"); |
1561 | buildfile_fp = fopen (buildfile_pathname, "rb"); |
1289 | if (buildfile_fp == NULL) |
1562 | if (buildfile_fp == NULL) |
1290 | { |
1563 | { |
Line 1293... | Line 1566... | ||
1293 | } |
1566 | } |
1294 | 1567 | ||
1295 | // stack up filesystem entries |
1568 | // stack up filesystem entries |
1296 | memcpy (&entry_parms, &default_parms, sizeof (default_parms)); |
1569 | memcpy (&entry_parms, &default_parms, sizeof (default_parms)); |
1297 | entry_parms.st_mode = S_IFDIR | default_parms.dperms; |
1570 | entry_parms.st_mode = S_IFDIR | default_parms.dperms; |
1298 | add_fsentry (&fsentries, &fsentry_count |
1571 | add_fsentry (&fsentries, &fsentry_count, &entry_parms, "", NULL); // add the root dir first |
1299 | 1572 | ||
1300 | while (fgets (line_buffer, sizeof (line_buffer), buildfile_fp) != NULL) |
1573 | while (fgets (line_buffer, sizeof (line_buffer), buildfile_fp) != NULL) |
1301 | { |
1574 | { |
- | 1575 | if (current_line != NULL) |
|
- | 1576 | free (current_line); |
|
- | 1577 | current_line = strdup (line_buffer); |
|
- | 1578 | if (current_line == NULL) |
|
- | 1579 | { |
|
- | 1580 | fprintf (stderr, "fatal error: out of memory\n"); |
|
- | 1581 | exit (1); |
|
- | 1582 | } |
|
1302 | lineno++; // keep track of current line number |
1583 | lineno++; // keep track of current line number |
1303 | //fprintf (stderr, "read buildfile line %d: {%s}\n", lineno, line_buffer); |
1584 | //fprintf (stderr, "read buildfile line %d: {%s}\n", lineno, line_buffer); |
1304 | 1585 | ||
1305 | line_ptr = line_buffer; |
1586 | line_ptr = line_buffer; |
1306 | while ((*line_ptr != 0) && isspace (*line_ptr)) |
1587 | while ((*line_ptr != 0) && isspace (*line_ptr)) |
Line 1313... | Line 1594... | ||
1313 | if ((string_len > 0) && (line_buffer[string_len - 1] == '\n')) |
1594 | if ((string_len > 0) && (line_buffer[string_len - 1] == '\n')) |
1314 | line_buffer[string_len - 1] = 0; // chop off newline for easier debug output |
1595 | line_buffer[string_len - 1] = 0; // chop off newline for easier debug output |
1315 | 1596 | ||
1316 | // reset entry values |
1597 | // reset entry values |
1317 | memcpy (&entry_parms, &default_parms, sizeof (default_parms)); |
1598 | memcpy (&entry_parms, &default_parms, sizeof (default_parms)); |
- | 1599 | path_in_ifs[0] = 0; |
|
- | 1600 | path_on_buildhost[0] = 0; |
|
1318 | 1601 | ||
1319 | //fprintf (stderr, "parsing buildfile line %d: [%s]\n", lineno, line_ptr); |
1602 | //fprintf (stderr, "parsing buildfile line %d: [%s]\n", lineno, line_ptr); |
1320 | 1603 | ||
1321 | // does this line start with an attribute block ? |
1604 | // does this line start with an attribute block ? |
1322 | if (*line_ptr == '[') |
1605 | if (*line_ptr == '[') |
Line 1368... | Line 1651... | ||
1368 | } |
1651 | } |
1369 | if ((sep = strchr (value, ',')) != NULL) // do we have a comma separating (optional) processor and boot file name ? |
1652 | if ((sep = strchr (value, ',')) != NULL) // do we have a comma separating (optional) processor and boot file name ? |
1370 | { |
1653 | { |
1371 | *sep = 0; |
1654 | *sep = 0; |
1372 | strcpy (image_processor, value); // save processor |
1655 | strcpy (image_processor, value); // save processor |
- | 1656 | update_MKIFS_PATH (image_processor); |
|
1373 | value = sep + 1; |
1657 | value = sep + 1; |
1374 | } |
1658 | } |
1375 | //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.) |
1659 | //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.) |
1376 | //strcpy (image_bootfile, bootfile_pathname); // FIXME: HACK |
1660 | //strcpy (image_bootfile, bootfile_pathname); // FIXME: HACK |
1377 | if (stat (bootfile_pathname, &stat_buf) != 0) |
1661 | if (stat (bootfile_pathname, &stat_buf) != 0) |
Line 1384... | Line 1668... | ||
1384 | if (stat (kernelfile_pathname, &stat_buf) != 0) |
1668 | if (stat (kernelfile_pathname, &stat_buf) != 0) |
1385 | { |
1669 | { |
1386 | fprintf (stderr, "fatal error: unable to read precompiled kernel file \"%s\" specified in --kernelfile argument\n", kernelfile_pathname); |
1670 | fprintf (stderr, "fatal error: unable to read precompiled kernel file \"%s\" specified in --kernelfile argument\n", kernelfile_pathname); |
1387 | exit (1); |
1671 | exit (1); |
1388 | } |
1672 | } |
1389 | entry_parms. |
1673 | entry_parms.data = malloc (stat_buf.st_size); |
1390 | if (entry_parms. |
1674 | if (entry_parms.data == NULL) |
1391 | { |
1675 | { |
1392 | fprintf (stderr, "fatal error: out of memory\n"); |
1676 | fprintf (stderr, "fatal error: out of memory\n"); |
1393 | exit (1); |
1677 | exit (1); |
1394 | } |
1678 | } |
1395 | fp = fopen (kernelfile_pathname, "rb"); |
1679 | fp = fopen (kernelfile_pathname, "rb"); |
1396 | fread (entry_parms. |
1680 | fread (entry_parms.data, 1, stat_buf.st_size, fp); |
1397 | fclose (fp); |
1681 | fclose (fp); |
1398 | entry_parms. |
1682 | entry_parms.datalen = stat_buf.st_size; |
1399 | } |
1683 | } |
- | 1684 | else if (strncmp (token, "mtime=", 6) == 0) { REACH_TOKEN_VALUE (); if (strcmp (value, "*") == 0) entry_parms.mtime = UINT32_MAX; else { |
|
- | 1685 | // value *must* be "YYYY-MM-DD-HH:MM:SS" by specification |
|
- | 1686 | memset (&utc_time, 0, sizeof (utc_time)); |
|
- | 1687 | if (sscanf (value, "%u-%u-%u-%u:%u:%u", &utc_time.tm_year, &utc_time.tm_mon, &utc_time.tm_mday, &utc_time.tm_hour, &utc_time.tm_min, &utc_time.tm_sec) != 6) |
|
- | 1688 | { |
|
- | 1689 | fprintf (stderr, "warning: syntax error in \"%s\" line %d: mtime specification not in YYYY-MM-DD-HH:MM:SS format (skipping)\n", buildfile_pathname, lineno); |
|
- | 1690 | continue; // invalid attribute block, skip line |
|
- | 1691 | } |
|
- | 1692 | utc_time.tm_mon--; // convert month from [1-12] to [0-11] |
|
- | 1693 | entry_parms.mtime = (uint32_t) mktime (&utc_time); |
|
- | 1694 | } |
|
- | 1695 | } |
|
1400 | else if (strcmp (token, "+script") == 0) { |
1696 | else if (strcmp (token, "+script") == 0) { |
1401 | entry_parms.is_compiled_bootscript = true; |
1697 | entry_parms.is_compiled_bootscript = true; |
- | 1698 | entry_parms.data = malloc (sizeof (INITIAL_STARTUP_SCRIPT) - 1); |
|
- | 1699 | if (entry_parms.data == NULL) |
|
- | 1700 | { |
|
- | 1701 | fprintf (stderr, "fatal error: out of memory\n"); |
|
- | 1702 | exit (1); |
|
- | 1703 | } |
|
1402 | entry_parms. |
1704 | memcpy (entry_parms.data, INITIAL_STARTUP_SCRIPT, sizeof (INITIAL_STARTUP_SCRIPT) - 1); // FIXME: HACK until the script compiler is implemented |
1403 | entry_parms. |
1705 | entry_parms.datalen = sizeof (INITIAL_STARTUP_SCRIPT) - 1; |
1404 | } |
1706 | } |
- | 1707 | else if (strcmp (token, "-script") == 0) entry_parms.is_compiled_bootscript = false; |
|
- | 1708 | else if (strcmp (token, "+followlink") == 0) entry_parms.should_follow_symlinks = true; |
|
- | 1709 | else if (strcmp (token, "-followlink") == 0) entry_parms.should_follow_symlinks = false; |
|
- | 1710 | else if (strcmp (token, "+autolink") == 0) entry_parms.should_autosymlink_dylib = true; |
|
- | 1711 | else if (strcmp (token, "-autolink") == 0) entry_parms.should_autosymlink_dylib = false; |
|
1405 | else fprintf (stderr, "warning: unimplemented attribute in \"%s\" line %d: '%s'\n", buildfile_pathname, lineno, token); |
1712 | else fprintf (stderr, "warning: unimplemented attribute in \"%s\" line %d: '%s'\n", buildfile_pathname, lineno, token); |
1406 | #undef REACH_TOKEN_VALUE |
1713 | #undef REACH_TOKEN_VALUE |
1407 | 1714 | ||
1408 | token = strtok (NULL, RECORD_SEP_STR); // proceed to next attribute token |
1715 | token = strtok (NULL, RECORD_SEP_STR); // proceed to next attribute token |
1409 | } |
1716 | } |
Line 1421... | Line 1728... | ||
1421 | } } while (0) |
1728 | } } while (0) |
1422 | #define APPLY_DEFAULT_ATTR_STR(attr,descr,fmt) do { if (strcmp (entry_parms.attr, default_parms.attr) != 0) { \ |
1729 | #define APPLY_DEFAULT_ATTR_STR(attr,descr,fmt) do { if (strcmp (entry_parms.attr, default_parms.attr) != 0) { \ |
1423 | fprintf (stderr, "info: changing default " descr " from " fmt " to " fmt " by attribute at \"%s\" line %d\n", default_parms.attr, entry_parms.attr, buildfile_pathname, lineno); \ |
1730 | fprintf (stderr, "info: changing default " descr " from " fmt " to " fmt " by attribute at \"%s\" line %d\n", default_parms.attr, entry_parms.attr, buildfile_pathname, lineno); \ |
1424 | strcpy (default_parms.attr, entry_parms.attr); \ |
1731 | strcpy (default_parms.attr, entry_parms.attr); \ |
1425 | } } while (0) |
1732 | } } while (0) |
1426 | APPLY_DEFAULT_ATTR_NUM (dperms, "directory permissions", "0%o"); |
1733 | APPLY_DEFAULT_ATTR_NUM (dperms, "directory permissions", "0%o"); |
1427 | APPLY_DEFAULT_ATTR_NUM (perms, "file permissions", "0%o"); |
1734 | APPLY_DEFAULT_ATTR_NUM (perms, "file permissions", "0%o"); |
1428 | APPLY_DEFAULT_ATTR_NUM (uid, "owner ID", "%d"); |
1735 | APPLY_DEFAULT_ATTR_NUM (uid, "owner ID", "%d"); |
1429 | APPLY_DEFAULT_ATTR_NUM (gid, "group ID", "%d"); |
1736 | APPLY_DEFAULT_ATTR_NUM (gid, "group ID", "%d"); |
1430 | APPLY_DEFAULT_ATTR_NUM (st_mode, "inode type", "0%o"); |
1737 | APPLY_DEFAULT_ATTR_NUM (st_mode, "inode type", "0%o"); |
1431 | APPLY_DEFAULT_ATTR_STR (prefix, "prefix", "\"%s\""); |
1738 | APPLY_DEFAULT_ATTR_STR (prefix, "prefix", "\"%s\""); |
1432 | APPLY_DEFAULT_ATTR_NUM (is_compiled_bootscript, "compiled script state", "%d"); |
1739 | APPLY_DEFAULT_ATTR_NUM (is_compiled_bootscript, "compiled script state", "%d"); |
- | 1740 | APPLY_DEFAULT_ATTR_NUM (should_follow_symlinks, "symlink resolution", "%d"); |
|
- | 1741 | APPLY_DEFAULT_ATTR_NUM (should_autosymlink_dylib, "dylib canonical name symlinking", "%d"); |
|
1433 | #undef APPLY_DEFAULT_ATTR_STR |
1742 | #undef APPLY_DEFAULT_ATTR_STR |
1434 | #undef APPLY_DEFAULT_ATTR_NUM |
1743 | #undef APPLY_DEFAULT_ATTR_NUM |
1435 | continue; // end of line reached, proceed to the next line |
1744 | continue; // end of line reached, proceed to the next line |
1436 | } |
1745 | } |
1437 | // end of attributes parsing |
1746 | // end of attributes parsing |
Line 1441... | Line 1750... | ||
1441 | string_len = sprintf (path_in_ifs, "%s", entry_parms.prefix); |
1750 | string_len = sprintf (path_in_ifs, "%s", entry_parms.prefix); |
1442 | while ((string_len > 0) && (path_in_ifs[string_len - 1] == '/')) |
1751 | while ((string_len > 0) && (path_in_ifs[string_len - 1] == '/')) |
1443 | string_len--; // chop off any trailing slashes from prefix |
1752 | string_len--; // chop off any trailing slashes from prefix |
1444 | write_ptr = &path_in_ifs[string_len]; |
1753 | write_ptr = &path_in_ifs[string_len]; |
1445 | *write_ptr++ = '/'; // add ONE trailing slash |
1754 | *write_ptr++ = '/'; // add ONE trailing slash |
- | 1755 | specifiedpathname_start = write_ptr; // remember the specified pathname will start here |
|
- | 1756 | is_quoted_context = (*line_ptr == '"'); |
|
- | 1757 | if (is_quoted_context) |
|
- | 1758 | line_ptr++; // skip a possible initial quote |
|
1446 | if (*line_ptr == '/') |
1759 | if (*line_ptr == '/') |
1447 | { |
1760 | { |
1448 | fprintf (stderr, "warning: paths in the IFS file should not begin with a leading '/' in \"%s\" line %d\n", buildfile_pathname, lineno); |
1761 | fprintf (stderr, "warning: paths in the IFS file should not begin with a leading '/' in \"%s\" line %d\n", buildfile_pathname, lineno); |
1449 | line_ptr++; // consistency check: paths in the IFS should not begin with a '/' |
1762 | line_ptr++; // consistency check: paths in the IFS should not begin with a '/' |
1450 | } |
1763 | } |
1451 | while ((*line_ptr != 0) && (*line_ptr != '=') && !isspace (*line_ptr)) |
1764 | while ((*line_ptr != 0) && ((!is_quoted_context && (*line_ptr != '=') && !isspace (*line_ptr)) || (is_quoted_context && (*line_ptr == '"')))) |
1452 | { |
1765 | { |
1453 | if (*line_ptr == '\\') |
1766 | if (*line_ptr == '\\') |
1454 | { |
1767 | { |
1455 | line_ptr++; |
1768 | line_ptr++; |
1456 | *write_ptr++ = *line_ptr; // unescape characters that are escaped with '\' |
1769 | *write_ptr++ = *line_ptr; // unescape characters that are escaped with '\' |
Line 1458... | Line 1771... | ||
1458 | else |
1771 | else |
1459 | *write_ptr++ = *line_ptr; |
1772 | *write_ptr++ = *line_ptr; |
1460 | line_ptr++; |
1773 | line_ptr++; |
1461 | } |
1774 | } |
1462 | *write_ptr = 0; // terminate the string |
1775 | *write_ptr = 0; // terminate the string |
- | 1776 | if (is_quoted_context && (*line_ptr == '"')) |
|
- | 1777 | line_ptr++; // skip a possible final quote |
|
1463 | 1778 | ||
1464 | // we reached a space OR an equal sign |
1779 | // we reached a space OR an equal sign |
1465 | while ((*line_ptr != 0) && isspace (*line_ptr)) |
1780 | while ((*line_ptr != 0) && isspace (*line_ptr)) |
1466 | line_ptr++; // skip optional spaces after the filename in the IFS |
1781 | line_ptr++; // skip optional spaces after the filename in the IFS |
1467 | - | ||
1468 | blob_data = NULL; |
- | |
1469 | blob_datasize = 0; |
- | |
1470 | blob_datalen = 0; |
- | |
1471 | 1782 | ||
1472 | // do we have an equal sign ? |
1783 | // do we have an equal sign ? |
1473 | if (*line_ptr == '=') // we must be creating either a directory or a file, do we have an equal sign ? |
1784 | if (*line_ptr == '=') // we must be creating either a directory or a file, do we have an equal sign ? |
1474 | { |
1785 | { |
1475 | line_ptr++; // skip the equal sign |
1786 | line_ptr++; // skip the equal sign |
Line 1483... | Line 1794... | ||
1483 | } |
1794 | } |
1484 | 1795 | ||
1485 | // read the host system's path, it may be either a path or a contents definition. Is it a content definition ? |
1796 | // read the host system's path, it may be either a path or a contents definition. Is it a content definition ? |
1486 | if (*line_ptr == '{') |
1797 | if (*line_ptr == '{') |
1487 | { |
1798 | { |
- | 1799 | path_on_buildhost[0] = 0; // this is an inline fine, which means it doesn't exist on the build host |
|
- | 1800 | allocated_size = 0; |
|
- | 1801 | ||
1488 | line_ptr++; // skip the leading content definition |
1802 | line_ptr++; // skip the leading content definition |
1489 | is_escaped_char = false; |
1803 | is_escaped_char = false; |
1490 | for (;;) |
1804 | for (;;) |
1491 | { |
1805 | { |
1492 | read_char = fgetc (buildfile_fp); |
1806 | read_char = fgetc (buildfile_fp); |
Line 1500... | Line 1814... | ||
1500 | else if ((read_char == '}') && !is_escaped_char) |
1814 | else if ((read_char == '}') && !is_escaped_char) |
1501 | break; // found an unescaped closing bracked, stop parsing |
1815 | break; // found an unescaped closing bracked, stop parsing |
1502 | else |
1816 | else |
1503 | { |
1817 | { |
1504 | is_escaped_char = false; // any other char, meaning the next one will not be escaped |
1818 | is_escaped_char = false; // any other char, meaning the next one will not be escaped |
1505 | if ( |
1819 | if (entry_parms.data == NULL) // only store the contents if we do NOT know the data yet |
1506 | { |
1820 | { |
1507 |
|
1821 | if (entry_parms.datalen == allocated_size) // reallocate in 4 kb blocks |
1508 | if (reallocated_ptr == NULL) |
- | |
1509 | { |
1822 | { |
- | 1823 | reallocated_ptr = realloc (entry_parms.data, allocated_size + 4096); |
|
- | 1824 | if (reallocated_ptr == NULL) |
|
- | 1825 | { |
|
1510 | fprintf (stderr, "fatal error: out of memory\n"); |
1826 | fprintf (stderr, "fatal error: out of memory\n"); |
1511 | exit (1); |
1827 | exit (1); |
- | 1828 | } |
|
- | 1829 | entry_parms.data = reallocated_ptr; |
|
- | 1830 | allocated_size += 4096; |
|
1512 | } |
1831 | } |
1513 |
|
1832 | entry_parms.data[entry_parms.datalen++] = read_char; |
1514 | blob_datasize += 4096; |
- | |
1515 | } |
1833 | } |
1516 | blob_data[blob_datalen++] = read_char; |
- | |
1517 | if (read_char == '\n') |
1834 | if (read_char == '\n') |
1518 | lineno++; |
1835 | lineno++; |
1519 | } |
1836 | } |
1520 | } |
1837 | } |
1521 | } |
1838 | } |
1522 | else // not a content definition between { brackets }, |
1839 | else // not a content definition between { brackets }, must be either a pathname on the build host, or the target of a symlink |
1523 | { |
1840 | { |
- | 1841 | is_quoted_context = (*line_ptr == '"'); |
|
- | 1842 | if (is_quoted_context) |
|
- | 1843 | line_ptr++; // skip a possible initial quote |
|
- | 1844 | specifiedpathname_start = line_ptr; // remember where the specified pathname starts |
|
1524 |
|
1845 | write_ptr = line_ptr; // now unescape all characters |
- | 1846 | while ((*line_ptr != 0) && ((!is_quoted_context && !isspace (*line_ptr)) || (is_quoted_context && (*line_ptr == '"')))) |
|
- | 1847 | { |
|
- | 1848 | if (*line_ptr == '\\') |
|
- | 1849 | { |
|
- | 1850 | line_ptr++; |
|
- | 1851 | *write_ptr++ = *line_ptr; // unescape characters that are escaped with '\' |
|
- | 1852 | } |
|
- | 1853 | else |
|
- | 1854 | *write_ptr++ = *line_ptr; |
|
- | 1855 | line_ptr++; |
|
- | 1856 | } |
|
- | 1857 | *write_ptr = 0; // terminate the string |
|
- | 1858 | if (is_quoted_context && (*line_ptr == '"')) |
|
- | 1859 | line_ptr++; // skip a possible final quote |
|
- | 1860 | ||
- | 1861 | if (S_ISLNK (entry_parms.st_mode)) // are we storing a symlink ? |
|
- | 1862 | { |
|
- | 1863 | entry_parms.datalen = strlen (specifiedpathname_start); // if so, store the symlink target as the dirent's blob data |
|
- | 1864 | entry_parms.data = strdup (specifiedpathname_start); |
|
- | 1865 | if (entry_parms.data == NULL) |
|
- | 1866 | { |
|
- | 1867 | fprintf (stderr, "fatal error: out of memory\n"); |
|
1525 |
|
1868 | exit (1); |
- | 1869 | } |
|
- | 1870 | } |
|
- | 1871 | else // it's a build host filesystem path |
|
- | 1872 | strcpy (path_on_buildhost, line_ptr); // the path on the build host is given after the equal sign |
|
1526 | } |
1873 | } |
1527 | } |
1874 | } |
1528 | else // no equal sign, meaning the file will have the same name on the build host filesystem |
1875 | else // no equal sign, meaning the file will have the same name on the build host filesystem |
1529 | { |
1876 | { |
1530 | // consistency check: symlinks MUST have an equal sign |
1877 | // consistency check: symlinks MUST have an equal sign |
Line 1532... | Line 1879... | ||
1532 | { |
1879 | { |
1533 | fprintf (stderr, "warning: syntax error in \"%s\" line %d: missing equal sign and symlink target (skipping)\n", buildfile_pathname, lineno); |
1880 | fprintf (stderr, "warning: syntax error in \"%s\" line %d: missing equal sign and symlink target (skipping)\n", buildfile_pathname, lineno); |
1534 | continue; // invalid symlink specification, skip line |
1881 | continue; // invalid symlink specification, skip line |
1535 | } |
1882 | } |
1536 | 1883 | ||
1537 |
|
1884 | strcpy (path_on_buildhost, specifiedpathname_start); // the path on the build host is the one specified |
- | 1885 | sep = strrchr (specifiedpathname_start, '/'); |
|
1538 |
|
1886 | if (sep != NULL) |
- | 1887 | memmove (specifiedpathname_start, sep + 1, strlen (sep + 1) + 1); // the path in the IFS will be the BASENAME of the path specified (after the prefix) |
|
1539 | } |
1888 | } |
1540 | 1889 | ||
1541 | // now add this entry to the image filesystem |
1890 | // now add this entry to the image filesystem |
- | 1891 | if (S_ISDIR (entry_parms.st_mode)) |
|
1542 |
|
1892 | entry_parms.st_mode |= entry_parms.dperms; |
- | 1893 | else if (S_ISLNK (entry_parms.st_mode)) |
|
1543 |
|
1894 | entry_parms.st_mode |= 0777; // NOTE: mkifs sets symlink permissions to rwxrwxrwx !? |
1544 |
|
1895 | else // file or device node |
1545 |
|
1896 | entry_parms.st_mode |= entry_parms.perms; |
1546 | } |
- | |
1547 | 1897 | ||
1548 | // sort the filesystem entries by pathname |
- | |
1549 |
|
1898 | add_fsentry (&fsentries, &fsentry_count, &entry_parms, path_in_ifs, path_on_buildhost); // and add filesystem entry |
1550 | 1899 | ||
1551 | // calculate filesystem entries size |
- | |
1552 | imgdir_size = sizeof (image_header); |
- | |
1553 | for (fsentry_index = 0; fsentry_index < fsentry_count; fsentry_index++) |
- | |
1554 | { |
- | |
1555 |
|
1900 | if (entry_parms.data != NULL) |
1556 |
|
1901 | free (entry_parms.data); // if blob data was allocated, free it |
1557 | } |
1902 | } |
1558 | fprintf (stderr, "info: image directory size: %zd (0x%zx)\n", imgdir_size, imgdir_size); |
- | |
1559 | 1903 | ||
1560 | // write IFS file |
1904 | // write IFS file |
1561 | fp = fopen (ifs_pathname, " |
1905 | fp = fopen (ifs_pathname, "w+b"); |
1562 | if (fp == NULL) |
1906 | if (fp == NULL) |
1563 | { |
1907 | { |
1564 | fprintf (stderr, "error: failed to open \"%s\" for writing (%s)\n", ifs_pathname, strerror (errno)); |
1908 | fprintf (stderr, "error: failed to open \"%s\" for writing (%s)\n", ifs_pathname, strerror (errno)); |
1565 | exit (1); |
1909 | exit (1); |
1566 | } |
1910 | } |
Line 1613... | Line 1957... | ||
1613 | imgheader_offset = ftell (fp); // save image header offset |
1957 | imgheader_offset = ftell (fp); // save image header offset |
1614 | memset (&image_header, 0, sizeof (image_header)); // prepare image header |
1958 | memset (&image_header, 0, sizeof (image_header)); // prepare image header |
1615 | memcpy (&image_header.signature, "imagefs", 7); // image filesystem signature, i.e. "imagefs" |
1959 | memcpy (&image_header.signature, "imagefs", 7); // image filesystem signature, i.e. "imagefs" |
1616 | image_header.flags = IMAGE_FLAGS_TRAILER_V2 | IMAGE_FLAGS_SORTED | IMAGE_FLAGS_INO_BITS; // endian neutral flags, 0x1c (IMAGE_FLAGS_TRAILER_V2 |Â IMAGE_FLAGS_SORTED |Â IMAGE_FLAGS_INO_BITS) |
1960 | image_header.flags = IMAGE_FLAGS_TRAILER_V2 | IMAGE_FLAGS_SORTED | IMAGE_FLAGS_INO_BITS; // endian neutral flags, 0x1c (IMAGE_FLAGS_TRAILER_V2 |Â IMAGE_FLAGS_SORTED |Â IMAGE_FLAGS_INO_BITS) |
1617 | image_header.image_size = WILL_BE_FILLED_LATER; // size from header to end of trailer (here 0xca6fe0 or 13 266 912) |
1961 | image_header.image_size = WILL_BE_FILLED_LATER; // size from header to end of trailer (here 0xca6fe0 or 13 266 912) |
1618 | image_header.hdr_dir_size = |
1962 | image_header.hdr_dir_size = WILL_BE_FILLED_LATER; // size from header to last dirent (here 0x12b8 or 4792) |
1619 | image_header.dir_offset = sizeof (image_header); // offset from header to first dirent (here 0x5c or 92) |
1963 | image_header.dir_offset = sizeof (image_header); // offset from header to first dirent (here 0x5c or 92) |
1620 | image_header.boot_ino[0] = image_kernel_ino; // inode of files for bootstrap p[ro?]g[ra?]ms (here 0xa0000002, 0, 0, 0) |
1964 | image_header.boot_ino[0] = image_kernel_ino; // inode of files for bootstrap p[ro?]g[ra?]ms (here 0xa0000002, 0, 0, 0) |
1621 | image_header.script_ino = image_bootscript_ino; // inode of file for script (here 3) |
1965 | image_header.script_ino = image_bootscript_ino; // inode of file for script (here 3) |
1622 | image_header.mountpoint[0] = '/'; // default mountpoint for image ("/" + "\0\0\0") |
1966 | image_header.mountpoint[0] = '/'; // default mountpoint for image ("/" + "\0\0\0") |
1623 | fwrite (&image_header, sizeof (image_header), 1, fp); // write image header |
1967 | fwrite (&image_header, sizeof (image_header), 1, fp); // write image header |
1624 | PAD_OUTFILE_TO (ROUND_TO_UPPER_MULTIPLE (ftell (fp), image_align)); // pad as necessary |
1968 | PAD_OUTFILE_TO (ROUND_TO_UPPER_MULTIPLE (ftell (fp), image_align)); // pad as necessary |
1625 | 1969 | ||
1626 | // write image directory (with the wrong file offsets) |
1970 | // write image directory (with the wrong file offsets) |
- | 1971 | if (image_header.flags & IMAGE_FLAGS_SORTED) |
|
- | 1972 | qsort (&fsentries[1], fsentry_count - 1, sizeof (fsentry_t), fsentry_compare_pathnames_cb); // sort the filesystem entries by pathname |
|
1627 | imgdir_offset = ftell (fp); |
1973 | imgdir_offset = ftell (fp); |
- | 1974 | imgdir_size = 0; // measure image dir size on the fly |
|
1628 | for (fsentry_index = 0; fsentry_index < fsentry_count; fsentry_index++) |
1975 | for (fsentry_index = 0; fsentry_index < fsentry_count; fsentry_index++) |
1629 | fwrite_fsentry (&fsentries[fsentry_index], fp); // NOTE: padding is handled in this function |
1976 | imgdir_size += fwrite_fsentry (&fsentries[fsentry_index], fp); // NOTE: padding is handled in this function |
1630 |
|
1977 | imgdir_size += fwrite ("\0\0\0\0", 1, 4, fp); // there seems to be 4 bytes of padding after the image directory |
1631 | 1978 | ||
1632 | // is it a bootable image with a kernel file ? |
1979 | // is it a bootable image with a kernel file ? |
1633 | if ((startupfile_pathname != NULL) && (kernelfile_pathname != NULL)) |
1980 | if ((startupfile_pathname != NULL) && (kernelfile_pathname != NULL)) |
1634 | { |
1981 | { |
1635 | // |
1982 | // start by writing the startup script data blob, if we have one |
1636 |
|
1983 | for (fsentry_index = 1; fsentry_index < fsentry_count; fsentry_index++) |
1637 | - | ||
1638 |
|
1984 | if (fsentries[fsentry_index].header.ino == image_bootscript_ino) |
- | 1985 | break; // locate it |
|
1639 |
|
1986 | if (fsentry_index < fsentry_count) // found it ? |
1640 | { |
1987 | { |
1641 | if (!S_ISREG (fsentries[fsentry_index].header.mode) || fsentries[fsentry_index].UNSAVED_was_data_written) |
- | |
1642 | continue; // skip all entries that don't have a separate data block and those who were written already |
- | |
1643 | curr_offset = ftell (fp); |
1988 | curr_offset = ftell (fp); |
1644 | if (curr_offset + fsentries[fsentry_index].u.file.size >= kernelfile_offset) |
1989 | if (curr_offset + fsentries[fsentry_index].u.file.size >= kernelfile_offset) |
- | 1990 | { |
|
1645 |
|
1991 | fprintf (stderr, "error: the compiled startup script is too big (%zd bytes, max is %zd) to fit at current offset %zd\n", (size_t) fsentries[fsentry_index].u.file.size, kernelfile_offset - curr_offset, curr_offset); |
- | 1992 | exit (1); |
|
- | 1993 | } |
|
1646 | fsentries[fsentry_index].u.file.offset = (uint32_t) (curr_offset - imgheader_offset); // save file data blob offset in file structure |
1994 | fsentries[fsentry_index].u.file.offset = (uint32_t) (curr_offset - imgheader_offset); // save file data blob offset in file structure |
1647 | fwrite (fsentries[fsentry_index].u.file.UNSAVED_databuf, 1, fsentries[fsentry_index].u.file.size, fp); // write file data blob |
1995 | fwrite (fsentries[fsentry_index].u.file.UNSAVED_databuf, 1, fsentries[fsentry_index].u.file.size, fp); // write file data blob |
1648 | PAD_OUTFILE_TO |
1996 | // PAD_OUTFILE_TO (ROUND_TO_UPPER_MULTIPLE (ftell (fp), image_align)); // pad as necessary |
1649 | fsentries[fsentry_index].UNSAVED_was_data_written = true; // and remember this file's data was written |
1997 | fsentries[fsentry_index].UNSAVED_was_data_written = true; // and remember this file's data was written |
- | 1998 | } |
|
- | 1999 | ||
- | 2000 | // now write the filesystem entries that may fit before the kernel |
|
- | 2001 | for (;;) |
|
- | 2002 | { |
|
- | 2003 | curr_offset = ftell (fp); // see where we are |
|
- | 2004 | available_space = kernelfile_offset - curr_offset; // measure the available space |
|
- | 2005 | ||
- | 2006 | // look for the biggest one that can fit |
|
- | 2007 | largest_index = 0; |
|
- | 2008 | largest_size = SIZE_MAX; |
|
- | 2009 | for (fsentry_index = 1; fsentry_index < fsentry_count; fsentry_index++) |
|
- | 2010 | { |
|
- | 2011 | if (!S_ISREG (fsentries[fsentry_index].header.mode) || fsentries[fsentry_index].UNSAVED_was_data_written || (fsentries[fsentry_index].u.file.size > available_space)) |
|
- | 2012 | continue; // skip all entries that don't have a separate data block, those who were written already and those that wouldn't fit |
|
- | 2013 | if (fsentries[fsentry_index].u.file.size > largest_size) |
|
- | 2014 | { |
|
- | 2015 | largest_size = fsentries[fsentry_index].u.file.size; |
|
- | 2016 | largest_index = fsentry_index; |
|
- | 2017 | } |
|
- | 2018 | } |
|
- | 2019 | if (largest_size == SIZE_MAX) |
|
- | 2020 | break; // found none ? if so, stop searching |
|
- | 2021 | ||
- | 2022 | fsentries[largest_index].u.file.offset = (uint32_t) (curr_offset - imgheader_offset); // save file data blob offset in file structure |
|
- | 2023 | fwrite (fsentries[largest_index].u.file.UNSAVED_databuf, 1, fsentries[largest_index].u.file.size, fp); // write file data blob |
|
- | 2024 | // PAD_OUTFILE_TO (ROUND_TO_UPPER_MULTIPLE (ftell (fp), image_align)); // pad as necessary |
|
- | 2025 | fsentries[largest_index].UNSAVED_was_data_written = true; // and remember this file's data was written |
|
1650 | } |
2026 | } |
1651 | PAD_OUTFILE_TO (kernelfile_offset); // reach the kernel offset |
2027 | PAD_OUTFILE_TO (kernelfile_offset); // reach the kernel offset |
1652 | 2028 | ||
1653 | // ###################################################################################################################################################################################################################################### |
2029 | // ###################################################################################################################################################################################################################################### |
1654 | // # FIXME: figure out how to re-create it: linker call involved |
2030 | // # FIXME: figure out how to re-create it: linker call involved |
Line 1657... | Line 2033... | ||
1657 | fwrite_filecontents (kernelfile_pathname, fp); // write kernel from blob file |
2033 | fwrite_filecontents (kernelfile_pathname, fp); // write kernel from blob file |
1658 | PAD_OUTFILE_TO (ROUND_TO_UPPER_MULTIPLE (ftell (fp), image_align)); // pad as necessary |
2034 | PAD_OUTFILE_TO (ROUND_TO_UPPER_MULTIPLE (ftell (fp), image_align)); // pad as necessary |
1659 | } |
2035 | } |
1660 | 2036 | ||
1661 | // then write all the other files |
2037 | // then write all the other files |
1662 | for (fsentry_index = |
2038 | for (fsentry_index = 1; fsentry_index < fsentry_count; fsentry_index++) |
1663 | { |
2039 | { |
1664 | if (!S_ISREG (fsentries[fsentry_index].header.mode) || fsentries[fsentry_index].UNSAVED_was_data_written) |
2040 | if (!S_ISREG (fsentries[fsentry_index].header.mode) || fsentries[fsentry_index].UNSAVED_was_data_written) |
1665 | continue; // skip all entries that don't have a separate data block and those who were written already |
2041 | continue; // skip all entries that don't have a separate data block and those who were written already |
1666 | curr_offset = ftell (fp); |
2042 | curr_offset = ftell (fp); |
1667 | fsentries[fsentry_index].u.file.offset = (uint32_t) (curr_offset - imgheader_offset); // save file data blob offset in file structure |
2043 | fsentries[fsentry_index].u.file.offset = (uint32_t) (curr_offset - imgheader_offset); // save file data blob offset in file structure |
1668 | fwrite (fsentries[fsentry_index].u.file.UNSAVED_databuf, 1, fsentries[fsentry_index].u.file.size, fp); // write file data blob |
2044 | fwrite (fsentries[fsentry_index].u.file.UNSAVED_databuf, 1, fsentries[fsentry_index].u.file.size, fp); // write file data blob |
1669 |
|
2045 | // PAD_OUTFILE_TO (ROUND_TO_UPPER_MULTIPLE (ftell (fp), image_align)); // pad as necessary |
1670 | fsentries[fsentry_index].UNSAVED_was_data_written = true; // and remember this file's data was written |
2046 | fsentries[fsentry_index].UNSAVED_was_data_written = true; // and remember this file's data was written |
1671 | } |
2047 | } |
1672 | 2048 | ||
1673 | // finally, write trailer (including empty checksum) |
2049 | // finally, write trailer (including empty checksum) |
1674 | imgtrailer_offset = ftell (fp); // save image trailer offset |
2050 | imgtrailer_offset = ftell (fp); // save image trailer offset |
Line 1696... | Line 2072... | ||
1696 | startup_header.ram_size = (uint32_t) final_size; // FIXME: this is necessarily a bit less, but should we really bother calculating the right size ? |
2072 | startup_header.ram_size = (uint32_t) final_size; // FIXME: this is necessarily a bit less, but should we really bother calculating the right size ? |
1697 | startup_header.stored_size = startup_header.ram_size; |
2073 | startup_header.stored_size = startup_header.ram_size; |
1698 | fwrite (&startup_header, sizeof (startup_header), 1, fp); // write startup header |
2074 | fwrite (&startup_header, sizeof (startup_header), 1, fp); // write startup header |
1699 | 2075 | ||
1700 | // compute SHA-512 checksum and V1 checksum of startup block |
2076 | // compute SHA-512 checksum and V1 checksum of startup block |
1701 |
|
2077 | blob_size = startuptrailer_offset - startupheader_offset; |
1702 | blob_data = malloc ( |
2078 | blob_data = malloc (blob_size + sizeof (startup_trailer)); |
1703 | if (blob_data == NULL) |
2079 | if (blob_data == NULL) |
1704 | { |
2080 | { |
1705 | fprintf (stderr, "fatal error: out of memory\n"); |
2081 | fprintf (stderr, "fatal error: out of memory\n"); |
1706 | exit (1); |
2082 | exit (1); |
1707 | } |
2083 | } |
1708 | fseek (fp, startupheader_offset, SEEK_SET); |
2084 | fseek (fp, startupheader_offset, SEEK_SET); |
1709 | fread (blob_data, 1, |
2085 | fread (blob_data, 1, blob_size, fp); |
1710 | SHA512 (blob_data, |
2086 | SHA512 (blob_data, blob_size, startup_trailer.sha512); // compute SHA512 checksum |
1711 | if ( ( (startup_header.flags1 & STARTUP_HDR_FLAGS1_BIGENDIAN) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) |
2087 | if ( ( (startup_header.flags1 & STARTUP_HDR_FLAGS1_BIGENDIAN) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) |
1712 | || (!(startup_header.flags1 & STARTUP_HDR_FLAGS1_BIGENDIAN) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))) |
2088 | || (!(startup_header.flags1 & STARTUP_HDR_FLAGS1_BIGENDIAN) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))) |
1713 | is_foreign_endianness = true; // if the header is big endian and we're on a little endian machine, or the other way around, it's a foreign endianness |
2089 | is_foreign_endianness = true; // if the header is big endian and we're on a little endian machine, or the other way around, it's a foreign endianness |
1714 | else |
2090 | else |
1715 | is_foreign_endianness = false; // else this header is for the same endianness as us |
2091 | is_foreign_endianness = false; // else this header is for the same endianness as us |
1716 |
|
2092 | fseek (fp, startupheader_offset, SEEK_SET); |
1717 |
|
2093 | fread (blob_data, 1, blob_size + SHA512_DIGEST_LENGTH, fp); |
1718 | startup_trailer.cksum = update_checksum ( |
2094 | startup_trailer.cksum = update_checksum (blob_data, blob_size + SHA512_DIGEST_LENGTH, is_foreign_endianness); // compute old checksum |
1719 | free (blob_data); |
2095 | free (blob_data); |
1720 | 2096 | ||
1721 | // rewrite startup trailer with final values |
2097 | // rewrite startup trailer with final values |
1722 | fseek (fp, startuptrailer_offset, SEEK_SET); |
2098 | fseek (fp, startuptrailer_offset, SEEK_SET); |
1723 | fwrite (&startup_trailer, sizeof (startup_trailer), 1, fp); // write startup trailer |
2099 | fwrite (&startup_trailer, sizeof (startup_trailer), 1, fp); // write startup trailer |
1724 | } |
2100 | } |
1725 | 2101 | ||
1726 | // rewrite image header with final values |
2102 | // rewrite image header with final values |
1727 | fseek (fp, imgheader_offset, SEEK_SET); |
2103 | fseek (fp, imgheader_offset, SEEK_SET); |
1728 | image_header.image_size = (uint32_t) (final_size - imgheader_offset); // size of uncompressed imagefs |
2104 | image_header.image_size = (uint32_t) (final_size - imgheader_offset); // size of uncompressed imagefs |
- | 2105 | image_header.hdr_dir_size = sizeof (image_header) + (uint32_t) imgdir_size; // size from start of image header to last dirent |
|
1729 | fwrite (&image_header, sizeof (image_header), 1, fp); // write image header |
2106 | fwrite (&image_header, sizeof (image_header), 1, fp); // write image header |
1730 | 2107 | ||
1731 | // rewrite image directory with final |
2108 | // rewrite image directory with final offset values |
1732 | fseek (fp, imgdir_offset, SEEK_SET); |
2109 | fseek (fp, imgdir_offset, SEEK_SET); |
1733 | for (fsentry_index = 0; fsentry_index < fsentry_count; fsentry_index++) |
2110 | for (fsentry_index = 0; fsentry_index < fsentry_count; fsentry_index++) |
1734 | fwrite_fsentry (&fsentries[fsentry_index], fp); |
2111 | fwrite_fsentry (&fsentries[fsentry_index], fp); |
1735 | 2112 | ||
1736 | // compute SHA-512 checksum and V1 checksum of image block |
2113 | // compute SHA-512 checksum and V1 checksum of image block |
1737 |
|
2114 | blob_size = imgtrailer_offset - imgheader_offset; |
1738 | blob_data = malloc ( |
2115 | blob_data = malloc (blob_size + sizeof (image_trailer)); |
1739 | if (blob_data == NULL) |
2116 | if (blob_data == NULL) |
1740 | { |
2117 | { |
1741 | fprintf (stderr, "fatal error: out of memory\n"); |
2118 | fprintf (stderr, "fatal error: out of memory\n"); |
1742 | exit (1); |
2119 | exit (1); |
1743 | } |
2120 | } |
1744 | fseek (fp, imgheader_offset, SEEK_SET); |
2121 | fseek (fp, imgheader_offset, SEEK_SET); |
1745 | fread (blob_data, 1, |
2122 | fread (blob_data, 1, blob_size, fp); |
1746 | SHA512 (blob_data, |
2123 | SHA512 (blob_data, blob_size, image_trailer.sha512); // compute SHA512 checksum |
1747 | if ( ( (image_header.flags & IMAGE_FLAGS_BIGENDIAN) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) |
2124 | if ( ( (image_header.flags & IMAGE_FLAGS_BIGENDIAN) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) |
1748 | || (!(image_header.flags & IMAGE_FLAGS_BIGENDIAN) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))) |
2125 | || (!(image_header.flags & IMAGE_FLAGS_BIGENDIAN) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))) |
1749 | is_foreign_endianness = true; // if the header is big endian and we're on a little endian machine, or the other way around, it's a foreign endianness |
2126 | is_foreign_endianness = true; // if the header is big endian and we're on a little endian machine, or the other way around, it's a foreign endianness |
1750 | else |
2127 | else |
1751 | is_foreign_endianness = false; // else this header is for the same endianness as us |
2128 | is_foreign_endianness = false; // else this header is for the same endianness as us |
1752 |
|
2129 | fseek (fp, imgheader_offset, SEEK_SET); |
1753 |
|
2130 | fread (blob_data, 1, blob_size + SHA512_DIGEST_LENGTH, fp); |
1754 | image_trailer.cksum = update_checksum ( |
2131 | image_trailer.cksum = update_checksum (blob_data, blob_size, is_foreign_endianness); // compute old checksum |
1755 | free (blob_data); |
2132 | free (blob_data); |
1756 | 2133 | ||
1757 | // rewrite image trailer with final checksum values |
2134 | // rewrite image trailer with final checksum values |
1758 | fseek (fp, imgtrailer_offset, SEEK_SET); |
2135 | fseek (fp, imgtrailer_offset, SEEK_SET); |
1759 | fwrite (&image_trailer, sizeof (image_trailer), 1, fp); // write image trailer |
2136 | fwrite (&image_trailer, sizeof (image_trailer), 1, fp); // write image trailer |
Line 1765... | Line 2142... | ||
1765 | } |
2142 | } |
1766 | 2143 | ||
1767 | 2144 | ||
1768 | static int dump_ifs_info (const char *ifs_pathname) |
2145 | static int dump_ifs_info (const char *ifs_pathname) |
1769 | { |
2146 | { |
- | 2147 | #define hex_printf(buf,size,...) do { \ |
|
- | 2148 | if ((size) <= 16 * 1024) /* only print when it's not too big (up to 16 kb) */\ |
|
1770 |
|
2149 | hex_fprintf (stdout, (buf), (size), 16, __VA_ARGS__); /* use 16 columns in hex output to stdout */ \ |
- | 2150 | else { \ |
|
- | 2151 | printf (__VA_ARGS__); \ |
|
- | 2152 | printf (" size %zd > 16kb, not printed\n", (size_t) (size)); \ |
|
- | 2153 | } \ |
|
- | 2154 | } while (0) |
|
1771 | #define BINARY(x) binary ((x), '-', 'x') |
2155 | #define BINARY(x) binary ((x), '-', 'x') |
1772 | 2156 | ||
1773 | static const char *startupheader_flags1_strings[8] = { |
2157 | static const char *startupheader_flags1_strings[8] = { |
1774 | "VIRTUAL", // bit 0 |
2158 | "VIRTUAL", // bit 0 |
1775 | "BIGENDIAN", // bit 1 |
2159 | "BIGENDIAN", // bit 1 |
Line 1880... | Line 2264... | ||
1880 | hex_printf ((uint8_t *) &startup_header->info[0], sizeof (startup_header->info), " info[48] =\n"); |
2264 | hex_printf ((uint8_t *) &startup_header->info[0], sizeof (startup_header->info), " info[48] =\n"); |
1881 | 2265 | ||
1882 | // validate that the file can contain up to the startup trailer |
2266 | // validate that the file can contain up to the startup trailer |
1883 | if (current_offset + startup_header->startup_size > filesize) |
2267 | if (current_offset + startup_header->startup_size > filesize) |
1884 | { |
2268 | { |
1885 |
|
2269 | printf ("WARNING: this IFS file is corrupted (startup trailer extends past end of file)\n"); |
1886 |
|
2270 | goto endofdata; |
1887 | } |
2271 | } |
1888 | 2272 | ||
1889 | // check if this endianness is ours |
2273 | // check if this endianness is ours |
1890 | if ( ( (startup_header->flags1 & STARTUP_HDR_FLAGS1_BIGENDIAN) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) |
2274 | if ( ( (startup_header->flags1 & STARTUP_HDR_FLAGS1_BIGENDIAN) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) |
1891 | || (!(startup_header->flags1 & STARTUP_HDR_FLAGS1_BIGENDIAN) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))) |
2275 | || (!(startup_header->flags1 & STARTUP_HDR_FLAGS1_BIGENDIAN) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))) |
Line 1907... | Line 2291... | ||
1907 | 2291 | ||
1908 | current_offset += sizeof (startup_header_t); // jump over the startup header and reach the startup blob |
2292 | current_offset += sizeof (startup_header_t); // jump over the startup header and reach the startup blob |
1909 | printf ("\n"); |
2293 | printf ("\n"); |
1910 | printf ("Startup blob at offset 0x%zx (%zd):\n", current_offset, current_offset); |
2294 | printf ("Startup blob at offset 0x%zx (%zd):\n", current_offset, current_offset); |
1911 | printf (" size 0x%zx (%zd) bytes\n", startupfile_blobsize, startupfile_blobsize); |
2295 | printf (" size 0x%zx (%zd) bytes\n", startupfile_blobsize, startupfile_blobsize); |
1912 | printf (" checksum %d\n", update_checksum ( |
2296 | printf (" checksum %d\n", update_checksum (&filedata[current_offset], startupfile_blobsize, is_foreign_endianness)); |
1913 | 2297 | ||
1914 | current_offset += startupfile_blobsize; // jump over the startup blob and reach the startup trailer |
2298 | current_offset += startupfile_blobsize; // jump over the startup blob and reach the startup trailer |
1915 | printf ("\n"); |
2299 | printf ("\n"); |
1916 | 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)); |
2300 | 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)); |
1917 | if (startup_header->flags1 & STARTUP_HDR_FLAGS1_TRAILER_V2) |
2301 | if (startup_header->flags1 & STARTUP_HDR_FLAGS1_TRAILER_V2) |
1918 | { |
2302 | { |
1919 | for (byte_index = 0; byte_index < SHA512_DIGEST_LENGTH; byte_index++) |
2303 | for (byte_index = 0; byte_index < SHA512_DIGEST_LENGTH; byte_index++) |
1920 | sprintf (&recorded_sha512[2 * byte_index], "%02x", startup_trailer_v2->sha512[byte_index]); |
2304 | sprintf (&recorded_sha512[2 * byte_index], "%02x", startup_trailer_v2->sha512[byte_index]); |
1921 | strcpy (computed_sha512, SHA512 (startup_header, (size_t) ((uint8_t *) startup_trailer_v2 - (uint8_t *) startup_header), NULL)); |
2305 | strcpy (computed_sha512, SHA512 (startup_header, (size_t) ((uint8_t *) startup_trailer_v2 - (uint8_t *) startup_header), NULL)); |
1922 | recorded_checksum = startup_trailer_v2->cksum; |
2306 | recorded_checksum = startup_trailer_v2->cksum; |
1923 | computed_checksum = update_checksum ( |
2307 | computed_checksum = update_checksum (startup_header, sizeof (startup_header_t) + startupfile_blobsize + SHA512_DIGEST_LENGTH, is_foreign_endianness); |
1924 | printf (" sha512 = %s - %s\n", recorded_sha512, (strcasecmp (computed_sha512, recorded_sha512) == 0 ? "GOOD" : "BAD")); |
2308 | printf (" sha512 = %s - %s\n", recorded_sha512, (strcasecmp (computed_sha512, recorded_sha512) == 0 ? "GOOD" : "BAD")); |
1925 | printf (" cksum = 0x%08x (%d) - %s\n", recorded_checksum, recorded_checksum, (computed_checksum == recorded_checksum ? "GOOD" : "BAD")); |
2309 | printf (" cksum = 0x%08x (%d) - %s\n", recorded_checksum, recorded_checksum, (computed_checksum == recorded_checksum ? "GOOD" : "BAD")); |
1926 | if (strcasecmp (computed_sha512, recorded_sha512) != 0) |
2310 | if (strcasecmp (computed_sha512, recorded_sha512) != 0) |
1927 | printf ("Computed SHA-512: %s\n", computed_sha512); |
2311 | printf ("Computed SHA-512: %s\n", computed_sha512); |
1928 | if (computed_checksum != recorded_checksum) |
2312 | if (computed_checksum != recorded_checksum) |
1929 | printf ("Computed cksum: 0x%08x (%d)\n", computed_checksum, computed_checksum); |
2313 | printf ("Computed cksum: 0x%08x (%d)\n", computed_checksum, computed_checksum); |
1930 | } |
2314 | } |
1931 | else // old v1 trailer |
2315 | else // old v1 trailer |
1932 | { |
2316 | { |
1933 | recorded_checksum = startup_trailer_v1->cksum; |
2317 | recorded_checksum = startup_trailer_v1->cksum; |
1934 | computed_checksum = update_checksum ( |
2318 | computed_checksum = update_checksum (startup_header, sizeof (startup_header) + startupfile_blobsize, is_foreign_endianness); |
1935 | printf (" cksum = 0x%08x (%d) - %s\n", recorded_checksum, recorded_checksum, (computed_checksum == recorded_checksum ? "GOOD" : "BAD")); |
2319 | printf (" cksum = 0x%08x (%d) - %s\n", recorded_checksum, recorded_checksum, (computed_checksum == recorded_checksum ? "GOOD" : "BAD")); |
1936 | if (computed_checksum != recorded_checksum) |
2320 | if (computed_checksum != recorded_checksum) |
1937 | printf ("Computed cksum: 0x%08x (%d)\n", computed_checksum, computed_checksum); |
2321 | printf ("Computed cksum: 0x%08x (%d)\n", computed_checksum, computed_checksum); |
1938 | } |
2322 | } |
1939 | 2323 | ||
Line 1970... | Line 2354... | ||
1970 | printf (" mountpoint = \"%s\"\n", image_header->mountpoint); |
2354 | printf (" mountpoint = \"%s\"\n", image_header->mountpoint); |
1971 | 2355 | ||
1972 | // validate that the file can contain up to the image trailer |
2356 | // validate that the file can contain up to the image trailer |
1973 | if (current_offset + image_header->image_size > filesize) |
2357 | if (current_offset + image_header->image_size > filesize) |
1974 | { |
2358 | { |
1975 |
|
2359 | printf ("WARNING: this IFS file is corrupted (image trailer extends past end of file)\n"); |
1976 |
|
2360 | goto endofdata; |
1977 | } |
2361 | } |
1978 | 2362 | ||
1979 | // check if this endianness is ours |
2363 | // check if this endianness is ours |
1980 | if ( ( (image_header->flags & IMAGE_FLAGS_BIGENDIAN) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) |
2364 | if ( ( (image_header->flags & IMAGE_FLAGS_BIGENDIAN) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) |
1981 | || (!(image_header->flags & IMAGE_FLAGS_BIGENDIAN) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))) |
2365 | || (!(image_header->flags & IMAGE_FLAGS_BIGENDIAN) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))) |
Line 2023... | Line 2407... | ||
2023 | fsentries[fsentry_count] = current_fsentry; |
2407 | fsentries[fsentry_count] = current_fsentry; |
2024 | fsentry_count++; |
2408 | fsentry_count++; |
2025 | 2409 | ||
2026 | printf ("\n"); |
2410 | printf ("\n"); |
2027 | 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); |
2411 | 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); |
2028 | 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")); |
2412 | printf (" size = 0x%04x (%d) - size of dirent - %s\n", current_fsentry->header.size, current_fsentry->header.size, ((current_fsentry->header.size > 0) && (current_offset + current_fsentry->header.size < filesize) ? "looks good" : "BAD")); |
2029 | 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")); |
2413 | 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")); |
2030 | 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" : "")); |
2414 | 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" : "")); |
2031 | 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); |
2415 | 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); |
2032 | printf (" gid = 0x%08x (%d) - owner group ID%s\n", current_fsentry->header.gid, current_fsentry->header.gid, (current_fsentry->header.gid == 0 ? " (root)" : "")); |
2416 | printf (" gid = 0x%08x (%d) - owner group ID%s\n", current_fsentry->header.gid, current_fsentry->header.gid, (current_fsentry->header.gid == 0 ? " (root)" : "")); |
2033 | printf (" uid = 0x%08x (%d) - owner user ID%s\n", current_fsentry->header.uid, current_fsentry->header.uid, (current_fsentry->header.uid == 0 ? " (root)" : "")); |
2417 | printf (" uid = 0x%08x (%d) - owner user ID%s\n", current_fsentry->header.uid, current_fsentry->header.uid, (current_fsentry->header.uid == 0 ? " (root)" : "")); |
Line 2051... | Line 2435... | ||
2051 | else // can only be a device |
2435 | else // can only be a device |
2052 | { |
2436 | { |
2053 | printf (" [DEVICE] dev = 0x%08x (%d)\n", current_fsentry->u.device.dev, current_fsentry->u.device.dev); |
2437 | printf (" [DEVICE] dev = 0x%08x (%d)\n", current_fsentry->u.device.dev, current_fsentry->u.device.dev); |
2054 | printf (" [DEVICE] rdev = 0x%08x (%d)\n", current_fsentry->u.device.rdev, current_fsentry->u.device.rdev); |
2438 | printf (" [DEVICE] rdev = 0x%08x (%d)\n", current_fsentry->u.device.rdev, current_fsentry->u.device.rdev); |
2055 | printf (" [DEVICE] path = \"%s\"\n", (char *) ¤t_fsentry->u.device.path); // convert from pointer to char array |
2439 | printf (" [DEVICE] path = \"%s\"\n", (char *) ¤t_fsentry->u.device.path); // convert from pointer to char array |
- | 2440 | } |
|
- | 2441 | ||
- | 2442 | if ((current_fsentry->header.size == 0) || (current_offset + current_fsentry->header.size >= filesize)) |
|
- | 2443 | { |
|
- | 2444 | printf ("WARNING: this IFS file is corrupted (the size of this directory entry is invalid)\n"); |
|
- | 2445 | goto endofdata; |
|
2056 | } |
2446 | } |
2057 | 2447 | ||
2058 | current_offset += current_fsentry->header.size; |
2448 | current_offset += current_fsentry->header.size; |
2059 | } |
2449 | } |
2060 | if (imageheader_offset + image_header->hdr_dir_size < current_offset + sizeof (current_fsentry->header)) |
2450 | if (imageheader_offset + image_header->hdr_dir_size < current_offset + sizeof (current_fsentry->header)) |
Line 2091... | Line 2481... | ||
2091 | printf ("File data blob at offset 0x%zx (%zd):\n", current_offset, current_offset); |
2481 | printf ("File data blob at offset 0x%zx (%zd):\n", current_offset, current_offset); |
2092 | printf (" corresponding dirent index: %zd/%zd\n", fsentry_index, fsentry_count); |
2482 | printf (" corresponding dirent index: %zd/%zd\n", fsentry_index, fsentry_count); |
2093 | printf (" corresponding inode 0x%08x (%d) -%s%s%s%s\n", current_fsentry->header.ino, current_fsentry->header.ino, (current_fsentry->header.ino & 0xE0000000 ? "" : " 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" : "")); |
2483 | printf (" corresponding inode 0x%08x (%d) -%s%s%s%s\n", current_fsentry->header.ino, current_fsentry->header.ino, (current_fsentry->header.ino & 0xE0000000 ? "" : " 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" : "")); |
2094 | printf (" corresponding path: \"%s\"\n", (char *) ¤t_fsentry->u.file.path); // convert from pointer to char array |
2484 | printf (" corresponding path: \"%s\"\n", (char *) ¤t_fsentry->u.file.path); // convert from pointer to char array |
2095 | printf (" size 0x%zx (%zd) bytes\n", (size_t) current_fsentry->u.file.size, (size_t) current_fsentry->u.file.size); |
2485 | printf (" size 0x%zx (%zd) bytes\n", (size_t) current_fsentry->u.file.size, (size_t) current_fsentry->u.file.size); |
- | 2486 | if (current_offset + 4 < filesize) |
|
- | 2487 | { |
|
- | 2488 | if ((current_fsentry->u.file.size < 1024) && (current_offset + current_fsentry->u.file.size < filesize)) |
|
- | 2489 | hex_printf (&filedata[current_offset], current_fsentry->u.file.size, " data:\n"); |
|
- | 2490 | else |
|
2096 | printf (" first 4 bytes: %02x%02x%02x%02x \"%c%c%c%c\" (%s)\n", (uint8_t) filedata[current_offset + 0], (uint8_t) filedata[current_offset + 1], (uint8_t) filedata[current_offset + 2], (uint8_t) filedata[current_offset + 3], (isprint (filedata[current_offset + 0]) ? filedata[current_offset + 0] : '.'), (isprint (filedata[current_offset + 1]) ? filedata[current_offset + 1] : '.'), (isprint (filedata[current_offset + 2]) ? filedata[current_offset + 2] : '.'), (isprint (filedata[current_offset + 3]) ? filedata[current_offset + 3] : '.'), (memcmp (&filedata[current_offset], |
2491 | printf (" first 4 bytes: %02x%02x%02x%02x \"%c%c%c%c\" (%s)\n", (uint8_t) filedata[current_offset + 0], (uint8_t) filedata[current_offset + 1], (uint8_t) filedata[current_offset + 2], (uint8_t) filedata[current_offset + 3], (isprint (filedata[current_offset + 0]) ? filedata[current_offset + 0] : '.'), (isprint (filedata[current_offset + 1]) ? filedata[current_offset + 1] : '.'), (isprint (filedata[current_offset + 2]) ? filedata[current_offset + 2] : '.'), (isprint (filedata[current_offset + 3]) ? filedata[current_offset + 3] : '.'), (memcmp (&filedata[current_offset], ELF_MAGIC_STR, 4) == 0 ? "ELF binary" : (memcmp (&filedata[current_offset], "#!", 2) == 0 ? "shell script" : "data file"))); |
- | 2492 | } |
|
- | 2493 | if (current_offset + current_fsentry->u.file.size < filesize) |
|
2097 | printf (" checksum %d\n", update_checksum ( |
2494 | printf (" checksum %d\n", update_checksum (&filedata[current_offset], current_fsentry->u.file.size, is_foreign_endianness)); |
- | 2495 | else |
|
- | 2496 | { |
|
- | 2497 | printf ("WARNING: this IFS file is corrupted (the size of this file data extends past the IFS size)\n"); |
|
- | 2498 | goto endofdata; |
|
- | 2499 | } |
|
2098 | 2500 | ||
2099 | current_offset += current_fsentry->u.file.size; // now jump over this file's data |
2501 | current_offset += current_fsentry->u.file.size; // now jump over this file's data |
2100 | } |
2502 | } |
2101 | } |
2503 | } |
2102 | 2504 | ||
Line 2111... | Line 2513... | ||
2111 | { |
2513 | { |
2112 | for (byte_index = 0; byte_index < SHA512_DIGEST_LENGTH; byte_index++) |
2514 | for (byte_index = 0; byte_index < SHA512_DIGEST_LENGTH; byte_index++) |
2113 | sprintf (&recorded_sha512[2 * byte_index], "%02x", image_trailer_v2->sha512[byte_index]); |
2515 | sprintf (&recorded_sha512[2 * byte_index], "%02x", image_trailer_v2->sha512[byte_index]); |
2114 | strcpy (computed_sha512, SHA512 (image_header, (size_t) ((uint8_t *) image_trailer_v2 - (uint8_t *) image_header), NULL)); |
2516 | strcpy (computed_sha512, SHA512 (image_header, (size_t) ((uint8_t *) image_trailer_v2 - (uint8_t *) image_header), NULL)); |
2115 | recorded_checksum = image_trailer_v2->cksum; |
2517 | recorded_checksum = image_trailer_v2->cksum; |
2116 | computed_checksum = update_checksum ( |
2518 | computed_checksum = update_checksum (image_header, image_header->image_size - sizeof (image_trailer_v2_t) + SHA512_DIGEST_LENGTH, is_foreign_endianness); |
2117 | printf (" sha512 = %s - %s\n", recorded_sha512, (strcasecmp (computed_sha512, recorded_sha512) == 0 ? "GOOD" : "BAD")); |
2519 | printf (" sha512 = %s - %s\n", recorded_sha512, (strcasecmp (computed_sha512, recorded_sha512) == 0 ? "GOOD" : "BAD")); |
2118 | printf (" cksum = 0x%08x (%d) - %s\n", recorded_checksum, recorded_checksum, (computed_checksum == recorded_checksum ? "GOOD" : "BAD")); |
2520 | printf (" cksum = 0x%08x (%d) - %s\n", recorded_checksum, recorded_checksum, (computed_checksum == recorded_checksum ? "GOOD" : "BAD")); |
2119 | if (strcasecmp (computed_sha512, recorded_sha512) != 0) |
2521 | if (strcasecmp (computed_sha512, recorded_sha512) != 0) |
2120 | printf ("Computed SHA-512: %s\n", computed_sha512); |
2522 | printf ("Computed SHA-512: %s\n", computed_sha512); |
2121 | if (computed_checksum != recorded_checksum) |
2523 | if (computed_checksum != recorded_checksum) |
2122 | printf ("Computed cksum: 0x%08x (%d)\n", computed_checksum, computed_checksum); |
2524 | printf ("Computed cksum: 0x%08x (%d)\n", computed_checksum, computed_checksum); |
2123 | } |
2525 | } |
2124 | else // old v1 trailer |
2526 | else // old v1 trailer |
2125 | { |
2527 | { |
2126 | recorded_checksum = image_trailer_v1->cksum; |
2528 | recorded_checksum = image_trailer_v1->cksum; |
2127 | computed_checksum = update_checksum ( |
2529 | computed_checksum = update_checksum (image_header, image_header->image_size - sizeof (image_trailer_v1_t), is_foreign_endianness); |
2128 | printf (" cksum = 0x%08x (%d) - %s\n", recorded_checksum, recorded_checksum, (computed_checksum == recorded_checksum ? "GOOD" : "BAD")); |
2530 | printf (" cksum = 0x%08x (%d) - %s\n", recorded_checksum, recorded_checksum, (computed_checksum == recorded_checksum ? "GOOD" : "BAD")); |
2129 | if (computed_checksum != recorded_checksum) |
2531 | if (computed_checksum != recorded_checksum) |
2130 | printf ("Computed cksum: 0x%08x (%d)\n", computed_checksum, computed_checksum); |
2532 | printf ("Computed cksum: 0x%08x (%d)\n", computed_checksum, computed_checksum); |
2131 | } |
2533 | } |
2132 | 2534 | ||
Line 2145... | Line 2547... | ||
2145 | break; // if not found, stop scanning |
2547 | break; // if not found, stop scanning |
2146 | 2548 | ||
2147 | bootfile_blobsize = byte_index - current_offset; |
2549 | bootfile_blobsize = byte_index - current_offset; |
2148 | printf ("Boot blob at offset 0x%zx (%zd):\n", current_offset, current_offset); |
2550 | printf ("Boot blob at offset 0x%zx (%zd):\n", current_offset, current_offset); |
2149 | printf (" size 0x%zx (%zd) bytes\n", bootfile_blobsize, bootfile_blobsize); |
2551 | printf (" size 0x%zx (%zd) bytes\n", bootfile_blobsize, bootfile_blobsize); |
2150 | printf (" checksum 0x%08x\n", update_checksum ( |
2552 | printf (" checksum 0x%08x\n", update_checksum (&filedata[current_offset], bootfile_blobsize, false)); // NOTE: endianness is not known yet -- assume same |
2151 | 2553 | ||
2152 | current_offset = byte_index; // now reach the next segment |
2554 | current_offset = byte_index; // now reach the next segment |
2153 | } |
2555 | } |
2154 | } |
2556 | } |
2155 | 2557 | ||
- | 2558 | endofdata: |
|
2156 | // at this point there's nothing left we're able to parse |
2559 | // at this point there's nothing left we're able to parse |
2157 | if (current_offset < filesize) |
2560 | if (current_offset < filesize) |
2158 | { |
2561 | { |
2159 | printf ("End of identifiable data reached.\n"); |
2562 | printf ("End of identifiable data reached.\n"); |
2160 | if (filesize - current_offset < 16384) |
- | |
2161 |
|
2563 | hex_printf (&filedata[current_offset], filesize - current_offset, "\n" "%zd extra bytes at offset %zx (%zd):\n", filesize - current_offset, current_offset, current_offset); |
2162 | else |
- | |
2163 | printf ("\n" "%zd extra bytes at offset %zx (%zd) - size > 16k, not printed\n", filesize - current_offset, current_offset, current_offset); |
- | |
2164 | } |
2564 | } |
2165 | 2565 | ||
2166 | printf ("End of file reached at offset 0x%zx (%zd)\n", filesize, filesize); |
2566 | printf ("End of file reached at offset 0x%zx (%zd)\n", filesize, filesize); |
2167 | printf ("IFS dissecation complete.\n"); |
2567 | printf ("IFS dissecation complete.\n"); |
2168 | return (0); |
2568 | return (0); |