Subversion Repositories QNX 8.QNX8 IFS tool

Rev

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

Rev 16 Rev 17
Line 82... Line 82...
82
   int uid; // owner user ID (e.g. 0 = root)
82
   int uid; // owner user ID (e.g. 0 = root)
83
   int gid; // owner group ID (e.g. 0 = root)
83
   int gid; // owner group ID (e.g. 0 = root)
84
   int st_mode; // entry type (e.g. S_IFREG for files) and permissions
84
   int st_mode; // entry type (e.g. S_IFREG for files) and permissions
85
   uint32_t mtime; // entry's modification time POSIX timestamp - set to UINT32_MAX to use the concerned files' mtime on the build host
85
   uint32_t mtime; // entry's modification time POSIX timestamp - set to UINT32_MAX to use the concerned files' mtime on the build host
86
   uint32_t mtime_for_inline_files; // same as above but only for files that don't exist on the build host (i.e. files with an explicit content blob)
86
   uint32_t mtime_for_inline_files; // same as above but only for files that don't exist on the build host (i.e. files with an explicit content blob)
87
   char prefix[MAXPATHLEN]; // install path (e.g. "proc/boot")
87
   char *prefix; // [prefix=path] install path (e.g. "proc/boot")
88
   bool should_follow_symlinks; // follow symlinks
88
   bool should_follow_symlinks; // follow symlinks
89
   bool should_autosymlink_dylib; // dynamic libraries should be written under their official SONAME and a named symlink be created pointing at them
89
   bool should_autosymlink_dylib; // dynamic libraries should be written under their official SONAME and a named symlink be created pointing at them
90
   bool should_keep_ld_output; // whether to keep .sym files produced by ld calls, togglable by the [+keeplinked] attribute
90
   bool should_keep_ld_output; // whether to keep .sym files produced by ld calls, togglable by the [+keeplinked] attribute
91
   bool is_compiled_bootscript; // entry has [+script] attribute
91
   bool is_compiled_bootscript; // entry has [+script] attribute
92
   int extra_ino_flags; // bitmap of extra inode flags (IFS_INO_xxx)
92
   int extra_ino_flags; // bitmap of extra inode flags (IFS_INO_xxx)
93
   char search[10 * MAXPATHLEN]; // binary search path (the default one will be constructed at startup)
93
   char *search; // [search=path[:path]] binary search path (the default one will be constructed at startup)
94
 
94
 
95
   buffer_t data; // the resolved file's own data bytes
95
   buffer_t data; // the resolved file's own data bytes
96
} parms_t;
96
} parms_t;
97
 
97
 
98
 
98
 
Line 109... Line 109...
109
static uint32_t image_align = 4; // default image alignment, as per QNX docs
109
static uint32_t image_align = 4; // default image alignment, as per QNX docs
110
static uint32_t image_kernel_ino = 0;
110
static uint32_t image_kernel_ino = 0;
111
static uint32_t image_bootscript_ino = 0;
111
static uint32_t image_bootscript_ino = 0;
112
#if defined(__x86_64__)
112
#if defined(__x86_64__)
113
static char image_processor[16] = "x86_64"; // default CPU type for which this image is built, either "x86_64" or "aarch64le" (will be used to find out the right include paths under $QNX_TARGET)
113
static char image_processor[16] = "x86_64"; // default CPU type for which this image is built, either "x86_64" or "aarch64le" (will be used to find out the right include paths under $QNX_TARGET)
-
 
114
static char image_processor_base[16] = "x86_64"; // default base CPU type for which this image is built, either "x86_64" or "aarch64le" (will be used to find out the right include paths under $QNX_TARGET)
114
#elif defined(__aarch64__)
115
#elif defined(__aarch64__)
115
static char image_processor[16] = "aarch64le"; // default CPU type for which this image is built, either "x86_64" or "aarch64le" (will be used to find out the right include paths under $QNX_TARGET)
116
static char image_processor[16] = "aarch64le"; // default CPU type for which this image is built, either "x86_64" or "aarch64le" (will be used to find out the right include paths under $QNX_TARGET)
-
 
117
static char image_processor_base[16] = "aarch64"; // default base CPU type for which this image is built, either "x86_64" or "aarch64le" (will be used to find out the right include paths under $QNX_TARGET)
116
#else // unknown platform
118
#else // unknown platform
117
#error Please port ifstool to this platform
119
#error Please port ifstool to this platform
118
#endif
120
#endif
119
static char *buildfile_pathname = NULL; // pathname of IFS build file
121
static char *buildfile_pathname = NULL; // pathname of IFS build file
120
static char *current_line = NULL; // copy of current line in IFS build file
122
static char *current_line = NULL; // copy of current line in IFS build file
121
static int lineno = 0; // current line number in IFS build file
123
static int lineno = 0; // current line number in IFS build file
122
static char *QNX_TARGET = NULL; // value of the $QNX_TARGET environment variable
124
static char *QNX_TARGET = NULL; // value of the $QNX_TARGET environment variable
123
static char *MKIFS_PATH = NULL; // value of the $MKIFS_PATH environment variable (may contain references to $QNX_TARGET). Initialized by this program if empty.
125
static char *SEARCH_PATH = NULL; // mallocated string of search paths, populated by the -r command-line argument
-
 
126
static char **saved_ELF_sections = NULL; // mallocated array of const strings, populated by the -s command-line argument
-
 
127
static size_t saved_ELF_section_count = 0; // number of elements in the saved_ELF_sections array
124
 
128
 
125
// bootable IFS support
129
// bootable IFS support
126
static char *bootfile_pathname = NULL;           // HACK: pathname to bootcode binary blob file to put at the start of a bootable IFS
130
static char *bootfile_pathname = NULL;           // HACK: pathname to bootcode binary blob file to put at the start of a bootable IFS
127
static size_t bootfile_size = 0;                 // HACK: size of the bootcode binary blob file to put at the start of a bootable IFS
131
static size_t bootfile_size = 0;                 // HACK: size of the bootcode binary blob file to put at the start of a bootable IFS
128
static char *startupfile_pathname = NULL;        // HACK: pathname to precompiled startup file blob to put in the startup header of a bootable IFS
132
static char *startupfile_pathname = NULL;        // HACK: pathname to precompiled startup file blob to put in the startup header of a bootable IFS
Line 135... Line 139...
135
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
139
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
136
 
140
 
137
 
141
 
138
// prototypes of local functions
142
// prototypes of local functions
139
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)
143
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)
140
static char *resolve_pathname (const char *pathname, const char *search_path); // locates pathname among MKIFS_PATH and returns a pointer to the resolved pathname (static string)
144
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)
141
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
145
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
142
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
146
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
143
static size_t Buffer_AppendIFSFileData (buffer_t *ifs_data, fsentry_t *fsentry); // writes the given filesystem entry's file data (i.e. its contents) to the IFS buffer
147
static size_t Buffer_AppendIFSFileData (buffer_t *ifs_data, fsentry_t *fsentry); // writes the given filesystem entry's file data (i.e. its contents) to the IFS buffer
144
static int Buffer_StripELFFile (buffer_t *file, const char *indicative_pathname); // strips an ELF file buffer the way mkifs does it and returns whether it succeeded
148
static int Buffer_StripELFFile (buffer_t *file, const char **saved_sections, const size_t saved_section_count, const char *indicative_pathname); // strips an ELF file buffer the way mkifs does it and returns whether it succeeded
145
static size_t add_fsentry (fsentry_t **fsentries, size_t *fsentry_count, parms_t *entry_parms, const char *stored_pathname, const char *buildhost_pathname); // stack up a new filesystem entry
149
static size_t add_fsentry (fsentry_t **fsentries, size_t *fsentry_count, parms_t *entry_parms, const char *stored_pathname, const char *buildhost_pathname); // stack up a new filesystem entry
146
static int fsentry_compare_pathnames_cb (const void *a, const void *b); // qsort() comparison callback that sorts filesystem entries by pathnames
150
static int fsentry_compare_pathnames_cb (const void *a, const void *b); // qsort() comparison callback that sorts filesystem entries by pathnames
147
static void update_MKIFS_PATH (const char *processor);
151
static void parse_line (FILE *buildfile_fp, char *line_buffer, fsentry_t **fsentries, size_t *fsentry_count, parms_t *default_parms); // parses a line in the build file and make the relevant changes to the fsentries array
148
 
152
 
149
 
153
 
150
// imported function prototypes
154
// imported function prototypes
151
extern int dump_ifs_info (const char *ifs_pathname, bool want_everything); // [implemented in ifsdump.c] dumps detailed info about a particular IFS file on the standard output, returns 0 on success and >0 on error
155
extern int dump_ifs_info (const char *ifs_pathname, bool want_everything); // [implemented in ifsdump.c] dumps detailed info about a particular IFS file on the standard output, returns 0 on success and >0 on error
152
extern int dump_ifs_contents (const char *ifs_pathname, const char *outdir); // [implemented in ifsdump.c] dumps the IFS filesystem contents in outdir, returns 0 on success and >0 on error
156
extern int dump_ifs_contents (const char *ifs_pathname, const char *outdir); // [implemented in ifsdump.c] dumps the IFS filesystem contents in outdir, returns 0 on success and >0 on error
Line 194... Line 198...
194
   }
198
   }
195
   return (ret);
199
   return (ret);
196
}
200
}
197
 
201
 
198
 
202
 
199
static char *resolve_pathname (const char *pathname, const char *search_path)
203
static char *resolve_pathname (const char *pathname, const char *search_paths_or_NULL_for_MKIFS_PATH_envvar)
200
{
204
{
201
   // locates pathname among search path and returns resolved pathname (static buffer) or NULL.
205
   // locates pathname among search path and returns resolved pathname (static buffer) or NULL.
202
 
206
 
-
 
207
   typedef struct default_path_s { bool uses_processor_base; char *subpath; } default_path_t;
-
 
208
 
-
 
209
   static const default_path_t default_paths[] =
-
 
210
   {
-
 
211
      { false, "/sbin"     }, // prefix with $PROCESSOR/
-
 
212
      { false, "/usr/sbin" }, // prefix with $PROCESSOR/
-
 
213
      { false, "/boot/sys" }, // prefix with $PROCESSOR/
-
 
214
      { true,  "/boot/sys" }, // prefix with $PROCESSOR_BASE/
-
 
215
      { false, "/bin"      }, // prefix with $PROCESSOR/
-
 
216
      { false, "/usr/bin"  }, // prefix with $PROCESSOR/
-
 
217
      { false, "/lib"      }, // prefix with $PROCESSOR/
-
 
218
      { false, "/lib/dll"  }, // prefix with $PROCESSOR/
-
 
219
      { false, "/usr/lib"  }  // prefix with $PROCESSOR/
-
 
220
   };
203
   static thread_local char *resolved_pathname = NULL;
221
   static thread_local char *resolved_pathname = NULL;
204
 
222
 
-
 
223
   size_t defaultpath_index;
205
   struct stat stat_buf;
224
   struct stat stat_buf;
206
   const char *nextsep;
225
   const char *nextsep;
207
   const char *token;
226
   const char *token;
208
 
227
 
209
   // initial allocation (per thread)
228
   // initial allocation (per thread)
Line 212... Line 231...
212
      resolved_pathname = malloc (MAXPATHLEN);
231
      resolved_pathname = malloc (MAXPATHLEN);
213
      ASSERT_WITH_ERRNO (resolved_pathname);
232
      ASSERT_WITH_ERRNO (resolved_pathname);
214
   }
233
   }
215
 
234
 
216
   // is it an absolute pathname (POSIX and Windows variants) ?
235
   // is it an absolute pathname (POSIX and Windows variants) ?
-
 
236
   if (IS_DIRSEP (pathname[0])
-
 
237
#ifdef _WIN32
217
   if (IS_DIRSEP (pathname[0]) || (isalpha (pathname[0]) && (pathname[1] == ':') && IS_DIRSEP (pathname[2])))
238
       || (isalpha (pathname[0]) && (pathname[1] == ':') && IS_DIRSEP (pathname[2]))
-
 
239
#endif // _WIN32
-
 
240
       )
218
      strcpy_s (resolved_pathname, MAXPATHLEN, pathname); // in this case, it MUST exist at its designated location (either absolute or relative to the current working directory)
241
      strcpy_s (resolved_pathname, MAXPATHLEN, pathname); // in this case, it MUST exist at its designated location (either absolute or relative to the current working directory)
219
   else // the path is relative, search it among the search paths we have
242
   else // the path is relative, search it among the search paths we have
220
   {
243
   {
-
 
244
      // QNX docs:
-
 
245
      // When searching for host files to be included in the image, search
-
 
246
      // the default paths used for storing binaries within the specified
-
 
247
      // directory before searching the default paths within $QNX_TARGET.
-
 
248
      // You can define multiple -r options; each adds a set of paths to
-
 
249
      // search for files. The -r options are evaluated from left to right
-
 
250
      // meaning the paths prefixed with the first (leftmost) rootdir are
-
 
251
      // searched first, then those prefixed with the second rootdir, and
-
 
252
      // so on.
-
 
253
      // Normally, mkifs searches any paths defined in $MKIFS_PATH when
-
 
254
      // it was called and then the default paths within $QNX_TARGET. The
-
 
255
      // default paths are based on the CPU architecture specified by
-
 
256
      // $PROCESSOR and $PROCESSOR_BASE. If you specify -r options, mkifs
-
 
257
      // searches the default paths prefixed with each dir variable before
-
 
258
      // searching those within $QNX_TARGET. These paths are:
-
 
259
      //   dir/${PROCESSOR}/sbin
-
 
260
      //   dir/${PROCESSOR}/usr/sbin
-
 
261
      //   dir/${PROCESSOR}/boot/sys
-
 
262
      //   dir/${PROCESSOR_BASE}/boot/sys
-
 
263
      //   dir/${PROCESSOR}/bin
-
 
264
      //   dir/${PROCESSOR}/usr/bin
-
 
265
      //   dir/${PROCESSOR}/lib
-
 
266
      //   dir/${PROCESSOR}/lib/dll
-
 
267
      //   dir/${PROCESSOR}/usr/lib
-
 
268
      // NOTE: The structure of the directory paths under dir must be
-
 
269
      // identical to that of the default paths under $QNX_TARGET, but the
-
 
270
      // root dir itself may be any path you choose. For example, if you
-
 
271
      // wanted to include /scratch/aarch64le/sbin/devb-sata, you would
-
 
272
      // specify a -r option like this:
-
 
273
      //   -r /scratch
-
 
274
      // Note that you don't include $PROCESSOR or $PROCESSOR_BASE in dir.
-
 
275
 
-
 
276
      //  - search all paths in explicit path/[default paths] (if explicit path supplied)
-
 
277
      //  - search all paths in (-r flags if have some|MKIFS_PATH)/[default paths] (if no explicit path supplied)
-
 
278
      //  - search all paths in $QNX_TARGET/[default paths]
-
 
279
 
-
 
280
      // if no file-specific explicit search path was supplied, use the path list supplied by the -r command-line arguments, else fallback to MKIFS_PATH if we don't have any
-
 
281
      if (search_paths_or_NULL_for_MKIFS_PATH_envvar == NULL)
-
 
282
         search_paths_or_NULL_for_MKIFS_PATH_envvar = (SEARCH_PATH != NULL ? SEARCH_PATH : getenv ("MKIFS_PATH"));
-
 
283
 
221
      // construct a potential final path using each element of the search path
284
      // construct a potential final path using each element of the search path
222
      token = (*search_path != 0 ? search_path : NULL);
285
      if (search_paths_or_NULL_for_MKIFS_PATH_envvar != NULL)
-
 
286
      {
-
 
287
         token = (*search_paths_or_NULL_for_MKIFS_PATH_envvar != 0 ? search_paths_or_NULL_for_MKIFS_PATH_envvar : NULL);
223
      nextsep = (token != NULL ? &token[strcspn (token, PATH_SEP)] : NULL);
288
         nextsep = (token != NULL ? &token[strcspn (token, PATH_SEP)] : NULL);
224
      while (token != NULL)
289
         while (token != NULL)
-
 
290
         {
-
 
291
            for (defaultpath_index = 0; defaultpath_index < sizeof (default_paths) / sizeof (default_paths[0]); defaultpath_index++)
-
 
292
            {
-
 
293
               sprintf_s (resolved_pathname, MAXPATHLEN, "%.*s/%s/%s/%s", (int) (nextsep - token), token, (default_paths[defaultpath_index].uses_processor_base ? image_processor_base : image_processor), default_paths[defaultpath_index].subpath, pathname);
-
 
294
               if ((stat (resolved_pathname, &stat_buf) == 0) && S_ISREG (stat_buf.st_mode))
-
 
295
                  return (resolved_pathname); // if a file can indeed be found at this location, stop searching
-
 
296
            }
-
 
297
 
-
 
298
            token = (*nextsep != 0 ? nextsep + 1 : NULL);
-
 
299
            nextsep = (token != NULL ? &token[strcspn (token, PATH_SEP)] : NULL);
-
 
300
         }
-
 
301
      }
-
 
302
 
-
 
303
      // file not found in search paths: look under QNX_TARGET
-
 
304
      for (defaultpath_index = 0; defaultpath_index < sizeof (default_paths) / sizeof (default_paths[0]); defaultpath_index++)
225
      {
305
      {
226
         sprintf_s (resolved_pathname, MAXPATHLEN, "%.*s/%s", (int) (nextsep - token), token, pathname);
306
         sprintf_s (resolved_pathname, MAXPATHLEN, "%s/%s/%s/%s", QNX_TARGET, (default_paths[defaultpath_index].uses_processor_base ? image_processor_base : image_processor), default_paths[defaultpath_index].subpath, pathname);
227
         if ((stat (resolved_pathname, &stat_buf) == 0) && S_ISREG (stat_buf.st_mode))
307
         if ((stat (resolved_pathname, &stat_buf) == 0) && S_ISREG (stat_buf.st_mode))
228
            return (resolved_pathname); // if a file can indeed be found at this location, stop searching
308
            return (resolved_pathname); // if a file can indeed be found at this location, stop searching
229
 
-
 
230
         token = (*nextsep != 0 ? nextsep + 1 : NULL);
-
 
231
         nextsep = (token != NULL ? &token[strcspn (token, PATH_SEP)] : NULL);
-
 
232
      }
309
      }
233
   }
310
   }
234
 
311
 
235
   errno = ENOENT; // we exhausted all possibilities
312
   errno = ENOENT; // we exhausted all possibilities
236
   return (NULL); // file not found, return with ENOENT
313
   return (NULL); // file not found, return with ENOENT
Line 318... Line 395...
318
{
395
{
319
   // writes the given filesystem entry's file data (i.e. its contents) to the IFS buffer
396
   // writes the given filesystem entry's file data (i.e. its contents) to the IFS buffer
320
 
397
 
321
   elf_program_header_t *phdr;
398
   elf_program_header_t *phdr;
322
   elf_header_t *elf;
399
   elf_header_t *elf;
-
 
400
   size_t fixed_physical_addr;
323
   size_t corrective_offset;
401
   size_t corrective_offset;
324
   //size_t segment_type;
402
   //size_t segment_type;
325
   size_t segment_size;
403
   size_t segment_size;
326
   size_t table_index;
404
   size_t table_index;
327
   size_t table_count;
405
   size_t table_count;
Line 349... Line 427...
349
 
427
 
350
 
428
 
351
         corrective_offset = ELF_GET_NUMERIC (elf, phdr, virtual_addr) - ELF_GET_NUMERIC (elf, phdr, file_offset);
429
         corrective_offset = ELF_GET_NUMERIC (elf, phdr, virtual_addr) - ELF_GET_NUMERIC (elf, phdr, file_offset);
352
         segment_size = ELF_GET_NUMERIC (elf, phdr, size_in_memory); // get this ELF segment's occupied size in memory
430
         segment_size = ELF_GET_NUMERIC (elf, phdr, size_in_memory); // get this ELF segment's occupied size in memory
353
         if (segment_size != 0) // only patch the physical address of segments that have an actual size in memory
431
         if (segment_size != 0) // only patch the physical address of segments that have an actual size in memory
-
 
432
         {
-
 
433
            fixed_physical_addr = ELF_GET_NUMERIC (elf, phdr, physical_addr) + image_base + data_offset - corrective_offset;
354
            ELF_SET_NUMERIC (elf, phdr, physical_addr, ELF_GET_NUMERIC (elf, phdr, physical_addr) + image_base + data_offset - corrective_offset); // 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)
434
            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)
-
 
435
         }
355
      }
436
      }
356
   }
437
   }
357
 
438
 
358
   ASSERT_WITH_ERRNO (Buffer_Append (ifs_data, fsentry->u.file.UNSAVED_databuf, fsentry->u.file.size)); // write file data blob
439
   ASSERT_WITH_ERRNO (Buffer_Append (ifs_data, fsentry->u.file.UNSAVED_databuf, fsentry->u.file.size)); // write file data blob
359
   return (ifs_data->size - data_offset); // return the number of bytes written
440
   return (ifs_data->size - data_offset); // return the number of bytes written
Line 374... Line 455...
374
   }
455
   }
375
   return (Buffer_OffsetOf (buffer, occurrence)); // can't fail
456
   return (Buffer_OffsetOf (buffer, occurrence)); // can't fail
376
}
457
}
377
 
458
 
378
 
459
 
379
static int Buffer_StripELFFile (buffer_t *file, const char *indicative_pathname)
460
static int Buffer_StripELFFile (buffer_t *file, const char **saved_sections, const size_t saved_section_count, const char *indicative_pathname)
380
{
461
{
381
   // NOTE: for each ELF file, mkifs
462
   // NOTE: for each ELF file, mkifs
382
   // -> alters the program header table and offsets each p_addr (physical address) member by <image_base> plus the current file offset (this cannot be done right now, will need to be done once they are known)
463
   // -> alters the program header table and offsets each p_addr (physical address) member by <image_base> plus the current file offset (this cannot be done right now, will need to be done once they are known)
383
   // -> throws away and reconstructs the sections table by keeping only the sections that are in the program header, and writes the section table at the start of the first thrown-away section
464
   // -> throws away and reconstructs the sections table by keeping only the sections that are in the program header, and writes the section table at the start of the first thrown-away section
384
   // FIXME: what if a thrown away section is located between two program segments ? are they collapsed, moving the segments beyond it one slot down ?
465
   // FIXME: what if a thrown away section is located between two program segments ? are they collapsed, moving the segments beyond it one slot down ?
Line 428... Line 509...
428
   {
509
   {
429
      const char *name;
510
      const char *name;
430
      elf_section_header_t header;
511
      elf_section_header_t header;
431
      buffer_t data;
512
      buffer_t data;
432
   } elf_section_t;
513
   } elf_section_t;
433
 
-
 
434
   static const char *saved_sections[] = { "QNX_info", ".gnu_debuglink", "QNX_usage", ".note.gnu.build-id" };
-
 
435
 
514
 
436
   const elf_program_header_t *phdr;
515
   const elf_program_header_t *phdr;
437
   const elf_section_header_t *shdr;
516
   const elf_section_header_t *shdr;
438
   elf_section_t *elf_sections = NULL; // mallocated
517
   elf_section_t *elf_sections = NULL; // mallocated
439
   elf_section_t *elf_section = NULL;
518
   elf_section_t *elf_section = NULL;
440
   size_t elf_section_count = 0;
519
   size_t elf_section_count = 0;
441
   size_t new_shdrtable_offset;
520
   size_t new_shdrtable_offset;
-
 
521
   size_t new_shdrtable_len;
442
   size_t sectiondata_start;
522
   size_t sectiondata_start;
443
   size_t sectiondata_size;
523
   size_t sectiondata_size;
444
   size_t array_index;
524
   size_t array_index;
445
   size_t table_index;
525
   size_t table_index;
446
   size_t table_count;
526
   size_t table_count;
Line 486... Line 566...
486
   ADD_SECTION (".shstrtab", &elf_section); // the first section will be the section names strings table
566
   ADD_SECTION (".shstrtab", &elf_section); // the first section will be the section names strings table
487
   ASSERT_WITH_ERRNO (Buffer_InitWithByteArray (&elf_section->data, "\0")); // initialize an empty section headers strings table
567
   ASSERT_WITH_ERRNO (Buffer_InitWithByteArray (&elf_section->data, "\0")); // initialize an empty section headers strings table
488
   ASSERT_WITH_ERRNO (Buffer_AppendByteArray (&elf_section->data, ".shstrtab\0")); // append ".shstrtab" *INCLUDING* its null terminator
568
   ASSERT_WITH_ERRNO (Buffer_AppendByteArray (&elf_section->data, ".shstrtab\0")); // append ".shstrtab" *INCLUDING* its null terminator
489
 
569
 
490
   // go through the saved sections array and see if such an ELF section is present in the ELF file
570
   // go through the saved sections array and see if such an ELF section is present in the ELF file
491
   for (array_index = 0; array_index < sizeof (saved_sections) / sizeof (saved_sections[0]); array_index++)
571
   for (array_index = 0; array_index < saved_section_count; array_index++)
492
      if ((shdr = elf_get_section_header_by_name (ELFHDR, saved_sections[array_index])) != NULL) // does this ELF have such a section ?
572
      if ((shdr = elf_get_section_header_by_name (ELFHDR, saved_sections[array_index])) != NULL) // does this ELF have such a section ?
493
      {
573
      {
494
         ADD_SECTION (saved_sections[array_index], &elf_section); // yes, so save it
574
         ADD_SECTION (saved_sections[array_index], &elf_section); // yes, so save it
495
         sectiondata_start = ELF_GET_NUMERIC (ELFHDR, shdr, file_offset); // identify section data start offset
575
         sectiondata_start = ELF_GET_NUMERIC (ELFHDR, shdr, file_offset); // identify section data start offset
496
         sectiondata_size = ELF_GET_NUMERIC (ELFHDR, shdr, size); // identify section data length
576
         sectiondata_size = ELF_GET_NUMERIC (ELFHDR, shdr, size); // identify section data length
497
         if (sectiondata_start + sectiondata_size >= new_shdrtable_offset) // should this section be moved ?
577
         if (sectiondata_start + sectiondata_size >= new_shdrtable_offset) // should this section be moved ?
498
            ASSERT_WITH_ERRNO (Buffer_InitWithData (&elf_section->data, &file->bytes[sectiondata_start], sectiondata_size)); // have a copy of this section's data
578
            ASSERT_WITH_ERRNO (Buffer_InitWithData (&elf_section->data, &file->bytes[sectiondata_start], sectiondata_size)); // have a copy of this section's data
499
         else
579
         else
500
            Buffer_Initialize (&elf_section->data); // this section is located before the place where we'll write the new section headers table, thus it doesn't need to be moved
580
            Buffer_Initialize (&elf_section->data); // this section is located before the place where we'll write the new section headers table, thus it doesn't need to be moved
501
         //LOG_DEBUG ("%s: section '%s' start 0x%llx len 0x%llx", indicative_pathname, saved_sections[array_index], (unsigned long long) sectiondata_start, (unsigned long long) sectiondata_size);
581
         //LOG_DEBUG ("%s: section '%s' start 0x%llx len 0x%llx", indicative_pathname, saved_ELF_sections[array_index], (unsigned long long) sectiondata_start, (unsigned long long) sectiondata_size);
502
 
582
 
503
         // prepare this section's "fixed" header
583
         // prepare this section's "fixed" header
504
         memcpy (&elf_section->header, shdr, ELF_STRUCT_SIZE (ELFHDR, shdr)); // have a copy of the old section header first
584
         memcpy (&elf_section->header, shdr, ELF_STRUCT_SIZE (ELFHDR, shdr)); // have a copy of the old section header first
505
         ELF_SET_NUMERIC (ELFHDR, &elf_section->header, name_offset, Buffer_LocateOrAppendIfNecessaryAndReturnOffsetOf (&elf_sections[0].data, elf_section->name)); // make sure this section name is in the ELF sections section header strings table and update the relative offset of the section name
585
         ELF_SET_NUMERIC (ELFHDR, &elf_section->header, name_offset, Buffer_LocateOrAppendIfNecessaryAndReturnOffsetOf (&elf_sections[0].data, elf_section->name)); // make sure this section name is in the ELF sections section header strings table and update the relative offset of the section name
506
      }
586
      }
Line 535... Line 615...
535
   for (table_index = 1; table_index < elf_section_count; table_index++)
615
   for (table_index = 1; table_index < elf_section_count; table_index++)
536
      Buffer_WriteAt (file, new_shdrtable_offset + table_index * ELF_STRUCT_SIZE (ELFHDR, &elf_sections[table_index].header), &elf_sections[table_index].header, ELF_STRUCT_SIZE (ELFHDR, &elf_sections[table_index].header)); // write each section header
616
      Buffer_WriteAt (file, new_shdrtable_offset + table_index * ELF_STRUCT_SIZE (ELFHDR, &elf_sections[table_index].header), &elf_sections[table_index].header, ELF_STRUCT_SIZE (ELFHDR, &elf_sections[table_index].header)); // write each section header
537
   Buffer_WriteAt (file, new_shdrtable_offset + table_index * ELF_STRUCT_SIZE (ELFHDR, &elf_sections[table_index].header), &elf_sections[0].header, ELF_STRUCT_SIZE (ELFHDR, &elf_sections[0].header)); // write the section header names section header last
617
   Buffer_WriteAt (file, new_shdrtable_offset + table_index * ELF_STRUCT_SIZE (ELFHDR, &elf_sections[table_index].header), &elf_sections[0].header, ELF_STRUCT_SIZE (ELFHDR, &elf_sections[0].header)); // write the section header names section header last
538
 
618
 
539
   // and finally fix the ELF master header
619
   // and finally fix the ELF master header
-
 
620
   new_shdrtable_len = 1 + elf_section_count; // take in account that the first entry in the section headers table is empty
540
   ELF_SET_NUMERIC (ELFHDR, ELFHDR, section_header_table_offset, new_shdrtable_offset);
621
   ELF_SET_NUMERIC (ELFHDR, ELFHDR, section_header_table_offset, new_shdrtable_offset);
541
   ELF_SET_NUMERIC (ELFHDR, ELFHDR, section_header_table_len, 1 + elf_section_count); // take in account that the first entry in the section headers table is empty 
622
   ELF_SET_NUMERIC (ELFHDR, ELFHDR, section_header_table_len, new_shdrtable_len);
542
   ELF_SET_NUMERIC (ELFHDR, ELFHDR, section_header_names_idx, elf_section_count); // the section headers strings table is the last section
623
   ELF_SET_NUMERIC (ELFHDR, ELFHDR, section_header_names_idx, elf_section_count); // the section headers strings table is the last section
543
 
624
 
544
   // align size with page size (4096 on x86, 16k on ARM), zerofilling the extra space
625
   // align size with page size (4096 on x86, 16k on ARM), zerofilling the extra space
545
   ASSERT_WITH_ERRNO (Buffer_PadWithZeroesTo (file, ROUND_TO_UPPER_MULTIPLE (file->size, page_size)));
626
   ASSERT_WITH_ERRNO (Buffer_PadWithZeroesTo (file, ROUND_TO_UPPER_MULTIPLE (file->size, page_size)));
546
 
627
 
Line 637... Line 718...
637
               // now parse the attribute tokens (NOTE: THE LIST OF ALLOWED ATTRIBUTES HERE IS NOT DOCUMENTED)
718
               // now parse the attribute tokens (NOTE: THE LIST OF ALLOWED ATTRIBUTES HERE IS NOT DOCUMENTED)
638
               token = strtok_r (linebit_start, RECORD_SEP, &ctx);
719
               token = strtok_r (linebit_start, RECORD_SEP, &ctx);
639
               while (token != NULL)
720
               while (token != NULL)
640
               {
721
               {
641
                  #define REACH_TOKEN_VALUE() do { value = strchr (token, '=') + 1; if (*value == '"') value++; } while (0)
722
                  #define REACH_TOKEN_VALUE() do { value = strchr (token, '=') + 1; if (*value == '"') value++; } while (0)
-
 
723
                  if (false)
-
 
724
                  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.)
642
                  if      (strncmp (token, "uid=",     4) == 0) { REACH_TOKEN_VALUE (); entry_parms->uid     = (int) read_integer (value); }
725
                  else if (strncmp (token, "uid=",     4) == 0) { REACH_TOKEN_VALUE (); entry_parms->uid     = (int) read_integer (value); }
643
                  else if (strncmp (token, "gid=",     4) == 0) { REACH_TOKEN_VALUE (); entry_parms->gid     = (int) read_integer (value); }
726
                  else if (strncmp (token, "gid=",     4) == 0) { REACH_TOKEN_VALUE (); entry_parms->gid     = (int) read_integer (value); }
644
                  else if (strncmp (token, "perms=",   6) == 0) { REACH_TOKEN_VALUE (); entry_parms->perms   = (int) read_integer (value); }
727
                  else if (strncmp (token, "perms=",   6) == 0) { REACH_TOKEN_VALUE (); entry_parms->perms   = (int) read_integer (value); }
645
                  else if (strncmp (token, "prefix=",  7) == 0) { REACH_TOKEN_VALUE (); strcpy (entry_parms->prefix, (*value == '/' ? value + 1 : value)); } // skip possible leading slash in prefix
-
 
646
                  else if (strcmp (token, "+followlink") == 0) entry_parms->should_follow_symlinks = true;
728
                  else if (strcmp (token, "+followlink") == 0) entry_parms->should_follow_symlinks = true;
647
                  else if (strcmp (token, "-followlink") == 0) entry_parms->should_follow_symlinks = false;
729
                  else if (strcmp (token, "-followlink") == 0) entry_parms->should_follow_symlinks = false;
648
                  else if (strcmp (token, "+keeplinked") == 0) entry_parms->should_keep_ld_output = true;
730
                  else if (strcmp (token, "+keeplinked") == 0) entry_parms->should_keep_ld_output = true;
649
                  else if (strcmp (token, "-keeplinked") == 0) entry_parms->should_keep_ld_output = false;
731
                  else if (strcmp (token, "-keeplinked") == 0) entry_parms->should_keep_ld_output = false;
650
                  else LOG_WARNING ("unimplemented bootstrap executable attribute in \"%s\" line %d: '%s'", buildfile_pathname, lineno, token);
732
                  else LOG_WARNING ("unimplemented bootstrap executable attribute in \"%s\" line %d: '%s'", buildfile_pathname, lineno, token);
Line 763... Line 845...
763
 
845
 
764
         // now we know which startup and procnto executables to use
846
         // now we know which startup and procnto executables to use
765
         LOG_DEBUG ("Startup: %s", startup_name);
847
         LOG_DEBUG ("Startup: %s", startup_name);
766
         LOG_DEBUG ("Kernel: %s", procnto_name);
848
         LOG_DEBUG ("Kernel: %s", procnto_name);
767
 
849
 
768
         sprintf (candidate_pathname, "%s/%s", entry_parms->prefix, procnto_name); // fix the entry name
850
         sprintf (candidate_pathname, "%s/%s", (entry_parms->prefix != NULL ? entry_parms->prefix : ""), procnto_name); // fix the entry name
769
         stored_pathname = candidate_pathname;
851
         stored_pathname = candidate_pathname;
770
         entry_parms->extra_ino_flags |= /*IFS_INO_PROCESSED_ELF | */IFS_INO_BOOTSTRAP_EXE; // procnto needs to have these flags stamped on the inode
852
         entry_parms->extra_ino_flags |= /*IFS_INO_PROCESSED_ELF | */IFS_INO_BOOTSTRAP_EXE; // procnto needs to have these flags stamped on the inode
771
         entry_parms->st_mode = S_IFREG | entry_parms->perms; // apply specified procnto permissions
853
         entry_parms->st_mode = S_IFREG | entry_parms->perms; // apply specified procnto permissions
772
         image_kernel_ino = entry_parms->extra_ino_flags | (inode_count + 1);
854
         image_kernel_ino = entry_parms->extra_ino_flags | (inode_count + 1);
773
 
855
 
Line 789... Line 871...
789
#endif
871
#endif
790
         ASSERT (access (linker_pathname, 0) == 0, "host cross-linker for QNX8 \"%s\" not found", linker_pathname);
872
         ASSERT (access (linker_pathname, 0) == 0, "host cross-linker for QNX8 \"%s\" not found", linker_pathname);
791
         sprintf (linker_sysroot_arg, "--sysroot=%s/%s/", QNX_TARGET, image_processor);
873
         sprintf (linker_sysroot_arg, "--sysroot=%s/%s/", QNX_TARGET, image_processor);
792
         sprintf (linker_script_pathname_arg, "-T%s/%s/lib/nto.link", QNX_TARGET, image_processor);
874
         sprintf (linker_script_pathname_arg, "-T%s/%s/lib/nto.link", QNX_TARGET, image_processor);
793
 
875
 
794
         resolved_pathname = resolve_pathname (procnto_name, (entry_parms->search[0] != 0 ? entry_parms->search : MKIFS_PATH)); // locate the procnto kernel location
876
         resolved_pathname = resolve_pathname (procnto_name, entry_parms->search); // locate the procnto kernel location
795
         ASSERT (resolved_pathname, "QNX kernel \"%s\" not found in search path", procnto_name);
877
         ASSERT (resolved_pathname, "QNX kernel \"%s\" not found in search path", procnto_name);
796
         strcpy (procnto_buildhost_pathname, resolved_pathname);
878
         strcpy (procnto_buildhost_pathname, resolved_pathname);
797
 
879
 
798
         sprintf (procnto_sym_filename, "%s.sym", procnto_name);
880
         sprintf (procnto_sym_filename, "%s.sym", procnto_name);
799
 
881
 
Line 820... Line 902...
820
         _spawnv (_P_WAIT, linker_pathname, linker_argv); // spawn the linker and produce a stripped procnto (wait for completion)
902
         _spawnv (_P_WAIT, linker_pathname, linker_argv); // spawn the linker and produce a stripped procnto (wait for completion)
821
         if (!Buffer_ReadFromFile (&entry_parms->data, procnto_sym_filename)) // load the output file
903
         if (!Buffer_ReadFromFile (&entry_parms->data, procnto_sym_filename)) // load the output file
822
            DIE_WITH_EXITCODE (1, "the host cross-linker failed to produce a readable stripped \"%s\" kernel: %s", procnto_sym_filename, strerror (errno));
904
            DIE_WITH_EXITCODE (1, "the host cross-linker failed to produce a readable stripped \"%s\" kernel: %s", procnto_sym_filename, strerror (errno));
823
         if (!entry_parms->should_keep_ld_output)
905
         if (!entry_parms->should_keep_ld_output)
824
            unlink (procnto_sym_filename); // remove the linker output file if we want to
906
            unlink (procnto_sym_filename); // remove the linker output file if we want to
-
 
907
 
-
 
908
         // now strip this prelinked ELF kernel file
-
 
909
         Buffer_StripELFFile (&entry_parms->data, saved_ELF_sections, 1, stored_pathname); // strip the ELF file as per QNX docs (only keep ONE section, which is "QNX_info")
-
 
910
         entry_parms->extra_ino_flags |= IFS_INO_PROCESSED_ELF; // mark this inode as a preprocessed ELF file
-
 
911
 
825
#else // !PROCNTO_WIP
912
#else // !PROCNTO_WIP
826
         /* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK */
913
         /* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK */
827
         /* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK */
914
         /* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK */
828
         /* HACK */
915
         /* HACK */
829
         /* HACK */ sprintf_s (candidate_pathname, MAXPATHLEN, "%s/procnto-smp-instr", entry_parms->prefix); // HACK: fix the entry name
916
         /* HACK */ sprintf_s (candidate_pathname, MAXPATHLEN, "%s/procnto-smp-instr", (entry_parms->prefix != NULL ? entry_parms->prefix : "")); // HACK: fix the entry name
830
         /* HACK */ stored_pathname = candidate_pathname;
917
         /* HACK */ stored_pathname = candidate_pathname;
831
         /* HACK */ entry_parms->extra_ino_flags |= IFS_INO_PROCESSED_ELF | IFS_INO_BOOTSTRAP_EXE; // procnto needs to have these flags stamped on the inode
918
         /* HACK */ entry_parms->extra_ino_flags |= IFS_INO_PROCESSED_ELF | IFS_INO_BOOTSTRAP_EXE; // procnto needs to have these flags stamped on the inode
832
         /* HACK */ entry_parms->st_mode = S_IFREG | 0700; // procnto requires 0700 permissions
919
         /* HACK */ entry_parms->st_mode = S_IFREG | 0700; // procnto requires 0700 permissions
833
         /* HACK */ image_kernel_ino = entry_parms->extra_ino_flags | (inode_count + 1);
920
         /* HACK */ image_kernel_ino = entry_parms->extra_ino_flags | (inode_count + 1);
834
         /* HACK */ free (entry_parms->data.bytes); // discard inline contents
921
         /* HACK */ free (entry_parms->data.bytes); // discard inline contents
Line 852... Line 939...
852
         entry_parms->mtime = entry_parms->mtime_for_inline_files; // if so, set it a mtime equal to the mtime to use for inline files
939
         entry_parms->mtime = entry_parms->mtime_for_inline_files; // if so, set it a mtime equal to the mtime to use for inline files
853
         LOG_INFO ("file: ino 0x%x uid %d gid %d mode 0%o path \"%s\" blob (len %zd)", entry_parms->extra_ino_flags | (inode_count + 1), entry_parms->uid, entry_parms->gid, entry_parms->st_mode, stored_pathname, entry_parms->data.size);
940
         LOG_INFO ("file: ino 0x%x uid %d gid %d mode 0%o path \"%s\" blob (len %zd)", entry_parms->extra_ino_flags | (inode_count + 1), entry_parms->uid, entry_parms->gid, entry_parms->st_mode, stored_pathname, entry_parms->data.size);
854
      }
941
      }
855
      else if (buildhost_pathname != NULL) // else was a source file pathname supplied ?
942
      else if (buildhost_pathname != NULL) // else was a source file pathname supplied ?
856
      {
943
      {
857
         resolved_pathname = resolve_pathname (buildhost_pathname, (entry_parms->search[0] != 0 ? entry_parms->search : MKIFS_PATH)); // locate the file
944
         resolved_pathname = resolve_pathname (buildhost_pathname, entry_parms->search); // locate the file
858
         if (resolved_pathname == NULL)
945
         if (resolved_pathname == NULL)
859
            DIE_WITH_EXITCODE (1, "filesystem entry \"%s\" specified in \"%s\" line %d not found on build host: %s", buildhost_pathname, buildfile_pathname, lineno, strerror (errno));
946
            DIE_WITH_EXITCODE (1, "filesystem entry \"%s\" specified in \"%s\" line %d not found on build host: %s", buildhost_pathname, buildfile_pathname, lineno, strerror (errno));
860
         if (!Buffer_ReadFromFile (&entry_parms->data, resolved_pathname))
947
         if (!Buffer_ReadFromFile (&entry_parms->data, resolved_pathname))
861
            DIE_WITH_EXITCODE (1, "filesystem entry \"%s\" specified in \"%s\" line %d can't be read: %s", buildhost_pathname, buildfile_pathname, lineno, strerror (errno));
948
            DIE_WITH_EXITCODE (1, "filesystem entry \"%s\" specified in \"%s\" line %d can't be read: %s", buildhost_pathname, buildfile_pathname, lineno, strerror (errno));
862
         stat (resolved_pathname, &stat_buf); // can't fail, since we could read it
949
         stat (resolved_pathname, &stat_buf); // can't fail, since we could read it
Line 894... Line 981...
894
                  }
981
                  }
895
 
982
 
896
               // do we have it ?
983
               // do we have it ?
897
               if ((canonical_dylib_name != NULL) && (canonical_dylib_name[0] != 0))
984
               if ((canonical_dylib_name != NULL) && (canonical_dylib_name[0] != 0))
898
               {
985
               {
899
                  sprintf_s (candidate_pathname, MAXPATHLEN, "%s/%s", entry_parms->prefix, canonical_dylib_name);
986
                  sprintf_s (candidate_pathname, MAXPATHLEN, "%s/%s", (entry_parms->prefix != NULL ? entry_parms->prefix : ""), canonical_dylib_name);
900
                  if (strcmp (candidate_pathname, stored_pathname) != 0) // claimed dylib name differs from passed name ?
987
                  if (strcmp (candidate_pathname, stored_pathname) != 0) // claimed dylib name differs from passed name ?
901
                  {
988
                  {
902
                     original_stored_pathname = stored_pathname; // if so, remember to create a symlink here
989
                     original_stored_pathname = stored_pathname; // if so, remember to create a symlink here
903
                     stored_pathname = candidate_pathname;
990
                     stored_pathname = candidate_pathname;
904
                  }
991
                  }
Line 907... Line 994...
907
         } // end if the file we're storing is a dylib
994
         } // end if the file we're storing is a dylib
908
 
995
 
909
         // now strip this ELF file if necessary
996
         // now strip this ELF file if necessary
910
         if (!(entry_parms->extra_ino_flags & IFS_INO_PROCESSED_ELF))
997
         if (!(entry_parms->extra_ino_flags & IFS_INO_PROCESSED_ELF))
911
         {
998
         {
912
            Buffer_StripELFFile (&entry_parms->data, stored_pathname); // strip the ELF file à la mkifs
999
            Buffer_StripELFFile (&entry_parms->data, saved_ELF_sections, saved_ELF_section_count, stored_pathname); // strip the ELF file à la mkifs
913
            entry_parms->extra_ino_flags |= IFS_INO_PROCESSED_ELF; // mark this inode as a preprocessed ELF file
1000
            entry_parms->extra_ino_flags |= IFS_INO_PROCESSED_ELF; // mark this inode as a preprocessed ELF file
914
         } // end if the file is not yet a processed ELF
1001
         } // end if the file is not yet a processed ELF
915
      } // end if the file we're storing is an ELF file
1002
      } // end if the file we're storing is an ELF file
916
      #undef ELFHDR // undefine the macro that used to always point to the ELF header at the beginning of the file
1003
      #undef ELFHDR // undefine the macro that used to always point to the ELF header at the beginning of the file
917
   }
1004
   }
Line 1006... Line 1093...
1006
   const char *pathname_b = (S_ISDIR (entry_b->header.mode) ? entry_b->u.dir.path : (S_ISREG (entry_b->header.mode) ? entry_b->u.file.path : (S_ISLNK (entry_b->header.mode) ? entry_b->u.symlink.path : entry_b->u.device.path)));
1093
   const char *pathname_b = (S_ISDIR (entry_b->header.mode) ? entry_b->u.dir.path : (S_ISREG (entry_b->header.mode) ? entry_b->u.file.path : (S_ISLNK (entry_b->header.mode) ? entry_b->u.symlink.path : entry_b->u.device.path)));
1007
   return (strcmp (pathname_a, pathname_b));
1094
   return (strcmp (pathname_a, pathname_b));
1008
}
1095
}
1009
 
1096
 
1010
 
1097
 
1011
static void update_MKIFS_PATH (const char *processor)
1098
static void parse_line (FILE *buildfile_fp, char *line_buffer, fsentry_t **fsentries, size_t *fsentry_count, parms_t *default_parms)
1012
{
1099
{
-
 
1100
   thread_local static char path_on_buildhost[MAXPATHLEN] = "";
-
 
1101
   thread_local static char path_in_ifs[MAXPATHLEN] = "";
1013
   // updates the value of MKIFS_PATH according to the passed processor name string, unless an environment variable already defines it
1102
   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)
1014
 
1103
 
-
 
1104
   bool should_discard_inline_contents;
-
 
1105
   bool is_quoted_context;
-
 
1106
   bool is_escaped_char;
-
 
1107
   struct stat stat_buf;
-
 
1108
   struct tm utc_time;
1015
   char processor_base[16];
1109
   void *reallocated_ptr;
-
 
1110
   size_t allocated_size;
1016
   size_t data_len;
1111
   size_t string_len;
-
 
1112
   char *specifiedpathname_start;
-
 
1113
   char *attrblock_start;
-
 
1114
   char *write_ptr;
1017
   char *envvar;
1115
   char *line_ptr;
-
 
1116
   char *value;
1018
   char *token;
1117
   char *token;
-
 
1118
   char *sep;
-
 
1119
   char *ctx;
-
 
1120
   int read_char;
1019
   
1121
 
-
 
1122
   line_ptr = line_buffer;
-
 
1123
   while ((*line_ptr != 0) && isspace (*line_ptr))
-
 
1124
      line_ptr++; // skip leading spaces
-
 
1125
 
-
 
1126
   if ((*line_ptr == 0) || (*line_ptr == '#'))
-
 
1127
      return; // skip empty or comment lines
-
 
1128
 
-
 
1129
   string_len = (int) strlen (line_buffer);
-
 
1130
   if ((string_len > 0) && (line_buffer[string_len - 1] == '\n'))
1020
   envvar = getenv ("MKIFS_PATH"); // look in the environment first, and construct a default one if not supplied
1131
      line_buffer[string_len - 1] = 0; // chop off newline for easier debug output
-
 
1132
 
1021
   if (envvar != NULL)
1133
   // reset entry values
1022
      MKIFS_PATH = envvar; // if envvar is present, set MKIFS_PATH to point to it
1134
   memcpy (&entry_parms, default_parms, sizeof (parms_t));
-
 
1135
   path_in_ifs[0] = 0;
-
 
1136
   path_on_buildhost[0] = 0;
-
 
1137
   should_discard_inline_contents = false;
-
 
1138
 
-
 
1139
   // does this line start with an attribute block ?
1023
   else // envvar not present
1140
   if (*line_ptr == '[')
1024
   {
1141
   {
-
 
1142
      line_ptr++; // skip the leading square bracket
-
 
1143
      attrblock_start = line_ptr; // remember where it starts
-
 
1144
      is_quoted_context = false;
-
 
1145
      while ((*line_ptr != 0) && !((*line_ptr == ']') && (line_ptr[-1] != '\\') && !is_quoted_context))
-
 
1146
      {
-
 
1147
         if (*line_ptr == '"')
-
 
1148
            is_quoted_context ^= true; // remember when we're between quotes
-
 
1149
         else if (!is_quoted_context && (*line_ptr == ' '))
-
 
1150
            *line_ptr = RECORD_SEP[0]; // turn all spaces outside quoted contexts into an ASCII record separator to ease token splitting
-
 
1151
         line_ptr++; // reach the next unescaped closing square bracket
-
 
1152
      }
1025
      if (MKIFS_PATH != NULL)
1153
      if (*line_ptr != ']')
-
 
1154
      {
-
 
1155
         LOG ("warning", 0, "syntax error in \"%s\" line %d: unterminated attributes block (skipping)", buildfile_pathname, lineno);
-
 
1156
         return; // invalid attribute block, skip line
-
 
1157
      }
1026
         free (MKIFS_PATH); // free any MKIFS_PATH that we constructed earlier
1158
      *line_ptr = 0; // end the attribute block so that it is a parsable C string
1027
 
1159
 
-
 
1160
      // now parse the attribute tokens
1028
      strcpy_s (processor_base, sizeof (processor_base), processor); // construct PROCESSOR_BASE
1161
      // DOCUMENTATION: https://www.qnx.com/developers/docs/8.0/com.qnx.doc.neutrino.utilities/topic/m/mkifs.html#mkifs__description
1029
      token = strchr (processor_base, '-');
1162
      token = strtok_r (attrblock_start, RECORD_SEP, &ctx);
1030
      if (token != NULL)
1163
      while (token != NULL)
-
 
1164
      {
-
 
1165
         // evaluate attribute token
-
 
1166
         #define REACH_TOKEN_VALUE() do { value = strchr (token, '=') + 1; if (*value == '"') value++; } while (0)
-
 
1167
         if (false) {}
-
 
1168
         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.)
-
 
1169
         else if (strncmp (token, "uid=",     4) == 0) { REACH_TOKEN_VALUE (); entry_parms.uid     = (int) read_integer (value); }
-
 
1170
         else if (strncmp (token, "gid=",     4) == 0) { REACH_TOKEN_VALUE (); entry_parms.gid     = (int) read_integer (value); }
-
 
1171
         else if (strncmp (token, "dperms=",  7) == 0) { REACH_TOKEN_VALUE (); entry_parms.dperms  = (int) read_integer (value); }
-
 
1172
         else if (strncmp (token, "perms=",   6) == 0) { REACH_TOKEN_VALUE (); entry_parms.perms   = (int) read_integer (value); }
-
 
1173
         else if (strncmp (token, "type=",    5) == 0) { REACH_TOKEN_VALUE ();
-
 
1174
            if      (strcmp (value, "dir")  == 0) entry_parms.st_mode = S_IFDIR;
-
 
1175
            else if (strcmp (value, "file") == 0) entry_parms.st_mode = S_IFREG;
-
 
1176
            else if (strcmp (value, "link") == 0) entry_parms.st_mode = S_IFLNK;
-
 
1177
            else if (strcmp (value, "fifo") == 0) entry_parms.st_mode = S_IFIFO;
-
 
1178
            else DIE_WITH_EXITCODE (1, "invalid 'type' attribute in \"%s\" line %d: '%s'", buildfile_pathname, lineno, value);
-
 
1179
         }
-
 
1180
         else if (strncmp (token, "image=",   6) == 0) { REACH_TOKEN_VALUE ();
-
 
1181
            image_base = (uint32_t) read_integer (value); // read image base address
-
 
1182
            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.)
-
 
1183
            if ((sep = strchr (value, ',')) != NULL) image_maxsize   = (uint32_t) read_integer (sep + 1); // if we have a comma, read optional image max size
-
 
1184
            if ((sep = strchr (value, '=')) != NULL) image_totalsize = (uint32_t) read_integer (sep + 1); // if we have an equal sign, read optional image padding size
-
 
1185
            if ((sep = strchr (value, '%')) != NULL) image_align     = (uint32_t) read_integer (sep + 1); // if we have a modulo sign, read optional image aligmnent
-
 
1186
            LOG_INFO ("image 0x%x-0x%x maxsize %d totalsize %d align %d", image_base, image_end, image_maxsize, image_totalsize, image_align);
-
 
1187
         }
-
 
1188
         else if (strncmp (token, "virtual=", 8) == 0) { REACH_TOKEN_VALUE ();
-
 
1189
            if ((bootfile_pathname == NULL) || (startupfile_pathname == NULL) || (kernelfile_pathname == NULL)) // HACK until I figure out how to re-create them
-
 
1190
               DIE_WITH_EXITCODE (1, "creating bootable images require the --bootfile, --startupfile and --kernelfile command-line options in \"%s\" line %d", buildfile_pathname, lineno);
-
 
1191
            if ((sep = strchr (value, ',')) != NULL) // do we have a comma separating (optional) processor and boot file name ?
-
 
1192
            {
-
 
1193
               *sep = 0;
-
 
1194
               strcpy_s (image_processor, sizeof (image_processor), value); // save processor
-
 
1195
               value = sep + 1;
-
 
1196
            }
-
 
1197
            //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.)
-
 
1198
            //strcpy (image_bootfile, bootfile_pathname); // FIXME: HACK
-
 
1199
            if (stat (bootfile_pathname, &stat_buf) != 0)
-
 
1200
               DIE_WITH_EXITCODE (1, "unable to stat the boot file \"%s\" specified in \"%s\" line %d: %s", bootfile_pathname, buildfile_pathname, lineno, strerror (errno));
-
 
1201
            bootfile_size = stat_buf.st_size; // save preboot file size
-
 
1202
            LOG_INFO ("processor \"%s\" bootfile \"%s\"\n", image_processor, bootfile_pathname);
-
 
1203
#if 1
-
 
1204
            // ######################################################################################################################################################################################################################################
-
 
1205
            // # FIXME: figure out how to re-create it: linker call involved
-
 
1206
            // # $ x86_64-pc-nto-qnx8.0.0-ld --sysroot=${QNX_TARGET}/x86_64/ -T${QNX_TARGET}/x86_64/lib/nto.link --section-start .text=0xffff800000001000 --no-relax ${QNX_TARGET}/x86_64/boot/sys/procnto-smp-instr -o procnto-smp-instr.sym.UNSTRIPPED
-
 
1207
            // ######################################################################################################################################################################################################################################
-
 
1208
//               if (!Buffer_ReadFromFile (&entry_parms.data, kernelfile_pathname))
-
 
1209
//                  DIE_WITH_EXITCODE (1, "unable to read precompiled kernel file \"%s\" specified in --kernelfile argument: %s", kernelfile_pathname, strerror (errno));
-
 
1210
#else // nonworking
-
 
1211
            strcpy (path_on_buildhost, "procnto-smp-instr");
-
 
1212
#endif // nonworking
-
 
1213
         }
-
 
1214
         else if (strncmp (token, "mtime=", 6) == 0) { REACH_TOKEN_VALUE (); if (strcmp (value, "*") == 0) entry_parms.mtime = UINT32_MAX; else {
-
 
1215
               // value *must* be "YYYY-MM-DD-HH:MM:SS" by specification
-
 
1216
               memset (&utc_time, 0, sizeof (utc_time));
-
 
1217
               if (sscanf_s (value, "%u-%u-%u-%u:%u:%u", &utc_time.tm_year, &utc_time.tm_mon, &utc_time.tm_mday, &utc_time.tm_hour, &utc_time.tm_min, &utc_time.tm_sec) != 6)
-
 
1218
               {
-
 
1219
                  LOG_WARNING ("syntax error in \"%s\" line %d: mtime specification not in YYYY-MM-DD-HH:MM:SS format (skipping)", buildfile_pathname, lineno);
1031
         *token = 0; // split anything from the first dash onwards
1220
                  continue; // invalid attribute block, skip line
-
 
1221
               }
-
 
1222
               utc_time.tm_mon--; // convert month from [1-12] to [0-11]
-
 
1223
               entry_parms.mtime = (uint32_t) mktime (&utc_time);
-
 
1224
            }
-
 
1225
         }
1032
      data_len = strlen (processor_base);
1226
         else if (strcmp (token, "+script")     == 0) {
-
 
1227
            entry_parms.is_compiled_bootscript = true;
-
 
1228
            ASSERT_WITH_ERRNO (Buffer_InitWithByteArray (&entry_parms.data, INITIAL_STARTUP_SCRIPT)); // FIXME: HACK until the script compiler is implemented
1033
      if ((data_len > 2) && ((processor_base[data_len - 2] == 'b') || (processor_base[data_len - 2] == 'l')) && (processor_base[data_len - 1] == 'e'))
1229
            should_discard_inline_contents = true; // remember we already have data (so as to discard the inline block's contents)
-
 
1230
         }
1034
         processor_base[data_len - 2] = 0; // if it ends with "le" or "be", strip that too
1231
         else if (strcmp (token, "-script")     == 0) entry_parms.is_compiled_bootscript = false;
-
 
1232
         else if (strcmp (token, "+followlink") == 0) entry_parms.should_follow_symlinks = true;
-
 
1233
         else if (strcmp (token, "-followlink") == 0) entry_parms.should_follow_symlinks = false;
-
 
1234
         else if (strcmp (token, "+autolink")   == 0) entry_parms.should_autosymlink_dylib = true;
-
 
1235
         else if (strcmp (token, "-autolink")   == 0) entry_parms.should_autosymlink_dylib = false;
-
 
1236
         else if (strcmp (token, "+keeplinked") == 0) entry_parms.should_keep_ld_output = true;
-
 
1237
         else if (strcmp (token, "-keeplinked") == 0) entry_parms.should_keep_ld_output = false;
-
 
1238
         else LOG_WARNING ("unimplemented attribute in \"%s\" line %d: '%s'", buildfile_pathname, lineno, token);
-
 
1239
         #undef REACH_TOKEN_VALUE
1035
 
1240
 
1036
      MKIFS_PATH = malloc (10 * MAXPATHLEN); // construct a default MKIFS_PATH now
1241
         token = strtok_r (NULL, RECORD_SEP, &ctx); // proceed to next attribute token
-
 
1242
      }
-
 
1243
 
1037
      ASSERT_WITH_ERRNO (MKIFS_PATH);
1244
      line_ptr++; // reach the next character
-
 
1245
      while ((*line_ptr != 0) && isspace (*line_ptr))
1038
      sprintf_s (MKIFS_PATH, 10 * MAXPATHLEN,
1246
         line_ptr++; // skip leading spaces
-
 
1247
 
-
 
1248
      // are we at the end of the line ? if so, it means the attribute values that are set should become the default
-
 
1249
      if ((*line_ptr == 0) || (*line_ptr == '#'))
-
 
1250
      {
1039
                 "." PATH_SEP "%s/%s/sbin" PATH_SEP "%s/%s/usr/sbin" PATH_SEP "%s/%s/boot/sys" PATH_SEP "%s/%s/boot/sys" PATH_SEP "%s/%s/bin" PATH_SEP "%s/%s/usr/bin" PATH_SEP "%s/%s/lib" PATH_SEP "%s/%s/lib/dll" PATH_SEP "%s/%s/usr/lib", // use a platform-specific character as path separator
1251
         #define APPLY_DEFAULT_ATTR_NUM(attr,descr,fmt) do { if (entry_parms.attr != default_parms->attr) { \
-
 
1252
               LOG_INFO ("changing default " descr " from " fmt " to " fmt " by attribute at \"%s\" line %d", default_parms->attr, entry_parms.attr, buildfile_pathname, lineno); \
1040
                 QNX_TARGET, processor,
1253
               default_parms->attr = entry_parms.attr; \
1041
                 QNX_TARGET, processor,
1254
            } } while (0)
1042
                 QNX_TARGET, processor,
1255
         #define APPLY_DEFAULT_ATTR_STR(attr,descr,fmt) do { if (((default_parms->attr == NULL) && (entry_parms.attr != NULL)) || ((default_parms->attr != NULL) && (entry_parms.attr == NULL)) || ((default_parms->attr != NULL) && (entry_parms.attr != NULL) && (strcmp (entry_parms.attr, default_parms->attr) != 0))) { \
-
 
1256
            LOG_INFO ("changing default " descr " from " fmt " to " fmt " by attribute at \"%s\" line %d", (default_parms->attr != NULL ? default_parms->attr : "none"), entry_parms.attr, buildfile_pathname, lineno); \
1043
                 QNX_TARGET, processor_base,
1257
               default_parms->attr = entry_parms.attr; \
1044
                 QNX_TARGET, processor,
1258
            } } while (0)
-
 
1259
         //APPLY_DEFAULT_ATTR_STR (new_cwd,                  "current working directory",       "\"%s\"");
-
 
1260
         APPLY_DEFAULT_ATTR_STR (search,                   "search path list",                "\"%s\"");
-
 
1261
         APPLY_DEFAULT_ATTR_STR (prefix,                   "prefix",                          "\"%s\"");
-
 
1262
         APPLY_DEFAULT_ATTR_NUM (dperms,                   "directory permissions",           "0%o");
-
 
1263
         APPLY_DEFAULT_ATTR_NUM (perms,                    "file permissions",                "0%o");
-
 
1264
         APPLY_DEFAULT_ATTR_NUM (uid,                      "owner ID",                        "%d");
-
 
1265
         APPLY_DEFAULT_ATTR_NUM (gid,                      "group ID",                        "%d");
-
 
1266
         APPLY_DEFAULT_ATTR_NUM (st_mode,                  "inode type",                      "0%o");
-
 
1267
         APPLY_DEFAULT_ATTR_NUM (is_compiled_bootscript,   "compiled script state",           "%d");
-
 
1268
         APPLY_DEFAULT_ATTR_NUM (should_follow_symlinks,   "symlink resolution",              "%d");
-
 
1269
         APPLY_DEFAULT_ATTR_NUM (should_autosymlink_dylib, "dylib canonical name symlinking", "%d");
-
 
1270
         APPLY_DEFAULT_ATTR_NUM (should_keep_ld_output,    "linker output preservation",      "%d");
1045
                 QNX_TARGET, processor,
1271
         #undef APPLY_DEFAULT_ATTR_STR
1046
                 QNX_TARGET, processor,
1272
         #undef APPLY_DEFAULT_ATTR_NUM
-
 
1273
         return; // end of line reached, proceed to the next line
-
 
1274
      }
1047
                 QNX_TARGET, processor,
1275
      // end of attributes parsing
-
 
1276
   } // end of "this line starts with an attributes block"
-
 
1277
 
-
 
1278
   // there's data in this line. We expect a filename in the IFS. Read it and unescape escaped characters
-
 
1279
   string_len = sprintf_s (path_in_ifs, sizeof (path_in_ifs), "%s", (entry_parms.prefix != NULL ? entry_parms.prefix : ""));
-
 
1280
   while ((string_len > 0) && (path_in_ifs[string_len - 1] == '/'))
-
 
1281
      string_len--; // chop off any trailing slashes from prefix
1048
                 QNX_TARGET, processor);
1282
   write_ptr = &path_in_ifs[string_len];
-
 
1283
   *write_ptr++ = '/'; // add ONE trailing slash
-
 
1284
   specifiedpathname_start = write_ptr; // remember the specified pathname will start here
-
 
1285
   is_quoted_context = (*line_ptr == '"');
-
 
1286
   if (is_quoted_context)
-
 
1287
      line_ptr++; // skip a possible initial quote
-
 
1288
   if (*line_ptr == '/')
-
 
1289
   {
-
 
1290
      LOG_WARNING ("paths in the IFS file should not begin with a leading '/' in \"%s\" line %d", buildfile_pathname, lineno);
-
 
1291
      line_ptr++; // consistency check: paths in the IFS should not begin with a '/'
1049
   }
1292
   }
-
 
1293
   while ((*line_ptr != 0) && ((!is_quoted_context && (*line_ptr != '=') && !isspace (*line_ptr)) || (is_quoted_context && (*line_ptr == '"'))))
-
 
1294
   {
-
 
1295
      if (*line_ptr == '\\')
-
 
1296
      {
-
 
1297
         line_ptr++;
-
 
1298
         *write_ptr++ = *line_ptr; // unescape characters that are escaped with '\'
-
 
1299
      }
-
 
1300
      else
-
 
1301
         *write_ptr++ = *line_ptr;
-
 
1302
      line_ptr++;
-
 
1303
   }
-
 
1304
   *write_ptr = 0; // terminate the string
-
 
1305
   if (is_quoted_context && (*line_ptr == '"'))
-
 
1306
      line_ptr++; // skip a possible final quote
-
 
1307
 
-
 
1308
   // we reached a space OR an equal sign
-
 
1309
   while ((*line_ptr != 0) && isspace (*line_ptr))
-
 
1310
      line_ptr++; // skip optional spaces after the filename in the IFS
-
 
1311
 
-
 
1312
   // do we have an equal sign ?
-
 
1313
   if (*line_ptr == '=') // we must be creating either a directory or a file, do we have an equal sign ?
-
 
1314
   {
-
 
1315
      line_ptr++; // skip the equal sign
-
 
1316
      while ((*line_ptr != 0) && isspace (*line_ptr))
-
 
1317
         line_ptr++; // skip optional spaces after the equal sign
-
 
1318
 
-
 
1319
      if (*line_ptr == 0)
-
 
1320
      {
-
 
1321
         LOG_WARNING ("syntax error in \"%s\" line %d: missing data specification after equal sign (skipping)", buildfile_pathname, lineno);
-
 
1322
         return; // invalid symlink specification, skip line
-
 
1323
      }
-
 
1324
 
-
 
1325
      // read the host system's path, it may be either a path or a contents definition. Is it a content definition ?
-
 
1326
      if (*line_ptr == '{')
-
 
1327
      {
-
 
1328
         allocated_size = 0;
-
 
1329
 
-
 
1330
         line_ptr++; // skip the leading content definition
-
 
1331
         is_escaped_char = false;
-
 
1332
         for (;;)
-
 
1333
         {
-
 
1334
            read_char = fgetc (buildfile_fp);
-
 
1335
            if (read_char == EOF)
-
 
1336
               DIE_WITH_EXITCODE (1, "syntax error in \"%s\" line %d: unterminated contents block (end of file reached)", buildfile_pathname, lineno); // invalid contents block
-
 
1337
            else if ((read_char == '\\') && !is_escaped_char)
-
 
1338
               is_escaped_char = true; // remember the next char is escaped
-
 
1339
            else if ((read_char == '}') && !is_escaped_char)
-
 
1340
               break; // found an unescaped closing bracked, stop parsing
-
 
1341
            else
-
 
1342
            {
-
 
1343
               is_escaped_char = false; // any other char, meaning the next one will not be escaped
-
 
1344
               if (!should_discard_inline_contents) // only store the contents if we do NOT know the data yet
-
 
1345
               {
-
 
1346
                  if (entry_parms.data.size == allocated_size) // reallocate in 4 kb blocks
-
 
1347
                  {
-
 
1348
                     reallocated_ptr = realloc (entry_parms.data.bytes, allocated_size + 4096);
-
 
1349
                     ASSERT_WITH_ERRNO (reallocated_ptr);
-
 
1350
                     entry_parms.data.bytes = reallocated_ptr;
-
 
1351
                     allocated_size += 4096;
-
 
1352
                  }
-
 
1353
                  entry_parms.data.bytes[entry_parms.data.size++] = read_char;
-
 
1354
               }
-
 
1355
               if (read_char == '\n')
-
 
1356
                  lineno++; // update line counter as we parse the inline content
-
 
1357
            }
-
 
1358
         } // end for
-
 
1359
      }
-
 
1360
      else // not a content definition between { brackets }, must be either a pathname on the build host, or the target of a symlink
-
 
1361
      {
-
 
1362
         is_quoted_context = (*line_ptr == '"');
-
 
1363
         if (is_quoted_context)
-
 
1364
            line_ptr++; // skip a possible initial quote
-
 
1365
         specifiedpathname_start = line_ptr; // remember where the specified pathname starts
-
 
1366
         write_ptr = line_ptr; // now unescape all characters
-
 
1367
         while ((*line_ptr != 0) && ((!is_quoted_context && !isspace (*line_ptr)) || (is_quoted_context && (*line_ptr == '"'))))
-
 
1368
         {
-
 
1369
            if (*line_ptr == '\\')
-
 
1370
            {
-
 
1371
               line_ptr++;
-
 
1372
               *write_ptr++ = *line_ptr; // unescape characters that are escaped with '\'
-
 
1373
            }
-
 
1374
            else
-
 
1375
               *write_ptr++ = *line_ptr;
-
 
1376
            line_ptr++;
-
 
1377
         }
-
 
1378
         *write_ptr = 0; // terminate the string
-
 
1379
         if (is_quoted_context && (*line_ptr == '"'))
-
 
1380
            line_ptr++; // skip a possible final quote
-
 
1381
 
-
 
1382
         if (S_ISLNK (entry_parms.st_mode)) // are we storing a symlink ?
-
 
1383
            ASSERT_WITH_ERRNO (Buffer_InitWithCString (&entry_parms.data, specifiedpathname_start)); // if so, store the symlink target as the dirent's blob data
-
 
1384
         else // it's a build host filesystem path
-
 
1385
            strcpy_s (path_on_buildhost, sizeof (path_on_buildhost), specifiedpathname_start); // the path on the build host is given after the equal sign
-
 
1386
      }
-
 
1387
   }
-
 
1388
   else // no equal sign, meaning the file will have the same name on the build host filesystem
-
 
1389
   {
-
 
1390
      // consistency check: symlinks MUST have an equal sign
-
 
1391
      if (entry_parms.st_mode == S_IFLNK)
-
 
1392
      {
-
 
1393
         LOG_WARNING ("syntax error in \"%s\" line %d: missing equal sign and symlink target (skipping)", buildfile_pathname, lineno);
-
 
1394
         return; // invalid symlink specification, skip line
-
 
1395
      }
-
 
1396
 
-
 
1397
      strcpy_s (path_on_buildhost, sizeof (path_on_buildhost), specifiedpathname_start); // the path on the build host is the one specified
-
 
1398
      sep = strrchr (specifiedpathname_start, '/');
-
 
1399
      if (sep != NULL)
-
 
1400
         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)
-
 
1401
   }
-
 
1402
 
-
 
1403
   // now add this entry to the image filesystem
-
 
1404
   if (S_ISDIR (entry_parms.st_mode))
-
 
1405
      entry_parms.st_mode |= entry_parms.dperms;
-
 
1406
   else if (S_ISLNK (entry_parms.st_mode))
-
 
1407
      entry_parms.st_mode |= 0777; // NOTE: mkifs sets symlink permissions to rwxrwxrwx !?
-
 
1408
   else // file or device node
-
 
1409
      entry_parms.st_mode |= entry_parms.perms;
-
 
1410
 
-
 
1411
   add_fsentry (fsentries, fsentry_count, &entry_parms, path_in_ifs, path_on_buildhost); // and add filesystem entry
-
 
1412
 
-
 
1413
   if (entry_parms.data.bytes != NULL)
-
 
1414
      free (entry_parms.data.bytes); // if blob data was allocated, free it
1050
 
1415
 
1051
   return;
1416
   return; //  finished parsing that line
1052
}
1417
}
1053
 
1418
 
1054
 
1419
 
1055
int main (int argc, char **argv)
1420
int main (int argc, char **argv)
1056
{
1421
{
Line 1088... Line 1453...
1088
      .prefix = "/proc/boot",
1453
      .prefix = "/proc/boot",
1089
      .should_follow_symlinks = true, // [+|-followlink]
1454
      .should_follow_symlinks = true, // [+|-followlink]
1090
      .should_autosymlink_dylib = true, // [+|-autolink]
1455
      .should_autosymlink_dylib = true, // [+|-autolink]
1091
      .is_compiled_bootscript = false, // [+|-script]
1456
      .is_compiled_bootscript = false, // [+|-script]
1092
      .extra_ino_flags = 0,
1457
      .extra_ino_flags = 0,
1093
      .search = "",
1458
      .search = NULL,
1094
      .data = { NULL, 0 }
1459
      .data = { NULL, 0 }
1095
   };
1460
   };
1096
   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)
1461
   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)
1097
 
1462
 
1098
   char path_on_buildhost[MAXPATHLEN] = "";
1463
   char path_on_buildhost[MAXPATHLEN] = "";
1099
   char path_in_ifs[MAXPATHLEN] = "";
1464
   char path_in_ifs[MAXPATHLEN] = "";
1100
   char *ifs_pathname = NULL;
1465
   char *ifs_pathname = NULL;
1101
   void *reallocated_ptr;
1466
   void *reallocated_ptr;
1102
   struct tm utc_time;
-
 
1103
   struct stat stat_buf;
-
 
1104
   size_t imgdir_size;
1467
   size_t reallocated_size;
1105
   size_t available_space;
1468
   size_t available_space;
1106
   size_t allocated_size;
-
 
1107
   size_t fsentry_index;
1469
   size_t fsentry_index;
1108
   size_t largest_index;
1470
   size_t largest_index;
1109
   size_t largest_size;
1471
   size_t largest_size;
-
 
1472
   size_t imgdir_size;
1110
   size_t curr_offset;
1473
   size_t curr_offset;
1111
   ifs_t ifs = { 0 };
1474
   ifs_t ifs = { 0 };
1112
   int32_t checksum;
1475
   int32_t checksum;
1113
   char *first_pathname = NULL;
1476
   char *first_pathname = NULL;
1114
   char *second_pathname = NULL;
1477
   char *second_pathname = NULL;
1115
   char *specifiedpathname_start;
-
 
1116
   char *directiveblock_start;
-
 
1117
   char *write_ptr;
-
 
1118
   char *line_ptr;
-
 
1119
   char *token;
-
 
1120
   char *value;
-
 
1121
   char *sep;
1478
   char *sep;
1122
   char *ctx;
-
 
1123
   int arg_index;
1479
   int arg_index;
1124
   bool is_quoted_context = false;
1480
   bool is_quoted_context = false;
1125
   bool is_escaped_char = false;
1481
   bool is_escaped_char = false;
1126
   bool should_discard_inline_contents = false;
1482
   bool should_discard_inline_contents = false;
1127
   bool want_info = false;
1483
   bool want_info = false;
Line 1129... Line 1485...
1129
   bool want_help = false;
1485
   bool want_help = false;
1130
   bool want_dump = false;
1486
   bool want_dump = false;
1131
   bool want_strip = false;
1487
   bool want_strip = false;
1132
   bool want_hexdump = false;
1488
   bool want_hexdump = false;
1133
   bool is_foreign_endianness;
1489
   bool is_foreign_endianness;
1134
   int string_len;
-
 
1135
   int read_char;
-
 
1136
   FILE *buildfile_fp;
1490
   FILE *buildfile_fp;
-
 
1491
 
-
 
1492
   // initialize stuff
-
 
1493
   saved_ELF_sections = (char **) malloc (4 * sizeof (char *));
-
 
1494
   ASSERT_WITH_ERRNO (saved_ELF_sections);
-
 
1495
   saved_ELF_sections[0] = "QNX_info"; // NOTE: MUST BE THE FIRST ONE as we artificially shrink down the array to 1 when using it for boot ELF files
-
 
1496
   saved_ELF_sections[1] = ".gnu_debuglink";
-
 
1497
   saved_ELF_sections[2] = "QNX_usage";
-
 
1498
   saved_ELF_sections[3] = ".note.gnu.build-id"; // undocumented by QNX, but nonetheless preserved
-
 
1499
   saved_ELF_section_count = 4;
1137
 
1500
 
1138
   // parse arguments
1501
   // parse arguments
1139
   for (arg_index = 1; arg_index < argc; arg_index++)
1502
   for (arg_index = 1; arg_index < argc; arg_index++)
1140
   {
1503
   {
1141
      if ((strcmp (argv[arg_index], "--bootfile") == 0) && (arg_index + 1 < argc)) // --bootfile path/to/blob.bin
1504
      if ((strcmp (argv[arg_index], "--bootfile") == 0) && (arg_index + 1 < argc)) // --bootfile path/to/blob.bin
Line 1179... Line 1542...
1179
         want_strip = true;
1542
         want_strip = true;
1180
      else if (strcmp (argv[arg_index], "--everything") == 0)
1543
      else if (strcmp (argv[arg_index], "--everything") == 0)
1181
         want_everything = true;
1544
         want_everything = true;
1182
      else if (strncmp (argv[arg_index], "-v", 2) == 0) // -v[....]
1545
      else if (strncmp (argv[arg_index], "-v", 2) == 0) // -v[....]
1183
         verbose_level += (int) strlen (argv[arg_index] + 1); // increase verbosity by the number of characters in this flag
1546
         verbose_level += (int) strlen (argv[arg_index] + 1); // increase verbosity by the number of characters in this flag
-
 
1547
      else if ((strcmp (argv[arg_index], "-l") == 0) && (arg_index + 1 < argc))
-
 
1548
         arg_index++; // these args will be parsed once the build file is open
-
 
1549
      else if ((strcmp (argv[arg_index], "-r") == 0) && (arg_index + 1 < argc))
-
 
1550
      {
-
 
1551
         reallocated_size = (SEARCH_PATH != NULL ? strlen (SEARCH_PATH) + 1 : 0) + strlen (argv[arg_index + 1]) + 1;
-
 
1552
         reallocated_ptr = realloc (SEARCH_PATH, reallocated_size); // grow search prefixes array
-
 
1553
         ASSERT_WITH_ERRNO (reallocated_ptr);
-
 
1554
         if (SEARCH_PATH != NULL)
-
 
1555
            strcat_s (reallocated_ptr, reallocated_size, PATH_SEP);
-
 
1556
         strcat_s (reallocated_ptr, reallocated_size, argv[++arg_index]); // stack up another search prefix
-
 
1557
         SEARCH_PATH = reallocated_ptr;
-
 
1558
      }
-
 
1559
      else if ((strcmp (argv[arg_index], "-s") == 0) && (arg_index + 1 < argc))
-
 
1560
      {
-
 
1561
         reallocated_ptr = realloc (saved_ELF_sections, (saved_ELF_section_count + 1) * sizeof (char *)); // grow ELF sections array
-
 
1562
         ASSERT_WITH_ERRNO (reallocated_ptr);
-
 
1563
         saved_ELF_sections = reallocated_ptr;
-
 
1564
         saved_ELF_sections[saved_ELF_section_count++] = argv[++arg_index]; // stack up another ELF section name to preserve
-
 
1565
      }
1184
      else if ((strcmp (argv[arg_index], "-?") == 0) || (strcmp (argv[arg_index], "--help") == 0))
1566
      else if ((strcmp (argv[arg_index], "-?") == 0) || (strcmp (argv[arg_index], "--help") == 0))
1185
         want_help = true;
1567
         want_help = true;
1186
      else if (first_pathname == NULL)
1568
      else if (first_pathname == NULL)
1187
         first_pathname = argv[arg_index];
1569
         first_pathname = argv[arg_index];
1188
      else if (second_pathname == NULL)
1570
      else if (second_pathname == NULL)
Line 1198... Line 1580...
1198
      fprintf (out, "ifstool - QNX in-kernel filesystem creation utility by Pierre-Marie Baty <pm@pmbaty.com>\n");
1580
      fprintf (out, "ifstool - QNX in-kernel filesystem creation utility by Pierre-Marie Baty <pm@pmbaty.com>\n");
1199
      fprintf (out, "          version " VERSION_FMT_YYYYMMDD "\n", VERSION_ARG_YYYYMMDD);
1581
      fprintf (out, "          version " VERSION_FMT_YYYYMMDD "\n", VERSION_ARG_YYYYMMDD);
1200
      if (!want_help)
1582
      if (!want_help)
1201
         fprintf (out, "error: missing parameters\n");
1583
         fprintf (out, "error: missing parameters\n");
1202
      fprintf (out, "usage:\n");
1584
      fprintf (out, "usage:\n");
1203
      fprintf (out, "    ifstool [--bootfile <pathname>] [--startupfile <pathname>@<EP_from_imgbase>] [--kernelfile <pathname>@<fileoffs>] [-n[n]] [-v[...]] <buildfile> <outfile>\n");
-
 
1204
      fprintf (out, "    ifstool --info [--everything] <ifs file>\n");
1585
      fprintf (out, "    ifstool --info [--everything] <ifs file>\n");
1205
      fprintf (out, "    ifstool --dump [--outdir <path>] <ifs file>\n");
1586
      fprintf (out, "    ifstool --dump [--outdir <path>] <ifs file>\n");
1206
      fprintf (out, "    ifstool --strip [--outfile <pathname>] <ELF file>\n");
1587
      fprintf (out, "    ifstool --strip [--outfile <pathname>] <ELF file>\n");
1207
      fprintf (out, "    ifstool --help\n");
1588
      fprintf (out, "    ifstool [-?|--help]\n");
-
 
1589
      fprintf (out, "    ifstool [--bootfile <pathname>] [--startupfile <pathname>@<EP_from_imgbase>] [--kernelfile <pathname>@<fileoffs>] [-l inputline] [-n[n]] [-r rootdir] [-v[...]] <buildfile> <outfile>\n");
1208
      fprintf (out, "NOTE: the compilation feature requires predigested boot, startup and kernel files produced by mkifs.\n");
1590
      fprintf (out, "NOTE: the compiler mode requires predigested boot, startup and kernel files produced by mkifs.\n");
-
 
1591
      fprintf (out, "options:\n");
-
 
1592
      fprintf (out, "    -?       Display some help information.\n");
-
 
1593
//      fprintf (out, "    -a .ext  Append a suffix to symbol files generated via [+keeplinked].\n");
-
 
1594
      fprintf (out, "    -l line  Process line before interpreting the buildfile. Input lines given\n");
-
 
1595
      fprintf (out, "             to mkifs should be quoted to prevent interpretation by the shell\n");
-
 
1596
      fprintf (out, "             (especially as mkifs input lines often contain spaces). Multiple\n");
-
 
1597
      fprintf (out, "             -l options are processed in the order specified. No default.\n");
-
 
1598
      fprintf (out, "    -n[n]    Force the modification times of all inline files to be 0. If you\n");
-
 
1599
      fprintf (out, "             specify -nn, mkifs sets the modification times of all files to 0.\n");
-
 
1600
      fprintf (out, "             When mkifs adds files to an IFS image, it uses the timestamp info\n");
-
 
1601
      fprintf (out, "             from the file on the host machine. If mkifs is creating an inline\n");
-
 
1602
      fprintf (out, "             file (which doesn't exist on the host machine), it must generate\n");
-
 
1603
      fprintf (out, "             its own timestamp information. By default, it's the time at which\n");
-
 
1604
      fprintf (out, "             the image is generated. This results in different checksum values\n");
-
 
1605
      fprintf (out, "             for two identical builds, because the file's times are different.\n");
-
 
1606
      fprintf (out, "             If you use -n, the checksum value is the same on all identical\n");
-
 
1607
      fprintf (out, "             builds. The -nn option addresses a quirk in NTFS with daylight\n");
-
 
1608
      fprintf (out, "             savings time. This forces the modification time for all files in\n");
-
 
1609
      fprintf (out, "             the IFS image to be set to 0. This ensures that subsequent builds\n");
-
 
1610
      fprintf (out, "             of the same IFS image have the same checksum.");
-
 
1611
//      fprintf (out, "    -o dir   Specify a directory to be used for all permanent build artifacts,\n");
-
 
1612
//      fprintf (out, "             other than the output image itself. The most common example is\n");
-
 
1613
//      fprintf (out, "             the .sym files generated by the [+keeplinked] attribute.\n");
-
 
1614
//      fprintf (out, "    -p file  Apply patching instructions from this file.\n");
-
 
1615
      fprintf (out, "    -r dir   When searching for host files to be included in the image, search\n");
-
 
1616
      fprintf (out, "             the default paths used for storing binaries within the specified\n");
-
 
1617
      fprintf (out, "             directory before searching the default paths within $QNX_TARGET.\n");
-
 
1618
      fprintf (out, "             You can define multiple -r options; each adds a set of paths to\n");
-
 
1619
      fprintf (out, "             search for files. The -r options are evaluated from left to right\n");
-
 
1620
      fprintf (out, "             meaning the paths prefixed with the first (leftmost) rootdir are\n");
-
 
1621
      fprintf (out, "             searched first, then those prefixed with the second rootdir, and\n");
-
 
1622
      fprintf (out, "             so on.\n");
-
 
1623
      fprintf (out, "             Normally, mkifs searches any paths defined in $MKIFS_PATH when\n");
-
 
1624
      fprintf (out, "             it was called and then the default paths within $QNX_TARGET. The\n");
-
 
1625
      fprintf (out, "             default paths are based on the CPU architecture specified by\n");
-
 
1626
      fprintf (out, "             $PROCESSOR and $PROCESSOR_BASE. If you specify -r options, mkifs\n");
-
 
1627
      fprintf (out, "             searches the default paths prefixed with each dir variable before\n");
-
 
1628
      fprintf (out, "             searching those within $QNX_TARGET. These paths are:\n");
-
 
1629
      fprintf (out, "               dir/${PROCESSOR}/sbin\n");
-
 
1630
      fprintf (out, "               dir/${PROCESSOR}/usr/sbin\n");
-
 
1631
      fprintf (out, "               dir/${PROCESSOR}/boot/sys\n");
-
 
1632
      fprintf (out, "               dir/${PROCESSOR_BASE}/boot/sys\n");
-
 
1633
      fprintf (out, "               dir/${PROCESSOR}/bin\n");
-
 
1634
      fprintf (out, "               dir/${PROCESSOR}/usr/bin\n");
-
 
1635
      fprintf (out, "               dir/${PROCESSOR}/lib\n");
-
 
1636
      fprintf (out, "               dir/${PROCESSOR}/lib/dll\n");
-
 
1637
      fprintf (out, "               dir/${PROCESSOR}/usr/lib\n");
-
 
1638
      fprintf (out, "             NOTE: The structure of the directory paths under dir must be\n");
-
 
1639
      fprintf (out, "             identical to that of the default paths under $QNX_TARGET, but the\n");
-
 
1640
      fprintf (out, "             root dir itself may be any path you choose. For example, if you\n");
-
 
1641
      fprintf (out, "             wanted to include /scratch/aarch64le/sbin/devb-sata, you would\n");
-
 
1642
      fprintf (out, "             specify a -r option like this:\n");
-
 
1643
      fprintf (out, "               -r /scratch\n");
-
 
1644
      fprintf (out, "             Note that you don't include $PROCESSOR or $PROCESSOR_BASE in dir.\n");
-
 
1645
      fprintf (out, "    -s name  Don't strip the named section from ELF executables when creating\n");
-
 
1646
      fprintf (out, "             an IFS image. You can use this option more than once to specify\n");
-
 
1647
      fprintf (out, "             additional sections. By default, mkifs doesn't strip:\n");
-
 
1648
      fprintf (out, "               .gnu_debuglink - the name and checksum of the debug info file\n");
-
 
1649
      fprintf (out, "               QNX_info       - build properties\n");
-
 
1650
      fprintf (out, "               QNX_usage      - usage message\n");
-
 
1651
      fprintf (out, "             You can use the keepsection attribute to specify the sections\n");
-
 
1652
      fprintf (out, "             that are not to be stripped from specific files in the image. For\n");
-
 
1653
      fprintf (out, "             files in the bootstrap section (like startup or procnto), the\n");
-
 
1654
      fprintf (out, "             global keepsection list affected by -s does not apply to these\n");
-
 
1655
      fprintf (out, "             files. For them, only the QNX_info section is kept.\n");
-
 
1656
      fprintf (out, "    -v[v..]  Operate verbosely. Specifying additional v options increases the\n");
-
 
1657
      fprintf (out, "             verbosity.\n");
1209
      exit (want_help ? 0 : 1);
1658
      exit (want_help ? 0 : 1);
1210
   }
1659
   }
