From bf6b35d908440cb5b23ae505caab125d02e94686 Mon Sep 17 00:00:00 2001 From: Kevin Day Date: Sat, 19 Dec 2020 22:04:04 -0600 Subject: [PATCH] Progress: controller program and execute function improvements. 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. --- level_1/fl_execute/c/execute-common.h | 10 +- level_2/fll_execute/c/execute.c | 14 +- level_2/fll_execute/c/execute.h | 3 +- level_2/fll_execute/c/private-execute.c | 36 ++-- level_2/fll_execute/c/private-execute.h | 8 +- level_3/controller/c/controller.h | 2 + level_3/controller/c/private-common.h | 6 +- level_3/controller/c/private-rule.c | 239 ++++++++++++--------- level_3/controller/c/private-rule.h | 39 +++- .../data/settings/example/entries/test.entry | 25 +++ .../settings/example/rules/command/multiple.rule | 10 + .../example/rules/maintenance/explode.rule | 11 + .../data/settings/example/rules/script/fail.rule | 17 ++ .../data/settings/example/rules/script/php.rule | 21 ++ .../data/settings/example/rules/script/python.rule | 14 ++ .../settings/example/rules/script/succeed.rule | 17 ++ level_3/controller/documents/rule.txt | 7 +- level_3/controller/specifications/rule.txt | 1 + 18 files changed, 331 insertions(+), 149 deletions(-) create mode 100644 level_3/controller/data/settings/example/entries/test.entry create mode 100644 level_3/controller/data/settings/example/rules/command/multiple.rule create mode 100644 level_3/controller/data/settings/example/rules/maintenance/explode.rule create mode 100644 level_3/controller/data/settings/example/rules/script/fail.rule create mode 100644 level_3/controller/data/settings/example/rules/script/php.rule create mode 100644 level_3/controller/data/settings/example/rules/script/python.rule create mode 100644 level_3/controller/data/settings/example/rules/script/succeed.rule diff --git a/level_1/fl_execute/c/execute-common.h b/level_1/fl_execute/c/execute-common.h index ec4b7bd..3efb1b7 100644 --- a/level_1/fl_execute/c/execute-common.h +++ b/level_1/fl_execute/c/execute-common.h @@ -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; diff --git a/level_2/fll_execute/c/execute.c b/level_2/fll_execute/c/execute.c index ab24c35..38145ed 100644 --- a/level_2/fll_execute/c/execute.c +++ b/level_2/fll_execute/c/execute.c @@ -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) { diff --git a/level_2/fll_execute/c/execute.h b/level_2/fll_execute/c/execute.h index 06ebe0f..00c18bd 100644 --- a/level_2/fll_execute/c/execute.h +++ b/level_2/fll_execute/c/execute.h @@ -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 diff --git a/level_2/fll_execute/c/private-execute.c b/level_2/fll_execute/c/private-execute.c index 57ffae9..eae5406 100644 --- a/level_2/fll_execute/c/private-execute.c +++ b/level_2/fll_execute/c/private-execute.c @@ -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_) diff --git a/level_2/fll_execute/c/private-execute.h b/level_2/fll_execute/c/private-execute.h index 8cf49db..96c9b7a 100644 --- a/level_2/fll_execute/c/private-execute.h +++ b/level_2/fll_execute/c/private-execute.h @@ -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 diff --git a/level_3/controller/c/controller.h b/level_3/controller/c/controller.h index cb95aa6..632a465 100644 --- a/level_3/controller/c/controller.h +++ b/level_3/controller/c/controller.h @@ -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" diff --git a/level_3/controller/c/private-common.h b/level_3/controller/c/private-common.h index 999442d..dbe8fdc 100644 --- a/level_3/controller/c/private-common.h +++ b/level_3/controller/c/private-common.h @@ -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); \ diff --git a/level_3/controller/c/private-rule.c b/level_3/controller/c/private-rule.c index 666ec89..04bb3b3 100644 --- a/level_3/controller/c/private-rule.c +++ b/level_3/controller/c/private-rule.c @@ -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, ¶meter, 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, ¶meter, 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, ¶meter, 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, ¶meter, 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]; diff --git a/level_3/controller/c/private-rule.h b/level_3/controller/c/private-rule.h index 3f79c12..7f46215 100644 --- a/level_3/controller/c/private-rule.h +++ b/level_3/controller/c/private-rule.h @@ -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 index 0000000..2cfb52d --- /dev/null +++ b/level_3/controller/data/settings/example/entries/test.entry @@ -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 index 0000000..dfc6144 --- /dev/null +++ b/level_3/controller/data/settings/example/rules/command/multiple.rule @@ -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 index 0000000..97b6fba --- /dev/null +++ b/level_3/controller/data/settings/example/rules/maintenance/explode.rule @@ -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 index 0000000..e2671cf --- /dev/null +++ b/level_3/controller/data/settings/example/rules/script/fail.rule @@ -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 index 0000000..cb67fd5 --- /dev/null +++ b/level_3/controller/data/settings/example/rules/script/php.rule @@ -0,0 +1,21 @@ +# fss-000d + +setting: + name "PHP script" + environment PATH + script php + +script: + start { +