Subversion Repositories QNX 8.QNX8 IFS tool

Rev

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 *) ((void *) __DATE__)) == *((uint32_t *) ((void *) "Jan ")) ? "01" : \
44
#define BUILDDATE_MONTH (*((uint32_t *) __DATE__) == *((uint32_t *) "Jan ") ? "01" : \
47
                         (*((uint32_t *) ((void *) __DATE__)) == *((uint32_t *) ((void *) "Feb ")) ? "02" : \
45
                         (*((uint32_t *) __DATE__) == *((uint32_t *) "Feb ") ? "02" : \
48
                          (*((uint32_t *) ((void *) __DATE__)) == *((uint32_t *) ((void *) "Mar ")) ? "03" : \
46
                          (*((uint32_t *) __DATE__) == *((uint32_t *) "Mar ") ? "03" : \
49
                           (*((uint32_t *) ((void *) __DATE__)) == *((uint32_t *) ((void *) "Apr ")) ? "04" : \
47
                           (*((uint32_t *) __DATE__) == *((uint32_t *) "Apr ") ? "04" : \
50
                            (*((uint32_t *) ((void *) __DATE__)) == *((uint32_t *) ((void *) "May ")) ? "05" : \
48
                            (*((uint32_t *) __DATE__) == *((uint32_t *) "May ") ? "05" : \
51
                             (*((uint32_t *) ((void *) __DATE__)) == *((uint32_t *) ((void *) "Jun ")) ? "06" : \
49
                             (*((uint32_t *) __DATE__) == *((uint32_t *) "Jun ") ? "06" : \
52
                              (*((uint32_t *) ((void *) __DATE__)) == *((uint32_t *) ((void *) "Jul ")) ? "07" : \
50
                              (*((uint32_t *) __DATE__) == *((uint32_t *) "Jul ") ? "07" : \
53
                               (*((uint32_t *) ((void *) __DATE__)) == *((uint32_t *) ((void *) "Aug ")) ? "08" : \
51
                               (*((uint32_t *) __DATE__) == *((uint32_t *) "Aug ") ? "08" : \
54
                                (*((uint32_t *) ((void *) __DATE__)) == *((uint32_t *) ((void *) "Sep ")) ? "09" : \
52
                                (*((uint32_t *) __DATE__) == *((uint32_t *) "Sep ") ? "09" : \
55
                                 (*((uint32_t *) ((void *) __DATE__)) == *((uint32_t *) ((void *) "Oct ")) ? "10" : \
53
                                 (*((uint32_t *) __DATE__) == *((uint32_t *) "Oct ") ? "10" : \
56
                                  (*((uint32_t *) ((void *) __DATE__)) == *((uint32_t *) ((void *) "Nov ")) ? "11" : \
54
                                  (*((uint32_t *) __DATE__) == *((uint32_t *) "Nov ") ? "11" : \
57
                                   (*((uint32_t *) ((void *) __DATE__)) == *((uint32_t *) ((void *) "Dec ")) ? "12" : "XX")))))))))))) // compiler will optimize this into a const string, e.g. "11"
55
                                   (*((uint32_t *) __DATE__) == *((uint32_t *) "Dec ") ? "12" : "XX")))))))))))) // compiler will optimize this into a const string, e.g. "11"
58
#define BUILDDATE_DAY   (*((uint16_t *) ((void *) &__DATE__[4])) == *((uint16_t *) ((void *) " 1")) ? "01" : \
56
#define BUILDDATE_DAY   (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) "  1 ") ? "01" : \
59
                         (*((uint16_t *) ((void *) &__DATE__[4])) == *((uint16_t *) ((void *) " 2")) ? "02" : \
57
                         (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) "  2 ") ? "02" : \
60
                          (*((uint16_t *) ((void *) &__DATE__[4])) == *((uint16_t *) ((void *) " 3")) ? "03" : \
58
                          (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) "  3 ") ? "03" : \
61
                           (*((uint16_t *) ((void *) &__DATE__[4])) == *((uint16_t *) ((void *) " 4")) ? "04" : \
59
                           (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) "  4 ") ? "04" : \
