Subversion Repositories QNX 8.QNX8 IFS tool

Rev

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

Rev 14 Rev 15
Line 20... Line 20...
20
// compiler-specific glue
20
// compiler-specific glue
21
#ifdef _MSC_VER
21
#ifdef _MSC_VER
22
#include <io.h>
22
#include <io.h>
23
#include <direct.h>
23
#include <direct.h>
24
#include <sys/utime.h>
24
#include <sys/utime.h>
-
 
25
#include <process.h>
25
#define __x86_64__ 1
26
#define __x86_64__ 1
26
#define __ORDER_BIG_ENDIAN__    4321
27
#define __ORDER_BIG_ENDIAN__    4321
27
#define __ORDER_LITTLE_ENDIAN__ 1234
28
#define __ORDER_LITTLE_ENDIAN__ 1234
28
#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
29
#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
29
#define __attribute__(x)
30
#define __attribute__(x)
Line 39... Line 40...
39
#define strcasecmp(s1,s2) _stricmp ((s1), (s2))
40
#define strcasecmp(s1,s2) _stricmp ((s1), (s2))
40
#define fseek(fp,off,m) _fseeki64 ((fp), (off), (m))
41
#define fseek(fp,off,m) _fseeki64 ((fp), (off), (m))
41
#define access(p,m) _access ((p), (m))
42
#define access(p,m) _access ((p), (m))
42
#define mkdir(p,m) _mkdir ((p))
43
#define mkdir(p,m) _mkdir ((p))
43
#define chmod(p,m) _chmod ((p), (m))
44
#define chmod(p,m) _chmod ((p), (m))
-
 
45
#define unlink(p) _unlink ((p))
44
#define utimbuf __utimbuf32
46
#define utimbuf __utimbuf32
45
#define utime(p,t) _utime32 ((p), (t))
47
#define utime(p,t) _utime32 ((p), (t))
46
#define MAXPATHLEN 1024
48
#define MAXPATHLEN 1024
47
#ifndef thread_local
49
#ifndef thread_local
48
#define thread_local __declspec(thread) // the thread_local keyword wasn't defined before C++11 and C23
50
#define thread_local __declspec(thread) // the thread_local keyword wasn't defined before C++11 and C23
Line 121... Line 123...
121
 
123
 
122
 
124
 
123
// macro to bring __FILE_NAME__ support to moronic compilers
125
// macro to bring __FILE_NAME__ support to moronic compilers
124
#ifndef __FILE_NAME__ // Clang 9+ has the macro, GCC 12+ added it too in 2021, MSVC obviously won't do it. Heh.
126
#ifndef __FILE_NAME__ // Clang 9+ has the macro, GCC 12+ added it too in 2021, MSVC obviously won't do it. Heh.
125
#define __FILE_NAME__ ( \
127
#define __FILE_NAME__ ( \
126
   (sizeof (__FILE__) >  2) && (__FILE__[sizeof (__FILE__) -  2] == '/') ? &__FILE__[sizeof (__FILE__) -  1] : \
128
   (sizeof (__FILE__) >  2) && ((__FILE__[sizeof (__FILE__) -  2] == '/') || (__FILE__[sizeof (__FILE__) -  2] == '\\')) ? &__FILE__[sizeof (__FILE__) -  1] : \
127
   (sizeof (__FILE__) >  3) && (__FILE__[sizeof (__FILE__) -  3] == '/') ? &__FILE__[sizeof (__FILE__) -  2] : \
129
   (sizeof (__FILE__) >  3) && ((__FILE__[sizeof (__FILE__) -  3] == '/') || (__FILE__[sizeof (__FILE__) -  3] == '\\')) ? &__FILE__[sizeof (__FILE__) -  2] : \
128
   (sizeof (__FILE__) >  4) && (__FILE__[sizeof (__FILE__) -  4] == '/') ? &__FILE__[sizeof (__FILE__) -  3] : \
130
   (sizeof (__FILE__) >  4) && ((__FILE__[sizeof (__FILE__) -  4] == '/') || (__FILE__[sizeof (__FILE__) -  4] == '\\')) ? &__FILE__[sizeof (__FILE__) -  3] : \
129
   (sizeof (__FILE__) >  5) && (__FILE__[sizeof (__FILE__) -  5] == '/') ? &__FILE__[sizeof (__FILE__) -  4] : \
131
   (sizeof (__FILE__) >  5) && ((__FILE__[sizeof (__FILE__) -  5] == '/') || (__FILE__[sizeof (__FILE__) -  5] == '\\')) ? &__FILE__[sizeof (__FILE__) -  4] : \
130
   (sizeof (__FILE__) >  6) && (__FILE__[sizeof (__FILE__) -  6] == '/') ? &__FILE__[sizeof (__FILE__) -  5] : \
132
   (sizeof (__FILE__) >  6) && ((__FILE__[sizeof (__FILE__) -  6] == '/') || (__FILE__[sizeof (__FILE__) -  6] == '\\')) ? &__FILE__[sizeof (__FILE__) -  5] : \
131
   (sizeof (__FILE__) >  7) && (__FILE__[sizeof (__FILE__) -  7] == '/') ? &__FILE__[sizeof (__FILE__) -  6] : \
133
   (sizeof (__FILE__) >  7) && ((__FILE__[sizeof (__FILE__) -  7] == '/') || (__FILE__[sizeof (__FILE__) -  7] == '\\')) ? &__FILE__[sizeof (__FILE__) -  6] : \
132
   (sizeof (__FILE__) >  8) && (__FILE__[sizeof (__FILE__) -  8] == '/') ? &__FILE__[sizeof (__FILE__) -  7] : \
134
   (sizeof (__FILE__) >  8) && ((__FILE__[sizeof (__FILE__) -  8] == '/') || (__FILE__[sizeof (__FILE__) -  8] == '\\')) ? &__FILE__[sizeof (__FILE__) -  7] : \
133
   (sizeof (__FILE__) >  9) && (__FILE__[sizeof (__FILE__) -  9] == '/') ? &__FILE__[sizeof (__FILE__) -  8] : \
135
   (sizeof (__FILE__) >  9) && ((__FILE__[sizeof (__FILE__) -  9] == '/') || (__FILE__[sizeof (__FILE__) -  9] == '\\')) ? &__FILE__[sizeof (__FILE__) -  8] : \
134
   (sizeof (__FILE__) > 10) && (__FILE__[sizeof (__FILE__) - 10] == '/') ? &__FILE__[sizeof (__FILE__) -  9] : \
136
   (sizeof (__FILE__) > 10) && ((__FILE__[sizeof (__FILE__) - 10] == '/') || (__FILE__[sizeof (__FILE__) - 10] == '\\')) ? &__FILE__[sizeof (__FILE__) -  9] : \
135
   (sizeof (__FILE__) > 11) && (__FILE__[sizeof (__FILE__) - 11] == '/') ? &__FILE__[sizeof (__FILE__) - 10] : \
137
   (sizeof (__FILE__) > 11) && ((__FILE__[sizeof (__FILE__) - 11] == '/') || (__FILE__[sizeof (__FILE__) - 11] == '\\')) ? &__FILE__[sizeof (__FILE__) - 10] : \
136
   (sizeof (__FILE__) > 12) && (__FILE__[sizeof (__FILE__) - 12] == '/') ? &__FILE__[sizeof (__FILE__) - 11] : \
138
   (sizeof (__FILE__) > 12) && ((__FILE__[sizeof (__FILE__) - 12] == '/') || (__FILE__[sizeof (__FILE__) - 12] == '\\')) ? &__FILE__[sizeof (__FILE__) - 11] : \
137
   (sizeof (__FILE__) > 13) && (__FILE__[sizeof (__FILE__) - 13] == '/') ? &__FILE__[sizeof (__FILE__) - 12] : \
139
   (sizeof (__FILE__) > 13) && ((__FILE__[sizeof (__FILE__) - 13] == '/') || (__FILE__[sizeof (__FILE__) - 13] == '\\')) ? &__FILE__[sizeof (__FILE__) - 12] : \
138
   (sizeof (__FILE__) > 14) && (__FILE__[sizeof (__FILE__) - 14] == '/') ? &__FILE__[sizeof (__FILE__) - 13] : \
140
   (sizeof (__FILE__) > 14) && ((__FILE__[sizeof (__FILE__) - 14] == '/') || (__FILE__[sizeof (__FILE__) - 14] == '\\')) ? &__FILE__[sizeof (__FILE__) - 13] : \
139
   (sizeof (__FILE__) > 15) && (__FILE__[sizeof (__FILE__) - 15] == '/') ? &__FILE__[sizeof (__FILE__) - 14] : \
141
   (sizeof (__FILE__) > 15) && ((__FILE__[sizeof (__FILE__) - 15] == '/') || (__FILE__[sizeof (__FILE__) - 15] == '\\')) ? &__FILE__[sizeof (__FILE__) - 14] : \
140
   (sizeof (__FILE__) > 16) && (__FILE__[sizeof (__FILE__) - 16] == '/') ? &__FILE__[sizeof (__FILE__) - 15] : \
142
   (sizeof (__FILE__) > 16) && ((__FILE__[sizeof (__FILE__) - 16] == '/') || (__FILE__[sizeof (__FILE__) - 16] == '\\')) ? &__FILE__[sizeof (__FILE__) - 15] : \
141
   (sizeof (__FILE__) > 17) && (__FILE__[sizeof (__FILE__) - 17] == '/') ? &__FILE__[sizeof (__FILE__) - 16] : \
143
   (sizeof (__FILE__) > 17) && ((__FILE__[sizeof (__FILE__) - 17] == '/') || (__FILE__[sizeof (__FILE__) - 17] == '\\')) ? &__FILE__[sizeof (__FILE__) - 16] : \
142
   (sizeof (__FILE__) > 18) && (__FILE__[sizeof (__FILE__) - 18] == '/') ? &__FILE__[sizeof (__FILE__) - 17] : \
144
   (sizeof (__FILE__) > 18) && ((__FILE__[sizeof (__FILE__) - 18] == '/') || (__FILE__[sizeof (__FILE__) - 18] == '\\')) ? &__FILE__[sizeof (__FILE__) - 17] : \
143
   (sizeof (__FILE__) > 19) && (__FILE__[sizeof (__FILE__) - 19] == '/') ? &__FILE__[sizeof (__FILE__) - 18] : \
145
   (sizeof (__FILE__) > 19) && ((__FILE__[sizeof (__FILE__) - 19] == '/') || (__FILE__[sizeof (__FILE__) - 19] == '\\')) ? &__FILE__[sizeof (__FILE__) - 18] : \
144
   (sizeof (__FILE__) > 20) && (__FILE__[sizeof (__FILE__) - 20] == '/') ? &__FILE__[sizeof (__FILE__) - 19] : \
146
   (sizeof (__FILE__) > 20) && ((__FILE__[sizeof (__FILE__) - 20] == '/') || (__FILE__[sizeof (__FILE__) - 20] == '\\')) ? &__FILE__[sizeof (__FILE__) - 19] : \
145
   (sizeof (__FILE__) > 21) && (__FILE__[sizeof (__FILE__) - 21] == '/') ? &__FILE__[sizeof (__FILE__) - 20] : \
147
   (sizeof (__FILE__) > 21) && ((__FILE__[sizeof (__FILE__) - 21] == '/') || (__FILE__[sizeof (__FILE__) - 21] == '\\')) ? &__FILE__[sizeof (__FILE__) - 20] : \
146
   (sizeof (__FILE__) > 22) && (__FILE__[sizeof (__FILE__) - 22] == '/') ? &__FILE__[sizeof (__FILE__) - 21] : \
148
   (sizeof (__FILE__) > 22) && ((__FILE__[sizeof (__FILE__) - 22] == '/') || (__FILE__[sizeof (__FILE__) - 22] == '\\')) ? &__FILE__[sizeof (__FILE__) - 21] : \
147
   (sizeof (__FILE__) > 23) && (__FILE__[sizeof (__FILE__) - 23] == '/') ? &__FILE__[sizeof (__FILE__) - 22] : \
149
   (sizeof (__FILE__) > 23) && ((__FILE__[sizeof (__FILE__) - 23] == '/') || (__FILE__[sizeof (__FILE__) - 23] == '\\')) ? &__FILE__[sizeof (__FILE__) - 22] : \
148
   (sizeof (__FILE__) > 24) && (__FILE__[sizeof (__FILE__) - 24] == '/') ? &__FILE__[sizeof (__FILE__) - 23] : \
150
   (sizeof (__FILE__) > 24) && ((__FILE__[sizeof (__FILE__) - 24] == '/') || (__FILE__[sizeof (__FILE__) - 24] == '\\')) ? &__FILE__[sizeof (__FILE__) - 23] : \
149
   (sizeof (__FILE__) > 25) && (__FILE__[sizeof (__FILE__) - 25] == '/') ? &__FILE__[sizeof (__FILE__) - 24] : \
151
   (sizeof (__FILE__) > 25) && ((__FILE__[sizeof (__FILE__) - 25] == '/') || (__FILE__[sizeof (__FILE__) - 25] == '\\')) ? &__FILE__[sizeof (__FILE__) - 24] : \
150
   (sizeof (__FILE__) > 26) && (__FILE__[sizeof (__FILE__) - 26] == '/') ? &__FILE__[sizeof (__FILE__) - 25] : \
152
   (sizeof (__FILE__) > 26) && ((__FILE__[sizeof (__FILE__) - 26] == '/') || (__FILE__[sizeof (__FILE__) - 26] == '\\')) ? &__FILE__[sizeof (__FILE__) - 25] : \
151
   (sizeof (__FILE__) > 27) && (__FILE__[sizeof (__FILE__) - 27] == '/') ? &__FILE__[sizeof (__FILE__) - 26] : \
153
   (sizeof (__FILE__) > 27) && ((__FILE__[sizeof (__FILE__) - 27] == '/') || (__FILE__[sizeof (__FILE__) - 27] == '\\')) ? &__FILE__[sizeof (__FILE__) - 26] : \
152
   (sizeof (__FILE__) > 28) && (__FILE__[sizeof (__FILE__) - 28] == '/') ? &__FILE__[sizeof (__FILE__) - 27] : \
154
   (sizeof (__FILE__) > 28) && ((__FILE__[sizeof (__FILE__) - 28] == '/') || (__FILE__[sizeof (__FILE__) - 28] == '\\')) ? &__FILE__[sizeof (__FILE__) - 27] : \
153
   (sizeof (__FILE__) > 29) && (__FILE__[sizeof (__FILE__) - 29] == '/') ? &__FILE__[sizeof (__FILE__) - 28] : \
155
   (sizeof (__FILE__) > 29) && ((__FILE__[sizeof (__FILE__) - 29] == '/') || (__FILE__[sizeof (__FILE__) - 29] == '\\')) ? &__FILE__[sizeof (__FILE__) - 28] : \
154
   (sizeof (__FILE__) > 30) && (__FILE__[sizeof (__FILE__) - 30] == '/') ? &__FILE__[sizeof (__FILE__) - 29] : \
156
   (sizeof (__FILE__) > 30) && ((__FILE__[sizeof (__FILE__) - 30] == '/') || (__FILE__[sizeof (__FILE__) - 30] == '\\')) ? &__FILE__[sizeof (__FILE__) - 29] : \
