Rev 19 | Rev 21 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
| Rev 19 | Rev 20 | ||
|---|---|---|---|
| Line 19... | Line 19... | ||
| 19 | #include <time.h> | 
            19 | #include <time.h> | 
          
| 20 | 20 | ||
| 21 | // platform-specific includes | 
            21 | // platform-specific includes | 
          
| 22 | #ifdef _MSC_VER | 
            22 | #ifdef _MSC_VER | 
          
| 23 | #include <sys/utime.h> | 
            23 | #include <sys/utime.h> | 
          
| - | 24 | #include <process.h> | 
          |
| 24 | #else // !_MSC_VER | 
            25 | #else // !_MSC_VER | 
          
| 25 | #include <sys/param.h> | 
            26 | #include <sys/param.h> | 
          
| 26 | #include <sys/sysmacros.h> | 
            27 | #include <sys/sysmacros.h> | 
          
| - | 28 | #include <sys/wait.h> | 
          |
| 27 | #include <unistd.h> | 
            29 | #include <unistd.h> | 
          
| 28 | #include <dirent.h> | 
            30 | #include <dirent.h> | 
          
| 29 | #include <utime.h> | 
            31 | #include <utime.h> | 
          
| 30 | #endif // _MSC_VER | 
            32 | #endif // _MSC_VER | 
          
| 31 | 33 | ||
| Line 88... | Line 90... | ||
| 88 | bool should_follow_symlinks; // follow symlinks  | 
            90 | bool should_follow_symlinks; // follow symlinks  | 
          
| 89 | bool should_autosymlink_dylib; // dynamic libraries should be written under their official SONAME and a named symlink be created pointing at them  | 
            91 | bool should_autosymlink_dylib; // dynamic libraries should be written under their official SONAME and a named symlink be created pointing at them  | 
          
| 90 | bool should_keep_ld_output; // whether to keep .sym files produced by ld calls, togglable by the [+keeplinked] attribute  | 
            92 | bool should_keep_ld_output; // whether to keep .sym files produced by ld calls, togglable by the [+keeplinked] attribute  | 
          
| 91 | bool should_ignore_duplicates; // [+|-dupignore] whether to ignore duplicates  | 
            93 | bool should_ignore_duplicates; // [+|-dupignore] whether to ignore duplicates  | 
          
| 92 | bool should_allow_nonexistent_files; // [+|-optional] whether to continue processing on unexistent files  | 
            94 | bool should_allow_nonexistent_files; // [+|-optional] whether to continue processing on unexistent files  | 
          
| - | 95 | bool is_bootstrap_file; // entry has the [virtual] attribute  | 
          |
| 93 | bool is_compiled_bootscript; // entry has [+script] attribute  | 
            96 | bool is_compiled_bootscript; // entry has [+script] attribute  | 
          
| 94 | int extra_ino_flags; // bitmap of extra inode flags (IFS_INO_xxx)  | 
            97 | int extra_ino_flags; // bitmap of extra inode flags (IFS_INO_xxx)  | 
          
| 95 | char *search; // [search=path[:path]] binary search path (the default one will be constructed at startup)  | 
            98 | char *search; // [search=path[:path]] binary search path (the default one will be constructed at startup)  | 
          
| 96 | 99 | ||
| 97 | 100 | ||
| Line 133... | Line 136... | ||
| 133 | // bootable IFS support | 
            136 | // bootable IFS support | 
          
| 134 | static char *bootfile_pathname = NULL; // HACK: pathname to bootcode binary blob file to put at the start of a bootable IFS  | 
            137 | static char *bootfile_pathname = NULL; // HACK: pathname to bootcode binary blob file to put at the start of a bootable IFS  | 
          
| 135 | static size_t bootfile_size = 0; // HACK: size of the bootcode binary blob file to put at the start of a bootable IFS  | 
            138 | static size_t bootfile_size = 0; // HACK: size of the bootcode binary blob file to put at the start of a bootable IFS  | 
          
| 136 | static char *startupfile_pathname = NULL; // HACK: pathname to precompiled startup file blob to put in the startup header of a bootable IFS  | 
            139 | static char *startupfile_pathname = NULL; // HACK: pathname to precompiled startup file blob to put in the startup header of a bootable IFS  | 
          
| 137 | static size_t startupfile_ep_from_imagebase = 0; // HACK: startup code entrypoint offset from image base for a bootable IFS  | 
            140 | static size_t startupfile_ep_from_imagebase = 0; // HACK: startup code entrypoint offset from image base for a bootable IFS  | 
          
| 138 | static char *kernelfile_pathname = NULL; // HACK: pathname to precompiled kernel file blob to put in a bootable IFS  | 
            - | |
| 139 | static size_t kernelfile_offset =  | 
            141 | static size_t kernelfile_offset = 0x32000; // kernel file offset in the IFS (is it ever supposed to change)  | 
          
| 140 | 142 | ||
| 141 | 143 | ||
| 142 | // exported function prototypes | 
            144 | // exported function prototypes | 
          
| 143 | int32_t update_checksum (const void *data, const size_t data_len, const bool is_foreign_endianness); // compute an IFS image or startup checksum to store in the trailer  | 
            145 | int32_t update_checksum (const void *data, const size_t data_len, const bool is_foreign_endianness); // compute an IFS image or startup checksum to store in the trailer  | 
          
| 144 | 146 | ||
| Line 146... | Line 148... | ||
| 146 | // prototypes of local functions | 
            148 | // prototypes of local functions | 
          
| 147 | 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)  | 
            149 | 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)  | 
          
| 148 | static char *resolve_pathname (const char *pathname, const char *search_paths_or_NULL_for_MKIFS_PATH_envvar); // locates pathname among the known search paths and returns a pointer to the resolved pathname (static string)  | 
            150 | static char *resolve_pathname (const char *pathname, const char *search_paths_or_NULL_for_MKIFS_PATH_envvar); // locates pathname among the known search paths and returns a pointer to the resolved pathname (static string)  | 
          
| 149 | static elf_section_header_t *elf_get_section_header_by_name (const elf_header_t *elf, const char *section_name); // get a pointer to a named section header in an ELF file  | 
            151 | static elf_section_header_t *elf_get_section_header_by_name (const elf_header_t *elf, const char *section_name); // get a pointer to a named section header in an ELF file  | 
          
| 150 | static size_t Buffer_WriteIFSDirectoryEntryAt (buffer_t *ifs_data, const size_t write_offset, const fsentry_t *fsentry); // writes the given filesystem entry (without its contents) to the IFS buffer  | 
            152 | static size_t Buffer_WriteIFSDirectoryEntryAt (buffer_t *ifs_data, const size_t write_offset, const fsentry_t *fsentry); // writes the given filesystem entry (without its contents) to the IFS buffer  | 
          
| 151 | static size_t Buffer_AppendIFSFileData (buffer_t *ifs_data, fsentry_t *fsentry); // writes the given filesystem entry's file data (i.e. its contents) to the IFS buffer  | 
            153 | static size_t Buffer_AppendIFSFileData (buffer_t *ifs_data, const fsentry_t *fsentry); // writes the given filesystem entry's file data (i.e. its contents) to the IFS buffer  | 
          
| 152 | static int Buffer_StripELFFile (buffer_t *file, const char **saved_sections, const size_t saved_section_count, const char *indicative_pathname); // strips an ELF file buffer the way mkifs does it and returns whether it succeeded  | 
            154 | static int Buffer_StripELFFile (buffer_t *file, const char **saved_sections, const size_t saved_section_count, const bool should_align_segsize_with_ramsize, const char *indicative_pathname); // strips an ELF file buffer the way mkifs does it and returns whether it succeeded  | 
          
| 153 | static void add_fsentry (fsentry_t **fsentries, size_t *fsentry_count, parms_t *entry_parms, const char *stored_pathname, const char *buildhost_pathname); // stack up a new filesystem entry in the the fsentries array  | 
            155 | static void add_fsentry (fsentry_t **fsentries, size_t *fsentry_count, parms_t *entry_parms, const char *stored_pathname, const char *buildhost_pathname); // stack up a new filesystem entry in the the fsentries array  | 
          
| 154 | static void add_directory_contents_recursively (fsentry_t **fsentries, size_t *fsentry_count, const char *dir_pathname, const size_t start_pathname_len, parms_t *default_parms); // adds the contents of the directory pointed to by dir_pathname to the fsentries array, recursively  | 
            156 | static void add_directory_contents_recursively (fsentry_t **fsentries, size_t *fsentry_count, const char *dir_pathname, const size_t start_pathname_len, parms_t *default_parms); // adds the contents of the directory pointed to by dir_pathname to the fsentries array, recursively  | 
          
| 155 | static int fsentry_compare_pathnames_cb (const void *a, const void *b); // qsort() comparison callback that sorts filesystem entries by pathnames  | 
            157 | static int fsentry_compare_pathnames_cb (const void *a, const void *b); // qsort() comparison callback that sorts filesystem entries by pathnames  | 
          
| 156 | static void parse_line (FILE *buildfile_fp, char *line_buffer, fsentry_t **fsentries, size_t *fsentry_count, parms_t *default_parms); // parses a line in the build file and make the relevant changes to the fsentries array  | 
            158 | static void parse_line (FILE *buildfile_fp, char *line_buffer, fsentry_t **fsentries, size_t *fsentry_count, parms_t *default_parms); // parses a line in the build file and make the relevant changes to the fsentries array  | 
          
| 157 | 159 | ||
| Line 448... | Line 450... | ||
| 448 | 450 | ||
| 449 | return (count);  | 
            451 | return (count);  | 
          
| 450 | } | 
            452 | } | 
          
| 451 | 453 | ||
| 452 | 454 | ||
| 453 | static size_t Buffer_AppendIFSFileData (buffer_t *ifs_data, fsentry_t *fsentry)  | 
            455 | static size_t Buffer_AppendIFSFileData (buffer_t *ifs_data, const fsentry_t *fsentry)  | 
          
