Subversion Repositories QNX 8.QNX8 IFS tool

Rev

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

Rev 1 Rev 2
Line 1... Line 1...
1
// ifstool.c -- portable reimplementation of QNX's mkifs by Pierre-Marie Baty <pm@pmbaty.com>
1
// ifstool.c -- portable reimplementation of QNX's mkifs by Pierre-Marie Baty <pm@pmbaty.com>
2
 
2
 
3
#include <stdint.h>
3
#include <stdint.h>
4
#include <stdbool.h>
4
#include <stdbool.h>
5
#include <stdlib.h>
5
#include <stdlib.h>
-
 
6
#include <stdarg.h>
6
#include <stdio.h>
7
#include <stdio.h>
7
#include <string.h>
8
#include <string.h>
8
#include <errno.h>
9
#include <errno.h>
9
#include <sys/stat.h>
10
#include <sys/stat.h>
10
#include <ctype.h>
11
#include <ctype.h>
Line 21... Line 22...
21
#define S_IFLNK 0xa000
22
#define S_IFLNK 0xa000
22
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
23
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
23
#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
24
#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
24
#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
25
#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
25
#define strdup(s) _strdup ((s))
26
#define strdup(s) _strdup ((s))
-
 
27
#define strcasecmp(s1,s2) _stricmp ((s1), (s2))
26
#define fseek(fp,off,m) _fseeki64 ((fp), (off), (m))
28
#define fseek(fp,off,m) _fseeki64 ((fp), (off), (m))
27
#define access(p,m) _access ((p), (m))
29
#define access(p,m) _access ((p), (m))
28
#define MAXPATHLEN 1024
30
#define MAXPATHLEN 1024
29
#else // !_MSC_VER
31
#else // !_MSC_VER
30
#include <sys/param.h>
32
#include <sys/param.h>
Line 192... Line 194...
192
   "\x88\x00" /*size*/ "\x00" /*type*/ "\x00" /*spare*/ "\x00" /*CPU mask*/ "\x00" /*flags*/ "\x00\x00" /*reserved*/ "\x00" /*policy*/ "\x00" /*priority*/ "\02" /*argc*/ "\x02" /*envc*/ "sh\0" /*executable*/ "sh\0" "/proc/boot/startup.sh\0" /*argv*/ "PATH=/sbin:/usr/sbin:/bin:/usr/bin:/proc/boot\0" "LD_LIBRARY_PATH=/proc/boot:/lib:/lib/dll:/usr/lib\0" /*envp*/ \
194
   "\x88\x00" /*size*/ "\x00" /*type*/ "\x00" /*spare*/ "\x00" /*CPU mask*/ "\x00" /*flags*/ "\x00\x00" /*reserved*/ "\x00" /*policy*/ "\x00" /*priority*/ "\02" /*argc*/ "\x02" /*envc*/ "sh\0" /*executable*/ "sh\0" "/proc/boot/startup.sh\0" /*argv*/ "PATH=/sbin:/usr/sbin:/bin:/usr/bin:/proc/boot\0" "LD_LIBRARY_PATH=/proc/boot:/lib:/lib/dll:/usr/lib\0" /*envp*/ \
193
   /* display_msg "Startup complete */ \
195
   /* display_msg "Startup complete */ \
194
   "\x18\x00" /*size*/ "\x03" /*type*/ "\x00" /*spare*/ "Startup complete\n\0" "\x00\00" /*padding*/ \
196
   "\x18\x00" /*size*/ "\x03" /*type*/ "\x00" /*spare*/ "Startup complete\n\0" "\x00\00" /*padding*/ \
195
   /* trailer */ \
197
   /* trailer */ \
196
   "\x00\x00\x00\x00"
198
   "\x00\x00\x00\x00"
197
#define INITIAL_STARTUP_SCRIPT_LEN (sizeof (INITIAL_STARTUP_SCRIPT) - 1)
-
 
198
 
199
 
199
 
200
 
