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);  |