Subversion Repositories QNX 8.QNX8 IFS tool

Rev

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

Rev 18 Rev 19
Line 18... Line 18...
18
#include <ctype.h>
18
#include <ctype.h>
19
#include <time.h>
19
#include <time.h>
20
 
20
 
21
// platform-specific includes
21
// platform-specific includes
22
#ifdef _MSC_VER
22
#ifdef _MSC_VER
23
#include <io.h>
-
 
24
#include <direct.h>
-
 
25
#include <sys/utime.h>
23
#include <sys/utime.h>
26
#else // !_MSC_VER
24
#else // !_MSC_VER
27
#include <sys/param.h>
25
#include <sys/param.h>
-
 
26
#include <sys/sysmacros.h>
28
#include <unistd.h>
27
#include <unistd.h>
-
 
28
#include <dirent.h>
29
#include <utime.h>
29
#include <utime.h>
30
#endif // _MSC_VER
30
#endif // _MSC_VER
31
 
31
 
32
// own includes
32
// own includes
33
#include "buffer.h"
33
#include "buffer.h"
Line 91... Line 91...
91
   bool should_ignore_duplicates; // [+|-dupignore] whether to ignore duplicates
91
   bool should_ignore_duplicates; // [+|-dupignore] whether to ignore duplicates
92
   bool should_allow_nonexistent_files; // [+|-optional] whether to continue processing on unexistent files
92
   bool should_allow_nonexistent_files; // [+|-optional] whether to continue processing on unexistent files
93
   bool is_compiled_bootscript; // entry has [+script] attribute
93
   bool is_compiled_bootscript; // entry has [+script] attribute
94
   int extra_ino_flags; // bitmap of extra inode flags (IFS_INO_xxx)
94
   int extra_ino_flags; // bitmap of extra inode flags (IFS_INO_xxx)
95
   char *search; // [search=path[:path]] binary search path (the default one will be constructed at startup)
95
   char *search; // [search=path[:path]] binary search path (the default one will be constructed at startup)
-
 
96
 
96
 
97
 
97
   buffer_t data; // the resolved file's own data bytes
98
   buffer_t data; // the resolved file's own data bytes
98
} parms_t;
99
} parms_t;
99
 
100
 
100
 
101
 
Line 125... Line 126...
125
static int lineno = 0; // current line number in IFS build file
126
static int lineno = 0; // current line number in IFS build file
126
static char *QNX_TARGET = NULL; // value of the $QNX_TARGET environment variable
127
static char *QNX_TARGET = NULL; // value of the $QNX_TARGET environment variable
127
static char *SEARCH_PATH = NULL; // mallocated string of search paths, populated by the -r command-line argument
128
static char *SEARCH_PATH = NULL; // mallocated string of search paths, populated by the -r command-line argument
128
static char **saved_ELF_sections = NULL; // mallocated array of const strings, populated by the -s command-line argument
129
static char **saved_ELF_sections = NULL; // mallocated array of const strings, populated by the -s command-line argument
129
static size_t saved_ELF_section_count = 0; // number of elements in the saved_ELF_sections array
130
static size_t saved_ELF_section_count = 0; // number of elements in the saved_ELF_sections array
-
 
131
static char *sym_suffix = ""; // .sym files extra suffix, settable with the -a command-line argument
130
 
132
 
131
// bootable IFS support
133
// bootable IFS support
132
static char *bootfile_pathname = NULL;           // HACK: pathname to bootcode binary blob file to put at the start of a bootable IFS
134
static char *bootfile_pathname = NULL;           // HACK: pathname to bootcode binary blob file to put at the start of a bootable IFS
133
static size_t bootfile_size = 0;                 // HACK: size of the bootcode binary blob file to put at the start of a bootable IFS
135
static size_t bootfile_size = 0;                 // HACK: size of the bootcode binary blob file to put at the start of a bootable IFS
134
static char *startupfile_pathname = NULL;        // HACK: pathname to precompiled startup file blob to put in the startup header of a bootable IFS
136
static char *startupfile_pathname = NULL;        // HACK: pathname to precompiled startup file blob to put in the startup header of a bootable IFS
Line 146... Line 148...
146
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)
148
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)
147
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
149
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
148
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
150
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
149
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
151
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
150
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
152
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
-
 
153
static void 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 in the the fsentries array
151
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
154
static void add_directory_contents_recursively (fsentry_t **fsentries, size_t *fsentry_count, const char *dir_pathname, const size_t start_pathname_len, parms_t *default_parms); // adds the contents of the directory pointed to by dir_pathname to the fsentries array, recursively
152
static int fsentry_compare_pathnames_cb (const void *a, const void *b); // qsort() comparison callback that sorts filesystem entries by pathnames
155
static int fsentry_compare_pathnames_cb (const void *a, const void *b); // qsort() comparison callback that sorts filesystem entries by pathnames
153
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
156
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
154
 
157
 
155
 
158
 
156
// imported function prototypes
159
// imported function prototypes
Line 688... Line 691...
688
   #undef ELFHDR // undefine the macro that used to always point to the ELF header at the beginning of the file
691
   #undef ELFHDR // undefine the macro that used to always point to the ELF header at the beginning of the file
689
   return (1); // success
692
   return (1); // success
690
}
693
}
691
 
694
 
692
 
695
 
