]> Kevux Git Server - fll/commitdiff
Progress: controller program and execute function improvements.
authorKevin Day <thekevinday@gmail.com>
Sun, 20 Dec 2020 04:04:04 +0000 (22:04 -0600)
committerKevin Day <thekevinday@gmail.com>
Sun, 20 Dec 2020 04:08:31 +0000 (22:08 -0600)
Get rid f fl_execute_parameter_option_fixated.
A better approach is just to allow a 0 to be passed instead of the string (aka: NULL).
The execute functions can then detect whether or not full fixation is needed.
An additional parameter check is now needed as if the program is 0 then there must be at least 1 argument defined.

Due to design changes the 'method' property for individual rule actions no longer needs to be on the rule action structure.
In fact, it is now confusing as each action represents only a single action (itself).

Add support for the "script" rule setting to designate the script program to run for scripts.

Add additional example entries and rules.

18 files changed:
level_1/fl_execute/c/execute-common.h
level_2/fll_execute/c/execute.c
level_2/fll_execute/c/execute.h
level_2/fll_execute/c/private-execute.c
level_2/fll_execute/c/private-execute.h
level_3/controller/c/controller.h
level_3/controller/c/private-common.h
level_3/controller/c/private-rule.c
level_3/controller/c/private-rule.h
level_3/controller/data/settings/example/entries/test.entry [new file with mode: 0644]
level_3/controller/data/settings/example/rules/command/multiple.rule [new file with mode: 0644]
level_3/controller/data/settings/example/rules/maintenance/explode.rule [new file with mode: 0644]
level_3/controller/data/settings/example/rules/script/fail.rule [new file with mode: 0644]
level_3/controller/data/settings/example/rules/script/php.rule [new file with mode: 0644]
level_3/controller/data/settings/example/rules/script/python.rule [new file with mode: 0644]
level_3/controller/data/settings/example/rules/script/succeed.rule [new file with mode: 0644]
level_3/controller/documents/rule.txt
level_3/controller/specifications/rule.txt

