]> Kevux Git Server - fll/commitdiff
Progress: controller program, featureless make tweaks, and execute cleanup.
authorKevin Day <thekevinday@gmail.com>
Thu, 17 Dec 2020 05:40:42 +0000 (23:40 -0600)
committerKevin Day <thekevinday@gmail.com>
Thu, 17 Dec 2020 05:40:42 +0000 (23:40 -0600)
I am going to be using controller program to codestorm how I want the execute functions to handle forking with child.
I may simplify the "pipe" arguments to only accept an input pipe and then write a execute fork functions that perform the fork and return to the caller so that the caller fully handles everything.
This would allow for the "non-fork" (as in "fork" is not in the function names) functions to only focus on simple executions.
This could then make way for the asynchronous behavior that is planned.

15 files changed:
level_0/f_execute/c/execute-common.h
level_3/controller/c/controller.c
level_3/controller/c/controller.h
level_3/controller/c/main.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-rule.h
level_3/controller/data/build/dependencies
level_3/controller/data/build/settings
level_3/controller/documents/entry.txt
level_3/fake/c/fake.h
level_3/fake/c/main.c

index cbd291b9c0775bede3db871ba2b0bfa5ba27ef31..b2201d119591dfd407d615e5861193f3b3b048ee 100644 (file)
@@ -17,7 +17,7 @@ extern "C" {
 #endif
 
 /**
- * A set containing the three standard descriptors for use in pipes.
+ * A set containing the standard descriptors for use in pipes during the execution process.
  *
  * Future versions may suppot stdwarn and stddebug if there ever is such a thing.
  *
index a79552429446692017b731c35b7d970a6d1bffdf..fc659835c8f4007bcd36df283a1e682cc5b69a9f 100644 (file)
@@ -273,7 +273,9 @@ extern "C" {
         if (f_file_exists(setting.path_pid.string) == F_true) {
           if (data->error.verbosity != f_console_verbosity_quiet) {
             fprintf(data->error.to.stream, "%c", f_string_eol_s[0]);
-            fprintf(data->error.to.stream, "%s%sThe pid file must not already exist.%s%c", data->error.context.before->string, data->error.prefix ? data->error.prefix : f_string_empty_s, data->error.context.after->string, f_string_eol_s[0]);
+            fprintf(data->error.to.stream, "%s%sThe pid file '", 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, setting.path_pid.string, data->error.notable.after->string);
+            fprintf(data->error.to.stream, "%s' must not already exist.%s%c", data->error.context.before->string, data->error.context.after->string, f_string_eol_s[0]);
           }
 
           status = F_status_set_error(F_available_not);
@@ -302,7 +304,9 @@ extern "C" {
           if (f_file_exists(setting.path_pid.string) == F_true) {
             if (data->error.verbosity != f_console_verbosity_quiet) {
               fprintf(data->error.to.stream, "%c", f_string_eol_s[0]);
-              fprintf(data->error.to.stream, "%s%sThe pid file must not already exist.%s%c", data->error.context.before->string, data->error.prefix ? data->error.prefix : f_string_empty_s, data->error.context.after->string, f_string_eol_s[0]);
+              fprintf(data->error.to.stream, "%s%sThe pid file '", 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, setting.path_pid.string, data->error.notable.after->string);
+              fprintf(data->error.to.stream, "%s' must not already exist.%s%c", data->error.context.before->string, data->error.context.after->string, f_string_eol_s[0]);
             }
 
             status = F_status_set_error(F_available_not);
@@ -310,25 +314,27 @@ extern "C" {
           }
 
           if (F_status_is_error_not(status)) {
-            status = controller_process_entry(*data, &setting, &cache);
+            status = controller_process_entry(data, &setting, &cache);
           }
 
-          if (F_status_is_error(status)) {
-            setting.ready = controller_setting_ready_fail;
-          }
-          else {
-            setting.ready = controller_setting_ready_done;
+          if (!(status == F_child || status == F_signal)) {
+            if (F_status_is_error(status)) {
+              setting.ready = controller_setting_ready_fail;
+            }
+            else {
+              setting.ready = controller_setting_ready_done;
 
-            // @todo wait here until told to quit, listening for "control" commands (and listening for signals).
-            // @todo clear cache periodically while waiting.
-            // controller_macro_cache_t_delete_simple(cache);
+              // @todo wait here until told to quit, listening for "control" commands (and listening for signals).
+              // @todo clear cache periodically while waiting.
+              // controller_macro_cache_t_delete_simple(cache);
+            }
           }
         }
       }
     }
 
     // ensure a newline is always put at the end of the program execution, unless in quiet mode.
-    if (data->error.verbosity != f_console_verbosity_quiet) {
+    if (!(status == F_child || status == F_signal) && data->error.verbosity != f_console_verbosity_quiet) {
       if (F_status_is_error(status)) {
         fprintf(data->error.to.stream, "%c", f_string_eol_s[0]);
       }
@@ -341,6 +347,10 @@ extern "C" {
 
     controller_delete_data(data);
 
+    if (status == F_child || status == F_signal) {
+      return status;
+    }
+
     if (setting.ready == controller_setting_ready_fail) {
       // @todo trigger failsafe/fallback execution, if defined.
     }
index da4d165929bc6274b4cd21c41949ddd1adc68db0..559018b5e4095de645b667bfb1216e8da58339f0 100644 (file)
@@ -13,6 +13,9 @@
  *
  * @todo research containers and build in container support into this, providing "container" appropriate verbiage for individual rules.
  * @todo research namespaces and user_namespaces, they may be important to support.
+ *
+ * @todo Implement "exit" files that are the opposite of "entry" files whereas rules specified within are all called via the "stop" action type.
+ *       This would then allow for switching modes.
  */
 #ifndef _controller_h
 
 #include <level_0/color.h>
 #include <level_0/console.h>
 #include <level_0/directory.h>
+#include <level_0/execute.h>
 #include <level_0/file.h>
 #include <level_0/fss.h>
 #include <level_0/path.h>
 #include <level_0/pipe.h>
 #include <level_0/print.h>
+#include <level_0/signal.h>
 
 // fll-1 includes
 #include <level_1/color.h>
@@ -142,12 +147,16 @@ extern "C" {
 
     f_string_lengths_t remaining;
     bool process_pipe;
-    pid_t pid;
 
     f_file_t output;
     fll_error_print_t error;
     fll_error_print_t warning;
 
+    pid_t pid;
+    mode_t umask;
+    int child;
+    f_signal_t signal;
+
     f_color_context_t context;
   } controller_data_t;
 
@@ -156,10 +165,13 @@ extern "C" {
       controller_console_parameter_t_initialize, \
       f_string_lengths_t_initialize, \
       F_false, \
-      0, \
       f_macro_file_t_initialize(f_type_output, f_type_descriptor_output, f_file_flag_write_only), \
       fll_error_print_t_initialize, \
       fll_macro_error_print_t_initialize_warning(), \
+      0, \
+      0, \
+      0, \
+      f_signal_t_initialize, \
       f_color_context_t_initialize, \
     }
 #endif // _di_controller_data_t_
index 9a5eef394de7d9f795cc89f2ab1ee80ff3b3bb57..ec2c9d569d17d519be217cac46cb1fb059de044e 100644 (file)
@@ -3,6 +3,7 @@
 int main(const unsigned long argc, const f_string_t *argv) {
   const f_console_arguments_t arguments = { argc, argv };
   controller_data_t data = controller_data_t_initialize;
+  f_status_t status = F_none;
 
   if (f_pipe_input_exists()) {
     data.process_pipe = F_true;
@@ -10,7 +11,29 @@ int main(const unsigned long argc, const f_string_t *argv) {
 
   data.pid = getpid();
 
-  const f_status_t status = controller_main(arguments, &data);
+  f_signal_set_empty(&data.signal.set);
+  f_signal_set_add(F_signal_abort, &data.signal.set);
+  f_signal_set_add(F_signal_hangup, &data.signal.set);
+  f_signal_set_add(F_signal_interrupt, &data.signal.set);
+  f_signal_set_add(F_signal_quit, &data.signal.set);
+  f_signal_set_add(F_signal_termination, &data.signal.set);
+  f_signal_set_handle(SIG_BLOCK, &data.signal.set);
+
+  status = f_signal_open(&data.signal);
+
+  // if there is an error opening a signal descriptor, then do not handle signals.
+  if (F_status_is_error(status)) {
+    f_signal_set_handle(SIG_UNBLOCK, &data.signal.set);
+    f_signal_close(&data.signal);
+  }
+
+  // @fixme: bad design in POSIX where there is no get umask without setting it.
+  data.umask = umask(0);
+
+  // restore umask.
+  umask(data.umask);
+
+  status = controller_main(arguments, &data);
 
   // flush output pipes before closing.
   fflush(f_type_output);
@@ -21,6 +44,12 @@ int main(const unsigned long argc, const f_string_t *argv) {
   close(f_type_descriptor_input);
   close(f_type_descriptor_error);
 
+  f_signal_close(&data.signal);
+
+  if (status == F_child) {
+    exit(data.child);
+  }
+
   if (F_status_is_error(status)) {
     return 1;
   }
index c6a6e7e076c9d35976d84ed93a901f0f0fe60d2c..bd0ec6404408d0a2f56b584f6ce606cc3df98270 100644 (file)
@@ -25,6 +25,7 @@ extern "C" {
   #define controller_string_entry         "entry"
   #define controller_string_entries       "entries"
   #define controller_string_environment   "environment"
+  #define controller_string_fail          "fail"
   #define controller_string_failsafe      "failsafe"
   #define controller_string_group         "group"
   #define controller_string_how           "how"
@@ -35,12 +36,14 @@ extern "C" {
   #define controller_string_name          "name"
   #define controller_string_need          "need"
   #define controller_string_no            "no"
+  #define controller_string_optional      "optional"
   #define controller_string_parameter     "parameter"
   #define controller_string_path          "path"
   #define controller_string_pid           "pid"
   #define controller_string_ready         "ready"
   #define controller_string_reload        "reload"
   #define controller_string_require       "require"
+  #define controller_string_required      "required"
   #define controller_string_restart       "restart"
   #define controller_string_rule          "rule"
   #define controller_string_rules         "rules"
@@ -49,6 +52,7 @@ extern "C" {
   #define controller_string_setting       "setting"
   #define controller_string_start         "start"
   #define controller_string_stop          "stop"
+  #define controller_string_succeed       "succeed"
   #define controller_string_synchronous   "synchronous"
   #define controller_string_timeout       "timeout"
   #define controller_string_type          "type"
@@ -71,6 +75,7 @@ extern "C" {
   #define controller_string_entry_length         5
   #define controller_string_entries_length       7
   #define controller_string_environment_length   11
+  #define controller_string_fail_length          4
   #define controller_string_failsafe_length      8
   #define controller_string_group_length         5
   #define controller_string_how_length           3
@@ -81,12 +86,14 @@ extern "C" {
   #define controller_string_name_length          4
   #define controller_string_need_length          4
   #define controller_string_no_length            2
+  #define controller_string_optional_length      8
   #define controller_string_parameter_length     9
   #define controller_string_path_length          4
   #define controller_string_pid_length           3
   #define controller_string_ready_length         5
   #define controller_string_reload_length        6
   #define controller_string_require_length       7
+  #define controller_string_required_length      8
   #define controller_string_restart_length       7
   #define controller_string_rule_length          4
   #define controller_string_rules_length         5
@@ -95,6 +102,7 @@ extern "C" {
   #define controller_string_setting_length       7
   #define controller_string_start_length         5
   #define controller_string_stop_length          4
+  #define controller_string_succeed_length       7
   #define controller_string_synchronous_length   11
   #define controller_string_timeout_length       7
   #define controller_string_type_length          4
@@ -243,9 +251,10 @@ extern "C" {
     controller_rule_setting_type_wish,
   };
 
-  #define controller_rule_option_simulate     0x1
-  #define controller_rule_option_asynchronous 0x2
-  #define controller_rule_option_wait         0x4
+  #define controller_rule_option_asynchronous 0x1
+  #define controller_rule_option_require      0x2
+  #define controller_rule_option_simulate     0x4
+  #define controller_rule_option_wait         0x8
 
   typedef struct {
     f_status_t status;
index 92221c7e5da57b99ca1af2ca45ab52ab82fa1be9..198211f65a8624e5e6a74f893f61b74585ce08fe 100644 (file)
@@ -161,7 +161,7 @@ extern "C" {
     status = f_file_stream_open(path_pid.string, f_macro_file_open_mode_truncate, &file);
     if (F_status_is_error(status)) return status;
 
-    fprintf(file.stream, "%llu\n", data.pid);
+    fprintf(file.stream, "%llu%c", data.pid, f_string_eol_s[0]);
 
     f_file_stream_close(F_true, &file);
 
@@ -174,6 +174,7 @@ extern "C" {
 #ifndef _di_controller_file_pid_delete_
   void controller_file_pid_delete(const controller_data_t data, const f_string_static_t path_pid) {
 
+    // only delete if the file exists and there is no error while checking.
     if (f_file_exists(path_pid.string) != F_true) {
       return;
     }
@@ -467,7 +468,7 @@ extern "C" {
 #endif // _di_controller_preprocess_entry_
 
 #ifndef _di_controller_process_entry_
-  f_return_status controller_process_entry(const controller_data_t data, controller_setting_t *setting, controller_cache_t *cache) {
+  f_return_status controller_process_entry(controller_data_t *data, controller_setting_t *setting, controller_cache_t *cache) {
     f_status_t status = F_none;
 
     f_array_length_t i = 0;
@@ -481,7 +482,7 @@ extern "C" {
 
     controller_entry_actions_t *actions = 0;
 
-    const bool simulate = data.parameters[controller_parameter_test].result == f_console_result_found;
+    const bool simulate = data->parameters[controller_parameter_test].result == f_console_result_found;
 
     cache->ats.used = 0;
     cache->line_action = 0;
@@ -491,15 +492,15 @@ extern "C" {
     cache->stack.used = 0;
 
     if (setting->ready == controller_setting_ready_yes) {
-      status = controller_perform_ready(data, setting, cache);
+      status = controller_perform_ready(*data, setting, cache);
       if (F_status_is_error(status)) return status;
     }
 
     status = fl_type_array_lengths_increase_by(controller_default_allocation_step, &cache->ats);
 
     if (F_status_is_error(status)) {
-      fll_error_print(data.error, F_status_set_fine(status), "fl_type_array_lengths_increase_by", F_true);
-      controller_entry_error_print(data.error, *cache);
+      fll_error_print(data->error, F_status_set_fine(status), "fl_type_array_lengths_increase_by", F_true);
+      controller_entry_error_print(data->error, *cache);
 
       return status;
     }
@@ -515,17 +516,17 @@ extern "C" {
     status = controller_string_dynamic_append_terminated(setting->entry.items.array[0].name, &cache->name_item);
 
     if (F_status_is_error(status)) {
-      fll_error_print(data.error, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true);
-      controller_entry_error_print(data.error, *cache);
+      fll_error_print(data->error, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true);
+      controller_entry_error_print(data->error, *cache);
 
       return status;
     }
 
     if (simulate) {
-      fprintf(data.output.stream, "%c", f_string_eol_s[0]);
-      fprintf(data.output.stream, "Processing entry item rule '");
-      fprintf(data.output.stream, "%s%s%s", data.context.set.title.before->string, controller_string_main, data.context.set.title.after->string);
-      fprintf(data.output.stream, "'.%c", f_string_eol_s[0]);
+      fprintf(data->output.stream, "%c", f_string_eol_s[0]);
+      fprintf(data->output.stream, "Processing entry item rule '");
+      fprintf(data->output.stream, "%s%s%s", data->context.set.title.before->string, controller_string_main, data->context.set.title.after->string);
+      fprintf(data->output.stream, "'.%c", f_string_eol_s[0]);
     }
 
     for (;;) {
@@ -540,8 +541,8 @@ extern "C" {
         status = controller_string_dynamic_append_terminated(controller_entry_action_type_name(actions->array[cache->ats.array[at_j]].type), &cache->name_action);
 
         if (F_status_is_error(status)) {
-          fll_error_print(data.error, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true);
-          controller_entry_error_print(data.error, *cache);
+          fll_error_print(data->error, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true);
+          controller_entry_error_print(data->error, *cache);
 
           return status;
         }
@@ -551,91 +552,91 @@ extern "C" {
           if (actions->array[cache->ats.array[at_j]].type == controller_entry_action_type_rule) {
 
             if (simulate) {
-              fprintf(data.output.stream, "%c", f_string_eol_s[0]);
-              fprintf(data.output.stream, "The entry item action '");
-              fprintf(data.output.stream, "%s%s%s", data.context.set.title.before->string, cache->name_action.string, data.context.set.title.after->string);
+              fprintf(data->output.stream, "%c", f_string_eol_s[0]);
+              fprintf(data->output.stream, "The entry item action '");
+              fprintf(data->output.stream, "%s%s%s", data->context.set.title.before->string, cache->name_action.string, data->context.set.title.after->string);
 
               if (actions->array[cache->ats.array[at_j]].parameters.used) {
-                fprintf(data.output.stream, " ");
-                fprintf(data.output.stream, "%s", data.context.set.notable.before->string);
-                controller_entry_action_parameters_print(data.output.stream, actions->array[cache->ats.array[at_j]]);
-                fprintf(data.output.stream, "%s", data.context.set.notable.after->string);
+                fprintf(data->output.stream, " ");
+                fprintf(data->output.stream, "%s", data->context.set.notable.before->string);
+                controller_entry_action_parameters_print(data->output.stream, actions->array[cache->ats.array[at_j]]);
+                fprintf(data->output.stream, "%s", data->context.set.notable.after->string);
               }
 
-              fprintf(data.output.stream, "' is %s and is in a %sfailed%s state, skipping execution.%c", actions->array[cache->ats.array[at_j]].code & controller_entry_rule_code_require ? "required" : "optional", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]);
+              fprintf(data->output.stream, "' is %s and is in a %sfailed%s state, skipping execution.%c", actions->array[cache->ats.array[at_j]].code & controller_entry_rule_code_require ? "required" : "optional", data->error.context.before->string, data->error.context.after->string, f_string_eol_s[0]);
             }
             else if (actions->array[cache->ats.array[at_j]].code & controller_entry_rule_code_require) {
 
-              if (data.error.verbosity != f_console_verbosity_quiet) {
-                fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
-                fprintf(data.error.to.stream, "%s%sThe entry item action '", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s);
-                fprintf(data.error.to.stream, "%s%s%s", data.error.context.after->string, data.error.notable.before->string, cache->name_action.string);
+              if (data->error.verbosity != f_console_verbosity_quiet) {
+                fprintf(data->error.to.stream, "%c", f_string_eol_s[0]);
+                fprintf(data->error.to.stream, "%s%sThe entry item action '", data->error.context.before->string, data->error.prefix ? data->error.prefix : f_string_empty_s);
+                fprintf(data->error.to.stream, "%s%s%s", data->error.context.after->string, data->error.notable.before->string, cache->name_action.string);
 
                 if (actions->array[cache->ats.array[at_j]].parameters.used) {
-                  fprintf(data.error.to.stream, " ");
-                  controller_entry_action_parameters_print(data.error.to.stream, actions->array[cache->ats.array[at_j]]);
+                  fprintf(data->error.to.stream, " ");
+                  controller_entry_action_parameters_print(data->error.to.stream, actions->array[cache->ats.array[at_j]]);
                 }
 
-                fprintf(data.error.to.stream, "%s%s' is ", data.error.notable.after->string, data.error.context.before->string);
-                fprintf(data.error.to.stream, "%s%srequired%s", data.error.context.after->string, data.error.notable.before->string, data.error.notable.after->string);
-                fprintf(data.error.to.stream, "%s and is in a ", data.error.context.before->string);
-                fprintf(data.error.to.stream, "%s%sfailed%s", data.error.context.after->string, data.error.notable.before->string, data.error.notable.after->string);
-                fprintf(data.error.to.stream, "%s state, skipping execution.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]);
+                fprintf(data->error.to.stream, "%s%s' is ", data->error.notable.after->string, data->error.context.before->string);
+                fprintf(data->error.to.stream, "%s%srequired%s", data->error.context.after->string, data->error.notable.before->string, data->error.notable.after->string);
+                fprintf(data->error.to.stream, "%s and is in a ", data->error.context.before->string);
+                fprintf(data->error.to.stream, "%s%sfailed%s", data->error.context.after->string, data->error.notable.before->string, data->error.notable.after->string);
+                fprintf(data->error.to.stream, "%s state, skipping execution.%s%c", data->error.context.before->string, data->error.context.after->string, f_string_eol_s[0]);
               }
 
-              controller_entry_error_print(data.error, *cache);
+              controller_entry_error_print(data->error, *cache);
 
               return F_status_is_error(F_require);
             }
-            else if (data.warning.verbosity == f_console_verbosity_debug) {
-              fprintf(data.warning.to.stream, "%c", f_string_eol_s[0]);
-              fprintf(data.warning.to.stream, "%s%sThe entry item action '", data.warning.context.before->string, data.warning.prefix ? data.warning.prefix : f_string_empty_s);
-              fprintf(data.warning.to.stream, "%s%s%s", data.warning.context.after->string, data.warning.notable.before->string, cache->name_action.string);
+            else if (data->warning.verbosity == f_console_verbosity_debug) {
+              fprintf(data->warning.to.stream, "%c", f_string_eol_s[0]);
+              fprintf(data->warning.to.stream, "%s%sThe entry item action '", data->warning.context.before->string, data->warning.prefix ? data->warning.prefix : f_string_empty_s);
+              fprintf(data->warning.to.stream, "%s%s%s", data->warning.context.after->string, data->warning.notable.before->string, cache->name_action.string);
 
               if (actions->array[cache->ats.array[at_j]].parameters.used) {
-                fprintf(data.warning.to.stream, " ");
-                controller_entry_action_parameters_print(data.warning.to.stream, actions->array[cache->ats.array[at_j]]);
+                fprintf(data->warning.to.stream, " ");
+                controller_entry_action_parameters_print(data->warning.to.stream, actions->array[cache->ats.array[at_j]]);
               }
 
-              fprintf(data.warning.to.stream, "%s%s' is ", data.warning.notable.after->string, data.warning.context.before->string);
-              fprintf(data.warning.to.stream, "%s%srequired%s", data.warning.context.after->string, data.warning.notable.before->string, data.warning.notable.after->string);
-              fprintf(data.warning.to.stream, "%s and is in a ", data.warning.context.before->string);
-              fprintf(data.warning.to.stream, "%s%sfailed%s", data.warning.context.after->string, data.warning.notable.before->string, data.warning.notable.after->string);
-              fprintf(data.warning.to.stream, "%s state, skipping execution.%s%c", data.warning.context.before->string, data.warning.context.after->string, f_string_eol_s[0]);
+              fprintf(data->warning.to.stream, "%s%s' is ", data->warning.notable.after->string, data->warning.context.before->string);
+              fprintf(data->warning.to.stream, "%s%srequired%s", data->warning.context.after->string, data->warning.notable.before->string, data->warning.notable.after->string);
+              fprintf(data->warning.to.stream, "%s and is in a ", data->warning.context.before->string);
+              fprintf(data->warning.to.stream, "%s%sfailed%s", data->warning.context.after->string, data->warning.notable.before->string, data->warning.notable.after->string);
+              fprintf(data->warning.to.stream, "%s state, skipping execution.%s%c", data->warning.context.before->string, data->warning.context.after->string, f_string_eol_s[0]);
 
-              controller_entry_error_print(data.warning, *cache);
+              controller_entry_error_print(data->warning, *cache);
             }
           }
           else {
             if (simulate) {
-              fprintf(data.output.stream, "%c", f_string_eol_s[0]);
-              fprintf(data.output.stream, "The entry item action '");
-              fprintf(data.output.stream, "%s%s%s", data.context.set.title.before->string, cache->name_action.string, data.context.set.title.after->string);
+              fprintf(data->output.stream, "%c", f_string_eol_s[0]);
+              fprintf(data->output.stream, "The entry item action '");
+              fprintf(data->output.stream, "%s%s%s", data->context.set.title.before->string, cache->name_action.string, data->context.set.title.after->string);
 
               if (actions->array[cache->ats.array[at_j]].parameters.used) {
-                fprintf(data.output.stream, " ");
-                fprintf(data.output.stream, "%s", data.context.set.notable.before->string);
-                controller_entry_action_parameters_print(data.output.stream, actions->array[cache->ats.array[at_j]]);
-                fprintf(data.output.stream, "%s", data.context.set.notable.after->string);
+                fprintf(data->output.stream, " ");
+                fprintf(data->output.stream, "%s", data->context.set.notable.before->string);
+                controller_entry_action_parameters_print(data->output.stream, actions->array[cache->ats.array[at_j]]);
+                fprintf(data->output.stream, "%s", data->context.set.notable.after->string);
               }
 
-              fprintf(data.output.stream, "' is in a %sfailed%s state, skipping.%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]);
+              fprintf(data->output.stream, "' is in a %sfailed%s state, skipping.%c", data->error.context.before->string, data->error.context.after->string, f_string_eol_s[0]);
             }
-            else if (data.warning.verbosity == f_console_verbosity_debug) {
-              fprintf(data.warning.to.stream, "%c", f_string_eol_s[0]);
-              fprintf(data.warning.to.stream, "%s%sThe entry item action '", data.warning.context.before->string, data.warning.prefix ? data.warning.prefix : f_string_empty_s);
-              fprintf(data.warning.to.stream, "%s%s", data.warning.notable.before->string, cache->name_action.string);
+            else if (data->warning.verbosity == f_console_verbosity_debug) {
+              fprintf(data->warning.to.stream, "%c", f_string_eol_s[0]);
+              fprintf(data->warning.to.stream, "%s%sThe entry item action '", data->warning.context.before->string, data->warning.prefix ? data->warning.prefix : f_string_empty_s);
+              fprintf(data->warning.to.stream, "%s%s", data->warning.notable.before->string, cache->name_action.string);
 
               if (actions->array[cache->ats.array[at_j]].parameters.used) {
-                fprintf(data.warning.to.stream, " ");
-                controller_entry_action_parameters_print(data.warning.to.stream, actions->array[cache->ats.array[at_j]]);
+                fprintf(data->warning.to.stream, " ");
+                controller_entry_action_parameters_print(data->warning.to.stream, actions->array[cache->ats.array[at_j]]);
               }
 
-              fprintf(data.warning.to.stream, "%s' is in a ", data.warning.notable.after->string);
-              fprintf(data.warning.to.stream, "%s%sfailed%s", data.warning.context.after->string, data.warning.notable.before->string, data.warning.notable.after->string);
-              fprintf(data.warning.to.stream, "%s state, skipping.%s%c", data.warning.context.before->string, data.warning.context.after->string, f_string_eol_s[0]);
+              fprintf(data->warning.to.stream, "%s' is in a ", data->warning.notable.after->string);
+              fprintf(data->warning.to.stream, "%s%sfailed%s", data->warning.context.after->string, data->warning.notable.before->string, data->warning.notable.after->string);
+              fprintf(data->warning.to.stream, "%s state, skipping.%s%c", data->warning.context.before->string, data->warning.context.after->string, f_string_eol_s[0]);
 
-              controller_entry_error_print(data.warning, *cache);
+              controller_entry_error_print(data->warning, *cache);
             }
           }
 
@@ -647,23 +648,23 @@ extern "C" {
           if (setting->ready == controller_setting_ready_wait) {
 
             if (simulate) {
-              fprintf(data.output.stream, "%c", f_string_eol_s[0]);
-              fprintf(data.output.stream, "Processing entry item action '");
-              fprintf(data.output.stream, "%s%s%s", data.context.set.title.before->string, controller_string_ready, data.context.set.title.after->string);
-              fprintf(data.output.stream, "'.%c", f_string_eol_s[0]);
+              fprintf(data->output.stream, "%c", f_string_eol_s[0]);
+              fprintf(data->output.stream, "Processing entry item action '");
+              fprintf(data->output.stream, "%s%s%s", data->context.set.title.before->string, controller_string_ready, data->context.set.title.after->string);
+              fprintf(data->output.stream, "'.%c", f_string_eol_s[0]);
             }
             else {
-              controller_perform_ready(data, setting, cache);
+              controller_perform_ready(*data, setting, cache);
               if (F_status_is_error(status)) return status;
             }
 
             setting->ready = controller_setting_ready_yes;
           }
           else if (simulate) {
-            fprintf(data.output.stream, "%c", f_string_eol_s[0]);
-            fprintf(data.output.stream, "Ignoring entry item action '");
-            fprintf(data.output.stream, "%s%s%s", data.context.set.title.before->string, controller_string_ready, data.context.set.title.after->string);
-            fprintf(data.output.stream, "', state already is ready.%c", f_string_eol_s[0]);
+            fprintf(data->output.stream, "%c", f_string_eol_s[0]);
+            fprintf(data->output.stream, "Ignoring entry item action '");
+            fprintf(data->output.stream, "%s%s%s", data->context.set.title.before->string, controller_string_ready, data->context.set.title.after->string);
+            fprintf(data->output.stream, "', state already is ready.%c", f_string_eol_s[0]);
           }
         }
         else if (actions->array[cache->ats.array[at_j]].type == controller_entry_action_type_item) {
@@ -671,14 +672,14 @@ extern "C" {
           if (actions->array[cache->ats.array[at_j]].number == 0 || actions->array[cache->ats.array[at_j]].number >= 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 (data.error.verbosity != f_console_verbosity_quiet) {
-              fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
-              fprintf(data.error.to.stream, "%s%sInvalid entry item index ", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s);
-              fprintf(data.error.to.stream, "%s%s%llu%s", data.error.context.after->string, data.error.notable.before->string, actions->array[cache->ats.array[at_j]].number, data.error.notable.after->string);
-              fprintf(data.error.to.stream, "%s detected.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]);
+            if (data->error.verbosity != f_console_verbosity_quiet) {
+              fprintf(data->error.to.stream, "%c", f_string_eol_s[0]);
+              fprintf(data->error.to.stream, "%s%sInvalid entry item index ", data->error.context.before->string, data->error.prefix ? data->error.prefix : f_string_empty_s);
+              fprintf(data->error.to.stream, "%s%s%llu%s", data->error.context.after->string, data->error.notable.before->string, actions->array[cache->ats.array[at_j]].number, data->error.notable.after->string);
+              fprintf(data->error.to.stream, "%s detected.%s%c", data->error.context.before->string, data->error.context.after->string, f_string_eol_s[0]);
             }
 
-            controller_entry_error_print(data.error, *cache);
+            controller_entry_error_print(data->error, *cache);
 
             return F_status_is_error(F_critical);
           }
@@ -686,8 +687,8 @@ extern "C" {
           status = fl_type_array_lengths_increase_by(controller_default_allocation_step, &cache->ats);
 
           if (F_status_is_error(status)) {
-            fll_error_print(data.error, F_status_set_fine(status), "fl_type_array_lengths_increase_by", F_true);
-            controller_entry_error_print(data.error, *cache);
+            fll_error_print(data->error, F_status_set_fine(status), "fl_type_array_lengths_increase_by", F_true);
+            controller_entry_error_print(data->error, *cache);
 
             return status;
           }
@@ -710,17 +711,17 @@ extern "C" {
           status = controller_string_dynamic_append_terminated(setting->entry.items.array[cache->ats.array[at_i]].name, &cache->name_item);
 
           if (F_status_is_error(status)) {
-            fll_error_print(data.error, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true);
-            controller_entry_error_print(data.error, *cache);
+            fll_error_print(data->error, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true);
+            controller_entry_error_print(data->error, *cache);
 
             return status;
           }
 
           if (simulate) {
-            fprintf(data.output.stream, "%c", f_string_eol_s[0]);
-            fprintf(data.output.stream, "Processing entry item '");
-            fprintf(data.output.stream, "%s%s%s", data.context.set.title.before->string, cache->name_item.string, data.context.set.title.after->string);
-            fprintf(data.output.stream, "'.%c", f_string_eol_s[0]);
+            fprintf(data->output.stream, "%c", f_string_eol_s[0]);
+            fprintf(data->output.stream, "Processing entry item '");
+            fprintf(data->output.stream, "%s%s%s", data->context.set.title.before->string, cache->name_item.string, data->context.set.title.after->string);
+            fprintf(data->output.stream, "'.%c", f_string_eol_s[0]);
           }
 
           // exit inner loop to force restarting and start processing the requested item.
@@ -731,8 +732,8 @@ extern "C" {
           status = controller_rules_increase(&setting->rules);
 
           if (F_status_is_error(status)) {
-            fll_error_print(data.error, F_status_set_fine(status), "controller_rules_increase", F_true);
-            controller_entry_error_print(data.error, *cache);
+            fll_error_print(data->error, F_status_set_fine(status), "controller_rules_increase", F_true);
+            controller_entry_error_print(data->error, *cache);
 
             return status;
           }
@@ -747,13 +748,13 @@ extern "C" {
           rule_id_name[actions->array[cache->ats.array[at_j]].parameters.array[0].used] = f_path_separator_s[0];
           rule_id_name[rule_id_length] = 0;
 
-          at = controller_rule_find_loaded(data, *setting, rule_id);
+          at = controller_rule_find_loaded(*data, *setting, rule_id);
 
           if (simulate) {
-            fprintf(data.output.stream, "%c", f_string_eol_s[0]);
-            fprintf(data.output.stream, "%s entry item rule '", actions->array[cache->ats.array[at_j]].type == controller_entry_action_type_rule ? "Processing" : "Considering");
-            fprintf(data.output.stream, "%s%s%s", data.context.set.title.before->string, rule_id.string, data.context.set.title.after->string);
-            fprintf(data.output.stream, "'.%c", f_string_eol_s[0]);
+            fprintf(data->output.stream, "%c", f_string_eol_s[0]);
+            fprintf(data->output.stream, "%s entry item rule '", actions->array[cache->ats.array[at_j]].type == controller_entry_action_type_rule ? "Processing" : "Considering");
+            fprintf(data->output.stream, "%s%s%s", data->context.set.title.before->string, rule_id.string, data->context.set.title.after->string);
+            fprintf(data->output.stream, "'.%c", f_string_eol_s[0]);
           }
 
           // the rule is not yet loaded, ensure that it is loaded.
@@ -775,7 +776,7 @@ extern "C" {
             memcpy(cache_name_item, cache->name_item.string, cache->name_item.used);
             memcpy(cache_name_file, cache->name_file.string, cache->name_file.used);
 
-            status = controller_rule_read(data, *setting, rule_id, cache, &setting->rules.array[setting->rules.used]);
+            status = controller_rule_read(*data, *setting, rule_id, cache, &setting->rules.array[setting->rules.used]);
 
             // restore cache.
             memcpy(cache->name_action.string, cache_name_action, cache_name_action_used);
@@ -794,7 +795,7 @@ extern "C" {
             cache->line_item = cache_line_item;
 
             if (F_status_is_error(status)) {
-              controller_entry_error_print(data.error, *cache);
+              controller_entry_error_print(data->error, *cache);
 
               if (!simulate) break;
             }
@@ -832,12 +833,18 @@ extern "C" {
                 rule_options |= controller_rule_option_asynchronous;
               }
 
+              if (actions->array[cache->ats.array[at_j]].code & controller_entry_rule_code_require) {
+                rule_options |= controller_rule_option_require;
+              }
+
               if (actions->array[cache->ats.array[at_j]].code & controller_entry_rule_code_wait) {
                 rule_options |= controller_rule_option_wait;
               }
 
               // @todo: this will also need to support the asynchronous/wait behavior.
-              status = controller_rule_process(data, at, rule_options, setting, cache);
+              status = controller_rule_process(at, controller_rule_action_type_start, rule_options, data, setting, cache);
+
+              if (status == F_child || status == F_signal) break;
             }
 
             // restore cache.
@@ -858,7 +865,7 @@ extern "C" {
           }
 
           if (F_status_is_error(status)) {
-            controller_entry_error_print(data.error, *cache);
+            controller_entry_error_print(data->error, *cache);
 
             if (!simulate || F_status_set_fine(status) == F_memory_not || F_status_set_fine(status) == F_memory_allocation || F_status_set_fine(status) == F_memory_reallocation) {
               break;
@@ -880,14 +887,14 @@ extern "C" {
               code = controller_string_stop;
             }
 
-            fprintf(data.output.stream, "%c", f_string_eol_s[0]);
-            fprintf(data.output.stream, "Processing entry item action '");
-            fprintf(data.output.stream, "%s%s%s", data.context.set.title.before->string, controller_string_timeout, data.context.set.title.after->string);
-            fprintf(data.output.stream, "' setting '");
-            fprintf(data.output.stream, "%s%s%s", data.context.set.important.before->string, code, data.context.set.important.after->string);
-            fprintf(data.output.stream, "' to '");
-            fprintf(data.output.stream, "%s%llu%s", data.context.set.important.before->string, actions->array[cache->ats.array[at_j]].number, data.context.set.important.after->string);
-            fprintf(data.output.stream, "' MegaTime (milliseconds).%c", f_string_eol_s[0]);
+            fprintf(data->output.stream, "%c", f_string_eol_s[0]);
+            fprintf(data->output.stream, "Processing entry item action '");
+            fprintf(data->output.stream, "%s%s%s", data->context.set.title.before->string, controller_string_timeout, data->context.set.title.after->string);
+            fprintf(data->output.stream, "' setting '");
+            fprintf(data->output.stream, "%s%s%s", data->context.set.important.before->string, code, data->context.set.important.after->string);
+            fprintf(data->output.stream, "' to '");
+            fprintf(data->output.stream, "%s%llu%s", data->context.set.important.before->string, actions->array[cache->ats.array[at_j]].number, data->context.set.important.after->string);
+            fprintf(data->output.stream, "' MegaTime (milliseconds).%c", f_string_eol_s[0]);
           }
 
           if (actions->array[cache->ats.array[at_j]].code == controller_entry_timeout_code_kill) {
@@ -905,14 +912,14 @@ extern "C" {
           if (actions->array[cache->ats.array[at_j]].number == 0 || actions->array[cache->ats.array[at_j]].number >= 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 (data.error.verbosity != f_console_verbosity_quiet) {
-              fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
-              fprintf(data.error.to.stream, "%s%sInvalid entry item index ", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s);
-              fprintf(data.error.to.stream, "%s%s%llu%s", data.error.context.after->string, data.error.notable.before->string, actions->array[cache->ats.array[at_j]].number, data.error.notable.after->string);
-              fprintf(data.error.to.stream, "%s detected.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]);
+            if (data->error.verbosity != f_console_verbosity_quiet) {
+              fprintf(data->error.to.stream, "%c", f_string_eol_s[0]);
+              fprintf(data->error.to.stream, "%s%sInvalid entry item index ", data->error.context.before->string, data->error.prefix ? data->error.prefix : f_string_empty_s);
+              fprintf(data->error.to.stream, "%s%s%llu%s", data->error.context.after->string, data->error.notable.before->string, actions->array[cache->ats.array[at_j]].number, data->error.notable.after->string);
+              fprintf(data->error.to.stream, "%s detected.%s%c", data->error.context.before->string, data->error.context.after->string, f_string_eol_s[0]);
             }
 
-            controller_entry_error_print(data.error, *cache);
+            controller_entry_error_print(data->error, *cache);
 
             return F_status_is_error(F_critical);
           }
@@ -921,17 +928,19 @@ extern "C" {
             setting->failsafe_rule_id = actions->array[cache->ats.array[at_j]].number;
 
             if (simulate) {
-              fprintf(data.output.stream, "%c", f_string_eol_s[0]);
-              fprintf(data.output.stream, "Processing entry item action '");
-              fprintf(data.output.stream, "%s%s%s", data.context.set.title.before->string, controller_string_failsafe, data.context.set.title.after->string);
-              fprintf(data.output.stream, "' setting value to '");
-              fprintf(data.output.stream, "%s%s%s", data.context.set.important.before->string, setting->entry.items.array[setting->failsafe_rule_id].name.string, data.context.set.important.after->string);
-              fprintf(data.output.stream, "'.%c", f_string_eol_s[0]);
+              fprintf(data->output.stream, "%c", f_string_eol_s[0]);
+              fprintf(data->output.stream, "Processing entry item action '");
+              fprintf(data->output.stream, "%s%s%s", data->context.set.title.before->string, controller_string_failsafe, data->context.set.title.after->string);
+              fprintf(data->output.stream, "' setting value to '");
+              fprintf(data->output.stream, "%s%s%s", data->context.set.important.before->string, setting->entry.items.array[setting->failsafe_rule_id].name.string, data->context.set.important.after->string);
+              fprintf(data->output.stream, "'.%c", f_string_eol_s[0]);
             }
           }
         }
       } // for
 
+      if (status == F_child || status == F_signal) break;
+
       cache->line_action = 0;
       cache->name_action.used = 0;
 
@@ -959,16 +968,20 @@ extern "C" {
         status = controller_string_dynamic_append_terminated(setting->entry.items.array[cache->ats.array[at_i]].name, &cache->name_item);
 
         if (F_status_is_error(status)) {
-          fll_error_print(data.error, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true);
-          controller_entry_error_print(data.error, *cache);
+          fll_error_print(data->error, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true);
+          controller_entry_error_print(data->error, *cache);
 
           break;
         }
       }
     } // for
 
+    if (status == F_child || status == F_signal) {
+      return status;
+    }
+
     if (F_status_is_error_not(status) && simulate) {
-      fprintf(data.output.stream, "%c", f_string_eol_s[0]);
+      fprintf(data->output.stream, "%c", f_string_eol_s[0]);
     }
 
     return status;
index 376537e87d2478b88b50747b3ac6d676551ca917..d9c0d786115b169a85dd545acbc529894d4c336c 100644 (file)
@@ -234,7 +234,7 @@ extern "C" {
  * @see fl_type_array_lengths_increase_by()
  */
 #ifndef _di_controller_process_entry_
-  extern f_return_status controller_process_entry(const controller_data_t data, controller_setting_t *setting, controller_cache_t *cache) f_gcc_attribute_visibility_internal;
+  extern f_return_status controller_process_entry(controller_data_t *data, controller_setting_t *setting, controller_cache_t *cache) f_gcc_attribute_visibility_internal;
 #endif // _di_controller_process_entry_
 
 /**
index ba80d290393eb4b6577c36c8ffb6f33365d9d441..25af69d32f98e5745a688c08b0d2d40949ec48f8 100644 (file)
@@ -257,7 +257,7 @@ extern "C" {
             }
 
             fprintf(data.error.to.stream, "exactly ", data.error.context.before->string);
-            fprintf(data.error.to.stream, "%s%s%u%s", data.error.context.after->string, parameters, data.error.notable.after->string);
+            fprintf(data.error.to.stream, "%s%s%u%s", data.error.context.after->string, data.error.notable.before->string, parameters, data.error.notable.after->string);
             fprintf(data.error.to.stream, "%s parameters.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]);
           }
         }
index a86f4bfb822550b37d1c80b7ac812ec103135f67..8b3504b11589f1a68a74c96da5a43ebbd3910e93 100644 (file)
@@ -401,21 +401,103 @@ extern "C" {
 #endif // _di_controller_rule_error_need_want_wish_print_
 
 #ifndef _di_controller_rule_execute_
-  f_return_status controller_rule_execute(const controller_data_t data, const controller_cache_t cache, const f_array_length_t index, controller_setting_t *setting) {
-    // @todo this needs the "action" in which to perform, such as "start", "stop", "restart", etc..
-    // @todo
+  f_return_status controller_rule_execute(const controller_cache_t cache, const f_array_length_t index, const uint8_t action, controller_data_t *data, controller_setting_t *setting) {
+
+    f_array_length_t i = 0;
+    f_array_length_t j = 0;
+    f_array_length_t k = 0;
+
+    controller_rule_item_t *rule_item = 0;
+    controller_rule_action_t *rule_action = 0;
+
+    for (i = 0; i < setting->rules.array[index].items.used; ++i) {
+
+      if (setting->rules.array[index].items.array[i].type == controller_rule_item_type_setting) continue;
+
+      rule_item = &setting->rules.array[index].items.array[i];
+
+      for (j = 0; j < rule_item->actions.used; ++j) {
+
+        if (rule_item->actions.array[j].type != action) continue;
+
+        rule_action = &rule_item->actions.array[j];
+
+        if (rule_item->type == controller_rule_item_type_command) {
+          if (rule_action->method == controller_rule_action_method_extended) {
+            // @todo
+          }
+          else {
+            // @todo extended list execution.
+          }
+        }
+        else if (rule_item->type == controller_rule_item_type_script) {
+          if (rule_action->method == controller_rule_action_method_extended) {
+          // @todo
+          }
+          else {
+            // @todo extended list execution.
+          }
+        }
+        else if (rule_item->type == controller_rule_item_type_service) {
+          if (rule_action->method == controller_rule_action_method_extended) {
+          // @todo
+          }
+          else {
+            // @todo extended list execution.
+          }
+        }
+        else {
+          // unknown, just ignore for now. (@todo print a warning when in debug mode.)
+          continue;
+        }
+      } // for
+    } // for
+
+    return F_none;
   }
 #endif // _di_controller_rule_execute_
 
+#ifndef _di_controller_rule_execute_script_
+  f_return_status controller_rule_execute_script(const controller_rule_action_t action, controller_data_t *data) {
+
+    // child processes should receive all signals, without blocking.
+    f_signal_how_t signals = f_signal_how_t_initialize;
+    f_signal_set_empty(&signals.block);
+    f_signal_set_fill(&signals.block_not);
+
+    f_execute_pipe_t pipe = f_execute_pipe_t_initialize;
+
+    f_status_t status = F_none;
+    //f_status_t status = fll_execute_program_environment(program.string, arguments, environment.names, environment.values, &signals, &pipe, &data->child);
+
+    if (status == F_child) {
+      // @todo wait for parent pipe.
+      // @todo how do I get status code? there will likely need to be more changes to fll_execute_program_environment()...
+      return F_child;
+    }
+
+    // parent process should print to the pipe.
+
+    // @todo handle errors, print messages, etc..
+    if (data->child != 0) {
+      status = F_status_set_error(F_failure);
+    }
+    else if (F_status_is_error(status)) {
+    }
+
+    data->child = 0;
+
+    return status;
+  }
+#endif // _di_controller_rule_execute_script_
+
 #ifndef _di_controller_rule_find_loaded_
   f_array_length_t controller_rule_find_loaded(const controller_data_t data, const controller_setting_t setting, const f_string_static_t rule_id) {
 
     f_array_length_t i = 0;
 
     for (; i < setting.rules.used; ++i) {
-      if (fl_string_dynamic_compare(rule_id, setting.rules.array[i].id) == F_equal_to) {
-        return i;
-      }
+      if (fl_string_dynamic_compare(rule_id, setting.rules.array[i].id) == F_equal_to) break;
     } // for
 
     return i;
@@ -728,11 +810,33 @@ extern "C" {
 #endif // _di_controller_rule_path_
 
 #ifndef _di_controller_rule_process_
-  f_return_status controller_rule_process(const controller_data_t data, const f_array_length_t index, const uint8_t options, controller_setting_t *setting, controller_cache_t *cache) {
+  f_return_status controller_rule_process(const f_array_length_t index, const uint8_t action, const uint8_t options, controller_data_t *data, controller_setting_t *setting, controller_cache_t *cache) {
+
+    switch (action) {
+      case controller_rule_action_type_kill:
+      case controller_rule_action_type_reload:
+      case controller_rule_action_type_restart:
+      case controller_rule_action_type_start:
+      case controller_rule_action_type_stop:
+        break;
+
+      default:
+
+        if (data->error.verbosity != f_console_verbosity_quiet) {
+          fprintf(data->error.to.stream, "%c", f_string_eol_s[0]);
+          fprintf(data->error.to.stream, "%s%sUnsupported action type '", 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, controller_rule_action_type_name(action), data->error.notable.after->string);
+          fprintf(data->error.to.stream, "%s' while attempting to execute rule.%s%c", data->error.context.before->string, data->error.context.after->string, f_string_eol_s[0]);
+
+          controller_rule_error_print(data->error, *cache, F_true);
+        }
+
+        return F_status_set_error(F_parameter);
+    }
 
     if (index >= setting->rules.used) {
-      fll_error_print(data.error, F_parameter, "controller_rule_process", F_true);
-      controller_rule_error_print(data.error, *cache, F_true);
+      fll_error_print(data->error, F_parameter, "controller_rule_process", F_true);
+      controller_rule_error_print(data->error, *cache, F_true);
 
       return F_status_set_error(F_parameter);
     }
@@ -740,8 +844,8 @@ extern "C" {
     f_status_t status = fl_type_array_lengths_increase_by(controller_default_allocation_step, &cache->stack);
 
     if (F_status_is_error(status)) {
-      fll_error_print(data.error, F_status_set_fine(status), "fl_type_array_lengths_increase_by", F_true);
-      controller_rule_error_print(data.error, *cache, F_true);
+      fll_error_print(data->error, F_status_set_fine(status), "fl_type_array_lengths_increase_by", F_true);
+      controller_rule_error_print(data->error, *cache, F_true);
 
       return status;
     }
@@ -751,13 +855,13 @@ extern "C" {
     for (; i < cache->stack.used; ++i) {
 
       if (cache->stack.array[i] == index) {
-        if (data.error.verbosity != f_console_verbosity_quiet) {
-          fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
-          fprintf(data.error.to.stream, "%s%sThe rule '", 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, setting->rules.array[i].name.string, data.error.notable.after->string);
-          fprintf(data.error.to.stream, "%s' is already on the execution stack, this recursion is prohibited.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]);
+        if (data->error.verbosity != f_console_verbosity_quiet) {
+          fprintf(data->error.to.stream, "%c", f_string_eol_s[0]);
+          fprintf(data->error.to.stream, "%s%sThe rule '", 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, setting->rules.array[i].name.string, data->error.notable.after->string);
+          fprintf(data->error.to.stream, "%s' is already on the execution stack, this recursion is prohibited.%s%c", data->error.context.before->string, data->error.context.after->string, f_string_eol_s[0]);
 
-          controller_rule_error_print(data.error, *cache, F_true);
+          controller_rule_error_print(data->error, *cache, F_true);
         }
 
         // never continue on recursion errors even in simulate mode.
@@ -776,8 +880,8 @@ extern "C" {
     }
 
     if (F_status_is_error(status)) {
-      fll_error_print(data.error, F_status_set_fine(status), "fl_string_append", F_true);
-      controller_rule_error_print(data.error, *cache, F_true);
+      fll_error_print(data->error, F_status_set_fine(status), "fl_string_append", F_true);
+      controller_rule_error_print(data->error, *cache, F_true);
 
       return status;
     }
@@ -785,8 +889,8 @@ extern "C" {
     status = fl_string_dynamic_append(setting->rules.array[index].id, &cache->name_file);
 
     if (F_status_is_error(status)) {
-      fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_append", F_true);
-      controller_rule_error_print(data.error, *cache, F_true);
+      fll_error_print(data->error, F_status_set_fine(status), "fl_string_dynamic_append", F_true);
+      controller_rule_error_print(data->error, *cache, F_true);
 
       return status;
     }
@@ -798,8 +902,8 @@ extern "C" {
     }
 
     if (F_status_is_error(status)) {
-      fll_error_print(data.error, F_status_set_fine(status), "fl_string_append", F_true);
-      controller_rule_error_print(data.error, *cache, F_true);
+      fll_error_print(data->error, F_status_set_fine(status), "fl_string_append", F_true);
+      controller_rule_error_print(data->error, *cache, F_true);
 
       return status;
     }
@@ -807,8 +911,8 @@ extern "C" {
     status = fl_string_dynamic_terminate_after(&cache->name_file);
 
     if (F_status_is_error(status)) {
-      fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_terminate_after", F_true);
-      controller_rule_error_print(data.error, *cache, F_true);
+      fll_error_print(data->error, F_status_set_fine(status), "fl_string_dynamic_terminate_after", F_true);
+      controller_rule_error_print(data->error, *cache, F_true);
 
       return status;
     }
@@ -817,8 +921,8 @@ extern "C" {
 
     controller_rule_t *rule = &setting->rules.array[index];
 
-    if ((options & controller_rule_option_simulate) && data.parameters[controller_parameter_validate].result == f_console_result_found) {
-      controller_rule_simulate(data, *cache, index, options, setting);
+    if ((options & controller_rule_option_simulate) && data->parameters[controller_parameter_validate].result == f_console_result_found) {
+      controller_rule_simulate(*data, *cache, index, controller_rule_action_type_start, options, setting);
     }
 
     {
@@ -841,21 +945,21 @@ extern "C" {
       for (i = 0; i < 3; ++i) {
 
         for (j = 0; j < dynamics[i]->used; ++j) {
-          at = controller_rule_find_loaded(data, *setting, dynamics[i]->array[j]);
+          at = controller_rule_find_loaded(*data, *setting, dynamics[i]->array[j]);
 
           if (at == setting->rules.used) {
             if (i == 0) {
-              controller_rule_error_need_want_wish_print(data.error, strings[i], dynamics[i]->array[j].string, "was not found");
+              controller_rule_error_need_want_wish_print(data->error, strings[i], dynamics[i]->array[j].string, "was not found");
 
               status = F_status_set_error(F_found_not);
-              controller_rule_error_print(data.error, *cache, F_true);
+              controller_rule_error_print(data->error, *cache, F_true);
 
               if (!(options & controller_rule_option_simulate)) break;
             }
             else {
-              if (data.warning.verbosity == f_console_verbosity_debug) {
-                controller_rule_error_need_want_wish_print(data.warning, strings[i], dynamics[i]->array[j].string, "was not found");
-                controller_rule_error_print(data.warning, *cache, F_true);
+              if (data->warning.verbosity == f_console_verbosity_debug) {
+                controller_rule_error_need_want_wish_print(data->warning, strings[i], dynamics[i]->array[j].string, "was not found");
+                controller_rule_error_print(data->warning, *cache, F_true);
               }
             }
           }
@@ -871,8 +975,8 @@ extern "C" {
               status = fl_type_array_lengths_increase_by(controller_default_allocation_step, &cache->stack);
 
               if (F_status_is_error(status)) {
-                fll_error_print(data.error, F_status_set_fine(status), "fl_type_array_lengths_increase_by", F_true);
-                controller_rule_error_print(data.error, *cache, F_true);
+                fll_error_print(data->error, F_status_set_fine(status), "fl_type_array_lengths_increase_by", F_true);
+                controller_rule_error_print(data->error, *cache, F_true);
 
                 // always exit on memory errors, even in simulate mode.
                 break;
@@ -895,7 +999,9 @@ extern "C" {
               memcpy(cache_name_file, cache->name_file.string, cache->name_file.used);
 
               // @todo: this should pass or use the asynchronous state.
-              status = controller_rule_process(data, at, options, setting, cache);
+              status = controller_rule_process(at, controller_rule_action_type_start, options, data, setting, cache);
+
+              if (status == F_child || status == F_signal) break;
 
               // restore cache.
               memcpy(cache->name_action.string, cache_name_action, cache_name_action_used);
@@ -915,17 +1021,17 @@ extern "C" {
               if (F_status_is_error(status)) {
                 if (i == 0 || i == 1 || F_status_set_fine(status) == F_memory_not || F_status_set_fine(status) == F_memory_allocation || F_status_set_fine(status) == F_memory_reallocation) {
 
-                  controller_rule_error_need_want_wish_print(data.error, strings[i], dynamics[i]->array[j].string, "failed during execution");
-                  controller_rule_error_print(data.error, *cache, F_true);
+                  controller_rule_error_need_want_wish_print(data->error, strings[i], dynamics[i]->array[j].string, "failed during execution");
+                  controller_rule_error_print(data->error, *cache, F_true);
 
                   if (!(options & controller_rule_option_simulate) || F_status_set_fine(status) == F_memory_not || F_status_set_fine(status) == F_memory_allocation || F_status_set_fine(status) == F_memory_reallocation) {
                     break;
                   }
                 }
                 else {
-                  if (data.warning.verbosity == f_console_verbosity_debug) {
-                    controller_rule_error_need_want_wish_print(data.warning, strings[i], dynamics[i]->array[j].string, "failed during execution");
-                    controller_rule_error_print(data.warning, *cache, F_true);
+                  if (data->warning.verbosity == f_console_verbosity_debug) {
+                    controller_rule_error_need_want_wish_print(data->warning, strings[i], dynamics[i]->array[j].string, "failed during execution");
+                    controller_rule_error_print(data->warning, *cache, F_true);
                   }
                 }
               }
@@ -933,32 +1039,75 @@ extern "C" {
             else if (F_status_is_error(setting->rules.array[at].status)) {
 
               if (i == 0 || i == 1) {
-                controller_rule_error_need_want_wish_print(data.error, strings[i], dynamics[i]->array[j].string, "is in a failed state");
+                controller_rule_error_need_want_wish_print(data->error, strings[i], dynamics[i]->array[j].string, "is in a failed state");
 
                 status = F_status_set_error(F_found_not);
-                controller_rule_error_print(data.error, *cache, F_true);
+                controller_rule_error_print(data->error, *cache, F_true);
 
                 if (!(options & controller_rule_option_simulate)) break;
               }
               else {
-                if (data.warning.verbosity == f_console_verbosity_debug) {
-                  controller_rule_error_need_want_wish_print(data.warning, strings[i], dynamics[i]->array[j].string, "is in a failed state");
-                  controller_rule_error_print(data.warning, *cache, F_true);
+                if (data->warning.verbosity == f_console_verbosity_debug) {
+                  controller_rule_error_need_want_wish_print(data->warning, strings[i], dynamics[i]->array[j].string, "is in a failed state");
+                  controller_rule_error_print(data->warning, *cache, F_true);
                 }
               }
             }
           }
         } // for
 
+        if (status == F_child || status == F_signal) break;
+
         if (F_status_is_error(status) && !(options & controller_rule_option_simulate)) break;
       } // for
     }
 
     if (!(options & controller_rule_option_simulate) && F_status_is_error_not(status)) {
-      status = controller_rule_execute(data, *cache, index, setting);
 
-      if (F_status_is_error(status)) {
-        fll_error_print(data.error, F_status_set_fine(status), "controller_rule_execute", F_true);
+      // find at least one of the requested action when the rule is required.
+      if (options & controller_rule_option_require) {
+        bool missing = F_true;
+
+        f_array_length_t j = 0;
+
+        for (i = 0; i < rule->items.used; ++i) {
+
+          for (j = 0; j < rule->items.array[i].actions.used; ++j) {
+
+            if (rule->items.array[i].actions.array[j].type == action) {
+              missing = F_false;
+              break;
+            }
+          } // for
+        } // for
+
+        if (missing) {
+
+          if (data->error.verbosity != f_console_verbosity_quiet) {
+            fprintf(data->error.to.stream, "%c", f_string_eol_s[0]);
+            fprintf(data->error.to.stream, "%s%sThe rule '", 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, rule->name.used ? rule->name.string : f_string_empty_s, data->error.notable.after->string);
+            fprintf(data->error.to.stream, "%s' has no '", data->error.context.before->string);
+            fprintf(data->error.to.stream, "%s%s%s%s", data->error.context.after->string, data->error.notable.before->string, controller_rule_action_type_name(action).string, data->error.notable.after->string);
+            fprintf(data->error.to.stream, "%s' action to execute.%s%c", data->error.context.before->string, data->error.context.after->string, f_string_eol_s[0]);
+
+            controller_rule_error_print(data->error, *cache, F_true);
+          }
+
+          status = F_status_set_error(F_parameter);
+        }
+      }
+
+      if (F_status_is_error_not(status)) {
+        status = controller_rule_execute(*cache, index, action, data, setting);
+
+        if (F_status_is_error(status)) {
+          fll_error_print(data->error, F_status_set_fine(status), "controller_rule_execute", F_true);
+        }
+
+        if (status == F_child) {
+          return F_child;
+        }
       }
     }
 
@@ -1616,10 +1765,13 @@ extern "C" {
       }
 
       if (cache->content_actions.array[i].used != 2) {
-        fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
-        fprintf(data.error.to.stream, "%s%sRule setting requires exactly two Content.%s%c", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s, data.error.context.after->string, f_string_eol_s[0]);
 
-        controller_rule_error_print(data.error, *cache, F_false);
+        if (data.error.verbosity != f_console_verbosity_quiet) {
+          fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
+          fprintf(data.error.to.stream, "%s%sRule setting requires exactly two Content.%s%c", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s, data.error.context.after->string, f_string_eol_s[0]);
+
+          controller_rule_error_print(data.error, *cache, F_false);
+        }
 
         if (F_status_is_error_not(status_return)) {
           status_return = F_status_set_error(F_valid_not);
@@ -1721,25 +1873,75 @@ extern "C" {
 #endif // _di_controller_rule_setting_read_
 
 #ifndef _di_controller_rule_simulate_
-  void controller_rule_simulate(const controller_data_t data, const controller_cache_t cache, const f_array_length_t index, const uint8_t options, controller_setting_t *setting) {
+  void controller_rule_simulate(const controller_data_t data, const controller_cache_t cache, const f_array_length_t index, const uint8_t action, const uint8_t options, controller_setting_t *setting) {
+
+    switch (action) {
+      case controller_rule_action_type_kill:
+      case controller_rule_action_type_reload:
+      case controller_rule_action_type_restart:
+      case controller_rule_action_type_start:
+      case controller_rule_action_type_stop:
+        break;
+
+      default:
+
+        if (data.error.verbosity != f_console_verbosity_quiet) {
+          fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
+          fprintf(data.error.to.stream, "%s%sUnsupported action type '", 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, controller_rule_action_type_name(action).string, data.error.notable.after->string);
+          fprintf(data.error.to.stream, "%s' while attempting to simulate rule execution.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]);
+
+          controller_rule_error_print(data.error, cache, F_true);
+        }
 
-    // @todo this needs the "action" in which to perform, such as "start", "stop", "restart", etc..
+        return;
+    }
 
     controller_rule_t * const rule = &setting->rules.array[index];
 
+    f_array_length_t i = 0;
+    f_array_length_t j = 0;
+
+    // find at least one of the requested action.
+    {
+      bool missing = F_true;
+
+      for (; i < rule->items.used; ++i) {
+
+        for (j = 0; j < rule->items.array[i].actions.used; ++j) {
+
+          if (rule->items.array[i].actions.array[j].type == action) {
+            missing = F_false;
+            break;
+          }
+        } // for
+      } // for
+
+      if (missing) {
+        fprintf(data.output.stream, "%c", f_string_eol_s[0]);
+        fprintf(data.output.stream, "Rule '");
+        fprintf(data.output.stream, "%s%s%s", data.context.set.title.before->string, rule->name.used ? rule->name.string : f_string_empty_s, data.context.set.title.after->string);
+        fprintf(data.output.stream, "' has no '");
+        fprintf(data.output.stream, "%s%s%s", data.context.set.important.before->string, controller_rule_action_type_name(action).string, data.context.set.important.after->string);
+        fprintf(data.output.stream, "' action to execute and would '");
+        fprintf(data.output.stream, "%s%s%s", data.context.set.important.before->string, options & controller_rule_option_require ? controller_string_fail : controller_string_succeed, data.context.set.important.after->string);
+        fprintf(data.output.stream, "' because it is '");
+        fprintf(data.output.stream, "%s%s%s", data.context.set.important.before->string, options & controller_rule_option_require ? controller_string_required : controller_string_optional, data.context.set.important.after->string);
+        fprintf(data.output.stream, "'.%c", f_string_eol_s[0]);
+      }
+    }
+
     fprintf(data.output.stream, "%c", f_string_eol_s[0]);
     fprintf(data.output.stream, "Rule %s%s%s {%c", data.context.set.title.before->string, rule->id.used ? rule->id.string : f_string_empty_s, data.context.set.title.after->string, f_string_eol_s[0]);
     fprintf(data.output.stream, "  %s%s%s %s%c", data.context.set.important.before->string, controller_string_name, data.context.set.important.after->string, rule->name.used ? rule->name.string : f_string_empty_s, f_string_eol_s[0]);
-    fprintf(data.output.stream, "  %s%s%s %s%c", data.context.set.important.before->string, controller_string_control_group, data.context.set.important.after->string, rule->control_group.used ? rule->control_group.string : f_string_empty_s, f_string_eol_s[0]);
     fprintf(data.output.stream, "  %s%s%s %s%c", data.context.set.important.before->string, controller_string_how, data.context.set.important.after->string, options & controller_rule_option_asynchronous ? controller_string_asynchronous : controller_string_synchronous, f_string_eol_s[0]);
     fprintf(data.output.stream, "  %s%s%s %s%c", data.context.set.important.before->string, controller_string_wait, data.context.set.important.after->string, options & controller_rule_option_wait ? controller_string_yes : controller_string_no, f_string_eol_s[0]);
-
-    f_array_length_t i = 0;
+    fprintf(data.output.stream, "  %s%s%s %s%c", data.context.set.important.before->string, controller_string_control_group, data.context.set.important.after->string, rule->control_group.used ? rule->control_group.string : f_string_empty_s, f_string_eol_s[0]);
 
     fprintf(data.output.stream, "  %s%s%s {%c", data.context.set.important.before->string, controller_string_define, data.context.set.important.after->string, f_string_eol_s[0]);
 
     if (rule->define.used) {
-      for (; i < rule->define.used; ++i) {
+      for (i = 0; i < rule->define.used; ++i) {
 
         if (rule->define.array[i].name.used && rule->define.array[i].value.used) {
           fprintf(data.output.stream, "    %s %s=%s %s%c", rule->define.array[i].name.string, data.context.set.important.before->string, data.context.set.important.after->string, rule->define.array[i].value.string, f_string_eol_s[0]);
index 50454b11abef476a51893372495bf41c91900bb4..c86bf3702bb8f338c04c0147cfbd5607660f2825 100644 (file)
@@ -171,24 +171,35 @@ extern "C" {
 /**
  * Perform an execution of the given rule.
  *
- * @param data
- *   The program data.
  * @param cache
  *   A structure for containing and caching relevant data.
  * @param index
  *   The position in the setting.rules array representing the rule to simulate.
+ * @param action
+ *   The action to perform based on the action type codes.
+ *
+ *   Only subset of the action type codes are supported:
+ *   - controller_rule_action_type_kill
+ *   - controller_rule_action_type_reload
+ *   - controller_rule_action_type_restart
+ *   - controller_rule_action_type_start
+ *   - controller_rule_action_type_stop
+ * @param data
+ *   The program data.
  * @param setting
  *   The controller settings data.
  *
  * @return
  *   F_none on success.
+ *   F_child on child process exiting.
+ *   F_signal on (exit) signal received.
  *
  *   On success and the rule is run synchronously, then the individual status for the rule is set to F_complete.
  *   On success and the rule is run asynchronously, then the individual status for the rule is set to F_busy.
  *   On failure, the individual status for the rule is set to an appropriate error status.
  */
 #ifndef _di_controller_rule_execute_
-  extern f_return_status controller_rule_execute(const controller_data_t data, const controller_cache_t cache, const f_array_length_t index, controller_setting_t *setting) f_gcc_attribute_visibility_internal;
+  extern f_return_status controller_rule_execute(const controller_cache_t cache, const f_array_length_t index, const uint8_t action, controller_data_t *data, controller_setting_t *setting) f_gcc_attribute_visibility_internal;
 #endif // _di_controller_rule_execute_
 
 /**
@@ -345,17 +356,24 @@ extern "C" {
  *
  * This function is recursively called for each "need", "want", and "wish", and has a max recursion length of the max size of the f_array_lengths_t array.
  *
- * @todo add asynchronous boolean? (will also need a wait boolean, so this should probably be a uint8_t with using bitwise states).
- *
- * @param data
- *   The program data.
  * @param index
  *   Position in the rules array representing the rule to execute
+ * @param action
+ *   The action to perform based on the action type codes.
+ *
+ *   Only subset of the action type codes are supported:
+ *   - controller_rule_action_type_kill
+ *   - controller_rule_action_type_reload
+ *   - controller_rule_action_type_restart
+ *   - controller_rule_action_type_start
+ *   - controller_rule_action_type_stop
  * @param options
  *   A number using bits to represent specific boolean options.
  *   If no bits set, then operate normally in a synchronous manner.
  *   If bit controller_rule_option_simulate, then the rule execution is in simulation mode (printing a message that the rule would be executed but does not execute the rule).
  *   If bit controller_rule_option_asynchronous, then run asynchronously.
+ * @param data
+ *   The program data.
  * @param setting
  *   The controller settings data.
  * @param cache
@@ -364,10 +382,12 @@ extern "C" {
  *   This utilizes line_action, line_item, name_action, and name_item from cache, but they are backed up before starting and then restored after finishing.
  *
  * @return
- *    F_none on success.
+ *   F_none on success.
+ *   F_child on child process exiting.
+ *   F_signal on (exit) signal received.
  */
 #ifndef _di_controller_rule_process_
-  extern f_return_status controller_rule_process(const controller_data_t data, const f_array_length_t index, const uint8_t options, controller_setting_t *setting, controller_cache_t *cache) f_gcc_attribute_visibility_internal;
+  extern f_return_status controller_rule_process(const f_array_length_t index, const uint8_t action, const uint8_t options, controller_data_t *data, controller_setting_t *setting, controller_cache_t *cache) f_gcc_attribute_visibility_internal;
 #endif // _di_controller_rule_process_
 
 /**
@@ -456,6 +476,15 @@ extern "C" {
  *   A structure for containing and caching relevant data.
  * @param index
  *   The position in the setting.rules array representing the rule to simulate.
+ * @param action
+ *   The action to perform based on the action type codes.
+ *
+ *   Only subset of the action type codes are supported:
+ *   - controller_rule_action_type_kill
+ *   - controller_rule_action_type_reload
+ *   - controller_rule_action_type_restart
+ *   - controller_rule_action_type_start
+ *   - controller_rule_action_type_stop
  * @param options
  *   A number using bits to represent specific boolean options.
  *   If no bits set, then operate normally in a synchronous manner.
@@ -465,7 +494,7 @@ extern "C" {
  *   The controller settings data.
  */
 #ifndef _di_controller_rule_simulate_
-  extern void controller_rule_simulate(const controller_data_t data, const controller_cache_t cache, const f_array_length_t index, const uint8_t options, controller_setting_t *setting) f_gcc_attribute_visibility_internal;
+  extern void controller_rule_simulate(const controller_data_t data, const controller_cache_t cache, const f_array_length_t index, const uint8_t action, const uint8_t options, controller_setting_t *setting) f_gcc_attribute_visibility_internal;
 #endif // _di_controller_rule_simulate_
 
 /**
index 548bde98b863a0e0ccdd72348c1eb2315ebfdbb8..32305e204de720491de62f91a5ebc4db5e43f8aa 100644 (file)
@@ -9,12 +9,14 @@ f_color
 f_console
 f_conversion
 f_directory
+f_execute
 f_file
 f_fss
 f_iki
 f_path
 f_pipe
 f_print
+f_signal
 fl_color
 fl_console
 fl_conversion
index 2b063b6bfd0a45df9dd364d6731b7f1c831715f7..95f70d8f12a355d20941fb3d2d6ea1c2307045d0 100644 (file)
@@ -19,7 +19,7 @@ build_compiler gcc
 build_indexer ar
 build_language c
 build_libraries -lc
-build_libraries-individual -lfll_error -lfll_fss -lfll_path -lfll_program -lfll_status -lfl_color -lfl_console -lfl_conversion -lfl_fss -lfl_iki -lfl_status -lfl_string -lfl_type -lf_console -lf_conversion -lf_directory -lf_file -lf_fss -lf_iki -lf_memory -lf_path -lf_pipe -lf_print -lf_utf
+build_libraries-individual -lfll_error -lfll_fss -lfll_path -lfll_program -lfll_status -lfl_color -lfl_console -lfl_conversion -lfl_fss -lfl_iki -lfl_status -lfl_string -lfl_type -lf_console -lf_conversion -lf_directory -lf_file -lf_fss -lf_iki -lf_memory -lf_path -lf_pipe -lf_print -lf_signal -lf_utf
 build_libraries-level -lfll_2 -lfll_1 -lfll_0
 build_libraries-monolithic -lfll
 build_sources_library controller.c private-control.c private-controller.c private-entry.c private-rule.c
index f6d755ea518d4f7a0556baaede1abeb430e1f237..12047fb6d26e9e8f8c444724f45ff7bc1107fc91 100644 (file)
@@ -50,6 +50,8 @@ Entry Documentation:
   Until that execution succeeds and the daemon goes into the background the representing rule will block.
   After the daemon goes into the background, then the representing rule will be fully executed.
 
+  Any "rule" specified in this entry file is always executed using the "start" rule action type.
+
   The "timeout" Action provides default global settings for each of the three special situations: "start", "stop", and "kill".
   Each of these may only have a single one exist at a time (one "start", one "stop", and one "kill").
   Each successive "timeout" Action, specific to each Action Name (such as "start"), specified replaces the previously defined "timeout" Action (in a top-down manner).
index 67fcb93f883d5410726de05820760f111056509c..509e984667d084346e3e4f44dd528026fa8695a0 100644 (file)
 
 // fll-0 includes
 #include <level_0/type.h>
-#include <level_0/status.h>
 #include <level_0/type_array.h>
+#include <level_0/status.h>
 #include <level_0/memory.h>
-#include <level_0/signal.h>
 #include <level_0/string.h>
 #include <level_0/utf.h>
 #include <level_0/account.h>
@@ -65,6 +64,7 @@
 #include <level_0/file.h>
 #include <level_0/iki.h>
 #include <level_0/path.h>
+#include <level_0/signal.h>
 
 // fll-1 includes
 #include <level_1/color.h>
index 1091ef4ab3609bc497307fa0308fee52d9674427..847f076a6b69823287f431a14a75277e9f47b264 100644 (file)
@@ -43,8 +43,6 @@ int main(const unsigned long argc, const f_string_t *argv) {
 
   status = fake_main(arguments, &data);
 
-  f_signal_close(&data.signal);
-
   // flush output pipes before closing.
   fflush(f_type_output);
   fflush(f_type_error);
@@ -54,13 +52,15 @@ int main(const unsigned long argc, const f_string_t *argv) {
   close(f_type_descriptor_input);
   close(f_type_descriptor_error);
 
-  if (F_status_is_error(status)) {
-    return 1;
-  }
+  f_signal_close(&data.signal);
 
   if (status == F_child) {
     exit(data.child);
   }
 
+  if (F_status_is_error(status)) {
+    return 1;
+  }
+
   return 0;
 }