200
typedef struct fsentry_s
201
typedef struct __attribute__((packed)) fsentry_s
201
{
202
{
202
   struct __attribute__((packed)) fsentry_header_s
203
   struct __attribute__((packed)) fsentry_header_s
203
   {
204
   {
204
      uint16_t size; // size of dirent
205
      uint16_t size; // size of dirent
205
      uint16_t extattr_offset; // if zero, no extattr data
206
      uint16_t extattr_offset; // if zero, no extattr data
Line 207... Line 208...
207
      uint32_t mode; // mode and perms of entry
208
      uint32_t mode; // mode and perms of entry
208
      uint32_t gid;
209
      uint32_t gid;
209
      uint32_t uid;
210
      uint32_t uid;
210
      uint32_t mtime;
211
      uint32_t mtime;
211
   } header;
212
   } header;
212
   union fsentry_specific_u
213
   union __attribute__((packed)) fsentry_specific_u
213
   {
214
   {
214
      struct fsentry_file_s // when (mode & S_IFMT) == S_IFREG
215
      struct __attribute__((packed)) fsentry_file_s // when (mode & S_IFMT) == S_IFREG
215
      {
216
      {
216
         uint32_t offset; // offset from header
217
         uint32_t offset; // offset from header
217
         uint32_t size;
218
         uint32_t size;
218
         char *path; // null terminated path (no leading slash)
219
         char *path; // null terminated path (no leading slash)
219
         char *UNSAVED_databuf; // file data blob buffer (NOT SAVED IN THE IFS)
220
         char *UNSAVED_databuf; // file data blob buffer (NOT SAVED IN THE IFS)
220
      } file;
221
      } file;
221
      struct fsentry_dir_s // when (mode & S_IFMT) == S_IFDIR
222
      struct __attribute__((packed)) fsentry_dir_s // when (mode & S_IFMT) == S_IFDIR
222
      {
223
      {
223
         char *path; // null terminated path (no leading slash)
224
         char *path; // null terminated path (no leading slash)
224
      } dir;
225
      } dir;
225
      struct fsentry_symlink_s // when (mode & S_IFMT) == S_IFLNK
226
      struct __attribute__((packed)) fsentry_symlink_s // when (mode & S_IFMT) == S_IFLNK
226
      {
227
      {
227
         uint16_t sym_offset; // offset to 'contents' from 'path'
228
         uint16_t sym_offset; // offset to 'contents' from 'path'
228
         uint16_t sym_size; // strlen (contents)
229
         uint16_t sym_size; // strlen (contents)
229
         char *path; // null terminated path (no leading slash)
230
         char *path; // null terminated path (no leading slash)
230
         char *contents; // null terminated symlink contents
231
         char *contents; // null terminated symlink contents
231
      } symlink;
232
      } symlink;
232
      struct fsentry_device_s // when (mode & S_IFMT) == S_IF<CHR|BLK|FIFO|NAM|SOCK>
233
      struct __attribute__((packed)) fsentry_device_s // when (mode & S_IFMT) == S_IF<CHR|BLK|FIFO|NAM|SOCK>
233
      {
234
      {
234
         uint32_t dev;
235
         uint32_t dev;
235
         uint32_t rdev;
236
         uint32_t rdev;
236
         char *path; // null terminated path (no leading slash)
237
         char *path; // null terminated path (no leading slash)
237
      } device;
238
      } device;
Line 268... Line 269...
268
 
269
 
269
 
270
 
270
typedef struct __attribute__((packed)) startup_trailer_s
271
typedef struct __attribute__((packed)) startup_trailer_s
271
{
272
{
272
   uint32_t cksum; // checksum from start of header to start of trailer
273
   uint32_t cksum; // checksum from start of header to start of trailer
273
} startup_trailer_t;
274
} startup_trailer_v1_t;
274
 
275
 
275
 
276
 
276
// NOTE: The checksums in this trailer will only be valid prior to entering startup.
277
// NOTE: The checksums in this trailer will only be valid prior to entering startup.
277
// Because the startup binary is executed in-place, its data segment will change once the program is running.
278
// Because the startup binary is executed in-place, its data segment will change once the program is running.
278
// Hence, any checksum validation would need to be done by the boot loader / IFS.
279
// Hence, any checksum validation would need to be done by the boot loader / IFS.
Line 300... Line 301...
300
 
301
 
301
 
302
 
302
typedef struct __attribute__((packed)) image_trailer_v1_s
303
typedef struct __attribute__((packed)) image_trailer_v1_s
303
{
304
{
304
   uint32_t cksum; // checksum from start of header to start of trailer
305
   uint32_t cksum; // checksum from start of header to start of trailer
305
} image_trailer_v1_t;
306
} image_trailer_v1_t; // NOTE: this is the same structure as startup_trailer_v1_t
306
 
307
 
307
 
308
 
308
// NOTE: the checksums in this trailer will only be valid until the first non-startup bootstrap binary (e.g., startup-verifier, procnto, ...) is invoked.
309
// NOTE: the checksums in this trailer will only be valid until the first non-startup bootstrap binary (e.g., startup-verifier, procnto, ...) is invoked.
309
// Because bootstrap binaries execute in-place, their data segments will change once the programs are running.
310
// Because bootstrap binaries execute in-place, their data segments will change once the programs are running.
310
// Hence, any checksum validation would need to be done either by the boot loader / IFS or by the startup.
311
// Hence, any checksum validation would need to be done either by the boot loader / IFS or by the startup.
311
typedef struct __attribute__((packed)) image_trailer_v2_s
312
typedef struct __attribute__((packed)) image_trailer_v2_s
312
{
313
{
313
   uint8_t sha512[64]; // SHA512 from start of image header to start of trailer
314
   uint8_t sha512[64]; // SHA512 from start of image header to start of trailer
314
   uint32_t cksum; // checksum from start of header to start of this member
315
   uint32_t cksum; // checksum from start of header to start of this member
315
} image_trailer_v2_t;
316
} image_trailer_v2_t; // NOTE: this is the same structure as startup_trailer_v2_t
316
 
317
 
317
 
318
 
318
#ifdef _MSC_VER
319
#ifdef _MSC_VER
319
#pragma pack(pop)
320
#pragma pack(pop)
320
#endif // _MSC_VER
321
#endif // _MSC_VER
Line 326... Line 327...
326
   int perms; // file permissions (e.g. 0644)
327
   int perms; // file permissions (e.g. 0644)
327
   int uid; // owner user ID (e.g. 0 = root)
328
   int uid; // owner user ID (e.g. 0 = root)
328
   int gid; // owner group ID (e.g. 0 = root)
329
   int gid; // owner group ID (e.g. 0 = root)
329
   int st_mode; // entry type (e.g. S_IFREG for files) and permissions
330
   int st_mode; // entry type (e.g. S_IFREG for files) and permissions
330
   char prefix[MAXPATHLEN]; // install path (e.g. "proc/boot")
331
   char prefix[MAXPATHLEN]; // install path (e.g. "proc/boot")
331
   bool should_compile_contents_as_startup_script;
332
   bool is_compiled_bootscript; // entry has [+script] attribute
332
   char search[10 * MAXPATHLEN]; // binary search path (the default one will be constructed at startup)
333
   char search[10 * MAXPATHLEN]; // binary search path (the default one will be constructed at startup)
-
 
334
 
-
 
335
   uint8_t *precompiled_data;
-
 
336
   size_t precompiled_datalen;
333
} parms_t;
337
} parms_t;
334
 
338
 
335
 
339
 
336
// global variables
340
// global variables
337
static char line_buffer[4096]; // scrap buffer for the IFS build file parser
341
static char line_buffer[4096]; // scrap buffer for the IFS build file parser
Line 352... Line 356...
352
static void sha512_private_transform (SHA512_CTX *context, const uint64_t *data); // used internally in SHA512_Update() and SHA512_Final()
356
static void sha512_private_transform (SHA512_CTX *context, const uint64_t *data); // used internally in SHA512_Update() and SHA512_Final()
353
static void SHA512_Init (SHA512_CTX *context);
357
static void SHA512_Init (SHA512_CTX *context);
354
static void SHA512_Update (SHA512_CTX *context, void *data, size_t len);
358
static void SHA512_Update (SHA512_CTX *context, void *data, size_t len);
355
static void SHA512_Final (uint8_t digest[SHA512_DIGEST_LENGTH], SHA512_CTX *context);
359
static void SHA512_Final (uint8_t digest[SHA512_DIGEST_LENGTH], SHA512_CTX *context);
356
static uint8_t *SHA512 (void *data, size_t data_len, uint8_t *digest); // computes a SHA-512 in one pass (shortcut for SHA512_Init(), SHA512_Update() N times and SHA512_Final())
360
static uint8_t *SHA512 (void *data, size_t data_len, uint8_t *digest); // computes a SHA-512 in one pass (shortcut for SHA512_Init(), SHA512_Update() N times and SHA512_Final())
357
static int update_checksum_int32s (const int32_t start_value, const int32_t *data, const size_t len); // update the sum of an array of 32-bit signed integers
361
static int32_t update_checksum32 (const int32_t start_value, const void *data, const size_t len); // update the sum of an array of 32-bit signed integers
358
static long long read_integer (const char *str); // reads an integer number for a string that may be specified in either hex, octal or decimal base, and may have an optional unit suffix (k, m, g, t)
362
static long long read_integer (const char *str); // reads an integer number for a string that may be specified in either hex, octal or decimal base, and may have an optional unit suffix (k, m, g, t)
-
 
363
static void hex_fprintf (FILE *fp, const uint8_t *data, size_t data_size, int howmany_columns, const char *fmt, ...); // hexdump-style formatted output to a file stream (which may be stdout/stderr)
-
 
364
static char *binary (const uint8_t x, char char_for_zero, char char_for_one); // returns the binary representation of byte 'x' as a string
-
 
365
static char *describe_uint8 (const uint8_t x, const char *bitwise_stringdescs[8]); // returns the ORed description of byte 'x' according to the description strings for each bit
359
static int fwrite_filecontents (const char *pathname, FILE *fp); // dumps the contents of pathname into fp
366
static int fwrite_filecontents (const char *pathname, FILE *fp); // dumps the contents of pathname into fp
360
static size_t fwrite_fsentry (const fsentry_t *fsentry, FILE *fp); // writes the given filesystem entry into fp (without its contents)
367
static size_t fwrite_fsentry (const fsentry_t *fsentry, FILE *fp); // writes the given filesystem entry into fp (without its contents)
361
static size_t add_fsentry (fsentry_t **fsentries, size_t *fsentry_count, const char *stored_pathname, parms_t *entry_parms, const uint8_t *data, const size_t entry_datalen); // stack up a new filesystem entry
368
static size_t add_fsentry (fsentry_t **fsentries, size_t *fsentry_count, const char *stored_pathname, parms_t *entry_parms, const uint8_t *data, const size_t entry_datalen); // stack up a new filesystem entry
362
static int fsentry_compare_pathnames_cb (const void *a, const void *b); // qsort() comparison callback that sorts filesystem entries by pathnames
369
static int fsentry_compare_pathnames_cb (const void *a, const void *b); // qsort() comparison callback that sorts filesystem entries by pathnames
363
static int fsentry_compare_sizes_cb (const void *a, const void *b); // qsort() comparison callback that sorts filesystem entries by size
370
static int fsentry_compare_sizes_cb (const void *a, const void *b); // qsort() comparison callback that sorts filesystem entries by size
-
 
371
static int dump_ifs_info (const char *ifs_pathname); // dumps detailed info about a particular IFS file on the standard output, returns 0 on success and >0 on error
364
 
372
 
365
 
373
 
366
static void sha512_private_transform (SHA512_CTX *context, const uint64_t *data)
374
static void sha512_private_transform (SHA512_CTX *context, const uint64_t *data)
367
{
375
{
368
   // logical functions used in SHA-384 and SHA-512
376
   // logical functions used in SHA-384 and SHA-512
Line 584... Line 592...
584
   #undef SHA512_SHORT_BLOCK_LENGTH
592
   #undef SHA512_SHORT_BLOCK_LENGTH
585
   return;
593
   return;
586
}
594
}
587
 
595
 
588
 
596
 
589
static uint8_t *SHA512 (void *data, size_t data_len, uint8_t *digest)
597
static uint8_t *SHA512 (void *data, size_t data_len, uint8_t *digest_or_NULL)
590
{
598
{
591
   // computes the SHA-512 hash of a block of data in one pass and write it to digest
599
   // 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
-
 
600
   // returns the STRING REPRESENTATION of digest in a statically-allocated string
-
 
601
 
-
 
602
   static uint8_t static_digest[SHA512_DIGEST_LENGTH] = "";
-
 
603
   static char digest_as_string[2 * SHA512_DIGEST_LENGTH + 1] = "";
592
 
604
 
593
   SHA512_CTX ctx;
605
   SHA512_CTX ctx;
-
 
606
   size_t byte_index;
-
 
607
 
594
   SHA512_Init (&ctx);
608
   SHA512_Init (&ctx);
595
   SHA512_Update (&ctx, data, data_len);
609
   SHA512_Update (&ctx, data, data_len);
-
 
610
   if (digest_or_NULL == NULL)
-
 
611
      digest_or_NULL = static_digest;
596
   SHA512_Final (digest, &ctx);
612
   SHA512_Final (digest_or_NULL, &ctx);
-
 
613
 
-
 
614
   for (byte_index = 0; byte_index < SHA512_DIGEST_LENGTH; byte_index++)
-
 
615
      sprintf (&digest_as_string[2 * byte_index], "%02x", digest_or_NULL[byte_index]);
597
   return (digest);
616
   return (digest_as_string);
598
}
617
}
599
 
618
 
600
 
619
 
601
static int update_checksum_int32s (const int32_t start_value, const int32_t *data, const size_t len)
620
static int32_t update_checksum32 (const int32_t start_value, const void *data, const size_t len)
602
{
621
{
603
   // compute the sum of an array of 32-bit signed integers
622
   // compute the sum of an array of 32-bit signed integers
604
 
623
 
605
   size_t byte_index;
624
   const int32_t *values_array = data;
606
   int32_t sum = start_value;
625
   int32_t sum = start_value;
-
 
626
 
607
   for (byte_index = 0; byte_index < len; byte_index += sizeof (int32_t))
627
   for (size_t value_index = 0; value_index < len / sizeof (int32_t); value_index++)
608
      sum += *data++;
628
      sum += values_array[value_index];
-
 
629
 
609
   return (sum);
630
   return (sum);
610
}
631
}
611
 
632
 
612
 
633
 
613
static long long read_integer (const char *str)
634
static long long read_integer (const char *str)
Line 622... Line 643...
622
      else if ((*endptr == 'm') || (*endptr == 'M')) ret *= (size_t) 1024 * 1024;
643
      else if ((*endptr == 'm') || (*endptr == 'M')) ret *= (size_t) 1024 * 1024;
623
      else if ((*endptr == 'g') || (*endptr == 'G')) ret *= (size_t) 1024 * 1024 * 1024;
644
      else if ((*endptr == 'g') || (*endptr == 'G')) ret *= (size_t) 1024 * 1024 * 1024;
624
      else if ((*endptr == 't') || (*endptr == 'T')) ret *= (size_t) 1024 * 1024 * 1024 * 1024; // future-proof enough, I suppose?
645
      else if ((*endptr == 't') || (*endptr == 'T')) ret *= (size_t) 1024 * 1024 * 1024 * 1024; // future-proof enough, I suppose?
625
   }
646
   }
626
   return (ret);
647
   return (ret);
-
 
648
}
-
 
649
 
-
 
650
 
-
 
651
static void hex_fprintf (FILE *fp, const uint8_t *data, size_t data_size, int howmany_columns, const char *fmt, ...)
-
 
652
{
-
 
653
   // this function logs hexadecimal data to an opened file pointer (or to stdout/stderr)
-
 
654
 
-
 
655
   va_list argptr;
-
 
656
   size_t index;
-
 
657
   int i;
-
 
658
 
-
 
659
   // concatenate all the arguments in one string and write it to the file
-
 
660
   va_start (argptr, fmt);
-
 
661
   vfprintf (fp, fmt, argptr);
-
 
662
   va_end (argptr);
-
 
663
 
-
 
664
   // for each row of howmany_columns bytes of data...
-
 
665
   for (index = 0; index < data_size; index += howmany_columns)
-
 
666
   {
-
 
667
      fprintf (fp, "    %05zu  ", index); // print array address of row
-
 
668
      for (i = 0; i < howmany_columns; i++)
-
 
669
         if (index + i < data_size)
-
 
670
            fprintf (fp, " %02X", data[index + i]); // if row contains data, print data as hex bytes
-
 
671
         else
-
 
672
            fprintf (fp, "   "); // else fill the space with blanks
-
 
673
      fprintf (fp, "   ");
-
 
674
      for (i = 0; i < howmany_columns; i++)
-
 
675
         if (index + i < data_size)
-
 
676
            fputc ((data[index + i] >= 32) && (data[index + i] < 127) ? data[index + i] : '.', fp); // now if row contains data, print data as ASCII
-
 
677
         else
-
 
678
            fputc (' ', fp); // else fill the space with blanks
-
 
679
      fputc ('\n', fp);
-
 
680
   }
-
 
681
 
-
 
682
   return; // and return
-
 
683
}
-
 