| 454 | { | 
            456 | { | 
          
| 455 |    // writes the given filesystem entry's file data (i.e. its contents) to the IFS buffer | 
            457 |    // writes the given filesystem entry's file data (i.e. its contents) to the IFS buffer | 
          
| 456 | 458 | ||
| 457 | elf_program_header_t *phdr;  | 
            459 | elf_program_header_t *phdr;  | 
          
| 458 | elf_header_t *elf;  | 
            460 | elf_header_t *elf;  | 
          
| 459 | size_t fixed_physical_addr;  | 
            461 | size_t fixed_physical_addr;  | 
          
| 460 | size_t corrective_offset;  | 
            462 | size_t corrective_offset;  | 
          
| 461 |    //size_t segment_type; | 
            463 |    //size_t segment_type; | 
          
| 462 | size_t  | 
            464 | size_t size_in_memory;  | 
          
| 463 | size_t table_index;  | 
            465 | size_t table_index;  | 
          
| 464 | size_t table_count;  | 
            466 | size_t table_count;  | 
          
| 465 | size_t data_offset;  | 
            467 | size_t data_offset;  | 
          
| 466 | 468 | ||
| 467 | ASSERT (S_ISREG (fsentry->header.mode), "function called for invalid dirent"); // consistency check  | 
            469 | ASSERT (S_ISREG (fsentry->header.mode), "function called for invalid dirent"); // consistency check  | 
          
| 468 | data_offset = ifs_data->size; // see where we are  | 
            470 | data_offset = ifs_data->size; // see where we are  | 
          
| 469 | 471 | ||
| 470 |    // is the file we're storing a preprocessed ELF file ? | 
            472 |    // is the file we're storing a preprocessed ELF file ? | 
          
| 471 | if  | 
            473 | if (fsentry->header.ino & IFS_INO_PROCESSED_ELF)  | 
          
| 472 | #ifndef PROCNTO_WIP | 
            - | |
| 473 | && (strstr (fsentry->u.file.path, "/procnto-smp-instr") == NULL)  | 
            - | |
| 474 | #endif // !PROCNTO_WIP | 
            - | |
| 475 |        ) | 
            - | |
| 476 |    { | 
            474 |    { | 
          
| 477 | 475 | ||
| 478 | elf = (elf_header_t *) fsentry->u.file.UNSAVED_databuf; // quick access to ELF header  | 
            476 | elf = (elf_header_t *) fsentry->u.file.UNSAVED_databuf; // quick access to ELF header  | 
          
| 479 | table_count = ELF_GET_NUMERIC (elf, elf, program_header_table_len); // get the number of program headers  | 
            477 | table_count = ELF_GET_NUMERIC (elf, elf, program_header_table_len); // get the number of program headers  | 
          
| 480 | for (table_index = 0; table_index < table_count; table_index++)  | 
            478 | for (table_index = 0; table_index < table_count; table_index++)  | 
          
| Line 484... | Line 482... | ||
| 484 |          //if (!((segment_type >= 2) && (segment_type <= 7) || ((segment_type >= 0x6474e550) && (segment_type <= 0x6474e552)) || (segment_type == 0x70000001))) | 
            482 |          //if (!((segment_type >= 2) && (segment_type <= 7) || ((segment_type >= 0x6474e550) && (segment_type <= 0x6474e552)) || (segment_type == 0x70000001))) | 
          
| 485 |          //   continue; // NOTE: only certain segments types must be corrected | 
            483 |          //   continue; // NOTE: only certain segments types must be corrected | 
          
| 486 | 484 | ||
| 487 | 485 | ||
| 488 | corrective_offset = ELF_GET_NUMERIC (elf, phdr, virtual_addr) - ELF_GET_NUMERIC (elf, phdr, file_offset);  | 
            486 | corrective_offset = ELF_GET_NUMERIC (elf, phdr, virtual_addr) - ELF_GET_NUMERIC (elf, phdr, file_offset);  | 
          
| 489 | 
  | 
            487 | size_in_memory = ELF_GET_NUMERIC (elf, phdr, size_in_memory); // get this ELF segment's occupied size in memory  | 
          
| 490 | if (  | 
            488 | if (size_in_memory != 0) // only patch the physical address of segments that have an actual size in memory  | 
          
| 491 |          { | 
            489 |          { | 
          
| 492 | fixed_physical_addr = ELF_GET_NUMERIC (elf, phdr, physical_addr) + image_base + data_offset - corrective_offset;  | 
            490 | fixed_physical_addr = ELF_GET_NUMERIC (elf, phdr, physical_addr) + image_base + data_offset - corrective_offset;  | 
          
| 493 | ELF_SET_NUMERIC (elf, phdr, physical_addr, fixed_physical_addr); // patch the physical address member of the program header table (NOTE: data_offset is the location where the file data is about to be written)  | 
            491 | ELF_SET_NUMERIC (elf, phdr, physical_addr, fixed_physical_addr); // patch the physical address member of the program header table (NOTE: data_offset is the location where the file data is about to be written)  | 
          
| 494 |          } | 
            492 |          } | 
          
| 495 |       } | 
            493 |       } | 
          
| Line 514... | Line 512... | ||
| 514 |    } | 
            512 |    } | 
          
| 515 | return (Buffer_OffsetOf (buffer, occurrence)); // can't fail  | 
            513 | return (Buffer_OffsetOf (buffer, occurrence)); // can't fail  | 
          
| 516 | } | 
            514 | } | 
          
| 517 | 515 | ||
| 518 | 516 | ||
| 519 | static int Buffer_StripELFFile (buffer_t *file, const char **saved_sections, const size_t saved_section_count, const char *indicative_pathname)  | 
            517 | static int Buffer_StripELFFile (buffer_t *file, const char **saved_sections, const size_t saved_section_count, const bool should_align_segsize_with_ramsize, const char *indicative_pathname)  | 
          
| 520 | { | 
            518 | { | 
          
| 521 |    // NOTE: for each ELF file, mkifs | 
            519 |    // NOTE: for each ELF file, mkifs | 
          
| 522 |    // -> alters the program header table and offsets each p_addr (physical address) member by <image_base> plus the current file offset (this cannot be done right now, will need to be done once they are known) | 
            520 |    // -> alters the program header table and offsets each p_addr (physical address) member by <image_base> plus the current file offset (this cannot be done right now, will need to be done once they are known) | 
          
| 523 |    // -> throws away and reconstructs the sections table by keeping only the sections that are in the program header, and writes the section table at the start of the first thrown-away section | 
            521 |    // -> throws away and reconstructs the sections table by keeping only the sections that are in the program header, and writes the section table at the start of the first thrown-away section | 
          
| 524 |    // FIXME: what if a thrown away section is located between two program segments ? are they collapsed, moving the segments beyond it one slot down ? | 
            522 |    // FIXME: what if a thrown away section is located between two program segments ? are they collapsed, moving the segments beyond it one slot down ? | 
          
| Line 569... | Line 567... | ||
| 569 | const char *name;  | 
            567 | const char *name;  | 
          
| 570 |       elf_section_header_t header; | 
            568 |       elf_section_header_t header; | 
          
| 571 |       buffer_t data; | 
            569 |       buffer_t data; | 
          
| 572 | } elf_section_t;  | 
            570 | } elf_section_t;  | 
          
| 573 | 571 | ||
| 574 | const elf_program_header_t *phdr;  | 
            - | |
| 575 | const elf_section_header_t *shdr;  | 
            572 | const elf_section_header_t *shdr;  | 
          
| - | 573 | elf_program_header_t *phdr;  | 
          |
| - | 574 | elf_program_header_t *other_phdr;  | 
          |
| 576 | elf_section_t *elf_sections = NULL; // mallocated  | 
            575 | elf_section_t *elf_sections = NULL; // mallocated  | 
          
| 577 | elf_section_t *elf_section = NULL;  | 
            576 | elf_section_t *elf_section = NULL;  | 
          
| 578 | size_t elf_section_count = 0;  | 
            577 | size_t elf_section_count = 0;  | 
          
| 579 | size_t new_shdrtable_offset;  | 
            578 | size_t new_shdrtable_offset;  | 
          
| 580 | size_t new_shdrtable_len;  | 
            579 | size_t new_shdrtable_len;  | 
          
| 581 | size_t sectiondata_start;  | 
            580 | size_t sectiondata_start;  | 
          
| 582 | size_t sectiondata_size;  | 
            581 | size_t sectiondata_size;  | 
          
| - | 582 | size_t size_in_memory;  | 
          |
| - | 583 | size_t size_in_file;  | 
          |
| - | 584 | size_t file_offset;  | 
          |
| 583 | size_t array_index;  | 
            585 | size_t array_index;  | 
          
| 584 | size_t table_index;  | 
            586 | size_t table_index;  | 
          
| 585 | size_t table_count;  | 
            587 | size_t table_count;  | 
          
| 586 | size_t page_size;  | 
            588 | size_t page_size;  | 
          
| 587 | 589 | ||
| Line 594... | Line 596... | ||
| 594 |    { | 
            596 |    { | 
          
| 595 | errno = ENOTSUP; // unsupported architecture: set errno to something meaningful  | 
            597 | errno = ENOTSUP; // unsupported architecture: set errno to something meaningful  | 
          
| 596 | return (0); // and return an error value  | 
            598 | return (0); // and return an error value  | 
          
| 597 |    } | 
            599 |    } | 
          
| 598 | 600 | ||
| 599 |    //  | 
            601 |    // if we should align the segment sizes in the ELF file with their occupied memory size (such is the case for e.g. procnto), do that first | 
          
| - | 602 | table_count = ELF_GET_NUMERIC (ELFHDR, ELFHDR, program_header_table_len); // get the number of program headers  | 
          |
| - | 603 | for (table_index = 0; table_index < table_count; table_index++)  | 
          |
| - | 604 |    { | 
          |
| - | 605 | phdr = (elf_program_header_t *) &file->bytes[ELF_GET_NUMERIC (ELFHDR, ELFHDR, program_header_table_offset) + (size_t) ELF_GET_NUMERIC (ELFHDR, ELFHDR, program_header_item_size) * table_index]; // quick access to program header  | 
          |
| - | 606 | file_offset = ELF_GET_NUMERIC (ELFHDR, phdr, file_offset); // get this ELF segment's start offset in the ELF file  | 
          |
| - | 607 | size_in_memory = ELF_GET_NUMERIC (ELFHDR, phdr, size_in_memory); // get this ELF segment's occupied size in memory  | 
          |
| - | 608 | size_in_file = ELF_GET_NUMERIC (ELFHDR, phdr, size_in_file); // get this ELF segment's occupied size in the ELF file  | 
          |
| - | 609 | if (should_align_segsize_with_ramsize && (size_in_memory != size_in_file)) // should we align this segment's file size with its claimed RAM size ? (such is the case for e.g. procnto)  | 
          |
| - | 610 |       { | 
          |
| - | 611 | if (size_in_memory > size_in_file) // is it bigger ? if so, make sure we won't be overwriting other segments beyond this one  | 
          |
| - | 612 |          { | 
          |
| - | 613 | for (array_index = 0; array_index < table_count; array_index++)  | 
          |
| - | 614 |             { | 
          |
| - | 615 | other_phdr = (elf_program_header_t *) &file->bytes[ELF_GET_NUMERIC (ELFHDR, ELFHDR, program_header_table_offset) + (size_t) ELF_GET_NUMERIC (ELFHDR, ELFHDR, program_header_item_size) * array_index]; // quick access to program header  | 
          |
| - | 616 | if (other_phdr == phdr)  | 
          |
| - | 617 | continue; // skip self  | 
          |
| - | 618 | if (ELF_GET_NUMERIC (ELFHDR, other_phdr, file_offset) + ELF_GET_NUMERIC (ELFHDR, other_phdr, size_in_file) < file_offset)  | 
          |
| - | 619 | continue; // skip segments that are located before this one  | 
          |
| - | 620 | if (ELF_GET_NUMERIC (ELFHDR, other_phdr, file_offset) > file_offset + size_in_memory)  | 
          |
| - | 621 | continue; // skip segments that are located after this one, including its corrected size  | 
          |
| - | 622 | DIE_WITH_EXITCODE (1, "remapping ELF segment would overwrite segment #%zd in the same file", array_index);  | 
          |
| - | 623 |             } | 
          |
| - | 624 | ||
| - | 625 |             // finally, memset() the extra area | 
          |
| - | 626 | Buffer_WriteAt (file, file_offset + size_in_memory, NULL, 0); // reallocate the ELF file data buffer if necessary  | 
          |
| - | 627 | memset (&file->bytes[file_offset + size_in_file], 0, size_in_memory - size_in_file); // and write zeroes over the extra space  | 
          |
| - | 628 |          } | 
          |
| - | 629 | ELF_SET_NUMERIC (ELFHDR, phdr, size_in_file, size_in_memory); // patch this segment's size in the ELF file so that it matches the RAM size  | 
          |
| - | 630 |       } | 
          |
| - | 631 |    } | 
          |
| 600 | 632 | ||
| - | 633 |    // now parse the program header table, and measure the farthest offset known by this table where we'll write the reconstructed section headers table | 
          |
| 601 | new_shdrtable_offset = 0;  | 
            634 | new_shdrtable_offset = 0;  | 
          
| 602 | table_count = ELF_GET_NUMERIC (ELFHDR, ELFHDR, program_header_table_len);  | 
            635 | table_count = ELF_GET_NUMERIC (ELFHDR, ELFHDR, program_header_table_len);  | 
          
| 603 | for (table_index = 0; table_index < table_count; table_index++)  | 
            636 | for (table_index = 0; table_index < table_count; table_index++)  | 
          
| 604 |    { | 
            637 |    { | 
          
| 605 | phdr = (elf_program_header_t *) &file->bytes[ELF_GET_NUMERIC (ELFHDR, ELFHDR, program_header_table_offset) + (size_t) ELF_GET_NUMERIC (ELFHDR, ELFHDR, program_header_item_size) * table_index]; // quick access to program header  | 
            638 | phdr = (elf_program_header_t *) &file->bytes[ELF_GET_NUMERIC (ELFHDR, ELFHDR, program_header_table_offset) + (size_t) ELF_GET_NUMERIC (ELFHDR, ELFHDR, program_header_item_size) * table_index]; // quick access to program header  | 
          
| Line 693... | Line 726... | ||
| 693 | } | 
            726 | } | 
          
| 694 | 727 | ||
| 695 | 728 | ||
| 696 | static void add_fsentry (fsentry_t **fsentries, size_t *fsentry_count, parms_t *entry_parms, const char *stored_pathname, const char *buildhost_pathname)  | 
            729 | static void add_fsentry (fsentry_t **fsentries, size_t *fsentry_count, parms_t *entry_parms, const char *stored_pathname, const char *buildhost_pathname)  | 
          
| 697 | { | 
            730 | { | 
          
| - | 731 |    #define STRINGARRAY_INIT(string_array) do { (string_array)->args = NULL; (string_array)->count = 0; } while (0) | 
          |
| - | 732 |    #define STRINGARRAY_PUSH(string_array,str) do { \ | 
          |
| - | 733 |       reallocated_ptr = realloc ((string_array)->args, ((string_array)->count + 1) * sizeof (char *)); \ | 
          |
| - | 734 |       ASSERT_WITH_ERRNO (reallocated_ptr); \ | 
          |
| - | 735 |       (string_array)->args = reallocated_ptr; \ | 
          |
| - | 736 |       (string_array)->args[(string_array)->count] = ((str) != NULL ? strdup ((str)) : NULL); \ | 
          |
| - | 737 |       if ((str) != NULL) \ | 
          |
| - | 738 |          ASSERT_WITH_ERRNO ((string_array)->args[(string_array)->count]); \ | 
          |
| - | 739 |       (string_array)->count++; \ | 
          |
| - | 740 |    } while (0) | 
          |
| - | 741 |    #define STRINGARRAY_FREE(string_array) do { \ | 
          |
| - | 742 |       if ((string_array)->args != NULL) { \ | 
          |
| - | 743 |          for (array_index = 0; array_index < (string_array)->count; array_index++) \ | 
          |
| - | 744 |             if ((string_array)->args[array_index] != NULL) \ | 
          |
| - | 745 |                free ((string_array)->args[array_index]); \ | 
          |
| - | 746 |          free ((string_array)->args); \ | 
          |
| - | 747 |          (string_array)->args = NULL; \ | 
          |
| - | 748 |       } \ | 
          |
| - | 749 |       (string_array)->count = 0; \ | 
          |
| - | 750 |    } while (0) | 
          |
| - | 751 | ||
| - | 752 | typedef struct stringarray_s  | 
          |
| - | 753 |    { | 
          |
| - | 754 | char **args;  | 
          |
| - | 755 | size_t count;  | 
          |
| - | 756 | } stringarray_t;  | 
          |
| - | 757 | ||
| 698 | static thread_local char *candidate_pathname = NULL;  | 
            758 | static thread_local char *candidate_pathname = NULL;  | 
          
| 699 | static int inode_count = 0; // will be preincremented each time this function is called  | 
            759 | static int inode_count = 0; // will be preincremented each time this function is called  | 
          
| 700 | 760 | ||
| - | 761 | stringarray_t global_argv = { NULL, 0 };  | 
          |
| - | 762 | stringarray_t global_envp = { NULL, 0 };  | 
          |
| - | 763 | stringarray_t line_argv = { NULL, 0 };  | 
          |
| - | 764 | stringarray_t line_envp = { NULL, 0 };  | 
          |
| - | 765 | stringarray_t startup_argv = { NULL, 0 };  | 
          |
| - | 766 | stringarray_t startup_envp = { NULL, 0 };  | 
          |
| - | 767 | stringarray_t procnto_argv = { NULL, 0 };  | 
          |
| - | 768 | stringarray_t procnto_envp = { NULL, 0 };  | 
          |
| - | 769 | stringarray_t linker_argv = { NULL, 0 };  | 
          |
| 701 | const char *stored_pathname_without_leading_slash;  | 
            770 | const char *stored_pathname_without_leading_slash;  | 
          
| 702 | const char *original_stored_pathname = NULL;  | 
            771 | const char *original_stored_pathname = NULL;  | 
          
| - | 772 |    buffer_t current_line; | 
          |
| 703 | buffer_t *shstrtab = NULL;  | 
            773 | buffer_t *shstrtab = NULL;  | 
          
| 704 | const char *canonical_dylib_name;  | 
            774 | const char *canonical_dylib_name;  | 
          
| 705 | const char *dynamic_strings; // strings table of the ".dynamic" section  | 
            775 | const char *dynamic_strings; // strings table of the ".dynamic" section  | 
          
| 706 | const char *last_dirsep;  | 
            776 | const char *last_dirsep;  | 
          
| 707 | 
  | 
            777 | size_t array_index;  | 
          
| 708 | size_t  | 
            778 | size_t line_index;  | 
          
| 709 | size_t fsentry_index;  | 
            779 | size_t fsentry_index;  | 
          
| 710 | char *startup_name = NULL;  | 
            - | |
| 711 | char *procnto_name = NULL;  | 
            - | |
| 712 | char *resolved_pathname;  | 
            780 | char *resolved_pathname;  | 
          
| - | 781 | char *linebit_start;  | 
          |
| - | 782 | char *write_ptr;  | 
          |
| - | 783 | char *read_ptr;  | 
          |
| - | 784 | char *token;  | 
          |
| - | 785 | char *value;  | 
          |
| - | 786 | char *ctx;  | 
          |
| 713 | void *reallocated_ptr;  | 
            787 | void *reallocated_ptr;  | 
          
| 714 | void *old_data;  | 
            788 | void *old_data;  | 
          
| - | 789 |    bool is_quoted_context; | 
          |
| - | 790 |    bool is_end_of_line; | 
          |
| 715 | struct stat stat_buf;  | 
            791 | struct stat stat_buf;  | 
          
| 716 | fsentry_t *fsentry;  | 
            792 | fsentry_t *fsentry;  | 
          
| 717 | int retval;  | 
            793 | int retval;  | 
          
| 718 | 794 | ||
| 719 |    // initial allocation (per thread) | 
            795 |    // initial allocation (per thread) | 
          
| Line 727... | Line 803... | ||
| 727 |    { | 
            803 |    { | 
          
| 728 | LOG_INFO ("directory: ino 0x%x uid %d gid %d mode 0%o path \"%s\"", inode_count + 1, entry_parms->uid, entry_parms->gid, entry_parms->st_mode, stored_pathname);  | 
            804 | LOG_INFO ("directory: ino 0x%x uid %d gid %d mode 0%o path \"%s\"", inode_count + 1, entry_parms->uid, entry_parms->gid, entry_parms->st_mode, stored_pathname);  | 
          
| 729 |    } | 
            805 |    } | 
          
| 730 | else if (S_ISREG (entry_parms->st_mode)) // else are we storing a regular file ?  | 
            806 | else if (S_ISREG (entry_parms->st_mode)) // else are we storing a regular file ?  | 
          