155
   (sizeof (__FILE__) > 31) && (__FILE__[sizeof (__FILE__) - 31] == '/') ? &__FILE__[sizeof (__FILE__) - 30] : \
157
   (sizeof (__FILE__) > 31) && ((__FILE__[sizeof (__FILE__) - 31] == '/') || (__FILE__[sizeof (__FILE__) - 31] == '\\')) ? &__FILE__[sizeof (__FILE__) - 30] : \
156
   (sizeof (__FILE__) > 32) && (__FILE__[sizeof (__FILE__) - 32] == '/') ? &__FILE__[sizeof (__FILE__) - 31] : \
158
   (sizeof (__FILE__) > 32) && ((__FILE__[sizeof (__FILE__) - 32] == '/') || (__FILE__[sizeof (__FILE__) - 32] == '\\')) ? &__FILE__[sizeof (__FILE__) - 31] : \
157
   (sizeof (__FILE__) > 33) && (__FILE__[sizeof (__FILE__) - 33] == '/') ? &__FILE__[sizeof (__FILE__) - 32] : \
159
   (sizeof (__FILE__) > 33) && ((__FILE__[sizeof (__FILE__) - 33] == '/') || (__FILE__[sizeof (__FILE__) - 33] == '\\')) ? &__FILE__[sizeof (__FILE__) - 32] : \
158
   __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.
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.
159
#endif // !__FILE_NAME__
161
#endif // !__FILE_NAME__
160
 
162
 
-
 
163
 
-
 
164
// logging macros
-
 
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)
-
 
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__)
-
 
170
 
-
 
171
// macro to gently exit with an error message
-
 
172
#define DIE_WITH_EXITCODE(exitcode,...) do { LOG_ERROR (__VA_ARGS__); exit ((exitcode)); } while (0)
161
 
173
 
162
// macro to exit less brutally than with abort() if something doesn't go the way we'd like to
174
// macro to exit less brutally than with abort() if something doesn't go the way we'd like to
163
#define WELLMANNERED_ASSERT(is_is_true,...) do { if (!(is_is_true)) { fprintf (stderr, "ifstool: fatal error: consistency check in %s() at %s line %d failed: ", __FUNCTION__, __FILE_NAME__, __LINE__); fprintf (stderr, __VA_ARGS__); fputc ('\n', stderr); exit (1); } } while (0)
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)
164
 
176
 
165
 
177
 
166
// macros for checked read/write/seek operations
178
// macros for checked read/write/seek operations
167
#define fseek_or_die(fp,pos,mode) WELLMANNERED_ASSERT (fseek ((fp), (pos), (mode)) == 0, "fseek() failed with errno %d (%s)", errno, strerror (errno))
179
#define fseek_or_die(fp,pos,mode) WELLMANNERED_ASSERT (fseek ((fp), (pos), (mode)) == 0, "fseek() failed with errno %d (%s)", errno, strerror (errno))
168
#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))
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))
Line 695... Line 707...
695
   uint32_t mtime; // entry's modification time POSIX timestamp - set to UINT32_MAX to use the concerned files' mtime on the build host
707
   uint32_t mtime; // entry's modification time POSIX timestamp - set to UINT32_MAX to use the concerned files' mtime on the build host
696
   uint32_t mtime_for_inline_files; // same as above but only for files that don't exist on the build host (i.e. files with an explicit content blob)
708
   uint32_t mtime_for_inline_files; // same as above but only for files that don't exist on the build host (i.e. files with an explicit content blob)
697
   char prefix[MAXPATHLEN]; // install path (e.g. "proc/boot")
709
   char prefix[MAXPATHLEN]; // install path (e.g. "proc/boot")
698
   bool should_follow_symlinks; // follow symlinks
710
   bool should_follow_symlinks; // follow symlinks
699
   bool should_autosymlink_dylib; // dynamic libraries should be written under their official SONAME and a named symlink be created pointing at them
711
   bool should_autosymlink_dylib; // dynamic libraries should be written under their official SONAME and a named symlink be created pointing at them
-
 
712
   bool should_keep_ld_output; // whether to keep .sym files produced by ld calls, togglable by the [+keeplinked] attribute
700
   bool is_compiled_bootscript; // entry has [+script] attribute
713
   bool is_compiled_bootscript; // entry has [+script] attribute
701
   int extra_ino_flags; // bitmap of extra inode flags (IFS_INO_xxx)
714
   int extra_ino_flags; // bitmap of extra inode flags (IFS_INO_xxx)
702
   char search[10 * MAXPATHLEN]; // binary search path (the default one will be constructed at startup)
715
   char search[10 * MAXPATHLEN]; // binary search path (the default one will be constructed at startup)
703
 
716
 
704
   buffer_t data;
717
   buffer_t data;
Line 719... Line 732...
719
#elif defined(__aarch64__)
732
#elif defined(__aarch64__)
720
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)
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)
721
#else // unknown platform
734
#else // unknown platform
722
#error Please port ifstool to this platform
735
#error Please port ifstool to this platform
723
#endif
736
#endif
-
 
737
static int verbose_level = 1; // verbosity level, can be increased with multiple -v[...] flags
724
static char *buildfile_pathname = NULL; // pathname of IFS build file
738
static char *buildfile_pathname = NULL; // pathname of IFS build file
725
static char *current_line = NULL; // copy of current line in IFS build file
739
static char *current_line = NULL; // copy of current line in IFS build file
726
static int lineno = 0; // current line number in IFS build file
740
static int lineno = 0; // current line number in IFS build file
727
static char *QNX_TARGET = NULL; // value of the $QNX_TARGET environment variable
741
static char *QNX_TARGET = NULL; // value of the $QNX_TARGET environment variable
728
static char *MKIFS_PATH = NULL; // value of the $MKIFS_PATH environment variable (may contain references to $QNX_TARGET). Initialized by this program if empty.
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.
-
 
743
 
-
 
744
// bootable IFS support
-
 
745
static char *bootfile_pathname = NULL;           // HACK: pathname to bootcode binary blob file to put at the start of a bootable IFS
-
 
746
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
-
 
748
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
-
 
750
static size_t kernelfile_offset = 0;             // HACK: kernel file offset in bootable IFS
729
 
751
 
730
 
752
 
731
// prototypes of local functions
753
// prototypes of local functions
732
static void sha512_private_transform (SHA512_CTX *context, const uint64_t *data); // used internally in SHA512_Update() and SHA512_Final()
754
static void sha512_private_transform (SHA512_CTX *context, const uint64_t *data); // used internally in SHA512_Update() and SHA512_Final()
733
static void SHA512_Init (SHA512_CTX *context);
755
static void SHA512_Init (SHA512_CTX *context);
Line 1030... Line 1052...
1030
 
1052
 
1031
   char *endptr = NULL;
1053
   char *endptr = NULL;
1032
   long long ret = strtoll (str, &endptr, 0); // use strtoll() to handle hexadecimal (0x...), octal (0...) and decimal (...) bases
1054
   long long ret = strtoll (str, &endptr, 0); // use strtoll() to handle hexadecimal (0x...), octal (0...) and decimal (...) bases
1033
   if (endptr != NULL)
1055
   if (endptr != NULL)
1034
   {
1056
   {
1035
      if ((*endptr == 'k') || (*endptr == 'K')) ret *= (size_t) 1024;
1057
      if      ((*endptr == 'k') || (*endptr == 'K')) ret *= (size_t) 1024;
1036
      else if ((*endptr == 'm') || (*endptr == 'M')) ret *= (size_t) 1024 * 1024;
1058
      else if ((*endptr == 'm') || (*endptr == 'M')) ret *= (size_t) 1024 * 1024;
1037
      else if ((*endptr == 'g') || (*endptr == 'G')) ret *= (size_t) 1024 * 1024 * 1024;
1059
      else if ((*endptr == 'g') || (*endptr == 'G')) ret *= (size_t) 1024 * 1024 * 1024;
1038
      else if ((*endptr == 't') || (*endptr == 'T')) ret *= (size_t) 1024 * 1024 * 1024 * 1024; // future-proof enough, I suppose?
1060
      else if ((*endptr == 't') || (*endptr == 'T')) ret *= (size_t) 1024 * 1024 * 1024 * 1024; // future-proof enough, I suppose?
1039
   }
1061
   }
1040
   return (ret);
1062
   return (ret);
Line 1108... Line 1130...
1108
 
1130
 
1109
static char *read_filecontents (const char *pathname, const char *search_path, buffer_t *outbuf)
1131
static char *read_filecontents (const char *pathname, const char *search_path, buffer_t *outbuf)
1110
{
1132
{
1111
   // locates pathname among MKIFS_PATH, and places its contents in a buffer (caller frees). Returns resolved pathname (static buffer) or NULL.
1133
   // locates pathname among MKIFS_PATH, and places its contents in a buffer (caller frees). Returns resolved pathname (static buffer) or NULL.
1112
 
1134
 
1113
   static thread_local char final_pathname[MAXPATHLEN];
1135
   static thread_local char resolved_pathname[MAXPATHLEN];
1114
 
1136
 
1115
   const char *nextsep;
1137
   const char *nextsep;
1116
   const char *token;
1138
   const char *token;
1117
   FILE *fp;
1139
   FILE *fp;
1118
 
1140
 
1119
   // is it an absolute pathname (POSIX and Windows variants) ?
1141
   // is it an absolute pathname (POSIX and Windows variants) ?
1120
   if (IS_DIRSEP (pathname[0]) || (isalpha (pathname[0]) && (pathname[1] == ':') && IS_DIRSEP (pathname[2])))
1142
   if (IS_DIRSEP (pathname[0]) || (isalpha (pathname[0]) && (pathname[1] == ':') && IS_DIRSEP (pathname[2])))
1121
      strcpy (final_pathname, pathname); // in this case, it MUST exist at its designated location (either absolute or relative to the current working directory)
1143
      strcpy (resolved_pathname, pathname); // in this case, it MUST exist at its designated location (either absolute or relative to the current working directory)
1122
   else // the path is relative, search it among the search paths we have
1144
   else // the path is relative, search it among the search paths we have
1123
   {
1145
   {
1124
      // construct a potential final path using each element of the search path
1146
      // construct a potential final path using each element of the search path
1125
      token = (*search_path != 0 ? search_path : NULL);
1147
      token = (*search_path != 0 ? search_path : NULL);
1126
      nextsep = (token != NULL ? &token[strcspn (token, PATH_SEP_STR)] : NULL);
1148
      nextsep = (token != NULL ? &token[strcspn (token, PATH_SEP_STR)] : NULL);
1127
      while (token != NULL)
1149
      while (token != NULL)
1128
      {
1150
      {
1129
         sprintf (final_pathname, "%.*s/%s", (int) (nextsep - token), token, pathname);
1151
         sprintf (resolved_pathname, "%.*s/%s", (int) (nextsep - token), token, pathname);
1130
         if (access (final_pathname, 0) == 0)
1152
         if (access (resolved_pathname, 0) == 0)
1131
            break; // if a file can indeed be found at this location, stop searching
1153
            break; // if a file can indeed be found at this location, stop searching
1132
 
1154
 
1133
         token = (*nextsep != 0 ? nextsep + 1 : NULL);
1155
         token = (*nextsep != 0 ? nextsep + 1 : NULL);
1134
         nextsep = (token != NULL ? &token[strcspn (token, PATH_SEP_STR)] : NULL);
1156
         nextsep = (token != NULL ? &token[strcspn (token, PATH_SEP_STR)] : NULL);
1135
      }
1157
      }
Line 1141... Line 1163...
1141
         return (NULL); // file not found, return with ENOENT
1163
         return (NULL); // file not found, return with ENOENT
1142
      }
1164
      }
1143
   }
1165
   }
1144
 
1166
 
1145
   // now open and read the file
1167
   // now open and read the file
1146
   fp = fopen (final_pathname, "rb");
1168
   fp = fopen (resolved_pathname, "rb");
1147
   if (fp == NULL)
1169
   if (fp == NULL)
1148
      return (NULL); // unexistent file (errno is set to ENOENT)
1170
      return (NULL); // unexistent file (errno is set to ENOENT)
1149
 
1171
 
-
 
1172
   // if we don't want its contents, close it and return the resolved pathname
-
 
1173
   if (outbuf == NULL)
-
 
1174
   {
-
 
1175
      fclose (fp);
-
 
1176
      return (resolved_pathname);
-
 
1177
   }
-
 
1178
 
-
 
1179
   // the user supplied a data buffer: read the file contents
1150
   fseek (fp, 0, SEEK_END);
1180
   fseek (fp, 0, SEEK_END);
1151
   outbuf->len = ftell (fp); // measure file length
1181
   outbuf->len = ftell (fp); // measure file length
1152
   fseek (fp, 0, SEEK_SET);
1182
   fseek (fp, 0, SEEK_SET);
1153
   outbuf->bytes = malloc (outbuf->len);
1183
   outbuf->bytes = malloc (outbuf->len);
1154
   if (outbuf->bytes == NULL)
1184
   if (outbuf->bytes == NULL)
Line 1163... Line 1193...
1163
      outbuf->len = 0;
1193
      outbuf->len = 0;
1164
      return (NULL); // short read (errno is set)
1194
      return (NULL); // short read (errno is set)
1165
   }
1195
   }
1166
   fclose (fp); // close the file
1196
   fclose (fp); // close the file
1167
 
1197
 
1168
   return (final_pathname); // file was read successfully and its content put in databuf with size datalen
1198
   return (resolved_pathname); // file was read successfully and its content put in databuf with size datalen
1169
}
1199
}
1170
 
1200
 
1171
 
1201
 
1172
static int fwrite_filecontents (const char *pathname, FILE *fp)
1202
static int fwrite_filecontents (const char *pathname, FILE *fp)
1173
{
1203
{
Line 1302... Line 1332...
1302
      if (fp != NULL)
1332
      if (fp != NULL)
1303
         fwrite_or_die (fsentry->u.device.path, 1, (size_t) datalen, fp); // write null-terminated path (no leading slash)
1333
         fwrite_or_die (fsentry->u.device.path, 1, (size_t) datalen, fp); // write null-terminated path (no leading slash)
1304
      count += datalen;
1334
      count += datalen;
1305
   }
1335
   }
1306
 
1336
 
-
 
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);
1307
   if (count < fsentry->header.size)
1338
   if (count < fsentry->header.size)
1308
   {
1339
   {
1309
      if (fp != NULL)
1340
      if (fp != NULL)
1310
         fwrite_or_die (zeropad_buffer, 1, fsentry->header.size - count, fp); // pad as necessary
1341
         fwrite_or_die (zeropad_buffer, 1, fsentry->header.size - count, fp); // pad as necessary
1311
      count += fsentry->header.size - count;
1342
      count += fsentry->header.size - count;
1312
   }
-
 
1313
   else if (count > fsentry->header.size)
-
 
1314
   {
-
 
1315
      fprintf (stderr, "ERROR: attempt to write invalid dirent (claimed size %zd, written size %zd). Aborting.\n", (size_t) fsentry->header.size, count);
-
 
1316
      exit (1);
-
 
1317
   }
1343
   }
1318
 
1344
 
1319
   return (count);
1345
   return (count);