684
 
-
 
685
 
-
 
686
static char *binary (const uint8_t x, char char_for_zero, char char_for_one)
-
 
687
{
-
 
688
   // returns the binary representation of x as a string
-
 
689
 
-
 
690
   static char outstr[9] = "00000000";
-
 
691
   for (int i = 0; i < 8; i++)
-
 
692
      outstr[i] = (x & (0x80 >> i) ? char_for_one : char_for_zero);
-
 
693
   return (outstr);
-
 
694
}
-
 
695
 
-
 
696
 
-
 
697
static char *describe_uint8 (const uint8_t x, const char *bitwise_stringdescs[8])
-
 
698
{
-
 
699
   // returns the ORed description of byte 'x' according to the description strings for each bit
-
 
700
 
-
 
701
   static char *default_bitstrings[8] = { "bit0", "bit1", "bit2", "bit3", "bit4", "bit5", "bit6", "bit7" };
-
 
702
   static char outstr[8 * 64] = "";
-
 
703
 
-
 
704
   outstr[0] = 0;
-
 
705
   for (int i = 0; i < 8; i++)
-
 
706
      if (x & (1 << i))
-
 
707
      {
-
 
708
         if (outstr[0] != 0)
-
 
709
            strcat (outstr, "|");
-
 
710
         strcat (outstr, ((bitwise_stringdescs != NULL) && (*bitwise_stringdescs[i] != 0) ? bitwise_stringdescs[i] : default_bitstrings[i]));
-
 
711
      }
-
 
712
   return (outstr);
627
}
713
}
628
 
714
 
629
 
715
 
630
static int fwrite_filecontents (const char *pathname, FILE *fp)
716
static int fwrite_filecontents (const char *pathname, FILE *fp)
631
{
717
{
Line 737... Line 823...
737
   void *reallocated_ptr;
823
   void *reallocated_ptr;
738
   char processor_base[16];
824
   char processor_base[16];
739
   struct stat stat_buf;
825
   struct stat stat_buf;
740
   uint8_t *data_buffer = NULL;
826
   uint8_t *data_buffer = NULL;
741
   size_t data_len = 0;
827
   size_t data_len = 0;
742
   uint32_t mtime = 0;
828
   uint32_t mtime = (uint32_t) time (NULL);
743
   uint32_t extra_ino_flags = 0;
829
   uint32_t extra_ino_flags = 0;
744
   fsentry_t *fsentry;
830
   fsentry_t *fsentry;
745
   char *token;
831
   char *token;
746
   FILE *fp;
832
   FILE *fp;
747
 
833
 
Line 755... Line 841...
755
      {
841
      {
756
         if (strcmp (stored_pathname, "proc/boot/boot") == 0) // is it the kernel ?
842
         if (strcmp (stored_pathname, "proc/boot/boot") == 0) // is it the kernel ?
757
         {
843
         {
758
            // HACK: for now just consider the kernel as a binary blob
844
            // HACK: for now just consider the kernel as a binary blob
759
            // FIXME: reimplement properly
845
            // FIXME: reimplement properly
760
            if (stat ("procnto-smp-instr.bin", &stat_buf) != 0)
-
 
761
            {
-
 
762
               fprintf (stderr, "fatal error: unable to read procnto-smp-instr.bin\n");
-
 
763
               exit (1);
-
 
764
            }
-
 
765
            data_len = stat_buf.st_size;
846
            data_len = entry_datalen;
766
            mtime = (uint32_t) time (NULL);
-
 
767
            data_buffer = malloc (data_len);
847
            data_buffer = malloc (data_len);
768
            if (data_buffer == NULL)
848
            if (data_buffer == NULL)
769
            {
849
            {
770
               fprintf (stderr, "fatal error: out of memory\n");
850
               fprintf (stderr, "fatal error: out of memory\n");
771
               exit (1);
851
               exit (1);
772
            }
852
            }
773
            fp = fopen ("procnto-smp-instr.bin", "rb");
-
 
774
            fread (data_buffer, 1, data_len, fp);
853
            memcpy (data_buffer, entry_data, data_len);
775
            fclose (fp);
-
 
-
 
854
 
776
            sprintf (candidate_pathname, "%s/procnto-smp-instr", entry_parms->prefix);
855
            sprintf (candidate_pathname, "%s/procnto-smp-instr", entry_parms->prefix); // fix the entry name
777
            stored_pathname = candidate_pathname;
856
            stored_pathname = candidate_pathname;
778
            extra_ino_flags = IFS_INO_PROCESSED_ELF | IFS_INO_BOOTSTRAP_EXE;
857
            extra_ino_flags = IFS_INO_PROCESSED_ELF | IFS_INO_BOOTSTRAP_EXE; // procnto needs to have these flags stamped on the inode
779
            image_kernel_ino = extra_ino_flags | (inode_count + 1);
858
            image_kernel_ino = extra_ino_flags | (inode_count + 1);
780
         }
859
         }
781
         else if (entry_parms->should_compile_contents_as_startup_script) // should we compile this contents as a startup script ?
860
         else if (entry_parms->is_compiled_bootscript) // else is it a startup script ?
-
 
861
            image_bootscript_ino = inode_count + 1; // save boot script inode number for image header
-
 
862
 
-
 
863
         // should we substitute precompiled data to this data blob ?
-
 
864
         if ((entry_parms->precompiled_data != NULL) && (entry_parms->precompiled_datalen > 0))
782
         {
865
         {
783
            // HACK: for now just use a precompiled script
866
            data_len = entry_parms->precompiled_datalen;
784
            // FIXME: replace this with a true compilation with the rules defined above
-
 
785
            data_buffer = malloc (INITIAL_STARTUP_SCRIPT_LEN);
867
            data_buffer = malloc (data_len);
786
            if (data_buffer == NULL)
868
            if (data_buffer == NULL)
787
            {
869
            {
788
               fprintf (stderr, "fatal error: out of memory\n");
870
               fprintf (stderr, "fatal error: out of memory\n");
789
               exit (1);
871
               exit (1);
790
            }
872
            }
791
            memcpy (data_buffer, INITIAL_STARTUP_SCRIPT, INITIAL_STARTUP_SCRIPT_LEN);
873
            memcpy (data_buffer, entry_parms->precompiled_data, data_len);
792
            data_len = INITIAL_STARTUP_SCRIPT_LEN;
-
 
793
            image_bootscript_ino = inode_count + 1; // save boot script inode number for image header
-
 
794
         }
874
         }
795
         else // else it's an explicit blob of some other sort
875
         else // else use the supplied data blob
796
         {
876
         {
797
            data_len = entry_datalen;
877
            data_len = entry_datalen;
798
            mtime = (uint32_t) time (NULL);
-
 
799
 
-
 
800
            data_buffer = malloc (data_len);
878
            data_buffer = malloc (data_len);
801
            if (data_buffer == NULL)
879
            if (data_buffer == NULL)
802
            {
880
            {
803
               fprintf (stderr, "fatal error: out of memory\n");
881
               fprintf (stderr, "fatal error: out of memory\n");
804
               exit (1);
882
               exit (1);
805
            }
883
            }
806
            memcpy (data_buffer, entry_data, data_len);
884
            memcpy (data_buffer, entry_data, data_len);
807
         }
885
         }
-
 
886
/*
-
 
887
         else if (entry_parms->should_compile_contents_as_startup_script) // should we compile this contents as a startup script ?
-
 
888
         {
-
 
889
            // HACK: for now just use a precompiled script
-
 
890
            // FIXME: replace this with a true compilation with the rules defined above
-
 
891
            data_buffer = malloc (INITIAL_STARTUP_SCRIPT_LEN);
-
 
892
            if (data_buffer == NULL)
-
 
893
            {
-
 
894
               fprintf (stderr, "fatal error: out of memory\n");
-
 
895
               exit (1);
-
 
896
            }
-
 
897
            memcpy (data_buffer, INITIAL_STARTUP_SCRIPT, INITIAL_STARTUP_SCRIPT_LEN);
-
 
898
            data_len = INITIAL_STARTUP_SCRIPT_LEN;
-
 
899
            image_bootscript_ino = inode_count + 1; // save boot script inode number for image header
-
 
900
         }*/
808
 
901
 
809
         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, data_len);
902
         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, data_len);
810
      }
903
      }
811
      else if ((entry_data != NULL) && (entry_data[0] != 0)) // else entry_datalen == 0, was some sort of pathname supplied ?
904
      else if ((entry_data != NULL) && (entry_data[0] != 0)) // else entry_datalen == 0, was some sort of pathname supplied ?
812
      {
905
      {
Line 902... Line 995...
902
      }
995
      }
903
   }
996
   }
904
   else if (S_ISLNK (entry_parms->st_mode)) // else are we storing a symbolic link ?
997
   else if (S_ISLNK (entry_parms->st_mode)) // else are we storing a symbolic link ?