62
                            (*((uint16_t *) ((void *) &__DATE__[4])) == *((uint16_t *) ((void *) " 5")) ? "05" : \
60
                            (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) "  5 ") ? "05" : \
63
                             (*((uint16_t *) ((void *) &__DATE__[4])) == *((uint16_t *) ((void *) " 6")) ? "06" : \
61
                             (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) "  6 ") ? "06" : \
64
                              (*((uint16_t *) ((void *) &__DATE__[4])) == *((uint16_t *) ((void *) " 7")) ? "07" : \
62
                              (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) "  7 ") ? "07" : \
65
                               (*((uint16_t *) ((void *) &__DATE__[4])) == *((uint16_t *) ((void *) " 8")) ? "08" : \
63
                               (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) "  8 ") ? "08" : \
66
                                (*((uint16_t *) ((void *) &__DATE__[4])) == *((uint16_t *) ((void *) " 9")) ? "09" : \
64
                                (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) "  9 ") ? "09" : \
67
                                 (*((uint16_t *) ((void *) &__DATE__[4])) == *((uint16_t *) ((void *) "10")) ? "10" : \
65
                                 (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 10 ") ? "10" : \
68
                                  (*((uint16_t *) ((void *) &__DATE__[4])) == *((uint16_t *) ((void *) "11")) ? "11" : \
66
                                  (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 11 ") ? "11" : \
69
                                   (*((uint16_t *) ((void *) &__DATE__[4])) == *((uint16_t *) ((void *) "12")) ? "12" : \
67
                                   (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 12 ") ? "12" : \
70
                                    (*((uint16_t *) ((void *) &__DATE__[4])) == *((uint16_t *) ((void *) "13")) ? "13" : \
68
                                    (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 13 ") ? "13" : \
71
                                     (*((uint16_t *) ((void *) &__DATE__[4])) == *((uint16_t *) ((void *) "14")) ? "14" : \
69
                                     (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 14 ") ? "14" : \
72
                                      (*((uint16_t *) ((void *) &__DATE__[4])) == *((uint16_t *) ((void *) "15")) ? "15" : \
70
                                      (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 15 ") ? "15" : \
73
                                       (*((uint16_t *) ((void *) &__DATE__[4])) == *((uint16_t *) ((void *) "16")) ? "16" : \
71
                                       (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 16 ") ? "16" : \
74
                                        (*((uint16_t *) ((void *) &__DATE__[4])) == *((uint16_t *) ((void *) "17")) ? "17" : \
72
                                        (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 17 ") ? "17" : \
75
                                         (*((uint16_t *) ((void *) &__DATE__[4])) == *((uint16_t *) ((void *) "18")) ? "18" : \
73
                                         (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 18 ") ? "18" : \
76
                                          (*((uint16_t *) ((void *) &__DATE__[4])) == *((uint16_t *) ((void *) "19")) ? "19" : \
74
                                          (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 19 ") ? "19" : \
77
                                           (*((uint16_t *) ((void *) &__DATE__[4])) == *((uint16_t *) ((void *) "20")) ? "20" : \
75
                                           (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 20 ") ? "20" : \
78
                                            (*((uint16_t *) ((void *) &__DATE__[4])) == *((uint16_t *) ((void *) "21")) ? "21" : \
76
                                            (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 21 ") ? "21" : \
79
                                             (*((uint16_t *) ((void *) &__DATE__[4])) == *((uint16_t *) ((void *) "22")) ? "22" : \
77
                                             (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 22 ") ? "22" : \
80
                                              (*((uint16_t *) ((void *) &__DATE__[4])) == *((uint16_t *) ((void *) "23")) ? "23" : \
78
                                              (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 23 ") ? "23" : \
81
                                               (*((uint16_t *) ((void *) &__DATE__[4])) == *((uint16_t *) ((void *) "24")) ? "24" : \
79
                                               (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 24 ") ? "24" : \
82
                                                (*((uint16_t *) ((void *) &__DATE__[4])) == *((uint16_t *) ((void *) "25")) ? "25" : \
80
                                                (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 25 ") ? "25" : \
83
                                                 (*((uint16_t *) ((void *) &__DATE__[4])) == *((uint16_t *) ((void *) "26")) ? "26" : \
81
                                                 (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 26 ") ? "26" : \
84
                                                  (*((uint16_t *) ((void *) &__DATE__[4])) == *((uint16_t *) ((void *) "27")) ? "27" : \
82
                                                  (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 27 ") ? "27" : \
85
                                                   (*((uint16_t *) ((void *) &__DATE__[4])) == *((uint16_t *) ((void *) "28")) ? "28" : \
83
                                                   (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 28 ") ? "28" : \
86
                                                    (*((uint16_t *) ((void *) &__DATE__[4])) == *((uint16_t *) ((void *) "29")) ? "29" : \
84
                                                    (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 29 ") ? "29" : \
87
                                                     (*((uint16_t *) ((void *) &__DATE__[4])) == *((uint16_t *) ((void *) "30")) ? "30" : \
85
                                                     (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 30 ") ? "30" : \
88
                                                      (*((uint16_t *) ((void *) &__DATE__[4])) == *((uint16_t *) ((void *) "31")) ? "31" : "XX"))))))))))))))))))))))))))))))) // compiler will optimize this into a const string, e.g. "14"
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.so\0" "/usr/lib/ldqnx-64.so.2\0" \
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 *precompiled_data;
533
   uint8_t *data;
387
   size_t precompiled_datalen;
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 (const int32_t start_value, 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
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, const char *stored_pathname, parms_t *entry_parms, const uint8_t *data, const size_t entry_datalen); // stack up a new filesystem entry
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 int fsentry_compare_sizes_cb (const void *a, const void *b); // qsort() comparison callback that sorts filesystem entries by size
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 (const int32_t start_value, const void *data, const size_t data_len, const bool is_foreign_endianness)
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
   int32_t image_cksum = start_value;
832
   const char *current_char_ptr;
677
   const char *current_char_ptr = data;
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 ((fp != NULL) && (count % image_align != 0))
1094
   if (count < fsentry->header.size)
-
 
1095
   {
-
 
1096
      if (fp != NULL)
871
      fwrite (zeropad_buffer, count % image_align, 1, fp); // pad as necessary
1097
         fwrite (zeropad_buffer, fsentry->header.size - count, 1, fp); // pad as necessary
872
   count = ROUND_TO_UPPER_MULTIPLE (count, image_align);
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, const char *stored_pathname, parms_t *entry_parms, const uint8_t *entry_data, const size_t entry_datalen)
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
   char processor_base[16];
1129
   void *old_data;
886
   struct stat stat_buf;
1130
   struct stat stat_buf;
887
   uint8_t *data_buffer = NULL;
1131
   size_t table_index;
888
   size_t data_len = 0;
1132
   size_t table_count;
889
   uint32_t mtime = (uint32_t) time (NULL);
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 ((entry_data != NULL) && (entry_datalen > 0)) // was an explicit contents blob supplied ?
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
            // HACK: for now just consider the kernel as a binary blob
1145
         // HACK: for now just consider the kernel as a binary blob
906
            // FIXME: reimplement properly
1146
         // FIXME: reimplement properly
907
            data_len = entry_datalen;
1147
         sprintf (candidate_pathname, "%s/procnto-smp-instr", entry_parms->prefix); // fix the entry name
908
            data_buffer = malloc (data_len);
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
            if (data_buffer == NULL)
1150
         image_kernel_ino = extra_ino_flags | (inode_count + 1);
910
            {
1151
      }
911
               fprintf (stderr, "fatal error: out of memory\n");
1152
      else if (entry_parms->is_compiled_bootscript) // else is it a startup script ?
912
               exit (1);
-
 
913
            }
-
 
914
            memcpy (data_buffer, entry_data, data_len);
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
         // should we substitute precompiled data to this data blob ?
1155
      // do we already know the data for this data blob ?
925
         if ((entry_parms->precompiled_data != NULL) && (entry_parms->precompiled_datalen > 0))
1156
      if (entry_parms->data != NULL)
926
         {
1157
      {
927
            data_len = entry_parms->precompiled_datalen;
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
            memcpy (data_buffer, entry_parms->precompiled_data, data_len);
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 ((entry_data != NULL) && (entry_data[0] != 0)) // else entry_datalen == 0, was some sort of pathname supplied ?
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
             || (isalpha (entry_data[0])
1179
         resolved_pathname = read_filecontents (buildhost_pathname, (entry_parms->search[0] != 0 ? entry_parms->search : MKIFS_PATH), &entry_parms->data, &entry_parms->datalen);
970
                 && (entry_data[1] == ':')
1180
         if (resolved_pathname == NULL)
971
                 && IS_DIRSEP (entry_data[2])))
-
 
972
         {
1181
         {
973
            // in this case, it MUST exist at its designated location (either absolute or relative to the current working directory)
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
            strcpy (candidate_pathname, entry_data);
1183
            fprintf (stderr, "             v\n");
975
            if (stat (candidate_pathname, &stat_buf) != 0)
1184
            fprintf (stderr, "%s", current_line);
976
            {
-
 
977
               fprintf (stderr, "fatal error: filesystem entry \"%s\" specified in \"%s\" line %d not found on build host\n", entry_data, buildfile_pathname, lineno);
1185
            fprintf (stderr, "             ^\n");
978
               exit (1);
1186
            exit (1);
979
            }
-
 
980
         }
1187
         }
981
         else // the path is relative, search it among the search paths we have
-
 
982
         {
-
 
983
            // is the search path NOT defined ?
1188
         stat (resolved_pathname, &stat_buf); // can't fail
984
            if (entry_parms->search[0] == 0)
1189
         if (entry_parms->mtime == UINT32_MAX)
985
            {
-
 
986
               // initialize the default search path in MKIFS_PATH
1190
            entry_parms->mtime = (uint32_t) stat_buf.st_mtime;
987
               if (MKIFS_PATH == NULL)
-
 
988
               {
-
 
989
                  MKIFS_PATH = getenv ("MKIFS_PATH"); // look in the environment first, and construct a default one if not supplied
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
                     if (token != NULL)
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
                     sprintf (MKIFS_PATH, ".|%s/%s/sbin|%s/%s/usr/sbin|%s/%s/boot/sys|%s/%s/boot/sys|%s/%s/bin|%s/%s/usr/bin|%s/%s/lib|%s/%s/lib/dll|%s/%s/usr/lib", // use a platform-agnostic character as path separator
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
                                          QNX_TARGET, image_processor,
1195
      if ((entry_parms->datalen > 52) // file is big enough to contain an ELF header
1010
                                          QNX_TARGET, processor_base,
1196
          && ((elf = (elf_header_t *) entry_parms->data) != NULL) // cast (necessary true)
1011
                                          QNX_TARGET, image_processor,
-
 
1012
                                          QNX_TARGET, image_processor,
1197
          && (memcmp (ELF_HDR_MEMBER (elf, magic), ELF_MAGIC_STR, 4) == 0) // file starts with the ELF magic
1013
                                          QNX_TARGET, image_processor,
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
                                          QNX_TARGET, image_processor,
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
                                          QNX_TARGET, image_processor);
1200
          && entry_parms->should_autosymlink_dylib) // we should store it under its official .so name
1016
                  }
1201
      {
1017
               } // at this point MKIFS_PATH is defined
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
            // convert path separators in the MKIFS_PATH environment variable into something platform-agnostic
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
            for (token = entry_parms->search; *token != 0; token++)
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
               if (*token == PATH_SEP)
1217
               shdr_dynamic = shdr;
-
 
1218
            else if (strcmp (elf_section_name, ".dynstr") == 0)
1025
                  *token = '|';
1219
               shdr_dynstr = shdr;
-
 
1220
         }
1026
 
1221
 
1027
            token = strtok (entry_parms->search, "|");
1222
         // make sure we have both the dynamic section header and its own strings table header
1028
            while (token != NULL)
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
               sprintf (candidate_pathname, "%s/%s", token, entry_data);
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 (stat (candidate_pathname, &stat_buf) == 0)
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
            if (token == NULL)
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
               fprintf (stderr, "fatal error: filesystem entry \"%s\" specified in \"%s\" line %d not found on build host\n", entry_data, buildfile_pathname, lineno);
1241
               if (strcmp (candidate_pathname, stored_pathname) != 0) // claimed dylib name differs from passed name ?
1038
               exit (1);
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, data_buffer);
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 (entry_data, ':') == NULL)
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, entry_data);
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
   // reallocate filesystem entries array to hold one more slot
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) + ROUND_TO_UPPER_MULTIPLE (strlen (fsentry->u.dir.path) + 1, image_align)); // now we can set the size
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) data_len;
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.path = strdup (stored_pathname);
1289
      fsentry->u.file.UNSAVED_databuf = malloc (entry_parms->datalen);
1110
      fsentry->u.file.UNSAVED_databuf = data_buffer;
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) + ROUND_TO_UPPER_MULTIPLE (strlen (fsentry->u.file.path) + 1, image_align)); // now we can set the size
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) data_len;
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.path = strdup (stored_pathname);
1304
      fsentry->u.symlink.contents = strdup (entry_parms->data);
1119
      fsentry->u.symlink.contents = data_buffer;
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) + ROUND_TO_UPPER_MULTIPLE ((size_t) fsentry->u.symlink.sym_offset + fsentry->u.symlink.sym_size + 1, image_align)); // now we can set the size
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 (entry_data, NULL, 0); // use strtol() to parse decimal (...), hexadecimal (0x...) and octal (0...) numbers
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 (entry_data, ':') + 1, NULL, 0); // use strtol() to parse decimal (...), hexadecimal (0x...) and octal (0...) numbers
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) + ROUND_TO_UPPER_MULTIPLE (strlen (fsentry->u.device.path), image_align)); // now we can set the size
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 int fsentry_compare_sizes_cb (const void *a, const void *b)
1354
static void update_MKIFS_PATH (const char *processor)
1149
{
1355
{
1150
   // qsort() callback that compares two imagefs filesystem entries and sort them by increasing data size
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
   const fsentry_t *entry_a = (const fsentry_t *) a;
1372
      token = strchr (processor_base, '-');
-
 
1373
      if (token != NULL)
-
 
1374
         *token = 0; // split anything from the first dash onwards
1153
   const fsentry_t *entry_b = (const fsentry_t *) b;
1375
      data_len = strlen (processor_base);
1154
   const int32_t size_a = (S_ISREG (entry_a->header.mode) ? entry_a->u.file.size : 0); // only files (i.e. entries wearing the S_IFREG flag) have a separate data block
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
   const int32_t size_b = (S_ISREG (entry_b->header.mode) ? entry_b->u.file.size : 0); // only files (i.e. entries wearing the S_IFREG flag) have a separate data block
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
   return ((int) size_b - (int) size_a);
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 = { 0755, 0644, 0, 0, S_IFREG, "/proc/boot", false, "", NULL, 0 }; // default parameters for a filesystem entry
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 *line_ptr;
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, "", &entry_parms, NULL, 0); // add the root dir first
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.precompiled_data = malloc (stat_buf.st_size);
1673
               entry_parms.data = malloc (stat_buf.st_size);
1390
               if (entry_parms.precompiled_data == NULL)
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.precompiled_data, 1, stat_buf.st_size, fp);
1680
               fread (entry_parms.data, 1, stat_buf.st_size, fp);