1320
}
1346
}
1321
 
1347
 
Line 1336... Line 1362...
1336
      new_shdr = (elf_section_header_t *) &new_shtab.bytes[(sectionhdr_offset)]; /* now fix this section header */ \
1362
      new_shdr = (elf_section_header_t *) &new_shtab.bytes[(sectionhdr_offset)]; /* now fix this section header */ \
1337
      ELF_SET_NUMERIC (elf, new_shdr, file_offset, entry_parms->data.len); /* fix section offset in the new section headers table */ \
1363
      ELF_SET_NUMERIC (elf, new_shdr, file_offset, entry_parms->data.len); /* fix section offset in the new section headers table */ \
1338
      entry_parms->data.len += (section).len; /* update new ELF file length */ \
1364
      entry_parms->data.len += (section).len; /* update new ELF file length */ \
1339
   } while (0)
1365
   } while (0)
1340
 
1366
 
1341
   static thread_local char candidate_pathname[1024];
1367
   static thread_local char candidate_pathname[MAXPATHLEN];
1342
   static int inode_count = 0; // will be preincremented each time this function is called
1368
   static int inode_count = 0; // will be preincremented each time this function is called
1343
 
1369
 
1344
   const char *original_stored_pathname = NULL;
1370
   const char *original_stored_pathname = NULL;
1345
   const elf_dynamic_section_entry_t *dynamic_entry; // dynamic section entry
1371
   const elf_dynamic_section_entry_t *dynamic_entry; // dynamic section entry
1346
   const elf_section_header_t *shdr_dynstr; // dynamic strings
1372
   const elf_section_header_t *shdr_dynstr; // dynamic strings
Line 1361... Line 1387...
1361
   buffer_t elfsection_qnxinfo   = { NULL, 0 };
1387
   buffer_t elfsection_qnxinfo   = { NULL, 0 };
1362
   buffer_t elfsection_qnxusage  = { NULL, 0 };
1388
   buffer_t elfsection_qnxusage  = { NULL, 0 };
1363
   buffer_t elfsection_debuglink = { NULL, 0 };
1389
   buffer_t elfsection_debuglink = { NULL, 0 };
1364
   buffer_t elfsection_buildid   = { NULL, 0 };
1390
   buffer_t elfsection_buildid   = { NULL, 0 };
1365
   buffer_t elfsection_shstrtab  = { NULL, 0 };
1391
   buffer_t elfsection_shstrtab  = { NULL, 0 };
-
 
1392
   char *global_envstring = NULL;
-
 
1393
   size_t global_envstring_len = 0;
-
 
1394
   char *startup_name = NULL;
-
 
1395
   char *procnto_name = NULL;
1366
   char *resolved_pathname;
1396
   char *resolved_pathname;
1367
   void *reallocated_ptr;
1397
   void *reallocated_ptr;
1368
   void *old_data;
1398
   void *old_data;
1369
   struct stat stat_buf;
1399
   struct stat stat_buf;
1370
   size_t new_shdrtable_offset;
1400
   size_t new_shdrtable_offset;
Line 1374... Line 1404...
1374
   size_t name_len;
1404
   size_t name_len;
1375
   fsentry_t *fsentry;
1405
   fsentry_t *fsentry;
1376
 
1406
 
1377
   if (S_ISDIR (entry_parms->st_mode)) // are we storing a directory ?
1407
   if (S_ISDIR (entry_parms->st_mode)) // are we storing a directory ?
1378
   {
1408
   {
1379
      fprintf (stderr, "directory: ino 0x%x uid %d gid %d mode 0%o path \"%s\"\n", inode_count + 1, entry_parms->uid, entry_parms->gid, entry_parms->st_mode, stored_pathname);
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);
1380
   }
1410
   }
1381
   else if (S_ISREG (entry_parms->st_mode)) // else are we storing a regular file ?
1411
   else if (S_ISREG (entry_parms->st_mode)) // else are we storing a regular file ?
1382
   {
1412
   {
1383
      if (strcmp (stored_pathname, "/proc/boot/boot") == 0) // is it the kernel ?
1413
      if (strcmp (stored_pathname, "/proc/boot/boot") == 0) // is it the kernel ?
1384
      {
1414
      {
1385
         // HACK: for now just consider the kernel as a binary blob
1415
         // HACK: for now just consider the kernel as a binary blob
1386
         // FIXME: reimplement properly
1416
         // FIXME: reimplement properly
-
 
1417
#ifdef PROCNTO_WIP // FIXME: segment corruption somewhere!
-
 
1418
         char *linebit_start;
-
 
1419
         char *content_line;
-
 
1420
         char *write_ptr;
-
 
1421
         char *token;
-
 
1422
         char *value;
-
 
1423
         bool is_quoted_context;
-
 
1424
         bool was_string_split;
-
 
1425
 
-
 
1426
         // parse each line of contents
-
 
1427
         WELLMANNERED_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"))
-
 
1429
         {
-
 
1430
            while (isspace (*content_line))
-
 
1431
               content_line++; // skip leading spaces
-
 
1432
            if ((*content_line == '#') || (*content_line == 0))
-
 
1433
               continue; // skip comments and empty lines
-
 
1434
 
-
 
1435
            // format of a line: [attributes] [env assignation] [...] [executable] [arg] [...] [comment]
-
 
1436
            // example: "[uid=0 gid=0 perms=0700] CONFIG_PATH=/proc/boot:/etc procnto-smp-instr -v -mr -d 0777 -u 0777"
-
 
1437
            //LOG_DEBUG ("parsing line: %s", content_line);
-
 
1438
 
-
 
1439
            // does this line start with an attribute block ?
-
 
1440
            if (*content_line == '[')
-
 
1441
            {
-
 
1442
               content_line++; // skip the leading square bracket
-
 
1443
               linebit_start = content_line; // remember where it starts
-
 
1444
               is_quoted_context = false; // reach the next unescaped closing square bracket that is not between quotes
-
 
1445
               while ((*content_line != 0) && !((*content_line == ']') && (content_line[-1] != '\\') && !is_quoted_context))
-
 
1446
               {
-
 
1447
                  if (*content_line == '"')
-
 
1448
                     is_quoted_context ^= true; // remember when we're between quotes
-
 
1449
                  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
-
 
1451
                  content_line++; // reach the next unescaped closing square bracket
-
 
1452
               }
-
 
1453
               if (*content_line != ']')
-
 
1454
               {
-
 
1455
                  LOG ("warning", 0, "syntax error in \"%s\" line %d: unterminated attributes block (skipping)", buildfile_pathname, lineno);
-
 
1456
                  continue; // invalid attribute block, skip line
-
 
1457
               }
-
 
1458
               *content_line = 0; // end the attribute block so that it is a parsable C string
-
 
1459
 
-
 
1460
               // now parse the attribute tokens (NOTE: THE LIST OF ALLOWED ATTRIBUTES HERE IS NOT DOCUMENTED)
-
 
1461
               token = strtok (linebit_start, RECORD_SEP_STR);
-
 
1462
               while (token != NULL)
-
 
1463
               {
-
 
1464
                  #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); }
-
 
1466
                  else if (strncmp (token, "gid=",     4) == 0) { REACH_TOKEN_VALUE (); entry_parms->gid     = (int) read_integer (value); }
-
 
1467
                  else if (strncmp (token, "perms=",   6) == 0) { REACH_TOKEN_VALUE (); entry_parms->perms   = (int) read_integer (value); }
-
 
1468
                  else if (strncmp (token, "prefix=",  7) == 0) { REACH_TOKEN_VALUE (); strcpy (entry_parms->prefix, (*value == '/' ? value + 1 : value)); } // skip possible leading slash in prefix
-
 
1469
                  else if (strcmp (token, "+followlink") == 0) entry_parms->should_follow_symlinks = true;
-
 
1470
                  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;
-
 
1472
                  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);
-
 
1474
                  #undef REACH_TOKEN_VALUE
-
 
1475
                  token = strtok (NULL, RECORD_SEP_STR); // proceed to next attribute token
-
 
1476
               }
-
 
1477
 
-
 
1478
               content_line++; // reach the next character
-
 
1479
               while ((*content_line != 0) && isspace (*content_line))
-
 
1480
                  content_line++; // skip leading spaces
-
 
1481
            } // end of "this line starts with an attributes block"
-
 
1482
 
-
 
1483
            // there's data in this line. We expect an executable OR a variable name. Read it and unescape escaped characters
-
 
1484
            while (*content_line != 0)
-
 
1485
            {
-
 
1486
               linebit_start = content_line; // remember the name starts here
-
 
1487
               write_ptr = linebit_start;
-
 
1488
               is_quoted_context = (*content_line == '"');
-
 
1489
               if (is_quoted_context)
-
 
1490
                  content_line++; // skip a possible initial quote in the name
-
 
1491
               while ((*content_line != 0) && ((!is_quoted_context && (*content_line != '=') && !isspace (*content_line)) || (is_quoted_context && (*content_line == '"'))))
-
 
1492
               {
-
 
1493
                  if (*content_line == '\\')
-
 
1494
                  {
-
 
1495
                     content_line++;
-
 
1496
                     *write_ptr++ = *content_line; // unescape characters that are escaped with '\'
-
 
1497
                  }
-
 
1498
                  else
-
 
1499
                     *write_ptr++ = *content_line;
-
 
1500
                  content_line++;
-
 
1501
               }
-
 
1502
 
-
 
1503
               // we reached a closing quote, a space OR an equal sign
-
 
1504
               if (*content_line == '=')
-
 
1505
               {
-
 
1506
                  // it's an environment variable assignation
-
 
1507
                  *write_ptr++ = *content_line++; // skip the equal sign
-
 
1508
                  is_quoted_context = (*content_line == '"');
-
 
1509
                  if (is_quoted_context)
-
 
1510
                     content_line++; // skip a possible initial quote in the value
-
 
1511
                  while ((*content_line != 0) && ((!is_quoted_context && (*content_line != '=') && !isspace (*content_line)) || (is_quoted_context && (*content_line == '"'))))
-
 
1512
                  {
-
 
1513
                     if (*content_line == '\\')
-
 
1514
                     {
-
 
1515
                        content_line++;
-
 
1516
                        *write_ptr++ = *content_line; // unescape characters that are escaped with '\'
-
 
1517
                     }
-
 
1518
                     else
-
 
1519
                        *write_ptr++ = *content_line;
-
 
1520
                     content_line++;
-
 
1521
                  }
-
 
1522
                  if (*write_ptr != 0)
-
 
1523
                  {
-
 
1524
                     *write_ptr = 0; // terminate the string if necessary
-
 
1525
                     was_string_split = true;
-
 
1526
                  }
-
 
1527
                  else
-
 
1528
                     was_string_split = false;
-
 
1529
                  if (is_quoted_context && (*content_line == '"'))
-
 
1530
                     content_line++; // skip a possible final quote
-
 
1531
                  while ((*content_line != 0) && isspace (*content_line))
-
 
1532
                     content_line++; // skip spaces
-
 
1533
 
-
 
1534
                  // now linebit_start is of the form "NAME=VALUE"
-
 
1535
                  LOG_DEBUG ("assignation: [%s]", linebit_start);
-
 
1536
 
-
 
1537
                  // TODO: grow global_envstring
-
 
1538
 
-
 
1539
                  //reallocated_ptr = realloc (global_envstring, global_envstring_len + strlen ())
-
 
1540
 
-
 
1541
                  if (was_string_split)
-
 
1542
                     *write_ptr = ' '; // restore string continuity for parsing to continue
-
 
1543
                  while ((*content_line != 0) && isspace (*content_line))
-
 
1544
                     content_line++; // skip spaces
-
 
1545
               }
-
 
1546
               else // it's either a closing quote or a space
-
 
1547
               {
-
 
1548
                  *write_ptr = 0; // terminate the string
-
 
1549
                  if (is_quoted_context && (*content_line == '"'))
-
 
1550
                     content_line++; // skip a possible final quote
-
 
1551
 
-
 
1552
                  LOG_DEBUG ("exe name: [%s]", linebit_start);
-
 
1553
 
-
 
1554
                  while ((*content_line != 0) && isspace (*content_line))
-
 
1555
                     content_line++; // skip leading spaces
-
 
1556
 
-
 
1557
                  // it's an executable name. As per QNX docs, the first executable must be startup-*, the last executable must be procnto.
-
 
1558
                  if (startup_name == NULL)
-
 
1559
                     startup_name = strdup (linebit_start);
-
 
1560
                  else
-
 
1561
                  {
-
 
1562
                     if (procnto_name != NULL)
-
 
1563
                        free (procnto_name);
-
 
1564
                     procnto_name = strdup (linebit_start);
-
 
1565
                  }
-
 
1566
 
-
 
1567
                  if ((*content_line == '#') || (*content_line == 0))
-
 
1568
                     break; // if we reach the end of the line, stop parsing
-
 
1569
 
-
 
1570
                  // what comes after now must be optional arguments
-
 
1571
                  while ((*content_line != 0) && isspace (*content_line))
-
 
1572
                     content_line++; // skip leading spaces
-
 
1573
 
-
 
1574
                  // FIXME: parse executable command-line arguments
-
 
1575
 
-
 
1576
                  break; // stop parsing once all the arguments have been read
-
 
1577
               }
-
 
1578
            }
-
 
1579
         } // end of parsing
-
 
1580
         free (entry_parms->data.bytes); // free the inline specification once it's parsed
-
 
1581
         entry_parms->data.bytes = NULL;
-
 
1582
         entry_parms->data.len = 0;
-
 
1583
 
-
 
1584
         WELLMANNERED_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");
-
 
1586
 
-
 
1587
         // now we know which startup and procnto executables to use
-
 
1588
         LOG_DEBUG ("Startup: %s", startup_name);
-
 
1589
         LOG_DEBUG ("Kernel: %s", procnto_name);
-
 
1590
 
1387
         sprintf (candidate_pathname, "%s/procnto-smp-instr", entry_parms->prefix); // fix the entry name
1591
         sprintf (candidate_pathname, "%s/%s", entry_parms->prefix, procnto_name); // fix the entry name
1388
         stored_pathname = candidate_pathname;
1592
         stored_pathname = candidate_pathname;
1389
         entry_parms->extra_ino_flags |= IFS_INO_PROCESSED_ELF | IFS_INO_BOOTSTRAP_EXE; // procnto needs to have these flags stamped on the inode
1593
         entry_parms->extra_ino_flags |= /*IFS_INO_PROCESSED_ELF | */IFS_INO_BOOTSTRAP_EXE; // procnto needs to have these flags stamped on the inode
1390
         entry_parms->st_mode = S_IFREG | 0700; // procnto requires 0700 permissions
1594
         entry_parms->st_mode = S_IFREG | entry_parms->perms; // apply specified procnto permissions
1391
         image_kernel_ino = entry_parms->extra_ino_flags | (inode_count + 1);
1595
         image_kernel_ino = entry_parms->extra_ino_flags | (inode_count + 1);
-
 
1596
 
-
 
1597
         static thread_local char linker_pathname[MAXPATHLEN] = "";
-
 
1598
         static thread_local char linker_sysroot_arg[MAXPATHLEN] = "";
-
 
1599
         static thread_local char linker_script_pathname_arg[MAXPATHLEN] = "";
-
 
1600
         static thread_local char procnto_buildhost_pathname[MAXPATHLEN] = "";
-
 
1601
         static thread_local char procnto_sym_filename[MAXPATHLEN] = "";
-
 
1602
 
-
 
1603
         // construct the arguments that are based on environment variables (infer QNX_HOST from QNX_TARGET)
-
 
1604
#if defined(_WIN32)
-
 
1605
         sprintf (linker_pathname, "%s/../../host/win64/x86_64/usr/bin/%s-ld.exe", QNX_TARGET, (strcmp (image_processor, "x86_64") == 0 ? "x86_64-pc-nto-qnx8.0.0" : "aarch64-unknown-nto-qnx8.0.0")); // Win32: note the .exe extension
-
 
1606
#elif defined(__linux__)
-
 
1607
         sprintf (linker_pathname, "%s/../../host/linux/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"));
-
 
1608
#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"));
-
 
1610
#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.
-
 
1612
#endif
-
 
1613
         WELLMANNERED_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);
-
 
1615
         sprintf (linker_script_pathname_arg, "-T%s/%s/lib/nto.link", QNX_TARGET, image_processor);
-
 
1616
 
-
 
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
-
 
1618
         WELLMANNERED_ASSERT (resolved_pathname, "QNX kernel \"%s\" not found in search path", procnto_name);
-
 
1619
         strcpy (procnto_buildhost_pathname, resolved_pathname);
-
 
1620
 
-
 
1621
         sprintf (procnto_sym_filename, "%s.sym", procnto_name);
-
 
1622
 
-
 
1623
         const char *linker_argv[] = // construct the linker invokation argv
-
 
1624
         {
-
 
1625
            strrchr (linker_pathname, '/') + 1, // "${TARGET_TRIPLE}-ld"
-
 
1626
            linker_sysroot_arg, // "--sysroot=${QNX_TARGET}/${TARGET_CPU}/"
-
 
1627
            linker_script_pathname_arg, // "-T${QNX_TARGET}/${TARGET_CPU}/lib/nto.link"
-
 
1628
            "--section-start",
-
 
1629
            ".text=0xffff800000001000",
-
 
1630
            "--no-relax",
-
 
1631
            procnto_buildhost_pathname, // "${QNX_TARGET}/${TARGET_CPU}/boot/sys/procnto-smp-instr"
-
 
1632
            "-o",
-
 
1633
            procnto_sym_filename, // "procnto-smp-instr.sym"
-
 
1634
            NULL
-
 
1635
         };
-
 
1636
         if (verbose_level > 2)
-
 
1637
         {
-
 
1638
            fprintf (stderr, "ifstool: calling:");
-
 
1639
            for (table_index = 0; table_index < sizeof (linker_argv) / sizeof (linker_argv[0]) - 1; table_index++)
-
 
1640
               fprintf (stderr, " '%s'", linker_argv[table_index]);
-
 
1641
            fputc ('\n', stderr);
-
 
1642
         }
-
 
1643
         _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
-
 
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));
-
 