905
   {
998
   {
906
      data_len = strlen (entry_data);
999
      data_len = strlen (entry_data);
907
      mtime = (uint32_t) time (NULL);
-
 
908
 
1000
 
909
      data_buffer = malloc (data_len + 1);
1001
      data_buffer = malloc (data_len + 1);
910
      if (data_buffer == NULL)
1002
      if (data_buffer == NULL)
911
      {
1003
      {
912
         fprintf (stderr, "fatal error: out of memory\n");
1004
         fprintf (stderr, "fatal error: out of memory\n");
Line 1008... Line 1100...
1008
{
1100
{
1009
   // program entrypoint
1101
   // program entrypoint
1010
 
1102
 
1011
   #define PAD_OUTFILE_TO(val) do { curr_offset = ftell (fp); while (curr_offset < (val)) { putc (0, fp); curr_offset++; } } while (0)
1103
   #define PAD_OUTFILE_TO(val) do { curr_offset = ftell (fp); while (curr_offset < (val)) { putc (0, fp); curr_offset++; } } while (0)
1012
 
1104
 
1013
   startup_header_t startup_header = { 0 }; // output IFS's startup header
1105
   static startup_header_t startup_header = { 0 }; // output IFS's startup header
1014
   startup_trailer_v2_t startup_trailer = { 0 }; // output IFS's startup trailer (version 2, with SHA-512 checksum and int32 checksum)
1106
   static startup_trailer_v2_t startup_trailer = { 0 }; // output IFS's startup trailer (version 2, with SHA-512 checksum and int32 checksum)
1015
   image_header_t image_header = { 0 }; // output IFS's imagefs header
1107
   static image_header_t image_header = { 0 }; // output IFS's imagefs header
1016
   image_trailer_v2_t image_trailer = { 0 }; // output IFS's imagefs trailer (version 2, with SHA-512 checksum and int32 checksum)
1108
   static image_trailer_v2_t image_trailer = { 0 }; // output IFS's imagefs trailer (version 2, with SHA-512 checksum and int32 checksum)
1017
   fsentry_t *fsentries = NULL; // output IFS's filesystem entries
1109
   static fsentry_t *fsentries = NULL; // output IFS's filesystem entries
1018
   size_t fsentry_count = 0; // number of entries in the IFS filesystem
1110
   static size_t fsentry_count = 0; // number of entries in the IFS filesystem
1019
   parms_t default_parms = { 0755, 0644, 0, 0, S_IFREG, "/proc/boot", false, "" }; // default parameters for a filesystem entry
1111
   static parms_t default_parms = { 0755, 0644, 0, 0, S_IFREG, "/proc/boot", false, "", NULL, 0 }; // default parameters for a filesystem entry
1020
   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)
1112
   static parms_t entry_parms = { 0 }; // current parameters for a filesystem entry (will be initialized to default_parms each time a new entry is parsed in the build file)
1021
 
1113
 
1022
   // bootable IFS support
1114
   // bootable IFS support
1023
   char *bootfile_pathname = NULL;           // HACK: pathname to bootcode binary blob file to put at the start of a bootable IFS
1115
   char *bootfile_pathname = NULL;           // HACK: pathname to bootcode binary blob file to put at the start of a bootable IFS
-
 
1116
   size_t bootfile_size = 0;                 // HACK: size of the bootcode binary blob file to put at the start of a bootable IFS
1024
   char *startupfile_pathname = NULL;        // HACK: pathname to precompiled startup file blob to put in the startup header of a bootable IFS
1117
   char *startupfile_pathname = NULL;        // HACK: pathname to precompiled startup file blob to put in the startup header of a bootable IFS
1025
   size_t startupfile_ep_from_imagebase = 0; // HACK: startup code entrypoint offset from image base for a bootable IFS 
1118
   size_t startupfile_ep_from_imagebase = 0; // HACK: startup code entrypoint offset from image base for a bootable IFS 
1026
   char *kernelfile_pathname = NULL;         // HACK: pathname to precompiled kernel file blob to put in a bootable IFS
1119
   char *kernelfile_pathname = NULL;         // HACK: pathname to precompiled kernel file blob to put in a bootable IFS
1027
   size_t kernelfile_offset = 0;             // HACK: kernel file offset in bootable IFS
1120
   size_t kernelfile_offset = 0;             // HACK: kernel file offset in bootable IFS
1028
 
1121
 
1029
   char path_in_ifs[MAXPATHLEN];
1122
   char path_in_ifs[MAXPATHLEN];
1030
   char image_bootfile[MAXPATHLEN];
-
 
1031
   size_t image_bootfilesize = 0;
-
 
1032
   char *ifs_pathname = NULL;
1123
   char *ifs_pathname = NULL;
1033
   void *reallocated_ptr;
1124
   void *reallocated_ptr;
1034
   struct stat stat_buf;
1125
   struct stat stat_buf;
1035
   size_t startuptrailer_offset;
1126
   size_t startuptrailer_offset;
1036
   size_t startupheader_offset;
1127
   size_t startupheader_offset;
Line 1099... Line 1190...
1099
      else if (ifs_pathname == NULL)
1190
      else if (ifs_pathname == NULL)
1100
         ifs_pathname = argv[arg_index];
1191
         ifs_pathname = argv[arg_index];
1101
   }
1192
   }
1102
 
1193
 
1103
   // do we not have enough information to run ?
1194
   // do we not have enough information to run ?
1104
   if (want_help || (ifs_pathname == NULL) || (!want_info && (buildfile_pathname == NULL)))
1195
   if (want_help || (buildfile_pathname == NULL) || (!want_info && (ifs_pathname == NULL)))
1105
   {
1196
   {
1106
      if (want_help)
1197
      if (want_help)
1107
         fprintf (stdout, "ifstool - QNX in-kernel filesystem creation utility by Pierre-Marie Baty <pm@pmbaty.com>\n");
1198
         fprintf (stdout, "ifstool - QNX in-kernel filesystem creation utility by Pierre-Marie Baty <pm@pmbaty.com>\n");
1108
      else
1199
      else
1109
         fprintf (stderr, "error: missing parameters\n");
1200
         fprintf (stderr, "error: missing parameters\n");
Line 1111... Line 1202...
1111
      fprintf ((want_help ? stdout : stderr), "    ifstool [--bootfile <pathname>] [--startupfile <pathname>@<EP_from_imgbase>] [--kernelfile <pathname>@<fileoffs>] <buildfile> <outfile>\n");
1202
      fprintf ((want_help ? stdout : stderr), "    ifstool [--bootfile <pathname>] [--startupfile <pathname>@<EP_from_imgbase>] [--kernelfile <pathname>@<fileoffs>] <buildfile> <outfile>\n");
1112
      fprintf ((want_help ? stdout : stderr), "    ifstool --info <ifs file>\n");
1203
      fprintf ((want_help ? stdout : stderr), "    ifstool --info <ifs file>\n");
1113
      fprintf ((want_help ? stdout : stderr), "    ifstool --help\n");
1204
      fprintf ((want_help ? stdout : stderr), "    ifstool --help\n");
1114
      exit (want_help ? 0 : 1);
1205
      exit (want_help ? 0 : 1);
1115
   }
1206
   }
-
 
1207
 
-
 
1208
   // do we want info about a particular IFS ? if so, dump it
-
 
1209
   if (want_info)
-
 
1210
      exit (dump_ifs_info (buildfile_pathname)); // NOTE: the first argument after --info is actually the IFS file, not a build file, but the arguments are collected in this order
1116
 
1211
 
1117
   // make sure we have ${QNX_TARGET} pointing somewhere
1212
   // make sure we have ${QNX_TARGET} pointing somewhere
1118
   QNX_TARGET = getenv ("QNX_TARGET");
1213
   QNX_TARGET = getenv ("QNX_TARGET");
1119
   if (QNX_TARGET == NULL)
1214
   if (QNX_TARGET == NULL)
1120
   {
1215
   {
Line 1214... Line 1309...
1214
                  *sep = 0;
1309
                  *sep = 0;
1215
                  strcpy (image_processor, value); // save processor
1310
                  strcpy (image_processor, value); // save processor
1216
                  value = sep + 1;
1311
                  value = sep + 1;
1217
               }
1312
               }
1218
               //sprintf (image_bootfile, "%s/%s/boot/sys/%s.boot", QNX_TARGET, image_processor, value); // save preboot file name (FIXME: we should search in MKIFS_PATH instead of this. Not important.)
1313
               //sprintf (image_bootfile, "%s/%s/boot/sys/%s.boot", QNX_TARGET, image_processor, value); // save preboot file name (FIXME: we should search in MKIFS_PATH instead of this. Not important.)
1219
               strcpy (image_bootfile, bootfile_pathname); // FIXME: HACK
1314
               //strcpy (image_bootfile, bootfile_pathname); // FIXME: HACK
1220
               if (stat (image_bootfile, &stat_buf) != 0)
1315
               if (stat (bootfile_pathname, &stat_buf) != 0)
1221
               {
1316
               {
1222
                  fprintf (stderr, "error: unable to stat the boot file \"%s\" specified in \"%s\" line %d: %s\n", image_bootfile, buildfile_pathname, lineno, strerror (errno));
1317
                  fprintf (stderr, "error: unable to stat the boot file \"%s\" specified in \"%s\" line %d: %s\n", bootfile_pathname, buildfile_pathname, lineno, strerror (errno));
1223
                  exit (1);
1318
                  exit (1);
1224
               }
1319
               }
1225
               image_bootfilesize = stat_buf.st_size; // save preboot file size
1320
               bootfile_size = stat_buf.st_size; // save preboot file size
1226
               fprintf (stderr, "info: processor \"%s\" bootfile \"%s\"\n", image_processor, image_bootfile);
1321
               fprintf (stderr, "info: processor \"%s\" bootfile \"%s\"\n", image_processor, bootfile_pathname);
-
 
1322
               if (stat (kernelfile_pathname, &stat_buf) != 0)
-
 
1323
               {
-
 
1324
                  fprintf (stderr, "fatal error: unable to read precompiled kernel file \"%s\" specified in --kernelfile argument\n", kernelfile_pathname);
-
 
1325
                  exit (1);
-
 
1326
               }
-
 
1327
               entry_parms.precompiled_data = malloc (stat_buf.st_size);
-
 
1328
               if (entry_parms.precompiled_data == NULL)
-
 
1329
               {
-
 
1330
                  fprintf (stderr, "fatal error: out of memory\n");
-
 
1331
                  exit (1);
-
 
1332
               }
-
 
1333
               fp = fopen ("procnto-smp-instr.bin", "rb");
-
 
1334
               fread (entry_parms.precompiled_data, 1, stat_buf.st_size, fp);
-
 
1335
               fclose (fp);
-
 
1336
               entry_parms.precompiled_datalen = stat_buf.st_size;
-
 
1337
            }
-
 
1338
            else if (strcmp (token, "+script") == 0) {
-
 
1339
               entry_parms.is_compiled_bootscript = true;
-
 
1340
               entry_parms.precompiled_data = INITIAL_STARTUP_SCRIPT; // HACK until the script compiler is implemented
-
 
1341
               entry_parms.precompiled_datalen = sizeof (INITIAL_STARTUP_SCRIPT) - 1;
1227
            }
1342
            }
1228
            else if (strcmp (token, "+script") == 0) entry_parms.should_compile_contents_as_startup_script = true;
-
 
1229
            else fprintf (stderr, "warning: unimplemented attribute in \"%s\" line %d: '%s'\n", buildfile_pathname, lineno, token);
1343
            else fprintf (stderr, "warning: unimplemented attribute in \"%s\" line %d: '%s'\n", buildfile_pathname, lineno, token);
1230
            #undef REACH_TOKEN_VALUE
1344
            #undef REACH_TOKEN_VALUE
1231
 
1345
 
1232
            token = strtok (NULL, RECORD_SEP_STR); // proceed to next attribute token
1346
            token = strtok (NULL, RECORD_SEP_STR); // proceed to next attribute token
1233
         }
1347
         }
Line 1251... Line 1365...
1251
            APPLY_DEFAULT_ATTR_NUM (perms,   "file permissions",      "0%o");
1365
            APPLY_DEFAULT_ATTR_NUM (perms,   "file permissions",      "0%o");