1397
               fclose (fp);
1681
               fclose (fp);
1398
               entry_parms.precompiled_datalen = stat_buf.st_size;
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.precompiled_data = INITIAL_STARTUP_SCRIPT; // HACK until the script compiler is implemented
1704
               memcpy (entry_parms.data, INITIAL_STARTUP_SCRIPT, sizeof (INITIAL_STARTUP_SCRIPT) - 1); // FIXME: HACK until the script compiler is implemented
1403
               entry_parms.precompiled_datalen = sizeof (INITIAL_STARTUP_SCRIPT) - 1;
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 (blob_datalen == blob_datasize) // reallocate in 4 kb blocks
1819
                  if (entry_parms.data == NULL) // only store the contents if we do NOT know the data yet
1506
                  {
1820
                  {
1507
                     reallocated_ptr = realloc (blob_data, blob_datasize + 4096);
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
                     blob_data = reallocated_ptr;
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 }, meaning it's a build host filesystem path
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
            blob_data = line_ptr; // explicit pathname on build host
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
            blob_datalen = 0;
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
         blob_data = &path_in_ifs[strlen (entry_parms.prefix) + 1]; // same pathname
1884
         strcpy (path_on_buildhost, specifiedpathname_start); // the path on the build host is the one specified
-
 
1885
         sep = strrchr (specifiedpathname_start, '/');
1538
         blob_datalen = 0;
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
      entry_parms.st_mode |= (S_ISDIR (entry_parms.st_mode) ? entry_parms.dperms : entry_parms.perms); // complete entry permissions
1892
         entry_parms.st_mode |= entry_parms.dperms;
-
 
1893
      else if (S_ISLNK (entry_parms.st_mode))
1543
      add_fsentry (&fsentries, &fsentry_count, path_in_ifs, &entry_parms, blob_data, blob_datalen); // and add filesystem entry
1894
         entry_parms.st_mode |= 0777; // NOTE: mkifs sets symlink permissions to rwxrwxrwx !?
1544
      if (blob_datasize > 0)
1895
      else // file or device node
1545
         free (blob_data); // if blob data was allocated, free it
1896
         entry_parms.st_mode |= entry_parms.perms;
1546
   }