693
static size_t add_fsentry (fsentry_t **fsentries, size_t *fsentry_count, parms_t *entry_parms, const char *stored_pathname, const char *buildhost_pathname)
696
static void add_fsentry (fsentry_t **fsentries, size_t *fsentry_count, parms_t *entry_parms, const char *stored_pathname, const char *buildhost_pathname)
694
{
697
{
695
   static thread_local char *candidate_pathname = NULL;
698
   static thread_local char *candidate_pathname = NULL;
696
   static int inode_count = 0; // will be preincremented each time this function is called
699
   static int inode_count = 0; // will be preincremented each time this function is called
697
 
700
 
698
   const char *stored_pathname_without_leading_slash;
701
   const char *stored_pathname_without_leading_slash;
Line 709... Line 712...
709
   char *resolved_pathname;
712
   char *resolved_pathname;
710
   void *reallocated_ptr;
713
   void *reallocated_ptr;
711
   void *old_data;
714
   void *old_data;
712
   struct stat stat_buf;
715
   struct stat stat_buf;
713
   fsentry_t *fsentry;
716
   fsentry_t *fsentry;
-
 
717
   int retval;
714
 
718
 
715
   // initial allocation (per thread)
719
   // initial allocation (per thread)
716
   if (candidate_pathname == NULL)
720
   if (candidate_pathname == NULL)
717
   {
721
   {
718
      candidate_pathname = malloc (MAXPATHLEN);
722
      candidate_pathname = malloc (MAXPATHLEN);
Line 933... Line 937...
933
 
937
 
934
         resolved_pathname = resolve_pathname (procnto_name, entry_parms->search); // locate the procnto kernel location
938
         resolved_pathname = resolve_pathname (procnto_name, entry_parms->search); // locate the procnto kernel location
935
         ASSERT (resolved_pathname, "QNX kernel \"%s\" not found in search path", procnto_name);
939
         ASSERT (resolved_pathname, "QNX kernel \"%s\" not found in search path", procnto_name);
936
         strcpy (procnto_buildhost_pathname, resolved_pathname);
940
         strcpy (procnto_buildhost_pathname, resolved_pathname);
937
 
941
 
938
         sprintf (procnto_sym_filename, "%s.sym", procnto_name);
942
         sprintf_s (procnto_sym_filename, sizeof (procnto_sym_filename), "%s.sym%s", procnto_name, sym_suffix);
939
 
943
 
940
         const char *linker_argv[] = // construct the linker invokation argv
944
         const char *linker_argv[] = // construct the linker invokation argv
941
         {
945
         {
942
            strrchr (linker_pathname, '/') + 1, // "${TARGET_TRIPLE}-ld"
946
            strrchr (linker_pathname, '/') + 1, // "${TARGET_TRIPLE}-ld"
943
            linker_sysroot_arg, // "--sysroot=${QNX_TARGET}/${TARGET_CPU}/"
947
            linker_sysroot_arg, // "--sysroot=${QNX_TARGET}/${TARGET_CPU}/"
Line 962... Line 966...
962
            DIE_WITH_EXITCODE (1, "the host cross-linker failed to produce a readable stripped \"%s\" kernel: %s", procnto_sym_filename, strerror (errno));
966
            DIE_WITH_EXITCODE (1, "the host cross-linker failed to produce a readable stripped \"%s\" kernel: %s", procnto_sym_filename, strerror (errno));
963
         if (!entry_parms->should_keep_ld_output)
967
         if (!entry_parms->should_keep_ld_output)
964
            unlink (procnto_sym_filename); // remove the linker output file if we want to
968
            unlink (procnto_sym_filename); // remove the linker output file if we want to
965
 
969
 
966
         // now strip this prelinked ELF kernel file
970
         // now strip this prelinked ELF kernel file
967
         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")
971
         Buffer_StripELFFile (&entry_parms->data, (const char **) saved_ELF_sections, 1, stored_pathname); // strip the ELF file as per QNX docs (only keep ONE section, which is "QNX_info")
968
         entry_parms->extra_ino_flags |= IFS_INO_PROCESSED_ELF; // mark this inode as a preprocessed ELF file
972
         entry_parms->extra_ino_flags |= IFS_INO_PROCESSED_ELF; // mark this inode as a preprocessed ELF file
969
 
973
 
970
#else // !PROCNTO_WIP
974
#else // !PROCNTO_WIP
971
         /* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK */
975
         /* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK */
972
         /* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK */
976
         /* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK */
Line 1003... Line 1007...
1003
         if (resolved_pathname == NULL)
1007
         if (resolved_pathname == NULL)
1004
         {
1008
         {
1005
            if (entry_parms->should_allow_nonexistent_files)
1009
            if (entry_parms->should_allow_nonexistent_files)
1006
            {
1010
            {
1007
               LOG_WARNING ("filesystem entry \"%s\" specified in \"%s\" line %d not found on build host: ignoring", buildhost_pathname, buildfile_pathname, lineno);
1011
               LOG_WARNING ("filesystem entry \"%s\" specified in \"%s\" line %d not found on build host: ignoring", buildhost_pathname, buildfile_pathname, lineno);
1008
               return (*fsentry_count); // if we're allowed to continue when a file to add doesn't exist, do so, else die with an error message
1012
               return; // if we're allowed to continue when a file to add doesn't exist, do so, else die with an error message
1009
            }
1013
            }
1010
            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));
1014
            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));
1011
         }
1015
         }
1012
         if (!Buffer_ReadFromFile (&entry_parms->data, resolved_pathname))
1016
         if (!Buffer_ReadFromFile (&entry_parms->data, resolved_pathname))
1013
            DIE_WITH_EXITCODE (1, "filesystem entry \"%s\" specified in \"%s\" line %d can't be read: %s", buildhost_pathname, buildfile_pathname, lineno, strerror (errno));
1017
            DIE_WITH_EXITCODE (1, "filesystem entry \"%s\" specified in \"%s\" line %d can't be read: %s", buildhost_pathname, buildfile_pathname, lineno, strerror (errno));
1014
         stat (resolved_pathname, &stat_buf); // can't fail, since we could read it
1018
         stat (resolved_pathname, &stat_buf); // can't fail, since we could read it
1015
         if (entry_parms->mtime == UINT32_MAX)
1019
         if (entry_parms->mtime == UINT32_MAX)
1016
            entry_parms->mtime = (uint32_t) stat_buf.st_mtime;
1020
            entry_parms->mtime = (uint32_t) stat_buf.st_mtime;
1017
         LOG_INFO ("file: ino 0x%x uid %d gid %d mode 0%o path \"%s\" buildhost_file \"%s\" (len %zd)", inode_count + 1, entry_parms->uid, entry_parms->gid, entry_parms->st_mode, stored_pathname, buildhost_pathname, entry_parms->data.size);
1021
         LOG_INFO ("file: ino 0x%x uid %d gid %d mode 0%o path \"%s\" buildhost_file \"%s\" (len %zd)", inode_count + 1, entry_parms->uid, entry_parms->gid, entry_parms->st_mode, stored_pathname, buildhost_pathname, entry_parms->data.size);
1018
      }
1022
      }
-
 
1023
      else
-
 
1024
         DIE_WITH_EXITCODE (1, "unexpected code path: can't store a file without neither explicit contents nor a host pathname. This is a bug in the program. Please contact the author.");
1019
 
1025
 
1020
      // is the file we're storing an ELF file ?
1026
      // is the file we're storing an ELF file ?
1021
      #define ELFHDR ((elf_header_t *) entry_parms->data.bytes) // this convenient definition will make sure the ELF header points at the right location, even after entry_parms.data->byte is reallocated
1027
      #define ELFHDR ((elf_header_t *) entry_parms->data.bytes) // this convenient definition will make sure the ELF header points at the right location, even after entry_parms.data->byte is reallocated
1022
      if ((entry_parms->data.size > 52) // file is big enough to contain an ELF header
1028
      if ((entry_parms->data.size > 52) // file is big enough to contain an ELF header
1023
          && (memcmp (ELF_GET_STRING (ELFHDR, ELFHDR, magic), ELF_MAGIC_STR, 4) == 0)) // file starts with the ELF magic
1029
          && (memcmp (ELF_GET_STRING (ELFHDR, ELFHDR, magic), ELF_MAGIC_STR, 4) == 0)) // file starts with the ELF magic