1252
            APPLY_DEFAULT_ATTR_NUM (uid,     "owner ID",              "%d");
1366
            APPLY_DEFAULT_ATTR_NUM (uid,     "owner ID",              "%d");
1253
            APPLY_DEFAULT_ATTR_NUM (gid,     "group ID",              "%d");
1367
            APPLY_DEFAULT_ATTR_NUM (gid,     "group ID",              "%d");
1254
            APPLY_DEFAULT_ATTR_NUM (st_mode, "inode type",            "0%o");
1368
            APPLY_DEFAULT_ATTR_NUM (st_mode, "inode type",            "0%o");
1255
            APPLY_DEFAULT_ATTR_STR (prefix,  "prefix",                "\"%s\"");
1369
            APPLY_DEFAULT_ATTR_STR (prefix,  "prefix",                "\"%s\"");
1256
            APPLY_DEFAULT_ATTR_NUM (should_compile_contents_as_startup_script, "compiled script state", "%d");
1370
            APPLY_DEFAULT_ATTR_NUM (is_compiled_bootscript, "compiled script state", "%d");
1257
            #undef APPLY_DEFAULT_ATTR_STR
1371
            #undef APPLY_DEFAULT_ATTR_STR
1258
            #undef APPLY_DEFAULT_ATTR_NUM
1372
            #undef APPLY_DEFAULT_ATTR_NUM
1259
            continue; // end of line reached, proceed to the next line
1373
            continue; // end of line reached, proceed to the next line
1260
         }
1374
         }
1261
         // end of attributes parsing
1375
         // end of attributes parsing
Line 1387... Line 1501...
1387
   {
1501
   {
1388
      fprintf (stderr, "error: failed to open \"%s\" for writing (%s)\n", ifs_pathname, strerror (errno));
1502
      fprintf (stderr, "error: failed to open \"%s\" for writing (%s)\n", ifs_pathname, strerror (errno));
1389
      exit (1);
1503
      exit (1);
1390
   }
1504
   }
1391
 
1505
 
1392
   // do we have a boot file ? if so, this is a bootable image
1506
   // do we have a startup file ? if so, this is a bootable image
1393
   if (image_bootfile[0] != 0)
1507
   if (startupfile_pathname != NULL)
1394
   {
1508
   {
1395
      // write boot prefix
1509
      // write boot prefix
1396
      fwrite_filecontents (image_bootfile, fp);
1510
      fwrite_filecontents (bootfile_pathname, fp);
1397
      PAD_OUTFILE_TO (ROUND_TO_UPPER_MULTIPLE (ftell (fp), image_align)); // pad as necessary
1511
      PAD_OUTFILE_TO (ROUND_TO_UPPER_MULTIPLE (ftell (fp), image_align)); // pad as necessary
1398
 
1512
 
1399
      startupheader_offset = ftell (fp); // save startup header offset
1513
      startupheader_offset = ftell (fp); // save startup header offset
1400
      memset (&startup_header, 0, sizeof (startup_header)); // prepare startup header
1514
      memset (&startup_header, 0, sizeof (startup_header)); // prepare startup header
1401
      memcpy (startup_header.signature, "\xeb\x7e\xff\x00", 4); // startup header signature, i.e. 0xff7eeb
1515
      memcpy (startup_header.signature, "\xeb\x7e\xff\x00", 4); // startup header signature, i.e. 0xff7eeb
Line 1410... Line 1524...
1410
      {
1524
      {
1411
         fprintf (stderr, "fatal error: unsupported processor type '%s' found in build file \"%s\"\n", image_processor, buildfile_pathname);
1525
         fprintf (stderr, "fatal error: unsupported processor type '%s' found in build file \"%s\"\n", image_processor, buildfile_pathname);
1412
         exit (1);
1526
         exit (1);
1413
      }
1527
      }
1414
      startup_header.startup_vaddr = image_base + (uint32_t) startupfile_ep_from_imagebase; // [I ] Virtual Address to transfer to after IPL is done, here 0x01403008 (appears in "Entry" column for "startup.*")
1528
      startup_header.startup_vaddr = image_base + (uint32_t) startupfile_ep_from_imagebase; // [I ] Virtual Address to transfer to after IPL is done, here 0x01403008 (appears in "Entry" column for "startup.*")
1415
      startup_header.image_paddr   = image_base + (uint32_t) image_bootfilesize;            // F[IS] Physical address of image, here 0x01400f30 (appears in "Offset" column for "startup-header" which is the first entry/start of file)
1529
      startup_header.image_paddr   = image_base + (uint32_t) bootfile_size;                 // F[IS] Physical address of image, here 0x01400f30 (appears in "Offset" column for "startup-header" which is the first entry/start of file)
1416
      startup_header.ram_paddr     = startup_header.image_paddr;                            // [IS] Physical address of RAM to copy image to (startup_size bytes copied), here 0x01400f30 (same as above)
1530
      startup_header.ram_paddr     = startup_header.image_paddr;                            // [IS] Physical address of RAM to copy image to (startup_size bytes copied), here 0x01400f30 (same as above)
1417
      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)
1531
      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)
1418
      startup_header.startup_size  = WILL_BE_FILLED_LATER;                                  // [I ] Size of startup (never compressed), here 0x02f148 or 192 840 bytes
1532
      startup_header.startup_size  = WILL_BE_FILLED_LATER;                                  // [I ] Size of startup (never compressed), here 0x02f148 or 192 840 bytes
1419
      startup_header.stored_size   = startup_header.ram_size;                               // [I ] Size of entire image, here 0x00cd6128 (same as ram_size)
1533
      startup_header.stored_size   = WILL_BE_FILLED_LATER;                                  // [I ] Size of entire image, here 0x00cd6128 (same as ram_size)
1420
      startup_header.imagefs_size  = WILL_BE_FILLED_LATER;                                  // [ S] Size of uncompressed imagefs, here 0x00ca6fe0 or 13 266 912 bytes
1534
      startup_header.imagefs_size  = WILL_BE_FILLED_LATER;                                  // [ S] Size of uncompressed imagefs, here 0x00ca6fe0 or 13 266 912 bytes
1421
      startup_header.preboot_size  = (uint16_t) image_bootfilesize;                         // [I ] Size of loaded before header, here 0xf30 or 3888 bytes (size of "bios.boot" file))
1535
      startup_header.preboot_size  = (uint16_t) bootfile_size;                              // [I ] Size of loaded before header, here 0xf30 or 3888 bytes (size of "bios.boot" file))
1422
      fwrite (&startup_header, sizeof (startup_header), 1, fp); // write startup header
1536
      fwrite (&startup_header, sizeof (startup_header), 1, fp); // write startup header
1423
      PAD_OUTFILE_TO (ROUND_TO_UPPER_MULTIPLE (ftell (fp), image_align)); // pad as necessary
1537
      PAD_OUTFILE_TO (ROUND_TO_UPPER_MULTIPLE (ftell (fp), image_align)); // pad as necessary
1424
 
1538
 
1425
      // ######################################################################################################################################################################################################################################
1539
      // ######################################################################################################################################################################################################################################
1426
      // # FIXME: figure out how to re-create it: linker call involved
1540
      // # FIXME: figure out how to re-create it: linker call involved
Line 1452... Line 1566...
1452
   for (fsentry_index = 0; fsentry_index < fsentry_count; fsentry_index++)
1566
   for (fsentry_index = 0; fsentry_index < fsentry_count; fsentry_index++)
1453
      fwrite_fsentry (&fsentries[fsentry_index], fp);
1567
      fwrite_fsentry (&fsentries[fsentry_index], fp);
1454
   PAD_OUTFILE_TO (ROUND_TO_UPPER_MULTIPLE (ftell (fp), image_align)); // pad as necessary
1568
   PAD_OUTFILE_TO (ROUND_TO_UPPER_MULTIPLE (ftell (fp), image_align)); // pad as necessary
1455
 
1569
 
1456
   // is it a bootable image with a kernel file ?
1570
   // is it a bootable image with a kernel file ?
1457
   if ((image_bootfile[0] != 0) && (kernelfile_pathname != NULL))
1571
   if ((startupfile_pathname != NULL) && (kernelfile_pathname != NULL))
1458
   {
1572
   {
1459
      // sort the filesystem entries by sizes
1573
      // sort the filesystem entries by sizes
1460
      qsort (fsentries, fsentry_count, sizeof (fsentry_t), fsentry_compare_sizes_cb);
1574
      qsort (fsentries, fsentry_count, sizeof (fsentry_t), fsentry_compare_sizes_cb);
1461
 
1575
 
1462
      // write as many small files as we can before reaching the kernel offset 
1576
      // write as many small files as we can before reaching the kernel offset 
Line 1508... Line 1622...
1508
   {
1622
   {
1509
      fprintf (stderr, "error: image file \"%s\" size %zd exceeds max size (%zd)\n", ifs_pathname, final_size, (size_t) image_maxsize);
1623
      fprintf (stderr, "error: image file \"%s\" size %zd exceeds max size (%zd)\n", ifs_pathname, final_size, (size_t) image_maxsize);
1510
      exit (1);
1624
      exit (1);
1511
   }
1625
   }
1512
 
1626
 
1513
   // do we have a boot file ? if so, this is a bootable image
1627
   // do we have a startup file ? if so, this is a bootable image
1514
   if (image_bootfile[0] == 0)
1628
   if (startupfile_pathname != NULL)
1515
   {
1629
   {
1516
      // rewrite startup header with final values
1630
      // rewrite startup header with final values
1517
      fseek (fp, startupheader_offset, SEEK_SET);
1631
      fseek (fp, startupheader_offset, SEEK_SET);
1518
      startup_header.startup_size = (uint32_t) (imgheader_offset - startupheader_offset); // size of startup header up to image header
1632
      startup_header.startup_size = (uint32_t) (imgheader_offset - startupheader_offset); // size of startup header up to image header
1519
      startup_header.imagefs_size = (uint32_t) (final_size - imgheader_offset); // size of uncompressed imagefs
1633
      startup_header.imagefs_size = (uint32_t) (final_size - imgheader_offset); // size of uncompressed imagefs
1520
      startup_header.ram_size = (uint32_t) final_size; // FIXME: this is necessarily a bit less, but should we really bother calculating the right size ?
1634
      startup_header.ram_size = (uint32_t) final_size; // FIXME: this is necessarily a bit less, but should we really bother calculating the right size ?
-
 
1635
      startup_header.stored_size = startup_header.ram_size;
1521
      fwrite (&startup_header, sizeof (startup_header), 1, fp); // write startup header
1636
      fwrite (&startup_header, sizeof (startup_header), 1, fp); // write startup header
1522
 
1637
 
1523
      // compute SHA-512 checksum and V1 checksum of startup block
1638
      // compute SHA-512 checksum and V1 checksum of startup block
1524
      blob_datasize = startuptrailer_offset - startupheader_offset;
1639
      blob_datasize = startuptrailer_offset - startupheader_offset;
1525
      blob_data = malloc (blob_datasize);
1640
      blob_data = malloc (blob_datasize);
Line 1530... Line 1645...
1530
      }
1645
      }
1531
      fseek (fp, startupheader_offset, SEEK_SET);
1646
      fseek (fp, startupheader_offset, SEEK_SET);
1532
      fread (blob_data, 1, blob_datasize, fp);
1647
      fread (blob_data, 1, blob_datasize, fp);
1533
      SHA512 (blob_data, blob_datasize, startup_trailer.sha512); // compute SHA512 checksum
1648
      SHA512 (blob_data, blob_datasize, startup_trailer.sha512); // compute SHA512 checksum
1534
      startup_trailer.cksum = 0; // compute old checksum
1649
      startup_trailer.cksum = 0; // compute old checksum
1535
      startup_trailer.cksum = update_checksum_int32s (startup_trailer.cksum, (const int32_t *) blob_data, blob_datasize);
1650
      startup_trailer.cksum = update_checksum32 (startup_trailer.cksum, (const uint32_t *) blob_data, blob_datasize);
1536
      startup_trailer.cksum = update_checksum_int32s (startup_trailer.cksum, (const int32_t *) startup_trailer.sha512, sizeof (startup_trailer.sha512));
1651
      startup_trailer.cksum = update_checksum32 (startup_trailer.cksum, (const uint32_t *) startup_trailer.sha512, sizeof (startup_trailer.sha512));
1537
      free (blob_data);
1652
      free (blob_data);
1538
 
1653
 
1539
      // rewrite startup trailer with final values
1654
      // rewrite startup trailer with final values
1540
      fseek (fp, startuptrailer_offset, SEEK_SET);
1655
      fseek (fp, startuptrailer_offset, SEEK_SET);
1541
      fwrite (&startup_trailer, sizeof (startup_trailer), 1, fp); // write startup trailer
1656
      fwrite (&startup_trailer, sizeof (startup_trailer), 1, fp); // write startup trailer
Line 1561... Line 1676...
1561
   }
1676
   }
