From 6f3ac7ac0c059d926c1d5b3ebc984cef0bad2592 Mon Sep 17 00:00:00 2001 From: Kevin Day Date: Sun, 6 Dec 2020 17:45:41 -0600 Subject: [PATCH] Progress: controller program. Add the daemon mode where controller does not act like an init program. --- level_3/controller/c/controller.c | 96 ++++-- level_3/controller/c/controller.h | 6 +- level_3/controller/c/private-common.h | 2 + level_3/controller/c/private-controller.c | 342 ++++++++++++++++++--- level_3/controller/c/private-controller.h | 115 ++++++- level_3/controller/c/private-entry.c | 56 +--- level_3/controller/c/private-entry.h | 18 +- .../controller/data/settings/entries/default.entry | 4 +- 8 files changed, 508 insertions(+), 131 deletions(-) diff --git a/level_3/controller/c/controller.c b/level_3/controller/c/controller.c index 71fb725..d95d6ad 100644 --- a/level_3/controller/c/controller.c +++ b/level_3/controller/c/controller.c @@ -26,11 +26,12 @@ extern "C" { fprintf(output.stream, "%c", f_string_eol[0]); + fll_program_print_help_option(output, context, controller_short_daemon, controller_long_daemon, f_console_symbol_short_enable, f_console_symbol_long_enable, " Run in daemon only mode (do not process the entry)."); fll_program_print_help_option(output, context, controller_short_interruptable, controller_long_interruptable, f_console_symbol_short_enable, f_console_symbol_long_enable, "Designate that this program can be interrupted."); fll_program_print_help_option(output, context, controller_short_pid, controller_long_pid, f_console_symbol_short_enable, f_console_symbol_long_enable, " Specify a custom pid file path, such as '" controller_path_pid "'."); fll_program_print_help_option(output, context, controller_short_settings, controller_long_settings, f_console_symbol_short_enable, f_console_symbol_long_enable, " Specify a custom settings path, such as '" controller_path_settings "'."); fll_program_print_help_option(output, context, controller_short_test, controller_long_test, f_console_symbol_short_enable, f_console_symbol_long_enable, " Run in test mode, where nothing is actually run (a simulation)."); - fll_program_print_help_option(output, context, controller_short_validate, controller_long_validate, f_console_symbol_short_enable, f_console_symbol_long_enable, " Validate the settings (entry and rules)."); + fll_program_print_help_option(output, context, controller_short_validate, controller_long_validate, f_console_symbol_short_enable, f_console_symbol_long_enable, " Validate the settings (entry and rules) without running (or simulating)."); fll_program_print_help_usage(output, context, controller_name, "entry"); @@ -208,7 +209,7 @@ extern "C" { } } - // the pid file is required. + // a pid file path is required. if (!setting.path_pid.used) { status = fl_string_append(controller_path_pid, controller_path_pid_length, &setting.path_pid); @@ -219,43 +220,78 @@ extern "C" { } } - if (F_status_is_error_not(status)) { - status = controller_entry_read(*data, setting, entry_name, &cache, &setting.entry); + if (data->parameters[controller_parameter_daemon].result == f_console_result_found) { - // @fixme this is temporary and may or may not be used when finished codestorming. - if (F_status_is_error(setting.entry.status)) { - status = setting.entry.status; - } - } + if (data->parameters[controller_parameter_validate].result == f_console_result_found) { + if (data->error.verbosity != f_console_verbosity_quiet) { + fprintf(data->error.to.stream, "%c", f_string_eol[0]); + fprintf(data->error.to.stream, "%s%sThe parameter '", data->error.context.before->string, data->error.prefix ? data->error.prefix : ""); + fprintf(data->error.to.stream, "%s%s%s%s%s", data->error.context.after->string, data->error.notable.before->string, f_console_symbol_long_enable, controller_long_validate, data->error.notable.after->string); + fprintf(data->error.to.stream, "%s' must not be specified with the parameter '", data->error.context.before->string); + fprintf(data->error.to.stream, "%s%s%s%s%s", data->error.context.after->string, data->error.notable.before->string, f_console_symbol_long_enable, controller_long_daemon, data->error.notable.after->string); + fprintf(data->error.to.stream, "%s'.%s%c", data->error.context.before->string, data->error.context.after->string, f_string_eol[0]); + } - if (F_status_is_error_not(status)) { - status = controller_preprocess_items(*data, &setting, &cache); - } + status = F_status_set_error(F_parameter); + } - if (F_status_is_error_not(status)) { + if (F_status_is_error_not(status)) { + setting.ready = controller_setting_ready_done; - if (data->parameters[controller_parameter_test].result == f_console_result_found || data->parameters[controller_parameter_validate].result == f_console_result_found) { - // @todo validate happens first, report and handle validation problems or success. + 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[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 : "", data->error.context.after->string, f_string_eol[0]); + } - if (data->parameters[controller_parameter_test].result == f_console_result_found) { - // @todo after validation succeeds, perform test run. + status = F_status_set_error(F_available_not); + setting.ready = controller_setting_ready_abort; } + + // @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); + } + } + else { + + if (F_status_is_error_not(status)) { + status = controller_entry_read(*data, setting, entry_name, &cache, &setting.entry); + } + + if (F_status_is_error(status)) { + setting.ready = controller_setting_ready_fail; } else { - // @todo check to see if the standard pid file exists before attempting to start (when in normal operation mode). - // @todo real execution. + status = controller_preprocess_entry(*data, &setting, &cache); - // @todo create pid file but not until "ready", so be sure to add this after pre-processing the entry file. - if (setting.ready) { - controller_file_pid_create(*data, setting.path_pid); - } + if (data->parameters[controller_parameter_validate].result == f_console_result_none) { - // @todo when everything is ready, wait here until told to quit. - // @todo clear cache periodically while waiting and no commands. - // controller_macro_cache_t_delete_simple(cache); + 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[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 : "", data->error.context.after->string, f_string_eol[0]); + } + + status = F_status_set_error(F_available_not); + setting.ready = controller_setting_ready_abort; + } - // @todo on failures that prevent normal execution: trigger failsafe/fallback execution, if defined - // @todo otherwise, set ready to controller_setting_ready_done. + if (F_status_is_error_not(status)) { + 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; + + // @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); + } + } } } @@ -273,6 +309,10 @@ extern "C" { controller_delete_data(data); + if (setting.ready == controller_setting_ready_fail) { + // @todo trigger failsafe/fallback execution, if defined. + } + return status; } #endif // _di_controller_main_ diff --git a/level_3/controller/c/controller.h b/level_3/controller/c/controller.h index cb95cd9..1ded520 100644 --- a/level_3/controller/c/controller.h +++ b/level_3/controller/c/controller.h @@ -78,12 +78,14 @@ extern "C" { #define controller_path_pid_length 34 #define controller_path_settings_length 15 + #define controller_short_daemon "d" #define controller_short_interruptable "i" #define controller_short_pid "p" #define controller_short_settings "s" #define controller_short_test "t" #define controller_short_validate "V" + #define controller_long_daemon "daemon" #define controller_long_interruptable "interruptable" #define controller_long_pid "pid" #define controller_long_settings "settings" @@ -101,6 +103,7 @@ extern "C" { controller_parameter_verbosity_debug, controller_parameter_version, + controller_parameter_daemon, controller_parameter_interruptable, controller_parameter_pid, controller_parameter_settings, @@ -119,6 +122,7 @@ extern "C" { f_console_parameter_t_initialize(f_console_standard_short_verbose, f_console_standard_long_verbose, 0, 0, f_console_type_inverse), \ f_console_parameter_t_initialize(f_console_standard_short_debug, f_console_standard_long_debug, 0, 0, f_console_type_inverse), \ f_console_parameter_t_initialize(f_console_standard_short_version, f_console_standard_long_version, 0, 0, f_console_type_inverse), \ + f_console_parameter_t_initialize(controller_short_daemon, controller_long_daemon, 0, 0, f_console_type_normal), \ f_console_parameter_t_initialize(controller_short_interruptable, controller_long_interruptable, 0, 0, f_console_type_normal), \ f_console_parameter_t_initialize(controller_short_pid, controller_long_pid, 0, 1, f_console_type_normal), \ f_console_parameter_t_initialize(controller_short_settings, controller_long_settings, 0, 1, f_console_type_normal), \ @@ -126,7 +130,7 @@ extern "C" { f_console_parameter_t_initialize(controller_short_validate, controller_long_validate, 0, 0, f_console_type_normal), \ } - #define controller_total_parameters 14 + #define controller_total_parameters 15 #endif // _di_controller_defines_ #ifndef _di_controller_data_t_ diff --git a/level_3/controller/c/private-common.h b/level_3/controller/c/private-common.h index 5d7200a..1e1875e 100644 --- a/level_3/controller/c/private-common.h +++ b/level_3/controller/c/private-common.h @@ -431,6 +431,8 @@ extern "C" { controller_setting_ready_wait, controller_setting_ready_yes, controller_setting_ready_done, + controller_setting_ready_fail, + controller_setting_ready_abort, }; typedef struct { diff --git a/level_3/controller/c/private-controller.c b/level_3/controller/c/private-controller.c index 3733dc5..9a3da48 100644 --- a/level_3/controller/c/private-controller.c +++ b/level_3/controller/c/private-controller.c @@ -52,6 +52,32 @@ extern "C" { } #endif // _di_controller_entry_action_type_name_ +#ifndef _di_controller_string_dynamic_append_terminated_ + f_return_status controller_string_dynamic_append_terminated(const f_string_static_t source, f_string_dynamic_t *destination) { + + f_status_t status = fl_string_dynamic_append(source, destination); + + if (F_status_is_error(status)) return status; + + status = fl_string_dynamic_terminate_after(destination); + + return status; + } +#endif // _di_controller_string_dynamic_append_terminated_ + +#ifndef _di_controller_string_dynamic_partial_append_terminated_ + f_return_status controller_string_dynamic_partial_append_terminated(const f_string_static_t source, const f_string_range_t range, f_string_dynamic_t *destination) { + + f_status_t status = fl_string_dynamic_partial_append(source, range, destination); + + if (F_status_is_error(status)) return status; + + status = fl_string_dynamic_terminate_after(destination); + + return status; + } +#endif // _di_controller_string_dynamic_partial_append_terminated_ + #ifndef _di_controller_file_load_ f_return_status controller_file_load(const controller_data_t data, const controller_setting_t setting, const f_string_t path_prefix, const f_string_static_t path_name, const f_string_t path_suffix, const f_string_length_t path_prefix_length, const f_string_length_t path_suffix_length, f_string_dynamic_t *path_file, f_string_dynamic_t *buffer) { f_status_t status = F_none; @@ -205,7 +231,11 @@ extern "C" { status = fl_conversion_string_to_decimal_unsigned(pid_buffer.string, &number, range); if (F_status_is_error_not(status) && number == data.pid) { - f_file_remove(path_pid.string); + status = f_file_remove(path_pid.string); + + if (F_status_is_error(status) && data.warning.verbosity == f_console_verbosity_debug) { + fll_error_file_print(data.warning, F_status_set_fine(status), "f_file_remove", F_true, path_pid.string, "delete", fll_error_file_type_file); + } } } @@ -213,8 +243,36 @@ extern "C" { } #endif // _di_controller_file_pid_delete_ -#ifndef _di_controller_preprocess_items_ - f_return_status controller_preprocess_items(const controller_data_t data, controller_setting_t *setting, controller_cache_t *cache) { +#ifndef _di_controller_perform_ready_ + f_return_status controller_perform_ready(const controller_data_t data, controller_setting_t *setting, controller_cache_t *cache) { + f_status_t status = F_none; + + // only create pid file when not in validate mode. + if (data.parameters[controller_parameter_validate].result == f_console_result_none) { + + status = controller_file_pid_create(data, setting->path_pid); + + // 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) { + return status; + } + + status = F_none; + } + } + + return status; + } +#endif // _di_controller_perform_ready_ + +#ifndef _di_controller_preprocess_entry_ + f_return_status controller_preprocess_entry(const controller_data_t data, controller_setting_t *setting, controller_cache_t *cache) { f_status_t status = F_none; f_status_t status2 = F_none; @@ -231,6 +289,10 @@ extern "C" { setting->ready = controller_setting_ready_no; cache->ats.used = 0; + cache->line_action = 0; + cache->line_item = 0; + cache->name_action.used = 0; + cache->name_item.used = 0; status = fl_type_array_lengths_increase_by(controller_default_allocation_step, &cache->ats); @@ -246,19 +308,10 @@ extern "C" { cache->line_item = setting->entry.items.array[0].line; cache->name_item.used = 0; - status = fl_string_dynamic_append(setting->entry.items.array[0].name, &cache->name_item); + 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), "fl_string_dynamic_append", F_true); - controller_entry_error_print(data.error, *cache); - - return status; - } - - status = fl_string_dynamic_terminate_after(&cache->name_item); - - if (F_status_is_error(status)) { - fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_terminate_after", F_true); + 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; @@ -273,19 +326,10 @@ extern "C" { cache->line_action = actions->array[cache->ats.array[at_j]].line; cache->name_action.used = 0; - status2 = fl_string_dynamic_append(controller_entry_action_type_name(actions->array[cache->ats.array[at_j]].type), &cache->name_action); + status2 = 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(status2)) { - fll_error_print(data.error, F_status_set_fine(status2), "fl_string_dynamic_append", F_true); - controller_entry_error_print(data.error, *cache); - - return status2; - } - - status2 = fl_string_dynamic_terminate_after(&cache->name_action); - - if (F_status_is_error(status2)) { - fll_error_print(data.error, F_status_set_fine(status2), "fl_string_dynamic_terminate_after", F_true); + fll_error_print(data.error, F_status_set_fine(status2), "controller_string_dynamic_append_terminated", F_true); controller_entry_error_print(data.error, *cache); return status2; @@ -369,19 +413,10 @@ extern "C" { cache->name_item.used = 0; cache->line_item = setting->entry.items.array[i].line; - status2 = fl_string_dynamic_append(setting->entry.items.array[i].name, &cache->name_item); + status2 = controller_string_dynamic_append_terminated(setting->entry.items.array[i].name, &cache->name_item); if (F_status_is_error(status2)) { - fll_error_print(data.error, F_status_set_fine(status2), "fl_string_dynamic_append", F_true); - controller_entry_error_print(data.error, *cache); - - return status2; - } - - status2 = fl_string_dynamic_terminate_after(&cache->name_item); - - if (F_status_is_error(status2)) { - fll_error_print(data.error, F_status_set_fine(status2), "fl_string_dynamic_terminate_after", F_true); + fll_error_print(data.error, F_status_set_fine(status2), "controller_string_dynamic_append_terminated", F_true); controller_entry_error_print(data.error, *cache); return status2; @@ -431,19 +466,10 @@ extern "C" { cache->line_item = setting->entry.items.array[cache->ats.array[at_i]].line; cache->name_item.used = 0; - status2 = fl_string_dynamic_append(setting->entry.items.array[cache->ats.array[at_i]].name, &cache->name_item); + status2 = controller_string_dynamic_append_terminated(setting->entry.items.array[cache->ats.array[at_i]].name, &cache->name_item); if (F_status_is_error(status2)) { - fll_error_print(data.error, F_status_set_fine(status2), "fl_string_dynamic_append", F_true); - controller_entry_error_print(data.error, *cache); - - return status2; - } - - status2 = fl_string_dynamic_terminate_after(&cache->name_item); - - if (F_status_is_error(status2)) { - fll_error_print(data.error, F_status_set_fine(status2), "fl_string_dynamic_terminate_after", F_true); + fll_error_print(data.error, F_status_set_fine(status2), "controller_string_dynamic_append_terminated", F_true); controller_entry_error_print(data.error, *cache); return status2; @@ -456,15 +482,233 @@ extern "C" { setting->ready = controller_setting_ready_yes; } + return status; + } +#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_status_t status = F_none; + + f_array_length_t i = 0; + f_array_length_t j = 0; + + f_array_length_t at_i = 0; + f_array_length_t at_j = 1; + + controller_entry_actions_t *actions = 0; + + const bool simulate = data.parameters[controller_parameter_test].result == f_console_result_found; + cache->ats.used = 0; cache->line_action = 0; cache->line_item = 0; cache->name_action.used = 0; cache->name_item.used = 0; + if (setting->ready == controller_setting_ready_yes) { + 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); + + return status; + } + + cache->ats.array[0] = 0; + cache->ats.array[1] = 0; + cache->ats.used = 2; + + cache->line_item = setting->entry.items.array[0].line; + cache->name_item.used = 0; + + 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); + + return status; + } + + for (;;) { + + actions = &setting->entry.items.array[cache->ats.array[at_i]].actions; + + for (; cache->ats.array[at_j] < actions->used; ++cache->ats.array[at_j]) { + + cache->line_action = actions->array[cache->ats.array[at_j]].line; + cache->name_action.used = 0; + + 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); + + return status; + } + + if (actions->array[cache->ats.array[at_j]].type == controller_entry_action_type_ready) { + + if (setting->ready == controller_setting_ready_wait) { + setting->ready = controller_setting_ready_yes; + + controller_perform_ready(data, setting, cache); + if (F_status_is_error(status)) return status; + } + } + else if (actions->array[cache->ats.array[at_j]].type == controller_entry_action_type_item) { + + 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[0]); + fprintf(data.error.to.stream, "%s%sInvalid entry item index ", data.error.context.before->string, data.error.prefix ? data.error.prefix : ""); + 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[0]); + } + + controller_entry_error_print(data.error, *cache); + + return F_status_is_error(F_critical); + } + + 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); + + return status; + } + + // continue into the requested item. + at_i = cache->ats.used; + at_j = cache->ats.used + 1; + + cache->ats.array[at_i] = actions->array[cache->ats.array[at_j]].number; + cache->ats.array[at_j] = 0; + cache->ats.used += 2; + + cache->name_action.used = 0; + cache->line_action = 0; + + cache->name_item.used = 0; + cache->line_item = setting->entry.items.array[actions->array[cache->ats.array[at_j]].number].line; + + status = controller_string_dynamic_append_terminated(setting->entry.items.array[actions->array[cache->ats.array[at_j]].number].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); + + return status; + } + + break; + } + else if (actions->array[cache->ats.array[at_j]].type == controller_entry_action_type_consider || actions->array[cache->ats.array[at_j]].type == controller_entry_action_type_rule) { + + // 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; + + char cache_name_item[cache_name_action_used]; + char cache_name_action[cache_name_item_used]; + + memcpy(cache_name_item, cache->name_item.string, cache->name_item.used); + memcpy(cache_name_action, cache->name_action.string, cache->name_action.used); + + const f_string_length_t rule_id_length = actions->array[cache->ats.array[at_j]].parameters.array[0].used + actions->array[cache->ats.array[at_j]].parameters.array[1].used + 1; + char rule_id_name[rule_id_length + 1]; + const f_string_static_t rule_id = f_macro_string_static_t_initialize(rule_id_name, rule_id_length); + + memcpy(rule_id_name, actions->array[cache->ats.array[at_j]].parameters.array[0].string, actions->array[cache->ats.array[at_j]].parameters.array[0].used); + memcpy(rule_id_name + actions->array[cache->ats.array[at_j]].parameters.array[0].used + 1, actions->array[cache->ats.array[at_j]].parameters.array[1].string, actions->array[cache->ats.array[at_j]].parameters.array[1].used); + + rule_id_name[actions->array[cache->ats.array[at_j]].parameters.array[0].used] = f_path_separator[0]; + rule_id_name[rule_id_length] = 0; + + // @todo check if the rule is already loaded by using the "rule_id", if not then load it. + + //status = controller_rule_read(data, *setting, rule_id, cache, &setting->rules.array[setting->rules.used]); + + // @todo execute rule. + if (F_status_is_error_not(status) && actions->array[cache->ats.array[at_j]].type == controller_entry_action_type_rule) { + //setting->rules.used++; + //status = controller_rule_process(); + } + + // 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); + + cache->name_action.string[cache_name_action_used] = 0; + cache->name_item.string[cache_name_item_used] = 0; + + cache->name_action.used = cache_name_action_used; + cache->name_item.used = cache_name_item_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); + + if (!simulate) break; + } + } + else if (actions->array[cache->ats.array[at_j]].type == controller_entry_action_type_timeout) { + // @todo + } + else if (actions->array[cache->ats.array[at_j]].type == controller_entry_action_type_failsafe) { + // @todo + } + + } // for + + cache->line_action = 0; + cache->name_action.used = 0; + + // end of actions found, so drop to previous loop in stack. + if (cache->ats.array[at_j] == actions->used) { + + // all actions for "main" are processed so there is nothing left to do. + if (at_i == 0) break; + + at_i -= 2; + at_j -= 2; + + cache->ats.used -= 2; + cache->ats.array[at_j]++; + + cache->line_item = setting->entry.items.array[cache->ats.array[at_i]].line; + cache->name_item.used = 0; + + 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); + + return status; + } + } + } // for + return status; } -#endif // _di_controller_preprocess_items_ +#endif // _di_controller_process_entry_ #ifndef _di_controller_status_simplify_ f_return_status controller_status_simplify(const f_status_t status) { @@ -489,7 +733,7 @@ extern "C" { return F_status_set_error(F_number); } - if (status == F_parameter || status == F_found_not || status == F_interrupt || status == F_supported_not) { + if (status == F_parameter || status == F_found_not || status == F_interrupt || status == F_supported_not || status == F_critical) { return F_status_set_error(status); } diff --git a/level_3/controller/c/private-controller.h b/level_3/controller/c/private-controller.h index 4615ce1..e7058c0 100644 --- a/level_3/controller/c/private-controller.h +++ b/level_3/controller/c/private-controller.h @@ -11,6 +11,7 @@ #ifdef __cplusplus extern "C" { #endif + /** * Get a string representing the entry action type. * @@ -26,6 +27,50 @@ extern "C" { #endif // _di_controller_entry_action_type_name_ /** + * Append a string and then add a NULL after the end of the string. + * + * @param source + * The string to copy from. + * @param destination + * The string to copy to. + * + * @return + * F_none on success. + * + * Errors (with error bit) from: fl_string_dynamic_append(). + * Errors (with error bit) from: fl_string_dynamic_terminate_after(). + * + * @see fl_string_dynamic_append() + * @see fl_string_dynamic_terminate_after() + */ +#ifndef _di_controller_string_dynamic_append_terminated_ + extern f_return_status controller_string_dynamic_append_terminated(const f_string_static_t from, f_string_dynamic_t *destination) f_gcc_attribute_visibility_internal; +#endif // _di_controller_string_dynamic_append_terminated_ + +/** + * Append given range from within a string and then add a NULL after the end of the string. + * + * @param from + * The string to copy from. + * @param range + * The range within the from string to copy. + * @param destination + * The string to copy to. + * + * @return + * F_none on success. + * + * Errors (with error bit) from: fl_string_dynamic_append(). + * Errors (with error bit) from: fl_string_dynamic_terminate_after(). + * + * @see fl_string_dynamic_append() + * @see fl_string_dynamic_terminate_after() + */ +#ifndef _di_controller_string_dynamic_partial_append_terminated_ + extern f_return_status controller_string_dynamic_partial_append_terminated(const f_string_static_t from, const f_string_range_t range, f_string_dynamic_t *destination) f_gcc_attribute_visibility_internal; +#endif // _di_controller_string_dynamic_partial_append_terminated_ + +/** * Load a file from the controller settings directory. * * @param data @@ -100,7 +145,9 @@ extern "C" { #endif // _di_controller_file_pid_delete_ /** - * Load relevant rules into memory and performing other pre-process tasks. + * Perform all activities requiring the state to be "ready". + * + * This prints messages on errors. * * @param data * The program data. @@ -111,10 +158,70 @@ extern "C" { * * @return * F_none on success. + * + * Errors from controller_file_pid_create() are not returned, unless it is a memory error. + * + * @see controller_file_pid_create() + */ +#ifndef _di_controller_perform_ready_ + extern f_return_status controller_perform_ready(const controller_data_t data, controller_setting_t *setting, controller_cache_t *cache) f_gcc_attribute_visibility_internal; +#endif // _di_controller_perform_ready_ + +/** + * Pre-process all items for the loaded entry. + * + * @param data + * The program data. + * @param setting + * The controller settings data. + * @param cache + * The cache. + * + * @return + * F_none on success. + * F_recurse (with error bit) on a recursion error. + * F_valid_not (with error bit) on invalid entry item, entry item action, or entry item action value. + * + * Errors (with error bit) from: fl_string_dynamic_append(). + * Errors (with error bit) from: fl_string_dynamic_terminate_after(). + * Errors (with error bit) from: fl_type_array_lengths_increase_by(). + * + * This will detect and report all errors, but only the first error is returned. + * Memory related errors return immediately. + * + * @see fl_string_dynamic_append() + * @see fl_string_dynamic_terminate_after() + * @see fl_type_array_lengths_increase_by() + */ +#ifndef _di_controller_preprocess_entry_ + extern f_return_status controller_preprocess_entry(const controller_data_t data, controller_setting_t *setting, controller_cache_t *cache) f_gcc_attribute_visibility_internal; +#endif // _di_controller_preprocess_entry_ + +/** + * Process (execute) all items for the loaded entry. + * + * @param data + * The program data. + * @param setting + * The controller settings data. + * @param cache + * The cache. + * + * @return + * F_none on success. + * F_critical (with error bit) on any critical error. + * + * Errors (with error bit) from: controller_perform_ready(). + * Errors (with error bit) from: controller_string_dynamic_append_terminated(). + * Errors (with error bit) from: fl_type_array_lengths_increase_by(). + * + * @see controller_perform_ready() + * @see controller_string_dynamic_append_terminated() + * @see fl_type_array_lengths_increase_by() */ -#ifndef _di_controller_preprocess_items_ - extern f_return_status controller_preprocess_items(const controller_data_t data, controller_setting_t *setting, controller_cache_t *cache) f_gcc_attribute_visibility_internal; -#endif // _di_controller_preprocess_items_ +#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; +#endif // _di_controller_process_entry_ /** * Given a wide range of status codes, simplify them down to a small subset. diff --git a/level_3/controller/c/private-entry.c b/level_3/controller/c/private-entry.c index 4f56c6a..79a9b51 100644 --- a/level_3/controller/c/private-entry.c +++ b/level_3/controller/c/private-entry.c @@ -640,17 +640,10 @@ extern "C" { break; } - status = fl_string_dynamic_partial_append_nulless(cache->buffer_file, cache->object_items.array[i], &cache->name_item); + status = controller_string_dynamic_partial_append_terminated(cache->buffer_file, cache->object_items.array[i], &cache->name_item); if (F_status_is_error(status)) { - fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_partial_append_nulless", F_true); - break; - } - - status = fl_string_dynamic_terminate_after(&cache->name_item); - - if (F_status_is_error(status)) { - fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_terminate_after", F_true); + fll_error_print(data.error, F_status_set_fine(status), "controller_string_dynamic_partial_append_terminated", F_true); break; } @@ -707,17 +700,10 @@ extern "C" { entry->items.array[at].line = cache->line_item; - status = fl_string_dynamic_append(cache->name_item, &entry->items.array[at].name); + status = controller_string_dynamic_append_terminated(cache->name_item, &entry->items.array[at].name); if (F_status_is_error(status)) { - fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_append", F_true); - break; - } - - status = fl_string_dynamic_terminate_after(&entry->items.array[at].name); - - if (F_status_is_error(status)) { - fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_terminate_after", F_true); + fll_error_print(data.error, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true); break; } @@ -784,31 +770,10 @@ extern "C" { cache->line_action = action->line; cache->line_item = entry->items.array[i].line; - status = fl_string_dynamic_append(entry->items.array[i].name, &cache->name_item); + status = controller_string_dynamic_append_terminated(entry->items.array[i].name, &cache->name_item); if (F_status_is_error(status)) { - fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_append", F_true); - break; - } - - status = fl_string_dynamic_terminate_after(&cache->name_item); - - if (F_status_is_error(status)) { - fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_terminate_after", F_true); - break; - } - - status = fl_string_dynamic_append(entry->items.array[i].name, &cache->name_item); - - if (F_status_is_error(status)) { - fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_append", F_true); - break; - } - - status = fl_string_dynamic_terminate_after(&cache->name_item); - - if (F_status_is_error(status)) { - fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_terminate_after", F_true); + fll_error_print(data.error, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true); break; } @@ -832,7 +797,7 @@ extern "C" { // the error is already fully printed and the entry status is already assigned, so immediately exit. if (missing & 0x2) { - return F_false; + return entry->status; } } } @@ -843,11 +808,12 @@ extern "C" { controller_entry_error_print(data.error, *cache); entry->status = controller_status_simplify(F_status_set_fine(status)); - return F_false; + } + else { + entry->status = F_none; } - entry->status = F_none; - return F_true; + return entry->status; } #endif // _di_controller_entry_read_ diff --git a/level_3/controller/c/private-entry.h b/level_3/controller/c/private-entry.h index 81f8ad5..3857d20 100644 --- a/level_3/controller/c/private-entry.h +++ b/level_3/controller/c/private-entry.h @@ -129,13 +129,27 @@ extern "C" { * The processed entry. * * @return - * F_true on success. - * F_false on failure. + * F_none on success. + * + * Errors (with error bit) from: controller_entry_actions_read(). + * Errors (with error bit) from: controller_entry_items_increase_by(). + * Errors (with error bit) from: controller_file_load(). + * Errors (with error bit) from: controller_status_simplify(). + * Errors (with error bit) from: controller_string_dynamic_append_terminated(). + * Errors (with error bit) from: controller_string_dynamic_partial_append_terminated(). + * Errors (with error bit) from: f_fss_count_lines(). + * Errors (with error bit) from: fl_fss_apply_delimit(). + * Errors (with error bit) from: fl_string_dynamic_append(). + * Errors (with error bit) from: fl_string_dynamic_partial_append_nulless(). + * Errors (with error bit) from: fl_string_dynamic_terminate(). + * Errors (with error bit) from: fll_fss_basic_list_read(). * * @see controller_entry_actions_read() * @see controller_entry_items_increase_by() * @see controller_file_load() * @see controller_status_simplify() + * @see controller_string_dynamic_append_terminated() + * @see controller_string_dynamic_partial_append_terminated() * @see f_fss_count_lines() * @see fl_fss_apply_delimit() * @see fl_string_dynamic_append() diff --git a/level_3/controller/data/settings/entries/default.entry b/level_3/controller/data/settings/entries/default.entry index ff05693..d6770a2 100644 --- a/level_3/controller/data/settings/entries/default.entry +++ b/level_3/controller/data/settings/entries/default.entry @@ -8,14 +8,14 @@ main: timeout stop 7 timeout kill 3 + failsafe maintenance + item boot item net item time item keyboard item console - failsafe maintenance - boot: rule boot filesystem require rule boot modules require -- 1.8.3.1