1211
 
1660
 
1212
   // do we want info about a particular IFS ? if so, dissecate it
1661
   // do we want info about a particular IFS ? if so, dissecate it
1213
   if (want_info)
1662
   if (want_info)
Line 1224... Line 1673...
1224
   // else do we want to strip an ELF file ? if so, do so
1673
   // else do we want to strip an ELF file ? if so, do so
1225
   else if (want_strip)
1674
   else if (want_strip)
1226
   {
1675
   {
1227
      buffer_t file;
1676
      buffer_t file;
1228
      ASSERT (Buffer_ReadFromFile (&file, first_pathname), "can't open \"%s\" for reading: %s", first_pathname, strerror (errno));
1677
      ASSERT (Buffer_ReadFromFile (&file, first_pathname), "can't open \"%s\" for reading: %s", first_pathname, strerror (errno));
1229
      ASSERT (Buffer_StripELFFile (&file, first_pathname), "error stripping \"%s\": %s", first_pathname, strerror (errno));
1678
      ASSERT (Buffer_StripELFFile (&file, saved_ELF_sections, saved_ELF_section_count, first_pathname), "error stripping \"%s\": %s", first_pathname, strerror (errno));
1230
      ASSERT_WITH_ERRNO (Buffer_WriteToFile (&file, (second_pathname != NULL ? second_pathname : "<stdout>")));
1679
      ASSERT_WITH_ERRNO (Buffer_WriteToFile (&file, (second_pathname != NULL ? second_pathname : "<stdout>")));
1231
      exit (0);
1680
      exit (0);
1232
   }
1681
   }
1233
 
1682
 
1234
   // we want to CREATE an IFS file
1683
   // we want to CREATE an IFS file
Line 1239... Line 1688...
1239
   QNX_TARGET = getenv ("QNX_TARGET");
1688
   QNX_TARGET = getenv ("QNX_TARGET");
1240
   if (QNX_TARGET == NULL)
1689
   if (QNX_TARGET == NULL)
1241
      DIE_WITH_EXITCODE (1, "the QNX_TARGET environment variable is not set");
1690
      DIE_WITH_EXITCODE (1, "the QNX_TARGET environment variable is not set");
1242
   else if (access (QNX_TARGET, 0) != 0)
1691
   else if (access (QNX_TARGET, 0) != 0)
1243
      DIE_WITH_EXITCODE (1, "the QNX_TARGET environment variable doesn't point to an existing directory");
1692
      DIE_WITH_EXITCODE (1, "the QNX_TARGET environment variable doesn't point to an existing directory");
1244
 
-
 
1245
   // prepare a default MKIFS_PATH assuming the host processor
-
 
1246
   update_MKIFS_PATH (image_processor);
-
 
1247
 
1693
 
1248
   // open build file
1694
   // open build file
1249
   fopen_s (&buildfile_fp, buildfile_pathname, "rb");
1695
   fopen_s (&buildfile_fp, buildfile_pathname, "rb");
1250
   if (buildfile_fp == NULL)
1696
   if (buildfile_fp == NULL)
1251
      DIE_WITH_EXITCODE (1, "unable to open build file \"%s\" for reading: %s", buildfile_pathname, strerror (errno));
1697
      DIE_WITH_EXITCODE (1, "unable to open build file \"%s\" for reading: %s", buildfile_pathname, strerror (errno));
1252
 
1698
 
1253
   // stack up filesystem entries
1699
   // stack up filesystem entries
1254
   memcpy (&entry_parms, &default_parms, sizeof (default_parms));
1700
   memcpy (&entry_parms, &default_parms, sizeof (default_parms));
1255
   entry_parms.st_mode = S_IFDIR | default_parms.dperms;
1701
   entry_parms.st_mode = S_IFDIR | default_parms.dperms;
1256
   add_fsentry (&fsentries, &fsentry_count, &entry_parms, "", NULL); // add the root dir first
1702
   add_fsentry (&fsentries, &fsentry_count, &entry_parms, "", NULL); // add the root dir first
-
 
1703
 
-
 
1704
   // parse -l arguments before everything else
-
 
1705
   for (arg_index = 1; arg_index < argc; arg_index++)
-
 
1706
      if ((strcmp (argv[arg_index], "-l") == 0) && (arg_index + 1 < argc))
-
 
1707
         parse_line (NULL, argv[++arg_index], &fsentries, &fsentry_count, &default_parms);
1257
 
1708
 
1258
   // parse the IFS build file line per line
1709
   // parse the IFS build file line per line
1259
   while (fgets (line_buffer, sizeof (line_buffer), buildfile_fp) != NULL)
1710
   while (fgets (line_buffer, sizeof (line_buffer), buildfile_fp) != NULL)
1260
   {
1711
   {
1261
      if (current_line != NULL)
1712
      if (current_line != NULL)
1262
         free (current_line);
1713
         free (current_line);
1263
      current_line = strdup (line_buffer);
1714
      current_line = strdup (line_buffer);
1264
      ASSERT_WITH_ERRNO (current_line);
1715
      ASSERT_WITH_ERRNO (current_line);
1265
      lineno++; // keep track of current line number
1716
      lineno++; // keep track of current line number
-
 
1717
      parse_line (buildfile_fp, line_buffer, &fsentries, &fsentry_count, &default_parms);
-
 
1718
   }
1266
 
1719
 
1267
      line_ptr = line_buffer;
-
 
1268
      while ((*line_ptr != 0) && isspace (*line_ptr))
1720
   fclose (buildfile_fp); // finished parsing the build file
1269
         line_ptr++; // skip leading spaces
-
 
1270
 
1721
 
1271
      if ((*line_ptr == 0) || (*line_ptr == '#'))
-
 
1272
         continue; // skip empty or comment lines
-
 
1273
 
-
 
1274
      string_len = (int) strlen (line_buffer);
1722
   // parse the IFS build file line per line
1275
      if ((string_len > 0) && (line_buffer[string_len - 1] == '\n'))
1723
   while (fgets (line_buffer, sizeof (line_buffer), buildfile_fp) != NULL)
1276
         line_buffer[string_len - 1] = 0; // chop off newline for easier debug output
-
 
1277
 
-
 
1278
      // reset entry values
-
 
1279
      memcpy (&entry_parms, &default_parms, sizeof (default_parms));
-
 
1280
      path_in_ifs[0] = 0;
-
 
1281
      path_on_buildhost[0] = 0;
-
 
1282
      should_discard_inline_contents = false;
-
 
1283
 
-
 
1284
      // does this line start with an attribute block ?
-
 
1285
      if (*line_ptr == '[')
-
 
1286
      {
1724
   {
1287
         line_ptr++; // skip the leading square bracket
-
 
1288
         directiveblock_start = line_ptr; // remember where it starts
-
 
1289
         is_quoted_context = false;
-
 
1290
         while ((*line_ptr != 0) && !((*line_ptr == ']') && (line_ptr[-1] != '\\') && !is_quoted_context))
-
 
1291
         {
-
 
1292
            if (*line_ptr == '"')
-
 
1293
               is_quoted_context ^= true; // remember when we're between quotes
-
 
1294
            else if (!is_quoted_context && (*line_ptr == ' '))
-
 
1295
               *line_ptr = RECORD_SEP[0]; // turn all spaces outside quoted contexts into an ASCII record separator to ease token splitting
-
 
1296
            line_ptr++; // reach the next unescaped closing square bracket
-
 
1297
         }
-
 
1298
         if (*line_ptr != ']')
-
 
1299
         {
-
 
1300
            LOG ("warning", 0, "syntax error in \"%s\" line %d: unterminated attributes block (skipping)", buildfile_pathname, lineno);
-
 
1301
            continue; // invalid attribute block, skip line
-
 
1302
         }
-
 
1303
         *line_ptr = 0; // end the attribute block so that it is a parsable C string
-
 
1304
 
-
 
1305
         // now parse the attribute tokens
-
 
1306
         // DOCUMENTATION: https://www.qnx.com/developers/docs/8.0/com.qnx.doc.neutrino.utilities/topic/m/mkifs.html#mkifs__description
-
 
1307
         token = strtok_r (directiveblock_start, RECORD_SEP, &ctx);
-
 
1308
         while (token != NULL)
1725
      if (current_line != NULL)
1309
         {
-
 
1310
            // evaluate attribute token
-
 
1311
            #define REACH_TOKEN_VALUE() do { value = strchr (token, '=') + 1; if (*value == '"') value++; } while (0)
-
 
1312
            if      (strncmp (token, "uid=",     4) == 0) { REACH_TOKEN_VALUE (); entry_parms.uid     = (int) read_integer (value); }
-
 
1313
            else if (strncmp (token, "gid=",     4) == 0) { REACH_TOKEN_VALUE (); entry_parms.gid     = (int) read_integer (value); }
-
 
1314
            else if (strncmp (token, "dperms=",  7) == 0) { REACH_TOKEN_VALUE (); entry_parms.dperms  = (int) read_integer (value); }
-
 
1315
            else if (strncmp (token, "perms=",   6) == 0) { REACH_TOKEN_VALUE (); entry_parms.perms   = (int) read_integer (value); }
-
 
1316
            else if (strncmp (token, "type=",    5) == 0) { REACH_TOKEN_VALUE ();
-
 
1317
               if      (strcmp (value, "dir")  == 0) entry_parms.st_mode = S_IFDIR;
-
 
1318
               else if (strcmp (value, "file") == 0) entry_parms.st_mode = S_IFREG;
-
 
1319
               else if (strcmp (value, "link") == 0) entry_parms.st_mode = S_IFLNK;
-
 
1320
               else if (strcmp (value, "fifo") == 0) entry_parms.st_mode = S_IFIFO;
-
 
1321
               else DIE_WITH_EXITCODE (1, "invalid 'type' attribute in \"%s\" line %d: '%s'", buildfile_pathname, lineno, value);
-
 
1322
            }
-
 
1323
            else if (strncmp (token, "prefix=",  7) == 0) { REACH_TOKEN_VALUE (); strcpy_s (entry_parms.prefix, sizeof (entry_parms.prefix), (*value == '/' ? value + 1 : value)); } // skip possible leading slash in prefix
-
 
1324
            else if (strncmp (token, "image=",   6) == 0) { REACH_TOKEN_VALUE ();
-
 
1325
               image_base = (uint32_t) read_integer (value); // read image base address
-
 
1326
               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.)
-
 
1327
               if ((sep = strchr (value, ',')) != NULL) image_maxsize   = (uint32_t) read_integer (sep + 1); // if we have a comma, read optional image max size
-
 
1328
               if ((sep = strchr (value, '=')) != NULL) image_totalsize = (uint32_t) read_integer (sep + 1); // if we have an equal sign, read optional image padding size
-
 
1329
               if ((sep = strchr (value, '%')) != NULL) image_align     = (uint32_t) read_integer (sep + 1); // if we have a modulo sign, read optional image aligmnent
-
 
1330
               LOG_INFO ("image 0x%x-0x%x maxsize %d totalsize %d align %d", image_base, image_end, image_maxsize, image_totalsize, image_align);
-
 
1331
            }
-
 
1332
            else if (strncmp (token, "virtual=", 8) == 0) { REACH_TOKEN_VALUE ();
-
 
1333
               if ((bootfile_pathname == NULL) || (startupfile_pathname == NULL) || (kernelfile_pathname == NULL)) // HACK until I figure out how to re-create them
-
 
1334
                  DIE_WITH_EXITCODE (1, "creating bootable images require the --bootfile, --startupfile and --kernelfile command-line options in \"%s\" line %d", buildfile_pathname, lineno);
-
 
1335
               if ((sep = strchr (value, ',')) != NULL) // do we have a comma separating (optional) processor and boot file name ?
-
 
1336
               {
-
 
1337
                  *sep = 0;
-
 
1338
                  strcpy_s (image_processor, sizeof (image_processor), value); // save processor
-
 
1339
                  update_MKIFS_PATH (image_processor);
-
 
1340
                  value = sep + 1;
-
 
1341
               }
-
 
1342
               //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.)
-
 
1343
               //strcpy (image_bootfile, bootfile_pathname); // FIXME: HACK
-
 
1344
               if (stat (bootfile_pathname, &stat_buf) != 0)
-
 
1345
                  DIE_WITH_EXITCODE (1, "unable to stat the boot file \"%s\" specified in \"%s\" line %d: %s", bootfile_pathname, buildfile_pathname, lineno, strerror (errno));
-
 
1346
               bootfile_size = stat_buf.st_size; // save preboot file size
-
 
1347
               LOG_INFO ("processor \"%s\" bootfile \"%s\"\n", image_processor, bootfile_pathname);
-
 
1348
#if 1
-
 
1349
               // ######################################################################################################################################################################################################################################
-
 
1350
               // # FIXME: figure out how to re-create it: linker call involved
-
 
1351
               // # $ x86_64-pc-nto-qnx8.0.0-ld --sysroot=${QNX_TARGET}/x86_64/ -T${QNX_TARGET}/x86_64/lib/nto.link --section-start .text=0xffff800000001000 --no-relax ${QNX_TARGET}/x86_64/boot/sys/procnto-smp-instr -o procnto-smp-instr.sym.UNSTRIPPED
-
 
1352
               // ######################################################################################################################################################################################################################################
-
 
1353
//               if (!Buffer_ReadFromFile (&entry_parms.data, kernelfile_pathname))
-
 
1354
//                  DIE_WITH_EXITCODE (1, "unable to read precompiled kernel file \"%s\" specified in --kernelfile argument: %s", kernelfile_pathname, strerror (errno));
-
 
1355
#else // nonworking
-
 
1356
               strcpy (path_on_buildhost, "procnto-smp-instr");
-
 
1357
#endif // nonworking
-
 
1358
            }
-
 
1359
            else if (strncmp (token, "mtime=", 6) == 0) { REACH_TOKEN_VALUE (); if (strcmp (value, "*") == 0) entry_parms.mtime = UINT32_MAX; else {
-
 
1360
                  // value *must* be "YYYY-MM-DD-HH:MM:SS" by specification
-
 
1361
                  memset (&utc_time, 0, sizeof (utc_time));
-
 
1362
                  if (sscanf_s (value, "%u-%u-%u-%u:%u:%u", &utc_time.tm_year, &utc_time.tm_mon, &utc_time.tm_mday, &utc_time.tm_hour, &utc_time.tm_min, &utc_time.tm_sec) != 6)
-
 
1363
                  {
-
 
1364
                     LOG_WARNING ("syntax error in \"%s\" line %d: mtime specification not in YYYY-MM-DD-HH:MM:SS format (skipping)", buildfile_pathname, lineno);
-
 
1365
                     continue; // invalid attribute block, skip line
-
 
1366
                  }
-
 
1367
                  utc_time.tm_mon--; // convert month from [1-12] to [0-11]
-
 
1368
                  entry_parms.mtime = (uint32_t) mktime (&utc_time);
-
 
1369
               }
-
 
1370
            }
-
 
1371
            else if (strcmp (token, "+script")     == 0) {
-
 
1372
               entry_parms.is_compiled_bootscript = true;
-
 
1373
               ASSERT_WITH_ERRNO (Buffer_InitWithByteArray (&entry_parms.data, INITIAL_STARTUP_SCRIPT)); // FIXME: HACK until the script compiler is implemented
-
 
1374
               should_discard_inline_contents = true; // remember we already have data (so as to discard the inline block's contents)
-
 
1375
            }
-
 
1376
            else if (strcmp (token, "-script")     == 0) entry_parms.is_compiled_bootscript = false;
-
 
1377
            else if (strcmp (token, "+followlink") == 0) entry_parms.should_follow_symlinks = true;
-
 
1378
            else if (strcmp (token, "-followlink") == 0) entry_parms.should_follow_symlinks = false;
-
 
1379
            else if (strcmp (token, "+autolink")   == 0) entry_parms.should_autosymlink_dylib = true;
-
 
1380
            else if (strcmp (token, "-autolink")   == 0) entry_parms.should_autosymlink_dylib = false;
-
 
1381
            else if (strcmp (token, "+keeplinked") == 0) entry_parms.should_keep_ld_output = true;
-
 
1382
            else if (strcmp (token, "-keeplinked") == 0) entry_parms.should_keep_ld_output = false;
-
 
1383
            else LOG_WARNING ("unimplemented attribute in \"%s\" line %d: '%s'", buildfile_pathname, lineno, token);
-
 
1384
            #undef REACH_TOKEN_VALUE
-
 
1385
 
-
 
1386
            token = strtok_r (NULL, RECORD_SEP, &ctx); // proceed to next attribute token
-
 
1387
         }
-
 
1388
 
-
 
1389
         line_ptr++; // reach the next character
-
 
1390
         while ((*line_ptr != 0) && isspace (*line_ptr))
-
 
1391
            line_ptr++; // skip leading spaces
-
 
1392
 
-
 
1393
         // are we at the end of the line ? if so, it means the attribute values that are set should become the default
-
 
1394
         if ((*line_ptr == 0) || (*line_ptr == '#'))
-
 
1395
         {
-
 
1396
            #define APPLY_DEFAULT_ATTR_NUM(attr,descr,fmt) do { if (entry_parms.attr != default_parms.attr) { \
-
 
1397
                  LOG_INFO ("changing default " descr " from " fmt " to " fmt " by attribute at \"%s\" line %d", default_parms.attr, entry_parms.attr, buildfile_pathname, lineno); \
-
 
1398
                  default_parms.attr = entry_parms.attr; \
-
 
1399
               } } while (0)
-
 
1400
            #define APPLY_DEFAULT_ATTR_STR(attr,descr,fmt) do { if (strcmp (entry_parms.attr, default_parms.attr) != 0) { \
-
 
1401
                  LOG_INFO ("changing default " descr " from " fmt " to " fmt " by attribute at \"%s\" line %d", default_parms.attr, entry_parms.attr, buildfile_pathname, lineno); \
-
 
1402
                  strcpy_s (default_parms.attr, sizeof (default_parms.attr), entry_parms.attr); \
-
 
1403
               } } while (0)