| 731 |    { | 
            807 |    { | 
          
| 732 | if (  | 
            808 | if (entry_parms->is_bootstrap_file) // is it the bootstrap file ?  | 
          
| 733 |       { | 
            809 |       { | 
          
| 734 |          // HACK: for now just consider the kernel as a binary blob | 
            - | |
| 735 |          // FIXME: reimplement properly | 
            - | |
| 736 | #ifdef PROCNTO_WIP | 
            - | |
| 737 | char *linebit_start;  | 
            - | |
| 738 | char *content_line;  | 
            - | |
| 739 | char *write_ptr;  | 
            - | |
| 740 | char *token;  | 
            - | |
| 741 | char *value;  | 
            - | |
| 742 | char *ctx;  | 
            - | |
| 743 |          bool is_quoted_context; | 
            - | |
| 744 |          bool was_string_split; | 
            - | |
| 745 | - | ||
| 746 |          // parse each line of contents | 
            810 |          // parse each line of contents | 
          
| 747 | ASSERT (entry_parms->data.  | 
            811 | ASSERT (entry_parms->data.size > 0, "kernel specification without inline contents");  | 
          
| - | 812 | ||
| - | 813 |          // parse buffer (non-destructively) line after line | 
          |
| - | 814 | Buffer_Initialize (¤t_line);  | 
          |
| 748 | for (  | 
            815 | for (line_index = 0; Buffer_GetNthLine (&entry_parms->data, line_index, ¤t_line); line_index++)  | 
          
| 749 |          { | 
            816 |          { | 
          
| - | 817 | read_ptr = current_line.bytes;  | 
          |
| 750 | while (isspace (*  | 
            818 | while (isspace (*read_ptr))  | 
          
| 751 | 
  | 
            819 | read_ptr++; // skip leading spaces  | 
          
| 752 | if ((*  | 
            820 | if ((*read_ptr == '#') || (*read_ptr == 0))  | 
          
| 753 | continue; // skip comments and empty lines  | 
            821 | continue; // skip comments and empty lines  | 
          
| 754 | 822 | ||
| 755 |             // format of a line: [attributes] [env assignation] [...] [executable] [arg] [...] [comment] | 
            823 |             // format of a line: [attributes] [env assignation] [...] [executable] [arg] [...] [comment] | 
          
| 756 |             // example: "[uid=0 gid=0 perms=0700] CONFIG_PATH=/proc/boot:/etc procnto-smp-instr -v -mr -d 0777 -u 0777" | 
            824 |             // example: "[uid=0 gid=0 perms=0700] CONFIG_PATH=/proc/boot:/etc procnto-smp-instr -v -mr -d 0777 -u 0777" | 
          
| - | 825 | ||
| 757 | 
  | 
            826 | LOG_DEBUG ("parsing line: %s", read_ptr);  | 
          
| 758 | 827 | ||
| 759 |             // does this line start with an attribute block ? | 
            828 |             // does this line start with an attribute block ? | 
          
| 760 | if (*  | 
            829 | if (*read_ptr == '[')  | 
          
| 761 |             { | 
            830 |             { | 
          
| 762 | 
  | 
            831 | read_ptr++; // skip the leading square bracket  | 
          
| 763 | linebit_start =  | 
            832 | linebit_start = read_ptr; // remember where it starts  | 
          
| 764 | is_quoted_context = false; // reach the next unescaped closing square bracket that is not between quotes  | 
            833 | is_quoted_context = false; // reach the next unescaped closing square bracket that is not between quotes  | 
          
| 765 | while ((*  | 
            834 | while ((*read_ptr != 0) && !((*read_ptr == ']') && (read_ptr[-1] != '\\') && !is_quoted_context))  | 
          
| 766 |                { | 
            835 |                { | 
          
| 767 | if (*  | 
            836 | if (*read_ptr == '"')  | 
          
| 768 | is_quoted_context ^= true; // remember when we're between quotes  | 
            837 | is_quoted_context ^= true; // remember when we're between quotes  | 
          
| 769 | else if (!is_quoted_context && (*  | 
            838 | else if (!is_quoted_context && (*read_ptr == ' '))  | 
          
| 770 | *  | 
            839 | *read_ptr = RECORD_SEP[0]; // turn all spaces outside quoted contexts into an ASCII record separator to ease token splitting  | 
          
| 771 | 
  | 
            840 | read_ptr++; // reach the next unescaped closing square bracket  | 
          
| 772 |                } | 
            841 |                } | 
          
| 773 | if (*  | 
            842 | if (*read_ptr != ']')  | 
          
| 774 |                { | 
            843 |                { | 
          
| 775 | LOG ("warning", 0, "syntax error in \"%s\" line %d: unterminated attributes block (skipping)", buildfile_pathname, lineno);  | 
            844 | LOG ("warning", 0, "syntax error in \"%s\" line %d: unterminated attributes block (skipping)", buildfile_pathname, lineno);  | 
          
| 776 | continue; // invalid attribute block, skip line  | 
            845 | continue; // invalid attribute block, skip line  | 
          
| 777 |                } | 
            846 |                } | 
          
| - | 847 | is_end_of_line = (*read_ptr == 0); // see if we're at the end of line already  | 
          |
| 778 | *  | 
            848 | *read_ptr = 0; // end the attribute block in all cases so that it is a parsable C string  | 
          
| 779 | 849 | ||
| 780 |                // now parse the attribute tokens (NOTE: THE LIST OF ALLOWED ATTRIBUTES HERE IS NOT DOCUMENTED) | 
            850 |                // now parse the attribute tokens (NOTE: THE LIST OF ALLOWED ATTRIBUTES HERE IS NOT DOCUMENTED) | 
          
| 781 | token = strtok_r (linebit_start, RECORD_SEP, &ctx);  | 
            851 | token = strtok_r (linebit_start, RECORD_SEP, &ctx);  | 
          
| 782 | while (token != NULL)  | 
            852 | while (token != NULL)  | 
          
| 783 |                { | 
            853 |                { | 
          
| 784 |                   #define REACH_TOKEN_VALUE() do { value = strchr (token, '=') + 1; if (*value == '"') value++; } while (0) | 
            854 |                   #define REACH_TOKEN_VALUE() do { value = strchr (token, '=') + 1; if (*value == '"') value++; } while (0) | 
          
| 785 | if (false)  | 
            855 | if (false) {}  | 
          
| 786 | else if (strncmp (token, "prefix=", 7) == 0) { REACH_TOKEN_VALUE (); entry_parms->prefix = (*value == '/' ? value + 1 : value); } // skip possible leading slash in prefix (NOTE: stolen pointer. Do not free.)  | 
            856 | else if (strncmp (token, "prefix=", 7) == 0) { REACH_TOKEN_VALUE (); entry_parms->prefix = (*value == '/' ? value + 1 : value); } // skip possible leading slash in prefix (NOTE: stolen pointer. Do not free.)  | 
          
| 787 | else if (strncmp (token, "uid=", 4) == 0) { REACH_TOKEN_VALUE (); entry_parms->uid = (int) read_integer (value); }  | 
            857 | else if (strncmp (token, "uid=", 4) == 0) { REACH_TOKEN_VALUE (); entry_parms->uid = (int) read_integer (value); }  | 
          
| 788 | else if (strncmp (token, "gid=", 4) == 0) { REACH_TOKEN_VALUE (); entry_parms->gid = (int) read_integer (value); }  | 
            858 | else if (strncmp (token, "gid=", 4) == 0) { REACH_TOKEN_VALUE (); entry_parms->gid = (int) read_integer (value); }  | 
          
| 789 | else if (strncmp (token, "perms=", 6) == 0) { REACH_TOKEN_VALUE (); entry_parms->perms = (int) read_integer (value); }  | 
            859 | else if (strncmp (token, "perms=", 6) == 0) { REACH_TOKEN_VALUE (); entry_parms->perms = (int) read_integer (value); }  | 
          
| 790 | else if (strcmp (token, "+followlink") == 0) entry_parms->should_follow_symlinks = true;  | 
            860 | else if (strcmp (token, "+followlink") == 0) entry_parms->should_follow_symlinks = true;  | 
          
| Line 794... | Line 864... | ||
| 794 | else LOG_WARNING ("unimplemented bootstrap executable attribute in \"%s\" line %d: '%s'", buildfile_pathname, lineno, token);  | 
            864 | else LOG_WARNING ("unimplemented bootstrap executable attribute in \"%s\" line %d: '%s'", buildfile_pathname, lineno, token);  | 
          
| 795 |                   #undef REACH_TOKEN_VALUE | 
            865 |                   #undef REACH_TOKEN_VALUE | 
          
| 796 | token = strtok_r (NULL, RECORD_SEP, &ctx); // proceed to next attribute token  | 
            866 | token = strtok_r (NULL, RECORD_SEP, &ctx); // proceed to next attribute token  | 
          
| 797 |                } | 
            867 |                } | 
          
| 798 | 868 | ||
| 799 | 
  | 
            869 | if (is_end_of_line)  | 
          
| 800 | 
  | 
            870 | continue; // if end of line was reached, proceed to the next line  | 
          
| 801 | 
  | 
            871 |                else | 
          
| - | 872 | read_ptr++; // else reach the next character (after the NUL split) and continue processing the same line  | 
          |
| 802 | } // end of "this line starts with an attributes block"  | 
            873 | } // end of "this line starts with an attributes block"  | 
          
| 803 | 874 | ||
| - | 875 |             // at this point we are past the attributes block | 
          |
| - | 876 | ||
| - | 877 |             // reset contextual argv/envp arrays | 
          |
| - | 878 | line_argv.args = NULL;  | 
          |
| - | 879 | line_argv.count = 0;  | 
          |
| - | 880 | line_envp.args = NULL;  | 
          |
| - | 881 | line_envp.count = 0;  | 
          |
| - | 882 | ||
| 804 |             //  | 
            883 |             // now read each word (or quoted group of words), unescaping escaped characters | 
          
| 805 | while (*  | 
            884 | while (*read_ptr != 0)  | 
          
| 806 |             { | 
            885 |             { | 
          
| - | 886 | while ((*read_ptr != 0) && isspace (*read_ptr))  | 
          |
| - | 887 | read_ptr++; // skip intermediate spaces and reach the next word  | 
          |
| - | 888 | ||
| - | 889 | if (*read_ptr == '#')  | 
          |
| - | 890 | break; // if the rest of the line is commented out, stop parsing it and proceed to the next line  | 
          |
| - | 891 | ||
| 807 | linebit_start =  | 
            892 | linebit_start = read_ptr; // remember the word (or quoted group of words) starts here  | 
          
| 808 | write_ptr =  | 
            893 | write_ptr = read_ptr;  | 
          
| 809 | is_quoted_context = (*  | 
            894 | is_quoted_context = (*read_ptr == '"'); // see if we're entering a quoted context or not  | 
          
| 810 | if (is_quoted_context)  | 
            895 | if (is_quoted_context)  | 
          
| 811 | 
  | 
            896 | read_ptr++; // skip a possible initial quote in the word  | 
          
| 812 | while ((*  | 
            897 | while ((*read_ptr != 0) && ((!is_quoted_context && !isspace (*read_ptr)) || (is_quoted_context && (*read_ptr == '"'))))  | 
          
| 813 |                { | 
            898 |                { | 
          
| 814 | if (*  | 
            899 | if (*read_ptr == '\\')  | 
          
| 815 |                   { | 
            - | |
| 816 |                      content_line++; | 
            - | |
| 817 | 
  | 
            900 | read_ptr++; // unescape characters that are escaped with '\' by advancing the read pointer  | 
          
| 818 |                   } | 
            - | |
| 819 |                   else | 
            - | |
| 820 | 
  | 
            901 | *write_ptr++ = *read_ptr++; // recopy characters as we read them  | 
          
| 821 |                   content_line++; | 
            - | |
| 822 |                } | 
            902 |                } | 
          
| - | 903 | is_end_of_line = (*read_ptr == 0); // see if we're at the end of line already  | 
          |
| - | 904 | *write_ptr = 0; // stop the rewritten string here  | 
          |
| 823 | 905 | ||
| 824 |                // we reached a closing quote, a space OR an equal sign | 
            - | |
| 825 | if (*content_line == '=')  | 
            - | |
| 826 |                { | 
            - | |
| 827 |                   // it's an environment variable assignation | 
            - | |
| 828 | *write_ptr++ = *content_line++; // skip the equal sign  | 
            - | |
| 829 | is_quoted_context = (*content_line == '"');  | 
            - | |
| 830 | if (is_quoted_context)  | 
            - | |
| 831 | content_line++; // skip a possible initial quote in the value  | 
            - | |
| 832 | 
  | 
            906 |                // end of word, i.e. we reached either a closing quote or a space. The string bit has been rewritted at linebit_start without quotes and with characters unescaped. | 
          
| 833 |                   { | 
            - | |
| 834 | if (*content_line == '\\')  | 
            - | |
| 835 |                      { | 
            - | |
| 836 |                         content_line++; | 
            - | |
| 837 | *write_ptr++ = *content_line; // unescape characters that are escaped with '\'  | 
            - | |
| 838 |                      } | 
            - | |
| 839 |                      else | 
            - | |
| 840 | *write_ptr++ = *content_line;  | 
            - | |
| 841 |                      content_line++; | 
            - | |
| 842 |                   } | 
            - | |
| 843 | if (*write_ptr != 0)  | 
            - | |
| 844 |                   { | 
            - | |
| 845 | *write_ptr = 0; // terminate the string if necessary  | 
            - | |
| 846 | was_string_split = true;  | 
            - | |
| 847 |                   } | 
            - | |
| 848 |                   else | 
            - | |
| 849 | was_string_split = false;  | 
            - | |
| 850 | if (is_quoted_context && (*content_line == '"'))  | 
            - | |
| 851 | content_line++; // skip a possible final quote  | 
            - | |
| 852 | while ((*content_line != 0) && isspace (*content_line))  | 
            - | |
| 853 | content_line++; // skip spaces  | 
            - | |
| 854 | 907 | ||
| - | 908 | if ((strchr (linebit_start, '=') != NULL) && (line_argv.count == 0)) // is it an assignation AND have we not started constructing argv yet?  | 
          |
| - | 909 |                { | 
          |
| - | 910 | STRINGARRAY_PUSH (&line_envp, linebit_start); // linebit_start is of the form "NAME=VALUE": it's an environment variable assignation  | 
          |
| - | 911 | LOG_DEBUG ("collected envp: [%s]", linebit_start);  | 
          |
| - | 912 |                } | 
          |
| 855 | 
  | 
            913 | else // it's an executable argument (argv)  | 
          
| - | 914 |                { | 
          |
| - | 915 | STRINGARRAY_PUSH (&line_argv, linebit_start); // linebit_start is either NOT of the form "NAME=VALUE" OR we started constructing argv: it's a command-line argument  | 
          |
| 856 | LOG_DEBUG ("  | 
            916 | LOG_DEBUG ("collected argv: [%s]", linebit_start);  | 
          
| - | 917 |                } | 
          |
| 857 | 918 | ||
| - | 919 | if (!is_end_of_line)  | 
          |
| - | 920 | read_ptr++; // if we haven't reach the end of the line yet, advance to the next character (after the NUL split)  | 
          |
| 858 | 
  | 
            921 | } // end while (*read_ptr != 0)  | 
          
| 859 | 922 | ||
| 860 | 
  | 
            923 |             // we finished parsing the line | 
          
| 861 | 924 | ||
| - | 925 |             // did we fill an executable argv? As per QNX docs, the first executable must be startup-*, the last executable must be procnto. | 
          |
| - | 926 | if (line_argv.count > 0)  | 
          |
| - | 927 |             { | 
          |
| 862 | 
  | 
            928 | if (startup_argv.args == NULL)  | 
          
| - | 929 |                { | 
          |
| 863 | 
  | 
            930 | startup_argv.args = line_argv.args; // relocate these pointers to the right place  | 
          
| 864 | 
  | 
            931 | startup_argv.count = line_argv.count;  | 
          
| - | 932 | startup_envp.args = line_envp.args; // relocate these pointers to the right place  | 
          |
| 865 | 
  | 
            933 | startup_envp.count = line_envp.count;  | 
          
| 866 |                } | 
            934 |                } | 
          
| 867 | else  | 
            935 |                else | 
          
| 868 |                { | 
            936 |                { | 
          
| 869 | *write_ptr = 0; // terminate the string  | 
            - | |
| 870 | if (is_quoted_context && (*content_line == '"'))  | 
            - | |
| 871 | content_line++; // skip a possible final quote  | 
            - | |
| 872 | - | ||
| 873 | LOG_DEBUG ("exe name: [%s]", linebit_start);  | 
            - | |
| 874 | - | ||
| 875 | while ((*content_line != 0) && isspace (*content_line))  | 
            - | |
| 876 | content_line++; // skip leading spaces  | 
            - | |
| 877 | - | ||
| 878 |                   //  | 
            937 | STRINGARRAY_FREE (&procnto_argv); // if procnto's argv was already assigned, free the previous array as we'll be replacing it with a new one  | 
          
| 879 | if (startup_name == NULL)  | 
            - | |
| 880 | 
  | 
            938 | procnto_argv.args = line_argv.args; // relocate these pointers to the right place  | 
          
| 881 |                   else | 
            - | |
| 882 |                   { | 
            - | |
| 883 | if (procnto_name != NULL)  | 
            - | |
| 884 | free (procnto_name);  | 
            - | |
| 885 | 
  | 
            939 | procnto_argv.count = line_argv.count;  | 
          
| 886 |                   } | 
            - | |
| 887 | - | ||
| 888 | if ((*content_line == '#') || (*content_line == 0))  | 
            - | |
| 889 | 
  | 
            940 | STRINGARRAY_FREE (&procnto_envp); // if procnto's envp was already assigned, free the previous array as we'll be replacing it with a new one  | 
          
| 890 | - | ||
| 891 |                   // what comes after now must be optional arguments | 
            - | |
| 892 | 
  | 
            941 | procnto_envp.args = line_envp.args; // relocate these pointers to the right place  | 
          
| 893 | 
  | 
            942 | procnto_envp.count = line_envp.count;  | 
          
| 894 | - | ||
| 895 |                   // FIXME: parse executable command-line arguments | 
            - | |
| 896 | - | ||
| 897 | break; // stop parsing once all the arguments have been read  | 
            - | |
| 898 |                } | 
            943 |                } | 
          
| - | 944 | line_argv.args = NULL; // void the line_argv array so as to not free it as we stole its args pointers  | 
          |
| - | 945 | line_argv.count = 0;  | 
          |
| - | 946 | line_envp.args = NULL; // void the line_envp array so as to not free it as we stole its args pointers  | 
          |
| - | 947 | line_envp.count = 0;  | 
          |
| 899 |             } | 
            948 |             } | 
          
| - | 949 | else // this line contained no executable invokation, so stack up its envp assignations into the global envp array  | 
          |
| - | 950 | for (array_index = 0; array_index < line_envp.count; array_index++)  | 
          |
| - | 951 | STRINGARRAY_PUSH (&global_envp, line_envp.args[array_index]);  | 
          |
| - | 952 | ||
| - | 953 |             // release the contextual argv/envp arrays | 
          |
| 900 | 
  | 
            954 | STRINGARRAY_FREE (&line_argv);  | 
          
| - | 955 | STRINGARRAY_FREE (&line_envp);  | 
          |
| - | 956 | ||
| - | 957 | } // end for (line_index = 0; Buffer_GetNthLine (&entry_parms->data, line_index, ¤t_line); line_index++)  | 
          |
| 901 | free (entry_parms->data.bytes); // free the inline specification once it's parsed  | 
            958 | free (entry_parms->data.bytes); // free the inline specification once it's parsed  | 
          
| 902 | entry_parms->data.bytes = NULL;  | 
            959 | entry_parms->data.bytes = NULL;  | 
          
| 903 | entry_parms->data.  | 
            960 | entry_parms->data.size = 0;  | 
          
| 904 | 961 | ||
| 905 | ASSERT (  | 
            962 | ASSERT (startup_argv.args && startup_argv.args[0] && *startup_argv.args[0], "the QNX startup executable (startup-*) is missing in this bootstrap inline specification");  | 
          
| 906 | ASSERT (  | 
            963 | ASSERT (procnto_argv.args && procnto_argv.args[0] && *procnto_argv.args[0], "the QNX kernel (procnto-*) is missing in this bootstrap inline specification");  | 
          
| 907 | 964 | ||
| 908 |          // now we know which startup and procnto executables to use | 
            965 |          // now we know which startup and procnto executables to use | 
          
| 909 | LOG_DEBUG ("Startup: %s",  | 
            966 | LOG_DEBUG ("Startup: %s", startup_argv.args[0]);  | 
          
| 910 | LOG_DEBUG ("Kernel: %s",  | 
            967 | LOG_DEBUG ("Kernel: %s", procnto_argv.args[0]);  | 
          
| 911 | - | ||
| 912 | sprintf (candidate_pathname, "%s/%s", (entry_parms->prefix != NULL ? entry_parms->prefix : ""), procnto_name); // fix the entry name  | 
            - | |
| 913 | stored_pathname = candidate_pathname;  | 
            - | |
| 914 | entry_parms->extra_ino_flags |= /*IFS_INO_PROCESSED_ELF | */IFS_INO_BOOTSTRAP_EXE; // procnto needs to have these flags stamped on the inode  | 
            - | |
| 915 | entry_parms->st_mode = S_IFREG | entry_parms->perms; // apply specified procnto permissions  | 
            - | |
| 916 | image_kernel_ino = entry_parms->extra_ino_flags | (inode_count + 1);  | 
            - | |
| 917 | 968 | ||
| 918 | static thread_local char linker_pathname[MAXPATHLEN] = "";  | 
            969 | static thread_local char linker_pathname[MAXPATHLEN] = "";  | 
          
| 919 | static thread_local char linker_sysroot_arg[MAXPATHLEN] = "";  | 
            970 | static thread_local char linker_sysroot_arg[MAXPATHLEN] = "";  | 
          
| 920 | static thread_local char linker_script_pathname_arg[MAXPATHLEN] = "";  | 
            971 | static thread_local char linker_script_pathname_arg[MAXPATHLEN] = "";  | 
          
| 921 | static thread_local char procnto_buildhost_pathname[MAXPATHLEN] = "";  | 
            972 | static thread_local char procnto_buildhost_pathname[MAXPATHLEN] = "";  | 
          
| 922 | static thread_local char procnto_sym_filename[MAXPATHLEN] = "";  | 
            973 | static thread_local char procnto_sym_filename[MAXPATHLEN] = "";  | 
          
| - | 974 | buffer_t bootargs_buffer = { 0 };  | 
          |
| - | 975 | char *bootargs_location;  | 
          |
| 923 | 976 | ||
| 924 |          // construct the arguments that are based on environment variables (infer QNX_HOST from QNX_TARGET) | 
            977 |          // construct the arguments that are based on environment variables (infer QNX_HOST from QNX_TARGET) | 
          
| 925 | #if defined(_WIN32) | 
            978 | #if defined(_WIN32) | 
          
| 926 | 
  | 
            979 | sprintf_s (linker_pathname, sizeof (linker_pathname), "%s/../../host/win64/x86_64/usr/bin/%s-ld.exe", QNX_TARGET, (strcmp (image_processor, "x86_64") == 0 ? "x86_64-pc-nto-qnx8.0.0" : "aarch64-unknown-nto-qnx8.0.0")); // Win32: note the .exe extension  | 
          
| 927 | #elif defined(__linux__) | 
            980 | #elif defined(__linux__) | 
          
| 928 | 
  | 
            981 | sprintf_s (linker_pathname, sizeof (linker_pathname), "%s/../../host/linux/x86_64/usr/bin/%s-ld", QNX_TARGET, (strcmp (image_processor, "x86_64") == 0 ? "x86_64-pc-nto-qnx8.0.0" : "aarch64-unknown-nto-qnx8.0.0"));  | 
          
| 929 | #elif defined(__QNXNTO__) | 
            982 | #elif defined(__QNXNTO__) | 
          
| 930 | 
  | 
            983 | sprintf_s (linker_pathname, sizeof (linker_pathname), "%s/../../host/qnx8/x86_64/usr/bin/%s-ld", QNX_TARGET, (strcmp (image_processor, "x86_64") == 0 ? "x86_64-pc-nto-qnx8.0.0" : "aarch64-unknown-nto-qnx8.0.0"));  | 
          
| 931 | #else // wtf are you building this on? | 
            984 | #else // wtf are you building this on? | 
          
| 932 | #error Please port the GNU linker x86_64-pc-nto-qnx8.0.0-ld and aarch64-unknown-nto-qnx8.0.0-ld to your host architecture first before compiling ifstool. | 
            985 | #error Please port the GNU linker x86_64-pc-nto-qnx8.0.0-ld and aarch64-unknown-nto-qnx8.0.0-ld to your host architecture first before compiling ifstool. | 
          
| 933 | #endif | 
            986 | #endif | 
          
| 934 | ASSERT (access (linker_pathname, 0) == 0, "host cross-linker for QNX8 \"%s\" not found", linker_pathname);  | 
            987 | ASSERT (access (linker_pathname, 0) == 0, "host cross-linker for QNX8 \"%s\" not found", linker_pathname);  | 
          
| 935 | 
  | 
            988 | sprintf_s (linker_sysroot_arg, sizeof (linker_sysroot_arg), "--sysroot=%s/%s/", QNX_TARGET, image_processor);  | 
          
| 936 | 
  | 
            989 | sprintf_s (linker_script_pathname_arg, sizeof (linker_script_pathname_arg), "-T%s/%s/lib/nto.link", QNX_TARGET, image_processor);  | 
          
| 937 | 990 | ||
| 938 | resolved_pathname = resolve_pathname (  | 
            991 | resolved_pathname = resolve_pathname (procnto_argv.args[0], entry_parms->search); // locate the procnto kernel location  | 
          
| 939 | ASSERT (resolved_pathname, "QNX kernel \"%s\" not found in search path",  | 
            992 | ASSERT (resolved_pathname, "QNX kernel \"%s\" not found in search path", procnto_argv.args[0]);  | 
          
| 940 | 
  | 
            993 | strcpy_s (procnto_buildhost_pathname, sizeof (procnto_buildhost_pathname), resolved_pathname);  | 
          
| 941 | 994 | ||
| 942 | sprintf_s (procnto_sym_filename, sizeof (procnto_sym_filename), "%s.sym%s",  | 
            995 | sprintf_s (procnto_sym_filename, sizeof (procnto_sym_filename), "%s.sym%s", procnto_argv.args[0], sym_suffix);  | 
          
| 943 | 996 | ||
| 944 | 
  | 
            997 |          // construct the linker invokation command-line arguments array (argv) | 
          
| 945 |           | 
            998 | STRINGARRAY_INIT (&linker_argv);  | 
          
| 946 | 
  | 
            999 | STRINGARRAY_PUSH (&linker_argv, strrchr (linker_pathname, '/') + 1); // "${TARGET_TRIPLE}-ld"  | 
          
| 947 | 
  | 
            1000 | STRINGARRAY_PUSH (&linker_argv, linker_sysroot_arg); // "--sysroot=${QNX_TARGET}/${TARGET_CPU}/"  | 
          
| 948 | 
  | 
            1001 | STRINGARRAY_PUSH (&linker_argv, linker_script_pathname_arg); // "-T${QNX_TARGET}/${TARGET_CPU}/lib/nto.link"  | 
          
| 949 | 
  | 
            1002 | STRINGARRAY_PUSH (&linker_argv, "--section-start");  | 
          
| 950 | 
  | 
            1003 | STRINGARRAY_PUSH (&linker_argv, ".text=0xffff800000001000");  | 
          
| 951 | 
  | 
            1004 | STRINGARRAY_PUSH (&linker_argv, "--no-relax");  | 
          
| 952 | 
  | 
            1005 | STRINGARRAY_PUSH (&linker_argv, procnto_buildhost_pathname); // "${QNX_TARGET}/${TARGET_CPU}/boot/sys/procnto-smp-instr"  | 
          
| 953 | 
  | 
            1006 | STRINGARRAY_PUSH (&linker_argv, "-o");  | 
          
| 954 | 
  | 
            1007 | STRINGARRAY_PUSH (&linker_argv, procnto_sym_filename); // "procnto-smp-instr.sym"  | 
          
| 955 | 
  | 
            1008 | STRINGARRAY_PUSH (&linker_argv, NULL); // don't forget to terminate the argv array with a NULL pointer  | 
          
| 956 | };  | 
            - | |
| 957 | if (verbose_level > 2)  | 
            1009 | if (verbose_level > 2)  | 
          
| 958 |          { | 
            1010 |          { | 
          
| 959 | fprintf (stderr, "ifstool: calling:");  | 
            1011 | fprintf (stderr, "ifstool: calling:");  | 
          
| 960 | for (  | 
            1012 | for (array_index = 0; array_index < linker_argv.count - 1; array_index++)  | 
          
| 961 | fprintf (stderr, " '%s'", linker_argv[  | 
            1013 | fprintf (stderr, " '%s'", linker_argv.args[array_index]);  | 
          
| 962 | fputc ('\n', stderr);  | 
            1014 | fputc ('\n', stderr);  | 
          
| 963 |          } | 
            1015 |          } | 
          
| - | 1016 | #ifdef _WIN32 | 
          |
| 964 | _spawnv (_P_WAIT, linker_pathname, linker_argv); // spawn the linker and produce a stripped procnto (wait for completion)  | 
            1017 | _spawnv (_P_WAIT, linker_pathname, linker_argv.args); // spawn the linker and produce a stripped procnto (wait for completion)  | 
          
| - | 1018 | #else // !_WIN32, thus POSIX | 
          |
| - | 1019 | do {  | 
          |
| - | 1020 | int status;  | 
          |
| - | 1021 | pid_t pid = fork (); // duplicate ourselves so as to create a new process  | 
          |
| - | 1022 | ASSERT_WITH_ERRNO (pid != -1);  | 
          |
| - | 1023 | if (pid == 0)  | 
          |
| - | 1024 |             { | 
          |
| - | 1025 | execv (linker_pathname, linker_argv); // spawn the child process  | 
          |
| - | 1026 | DIE_WITH_EXITCODE (1, "execve() failed"); // exec never returns  | 
          |
| - | 1027 |             } | 
          |
| - | 1028 |             else | 
          |
| - | 1029 | waitpid (pid, &status, 0); // wait for the child to finish  | 
          |
| - | 1030 | } while (0);  | 
          |
| - | 1031 | #endif // _WIN32 | 
          |
| - | 1032 | STRINGARRAY_FREE (&linker_argv);  | 
          |
| 965 | if (!Buffer_ReadFromFile (&entry_parms->data, procnto_sym_filename)) // load the output file  | 
            1033 | if (!Buffer_ReadFromFile (&entry_parms->data, procnto_sym_filename)) // load the output file  | 
          
| 966 | DIE_WITH_EXITCODE (1, "the host cross-linker failed to produce a readable stripped \"%s\" kernel: %s", procnto_sym_filename, strerror (errno));  | 
            1034 | DIE_WITH_EXITCODE (1, "the host cross-linker failed to produce a readable stripped \"%s\" kernel: %s", procnto_sym_filename, strerror (errno));  | 
          
| 967 | if (!entry_parms->should_keep_ld_output)  | 
            1035 | if (!entry_parms->should_keep_ld_output)  | 
          
| 968 | unlink (procnto_sym_filename); // remove the linker output file if we want to  | 
            1036 | unlink (procnto_sym_filename); // remove the linker output file if we want to  | 
          
| - | 1037 | ||
| - | 1038 |          // save the boot arguments. The magic to look for is "ddpvbskr" -- whatever that means | 
          |
| - | 1039 | if ((bootargs_location = Buffer_FindFirstByteArray (&entry_parms->data, "ddpvbskr")) == NULL)  | 
          |
| - | 1040 | DIE_WITH_EXITCODE (1, "unable to find boot args location in the stripped \"%s\" kernel", stored_pathname);  | 
          |
| - | 1041 | Buffer_InitWithSize (&bootargs_buffer, sizeof (bootargs_entry_t)); // prepare a boot args entry  | 
          |
| - | 1042 | ((bootargs_entry_t *) bootargs_buffer.bytes)->argc = (uint8_t) procnto_argv.count;  | 
          |
| - | 1043 | ((bootargs_entry_t *) bootargs_buffer.bytes)->envc = (uint8_t) (global_envp.count + procnto_envp.count);  | 
          |
| - | 1044 | ((bootargs_entry_t *) bootargs_buffer.bytes)->shdr_addr = (uint32_t) (image_base + bootfile_size); // same value as startup_header.image_paddr (which is not set yet) (TODO: support 64-bit shdr_addr offsets -- see comment in bootargs_entry_t struct)  | 
          |
| - | 1045 | for (array_index = 0; array_index < procnto_argv.count; array_index++)  | 
          |
| - | 1046 | ASSERT_WITH_ERRNO (Buffer_Append (&bootargs_buffer, procnto_argv.args[array_index], strlen (procnto_argv.args[array_index]) + 1)); // append string including NUL terminator  | 
          |
| - | 1047 | for (array_index = 0; array_index < global_envp.count; array_index++)  | 
          |
| - | 1048 | ASSERT_WITH_ERRNO (Buffer_Append (&bootargs_buffer, global_envp.args[array_index], strlen (global_envp.args[array_index]) + 1)); // append string including NUL terminator  | 
          |
| - | 1049 | for (array_index = 0; array_index < procnto_envp.count; array_index++)  | 
          |
| - | 1050 | ASSERT_WITH_ERRNO (Buffer_Append (&bootargs_buffer, procnto_envp.args[array_index], strlen (procnto_envp.args[array_index]) + 1)); // append string including NUL terminator  | 
          |
| - | 1051 | ((bootargs_entry_t *) bootargs_buffer.bytes)->size_hi = (uint8_t) ((bootargs_buffer.size >> 8) & 0xff);  | 
          |
| - | 1052 | ((bootargs_entry_t *) bootargs_buffer.bytes)->size_lo = (uint8_t) ((bootargs_buffer.size >> 0) & 0xff);  | 
          |
| - | 1053 | ASSERT_WITH_ERRNO (Buffer_WriteBufferAt (&entry_parms->data, (size_t) bootargs_location - (size_t) entry_parms->data.bytes, &bootargs_buffer));  | 
          |
| - | 1054 | Buffer_Forget (&bootargs_buffer); // release the boot args buffer once it's written  | 
          |
| 969 | 1055 | ||
| 970 |          // now strip this prelinked ELF kernel file | 
            1056 |          // now strip this prelinked ELF kernel file | 
          
| 971 | Buffer_StripELFFile (&entry_parms->data, (const char **) saved_ELF_sections, 1, stored_pathname); // strip the ELF file as per QNX docs (only keep ONE section, which is "QNX_info")  | 
            1057 | ASSERT_WITH_ERRNO (Buffer_StripELFFile (&entry_parms->data, (const char **) saved_ELF_sections, 1, true, stored_pathname)); // strip the ELF file as per QNX docs (only keep ONE section, which is "QNX_info", and align the segment size in file with the size it occupies in memory)  | 
          
| - | 1058 | ||
| - | 1059 | sprintf_s (candidate_pathname, MAXPATHLEN, "%s/%s", (entry_parms->prefix != NULL ? entry_parms->prefix : ""), procnto_argv.args[0]); // fix the entry name  | 
          |
| - | 1060 | stored_pathname = candidate_pathname;  | 
          |
| - | 1061 | ||
| 972 | entry_parms->extra_ino_flags |= IFS_INO_PROCESSED_ELF; // mark this inode as a preprocessed ELF file  | 
            1062 | entry_parms->extra_ino_flags |= IFS_INO_PROCESSED_ELF | IFS_INO_BOOTSTRAP_EXE; // mark this inode as a preprocessed *bootstrap* ELF file  | 
          
| - | 1063 | entry_parms->st_mode = S_IFREG | entry_parms->perms; // procnto is a regular file  | 
          |
| - | 1064 | image_kernel_ino = entry_parms->extra_ino_flags | (inode_count + 1);  | 
          |
| 973 | 1065 | ||
| 974 | #else // !PROCNTO_WIP | 
            - | |
| 975 | /* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK */  | 
            - | |
| 976 | /* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK */  | 
            - | |
| 977 |          /* HACK */ | 
            - | |
| 978 | /* HACK */ sprintf_s (candidate_pathname, MAXPATHLEN, "%s/procnto-smp-instr", (entry_parms->prefix != NULL ? entry_parms->prefix : "")); // HACK: fix the entry name  | 
            - | |
| 979 | /* HACK */ stored_pathname = candidate_pathname;  | 
            - | |
| 980 | /* HACK */ entry_parms->extra_ino_flags |= IFS_INO_PROCESSED_ELF | IFS_INO_BOOTSTRAP_EXE; // procnto needs to have these flags stamped on the inode  | 
            - | |
| 981 | 
  | 
            1066 | STRINGARRAY_FREE (&procnto_argv); // release procnto's argv array  | 
          
| 982 | /* HACK */ image_kernel_ino = entry_parms->extra_ino_flags | (inode_count + 1);  | 
            - | |
| 983 | 
  | 
            1067 | STRINGARRAY_FREE (&procnto_envp); // release procnto's envp array  | 
          
| 984 | 
  | 
            1068 | STRINGARRAY_FREE (&global_envp); // release the global envp array  | 
          
| 985 | /* HACK */ if (!Buffer_ReadFromFile (&entry_parms->data, kernelfile_pathname)) // read kernel file as a precompiled binary blob  | 
            - | |
| 986 | /* HACK */ {  | 
            - | |
| 987 | /* HACK */ fprintf (stderr, "fatal error: unable to read precompiled kernel file \"%s\" specified in --kernelfile argument\n", kernelfile_pathname);  | 
            - | |
| 988 | /* HACK */ exit (1);  | 
            - | |
| 989 | /* HACK */ }  | 
            - | |
| 990 |          /* HACK */ | 
            - | |
| 991 | /* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK */  | 
            - | |
| 992 | /* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK */  | 
            - | |
| 993 | #endif // PROCNTO_WIP | 
            - | |
| 994 |       } | 
            1069 |       } | 
          
| 995 | else if (entry_parms->is_compiled_bootscript) // else is it a startup script ?  | 
            1070 | else if (entry_parms->is_compiled_bootscript) // else is it a startup script ?  | 
          
| 996 | image_bootscript_ino = inode_count + 1; // save boot script inode number for image header  | 
            1071 | image_bootscript_ino = inode_count + 1; // save boot script inode number for image header  | 
          
| 997 | 1072 | ||
| 998 |       // do we already know the data for this data blob ? | 
            1073 |       // do we already know the data for this data blob ? | 
          
| Line 1065... | Line 1140... | ||
| 1065 | } // end if the file we're storing is a dylib  | 
            1140 | } // end if the file we're storing is a dylib  | 
          
| 1066 | 1141 | ||
| 1067 |          // now strip this ELF file if necessary | 
            1142 |          // now strip this ELF file if necessary | 
          
| 1068 | if (!(entry_parms->extra_ino_flags & IFS_INO_PROCESSED_ELF))  | 
            1143 | if (!(entry_parms->extra_ino_flags & IFS_INO_PROCESSED_ELF))  | 
          
| 1069 |          { | 
            1144 |          { | 
          
| 1070 | Buffer_StripELFFile (&entry_parms->data, (const char **) saved_ELF_sections, saved_ELF_section_count, stored_pathname); // strip the ELF file à la mkifs  | 
            1145 | Buffer_StripELFFile (&entry_parms->data, (const char **) saved_ELF_sections, saved_ELF_section_count, false, stored_pathname); // strip the ELF file à la mkifs  | 
          
| 1071 | entry_parms->extra_ino_flags |= IFS_INO_PROCESSED_ELF; // mark this inode as a preprocessed ELF file  | 
            1146 | entry_parms->extra_ino_flags |= IFS_INO_PROCESSED_ELF; // mark this inode as a preprocessed ELF file  | 
          
| 1072 | } // end if the file is not yet a processed ELF  | 
            1147 | } // end if the file is not yet a processed ELF  | 
          
| 1073 | } // end if the file we're storing is an ELF file  | 
            1148 | } // end if the file we're storing is an ELF file  | 
          
| 1074 |       #undef ELFHDR // undefine the macro that used to always point to the ELF header at the beginning of the file | 
            1149 |       #undef ELFHDR // undefine the macro that used to always point to the ELF header at the beginning of the file | 
          
| 1075 |    } | 
            1150 |    } | 
          
| Line 1357... | Line 1432... | ||
| 1357 | if ((sep = strchr (value, '=')) != NULL) image_totalsize = (uint32_t) read_integer (sep + 1); // if we have an equal sign, read optional image padding size  | 
            1432 | if ((sep = strchr (value, '=')) != NULL) image_totalsize = (uint32_t) read_integer (sep + 1); // if we have an equal sign, read optional image padding size  | 
          
| 1358 | if ((sep = strchr (value, '%')) != NULL) image_align = (uint32_t) read_integer (sep + 1); // if we have a modulo sign, read optional image aligmnent  | 
            1433 | if ((sep = strchr (value, '%')) != NULL) image_align = (uint32_t) read_integer (sep + 1); // if we have a modulo sign, read optional image aligmnent  | 
          
| 1359 | LOG_INFO ("image 0x%x-0x%x maxsize %d totalsize %d align %d", image_base, image_end, image_maxsize, image_totalsize, image_align);  | 
            1434 | LOG_INFO ("image 0x%x-0x%x maxsize %d totalsize %d align %d", image_base, image_end, image_maxsize, image_totalsize, image_align);  | 
          
| 1360 |          } | 
            1435 |          } | 
          
| 1361 | else if (strncmp (token, "virtual=", 8) == 0) { REACH_TOKEN_VALUE ();  | 
            1436 | else if (strncmp (token, "virtual=", 8) == 0) { REACH_TOKEN_VALUE ();  | 
          
| 1362 | if ((bootfile_pathname == NULL) || (startupfile_pathname  | 
            1437 | if ((bootfile_pathname == NULL) || (startupfile_pathname == NULL)) // HACK until I figure out how to re-create them  | 
          
| 1363 | DIE_WITH_EXITCODE (1, "creating bootable images require the --bootfile, --startupfile and --kernelfile command-line options in \"%s\" line %d", buildfile_pathname, lineno);  | 
            1438 | DIE_WITH_EXITCODE (1, "creating bootable images require the --bootfile, --startupfile and --kernelfile command-line options in \"%s\" line %d", buildfile_pathname, lineno);  | 
          
| 1364 | if ((sep = strchr (value, ',')) != NULL) // do we have a comma separating (optional) processor and boot file name ?  | 
            1439 | if ((sep = strchr (value, ',')) != NULL) // do we have a comma separating (optional) processor and boot file name ?  | 
          
| 1365 |             { | 
            1440 |             { | 
          
| 1366 | *sep = 0;  | 
            1441 | *sep = 0;  | 
          
| 1367 | strcpy_s (image_processor, sizeof (image_processor), value); // save processor  | 
            1442 | strcpy_s (image_processor, sizeof (image_processor), value); // save processor  | 
          
| Line 1371... | Line 1446... | ||
| 1371 |             //strcpy (image_bootfile, bootfile_pathname); // FIXME: HACK | 
            1446 |             //strcpy (image_bootfile, bootfile_pathname); // FIXME: HACK | 
          
| 1372 | if (stat (bootfile_pathname, &stat_buf) != 0)  | 
            1447 | if (stat (bootfile_pathname, &stat_buf) != 0)  | 
          
| 1373 | DIE_WITH_EXITCODE (1, "unable to stat the boot file \"%s\" specified in \"%s\" line %d: %s", bootfile_pathname, buildfile_pathname, lineno, strerror (errno));  | 
            1448 | DIE_WITH_EXITCODE (1, "unable to stat the boot file \"%s\" specified in \"%s\" line %d: %s", bootfile_pathname, buildfile_pathname, lineno, strerror (errno));  | 
          
| 1374 | bootfile_size = stat_buf.st_size; // save preboot file size  | 
            1449 | bootfile_size = stat_buf.st_size; // save preboot file size  | 
          
| 1375 | LOG_INFO ("processor \"%s\" bootfile \"%s\"\n", image_processor, bootfile_pathname);  | 
            1450 | LOG_INFO ("processor \"%s\" bootfile \"%s\"\n", image_processor, bootfile_pathname);  | 
          
| 1376 | #if 1 | 
            - | |
| 1377 |             // ###################################################################################################################################################################################################################################### | 
            - | |
| 1378 |             // # FIXME: figure out how to re-create it: linker call involved | 
            - | |
| 1379 |             // # $ 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 | 
            - | |
| 1380 |             // ###################################################################################################################################################################################################################################### | 
            - | |
| 1381 | //               if (!Buffer_ReadFromFile (&entry_parms.data, kernelfile_pathname)) | 
            - | |
| 1382 | //                  DIE_WITH_EXITCODE (1, "unable to read precompiled kernel file \"%s\" specified in --kernelfile argument: %s", kernelfile_pathname, strerror (errno)); | 
            - | |
| 1383 | #else // nonworking | 
            - | |
| 1384 | 
  | 
            1451 | entry_parms.is_bootstrap_file = true;  | 
          
| 1385 | #endif // nonworking | 
            - | |
| 1386 |          } | 
            1452 |          } | 
          
| 1387 | else if (strncmp (token, "mtime=", 6) == 0) { REACH_TOKEN_VALUE (); if (strcmp (value, "*") == 0) entry_parms.mtime = UINT32_MAX; else {  | 
            1453 | else if (strncmp (token, "mtime=", 6) == 0) { REACH_TOKEN_VALUE (); if (strcmp (value, "*") == 0) entry_parms.mtime = UINT32_MAX; else {  | 
          
| 1388 |                // value *must* be "YYYY-MM-DD-HH:MM:SS" by specification | 
            1454 |                // value *must* be "YYYY-MM-DD-HH:MM:SS" by specification | 
          
| 1389 | memset (&utc_time, 0, sizeof (utc_time));  | 
            1455 | memset (&utc_time, 0, sizeof (utc_time));  | 
          
| 1390 | if (sscanf_s (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)  | 
            1456 | if (sscanf_s (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 1692... | Line 1758... | ||
| 1692 | DIE_WITH_EXITCODE (1, "the --startupfile arguments expects <pathname>@<entrypoint_from_image_base>");  | 
            1758 | DIE_WITH_EXITCODE (1, "the --startupfile arguments expects <pathname>@<entrypoint_from_image_base>");  | 
          
| 1693 | *sep = 0;  | 
            1759 | *sep = 0;  | 
          
| 1694 | startupfile_pathname = argv[arg_index];  | 
            1760 | startupfile_pathname = argv[arg_index];  | 
          
| 1695 | startupfile_ep_from_imagebase = (size_t) read_integer (sep + 1);  | 
            1761 | startupfile_ep_from_imagebase = (size_t) read_integer (sep + 1);  | 
          
| 1696 |       } | 
            1762 |       } | 
          
| 1697 | else if ((strcmp (argv[arg_index], "--  | 
            1763 | else if ((strcmp (argv[arg_index], "--kerneloffs") == 0) && (arg_index + 1 < argc)) // --kerneloffs 0x32000 (undocumented)  | 
          
| 1698 |       { | 
            - | |
| 1699 | sep = strchr (argv[++arg_index], '@');  | 
            - | |
| 1700 | if ((sep == NULL) || (sep[1] == 0))  | 
            - | |
| 1701 | DIE_WITH_EXITCODE (1, "the --kernelfile arguments expects <pathname>@<fileoffset>");  | 
            - | |
| 1702 | *sep = 0;  | 
            - | |
| 1703 | kernelfile_pathname = argv[arg_index];  | 
            - | |
| 1704 | kernelfile_offset = (size_t) read_integer (  | 
            1764 | kernelfile_offset = (size_t) read_integer (argv[++arg_index]);  | 
          
| 1705 |       } | 
            - | |
| 1706 | else if ((strcmp (argv[arg_index], "-a") == 0) && (arg_index + 1 < argc)) // -a suffix  | 
            1765 | else if ((strcmp (argv[arg_index], "-a") == 0) && (arg_index + 1 < argc)) // -a suffix  | 
          
| 1707 | sym_suffix = argv[++arg_index];  | 
            1766 | sym_suffix = argv[++arg_index];  | 
          
| 1708 | else if (strcmp (argv[arg_index], "-n") == 0)  | 
            1767 | else if (strcmp (argv[arg_index], "-n") == 0)  | 
          
| 1709 | default_parms.mtime_for_inline_files = 0; // inline files should have a mtime set to zero  | 
            1768 | default_parms.mtime_for_inline_files = 0; // inline files should have a mtime set to zero  | 
          
| 1710 | else if (strcmp (argv[arg_index], "-nn") == 0)  | 
            1769 | else if (strcmp (argv[arg_index], "-nn") == 0)  | 
          
| Line 1747... | Line 1806... | ||
| 1747 | saved_ELF_sections = reallocated_ptr;  | 
            1806 | saved_ELF_sections = reallocated_ptr;  | 
          
| 1748 | saved_ELF_sections[saved_ELF_section_count++] = argv[++arg_index]; // stack up another ELF section name to preserve  | 
            1807 | saved_ELF_sections[saved_ELF_section_count++] = argv[++arg_index]; // stack up another ELF section name to preserve  | 
          
| 1749 |       } | 
            1808 |       } | 
          
| 1750 | else if ((strcmp (argv[arg_index], "-?") == 0) || (strcmp (argv[arg_index], "--help") == 0))  | 
            1809 | else if ((strcmp (argv[arg_index], "-?") == 0) || (strcmp (argv[arg_index], "--help") == 0))  | 
          
| 1751 | want_help = true;  | 
            1810 | want_help = true;  | 
          
| 1752 | else if (first_pathname == NULL)  | 
            1811 | else if ((first_pathname == NULL) && (*argv[arg_index] != '-'))  | 
          
| 1753 | first_pathname = argv[arg_index];  | 
            1812 | first_pathname = argv[arg_index];  | 
          
| 1754 | else if (second_pathname == NULL)  | 
            1813 | else if ((second_pathname == NULL) && (*argv[arg_index] != '-'))  | 
          
| 1755 | second_pathname = argv[arg_index];  | 
            1814 | second_pathname = argv[arg_index];  | 
          
| 1756 | else if (third_pathname == NULL)  | 
            1815 | else if ((third_pathname == NULL) && (*argv[arg_index] != '-'))  | 
          
| 1757 | third_pathname = argv[arg_index];  | 
            1816 | third_pathname = argv[arg_index];  | 
          
| 1758 |       else | 
            1817 |       else | 
          
| 1759 | DIE_WITH_EXITCODE (1, "unrecognized option: '%s'", argv[arg_index]);  | 
            1818 | DIE_WITH_EXITCODE (1, "unrecognized option: '%s'", argv[arg_index]);  | 
          
| 1760 |    } | 
            1819 |    } | 
          
| 1761 | 1820 | ||
| Line 1860... | Line 1919... | ||
| 1860 |    // else do we want to strip an ELF file ? if so, do so | 
            1919 |    // else do we want to strip an ELF file ? if so, do so | 
          
| 1861 | else if (want_strip)  | 
            1920 | else if (want_strip)  | 
          
| 1862 |    { | 
            1921 |    { | 
          
| 1863 |       buffer_t file; | 
            1922 |       buffer_t file; | 
          
| 1864 | ASSERT (Buffer_ReadFromFile (&file, first_pathname), "can't open \"%s\" for reading: %s", first_pathname, strerror (errno));  | 
            1923 | ASSERT (Buffer_ReadFromFile (&file, first_pathname), "can't open \"%s\" for reading: %s", first_pathname, strerror (errno));  | 
          
| 1865 | ASSERT (Buffer_StripELFFile (&file, (const char **) saved_ELF_sections, saved_ELF_section_count, first_pathname), "error stripping \"%s\": %s", first_pathname, strerror (errno));  | 
            1924 | ASSERT (Buffer_StripELFFile (&file, (const char **) saved_ELF_sections, saved_ELF_section_count, false, first_pathname), "error stripping \"%s\": %s", first_pathname, strerror (errno));  | 
          
| 1866 | ASSERT_WITH_ERRNO (Buffer_WriteToFile (&file, (second_pathname != NULL ? second_pathname : "<stdout>")));  | 
            1925 | ASSERT_WITH_ERRNO (Buffer_WriteToFile (&file, (second_pathname != NULL ? second_pathname : "<stdout>")));  | 
          
| 1867 | exit (0);  | 
            1926 | exit (0);  | 
          
| 1868 |    } | 
            1927 |    } | 
          
| 1869 | 1928 | ||
| 1870 |    // we want to CREATE an IFS file | 
            1929 |    // we want to CREATE an IFS file | 
          
| Line 2006... | Line 2065... | ||
| 2006 | curr_offset += fsentries[fsentry_index].header.size; // advance to the next one  | 
            2065 | curr_offset += fsentries[fsentry_index].header.size; // advance to the next one  | 
          
| 2007 |    } | 
            2066 |    } | 
          
| 2008 | ASSERT_WITH_ERRNO (Buffer_AppendByteArray (&ifs.data, "\0\0\0\0")); // there seems to be 4 bytes of padding after the image directory  | 
            2067 | ASSERT_WITH_ERRNO (Buffer_AppendByteArray (&ifs.data, "\0\0\0\0")); // there seems to be 4 bytes of padding after the image directory  | 
          
| 2009 | imgdir_size = ifs.data.size - ifs.offsets.imagedir; // measure image dir size and save it for future use  | 
            2068 | imgdir_size = ifs.data.size - ifs.offsets.imagedir; // measure image dir size and save it for future use  | 
          
| 2010 | 2069 | ||
| 2011 |    // is it a bootable image with a  | 
            2070 |    // is it a bootable image with a startup file ? | 
          
| 2012 | if  | 
            2071 | if (startupfile_pathname != NULL)  | 
          
| 2013 |    { | 
            2072 |    { | 
          
| 2014 |       // start by writing the startup script data blob, if we have one | 
            2073 |       // start by writing the startup script data blob, if we have one | 
          
| 2015 | for (fsentry_index = 1; fsentry_index < fsentry_count; fsentry_index++)  | 
            2074 | for (fsentry_index = 1; fsentry_index < fsentry_count; fsentry_index++)  | 
          
| 2016 | if (fsentries[fsentry_index].header.ino == image_bootscript_ino)  | 
            2075 | if (fsentries[fsentry_index].header.ino == image_bootscript_ino)  | 
          
| 2017 | break; // locate the startup script directory entry  | 
            2076 | break; // locate the startup script directory entry  | 
          
| 2018 | if (fsentry_index < fsentry_count) // found it ?  | 
            2077 | if (fsentry_index < fsentry_count) // found it ?  | 
          
| 2019 |       { | 
            2078 |       { | 
          
| 2020 | if (ifs.data.size + fsentries[fsentry_index].u.file.size >= kernelfile_offset)  | 
            2079 | if (ifs.data.size + fsentries[fsentry_index].u.file.size >= kernelfile_offset)  | 
          
| 2021 | DIE_WITH_EXITCODE (1, "the compiled startup script is too big (%zd bytes, max is %zd) to fit at current offset %zd", (size_t) fsentries[fsentry_index].u.file.size, kernelfile_offset - ifs.data.size, ifs.data.size);  | 
            2080 | DIE_WITH_EXITCODE (1, "the compiled startup script is too big (%zd bytes, max is %zd) to fit at current offset %zd. Use --kerneloffs <addr> to relocate (warning: untested)", (size_t) fsentries[fsentry_index].u.file.size, kernelfile_offset - ifs.data.size, ifs.data.size);  | 
          
| 2022 | fsentries[fsentry_index].u.file.offset = (uint32_t) (ifs.data.size - ifs.offsets.imageheader); // save file data blob offset in file structure  | 
            2081 | fsentries[fsentry_index].u.file.offset = (uint32_t) (ifs.data.size - ifs.offsets.imageheader); // save file data blob offset in file structure  | 
          
| 2023 | Buffer_AppendIFSFileData (&ifs.data, &fsentries[fsentry_index]); // write file data  | 
            2082 | Buffer_AppendIFSFileData (&ifs.data, &fsentries[fsentry_index]); // write file data  | 
          
| 2024 | fsentries[fsentry_index].UNSAVED_was_data_written = true; // and remember this file's data was written  | 
            2083 | fsentries[fsentry_index].UNSAVED_was_data_written = true; // and remember this file's data was written  | 
          
| 2025 |       } | 
            2084 |       } | 
          
| 2026 | 2085 | ||
| Line 2057... | Line 2116... | ||
| 2057 |       // now write the QNX kernel | 
            2116 |       // now write the QNX kernel | 
          
| 2058 | for (fsentry_index = 1; fsentry_index < fsentry_count; fsentry_index++)  | 
            2117 | for (fsentry_index = 1; fsentry_index < fsentry_count; fsentry_index++)  | 
          
| 2059 | if (fsentries[fsentry_index].header.ino == image_kernel_ino)  | 
            2118 | if (fsentries[fsentry_index].header.ino == image_kernel_ino)  | 
          
| 2060 | break; // locate the kernel directory entry (can't fail)  | 
            2119 | break; // locate the kernel directory entry (can't fail)  | 
          
| 2061 | fsentries[fsentry_index].u.file.offset = (uint32_t) (ifs.data.size - ifs.offsets.imageheader); // save file data blob offset in file structure  | 
            2120 | fsentries[fsentry_index].u.file.offset = (uint32_t) (ifs.data.size - ifs.offsets.imageheader); // save file data blob offset in file structure  | 
          
| 2062 | #ifdef PROCNTO_WIP | 
            - | |
| 2063 |       // is the kernel we're storing a preprocessed ELF kernel ? | 
            - | |
| 2064 | if (fsentries[fsentry_index].header.ino & IFS_INO_PROCESSED_ELF)  | 
            - | |
| 2065 |       { | 
            - | |
| 2066 | elf = (elf_header_t *) fsentries[fsentry_index].u.file.UNSAVED_databuf; // quick access to ELF header  | 
            - | |
| 2067 | table_count = ELF_GET_NUMERIC (elf, elf, program_header_table_len); // get the number of program headers  | 
            - | |
| 2068 | for (table_index = 0; table_index < table_count; table_index++)  | 
            - | |
| 2069 |          { | 
            - | |
| 2070 | phdr = (elf_program_header_t *) &fsentries[fsentry_index].u.file.UNSAVED_databuf[ELF_GET_NUMERIC (elf, elf, program_header_table_offset) + (size_t) ELF_GET_NUMERIC (elf, elf, program_header_item_size) * table_index]; // quick access to program header  | 
            - | |
| 2071 | corrective_offset = ELF_GET_NUMERIC (elf, phdr, virtual_addr) - ELF_GET_NUMERIC (elf, phdr, file_offset);  | 
            - | |
| 2072 | if (ELF_GET_NUMERIC (elf, phdr, size_in_memory) != 0) // only patch the physical address of segments that have an actual size in memory  | 
            - | |
| 2073 | ELF_SET_NUMERIC (elf, phdr, physical_addr, ELF_GET_NUMERIC (elf, phdr, physical_addr) + image_base + ifs.data.size - corrective_offset); // patch the physical address member of the program header table (NOTE: ifs.data.size is the location where the file data is about to be written)  | 
            - | |
| 2074 |          } | 
            - | |
| 2075 |       } | 
            - | |
| 2076 | #endif // PROCNTO_WIP | 
            - | |
| 2077 | Buffer_AppendIFSFileData (&ifs.data, &fsentries[fsentry_index]); // write kernel file data  | 
            2121 | Buffer_AppendIFSFileData (&ifs.data, &fsentries[fsentry_index]); // write kernel file data  | 
          
| 2078 | fsentries[fsentry_index].UNSAVED_was_data_written = true; // and remember this file's data was written  | 
            2122 | fsentries[fsentry_index].UNSAVED_was_data_written = true; // and remember this file's data was written  | 
          
| 2079 |    } | 
            2123 |    } | 
          
| 2080 | 2124 | ||
| 2081 |    // then write all the other files by increasing inode number: ELF files first | 
            2125 |    // then write all the other files by increasing inode number: ELF files first |