Rev 7 | Rev 9 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 7 | Rev 8 | ||
---|---|---|---|
Line 30... | Line 30... | ||
30 | #define strdup(s) _strdup ((s)) |
30 | #define strdup(s) _strdup ((s)) |
31 | #define strcasecmp(s1,s2) _stricmp ((s1), (s2)) |
31 | #define strcasecmp(s1,s2) _stricmp ((s1), (s2)) |
32 | #define fseek(fp,off,m) _fseeki64 ((fp), (off), (m)) |
32 | #define fseek(fp,off,m) _fseeki64 ((fp), (off), (m)) |
33 | #define access(p,m) _access ((p), (m)) |
33 | #define access(p,m) _access ((p), (m)) |
34 | #define MAXPATHLEN 1024 |
34 | #define MAXPATHLEN 1024 |
- | 35 | #ifndef thread_local |
|
- | 36 | #define thread_local __declspec(thread) // the thread_local keyword wasn't defined before C++11 and C23 |
|
- | 37 | #endif // !thread_local |
|
35 | #else // !_MSC_VER |
38 | #else // !_MSC_VER |
36 | #include <sys/param.h> |
39 | #include <sys/param.h> |
37 | #include <unistd.h> |
40 | #include <unistd.h> |
- | 41 | #ifndef thread_local |
|
- | 42 | #define thread_local __thread // the thread_local keyword wasn't defined before C++11 and C23 |
|
- | 43 | #endif // !thread_local |
|
38 | #endif // _MSC_VER |
44 | #endif // _MSC_VER |
39 | 45 | ||
40 | 46 | ||
41 | // handy macros that generate a version number in the format "YYYYMMDD" corresponding to the build date. Usage: printf ("version " VERSION_FMT_YYYYMMDD "\n", VERSION_ARG_YYYYMMDD); |
47 | // handy macros that generate a version number in the format "YYYYMMDD" corresponding to the build date. Usage: printf ("version " VERSION_FMT_YYYYMMDD "\n", VERSION_ARG_YYYYMMDD); |
42 | #ifndef VERSION_ARG_YYYYMMDD |
48 | #ifndef VERSION_ARG_YYYYMMDD |
Line 85... | Line 91... | ||
85 | (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 30 ") ? "30" : \ |
91 | (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 30 ") ? "30" : \ |
86 | (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 31 ") ? "31" : "XX"))))))))))))))))))))))))))))))) // compiler will optimize this into a const string, e.g. "14" |
92 | (*((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 31 ") ? "31" : "XX"))))))))))))))))))))))))))))))) // compiler will optimize this into a const string, e.g. "14" |
87 | #define VERSION_FMT_YYYYMMDD "%04s%02s%02s" |
93 | #define VERSION_FMT_YYYYMMDD "%04s%02s%02s" |
88 | #define VERSION_ARG_YYYYMMDD BUILDDATE_YEAR, BUILDDATE_MONTH, BUILDDATE_DAY |
94 | #define VERSION_ARG_YYYYMMDD BUILDDATE_YEAR, BUILDDATE_MONTH, BUILDDATE_DAY |
89 | #endif // !VERSION_ARG_YYYYMMDD |
95 | #endif // !VERSION_ARG_YYYYMMDD |
- | 96 | ||
- | 97 | ||
- | 98 | // we don't mind about this macro's efficiency... |
|
- | 99 | #define __FILENAME__ (strrchr (__FILE__, '\\') ? strrchr (__FILE__, '\\') + 1 : (strrchr (__FILE__, '/') ? strrchr (__FILE__, '/') + 1 : __FILE__)) |
|
- | 100 | ||
- | 101 | ||
- | 102 | // exit less brutally than with abort() if something doesn't go the way we'd like to |
|
- | 103 | #define WELLMANNERED_ASSERT(is_is_true,...) do { if (!(is_is_true)) { fprintf (stderr, "ifstool: fatal error: assertion within %s() in %s line %d failed: ", __FUNCTION__, __FILENAME__, __LINE__); fprintf (stderr, __VA_ARGS__); fputc ('\n', stderr); exit (1); } } while (0) |
|
- | 104 | ||
- | 105 | ||
- | 106 | // checked read/write/seek operations |
|
- | 107 | #define fseek_or_die(fp,pos,mode) do { if (fseek ((fp), (pos), (mode)) != 0) { fprintf (stderr, "ifstool: fatal error: fseek() failure within %s() in %s line %d: errno %d (%s)\n", __FUNCTION__, __FILENAME__, __LINE__, errno, strerror (errno)); exit (1); } } while (0) |
|
- | 108 | #define fread_or_die(buf,sz,len,fp) do { if (fread ((buf), (sz), (len), (fp)) != (len)) { fprintf (stderr, "ifstool: fatal error: fread() failure within %s() in %s line %d: errno %d (%s)\n", __FUNCTION__, __FILENAME__, __LINE__, errno, strerror (errno)); exit (1); } } while (0) |
|
- | 109 | #define fwrite_or_die(buf,sz,len,fp) do { if ((fwrite ((buf), (sz), (len), (fp)) != (len)) || (fflush ((fp)) != 0)) { fprintf (stderr, "ifstool: fatal error: fwrite() failure within %s() in %s line %d: errno %d (%s)\n", __FUNCTION__, __FILENAME__, __LINE__, errno, strerror (errno)); exit (1); } } while (0) |
|
90 | 110 | ||
91 | 111 | ||
92 | #define ROUND_TO_UPPER_MULTIPLE(val,multiple) ((((val) + (size_t) (multiple) - 1) / (multiple)) * (multiple)) // note that val is being evaluated once, so it can be the result of a function call |
112 | #define ROUND_TO_UPPER_MULTIPLE(val,multiple) ((((val) + (size_t) (multiple) - 1) / (multiple)) * (multiple)) // note that val is being evaluated once, so it can be the result of a function call |
93 | #ifdef _WIN32 |
113 | #ifdef _WIN32 |
94 | #define IS_DIRSEP(c) (((c) == '/') || ((c) == '\\')) |
114 | #define IS_DIRSEP(c) (((c) == '/') || ((c) == '\\')) |
Line 804... | Line 824... | ||
804 | static uint8_t *SHA512 (void *data, size_t data_len, uint8_t *digest_or_NULL) |
824 | static uint8_t *SHA512 (void *data, size_t data_len, uint8_t *digest_or_NULL) |
805 | { |
825 | { |
806 | // computes the SHA-512 hash of a block of data in one pass and write it to digest, or to a static buffer if NULL |
826 | // computes the SHA-512 hash of a block of data in one pass and write it to digest, or to a static buffer if NULL |
807 | // returns the STRING REPRESENTATION of digest in a statically-allocated string |
827 | // returns the STRING REPRESENTATION of digest in a statically-allocated string |
808 | 828 | ||
809 | static uint8_t static_digest[SHA512_DIGEST_LENGTH] = ""; |
829 | static thread_local uint8_t static_digest[SHA512_DIGEST_LENGTH] = ""; |
810 | static char digest_as_string[2 * SHA512_DIGEST_LENGTH + 1] = ""; |
830 | static thread_local char digest_as_string[2 * SHA512_DIGEST_LENGTH + 1] = ""; |
811 | 831 | ||
812 | SHA512_CTX ctx; |
832 | SHA512_CTX ctx; |
813 | size_t byte_index; |
833 | size_t byte_index; |
814 | 834 | ||
815 | SHA512_Init (&ctx); |
835 | SHA512_Init (&ctx); |
Line 838... | Line 858... | ||
838 | for (i = 0; i < data_len; i++) |
858 | for (i = 0; i < data_len; i++) |
839 | { |
859 | { |
840 | accumulator[i % 4] = *current_char_ptr; |
860 | accumulator[i % 4] = *current_char_ptr; |
841 | if (i % 4 == 3) |
861 | if (i % 4 == 3) |
842 | if (is_foreign_endianness) |
862 | if (is_foreign_endianness) |
843 | image_cksum += (accumulator[3] << |
863 | image_cksum += (accumulator[3] << 0) + (accumulator[2] << 8) + (accumulator[1] << 16) + (accumulator[0] << 24); |
844 | else |
864 | else |
845 | image_cksum += (accumulator[0] << |
865 | image_cksum += (accumulator[0] << 0) + (accumulator[1] << 8) + (accumulator[2] << 16) + (accumulator[3] << 24); |
846 | current_char_ptr++; |
866 | current_char_ptr++; |
847 | } |
867 | } |
848 | 868 | ||
849 | return (is_foreign_endianness ? __builtin_bswap32 (-image_cksum) : -image_cksum); |
869 | return (is_foreign_endianness ? __builtin_bswap32 (-image_cksum) : -image_cksum); |
850 | } |
870 | } |
Line 904... | Line 924... | ||
904 | 924 | ||
905 | static char *binary (const uint8_t x, char char_for_zero, char char_for_one) |
925 | static char *binary (const uint8_t x, char char_for_zero, char char_for_one) |
906 | { |
926 | { |
907 | // returns the binary representation of x as a string |
927 | // returns the binary representation of x as a string |
908 | 928 | ||
909 | static char outstr[9] = "00000000"; |
929 | static thread_local char outstr[9] = "00000000"; |
910 | for (int i = 0; i < 8; i++) |
930 | for (int i = 0; i < 8; i++) |
911 | outstr[i] = (x & (0x80 >> i) ? char_for_one : char_for_zero); |
931 | outstr[i] = (x & (0x80 >> i) ? char_for_one : char_for_zero); |
912 | return (outstr); |
932 | return (outstr); |
913 | } |
933 | } |
914 | 934 | ||
915 | 935 | ||
916 | static char *describe_uint8 (const uint8_t x, const char *bitwise_stringdescs[8]) |
936 | static char *describe_uint8 (const uint8_t x, const char *bitwise_stringdescs[8]) |
917 | { |
937 | { |
918 | // returns the ORed description of byte 'x' according to the description strings for each bit |
938 | // returns the ORed description of byte 'x' according to the description strings for each bit |
919 | 939 | ||
920 | static char *default_bitstrings[8] = { "bit0", "bit1", "bit2", "bit3", "bit4", "bit5", "bit6", "bit7" }; |
940 | static thread_local char *default_bitstrings[8] = { "bit0", "bit1", "bit2", "bit3", "bit4", "bit5", "bit6", "bit7" }; |
921 | static char outstr[8 * 64] = ""; |
941 | static thread_local char outstr[8 * 64] = ""; |
922 | 942 | ||
923 | outstr[0] = 0; |
943 | outstr[0] = 0; |
924 | for (int i = 0; i < 8; i++) |
944 | for (int i = 0; i < 8; i++) |
925 | if (x & (1 << i)) |
945 | if (x & (1 << i)) |
926 | { |
946 | { |
Line 934... | Line 954... | ||
934 | 954 | ||
935 | static char *read_filecontents (const char *pathname, const char *search_path, uint8_t **databuf, size_t *datalen) |
955 | static char *read_filecontents (const char *pathname, const char *search_path, uint8_t **databuf, size_t *datalen) |
936 | { |
956 | { |
937 | // locates pathname among MKIFS_PATH, and places its contents in a buffer (caller frees). Returns resolved pathname (static buffer) or NULL. |
957 | // locates pathname among MKIFS_PATH, and places its contents in a buffer (caller frees). Returns resolved pathname (static buffer) or NULL. |
938 | 958 | ||
939 |
|
959 | static thread_local char final_pathname[MAXPATHLEN]; |
940 | 960 | ||
941 | const char *nextsep; |
961 | const char *nextsep; |
942 | const char *token; |
962 | const char *token; |
943 | FILE *fp; |
963 | FILE *fp; |
944 | 964 | ||
Line 946... | Line 966... | ||
946 | if (IS_DIRSEP (pathname[0]) || (isalpha (pathname[0]) && (pathname[1] == ':') && IS_DIRSEP (pathname[2]))) |
966 | if (IS_DIRSEP (pathname[0]) || (isalpha (pathname[0]) && (pathname[1] == ':') && IS_DIRSEP (pathname[2]))) |
947 | strcpy (final_pathname, pathname); // in this case, it MUST exist at its designated location (either absolute or relative to the current working directory) |
967 | strcpy (final_pathname, pathname); // in this case, it MUST exist at its designated location (either absolute or relative to the current working directory) |
948 | else // the path is relative, search it among the search paths we have |
968 | else // the path is relative, search it among the search paths we have |
949 | { |
969 | { |
950 | // construct a potential final path using each element of the search path |
970 | // construct a potential final path using each element of the search path |
951 | token = search_path; |
971 | token = (*search_path != 0 ? search_path : NULL); |
952 | nextsep = &token[strcspn (token, PATH_SEP_STR)]; |
972 | nextsep = (token != NULL ? &token[strcspn (token, PATH_SEP_STR)] : NULL); |
953 | while (token != NULL) |
973 | while (token != NULL) |
954 | { |
974 | { |
955 | sprintf (final_pathname, "%.*s/%s", (int) (nextsep - token), token, pathname); |
975 | sprintf (final_pathname, "%.*s/%s", (int) (nextsep - token), token, pathname); |
956 | if (access (final_pathname, 0) == 0) |
976 | if (access (final_pathname, 0) == 0) |
957 | break; // if a file can indeed be found at this location, stop searching |
977 | break; // if a file can indeed be found at this location, stop searching |
Line 1019... | Line 1039... | ||
1019 | fseek (blob_fp, 0, SEEK_SET); |
1039 | fseek (blob_fp, 0, SEEK_SET); |
1020 | fread (blob_buffer, 1, blob_size, blob_fp); |
1040 | fread (blob_buffer, 1, blob_size, blob_fp); |
1021 | fclose (blob_fp); |
1041 | fclose (blob_fp); |
1022 | 1042 | ||
1023 | ret = (int) fwrite (blob_buffer, 1, blob_size, fp); |
1043 | ret = (int) fwrite (blob_buffer, 1, blob_size, fp); |
- | 1044 | fflush (fp); // force flush to disk, because the C stream API is *buffered* |
|
1024 | free (blob_buffer); |
1045 | free (blob_buffer); |
1025 | return (ret); |
1046 | return (ret); |
1026 | } |
1047 | } |
1027 | 1048 | ||
1028 | 1049 | ||
Line 1036... | Line 1057... | ||
1036 | size_t datalen; |
1057 | size_t datalen; |
1037 | size_t count; |
1058 | size_t count; |
1038 | 1059 | ||
1039 | count = 0; |
1060 | count = 0; |
1040 | if (fp != NULL) |
1061 | if (fp != NULL) |
1041 |
|
1062 | fwrite_or_die (&fsentry->header, 1, sizeof (fsentry->header), fp); // write the entry header (PACKED STRUCT) |
1042 | count += sizeof (fsentry->header); |
1063 | count += sizeof (fsentry->header); |
1043 | if (S_ISREG (fsentry->header.mode)) |
1064 | if (S_ISREG (fsentry->header.mode)) |
1044 | { |
1065 | { |
1045 | if (fp != NULL) |
1066 | if (fp != NULL) |
1046 | { |
1067 | { |
1047 |
|
1068 | fwrite_or_die (&fsentry->u.file.offset, 1, sizeof (uint32_t), fp); // write offset |
1048 |
|
1069 | fwrite_or_die (&fsentry->u.file.size, 1, sizeof (uint32_t), fp); // write size |
1049 | } |
1070 | } |
1050 | count += 2 * sizeof (uint32_t); |
1071 | count += 2 * sizeof (uint32_t); |
1051 | datalen = strlen (fsentry->u.file.path) + 1; |
1072 | datalen = strlen (fsentry->u.file.path) + 1; |
1052 | if (fp != NULL) |
1073 | if (fp != NULL) |
1053 |
|
1074 | fwrite_or_die (fsentry->u.file.path, 1, (size_t) datalen, fp); // write null-terminated path (no leading slash) |
1054 | count += datalen; |
1075 | count += datalen; |
1055 | } |
1076 | } |
1056 | else if (S_ISDIR (fsentry->header.mode)) |
1077 | else if (S_ISDIR (fsentry->header.mode)) |
1057 | { |
1078 | { |
1058 | datalen = strlen (fsentry->u.dir.path) + 1; |
1079 | datalen = strlen (fsentry->u.dir.path) + 1; |
1059 | if (fp != NULL) |
1080 | if (fp != NULL) |
1060 |
|
1081 | fwrite_or_die (fsentry->u.dir.path, 1, (size_t) datalen, fp); // write null-terminated path (no leading slash) |
1061 | count += datalen; |
1082 | count += datalen; |
1062 | } |
1083 | } |
1063 | else if (S_ISLNK (fsentry->header.mode)) |
1084 | else if (S_ISLNK (fsentry->header.mode)) |
1064 | { |
1085 | { |
1065 | if (fp != NULL) |
1086 | if (fp != NULL) |
1066 | { |
1087 | { |
1067 |
|
1088 | fwrite_or_die (&fsentry->u.symlink.sym_offset, 1, sizeof (uint16_t), fp); // write offset |
1068 |
|
1089 | fwrite_or_die (&fsentry->u.symlink.sym_size, 1, sizeof (uint16_t), fp); // write size |
1069 | } |
1090 | } |
1070 | count += 2 * sizeof (uint16_t); |
1091 | count += 2 * sizeof (uint16_t); |
1071 | datalen = strlen (fsentry->u.symlink.path) + 1; |
1092 | datalen = strlen (fsentry->u.symlink.path) + 1; |
1072 | if (fp != NULL) |
1093 | if (fp != NULL) |
1073 |
|
1094 | fwrite_or_die (fsentry->u.symlink.path, 1, (size_t) datalen, fp); // write null-terminated path (no leading slash) |
1074 | count += datalen; |
1095 | count += datalen; |
1075 | datalen = strlen (fsentry->u.symlink.contents) + 1; |
1096 | datalen = strlen (fsentry->u.symlink.contents) + 1; |
1076 | if (fp != NULL) |
1097 | if (fp != NULL) |
1077 |
|
1098 | fwrite_or_die (fsentry->u.symlink.contents, 1, (size_t) datalen, fp); // write null-terminated symlink contents |
1078 | count += datalen; |
1099 | count += datalen; |
1079 | } |
1100 | } |
1080 | else |
1101 | else |
1081 | { |
1102 | { |
1082 | if (fp != NULL) |
1103 | if (fp != NULL) |
1083 | { |
1104 | { |
1084 |
|
1105 | fwrite_or_die (&fsentry->u.device.dev, 1, sizeof (uint32_t), fp); // write dev number |
1085 |
|
1106 | fwrite_or_die (&fsentry->u.device.rdev, 1, sizeof (uint32_t), fp); // write rdev number |
1086 | } |
1107 | } |
1087 | count += 2 * sizeof (uint32_t); |
1108 | count += 2 * sizeof (uint32_t); |
1088 | datalen = strlen (fsentry->u.device.path) + 1; |
1109 | datalen = strlen (fsentry->u.device.path) + 1; |
1089 | if (fp != NULL) |
1110 | if (fp != NULL) |
1090 |
|
1111 | fwrite_or_die (fsentry->u.device.path, 1, (size_t) datalen, fp); // write null-terminated path (no leading slash) |
1091 | count += datalen; |
1112 | count += datalen; |
1092 | } |
1113 | } |
1093 | 1114 | ||
1094 | if (count < fsentry->header.size) |
1115 | if (count < fsentry->header.size) |
1095 | { |
1116 | { |
1096 | if (fp != NULL) |
1117 | if (fp != NULL) |
1097 |
|
1118 | fwrite_or_die (zeropad_buffer, 1, fsentry->header.size - count, fp); // pad as necessary |
1098 | count += fsentry->header.size - count; |
1119 | count += fsentry->header.size - count; |
1099 | } |
1120 | } |
1100 | else if (count > fsentry->header.size) |
1121 | else if (count > fsentry->header.size) |
1101 | { |
1122 | { |
1102 | fprintf (stderr, "ERROR: attempt to write invalid dirent (claimed size %zd, written size %zd). Aborting.\n", (size_t) fsentry->header.size, count); |
1123 | fprintf (stderr, "ERROR: attempt to write invalid dirent (claimed size %zd, written size %zd). Aborting.\n", (size_t) fsentry->header.size, count); |
Line 1107... | Line 1128... | ||
1107 | } |
1128 | } |
1108 | 1129 | ||
1109 | 1130 | ||
1110 | static size_t add_fsentry (fsentry_t **fsentries, size_t *fsentry_count, parms_t *entry_parms, const char *stored_pathname, const char *buildhost_pathname) |
1131 | static size_t add_fsentry (fsentry_t **fsentries, size_t *fsentry_count, parms_t *entry_parms, const char *stored_pathname, const char *buildhost_pathname) |
1111 | { |
1132 | { |
1112 | static char candidate_pathname[1024]; |
1133 | static thread_local char candidate_pathname[1024]; |
1113 | static int inode_count = 0; // will be preincremented each time this function is called |
1134 | static int inode_count = 0; // will be preincremented each time this function is called |
1114 | 1135 | ||
1115 | const char *original_stored_pathname = NULL; |
1136 | const char *original_stored_pathname = NULL; |
1116 | const elf_dynamic_section_entry_t *dynamic_entry; // dynamic section entry |
1137 | const elf_dynamic_section_entry_t *dynamic_entry; // dynamic section entry |
1117 | const elf_section_header_t *shdr_shstr; // section headers strings (containing ELF sections names) |
1138 | const elf_section_header_t *shdr_shstr; // section headers strings (containing ELF sections names) |
Line 1145... | Line 1166... | ||
1145 | // HACK: for now just consider the kernel as a binary blob |
1166 | // HACK: for now just consider the kernel as a binary blob |
1146 | // FIXME: reimplement properly |
1167 | // FIXME: reimplement properly |
1147 | sprintf (candidate_pathname, "%s/procnto-smp-instr", entry_parms->prefix); // fix the entry name |
1168 | sprintf (candidate_pathname, "%s/procnto-smp-instr", entry_parms->prefix); // fix the entry name |
1148 | stored_pathname = candidate_pathname; |
1169 | stored_pathname = candidate_pathname; |
1149 | extra_ino_flags = IFS_INO_PROCESSED_ELF | IFS_INO_BOOTSTRAP_EXE; // procnto needs to have these flags stamped on the inode |
1170 | extra_ino_flags = IFS_INO_PROCESSED_ELF | IFS_INO_BOOTSTRAP_EXE; // procnto needs to have these flags stamped on the inode |
- | 1171 | entry_parms->st_mode = S_IFREG | 0700; // procnto requires 0700 permissions |
|
1150 | image_kernel_ino = extra_ino_flags | (inode_count + 1); |
1172 | image_kernel_ino = extra_ino_flags | (inode_count + 1); |
1151 | } |
1173 | } |
1152 | else if (entry_parms->is_compiled_bootscript) // else is it a startup script ? |
1174 | else if (entry_parms->is_compiled_bootscript) // else is it a startup script ? |
1153 | image_bootscript_ino = inode_count + 1; // save boot script inode number for image header |
1175 | image_bootscript_ino = inode_count + 1; // save boot script inode number for image header |
1154 | 1176 | ||
Line 1156... | Line 1178... | ||
1156 | if (entry_parms->data != NULL) |
1178 | if (entry_parms->data != NULL) |
1157 | { |
1179 | { |
1158 | entry_parms->mtime = entry_parms->mtime_for_inline_files; |
1180 | entry_parms->mtime = entry_parms->mtime_for_inline_files; |
1159 | fprintf (stderr, "file: ino 0x%x uid %d gid %d mode 0%o path \"%s\" blob (len %zd)\n", extra_ino_flags | (inode_count + 1), entry_parms->uid, entry_parms->gid, entry_parms->st_mode, stored_pathname, entry_parms->datalen); |
1181 | fprintf (stderr, "file: ino 0x%x uid %d gid %d mode 0%o path \"%s\" blob (len %zd)\n", extra_ino_flags | (inode_count + 1), entry_parms->uid, entry_parms->gid, entry_parms->st_mode, stored_pathname, entry_parms->datalen); |
1160 | } |
1182 | } |
1161 | /* |
- | |
1162 | else if (entry_parms->should_compile_contents_as_startup_script) // should we compile this contents as a startup script ? |
- | |
1163 | { |
- | |
1164 | // HACK: for now just use a precompiled script |
- | |
1165 | // FIXME: replace this with a true compilation with the rules defined above |
- | |
1166 | data_buffer = malloc (INITIAL_STARTUP_SCRIPT_LEN); |
- | |
1167 | if (data_buffer == NULL) |
- | |
1168 | { |
- | |
1169 | fprintf (stderr, "fatal error: out of memory\n"); |
- | |
1170 | exit (1); |
- | |
1171 | } |
- | |
1172 | memcpy (data_buffer, INITIAL_STARTUP_SCRIPT, INITIAL_STARTUP_SCRIPT_LEN); |
- | |
1173 | data_len = INITIAL_STARTUP_SCRIPT_LEN; |
- | |
1174 | image_bootscript_ino = inode_count + 1; // save boot script inode number for image header |
- | |
1175 | }*/ |
- | |
1176 | - | ||
1177 | else if (buildhost_pathname != NULL) // else |
1183 | else if (buildhost_pathname != NULL) // else was a source file pathname supplied ? |
1178 | { |
1184 | { |
1179 | resolved_pathname = read_filecontents (buildhost_pathname, (entry_parms->search[0] != 0 ? entry_parms->search : MKIFS_PATH), &entry_parms->data, &entry_parms->datalen); |
1185 | resolved_pathname = read_filecontents (buildhost_pathname, (entry_parms->search[0] != 0 ? entry_parms->search : MKIFS_PATH), &entry_parms->data, &entry_parms->datalen); // locate the file |
1180 | if (resolved_pathname == NULL) |
1186 | if (resolved_pathname == NULL) |
1181 | { |
1187 | { |
1182 | fprintf (stderr, "fatal error: filesystem entry \"%s\" specified in \"%s\" line %d not found on build host: %s\n", buildhost_pathname, buildfile_pathname, lineno, strerror (errno)); |
1188 | fprintf (stderr, "fatal error: filesystem entry \"%s\" specified in \"%s\" line %d not found on build host: %s\n", buildhost_pathname, buildfile_pathname, lineno, strerror (errno)); |
1183 | fprintf (stderr, " v\n"); |
- | |
1184 | fprintf (stderr, "%s", current_line); |
- | |
1185 | fprintf (stderr, " ^\n"); |
- | |
1186 | exit (1); |
1189 | exit (1); |
1187 | } |
1190 | } |
1188 | stat (resolved_pathname, &stat_buf); // can't fail |
1191 | stat (resolved_pathname, &stat_buf); // can't fail |
1189 | if (entry_parms->mtime == UINT32_MAX) |
1192 | if (entry_parms->mtime == UINT32_MAX) |
1190 | entry_parms->mtime = (uint32_t) stat_buf.st_mtime; |
1193 | entry_parms->mtime = (uint32_t) stat_buf.st_mtime; |
1191 | fprintf (stderr, "file: ino 0x%x uid %d gid %d mode 0%o path \"%s\" buildhost_file \"%s\" (len %zd)\n", inode_count + 1, entry_parms->uid, entry_parms->gid, entry_parms->st_mode, stored_pathname, buildhost_pathname, entry_parms->datalen); |
1194 | fprintf (stderr, "file: ino 0x%x uid %d gid %d mode 0%o path \"%s\" buildhost_file \"%s\" (len %zd)\n", inode_count + 1, entry_parms->uid, entry_parms->gid, entry_parms->st_mode, stored_pathname, buildhost_pathname, entry_parms->datalen); |
1192 | } |
1195 | } |
1193 | 1196 | ||
1194 | // is the file we're storing a dylib and should we check for its canonical name ? FIXME: support for big endian is wrong. We should swap only if endianness is foreign, and also swap all ELF struct members below. |
1197 | // is the file we're storing a dylib and should we check for its canonical name ? FIXME: support for big endian is wrong. We should swap only if endianness is foreign, and also swap all ELF struct members below. |
1195 | if ((entry_parms->datalen > 52) // file is big enough to contain an ELF header |
1198 | if ((entry_parms->datalen > 52) // file is big enough to contain an ELF header |
1196 | && ((elf = (elf_header_t *) entry_parms->data) != NULL) // cast (necessary true) |
1199 | && ((elf = (elf_header_t *) entry_parms->data) != NULL) // cast (necessary true) |
1197 | && (memcmp (ELF_HDR_MEMBER (elf, magic), ELF_MAGIC_STR, 4) == 0) // file starts with the ELF magic |
1200 | && (memcmp (ELF_HDR_MEMBER (elf, magic), ELF_MAGIC_STR, 4) == 0) // file starts with the ELF magic |
Line 1285... | Line 1288... | ||
1285 | { |
1288 | { |
1286 | fsentry->u.file.offset = WILL_BE_FILLED_LATER; // will be filled later in main() when the file's data blob will be written to the output file |
1289 | fsentry->u.file.offset = WILL_BE_FILLED_LATER; // will be filled later in main() when the file's data blob will be written to the output file |
1287 | fsentry->u.file.size = (uint32_t) entry_parms->datalen; |
1290 | fsentry->u.file.size = (uint32_t) entry_parms->datalen; |
1288 | fsentry->u.file.path = strdup (stored_pathname[0] == '/' ? &stored_pathname[1] : stored_pathname); |
1291 | fsentry->u.file.path = strdup (stored_pathname[0] == '/' ? &stored_pathname[1] : stored_pathname); |
1289 | fsentry->u.file.UNSAVED_databuf = malloc (entry_parms->datalen); |
1292 | fsentry->u.file.UNSAVED_databuf = malloc (entry_parms->datalen); |
1290 |
|
1293 | WELLMANNERED_ASSERT (fsentry->u.file.UNSAVED_databuf, "out of memory"); |
1291 | { |
- | |
1292 | fprintf (stderr, "fatal error: out of memory\n"); |
- | |
1293 | exit (1); |
- | |
1294 | } |
- | |
1295 | memcpy (fsentry->u.file.UNSAVED_databuf, entry_parms->data, entry_parms->datalen); |
1294 | memcpy (fsentry->u.file.UNSAVED_databuf, entry_parms->data, entry_parms->datalen); |
1296 | fsentry->header.size = (uint16_t) ROUND_TO_UPPER_MULTIPLE (sizeof (fsentry->header) + sizeof (uint32_t) + sizeof (uint32_t) + strlen (fsentry->u.file.path) + 1, image_align); // now we can set the size |
1295 | fsentry->header.size = (uint16_t) ROUND_TO_UPPER_MULTIPLE (sizeof (fsentry->header) + sizeof (uint32_t) + sizeof (uint32_t) + strlen (fsentry->u.file.path) + 1, image_align); // now we can set the size |
1297 | fsentry->UNSAVED_was_data_written = false; // there *IS* data to save |
1296 | fsentry->UNSAVED_was_data_written = false; // there *IS* data to save |
1298 | } |
1297 | } |
1299 | else if (S_ISLNK (entry_parms->st_mode)) |
1298 | else if (S_ISLNK (entry_parms->st_mode)) |
1300 | { |
1299 | { |
1301 | fsentry->u.symlink.sym_offset = (uint16_t) (strlen (stored_pathname[0] == '/' ? &stored_pathname[1] : stored_pathname) + 1); |
1300 | fsentry->u.symlink.sym_offset = (uint16_t) (strlen (stored_pathname[0] == '/' ? &stored_pathname[1] : stored_pathname) + 1); |
1302 | fsentry->u.symlink.sym_size = (uint16_t) entry_parms->datalen; |
1301 | fsentry->u.symlink.sym_size = (uint16_t) entry_parms->datalen; |
1303 | fsentry->u.symlink.path = strdup (stored_pathname[0] == '/' ? &stored_pathname[1] : stored_pathname); |
1302 | fsentry->u.symlink.path = strdup (stored_pathname[0] == '/' ? &stored_pathname[1] : stored_pathname); |
1304 | fsentry->u.symlink.contents = strdup (entry_parms->data); |
1303 | fsentry->u.symlink.contents = strdup (entry_parms->data); |
1305 |
|
1304 | WELLMANNERED_ASSERT (fsentry->u.symlink.contents, "out of memory"); |
1306 | { |
- | |
1307 | fprintf (stderr, "fatal error: out of memory\n"); |
- | |
1308 | exit (1); |
- | |
1309 | } |
- | |
1310 | fsentry->header.size = (uint16_t) ROUND_TO_UPPER_MULTIPLE (sizeof (fsentry->header) + sizeof (uint16_t) + sizeof (uint16_t) + (size_t) fsentry->u.symlink.sym_offset + fsentry->u.symlink.sym_size + 1, image_align); // now we can set the size |
1305 | fsentry->header.size = (uint16_t) ROUND_TO_UPPER_MULTIPLE (sizeof (fsentry->header) + sizeof (uint16_t) + sizeof (uint16_t) + (size_t) fsentry->u.symlink.sym_offset + fsentry->u.symlink.sym_size + 1, image_align); // now we can set the size |
1311 | fsentry->UNSAVED_was_data_written = true; // no data to save |
1306 | fsentry->UNSAVED_was_data_written = true; // no data to save |
1312 | } |
1307 | } |
1313 | else // necessarily a device node |
1308 | else // necessarily a device node |
1314 | { |
1309 | { |
Line 1375... | Line 1370... | ||
1375 | data_len = strlen (processor_base); |
1370 | data_len = strlen (processor_base); |
1376 | if ((data_len > 2) && ((processor_base[data_len - 2] == 'b') || (processor_base[data_len - 2] == 'l')) && (processor_base[data_len - 1] == 'e')) |
1371 | if ((data_len > 2) && ((processor_base[data_len - 2] == 'b') || (processor_base[data_len - 2] == 'l')) && (processor_base[data_len - 1] == 'e')) |
1377 | processor_base[data_len - 2] = 0; // if it ends with "le" or "be", strip that too |
1372 | processor_base[data_len - 2] = 0; // if it ends with "le" or "be", strip that too |
1378 | 1373 | ||
1379 | MKIFS_PATH = malloc (10 * MAXPATHLEN); // construct a default MKIFS_PATH now |
1374 | MKIFS_PATH = malloc (10 * MAXPATHLEN); // construct a default MKIFS_PATH now |
1380 | if (MKIFS_PATH == NULL) |
- | |
1381 | { |
- | |
1382 |
|
1375 | WELLMANNERED_ASSERT (MKIFS_PATH, "out of memory"); |
1383 | exit (1); |
- | |
1384 | } |
- | |
1385 | sprintf (MKIFS_PATH, "." PATH_SEP_STR "%s/%s/sbin" PATH_SEP_STR "%s/%s/usr/sbin" PATH_SEP_STR "%s/%s/boot/sys" PATH_SEP_STR "%s/%s/boot/sys" PATH_SEP_STR "%s/%s/bin" PATH_SEP_STR "%s/%s/usr/bin" PATH_SEP_STR "%s/%s/lib" PATH_SEP_STR "%s/%s/lib/dll" PATH_SEP_STR "%s/%s/usr/lib", // use a platform-specific character as path separator |
1376 | sprintf (MKIFS_PATH, "." PATH_SEP_STR "%s/%s/sbin" PATH_SEP_STR "%s/%s/usr/sbin" PATH_SEP_STR "%s/%s/boot/sys" PATH_SEP_STR "%s/%s/boot/sys" PATH_SEP_STR "%s/%s/bin" PATH_SEP_STR "%s/%s/usr/bin" PATH_SEP_STR "%s/%s/lib" PATH_SEP_STR "%s/%s/lib/dll" PATH_SEP_STR "%s/%s/usr/lib", // use a platform-specific character as path separator |
1386 | QNX_TARGET, processor, |
1377 | QNX_TARGET, processor, |
1387 | QNX_TARGET, processor, |
1378 | QNX_TARGET, processor, |
1388 | QNX_TARGET, processor, |
1379 | QNX_TARGET, processor, |
1389 | QNX_TARGET, processor_base, |
1380 | QNX_TARGET, processor_base, |
Line 1442... | Line 1433... | ||
1442 | void *reallocated_ptr; |
1433 | void *reallocated_ptr; |
1443 | struct tm utc_time; |
1434 | struct tm utc_time; |
1444 | struct stat stat_buf; |
1435 | struct stat stat_buf; |
1445 | size_t startuptrailer_offset; |
1436 | size_t startuptrailer_offset; |
1446 | size_t startupheader_offset; |
1437 | size_t startupheader_offset; |
1447 | size_t |
1438 | size_t imagetrailer_offset; |
1448 | size_t |
1439 | size_t imageheader_offset; |
1449 | size_t imgdir_offset; |
1440 | size_t imgdir_offset; |
1450 | size_t imgdir_size; |
1441 | size_t imgdir_size; |
1451 | size_t final_size; |
1442 | size_t final_size; |
1452 | size_t blob_size; |
1443 | size_t blob_size; |
1453 | size_t available_space; |
1444 | size_t available_space; |
1454 | size_t allocated_size; |
1445 | size_t allocated_size; |
1455 | size_t fsentry_index; |
1446 | size_t fsentry_index; |
1456 | size_t largest_index; |
1447 | size_t largest_index; |
1457 | size_t largest_size; |
1448 | size_t largest_size; |
1458 | size_t curr_offset; |
1449 | size_t curr_offset; |
- | 1450 | uint8_t *blob_data; |
|
- | 1451 | int32_t checksum; |
|
1459 | char *specifiedpathname_start; |
1452 | char *specifiedpathname_start; |
1460 | char *directiveblock_start; |
1453 | char *directiveblock_start; |
1461 | char *blob_data; |
- | |
1462 | char *write_ptr; |
1454 | char *write_ptr; |
1463 | char *line_ptr; |
1455 | char *line_ptr; |
1464 | char *token; |
1456 | char *token; |
1465 | char *value; |
1457 | char *value; |
1466 | char *sep; |
1458 | char *sep; |
1467 | //char *ctx; |
1459 | //char *ctx; |
1468 | int arg_index; |
1460 | int arg_index; |
1469 | bool is_quoted_context = false; |
1461 | bool is_quoted_context = false; |
1470 | bool is_escaped_char = false; |
1462 | bool is_escaped_char = false; |
- | 1463 | bool has_data_already = false; |
|
1471 | bool want_info = false; |
1464 | bool want_info = false; |
1472 | bool want_help = false; |
1465 | bool want_help = false; |
1473 | bool is_foreign_endianness; |
1466 | bool is_foreign_endianness; |
1474 | int string_len; |
1467 | int string_len; |
1475 | int read_char; |
1468 | int read_char; |
Line 1573... | Line 1566... | ||
1573 | while (fgets (line_buffer, sizeof (line_buffer), buildfile_fp) != NULL) |
1566 | while (fgets (line_buffer, sizeof (line_buffer), buildfile_fp) != NULL) |
1574 | { |
1567 | { |
1575 | if (current_line != NULL) |
1568 | if (current_line != NULL) |
1576 | free (current_line); |
1569 | free (current_line); |
1577 | current_line = strdup (line_buffer); |
1570 | current_line = strdup (line_buffer); |
1578 | if (current_line == NULL) |
- | |
1579 | { |
- | |
1580 |
|
1571 | WELLMANNERED_ASSERT (current_line, "out of memory"); |
1581 | exit (1); |
- | |
1582 | } |
- | |
1583 | lineno++; // keep track of current line number |
1572 | lineno++; // keep track of current line number |
1584 | //fprintf (stderr, "read buildfile line %d: {%s}\n", lineno, line_buffer); |
1573 | //fprintf (stderr, "read buildfile line %d: {%s}\n", lineno, line_buffer); |
1585 | 1574 | ||
1586 | line_ptr = line_buffer; |
1575 | line_ptr = line_buffer; |
1587 | while ((*line_ptr != 0) && isspace (*line_ptr)) |
1576 | while ((*line_ptr != 0) && isspace (*line_ptr)) |
Line 1596... | Line 1585... | ||
1596 | 1585 | ||
1597 | // reset entry values |
1586 | // reset entry values |
1598 | memcpy (&entry_parms, &default_parms, sizeof (default_parms)); |
1587 | memcpy (&entry_parms, &default_parms, sizeof (default_parms)); |
1599 | path_in_ifs[0] = 0; |
1588 | path_in_ifs[0] = 0; |
1600 | path_on_buildhost[0] = 0; |
1589 | path_on_buildhost[0] = 0; |
- | 1590 | has_data_already = false; |
|
1601 | 1591 | ||
1602 | //fprintf (stderr, "parsing buildfile line %d: [%s]\n", lineno, line_ptr); |
1592 | //fprintf (stderr, "parsing buildfile line %d: [%s]\n", lineno, line_ptr); |
1603 | 1593 | ||
1604 | // does this line start with an attribute block ? |
1594 | // does this line start with an attribute block ? |
1605 | if (*line_ptr == '[') |
1595 | if (*line_ptr == '[') |
Line 1663... | Line 1653... | ||
1663 | fprintf (stderr, "error: unable to stat the boot file \"%s\" specified in \"%s\" line %d: %s\n", bootfile_pathname, buildfile_pathname, lineno, strerror (errno)); |
1653 | fprintf (stderr, "error: unable to stat the boot file \"%s\" specified in \"%s\" line %d: %s\n", bootfile_pathname, buildfile_pathname, lineno, strerror (errno)); |
1664 | exit (1); |
1654 | exit (1); |
1665 | } |
1655 | } |
1666 | bootfile_size = stat_buf.st_size; // save preboot file size |
1656 | bootfile_size = stat_buf.st_size; // save preboot file size |
1667 | fprintf (stderr, "info: processor \"%s\" bootfile \"%s\"\n", image_processor, bootfile_pathname); |
1657 | fprintf (stderr, "info: processor \"%s\" bootfile \"%s\"\n", image_processor, bootfile_pathname); |
1668 | if ( |
1658 | if (read_filecontents (kernelfile_pathname, ".", &entry_parms.data, &entry_parms.datalen) == NULL) |
1669 | { |
1659 | { |
1670 | fprintf (stderr, "fatal error: unable to read precompiled kernel file \"%s\" specified in --kernelfile argument\n", kernelfile_pathname); |
1660 | fprintf (stderr, "fatal error: unable to read precompiled kernel file \"%s\" specified in --kernelfile argument\n", kernelfile_pathname); |
1671 | exit (1); |
1661 | exit (1); |
1672 | } |
1662 | } |
1673 |
|
1663 | has_data_already = true; // remember we already have data |
1674 | if (entry_parms.data == NULL) |
- | |
1675 | { |
- | |
1676 | fprintf (stderr, "fatal error: out of memory\n"); |
- | |
1677 | exit (1); |
- | |
1678 | } |
- | |
1679 | fp = fopen (kernelfile_pathname, "rb"); |
- | |
1680 | fread (entry_parms.data, 1, stat_buf.st_size, fp); |
- | |
1681 | fclose (fp); |
- | |
1682 | entry_parms.datalen = stat_buf.st_size; |
- | |
1683 | } |
1664 | } |
1684 | else if (strncmp (token, "mtime=", 6) == 0) { REACH_TOKEN_VALUE (); if (strcmp (value, "*") == 0) entry_parms.mtime = UINT32_MAX; else { |
1665 | else if (strncmp (token, "mtime=", 6) == 0) { REACH_TOKEN_VALUE (); if (strcmp (value, "*") == 0) entry_parms.mtime = UINT32_MAX; else { |
1685 | // value *must* be "YYYY-MM-DD-HH:MM:SS" by specification |
1666 | // value *must* be "YYYY-MM-DD-HH:MM:SS" by specification |
1686 | memset (&utc_time, 0, sizeof (utc_time)); |
1667 | memset (&utc_time, 0, sizeof (utc_time)); |
1687 | if (sscanf (value, "%u-%u-%u-%u:%u:%u", &utc_time.tm_year, &utc_time.tm_mon, &utc_time.tm_mday, &utc_time.tm_hour, &utc_time.tm_min, &utc_time.tm_sec) != 6) |
1668 | if (sscanf (value, "%u-%u-%u-%u:%u:%u", &utc_time.tm_year, &utc_time.tm_mon, &utc_time.tm_mday, &utc_time.tm_hour, &utc_time.tm_min, &utc_time.tm_sec) != 6) |
Line 1694... | Line 1675... | ||
1694 | } |
1675 | } |
1695 | } |
1676 | } |
1696 | else if (strcmp (token, "+script") == 0) { |
1677 | else if (strcmp (token, "+script") == 0) { |
1697 | entry_parms.is_compiled_bootscript = true; |
1678 | entry_parms.is_compiled_bootscript = true; |
1698 | entry_parms.data = malloc (sizeof (INITIAL_STARTUP_SCRIPT) - 1); |
1679 | entry_parms.data = malloc (sizeof (INITIAL_STARTUP_SCRIPT) - 1); |
1699 | if (entry_parms.data == NULL) |
- | |
1700 | { |
- | |
1701 |
|
1680 | WELLMANNERED_ASSERT (entry_parms.data, "out of memory"); |
1702 | exit (1); |
- | |
1703 | } |
- | |
1704 | memcpy (entry_parms.data, INITIAL_STARTUP_SCRIPT, sizeof (INITIAL_STARTUP_SCRIPT) - 1); // FIXME: HACK until the script compiler is implemented |
1681 | memcpy (entry_parms.data, INITIAL_STARTUP_SCRIPT, sizeof (INITIAL_STARTUP_SCRIPT) - 1); // FIXME: HACK until the script compiler is implemented |
1705 | entry_parms.datalen = sizeof (INITIAL_STARTUP_SCRIPT) - 1; |
1682 | entry_parms.datalen = sizeof (INITIAL_STARTUP_SCRIPT) - 1; |
- | 1683 | has_data_already = true; // remember we already have data |
|
1706 | } |
1684 | } |
1707 | else if (strcmp (token, "-script") == 0) entry_parms.is_compiled_bootscript = false; |
1685 | else if (strcmp (token, "-script") == 0) entry_parms.is_compiled_bootscript = false; |
1708 | else if (strcmp (token, "+followlink") == 0) entry_parms.should_follow_symlinks = true; |
1686 | else if (strcmp (token, "+followlink") == 0) entry_parms.should_follow_symlinks = true; |
1709 | else if (strcmp (token, "-followlink") == 0) entry_parms.should_follow_symlinks = false; |
1687 | else if (strcmp (token, "-followlink") == 0) entry_parms.should_follow_symlinks = false; |
1710 | else if (strcmp (token, "+autolink") == 0) entry_parms.should_autosymlink_dylib = true; |
1688 | else if (strcmp (token, "+autolink") == 0) entry_parms.should_autosymlink_dylib = true; |
Line 1807... | Line 1785... | ||
1807 | if (read_char == EOF) |
1785 | if (read_char == EOF) |
1808 | { |
1786 | { |
1809 | fprintf (stderr, "fatal error: syntax error in \"%s\" line %d: unterminated contents block (end of file reached)\n", buildfile_pathname, lineno); |
1787 | fprintf (stderr, "fatal error: syntax error in \"%s\" line %d: unterminated contents block (end of file reached)\n", buildfile_pathname, lineno); |
1810 | exit (1); // invalid contents block |
1788 | exit (1); // invalid contents block |
1811 | } |
1789 | } |
1812 | else if (read_char == '\\') |
1790 | else if ((read_char == '\\') && !is_escaped_char) |
1813 | is_escaped_char = true; // remember the next char is escaped |
1791 | is_escaped_char = true; // remember the next char is escaped |
1814 | else if ((read_char == '}') && !is_escaped_char) |
1792 | else if ((read_char == '}') && !is_escaped_char) |
1815 | break; // found an unescaped closing bracked, stop parsing |
1793 | break; // found an unescaped closing bracked, stop parsing |
1816 | else |
1794 | else |
1817 | { |
1795 | { |
1818 | is_escaped_char = false; // any other char, meaning the next one will not be escaped |
1796 | is_escaped_char = false; // any other char, meaning the next one will not be escaped |
1819 | if ( |
1797 | if (!has_data_already) // only store the contents if we do NOT know the data yet |
1820 | { |
1798 | { |
1821 | if (entry_parms.datalen == allocated_size) // reallocate in 4 kb blocks |
1799 | if (entry_parms.datalen == allocated_size) // reallocate in 4 kb blocks |
1822 | { |
1800 | { |
1823 | reallocated_ptr = realloc (entry_parms.data, allocated_size + 4096); |
1801 | reallocated_ptr = realloc (entry_parms.data, allocated_size + 4096); |
1824 | if (reallocated_ptr == NULL) |
- | |
1825 | { |
- | |
1826 |
|
1802 | WELLMANNERED_ASSERT (reallocated_ptr, "out of memory"); |
1827 | exit (1); |
- | |
1828 | } |
- | |
1829 | entry_parms.data = reallocated_ptr; |
1803 | entry_parms.data = reallocated_ptr; |
1830 | allocated_size += 4096; |
1804 | allocated_size += 4096; |
1831 | } |
1805 | } |
1832 | entry_parms.data[entry_parms.datalen++] = read_char; |
1806 | entry_parms.data[entry_parms.datalen++] = read_char; |
1833 | } |
1807 | } |
1834 | if (read_char == '\n') |
1808 | if (read_char == '\n') |
1835 | lineno++; |
1809 | lineno++; // update line counter as we parse the inline content |
1836 | } |
1810 | } |
1837 | } |
1811 | } // end for |
- | 1812 | has_data_already = true; // remember we have data now |
|
1838 | } |
1813 | } |
1839 | else // not a content definition between { brackets }, must be either a pathname on the build host, or the target of a symlink |
1814 | else // not a content definition between { brackets }, must be either a pathname on the build host, or the target of a symlink |
1840 | { |
1815 | { |
1841 | is_quoted_context = (*line_ptr == '"'); |
1816 | is_quoted_context = (*line_ptr == '"'); |
1842 | if (is_quoted_context) |
1817 | if (is_quoted_context) |
Line 1858... | Line 1833... | ||
1858 | if (is_quoted_context && (*line_ptr == '"')) |
1833 | if (is_quoted_context && (*line_ptr == '"')) |
1859 | line_ptr++; // skip a possible final quote |
1834 | line_ptr++; // skip a possible final quote |
1860 | 1835 | ||
1861 | if (S_ISLNK (entry_parms.st_mode)) // are we storing a symlink ? |
1836 | if (S_ISLNK (entry_parms.st_mode)) // are we storing a symlink ? |
1862 | { |
1837 | { |
1863 | entry_parms. |
1838 | entry_parms.data = strdup (specifiedpathname_start); // if so, store the symlink target as the dirent's blob data |
1864 | entry_parms.data |
1839 | WELLMANNERED_ASSERT (entry_parms.data, "out of memory"); |
1865 |
|
1840 | entry_parms.datalen = strlen (specifiedpathname_start); |
1866 | { |
- | |
1867 |
|
1841 | has_data_already = true; // remember we have data now |
1868 | exit (1); |
- | |
1869 | } |
- | |
1870 | } |
1842 | } |
1871 | else // it's a build host filesystem path |
1843 | else // it's a build host filesystem path |
1872 | strcpy (path_on_buildhost, line_ptr); // the path on the build host is given after the equal sign |
1844 | strcpy (path_on_buildhost, line_ptr); // the path on the build host is given after the equal sign |
1873 | } |
1845 | } |
1874 | } |
1846 | } |
Line 1937... | Line 1909... | ||
1937 | startup_header.ram_size = WILL_BE_FILLED_LATER; // [ S] Amount of RAM used by the startup program and executables contained in the file system, here 0x00cd6128 i.e. 13 459 752 dec. which is 13 Mb. i.e. IFS file size minus 0x9eee (40686) |
1909 | startup_header.ram_size = WILL_BE_FILLED_LATER; // [ S] Amount of RAM used by the startup program and executables contained in the file system, here 0x00cd6128 i.e. 13 459 752 dec. which is 13 Mb. i.e. IFS file size minus 0x9eee (40686) |
1938 | startup_header.startup_size = WILL_BE_FILLED_LATER; // [I ] Size of startup (never compressed), here 0x02f148 or 192 840 bytes |
1910 | startup_header.startup_size = WILL_BE_FILLED_LATER; // [I ] Size of startup (never compressed), here 0x02f148 or 192 840 bytes |
1939 | startup_header.stored_size = WILL_BE_FILLED_LATER; // [I ] Size of entire image, here 0x00cd6128 (same as ram_size) |
1911 | startup_header.stored_size = WILL_BE_FILLED_LATER; // [I ] Size of entire image, here 0x00cd6128 (same as ram_size) |
1940 | startup_header.imagefs_size = WILL_BE_FILLED_LATER; // [ S] Size of uncompressed imagefs, here 0x00ca6fe0 or 13 266 912 bytes |
1912 | startup_header.imagefs_size = WILL_BE_FILLED_LATER; // [ S] Size of uncompressed imagefs, here 0x00ca6fe0 or 13 266 912 bytes |
1941 | startup_header.preboot_size = (uint16_t) bootfile_size; // [I ] Size of loaded before header, here 0xf30 or 3888 bytes (size of "bios.boot" file)) |
1913 | startup_header.preboot_size = (uint16_t) bootfile_size; // [I ] Size of loaded before header, here 0xf30 or 3888 bytes (size of "bios.boot" file)) |
1942 |
|
1914 | fwrite_or_die (&startup_header, 1, sizeof (startup_header), fp); // write startup header |
1943 | PAD_OUTFILE_TO (ROUND_TO_UPPER_MULTIPLE (ftell (fp), image_align)); // pad as necessary |
1915 | PAD_OUTFILE_TO (ROUND_TO_UPPER_MULTIPLE (ftell (fp), image_align)); // pad as necessary |
1944 | 1916 | ||
1945 | // ###################################################################################################################################################################################################################################### |
1917 | // ###################################################################################################################################################################################################################################### |
1946 | // # FIXME: figure out how to re-create it: linker call involved |
1918 | // # FIXME: figure out how to re-create it: linker call involved |
1947 | // # $ x86_64-pc-nto-qnx8.0.0-ld --sysroot=${QNX_TARGET}/x86_64/ -T${QNX_TARGET}/x86_64/lib/nto.link --section-start .text=0x1401030 --no-relax ${QNX_TARGET}/x86_64/boot/sys/startup-x86 -o startup.bin.UNSTRIPPED |
1919 | // # $ x86_64-pc-nto-qnx8.0.0-ld --sysroot=${QNX_TARGET}/x86_64/ -T${QNX_TARGET}/x86_64/lib/nto.link --section-start .text=0x1401030 --no-relax ${QNX_TARGET}/x86_64/boot/sys/startup-x86 -o startup.bin.UNSTRIPPED |
1948 | // ###################################################################################################################################################################################################################################### |
1920 | // ###################################################################################################################################################################################################################################### |
1949 | fwrite_filecontents (startupfile_pathname, fp); // write startup code from blob file |
1921 | fwrite_filecontents (startupfile_pathname, fp); // write startup code from blob file |
1950 | PAD_OUTFILE_TO (ROUND_TO_UPPER_MULTIPLE (ftell (fp), image_align)); // pad as necessary |
1922 | PAD_OUTFILE_TO (ROUND_TO_UPPER_MULTIPLE (ftell (fp), image_align)); // pad as necessary |
1951 | 1923 | ||
1952 | startuptrailer_offset = ftell (fp); // save startup trailer offset |
1924 | startuptrailer_offset = ftell (fp); // save startup trailer offset |
1953 |
|
1925 | fwrite_or_die (&startup_trailer, 1, sizeof (startup_trailer), fp); // write startup trailer |
1954 | PAD_OUTFILE_TO (ROUND_TO_UPPER_MULTIPLE (ftell (fp), image_align)); // pad as necessary |
1926 | PAD_OUTFILE_TO (ROUND_TO_UPPER_MULTIPLE (ftell (fp), image_align)); // pad as necessary |
1955 | } |
1927 | } |
1956 | 1928 | ||
1957 |
|
1929 | imageheader_offset = ftell (fp); // save image header offset |
1958 | memset (&image_header, 0, sizeof (image_header)); // prepare image header |
1930 | memset (&image_header, 0, sizeof (image_header)); // prepare image header |
1959 | memcpy (&image_header.signature, "imagefs", 7); // image filesystem signature, i.e. "imagefs" |
1931 | memcpy (&image_header.signature, "imagefs", 7); // image filesystem signature, i.e. "imagefs" |
1960 | image_header.flags = IMAGE_FLAGS_TRAILER_V2 | IMAGE_FLAGS_SORTED | IMAGE_FLAGS_INO_BITS; // endian neutral flags, 0x1c (IMAGE_FLAGS_TRAILER_V2 |Â IMAGE_FLAGS_SORTED |Â IMAGE_FLAGS_INO_BITS) |
1932 | image_header.flags = IMAGE_FLAGS_TRAILER_V2 | IMAGE_FLAGS_SORTED | IMAGE_FLAGS_INO_BITS; // endian neutral flags, 0x1c (IMAGE_FLAGS_TRAILER_V2 |Â IMAGE_FLAGS_SORTED |Â IMAGE_FLAGS_INO_BITS) |
1961 | image_header.image_size = WILL_BE_FILLED_LATER; // size from header to end of trailer (here 0xca6fe0 or 13 266 912) |
1933 | image_header.image_size = WILL_BE_FILLED_LATER; // size from header to end of trailer (here 0xca6fe0 or 13 266 912) |
1962 | image_header.hdr_dir_size = WILL_BE_FILLED_LATER; // size from header to last dirent (here 0x12b8 or 4792) |
1934 | image_header.hdr_dir_size = WILL_BE_FILLED_LATER; // size from header to last dirent (here 0x12b8 or 4792) |
1963 | image_header.dir_offset = sizeof (image_header); // offset from header to first dirent (here 0x5c or 92) |
1935 | image_header.dir_offset = sizeof (image_header); // offset from header to first dirent (here 0x5c or 92) |
1964 | image_header.boot_ino[0] = image_kernel_ino; // inode of files for bootstrap p[ro?]g[ra?]ms (here 0xa0000002, 0, 0, 0) |
1936 | image_header.boot_ino[0] = image_kernel_ino; // inode of files for bootstrap p[ro?]g[ra?]ms (here 0xa0000002, 0, 0, 0) |
1965 | image_header.script_ino = image_bootscript_ino; // inode of file for script (here 3) |
1937 | image_header.script_ino = image_bootscript_ino; // inode of file for script (here 3) |
1966 | image_header.mountpoint[0] = '/'; // default mountpoint for image ("/" + "\0\0\0") |
1938 | image_header.mountpoint[0] = '/'; // default mountpoint for image ("/" + "\0\0\0") |
1967 |
|
1939 | fwrite_or_die (&image_header, 1, sizeof (image_header), fp); // write image header |
1968 | PAD_OUTFILE_TO (ROUND_TO_UPPER_MULTIPLE (ftell (fp), image_align)); // pad as necessary |
1940 | PAD_OUTFILE_TO (ROUND_TO_UPPER_MULTIPLE (ftell (fp), image_align)); // pad as necessary |
1969 | 1941 | ||
1970 | // write image directory (with the wrong file offsets) |
1942 | // write image directory (with the wrong file offsets) |
1971 | if (image_header.flags & IMAGE_FLAGS_SORTED) |
- | |
1972 | qsort (&fsentries[1], fsentry_count - 1, sizeof (fsentry_t), fsentry_compare_pathnames_cb); // sort the filesystem entries by pathname |
- | |
1973 | imgdir_offset = ftell (fp); |
1943 | imgdir_offset = ftell (fp); |
1974 | imgdir_size = 0; // measure image dir size on the fly |
1944 | imgdir_size = 0; // measure image dir size on the fly |
1975 | for (fsentry_index = 0; fsentry_index < fsentry_count; fsentry_index++) |
1945 | for (fsentry_index = 0; fsentry_index < fsentry_count; fsentry_index++) |
1976 | imgdir_size += fwrite_fsentry (&fsentries[fsentry_index], fp); // NOTE: padding is handled in this function |
1946 | imgdir_size += fwrite_fsentry (&fsentries[fsentry_index], fp); // NOTE: padding is handled in this function |
- | 1947 | ||
1977 |
|
1948 | fwrite_or_die ("\0\0\0\0", 1, 4, fp); // there seems to be 4 bytes of padding after the image directory |
- | 1949 | imgdir_size += 4; |
|
1978 | 1950 | ||
1979 | // is it a bootable image with a kernel file ? |
1951 | // is it a bootable image with a kernel file ? |
1980 | if ((startupfile_pathname != NULL) && (kernelfile_pathname != NULL)) |
1952 | if ((startupfile_pathname != NULL) && (kernelfile_pathname != NULL)) |
1981 | { |
1953 | { |
1982 | // start by writing the startup script data blob, if we have one |
1954 | // start by writing the startup script data blob, if we have one |
1983 | for (fsentry_index = 1; fsentry_index < fsentry_count; fsentry_index++) |
1955 | for (fsentry_index = 1; fsentry_index < fsentry_count; fsentry_index++) |
1984 | if (fsentries[fsentry_index].header.ino == image_bootscript_ino) |
1956 | if (fsentries[fsentry_index].header.ino == image_bootscript_ino) |
1985 | break; // locate |
1957 | break; // locate the startup script directory entry |
1986 | if (fsentry_index < fsentry_count) // found it ? |
1958 | if (fsentry_index < fsentry_count) // found it ? |
1987 | { |
1959 | { |
1988 | curr_offset = ftell (fp); |
1960 | curr_offset = ftell (fp); |
1989 | if (curr_offset + fsentries[fsentry_index].u.file.size >= kernelfile_offset) |
1961 | if (curr_offset + fsentries[fsentry_index].u.file.size >= kernelfile_offset) |
1990 | { |
1962 | { |
1991 | fprintf (stderr, "error: the compiled startup script is too big (%zd bytes, max is %zd) to fit at current offset %zd\n", (size_t) fsentries[fsentry_index].u.file.size, kernelfile_offset - curr_offset, curr_offset); |
1963 | fprintf (stderr, "error: the compiled startup script is too big (%zd bytes, max is %zd) to fit at current offset %zd\n", (size_t) fsentries[fsentry_index].u.file.size, kernelfile_offset - curr_offset, curr_offset); |
1992 | exit (1); |
1964 | exit (1); |
1993 | } |
1965 | } |
1994 | fsentries[fsentry_index].u.file.offset = (uint32_t) (curr_offset - |
1966 | fsentries[fsentry_index].u.file.offset = (uint32_t) (curr_offset - imageheader_offset); // save file data blob offset in file structure |
1995 |
|
1967 | fwrite_or_die (fsentries[fsentry_index].u.file.UNSAVED_databuf, 1, fsentries[fsentry_index].u.file.size, fp); // write file data blob |
1996 | // PAD_OUTFILE_TO (ROUND_TO_UPPER_MULTIPLE (ftell (fp), image_align)); // pad as necessary |
- | |
1997 | fsentries[fsentry_index].UNSAVED_was_data_written = true; // and remember this file's data was written |
1968 | fsentries[fsentry_index].UNSAVED_was_data_written = true; // and remember this file's data was written |
1998 | } |
1969 | } |
1999 | 1970 | ||
2000 | // now write the filesystem entries that may fit before the kernel |
1971 | // now write the filesystem entries that may fit before the kernel |
2001 | for (;;) |
1972 | for (;;) |
Line 2003... | Line 1974... | ||
2003 | curr_offset = ftell (fp); // see where we are |
1974 | curr_offset = ftell (fp); // see where we are |
2004 | available_space = kernelfile_offset - curr_offset; // measure the available space |
1975 | available_space = kernelfile_offset - curr_offset; // measure the available space |
2005 | 1976 | ||
2006 | // look for the biggest one that can fit |
1977 | // look for the biggest one that can fit |
2007 | largest_index = 0; |
1978 | largest_index = 0; |
2008 | largest_size = |
1979 | largest_size = 0; |
2009 | for (fsentry_index = 1; fsentry_index < fsentry_count; fsentry_index++) |
1980 | for (fsentry_index = 1; fsentry_index < fsentry_count; fsentry_index++) |
2010 | { |
1981 | { |
2011 | if (!S_ISREG (fsentries[fsentry_index].header.mode) || fsentries[fsentry_index].UNSAVED_was_data_written || (fsentries[fsentry_index].u.file.size > available_space)) |
1982 | if (!S_ISREG (fsentries[fsentry_index].header.mode) || fsentries[fsentry_index].UNSAVED_was_data_written || (fsentries[fsentry_index].u.file.size > available_space)) |
2012 | continue; // skip all entries that don't have a separate data block, those who were written already and those that wouldn't fit |
1983 | continue; // skip all entries that don't have a separate data block, those who were written already and those that wouldn't fit |
2013 | if (fsentries[fsentry_index].u.file.size > largest_size) |
1984 | if (fsentries[fsentry_index].u.file.size > largest_size) |
2014 | { |
1985 | { |
2015 | largest_size = fsentries[fsentry_index].u.file.size; |
1986 | largest_size = fsentries[fsentry_index].u.file.size; |
2016 | largest_index = fsentry_index; |
1987 | largest_index = fsentry_index; |
2017 | } |
1988 | } |
2018 | } |
1989 | } |
2019 | if (largest_size == |
1990 | if (largest_size == 0) |
2020 | break; // found none ? if so, stop searching |
1991 | break; // found none ? if so, stop searching |
2021 | 1992 | ||
2022 | fsentries[largest_index].u.file.offset = (uint32_t) (curr_offset - |
1993 | fsentries[largest_index].u.file.offset = (uint32_t) (curr_offset - imageheader_offset); // save file data blob offset in file structure |
2023 |
|
1994 | fwrite_or_die (fsentries[largest_index].u.file.UNSAVED_databuf, 1, fsentries[largest_index].u.file.size, fp); // write file data blob |
2024 | // PAD_OUTFILE_TO (ROUND_TO_UPPER_MULTIPLE (ftell (fp), image_align)); // pad as necessary |
- | |
2025 | fsentries[largest_index].UNSAVED_was_data_written = true; // and remember this file's data was written |
1995 | fsentries[largest_index].UNSAVED_was_data_written = true; // and remember this file's data was written |
2026 | } |
1996 | } |
2027 | PAD_OUTFILE_TO (kernelfile_offset); // reach the kernel offset |
1997 | PAD_OUTFILE_TO (kernelfile_offset); // reach the kernel offset |
2028 | 1998 | ||
- | 1999 | // now write the QNX kernel |
|
- | 2000 | for (fsentry_index = 1; fsentry_index < fsentry_count; fsentry_index++) |
|
- | 2001 | if (fsentries[fsentry_index].header.ino == image_kernel_ino) |
|
- | 2002 | break; // locate the kernel directory entry (can't fail) |
|
- | 2003 | curr_offset = ftell (fp); // see where we are |
|
- | 2004 | fsentries[fsentry_index].u.file.offset = (uint32_t) (curr_offset - imageheader_offset); // save file data blob offset in file structure |
|
2029 | // ###################################################################################################################################################################################################################################### |
2005 | // ###################################################################################################################################################################################################################################### |
2030 | // # FIXME: figure out how to re-create it: linker call involved |
2006 | // # FIXME: figure out how to re-create it: linker call involved |
2031 | // # $ x86_64-pc-nto-qnx8.0.0-ld --sysroot=${QNX_TARGET}/x86_64/ -T${QNX_TARGET}/x86_64/lib/nto.link --section-start .text=0xffff800000001000 --no-relax ${QNX_TARGET}/x86_64/boot/sys/procnto-smp-instr -o procnto-smp-instr.sym.UNSTRIPPED |
2007 | // # $ x86_64-pc-nto-qnx8.0.0-ld --sysroot=${QNX_TARGET}/x86_64/ -T${QNX_TARGET}/x86_64/lib/nto.link --section-start .text=0xffff800000001000 --no-relax ${QNX_TARGET}/x86_64/boot/sys/procnto-smp-instr -o procnto-smp-instr.sym.UNSTRIPPED |
2032 | // ###################################################################################################################################################################################################################################### |
2008 | // ###################################################################################################################################################################################################################################### |
2033 | fwrite_filecontents (kernelfile_pathname, fp); // write kernel from blob file |
2009 | fwrite_filecontents (kernelfile_pathname, fp); // write kernel from blob file |
2034 | PAD_OUTFILE_TO (ROUND_TO_UPPER_MULTIPLE (ftell (fp), image_align)); // pad as necessary |
2010 | PAD_OUTFILE_TO (ROUND_TO_UPPER_MULTIPLE (ftell (fp), image_align)); // pad as necessary |
- | 2011 | fsentries[fsentry_index].UNSAVED_was_data_written = true; // and remember this file's data was written |
|
2035 | } |
2012 | } |
2036 | 2013 | ||
2037 | // then write all the other files |
2014 | // then write all the other files by increasing inode number: ELF files first |
2038 | for (fsentry_index = 1; fsentry_index < fsentry_count; fsentry_index++) |
2015 | for (fsentry_index = 1; fsentry_index < fsentry_count; fsentry_index++) |
2039 | { |
2016 | { |
2040 | if (!S_ISREG (fsentries[fsentry_index].header.mode) || fsentries[fsentry_index].UNSAVED_was_data_written |
2017 | if (!S_ISREG (fsentries[fsentry_index].header.mode) || fsentries[fsentry_index].UNSAVED_was_data_written // filter out anything that's not a file, and anything that's been already written |
- | 2018 | || (fsentries[fsentry_index].u.file.size < 4) || (memcmp (fsentries[fsentry_index].u.file.UNSAVED_databuf, ELF_MAGIC_STR, 4) != 0)) // filter out anything that's not an ELF file |
|
2041 | continue; // skip all entries that don't have a separate data block and those who were written already |
2019 | continue; // skip all entries that don't have a separate data block and those who were written already |
2042 | curr_offset = ftell (fp); |
2020 | curr_offset = ftell (fp); |
2043 | fsentries[fsentry_index].u.file.offset = (uint32_t) (curr_offset - |
2021 | fsentries[fsentry_index].u.file.offset = (uint32_t) (curr_offset - imageheader_offset); // save file data blob offset in file structure |
2044 |
|
2022 | fwrite_or_die (fsentries[fsentry_index].u.file.UNSAVED_databuf, 1, fsentries[fsentry_index].u.file.size, fp); // write file data blob |
2045 | // PAD_OUTFILE_TO (ROUND_TO_UPPER_MULTIPLE (ftell (fp), image_align)); // pad as necessary |
- | |
2046 | fsentries[fsentry_index].UNSAVED_was_data_written = true; // and remember this file's data was written |
2023 | fsentries[fsentry_index].UNSAVED_was_data_written = true; // and remember this file's data was written |
2047 | } |
2024 | } |
- | 2025 | for (fsentry_index = 1; fsentry_index < fsentry_count; fsentry_index++) // other files (non-ELF, e.g. scripts and data files) last |
|
- | 2026 | { |
|
- | 2027 | if (!S_ISREG (fsentries[fsentry_index].header.mode) || fsentries[fsentry_index].UNSAVED_was_data_written) // filter out anything that's not a file, and anything that's been already written |
|
- | 2028 | continue; // skip all entries that don't have a separate data block and those who were written already |
|
- | 2029 | curr_offset = ftell (fp); |
|
- | 2030 | fsentries[fsentry_index].u.file.offset = (uint32_t) (curr_offset - imageheader_offset); // save file data blob offset in file structure |
|
- | 2031 | fwrite_or_die (fsentries[fsentry_index].u.file.UNSAVED_databuf, 1, fsentries[fsentry_index].u.file.size, fp); // write file data blob |
|
- | 2032 | fsentries[fsentry_index].UNSAVED_was_data_written = true; // and remember this file's data was written |
|
- | 2033 | } |
|
- | 2034 | PAD_OUTFILE_TO (ROUND_TO_UPPER_MULTIPLE (ftell (fp), image_align)); // pad as necessary |
|
2048 | 2035 | ||
2049 | // finally, write trailer (including empty checksum) |
2036 | // finally, write trailer (including empty checksum) |
2050 |
|
2037 | imagetrailer_offset = ftell (fp); // save image trailer offset |
2051 |
|
2038 | fwrite_or_die (&image_trailer, 1, sizeof (image_trailer), fp); // write image trailer |
2052 | PAD_OUTFILE_TO (ROUND_TO_UPPER_MULTIPLE (ftell (fp), image_align)); // pad as necessary |
2039 | PAD_OUTFILE_TO (ROUND_TO_UPPER_MULTIPLE (ftell (fp), image_align)); // pad as necessary |
2053 | 2040 | ||
2054 | // if we need to pad it to a specific length, do so |
2041 | // if we need to pad it to a specific length, do so |
2055 | PAD_OUTFILE_TO (image_totalsize); |
2042 | PAD_OUTFILE_TO (image_totalsize); |
2056 | final_size = ftell (fp); |
2043 | final_size = ftell (fp); |
Line 2064... | Line 2051... | ||
2064 | 2051 | ||
2065 | // do we have a startup file ? if so, this is a bootable image |
2052 | // do we have a startup file ? if so, this is a bootable image |
2066 | if (startupfile_pathname != NULL) |
2053 | if (startupfile_pathname != NULL) |
2067 | { |
2054 | { |
2068 | // rewrite startup header with final values |
2055 | // rewrite startup header with final values |
2069 |
|
2056 | fseek_or_die (fp, startupheader_offset, SEEK_SET); |
2070 | startup_header.startup_size = (uint32_t) ( |
2057 | startup_header.startup_size = (uint32_t) (imageheader_offset - startupheader_offset); // size of startup header up to image header |
2071 | startup_header.imagefs_size = (uint32_t) (final_size - |
2058 | startup_header.imagefs_size = (uint32_t) (final_size - imageheader_offset); // size of uncompressed imagefs |
2072 | startup_header.ram_size = (uint32_t) final_size; // FIXME: this is necessarily |
2059 | startup_header.ram_size = (uint32_t) final_size; // FIXME: this is necessarily less, but should we really bother calculating the right size ? |
2073 | startup_header.stored_size = |
2060 | startup_header.stored_size = (uint32_t) final_size; |
2074 |
|
2061 | fwrite_or_die (&startup_header, 1, sizeof (startup_header), fp); // write startup header |
- | 2062 | } |
|
2075 | 2063 | ||
- | 2064 | // rewrite image header with final values |
|
- | 2065 | fseek_or_die (fp, imageheader_offset, SEEK_SET); |
|
- | 2066 | image_header.image_size = (uint32_t) (final_size - imageheader_offset); // size of uncompressed imagefs |
|
- | 2067 | image_header.hdr_dir_size = sizeof (image_header) + (uint32_t) imgdir_size; // size from start of image header to last dirent |
|
- | 2068 | fwrite_or_die (&image_header, 1, sizeof (image_header), fp); // write image header |
|
- | 2069 | ||
- | 2070 | // rewrite image directory with final offset values |
|
- | 2071 | fseek_or_die (fp, imgdir_offset, SEEK_SET); |
|
- | 2072 | if (image_header.flags & IMAGE_FLAGS_SORTED) |
|
- | 2073 | qsort (&fsentries[1], fsentry_count - 1, sizeof (fsentry_t), fsentry_compare_pathnames_cb); // sort the filesystem entries by pathname |
|
- | 2074 | for (fsentry_index = 0; fsentry_index < fsentry_count; fsentry_index++) |
|
- | 2075 | fwrite_fsentry (&fsentries[fsentry_index], fp); |
|
- | 2076 | ||
- | 2077 | fclose (fp); // ensure everything is flushed |
|
- | 2078 | ||
- | 2079 | // ALL CHECKSUMS AT THE VERY END |
|
- | 2080 | ||
- | 2081 | blob_data = NULL; |
|
- | 2082 | read_filecontents (ifs_pathname, ".", &blob_data, &blob_size); |
|
- | 2083 | WELLMANNERED_ASSERT (blob_data, "failed to open IFS file for checksumming: %s", strerror (errno)); |
|
- | 2084 | ||
- | 2085 | // do we have a startup file ? if so, this is a bootable image |
|
- | 2086 | if (startupfile_pathname != NULL) |
|
- | 2087 | { |
|
2076 | // compute SHA-512 checksum and V1 checksum of startup block |
2088 | // compute SHA-512 checksum and V1 checksum of startup block |
2077 | blob_size = startuptrailer_offset - startupheader_offset; |
- | |
2078 | blob_data = malloc (blob_size + sizeof (startup_trailer)); |
- | |
2079 | if (blob_data == NULL) |
- | |
2080 | { |
- | |
2081 | fprintf (stderr, "fatal error: out of memory\n"); |
- | |
2082 | exit (1); |
- | |
2083 | } |
- | |
2084 | fseek (fp, startupheader_offset, SEEK_SET); |
- | |
2085 | fread (blob_data, 1, blob_size, fp); |
- | |
2086 | SHA512 (blob_data, blob_size, startup_trailer.sha512); // compute SHA512 checksum |
- | |
2087 | if ( ( (startup_header.flags1 & STARTUP_HDR_FLAGS1_BIGENDIAN) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) |
2089 | if ( ( (startup_header.flags1 & STARTUP_HDR_FLAGS1_BIGENDIAN) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) |
2088 | || (!(startup_header.flags1 & STARTUP_HDR_FLAGS1_BIGENDIAN) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))) |
2090 | || (!(startup_header.flags1 & STARTUP_HDR_FLAGS1_BIGENDIAN) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))) |
2089 | is_foreign_endianness = true; // if the header is big endian and we're on a little endian machine, or the other way around, it's a foreign endianness |
2091 | is_foreign_endianness = true; // if the header is big endian and we're on a little endian machine, or the other way around, it's a foreign endianness |
2090 | else |
2092 | else |
2091 | is_foreign_endianness = false; // else this header is for the same endianness as us |
2093 | is_foreign_endianness = false; // else this header is for the same endianness as us |
2092 | fseek (fp, startupheader_offset, SEEK_SET); |
- | |
2093 | fread (blob_data, 1, blob_size + SHA512_DIGEST_LENGTH, fp); |
- | |
2094 | startup_trailer.cksum = update_checksum (blob_data, blob_size + SHA512_DIGEST_LENGTH, is_foreign_endianness); // compute old checksum |
- | |
2095 | free (blob_data); |
- | |
2096 | 2094 | ||
2097 | // |
2095 | SHA512 (&blob_data[startupheader_offset], startuptrailer_offset - startupheader_offset, &blob_data[startuptrailer_offset]); // compute SHA512 checksum and write it in place in blob data |
2098 |
|
2096 | checksum = update_checksum (&blob_data[startupheader_offset], startuptrailer_offset + SHA512_DIGEST_LENGTH - startupheader_offset, is_foreign_endianness); // compute old checksum |
2099 |
|
2097 | memcpy (&blob_data[startuptrailer_offset + SHA512_DIGEST_LENGTH], &checksum, 4); // and write it in place |
2100 | } |
2098 | } |
2101 | - | ||
2102 | // rewrite image header with final values |
- | |
2103 | fseek (fp, imgheader_offset, SEEK_SET); |
- | |
2104 | image_header.image_size = (uint32_t) (final_size - imgheader_offset); // size of uncompressed imagefs |
- | |
2105 | image_header.hdr_dir_size = sizeof (image_header) + (uint32_t) imgdir_size; // size from start of image header to last dirent |
- | |
2106 | fwrite (&image_header, sizeof (image_header), 1, fp); // write image header |
- | |
2107 | - | ||
2108 | // rewrite image directory with final offset values |
- | |
2109 | fseek (fp, imgdir_offset, SEEK_SET); |
- | |
2110 | for (fsentry_index = 0; fsentry_index < fsentry_count; fsentry_index++) |
- | |
2111 | fwrite_fsentry (&fsentries[fsentry_index], fp); |
- | |
2112 | 2099 | ||
2113 | // compute SHA-512 checksum and V1 checksum of image block |
2100 | // compute SHA-512 checksum and V1 checksum of image block |
2114 | blob_size = imgtrailer_offset - imgheader_offset; |
- | |
2115 | blob_data = malloc (blob_size + sizeof (image_trailer)); |
- | |
2116 | if (blob_data == NULL) |
- | |
2117 | { |
- | |
2118 | fprintf (stderr, "fatal error: out of memory\n"); |
- | |
2119 | exit (1); |
- | |
2120 | } |
- | |
2121 | fseek (fp, imgheader_offset, SEEK_SET); |
- | |
2122 | fread (blob_data, 1, blob_size, fp); |
- | |
2123 | SHA512 (blob_data, blob_size, image_trailer.sha512); // compute SHA512 checksum |
- | |
2124 | if ( ( (image_header.flags & IMAGE_FLAGS_BIGENDIAN) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) |
2101 | if ( ( (image_header.flags & IMAGE_FLAGS_BIGENDIAN) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) |
2125 | || (!(image_header.flags & IMAGE_FLAGS_BIGENDIAN) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))) |
2102 | || (!(image_header.flags & IMAGE_FLAGS_BIGENDIAN) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))) |
2126 | is_foreign_endianness = true; // if the header is big endian and we're on a little endian machine, or the other way around, it's a foreign endianness |
2103 | is_foreign_endianness = true; // if the header is big endian and we're on a little endian machine, or the other way around, it's a foreign endianness |
2127 | else |
2104 | else |
2128 | is_foreign_endianness = false; // else this header is for the same endianness as us |
2105 | is_foreign_endianness = false; // else this header is for the same endianness as us |
2129 | fseek (fp, imgheader_offset, SEEK_SET); |
- | |
2130 | fread (blob_data, 1, blob_size + SHA512_DIGEST_LENGTH, fp); |
- | |
2131 | image_trailer.cksum = update_checksum (blob_data, blob_size, is_foreign_endianness); // compute old checksum |
- | |
2132 | free (blob_data); |
- | |
2133 | 2106 | ||
2134 | // |
2107 | SHA512 (&blob_data[imageheader_offset], imagetrailer_offset - imageheader_offset, &blob_data[imagetrailer_offset]); // compute SHA512 checksum and write it in place in blob data |
2135 |
|
2108 | checksum = update_checksum (&blob_data[imageheader_offset], imagetrailer_offset + SHA512_DIGEST_LENGTH - imageheader_offset, is_foreign_endianness); // compute old checksum |
2136 |
|
2109 | memcpy (&blob_data[imagetrailer_offset + SHA512_DIGEST_LENGTH], &checksum, 4); // and write it in place |
2137 | 2110 | ||
2138 | // |
2111 | // now rewrite IFS with the correct checksums |
- | 2112 | fp = fopen (ifs_pathname, "wb"); |
|
- | 2113 | WELLMANNERED_ASSERT (fp, "failed to reopen IFS file for checksumming: %s", strerror (errno)); |
|
- | 2114 | fwrite_or_die (blob_data, 1, blob_size, fp); |
|
2139 | fclose (fp); |
2115 | fclose (fp); |
- | 2116 | free (blob_data); |
|
- | 2117 | ||
- | 2118 | // finished, exit with a success code |
|
2140 | fprintf (stdout, "Success\n"); |
2119 | fprintf (stdout, "Success\n"); |
2141 | exit (0); |
2120 | exit (0); |
2142 | } |
2121 | } |
2143 | 2122 | ||
2144 | 2123 | ||
Line 2174... | Line 2153... | ||
2174 | "", // bit 6 |
2153 | "", // bit 6 |
2175 | "", // bit 7 |
2154 | "", // bit 7 |
2176 | }; |
2155 | }; |
2177 | 2156 | ||
2178 | startup_header_t *startup_header = NULL; |
2157 | startup_header_t *startup_header = NULL; |
- | 2158 | size_t startupheader_offset = 0; |
|
2179 | startup_trailer_v1_t *startup_trailer_v1 = NULL; |
2159 | startup_trailer_v1_t *startup_trailer_v1 = NULL; |
2180 | startup_trailer_v2_t *startup_trailer_v2 = NULL; |
2160 | startup_trailer_v2_t *startup_trailer_v2 = NULL; |
- | 2161 | size_t startuptrailer_offset = 0; |
|
2181 | image_header_t *image_header = NULL; |
2162 | image_header_t *image_header = NULL; |
2182 | size_t imageheader_offset = 0; |
2163 | size_t imageheader_offset = 0; |
2183 | image_trailer_v1_t *image_trailer_v1 = NULL; |
2164 | image_trailer_v1_t *image_trailer_v1 = NULL; |
2184 | image_trailer_v2_t *image_trailer_v2 = NULL; |
2165 | image_trailer_v2_t *image_trailer_v2 = NULL; |
2185 | size_t imagetrailer_offset = 0; |
2166 | size_t imagetrailer_offset = 0; |
Line 2200... | Line 2181... | ||
2200 | uint32_t recorded_checksum; |
2181 | uint32_t recorded_checksum; |
2201 | uint32_t computed_checksum; |
2182 | uint32_t computed_checksum; |
2202 | uint8_t *filedata; |
2183 | uint8_t *filedata; |
2203 | size_t filesize; |
2184 | size_t filesize; |
2204 | time_t mtime; |
2185 | time_t mtime; |
2205 | FILE *fp; |
- | |
2206 | 2186 | ||
2207 | // open and read IFS file |
2187 | // open and read IFS file |
2208 |
|
2188 | if (read_filecontents (ifs_pathname, ".", &filedata, &filesize) == NULL) |
2209 | if (fp == NULL) |
- | |
2210 | { |
2189 | { |
2211 | fprintf (stderr, "error: can't open \"%s\" for reading: %s\n", ifs_pathname, strerror (errno)); |
2190 | fprintf (stderr, "error: can't open \"%s\" for reading: %s\n", ifs_pathname, strerror (errno)); |
2212 | return (1); |
2191 | return (1); |
2213 | } |
2192 | } |
2214 | fseek (fp, 0, SEEK_END); |
- | |
2215 | filesize = ftell (fp); |
- | |
2216 | filedata = malloc (filesize); |
- | |
2217 | if (filedata == NULL) |
- | |
2218 | { |
- | |
2219 | fprintf (stderr, "fatal error: out of memory\n"); |
- | |
2220 | exit (1); |
- | |
2221 | } |
- | |
2222 | fseek (fp, 0, SEEK_SET); |
- | |
2223 | fread (filedata, 1, filesize, fp); |
- | |
2224 | fclose (fp); |
- | |
2225 | 2193 | ||
2226 | printf ("QNX In-kernel Filesystem analysis produced by ifstool version " VERSION_FMT_YYYYMMDD "\n", VERSION_ARG_YYYYMMDD); |
2194 | printf ("QNX In-kernel Filesystem analysis produced by ifstool version " VERSION_FMT_YYYYMMDD "\n", VERSION_ARG_YYYYMMDD); |
2227 | printf ("IFS file \"%s\" - size 0x%zx (%zd) bytes\n", ifs_pathname, filesize, filesize); |
2195 | printf ("IFS file \"%s\" - size 0x%zx (%zd) bytes\n", ifs_pathname, filesize, filesize); |
2228 | 2196 | ||
2229 | // parse file from start to end |
2197 | // parse file from start to end |
Line 2231... | Line 2199... | ||
2231 | for (;;) |
2199 | for (;;) |
2232 | { |
2200 | { |
2233 | // does a startup header start here ? |
2201 | // does a startup header start here ? |
2234 | if ((current_offset + sizeof (startup_header_t) < filesize) && (memcmp (&filedata[current_offset], "\xeb\x7e\xff\x00", 4) == 0)) |
2202 | if ((current_offset + sizeof (startup_header_t) < filesize) && (memcmp (&filedata[current_offset], "\xeb\x7e\xff\x00", 4) == 0)) |
2235 | { |
2203 | { |
- | 2204 | startupheader_offset = current_offset; |
|
2236 | startup_header = (startup_header_t *) &filedata[ |
2205 | startup_header = (startup_header_t *) &filedata[startupheader_offset]; |
2237 | 2206 | ||
2238 | // layout: |
2207 | // layout: |
2239 | // [STARTUP HEADER] |
2208 | // [STARTUP HEADER] |
2240 | // (startup file blob) |
2209 | // (startup file blob) |
2241 | // [STARTUP TRAILER v1 or v2] |
2210 | // [STARTUP TRAILER v1 or v2] |
Line 2278... | Line 2247... | ||
2278 | is_foreign_endianness = false; // else this header is for the same endianness as us |
2247 | is_foreign_endianness = false; // else this header is for the same endianness as us |
2279 | 2248 | ||
2280 | // locate the right startup trailer at the right offset |
2249 | // locate the right startup trailer at the right offset |
2281 | if (startup_header->flags1 & STARTUP_HDR_FLAGS1_TRAILER_V2) |
2250 | if (startup_header->flags1 & STARTUP_HDR_FLAGS1_TRAILER_V2) |
2282 | { |
2251 | { |
2283 |
|
2252 | startuptrailer_offset = current_offset + startup_header->startup_size - sizeof (startup_trailer_v2_t); |
- | 2253 | startup_trailer_v2 = (startup_trailer_v2_t *) &filedata[startuptrailer_offset]; |
|
2284 | startupfile_blobsize = startup_header->startup_size - sizeof (startup_header_t) - sizeof (startup_trailer_v2_t); |
2254 | startupfile_blobsize = startup_header->startup_size - sizeof (startup_header_t) - sizeof (startup_trailer_v2_t); |
2285 | } |
2255 | } |
2286 | else // old V1 trailer |
2256 | else // old V1 trailer |
2287 | { |
2257 | { |
2288 |
|
2258 | startuptrailer_offset = current_offset + startup_header->startup_size - sizeof (startup_trailer_v1_t); |
- | 2259 | startup_trailer_v1 = (startup_trailer_v1_t *) &filedata[startuptrailer_offset]; |
|
2289 | startupfile_blobsize = startup_header->startup_size - sizeof (startup_header_t) - sizeof (startup_trailer_v1_t); |
2260 | startupfile_blobsize = startup_header->startup_size - sizeof (startup_header_t) - sizeof (startup_trailer_v1_t); |
2290 | } |
2261 | } |
2291 | 2262 | ||
2292 | current_offset += sizeof (startup_header_t); // jump over the startup header and reach the startup blob |
2263 | current_offset += sizeof (startup_header_t); // jump over the startup header and reach the startup blob |
2293 | printf ("\n"); |
2264 | printf ("\n"); |
Line 2300... | Line 2271... | ||
2300 | printf ("Startup trailer at offset 0x%zx (%zd) - version %d:\n", current_offset, current_offset, (startup_header->flags1 & STARTUP_HDR_FLAGS1_TRAILER_V2 ? 2 : 1)); |
2271 | printf ("Startup trailer at offset 0x%zx (%zd) - version %d:\n", current_offset, current_offset, (startup_header->flags1 & STARTUP_HDR_FLAGS1_TRAILER_V2 ? 2 : 1)); |
2301 | if (startup_header->flags1 & STARTUP_HDR_FLAGS1_TRAILER_V2) |
2272 | if (startup_header->flags1 & STARTUP_HDR_FLAGS1_TRAILER_V2) |
2302 | { |
2273 | { |
2303 | for (byte_index = 0; byte_index < SHA512_DIGEST_LENGTH; byte_index++) |
2274 | for (byte_index = 0; byte_index < SHA512_DIGEST_LENGTH; byte_index++) |
2304 | sprintf (&recorded_sha512[2 * byte_index], "%02x", startup_trailer_v2->sha512[byte_index]); |
2275 | sprintf (&recorded_sha512[2 * byte_index], "%02x", startup_trailer_v2->sha512[byte_index]); |
2305 | strcpy (computed_sha512, SHA512 (startup_header, |
2276 | strcpy (computed_sha512, SHA512 (startup_header, startuptrailer_offset - startupheader_offset, NULL)); |
2306 | recorded_checksum = startup_trailer_v2->cksum; |
2277 | recorded_checksum = startup_trailer_v2->cksum; |
2307 | computed_checksum = update_checksum (startup_header, |
2278 | computed_checksum = update_checksum (startup_header, startuptrailer_offset + SHA512_DIGEST_LENGTH - startupheader_offset, is_foreign_endianness); |
2308 | printf (" sha512 = %s - %s\n", recorded_sha512, (strcasecmp (computed_sha512, recorded_sha512) == 0 ? "GOOD" : "BAD")); |
2279 | printf (" sha512([0x%zx-0x%zx[) = %s - %s\n", startupheader_offset, startuptrailer_offset, recorded_sha512, (strcasecmp (computed_sha512, recorded_sha512) == 0 ? "GOOD" : "BAD")); |
2309 | printf (" cksum = 0x%08x (%d) - %s\n", recorded_checksum, recorded_checksum, (computed_checksum == recorded_checksum ? "GOOD" : "BAD")); |
2280 | printf (" cksum([0x%zx-0x%zx[) = 0x%08x (%d) - %s\n", startupheader_offset, startuptrailer_offset + SHA512_DIGEST_LENGTH, recorded_checksum, recorded_checksum, (computed_checksum == recorded_checksum ? "GOOD" : "BAD")); |
2310 | if (strcasecmp (computed_sha512, recorded_sha512) != 0) |
2281 | if (strcasecmp (computed_sha512, recorded_sha512) != 0) |
2311 | printf ("Computed SHA-512: %s\n", computed_sha512); |
2282 | printf ("Computed SHA-512: %s\n", computed_sha512); |
2312 | if (computed_checksum != recorded_checksum) |
2283 | if (computed_checksum != recorded_checksum) |
2313 | printf ("Computed cksum: 0x%08x (%d)\n", computed_checksum, computed_checksum); |
2284 | printf ("Computed cksum: 0x%08x (%d)\n", computed_checksum, computed_checksum); |
2314 | } |
2285 | } |
2315 | else // old v1 trailer |
2286 | else // old v1 trailer |
2316 | { |
2287 | { |
2317 | recorded_checksum = startup_trailer_v1->cksum; |
2288 | recorded_checksum = startup_trailer_v1->cksum; |
2318 | computed_checksum = update_checksum (startup_header, sizeof (startup_header) + startupfile_blobsize, is_foreign_endianness); |
2289 | computed_checksum = update_checksum (startup_header, sizeof (startup_header) + startupfile_blobsize, is_foreign_endianness); |
2319 | printf (" cksum = 0x%08x (%d) - %s\n", recorded_checksum, recorded_checksum, (computed_checksum == recorded_checksum ? "GOOD" : "BAD")); |
2290 | printf (" cksum([0x%zx-0x%zx[) = 0x%08x (%d) - %s\n", startupheader_offset, startuptrailer_offset, recorded_checksum, recorded_checksum, (computed_checksum == recorded_checksum ? "GOOD" : "BAD")); |
2320 | if (computed_checksum != recorded_checksum) |
2291 | if (computed_checksum != recorded_checksum) |
2321 | printf ("Computed cksum: 0x%08x (%d)\n", computed_checksum, computed_checksum); |
2292 | printf ("Computed cksum: 0x%08x (%d)\n", computed_checksum, computed_checksum); |
2322 | } |
2293 | } |
2323 | 2294 | ||
2324 | current_offset += (startup_header->flags1 & STARTUP_HDR_FLAGS1_TRAILER_V2 ? sizeof (startup_trailer_v2_t) : sizeof (startup_trailer_v1_t)); // now reach the next segment |
2295 | current_offset += (startup_header->flags1 & STARTUP_HDR_FLAGS1_TRAILER_V2 ? sizeof (startup_trailer_v2_t) : sizeof (startup_trailer_v1_t)); // now reach the next segment |
Line 2396... | Line 2367... | ||
2396 | if (imageheader_offset + image_header->hdr_dir_size - current_offset < sizeof (current_fsentry->header)) |
2367 | if (imageheader_offset + image_header->hdr_dir_size - current_offset < sizeof (current_fsentry->header)) |
2397 | break; // end padding reached |
2368 | break; // end padding reached |
2398 | 2369 | ||
2399 | // stack up the filesystem entry pointers in an array while we read them |
2370 | // stack up the filesystem entry pointers in an array while we read them |
2400 | reallocated_ptr = realloc (fsentries, (fsentry_count + 1) * sizeof (fsentry_t *)); |
2371 | reallocated_ptr = realloc (fsentries, (fsentry_count + 1) * sizeof (fsentry_t *)); |
2401 | if (reallocated_ptr == NULL) |
- | |
2402 | { |
- | |
2403 |
|
2372 | WELLMANNERED_ASSERT (reallocated_ptr, "out of memory"); |
2404 | exit (1); |
- | |
2405 | } |
- | |
2406 | fsentries = reallocated_ptr; |
2373 | fsentries = reallocated_ptr; |
2407 | fsentries[fsentry_count] = current_fsentry; |
2374 | fsentries[fsentry_count] = current_fsentry; |
2408 | fsentry_count++; |
2375 | fsentry_count++; |
2409 | 2376 | ||
2410 | printf ("\n"); |
2377 | printf ("\n"); |
Line 2483... | Line 2450... | ||
2483 | printf (" corresponding inode 0x%08x (%d) -%s%s%s%s\n", current_fsentry->header.ino, current_fsentry->header.ino, (current_fsentry->header.ino & 0xE0000000 ? "" : " nothing special"), (current_fsentry->header.ino & IFS_INO_PROCESSED_ELF ? " PROCESSED_ELF" : ""), (current_fsentry->header.ino & IFS_INO_RUNONCE_ELF ? " RUNONCE_ELF" : ""), (current_fsentry->header.ino & IFS_INO_BOOTSTRAP_EXE ? " BOOTSTRAP_EXE" : "")); |
2450 | printf (" corresponding inode 0x%08x (%d) -%s%s%s%s\n", current_fsentry->header.ino, current_fsentry->header.ino, (current_fsentry->header.ino & 0xE0000000 ? "" : " nothing special"), (current_fsentry->header.ino & IFS_INO_PROCESSED_ELF ? " PROCESSED_ELF" : ""), (current_fsentry->header.ino & IFS_INO_RUNONCE_ELF ? " RUNONCE_ELF" : ""), (current_fsentry->header.ino & IFS_INO_BOOTSTRAP_EXE ? " BOOTSTRAP_EXE" : "")); |
2484 | printf (" corresponding path: \"%s\"\n", (char *) ¤t_fsentry->u.file.path); // convert from pointer to char array |
2451 | printf (" corresponding path: \"%s\"\n", (char *) ¤t_fsentry->u.file.path); // convert from pointer to char array |
2485 | printf (" size 0x%zx (%zd) bytes\n", (size_t) current_fsentry->u.file.size, (size_t) current_fsentry->u.file.size); |
2452 | printf (" size 0x%zx (%zd) bytes\n", (size_t) current_fsentry->u.file.size, (size_t) current_fsentry->u.file.size); |
2486 | if (current_offset + 4 < filesize) |
2453 | if (current_offset + 4 < filesize) |
2487 | { |
2454 | { |
2488 | if ((current_fsentry->u.file.size < 1024) && (current_offset + current_fsentry->u.file.size < filesize)) |
2455 | if ((current_fsentry->u.file.size < 16 * 1024) && (current_offset + current_fsentry->u.file.size < filesize)) |
2489 | hex_printf (&filedata[current_offset], current_fsentry->u.file.size, " data:\n"); |
2456 | hex_printf (&filedata[current_offset], current_fsentry->u.file.size, " data:\n"); |
2490 | else |
2457 | else |
2491 | printf (" first 4 bytes: %02x%02x%02x%02x \"%c%c%c%c\" (%s)\n", (uint8_t) filedata[current_offset + 0], (uint8_t) filedata[current_offset + 1], (uint8_t) filedata[current_offset + 2], (uint8_t) filedata[current_offset + 3], (isprint (filedata[current_offset + 0]) ? filedata[current_offset + 0] : '.'), (isprint (filedata[current_offset + 1]) ? filedata[current_offset + 1] : '.'), (isprint (filedata[current_offset + 2]) ? filedata[current_offset + 2] : '.'), (isprint (filedata[current_offset + 3]) ? filedata[current_offset + 3] : '.'), (memcmp (&filedata[current_offset], ELF_MAGIC_STR, 4) == 0 ? "ELF binary" : (memcmp (&filedata[current_offset], "#!", 2) == 0 ? "shell script" : "data file"))); |
2458 | printf (" first 4 bytes: %02x%02x%02x%02x \"%c%c%c%c\" (%s)\n", (uint8_t) filedata[current_offset + 0], (uint8_t) filedata[current_offset + 1], (uint8_t) filedata[current_offset + 2], (uint8_t) filedata[current_offset + 3], (isprint (filedata[current_offset + 0]) ? filedata[current_offset + 0] : '.'), (isprint (filedata[current_offset + 1]) ? filedata[current_offset + 1] : '.'), (isprint (filedata[current_offset + 2]) ? filedata[current_offset + 2] : '.'), (isprint (filedata[current_offset + 3]) ? filedata[current_offset + 3] : '.'), (memcmp (&filedata[current_offset], ELF_MAGIC_STR, 4) == 0 ? "ELF binary" : (memcmp (&filedata[current_offset], "#!", 2) == 0 ? "shell script" : "data file"))); |
2492 | } |
2459 | } |
2493 | if (current_offset + current_fsentry->u.file.size < filesize) |
2460 | if (current_offset + current_fsentry->u.file.size < filesize) |
Line 2511... | Line 2478... | ||
2511 | printf ("Image trailer at offset 0x%zx (%zd) - version %d:\n", current_offset, current_offset, (image_header->flags & IMAGE_FLAGS_TRAILER_V2 ? 2 : 1)); |
2478 | printf ("Image trailer at offset 0x%zx (%zd) - version %d:\n", current_offset, current_offset, (image_header->flags & IMAGE_FLAGS_TRAILER_V2 ? 2 : 1)); |
2512 | if (image_header->flags & IMAGE_FLAGS_TRAILER_V2) |
2479 | if (image_header->flags & IMAGE_FLAGS_TRAILER_V2) |
2513 | { |
2480 | { |
2514 | for (byte_index = 0; byte_index < SHA512_DIGEST_LENGTH; byte_index++) |
2481 | for (byte_index = 0; byte_index < SHA512_DIGEST_LENGTH; byte_index++) |
2515 | sprintf (&recorded_sha512[2 * byte_index], "%02x", image_trailer_v2->sha512[byte_index]); |
2482 | sprintf (&recorded_sha512[2 * byte_index], "%02x", image_trailer_v2->sha512[byte_index]); |
2516 | strcpy (computed_sha512, SHA512 (image_header, |
2483 | strcpy (computed_sha512, SHA512 (image_header, imagetrailer_offset - imageheader_offset, NULL)); |
2517 | recorded_checksum = image_trailer_v2->cksum; |
2484 | recorded_checksum = image_trailer_v2->cksum; |
2518 | computed_checksum = update_checksum (image_header, |
2485 | computed_checksum = update_checksum (image_header, imagetrailer_offset + SHA512_DIGEST_LENGTH - imageheader_offset, is_foreign_endianness); |
2519 | printf (" sha512 = %s - %s\n", recorded_sha512, (strcasecmp (computed_sha512, recorded_sha512) == 0 ? "GOOD" : "BAD")); |
2486 | printf (" sha512([0x%zx-0x%zx[) = %s - %s\n", imageheader_offset, imagetrailer_offset, recorded_sha512, (strcasecmp (computed_sha512, recorded_sha512) == 0 ? "GOOD" : "BAD")); |
2520 | printf (" cksum = 0x%08x (%d) - %s\n", recorded_checksum, recorded_checksum, (computed_checksum == recorded_checksum ? "GOOD" : "BAD")); |
2487 | printf (" cksum([0x%zx-0x%zx[) = 0x%08x (%d) - %s\n", imageheader_offset, imagetrailer_offset + SHA512_DIGEST_LENGTH, recorded_checksum, recorded_checksum, (computed_checksum == recorded_checksum ? "GOOD" : "BAD")); |
2521 | if (strcasecmp (computed_sha512, recorded_sha512) != 0) |
2488 | if (strcasecmp (computed_sha512, recorded_sha512) != 0) |
2522 | printf ("Computed SHA-512: %s\n", computed_sha512); |
2489 | printf ("Computed SHA-512: %s\n", computed_sha512); |
2523 | if (computed_checksum != recorded_checksum) |
2490 | if (computed_checksum != recorded_checksum) |
2524 | printf ("Computed cksum: 0x%08x (%d)\n", computed_checksum, computed_checksum); |
2491 | printf ("Computed cksum: 0x%08x (%d)\n", computed_checksum, computed_checksum); |
2525 | } |
2492 | } |
2526 | else // old v1 trailer |
2493 | else // old v1 trailer |
2527 | { |
2494 | { |
2528 | recorded_checksum = image_trailer_v1->cksum; |
2495 | recorded_checksum = image_trailer_v1->cksum; |
2529 | computed_checksum = update_checksum (image_header, image_header->image_size - sizeof (image_trailer_v1_t), is_foreign_endianness); |
2496 | computed_checksum = update_checksum (image_header, image_header->image_size - sizeof (image_trailer_v1_t), is_foreign_endianness); |
2530 | printf (" cksum = 0x%08x (%d) - %s\n", recorded_checksum, recorded_checksum, (computed_checksum == recorded_checksum ? "GOOD" : "BAD")); |
2497 | printf (" cksum([0x%zx-0x%zx[) = 0x%08x (%d) - %s\n", imageheader_offset, imagetrailer_offset, recorded_checksum, recorded_checksum, (computed_checksum == recorded_checksum ? "GOOD" : "BAD")); |
2531 | if (computed_checksum != recorded_checksum) |
2498 | if (computed_checksum != recorded_checksum) |
2532 | printf ("Computed cksum: 0x%08x (%d)\n", computed_checksum, computed_checksum); |
2499 | printf ("Computed cksum: 0x%08x (%d)\n", computed_checksum, computed_checksum); |
2533 | } |
2500 | } |
2534 | 2501 | ||
2535 | current_offset += (image_header->flags & IMAGE_FLAGS_TRAILER_V2 ? sizeof (image_trailer_v2_t) : sizeof (image_trailer_v1_t)); // now reach the next segment (typically end of file) |
2502 | current_offset += (image_header->flags & IMAGE_FLAGS_TRAILER_V2 ? sizeof (image_trailer_v2_t) : sizeof (image_trailer_v1_t)); // now reach the next segment (typically end of file) |