]> Kevux Git Server - fll/commitdiff
Progress: controller program, implementing failsafe.
authorKevin Day <thekevinday@gmail.com>
Tue, 13 Apr 2021 03:18:47 +0000 (22:18 -0500)
committerKevin Day <thekevinday@gmail.com>
Tue, 13 Apr 2021 03:30:41 +0000 (22:30 -0500)
Minor code cleanup:
- Removing no longer valid documentation.
- Cleaning up syntax, such as spacing.
- Updating documentation comments.
- Pass controller_main_t as a pointer in the entry function, updating all uses.
- Remove @fixme for considering status handling because I don't plan on bothering with this now.

A lot of the controller_print_unlock_flush() calls are using the incorrect stream.

Use status_lock as a return in cases where the status that is retuned shouldn't become lost when processing the locks.
Otherwise, the errors may never properly bubble to the parent and therefore may never trigger the failsafe.

The failsafe is not a rule id, but instead an item id.

If and when failsafe support is enabled, trigger it.
The currently implemented code only handles synchronous failures.

Begin work with adding a "failed" flag so that asynchronous, but required, failures can be detected for the purposes of failsafe execution.

level_3/controller/c/controller.c
level_3/controller/c/private-common.c
level_3/controller/c/private-common.h
level_3/controller/c/private-controller.c
level_3/controller/c/private-controller.h
level_3/controller/c/private-entry.c
level_3/controller/c/private-rule.c
level_3/controller/c/private-thread.c
level_3/controller/data/settings/example/entries/test.entry
level_3/controller/data/settings/example/rules/script/fail.rule

index 2c704a05bdb1c53f6f28f3d8e1b1c253bcbd2de7..0647ff1cdb40c60bceaf25791b3e48697cc51042 100644 (file)
@@ -376,10 +376,6 @@ extern "C" {
       return status;
     }
 
-    if (setting.ready == controller_setting_ready_fail) {
-      // @todo trigger failsafe/fallback execution, if defined.
-    }
-
     return status;
   }
 #endif // _di_controller_main_
