Rev 22 | Rev 25 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
| Rev 22 | Rev 24 | ||
|---|---|---|---|
| Line 162... | Line 162... | ||
| 162 | 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 |
162 | 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 |
| 163 | 163 | ||
| 164 | 164 | ||
| 165 | // prototypes of local functions |
165 | // prototypes of local functions |
| 166 | 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) |
166 | 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) |
| - | 167 | static char *resolve_envvars (const char *str); // resolves environment variables in str and replaces them with their value, or an empty string if undefined. Returns a mallocated string (caller frees) |
|
| 167 | 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) |
168 | 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) |
| 168 | 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 |
169 | 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 |
| 169 | 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 |
170 | 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 |
| 170 | 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 |
171 | 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 |
| 171 | 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 |
172 | 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 |
| Line 219... | Line 220... | ||
| 219 | else if ((*endptr == 'm') || (*endptr == 'M')) ret *= (size_t) 1024 * 1024; |
220 | else if ((*endptr == 'm') || (*endptr == 'M')) ret *= (size_t) 1024 * 1024; |
| 220 | else if ((*endptr == 'g') || (*endptr == 'G')) ret *= (size_t) 1024 * 1024 * 1024; |
221 | else if ((*endptr == 'g') || (*endptr == 'G')) ret *= (size_t) 1024 * 1024 * 1024; |
| 221 | else if ((*endptr == 't') || (*endptr == 'T')) ret *= (size_t) 1024 * 1024 * 1024 * 1024; // future-proof enough, I suppose? |
222 | else if ((*endptr == 't') || (*endptr == 'T')) ret *= (size_t) 1024 * 1024 * 1024 * 1024; // future-proof enough, I suppose? |
| 222 | } |
223 | } |
| 223 | return (ret); |
224 | return (ret); |
| - | 225 | } |
|
| - | 226 | ||
| - | 227 | ||
| - | 228 | static char *resolve_envvars (const char *str) |
|
| - | 229 | { |
|
| - | 230 | // resolves environment variables in str and replaces them with their value, or an empty string if undefined |
|
| - | 231 | // returns a mallocated string (caller frees), or dies with errno |
|
| - | 232 | ||
| - | 233 | signed int erase_index; |
|
| - | 234 | void *reallocated_ptr; |
|
| - | 235 | size_t replacement_len; |
|
| - | 236 | size_t middlebit_len; |
|
| - | 237 | size_t old_str_len; |
|
| - | 238 | size_t new_str_len; |
|
| - | 239 | size_t endbit_len; |
|
| - | 240 | char erased_char; |
|
| - | 241 | char *resolved_str; |
|
| - | 242 | char *replacement; |
|
| - | 243 | char *varname; |
|
| - | 244 | char *endbit; |
|
| - | 245 | char *token; |
|
| - | 246 | ||
| - | 247 | resolved_str = strdup (str); // have a working copy of the input string |
|
| - | 248 | ASSERT_WITH_ERRNO (resolved_str); |
|
| - | 249 | while ((((token = strstr (resolved_str, "${")) != NULL) && ((endbit = strchr (token, '}')) != NULL)) // look for variables in the "${VARNAME}" format *AND* in "$VARNAME" format |
|
| - | 250 | || (((token = strstr (resolved_str, "$")) != NULL) && ((middlebit_len = strspn (token, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_")) != strlen (token)))) |
|
| - | 251 | { |
|
| - | 252 | if (token[1] == '{') // "${VARNAME}" format |
|
| - | 253 | { |
|
| - | 254 | endbit++; // locate where the end bit begins |
|
| - | 255 | varname = token + 2; // skip the leading two characters: "${" |
|
| - | 256 | erase_index = -1; // we shall split the string at the character that's *just before* where the end bit starts |
|
| - | 257 | } |
|
| - | 258 | else // "$VARNAME" format |
|
| - | 259 | { |
|
| - | 260 | endbit = &token[middlebit_len]; // locate where the end bit begins |
|
| - | 261 | varname = token + 1; // skip the leading '$' |
|
| - | 262 | erase_index = 0; // we shall split the string at the character that's *right where* the end bit starts |
|
| - | 263 | } |
|
| - | 264 | old_str_len = strlen (resolved_str); // measure current string length |
|
| - | 265 | endbit_len = strlen (endbit); // measure the length of the end bit (skip the closing curly brace) |
|
| - | 266 | erased_char = endbit[erase_index]; // remember which is the character we're going to erase |
|
| - | 267 | endbit[erase_index] = 0; // split the string at the end of the variable name |
|
| - | 268 | if (strcmp (varname, "PFS") == 0) |
|
| - | 269 | replacement = PATH_SEP; // special case: if it's the PFS variable, select ":" or ";" based on the host platform |
|
| - | 270 | else |
|
| - | 271 | replacement = getenv (varname); // peek at the environment for its value |
|
| - | 272 | if (replacement == NULL) |
|
| - | 273 | replacement = ""; // if this variable isn't defined, fallback to an empty string, just like what a UNIX shell does |
|
| - | 274 | endbit[erase_index] = erased_char; // put the erased character back |
|
| - | 275 | replacement_len = strlen (replacement); // measure replacement length |
|
| - | 276 | new_str_len = (size_t) token - (size_t) resolved_str + replacement_len + endbit_len; // measure updated string len |
|
| - | 277 | if (new_str_len > old_str_len) |
|
| - | 278 | { |
|
| - | 279 | reallocated_ptr = realloc (resolved_str, new_str_len + 1); // grow it if necessary |
|
| - | 280 | ASSERT_WITH_ERRNO (reallocated_ptr); |
|
| - | 281 | token = &((char *) reallocated_ptr)[token - resolved_str]; // fix the pointers that may have moved |
|
| - | 282 | endbit = &((char *) reallocated_ptr)[endbit - resolved_str]; // fix the pointers that may have moved |
|
| - | 283 | resolved_str = reallocated_ptr; |
|
| - | 284 | } |
|
| - | 285 | memmove (token + replacement_len, endbit, endbit_len + 1); // move the end bit to its final location (including its nul terminator) |
|
| - | 286 | memcpy (token, replacement, replacement_len); // and patch the replacement in between |
|
| - | 287 | } |
|
| - | 288 | ||
| - | 289 | return (resolved_str); // finished, return the mallocated resolved string (caller frees) |
|
| 224 | } |
290 | } |
| 225 | 291 | ||
| 226 | 292 | ||
| 227 | static char *resolve_pathname (const char *pathname, const char *search_paths_or_NULL_for_MKIFS_PATH_envvar) |
293 | static char *resolve_pathname (const char *pathname, const char *search_paths_or_NULL_for_MKIFS_PATH_envvar) |
| 228 | { |
294 | { |
| Line 242... | Line 308... | ||
| 242 | { false, "/lib/dll" }, // prefix with $PROCESSOR/ |
308 | { false, "/lib/dll" }, // prefix with $PROCESSOR/ |
| 243 | { false, "/usr/lib" } // prefix with $PROCESSOR/ |
309 | { false, "/usr/lib" } // prefix with $PROCESSOR/ |
| 244 | }; |
310 | }; |
| 245 | static thread_local char *resolved_pathname = NULL; |
311 | static thread_local char *resolved_pathname = NULL; |
| 246 | 312 | ||
| 247 |
|
313 | char *pathname_without_envvars; |
| 248 | char *resolved_search_path; |
314 | char *resolved_search_path; |
| 249 | char *replacement; |
- | |
| 250 | size_t old_searchpath_len; |
- | |
| 251 | size_t new_searchpath_len; |
- | |
| 252 | size_t replacement_len; |
- | |
| 253 | size_t middlebit_len; |
- | |
| 254 | size_t endbit_len; |
- | |
| 255 | size_t defaultpath_index; |
315 | size_t defaultpath_index; |
| 256 | struct stat stat_buf; |
316 | struct stat stat_buf; |
| 257 | int erase_index; |
- | |
| 258 | char erased_char; |
- | |
| 259 | char *varname; |
- | |
| 260 | char *nextsep; |
317 | char *nextsep; |
| 261 | char *endbit; |
- | |
| 262 | char *token; |
318 | char *token; |
| 263 | 319 | ||
| 264 | // initial allocation (per thread) |
- | |
| 265 | if (resolved_pathname == NULL) |
- | |
| 266 | { |
- | |
| 267 |
|
320 | // resolve possible environment variables in pathname |
| 268 |
|
321 | pathname_without_envvars = resolve_envvars (pathname); |
| 269 | } |
- | |
| 270 | 322 | ||
| 271 | // is it an absolute pathname (POSIX and Windows variants) ? |
323 | // is it an absolute pathname (POSIX and Windows variants) OR a relative pathname ? |
| 272 | if (IS_DIRSEP (pathname[0]) |
324 | if (IS_DIRSEP (pathname[0]) |
| 273 | #ifdef _WIN32 |
325 | #ifdef _WIN32 |
| 274 | || (isalpha (pathname[0]) && (pathname[1] == ':') && IS_DIRSEP (pathname[2])) |
326 | || (isalpha (pathname[0]) && (pathname[1] == ':') && IS_DIRSEP (pathname[2])) |
| - | 327 | || (strchr (pathname, '\\') != NULL) |
|
| 275 | #endif // _WIN32 |
328 | #endif // _WIN32 |
| - | 329 | || (strchr (pathname, '/') != NULL) |
|
| 276 | ) |
330 | ) |
| 277 |
|
331 | return (pathname_without_envvars); // in this case, it MUST exist at its designated location (either absolute or relative to the current working directory) |
| 278 | else // |
332 | else // what we've been given is just a basename, so search it among the search paths we have |
| 279 | { |
333 | { |
| 280 | // QNX docs: |
334 | // QNX docs: |
| 281 | // When searching for host files to be included in the image, search |
335 | // When searching for host files to be included in the image, search the default paths used for storing binaries within the specified directory before searching the default paths within $QNX_TARGET. |
| 282 | // the default paths used for storing binaries within the specified |
- | |
| 283 | // directory before searching the default paths within $QNX_TARGET. |
- | |
| 284 | // You can define multiple -r options; each adds a set of paths to |
336 | // You can define multiple -r options; each adds a set of paths to search for files. |
| 285 | // search for files. The -r options are evaluated from left to right |
- | |
| 286 | // meaning the paths prefixed with the first (leftmost) rootdir are |
337 | // The -r options are evaluated from left to right meaning the paths prefixed with the first (leftmost) rootdir are searched first, then those prefixed with the second rootdir, and so on. |
| 287 | // searched first, then those prefixed with the second rootdir, and |
- | |
| 288 | // so on. |
- | |
| 289 | // Normally, mkifs searches any paths defined in $MKIFS_PATH when |
338 | // Normally, mkifs searches any paths defined in $MKIFS_PATH when it was called and then the default paths within $QNX_TARGET. |
| 290 | // it was called and then the default paths within $QNX_TARGET. The |
- | |
| 291 | // default paths are based on the CPU architecture specified by |
339 | // The default paths are based on the CPU architecture specified by $PROCESSOR and $PROCESSOR_BASE. |
| 292 | // $PROCESSOR and $PROCESSOR_BASE. If you specify -r options, mkifs |
- | |
| 293 | // searches the default paths prefixed with each dir variable before |
340 | // If you specify -r options, mkifs searches the default paths prefixed with each dir variable before searching those within $QNX_TARGET. |
| 294 | // |
341 | // These paths are: |
| 295 | // dir/${PROCESSOR}/sbin |
342 | // dir/${PROCESSOR}/sbin |
| 296 | // dir/${PROCESSOR}/usr/sbin |
343 | // dir/${PROCESSOR}/usr/sbin |
| 297 | // dir/${PROCESSOR}/boot/sys |
344 | // dir/${PROCESSOR}/boot/sys |
| 298 | // dir/${PROCESSOR_BASE}/boot/sys |
345 | // dir/${PROCESSOR_BASE}/boot/sys |
| 299 | // dir/${PROCESSOR}/bin |
346 | // dir/${PROCESSOR}/bin |
| 300 | // dir/${PROCESSOR}/usr/bin |
347 | // dir/${PROCESSOR}/usr/bin |
| 301 | // dir/${PROCESSOR}/lib |
348 | // dir/${PROCESSOR}/lib |
| 302 | // dir/${PROCESSOR}/lib/dll |
349 | // dir/${PROCESSOR}/lib/dll |
| 303 | // dir/${PROCESSOR}/usr/lib |
350 | // dir/${PROCESSOR}/usr/lib |
| 304 | // NOTE: The structure of the directory paths under dir must be |
- | |
| 305 | // identical to that of the default paths under $QNX_TARGET, but the |
351 | // NOTE: The structure of the directory paths under dir must be identical to that of the default paths under $QNX_TARGET, but the root dir itself may be any path you choose. |
| 306 | // root dir itself may be any path you choose. For example, if you |
- | |
| 307 | // wanted to include /scratch/aarch64le/sbin/devb-sata, you would |
352 | // For example, if you wanted to include /scratch/aarch64le/sbin/devb-sata, you would specify a -r option like this: |
| 308 | // specify a -r option like this: |
- | |
| 309 | // -r /scratch |
353 | // -r /scratch |
| 310 | // Note that you don't include $PROCESSOR or $PROCESSOR_BASE in dir. |
354 | // Note that you don't include $PROCESSOR or $PROCESSOR_BASE in dir. |
| 311 | 355 | ||
| 312 | // - search all paths in explicit path/[default paths] (if explicit path supplied) |
356 | // - search all paths in explicit path/[default paths] (if explicit path supplied) |
| 313 | // - search all paths in (-r flags if have some|MKIFS_PATH)/[default paths] (if no explicit path supplied) |
357 | // - search all paths in (-r flags if have some|MKIFS_PATH)/[default paths] (if no explicit path supplied) |
| 314 | // - search all paths in $QNX_TARGET/[default paths] |
358 | // - search all paths in $QNX_TARGET/[default paths] |
| - | 359 | ||
| - | 360 | // initial allocation (per thread) |
|
| - | 361 | if (resolved_pathname == NULL) |
|
| - | 362 | { |
|
| - | 363 | resolved_pathname = malloc (MAXPATHLEN); |
|
| - | 364 | ASSERT_WITH_ERRNO (resolved_pathname); |
|
| - | 365 | } |
|
| 315 | 366 | ||
| 316 | // if no file-specific explicit search path was supplied, use the path list supplied by the -r command-line arguments, else fallback to MKIFS_PATH if we don't have any |
367 | // if no file-specific explicit search path was supplied, use the path list supplied by the -r command-line arguments, else fallback to MKIFS_PATH if we don't have any |
| 317 | if (search_paths_or_NULL_for_MKIFS_PATH_envvar == NULL) |
368 | if (search_paths_or_NULL_for_MKIFS_PATH_envvar == NULL) |
| 318 | search_paths_or_NULL_for_MKIFS_PATH_envvar = (SEARCH_PATH != NULL ? SEARCH_PATH : getenv ("MKIFS_PATH")); |
369 | search_paths_or_NULL_for_MKIFS_PATH_envvar = (SEARCH_PATH != NULL ? SEARCH_PATH : getenv ("MKIFS_PATH")); |
| 319 | 370 | ||
| 320 | // construct a potential final path using each element of the search path |
371 | // construct a potential final path using each element of the search path |
| 321 | if (search_paths_or_NULL_for_MKIFS_PATH_envvar != NULL) |
372 | if (search_paths_or_NULL_for_MKIFS_PATH_envvar != NULL) |
| 322 | { |
373 | { |
| 323 | // the first step is to resolve all environment variables in the search path |
374 | // the first step is to resolve all environment variables in the search path |
| 324 | resolved_search_path = |
375 | resolved_search_path = resolve_envvars (search_paths_or_NULL_for_MKIFS_PATH_envvar); |
| 325 | ASSERT_WITH_ERRNO (resolved_search_path); |
- | |
| 326 | while ((((token = strstr (resolved_search_path, "${")) != NULL) && ((endbit = strchr (token, '}')) != NULL)) // look for variables in the "${VARNAME}" format *AND* in "$VARNAME" format |
- | |
| 327 | || (((token = strstr (resolved_search_path, "$")) != NULL) && ((middlebit_len = strspn (token, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_")) != strlen (token)))) |
- | |
| 328 | { |
- | |
| 329 | if (token[1] == '{') // "${VARNAME}" format |
- | |
| 330 | { |
- | |
| 331 | endbit++; // locate where the end bit begins |
- | |
| 332 | varname = token + 2; // skip the leading two characters: "${" |
- | |
| 333 | erase_index = -1; // we shall split the string at the character that's *just before* where the end bit starts |
- | |
| 334 | } |
- | |
| 335 | else // "$VARNAME" format |
- | |
| 336 | { |
- | |
| 337 | endbit = &token[middlebit_len]; // locate where the end bit begins |
- | |
| 338 | varname = token + 1; // skip the leading '$' |
- | |
| 339 | erase_index = 0; // we shall split the string at the character that's *right where* the end bit starts |
- | |
| 340 | } |
- | |
| 341 | old_searchpath_len = strlen (resolved_search_path); // measure current string length |
- | |
| 342 | endbit_len = strlen (endbit); // measure the length of the end bit (skip the closing curly brace) |
- | |
| 343 | erased_char = endbit[erase_index]; // remember which is the character we're going to erase |
- | |
| 344 | endbit[erase_index] = 0; // split the string at the end of the variable name |
- | |
| 345 | replacement = getenv (varname); // peek at the environment for its value |
- | |
| 346 | if (replacement == NULL) |
- | |
| 347 | replacement = ""; // if this variable isn't defined, fallback to an empty string, just like what a UNIX shell does |
- | |
| 348 | endbit[erase_index] = erased_char; // put the erased character back |
- | |
| 349 | replacement_len = strlen (replacement); // measure replacement length |
- | |
| 350 | new_searchpath_len = (size_t) token - (size_t) resolved_search_path + replacement_len + endbit_len; // measure updated search path len |
- | |
| 351 | if (new_searchpath_len > old_searchpath_len) |
- | |
| 352 | { |
- | |
| 353 | reallocated_ptr = realloc (resolved_search_path, new_searchpath_len + 1); // grow it if necessary |
- | |
| 354 | ASSERT_WITH_ERRNO (reallocated_ptr); |
- | |
| 355 | token = &((char *) reallocated_ptr)[token - resolved_search_path]; // fix the pointers that may have moved |
- | |
| 356 | endbit = &((char *) reallocated_ptr)[endbit - resolved_search_path]; // fix the pointers that may have moved |
- | |
| 357 | resolved_search_path = reallocated_ptr; |
- | |
| 358 | } |
- | |
| 359 | memmove (token + replacement_len, endbit, endbit_len + 1); // move the end bit to its final location (including its nul terminator) |
- | |
| 360 | memcpy (token, replacement, replacement_len); // and patch the replacement in between |
- | |
| 361 | } |
- | |
| 362 | 376 | ||
| 363 | // now split this search path string into multiple tokens and process them one after the other |
377 | // now split this search path string into multiple tokens and process them one after the other |
| 364 | token = (*resolved_search_path != 0 ? resolved_search_path : NULL); |
378 | token = (*resolved_search_path != 0 ? resolved_search_path : NULL); |
| 365 | nextsep = (token != NULL ? &token[strcspn (token, PATH_SEP)] : NULL); |
379 | nextsep = (token != NULL ? &token[strcspn (token, PATH_SEP)] : NULL); |
| 366 | while (token != NULL) |
380 | while (token != NULL) |
| 367 | { |
381 | { |
| 368 | // look under this search path at each of the known subpaths |
382 | // look under this search path at each of the known subpaths |
| 369 | for (defaultpath_index = 0; defaultpath_index < sizeof (default_paths) / sizeof (default_paths[0]); defaultpath_index++) |
383 | for (defaultpath_index = 0; defaultpath_index < sizeof (default_paths) / sizeof (default_paths[0]); defaultpath_index++) |
| 370 | { |
384 | { |
| 371 | sprintf_s (resolved_pathname, MAXPATHLEN, "%.*s/%s/%s/%s", (int) (nextsep - token), token, (default_paths[defaultpath_index].uses_processor_base ? image_processor_base : image_processor), default_paths[defaultpath_index].subpath, |
385 | sprintf_s (resolved_pathname, MAXPATHLEN, "%.*s/%s/%s/%s", (int) (nextsep - token), token, (default_paths[defaultpath_index].uses_processor_base ? image_processor_base : image_processor), default_paths[defaultpath_index].subpath, pathname_without_envvars); |
| 372 | if ((stat (resolved_pathname, &stat_buf) == 0) && S_ISREG (stat_buf.st_mode)) |
386 | if ((stat (resolved_pathname, &stat_buf) == 0) && S_ISREG (stat_buf.st_mode)) |
| - | 387 | { |
|
| - | 388 | free (pathname_without_envvars); |
|
| 373 | return (resolved_pathname); // if a file can indeed be found at this location, stop searching |
389 | return (resolved_pathname); // if a file can indeed be found at this location, stop searching |
| - | 390 | } |
|
| 374 | } |
391 | } |
| 375 | 392 | ||
| 376 | token = (*nextsep != 0 ? nextsep + 1 : NULL); |
393 | token = (*nextsep != 0 ? nextsep + 1 : NULL); |
| 377 | nextsep = (token != NULL ? &token[strcspn (token, PATH_SEP)] : NULL); |
394 | nextsep = (token != NULL ? &token[strcspn (token, PATH_SEP)] : NULL); |
| 378 | } |
395 | } |
| 379 | } |
396 | } |
| 380 | 397 | ||
| 381 | // file not found in search paths: look under QNX_TARGET at each of the known subpaths |
398 | // file not found in search paths: look under QNX_TARGET at each of the known subpaths |
| 382 | for (defaultpath_index = 0; defaultpath_index < sizeof (default_paths) / sizeof (default_paths[0]); defaultpath_index++) |
399 | for (defaultpath_index = 0; defaultpath_index < sizeof (default_paths) / sizeof (default_paths[0]); defaultpath_index++) |
| 383 | { |
400 | { |
| 384 | sprintf_s (resolved_pathname, MAXPATHLEN, "%s/%s/%s/%s", QNX_TARGET, (default_paths[defaultpath_index].uses_processor_base ? image_processor_base : image_processor), default_paths[defaultpath_index].subpath, |
401 | sprintf_s (resolved_pathname, MAXPATHLEN, "%s/%s/%s/%s", QNX_TARGET, (default_paths[defaultpath_index].uses_processor_base ? image_processor_base : image_processor), default_paths[defaultpath_index].subpath, pathname_without_envvars); |
| 385 | if ((stat (resolved_pathname, &stat_buf) == 0) && S_ISREG (stat_buf.st_mode)) |
402 | if ((stat (resolved_pathname, &stat_buf) == 0) && S_ISREG (stat_buf.st_mode)) |
| - | 403 | { |
|
| - | 404 | free (pathname_without_envvars); |
|
| 386 | return (resolved_pathname); // if a file can indeed be found at this location, stop searching |
405 | return (resolved_pathname); // if a file can indeed be found at this location, stop searching |
| - | 406 | } |
|
| 387 | } |
407 | } |
| 388 | } |
408 | } |
| 389 | 409 | ||
| - | 410 | free (pathname_without_envvars); |
|
| 390 | errno = ENOENT; // we exhausted all possibilities |
411 | errno = ENOENT; // we exhausted all possibilities |
| 391 | return (NULL); // file not found, return with ENOENT |
412 | return (NULL); // file not found, return with ENOENT |
| 392 | } |
413 | } |
| 393 | 414 | ||
| 394 | 415 | ||
| Line 752... | Line 773... | ||
| 752 | static thread_local stringarray_t aps_partnames = { NULL, 0 }; |
773 | static thread_local stringarray_t aps_partnames = { NULL, 0 }; |
| 753 | static int inode_count = 0; // will be preincremented each time this function is called |
774 | static int inode_count = 0; // will be preincremented each time this function is called |
| 754 | 775 | ||
| 755 | typedef struct scriptcmd_s |
776 | typedef struct scriptcmd_s |
| 756 | { |
777 | { |
| 757 |
|
778 | char *argv0; |
| 758 | int cpu_number; |
779 | int cpu_number; |
| 759 | bool is_external; |
780 | bool is_external; |
| 760 | int priority; |
781 | int priority; |
| 761 | int sched_policy; |
782 | int sched_policy; |
| 762 | int aps_partindex; |
783 | int aps_partindex; |
| Line 810... | Line 831... | ||
| 810 | ASSERT_WITH_ERRNO (candidate_pathname); |
831 | ASSERT_WITH_ERRNO (candidate_pathname); |
| 811 | } |
832 | } |
| 812 | 833 | ||
| 813 | if (S_ISDIR (entry_parms->st_mode)) // are we storing a directory ? |
834 | if (S_ISDIR (entry_parms->st_mode)) // are we storing a directory ? |
| 814 | { |
835 | { |
| 815 | if (buildhost_pathname != NULL) // was a source file pathname supplied ? |
836 | if ((buildhost_pathname != NULL) && (buildhost_pathname[0] != 0)) // was a source file pathname supplied ? |
| 816 | { |
837 | { |
| 817 | memcpy (&default_parms, entry_parms, sizeof (parms_t)); // apply current entry parameters when including a directory recursively |
838 | memcpy (&default_parms, entry_parms, sizeof (parms_t)); // apply current entry parameters when including a directory recursively |
| 818 | add_directory_contents_recursively (fsentries, fsentry_count, buildhost_pathname, strlen (buildhost_pathname), &default_parms); // if so, add this diretory contents recursively |
839 | add_directory_contents_recursively (fsentries, fsentry_count, buildhost_pathname, strlen (buildhost_pathname), &default_parms); // if so, add this diretory contents recursively |
| 819 | } |
840 | } |
| 820 | 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); |
841 | 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); |
| Line 1348... | Line 1369... | ||
| 1348 | LOG_INFO ("changing default " descr " from " fmt " to " fmt " by attribute at \"%s\" line %zd of inline document '%s'", default_scriptcmd_params.attr, current_scriptcmd_params.attr, buildfile_pathname, 1 + line_index, stored_pathname); \ |
1369 | LOG_INFO ("changing default " descr " from " fmt " to " fmt " by attribute at \"%s\" line %zd of inline document '%s'", default_scriptcmd_params.attr, current_scriptcmd_params.attr, buildfile_pathname, 1 + line_index, stored_pathname); \ |
| 1349 | default_scriptcmd_params.attr = current_scriptcmd_params.attr; \ |
1370 | default_scriptcmd_params.attr = current_scriptcmd_params.attr; \ |
| 1350 | } } while (0) |
1371 | } } while (0) |
| 1351 | #define APPLY_DEFAULT_ATTR_STR(attr,descr,fmt) do { if (((default_scriptcmd_params.attr == NULL) && (current_scriptcmd_params.attr != NULL)) || ((default_scriptcmd_params.attr != NULL) && (current_scriptcmd_params.attr == NULL)) || ((default_scriptcmd_params.attr != NULL) && (current_scriptcmd_params.attr != NULL) && (strcmp (current_scriptcmd_params.attr, default_scriptcmd_params.attr) != 0))) { \ |
1372 | #define APPLY_DEFAULT_ATTR_STR(attr,descr,fmt) do { if (((default_scriptcmd_params.attr == NULL) && (current_scriptcmd_params.attr != NULL)) || ((default_scriptcmd_params.attr != NULL) && (current_scriptcmd_params.attr == NULL)) || ((default_scriptcmd_params.attr != NULL) && (current_scriptcmd_params.attr != NULL) && (strcmp (current_scriptcmd_params.attr, default_scriptcmd_params.attr) != 0))) { \ |
| 1352 | LOG_INFO ("changing default " descr " from " fmt " to " fmt " by attribute at \"%s\" line %zd of inline document '%s'", (default_scriptcmd_params.attr != NULL ? default_scriptcmd_params.attr : "none"), current_scriptcmd_params.attr, buildfile_pathname, 1 + line_index, stored_pathname); \ |
1373 | LOG_INFO ("changing default " descr " from " fmt " to " fmt " by attribute at \"%s\" line %zd of inline document '%s'", (default_scriptcmd_params.attr != NULL ? default_scriptcmd_params.attr : "none"), current_scriptcmd_params.attr, buildfile_pathname, 1 + line_index, stored_pathname); \ |
| - | 1374 | if (default_scriptcmd_params.attr != NULL) free (default_scriptcmd_params.attr); \ |
|
| - | 1375 | default_scriptcmd_params.attr = strdup (current_scriptcmd_params.attr); \ |
|
| - | 1376 | ASSERT_WITH_ERRNO (default_scriptcmd_params.attr != NULL); \ |
|
| 1353 | default_scriptcmd_params.attr = current_scriptcmd_params.attr; \ |
1377 | default_scriptcmd_params.attr = current_scriptcmd_params.attr; \ |
| 1354 | } } while (0) |
1378 | } } while (0) |
| 1355 | APPLY_DEFAULT_ATTR_STR (argv0, "executable name", "\"%s\""); |
1379 | APPLY_DEFAULT_ATTR_STR (argv0, "executable name", "\"%s\""); |
| 1356 | APPLY_DEFAULT_ATTR_NUM (cpu_number, "CPU mask", "0%o"); |
1380 | APPLY_DEFAULT_ATTR_NUM (cpu_number, "CPU mask", "0%o"); |
| 1357 | APPLY_DEFAULT_ATTR_NUM (is_external, "external command flag", "0%o"); |
1381 | APPLY_DEFAULT_ATTR_NUM (is_external, "external command flag", "0%o"); |
| Line 1771... | Line 1795... | ||
| 1771 | LOG_INFO ("changing default " descr " from " fmt " to " fmt " by attribute at \"%s\" line %d", default_parms->attr, entry_parms.attr, buildfile_pathname, lineno); \ |
1795 | LOG_INFO ("changing default " descr " from " fmt " to " fmt " by attribute at \"%s\" line %d", default_parms->attr, entry_parms.attr, buildfile_pathname, lineno); \ |
| 1772 | default_parms->attr = entry_parms.attr; \ |
1796 | default_parms->attr = entry_parms.attr; \ |
| 1773 | } } while (0) |
1797 | } } while (0) |
| 1774 | #define APPLY_DEFAULT_ATTR_STR(attr,descr,fmt) do { if (((default_parms->attr == NULL) && (entry_parms.attr != NULL)) || ((default_parms->attr != NULL) && (entry_parms.attr == NULL)) || ((default_parms->attr != NULL) && (entry_parms.attr != NULL) && (strcmp (entry_parms.attr, default_parms->attr) != 0))) { \ |
1798 | #define APPLY_DEFAULT_ATTR_STR(attr,descr,fmt) do { if (((default_parms->attr == NULL) && (entry_parms.attr != NULL)) || ((default_parms->attr != NULL) && (entry_parms.attr == NULL)) || ((default_parms->attr != NULL) && (entry_parms.attr != NULL) && (strcmp (entry_parms.attr, default_parms->attr) != 0))) { \ |
| 1775 | LOG_INFO ("changing default " descr " from " fmt " to " fmt " by attribute at \"%s\" line %d", (default_parms->attr != NULL ? default_parms->attr : "none"), entry_parms.attr, buildfile_pathname, lineno); \ |
1799 | LOG_INFO ("changing default " descr " from " fmt " to " fmt " by attribute at \"%s\" line %d", (default_parms->attr != NULL ? default_parms->attr : "none"), entry_parms.attr, buildfile_pathname, lineno); \ |
| - | 1800 | if (default_parms->attr != NULL) free (default_parms->attr); \ |
|
| 1776 | default_parms->attr = entry_parms.attr; \ |
1801 | default_parms->attr = strdup (entry_parms.attr); \ |
| - | 1802 | ASSERT_WITH_ERRNO (default_parms->attr != NULL); \ |
|
| 1777 | } } while (0) |
1803 | } } while (0) |
| 1778 | //APPLY_DEFAULT_ATTR_STR (new_cwd, "current working directory", "\"%s\""); |
1804 | //APPLY_DEFAULT_ATTR_STR (new_cwd, "current working directory", "\"%s\""); |
| 1779 | APPLY_DEFAULT_ATTR_STR (search, "search path list", "\"%s\""); |
1805 | APPLY_DEFAULT_ATTR_STR (search, "search path list", "\"%s\""); |
| 1780 | APPLY_DEFAULT_ATTR_STR (prefix, "prefix", "\"%s\""); |
1806 | APPLY_DEFAULT_ATTR_STR (prefix, "prefix", "\"%s\""); |
| 1781 | APPLY_DEFAULT_ATTR_NUM (dperms, "directory permissions", "0%o"); |
1807 | APPLY_DEFAULT_ATTR_NUM (dperms, "directory permissions", "0%o"); |
| Line 1809... | Line 1835... | ||
| 1809 | if (*line_ptr == '/') |
1835 | if (*line_ptr == '/') |
| 1810 | { |
1836 | { |
| 1811 | LOG_WARNING ("paths in the IFS file should not begin with a leading '/' in \"%s\" line %d", buildfile_pathname, lineno); |
1837 | LOG_WARNING ("paths in the IFS file should not begin with a leading '/' in \"%s\" line %d", buildfile_pathname, lineno); |
| 1812 | line_ptr++; // consistency check: paths in the IFS should not begin with a '/' |
1838 | line_ptr++; // consistency check: paths in the IFS should not begin with a '/' |
| 1813 | } |
1839 | } |
| 1814 | while ((*line_ptr != 0) && ((!is_quoted_context && (*line_ptr != '=') && !isspace (*line_ptr)) || (is_quoted_context && (*line_ptr |
1840 | while ((*line_ptr != 0) && ((!is_quoted_context && (*line_ptr != '=') && !isspace (*line_ptr)) || (is_quoted_context && (*line_ptr != '"')))) |
| 1815 | { |
1841 | { |
| 1816 | if (*line_ptr == '\\') |
1842 | if (*line_ptr == '\\') |
| 1817 | { |
1843 | { |
| 1818 | line_ptr++; |
1844 | line_ptr++; |
| 1819 | *write_ptr++ = *line_ptr; // unescape characters that are escaped with '\' |
1845 | *write_ptr++ = *line_ptr; // unescape characters that are escaped with '\' |
| Line 1883... | Line 1909... | ||
| 1883 | is_quoted_context = (*line_ptr == '"'); |
1909 | is_quoted_context = (*line_ptr == '"'); |
| 1884 | if (is_quoted_context) |
1910 | if (is_quoted_context) |
| 1885 | line_ptr++; // skip a possible initial quote |
1911 | line_ptr++; // skip a possible initial quote |
| 1886 | specifiedpathname_start = line_ptr; // remember where the specified pathname starts |
1912 | specifiedpathname_start = line_ptr; // remember where the specified pathname starts |
| 1887 | write_ptr = line_ptr; // now unescape all characters |
1913 | write_ptr = line_ptr; // now unescape all characters |
| 1888 | while ((*line_ptr != 0) && ((!is_quoted_context && !isspace (*line_ptr)) || (is_quoted_context && (*line_ptr |
1914 | while ((*line_ptr != 0) && ((!is_quoted_context && !isspace (*line_ptr)) || (is_quoted_context && (*line_ptr != '"')))) |
| 1889 | { |
1915 | { |
| 1890 | if (*line_ptr == '\\') |
1916 | if (*line_ptr == '\\') |
| 1891 | { |
1917 | { |
| 1892 | line_ptr++; |
1918 | line_ptr++; |
| 1893 | *write_ptr++ = *line_ptr; // unescape characters that are escaped with '\' |
1919 | *write_ptr++ = *line_ptr; // unescape characters that are escaped with '\' |
| Line 1966... | Line 1992... | ||
| 1966 | parms_t default_parms = { // default parameters for a filesystem entry |
1992 | parms_t default_parms = { // default parameters for a filesystem entry |
| 1967 | .dperms = 0755, |
1993 | .dperms = 0755, |
| 1968 | .perms = 0644, |
1994 | .perms = 0644, |
| 1969 | .mtime = UINT32_MAX, |
1995 | .mtime = UINT32_MAX, |
| 1970 | .mtime_for_inline_files = UINT32_MAX, |
1996 | .mtime_for_inline_files = UINT32_MAX, |
| 1971 | .prefix = |
1997 | .prefix = NULL, // will be initialized to a *mallocated* string: "/proc/boot" |
| 1972 | .should_follow_symlinks = true, // [+|-followlink] |
1998 | .should_follow_symlinks = true, // [+|-followlink] |
| 1973 | .should_autosymlink_dylib = true, // [+|-autolink] |
1999 | .should_autosymlink_dylib = true, // [+|-autolink] |
| 1974 | }; |
2000 | }; |
| 1975 | 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) |
2001 | 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) |
| 1976 | 2002 | ||
| Line 2012... | Line 2038... | ||
| 2012 | saved_ELF_sections[0] = "QNX_info"; // NOTE: MUST BE THE FIRST ONE as we artificially shrink down the array to 1 when using it for boot ELF files |
2038 | saved_ELF_sections[0] = "QNX_info"; // NOTE: MUST BE THE FIRST ONE as we artificially shrink down the array to 1 when using it for boot ELF files |
| 2013 | saved_ELF_sections[1] = ".gnu_debuglink"; |
2039 | saved_ELF_sections[1] = ".gnu_debuglink"; |
| 2014 | saved_ELF_sections[2] = "QNX_usage"; |
2040 | saved_ELF_sections[2] = "QNX_usage"; |
| 2015 | saved_ELF_sections[3] = ".note.gnu.build-id"; // undocumented by QNX, but nonetheless preserved |
2041 | saved_ELF_sections[3] = ".note.gnu.build-id"; // undocumented by QNX, but nonetheless preserved |
| 2016 | saved_ELF_section_count = 4; |
2042 | saved_ELF_section_count = 4; |
| - | 2043 | default_parms.prefix = strdup ("/proc/boot"); |
|
| - | 2044 | ASSERT_WITH_ERRNO (default_parms.prefix); |
|
| 2017 | 2045 | ||
| 2018 | // parse arguments |
2046 | // parse arguments |
| 2019 | for (arg_index = 1; arg_index < argc; arg_index++) |
2047 | for (arg_index = 1; arg_index < argc; arg_index++) |
| 2020 | { |
2048 | { |
| 2021 | if ((strcmp (argv[arg_index], "--bootfile") == 0) && (arg_index + 1 < argc)) // --bootfile path/to/blob.bin |
2049 | if ((strcmp (argv[arg_index], "--bootfile") == 0) && (arg_index + 1 < argc)) // --bootfile path/to/blob.bin |