]> Kevux Git Server - fll/commitdiff
Security: A child process of an execv() family of functions may leak memory if script...
authorKevin Day <thekevinday@gmail.com>
Sun, 13 Dec 2020 19:01:48 +0000 (13:01 -0600)
committerKevin Day <thekevinday@gmail.com>
Sun, 13 Dec 2020 19:01:48 +0000 (13:01 -0600)
When calling a bash script, the exit() call gets triggered but memory is never cleared.
I am suspecting that this is happening because the script is run in the current process space whereas when calling a binary the process changes for the child.

There are new status codes: F_child, F_child_not, F_parent, F_parent_not.

The execute functions do not know what type of file is being executed.
Return F_child for the child process and allow the caller to handle the exit behavior of the child process.

This required significant changes to the Featureless Make, but the Featureless Make now always clears memory even for scripts.

The firewall program also had to be changed.
Instead of solving the potentially issues there, I decided to (for the time being) just mimic the previous behavior and call exit for the child process.
The firewall program needs a rewrite anyway, so I am holding off on major changes.

Refactor, cleanup, and improve the execute family of functions.
This was my original commit plans but when I observed the memory leak the refactor and cleanup became this security related commit.

As per cleanup plans:
  - Moved common code into shared private functions.
  - Change parameter checking granularity.
  - Allow for 0 length strings as arguments.
  - Avoid memory allocation inside execute functions.
  - Consistently check WIFEXITED() on child process result.
  - Update the documentation to follow more recent practices.

17 files changed:
level_0/f_status/c/status.h
level_1/fl_status/c/status.c
level_1/fl_status/c/status.h
level_2/fll_execute/c/execute.c
level_2/fll_execute/c/execute.h
level_2/fll_execute/c/private-execute.c
level_2/fll_execute/c/private-execute.h
level_2/fll_status/c/status.c
level_3/fake/c/fake.c
level_3/fake/c/fake.h
level_3/fake/c/main.c
level_3/fake/c/private-build.c
level_3/fake/c/private-build.h
level_3/fake/c/private-fake.c
level_3/fake/c/private-make.c
level_3/fake/c/private-make.h
level_3/firewall/c/private-firewall.c