index 6eff7157fa2c8296bda397eae489c22f50d03a4b..b7aa086691e8339ea2d46a0aab7a7bb0a1218d96 100644 (file)
@@ -165,6 +165,7 @@ extern "C" {
   void controller_lock_delete_simple(controller_lock_t *lock) {
 
     controller_lock_delete_mutex(&lock->print);
+
     controller_lock_delete_rw(&lock->process);
     controller_lock_delete_rw(&lock->rule);
   }
index 045e2c799c2a25ae7b7ffc81f233b2ed342ec22a..f90a0ef2d888ba0a2b597edd1126704a18cbdaeb 100644 (file)
@@ -435,12 +435,10 @@ extern "C" {
  * A structure for sharing mutexes globally between different threads.
  *
  * The print lock is intended to lock any activity printing to stdout/stderr.
- * The entry lock is intended to lock any activity on the entrys structure.
  * The process lock is intended to lock any activity on the processs structure.
  * The rule lock is intended to lock any activity on the rules structure.
  *
  * print:   The print mutex lock.
- * entry:   The entry r/w lock.
  * process: The process r/w lock.
  * rule:    The rule r/w lock.
  */
@@ -1002,11 +1000,11 @@ extern "C" {
  * timeout_start:    The timeout to wait relating to starting a process.
  * timeout_stop:     The timeout to wait relating to stopping a process.
  * failsafe_enabled: TRUE if failsafe execution is enabled, FALSE otherwise.
- * failsafe_rule_id: The Rule ID (such as "failsafe/bash") to execute when failsafe execution is enabled.
+ * failsafe_item_id: The Entry Item ID to execute when failsafe execution is enabled.
  * path_control:     File path to the control socket.
  * path_pid:         File path to the PID file.
  * path_setting:     File path to the setting directory.
- * entry:            The entry settings.
+ * entry:            The Entry settings.
  * rules:            All rules and their respective settings.
  */
 #ifndef _di_controller_setting_t
@@ -1028,7 +1026,7 @@ extern "C" {
     f_number_unsigned_t timeout_stop;
 
     bool failsafe_enabled;
-    f_array_length_t failsafe_rule_id;
+    f_array_length_t failsafe_item_id;
 
     f_string_dynamic_t path_control;
     f_string_dynamic_t path_pid;
@@ -1095,6 +1093,7 @@ extern "C" {
 
   typedef struct {
     bool enabled;
+    bool failed;
     int signal;
     f_status_t status;
 
@@ -1110,6 +1109,7 @@ extern "C" {
 
   #define controller_thread_t_initialize { \
     F_true, \
+    F_false, \
     0, \
     F_none, \
     f_thread_id_t_initialize, \
index 3052cd92de5dbf3e39f307c23284301e4b4c5761..e9d4fcab2fb90525ccfc6e50fd8c488573bc356c 100644 (file)
@@ -106,7 +106,7 @@ extern "C" {
 
         fll_error_file_print(main.data->error, F_status_set_fine(status), "f_file_stream_open", F_true, path, "open", fll_error_file_type_file);
 
-        controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+        controller_print_unlock_flush(main.data->error.to.stream, &main.thread->lock.print);
       }
     }
     else {
@@ -118,7 +118,7 @@ extern "C" {
 
           fll_error_file_print(main.data->error, F_status_set_fine(status), "f_file_stream_read", F_true, path, "read", fll_error_file_type_file);
 
-          controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+          controller_print_unlock_flush(main.data->error.to.stream, &main.thread->lock.print);
         }
       }
     }
@@ -136,7 +136,7 @@ extern "C" {
 
           fll_error_file_print(main.data->error, F_status_set_fine(status), "f_file_stat", F_true, path, "stat", fll_error_file_type_file);
 
-          controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+          controller_print_unlock_flush(main.data->error.to.stream, &main.thread->lock.print);
         }
       }
       else {
@@ -364,7 +364,7 @@ extern "C" {
 
             controller_entry_error_print_cache(main.data->error, cache->action);
 
-            controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+            controller_print_unlock_flush(main.data->error.to.stream, &main.thread->lock.print);
           }
 
           return status;
@@ -377,7 +377,7 @@ extern "C" {
 
           controller_entry_error_print_cache(main.data->warning, cache->action);
 
-          controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+          controller_print_unlock_flush(main.data->warning.to.stream, &main.thread->lock.print);
         }
 
         status = F_none;
@@ -465,7 +465,7 @@ extern "C" {
 
               controller_entry_error_print_cache(main.data->warning, cache->action);
 
-              controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+              controller_print_unlock_flush(main.data->warning.to.stream, &main.thread->lock.print);
             }
           }
 
@@ -498,7 +498,7 @@ extern "C" {
 
                     controller_entry_error_print_cache(main.data->error, cache->action);
 
-                    controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+                    controller_print_unlock_flush(main.data->error.to.stream, &main.thread->lock.print);
                   }
 
                   if (F_status_is_error_not(status)) {
@@ -561,7 +561,7 @@ extern "C" {
 
                 controller_entry_error_print_cache(main.data->error, cache->action);
 
-                controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+                controller_print_unlock_flush(main.data->error.to.stream, &main.thread->lock.print);
               }
 
               if (F_status_is_error_not(status)) {
@@ -617,7 +617,7 @@ extern "C" {
 #endif // _di_controller_preprocess_entry_
 
 #ifndef _di_controller_process_entry_
-  f_status_t controller_process_entry(controller_main_t main, controller_cache_t *cache) {
+  f_status_t controller_process_entry(const bool failsafe, controller_main_t *main, controller_cache_t *cache) {
     f_status_t status = F_none;
 
     f_array_length_t i = 0;
@@ -637,7 +637,7 @@ extern "C" {
     // an empty stack is used here because each rule here is the first rule run in the rule's scope.
     const f_array_lengths_t stack = f_array_lengths_t_initialize;
 
-    const bool simulate = main.data->parameters[controller_parameter_test].result == f_console_result_found;
+    const bool simulate = main->data->parameters[controller_parameter_test].result == f_console_result_found;
 
     cache->ats.used = 0;
     cache->stack.used = 0;
@@ -647,53 +647,53 @@ extern "C" {
     cache->action.name_action.used = 0;
     cache->action.name_item.used = 0;
 
-    if (main.setting->ready == controller_setting_ready_yes) {
-      status = controller_perform_ready(main, cache);
+    if (main->setting->ready == controller_setting_ready_yes) {
+      status = controller_perform_ready(*main, cache);
       if (F_status_is_error(status)) return status;
     }
 
     f_macro_array_lengths_t_increase_by(status, cache->ats, controller_default_allocation_step)
 
     if (F_status_is_error(status)) {
-      controller_entry_error_print(main.data->error, cache->action, F_status_set_fine(status), "f_macro_array_lengths_t_increase_by", F_true, main.thread);
+      controller_entry_error_print(main->data->error, cache->action, F_status_set_fine(status), "f_macro_array_lengths_t_increase_by", F_true, main->thread);
 
       return status;
     }
 
     // utilize the ats cache as an item execution stack (at_i is for item index, and at_j (at_i + 1) is for action index).
-    cache->ats.array[0] = 0;
+    cache->ats.array[0] = failsafe ? main->setting->failsafe_item_id : 0;
     cache->ats.array[1] = 0;
     cache->ats.used = 2;
 
-    cache->action.line_item = main.setting->entry.items.array[0].line;
+    cache->action.line_item = main->setting->entry.items.array[cache->ats.array[0]].line;
     cache->action.name_item.used = 0;
 
-    status = controller_string_dynamic_append_terminated(main.setting->entry.items.array[0].name, &cache->action.name_item);
+    status = controller_string_dynamic_append_terminated(main->setting->entry.items.array[cache->ats.array[0]].name, &cache->action.name_item);
 
     if (F_status_is_error(status)) {
-      controller_entry_error_print(main.data->error, cache->action, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true, main.thread);
+      controller_entry_error_print(main->data->error, cache->action, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true, main->thread);
 
       return status;
     }
 
     if (simulate) {
-      if (main.data->error.verbosity != f_console_verbosity_quiet) {
-        f_thread_mutex_lock(&main.thread->lock.print);
+      if (main->data->error.verbosity != f_console_verbosity_quiet) {
+        f_thread_mutex_lock(&main->thread->lock.print);
 
-        fprintf(main.data->output.stream, "%c", f_string_eol_s[0]);
-        fprintf(main.data->output.stream, "Processing entry item '");
-        fprintf(main.data->output.stream, "%s%s%s", main.data->context.set.title.before->string, controller_string_main_s, main.data->context.set.title.after->string);
-        fprintf(main.data->output.stream, "'.%c", f_string_eol_s[0]);
+        fprintf(main->data->output.stream, "%c", f_string_eol_s[0]);
+        fprintf(main->data->output.stream, "Processing %sentry item '", (failsafe ? "failsafe " : ""));
+        fprintf(main->data->output.stream, "%s%s%s", main->data->context.set.title.before->string, cache->action.name_item.string, main->data->context.set.title.after->string);
+        fprintf(main->data->output.stream, "'.%c", f_string_eol_s[0]);
 
-        controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+        controller_print_unlock_flush(main->data->output.stream, &main->thread->lock.print);
       }
     }
 
-    for (; main.thread->enabled; ) {
+    for (; main->thread->enabled; ) {
 
-      entry_actions = &main.setting->entry.items.array[cache->ats.array[at_i]].actions;
+      entry_actions = &main->setting->entry.items.array[cache->ats.array[at_i]].actions;
 
-      for (; cache->ats.array[at_j] < entry_actions->used && main.thread->enabled; ++cache->ats.array[at_j]) {
+      for (; cache->ats.array[at_j] < entry_actions->used && main->thread->enabled; ++cache->ats.array[at_j]) {
 
         entry_action = &entry_actions->array[cache->ats.array[at_j]];
 
@@ -703,7 +703,7 @@ extern "C" {
         status = controller_string_dynamic_append_terminated(controller_entry_action_type_name(entry_action->type), &cache->action.name_action);
 
         if (F_status_is_error(status)) {
-          controller_entry_error_print(main.data->error, cache->action, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true, main.thread);
+          controller_entry_error_print(main->data->error, cache->action, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true, main->thread);
 
           return status;
         }
@@ -711,115 +711,115 @@ extern "C" {
         if (F_status_is_error(entry_action->status)) {
           if (entry_action->type == controller_entry_action_type_rule) {
             if (simulate) {
-              if (main.data->error.verbosity != f_console_verbosity_quiet) {
-                f_thread_mutex_lock(&main.thread->lock.print);
+              if (main->data->error.verbosity != f_console_verbosity_quiet) {
+                f_thread_mutex_lock(&main->thread->lock.print);
 
-                fprintf(main.data->output.stream, "%c", f_string_eol_s[0]);
-                fprintf(main.data->output.stream, "The entry item action '");
-                fprintf(main.data->output.stream, "%s%s%s", main.data->context.set.title.before->string, cache->action.name_action.string, main.data->context.set.title.after->string);
+                fprintf(main->data->output.stream, "%c", f_string_eol_s[0]);
+                fprintf(main->data->output.stream, "The entry item action '");
+                fprintf(main->data->output.stream, "%s%s%s", main->data->context.set.title.before->string, cache->action.name_action.string, main->data->context.set.title.after->string);
 
                 if (entry_action->parameters.used) {
-                  fprintf(main.data->output.stream, f_string_space_s);
-                  fprintf(main.data->output.stream, "%s", main.data->context.set.notable.before->string);
-                  controller_entry_action_parameters_print(main.data->output.stream, entry_actions->array[cache->ats.array[at_j]]);
-                  fprintf(main.data->output.stream, "%s", main.data->context.set.notable.after->string);
+                  fprintf(main->data->output.stream, f_string_space_s);
+                  fprintf(main->data->output.stream, "%s", main->data->context.set.notable.before->string);
+                  controller_entry_action_parameters_print(main->data->output.stream, entry_actions->array[cache->ats.array[at_j]]);
+                  fprintf(main->data->output.stream, "%s", main->data->context.set.notable.after->string);
                 }
 
-                fprintf(main.data->output.stream, "' is %s and is in a %sfailed%s state, skipping execution.%c", entry_action->code & controller_entry_rule_code_require ? "required" : "optional", main.data->error.context.before->string, main.data->error.context.after->string, f_string_eol_s[0]);
+                fprintf(main->data->output.stream, "' is %s and is in a %sfailed%s state, skipping execution.%c", entry_action->code & controller_entry_rule_code_require ? "required" : "optional", main->data->error.context.before->string, main->data->error.context.after->string, f_string_eol_s[0]);
 
-                controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+                controller_print_unlock_flush(main->data->output.stream, &main->thread->lock.print);
               }
             }
             else if (entry_action->code & controller_entry_rule_code_require) {
 
-              if (main.data->error.verbosity != f_console_verbosity_quiet) {
-                f_thread_mutex_lock(&main.thread->lock.print);
+              if (main->data->error.verbosity != f_console_verbosity_quiet) {
+                f_thread_mutex_lock(&main->thread->lock.print);
 
-                fprintf(main.data->error.to.stream, "%c", f_string_eol_s[0]);
-                fprintf(main.data->error.to.stream, "%s%sThe entry item action '", main.data->error.context.before->string, main.data->error.prefix ? main.data->error.prefix : f_string_empty_s);
-                fprintf(main.data->error.to.stream, "%s%s%s", main.data->error.context.after->string, main.data->error.notable.before->string, cache->action.name_action.string);
+                fprintf(main->data->error.to.stream, "%c", f_string_eol_s[0]);
+                fprintf(main->data->error.to.stream, "%s%sThe entry item action '", main->data->error.context.before->string, main->data->error.prefix ? main->data->error.prefix : f_string_empty_s);
+                fprintf(main->data->error.to.stream, "%s%s%s", main->data->error.context.after->string, main->data->error.notable.before->string, cache->action.name_action.string);
 
                 if (entry_action->parameters.used) {
-                  fprintf(main.data->error.to.stream, f_string_space_s);
-                  controller_entry_action_parameters_print(main.data->error.to.stream, entry_actions->array[cache->ats.array[at_j]]);
+                  fprintf(main->data->error.to.stream, f_string_space_s);
+                  controller_entry_action_parameters_print(main->data->error.to.stream, entry_actions->array[cache->ats.array[at_j]]);
                 }
 
-                fprintf(main.data->error.to.stream, "%s%s' is ", main.data->error.notable.after->string, main.data->error.context.before->string);
-                fprintf(main.data->error.to.stream, "%s%srequired%s", main.data->error.context.after->string, main.data->error.notable.before->string, main.data->error.notable.after->string);
-                fprintf(main.data->error.to.stream, "%s and is in a ", main.data->error.context.before->string);
-                fprintf(main.data->error.to.stream, "%s%sfailed%s", main.data->error.context.after->string, main.data->error.notable.before->string, main.data->error.notable.after->string);
-                fprintf(main.data->error.to.stream, "%s state, skipping execution.%s%c", main.data->error.context.before->string, main.data->error.context.after->string, f_string_eol_s[0]);
+                fprintf(main->data->error.to.stream, "%s%s' is ", main->data->error.notable.after->string, main->data->error.context.before->string);
+                fprintf(main->data->error.to.stream, "%s%srequired%s", main->data->error.context.after->string, main->data->error.notable.before->string, main->data->error.notable.after->string);
+                fprintf(main->data->error.to.stream, "%s and is in a ", main->data->error.context.before->string);
+                fprintf(main->data->error.to.stream, "%s%sfailed%s", main->data->error.context.after->string, main->data->error.notable.before->string, main->data->error.notable.after->string);
+                fprintf(main->data->error.to.stream, "%s state, skipping execution.%s%c", main->data->error.context.before->string, main->data->error.context.after->string, f_string_eol_s[0]);
 
-                controller_entry_error_print_cache(main.data->error, cache->action);
+                controller_entry_error_print_cache(main->data->error, cache->action);
 
-                controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+                controller_print_unlock_flush(main->data->error.to.stream, &main->thread->lock.print);
               }
 
               return F_status_is_error(F_require);
             }
-            else if (main.data->warning.verbosity == f_console_verbosity_debug) {
-              f_thread_mutex_lock(&main.thread->lock.print);
+            else if (main->data->warning.verbosity == f_console_verbosity_debug) {
+              f_thread_mutex_lock(&main->thread->lock.print);
 
-              fprintf(main.data->warning.to.stream, "%c", f_string_eol_s[0]);
-              fprintf(main.data->warning.to.stream, "%s%sThe entry item action '", main.data->warning.context.before->string, main.data->warning.prefix ? main.data->warning.prefix : f_string_empty_s);
-              fprintf(main.data->warning.to.stream, "%s%s%s", main.data->warning.context.after->string, main.data->warning.notable.before->string, cache->action.name_action.string);
+              fprintf(main->data->warning.to.stream, "%c", f_string_eol_s[0]);
+              fprintf(main->data->warning.to.stream, "%s%sThe entry item action '", main->data->warning.context.before->string, main->data->warning.prefix ? main->data->warning.prefix : f_string_empty_s);
+              fprintf(main->data->warning.to.stream, "%s%s%s", main->data->warning.context.after->string, main->data->warning.notable.before->string, cache->action.name_action.string);
 
               if (entry_action->parameters.used) {
-                fprintf(main.data->warning.to.stream, f_string_space_s);
-                controller_entry_action_parameters_print(main.data->warning.to.stream, entry_actions->array[cache->ats.array[at_j]]);
+                fprintf(main->data->warning.to.stream, f_string_space_s);
+                controller_entry_action_parameters_print(main->data->warning.to.stream, entry_actions->array[cache->ats.array[at_j]]);
               }
 
-              fprintf(main.data->warning.to.stream, "%s%s' is ", main.data->warning.notable.after->string, main.data->warning.context.before->string);
-              fprintf(main.data->warning.to.stream, "%s%srequired%s", main.data->warning.context.after->string, main.data->warning.notable.before->string, main.data->warning.notable.after->string);
-              fprintf(main.data->warning.to.stream, "%s and is in a ", main.data->warning.context.before->string);
-              fprintf(main.data->warning.to.stream, "%s%sfailed%s", main.data->warning.context.after->string, main.data->warning.notable.before->string, main.data->warning.notable.after->string);
-              fprintf(main.data->warning.to.stream, "%s state, skipping execution.%s%c", main.data->warning.context.before->string, main.data->warning.context.after->string, f_string_eol_s[0]);
+              fprintf(main->data->warning.to.stream, "%s%s' is ", main->data->warning.notable.after->string, main->data->warning.context.before->string);
+              fprintf(main->data->warning.to.stream, "%s%srequired%s", main->data->warning.context.after->string, main->data->warning.notable.before->string, main->data->warning.notable.after->string);
+              fprintf(main->data->warning.to.stream, "%s and is in a ", main->data->warning.context.before->string);
+              fprintf(main->data->warning.to.stream, "%s%sfailed%s", main->data->warning.context.after->string, main->data->warning.notable.before->string, main->data->warning.notable.after->string);
+              fprintf(main->data->warning.to.stream, "%s state, skipping execution.%s%c", main->data->warning.context.before->string, main->data->warning.context.after->string, f_string_eol_s[0]);
 
-              controller_entry_error_print_cache(main.data->warning, cache->action);
+              controller_entry_error_print_cache(main->data->warning, cache->action);
 
-              controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+              controller_print_unlock_flush(main->data->warning.to.stream, &main->thread->lock.print);
             }
           }
           else {
             if (simulate) {
-              if (main.data->error.verbosity != f_console_verbosity_quiet) {
-                f_thread_mutex_lock(&main.thread->lock.print);
+              if (main->data->error.verbosity != f_console_verbosity_quiet) {
+                f_thread_mutex_lock(&main->thread->lock.print);
 
-                fprintf(main.data->output.stream, "%c", f_string_eol_s[0]);
-                fprintf(main.data->output.stream, "The entry item action '");
-                fprintf(main.data->output.stream, "%s%s%s", main.data->context.set.title.before->string, cache->action.name_action.string, main.data->context.set.title.after->string);
+                fprintf(main->data->output.stream, "%c", f_string_eol_s[0]);
+                fprintf(main->data->output.stream, "The entry item action '");
+                fprintf(main->data->output.stream, "%s%s%s", main->data->context.set.title.before->string, cache->action.name_action.string, main->data->context.set.title.after->string);
 
                 if (entry_action->parameters.used) {
-                  fprintf(main.data->output.stream, f_string_space_s);
-                  fprintf(main.data->output.stream, "%s", main.data->context.set.notable.before->string);
-                  controller_entry_action_parameters_print(main.data->output.stream, entry_actions->array[cache->ats.array[at_j]]);
-                  fprintf(main.data->output.stream, "%s", main.data->context.set.notable.after->string);
+                  fprintf(main->data->output.stream, f_string_space_s);
+                  fprintf(main->data->output.stream, "%s", main->data->context.set.notable.before->string);
+                  controller_entry_action_parameters_print(main->data->output.stream, entry_actions->array[cache->ats.array[at_j]]);
+                  fprintf(main->data->output.stream, "%s", main->data->context.set.notable.after->string);
                 }
 
-                fprintf(main.data->output.stream, "' is in a %sfailed%s state, skipping.%c", main.data->error.context.before->string, main.data->error.context.after->string, f_string_eol_s[0]);
+                fprintf(main->data->output.stream, "' is in a %sfailed%s state, skipping.%c", main->data->error.context.before->string, main->data->error.context.after->string, f_string_eol_s[0]);
 
-                controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+                controller_print_unlock_flush(main->data->output.stream, &main->thread->lock.print);
               }
             }
-            else if (main.data->warning.verbosity == f_console_verbosity_debug) {
-              f_thread_mutex_lock(&main.thread->lock.print);
+            else if (main->data->warning.verbosity == f_console_verbosity_debug) {
+              f_thread_mutex_lock(&main->thread->lock.print);
 
-              fprintf(main.data->warning.to.stream, "%c", f_string_eol_s[0]);
-              fprintf(main.data->warning.to.stream, "%s%sThe entry item action '", main.data->warning.context.before->string, main.data->warning.prefix ? main.data->warning.prefix : f_string_empty_s);
-              fprintf(main.data->warning.to.stream, "%s%s", main.data->warning.notable.before->string, cache->action.name_action.string);
+              fprintf(main->data->warning.to.stream, "%c", f_string_eol_s[0]);
+              fprintf(main->data->warning.to.stream, "%s%sThe entry item action '", main->data->warning.context.before->string, main->data->warning.prefix ? main->data->warning.prefix : f_string_empty_s);
+              fprintf(main->data->warning.to.stream, "%s%s", main->data->warning.notable.before->string, cache->action.name_action.string);
 
               if (entry_action->parameters.used) {
-                fprintf(main.data->warning.to.stream, f_string_space_s);
-                controller_entry_action_parameters_print(main.data->warning.to.stream, entry_actions->array[cache->ats.array[at_j]]);
+                fprintf(main->data->warning.to.stream, f_string_space_s);
+                controller_entry_action_parameters_print(main->data->warning.to.stream, entry_actions->array[cache->ats.array[at_j]]);
               }
 
-              fprintf(main.data->warning.to.stream, "%s' is in a ", main.data->warning.notable.after->string);
-              fprintf(main.data->warning.to.stream, "%s%sfailed%s", main.data->warning.context.after->string, main.data->warning.notable.before->string, main.data->warning.notable.after->string);
-              fprintf(main.data->warning.to.stream, "%s state, skipping.%s%c", main.data->warning.context.before->string, main.data->warning.context.after->string, f_string_eol_s[0]);
+              fprintf(main->data->warning.to.stream, "%s' is in a ", main->data->warning.notable.after->string);
+              fprintf(main->data->warning.to.stream, "%s%sfailed%s", main->data->warning.context.after->string, main->data->warning.notable.before->string, main->data->warning.notable.after->string);
+              fprintf(main->data->warning.to.stream, "%s state, skipping.%s%c", main->data->warning.context.before->string, main->data->warning.context.after->string, f_string_eol_s[0]);
 
-              controller_entry_error_print_cache(main.data->warning, cache->action);
+              controller_entry_error_print_cache(main->data->warning, cache->action);
 
-              controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+              controller_print_unlock_flush(main->data->warning.to.stream, &main->thread->lock.print);
             }
           }
 
@@ -828,57 +828,58 @@ extern "C" {
 
         if (entry_action->type == controller_entry_action_type_ready) {
 
-          if (main.setting->ready == controller_setting_ready_wait) {
+          if (main->setting->ready == controller_setting_ready_wait) {
 
             if (simulate) {
-              if (main.data->error.verbosity != f_console_verbosity_quiet) {
-                f_thread_mutex_lock(&main.thread->lock.print);
+              if (main->data->error.verbosity != f_console_verbosity_quiet) {
+                f_thread_mutex_lock(&main->thread->lock.print);
 
-                fprintf(main.data->output.stream, "%c", f_string_eol_s[0]);
-                fprintf(main.data->output.stream, "Processing entry item action '");
-                fprintf(main.data->output.stream, "%s%s%s", main.data->context.set.title.before->string, controller_string_ready_s, main.data->context.set.title.after->string);
-                fprintf(main.data->output.stream, "'.%c", f_string_eol_s[0]);
+                fprintf(main->data->output.stream, "%c", f_string_eol_s[0]);
+                fprintf(main->data->output.stream, "Processing entry item action '");
+                fprintf(main->data->output.stream, "%s%s%s", main->data->context.set.title.before->string, controller_string_ready_s, main->data->context.set.title.after->string);
+                fprintf(main->data->output.stream, "'.%c", f_string_eol_s[0]);
 
-                controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+                controller_print_unlock_flush(main->data->output.stream, &main->thread->lock.print);
               }
             }
             else {
-              controller_perform_ready(main, cache);
+              controller_perform_ready(*main, cache);
 
               if (F_status_is_error(status)) return status;
             }
 
-            main.setting->ready = controller_setting_ready_yes;
+            main->setting->ready = controller_setting_ready_yes;
           }
           else if (simulate) {
-            if (main.data->error.verbosity != f_console_verbosity_quiet) {
-              f_thread_mutex_lock(&main.thread->lock.print);
+            if (main->data->error.verbosity != f_console_verbosity_quiet) {
+              f_thread_mutex_lock(&main->thread->lock.print);
 
-              fprintf(main.data->output.stream, "%c", f_string_eol_s[0]);
-              fprintf(main.data->output.stream, "Ignoring entry item action '");
-              fprintf(main.data->output.stream, "%s%s%s", main.data->context.set.title.before->string, controller_string_ready_s, main.data->context.set.title.after->string);
-              fprintf(main.data->output.stream, "', state already is ready.%c", f_string_eol_s[0]);
+              fprintf(main->data->output.stream, "%c", f_string_eol_s[0]);
+              fprintf(main->data->output.stream, "Ignoring entry item action '");
+              fprintf(main->data->output.stream, "%s%s%s", main->data->context.set.title.before->string, controller_string_ready_s, main->data->context.set.title.after->string);
+              fprintf(main->data->output.stream, "', state already is ready.%c", f_string_eol_s[0]);
 
-              controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+              controller_print_unlock_flush(main->data->output.stream, &main->thread->lock.print);
             }
           }
         }
         else if (entry_action->type == controller_entry_action_type_item) {
 
-          if (entry_action->number == 0 || entry_action->number >= main.setting->entry.items.used) {
+          // @todo also prevent failsafe item from being recursively called, when failsafe == F_true.
+          if (entry_action->number == 0 || entry_action->number >= main->setting->entry.items.used) {
 
             // This should not happen if the pre-process is working as designed, but in case it doesn't, return a critical error to prevent infinite recursion and similar errors.
-            if (main.data->error.verbosity != f_console_verbosity_quiet) {
-              f_thread_mutex_lock(&main.thread->lock.print);
+            if (main->data->error.verbosity != f_console_verbosity_quiet) {
+              f_thread_mutex_lock(&main->thread->lock.print);
 
-              fprintf(main.data->error.to.stream, "%c", f_string_eol_s[0]);
-              fprintf(main.data->error.to.stream, "%s%sInvalid entry item index ", main.data->error.context.before->string, main.data->error.prefix ? main.data->error.prefix : f_string_empty_s);
-              fprintf(main.data->error.to.stream, "%s%s%llu%s", main.data->error.context.after->string, main.data->error.notable.before->string, entry_action->number, main.data->error.notable.after->string);
-              fprintf(main.data->error.to.stream, "%s detected.%s%c", main.data->error.context.before->string, main.data->error.context.after->string, f_string_eol_s[0]);
+              fprintf(main->data->error.to.stream, "%c", f_string_eol_s[0]);
+              fprintf(main->data->error.to.stream, "%s%sInvalid entry item index ", main->data->error.context.before->string, main->data->error.prefix ? main->data->error.prefix : f_string_empty_s);
+              fprintf(main->data->error.to.stream, "%s%s%llu%s", main->data->error.context.after->string, main->data->error.notable.before->string, entry_action->number, main->data->error.notable.after->string);
+              fprintf(main->data->error.to.stream, "%s detected.%s%c", main->data->error.context.before->string, main->data->error.context.after->string, f_string_eol_s[0]);
 
-              controller_entry_error_print_cache(main.data->error, cache->action);
+              controller_entry_error_print_cache(main->data->error, cache->action);
 
-              controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+              controller_print_unlock_flush(main->data->error.to.stream, &main->thread->lock.print);
             }
 
             return F_status_is_error(F_critical);
@@ -887,7 +888,7 @@ extern "C" {
           f_macro_array_lengths_t_increase_by(status, cache->ats, controller_default_allocation_step)
 
           if (F_status_is_error(status)) {
-            controller_entry_error_print(main.data->error, cache->action, F_status_set_fine(status), "f_macro_array_lengths_t_increase_by", F_true, main.thread);
+            controller_entry_error_print(main->data->error, cache->action, F_status_set_fine(status), "f_macro_array_lengths_t_increase_by", F_true, main->thread);
 
             return status;
           }
@@ -905,26 +906,26 @@ extern "C" {
           cache->action.line_action = 0;
 
           cache->action.name_item.used = 0;
-          cache->action.line_item = main.setting->entry.items.array[cache->ats.array[at_i]].line;
+          cache->action.line_item = main->setting->entry.items.array[cache->ats.array[at_i]].line;
 
-          status = controller_string_dynamic_append_terminated(main.setting->entry.items.array[cache->ats.array[at_i]].name, &cache->action.name_item);
+          status = controller_string_dynamic_append_terminated(main->setting->entry.items.array[cache->ats.array[at_i]].name, &cache->action.name_item);
 
           if (F_status_is_error(status)) {
-            controller_entry_error_print(main.data->error, cache->action, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true, main.thread);
+            controller_entry_error_print(main->data->error, cache->action, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true, main->thread);
 
             return status;
           }
 
           if (simulate) {
-            if (main.data->error.verbosity != f_console_verbosity_quiet) {
-              f_thread_mutex_lock(&main.thread->lock.print);
+            if (main->data->error.verbosity != f_console_verbosity_quiet) {
+              f_thread_mutex_lock(&main->thread->lock.print);
 
-              fprintf(main.data->output.stream, "%c", f_string_eol_s[0]);
-              fprintf(main.data->output.stream, "Processing entry item '");
-              fprintf(main.data->output.stream, "%s%s%s", main.data->context.set.title.before->string, cache->action.name_item.string, main.data->context.set.title.after->string);
-              fprintf(main.data->output.stream, "'.%c", f_string_eol_s[0]);
+              fprintf(main->data->output.stream, "%c", f_string_eol_s[0]);
+              fprintf(main->data->output.stream, "Processing entry item '");
+              fprintf(main->data->output.stream, "%s%s%s", main->data->context.set.title.before->string, cache->action.name_item.string, main->data->context.set.title.after->string);
+              fprintf(main->data->output.stream, "'.%c", f_string_eol_s[0]);
 
-              controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+              controller_print_unlock_flush(main->data->output.stream, &main->thread->lock.print);
             }
           }
 
@@ -933,24 +934,24 @@ extern "C" {
         }
         else if (entry_action->type == controller_entry_action_type_consider || entry_action->type == controller_entry_action_type_rule) {
 
-          status = controller_lock_write(main.thread, &main.thread->lock.rule);
+          status = controller_lock_write(main->thread, &main->thread->lock.rule);
 
           if (status == F_signal) {
             break;
           }
 
-          if (!main.thread->enabled) {
-            f_thread_unlock(&main.thread->lock.rule);
+          if (!main->thread->enabled) {
+            f_thread_unlock(&main->thread->lock.rule);
 
             break;
           }
 
-          status = controller_rules_increase(&main.setting->rules);
+          status = controller_rules_increase(&main->setting->rules);
 
-          f_thread_unlock(&main.thread->lock.rule);
+          f_thread_unlock(&main->thread->lock.rule);
 
           if (F_status_is_error(status)) {
-            controller_entry_error_print(main.data->error, cache->action, F_status_set_fine(status), "controller_rules_increase", F_true, main.thread);
+            controller_entry_error_print(main->data->error, cache->action, F_status_set_fine(status), "controller_rules_increase", F_true, main->thread);
 
             return status;
           }
@@ -965,26 +966,26 @@ extern "C" {
           id_rule_name[entry_action->parameters.array[0].used] = f_path_separator_s[0];
           id_rule_name[id_rule_length] = 0;
 
-          f_thread_lock_read(&main.thread->lock.rule);
+          f_thread_lock_read(&main->thread->lock.rule);
 
-          status = controller_rule_find(alias_rule, main.setting->rules, &at);
+          status = controller_rule_find(alias_rule, main->setting->rules, &at);
 
-          f_thread_unlock(&main.thread->lock.rule);
+          f_thread_unlock(&main->thread->lock.rule);
 
           if (simulate) {
-            if (main.data->error.verbosity != f_console_verbosity_quiet) {
-              f_thread_mutex_lock(&main.thread->lock.print);
+            if (main->data->error.verbosity != f_console_verbosity_quiet) {
+              f_thread_mutex_lock(&main->thread->lock.print);
 
-              fprintf(main.data->output.stream, "%c", f_string_eol_s[0]);
-              fprintf(main.data->output.stream, "%s entry item rule '", entry_action->type == controller_entry_action_type_rule ? "Processing" : "Considering");
-              fprintf(main.data->output.stream, "%s%s%s", main.data->context.set.title.before->string, alias_rule.string, main.data->context.set.title.after->string);
-              fprintf(main.data->output.stream, "'.%c", f_string_eol_s[0]);
+              fprintf(main->data->output.stream, "%c", f_string_eol_s[0]);
+              fprintf(main->data->output.stream, "%s entry item rule '", entry_action->type == controller_entry_action_type_rule ? "Processing" : "Considering");
+              fprintf(main->data->output.stream, "%s%s%s", main->data->context.set.title.before->string, alias_rule.string, main->data->context.set.title.after->string);
+              fprintf(main->data->output.stream, "'.%c", f_string_eol_s[0]);
 
-              controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+              controller_print_unlock_flush(main->data->output.stream, &main->thread->lock.print);
             }
           }
 
-          if (!main.thread->enabled) break;
+          if (!main->thread->enabled) break;
 
           // the rule is not yet loaded, ensure that it is loaded.
           if (status != F_true) {
@@ -1005,19 +1006,19 @@ extern "C" {
             memcpy(cache_name_item, cache->action.name_item.string, cache->action.name_item.used);
             memcpy(cache_name_file, cache->action.name_file.string, cache->action.name_file.used);
 
-            status = controller_lock_write(main.thread, &main.thread->lock.rule);
+            status = controller_lock_write(main->thread, &main->thread->lock.rule);
 
             if (status == F_signal) {
               break;
             }
 
-            if (!main.thread->enabled) {
-              f_thread_unlock(&main.thread->lock.rule);
+            if (!main->thread->enabled) {
+              f_thread_unlock(&main->thread->lock.rule);
 
               break;
             }
 
-            status = controller_rule_read(alias_rule, main, cache, &main.setting->rules.array[main.setting->rules.used]);
+            status = controller_rule_read(alias_rule, *main, cache, &main->setting->rules.array[main->setting->rules.used]);
 
             // restore cache.
             memcpy(cache->action.name_action.string, cache_name_action, cache_name_action_used);
@@ -1035,75 +1036,75 @@ extern "C" {
             cache->action.line_action = cache_line_action;
             cache->action.line_item = cache_line_item;
 
-            if (!main.thread->enabled) {
-              f_thread_unlock(&main.thread->lock.rule);
+            if (!main->thread->enabled) {
+              f_thread_unlock(&main->thread->lock.rule);
 
               break;
             }
 
             if (F_status_is_error(status)) {
 
-              if (main.data->error.verbosity != f_console_verbosity_quiet) {
-                f_thread_mutex_lock(&main.thread->lock.print);
+              if (main->data->error.verbosity != f_console_verbosity_quiet) {
+                f_thread_mutex_lock(&main->thread->lock.print);
 
-                controller_entry_error_print_cache(main.data->error, cache->action);
+                controller_entry_error_print_cache(main->data->error, cache->action);
 
-                controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+                controller_print_unlock_flush(main->data->output.stream, &main->thread->lock.print);
               }
 
               if (!simulate) {
-                f_thread_unlock(&main.thread->lock.rule);
+                f_thread_unlock(&main->thread->lock.rule);
 
                 break;
               }
             }
             else {
-              main.setting->rules.used++;
+              main->setting->rules.used++;
             }
 
-            f_thread_unlock(&main.thread->lock.rule);
+            f_thread_unlock(&main->thread->lock.rule);
 
             // ensure that a process exists for the added rule.
             if (F_status_is_error_not(status)) {
-              f_thread_lock_read(&main.thread->lock.process);
+              f_thread_lock_read(&main->thread->lock.process);
 
-              if (controller_find_process(alias_rule, main.thread->processs, 0) == F_false) {
+              if (controller_find_process(alias_rule, main->thread->processs, 0) == F_false) {
 
-                f_thread_unlock(&main.thread->lock.process);
+                f_thread_unlock(&main->thread->lock.process);
 
-                status = controller_lock_write(main.thread, &main.thread->lock.process);
+                status = controller_lock_write(main->thread, &main->thread->lock.process);
 
                 if (status == F_signal) {
                   break;
                 }
 
-                if (!main.thread->enabled) {
-                  f_thread_unlock(&main.thread->lock.process);
+                if (!main->thread->enabled) {
+                  f_thread_unlock(&main->thread->lock.process);
 
                   break;
                 }
 
-                status = controller_processs_increase(&main.thread->processs);
+                status = controller_processs_increase(&main->thread->processs);
 
                 if (F_status_is_error(status)) {
-                  controller_entry_error_print(main.data->error, cache->action, F_status_set_fine(status), "controller_processs_increase", F_true, main.thread);
+                  controller_entry_error_print(main->data->error, cache->action, F_status_set_fine(status), "controller_processs_increase", F_true, main->thread);
                 }
-                else if (main.thread->processs.array[main.thread->processs.used]) {
+                else if (main->thread->processs.array[main->thread->processs.used]) {
 
                   // only copy the rule alias, as that is all that is needed at this point (the entire rule gets copied prior to executing/processing).
-                  controller_process_t *process = main.thread->processs.array[main.thread->processs.used];
+                  controller_process_t *process = main->thread->processs.array[main->thread->processs.used];
 
-                  status = controller_lock_write(main.thread, &process->lock);
+                  status = controller_lock_write(main->thread, &process->lock);
 
                   if (status == F_signal) {
-                    f_thread_unlock(&main.thread->lock.process);
+                    f_thread_unlock(&main->thread->lock.process);
 
                     break;
                   }
 
-                  if (!main.thread->enabled) {
+                  if (!main->thread->enabled) {
                     f_thread_unlock(&process->lock);
-                    f_thread_unlock(&main.thread->lock.process);
+                    f_thread_unlock(&main->thread->lock.process);
 
                     break;
                   }
@@ -1113,16 +1114,16 @@ extern "C" {
                   status = f_string_dynamic_append(alias_rule, &process->rule.alias);
 
                   if (F_status_is_error(status)) {
-                    controller_entry_error_print(main.data->error, cache->action, F_status_set_fine(status), "f_string_dynamic_append", F_true, main.thread);
+                    controller_entry_error_print(main->data->error, cache->action, F_status_set_fine(status), "f_string_dynamic_append", F_true, main->thread);
                   }
                   else {
                     status = f_string_dynamic_terminate_after(&process->rule.alias);
 
                     if (F_status_is_error(status)) {
-                      controller_entry_error_print(main.data->error, cache->action, F_status_set_fine(status), "f_string_dynamic_terminate_after", F_true, main.thread);
+                      controller_entry_error_print(main->data->error, cache->action, F_status_set_fine(status), "f_string_dynamic_terminate_after", F_true, main->thread);
                     }
                     else {
-                      process->id = main.thread->processs.used++;
+                      process->id = main->thread->processs.used++;
                     }
                   }
 
@@ -1130,7 +1131,7 @@ extern "C" {
                 }
               }
 
-              f_thread_unlock(&main.thread->lock.process);
+              f_thread_unlock(&main->thread->lock.process);
             }
           }
 
@@ -1154,22 +1155,26 @@ extern "C" {
               rule_options |= controller_rule_option_wait;
             }
 
-            if (main.data->parameters[controller_parameter_validate].result == f_console_result_found) {
+            if (main->data->parameters[controller_parameter_validate].result == f_console_result_found) {
               rule_options |= controller_rule_option_validate;
             }
 
             if (entry_action->code & controller_entry_rule_code_asynchronous) {
-              if (main.data->parameters[controller_parameter_validate].result != f_console_result_found) {
+              if (main->data->parameters[controller_parameter_validate].result != f_console_result_found) {
                 process_options |= controller_process_option_asynchronous;
                 rule_options |= controller_rule_option_asynchronous;
               }
             }
 
-            status = controller_rule_process_begin(process_options, alias_rule, controller_rule_action_type_start, rule_options, stack, main, *cache);
+            status = controller_rule_process_begin(process_options, alias_rule, controller_rule_action_type_start, rule_options, stack, *main, *cache);
 
-            if (F_status_set_fine(status) == F_memory_not || status == F_child || status == F_signal || !main.thread->enabled) {
+            if (F_status_set_fine(status) == F_memory_not || status == F_child || status == F_signal || !main->thread->enabled) {
               break;
             }
+
+            if (F_status_is_error(status) && !simulate && (entry_action->code & controller_entry_rule_code_require)) {
+              return F_status_set_error(F_require);
+            }
           }
         }
         else if (entry_action->type == controller_entry_action_type_timeout) {
@@ -1187,75 +1192,89 @@ extern "C" {
               code = controller_string_stop_s;
             }
 
-            if (main.data->error.verbosity != f_console_verbosity_quiet) {
-              f_thread_mutex_lock(&main.thread->lock.print);
+            if (main->data->error.verbosity != f_console_verbosity_quiet) {
+              f_thread_mutex_lock(&main->thread->lock.print);
 
-              fprintf(main.data->output.stream, "%c", f_string_eol_s[0]);
-              fprintf(main.data->output.stream, "Processing entry item action '");
-              fprintf(main.data->output.stream, "%s%s%s", main.data->context.set.title.before->string, controller_string_timeout_s, main.data->context.set.title.after->string);
-              fprintf(main.data->output.stream, "' setting '");
-              fprintf(main.data->output.stream, "%s%s%s", main.data->context.set.important.before->string, code, main.data->context.set.important.after->string);
-              fprintf(main.data->output.stream, "' to '");
-              fprintf(main.data->output.stream, "%s%llu%s", main.data->context.set.important.before->string, entry_action->number, main.data->context.set.important.after->string);
-              fprintf(main.data->output.stream, "' MegaTime (milliseconds).%c", f_string_eol_s[0]);
+              fprintf(main->data->output.stream, "%c", f_string_eol_s[0]);
+              fprintf(main->data->output.stream, "Processing entry item action '");
+              fprintf(main->data->output.stream, "%s%s%s", main->data->context.set.title.before->string, controller_string_timeout_s, main->data->context.set.title.after->string);
+              fprintf(main->data->output.stream, "' setting '");
+              fprintf(main->data->output.stream, "%s%s%s", main->data->context.set.important.before->string, code, main->data->context.set.important.after->string);
+              fprintf(main->data->output.stream, "' to '");
+              fprintf(main->data->output.stream, "%s%llu%s", main->data->context.set.important.before->string, entry_action->number, main->data->context.set.important.after->string);
+              fprintf(main->data->output.stream, "' MegaTime (milliseconds).%c", f_string_eol_s[0]);
 
-              controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+              controller_print_unlock_flush(main->data->output.stream, &main->thread->lock.print);
             }
           }
 
           if (entry_action->code == controller_entry_timeout_code_kill) {
-            main.setting->timeout_kill = entry_action->number;
+            main->setting->timeout_kill = entry_action->number;
           }
           else if (entry_action->code == controller_entry_timeout_code_start) {
-            main.setting->timeout_start = entry_action->number;
+            main->setting->timeout_start = entry_action->number;
           }
           else if (entry_action->code == controller_entry_timeout_code_stop) {
-            main.setting->timeout_stop = entry_action->number;
+            main->setting->timeout_stop = entry_action->number;
           }
         }
         else if (entry_action->type == controller_entry_action_type_failsafe) {
 
-          if (entry_action->number == 0 || entry_action->number >= main.setting->entry.items.used) {
+          if (failsafe) {
+            if (main->data->warning.verbosity == f_console_verbosity_debug) {
+              f_thread_mutex_lock(&main->thread->lock.print);
 
-            // This should not happen if the pre-process is working as designed, but in case it doesn't, return a critical error to prevent infinite recursion and similar errors.
-            if (main.data->error.verbosity != f_console_verbosity_quiet) {
-              f_thread_mutex_lock(&main.thread->lock.print);
+              fprintf(main->data->warning.to.stream, "%c", f_string_eol_s[0]);
+              fprintf(main->data->warning.to.stream, "%s%sFailsafe may not be specified when running in failsafe, ignoring.%s%c", main->data->warning.context.before->string, main->data->warning.prefix ? main->data->warning.prefix : f_string_empty_s, main->data->warning.context.after->string, f_string_eol_s[0]);
 
-              fprintf(main.data->error.to.stream, "%c", f_string_eol_s[0]);
-              fprintf(main.data->error.to.stream, "%s%sInvalid entry item index ", main.data->error.context.before->string, main.data->error.prefix ? main.data->error.prefix : f_string_empty_s);
-              fprintf(main.data->error.to.stream, "%s%s%llu%s", main.data->error.context.after->string, main.data->error.notable.before->string, entry_action->number, main.data->error.notable.after->string);
-              fprintf(main.data->error.to.stream, "%s detected.%s%c", main.data->error.context.before->string, main.data->error.context.after->string, f_string_eol_s[0]);
+              controller_entry_error_print_cache(main->data->warning, cache->action);
 
-              controller_entry_error_print_cache(main.data->error, cache->action);
-
-              controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+              controller_print_unlock_flush(main->data->warning.to.stream, &main->thread->lock.print);
             }
-
-            return F_status_is_error(F_critical);
           }
           else {
-            main.setting->failsafe_enabled = F_true;
-            main.setting->failsafe_rule_id = entry_action->number;
+            if (entry_action->number == 0 || entry_action->number >= main->setting->entry.items.used) {
 
-            if (simulate) {
-              if (main.data->error.verbosity != f_console_verbosity_quiet) {
-                f_thread_mutex_lock(&main.thread->lock.print);
+              // This should not happen if the pre-process is working as designed, but in case it doesn't, return a critical error to prevent infinite recursion and similar errors.
+              if (main->data->error.verbosity != f_console_verbosity_quiet) {
+                f_thread_mutex_lock(&main->thread->lock.print);
+
+                fprintf(main->data->error.to.stream, "%c", f_string_eol_s[0]);
+                fprintf(main->data->error.to.stream, "%s%sInvalid entry item index ", main->data->error.context.before->string, main->data->error.prefix ? main->data->error.prefix : f_string_empty_s);
+                fprintf(main->data->error.to.stream, "%s%s%llu%s", main->data->error.context.after->string, main->data->error.notable.before->string, entry_action->number, main->data->error.notable.after->string);
+                fprintf(main->data->error.to.stream, "%s detected.%s%c", main->data->error.context.before->string, main->data->error.context.after->string, f_string_eol_s[0]);
 
-                fprintf(main.data->output.stream, "%c", f_string_eol_s[0]);
-                fprintf(main.data->output.stream, "Processing entry item action '");
-                fprintf(main.data->output.stream, "%s%s%s", main.data->context.set.title.before->string, controller_string_failsafe_s, main.data->context.set.title.after->string);
-                fprintf(main.data->output.stream, "' setting value to '");
-                fprintf(main.data->output.stream, "%s%s%s", main.data->context.set.important.before->string, main.setting->entry.items.array[main.setting->failsafe_rule_id].name.string, main.data->context.set.important.after->string);
-                fprintf(main.data->output.stream, "'.%c", f_string_eol_s[0]);
+                controller_entry_error_print_cache(main->data->error, cache->action);
 
-                controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+                controller_print_unlock_flush(main->data->error.to.stream, &main->thread->lock.print);
+              }
+
+              return F_status_is_error(F_critical);
+            }
+            else {
+              main->setting->failsafe_enabled = F_true;
+              main->setting->failsafe_item_id = entry_action->number;
+
+              if (simulate) {
+                if (main->data->error.verbosity != f_console_verbosity_quiet) {
+                  f_thread_mutex_lock(&main->thread->lock.print);
+
+                  fprintf(main->data->output.stream, "%c", f_string_eol_s[0]);
+                  fprintf(main->data->output.stream, "Processing entry item action '");
+                  fprintf(main->data->output.stream, "%s%s%s", main->data->context.set.title.before->string, controller_string_failsafe_s, main->data->context.set.title.after->string);
+                  fprintf(main->data->output.stream, "' setting value to '");
+                  fprintf(main->data->output.stream, "%s%s%s", main->data->context.set.important.before->string, main->setting->entry.items.array[main->setting->failsafe_item_id].name.string, main->data->context.set.important.after->string);
+                  fprintf(main->data->output.stream, "'.%c", f_string_eol_s[0]);
+
+                  controller_print_unlock_flush(main->data->output.stream, &main->thread->lock.print);
+                }
               }
             }
           }
         }
       } // for
 
-      if (!main.thread->enabled) {
+      if (!main->thread->enabled) {
         status = F_signal;
       }
 
@@ -1265,7 +1284,7 @@ extern "C" {
       cache->action.name_action.used = 0;
 
       if (F_status_is_error(status)) {
-        if (F_status_set_fine(status) == F_memory_not) {
+        if (F_status_set_fine(status) == F_memory_not || F_status_set_fine(status) == F_require) {
           break;
         }
       }
@@ -1282,20 +1301,20 @@ extern "C" {
         cache->ats.used -= 2;
         cache->ats.array[at_j]++;
 
-        cache->action.line_item = main.setting->entry.items.array[cache->ats.array[at_i]].line;
+        cache->action.line_item = main->setting->entry.items.array[cache->ats.array[at_i]].line;
         cache->action.name_item.used = 0;
 
-        status = controller_string_dynamic_append_terminated(main.setting->entry.items.array[cache->ats.array[at_i]].name, &cache->action.name_item);
+        status = controller_string_dynamic_append_terminated(main->setting->entry.items.array[cache->ats.array[at_i]].name, &cache->action.name_item);
 
         if (F_status_is_error(status)) {
-          controller_entry_error_print(main.data->error, cache->action, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true, main.thread);
+          controller_entry_error_print(main->data->error, cache->action, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true, main->thread);
 
           break;
         }
       }
     } // for
 
-    if (!main.thread->enabled) {
+    if (!main->thread->enabled) {
       return F_signal;
     }
 
@@ -1303,16 +1322,20 @@ extern "C" {
       return status;
     }
 
+    // @todo wait for all asynchronous processes to complete.
+    //       then, check to see if any "required" rule failed.
+    //       if failed, then return F_status_set_error(F_require).
+
     if (simulate) {
-      if (main.data->error.verbosity != f_console_verbosity_quiet) {
-        f_thread_mutex_lock(&main.thread->lock.print);
+      if (main->data->error.verbosity != f_console_verbosity_quiet) {
+        f_thread_mutex_lock(&main->thread->lock.print);
 
-        fprintf(main.data->output.stream, "%c", f_string_eol_s[0]);
-        fprintf(main.data->output.stream, "Done processing entry item '");
-        fprintf(main.data->output.stream, "%s%s%s", main.data->context.set.title.before->string, controller_string_main_s, main.data->context.set.title.after->string);
-        fprintf(main.data->output.stream, "'.%c%c", f_string_eol_s[0], f_string_eol_s[0]);
+        fprintf(main->data->output.stream, "%c", f_string_eol_s[0]);
+        fprintf(main->data->output.stream, "Done processing entry item '");
+        fprintf(main->data->output.stream, "%s%s%s", main->data->context.set.title.before->string, controller_string_main_s, main->data->context.set.title.after->string);
+        fprintf(main->data->output.stream, "'.%c%c", f_string_eol_s[0], f_string_eol_s[0]);
 
-        controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+        controller_print_unlock_flush(main->data->output.stream, &main->thread->lock.print);
       }
     }
 
@@ -1347,11 +1370,11 @@ extern "C" {
       return F_status_set_error(status);
     }
 
-    if (status == F_failure) {
-      return F_status_set_error(F_failure);
+    if (status == F_valid_not) {
+      return F_status_set_error(F_valid_not);
     }
 
-    return F_status_set_error(F_valid_not);
+    return F_status_set_error(F_failure);
   }
 #endif // _di_controller_status_simplify_error_
 
index 8149c96b7978a8286c0d694eff0ae4b7539d10b6..0788661bdff582c8548593f3c5f890100286b111 100644 (file)
@@ -289,6 +289,9 @@ extern "C" {
 /**
  * Process (execute) all items for the loaded entry.
  *
+ * @param failsafe
+ *   If TRUE, operate in failsafe mode (starts at designated failsafe Item).
+ *   If FALSE, operate in normal mode (starts at "main" Item).
  * @param main
  *   The main data.
  * @param cache
@@ -296,6 +299,8 @@ extern "C" {
  *
  * @return
  *   F_none on success.
+ *
+ *   F_require (with error bit) if a required entry item failed.
  *   F_critical (with error bit) on any critical error.
  *
  *   Errors (with error bit) from: f_macro_array_lengths_t_increase_by().
@@ -307,7 +312,7 @@ extern "C" {
  * @see controller_string_dynamic_append_terminated()
  */
 #ifndef _di_controller_process_entry_
-  extern f_status_t controller_process_entry(controller_main_t main, controller_cache_t *cache) f_gcc_attribute_visibility_internal;
+  extern f_status_t controller_process_entry(const bool failsafe, controller_main_t *main, controller_cache_t *cache) f_gcc_attribute_visibility_internal;
 #endif // _di_controller_process_entry_
 
 /**
index 1b6a604817edfc268d781a6f7e52df95481efddf..4f98dd1d8af61ccfaa58d71e84a33fb551a23a89 100644 (file)
@@ -673,7 +673,7 @@ extern "C" {
           fprintf(main.data->error.to.stream, "%c", f_string_eol_s[0]);
           fprintf(main.data->error.to.stream, "%s%sThe entry file is empty.%s%c", main.data->error.context.before->string, main.data->error.prefix ? main.data->error.prefix : f_string_empty_s, main.data->error.context.after->string, f_string_eol_s[0]);
 
-          controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+          controller_print_unlock_flush(main.data->error.to.stream, &main.thread->lock.print);
         }
 
         status = F_status_set_error(F_data_not);
@@ -762,7 +762,7 @@ extern "C" {
 
                 controller_entry_error_print_cache(main.data->warning, cache->action);
 
-                controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+                controller_print_unlock_flush(main.data->warning.to.stream, &main.thread->lock.print);
               }
 
               code |= 0x2;
@@ -811,7 +811,7 @@ extern "C" {
 
             controller_entry_error_print_cache(main.data->error, cache->action);
 
-            controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+            controller_print_unlock_flush(main.data->error.to.stream, &main.thread->lock.print);
 
             if (F_status_set_fine(status) == F_memory_not) {
               break;
@@ -832,7 +832,7 @@ extern "C" {
               fprintf(main.data->error.to.stream, "%s%s%s%s", main.data->error.context.after->string, main.data->error.notable.before->string, controller_string_main_s, main.data->error.notable.after->string);
               fprintf(main.data->error.to.stream, "%s' was not found.%s%c", main.data->error.context.before->string, main.data->error.context.after->string, f_string_eol_s[0]);
 
-              controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+              controller_print_unlock_flush(main.data->error.to.stream, &main.thread->lock.print);
             }
 
             status = F_status_set_error(F_found_not);
@@ -896,15 +896,12 @@ extern "C" {
 
                       controller_entry_error_print_cache(main.data->error, cache->action);
 
-                      controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+                      controller_print_unlock_flush(main.data->error.to.stream, &main.thread->lock.print);
                     }
 
                     action->number = 0;
                     action->status = controller_status_simplify_error(F_found_not);
 
-                    // @fixme review how main.setting->entry.status is being handled with respect to action->status (here the action failed, should the entire entry fail? at the moment if mode is simulation this prevents simulation from continuing).
-                    //main.setting->entry.status = controller_status_simplify_error(F_found_not);
-
                     cache->action.name_action.used = 0;
                     cache->action.name_item.used = 0;
                   }
@@ -914,12 +911,6 @@ extern "C" {
                 }
               } // for
             } // for
-
-            // the error is already fully printed and the entry status is already assigned, so immediately exit.
-            if (missing & 0x2) {
-              // @fixme review how main.setting->entry.status is being handled with respect to action->status (here the action failed, should the entire entry fail? at the moment if mode is simulation this prevents simulation from continuing).
-              //return main.setting->entry.status;
-            }
           }
         }
       }
index 11f76ceaddb82ac37a2162f68b7dee66a634276e..70e6bb2c749f415dcfe4afe16966476535bd2110 100644 (file)
@@ -426,7 +426,7 @@ extern "C" {
 
         controller_rule_error_print_cache(main.data->warning, cache->action, F_true);
 
-        controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+        controller_print_unlock_flush(main.data->warning.to.stream, &main.thread->lock.print);
       }
     }
 
@@ -913,7 +913,7 @@ extern "C" {
 
             controller_rule_error_print_cache(main.data->warning, process->cache.action, F_true);
 
-            controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+            controller_print_unlock_flush(main.data->warning.to.stream, &main.thread->lock.print);
           }
 
           if (success == F_false) {
@@ -955,6 +955,8 @@ extern "C" {
   f_status_t controller_rule_execute_foreground(const uint8_t type, const controller_rule_action_t action, const f_string_t program, const f_string_dynamics_t arguments, const uint8_t options, const controller_main_t main, controller_execute_set_t * const execute_set, controller_process_t *process) {
 
     f_status_t status = F_none;
+    f_status_t status_lock = F_none;
+
     int result = 0;
     pid_t id_child = 0;
 
@@ -996,10 +998,10 @@ extern "C" {
 
       f_thread_unlock(&process->lock);
 
-      status = controller_lock_write(main.thread, &process->lock);
+      status_lock = controller_lock_write(main.thread, &process->lock);
 
-      if (status == F_signal) {
-        return status;
+      if (status_lock == F_signal) {
+        return status_lock;
       }
 
       if (!main.thread->enabled) {
@@ -1023,10 +1025,10 @@ extern "C" {
         return F_signal;
       }
 
-      status = controller_lock_write(main.thread, &process->lock);
+      status_lock = controller_lock_write(main.thread, &process->lock);
 
-      if (status == F_signal) {
-        return status;
+      if (status_lock == F_signal) {
+        return status_lock;
       }
 
       if (!main.thread->enabled) {
@@ -1086,7 +1088,7 @@ extern "C" {
         controller_error_print(main.data->error, F_status_set_fine(status), "fll_execute_program", F_true, main.thread);
       }
 
-      controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+      controller_print_unlock_flush(main.data->error.to.stream, &main.thread->lock.print);
 
       status = F_status_set_error(status);
     }
@@ -1099,6 +1101,8 @@ extern "C" {
   f_status_t controller_rule_execute_pid_with(const uint8_t type, const controller_rule_action_t action, const f_string_t program, const f_string_dynamics_t arguments, const uint8_t options, const controller_main_t main, controller_execute_set_t * const execute_set, controller_process_t *process) {
 
     f_status_t status = F_none;
+    f_status_t status_lock = F_none;
+
     int result = 0;
     pid_t id_child = 0;
 
@@ -1149,10 +1153,10 @@ extern "C" {
 
       f_thread_unlock(&process->lock);
 
-      status = controller_lock_write(main.thread, &process->lock);
+      status_lock = controller_lock_write(main.thread, &process->lock);
 
-      if (status == F_signal) {
-        return status;
+      if (status_lock == F_signal) {
+        return status_lock;
       }
 
       if (!main.thread->enabled) {
@@ -1176,10 +1180,10 @@ extern "C" {
         return F_signal;
       }
 
-      status = controller_lock_write(main.thread, &process->lock);
+      status_lock = controller_lock_write(main.thread, &process->lock);
 
-      if (status == F_signal) {
-        return status;
+      if (status_lock == F_signal) {
+        return status_lock;
       }
 
       if (!main.thread->enabled) {
@@ -1239,7 +1243,7 @@ extern "C" {
         controller_error_print(main.data->error, F_status_set_fine(status), "fll_execute_program", F_true, main.thread);
       }
 
-      controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+      controller_print_unlock_flush(main.data->error.to.stream, &main.thread->lock.print);
 
       return F_status_set_error(status);
     }
@@ -1405,7 +1409,7 @@ extern "C" {
 
           controller_rule_error_print_cache(main.data->warning, cache->action, F_true);
 
-          controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+          controller_print_unlock_flush(main.data->warning.to.stream, &main.thread->lock.print);
         }
 
         continue;
@@ -1424,7 +1428,7 @@ extern "C" {
             fprintf(main.data->error.to.stream, "%s", main.data->error.notable.after->string);
             fprintf(main.data->error.to.stream, "%s'.%s%c", main.data->error.context.before->string, main.data->error.context.after->string, f_string_eol_s[0]);
 
-            controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+            controller_print_unlock_flush(main.data->error.to.stream, &main.thread->lock.print);
           }
 
           status = F_status_set_error(F_supported_not);
@@ -1626,13 +1630,14 @@ extern "C" {
 
           controller_rule_error_print_cache(main.data->error, process->cache.action, F_true);
 
-          controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+          controller_print_unlock_flush(main.data->error.to.stream, &main.thread->lock.print);
         }
 
         return F_status_set_error(F_parameter);
     }
 
     f_status_t status = F_none;
+    f_status_t status_lock = F_none;
 
     process->cache.action.name_action.used = 0;
     process->cache.action.name_item.used = 0;
@@ -1752,7 +1757,7 @@ extern "C" {
               controller_rule_item_error_print_need_want_wish(main.data->error, strings[i], dynamics[i]->array[j].string, "was not found");
               controller_rule_error_print_cache(main.data->error, process->cache.action, F_true);
 
-              controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+              controller_print_unlock_flush(main.data->error.to.stream, &main.thread->lock.print);
 
               status = F_status_set_error(F_found_not);
 
@@ -1773,7 +1778,7 @@ extern "C" {
                 controller_rule_item_error_print_need_want_wish(main.data->warning, strings[i], dynamics[i]->array[j].string, "was not found");
                 controller_rule_error_print_cache(main.data->warning, process->cache.action, F_true);
 
-                controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+                controller_print_unlock_flush(main.data->warning.to.stream, &main.thread->lock.print);
               }
             }
           }
@@ -1839,7 +1844,7 @@ extern "C" {
                     controller_rule_item_error_print_need_want_wish(main.data->error, strings[i], alias_other_buffer, "failed during execution");
                     controller_rule_error_print_cache(main.data->error, process->cache.action, F_true);
 
-                    controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+                    controller_print_unlock_flush(main.data->error.to.stream, &main.thread->lock.print);
 
                     if (!(process_other->options & controller_rule_option_simulate) || F_status_set_fine(status) == F_memory_not) {
                       f_thread_unlock(&process_other->active);
@@ -1854,7 +1859,7 @@ extern "C" {
                       controller_rule_item_error_print_need_want_wish(main.data->warning, strings[i], alias_other_buffer, "failed during execution");
                       controller_rule_error_print_cache(main.data->warning, process->cache.action, F_true);
 
-                      controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+                      controller_print_unlock_flush(main.data->warning.to.stream, &main.thread->lock.print);
                     }
                   }
                 }
@@ -1882,7 +1887,7 @@ extern "C" {
                 status = F_status_set_error(F_found_not);
                 controller_rule_error_print_cache(main.data->error, process->cache.action, F_true);
 
-                controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+                controller_print_unlock_flush(main.data->error.to.stream, &main.thread->lock.print);
 
                 if (!(process_other->options & controller_rule_option_simulate)) {
                   f_thread_unlock(&main.thread->lock.rule);
@@ -1901,7 +1906,7 @@ extern "C" {
                   controller_rule_item_error_print_need_want_wish(main.data->warning, strings[i], alias_other_buffer, "is in a failed state");
                   controller_rule_error_print_cache(main.data->warning, process->cache.action, F_true);
 
-                  controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+                  controller_print_unlock_flush(main.data->warning.to.stream, &main.thread->lock.print);
                 }
               }
             }
@@ -1975,7 +1980,7 @@ extern "C" {
 
             controller_rule_error_print_cache(main.data->error, process->cache.action, F_true);
 
-            controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+            controller_print_unlock_flush(main.data->error.to.stream, &main.thread->lock.print);
           }
 
           status = F_status_set_error(F_parameter);
@@ -2003,12 +2008,12 @@ extern "C" {
 
     f_thread_unlock(&process->lock);
 
-    status = controller_lock_write(main.thread, &process->lock);
+    status_lock = controller_lock_write(main.thread, &process->lock);
 
-    if (status == F_signal) {
+    if (status_lock == F_signal) {
       f_thread_lock_read(&process->lock);
 
-      return status;
+      return status_lock;
     }
 
     if (!main.thread->enabled) {
@@ -2025,13 +2030,13 @@ extern "C" {
       process->rule.status = status;
     }
 
-    status = controller_lock_write(main.thread, &main.thread->lock.rule);
+    status_lock = controller_lock_write(main.thread, &main.thread->lock.rule);
 
-    if (status == F_signal) {
+    if (status_lock == F_signal) {
       f_thread_unlock(&process->lock);
       f_thread_lock_read(&process->lock);
 
-      return status;
+      return status_lock;
     }
 
     if (!main.thread->enabled) {
@@ -2105,7 +2110,7 @@ extern "C" {
           controller_rule_item_error_print_rule_not_loaded(main.data->error, alias_rule.string);
           controller_rule_error_print_cache(main.data->error, cache.action, F_false);
 
-          controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+          controller_print_unlock_flush(main.data->error.to.stream, &main.thread->lock.print);
         }
 
         return status;
@@ -2285,6 +2290,8 @@ extern "C" {
     }
 
     f_status_t status = F_none;
+    f_status_t status_lock = F_none;
+
     f_array_length_t id_rule = 0;
 
     const f_array_length_t used_original_stack = process->stack.used;
@@ -2295,14 +2302,14 @@ extern "C" {
 
       f_thread_unlock(&process->lock);
 
-      status = controller_lock_write(main.thread, &process->lock);
+      status_lock = controller_lock_write(main.thread, &process->lock);
 
-      if (status == F_signal) {
+      if (status_lock == F_signal) {
         if (options & controller_process_option_asynchronous) {
           f_thread_unlock(&process->active);
         }
 
-        return status;
+        return status_lock;
       }
 
       if (!main.thread->enabled) {
@@ -2341,7 +2348,7 @@ extern "C" {
 
               controller_rule_error_print_cache(main.data->error, process->cache.action, F_true);
 
-              controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+              controller_print_unlock_flush(main.data->error.to.stream, &main.thread->lock.print);
             }
 
             // never continue on circular recursion errors even in simulate mode.
@@ -2370,14 +2377,14 @@ extern "C" {
           else {
             f_thread_unlock(&process->lock);
 
-            status = controller_lock_write(main.thread, &process->lock);
+            status_lock = controller_lock_write(main.thread, &process->lock);
 
-            if (status == F_signal) {
+            if (status_lock == F_signal) {
               if (options & controller_process_option_asynchronous) {
                 f_thread_unlock(&process->active);
               }
 
-              return status;
+              return status_lock;
             }
 
             if (!main.thread->enabled) {
@@ -2401,14 +2408,14 @@ extern "C" {
       if (F_status_is_error(status)) {
         f_thread_unlock(&main.thread->lock.rule);
 
-        status = controller_lock_write(main.thread, &main.thread->lock.rule);
+        status_lock = controller_lock_write(main.thread, &main.thread->lock.rule);
 
-        if (status == F_signal) {
+        if (status_lock == F_signal) {
           if (options & controller_process_option_asynchronous) {
             f_thread_unlock(&process->active);
           }
 
-          return status;
+          return status_lock;
         }
 
         if (!main.thread->enabled) {
@@ -2436,14 +2443,14 @@ extern "C" {
     else {
       f_thread_unlock(&main.thread->lock.rule);
 
-      status = controller_lock_write(main.thread, &main.thread->lock.rule);
+      status_lock = controller_lock_write(main.thread, &main.thread->lock.rule);
 
-      if (status == F_signal) {
+      if (status_lock == F_signal) {
         if (options & controller_process_option_asynchronous) {
           f_thread_unlock(&process->active);
         }
 
-        return status;
+        return status_lock;
       }
 
       if (!main.thread->enabled) {
@@ -2470,7 +2477,7 @@ extern "C" {
         controller_rule_item_error_print_rule_not_loaded(main.data->error, process->rule.alias.string);
         controller_rule_error_print_cache(main.data->error, process->cache.action, F_false);
 
-        controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+        controller_print_unlock_flush(main.data->error.to.stream, &main.thread->lock.print);
       }
     }
 
@@ -2488,14 +2495,14 @@ extern "C" {
       return status;
     }
 
-    status = controller_lock_write(main.thread, &process->lock);
+    status_lock = controller_lock_write(main.thread, &process->lock);
 
-    if (status == F_signal) {
+    if (status_lock == F_signal) {
       if (options & controller_process_option_asynchronous) {
         f_thread_unlock(&process->active);
       }
 
-      return status;
+      return status_lock;
     }
 
     if (!main.thread->enabled) {
@@ -2934,7 +2941,7 @@ extern "C" {
 
           controller_rule_error_print_cache(main.data->warning, cache->action, F_false);
 
-          controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+          controller_print_unlock_flush(main.data->warning.to.stream, &main.thread->lock.print);
         }
 
         continue;
@@ -2955,7 +2962,7 @@ extern "C" {
 
           controller_rule_error_print_cache(main.data->warning, cache->action, F_false);
 
-          controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+          controller_print_unlock_flush(main.data->warning.to.stream, &main.thread->lock.print);
         }
 
         continue;
@@ -3018,7 +3025,7 @@ extern "C" {
 
             controller_rule_error_print_cache(main.data->error, cache->action, F_false);
 
-            controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+            controller_print_unlock_flush(main.data->error.to.stream, &main.thread->lock.print);
           }
 
           if (F_status_is_error_not(status_return)) {
@@ -3074,7 +3081,7 @@ extern "C" {
                   f_print_dynamic_partial(main.data->error.to.stream, cache->buffer_item, cache->content_actions.array[i].array[j]);
                   fprintf(main.data->error.to.stream, "%s%s', the number is too large for this system.%s%c", main.data->error.notable.after->string, main.data->error.context.before->string, main.data->error.context.after->string, f_string_eol_s[0]);
 
-                  controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+                  controller_print_unlock_flush(main.data->error.to.stream, &main.thread->lock.print);
                 }
                 else {
                   f_thread_mutex_lock(&main.thread->lock.print);
@@ -3085,7 +3092,7 @@ extern "C" {
                   f_print_dynamic_partial(main.data->error.to.stream, cache->buffer_item, cache->content_actions.array[i].array[j]);
                   fprintf(main.data->error.to.stream, "%s%s', only whole numbers are allowed for an affinity value.%s%c", main.data->error.notable.after->string, main.data->error.context.before->string, main.data->error.context.after->string, f_string_eol_s[0]);
 
-                  controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+                  controller_print_unlock_flush(main.data->error.to.stream, &main.thread->lock.print);
                 }
 
                 // get the current line number within the settings item.
@@ -3140,7 +3147,7 @@ extern "C" {
 
             controller_rule_error_print_cache(main.data->error, cache->action, F_false);
 
-            controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+            controller_print_unlock_flush(main.data->error.to.stream, &main.thread->lock.print);
           }
 
           if (F_status_is_error_not(status_return)) {
@@ -3265,7 +3272,7 @@ extern "C" {
 
             controller_rule_error_print_cache(main.data->error, cache->action, F_false);
 
-            controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+            controller_print_unlock_flush(main.data->error.to.stream, &main.thread->lock.print);
           }
 
           if (F_status_is_error_not(status_return)) {
@@ -3299,7 +3306,7 @@ extern "C" {
 
             controller_rule_error_print_cache(main.data->error, cache->action, F_false);
 
-            controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+            controller_print_unlock_flush(main.data->error.to.stream, &main.thread->lock.print);
           }
 
           if (F_status_is_error_not(status_return)) {
@@ -3386,7 +3393,7 @@ extern "C" {
 
             controller_rule_error_print_cache(main.data->error, cache->action, F_false);
 
-            controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+            controller_print_unlock_flush(main.data->error.to.stream, &main.thread->lock.print);
           }
 
           if (F_status_is_error_not(status_return)) {
@@ -3463,7 +3470,7 @@ extern "C" {
 
             controller_rule_error_print_cache(main.data->error, cache->action, F_true);
 
-            controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+            controller_print_unlock_flush(main.data->error.to.stream, &main.thread->lock.print);
           }
 
           if (F_status_is_error_not(status_return)) {
@@ -3491,7 +3498,7 @@ extern "C" {
 
               controller_rule_error_print_cache(main.data->error, cache->action, F_false);
 
-              controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+              controller_print_unlock_flush(main.data->error.to.stream, &main.thread->lock.print);
             }
 
             status = F_status_set_error(F_valid_not);
@@ -3566,7 +3573,7 @@ extern "C" {
 
                 controller_rule_error_print_cache(main.data->error, cache->action, F_false);
 
-                controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+                controller_print_unlock_flush(main.data->error.to.stream, &main.thread->lock.print);
               }
 
               status = F_status_set_error(F_valid_not);
@@ -3630,7 +3637,7 @@ extern "C" {
 
             controller_rule_error_print_cache(main.data->error, cache->action, F_false);
 
-            controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+            controller_print_unlock_flush(main.data->error.to.stream, &main.thread->lock.print);
           }
 
           if (F_status_is_error_not(status_return)) {
@@ -3690,7 +3697,7 @@ extern "C" {
 
                   controller_rule_error_print_cache(main.data->error, cache->action, F_false);
 
-                  controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+                  controller_print_unlock_flush(main.data->error.to.stream, &main.thread->lock.print);
                 }
 
                 if (F_status_is_error_not(status_return)) {
@@ -3703,7 +3710,7 @@ extern "C" {
                 // this function should only return F_complete_not_utf on error.
                 controller_rule_error_print(main.data->error, cache->action, F_complete_not_utf, "controller_validate_has_graph", F_true, F_false, main.thread);
 
-                controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+                controller_print_unlock_flush(main.data->error.to.stream, &main.thread->lock.print);
 
                 if (F_status_is_error_not(status_return)) {
                   status_return = status;
@@ -3782,7 +3789,7 @@ extern "C" {
 
             controller_rule_error_print_cache(main.data->error, cache->action, F_false);
 
-            controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+            controller_print_unlock_flush(main.data->error.to.stream, &main.thread->lock.print);
           }
 
           if (F_status_is_error_not(status_return)) {
@@ -3834,7 +3841,7 @@ extern "C" {
 
             controller_rule_error_print_cache(main.data->error, cache->action, F_false);
 
-            controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+            controller_print_unlock_flush(main.data->error.to.stream, &main.thread->lock.print);
           }
 
           if (F_status_is_error_not(status_return)) {
@@ -3887,7 +3894,7 @@ extern "C" {
 
                 controller_rule_error_print_cache(main.data->error, cache->action, F_false);
 
-                controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+                controller_print_unlock_flush(main.data->error.to.stream, &main.thread->lock.print);
               }
 
               if (F_status_is_error_not(status_return)) {
@@ -3932,7 +3939,7 @@ extern "C" {
 
             controller_rule_error_print_cache(main.data->error, cache->action, F_false);
 
-            controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+            controller_print_unlock_flush(main.data->error.to.stream, &main.thread->lock.print);
           }
 
           if (F_status_is_error_not(status_return)) {
@@ -3960,7 +3967,7 @@ extern "C" {
 
             controller_rule_error_print_cache(main.data->error, cache->action, F_false);
 
-            controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+            controller_print_unlock_flush(main.data->error.to.stream, &main.thread->lock.print);
 
             if (F_status_set_fine(status) == F_memory_not) {
               status_return = status;
@@ -3987,7 +3994,7 @@ extern "C" {
 
             controller_rule_error_print_cache(main.data->error, cache->action, F_false);
 
-            controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+            controller_print_unlock_flush(main.data->error.to.stream, &main.thread->lock.print);
 
             if (F_status_set_fine(status) == F_memory_not) {
               status_return = status;
@@ -4015,7 +4022,7 @@ extern "C" {
 
               controller_rule_error_print_cache(main.data->error, cache->action, F_false);
 
-              controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+              controller_print_unlock_flush(main.data->error.to.stream, &main.thread->lock.print);
 
               status_return = status;
               break;
@@ -4035,7 +4042,7 @@ extern "C" {
 
               controller_rule_error_print_cache(main.data->error, cache->action, F_false);
 
-              controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+              controller_print_unlock_flush(main.data->error.to.stream, &main.thread->lock.print);
             }
 
             if (F_status_is_error_not(status_return)) {
@@ -4076,7 +4083,7 @@ extern "C" {
 
                 controller_rule_error_print_cache(main.data->error, cache->action, F_false);
 
-                controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+                controller_print_unlock_flush(main.data->error.to.stream, &main.thread->lock.print);
               }
 
               if (F_status_is_error_not(status_return)) {
@@ -4116,7 +4123,7 @@ extern "C" {
                 fprintf(main.data->error.to.stream, "%s", main.data->error.notable.after->string);
                 fprintf(main.data->error.to.stream, "%s' because no user was found by that name.%s%c", main.data->error.context.before->string, main.data->error.context.after->string, f_string_eol_s[0]);
 
-                controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+                controller_print_unlock_flush(main.data->error.to.stream, &main.thread->lock.print);
               }
             }
             else if (status == F_number_too_large) {
@@ -4130,7 +4137,7 @@ extern "C" {
                 fprintf(main.data->error.to.stream, "%s", main.data->error.notable.after->string);
                 fprintf(main.data->error.to.stream, "%s' because the given ID is too large.%s%c", main.data->error.context.before->string, main.data->error.context.after->string, f_string_eol_s[0]);
 
-                controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+                controller_print_unlock_flush(main.data->error.to.stream, &main.thread->lock.print);
               }
             }
             else if (status == F_number) {
@@ -4144,7 +4151,7 @@ extern "C" {
                 fprintf(main.data->error.to.stream, "%s", main.data->error.notable.after->string);
                 fprintf(main.data->error.to.stream, "%s' because the given ID is not a valid supported number.%s%c", main.data->error.context.before->string, main.data->error.context.after->string, f_string_eol_s[0]);
 
-                controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+                controller_print_unlock_flush(main.data->error.to.stream, &main.thread->lock.print);
               }
             }
             else {
@@ -4188,7 +4195,7 @@ extern "C" {
 
             controller_rule_error_print_cache(main.data->error, cache->action, F_false);
 
-            controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+            controller_print_unlock_flush(main.data->error.to.stream, &main.thread->lock.print);
           }
 
           if (F_status_is_error_not(status_return)) {
@@ -4245,7 +4252,7 @@ extern "C" {
                 fprintf(main.data->error.to.stream, "%s", main.data->error.notable.after->string);
                 fprintf(main.data->error.to.stream, "%s' because no group was found by that name.%s%c", main.data->error.context.before->string, main.data->error.context.after->string, f_string_eol_s[0]);
 
-                controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+                controller_print_unlock_flush(main.data->error.to.stream, &main.thread->lock.print);
               }
             }
             else if (status == F_number_too_large) {
@@ -4259,7 +4266,7 @@ extern "C" {
                 fprintf(main.data->error.to.stream, "%s", main.data->error.notable.after->string);
                 fprintf(main.data->error.to.stream, "%s' because the given ID is too large.%s%c", main.data->error.context.before->string, main.data->error.context.after->string, f_string_eol_s[0]);
 
-                controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+                controller_print_unlock_flush(main.data->error.to.stream, &main.thread->lock.print);
               }
             }
             else if (status == F_number) {
@@ -4273,7 +4280,7 @@ extern "C" {
                 fprintf(main.data->error.to.stream, "%s", main.data->error.notable.after->string);
                 fprintf(main.data->error.to.stream, "%s' because the given ID is not a valid supported number.%s%c", main.data->error.context.before->string, main.data->error.context.after->string, f_string_eol_s[0]);
 
-                controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+                controller_print_unlock_flush(main.data->error.to.stream, &main.thread->lock.print);
               }
             }
             else {
@@ -4395,7 +4402,7 @@ extern "C" {
 
                 controller_rule_error_print_cache(main.data->error, cache->action, F_false);
 
-                controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+                controller_print_unlock_flush(main.data->error.to.stream, &main.thread->lock.print);
               }
 
               if (F_status_is_error_not(status_return)) {
@@ -4447,7 +4454,7 @@ extern "C" {
 
           controller_rule_error_print_cache(main.data->error, cache->action, F_false);
 
-          controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+          controller_print_unlock_flush(main.data->error.to.stream, &main.thread->lock.print);
         }
 
         if (F_status_is_error_not(status_return)) {
@@ -4554,7 +4561,7 @@ extern "C" {
           fprintf(main.data->error.to.stream, "%s", main.data->error.notable.after->string);
           fprintf(main.data->error.to.stream, "%s'.%s%c", main.data->error.context.before->string, main.data->error.context.after->string, f_string_eol_s[0]);
 
-          controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
+          controller_print_unlock_flush(main.data->error.to.stream, &main.thread->lock.print);
         }
 
         setting_values->array[setting_values->used].used = 0;
@@ -4603,7 +4610,7 @@ extern "C" {
           controller_rule_error_print_cache(data->error, cache->action, F_true);
         }
 
-        controller_print_unlock_flush(data->output.stream, &main.thread->lock.print);
+        controller_print_unlock_flush(data->error.to.stream, &main.thread->lock.print);
 
         return;
     }
index c9bce23f4468e2b0ddbda703566cfdee569c7209..349faf911723ef19ba9cb1814d94ba5c49a6ea21 100644 (file)
@@ -486,10 +486,27 @@ extern "C" {
           *status = F_status_set_error(F_available_not);
         }
         else {
-          *status = controller_process_entry(*entry->main, cache);
+          *status = controller_process_entry(F_false, entry->main, cache);
 
           if (F_status_is_error(*status)) {
             entry->setting->ready = controller_setting_ready_fail;
+
+            if (F_status_set_fine(*status) == F_require && entry->main->setting->failsafe_enabled) {
+              const f_status_t status_failsafe = controller_process_entry(F_true, entry->main, cache);
+
+              if (F_status_is_error(status_failsafe)) {
+                if (data->error.verbosity != f_console_verbosity_quiet) {
+                  f_thread_mutex_lock(&entry->main->thread->lock.print);
+
+                  fprintf(data->error.to.stream, "%c", f_string_eol_s[0]);
+                  fprintf(data->error.to.stream, "%s%sFailed while processing requested failsafe item '", data->error.context.before->string, data->error.prefix ? data->error.prefix : f_string_empty_s);
+                  fprintf(data->error.to.stream, "%s%s%s%s", data->error.context.after->string, data->error.notable.before->string, entry->main->setting->entry.items.array[entry->main->setting->failsafe_enabled].name.string, data->error.notable.after->string);
+                  fprintf(data->error.to.stream, "%s'.%s%c", data->error.context.before->string, data->error.context.after->string, f_string_eol_s[0]);
+
+                  controller_print_unlock_flush(data->error.to.stream, &entry->main->thread->lock.print);
+                }
+              }
+            }
           }
           else if (*status == F_signal || *status == F_child) {
             entry->setting->ready = controller_setting_ready_abort;
index 2efd90816b9dbd5565e4cc56b83ef7df3001a68a..6576bd6ab3e14d585866b46039f4ce4e0cdac130 100644 (file)
@@ -21,7 +21,7 @@ first:
   #rule script python
 
 last:
-  rule script fail
+  rule script fail require wait
 
 boom:
   rule maintenance explode
index 059a7f7e923da980184fc68aecb36896cf699375..560bd7867db264d812200ed699ab2cbfc4fde98b 100644 (file)
@@ -8,7 +8,7 @@ script:
   start {
     \#!/bin/bash
     my_function() {
-      echo "Hello this is the last script."
+      echo "Hello this is the last script, it should trigger failure."
       return 1;
     \}