Subversion Repositories QNX 8.QNX8 IFS tool

Rev

Rev 33 | Rev 35 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

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