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)) { |
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 |
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 ( |
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 ( |
1151 | sprintf (resolved_pathname, "%.*s/%s", (int) (nextsep - token), token, pathname); |
1130 | if (access ( |
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 ( |
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 ( |
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[ |
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 |
|
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/ |
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 |
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 | |
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 |
|
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 |
|
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 |
|
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 |
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 |
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 |
|
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 |
|
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 |
|
1965 | DIE_WITH_EXITCODE (1, "device entry \"%s\" malformed (no 'dev:rdev' pair)", stored_pathname); |
1695 | exit (1); |
- | |
1696 | } |
- | |
1697 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 (); |
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
2372 | // if (read_filecontents (kernelfile_pathname, ".", &entry_parms.data) == NULL) |
2117 | { |
- | |
2118 |
|
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 |
|
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 |
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 | |
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 | |
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
2749 | LOG_INFO ("Current offset: 0x%zx", curr_offset); |
2511 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 *) ¤t_fsentry->u.device.path); // convert from pointer to char array |
3178 | printf (" [DEVICE] path = \"%s\"\n", (char *) ¤t_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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |