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 |
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 |
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 |
|
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 |
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 |
|
1110 | || (S_ISREG (fsentry->header.mode) && (strcmp (fsentry->u.file.path, stored_pathname_without_leading_slash) == 0)) |
1088 |
|
1111 | || (S_ISLNK (fsentry->header.mode) && (strcmp (fsentry->u.symlink.path, stored_pathname_without_leading_slash) == 0)) |
1089 |
|
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 |
|
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; // |
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 |
|
1618 | startup_header_t startup_header = { 0 }; // output IFS's startup header |
1536 |
|
1619 | startup_trailer_v2_t startup_trailer = { 0 }; // output IFS's startup trailer (version 2, with SHA-512 checksum and int32 checksum) |
1537 |
|
1620 | image_header_t image_header = { 0 }; // output IFS's imagefs header |
1538 |
|
1621 | image_trailer_v2_t image_trailer = { 0 }; // output IFS's imagefs trailer (version 2, with SHA-512 checksum and int32 checksum) |
1539 |
|
1622 | fsentry_t *fsentries = NULL; // output IFS's filesystem entries |
1540 |
|
1623 | size_t fsentry_count = 0; // number of entries in the IFS filesystem |
1541 |
|
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 |
|
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 |
1762 | // do we want to display help ? (TODO: everything that's commented out is pending implementation) |
1673 | if (want_help |
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> |
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 |
|
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 |
|
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 |
|
1918 | // if a root dir was specified, open it as a directory and recursively add all of its contents to the filesystem |
1820 | { |
- | |
1821 |
|
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 |
|
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 |
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); |