From: Kevin Day Date: Wed, 16 Dec 2020 04:15:19 +0000 (-0600) Subject: Progress: controller program. X-Git-Tag: 0.5.2~12 X-Git-Url: https://git.kevux.org/?a=commitdiff_plain;h=7b64516b44506c50d39d918b364bf5744dc01a73;p=fll Progress: controller program. --- diff --git a/level_3/controller/c/private-common.h b/level_3/controller/c/private-common.h index 881bcd3..c6a6e7e 100644 --- a/level_3/controller/c/private-common.h +++ b/level_3/controller/c/private-common.h @@ -27,12 +27,14 @@ extern "C" { #define controller_string_environment "environment" #define controller_string_failsafe "failsafe" #define controller_string_group "group" + #define controller_string_how "how" #define controller_string_item "item" #define controller_string_kill "kill" #define controller_string_main "main" #define controller_string_method "method" #define controller_string_name "name" #define controller_string_need "need" + #define controller_string_no "no" #define controller_string_parameter "parameter" #define controller_string_path "path" #define controller_string_pid "pid" @@ -47,6 +49,7 @@ extern "C" { #define controller_string_setting "setting" #define controller_string_start "start" #define controller_string_stop "stop" + #define controller_string_synchronous "synchronous" #define controller_string_timeout "timeout" #define controller_string_type "type" #define controller_string_use "use" @@ -54,6 +57,7 @@ extern "C" { #define controller_string_wait "wait" #define controller_string_want "want" #define controller_string_wish "wish" + #define controller_string_yes "yes" #define controller_string_action_length 6 #define controller_string_actions_length 7 @@ -69,12 +73,14 @@ extern "C" { #define controller_string_environment_length 11 #define controller_string_failsafe_length 8 #define controller_string_group_length 5 + #define controller_string_how_length 3 #define controller_string_item_length 4 #define controller_string_kill_length 4 #define controller_string_main_length 4 #define controller_string_method_length 6 #define controller_string_name_length 4 #define controller_string_need_length 4 + #define controller_string_no_length 2 #define controller_string_parameter_length 9 #define controller_string_path_length 4 #define controller_string_pid_length 3 @@ -89,6 +95,7 @@ extern "C" { #define controller_string_setting_length 7 #define controller_string_start_length 5 #define controller_string_stop_length 4 + #define controller_string_synchronous_length 11 #define controller_string_timeout_length 7 #define controller_string_type_length 4 #define controller_string_use_length 3 @@ -96,6 +103,7 @@ extern "C" { #define controller_string_wait_length 4 #define controller_string_want_length 4 #define controller_string_wish_length 4 + #define controller_string_yes_length 3 #endif // _di_controller_string_ #ifndef _di_controller_rule_action_t_ @@ -235,6 +243,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 + typedef struct { f_status_t status; f_number_signed_t process; // @todo: for background/threaded support (ideally should hold the process id, but remove if this ends up not being the strategy) (this can also be used by the parent/main process to check to see if the child no longer a child of this process). diff --git a/level_3/controller/c/private-controller.c b/level_3/controller/c/private-controller.c index 27cd1e4..92221c7 100644 --- a/level_3/controller/c/private-controller.c +++ b/level_3/controller/c/private-controller.c @@ -228,15 +228,20 @@ extern "C" { // report pid file error but because this could be an "init" program, consider the pid file as optional and continue on. if (F_status_is_error(status)) { - fll_error_file_print(data.error, F_status_set_fine(status), "controller_file_pid_create", F_true, setting->path_pid.string, "create", fll_error_file_type_file); - - controller_entry_error_print(data.error, *cache); // always return immediately on memory errors. if (F_status_set_fine(status) == F_memory_not || F_status_set_fine(status) == F_memory_allocation || F_status_set_fine(status) == F_memory_reallocation) { + fll_error_file_print(data.error, F_status_set_fine(status), "controller_file_pid_create", F_true, setting->path_pid.string, "create", fll_error_file_type_file); + + controller_entry_error_print(data.error, *cache); + return status; } + fll_error_file_print(data.warning, F_status_set_fine(status), "controller_file_pid_create", F_true, setting->path_pid.string, "create", fll_error_file_type_file); + + controller_entry_error_print(data.warning, *cache); + status = F_none; } } @@ -472,6 +477,8 @@ extern "C" { f_array_length_t at_i = 0; f_array_length_t at_j = 1; + uint8_t rule_options = 0; + controller_entry_actions_t *actions = 0; const bool simulate = data.parameters[controller_parameter_test].result == f_console_result_found; @@ -540,14 +547,96 @@ extern "C" { } if (F_status_is_error(actions->array[cache->ats.array[at_j]].status)) { - 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, "' is in a %sfailed%s state, skipping execution.%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]); + + 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); + + 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, "' 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 (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, "%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); + + 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); + + 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, "%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); + } } else { - // @todo check to see if this rule is "required" and if so immediately fail, otherwise report a failure as a warning (normal verbosity, not debug verbosity). + 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); + + 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, "' 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); + + 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, "%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); + } } continue; @@ -574,7 +663,7 @@ extern "C" { 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 is already ready.%c", f_string_eol_s[0]); + 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) { @@ -667,9 +756,43 @@ extern "C" { fprintf(data.output.stream, "'.%c", f_string_eol_s[0]); } + // the rule is not yet loaded, ensure that it is loaded. if (at == setting->rules.used) { + + // rule execution will re-use the existing cache, so save the current cache. + const f_array_length_t cache_line_action = cache->line_action; + const f_array_length_t cache_line_item = cache->line_item; + + const f_string_length_t cache_name_action_used = cache->name_action.used; + const f_string_length_t cache_name_item_used = cache->name_item.used; + const f_string_length_t cache_name_file_used = cache->name_file.used; + + char cache_name_action[cache_name_action_used]; + char cache_name_item[cache_name_item_used]; + char cache_name_file[cache_name_file_used]; + + memcpy(cache_name_action, cache->name_action.string, cache->name_action.used); + 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]); + // restore cache. + memcpy(cache->name_action.string, cache_name_action, cache_name_action_used); + memcpy(cache->name_item.string, cache_name_item, cache_name_item_used); + memcpy(cache->name_file.string, cache_name_file, cache_name_file_used); + + cache->name_action.string[cache_name_action_used] = 0; + cache->name_item.string[cache_name_item_used] = 0; + cache->name_file.string[cache_name_file_used] = 0; + + cache->name_action.used = cache_name_action_used; + cache->name_item.used = cache_name_item_used; + cache->name_file.used = cache_name_file_used; + + cache->line_action = cache_line_action; + cache->line_item = cache_line_item; + if (F_status_is_error(status)) { controller_entry_error_print(data.error, *cache); @@ -699,8 +822,22 @@ extern "C" { memcpy(cache_name_file, cache->name_file.string, cache->name_file.used); if (actions->array[cache->ats.array[at_j]].type == controller_entry_action_type_rule) { + rule_options = 0; + + if (simulate) { + rule_options |= controller_rule_option_simulate; + } + + if (actions->array[cache->ats.array[at_j]].code & controller_entry_rule_code_asynchronous) { + rule_options |= controller_rule_option_asynchronous; + } + + 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, simulate, setting, cache); + status = controller_rule_process(data, at, rule_options, setting, cache); } // restore cache. @@ -793,7 +930,6 @@ extern "C" { } } } - } // for cache->line_action = 0; diff --git a/level_3/controller/c/private-entry.c b/level_3/controller/c/private-entry.c index 6b677b6..ba80d29 100644 --- a/level_3/controller/c/private-entry.c +++ b/level_3/controller/c/private-entry.c @@ -7,6 +7,24 @@ extern "C" { #endif +#ifndef _di_controller_entry_action_parameters_print_ + void controller_entry_action_parameters_print(FILE * const stream, const controller_entry_action_t action) { + + f_array_length_t index = 0; + + for (;;) { + + f_print_dynamic(stream, action.parameters.array[index]); + + ++index; + + if (index == action.parameters.used) break; + + fprintf(stream, " "); + } // for + } +#endif // _di_controller_entry_action_parameters_print_ + #ifndef _di_controller_entry_action_type_name_ f_string_static_t controller_entry_action_type_name(const uint8_t type) { @@ -396,13 +414,13 @@ extern "C" { for (j = 2; j < action->parameters.used; ++j) { if (fl_string_dynamic_compare_string(controller_string_asynchronous, action->parameters.array[j], controller_string_asynchronous_length) == F_equal_to) { - action->code = controller_entry_rule_code_asynchronous; + action->code |= controller_entry_rule_code_asynchronous; } else if (fl_string_dynamic_compare_string(controller_string_require, action->parameters.array[j], controller_string_require_length) == F_equal_to) { - action->code = controller_entry_rule_code_require; + action->code |= controller_entry_rule_code_require; } else if (fl_string_dynamic_compare_string(controller_string_wait, action->parameters.array[j], controller_string_wait_length) == F_equal_to) { - action->code = controller_entry_rule_code_wait; + action->code |= controller_entry_rule_code_wait; } else { if (action->status == F_none) { diff --git a/level_3/controller/c/private-entry.h b/level_3/controller/c/private-entry.h index 1db153f..90d5744 100644 --- a/level_3/controller/c/private-entry.h +++ b/level_3/controller/c/private-entry.h @@ -13,6 +13,18 @@ extern "C" { #endif /** + * Print all parameters for some action, separated by a space. + * + * @param stream + * The file stream to print to. + * @param action + * The entry action whose parameters will be printed. + */ +#ifndef _di_controller_entry_action_parameters_print_ + extern void controller_entry_action_parameters_print(FILE * const stream, const controller_entry_action_t action) f_gcc_attribute_visibility_internal; +#endif // _di_controller_entry_action_parameters_print_ + +/** * Get a string representing the entry action type. * * @param type diff --git a/level_3/controller/c/private-rule.c b/level_3/controller/c/private-rule.c index 459c07a..a86f4bf 100644 --- a/level_3/controller/c/private-rule.c +++ b/level_3/controller/c/private-rule.c @@ -728,7 +728,7 @@ 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 bool simulate, controller_setting_t *setting, controller_cache_t *cache) { + 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) { if (index >= setting->rules.used) { fll_error_print(data.error, F_parameter, "controller_rule_process", F_true); @@ -817,8 +817,8 @@ extern "C" { controller_rule_t *rule = &setting->rules.array[index]; - if (simulate && data.parameters[controller_parameter_validate].result == f_console_result_found) { - controller_rule_simulate(data, *cache, index, setting); + if ((options & controller_rule_option_simulate) && data.parameters[controller_parameter_validate].result == f_console_result_found) { + controller_rule_simulate(data, *cache, index, options, setting); } { @@ -850,7 +850,7 @@ extern "C" { status = F_status_set_error(F_found_not); controller_rule_error_print(data.error, *cache, F_true); - if (!simulate) break; + if (!(options & controller_rule_option_simulate)) break; } else { if (data.warning.verbosity == f_console_verbosity_debug) { @@ -895,7 +895,7 @@ 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, simulate, setting, cache); + status = controller_rule_process(data, at, options, setting, cache); // restore cache. memcpy(cache->name_action.string, cache_name_action, cache_name_action_used); @@ -918,7 +918,7 @@ extern "C" { 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 (!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) { + 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; } } @@ -938,7 +938,7 @@ extern "C" { status = F_status_set_error(F_found_not); controller_rule_error_print(data.error, *cache, F_true); - if (!simulate) break; + if (!(options & controller_rule_option_simulate)) break; } else { if (data.warning.verbosity == f_console_verbosity_debug) { @@ -950,11 +950,11 @@ extern "C" { } } // for - if (F_status_is_error(status) && !simulate) break; + if (F_status_is_error(status) && !(options & controller_rule_option_simulate)) break; } // for } - if (!simulate && F_status_is_error_not(status)) { + 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)) { @@ -1721,7 +1721,7 @@ 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, 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 options, controller_setting_t *setting) { // @todo this needs the "action" in which to perform, such as "start", "stop", "restart", etc.. @@ -1731,6 +1731,8 @@ extern "C" { 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; diff --git a/level_3/controller/c/private-rule.h b/level_3/controller/c/private-rule.h index 6c7545b..50454b1 100644 --- a/level_3/controller/c/private-rule.h +++ b/level_3/controller/c/private-rule.h @@ -351,9 +351,11 @@ extern "C" { * The program data. * @param index * Position in the rules array representing the rule to execute - * @param simulate - * If TRUE, then the rule execution is simulated (printing a message that the rule would be executed but does not execut the rule). - * If FALSE, the rule is not simulated and is executed as normal. + * @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 setting * The controller settings data. * @param cache @@ -365,7 +367,7 @@ extern "C" { * F_none on success. */ #ifndef _di_controller_rule_process_ - extern f_return_status controller_rule_process(const controller_data_t data, const f_array_length_t index, const bool simulate, controller_setting_t *setting, controller_cache_t *cache) f_gcc_attribute_visibility_internal; + 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; #endif // _di_controller_rule_process_ /** @@ -454,11 +456,16 @@ 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 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 setting * 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, 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 options, controller_setting_t *setting) f_gcc_attribute_visibility_internal; #endif // _di_controller_rule_simulate_ /**