-
 
1547
 
1897
 
1548
   // sort the filesystem entries by pathname
-
 
1549
   qsort (&fsentries[1], fsentry_count - 1, sizeof (fsentry_t), fsentry_compare_pathnames_cb);
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
      fprintf (stderr, "info: sorted entry: %s\n", (S_ISDIR (fsentries[fsentry_index].header.mode) ? fsentries[fsentry_index].u.dir.path : (S_ISREG (fsentries[fsentry_index].header.mode) ? fsentries[fsentry_index].u.file.path : (S_ISLNK (fsentries[fsentry_index].header.mode) ? fsentries[fsentry_index].u.symlink.path : fsentries[fsentry_index].u.device.path))));
1900
      if (entry_parms.data != NULL)
1556
      imgdir_size += fwrite_fsentry (&fsentries[fsentry_index], NULL);
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, "wb");
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  = (uint32_t) imgdir_size; // size from header to last dirent (here 0x12b8 or 4792)
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
   PAD_OUTFILE_TO (ROUND_TO_UPPER_MULTIPLE (ftell (fp), image_align)); // pad as necessary
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
      // sort the filesystem entries by sizes
1982
      // start by writing the startup script data blob, if we have one
1636
      qsort (fsentries, fsentry_count, sizeof (fsentry_t), fsentry_compare_sizes_cb);