1647
         if (!entry_parms->should_keep_ld_output)
-
 
1648
            unlink (procnto_sym_filename); // remove the linker output file if we want to
-
 
1649
#else // !PROCNTO_WIP
-
 
1650
         /* 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 */
-
 
1652
         /* HACK */
-
 
1653
         /* HACK */ sprintf (candidate_pathname, "%s/procnto-smp-instr", entry_parms->prefix); // HACK: fix the entry name
-
 
1654
         /* 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
-
 
1656
         /* 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);
-
 
1658
         /* HACK */ free (entry_parms->data.bytes); // discard inline contents
-
 
1659
         /* HACK */ entry_parms->data.bytes = NULL;
-
 
1660
         /* HACK */ entry_parms->data.len = 0;
-
 
1661
         /* HACK */ if (read_filecontents (kernelfile_pathname, ".", &entry_parms->data) == NULL) // read kernel file as a precompiled binary blob
-
 
1662
         /* HACK */ {
-
 
1663
         /* HACK */    fprintf (stderr, "fatal error: unable to read precompiled kernel file \"%s\" specified in --kernelfile argument\n", kernelfile_pathname);
-
 
1664
         /* HACK */    exit (1);
-
 
1665
         /* HACK */ }
-
 
1666
         /* HACK */
-
 
1667
         /* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK */
-
 
1668
         /* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK */
-
 
1669
#endif // PROCNTO_WIP
1392
      }
1670
      }
1393
      else if (entry_parms->is_compiled_bootscript) // else is it a startup script ?
1671
      else if (entry_parms->is_compiled_bootscript) // else is it a startup script ?
1394
         image_bootscript_ino = inode_count + 1; // save boot script inode number for image header
1672
         image_bootscript_ino = inode_count + 1; // save boot script inode number for image header
1395
 
1673
 
1396
      // do we already know the data for this data blob ?
1674
      // do we already know the data for this data blob ?
1397
      if (entry_parms->data.bytes != NULL)
1675
      if (entry_parms->data.bytes != NULL)
1398
      {
1676
      {
1399
         entry_parms->mtime = entry_parms->mtime_for_inline_files;
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
1400
         fprintf (stderr, "file: ino 0x%x uid %d gid %d mode 0%o path \"%s\" blob (len %zd)\n", entry_parms->extra_ino_flags | (inode_count + 1), entry_parms->uid, entry_parms->gid, entry_parms->st_mode, stored_pathname, entry_parms->data.len);
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);
1401
      }
1679
      }
1402
      else if (buildhost_pathname != NULL) // else was a source file pathname supplied ?
1680
      else if (buildhost_pathname != NULL) // else was a source file pathname supplied ?
1403
      {
1681
      {
1404
         resolved_pathname = read_filecontents (buildhost_pathname, (entry_parms->search[0] != 0 ? entry_parms->search : MKIFS_PATH), &entry_parms->data); // locate the file
1682
         resolved_pathname = read_filecontents (buildhost_pathname, (entry_parms->search[0] != 0 ? entry_parms->search : MKIFS_PATH), &entry_parms->data); // locate the file
1405
         if (resolved_pathname == NULL)
1683
         if (resolved_pathname == NULL)
1406
         {
-
 
1407
            fprintf (stderr, "fatal error: filesystem entry \"%s\" specified in \"%s\" line %d not found on build host: %s\n", buildhost_pathname, buildfile_pathname, lineno, strerror (errno));
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));
1408
            exit (1);
-
 
1409
         }
-
 
1410
         stat (resolved_pathname, &stat_buf); // can't fail
1685
         stat (resolved_pathname, &stat_buf); // can't fail
1411
         if (entry_parms->mtime == UINT32_MAX)
1686
         if (entry_parms->mtime == UINT32_MAX)
1412
            entry_parms->mtime = (uint32_t) stat_buf.st_mtime;
1687
            entry_parms->mtime = (uint32_t) stat_buf.st_mtime;
1413
         fprintf (stderr, "file: ino 0x%x uid %d gid %d mode 0%o path \"%s\" buildhost_file \"%s\" (len %zd)\n", inode_count + 1, entry_parms->uid, entry_parms->gid, entry_parms->st_mode, stored_pathname, buildhost_pathname, entry_parms->data.len);
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);
1414
      }
1689
      }
1415
 
1690
 
1416
      // is the file we're storing an ELF file ?
1691
      // is the file we're storing an ELF file ?
1417
      if ((entry_parms->data.len > 52) // file is big enough to contain an ELF header
1692
      if ((entry_parms->data.len > 52) // file is big enough to contain an ELF header
1418
          && ((elf = (elf_header_t *) entry_parms->data.bytes) != NULL) // cast (necessary true)
1693
          && ((elf = (elf_header_t *) entry_parms->data.bytes) != NULL) // cast (necessary true)
Line 1458... Line 1733...
1458
 
1733
 
1459
         // now strip this ELF file if necessary
1734
         // now strip this ELF file if necessary
1460
         if (!(entry_parms->extra_ino_flags & IFS_INO_PROCESSED_ELF))
1735
         if (!(entry_parms->extra_ino_flags & IFS_INO_PROCESSED_ELF))
1461
         {
1736
         {
1462
            // NOTE: for each ELF file, mkifs
1737
            // NOTE: for each ELF file, mkifs
1463
            // -> alters the program header table and offsets each p_addr (physical address) member by 0x1400000 plus the current file offset (this cannot be done right now, will need to be done once they are known)
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)
1464
            // -> 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
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
1465
            // FIXME: what if a thrown away section is located between two program segments ? are they collapsed, moving the segments beyond it one slot down ?
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 ?
1466
 
1741
 
1467
            // reconstructed ELF:
1742
            // reconstructed ELF:
1468
            // ==== START OF FILE ====
1743
            // ==== START OF FILE ====
Line 1473... Line 1748...
1473
            //  "............GNU....ZY.....c.o..l"
1748
            //  "............GNU....ZY.....c.o..l"
1474
            // PROGRAM
1749
            // PROGRAM
1475
            // sections table
1750
            // sections table
1476
            // + section 1: ALL ZEROES
1751
            // + section 1: ALL ZEROES
1477
            // + 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"
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"
1478
            // + section 3: fileoffs 0x22a5 size 0x1c --> ".gnu_debuglink" --> indicates the debug file (and a possible checksum?): "pci_debug2.so.3.0.sym" "\0\0\0" "VX2p"
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"
1479
            // + 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.."
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.."
1480
            // + section 5: fileoffs 0x190 size 0x32 --> ".note.gnu.build-id" --> GNU build ID
1755
            // + section 5: fileoffs 0x190 size 0x32 --> ".note.gnu.build-id" --> GNU build ID
1481
            // + section 6: fileoffs 0x256e size 0x40 --> ".shstrtab" --> sections names strings table
1756
            // + section 6: fileoffs 0x256e size 0x40 --> ".shstrtab" --> sections names strings table
1482
            // section data 2 (named "QNX_info")
1757
            // section data 2 (named "QNX_info")
1483
            //  (QNX binary description)
1758
            //  (QNX binary description)
Line 1673... Line 1948...
1673
            if (ELF_GET_NUMERIC (elf, elf, instruction_set) == ELF_MACHINE_X86_64)
1948
            if (ELF_GET_NUMERIC (elf, elf, instruction_set) == ELF_MACHINE_X86_64)
1674
               entry_parms->data.len = ROUND_TO_UPPER_MULTIPLE (end_padding_offset, 4 * 1024); // 4 kb pages on Intel processors
1949
               entry_parms->data.len = ROUND_TO_UPPER_MULTIPLE (end_padding_offset, 4 * 1024); // 4 kb pages on Intel processors
1675
            else if (ELF_GET_NUMERIC (elf, elf, instruction_set) == ELF_MACHINE_AARCH64)
1950
            else if (ELF_GET_NUMERIC (elf, elf, instruction_set) == ELF_MACHINE_AARCH64)
1676
               entry_parms->data.len = ROUND_TO_UPPER_MULTIPLE (end_padding_offset, 16 * 1024); // 16 kb pages on ARM64
1951
               entry_parms->data.len = ROUND_TO_UPPER_MULTIPLE (end_padding_offset, 16 * 1024); // 16 kb pages on ARM64
1677
            else
1952
            else
1678
            {
-
 
1679
               fprintf (stderr, "fatal error: this ELF file \"%s\" does not belong to an architecture supported by ifstool (neither x86_64, nor aarch64)\n", stored_pathname);
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);
1680
               exit (1);
-
 
1681
            }
1954
 
1682
            memset (&entry_parms->data.bytes[end_padding_offset], 0, entry_parms->data.len - end_padding_offset); // zerofill
1955
            memset (&entry_parms->data.bytes[end_padding_offset], 0, entry_parms->data.len - end_padding_offset); // zerofill
1683
 
-
 
1684
            entry_parms->extra_ino_flags |= IFS_INO_PROCESSED_ELF; // mark this inode as a preprocessed ELF file
1956
            entry_parms->extra_ino_flags |= IFS_INO_PROCESSED_ELF; // mark this inode as a preprocessed ELF file
1685
         } // end if the file is not yet a processed ELF
1957
         } // end if the file is not yet a processed ELF
1686
      } // end if the file we're storing is an ELF file
1958
      } // end if the file we're storing is an ELF file
1687
   }
1959
   }
1688
   else if (S_ISLNK (entry_parms->st_mode)) // else are we storing a symbolic link ?
1960
   else if (S_ISLNK (entry_parms->st_mode)) // else are we storing a symbolic link ?
1689
      fprintf (stderr, "symlink: ino 0x%x uid %d gid %d mode 0%o path \"%s\" -> \"%s\"\n", inode_count + 1, entry_parms->uid, entry_parms->gid, entry_parms->st_mode, stored_pathname, entry_parms->data.bytes);
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);
1690
   else // we must be storing a FIFO
1962
   else // we must be storing a FIFO
1691
   {
1963
   {
1692
      if (strchr (entry_parms->data.bytes, ':') == NULL)
1964
      if (strchr (entry_parms->data.bytes, ':') == NULL)
1693
      {
-
 
1694
         fprintf (stderr, "fatal error: device entry \"%s\" malformed (no 'dev:rdev' pair)\n", stored_pathname);
1965
         DIE_WITH_EXITCODE (1, "device entry \"%s\" malformed (no 'dev:rdev' pair)", stored_pathname);
1695
         exit (1);
-
 
1696
      }
-
 
1697
      fprintf (stderr, "fifo: ino 0x%x uid %d gid %d mode 0%o path \"%s\" dev rdev %s)\n", inode_count + 1, entry_parms->uid, entry_parms->gid, entry_parms->st_mode, stored_pathname, entry_parms->data.bytes);
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);
1698
   }
1967
   }
1699
 
1968
 
1700
   // grow filesystem entries array to hold one more slot
1969
   // grow filesystem entries array to hold one more slot
1701
   reallocated_ptr = realloc (*fsentries, (*fsentry_count + 1) * sizeof (fsentry_t)); // attempt to reallocate
1970
   reallocated_ptr = realloc (*fsentries, (*fsentry_count + 1) * sizeof (fsentry_t)); // attempt to reallocate
1702
   if (reallocated_ptr == NULL)
-
 
1703
   {
-
 
1704
      fprintf (stderr, "fatal error: out of memory\n");
1971
   WELLMANNERED_ASSERT (reallocated_ptr, "out of memory");
1705
      exit (1);
-
 
1706
   }
-
 
1707
   *fsentries = reallocated_ptr; // save reallocated pointer
1972
   *fsentries = reallocated_ptr; // save reallocated pointer
1708
   fsentry = &(*fsentries)[*fsentry_count]; // quick access to fs entry slot
1973
   fsentry = &(*fsentries)[*fsentry_count]; // quick access to fs entry slot
1709
   //fsentry->header.size = 0; // will be filled once we know it
1974
   //fsentry->header.size = 0; // will be filled once we know it
1710
   fsentry->header.extattr_offset = 0;
1975
   fsentry->header.extattr_offset = 0;
1711
   fsentry->header.ino = entry_parms->extra_ino_flags | (++inode_count);
1976
   fsentry->header.ino = entry_parms->extra_ino_flags | (++inode_count);
Line 1852... Line 2117...
1852
      .extra_ino_flags = 0,
