Subversion Repositories QNX 8.QNX8 IFS tool

Rev

Rev 15 | Rev 17 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 15 Rev 16
Line 3... Line 3...
3
// TODO: preboot file stripping
3
// TODO: preboot file stripping
4
// TODO: startup file stripping
4
// TODO: startup file stripping
5
// TODO: kernel file stripping
5
// TODO: kernel file stripping
6
// TODO: boot script compiler
6
// TODO: boot script compiler
7
 
7
 
-
 
8
// standard C includes
8
#include <stdint.h>
9
#include <stdint.h>
9
#include <stdbool.h>
10
#include <stdbool.h>
10
#include <stdlib.h>
11
#include <stdlib.h>
11
#include <stdarg.h>
12
#include <stdarg.h>
12
#include <stdio.h>
13
#include <stdio.h>
13
#include <string.h>
14
#include <string.h>
-
 
15
#include <limits.h>
14
#include <errno.h>
16
#include <errno.h>
15
#include <sys/stat.h>
17
#include <sys/stat.h>
16
#include <ctype.h>
18
#include <ctype.h>
17
#include <time.h>
19
#include <time.h>
18
 
20
 
19
 
-
 
20
// compiler-specific glue
21
// platform-specific includes
21
#ifdef _MSC_VER
22
#ifdef _MSC_VER
22
#include <io.h>
23
#include <io.h>
23
#include <direct.h>
24
#include <direct.h>
24
#include <sys/utime.h>
25
#include <sys/utime.h>
25
#include <process.h>
-
 
26
#define __x86_64__ 1
-
 
27
#define __ORDER_BIG_ENDIAN__    4321
-
 
28
#define __ORDER_LITTLE_ENDIAN__ 1234
-
 
29
#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
-
 
30
#define __attribute__(x)
-
 
31
#define __builtin_bswap16(x) _byteswap_ushort ((unsigned short) (x))
-
 
32
#define __builtin_bswap32(x) _byteswap_ulong ((unsigned long) (x))
-
 
33
#define __builtin_bswap64(x) _byteswap_uint64 ((unsigned long long) (x))
-
 
34
#define S_IFIFO 0x1000
-
 
35
#define S_IFLNK 0xa000
-
 
36
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
-
 
37
#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
-
 
38
#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
-
 
39
#define strdup(s) _strdup ((s))
-
 
40
#define strcasecmp(s1,s2) _stricmp ((s1), (s2))
-
 
41
#define fseek(fp,off,m) _fseeki64 ((fp), (off), (m))
-
 
42
#define access(p,m) _access ((p), (m))
-
 
43
#define mkdir(p,m) _mkdir ((p))
-
 
44
#define chmod(p,m) _chmod ((p), (m))
-
 
45
#define unlink(p) _unlink ((p))
-
 
46
#define utimbuf __utimbuf32
-
 
47
#define utime(p,t) _utime32 ((p), (t))
-
 
48
#define MAXPATHLEN 1024
-
 
49
#ifndef thread_local
-
 
50
#define thread_local __declspec(thread) // the thread_local keyword wasn't defined before C++11 and C23
-
 
51
#endif // !thread_local
-
 
52
#define START_OF_PACKED_STRUCT() __pragma(pack(push)) __pragma(pack(1))
-
 
53
#define END_OF_PACKED_STRUCT() __pragma(pack(pop))
-
 
54
#define PACKED(thing) thing
-
 
55
#else // !_MSC_VER
26
#else // !_MSC_VER
56
#include <sys/param.h>
27
#include <sys/param.h>
57
#include <unistd.h>
28
#include <unistd.h>
58
#include <utime.h>
29
#include <utime.h>
59
#ifndef thread_local
-
 
60
#define thread_local __thread // the thread_local keyword wasn't defined before C++11 and C23
-
 
61
#endif // !thread_local
-
 
62
#define START_OF_PACKED_STRUCT()
-
 
63
#define END_OF_PACKED_STRUCT()
-
 
64
#define PACKED(thing) thing __attribute__((packed))
-
 
65
#endif // _MSC_VER
30
#endif // _MSC_VER
66
 
31
 
-
 
32
// own includes
-
 
33
#include "buffer.h"
-
 
34
#include "sha512.h"
-
 
35
#include "elffile.h"
-
 
36
#include "ifsfile.h"
-
 
37
#include "utility.h"
67
 
38
 
68
// 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);
-
 
69
#ifndef VERSION_ARG_YYYYMMDD
-
 
70
#define BUILDDATE_YEAR  (&__DATE__[7]) // compiler will optimize this into a const string, e.g. "2021"
-
 
71
#define BUILDDATE_MONTH ( \
-
 
72
   *((uint32_t *) __DATE__) == *((uint32_t *) "Jan ") ? "01" : \
-
 
73
   *((uint32_t *) __DATE__) == *((uint32_t *) "Feb ") ? "02" : \
-
 
74
   *((uint32_t *) __DATE__) == *((uint32_t *) "Mar ") ? "03" : \
-
 
75
   *((uint32_t *) __DATE__) == *((uint32_t *) "Apr ") ? "04" : \
-
 
76
   *((uint32_t *) __DATE__) == *((uint32_t *) "May ") ? "05" : \
-
 
77
   *((uint32_t *) __DATE__) == *((uint32_t *) "Jun ") ? "06" : \
-
 
78
   *((uint32_t *) __DATE__) == *((uint32_t *) "Jul ") ? "07" : \
-
 
79
   *((uint32_t *) __DATE__) == *((uint32_t *) "Aug ") ? "08" : \
-
 
80
   *((uint32_t *) __DATE__) == *((uint32_t *) "Sep ") ? "09" : \
-
 
81
   *((uint32_t *) __DATE__) == *((uint32_t *) "Oct ") ? "10" : \
-
 
82
   *((uint32_t *) __DATE__) == *((uint32_t *) "Nov ") ? "11" : \
-
 
83
   *((uint32_t *) __DATE__) == *((uint32_t *) "Dec ") ? "12" : \
-
 
84
   "XX" \
-
 
85
) // compiler will optimize this into a const string, e.g. "11"
-
 
86
#define BUILDDATE_DAY ( \
-
 
87
   *((uint32_t *) &__DATE__[3]) == *((uint32_t *) "  1 ") ? "01" : \
-
 
88
   *((uint32_t *) &__DATE__[3]) == *((uint32_t *) "  2 ") ? "02" : \
-
 
89
   *((uint32_t *) &__DATE__[3]) == *((uint32_t *) "  3 ") ? "03" : \
-
 
90
   *((uint32_t *) &__DATE__[3]) == *((uint32_t *) "  4 ") ? "04" : \
-
 
91
   *((uint32_t *) &__DATE__[3]) == *((uint32_t *) "  5 ") ? "05" : \
-
 
92
   *((uint32_t *) &__DATE__[3]) == *((uint32_t *) "  6 ") ? "06" : \
-
 
93
   *((uint32_t *) &__DATE__[3]) == *((uint32_t *) "  7 ") ? "07" : \
-
 
94
   *((uint32_t *) &__DATE__[3]) == *((uint32_t *) "  8 ") ? "08" : \
-
 
95
   *((uint32_t *) &__DATE__[3]) == *((uint32_t *) "  9 ") ? "09" : \
-
 
96
   *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 10 ") ? "10" : \
-
 
97
   *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 11 ") ? "11" : \
-
 
98
   *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 12 ") ? "12" : \
-
 
99
   *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 13 ") ? "13" : \
-
 
100
   *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 14 ") ? "14" : \
-
 
101
   *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 15 ") ? "15" : \
-
 
102
   *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 16 ") ? "16" : \
-
 
103
   *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 17 ") ? "17" : \
-
 
104
   *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 18 ") ? "18" : \
-
 
105
   *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 19 ") ? "19" : \
-
 
106
   *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 20 ") ? "20" : \
-
 
107
   *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 21 ") ? "21" : \
-
 
108
   *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 22 ") ? "22" : \
-
 
109
   *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 23 ") ? "23" : \
-
 
110
   *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 24 ") ? "24" : \
-
 
111
   *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 25 ") ? "25" : \
-
 
112
   *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 26 ") ? "26" : \
-
 
113
   *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 27 ") ? "27" : \
-
 
114
   *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 28 ") ? "28" : \
-
 
115
   *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 29 ") ? "29" : \
-
 
116
   *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 30 ") ? "30" : \
-
 
117
   *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 31 ") ? "31" : \
-
 
118
   "XX" \
-
 
119
) // compiler will optimize this into a const string, e.g. "14"
-
 
120
#define VERSION_FMT_YYYYMMDD "%s%s%s"
-
 
121
#define VERSION_ARG_YYYYMMDD BUILDDATE_YEAR, BUILDDATE_MONTH, BUILDDATE_DAY
-
 
122
#endif // !VERSION_ARG_YYYYMMDD
-
 
123
 
39
 
124
 
-
 
125
// macro to bring __FILE_NAME__ support to moronic compilers
-
 
126
#ifndef __FILE_NAME__ // Clang 9+ has the macro, GCC 12+ added it too in 2021, MSVC obviously won't do it. Heh.
-
 
127
#define __FILE_NAME__ ( \
-
 
128
   (sizeof (__FILE__) >  2) && ((__FILE__[sizeof (__FILE__) -  2] == '/') || (__FILE__[sizeof (__FILE__) -  2] == '\\')) ? &__FILE__[sizeof (__FILE__) -  1] : \
-
 
129
   (sizeof (__FILE__) >  3) && ((__FILE__[sizeof (__FILE__) -  3] == '/') || (__FILE__[sizeof (__FILE__) -  3] == '\\')) ? &__FILE__[sizeof (__FILE__) -  2] : \
-
 
130
   (sizeof (__FILE__) >  4) && ((__FILE__[sizeof (__FILE__) -  4] == '/') || (__FILE__[sizeof (__FILE__) -  4] == '\\')) ? &__FILE__[sizeof (__FILE__) -  3] : \
-
 
131
   (sizeof (__FILE__) >  5) && ((__FILE__[sizeof (__FILE__) -  5] == '/') || (__FILE__[sizeof (__FILE__) -  5] == '\\')) ? &__FILE__[sizeof (__FILE__) -  4] : \
-
 
132
   (sizeof (__FILE__) >  6) && ((__FILE__[sizeof (__FILE__) -  6] == '/') || (__FILE__[sizeof (__FILE__) -  6] == '\\')) ? &__FILE__[sizeof (__FILE__) -  5] : \
-
 
133
   (sizeof (__FILE__) >  7) && ((__FILE__[sizeof (__FILE__) -  7] == '/') || (__FILE__[sizeof (__FILE__) -  7] == '\\')) ? &__FILE__[sizeof (__FILE__) -  6] : \
-
 
134
   (sizeof (__FILE__) >  8) && ((__FILE__[sizeof (__FILE__) -  8] == '/') || (__FILE__[sizeof (__FILE__) -  8] == '\\')) ? &__FILE__[sizeof (__FILE__) -  7] : \
-
 
135
   (sizeof (__FILE__) >  9) && ((__FILE__[sizeof (__FILE__) -  9] == '/') || (__FILE__[sizeof (__FILE__) -  9] == '\\')) ? &__FILE__[sizeof (__FILE__) -  8] : \
-
 
136
   (sizeof (__FILE__) > 10) && ((__FILE__[sizeof (__FILE__) - 10] == '/') || (__FILE__[sizeof (__FILE__) - 10] == '\\')) ? &__FILE__[sizeof (__FILE__) -  9] : \
-
 
137
   (sizeof (__FILE__) > 11) && ((__FILE__[sizeof (__FILE__) - 11] == '/') || (__FILE__[sizeof (__FILE__) - 11] == '\\')) ? &__FILE__[sizeof (__FILE__) - 10] : \
-
 
138
   (sizeof (__FILE__) > 12) && ((__FILE__[sizeof (__FILE__) - 12] == '/') || (__FILE__[sizeof (__FILE__) - 12] == '\\')) ? &__FILE__[sizeof (__FILE__) - 11] : \
-
 
139
   (sizeof (__FILE__) > 13) && ((__FILE__[sizeof (__FILE__) - 13] == '/') || (__FILE__[sizeof (__FILE__) - 13] == '\\')) ? &__FILE__[sizeof (__FILE__) - 12] : \
-
 
140
   (sizeof (__FILE__) > 14) && ((__FILE__[sizeof (__FILE__) - 14] == '/') || (__FILE__[sizeof (__FILE__) - 14] == '\\')) ? &__FILE__[sizeof (__FILE__) - 13] : \
-
 
141
   (sizeof (__FILE__) > 15) && ((__FILE__[sizeof (__FILE__) - 15] == '/') || (__FILE__[sizeof (__FILE__) - 15] == '\\')) ? &__FILE__[sizeof (__FILE__) - 14] : \
-
 
142
   (sizeof (__FILE__) > 16) && ((__FILE__[sizeof (__FILE__) - 16] == '/') || (__FILE__[sizeof (__FILE__) - 16] == '\\')) ? &__FILE__[sizeof (__FILE__) - 15] : \
-
 
143
   (sizeof (__FILE__) > 17) && ((__FILE__[sizeof (__FILE__) - 17] == '/') || (__FILE__[sizeof (__FILE__) - 17] == '\\')) ? &__FILE__[sizeof (__FILE__) - 16] : \
-
 
144
   (sizeof (__FILE__) > 18) && ((__FILE__[sizeof (__FILE__) - 18] == '/') || (__FILE__[sizeof (__FILE__) - 18] == '\\')) ? &__FILE__[sizeof (__FILE__) - 17] : \
-
 
145
   (sizeof (__FILE__) > 19) && ((__FILE__[sizeof (__FILE__) - 19] == '/') || (__FILE__[sizeof (__FILE__) - 19] == '\\')) ? &__FILE__[sizeof (__FILE__) - 18] : \
-
 
146
   (sizeof (__FILE__) > 20) && ((__FILE__[sizeof (__FILE__) - 20] == '/') || (__FILE__[sizeof (__FILE__) - 20] == '\\')) ? &__FILE__[sizeof (__FILE__) - 19] : \
-
 
147
   (sizeof (__FILE__) > 21) && ((__FILE__[sizeof (__FILE__) - 21] == '/') || (__FILE__[sizeof (__FILE__) - 21] == '\\')) ? &__FILE__[sizeof (__FILE__) - 20] : \
-
 
148
   (sizeof (__FILE__) > 22) && ((__FILE__[sizeof (__FILE__) - 22] == '/') || (__FILE__[sizeof (__FILE__) - 22] == '\\')) ? &__FILE__[sizeof (__FILE__) - 21] : \
-
 
149
   (sizeof (__FILE__) > 23) && ((__FILE__[sizeof (__FILE__) - 23] == '/') || (__FILE__[sizeof (__FILE__) - 23] == '\\')) ? &__FILE__[sizeof (__FILE__) - 22] : \
-
 
150
   (sizeof (__FILE__) > 24) && ((__FILE__[sizeof (__FILE__) - 24] == '/') || (__FILE__[sizeof (__FILE__) - 24] == '\\')) ? &__FILE__[sizeof (__FILE__) - 23] : \
-
 
151
   (sizeof (__FILE__) > 25) && ((__FILE__[sizeof (__FILE__) - 25] == '/') || (__FILE__[sizeof (__FILE__) - 25] == '\\')) ? &__FILE__[sizeof (__FILE__) - 24] : \
-
 
152
   (sizeof (__FILE__) > 26) && ((__FILE__[sizeof (__FILE__) - 26] == '/') || (__FILE__[sizeof (__FILE__) - 26] == '\\')) ? &__FILE__[sizeof (__FILE__) - 25] : \
-
 
153
   (sizeof (__FILE__) > 27) && ((__FILE__[sizeof (__FILE__) - 27] == '/') || (__FILE__[sizeof (__FILE__) - 27] == '\\')) ? &__FILE__[sizeof (__FILE__) - 26] : \
-
 
154
   (sizeof (__FILE__) > 28) && ((__FILE__[sizeof (__FILE__) - 28] == '/') || (__FILE__[sizeof (__FILE__) - 28] == '\\')) ? &__FILE__[sizeof (__FILE__) - 27] : \
-
 
155
   (sizeof (__FILE__) > 29) && ((__FILE__[sizeof (__FILE__) - 29] == '/') || (__FILE__[sizeof (__FILE__) - 29] == '\\')) ? &__FILE__[sizeof (__FILE__) - 28] : \
-
 
156
   (sizeof (__FILE__) > 30) && ((__FILE__[sizeof (__FILE__) - 30] == '/') || (__FILE__[sizeof (__FILE__) - 30] == '\\')) ? &__FILE__[sizeof (__FILE__) - 29] : \
-
 
157
   (sizeof (__FILE__) > 31) && ((__FILE__[sizeof (__FILE__) - 31] == '/') || (__FILE__[sizeof (__FILE__) - 31] == '\\')) ? &__FILE__[sizeof (__FILE__) - 30] : \
-
 
158
   (sizeof (__FILE__) > 32) && ((__FILE__[sizeof (__FILE__) - 32] == '/') || (__FILE__[sizeof (__FILE__) - 32] == '\\')) ? &__FILE__[sizeof (__FILE__) - 31] : \
-
 
159
   (sizeof (__FILE__) > 33) && ((__FILE__[sizeof (__FILE__) - 33] == '/') || (__FILE__[sizeof (__FILE__) - 33] == '\\')) ? &__FILE__[sizeof (__FILE__) - 32] : \
-
 
160
   __FILE__) // this *COMPILE-TIME* macro complements the __FILE__ macro defined by the C standard by returning just the filename portion of the full path. Supports filenames up to 32 chars. Expand as necessary.
-
 
161
#endif // !__FILE_NAME__
-
 
162
 
-
 
163
 
-
 
164
// logging macros
40
// compiler-specific glue
165
#define LOG(type,lvl,...) do { if ((lvl) <= verbose_level) { fprintf (stderr, "ifstool: %s: ", (type)); if (verbose_level > 1) fprintf (stderr, "%s:%d:%s(): ", __FILE_NAME__, __LINE__, __FUNCTION__); fprintf (stderr, __VA_ARGS__); fputc ('\n', stderr); } } while (0)
41
#ifndef _MSC_VER
166
#define LOG_ERROR(...)   LOG ("error",   0, __VA_ARGS__)
-
 
167
#define LOG_WARNING(...) LOG ("warning", 1, __VA_ARGS__)
-
 
168
#define LOG_INFO(...)    LOG ("info",    2, __VA_ARGS__)
-
 
169
#define LOG_DEBUG(...)   LOG ("debug",   3, __VA_ARGS__)
42
#define sscanf_s sscanf // WARNING: TRUE FOR THIS FILE ONLY!
170
 
-
 
171
// macro to gently exit with an error message
43
#endif // !_MSC_VER
172
#define DIE_WITH_EXITCODE(exitcode,...) do { LOG_ERROR (__VA_ARGS__); exit ((exitcode)); } while (0)
-
 
173
 
-
 
174
// macro to exit less brutally than with abort() if something doesn't go the way we'd like to
-
 
175
#define WELLMANNERED_ASSERT(is_is_true,...) do { if (!(is_is_true)) { LOG ("fatal error", 0, "consistency check failed"); LOG ("fatal error", 0, __VA_ARGS__); exit (1); } } while (0)
-
 
176
 
-
 
177
 
-
 
178
// macros for checked read/write/seek operations
-
 
179
#define fseek_or_die(fp,pos,mode) WELLMANNERED_ASSERT (fseek ((fp), (pos), (mode)) == 0, "fseek() failed with errno %d (%s)", errno, strerror (errno))
-
 
180
#define fread_or_die(buf,sz,len,fp) WELLMANNERED_ASSERT (fread ((buf), (sz), (len), (fp)) == (len), "fread() failed with errno %d (%s)", errno, strerror (errno))
-
 
181
#define fwrite_or_die(buf,sz,len,fp) WELLMANNERED_ASSERT ((fwrite ((buf), (sz), (len), (fp)) == (len)) && (fflush ((fp)) == 0), "flushed fwrite() failed with errno %d (%s)", errno, strerror (errno))
-
 
182
 
44
 
183
 
45
 
184
// macros for accessing ELF files
-
 
185
#define ELF_MAGIC_STR "\x7f" "ELF"
-
 
186
#define ELF_ENDIAN_LITTLE 1 // 'endianness' member of an ELF header: ELF file is little endian
-
 
187
#define ELF_ENDIAN_BIG    2 // 'endianness' member of an ELF header: ELF file is big endian
-
 
188
#define ELF_MACHINE_X86_64  0x3e // 'instruction_set' member of an ELF header, also used in the IFS startup header: ELF file is for x86_64 processors (62 decimal)
-
 
189
#define ELF_MACHINE_AARCH64 0xb7 // 'instruction_set' member of an ELF header, also used in the IFS startup header: ELF file is for ARM64 processors (183 decimal)
-
 
190
#define ELF_SECTIONTYPE_STRINGTABLE 3
-
 
191
#define ELF_DT_NULL    0 // marks end of dynamic section
-
 
192
#define ELF_DT_SONAME 14 // canonical name of shared object
-
 
193
#define ELF_GET_NUMERIC(elfhdr,elfstruct,member) ((elfhdr)->u.elf.platform_size == 2 ? /* is it a 64-bit ELF file ? */ \
-
 
194
   ( \
-
 
195
      (sizeof ((elfstruct)->u.elf64.member) == 1) || (((elfhdr)->u.elf.endianness == 1) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) || (((elfhdr)->u.elf.endianness == 2) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) ? /* single-byte, or same endianness ? */ \
46
// libasan (Address Sanitizer) options: this is not a daemon, so I don't care about leaks: they will be recovered by the OS at program exit
196
         (elfstruct)->u.elf64.member /* same endianness, or single byte required: don't swap */ \
-
 
197
      : /* else */ \
-
 
198
         (sizeof ((elfstruct)->u.elf64.member) == 8 ? __builtin_bswap64 ((elfstruct)->u.elf64.member) : (sizeof ((elfstruct)->u.elf64.member) == 4 ? __builtin_bswap32 ((elfstruct)->u.elf64.member) : __builtin_bswap16 ((elfstruct)->u.elf64.member))) /* different endianness: swap */ \
47
const char *__asan_default_options () { return ("detect_leaks=0"); }
199
   ) \
-
 
200
   : /* else peek at 32-bit ELF */ \
-
 
201
   ( \
-
 
202
      (sizeof ((elfstruct)->u.elf32.member) == 1) || (((elfhdr)->u.elf.endianness == 1) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) || (((elfhdr)->u.elf.endianness == 2) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) ? /* single-byte, or same endianness ? */ \
-
 
203
         (elfstruct)->u.elf32.member /* same endianness, or single byte required: don't swap */ \
-
 
204
      : /* else */ \
-
 
205
         (sizeof ((elfstruct)->u.elf32.member) == 4 ? __builtin_bswap32 ((elfstruct)->u.elf32.member) : __builtin_bswap16 ((elfstruct)->u.elf32.member)) /* different endianness: swap */ \
-
 
206
   ) \
-
 
207
) // this macro supports 32- and 64-bit ELF files in low and big endianness transparently
-
 
208
#define ELF_SET_NUMERIC(elfhdr,elfstruct,member,data) ((elfhdr)->u.elf.platform_size == 2 ? /* is it a 64-bit ELF file ? */ \
-
 
209
   ((elfstruct)->u.elf64.member = ( \
-
 
210
      (sizeof ((elfstruct)->u.elf64.member) == 1) || (((elfhdr)->u.elf.endianness == 1) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) || (((elfhdr)->u.elf.endianness == 2) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) ? /* single-byte, or same endianness ? */ \
-
 
211
         (sizeof ((elfstruct)->u.elf64.member) == 8 ? (uint64_t) ((data)) : (sizeof ((elfstruct)->u.elf64.member) == 4 ? (uint32_t) ((data)) : (sizeof ((elfstruct)->u.elf64.member) == 2 ? (uint16_t) ((data)) : (uint8_t) ((data))))) /* same endianness, or single byte required: don't swap */ \
-
 
212
      : /* else */ \
-
 
213
         (sizeof ((elfstruct)->u.elf64.member) == 8 ? __builtin_bswap64 ((data)) : (sizeof ((elfstruct)->u.elf64.member) == 4 ? __builtin_bswap32 ((data)) : __builtin_bswap16 ((data)))) /* different endianness: swap */ \
-
 
214
   )) \
-
 
215
   : /* else poke at 32-bit ELF */ \
-
 
216
   ((elfstruct)->u.elf32.member = ( \
-
 
217
      (sizeof ((elfstruct)->u.elf32.member) == 1) || (((elfhdr)->u.elf.endianness == 1) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) || (((elfhdr)->u.elf.endianness == 2) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) ? /* single-byte, or same endianness ? */ \
-
 
218
         (sizeof ((elfstruct)->u.elf64.member) == 4 ? (uint32_t) ((data)) : (sizeof ((elfstruct)->u.elf64.member) == 2 ? (uint16_t) ((data)) : (uint8_t) ((data)))) /* same endianness, or single byte required: don't swap */ \
-
 
219
      : /* else */ \
-
 
220
         (sizeof ((elfstruct)->u.elf32.member) == 4 ? __builtin_bswap32 ((data)) : __builtin_bswap16 ((data))) /* different endianness: swap */ \
-
 
221
   )) \
-
 
222
) // this macro supports 32- and 64-bit ELF files in low and big endianness transparently
-
 
223
#define ELF_GET_STRING(elfhdr,elfstruct,member) ((elfhdr)->u.elf.platform_size == 2 ? (elfstruct)->u.elf64.member : (elfstruct)->u.elf32.member) // this macro supports 32- and 64-bit ELF files transparently
-
 
224
#define ELF_SET_STRING(elfhdr,elfstruct,member,data,len) memcpy (((elfhdr)->u.elf.platform_size == 2 ? (elfstruct)->u.elf64.member : (elfstruct)->u.elf32.member), (data), (len)) // this macro supports 32- and 64-bit ELF files transparently
-
 
225
#define ELF_STRUCT_SIZE(elfhdr,elfstruct) ((elfhdr)->u.elf.platform_size == 2 ? sizeof ((elfstruct)->u.elf64) : sizeof ((elfstruct)->u.elf32)) // this macro supports 32- and 64-bit ELF files transparently
-
 
226
 
48
 
227
 
49
 
228
// placeholder value
50
// placeholder value
229
#define WILL_BE_FILLED_LATER 0xbaadf00d // urgh
51
#define WILL_BE_FILLED_LATER 0xbaadf00d // urgh
230
 
-
 
231
 
-
 
232
// bitmapped flags used in the flags1 member of the startup header
-
 
233
#define STARTUP_HDR_FLAGS1_VIRTUAL        (1 << 0)
-
 
234
#define STARTUP_HDR_FLAGS1_BIGENDIAN      (1 << 1)
-
 
235
//#define STARTUP_HDR_FLAGS1_COMPRESS_MASK  0x1c
-
 
236
//#define STARTUP_HDR_FLAGS1_COMPRESS_SHIFT 0x02
-
 
237
//#define STARTUP_HDR_FLAGS1_COMPRESS_NONE  0x00
-
 
238
//#define STARTUP_HDR_FLAGS1_COMPRESS_ZLIB  0x04
-
 
239
//#define STARTUP_HDR_FLAGS1_COMPRESS_LZO   0x08
-
 
240
//#define STARTUP_HDR_FLAGS1_COMPRESS_UCL   0x0c
-
 
241
#define STARTUP_HDR_FLAGS1_TRAILER_V2     (1 << 5) // if set, then a struct startup_trailer_v2 follows the startup. If the image is compressed, then the compressed imagefs is followed by a struct image_trailer_v2
-
 
242
 
-
 
243
 
-
 
244
// bitmapped flags used in the flags member of the image header
-
 
245
#define IMAGE_FLAGS_BIGENDIAN  (1 << 0) // header, trailer, dirents in big-endian format
-
 
246
#define IMAGE_FLAGS_READONLY   (1 << 1) // do not try to write to image (rom/flash)
-
 
247
#define IMAGE_FLAGS_INO_BITS   (1 << 2) // inode bits valid
-
 
248
#define IMAGE_FLAGS_SORTED     (1 << 3) // dirent section is sorted (by pathname)
-
 
249
#define IMAGE_FLAGS_TRAILER_V2 (1 << 4) // image uses struct image_trailer_v2
-
 
250
 
-
 
251
 
-
 
252
// bitmapped flags superposed to a filesystem entry's inode number
-
 
253
#define IFS_INO_PROCESSED_ELF 0x80000000
-
 
254
#define IFS_INO_RUNONCE_ELF   0x40000000
-
 
255
#define IFS_INO_BOOTSTRAP_EXE 0x20000000
-
 
256
 
52
 
257
 
53
 
258
// miscellaneous macros
54
// miscellaneous macros
259
#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
55
#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
260
#ifdef _WIN32
56
#ifdef _WIN32
261
#define IS_DIRSEP(c) (((c) == '/') || ((c) == '\\')) // platform-specific directory separator, Win32 variant
57
#define IS_DIRSEP(c) (((c) == '/') || ((c) == '\\')) // platform-specific directory separator, Win32 variant
262
#define PATH_SEP ';' // platform-specific PATH element separator, Win32 variant
-
 
263
#define PATH_SEP_STR ";" // platform-specific PATH element separator (as string), Win32 variant
58
#define PATH_SEP ";" // platform-specific PATH element separator (as string), Win32 variant
264
#else // !_WIN32, thus POSIX
59
#else // !_WIN32, thus POSIX
265
#define IS_DIRSEP(c) ((c) == '/') // platform-specific directory separator, UNIX variant
60
#define IS_DIRSEP(c) ((c) == '/') // platform-specific directory separator, UNIX variant
266
#define PATH_SEP ':' // platform-specific PATH element separator, UNIX variant
-
 
267
#define PATH_SEP_STR ":" // platform-specific PATH element separator (as string), UNIX variant
61
#define PATH_SEP ":" // platform-specific PATH element separator (as string), UNIX variant
268
#endif // _WIN32
62
#endif // _WIN32
269
#define RECORD_SEP '\x1e' // arbitrarily-chosen ASCII record separator
-
 
270
#define RECORD_SEP_STR "\x1e" // arbitrarily-chosen ASCII record separator (as string)
63
#define RECORD_SEP "\x1e" // arbitrarily-chosen ASCII record separator, as a C string suitable for e.g. strtok()
271
 
-
 
272
 
-
 
273
// SHA-512 block and digest sizes
-
 
274
#define SHA512_BLOCK_LENGTH 128 // in bytes
-
 
275
#define SHA512_DIGEST_LENGTH 64 // in bytes
-
 
276
 
-
 
277
 
-
 
278
// SHA-512 computation context structure type definition
-
 
279
typedef struct sha512_ctx_s
-
 
280
{
-
 
281
   uint64_t state[8];
-
 
282
   uint64_t bitcount[2];
-
 
283
   uint8_t buffer[SHA512_BLOCK_LENGTH];
-
 
284
} SHA512_CTX;
-
 
285
 
-
 
286
 
-
 
287
#if 0 // TODO: startup script compiler. Someday.
-
 
288
#define SCRIPT_FLAGS_EXTSCHED   0x01
-
 
289
#define SCRIPT_FLAGS_SESSION    0x02
-
 
290
#define SCRIPT_FLAGS_SCHED_SET  0x04
-
 
291
#define SCRIPT_FLAGS_CPU_SET    0x08
-
 
292
#define SCRIPT_FLAGS_BACKGROUND 0x20
-
 
293
#define SCRIPT_FLAGS_KDEBUG     0x40
-
 
294
 
-
 
295
#define SCRIPT_POLICY_NOCHANGE 0
-
 
296
#define SCRIPT_POLICY_FIFO     1
-
 
297
#define SCRIPT_POLICY_RR       2
-
 
298
#define SCRIPT_POLICY_OTHER    3
-
 
299
 
-
 
300
#define SCRIPT_TYPE_EXTERNAL        0
-
 
301
#define SCRIPT_TYPE_WAITFOR         1
-
 
302
#define SCRIPT_TYPE_REOPEN          2
-
 
303
#define SCRIPT_TYPE_DISPLAY_MSG     3
-
 
304
#define SCRIPT_TYPE_PROCMGR_SYMLINK 4
-
 
305
#define SCRIPT_TYPE_EXTSCHED_APS    5
-
 
306
 
-
 
307
#define SCRIPT_CHECKS_MS 100
-
 
308
 
-
 
309
#define SCRIPT_SCHED_EXT_NONE 0
-
 
310
#define SCRIPT_SCHED_EXT_APS  1
-
 
311
 
-
 
312
#define SCRIPT_APS_SYSTEM_PARTITION_ID   0
-
 
313
#define SCRIPT_APS_SYSTEM_PARTITION_NAME "System"
-
 
314
#define SCRIPT_APS_PARTITION_NAME_LENGTH 15
-
 
315
#define SCRIPT_APS_MAX_PARTITIONS        8
-
 
316
 
-
 
317
 
-
 
318
START_OF_PACKED_STRUCT () // we need byte-alignment for this struct
-
 
319
typedef PACKED (struct) bootscriptcmd_header_s
-
 
320
{
-
 
321
   uint16_t size; // size of cmd entry
-
 
322
   uint8_t type;
-
 
323
   uint8_t spare;
-
 
324
} bootscriptcmd_header_t;
-
 
325
END_OF_PACKED_STRUCT () // restore default alignment
-
 
326
 
-
 
327
 
-
 
328
START_OF_PACKED_STRUCT () // we need byte-alignment for this struct
-
 
329
typedef union bootscriptcmd_s
-
 
330
{
-
 
331
   PACKED (struct) script_external
-
 
332
   {
-
 
333
      bootscriptcmd_header_t hdr;
-
 
334
      uint8_t cpu; // CPU (turn into runmask)
-
 
335
      uint8_t flags;
-
 
336
      union script_external_extsched
-
 
337
      {
-
 
338
         uint8_t reserved[2];
-
 
339
         PACKED (struct)
-
 
340
         {
-
 
341
            uint8_t id;
-
 
342
            uint8_t reserved[1];
-
 
343
         } aps;
-
 
344
      } extsched; // extended scheduler
-
 
345
      uint8_t policy; // POLICY_FIFO, POLICY_RR, ...
-
 
346
      uint8_t priority; // priority to run cmd at
-
 
347
      uint8_t argc; // # of args
-
 
348
      uint8_t envc; // # of environment entries
-
 
349
      char args[0]; // executable, argv, envp (null padded to 32-bit align)
-
 
350
   } external;
-
 
351
   PACKED (struct) script_waitfor_reopen
-
 
352
   {
-
 
353
      bootscriptcmd_header_t hdr;
-
 
354
      uint16_t checks;
-
 
355
      char fname[0]; // char fname[] (null padded to 32-bit align)
-
 
356
   } waitfor_reopen;
-
 
357
   PACKED (struct) script_display_msg
-
 
358
   {
-
 
359
      bootscriptcmd_header_t hdr;
-
 
360
      char msg[0]; // char msg[] (null padded to 32-bit align)
-
 
361
   } display_msg;
-
 
362
   PACKED (struct) script_procmgr_symlink
-
 
363
   {
-
 
364
      bootscriptcmd_header_t hdr;
-
 
365
      char src_dest[0]; // <src_name>, '\0', <dest_name> '\0' (null padded to 32-bit align)
-
 
366
   } procmgr_symlink;
-
 
367
   PACKED (struct) script_extsched_aps
-
 
368
   {
-
 
369
      bootscriptcmd_header_t hdr;
-
 
370
      uint8_t parent;
-
 
371
      uint8_t budget;
-
 
372
      uint16_t critical;
-
 
373
      uint8_t id;
-
 
374
      char pname[0]; // char pname[] (null padded to 32-bit align)
-
 
375
   } extsched_aps;
-
 
376
} bootscriptcmd_t;
-
 
377
END_OF_PACKED_STRUCT () // restore default alignment
-
 
378
#endif // 0
-
 
379
 
64
 
380
 
65
 
381
#define INITIAL_STARTUP_SCRIPT \
66
#define INITIAL_STARTUP_SCRIPT \
382
   /* procmgr_symlink /proc/boot/ldqnx-64.so.2 /usr/lib/ldqnx-64.so.2 */ \
67
   /* procmgr_symlink /proc/boot/ldqnx-64.so.2 /usr/lib/ldqnx-64.so.2 */ \
383
   "\x34\x00" /*size*/ "\x04" /*type*/ "\x00" /*spare*/ "/proc/boot/ldqnx-64.so.2\0" "/usr/lib/ldqnx-64.so.2\0" \
68
   "\x34\x00" /*size*/ "\x04" /*type*/ "\x00" /*spare*/ "/proc/boot/ldqnx-64.so.2\0" "/usr/lib/ldqnx-64.so.2\0" \
Line 385... Line 70...
385
   "\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*/ \
70
   "\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*/ \
386
   /* display_msg "Startup complete */ \
71
   /* display_msg "Startup complete */ \
387
   "\x18\x00" /*size*/ "\x03" /*type*/ "\x00" /*spare*/ "Startup complete\n\0" "\x00\00" /*padding*/ \
72
   "\x18\x00" /*size*/ "\x03" /*type*/ "\x00" /*spare*/ "Startup complete\n\0" "\x00\00" /*padding*/ \
388
   /* trailer */ \
73
   /* trailer */ \
389
   "\x00\x00\x00\x00"
74
   "\x00\x00\x00\x00"
390
 
-
 
391
 
-
 
392
START_OF_PACKED_STRUCT () // we need byte-alignment for this struct
-
 
393
typedef PACKED (struct) fsentry_s
-
 
394
{
-
 
395
   PACKED (struct) fsentry_header_s
-
 
396
   {
-
 
397
      uint16_t size; // size of dirent
-
 
398
      uint16_t extattr_offset; // if zero, no extattr data
-
 
399
      uint32_t ino; // if zero, skip entry
-
 
400
      uint32_t mode; // mode and perms of entry
-
 
401
      uint32_t gid;
-
 
402
      uint32_t uid;
-
 
403
      uint32_t mtime;
-
 
404
   } header;
-
 
405
   PACKED (union) fsentry_specific_u
-
 
406
   {
-
 
407
      PACKED (struct) fsentry_file_s // when (mode & S_IFMT) == S_IFREG
-
 
408
      {
-
 
409
         uint32_t offset; // offset from header
-
 
410
         uint32_t size;
-
 
411
         char *path; // null terminated path (no leading slash)
-
 
412
         char *UNSAVED_databuf; // file data blob buffer (NOT SAVED IN THE IFS)
-
 
413
      } file;
-
 
414
      PACKED (struct) fsentry_dir_s // when (mode & S_IFMT) == S_IFDIR
-
 
415
      {
-
 
416
         char *path; // null terminated path (no leading slash)
-
 
417
      } dir;
-
 
418
      PACKED (struct) fsentry_symlink_s // when (mode & S_IFMT) == S_IFLNK
-
 
419
      {
-
 
420
         uint16_t sym_offset; // offset to 'contents' from 'path'
-
 
421
         uint16_t sym_size; // strlen (contents)
-
 
422
         char *path; // null terminated path (no leading slash)
-
 
423
         char *contents; // null terminated symlink contents
-
 
424
      } symlink;
-
 
425
      PACKED (struct) fsentry_device_s // when (mode & S_IFMT) == S_IF<CHR|BLK|FIFO|NAM|SOCK>
-
 
426
      {
-
 
427
         uint32_t dev;
-
 
428
         uint32_t rdev;
-
 
429
         char *path; // null terminated path (no leading slash)
-
 
430
      } device;
-
 
431
   } u;
-
 
432
   bool UNSAVED_was_data_written; // whether this entry's data was written to the image (NOT SAVED IN THE IFS)
-
 
433
} fsentry_t;
-
 
434
END_OF_PACKED_STRUCT () // restore default alignment
-
 
435
 
-
 
436
 
-
 
437
START_OF_PACKED_STRUCT () // we need byte-alignment for this struct
-
 
438
typedef PACKED (struct) startup_header_s // size 256 bytes
-
 
439
{
-
 
440
   // I - used by the QNX IPL
-
 
441
   // S - used by the startup program
-
 
442
   uint8_t signature[4];   // [I ] Header signature, "\xeb\x7e\xff\x00"
-
 
443
   uint16_t version;       // [I ] Header version, i.e. 1
-
 
444
   uint8_t flags1;         // [IS] Misc flags, 0x21 (= 0x20 | STARTUP_HDR_FLAGS1_VIRTUAL)
-
 
445
   uint8_t flags2;         // [  ] No flags defined yet (0)
-
 
446
   uint16_t header_size;   // [ S] sizeof(struct startup_header), i.e. 256
-
 
447
   uint16_t machine;       // [IS] Machine type from elfdefinitions.h, i.e. 0x003E --> _ELF_DEFINE_EM(EM_X86_64, 62, "AMD x86-64 architecture")
-
 
448
   uint32_t startup_vaddr; // [I ] Virtual Address to transfer to after IPL is done, here 0x01403008 (appears in "Entry" column for "startup.*")
-
 
449
   uint32_t paddr_bias;    // [ S] Value to add to physical address to get a value to put into a pointer and indirected through, here 0 (no indirections)
-
 
450
   uint32_t image_paddr;   // [IS] Physical address of image, here 0x01400f30 (appears in "Offset" column for "startup-header" which is the first entry/start of file)
-
 
451
   uint32_t ram_paddr;     // [IS] Physical address of RAM to copy image to (startup_size bytes copied), here 0x01400f30 (same as above)
-
 
452
   uint32_t ram_size;      // [ S] Amount of RAM used by the startup program and executables contained in the file system, here 0x00cd6128 i.e. 13 459 752 dec. which is 13 Mb. i.e. IFS file size minus 0x9eee
-
 
453
   uint32_t startup_size;  // [I ] Size of startup (never compressed), here 0x02f148 or 192 840 bytes
-
 
454
   uint32_t stored_size;   // [I ] Size of entire image, here 0x00cd6128 (same as ram_size)
-
 
455
   uint32_t imagefs_paddr; // [IS] Set by IPL to where the imagefs is when startup runs (0)
-
 
456
   uint32_t imagefs_size;  // [ S] Size of uncompressed imagefs, here 0x00ca6fe0 or 13 266 912 bytes
-
 
457
   uint16_t preboot_size;  // [I ] Size of loaded before header, here 0xf30 or 3888 bytes (size of "bios.boot" file))
-
 
458
   uint16_t zero0;         // [  ] Zeros
-
 
459
   uint32_t zero[1];       // [  ] Zeros
-
 
460
   uint64_t addr_off;      // [ S] Offset to add to startup_vaddr, image_paddr, ram_paddr, and imagefs_paddr members, here zero (0)
-
 
461
   uint32_t info[48];      // [IS] Array of startup_info* structures (zero filled)
-
 
462
} startup_header_t;
-
 
463
END_OF_PACKED_STRUCT () // restore default alignment
-
 
464
 
-
 
465
 
-
 
466
START_OF_PACKED_STRUCT () // we need byte-alignment for this struct
-
 
467
typedef PACKED (struct) startup_trailer_s
-
 
468
{
-
 
469
   uint32_t cksum; // checksum from start of header to start of trailer
-
 
470
} startup_trailer_v1_t;
-
 
471
END_OF_PACKED_STRUCT () // restore default alignment
-
 
472
 
-
 
473
 
-
 
474
// NOTE: The checksums in this trailer will only be valid prior to entering startup.
-
 
475
// Because the startup binary is executed in-place, its data segment will change once the program is running.
-
 
476
// Hence, any checksum validation would need to be done by the boot loader / IFS.
-
 
477
START_OF_PACKED_STRUCT () // we need byte-alignment for this struct
-
 
478
typedef PACKED (struct) startup_trailer_v2_s
-
 
479
{
-
 
480
   uint8_t sha512[64]; // SHA512 from start of header to start of trailer
-
 
481
   uint32_t cksum; // checksum from start of header to start of this member
-
 
482
} startup_trailer_v2_t;
-
 
483
END_OF_PACKED_STRUCT () // restore default alignment
-
 
484
 
-
 
485
 
-
 
486
START_OF_PACKED_STRUCT () // we need byte-alignment for this struct
-
 
487
typedef PACKED (struct) image_header_s
-
 
488
{
-
 
489
   uint8_t signature[7]; // image filesystem signature, i.e. "imagefs"
-
 
490
   uint8_t flags; // endian neutral flags, 0x1c
-
 
491
   uint32_t image_size; // size from start of header to end of trailer (here 0xca6fe0 or 13 266 912)
-
 
492
   uint32_t hdr_dir_size; // size from start of header to last dirent (here 0x12b8 or 4792)
-
 
493
   uint32_t dir_offset; // offset from start of header to start of first dirent (here 0x5c or 92)
-
 
494
   uint32_t boot_ino[4]; // inode of files for bootstrap pgms (here 0xa0000002, 0, 0, 0)
-
 
495
   uint32_t script_ino; // inode of file for script (here 3)
-
 
496
   uint32_t chain_paddr; // offset to next filesystem signature (0)
-
 
497
   uint32_t spare[10]; // zerofill
-
 
498
   uint32_t mountflags; // default _MOUNT_* from sys/iomsg.h (0)
-
 
499
   char mountpoint[4]; // default mountpoint for image ("/" + "\0\0\0")
-
 
500
} image_header_t;
-
 
501
END_OF_PACKED_STRUCT () // restore default alignment
-
 
502
 
-
 
503
 
-
 
504
START_OF_PACKED_STRUCT () // we need byte-alignment for this struct
-
 
505
typedef PACKED (struct) image_trailer_v1_s
-
 
506
{
-
 
507
   uint32_t cksum; // checksum from start of header to start of trailer
-
 
508
} image_trailer_v1_t; // NOTE: this is the same structure as startup_trailer_v1_t
-
 
509
END_OF_PACKED_STRUCT () // restore default alignment
-
 
510
 
-
 
511
 
-
 
512
// NOTE: the checksums in this trailer will only be valid until the first non-startup bootstrap binary (e.g., startup-verifier, procnto, ...) is invoked.
-
 
513
// Because bootstrap binaries execute in-place, their data segments will change once the programs are running.
-
 
514
// Hence, any checksum validation would need to be done either by the boot loader / IFS or by the startup.
-
 
515
START_OF_PACKED_STRUCT () // we need byte-alignment for this struct
-
 
516
typedef PACKED (struct) image_trailer_v2_s
-
 
517
{
-
 
518
   uint8_t sha512[64]; // SHA512 from start of image header to start of trailer
-
 
519
   uint32_t cksum; // checksum from start of header to start of this member
-
 
520
} image_trailer_v2_t; // NOTE: this is the same structure as startup_trailer_v2_t
-
 
521
END_OF_PACKED_STRUCT () // restore default alignment
-
 
522
 
-
 
523
 
-
 
524
// Executable and Linkable Format master header structure type definition
-
 
525
START_OF_PACKED_STRUCT () // we need byte-alignment for this struct
-
 
526
typedef PACKED (struct) elf_header_s
-
 
527
{
-
 
528
   PACKED (union)
-
 
529
   {
-
 
530
      PACKED (struct)
-
 
531
      {
-
 
532
         uint8_t magic[4];                     // offset 0: "\x7f" + "ELF"
-
 
533
         uint8_t platform_size;                // offset 4: 1 = 32-bit, 2 = 64-bit
-
 
534
         uint8_t endianness;                   // offset 5: 1 = little endian, 2 = big endian
-
 
535
         uint8_t header_version;               // offset 6: typically 1
-
 
536
         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
-
 
537
         uint8_t spare[8];                     // offset 8: zeroes
-
 
538
         uint16_t type;                        // offset 16: 1 = relocatable, 2 = executable, 3 = shared, 4 = core dump
-
 
539
         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
-
 
540
         uint32_t elf_version;                 // offset 20: typically 1
-
 
541
      } elf;
-
 
542
      PACKED (struct) // size == 52
-
 
543
      {
-
 
544
         uint8_t magic[4];                     // offset 0: "\x7f" + "ELF"
-
 
545
         uint8_t platform_size;                // offset 4: 1 = 32-bit, 2 = 64-bit
-
 
546
         uint8_t endianness;                   // offset 5: 1 = little endian, 2 = big endian
-
 
547
         uint8_t header_version;               // offset 6: typically 1
-
 
548
         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
-
 
549
         uint8_t spare[8];                     // offset 8: zeroes
-
 
550
         uint16_t type;                        // offset 16: 1 = relocatable, 2 = executable, 3 = shared, 4 = core dump
-
 
551
         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
-
 
552
         uint32_t elf_version;                 // offset 20: typically 1
-
 
553
         uint32_t entrypoint_offset;           // offset 24: offset to program entrypoint
-
 
554
         uint32_t program_header_table_offset; // offset 28: offset to program header table
-
 
555
         uint32_t section_header_table_offset; // offset 32: offset to section header table
-
 
556
         uint32_t flags;                       // offset 36: flags (architecture-dependent, none for x86)
-
 
557
         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!
-
 
558
         uint16_t program_header_item_size;    // offset 42: size of an entry in the program header table
-
 
559
         uint16_t program_header_table_len;    // offset 44: number of entries in the program header table
-
 
560
         uint16_t section_header_item_size;    // offset 46: size of an entry in the section header table
-
 
561
         uint16_t section_header_table_len;    // offset 48: number of entries in the section header table
-
 
562
         uint16_t section_header_names_idx;    // offset 50: index of the entry in the section header table that contains the section names
-
 
563
      } elf32; // size == 52
-
 
564
      PACKED (struct) // size == 64
-
 
565
      {
-
 
566
         uint8_t magic[4];                     // offset 0: "\x7f" + "ELF"
-
 
567
         uint8_t platform_size;                // offset 4: 1 = 32-bit, 2 = 64-bit
-
 
568
         uint8_t endianness;                   // offset 5: 1 = little endian, 2 = big endian
-
 
569
         uint8_t header_version;               // offset 6: typically 1
-
 
570
         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
-
 
571
         uint8_t spare[8];                     // offset 8: zeroes
-
 
572
         uint16_t type;                        // offset 16: 1 = relocatable, 2 = executable, 3 = shared, 4 = core dump
-
 
573
         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
-
 
574
         uint32_t elf_version;                 // offset 20: typically 1
-
 
575
         uint64_t entrypoint_offset;           // offset 24: program entry offset
-
 
576
         uint64_t program_header_table_offset; // offset 32: offset to program header table
-
 
577
         uint64_t section_header_table_offset; // offset 40: offset to section header table
-
 
578
         uint32_t flags;                       // offset 48: flags (architecture-dependent, none for x86)
-
 
579
         uint16_t header_size;                 // offset 52: size of ELF header, 52 for 32-bit ELF and 64 for 64-bit ELF
-
 
580
         uint16_t program_header_item_size;    // offset 54: size of an entry in the program header table
-
 
581
         uint16_t program_header_table_len;    // offset 56: number of entries in the program header table
-
 
582
         uint16_t section_header_item_size;    // offset 58: size of an entry in the section header table
-
 
583
         uint16_t section_header_table_len;    // offset 60: number of entries in the section header table
-
 
584
         uint16_t section_header_names_idx;    // offset 62: index of the entry in the section header table that contains the section names
-
 
585
      } elf64; // size == 64
-
 
586
   } u;
-
 
587
} elf_header_t;
-
 
588
END_OF_PACKED_STRUCT () // restore default alignment
-
 
589
 
-
 
590
 
-
 
591
// Executable and Linkable Format program header structure type definition
-
 
592
START_OF_PACKED_STRUCT () // we need byte-alignment for this struct
-
 
593
typedef PACKED (struct) elf_program_header_s
-
 
594
{
-
 
595
   PACKED (union)
-
 
596
   {
-
 
597
      PACKED (struct)
-
 
598
      {
-
 
599
         uint32_t segment_type; // offset 0: type of segment (0: unused table entry, 1: loadable, 2: dynamic linking information, 3: interpreter information, 4: auxiliary information, 5: reserved, 6: this very segment, 7: TLS template)
-
 
600
      } elf;
-
 
601
      PACKED (struct) // size == 32
-
 
602
      {
-
 
603
         uint32_t segment_type;   // offset 0: type of segment (0: unused table entry, 1: loadable, 2: dynamic linking information, 3: interpreter information, 4: auxiliary information, 5: reserved, 6: this very segment, 7: TLS template)
-
 
604
         uint32_t file_offset;    // offset 4: file offset of this segment
-
 
605
         uint32_t virtual_addr;   // offset 8: virtual address where this segment should be mapped in memory
-
 
606
         uint32_t physical_addr;  // offset 12: on systems where this is relevant, PHYSICAL address where this segment should be mapped in memory
-
 
607
         uint32_t size_in_file;   // offset 16: size of this segment in the ELF file (may be zero)
-
 
608
         uint32_t size_in_memory; // offset 20: size of this segment in memory (may be zero)
-
 
609
         uint32_t segment_flags;  // offset 24: bitmap of segment flags (1: executable, 2: writable, 4: readable)
-
 
610
         uint32_t alignment;      // offset 28: memory alignment (0 or 1 mean non alignment, else must be a power of 2 where virtual_addr == file_offset % alignment)
-
 
611
      } elf32; // size == 32
-
 
612
      PACKED (struct) // size == 56
-
 
613
      {
-
 
614
         uint32_t segment_type;   // offset 0: type of segment (0: unused table entry, 1: loadable, 2: dynamic linking information, 3: interpreter information, 4: auxiliary information, 5: reserved, 6: this very segment, 7: TLS template)
-
 
615
         uint32_t segment_flags;  // offset 4: bitmap of segment flags (1: executable, 2: writable, 4: readable)
-
 
616
         uint64_t file_offset;    // offset 8: file offset of this segment
-
 
617
         uint64_t virtual_addr;   // offset 16: virtual address where this segment should be mapped in memory
-
 
618
         uint64_t physical_addr;  // offset 24: on systems where this is relevant, PHYSICAL address where this segment should be mapped in memory
-
 
619
         uint64_t size_in_file;   // offset 32: size of this segment in the ELF file (may be zero)
-
 
620
         uint64_t size_in_memory; // offset 40: size of this segment in memory (may be zero)
-
 
621
         uint64_t alignment;      // offset 48: memory alignment (0 or 1 mean non alignment, else must be a power of 2 where virtual_addr == file_offset % alignment)
-
 
622
      } elf64; // size == 56
-
 
623
   } u;
-
 
624
} elf_program_header_t;
-
 
625
END_OF_PACKED_STRUCT () // restore default alignment
-
 
626
 
-
 
627
 
-
 
628
// Executable and Linkable Format section header structure type definition
-
 
629
START_OF_PACKED_STRUCT () // we need byte-alignment for this struct
-
 
630
typedef PACKED (struct) elf_section_header_s
-
 
631
{
-
 
632
   PACKED (union)
-
 
633
   {
-
 
634
      PACKED (struct)
-
 
635
      {
-
 
636
         uint32_t name_offset; // offset 0: offset in the string table of the name of this section
-
 
637
         uint32_t type;        // offset 4: section type (0: unused, 1: program data, 2: symbols table, 3: strings table, 4: relocs with addends, 5: symbols hash table, 6: dyld info, 7: notes, 8: BSS, 9: relocs without addends, 11: dyld symbols table, 14: constructors, 15: destructors, 16, preconstructors, 17: group, 18: extended section indices, 19: number of typedefs ...)
-
 
638
      } elf;
-
 
639
      PACKED (struct) // size == 40
-
 
640
      {
-
 
641
         uint32_t name_offset;  // offset 0: offset in the string table of the name of this section
-
 
642
         uint32_t type;         // offset 4: section type (0: unused, 1: program data, 2: symbols table, 3: strings table, 4: relocs with addends, 5: symbols hash table, 6: dyld info, 7: notes, 8: BSS, 9: relocs without addends, 11: dyld symbols table, 14: constructors, 15: destructors, 16, preconstructors, 17: group, 18: extended section indices, 19: number of typedefs ...)
-
 
643
         uint32_t flags;        // offset 8: bitmapped flags (1: writable, 2: takes RAM, 4: executable, 8: reserved, 16: mergeable, 32: contains C-strings, 64: sh_info contains SHT index, 128: preserve order, 256: OS-specific, 512: group member, 1024: TLS template ...)
-
 
644
         uint32_t virtual_addr; // offset 12: address in virtual memory where this section may be loaded
-
 
645
         uint32_t file_offset;  // offset 16: offset of this section in the ELF file
-
 
646
         uint32_t size;         // offset 20: size of this section
-
 
647
         uint32_t linked_index; // offset 24: optional section index of an associated section
-
 
648
         uint32_t info;         // offset 28: optional extra information
-
 
649
         uint32_t alignment;    // offset 32: required memory alignment (must be a power of 2)
-
 
650
         uint32_t entry_size;   // offset 36: for table-like sections, size of an element in the table
-
 
651
      } elf32; // size == 40
-
 
652
      PACKED (struct) // size == 64
-
 
653
      {
-
 
654
         uint32_t name_offset;  // offset 0: offset in the string table of the name of this section
-
 
655
         uint32_t type;         // offset 4: section type (0: unused, 1: program data, 2: symbols table, 3: strings table, 4: relocs with addends, 5: symbols hash table, 6: dyld info, 7: notes, 8: BSS, 9: relocs without addends, 11: dyld symbols table, 14: constructors, 15: destructors, 16, preconstructors, 17: group, 18: extended section indices, 19: number of typedefs ...)
-
 
656
         uint64_t flags;        // offset 8: bitmapped flags (1: writable, 2: takes RAM, 4: executable, 8: reserved, 16: mergeable, 32: contains C-strings, 64: sh_info contains SHT index, 128: preserve order, 256: OS-specific, 512: group member, 1024: TLS template ...)
-
 
657
         uint64_t virtual_addr; // offset 16: address in virtual memory where this section may be loaded
-
 
658
         uint64_t file_offset;  // offset 24: offset of this section in the ELF file
-
 
659
         uint64_t size;         // offset 32: size of this section
-
 
660
         uint32_t linked_index; // offset 40: optional section index of an associated section
-
 
661
         uint32_t info;         // offset 44: optional extra information
-
 
662
         uint64_t alignment;    // offset 48: required memory alignment (must be a power of 2)
-
 
663
         uint64_t entry_size;   // offset 56: for table-like sections, size of an element in the table
-
 
664
      } elf64; // size == 64
-
 
665
   } u;
-
 
666
} elf_section_header_t;
-
 
667
END_OF_PACKED_STRUCT () // restore default alignment
-
 
668
 
-
 
669
 
-
 
670
// Executable and Linkable Format dynamic section entry structure type definition
-
 
671
START_OF_PACKED_STRUCT () // we need byte-alignment for this struct
-
 
672
typedef PACKED (struct) elf_dynamic_section_entry_s
-
 
673
{
-
 
674
   PACKED (union)
-
 
675
   {
-
 
676
      PACKED (struct) // size == 8
-
 
677
      {
-
 
678
         int32_t tag; // dynamic entry type (one of ELF_DT_xxx #defines)
-
 
679
         uint32_t value; // value (as integer, or as pointed address)
-
 
680
      } elf32; // size == 8
-
 
681
      PACKED (struct) // size == 16
-
 
682
      {
-
 
683
         int64_t tag; // dynamic entry type (one of ELF_DT_xxx #defines)
-
 
684
         uint64_t value; // value (as integer, or as pointed address)
-
 
685
      } elf64; // size == 16
-
 
686
   } u;
-
 
687
} elf_dynamic_section_entry_t;
-
 
688
END_OF_PACKED_STRUCT () // restore default alignment
-
 
689
 
-
 
690
 
-
 
691
// generic buffer structure type definition
-
 
692
typedef struct buffer_s
-
 
693
{
-
 
694
   uint8_t *bytes; // mallocated data
-
 
695
   size_t len; // length of allocated data
-
 
696
} buffer_t;
-
 
697
 
75
 
698
 
76
 
699
// IFS directory entry insertion parameters structure type definition
77
// IFS directory entry insertion parameters structure type definition
700
typedef struct parms_s
78
typedef struct parms_s
701
{
79
{
Line 712... Line 90...
712
   bool should_keep_ld_output; // whether to keep .sym files produced by ld calls, togglable by the [+keeplinked] attribute
90
   bool should_keep_ld_output; // whether to keep .sym files produced by ld calls, togglable by the [+keeplinked] attribute
713
   bool is_compiled_bootscript; // entry has [+script] attribute
91
   bool is_compiled_bootscript; // entry has [+script] attribute
714
   int extra_ino_flags; // bitmap of extra inode flags (IFS_INO_xxx)
92
   int extra_ino_flags; // bitmap of extra inode flags (IFS_INO_xxx)
715
   char search[10 * MAXPATHLEN]; // binary search path (the default one will be constructed at startup)
93
   char search[10 * MAXPATHLEN]; // binary search path (the default one will be constructed at startup)
716
 
94
 
717
   buffer_t data;
95
   buffer_t data; // the resolved file's own data bytes
718
} parms_t;
96
} parms_t;
719
 
97
 
720
 
98
 
721
// global variables
99
// exported globals
-
 
100
int verbose_level = 1; // verbosity level, can be increased with multiple -v[...] flags
-
 
101
 
-
 
102
 
-
 
103
// global variables used in this module only
722
static char line_buffer[4096]; // scrap buffer for the IFS build file parser
104
static char line_buffer[4096]; // scrap buffer for the IFS build file parser
723
static uint32_t image_base = 4 * 1024 * 1024; // default image base, as per QNX docs -- can be changed with the [image=XXXX] attribute in the IFS build file
105
static uint32_t image_base = 4 * 1024 * 1024; // default image base, as per QNX docs -- can be changed with the [image=XXXX] attribute in the IFS build file
724
static uint32_t image_end = UINT32_MAX; // default image end (no limit)
106
static uint32_t image_end = UINT32_MAX; // default image end (no limit)
725
static uint32_t image_maxsize = UINT32_MAX; // default image max size (no limit)
107
static uint32_t image_maxsize = UINT32_MAX; // default image max size (no limit)
726
static uint32_t image_totalsize = 0; // image total size, measured once all the blocks have been written to the output IFS file
108
static uint32_t image_totalsize = 0; // image total size, measured once all the blocks have been written to the output IFS file
Line 732... Line 114...
732
#elif defined(__aarch64__)
114
#elif defined(__aarch64__)
733
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)
115
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)
734
#else // unknown platform
116
#else // unknown platform
735
#error Please port ifstool to this platform
117
#error Please port ifstool to this platform
736
#endif
118
#endif
737
static int verbose_level = 1; // verbosity level, can be increased with multiple -v[...] flags
-
 
738
static char *buildfile_pathname = NULL; // pathname of IFS build file
119
static char *buildfile_pathname = NULL; // pathname of IFS build file
739
static char *current_line = NULL; // copy of current line in IFS build file
120
static char *current_line = NULL; // copy of current line in IFS build file
740
static int lineno = 0; // current line number in IFS build file
121
static int lineno = 0; // current line number in IFS build file
741
static char *QNX_TARGET = NULL; // value of the $QNX_TARGET environment variable
122
static char *QNX_TARGET = NULL; // value of the $QNX_TARGET environment variable
742
static char *MKIFS_PATH = NULL; // value of the $MKIFS_PATH environment variable (may contain references to $QNX_TARGET). Initialized by this program if empty.
123
static char *MKIFS_PATH = NULL; // value of the $MKIFS_PATH environment variable (may contain references to $QNX_TARGET). Initialized by this program if empty.
Line 746... Line 127...
746
static size_t bootfile_size = 0;                 // HACK: size of the bootcode binary blob file to put at the start of a bootable IFS
127
static size_t bootfile_size = 0;                 // HACK: size of the bootcode binary blob file to put at the start of a bootable IFS
747
static char *startupfile_pathname = NULL;        // HACK: pathname to precompiled startup file blob to put in the startup header of a bootable IFS
128
static char *startupfile_pathname = NULL;        // HACK: pathname to precompiled startup file blob to put in the startup header of a bootable IFS
748
static size_t startupfile_ep_from_imagebase = 0; // HACK: startup code entrypoint offset from image base for a bootable IFS 
129
static size_t startupfile_ep_from_imagebase = 0; // HACK: startup code entrypoint offset from image base for a bootable IFS 
749
static char *kernelfile_pathname = NULL;         // HACK: pathname to precompiled kernel file blob to put in a bootable IFS
130
static char *kernelfile_pathname = NULL;         // HACK: pathname to precompiled kernel file blob to put in a bootable IFS
750
static size_t kernelfile_offset = 0;             // HACK: kernel file offset in bootable IFS
131
static size_t kernelfile_offset = 0;             // HACK: kernel file offset in bootable IFS
-
 
132
 
-
 
133
 
-
 
134
// exported function prototypes
-
 
135
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
751
 
136
 
752
 
137
 
753
// prototypes of local functions
138
// prototypes of local functions
754
static void sha512_private_transform (SHA512_CTX *context, const uint64_t *data); // used internally in SHA512_Update() and SHA512_Final()
-
 
755
static void SHA512_Init (SHA512_CTX *context);
-
 
756
static void SHA512_Update (SHA512_CTX *context, void *data, size_t len);
-
 
757
static void SHA512_Final (uint8_t digest[SHA512_DIGEST_LENGTH], SHA512_CTX *context);
-
 
758
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())
-
 
759
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
-
 
760
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)
139
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)
761
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)
-
 
762
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
-
 
763
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
-
 
764
static char *read_filecontents (const char *pathname, const char *search_path, buffer_t *outbuf); // 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)
140
static char *resolve_pathname (const char *pathname, const char *search_path); // locates pathname among MKIFS_PATH and returns a pointer to the resolved pathname (static string)
765
static int fwrite_filecontents (const char *pathname, FILE *fp); // dumps the contents of pathname into fp
-
 
766
static int relative_offset_of_in (const char *name, const buffer_t *stringbuf); // returns the relative offset of a particular string in a string table
-
 
767
static elf_section_header_t *elf_get_section_header_by_name (const elf_header_t *elf, const char *section_name); // get a pointer to a named section header in an ELF file
141
static elf_section_header_t *elf_get_section_header_by_name (const elf_header_t *elf, const char *section_name); // get a pointer to a named section header in an ELF file
-
 
142
static size_t Buffer_WriteIFSDirectoryEntryAt (buffer_t *ifs_data, const size_t write_offset, const fsentry_t *fsentry); // writes the given filesystem entry (without its contents) to the IFS buffer
768
static size_t fwrite_fsentry (const fsentry_t *fsentry, FILE *fp); // writes the given filesystem entry into fp (without its contents)
143
static size_t Buffer_AppendIFSFileData (buffer_t *ifs_data, fsentry_t *fsentry); // writes the given filesystem entry's file data (i.e. its contents) to the IFS buffer
-
 
144
static int Buffer_StripELFFile (buffer_t *file, const char *indicative_pathname); // strips an ELF file buffer the way mkifs does it and returns whether it succeeded
769
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
145
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
770
static int fsentry_compare_pathnames_cb (const void *a, const void *b); // qsort() comparison callback that sorts filesystem entries by pathnames
146
static int fsentry_compare_pathnames_cb (const void *a, const void *b); // qsort() comparison callback that sorts filesystem entries by pathnames
771
static void update_MKIFS_PATH (const char *processor);
147
static void update_MKIFS_PATH (const char *processor);
772
static int dump_ifs_info (const char *ifs_pathname, bool want_everything); // dumps detailed info about a particular IFS file on the standard output, returns 0 on success and >0 on error
-
 
773
static int create_intermediate_dirs (const char *file_pathname); // creates all intermediate directories to file_pathname so that fopen(file_pathname, "w") doesn't fail
-
 
774
static int dump_ifs_contents (const char *ifs_pathname, const char *outdir); // dumps the IFS filesystem contents in outdir, returns 0 on success and >0 on error
-
 
775
 
148
 
776
 
149
 
777
static void sha512_private_transform (SHA512_CTX *context, const uint64_t *data)
-
 
778
{
-
 
779
   // logical functions used in SHA-384 and SHA-512
-
 
780
   #define S64(b,x)      (((x) >> (b)) | ((x) << (64 - (b)))) // 64-bit rotate right
-
 
781
   #define Ch(x,y,z)     (((x) & (y)) ^ ((~(x)) & (z)))
-
 
782
   #define Maj(x,y,z)    (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
-
 
783
   #define Sigma0_512(x) (S64(28, (x)) ^ S64(34, (x)) ^ S64(39, (x)))
-
 
784
   #define Sigma1_512(x) (S64(14, (x)) ^ S64(18, (x)) ^ S64(41, (x)))
-
 
785
   #define sigma0_512(x) (S64( 1, (x)) ^ S64( 8, (x)) ^ ((x) >> 7))
-
 
786
   #define sigma1_512(x) (S64(19, (x)) ^ S64(61, (x)) ^ ((x) >> 6))
-
 
787
 
-
 
788
   // hash constant words K for SHA-384 and SHA-512
-
 
789
   static const uint64_t K512[80] = {
-
 
790
      0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL, 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL,
-
 
791
      0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL,
-
 
792
      0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
-
 
793
      0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL, 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL,
-
 
794
      0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL, 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL,
-
 
795
      0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, 0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
-
 
796
      0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL, 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL,
-
 
797
      0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL,
-
 
798
      0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
-
 
799
      0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL, 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL
-
 
800
   };
-
 
801
 
-
 
802
   uint64_t     a, b, c, d, e, f, g, h, s0, s1;
-
 
803
   uint64_t     T1, T2, *W512 = (uint64_t *) context->buffer;
-
 
804
   int j;
-
 
805
 
-
 
806
   // initialize registers with the prev. intermediate value
-
 
807
   a = context->state[0]; b = context->state[1]; c = context->state[2]; d = context->state[3]; e = context->state[4]; f = context->state[5]; g = context->state[6]; h = context->state[7];
-
 
808
 
-
 
809
   for (j = 0; j < 16; j++)
-
 
810
   {
-
 
811
#if __BYTE_ORDER__ ==  __ORDER_LITTLE_ENDIAN__
-
 
812
      W512[j] = __builtin_bswap64 (*data); // convert to host byte order
-
 
813
#elif // __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
-
 
814
      W512[j] = *data;
-
 
815
#else // __BYTE_ORDER__ == ???
-
 
816
#error Please port this SHA-512 code to your exotic endianness platform. What are you compiling this on? PDP? Honeywell?
-
 
817
#endif // __BYTE_ORDER__ ==  __ORDER_LITTLE_ENDIAN__
-
 
818
 
-
 
819
      // apply the SHA-512 compression function to update a..h
-
 
820
      T1 = h + Sigma1_512 (e) + Ch (e, f, g) + K512[j] + W512[j];
-
 
821
      T2 = Sigma0_512 (a) + Maj (a, b, c);
-
 
822
 
-
 
823
      // update registers
-
 
824
      h = g; g = f; f = e; e = d + T1; d = c; c = b; b = a; a = T1 + T2;
-
 
825
 
-
 
826
      data++;
-
 
827
   }
-
 
828
 
-
 
829
   for (; j < 80; j++)
-
 
830
   {
-
 
831
      // part of the message block expansion
-
 
832
      s0 = W512[(j + 1) & 0x0f];
-
 
833
      s0 = sigma0_512 (s0);
-
 
834
      s1 = W512[(j + 14) & 0x0f];
-
 
835
      s1 = sigma1_512 (s1);
-
 
836
 
-
 
837
      // apply the SHA-512 compression function to update a..h
-
 
838
      T1 = h + Sigma1_512 (e) + Ch (e, f, g) + K512[j] + (W512[j & 0x0f] += s1 + W512[(j + 9) & 0x0f] + s0);
-
 
839
      T2 = Sigma0_512 (a) + Maj (a, b, c);
-
 
840
 
-
 
841
      // update registers
150
// imported function prototypes
842
      h = g; g = f; f = e; e = d + T1; d = c; c = b; b = a; a = T1 + T2;
-
 
843
   }
-
 
844
 
-
 
845
   // compute the current intermediate hash value
-
 
846
   context->state[0] += a; context->state[1] += b; context->state[2] += c; context->state[3] += d; context->state[4] += e; context->state[5] += f; context->state[6] += g; context->state[7] += h;
151
extern int dump_ifs_info (const char *ifs_pathname, bool want_everything); // [implemented in ifsdump.c] dumps detailed info about a particular IFS file on the standard output, returns 0 on success and >0 on error
847
 
-
 
848
   // clean up
-
 
849
   a = b = c = d = e = f = g = h = T1 = T2 = 0;
-
 
850
   #undef sigma1_512
-
 
851
   #undef sigma0_512
-
 
852
   #undef Sigma1_512
-
 
853
   #undef Sigma0_512
-
 
854
   #undef Maj
-
 
855
   #undef Ch
-
 
856
   #undef S64
-
 
857
   return;
-
 
858
}
-
 
859
 
-
 
860
 
-
 
861
static void SHA512_Init (SHA512_CTX *context)
-
 
862
{
-
 
863
   // initial hash value H for SHA-512
-
 
864
   static const uint64_t sha512_initial_hash_value[8] = {
-
 
865
      0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, 0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL, 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL, 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL
-
 
866
   };
-
 
867
 
-
 
868
   memcpy (context->state, sha512_initial_hash_value, SHA512_DIGEST_LENGTH);
-
 
869
   memset (context->buffer, 0, SHA512_BLOCK_LENGTH);
-
 
870
   context->bitcount[0] = context->bitcount[1] = 0;
-
 
871
}
-
 
872
 
-
 
873
 
-
 
874
void SHA512_Update (SHA512_CTX *context, void *datain, size_t len)
-
 
875
{
-
 
876
   #define ADDINC128(w,n) do { \
-
 
877
           (w)[0] += (uint64_t) (n); \
-
 
878
           if ((w)[0] < (n)) \
-
 
879
                   (w)[1]++; \
-
 
880
   } while (0) // macro for incrementally adding the unsigned 64-bit integer n to the unsigned 128-bit integer (represented using a two-element array of 64-bit words
152
extern int dump_ifs_contents (const char *ifs_pathname, const char *outdir); // [implemented in ifsdump.c] dumps the IFS filesystem contents in outdir, returns 0 on success and >0 on error
881
 
-
 
882
   size_t freespace, usedspace;
-
 
883
   const uint8_t *data = (const uint8_t *) datain;
-
 
884
 
-
 
885
   if (len == 0)
-
 
886
      return; // calling with empty data is valid - we do nothing
-
 
887
 
-
 
888
   usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH;
-
 
889
   if (usedspace > 0)
-
 
890
   {
-
 
891
      // calculate how much free space is available in the buffer
-
 
892
      freespace = SHA512_BLOCK_LENGTH - usedspace;
-
 
893
 
-
 
894
      if (len >= freespace)
-
 
895
      {
-
 
896
         // fill the buffer completely and process it
-
 
897
         memcpy (&context->buffer[usedspace], data, freespace);
-
 
898
         ADDINC128 (context->bitcount, freespace << 3);
-
 
899
         len -= freespace;
-
 
900
         data += freespace;
-
 
901
         sha512_private_transform (context, (uint64_t *) context->buffer);
-
 
902
      }
-
 
903
      else
-
 
904
      {
-
 
905
         // the buffer is not full yet
-
 
906
         memcpy (&context->buffer[usedspace], data, len);
-
 
907
         ADDINC128 (context->bitcount, len << 3);
-
 
908
 
-
 
909
         // clean up
-
 
910
         usedspace = freespace = 0;
-
 
911
         return;
-
 
912
      }
-
 
913
   }
-
 
914
 
-
 
915
   while (len >= SHA512_BLOCK_LENGTH)
-
 
916
   {
-
 
917
      // process as many complete blocks as we can
-
 
918
      sha512_private_transform (context, (uint64_t *) data);
-
 
919
      ADDINC128 (context->bitcount, SHA512_BLOCK_LENGTH << 3);
-
 
920
      len -= SHA512_BLOCK_LENGTH;
-
 
921
      data += SHA512_BLOCK_LENGTH;
-
 
922
   }
-
 
923
 
-
 
924
   if (len > 0)
-
 
925
   {
-
 
926
      // save leftovers
-
 
927
      memcpy (context->buffer, data, len);
-
 
928
      ADDINC128 (context->bitcount, len << 3);
-
 
929
   }
-
 
930
 
-
 
931
   // clean up
-
 
932
   usedspace = freespace = 0;
-
 
933
   #undef ADDINC128
-
 
934
   return;
-
 
935
}
-
 
936
 
-
 
937
 
-
 
938
static void SHA512_Final (uint8_t digest[SHA512_DIGEST_LENGTH], SHA512_CTX *context)
-
 
939
{
-
 
940
   #define SHA512_SHORT_BLOCK_LENGTH (SHA512_BLOCK_LENGTH - 16)
-
 
941
 
-
 
942
   size_t usedspace;
-
 
943
   union { uint8_t *as_bytes; uint64_t *as_uint64s; } cast_var = { NULL };
-
 
944
 
-
 
945
   // if no digest buffer is passed, don't bother finalizing the computation
-
 
946
   if (digest != NULL)
-
 
947
   {
-
 
948
      usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH;
-
 
949
 
-
 
950
#if __BYTE_ORDER__ ==  __ORDER_LITTLE_ENDIAN__
-
 
951
      context->bitcount[0] = __builtin_bswap64 (context->bitcount[0]); // convert from host byte order
-
 
952
      context->bitcount[1] = __builtin_bswap64 (context->bitcount[1]); // convert from host byte order
-
 
953
#endif // __BYTE_ORDER__ ==  __ORDER_LITTLE_ENDIAN__
-
 
954
 
-
 
955
      if (usedspace > 0)
-
 
956
      {
-
 
957
         // begin padding with a 1 bit
-
 
958
         context->buffer[usedspace++] = 0x80;
-
 
959
 
-
 
960
         if (usedspace <= SHA512_SHORT_BLOCK_LENGTH)
-
 
961
            memset (&context->buffer[usedspace], 0, SHA512_SHORT_BLOCK_LENGTH - usedspace); // set-up for the last transform
-
 
962
         else
-
 
963
         {
-
 
964
            if (usedspace < SHA512_BLOCK_LENGTH)
-
 
965
               memset (&context->buffer[usedspace], 0, SHA512_BLOCK_LENGTH - usedspace);
-
 
966
 
-
 
967
            sha512_private_transform (context, (uint64_t *) context->buffer); // do second-to-last transform
-
 
968
            memset (context->buffer, 0, SHA512_BLOCK_LENGTH - 2); // and set-up for the last transform
-
 
969
         }
-
 
970
      }
-
 
971
      else // usedspace == 0
-
 
972
      {
-
 
973
         memset (context->buffer, 0, SHA512_SHORT_BLOCK_LENGTH); // prepare for final transform
-
 
974
         *context->buffer = 0x80; // begin padding with a 1 bit
-
 
975
      }
-
 
976
 
-
 
977
      // store the length of input data (in bits)
-
 
978
      cast_var.as_bytes = context->buffer;
-
 
979
      cast_var.as_uint64s[SHA512_SHORT_BLOCK_LENGTH / 8 + 0] = context->bitcount[1];
-
 
980
      cast_var.as_uint64s[SHA512_SHORT_BLOCK_LENGTH / 8 + 1] = context->bitcount[0];
-
 
981
 
-
 
982
      // final transform
-
 
983
      sha512_private_transform (context, (uint64_t *) context->buffer);
-
 
984
 
-
 
985
      // save the hash data for output
-
 
986
#if __BYTE_ORDER__ ==  __ORDER_LITTLE_ENDIAN__
-
 
987
      for (int j = 0; j < 8; j++)
-
 
988
         context->state[j] = __builtin_bswap64 (context->state[j]); // convert to host byte order
-
 
989
#endif // __BYTE_ORDER__ ==  __ORDER_LITTLE_ENDIAN__
-
 
990
      memcpy (digest, context->state, SHA512_DIGEST_LENGTH);
-
 
991
   }
-
 
992
 
-
 
993
   // zero out state data
-
 
994
   memset (context, 0, sizeof (SHA512_CTX));
-
 
995
   #undef SHA512_SHORT_BLOCK_LENGTH
-
 
996
   return;
-
 
997
}
-
 
998
 
-
 
999
 
-
 
1000
static uint8_t *SHA512 (void *data, size_t data_len, uint8_t *digest_or_NULL)
-
 
1001
{
-
 
1002
   // computes the SHA-512 hash of a block of data in one pass and write it to digest, or to a static buffer if NULL
153
extern int dump_file_hex (const char *pathname); // [implemented in ifsdump.c] dumps the contents of pathname to stdout in mixed hexadecimal + ASCII (hex editor) format
1003
   // returns the STRING REPRESENTATION of digest in a statically-allocated string
-
 
1004
 
-
 
1005
   static thread_local uint8_t static_digest[SHA512_DIGEST_LENGTH] = "";
-
 
1006
   static thread_local char digest_as_string[2 * SHA512_DIGEST_LENGTH + 1] = "";
-
 
1007
 
-
 
1008
   SHA512_CTX ctx;
-
 
1009
   size_t byte_index;
-
 
1010
 
-
 
1011
   SHA512_Init (&ctx);
-
 
1012
   SHA512_Update (&ctx, data, data_len);
-
 
1013
   if (digest_or_NULL == NULL)
-
 
1014
      digest_or_NULL = static_digest;
-
 
1015
   SHA512_Final (digest_or_NULL, &ctx);
-
 
1016
 
-
 
1017
   for (byte_index = 0; byte_index < SHA512_DIGEST_LENGTH; byte_index++)
-
 
1018
      sprintf (&digest_as_string[2 * byte_index], "%02x", digest_or_NULL[byte_index]);
-
 
1019
   return (digest_as_string);
-
 
1020
}
-
 
1021
 
154
 
1022
 
155
 
1023
static int32_t update_checksum (const void *data, const size_t data_len, const bool is_foreign_endianness)
156
int32_t update_checksum (const void *data, const size_t data_len, const bool is_foreign_endianness)
1024
{
157
{
1025
   // 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
158
   // 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
1026
 
159
 
1027
   uint8_t accumulator[4] = { 0, 0, 0, 0 };
160
   uint8_t accumulator[4] = { 0, 0, 0, 0 };
1028
   const char *current_char_ptr;
161
   const char *current_char_ptr;
Line 1061... Line 194...
1061
   }
194
   }
1062
   return (ret);
195
   return (ret);
1063
}
196
}
1064
 
197
 
1065
 
198
 
1066
static void hex_fprintf (FILE *fp, const uint8_t *data, size_t data_size, int howmany_columns, const char *fmt, ...)
199
static char *resolve_pathname (const char *pathname, const char *search_path)
1067
{
200
{
1068
   // this function logs hexadecimal data to an opened file pointer (or to stdout/stderr)
201
   // locates pathname among search path and returns resolved pathname (static buffer) or NULL.
1069
 
202
 
1070
   va_list argptr;
203
   static thread_local char *resolved_pathname = NULL;
1071
   size_t index;
-
 
1072
   int i;
-
 
1073
 
204
 
1074
   // concatenate all the arguments in one string and write it to the file
-
 
1075
   va_start (argptr, fmt);
205
   struct stat stat_buf;
1076
   vfprintf (fp, fmt, argptr);
206
   const char *nextsep;
1077
   va_end (argptr);
207
   const char *token;
1078
 
208
 
1079
   // for each row of howmany_columns bytes of data...
209
   // initial allocation (per thread)
1080
   for (index = 0; index < data_size; index += howmany_columns)
210
   if (resolved_pathname == NULL)
1081
   {
211
   {
1082
      fprintf (fp, "    %05zu  ", index); // print array address of row
-
 
1083
      for (i = 0; i < howmany_columns; i++)
212
      resolved_pathname = malloc (MAXPATHLEN);
1084
         if (index + i < data_size)
213
      ASSERT_WITH_ERRNO (resolved_pathname);
1085
            fprintf (fp, " %02X", data[index + i]); // if row contains data, print data as hex bytes
-
 
1086
         else
-
 
1087
            fprintf (fp, "   "); // else fill the space with blanks
-
 
1088
      fprintf (fp, "   ");
-
 
1089
      for (i = 0; i < howmany_columns; i++)
-
 
1090
         if (index + i < data_size)
-
 
1091
            fputc ((data[index + i] >= 32) && (data[index + i] < 127) ? data[index + i] : '.', fp); // now if row contains data, print data as ASCII
-
 
1092
         else
-
 
1093
            fputc (' ', fp); // else fill the space with blanks
-
 
1094
      fputc ('\n', fp);
-
 
1095
   }
214
   }
1096
 
-
 
1097
   return; // and return
-
 
1098
}
-
 
1099
 
-
 
1100
 
-
 
1101
static char *binary (const uint8_t x, char char_for_zero, char char_for_one)
-
 
1102
{
-
 
1103
   // returns the binary representation of x as a string
-
 
1104
 
-
 
1105
   static thread_local char outstr[9] = "00000000";
-
 
1106
   for (int i = 0; i < 8; i++)
-
 
1107
      outstr[i] = (x & (0x80 >> i) ? char_for_one : char_for_zero);
-
 
1108
   return (outstr);
-
 
1109
}
-
 
1110
 
-
 
1111
 
-
 
1112
static char *describe_uint8 (const uint8_t x, const char *bitwise_stringdescs[8])
-
 
1113
{
-
 
1114
   // returns the ORed description of byte 'x' according to the description strings for each bit
-
 
1115
 
-
 
1116
   static thread_local char *default_bitstrings[8] = { "bit0", "bit1", "bit2", "bit3", "bit4", "bit5", "bit6", "bit7" };
-
 
1117
   static thread_local char outstr[8 * 64] = "";
-
 
1118
 
-
 
1119
   outstr[0] = 0;
-
 
1120
   for (int i = 0; i < 8; i++)
-
 
1121
      if (x & (1 << i))
-
 
1122
      {
-
 
1123
         if (outstr[0] != 0)
-
 
1124
            strcat (outstr, "|");
-
 
1125
         strcat (outstr, ((bitwise_stringdescs != NULL) && (*bitwise_stringdescs[i] != 0) ? bitwise_stringdescs[i] : default_bitstrings[i]));
-
 
1126
      }
-
 
1127
   return (outstr);
-
 
1128
}
-
 
1129
 
-
 
1130
 
-
 
1131
static char *read_filecontents (const char *pathname, const char *search_path, buffer_t *outbuf)
-
 
1132
{
-
 
1133
   // locates pathname among MKIFS_PATH, and places its contents in a buffer (caller frees). Returns resolved pathname (static buffer) or NULL.
-
 
1134
 
-
 
1135
   static thread_local char resolved_pathname[MAXPATHLEN];
-
 
1136
 
-
 
1137
   const char *nextsep;
-
 
1138
   const char *token;
-
 
1139
   FILE *fp;
-
 
1140
 
215
 
1141
   // is it an absolute pathname (POSIX and Windows variants) ?
216
   // is it an absolute pathname (POSIX and Windows variants) ?
1142
   if (IS_DIRSEP (pathname[0]) || (isalpha (pathname[0]) && (pathname[1] == ':') && IS_DIRSEP (pathname[2])))
217
   if (IS_DIRSEP (pathname[0]) || (isalpha (pathname[0]) && (pathname[1] == ':') && IS_DIRSEP (pathname[2])))
1143
      strcpy (resolved_pathname, pathname); // in this case, it MUST exist at its designated location (either absolute or relative to the current working directory)
218
      strcpy_s (resolved_pathname, MAXPATHLEN, pathname); // in this case, it MUST exist at its designated location (either absolute or relative to the current working directory)
1144
   else // the path is relative, search it among the search paths we have
219
   else // the path is relative, search it among the search paths we have
1145
   {
220
   {
1146
      // construct a potential final path using each element of the search path
221
      // construct a potential final path using each element of the search path
1147
      token = (*search_path != 0 ? search_path : NULL);
222
      token = (*search_path != 0 ? search_path : NULL);
1148
      nextsep = (token != NULL ? &token[strcspn (token, PATH_SEP_STR)] : NULL);
223
      nextsep = (token != NULL ? &token[strcspn (token, PATH_SEP)] : NULL);
1149
      while (token != NULL)
224
      while (token != NULL)
1150
      {
225
      {
1151
         sprintf (resolved_pathname, "%.*s/%s", (int) (nextsep - token), token, pathname);
226
         sprintf_s (resolved_pathname, MAXPATHLEN, "%.*s/%s", (int) (nextsep - token), token, pathname);
1152
         if (access (resolved_pathname, 0) == 0)
227
         if ((stat (resolved_pathname, &stat_buf) == 0) && S_ISREG (stat_buf.st_mode))
1153
            break; // if a file can indeed be found at this location, stop searching
228
            return (resolved_pathname); // if a file can indeed be found at this location, stop searching
1154
 
229
 
1155
         token = (*nextsep != 0 ? nextsep + 1 : NULL);
230
         token = (*nextsep != 0 ? nextsep + 1 : NULL);
1156
         nextsep = (token != NULL ? &token[strcspn (token, PATH_SEP_STR)] : NULL);
231
         nextsep = (token != NULL ? &token[strcspn (token, PATH_SEP)] : NULL);
1157
      }
-
 
1158
 
-
 
1159
      // have we exhausted all possibilities ?
-
 
1160
      if (token == NULL)
-
 
1161
      {
-
 
1162
         errno = ENOENT;
-
 
1163
         return (NULL); // file not found, return with ENOENT
-
 
1164
      }
232
      }
1165
   }
233
   }
1166
 
234
 
1167
   // now open and read the file
235
   errno = ENOENT; // we exhausted all possibilities
1168
   fp = fopen (resolved_pathname, "rb");
-
 
1169
   if (fp == NULL)
-
 
1170
      return (NULL); // unexistent file (errno is set to ENOENT)
236
   return (NULL); // file not found, return with ENOENT
-
 
237
}
1171
 
238
 
-
 
239
 
-
 
240
static size_t Buffer_WriteIFSDirectoryEntryAt (buffer_t *ifs, const size_t write_offset, const fsentry_t *fsentry)
-
 
241
{
-
 
242
   // writes a directory entry in the image filesystem buffer pointed to by ifs at write_offset (or fakes so if ifs is NULL)
1172
   // if we don't want its contents, close it and return the resolved pathname
243
   // and return the number of bytes written (or that would have been written)
-
 
244
 
-
 
245
   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";
-
 
246
 
-
 
247
   size_t datalen;
-
 
248
   size_t count;
-
 
249
 
-
 
250
   count = 0;
1173
   if (outbuf == NULL)
251
   if (ifs != NULL)
-
 
252
      ASSERT_WITH_ERRNO (Buffer_WriteAt (ifs, write_offset + count, &fsentry->header, sizeof (fsentry->header))); // write the entry header (PACKED STRUCT)
-
 
253
   count += sizeof (fsentry->header);
-
 
254
   if (S_ISREG (fsentry->header.mode))
1174
   {
255
   {
-
 
256
      if (ifs != NULL)
-
 
257
         ASSERT_WITH_ERRNO (Buffer_WriteAt (ifs, write_offset + count, &fsentry->u.file.offset, sizeof (uint32_t))); // write offset
-
 
258
      count += sizeof (uint32_t);
1175
      fclose (fp);
259
      if (ifs != NULL)
-
 
260
         ASSERT_WITH_ERRNO (Buffer_WriteAt (ifs, write_offset + count, &fsentry->u.file.size,   sizeof (uint32_t))); // write size
1176
      return (resolved_pathname);
261
      count += sizeof (uint32_t);
-
 
262
      datalen = strlen (fsentry->u.file.path) + 1;
-
 
263
      if (ifs != NULL)
-
 
264
         ASSERT_WITH_ERRNO (Buffer_WriteAt (ifs, write_offset + count, fsentry->u.file.path, datalen)); // write null-terminated path (no leading slash)
-
 
265
      count += datalen;
1177
   }
266
   }
1178
 
-
 
1179
   // the user supplied a data buffer: read the file contents
-
 
1180
   fseek (fp, 0, SEEK_END);
-
 
1181
   outbuf->len = ftell (fp); // measure file length
-
 
1182
   fseek (fp, 0, SEEK_SET);
-
 
1183
   outbuf->bytes = malloc (outbuf->len);
-
 
1184
   if (outbuf->bytes == NULL)
267
   else if (S_ISDIR (fsentry->header.mode))
1185
   {
268
   {
1186
      fclose (fp);
269
      datalen = strlen (fsentry->u.dir.path) + 1;
1187
      outbuf->len = 0;
270
      if (ifs != NULL)
-
 
271
         ASSERT_WITH_ERRNO (Buffer_WriteAt (ifs, write_offset + count, fsentry->u.dir.path, datalen)); // write null-terminated path (no leading slash)
1188
      return (NULL); // out of memory (errno is set to ENOMEM)
272
      count += datalen;
1189
   }
273
   }
1190
   if (fread (outbuf->bytes, 1, outbuf->len, fp) != outbuf->len) // read the file in whole
274
   else if (S_ISLNK (fsentry->header.mode))
1191
   {
275
   {
-
 
276
      if (ifs != NULL)
-
 
277
         ASSERT_WITH_ERRNO (Buffer_WriteAt (ifs, write_offset + count, &fsentry->u.symlink.sym_offset, sizeof (uint16_t))); // write offset
-
 
278
      count += sizeof (uint16_t);
1192
      fclose (fp);
279
      if (ifs != NULL)
-
 
280
         ASSERT_WITH_ERRNO (Buffer_WriteAt (ifs, write_offset + count, &fsentry->u.symlink.sym_size,   sizeof (uint16_t))); // write size
-
 
281
      count += sizeof (uint16_t);
-
 
282
      datalen = strlen (fsentry->u.symlink.path) + 1;
-
 
283
      if (ifs != NULL)
-
 
284
         ASSERT_WITH_ERRNO (Buffer_WriteAt (ifs, write_offset + count, fsentry->u.symlink.path, datalen)); // write null-terminated path (no leading slash)
-
 
285
      count += datalen;
-
 
286
      datalen = strlen (fsentry->u.symlink.contents) + 1;
-
 
287
      if (ifs != NULL)
-
 
288
         ASSERT_WITH_ERRNO (Buffer_WriteAt (ifs, write_offset + count, fsentry->u.symlink.contents, datalen)); // write null-terminated symlink contents
1193
      outbuf->len = 0;
289
      count += datalen;
-
 
290
   }
-
 
291
   else
-
 
292
   {
-
 
293
      if (ifs != NULL)
-
 
294
         ASSERT_WITH_ERRNO (Buffer_WriteAt (ifs, write_offset + count, &fsentry->u.device.dev,  sizeof (uint32_t))); // write dev number
-
 
295
      count += sizeof (uint32_t);
-
 
296
      if (ifs != NULL)
-
 
297
         ASSERT_WITH_ERRNO (Buffer_WriteAt (ifs, write_offset + count, &fsentry->u.device.rdev, sizeof (uint32_t))); // write rdev number
-
 
298
      count += sizeof (uint32_t);
1194
      return (NULL); // short read (errno is set)
299
      datalen = strlen (fsentry->u.device.path) + 1;
-
 
300
      if (ifs != NULL)
-
 
301
         ASSERT_WITH_ERRNO (Buffer_WriteAt (ifs, write_offset + count, fsentry->u.device.path, datalen)); // write null-terminated path (no leading slash)
-
 
302
      count += datalen;
1195
   }
303
   }
1196
   fclose (fp); // close the file
-
 
1197
 
304
 
1198
   return (resolved_pathname); // file was read successfully and its content put in databuf with size datalen
305
   ASSERT (count <= fsentry->header.size, "attempt to write invalid dirent (claimed size %zd, written size %zd). Aborting.", (size_t) fsentry->header.size, count);
-
 
306
   if (count < fsentry->header.size)
-
 
307
   {
-
 
308
      if (ifs != NULL)
-
 
309
         ASSERT_WITH_ERRNO (Buffer_WriteAt (ifs, write_offset + count, zeropad_buffer, fsentry->header.size - count)); // pad as necessary
-
 
310
      count += fsentry->header.size - count;
-
 
311
   }
-
 
312
 
-
 
313
   return (count);
1199
}
314
}
1200
 
315
 
1201
 
316
 
1202
static int fwrite_filecontents (const char *pathname, FILE *fp)
317
static size_t Buffer_AppendIFSFileData (buffer_t *ifs_data, fsentry_t *fsentry)
1203
{
318
{
1204
   // dumps the binary contents of pathname to fp
319
   // writes the given filesystem entry's file data (i.e. its contents) to the IFS buffer
1205
 
320
 
-
 
321
   elf_program_header_t *phdr;
-
 
322
   elf_header_t *elf;
1206
   uint8_t *blob_buffer;
323
   size_t corrective_offset;
-
 
324
   //size_t segment_type;
1207
   size_t blob_size;
325
   size_t segment_size;
-
 
326
   size_t table_index;
1208
   FILE *blob_fp;
327
   size_t table_count;
1209
   int ret;
328
   size_t data_offset;
1210
 
329
 
1211
   blob_fp = fopen (pathname, "rb");
330
   ASSERT (S_ISREG (fsentry->header.mode), "function called for invalid dirent"); // consistency check
1212
   if (blob_fp == NULL)
-
 
1213
      return (-1); // errno is set
331
   data_offset = ifs_data->size; // see where we are
1214
 
332
 
-
 
333
   // is the file we're storing a preprocessed ELF file ?
1215
   fseek (blob_fp, 0, SEEK_END);
334
   if ((fsentry->header.ino & IFS_INO_PROCESSED_ELF)
1216
   blob_size = ftell (blob_fp);
335
#ifndef PROCNTO_WIP
1217
   blob_buffer = malloc (blob_size);
336
      && (strstr (fsentry->u.file.path, "/procnto-smp-instr") == NULL)
1218
   if (blob_buffer == NULL)
337
#endif // !PROCNTO_WIP
-
 
338
       )
1219
   {
339
   {
1220
      fclose (blob_fp);
-
 
1221
      return (-1); // errno is set to ENOMEM
-
 
1222
   }
-
 
1223
   fseek (blob_fp, 0, SEEK_SET);
-
 
1224
   fread (blob_buffer, 1, blob_size, blob_fp);
-
 
1225
   fclose (blob_fp);
-
 
1226
 
340
 
1227
   ret = (int) fwrite (blob_buffer, 1, blob_size, fp);
341
      elf = (elf_header_t *) fsentry->u.file.UNSAVED_databuf; // quick access to ELF header
1228
   fflush (fp); // force flush to disk, because the C stream API is *buffered*
342
      table_count = ELF_GET_NUMERIC (elf, elf, program_header_table_len); // get the number of program headers
1229
   free (blob_buffer);
343
      for (table_index = 0; table_index < table_count; table_index++)
1230
   return (ret);
344
      {
1231
}
-
 
-
 
345
         phdr = (elf_program_header_t *) &fsentry->u.file.UNSAVED_databuf[ELF_GET_NUMERIC (elf, elf, program_header_table_offset) + (size_t) ELF_GET_NUMERIC (elf, elf, program_header_item_size) * table_index]; // quick access to program header
-
 
346
         //segment_type = ELF_GET_NUMERIC (elf, phdr, segment_type); // get segment type
-
 
347
         //if (!((segment_type >= 2) && (segment_type <= 7) || ((segment_type >= 0x6474e550) && (segment_type <= 0x6474e552)) || (segment_type == 0x70000001)))
-
 
348
         //   continue; // NOTE: only certain segments types must be corrected
1232
 
349
 
1233
 
350
 
1234
static int relative_offset_of_in (const char *name, const buffer_t *stringbuf)
351
         corrective_offset = ELF_GET_NUMERIC (elf, phdr, virtual_addr) - ELF_GET_NUMERIC (elf, phdr, file_offset);
1235
{
-
 
1236
   int name_len = (int) strlen (name) + 1;
-
 
1237
   WELLMANNERED_ASSERT (name_len < stringbuf->len, "bad call (name longer than string table)");
352
         segment_size = ELF_GET_NUMERIC (elf, phdr, size_in_memory); // get this ELF segment's occupied size in memory
1238
   for (int idx = 0; idx <= stringbuf->len - name_len; idx++)
353
         if (segment_size != 0) // only patch the physical address of segments that have an actual size in memory
1239
      if (memcmp (&stringbuf->bytes[idx], name, name_len) == 0)
354
            ELF_SET_NUMERIC (elf, phdr, physical_addr, ELF_GET_NUMERIC (elf, phdr, physical_addr) + image_base + data_offset - corrective_offset); // patch the physical address member of the program header table (NOTE: data_offset is the location where the file data is about to be written)
1240
         return (idx);
355
      }
-
 
356
   }
-
 
357
 
1241
   WELLMANNERED_ASSERT (false, "bad call (name '%s' not found in string table)", name);
358
   ASSERT_WITH_ERRNO (Buffer_Append (ifs_data, fsentry->u.file.UNSAVED_databuf, fsentry->u.file.size)); // write file data blob
1242
   return (0);
359
   return (ifs_data->size - data_offset); // return the number of bytes written
1243
}
360
}
1244
 
361
 
1245
 
362
 
1246
static elf_section_header_t *elf_get_section_header_by_name (const elf_header_t *elf, const char *section_name)
363
static inline size_t Buffer_LocateOrAppendIfNecessaryAndReturnOffsetOf (buffer_t *buffer, const char *str)
1247
{
364
{
1248
   elf_section_header_t *shdr_shstrtab; // section header of the section header strings table
365
   // helper function used in add_fsentry(): locates or appends str to buffer and returns its relative offset in the buffer
1249
   elf_section_header_t *shdr;
-
 
1250
   size_t table_count;
-
 
1251
   size_t table_index;
-
 
1252
   char *shstrtab; // section header strings table
-
 
1253
   char *name;
-
 
1254
 
366
 
1255
   shdr_shstrtab = (elf_section_header_t *) ((uint8_t *) elf + ELF_GET_NUMERIC (elf, elf, section_header_table_offset) + (size_t) ELF_GET_NUMERIC (elf, elf, section_header_item_size) * ELF_GET_NUMERIC (elf, elf, section_header_names_idx)); // quick access to section header for the section that contains the section names
367
   size_t str_len_including_terminator = strlen (str) + 1;
1256
   shstrtab = ((uint8_t *) elf + ELF_GET_NUMERIC (elf, shdr_shstrtab, file_offset)); // locate the start of the strings table that contains the section names
368
   void *occurrence = Buffer_FindFirst (buffer, str, str_len_including_terminator);
1257
 
-
 
1258
   // cycle through the sections table
369
   if (occurrence == NULL)
1259
   table_count = ELF_GET_NUMERIC (elf, elf, section_header_table_len);
-
 
1260
   for (table_index = 0; table_index < table_count; table_index++)
-
 
1261
   {
370
   {
1262
      shdr = (elf_section_header_t *) ((uint8_t *) elf + ELF_GET_NUMERIC (elf, elf, section_header_table_offset) + (size_t) ELF_GET_NUMERIC (elf, elf, section_header_item_size) * table_index); // quick access to section header
371
      ASSERT_WITH_ERRNO (Buffer_Append (buffer, str, str_len_including_terminator));
1263
      name = &shstrtab[ELF_GET_NUMERIC (elf, shdr, name_offset)]; // peek at its name
372
      occurrence = Buffer_FindFirst (buffer, str, str_len_including_terminator);
1264
      if (strcmp (name, section_name) == 0)
373
      ASSERT_WITH_ERRNO (occurrence);
1265
         return (shdr); // if found, return a pointer to this section header
-
 
1266
   }
374
   }
1267
 
-
 
1268
   return (NULL); // section not found
375
   return (Buffer_OffsetOf (buffer, occurrence)); // can't fail
1269
}
376
}
1270
 
377
 
1271
 
378
 
1272
static size_t fwrite_fsentry (const fsentry_t *fsentry, FILE *fp)
379
static int Buffer_StripELFFile (buffer_t *file, const char *indicative_pathname)
1273
{
380
{
-
 
381
   // NOTE: for each ELF file, mkifs
-
 
382
   // -> alters the program header table and offsets each p_addr (physical address) member by <image_base> plus the current file offset (this cannot be done right now, will need to be done once they are known)
1274
   // writes a directory entry in the image filesystem file pointed to by fp (or fakes so if fp is NULL)
383
   // -> throws away and reconstructs the sections table by keeping only the sections that are in the program header, and writes the section table at the start of the first thrown-away section
1275
   // and return the number of bytes written (or that would have been written)
384
   // FIXME: what if a thrown away section is located between two program segments ? are they collapsed, moving the segments beyond it one slot down ?
1276
 
385
 
-
 
386
   // reconstructed ELF:
-
 
387
   // ==== START OF FILE ====
-
 
388
   // ELF header
-
 
389
   // program header table
-
 
390
   //  (same sections, just p_addr offset changed)
-
 
391
   // section data 5 (named ".note.gnu.build-id")
-
 
392
   //  "............GNU....ZY.....c.o..l"
-
 
393
   // PROGRAM
-
 
394
   // sections table
-
 
395
   // + section 1: ALL ZEROES
1277
   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";
396
   // + section 2: fileoffs 0x21a8 size 0xfd --> "QNX_info" --> QNX binary description: "NAME=pci_debug2.so.3.0\nDESCRIPTION=PCI Server System Debug Module\nDATE=2023/11/19-10:01:13-EST\nSTATE=lookup\nHOST=docker-n1.bts.rim.net\nUSER=builder\nVERSION=QNXOS_main\nTAGID=QNXOS_800-135\nPACKAGE=com.qnx.qnx800.target.pci.debug/3.0.0.00135T202311191043L\n"
-
 
397
   // + section 3: fileoffs 0x22a5 size 0x1c --> ".gnu_debuglink" --> indicates the debug file and its checksum: "pci_debug2.so.3.0.sym" "\0\0\0" "VX2p"
-
 
398
   // + section 4: fileoffs 0x22c1 size 0x2ad --> "QNX_usage" --> HELP TEXT: "\n-------------------------------------------------------------------------------\n%C\n\nThis module implements debug logging for all PCI server modules. It is\nincluded by setting the environment variable PCI_DEBUG_MODULE and uses\nthe slogger2 APIs.\nNOTE:.On systems which support slogger2, you are encouraged to use this module.instead of pci_debug.so...Release History.---------------..3.0 - This module is functionally equivalent to the previous 2.x version.      however it is incompatible with all pre v3.x PCI components..2.1 - fixes a bug whereby if slogger2 is not running and the PCI_DEBUG_MODULE.      environment variable is set, the client will SIGSEGV..2.0 - initial release.."
-
 
399
   // + section 5: fileoffs 0x190 size 0x32 --> ".note.gnu.build-id" --> GNU build ID
-
 
400
   // + section 6: fileoffs 0x256e size 0x40 --> ".shstrtab" --> sections names strings table
-
 
401
   // section data 2 (named "QNX_info")
-
 
402
   //  (QNX binary description)
-
 
403
   // section data 3 (named ".gnu_debuglink")
-
 
404
   //  (debug file)
-
 
405
   // section data 4 (named "QNX_usage")
-
 
406
   //  (help text)
-
 
407
   // section data 6 (named ".shstrtab")
-
 
408
   //  "\0"
-
 
409
   //  ".shstrtab\0"
-
 
410
   //  "QNX_info\0"
-
 
411
   //  ".gnu_debuglink\0"
-
 
412
   //  "QNX_usage\0"
-
 
413
   //  ".note.gnu.build-id\0"
-
 
414
   // ==== END OF FILE ====
1278
 
415
 
-
 
416
   #define ELFHDR ((elf_header_t *) file->bytes) // this convenient definition will make sure the ELF header points at the right location, even after entry_parms.data->byte is reallocated
-
 
417
   #define ADD_SECTION(section_name,section_ptr) do { \
-
 
418
      void *reallocated_ptr = realloc (elf_sections, (elf_section_count + 1) * sizeof (elf_section_t)); \
-
 
419
      ASSERT_WITH_ERRNO (reallocated_ptr); \
-
 
420
      elf_sections = reallocated_ptr; \
-
 
421
      elf_sections[elf_section_count].name = (section_name); \
-
 
422
      Buffer_Initialize (&elf_sections[elf_section_count].data); \
-
 
423
      *(section_ptr) = &elf_sections[elf_section_count]; \
1279
   size_t datalen;
424
      elf_section_count++; \
1280
   size_t count;
425
   } while (0)
1281
 
426
 
1282
   count = 0;
-
 
1283
   if (fp != NULL)
-
 
1284
      fwrite_or_die (&fsentry->header, 1, sizeof (fsentry->header), fp); // write the entry header (PACKED STRUCT)
-
 
1285
   count += sizeof (fsentry->header);
427
   typedef struct elf_section_s
1286
   if (S_ISREG (fsentry->header.mode))
-
 
1287
   {
428
   {
1288
      if (fp != NULL)
429
      const char *name;
-
 
430
      elf_section_header_t header;
1289
      {
431
      buffer_t data;
-
 
432
   } elf_section_t;
-
 
433
 
1290
         fwrite_or_die (&fsentry->u.file.offset, 1, sizeof (uint32_t), fp); // write offset
434
   static const char *saved_sections[] = { "QNX_info", ".gnu_debuglink", "QNX_usage", ".note.gnu.build-id" };
-
 
435
 
-
 
436
   const elf_program_header_t *phdr;
-
 
437
   const elf_section_header_t *shdr;
1291
         fwrite_or_die (&fsentry->u.file.size,   1, sizeof (uint32_t), fp); // write size
438
   elf_section_t *elf_sections = NULL; // mallocated
-
 
439
   elf_section_t *elf_section = NULL;
1292
      }
440
   size_t elf_section_count = 0;
1293
      count += 2 * sizeof (uint32_t);
441
   size_t new_shdrtable_offset;
-
 
442
   size_t sectiondata_start;
1294
      datalen = strlen (fsentry->u.file.path) + 1;
443
   size_t sectiondata_size;
-
 
444
   size_t array_index;
-
 
445
   size_t table_index;
-
 
446
   size_t table_count;
1295
      if (fp != NULL)
447
   size_t page_size;
-
 
448
 
-
 
449
   // find out the platform page size
-
 
450
   if (ELF_GET_NUMERIC (ELFHDR, ELFHDR, instruction_set) == ELF_MACHINE_X86_64)
-
 
451
      page_size = 4 * 1024; // 4 kb pages on Intel processors
-
 
452
   else if (ELF_GET_NUMERIC (ELFHDR, ELFHDR, instruction_set) == ELF_MACHINE_AARCH64)
-
 
453
      page_size = 16 * 1024; // 16 kb pages on ARM64
-
 
454
   else
-
 
455
   {
1296
         fwrite_or_die (fsentry->u.file.path, 1, (size_t) datalen, fp); // write null-terminated path (no leading slash)
456
      errno = ENOTSUP; // unsupported architecture: set errno to something meaningful
1297
      count += datalen;
457
      return (0); // and return an error value
1298
   }
458
   }
-
 
459
 
-
 
460
   // parse the program header table, and measure the farthest offset known by this table where we'll write the reconstructed section headers table
-
 
461
 
-
 
462
   new_shdrtable_offset = 0;
-
 
463
   table_count = ELF_GET_NUMERIC (ELFHDR, ELFHDR, program_header_table_len);
1299
   else if (S_ISDIR (fsentry->header.mode))
464
   for (table_index = 0; table_index < table_count; table_index++)
1300
   {
465
   {
-
 
466
      phdr = (elf_program_header_t *) &file->bytes[ELF_GET_NUMERIC (ELFHDR, ELFHDR, program_header_table_offset) + (size_t) ELF_GET_NUMERIC (ELFHDR, ELFHDR, program_header_item_size) * table_index]; // quick access to program header
1301
      datalen = strlen (fsentry->u.dir.path) + 1;
467
      if (ELF_GET_NUMERIC (ELFHDR, phdr, file_offset) + ELF_GET_NUMERIC (ELFHDR, phdr, size_in_file) > new_shdrtable_offset)
1302
      if (fp != NULL)
-
 
1303
         fwrite_or_die (fsentry->u.dir.path, 1, (size_t) datalen, fp); // write null-terminated path (no leading slash)
468
         new_shdrtable_offset = ELF_GET_NUMERIC (ELFHDR, phdr, file_offset) + ELF_GET_NUMERIC (ELFHDR, phdr, size_in_file); // keep track of the farthest offset known by the program headers table
1304
      count += datalen;
-
 
1305
   }
469
   }
-
 
470
   /*
1306
   else if (S_ISLNK (fsentry->header.mode))
471
   size_t new_shdrtable_offset_method2 = 0;
-
 
472
   for (table_index = 0; table_index < table_count; table_index++)
1307
   {
473
   {
-
 
474
      phdr = (elf_program_header_t *) &file->bytes[ELF_GET_NUMERIC (ELFHDR, ELFHDR, program_header_table_offset) + (size_t) ELF_GET_NUMERIC (ELFHDR, ELFHDR, program_header_item_size) * table_index]; // quick access to program header
-
 
475
      size_t segment_type = ELF_GET_NUMERIC (ELFHDR, phdr, segment_type); // get segment type
-
 
476
      if (!((segment_type >= 2) && (segment_type <= 7)))
-
 
477
         continue; // NOTE: only certain segments types must be corrected
-
 
478
      if (ELF_GET_NUMERIC (ELFHDR, phdr, file_offset) + ELF_GET_NUMERIC (ELFHDR, phdr, size_in_memory) > new_shdrtable_offset_method2)
-
 
479
         new_shdrtable_offset_method2 = ELF_GET_NUMERIC (ELFHDR, phdr, file_offset) + ELF_GET_NUMERIC (ELFHDR, phdr, size_in_memory);
-
 
480
   }
-
 
481
   if (new_shdrtable_offset_method2 > new_shdrtable_offset)
-
 
482
      LOG_DEBUG ("METHOD2: %llx > %llx", new_shdrtable_offset_method2, new_shdrtable_offset);*/
-
 
483
   //new_shdrtable_offset = ROUND_TO_UPPER_MULTIPLE (new_shdrtable_offset, page_size); // round to page size
-
 
484
 
1308
      if (fp != NULL)
485
   // re-create the section header table
-
 
486
   ADD_SECTION (".shstrtab", &elf_section); // the first section will be the section names strings table
-
 
487
   ASSERT_WITH_ERRNO (Buffer_InitWithByteArray (&elf_section->data, "\0")); // initialize an empty section headers strings table
-
 
488
   ASSERT_WITH_ERRNO (Buffer_AppendByteArray (&elf_section->data, ".shstrtab\0")); // append ".shstrtab" *INCLUDING* its null terminator
-
 
489
 
-
 
490
   // go through the saved sections array and see if such an ELF section is present in the ELF file
-
 
491
   for (array_index = 0; array_index < sizeof (saved_sections) / sizeof (saved_sections[0]); array_index++)
-
 
492
      if ((shdr = elf_get_section_header_by_name (ELFHDR, saved_sections[array_index])) != NULL) // does this ELF have such a section ?
1309
      {
493
      {
-
 
494
         ADD_SECTION (saved_sections[array_index], &elf_section); // yes, so save it
1310
         fwrite_or_die (&fsentry->u.symlink.sym_offset, 1, sizeof (uint16_t), fp); // write offset
495
         sectiondata_start = ELF_GET_NUMERIC (ELFHDR, shdr, file_offset); // identify section data start offset
-
 
496
         sectiondata_size = ELF_GET_NUMERIC (ELFHDR, shdr, size); // identify section data length
-
 
497
         if (sectiondata_start + sectiondata_size >= new_shdrtable_offset) // should this section be moved ?
-
 
498
            ASSERT_WITH_ERRNO (Buffer_InitWithData (&elf_section->data, &file->bytes[sectiondata_start], sectiondata_size)); // have a copy of this section's data
-
 
499
         else
-
 
500
            Buffer_Initialize (&elf_section->data); // this section is located before the place where we'll write the new section headers table, thus it doesn't need to be moved
-
 
501
         //LOG_DEBUG ("%s: section '%s' start 0x%llx len 0x%llx", indicative_pathname, saved_sections[array_index], (unsigned long long) sectiondata_start, (unsigned long long) sectiondata_size);
-
 
502
 
-
 
503
         // prepare this section's "fixed" header
-
 
504
         memcpy (&elf_section->header, shdr, ELF_STRUCT_SIZE (ELFHDR, shdr)); // have a copy of the old section header first
1311
         fwrite_or_die (&fsentry->u.symlink.sym_size,   1, sizeof (uint16_t), fp); // write size
505
         ELF_SET_NUMERIC (ELFHDR, &elf_section->header, name_offset, Buffer_LocateOrAppendIfNecessaryAndReturnOffsetOf (&elf_sections[0].data, elf_section->name)); // make sure this section name is in the ELF sections section header strings table and update the relative offset of the section name
1312
      }
506
      }
1313
      count += 2 * sizeof (uint16_t);
-
 
-
 
507
 
1314
      datalen = strlen (fsentry->u.symlink.path) + 1;
508
   // jump over the new section headers table and write the saved sections data after the section headers table
1315
      if (fp != NULL)
-
 
1316
         fwrite_or_die (fsentry->u.symlink.path, 1, (size_t) datalen, fp); // write null-terminated path (no leading slash)
509
   file->size = new_shdrtable_offset + (1 + elf_section_count) * ELF_STRUCT_SIZE (ELFHDR, &elf_sections[0].header); // start by truncating the ELF file: assume there are no sections beyond the section headers table until known otherwise
1317
      count += datalen;
-
 
1318
      datalen = strlen (fsentry->u.symlink.contents) + 1;
510
   for (table_index = 1; table_index < elf_section_count; table_index++)
1319
      if (fp != NULL)
-
 
1320
         fwrite_or_die (fsentry->u.symlink.contents, 1, (size_t) datalen, fp); // write null-terminated symlink contents
-
 
1321
      count += datalen;
-
 
1322
   }
-
 
1323
   else
-
 
1324
   {
511
   {
-
 
512
      elf_section = &elf_sections[table_index]; // quick access to ELF section about to be written
1325
      if (fp != NULL)
513
      if (elf_section->data.bytes != NULL) // was this section data backed up waiting to be relocated ?
1326
      {
514
      {
1327
         fwrite_or_die (&fsentry->u.device.dev,  1, sizeof (uint32_t), fp); // write dev number
515
         ELF_SET_NUMERIC (ELFHDR, &elf_section->header, file_offset, file->size); // fix section offset
1328
         fwrite_or_die (&fsentry->u.device.rdev, 1, sizeof (uint32_t), fp); // write rdev number
516
         Buffer_AppendBuffer (file, &elf_section->data); // append this section's data to the ELF file
1329
      }
517
      }
1330
      count += 2 * sizeof (uint32_t);
-
 
1331
      datalen = strlen (fsentry->u.device.path) + 1;
-
 
1332
      if (fp != NULL)
-
 
1333
         fwrite_or_die (fsentry->u.device.path, 1, (size_t) datalen, fp); // write null-terminated path (no leading slash)
-
 
1334
      count += datalen;
-
 
1335
   }
518
   }
-
 
519
   // write the section header strings table as the last section
-
 
520
   elf_section = &elf_sections[0]; // quick access to ELF section about to be written
-
 
521
   ELF_SET_NUMERIC (ELFHDR, &elf_section->header, name_offset, Buffer_LocateOrAppendIfNecessaryAndReturnOffsetOf (&elf_sections[0].data, elf_section->name)); // update the relative offset of the section name
-
 
522
   ELF_SET_NUMERIC (ELFHDR, &elf_section->header, type, ELF_SECTIONTYPE_STRINGTABLE); // section type (SHT_STRTAB)
-
 
523
   ELF_SET_NUMERIC (ELFHDR, &elf_section->header, flags, 0); // section flags (we could set SHF_STRINGS i.e. 0x20 here, but mkifs does not, so mimic that)
-
 
524
   ELF_SET_NUMERIC (ELFHDR, &elf_section->header, virtual_addr, 0); // this section does not need to be mapped
-
 
525
   ELF_SET_NUMERIC (ELFHDR, &elf_section->header, file_offset, file->size); // fix section offset
-
 
526
   ELF_SET_NUMERIC (ELFHDR, &elf_section->header, size, elf_sections[0].data.size); // section size
-
 
527
   ELF_SET_NUMERIC (ELFHDR, &elf_section->header, linked_index, 0); // this section is not linked to any other
-
 
528
   ELF_SET_NUMERIC (ELFHDR, &elf_section->header, info, 0); // this section has no additional info
-
 
529
   ELF_SET_NUMERIC (ELFHDR, &elf_section->header, alignment, 1); // this section is byte-aligned
-
 
530
   ELF_SET_NUMERIC (ELFHDR, &elf_section->header, entry_size, 0); // this section is not a table, so entry_size is zero
-
 
531
   Buffer_AppendBuffer (file, &elf_section->data); // append section headers strings table section data to ELF file
1336
 
532
 
1337
   WELLMANNERED_ASSERT (count <= fsentry->header.size, "attempt to write invalid dirent (claimed size %zd, written size %zd). Aborting.", (size_t) fsentry->header.size, count);
-
 
1338
   if (count < fsentry->header.size)
533
   // now write the section headers table
1339
   {
-
 
1340
      if (fp != NULL)
-
 
1341
         fwrite_or_die (zeropad_buffer, 1, fsentry->header.size - count, fp); // pad as necessary
534
   memset (&file->bytes[new_shdrtable_offset], 0, ELF_STRUCT_SIZE (ELFHDR, &elf_sections[0].header)); // the first section header is always zerofilled
1342
      count += fsentry->header.size - count;
535
   for (table_index = 1; table_index < elf_section_count; table_index++)
1343
   }
-
 
-
 
536
      Buffer_WriteAt (file, new_shdrtable_offset + table_index * ELF_STRUCT_SIZE (ELFHDR, &elf_sections[table_index].header), &elf_sections[table_index].header, ELF_STRUCT_SIZE (ELFHDR, &elf_sections[table_index].header)); // write each section header
-
 
537
   Buffer_WriteAt (file, new_shdrtable_offset + table_index * ELF_STRUCT_SIZE (ELFHDR, &elf_sections[table_index].header), &elf_sections[0].header, ELF_STRUCT_SIZE (ELFHDR, &elf_sections[0].header)); // write the section header names section header last
1344
 
538
 
-
 
539
   // and finally fix the ELF master header
-
 
540
   ELF_SET_NUMERIC (ELFHDR, ELFHDR, section_header_table_offset, new_shdrtable_offset);
-
 
541
   ELF_SET_NUMERIC (ELFHDR, ELFHDR, section_header_table_len, 1 + elf_section_count); // take in account that the first entry in the section headers table is empty 
-
 
542
   ELF_SET_NUMERIC (ELFHDR, ELFHDR, section_header_names_idx, elf_section_count); // the section headers strings table is the last section
-
 
543
 
-
 
544
   // align size with page size (4096 on x86, 16k on ARM), zerofilling the extra space
-
 
545
   ASSERT_WITH_ERRNO (Buffer_PadWithZeroesTo (file, ROUND_TO_UPPER_MULTIPLE (file->size, page_size)));
-
 
546
 
-
 
547
   // cleanup
-
 
548
   for (table_index = 0; table_index < elf_section_count; table_index++)
-
 
549
      Buffer_Forget (&elf_sections[table_index].data); // free all sections' backing buffers
-
 
550
 
-
 
551
   #undef ELFHDR // undefine the macro that used to always point to the ELF header at the beginning of the file
1345
   return (count);
552
   return (1); // success
1346
}
553
}
1347
 
554
 
1348
 
555
 
1349
static size_t add_fsentry (fsentry_t **fsentries, size_t *fsentry_count, parms_t *entry_parms, const char *stored_pathname, const char *buildhost_pathname)
556
static size_t add_fsentry (fsentry_t **fsentries, size_t *fsentry_count, parms_t *entry_parms, const char *stored_pathname, const char *buildhost_pathname)
1350
{
557
{
1351
   #define ADD_NAME_TO_STRINGTABLE(name,strtab) do { \
-
 
1352
      name_len = strlen ((name)) + 1; \
-
 
1353
      reallocated_ptr = realloc ((strtab).bytes, (strtab).len + name_len); \
-
 
1354
      WELLMANNERED_ASSERT (reallocated_ptr, "out of memory"); \
-
 
1355
      (strtab).bytes = reallocated_ptr; \
-
 
1356
      memcpy (&(strtab).bytes[(strtab).len], (name), name_len); \
-
 
1357
      (strtab).len += name_len; \
-
 
1358
   } while (0)
-
 
1359
   #define APPEND_SECTION_DATA(section,sectionhdr_offset) do { \
-
 
1360
      memcpy (&entry_parms->data.bytes[entry_parms->data.len], (section).bytes, (section).len); /* write section in place */ \
-
 
1361
      free ((section).bytes); /* free it */ \
-
 
1362
      new_shdr = (elf_section_header_t *) &new_shtab.bytes[(sectionhdr_offset)]; /* now fix this section header */ \
-
 
1363
      ELF_SET_NUMERIC (elf, new_shdr, file_offset, entry_parms->data.len); /* fix section offset in the new section headers table */ \
-
 
1364
      entry_parms->data.len += (section).len; /* update new ELF file length */ \
-
 
1365
   } while (0)
-
 
1366
 
-
 
1367
   static thread_local char candidate_pathname[MAXPATHLEN];
558
   static thread_local char *candidate_pathname = NULL;
1368
   static int inode_count = 0; // will be preincremented each time this function is called
559
   static int inode_count = 0; // will be preincremented each time this function is called
1369
 
560
 
1370
   const char *original_stored_pathname = NULL;
561
   const char *original_stored_pathname = NULL;
1371
   const elf_dynamic_section_entry_t *dynamic_entry; // dynamic section entry
-
 
1372
   const elf_section_header_t *shdr_dynstr; // dynamic strings
-
 
1373
   const elf_section_header_t *shdr_dynamic; // dynamic section
-
 
1374
   const elf_section_header_t *shdr;
-
 
1375
   elf_section_header_t *new_shdr;
-
 
1376
   size_t new_qnxinfo_shdr_offset;
-
 
1377
   size_t new_debuglink_shdr_offset;
-
 
1378
   size_t new_qnxusage_shdr_offset;
-
 
1379
   size_t new_buildid_shdr_offset;
-
 
1380
   size_t new_shstrtab_shdr_offset;
562
   buffer_t *shstrtab = NULL;
1381
   elf_program_header_t *phdr;
-
 
1382
   const char *canonical_dylib_name;
563
   const char *canonical_dylib_name;
1383
   const char *dynamic_strings; // strings table of the ".dynamic" section
564
   const char *dynamic_strings; // strings table of the ".dynamic" section
1384
   const char *last_dirsep;
565
   const char *last_dirsep;
1385
   elf_header_t *elf;
-
 
1386
   buffer_t new_shtab = { NULL, 0 };
-
 
1387
   buffer_t elfsection_qnxinfo   = { NULL, 0 };
-
 
1388
   buffer_t elfsection_qnxusage  = { NULL, 0 };
-
 
1389
   buffer_t elfsection_debuglink = { NULL, 0 };
-
 
1390
   buffer_t elfsection_buildid   = { NULL, 0 };
-
 
1391
   buffer_t elfsection_shstrtab  = { NULL, 0 };
-
 
1392
   char *global_envstring = NULL;
566
   char *global_envstring = NULL;
1393
   size_t global_envstring_len = 0;
567
   size_t global_envstring_len = 0;
1394
   char *startup_name = NULL;
568
   char *startup_name = NULL;
1395
   char *procnto_name = NULL;
569
   char *procnto_name = NULL;
1396
   char *resolved_pathname;
570
   char *resolved_pathname;
1397
   void *reallocated_ptr;
571
   void *reallocated_ptr;
1398
   void *old_data;
572
   void *old_data;
1399
   struct stat stat_buf;
573
   struct stat stat_buf;
1400
   size_t new_shdrtable_offset;
-
 
1401
   size_t end_padding_offset;
-
 
1402
   size_t table_index;
-
 
1403
   size_t table_count;
-
 
1404
   size_t name_len;
-
 
1405
   fsentry_t *fsentry;
574
   fsentry_t *fsentry;
-
 
575
 
-
 
576
   // initial allocation (per thread)
-
 
577
   if (candidate_pathname == NULL)
-
 
578
   {
-
 
579
      candidate_pathname = malloc (MAXPATHLEN);
-
 
580
      ASSERT_WITH_ERRNO (candidate_pathname);
-
 
581
   }
1406
 
582
 
1407
   if (S_ISDIR (entry_parms->st_mode)) // are we storing a directory ?
583
   if (S_ISDIR (entry_parms->st_mode)) // are we storing a directory ?
1408
   {
584
   {
1409
      LOG_INFO ("directory: ino 0x%x uid %d gid %d mode 0%o path \"%s\"", inode_count + 1, entry_parms->uid, entry_parms->gid, entry_parms->st_mode, stored_pathname);
585
      LOG_INFO ("directory: ino 0x%x uid %d gid %d mode 0%o path \"%s\"", inode_count + 1, entry_parms->uid, entry_parms->gid, entry_parms->st_mode, stored_pathname);
1410
   }
586
   }
Line 1418... Line 594...
1418
         char *linebit_start;
594
         char *linebit_start;
1419
         char *content_line;
595
         char *content_line;
1420
         char *write_ptr;
596
         char *write_ptr;
1421
         char *token;
597
         char *token;
1422
         char *value;
598
         char *value;
-
 
599
         char *ctx;
1423
         bool is_quoted_context;
600
         bool is_quoted_context;
1424
         bool was_string_split;
601
         bool was_string_split;
1425
 
602
 
1426
         // parse each line of contents
603
         // parse each line of contents
1427
         WELLMANNERED_ASSERT (entry_parms->data.len > 0, "kernel specification without inline contents");
604
         ASSERT (entry_parms->data.len > 0, "kernel specification without inline contents");
1428
         for (content_line = strtok (entry_parms->data.bytes, "\n"); content_line != NULL; content_line = strtok (NULL, "\n"))
605
         for (content_line = strtok_r (entry_parms->data.bytes, "\n", &ctx); content_line != NULL; content_line = strtok_r (NULL, "\n", ctx))
1429
         {
606
         {
1430
            while (isspace (*content_line))
607
            while (isspace (*content_line))
1431
               content_line++; // skip leading spaces
608
               content_line++; // skip leading spaces
1432
            if ((*content_line == '#') || (*content_line == 0))
609
            if ((*content_line == '#') || (*content_line == 0))
1433
               continue; // skip comments and empty lines
610
               continue; // skip comments and empty lines
Line 1445... Line 622...
1445
               while ((*content_line != 0) && !((*content_line == ']') && (content_line[-1] != '\\') && !is_quoted_context))
622
               while ((*content_line != 0) && !((*content_line == ']') && (content_line[-1] != '\\') && !is_quoted_context))
1446
               {
623
               {
1447
                  if (*content_line == '"')
624
                  if (*content_line == '"')
1448
                     is_quoted_context ^= true; // remember when we're between quotes
625
                     is_quoted_context ^= true; // remember when we're between quotes
1449
                  else if (!is_quoted_context && (*content_line == ' '))
626
                  else if (!is_quoted_context && (*content_line == ' '))
1450
                     *content_line = RECORD_SEP; // turn all spaces outside quoted contexts into an ASCII record separator to ease token splitting
627
                     *content_line = RECORD_SEP[0]; // turn all spaces outside quoted contexts into an ASCII record separator to ease token splitting
1451
                  content_line++; // reach the next unescaped closing square bracket
628
                  content_line++; // reach the next unescaped closing square bracket
1452
               }
629
               }
1453
               if (*content_line != ']')
630
               if (*content_line != ']')
1454
               {
631
               {
1455
                  LOG ("warning", 0, "syntax error in \"%s\" line %d: unterminated attributes block (skipping)", buildfile_pathname, lineno);
632
                  LOG ("warning", 0, "syntax error in \"%s\" line %d: unterminated attributes block (skipping)", buildfile_pathname, lineno);
1456
                  continue; // invalid attribute block, skip line
633
                  continue; // invalid attribute block, skip line
1457
               }
634
               }
1458
               *content_line = 0; // end the attribute block so that it is a parsable C string
635
               *content_line = 0; // end the attribute block so that it is a parsable C string
1459
 
636
 
1460
               // now parse the attribute tokens (NOTE: THE LIST OF ALLOWED ATTRIBUTES HERE IS NOT DOCUMENTED)
637
               // now parse the attribute tokens (NOTE: THE LIST OF ALLOWED ATTRIBUTES HERE IS NOT DOCUMENTED)
1461
               token = strtok (linebit_start, RECORD_SEP_STR);
638
               token = strtok_r (linebit_start, RECORD_SEP, &ctx);
1462
               while (token != NULL)
639
               while (token != NULL)
1463
               {
640
               {
1464
                  #define REACH_TOKEN_VALUE() do { value = strchr (token, '=') + 1; if (*value == '"') value++; } while (0)
641
                  #define REACH_TOKEN_VALUE() do { value = strchr (token, '=') + 1; if (*value == '"') value++; } while (0)
1465
                  if      (strncmp (token, "uid=",     4) == 0) { REACH_TOKEN_VALUE (); entry_parms->uid     = (int) read_integer (value); }
642
                  if      (strncmp (token, "uid=",     4) == 0) { REACH_TOKEN_VALUE (); entry_parms->uid     = (int) read_integer (value); }
1466
                  else if (strncmp (token, "gid=",     4) == 0) { REACH_TOKEN_VALUE (); entry_parms->gid     = (int) read_integer (value); }
643
                  else if (strncmp (token, "gid=",     4) == 0) { REACH_TOKEN_VALUE (); entry_parms->gid     = (int) read_integer (value); }
Line 1470... Line 647...
1470
                  else if (strcmp (token, "-followlink") == 0) entry_parms->should_follow_symlinks = false;
647
                  else if (strcmp (token, "-followlink") == 0) entry_parms->should_follow_symlinks = false;
1471
                  else if (strcmp (token, "+keeplinked") == 0) entry_parms->should_keep_ld_output = true;
648
                  else if (strcmp (token, "+keeplinked") == 0) entry_parms->should_keep_ld_output = true;
1472
                  else if (strcmp (token, "-keeplinked") == 0) entry_parms->should_keep_ld_output = false;
649
                  else if (strcmp (token, "-keeplinked") == 0) entry_parms->should_keep_ld_output = false;
1473
                  else LOG_WARNING ("unimplemented bootstrap executable attribute in \"%s\" line %d: '%s'", buildfile_pathname, lineno, token);
650
                  else LOG_WARNING ("unimplemented bootstrap executable attribute in \"%s\" line %d: '%s'", buildfile_pathname, lineno, token);
1474
                  #undef REACH_TOKEN_VALUE
651
                  #undef REACH_TOKEN_VALUE
1475
                  token = strtok (NULL, RECORD_SEP_STR); // proceed to next attribute token
652
                  token = strtok_r (NULL, RECORD_SEP, &ctx); // proceed to next attribute token
1476
               }
653
               }
1477
 
654
 
1478
               content_line++; // reach the next character
655
               content_line++; // reach the next character
1479
               while ((*content_line != 0) && isspace (*content_line))
656
               while ((*content_line != 0) && isspace (*content_line))
1480
                  content_line++; // skip leading spaces
657
                  content_line++; // skip leading spaces
Line 1579... Line 756...
1579
         } // end of parsing
756
         } // end of parsing
1580
         free (entry_parms->data.bytes); // free the inline specification once it's parsed
757
         free (entry_parms->data.bytes); // free the inline specification once it's parsed
1581
         entry_parms->data.bytes = NULL;
758
         entry_parms->data.bytes = NULL;
1582
         entry_parms->data.len = 0;
759
         entry_parms->data.len = 0;
1583
 
760
 
1584
         WELLMANNERED_ASSERT (startup_name && *startup_name, "the QNX startup executable (startup-*) is missing in this bootstrap inline specification");
761
         ASSERT (startup_name && *startup_name, "the QNX startup executable (startup-*) is missing in this bootstrap inline specification");
1585
         WELLMANNERED_ASSERT (procnto_name && *procnto_name, "the QNX kernel (procnto-*) is missing in this bootstrap inline specification");
762
         ASSERT (procnto_name && *procnto_name, "the QNX kernel (procnto-*) is missing in this bootstrap inline specification");
1586
 
763
 
1587
         // now we know which startup and procnto executables to use
764
         // now we know which startup and procnto executables to use
1588
         LOG_DEBUG ("Startup: %s", startup_name);
765
         LOG_DEBUG ("Startup: %s", startup_name);
1589
         LOG_DEBUG ("Kernel: %s", procnto_name);
766
         LOG_DEBUG ("Kernel: %s", procnto_name);
1590
 
767
 
Line 1608... Line 785...
1608
#elif defined(__QNXNTO__)
785
#elif defined(__QNXNTO__)
1609
         sprintf (linker_pathname, "%s/../../host/qnx8/x86_64/usr/bin/%s-ld", QNX_TARGET, (strcmp (image_processor, "x86_64") == 0 ? "x86_64-pc-nto-qnx8.0.0" : "aarch64-unknown-nto-qnx8.0.0"));
786
         sprintf (linker_pathname, "%s/../../host/qnx8/x86_64/usr/bin/%s-ld", QNX_TARGET, (strcmp (image_processor, "x86_64") == 0 ? "x86_64-pc-nto-qnx8.0.0" : "aarch64-unknown-nto-qnx8.0.0"));
1610
#else // wtf are you building this on?
787
#else // wtf are you building this on?
1611
#error Please port the GNU linker x86_64-pc-nto-qnx8.0.0-ld and aarch64-unknown-nto-qnx8.0.0-ld to your host architecture first before compiling ifstool.
788
#error Please port the GNU linker x86_64-pc-nto-qnx8.0.0-ld and aarch64-unknown-nto-qnx8.0.0-ld to your host architecture first before compiling ifstool.
1612
#endif
789
#endif
1613
         WELLMANNERED_ASSERT (access (linker_pathname, 0) == 0, "host cross-linker for QNX8 \"%s\" not found", linker_pathname);
790
         ASSERT (access (linker_pathname, 0) == 0, "host cross-linker for QNX8 \"%s\" not found", linker_pathname);
1614
         sprintf (linker_sysroot_arg, "--sysroot=%s/%s/", QNX_TARGET, image_processor);
791
         sprintf (linker_sysroot_arg, "--sysroot=%s/%s/", QNX_TARGET, image_processor);
1615
         sprintf (linker_script_pathname_arg, "-T%s/%s/lib/nto.link", QNX_TARGET, image_processor);
792
         sprintf (linker_script_pathname_arg, "-T%s/%s/lib/nto.link", QNX_TARGET, image_processor);
1616
 
793
 
1617
         resolved_pathname = read_filecontents (procnto_name, (entry_parms->search[0] != 0 ? entry_parms->search : MKIFS_PATH), NULL); // locate the procnto kernel location, but do not load it
794
         resolved_pathname = resolve_pathname (procnto_name, (entry_parms->search[0] != 0 ? entry_parms->search : MKIFS_PATH)); // locate the procnto kernel location
1618
         WELLMANNERED_ASSERT (resolved_pathname, "QNX kernel \"%s\" not found in search path", procnto_name);
795
         ASSERT (resolved_pathname, "QNX kernel \"%s\" not found in search path", procnto_name);
1619
         strcpy (procnto_buildhost_pathname, resolved_pathname);
796
         strcpy (procnto_buildhost_pathname, resolved_pathname);
1620
 
797
 
1621
         sprintf (procnto_sym_filename, "%s.sym", procnto_name);
798
         sprintf (procnto_sym_filename, "%s.sym", procnto_name);
1622
 
799
 
1623
         const char *linker_argv[] = // construct the linker invokation argv
800
         const char *linker_argv[] = // construct the linker invokation argv
Line 1639... Line 816...
1639
            for (table_index = 0; table_index < sizeof (linker_argv) / sizeof (linker_argv[0]) - 1; table_index++)
816
            for (table_index = 0; table_index < sizeof (linker_argv) / sizeof (linker_argv[0]) - 1; table_index++)
1640
               fprintf (stderr, " '%s'", linker_argv[table_index]);
817
               fprintf (stderr, " '%s'", linker_argv[table_index]);
1641
            fputc ('\n', stderr);
818
            fputc ('\n', stderr);
1642
         }
819
         }
1643
         _spawnv (_P_WAIT, linker_pathname, linker_argv); // spawn the linker and produce a stripped procnto (wait for completion)
820
         _spawnv (_P_WAIT, linker_pathname, linker_argv); // spawn the linker and produce a stripped procnto (wait for completion)
1644
         resolved_pathname = read_filecontents (procnto_sym_filename, ".", &entry_parms->data); // locate the output file and load it
821
         if (!Buffer_ReadFromFile (&entry_parms->data, procnto_sym_filename)) // load the output file
1645
         if (resolved_pathname == NULL)
-
 
1646
            DIE_WITH_EXITCODE (1, "the host cross-linker failed to produce a readable stripped \"%s\" kernel: %s", procnto_sym_filename, strerror (errno));
822
            DIE_WITH_EXITCODE (1, "the host cross-linker failed to produce a readable stripped \"%s\" kernel: %s", procnto_sym_filename, strerror (errno));
1647
         if (!entry_parms->should_keep_ld_output)
823
         if (!entry_parms->should_keep_ld_output)
1648
            unlink (procnto_sym_filename); // remove the linker output file if we want to
824
            unlink (procnto_sym_filename); // remove the linker output file if we want to
1649
#else // !PROCNTO_WIP
825
#else // !PROCNTO_WIP
1650
         /* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK */
826
         /* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK */
1651
         /* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK */
827
         /* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK */
1652
         /* HACK */
828
         /* HACK */
1653
         /* HACK */ sprintf (candidate_pathname, "%s/procnto-smp-instr", entry_parms->prefix); // HACK: fix the entry name
829
         /* HACK */ sprintf_s (candidate_pathname, MAXPATHLEN, "%s/procnto-smp-instr", entry_parms->prefix); // HACK: fix the entry name
1654
         /* HACK */ stored_pathname = candidate_pathname;
830
         /* HACK */ stored_pathname = candidate_pathname;
1655
         /* HACK */ entry_parms->extra_ino_flags |= IFS_INO_PROCESSED_ELF | IFS_INO_BOOTSTRAP_EXE; // procnto needs to have these flags stamped on the inode
831
         /* HACK */ entry_parms->extra_ino_flags |= IFS_INO_PROCESSED_ELF | IFS_INO_BOOTSTRAP_EXE; // procnto needs to have these flags stamped on the inode
1656
         /* HACK */ entry_parms->st_mode = S_IFREG | 0700; // procnto requires 0700 permissions
832
         /* HACK */ entry_parms->st_mode = S_IFREG | 0700; // procnto requires 0700 permissions
1657
         /* HACK */ image_kernel_ino = entry_parms->extra_ino_flags | (inode_count + 1);
833
         /* HACK */ image_kernel_ino = entry_parms->extra_ino_flags | (inode_count + 1);
1658
         /* HACK */ free (entry_parms->data.bytes); // discard inline contents
834
         /* HACK */ free (entry_parms->data.bytes); // discard inline contents
1659
         /* HACK */ entry_parms->data.bytes = NULL;
-
 
1660
         /* HACK */ entry_parms->data.len = 0;
835
         /* HACK */ Buffer_Initialize (&entry_parms->data);
1661
         /* HACK */ if (read_filecontents (kernelfile_pathname, ".", &entry_parms->data) == NULL) // read kernel file as a precompiled binary blob
836
         /* HACK */ if (!Buffer_ReadFromFile (&entry_parms->data, kernelfile_pathname)) // read kernel file as a precompiled binary blob
1662
         /* HACK */ {
837
         /* HACK */ {
1663
         /* HACK */    fprintf (stderr, "fatal error: unable to read precompiled kernel file \"%s\" specified in --kernelfile argument\n", kernelfile_pathname);
838
         /* HACK */    fprintf (stderr, "fatal error: unable to read precompiled kernel file \"%s\" specified in --kernelfile argument\n", kernelfile_pathname);
1664
         /* HACK */    exit (1);
839
         /* HACK */    exit (1);
1665
         /* HACK */ }
840
         /* HACK */ }
1666
         /* HACK */
841
         /* HACK */
Line 1673... Line 848...
1673
 
848
 
1674
      // do we already know the data for this data blob ?
849
      // do we already know the data for this data blob ?
1675
      if (entry_parms->data.bytes != NULL)
850
      if (entry_parms->data.bytes != NULL)
1676
      {
851
      {
1677
         entry_parms->mtime = entry_parms->mtime_for_inline_files; // if so, set it a mtime equal to the mtime to use for inline files
852
         entry_parms->mtime = entry_parms->mtime_for_inline_files; // if so, set it a mtime equal to the mtime to use for inline files
1678
         LOG_INFO ("file: ino 0x%x uid %d gid %d mode 0%o path \"%s\" blob (len %zd)", entry_parms->extra_ino_flags | (inode_count + 1), entry_parms->uid, entry_parms->gid, entry_parms->st_mode, stored_pathname, entry_parms->data.len);
853
         LOG_INFO ("file: ino 0x%x uid %d gid %d mode 0%o path \"%s\" blob (len %zd)", entry_parms->extra_ino_flags | (inode_count + 1), entry_parms->uid, entry_parms->gid, entry_parms->st_mode, stored_pathname, entry_parms->data.size);
1679
      }
854
      }
1680
      else if (buildhost_pathname != NULL) // else was a source file pathname supplied ?
855
      else if (buildhost_pathname != NULL) // else was a source file pathname supplied ?
1681
      {
856
      {
1682
         resolved_pathname = read_filecontents (buildhost_pathname, (entry_parms->search[0] != 0 ? entry_parms->search : MKIFS_PATH), &entry_parms->data); // locate the file
857
         resolved_pathname = resolve_pathname (buildhost_pathname, (entry_parms->search[0] != 0 ? entry_parms->search : MKIFS_PATH)); // locate the file
1683
         if (resolved_pathname == NULL)
858
         if (resolved_pathname == NULL)
1684
            DIE_WITH_EXITCODE (1, "filesystem entry \"%s\" specified in \"%s\" line %d not found on build host: %s", buildhost_pathname, buildfile_pathname, lineno, strerror (errno));
859
            DIE_WITH_EXITCODE (1, "filesystem entry \"%s\" specified in \"%s\" line %d not found on build host: %s", buildhost_pathname, buildfile_pathname, lineno, strerror (errno));
-
 
860
         if (!Buffer_ReadFromFile (&entry_parms->data, resolved_pathname))
-
 
861
            DIE_WITH_EXITCODE (1, "filesystem entry \"%s\" specified in \"%s\" line %d can't be read: %s", buildhost_pathname, buildfile_pathname, lineno, strerror (errno));
1685
         stat (resolved_pathname, &stat_buf); // can't fail
862
         stat (resolved_pathname, &stat_buf); // can't fail, since we could read it
1686
         if (entry_parms->mtime == UINT32_MAX)
863
         if (entry_parms->mtime == UINT32_MAX)
1687
            entry_parms->mtime = (uint32_t) stat_buf.st_mtime;
864
            entry_parms->mtime = (uint32_t) stat_buf.st_mtime;
1688
         LOG_INFO ("file: ino 0x%x uid %d gid %d mode 0%o path \"%s\" buildhost_file \"%s\" (len %zd)", inode_count + 1, entry_parms->uid, entry_parms->gid, entry_parms->st_mode, stored_pathname, buildhost_pathname, entry_parms->data.len);
865
         LOG_INFO ("file: ino 0x%x uid %d gid %d mode 0%o path \"%s\" buildhost_file \"%s\" (len %zd)", inode_count + 1, entry_parms->uid, entry_parms->gid, entry_parms->st_mode, stored_pathname, buildhost_pathname, entry_parms->data.size);
1689
      }
866
      }
1690
 
867
 
1691
      // is the file we're storing an ELF file ?
868
      // is the file we're storing an ELF file ?
-
 
869
      #define ELFHDR ((elf_header_t *) entry_parms->data.bytes) // this convenient definition will make sure the ELF header points at the right location, even after entry_parms.data->byte is reallocated
1692
      if ((entry_parms->data.len > 52) // file is big enough to contain an ELF header
870
      if ((entry_parms->data.size > 52) // file is big enough to contain an ELF header
1693
          && ((elf = (elf_header_t *) entry_parms->data.bytes) != NULL) // cast (necessary true)
-
 
1694
          && (memcmp (ELF_GET_STRING (elf, elf, magic), ELF_MAGIC_STR, 4) == 0)) // file starts with the ELF magic
871
          && (memcmp (ELF_GET_STRING (ELFHDR, ELFHDR, magic), ELF_MAGIC_STR, 4) == 0)) // file starts with the ELF magic
1695
      {
872
      {
1696
         // is the file we're storing a relocatable executable (i.e. a dynamic library) and should we check for its canonical name ?
873
         // is the file we're storing a relocatable executable (i.e. a dynamic library) and should we check for its canonical name ?
1697
         if ((ELF_GET_NUMERIC (elf, elf, type) == 3) && entry_parms->should_autosymlink_dylib)
874
         if ((ELF_GET_NUMERIC (ELFHDR, ELFHDR, type) == ELF_TYPE_DYNAMICLIB) && entry_parms->should_autosymlink_dylib)
1698
         {
875
         {
1699
            // we need to find the SONAME of this library
-
 
1700
            canonical_dylib_name = NULL;
-
 
1701
 
-
 
1702
            // locate the sections we need (the dynamic section and its strings table)
876
            // locate the sections we need (the dynamic section and its strings table)
1703
            shdr_dynamic = elf_get_section_header_by_name (elf, ".dynamic");
877
            const elf_section_header_t *shdr_dynamic = elf_get_section_header_by_name (ELFHDR, ".dynamic");
1704
            shdr_dynstr = elf_get_section_header_by_name (elf, ".dynstr");
878
            const elf_section_header_t *shdr_dynstr = elf_get_section_header_by_name (ELFHDR, ".dynstr");
1705
 
879
 
1706
            // make sure we have both the dynamic section header and its own strings table header
880
            // make sure we have both the dynamic section header and its own strings table header
1707
            if ((shdr_dynamic != NULL) && (shdr_dynstr != NULL))
881
            if ((shdr_dynamic != NULL) && (shdr_dynstr != NULL))
1708
            {
882
            {
1709
               dynamic_strings = (char *) &entry_parms->data.bytes[ELF_GET_NUMERIC (elf, shdr_dynstr, file_offset)]; // quick access to dynamic sections strings table
883
               dynamic_strings = (char *) &entry_parms->data.bytes[ELF_GET_NUMERIC (ELFHDR, shdr_dynstr, file_offset)]; // quick access to dynamic sections strings table
1710
 
884
 
1711
               // walk through the dynamic section, look for the DT_SONAME entry
885
               // walk through the dynamic section, look for the DT_SONAME entry
-
 
886
               canonical_dylib_name = NULL; // assume none until told otherwise
1712
               for (dynamic_entry = (elf_dynamic_section_entry_t *) &entry_parms->data.bytes[ELF_GET_NUMERIC (elf, shdr_dynamic, file_offset)];
887
               for (elf_dynamic_section_entry_t *dynamic_entry = (elf_dynamic_section_entry_t *) &entry_parms->data.bytes[ELF_GET_NUMERIC (ELFHDR, shdr_dynamic, file_offset)];
1713
                    (ELF_GET_NUMERIC (elf, dynamic_entry, tag) != ELF_DT_NULL);
888
                    (ELF_GET_NUMERIC (ELFHDR, dynamic_entry, tag) != ELF_DT_NULL);
1714
                    dynamic_entry = (elf_dynamic_section_entry_t *) ((uint8_t *) dynamic_entry + ELF_STRUCT_SIZE (elf, dynamic_entry)))
889
                    dynamic_entry = (elf_dynamic_section_entry_t *) ((uint8_t *) dynamic_entry + ELF_STRUCT_SIZE (ELFHDR, dynamic_entry)))
1715
                  if (ELF_GET_NUMERIC (elf, dynamic_entry, tag) == ELF_DT_SONAME)
890
                  if (ELF_GET_NUMERIC (ELFHDR, dynamic_entry, tag) == ELF_DT_SONAME)
1716
                  {
891
                  {
1717
                     canonical_dylib_name = dynamic_strings + ELF_GET_NUMERIC (elf, dynamic_entry, value);
892
                     canonical_dylib_name = dynamic_strings + ELF_GET_NUMERIC (ELFHDR, dynamic_entry, value);
1718
                     break;
893
                     break;
1719
                  }
894
                  }
1720
 
895
 
1721
               // do we have it ?
896
               // do we have it ?
1722
               if ((canonical_dylib_name != NULL) && (canonical_dylib_name[0] != 0))
897
               if ((canonical_dylib_name != NULL) && (canonical_dylib_name[0] != 0))
1723
               {
898
               {
1724
                  sprintf (candidate_pathname, "%s/%s", entry_parms->prefix, canonical_dylib_name);
899
                  sprintf_s (candidate_pathname, MAXPATHLEN, "%s/%s", entry_parms->prefix, canonical_dylib_name);
1725
                  if (strcmp (candidate_pathname, stored_pathname) != 0) // claimed dylib name differs from passed name ?
900
                  if (strcmp (candidate_pathname, stored_pathname) != 0) // claimed dylib name differs from passed name ?
1726
                  {
901
                  {
1727
                     original_stored_pathname = stored_pathname; // if so, remember to create a symlink here
902
                     original_stored_pathname = stored_pathname; // if so, remember to create a symlink here
1728
                     stored_pathname = candidate_pathname;
903
                     stored_pathname = candidate_pathname;
1729
                  }
904
                  }
Line 1732... Line 907...
1732
         } // end if the file we're storing is a dylib
907
         } // end if the file we're storing is a dylib
1733
 
908
 
1734
         // now strip this ELF file if necessary
909
         // now strip this ELF file if necessary
1735
         if (!(entry_parms->extra_ino_flags & IFS_INO_PROCESSED_ELF))
910
         if (!(entry_parms->extra_ino_flags & IFS_INO_PROCESSED_ELF))
1736
         {
911
         {
1737
            // NOTE: for each ELF file, mkifs
-
 
1738
            // -> alters the program header table and offsets each p_addr (physical address) member by <image_base> plus the current file offset (this cannot be done right now, will need to be done once they are known)
-
 
1739
            // -> throws away and reconstructs the sections table by keeping only the sections that are in the program header, and writes the section table at the start of the first thrown-away section
-
 
1740
            // FIXME: what if a thrown away section is located between two program segments ? are they collapsed, moving the segments beyond it one slot down ?
-
 
1741
 
-
 
1742
            // reconstructed ELF:
-
 
1743
            // ==== START OF FILE ====
-
 
1744
            // ELF header
-
 
1745
            // program header table
-
 
1746
            //  (same sections, just p_addr offset changed)
-
 
1747
            // section data 5 (named ".note.gnu.build-id")
-
 
1748
            //  "............GNU....ZY.....c.o..l"
-
 
1749
            // PROGRAM
-
 
1750
            // sections table
-
 
1751
            // + section 1: ALL ZEROES
-
 
1752
            // + section 2: fileoffs 0x21a8 size 0xfd --> "QNX_info" --> QNX binary description: "NAME=pci_debug2.so.3.0\nDESCRIPTION=PCI Server System Debug Module\nDATE=2023/11/19-10:01:13-EST\nSTATE=lookup\nHOST=docker-n1.bts.rim.net\nUSER=builder\nVERSION=QNXOS_main\nTAGID=QNXOS_800-135\nPACKAGE=com.qnx.qnx800.target.pci.debug/3.0.0.00135T202311191043L\n"
912
            Buffer_StripELFFile (&entry_parms->data, stored_pathname); // strip the ELF file à la mkifs
1753
            // + section 3: fileoffs 0x22a5 size 0x1c --> ".gnu_debuglink" --> indicates the debug file and its checksum: "pci_debug2.so.3.0.sym" "\0\0\0" "VX2p"
-
 
1754
            // + section 4: fileoffs 0x22c1 size 0x2ad --> "QNX_usage" --> HELP TEXT: "\n-------------------------------------------------------------------------------\n%C\n\nThis module implements debug logging for all PCI server modules. It is\nincluded by setting the environment variable PCI_DEBUG_MODULE and uses\nthe slogger2 APIs.\nNOTE:.On systems which support slogger2, you are encouraged to use this module.instead of pci_debug.so...Release History.---------------..3.0 - This module is functionally equivalent to the previous 2.x version.      however it is incompatible with all pre v3.x PCI components..2.1 - fixes a bug whereby if slogger2 is not running and the PCI_DEBUG_MODULE.      environment variable is set, the client will SIGSEGV..2.0 - initial release.."
-
 
1755
            // + section 5: fileoffs 0x190 size 0x32 --> ".note.gnu.build-id" --> GNU build ID
-
 
1756
            // + section 6: fileoffs 0x256e size 0x40 --> ".shstrtab" --> sections names strings table
-
 
1757
            // section data 2 (named "QNX_info")
-
 
1758
            //  (QNX binary description)
-
 
1759
            // section data 3 (named ".gnu_debuglink")
-
 
1760
            //  (debug file)
-
 
1761
            // section data 4 (named "QNX_usage")
-
 
1762
            //  (help text)
-
 
1763
            // section data 6 (named ".shstrtab")
-
 
1764
            //  "\0"
-
 
1765
            //  ".shstrtab\0"
-
 
1766
            //  "QNX_info\0"
-
 
1767
            //  ".gnu_debuglink\0"
-
 
1768
            //  "QNX_usage\0"
-
 
1769
            //  ".note.gnu.build-id\0"
-
 
1770
            // ==== END OF FILE ====
-
 
1771
 
-
 
1772
            // parse the program header table, and measure the farthest offset known by this table where we'll write the reconstructed section headers table
-
 
1773
 
-
 
1774
            new_shdrtable_offset = 0;
-
 
1775
            table_count = ELF_GET_NUMERIC (elf, elf, program_header_table_len);
-
 
1776
            for (table_index = 0; table_index < table_count; table_index++)
-
 
1777
            {
-
 
1778
               phdr = (elf_program_header_t *) &entry_parms->data.bytes[ELF_GET_NUMERIC (elf, elf, program_header_table_offset) + (size_t) ELF_GET_NUMERIC (elf, elf, program_header_item_size) * table_index]; // quick access to program header
-
 
1779
               if (ELF_GET_NUMERIC (elf, phdr, file_offset) + ELF_GET_NUMERIC (elf, phdr, size_in_file) > new_shdrtable_offset)
-
 
1780
                  new_shdrtable_offset = ELF_GET_NUMERIC (elf, phdr, file_offset) + ELF_GET_NUMERIC (elf, phdr, size_in_file);
-
 
1781
            }
-
 
1782
 
-
 
1783
            // re-create the section header table
-
 
1784
 
-
 
1785
            elfsection_shstrtab.bytes = malloc (1); // initialize an empty section headers strings table
-
 
1786
            WELLMANNERED_ASSERT (elfsection_shstrtab.bytes, "out of memory");
-
 
1787
            elfsection_shstrtab.bytes[0] = 0;
-
 
1788
            elfsection_shstrtab.len = 1;
-
 
1789
            ADD_NAME_TO_STRINGTABLE (".shstrtab", elfsection_shstrtab);
-
 
1790
 
-
 
1791
            new_shtab.bytes = malloc (ELF_STRUCT_SIZE (elf, shdr)); // prepare a section headers table with just the default entry
-
 
1792
            WELLMANNERED_ASSERT (new_shtab.bytes, "out of memory");
-
 
1793
            memset (new_shtab.bytes, 0, ELF_STRUCT_SIZE (elf, shdr)); // the first section header is always zerofilled
-
 
1794
            new_shtab.len = ELF_STRUCT_SIZE (elf, shdr); // and remember how big the section headers table is now
-
 
1795
            if ((shdr = elf_get_section_header_by_name (elf, "QNX_info")) != NULL)
-
 
1796
            {
-
 
1797
               if (ELF_GET_NUMERIC (elf, shdr, file_offset) > new_shdrtable_offset) // if this section needs to be moved around, have a copy of it
-
 
1798
               {
-
 
1799
                  elfsection_qnxinfo.len = ELF_GET_NUMERIC (elf, shdr, size);
-
 
1800
                  elfsection_qnxinfo.bytes = malloc (elfsection_qnxinfo.len);
-
 
1801
                  WELLMANNERED_ASSERT (elfsection_qnxinfo.bytes, "out of memory");
-
 
1802
                  memcpy (elfsection_qnxinfo.bytes, &entry_parms->data.bytes[ELF_GET_NUMERIC (elf, shdr, file_offset)], elfsection_qnxinfo.len);
-
 
1803
               }
-
 
1804
               reallocated_ptr = realloc (new_shtab.bytes, new_shtab.len + ELF_STRUCT_SIZE (elf, shdr)); // grow our section headers table to have one entry more
-
 
1805
               WELLMANNERED_ASSERT (reallocated_ptr, "out of memory");
-
 
1806
               new_shtab.bytes = reallocated_ptr; // reallocation succeeded, save the new pointer
-
 
1807
               new_qnxinfo_shdr_offset = new_shtab.len; // remember the new offset of this section header
-
 
1808
               new_shtab.len += ELF_STRUCT_SIZE (elf, shdr); // and remember how bigger the section headers table is now
-
 
1809
 
-
 
1810
               new_shdr = (elf_section_header_t *) &new_shtab.bytes[new_qnxinfo_shdr_offset]; // now populate this section header
-
 
1811
               ADD_NAME_TO_STRINGTABLE ("QNX_info", elfsection_shstrtab);
-
 
1812
               ELF_SET_NUMERIC (elf, new_shdr, name_offset, relative_offset_of_in ("QNX_info", &elfsection_shstrtab)); // update the relative offset of the section name
-
 
1813
               ELF_SET_NUMERIC (elf, new_shdr, type,         ELF_GET_NUMERIC (elf, shdr, type)); // duplicate section type
-
 
1814
               ELF_SET_NUMERIC (elf, new_shdr, flags,        ELF_GET_NUMERIC (elf, shdr, flags)); // duplicate section flags
-
 
1815
               ELF_SET_NUMERIC (elf, new_shdr, virtual_addr, ELF_GET_NUMERIC (elf, shdr, virtual_addr)); // duplicate section virtual address
-
 
1816
               ELF_SET_NUMERIC (elf, new_shdr, file_offset, (ELF_GET_NUMERIC (elf, shdr, file_offset) > new_shdrtable_offset ? WILL_BE_FILLED_LATER : ELF_GET_NUMERIC (elf, shdr, file_offset))); // duplicate section offset only if it doesn't move
-
 
1817
               ELF_SET_NUMERIC (elf, new_shdr, size,         ELF_GET_NUMERIC (elf, shdr, size)); // duplicate section size
-
 
1818
               ELF_SET_NUMERIC (elf, new_shdr, linked_index, ELF_GET_NUMERIC (elf, shdr, linked_index)); // duplicate section linked index (which should be zero anyway)
-
 
1819
               ELF_SET_NUMERIC (elf, new_shdr, info,         ELF_GET_NUMERIC (elf, shdr, info)); // duplicate section info
-
 
1820
               ELF_SET_NUMERIC (elf, new_shdr, alignment,    ELF_GET_NUMERIC (elf, shdr, alignment)); // duplicate section alignment
-
 
1821
               ELF_SET_NUMERIC (elf, new_shdr, entry_size,   ELF_GET_NUMERIC (elf, shdr, entry_size)); // duplicate section entry size
-
 
1822
            }
-
 
1823
            if ((shdr = elf_get_section_header_by_name (elf, ".gnu_debuglink")) != NULL)
-
 
1824
            {
-
 
1825
               if (ELF_GET_NUMERIC (elf, shdr, file_offset) > new_shdrtable_offset) // if this section needs to be moved around, have a copy of it
-
 
1826
               {
-
 
1827
                  elfsection_debuglink.len = ELF_GET_NUMERIC (elf, shdr, size);
-
 
1828
                  elfsection_debuglink.bytes = malloc (elfsection_debuglink.len);
-
 
1829
                  WELLMANNERED_ASSERT (elfsection_debuglink.bytes, "out of memory");
-
 
1830
                  memcpy (elfsection_debuglink.bytes, &entry_parms->data.bytes[ELF_GET_NUMERIC (elf, shdr, file_offset)], elfsection_debuglink.len);
-
 
1831
               }
-
 
1832
               reallocated_ptr = realloc (new_shtab.bytes, new_shtab.len + ELF_STRUCT_SIZE (elf, shdr)); // grow our section headers table to have one entry more
-
 
1833
               WELLMANNERED_ASSERT (reallocated_ptr, "out of memory");
-
 
1834
               new_shtab.bytes = reallocated_ptr; // reallocation succeeded, save the new pointer
-
 
1835
               new_debuglink_shdr_offset = new_shtab.len; // remember the new offset of this section header
-
 
1836
               new_shtab.len += ELF_STRUCT_SIZE (elf, shdr); // and remember how bigger the section headers table is now
-
 
1837
 
-
 
1838
               new_shdr = (elf_section_header_t *) &new_shtab.bytes[new_debuglink_shdr_offset]; // now populate this section header
-
 
1839
               ADD_NAME_TO_STRINGTABLE (".gnu_debuglink", elfsection_shstrtab);
-
 
1840
               ELF_SET_NUMERIC (elf, new_shdr, name_offset, relative_offset_of_in (".gnu_debuglink", &elfsection_shstrtab)); // update the relative offset of the section name
-
 
1841
               ELF_SET_NUMERIC (elf, new_shdr, type,         ELF_GET_NUMERIC (elf, shdr, type)); // duplicate section type
-
 
1842
               ELF_SET_NUMERIC (elf, new_shdr, flags,        ELF_GET_NUMERIC (elf, shdr, flags)); // duplicate section flags
-
 
1843
               ELF_SET_NUMERIC (elf, new_shdr, virtual_addr, ELF_GET_NUMERIC (elf, shdr, virtual_addr)); // duplicate section virtual address
-
 
1844
               ELF_SET_NUMERIC (elf, new_shdr, file_offset, (ELF_GET_NUMERIC (elf, shdr, file_offset) > new_shdrtable_offset ? WILL_BE_FILLED_LATER : ELF_GET_NUMERIC (elf, shdr, file_offset))); // duplicate section offset only if it doesn't move
-
 
1845
               ELF_SET_NUMERIC (elf, new_shdr, size,         ELF_GET_NUMERIC (elf, shdr, size)); // duplicate section size
-
 
1846
               ELF_SET_NUMERIC (elf, new_shdr, linked_index, ELF_GET_NUMERIC (elf, shdr, linked_index)); // duplicate section linked index (which should be zero anyway)
-
 
1847
               ELF_SET_NUMERIC (elf, new_shdr, info,         ELF_GET_NUMERIC (elf, shdr, info)); // duplicate section info
-
 
1848
               ELF_SET_NUMERIC (elf, new_shdr, alignment,    ELF_GET_NUMERIC (elf, shdr, alignment)); // duplicate section alignment
-
 
1849
               ELF_SET_NUMERIC (elf, new_shdr, entry_size,   ELF_GET_NUMERIC (elf, shdr, entry_size)); // duplicate section entry size
-
 
1850
            }
-
 
1851
            if ((shdr = elf_get_section_header_by_name (elf, "QNX_usage")) != NULL)
-
 
1852
            {
-
 
1853
               if (ELF_GET_NUMERIC (elf, shdr, file_offset) > new_shdrtable_offset) // if this section needs to be moved around, have a copy of it
-
 
1854
               {
-
 
1855
                  elfsection_qnxusage.len = ELF_GET_NUMERIC (elf, shdr, size);
-
 
1856
                  elfsection_qnxusage.bytes = malloc (elfsection_qnxusage.len);
-
 
1857
                  WELLMANNERED_ASSERT (elfsection_qnxusage.bytes, "out of memory");
-
 
1858
                  memcpy (elfsection_qnxusage.bytes, &entry_parms->data.bytes[ELF_GET_NUMERIC (elf, shdr, file_offset)], elfsection_qnxusage.len);
-
 
1859
               }
-
 
1860
               reallocated_ptr = realloc (new_shtab.bytes, new_shtab.len + ELF_STRUCT_SIZE (elf, shdr)); // grow our section headers table to have one entry more
-
 
1861
               WELLMANNERED_ASSERT (reallocated_ptr, "out of memory");
-
 
1862
               new_shtab.bytes = reallocated_ptr; // reallocation succeeded, save the new pointer
-
 
1863
               new_qnxusage_shdr_offset = new_shtab.len; // remember the new offset of this section header
-
 
1864
               new_shtab.len += ELF_STRUCT_SIZE (elf, shdr); // and remember how bigger the section headers table is now
-
 
1865
 
-
 
1866
               new_shdr = (elf_section_header_t *) &new_shtab.bytes[new_qnxusage_shdr_offset]; // now populate this section header
-
 
1867
               ADD_NAME_TO_STRINGTABLE ("QNX_usage", elfsection_shstrtab);
-
 
1868
               ELF_SET_NUMERIC (elf, new_shdr, name_offset, relative_offset_of_in ("QNX_usage", &elfsection_shstrtab)); // update the relative offset of the section name
-
 
1869
               ELF_SET_NUMERIC (elf, new_shdr, type,         ELF_GET_NUMERIC (elf, shdr, type)); // duplicate section type
-
 
1870
               ELF_SET_NUMERIC (elf, new_shdr, flags,        ELF_GET_NUMERIC (elf, shdr, flags)); // duplicate section flags
-
 
1871
               ELF_SET_NUMERIC (elf, new_shdr, virtual_addr, ELF_GET_NUMERIC (elf, shdr, virtual_addr)); // duplicate section virtual address
-
 
1872
               ELF_SET_NUMERIC (elf, new_shdr, file_offset, (ELF_GET_NUMERIC (elf, shdr, file_offset) > new_shdrtable_offset ? WILL_BE_FILLED_LATER : ELF_GET_NUMERIC (elf, shdr, file_offset))); // duplicate section offset only if it doesn't move
-
 
1873
               ELF_SET_NUMERIC (elf, new_shdr, size,         ELF_GET_NUMERIC (elf, shdr, size)); // duplicate section size
-
 
1874
               ELF_SET_NUMERIC (elf, new_shdr, linked_index, ELF_GET_NUMERIC (elf, shdr, linked_index)); // duplicate section linked index (which should be zero anyway)
-
 
1875
               ELF_SET_NUMERIC (elf, new_shdr, info,         ELF_GET_NUMERIC (elf, shdr, info)); // duplicate section info
-
 
1876
               ELF_SET_NUMERIC (elf, new_shdr, alignment,    ELF_GET_NUMERIC (elf, shdr, alignment)); // duplicate section alignment
-
 
1877
               ELF_SET_NUMERIC (elf, new_shdr, entry_size,   ELF_GET_NUMERIC (elf, shdr, entry_size)); // duplicate section entry size
-
 
1878
            }
-
 
1879
            if ((shdr = elf_get_section_header_by_name (elf, ".note.gnu.build-id")) != NULL)
-
 
1880
            {
-
 
1881
               if (ELF_GET_NUMERIC (elf, shdr, file_offset) > new_shdrtable_offset) // if this section needs to be moved around, have a copy of it
-
 
1882
               {
-
 
1883
                  elfsection_buildid.len = ELF_GET_NUMERIC (elf, shdr, size);
-
 
1884
                  elfsection_buildid.bytes = malloc (elfsection_buildid.len);
-
 
1885
                  WELLMANNERED_ASSERT (elfsection_buildid.bytes, "out of memory");
-
 
1886
                  memcpy (elfsection_buildid.bytes, &entry_parms->data.bytes[ELF_GET_NUMERIC (elf, shdr, file_offset)], elfsection_buildid.len);
-
 
1887
               }
-
 
1888
               reallocated_ptr = realloc (new_shtab.bytes, new_shtab.len + ELF_STRUCT_SIZE (elf, shdr)); // grow our section headers table to have one entry more
-
 
1889
               WELLMANNERED_ASSERT (reallocated_ptr, "out of memory");
-
 
1890
               new_shtab.bytes = reallocated_ptr; // reallocation succeeded, save the new pointer
-
 
1891
               new_buildid_shdr_offset = new_shtab.len; // remember the new offset of this section header
-
 
1892
               new_shtab.len += ELF_STRUCT_SIZE (elf, shdr); // and remember how bigger the section headers table is now
-
 
1893
 
-
 
1894
               new_shdr = (elf_section_header_t *) &new_shtab.bytes[new_buildid_shdr_offset]; // now populate this section header
-
 
1895
               ADD_NAME_TO_STRINGTABLE (".note.gnu.build-id", elfsection_shstrtab);
-
 
1896
               ELF_SET_NUMERIC (elf, new_shdr, name_offset, relative_offset_of_in (".note.gnu.build-id", &elfsection_shstrtab)); // update the relative offset of the section name
-
 
1897
               ELF_SET_NUMERIC (elf, new_shdr, type,         ELF_GET_NUMERIC (elf, shdr, type)); // duplicate section type
-
 
1898
               ELF_SET_NUMERIC (elf, new_shdr, flags,        ELF_GET_NUMERIC (elf, shdr, flags)); // duplicate section flags
-
 
1899
               ELF_SET_NUMERIC (elf, new_shdr, virtual_addr, ELF_GET_NUMERIC (elf, shdr, virtual_addr)); // duplicate section virtual address
-
 
1900
               ELF_SET_NUMERIC (elf, new_shdr, file_offset, (ELF_GET_NUMERIC (elf, shdr, file_offset) > new_shdrtable_offset ? WILL_BE_FILLED_LATER : ELF_GET_NUMERIC (elf, shdr, file_offset))); // duplicate section offset only if it doesn't move
-
 
1901
               ELF_SET_NUMERIC (elf, new_shdr, size,         ELF_GET_NUMERIC (elf, shdr, size)); // duplicate section size
-
 
1902
               ELF_SET_NUMERIC (elf, new_shdr, linked_index, ELF_GET_NUMERIC (elf, shdr, linked_index)); // duplicate section linked index (which should be zero anyway)
-
 
1903
               ELF_SET_NUMERIC (elf, new_shdr, info,         ELF_GET_NUMERIC (elf, shdr, info)); // duplicate section info
-
 
1904
               ELF_SET_NUMERIC (elf, new_shdr, alignment,    ELF_GET_NUMERIC (elf, shdr, alignment)); // duplicate section alignment
-
 
1905
               ELF_SET_NUMERIC (elf, new_shdr, entry_size,   ELF_GET_NUMERIC (elf, shdr, entry_size)); // duplicate section entry size
-
 
1906
            }
-
 
1907
            reallocated_ptr = realloc (new_shtab.bytes, new_shtab.len + ELF_STRUCT_SIZE (elf, shdr)); // grow our section headers table to have one entry more
-
 
1908
            WELLMANNERED_ASSERT (reallocated_ptr, "out of memory");
-
 
1909
            new_shtab.bytes = reallocated_ptr; // reallocation succeeded, save the new pointer
-
 
1910
            new_shstrtab_shdr_offset = new_shtab.len; // remember the new offset of this section header
-
 
1911
            new_shtab.len += ELF_STRUCT_SIZE (elf, shdr); // and remember how bigger the section headers table is now
-
 
1912
 
-
 
1913
            new_shdr = (elf_section_header_t *) &new_shtab.bytes[new_shstrtab_shdr_offset]; // now populate this section header
-
 
1914
            ELF_SET_NUMERIC (elf, new_shdr, name_offset, relative_offset_of_in (".shstrtab", &elfsection_shstrtab)); // update the relative offset of the section name
-
 
1915
            ELF_SET_NUMERIC (elf, new_shdr, type,         ELF_SECTIONTYPE_STRINGTABLE); // section type (SHT_STRTAB)
-
 
1916
            ELF_SET_NUMERIC (elf, new_shdr, flags,        0); // section flags (we could set SHF_STRINGS i.e. 0x20 here, but mkifs does not, so mimic that)
-
 
1917
            ELF_SET_NUMERIC (elf, new_shdr, virtual_addr, 0); // this section does not need to be mapped
-
 
1918
            ELF_SET_NUMERIC (elf, new_shdr, file_offset, WILL_BE_FILLED_LATER); // will be filled once we know it
-
 
1919
            ELF_SET_NUMERIC (elf, new_shdr, size,         elfsection_shstrtab.len); // section size
-
 
1920
            ELF_SET_NUMERIC (elf, new_shdr, linked_index, 0); // this section is not linked to any other
-
 
1921
            ELF_SET_NUMERIC (elf, new_shdr, info,         0); // this section has no additional info
-
 
1922
            ELF_SET_NUMERIC (elf, new_shdr, alignment,    1); // this section is byte-aligned
-
 
1923
            ELF_SET_NUMERIC (elf, new_shdr, entry_size,   0); // this section is not a table, so entry_size is zero
-
 
1924
 
-
 
1925
            // jump over the new section headers table and write the sections that need to be relocated after the section headers table
-
 
1926
            entry_parms->data.len = new_shdrtable_offset + new_shtab.len; // assume there are no sections beyond the section headers table until known otherwise
-
 
1927
            if (elfsection_qnxinfo.bytes != NULL)
-
 
1928
               APPEND_SECTION_DATA (elfsection_qnxinfo, new_qnxinfo_shdr_offset); // write "QNX_info" section data if we have such a section
-
 
1929
            if (elfsection_debuglink.bytes != NULL)
-
 
1930
               APPEND_SECTION_DATA (elfsection_debuglink, new_debuglink_shdr_offset); // write ".gnu_debuglink" section data if we have such a section
-
 
1931
            if (elfsection_qnxusage.bytes != NULL)
-
 
1932
               APPEND_SECTION_DATA (elfsection_qnxusage, new_qnxusage_shdr_offset); // write "QNX_usage" section data if we have such a section
-
 
1933
            if (elfsection_buildid.bytes != NULL)
-
 
1934
               APPEND_SECTION_DATA (elfsection_buildid, new_buildid_shdr_offset); // write ".note.gnu.build-id" section data if we have such a section
-
 
1935
            APPEND_SECTION_DATA (elfsection_shstrtab, new_shstrtab_shdr_offset); // write the section header strings table as the last section
-
 
1936
 
-
 
1937
            // now write the section headers table
-
 
1938
            memcpy (&entry_parms->data.bytes[new_shdrtable_offset], new_shtab.bytes, new_shtab.len);
-
 
1939
            free (new_shtab.bytes); // free it
-
 
1940
 
-
 
1941
            // and finally fix the ELF header
-
 
1942
            ELF_SET_NUMERIC (elf, elf, section_header_table_offset, new_shdrtable_offset);
-
 
1943
            ELF_SET_NUMERIC (elf, elf, section_header_table_len, new_shtab.len / ELF_STRUCT_SIZE (elf, shdr));
-
 
1944
            ELF_SET_NUMERIC (elf, elf, section_header_names_idx, new_shtab.len / ELF_STRUCT_SIZE (elf, shdr) - 1); // the section headers strings table is the last section
-
 
1945
 
-
 
1946
            // align size with page size (4096 on x86, 16k on ARM)
-
 
1947
            end_padding_offset = entry_parms->data.len;
-
 
1948
            if (ELF_GET_NUMERIC (elf, elf, instruction_set) == ELF_MACHINE_X86_64)
-
 
1949
               entry_parms->data.len = ROUND_TO_UPPER_MULTIPLE (end_padding_offset, 4 * 1024); // 4 kb pages on Intel processors
-
 
1950
            else if (ELF_GET_NUMERIC (elf, elf, instruction_set) == ELF_MACHINE_AARCH64)
-
 
1951
               entry_parms->data.len = ROUND_TO_UPPER_MULTIPLE (end_padding_offset, 16 * 1024); // 16 kb pages on ARM64
-
 
1952
            else
-
 
1953
               DIE_WITH_EXITCODE (1, "this ELF file \"%s\" does not belong to an architecture supported by ifstool (neither x86_64, nor aarch64)", stored_pathname);
-
 
1954
 
-
 
1955
            memset (&entry_parms->data.bytes[end_padding_offset], 0, entry_parms->data.len - end_padding_offset); // zerofill
-
 
1956
            entry_parms->extra_ino_flags |= IFS_INO_PROCESSED_ELF; // mark this inode as a preprocessed ELF file
913
            entry_parms->extra_ino_flags |= IFS_INO_PROCESSED_ELF; // mark this inode as a preprocessed ELF file
1957
         } // end if the file is not yet a processed ELF
914
         } // end if the file is not yet a processed ELF
1958
      } // end if the file we're storing is an ELF file
915
      } // end if the file we're storing is an ELF file
-
 
916
      #undef ELFHDR // undefine the macro that used to always point to the ELF header at the beginning of the file
1959
   }
917
   }
1960
   else if (S_ISLNK (entry_parms->st_mode)) // else are we storing a symbolic link ?
918
   else if (S_ISLNK (entry_parms->st_mode)) // else are we storing a symbolic link ?
1961
      LOG_INFO ("symlink: ino 0x%x uid %d gid %d mode 0%o path \"%s\" -> \"%s\"", inode_count + 1, entry_parms->uid, entry_parms->gid, entry_parms->st_mode, stored_pathname, entry_parms->data.bytes);
919
      LOG_INFO ("symlink: ino 0x%x uid %d gid %d mode 0%o path \"%s\" -> \"%s\"", inode_count + 1, entry_parms->uid, entry_parms->gid, entry_parms->st_mode, stored_pathname, entry_parms->data.bytes);
1962
   else // we must be storing a FIFO
920
   else // we must be storing a FIFO
1963
   {
921
   {
Line 1966... Line 924...
1966
      LOG_INFO ("fifo: ino 0x%x uid %d gid %d mode 0%o path \"%s\" dev:rdev %s)", inode_count + 1, entry_parms->uid, entry_parms->gid, entry_parms->st_mode, stored_pathname, entry_parms->data.bytes);
924
      LOG_INFO ("fifo: ino 0x%x uid %d gid %d mode 0%o path \"%s\" dev:rdev %s)", inode_count + 1, entry_parms->uid, entry_parms->gid, entry_parms->st_mode, stored_pathname, entry_parms->data.bytes);
1967
   }
925
   }
1968
 
926
 
1969
   // grow filesystem entries array to hold one more slot
927
   // grow filesystem entries array to hold one more slot
1970
   reallocated_ptr = realloc (*fsentries, (*fsentry_count + 1) * sizeof (fsentry_t)); // attempt to reallocate
928
   reallocated_ptr = realloc (*fsentries, (*fsentry_count + 1) * sizeof (fsentry_t)); // attempt to reallocate
1971
   WELLMANNERED_ASSERT (reallocated_ptr, "out of memory");
929
   ASSERT_WITH_ERRNO (reallocated_ptr);
1972
   *fsentries = reallocated_ptr; // save reallocated pointer
930
   *fsentries = reallocated_ptr; // save reallocated pointer
1973
   fsentry = &(*fsentries)[*fsentry_count]; // quick access to fs entry slot
931
   fsentry = &(*fsentries)[*fsentry_count]; // quick access to fs entry slot
1974
   //fsentry->header.size = 0; // will be filled once we know it
-
 
1975
   fsentry->header.extattr_offset = 0;
932
   fsentry->header.extattr_offset = 0;
1976
   fsentry->header.ino = entry_parms->extra_ino_flags | (++inode_count);
933
   fsentry->header.ino = entry_parms->extra_ino_flags | (++inode_count);
1977
   fsentry->header.mode = entry_parms->st_mode;
934
   fsentry->header.mode = entry_parms->st_mode;
1978
   fsentry->header.gid = entry_parms->gid;
935
   fsentry->header.gid = entry_parms->gid;
1979
   fsentry->header.uid = entry_parms->uid;
936
   fsentry->header.uid = entry_parms->uid;
1980
   fsentry->header.mtime = (entry_parms->mtime == UINT32_MAX ? (uint32_t) time (NULL) : entry_parms->mtime);
937
   fsentry->header.mtime = (entry_parms->mtime == UINT32_MAX ? (uint32_t) time (NULL) : entry_parms->mtime);
1981
   if (S_ISDIR (entry_parms->st_mode))
938
   if (S_ISDIR (entry_parms->st_mode))
1982
   {
939
   {
1983
      fsentry->u.dir.path = strdup (stored_pathname[0] == '/' ? &stored_pathname[1] : stored_pathname);
940
      fsentry->u.dir.path = strdup (stored_pathname[0] == '/' ? &stored_pathname[1] : stored_pathname);
-
 
941
 
1984
      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
942
      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
1985
      fsentry->UNSAVED_was_data_written = true; // no data to save
943
      fsentry->UNSAVED_was_data_written = true; // no data to save
1986
   }
944
   }
1987
   else if (S_ISREG (entry_parms->st_mode))
945
   else if (S_ISREG (entry_parms->st_mode))
1988
   {
946
   {
1989
      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
947
      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
1990
      fsentry->u.file.size = (uint32_t) entry_parms->data.len;
948
      fsentry->u.file.size = (uint32_t) entry_parms->data.size;
1991
      fsentry->u.file.path = strdup (stored_pathname[0] == '/' ? &stored_pathname[1] : stored_pathname);
949
      fsentry->u.file.path = strdup (stored_pathname[0] == '/' ? &stored_pathname[1] : stored_pathname);
1992
      fsentry->u.file.UNSAVED_databuf = malloc (entry_parms->data.len);
950
      fsentry->u.file.UNSAVED_databuf = malloc (entry_parms->data.size);
1993
      WELLMANNERED_ASSERT (fsentry->u.file.UNSAVED_databuf, "out of memory");
951
      ASSERT_WITH_ERRNO (fsentry->u.file.UNSAVED_databuf);
1994
      memcpy (fsentry->u.file.UNSAVED_databuf, entry_parms->data.bytes, entry_parms->data.len);
952
      memcpy (fsentry->u.file.UNSAVED_databuf, entry_parms->data.bytes, entry_parms->data.size);
-
 
953
 
1995
      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
954
      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
1996
      fsentry->UNSAVED_was_data_written = false; // there *IS* data to save
955
      fsentry->UNSAVED_was_data_written = false; // there *IS* data to save
1997
   }
956
   }
1998
   else if (S_ISLNK (entry_parms->st_mode))
957
   else if (S_ISLNK (entry_parms->st_mode))
1999
   {
958
   {
2000
      fsentry->u.symlink.sym_offset = (uint16_t) (strlen (stored_pathname[0] == '/' ? &stored_pathname[1] : stored_pathname) + 1);
959
      fsentry->u.symlink.sym_offset = (uint16_t) (strlen (stored_pathname[0] == '/' ? &stored_pathname[1] : stored_pathname) + 1);
2001
      fsentry->u.symlink.sym_size = (uint16_t) entry_parms->data.len;
960
      fsentry->u.symlink.sym_size = (uint16_t) entry_parms->data.size;
2002
      fsentry->u.symlink.path = strdup (stored_pathname[0] == '/' ? &stored_pathname[1] : stored_pathname);
961
      fsentry->u.symlink.path = strdup (stored_pathname[0] == '/' ? &stored_pathname[1] : stored_pathname);
2003
      fsentry->u.symlink.contents = strdup (entry_parms->data.bytes);
962
      fsentry->u.symlink.contents = strdup (entry_parms->data.bytes);
2004
      WELLMANNERED_ASSERT (fsentry->u.symlink.contents, "out of memory");
963
      ASSERT_WITH_ERRNO (fsentry->u.symlink.contents);
-
 
964
 
2005
      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
965
      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
2006
      fsentry->UNSAVED_was_data_written = true; // no data to save
966
      fsentry->UNSAVED_was_data_written = true; // no data to save
2007
   }
967
   }
2008
   else // necessarily a device node
968
   else // necessarily a device node
2009
   {
969
   {
2010
      fsentry->u.device.dev  = strtol (entry_parms->data.bytes, NULL, 0); // use strtol() to parse decimal (...), hexadecimal (0x...) and octal (0...) numbers
970
      fsentry->u.device.dev  = strtol (entry_parms->data.bytes, NULL, 0); // use strtol() to parse decimal (...), hexadecimal (0x...) and octal (0...) numbers
2011
      fsentry->u.device.rdev = strtol (strchr (entry_parms->data.bytes, ':') + 1, NULL, 0); // use strtol() to parse decimal (...), hexadecimal (0x...) and octal (0...) numbers
971
      fsentry->u.device.rdev = strtol (strchr (entry_parms->data.bytes, ':') + 1, NULL, 0); // use strtol() to parse decimal (...), hexadecimal (0x...) and octal (0...) numbers
2012
      fsentry->u.device.path = strdup (stored_pathname[0] == '/' ? &stored_pathname[1] : stored_pathname);
972
      fsentry->u.device.path = strdup (stored_pathname[0] == '/' ? &stored_pathname[1] : stored_pathname);
-
 
973
 
2013
      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
974
      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
2014
      fsentry->UNSAVED_was_data_written = true; // no data to save
975
      fsentry->UNSAVED_was_data_written = true; // no data to save
2015
   }
976
   }
2016
   (*fsentry_count)++;
977
   (*fsentry_count)++;
2017
 
978
 
Line 2024... Line 985...
2024
      entry_parms->st_mode = S_IFLNK | 0777; // NOTE: mkifs stores symlink permissions as rwxrwxrwx !
985
      entry_parms->st_mode = S_IFLNK | 0777; // NOTE: mkifs stores symlink permissions as rwxrwxrwx !
2025
      entry_parms->extra_ino_flags = (fsentry->header.ino & (IFS_INO_PROCESSED_ELF | IFS_INO_RUNONCE_ELF | IFS_INO_BOOTSTRAP_EXE)); // preserve target's inode flags
986
      entry_parms->extra_ino_flags = (fsentry->header.ino & (IFS_INO_PROCESSED_ELF | IFS_INO_RUNONCE_ELF | IFS_INO_BOOTSTRAP_EXE)); // preserve target's inode flags
2026
      last_dirsep = strrchr (stored_pathname, '/');
987
      last_dirsep = strrchr (stored_pathname, '/');
2027
      old_data = entry_parms->data.bytes; // backup previous data pointer
988
      old_data = entry_parms->data.bytes; // backup previous data pointer
2028
      entry_parms->data.bytes = (uint8_t *) (last_dirsep == NULL ? stored_pathname : last_dirsep + 1); // store symlink target in dirent data
989
      entry_parms->data.bytes = (uint8_t *) (last_dirsep == NULL ? stored_pathname : last_dirsep + 1); // store symlink target in dirent data
2029
      entry_parms->data.len = strlen (entry_parms->data.bytes);
990
      entry_parms->data.size = strlen (entry_parms->data.bytes);
2030
      add_fsentry (fsentries, fsentry_count, entry_parms, original_stored_pathname, NULL);
991
      add_fsentry (fsentries, fsentry_count, entry_parms, original_stored_pathname, NULL);
2031
      entry_parms->data.bytes = old_data; // restore previous data pointer so that it can be freed normally
992
      entry_parms->data.bytes = old_data; // restore previous data pointer so that it can be freed normally
2032
   }
993
   }
2033
 
994
 
2034
   return (*fsentry_count);
995
   return (*fsentry_count);
Line 2062... Line 1023...
2062
   else // envvar not present
1023
   else // envvar not present
2063
   {
1024
   {
2064
      if (MKIFS_PATH != NULL)
1025
      if (MKIFS_PATH != NULL)
2065
         free (MKIFS_PATH); // free any MKIFS_PATH that we constructed earlier
1026
         free (MKIFS_PATH); // free any MKIFS_PATH that we constructed earlier
2066
 
1027
 
2067
      strcpy (processor_base, processor); // construct PROCESSOR_BASE
1028
      strcpy_s (processor_base, sizeof (processor_base), processor); // construct PROCESSOR_BASE
2068
      token = strchr (processor_base, '-');
1029
      token = strchr (processor_base, '-');
2069
      if (token != NULL)
1030
      if (token != NULL)
2070
         *token = 0; // split anything from the first dash onwards
1031
         *token = 0; // split anything from the first dash onwards
2071
      data_len = strlen (processor_base);
1032
      data_len = strlen (processor_base);
2072
      if ((data_len > 2) && ((processor_base[data_len - 2] == 'b') || (processor_base[data_len - 2] == 'l')) && (processor_base[data_len - 1] == 'e'))
1033
      if ((data_len > 2) && ((processor_base[data_len - 2] == 'b') || (processor_base[data_len - 2] == 'l')) && (processor_base[data_len - 1] == 'e'))
2073
         processor_base[data_len - 2] = 0; // if it ends with "le" or "be", strip that too
1034
         processor_base[data_len - 2] = 0; // if it ends with "le" or "be", strip that too
2074
 
1035
 
2075
      MKIFS_PATH = malloc (10 * MAXPATHLEN); // construct a default MKIFS_PATH now
1036
      MKIFS_PATH = malloc (10 * MAXPATHLEN); // construct a default MKIFS_PATH now
-
 
1037
      ASSERT_WITH_ERRNO (MKIFS_PATH);
2076
      WELLMANNERED_ASSERT (MKIFS_PATH, "out of memory");
1038
      sprintf_s (MKIFS_PATH, 10 * MAXPATHLEN,
2077
      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
1039
                 "." PATH_SEP "%s/%s/sbin" PATH_SEP "%s/%s/usr/sbin" PATH_SEP "%s/%s/boot/sys" PATH_SEP "%s/%s/boot/sys" PATH_SEP "%s/%s/bin" PATH_SEP "%s/%s/usr/bin" PATH_SEP "%s/%s/lib" PATH_SEP "%s/%s/lib/dll" PATH_SEP "%s/%s/usr/lib", // use a platform-specific character as path separator
2078
               QNX_TARGET, processor,
1040
                 QNX_TARGET, processor,
2079
               QNX_TARGET, processor,
1041
                 QNX_TARGET, processor,
2080
               QNX_TARGET, processor,
1042
                 QNX_TARGET, processor,
2081
               QNX_TARGET, processor_base,
1043
                 QNX_TARGET, processor_base,
2082
               QNX_TARGET, processor,
1044
                 QNX_TARGET, processor,
2083
               QNX_TARGET, processor,
1045
                 QNX_TARGET, processor,
2084
               QNX_TARGET, processor,
1046
                 QNX_TARGET, processor,
2085
               QNX_TARGET, processor,
1047
                 QNX_TARGET, processor,
2086
               QNX_TARGET, processor);
1048
                 QNX_TARGET, processor);
2087
   }
1049
   }
2088
 
1050
 
2089
   return;
1051
   return;
2090
}
1052
}
2091
 
1053
 
2092
 
1054
 
2093
int main (int argc, char **argv)
1055
int main (int argc, char **argv)
2094
{
1056
{
2095
   // program entrypoint
1057
   // program entrypoint
2096
 
1058
 
-
 
1059
   typedef struct ifs_offsets_s
-
 
1060
   {
-
 
1061
      size_t startupheader;
-
 
1062
      size_t startuptrailer;
-
 
1063
      size_t imageheader;
-
 
1064
      size_t imagedir;
-
 
1065
      size_t imagetrailer;
-
 
1066
   } ifs_offsets_t;
-
 
1067
   typedef struct ifs_s
-
 
1068
   {
-
 
1069
      buffer_t data;
-
 
1070
      ifs_offsets_t offsets;
2097
   #define PAD_OUTFILE_TO(val) do { curr_offset = ftell (fp); while (curr_offset < (val)) { putc (0, fp); curr_offset++; } } while (0)
1071
      size_t final_size; // final size: not known (because not set) until everything has been written
-
 
1072
   } ifs_t;
2098
 
1073
 
2099
   static startup_header_t startup_header = { 0 }; // output IFS's startup header
1074
   static startup_header_t startup_header = { 0 }; // output IFS's startup header
2100
   static startup_trailer_v2_t startup_trailer = { 0 }; // output IFS's startup trailer (version 2, with SHA-512 checksum and int32 checksum)
1075
   static startup_trailer_v2_t startup_trailer = { 0 }; // output IFS's startup trailer (version 2, with SHA-512 checksum and int32 checksum)
2101
   static image_header_t image_header = { 0 }; // output IFS's imagefs header
1076
   static image_header_t image_header = { 0 }; // output IFS's imagefs header
2102
   static image_trailer_v2_t image_trailer = { 0 }; // output IFS's imagefs trailer (version 2, with SHA-512 checksum and int32 checksum)
1077
   static image_trailer_v2_t image_trailer = { 0 }; // output IFS's imagefs trailer (version 2, with SHA-512 checksum and int32 checksum)
Line 2122... Line 1097...
2122
 
1097
 
2123
   char path_on_buildhost[MAXPATHLEN] = "";
1098
   char path_on_buildhost[MAXPATHLEN] = "";
2124
   char path_in_ifs[MAXPATHLEN] = "";
1099
   char path_in_ifs[MAXPATHLEN] = "";
2125
   char *ifs_pathname = NULL;
1100
   char *ifs_pathname = NULL;
2126
   void *reallocated_ptr;
1101
   void *reallocated_ptr;
2127
   const elf_header_t *elf;
-
 
2128
   elf_program_header_t *phdr;
-
 
2129
   struct tm utc_time;
1102
   struct tm utc_time;
2130
   struct stat stat_buf;
1103
   struct stat stat_buf;
2131
   size_t startuptrailer_offset;
-
 
2132
   size_t startupheader_offset;
-
 
2133
   size_t imagetrailer_offset;
-
 
2134
   size_t imageheader_offset;
-
 
2135
   size_t corrective_offset;
-
 
2136
   size_t imgdir_offset;
-
 
2137
   size_t imgdir_size;
1104
   size_t imgdir_size;
2138
   size_t final_size;
-
 
2139
   size_t available_space;
1105
   size_t available_space;
2140
   size_t allocated_size;
1106
   size_t allocated_size;
2141
   size_t fsentry_index;
1107
   size_t fsentry_index;
2142
   size_t largest_index;
1108
   size_t largest_index;
2143
   size_t largest_size;
1109
   size_t largest_size;
2144
   size_t curr_offset;
1110
   size_t curr_offset;
2145
   size_t table_index;
-
 
2146
   size_t table_count;
1111
   ifs_t ifs = { 0 };
2147
   buffer_t blob;
-
 
2148
   int32_t checksum;
1112
   int32_t checksum;
-
 
1113
   char *first_pathname = NULL;
-
 
1114
   char *second_pathname = NULL;
2149
   char *specifiedpathname_start;
1115
   char *specifiedpathname_start;
2150
   char *directiveblock_start;
1116
   char *directiveblock_start;
2151
   char *write_ptr;
1117
   char *write_ptr;
2152
   char *line_ptr;
1118
   char *line_ptr;
2153
   char *outdir = ".";
-
 
2154
   char *token;
1119
   char *token;
2155
   char *value;
1120
   char *value;
2156
   char *sep;
1121
   char *sep;
2157
   //char *ctx;
1122
   char *ctx;
2158
   int arg_index;
1123
   int arg_index;
2159
   bool is_quoted_context = false;
1124
   bool is_quoted_context = false;
2160
   bool is_escaped_char = false;
1125
   bool is_escaped_char = false;
2161
   bool should_discard_inline_contents = false;
1126
   bool should_discard_inline_contents = false;
2162
   bool want_info = false;
1127
   bool want_info = false;
2163
   bool want_everything = false;
1128
   bool want_everything = false;
2164
   bool want_help = false;
1129
   bool want_help = false;
2165
   bool want_dump = false;
1130
   bool want_dump = false;
-
 
1131
   bool want_strip = false;
2166
   bool want_hexdump = false;
1132
   bool want_hexdump = false;
2167
   bool is_foreign_endianness;
1133
   bool is_foreign_endianness;
2168
   int string_len;
1134
   int string_len;
2169
   int read_char;
1135
   int read_char;
2170
   FILE *buildfile_fp;
1136
   FILE *buildfile_fp;
2171
   FILE *fp;
-
 
2172
 
1137
 
2173
   // parse arguments
1138
   // parse arguments
2174
   for (arg_index = 1; arg_index < argc; arg_index++)
1139
   for (arg_index = 1; arg_index < argc; arg_index++)
2175
   {
1140
   {
2176
      if ((strcmp (argv[arg_index], "--bootfile") == 0) && (arg_index + 1 < argc)) // --bootfile path/to/blob.bin
1141
      if ((strcmp (argv[arg_index], "--bootfile") == 0) && (arg_index + 1 < argc)) // --bootfile path/to/blob.bin
Line 2199... Line 1164...
2199
      {
1164
      {
2200
         default_parms.mtime = 0; // *all* files should have a mtime set to zero
1165
         default_parms.mtime = 0; // *all* files should have a mtime set to zero
2201
         default_parms.mtime_for_inline_files = 0;
1166
         default_parms.mtime_for_inline_files = 0;
2202
      }
1167
      }
2203
      else if ((strcmp (argv[arg_index], "--outdir") == 0) && (arg_index + 1 < argc)) // --outdir path
1168
      else if ((strcmp (argv[arg_index], "--outdir") == 0) && (arg_index + 1 < argc)) // --outdir path
-
 
1169
         second_pathname = argv[++arg_index];
-
 
1170
      else if ((strcmp (argv[arg_index], "--outfile") == 0) && (arg_index + 1 < argc)) // --outfile pathname
2204
         outdir = argv[++arg_index];
1171
         second_pathname = argv[++arg_index];
2205
      else if (strcmp (argv[arg_index], "--info") == 0)
1172
      else if (strcmp (argv[arg_index], "--info") == 0)
2206
         want_info = true;
1173
         want_info = true;
2207
      else if (strcmp (argv[arg_index], "--dump") == 0)
1174
      else if (strcmp (argv[arg_index], "--dump") == 0)
2208
         want_dump = true;
1175
         want_dump = true;
2209
      else if (strcmp (argv[arg_index], "--hexdump") == 0) // voluntarily undocumented
1176
      else if (strcmp (argv[arg_index], "--hexdump") == 0) // voluntarily undocumented
2210
         want_hexdump = true;
1177
         want_hexdump = true;
-
 
1178
      else if (strcmp (argv[arg_index], "--strip") == 0)
-
 
1179
         want_strip = true;
2211
      else if (strcmp (argv[arg_index], "--everything") == 0)
1180
      else if (strcmp (argv[arg_index], "--everything") == 0)
2212
         want_everything = true;
1181
         want_everything = true;
2213
      else if (strncmp (argv[arg_index], "-v", 2) == 0) // -v[....]
1182
      else if (strncmp (argv[arg_index], "-v", 2) == 0) // -v[....]
2214
         verbose_level += (int) strlen (argv[arg_index] + 1); // increase verbosity by the number of characters in this flag
1183
         verbose_level += (int) strlen (argv[arg_index] + 1); // increase verbosity by the number of characters in this flag
2215
      else if ((strcmp (argv[arg_index], "-?") == 0) || (strcmp (argv[arg_index], "--help") == 0))
1184
      else if ((strcmp (argv[arg_index], "-?") == 0) || (strcmp (argv[arg_index], "--help") == 0))
2216
         want_help = true;
1185
         want_help = true;
2217
      else if (buildfile_pathname == NULL)
1186
      else if (first_pathname == NULL)
2218
         buildfile_pathname = argv[arg_index];
1187
         first_pathname = argv[arg_index];
2219
      else if (ifs_pathname == NULL)
1188
      else if (second_pathname == NULL)
2220
         ifs_pathname = argv[arg_index];
1189
         second_pathname = argv[arg_index];
-
 
1190
      else
-
 
1191
         DIE_WITH_EXITCODE (1, "unrecognized option: '%s'", argv[arg_index]);
2221
   }
1192
   }
2222
 
1193
 
2223
   // do we not have enough information to run ?
1194
   // do we not have enough information to run ?
2224
   if (want_help || (buildfile_pathname == NULL) || (!want_info && !want_dump && !want_hexdump && (ifs_pathname == NULL)))
1195
   if (want_help || (first_pathname == NULL) || (!want_info && !want_dump && !want_hexdump && !want_strip && (second_pathname == NULL)))
2225
   {
1196
   {
2226
      fp = (want_help ? stdout : stderr); // select the right output channel
1197
      FILE *out = (want_help ? stdout : stderr); // select the right output channel
2227
      fprintf (fp, "ifstool - QNX in-kernel filesystem creation utility by Pierre-Marie Baty <pm@pmbaty.com>\n");
1198
      fprintf (out, "ifstool - QNX in-kernel filesystem creation utility by Pierre-Marie Baty <pm@pmbaty.com>\n");
2228
      fprintf (fp, "          version " VERSION_FMT_YYYYMMDD "\n", VERSION_ARG_YYYYMMDD);
1199
      fprintf (out, "          version " VERSION_FMT_YYYYMMDD "\n", VERSION_ARG_YYYYMMDD);
2229
      if (!want_help)
1200
      if (!want_help)
2230
         fprintf (fp, "error: missing parameters\n");
1201
         fprintf (out, "error: missing parameters\n");
2231
      fprintf (fp, "usage:\n");
1202
      fprintf (out, "usage:\n");
2232
      fprintf (fp, "    ifstool [--bootfile <pathname>] [--startupfile <pathname>@<EP_from_imgbase>] [--kernelfile <pathname>@<fileoffs>] [-n[n]] <buildfile> <outfile>\n");
1203
      fprintf (out, "    ifstool [--bootfile <pathname>] [--startupfile <pathname>@<EP_from_imgbase>] [--kernelfile <pathname>@<fileoffs>] [-n[n]] [-v[...]] <buildfile> <outfile>\n");
2233
      fprintf (fp, "    ifstool --info [--everything] <ifs file>\n");
1204
      fprintf (out, "    ifstool --info [--everything] <ifs file>\n");
2234
      fprintf (fp, "    ifstool --dump [--outdir <path>] <ifs file>\n");
1205
      fprintf (out, "    ifstool --dump [--outdir <path>] <ifs file>\n");
-
 
1206
      fprintf (out, "    ifstool --strip [--outfile <pathname>] <ELF file>\n");
2235
      fprintf (fp, "    ifstool --help\n");
1207
      fprintf (out, "    ifstool --help\n");
2236
      fprintf (fp, "NOTE: the compilation feature requires predigested boot, startup and kernel files produced by mkifs.\n");
1208
      fprintf (out, "NOTE: the compilation feature requires predigested boot, startup and kernel files produced by mkifs.\n");
2237
      exit (want_help ? 0 : 1);
1209
      exit (want_help ? 0 : 1);
2238
   }
1210
   }
2239
 
1211
 
2240
   // do we want info about a particular IFS ? if so, dissecate it
1212
   // do we want info about a particular IFS ? if so, dissecate it
2241
   if (want_info)
1213
   if (want_info)
2242
      exit (dump_ifs_info (buildfile_pathname, want_everything)); // NOTE: the first argument after --info is actually the IFS file, not a build file, but the arguments are collected in this order
1214
      exit (dump_ifs_info (first_pathname, want_everything));
2243
 
1215
 
2244
   // else do we want to dump its contents ? if so, do so
1216
   // else do we want to dump its contents ? if so, do so
2245
   else if (want_dump)
1217
   else if (want_dump)
2246
      exit (dump_ifs_contents (buildfile_pathname, outdir)); // NOTE: the first argument after --info is actually the IFS file, not a build file, but the arguments are collected in this order
1218
      exit (dump_ifs_contents (first_pathname, (second_pathname != NULL ? second_pathname : ".")));
2247
 
1219
 
2248
   // else do we want to hex dump a file ? (this is voluntarily undocumented)
1220
   // else do we want to hex dump a file ? (this is voluntarily undocumented)
2249
   else if (want_hexdump)
1221
   else if (want_hexdump)
-
 
1222
      exit (dump_file_hex (first_pathname));
-
 
1223
 
-
 
1224
   // else do we want to strip an ELF file ? if so, do so
-
 
1225
   else if (want_strip)
2250
   {
1226
   {
-
 
1227
      buffer_t file;
2251
      if (read_filecontents (buildfile_pathname, ".", &blob) == NULL)
1228
      ASSERT (Buffer_ReadFromFile (&file, first_pathname), "can't open \"%s\" for reading: %s", first_pathname, strerror (errno));
2252
         DIE_WITH_EXITCODE (1, "can't read \"%s\": %s", buildfile_pathname, strerror (errno));
1229
      ASSERT (Buffer_StripELFFile (&file, first_pathname), "error stripping \"%s\": %s", first_pathname, strerror (errno));
2253
      hex_fprintf (stdout, blob.bytes, blob.len, 16, "%s (%zd bytes):\n", buildfile_pathname, blob.len);
1230
      ASSERT_WITH_ERRNO (Buffer_WriteToFile (&file, (second_pathname != NULL ? second_pathname : "<stdout>")));
2254
      exit (0);
1231
      exit (0);
2255
   }
1232
   }
-
 
1233
 
-
 
1234
   // we want to CREATE an IFS file
-
 
1235
   buildfile_pathname = first_pathname; // assign the pathnames properly
-
 
1236
   ifs_pathname = second_pathname;
2256
 
1237
 
2257
   // make sure we have ${QNX_TARGET} pointing somewhere
1238
   // make sure we have ${QNX_TARGET} pointing somewhere
2258
   QNX_TARGET = getenv ("QNX_TARGET");
1239
   QNX_TARGET = getenv ("QNX_TARGET");
2259
   if (QNX_TARGET == NULL)
1240
   if (QNX_TARGET == NULL)
2260
      DIE_WITH_EXITCODE (1, "the QNX_TARGET environment variable is not set");
1241
      DIE_WITH_EXITCODE (1, "the QNX_TARGET environment variable is not set");
Line 2263... Line 1244...
2263
 
1244
 
2264
   // prepare a default MKIFS_PATH assuming the host processor
1245
   // prepare a default MKIFS_PATH assuming the host processor
2265
   update_MKIFS_PATH (image_processor);
1246
   update_MKIFS_PATH (image_processor);
2266
 
1247
 
2267
   // open build file
1248
   // open build file
2268
   buildfile_fp = fopen (buildfile_pathname, "rb");
1249
   fopen_s (&buildfile_fp, buildfile_pathname, "rb");
2269
   if (buildfile_fp == NULL)
1250
   if (buildfile_fp == NULL)
2270
      DIE_WITH_EXITCODE (1, "unable to open build file \"%s\" for reading: %s", buildfile_pathname, strerror (errno));
1251
      DIE_WITH_EXITCODE (1, "unable to open build file \"%s\" for reading: %s", buildfile_pathname, strerror (errno));
2271
 
1252
 
2272
   // stack up filesystem entries
1253
   // stack up filesystem entries
2273
   memcpy (&entry_parms, &default_parms, sizeof (default_parms));
1254
   memcpy (&entry_parms, &default_parms, sizeof (default_parms));
Line 2278... Line 1259...
2278
   while (fgets (line_buffer, sizeof (line_buffer), buildfile_fp) != NULL)
1259
   while (fgets (line_buffer, sizeof (line_buffer), buildfile_fp) != NULL)
2279
   {
1260
   {
2280
      if (current_line != NULL)
1261
      if (current_line != NULL)
2281
         free (current_line);
1262
         free (current_line);
2282
      current_line = strdup (line_buffer);
1263
      current_line = strdup (line_buffer);
2283
      WELLMANNERED_ASSERT (current_line, "out of memory");
1264
      ASSERT_WITH_ERRNO (current_line);
2284
      lineno++; // keep track of current line number
1265
      lineno++; // keep track of current line number
2285
 
1266
 
2286
      line_ptr = line_buffer;
1267
      line_ptr = line_buffer;
2287
      while ((*line_ptr != 0) && isspace (*line_ptr))
1268
      while ((*line_ptr != 0) && isspace (*line_ptr))
2288
         line_ptr++; // skip leading spaces
1269
         line_ptr++; // skip leading spaces
Line 2309... Line 1290...
2309
         while ((*line_ptr != 0) && !((*line_ptr == ']') && (line_ptr[-1] != '\\') && !is_quoted_context))
1290
         while ((*line_ptr != 0) && !((*line_ptr == ']') && (line_ptr[-1] != '\\') && !is_quoted_context))
2310
         {
1291
         {
2311
            if (*line_ptr == '"')
1292
            if (*line_ptr == '"')
2312
               is_quoted_context ^= true; // remember when we're between quotes
1293
               is_quoted_context ^= true; // remember when we're between quotes
2313
            else if (!is_quoted_context && (*line_ptr == ' '))
1294
            else if (!is_quoted_context && (*line_ptr == ' '))
2314
               *line_ptr = RECORD_SEP; // turn all spaces outside quoted contexts into an ASCII record separator to ease token splitting
1295
               *line_ptr = RECORD_SEP[0]; // turn all spaces outside quoted contexts into an ASCII record separator to ease token splitting
2315
            line_ptr++; // reach the next unescaped closing square bracket
1296
            line_ptr++; // reach the next unescaped closing square bracket
2316
         }
1297
         }
2317
         if (*line_ptr != ']')
1298
         if (*line_ptr != ']')
2318
         {
1299
         {
2319
            LOG ("warning", 0, "syntax error in \"%s\" line %d: unterminated attributes block (skipping)", buildfile_pathname, lineno);
1300
            LOG ("warning", 0, "syntax error in \"%s\" line %d: unterminated attributes block (skipping)", buildfile_pathname, lineno);
Line 2321... Line 1302...
2321
         }
1302
         }
2322
         *line_ptr = 0; // end the attribute block so that it is a parsable C string
1303
         *line_ptr = 0; // end the attribute block so that it is a parsable C string
2323
 
1304
 
2324
         // now parse the attribute tokens
1305
         // now parse the attribute tokens
2325
         // DOCUMENTATION: https://www.qnx.com/developers/docs/8.0/com.qnx.doc.neutrino.utilities/topic/m/mkifs.html#mkifs__description
1306
         // DOCUMENTATION: https://www.qnx.com/developers/docs/8.0/com.qnx.doc.neutrino.utilities/topic/m/mkifs.html#mkifs__description
2326
         token = strtok (directiveblock_start, RECORD_SEP_STR);
1307
         token = strtok_r (directiveblock_start, RECORD_SEP, &ctx);
2327
         while (token != NULL)
1308
         while (token != NULL)
2328
         {
1309
         {
2329
            // evaluate attribute token
1310
            // evaluate attribute token
2330
            #define REACH_TOKEN_VALUE() do { value = strchr (token, '=') + 1; if (*value == '"') value++; } while (0)
1311
            #define REACH_TOKEN_VALUE() do { value = strchr (token, '=') + 1; if (*value == '"') value++; } while (0)
2331
            if      (strncmp (token, "uid=",     4) == 0) { REACH_TOKEN_VALUE (); entry_parms.uid     = (int) read_integer (value); }
1312
            if      (strncmp (token, "uid=",     4) == 0) { REACH_TOKEN_VALUE (); entry_parms.uid     = (int) read_integer (value); }
Line 2337... Line 1318...
2337
               else if (strcmp (value, "file") == 0) entry_parms.st_mode = S_IFREG;
1318
               else if (strcmp (value, "file") == 0) entry_parms.st_mode = S_IFREG;
2338
               else if (strcmp (value, "link") == 0) entry_parms.st_mode = S_IFLNK;
1319
               else if (strcmp (value, "link") == 0) entry_parms.st_mode = S_IFLNK;
2339
               else if (strcmp (value, "fifo") == 0) entry_parms.st_mode = S_IFIFO;
1320
               else if (strcmp (value, "fifo") == 0) entry_parms.st_mode = S_IFIFO;
2340
               else DIE_WITH_EXITCODE (1, "invalid 'type' attribute in \"%s\" line %d: '%s'", buildfile_pathname, lineno, value);
1321
               else DIE_WITH_EXITCODE (1, "invalid 'type' attribute in \"%s\" line %d: '%s'", buildfile_pathname, lineno, value);
2341
            }
1322
            }
2342
            else if (strncmp (token, "prefix=",  7) == 0) { REACH_TOKEN_VALUE (); strcpy (entry_parms.prefix, (*value == '/' ? value + 1 : value)); } // skip possible leading slash in prefix
1323
            else if (strncmp (token, "prefix=",  7) == 0) { REACH_TOKEN_VALUE (); strcpy_s (entry_parms.prefix, sizeof (entry_parms.prefix), (*value == '/' ? value + 1 : value)); } // skip possible leading slash in prefix
2343
            else if (strncmp (token, "image=",   6) == 0) { REACH_TOKEN_VALUE ();
1324
            else if (strncmp (token, "image=",   6) == 0) { REACH_TOKEN_VALUE ();
2344
               image_base = (uint32_t) read_integer (value); // read image base address
1325
               image_base = (uint32_t) read_integer (value); // read image base address
2345
               if ((sep = strchr (value, '-')) != NULL) image_end       = (uint32_t) read_integer (sep + 1); // if we have a dash, read optional image end (TODO: check this value and produce an error in the relevant case. Not important.)
1326
               if ((sep = strchr (value, '-')) != NULL) image_end       = (uint32_t) read_integer (sep + 1); // if we have a dash, read optional image end (TODO: check this value and produce an error in the relevant case. Not important.)
2346
               if ((sep = strchr (value, ',')) != NULL) image_maxsize   = (uint32_t) read_integer (sep + 1); // if we have a comma, read optional image max size
1327
               if ((sep = strchr (value, ',')) != NULL) image_maxsize   = (uint32_t) read_integer (sep + 1); // if we have a comma, read optional image max size
2347
               if ((sep = strchr (value, '=')) != NULL) image_totalsize = (uint32_t) read_integer (sep + 1); // if we have an equal sign, read optional image padding size
1328
               if ((sep = strchr (value, '=')) != NULL) image_totalsize = (uint32_t) read_integer (sep + 1); // if we have an equal sign, read optional image padding size
Line 2352... Line 1333...
2352
               if ((bootfile_pathname == NULL) || (startupfile_pathname == NULL) || (kernelfile_pathname == NULL)) // HACK until I figure out how to re-create them
1333
               if ((bootfile_pathname == NULL) || (startupfile_pathname == NULL) || (kernelfile_pathname == NULL)) // HACK until I figure out how to re-create them
2353
                  DIE_WITH_EXITCODE (1, "creating bootable images require the --bootfile, --startupfile and --kernelfile command-line options in \"%s\" line %d", buildfile_pathname, lineno);
1334
                  DIE_WITH_EXITCODE (1, "creating bootable images require the --bootfile, --startupfile and --kernelfile command-line options in \"%s\" line %d", buildfile_pathname, lineno);
2354
               if ((sep = strchr (value, ',')) != NULL) // do we have a comma separating (optional) processor and boot file name ?
1335
               if ((sep = strchr (value, ',')) != NULL) // do we have a comma separating (optional) processor and boot file name ?
2355
               {
1336
               {
2356
                  *sep = 0;
1337
                  *sep = 0;
2357
                  strcpy (image_processor, value); // save processor
1338
                  strcpy_s (image_processor, sizeof (image_processor), value); // save processor
2358
                  update_MKIFS_PATH (image_processor);
1339
                  update_MKIFS_PATH (image_processor);
2359
                  value = sep + 1;
1340
                  value = sep + 1;
2360
               }
1341
               }
2361
               //sprintf (image_bootfile, "%s/%s/boot/sys/%s.boot", QNX_TARGET, image_processor, value); // save preboot file name (TODO: we should search in MKIFS_PATH instead of this. Not important.)
1342
               //sprintf (image_bootfile, "%s/%s/boot/sys/%s.boot", QNX_TARGET, image_processor, value); // save preboot file name (TODO: we should search in MKIFS_PATH instead of this. Not important.)
2362
               //strcpy (image_bootfile, bootfile_pathname); // FIXME: HACK
1343
               //strcpy (image_bootfile, bootfile_pathname); // FIXME: HACK
Line 2367... Line 1348...
2367
#if 1
1348
#if 1
2368
               // ######################################################################################################################################################################################################################################
1349
               // ######################################################################################################################################################################################################################################
2369
               // # FIXME: figure out how to re-create it: linker call involved
1350
               // # FIXME: figure out how to re-create it: linker call involved
2370
               // # $ x86_64-pc-nto-qnx8.0.0-ld --sysroot=${QNX_TARGET}/x86_64/ -T${QNX_TARGET}/x86_64/lib/nto.link --section-start .text=0xffff800000001000 --no-relax ${QNX_TARGET}/x86_64/boot/sys/procnto-smp-instr -o procnto-smp-instr.sym.UNSTRIPPED
1351
               // # $ x86_64-pc-nto-qnx8.0.0-ld --sysroot=${QNX_TARGET}/x86_64/ -T${QNX_TARGET}/x86_64/lib/nto.link --section-start .text=0xffff800000001000 --no-relax ${QNX_TARGET}/x86_64/boot/sys/procnto-smp-instr -o procnto-smp-instr.sym.UNSTRIPPED
2371
               // ######################################################################################################################################################################################################################################
1352
               // ######################################################################################################################################################################################################################################
2372
//               if (read_filecontents (kernelfile_pathname, ".", &entry_parms.data) == NULL)
1353
//               if (!Buffer_ReadFromFile (&entry_parms.data, kernelfile_pathname))
2373
//                  DIE_WITH_EXITCODE (1, "unable to read precompiled kernel file \"%s\" specified in --kernelfile argument: %s", kernelfile_pathname, strerror (errno));
1354
//                  DIE_WITH_EXITCODE (1, "unable to read precompiled kernel file \"%s\" specified in --kernelfile argument: %s", kernelfile_pathname, strerror (errno));
2374
#else // nonworking
1355
#else // nonworking
2375
               strcpy (path_on_buildhost, "procnto-smp-instr");
1356
               strcpy (path_on_buildhost, "procnto-smp-instr");
2376
#endif // nonworking
1357
#endif // nonworking
2377
            }
1358
            }
2378
            else if (strncmp (token, "mtime=", 6) == 0) { REACH_TOKEN_VALUE (); if (strcmp (value, "*") == 0) entry_parms.mtime = UINT32_MAX; else {
1359
            else if (strncmp (token, "mtime=", 6) == 0) { REACH_TOKEN_VALUE (); if (strcmp (value, "*") == 0) entry_parms.mtime = UINT32_MAX; else {
2379
                  // value *must* be "YYYY-MM-DD-HH:MM:SS" by specification
1360
                  // value *must* be "YYYY-MM-DD-HH:MM:SS" by specification
2380
                  memset (&utc_time, 0, sizeof (utc_time));
1361
                  memset (&utc_time, 0, sizeof (utc_time));
2381
                  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)
1362
                  if (sscanf_s (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)
2382
                  {
1363
                  {
2383
                     LOG_WARNING ("syntax error in \"%s\" line %d: mtime specification not in YYYY-MM-DD-HH:MM:SS format (skipping)", buildfile_pathname, lineno);
1364
                     LOG_WARNING ("syntax error in \"%s\" line %d: mtime specification not in YYYY-MM-DD-HH:MM:SS format (skipping)", buildfile_pathname, lineno);
2384
                     continue; // invalid attribute block, skip line
1365
                     continue; // invalid attribute block, skip line
2385
                  }
1366
                  }
2386
                  utc_time.tm_mon--; // convert month from [1-12] to [0-11]
1367
                  utc_time.tm_mon--; // convert month from [1-12] to [0-11]
2387
                  entry_parms.mtime = (uint32_t) mktime (&utc_time);
1368
                  entry_parms.mtime = (uint32_t) mktime (&utc_time);
2388
               }
1369
               }
2389
            }
1370
            }
2390
            else if (strcmp (token, "+script")     == 0) {
1371
            else if (strcmp (token, "+script")     == 0) {
2391
               entry_parms.is_compiled_bootscript = true;
1372
               entry_parms.is_compiled_bootscript = true;
2392
               entry_parms.data.bytes = malloc (sizeof (INITIAL_STARTUP_SCRIPT) - 1);
-
 
2393
               WELLMANNERED_ASSERT (entry_parms.data.bytes, "out of memory");
-
 
2394
               memcpy (entry_parms.data.bytes, INITIAL_STARTUP_SCRIPT, sizeof (INITIAL_STARTUP_SCRIPT) - 1); // FIXME: HACK until the script compiler is implemented
1373
               ASSERT_WITH_ERRNO (Buffer_InitWithByteArray (&entry_parms.data, INITIAL_STARTUP_SCRIPT)); // FIXME: HACK until the script compiler is implemented
2395
               entry_parms.data.len = sizeof (INITIAL_STARTUP_SCRIPT) - 1;
-
 
2396
               should_discard_inline_contents = true; // remember we already have data (so as to discard the inline block's contents)
1374
               should_discard_inline_contents = true; // remember we already have data (so as to discard the inline block's contents)
2397
            }
1375
            }
2398
            else if (strcmp (token, "-script")     == 0) entry_parms.is_compiled_bootscript = false;
1376
            else if (strcmp (token, "-script")     == 0) entry_parms.is_compiled_bootscript = false;
2399
            else if (strcmp (token, "+followlink") == 0) entry_parms.should_follow_symlinks = true;
1377
            else if (strcmp (token, "+followlink") == 0) entry_parms.should_follow_symlinks = true;
2400
            else if (strcmp (token, "-followlink") == 0) entry_parms.should_follow_symlinks = false;
1378
            else if (strcmp (token, "-followlink") == 0) entry_parms.should_follow_symlinks = false;
Line 2403... Line 1381...
2403
            else if (strcmp (token, "+keeplinked") == 0) entry_parms.should_keep_ld_output = true;
1381
            else if (strcmp (token, "+keeplinked") == 0) entry_parms.should_keep_ld_output = true;
2404
            else if (strcmp (token, "-keeplinked") == 0) entry_parms.should_keep_ld_output = false;
1382
            else if (strcmp (token, "-keeplinked") == 0) entry_parms.should_keep_ld_output = false;
2405
            else LOG_WARNING ("unimplemented attribute in \"%s\" line %d: '%s'", buildfile_pathname, lineno, token);
1383
            else LOG_WARNING ("unimplemented attribute in \"%s\" line %d: '%s'", buildfile_pathname, lineno, token);
2406
            #undef REACH_TOKEN_VALUE
1384
            #undef REACH_TOKEN_VALUE
2407
 
1385
 
2408
            token = strtok (NULL, RECORD_SEP_STR); // proceed to next attribute token
1386
            token = strtok_r (NULL, RECORD_SEP, &ctx); // proceed to next attribute token
2409
         }
1387
         }
2410
 
1388
 
2411
         line_ptr++; // reach the next character
1389
         line_ptr++; // reach the next character
2412
         while ((*line_ptr != 0) && isspace (*line_ptr))
1390
         while ((*line_ptr != 0) && isspace (*line_ptr))
2413
            line_ptr++; // skip leading spaces
1391
            line_ptr++; // skip leading spaces
Line 2419... Line 1397...
2419
                  LOG_INFO ("changing default " descr " from " fmt " to " fmt " by attribute at \"%s\" line %d", default_parms.attr, entry_parms.attr, buildfile_pathname, lineno); \
1397
                  LOG_INFO ("changing default " descr " from " fmt " to " fmt " by attribute at \"%s\" line %d", default_parms.attr, entry_parms.attr, buildfile_pathname, lineno); \
2420
                  default_parms.attr = entry_parms.attr; \
1398
                  default_parms.attr = entry_parms.attr; \
2421
               } } while (0)
1399
               } } while (0)
2422
            #define APPLY_DEFAULT_ATTR_STR(attr,descr,fmt) do { if (strcmp (entry_parms.attr, default_parms.attr) != 0) { \
1400
            #define APPLY_DEFAULT_ATTR_STR(attr,descr,fmt) do { if (strcmp (entry_parms.attr, default_parms.attr) != 0) { \
2423
                  LOG_INFO ("changing default " descr " from " fmt " to " fmt " by attribute at \"%s\" line %d", default_parms.attr, entry_parms.attr, buildfile_pathname, lineno); \
1401
                  LOG_INFO ("changing default " descr " from " fmt " to " fmt " by attribute at \"%s\" line %d", default_parms.attr, entry_parms.attr, buildfile_pathname, lineno); \
2424
                  strcpy (default_parms.attr, entry_parms.attr); \
1402
                  strcpy_s (default_parms.attr, sizeof (default_parms.attr), entry_parms.attr); \
2425
               } } while (0)
1403
               } } while (0)
2426
            APPLY_DEFAULT_ATTR_NUM (dperms,                   "directory permissions",           "0%o");
1404
            APPLY_DEFAULT_ATTR_NUM (dperms,                   "directory permissions",           "0%o");
2427
            APPLY_DEFAULT_ATTR_NUM (perms,                    "file permissions",                "0%o");
1405
            APPLY_DEFAULT_ATTR_NUM (perms,                    "file permissions",                "0%o");
2428
            APPLY_DEFAULT_ATTR_NUM (uid,                      "owner ID",                        "%d");
1406
            APPLY_DEFAULT_ATTR_NUM (uid,                      "owner ID",                        "%d");
2429
            APPLY_DEFAULT_ATTR_NUM (gid,                      "group ID",                        "%d");
1407
            APPLY_DEFAULT_ATTR_NUM (gid,                      "group ID",                        "%d");
Line 2439... Line 1417...
2439
         }
1417
         }
2440
         // end of attributes parsing
1418
         // end of attributes parsing
2441
      } // end of "this line starts with an attributes block"
1419
      } // end of "this line starts with an attributes block"
2442
 
1420
 
2443
      // there's data in this line. We expect a filename in the IFS. Read it and unescape escaped characters
1421
      // there's data in this line. We expect a filename in the IFS. Read it and unescape escaped characters
2444
      string_len = sprintf (path_in_ifs, "%s", entry_parms.prefix);
1422
      string_len = sprintf_s (path_in_ifs, sizeof (path_in_ifs), "%s", entry_parms.prefix);
2445
      while ((string_len > 0) && (path_in_ifs[string_len - 1] == '/'))
1423
      while ((string_len > 0) && (path_in_ifs[string_len - 1] == '/'))
2446
         string_len--; // chop off any trailing slashes from prefix
1424
         string_len--; // chop off any trailing slashes from prefix
2447
      write_ptr = &path_in_ifs[string_len];
1425
      write_ptr = &path_in_ifs[string_len];
2448
      *write_ptr++ = '/'; // add ONE trailing slash
1426
      *write_ptr++ = '/'; // add ONE trailing slash
2449
      specifiedpathname_start = write_ptr; // remember the specified pathname will start here
1427
      specifiedpathname_start = write_ptr; // remember the specified pathname will start here
Line 2506... Line 1484...
2506
               else
1484
               else
2507
               {
1485
               {
2508
                  is_escaped_char = false; // any other char, meaning the next one will not be escaped
1486
                  is_escaped_char = false; // any other char, meaning the next one will not be escaped
2509
                  if (!should_discard_inline_contents) // only store the contents if we do NOT know the data yet
1487
                  if (!should_discard_inline_contents) // only store the contents if we do NOT know the data yet
2510
                  {
1488
                  {
2511
                     if (entry_parms.data.len == allocated_size) // reallocate in 4 kb blocks
1489
                     if (entry_parms.data.size == allocated_size) // reallocate in 4 kb blocks
2512
                     {
1490
                     {
2513
                        reallocated_ptr = realloc (entry_parms.data.bytes, allocated_size + 4096);
1491
                        reallocated_ptr = realloc (entry_parms.data.bytes, allocated_size + 4096);
2514
                        WELLMANNERED_ASSERT (reallocated_ptr != NULL, "out of memory");
1492
                        ASSERT_WITH_ERRNO (reallocated_ptr);
2515
                        entry_parms.data.bytes = reallocated_ptr;
1493
                        entry_parms.data.bytes = reallocated_ptr;
2516
                        allocated_size += 4096;
1494
                        allocated_size += 4096;
2517
                     }
1495
                     }
2518
                     entry_parms.data.bytes[entry_parms.data.len++] = read_char;
1496
                     entry_parms.data.bytes[entry_parms.data.size++] = read_char;
2519
                  }
1497
                  }
2520
                  if (read_char == '\n')
1498
                  if (read_char == '\n')
2521
                     lineno++; // update line counter as we parse the inline content
1499
                     lineno++; // update line counter as we parse the inline content
2522
               }
1500
               }
2523
            } // end for
1501
            } // end for
Line 2543... Line 1521...
2543
            *write_ptr = 0; // terminate the string
1521
            *write_ptr = 0; // terminate the string
2544
            if (is_quoted_context && (*line_ptr == '"'))
1522
            if (is_quoted_context && (*line_ptr == '"'))
2545
               line_ptr++; // skip a possible final quote
1523
               line_ptr++; // skip a possible final quote
2546
 
1524
 
2547
            if (S_ISLNK (entry_parms.st_mode)) // are we storing a symlink ?
1525
            if (S_ISLNK (entry_parms.st_mode)) // are we storing a symlink ?
2548
            {
-
 
2549
               entry_parms.data.bytes = strdup (specifiedpathname_start); // if so, store the symlink target as the dirent's blob data
1526
               ASSERT_WITH_ERRNO (Buffer_InitWithCString (&entry_parms.data, specifiedpathname_start)); // if so, store the symlink target as the dirent's blob data
2550
               WELLMANNERED_ASSERT (entry_parms.data.bytes != NULL, "out of memory");
-
 
2551
               entry_parms.data.len = strlen (specifiedpathname_start);
-
 
2552
            }
-
 
2553
            else // it's a build host filesystem path
1527
            else // it's a build host filesystem path
2554
               strcpy (path_on_buildhost, line_ptr); // the path on the build host is given after the equal sign
1528
               strcpy_s (path_on_buildhost, sizeof (path_on_buildhost), specifiedpathname_start); // the path on the build host is given after the equal sign
2555
         }
1529
         }
2556
      }
1530
      }
2557
      else // no equal sign, meaning the file will have the same name on the build host filesystem
1531
      else // no equal sign, meaning the file will have the same name on the build host filesystem
2558
      {
1532
      {
2559
         // consistency check: symlinks MUST have an equal sign
1533
         // consistency check: symlinks MUST have an equal sign
Line 2561... Line 1535...
2561
         {
1535
         {
2562
            LOG_WARNING ("syntax error in \"%s\" line %d: missing equal sign and symlink target (skipping)", buildfile_pathname, lineno);
1536
            LOG_WARNING ("syntax error in \"%s\" line %d: missing equal sign and symlink target (skipping)", buildfile_pathname, lineno);
2563
            continue; // invalid symlink specification, skip line
1537
            continue; // invalid symlink specification, skip line
2564
         }
1538
         }
2565
 
1539
 
2566
         strcpy (path_on_buildhost, specifiedpathname_start); // the path on the build host is the one specified
1540
         strcpy_s (path_on_buildhost, sizeof (path_on_buildhost), specifiedpathname_start); // the path on the build host is the one specified
2567
         sep = strrchr (specifiedpathname_start, '/');
1541
         sep = strrchr (specifiedpathname_start, '/');
2568
         if (sep != NULL)
1542
         if (sep != NULL)
2569
            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)
1543
            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)
2570
      }
1544
      }
2571
 
1545
 
Line 2581... Line 1555...
2581
 
1555
 
2582
      if (entry_parms.data.bytes != NULL)
1556
      if (entry_parms.data.bytes != NULL)
2583
         free (entry_parms.data.bytes); // if blob data was allocated, free it
1557
         free (entry_parms.data.bytes); // if blob data was allocated, free it
2584
   }
1558
   }
2585
 
1559
 
2586
   // write IFS file
1560
   fclose (buildfile_fp); // finished parsing the build file
-
 
1561
 
2587
   fp = fopen (ifs_pathname, "w+b");
1562
   //////////////////////////////////
2588
   if (fp == NULL)
1563
   // start constructing the IFS file
-
 
1564
 
2589
      DIE_WITH_EXITCODE (1, "failed to open \"%s\" for writing: %s", ifs_pathname, strerror (errno));
1565
   Buffer_Initialize (&ifs.data);
2590
 
1566
 
2591
   // do we have a startup file ? if so, this is a bootable image
1567
   // do we have a startup file ? if so, this is a bootable image
2592
   if (startupfile_pathname != NULL)
1568
   if (startupfile_pathname != NULL)
2593
   {
1569
   {
2594
      // write boot prefix
1570
      // write boot prefix
2595
      // ######################################################################################################################################################################################################################################
1571
      // ######################################################################################################################################################################################################################################
2596
      // # FIXME: figure out how to re-create it
1572
      // # FIXME: figure out how to re-create it
2597
      // ######################################################################################################################################################################################################################################
1573
      // ######################################################################################################################################################################################################################################
-
 
1574
      buffer_t file;
2598
      fwrite_filecontents (bootfile_pathname, fp);
1575
      if (!Buffer_ReadFromFile (&file, bootfile_pathname))
-
 
1576
         DIE_WITH_EXITCODE (1, "failed to open \"%s\" for reading: %s", bootfile_pathname, strerror (errno));
-
 
1577
      ASSERT_WITH_ERRNO (Buffer_AppendBuffer (&ifs.data, &file)); // write boot blob
-
 
1578
      Buffer_Forget (&file);
2599
      PAD_OUTFILE_TO (ROUND_TO_UPPER_MULTIPLE (ftell (fp), image_align)); // pad as necessary
1579
      ASSERT_WITH_ERRNO (Buffer_PadWithZeroesTo (&ifs.data, ROUND_TO_UPPER_MULTIPLE (ifs.data.size, image_align))); // pad as necessary
2600
 
1580
 
2601
      startupheader_offset = ftell (fp); // save startup header offset
1581
      ifs.offsets.startupheader = ifs.data.size; // save startup header offset for future use
2602
      memset (&startup_header, 0, sizeof (startup_header)); // prepare startup header
1582
      memset (&startup_header, 0, sizeof (startup_header)); // prepare startup header
2603
      memcpy (startup_header.signature, "\xeb\x7e\xff\x00", 4); // startup header signature, i.e. 0xff7eeb
1583
      memcpy (startup_header.signature, "\xeb\x7e\xff\x00", 4); // startup header signature, i.e. 0xff7eeb
2604
      startup_header.version       = 1;
1584
      startup_header.version       = 1;
2605
      startup_header.flags1        = STARTUP_HDR_FLAGS1_VIRTUAL | STARTUP_HDR_FLAGS1_TRAILER_V2; // flags, 0x21 (STARTUP_HDR_FLAGS1_VIRTUAL | STARTUP_HDR_FLAGS1_TRAILER_V2)
1585
      startup_header.flags1        = STARTUP_HDR_FLAGS1_VIRTUAL | STARTUP_HDR_FLAGS1_TRAILER_V2; // flags, 0x21 (STARTUP_HDR_FLAGS1_VIRTUAL | STARTUP_HDR_FLAGS1_TRAILER_V2)
2606
      startup_header.header_size   = sizeof (startup_header); // 256
1586
      startup_header.header_size   = sizeof (startup_header); // 256
Line 2616... Line 1596...
2616
      startup_header.ram_size      = WILL_BE_FILLED_LATER;                                  // [ S] Amount of RAM used by the startup program and executables contained in the file system, here 0x00cd6128 i.e. 13 459 752 dec. which is 13 Mb. i.e. IFS file size minus 0x9eee (40686)
1596
      startup_header.ram_size      = WILL_BE_FILLED_LATER;                                  // [ S] Amount of RAM used by the startup program and executables contained in the file system, here 0x00cd6128 i.e. 13 459 752 dec. which is 13 Mb. i.e. IFS file size minus 0x9eee (40686)
2617
      startup_header.startup_size  = WILL_BE_FILLED_LATER;                                  // [I ] Size of startup (never compressed), here 0x02f148 or 192 840 bytes
1597
      startup_header.startup_size  = WILL_BE_FILLED_LATER;                                  // [I ] Size of startup (never compressed), here 0x02f148 or 192 840 bytes
2618
      startup_header.stored_size   = WILL_BE_FILLED_LATER;                                  // [I ] Size of entire image, here 0x00cd6128 (same as ram_size)
1598
      startup_header.stored_size   = WILL_BE_FILLED_LATER;                                  // [I ] Size of entire image, here 0x00cd6128 (same as ram_size)
2619
      startup_header.imagefs_size  = WILL_BE_FILLED_LATER;                                  // [ S] Size of uncompressed imagefs, here 0x00ca6fe0 or 13 266 912 bytes
1599
      startup_header.imagefs_size  = WILL_BE_FILLED_LATER;                                  // [ S] Size of uncompressed imagefs, here 0x00ca6fe0 or 13 266 912 bytes
2620
      startup_header.preboot_size  = (uint16_t) bootfile_size;                              // [I ] Size of loaded before header, here 0xf30 or 3888 bytes (size of "bios.boot" file))
1600
      startup_header.preboot_size  = (uint16_t) bootfile_size;                              // [I ] Size of loaded before header, here 0xf30 or 3888 bytes (size of "bios.boot" file))
2621
      fwrite_or_die (&startup_header, 1, sizeof (startup_header), fp); // write startup header
1601
      ASSERT_WITH_ERRNO (Buffer_Append (&ifs.data, &startup_header, sizeof (startup_header))); // write startup header
2622
      PAD_OUTFILE_TO (ROUND_TO_UPPER_MULTIPLE (ftell (fp), image_align)); // pad as necessary
1602
      ASSERT_WITH_ERRNO (Buffer_PadWithZeroesTo (&ifs.data, ROUND_TO_UPPER_MULTIPLE (ifs.data.size, image_align))); // pad as necessary
2623
 
1603
 
2624
      // ######################################################################################################################################################################################################################################
1604
      // ######################################################################################################################################################################################################################################
2625
      // # FIXME: figure out how to re-create it:
1605
      // # FIXME: figure out how to re-create it:
2626
      // first: open "startup-x86" ELF file,
1606
      // first: open "startup-x86" ELF file,
2627
      //        lookup section headers table (there is no program headers table in this one)
1607
      //        lookup section headers table (there is no program headers table in this one)
2628
      //        FIXME: figure out something in there where the result is 0x1401030 !!!
1608
      //        FIXME: figure out something in there where the result is 0x1401030 !!!
2629
      // then: call the linker: ld --sysroot=${QNX_TARGET}/x86_64/ -T${QNX_TARGET}/x86_64/lib/nto.link --section-start .text=0x1401030 --no-relax ${QNX_TARGET}/x86_64/boot/sys/startup-x86 -o startup.bin.UNSTRIPPED
1609
      // then: call the linker: ld --sysroot=${QNX_TARGET}/x86_64/ -T${QNX_TARGET}/x86_64/lib/nto.link --section-start .text=0x1401030 --no-relax ${QNX_TARGET}/x86_64/boot/sys/startup-x86 -o startup.bin.UNSTRIPPED
2630
      // then: parse resulting ELF file, take all program segments and concatenate them --> this is the blob (FIXME: wrong?)
1610
      // then: parse resulting ELF file, take all program segments and concatenate them --> this is the blob (FIXME: wrong?)
2631
      // ######################################################################################################################################################################################################################################
1611
      // ######################################################################################################################################################################################################################################
2632
#if 0 // nonworking
1612
#if 0 // nonworking
2633
      {
-
 
2634
         buffer_t startupfile;
-
 
2635
         elf_section_header_t *shdr_text;
-
 
2636
         size_t segment_len;
-
 
2637
FILE *control_fp = fopen ("startup.bin.MYSTRIPPED", "wb");
-
 
2638
 
-
 
2639
         if (read_filecontents ("startup.bin.UNSTRIPPED", MKIFS_PATH, &startupfile) == NULL)
-
 
2640
            DIE_WITH_EXITCODE (1, "couldn't read startup-x86");
-
 
2641
         elf = (elf_header_t *) startupfile.bytes; // quick access to ELF header
-
 
2642
         table_count = ELF_GET_NUMERIC (elf, elf, program_header_table_len); // get the number of program headers
-
 
2643
         for (table_index = 0; table_index < table_count; table_index++) // cycle through program headers
-
 
2644
         {
-
 
2645
            phdr = (elf_program_header_t *) &startupfile.bytes[ELF_GET_NUMERIC (elf, elf, program_header_table_offset) + (size_t) ELF_GET_NUMERIC (elf, elf, program_header_item_size) * table_index]; // quick access to program header
-
 
2646
            segment_len = ELF_GET_NUMERIC (elf, phdr, size_in_file);
-
 
2647
            fwrite_or_die (&startupfile.bytes[ELF_GET_NUMERIC (elf, phdr, file_offset)], 1, segment_len, fp); // dump program segment
-
 
2648
fwrite_or_die (&startupfile.bytes[ELF_GET_NUMERIC (elf, phdr, file_offset)], 1, segment_len, control_fp); // dump program segment
-
 
2649
while (segment_len % 4096 > 0)
-
 
2650
{
-
 
2651
   fputc (0, control_fp);
-
 
2652
   segment_len++;
1613
      // <deleted>
2653
}
-
 
2654
         }
-
 
2655
 
-
 
2656
fclose (control_fp);
-
 
2657
         free (startupfile.bytes);
-
 
2658
      }
-
 
2659
#else // working
1614
#else // working
-
 
1615
      if (!Buffer_ReadFromFile (&file, startupfile_pathname))
-
 
1616
         DIE_WITH_EXITCODE (1, "failed to open \"%s\" for reading: %s", startupfile_pathname, strerror (errno));
2660
      fwrite_filecontents (startupfile_pathname, fp); // write startup code from blob file
1617
      ASSERT_WITH_ERRNO (Buffer_AppendBuffer (&ifs.data, &file)); // write startup blob
-
 
1618
      Buffer_Forget (&file);
2661
#endif // working
1619
#endif // working
2662
      PAD_OUTFILE_TO (ROUND_TO_UPPER_MULTIPLE (ftell (fp), image_align)); // pad as necessary
1620
      ASSERT_WITH_ERRNO (Buffer_PadWithZeroesTo (&ifs.data, ROUND_TO_UPPER_MULTIPLE (ifs.data.size, image_align))); // pad as necessary
2663
 
1621
 
2664
      startuptrailer_offset = ftell (fp); // save startup trailer offset
1622
      ifs.offsets.startuptrailer = ifs.data.size; // save startup trailer offset for future use
2665
      fwrite_or_die (&startup_trailer, 1, sizeof (startup_trailer), fp); // write startup trailer
1623
      ASSERT_WITH_ERRNO (Buffer_Append (&ifs.data, &startup_trailer, sizeof (startup_trailer))); // write startup trailer
2666
      PAD_OUTFILE_TO (ROUND_TO_UPPER_MULTIPLE (ftell (fp), image_align)); // pad as necessary
1624
      ASSERT_WITH_ERRNO (Buffer_PadWithZeroesTo (&ifs.data, ROUND_TO_UPPER_MULTIPLE (ifs.data.size, image_align))); // pad as necessary
2667
   }
1625
   }
2668
 
1626
 
2669
   imageheader_offset = ftell (fp); // save image header offset
1627
   ifs.offsets.imageheader = ifs.data.size; // save image header offset for future use
2670
   memset (&image_header, 0, sizeof (image_header)); // prepare image header
1628
   memset (&image_header, 0, sizeof (image_header)); // prepare image header
2671
   memcpy (&image_header.signature, "imagefs", 7); // image filesystem signature, i.e. "imagefs"
1629
   memcpy (&image_header.signature, "imagefs", 7); // image filesystem signature, i.e. "imagefs"
2672
   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)
1630
   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)
2673
   image_header.image_size    = WILL_BE_FILLED_LATER; // size from header to end of trailer (here 0xca6fe0 or 13 266 912)
1631
   image_header.image_size    = WILL_BE_FILLED_LATER; // size from header to end of trailer (here 0xca6fe0 or 13 266 912)
2674
   image_header.hdr_dir_size  = WILL_BE_FILLED_LATER; // size from header to last dirent (here 0x12b8 or 4792)
1632
   image_header.hdr_dir_size  = WILL_BE_FILLED_LATER; // size from header to last dirent (here 0x12b8 or 4792)
2675
   image_header.dir_offset    = sizeof (image_header); // offset from header to first dirent (here 0x5c or 92)
1633
   image_header.dir_offset    = sizeof (image_header); // offset from header to first dirent (here 0x5c or 92)
2676
   image_header.boot_ino[0]   = image_kernel_ino; // inode of files for bootstrap p[ro?]g[ra?]ms (here 0xa0000002, 0, 0, 0)
1634
   image_header.boot_ino[0]   = image_kernel_ino; // inode of files for bootstrap p[ro?]g[ra?]ms (here 0xa0000002, 0, 0, 0)
2677
   image_header.script_ino    = image_bootscript_ino; // inode of file for script (here 3)
1635
   image_header.script_ino    = image_bootscript_ino; // inode of file for script (here 3)
2678
   image_header.mountpoint[0] = '/'; // default mountpoint for image ("/" + "\0\0\0")
1636
   image_header.mountpoint[0] = '/'; // default mountpoint for image ("/" + "\0\0\0")
2679
   fwrite_or_die (&image_header, 1, sizeof (image_header), fp); // write image header
1637
   ASSERT_WITH_ERRNO (Buffer_Append (&ifs.data, &image_header, sizeof (image_header))); // write image header
2680
   PAD_OUTFILE_TO (ROUND_TO_UPPER_MULTIPLE (ftell (fp), image_align)); // pad as necessary
1638
   ASSERT_WITH_ERRNO (Buffer_PadWithZeroesTo (&ifs.data, ROUND_TO_UPPER_MULTIPLE (ifs.data.size, image_align))); // pad as necessary
2681
 
1639
 
2682
   // write image directory (with the wrong file offsets)
1640
   // write image directory (with the wrong file offsets)
2683
   imgdir_offset = ftell (fp);
1641
   ifs.offsets.imagedir = ifs.data.size; // save image directory offset for future use
2684
   imgdir_size = 0; // measure image dir size on the fly
1642
   curr_offset = ifs.offsets.imagedir;
2685
   for (fsentry_index = 0; fsentry_index < fsentry_count; fsentry_index++)
1643
   for (fsentry_index = 0; fsentry_index < fsentry_count; fsentry_index++)
-
 
1644
   {
-
 
1645
      Buffer_WriteIFSDirectoryEntryAt (&ifs.data, curr_offset, &fsentries[fsentry_index]); // write each dirent (the unknown fields will be fixed later)
2686
      imgdir_size += fwrite_fsentry (&fsentries[fsentry_index], fp); // NOTE: padding is handled in this function
1646
      curr_offset += fsentries[fsentry_index].header.size; // advance to the next one
2687
 
1647
   }
2688
   fwrite_or_die ("\0\0\0\0", 1, 4, fp); // there seems to be 4 bytes of padding after the image directory
1648
   ASSERT_WITH_ERRNO (Buffer_AppendByteArray (&ifs.data, "\0\0\0\0")); // there seems to be 4 bytes of padding after the image directory
2689
   imgdir_size += 4;
1649
   imgdir_size = ifs.data.size - ifs.offsets.imagedir; // measure image dir size and save it for future use
2690
 
1650
 
2691
   // is it a bootable image with a kernel file ?
1651
   // is it a bootable image with a kernel file ?
2692
   if ((startupfile_pathname != NULL) && (kernelfile_pathname != NULL))
1652
   if ((startupfile_pathname != NULL) && (kernelfile_pathname != NULL))
2693
   {
1653
   {
2694
      // start by writing the startup script data blob, if we have one
1654
      // start by writing the startup script data blob, if we have one
2695
      for (fsentry_index = 1; fsentry_index < fsentry_count; fsentry_index++)
1655
      for (fsentry_index = 1; fsentry_index < fsentry_count; fsentry_index++)
2696
         if (fsentries[fsentry_index].header.ino == image_bootscript_ino)
1656
         if (fsentries[fsentry_index].header.ino == image_bootscript_ino)
2697
            break; // locate the startup script directory entry
1657
            break; // locate the startup script directory entry
2698
      if (fsentry_index < fsentry_count) // found it ?
1658
      if (fsentry_index < fsentry_count) // found it ?
2699
      {
1659
      {
2700
         curr_offset = ftell (fp);
-
 
2701
         if (curr_offset + fsentries[fsentry_index].u.file.size >= kernelfile_offset)
1660
         if (ifs.data.size + fsentries[fsentry_index].u.file.size >= kernelfile_offset)
2702
            DIE_WITH_EXITCODE (1, "the compiled startup script is too big (%zd bytes, max is %zd) to fit at current offset %zd", (size_t) fsentries[fsentry_index].u.file.size, kernelfile_offset - curr_offset, curr_offset);
1661
            DIE_WITH_EXITCODE (1, "the compiled startup script is too big (%zd bytes, max is %zd) to fit at current offset %zd", (size_t) fsentries[fsentry_index].u.file.size, kernelfile_offset - ifs.data.size, ifs.data.size);
2703
         fsentries[fsentry_index].u.file.offset = (uint32_t) (curr_offset - imageheader_offset); // save file data blob offset in file structure
1662
         fsentries[fsentry_index].u.file.offset = (uint32_t) (ifs.data.size - ifs.offsets.imageheader); // save file data blob offset in file structure
2704
         fwrite_or_die (fsentries[fsentry_index].u.file.UNSAVED_databuf, 1, fsentries[fsentry_index].u.file.size, fp); // write file data blob
1663
         Buffer_AppendIFSFileData (&ifs.data, &fsentries[fsentry_index]); // write file data
2705
         fsentries[fsentry_index].UNSAVED_was_data_written = true; // and remember this file's data was written
1664
         fsentries[fsentry_index].UNSAVED_was_data_written = true; // and remember this file's data was written
2706
      }
1665
      }
2707
 
1666
 
2708
      // now write the filesystem entries that may fit before the kernel
1667
      // now write the filesystem entries that may fit before the kernel
2709
      for (;;)
1668
      for (;;)
2710
      {
1669
      {
2711
         curr_offset = ftell (fp); // see where we are
-
 
2712
         available_space = kernelfile_offset - curr_offset; // measure the available space
1670
         available_space = kernelfile_offset - ifs.data.size; // measure the available space until the kernel
2713
 
1671
 
2714
         // look for the biggest one that can fit
1672
         // look for the biggest one that can fit
2715
         largest_index = 0;
1673
         largest_index = 0;
2716
         largest_size = 0;
1674
         largest_size = 0;
2717
         for (fsentry_index = 1; fsentry_index < fsentry_count; fsentry_index++)
1675
         for (fsentry_index = 1; fsentry_index < fsentry_count; fsentry_index++)
Line 2724... Line 1682...
2724
               largest_index = fsentry_index;
1682
               largest_index = fsentry_index;
2725
            }
1683
            }
2726
         }
1684
         }
2727
         if (largest_size == 0)
1685
         if (largest_size == 0)
2728
            break; // found none ? if so, stop searching
1686
            break; // found none ? if so, stop searching
-
 
1687
         fsentry_index = largest_index;
2729
 
1688
 
2730
         fsentries[largest_index].u.file.offset = (uint32_t) (curr_offset - imageheader_offset); // save file data blob offset in file structure
1689
         fsentries[fsentry_index].u.file.offset = (uint32_t) (ifs.data.size - ifs.offsets.imageheader); // save file data blob offset in file structure
2731
 
-
 
2732
         // is the file we're storing a preprocessed ELF file ?
-
 
2733
         if (fsentries[largest_index].header.ino & IFS_INO_PROCESSED_ELF)
-
 
2734
         {
-
 
2735
            elf = (elf_header_t *) fsentries[largest_index].u.file.UNSAVED_databuf; // quick access to ELF header
-
 
2736
            table_count = ELF_GET_NUMERIC (elf, elf, program_header_table_len); // get the number of program headers
-
 
2737
            for (table_index = 0; table_index < table_count; table_index++)
-
 
2738
            {
-
 
2739
               phdr = (elf_program_header_t *) &fsentries[largest_index].u.file.UNSAVED_databuf[ELF_GET_NUMERIC (elf, elf, program_header_table_offset) + (size_t) ELF_GET_NUMERIC (elf, elf, program_header_item_size) * table_index]; // quick access to program header
1690
         Buffer_AppendIFSFileData (&ifs.data, &fsentries[fsentry_index]); // write file data
2740
               corrective_offset = ELF_GET_NUMERIC (elf, phdr, virtual_addr) - ELF_GET_NUMERIC (elf, phdr, file_offset);
-
 
2741
               if (ELF_GET_NUMERIC (elf, phdr, size_in_memory) != 0) // only patch the physical address of segments that have an actual size in memory
-
 
2742
                  ELF_SET_NUMERIC (elf, phdr, physical_addr, ELF_GET_NUMERIC (elf, phdr, physical_addr) + image_base + curr_offset - corrective_offset); // patch the physical address member of the program header table
-
 
2743
            }
-
 
2744
         }
-
 
2745
 
-
 
2746
         fwrite_or_die (fsentries[largest_index].u.file.UNSAVED_databuf, 1, fsentries[largest_index].u.file.size, fp); // write file data blob
-
 
2747
         fsentries[largest_index].UNSAVED_was_data_written = true; // and remember this file's data was written
1691
         fsentries[fsentry_index].UNSAVED_was_data_written = true; // and remember this file's data was written
2748
      }
1692
      }
2749
      LOG_INFO ("Current offset: 0x%zx", curr_offset);
1693
      LOG_INFO ("Last written offset: 0x%zx", ifs.data.size);
2750
      LOG_INFO ("Kernel file offset: 0x%zx", kernelfile_offset);
1694
      LOG_INFO ("Kernel file offset: 0x%zx", kernelfile_offset);
2751
      PAD_OUTFILE_TO (kernelfile_offset); // reach the kernel offset
1695
      ASSERT_WITH_ERRNO (Buffer_PadWithZeroesTo (&ifs.data, kernelfile_offset)); // reach the kernel offset
2752
 
1696
 
2753
      // now write the QNX kernel
1697
      // now write the QNX kernel
2754
      for (fsentry_index = 1; fsentry_index < fsentry_count; fsentry_index++)
1698
      for (fsentry_index = 1; fsentry_index < fsentry_count; fsentry_index++)
2755
         if (fsentries[fsentry_index].header.ino == image_kernel_ino)
1699
         if (fsentries[fsentry_index].header.ino == image_kernel_ino)
2756
            break; // locate the kernel directory entry (can't fail)
1700
            break; // locate the kernel directory entry (can't fail)
2757
      curr_offset = ftell (fp); // see where we are
-
 
2758
      fsentries[fsentry_index].u.file.offset = (uint32_t) (curr_offset - imageheader_offset); // save file data blob offset in file structure
1701
      fsentries[fsentry_index].u.file.offset = (uint32_t) (ifs.data.size - ifs.offsets.imageheader); // save file data blob offset in file structure
2759
#ifdef PROCNTO_WIP
1702
#ifdef PROCNTO_WIP
2760
      // is the kernel we're storing a preprocessed ELF kernel ?
1703
      // is the kernel we're storing a preprocessed ELF kernel ?
2761
      if (fsentries[fsentry_index].header.ino & IFS_INO_PROCESSED_ELF)
1704
      if (fsentries[fsentry_index].header.ino & IFS_INO_PROCESSED_ELF)
2762
      {
1705
      {
2763
         elf = (elf_header_t *) fsentries[fsentry_index].u.file.UNSAVED_databuf; // quick access to ELF header
1706
         elf = (elf_header_t *) fsentries[fsentry_index].u.file.UNSAVED_databuf; // quick access to ELF header
Line 2765... Line 1708...
2765
         for (table_index = 0; table_index < table_count; table_index++)
1708
         for (table_index = 0; table_index < table_count; table_index++)
2766
         {
1709
         {
2767
            phdr = (elf_program_header_t *) &fsentries[fsentry_index].u.file.UNSAVED_databuf[ELF_GET_NUMERIC (elf, elf, program_header_table_offset) + (size_t) ELF_GET_NUMERIC (elf, elf, program_header_item_size) * table_index]; // quick access to program header
1710
            phdr = (elf_program_header_t *) &fsentries[fsentry_index].u.file.UNSAVED_databuf[ELF_GET_NUMERIC (elf, elf, program_header_table_offset) + (size_t) ELF_GET_NUMERIC (elf, elf, program_header_item_size) * table_index]; // quick access to program header
2768
            corrective_offset = ELF_GET_NUMERIC (elf, phdr, virtual_addr) - ELF_GET_NUMERIC (elf, phdr, file_offset);
1711
            corrective_offset = ELF_GET_NUMERIC (elf, phdr, virtual_addr) - ELF_GET_NUMERIC (elf, phdr, file_offset);
2769
            if (ELF_GET_NUMERIC (elf, phdr, size_in_memory) != 0) // only patch the physical address of segments that have an actual size in memory
1712
            if (ELF_GET_NUMERIC (elf, phdr, size_in_memory) != 0) // only patch the physical address of segments that have an actual size in memory
2770
               ELF_SET_NUMERIC (elf, phdr, physical_addr, ELF_GET_NUMERIC (elf, phdr, physical_addr) + image_base + curr_offset - corrective_offset); // patch the physical address member of the program header table
1713
               ELF_SET_NUMERIC (elf, phdr, physical_addr, ELF_GET_NUMERIC (elf, phdr, physical_addr) + image_base + ifs.data.size - corrective_offset); // patch the physical address member of the program header table (NOTE: ifs.data.size is the location where the file data is about to be written)
2771
         }
1714
         }
2772
      }
1715
      }
2773
#endif // PROCNTO_WIP
1716
#endif // PROCNTO_WIP
2774
      fwrite_or_die (fsentries[fsentry_index].u.file.UNSAVED_databuf, 1, fsentries[fsentry_index].u.file.size, fp); // write kernel file data blob
1717
      Buffer_AppendIFSFileData (&ifs.data, &fsentries[fsentry_index]); // write kernel file data
2775
      PAD_OUTFILE_TO (ROUND_TO_UPPER_MULTIPLE (ftell (fp), image_align)); // pad as necessary
-
 
2776
      fsentries[fsentry_index].UNSAVED_was_data_written = true; // and remember this file's data was written
1718
      fsentries[fsentry_index].UNSAVED_was_data_written = true; // and remember this file's data was written
2777
   }
1719
   }
2778
 
1720
 
2779
   // then write all the other files by increasing inode number: ELF files first
1721
   // then write all the other files by increasing inode number: ELF files first
2780
   for (fsentry_index = 1; fsentry_index < fsentry_count; fsentry_index++)
1722
   for (fsentry_index = 1; fsentry_index < fsentry_count; fsentry_index++)
2781
   {
1723
   {
2782
      if (!S_ISREG (fsentries[fsentry_index].header.mode) || fsentries[fsentry_index].UNSAVED_was_data_written // filter out anything that's not a file, and anything that's been already written
1724
      if (!S_ISREG (fsentries[fsentry_index].header.mode) || fsentries[fsentry_index].UNSAVED_was_data_written // filter out anything that's not a file, and anything that's been already written
2783
          || (fsentries[fsentry_index].u.file.size < 4) || (memcmp (fsentries[fsentry_index].u.file.UNSAVED_databuf, ELF_MAGIC_STR, 4) != 0)) // filter out anything that's not an ELF file
1725
          || (fsentries[fsentry_index].u.file.size < 4) || (memcmp (fsentries[fsentry_index].u.file.UNSAVED_databuf, ELF_MAGIC_STR, 4) != 0)) // filter out anything that's not an ELF file
2784
         continue; // skip all entries that don't have a separate data block and those who were written already
1726
         continue; // skip all entries that don't have a separate data block and those who were written already
2785
      curr_offset = ftell (fp);
-
 
2786
      fsentries[fsentry_index].u.file.offset = (uint32_t) (curr_offset - imageheader_offset); // save file data blob offset in file structure
1727
      fsentries[fsentry_index].u.file.offset = (uint32_t) (ifs.data.size - ifs.offsets.imageheader); // save file data blob offset in file structure
2787
 
-
 
2788
      // is the file we're storing a preprocessed ELF file ?
-
 
2789
      if (fsentries[fsentry_index].header.ino & IFS_INO_PROCESSED_ELF)
-
 
2790
      {
-
 
2791
         elf = (elf_header_t *) fsentries[fsentry_index].u.file.UNSAVED_databuf; // quick access to ELF header
-
 
2792
         table_count = ELF_GET_NUMERIC (elf, elf, program_header_table_len); // get the number of program headers
-
 
2793
         for (table_index = 0; table_index < table_count; table_index++)
-
 
2794
         {
-
 
2795
            phdr = (elf_program_header_t *) &fsentries[fsentry_index].u.file.UNSAVED_databuf[ELF_GET_NUMERIC (elf, elf, program_header_table_offset) + (size_t) ELF_GET_NUMERIC (elf, elf, program_header_item_size) * table_index]; // quick access to program header
1728
      Buffer_AppendIFSFileData (&ifs.data, &fsentries[fsentry_index]); // write file data
2796
            corrective_offset = ELF_GET_NUMERIC (elf, phdr, virtual_addr) - ELF_GET_NUMERIC (elf, phdr, file_offset);
-
 
2797
            if (ELF_GET_NUMERIC (elf, phdr, size_in_memory) != 0) // only patch the physical address of segments that have an actual size in memory
-
 
2798
               ELF_SET_NUMERIC (elf, phdr, physical_addr, ELF_GET_NUMERIC (elf, phdr, physical_addr) + image_base + curr_offset - corrective_offset); // patch the physical address member of the program header table
-
 
2799
         }
-
 
2800
      }
-
 
2801
 
-
 
2802
      fwrite_or_die (fsentries[fsentry_index].u.file.UNSAVED_databuf, 1, fsentries[fsentry_index].u.file.size, fp); // write file data blob
-
 
2803
      fsentries[fsentry_index].UNSAVED_was_data_written = true; // and remember this file's data was written
1729
      fsentries[fsentry_index].UNSAVED_was_data_written = true; // and remember this file's data was written
2804
   }
1730
   }
2805
   for (fsentry_index = 1; fsentry_index < fsentry_count; fsentry_index++) // other files (non-ELF, e.g. scripts and data files) last
1731
   for (fsentry_index = 1; fsentry_index < fsentry_count; fsentry_index++) // other files (non-ELF, e.g. scripts and data files) last
2806
   {
1732
   {
2807
      if (!S_ISREG (fsentries[fsentry_index].header.mode) || fsentries[fsentry_index].UNSAVED_was_data_written) // filter out anything that's not a file, and anything that's been already written
1733
      if (!S_ISREG (fsentries[fsentry_index].header.mode) || fsentries[fsentry_index].UNSAVED_was_data_written) // filter out anything that's not a file, and anything that's been already written
2808
         continue; // skip all entries that don't have a separate data block and those who were written already
1734
         continue; // skip all entries that don't have a separate data block and those who were written already
2809
      curr_offset = ftell (fp);
-
 
2810
      fsentries[fsentry_index].u.file.offset = (uint32_t) (curr_offset - imageheader_offset); // save file data blob offset in file structure
1735
      fsentries[fsentry_index].u.file.offset = (uint32_t) (ifs.data.size - ifs.offsets.imageheader); // save file data blob offset in file structure
2811
      fwrite_or_die (fsentries[fsentry_index].u.file.UNSAVED_databuf, 1, fsentries[fsentry_index].u.file.size, fp); // write file data blob
1736
      Buffer_AppendIFSFileData (&ifs.data, &fsentries[fsentry_index]); // write file data
2812
      fsentries[fsentry_index].UNSAVED_was_data_written = true; // and remember this file's data was written
1737
      fsentries[fsentry_index].UNSAVED_was_data_written = true; // and remember this file's data was written
2813
   }
1738
   }
2814
   PAD_OUTFILE_TO (ROUND_TO_UPPER_MULTIPLE (ftell (fp), image_align)); // pad as necessary
1739
   ASSERT_WITH_ERRNO (Buffer_PadWithZeroesTo (&ifs.data, ROUND_TO_UPPER_MULTIPLE (ifs.data.size, image_align))); // pad as necessary
2815
 
1740
 
2816
   // finally, write trailer (including empty checksum)
1741
   // finally, write trailer (including empty checksum)
2817
   imagetrailer_offset = ftell (fp); // save image trailer offset
1742
   ifs.offsets.imagetrailer = ifs.data.size; // save image trailer offset for future use
2818
   fwrite_or_die (&image_trailer, 1, sizeof (image_trailer), fp); // write image trailer
1743
   ASSERT_WITH_ERRNO (Buffer_Append (&ifs.data, &image_trailer, sizeof (image_trailer))); // write image trailer
2819
   PAD_OUTFILE_TO (ROUND_TO_UPPER_MULTIPLE (ftell (fp), image_align)); // pad as necessary
1744
   ASSERT_WITH_ERRNO (Buffer_PadWithZeroesTo (&ifs.data, ROUND_TO_UPPER_MULTIPLE (ifs.data.size, image_align))); // pad as necessary
2820
 
1745
 
2821
   // if we need to pad it to a specific length, do so
1746
   // if we need to pad it to a specific length, do so
2822
   PAD_OUTFILE_TO (image_totalsize);
1747
   ASSERT_WITH_ERRNO (Buffer_PadWithZeroesTo (&ifs.data, image_totalsize));
2823
   final_size = ftell (fp);
1748
   ifs.final_size = ifs.data.size; // and this is the final size of the IFS
2824
 
1749
 
2825
   // see if we are past the image max size, in which case it's an error
1750
   // see if we are past the image max size, in which case it's an error
2826
   if (final_size > image_maxsize)
1751
   if (ifs.final_size > image_maxsize)
2827
      DIE_WITH_EXITCODE (1, "image file \"%s\" size %zd exceeds max size (%zd)", ifs_pathname, final_size, (size_t) image_maxsize);
1752
      DIE_WITH_EXITCODE (1, "image file \"%s\" size %zd exceeds max size (%zd)", ifs_pathname, ifs.final_size, (size_t) image_maxsize);
2828
 
1753
 
2829
   // do we have a startup file ? if so, this is a bootable image
1754
   // do we have a startup file ? if so, this is a bootable image
2830
   if (startupfile_pathname != NULL)
1755
   if (startupfile_pathname != NULL)
2831
   {
1756
   {
2832
      // rewrite startup header with final values
1757
      // patch the startup header with its final values
2833
      fseek_or_die (fp, startupheader_offset, SEEK_SET);
-
 
2834
      startup_header.startup_size = (uint32_t) (imageheader_offset - startupheader_offset); // size of startup header up to image header
1758
      startup_header.startup_size = (uint32_t) (ifs.offsets.imageheader - ifs.offsets.startupheader); // size of startup header up to image header
2835
      startup_header.imagefs_size = (uint32_t) (final_size - imageheader_offset); // size of uncompressed imagefs
1759
      startup_header.imagefs_size = (uint32_t) (ifs.final_size - ifs.offsets.imageheader); // size of uncompressed imagefs
2836
      startup_header.ram_size     = (uint32_t) (final_size - startupheader_offset);
1760
      startup_header.ram_size     = (uint32_t) (ifs.final_size - ifs.offsets.startupheader);
2837
      startup_header.stored_size  = (uint32_t) (final_size - startupheader_offset);
1761
      startup_header.stored_size  = (uint32_t) (ifs.final_size - ifs.offsets.startupheader);
2838
      fwrite_or_die (&startup_header, 1, sizeof (startup_header), fp); // write startup header
1762
      ASSERT_WITH_ERRNO (Buffer_WriteAt (&ifs.data, ifs.offsets.startupheader, &startup_header, sizeof (startup_header))); // write the final startup header at its right offset
2839
   }
1763
   }
2840
 
1764
 
2841
   // rewrite image header with final values
1765
   // rewrite image header with final values
2842
   fseek_or_die (fp, imageheader_offset, SEEK_SET);
-
 
2843
   image_header.image_size = (uint32_t) (final_size - imageheader_offset); // size of uncompressed imagefs
1766
   image_header.image_size = (uint32_t) (ifs.final_size - ifs.offsets.imageheader); // size of uncompressed imagefs
2844
   image_header.hdr_dir_size = sizeof (image_header) + (uint32_t) imgdir_size; // size from start of image header to last dirent
1767
   image_header.hdr_dir_size = sizeof (image_header) + (uint32_t) imgdir_size; // size from start of image header to last dirent
2845
   fwrite_or_die (&image_header, 1, sizeof (image_header), fp); // write image header
1768
   ASSERT_WITH_ERRNO (Buffer_WriteAt (&ifs.data, ifs.offsets.imageheader, &image_header, sizeof (image_header))); // write image header
2846
 
1769
 
2847
   // rewrite image directory with final offset values
1770
   // rewrite image directory with final offset values
2848
   fseek_or_die (fp, imgdir_offset, SEEK_SET);
-
 
2849
   if (image_header.flags & IMAGE_FLAGS_SORTED)
1771
   if (image_header.flags & IMAGE_FLAGS_SORTED)
2850
      qsort (&fsentries[1], fsentry_count - 1, sizeof (fsentry_t), fsentry_compare_pathnames_cb); // sort the filesystem entries by pathname
1772
      qsort (&fsentries[1], fsentry_count - 1, sizeof (fsentry_t), fsentry_compare_pathnames_cb); // sort the filesystem entries by pathname if necessary
-
 
1773
   curr_offset = ifs.offsets.imagedir; // position ourselves at the beginning of the image directory
2851
   for (fsentry_index = 0; fsentry_index < fsentry_count; fsentry_index++)
1774
   for (fsentry_index = 0; fsentry_index < fsentry_count; fsentry_index++)
-
 
1775
   {
-
 
1776
      Buffer_WriteIFSDirectoryEntryAt (&ifs.data, curr_offset, &fsentries[fsentry_index]); // rewrite each dirent
2852
      fwrite_fsentry (&fsentries[fsentry_index], fp);
1777
      curr_offset += fsentries[fsentry_index].header.size; // advance to the next one
2853
 
1778
   }
2854
   fclose (fp); // ensure everything is flushed
-
 
2855
 
1779
 
2856
   // ALL CHECKSUMS AT THE VERY END
1780
   // ALL CHECKSUMS AT THE VERY END
2857
 
-
 
2858
   read_filecontents (ifs_pathname, ".", &blob);
-
 
2859
   WELLMANNERED_ASSERT (blob.bytes != NULL, "failed to open IFS file for checksumming: %s", strerror (errno));
-
 
2860
 
1781
 
2861
   // do we have a startup file ? if so, this is a bootable image
1782
   // do we have a startup file ? if so, this is a bootable image
2862
   if (startupfile_pathname != NULL)
1783
   if (startupfile_pathname != NULL)
2863
   {
1784
   {
2864
      // compute SHA-512 checksum and V1 checksum of startup block
1785
      // compute SHA-512 checksum and V1 checksum of startup block
Line 2866... Line 1787...
2866
          || (!(startup_header.flags1 & STARTUP_HDR_FLAGS1_BIGENDIAN) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)))
1787
          || (!(startup_header.flags1 & STARTUP_HDR_FLAGS1_BIGENDIAN) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)))
2867
         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
1788
         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
2868
      else
1789
      else
2869
         is_foreign_endianness = false; // else this header is for the same endianness as us
1790
         is_foreign_endianness = false; // else this header is for the same endianness as us
2870
 
1791
 
-
 
1792
      if (startup_header.flags1 & STARTUP_HDR_FLAGS1_TRAILER_V2) // is it a V2 trailer ?
-
 
1793
      {
2871
      SHA512 (&blob.bytes[startupheader_offset], startuptrailer_offset - startupheader_offset, &blob.bytes[startuptrailer_offset]); // compute SHA512 checksum and write it in place in blob data
1794
         SHA512 (&ifs.data.bytes[ifs.offsets.startupheader], ifs.offsets.startuptrailer - ifs.offsets.startupheader, &ifs.data.bytes[ifs.offsets.startuptrailer]); // compute SHA512 checksum and write it in place
2872
      checksum = update_checksum (&blob.bytes[startupheader_offset], startuptrailer_offset + SHA512_DIGEST_LENGTH - startupheader_offset, is_foreign_endianness); // compute old checksum
1795
         checksum = update_checksum (&ifs.data.bytes[ifs.offsets.startupheader], ifs.offsets.startuptrailer + SHA512_DIGEST_LENGTH - ifs.offsets.startupheader, is_foreign_endianness); // compute old checksum
2873
      memcpy (&blob.bytes[startuptrailer_offset + SHA512_DIGEST_LENGTH], &checksum, 4); // and write it in place
1796
         memcpy (&ifs.data.bytes[ifs.offsets.startuptrailer + SHA512_DIGEST_LENGTH], &checksum, 4); // and write it in place
-
 
1797
      }
-
 
1798
      else // old V1 trailer
-
 
1799
      {
-
 
1800
         checksum = update_checksum (&ifs.data.bytes[ifs.offsets.startupheader], ifs.offsets.startuptrailer - ifs.offsets.startupheader, is_foreign_endianness); // compute old checksum
-
 
1801
         memcpy (&ifs.data.bytes[ifs.offsets.startuptrailer], &checksum, 4); // and write it in place
-
 
1802
      }
2874
   }
1803
   }
2875
 
1804
 
2876
   // compute SHA-512 checksum and V1 checksum of image block
1805
   // compute SHA-512 checksum and V1 checksum of image block
2877
   if (   ( (image_header.flags & IMAGE_FLAGS_BIGENDIAN) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
1806
   if (   ( (image_header.flags & IMAGE_FLAGS_BIGENDIAN) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
2878
       || (!(image_header.flags & IMAGE_FLAGS_BIGENDIAN) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)))
1807
       || (!(image_header.flags & IMAGE_FLAGS_BIGENDIAN) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)))
2879
      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
1808
      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
2880
   else
1809
   else
2881
      is_foreign_endianness = false; // else this header is for the same endianness as us
1810
      is_foreign_endianness = false; // else this header is for the same endianness as us
2882
 
1811
 
2883
   SHA512 (&blob.bytes[imageheader_offset], imagetrailer_offset - imageheader_offset, &blob.bytes[imagetrailer_offset]); // compute SHA512 checksum and write it in place in blob data
-
 
2884
   checksum = update_checksum (&blob.bytes[imageheader_offset], imagetrailer_offset + SHA512_DIGEST_LENGTH - imageheader_offset, is_foreign_endianness); // compute old checksum
-
 
2885
   memcpy (&blob.bytes[imagetrailer_offset + SHA512_DIGEST_LENGTH], &checksum, 4); // and write it in place
1812
   if (image_header.flags & IMAGE_FLAGS_TRAILER_V2) // is it a V2 trailer ?
2886
 
-
 
2887
   // now rewrite IFS with the correct checksums
-
 
2888
   fp = fopen (ifs_pathname, "wb");
-
 
2889
   WELLMANNERED_ASSERT (fp, "failed to reopen IFS file for checksumming: %s", strerror (errno));
-
 
2890
   fwrite_or_die (blob.bytes, 1, blob.len, fp);
-
 
2891
   fclose (fp);
-
 
2892
   free (blob.bytes);
-
 
2893
 
-
 
2894
   // finished, exit with a success code
-
 
2895
   LOG_INFO ("Success");
-
 
2896
   exit (0);
-
 
2897
}
-
 
2898
 
-
 
2899
 
-
 
2900
static int dump_ifs_info (const char *ifs_pathname, bool want_everything)
-
 
2901
{
-
 
2902
   #define hex_printf(buf,size,...) do { \
-
 
2903
      if (want_everything || ((size) <= 16 * 1024)) /* only print when it's not too big (up to 16 kb) */\
-
 
2904
         hex_fprintf (stdout, (buf), (size), 16, __VA_ARGS__); /* use 16 columns in hex output to stdout */ \
-
 
2905
      else { \
-
 
2906
         printf (__VA_ARGS__); \
-
 
2907
         hex_fprintf (stdout, (buf), 1024, 16, "   first kilobyte:\n"); \
-
 
2908
      } \
-
 
2909
   } while (0)
-
 
2910
   #define BINARY(x) binary ((x), '-', 'x')
-
 
2911
 
-
 
2912
   static const char *startupheader_flags1_strings[8] = {
-
 
2913
      "VIRTUAL", // bit 0
-
 
2914
      "BIGENDIAN", // bit 1
-
 
2915
      "COMPRESS_BIT1", // bit 2
-
 
2916
      "COMPRESS_BIT2", // bit 3
-
 
2917
      "COMPRESS_BIT3", // bit 4
-
 
2918
      "TRAILER_V2", // bit 5
-
 
2919
      "", // bit 6
-
 
2920
      "", // bit 7
-
 
2921
   };
-
 
2922
   static const char *imageheader_flags_strings[8] = {
-
 
2923
      "BIGENDIAN", // bit 0
-
 
2924
      "READONLY", // bit 1
-
 
2925
      "INO_BITS", // bit 2
-
 
2926
      "SORTED", // bit 3
-
 
2927
      "TRAILER_V2", // bit 4
-
 
2928
      "", // bit 5
-
 
2929
      "", // bit 6
-
 
2930
      "", // bit 7
-
 
2931
   };
-
 
2932
 
-
 
2933
   startup_header_t *startup_header = NULL;
-
 
2934
   size_t startupheader_offset = 0;
-
 
2935
   startup_trailer_v1_t *startup_trailer_v1 = NULL;
-
 
2936
   startup_trailer_v2_t *startup_trailer_v2 = NULL;
-
 
2937
   size_t startuptrailer_offset = 0;
-
 
2938
   image_header_t *image_header = NULL;
-
 
2939
   size_t imageheader_offset = 0;
-
 
2940
   image_trailer_v1_t *image_trailer_v1 = NULL;
-
 
2941
   image_trailer_v2_t *image_trailer_v2 = NULL;
-
 
2942
   size_t imagetrailer_offset = 0;
-
 
2943
   fsentry_t **fsentries = NULL; // mallocated
-
 
2944
   size_t fsentry_count = 0;
-
 
2945
   fsentry_t *current_fsentry = NULL;
-
 
2946
   char recorded_sha512[2 * SHA512_DIGEST_LENGTH + 1] = "";
-
 
2947
   char computed_sha512[2 * SHA512_DIGEST_LENGTH + 1] = "";
-
 
2948
   size_t startupfile_blobsize = 0;
-
 
2949
   void *reallocated_ptr;
-
 
2950
   bool is_foreign_endianness;
-
 
2951
   size_t bootfile_blobsize = 0;
-
 
2952
   size_t current_offset;
-
 
2953
   size_t fsentry_index;
-
 
2954
   size_t nearest_distance;
-
 
2955
   size_t nearest_index;
-
 
2956
   size_t byte_index;
-
 
2957
   uint32_t recorded_checksum;
-
 
2958
   uint32_t computed_checksum;
-
 
2959
   buffer_t file;
-
 
2960
   time_t mtime;
-
 
2961
 
-
 
2962
   // open and read IFS file
-
 
2963
   if (read_filecontents (ifs_pathname, ".", &file) == NULL)
-
 
2964
      DIE_WITH_EXITCODE (1, "can't open \"%s\" for reading: %s", ifs_pathname, strerror (errno));
-
 
2965
 
-
 
2966
   printf ("QNX In-kernel Filesystem analysis produced by ifstool version " VERSION_FMT_YYYYMMDD "\n", VERSION_ARG_YYYYMMDD);
-
 
2967
   printf ("IFS file \"%s\" - size 0x%zx (%zd) bytes\n", ifs_pathname, file.len, file.len);
-
 
2968
 
-
 
2969
   // parse file from start to end
-
 
2970
   current_offset = 0;
-
 
2971
   for (;;)
-
 
2972
   {
1813
   {
2973
      // does a startup header start here ?
-
 
2974
      if ((current_offset + sizeof (startup_header_t) < file.len) && (memcmp (&file.bytes[current_offset], "\xeb\x7e\xff\x00", 4) == 0))
-
 
2975
      {
-
 
2976
         startupheader_offset = current_offset;
-
 
2977
         startup_header = (startup_header_t *) &file.bytes[startupheader_offset];
-
 
2978
 
-
 
2979
         // layout:
-
 
2980
         // [STARTUP HEADER]
-
 
2981
         // (startup file blob)
-
 
2982
         // [STARTUP TRAILER v1 or v2]
-
 
2983
 
-
 
2984
         printf ("\n");
-
 
2985
         printf ("Startup header at offset 0x%zx (%zd):\n", current_offset, current_offset);
-
 
2986
         printf ("   signature     = %02x %02x %02x %02x - good\n", startup_header->signature[0], startup_header->signature[1], startup_header->signature[2], startup_header->signature[3]);
-
 
2987
         printf ("   version       = 0x%04x (%d) - %s\n", startup_header->version, startup_header->version, (startup_header->version == 1 ? "looks good" : "???"));
-
 
2988
         printf ("   flags1        = 0x%02x (%s)\n", startup_header->flags1, describe_uint8 (startup_header->flags1, startupheader_flags1_strings));
-
 
2989
         printf ("   flags2        = 0x%02x (%s) - %s\n", startup_header->flags2, BINARY (startup_header->flags2), (startup_header->flags2 == 0 ? "looks good" : "???"));
-
 
2990
         printf ("   header_size   = 0x%04x (%d) - %s\n", startup_header->header_size, startup_header->header_size, (startup_header->header_size == sizeof (startup_header_t) ? "looks good" : "BAD"));
-
 
2991
         printf ("   machine       = 0x%04x (%d) - %s\n", startup_header->machine, startup_header->machine, (startup_header->machine == ELF_MACHINE_X86_64 ? "x86_64" : (startup_header->machine == ELF_MACHINE_AARCH64 ? "aarch64" : "unknown")));
-
 
2992
         printf ("   startup_vaddr = 0x%08x (%d) - virtual address to transfer to after IPL is done\n", startup_header->startup_vaddr, startup_header->startup_vaddr);
-
 
2993
         printf ("   paddr_bias    = 0x%08x (%d) - value to add to physical addresses to get an indirectable pointer value\n", startup_header->paddr_bias, startup_header->paddr_bias);
-
 
2994
         printf ("   image_paddr   = 0x%08x (%d) - physical address of image\n", startup_header->image_paddr, startup_header->image_paddr);
-
 
2995
         printf ("   ram_paddr     = 0x%08x (%d) - physical address of RAM to copy image to (startup_size bytes copied)\n", startup_header->ram_paddr, startup_header->ram_paddr);
-
 
2996
         printf ("   ram_size      = 0x%08x (%d) - amount of RAM used by the startup program and executables in the fs\n", startup_header->ram_size, startup_header->ram_size);
-
 
2997
         printf ("   startup_size  = 0x%08x (%d) - size of startup (never compressed) - %s\n", startup_header->startup_size, startup_header->startup_size, (current_offset + sizeof (image_header_t) + startup_header->startup_size + (startup_header->flags1 & STARTUP_HDR_FLAGS1_TRAILER_V2 ? sizeof (image_trailer_v2_t) : sizeof (image_trailer_v1_t)) < file.len ? "looks good" : "BAD (IFS file too short)"));
-
 
2998
         printf ("   stored_size   = 0x%08x (%d) - size of entire image - %s\n", startup_header->stored_size, startup_header->stored_size, (startup_header->stored_size == startup_header->ram_size ? "looks good" : "???"));
-
 
2999
         printf ("   imagefs_paddr = 0x%08x (%d) - set by IPL when startup runs - %s\n", startup_header->imagefs_paddr, startup_header->imagefs_paddr, (startup_header->imagefs_paddr == 0 ? "looks good" : "??? should be zero"));
-
 
3000
         printf ("   imagefs_size  = 0x%08x (%d) - size of uncompressed imagefs\n", startup_header->imagefs_size, startup_header->imagefs_size);
-
 
3001
         printf ("   preboot_size  = 0x%04x (%d) - size of loaded before header - %s\n", startup_header->preboot_size, startup_header->preboot_size, (startup_header->preboot_size == current_offset ? "looks good" : "???"));
-
 
3002
         printf ("   zero0         = 0x%04x (%d) - zeros - %s\n", startup_header->zero0, startup_header->zero0, (startup_header->zero0 == 0 ? "looks good" : "??? should be zero"));
-
 
3003
         printf ("   zero[0]       = 0x%08x (%d) - zeros - %s\n", startup_header->zero[0], startup_header->zero[0], (startup_header->zero[0] == 0 ? "looks good" : "??? should be zero"));
-
 
3004
         printf ("   addr_off      = 0x%016llx (%lld) - offset for startup_vaddr and [image|ram|imagefs]_paddr - %s\n", startup_header->addr_off, startup_header->addr_off, (startup_header->addr_off == 0 ? "looks good" : "??? should be zero"));
-
 
3005
         hex_printf ((uint8_t *) &startup_header->info[0], sizeof (startup_header->info), "   info[48] =\n");
-
 
3006
 
-
 
3007
         // validate that the file can contain up to the startup trailer
-
 
3008
         if (current_offset + startup_header->startup_size > file.len)
-
 
3009
         {
-
 
3010
            LOG_WARNING ("this IFS file is corrupted (startup trailer extends past end of file)");
-
 
3011
            goto endofdata;
-
 
3012
         }
-
 
3013
 
-
 
3014
         // check if this endianness is ours
-
 
3015
         if (   ( (startup_header->flags1 & STARTUP_HDR_FLAGS1_BIGENDIAN) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
-
 
3016
             || (!(startup_header->flags1 & STARTUP_HDR_FLAGS1_BIGENDIAN) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)))
-
 
3017
            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
-
 
3018
         else
-
 
3019
            is_foreign_endianness = false; // else this header is for the same endianness as us
-
 
3020
 
-
 
3021
         // locate the right startup trailer at the right offset
-
 
3022
         if (startup_header->flags1 & STARTUP_HDR_FLAGS1_TRAILER_V2)
-
 
3023
         {
-
 
3024
            startuptrailer_offset = current_offset + startup_header->startup_size - sizeof (startup_trailer_v2_t);
-
 
3025
            startup_trailer_v2 = (startup_trailer_v2_t *) &file.bytes[startuptrailer_offset];
-
 
3026
            startupfile_blobsize = startup_header->startup_size - sizeof (startup_header_t) - sizeof (startup_trailer_v2_t);
-
 
3027
         }
-
 
3028
         else // old V1 trailer
-
 
3029
         {
-
 
3030
            startuptrailer_offset = current_offset + startup_header->startup_size - sizeof (startup_trailer_v1_t);
-
 
3031
            startup_trailer_v1 = (startup_trailer_v1_t *) &file.bytes[startuptrailer_offset];
-
 
3032
            startupfile_blobsize = startup_header->startup_size - sizeof (startup_header_t) - sizeof (startup_trailer_v1_t);
-
 
3033
         }
-
 
3034
 
-
 
3035
         current_offset += sizeof (startup_header_t); // jump over the startup header and reach the startup blob
-
 
3036
         printf ("\n");
-
 
3037
         printf ("Startup blob at offset 0x%zx (%zd):\n", current_offset, current_offset);
-
 
3038
         printf ("   size 0x%zx (%zd) bytes\n", startupfile_blobsize, startupfile_blobsize);
-
 
3039
         printf ("   checksum %d\n", update_checksum (&file.bytes[current_offset], startupfile_blobsize, is_foreign_endianness));
-
 
3040
 
-
 
3041
         current_offset += startupfile_blobsize; // jump over the startup blob and reach the startup trailer
-
 
3042
         printf ("\n");
-
 
3043
         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));
-
 
3044
         if (startup_header->flags1 & STARTUP_HDR_FLAGS1_TRAILER_V2)
-
 
3045
         {
-
 
3046
            for (byte_index = 0; byte_index < SHA512_DIGEST_LENGTH; byte_index++)
-
 
3047
               sprintf (&recorded_sha512[2 * byte_index], "%02x", startup_trailer_v2->sha512[byte_index]);
-
 
3048
            strcpy (computed_sha512, SHA512 (startup_header, startuptrailer_offset - startupheader_offset, NULL));
-
 
3049
            recorded_checksum = startup_trailer_v2->cksum;
-
 
3050
            computed_checksum = update_checksum (startup_header, startuptrailer_offset + SHA512_DIGEST_LENGTH - startupheader_offset, is_foreign_endianness);
-
 
3051
            printf ("    sha512([0x%zx-0x%zx[) = %s - %s\n", startupheader_offset, startuptrailer_offset, recorded_sha512, (strcasecmp (computed_sha512, recorded_sha512) == 0 ? "GOOD" : "BAD"));
-
 
3052
            printf ("    cksum([0x%zx-0x%zx[) = 0x%08x - %s\n", startupheader_offset, startuptrailer_offset + SHA512_DIGEST_LENGTH, recorded_checksum, (computed_checksum == recorded_checksum ? "GOOD" : "BAD"));
-
 
3053
            if (strcasecmp (computed_sha512, recorded_sha512) != 0)
-
 
3054
               printf ("Computed SHA-512: %s\n", computed_sha512);
-
 
3055
            if (computed_checksum != recorded_checksum)
-
 
3056
               printf ("Computed cksum: 0x%08x\n", computed_checksum);
-
 
3057
         }
-
 
3058
         else // old v1 trailer
-
 
3059
         {
-
 
3060
            recorded_checksum = startup_trailer_v1->cksum;
-
 
3061
            computed_checksum = update_checksum (startup_header, sizeof (startup_header) + startupfile_blobsize, is_foreign_endianness);
-
 
3062
            printf ("    cksum([0x%zx-0x%zx[) = 0x%08x - %s\n", startupheader_offset, startuptrailer_offset, recorded_checksum, (computed_checksum == recorded_checksum ? "GOOD" : "BAD"));
-
 
3063
            if (computed_checksum != recorded_checksum)
-
 
3064
               printf ("Computed cksum: 0x%08x\n", computed_checksum);
-
 
3065
         }
-
 
3066
 
-
 
3067
         current_offset += (startup_header->flags1 & STARTUP_HDR_FLAGS1_TRAILER_V2 ? sizeof (startup_trailer_v2_t) : sizeof (startup_trailer_v1_t)); // now reach the next segment
-
 
3068
      }
-
 
3069
 
-
 
3070
      // else does an image header start here ?
-
 
3071
      else if ((current_offset + sizeof (image_header_t) < file.len) && (memcmp (&file.bytes[current_offset], "imagefs", 7) == 0))
-
 
3072
      {
-
 
3073
         imageheader_offset = current_offset;
-
 
3074
         image_header = (image_header_t *) &file.bytes[imageheader_offset];
-
 
3075
 
-
 
3076
         // layout:
-
 
3077
         // [IMAGE HEADER]
-
 
3078
         // [image directory entries]
-
 
3079
         // [smallest file blobs up to KERNEL]
-
 
3080
         // [padding]
-
 
3081
         // [KERNEL]
-
 
3082
         // [rest of file blobs]
-
 
3083
         // [IMAGE FOOTER]
-
 
3084
 
-
 
3085
         printf ("\n");
-
 
3086
         printf ("Image header at offset %zx (%zd):\n", current_offset, current_offset);
-
 
3087
         printf ("   signature    = %02x %02x %02x %02x %02x %02x %02x (\"%.7s\") - good\n", image_header->signature[0], image_header->signature[1], image_header->signature[2], image_header->signature[3], image_header->signature[4], image_header->signature[5], image_header->signature[6], image_header->signature);
1814
      SHA512 (&ifs.data.bytes[ifs.offsets.imageheader], ifs.offsets.imagetrailer - ifs.offsets.imageheader, &ifs.data.bytes[ifs.offsets.imagetrailer]); // compute SHA512 checksum and write it in place
3088
         printf ("   flags        = 0x%02x (%s)\n", image_header->flags, describe_uint8 (image_header->flags, imageheader_flags_strings));
-
 
3089
         printf ("   image_size   = 0x%08x (%d) - size from header to end of trailer - %s\n", image_header->image_size, image_header->image_size, (current_offset + image_header->image_size <= file.len ? "looks good" : "BAD (IFS file too short)"));
-
 
3090
         printf ("   hdr_dir_size = 0x%08x (%d) - size from header to last dirent - %s\n", image_header->hdr_dir_size, image_header->hdr_dir_size, (current_offset + image_header->hdr_dir_size < file.len ? "looks good" : "BAD (IFS file too short)"));
-
 
3091
         printf ("   dir_offset   = 0x%08x (%d) - offset from header to first dirent - %s\n", image_header->dir_offset, image_header->dir_offset, (current_offset + image_header->dir_offset >= file.len ? "BAD (IFS file too short)" : (image_header->dir_offset > image_header->hdr_dir_size ? "BAD" : "looks good")));
-
 
3092
         printf ("   boot_ino[4]  = { 0x%08x, 0x%08x, 0x%08x, 0x%08x }\n", image_header->boot_ino[0], image_header->boot_ino[1], image_header->boot_ino[2], image_header->boot_ino[3]);
-
 
3093
         printf ("   script_ino   = 0x%08x (%d) - inode of compiled bootscript\n", image_header->script_ino, image_header->script_ino);
-
 
3094
         printf ("   chain_paddr  = 0x%08x (%d) - offset to next fs signature\n", image_header->chain_paddr, image_header->chain_paddr);
-
 
3095
         hex_printf ((uint8_t *) &image_header->spare[0], sizeof (image_header->spare), "   spare[10] =\n");
-
 
3096
         printf ("   mountflags   = 0x%08x (%s %s %s %s)\n", image_header->mountflags, BINARY (((uint8_t *) &image_header->mountflags)[0]), BINARY (((uint8_t *) &image_header->mountflags)[1]), BINARY (((uint8_t *) &image_header->mountflags)[2]), BINARY (((uint8_t *) &image_header->mountflags)[3]));
1815
      checksum = update_checksum (&ifs.data.bytes[ifs.offsets.imageheader], ifs.offsets.imagetrailer + SHA512_DIGEST_LENGTH - ifs.offsets.imageheader, is_foreign_endianness); // compute old checksum
3097
         printf ("   mountpoint   = \"%s\"\n", image_header->mountpoint);
-
 
3098
 
-
 
3099
         // validate that the file can contain up to the image trailer
-
 
3100
         if (current_offset + image_header->image_size > file.len)
-
 
3101
         {
-
 
3102
            LOG_WARNING ("this IFS file is corrupted (image trailer extends past end of file)");
-
 
3103
            goto endofdata;
-
 
3104
         }
-
 
3105
 
-
 
3106
         // check if this endianness is ours
-
 
3107
         if (   ( (image_header->flags & IMAGE_FLAGS_BIGENDIAN) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
-
 
3108
             || (!(image_header->flags & IMAGE_FLAGS_BIGENDIAN) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)))
-
 
3109
            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
-
 
3110
         else
-
 
3111
            is_foreign_endianness = false; // else this header is for the same endianness as us
-
 
3112
 
-
 
3113
         // locate the image trailer at the right offset
-
 
3114
         if (image_header->flags & IMAGE_FLAGS_TRAILER_V2)
-
 
3115
         {
-
 
3116
            imagetrailer_offset = current_offset + image_header->image_size - sizeof (image_trailer_v2_t);
-
 
3117
            image_trailer_v2 = (image_trailer_v2_t *) &file.bytes[imagetrailer_offset];
-
 
3118
         }
-
 
3119
         else // old V1 trailer
-
 
3120
         {
-
 
3121
            imagetrailer_offset = current_offset + image_header->image_size - sizeof (image_trailer_v1_t);
-
 
3122
            image_trailer_v1 = (image_trailer_v1_t *) &file.bytes[imagetrailer_offset];
-
 
3123
         }
-
 
3124
 
-
 
3125
         current_offset += sizeof (image_header_t); // jump over the image header and reach the first directory entry
-
 
3126
 
-
 
3127
         // there may be padding before the first directory entry
-
 
3128
         if (image_header->dir_offset - sizeof (image_header_t) > 0)
-
 
3129
            hex_printf (&file.bytes[current_offset], image_header->dir_offset - sizeof (image_header_t), "\n" "%zd padding bytes at offset 0x%zd (%zd):\n", image_header->dir_offset - sizeof (image_header_t), current_offset, current_offset);
-
 
3130
         current_offset += image_header->dir_offset - sizeof (image_header_t); // padding was processed, jump over it
-
 
3131
 
-
 
3132
         // dump all directory entries until the last one included
-
 
3133
         fsentries = NULL;
-
 
3134
         fsentry_count = 0;
-
 
3135
         while (current_offset < imageheader_offset + image_header->hdr_dir_size)
-
 
3136
         {
-
 
3137
            current_fsentry = (fsentry_t *) &file.bytes[current_offset];
-
 
3138
 
-
 
3139
            if (imageheader_offset + image_header->hdr_dir_size - current_offset < sizeof (current_fsentry->header))
-
 
3140
               break; // end padding reached
-
 
3141
 
-
 
3142
            // stack up the filesystem entry pointers in an array while we read them
-
 
3143
            reallocated_ptr = realloc (fsentries, (fsentry_count + 1) * sizeof (fsentry_t *));
-
 
3144
            WELLMANNERED_ASSERT (reallocated_ptr, "out of memory");
-
 
3145
            fsentries = reallocated_ptr;
-
 
3146
            fsentries[fsentry_count] = current_fsentry;
-
 
3147
            fsentry_count++;
-
 
3148
 
-
 
3149
            printf ("\n");
-
 
3150
            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);
-
 
3151
            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 < file.len) ? "looks good" : "BAD"));
-
 
3152
            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"));
-
 
3153
            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" : ""));
-
 
3154
            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);
-
 
3155
            printf ("   gid            = 0x%08x (%d) - owner group ID%s\n", current_fsentry->header.gid, current_fsentry->header.gid, (current_fsentry->header.gid == 0 ? " (root)" : ""));
-
 
3156
            printf ("   uid            = 0x%08x (%d) - owner user ID%s\n", current_fsentry->header.uid, current_fsentry->header.uid, (current_fsentry->header.uid == 0 ? " (root)" : ""));
-
 
3157
            mtime = (time_t) current_fsentry->header.mtime;
-
 
3158
            printf ("   mtime          = 0x%08x (%d) - POSIX timestamp: %s", current_fsentry->header.mtime, current_fsentry->header.mtime, asctime (localtime (&mtime))); // NOTE: asctime() provides the newline
-
 
3159
            if (S_ISDIR (current_fsentry->header.mode))
-
 
3160
               printf ("   [DIRECTORY] path = \"%s\"\n", (char *) &current_fsentry->u.dir.path); // convert from pointer to char array
-
 
3161
            else if (S_ISREG (current_fsentry->header.mode))
-
 
3162
            {
-
 
3163
               printf ("   [FILE] offset = 0x%08x (%d) - %s\n", current_fsentry->u.file.offset, current_fsentry->u.file.offset, (imageheader_offset + current_fsentry->u.file.offset < file.len ? "looks good" : "BAD (IFS file too short)"));
-
 
3164
               printf ("   [FILE] size   = 0x%08x (%d) - %s\n", current_fsentry->u.file.size, current_fsentry->u.file.size, (imageheader_offset + current_fsentry->u.file.offset + current_fsentry->u.file.size < file.len ? "looks good" : "BAD (IFS file too short)"));
-
 
3165
               printf ("   [FILE] path   = \"%s\"\n", (char *) &current_fsentry->u.file.path); // convert from pointer to char array
-
 
3166
            }
-
 
3167
            else if (S_ISLNK (current_fsentry->header.mode))
-
 
3168
            {
-
 
3169
               printf ("   [SYMLINK] sym_offset = 0x%04x (%d) - %s\n", current_fsentry->u.symlink.sym_offset, current_fsentry->u.symlink.sym_offset, (sizeof (current_fsentry->header) + 2 * sizeof (uint16_t) + current_fsentry->u.symlink.sym_offset <= current_fsentry->header.size ? "looks good" : "BAD (dirent too short)"));
-
 
3170
               printf ("   [SYMLINK] sym_size   = 0x%04x (%d) - %s\n", current_fsentry->u.symlink.sym_size, current_fsentry->u.symlink.sym_size, (sizeof (current_fsentry->header) + 2 * sizeof (uint16_t) + current_fsentry->u.symlink.sym_offset + current_fsentry->u.symlink.sym_size <= current_fsentry->header.size ? "looks good" : "BAD (dirent too short)"));
-
 
3171
               printf ("   [SYMLINK] path       = \"%s\"\n", (char *) &current_fsentry->u.symlink.path); // convert from pointer to char array
-
 
3172
               printf ("   [SYMLINK] contents   = \"%s\"\n", ((char *) &current_fsentry->u.symlink.path) + current_fsentry->u.symlink.sym_offset); // convert from pointer to char array
-
 
3173
            }
-
 
3174
            else // can only be a device
-
 
3175
            {
-
 
3176
               printf ("   [DEVICE] dev  = 0x%08x (%d)\n", current_fsentry->u.device.dev, current_fsentry->u.device.dev);
-
 
3177
               printf ("   [DEVICE] rdev = 0x%08x (%d)\n", current_fsentry->u.device.rdev, current_fsentry->u.device.rdev);
-
 
3178
               printf ("   [DEVICE] path = \"%s\"\n", (char *) &current_fsentry->u.device.path); // convert from pointer to char array
-
 
3179
            }
-
 
3180
 
-
 
3181
            if ((current_fsentry->header.size == 0) || (current_offset + current_fsentry->header.size >= file.len))
-
 
3182
            {
-
 
3183
               LOG_WARNING ("this IFS file is corrupted (the size of this directory entry is invalid)");
-
 
3184
               goto endofdata;
-
 
3185
            }
-
 
3186
 
-
 
3187
            current_offset += current_fsentry->header.size;
-
 
3188
         }
-
 
3189
         if (imageheader_offset + image_header->hdr_dir_size < current_offset + sizeof (current_fsentry->header))
-
 
3190
            hex_printf (&file.bytes[current_offset], imageheader_offset + image_header->hdr_dir_size - current_offset, "\n" "%zd padding bytes at offset 0x%zx (%zd):\n", imageheader_offset + image_header->hdr_dir_size - current_offset, current_offset, current_offset);
1816
      memcpy (&ifs.data.bytes[ifs.offsets.imagetrailer + SHA512_DIGEST_LENGTH], &checksum, 4); // and write it in place
3191
         current_offset += imageheader_offset + image_header->hdr_dir_size - current_offset; // padding was processed, jump over it
-
 
3192
 
-
 
3193
         // at this point we are past the directory entries; what is stored now, up to and until the image trailer, is the files' data
-
 
3194
         if (fsentry_count > 0)
-
 
3195
         {
-
 
3196
            while (current_offset < imagetrailer_offset) // and parse data up to the trailer
-
 
3197
            {
-
 
3198
               nearest_distance = SIZE_MAX;
-
 
3199
               nearest_index = SIZE_MAX;
-
 
3200
               for (fsentry_index = 0; fsentry_index < fsentry_count; fsentry_index++)
-
 
3201
                  if (S_ISREG (fsentries[fsentry_index]->header.mode) // if this directory entry a file (i.e. it has a data blob)...
-
 
3202
                      && (imageheader_offset + (size_t) fsentries[fsentry_index]->u.file.offset >= current_offset) // ... AND its data blob is still ahead of our current pointer ...
-
 
3203
                      && (imageheader_offset + (size_t) fsentries[fsentry_index]->u.file.offset - current_offset < nearest_distance)) // ... AND it's the closest to us we've found so far
-
 
3204
                  {
-
 
3205
                     nearest_distance = imageheader_offset + (size_t) fsentries[fsentry_index]->u.file.offset - current_offset; // then remember it
-
 
3206
                     nearest_index = fsentry_index;
-
 
3207
                  }
-
 
3208
               if (nearest_index == SIZE_MAX)
-
 
3209
                  break; // found no file ahead, which means we've parsed the whole file data area, so stop the loop so as to proceed to the image trailer
-
 
3210
 
-
 
3211
               fsentry_index = nearest_index;
-
 
3212
               current_fsentry = fsentries[fsentry_index]; // quick access to closest fsentry
-
 
3213
 
-
 
3214
               // there may be padding before the file data
-
 
3215
               if (imageheader_offset + (size_t) current_fsentry->u.file.offset - current_offset > 0)
-
 
3216
                  hex_printf (&file.bytes[current_offset], imageheader_offset + (size_t) current_fsentry->u.file.offset - current_offset, "\n" "%zd padding bytes at offset 0x%zx (%zd):\n", imageheader_offset + (size_t) current_fsentry->u.file.offset - current_offset, current_offset, current_offset);
-
 
3217
               current_offset += imageheader_offset + (size_t) current_fsentry->u.file.offset - current_offset; // padding was processed, jump over it
-
 
3218
 
-
 
3219
               printf ("\n");
-
 
3220
               printf ("File data blob at offset 0x%zx (%zd):\n", current_offset, current_offset);
-
 
3221
               printf ("   corresponding dirent index: %zd/%zd\n", fsentry_index, fsentry_count);
-
 
3222
               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" : ""));
-
 
3223
               printf ("   corresponding path: \"%s\"\n", (char *) &current_fsentry->u.file.path); // convert from pointer to char array
-
 
3224
               printf ("   size 0x%zx (%zd) bytes\n", (size_t) current_fsentry->u.file.size, (size_t) current_fsentry->u.file.size);
-
 
3225
               if (current_offset + 4 < file.len)
-
 
3226
                  hex_printf (&file.bytes[current_offset], current_fsentry->u.file.size, "   data:\n");
-
 
3227
               if (current_offset + current_fsentry->u.file.size < file.len)
-
 
3228
                  printf ("   checksum %d\n", update_checksum (&file.bytes[current_offset], current_fsentry->u.file.size, is_foreign_endianness));
-
 
3229
               else
-
 
3230
               {
-
 
3231
                  LOG_WARNING ("this IFS file is corrupted (the size of this file data extends past the IFS size)");
-
 
3232
                  goto endofdata;
-
 
3233
               }
-
 
3234
 
-
 
3235
               current_offset += current_fsentry->u.file.size; // now jump over this file's data
-
 
3236
            }
-
 
3237
         }
-
 
3238
 
-
 
3239
         // ad this point we're past the last file data, there may be padding before the image trailer
-
 
3240
         if (imagetrailer_offset - current_offset > 0)
-
 
3241
            hex_printf (&file.bytes[current_offset], imagetrailer_offset - current_offset, "\n" "%zd padding bytes at offset %zx (%zd):\n", imagetrailer_offset - current_offset, current_offset, current_offset);
-
 
3242
         current_offset += imagetrailer_offset - current_offset; // padding was processed, jump over it
-
 
3243
 
-
 
3244
         printf ("\n");
-
 
3245
         printf ("Image trailer at offset 0x%zx (%zd) - version %d:\n", current_offset, current_offset, (image_header->flags & IMAGE_FLAGS_TRAILER_V2 ? 2 : 1));
-
 
3246
         if (image_header->flags & IMAGE_FLAGS_TRAILER_V2)
-
 
3247
         {
-
 
3248
            for (byte_index = 0; byte_index < SHA512_DIGEST_LENGTH; byte_index++)
-
 
3249
               sprintf (&recorded_sha512[2 * byte_index], "%02x", image_trailer_v2->sha512[byte_index]);
-
 
3250
            strcpy (computed_sha512, SHA512 (image_header, imagetrailer_offset - imageheader_offset, NULL));
-
 
3251
            recorded_checksum = image_trailer_v2->cksum;
-
 
3252
            computed_checksum = update_checksum (image_header, imagetrailer_offset + SHA512_DIGEST_LENGTH - imageheader_offset, is_foreign_endianness);
-
 
3253
            printf ("    sha512([0x%zx-0x%zx[) = %s - %s\n", imageheader_offset, imagetrailer_offset, recorded_sha512, (strcasecmp (computed_sha512, recorded_sha512) == 0 ? "GOOD" : "BAD"));
-
 
3254
            printf ("    cksum([0x%zx-0x%zx[) = 0x%08x - %s\n", imageheader_offset, imagetrailer_offset + SHA512_DIGEST_LENGTH, recorded_checksum, (computed_checksum == recorded_checksum ? "GOOD" : "BAD"));
-
 
3255
            if (strcasecmp (computed_sha512, recorded_sha512) != 0)
-
 
3256
               printf ("Computed SHA-512: %s\n", computed_sha512);
-
 
3257
            if (computed_checksum != recorded_checksum)
-
 
3258
               printf ("Computed cksum: 0x%08x\n", computed_checksum);
-
 
3259
         }
-
 
3260
         else // old v1 trailer
-
 
3261
         {
-
 
3262
            recorded_checksum = image_trailer_v1->cksum;
-
 
3263
            computed_checksum = update_checksum (image_header, image_header->image_size - sizeof (image_trailer_v1_t), is_foreign_endianness);
-
 
3264
            printf ("    cksum([0x%zx-0x%zx[) = 0x%08x - %s\n", imageheader_offset, imagetrailer_offset, recorded_checksum, (computed_checksum == recorded_checksum ? "GOOD" : "BAD"));
-
 
3265
            if (computed_checksum != recorded_checksum)
-
 
3266
               printf ("Computed cksum: 0x%08x\n", computed_checksum);
-
 
3267
         }
-
 
3268
 
-
 
3269
         current_offset += (image_header->flags & IMAGE_FLAGS_TRAILER_V2 ? sizeof (image_trailer_v2_t) : sizeof (image_trailer_v1_t)); // now reach the next segment (typically end of file)
-
 
3270
      }
-
 
3271
 
-
 
3272
      // else it has to be a boot blob, of which we don't know the size, except that it has to fit in 0xffff bytes and be immediately followed by a startup header
-
 
3273
      else
-
 
3274
      {
-
 
3275
         // so scan for the first startup header magic and version (which makes us 6 bytes to scan for, i.e. "\xeb\x7e\xff\x00" for the magic and "\x01\x00" (LSB) for the version 1)
-
 
3276
         for (byte_index = current_offset; byte_index < file.len - 6; byte_index++)
-
 
3277
            if (memcmp (&file.bytes[byte_index], "\xeb\x7e\xff\x00" "\x01\x00", 4 + 2) == 0)
-
 
3278
               break; // stop as soon as we find it
-
 
3279
 
-
 
3280
         if (byte_index >= file.len - 6)
-
 
3281
            break; // if not found, stop scanning
-
 
3282
 
-
 
3283
         bootfile_blobsize = byte_index - current_offset;
-
 
3284
         printf ("Boot blob at offset 0x%zx (%zd):\n", current_offset, current_offset);
-
 
3285
         printf ("   size 0x%zx (%zd) bytes\n", bootfile_blobsize, bootfile_blobsize);
-
 
3286
         printf ("   checksum 0x%08x\n", update_checksum (&file.bytes[current_offset], bootfile_blobsize, false)); // NOTE: endianness is not known yet -- assume same
-
 
3287
 
-
 
3288
         current_offset = byte_index; // now reach the next segment
-
 
3289
      }
-
 
3290
   }
1817
   }
3291
 
-
 
3292
endofdata:
-
 
3293
   // at this point there's nothing left we're able to parse
-
 
3294
   if (current_offset < file.len)
1818
   else // old V1 trailer
3295
   {
1819
   {
3296
      printf ("End of identifiable data reached.\n");
1820
      checksum = update_checksum (&ifs.data.bytes[ifs.offsets.imageheader], ifs.offsets.imagetrailer - ifs.offsets.imageheader, is_foreign_endianness); // compute old checksum
3297
      hex_printf (&file.bytes[current_offset], file.len - current_offset, "\n" "%zd extra bytes at offset %zx (%zd):\n", file.len - current_offset, current_offset, current_offset);
1821
      memcpy (&ifs.data.bytes[ifs.offsets.imagetrailer], &checksum, 4); // and write it in place
3298
   }
1822
   }
3299
 
1823
 
3300
   printf ("End of file reached at offset 0x%zx (%zd)\n", file.len, file.len);
1824
   // now rewrite IFS with the correct checksums
3301
   printf ("IFS dissecation complete.\n");
1825
   ASSERT_WITH_ERRNO (Buffer_WriteToFile (&ifs.data, ifs_pathname));
3302
   return (0);
-
 
3303
}
-
 
3304
 
1826
 
3305
 
-
 
3306
static int create_intermediate_dirs (const char *file_pathname)
-
 
3307
{
-
 
3308
   // creates all intermediate directories from root (or cwd) up to file_path
-
 
3309
 
-
 
3310
   char *temp_pathname;
-
 
3311
   char *separator;
-
 
3312
   size_t string_index;
-
 
3313
   size_t length;
1827
   // finished, cleanup
3314
 
-
 
3315
   temp_pathname = strdup (file_pathname); // have a working copy of file_pathname
-
 
3316
   if (temp_pathname == NULL)
-
 
3317
      return (-1); // on strdup() failure, return an error value (errno is set)
-
 
3318
   length = strlen (temp_pathname);
-
 
3319
   for (string_index = length - 1; string_index != SIZE_MAX; string_index--) // i.e. loop until it overflows
1828
   for (fsentry_index = 0; fsentry_index < fsentry_count; fsentry_index++)
3320
      if ((temp_pathname[string_index] == '/') || (temp_pathname[string_index] == '\\'))
-
 
3321
         break; // look for the last directory separator and stop as soon as we find it
-
 
3322
   if (string_index != SIZE_MAX)
-
 
3323
   {
1829
   {
3324
      for (; string_index < length; string_index++)
-
 
3325
         temp_pathname[string_index] = 0; // if we found one, break there so as to have just the path and clear the rest of the string
-
 
3326
      separator = strtok (&temp_pathname[1], "/\\"); // for each separator in the remaining string past the first one...
-
 
3327
      while (separator != NULL)
-
 
3328
      {
-
 
3329
         (void) mkdir (temp_pathname, 0755); // create directories recursively
-
 
3330
         temp_pathname[strlen (temp_pathname)] = '/'; // put the separator back
-
 
3331
         separator = strtok (NULL, "/\\"); // and look for the next one
-
 
3332
      }
-
 
3333
   }
1830
   }
3334
 
1831
 
3335
   free (temp_pathname); // release our working copy of file_pathname
-
 
3336
   return (0);
-
 
3337
}
-
 
3338
 
-
 
3339
 
-
 
3340
static int dump_ifs_contents (const char *ifs_pathname, const char *outdir)
-
 
3341
{
-
 
3342
   static char outfile_pathname[MAXPATHLEN] = "";
-
 
3343
 
-
 
3344
   startup_header_t *startup_header = NULL;
-
 
3345
   size_t startupheader_offset = 0;
-
 
3346
   image_header_t *image_header = NULL;
-
 
3347
   size_t imageheader_offset = 0;
-
 
3348
   size_t imagetrailer_offset = 0;
-
 
3349
   fsentry_t **fsentries = NULL; // mallocated
-
 
3350
   size_t fsentry_count = 0;
-
 
3351
   fsentry_t *current_fsentry = NULL;
-
 
3352
   size_t startupfile_blobsize = 0;
-
 
3353
   struct utimbuf file_times = { 0, 0 };
-
 
3354
   void *reallocated_ptr;
-
 
3355
   size_t bootfile_blobsize = 0;
-
 
3356
   size_t current_offset;
-
 
3357
   size_t fsentry_index;
-
 
3358
   size_t nearest_distance;
-
 
3359
   size_t nearest_index;
-
 
3360
   size_t byte_index;
-
 
3361
   buffer_t file;
-
 
3362
   FILE *fp;
-
 
3363
 
-
 
3364
   // open and read IFS file
-
 
3365
   if (read_filecontents (ifs_pathname, ".", &file) == NULL)
-
 
3366
      DIE_WITH_EXITCODE (1, "can't open \"%s\" for reading: %s\n", ifs_pathname, strerror (errno));
-
 
3367
 
-
 
3368
   // create the output directory
1832
   // and exit with a success code
3369
   create_intermediate_dirs (outdir);
-
 
3370
   (void) mkdir (outdir, 0755);
-
 
3371
 
-
 
3372
   // parse file from start to end
-
 
3373
   current_offset = 0;
-
 
3374
   for (;;)
-
 
3375
   {
-
 
3376
      // does a startup header start here ?
-
 
3377
      if ((current_offset + sizeof (startup_header_t) < file.len) && (memcmp (&file.bytes[current_offset], "\xeb\x7e\xff\x00", 4) == 0))
-
 
3378
      {
-
 
3379
         startupheader_offset = current_offset;
-
 
3380
         startup_header = (startup_header_t *) &file.bytes[startupheader_offset];
-
 
3381
 
-
 
3382
         // layout:
-
 
3383
         // [STARTUP HEADER]
-
 
3384
         // (startup file blob)
-
 
3385
         // [STARTUP TRAILER v1 or v2]
-
 
3386
 
-
 
3387
         // validate that the file can contain up to the startup trailer
-
 
3388
         if (current_offset + startup_header->startup_size > file.len)
-
 
3389
         {
-
 
3390
            LOG_WARNING ("this IFS file is corrupted (startup trailer extends past end of file)");
-
 
3391
            goto endofdata;
-
 
3392
         }
-
 
3393
 
-
 
3394
         // locate the right startup trailer at the right offset
-
 
3395
         if (startup_header->flags1 & STARTUP_HDR_FLAGS1_TRAILER_V2)
-
 
3396
            startupfile_blobsize = startup_header->startup_size - sizeof (startup_header_t) - sizeof (startup_trailer_v2_t);
-
 
3397
         else // old V1 trailer
-
 
3398
            startupfile_blobsize = startup_header->startup_size - sizeof (startup_header_t) - sizeof (startup_trailer_v1_t);
-
 
3399
 
-
 
3400
         current_offset += sizeof (startup_header_t); // jump over the startup header and reach the startup blob
-
 
3401
 
-
 
3402
         // write startup blob
-
 
3403
         sprintf (outfile_pathname, "%s/STARTUP.BLOB", outdir);
-
 
3404
         fp = fopen (outfile_pathname, "wb");
-
 
3405
         WELLMANNERED_ASSERT (fp, "failed to open '%s': %s", outfile_pathname, strerror (errno));
-
 
3406
         fwrite (&file.bytes[current_offset], 1, startupfile_blobsize, fp);
-
 
3407
         fclose (fp);
1833
   LOG_INFO ("Success");
3408
 
-
 
3409
         current_offset += startupfile_blobsize; // jump over the startup blob and reach the startup trailer
-
 
3410
         current_offset += (startup_header->flags1 & STARTUP_HDR_FLAGS1_TRAILER_V2 ? sizeof (startup_trailer_v2_t) : sizeof (startup_trailer_v1_t)); // jump over the startup trailer and reach the next segment
-
 
3411
      }
-
 
3412
 
-
 
3413
      // else does an image header start here ?
-
 
3414
      else if ((current_offset + sizeof (image_header_t) < file.len) && (memcmp (&file.bytes[current_offset], "imagefs", 7) == 0))
-
 
3415
      {
-
 
3416
         imageheader_offset = current_offset;
-
 
3417
         image_header = (image_header_t *) &file.bytes[imageheader_offset];
-
 
3418
 
-
 
3419
         // layout:
-
 
3420
         // [IMAGE HEADER]
-
 
3421
         // [image directory entries]
-
 
3422
         // [smallest file blobs up to KERNEL]
-
 
3423
         // [padding]
-
 
3424
         // [KERNEL]
-
 
3425
         // [rest of file blobs]
-
 
3426
         // [IMAGE FOOTER]
-
 
3427
 
-
 
3428
         // validate that the file can contain up to the image trailer
-
 
3429
         if (current_offset + image_header->image_size > file.len)
-
 
3430
         {
-
 
3431
            LOG_WARNING ("this IFS file is corrupted (image trailer extends past end of file)");
-
 
3432
            goto endofdata;
-
 
3433
         }
-
 
3434
 
-
 
3435
         // locate the image trailer at the right offset
-
 
3436
         if (image_header->flags & IMAGE_FLAGS_TRAILER_V2)
-
 
3437
            imagetrailer_offset = current_offset + image_header->image_size - sizeof (image_trailer_v2_t);
-
 
3438
         else // old V1 trailer
-
 
3439
            imagetrailer_offset = current_offset + image_header->image_size - sizeof (image_trailer_v1_t);
-
 
3440
 
-
 
3441
         current_offset += sizeof (image_header_t); // jump over the image header
-
 
3442
         current_offset += image_header->dir_offset - sizeof (image_header_t); // jump over possible padding
-
 
3443
 
-
 
3444
         // dump all directory entries until the last one included
-
 
3445
         fsentries = NULL;
-
 
3446
         fsentry_count = 0;
-
 
3447
         while (current_offset < imageheader_offset + image_header->hdr_dir_size)
-
 
3448
         {
-
 
3449
            current_fsentry = (fsentry_t *) &file.bytes[current_offset];
-
 
3450
 
-
 
3451
            if (imageheader_offset + image_header->hdr_dir_size - current_offset < sizeof (current_fsentry->header))
-
 
3452
               break; // end padding reached
-
 
3453
 
-
 
3454
            // stack up the filesystem entry pointers in an array while we read them
-
 
3455
            reallocated_ptr = realloc (fsentries, (fsentry_count + 1) * sizeof (fsentry_t *));
-
 
3456
            WELLMANNERED_ASSERT (reallocated_ptr, "out of memory");
-
 
3457
            fsentries = reallocated_ptr;
-
 
3458
            fsentries[fsentry_count] = current_fsentry;
-
 
3459
            fsentry_count++;
-
 
3460
 
-
 
3461
            if ((current_fsentry->header.size == 0) || (current_offset + current_fsentry->header.size >= file.len))
-
 
3462
            {
-
 
3463
               LOG_WARNING ("this IFS file is corrupted (the size of this directory entry is invalid)");
-
 
3464
               goto endofdata;
-
 
3465
            }
-
 
3466
 
-
 
3467
            current_offset += current_fsentry->header.size;
-
 
3468
         }
-
 
3469
         current_offset += imageheader_offset + image_header->hdr_dir_size - current_offset; // jump over possible padding
-
 
3470
 
-
 
3471
         // at this point we are past the directory entries; what is stored now, up to and until the image trailer, is the files' data
-
 
3472
         if (fsentry_count > 0)
-
 
3473
         {
-
 
3474
            while (current_offset < imagetrailer_offset) // and parse data up to the trailer
-
 
3475
            {
-
 
3476
               nearest_distance = SIZE_MAX;
-
 
3477
               nearest_index = SIZE_MAX;
-
 
3478
               for (fsentry_index = 0; fsentry_index < fsentry_count; fsentry_index++)
-
 
3479
                  if (S_ISREG (fsentries[fsentry_index]->header.mode) // if this directory entry a file (i.e. it has a data blob)...
-
 
3480
                      && (imageheader_offset + (size_t) fsentries[fsentry_index]->u.file.offset >= current_offset) // ... AND its data blob is still ahead of our current pointer ...
-
 
3481
                      && (imageheader_offset + (size_t) fsentries[fsentry_index]->u.file.offset - current_offset < nearest_distance)) // ... AND it's the closest to us we've found so far
-
 
3482
                  {
-
 
3483
                     nearest_distance = imageheader_offset + (size_t) fsentries[fsentry_index]->u.file.offset - current_offset; // then remember it
-
 
3484
                     nearest_index = fsentry_index;
-
 
3485
                  }
-
 
3486
               if (nearest_index == SIZE_MAX)
-
 
3487
                  break; // found no file ahead, which means we've parsed the whole file data area, so stop the loop so as to proceed to the image trailer
-
 
3488
 
-
 
3489
               fsentry_index = nearest_index;
-
 
3490
               current_fsentry = fsentries[fsentry_index]; // quick access to closest fsentry
-
 
3491
 
-
 
3492
               current_offset += imageheader_offset + (size_t) current_fsentry->u.file.offset - current_offset; // jump over possible padding
-
 
3493
 
-
 
3494
               if (current_offset + current_fsentry->u.file.size >= file.len)
-
 
3495
               {
-
 
3496
                  LOG_WARNING ("this IFS file is corrupted (the size of this file data extends past the IFS size)");
-
 
3497
                  goto endofdata;
-
 
3498
               }
-
 
3499
 
-
 
3500
               // write filesystem data entry
-
 
3501
               if (S_ISDIR (current_fsentry->header.mode))
-
 
3502
               {
-
 
3503
                  sprintf (outfile_pathname, "%s/%s", outdir, (char *) &current_fsentry->u.dir.path); // convert from pointer to char array
-
 
3504
                  create_intermediate_dirs (outfile_pathname);
-
 
3505
                  (void) mkdir (outfile_pathname, current_fsentry->header.mode & 0777);
-
 
3506
               }
-
 
3507
               else if (S_ISLNK (current_fsentry->header.mode))
-
 
3508
               {
-
 
3509
                  sprintf (outfile_pathname, "%s/%s", outdir, (char *) &current_fsentry->u.symlink.path); // convert from pointer to char array
-
 
3510
                  create_intermediate_dirs (outfile_pathname);
-
 
3511
#ifdef _WIN32
-
 
3512
                  fp = fopen (outfile_pathname, "wb"); // on Windows create symlinks as plain files
-
 
3513
                  WELLMANNERED_ASSERT (fp, "failed to open '%s': %s", outfile_pathname, strerror (errno));
-
 
3514
                  fwrite ((char *) &current_fsentry->u.symlink.path + current_fsentry->u.symlink.sym_offset, 1, current_fsentry->u.symlink.sym_size, fp); // convert from pointer to char array
-
 
3515
                  fclose (fp);
-
 
3516
#else // !_WIN32, thus POSIX
-
 
3517
                  symlink (current_fsentry->u.symlink.contents, outfile_pathname); // on UNIX systems, just create the symlink for real
-
 
3518
#endif // _WIN32
-
 
3519
               }
-
 
3520
               else if (S_ISREG (current_fsentry->header.mode))
-
 
3521
               {
-
 
3522
                  sprintf (outfile_pathname, "%s/%s", outdir, (char *) &current_fsentry->u.file.path); // convert from pointer to char array
-
 
3523
                  create_intermediate_dirs (outfile_pathname);
-
 
3524
                  fp = fopen (outfile_pathname, "wb"); // on Windows create symlinks as plain files
-
 
3525
                  WELLMANNERED_ASSERT (fp, "failed to open '%s': %s", outfile_pathname, strerror (errno));
-
 
3526
                  fwrite (&file.bytes[current_offset], 1, current_fsentry->u.file.size, fp);
-
 
3527
                  fclose (fp);
-
 
3528
               }
-
 
3529
               else // must be a device node. Since we might not be the super-user and/or on Win32, create plain file with "X:Y" as data
-
 
3530
               {
-
 
3531
                  sprintf (outfile_pathname, "%s/%s", outdir, (char *) &current_fsentry->u.device.path); // convert from pointer to char array
-
 
3532
                  create_intermediate_dirs (outfile_pathname);
-
 
3533
                  fp = fopen (outfile_pathname, "wb"); // on Windows create symlinks as plain files
-
 
3534
                  WELLMANNERED_ASSERT (fp, "failed to open '%s': %s", outfile_pathname, strerror (errno));
-
 
3535
                  fprintf (fp, "%u:%u", current_fsentry->u.device.dev, current_fsentry->u.device.rdev);
-
 
3536
                  fclose (fp);
-
 
3537
               }
-
 
3538
 
-
 
3539
               // set created file mtime
-
 
3540
               file_times.actime = current_fsentry->header.mtime;
-
 
3541
               file_times.modtime = current_fsentry->header.mtime;
-
 
3542
               utime (outfile_pathname, &file_times);
-
 
3543
 
-
 
3544
               // set created file mode
-
 
3545
#ifndef _WIN32
-
 
3546
               (void) chmod (outfile_pathname, current_fsentry->header.mode & 0777); // only on POSIX systems
-
 
3547
#endif // !_WIN32
-
 
3548
 
-
 
3549
               current_offset += current_fsentry->u.file.size; // now jump over this file's data
-
 
3550
            }
-
 
3551
         }
-
 
3552
 
-
 
3553
         // ad this point we're past the last file data, there may be padding before the image trailer
-
 
3554
         current_offset += imagetrailer_offset - current_offset; // jump over possible padding and reach the image trailer
-
 
3555
         current_offset += (image_header->flags & IMAGE_FLAGS_TRAILER_V2 ? sizeof (image_trailer_v2_t) : sizeof (image_trailer_v1_t)); // now jump over the image trailer and reach the next segment (typically end of file)
-
 
3556
      }
-
 
3557
 
-
 
3558
      // else it has to be a boot blob, of which we don't know the size, except that it has to fit in 0xffff bytes and be immediately followed by a startup header
-
 
3559
      else
-
 
3560
      {
-
 
3561
         // so scan for the first startup header magic and version (which makes us 6 bytes to scan for, i.e. "\xeb\x7e\xff\x00" for the magic and "\x01\x00" (LSB) for the version 1)
-
 
3562
         for (byte_index = current_offset; byte_index < file.len - 6; byte_index++)
-
 
3563
            if (memcmp (&file.bytes[byte_index], "\xeb\x7e\xff\x00" "\x01\x00", 4 + 2) == 0)
-
 
3564
               break; // stop as soon as we find it
-
 
3565
 
-
 
3566
         if (byte_index >= file.len - 6)
-
 
3567
            break; // if not found, stop scanning
-
 
3568
 
-
 
3569
         bootfile_blobsize = byte_index - current_offset;
-
 
3570
 
-
 
3571
         // write boot blob
-
 
3572
         sprintf (outfile_pathname, "%s/BOOT.BLOB", outdir);
-
 
3573
         fp = fopen (outfile_pathname, "wb");
-
 
3574
         WELLMANNERED_ASSERT (fp, "failed to open '%s': %s", outfile_pathname, strerror (errno));
-
 
3575
         fwrite (&file.bytes[current_offset], 1, bootfile_blobsize, fp);
-
 
3576
         fclose (fp);
-
 
3577
 
-
 
3578
         current_offset = byte_index; // now reach the next segment
-
 
3579
      }
-
 
3580
   }
-
 
3581
 
-
 
3582
endofdata:
-
 
3583
   return (0);
1834
   exit (0);
3584
}
1835
}