1983
      for (fsentry_index = 1; fsentry_index < fsentry_count; fsentry_index++)
1637
 
-
 
1638
      // write as many small files as we can before reaching the kernel offset 
1984
         if (fsentries[fsentry_index].header.ino == image_bootscript_ino)
-
 
1985
            break; // locate it
1639
      for (fsentry_index = 0; fsentry_index < fsentry_count; fsentry_index++)
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
            break; // stop writing entries as soon as we reach the kernel file offset
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 (ROUND_TO_UPPER_MULTIPLE (ftell (fp), image_align)); // pad as necessary
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 = 0; fsentry_index < fsentry_count; 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
      PAD_OUTFILE_TO (ROUND_TO_UPPER_MULTIPLE (ftell (fp), image_align)); // pad as necessary
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
      blob_datasize = startuptrailer_offset - startupheader_offset;
2077
      blob_size = startuptrailer_offset - startupheader_offset;
1702
      blob_data = malloc (blob_datasize);
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, blob_datasize, fp);
2085
      fread (blob_data, 1, blob_size, fp);
1710
      SHA512 (blob_data, blob_datasize, startup_trailer.sha512); // compute SHA512 checksum
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
      startup_trailer.cksum = 0; // compute old checksum
2092
      fseek (fp, startupheader_offset, SEEK_SET);