Line 1059... Line 1065...
1059
         } // end if the file we're storing is a dylib
1065
         } // end if the file we're storing is a dylib
1060
 
1066
 
1061
         // now strip this ELF file if necessary
1067
         // now strip this ELF file if necessary
1062
         if (!(entry_parms->extra_ino_flags & IFS_INO_PROCESSED_ELF))
1068
         if (!(entry_parms->extra_ino_flags & IFS_INO_PROCESSED_ELF))
1063
         {
1069
         {
1064
            Buffer_StripELFFile (&entry_parms->data, saved_ELF_sections, saved_ELF_section_count, stored_pathname); // strip the ELF file à la mkifs
1070
            Buffer_StripELFFile (&entry_parms->data, (const char **) saved_ELF_sections, saved_ELF_section_count, stored_pathname); // strip the ELF file à la mkifs
1065
            entry_parms->extra_ino_flags |= IFS_INO_PROCESSED_ELF; // mark this inode as a preprocessed ELF file
1071
            entry_parms->extra_ino_flags |= IFS_INO_PROCESSED_ELF; // mark this inode as a preprocessed ELF file
1066
         } // end if the file is not yet a processed ELF
1072
         } // end if the file is not yet a processed ELF
1067
      } // end if the file we're storing is an ELF file
1073
      } // end if the file we're storing is an ELF file
1068
      #undef ELFHDR // undefine the macro that used to always point to the ELF header at the beginning of the file
1074
      #undef ELFHDR // undefine the macro that used to always point to the ELF header at the beginning of the file
1069
   }
1075
   }
1070
   else if (S_ISLNK (entry_parms->st_mode)) // else are we storing a symbolic link ?
1076
   else if (S_ISLNK (entry_parms->st_mode)) // else are we storing a symbolic link ?
-
 
1077
   {
-
 
1078
      // do we already know the data for this data blob ?
-
 
1079
      if (entry_parms->data.bytes != NULL)
-
 
1080
      {
-
 
1081
         entry_parms->mtime = entry_parms->mtime_for_inline_files; // if so, set it a mtime equal to the mtime to use for inline files
1071
      LOG_INFO ("symlink: ino 0x%x uid %d gid %d mode 0%o path \"%s\" -> \"%s\"", inode_count + 1, entry_parms->uid, entry_parms->gid, entry_parms->st_mode, stored_pathname, entry_parms->data.bytes);
1082
         LOG_INFO ("symlink: ino 0x%x uid %d gid %d mode 0%o path \"%s\" -> \"%s\"", inode_count + 1, entry_parms->uid, entry_parms->gid, entry_parms->st_mode, stored_pathname, entry_parms->data.bytes);
-
 
1083
      }
-
 
1084
      else if (buildhost_pathname != NULL) // else was a source file pathname supplied ?
-
 
1085
      {
-
 
1086
         entry_parms->data.bytes = malloc (MAXPATHLEN); // allocate enough space for symlink data
-
 
1087
         ASSERT_WITH_ERRNO (entry_parms->data.bytes);
-
 
1088
         retval = readlink (buildhost_pathname, entry_parms->data.bytes, MAXPATHLEN); // read symlink contents
-
 
1089
         ASSERT_WITH_ERRNO (retval > 0);
-
 
1090
         entry_parms->data.size = retval; // save symlink target length
-
 
1091
      }
-
 
1092
      else
-
 
1093
         DIE_WITH_EXITCODE (1, "unexpected code path: can't store a symlink without neither explicit contents nor a host pathname. This is a bug in the program. Please contact the author.");
-
 
1094
   }
1072
   else // we must be storing a FIFO
1095
   else // we must be storing a FIFO
1073
   {
1096
   {
1074
      if (strchr (entry_parms->data.bytes, ':') == NULL)
1097
      if ((entry_parms->data.bytes == NULL) || (strchr (entry_parms->data.bytes, ':') == NULL))
1075
         DIE_WITH_EXITCODE (1, "device entry \"%s\" malformed (no 'dev:rdev' pair)", stored_pathname);
1098
         DIE_WITH_EXITCODE (1, "device entry \"%s\" malformed (no 'dev:rdev' pair)", stored_pathname);
1076
      LOG_INFO ("fifo: ino 0x%x uid %d gid %d mode 0%o path \"%s\" dev:rdev %s)", inode_count + 1, entry_parms->uid, entry_parms->gid, entry_parms->st_mode, stored_pathname, entry_parms->data.bytes);
1099
      LOG_INFO ("fifo: ino 0x%x uid %d gid %d mode 0%o path \"%s\" dev:rdev %s)", inode_count + 1, entry_parms->uid, entry_parms->gid, entry_parms->st_mode, stored_pathname, entry_parms->data.bytes);
1077
   }
1100
   }
1078
 
1101
 
1079
   // have a pointer to where the stored pathname actually starts, without the leading slash
1102
   // have a pointer to where the stored pathname actually starts, without the leading slash
Line 1082... Line 1105...
1082
   // see if this item already has an entry in the current list of filesystem entries
1105
   // see if this item already has an entry in the current list of filesystem entries
1083
   for (fsentry_index = 0; fsentry_index < *fsentry_count; fsentry_index++)
1106
   for (fsentry_index = 0; fsentry_index < *fsentry_count; fsentry_index++)
1084
   {
1107
   {
1085
      fsentry = &(*fsentries)[fsentry_index]; // quick access to fs entry slot
1108
      fsentry = &(*fsentries)[fsentry_index]; // quick access to fs entry slot
1086
      if (   (S_ISDIR  (fsentry->header.mode) && (strcmp (fsentry->u.dir.path,     stored_pathname_without_leading_slash) == 0))
1109
      if (   (S_ISDIR  (fsentry->header.mode) && (strcmp (fsentry->u.dir.path,     stored_pathname_without_leading_slash) == 0))
1087
            || (S_ISREG  (fsentry->header.mode) && (strcmp (fsentry->u.file.path,    stored_pathname_without_leading_slash) == 0))
1110
          || (S_ISREG  (fsentry->header.mode) && (strcmp (fsentry->u.file.path,    stored_pathname_without_leading_slash) == 0))
1088
            || (S_ISLNK  (fsentry->header.mode) && (strcmp (fsentry->u.symlink.path, stored_pathname_without_leading_slash) == 0))
1111
          || (S_ISLNK  (fsentry->header.mode) && (strcmp (fsentry->u.symlink.path, stored_pathname_without_leading_slash) == 0))
1089
            || (S_ISFIFO (fsentry->header.mode) && (strcmp (fsentry->u.symlink.path, stored_pathname_without_leading_slash) == 0)))
1112
          || (S_ISFIFO (fsentry->header.mode) && (strcmp (fsentry->u.symlink.path, stored_pathname_without_leading_slash) == 0)))
1090
         break; // stop searching as soon as we find a duplicate
1113
         break; // stop searching as soon as we find a duplicate
1091
   }
1114
   }