1562
   fseek (fp, imgheader_offset, SEEK_SET);
1677
   fseek (fp, imgheader_offset, SEEK_SET);
1563
   fread (blob_data, 1, blob_datasize, fp);
1678
   fread (blob_data, 1, blob_datasize, fp);
1564
   SHA512 (blob_data, blob_datasize, image_trailer.sha512); // compute SHA512 checksum
1679
   SHA512 (blob_data, blob_datasize, image_trailer.sha512); // compute SHA512 checksum
1565
   image_trailer.cksum = 0; // compute old checksum
1680
   image_trailer.cksum = 0; // compute old checksum
1566
   image_trailer.cksum = update_checksum_int32s (image_trailer.cksum, (const int32_t *) blob_data, blob_datasize);
1681
   image_trailer.cksum = update_checksum32 (image_trailer.cksum, (const uint32_t *) blob_data, blob_datasize);
1567
   image_trailer.cksum = update_checksum_int32s (image_trailer.cksum, (const int32_t *) image_trailer.sha512, sizeof (image_trailer.sha512));
1682
   image_trailer.cksum = update_checksum32 (image_trailer.cksum, (const uint32_t *) image_trailer.sha512, sizeof (image_trailer.sha512));
1568
   free (blob_data);
1683
   free (blob_data);
1569
 
1684
 
1570
   // rewrite image trailer with final checksum values
1685
   // rewrite image trailer with final checksum values
1571
   fseek (fp, imgtrailer_offset, SEEK_SET);
1686
   fseek (fp, imgtrailer_offset, SEEK_SET);
1572
   fwrite (&image_trailer, sizeof (image_trailer), 1, fp); // write image trailer
1687
   fwrite (&image_trailer, sizeof (image_trailer), 1, fp); // write image trailer
1573
 
1688
 
1574
   // finished, close IFS file and exit with a success code
1689
   // finished, close IFS file and exit with a success code
1575
   fclose (fp);
1690
   fclose (fp);
1576
   fprintf (stdout, "Success\n");
1691
   fprintf (stdout, "Success\n");
1577
   exit (0);
1692
   exit (0);
-
 
1693
}
-
 
1694
 
-
 
1695
 
-
 
1696
static int dump_ifs_info (const char *ifs_pathname)
-
 
