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