1092
 
1115
 
1093
   // is there already an entry for this item ?
1116
   // is there already an entry for this item ?
1094
   if (fsentry_index < *fsentry_count)
1117
   if (fsentry_index < *fsentry_count)
Line 1167... Line 1190...
1167
      entry_parms->data.size = strlen (entry_parms->data.bytes);
1190
      entry_parms->data.size = strlen (entry_parms->data.bytes);
1168
      add_fsentry (fsentries, fsentry_count, entry_parms, original_stored_pathname, NULL);
1191
      add_fsentry (fsentries, fsentry_count, entry_parms, original_stored_pathname, NULL);
1169
      entry_parms->data.bytes = old_data; // restore previous data pointer so that it can be freed normally
1192
      entry_parms->data.bytes = old_data; // restore previous data pointer so that it can be freed normally
1170
   }
1193
   }
1171
 
1194
 
-
 
1195
   return; // finished, return to our caller
-
 
1196
}
-
 
1197
 
-
 
1198
 
-
 
1199
static void add_directory_contents_recursively (fsentry_t **fsentries, size_t *fsentry_count, const char *dir_pathname, const size_t start_pathname_len, parms_t *default_parms)
-
 
1200
{
-
 
1201
   // adds the contents of the directory pointed to by dir_pathname to the fsentries array, recursively
-
 
1202
   // start_pathname_len is initialized to the length of dir_pathname by the top caller, and passed down unchanged,
-
 
1203
   // so that each sublevel of the recursion knows the depth of the relative path in which it is.
-
 
1204
 
-
 
1205
   thread_local static char item_pathname[MAXPATHLEN] = "";
-
 
1206
   thread_local static parms_t entry_parms = { 0 };
-
 
1207
   thread_local static struct stat stat_buf = { 0 };
-
 
1208
   thread_local static char major_minor[64];
-
 
1209
 
-
 
1210
   DIR *dirp;
1172
   return (*fsentry_count);
1211
   struct dirent *dp;
-
 
1212
 
-
 
1213
   // open the directory
-
 
1214
   dirp = opendir (dir_pathname);
-
 
1215
   if (dirp == NULL)
-
 
1216
      DIE_WITH_EXITCODE (1, "unable to open directory \"%s\" for recursive inclusion", dir_pathname);
-
 
1217
 
-
 
1218
   // enumerate its contents
-
 
1219
   while ((dp = readdir (dirp)) != NULL)
-
 
1220
   {
-
 
1221
      if ((strcmp (dp->d_name, ".") == 0) || (strcmp (dp->d_name, "..") == 0))
-
 
1222
         continue; // skip self and parent
-
 
1223
 
-
 
1224
      memcpy (&entry_parms, default_parms, sizeof (parms_t));
-
 
1225
      sprintf_s (item_pathname, sizeof (item_pathname), "%s/%s", dir_pathname, dp->d_name); // construct item's pathname
-
 
1226
      ASSERT_WITH_ERRNO (stat (item_pathname, &stat_buf) == 0); // peek info about this entry (or die trying)
-
 
1227
      if (S_ISDIR (stat_buf.st_mode))
-
 
1228
      {
-
 
1229
         entry_parms.st_mode |= entry_parms.dperms; // apply DIRECTORY default permissions
-
 
1230
         add_fsentry (fsentries, fsentry_count, &entry_parms, &item_pathname[start_pathname_len], NULL); // add a filesystem entry of type "directory"
-
 
1231
         add_directory_contents_recursively (fsentries, fsentry_count, item_pathname, start_pathname_len, default_parms); // dwell into this directory and add its children recursively
-
 
1232
      }
-
 
1233
      else if (S_ISLNK (stat_buf.st_mode))
-
 
1234
      {
-
 
1235
         entry_parms.st_mode |= 0777; // NOTE: mkifs sets symlink permissions to rwxrwxrwx !?
-
 
1236
         add_fsentry (fsentries, fsentry_count, &entry_parms, &item_pathname[start_pathname_len], item_pathname); // add a filesystem entry of type "link"
-
 
1237
      }
-
 
1238
      else if (S_ISREG (stat_buf.st_mode))
-
 
1239
      {
-
 
1240
         entry_parms.st_mode |= entry_parms.perms; // apply FILE default permissions
-
 
1241
         add_fsentry (fsentries, fsentry_count, &entry_parms, &item_pathname[start_pathname_len], item_pathname); // add a filesystem entry of type "regular file"
-
 
1242
      }
-
 
1243
      else if (S_ISFIFO (stat_buf.st_mode))
-
 
1244
      {
-
 
1245
         entry_parms.st_mode |= entry_parms.perms; // apply FILE default permissions
-
 
1246
         sprintf_s (major_minor, sizeof (major_minor), "%u:%u", (unsigned int) major (stat_buf.st_rdev), (unsigned int) minor (stat_buf.st_rdev));
-
 
1247
         entry_parms.data.bytes = major_minor;
-
 
1248
         add_fsentry (fsentries, fsentry_count, &entry_parms, &item_pathname[start_pathname_len], NULL); // add a filesystem entry of type "FIFO"
-
 
1249
      }
-
 
1250
      else
-
 
1251
         LOG_WARNING ("ignoring unsupported directory entry: \"%s\" (type 0%o)", item_pathname, stat_buf.st_mode & S_IFMT);
-
 
1252
   }
-
 
1253
 
-
 
1254
   closedir (dirp); // finished parsing this level, close the directory handle
-
 
1255
   return; // and return to our caller
1173
}
1256
}
1174
 
1257
 
1175
 
1258
 