index a49e09be36685d9f1c08d82bcc1ed6d80cff0a1b..4320da8813a88ef8bf62ea9f22d464f88a4d47a0 100644 (file)
@@ -153,6 +153,8 @@ extern "C" {
       F_block_not,
       F_bound,
       F_bound_not,
+      F_child,
+      F_child_not,
       F_complete,
       F_complete_not,
       F_connected,
@@ -210,6 +212,8 @@ extern "C" {
       F_output_not,
       F_parameter,
       F_parameter_not,
+      F_parent,
+      F_parent_not,
       F_pipe,
       F_pipe_not,
       F_port,
index 68ea3460c0d84e2bf2b1ab2c55c8796bc0177c7b..195d6703311f06fd804214997bbfea5ebfebaeca 100644 (file)
@@ -242,6 +242,12 @@ extern "C" {
         case F_bound_not:
           *string = FL_status_string_bound_not;
           break;
+        case F_child:
+          *string = FL_status_string_child;
+          break;
+        case F_child_not:
+          *string = FL_status_string_child_not;
+          break;
         case F_complete:
           *string = FL_status_string_complete;
           break;
@@ -413,6 +419,12 @@ extern "C" {
         case F_parameter_not:
           *string = FL_status_string_parameter_not;
           break;
+        case F_parent:
+          *string = FL_status_string_parent;
+          break;
+        case F_parent_not:
+          *string = FL_status_string_parent_not;
+          break;
         case F_pipe:
           *string = FL_status_string_pipe;
           break;
index 4985b7582aa2e8e4bb28088b16de24445487e60d..0c64a480ce9cb53218bfaf4b7c2806bbbc96fb58 100644 (file)
@@ -172,6 +172,8 @@ extern "C" {
     #define FL_status_string_block_not        "F_block_not"
     #define FL_status_string_bound            "F_bound"
     #define FL_status_string_bound_not        "F_bound_not"
+    #define FL_status_string_child            "F_child"
+    #define FL_status_string_child_not        "F_child_not"
     #define FL_status_string_complete         "F_complete"
     #define FL_status_string_complete_not     "F_complete_not"
     #define FL_status_string_connected        "F_connected"
@@ -229,6 +231,8 @@ extern "C" {
     #define FL_status_string_output_not       "F_output_not"
     #define FL_status_string_parameter        "F_parameter"
     #define FL_status_string_parameter_not    "F_parameter_not"
+    #define FL_status_string_parent           "F_parent"
+    #define FL_status_string_parent_not       "F_parent_not"
     #define FL_status_string_pipe             "F_pipe"
     #define FL_status_string_pipe_not         "F_pipe_not"
     #define FL_status_string_port             "F_port"
@@ -287,6 +291,8 @@ extern "C" {
     #define FL_status_string_block_not_length        11
     #define FL_status_string_bound_length            7
     #define FL_status_string_bound_not_length        11
+    #define FL_status_string_child_length            7
+    #define FL_status_string_child_not_length        11
     #define FL_status_string_complete_length         10
     #define FL_status_string_complete_not_length     14
     #define FL_status_string_connected_length        11
@@ -344,6 +350,8 @@ extern "C" {
     #define FL_status_string_output_not_length       12
     #define FL_status_string_parameter_length        11
     #define FL_status_string_parameter_not_length    15
+    #define FL_status_string_parent_length           8
+    #define FL_status_string_parent_not_length       12
     #define FL_status_string_pipe_length             6
     #define FL_status_string_pipe_not_length         10
     #define FL_status_string_port_length             6
index a60de33b39d55367ba05ca36bab6827dc4a6f683..c0b78ee2b723ec459f4d72f58fd8d76560ef8e41 100644 (file)
@@ -9,14 +9,9 @@ extern "C" {
   f_return_status fll_execute_arguments_add(const f_string_t source, const f_string_length_t length, f_string_dynamics_t *arguments) {
     #ifndef _di_level_2_parameter_checking_
       if (!arguments) return F_status_set_error(F_parameter);
-      if (arguments->used > arguments->size) return F_status_set_error(F_parameter);
     #endif // _di_level_2_parameter_checking_
 
-    if (!length) return F_data_not;
-
-    f_status_t status = F_none;
-
-    status = private_fll_execute_arguments_add(source, length, arguments);
+    const f_status_t status = private_fll_execute_arguments_add(source, length, arguments);
     if (F_status_is_error(status)) return status;
 
     return F_none;
@@ -27,15 +22,9 @@ extern "C" {
   f_return_status fll_execute_arguments_add_parameter(const f_string_t prefix, const f_string_length_t prefix_length, const f_string_t name, const f_string_length_t name_length, const f_string_t value, const f_string_length_t value_length, f_string_dynamics_t *arguments) {
     #ifndef _di_level_2_parameter_checking_
       if (!arguments) return F_status_set_error(F_parameter);
-      if (arguments->used > arguments->size) return F_status_set_error(F_parameter);
     #endif // _di_level_2_parameter_checking_
 
-    if (!name_length) return F_data_not;
-    if (!value_length) return F_data_not;
-
-    f_status_t status = F_none;
-
-    status = private_fll_execute_arguments_add_parameter(prefix, prefix_length, name, name_length, value, value_length, arguments);
+    const f_status_t status = private_fll_execute_arguments_add_parameter(prefix, prefix_length, name, name_length, value, value_length, arguments);
     if (F_status_is_error(status)) return status;
 
     return F_none;
@@ -46,16 +35,11 @@ extern "C" {
   f_return_status fll_execute_arguments_add_parameter_set(const f_string_t prefix[], const f_string_length_t prefix_length[], const f_string_t name[], const f_string_length_t name_length[], const f_string_t value[], const f_string_length_t value_length[], const f_array_length_t size, f_string_dynamics_t *arguments) {
     #ifndef _di_level_2_parameter_checking_
       if (!arguments) return F_status_set_error(F_parameter);
-      if (arguments->used > arguments->size) return F_status_set_error(F_parameter);
     #endif // _di_level_2_parameter_checking_
 
-    if (!size) return F_data_not;
-
     f_status_t status = F_none;
 
     for (f_array_length_t i = 0; i < size; i++) {
-      if (!name_length[i]) continue;
-      if (!value_length[i]) continue;
 
       status = private_fll_execute_arguments_add_parameter(prefix[i], prefix_length[i], name[i], name_length[i], value[i], value_length[i], arguments);
       if (F_status_is_error(status)) return status;
@@ -69,15 +53,11 @@ extern "C" {
   f_return_status fll_execute_arguments_add_set(const f_string_t source[], const f_string_length_t length[], const f_array_length_t size, f_string_dynamics_t *arguments) {
     #ifndef _di_level_2_parameter_checking_
       if (!arguments) return F_status_set_error(F_parameter);
-      if (arguments->used > arguments->size) return F_status_set_error(F_parameter);
     #endif // _di_level_2_parameter_checking_
 
-    if (!size) return F_data_not;
-
     f_status_t status = F_none;
 
     for (f_array_length_t i = 0; i < size; i++) {
-      if (!length[i]) continue;
 
       status = private_fll_execute_arguments_add(source[i], length[i], arguments);
       if (F_status_is_error(status)) return status;
@@ -90,16 +70,10 @@ extern "C" {
 #ifndef _di_fll_execute_arguments_dynamic_add_
   f_return_status fll_execute_arguments_dynamic_add(const f_string_static_t source, f_string_dynamics_t *arguments) {
     #ifndef _di_level_2_parameter_checking_
-      if (source.used > source.size) return F_status_set_error(F_parameter);
       if (!arguments) return F_status_set_error(F_parameter);
-      if (arguments->used > arguments->size) return F_status_set_error(F_parameter);
     #endif // _di_level_2_parameter_checking_
 
-    if (!source.used) return F_data_not;
-
-    f_status_t status = F_none;
-
-    status = private_fll_execute_arguments_add(source.string, source.used, arguments);
+    const f_status_t status = private_fll_execute_arguments_add(source.string, source.used, arguments);
     if (F_status_is_error(status)) return status;
 
     return F_none;
@@ -109,19 +83,10 @@ extern "C" {
 #ifndef _di_fll_execute_arguments_dynamic_add_parameter_
   f_return_status fll_execute_arguments_dynamic_add_parameter(const f_string_static_t prefix, const f_string_static_t name, const f_string_static_t value, f_string_dynamics_t *arguments) {
     #ifndef _di_level_2_parameter_checking_
-      if (prefix.used > prefix.size) return F_status_set_error(F_parameter);
-      if (name.used > name.size) return F_status_set_error(F_parameter);
-      if (value.used > value.size) return F_status_set_error(F_parameter);
       if (!arguments) return F_status_set_error(F_parameter);
-      if (arguments->used > arguments->size) return F_status_set_error(F_parameter);
     #endif // _di_level_2_parameter_checking_
 
-    if (!name.used) return F_data_not;
-    if (!value.used) return F_data_not;
-
-    f_status_t status = F_none;
-
-    status = private_fll_execute_arguments_add_parameter(prefix.string, prefix.used, name.string, name.used, value.string, value.used, arguments);
+    const f_status_t status = private_fll_execute_arguments_add_parameter(prefix.string, prefix.used, name.string, name.used, value.string, value.used, arguments);
     if (F_status_is_error(status)) return status;
 
     return F_none;
@@ -132,19 +97,11 @@ extern "C" {
   f_return_status fll_execute_arguments_dynamic_add_parameter_set(const f_string_static_t prefix[], const f_string_static_t name[], const f_string_static_t value[], const f_array_length_t size, f_string_dynamics_t *arguments) {
     #ifndef _di_level_2_parameter_checking_
       if (!arguments) return F_status_set_error(F_parameter);
-      if (arguments->used > arguments->size) return F_status_set_error(F_parameter);
     #endif // _di_level_2_parameter_checking_
 
-    if (!size) return F_data_not;
-
     f_status_t status = F_none;
 
     for (f_array_length_t i = 0; i < size; i++) {
-      if (prefix[i].used > prefix[i].size) continue;
-      if (!name[i].used) continue;
-      if (name[i].used > name[i].size) continue;
-      if (!value[i].used) continue;
-      if (value[i].used > value[i].size) continue;
 
       status = private_fll_execute_arguments_add_parameter(prefix[i].string, prefix[i].used, name[i].string, name[i].used, value[i].string, value[i].used, arguments);
       if (F_status_is_error(status)) return status;
@@ -158,16 +115,11 @@ extern "C" {
   f_return_status fll_execute_arguments_dynamic_add_set(const f_string_static_t source[], const f_array_length_t size, f_string_dynamics_t *arguments) {
     #ifndef _di_level_2_parameter_checking_
       if (!arguments) return F_status_set_error(F_parameter);
-      if (arguments->used > arguments->size) return F_status_set_error(F_parameter);
     #endif // _di_level_2_parameter_checking_
 
-    if (!size) return F_data_not;
-
     f_status_t status = F_none;
 
     for (f_array_length_t i = 0; i < size; i++) {
-      if (!source[i].used) continue;
-      if (source[i].used > source[i].size) continue;
 
       status = private_fll_execute_arguments_add(source[i].string, source[i].used, arguments);
       if (F_status_is_error(status)) return status;
@@ -181,240 +133,63 @@ extern "C" {
   f_return_status fll_execute_path(const f_string_t program_path, const f_string_statics_t arguments, const f_signal_how_t *signals, int *result) {
     #ifndef _di_level_2_parameter_checking_
       if (!result) return F_status_set_error(F_parameter);
-      if (arguments.used > arguments.size) return F_status_set_error(F_parameter);
     #endif // _di_level_2_parameter_checking_
 
     // create a string array that is compatible with execv() calls.
     f_string_t fixed_arguments[arguments.used + 2];
 
-    f_string_t last_slash = f_string_t_initialize;
-    f_string_t program_name = f_string_t_initialize;
-
-    f_string_length_t name_size = 0;
+    const f_string_t last_slash = strrchr(program_path, '/');
+    const f_string_length_t name_size = last_slash ? strnlen(last_slash, f_path_max) : strnlen(program_path, f_path_max);
 
-    f_status_t status = F_none;
+    char program_name[name_size + 1];
 
-    last_slash = strrchr(program_path, '/');
+    program_name[name_size] = 0;
 
-    if (!last_slash) {
-      name_size = strnlen(program_path, f_path_max);
+    private_fll_execute_path_arguments_fixate(last_slash ? last_slash : program_path, arguments, name_size, program_name, fixed_arguments);
 
-      if (name_size > 1) {
-        f_macro_string_t_new(status, program_name, name_size + 1);
-        if (F_status_is_error(status)) return status;
+    {
+      const f_status_t status = f_file_exists(program_path);
 
-        memcpy(program_name, program_path, name_size);
-        memset(program_name, name_size, 0);
-      }
-      else {
-        name_size = 0;
-      }
-    }
-    else {
-      name_size = strnlen(last_slash, f_path_max);
-
-      if (name_size > 1) {
-        f_macro_string_t_new(status, program_name, name_size + 1);
-        if (F_status_is_error(status)) return status;
-
-        memcpy(program_name, last_slash + 1, name_size);
-        memset(program_name, name_size, 0);
-      }
-      else {
-        name_size = 0;
-      }
-    }
-
-    if (!name_size) {
-      fixed_arguments[0] = 0;
-    }
-    else {
-      fixed_arguments[0] = program_name;
-    }
-
-    for (f_string_length_t i = 0; i < arguments.used; i++) {
-      fixed_arguments[i + 1] = arguments.array[i].string;
-    } // for
-
-    // insert the required array terminated.
-    fixed_arguments[arguments.used + 1] = 0;
-
-    status = f_file_exists(program_path);
-
-    if (F_status_is_error(status)) {
-      if (name_size > 0) f_macro_string_t_delete_simple(program_name, name_size);
-
-      return status;
-    }
-    else if (status == F_false) {
-      if (name_size > 0) f_macro_string_t_delete_simple(program_name, name_size);
-
-      return F_status_set_error(F_file_found_not);
-    }
-
-    pid_t process_id = 0;
-
-    process_id = fork();
-
-    if (process_id < 0) {
-      if (name_size > 0) {
-        f_macro_string_t_delete_simple(program_name, name_size);
+      if (F_status_is_error(status)) {
+        return status;
       }
-
-      return F_status_set_error(F_fork);
-    }
-
-    // child process.
-    if (!process_id) {
-      if (signals) {
-        f_signal_set_handle(SIG_BLOCK, &signals->block);
-        f_signal_set_handle(SIG_UNBLOCK, &signals->block_not);
+      else if (status == F_false) {
+        return F_status_set_error(F_file_found_not);
       }
-
-      const int code = execv(program_path, fixed_arguments);
-
-      exit(code);
     }
 
-    // have the parent wait for the child process to finish
-    waitpid(process_id, result, WUNTRACED | WCONTINUED);
-
-    if (name_size > 0) {
-      f_macro_string_t_delete_simple(program_name, name_size);
-    }
-
-    if (result != 0 && *result != 0) {
-      return F_status_set_error(F_failure);
-    }
-
-    return F_none;
+    return private_fll_execute_fork(program_name, fixed_arguments, F_false, signals, result);
   }
 #endif // _di_fll_execute_path_
 
 #ifndef _di_fll_execute_path_environment_
-  f_return_status fll_execute_path_environment(const f_string_t program_path, const f_string_statics_t arguments, const f_signal_how_t *signals, const f_string_statics_t names, const f_string_statics_t values, int *result) {
+  f_return_status fll_execute_path_environment(const f_string_t program_path, const f_string_statics_t arguments, const f_string_statics_t names, const f_string_statics_t values, const f_signal_how_t *signals, int *result) {
     #ifndef _di_level_2_parameter_checking_
       if (!result) return F_status_set_error(F_parameter);
-      if (arguments.used > arguments.size) return F_status_set_error(F_parameter);
-      if (names.used > names.size) return F_status_set_error(F_parameter);
-      if (values.used > values.size) return F_status_set_error(F_parameter);
-      if (names.used > values.used) return F_status_set_error(F_parameter);
     #endif // _di_level_2_parameter_checking_
 
     // create a string array that is compatible with execv() calls.
     f_string_t fixed_arguments[arguments.used + 2];
 
-    f_string_t last_slash = f_string_t_initialize;
-    f_string_t program_name = f_string_t_initialize;
-
-    f_string_length_t name_size = 0;
-
-    f_status_t status = F_none;
-
-    last_slash = strrchr(program_path, '/');
-
-    if (!last_slash) {
-      name_size = strnlen(program_path, f_path_max);
-
-      if (name_size > 1) {
-        f_macro_string_t_new(status, program_name, name_size + 1);
-
-        if (F_status_is_error(status)) return status;
+    const f_string_t last_slash = strrchr(program_path, '/');
+    const f_string_length_t name_size = last_slash ? strnlen(last_slash, f_path_max) : strnlen(program_path, f_path_max);
 
-        memcpy(program_name, program_path, name_size);
-        memset(program_name, name_size, 0);
-      }
-      else {
-        name_size = 0;
-      }
-    }
-    else {
-      name_size = strnlen(last_slash, f_path_max);
+    char program_name[name_size + 1];
 
-      if (name_size > 1) {
-        f_macro_string_t_new(status, program_name, name_size + 1);
+    private_fll_execute_path_arguments_fixate(last_slash ? last_slash : program_path, arguments, name_size, program_name, fixed_arguments);
 
-        if (F_status_is_error(status)) return status;
+    {
+      const f_status_t status = f_file_exists(program_path);
 
-        memcpy(program_name, last_slash + 1, name_size);
-        memset(program_name, name_size, 0);
-      }
-      else {
-        name_size = 0;
-      }
-    }
-
-    if (!name_size) {
-      fixed_arguments[0] = 0;
-    }
-    else {
-      fixed_arguments[0] = program_name;
-    }
-
-    for (f_string_length_t i = 0; i < arguments.used; i++) {
-      fixed_arguments[i + 1] = arguments.array[i].string;
-    } // for
-
-    // insert the required array terminated.
-    fixed_arguments[arguments.used + 1] = 0;
-
-    status = f_file_exists(program_path);
-
-    if (F_status_is_error(status)) {
-      if (name_size > 0) f_macro_string_t_delete_simple(program_name, name_size);
-
-      return status;
-    }
-    else if (status == F_false) {
-      if (name_size > 0) f_macro_string_t_delete_simple(program_name, name_size);
-
-      return F_status_set_error(F_file_found_not);
-    }
-
-    pid_t process_id = 0;
-
-    process_id = fork();
-
-    if (process_id < 0) {
-      if (name_size > 0) f_macro_string_t_delete_simple(program_name, name_size);
-
-      return F_status_set_error(F_fork);
-    }
-
-    // child process.
-    if (!process_id) {
-      if (signals) {
-        f_signal_set_handle(SIG_BLOCK, &signals->block);
-        f_signal_set_handle(SIG_UNBLOCK, &signals->block_not);
+      if (F_status_is_error(status)) {
+        return status;
       }
-
-      clearenv();
-
-      for (f_array_length_t i = 0; i < names.used; i++) {
-        f_environment_set_dynamic(names.array[i], values.array[i], F_true);
-      } // for
-
-      const int code = execv(program_path, fixed_arguments);
-
-      exit(code);
-    }
-
-    // have the parent wait for the child process to finish.
-    waitpid(process_id, result, WUNTRACED | WCONTINUED);
-
-    if (name_size > 0) {
-      f_macro_string_t_delete_simple(program_name, name_size);
-    }
-
-    if (result != 0) {
-      if (WIFEXITED(*result)) {
-        return F_none;
+      else if (status == F_false) {
+        return F_status_set_error(F_file_found_not);
       }
-
-      return F_status_set_error(F_failure);
     }
 
-    return F_none;
+    return private_fll_execute_fork_environment(program_name, fixed_arguments, F_false, names, values, signals, result);
   }
 #endif // _di_fll_execute_path_environment_
 
@@ -422,7 +197,6 @@ extern "C" {
   f_return_status fll_execute_program(const f_string_t program_name, const f_string_statics_t arguments, const f_signal_how_t *signals, int *result) {
     #ifndef _di_level_2_parameter_checking_
       if (!result) return F_status_set_error(F_parameter);
-      if (arguments.used > arguments.size) return F_status_set_error(F_parameter);
     #endif // _di_level_2_parameter_checking_
 
     // create a string array that is compatible with execv() calls.
@@ -430,55 +204,21 @@ extern "C" {
 
     fixed_arguments[0] = program_name;
 
-    f_status_t status = F_none;
-    f_array_length_t i = 0;
-
-    for (; i < arguments.used; i++) {
+    for (f_array_length_t i = 0; i < arguments.used; i++) {
       fixed_arguments[i + 1] = arguments.array[i].string;
     } // for
 
     // insert the required array terminated.
     fixed_arguments[arguments.used + 1] = 0;
 
-    pid_t process_id = 0;
-
-    process_id = fork();
-
-    if (process_id < 0) {
-      return F_status_set_error(F_fork);
-    }
-
-    // child process.
-    if (!process_id) {
-      if (signals) {
-        f_signal_set_handle(SIG_BLOCK, &signals->block);
-        f_signal_set_handle(SIG_UNBLOCK, &signals->block_not);
-      }
-
-      const int code = execvp(program_name, fixed_arguments);
-
-      exit(code);
-    }
-
-    // have the parent wait for the child process to finish
-    waitpid(process_id, result, WUNTRACED | WCONTINUED);
-
-    if (result != 0 && *result != 0) {
-      return F_status_set_error(F_failure);
-    }
-
-    return F_none;
+    return private_fll_execute_fork(program_name, fixed_arguments, F_true, signals, result);
   }
 #endif // _di_fll_execute_program_
 
 #ifndef _di_fll_execute_program_environment_
-  f_return_status fll_execute_program_environment(const f_string_t program_name, const f_string_statics_t arguments, const f_signal_how_t *signals, const f_string_statics_t names, const f_string_statics_t values, int *result) {
+  f_return_status fll_execute_program_environment(const f_string_t program_name, const f_string_statics_t arguments, const f_string_statics_t names, const f_string_statics_t values, const f_signal_how_t *signals, int *result) {
     #ifndef _di_level_2_parameter_checking_
       if (!result) return F_status_set_error(F_parameter);
-      if (arguments.used > arguments.size) return F_status_set_error(F_parameter);
-      if (names.used > names.size) return F_status_set_error(F_parameter);
-      if (values.used > values.size) return F_status_set_error(F_parameter);
-      if (names.used > values.used) return F_status_set_error(F_parameter);
     #endif // _di_level_2_parameter_checking_
 
     // create a string array that is compatible with execv() calls.
@@ -486,10 +226,7 @@ extern "C" {
 
     fixed_arguments[0] = program_name;
 
-    f_status_t status = F_none;
-    f_array_length_t i = 0;
-
-    for (; i < arguments.used; i++) {
+    for (f_array_length_t i = 0; i < arguments.used; i++) {
       fixed_arguments[i + 1] = arguments.array[i].string;
     } // for
 
@@ -499,7 +236,7 @@ extern "C" {
     f_string_dynamic_t path = f_string_dynamic_t_initialize;
     f_string_dynamics_t paths = f_string_dynamics_t_initialize;
 
-    status = f_environment_get("PATH", &path);
+    f_status_t status = f_environment_get("PATH", &path);
 
     if (F_status_is_error(status)) {
 
@@ -528,7 +265,7 @@ extern "C" {
     const f_string_length_t program_name_length = strnlen(program_name, f_path_max);
     f_string_dynamic_t *found = 0;
 
-    for (i = 0; i < paths.used; i++) {
+    for (f_array_length_t i = 0; i < paths.used; i++) {
 
       status = fl_string_append(program_name, program_name_length, &paths.array[i]);
 
@@ -578,38 +315,7 @@ extern "C" {
     f_macro_string_dynamics_t_delete(status, paths);
     if (F_status_is_error(status)) return status;
 
-    pid_t process_id = 0;
-
-    process_id = fork();
-
-    if (process_id < 0) {
-      return F_status_set_error(F_fork);
-    }
-
-    // child process.
-    if (!process_id) {
-      if (signals) {
-        f_signal_set_handle(SIG_BLOCK, &signals->block);
-        f_signal_set_handle(SIG_UNBLOCK, &signals->block_not);
-      }
-
-      clearenv();
-
-      for (i = 0; i < names.used; i++) {
-        f_environment_set_dynamic(names.array[i], values.array[i], F_true);
-      } // for
-
-      const int code = execvp(program_path, fixed_arguments);
-
-      exit(code);
-    }
-
-    // have the parent wait for the child process to finish
-    waitpid(process_id, result, WUNTRACED | WCONTINUED);
-
-    if (result != 0 && *result != 0) return F_status_set_error(F_failure);
-
-    return F_none;
+    return private_fll_execute_fork_environment(program_name, fixed_arguments, F_true, names, values, signals, result);
   }
 #endif // _di_fll_execute_program_environment_
 
index fd51d3101e852bf19cf67f98318ab831c0037abc..756965bfad743412b9dceca84899821d35f7d0ca 100644 (file)
@@ -52,18 +52,23 @@ extern "C" {
  *
  * @return
  *   F_none on success.
- *   F_data_not if source length is 0.
- *   F_array_too_large (with error bit) if arguments array is too large for further allocation.
- *   F_memory_allocation (with error bit) on allocation error.
- *   F_memory_reallocation (with error bit) on reallocation error.
- *   F_parameter (with error bit) if a parameter is invalid.
  *
+ *   Errors (with error bit) from: f_macro_string_dynamic_t_delete_simple().
+ *   Errors (with error bit) from: f_macro_string_dynamics_t_resize().
  *   Errors (with error bit) from: fl_string_append().
  *   Errors (with error bit) from: fl_string_dynamic_terminate().
+ *   Errors (with error bit) from: fl_string_dynamics_increase().
+ *
+ * @see f_macro_string_dynamic_t_delete_simple()
+ * @see f_macro_string_dynamics_t_resize()
+ * @see fl_string_append()
+ * @see fl_string_dynamic_terminate()
+ * @see fl_string_dynamics_increase()
  */
 #ifndef _di_fll_execute_arguments_add_
   extern f_return_status fll_execute_arguments_add(const f_string_t source, const f_string_length_t length, f_string_dynamics_t *arguments);
 #endif // _di_fll_execute_arguments_add_
+
 /**
  * Add parameters as arguments to the execution arguments array.
  *
@@ -93,14 +98,18 @@ extern "C" {
  *
  * @return
  *   F_none on success.
- *   F_data_not if source length is 0.
- *   F_array_too_large (with error bit) if arguments array is too large for further allocation.
- *   F_memory_allocation (with error bit) on allocation error.
- *   F_memory_reallocation (with error bit) on reallocation error.
- *   F_parameter (with error bit) if a parameter is invalid.
  *
+ *   Errors (with error bit) from: f_macro_string_dynamic_t_delete_simple().
+ *   Errors (with error bit) from: f_macro_string_dynamics_t_resize().
  *   Errors (with error bit) from: fl_string_append().
  *   Errors (with error bit) from: fl_string_dynamic_terminate().
+ *   Errors (with error bit) from: fl_string_dynamics_increase().
+ *
+ * @see f_macro_string_dynamic_t_delete_simple()
+ * @see f_macro_string_dynamics_t_resize()
+ * @see fl_string_append()
+ * @see fl_string_dynamic_terminate()
+ * @see fl_string_dynamics_increase()
  */
 #ifndef _di_fll_execute_arguments_add_parameter_
   extern f_return_status fll_execute_arguments_add_parameter(const f_string_t prefix, const f_string_length_t prefix_length, const f_string_t name, const f_string_length_t name_length, const f_string_t value, const f_string_length_t value_length, f_string_dynamics_t *arguments);
@@ -137,14 +146,18 @@ extern "C" {
  *
  * @return
  *   F_none on success.
- *   F_data_not if size is 0.
- *   F_array_too_large (with error bit) if arguments array is too large for further allocation.
- *   F_memory_allocation (with error bit) on allocation error.
- *   F_memory_reallocation (with error bit) on reallocation error.
- *   F_parameter (with error bit) if a parameter is invalid.
  *
+ *   Errors (with error bit) from: f_macro_string_dynamic_t_delete_simple().
+ *   Errors (with error bit) from: f_macro_string_dynamics_t_resize().
  *   Errors (with error bit) from: fl_string_append().
  *   Errors (with error bit) from: fl_string_dynamic_terminate().
+ *   Errors (with error bit) from: fl_string_dynamics_increase().
+ *
+ * @see f_macro_string_dynamic_t_delete_simple()
+ * @see f_macro_string_dynamics_t_resize()
+ * @see fl_string_append()
+ * @see fl_string_dynamic_terminate()
+ * @see fl_string_dynamics_increase()
  */
 #ifndef _di_fll_execute_arguments_add_parameter_set_
   extern f_return_status fll_execute_arguments_add_parameter_set(const f_string_t prefix[], const f_string_length_t prefix_length[], const f_string_t name[], const f_string_length_t name_length[], const f_string_t value[], const f_string_length_t value_length[], const f_array_length_t size, f_string_dynamics_t *arguments);
@@ -167,14 +180,18 @@ extern "C" {
  *
  * @return
  *   F_none on success.
- *   F_data_not if size is 0.
- *   F_array_too_large (with error bit) if arguments array is too large for further allocation.
- *   F_memory_allocation (with error bit) on allocation error.
- *   F_memory_reallocation (with error bit) on reallocation error.
- *   F_parameter (with error bit) if a parameter is invalid.
  *
+ *   Errors (with error bit) from: f_macro_string_dynamic_t_delete_simple().
+ *   Errors (with error bit) from: f_macro_string_dynamics_t_resize().
  *   Errors (with error bit) from: fl_string_append().
  *   Errors (with error bit) from: fl_string_dynamic_terminate().
+ *   Errors (with error bit) from: fl_string_dynamics_increase().
+ *
+ * @see f_macro_string_dynamic_t_delete_simple()
+ * @see f_macro_string_dynamics_t_resize()
+ * @see fl_string_append()
+ * @see fl_string_dynamic_terminate()
+ * @see fl_string_dynamics_increase()
  */
 #ifndef _di_fll_execute_arguments_add_set_
   extern f_return_status fll_execute_arguments_add_set(const f_string_t source[], const f_string_length_t length[], const f_array_length_t size, f_string_dynamics_t *arguments);
@@ -193,14 +210,18 @@ extern "C" {
  *
  * @return
  *   F_none on success.
- *   F_data_not if source length is 0.
- *   F_array_too_large (with error bit) if arguments array is too large for further allocation.
- *   F_memory_allocation (with error bit) on allocation error.
- *   F_memory_reallocation (with error bit) on reallocation error.
- *   F_parameter (with error bit) if a parameter is invalid.
  *
+ *   Errors (with error bit) from: f_macro_string_dynamic_t_delete_simple().
+ *   Errors (with error bit) from: f_macro_string_dynamics_t_resize().
  *   Errors (with error bit) from: fl_string_append().
  *   Errors (with error bit) from: fl_string_dynamic_terminate().
+ *   Errors (with error bit) from: fl_string_dynamics_increase().
+ *
+ * @see f_macro_string_dynamic_t_delete_simple()
+ * @see f_macro_string_dynamics_t_resize()
+ * @see fl_string_append()
+ * @see fl_string_dynamic_terminate()
+ * @see fl_string_dynamics_increase()
  */
 #ifndef _di_fll_execute_arguments_dynamic_add_
   extern f_return_status fll_execute_arguments_dynamic_add(const f_string_static_t source, f_string_dynamics_t *arguments);
@@ -229,14 +250,18 @@ extern "C" {
  *
  * @return
  *   F_none on success.
- *   F_data_not if source length is 0.
- *   F_array_too_large (with error bit) if arguments array is too large for further allocation.
- *   F_memory_allocation (with error bit) on allocation error.
- *   F_memory_reallocation (with error bit) on reallocation error.
- *   F_parameter (with error bit) if a parameter is invalid.
  *
+ *   Errors (with error bit) from: f_macro_string_dynamic_t_delete_simple().
+ *   Errors (with error bit) from: f_macro_string_dynamics_t_resize().
  *   Errors (with error bit) from: fl_string_append().
  *   Errors (with error bit) from: fl_string_dynamic_terminate().
+ *   Errors (with error bit) from: fl_string_dynamics_increase().
+ *
+ * @see f_macro_string_dynamic_t_delete_simple()
+ * @see f_macro_string_dynamics_t_resize()
+ * @see fl_string_append()
+ * @see fl_string_dynamic_terminate()
+ * @see fl_string_dynamics_increase()
  */
 #ifndef _di_fll_execute_arguments_dynamic_add_parameter_
   extern f_return_status fll_execute_arguments_dynamic_add_parameter(const f_string_static_t prefix, const f_string_static_t name, const f_string_static_t value, f_string_dynamics_t *arguments);
@@ -267,14 +292,18 @@ extern "C" {
  *
  * @return
  *   F_none on success.
- *   F_data_not if source length is 0.
- *   F_array_too_large (with error bit) if arguments array is too large for further allocation.
- *   F_memory_allocation (with error bit) on allocation error.
- *   F_memory_reallocation (with error bit) on reallocation error.
- *   F_parameter (with error bit) if a parameter is invalid.
  *
+ *   Errors (with error bit) from: f_macro_string_dynamic_t_delete_simple().
+ *   Errors (with error bit) from: f_macro_string_dynamics_t_resize().
  *   Errors (with error bit) from: fl_string_append().
  *   Errors (with error bit) from: fl_string_dynamic_terminate().
+ *   Errors (with error bit) from: fl_string_dynamics_increase().
+ *
+ * @see f_macro_string_dynamic_t_delete_simple()
+ * @see f_macro_string_dynamics_t_resize()
+ * @see fl_string_append()
+ * @see fl_string_dynamic_terminate()
+ * @see fl_string_dynamics_increase()
  */
 #ifndef _di_fll_execute_arguments_dynamic_add_parameter_set_
   extern f_return_status fll_execute_arguments_dynamic_add_parameter_set(const f_string_static_t prefix[], const f_string_static_t name[], const f_string_static_t value[], const f_array_length_t size, f_string_dynamics_t *arguments);
@@ -295,14 +324,18 @@ extern "C" {
  *
  * @return
  *   F_none on success.
- *   F_data_not if source length is 0.
- *   F_array_too_large (with error bit) if arguments array is too large for further allocation.
- *   F_memory_allocation (with error bit) on allocation error.
- *   F_memory_reallocation (with error bit) on reallocation error.
- *   F_parameter (with error bit) if a parameter is invalid.
  *
+ *   Errors (with error bit) from: f_macro_string_dynamic_t_delete_simple().
+ *   Errors (with error bit) from: f_macro_string_dynamics_t_resize().
  *   Errors (with error bit) from: fl_string_append().
  *   Errors (with error bit) from: fl_string_dynamic_terminate().
+ *   Errors (with error bit) from: fl_string_dynamics_increase().
+ *
+ * @see f_macro_string_dynamic_t_delete_simple()
+ * @see f_macro_string_dynamics_t_resize()
+ * @see fl_string_append()
+ * @see fl_string_dynamic_terminate()
+ * @see fl_string_dynamics_increase()
  */
 #ifndef _di_fll_execute_arguments_dynamic_add_set_
   extern f_return_status fll_execute_arguments_dynamic_add_set(const f_string_static_t source[], const f_array_length_t size, f_string_dynamics_t *arguments);
@@ -313,6 +346,10 @@ extern "C" {
  *
  * This does validate that the program path exists.
  *
+ * This does not call exit() when the child process exits.
+ * Instead, this returns F_child and assigns the child's return code to result.
+ * The caller is expected to handle the appropriate exit procedures and memory deallocation.
+ *
  * @param program_path
  *   The entire path to the program.
  * @param arguments
@@ -325,22 +362,22 @@ extern "C" {
  *
  * @return
  *   F_none on success.
- *   F_access_denied (with error bit) on access denied for program_path.
- *   F_directory (with error bit) on invalid directory in program_path.
+ *   F_child on success but this is the child thread (this may happen when calling scripts rather than executing a binary).
  *   F_failure (with error bit) if result is non-zero.
- *   F_file_found_not (with error bit) if file does not exist at the program_path.
- *   F_file_stat (with error bit) on stat error while checking the program_path.
- *   F_loop (with error bit) on loop error while checking the program_path.
- *   F_memory_allocation (with error bit) on allocation error.
- *   F_memory_not (with error bit) if out of memory.
- *   F_memory_reallocation (with error bit) on reallocation error.
- *   F_name (with error bit) on path name error.
- *   F_number_overflow (with error bit) on overflow error.
- *   F_parameter (with error bit) if a parameter is invalid.
+ *   F_fork (with error bit) if fork failed.
  *
  *   Errors (with error bit) from: f_file_exists().
+ *   Errors (with error bit) from: f_signal_set_handle().
  *
  * @see execv()
+ * @see exit()
+ * @see fork()
+ * @see memcpy()
+ * @see strnlen()
+ * @see waitpid()
+ *
+ * @see f_file_exists()
+ * @see f_signal_set_handle()
  */
 #ifndef _di_fll_execute_path_
   extern f_return_status fll_execute_path(const f_string_t program_path, const f_string_statics_t arguments, const f_signal_how_t *signals, int *result);
@@ -353,6 +390,10 @@ extern "C" {
  *
  * The environment is defined by the names and values pair.
  *
+ * This does not call exit() when the child process exits.
+ * Instead, this returns F_child and assigns the child's return code to result.
+ * The caller is expected to handle the appropriate exit procedures and memory deallocation.
+ *
  * @param program_path
  *   The entire path to the program.
  * @param arguments
@@ -361,37 +402,39 @@ extern "C" {
  *   An array of strings representing the environment variable names.
  *   At most names.used variables are created.
  *   Duplicate names are overwritten.
- * @param set_signal
- *   (optional) A pointer to the set of signals.
- *   Set to 0 to disable.
  * @param values
  *   An array of strings representing the environment variable names.
  *   The values.used must be of at least names.used.
  *   Set individual strings.used to 0 for empty/NULL values.
+ * @param signals
+ *   (optional) A pointer to the set of signals.
+ *   Set to 0 to disable.
  * @param result
  *   The code returned after finishing execution of program_path.
  *
  * @return
  *   F_none on success.
- *   F_access_denied (with error bit) on access denied for program_path.
- *   F_directory (with error bit) on invalid directory in program_path.
+ *   F_child on success but this is the child thread (this may happen when calling scripts rather than executing a binary).
  *   F_failure (with error bit) if result is non-zero.
- *   F_file_found_not (with error bit) if file does not exist at the program_path.
- *   F_file_stat (with error bit) on stat error while checking the program_path.
- *   F_loop (with error bit) on loop error while checking the program_path.
- *   F_memory_allocation (with error bit) on allocation error.
- *   F_memory_not (with error bit) if out of memory.
- *   F_memory_reallocation (with error bit) on reallocation error.
- *   F_name (with error bit) on path name error.
- *   F_number_overflow (with error bit) on overflow error.
- *   F_parameter (with error bit) if a parameter is invalid.
+ *   F_fork (with error bit) if fork failed.
  *
+ *   Errors (with error bit) from: f_environment_set_dynamic().
  *   Errors (with error bit) from: f_file_exists().
+ *   Errors (with error bit) from: f_signal_set_handle().
  *
  * @see execv()
+ * @see clearenv()
+ * @see fork()
+ * @see memcpy()
+ * @see strnlen()
+ * @see waitpid()
+ *
+ * @see f_environment_set_dynamic()
+ * @see f_file_exists()
+ * @see f_signal_set_handle()
  */
 #ifndef _di_fll_execute_path_environment_
-  f_return_status fll_execute_path_environment(const f_string_t program_path, const f_string_statics_t arguments, const f_signal_how_t *signals, const f_string_statics_t names, const f_string_statics_t values, int *result);
+  extern f_return_status fll_execute_path_environment(const f_string_t program_path, const f_string_statics_t arguments, const f_string_statics_t names, const f_string_statics_t values, const f_signal_how_t *signals, int *result);
 #endif // _di_fll_execute_path_environment_
 
 /**
@@ -399,6 +442,10 @@ extern "C" {
  *
  * This does not validate the path to the program.
  *
+ * This does not call exit() when the child process exits.
+ * Instead, this returns F_child and assigns the child's return code to result.
+ * The caller is expected to handle the appropriate exit procedures and memory deallocation.
+ *
  * @param program_name
  *   The name of the program.
  * @param arguments
@@ -411,17 +458,20 @@ extern "C" {
  *
  * @return
  *   F_none on success.
+ *   F_child on success but this is the child thread (this may happen when calling scripts rather than executing a binary).
  *   F_failure (with error bit) if result is non-zero.
- *   F_file_found_not (with error bit) if file does not exist at the program_path.
- *   F_fork (with error bit) on fork failure.
- *   F_memory_allocation (with error bit) on allocation error.
- *   F_memory_reallocation (with error bit) on reallocation error.
- *   F_parameter (with error bit) if a parameter is invalid.
- *   F_string_too_large (with error bit) if the combined string (generated from PATH) is too large.
+ *   F_fork (with error bit) if fork failed.
  *
  *   Errors (with error bit) from: f_file_exists().
+ *   Errors (with error bit) from: f_signal_set_handle().
  *
  * @see execvp()
+ * @see fork()
+ * @see strnlen()
+ * @see waitpid()
+ *
+ * @see f_file_exists()
+ * @see f_signal_set_handle()
  */
 #ifndef _di_fll_execute_program_
   extern f_return_status fll_execute_program(const f_string_t program_name, const f_string_statics_t arguments, const f_signal_how_t *signals, int *result);
@@ -436,6 +486,10 @@ extern "C" {
  * This is done because the PATH environment will get cleared or may be set differently.
  * Execution of program_name is done using the PATH environment prior to clearing and reassigning the environment variables.
  *
+ * Unlike the execv() family of functions, this does not call exit() when the child process exits.
+ * Instead, this returns F_child and assigns the child's return code to result.
+ * The caller is expected to handle the appropriate exit procedures and memory deallocation.
+ *
  * @param program_name
  *   The name of the program.
  * @param arguments
@@ -444,42 +498,46 @@ extern "C" {
  *   An array of strings representing the environment variable names.
  *   At most names.used variables are created.
  *   Duplicate names are overwritten.
- * @param set_signal
- *   (optional) A pointer to the set of signals.
- *   Set to 0 to disable.
  * @param values
  *   An array of strings representing the environment variable names.
  *   The values.used must be of at least names.used.
  *   Set individual strings.used to 0 for empty/null values.
+ * @param signals
+ *   (optional) A pointer to the set of signals.
+ *   Set to 0 to disable.
  * @param result
  *   The code returned after finishing execution of program.
  *
  * @return
  *   F_none on success.
- *   F_access_denied (with error bit) on access denied for program_path.
- *   F_array_too_large (with error bit) if paths array (generated from PATH) is too large for further addressing.
- *   F_directory (with error bit) on invalid directory in program_path.
+ *   F_child on success but this is the child thread (this may happen when calling scripts rather than executing a binary).
  *   F_failure (with error bit) if result is non-zero.
- *   F_file_found_not (with error bit) if file does not exist at the program_path.
- *   F_fork (with error bit) on fork failure.
- *   F_loop (with error bit) on loop error while checking the program_path.
- *   F_memory_allocation (with error bit) on allocation error.
- *   F_memory_not (with error bit) if out of memory.
- *   F_memory_reallocation (with error bit) on reallocation error.
- *   F_name (with error bit) on path name error.
- *   F_number_overflow (with error bit) on overflow error.
- *   F_parameter (with error bit) if a parameter is invalid.
- *   F_string_too_large (with error bit) if the combined string (generated from PATH) is too large.
+ *   F_fork (with error bit) if fork failed.
  *
+ *   Errors (with error bit) from: f_environment_get().
  *   Errors (with error bit) from: f_file_exists().
+ *   Errors (with error bit) from: f_macro_string_dynamic_t_delete().
+ *   Errors (with error bit) from: f_macro_string_dynamics_t_delete().
+ *   Errors (with error bit) from: f_signal_set_handle().
  *   Errors (with error bit) from: fl_environment_path_explode_dynamic().
  *   Errors (with error bit) from: fl_string_append().
  *   Errors (with error bit) from: fl_string_dynamic_terminate().
  *
- * @see execvpe()
+ * @see execvp()
+ * @see fork()
+ * @see memcpy()
+ * @see strnlen()
+ * @see waitpid()
+ *
+ * @see f_environment_get()
+ * @see f_file_exists()
+ * @see f_signal_set_handle()
+ * @see fl_environment_path_explode_dynamic()
+ * @see fl_string_append()
+ * @see fl_string_dynamic_terminate()
  */
 #ifndef _di_fll_execute_program_environment_
-  extern f_return_status fll_execute_program_environment(const f_string_t program_name, const f_string_statics_t arguments, const f_signal_how_t *signals, const f_string_statics_t names, const f_string_statics_t values, int *result);
+  extern f_return_status fll_execute_program_environment(const f_string_t program_name, const f_string_statics_t arguments, const f_string_statics_t names, const f_string_statics_t values, const f_signal_how_t *signals, int *result);
 #endif // _di_fll_execute_program_environment_
 
 #ifdef __cplusplus
index aae70769b5c82e134e85d0bd2c08e4febfbd2bfc..11e12dc4477985a6c6288f82911a2a3fe15b2ed4 100644 (file)
@@ -7,27 +7,19 @@ extern "C" {
 
 #if !defined(_di_fll_execute_arguments_add_) || !defined(_di_fll_execute_arguments_add_set_) || !defined(_di_fll_execute_arguments_dynamic_add_) || !defined(_di_fll_execute_arguments_dynamic_add_set_)
   f_return_status private_fll_execute_arguments_add(const f_string_t source, const f_string_length_t length, f_string_dynamics_t *arguments) {
-    f_status_t status = F_none;
 
-    if (arguments->used == arguments->size) {
-      if (arguments->size + f_memory_default_allocation_step > f_array_length_t_size) {
-        if (arguments->size + 1 > f_array_length_t_size) return F_status_set_error(F_array_too_large);
-        f_macro_string_dynamics_t_resize(status, (*arguments), arguments->size + 1);
-      }
-      else {
-        f_macro_string_dynamics_t_resize(status, (*arguments), arguments->size + f_memory_default_allocation_step);
-      }
-
-      if (F_status_is_error(status)) return status;
-    }
+    f_status_t status = fl_string_dynamics_increase(arguments);
+    if (F_status_is_error(status)) return status;
 
     f_string_dynamic_t argument = f_string_dynamic_t_initialize;
 
-    status = fl_string_append(source, length, &argument);
+    if (length) {
+      status = fl_string_append(source, length, &argument);
 
-    if (F_status_is_error(status)) {
-      f_macro_string_dynamic_t_delete_simple(argument);
-      return status;
+      if (F_status_is_error(status)) {
+        f_macro_string_dynamic_t_delete_simple(argument);
+        return status;
+      }
     }
 
     status = fl_string_dynamic_terminate(&argument);
@@ -48,23 +40,13 @@ extern "C" {
 
 #if !defined(_di_fll_execute_arguments_add_parameter_) || !defined(_di_fll_execute_arguments_add_parameter_set_) || !defined(_di_fll_execute_arguments_dynamic_add_parameter_) || !defined(_di_fll_execute_arguments_dynamic_add_parameter_set_)
   f_return_status private_fll_execute_arguments_add_parameter(const f_string_t prefix, const f_string_length_t prefix_length, const f_string_t name, const f_string_length_t name_length, const f_string_t value, const f_string_length_t value_length, f_string_dynamics_t *arguments) {
-    f_status_t status = F_none;
 
-    if (arguments->used + 1 >= arguments->size) {
-      if (arguments->size + f_memory_default_allocation_step > f_array_length_t_size) {
-        if (arguments->size + 2 > f_array_length_t_size) return F_status_set_error(F_array_too_large);
-        f_macro_string_dynamics_t_resize(status, (*arguments), arguments->size + 2);
-      }
-      else {
-        f_macro_string_dynamics_t_resize(status, (*arguments), arguments->size + f_memory_default_allocation_step + 1);
-      }
-
-      if (F_status_is_error(status)) return status;
-    }
+    f_status_t status = fl_string_dynamics_increase(arguments);
+    if (F_status_is_error(status)) return status;
 
     f_string_dynamic_t argument = f_string_dynamic_t_initialize;
 
-    if (prefix_length > 0) {
+    if (prefix_length) {
       status = fl_string_append(prefix, prefix_length, &argument);
 
       if (F_status_is_error(status)) {
@@ -73,11 +55,13 @@ extern "C" {
       }
     }
 
-    status = fl_string_append(name, name_length, &argument);
+    if (name_length) {
+      status = fl_string_append(name, name_length, &argument);
 
-    if (F_status_is_error(status)) {
-      f_macro_string_dynamic_t_delete_simple(argument);
-      return status;
+      if (F_status_is_error(status)) {
+        f_macro_string_dynamic_t_delete_simple(argument);
+        return status;
+      }
     }
 
     status = fl_string_dynamic_terminate(&argument);
@@ -94,14 +78,23 @@ extern "C" {
 
     f_macro_string_dynamic_t_clear(argument);
 
-    status = fl_string_append(value, value_length, &argument);
+    if (value_length) {
+      status = fl_string_append(value, value_length, &argument);
+
+      if (F_status_is_error(status)) {
+        f_macro_string_dynamic_t_delete_simple(argument);
+        return status;
+      }
+    }
+
+    status = fl_string_dynamic_terminate(&argument);
 
     if (F_status_is_error(status)) {
       f_macro_string_dynamic_t_delete_simple(argument);
       return status;
     }
 
-    status = fl_string_dynamic_terminate(&argument);
+    status = fl_string_dynamics_increase(arguments);
 
     if (F_status_is_error(status)) {
       f_macro_string_dynamic_t_delete_simple(argument);
@@ -117,6 +110,113 @@ extern "C" {
   }
 #endif // !defined(_di_fll_execute_arguments_add_parameter_) || !defined(_di_fll_execute_arguments_add_parameter_set_) || !defined(_di_fll_execute_arguments_dynamic_add_parameter_) || !defined(_di_fll_execute_arguments_dynamic_add_parameter_set_)
 
+#if !defined(_di_fll_execute_path_) || !defined(_di_fll_execute_program_)
+  f_return_status private_fll_execute_fork(const f_string_t program_path, const f_string_t fixed_arguments[], const bool execute_program, const f_signal_how_t *signals, int *result) {
+
+    const pid_t process_id = fork();
+
+    if (process_id < 0) {
+      return F_status_set_error(F_fork);
+    }
+
+    // child process.
+    if (!process_id) {
+
+      if (signals) {
+        f_signal_set_handle(SIG_BLOCK, &signals->block);
+        f_signal_set_handle(SIG_UNBLOCK, &signals->block_not);
+      }
+
+      const int code = execute_program ? execvp(program_path, fixed_arguments) : execv(program_path, fixed_arguments);
+
+      if (result) {
+        *result = code;
+      }
+
+      return F_child;
+    }
+
+    // have the parent wait for the child process to finish.
+    waitpid(process_id, result, WUNTRACED | WCONTINUED);
+
+    if (result != 0) {
+      if (WIFEXITED(*result)) {
+        return F_none;
+      }
+
+      return F_status_set_error(F_failure);
+    }
+
+    return F_none;
+  }
+#endif // !defined(_di_fll_execute_path_) || !defined(_di_fll_execute_program_)
+
+#if !defined(_di_fll_execute_path_environment_) || !defined(_di_fll_execute_program_environment_)
+  f_return_status private_fll_execute_fork_environment(const f_string_t program_path, const f_string_t fixed_arguments[], const bool execute_program, const f_string_statics_t names, const f_string_statics_t values, const f_signal_how_t *signals, int *result) {
+
+    const pid_t process_id = fork();
+
+    if (process_id < 0) {
+      return F_status_set_error(F_fork);
+    }
+
+    // child process.
+    if (!process_id) {
+      if (signals) {
+        f_signal_set_handle(SIG_BLOCK, &signals->block);
+        f_signal_set_handle(SIG_UNBLOCK, &signals->block_not);
+      }
+
+      clearenv();
+
+      for (f_array_length_t i = 0; i < names.used; i++) {
+        f_environment_set_dynamic(names.array[i], values.array[i], F_true);
+      } // for
+
+      const int code = execute_program ? execvp(program_path, fixed_arguments) : execv(program_path, fixed_arguments);
+
+      if (result) {
+        *result = code;
+      }
+
+      return F_child;
+    }
+
+    // have the parent wait for the child process to finish.
+    waitpid(process_id, result, WUNTRACED | WCONTINUED);
+
+    if (result != 0) {
+      if (WIFEXITED(*result)) {
+        return F_none;
+      }
+
+      return F_status_set_error(F_failure);
+    }
+  }
+#endif // !defined(_di_fll_execute_path_environment_) || !defined(_di_fll_execute_program_environment_)
+
+#if !defined(_di_fll_execute_path_) || !defined(_di_fll_execute_path_environment_)
+  void private_fll_execute_path_arguments_fixate(const f_string_t program_path, const f_string_statics_t arguments, const f_string_length_t name_size, char program_name[], f_string_t fixed_arguments[]) {
+
+    memcpy(program_name, program_path, name_size);
+    program_name[name_size] = 0;
+
+    if (name_size) {
+      fixed_arguments[0] = program_name;
+    }
+    else {
+      fixed_arguments[0] = 0;
+    }
+
+    for (f_string_length_t i = 0; i < arguments.used; i++) {
+      fixed_arguments[i + 1] = arguments.array[i].string;
+    } // for
+
+    // insert the required end of array designator.
+    fixed_arguments[arguments.used + 1] = 0;
+  }
+#endif // !defined(_di_fll_execute_path_) || !defined(_di_fll_execute_path_environment_)
+
 #ifdef __cplusplus
 } // extern "C"
 #endif
index cf75d092fd974f66fe52c1148ed1041a3b0bd2c4..0b7df63a7a227ea9aba09073e33e008f3aa38cda 100644 (file)
@@ -44,12 +44,18 @@ extern "C" {
  *
  * @return
  *   F_none on success.
- *   F_data_not if name_length is 0.
- *   F_array_too_large (with error bit) if arguments array is too large for further allocation.
- *   F_memory_allocation (with error bit) on allocation error.
- *   F_memory_reallocation (with error bit) on reallocation error.
- *   F_parameter (with error bit) if a parameter is invalid.
  *
+ *   Errors (with error bit) from: f_macro_string_dynamic_t_delete_simple().
+ *   Errors (with error bit) from: f_macro_string_dynamics_t_resize().
+ *   Errors (with error bit) from: fl_string_append().
+ *   Errors (with error bit) from: fl_string_dynamic_terminate().
+ *   Errors (with error bit) from: fl_string_dynamics_increase().
+ *
+ * @see f_macro_string_dynamic_t_delete_simple()
+ * @see f_macro_string_dynamics_t_resize()
+ * @see fl_string_append()
+ * @see fl_string_dynamic_terminate()
+ * @see fl_string_dynamics_increase()
  * @see fll_execute_arguments_add()
  * @see fll_execute_arguments_add_set()
  * @see fll_execute_arguments_dynamic_add()
@@ -81,12 +87,18 @@ extern "C" {
  *
  * @return
  *   F_none on success.
- *   F_data_not if name_length is 0.
- *   F_array_too_large (with error bit) if arguments array is too large for further allocation.
- *   F_memory_allocation (with error bit) on allocation error.
- *   F_memory_reallocation (with error bit) on reallocation error.
- *   F_parameter (with error bit) if a parameter is invalid.
  *
+ *   Errors (with error bit) from: f_macro_string_dynamic_t_delete_simple().
+ *   Errors (with error bit) from: f_macro_string_dynamics_t_resize().
+ *   Errors (with error bit) from: fl_string_append().
+ *   Errors (with error bit) from: fl_string_dynamic_terminate().
+ *   Errors (with error bit) from: fl_string_dynamics_increase().
+ *
+ * @see f_macro_string_dynamic_t_delete_simple()
+ * @see f_macro_string_dynamics_t_resize()
+ * @see fl_string_append()
+ * @see fl_string_dynamic_terminate()
+ * @see fl_string_dynamics_increase()
  * @see fll_execute_arguments_add_parameter()
  * @see fll_execute_arguments_add_parameter_set()
  * @see fll_execute_arguments_dynamic_add_parameter()
@@ -96,6 +108,100 @@ extern "C" {
   extern f_return_status private_fll_execute_arguments_add_parameter(const f_string_t prefix, const f_string_length_t prefix_length, const f_string_t name, const f_string_length_t name_length, const f_string_t value, const f_string_length_t value_length, f_string_dynamics_t *arguments) f_gcc_attribute_visibility_internal;
 #endif // !defined(_di_fll_execute_arguments_add_parameter_) || !defined(_di_fll_execute_arguments_add_parameter_set_) || !defined(_di_fll_execute_arguments_dynamic_add_parameter_) || !defined(_di_fll_execute_arguments_dynamic_add_parameter_set_)
 
+/**
+ * Private function for performing the fork and execute operation.
+ *
+ * @param program_path
+ *   The part of the path to the program representing the program name to copy from.
+ * @param fixed_arguments
+ *   A fixed array of strings representing the arguments.
+ * @param execute_path
+ *   If TRUE then execvp() is called to perform execution.
+ *   If FALSE then execv() is called to perform execution.
+ * @param set_signal
+ *   (optional) A pointer to the set of signals.
+ *   Set to 0 to disable.
+ * @param result
+ *   The code returned after finishing execution of program_path.
+ *
+ * @return
+ *   F_none on success.
+ *   F_child on success but this is the child thread.
+ *   F_fork (with error bit set) on fork failure.
+ *   F_failure (with error bit set) on execution failure.
+ *
+ * @see execv()
+ * @see execvp()
+ * @see fll_execute_path()
+ * @see fll_execute_program()
+ */
+#if !defined(_di_fll_execute_path_) || !defined(_di_fll_execute_program_)
+  extern f_return_status private_fll_execute_fork(const f_string_t program_path, const f_string_t fixed_arguments[], const bool execute_path, const f_signal_how_t *signals, int *result) f_gcc_attribute_visibility_internal;
+#endif // !defined(_di_fll_execute_path_) || !defined(_di_fll_execute_program_)
+
+/**
+ * Private function for performing the fork and execute operation using a specified environment.
+ *
+ * @param program_path
+ *   The part of the path to the program representing the program name to copy from.
+ * @param fixed_arguments
+ *   A fixed array of strings representing the arguments.
+ * @param execute_program
+ *   If TRUE then execvp() is called to perform execution.
+ *   If FALSE then execv() is called to perform execution.
+ * @param names
+ *   An array of strings representing the environment variable names.
+ *   At most names.used variables are created.
+ *   Duplicate names are overwritten.
+ * @param values
+ *   An array of strings representing the environment variable names.
+ *   The values.used must be of at least names.used.
+ *   Set individual strings.used to 0 for empty/NULL values.
+ * @param signals
+ *   (optional) A pointer to the set of signals.
+ *   Set to 0 to disable.
+ * @param result
+ *   The code returned after finishing execution of program_path.
+ *
+ * @return
+ *   F_none on success.
+ *   F_child on success but this is the child thread.
+ *   F_fork (with error bit set) on fork failure.
+ *   F_failure (with error bit set) on execution failure.
+ *
+ * @see execv()
+ * @see execvpe()
+ * @see fll_execute_path_environment()
+ * @see fll_execute_program_environment()
+ */
+#if !defined(_di_fll_execute_path_environment_) || !defined(_di_fll_execute_program_environment_)
+  extern f_return_status private_fll_execute_fork_environment(const f_string_t program_path, const f_string_t fixed_arguments[], const bool execute_program, const f_string_statics_t names, const f_string_statics_t values, const f_signal_how_t *signals, int *result) f_gcc_attribute_visibility_internal;
+#endif // !defined(_di_fll_execute_path_environment_) || !defined(_di_fll_execute_program_environment_)
+
+/**
+ * Private function for reconstructing the arguments into a fixed array.
+ *
+ * @param program_path
+ *   The part of the path to the program representing the program name to copy from.
+ * @param arguments
+ *   An array of strings representing the arguments.
+ * @param name_size
+ *   The size of the program_path to copy.
+ * @param program_name
+ *   The destination to copy the name to.
+ * @param fixed_arguments
+ *   The array of arguments to be updated with the program name.
+ *
+ * @return
+ *   F_none on success.
+ *
+ * @see fll_execute_path()
+ * @see fll_execute_path_environment()
+ */
+#if !defined(_di_fll_execute_path_) || !defined(_di_fll_execute_path_environment_)
+  extern void private_fll_execute_path_arguments_fixate(const f_string_t program_path, const f_string_statics_t arguments, const f_string_length_t name_size, char program_name[], f_string_t fixed_arguments[]) f_gcc_attribute_visibility_internal;
+#endif // !defined(_di_fll_execute_path_) || !defined(_di_fll_execute_path_environment_)
+
 #ifdef __cplusplus
 } // extern "C"
 #endif
index c209c881f15e708c04c4d4012d9633c0b4c600f8..a539418d5c6cf59aad1fc480330c29f54392b29c 100644 (file)
@@ -416,6 +416,16 @@ extern "C" {
         return F_none;
       }
 
+      if (fl_string_compare(string, FL_status_string_child, length, FL_status_string_child_length) == F_equal_to) {
+        *code = F_child;
+        return F_none;
+      }
+
+      if (fl_string_compare(string, FL_status_string_child_not, length, FL_status_string_child_not_length) == F_equal_to) {
+        *code = F_child_not;
+        return F_none;
+      }
+
       if (fl_string_compare(string, FL_status_string_connected, length, FL_status_string_connected_length) == F_equal_to) {
         *code = F_connected;
         return F_none;
@@ -691,6 +701,16 @@ extern "C" {
         return F_none;
       }
 
+      if (fl_string_compare(string, FL_status_string_parent, length, FL_status_string_parent_length) == F_equal_to) {
+        *code = F_parent;
+        return F_none;
+      }
+
+      if (fl_string_compare(string, FL_status_string_parent_not, length, FL_status_string_parent_not_length) == F_equal_to) {
+        *code = F_parent_not;
+        return F_none;
+      }
+
       if (fl_string_compare(string, FL_status_string_pipe, length, FL_status_string_pipe_length) == F_equal_to) {
         *code = F_pipe;
         return F_none;
index f3fa3ddd91c3c71275a1048778dae20b421417b7..0f1d37b55c1cbc902363b3a01b63db071c72a577 100644 (file)
@@ -290,7 +290,7 @@ extern "C" {
           if (F_status_is_error_not(status) && status != F_signal) {
             f_string_static_t stub = f_string_static_t_initialize;
 
-            status = fake_build_operate(*data, stub);
+            status = fake_build_operate(stub, data);
           }
         }
         else if (data->operation == fake_operation_clean) {
@@ -310,14 +310,18 @@ extern "C" {
           }
 
           if (F_status_is_error_not(status) && status != F_signal) {
-            status = fake_make_operate(*data);
+            status = fake_make_operate(data);
+
+            if (status == F_child) {
+              break;
+            }
           }
         }
         else if (data->operation == fake_operation_skeleton) {
           status = fake_skeleton_operate(*data);
         }
 
-        if (status == F_signal || fake_signal_received(*data)) {
+        if (status == F_signal || status == F_child || fake_signal_received(*data)) {
           break;
         }
         else if (F_status_is_error(status)) {
@@ -337,7 +341,7 @@ extern "C" {
         if (F_status_is_error(status) || status == F_signal) {
           fprintf(data->error.to.stream, "%c", f_string_eol[0]);
         }
-        else {
+        else if (status != F_child) {
           fprintf(data->output.stream, "%cAll operations complete.%c%c", f_string_eol[0], f_string_eol[0], f_string_eol[0]);
         }
       }
index 67954cb9506f209865e03e572a8348a27b5eb0e4..6e6f91af0aade2e55f40bb9e385bb5a37e9f5f08 100644 (file)
@@ -378,6 +378,7 @@ extern "C" {
     uint8_t operation;
 
     mode_t umask;
+    int child;
     f_signal_t signal;
 
     f_string_dynamics_t define;
@@ -445,6 +446,7 @@ extern "C" {
       fll_error_print_t_initialize, \
       0, \
       0, \
+      0, \
       f_signal_t_initialize, \
       f_string_dynamics_t_initialize, \
       f_string_dynamic_t_initialize, \
index 7aa01253605dd91491425f5197ccf426184f1b5c..5d612b00b0b6f78c654f62f665d10bd06f368b1b 100644 (file)
@@ -11,6 +11,8 @@
  * @return
  *   0 on success.
  *   1 on error.
+ *
+ * @see exit()
  */
 int main(const unsigned long argc, const f_string_t *argv) {
   const f_console_arguments_t arguments = { argc, argv };
@@ -47,5 +49,9 @@ int main(const unsigned long argc, const f_string_t *argv) {
     return 1;
   }
 
+  if (status == F_child) {
+    exit(data.child);
+  }
+
   return 0;
 }
index 87b08037b7f6c3644eb6876f597d48f284f858ac..fcee29f7098738e70708aaf5969d232696d416f5 100644 (file)
@@ -165,7 +165,7 @@ extern "C" {
 
 #ifndef _di_fake_build_copy_
   void fake_build_copy(const fake_data_t data, const f_mode_t mode, const f_string_t label, const f_string_static_t source, const f_string_static_t destination, const f_string_statics_t files, const f_string_static_t file_stage, const f_string_length_t preserve, f_status_t *status) {
-    if (F_status_is_error(*status) || f_file_exists(file_stage.string) == F_true) return;
+    if (F_status_is_error(*status) || f_file_exists(file_stage.string) == F_true || *status == F_child) return;
 
     if (fake_signal_received(data)) {
       *status = F_status_set_error(F_signal);
@@ -379,7 +379,7 @@ extern "C" {
 
 #ifndef _di_fake_build_skeleton_
   void fake_build_skeleton(const fake_data_t data, const fake_build_data_t data_build, const mode_t mode, const f_string_static_t file_stage, f_status_t *status) {
-    if (F_status_is_error(*status) || f_file_exists(file_stage.string) == F_true) return;
+    if (F_status_is_error(*status) || f_file_exists(file_stage.string) == F_true || *status == F_child) return;
 
     if (fake_signal_received(data)) {
       *status = F_status_set_error(F_signal);
@@ -464,13 +464,13 @@ extern "C" {
 #endif // _di_fake_build_skeleton_
 
 #ifndef _di_fake_build_execute_process_script_
-  void fake_build_execute_process_script(const fake_data_t data, const fake_build_data_t data_build, const f_string_static_t process_script, const f_string_static_t file_stage, f_status_t *status) {
-    if (F_status_is_error(*status) || f_file_exists(file_stage.string) == F_true) return;
-    if (!process_script.used) return;
+  int fake_build_execute_process_script(const fake_data_t data, const fake_build_data_t data_build, const f_string_static_t process_script, const f_string_static_t file_stage, f_status_t *status) {
+    if (F_status_is_error(*status) || f_file_exists(file_stage.string) == F_true || *status == F_child) return data.child;
+    if (!process_script.used) return 0;
 
     if (fake_signal_received(data)) {
       *status = F_status_set_error(F_signal);
-      return;
+      return 0;
     }
 
     f_string_dynamics_t arguments = f_string_dynamics_t_initialize;
@@ -515,7 +515,7 @@ extern "C" {
       fll_error_print(data.error, F_status_set_fine(*status), "fll_execute_arguments_add", F_true);
 
       f_macro_string_dynamics_t_delete_simple(arguments);
-      return;
+      return 0;
     }
 
     {
@@ -536,7 +536,7 @@ extern "C" {
 
           f_macro_string_dynamic_t_delete_simple(defines);
           f_macro_string_dynamics_t_delete_simple(arguments);
-          return;
+          return 0;
         }
 
         *status = fl_string_dynamic_terminate_after(&defines);
@@ -546,7 +546,7 @@ extern "C" {
 
           f_macro_string_dynamic_t_delete_simple(defines);
           f_macro_string_dynamics_t_delete_simple(arguments);
-          return;
+          return 0;
         }
       }
 
@@ -618,7 +618,7 @@ extern "C" {
         fll_error_print(data.error, F_status_set_fine(*status), "fll_execute_arguments_add_parameter_set", F_true);
 
         f_macro_string_dynamics_t_delete_simple(arguments);
-        return;
+        return 0;
       }
     }
 
@@ -646,10 +646,12 @@ extern "C" {
 
         f_macro_string_dynamic_t_delete_simple(path);
         f_macro_string_dynamics_t_delete_simple(arguments);
-        return;
+        return 0;
       }
     }
 
+    int return_code = 0;
+
     if (fake_signal_received(data)) {
       *status = F_status_set_error(F_signal);
 
@@ -657,21 +659,19 @@ extern "C" {
       f_macro_string_dynamics_t_delete_simple(arguments);
     }
     else {
-      int return_code = 0;
-
       // child processes should receive all signals, without blocking.
       f_signal_how_t signals = f_signal_how_t_initialize;
       f_signal_set_empty(&signals.block);
       f_signal_set_fill(&signals.block_not);
 
-      *status = fll_execute_path_environment(path.string, arguments, &signals, data_build.environment.names, data_build.environment.values, &return_code);
+      *status = fll_execute_path_environment(path.string, arguments, data_build.environment.names, data_build.environment.values, &signals, &return_code);
 
       f_macro_string_dynamics_t_delete_simple(arguments);
 
       if (fake_signal_received(data)) {
         *status = F_status_set_error(F_signal);
       }
-      else {
+      else if (*status != F_child) {
         if (F_status_is_error(*status)) {
           if (F_status_set_fine(*status) == F_failure) {
             if (data.error.verbosity != f_console_verbosity_quiet) {
@@ -693,6 +693,8 @@ extern "C" {
     }
 
     f_macro_string_dynamic_t_delete_simple(path);
+
+    return return_code;
   }
 #endif // _di_fake_build_execute_process_script_
 
@@ -730,19 +732,21 @@ extern "C" {
 #endif // _di_fake_build_get_file_name_without_extension_
 
 #ifndef _di_fake_build_libraries_script_
-  void fake_build_libraries_script(const fake_data_t data, const fake_build_data_t data_build, const f_mode_t mode, const f_string_static_t file_stage, f_status_t *status) {
-    if (F_status_is_error(*status) || f_file_exists(file_stage.string) == F_true) return;
+  int fake_build_libraries_script(const fake_data_t data, const fake_build_data_t data_build, const f_mode_t mode, const f_string_static_t file_stage, f_status_t *status) {
+    if (F_status_is_error(*status) || f_file_exists(file_stage.string) == F_true || *status == F_child) return data.child;
 
     // @todo needs to perform some sort of regex replace on the library scripts.
 
     fake_build_touch(data, file_stage, status);
+
+    return 0;
   }
 #endif // _di_fake_build_libraries_script_
 
 #ifndef _di_fake_build_library_shared_
-  void fake_build_library_shared(const fake_data_t data, const fake_build_data_t data_build, const f_mode_t mode, const f_string_static_t file_stage, f_status_t *status) {
-    if (F_status_is_error(*status) || f_file_exists(file_stage.string) == F_true) return;
-    if (!data_build.setting.build_sources_library.used) return;
+  int fake_build_library_shared(const fake_data_t data, const fake_build_data_t data_build, const f_mode_t mode, const f_string_static_t file_stage, f_status_t *status) {
+    if (F_status_is_error(*status) || f_file_exists(file_stage.string) == F_true || *status == F_child) return data.child;
+    if (!data_build.setting.build_sources_library.used) return 0;
 
     if (data.error.verbosity != f_console_verbosity_quiet) {
       fprintf(data.output.stream, "%c", f_string_eol[0]);
@@ -786,7 +790,7 @@ extern "C" {
         fll_error_print(data.error, F_status_set_fine(*status), "fll_execute_arguments_add", F_true);
 
         f_macro_string_dynamics_t_delete_simple(arguments);
-        return;
+        return 0;
       }
     }
 
@@ -925,16 +929,22 @@ extern "C" {
         fll_error_print(data.error, F_status_set_fine(*status), "fll_execute_arguments_add", F_true);
 
         f_macro_string_dynamics_t_delete_simple(arguments);
-        return;
+        return 0;
       }
     }
 
-    fake_execute(data, data_build.environment, data_build.setting.build_compiler, arguments, status);
+    {
+      const int result = fake_execute(data, data_build.environment, data_build.setting.build_compiler, arguments, status);
 
-    f_macro_string_dynamics_t_delete_simple(arguments);
+      f_macro_string_dynamics_t_delete_simple(arguments);
 
-    if (F_status_is_error(*status)) {
-      return;
+      if (F_status_is_error(*status)) {
+        return 0;
+      }
+
+      if (*status == F_child) {
+        return result;
+      }
     }
 
     if (data_build.setting.version_target != fake_build_version_type_micro) {
@@ -963,7 +973,7 @@ extern "C" {
 
       if (fake_signal_received(data)) {
         *status = F_status_set_error(F_signal);
-        return;
+        return 0;
       }
 
       *status = f_file_link(parameter_file_name_micro, parameter_file_path);
@@ -974,11 +984,11 @@ extern "C" {
       else if (F_status_is_error(*status)) {
         if (F_status_set_fine(*status) == F_file_found) {
           fll_error_file_print(data.error, F_status_set_fine(*status), "f_file_link", F_true, parameter_file_path, "link", fll_error_file_type_file);
-          return;
+          return 0;
         }
 
         fll_error_file_print(data.error, F_status_set_fine(*status), "f_file_link", F_true, parameter_file_name_micro, "link", fll_error_file_type_file);
-        return;
+        return 0;
       }
     }
 
@@ -995,7 +1005,7 @@ extern "C" {
 
       if (fake_signal_received(data)) {
         *status = F_status_set_error(F_signal);
-        return;
+        return 0;
       }
 
       if (data_build.setting.version_target == fake_build_version_type_major) {
@@ -1027,7 +1037,7 @@ extern "C" {
         if (F_status_set_fine(*status) == F_file_found) {
           fll_error_file_print(data.error, F_status_set_fine(*status), "f_file_link", F_true, parameter_file_path, "link", fll_error_file_type_file);
 
-          return;
+          return 0;
         }
 
         if (data_build.setting.version_target == fake_build_version_type_major) {
@@ -1040,18 +1050,20 @@ extern "C" {
           fll_error_file_print(data.error, F_status_set_fine(*status), "f_file_link", F_true, parameter_file_name_micro, "link", fll_error_file_type_file);
         }
 
-        return;
+        return 0;
       }
     }
 
     fake_build_touch(data, file_stage, status);
+
+    return 0;
   }
 #endif // _di_fake_build_library_shared_
 
 #ifndef _di_fake_build_library_static_
-  void fake_build_library_static(const fake_data_t data, const fake_build_data_t data_build, const f_mode_t mode, const f_string_static_t file_stage, f_status_t *status) {
-    if (F_status_is_error(*status) || f_file_exists(file_stage.string) == F_true) return;
-    if (!data_build.setting.build_sources_library.used) return;
+  int fake_build_library_static(const fake_data_t data, const fake_build_data_t data_build, const f_mode_t mode, const f_string_static_t file_stage, f_status_t *status) {
+    if (F_status_is_error(*status) || f_file_exists(file_stage.string) == F_true || *status == F_child) return data.child;
+    if (!data_build.setting.build_sources_library.used) return 0;
 
     if (data.error.verbosity != f_console_verbosity_quiet) {
       fprintf(data.output.stream, "%c", f_string_eol[0]);
@@ -1167,17 +1179,21 @@ extern "C" {
       } // for
     }
 
+    int result = data.child;
+
     if (F_status_is_error_not(*status)) {
-      fake_execute(data, data_build.environment, data_build.setting.build_indexer, arguments, status);
+      result = fake_execute(data, data_build.environment, data_build.setting.build_indexer, arguments, status);
     }
 
     f_macro_string_dynamic_t_delete_simple(file_name);
     f_macro_string_dynamic_t_delete_simple(source_path);
     f_macro_string_dynamics_t_delete_simple(arguments);
 
-    if (F_status_is_error_not(*status)) {
+    if (F_status_is_error_not(*status) && *status != F_child) {
       fake_build_touch(data, file_stage, status);
     }
+
+    return result;
   }
 #endif // _di_fake_build_library_static_
 
@@ -2377,9 +2393,9 @@ extern "C" {
 #endif // _di_fake_build_load_stage_
 
 #ifndef _di_fake_build_objects_static_
-  void fake_build_objects_static(const fake_data_t data, const fake_build_data_t data_build, const f_mode_t mode, const f_string_static_t file_stage, f_status_t *status) {
-    if (F_status_is_error(*status) || f_file_exists(file_stage.string) == F_true) return;
-    if (!data_build.setting.build_sources_library.used) return;
+  int fake_build_objects_static(const fake_data_t data, const fake_build_data_t data_build, const f_mode_t mode, const f_string_static_t file_stage, f_status_t *status) {
+    if (F_status_is_error(*status) || f_file_exists(file_stage.string) == F_true || *status == F_child) return data.child;
+    if (!data_build.setting.build_sources_library.used) return 0;
 
     if (data.error.verbosity != f_console_verbosity_quiet) {
       fprintf(data.output.stream, "%c", f_string_eol[0]);
@@ -2395,6 +2411,8 @@ extern "C" {
 
     const f_string_static_t *path_sources = &data.path_sources;
 
+    int result = data.child;
+
     if (data_build.setting.path_standard) {
       path_sources = &data.path_sources_c;
 
@@ -2555,27 +2573,29 @@ extern "C" {
         break;
       }
 
-      fake_execute(data, data_build.environment, data_build.setting.build_compiler, arguments, status);
+      result = fake_execute(data, data_build.environment, data_build.setting.build_compiler, arguments, status);
 
       f_macro_string_dynamics_t_delete_simple(arguments);
 
-      if (F_status_is_error(*status)) break;
+      if (F_status_is_error(*status) || *status == F_child) break;
     } // for
 
     f_macro_string_dynamic_t_delete_simple(file_name);
     f_macro_string_dynamic_t_delete_simple(destination_path);
     f_macro_string_dynamics_t_delete_simple(arguments);
 
-    if (F_status_is_error_not(*status)) {
+    if (F_status_is_error_not(*status) && *status != F_child) {
       fake_build_touch(data, file_stage, status);
     }
+
+    return result;
   }
 #endif // _di_fake_build_objects_static_
 
 #ifndef _di_fake_build_operate_
-  f_return_status fake_build_operate(const fake_data_t data, const f_string_static_t setting_file) {
+  f_return_status fake_build_operate(const f_string_static_t setting_file, fake_data_t *data) {
 
-    if (fake_signal_received(data)) {
+    if (fake_signal_received(*data)) {
       return F_signal;
     }
 
@@ -2585,70 +2605,70 @@ extern "C" {
     fake_build_data_t data_build = fake_build_data_t_initialize;
     fake_build_stage_t stage = fake_build_stage_t_initialize;
 
-    f_macro_mode_t_set_default_umask(mode, data.umask);
+    f_macro_mode_t_set_default_umask(mode, data->umask);
 
-    fake_build_load_setting(data, setting_file, &data_build.setting, &status);
+    fake_build_load_setting(*data, setting_file, &data_build.setting, &status);
 
     if (F_status_is_fine(status)) {
-      if (data.error.verbosity != f_console_verbosity_quiet) {
-        fprintf(data.output.stream, "%c", f_string_eol[0]);
-        fl_color_print(data.output.stream, data.context.set.important, "Building project%c", data_build.setting.project_name.used ? ' ' : 0);
+      if (data->error.verbosity != f_console_verbosity_quiet) {
+        fprintf(data->output.stream, "%c", f_string_eol[0]);
+        fl_color_print(data->output.stream, data->context.set.important, "Building project%c", data_build.setting.project_name.used ? ' ' : 0);
 
         if (data_build.setting.project_name.used) {
-          fl_color_print_code(data.output.stream, data.context.notable);
-          f_print_dynamic(data.output.stream, data_build.setting.project_name);
-          fl_color_print_code(data.output.stream, data.context.reset);
+          fl_color_print_code(data->output.stream, data->context.notable);
+          f_print_dynamic(data->output.stream, data_build.setting.project_name);
+          fl_color_print_code(data->output.stream, data->context.reset);
         }
 
-        fl_color_print(data.output.stream, data.context.set.important, ".");
-        fprintf(data.output.stream, "%c", f_string_eol[0]);
+        fl_color_print(data->output.stream, data->context.set.important, ".");
+        fprintf(data->output.stream, "%c", f_string_eol[0]);
       }
     }
 
-    fake_build_load_stage(data, setting_file, &stage, &status);
+    fake_build_load_stage(*data, setting_file, &stage, &status);
 
-    fake_build_load_environment(data, data_build, &data_build.environment, &status);
+    fake_build_load_environment(*data, data_build, &data_build.environment, &status);
 
-    fake_build_skeleton(data, data_build, mode.directory, stage.file_skeleton, &status);
+    fake_build_skeleton(*data, data_build, mode.directory, stage.file_skeleton, &status);
 
-    fake_build_execute_process_script(data, data_build, data_build.setting.process_pre, stage.file_process_pre, &status);
+    data->child = fake_build_execute_process_script(*data, data_build, data_build.setting.process_pre, stage.file_process_pre, &status);
 
-    fake_build_copy(data, mode, "setting files", data.path_data_settings, data.path_build_settings, data_build.setting.build_sources_setting, stage.file_sources_settings, 0, &status);
+    fake_build_copy(*data, mode, "setting files", data->path_data_settings, data->path_build_settings, data_build.setting.build_sources_setting, stage.file_sources_settings, 0, &status);
 
     if (data_build.setting.build_language == fake_build_language_type_bash) {
-      fake_build_libraries_script(data, data_build, mode, stage.file_libraries_script, &status);
+      fake_build_libraries_script(*data, data_build, mode, stage.file_libraries_script, &status);
 
-      fake_build_programs_script(data, data_build, mode, stage.file_programs_script, &status);
+      fake_build_programs_script(*data, data_build, mode, stage.file_programs_script, &status);
 
       if (data_build.setting.build_script) {
-        fake_build_copy(data, mode, "scripts", data.path_sources_script, data.path_build_programs_script, data_build.setting.build_sources_script, stage.file_sources_script, 0, &status);
+        fake_build_copy(*data, mode, "scripts", data->path_sources_script, data->path_build_programs_script, data_build.setting.build_sources_script, stage.file_sources_script, 0, &status);
       }
     }
     else {
       if (data_build.setting.build_sources_headers.used) {
-        const f_string_static_t *path_sources = &data.path_sources;
+        const f_string_static_t *path_sources = &data->path_sources;
 
         if (data_build.setting.path_standard) {
-          path_sources = &data.path_sources_c;
+          path_sources = &data->path_sources_c;
 
           if (data_build.setting.build_language == fake_build_language_type_cpp) {
-            path_sources = &data.path_sources_cpp;
+            path_sources = &data->path_sources_cpp;
           }
         }
-        else if (data.parameters[fake_parameter_path_sources].result != f_console_result_additional) {
+        else if (data->parameters[fake_parameter_path_sources].result != f_console_result_additional) {
           path_sources = &data_build.setting.path_sources;
         }
 
         const f_string_length_t path_sources_base_length = path_sources->used;
 
         f_string_static_t path_headers = f_string_static_t_initialize;
-        f_string_length_t directory_headers_length = data.path_build_includes.used + data_build.setting.path_headers.used;
+        f_string_length_t directory_headers_length = data->path_build_includes.used + data_build.setting.path_headers.used;
 
         char directory_headers[directory_headers_length + 1];
 
         if (data_build.setting.path_headers.used > 0) {
-          memcpy(directory_headers, data.path_build_includes.string, data.path_build_includes.used);
-          memcpy(directory_headers + data.path_build_includes.used, data_build.setting.path_headers.string, data_build.setting.path_headers.used);
+          memcpy(directory_headers, data->path_build_includes.string, data->path_build_includes.used);
+          memcpy(directory_headers + data->path_build_includes.used, data_build.setting.path_headers.string, data_build.setting.path_headers.used);
 
           directory_headers[directory_headers_length] = 0;
 
@@ -2657,7 +2677,7 @@ extern "C" {
           path_headers.size = directory_headers_length + 1;
         }
         else {
-          memcpy(directory_headers, data.path_build_includes.string, data.path_build_includes.used);
+          memcpy(directory_headers, data->path_build_includes.string, data->path_build_includes.used);
 
           directory_headers[directory_headers_length] = 0;
 
@@ -2666,29 +2686,29 @@ extern "C" {
           path_headers.size = directory_headers_length + 1;
         }
 
-        fake_build_copy(data, mode, "header files", *path_sources, path_headers, data_build.setting.build_sources_headers, stage.file_sources_headers, data_build.setting.path_headers_preserve ? path_sources_base_length : 0, &status);
+        fake_build_copy(*data, mode, "header files", *path_sources, path_headers, data_build.setting.build_sources_headers, stage.file_sources_headers, data_build.setting.path_headers_preserve ? path_sources_base_length : 0, &status);
       }
 
       if (data_build.setting.build_shared) {
-        fake_build_library_shared(data, data_build, mode, stage.file_libraries_shared, &status);
+        data->child = fake_build_library_shared(*data, data_build, mode, stage.file_libraries_shared, &status);
 
-        fake_build_program_shared(data, data_build, mode, stage.file_programs_shared, &status);
+        data->child = fake_build_program_shared(*data, data_build, mode, stage.file_programs_shared, &status);
       }
 
       if (data_build.setting.build_static) {
-        fake_build_objects_static(data, data_build, mode, stage.file_objects_static, &status);
+        data->child = fake_build_objects_static(*data, data_build, mode, stage.file_objects_static, &status);
 
-        fake_build_library_static(data, data_build, mode, stage.file_libraries_static, &status);
+        data->child = fake_build_library_static(*data, data_build, mode, stage.file_libraries_static, &status);
 
-        fake_build_program_static(data, data_build, mode, stage.file_programs_static, &status);
+        data->child = fake_build_program_static(*data, data_build, mode, stage.file_programs_static, &status);
       }
 
       if (data_build.setting.build_script) {
-        fake_build_copy(data, mode, "scripts", data.path_sources_script, data.path_build_programs_script, data_build.setting.build_sources_script, stage.file_sources_script, 0, &status);
+        fake_build_copy(*data, mode, "scripts", data->path_sources_script, data->path_build_programs_script, data_build.setting.build_sources_script, stage.file_sources_script, 0, &status);
       }
     }
 
-    fake_build_execute_process_script(data, data_build, data_build.setting.process_post, stage.file_process_post, &status);
+    fake_build_execute_process_script(*data, data_build, data_build.setting.process_post, stage.file_process_post, &status);
 
     fake_macro_build_data_delete_simple(data_build);
     fake_macro_build_stage_t_delete_simple(stage);
@@ -2703,19 +2723,21 @@ extern "C" {
 #endif // _di_fake_build_operate_
 
 #ifndef _di_fake_build_programs_script_
-  void fake_build_programs_script(const fake_data_t data, const fake_build_data_t data_build, const f_mode_t mode, const f_string_static_t file_stage, f_status_t *status) {
-    if (F_status_is_error(*status) || f_file_exists(file_stage.string) == F_true) return;
+  int fake_build_programs_script(const fake_data_t data, const fake_build_data_t data_build, const f_mode_t mode, const f_string_static_t file_stage, f_status_t *status) {
+    if (F_status_is_error(*status) || f_file_exists(file_stage.string) == F_true || *status == F_child) return data.child;
 
     // @todo needs to perform some sort of regex replace on the program scripts.
 
     fake_build_touch(data, file_stage, status);
+
+    return 0;
   }
 #endif // _di_fake_build_programs_script_
 
 #ifndef _di_fake_build_program_shared_
-  void fake_build_program_shared(const fake_data_t data, const fake_build_data_t data_build, const f_mode_t mode, const f_string_static_t file_stage, f_status_t *status) {
-    if (F_status_is_error(*status) || f_file_exists(file_stage.string) == F_true) return;
-    if (!data_build.setting.build_sources_program.used) return;
+  int fake_build_program_shared(const fake_data_t data, const fake_build_data_t data_build, const f_mode_t mode, const f_string_static_t file_stage, f_status_t *status) {
+    if (F_status_is_error(*status) || f_file_exists(file_stage.string) == F_true || *status == F_child) return data.child;
+    if (!data_build.setting.build_sources_program.used) return 0;
 
     if (data.error.verbosity != f_console_verbosity_quiet) {
       fprintf(data.output.stream, "%c", f_string_eol[0]);
@@ -2799,23 +2821,25 @@ extern "C" {
       fll_error_print(data.error, F_status_set_fine(*status), "fll_execute_arguments_add", F_true);
 
       f_macro_string_dynamics_t_delete_simple(arguments);
-      return;
+      return 0;
     }
 
-    fake_execute(data, data_build.environment, data_build.setting.build_compiler, arguments, status);
+    int result = fake_execute(data, data_build.environment, data_build.setting.build_compiler, arguments, status);
 
     f_macro_string_dynamics_t_delete_simple(arguments);
 
-    if (F_status_is_error_not(*status)) {
+    if (F_status_is_error_not(*status) && *status != F_child) {
       fake_build_touch(data, file_stage, status);
     }
+
+    return result;
   }
 #endif // _di_fake_build_program_shared_
 
 #ifndef _di_fake_build_program_static_
-  void fake_build_program_static(const fake_data_t data, const fake_build_data_t data_build, const f_mode_t mode, const f_string_static_t file_stage, f_status_t *status) {
-    if (F_status_is_error(*status) || f_file_exists(file_stage.string) == F_true) return;
-    if (!data_build.setting.build_sources_program.used) return;
+  int fake_build_program_static(const fake_data_t data, const fake_build_data_t data_build, const f_mode_t mode, const f_string_static_t file_stage, f_status_t *status) {
+    if (F_status_is_error(*status) || f_file_exists(file_stage.string) == F_true || *status == F_child) return data.child;
+    if (!data_build.setting.build_sources_program.used) return 0;
 
     if (data.error.verbosity != f_console_verbosity_quiet) {
       fprintf(data.output.stream, "%c", f_string_eol[0]);
@@ -2915,16 +2939,18 @@ extern "C" {
       fll_error_print(data.error, F_status_set_fine(*status), "fll_execute_arguments_add", F_true);
 
       f_macro_string_dynamics_t_delete_simple(arguments);
-      return;
+      return 0;
     }
 
-    fake_execute(data, data_build.environment, data_build.setting.build_compiler, arguments, status);
+    int result = fake_execute(data, data_build.environment, data_build.setting.build_compiler, arguments, status);
 
     f_macro_string_dynamics_t_delete_simple(arguments);
 
-    if (F_status_is_error_not(*status)) {
+    if (F_status_is_error_not(*status) && *status != F_child) {
       fake_build_touch(data, file_stage, status);
     }
+
+    return result;
   }
 #endif // _di_fake_build_program_static_
 
index c88a2b451d3c38ad04e055b2e2d87e201b68f870..c248381fdbe7cbd4707d2a32b29d8913093851cf 100644 (file)
@@ -483,15 +483,16 @@ extern "C" {
  * @param file_stage
  *   The specific stage file path.
  * @param status
- *   The return status.
- *
- * @return
  *   F_none on success.
  *
  *   Status codes (with error bit) are returned on any problem.
+ *
+ * @return
+ *   The return code of the execution process.
+ *   This generally is only needed when F_child is returned, where this holds the return status of the child process.
  */
 #ifndef _di_fake_build_execute_process_script_
-  extern void fake_build_execute_process_script(const fake_data_t data, const fake_build_data_t data_build, const f_string_static_t process_script, const f_string_static_t file_stage, f_status_t *status) f_gcc_attribute_visibility_internal;
+  extern int fake_build_execute_process_script(const fake_data_t data, const fake_build_data_t data_build, const f_string_static_t process_script, const f_string_static_t file_stage, f_status_t *status) f_gcc_attribute_visibility_internal;
 #endif // _di_fake_build_execute_process_script_
 
 /**
@@ -525,15 +526,16 @@ extern "C" {
  * @param file_stage
  *   The specific stage file path.
  * @param status
- *   The return status.
- *
- * @return
  *   F_none on success.
  *
  *   Status codes (with error bit) are returned on any problem.
+ *
+ * @return
+ *   The return code of the execution process.
+ *   This generally is only needed when F_child is returned, where this holds the return status of the child process.
  */
 #ifndef _di_fake_build_libraries_script_
-  extern void fake_build_libraries_script(const fake_data_t data, const fake_build_data_t data_build, const f_mode_t mode, const f_string_static_t file_stage, f_status_t *status) f_gcc_attribute_visibility_internal;
+  extern int fake_build_libraries_script(const fake_data_t data, const fake_build_data_t data_build, const f_mode_t mode, const f_string_static_t file_stage, f_status_t *status) f_gcc_attribute_visibility_internal;
 #endif // _di_fake_build_libraries_script_
 
 /**
@@ -548,15 +550,16 @@ extern "C" {
  * @param file_stage
  *   The specific stage file path.
  * @param status
- *   The return status.
- *
- * @return
  *   F_none on success.
  *
  *   Status codes (with error bit) are returned on any problem.
+ *
+ * @return
+ *   The return code of the execution process.
+ *   This generally is only needed when F_child is returned, where this holds the return status of the child process.
  */
 #ifndef _di_fake_build_library_shared_
-  extern void fake_build_library_shared(const fake_data_t data, const fake_build_data_t data_build, const f_mode_t mode, const f_string_static_t file_stage, f_status_t *status) f_gcc_attribute_visibility_internal;
+  extern int fake_build_library_shared(const fake_data_t data, const fake_build_data_t data_build, const f_mode_t mode, const f_string_static_t file_stage, f_status_t *status) f_gcc_attribute_visibility_internal;
 #endif // _di_fake_build_library_shared_
 
 /**
@@ -571,15 +574,16 @@ extern "C" {
  * @param file_stage
  *   The specific stage file path.
  * @param status
- *   The return status.
- *
- * @return
  *   F_none on success.
  *
  *   Status codes (with error bit) are returned on any problem.
+ *
+ * @return
+ *   The return code of the execution process.
+ *   This generally is only needed when F_child is returned, where this holds the return status of the child process.
  */
 #ifndef _di_fake_build_library_static_
-  extern void fake_build_library_static(const fake_data_t data, const fake_build_data_t data_build, const f_mode_t mode, const f_string_static_t file_stage, f_status_t *status) f_gcc_attribute_visibility_internal;
+  extern int fake_build_library_static(const fake_data_t data, const fake_build_data_t data_build, const f_mode_t mode, const f_string_static_t file_stage, f_status_t *status) f_gcc_attribute_visibility_internal;
 #endif // _di_fake_build_library_static_
 
 /**
@@ -711,25 +715,26 @@ extern "C" {
  * @param file_stage
  *   The specific stage file path.
  * @param status
- *   The return status.
- *
- * @return
  *   F_none on success.
  *
  *   Status codes (with error bit) are returned on any problem.
+ *
+ * @return
+ *   The return code of the execution process.
+ *   This generally is only needed when F_child is returned, where this holds the return status of the child process.
  */
 #ifndef _di_fake_build_objects_static_
-  extern void fake_build_objects_static(const fake_data_t data, const fake_build_data_t data_build, const f_mode_t mode, const f_string_static_t file_stage, f_status_t *status) f_gcc_attribute_visibility_internal;
+  extern int fake_build_objects_static(const fake_data_t data, const fake_build_data_t data_build, const f_mode_t mode, const f_string_static_t file_stage, f_status_t *status) f_gcc_attribute_visibility_internal;
 #endif // _di_fake_build_objects_static_
 
 /**
  * Execute the build operation.
  *
- * @param data
- *   The program data.
  * @param setting_file
  *   The name of the settings file to use.
  *   If setting_file.used is 0, then the default or program parameter supplied file is used.
+ * @param data
+ *   The program data.
  *
  * @return
  *   F_none on success.
@@ -737,7 +742,7 @@ extern "C" {
  *   Status codes (with error bit) are returned on any problem.
  */
 #ifndef _di_fake_build_operate_
-  extern f_return_status fake_build_operate(const fake_data_t data, const f_string_static_t setting_file) f_gcc_attribute_visibility_internal;
+  extern f_return_status fake_build_operate(const f_string_static_t setting_file, fake_data_t *data) f_gcc_attribute_visibility_internal;
 #endif // _di_fake_build_operate_
 
 /**
@@ -752,15 +757,16 @@ extern "C" {
  * @param file_stage
  *   The specific stage file path.
  * @param status
- *   The return status.
- *
- * @return
  *   F_none on success.
  *
  *   Status codes (with error bit) are returned on any problem.
+ *
+ * @return
+ *   The return code of the execution process.
+ *   This generally is only needed when F_child is returned, where this holds the return status of the child process.
  */
 #ifndef _di_fake_build_programs_script_
-  extern void fake_build_programs_script(const fake_data_t data, const fake_build_data_t data_build, const f_mode_t mode, const f_string_static_t file_stage, f_status_t *status) f_gcc_attribute_visibility_internal;
+  extern int fake_build_programs_script(const fake_data_t data, const fake_build_data_t data_build, const f_mode_t mode, const f_string_static_t file_stage, f_status_t *status) f_gcc_attribute_visibility_internal;
 #endif // _di_fake_build_programs_script_
 
 /**
@@ -775,15 +781,16 @@ extern "C" {
  * @param file_stage
  *   The specific stage file path.
  * @param status
- *   The return status.
- *
- * @return
  *   F_none on success.
  *
  *   Status codes (with error bit) are returned on any problem.
+ *
+ * @return
+ *   The return code of the execution process.
+ *   This generally is only needed when F_child is returned, where this holds the return status of the child process.
  */
 #ifndef _di_fake_build_program_shared_
-  extern void fake_build_program_shared(const fake_data_t data, const fake_build_data_t data_build, const f_mode_t mode, const f_string_static_t file_stage, f_status_t *status) f_gcc_attribute_visibility_internal;
+  extern int fake_build_program_shared(const fake_data_t data, const fake_build_data_t data_build, const f_mode_t mode, const f_string_static_t file_stage, f_status_t *status) f_gcc_attribute_visibility_internal;
 #endif // _di_fake_build_program_shared_
 
 /**
@@ -798,15 +805,16 @@ extern "C" {
  * @param file_stage
  *   The specific stage file path.
  * @param status
- *   The return status.
- *
- * @return
  *   F_none on success.
  *
  *   Status codes (with error bit) are returned on any problem.
+ *
+ * @return
+ *   The return code of the execution process.
+ *   This generally is only needed when F_child is returned, where this holds the return status of the child process.
  */
 #ifndef _di_fake_build_program_static_
-  extern void fake_build_program_static(const fake_data_t data, const fake_build_data_t data_build, const f_mode_t mode, const f_string_static_t file_stage, f_status_t *status) f_gcc_attribute_visibility_internal;
+  extern int fake_build_program_static(const fake_data_t data, const fake_build_data_t data_build, const f_mode_t mode, const f_string_static_t file_stage, f_status_t *status) f_gcc_attribute_visibility_internal;
 #endif // _di_fake_build_program_static_
 
 /**
index 9969f72d541712e8890fe6207c89cef583aaad46..9e56f0fcc1080613339b47ce8a6e39cf8f6626f8 100644 (file)
@@ -41,12 +41,16 @@ extern "C" {
       f_signal_set_empty(&signals.block);
       f_signal_set_fill(&signals.block_not);
 
-      *status = fll_execute_program_environment(program.string, arguments, &signals, environment.names, environment.values, &return_code);
+      *status = fll_execute_program_environment(program.string, arguments, environment.names, environment.values, &signals, &return_code);
 
       if (fake_signal_received(data)) {
         *status = F_status_set_error(F_signal);
         return 0;
       }
+
+      if (*status == F_child) {
+        return return_code;
+      }
     }
     else {
       *status = F_status_set_error(F_file_found_not);
index 1b984e0059a54beefcc312ba0d498aba6ce95225..67ce461ee83a9192e00ec285983dccd70623b1af 100644 (file)
@@ -1048,15 +1048,15 @@ extern "C" {
 #endif // _di_fake_make_load_parameters_
 
 #ifndef _di_fake_make_operate_
-  f_return_status fake_make_operate(const fake_data_t data) {
+  f_return_status fake_make_operate(fake_data_t *data) {
 
-    if (fake_signal_received(data)) {
+    if (fake_signal_received(*data)) {
       return F_signal;
     }
 
-    if (data.error.verbosity != f_console_verbosity_quiet) {
-      fprintf(data.output.stream, "%c", f_string_eol[0]);
-      fl_color_print(data.output.stream, data.context.set.important, "Making project.%c", f_string_eol[0]);
+    if (data->error.verbosity != f_console_verbosity_quiet) {
+      fprintf(data->output.stream, "%c", f_string_eol[0]);
+      fl_color_print(data->output.stream, data->context.set.important, "Making project.%c", f_string_eol[0]);
     }
 
     f_status_t status = F_none;
@@ -1068,11 +1068,11 @@ extern "C" {
     f_macro_string_dynamics_new(status, data_make.path.stack, f_memory_default_allocation_step);
 
     if (F_status_is_error(status)) {
-      fll_error_print(data.error, F_status_set_fine(status), "f_macro_string_dynamics_new", F_true);
+      fll_error_print(data->error, F_status_set_fine(status), "f_macro_string_dynamics_new", F_true);
       return status;
     }
 
-    if (fake_signal_received(data)) {
+    if (fake_signal_received(*data)) {
       fake_macro_make_data_t_delete_simple(data_make);
       return F_signal;
     }
@@ -1080,7 +1080,7 @@ extern "C" {
     status = f_path_current(F_true, &data_make.path.stack.array[0]);
 
     if (F_status_is_error(status)) {
-      fll_error_print(data.error, F_status_set_fine(status), "f_path_current", F_true);
+      fll_error_print(data->error, F_status_set_fine(status), "f_path_current", F_true);
 
       fake_macro_make_data_t_delete_simple(data_make);
       return status;
@@ -1089,7 +1089,7 @@ extern "C" {
     status = f_directory_open(data_make.path.stack.array[0].string, F_false, &data_make.path.top.id);
 
     if (F_status_is_error(status)) {
-      fll_error_print(data.error, F_status_set_fine(status), "f_directory_open", F_true);
+      fll_error_print(data->error, F_status_set_fine(status), "f_directory_open", F_true);
 
       fake_macro_make_data_t_delete_simple(data_make);
       return status;
@@ -1097,11 +1097,11 @@ extern "C" {
 
     data_make.path.stack.used = 1;
 
-    f_macro_mode_t_set_default_umask(mode, data.umask);
+    f_macro_mode_t_set_default_umask(mode, data->umask);
 
-    fake_make_load_parameters(data, &data_make, &status);
+    fake_make_load_parameters(*data, &data_make, &status);
 
-    fake_make_load_fakefile(data, &data_make, &status);
+    fake_make_load_fakefile(*data, &data_make, &status);
 
     if (F_status_is_error(status)) {
       fake_macro_make_data_t_delete_simple(data_make);
@@ -1116,15 +1116,15 @@ extern "C" {
 
     if (data_make.setting_make.fail == fake_make_operation_fail_type_exit) {
       data_make.error.prefix = fll_error_print_error;
-      data_make.error.context = data.context.set.error;
-      data_make.error.notable = data.context.set.notable;
+      data_make.error.context = data->context.set.error;
+      data_make.error.notable = data->context.set.notable;
       data_make.error.to.stream = f_type_error;
       data_make.error.to.id = f_type_descriptor_error;
     }
     else if (data_make.setting_make.fail == fake_make_operation_fail_type_warn) {
       data_make.error.prefix = fll_error_print_warning;
-      data_make.error.context = data.context.set.warning;
-      data_make.error.notable = data.context.set.notable;
+      data_make.error.context = data->context.set.warning;
+      data_make.error.notable = data->context.set.notable;
       data_make.error.to.stream = f_type_warning;
       data_make.error.to.id = f_type_descriptor_warning;
     }
@@ -1133,7 +1133,13 @@ extern "C" {
       data_make.error.to.id = -1;
     }
 
-    fake_make_operate_section(data, data_make.main, &data_make, &section_stack, &status);
+    {
+      const int result = fake_make_operate_section(data_make.main, data, &data_make, &section_stack, &status);
+
+      if (status == F_child) {
+        data->child = result;
+      }
+    }
 
     if (data_make.path.current.stream) {
       f_file_stream_close(F_true, &data_make.path.current);
@@ -1142,13 +1148,13 @@ extern "C" {
     {
       f_status_t status_path = f_path_change_at(data_make.path.top.id);
 
-      if (F_status_is_error(status_path) && data.error.verbosity == f_console_verbosity_verbose) {
-        fprintf(data.output.stream, "%c", f_string_eol[0]);
-        fl_color_print(data.output.stream, data.context.set.warning, "%sFailed change back to orignal path '", fll_error_print_warning);
-        fl_color_print(data.output.stream, data.context.set.notable, "%s", data_make.path.stack.array[0].string);
-        fl_color_print(data.output.stream, data.context.set.warning, "', status code = ");
-        fl_color_print(data.output.stream, data.context.set.notable, "%llu", F_status_set_fine(status_path));
-        fl_color_print(data.output.stream, data.context.set.warning, ".%c", f_string_eol[0]);
+      if (F_status_is_error(status_path) && data->error.verbosity == f_console_verbosity_verbose) {
+        fprintf(data->output.stream, "%c", f_string_eol[0]);
+        fl_color_print(data->output.stream, data->context.set.warning, "%sFailed change back to orignal path '", fll_error_print_warning);
+        fl_color_print(data->output.stream, data->context.set.notable, "%s", data_make.path.stack.array[0].string);
+        fl_color_print(data->output.stream, data->context.set.warning, "', status code = ");
+        fl_color_print(data->output.stream, data->context.set.notable, "%llu", F_status_set_fine(status_path));
+        fl_color_print(data->output.stream, data->context.set.warning, ".%c", f_string_eol[0]);
       }
     }
 
@@ -1883,19 +1889,19 @@ extern "C" {
 #endif // _di_fake_make_operate_expand_environment_
 
 #ifndef _di_fake_make_operate_section_
-  void fake_make_operate_section(const fake_data_t data, const f_array_length_t id_section, fake_make_data_t *data_make, f_string_lengths_t *section_stack, f_status_t *status) {
-    if (F_status_is_error(*status)) return;
+  int fake_make_operate_section(const f_array_length_t id_section, fake_data_t *data, fake_make_data_t *data_make, f_string_lengths_t *section_stack, f_status_t *status) {
+    if (F_status_is_error(*status) || *status == F_child) return data->child;
 
-    if (fake_signal_received(data)) {
+    if (fake_signal_received(*data)) {
       *status = F_status_set_error(F_signal);
-      return;
+      return 0;
     }
 
     if (id_section > data_make->fakefile.used) {
       *status = F_status_set_error(F_parameter);
 
       fll_error_print(data_make->error, F_parameter, "fake_make_operate_section", F_true);
-      return;
+      return 0;
     }
 
     // add the operation id to the operation stack.
@@ -1904,7 +1910,7 @@ extern "C" {
 
       if (F_status_is_error(*status)) {
         fll_error_print(data_make->error, F_status_set_fine(*status), "fl_string_lengths_increase_by", F_true);
-        return;
+        return 0;
       }
     }
 
@@ -1914,21 +1920,21 @@ extern "C" {
 
     const f_fss_named_t *section = &data_make->fakefile.array[id_section];
 
-    if (data.error.verbosity != f_console_verbosity_quiet) {
-      fprintf(data.output.stream, "%c", f_string_eol[0]);
+    if (data->error.verbosity != f_console_verbosity_quiet) {
+      fprintf(data->output.stream, "%c", f_string_eol[0]);
 
-      fl_color_print(data.output.stream, data.context.set.important, "Processing Section '");
+      fl_color_print(data->output.stream, data->context.set.important, "Processing Section '");
 
-      fl_color_print_code(data.output.stream, *data.context.set.notable.before);
-      f_print_dynamic_partial(data.output.stream, data_make->buffer, section->name);
-      fl_color_print_code(data.output.stream, *data.context.set.notable.after);
+      fl_color_print_code(data->output.stream, *data->context.set.notable.before);
+      f_print_dynamic_partial(data->output.stream, data_make->buffer, section->name);
+      fl_color_print_code(data->output.stream, *data->context.set.notable.after);
 
-      fl_color_print(data.output.stream, data.context.set.important, "'.%c", f_string_eol[0]);
+      fl_color_print(data->output.stream, data->context.set.important, "'.%c", f_string_eol[0]);
     }
 
     if (!section->objects.used) {
       section_stack->used--;
-      return;
+      return 0;
     }
 
     const f_string_static_t operations_name[] = {
@@ -2053,7 +2059,7 @@ extern "C" {
       operation = 0;
       operation_name = 0;
 
-      if (fake_signal_received(data)) {
+      if (fake_signal_received(*data)) {
         *status = F_status_set_error(F_signal);
         break;
       }
@@ -2068,13 +2074,13 @@ extern "C" {
       } // for
 
       if (!operation) {
-        fake_print_message_section_operation_unknown(data, data_make->error, data_make->buffer, section->name, section->objects.array[i]);
+        fake_print_message_section_operation_unknown(*data, data_make->error, data_make->buffer, section->name, section->objects.array[i]);
 
         *status = F_status_set_error(F_valid_not);
       }
       else if (operation == fake_make_operation_type_operate) {
         if (section_stack->used == fake_make_section_stack_max) {
-          fake_print_message_section_operation_stack_max(data, data_make->error, data_make->buffer, section->name, section->objects.array[i], fake_make_section_stack_max);
+          fake_print_message_section_operation_stack_max(*data, data_make->error, data_make->buffer, section->name, section->objects.array[i], fake_make_section_stack_max);
 
           *status = F_status_set_error(F_recurse);
         }
@@ -2083,7 +2089,7 @@ extern "C" {
       if (F_status_is_error_not(*status)) {
         operations[i] = operation;
 
-        fake_make_operate_expand(data, section->name, operation, *operation_name, section->contents.array[i], section->quotess.array[i], data_make, &arguments[i], status);
+        fake_make_operate_expand(*data, section->name, operation, *operation_name, section->contents.array[i], section->quotess.array[i], data_make, &arguments[i], status);
       }
 
       if (operation_if == fake_make_operation_if_type_true_next) {
@@ -2096,7 +2102,7 @@ extern "C" {
         operation_if = fake_make_operation_if_type_false_always;
       }
 
-      fake_make_operate_validate(data, section->name, operation, *operation_name, arguments[i], &operation_if, data_make, section_stack, status);
+      fake_make_operate_validate(*data, section->name, operation, *operation_name, arguments[i], &operation_if, data_make, section_stack, status);
 
       if (F_status_is_error_not(*status)) {
 
@@ -2113,7 +2119,11 @@ extern "C" {
           continue;
         }
 
-        fake_make_operate_process(data, section->name, operation, *operation_name, arguments[i], success, &operation_if, data_make, section_stack, status);
+        const int result = fake_make_operate_process(section->name, operation, *operation_name, arguments[i], success, &operation_if, data, data_make, section_stack, status);
+
+        if (*status == F_child) {
+          return result;
+        }
       }
       else {
 
@@ -2173,13 +2183,13 @@ extern "C" {
         if (F_status_set_fine(*status) == F_signal_abort && !section_stack->used) {
           data_make->setting_make.fail = fake_make_operation_fail_type_exit;
           data_make->error.prefix = fll_error_print_error;
-          data_make->error.context = data.context.set.error;
-          data_make->error.notable = data.context.set.notable;
+          data_make->error.context = data->context.set.error;
+          data_make->error.notable = data->context.set.notable;
           data_make->error.to.stream = f_type_error;
           data_make->error.to.id = f_type_descriptor_error;
         }
 
-        fake_print_message_section_operation_failed(data, data_make->error, data_make->buffer, section->name, section->objects.array[i]);
+        fake_print_message_section_operation_failed(*data, data_make->error, data_make->buffer, section->name, section->objects.array[i]);
 
         // F_signal_abort is used by the break section operation.
         if (F_status_set_fine(*status) == F_signal_abort) {
@@ -2226,12 +2236,12 @@ extern "C" {
         f_macro_string_dynamics_t_delete_simple(arguments[i]);
       } // for
 
-      return;
+      return 0;
     }
 
     if (i == section->objects.used && (operation_if == fake_make_operation_if_type_true_next || operation_if == fake_make_operation_if_type_false_next || operation_if == fake_make_operation_if_type_else_true || operation_if == fake_make_operation_if_type_else_false)) {
 
-      if (data.error.verbosity != f_console_verbosity_quiet && data_make->error.to.stream) {
+      if (data->error.verbosity != f_console_verbosity_quiet && data_make->error.to.stream) {
         const char *type_name = 0;
 
         if (operation_if == fake_make_operation_if_type_true_next || operation_if == fake_make_operation_if_type_false_next) {
@@ -2247,7 +2257,7 @@ extern "C" {
         fl_color_print(data_make->error.to.stream, data_make->error.context, "' at end of section.%c", f_string_eol[0]);
       }
 
-      fake_print_message_section_operation_failed(data, data_make->error, data_make->buffer, section->name, section->objects.array[section->objects.used - 1]);
+      fake_print_message_section_operation_failed(*data, data_make->error, data_make->buffer, section->name, section->objects.array[section->objects.used - 1]);
 
       *status = F_status_set_error(F_failure);
     }
@@ -2262,22 +2272,29 @@ extern "C" {
     } // for
 
     section_stack->used--;
+
+    return 0;
   }
 #endif // _di_fake_make_operate_section_
 
 #ifndef _di_fake_make_operate_process_
-  void fake_make_operate_process(const fake_data_t data, const f_string_range_t section_name, const uint8_t operation, const f_string_static_t operation_name, const f_string_dynamics_t arguments, const bool success, uint8_t *operation_if, fake_make_data_t *data_make, f_string_lengths_t *section_stack, f_status_t *status) {
+  int fake_make_operate_process(const f_string_range_t section_name, const uint8_t operation, const f_string_static_t operation_name, const f_string_dynamics_t arguments, const bool success, uint8_t *operation_if, fake_data_t *data, fake_make_data_t *data_make, f_string_lengths_t *section_stack, f_status_t *status) {
+    if (*status == F_child) return data->child;
 
     if (operation == fake_make_operation_type_index) {
-      int return_code = fake_execute(data, data_make->environment, data_make->setting_build.build_indexer, arguments, status);
+      const f_status_t result = fake_execute(*data, data_make->environment, data_make->setting_build.build_indexer, arguments, status);
 
       if (F_status_is_error(*status)) {
         fll_error_print(data_make->error, F_status_set_fine(*status), "fake_execute", F_true);
       }
 
-      fake_make_operate_process_return(data, return_code, data_make, status);
+      if (*status == F_child) {
+        return result;
+      }
 
-      return;
+      fake_make_operate_process_return(*data, result, data_make, status);
+
+      return 0;
     }
 
     if (operation == fake_make_operation_type_break) {
@@ -2289,54 +2306,54 @@ extern "C" {
         *status = F_status_set_error(F_signal_abort);
       }
       else {
-        return;
+        return 0;
       }
 
-      if (data.error.verbosity == f_console_verbosity_verbose) {
-        fprintf(data.output.stream, "Breaking as '");
-        fl_color_print(data.output.stream, data.context.set.notable, "%s", arguments.used ? arguments.array[0].string : fake_make_operation_argument_success);
-        fprintf(data.output.stream, "'.%c", f_string_eol[0]);
+      if (data->error.verbosity == f_console_verbosity_verbose) {
+        fprintf(data->output.stream, "Breaking as '");
+        fl_color_print(data->output.stream, data->context.set.notable, "%s", arguments.used ? arguments.array[0].string : fake_make_operation_argument_success);
+        fprintf(data->output.stream, "'.%c", f_string_eol[0]);
       }
 
-      return;
+      return 0;
     }
 
     if (operation == fake_make_operation_type_build) {
       f_string_static_t stub = f_string_static_t_initialize;
 
-      *status = fake_build_operate(data, arguments.used ? arguments.array[0] : stub);
+      *status = fake_build_operate(arguments.used ? arguments.array[0] : stub, data);
 
       if (F_status_set_fine(*status) == F_signal) {
         *status = F_status_set_error(F_signal);
-        return;
+        return 0;
       }
 
       if (F_status_is_error(*status)) {
-        fake_make_operate_process_return(data, 1, data_make, status);
+        fake_make_operate_process_return(*data, 1, data_make, status);
       }
       else {
-        fake_make_operate_process_return(data, 0, data_make, status);
+        fake_make_operate_process_return(*data, 0, data_make, status);
       }
 
-      return;
+      return 0;
     }
 
     if (operation == fake_make_operation_type_clean) {
-      *status = fake_clean_operate(data);
+      *status = fake_clean_operate(*data);
 
       if (F_status_set_fine(*status) == F_signal) {
         *status = F_status_set_error(F_signal);
-        return;
+        return 0;
       }
 
       if (F_status_is_error(*status)) {
-        fake_make_operate_process_return(data, 1, data_make, status);
+        fake_make_operate_process_return(*data, 1, data_make, status);
       }
       else {
-        fake_make_operate_process_return(data, 0, data_make, status);
+        fake_make_operate_process_return(*data, 0, data_make, status);
       }
 
-      return;
+      return 0;
     }
 
     if (operation == fake_make_operation_type_clone) {
@@ -2347,8 +2364,8 @@ extern "C" {
 
       f_string_length_t destination_length = 0;
 
-      if (data.error.verbosity == f_console_verbosity_verbose) {
-        recurse.output = data.output;
+      if (data->error.verbosity == f_console_verbosity_verbose) {
+        recurse.output = data->output;
         recurse.verbose = fake_verbose_print_clone;
       }
 
@@ -2361,7 +2378,7 @@ extern "C" {
         if (F_status_is_error(status_file)) {
           fll_error_file_print(data_make->error, F_status_set_fine(status_file), "f_directory_is", F_true, arguments.array[1].string, "identify", fll_error_file_type_directory);
           *status = F_status_set_error(F_failure);
-          return;
+          return 0;
         }
 
         if (status_file == F_false || status_file == F_file_found_not) {
@@ -2405,12 +2422,12 @@ extern "C" {
             fll_error_file_print(data_make->error, F_status_set_fine(status_file), "f_file_clone", F_true, arguments.array[i].string, "clone", fll_error_file_type_file);
             *status = F_status_set_error(F_failure);
           }
-          else if (data.error.verbosity == f_console_verbosity_verbose) {
-            fprintf(data.output.stream, "Cloned '");
-            fl_color_print(data.output.stream, data.context.set.notable, "%s", arguments.array[i].string);
-            fprintf(data.output.stream, "' to '");
-            fl_color_print(data.output.stream, data.context.set.notable, "%s", destination);
-            fprintf(data.output.stream, "'.%c", f_string_eol[0]);
+          else if (data->error.verbosity == f_console_verbosity_verbose) {
+            fprintf(data->output.stream, "Cloned '");
+            fl_color_print(data->output.stream, data->context.set.notable, "%s", arguments.array[i].string);
+            fprintf(data->output.stream, "' to '");
+            fl_color_print(data->output.stream, data->context.set.notable, "%s", destination);
+            fprintf(data->output.stream, "'.%c", f_string_eol[0]);
           }
         }
         else if (F_status_is_error(status_file)) {
@@ -2420,19 +2437,23 @@ extern "C" {
         }
       } // for
 
-      return;
+      return 0;
     }
 
     if (operation == fake_make_operation_type_compile) {
-      int return_code = fake_execute(data, data_make->environment, data_make->setting_build.build_compiler, arguments, status);
+      const int result = fake_execute(*data, data_make->environment, data_make->setting_build.build_compiler, arguments, status);
 
       if (F_status_is_error(*status)) {
         fll_error_print(data_make->error, F_status_set_fine(*status), "fake_execute", F_true);
       }
 
-      fake_make_operate_process_return(data, return_code, data_make, status);
+      if (*status == F_child) {
+        return result;
+      }
 
-      return;
+      fake_make_operate_process_return(*data, result, data_make, status);
+
+      return 0;
     }
 
     if (operation == fake_make_operation_type_copy) {
@@ -2445,10 +2466,10 @@ extern "C" {
 
       f_mode_t mode = f_mode_t_initialize;
 
-      f_macro_mode_t_set_default_umask(mode, data.umask);
+      f_macro_mode_t_set_default_umask(mode, data->umask);
 
-      if (data.error.verbosity == f_console_verbosity_verbose) {
-        recurse.output = data.output;
+      if (data->error.verbosity == f_console_verbosity_verbose) {
+        recurse.output = data->output;
         recurse.verbose = fake_verbose_print_copy;
       }
 
@@ -2462,7 +2483,7 @@ extern "C" {
           fll_error_file_print(data_make->error, F_status_set_fine(status_file), "f_directory_is", F_true, arguments.array[1].string, "identify", fll_error_file_type_directory);
 
           *status = F_status_set_error(F_failure);
-          return;
+          return 0;
         }
 
         if (status_file == F_false || status_file == F_file_found_not) {
@@ -2505,12 +2526,12 @@ extern "C" {
             fll_error_file_print(data_make->error, F_status_set_fine(status_file), "f_file_copy", F_true, arguments.array[i].string, "copy", fll_error_file_type_file);
             *status = F_status_set_error(F_failure);
           }
-          else if (data.error.verbosity == f_console_verbosity_verbose) {
-            fprintf(data.output.stream, "Copied '");
-            fl_color_print(data.output.stream, data.context.set.notable, "%s", arguments.array[i].string);
-            fprintf(data.output.stream, "' to '");
-            fl_color_print(data.output.stream, data.context.set.notable, "%s", destination);
-            fprintf(data.output.stream, "'.%c", f_string_eol[0]);
+          else if (data->error.verbosity == f_console_verbosity_verbose) {
+            fprintf(data->output.stream, "Copied '");
+            fl_color_print(data->output.stream, data->context.set.notable, "%s", arguments.array[i].string);
+            fprintf(data->output.stream, "' to '");
+            fl_color_print(data->output.stream, data->context.set.notable, "%s", destination);
+            fprintf(data->output.stream, "'.%c", f_string_eol[0]);
           }
         }
         else if (F_status_is_error(status_file)) {
@@ -2520,7 +2541,7 @@ extern "C" {
         }
       } // for
 
-      return;
+      return 0;
     }
 
     if (operation == fake_make_operation_type_define) {
@@ -2535,13 +2556,13 @@ extern "C" {
       if (F_status_is_error(*status)) {
         fll_error_print(data_make->error, F_status_set_fine(*status), "f_environment_set", F_true);
       }
-      else if (data.error.verbosity == f_console_verbosity_verbose) {
-        fprintf(data.output.stream, "Defined environment variable '");
-        fl_color_print(data.output.stream, data.context.set.notable, "%s", arguments.array[0].string);
-        fprintf(data.output.stream, "'.%c", f_string_eol[0]);
+      else if (data->error.verbosity == f_console_verbosity_verbose) {
+        fprintf(data->output.stream, "Defined environment variable '");
+        fl_color_print(data->output.stream, data->context.set.notable, "%s", arguments.array[0].string);
+        fprintf(data->output.stream, "'.%c", f_string_eol[0]);
       }
 
-      return;
+      return 0;
     }
 
     if (operation == fake_make_operation_type_delete || operation == fake_make_operation_type_deletes) {
@@ -2555,22 +2576,22 @@ extern "C" {
 
         if (F_status_is_error(*status)) {
           if (F_status_set_fine(*status) == F_file_found_not) {
-            if (data.error.verbosity == f_console_verbosity_verbose) {
-              fprintf(data.output.stream, "%c", f_string_eol[0]);
-              fl_color_print(data.output.stream, data.context.set.warning, "%sthe file '", fll_error_print_warning);
-              fl_color_print(data.output.stream, data.context.set.notable, "%s", arguments.array[i].string);
-              fl_color_print(data.output.stream, data.context.set.warning, "' was not found.%c", f_string_eol[0]);
+            if (data->error.verbosity == f_console_verbosity_verbose) {
+              fprintf(data->output.stream, "%c", f_string_eol[0]);
+              fl_color_print(data->output.stream, data->context.set.warning, "%sthe file '", fll_error_print_warning);
+              fl_color_print(data->output.stream, data->context.set.notable, "%s", arguments.array[i].string);
+              fl_color_print(data->output.stream, data->context.set.warning, "' was not found.%c", f_string_eol[0]);
             }
 
             *status = F_none;
           }
           else {
             fll_error_file_print(data_make->error, F_status_set_fine(*status), "f_file_stat", F_true, arguments.array[i].string, "delete", fll_error_file_type_file);
-            return;
+            return 0;
           }
         }
         else if (f_macro_file_type_is_directory(file_stat.st_mode)) {
-          if (data.error.verbosity == f_console_verbosity_verbose) {
+          if (data->error.verbosity == f_console_verbosity_verbose) {
             *status = f_directory_remove_custom(arguments.array[i].string, recursion_max, F_false, fake_clean_remove_recursively_verbosely);
           }
           else {
@@ -2578,10 +2599,10 @@ extern "C" {
           }
 
           if (F_status_set_fine(*status) == F_file_found_not) {
-            if (data.error.verbosity == f_console_verbosity_verbose) {
-              fprintf(data.output.stream, "The directory '");
-              fl_color_print(data.output.stream, data.context.set.notable, "%s", arguments.array[i].string);
-              fprintf(data.output.stream, "' does not exist.%c", f_string_eol[0]);
+            if (data->error.verbosity == f_console_verbosity_verbose) {
+              fprintf(data->output.stream, "The directory '");
+              fl_color_print(data->output.stream, data->context.set.notable, "%s", arguments.array[i].string);
+              fprintf(data->output.stream, "' does not exist.%c", f_string_eol[0]);
             }
 
             *status = F_none;
@@ -2589,22 +2610,22 @@ extern "C" {
 
           if (F_status_is_error(*status)) {
             fll_error_file_print(data_make->error, F_status_set_fine(*status), "f_directory_remove", F_true, arguments.array[i].string, "delete", fll_error_file_type_directory);
-            return;
+            return 0;
           }
-          else if (data.error.verbosity == f_console_verbosity_verbose) {
-            fprintf(data.output.stream, "Removed '");
-            fl_color_print(data.output.stream, data.context.set.notable, "%s", arguments.array[i].string);
-            fprintf(data.output.stream, "'.%c", f_string_eol[0]);
+          else if (data->error.verbosity == f_console_verbosity_verbose) {
+            fprintf(data->output.stream, "Removed '");
+            fl_color_print(data->output.stream, data->context.set.notable, "%s", arguments.array[i].string);
+            fprintf(data->output.stream, "'.%c", f_string_eol[0]);
           }
         }
         else {
           *status = f_file_remove(arguments.array[i].string);
 
           if (F_status_set_fine(*status) == F_file_found_not) {
-            if (data.error.verbosity == f_console_verbosity_verbose) {
-              fprintf(data.output.stream, "The file '");
-              fl_color_print(data.output.stream, data.context.set.notable, "%s", arguments.array[i].string);
-              fprintf(data.output.stream, "' does not exist.%c", f_string_eol[0]);
+            if (data->error.verbosity == f_console_verbosity_verbose) {
+              fprintf(data->output.stream, "The file '");
+              fl_color_print(data->output.stream, data->context.set.notable, "%s", arguments.array[i].string);
+              fprintf(data->output.stream, "' does not exist.%c", f_string_eol[0]);
             }
 
             *status = F_none;
@@ -2612,17 +2633,17 @@ extern "C" {
 
           if (F_status_is_error(*status)) {
             fll_error_file_print(data_make->error, F_status_set_fine(*status), "f_file_remove", F_true, arguments.array[i].string, "delete", fll_error_file_type_file);
-            return;
+            return 0;
           }
-          else if (data.error.verbosity == f_console_verbosity_verbose) {
-            fprintf(data.output.stream, "Removed '");
-            fl_color_print(data.output.stream, data.context.set.notable, "%s", arguments.array[i].string);
-            fprintf(data.output.stream, "'.%c", f_string_eol[0]);
+          else if (data->error.verbosity == f_console_verbosity_verbose) {
+            fprintf(data->output.stream, "Removed '");
+            fl_color_print(data->output.stream, data->context.set.notable, "%s", arguments.array[i].string);
+            fprintf(data->output.stream, "'.%c", f_string_eol[0]);
           }
         }
       } // for
 
-      return;
+      return 0;
     }
 
     if (operation == fake_make_operation_type_else) {
@@ -2634,7 +2655,7 @@ extern "C" {
         *operation_if = fake_make_operation_if_type_else_true;
       }
 
-      return;
+      return 0;
     }
 
     if (operation == fake_make_operation_type_exit) {
@@ -2648,22 +2669,22 @@ extern "C" {
         // forcing exit forces fail mode.
         data_make->setting_make.fail = fake_make_operation_fail_type_exit;
         data_make->error.prefix = fll_error_print_error;
-        data_make->error.context = data.context.set.error;
-        data_make->error.notable = data.context.set.notable;
+        data_make->error.context = data->context.set.error;
+        data_make->error.notable = data->context.set.notable;
         data_make->error.to.stream = f_type_error;
         data_make->error.to.id = f_type_descriptor_error;
       }
       else {
-        return;
+        return 0;
       }
 
-      if (data.error.verbosity == f_console_verbosity_verbose) {
-        fprintf(data.output.stream, "Exiting as '");
-        fl_color_print(data.output.stream, data.context.set.notable, "%s", arguments.used ? arguments.array[0].string : fake_make_operation_argument_success);
-        fprintf(data.output.stream, "'.%c", f_string_eol[0]);
+      if (data->error.verbosity == f_console_verbosity_verbose) {
+        fprintf(data->output.stream, "Exiting as '");
+        fl_color_print(data->output.stream, data->context.set.notable, "%s", arguments.used ? arguments.array[0].string : fake_make_operation_argument_success);
+        fprintf(data->output.stream, "'.%c", f_string_eol[0]);
       }
 
-      return;
+      return 0;
     }
 
     if (operation == fake_make_operation_type_fail) {
@@ -2671,16 +2692,16 @@ extern "C" {
       if (fl_string_dynamic_compare_string(fake_make_operation_argument_exit, arguments.array[0], fake_make_operation_argument_exit_length) == F_equal_to) {
         data_make->setting_make.fail = fake_make_operation_fail_type_exit;
         data_make->error.prefix = fll_error_print_error;
-        data_make->error.context = data.context.set.error;
-        data_make->error.notable = data.context.set.notable;
+        data_make->error.context = data->context.set.error;
+        data_make->error.notable = data->context.set.notable;
         data_make->error.to.stream = f_type_error;
         data_make->error.to.id = f_type_descriptor_error;
       }
       else if (fl_string_dynamic_compare_string(fake_make_operation_argument_warn, arguments.array[0], fake_make_operation_argument_warn_length) == F_equal_to) {
         data_make->setting_make.fail = fake_make_operation_fail_type_warn;
         data_make->error.prefix = fll_error_print_warning;
-        data_make->error.context = data.context.set.warning;
-        data_make->error.notable = data.context.set.notable;
+        data_make->error.context = data->context.set.warning;
+        data_make->error.notable = data->context.set.notable;
         data_make->error.to.stream = f_type_warning;
         data_make->error.to.id = f_type_descriptor_warning;
       }
@@ -2690,41 +2711,41 @@ extern "C" {
         data_make->error.to.id = -1;
       }
 
-      if (data.error.verbosity == f_console_verbosity_verbose) {
-        fprintf(data.output.stream, "Set failure state to '");
+      if (data->error.verbosity == f_console_verbosity_verbose) {
+        fprintf(data->output.stream, "Set failure state to '");
 
         if (data_make->setting_make.fail == fake_make_operation_fail_type_exit) {
-          fl_color_print(data.output.stream, data.context.set.notable, "%s", fake_make_operation_argument_exit);
+          fl_color_print(data->output.stream, data->context.set.notable, "%s", fake_make_operation_argument_exit);
         }
         else if (data_make->setting_make.fail == fake_make_operation_fail_type_warn) {
-          fl_color_print(data.output.stream, data.context.set.notable, "%s", fake_make_operation_argument_warn);
+          fl_color_print(data->output.stream, data->context.set.notable, "%s", fake_make_operation_argument_warn);
         }
         else if (data_make->setting_make.fail == fake_make_operation_fail_type_ignore) {
-          fl_color_print(data.output.stream, data.context.set.notable, "%s", fake_make_operation_argument_ignore);
+          fl_color_print(data->output.stream, data->context.set.notable, "%s", fake_make_operation_argument_ignore);
         }
 
-        fprintf(data.output.stream, "'.%c", f_string_eol[0]);
+        fprintf(data->output.stream, "'.%c", f_string_eol[0]);
       }
 
-      return;
+      return 0;
     }
 
     if (operation == fake_make_operation_type_group) {
       gid_t id = 0;
 
-      *status = fake_make_get_id_group(data, data_make->error, arguments.array[0], &id);
-      if (F_status_is_error(*status)) return;
+      *status = fake_make_get_id_group(*data, data_make->error, arguments.array[0], &id);
+      if (F_status_is_error(*status)) return 0;
 
       f_status_t status_file = F_none;
 
       for (f_array_length_t i = 1; i < arguments.used; i++) {
 
-        status_file = fake_make_assure_inside_project(data, arguments.array[i], data_make);
+        status_file = fake_make_assure_inside_project(*data, arguments.array[i], data_make);
 
         if (F_status_is_error(status_file)) {
           *status = status_file;
 
-          fake_print_message_section_operation_path_outside(data, data_make->error, F_status_set_fine(*status), "fake_make_assure_inside_project", data_make->path_cache.used ? data_make->path_cache.string : arguments.array[i].string);
+          fake_print_message_section_operation_path_outside(*data, data_make->error, F_status_set_fine(*status), "fake_make_assure_inside_project", data_make->path_cache.used ? data_make->path_cache.string : arguments.array[i].string);
 
           continue;
         }
@@ -2736,34 +2757,34 @@ extern "C" {
 
           fll_error_file_print(data_make->error, F_status_set_fine(*status), "f_file_role_change", F_true, arguments.array[i].string, "change group of", fll_error_file_type_file);
         }
-        else if (data.error.verbosity == f_console_verbosity_verbose) {
-          fprintf(data.output.stream, "Changed group of '");
-          fl_color_print(data.output.stream, data.context.set.notable, "%s", arguments.array[i].string);
-          fprintf(data.output.stream, "' to ");
-          fl_color_print(data.output.stream, data.context.set.notable, "%llu", id);
-          fprintf(data.output.stream, ".%c", f_string_eol[0]);
+        else if (data->error.verbosity == f_console_verbosity_verbose) {
+          fprintf(data->output.stream, "Changed group of '");
+          fl_color_print(data->output.stream, data->context.set.notable, "%s", arguments.array[i].string);
+          fprintf(data->output.stream, "' to ");
+          fl_color_print(data->output.stream, data->context.set.notable, "%llu", id);
+          fprintf(data->output.stream, ".%c", f_string_eol[0]);
         }
       } // for
 
-      return;
+      return 0;
     }
 
     if (operation == fake_make_operation_type_groups) {
       gid_t id = 0;
 
-      *status = fake_make_get_id_group(data, data_make->error, arguments.array[0], &id);
-      if (F_status_is_error(*status)) return;
+      *status = fake_make_get_id_group(*data, data_make->error, arguments.array[0], &id);
+      if (F_status_is_error(*status)) return 0;
 
       f_status_t status_file = F_none;
 
       for (f_array_length_t i = 1; i < arguments.used; i++) {
 
-        status_file = fake_make_assure_inside_project(data, arguments.array[i], data_make);
+        status_file = fake_make_assure_inside_project(*data, arguments.array[i], data_make);
 
         if (F_status_is_error(status_file)) {
           *status = status_file;
 
-          fake_print_message_section_operation_path_outside(data, data_make->error, F_status_set_fine(*status), "fake_make_assure_inside_project", data_make->path_cache.used ? data_make->path_cache.string : arguments.array[i].string);
+          fake_print_message_section_operation_path_outside(*data, data_make->error, F_status_set_fine(*status), "fake_make_assure_inside_project", data_make->path_cache.used ? data_make->path_cache.string : arguments.array[i].string);
 
           continue;
         }
@@ -2775,16 +2796,16 @@ extern "C" {
 
           fll_error_file_print(data_make->error, F_status_set_fine(*status), "fll_file_role_change_all", F_true, arguments.array[i].string, "change group of", fll_error_file_type_file);
         }
-        else if (data.error.verbosity == f_console_verbosity_verbose) {
-          fprintf(data.output.stream, "Changed group of '");
-          fl_color_print(data.output.stream, data.context.set.notable, "%s", arguments.array[i].string);
-          fprintf(data.output.stream, "' to ");
-          fl_color_print(data.output.stream, data.context.set.notable, "%llu", id);
-          fprintf(data.output.stream, ".%c", f_string_eol[0]);
+        else if (data->error.verbosity == f_console_verbosity_verbose) {
+          fprintf(data->output.stream, "Changed group of '");
+          fl_color_print(data->output.stream, data->context.set.notable, "%s", arguments.array[i].string);
+          fprintf(data->output.stream, "' to ");
+          fl_color_print(data->output.stream, data->context.set.notable, "%llu", id);
+          fprintf(data->output.stream, ".%c", f_string_eol[0]);
         }
       } // for
 
-      return;
+      return 0;
     }
 
     if (operation == fake_make_operation_type_if) {
@@ -2797,7 +2818,7 @@ extern "C" {
           *operation_if = fake_make_operation_if_type_false_next;
         }
 
-        return;
+        return 0;
       }
 
       if (*operation_if == fake_make_operation_if_type_if_failure) {
@@ -2808,14 +2829,14 @@ extern "C" {
           *operation_if = fake_make_operation_if_type_true_next;
         }
 
-        return;
+        return 0;
       }
 
       if (*operation_if == fake_make_operation_if_type_if_group) {
         uid_t id = 0;
 
-        *status = fake_make_get_id_group(data, data_make->error, arguments.array[1], &id);
-        if (F_status_is_error(*status)) return;
+        *status = fake_make_get_id_group(*data, data_make->error, arguments.array[1], &id);
+        if (F_status_is_error(*status)) return 0;
 
         uid_t id_file = 0;
 
@@ -2836,7 +2857,7 @@ extern "C" {
           }
         } // for
 
-        return;
+        return 0;
       }
 
       if (*operation_if == fake_make_operation_if_type_if_mode) {
@@ -2852,11 +2873,11 @@ extern "C" {
         {
           uint8_t mode_replace = 0;
 
-          *status = fake_make_get_id_mode(data, data_make->error, arguments.array[2], &mode_rule, &mode_replace);
+          *status = fake_make_get_id_mode(*data, data_make->error, arguments.array[2], &mode_rule, &mode_replace);
 
           if (F_status_is_error(*status)) {
             *operation_if = fake_make_operation_if_type_false_always_next;
-            return;
+            return 0;
           }
 
           *status = f_file_mode_to_mode(mode_rule, &mode_match);
@@ -2864,7 +2885,7 @@ extern "C" {
           if (F_status_is_error(*status)) {
             *operation_if = fake_make_operation_if_type_false_always_next;
             fll_error_print(data_make->error, F_status_set_fine(*status), "f_file_mode_to_mode", F_true);
-            return;
+            return 0;
           }
         }
 
@@ -2896,14 +2917,14 @@ extern "C" {
           }
         } // for
 
-        return;
+        return 0;
       }
 
       if (*operation_if == fake_make_operation_if_type_if_owner) {
         uid_t id = 0;
 
-        *status = fake_make_get_id_owner(data, data_make->error, arguments.array[1], &id);
-        if (F_status_is_error(*status)) return;
+        *status = fake_make_get_id_owner(*data, data_make->error, arguments.array[1], &id);
+        if (F_status_is_error(*status)) return 0;
 
         uid_t id_file = 0;
 
@@ -2925,7 +2946,7 @@ extern "C" {
           }
         } // for
 
-        return;
+        return 0;
       }
 
       if (*operation_if == fake_make_operation_if_type_if_is) {
@@ -3011,7 +3032,7 @@ extern "C" {
           }
         } // for
 
-        return;
+        return 0;
       }
 
       if (*operation_if == fake_make_operation_if_type_if_exists) {
@@ -3033,7 +3054,7 @@ extern "C" {
           }
         } // for
 
-        return;
+        return 0;
       }
 
       if (*operation_if == fake_make_operation_if_type_if_defined) {
@@ -3053,7 +3074,7 @@ extern "C" {
 
           if (!data_make->setting_make.parameter.used) {
             *operation_if = fake_make_operation_if_type_false_next;
-            return;
+            return 0;
           }
 
           f_array_length_t i = 2;
@@ -3079,7 +3100,7 @@ extern "C" {
           } // for
         }
 
-        return;
+        return 0;
       }
 
       if (*operation_if == fake_make_operation_if_type_if_equal) {
@@ -3093,7 +3114,7 @@ extern "C" {
           }
         } // for
 
-        return;
+        return 0;
       }
 
       if (*operation_if == fake_make_operation_if_type_if_equal_not) {
@@ -3114,7 +3135,7 @@ extern "C" {
           } // for
         } // for
 
-        return;
+        return 0;
       }
 
       if (*operation_if == fake_make_operation_if_type_if_greater || *operation_if == fake_make_operation_if_type_if_greater_equal || *operation_if == fake_make_operation_if_type_if_less || *operation_if == fake_make_operation_if_type_if_less_equal) {
@@ -3243,26 +3264,26 @@ extern "C" {
           *status = F_status_set_error(F_failure);
           *operation_if = fake_make_operation_if_type_false_always_next;
 
-          if (data.error.verbosity != f_console_verbosity_quiet && data_make->error.to.stream) {
-            fprintf(data.output.stream, "%c", f_string_eol[0]);
+          if (data->error.verbosity != f_console_verbosity_quiet && data_make->error.to.stream) {
+            fprintf(data->output.stream, "%c", f_string_eol[0]);
 
             if ((i == 1 && number_left > f_number_t_size_unsigned) || (i > 1 && number_right > f_number_t_size_unsigned)) {
-              fl_color_print(data.error.to.stream, data_make->error.context, "%sThe number '", data_make->error.prefix);
-              fl_color_print(data.error.to.stream, data_make->error.notable, "%c%s", arguments.array[i].string);
-              fl_color_print(data.error.to.stream, data_make->error.context, "' may only be between the ranges -%llu to %llu.%c", f_number_t_size_unsigned, f_number_t_size_unsigned, f_string_eol[0]);
+              fl_color_print(data->error.to.stream, data_make->error.context, "%sThe number '", data_make->error.prefix);
+              fl_color_print(data->error.to.stream, data_make->error.notable, "%c%s", arguments.array[i].string);
+              fl_color_print(data->error.to.stream, data_make->error.context, "' may only be between the ranges -%llu to %llu.%c", f_number_t_size_unsigned, f_number_t_size_unsigned, f_string_eol[0]);
             }
             else {
-              fl_color_print(data.error.to.stream, data_make->error.context, "%sInvalid or unsupported number provided '", data_make->error.prefix);
-              fl_color_print(data.error.to.stream, data_make->error.notable, "%s", arguments.array[i].string);
-              fl_color_print(data.error.to.stream, data_make->error.context, "'.%c", f_string_eol[0]);
+              fl_color_print(data->error.to.stream, data_make->error.context, "%sInvalid or unsupported number provided '", data_make->error.prefix);
+              fl_color_print(data->error.to.stream, data_make->error.notable, "%s", arguments.array[i].string);
+              fl_color_print(data->error.to.stream, data_make->error.context, "'.%c", f_string_eol[0]);
             }
           }
         }
 
-        return;
+        return 0;
       }
 
-      return;
+      return 0;
     }
 
     if (operation == fake_make_operation_type_link) {
@@ -3271,23 +3292,23 @@ extern "C" {
       if (F_status_is_error(*status)) {
         fll_error_file_print(data_make->error, F_status_set_fine(*status), "f_file_link", F_true, arguments.array[1].string, "create link", fll_error_file_type_file);
       }
-      else if (data.error.verbosity == f_console_verbosity_verbose) {
-        fprintf(data.output.stream, "Created symbolic link from '");
-        fl_color_print(data.error.to.stream, data.context.set.notable, "%s", arguments.array[1].string);
-        fprintf(data.output.stream, "' to '");
-        fl_color_print(data.error.to.stream, data.context.set.notable, "%s", arguments.array[0].string);
-        fprintf(data.output.stream, "'.%c", f_string_eol[0]);
+      else if (data->error.verbosity == f_console_verbosity_verbose) {
+        fprintf(data->output.stream, "Created symbolic link from '");
+        fl_color_print(data->error.to.stream, data->context.set.notable, "%s", arguments.array[1].string);
+        fprintf(data->output.stream, "' to '");
+        fl_color_print(data->error.to.stream, data->context.set.notable, "%s", arguments.array[0].string);
+        fprintf(data->output.stream, "'.%c", f_string_eol[0]);
       }
 
-      return;
+      return 0;
     }
 
     if (operation == fake_make_operation_type_mode) {
       f_file_mode_t mode_rule = 0;
       uint8_t replace = 0;
 
-      *status = fake_make_get_id_mode(data, data_make->error, arguments.array[0], &mode_rule, &replace);
-      if (F_status_is_error(*status)) return;
+      *status = fake_make_get_id_mode(*data, data_make->error, arguments.array[0], &mode_rule, &replace);
+      if (F_status_is_error(*status)) return 0;
 
       mode_t mode = 0;
       mode_t mode_file = 0;
@@ -3316,24 +3337,24 @@ extern "C" {
           break;
         }
 
-        if (data.error.verbosity == f_console_verbosity_verbose) {
-          fprintf(data.output.stream, "Changed mode of '");
-          fl_color_print(data.error.to.stream, data.context.set.notable, "%s", arguments.array[i].string);
-          fprintf(data.output.stream, "' to ");
-          fl_color_print(data.error.to.stream, data.context.set.notable, "%#o", mode);
-          fprintf(data.output.stream, ".%c", f_string_eol[0]);
+        if (data->error.verbosity == f_console_verbosity_verbose) {
+          fprintf(data->output.stream, "Changed mode of '");
+          fl_color_print(data->error.to.stream, data->context.set.notable, "%s", arguments.array[i].string);
+          fprintf(data->output.stream, "' to ");
+          fl_color_print(data->error.to.stream, data->context.set.notable, "%#o", mode);
+          fprintf(data->output.stream, ".%c", f_string_eol[0]);
         }
       } // for
 
-      return;
+      return 0;
     }
 
     if (operation == fake_make_operation_type_modes) {
       f_file_mode_t mode_rule = 0;
       uint8_t replace = 0;
 
-      *status = fake_make_get_id_mode(data, data_make->error, arguments.array[0], &mode_rule, &replace);
-      if (F_status_is_error(*status)) return;
+      *status = fake_make_get_id_mode(*data, data_make->error, arguments.array[0], &mode_rule, &replace);
+      if (F_status_is_error(*status)) return 0;
 
       mode_t mode = 0;
       mode_t mode_file = 0;
@@ -3362,16 +3383,16 @@ extern "C" {
           break;
         }
 
-        if (data.error.verbosity == f_console_verbosity_verbose) {
-          fprintf(data.output.stream, "Changed mode of '");
-          fl_color_print(data.error.to.stream, data.context.set.notable, "%s", arguments.array[i].string);
-          fprintf(data.output.stream, "' to ");
-          fl_color_print(data.error.to.stream, data.context.set.notable, "%#o", mode);
-          fprintf(data.output.stream, ".%c", f_string_eol[0]);
+        if (data->error.verbosity == f_console_verbosity_verbose) {
+          fprintf(data->output.stream, "Changed mode of '");
+          fl_color_print(data->error.to.stream, data->context.set.notable, "%s", arguments.array[i].string);
+          fprintf(data->output.stream, "' to ");
+          fl_color_print(data->error.to.stream, data->context.set.notable, "%#o", mode);
+          fprintf(data->output.stream, ".%c", f_string_eol[0]);
         }
       } // for
 
-      return;
+      return 0;
     }
 
     if (operation == fake_make_operation_type_move) {
@@ -3382,8 +3403,8 @@ extern "C" {
 
       f_string_length_t destination_length = 0;
 
-      if (data.error.verbosity == f_console_verbosity_verbose) {
-        recurse.output = data.output;
+      if (data->error.verbosity == f_console_verbosity_verbose) {
+        recurse.output = data->output;
         recurse.verbose = fake_verbose_print_move;
       }
 
@@ -3397,7 +3418,7 @@ extern "C" {
           fll_error_file_print(data_make->error, F_status_set_fine(*status), "f_directory_is", F_true, arguments.array[1].string, "identify", fll_error_file_type_directory);
 
           *status = F_status_set_error(F_failure);
-          return;
+          return 0;
         }
 
         if (status_file == F_false || status_file == F_file_found_not) {
@@ -3432,7 +3453,7 @@ extern "C" {
         }
       } // for
 
-      return;
+      return 0;
     }
 
     if (operation == fake_make_operation_type_operate) {
@@ -3446,10 +3467,10 @@ extern "C" {
       } // for
 
       if (id_section == data_make->fakefile.used) {
-        return;
+        return 0;
       }
 
-      fake_make_operate_section(data, id_section, data_make, section_stack, status);
+      const int result = fake_make_operate_section(id_section, data, data_make, section_stack, status);
 
       // Ensure that a break only happens within its active operation stack.
       if (*status == F_signal_abort) {
@@ -3459,25 +3480,25 @@ extern "C" {
         *status = F_status_set_error(F_failure);
       }
 
-      return;
+      return result;
     }
 
     if (operation == fake_make_operation_type_owner) {
       uid_t id = 0;
 
-      *status = fake_make_get_id_owner(data, data_make->error, arguments.array[0], &id);
-      if (F_status_is_error(*status)) return;
+      *status = fake_make_get_id_owner(*data, data_make->error, arguments.array[0], &id);
+      if (F_status_is_error(*status)) return 0;
 
       f_status_t status_file = F_none;
 
       for (f_array_length_t i = 1; i < arguments.used; i++) {
 
-        status_file = fake_make_assure_inside_project(data, arguments.array[i], data_make);
+        status_file = fake_make_assure_inside_project(*data, arguments.array[i], data_make);
 
         if (F_status_is_error(status_file)) {
           *status = status_file;
 
-          fake_print_message_section_operation_path_outside(data, data_make->error, F_status_set_fine(*status), "fake_make_assure_inside_project", data_make->path_cache.used ? data_make->path_cache.string : arguments.array[i].string);
+          fake_print_message_section_operation_path_outside(*data, data_make->error, F_status_set_fine(*status), "fake_make_assure_inside_project", data_make->path_cache.used ? data_make->path_cache.string : arguments.array[i].string);
 
           continue;
         }
@@ -3490,34 +3511,34 @@ extern "C" {
           fll_error_file_print(data_make->error, F_status_set_fine(*status), "f_file_role_change", F_true, arguments.array[i].string, "change owner of", fll_error_file_type_file);
           break;
         }
-        else if (data.error.verbosity == f_console_verbosity_verbose) {
-          fprintf(data.output.stream, "Changed owner of '");
-          fl_color_print(data.error.to.stream, data.context.set.notable, "%s", arguments.array[i].string);
-          fprintf(data.output.stream, "' to ");
-          fl_color_print(data.error.to.stream, data.context.set.notable, "%d", id);
-          fprintf(data.output.stream, ".%c", f_string_eol[0]);
+        else if (data->error.verbosity == f_console_verbosity_verbose) {
+          fprintf(data->output.stream, "Changed owner of '");
+          fl_color_print(data->error.to.stream, data->context.set.notable, "%s", arguments.array[i].string);
+          fprintf(data->output.stream, "' to ");
+          fl_color_print(data->error.to.stream, data->context.set.notable, "%d", id);
+          fprintf(data->output.stream, ".%c", f_string_eol[0]);
         }
       } // for
 
-      return;
+      return 0;
     }
 
     if (operation == fake_make_operation_type_owners) {
       uid_t id = 0;
 
-      *status = fake_make_get_id_owner(data, data_make->error, arguments.array[0], &id);
-      if (F_status_is_error(*status)) return;
+      *status = fake_make_get_id_owner(*data, data_make->error, arguments.array[0], &id);
+      if (F_status_is_error(*status)) return 0;
 
       f_status_t status_file = F_none;
 
       for (f_array_length_t i = 1; i < arguments.used; i++) {
 
-        status_file = fake_make_assure_inside_project(data, arguments.array[i], data_make);
+        status_file = fake_make_assure_inside_project(*data, arguments.array[i], data_make);
 
         if (F_status_is_error(status_file)) {
           *status = status_file;
 
-          fake_print_message_section_operation_path_outside(data, data_make->error, F_status_set_fine(*status), "fake_make_assure_inside_project", data_make->path_cache.used ? data_make->path_cache.string : arguments.array[i].string);
+          fake_print_message_section_operation_path_outside(*data, data_make->error, F_status_set_fine(*status), "fake_make_assure_inside_project", data_make->path_cache.used ? data_make->path_cache.string : arguments.array[i].string);
 
           continue;
         }
@@ -3529,16 +3550,16 @@ extern "C" {
 
           fll_error_file_print(data_make->error, F_status_set_fine(*status), "fll_file_role_change_all", F_true, arguments.array[i].string, "change owner of", fll_error_file_type_file);
         }
-        else if (data.error.verbosity == f_console_verbosity_verbose) {
-          fprintf(data.output.stream, "Changed owner of '");
-          fl_color_print(data.error.to.stream, data.context.set.notable, "%s", arguments.array[i].string);
-          fprintf(data.output.stream, "' to ");
-          fl_color_print(data.error.to.stream, data.context.set.notable, "%d", id);
-          fprintf(data.output.stream, ".%c", f_string_eol[0]);
+        else if (data->error.verbosity == f_console_verbosity_verbose) {
+          fprintf(data->output.stream, "Changed owner of '");
+          fl_color_print(data->error.to.stream, data->context.set.notable, "%s", arguments.array[i].string);
+          fprintf(data->output.stream, "' to ");
+          fl_color_print(data->error.to.stream, data->context.set.notable, "%d", id);
+          fprintf(data->output.stream, ".%c", f_string_eol[0]);
         }
       } // for
 
-      return;
+      return 0;
     }
 
     if (operation == fake_make_operation_type_pop) {
@@ -3549,98 +3570,98 @@ extern "C" {
       *status = f_path_change(data_make->path.stack.array[data_make->path.stack.used - 1].string);
 
       if (F_status_is_error(*status)) {
-        fake_print_message_section_operation_path_stack_max(data, data_make->error, F_status_set_fine(*status), "f_path_change", data_make->path.stack.array[data_make->path.stack.used - 1].string);
-        return;
+        fake_print_message_section_operation_path_stack_max(*data, data_make->error, F_status_set_fine(*status), "f_path_change", data_make->path.stack.array[data_make->path.stack.used - 1].string);
+        return 0;
       }
 
-      if (data.error.verbosity == f_console_verbosity_verbose) {
-        *status = fake_make_path_relative(data, data_make->path.stack.array[data_make->path.stack.used - 1], data_make);
+      if (data->error.verbosity == f_console_verbosity_verbose) {
+        *status = fake_make_path_relative(*data, data_make->path.stack.array[data_make->path.stack.used - 1], data_make);
 
         if (F_status_is_error(*status)) {
           fll_error_print(data_make->error, F_status_set_fine(*status), "fake_make_path_relative", F_true);
-          return;
+          return 0;
         }
 
-        fprintf(data.output.stream, "Changed to project path '");
-        fl_color_print_code(data.output.stream, *data.context.set.notable.before);
-        f_print_dynamic(data.output.stream, data_make->path_cache);
-        fl_color_print_code(data.output.stream, *data.context.set.notable.after);
-        fprintf(data.output.stream, "'.%c", f_string_eol[0]);
+        fprintf(data->output.stream, "Changed to project path '");
+        fl_color_print_code(data->output.stream, *data->context.set.notable.before);
+        f_print_dynamic(data->output.stream, data_make->path_cache);
+        fl_color_print_code(data->output.stream, *data->context.set.notable.after);
+        fprintf(data->output.stream, "'.%c", f_string_eol[0]);
       }
 
-      return;
+      return 0;
     }
 
     if (operation == fake_make_operation_type_print) {
       for (f_array_length_t i = 0; i < arguments.used; i++) {
-        f_print_dynamic(data.output.stream, arguments.array[i]);
+        f_print_dynamic(data->output.stream, arguments.array[i]);
 
         if (i + 1 < arguments.used) {
-          fprintf(data.output.stream, " ");
+          fprintf(data->output.stream, " ");
         }
       } // for
 
-      fprintf(data.output.stream, "%c", f_string_eol[0]);
-      return;
+      fprintf(data->output.stream, "%c", f_string_eol[0]);
+      return 0;
     }
 
     if (operation == fake_make_operation_type_run) {
-      *status = fake_make_operate_process_run(data, arguments, F_false, data_make);
-      return;
+      *status = fake_make_operate_process_run(*data, arguments, F_false, data_make);
+      return 0;
     }
 
     if (operation == fake_make_operation_type_shell) {
-      *status = fake_make_operate_process_run(data, arguments, F_true, data_make);
-      return;
+      *status = fake_make_operate_process_run(*data, arguments, F_true, data_make);
+      return 0;
     }
 
     if (operation == fake_make_operation_type_skeleton) {
-      *status = fake_skeleton_operate(data);
+      *status = fake_skeleton_operate(*data);
 
       if (F_status_set_fine(*status) == F_signal) {
         *status = F_status_set_error(F_signal);
-        return;
+        return 0;
       }
 
       if (F_status_is_error(*status)) {
-        fake_make_operate_process_return(data, 1, data_make, status);
+        fake_make_operate_process_return(*data, 1, data_make, status);
       }
       else {
-        fake_make_operate_process_return(data, 0, data_make, status);
+        fake_make_operate_process_return(*data, 0, data_make, status);
       }
 
-      return;
+      return 0;
     }
 
     if (operation == fake_make_operation_type_to) {
-      *status = fake_make_assure_inside_project(data, arguments.array[0], data_make);
+      *status = fake_make_assure_inside_project(*data, arguments.array[0], data_make);
 
       if (F_status_is_error(*status)) {
-        fake_print_message_section_operation_path_outside(data, data_make->error, F_status_set_fine(*status), "fake_make_assure_inside_project", data_make->path_cache.used ? data_make->path_cache.string : arguments.array[0].string);
+        fake_print_message_section_operation_path_outside(*data, data_make->error, F_status_set_fine(*status), "fake_make_assure_inside_project", data_make->path_cache.used ? data_make->path_cache.string : arguments.array[0].string);
 
         if (F_status_set_fine(*status) == F_false) {
           *status = F_status_set_error(F_failure);
         }
 
-        return;
+        return 0;
       }
 
       *status = f_path_change(arguments.array[0].string);
 
       if (F_status_is_error(*status)) {
-        fake_print_message_section_operation_path_stack_max(data, data_make->error, F_status_set_fine(*status), "f_path_change", arguments.array[0].string);
+        fake_print_message_section_operation_path_stack_max(*data, data_make->error, F_status_set_fine(*status), "f_path_change", arguments.array[0].string);
       }
       else {
         if (data_make->path.stack.used == data_make->path.stack.size) {
           *status = fl_string_dynamics_increase_by(f_memory_default_allocation_step, &data_make->path.stack);
 
           if (F_status_set_fine(*status) == F_array_too_large) {
-            fake_print_message_section_operation_path_stack_max(data, data_make->error, F_array_too_large, "fl_string_lengths_increase_by", "path stack");
-            return;
+            fake_print_message_section_operation_path_stack_max(*data, data_make->error, F_array_too_large, "fl_string_lengths_increase_by", "path stack");
+            return 0;
           }
           else if (F_status_is_error(*status)) {
             fll_error_print(data_make->error, F_status_set_fine(*status), "f_macro_string_dynamics_t_resize", F_true);
-            return;
+            return 0;
           }
         }
 
@@ -3651,28 +3672,28 @@ extern "C" {
 
         if (F_status_is_error(*status)) {
           fll_error_print(data_make->error, F_status_set_fine(*status), "fl_string_dynamic_append_nulless", F_true);
-          return;
+          return 0;
         }
 
-        if (data.error.verbosity == f_console_verbosity_verbose) {
-          *status = fake_make_path_relative(data, data_make->path.stack.array[data_make->path.stack.used], data_make);
+        if (data->error.verbosity == f_console_verbosity_verbose) {
+          *status = fake_make_path_relative(*data, data_make->path.stack.array[data_make->path.stack.used], data_make);
 
           if (F_status_is_error(*status)) {
             fll_error_print(data_make->error, F_status_set_fine(*status), "fake_make_path_relative", F_true);
-            return;
+            return 0;
           }
 
-          fprintf(data.output.stream, "Changed to project path '");
-          fl_color_print_code(data.output.stream, *data.context.set.notable.before);
-          f_print_dynamic(data.output.stream, data_make->path_cache);
-          fl_color_print_code(data.output.stream, *data.context.set.notable.after);
-          fprintf(data.output.stream, "'.%c", f_string_eol[0]);
+          fprintf(data->output.stream, "Changed to project path '");
+          fl_color_print_code(data->output.stream, *data->context.set.notable.before);
+          f_print_dynamic(data->output.stream, data_make->path_cache);
+          fl_color_print_code(data->output.stream, *data->context.set.notable.after);
+          fprintf(data->output.stream, "'.%c", f_string_eol[0]);
         }
 
         data_make->path.stack.used++;
       }
 
-      return;
+      return 0;
     }
 
     if (operation == fake_make_operation_type_top) {
@@ -3680,12 +3701,12 @@ extern "C" {
       *status = f_path_change_at(data_make->path.top.id);
 
       if (F_status_is_error(*status)) {
-        fake_print_message_section_operation_path_stack_max(data, data_make->error, F_status_set_fine(*status), "f_path_change", arguments.array[0].string);
-        return;
+        fake_print_message_section_operation_path_stack_max(*data, data_make->error, F_status_set_fine(*status), "f_path_change", arguments.array[0].string);
+        return 0;
       }
 
-      if (data.error.verbosity == f_console_verbosity_verbose) {
-        fprintf(data.output.stream, "Changed to project path ''.%c", f_string_eol[0]);
+      if (data->error.verbosity == f_console_verbosity_verbose) {
+        fprintf(data->output.stream, "Changed to project path ''.%c", f_string_eol[0]);
       }
 
       // clear stack, except for the project root.
@@ -3694,13 +3715,13 @@ extern "C" {
       } // for
 
       data_make->path.stack.used = 1;
-      return;
+      return 0;
     }
 
     if (operation == fake_make_operation_type_touch) {
       f_mode_t mode = f_mode_t_initialize;
 
-      f_macro_mode_t_set_default_umask(mode, data.umask);
+      f_macro_mode_t_set_default_umask(mode, data->umask);
 
       for (f_array_length_t i = 1; i < arguments.used; i++) {
 
@@ -3733,18 +3754,18 @@ extern "C" {
           }
         }
 
-        if (data.error.verbosity == f_console_verbosity_verbose) {
-          fprintf(data.output.stream, "Touched %s '", arguments.array[0].string);
-          fl_color_print_code(data.output.stream, *data.context.set.notable.before);
-          f_print_dynamic(data.output.stream, arguments.array[i]);
-          fl_color_print_code(data.output.stream, *data.context.set.notable.after);
-          fprintf(data.output.stream, "'.%c", f_string_eol[0]);
+        if (data->error.verbosity == f_console_verbosity_verbose) {
+          fprintf(data->output.stream, "Touched %s '", arguments.array[0].string);
+          fl_color_print_code(data->output.stream, *data->context.set.notable.before);
+          f_print_dynamic(data->output.stream, arguments.array[i]);
+          fl_color_print_code(data->output.stream, *data->context.set.notable.after);
+          fprintf(data->output.stream, "'.%c", f_string_eol[0]);
         }
 
       } // for
-
-      return;
     }
+
+    return 0;
   }
 #endif // _di_fake_make_operate_process_
 
@@ -3826,10 +3847,10 @@ extern "C" {
     f_signal_set_fill(&signals.block_not);
 
     if (as_shell) {
-      status = fll_execute_path_environment(program.string, arguments, &signals, data_make->environment.names, data_make->environment.values, &return_code);
+      status = fll_execute_path_environment(program.string, arguments, data_make->environment.names, data_make->environment.values, &signals, &return_code);
     }
     else {
-      status = fll_execute_program_environment(program.string, arguments, &signals, data_make->environment.names, data_make->environment.values, &return_code);
+      status = fll_execute_program_environment(program.string, arguments, data_make->environment.names, data_make->environment.values, &signals, &return_code);
     }
 
     if (status == F_status_set_error(F_signal)) {
index 8b83d3a783a03972ecf4b4268f60f62388a4a032..5a412c35d5ecb4c814f917cfd1ebff971e5c256f 100644 (file)
@@ -538,7 +538,7 @@ extern "C" {
  *   Status codes (with error bit) are returned on any problem.
  */
 #ifndef _di_fake_make_operate_
-  extern f_return_status fake_make_operate(const fake_data_t data) f_gcc_attribute_visibility_internal;
+  extern f_return_status fake_make_operate(fake_data_t *data) f_gcc_attribute_visibility_internal;
 #endif // _di_fake_make_operate_
 
 /**
@@ -622,29 +622,32 @@ extern "C" {
 /**
  * Perform the make operations within the given section.
  *
- * @param data
- *   The program data.
  * @param id_section
  *   The array location id within the fakefile of the section to operate on.
+ * @param data
+ *   The program data.
  * @param data_make
  *   All make related setting data, including data from the fakefile and optionally build settings file.
  * @param section_stack
  *   The current operation stack.
  * @param status
- *   The return status.
- *
+ *   F_none on success.
  *   F_valid_not (with error bit set) is returned if any part of the section is invalid, such as an invalid operation name.
  *   F_recurse (with error bit set) is returned if unable to recurse to another operation section (usually max stack depth reached).
+ *
+ *   Status codes (with error bit) are returned on any problem.
+ *
+ * @return
+ *   The return code of the execution process.
+ *   This generally is only needed when F_child is returned, where this holds the return status of the child process.
  */
 #ifndef _di_fake_make_operate_section_
-  void fake_make_operate_section(const fake_data_t data, const f_array_length_t id_section, fake_make_data_t *data_make, f_string_lengths_t *section_stack, f_status_t *status) f_gcc_attribute_visibility_internal;
+  int fake_make_operate_section(const f_array_length_t id_section, fake_data_t *data, fake_make_data_t *data_make, f_string_lengths_t *section_stack, f_status_t *status) f_gcc_attribute_visibility_internal;
 #endif // _di_fake_make_operate_section_
 
 /**
  * Perform a specific make operation within the given section.
  *
- * @param data
- *   The program data.
  * @param section_name
  *   The section name.
  * @param operation
@@ -657,17 +660,23 @@ extern "C" {
  *   Whether or not a previous section operation succeeded or failed.
  * @param operation_if
  *   The if-condition status for the current operation.
+ * @param data
+ *   The program data.
  * @param data_make
  *   All make related setting data, including data from the fakefile and optionally build settings file.
  * @param section_stack
  *   The current operation stack.
  * @param status
- *   The return status.
+ *   F_none on success.
  *
  *   Status codes (with error bit) are returned on any problem.
+ *
+ * @return
+ *   The return code of the execution process.
+ *   This generally is only needed when F_child is returned, where this holds the return status of the child process.
  */
 #ifndef _di_fake_make_operate_process_
-  extern void fake_make_operate_process(const fake_data_t data, const f_string_range_t section_name, const uint8_t operation, const f_string_static_t operation_name, const f_string_dynamics_t arguments, const bool success, uint8_t *operation_if, fake_make_data_t *data_make, f_string_lengths_t *section_stack, f_status_t *status) f_gcc_attribute_visibility_internal;
+  extern int fake_make_operate_process(const f_string_range_t section_name, const uint8_t operation, const f_string_static_t operation_name, const f_string_dynamics_t arguments, const bool success, uint8_t *operation_if, fake_data_t *data, fake_make_data_t *data_make, f_string_lengths_t *section_stack, f_status_t *status) f_gcc_attribute_visibility_internal;
 #endif // _di_fake_make_operate_process_
 
 /**
index 62b985cfd8bd5d8b700e2429f82204399be1cf25..6f8beb0c89e650d609d75f618533b3a9b92fa079 100644 (file)
@@ -754,6 +754,11 @@ f_return_status firewall_perform_commands(const firewall_local_data_t local, con
 
                     status = fll_execute_program((f_string_t) current_tool, arguments, 0, &return_code);
 
+                    // immediately exit child process, @todo this may require additional memory deallocation and relating changes.
+                    if (status == F_child) {
+                      exit(return_code);
+                    }
+
                     if (status == F_failure) {
                       fl_color_print(data.error.to.stream, data.context.set.error, "%sFailed to perform requested %s operation:%c", fll_error_print_error, current_tool, f_string_eol[0]);
                       fprintf(f_type_error, "  ");
@@ -823,6 +828,11 @@ f_return_status firewall_perform_commands(const firewall_local_data_t local, con
 
           status = fll_execute_program(current_tool, arguments, 0, &return_code);
 
+          // immediately exit child process, @todo this may require additional memory deallocation and relating changes.
+          if (status == F_child) {
+            exit(return_code);
+          }
+
           if (status == F_failure) {
             fl_color_print(data.error.to.stream, data.context.set.error, "%sFailed to perform requested %s operation:%c", fll_error_print_error, current_tool, f_string_eol[0]);
             fprintf(f_type_error, "  ");
@@ -1062,6 +1072,11 @@ f_return_status firewall_create_custom_chains(firewall_reserved_chains_t *reserv
         tool = firewall_program_iptables;
         status = fll_execute_program((f_string_t) firewall_tool_iptables, arguments, 0, &return_code);
 
+        // immediately exit child process, @todo this may require additional memory deallocation and relating changes.
+        if (status == F_child) {
+          exit(return_code);
+        }
+
         if (F_status_is_error_not(status)) {
           if (data->error.verbosity == f_console_verbosity_debug) {
             fl_color_print_code(f_type_debug, data->context.warning);
@@ -1077,6 +1092,11 @@ f_return_status firewall_create_custom_chains(firewall_reserved_chains_t *reserv
 
           tool = firewall_program_ip6tables;
           status = fll_execute_program((f_string_t) firewall_tool_ip6tables, arguments, 0, &return_code);
+
+          // immediately exit child process, @todo this may require additional memory deallocation and relating changes.
+          if (status == F_child) {
+            exit(return_code);
+          }
         }
 
         if (F_status_is_error(status)) {
@@ -1161,6 +1181,11 @@ f_return_status firewall_delete_chains(const firewall_data_t data) {
 
     status = fll_execute_program(tools[i], arguments, 0, &return_code);
 
+    // immediately exit child process, @todo this may require additional memory deallocation and relating changes.
+    if (status == F_child) {
+      exit(return_code);
+    }
+
     if (F_status_is_error(status)) {
       status = F_status_set_fine(status);
 
@@ -1216,6 +1241,11 @@ f_return_status firewall_delete_chains(const firewall_data_t data) {
 
     status = fll_execute_program(tools[i], arguments, 0, &return_code);
 
+    // immediately exit child process, @todo this may require additional memory deallocation and relating changes.
+    if (status == F_child) {
+      exit(return_code);
+    }
+
     if (F_status_is_error(status)) {
       status = F_status_set_fine(status);
 
@@ -1293,6 +1323,11 @@ f_return_status firewall_default_lock(const firewall_data_t data) {
 
       status = fll_execute_program(tools[j], arguments, 0, &return_code);
 
+      // immediately exit child process, @todo this may require additional memory deallocation and relating changes.
+      if (status == F_child) {
+        exit(return_code);
+      }
+
       if (F_status_is_error(status)) {
         status = F_status_set_fine(status);