Rev 21 | Rev 24 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 21 | Rev 22 | ||
---|---|---|---|
Line 4... | Line 4... | ||
4 | // TODO: startup file stripping |
4 | // TODO: startup file stripping |
5 | // TODO: boot script compiler |
- | |
6 | 5 | ||
7 | // standard C includes |
6 | // standard C includes |
8 | #include <stdint.h> |
7 | #include <stdint.h> |
9 | #include <stdbool.h> |
8 | #include <stdbool.h> |
10 | #include <stdlib.h> |
9 | #include <stdlib.h> |
Line 62... | Line 61... | ||
62 | #define PATH_SEP ":" // platform-specific PATH element separator (as string), UNIX variant |
61 | #define PATH_SEP ":" // platform-specific PATH element separator (as string), UNIX variant |
63 | #endif // _WIN32 |
62 | #endif // _WIN32 |
64 | #define RECORD_SEP "\x1e" // arbitrarily-chosen ASCII record separator, as a C string suitable for e.g. strtok() |
63 | #define RECORD_SEP "\x1e" // arbitrarily-chosen ASCII record separator, as a C string suitable for e.g. strtok() |
65 | 64 | ||
66 | 65 | ||
- | 66 | // macros for constructing and destructing string arrays |
|
- | 67 | #define STRINGARRAY_INIT(string_array) do { (string_array)->args = NULL; (string_array)->count = 0; } while (0) |
|
67 | #define |
68 | #define STRINGARRAY_PUSH(string_array,str) do { \ |
68 | |
69 | reallocated_ptr = realloc ((string_array)->args, ((string_array)->count + 1) * sizeof (char *)); \ |
- | 70 | ASSERT_WITH_ERRNO (reallocated_ptr); \ |
|
- | 71 | (string_array)->args = reallocated_ptr; \ |
|
69 | |
72 | (string_array)->args[(string_array)->count] = ((str) != NULL ? strdup ((str)) : NULL); \ |
70 | |
73 | if ((str) != NULL) \ |
71 | |
74 | ASSERT_WITH_ERRNO ((string_array)->args[(string_array)->count]); \ |
72 | |
75 | (string_array)->count++; \ |
- | 76 | } while (0) |
|
- | 77 | #define STRINGARRAY_FREE(string_array) do { \ |
|
- | 78 | if ((string_array)->args != NULL) { \ |
|
73 | |
79 | for (array_index = 0; array_index < (string_array)->count; array_index++) \ |
- | 80 | if ((string_array)->args[array_index] != NULL) \ |
|
- | 81 | free ((string_array)->args[array_index]); \ |
|
- | 82 | free ((string_array)->args); \ |
|
- | 83 | (string_array)->args = NULL; \ |
|
- | 84 | } \ |
|
- | 85 | (string_array)->count = 0; \ |
|
74 | |
86 | } while (0) |
- | 87 | ||
- | 88 | ||
- | 89 | // string array structure type definition |
|
- | 90 | typedef struct stringarray_s |
|
- | 91 | { |
|
- | 92 | char **args; |
|
75 |
|
93 | size_t count; |
- | 94 | } stringarray_t; |
|
76 | 95 | ||
77 | 96 | ||
78 | // IFS directory entry insertion parameters structure type definition |
97 | // IFS directory entry insertion parameters structure type definition |
79 | typedef struct parms_s |
98 | typedef struct parms_s |
80 | { |
99 | { |
Line 130... | Line 149... | ||
130 | static char **saved_ELF_sections = NULL; // mallocated array of const strings, populated by the -s command-line argument |
149 | static char **saved_ELF_sections = NULL; // mallocated array of const strings, populated by the -s command-line argument |
131 | static size_t saved_ELF_section_count = 0; // number of elements in the saved_ELF_sections array |
150 | static size_t saved_ELF_section_count = 0; // number of elements in the saved_ELF_sections array |
132 | static char *sym_suffix = ""; // .sym files extra suffix, settable with the -a command-line argument |
151 | static char *sym_suffix = ""; // .sym files extra suffix, settable with the -a command-line argument |
133 | 152 | ||
134 | // bootable IFS support |
153 | // bootable IFS support |
135 | static char *bootfile_pathname = NULL; // HACK: pathname to bootcode binary blob file to put at the start of a bootable IFS |
154 | static char *bootfile_pathname = NULL; // FIXME: HACK: pathname to bootcode binary blob file to put at the start of a bootable IFS |
136 | static size_t bootfile_size = 0; // HACK: size of the bootcode binary blob file to put at the start of a bootable IFS |
155 | static size_t bootfile_size = 0; // FIXME: HACK: size of the bootcode binary blob file to put at the start of a bootable IFS |
137 | static char *startupfile_pathname = NULL; // HACK: pathname to precompiled startup file blob to put in the startup header of a bootable IFS |
156 | static char *startupfile_pathname = NULL; // FIXME: HACK: pathname to precompiled startup file blob to put in the startup header of a bootable IFS |
138 | static size_t startupfile_ep_from_imagebase = 0; // HACK: startup code entrypoint offset from image base for a bootable IFS |
157 | static size_t startupfile_ep_from_imagebase = 0; // FIXME: HACK: startup code entrypoint offset from image base for a bootable IFS |
139 | static size_t kernelfile_offset = 0x32000; // kernel file offset in the IFS (is it ever supposed to change?) |
158 | static size_t kernelfile_offset = 0x32000; // kernel file offset in the IFS (is it ever supposed to change?) |
140 | 159 | ||
141 | 160 | ||
142 | // exported function prototypes |
161 | // exported function prototypes |
143 | 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 |
162 | 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 |
Line 620... | Line 639... | ||
620 | DIE_WITH_EXITCODE (1, "remapping ELF segment would overwrite segment #%zd in the same file", array_index); |
639 | DIE_WITH_EXITCODE (1, "remapping ELF segment would overwrite segment #%zd in the same file", array_index); |
621 | } |
640 | } |
622 | 641 | ||
623 | // finally, memset() the extra area |
642 | // finally, memset() the extra area |
624 | Buffer_WriteAt (file, file_offset + size_in_memory, NULL, 0); // reallocate the ELF file data buffer if necessary |
643 | Buffer_WriteAt (file, file_offset + size_in_memory, NULL, 0); // reallocate the ELF file data buffer if necessary |
- | 644 | phdr = (elf_program_header_t *) &file->bytes[ELF_GET_NUMERIC (ELFHDR, ELFHDR, program_header_table_offset) + (size_t) ELF_GET_NUMERIC (ELFHDR, ELFHDR, program_header_item_size) * table_index]; // restore access to program header (which may have moved) |
|
625 | memset (&file->bytes[file_offset + size_in_file], 0, size_in_memory - size_in_file); // and write zeroes over the extra space |
645 | memset (&file->bytes[file_offset + size_in_file], 0, size_in_memory - size_in_file); // and write zeroes over the extra space |
626 | } |
646 | } |
627 | ELF_SET_NUMERIC (ELFHDR, phdr, size_in_file, size_in_memory); // patch this segment's size in the ELF file so that it matches the RAM size |
647 | ELF_SET_NUMERIC (ELFHDR, phdr, size_in_file, size_in_memory); // patch this segment's size in the ELF file so that it matches the RAM size |
628 | } |
648 | } |
629 | } |
649 | } |
Line 724... | Line 744... | ||
724 | } |
744 | } |
725 | 745 | ||
726 | 746 | ||
727 | static void add_fsentry (fsentry_t **fsentries, size_t *fsentry_count, parms_t *entry_parms, const char *stored_pathname, const char *buildhost_pathname) |
747 | static void add_fsentry (fsentry_t **fsentries, size_t *fsentry_count, parms_t *entry_parms, const char *stored_pathname, const char *buildhost_pathname) |
728 | { |
748 | { |
729 | #define STRINGARRAY_INIT(string_array) do { (string_array)->args = NULL; (string_array)->count = 0; } while (0) |
- | |
730 | #define STRINGARRAY_PUSH(string_array,str) do { \ |
- | |
731 | reallocated_ptr = realloc ((string_array)->args, ((string_array)->count + 1) * sizeof (char *)); \ |
- | |
732 | ASSERT_WITH_ERRNO (reallocated_ptr); \ |
- | |
733 | (string_array)->args = reallocated_ptr; \ |
- | |
734 | (string_array)->args[(string_array)->count] = ((str) != NULL ? strdup ((str)) : NULL); \ |
- | |
735 | if ((str) != NULL) \ |
- | |
736 | ASSERT_WITH_ERRNO ((string_array)->args[(string_array)->count]); \ |
- | |
737 | (string_array)->count++; \ |
- | |
738 | } while (0) |
- | |
739 | #define STRINGARRAY_FREE(string_array) do { \ |
- | |
740 | if ((string_array)->args != NULL) { \ |
- | |
741 | for (array_index = 0; array_index < (string_array)->count; array_index++) \ |
- | |
742 | if ((string_array)->args[array_index] != NULL) \ |
- | |
743 | free ((string_array)->args[array_index]); \ |
- | |
744 | free ((string_array)->args); \ |
- | |
745 | (string_array)->args = NULL; \ |
- | |
746 | } \ |
- | |
747 | (string_array)->count = 0; \ |
- | |
748 | } while (0) |
- | |
749 | - | ||
750 | typedef struct stringarray_s |
- | |
751 | { |
- | |
752 | char **args; |
- | |
753 | size_t count; |
- | |
754 | } stringarray_t; |
- | |
755 | - | ||
756 | static thread_local char *candidate_pathname = NULL; |
749 | static thread_local char *candidate_pathname = NULL; |
757 | static thread_local parms_t default_parms = { 0 }; |
750 | static thread_local parms_t default_parms = { 0 }; |
- | 751 | static thread_local stringarray_t global_envp = { NULL, 0 }; |
|
- | 752 | static thread_local stringarray_t aps_partnames = { NULL, 0 }; |
|
758 | static int inode_count = 0; // will be preincremented each time this function is called |
753 | static int inode_count = 0; // will be preincremented each time this function is called |
759 | 754 | ||
- | 755 | typedef struct scriptcmd_s |
|
- | 756 | { |
|
- | 757 | const char *argv0; |
|
- | 758 | int cpu_number; |
|
- | 759 | bool is_external; |
|
- | 760 | int priority; |
|
- | 761 | int sched_policy; |
|
- | 762 | int aps_partindex; |
|
- | 763 | bool is_session_leader; |
|
- | 764 | bool is_background_task; |
|
- | 765 | bool has_debug_flag; |
|
- | 766 | } scriptcmd_t; |
|
- | 767 | ||
- | 768 | scriptcmd_t default_scriptcmd_params = { NULL, -1, false, -1, -1, -1, false, false, false }; |
|
- | 769 | scriptcmd_t current_scriptcmd_params = { 0 }; |
|
760 | stringarray_t global_argv = { NULL, 0 }; |
770 | stringarray_t global_argv = { NULL, 0 }; |
761 | stringarray_t global_envp = { NULL, 0 }; |
- | |
762 | stringarray_t line_argv = { NULL, 0 }; |
771 | stringarray_t line_argv = { NULL, 0 }; |
763 | stringarray_t line_envp = { NULL, 0 }; |
772 | stringarray_t line_envp = { NULL, 0 }; |
764 | stringarray_t startup_argv = { NULL, 0 }; |
773 | stringarray_t startup_argv = { NULL, 0 }; |
765 | stringarray_t startup_envp = { NULL, 0 }; |
774 | stringarray_t startup_envp = { NULL, 0 }; |
766 | stringarray_t procnto_argv = { NULL, 0 }; |
775 | stringarray_t procnto_argv = { NULL, 0 }; |
767 | stringarray_t procnto_envp = { NULL, 0 }; |
776 | stringarray_t procnto_envp = { NULL, 0 }; |
768 | stringarray_t linker_argv = { NULL, 0 }; |
777 | stringarray_t linker_argv = { NULL, 0 }; |
769 | const char *stored_pathname_without_leading_slash; |
778 | const char *stored_pathname_without_leading_slash; |
770 | const char *original_stored_pathname = NULL; |
779 | const char *original_stored_pathname = NULL; |
771 | buffer_t current_line; |
780 | buffer_t current_line; |
- | 781 | buffer_t compiled_script; |
|
- | 782 | buffer_t compiled_scriptline; |
|
772 | buffer_t *shstrtab = NULL; |
783 | buffer_t *shstrtab = NULL; |
773 | const char *canonical_dylib_name; |
784 | const char *canonical_dylib_name; |
774 | const char *dynamic_strings; // strings table of the ".dynamic" section |
785 | const char *dynamic_strings; // strings table of the ".dynamic" section |
775 | const char *last_dirsep; |
786 | const char *last_dirsep; |
776 | size_t array_index; |
787 | size_t array_index; |
777 | size_t line_index; |
788 | size_t line_index; |
778 | size_t fsentry_index; |
789 | size_t fsentry_index; |
- | 790 | size_t wait_time; |
|
779 | char *resolved_pathname; |
791 | char *resolved_pathname; |
780 | char *linebit_start; |
792 | char *linebit_start; |
781 | char *write_ptr; |
793 | char *write_ptr; |
782 | char *read_ptr; |
794 | char *read_ptr; |
783 | char *token; |
795 | char *token; |
Line 870... | Line 882... | ||
870 | *read_ptr = RECORD_SEP[0]; // turn all spaces outside quoted contexts into an ASCII record separator to ease token splitting |
882 | *read_ptr = RECORD_SEP[0]; // turn all spaces outside quoted contexts into an ASCII record separator to ease token splitting |
871 | read_ptr++; // reach the next unescaped closing square bracket |
883 | read_ptr++; // reach the next unescaped closing square bracket |
872 | } |
884 | } |
873 | if (*read_ptr != ']') |
885 | if (*read_ptr != ']') |
874 | { |
886 | { |
875 | LOG ("warning", 0, "syntax error in \"%s\" line |
887 | LOG ("warning", 0, "syntax error in \"%s\" line %zd of inline document '%s': unterminated attributes block (skipping)", buildfile_pathname, 1 + line_index, stored_pathname); |
876 | continue; // invalid attribute block, skip line |
888 | continue; // invalid attribute block, skip line |
877 | } |
889 | } |
878 | is_end_of_line = (*read_ptr == 0); // see if we're at the end of line already |
890 | is_end_of_line = (*read_ptr == 0); // see if we're at the end of line already |
879 | *read_ptr = 0; // end the attribute block in all cases so that it is a parsable C string |
891 | *read_ptr = 0; // end the attribute block in all cases so that it is a parsable C string |
880 | 892 | ||
Line 890... | Line 902... | ||
890 | else if (strncmp (token, "perms=", 6) == 0) { REACH_TOKEN_VALUE (); entry_parms->perms = (int) read_integer (value); } |
902 | else if (strncmp (token, "perms=", 6) == 0) { REACH_TOKEN_VALUE (); entry_parms->perms = (int) read_integer (value); } |
891 | else if (strcmp (token, "+followlink") == 0) entry_parms->should_follow_symlinks = true; |
903 | else if (strcmp (token, "+followlink") == 0) entry_parms->should_follow_symlinks = true; |
892 | else if (strcmp (token, "-followlink") == 0) entry_parms->should_follow_symlinks = false; |
904 | else if (strcmp (token, "-followlink") == 0) entry_parms->should_follow_symlinks = false; |
893 | else if (strcmp (token, "+keeplinked") == 0) entry_parms->should_keep_ld_output = true; |
905 | else if (strcmp (token, "+keeplinked") == 0) entry_parms->should_keep_ld_output = true; |
894 | else if (strcmp (token, "-keeplinked") == 0) entry_parms->should_keep_ld_output = false; |
906 | else if (strcmp (token, "-keeplinked") == 0) entry_parms->should_keep_ld_output = false; |
895 | else LOG_WARNING ("unimplemented bootstrap executable attribute in \"%s\" line |
907 | else LOG_WARNING ("unimplemented bootstrap executable attribute in \"%s\" line %zd of inline document '%s': '%s'", buildfile_pathname, 1 + line_index, stored_pathname, token); |
896 | #undef REACH_TOKEN_VALUE |
908 | #undef REACH_TOKEN_VALUE |
897 | token = strtok_r (NULL, RECORD_SEP, &ctx); // proceed to next attribute token |
909 | token = strtok_r (NULL, RECORD_SEP, &ctx); // proceed to next attribute token |
898 | } |
910 | } |
899 | 911 | ||
900 | if (is_end_of_line) |
912 | if (is_end_of_line) |
Line 923... | Line 935... | ||
923 | linebit_start = read_ptr; // remember the word (or quoted group of words) starts here |
935 | linebit_start = read_ptr; // remember the word (or quoted group of words) starts here |
924 | write_ptr = read_ptr; |
936 | write_ptr = read_ptr; |
925 | is_quoted_context = (*read_ptr == '"'); // see if we're entering a quoted context or not |
937 | is_quoted_context = (*read_ptr == '"'); // see if we're entering a quoted context or not |
926 | if (is_quoted_context) |
938 | if (is_quoted_context) |
927 | read_ptr++; // skip a possible initial quote in the word |
939 | read_ptr++; // skip a possible initial quote in the word |
928 | while ((*read_ptr != 0) && ((!is_quoted_context && !isspace (*read_ptr)) || (is_quoted_context && (*read_ptr |
940 | while ((*read_ptr != 0) && ((!is_quoted_context && !isspace (*read_ptr)) || (is_quoted_context && (*read_ptr != '"')))) |
929 | { |
941 | { |
930 | if (*read_ptr == '\\') |
942 | if (*read_ptr == '\\') |
931 | read_ptr++; // unescape characters that are escaped with '\' by advancing the read pointer |
943 | read_ptr++; // unescape characters that are escaped with '\' by advancing the read pointer |
932 | *write_ptr++ = *read_ptr++; // recopy characters as we read them |
944 | *write_ptr++ = *read_ptr++; // recopy characters as we read them |
933 | } |
945 | } |
Line 984... | Line 996... | ||
984 | // release the contextual argv/envp arrays |
996 | // release the contextual argv/envp arrays |
985 | STRINGARRAY_FREE (&line_argv); |
997 | STRINGARRAY_FREE (&line_argv); |
986 | STRINGARRAY_FREE (&line_envp); |
998 | STRINGARRAY_FREE (&line_envp); |
987 | 999 | ||
988 | } // end for (line_index = 0; Buffer_GetNthLine (&entry_parms->data, line_index, ¤t_line); line_index++) |
1000 | } // end for (line_index = 0; Buffer_GetNthLine (&entry_parms->data, line_index, ¤t_line); line_index++) |
989 |
|
1001 | Buffer_Forget (&entry_parms->data); // free the inline specification once it's parsed |
990 | entry_parms->data.bytes = NULL; |
- | |
991 | entry_parms->data.size = 0; |
- | |
992 | 1002 | ||
993 | ASSERT (startup_argv.args && startup_argv.args[0] && *startup_argv.args[0], "the QNX startup executable (startup-*) is missing in this bootstrap inline specification"); |
1003 | ASSERT (startup_argv.args && startup_argv.args[0] && *startup_argv.args[0], "the QNX startup executable (startup-*) is missing in this bootstrap inline specification"); |
994 | ASSERT (procnto_argv.args && procnto_argv.args[0] && *procnto_argv.args[0], "the QNX kernel (procnto-*) is missing in this bootstrap inline specification"); |
1004 | ASSERT (procnto_argv.args && procnto_argv.args[0] && *procnto_argv.args[0], "the QNX kernel (procnto-*) is missing in this bootstrap inline specification"); |
995 | 1005 | ||
996 | // now we know which startup and procnto executables to use |
1006 | // now we know which startup and procnto executables to use |
Line 1005... | Line 1015... | ||
1005 | buffer_t bootargs_buffer = { 0 }; |
1015 | buffer_t bootargs_buffer = { 0 }; |
1006 | char *bootargs_location; |
1016 | char *bootargs_location; |
1007 | 1017 | ||
1008 | // construct the arguments that are based on environment variables (infer QNX_HOST from QNX_TARGET) |
1018 | // construct the arguments that are based on environment variables (infer QNX_HOST from QNX_TARGET) |
1009 | #if defined(_WIN32) |
1019 | #if defined(_WIN32) |
1010 | sprintf_s (linker_pathname, sizeof (linker_pathname), "%s/../../host/win64/x86_64/usr/bin/%s-ld.exe", QNX_TARGET, (strcmp (image_processor, "x86_64") == 0 ? "x86_64-pc-nto-qnx8.0.0" : "aarch64-unknown-nto-qnx8.0.0")); // Win32: note the .exe extension |
1020 | sprintf_s (linker_pathname, sizeof (linker_pathname), "%s/../../host/win64/x86_64/usr/bin/%s-ld" /*"-2.41.0"*/ ".exe", QNX_TARGET, (strcmp (image_processor, "x86_64") == 0 ? "x86_64-pc-nto-qnx8.0.0" : "aarch64-unknown-nto-qnx8.0.0")); // Win32: note the .exe extension |
1011 | #elif defined(__linux__) |
1021 | #elif defined(__linux__) |
1012 | sprintf_s (linker_pathname, sizeof (linker_pathname), "%s/../../host/linux/x86_64/usr/bin/%s-ld", QNX_TARGET, (strcmp (image_processor, "x86_64") == 0 ? "x86_64-pc-nto-qnx8.0.0" : "aarch64-unknown-nto-qnx8.0.0")); |
1022 | sprintf_s (linker_pathname, sizeof (linker_pathname), "%s/../../host/linux/x86_64/usr/bin/%s-ld" /*"-2.41.0"*/, QNX_TARGET, (strcmp (image_processor, "x86_64") == 0 ? "x86_64-pc-nto-qnx8.0.0" : "aarch64-unknown-nto-qnx8.0.0")); |
1013 | #elif defined(__QNXNTO__) |
1023 | #elif defined(__QNXNTO__) |
1014 | sprintf_s (linker_pathname, sizeof (linker_pathname), "%s/../../host/qnx8/x86_64/usr/bin/%s-ld", QNX_TARGET, (strcmp (image_processor, "x86_64") == 0 ? "x86_64-pc-nto-qnx8.0.0" : "aarch64-unknown-nto-qnx8.0.0")); |
1024 | sprintf_s (linker_pathname, sizeof (linker_pathname), "%s/../../host/qnx8/x86_64/usr/bin/%s-ld" /*"-2.41.0"*/, QNX_TARGET, (strcmp (image_processor, "x86_64") == 0 ? "x86_64-pc-nto-qnx8.0.0" : "aarch64-unknown-nto-qnx8.0.0")); |
1015 | #else // wtf are you building this on? |
1025 | #else // wtf are you building this on? |
1016 | #error Please port the GNU linker x86_64-pc-nto-qnx8.0.0-ld and aarch64-unknown-nto-qnx8.0.0-ld to your host architecture first before compiling ifstool. |
1026 | #error Please port the GNU linker x86_64-pc-nto-qnx8.0.0-ld and aarch64-unknown-nto-qnx8.0.0-ld to your host architecture first before compiling ifstool. |
1017 | #endif |
1027 | #endif |
1018 | ASSERT (access (linker_pathname, 0) == 0, "host cross-linker for QNX8 \"%s\" not found", linker_pathname); |
1028 | ASSERT (access (linker_pathname, 0) == 0, "host cross-linker for QNX8 \"%s\" not found", linker_pathname); |
1019 | sprintf_s (linker_sysroot_arg, sizeof (linker_sysroot_arg), "--sysroot=%s/%s/", QNX_TARGET, image_processor); |
1029 | sprintf_s (linker_sysroot_arg, sizeof (linker_sysroot_arg), "--sysroot=%s/%s/", QNX_TARGET, image_processor); |
Line 1034... | Line 1044... | ||
1034 | STRINGARRAY_PUSH (&linker_argv, ".text=0xffff800000001000"); |
1044 | STRINGARRAY_PUSH (&linker_argv, ".text=0xffff800000001000"); |
1035 | STRINGARRAY_PUSH (&linker_argv, "--no-relax"); |
1045 | STRINGARRAY_PUSH (&linker_argv, "--no-relax"); |
1036 | STRINGARRAY_PUSH (&linker_argv, procnto_buildhost_pathname); // "${QNX_TARGET}/${TARGET_CPU}/boot/sys/procnto-smp-instr" |
1046 | STRINGARRAY_PUSH (&linker_argv, procnto_buildhost_pathname); // "${QNX_TARGET}/${TARGET_CPU}/boot/sys/procnto-smp-instr" |
1037 | STRINGARRAY_PUSH (&linker_argv, "-o"); |
1047 | STRINGARRAY_PUSH (&linker_argv, "-o"); |
1038 | STRINGARRAY_PUSH (&linker_argv, procnto_sym_filename); // "procnto-smp-instr.sym" |
1048 | STRINGARRAY_PUSH (&linker_argv, procnto_sym_filename); // "procnto-smp-instr.sym" |
- | 1049 | #ifdef __GNUC__ |
|
- | 1050 | #pragma GCC diagnostic push |
|
- | 1051 | #pragma GCC diagnostic ignored "-Wnonnull" // the GCC linter is wrong here: I *do* check for NULL before calling strdup() |
|
- | 1052 | #endif // __GNUC__ |
|
1039 | STRINGARRAY_PUSH (&linker_argv, NULL); // don't forget to terminate the argv array with a NULL pointer |
1053 | STRINGARRAY_PUSH (&linker_argv, NULL); // don't forget to terminate the argv array with a NULL pointer |
- | 1054 | #ifdef __GNUC__ |
|
- | 1055 | #pragma GCC diagnostic pop |
|
- | 1056 | #endif // __GNUC__ |
|
1040 | if (verbose_level > 2) |
1057 | if (verbose_level > 2) |
1041 | { |
1058 | { |
1042 | fprintf (stderr, "ifstool: calling:"); |
1059 | fprintf (stderr, "ifstool: calling:"); |
1043 | for (array_index = 0; array_index < linker_argv.count - 1; array_index++) |
1060 | for (array_index = 0; array_index < linker_argv.count - 1; array_index++) |
1044 | fprintf (stderr, " '%s'", linker_argv.args[array_index]); |
1061 | fprintf (stderr, " '%s'", linker_argv.args[array_index]); |
Line 1049... | Line 1066... | ||
1049 | #else // !_WIN32, thus POSIX |
1066 | #else // !_WIN32, thus POSIX |
1050 | do { |
1067 | do { |
1051 | int status; |
1068 | int status; |
1052 | pid_t pid = fork (); // duplicate ourselves so as to create a new process |
1069 | pid_t pid = fork (); // duplicate ourselves so as to create a new process |
1053 | ASSERT_WITH_ERRNO (pid != -1); |
1070 | ASSERT_WITH_ERRNO (pid != -1); |
1054 | if (pid == 0) |
1071 | if (pid == 0) // we are the child |
1055 | { |
1072 | { |
1056 | execv (linker_pathname, linker_argv); // |
1073 | execv (linker_pathname, linker_argv.args); // execute the linker and produce a stripped procnto (wait for completion) |
1057 | DIE_WITH_EXITCODE (1, "execve() failed"); // exec never returns |
1074 | DIE_WITH_EXITCODE (1, "execve() failed"); // exec never returns |
1058 | } |
1075 | } |
1059 | else |
1076 | else // we are the parent |
1060 | waitpid (pid, &status, 0); // wait for the child to finish |
1077 | waitpid (pid, &status, 0); // wait for the child to finish |
1061 | } while (0); |
1078 | } while (0); |
1062 | #endif // _WIN32 |
1079 | #endif // _WIN32 |
1063 | STRINGARRAY_FREE (&linker_argv); |
1080 | STRINGARRAY_FREE (&linker_argv); |
1064 | if (!Buffer_ReadFromFile (&entry_parms->data, procnto_sym_filename)) // load the output file |
1081 | if (!Buffer_ReadFromFile (&entry_parms->data, procnto_sym_filename)) // load the output file |
Line 1094... | Line 1111... | ||
1094 | entry_parms->st_mode = S_IFREG | entry_parms->perms; // procnto is a regular file |
1111 | entry_parms->st_mode = S_IFREG | entry_parms->perms; // procnto is a regular file |
1095 | image_kernel_ino = entry_parms->extra_ino_flags | (inode_count + 1); |
1112 | image_kernel_ino = entry_parms->extra_ino_flags | (inode_count + 1); |
1096 | 1113 | ||
1097 | STRINGARRAY_FREE (&procnto_argv); // release procnto's argv array |
1114 | STRINGARRAY_FREE (&procnto_argv); // release procnto's argv array |
1098 | STRINGARRAY_FREE (&procnto_envp); // release procnto's envp array |
1115 | STRINGARRAY_FREE (&procnto_envp); // release procnto's envp array |
1099 | STRINGARRAY_FREE |
1116 | //STRINGARRAY_FREE (&global_envp); // DO NOT release the global envp array. It is inherited by the boot scripts. |
1100 | } |
1117 | } // end of "is bootstrap file" |
1101 | else if (entry_parms->is_compiled_bootscript) // else is it a startup script ? |
1118 | else if (entry_parms->is_compiled_bootscript) // else is it a startup script that we need to compile ? |
- | 1119 | { |
|
1102 | image_bootscript_ino = inode_count + 1; // save boot script inode number for image header |
1120 | image_bootscript_ino = inode_count + 1; // save boot script inode number for image header |
- | 1121 | Buffer_Initialize (&compiled_script); |
|
- | 1122 | ||
- | 1123 | // parse buffer (non-destructively) line after line |
|
- | 1124 | Buffer_Initialize (¤t_line); |
|
- | 1125 | for (line_index = 0; Buffer_GetNthLine (&entry_parms->data, line_index, ¤t_line); line_index++) |
|
- | 1126 | { |
|
- | 1127 | read_ptr = current_line.bytes; |
|
- | 1128 | while (isspace (*read_ptr)) |
|
- | 1129 | read_ptr++; // skip leading spaces |
|
- | 1130 | if ((*read_ptr == '#') || (*read_ptr == 0)) |
|
- | 1131 | continue; // skip comments and empty lines |
|
- | 1132 | ||
- | 1133 | // format of a line: [attributes] [env assignation] [...] [executable] [arg] [...] [&] [comment] |
|
- | 1134 | // example: "[pri=20f] devc-con -n9 &" |
|
- | 1135 | ||
- | 1136 | LOG_DEBUG ("parsing line: %s", read_ptr); |
|
- | 1137 | Buffer_Initialize (&compiled_scriptline); |
|
- | 1138 | memcpy (¤t_scriptcmd_params, &default_scriptcmd_params, sizeof (default_scriptcmd_params)); |
|
- | 1139 | ||
- | 1140 | // does this line start with an attribute block ? |
|
- | 1141 | if (*read_ptr == '[') |
|
- | 1142 | { |
|
- | 1143 | read_ptr++; // skip the leading square bracket |
|
- | 1144 | linebit_start = read_ptr; // remember where it starts |
|
- | 1145 | is_quoted_context = false; // reach the next unescaped closing square bracket that is not between quotes |
|
- | 1146 | while ((*read_ptr != 0) && !((*read_ptr == ']') && (read_ptr[-1] != '\\') && !is_quoted_context)) |
|
- | 1147 | { |
|
- | 1148 | if (*read_ptr == '"') |
|
- | 1149 | is_quoted_context ^= true; // remember when we're between quotes |
|
- | 1150 | else if (!is_quoted_context && (*read_ptr == ' ')) |
|
- | 1151 | *read_ptr = RECORD_SEP[0]; // turn all spaces outside quoted contexts into an ASCII record separator to ease token splitting |
|
- | 1152 | read_ptr++; // reach the next unescaped closing square bracket |
|
- | 1153 | } |
|
- | 1154 | if (*read_ptr != ']') |
|
- | 1155 | { |
|
- | 1156 | LOG ("warning", 0, "syntax error in \"%s\" line %zd of inline document '%s': unterminated attributes block (skipping)", buildfile_pathname, 1 + line_index, stored_pathname); |
|
- | 1157 | continue; // invalid attribute block, skip line |
|
- | 1158 | } |
|
- | 1159 | is_end_of_line = (*read_ptr == 0); // see if we're at the end of line already |
|
- | 1160 | *read_ptr = 0; // end the attribute block in all cases so that it is a parsable C string |
|
- | 1161 | ||
- | 1162 | // now parse the attribute tokens |
|
- | 1163 | token = strtok_r (linebit_start, RECORD_SEP, &ctx); |
|
- | 1164 | while (token != NULL) |
|
- | 1165 | { |
|
- | 1166 | #define REACH_TOKEN_VALUE() do { value = strchr (token, '=') + 1; if (*value == '"') value++; } while (0) |
|
- | 1167 | if (false) {} |
|
- | 1168 | else if (strncmp (token, "argv0=", 6) == 0) { REACH_TOKEN_VALUE (); current_scriptcmd_params.argv0 = value; } // NOTE: stolen pointer. Do not free. |
|
- | 1169 | else if (strncmp (token, "cpu=", 4) == 0) { REACH_TOKEN_VALUE (); current_scriptcmd_params.cpu_number = (int) atoi (value); } |
|
- | 1170 | else if (strncmp (token, "pri=", 4) == 0) { REACH_TOKEN_VALUE (); current_scriptcmd_params.priority = (int) strtol (value, &ctx, 0); if (ctx != NULL) current_scriptcmd_params.sched_policy = (*ctx == 'f' ? SCRIPTCMD_SCHEDULERPOLICY_FIFO : SCRIPTCMD_SCHEDULERPOLICY_RR); } |
|
- | 1171 | else if (strncmp (token, "sched_aps=", 10) == 0) { REACH_TOKEN_VALUE (); |
|
- | 1172 | for (array_index = 0; array_index < aps_partnames.count; array_index++) if (strcmp (aps_partnames.args[array_index], value) == 0) break; |
|
- | 1173 | if (array_index == aps_partnames.count) |
|
- | 1174 | DIE_WITH_EXITCODE (1, "syntax error in \"%s\" line %zd of inline document '%s': APS partition name '%s' not found: please declare it first", buildfile_pathname, 1 + line_index, stored_pathname, value); // consistency check (TODO: check that the sum of all budgets don't exceed 100%) |
|
- | 1175 | current_scriptcmd_params.aps_partindex = (int) array_index; |
|
- | 1176 | } |
|
- | 1177 | else if (strcmp (token, "+external") == 0) current_scriptcmd_params.is_external = true; |
|
- | 1178 | else if (strcmp (token, "-external") == 0) current_scriptcmd_params.is_external = false; |
|
- | 1179 | else if (strcmp (token, "+session") == 0) current_scriptcmd_params.is_session_leader = true; |
|
- | 1180 | else if (strcmp (token, "-session") == 0) current_scriptcmd_params.is_session_leader = false; |
|
- | 1181 | else if (strcmp (token, "+debug") == 0) current_scriptcmd_params.has_debug_flag = true; |
|
- | 1182 | else if (strcmp (token, "-debug") == 0) current_scriptcmd_params.has_debug_flag = false; |
|
- | 1183 | else LOG_WARNING ("unimplemented boot script modifier in \"%s\" line %zd of inline document '%s': '%s'", buildfile_pathname, 1 + line_index, stored_pathname, token); |
|
- | 1184 | #undef REACH_TOKEN_VALUE |
|
- | 1185 | token = strtok_r (NULL, RECORD_SEP, &ctx); // proceed to next attribute token |
|
- | 1186 | } |
|
- | 1187 | ||
- | 1188 | if (is_end_of_line) |
|
- | 1189 | continue; // if end of line was reached, proceed to the next line |
|
- | 1190 | else |
|
- | 1191 | read_ptr++; // else reach the next character (after the NUL split) and continue processing the same line |
|
- | 1192 | } // end of "this line starts with an attributes block" |
|
- | 1193 | ||
- | 1194 | // at this point we are past the attributes block |
|
- | 1195 | ||
- | 1196 | // reset contextual argv/envp arrays |
|
- | 1197 | line_argv.args = NULL; |
|
- | 1198 | line_argv.count = 0; |
|
- | 1199 | line_envp.args = NULL; |
|
- | 1200 | line_envp.count = 0; |
|
- | 1201 | ||
- | 1202 | // now read each word (or quoted group of words), unescaping escaped characters |
|
- | 1203 | while (*read_ptr != 0) |
|
- | 1204 | { |
|
- | 1205 | while ((*read_ptr != 0) && isspace (*read_ptr)) |
|
- | 1206 | read_ptr++; // skip intermediate spaces and reach the next word |
|
- | 1207 | ||
- | 1208 | if (*read_ptr == '#') |
|
- | 1209 | break; // if the rest of the line is commented out, stop parsing it and proceed to the next line |
|
- | 1210 | ||
- | 1211 | linebit_start = read_ptr; // remember the word (or quoted group of words) starts here |
|
- | 1212 | write_ptr = read_ptr; |
|
- | 1213 | is_quoted_context = (*read_ptr == '"'); // see if we're entering a quoted context or not |
|
- | 1214 | if (is_quoted_context) |
|
- | 1215 | read_ptr++; // skip a possible initial quote in the word |
|
- | 1216 | while ((*read_ptr != 0) && ((!is_quoted_context && !isspace (*read_ptr)) || (is_quoted_context && (*read_ptr != '"')))) |
|
- | 1217 | { |
|
- | 1218 | if (*read_ptr == '\\') |
|
- | 1219 | read_ptr++; // unescape characters that are escaped with '\' by advancing the read pointer |
|
- | 1220 | *write_ptr++ = *read_ptr++; // recopy characters as we read them |
|
- | 1221 | } |
|
- | 1222 | is_end_of_line = (*read_ptr == 0); // see if we're at the end of line already |
|
- | 1223 | *write_ptr = 0; // stop the rewritten string here |
|
- | 1224 | ||
- | 1225 | // end of word, i.e. we reached either a closing quote or a space. The string bit has been rewritted at linebit_start without quotes and with characters unescaped. |
|
- | 1226 | STRINGARRAY_PUSH (&line_argv, linebit_start); |
|
- | 1227 | LOG_DEBUG ("collected bootscript argv: [%s]", linebit_start); |
|
- | 1228 | ||
- | 1229 | if (!is_end_of_line) |
|
- | 1230 | read_ptr++; // if we haven't reach the end of the line yet, advance to the next character (after the NUL split) |
|
- | 1231 | } // end while (*read_ptr != 0) |
|
- | 1232 | ||
- | 1233 | // we finished parsing the line |
|
- | 1234 | ||
- | 1235 | // did we fill an executable argv? As per QNX docs, the first executable must be startup-*, the last executable must be procnto. |
|
- | 1236 | if (line_argv.count > 0) |
|
- | 1237 | { |
|
- | 1238 | // is it one of the few builtin commands ? |
|
- | 1239 | if (!current_scriptcmd_params.is_external && (strcmp (line_argv.args[0], "waitfor") == 0)) |
|
- | 1240 | { |
|
- | 1241 | if (line_argv.count < 2) |
|
- | 1242 | DIE_WITH_EXITCODE (1, "syntax error in \"%s\" line %zd of inline document '%s': waitfor requires 1 or 2 arguments", buildfile_pathname, 1 + line_index, stored_pathname); |
|
- | 1243 | ||
- | 1244 | ASSERT_WITH_ERRNO (Buffer_InitWithData (&compiled_scriptline, "##" SCRIPTCMD_TYPE_WAITFOR "\x00", 4)); // size as u16LE, type, spare |
|
- | 1245 | wait_time = (line_argv.count > 2 ? (size_t) (10.0 * atof (line_argv.args[2])) : 50); // convert dotted number to tenths of seconds. Default to 5 seconds (50 tenths) |
|
- | 1246 | if (wait_time > 0xffff) |
|
- | 1247 | wait_time = 0xffff; |
|
- | 1248 | ASSERT_WITH_ERRNO (Buffer_WriteInt8At (&compiled_scriptline, 4, (wait_time >> 0) & 0xff)); // wait time lo |
|
- | 1249 | ASSERT_WITH_ERRNO (Buffer_WriteInt8At (&compiled_scriptline, 5, (wait_time >> 8) & 0xff)); // wait time hi |
|
- | 1250 | ASSERT_WITH_ERRNO (Buffer_Append (&compiled_scriptline, line_argv.args[1], strlen (line_argv.args[1]) + 1)); |
|
- | 1251 | } |
|
- | 1252 | else if (!current_scriptcmd_params.is_external && (strcmp (line_argv.args[0], "reopen") == 0)) |
|
- | 1253 | { |
|
- | 1254 | ASSERT_WITH_ERRNO (Buffer_InitWithData (&compiled_scriptline, "##" SCRIPTCMD_TYPE_REOPEN "\x00", 4)); // size as u16LE, type, spare |
|
- | 1255 | wait_time = (line_argv.count > 2 ? (size_t) (10.0 * atof (line_argv.args[2])) : 50); // convert dotted number to tenths of seconds. Default to 5 seconds (50 tenths) |
|
- | 1256 | if (wait_time > 0xffff) |
|
- | 1257 | wait_time = 0xffff; |
|
- | 1258 | ASSERT_WITH_ERRNO (Buffer_WriteInt8At (&compiled_scriptline, 4, (wait_time >> 0) & 0xff)); // wait time lo |
|
- | 1259 | ASSERT_WITH_ERRNO (Buffer_WriteInt8At (&compiled_scriptline, 5, (wait_time >> 8) & 0xff)); // wait time hi |
|
- | 1260 | ASSERT_WITH_ERRNO (Buffer_Append (&compiled_scriptline, (line_argv.count > 1 ? line_argv.args[1] : "/dev/console"), strlen (line_argv.count > 1 ? line_argv.args[1] : "/dev/console") + 1)); |
|
- | 1261 | } |
|
- | 1262 | else if (!current_scriptcmd_params.is_external && (strcmp (line_argv.args[0], "display_msg") == 0)) |
|
- | 1263 | { |
|
- | 1264 | ASSERT_WITH_ERRNO (Buffer_InitWithData (&compiled_scriptline, "##" SCRIPTCMD_TYPE_DISPLAY_MSG "\x00", 4)); // size as u16LE, type, spare |
|
- | 1265 | for (array_index = 1; array_index < line_argv.count; array_index++) |
|
- | 1266 | { |
|
- | 1267 | if (array_index > 1) |
|
- | 1268 | ASSERT_WITH_ERRNO (Buffer_AppendByteArray (&compiled_scriptline, " ")); // separate each arg with a space |
|
- | 1269 | ASSERT_WITH_ERRNO (Buffer_Append (&compiled_scriptline, line_argv.args[array_index], strlen (line_argv.args[array_index]))); |
|
- | 1270 | } |
|
- | 1271 | ASSERT_WITH_ERRNO (Buffer_AppendByteArray (&compiled_scriptline, "\n\0")); // don't forget to append a newline to the message printed |
|
- | 1272 | } |
|
- | 1273 | else if (!current_scriptcmd_params.is_external && (strcmp (line_argv.args[0], "procmgr_symlink") == 0)) |
|
- | 1274 | { |
|
- | 1275 | if (line_argv.count < 3) |
|
- | 1276 | DIE_WITH_EXITCODE (1, "syntax error in \"%s\" line %zd of inline document '%s': procmgr_symlink requires 2 arguments", buildfile_pathname, 1 + line_index, stored_pathname); |
|
- | 1277 | ||
- | 1278 | ASSERT_WITH_ERRNO (Buffer_InitWithData (&compiled_scriptline, "##" SCRIPTCMD_TYPE_PROCMGR_SYMLINK "\x00", 4)); // size as u16LE, type, spare |
|
- | 1279 | ASSERT_WITH_ERRNO (Buffer_Append (&compiled_scriptline, line_argv.args[1], strlen (line_argv.args[1]) + 1)); |
|
- | 1280 | ASSERT_WITH_ERRNO (Buffer_Append (&compiled_scriptline, line_argv.args[2], strlen (line_argv.args[2]) + 1)); |
|
- | 1281 | } |
|
- | 1282 | else if (!current_scriptcmd_params.is_external && (strcmp (line_argv.args[0], "sched_aps") == 0)) |
|
- | 1283 | { |
|
- | 1284 | token = (line_argv.count > 1 ? line_argv.args[1] : "System"); |
|
- | 1285 | if ((strlen (token) > 15) || (strchr (token, '/') != NULL)) |
|
- | 1286 | DIE_WITH_EXITCODE (1, "syntax error in \"%s\" line %zd of inline document '%s': APS partition names must be less than 16 characters long and not contain a '/' separator", buildfile_pathname, 1 + line_index, stored_pathname); // consistency check (TODO: check that the sum of all budgets don't exceed 100%) |
|
- | 1287 | for (array_index = 0; array_index < aps_partnames.count; array_index++) |
|
- | 1288 | if (strcmp (aps_partnames.args[array_index], token) == 0) |
|
- | 1289 | break; // find the APS partition ID in the global APS partition names table |
|
- | 1290 | if (array_index == aps_partnames.count) |
|
- | 1291 | STRINGARRAY_PUSH (&aps_partnames, token); // if not found, add a new partition name to the table |
|
- | 1292 | ASSERT_WITH_ERRNO (Buffer_InitWithData (&compiled_scriptline, "##" SCRIPTCMD_TYPE_EXTSCHED_APS "\x00", 4)); // size as u16LE, type, spare |
|
- | 1293 | ASSERT_WITH_ERRNO (Buffer_WriteInt8At (&compiled_scriptline, 4, 0)); // parent (system partition) |
|
- | 1294 | ASSERT_WITH_ERRNO (Buffer_WriteInt8At (&compiled_scriptline, 5, (line_argv.count > 2 ? (uint8_t) atoi (line_argv.args[2]) : 0))); // budget |
|
- | 1295 | ASSERT_WITH_ERRNO (Buffer_WriteInt8At (&compiled_scriptline, 6, ((line_argv.count > 3 ? (uint8_t) atoi (line_argv.args[3]) : 0) >> 0) & 0xff)); // critical lo |
|
- | 1296 | ASSERT_WITH_ERRNO (Buffer_WriteInt8At (&compiled_scriptline, 7, ((line_argv.count > 3 ? (uint8_t) atoi (line_argv.args[3]) : 0) >> 8) & 0xff)); // critical hi |
|
- | 1297 | ASSERT_WITH_ERRNO (Buffer_WriteInt8At (&compiled_scriptline, 8, (uint8_t) array_index)); // APS partition ID |
|
- | 1298 | ASSERT_WITH_ERRNO (Buffer_Append (&compiled_scriptline, token, strlen (token) + 1)); // partition name |
|
- | 1299 | } |
|
- | 1300 | else // not a builtin, which means it is an external command |
|
- | 1301 | { |
|
- | 1302 | if (strcmp (line_argv.args[line_argv.count - 1], "&") == 0) // is the last argument an ampersand (fork sign) on its own ? (variant 1) |
|
- | 1303 | { |
|
- | 1304 | current_scriptcmd_params.is_background_task = true; // remember this is a background task |
|
- | 1305 | free (line_argv.args[line_argv.count - 1]); // prevent leaking the last arg |
|
- | 1306 | line_argv.count--; // and adjust the arg count |
|
- | 1307 | } |
|
- | 1308 | else if (((token = strrchr (line_argv.args[line_argv.count - 1], '&')) != NULL) && (token[1] == 0)) // else does the last argument END with a fork sign ? (variant 2) |
|
- | 1309 | { |
|
- | 1310 | current_scriptcmd_params.is_background_task = true; // remember this is a background task |
|
- | 1311 | *token = 0; // and chop off the ampersand from that arg |
|
- | 1312 | } |
|
- | 1313 | ||
- | 1314 | ASSERT_WITH_ERRNO (Buffer_InitWithData (&compiled_scriptline, "##" SCRIPTCMD_TYPE_EXTERNAL "\x00", 4)); // size as u16LE, type, spare |
|
- | 1315 | ASSERT_WITH_ERRNO (Buffer_WriteInt8At (&compiled_scriptline, 4, (current_scriptcmd_params.cpu_number != -1 ? (uint8_t) current_scriptcmd_params.cpu_number : 0))); // CPU |
|
- | 1316 | ASSERT_WITH_ERRNO (Buffer_WriteInt8At (&compiled_scriptline, 5, (current_scriptcmd_params.aps_partindex != -1 ? SCRIPTCMD_FLAG_EXTSCHED : 0) |
|
- | 1317 | | (current_scriptcmd_params.is_session_leader ? SCRIPTCMD_FLAG_SESSION : 0) |
|
- | 1318 | | (current_scriptcmd_params.sched_policy != -1 ? SCRIPTCMD_FLAG_SCHED_SET : 0) |
|
- | 1319 | | (current_scriptcmd_params.cpu_number != -1 ? SCRIPTCMD_FLAG_CPU_SET : 0) |
|
- | 1320 | | (current_scriptcmd_params.is_background_task ? SCRIPTCMD_FLAG_BACKGROUND : 0) |
|
- | 1321 | | (current_scriptcmd_params.has_debug_flag ? SCRIPTCMD_FLAG_KDEBUG : 0))); // flags |
|
- | 1322 | ASSERT_WITH_ERRNO (Buffer_WriteInt8At (&compiled_scriptline, 6, (current_scriptcmd_params.aps_partindex != -1 ? (uint8_t) current_scriptcmd_params.aps_partindex : 0))); // adaptative partitioning ID |
|
- | 1323 | ASSERT_WITH_ERRNO (Buffer_WriteInt8At (&compiled_scriptline, 7, 0)); // reserved |
|
- | 1324 | ASSERT_WITH_ERRNO (Buffer_WriteInt8At (&compiled_scriptline, 8, (current_scriptcmd_params.sched_policy != -1 ? current_scriptcmd_params.sched_policy : 0))); // scheduling policy |
|
- | 1325 | ASSERT_WITH_ERRNO (Buffer_WriteInt8At (&compiled_scriptline, 9, (current_scriptcmd_params.priority != -1 ? current_scriptcmd_params.priority : 0))); // scheduling priority |
|
- | 1326 | ASSERT_WITH_ERRNO (Buffer_WriteInt8At (&compiled_scriptline, 10, (uint8_t) line_argv.count)); // argc |
|
- | 1327 | ASSERT_WITH_ERRNO (Buffer_WriteInt8At (&compiled_scriptline, 11, (uint8_t) global_envp.count)); // envc |
|
- | 1328 | ASSERT_WITH_ERRNO (Buffer_Append (&compiled_scriptline, line_argv.args[0], strlen (line_argv.args[0]) + 1)); // executable |
|
- | 1329 | ASSERT_WITH_ERRNO (Buffer_Append (&compiled_scriptline, (current_scriptcmd_params.argv0 != NULL ? current_scriptcmd_params.argv0 : line_argv.args[0]), strlen (current_scriptcmd_params.argv0 != NULL ? current_scriptcmd_params.argv0 : line_argv.args[0]) + 1)); // argv[0] |
|
- | 1330 | for (array_index = 1; array_index < line_argv.count; array_index++) |
|
- | 1331 | ASSERT_WITH_ERRNO (Buffer_Append (&compiled_scriptline, line_argv.args[array_index], strlen (line_argv.args[array_index]) + 1)); // argv[n] |
|
- | 1332 | for (array_index = 0; array_index < global_envp.count; array_index++) |
|
- | 1333 | ASSERT_WITH_ERRNO (Buffer_Append (&compiled_scriptline, global_envp.args[array_index], strlen (global_envp.args[array_index]) + 1)); // envp[n] |
|
- | 1334 | } |
|
- | 1335 | ASSERT_WITH_ERRNO (Buffer_PadWithZeroesTo (&compiled_scriptline, ROUND_TO_UPPER_MULTIPLE (compiled_scriptline.size, 4))); // pad compiled command buffer to upper 32-bit multiple |
|
- | 1336 | ||
- | 1337 | // fix the size of this compiled boot script command |
|
- | 1338 | ASSERT_WITH_ERRNO (Buffer_WriteInt8At (&compiled_scriptline, 0, (compiled_scriptline.size >> 0) & 0xff)); // size lo |
|
- | 1339 | ASSERT_WITH_ERRNO (Buffer_WriteInt8At (&compiled_scriptline, 1, (compiled_scriptline.size >> 8) & 0xff)); // size hi |
|
- | 1340 | ||
- | 1341 | // now concatenate this newly compiled boot script line to the compiled boot script buffer |
|
- | 1342 | ASSERT_WITH_ERRNO (Buffer_AppendBuffer (&compiled_script, &compiled_scriptline)); |
|
- | 1343 | Buffer_Forget (&compiled_scriptline); |
|
- | 1344 | } |
|
- | 1345 | else // this line contained no executable invokation, so make the parameters that changed the default ones |
|
- | 1346 | { |
|
- | 1347 | #define APPLY_DEFAULT_ATTR_NUM(attr,descr,fmt) do { if (current_scriptcmd_params.attr != default_scriptcmd_params.attr) { \ |
|
- | 1348 | LOG_INFO ("changing default " descr " from " fmt " to " fmt " by attribute at \"%s\" line %zd of inline document '%s'", default_scriptcmd_params.attr, current_scriptcmd_params.attr, buildfile_pathname, 1 + line_index, stored_pathname); \ |
|
- | 1349 | default_scriptcmd_params.attr = current_scriptcmd_params.attr; \ |
|
- | 1350 | } } while (0) |
|
- | 1351 | #define APPLY_DEFAULT_ATTR_STR(attr,descr,fmt) do { if (((default_scriptcmd_params.attr == NULL) && (current_scriptcmd_params.attr != NULL)) || ((default_scriptcmd_params.attr != NULL) && (current_scriptcmd_params.attr == NULL)) || ((default_scriptcmd_params.attr != NULL) && (current_scriptcmd_params.attr != NULL) && (strcmp (current_scriptcmd_params.attr, default_scriptcmd_params.attr) != 0))) { \ |
|
- | 1352 | LOG_INFO ("changing default " descr " from " fmt " to " fmt " by attribute at \"%s\" line %zd of inline document '%s'", (default_scriptcmd_params.attr != NULL ? default_scriptcmd_params.attr : "none"), current_scriptcmd_params.attr, buildfile_pathname, 1 + line_index, stored_pathname); \ |
|
- | 1353 | default_scriptcmd_params.attr = current_scriptcmd_params.attr; \ |
|
- | 1354 | } } while (0) |
|
- | 1355 | APPLY_DEFAULT_ATTR_STR (argv0, "executable name", "\"%s\""); |
|
- | 1356 | APPLY_DEFAULT_ATTR_NUM (cpu_number, "CPU mask", "0%o"); |
|
- | 1357 | APPLY_DEFAULT_ATTR_NUM (is_external, "external command flag", "0%o"); |
|
- | 1358 | APPLY_DEFAULT_ATTR_NUM (priority, "scheduling priority", "0%o"); |
|
- | 1359 | APPLY_DEFAULT_ATTR_NUM (sched_policy, "scheduling policy", "0%o"); |
|
- | 1360 | APPLY_DEFAULT_ATTR_NUM (aps_partindex, "APS partition index", "0%o"); |
|
- | 1361 | APPLY_DEFAULT_ATTR_NUM (is_session_leader, "session leader flag", "0%o"); |
|
- | 1362 | APPLY_DEFAULT_ATTR_NUM (is_background_task, "background task flag", "0%o"); |
|
- | 1363 | APPLY_DEFAULT_ATTR_NUM (has_debug_flag, "debug flag", "0%o"); |
|
- | 1364 | #undef APPLY_DEFAULT_ATTR_STR |
|
- | 1365 | #undef APPLY_DEFAULT_ATTR_NUM |
|
- | 1366 | } |
|
- | 1367 | ||
- | 1368 | // release the contextual argv/envp arrays |
|
- | 1369 | STRINGARRAY_FREE (&line_argv); |
|
- | 1370 | STRINGARRAY_FREE (&line_envp); |
|
- | 1371 | ||
- | 1372 | } // end for (line_index = 0; Buffer_GetNthLine (&entry_parms->data, line_index, ¤t_line); line_index++) |
|
- | 1373 | Buffer_Forget (&entry_parms->data); // free the inline specification once it's parsed |
|
- | 1374 | ||
- | 1375 | ASSERT_WITH_ERRNO (Buffer_AppendByteArray (&compiled_script, "\x00\x00\x00\x00")); // terminate the compiled boot script with a 4-byte trailer |
|
- | 1376 | entry_parms->data.bytes = compiled_script.bytes; // and steal the compiled boot script buffer |
|
- | 1377 | entry_parms->data.size = compiled_script.size; |
|
- | 1378 | } // end of "is compiled bootscript" |
|
1103 | 1379 | ||
1104 | // do we already know the data for this data blob ? |
1380 | // do we already know the data for this data blob ? |
1105 | if (entry_parms->data.bytes != NULL) |
1381 | if (entry_parms->data.bytes != NULL) |
1106 | { |
1382 | { |
1107 | entry_parms->mtime = entry_parms->mtime_for_inline_files; // if so, set it a mtime equal to the mtime to use for inline files |
1383 | entry_parms->mtime = entry_parms->mtime_for_inline_files; // if so, set it a mtime equal to the mtime to use for inline files |
Line 1438... | Line 1714... | ||
1438 | if ((sep = strchr (value, '=')) != NULL) image_totalsize = (uint32_t) read_integer (sep + 1); // if we have an equal sign, read optional image padding size |
1714 | if ((sep = strchr (value, '=')) != NULL) image_totalsize = (uint32_t) read_integer (sep + 1); // if we have an equal sign, read optional image padding size |
1439 | if ((sep = strchr (value, '%')) != NULL) image_align = (uint32_t) read_integer (sep + 1); // if we have a modulo sign, read optional image aligmnent |
1715 | if ((sep = strchr (value, '%')) != NULL) image_align = (uint32_t) read_integer (sep + 1); // if we have a modulo sign, read optional image aligmnent |
1440 | LOG_INFO ("image 0x%x-0x%x maxsize %d totalsize %d align %d", image_base, image_end, image_maxsize, image_totalsize, image_align); |
1716 | LOG_INFO ("image 0x%x-0x%x maxsize %d totalsize %d align %d", image_base, image_end, image_maxsize, image_totalsize, image_align); |
1441 | } |
1717 | } |
1442 | else if (strncmp (token, "virtual=", 8) == 0) { REACH_TOKEN_VALUE (); |
1718 | else if (strncmp (token, "virtual=", 8) == 0) { REACH_TOKEN_VALUE (); |
1443 | if ((bootfile_pathname == NULL) || (startupfile_pathname == NULL)) // HACK until I figure out how to re-create them |
1719 | if ((bootfile_pathname == NULL) || (startupfile_pathname == NULL)) // FIXME: HACK until I figure out how to re-create them |
1444 | DIE_WITH_EXITCODE (1, "creating bootable images require the -- |
1720 | DIE_WITH_EXITCODE (1, "creating bootable images require the --bootfile and --startupfile command-line options in \"%s\" line %d", buildfile_pathname, lineno); |
1445 | if ((sep = strchr (value, ',')) != NULL) // do we have a comma separating (optional) processor and boot file name ? |
1721 | if ((sep = strchr (value, ',')) != NULL) // do we have a comma separating (optional) processor and boot file name ? |
1446 | { |
1722 | { |
1447 | *sep = 0; |
1723 | *sep = 0; |
1448 | strcpy_s (image_processor, sizeof (image_processor), value); // save processor |
1724 | strcpy_s (image_processor, sizeof (image_processor), value); // save processor |
1449 | value = sep + 1; |
1725 | value = sep + 1; |
1450 | } |
1726 | } |
1451 | //sprintf (image_bootfile, "%s/%s/boot/sys/%s.boot", QNX_TARGET, image_processor, value); // save preboot file name (TODO: we should search in MKIFS_PATH instead of this. Not important.) |
- | |
1452 | //strcpy (image_bootfile, bootfile_pathname); // FIXME: HACK |
- | |
1453 | if (stat (bootfile_pathname, &stat_buf) != 0) |
1727 | if (stat (bootfile_pathname, &stat_buf) != 0) |
1454 | DIE_WITH_EXITCODE (1, "unable to stat the boot file \"%s\" specified in \"%s\" line %d: %s", bootfile_pathname, buildfile_pathname, lineno, strerror (errno)); |
1728 | DIE_WITH_EXITCODE (1, "unable to stat the boot file \"%s\" specified in \"%s\" line %d: %s", bootfile_pathname, buildfile_pathname, lineno, strerror (errno)); |
1455 | bootfile_size = stat_buf.st_size; // save preboot file size |
1729 | bootfile_size = stat_buf.st_size; // save preboot file size |
1456 | LOG_INFO ("processor \"%s\" bootfile \"%s\"\n", image_processor, bootfile_pathname); |
1730 | LOG_INFO ("processor \"%s\" bootfile \"%s\"\n", image_processor, bootfile_pathname); |
1457 | entry_parms.is_bootstrap_file = true; |
1731 | entry_parms.is_bootstrap_file = true; |
Line 1466... | Line 1740... | ||
1466 | } |
1740 | } |
1467 | utc_time.tm_mon--; // convert month from [1-12] to [0-11] |
1741 | utc_time.tm_mon--; // convert month from [1-12] to [0-11] |
1468 | entry_parms.mtime = (uint32_t) mktime (&utc_time); |
1742 | entry_parms.mtime = (uint32_t) mktime (&utc_time); |
1469 | } |
1743 | } |
1470 | } |
1744 | } |
1471 | else if (strcmp (token, "+script") == 0) |
1745 | else if (strcmp (token, "+script") == 0) entry_parms.is_compiled_bootscript = true; |
1472 | entry_parms.is_compiled_bootscript = true; |
- | |
1473 | ASSERT_WITH_ERRNO (Buffer_InitWithByteArray (&entry_parms.data, INITIAL_STARTUP_SCRIPT)); // FIXME: HACK until the script compiler is implemented |
- | |
1474 | should_discard_inline_contents = true; // remember we already have data (so as to discard the inline block's contents) |
- | |
1475 | } |
- | |
1476 | else if (strcmp (token, "-script") == 0) entry_parms.is_compiled_bootscript = false; |
1746 | else if (strcmp (token, "-script") == 0) entry_parms.is_compiled_bootscript = false; |
1477 | else if (strcmp (token, "+followlink") == 0) entry_parms.should_follow_symlinks = true; |
1747 | else if (strcmp (token, "+followlink") == 0) entry_parms.should_follow_symlinks = true; |
1478 | else if (strcmp (token, "-followlink") == 0) entry_parms.should_follow_symlinks = false; |
1748 | else if (strcmp (token, "-followlink") == 0) entry_parms.should_follow_symlinks = false; |
1479 | else if (strcmp (token, "+autolink") == 0) entry_parms.should_autosymlink_dylib = true; |
1749 | else if (strcmp (token, "+autolink") == 0) entry_parms.should_autosymlink_dylib = true; |
1480 | else if (strcmp (token, "-autolink") == 0) entry_parms.should_autosymlink_dylib = false; |
1750 | else if (strcmp (token, "-autolink") == 0) entry_parms.should_autosymlink_dylib = false; |