1176
static int fsentry_compare_pathnames_cb (const void *a, const void *b)
1259
static int fsentry_compare_pathnames_cb (const void *a, const void *b)
1177
{
1260
{
Line 1212... Line 1295...
1212
   line_ptr = line_buffer;
1295
   line_ptr = line_buffer;
1213
   while ((*line_ptr != 0) && isspace (*line_ptr))
1296
   while ((*line_ptr != 0) && isspace (*line_ptr))
1214
      line_ptr++; // skip leading spaces
1297
      line_ptr++; // skip leading spaces
1215
 
1298
 
1216
   if ((*line_ptr == 0) || (*line_ptr == '#'))
1299
   if ((*line_ptr == 0) || (*line_ptr == '#'))
1217
      return; // skip empty or comment lines
1300
      return; // don't process empty lines and comments
1218
 
1301
 
1219
   string_len = (int) strlen (line_buffer);
1302
   string_len = (int) strlen (line_buffer);
1220
   if ((string_len > 0) && (line_buffer[string_len - 1] == '\n'))
1303
   if ((string_len > 0) && (line_buffer[string_len - 1] == '\n'))
1221
      line_buffer[string_len - 1] = 0; // chop off newline for easier debug output
1304
      line_buffer[string_len - 1] = 0; // chop off newline for easier debug output
1222
 
1305
 
Line 1316... Line 1399...
1316
         else if (strcmp (token, "+script")     == 0) {
1399
         else if (strcmp (token, "+script")     == 0) {
1317
            entry_parms.is_compiled_bootscript = true;
1400
            entry_parms.is_compiled_bootscript = true;
1318
            ASSERT_WITH_ERRNO (Buffer_InitWithByteArray (&entry_parms.data, INITIAL_STARTUP_SCRIPT)); // FIXME: HACK until the script compiler is implemented
1401
            ASSERT_WITH_ERRNO (Buffer_InitWithByteArray (&entry_parms.data, INITIAL_STARTUP_SCRIPT)); // FIXME: HACK until the script compiler is implemented
1319
            should_discard_inline_contents = true; // remember we already have data (so as to discard the inline block's contents)
1402
            should_discard_inline_contents = true; // remember we already have data (so as to discard the inline block's contents)
1320
         }
1403
         }
1321
         else if (strcmp (token, "-script")     == 0) entry_parms.is_compiled_bootscript = false;
1404
         else if (strcmp (token, "-script")     == 0) entry_parms.is_compiled_bootscript         = false;
1322
         else if (strcmp (token, "+followlink") == 0) entry_parms.should_follow_symlinks = true;
1405
         else if (strcmp (token, "+followlink") == 0) entry_parms.should_follow_symlinks         = true;
1323
         else if (strcmp (token, "-followlink") == 0) entry_parms.should_follow_symlinks = false;
1406
         else if (strcmp (token, "-followlink") == 0) entry_parms.should_follow_symlinks         = false;
1324
         else if (strcmp (token, "+autolink")   == 0) entry_parms.should_autosymlink_dylib = true;
1407
         else if (strcmp (token, "+autolink")   == 0) entry_parms.should_autosymlink_dylib       = true;
1325
         else if (strcmp (token, "-autolink")   == 0) entry_parms.should_autosymlink_dylib = false;
1408
         else if (strcmp (token, "-autolink")   == 0) entry_parms.should_autosymlink_dylib       = false;
1326
         else if (strcmp (token, "+keeplinked") == 0) entry_parms.should_keep_ld_output = true;
1409
         else if (strcmp (token, "+keeplinked") == 0) entry_parms.should_keep_ld_output          = true;
1327
         else if (strcmp (token, "-keeplinked") == 0) entry_parms.should_keep_ld_output = false;
1410
         else if (strcmp (token, "-keeplinked") == 0) entry_parms.should_keep_ld_output          = false;
1328
         else if (strcmp (token, "+dupignore")  == 0) entry_parms.should_ignore_duplicates = true;
1411
         else if (strcmp (token, "+dupignore")  == 0) entry_parms.should_ignore_duplicates       = true;
1329
         else if (strcmp (token, "-dupignore")  == 0) entry_parms.should_ignore_duplicates = false;
1412
         else if (strcmp (token, "-dupignore")  == 0) entry_parms.should_ignore_duplicates       = false;
1330
         else if (strcmp (token, "+optional")   == 0) entry_parms.should_allow_nonexistent_files = true;
1413
         else if (strcmp (token, "+optional")   == 0) entry_parms.should_allow_nonexistent_files = true;
1331
         else if (strcmp (token, "-optional")   == 0) entry_parms.should_allow_nonexistent_files = false;
1414
         else if (strcmp (token, "-optional")   == 0) entry_parms.should_allow_nonexistent_files = false;
1332
         else LOG_WARNING ("unimplemented attribute in \"%s\" line %d: '%s'", buildfile_pathname, lineno, token);
1415
         else LOG_WARNING ("unimplemented attribute in \"%s\" line %d: '%s'", buildfile_pathname, lineno, token);
1333
         #undef REACH_TOKEN_VALUE
1416
         #undef REACH_TOKEN_VALUE
1334
 
1417
 
Line 1530... Line 1613...
1530
      buffer_t data;
1613
      buffer_t data;
1531
      ifs_offsets_t offsets;
1614
      ifs_offsets_t offsets;
1532
      size_t final_size; // final size: not known (because not set) until everything has been written
1615
      size_t final_size; // final size: not known (because not set) until everything has been written
1533
   } ifs_t;
1616
   } ifs_t;
1534
 
1617
 
1535
   static startup_header_t startup_header = { 0 }; // output IFS's startup header
1618
   startup_header_t startup_header = { 0 }; // output IFS's startup header
1536
   static startup_trailer_v2_t startup_trailer = { 0 }; // output IFS's startup trailer (version 2, with SHA-512 checksum and int32 checksum)
1619
   startup_trailer_v2_t startup_trailer = { 0 }; // output IFS's startup trailer (version 2, with SHA-512 checksum and int32 checksum)
1537
   static image_header_t image_header = { 0 }; // output IFS's imagefs header
1620
   image_header_t image_header = { 0 }; // output IFS's imagefs header
1538
   static image_trailer_v2_t image_trailer = { 0 }; // output IFS's imagefs trailer (version 2, with SHA-512 checksum and int32 checksum)
1621
   image_trailer_v2_t image_trailer = { 0 }; // output IFS's imagefs trailer (version 2, with SHA-512 checksum and int32 checksum)
1539
   static fsentry_t *fsentries = NULL; // output IFS's filesystem entries
1622
   fsentry_t *fsentries = NULL; // output IFS's filesystem entries
1540
   static size_t fsentry_count = 0; // number of entries in the IFS filesystem
1623
   size_t fsentry_count = 0; // number of entries in the IFS filesystem
1541
   static parms_t default_parms = { // default parameters for a filesystem entry
1624
   parms_t default_parms = { // default parameters for a filesystem entry
1542
      .dperms = 0755,
1625
      .dperms = 0755,
1543
      .perms = 0644,
1626
      .perms = 0644,
1544
      .uid = 0,
1627
      .uid = 0,
1545
      .gid = 0,
1628
      .gid = 0,
1546
      .st_mode = S_IFREG,
1629
      .st_mode = S_IFREG,
Line 1552... Line 1635...
1552
      .is_compiled_bootscript = false, // [+|-script]
1635
      .is_compiled_bootscript = false, // [+|-script]
1553
      .extra_ino_flags = 0,
1636
      .extra_ino_flags = 0,
1554
      .search = NULL,
1637
      .search = NULL,
1555
      .data = { NULL, 0 }
1638
      .data = { NULL, 0 }
1556
   };
1639
   };