1697
{
-
 
1698
   #define hex_printf(buf,size,...) hex_fprintf (stdout, (buf), (size), 16, __VA_ARGS__) // use 16 columns in hex output to stdout
-
 
1699
   #define BINARY(x) binary ((x), '-', 'x')
-
 
1700
 
-
 
1701
   static const char *startupheader_flags1_strings[8] = {
-
 
1702
      "VIRTUAL", // bit 0
-
 
1703
      "BIGENDIAN", // bit 1
-
 
1704
      "COMPRESS_BIT1", // bit 2
-
 
1705
      "COMPRESS_BIT2", // bit 3
-
 
1706
      "COMPRESS_BIT3", // bit 4
-
 
1707
      "TRAILER_V2", // bit 5
-
 
1708
      "", // bit 6
-
 
1709
      "", // bit 7
-
 
1710
   };
-
 
1711
   static const char *imageheader_flags_strings[8] = {
-
 
1712
      "BIGENDIAN", // bit 0
-
 
1713
      "READONLY", // bit 1
-
 
1714
      "INO_BITS", // bit 2
-
 
1715
      "SORTED", // bit 3
-
 
1716
      "TRAILER_V2", // bit 4
-
 
1717
      "", // bit 5
-
 
1718
      "", // bit 6
-
 
1719
      "", // bit 7
-
 
1720
   };
-
 
1721
 
-
 
1722
   startup_header_t *startup_header = NULL;
-
 
1723
   startup_trailer_v1_t *startup_trailer_v1 = NULL;
-
 
1724
   startup_trailer_v2_t *startup_trailer_v2 = NULL;
-
 
1725
   image_header_t *image_header = NULL;
-
 
1726
   size_t imageheader_offset = 0;
-
 
1727
   image_trailer_v1_t *image_trailer_v1 = NULL;
-
 
1728
   image_trailer_v2_t *image_trailer_v2 = NULL;
-
 
1729
   fsentry_t *current_fsentry = NULL;
-
 
1730
   char recorded_sha512[2 * SHA512_DIGEST_LENGTH + 1] = "";
-
 
1731
   char computed_sha512[2 * SHA512_DIGEST_LENGTH + 1] = "";
-
 
1732
   size_t startupfile_blobsize = 0;
-
 
1733
   size_t bootfile_blobsize = 0;
-
 
1734
   size_t current_offset;
-
 
1735
   size_t byte_index;
-
 
1736
   uint32_t recorded_checksum;
-
 
1737
   uint32_t computed_checksum;
-
 
1738
   uint8_t *filedata;
-
 
1739
   size_t filesize;
-
 
1740
   time_t mtime;
-
 
1741
   FILE *fp;
-
 
1742
 
-
 
1743
   // open and read IFS file
-
 
1744
   fp = fopen (ifs_pathname, "rb");
-
 
1745
   if (fp == NULL)
-
 
1746
   {
-
 
1747
      fprintf (stderr, "error: can't open \"%s\" for reading: %s\n", ifs_pathname, strerror (errno));
-
 
1748
      return (1);
-
 
1749
   }
-
 
1750
   fseek (fp, 0, SEEK_END);
-
 
1751
   filesize = ftell (fp);
-
 
1752
   filedata = malloc (filesize);
-
 
1753
   if (filedata == NULL)
-
 
1754
   {
-
 
1755
      fprintf (stderr, "fatal error: out of memory\n");
-
 
1756
      exit (1);
-
 
1757
   }
-
 
1758
   fseek (fp, 0, SEEK_SET);
-
 
1759
   fread (filedata, 1, filesize, fp);
-
 
1760
   fclose (fp);
-
 
1761
 
-
 
1762
   printf ("IFS file \"%s\" - size 0x%zx (%zd) bytes\n", ifs_pathname, filesize, filesize);
-
 
1763
 
-
 
1764
   // parse file from start to end
-
 
1765
   current_offset = 0;
-
 
1766
   for (;;)
-
 
1767
   {
-
 
1768
      // does a startup header start here ?
-
 
1769
      if ((current_offset + sizeof (startup_header_t) < filesize) && (memcmp (&filedata[current_offset], "\xeb\x7e\xff\x00", 4) == 0))
-
 
1770
      {
-
 
1771
         startup_header = (startup_header_t *) &filedata[current_offset];
-
 
1772
 
-
 
1773
         // layout:
-
 
1774
         // [STARTUP HEADER]
-
 
1775
         // (startup file blob)
-
 
1776
         // [STARTUP TRAILER v1 or v2]
-
 
1777
 
-
 
1778
         printf ("\n");
-
 
1779
         printf ("Startup header at offset 0x%zx (%zd):\n", current_offset, current_offset);
-
 
1780
         printf ("   signature     = %02x %02x %02x %02x - good\n", startup_header->signature[0], startup_header->signature[1], startup_header->signature[2], startup_header->signature[3]);
-
 
1781
         printf ("   version       = 0x%04x (%d) - %s\n", startup_header->version, startup_header->version, (startup_header->version == 1 ? "looks good" : "???"));
-
 
1782
         printf ("   flags1        = 0x%02x (%s)\n", startup_header->flags1, describe_uint8 (startup_header->flags1, startupheader_flags1_strings));
-
 
1783
         printf ("   flags2        = 0x%02x (%s) - %s\n", startup_header->flags2, BINARY (startup_header->flags2), (startup_header->flags2 == 0 ? "looks good" : "???"));
-
 
1784
         printf ("   header_size   = 0x%04x (%d) - %s\n", startup_header->header_size, startup_header->header_size, (startup_header->header_size == sizeof (startup_header_t) ? "looks good" : "BAD"));
-
 
1785
         printf ("   machine       = 0x%04x (%d) - %s\n", startup_header->machine, startup_header->machine, (startup_header->machine == STARTUP_HDR_MACHINE_X86_64 ? "x86_64" : (startup_header->machine == STARTUP_HDR_MACHINE_AARCH64 ? "aarch64" : "unknown")));
-
 
1786
         printf ("   startup_vaddr = 0x%08x (%d) - virtual address to transfer to after IPL is done\n", startup_header->startup_vaddr, startup_header->startup_vaddr);
-
 
1787
         printf ("   paddr_bias    = 0x%08x (%d) - value to add to physical addresses to get an indirectable pointer value\n", startup_header->paddr_bias, startup_header->paddr_bias);
-
 
1788
         printf ("   image_paddr   = 0x%08x (%d) - physical address of image\n", startup_header->image_paddr, startup_header->image_paddr);
-
 
1789
         printf ("   ram_paddr     = 0x%08x (%d) - physical address of RAM to copy image to (startup_size bytes copied)\n", startup_header->ram_paddr, startup_header->ram_paddr);
-
 
1790
         printf ("   ram_size      = 0x%08x (%d) - amount of RAM used by the startup program and executables in the fs\n", startup_header->ram_size, startup_header->ram_size);
-
 
1791
         printf ("   startup_size  = 0x%08x (%d) - size of startup (never compressed) - %s\n", startup_header->startup_size, startup_header->startup_size, (current_offset + sizeof (image_header_t) + startup_header->startup_size + (startup_header->flags1 & STARTUP_HDR_FLAGS1_TRAILER_V2 ? sizeof (image_trailer_v2_t) : sizeof (image_trailer_v1_t)) < filesize ? "looks good" : "BAD (IFS file too short)"));
-
 
1792
         printf ("   stored_size   = 0x%08x (%d) - size of entire image - %s\n", startup_header->stored_size, startup_header->stored_size, (startup_header->stored_size == startup_header->ram_size ? "looks good" : "???"));
-
 
1793
         printf ("   imagefs_paddr = 0x%08x (%d) - set by IPL when startup runs - %s\n", startup_header->imagefs_paddr, startup_header->imagefs_paddr, (startup_header->imagefs_paddr == 0 ? "looks good" : "??? should be zero"));
-
 
1794
         printf ("   imagefs_size  = 0x%08x (%d) - size of uncompressed imagefs\n", startup_header->imagefs_size, startup_header->imagefs_size);
-
 
1795
         printf ("   preboot_size  = 0x%04x (%d) - size of loaded before header - %s\n", startup_header->preboot_size, startup_header->preboot_size, (startup_header->preboot_size == current_offset ? "looks good" : "???"));
-
 
1796
         printf ("   zero0         = 0x%04x (%d) - zeros - %s\n", startup_header->zero0, startup_header->zero0, (startup_header->zero0 == 0 ? "looks good" : "??? should be zero"));
-
 
1797
         printf ("   zero[0]       = 0x%08x (%d) - zeros - %s\n", startup_header->zero[0], startup_header->zero[0], (startup_header->zero[0] == 0 ? "looks good" : "??? should be zero"));
-
 
1798
         printf ("   addr_off      = 0x%016llx (%lld) - offset for startup_vaddr and [image|ram|imagefs]_paddr - %s\n", startup_header->addr_off, startup_header->addr_off, (startup_header->addr_off == 0 ? "looks good" : "??? should be zero"));
-
 
1799
         hex_printf ((uint8_t *) &startup_header->info[0], sizeof (startup_header->info), "   info[48] =\n");
-
 
1800
 
-
 
1801
         // validate that the file can contain up to the startup trailer
-
 
1802
         if (current_offset + startup_header->startup_size > filesize)
-
 
1803
         {
-
 
1804
            fprintf (stderr, "WARNING: this IFS file is too short (startup trailer would be past end of file)\n");
-
 
1805
            break;
-
 
1806
         }
-
 
1807
 
-
 
1808
         // locate the right startup trailer at the right offset
-
 
1809
         if (startup_header->flags1 & STARTUP_HDR_FLAGS1_TRAILER_V2)
-
 
1810
         {
-
 
1811
            startup_trailer_v2 = (startup_trailer_v2_t *) &filedata[current_offset + startup_header->startup_size - sizeof (startup_trailer_v2_t)];
-
 
1812
            startupfile_blobsize = startup_header->startup_size - sizeof (startup_header_t) - sizeof (startup_trailer_v2_t);
-
 
1813
         }
-
 
1814
         else // old V1 trailer
-
 
1815
         {
-
 
1816
            startup_trailer_v1 = (startup_trailer_v1_t *) &filedata[current_offset + startup_header->startup_size - sizeof (startup_trailer_v1_t)];
-
 
1817
            startupfile_blobsize = startup_header->startup_size - sizeof (startup_header_t) - sizeof (startup_trailer_v1_t);
-
 
1818
         }
-
 
1819
 
-
 
1820
         current_offset += sizeof (startup_header_t); // jump over the startup header and reach the startup blob
-
 
1821
         printf ("\n");
-
 
1822
         printf ("Startup blob at offset 0x%zx (%zd):\n", current_offset, current_offset);
-
 
1823
         printf ("   size 0x%zx (%zd) bytes\n", startupfile_blobsize, startupfile_blobsize);
-
 
1824
         printf ("   checksum %d\n", update_checksum32 (0, (uint32_t *) &filedata[current_offset], startupfile_blobsize));
-
 
1825
 
-
 
1826
         current_offset += startupfile_blobsize; // jump over the startup blob and reach the startup trailer
-
 
1827
         printf ("\n");
-
 
1828
         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));
-
 
1829
         if (startup_header->flags1 & STARTUP_HDR_FLAGS1_TRAILER_V2)
-
 
1830
         {
-
 
1831
            for (byte_index = 0; byte_index < SHA512_DIGEST_LENGTH; byte_index++)
-
 
1832
               sprintf (&recorded_sha512[2 * byte_index], "%02x", startup_trailer_v2->sha512[byte_index]);
-
 
1833
            strcpy (computed_sha512, SHA512 (startup_header, (size_t) ((uint8_t *) startup_trailer_v2 - (uint8_t *) startup_header), NULL));
-
 
1834
            recorded_checksum = startup_trailer_v2->cksum;
-
 
1835
            computed_checksum = update_checksum32 (0, (uint32_t *) startup_header, sizeof (startup_header) + startupfile_blobsize + SHA512_DIGEST_LENGTH);
-
 
1836
            printf ("    sha512 = %s - %s\n", recorded_sha512, (strcasecmp (computed_sha512, recorded_sha512) == 0 ? "GOOD" : "BAD"));
-
 
1837
            printf ("    cksum = 0x%08x (%d) - %s\n", recorded_checksum, recorded_checksum, (computed_checksum == recorded_checksum ? "GOOD" : "BAD"));
-
 
1838
            if (strcasecmp (computed_sha512, recorded_sha512) != 0)
-
 
1839
               printf ("Computed SHA-512: %s\n", computed_sha512);
-
 
1840
            if (computed_checksum != recorded_checksum)
-
 
1841
               printf ("Computed cksum: 0x%08x (%d)\n", computed_checksum, computed_checksum);
-
 
1842
         }
-
 
1843
         else // old v1 trailer
-
 
1844
         {
-
 
1845
            recorded_checksum = startup_trailer_v1->cksum;
-
 
1846
            computed_checksum = update_checksum32 (0, (uint32_t *) startup_header, sizeof (startup_header) + startupfile_blobsize);
-
 
1847
            printf ("    cksum = 0x%08x (%d) - %s\n", recorded_checksum, recorded_checksum, (computed_checksum == recorded_checksum ? "GOOD" : "BAD"));
-
 
1848
            if (computed_checksum != recorded_checksum)
-
 
1849
               printf ("Computed cksum: 0x%08x (%d)\n", computed_checksum, computed_checksum);
-
 
1850
         }
-
 
1851
 
-
 
1852
         current_offset += (startup_header->flags1 & STARTUP_HDR_FLAGS1_TRAILER_V2 ? sizeof (image_trailer_v2_t) : sizeof (image_trailer_v1_t)); // now reach the next segment
-
 
1853
      }
-
 
1854
 
-
 
1855
      // else does an image header start here ?
-
 
1856
      else if ((current_offset + sizeof (image_header_t) < filesize) && (memcmp (&filedata[current_offset], "imagefs", 7) == 0))
-
 