2117
      .extra_ino_flags = 0,
1853
      .search = "",
2118
      .search = "",
1854
      .data = { NULL, 0 }
2119
      .data = { NULL, 0 }
1855
   };
2120
   };
1856
   static parms_t entry_parms = { 0 }; // current parameters for a filesystem entry (will be initialized to default_parms each time a new entry is parsed in the build file)
2121
   static parms_t entry_parms = { 0 }; // current parameters for a filesystem entry (will be initialized to default_parms each time a new entry is parsed in the build file)
1857
 
-
 
1858
   // bootable IFS support
-
 
1859
   char *bootfile_pathname = NULL;           // HACK: pathname to bootcode binary blob file to put at the start of a bootable IFS
-
 
1860
   size_t bootfile_size = 0;                 // HACK: size of the bootcode binary blob file to put at the start of a bootable IFS
-
 
1861
   char *startupfile_pathname = NULL;        // HACK: pathname to precompiled startup file blob to put in the startup header of a bootable IFS
-
 
1862
   size_t startupfile_ep_from_imagebase = 0; // HACK: startup code entrypoint offset from image base for a bootable IFS 
-
 
1863
   char *kernelfile_pathname = NULL;         // HACK: pathname to precompiled kernel file blob to put in a bootable IFS
-
 
1864
   size_t kernelfile_offset = 0;             // HACK: kernel file offset in bootable IFS
-
 
1865
 
2122
 
1866
   char path_on_buildhost[MAXPATHLEN] = "";
2123
   char path_on_buildhost[MAXPATHLEN] = "";
1867
   char path_in_ifs[MAXPATHLEN] = "";
2124
   char path_in_ifs[MAXPATHLEN] = "";
1868
   char *ifs_pathname = NULL;
2125
   char *ifs_pathname = NULL;
1869
   void *reallocated_ptr;
2126
   void *reallocated_ptr;
Line 1904... Line 2161...
1904
   bool should_discard_inline_contents = false;
2161
   bool should_discard_inline_contents = false;
1905
   bool want_info = false;
2162
   bool want_info = false;
1906
   bool want_everything = false;
2163
   bool want_everything = false;
1907
   bool want_help = false;
2164
   bool want_help = false;
1908
   bool want_dump = false;
2165
   bool want_dump = false;
-
 
2166
   bool want_hexdump = false;
1909
   bool is_foreign_endianness;
2167
   bool is_foreign_endianness;
1910
   int string_len;
2168
   int string_len;
1911
   int read_char;
2169
   int read_char;
1912
   FILE *buildfile_fp;
2170
   FILE *buildfile_fp;
1913
   FILE *fp;
2171
   FILE *fp;
Line 1919... Line 2177...
1919
         bootfile_pathname = argv[++arg_index];
2177
         bootfile_pathname = argv[++arg_index];
1920
      else if ((strcmp (argv[arg_index], "--startupfile") == 0) && (arg_index + 1 < argc)) // --startupfile path/to/blob.bin@0x1030
2178
      else if ((strcmp (argv[arg_index], "--startupfile") == 0) && (arg_index + 1 < argc)) // --startupfile path/to/blob.bin@0x1030
1921
      {
2179
      {
1922
         sep = strchr (argv[++arg_index], '@');
2180
         sep = strchr (argv[++arg_index], '@');
1923
         if ((sep == NULL) || (sep[1] == 0))
2181
         if ((sep == NULL) || (sep[1] == 0))
1924
         {
-
 
1925
            fprintf (stderr, "error: the --startupfile arguments expects <pathname>@<entrypoint_from_image_base>\n");
2182
            DIE_WITH_EXITCODE (1, "the --startupfile arguments expects <pathname>@<entrypoint_from_image_base>");
1926
            exit (1);
-
 
1927
         }
-
 
1928
         *sep = 0;
2183
         *sep = 0;
1929
         startupfile_pathname = argv[arg_index];
2184
         startupfile_pathname = argv[arg_index];
1930
         startupfile_ep_from_imagebase = (size_t) read_integer (sep + 1);
2185
         startupfile_ep_from_imagebase = (size_t) read_integer (sep + 1);
1931
      }
2186
      }
1932
      else if ((strcmp (argv[arg_index], "--kernelfile") == 0) && (arg_index + 1 < argc)) // --kernelfile path/to/blob.bin@0x32000
2187
      else if ((strcmp (argv[arg_index], "--kernelfile") == 0) && (arg_index + 1 < argc)) // --kernelfile path/to/blob.bin@0x32000
1933
      {
2188
      {
1934
         sep = strchr (argv[++arg_index], '@');
2189
         sep = strchr (argv[++arg_index], '@');
1935
         if ((sep == NULL) || (sep[1] == 0))
2190
         if ((sep == NULL) || (sep[1] == 0))
1936
         {
-
 
1937
            fprintf (stderr, "error: the --kernelfile arguments expects <pathname>@<fileoffset>\n");
2191
            DIE_WITH_EXITCODE (1, "the --kernelfile arguments expects <pathname>@<fileoffset>");
1938
            exit (1);
-
 
1939
         }
-
 
1940
         *sep = 0;
2192
         *sep = 0;
1941
         kernelfile_pathname = argv[arg_index];
2193
         kernelfile_pathname = argv[arg_index];
1942
         kernelfile_offset = (size_t) read_integer (sep + 1);
2194
         kernelfile_offset = (size_t) read_integer (sep + 1);
1943
      }
2195
      }
1944
      else if (strcmp (argv[arg_index], "-n") == 0)
2196
      else if (strcmp (argv[arg_index], "-n") == 0)
Line 1952... Line 2204...
1952
         outdir = argv[++arg_index];
2204
         outdir = argv[++arg_index];
1953
      else if (strcmp (argv[arg_index], "--info") == 0)
2205
      else if (strcmp (argv[arg_index], "--info") == 0)
1954
         want_info = true;
2206
         want_info = true;
1955
      else if (strcmp (argv[arg_index], "--dump") == 0)
2207
      else if (strcmp (argv[arg_index], "--dump") == 0)
1956
         want_dump = true;
2208
         want_dump = true;
-
 
2209
      else if (strcmp (argv[arg_index], "--hexdump") == 0) // voluntarily undocumented
-
 
2210
         want_hexdump = true;
1957
      else if (strcmp (argv[arg_index], "--everything") == 0)
2211
      else if (strcmp (argv[arg_index], "--everything") == 0)
1958
         want_everything = true;
2212
         want_everything = true;
-
 
2213
      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
1959
      else if ((strcmp (argv[arg_index], "-?") == 0) || (strcmp (argv[arg_index], "--help") == 0))
2215
      else if ((strcmp (argv[arg_index], "-?") == 0) || (strcmp (argv[arg_index], "--help") == 0))
1960
         want_help = true;
2216
         want_help = true;
1961
      else if (buildfile_pathname == NULL)
2217
      else if (buildfile_pathname == NULL)
1962
         buildfile_pathname = argv[arg_index];
2218
         buildfile_pathname = argv[arg_index];
1963
      else if (ifs_pathname == NULL)
2219
      else if (ifs_pathname == NULL)
1964
         ifs_pathname = argv[arg_index];
2220
         ifs_pathname = argv[arg_index];
1965
   }
2221
   }
1966
 
2222
 
1967
   // do we not have enough information to run ?
2223
   // do we not have enough information to run ?
1968
   if (want_help || (buildfile_pathname == NULL) || (!want_info && !want_dump && (ifs_pathname == NULL)))
2224
   if (want_help || (buildfile_pathname == NULL) || (!want_info && !want_dump && !want_hexdump && (ifs_pathname == NULL)))