index ec4b7bd99283e9fe52735c71e8d844f59e790d5c..3efb1b7d8877809bcf760f422321914df1d071ec 100644 (file)
@@ -20,9 +20,8 @@ extern "C" {
  * A structure for containing additional parameters for the execute functions that call the execv() family of functions.
  *
  * bitwise options:
- *   fl_execute_parameter_option_exit:    used to desginate to exit after calling child otherwise child process will return.
- *   fl_execute_parameter_option_fixated: used to designate that the program is already fixated in index 0 of the arguments array.
- *   fl_execute_parameter_option_path:    used to designate that this is a path to a program (such as '/bin/bash').
+ *   fl_execute_parameter_option_exit: used to desginate to exit after calling child otherwise child process will return.
+ *   fl_execute_parameter_option_path: used to designate that this is a path to a program (such as '/bin/bash').
  *
  * option:      accepts the bitwise options
  * environment: the environment variable name and value pairs, set to 0 to not use.
@@ -30,9 +29,8 @@ extern "C" {
  * data:        the data to pipe to the child process, set to 0 to not use.
  */
 #ifndef _di_fl_execute_parameter_t_
-  #define fl_execute_parameter_option_exit    0x1
-  #define fl_execute_parameter_option_fixated 0x2
-  #define fl_execute_parameter_option_path    0x4
+  #define fl_execute_parameter_option_exit 0x1
+  #define fl_execute_parameter_option_path 0x2
 
   typedef struct {
     uint8_t option;
index ab24c358301a89817166d22449dc675875cd644a..38145ed3e841997772147dedbf93acfb94abc728 100644 (file)
@@ -132,20 +132,21 @@ extern "C" {
 #ifndef _di_fll_execute_into_
   f_return_status fll_execute_into(const f_string_t program, const f_string_statics_t arguments, const uint8_t option, int *result) {
     #ifndef _di_level_2_parameter_checking_
+      if (!program && !arguments.used) return F_status_set_error(F_parameter);
       if (!result) return F_status_set_error(F_parameter);
     #endif // _di_level_2_parameter_checking_
 
     // create a string array that is compatible with execv() calls.
     f_string_t fixed_arguments[arguments.used + 2];
 
-    const f_string_t last_slash = strrchr(program, f_path_separator_s[0]);
-    const f_string_length_t name_size = last_slash ? strnlen(last_slash, f_path_max) : strnlen(program, f_path_max);
+    const f_string_t last_slash = strrchr(program ? program : arguments.array[0].string, f_path_separator_s[0]);
+    const f_string_length_t name_size = last_slash ? strnlen(last_slash, f_path_max) : strnlen(program ? program : arguments.array[0].string, f_path_max);
 
     char program_name[name_size + 1];
 
     program_name[name_size] = 0;
 
-    private_fll_execute_path_arguments_fixate(last_slash ? last_slash : program, arguments, option, name_size, program_name, fixed_arguments);
+    private_fll_execute_path_arguments_fixate(last_slash ? last_slash : program ? program : arguments.array[0].string, arguments, !program, name_size, program_name, fixed_arguments);
 
     const int code = option & fl_execute_parameter_option_path ? execv(program, fixed_arguments) : execvp(program, fixed_arguments);
 
@@ -169,20 +170,21 @@ extern "C" {
 #ifndef _di_fll_execute_program_
   f_return_status fll_execute_program(const f_string_t program, const f_string_statics_t arguments, fl_execute_parameter_t * const parameter, int *result) {
     #ifndef _di_level_2_parameter_checking_
+      if (!program && !arguments.used) return F_status_set_error(F_parameter);
       if (!result) return F_status_set_error(F_parameter);
     #endif // _di_level_2_parameter_checking_
 
     // create a string array that is compatible with execv() calls.
     f_string_t fixed_arguments[arguments.used + 2];
 
-    const f_string_t last_slash = strrchr(program, f_path_separator_s[0]);
-    const f_string_length_t name_size = last_slash ? strnlen(last_slash, f_path_max) : strnlen(program, f_path_max);
+    const f_string_t last_slash = strrchr(program ? program : arguments.array[0].string, f_path_separator_s[0]);
+    const f_string_length_t name_size = last_slash ? strnlen(last_slash, f_path_max) : strnlen(program ? program : arguments.array[0].string, f_path_max);
 
     char program_name[name_size + 1];
 
     program_name[name_size] = 0;
 
-    private_fll_execute_path_arguments_fixate(last_slash ? last_slash : program, arguments, parameter->option, name_size, program_name, fixed_arguments);
+    private_fll_execute_path_arguments_fixate(last_slash ? last_slash : program ? program : arguments.array[0].string, arguments, !program, name_size, program_name, fixed_arguments);
 
     // when the environment is to be cleared, a full path must be used.
     if (parameter && !(parameter->option & fl_execute_parameter_option_path) && parameter->environment) {
index 06ebe0f085ff416aed5cd606c6782d96d8b441be..00c18bd1a8b059c71fa2d069d7bb74b8d7091f1f 100644 (file)
@@ -340,13 +340,13 @@ extern "C" {
  *
  * @param program
  *   The name or path of the program.
+ *   The string pointer may be set to 0, to designate that the first index in arguments is assumed to be the program.
  * @param arguments
  *   An array of strings representing the arguments.
  * @param option
  *   A bitwise set of options, such as: fl_execute_parameter_option_exit, and fl_execute_parameter_option_path.
  *   If fl_execute_parameter_option_exit: this will call exit() at the end of execution (be it success or failure).
  *   If fl_execute_parameter_option_path: this is a program path (such as "/bin/bash"), otherwise this is a program (such as "bash").
- *   If fl_execute_parameter_option_fixated: this is a program path is already in the arguments at index 0.
  * @param result
  *   The code returned after finishing execution of program.
  *
@@ -383,6 +383,7 @@ extern "C" {
  *
  * @param program
  *   The name or path of the program.
+ *   The string pointer may be set to 0, to designate that the first index in arguments is assumed to be the program.
  * @param arguments
  *   An array of strings representing the arguments.
  * @param parameter
index 57ffae9247bc47e573ca7dc1f19964766b84afbf..eae5406625939d5bf13bd7851b468964a1249259 100644 (file)
@@ -253,35 +253,35 @@ extern "C" {
 #endif // !defined(_di_fll_execute_program_)
 
 #if !defined(_di_fll_execute_program_)
-  void private_fll_execute_path_arguments_fixate(const f_string_t program_path, const f_string_statics_t arguments, const uint8_t option, const f_string_length_t name_size, char program_name[], f_string_t fixed_arguments[]) {
+  void private_fll_execute_path_arguments_fixate(const f_string_t program_path, const f_string_statics_t arguments, const bool fixated_is, const f_string_length_t name_size, char program_name[], f_string_t fixed_arguments[]) {
 
-    if (option & fl_execute_parameter_option_fixated) {
+    memcpy(program_name, program_path, name_size);
+    program_name[name_size] = 0;
 
-      for (f_string_length_t i = 0; i < arguments.used; i++) {
-        fixed_arguments[i] = arguments.array[i].string;
-      } // for
-
-      // insert the required end of array designator.
-      fixed_arguments[arguments.used] = 0;
+    if (name_size) {
+      fixed_arguments[0] = program_name;
     }
     else {
-      memcpy(program_name, program_path, name_size);
-      program_name[name_size] = 0;
+      fixed_arguments[0] = 0;
+    }
 
-      if (name_size) {
-        fixed_arguments[0] = program_name;
-      }
-      else {
-        fixed_arguments[0] = 0;
-      }
+    f_string_length_t i = 0;
 
-      for (f_string_length_t i = 0; i < arguments.used; i++) {
+    if (fixated_is) {
+      for (i = 1; i < arguments.used; ++i) {
+        fixed_arguments[i] = arguments.array[i].string;
+      } // for
+    }
+    else {
+      for (; i < arguments.used; ++i) {
         fixed_arguments[i + 1] = arguments.array[i].string;
       } // for
+
+      i++;
     }
 
     // insert the required end of array designator.
-    fixed_arguments[arguments.used + 1] = 0;
+    fixed_arguments[i] = 0;
   }
 #endif // !defined(_di_fll_execute_program_)
 
index 8cf49db96698e2484bd60ce6a3dc53821ba6aba0..96c9b7a9986a2b4ee216f39eba9d097486c98772 100644 (file)
@@ -215,9 +215,9 @@ extern "C" {
  *   The part of the path to the program representing the program name to copy from.
  * @param arguments
  *   An array of strings representing the arguments.
- * @param option
- *   The bitwise option from fl_execute_parameter_t.option.
- *   This only cares about fl_execute_parameter_option_fixated.
+ * @param fixated_is
+ *   If TRUE, then this is a path to a program (such as "/bin/bash").
+ *   If FALSE, then this is not a path to a program (such as "bash").
  * @param name_size
  *   The size of the program_path to copy.
  * @param program_name
@@ -231,7 +231,7 @@ extern "C" {
  * @see fll_execute_program()
  */
 #if !defined(_di_fll_execute_program_)
-  extern void private_fll_execute_path_arguments_fixate(const f_string_t program_path, const f_string_statics_t arguments, const uint8_t option, const f_string_length_t name_size, char program_name[], f_string_t fixed_arguments[]) f_gcc_attribute_visibility_internal;
+  extern void private_fll_execute_path_arguments_fixate(const f_string_t program_path, const f_string_statics_t arguments, const bool fixated_is, const f_string_length_t name_size, char program_name[], f_string_t fixed_arguments[]) f_gcc_attribute_visibility_internal;
 #endif // !defined(_di_fll_execute_program_)
 
 #ifdef __cplusplus
index cb95aa650f30477851c91cdb7f5196cf6a912eed..632a465d099af449caf4d04d1cdaaec91ce0373f 100644 (file)
@@ -81,6 +81,8 @@ extern "C" {
   // This specifically must be at least 2 for this project.
   #define controller_default_allocation_step 4
 
+  #define controller_default_program_script "bash"
+
   #define controller_path_pid      "/var/run/controller/controller-"
   #define controller_path_settings "/etc/controller"
   #define controller_path_suffix   ".pid"
index 999442d6aabb19b1029fa3bb0b00775e7fc025ec..dbe8fdc8743e47d5d3c937e4f8d00fae4a0c182c 100644 (file)
@@ -143,7 +143,6 @@ extern "C" {
   };
 
   typedef struct {
-    uint8_t method;
     uint8_t type;
 
     f_string_length_t line;
@@ -157,7 +156,6 @@ extern "C" {
     { \
       0, \
       0, \
-      0, \
       F_known_not, \
       f_string_dynamics_t_initialize, \
     }
@@ -251,6 +249,7 @@ extern "C" {
     controller_rule_setting_type_need,
     controller_rule_setting_type_parameter,
     controller_rule_setting_type_path,
+    controller_rule_setting_type_script,
     controller_rule_setting_type_want,
     controller_rule_setting_type_wish,
   };
@@ -274,6 +273,7 @@ extern "C" {
     f_string_dynamic_t name;
     f_string_dynamic_t control_group;
     f_string_dynamic_t path;
+    f_string_dynamic_t script;
 
     f_string_maps_t define;
     f_string_maps_t parameter;
@@ -298,6 +298,7 @@ extern "C" {
       f_string_dynamic_t_initialize, \
       f_string_dynamic_t_initialize, \
       f_string_dynamic_t_initialize, \
+      f_string_dynamic_t_initialize, \
       f_string_maps_t_initialize, \
       f_string_maps_t_initialize, \
       f_string_dynamics_t_initialize, \
@@ -312,6 +313,7 @@ extern "C" {
     fl_string_dynamic_delete(&rule.name); \
     fl_string_dynamic_delete(&rule.control_group); \
     fl_string_dynamic_delete(&rule.path); \
+    fl_string_dynamic_delete(&rule.script); \
     f_macro_string_maps_t_delete_simple(rule.define) \
     f_macro_string_maps_t_delete_simple(rule.parameter) \
     fl_string_dynamics_delete(&rule.environment); \
index 666ec894521d0f697e1dbfdb5131c7bd26a6861d..04bb3b3e8af3ba2c0b67146d1f2c32b2c9b9bf77 100644 (file)
@@ -199,95 +199,100 @@ extern "C" {
         fll_error_print(data.error, F_status_set_fine(status), "fl_fss_extended_list_content_read", F_true);
       }
       else if (status == FL_fss_found_content) {
+        status = fl_fss_apply_delimit(cache->delimits, &cache->buffer_item);
 
-        // "script" types use the entire content and can be directly passed through.
-        if (item->type == controller_rule_item_type_script) {
-          actions->array[actions->used].parameters.used = 0;
-
-          status = fl_string_dynamics_increase(&actions->array[actions->used].parameters);
+        if (F_status_is_error(status)) {
+          fll_error_print(data.error, F_status_set_fine(status), "fl_fss_apply_delimit", F_true);
+        }
+        else {
 
-          if (F_status_is_error(status)) {
-            fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamics_increase", F_true);
-          }
-          else {
-            actions->array[actions->used].type = type;
-            actions->array[actions->used].method = method;
-            actions->array[actions->used].line = cache->line_action;
+          // "script" types use the entire content and can be directly passed through.
+          if (item->type == controller_rule_item_type_script) {
+            actions->array[actions->used].parameters.used = 0;
 
-            status = fl_string_dynamic_partial_append_nulless(cache->buffer_item, cache->content_action.array[0], &actions->array[actions->used].parameters.array[0]);
+            status = fl_string_dynamics_increase(&actions->array[actions->used].parameters);
 
             if (F_status_is_error(status)) {
-              fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_append_nulless", F_true);
+              fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamics_increase", F_true);
             }
+            else {
+              actions->array[actions->used].type = type;
+              actions->array[actions->used].line = cache->line_action;
 
-            status = fl_string_dynamic_terminate_after(&actions->array[actions->used].parameters.array[0]);
+              status = fl_string_dynamic_partial_append_nulless(cache->buffer_item, cache->content_action.array[0], &actions->array[actions->used].parameters.array[0]);
 
-            if (F_status_is_error(status)) {
-              fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_terminate_after", F_true);
-            }
-            else {
-              actions->array[actions->used].parameters.used = 1;
-              actions->used++;
-            }
-          }
+              if (F_status_is_error(status)) {
+                fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_append_nulless", F_true);
+              }
 
-          return status;
-        }
+              status = fl_string_dynamic_terminate_after(&actions->array[actions->used].parameters.array[0]);
 
-        // the object_actions and content_actions caches are being used for the purposes of getting the parameters a given the action.
-        status = fll_fss_extended_read(cache->buffer_item, &cache->content_action.array[0], &cache->object_actions, &cache->content_actions, 0, 0, &cache->delimits, 0);
+              if (F_status_is_error(status)) {
+                fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_terminate_after", F_true);
+              }
+              else {
+                actions->array[actions->used].parameters.used = 1;
+                actions->used++;
+              }
+            }
 
-        if (F_status_is_error(status)) {
-          fll_error_print(data.error, F_status_set_fine(status), "fll_fss_extended_read", F_true);
-        }
-        else {
-          status = fl_fss_apply_delimit(cache->delimits, &cache->buffer_item);
+            return status;
+          }
+
+          // the object_actions and content_actions caches are being used for the purposes of getting the parameters a given the action.
+          status = fll_fss_extended_read(cache->buffer_item, &cache->content_action.array[0], &cache->object_actions, &cache->content_actions, 0, 0, &cache->delimits, 0);
 
           if (F_status_is_error(status)) {
-            fll_error_print(data.error, F_status_set_fine(status), "fl_fss_apply_delimit", F_true);
+            fll_error_print(data.error, F_status_set_fine(status), "fll_fss_extended_read", F_true);
           }
           else {
-            f_array_length_t i = 0;
-            f_array_length_t j = 0;
+            status = fl_fss_apply_delimit(cache->delimits, &cache->buffer_item);
 
-            for (; i < cache->object_actions.used; ++i) {
+            if (F_status_is_error(status)) {
+              fll_error_print(data.error, F_status_set_fine(status), "fl_fss_apply_delimit", F_true);
+            }
+            else {
+              f_array_length_t i = 0;
+              f_array_length_t j = 0;
 
-              status = controller_rule_actions_increase_by(controller_default_allocation_step, actions);
+              for (; i < cache->object_actions.used; ++i) {
 
-              if (F_status_is_error(status)) {
-                fll_error_print(data.error, F_status_set_fine(status), "controller_rule_actions_increase_by", F_true);
-                break;
-              }
+                status = controller_rule_actions_increase_by(controller_default_allocation_step, actions);
 
-              status = f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &actions->array[actions->used].line);
+                if (F_status_is_error(status)) {
+                  fll_error_print(data.error, F_status_set_fine(status), "controller_rule_actions_increase_by", F_true);
+                  break;
+                }
 
-              if (F_status_is_error(status)) {
-                fll_error_print(data.error, F_status_set_fine(status), "f_fss_count_lines", F_true);
-                break;
-              }
+                status = f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &actions->array[actions->used].line);
 
-              actions->array[actions->used].type = type;
-              actions->array[actions->used].method = method;
-              actions->array[actions->used].line += ++item->line;
-              actions->array[actions->used].parameters.used = 0;
-              actions->array[actions->used].status = F_known_not;
+                if (F_status_is_error(status)) {
+                  fll_error_print(data.error, F_status_set_fine(status), "f_fss_count_lines", F_true);
+                  break;
+                }
 
-              status = fl_string_dynamics_increase(&actions->array[actions->used].parameters);
+                actions->array[actions->used].type = type;
+                actions->array[actions->used].line += ++item->line;
+                actions->array[actions->used].parameters.used = 0;
+                actions->array[actions->used].status = F_known_not;
 
-              if (F_status_is_error(status)) {
-                fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamics_increase", F_true);
+                status = fl_string_dynamics_increase(&actions->array[actions->used].parameters);
 
-                actions->array[actions->used].status = controller_status_simplify(F_status_set_fine(status));
-                break;
-              }
+                if (F_status_is_error(status)) {
+                  fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamics_increase", F_true);
+
+                  actions->array[actions->used].status = controller_status_simplify(F_status_set_fine(status));
+                  break;
+                }
 
-              status = controller_rule_parameters_read(data, cache->buffer_item, &cache->object_actions.array[i], &cache->content_actions.array[i], &actions->array[actions->used].parameters);
+                status = controller_rule_parameters_read(data, cache->buffer_item, &cache->object_actions.array[i], &cache->content_actions.array[i], &actions->array[actions->used].parameters);
 
-              actions->array[actions->used].status = controller_status_simplify(F_status_set_fine(status));
-              actions->used++;
-            } // for
+                actions->array[actions->used].status = controller_status_simplify(F_status_set_fine(status));
+                actions->used++;
+              } // for
 
-            range->start = cache->content_action.array[0].start;
+              range->start = cache->content_action.array[0].start;
+            }
           }
         }
       }
@@ -318,7 +323,6 @@ extern "C" {
           }
           else {
             actions->array[actions->used].type = type;
-            actions->array[actions->used].method = method;
             actions->array[actions->used].line += ++item->line;
             actions->array[actions->used].parameters.used = 0;
             actions->array[actions->used].status = F_known_not;
@@ -389,19 +393,37 @@ extern "C" {
 #endif // _di_controller_rule_error_print_
 
 #ifndef _di_controller_rule_error_print_execute_
-  void controller_rule_error_print_execute(const fll_error_print_t output, const bool program_is, const f_string_t name, const int code) {
+  void controller_rule_error_print_execute(const fll_error_print_t output, const bool script_is, const f_string_t name, const int code) {
 
     if (output.verbosity != f_console_verbosity_quiet) {
       fprintf(output.to.stream, "%c", f_string_eol_s[0]);
-      fprintf(output.to.stream, "%s%sThe %s '", output.context.before->string, output.prefix ? output.prefix : f_string_empty_s, program_is ? controller_string_program : controller_string_script);
+      fprintf(output.to.stream, "%s%sThe %s '", output.context.before->string, output.prefix ? output.prefix : f_string_empty_s, script_is ? controller_string_script : controller_string_program);
       fprintf(output.to.stream, "%s%s%s%s", output.context.after->string, output.notable.before->string, name ? name : f_string_empty_s, output.notable.after->string);
-      fprintf(output.to.stream, "%s' failed with the exit code '", output.context.before->string);
-      fprintf(output.to.stream, "%s%s%d%s", output.context.after->string, output.notable.before->string, code, output.notable.after->string);
-      fprintf(output.to.stream, "%s'.%s%c", output.context.before->string, output.context.after->string, f_string_eol_s[0]);
+
+      if (code) {
+        fprintf(output.to.stream, "%s' failed with the exit code '", output.context.before->string);
+        fprintf(output.to.stream, "%s%s%i%s", output.context.after->string, output.notable.before->string, code, output.notable.after->string);
+        fprintf(output.to.stream, "%s'.%s%c", output.context.before->string, output.context.after->string, f_string_eol_s[0]);
+      }
+      else {
+        fprintf(output.to.stream, "%s' failed.%s%c", output.context.before->string, output.context.after->string, f_string_eol_s[0]);
+      }
     }
   }
 #endif // _di_controller_rule_error_print_execute_
 
+#ifndef _di_controller_rule_error_print_execute_not_found_
+  void controller_rule_error_print_execute_not_found(const fll_error_print_t output, const bool script_is, const f_string_t name) {
+
+    if (output.verbosity != f_console_verbosity_quiet) {
+      fprintf(output.to.stream, "%c", f_string_eol_s[0]);
+      fprintf(output.to.stream, "%s%sThe %s '", output.context.before->string, output.prefix ? output.prefix : f_string_empty_s, script_is ? controller_string_script : controller_string_program);
+      fprintf(output.to.stream, "%s%s%s%s", output.context.after->string, output.notable.before->string, name ? name : f_string_empty_s, output.notable.after->string);
+      fprintf(output.to.stream, "%s' could not be executed because it was not found.%s%c", output.context.before->string, output.context.after->string, f_string_eol_s[0]);
+    }
+  }
+#endif // _di_controller_rule_error_print_execute_not_found_
+
 #ifndef _di_controller_rule_error_print_need_want_wish_
   void controller_rule_error_print_need_want_wish(const fll_error_print_t output, const f_string_t need_want_wish, const f_string_t value, const f_string_t why) {
 
@@ -422,6 +444,7 @@ extern "C" {
     f_array_length_t j = 0;
     f_array_length_t k = 0;
 
+    controller_rule_t *rule = &setting->rules.array[index];
     controller_rule_item_t *item = 0;
     controller_rule_action_t *action = 0;
 
@@ -435,52 +458,60 @@ extern "C" {
     const f_string_dynamics_t arguments_none = f_string_dynamics_t_initialize;
     fl_execute_parameter_t parameter = fl_macro_execute_parameter_t_initialize(0, &environment, &signals, 0);
 
-    status = fll_environment_load_names(setting->rules.array[index].environment, &environment);
+    status = fll_environment_load_names(rule->environment, &environment);
 
     if (F_status_is_error(status)) {
       fll_error_print(data->error, F_status_set_fine(status), "fll_environment_load_names", F_true);
       return status;
     }
 
-    for (i = 0; i < setting->rules.array[index].items.used; ++i) {
+    for (i = 0; i < rule->items.used; ++i) {
 
-      if (setting->rules.array[index].items.array[i].type == controller_rule_item_type_setting) continue;
+      if (rule->items.array[i].type == controller_rule_item_type_setting) continue;
 
-      item = &setting->rules.array[index].items.array[i];
+      item = &rule->items.array[i];
 
       for (j = 0; j < item->actions.used; ++j) {
 
         if (item->actions.array[j].type != type) continue;
 
         action = &item->actions.array[j];
-        status = F_none;
 
         parameter.data = 0;
         parameter.option = 0;
 
         if (item->type == controller_rule_item_type_command) {
-          if (action->method == controller_rule_action_method_extended) {
-            // @todo
-          }
-          else {
-            // @todo extended list execution.
+
+          if (strchr(action->parameters.array[0].string, f_path_separator_s[0])) {
+            parameter.option |= fl_execute_parameter_option_path;
           }
+
+          status = controller_rule_execute_foreground(item->type, *action, 0, action->parameters, 0, &parameter, data);
+          if (F_status_is_error(status)) break;
         }
         else if (item->type == controller_rule_item_type_script) {
           parameter.data = &action->parameters.array[0];
 
-          status = controller_rule_execute_script(*action, 0, arguments_none, &parameter, data);
+          if (rule->script.used && strchr(rule->script.string, f_path_separator_s[0])) {
+            parameter.option |= fl_execute_parameter_option_path;
+          }
+
+          status = controller_rule_execute_foreground(item->type, *action, rule->script.used ? rule->script.string : controller_default_program_script, arguments_none, 0, &parameter, data);
           if (F_status_is_error(status)) break;
         }
         else if (item->type == controller_rule_item_type_service) {
-          if (action->method == controller_rule_action_method_extended) {
-            // @todo
-          }
-          else {
-            // @todo extended list execution.
+
+          if (strchr(action->parameters.array[0].string, f_path_separator_s[0])) {
+            parameter.option |= fl_execute_parameter_option_path;
           }
+
+          // @todo
+          //status = controller_rule_execute_background(item->type, *action, 0, action->parameters, 0, &parameter, data);
+          //if (F_status_is_error(status)) break;
         }
         else {
+          status = F_none;
+
           // unknown, just ignore for now. (@todo print a warning when in debug mode.)
           continue;
         }
@@ -488,7 +519,7 @@ extern "C" {
         if (status == F_child || status == F_signal) break;
       } // for
 
-      if (status == F_child || status == F_signal) break;
+      if (status == F_child || status == F_signal || F_status_is_error(status)) break;
     } // for
 
     fl_string_maps_delete(&environment);
@@ -497,12 +528,11 @@ extern "C" {
   }
 #endif // _di_controller_rule_execute_
 
-#ifndef _di_controller_rule_execute_script_
-  f_return_status controller_rule_execute_script(const controller_rule_action_t action, const uint8_t options, const f_string_dynamics_t arguments, fl_execute_parameter_t * const parameter, controller_data_t *data) {
+#ifndef _di_controller_rule_execute_foreground_
+  f_return_status 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, fl_execute_parameter_t * const parameter, controller_data_t *data) {
     int result = 0;
 
-    // @todo script program (such as: "bash") should be configurable somehow (a new entry setting? a new rule setting? both?).
-    f_status_t status = fll_execute_program(controller_string_bash, arguments, parameter, &result);
+    f_status_t status = fll_execute_program(program, arguments, parameter, &result);
 
     if (status == F_child) {
       data->child = result;
@@ -511,19 +541,26 @@ extern "C" {
     }
 
     if (result != 0) {
-      controller_rule_error_print_execute(data->error, F_false, controller_string_bash, result);
-
       status = F_status_set_error(F_failure);
     }
-    else if (F_status_is_error(status)) {
-      fll_error_print(data->error, F_status_set_fine(status), "fll_execute_program_environment", F_true);
+
+    if (F_status_is_error(status)) {
+      if (F_status_set_fine(status) == F_failure) {
+        controller_rule_error_print_execute(data->error, type == controller_rule_item_type_script, program, result);
+      }
+      else if (F_status_set_fine(status) == F_file_found_not) {
+        controller_rule_error_print_execute_not_found(data->error, F_false, program);
+      }
+      else {
+        fll_error_print(data->error, F_status_set_fine(status), "fll_execute_program_environment", F_true);
+      }
     }
 
     data->child = 0;
 
     return status;
   }
-#endif // _di_controller_rule_execute_script_
+#endif // _di_controller_rule_execute_foreground_
 
 #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) {
@@ -1136,7 +1173,6 @@ extern "C" {
         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);
           controller_rule_error_print(data->error, *cache, F_true);
         }
 
@@ -1445,6 +1481,9 @@ extern "C" {
       else if (fl_string_dynamic_compare_string(controller_string_path, cache->name_item, controller_string_path_length) == F_equal_to) {
         type = controller_rule_setting_type_path;
       }
+      else if (fl_string_dynamic_compare_string(controller_string_script, cache->name_item, controller_string_script_length) == F_equal_to) {
+        type = controller_rule_setting_type_script;
+      }
       else if (fl_string_dynamic_compare_string(controller_string_want, cache->name_item, controller_string_want_length) == F_equal_to) {
         type = controller_rule_setting_type_want;
       }
@@ -1599,7 +1638,7 @@ extern "C" {
         continue;
       }
 
-      if (type == controller_rule_setting_type_control_group || type == controller_rule_setting_type_name || type == controller_rule_setting_type_path) {
+      if (type == controller_rule_setting_type_control_group || type == controller_rule_setting_type_name || type == controller_rule_setting_type_path || type == controller_rule_setting_type_script) {
         if (type == controller_rule_setting_type_control_group) {
           setting_value = &rule->control_group;
         }
@@ -1609,6 +1648,9 @@ extern "C" {
         else if (type == controller_rule_setting_type_path) {
           setting_value = &rule->path;
         }
+        else if (type == controller_rule_setting_type_script) {
+          setting_value = &rule->script;
+        }
 
         if (setting_value->used || cache->content_actions.array[i].used != 1) {
           fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
@@ -1625,7 +1667,7 @@ extern "C" {
 
         setting_value->used = 0;
 
-        if (type == controller_rule_setting_type_control_group || type == controller_rule_setting_type_name) {
+        if (type == controller_rule_setting_type_control_group || type == controller_rule_setting_type_name || type == controller_rule_setting_type_script) {
 
           status = controller_string_dynamic_rip_nulless_terminated(cache->buffer_item, cache->content_actions.array[i].array[0], setting_value);
 
@@ -2074,9 +2116,8 @@ extern "C" {
           fprintf(data.output.stream, "    %s%s%s {%c", data.context.set.important.before->string, controller_string_action, data.context.set.important.after->string, f_string_eol_s[0]);
 
           fprintf(data.output.stream, "      %s%s%s %s%c", data.context.set.important.before->string, controller_string_type, data.context.set.important.after->string, controller_rule_action_type_name(action->type).string, f_string_eol_s[0]);
-          fprintf(data.output.stream, "      %s%s%s %s%c", data.context.set.important.before->string, controller_string_method, data.context.set.important.after->string, controller_rule_action_method_name(action->method).string, f_string_eol_s[0]);
 
-          if (action->method == controller_rule_action_method_extended_list && item->type == controller_rule_item_type_script) {
+          if (item->type == controller_rule_item_type_script) {
             fprintf(data.output.stream, "      %s%s%s {%c", data.context.set.important.before->string, controller_string_parameter, data.context.set.important.after->string, f_string_eol_s[0]);
 
             parameter = &action->parameters.array[0];
index 3f79c12f55a3bce2cceb400ac57a9012f895bbbf..7f462158842c40c1373dbd48038615dc38ea290f 100644 (file)
@@ -157,19 +157,34 @@ extern "C" {
  *
  * @param output
  *   The error or warning output structure.
- * @param program_is
- *   If TRUE, then this represents a program.
- *   If FALSE, then this represents a script.
+ * @param script_is
+ *   If TRUE, then this represents a script.
+ *   If FALSE, then this represents a program.
  * @param name
  *   The name of the program or script.
  * @param code
  *   The code returned by the executed program or script.
  */
 #ifndef _di_controller_rule_error_print_execute_
-  extern void controller_rule_error_print_execute(const fll_error_print_t output, const bool program_is, const f_string_t name, const int code) f_gcc_attribute_visibility_internal;
+  extern void controller_rule_error_print_execute(const fll_error_print_t output, const bool script_is, const f_string_t name, const int code) f_gcc_attribute_visibility_internal;
 #endif // _di_controller_rule_error_print_execute_
 
 /**
+ * Print an error or warning message related to the failed execution of some program or script for when the program or script is not found.
+ *
+ * @param output
+ *   The error or warning output structure.
+ * @param script_is
+ *   If TRUE, then this represents a script.
+ *   If FALSE, then this represents a program.
+ * @param code
+ *   The code returned by the executed program or script.
+ */
+#ifndef _di_controller_rule_error_print_execute_not_found_
+  extern void controller_rule_error_print_execute_not_found(const fll_error_print_t output, const bool script_is, const f_string_t name) f_gcc_attribute_visibility_internal;
+#endif // _di_controller_rule_error_print_execute_not_found_
+
+/**
  * Print an error or warning message related to need/want/wish settings of some rule.
  *
  * @param output
@@ -220,8 +235,10 @@ extern "C" {
 #endif // _di_controller_rule_execute_
 
 /**
- * Perform an execution of the given rule for the script execution type.
+ * Perform an execution of the given rule in the foreground.
  *
+ * @param type
+ *   The item type code.
  * @param action
  *   The action to perform based on the action type codes.
  *
@@ -231,12 +248,14 @@ extern "C" {
  *   - controller_rule_action_type_restart
  *   - controller_rule_action_type_start
  *   - controller_rule_action_type_stop
+ * @param program
+ *   The script program to use (such as "bash").
+ * @param arguments
+ *   The arguments to pass to the script.
  * @param options
  *   The controller execute options (and not fl_execute_parameter_t.option).
  *   This is for designating asynchronous and other controller specific execution options.
  *   @todo this is not yet implemented.
- * @param arguments
- *   The arguments to pass to the script.
  * @param parameter
  *   The execute parameter settings.
  * @param data
@@ -251,9 +270,9 @@ extern "C" {
  *
  * @see fll_execute_program()
  */
-#ifndef _di_controller_rule_execute_script_
-  extern f_return_status controller_rule_execute_script(const controller_rule_action_t action, const uint8_t options, const f_string_dynamics_t arguments, fl_execute_parameter_t * const parameter, controller_data_t *data) f_gcc_attribute_visibility_internal;
-#endif // _di_controller_rule_execute_script_
+#ifndef _di_controller_rule_execute_foreground_
+  extern f_return_status 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, fl_execute_parameter_t * const parameter, controller_data_t *data) f_gcc_attribute_visibility_internal;
+#endif // _di_controller_rule_execute_foreground_
 
 /**
  * Search the already loaded rules to see if one is found.
diff --git a/level_3/controller/data/settings/example/entries/test.entry b/level_3/controller/data/settings/example/entries/test.entry
new file mode 100644 (file)
index 0000000..2cfb52d
--- /dev/null
@@ -0,0 +1,25 @@
+# fss-0005
+
+main:
+  timeout start 7
+  timeout stop 7
+  timeout kill 3
+
+  failsafe boom
+
+  item first
+  item last
+
+first:
+  rule script succeed
+  rule script php
+  rule command multiple
+
+  # uncomment python to see it fail.
+  #rule script python
+
+last:
+  rule script fail
+
+boom:
+  rule maintenance explode
diff --git a/level_3/controller/data/settings/example/rules/command/multiple.rule b/level_3/controller/data/settings/example/rules/command/multiple.rule
new file mode 100644 (file)
index 0000000..dfc6144
--- /dev/null
@@ -0,0 +1,10 @@
+# fss-000d
+
+setting:
+  name "Multiple Commands: whoami and date"
+
+command:
+  start whoami
+
+command:
+  start date
diff --git a/level_3/controller/data/settings/example/rules/maintenance/explode.rule b/level_3/controller/data/settings/example/rules/maintenance/explode.rule
new file mode 100644 (file)
index 0000000..97b6fba
--- /dev/null
@@ -0,0 +1,11 @@
+# fss-000d
+
+setting:
+  name "Explosion!"
+  script sh
+
+script:
+  start {
+    echo "kaboooom!"
+  }
+
diff --git a/level_3/controller/data/settings/example/rules/script/fail.rule b/level_3/controller/data/settings/example/rules/script/fail.rule
new file mode 100644 (file)
index 0000000..e2671cf
--- /dev/null
@@ -0,0 +1,17 @@
+# fss-000d
+
+setting:
+  name "Scipt #2"
+  need script succeed
+
+script:
+  start {
+    \#!/bin/bash
+    my_function() {
+      echo "Hello this is the second script."
+      return 1;
+    \}
+
+    my_function
+  }
+
diff --git a/level_3/controller/data/settings/example/rules/script/php.rule b/level_3/controller/data/settings/example/rules/script/php.rule
new file mode 100644 (file)
index 0000000..cb67fd5
--- /dev/null
@@ -0,0 +1,21 @@
+# fss-000d
+
+setting:
+  name "PHP script"
+  environment PATH
+  script php
+
+script:
+  start {
+    <?php
+    print("\nThis is a PHP script.\n\n");
+
+    print(date("Y/m/d h:i:s a") . "\n\n");
+
+    var_dump(getenv());
+    print("\n");
+
+    print("Now executing 'date' program, assuming that it exists in \$PATH.\n");
+    passthru("date");
+    print("\n");
+  }
diff --git a/level_3/controller/data/settings/example/rules/script/python.rule b/level_3/controller/data/settings/example/rules/script/python.rule
new file mode 100644 (file)
index 0000000..57fabb2
--- /dev/null
@@ -0,0 +1,14 @@
+# fss-000d
+
+setting:
+  name "Python (Version 3.X) script"
+  environment PATH
+  script python3
+
+script:
+  start {
+    # Python's indentation design presents problems here and this will likely fail with "IndentationError: unexpected indent"
+    print("This is a Python script.\n");
+
+    # this is simply a design flaw of Python and as such Python scripts must not be tabbed over (making these files less readable).
+  }
diff --git a/level_3/controller/data/settings/example/rules/script/succeed.rule b/level_3/controller/data/settings/example/rules/script/succeed.rule
new file mode 100644 (file)
index 0000000..9080c60
--- /dev/null
@@ -0,0 +1,17 @@
+# fss-000d
+
+setting:
+  name "Scipt #1"
+  environment PATH
+  script sh
+
+script:
+  start {
+    echo
+    echo "Hello this is script #1 and should succeed."
+    echo
+
+    date
+    echo
+  }
+
index c1defe0682a0a553645d0ebf47c52287fc067df7..4836c2fa3054b1a5aa7f1094b0164666aca5b42d 100644 (file)
@@ -16,6 +16,7 @@ Rule Documentation:
     "need": A single rule required to be executed (must exist and must succeed) before this rule starts.
     "parameter": A statically defined IKI name and its associated value for use in this rule file.
     "path": A single Content used to set a custom PATH environment variable value.
+    "script": An executable name of a script, such as "bash", to use for the "script" Rule Type (which likely defaults to "bash" if not specified).
     "want": A single rule desired to be executed (may exist and must succeed) before this rule starts.
     "wish": A single rule desired to be executed (may exist and is not required to succeed) before this rule starts.
 
@@ -29,13 +30,13 @@ Rule Documentation:
   A "parameter" variable and an "environment" variable are mutually exclusive but an environment variable, in theory, can have an IKI variable assigned to it inside of a "script".
   These IKI variables are only substituted within a Rule Item's Content (and not within a Rule Setting nor within a Rule Item's Object).
 
-  The "command" outer most part provides a simple command to run under the different circumstances: "start", "stop", "restart", and "reload".
+  The "command" Rule Type provides a simple command to run under the different circumstances: "start", "stop", "restart", and "reload".
   A "command" always operates in the foreground.
 
-  The "service" outer most part provides a "command" accompanied with a PID file (Process Identifier file).
+  The "service" Rule Type provides a "command" accompanied with a PID file (Process Identifier file).
   Unlike the "command", a "service" always operates in the background.
 
-  The "script" outer most part provides a series of lines to be executed by a (Bash) script.
+  The "script" Rule Type provides a series of lines to be executed by a (Bash) script.
   This "script" operates in the foreground, but individual things done within the script may operate in foreground or background.
   The last return state is treated as an error, so be sure to finish the script with a return code of 0 to designate no error and any other whole number, such a 1, to designate an error.
   Therefore passing "exit 1" would return as an error and passing "exit 0" would return as a success.
index 769c70603095c1ccaf90cce6e9d06ad5d9edbf0d..7de6cc0321f2c9ad804d88b7189960a6ab6bdec7 100644 (file)
@@ -35,6 +35,7 @@ Rule Specification:
     "need": Two Content, the first being a partial path and the second being a rule file name without extension (such as "boot" "modules").
     "parameter": Two Content, the first Content must be a case-sensitive valid IKI name and the second being an IKI value.
     "path": One Content representing a valid PATH environment string (such as "/bin:/sbin:/usr/bin").
+    "script": One Content representing a valid program name or path (such as "bash" or "/bin/bash").
     "want": Two Content, the first being a partial path and the second being a rule file name without extension (such as "boot" "modules").
     "wish": Two Content, the first being a partial path and the second being a rule file name without extension (such as "boot" "modules").