1557
   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)
1640
   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)
1558
 
1641
 
1559
   char path_on_buildhost[MAXPATHLEN] = "";
1642
   char path_on_buildhost[MAXPATHLEN] = "";
1560
   char path_in_ifs[MAXPATHLEN] = "";
1643
   char path_in_ifs[MAXPATHLEN] = "";
1561
   char *ifs_pathname = NULL;
1644
   const char *ifs_pathname = NULL;
-
 
1645
   const char *rootdir_pathname = NULL;
-
 
1646
   const fsentry_t *fsentry;
1562
   void *reallocated_ptr;
1647
   void *reallocated_ptr;
1563
   size_t reallocated_size;
1648
   size_t reallocated_size;
1564
   size_t available_space;
1649
   size_t available_space;
1565
   size_t fsentry_index;
1650
   size_t fsentry_index;
1566
   size_t largest_index;
1651
   size_t largest_index;
Line 1569... Line 1654...
1569
   size_t curr_offset;
1654
   size_t curr_offset;
1570
   ifs_t ifs = { 0 };
1655
   ifs_t ifs = { 0 };
1571
   int32_t checksum;
1656
   int32_t checksum;
1572
   char *first_pathname = NULL;
1657
   char *first_pathname = NULL;
1573
   char *second_pathname = NULL;
1658
   char *second_pathname = NULL;
-
 
1659
   char *third_pathname = NULL;
1574
   char *sep;
1660
   char *sep;
1575
   int arg_index;
1661
   int arg_index;
1576
   bool is_quoted_context = false;
1662
   bool is_quoted_context = false;
1577
   bool is_escaped_char = false;
1663
   bool is_escaped_char = false;
1578
   bool should_discard_inline_contents = false;
1664
   bool should_discard_inline_contents = false;
Line 1615... Line 1701...
1615
            DIE_WITH_EXITCODE (1, "the --kernelfile arguments expects <pathname>@<fileoffset>");
1701
            DIE_WITH_EXITCODE (1, "the --kernelfile arguments expects <pathname>@<fileoffset>");
1616
         *sep = 0;
1702
         *sep = 0;
1617
         kernelfile_pathname = argv[arg_index];
1703
         kernelfile_pathname = argv[arg_index];
1618
         kernelfile_offset = (size_t) read_integer (sep + 1);
1704
         kernelfile_offset = (size_t) read_integer (sep + 1);
1619
      }
1705
      }
-
 
1706
      else if ((strcmp (argv[arg_index], "-a") == 0) && (arg_index + 1 < argc)) // -a suffix
-
 
1707
         sym_suffix = argv[++arg_index];
1620
      else if (strcmp (argv[arg_index], "-n") == 0)
1708
      else if (strcmp (argv[arg_index], "-n") == 0)
1621
         default_parms.mtime_for_inline_files = 0; // inline files should have a mtime set to zero
1709
         default_parms.mtime_for_inline_files = 0; // inline files should have a mtime set to zero
1622
      else if (strcmp (argv[arg_index], "-nn") == 0)
1710
      else if (strcmp (argv[arg_index], "-nn") == 0)
1623
      {
1711
      {
1624
         default_parms.mtime = 0; // *all* files should have a mtime set to zero
1712
         default_parms.mtime = 0; // *all* files should have a mtime set to zero
Line 1663... Line 1751...
1663
         want_help = true;
1751
         want_help = true;
1664
      else if (first_pathname == NULL)
1752
      else if (first_pathname == NULL)
1665
         first_pathname = argv[arg_index];
1753
         first_pathname = argv[arg_index];
1666
      else if (second_pathname == NULL)
1754
      else if (second_pathname == NULL)
1667
         second_pathname = argv[arg_index];
1755
         second_pathname = argv[arg_index];
-
 
1756
      else if (third_pathname == NULL)
-
 
1757
         third_pathname = argv[arg_index];
1668
      else
1758
      else
1669
         DIE_WITH_EXITCODE (1, "unrecognized option: '%s'", argv[arg_index]);
1759
         DIE_WITH_EXITCODE (1, "unrecognized option: '%s'", argv[arg_index]);
1670
   }
1760
   }
1671
 
1761
 
1672
   // do we not have enough information to run ?
1762
   // do we want to display help ? (TODO: everything that's commented out is pending implementation)
1673
   if (want_help || (first_pathname == NULL) || (!want_info && !want_dump && !want_hexdump && !want_strip && (second_pathname == NULL)))
1763
   if (want_help)