1969
   {
2225
   {
1970
      fp = (want_help ? stdout : stderr); // select the right output channel
2226
      fp = (want_help ? stdout : stderr); // select the right output channel
1971
      fprintf (fp, "ifstool - QNX in-kernel filesystem creation utility by Pierre-Marie Baty <pm@pmbaty.com>\n");
2227
      fprintf (fp, "ifstool - QNX in-kernel filesystem creation utility by Pierre-Marie Baty <pm@pmbaty.com>\n");
1972
      fprintf (fp, "          version " VERSION_FMT_YYYYMMDD "\n", VERSION_ARG_YYYYMMDD);
2228
      fprintf (fp, "          version " VERSION_FMT_YYYYMMDD "\n", VERSION_ARG_YYYYMMDD);
1973
      if (!want_help)
2229
      if (!want_help)
Line 1986... Line 2242...
1986
      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
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
1987
 
2243
 
1988
   // else do we want to dump its contents ? if so, do so
2244
   // else do we want to dump its contents ? if so, do so
1989
   else if (want_dump)
2245
   else if (want_dump)
1990
      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
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
-
 
2247
 
-
 
2248
   // else do we want to hex dump a file ? (this is voluntarily undocumented)
-
 
2249
   else if (want_hexdump)
-
 
2250
   {
-
 
2251
      if (read_filecontents (buildfile_pathname, ".", &blob) == NULL)
-
 
2252
         DIE_WITH_EXITCODE (1, "can't read \"%s\": %s", buildfile_pathname, strerror (errno));
-
 
2253
      hex_fprintf (stdout, blob.bytes, blob.len, 16, "%s (%zd bytes):\n", buildfile_pathname, blob.len);
-
 
2254
      exit (0);
-
 
2255
   }
1991
 
2256
 
1992
   // make sure we have ${QNX_TARGET} pointing somewhere
2257
   // make sure we have ${QNX_TARGET} pointing somewhere
1993
   QNX_TARGET = getenv ("QNX_TARGET");
2258
   QNX_TARGET = getenv ("QNX_TARGET");
1994
   if (QNX_TARGET == NULL)
2259
   if (QNX_TARGET == NULL)
1995
   {
-
 
1996
      fprintf (stderr, "error: the QNX_TARGET environment variable is not set\n");
2260
      DIE_WITH_EXITCODE (1, "the QNX_TARGET environment variable is not set");
1997
      exit (1);
-
 
1998
   }
-
 
1999
   else if (access (QNX_TARGET, 0) != 0)
2261
   else if (access (QNX_TARGET, 0) != 0)
2000
   {
-
 
2001
      fprintf (stderr, "error: the QNX_TARGET environment variable doesn't point to an existing directory\n");
2262
      DIE_WITH_EXITCODE (1, "the QNX_TARGET environment variable doesn't point to an existing directory");
2002
      exit (1);
-
 
2003
   }
-
 
2004
 
2263
 
2005
   // prepare a default MKIFS_PATH assuming the host processor
2264
   // prepare a default MKIFS_PATH assuming the host processor
2006
   update_MKIFS_PATH (image_processor);
2265
   update_MKIFS_PATH (image_processor);
2007
 
2266
 
2008
   // open build file
2267
   // open build file
2009
   buildfile_fp = fopen (buildfile_pathname, "rb");
2268
   buildfile_fp = fopen (buildfile_pathname, "rb");
2010
   if (buildfile_fp == NULL)
2269
   if (buildfile_fp == NULL)
2011
   {
-
 
2012
      fprintf (stderr, "error: unable to open build file \"%s\" for reading (%s)\n", buildfile_pathname, strerror (errno));
2270
      DIE_WITH_EXITCODE (1, "unable to open build file \"%s\" for reading: %s", buildfile_pathname, strerror (errno));
2013
      exit (1);
-
 
2014
   }
-
 
2015
 
2271
 
2016
   // stack up filesystem entries
2272
   // stack up filesystem entries
2017
   memcpy (&entry_parms, &default_parms, sizeof (default_parms));
2273
   memcpy (&entry_parms, &default_parms, sizeof (default_parms));
2018
   entry_parms.st_mode = S_IFDIR | default_parms.dperms;
2274
   entry_parms.st_mode = S_IFDIR | default_parms.dperms;
2019
   add_fsentry (&fsentries, &fsentry_count, &entry_parms, "", NULL); // add the root dir first
2275
   add_fsentry (&fsentries, &fsentry_count, &entry_parms, "", NULL); // add the root dir first
Line 2048... Line 2304...
2048
      if (*line_ptr == '[')
2304
      if (*line_ptr == '[')
2049
      {
2305
      {
2050
         line_ptr++; // skip the leading square bracket
2306
         line_ptr++; // skip the leading square bracket
2051
         directiveblock_start = line_ptr; // remember where it starts
2307
         directiveblock_start = line_ptr; // remember where it starts
2052
         is_quoted_context = false;
2308
         is_quoted_context = false;
2053
         while ((*line_ptr != 0) && !((*line_ptr == ']') && (line_ptr[-1] != '\\')))
2309
         while ((*line_ptr != 0) && !((*line_ptr == ']') && (line_ptr[-1] != '\\') && !is_quoted_context))
2054
         {
2310
         {
2055
            if (*line_ptr == '"')
2311
            if (*line_ptr == '"')
2056
               is_quoted_context ^= true; // remember when we're between quotes
2312
               is_quoted_context ^= true; // remember when we're between quotes
2057
            else if (!is_quoted_context && (*line_ptr == ' '))
2313
            else if (!is_quoted_context && (*line_ptr == ' '))
2058
               *line_ptr = RECORD_SEP; // turn all spaces outside quoted contexts into an ASCII record separator to ease token splitting
2314
               *line_ptr = RECORD_SEP; // turn all spaces outside quoted contexts into an ASCII record separator to ease token splitting
2059
            line_ptr++; // reach the next unescaped closing square bracket
2315
            line_ptr++; // reach the next unescaped closing square bracket
2060
         }
2316
         }
2061
         if (*line_ptr != ']')
2317
         if (*line_ptr != ']')
2062
         {
2318
         {
2063
            fprintf (stderr, "warning: syntax error in \"%s\" line %d: unterminated attributes block (skipping)\n", buildfile_pathname, lineno);
2319
            LOG ("warning", 0, "syntax error in \"%s\" line %d: unterminated attributes block (skipping)", buildfile_pathname, lineno);
2064
            continue; // invalid attribute block, skip line
2320
            continue; // invalid attribute block, skip line
2065
         }
2321
         }
2066
         *line_ptr = 0; // end the attribute block so that it is a parsable C string
2322
         *line_ptr = 0; // end the attribute block so that it is a parsable C string
2067
 
2323
 
2068
         // now parse the attribute tokens
2324
         // now parse the attribute tokens
Line 2074... Line 2330...
2074
            #define REACH_TOKEN_VALUE() do { value = strchr (token, '=') + 1; if (*value == '"') value++; } while (0)
2330
            #define REACH_TOKEN_VALUE() do { value = strchr (token, '=') + 1; if (*value == '"') value++; } while (0)
2075
            if      (strncmp (token, "uid=",     4) == 0) { REACH_TOKEN_VALUE (); entry_parms.uid     = (int) read_integer (value); }
2331
            if      (strncmp (token, "uid=",     4) == 0) { REACH_TOKEN_VALUE (); entry_parms.uid     = (int) read_integer (value); }
2076
            else if (strncmp (token, "gid=",     4) == 0) { REACH_TOKEN_VALUE (); entry_parms.gid     = (int) read_integer (value); }
2332
            else if (strncmp (token, "gid=",     4) == 0) { REACH_TOKEN_VALUE (); entry_parms.gid     = (int) read_integer (value); }
2077
            else if (strncmp (token, "dperms=",  7) == 0) { REACH_TOKEN_VALUE (); entry_parms.dperms  = (int) read_integer (value); }
2333
            else if (strncmp (token, "dperms=",  7) == 0) { REACH_TOKEN_VALUE (); entry_parms.dperms  = (int) read_integer (value); }
2078
            else if (strncmp (token, "perms=",   6) == 0) { REACH_TOKEN_VALUE (); entry_parms.perms   = (int) read_integer (value); }
2334
            else if (strncmp (token, "perms=",   6) == 0) { REACH_TOKEN_VALUE (); entry_parms.perms   = (int) read_integer (value); }
2079
            else if (strncmp (token, "type=",    5) == 0) { REACH_TOKEN_VALUE (); entry_parms.st_mode = (strcmp (value, "dir") == 0 ? S_IFDIR : (strcmp (value, "file") == 0 ? S_IFREG : (strcmp (value, "link") == 0 ? S_IFLNK : (strcmp (value, "fifo") == 0 ? S_IFIFO : (fprintf (stderr, "warning: invalid 'type' attribute in \"%s\" line %d: '%s', defaulting to 'file'\n", buildfile_pathname, lineno, value), S_IFREG))))); }
2335
            else if (strncmp (token, "type=",    5) == 0) { REACH_TOKEN_VALUE ();
-
 
2336
               if      (strcmp (value, "dir")  == 0) entry_parms.st_mode = S_IFDIR;
-
 
2337
               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;
-
 
2339
               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);
-
 
2341
            }
2080
            else if (strncmp (token, "prefix=",  7) == 0) { REACH_TOKEN_VALUE (); strcpy (entry_parms.prefix, (*value == '/' ? value + 1 : value)); } // skip possible leading slash in prefix
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
2081
            else if (strncmp (token, "image=",   6) == 0) { REACH_TOKEN_VALUE ();
2343
            else if (strncmp (token, "image=",   6) == 0) { REACH_TOKEN_VALUE ();
2082
               image_base = (uint32_t) read_integer (value); // read image base address
2344
               image_base = (uint32_t) read_integer (value); // read image base address
2083
               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.)
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.)
2084
               if ((sep = strchr (value, ',')) != NULL) image_maxsize   = (uint32_t) read_integer (sep + 1); // if we have a comma, read optional image max size
2346
               if ((sep = strchr (value, ',')) != NULL) image_maxsize   = (uint32_t) read_integer (sep + 1); // if we have a comma, read optional image max size
2085
               if ((sep = strchr (value, '=')) != NULL) image_totalsize = (uint32_t) read_integer (sep + 1); // if we have an equal sign, read optional image padding 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
2086
               if ((sep = strchr (value, '%')) != NULL) image_align     = (uint32_t) read_integer (sep + 1); // if we have a modulo sign, read optional image aligmnent
2348
               if ((sep = strchr (value, '%')) != NULL) image_align     = (uint32_t) read_integer (sep + 1); // if we have a modulo sign, read optional image aligmnent
2087
               fprintf (stderr, "info: image 0x%x-0x%x maxsize %d totalsize %d align %d\n", image_base, image_end, image_maxsize, image_totalsize, image_align);
2349
               LOG_INFO ("image 0x%x-0x%x maxsize %d totalsize %d align %d", image_base, image_end, image_maxsize, image_totalsize, image_align);
2088
            }
2350
            }
2089
            else if (strncmp (token, "virtual=", 8) == 0) { REACH_TOKEN_VALUE ();
2351
            else if (strncmp (token, "virtual=", 8) == 0) { REACH_TOKEN_VALUE ();
2090
               if ((bootfile_pathname == NULL) || (startupfile_pathname == NULL) || (kernelfile_pathname == NULL)) // HACK until I figure out how to re-create them
2352
               if ((bootfile_pathname == NULL) || (startupfile_pathname == NULL) || (kernelfile_pathname == NULL)) // HACK until I figure out how to re-create them
2091
               {
-
 
2092
                  fprintf (stderr, "error: creating bootable images require the --bootfile, --startupfile and --kernelfile command-line options in \"%s\" line %d\n", buildfile_pathname, lineno);
2353
                  DIE_WITH_EXITCODE (1, "creating bootable images require the --bootfile, --startupfile and --kernelfile command-line options in \"%s\" line %d", buildfile_pathname, lineno);
2093
                  exit (1);
-
 
2094
               }
-
 
2095
               if ((sep = strchr (value, ',')) != NULL) // do we have a comma separating (optional) processor and boot file name ?
2354
               if ((sep = strchr (value, ',')) != NULL) // do we have a comma separating (optional) processor and boot file name ?
2096
               {
2355
               {
2097
                  *sep = 0;
2356
                  *sep = 0;
2098
                  strcpy (image_processor, value); // save processor
2357
                  strcpy (image_processor, value); // save processor
2099
                  update_MKIFS_PATH (image_processor);
2358
                  update_MKIFS_PATH (image_processor);
2100
                  value = sep + 1;
2359
                  value = sep + 1;
2101
               }
2360
               }
2102
               //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.)
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.)
2103
               //strcpy (image_bootfile, bootfile_pathname); // FIXME: HACK
2362
               //strcpy (image_bootfile, bootfile_pathname); // FIXME: HACK
2104
               if (stat (bootfile_pathname, &stat_buf) != 0)
2363
               if (stat (bootfile_pathname, &stat_buf) != 0)
2105
               {
-
 
2106
                  fprintf (stderr, "error: unable to stat the boot file \"%s\" specified in \"%s\" line %d: %s\n", bootfile_pathname, buildfile_pathname, lineno, strerror (errno));
2364
                  DIE_WITH_EXITCODE (1, "unable to stat the boot file \"%s\" specified in \"%s\" line %d: %s", bootfile_pathname, buildfile_pathname, lineno, strerror (errno));
2107
                  exit (1);
-
 
2108
               }
-
 
2109
               bootfile_size = stat_buf.st_size; // save preboot file size
2365
               bootfile_size = stat_buf.st_size; // save preboot file size
2110
               fprintf (stderr, "info: processor \"%s\" bootfile \"%s\"\n", image_processor, bootfile_pathname);
2366
               LOG_INFO ("processor \"%s\" bootfile \"%s\"\n", image_processor, bootfile_pathname);
2111
#if 1
2367
#if 1
2112
               // ######################################################################################################################################################################################################################################
2368
               // ######################################################################################################################################################################################################################################
2113
               // # FIXME: figure out how to re-create it: linker call involved
2369
               // # FIXME: figure out how to re-create it: linker call involved
2114
               // # $ 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
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
2115
               // ######################################################################################################################################################################################################################################
2371
               // ######################################################################################################################################################################################################################################
2116
               if (read_filecontents (kernelfile_pathname, ".", &entry_parms.data) == NULL)
2372
//               if (read_filecontents (kernelfile_pathname, ".", &entry_parms.data) == NULL)
2117
               {
-
 
2118
                  fprintf (stderr, "fatal error: unable to read precompiled kernel file \"%s\" specified in --kernelfile argument\n", kernelfile_pathname);
2373
//                  DIE_WITH_EXITCODE (1, "unable to read precompiled kernel file \"%s\" specified in --kernelfile argument: %s", kernelfile_pathname, strerror (errno));
2119
                  exit (1);
-
 
2120
               }
-
 
2121
#else // nonworking
2374
#else // nonworking
2122
               strcpy (path_on_buildhost, "procnto-smp-instr");
2375
               strcpy (path_on_buildhost, "procnto-smp-instr");
2123
#endif // nonworking
2376
#endif // nonworking
2124
 
-
 
2125
               should_discard_inline_contents = true; // remember we already have data (so as to discard the inline block's contents)
-
 
2126
            }
2377
            }
2127
            else if (strncmp (token, "mtime=", 6) == 0) { REACH_TOKEN_VALUE (); if (strcmp (value, "*") == 0) entry_parms.mtime = UINT32_MAX; else {
2378
            else if (strncmp (token, "mtime=", 6) == 0) { REACH_TOKEN_VALUE (); if (strcmp (value, "*") == 0) entry_parms.mtime = UINT32_MAX; else {
2128
                  // value *must* be "YYYY-MM-DD-HH:MM:SS" by specification
2379
                  // value *must* be "YYYY-MM-DD-HH:MM:SS" by specification
2129
                  memset (&utc_time, 0, sizeof (utc_time));
2380
                  memset (&utc_time, 0, sizeof (utc_time));
2130
                  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)
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)
2131
                  {
2382
                  {
2132
                     fprintf (stderr, "warning: syntax error in \"%s\" line %d: mtime specification not in YYYY-MM-DD-HH:MM:SS format (skipping)\n", buildfile_pathname, lineno);
2383
                     LOG_WARNING ("syntax error in \"%s\" line %d: mtime specification not in YYYY-MM-DD-HH:MM:SS format (skipping)", buildfile_pathname, lineno);
2133
                     continue; // invalid attribute block, skip line
2384
                     continue; // invalid attribute block, skip line
2134
                  }
2385
                  }
2135
                  utc_time.tm_mon--; // convert month from [1-12] to [0-11]
2386
                  utc_time.tm_mon--; // convert month from [1-12] to [0-11]
2136
                  entry_parms.mtime = (uint32_t) mktime (&utc_time);
2387
                  entry_parms.mtime = (uint32_t) mktime (&utc_time);
2137
               }
2388
               }
Line 2147... Line 2398...
2147
            else if (strcmp (token, "-script")     == 0) entry_parms.is_compiled_bootscript = false;
2398
            else if (strcmp (token, "-script")     == 0) entry_parms.is_compiled_bootscript = false;
2148
            else if (strcmp (token, "+followlink") == 0) entry_parms.should_follow_symlinks = true;
2399
            else if (strcmp (token, "+followlink") == 0) entry_parms.should_follow_symlinks = true;
2149
            else if (strcmp (token, "-followlink") == 0) entry_parms.should_follow_symlinks = false;
2400
            else if (strcmp (token, "-followlink") == 0) entry_parms.should_follow_symlinks = false;
2150
            else if (strcmp (token, "+autolink")   == 0) entry_parms.should_autosymlink_dylib = true;
2401
            else if (strcmp (token, "+autolink")   == 0) entry_parms.should_autosymlink_dylib = true;
2151
            else if (strcmp (token, "-autolink")   == 0) entry_parms.should_autosymlink_dylib = false;
2402
            else if (strcmp (token, "-autolink")   == 0) entry_parms.should_autosymlink_dylib = false;
-
 
2403
            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;
2152
            else fprintf (stderr, "warning: unimplemented attribute in \"%s\" line %d: '%s'\n", buildfile_pathname, lineno, token);
2405
            else LOG_WARNING ("unimplemented attribute in \"%s\" line %d: '%s'", buildfile_pathname, lineno, token);
2153
            #undef REACH_TOKEN_VALUE
2406
            #undef REACH_TOKEN_VALUE
2154
 
2407
 
2155
            token = strtok (NULL, RECORD_SEP_STR); // proceed to next attribute token
2408
            token = strtok (NULL, RECORD_SEP_STR); // proceed to next attribute token
2156
         }
2409
         }
2157
 
2410
 
Line 2161... Line 2414...
2161
 
2414
 
2162
         // are we at the end of the line ? if so, it means the attribute values that are set should become the default
2415
         // are we at the end of the line ? if so, it means the attribute values that are set should become the default
2163
         if ((*line_ptr == 0) || (*line_ptr == '#'))
2416
         if ((*line_ptr == 0) || (*line_ptr == '#'))
2164
         {
2417
         {
2165
            #define APPLY_DEFAULT_ATTR_NUM(attr,descr,fmt) do { if (entry_parms.attr != default_parms.attr) { \
2418
            #define APPLY_DEFAULT_ATTR_NUM(attr,descr,fmt) do { if (entry_parms.attr != default_parms.attr) { \
2166
                  fprintf (stderr, "info: changing default " descr " from " fmt " to " fmt " by attribute at \"%s\" line %d\n", default_parms.attr, entry_parms.attr, buildfile_pathname, lineno); \
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); \
2167
                  default_parms.attr = entry_parms.attr; \
2420
                  default_parms.attr = entry_parms.attr; \
2168
               } } while (0)
2421
               } } while (0)
2169
            #define APPLY_DEFAULT_ATTR_STR(attr,descr,fmt) do { if (strcmp (entry_parms.attr, default_parms.attr) != 0) { \
2422
            #define APPLY_DEFAULT_ATTR_STR(attr,descr,fmt) do { if (strcmp (entry_parms.attr, default_parms.attr) != 0) { \
2170
                  fprintf (stderr, "info: changing default " descr " from " fmt " to " fmt " by attribute at \"%s\" line %d\n", default_parms.attr, entry_parms.attr, buildfile_pathname, lineno); \
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); \
2171
                  strcpy (default_parms.attr, entry_parms.attr); \
2424
                  strcpy (default_parms.attr, entry_parms.attr); \
2172
               } } while (0)
2425
               } } while (0)
2173
            APPLY_DEFAULT_ATTR_NUM (dperms,                   "directory permissions",           "0%o");
2426
            APPLY_DEFAULT_ATTR_NUM (dperms,                   "directory permissions",           "0%o");
2174
            APPLY_DEFAULT_ATTR_NUM (perms,                    "file permissions",                "0%o");
2427
            APPLY_DEFAULT_ATTR_NUM (perms,                    "file permissions",                "0%o");
2175
            APPLY_DEFAULT_ATTR_NUM (uid,                      "owner ID",                        "%d");
2428
            APPLY_DEFAULT_ATTR_NUM (uid,                      "owner ID",                        "%d");
Line 2177... Line 2430...
2177
            APPLY_DEFAULT_ATTR_NUM (st_mode,                  "inode type",                      "0%o");
2430
            APPLY_DEFAULT_ATTR_NUM (st_mode,                  "inode type",                      "0%o");
2178
            APPLY_DEFAULT_ATTR_STR (prefix,                   "prefix",                          "\"%s\"");
2431
            APPLY_DEFAULT_ATTR_STR (prefix,                   "prefix",                          "\"%s\"");
2179
            APPLY_DEFAULT_ATTR_NUM (is_compiled_bootscript,   "compiled script state",           "%d");
2432
            APPLY_DEFAULT_ATTR_NUM (is_compiled_bootscript,   "compiled script state",           "%d");
2180
            APPLY_DEFAULT_ATTR_NUM (should_follow_symlinks,   "symlink resolution",              "%d");
2433
            APPLY_DEFAULT_ATTR_NUM (should_follow_symlinks,   "symlink resolution",              "%d");
2181
            APPLY_DEFAULT_ATTR_NUM (should_autosymlink_dylib, "dylib canonical name symlinking", "%d");
2434
            APPLY_DEFAULT_ATTR_NUM (should_autosymlink_dylib, "dylib canonical name symlinking", "%d");
-
 
2435
            APPLY_DEFAULT_ATTR_NUM (should_keep_ld_output,    "linker output preservation",      "%d");
2182
            #undef APPLY_DEFAULT_ATTR_STR
2436
            #undef APPLY_DEFAULT_ATTR_STR
2183
            #undef APPLY_DEFAULT_ATTR_NUM
