Rev 33 | Rev 35 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 33 | Rev 34 | ||
---|---|---|---|
Line 49... | Line 49... | ||
49 | const char *__asan_default_options () { return ("detect_leaks=0"); } |
49 | const char *__asan_default_options () { return ("detect_leaks=0"); } |
50 | 50 | ||
51 | 51 | ||
52 | // placeholder value |
52 | // placeholder value |
53 | #define WILL_BE_FILLED_LATER 0xbaadf00d // urgh |
53 | #define WILL_BE_FILLED_LATER 0xbaadf00d // urgh |
- | 54 | ||
- | 55 | ||
- | 56 | // boot type values |
|
- | 57 | #define BOOTTYPE_NONE 0 |
|
- | 58 | #define BOOTTYPE_BIOS 1 |
|
- | 59 | #define BOOTTYPE_UEFI 2 |
|
54 | 60 | ||
55 | 61 | ||
56 | // miscellaneous macros |
62 | // miscellaneous macros |
57 | #define ROUND_TO_UPPER_MULTIPLE(val,multiple) ((((val) + (size_t) (multiple) - 1) / (multiple)) * (multiple)) // note that val is being evaluated once, so it can be the result of a function call |
63 | #define ROUND_TO_UPPER_MULTIPLE(val,multiple) ((((val) + (size_t) (multiple) - 1) / (multiple)) * (multiple)) // note that val is being evaluated once, so it can be the result of a function call |
58 | #ifdef _WIN32 |
64 | #ifdef _WIN32 |
Line 154... | Line 160... | ||
154 | static char **saved_ELF_sections = NULL; // mallocated array of const strings, populated by the -s command-line argument |
160 | static char **saved_ELF_sections = NULL; // mallocated array of const strings, populated by the -s command-line argument |
155 | static size_t saved_ELF_section_count = 0; // number of elements in the saved_ELF_sections array |
161 | static size_t saved_ELF_section_count = 0; // number of elements in the saved_ELF_sections array |
156 | static char *sym_suffix = ""; // .sym files extra suffix, settable with the -a command-line argument |
162 | static char *sym_suffix = ""; // .sym files extra suffix, settable with the -a command-line argument |
157 | 163 | ||
158 | // bootable IFS support |
164 | // bootable IFS support |
- | 165 | static int boot_type = BOOTTYPE_NONE; |
|
159 | static char *bootfile_pathname = NULL; // FIXME: HACK: pathname to bootcode binary blob file to put at the start of a bootable IFS |
166 | static char *bootfile_pathname = NULL; // FIXME: HACK: pathname to bootcode binary blob file to put at the start of a bootable IFS in BIOS mode |
160 | static size_t bootfile_size = 0; // FIXME: HACK: size of the bootcode binary blob file to put at the start of a bootable IFS |
167 | static size_t bootfile_size = 0; // FIXME: HACK: size of the bootcode binary blob file to put at the start of a bootable IFS in BIOS mode |
161 | static char *startupfile_pathname = NULL; // FIXME: HACK: pathname to precompiled startup file blob to put in the startup header of a bootable IFS |
168 | static char *startupfile_pathname = NULL; // FIXME: HACK: pathname to precompiled startup file blob to put in the startup header of a bootable IFS |
162 | static size_t startupfile_ep_from_imagebase = 0; // FIXME: HACK: startup code entrypoint offset from image base for a bootable IFS |
169 | static size_t startupfile_ep_from_imagebase = 0; // FIXME: HACK: startup code entrypoint offset from image base for a bootable IFS |
163 | static size_t kernelfile_offset = 0; // kernel file offset in the IFS (first offset rounded at pagesize after the dirents table) |
170 | static size_t kernelfile_offset = 0; // kernel file offset in the IFS (first offset rounded at pagesize after the dirents table) |
164 | 171 | ||
165 | 172 | ||
166 | // exported function prototypes |
173 | // exported function prototypes |
167 | int32_t update_checksum (const void *data, const size_t data_len, const bool is_foreign_endianness); // compute an IFS image or startup checksum to store in the trailer |
174 | int32_t update_checksum (const void *data, const size_t data_len, const bool is_foreign_endianness); // compute an IFS image or startup checksum to store in the trailer |
168 | 175 | ||
169 | 176 | ||
170 | // prototypes of local functions |
177 | // prototypes of local functions |
171 | static long long read_integer (const char *str); // reads an integer number for a string that may be specified in either hex, octal or decimal base, and may have an optional unit suffix (k, m, g, t) |
178 | static long long read_integer (const char *str, const int base_or_zero_for_auto); // reads an integer number for a string that may be specified in either hex, octal or decimal base, and may have an optional unit suffix (k, m, g, t) |
172 | static char *resolve_envvars (const char *str); // resolves environment variables in str and replaces them with their value, or an empty string if undefined. Returns a mallocated string (caller frees) |
179 | static char *resolve_envvars (const char *str); // resolves environment variables in str and replaces them with their value, or an empty string if undefined. Returns a mallocated string (caller frees) |
173 | static char *resolve_pathname (const char *pathname, const char *search_paths_or_NULL_for_MKIFS_PATH_envvar); // locates pathname among the known search paths and returns a pointer to the resolved pathname (static string) |
180 | static char *resolve_pathname (const char *pathname, const char *search_paths_or_NULL_for_MKIFS_PATH_envvar); // locates pathname among the known search paths and returns a pointer to the resolved pathname (static string) |
174 | static elf_section_header_t *elf_get_section_header_by_name (const elf_header_t *elf, const char *section_name); // get a pointer to a named section header in an ELF file |
181 | static elf_section_header_t *elf_get_section_header_by_name (const elf_header_t *elf, const char *section_name); // get a pointer to a named section header in an ELF file |
175 | static size_t Buffer_WriteIFSDirectoryEntryAt (buffer_t *ifs_data, const size_t write_offset, const fsentry_t *fsentry); // writes the given filesystem entry (without its contents) to the IFS buffer |
182 | static size_t Buffer_WriteIFSDirectoryEntryAt (buffer_t *ifs_data, const size_t write_offset, const fsentry_t *fsentry); // writes the given filesystem entry (without its contents) to the IFS buffer |
176 | static size_t Buffer_AppendIFSFileData (buffer_t *ifs_data, const fsentry_t *fsentry); // writes the given filesystem entry's file data (i.e. its contents) to the IFS buffer |
183 | static size_t Buffer_AppendIFSFileData (buffer_t *ifs_data, const fsentry_t *fsentry); // writes the given filesystem entry's file data (i.e. its contents) to the IFS buffer |
Line 211... | Line 218... | ||
211 | 218 | ||
212 | return (is_foreign_endianness ? __builtin_bswap32 (-image_cksum) : -image_cksum); |
219 | return (is_foreign_endianness ? __builtin_bswap32 (-image_cksum) : -image_cksum); |
213 | } |
220 | } |
214 | 221 | ||
215 | 222 | ||
216 | static long long read_integer (const char *str) |
223 | static long long read_integer (const char *str, const int base_or_zero_for_auto) |
217 | { |
224 | { |
218 | // reads a number for a string that may be specified in either hex, octal or decimal base, and may have an optional unit suffix (k, m, g, t) |
225 | // reads a number for a string that may be specified in either hex, octal or decimal base, and may have an optional unit suffix (k, m, g, t) |
219 | 226 | ||
220 | char *endptr = NULL; |
227 | char *endptr = NULL; |
221 | long long ret = strtoll (str, &endptr, |
228 | long long ret = strtoll (str, &endptr, base_or_zero_for_auto); // use strtoll() to handle hexadecimal (0x...), octal (0...) and decimal (...) bases |
222 | if (endptr != NULL) |
229 | if (endptr != NULL) |
223 | { |
230 | { |
224 | if ((*endptr == 'k') || (*endptr == 'K')) ret *= (size_t) 1024; |
231 | if ((*endptr == 'k') || (*endptr == 'K')) ret *= (size_t) 1024; |
225 | else if ((*endptr == 'm') || (*endptr == 'M')) ret *= (size_t) 1024 * 1024; |
232 | else if ((*endptr == 'm') || (*endptr == 'M')) ret *= (size_t) 1024 * 1024; |
226 | else if ((*endptr == 'g') || (*endptr == 'G')) ret *= (size_t) 1024 * 1024 * 1024; |
233 | else if ((*endptr == 'g') || (*endptr == 'G')) ret *= (size_t) 1024 * 1024 * 1024; |
Line 270... | Line 277... | ||
270 | endbit_len = strlen (endbit); // measure the length of the end bit (skip the closing curly brace) |
277 | endbit_len = strlen (endbit); // measure the length of the end bit (skip the closing curly brace) |
271 | erased_char = endbit[erase_index]; // remember which is the character we're going to erase |
278 | erased_char = endbit[erase_index]; // remember which is the character we're going to erase |
272 | endbit[erase_index] = 0; // split the string at the end of the variable name |
279 | endbit[erase_index] = 0; // split the string at the end of the variable name |
273 | if (strcmp (varname, "PFS") == 0) |
280 | if (strcmp (varname, "PFS") == 0) |
274 | replacement = PATH_SEP; // special case: if it's the PFS variable, select ":" or ";" based on the host platform |
281 | replacement = PATH_SEP; // special case: if it's the PFS variable, select ":" or ";" based on the host platform |
- | 282 | else if (strcmp (varname, "PROCESSOR") == 0) |
|
- | 283 | replacement = image_processor; // special case: if it's PROCESSOR, replace it with the processor name (e.g. "aarch64le") |
|
- | 284 | else if (strcmp (varname, "PROCESSOR_BASE") == 0) |
|
- | 285 | replacement = image_processor_base; // special case: if it's PROCESSOR_BASE, replace it with the processor base name (e.g. "aarch64") |
|
275 | else |
286 | else |
276 | replacement = getenv (varname); // peek at the environment for its value |
287 | replacement = getenv (varname); // peek at the environment for its value |
277 | if (replacement == NULL) |
288 | if (replacement == NULL) |
278 | replacement = ""; // if this variable isn't defined, fallback to an empty string, just like what a UNIX shell does |
289 | replacement = ""; // if this variable isn't defined, fallback to an empty string, just like what a UNIX shell does |
279 | endbit[erase_index] = erased_char; // put the erased character back |
290 | endbit[erase_index] = erased_char; // put the erased character back |
Line 525... | Line 536... | ||
525 | 536 | ||
526 | // is the file we're storing a preprocessed ELF file ? |
537 | // is the file we're storing a preprocessed ELF file ? |
527 | if (fsentry->header.ino & IFS_INO_PROCESSED_ELF) |
538 | if (fsentry->header.ino & IFS_INO_PROCESSED_ELF) |
528 | { |
539 | { |
529 | 540 | ||
530 | elf = (elf_header_t *) fsentry-> |
541 | elf = (elf_header_t *) fsentry->UNSAVED_databuf; // quick access to ELF header |
531 | table_count = ELF_GET_NUMERIC (elf, elf, program_header_table_len); // get the number of program headers |
542 | table_count = ELF_GET_NUMERIC (elf, elf, program_header_table_len); // get the number of program headers |
532 | for (table_index = 0; table_index < table_count; table_index++) |
543 | for (table_index = 0; table_index < table_count; table_index++) |
533 | { |
544 | { |
534 | phdr = (elf_program_header_t *) &fsentry-> |
545 | phdr = (elf_program_header_t *) &fsentry->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 |
535 | //segment_type = ELF_GET_NUMERIC (elf, phdr, segment_type); // get segment type |
546 | //segment_type = ELF_GET_NUMERIC (elf, phdr, segment_type); // get segment type |
536 | //if (!((segment_type >= 2) && (segment_type <= 7) || ((segment_type >= 0x6474e550) && (segment_type <= 0x6474e552)) || (segment_type == 0x70000001))) |
547 | //if (!((segment_type >= 2) && (segment_type <= 7) || ((segment_type >= 0x6474e550) && (segment_type <= 0x6474e552)) || (segment_type == 0x70000001))) |
537 | // continue; // NOTE: only certain segments types must be corrected |
548 | // continue; // NOTE: only certain segments types must be corrected |
538 | 549 | ||
539 | 550 | ||
Line 545... | Line 556... | ||
545 | ELF_SET_NUMERIC (elf, phdr, physical_addr, fixed_physical_addr); // patch the physical address member of the program header table (NOTE: data_offset is the location where the file data is about to be written) |
556 | ELF_SET_NUMERIC (elf, phdr, physical_addr, fixed_physical_addr); // patch the physical address member of the program header table (NOTE: data_offset is the location where the file data is about to be written) |
546 | } |
557 | } |
547 | } |
558 | } |
548 | } |
559 | } |
549 | 560 | ||
550 | ASSERT_WITH_ERRNO (Buffer_Append (ifs_data, fsentry-> |
561 | ASSERT_WITH_ERRNO (Buffer_Append (ifs_data, fsentry->UNSAVED_databuf, fsentry->u.file.size)); // write file data blob |
551 | return (ifs_data->size - data_offset); // return the number of bytes written |
562 | return (ifs_data->size - data_offset); // return the number of bytes written |
552 | } |
563 | } |
553 | 564 | ||
554 | 565 | ||
555 | static inline size_t Buffer_LocateOrAppendIfNecessaryAndReturnOffsetOf (buffer_t *buffer, const char *str) |
566 | static inline size_t Buffer_LocateOrAppendIfNecessaryAndReturnOffsetOf (buffer_t *buffer, const char *str) |
Line 800... | Line 811... | ||
800 | stringarray_t procnto_argv = { NULL, 0 }; |
811 | stringarray_t procnto_argv = { NULL, 0 }; |
801 | stringarray_t procnto_envp = { NULL, 0 }; |
812 | stringarray_t procnto_envp = { NULL, 0 }; |
802 | stringarray_t linker_argv = { NULL, 0 }; |
813 | stringarray_t linker_argv = { NULL, 0 }; |
803 | const char *stored_pathname_without_leading_slash; |
814 | const char *stored_pathname_without_leading_slash; |
804 | const char *original_stored_pathname = NULL; |
815 | const char *original_stored_pathname = NULL; |
- | 816 | const char *filename_bit; |
|
805 | buffer_t current_line; |
817 | buffer_t current_line; |
806 | buffer_t compiled_script; |
818 | buffer_t compiled_script; |
807 | buffer_t compiled_scriptline; |
819 | buffer_t compiled_scriptline; |
808 | buffer_t *shstrtab = NULL; |
820 | buffer_t *shstrtab = NULL; |
809 | const char *canonical_dylib_name; |
821 | const char *canonical_dylib_name; |
810 | const char *dynamic_strings; // strings table of the ".dynamic" section |
822 | const char *dynamic_strings; // strings table of the ".dynamic" section |
811 | const char *last_dirsep; |
823 | const char *last_dirsep; |
812 | size_t array_index; |
824 | size_t array_index; |
813 | size_t line_index; |
825 | size_t line_index; |
814 | size_t fsentry_index; |
826 | size_t fsentry_index; |
- | 827 | size_t pathbit_len; |
|
815 | size_t wait_time; |
828 | size_t wait_time; |
816 | char *resolved_pathname; |
829 | char *resolved_pathname; |
817 | char *linebit_start; |
830 | char *linebit_start; |
818 | char *write_ptr; |
831 | char *write_ptr; |
819 | char *read_ptr; |
832 | char *read_ptr; |
Line 920... | Line 933... | ||
920 | while (token != NULL) |
933 | while (token != NULL) |
921 | { |
934 | { |
922 | #define REACH_TOKEN_VALUE() do { value = strchr (token, '=') + 1; if (*value == '"') value++; } while (0) |
935 | #define REACH_TOKEN_VALUE() do { value = strchr (token, '=') + 1; if (*value == '"') value++; } while (0) |
923 | if (false) {} |
936 | if (false) {} |
924 | else if (strncmp (token, "prefix=", 7) == 0) { REACH_TOKEN_VALUE (); entry_parms->prefix = (*value == '/' ? value + 1 : value); } // skip possible leading slash in prefix (NOTE: stolen pointer. Do not free.) |
937 | else if (strncmp (token, "prefix=", 7) == 0) { REACH_TOKEN_VALUE (); entry_parms->prefix = (*value == '/' ? value + 1 : value); } // skip possible leading slash in prefix (NOTE: stolen pointer. Do not free.) |
925 | else if (strncmp (token, "uid=", 4) == 0) { REACH_TOKEN_VALUE (); entry_parms->uid = (int) read_integer (value); } |
938 | else if (strncmp (token, "uid=", 4) == 0) { REACH_TOKEN_VALUE (); entry_parms->uid = (int) read_integer (value, 10); } |
926 | else if (strncmp (token, "gid=", 4) == 0) { REACH_TOKEN_VALUE (); entry_parms->gid = (int) read_integer (value); } |
939 | else if (strncmp (token, "gid=", 4) == 0) { REACH_TOKEN_VALUE (); entry_parms->gid = (int) read_integer (value, 10); } |
927 | else if (strncmp (token, "perms=", 6) == 0) { REACH_TOKEN_VALUE (); entry_parms->perms = (int) read_integer (value); } |
940 | else if (strncmp (token, "perms=", 6) == 0) { REACH_TOKEN_VALUE (); entry_parms->perms = (int) read_integer (value, 8); } |
928 | else if (strcmp (token, "+followlink") == 0) entry_parms->should_follow_symlinks = true; |
941 | else if (strcmp (token, "+followlink") == 0) entry_parms->should_follow_symlinks = true; |
929 | else if (strcmp (token, "-followlink") == 0) entry_parms->should_follow_symlinks = false; |
942 | else if (strcmp (token, "-followlink") == 0) entry_parms->should_follow_symlinks = false; |
930 | else if (strcmp (token, "+keeplinked") == 0) entry_parms->should_keep_ld_output = true; |
943 | else if (strcmp (token, "+keeplinked") == 0) entry_parms->should_keep_ld_output = true; |
931 | else if (strcmp (token, "-keeplinked") == 0) entry_parms->should_keep_ld_output = false; |
944 | else if (strcmp (token, "-keeplinked") == 0) entry_parms->should_keep_ld_output = false; |
932 | else LOG_WARNING ("unimplemented bootstrap executable attribute in \"%s\" line %zd of inline document '%s': '%s'", buildfile_pathname, 1 + line_index, stored_pathname, token); |
945 | else LOG_WARNING ("unimplemented bootstrap executable attribute in \"%s\" line %zd of inline document '%s': '%s'", buildfile_pathname, 1 + line_index, stored_pathname, token); |
Line 1064... | Line 1077... | ||
1064 | STRINGARRAY_INIT (&linker_argv); |
1077 | STRINGARRAY_INIT (&linker_argv); |
1065 | STRINGARRAY_PUSH (&linker_argv, strrchr (linker_pathname, '/') + 1); // "${TARGET_TRIPLE}-ld" |
1078 | STRINGARRAY_PUSH (&linker_argv, strrchr (linker_pathname, '/') + 1); // "${TARGET_TRIPLE}-ld" |
1066 | STRINGARRAY_PUSH (&linker_argv, linker_sysroot_arg); // "--sysroot=${QNX_TARGET}/${TARGET_CPU}/" |
1079 | STRINGARRAY_PUSH (&linker_argv, linker_sysroot_arg); // "--sysroot=${QNX_TARGET}/${TARGET_CPU}/" |
1067 | STRINGARRAY_PUSH (&linker_argv, linker_script_pathname_arg); // "-T${QNX_TARGET}/${TARGET_CPU}/lib/nto.link" |
1080 | STRINGARRAY_PUSH (&linker_argv, linker_script_pathname_arg); // "-T${QNX_TARGET}/${TARGET_CPU}/lib/nto.link" |
1068 | STRINGARRAY_PUSH (&linker_argv, "--section-start"); |
1081 | STRINGARRAY_PUSH (&linker_argv, "--section-start"); |
1069 | STRINGARRAY_PUSH (&linker_argv, ".text=0xffff800000001000"); |
1082 | STRINGARRAY_PUSH (&linker_argv, (boot_type == BOOTTYPE_UEFI ? ".text=0xffff800000002000" : ".text=0xffff800000001000")); // FIXME: wild assumption! |
1070 | STRINGARRAY_PUSH (&linker_argv, "--no-relax"); |
1083 | STRINGARRAY_PUSH (&linker_argv, "--no-relax"); |
1071 | STRINGARRAY_PUSH (&linker_argv, procnto_buildhost_pathname); // "${QNX_TARGET}/${TARGET_CPU}/boot/sys/procnto-smp-instr" |
1084 | STRINGARRAY_PUSH (&linker_argv, procnto_buildhost_pathname); // "${QNX_TARGET}/${TARGET_CPU}/boot/sys/procnto-smp-instr" |
1072 | STRINGARRAY_PUSH (&linker_argv, "-o"); |
1085 | STRINGARRAY_PUSH (&linker_argv, "-o"); |
1073 | STRINGARRAY_PUSH (&linker_argv, procnto_sym_filename); // "procnto-smp-instr.sym" |
1086 | STRINGARRAY_PUSH (&linker_argv, procnto_sym_filename); // "procnto-smp-instr.sym" |
1074 | #ifdef __GNUC__ |
1087 | #ifdef __GNUC__ |
Line 1349... | Line 1362... | ||
1349 | ASSERT_WITH_ERRNO (Buffer_WriteInt8At (&compiled_scriptline, 8, (current_scriptcmd_params.sched_policy != -1 ? current_scriptcmd_params.sched_policy : 0))); // scheduling policy |
1362 | ASSERT_WITH_ERRNO (Buffer_WriteInt8At (&compiled_scriptline, 8, (current_scriptcmd_params.sched_policy != -1 ? current_scriptcmd_params.sched_policy : 0))); // scheduling policy |
1350 | ASSERT_WITH_ERRNO (Buffer_WriteInt8At (&compiled_scriptline, 9, (current_scriptcmd_params.priority != -1 ? current_scriptcmd_params.priority : 0))); // scheduling priority |
1363 | ASSERT_WITH_ERRNO (Buffer_WriteInt8At (&compiled_scriptline, 9, (current_scriptcmd_params.priority != -1 ? current_scriptcmd_params.priority : 0))); // scheduling priority |
1351 | ASSERT_WITH_ERRNO (Buffer_WriteInt8At (&compiled_scriptline, 10, (uint8_t) line_argv.count)); // argc |
1364 | ASSERT_WITH_ERRNO (Buffer_WriteInt8At (&compiled_scriptline, 10, (uint8_t) line_argv.count)); // argc |
1352 | ASSERT_WITH_ERRNO (Buffer_WriteInt8At (&compiled_scriptline, 11, (uint8_t) global_envp.count)); // envc |
1365 | ASSERT_WITH_ERRNO (Buffer_WriteInt8At (&compiled_scriptline, 11, (uint8_t) global_envp.count)); // envc |
1353 | ASSERT_WITH_ERRNO (Buffer_Append (&compiled_scriptline, line_argv.args[0], strlen (line_argv.args[0]) + 1)); // executable |
1366 | ASSERT_WITH_ERRNO (Buffer_Append (&compiled_scriptline, line_argv.args[0], strlen (line_argv.args[0]) + 1)); // executable |
- | 1367 | if (current_scriptcmd_params.argv0 != NULL) |
|
1354 | ASSERT_WITH_ERRNO (Buffer_Append (&compiled_scriptline, |
1368 | ASSERT_WITH_ERRNO (Buffer_Append (&compiled_scriptline, current_scriptcmd_params.argv0, strlen (current_scriptcmd_params.argv0) + 1)); // argv[0] -- explicit value from attribute |
- | 1369 | else |
|
- | 1370 | { |
|
- | 1371 | filename_bit = strrchr (line_argv.args[0], '/'); // argv[0] has an implicit value: look where the filename starts |
|
- | 1372 | filename_bit = (filename_bit != NULL ? filename_bit + 1 : line_argv.args[0]); |
|
- | 1373 | ASSERT_WITH_ERRNO (Buffer_Append (&compiled_scriptline, filename_bit, strlen (filename_bit) + 1)); // argv[0] -- store just the filename |
|
- | 1374 | } |
|
1355 | for (array_index = 1; array_index < line_argv.count; array_index++) |
1375 | for (array_index = 1; array_index < line_argv.count; array_index++) |
1356 | ASSERT_WITH_ERRNO (Buffer_Append (&compiled_scriptline, line_argv.args[array_index], strlen (line_argv.args[array_index]) + 1)); // argv[n] |
1376 | ASSERT_WITH_ERRNO (Buffer_Append (&compiled_scriptline, line_argv.args[array_index], strlen (line_argv.args[array_index]) + 1)); // argv[n] |
1357 | for (array_index = 0; array_index < global_envp.count; array_index++) |
1377 | for (array_index = 0; array_index < global_envp.count; array_index++) |
1358 | ASSERT_WITH_ERRNO (Buffer_Append (&compiled_scriptline, global_envp.args[array_index], strlen (global_envp.args[array_index]) + 1)); // envp[n] |
1378 | ASSERT_WITH_ERRNO (Buffer_Append (&compiled_scriptline, global_envp.args[array_index], strlen (global_envp.args[array_index]) + 1)); // envp[n] |
1359 | } |
1379 | } |
Line 1426... | Line 1446... | ||
1426 | if (!Buffer_ReadFromFile (&entry_parms->data, resolved_pathname)) |
1446 | if (!Buffer_ReadFromFile (&entry_parms->data, resolved_pathname)) |
1427 | DIE_WITH_EXITCODE (1, "filesystem entry \"%s\" specified in \"%s\" line %d can't be read from \"%s\": %s", buildhost_pathname, buildfile_pathname, lineno, resolved_pathname, strerror (errno)); |
1447 | DIE_WITH_EXITCODE (1, "filesystem entry \"%s\" specified in \"%s\" line %d can't be read from \"%s\": %s", buildhost_pathname, buildfile_pathname, lineno, resolved_pathname, strerror (errno)); |
1428 | stat (resolved_pathname, &stat_buf); // can't fail, since we could read it |
1448 | stat (resolved_pathname, &stat_buf); // can't fail, since we could read it |
1429 | if (entry_parms->mtime == UINT32_MAX) |
1449 | if (entry_parms->mtime == UINT32_MAX) |
1430 | entry_parms->mtime = (uint32_t) stat_buf.st_mtime; |
1450 | entry_parms->mtime = (uint32_t) stat_buf.st_mtime; |
- | 1451 | if ((entry_parms->data.size > 52) && (memcmp (entry_parms->data.bytes, ELF_MAGIC_STR, 4) == 0)) |
|
- | 1452 | entry_parms->st_mode |= 0111; // add +x permissions to ELF entries (undocumented mkifs behaviour) |
|
1431 | LOG_INFO ("file: ino 0x%x uid %d gid %d mode 0%o path \"%s\" buildhost_file \"%s\" (len %zd)", inode_count + 1, entry_parms->uid, entry_parms->gid, entry_parms->st_mode, stored_pathname, buildhost_pathname, entry_parms->data.size); |
1453 | LOG_INFO ("file: ino 0x%x uid %d gid %d mode 0%o path \"%s\" buildhost_file \"%s\" (len %zd)", inode_count + 1, entry_parms->uid, entry_parms->gid, entry_parms->st_mode, stored_pathname, buildhost_pathname, entry_parms->data.size); |
1432 | } |
1454 | } |
1433 | else |
1455 | else |
1434 | DIE_WITH_EXITCODE (1, "unexpected code path: can't store a file without neither explicit contents nor a host pathname. This is a bug in the program. Please contact the author."); |
1456 | DIE_WITH_EXITCODE (1, "unexpected code path: can't store a file without neither explicit contents nor a host pathname. This is a bug in the program. Please contact the author."); |
1435 | 1457 | ||
Line 1459... | Line 1481... | ||
1459 | { |
1481 | { |
1460 | canonical_dylib_name = dynamic_strings + ELF_GET_NUMERIC (ELFHDR, dynamic_entry, value); |
1482 | canonical_dylib_name = dynamic_strings + ELF_GET_NUMERIC (ELFHDR, dynamic_entry, value); |
1461 | break; |
1483 | break; |
1462 | } |
1484 | } |
1463 | 1485 | ||
- | 1486 | // do we have the canonical dylib name AND does it differ from the name under which we'll be storing this dylib ? |
|
1464 |
|
1487 | filename_bit = strrchr (stored_pathname, '/'); |
1465 | if ( |
1488 | if (filename_bit != NULL) |
1466 | { |
1489 | { |
- | 1490 | filename_bit++; |
|
- | 1491 | pathbit_len = filename_bit - stored_pathname; |
|
- | 1492 | } |
|
- | 1493 | else |
|
- | 1494 | { |
|
- | 1495 | filename_bit = stored_pathname; |
|
- | 1496 | pathbit_len = 0; |
|
- | 1497 | } |
|
1467 |
|
1498 | if ((canonical_dylib_name != NULL) && (canonical_dylib_name[0] != 0) && (strcmp (canonical_dylib_name, filename_bit) != 0)) |
- | 1499 | { |
|
1468 |
|
1500 | original_stored_pathname = stored_pathname; // if so, remember to create a symlink here |
- | 1501 | if (pathbit_len > 0) |
|
1469 | { |
1502 | { |
1470 |
|
1503 | strncpy_s (candidate_pathname, MAXPATHLEN, stored_pathname, pathbit_len); |
1471 |
|
1504 | strcpy_s (&candidate_pathname[pathbit_len], MAXPATHLEN - pathbit_len, canonical_dylib_name); |
1472 | } |
1505 | } |
- | 1506 | else |
|
- | 1507 | strcpy_s (candidate_pathname, MAXPATHLEN, canonical_dylib_name); |
|
- | 1508 | stored_pathname = candidate_pathname; |
|
1473 | } |
1509 | } |
1474 | } |
1510 | } |
1475 | } // end if the file we're storing is a dylib |
1511 | } // end if the file we're storing is a dylib |
1476 | 1512 | ||
1477 | // now strip this ELF file if necessary |
1513 | // now strip this ELF file if necessary |
Line 1499... | Line 1535... | ||
1499 | } |
1535 | } |
1500 | 1536 | ||
1501 | // is there already an entry for this item ? |
1537 | // is there already an entry for this item ? |
1502 | if (fsentry_index < *fsentry_count) |
1538 | if (fsentry_index < *fsentry_count) |
1503 | { |
1539 | { |
1504 | // if we should NOT ignore duplicates, bomb |
1540 | // if we should NOT ignore duplicates, bomb out (except for the root entry which is implicitly defined), else just return |
- | 1541 | if (strcmp (stored_pathname, "/") == 0) |
|
- | 1542 | return; // the root entry is implicitly defined: do not warn about it |
|
1505 | if ( |
1543 | else if (entry_parms->should_ignore_duplicates) |
- | 1544 | LOG_WARNING ("duplicate detected: entry \"%s\" specified in \"%s\" line %d already exists in build file (already defined line %d)", stored_pathname, buildfile_pathname, lineno, (*fsentries)[fsentry_index].UNSAVED_lineno); |
|
- | 1545 | else |
|
1506 | DIE_WITH_EXITCODE (1, "duplicate detected: entry \"%s\" specified in \"%s\" line %d already exists in |
1546 | DIE_WITH_EXITCODE (1, "duplicate detected: entry \"%s\" specified in \"%s\" line %d already exists in build file (already defined line %d)", stored_pathname, buildfile_pathname, lineno, (*fsentries)[fsentry_index].UNSAVED_lineno); |
1507 | } |
1547 | } |
1508 | else // this is a new entry: grow filesystem entries array to hold one more slot |
1548 | else // this is a new entry: grow filesystem entries array to hold one more slot |
1509 | { |
1549 | { |
1510 | reallocated_ptr = realloc (*fsentries, (*fsentry_count + 1) * sizeof (fsentry_t)); // attempt to reallocate |
1550 | reallocated_ptr = realloc (*fsentries, (*fsentry_count + 1) * sizeof (fsentry_t)); // attempt to reallocate |
1511 | ASSERT_WITH_ERRNO (reallocated_ptr); // verify |
1551 | ASSERT_WITH_ERRNO (reallocated_ptr); // verify |
Line 1531... | Line 1571... | ||
1531 | else if (S_ISREG (entry_parms->st_mode)) |
1571 | else if (S_ISREG (entry_parms->st_mode)) |
1532 | { |
1572 | { |
1533 | fsentry->u.file.offset = WILL_BE_FILLED_LATER; // will be filled later in main() when the file's data blob will be written to the output file |
1573 | fsentry->u.file.offset = WILL_BE_FILLED_LATER; // will be filled later in main() when the file's data blob will be written to the output file |
1534 | fsentry->u.file.size = (uint32_t) entry_parms->data.size; |
1574 | fsentry->u.file.size = (uint32_t) entry_parms->data.size; |
1535 | fsentry->u.file.path = strdup (stored_pathname_without_leading_slash); |
1575 | fsentry->u.file.path = strdup (stored_pathname_without_leading_slash); |
1536 | fsentry->u.file.UNSAVED_databuf = malloc (entry_parms->data.size); |
- | |
1537 | ASSERT_WITH_ERRNO (fsentry->u.file.UNSAVED_databuf); |
- | |
1538 | memcpy (fsentry->u.file.UNSAVED_databuf, entry_parms->data.bytes, entry_parms->data.size); |
- | |
1539 | 1576 | ||
1540 | fsentry->header.size = (uint16_t) ROUND_TO_UPPER_MULTIPLE (sizeof (fsentry->header) + sizeof (uint32_t) + sizeof (uint32_t) + strlen (fsentry->u.file.path) + 1, image_align); // now we can set the size |
1577 | fsentry->header.size = (uint16_t) ROUND_TO_UPPER_MULTIPLE (sizeof (fsentry->header) + sizeof (uint32_t) + sizeof (uint32_t) + strlen (fsentry->u.file.path) + 1, image_align); // now we can set the size |
- | 1578 | fsentry->UNSAVED_databuf = malloc (entry_parms->data.size); |
|
- | 1579 | ASSERT_WITH_ERRNO (fsentry->UNSAVED_databuf); |
|
- | 1580 | memcpy (fsentry->UNSAVED_databuf, entry_parms->data.bytes, entry_parms->data.size); |
|
1541 | fsentry->UNSAVED_was_data_written = false; // there *IS* data to save |
1581 | fsentry->UNSAVED_was_data_written = false; // there *IS* data to save |
1542 | } |
1582 | } |
1543 | else if (S_ISLNK (entry_parms->st_mode)) |
1583 | else if (S_ISLNK (entry_parms->st_mode)) |
1544 | { |
1584 | { |
1545 | fsentry->u.symlink.sym_offset = (uint16_t) (strlen (stored_pathname_without_leading_slash) + 1); |
1585 | fsentry->u.symlink.sym_offset = (uint16_t) (strlen (stored_pathname_without_leading_slash) + 1); |
Line 1558... | Line 1598... | ||
1558 | fsentry->u.device.path = strdup (stored_pathname_without_leading_slash); |
1598 | fsentry->u.device.path = strdup (stored_pathname_without_leading_slash); |
1559 | 1599 | ||
1560 | fsentry->header.size = (uint16_t) ROUND_TO_UPPER_MULTIPLE (sizeof (fsentry->header) + sizeof (uint32_t) + sizeof (uint32_t) + strlen (fsentry->u.device.path), image_align); // now we can set the size |
1600 | fsentry->header.size = (uint16_t) ROUND_TO_UPPER_MULTIPLE (sizeof (fsentry->header) + sizeof (uint32_t) + sizeof (uint32_t) + strlen (fsentry->u.device.path), image_align); // now we can set the size |
1561 | fsentry->UNSAVED_was_data_written = true; // no data to save |
1601 | fsentry->UNSAVED_was_data_written = true; // no data to save |
1562 | } |
1602 | } |
- | 1603 | ||
- | 1604 | fsentry->UNSAVED_lineno = lineno; // save the line number at which this entry was defined, for error reporting |
|
1563 | 1605 | ||
1564 | // should we also add a symlink to this entry ? (in case we stored a dylib file under its canonical name) |
1606 | // should we also add a symlink to this entry ? (in case we stored a dylib file under its canonical name) |
1565 | if (original_stored_pathname != NULL) |
1607 | if (original_stored_pathname != NULL) |
1566 | { |
1608 | { |
- | 1609 | old_data = entry_parms->data.bytes; // backup previous data pointer |
|
1567 | entry_parms->is_compiled_bootscript = false; |
1610 | entry_parms->is_compiled_bootscript = false; |
1568 | entry_parms->should_autosymlink_dylib = false; |
1611 | entry_parms->should_autosymlink_dylib = false; |
1569 | entry_parms->should_follow_symlinks = false; |
1612 | entry_parms->should_follow_symlinks = false; |
1570 | entry_parms->st_mode = S_IFLNK | 0777; // NOTE: mkifs stores symlink permissions as rwxrwxrwx ! |
1613 | entry_parms->st_mode = S_IFLNK | 0777; // NOTE: mkifs stores symlink permissions as rwxrwxrwx ! |
1571 | entry_parms->extra_ino_flags = (fsentry->header.ino & (IFS_INO_PROCESSED_ELF | IFS_INO_RUNONCE_ELF | IFS_INO_BOOTSTRAP_EXE)); // preserve target's inode flags |
1614 | entry_parms->extra_ino_flags = (fsentry->header.ino & (IFS_INO_PROCESSED_ELF | IFS_INO_RUNONCE_ELF | IFS_INO_BOOTSTRAP_EXE)); // preserve target's inode flags |
1572 | last_dirsep = strrchr (stored_pathname, '/'); |
- | |
1573 | old_data = entry_parms->data.bytes; // backup previous data pointer |
- | |
1574 | entry_parms->data.bytes = (uint8_t *) (last_dirsep == NULL ? stored_pathname : last_dirsep + 1); // store symlink target in dirent data |
1615 | entry_parms->data.bytes = (uint8_t *) ((last_dirsep = strrchr (stored_pathname, '/')) == NULL ? stored_pathname : last_dirsep + 1); // store symlink target in dirent data |
1575 | entry_parms->data.size = strlen (entry_parms->data.bytes); |
1616 | entry_parms->data.size = strlen (entry_parms->data.bytes); |
1576 | add_fsentry (fsentries, fsentry_count, entry_parms, original_stored_pathname, NULL); |
1617 | add_fsentry (fsentries, fsentry_count, entry_parms, original_stored_pathname, NULL); |
1577 | entry_parms->data.bytes = old_data; // restore previous data pointer so that it can be freed normally |
1618 | entry_parms->data.bytes = old_data; // restore previous data pointer so that it can be freed normally |
1578 | } |
1619 | } |
- | 1620 | ||
- | 1621 | #if 0 // DISABLED: not the right place to do that (causes duplicates) |
|
- | 1622 | // WEIRD HACK: if we stored a dylib under the form "xxxxx.so.yyyy", then add a symlink as "xxxxx.so". This is to replicate a weird (undocumented?) behaviour of mkifs. |
|
- | 1623 | if ((canonical_dylib_name != NULL) && ((token = strstr (stored_pathname, ".so.")) != NULL)) |
|
- | 1624 | { |
|
- | 1625 | old_data = entry_parms->data.bytes; // backup previous data pointer |
|
- | 1626 | entry_parms->is_compiled_bootscript = false; |
|
- | 1627 | entry_parms->should_autosymlink_dylib = false; |
|
- | 1628 | entry_parms->should_follow_symlinks = false; |
|
- | 1629 | entry_parms->st_mode = S_IFLNK | 0777; // NOTE: mkifs stores symlink permissions as rwxrwxrwx ! |
|
- | 1630 | entry_parms->extra_ino_flags = (fsentry->header.ino & (IFS_INO_PROCESSED_ELF | IFS_INO_RUNONCE_ELF | IFS_INO_BOOTSTRAP_EXE)); // preserve target's inode flags |
|
- | 1631 | entry_parms->data.bytes = (uint8_t *) ((last_dirsep = strrchr (stored_pathname, '/')) == NULL ? stored_pathname : last_dirsep + 1); // store symlink target in dirent data |
|
- | 1632 | entry_parms->data.size = strlen (entry_parms->data.bytes); |
|
- | 1633 | token[3] = 0; |
|
- | 1634 | add_fsentry (fsentries, fsentry_count, entry_parms, stored_pathname, NULL); |
|
- | 1635 | token[3] = '.'; |
|
- | 1636 | entry_parms->data.bytes = old_data; // restore previous data pointer so that it can be freed normally |
|
- | 1637 | } |
|
- | 1638 | #endif |
|
1579 | 1639 | ||
1580 | return; // finished, return to our caller |
1640 | return; // finished, return to our caller |
1581 | } |
1641 | } |
1582 | 1642 | ||
1583 | 1643 | ||
Line 1653... | Line 1713... | ||
1653 | } |
1713 | } |
1654 | 1714 | ||
1655 | 1715 | ||
1656 | static void parse_line (FILE *buildfile_fp, char *line_buffer, fsentry_t **fsentries, size_t *fsentry_count, parms_t *default_parms) |
1716 | static void parse_line (FILE *buildfile_fp, char *line_buffer, fsentry_t **fsentries, size_t *fsentry_count, parms_t *default_parms) |
1657 | { |
1717 | { |
- | 1718 | thread_local static char specified_pathname[MAXPATHLEN] = ""; // exactly as specified in the build file |
|
1658 | thread_local static char path_on_buildhost[MAXPATHLEN] = ""; |
1719 | thread_local static char path_on_buildhost[MAXPATHLEN] = ""; |
1659 | thread_local static char path_in_ifs[MAXPATHLEN] = ""; |
1720 | thread_local static char path_in_ifs[MAXPATHLEN] = ""; |
1660 | thread_local 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) |
1721 | thread_local 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) |
1661 | 1722 | ||
1662 | bool should_discard_inline_contents; |
1723 | bool should_discard_inline_contents; |
Line 1665... | Line 1726... | ||
1665 | struct stat stat_buf; |
1726 | struct stat stat_buf; |
1666 | struct tm utc_time; |
1727 | struct tm utc_time; |
1667 | void *reallocated_ptr; |
1728 | void *reallocated_ptr; |
1668 | size_t allocated_size; |
1729 | size_t allocated_size; |
1669 | size_t string_len; |
1730 | size_t string_len; |
1670 | char *specifiedpathname_start; |
- | |
1671 | char *attrblock_start; |
1731 | char *attrblock_start; |
- | 1732 | char *pathname_start; |
|
1672 | char *write_ptr; |
1733 | char *write_ptr; |
1673 | char *line_ptr; |
1734 | char *line_ptr; |
1674 | char *value; |
1735 | char *value; |
1675 | char *token; |
1736 | char *token; |
1676 | char *sep; |
1737 | char *sep; |
Line 1683... | Line 1744... | ||
1683 | 1744 | ||
1684 | if ((*line_ptr == 0) || (*line_ptr == '#')) |
1745 | if ((*line_ptr == 0) || (*line_ptr == '#')) |
1685 | return; // don't process empty lines and comments |
1746 | return; // don't process empty lines and comments |
1686 | 1747 | ||
1687 | string_len = (int) strlen (line_buffer); |
1748 | string_len = (int) strlen (line_buffer); |
1688 |
|
1749 | while ((string_len > 0) && ((line_buffer[string_len - 1] == '\r') || (line_buffer[string_len - 1] == '\n'))) |
1689 | line_buffer[ |
1750 | line_buffer[--string_len] = 0; // chop off carriage returns and newlines for easier debug output |
1690 | 1751 | ||
1691 | // reset entry values |
1752 | // reset entry values |
1692 | memcpy (&entry_parms, default_parms, sizeof (parms_t)); |
1753 | memcpy (&entry_parms, default_parms, sizeof (parms_t)); |
1693 | path_in_ifs[0] = 0; |
1754 | path_in_ifs[0] = 0; |
1694 | path_on_buildhost[0] = 0; |
1755 | path_on_buildhost[0] = 0; |
- | 1756 | specified_pathname[0] = 0; |
|
1695 | should_discard_inline_contents = false; |
1757 | should_discard_inline_contents = false; |
1696 | 1758 | ||
1697 | // does this line start with an attribute block ? |
1759 | // does this line start with an attribute block ? |
1698 | if (*line_ptr == '[') |
1760 | if (*line_ptr == '[') |
1699 | { |
1761 | { |
Line 1722... | Line 1784... | ||
1722 | { |
1784 | { |
1723 | // evaluate attribute token |
1785 | // evaluate attribute token |
1724 | #define REACH_TOKEN_VALUE() do { value = strchr (token, '=') + 1; if (*value == '"') value++; } while (0) |
1786 | #define REACH_TOKEN_VALUE() do { value = strchr (token, '=') + 1; if (*value == '"') value++; } while (0) |
1725 | if (false) {} |
1787 | if (false) {} |
1726 | else if (strncmp (token, "prefix=", 7) == 0) { REACH_TOKEN_VALUE (); entry_parms.prefix = (*value == '/' ? value + 1 : value); } // skip possible leading slash in prefix (NOTE: stolen pointer. Do not free.) |
1788 | else if (strncmp (token, "prefix=", 7) == 0) { REACH_TOKEN_VALUE (); entry_parms.prefix = (*value == '/' ? value + 1 : value); } // skip possible leading slash in prefix (NOTE: stolen pointer. Do not free.) |
1727 | else if (strncmp (token, "uid=", 4) == 0) { REACH_TOKEN_VALUE (); entry_parms.uid = (int) read_integer (value); } |
1789 | else if (strncmp (token, "uid=", 4) == 0) { REACH_TOKEN_VALUE (); entry_parms.uid = (int) read_integer (value, 10); } |
1728 | else if (strncmp (token, "gid=", 4) == 0) { REACH_TOKEN_VALUE (); entry_parms.gid = (int) read_integer (value); } |
1790 | else if (strncmp (token, "gid=", 4) == 0) { REACH_TOKEN_VALUE (); entry_parms.gid = (int) read_integer (value, 10); } |
1729 | else if (strncmp (token, "dperms=", 7) == 0) { REACH_TOKEN_VALUE (); entry_parms.dperms = (int) read_integer (value); } |
1791 | else if (strncmp (token, "dperms=", 7) == 0) { REACH_TOKEN_VALUE (); entry_parms.dperms = (int) read_integer (value, 8); } |
1730 | else if (strncmp (token, "perms=", 6) == 0) { REACH_TOKEN_VALUE (); entry_parms.perms = (int) read_integer (value); } |
1792 | else if (strncmp (token, "perms=", 6) == 0) { REACH_TOKEN_VALUE (); entry_parms.perms = (int) read_integer (value, 8); } |
1731 | else if (strncmp (token, "type=", 5) == 0) { REACH_TOKEN_VALUE (); |
1793 | else if (strncmp (token, "type=", 5) == 0) { REACH_TOKEN_VALUE (); |
1732 | if (strcmp (value, "dir") == 0) entry_parms.st_mode = S_IFDIR; |
1794 | if (strcmp (value, "dir") == 0) entry_parms.st_mode = S_IFDIR; |
1733 | else if (strcmp (value, "file") == 0) entry_parms.st_mode = S_IFREG; |
1795 | else if (strcmp (value, "file") == 0) entry_parms.st_mode = S_IFREG; |
1734 | else if (strcmp (value, "link") == 0) entry_parms.st_mode = S_IFLNK; |
1796 | else if (strcmp (value, "link") == 0) entry_parms.st_mode = S_IFLNK; |
1735 | else if (strcmp (value, "fifo") == 0) entry_parms.st_mode = S_IFIFO; |
1797 | else if (strcmp (value, "fifo") == 0) entry_parms.st_mode = S_IFIFO; |
1736 | else DIE_WITH_EXITCODE (1, "invalid 'type' attribute in \"%s\" line %d: '%s'", buildfile_pathname, lineno, value); |
1798 | else DIE_WITH_EXITCODE (1, "invalid 'type' attribute in \"%s\" line %d: '%s'", buildfile_pathname, lineno, value); |
1737 | } |
1799 | } |
1738 | else if (strncmp (token, "image=", 6) == 0) { REACH_TOKEN_VALUE (); |
1800 | else if (strncmp (token, "image=", 6) == 0) { REACH_TOKEN_VALUE (); |
1739 | image_base = (uint32_t) read_integer (value); // read image base address |
1801 | image_base = (uint32_t) read_integer (value, 0); // read image base address |
1740 | 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.) |
1802 | if ((sep = strchr (value, '-')) != NULL) image_end = (uint32_t) read_integer (sep + 1, 0); // if we have a dash, read optional image end (TODO: check this value and produce an error in the relevant case. Not important.) |
1741 | if ((sep = strchr (value, ',')) != NULL) image_maxsize = (uint32_t) read_integer (sep + 1); // if we have a comma, read optional image max size |
1803 | if ((sep = strchr (value, ',')) != NULL) image_maxsize = (uint32_t) read_integer (sep + 1, 0); // if we have a comma, read optional image max size |
1742 | if ((sep = strchr (value, '=')) != NULL) image_totalsize = (uint32_t) read_integer (sep + 1); // if we have an equal sign, read optional image padding size |
1804 | if ((sep = strchr (value, '=')) != NULL) image_totalsize = (uint32_t) read_integer (sep + 1, 0); // if we have an equal sign, read optional image padding size |
1743 | if ((sep = strchr (value, '%')) != NULL) image_align = (uint32_t) read_integer (sep + 1); // if we have a modulo sign, read optional image aligmnent |
1805 | if ((sep = strchr (value, '%')) != NULL) image_align = (uint32_t) read_integer (sep + 1, 0); // if we have a modulo sign, read optional image aligmnent |
1744 | LOG_INFO ("image 0x%x-0x%x maxsize %d totalsize %d align %d", image_base, image_end, image_maxsize, image_totalsize, image_align); |
1806 | LOG_INFO ("image 0x%x-0x%x maxsize %d totalsize %d align %d", image_base, image_end, image_maxsize, image_totalsize, image_align); |
1745 | } |
1807 | } |
1746 | else if (strncmp (token, "virtual=", 8) == 0) { REACH_TOKEN_VALUE (); |
1808 | else if (strncmp (token, "virtual=", 8) == 0) { REACH_TOKEN_VALUE (); |
1747 | if ((bootfile_pathname == NULL) || (startupfile_pathname == NULL)) // FIXME: HACK until I figure out how to re-create them |
- | |
1748 | DIE_WITH_EXITCODE (1, "creating bootable images require the --bootfile and --startupfile command-line options in \"%s\" line %d", buildfile_pathname, lineno); |
- | |
1749 | if ((sep = strchr (value, ',')) != NULL) // do we have a comma separating (optional) processor and boot file name ? |
1809 | if ((sep = strchr (value, ',')) != NULL) // do we have a comma separating (optional) processor and boot file name ? |
1750 | { |
1810 | { |
1751 | *sep = 0; |
1811 | *sep = 0; |
1752 | if (strcmp (value, "x86_64") == 0) |
1812 | if (strcmp (value, "x86_64") == 0) |
1753 | { |
1813 | { |
Line 1763... | Line 1823... | ||
1763 | } |
1823 | } |
1764 | else |
1824 | else |
1765 | DIE_WITH_EXITCODE (1, "unrecognized processor type in 'virtual' attribute in \"%s\" line %d: '%s'", buildfile_pathname, lineno, value); |
1825 | DIE_WITH_EXITCODE (1, "unrecognized processor type in 'virtual' attribute in \"%s\" line %d: '%s'", buildfile_pathname, lineno, value); |
1766 | value = sep + 1; |
1826 | value = sep + 1; |
1767 | } |
1827 | } |
- | 1828 | boot_type = (strstr (value, "uefi") != NULL ? BOOTTYPE_UEFI : BOOTTYPE_BIOS); // FIXME: this should be a boot FILE, not a hardcoded tag |
|
- | 1829 | if (boot_type == BOOTTYPE_UEFI) |
|
- | 1830 | { |
|
- | 1831 | if (startupfile_pathname == NULL) // FIXME: HACK until I figure out how to re-create it |
|
- | 1832 | DIE_WITH_EXITCODE (1, "creating bootable UEFI images requires the --startupfile command-line option in \"%s\" line %d", buildfile_pathname, lineno); |
|
- | 1833 | bootfile_size = ROUND_TO_UPPER_MULTIPLE (sizeof (uefi64_header_t), 512); // round to upper filesystem block (PE header constraint) |
|
- | 1834 | LOG_INFO ("processor \"%s\" bootfile <generated, UEFI>\n", image_processor); |
|
- | 1835 | } |
|
- | 1836 | else |
|
- | 1837 | { |
|
- | 1838 | if ((bootfile_pathname == NULL) || (startupfile_pathname == NULL)) // FIXME: HACK until I figure out how to re-create them |
|
- | 1839 | DIE_WITH_EXITCODE (1, "creating bootable BIOS images requires the --bootfile and --startupfile command-line options in \"%s\" line %d", buildfile_pathname, lineno); |
|
1768 | if (stat (bootfile_pathname, &stat_buf) != 0) |
1840 | if (stat (bootfile_pathname, &stat_buf) != 0) |
1769 | DIE_WITH_EXITCODE (1, "unable to stat the boot file \"%s\" specified in \"%s\" line %d: %s", bootfile_pathname, buildfile_pathname, lineno, strerror (errno)); |
1841 | DIE_WITH_EXITCODE (1, "unable to stat the boot file \"%s\" specified in \"%s\" line %d: %s", bootfile_pathname, buildfile_pathname, lineno, strerror (errno)); |
1770 | bootfile_size = stat_buf.st_size; // save preboot file size |
1842 | bootfile_size = stat_buf.st_size; // save preboot file size |
1771 | LOG_INFO ("processor \"%s\" bootfile \"%s\"\n", image_processor, bootfile_pathname); |
1843 | LOG_INFO ("processor \"%s\" bootfile \"%s\"\n", image_processor, bootfile_pathname); |
- | 1844 | } |
|
1772 | entry_parms.is_bootstrap_file = true; |
1845 | entry_parms.is_bootstrap_file = true; |
1773 | } |
1846 | } |
1774 | else if (strncmp (token, "mtime=", 6) == 0) { REACH_TOKEN_VALUE (); if (strcmp (value, "*") == 0) entry_parms.mtime = UINT32_MAX; else { |
1847 | else if (strncmp (token, "mtime=", 6) == 0) { REACH_TOKEN_VALUE (); if (strcmp (value, "*") == 0) entry_parms.mtime = UINT32_MAX; else { |
1775 | // value *must* be "YYYY-MM-DD-HH:MM:SS" by specification |
1848 | // value *must* be "YYYY-MM-DD-HH:MM:SS" by specification |
1776 | memset (&utc_time, 0, sizeof (utc_time)); |
1849 | memset (&utc_time, 0, sizeof (utc_time)); |
Line 1841... | Line 1914... | ||
1841 | } |
1914 | } |
1842 | // end of attributes parsing |
1915 | // end of attributes parsing |
1843 | } // end of "this line starts with an attributes block" |
1916 | } // end of "this line starts with an attributes block" |
1844 | 1917 | ||
1845 | // there's data in this line. We expect a filename in the IFS. Read it and unescape escaped characters |
1918 | // there's data in this line. We expect a filename in the IFS. Read it and unescape escaped characters |
1846 | string_len = sprintf_s (path_in_ifs, sizeof (path_in_ifs), "%s", (entry_parms.prefix != NULL ? entry_parms.prefix : "")); |
- | |
1847 | while ((string_len > 0) && (path_in_ifs[string_len - 1] == '/')) |
- | |
1848 | string_len--; // chop off any trailing slashes from prefix |
- | |
1849 | write_ptr = &path_in_ifs[string_len]; |
- | |
1850 | *write_ptr++ = '/'; // add ONE trailing slash |
- | |
1851 | specifiedpathname_start = write_ptr; // remember the specified pathname will start here |
- | |
1852 | is_quoted_context = (*line_ptr == '"'); |
1919 | is_quoted_context = (*line_ptr == '"'); |
1853 | if (is_quoted_context) |
1920 | if (is_quoted_context) |
1854 | line_ptr++; // skip a possible initial quote |
1921 | line_ptr++; // skip a possible initial quote |
1855 |
|
1922 | write_ptr = specified_pathname; |
1856 | { |
- | |
1857 | LOG_WARNING ("paths in the IFS file should not begin with a leading '/' in \"%s\" line %d", buildfile_pathname, lineno); |
- | |
1858 | line_ptr++; // consistency check: paths in the IFS should not begin with a '/' |
- | |
1859 | } |
- | |
1860 | while ((*line_ptr != 0) && ((!is_quoted_context && (*line_ptr != '=') && !isspace (*line_ptr)) || (is_quoted_context && (*line_ptr != '"')))) |
1923 | while ((*line_ptr != 0) && ((!is_quoted_context && (*line_ptr != '=') && !isspace (*line_ptr)) || (is_quoted_context && (*line_ptr != '"')))) |
1861 | { |
1924 | { |
1862 | if (*line_ptr == '\\') |
1925 | if (*line_ptr == '\\') |
1863 | { |
1926 | { |
1864 | line_ptr++; |
1927 | line_ptr++; |
Line 1875... | Line 1938... | ||
1875 | // we reached a space OR an equal sign |
1938 | // we reached a space OR an equal sign |
1876 | while ((*line_ptr != 0) && isspace (*line_ptr)) |
1939 | while ((*line_ptr != 0) && isspace (*line_ptr)) |
1877 | line_ptr++; // skip optional spaces after the filename in the IFS |
1940 | line_ptr++; // skip optional spaces after the filename in the IFS |
1878 | 1941 | ||
1879 | // do we have an equal sign ? |
1942 | // do we have an equal sign ? |
1880 | if (*line_ptr == '=') |
1943 | if (*line_ptr == '=') |
1881 | { |
1944 | { |
1882 | line_ptr++; // skip the equal sign |
1945 | line_ptr++; // skip the equal sign |
1883 | while ((*line_ptr != 0) && isspace (*line_ptr)) |
1946 | while ((*line_ptr != 0) && isspace (*line_ptr)) |
1884 | line_ptr++; // skip optional spaces after the equal sign |
1947 | line_ptr++; // skip optional spaces after the equal sign |
1885 | 1948 | ||
Line 1887... | Line 1950... | ||
1887 | { |
1950 | { |
1888 | LOG_WARNING ("syntax error in \"%s\" line %d: missing data specification after equal sign (skipping)", buildfile_pathname, lineno); |
1951 | LOG_WARNING ("syntax error in \"%s\" line %d: missing data specification after equal sign (skipping)", buildfile_pathname, lineno); |
1889 | return; // invalid symlink specification, skip line |
1952 | return; // invalid symlink specification, skip line |
1890 | } |
1953 | } |
1891 | 1954 | ||
1892 | // |
1955 | // it may be either a path or a contents definition. Is it a content definition ? |
1893 | if (*line_ptr == '{') |
1956 | if (*line_ptr == '{') |
1894 | { |
1957 | { |
1895 | allocated_size = 0; |
1958 | allocated_size = 0; |
1896 | 1959 | ||
1897 | line_ptr++; // skip the leading content definition |
1960 | line_ptr++; // skip the leading content definition |
Line 1899... | Line 1962... | ||
1899 | for (;;) |
1962 | for (;;) |
1900 | { |
1963 | { |
1901 | read_char = fgetc (buildfile_fp); |
1964 | read_char = fgetc (buildfile_fp); |
1902 | if (read_char == EOF) |
1965 | if (read_char == EOF) |
1903 | DIE_WITH_EXITCODE (1, "syntax error in \"%s\" line %d: unterminated contents block (end of file reached)", buildfile_pathname, lineno); // invalid contents block |
1966 | DIE_WITH_EXITCODE (1, "syntax error in \"%s\" line %d: unterminated contents block (end of file reached)", buildfile_pathname, lineno); // invalid contents block |
- | 1967 | else if (read_char == '\r') |
|
- | 1968 | continue; // just ignore carriage returns (Microsoft end of line format) |
|
1904 | else if ((read_char == '\\') && !is_escaped_char) |
1969 | else if ((read_char == '\\') && !is_escaped_char) |
1905 | is_escaped_char = true; // remember the next char is escaped |
1970 | is_escaped_char = true; // remember the next char is escaped |
1906 | else if ((read_char == '}') && !is_escaped_char) |
1971 | else if ((read_char == '}') && !is_escaped_char) |
1907 | break; // found an unescaped closing bracked, stop parsing |
1972 | break; // found an unescaped closing bracked, stop parsing |
1908 | else |
1973 | else |
Line 1927... | Line 1992... | ||
1927 | else // not a content definition between { brackets }, must be either a pathname on the build host, or the target of a symlink |
1992 | else // not a content definition between { brackets }, must be either a pathname on the build host, or the target of a symlink |
1928 | { |
1993 | { |
1929 | is_quoted_context = (*line_ptr == '"'); |
1994 | is_quoted_context = (*line_ptr == '"'); |
1930 | if (is_quoted_context) |
1995 | if (is_quoted_context) |
1931 | line_ptr++; // skip a possible initial quote |
1996 | line_ptr++; // skip a possible initial quote |
1932 |
|
1997 | pathname_start = line_ptr; // remember where the specified pathname starts |
1933 | write_ptr = line_ptr; // now unescape all characters |
1998 | write_ptr = line_ptr; // now unescape all characters |
1934 | while ((*line_ptr != 0) && ((!is_quoted_context && !isspace (*line_ptr)) || (is_quoted_context && (*line_ptr != '"')))) |
1999 | while ((*line_ptr != 0) && ((!is_quoted_context && !isspace (*line_ptr)) || (is_quoted_context && (*line_ptr != '"')))) |
1935 | { |
2000 | { |
1936 | if (*line_ptr == '\\') |
2001 | if (*line_ptr == '\\') |
1937 | { |
2002 | { |
Line 1945... | Line 2010... | ||
1945 | *write_ptr = 0; // terminate the string |
2010 | *write_ptr = 0; // terminate the string |
1946 | if (is_quoted_context && (*line_ptr == '"')) |
2011 | if (is_quoted_context && (*line_ptr == '"')) |
1947 | line_ptr++; // skip a possible final quote |
2012 | line_ptr++; // skip a possible final quote |
1948 | 2013 | ||
1949 | if (S_ISLNK (entry_parms.st_mode)) // are we storing a symlink ? |
2014 | if (S_ISLNK (entry_parms.st_mode)) // are we storing a symlink ? |
1950 | ASSERT_WITH_ERRNO (Buffer_InitWithCString (&entry_parms.data, |
2015 | ASSERT_WITH_ERRNO (Buffer_InitWithCString (&entry_parms.data, pathname_start)); // if so, store the symlink target as the dirent's blob data |
1951 | else // it's a build host filesystem path |
2016 | else // it's a build host filesystem path |
1952 | strcpy_s (path_on_buildhost, sizeof (path_on_buildhost), |
2017 | strcpy_s (path_on_buildhost, sizeof (path_on_buildhost), pathname_start); // the path on the build host is given after the equal sign |
1953 | } |
2018 | } |
1954 | } |
2019 | } |
1955 | else // no equal sign, meaning the file will have the same name on the build host filesystem |
2020 | else // no equal sign, meaning the file will have the same name on the build host filesystem |
1956 | { |
2021 | { |
1957 | // consistency check: symlinks MUST have an equal sign |
2022 | // consistency check: symlinks MUST have an equal sign |
Line 1959... | Line 2024... | ||
1959 | { |
2024 | { |
1960 | LOG_WARNING ("syntax error in \"%s\" line %d: missing equal sign and symlink target (skipping)", buildfile_pathname, lineno); |
2025 | LOG_WARNING ("syntax error in \"%s\" line %d: missing equal sign and symlink target (skipping)", buildfile_pathname, lineno); |
1961 | return; // invalid symlink specification, skip line |
2026 | return; // invalid symlink specification, skip line |
1962 | } |
2027 | } |
1963 | 2028 | ||
- | 2029 | // UNLESS we know we are storing (=creating empty) a directory, the path on the build host is the one specified |
|
- | 2030 | if (S_ISDIR (entry_parms.st_mode)) |
|
- | 2031 | path_on_buildhost[0] = 0; // we're storing a new empty directory: path on build host is nil |
|
- | 2032 | else |
|
1964 | strcpy_s (path_on_buildhost, sizeof (path_on_buildhost), |
2033 | strcpy_s (path_on_buildhost, sizeof (path_on_buildhost), specified_pathname); // the path on the build host is the one specified |
- | 2034 | ||
- | 2035 | if ((specified_pathname[0] != '/') && ((token = strrchr (specified_pathname, '/')) != NULL)) |
|
- | 2036 | memmove (specified_pathname, token + 1, strlen (token + 1) + 1); // unless it's absolute, the path in the IFS is the BASENAME of the path specified |
|
- | 2037 | } |
|
- | 2038 | ||
- | 2039 | // was the specified path in the build file absolute or relative ? |
|
1965 |
|
2040 | if (specified_pathname[0] == '/') |
- | 2041 | strcpy_s (path_in_ifs, sizeof (path_in_ifs), specified_pathname); // path is absolute, use it verbatim |
|
1966 |
|
2042 | else // path is relative |
- | 2043 | { |
|
- | 2044 | string_len = sprintf_s (path_in_ifs, sizeof (path_in_ifs), "%s", (entry_parms.prefix != NULL ? entry_parms.prefix : "")); // use path prefix |
|
- | 2045 | while ((string_len > 0) && (path_in_ifs[string_len - 1] == '/')) |
|
- | 2046 | string_len--; // chop off any trailing slashes from prefix |
|
- | 2047 | path_in_ifs[string_len++] = '/'; // add ONE trailing slash |
|
1967 |
|
2048 | strcpy_s (&path_in_ifs[string_len], sizeof (path_in_ifs) - string_len, specified_pathname); // construct an absolute path with the IFS prefix |
1968 | } |
2049 | } |
1969 | 2050 | ||
1970 | // now add this entry to the image filesystem |
2051 | // now add this entry to the image filesystem |
1971 | if (S_ISDIR (entry_parms.st_mode)) |
2052 | if (S_ISDIR (entry_parms.st_mode)) |
1972 | entry_parms.st_mode |= entry_parms.dperms; |
2053 | entry_parms.st_mode |= entry_parms.dperms; // directory |
1973 | else if (S_ISLNK (entry_parms.st_mode)) |
2054 | else if (S_ISLNK (entry_parms.st_mode)) |
1974 | entry_parms.st_mode |= 0777; // NOTE: mkifs sets symlink permissions to rwxrwxrwx !? |
2055 | entry_parms.st_mode |= 0777; // symlink (NOTE: mkifs sets symlink permissions to rwxrwxrwx !?) |
1975 | else |
2056 | else if (S_ISREG (entry_parms.st_mode)) |
1976 | entry_parms.st_mode |= entry_parms.perms; |
2057 | entry_parms.st_mode |= entry_parms.perms; // file |
- | 2058 | else |
|
- | 2059 | entry_parms.st_mode |= entry_parms.perms; // device node |
|
1977 | 2060 | ||
1978 | add_fsentry (fsentries, fsentry_count, &entry_parms, path_in_ifs, path_on_buildhost); // and add filesystem entry |
2061 | add_fsentry (fsentries, fsentry_count, &entry_parms, path_in_ifs, path_on_buildhost); // and add filesystem entry |
1979 | 2062 | ||
1980 | if (entry_parms.data.bytes != NULL) |
2063 | if (entry_parms.data.bytes != NULL) |
1981 | free (entry_parms.data.bytes); // if blob data was allocated, free it |
2064 | free (entry_parms.data.bytes); // if blob data was allocated, free it |
Line 2018... | Line 2101... | ||
2018 | .should_follow_symlinks = true, // [+|-followlink] |
2101 | .should_follow_symlinks = true, // [+|-followlink] |
2019 | .should_autosymlink_dylib = true, // [+|-autolink] |
2102 | .should_autosymlink_dylib = true, // [+|-autolink] |
2020 | }; |
2103 | }; |
2021 | 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) |
2104 | 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) |
2022 | 2105 | ||
- | 2106 | uefi64_header_t *uefi_header = NULL; |
|
2023 | char path_on_buildhost[MAXPATHLEN] = ""; |
2107 | char path_on_buildhost[MAXPATHLEN] = ""; |
2024 | char path_in_ifs[MAXPATHLEN] = ""; |
2108 | char path_in_ifs[MAXPATHLEN] = ""; |
2025 | const char *ifs_pathname = NULL; |
2109 | const char *ifs_pathname = NULL; |
2026 | const char *rootdir_pathname = NULL; |
2110 | const char *rootdir_pathname = NULL; |
2027 | const fsentry_t *fsentry; |
2111 | const fsentry_t *fsentry; |
2028 | void *reallocated_ptr; |
2112 | void *reallocated_ptr; |
2029 | buffer_t compressed_imagefs; |
2113 | buffer_t compressed_imagefs; |
- | 2114 | buffer_t opaqueblob_file; |
|
2030 | uint8_t *compressor_out; |
2115 | uint8_t *compressor_out; |
2031 | uint8_t *compressor_in; |
2116 | uint8_t *compressor_in; |
2032 | size_t compressor_outlen; |
2117 | size_t compressor_outlen; |
2033 | size_t compressor_inlen; |
2118 | size_t compressor_inlen; |
2034 | size_t reallocated_size; |
2119 | size_t reallocated_size; |
Line 2081... | Line 2166... | ||
2081 | sep = strchr (argv[++arg_index], '@'); |
2166 | sep = strchr (argv[++arg_index], '@'); |
2082 | if ((sep == NULL) || (sep[1] == 0)) |
2167 | if ((sep == NULL) || (sep[1] == 0)) |
2083 | DIE_WITH_EXITCODE (1, "the --startupfile arguments expects <pathname>@<entrypoint_from_image_base>"); |
2168 | DIE_WITH_EXITCODE (1, "the --startupfile arguments expects <pathname>@<entrypoint_from_image_base>"); |
2084 | *sep = 0; |
2169 | *sep = 0; |
2085 | startupfile_pathname = argv[arg_index]; |
2170 | startupfile_pathname = argv[arg_index]; |
2086 | startupfile_ep_from_imagebase = (size_t) read_integer (sep + 1); |
2171 | startupfile_ep_from_imagebase = (size_t) read_integer (sep + 1, 0); |
2087 | } |
2172 | } |
2088 | else if ((strcmp (argv[arg_index], "--kerneloffs") == 0) && (arg_index + 1 < argc)) // --kerneloffs 0x32000 (undocumented) |
- | |
2089 | kernelfile_offset = (size_t) read_integer (argv[++arg_index]); |
- | |
2090 | else if ((strcmp (argv[arg_index], "-a") == 0) && (arg_index + 1 < argc)) // -a suffix |
2173 | else if ((strcmp (argv[arg_index], "-a") == 0) && (arg_index + 1 < argc)) // -a suffix |
2091 | sym_suffix = argv[++arg_index]; |
2174 | sym_suffix = argv[++arg_index]; |
2092 | else if (strcmp (argv[arg_index], "-n") == 0) |
2175 | else if (strcmp (argv[arg_index], "-n") == 0) |
2093 | default_parms.mtime_for_inline_files = 0; // inline files should have a mtime set to zero |
2176 | default_parms.mtime_for_inline_files = 0; // inline files should have a mtime set to zero |
2094 | else if (strcmp (argv[arg_index], "-nn") == 0) |
2177 | else if (strcmp (argv[arg_index], "-nn") == 0) |
Line 2312... | Line 2395... | ||
2312 | 2395 | ||
2313 | // do we have a startup file ? if so, this is a bootable image |
2396 | // do we have a startup file ? if so, this is a bootable image |
2314 | if (startupfile_pathname != NULL) |
2397 | if (startupfile_pathname != NULL) |
2315 | { |
2398 | { |
2316 | // write boot prefix |
2399 | // write boot prefix |
- | 2400 | if (boot_type == BOOTTYPE_UEFI) // UEFI boot |
|
- | 2401 | { |
|
- | 2402 | ASSERT_WITH_ERRNO (Buffer_PadWithZeroesTo (&ifs.data, sizeof (uefi64_header_t))); // start by writing an empty UEFI header |
|
- | 2403 | uefi_header = (uefi64_header_t *) ifs.data.bytes; // have a convenience pointer |
|
- | 2404 | memcpy (&uefi_header->dos_header.signature, "MZ", 2); // store the MZ magic |
|
- | 2405 | uefi_header->dos_header.bytes_in_last_page = 144; // fixed value |
|
- | 2406 | uefi_header->dos_header.number_of_pages = 3; // fixed value |
|
- | 2407 | uefi_header->dos_header.header_size_in_paragraphs = sizeof (uefi_header->dos_header) / 16; |
|
- | 2408 | uefi_header->dos_header.requested_paragraphs = 0xffff; |
|
- | 2409 | uefi_header->dos_header.initial_stack_pointer_value = 0x00b8; // fixed value |
|
- | 2410 | uefi_header->dos_header.absolute_offset_to_relocation_table = sizeof (uefi_header->dos_header); |
|
- | 2411 | uefi_header->dos_header.absolute_offset_to_pe_header = sizeof (uefi_header->dos_header) + sizeof (uefi_header->dos_stub_bytes); |
|
- | 2412 | memcpy (uefi_header->dos_stub_bytes, "\x0E\x1F\xBA\x0E\x00\xB4\x09\xCD\x21\xB8\x01\x4C\xCD\x21" "This program cannot be run in DOS mode.\r\r\n" "\x24\x00\x00\x00\x00\x00\x00\x00", 64); // store DOS stub program |
|
- | 2413 | memcpy (&uefi_header->pe_header.signature, "PE\0\0", 4); // store the PE magic |
|
- | 2414 | uefi_header->pe_header.machine_type = (strcmp (image_processor, "x86_64") == 0 ? 0x8664 : (strcmp (image_processor, "aarch64le") == 0 ? 0xaa64 : 0xffff)); // store machine type |
|
- | 2415 | uefi_header->pe_header.number_of_sections = 1; // store number of sections |
|
- | 2416 | uefi_header->pe_header.epoch_timestamp = (uint32_t) time (NULL); // store timestamp (NOTE: mkifs doesn't obey its -nn arguments here, so neither shall we) |
|
- | 2417 | uefi_header->pe_header.size_of_optional_header = sizeof (uefi_header->optional_header64); // 240 bytes |
|
- | 2418 | uefi_header->pe_header.characteristics_bitmap = 0x0223; // store characteristics bitmap (executable, uses large addresses, relocs stripped, debug info stripped) |
|
- | 2419 | memcpy (uefi_header->optional_header64.signature, "\x0b\x02", 2); // store the 64-bit optional header magic |
|
- | 2420 | uefi_header->optional_header64.code_size = WILL_BE_FILLED_LATER; // total size of IFS minus 512 bytes for the UEFI boot header, i.e. size of startup blob plus size of image |
|
- | 2421 | uefi_header->optional_header64.entrypoint_address = (uint32_t) startupfile_ep_from_imagebase; |
|
- | 2422 | uefi_header->optional_header64.image_base = image_base; |
|
- | 2423 | uefi_header->optional_header64.section_alignment = (uint32_t) image_pagesize; |
|
- | 2424 | uefi_header->optional_header64.file_alignment = 512; // i.e. one filesystem block |
|
- | 2425 | uefi_header->optional_header64.image_size = WILL_BE_FILLED_LATER; // total IFS file size |
|
- | 2426 | uefi_header->optional_header64.size_of_headers = (uint32_t) bootfile_size; |
|
- | 2427 | uefi_header->optional_header64.subsystem_type = 10; // IMAGE_SUBSYSTEM_EFI_APPLICATION |
|
- | 2428 | uefi_header->optional_header64.stack_reserve_size = image_pagesize; |
|
- | 2429 | uefi_header->optional_header64.stack_commit_size = image_pagesize; |
|
- | 2430 | uefi_header->optional_header64.number_of_data_directories = 16; // mkifs reserves 16 data directories, filled with zeroes (FIXME: why?) |
|
- | 2431 | memcpy (uefi_header->unique_section.section_name, "image\0\0\0", 8); // store the unique section name |
|
- | 2432 | uefi_header->unique_section.virtual_size = WILL_BE_FILLED_LATER; // same as pe_image_optional_header64.code_size |
|
- | 2433 | uefi_header->unique_section.virtual_address = ROUND_TO_UPPER_MULTIPLE (uefi_header->optional_header64.size_of_headers, uefi_header->optional_header64.file_alignment); |
|
- | 2434 | uefi_header->unique_section.rawdata_size = WILL_BE_FILLED_LATER; // same as pe_image_optional_header64.code_size |
|
- | 2435 | uefi_header->unique_section.rawdata_offset = uefi_header->unique_section.virtual_address; |
|
- | 2436 | uefi_header->unique_section.characteristics_bitmap = 0x60; // image contains code + image contains initialized data |
|
- | 2437 | ASSERT_WITH_ERRNO (Buffer_PadWithZeroesTo (&ifs.data, uefi_header->optional_header64.size_of_headers)); // pad as necessary |
|
- | 2438 | } |
|
- | 2439 | else // BIOS boot |
|
- | 2440 | { |
|
2317 | // ###################################################################################################################################################################################################################################### |
2441 | // ###################################################################################################################################################################################################################################### |
2318 | // # FIXME: figure out how |
2442 | // # FIXME: figure out how mkifs produces the boot prefix out of the BIOS "boot file" here |
2319 | // ###################################################################################################################################################################################################################################### |
2443 | // ###################################################################################################################################################################################################################################### |
2320 | buffer_t file; |
- | |
2321 | if (!Buffer_ReadFromFile (& |
2444 | if (!Buffer_ReadFromFile (&opaqueblob_file, bootfile_pathname)) |
2322 | DIE_WITH_EXITCODE (1, "failed to open \"%s\" for reading: %s", bootfile_pathname, strerror (errno)); |
2445 | DIE_WITH_EXITCODE (1, "failed to open \"%s\" for reading: %s", bootfile_pathname, strerror (errno)); |
2323 | ASSERT_WITH_ERRNO (Buffer_AppendBuffer (&ifs.data, & |
2446 | ASSERT_WITH_ERRNO (Buffer_AppendBuffer (&ifs.data, &opaqueblob_file)); // write boot blob |
2324 | Buffer_Forget (& |
2447 | Buffer_Forget (&opaqueblob_file); |
2325 | ASSERT_WITH_ERRNO (Buffer_PadWithZeroesTo (&ifs.data, ROUND_TO_UPPER_MULTIPLE (ifs.data.size, image_align))); // pad as necessary |
2448 | ASSERT_WITH_ERRNO (Buffer_PadWithZeroesTo (&ifs.data, ROUND_TO_UPPER_MULTIPLE (ifs.data.size, image_align))); // pad as necessary |
- | 2449 | } |
|
2326 | 2450 | ||
2327 | ifs.offsets.startupheader = ifs.data.size; // save startup header offset for future use |
2451 | ifs.offsets.startupheader = ifs.data.size; // save startup header offset for future use |
2328 | memset (&startup_header, 0, sizeof (startup_header)); // prepare startup header |
2452 | memset (&startup_header, 0, sizeof (startup_header)); // prepare startup header |
2329 | memcpy (startup_header.signature, "\xeb\x7e\xff\x00", 4); // startup header signature, i.e. 0xff7eeb |
2453 | memcpy (startup_header.signature, "\xeb\x7e\xff\x00", 4); // startup header signature, i.e. 0xff7eeb |
2330 | startup_header.version = 1; |
2454 | startup_header.version = 1; |
Line 2356... | Line 2480... | ||
2356 | // then: parse resulting ELF file, take all program segments and concatenate them --> this is the blob (FIXME: wrong?) |
2480 | // then: parse resulting ELF file, take all program segments and concatenate them --> this is the blob (FIXME: wrong?) |
2357 | // ###################################################################################################################################################################################################################################### |
2481 | // ###################################################################################################################################################################################################################################### |
2358 | #if 0 // nonworking |
2482 | #if 0 // nonworking |
2359 | // <deleted> |
2483 | // <deleted> |
2360 | #else // working |
2484 | #else // working |
2361 | if (!Buffer_ReadFromFile (& |
2485 | if (!Buffer_ReadFromFile (&opaqueblob_file, startupfile_pathname)) |
2362 | DIE_WITH_EXITCODE (1, "failed to open \"%s\" for reading: %s", startupfile_pathname, strerror (errno)); |
2486 | DIE_WITH_EXITCODE (1, "failed to open \"%s\" for reading: %s", startupfile_pathname, strerror (errno)); |
2363 | ASSERT_WITH_ERRNO (Buffer_AppendBuffer (&ifs.data, & |
2487 | ASSERT_WITH_ERRNO (Buffer_AppendBuffer (&ifs.data, &opaqueblob_file)); // write startup blob |
2364 | Buffer_Forget (& |
2488 | Buffer_Forget (&opaqueblob_file); |
2365 | #endif // working |
2489 | #endif // working |
2366 | ASSERT_WITH_ERRNO (Buffer_PadWithZeroesTo (&ifs.data, ROUND_TO_UPPER_MULTIPLE (ifs.data.size, image_align))); // pad as necessary |
2490 | ASSERT_WITH_ERRNO (Buffer_PadWithZeroesTo (&ifs.data, ROUND_TO_UPPER_MULTIPLE (ifs.data.size, image_align))); // pad as necessary |
2367 | 2491 | ||
2368 | ifs.offsets.startuptrailer = ifs.data.size; // save startup trailer offset for future use |
2492 | ifs.offsets.startuptrailer = ifs.data.size; // save startup trailer offset for future use |
2369 | ASSERT_WITH_ERRNO (Buffer_Append (&ifs.data, &startup_trailer, sizeof (startup_trailer))); // write startup trailer |
2493 | ASSERT_WITH_ERRNO (Buffer_Append (&ifs.data, &startup_trailer, sizeof (startup_trailer))); // write startup trailer |
Line 2441... | Line 2565... | ||
2441 | 2565 | ||
2442 | // then write all the other files by increasing inode number: ELF files first |
2566 | // then write all the other files by increasing inode number: ELF files first |
2443 | for (fsentry_index = 1; fsentry_index < fsentry_count; fsentry_index++) |
2567 | for (fsentry_index = 1; fsentry_index < fsentry_count; fsentry_index++) |
2444 | { |
2568 | { |
2445 | if (!S_ISREG (fsentries[fsentry_index].header.mode) || fsentries[fsentry_index].UNSAVED_was_data_written // filter out anything that's not a file, and anything that's been already written |
2569 | if (!S_ISREG (fsentries[fsentry_index].header.mode) || fsentries[fsentry_index].UNSAVED_was_data_written // filter out anything that's not a file, and anything that's been already written |
2446 | || (fsentries[fsentry_index].u.file.size < 4) || (memcmp (fsentries[fsentry_index] |
2570 | || (fsentries[fsentry_index].u.file.size < 4) || (memcmp (fsentries[fsentry_index].UNSAVED_databuf, ELF_MAGIC_STR, 4) != 0)) // filter out anything that's not an ELF file |
2447 | continue; // skip all entries that don't have a separate data block and those who were written already |
2571 | continue; // skip all entries that don't have a separate data block and those who were written already |
2448 | fsentries[fsentry_index].u.file.offset = (uint32_t) (ifs.data.size - ifs.offsets.imageheader); // save file data blob offset in file structure |
2572 | fsentries[fsentry_index].u.file.offset = (uint32_t) (ifs.data.size - ifs.offsets.imageheader); // save file data blob offset in file structure |
2449 | Buffer_AppendIFSFileData (&ifs.data, &fsentries[fsentry_index]); // write file data |
2573 | Buffer_AppendIFSFileData (&ifs.data, &fsentries[fsentry_index]); // write file data |
2450 | fsentries[fsentry_index].UNSAVED_was_data_written = true; // and remember this file's data was written |
2574 | fsentries[fsentry_index].UNSAVED_was_data_written = true; // and remember this file's data was written |
2451 | } |
2575 | } |
Line 2616... | Line 2740... | ||
2616 | } |
2740 | } |
2617 | 2741 | ||
2618 | // do we have a startup file ? if so, this is a bootable image |
2742 | // do we have a startup file ? if so, this is a bootable image |
2619 | if (startupfile_pathname != NULL) |
2743 | if (startupfile_pathname != NULL) |
2620 | { |
2744 | { |
- | 2745 | if (boot_type == BOOTTYPE_UEFI) // UEFI boot: fix the final offsets and sizes in the EFI executable's PE header |
|
- | 2746 | { |
|
- | 2747 | uefi_header = (uefi64_header_t *) ifs.data.bytes; // have a convenience pointer |
|
- | 2748 | uefi_header->optional_header64.code_size = (uint32_t) (ifs.data.size - ifs.offsets.startupheader); // total size of IFS minus 512 bytes for the UEFI boot header, i.e. size of startup blob plus size of image |
|
- | 2749 | uefi_header->optional_header64.image_size = (uint32_t) ifs.data.size; // total IFS file size |
|
- | 2750 | uefi_header->unique_section.virtual_size = uefi_header->optional_header64.code_size; // same as pe_image_optional_header64.code_size |
|
- | 2751 | uefi_header->unique_section.rawdata_size = uefi_header->optional_header64.code_size; // same as pe_image_optional_header64.code_size |
|
- | 2752 | } |
|
- | 2753 | ||
2621 | // compute SHA-512 checksum and V1 checksum of startup block |
2754 | // compute SHA-512 checksum and V1 checksum of startup block |
2622 | if ( ( (startup_header.flags1 & STARTUP_HDR_FLAGS1_BIGENDIAN) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) |
2755 | if ( ( (startup_header.flags1 & STARTUP_HDR_FLAGS1_BIGENDIAN) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) |
2623 | || (!(startup_header.flags1 & STARTUP_HDR_FLAGS1_BIGENDIAN) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ))) |
2756 | || (!(startup_header.flags1 & STARTUP_HDR_FLAGS1_BIGENDIAN) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ))) |
2624 | is_foreign_endianness = true; // if the header is big endian and we're on a little endian machine, or the other way around, it's a foreign endianness |
2757 | is_foreign_endianness = true; // if the header is big endian and we're on a little endian machine, or the other way around, it's a foreign endianness |
2625 | else |
2758 | else |
Line 2653... | Line 2786... | ||
2653 | free (fsentry->u.symlink.contents); |
2786 | free (fsentry->u.symlink.contents); |
2654 | } |
2787 | } |
2655 | else if (S_ISREG (fsentry->header.mode)) |
2788 | else if (S_ISREG (fsentry->header.mode)) |
2656 | { |
2789 | { |
2657 | free (fsentry->u.file.path); |
2790 | free (fsentry->u.file.path); |
2658 | free (fsentry-> |
2791 | free (fsentry->UNSAVED_databuf); |
2659 | } |
2792 | } |
2660 | else if (S_ISFIFO (fsentry->header.mode)) |
2793 | else if (S_ISFIFO (fsentry->header.mode)) |
2661 | free (fsentry->u.device.path); |
2794 | free (fsentry->u.device.path); |
2662 | } |
2795 | } |
2663 | 2796 |