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 | ||