1717
      startup_trailer.cksum = update_checksum (startup_trailer.cksum, (const uint32_t *) blob_data, blob_datasize, is_foreign_endianness);
2093
      fread (blob_data, 1, blob_size + SHA512_DIGEST_LENGTH, fp);
1718
      startup_trailer.cksum = update_checksum (startup_trailer.cksum, (const uint32_t *) startup_trailer.sha512, sizeof (startup_trailer.sha512), is_foreign_endianness);
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 checksum values
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
   blob_datasize = imgtrailer_offset - imgheader_offset;
2114
   blob_size = imgtrailer_offset - imgheader_offset;
1738
   blob_data = malloc (blob_datasize);
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, blob_datasize, fp);
2122
   fread (blob_data, 1, blob_size, fp);
1746
   SHA512 (blob_data, blob_datasize, image_trailer.sha512); // compute SHA512 checksum
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
   image_trailer.cksum = 0; // compute old checksum
2129
   fseek (fp, imgheader_offset, SEEK_SET);
1753
   image_trailer.cksum = update_checksum (image_trailer.cksum, (const uint32_t *) blob_data, blob_datasize, is_foreign_endianness);
2130
   fread (blob_data, 1, blob_size + SHA512_DIGEST_LENGTH, fp);
1754
   image_trailer.cksum = update_checksum (image_trailer.cksum, (const uint32_t *) image_trailer.sha512, sizeof (image_trailer.sha512), is_foreign_endianness);
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
   #define hex_printf(buf,size,...) hex_fprintf (stdout, (buf), (size), 16, __VA_ARGS__) // use 16 columns in hex output to stdout
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
            fprintf (stderr, "WARNING: this IFS file is too short (startup trailer would be past end of file)\n");