2437
            #undef APPLY_DEFAULT_ATTR_NUM
2184
            continue; // end of line reached, proceed to the next line
2438
            continue; // end of line reached, proceed to the next line
2185
         }
2439
         }
2186
         // end of attributes parsing
2440
         // end of attributes parsing
Line 2196... Line 2450...
2196
      is_quoted_context = (*line_ptr == '"');
2450
      is_quoted_context = (*line_ptr == '"');
2197
      if (is_quoted_context)
2451
      if (is_quoted_context)
2198
         line_ptr++; // skip a possible initial quote
2452
         line_ptr++; // skip a possible initial quote
2199
      if (*line_ptr == '/')
2453
      if (*line_ptr == '/')
2200
      {
2454
      {
2201
         fprintf (stderr, "warning: paths in the IFS file should not begin with a leading '/' in \"%s\" line %d\n", buildfile_pathname, lineno);
2455
         LOG_WARNING ("paths in the IFS file should not begin with a leading '/' in \"%s\" line %d", buildfile_pathname, lineno);
2202
         line_ptr++; // consistency check: paths in the IFS should not begin with a '/'
2456
         line_ptr++; // consistency check: paths in the IFS should not begin with a '/'
2203
      }
2457
      }
2204
      while ((*line_ptr != 0) && ((!is_quoted_context && (*line_ptr != '=') && !isspace (*line_ptr)) || (is_quoted_context && (*line_ptr == '"'))))
2458
      while ((*line_ptr != 0) && ((!is_quoted_context && (*line_ptr != '=') && !isspace (*line_ptr)) || (is_quoted_context && (*line_ptr == '"'))))
2205
      {
2459
      {
2206
         if (*line_ptr == '\\')
2460
         if (*line_ptr == '\\')
Line 2227... Line 2481...
2227
         while ((*line_ptr != 0) && isspace (*line_ptr))
2481
         while ((*line_ptr != 0) && isspace (*line_ptr))
2228
            line_ptr++; // skip optional spaces after the equal sign
2482
            line_ptr++; // skip optional spaces after the equal sign
2229
 
2483
 
2230
         if (*line_ptr == 0)
2484
         if (*line_ptr == 0)
2231
         {
2485
         {
2232
            fprintf (stderr, "warning: syntax error in \"%s\" line %d: missing data specification after equal sign (skipping)\n", buildfile_pathname, lineno);
2486
            LOG_WARNING ("syntax error in \"%s\" line %d: missing data specification after equal sign (skipping)", buildfile_pathname, lineno);
2233
            continue; // invalid symlink specification, skip line
2487
            continue; // invalid symlink specification, skip line
2234
         }
2488
         }
2235
 
2489
 
2236
         // read the host system's path, it may be either a path or a contents definition. Is it a content definition ?
2490
         // read the host system's path, it may be either a path or a contents definition. Is it a content definition ?
2237
         if (*line_ptr == '{')
2491
         if (*line_ptr == '{')
Line 2242... Line 2496...
2242
            is_escaped_char = false;
2496
            is_escaped_char = false;
2243
            for (;;)
2497
            for (;;)
2244
            {
2498
            {
2245
               read_char = fgetc (buildfile_fp);
2499
               read_char = fgetc (buildfile_fp);
2246
               if (read_char == EOF)
2500
               if (read_char == EOF)
2247
               {
-
 
2248
                  fprintf (stderr, "fatal error: syntax error in \"%s\" line %d: unterminated contents block (end of file reached)\n", buildfile_pathname, lineno);
2501
                  DIE_WITH_EXITCODE (1, "syntax error in \"%s\" line %d: unterminated contents block (end of file reached)", buildfile_pathname, lineno); // invalid contents block
2249
                  exit (1); // invalid contents block
-
 
2250
               }
-
 
2251
               else if ((read_char == '\\') && !is_escaped_char)
2502
               else if ((read_char == '\\') && !is_escaped_char)
2252
                  is_escaped_char = true; // remember the next char is escaped
2503
                  is_escaped_char = true; // remember the next char is escaped
2253
               else if ((read_char == '}') && !is_escaped_char)
2504
               else if ((read_char == '}') && !is_escaped_char)
2254
                  break; // found an unescaped closing bracked, stop parsing
2505
                  break; // found an unescaped closing bracked, stop parsing
2255
               else
2506
               else
Line 2306... Line 2557...
2306
      else // no equal sign, meaning the file will have the same name on the build host filesystem
2557
      else // no equal sign, meaning the file will have the same name on the build host filesystem
2307
      {
2558
      {
2308
         // consistency check: symlinks MUST have an equal sign
2559
         // consistency check: symlinks MUST have an equal sign
2309
         if (entry_parms.st_mode == S_IFLNK)
2560
         if (entry_parms.st_mode == S_IFLNK)
2310
         {
2561
         {
2311
            fprintf (stderr, "warning: syntax error in \"%s\" line %d: missing equal sign and symlink target (skipping)\n", buildfile_pathname, lineno);
2562
            LOG_WARNING ("syntax error in \"%s\" line %d: missing equal sign and symlink target (skipping)", buildfile_pathname, lineno);
2312
            continue; // invalid symlink specification, skip line
2563
            continue; // invalid symlink specification, skip line
2313
         }
2564
         }
2314
 
2565
 
2315
         strcpy (path_on_buildhost, specifiedpathname_start); // the path on the build host is the one specified
2566
         strcpy (path_on_buildhost, specifiedpathname_start); // the path on the build host is the one specified
2316
         sep = strrchr (specifiedpathname_start, '/');
2567
         sep = strrchr (specifiedpathname_start, '/');
Line 2333... Line 2584...
2333
   }
2584
   }
2334
 
2585
 
2335
   // write IFS file
2586
   // write IFS file
2336
   fp = fopen (ifs_pathname, "w+b");
2587
   fp = fopen (ifs_pathname, "w+b");
2337
   if (fp == NULL)
2588
   if (fp == NULL)
2338
   {
-
 
2339
      fprintf (stderr, "error: failed to open \"%s\" for writing (%s)\n", ifs_pathname, strerror (errno));
2589
      DIE_WITH_EXITCODE (1, "failed to open \"%s\" for writing: %s", ifs_pathname, strerror (errno));
2340
      exit (1);
-
 
2341
   }
-
 
2342
 
2590
 
2343
   // do we have a startup file ? if so, this is a bootable image
2591
   // do we have a startup file ? if so, this is a bootable image
2344
   if (startupfile_pathname != NULL)
2592
   if (startupfile_pathname != NULL)
2345
   {
2593
   {
2346
      // write boot prefix
2594
      // write boot prefix
Line 2359... Line 2607...
2359
      if (strcmp (image_processor, "x86_64") == 0)
2607
      if (strcmp (image_processor, "x86_64") == 0)
2360
         startup_header.machine = ELF_MACHINE_X86_64; // EM_X86_64
2608
         startup_header.machine = ELF_MACHINE_X86_64; // EM_X86_64
2361
      else if (strcmp (image_processor, "aarch64le") == 0)
2609
      else if (strcmp (image_processor, "aarch64le") == 0)
2362
         startup_header.machine = ELF_MACHINE_AARCH64; // EM_AARCH64
2610
         startup_header.machine = ELF_MACHINE_AARCH64; // EM_AARCH64
2363
      else
2611
      else
2364
      {
-
 
2365
         fprintf (stderr, "fatal error: unsupported processor type '%s' found in build file \"%s\"\n", image_processor, buildfile_pathname);
2612
         DIE_WITH_EXITCODE (1, "unsupported processor type '%s' found in build file \"%s\"", image_processor, buildfile_pathname); // should not happen
2366
         exit (1);
-
 
2367
      }
-
 
2368
      startup_header.startup_vaddr = image_base + (uint32_t) startupfile_ep_from_imagebase; // [I ] Virtual Address to transfer to after IPL is done, here 0x01403008 (appears in "Entry" column for "startup.*")
2613
      startup_header.startup_vaddr = image_base + (uint32_t) startupfile_ep_from_imagebase; // [I ] Virtual Address to transfer to after IPL is done, here 0x01403008 (appears in "Entry" column for "startup.*")
2369
      startup_header.image_paddr   = image_base + (uint32_t) bootfile_size;                 // F[IS] Physical address of image, here 0x01400f30 (appears in "Offset" column for "startup-header" which is the first entry/start of file)
2614
      startup_header.image_paddr   = image_base + (uint32_t) bootfile_size;                 // F[IS] Physical address of image, here 0x01400f30 (appears in "Offset" column for "startup-header" which is the first entry/start of file)
2370
      startup_header.ram_paddr     = startup_header.image_paddr;                            // [IS] Physical address of RAM to copy image to (startup_size bytes copied), here 0x01400f30 (same as above)
2615
      startup_header.ram_paddr     = startup_header.image_paddr;                            // [IS] Physical address of RAM to copy image to (startup_size bytes copied), here 0x01400f30 (same as above)
2371
      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)
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)
2372
      startup_header.startup_size  = WILL_BE_FILLED_LATER;                                  // [I ] Size of startup (never compressed), here 0x02f148 or 192 840 bytes
2617
      startup_header.startup_size  = WILL_BE_FILLED_LATER;                                  // [I ] Size of startup (never compressed), here 0x02f148 or 192 840 bytes
Line 2390... Line 2635...
2390
         elf_section_header_t *shdr_text;
2635
         elf_section_header_t *shdr_text;
2391
         size_t segment_len;
2636
         size_t segment_len;
2392
FILE *control_fp = fopen ("startup.bin.MYSTRIPPED", "wb");
2637
FILE *control_fp = fopen ("startup.bin.MYSTRIPPED", "wb");
2393
 
2638
 
2394
         if (read_filecontents ("startup.bin.UNSTRIPPED", MKIFS_PATH, &startupfile) == NULL)
2639
         if (read_filecontents ("startup.bin.UNSTRIPPED", MKIFS_PATH, &startupfile) == NULL)
2395
         {
-
 
2396
            fprintf (stderr, "fatal error: couldn't read startup-x86\n");
2640
            DIE_WITH_EXITCODE (1, "couldn't read startup-x86");
2397
            exit (1);
-
 
2398
         }
-
 
2399
         elf = (elf_header_t *) startupfile.bytes; // quick access to ELF header
2641
         elf = (elf_header_t *) startupfile.bytes; // quick access to ELF header
2400
         table_count = ELF_GET_NUMERIC (elf, elf, program_header_table_len); // get the number of program headers
2642
         table_count = ELF_GET_NUMERIC (elf, elf, program_header_table_len); // get the number of program headers
2401
         for (table_index = 0; table_index < table_count; table_index++) // cycle through program headers
2643
         for (table_index = 0; table_index < table_count; table_index++) // cycle through program headers
2402
         {
2644
         {
2403
            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
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
Line 2455... Line 2697...
2455
            break; // locate the startup script directory entry
2697
            break; // locate the startup script directory entry
2456
      if (fsentry_index < fsentry_count) // found it ?
2698
      if (fsentry_index < fsentry_count) // found it ?
2457
      {
2699
      {
2458
         curr_offset = ftell (fp);
2700
         curr_offset = ftell (fp);
2459
         if (curr_offset + fsentries[fsentry_index].u.file.size >= kernelfile_offset)
2701
         if (curr_offset + fsentries[fsentry_index].u.file.size >= kernelfile_offset)
2460
         {
-
 
2461
            fprintf (stderr, "error: the compiled startup script is too big (%zd bytes, max is %zd) to fit at current offset %zd\n", (size_t) fsentries[fsentry_index].u.file.size, kernelfile_offset - curr_offset, curr_offset);
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);
2462
            exit (1);
-
 
2463
         }
-
 
2464
         fsentries[fsentry_index].u.file.offset = (uint32_t) (curr_offset - imageheader_offset); // save file data blob offset in file structure
2703
         fsentries[fsentry_index].u.file.offset = (uint32_t) (curr_offset - imageheader_offset); // save file data blob offset in file structure
2465
         fwrite_or_die (fsentries[fsentry_index].u.file.UNSAVED_databuf, 1, fsentries[fsentry_index].u.file.size, fp); // write file data blob
2704
         fwrite_or_die (fsentries[fsentry_index].u.file.UNSAVED_databuf, 1, fsentries[fsentry_index].u.file.size, fp); // write file data blob
2466
         fsentries[fsentry_index].UNSAVED_was_data_written = true; // and remember this file's data was written
2705
         fsentries[fsentry_index].UNSAVED_was_data_written = true; // and remember this file's data was written
2467
      }
2706
      }
2468
 
2707
 
Line 2505... Line 2744...
2505
         }
2744
         }
2506
 
2745
 
2507
         fwrite_or_die (fsentries[largest_index].u.file.UNSAVED_databuf, 1, fsentries[largest_index].u.file.size, fp); // write file data blob
2746
         fwrite_or_die (fsentries[largest_index].u.file.UNSAVED_databuf, 1, fsentries[largest_index].u.file.size, fp); // write file data blob
2508
         fsentries[largest_index].UNSAVED_was_data_written = true; // and remember this file's data was written
2747
         fsentries[largest_index].UNSAVED_was_data_written = true; // and remember this file's data was written
2509
      }
2748
      }
2510
      fprintf (stderr, "Current offset: 0x%zx\n", curr_offset);
2749
      LOG_INFO ("Current offset: 0x%zx", curr_offset);
2511
      fprintf (stderr, "Kernel file offset: 0x%zx\n", kernelfile_offset);
2750
      LOG_INFO ("Kernel file offset: 0x%zx", kernelfile_offset);
2512
      PAD_OUTFILE_TO (kernelfile_offset); // reach the kernel offset
2751
      PAD_OUTFILE_TO (kernelfile_offset); // reach the kernel offset
2513
 
2752
 
2514
      // now write the QNX kernel
2753
      // now write the QNX kernel
2515
      for (fsentry_index = 1; fsentry_index < fsentry_count; fsentry_index++)
2754
      for (fsentry_index = 1; fsentry_index < fsentry_count; fsentry_index++)
2516
         if (fsentries[fsentry_index].header.ino == image_kernel_ino)
2755
         if (fsentries[fsentry_index].header.ino == image_kernel_ino)
2517
            break; // locate the kernel directory entry (can't fail)
2756
            break; // locate the kernel directory entry (can't fail)
2518
      curr_offset = ftell (fp); // see where we are
2757
      curr_offset = ftell (fp); // see where we are
2519
      fsentries[fsentry_index].u.file.offset = (uint32_t) (curr_offset - imageheader_offset); // save file data blob offset in file structure
2758
      fsentries[fsentry_index].u.file.offset = (uint32_t) (curr_offset - imageheader_offset); // save file data blob offset in file structure
-
 
2759
#ifdef PROCNTO_WIP
-
 
2760
      // is the kernel we're storing a preprocessed ELF kernel ?
-
 
2761
      if (fsentries[fsentry_index].header.ino & IFS_INO_PROCESSED_ELF)
-
 
2762
      {
-
 
2763
         elf = (elf_header_t *) fsentries[fsentry_index].u.file.UNSAVED_databuf; // quick access to ELF header
-
 
2764
         table_count = ELF_GET_NUMERIC (elf, elf, program_header_table_len); // get the number of program headers
-
 
2765
         for (table_index = 0; table_index < table_count; table_index++)
-
 
2766
         {
-
 
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
-
 
2768
            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
-
 
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
-
 
2771
         }
-
 
2772
      }
-
 
2773
#endif // PROCNTO_WIP
2520
      fwrite_or_die (fsentries[fsentry_index].u.file.UNSAVED_databuf, 1, fsentries[fsentry_index].u.file.size, fp); // write kernel file data blob
2774
      fwrite_or_die (fsentries[fsentry_index].u.file.UNSAVED_databuf, 1, fsentries[fsentry_index].u.file.size, fp); // write kernel file data blob
2521
      PAD_OUTFILE_TO (ROUND_TO_UPPER_MULTIPLE (ftell (fp), image_align)); // pad as necessary
2775
      PAD_OUTFILE_TO (ROUND_TO_UPPER_MULTIPLE (ftell (fp), image_align)); // pad as necessary
2522
      fsentries[fsentry_index].UNSAVED_was_data_written = true; // and remember this file's data was written
2776
      fsentries[fsentry_index].UNSAVED_was_data_written = true; // and remember this file's data was written
2523
   }