1857
      {
-
 
1858
         imageheader_offset = current_offset;
-
 
1859
         image_header = (image_header_t *) &filedata[imageheader_offset];
-
 
1860
 
-
 
1861
         // layout:
-
 
1862
         // [IMAGE HEADER]
-
 
1863
         // [image directory entries]
-
 
1864
         // [file blobs up to KERNEL]
-
 
1865
         // [padding]
-
 
1866
         // [KERNEL]
-
 
1867
         // [file blobs]
-
 
1868
         // [IMAGE FOOTER]
-
 
1869
 
-
 
1870
         printf ("\n");
-
 
1871
         printf ("Image header at offset %zx (%zd):\n", current_offset, current_offset);
-
 
1872
         printf ("   signature    = %02x %02x %02x %02x %02x %02x %02x (\"%.7s\") - good\n", image_header->signature[0], image_header->signature[1], image_header->signature[2], image_header->signature[3], image_header->signature[4], image_header->signature[5], image_header->signature[6], image_header->signature);
-
 
1873
         printf ("   flags        = 0x%02x (%s)\n", image_header->flags, describe_uint8 (image_header->flags, imageheader_flags_strings));
-
 
1874
         printf ("   image_size   = 0x%08x (%d) - size from header to end of trailer - %s\n", image_header->image_size, image_header->image_size, (current_offset + image_header->image_size <= filesize ? "looks good" : "BAD (IFS file too short)"));
-
 
1875
         printf ("   hdr_dir_size = 0x%08x (%d) - size from header to last dirent - %s\n", image_header->hdr_dir_size, image_header->hdr_dir_size, (current_offset + image_header->hdr_dir_size < filesize ? "looks good" : "BAD (IFS file too short)"));
-
 
1876
         printf ("   dir_offset   = 0x%08x (%d) - offset from header to first dirent - %s\n", image_header->dir_offset, image_header->dir_offset, (current_offset + image_header->dir_offset >= filesize ? "BAD (IFS file too short)" : (image_header->dir_offset > image_header->hdr_dir_size ? "BAD" : "looks good")));
-
 
1877
         printf ("   boot_ino[4]  = { 0x%08x, 0x%08x, 0x%08x, 0x%08x }\n", image_header->boot_ino[0], image_header->boot_ino[1], image_header->boot_ino[2], image_header->boot_ino[3]);
-
 
1878
         printf ("   script_ino   = 0x%08x (%d) - inode of compiled bootscript\n", image_header->script_ino, image_header->script_ino);
-
 
1879
         printf ("   chain_paddr  = 0x%08x (%d) - offset to next fs signature\n", image_header->chain_paddr, image_header->chain_paddr);
-
 
1880
         hex_printf ((uint8_t *) &image_header->spare[0], sizeof (image_header->spare), "   spare[10] =\n");
-
 
1881
         printf ("   mountflags   = 0x%08x (%s %s %s %s)\n", image_header->mountflags, BINARY (((uint8_t *) &image_header->mountflags)[0]), BINARY (((uint8_t *) &image_header->mountflags)[1]), BINARY (((uint8_t *) &image_header->mountflags)[2]), BINARY (((uint8_t *) &image_header->mountflags)[3]));
-
 
1882
         printf ("   mountpoint   = \"%s\"\n", image_header->mountpoint);
-
 
1883
 
-
 
1884
         // validate that the file can contain up to the image trailer
-
 
1885
         if (current_offset + image_header->image_size > filesize)
-
 
1886
         {
-
 
1887
            fprintf (stderr, "WARNING: this IFS file is too short (image trailer would be past end of file)\n");
-
 
1888
            break;
-
 
1889
         }
-
 
1890
 
-
 
1891
         // locate the image trailer at the right offset
-
 
1892
         if (image_header->flags & IMAGE_FLAGS_TRAILER_V2)
-
 
1893
            image_trailer_v2 = (image_trailer_v2_t *) &filedata[current_offset + image_header->image_size - sizeof (image_trailer_v2_t)];
-
 
1894
         else // old V1 trailer
-
 
1895
            image_trailer_v1 = (image_trailer_v1_t *) &filedata[current_offset + image_header->image_size - sizeof (image_trailer_v1_t)];
-
 
1896
 
-
 
1897
         current_offset += sizeof (image_header_t); // jump over the image header and reach the first directory entry
-
 
1898
         if (image_header->dir_offset - sizeof (image_header_t) > 0)
-
 
1899
         {
-
 
1900
            hex_printf (&filedata[current_offset], image_header->dir_offset - sizeof (image_header_t), "\n%d extra bytes at offset 0x%zd (%zd):\n", image_header->dir_offset - sizeof (image_header_t), current_offset, current_offset);
-
 
1901
            current_offset += image_header->dir_offset - sizeof (image_header_t);
-
 
1902
         }
-
 
1903
 
-
 
1904
         // dump all directory entries until the last one included
-
 
1905
         while (&filedata[current_offset] < (uint8_t *) image_header + image_header->hdr_dir_size)
-
 
1906
         {
-
 
1907
            current_fsentry = (fsentry_t *) &filedata[current_offset];
-
 
1908
 
-
 
1909
            if (imageheader_offset + image_header->hdr_dir_size - current_offset < sizeof (current_fsentry->header))
-
 
1910
               break; // end padding reached
-
 
1911
 
-
 
1912
            printf ("\n");
-
 
1913
            printf ("Filesystem entry at offset 0x%zx (%zd) - last one at 0x%zd (%zd):\n", current_offset, current_offset, imageheader_offset + image_header->hdr_dir_size, imageheader_offset + image_header->hdr_dir_size);
-
 
1914
            printf ("   size           = 0x%04x (%d) - size of dirent - %s\n", current_fsentry->header.size, current_fsentry->header.size, (current_offset + current_fsentry->header.size < filesize ? "looks good" : "BAD"));
-
 
1915
            printf ("   extattr_offset = 0x%04x (%d) - %s\n", current_fsentry->header.extattr_offset, current_fsentry->header.extattr_offset, (current_fsentry->header.extattr_offset == 0 ? "no extattr" : "has extattr"));
-
 
1916
            printf ("   ino            = 0x%08x (%d) - inode number (%s%s%s%s)\n", current_fsentry->header.ino, current_fsentry->header.ino, (current_fsentry->header.ino & 0xE0000000 ? "is" : "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" : ""));
-
 
1917
            printf ("   mode           = 0x%08x (%d) - %s (0%o), POSIX permissions 0%o\n", current_fsentry->header.mode, current_fsentry->header.mode, (S_ISDIR (current_fsentry->header.mode) ? "directory" : (S_ISREG (current_fsentry->header.mode) ? "file" : (S_ISLNK (current_fsentry->header.mode) ? "symlink" : "device"))), (current_fsentry->header.mode & 0xF000) >> 12, current_fsentry->header.mode & 0xFFF);
-
 
1918
            printf ("   gid            = 0x%08x (%d) - owner group ID%s\n", current_fsentry->header.gid, current_fsentry->header.gid, (current_fsentry->header.gid == 0 ? " (root)" : ""));
-
 
1919
            printf ("   uid            = 0x%08x (%d) - owner user ID%s\n", current_fsentry->header.uid, current_fsentry->header.uid, (current_fsentry->header.uid == 0 ? " (root)" : ""));
-
 
1920
            mtime = (time_t) current_fsentry->header.mtime;
-
 
1921
            printf ("   mtime          = 0x%08x (%d) - POSIX timestamp: %s", current_fsentry->header.mtime, current_fsentry->header.mtime, asctime (localtime (&mtime))); // NOTE: asctime() provides the newline
-
 
1922
            if (S_ISDIR (current_fsentry->header.mode))
-
 
1923
               printf ("   [DIRECTORY] path = \"%s\"\n", (char *) &current_fsentry->u.dir.path); // convert from pointer to char array
-
 
1924
            else if (S_ISREG (current_fsentry->header.mode))
-
 
1925
            {
-
 
1926
               printf ("   [FILE] offset = 0x%08x (%d) - %s\n", current_fsentry->u.file.offset, current_fsentry->u.file.offset, (imageheader_offset + current_fsentry->u.file.offset < filesize ? "looks good" : "BAD (IFS file too short)"));
-
 
1927
               printf ("   [FILE] size   = 0x%08x (%d) - %s\n", current_fsentry->u.file.offset, current_fsentry->u.file.offset, (imageheader_offset + current_fsentry->u.file.offset + current_fsentry->u.file.size < filesize ? "looks good" : "BAD (IFS file too short)"));
-
 
1928
               printf ("   [FILE] path   = \"%s\"\n", (char *) &current_fsentry->u.file.path); // convert from pointer to char array
-
 
1929
            }
-
 
1930
            else if (S_ISLNK (current_fsentry->header.mode))
-
 
1931
            {
-
 
1932
               printf ("   [SYMLINK] sym_offset = 0x%04x (%d) - %s\n", current_fsentry->u.symlink.sym_offset, current_fsentry->u.symlink.sym_offset, (sizeof (current_fsentry->header) + 2 * sizeof (uint16_t) + current_fsentry->u.symlink.sym_offset <= current_fsentry->header.size ? "looks good" : "BAD (dirent too short)"));
-
 
1933
               printf ("   [SYMLINK] sym_size   = 0x%04x (%d) - %s\n", current_fsentry->u.symlink.sym_offset, current_fsentry->u.symlink.sym_offset, (sizeof (current_fsentry->header) + 2 * sizeof (uint16_t) + current_fsentry->u.symlink.sym_offset + current_fsentry->u.symlink.sym_size <= current_fsentry->header.size ? "looks good" : "BAD (dirent too short)"));
-
 
1934
               printf ("   [SYMLINK] path       = \"%s\"\n", (char *) &current_fsentry->u.symlink.path); // convert from pointer to char array
-
 
1935
               printf ("   [SYMLINK] contents   = \"%s\"\n", ((char *) &current_fsentry->u.symlink.path) + current_fsentry->u.symlink.sym_offset); // convert from pointer to char array
-
 
1936
            }
-
 
1937
            else // can only be a device
-
 
1938
            {
-
 
1939
               printf ("   [DEVICE] dev  = 0x%08x (%d)\n", current_fsentry->u.device.dev, current_fsentry->u.device.dev);
-
 
1940
               printf ("   [DEVICE] rdev = 0x%08x (%d)\n", current_fsentry->u.device.rdev, current_fsentry->u.device.rdev);
-
 
1941
               printf ("   [DEVICE] path = \"%s\"\n", (char *) &current_fsentry->u.device.path); // convert from pointer to char array
-
 
1942
            }
-
 
1943
 
-
 
1944
            current_offset += current_fsentry->header.size;
-
 
1945
         }
-
 
1946
         if (imageheader_offset + image_header->hdr_dir_size - current_offset < sizeof (current_fsentry->header))
-
 
1947
            hex_printf (&filedata[current_offset], imageheader_offset + image_header->hdr_dir_size - current_offset, "\n%d padding bytes at offset 0x%zx (%zd):\n", imageheader_offset + image_header->hdr_dir_size - current_offset, current_offset, current_offset);
-
 
1948
 
-
 
1949
 
-
 
1950
            // now jump at the first
-
 
1951
 
-
 
1952
         exit (0);
-
 
1953
      }
-
 
1954
 
-
 
1955
      // else it has to be a boot blob, of which we don't know the size, except that it has to fit in 0xffff bytes and be immediately followed by a startup header
-
 
1956
      else
-
 
1957
      {
-
 
1958
         // so scan for the first startup header magic and version (which makes us 6 bytes to scan for, i.e. "\xeb\x7e\xff\x00" for the magic and "\x01\x00" (LSB) for the version 1)
-
 
1959
         for (byte_index = current_offset; byte_index < filesize - 6; byte_index++)
-
 
1960
            if (memcmp (&filedata[byte_index], "\xeb\x7e\xff\x00" "\x01\x00", 4 + 2) == 0)
-
 
1961
               break; // stop as soon as we find it
-
 
1962
 
-
 
1963
         if (byte_index >= filesize - 6)
-
 
1964
            break; // if not found, stop scanning
-
 
1965
 
-
 
1966
         bootfile_blobsize = byte_index - current_offset;
-
 
1967
         printf ("Boot blob at offset 0x%zx (%zd):\n", current_offset, current_offset);
-
 
1968
         printf ("   size 0x%zx (%zd) bytes\n", bootfile_blobsize, bootfile_blobsize);
-
 
1969
         printf ("   checksum %d\n", update_checksum32 (0, (uint32_t *) &filedata[current_offset], bootfile_blobsize));
-
 
1970
 
-
 
1971
         current_offset = byte_index; // now reach the next segment
-
 
1972
      }
-
 
1973
   }
-
 
1974
 
-
 
1975
   printf ("End of identifiable data reached.\n");
-
 
1976
   if (current_offset < filesize)
-
 
1977
      hex_printf (&filedata[current_offset], filesize - current_offset, "\n%d extra bytes at offset %zx (%zd):\n", filesize - current_offset, current_offset, current_offset);
-
 
1978
   printf ("End of file reached at offset 0x%zx (%zd).\n", filesize, filesize);
-
 
1979
 
-
 
1980
   return (0);
1578
}
1981
}