2269
            printf ("WARNING: this IFS file is corrupted (startup trailer extends past end of file)\n");
1886
            break;
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 (0, &filedata[current_offset], startupfile_blobsize, is_foreign_endianness));
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 (0, startup_header, sizeof (startup_header_t) + startupfile_blobsize + SHA512_DIGEST_LENGTH, is_foreign_endianness);
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 (0, startup_header, sizeof (startup_header) + startupfile_blobsize, is_foreign_endianness);
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
            fprintf (stderr, "WARNING: this IFS file is too short (image trailer would be past end of file)\n");
2359
            printf ("WARNING: this IFS file is corrupted (image trailer extends past end of file)\n");
1976
            break;
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 *) &current_fsentry->u.device.path); // convert from pointer to char array
2439
               printf ("   [DEVICE] path = \"%s\"\n", (char *) &current_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 *) &current_fsentry->u.file.path); // convert from pointer to char array
2484
               printf ("   corresponding path: \"%s\"\n", (char *) &current_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], "\x7f" "ELF", 4) == 0 ? "ELF binary" : (memcmp (&filedata[current_offset], "#!", 2) == 0 ? "shell script" : "data file")));
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 (0, &filedata[current_offset], current_fsentry->u.file.size, is_foreign_endianness));
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 (0, image_header, image_header->image_size - sizeof (image_trailer_v2_t) + SHA512_DIGEST_LENGTH, is_foreign_endianness);
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 (0, image_header, image_header->image_size - sizeof (image_trailer_v1_t), is_foreign_endianness);
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 (0, &filedata[current_offset], bootfile_blobsize, false)); // NOTE: endianness is not known yet -- assume same
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
         hex_printf (&filedata[current_offset], filesize - current_offset, "\n" "%zd extra bytes at offset %zx (%zd):\n", filesize - current_offset, current_offset, current_offset);
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);