1674
   {
1764
   {
1675
      FILE *out = (want_help ? stdout : stderr); // select the right output channel
1765
      FILE *out = (want_help ? stdout : stderr); // select the right output channel
1676
      fprintf (out, "ifstool - QNX in-kernel filesystem creation utility by Pierre-Marie Baty <pm@pmbaty.com>\n");
1766
      fprintf (out, "ifstool - QNX in-kernel filesystem creation utility by Pierre-Marie Baty <pm@pmbaty.com>\n");
1677
      fprintf (out, "          version " VERSION_FMT_YYYYMMDD "\n", VERSION_ARG_YYYYMMDD);
1767
      fprintf (out, "          version " VERSION_FMT_YYYYMMDD "\n", VERSION_ARG_YYYYMMDD);
1678
      if (!want_help)
1768
      if (!want_help)
Line 1680... Line 1770...
1680
      fprintf (out, "usage:\n");
1770
      fprintf (out, "usage:\n");
1681
      fprintf (out, "    ifstool --info [--everything] <ifs file>\n");
1771
      fprintf (out, "    ifstool --info [--everything] <ifs file>\n");
1682
      fprintf (out, "    ifstool --dump [--outdir <path>] <ifs file>\n");
1772
      fprintf (out, "    ifstool --dump [--outdir <path>] <ifs file>\n");
1683
      fprintf (out, "    ifstool --strip [--outfile <pathname>] <ELF file>\n");
1773
      fprintf (out, "    ifstool --strip [--outfile <pathname>] <ELF file>\n");
1684
      fprintf (out, "    ifstool [-?|--help]\n");
1774
      fprintf (out, "    ifstool [-?|--help]\n");
-
 
1775
      // mkifs [-?] [-l inputline] [-n[n]] [-o directory] [-p patchfile] [-r rootdir] [-s section] [-v] [buildfile] [directory] [outputfile]
1685
      fprintf (out, "    ifstool [--bootfile <pathname>] [--startupfile <pathname>@<EP_from_imgbase>] [--kernelfile <pathname>@<fileoffs>] [-l inputline] [-n[n]] [-r rootdir] [-v[...]] <buildfile> <outfile>\n");
1776
      fprintf (out, "    ifstool [--bootfile <pathname>] [--startupfile <pathname>@<EP_from_imgbase>] [--kernelfile <pathname>@<fileoffs>] [-a suffix] [-l inputline] [-n[n]] [-r rootdir] [-s section] [-v[...]] <buildfile> [directory] [outfile]\n");
1686
      fprintf (out, "NOTE: the compiler mode requires predigested boot, startup and kernel files produced by mkifs.\n");
1777
      fprintf (out, "NOTE: the compiler mode requires predigested boot, startup and kernel files produced by mkifs.\n");
1687
      fprintf (out, "options:\n");
1778
      fprintf (out, "options:\n");
1688
      fprintf (out, "    -?       Display some help information.\n");
1779
      fprintf (out, "    -?       Display some help information.\n");
1689
//      fprintf (out, "    -a .ext  Append a suffix to symbol files generated via [+keeplinked].\n");
1780
      fprintf (out, "    -a .ext  Append a suffix to symbol files generated via [+keeplinked].\n");
1690
      fprintf (out, "    -l line  Process line before interpreting the buildfile. Input lines given\n");
1781
      fprintf (out, "    -l line  Process line before interpreting the buildfile. Input lines given\n");
1691
      fprintf (out, "             to mkifs should be quoted to prevent interpretation by the shell\n");
1782
      fprintf (out, "             to mkifs should be quoted to prevent interpretation by the shell\n");
1692
      fprintf (out, "             (especially as mkifs input lines often contain spaces). Multiple\n");
1783
      fprintf (out, "             (especially as mkifs input lines often contain spaces). Multiple\n");
1693
      fprintf (out, "             -l options are processed in the order specified. No default.\n");
1784
      fprintf (out, "             -l options are processed in the order specified. No default.\n");
1694
      fprintf (out, "    -n[n]    Force the modification times of all inline files to be 0. If you\n");
1785
      fprintf (out, "    -n[n]    Force the modification times of all inline files to be 0. If you\n");
Line 1752... Line 1843...
1752
      fprintf (out, "    -v[v..]  Operate verbosely. Specifying additional v options increases the\n");
1843
      fprintf (out, "    -v[v..]  Operate verbosely. Specifying additional v options increases the\n");
1753
      fprintf (out, "             verbosity.\n");
1844
      fprintf (out, "             verbosity.\n");
1754
      exit (want_help ? 0 : 1);
1845
      exit (want_help ? 0 : 1);
1755
   }
1846
   }
1756
 
1847
 
1757
   // do we want info about a particular IFS ? if so, dissecate it
1848
   // else do we want info about a particular IFS ? if so, dissecate it
1758
   if (want_info)
1849
   else if (want_info)
1759
      exit (dump_ifs_info (first_pathname, want_everything));
1850
      exit (dump_ifs_info (first_pathname, want_everything));
1760
 
1851
 
1761
   // else do we want to dump its contents ? if so, do so
1852
   // else do we want to dump its contents ? if so, do so
1762
   else if (want_dump)
1853
   else if (want_dump)
1763
      exit (dump_ifs_contents (first_pathname, (second_pathname != NULL ? second_pathname : ".")));
1854
      exit (dump_ifs_contents (first_pathname, (second_pathname != NULL ? second_pathname : ".")));
Line 1769... Line 1860...
1769
   // else do we want to strip an ELF file ? if so, do so
1860
   // else do we want to strip an ELF file ? if so, do so
1770
   else if (want_strip)
1861
   else if (want_strip)
1771
   {
1862
   {
1772
      buffer_t file;
1863
      buffer_t file;
1773
      ASSERT (Buffer_ReadFromFile (&file, first_pathname), "can't open \"%s\" for reading: %s", first_pathname, strerror (errno));
1864
      ASSERT (Buffer_ReadFromFile (&file, first_pathname), "can't open \"%s\" for reading: %s", first_pathname, strerror (errno));
1774
      ASSERT (Buffer_StripELFFile (&file, saved_ELF_sections, saved_ELF_section_count, first_pathname), "error stripping \"%s\": %s", first_pathname, strerror (errno));
1865
      ASSERT (Buffer_StripELFFile (&file, (const char **) saved_ELF_sections, saved_ELF_section_count, first_pathname), "error stripping \"%s\": %s", first_pathname, strerror (errno));
1775
      ASSERT_WITH_ERRNO (Buffer_WriteToFile (&file, (second_pathname != NULL ? second_pathname : "<stdout>")));
1866
      ASSERT_WITH_ERRNO (Buffer_WriteToFile (&file, (second_pathname != NULL ? second_pathname : "<stdout>")));
1776
      exit (0);
1867
      exit (0);
1777
   }
1868
   }
1778
 
1869
 
1779
   // we want to CREATE an IFS file
1870
   // we want to CREATE an IFS file
1780
   buildfile_pathname = first_pathname; // assign the pathnames properly
1871
   buildfile_pathname = first_pathname; // assign the pathnames properly
-
 
1872
   ifs_pathname = (third_pathname != NULL ? third_pathname : second_pathname); // this is some curious handling of cmdline args, but that's the way mkxfs does it
1781
   ifs_pathname = second_pathname;
1873
   rootdir_pathname = (third_pathname != NULL ? second_pathname : NULL);
1782
 
1874
 
1783
   // make sure we have ${QNX_TARGET} pointing somewhere
1875
   // make sure we have ${QNX_TARGET} pointing somewhere
1784
   QNX_TARGET = getenv ("QNX_TARGET");
1876
   QNX_TARGET = getenv ("QNX_TARGET");
1785
   if (QNX_TARGET == NULL)
1877
   if (QNX_TARGET == NULL)
1786
      DIE_WITH_EXITCODE (1, "the QNX_TARGET environment variable is not set");
1878
      DIE_WITH_EXITCODE (1, "the QNX_TARGET environment variable is not set");
1787
   else if (access (QNX_TARGET, 0) != 0)
1879
   else if (access (QNX_TARGET, 0) != 0)
1788
      DIE_WITH_EXITCODE (1, "the QNX_TARGET environment variable doesn't point to an existing directory");
1880
      DIE_WITH_EXITCODE (1, "the QNX_TARGET environment variable doesn't point to an existing directory");
1789
 
1881
 
1790
   // open build file
1882
   // open build file
-
 
1883
   if ((buildfile_pathname != NULL) && (strcmp (buildfile_pathname, "-") != 0))
-
 
1884
   {
1791
   fopen_s (&buildfile_fp, buildfile_pathname, "rb");
1885
      fopen_s (&buildfile_fp, buildfile_pathname, "rb"); // open it
1792
   if (buildfile_fp == NULL)
1886
      if (buildfile_fp == NULL)
1793
      DIE_WITH_EXITCODE (1, "unable to open build file \"%s\" for reading: %s", buildfile_pathname, strerror (errno));
1887
         DIE_WITH_EXITCODE (1, "unable to open build file \"%s\" for reading: %s", buildfile_pathname, strerror (errno));
-
 
1888
   }