-
 
1404
            APPLY_DEFAULT_ATTR_NUM (dperms,                   "directory permissions",           "0%o");
-
 
1405
            APPLY_DEFAULT_ATTR_NUM (perms,                    "file permissions",                "0%o");
-
 
1406
            APPLY_DEFAULT_ATTR_NUM (uid,                      "owner ID",                        "%d");
-
 
1407
            APPLY_DEFAULT_ATTR_NUM (gid,                      "group ID",                        "%d");
-
 
1408
            APPLY_DEFAULT_ATTR_NUM (st_mode,                  "inode type",                      "0%o");
-
 
1409
            APPLY_DEFAULT_ATTR_STR (prefix,                   "prefix",                          "\"%s\"");
-
 
1410
            APPLY_DEFAULT_ATTR_NUM (is_compiled_bootscript,   "compiled script state",           "%d");
-
 
1411
            APPLY_DEFAULT_ATTR_NUM (should_follow_symlinks,   "symlink resolution",              "%d");
-
 
1412
            APPLY_DEFAULT_ATTR_NUM (should_autosymlink_dylib, "dylib canonical name symlinking", "%d");
-
 
1413
            APPLY_DEFAULT_ATTR_NUM (should_keep_ld_output,    "linker output preservation",      "%d");
-
 
1414
            #undef APPLY_DEFAULT_ATTR_STR
-
 
1415
            #undef APPLY_DEFAULT_ATTR_NUM
-
 
1416
            continue; // end of line reached, proceed to the next line
-
 
1417
         }
-
 
1418
         // end of attributes parsing
-
 
1419
      } // end of "this line starts with an attributes block"
-
 
1420
 
-
 
1421
      // there's data in this line. We expect a filename in the IFS. Read it and unescape escaped characters
-
 
1422
      string_len = sprintf_s (path_in_ifs, sizeof (path_in_ifs), "%s", entry_parms.prefix);
-
 
1423
      while ((string_len > 0) && (path_in_ifs[string_len - 1] == '/'))
-
 
1424
         string_len--; // chop off any trailing slashes from prefix
-
 
1425
      write_ptr = &path_in_ifs[string_len];
-
 
1426
      *write_ptr++ = '/'; // add ONE trailing slash
-
 
1427
      specifiedpathname_start = write_ptr; // remember the specified pathname will start here
-
 
1428
      is_quoted_context = (*line_ptr == '"');
-
 
1429
      if (is_quoted_context)
-
 
1430
         line_ptr++; // skip a possible initial quote
-
 
1431
      if (*line_ptr == '/')
-
 
1432
      {
-
 
1433
         LOG_WARNING ("paths in the IFS file should not begin with a leading '/' in \"%s\" line %d", buildfile_pathname, lineno);
-
 
1434
         line_ptr++; // consistency check: paths in the IFS should not begin with a '/'
-
 
1435
      }
-
 
1436
      while ((*line_ptr != 0) && ((!is_quoted_context && (*line_ptr != '=') && !isspace (*line_ptr)) || (is_quoted_context && (*line_ptr == '"'))))
-
 
1437
      {
-
 
1438
         if (*line_ptr == '\\')
-
 
1439
         {
-
 
1440
            line_ptr++;
1726
         free (current_line);
1441
            *write_ptr++ = *line_ptr; // unescape characters that are escaped with '\'
-
 
1442
         }
-
 
1443
         else
-
 
1444
            *write_ptr++ = *line_ptr;
1727
      current_line = strdup (line_buffer);
1445
         line_ptr++;
-
 
1446
      }
-
 
1447
      *write_ptr = 0; // terminate the string
-
 
1448
      if (is_quoted_context && (*line_ptr == '"'))
-
 
1449
         line_ptr++; // skip a possible final quote
-
 
1450
 
-
 
1451
      // we reached a space OR an equal sign
-
 
1452
      while ((*line_ptr != 0) && isspace (*line_ptr))
-
 
1453
         line_ptr++; // skip optional spaces after the filename in the IFS
-
 
1454
 
-
 
1455
      // do we have an equal sign ?
-
 
1456
      if (*line_ptr == '=') // we must be creating either a directory or a file, do we have an equal sign ?
-
 
1457
      {
-
 
1458
         line_ptr++; // skip the equal sign
-
 
1459
         while ((*line_ptr != 0) && isspace (*line_ptr))
-
 
1460
            line_ptr++; // skip optional spaces after the equal sign
-
 
1461
 
-
 
1462
         if (*line_ptr == 0)
-
 
1463
         {
-
 
1464
            LOG_WARNING ("syntax error in \"%s\" line %d: missing data specification after equal sign (skipping)", buildfile_pathname, lineno);
-
 
1465
            continue; // invalid symlink specification, skip line
-
 
1466
         }
-
 
1467
 
-
 
1468
         // read the host system's path, it may be either a path or a contents definition. Is it a content definition ?
-
 
1469
         if (*line_ptr == '{')
-
 
1470
         {
-
 
1471
            allocated_size = 0;
-
 
1472
 
-
 
1473
            line_ptr++; // skip the leading content definition
-
 
1474
            is_escaped_char = false;
-
 
1475
            for (;;)
-
 
1476
            {
-
 
1477
               read_char = fgetc (buildfile_fp);
-
 
1478
               if (read_char == EOF)
-
 
1479
                  DIE_WITH_EXITCODE (1, "syntax error in \"%s\" line %d: unterminated contents block (end of file reached)", buildfile_pathname, lineno); // invalid contents block
-
 
1480
               else if ((read_char == '\\') && !is_escaped_char)
-
 
1481
                  is_escaped_char = true; // remember the next char is escaped
-
 
1482
               else if ((read_char == '}') && !is_escaped_char)
-
 
1483
                  break; // found an unescaped closing bracked, stop parsing
-
 
1484
               else
-
 
1485
               {
-
 
1486
                  is_escaped_char = false; // any other char, meaning the next one will not be escaped
-
 
1487
                  if (!should_discard_inline_contents) // only store the contents if we do NOT know the data yet
-
 
1488
                  {
-
 
1489
                     if (entry_parms.data.size == allocated_size) // reallocate in 4 kb blocks
-
 
1490
                     {
-
 
1491
                        reallocated_ptr = realloc (entry_parms.data.bytes, allocated_size + 4096);
-
 
1492
                        ASSERT_WITH_ERRNO (reallocated_ptr);
1728
      ASSERT_WITH_ERRNO (current_line);
1493
                        entry_parms.data.bytes = reallocated_ptr;
-
 
1494
                        allocated_size += 4096;
-
 
1495
                     }
-
 
1496
                     entry_parms.data.bytes[entry_parms.data.size++] = read_char;
-
 
1497
                  }
-
 
1498
                  if (read_char == '\n')
-
 
1499
                     lineno++; // update line counter as we parse the inline content
-
 
1500
               }
-
 
1501
            } // end for
-
 
1502
         }
-
 
1503
         else // not a content definition between { brackets }, must be either a pathname on the build host, or the target of a symlink
-
 
1504
         {
-
 
1505
            is_quoted_context = (*line_ptr == '"');
-
 
1506
            if (is_quoted_context)
-
 
1507
               line_ptr++; // skip a possible initial quote
-
 
1508
            specifiedpathname_start = line_ptr; // remember where the specified pathname starts
-
 
1509
            write_ptr = line_ptr; // now unescape all characters
-
 
1510
            while ((*line_ptr != 0) && ((!is_quoted_context && !isspace (*line_ptr)) || (is_quoted_context && (*line_ptr == '"'))))
-
 
1511
            {
-
 
1512
               if (*line_ptr == '\\')
-
 
1513
               {
-
 
1514
                  line_ptr++;
-
 
1515
                  *write_ptr++ = *line_ptr; // unescape characters that are escaped with '\'
-
 
1516
               }
-
 
1517
               else
-
 
1518
                  *write_ptr++ = *line_ptr;
-
 
1519
               line_ptr++;
-
 
1520
            }
-
 
1521
            *write_ptr = 0; // terminate the string
-
 
1522
            if (is_quoted_context && (*line_ptr == '"'))
-
 
1523
               line_ptr++; // skip a possible final quote
1729
      lineno++; // keep track of current line number
1524
 
-
 
1525
            if (S_ISLNK (entry_parms.st_mode)) // are we storing a symlink ?
-
 
1526
               ASSERT_WITH_ERRNO (Buffer_InitWithCString (&entry_parms.data, specifiedpathname_start)); // if so, store the symlink target as the dirent's blob data
-
 
1527
            else // it's a build host filesystem path
-
 
1528
               strcpy_s (path_on_buildhost, sizeof (path_on_buildhost), specifiedpathname_start); // the path on the build host is given after the equal sign
-
 
1529
         }
-
 
1530
      }
-
 
1531
      else // no equal sign, meaning the file will have the same name on the build host filesystem
-
 
1532
      {
-
 
1533
         // consistency check: symlinks MUST have an equal sign
-
 
1534
         if (entry_parms.st_mode == S_IFLNK)
-
 
1535
         {
-
 
1536
            LOG_WARNING ("syntax error in \"%s\" line %d: missing equal sign and symlink target (skipping)", buildfile_pathname, lineno);
-
 
1537
            continue; // invalid symlink specification, skip line
-
 
1538
         }
-
 
1539
 
-
 
1540
         strcpy_s (path_on_buildhost, sizeof (path_on_buildhost), specifiedpathname_start); // the path on the build host is the one specified
-
 
1541
         sep = strrchr (specifiedpathname_start, '/');
-
 
1542
         if (sep != NULL)
-
 
1543
            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)
-
 
1544
      }
-
 
1545
 
-
 
1546
      // now add this entry to the image filesystem
-
 
1547
      if (S_ISDIR (entry_parms.st_mode))
-
 
1548
         entry_parms.st_mode |= entry_parms.dperms;
-
 
1549
      else if (S_ISLNK (entry_parms.st_mode))
-
 
1550
         entry_parms.st_mode |= 0777; // NOTE: mkifs sets symlink permissions to rwxrwxrwx !?
-
 
1551
      else // file or device node
-
 
1552
         entry_parms.st_mode |= entry_parms.perms;
-
 
1553
 
-
 
1554
      add_fsentry (&fsentries, &fsentry_count, &entry_parms, path_in_ifs, path_on_buildhost); // and add filesystem entry
-
 
1555
 
1730
 
1556
      if (entry_parms.data.bytes != NULL)
-
 
1557
         free (entry_parms.data.bytes); // if blob data was allocated, free it
-
 
1558
   }
1731
   }
1559
 
1732
 
1560
   fclose (buildfile_fp); // finished parsing the build file
1733
   fclose (buildfile_fp); // finished parsing the build file
1561
 
1734
 
1562
   //////////////////////////////////
1735
   //////////////////////////////////