Subversion Repositories QNX 8.QNX8 IFS tool

Rev

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 INITIAL_STARTUP_SCRIPT \
68
#define STRINGARRAY_PUSH(string_array,str) do { \
68
   /* procmgr_symlink /proc/boot/ldqnx-64.so.2 /usr/lib/ldqnx-64.so.2 */ \
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
   "\x34\x00" /*size*/ "\x04" /*type*/ "\x00" /*spare*/ "/proc/boot/ldqnx-64.so.2\0" "/usr/lib/ldqnx-64.so.2\0" \
72
      (string_array)->args[(string_array)->count] = ((str) != NULL ? strdup ((str)) : NULL); \
70
   /* sh /proc/boot/startup.sh */ \
73
      if ((str) != NULL) \
71
   "\x88\x00" /*size*/ "\x00" /*type*/ "\x00" /*spare*/ "\x00" /*CPU mask*/ "\x00" /*flags*/ "\x00\x00" /*reserved*/ "\x00" /*policy*/ "\x00" /*priority*/ "\02" /*argc*/ "\x02" /*envc*/ "sh\0" /*executable*/ "sh\0" "/proc/boot/startup.sh\0" /*argv*/ "PATH=/sbin:/usr/sbin:/bin:/usr/bin:/proc/boot\0" "LD_LIBRARY_PATH=/proc/boot:/lib:/lib/dll:/usr/lib\0" /*envp*/ \
74
         ASSERT_WITH_ERRNO ((string_array)->args[(string_array)->count]); \
72
   /* display_msg "Startup complete */ \
75
      (string_array)->count++; \
-
 
76
   } while (0)
-
 
77
#define STRINGARRAY_FREE(string_array) do { \
-
 
78
      if ((string_array)->args != NULL) { \
73
   "\x18\x00" /*size*/ "\x03" /*type*/ "\x00" /*spare*/ "Startup complete\n\0" "\x00\00" /*padding*/ \
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
   /* trailer */ \
86
   } while (0)
-
 
87
 
-
 
88
 
-
 
89
// string array structure type definition
-
 
90
typedef struct stringarray_s
-
 
91
{
-
 
92
   char **args;
75
   "\x00\x00\x00\x00"
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 %d: unterminated attributes block (skipping)", buildfile_pathname, lineno);
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 %d: '%s'", buildfile_pathname, lineno, token);
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, &current_line); line_index++)
1000
         } // end for (line_index = 0; Buffer_GetNthLine (&entry_parms->data, line_index, &current_line); line_index++)
989
         free (entry_parms->data.bytes); // free the inline specification once it's parsed
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); // spawn the child process
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 (&global_envp); // release the global envp array
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 (&current_line);
-
 
1125
         for (line_index = 0; Buffer_GetNthLine (&entry_parms->data, line_index, &current_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 (&current_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, &current_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 --bootfile, --startupfile and --kernelfile command-line options in \"%s\" line %d", buildfile_pathname, lineno);
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;