-
 
1889
   else // no build file specified: use stdin
-
 
1890
   {
-
 
1891
      buildfile_pathname = "<stdin>";
-
 
1892
      buildfile_fp = stdin;
-
 
1893
   }
1794
 
1894
 
1795
   // stack up filesystem entries
1895
   // stack up filesystem entries
1796
   memcpy (&entry_parms, &default_parms, sizeof (default_parms));
1896
   memcpy (&entry_parms, &default_parms, sizeof (default_parms));
1797
   entry_parms.st_mode = S_IFDIR | default_parms.dperms;
1897
   entry_parms.st_mode = S_IFDIR | default_parms.dperms;
1798
   add_fsentry (&fsentries, &fsentry_count, &entry_parms, "", NULL); // add the root dir first
1898
   add_fsentry (&fsentries, &fsentry_count, &entry_parms, "", NULL); // add the root dir first
Line 1813... Line 1913...
1813
      parse_line (buildfile_fp, line_buffer, &fsentries, &fsentry_count, &default_parms);
1913
      parse_line (buildfile_fp, line_buffer, &fsentries, &fsentry_count, &default_parms);
1814
   }
1914
   }
1815
 
1915
 
1816
   fclose (buildfile_fp); // finished parsing the build file
1916
   fclose (buildfile_fp); // finished parsing the build file
1817
 
1917
 
1818
   // parse the IFS build file line per line
-
 
1819
   while (fgets (line_buffer, sizeof (line_buffer), buildfile_fp) != NULL)
1918
   // if a root dir was specified, open it as a directory and recursively add all of its contents to the filesystem
1820
   {
-
 
1821
      if (current_line != NULL)
1919
   if (rootdir_pathname != NULL)
1822
         free (current_line);
-
 
1823
      current_line = strdup (line_buffer);
-
 
1824
      ASSERT_WITH_ERRNO (current_line);
-
 
1825
      lineno++; // keep track of current line number
-
 
1826
 
-
 
1827
   }
-
 
1828
 
-
 
1829
   fclose (buildfile_fp); // finished parsing the build file
1920
      add_directory_contents_recursively (&fsentries, &fsentry_count, rootdir_pathname, strlen (rootdir_pathname), &default_parms);
1830
 
1921
 
1831
   //////////////////////////////////
1922
   //////////////////////////////////
1832
   // start constructing the IFS file
1923
   // start constructing the IFS file
1833
 
1924
 
1834
   Buffer_Initialize (&ifs.data);
1925
   Buffer_Initialize (&ifs.data);
Line 2016... Line 2107...
2016
   ASSERT_WITH_ERRNO (Buffer_PadWithZeroesTo (&ifs.data, image_totalsize));
2107
   ASSERT_WITH_ERRNO (Buffer_PadWithZeroesTo (&ifs.data, image_totalsize));
2017
   ifs.final_size = ifs.data.size; // and this is the final size of the IFS
2108
   ifs.final_size = ifs.data.size; // and this is the final size of the IFS
2018
 
2109
 
2019
   // see if we are past the image max size, in which case it's an error
2110
   // see if we are past the image max size, in which case it's an error
2020
   if (ifs.final_size > image_maxsize)
2111
   if (ifs.final_size > image_maxsize)
2021
      DIE_WITH_EXITCODE (1, "image file \"%s\" size %zd exceeds max size (%zd)", ifs_pathname, ifs.final_size, (size_t) image_maxsize);
2112
      DIE_WITH_EXITCODE (1, "image file size %zd exceeds max size (%zd)", ifs.final_size, (size_t) image_maxsize);
2022
 
2113
 
2023
   // do we have a startup file ? if so, this is a bootable image
2114
   // do we have a startup file ? if so, this is a bootable image
2024
   if (startupfile_pathname != NULL)
2115
   if (startupfile_pathname != NULL)
2025
   {
2116
   {
2026
      // patch the startup header with its final values
2117
      // patch the startup header with its final values
Line 2089... Line 2180...
2089
      checksum = update_checksum (&ifs.data.bytes[ifs.offsets.imageheader], ifs.offsets.imagetrailer - ifs.offsets.imageheader, is_foreign_endianness); // compute old checksum
2180
      checksum = update_checksum (&ifs.data.bytes[ifs.offsets.imageheader], ifs.offsets.imagetrailer - ifs.offsets.imageheader, is_foreign_endianness); // compute old checksum
2090
      memcpy (&ifs.data.bytes[ifs.offsets.imagetrailer], &checksum, 4); // and write it in place
2181
      memcpy (&ifs.data.bytes[ifs.offsets.imagetrailer], &checksum, 4); // and write it in place
2091
   }
2182
   }
2092
 
2183
 
2093
   // now rewrite IFS with the correct checksums
2184
   // now rewrite IFS with the correct checksums
2094
   ASSERT_WITH_ERRNO (Buffer_WriteToFile (&ifs.data, ifs_pathname));
2185
   ASSERT_WITH_ERRNO (Buffer_WriteToFile (&ifs.data, (ifs_pathname != NULL ? ifs_pathname : "<stdout>")));
2095
 
2186
 
2096
   // finished, cleanup
2187
   // finished, cleanup
2097
   for (fsentry_index = 0; fsentry_index < fsentry_count; fsentry_index++)
2188
   for (fsentry_index = 0; fsentry_index < fsentry_count; fsentry_index++)
2098
   {
2189
   {
-
 
2190
      fsentry = &fsentries[fsentry_index]; // quick access to filesystem entry
-
 
2191
      if (S_ISDIR (fsentry->header.mode))
-
 
2192
         free (fsentry->u.dir.path);
-
 
2193
      else if (S_ISLNK (fsentry->header.mode))
-
 
2194
      {
-
 
2195
         free (fsentry->u.symlink.path);
-
 
2196
         free (fsentry->u.symlink.contents);
-
 
2197
      }
-
 
2198
      else if (S_ISREG (fsentry->header.mode))
-
 
2199
      {
-
 
2200
         free (fsentry->u.file.path);
-
 
2201
         free (fsentry->u.file.UNSAVED_databuf);
-
 
2202
      }
-
 
2203
      else if (S_ISFIFO (fsentry->header.mode))
-
 
2204
         free (fsentry->u.device.path);
2099
   }
2205
   }
2100
 
2206
 
2101
   // and exit with a success code
2207
   // and exit with a success code
2102
   LOG_INFO ("Success");
2208
   LOG_INFO ("Success");
2103
   exit (0);
2209
   exit (0);