2777
   }
2524
 
2778
 
Line 2568... Line 2822...
2568
   PAD_OUTFILE_TO (image_totalsize);
2822
   PAD_OUTFILE_TO (image_totalsize);
2569
   final_size = ftell (fp);
2823
   final_size = ftell (fp);
2570
 
2824
 
2571
   // see if we are past the image max size, in which case it's an error
2825
   // see if we are past the image max size, in which case it's an error
2572
   if (final_size > image_maxsize)
2826
   if (final_size > image_maxsize)
2573
   {
-
 
2574
      fprintf (stderr, "error: image file \"%s\" size %zd exceeds max size (%zd)\n", ifs_pathname, final_size, (size_t) image_maxsize);
2827
      DIE_WITH_EXITCODE (1, "image file \"%s\" size %zd exceeds max size (%zd)", ifs_pathname, final_size, (size_t) image_maxsize);
2575
      exit (1);
-
 
2576
   }
-
 
2577
 
2828
 
2578
   // do we have a startup file ? if so, this is a bootable image
2829
   // do we have a startup file ? if so, this is a bootable image
2579
   if (startupfile_pathname != NULL)
2830
   if (startupfile_pathname != NULL)
2580
   {
2831
   {
2581
      // rewrite startup header with final values
2832
      // rewrite startup header with final values
Line 2639... Line 2890...
2639
   fwrite_or_die (blob.bytes, 1, blob.len, fp);
2890
   fwrite_or_die (blob.bytes, 1, blob.len, fp);
2640
   fclose (fp);
2891
   fclose (fp);
2641
   free (blob.bytes);
2892
   free (blob.bytes);
2642
 
2893
 
2643
   // finished, exit with a success code
2894
   // finished, exit with a success code
2644
   fprintf (stdout, "Success\n");
2895
   LOG_INFO ("Success");
2645
   exit (0);
2896
   exit (0);
2646
}
2897
}
2647
 
2898
 
2648
 
2899
 
2649
static int dump_ifs_info (const char *ifs_pathname, bool want_everything)
2900
static int dump_ifs_info (const char *ifs_pathname, bool want_everything)
Line 2708... Line 2959...
2708
   buffer_t file;
2959
   buffer_t file;
2709
   time_t mtime;
2960
   time_t mtime;
2710
 
2961
 
2711
   // open and read IFS file
2962
   // open and read IFS file
2712
   if (read_filecontents (ifs_pathname, ".", &file) == NULL)
2963
   if (read_filecontents (ifs_pathname, ".", &file) == NULL)
2713
   {
-
 
2714
      fprintf (stderr, "error: can't open \"%s\" for reading: %s\n", ifs_pathname, strerror (errno));
2964
      DIE_WITH_EXITCODE (1, "can't open \"%s\" for reading: %s", ifs_pathname, strerror (errno));
2715
      return (1);
-
 
2716
   }
-
 
2717
 
2965
 
2718
   printf ("QNX In-kernel Filesystem analysis produced by ifstool version " VERSION_FMT_YYYYMMDD "\n", VERSION_ARG_YYYYMMDD);
2966
   printf ("QNX In-kernel Filesystem analysis produced by ifstool version " VERSION_FMT_YYYYMMDD "\n", VERSION_ARG_YYYYMMDD);
2719
   printf ("IFS file \"%s\" - size 0x%zx (%zd) bytes\n", ifs_pathname, file.len, file.len);
2967
   printf ("IFS file \"%s\" - size 0x%zx (%zd) bytes\n", ifs_pathname, file.len, file.len);
2720
 
2968
 
2721
   // parse file from start to end
2969
   // parse file from start to end
Line 2757... Line 3005...
2757
         hex_printf ((uint8_t *) &startup_header->info[0], sizeof (startup_header->info), "   info[48] =\n");
3005
         hex_printf ((uint8_t *) &startup_header->info[0], sizeof (startup_header->info), "   info[48] =\n");
2758
 
3006
 
2759
         // validate that the file can contain up to the startup trailer
3007
         // validate that the file can contain up to the startup trailer
2760
         if (current_offset + startup_header->startup_size > file.len)
3008
         if (current_offset + startup_header->startup_size > file.len)
2761
         {
3009
         {
2762
            printf ("WARNING: this IFS file is corrupted (startup trailer extends past end of file)\n");
3010
            LOG_WARNING ("this IFS file is corrupted (startup trailer extends past end of file)");
2763
            goto endofdata;
3011
            goto endofdata;
2764
         }
3012
         }
2765
 
3013
 
2766
         // check if this endianness is ours
3014
         // check if this endianness is ours
2767
         if (   ( (startup_header->flags1 & STARTUP_HDR_FLAGS1_BIGENDIAN) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
3015
         if (   ( (startup_header->flags1 & STARTUP_HDR_FLAGS1_BIGENDIAN) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
Line 2849... Line 3097...
2849
         printf ("   mountpoint   = \"%s\"\n", image_header->mountpoint);
3097
         printf ("   mountpoint   = \"%s\"\n", image_header->mountpoint);
2850
 
3098
 
2851
         // validate that the file can contain up to the image trailer
3099
         // validate that the file can contain up to the image trailer
2852
         if (current_offset + image_header->image_size > file.len)
3100
         if (current_offset + image_header->image_size > file.len)
2853
         {
3101
         {
2854
            printf ("WARNING: this IFS file is corrupted (image trailer extends past end of file)\n");
3102
            LOG_WARNING ("this IFS file is corrupted (image trailer extends past end of file)");
2855
            goto endofdata;
3103
            goto endofdata;
2856
         }
3104
         }
2857
 
3105
 
2858
         // check if this endianness is ours
3106
         // check if this endianness is ours
2859
         if (   ( (image_header->flags & IMAGE_FLAGS_BIGENDIAN) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
3107
         if (   ( (image_header->flags & IMAGE_FLAGS_BIGENDIAN) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
Line 2930... Line 3178...
2930
               printf ("   [DEVICE] path = \"%s\"\n", (char *) &current_fsentry->u.device.path); // convert from pointer to char array
3178
               printf ("   [DEVICE] path = \"%s\"\n", (char *) &current_fsentry->u.device.path); // convert from pointer to char array
2931
            }
3179
            }
2932
 
3180
 
2933
            if ((current_fsentry->header.size == 0) || (current_offset + current_fsentry->header.size >= file.len))
3181
            if ((current_fsentry->header.size == 0) || (current_offset + current_fsentry->header.size >= file.len))
2934
            {
3182
            {
2935
               printf ("WARNING: this IFS file is corrupted (the size of this directory entry is invalid)\n");
3183
               LOG_WARNING ("this IFS file is corrupted (the size of this directory entry is invalid)");
2936
               goto endofdata;
3184
               goto endofdata;
2937
            }
3185
            }
2938
 
3186
 
2939
            current_offset += current_fsentry->header.size;
3187
            current_offset += current_fsentry->header.size;
2940
         }
3188
         }
Line 2978... Line 3226...
2978
                  hex_printf (&file.bytes[current_offset], current_fsentry->u.file.size, "   data:\n");
3226
                  hex_printf (&file.bytes[current_offset], current_fsentry->u.file.size, "   data:\n");
2979
               if (current_offset + current_fsentry->u.file.size < file.len)
3227
               if (current_offset + current_fsentry->u.file.size < file.len)
2980
                  printf ("   checksum %d\n", update_checksum (&file.bytes[current_offset], current_fsentry->u.file.size, is_foreign_endianness));
3228
                  printf ("   checksum %d\n", update_checksum (&file.bytes[current_offset], current_fsentry->u.file.size, is_foreign_endianness));
2981
               else
3229
               else
2982
               {
3230
               {
2983
                  printf ("WARNING: this IFS file is corrupted (the size of this file data extends past the IFS size)\n");
3231
                  LOG_WARNING ("this IFS file is corrupted (the size of this file data extends past the IFS size)");
2984
                  goto endofdata;
3232
                  goto endofdata;
2985
               }
3233
               }
2986
 
3234
 
2987
               current_offset += current_fsentry->u.file.size; // now jump over this file's data
3235
               current_offset += current_fsentry->u.file.size; // now jump over this file's data
2988
            }
3236
            }
Line 3113... Line 3361...
3113
   buffer_t file;
3361
   buffer_t file;
3114
   FILE *fp;
3362
   FILE *fp;
3115
 
3363
 
3116
   // open and read IFS file
3364
   // open and read IFS file
3117
   if (read_filecontents (ifs_pathname, ".", &file) == NULL)
3365
   if (read_filecontents (ifs_pathname, ".", &file) == NULL)
3118
   {
-
 
3119
      fprintf (stderr, "error: can't open \"%s\" for reading: %s\n", ifs_pathname, strerror (errno));
3366
      DIE_WITH_EXITCODE (1, "can't open \"%s\" for reading: %s\n", ifs_pathname, strerror (errno));
3120
      return (1);
-
 
3121
   }
-
 
3122
 
3367
 
3123
   // create the output directory
3368
   // create the output directory
3124
   create_intermediate_dirs (outdir);
3369
   create_intermediate_dirs (outdir);
3125
   (void) mkdir (outdir, 0755);
3370
   (void) mkdir (outdir, 0755);
3126
 
3371
 
Line 3140... Line 3385...
3140
         // [STARTUP TRAILER v1 or v2]
3385
         // [STARTUP TRAILER v1 or v2]
3141
 
3386
 
3142
         // validate that the file can contain up to the startup trailer
3387
         // validate that the file can contain up to the startup trailer
3143
         if (current_offset + startup_header->startup_size > file.len)
3388
         if (current_offset + startup_header->startup_size > file.len)
3144
         {
3389
         {
3145
            printf ("WARNING: this IFS file is corrupted (startup trailer extends past end of file)\n");
3390
            LOG_WARNING ("this IFS file is corrupted (startup trailer extends past end of file)");
3146
            goto endofdata;
3391
            goto endofdata;
3147
         }
3392
         }
3148
 
3393
 
3149
         // locate the right startup trailer at the right offset
3394
         // locate the right startup trailer at the right offset
3150
         if (startup_header->flags1 & STARTUP_HDR_FLAGS1_TRAILER_V2)
3395
         if (startup_header->flags1 & STARTUP_HDR_FLAGS1_TRAILER_V2)
Line 3181... Line 3426...
3181
         // [IMAGE FOOTER]
3426
         // [IMAGE FOOTER]
3182
 
3427
 
3183
         // validate that the file can contain up to the image trailer
3428
         // validate that the file can contain up to the image trailer
3184
         if (current_offset + image_header->image_size > file.len)
3429
         if (current_offset + image_header->image_size > file.len)
3185
         {
3430
         {
3186
            printf ("WARNING: this IFS file is corrupted (image trailer extends past end of file)\n");
3431
            LOG_WARNING ("this IFS file is corrupted (image trailer extends past end of file)");
3187
            goto endofdata;
3432
            goto endofdata;
3188
         }
3433
         }
3189
 
3434
 
3190
         // locate the image trailer at the right offset
3435
         // locate the image trailer at the right offset
3191
         if (image_header->flags & IMAGE_FLAGS_TRAILER_V2)
3436
         if (image_header->flags & IMAGE_FLAGS_TRAILER_V2)
Line 3213... Line 3458...
3213
            fsentries[fsentry_count] = current_fsentry;
3458
            fsentries[fsentry_count] = current_fsentry;
3214
            fsentry_count++;
3459
            fsentry_count++;
3215
 
3460
 
3216
            if ((current_fsentry->header.size == 0) || (current_offset + current_fsentry->header.size >= file.len))
3461
            if ((current_fsentry->header.size == 0) || (current_offset + current_fsentry->header.size >= file.len))
3217
            {
3462
            {
3218
               printf ("WARNING: this IFS file is corrupted (the size of this directory entry is invalid)\n");
3463
               LOG_WARNING ("this IFS file is corrupted (the size of this directory entry is invalid)");
3219
               goto endofdata;
3464
               goto endofdata;
3220
            }
3465
            }
3221
 
3466
 
3222
            current_offset += current_fsentry->header.size;
3467
            current_offset += current_fsentry->header.size;
3223
         }
3468
         }
Line 3246... Line 3491...
3246
 
3491
 
3247
               current_offset += imageheader_offset + (size_t) current_fsentry->u.file.offset - current_offset; // jump over possible padding
3492
               current_offset += imageheader_offset + (size_t) current_fsentry->u.file.offset - current_offset; // jump over possible padding
3248
 
3493
 
3249
               if (current_offset + current_fsentry->u.file.size >= file.len)
3494
               if (current_offset + current_fsentry->u.file.size >= file.len)
3250
               {
3495
               {
3251
                  printf ("WARNING: this IFS file is corrupted (the size of this file data extends past the IFS size)\n");
3496
                  LOG_WARNING ("this IFS file is corrupted (the size of this file data extends past the IFS size)");
3252
                  goto endofdata;
3497
                  goto endofdata;
3253
               }
3498
               }
3254
 
3499
 
3255
               // write filesystem data entry
3500
               // write filesystem data entry
3256
               if (S_ISDIR (current_fsentry->header.mode))
3501
               if (S_ISDIR (current_fsentry->header.mode))
Line 3295... Line 3540...
3295
               file_times.actime = current_fsentry->header.mtime;
3540
               file_times.actime = current_fsentry->header.mtime;
3296
               file_times.modtime = current_fsentry->header.mtime;
3541
               file_times.modtime = current_fsentry->header.mtime;
3297
               utime (outfile_pathname, &file_times);
3542
               utime (outfile_pathname, &file_times);
3298
 
3543
 
3299
               // set created file mode
3544
               // set created file mode
-
 
3545
#ifndef _WIN32
3300
               (void) chmod (outfile_pathname, current_fsentry->header.mode & 0777);
3546
               (void) chmod (outfile_pathname, current_fsentry->header.mode & 0777); // only on POSIX systems
-
 
3547
#endif // !_WIN32
3301
 
3548
 
3302
               current_offset += current_fsentry->u.file.size; // now jump over this file's data
3549
               current_offset += current_fsentry->u.file.size; // now jump over this file's data
3303
            }
3550
            }
3304
         }
3551
         }
3305
 
3552