From 5b09409e3c7b5eafc164405c5d487bdfd083be11 Mon Sep 17 00:00:00 2001 From: Kevin Day Date: Sun, 10 Oct 2021 21:47:29 -0500 Subject: [PATCH] Progress: Begin implementing re-run, fixing related problems. To properly operate as an init (and improve the controller execution functionality), programs and services need to re-run after exiting. A good example of this is the agetty program, which should re-run on both success and failure. I attempted to take a simple approach with this design. Example: rerun start success delay 1000 reset rerun start failure delay 5000 max 100 A "rerun" is applied to each Rule Action "start", "stop", "freeze", etc... Each Rule Action has either a "success" or a "failure" state. Each state may specify a delay, max, and a reset. The delay provides how long to wait before re-running. The max represents the maximum number of times to perform the re-run (setting to 0 results in no maximum). The reset designates that the opposite return result (either success or failure) will have its counter reset. That is, in the above example if failure is triggered 50 times and then success is triggered, the failure counter will be 0 again due to the reset on success. Not specifying "rerun" will disable re-running. This implements another array structure and the code is changed to perform the processing of the settings at an earlier point. The previous design is a quick and simple but required additional looping before each execution. The code now does the processing in the existing loops to avoid needing to loop later. This requires adding new variables to the structure increasing memory footprint there but also decreases memory footprint in the actions array (and results in smaller actions array). The "with" and "pid_file" are updated in this way as well. The "user" and "group" have not yet been updated and need to be. The configuration and validation of "rerun" is implemented, but the re-run functionality needs to be written. The error checking, handling, and exiting will need to be reviewed after this work is complete. --- level_3/controller/c/private-common.c | 8 + level_3/controller/c/private-common.h | 115 ++++++ level_3/controller/c/private-rule.c | 425 ++++++++++++++++++--- level_3/controller/c/private-rule.h | 32 ++ .../data/settings/rules/terminal/four.rule | 3 + .../data/settings/rules/terminal/one.rule | 3 + .../data/settings/rules/terminal/three.rule | 3 + .../data/settings/rules/terminal/two.rule | 3 + level_3/controller/documents/rule.txt | 16 +- level_3/controller/specifications/rule.txt | 8 + 10 files changed, 552 insertions(+), 64 deletions(-) diff --git a/level_3/controller/c/private-common.c b/level_3/controller/c/private-common.c index a9424af..bd6e142 100644 --- a/level_3/controller/c/private-common.c +++ b/level_3/controller/c/private-common.c @@ -27,6 +27,7 @@ extern "C" { const f_string_t controller_string_deadline_s = controller_string_deadline; const f_string_t controller_string_default_s = controller_string_default; const f_string_t controller_string_define_s = controller_string_define; + const f_string_t controller_string_delay_s = controller_string_delay; const f_string_t controller_string_disable_s = controller_string_disable; const f_string_t controller_string_entry_s = controller_string_entry; const f_string_t controller_string_entries_s = controller_string_entries; @@ -37,6 +38,7 @@ extern "C" { const f_string_t controller_string_exits_s = controller_string_exits; const f_string_t controller_string_fail_s = controller_string_fail; const f_string_t controller_string_failsafe_s = controller_string_failsafe; + const f_string_t controller_string_failure_s = controller_string_failure; const f_string_t controller_string_fifo_s = controller_string_fifo; const f_string_t controller_string_freeze_s = controller_string_freeze; const f_string_t controller_string_fsize_s = controller_string_fsize; @@ -51,6 +53,7 @@ extern "C" { const f_string_t controller_string_limit_s = controller_string_limit; const f_string_t controller_string_locks_s = controller_string_locks; const f_string_t controller_string_main_s = controller_string_main; + const f_string_t controller_string_max_s = controller_string_max; const f_string_t controller_string_memlock_s = controller_string_memlock; const f_string_t controller_string_method_s = controller_string_method; const f_string_t controller_string_mode_s = controller_string_mode; @@ -78,6 +81,8 @@ extern "C" { const f_string_t controller_string_reload_s = controller_string_reload; const f_string_t controller_string_require_s = controller_string_require; const f_string_t controller_string_required_s = controller_string_required; + const f_string_t controller_string_rerun_s = controller_string_rerun; + const f_string_t controller_string_reset_s = controller_string_reset; const f_string_t controller_string_restart_s = controller_string_restart; const f_string_t controller_string_resume_s = controller_string_resume; const f_string_t controller_string_round_robin_s = controller_string_round_robin; @@ -96,6 +101,7 @@ extern "C" { const f_string_t controller_string_start_s = controller_string_start; const f_string_t controller_string_stop_s = controller_string_stop; const f_string_t controller_string_succeed_s = controller_string_succeed; + const f_string_t controller_string_success_s = controller_string_success; const f_string_t controller_string_synchronous_s = controller_string_synchronous; const f_string_t controller_string_thaw_s = controller_string_thaw; const f_string_t controller_string_timeout_s = controller_string_timeout; @@ -732,6 +738,8 @@ extern "C" { #ifndef _di_controller_rule_item_delete_simple_ void controller_rule_item_delete_simple(controller_rule_item_t *item) { + f_string_dynamic_resize(0, &item->pid_file); + controller_rule_actions_delete_simple(&item->actions); } #endif // _di_controller_rule_item_delete_simple_ diff --git a/level_3/controller/c/private-common.h b/level_3/controller/c/private-common.h index b018c04..7855177 100644 --- a/level_3/controller/c/private-common.h +++ b/level_3/controller/c/private-common.h @@ -37,6 +37,7 @@ extern "C" { #define controller_string_deadline "deadline" #define controller_string_default "default" #define controller_string_define "define" + #define controller_string_delay "delay" #define controller_string_disable "disable" #define controller_string_entry "entry" #define controller_string_entries "entries" @@ -47,6 +48,7 @@ extern "C" { #define controller_string_exits "exits" #define controller_string_fail "fail" #define controller_string_failsafe "failsafe" + #define controller_string_failure "failure" #define controller_string_fifo "fifo" #define controller_string_freeze "freeze" #define controller_string_fsize "fsize" @@ -61,6 +63,7 @@ extern "C" { #define controller_string_limit "limit" #define controller_string_locks "locks" #define controller_string_main "main" + #define controller_string_max "max" #define controller_string_memlock "memlock" #define controller_string_method "method" #define controller_string_mode "mode" @@ -88,6 +91,8 @@ extern "C" { #define controller_string_reload "reload" #define controller_string_require "require" #define controller_string_required "required" + #define controller_string_rerun "rerun" + #define controller_string_reset "reset" #define controller_string_restart "restart" #define controller_string_resume "resume" #define controller_string_round_robin "round_robin" @@ -106,6 +111,7 @@ extern "C" { #define controller_string_start "start" #define controller_string_stop "stop" #define controller_string_succeed "succeed" + #define controller_string_success "success" #define controller_string_synchronous "synchronous" #define controller_string_thaw "thaw" #define controller_string_timeout "timeout" @@ -139,6 +145,7 @@ extern "C" { #define controller_string_deadline_length 8 #define controller_string_default_length 7 #define controller_string_define_length 6 + #define controller_string_delay_length 5 #define controller_string_disable_length 7 #define controller_string_entry_length 5 #define controller_string_entries_length 7 @@ -148,6 +155,7 @@ extern "C" { #define controller_string_exit_length 4 #define controller_string_exits_length 5 #define controller_string_fail_length 4 + #define controller_string_failure_length 7 #define controller_string_failsafe_length 8 #define controller_string_fifo_length 4 #define controller_string_freeze_length 6 @@ -163,6 +171,7 @@ extern "C" { #define controller_string_limit_length 5 #define controller_string_locks_length 5 #define controller_string_main_length 4 + #define controller_string_max_length 3 #define controller_string_memlock_length 7 #define controller_string_method_length 6 #define controller_string_mode_length 4 @@ -190,6 +199,8 @@ extern "C" { #define controller_string_reload_length 6 #define controller_string_require_length 7 #define controller_string_required_length 8 + #define controller_string_rerun_length 5 + #define controller_string_reset_length 5 #define controller_string_restart_length 7 #define controller_string_resume_length 6 #define controller_string_round_robin_length 11 @@ -208,6 +219,7 @@ extern "C" { #define controller_string_start_length 5 #define controller_string_stop_length 4 #define controller_string_succeed_length 7 + #define controller_string_success_length 7 #define controller_string_synchronous_length 11 #define controller_string_thaw_length 4 #define controller_string_timeout_length 7 @@ -241,6 +253,7 @@ extern "C" { extern const f_string_t controller_string_deadline_s; extern const f_string_t controller_string_default_s; extern const f_string_t controller_string_define_s; + extern const f_string_t controller_string_delay_s; extern const f_string_t controller_string_disable_s; extern const f_string_t controller_string_entry_s; extern const f_string_t controller_string_entries_s; @@ -251,6 +264,7 @@ extern "C" { extern const f_string_t controller_string_exits_s; extern const f_string_t controller_string_fail_s; extern const f_string_t controller_string_failsafe_s; + extern const f_string_t controller_string_failure_s; extern const f_string_t controller_string_fifo_s; extern const f_string_t controller_string_freeze_s; extern const f_string_t controller_string_fsize_s; @@ -265,6 +279,7 @@ extern "C" { extern const f_string_t controller_string_limit_s; extern const f_string_t controller_string_locks_s; extern const f_string_t controller_string_main_s; + extern const f_string_t controller_string_max_s; extern const f_string_t controller_string_memlock_s; extern const f_string_t controller_string_method_s; extern const f_string_t controller_string_mode_s; @@ -292,6 +307,8 @@ extern "C" { extern const f_string_t controller_string_reload_s; extern const f_string_t controller_string_require_s; extern const f_string_t controller_string_required_s; + extern const f_string_t controller_string_rerun_s; + extern const f_string_t controller_string_reset_s; extern const f_string_t controller_string_restart_s; extern const f_string_t controller_string_resume_s; extern const f_string_t controller_string_round_robin_s; @@ -310,6 +327,7 @@ extern "C" { extern const f_string_t controller_string_start_s; extern const f_string_t controller_string_stop_s; extern const f_string_t controller_string_succeed_s; + extern const f_string_t controller_string_success_s; extern const f_string_t controller_string_synchronous_s; extern const f_string_t controller_string_thaw_s; extern const f_string_t controller_string_timeout_s; @@ -526,6 +544,67 @@ extern "C" { #endif // _di_controller_mutex_t_ /** + * The Rule "rerun" item for controlling re-execution. + * + * count: A count of the number of executions. + * delay: The time to wait before attempting to re-run. + * max: The maximum number of times to re-run (with 0 representing re-run infinitely) for executions. + */ +#ifndef _di_controller_rule_rerun_item_t_ + typedef struct { + bool reset; + + f_number_unsigned_t count; + f_number_unsigned_t delay; + f_number_unsigned_t max; + } controller_rule_rerun_item_t; + + #define controller_rule_rerun_item_initialize { \ + F_false, \ + 0, \ + 5000, \ + 0, \ + } +#endif // _di_controller_rule_rerun_item_t_ + +/** + * The Rule "rerun" values for controlling re-execution. + * + * controller_rule_rerun_is_*: + * - failure: The success re-run is enabled. + * - failure_reset: Reset success counter when failure is returned. + * - success: The success re-run is enabled. + * - success_reset: Reset failure counter when success is returned. + * + * is: A bitwise set of options to designate whether rerun is enabled or not and other options. + * count_failure: A count of the number of failed executions. + * count_success: A count of the number of successful executions. + * delay_failure: The time to wait before attempting to "rerun" for failed executions. + * delay_success: The time to wait before attempting to "rerun" for successful executions. + * max_failure: The maximum number of times to "rerun" (with 0 representing "rerun" infinitely) for failed executions. + * max_success: The maximum number of times to "rerun" (with 0 representing "rerun" infinitely) for successful executions. + */ +#ifndef _di_controller_rule_rerun_t_ + #define controller_rule_rerun_is_failure 0x1 + #define controller_rule_rerun_is_failure_reset 0x2 + #define controller_rule_rerun_is_success 0x4 + #define controller_rule_rerun_is_success_reset 0x8 + + typedef struct { + uint8_t is; + + controller_rule_rerun_item_t failure; + controller_rule_rerun_item_t success; + } controller_rule_rerun_t; + + #define controller_rule_rerun_initialize { \ + 0, \ + controller_rule_rerun_item_initialize, \ + controller_rule_rerun_item_initialize, \ + } +#endif // _di_controller_rule_rerun_t_ + +/** * A Rule Action. * * controller_rule_action_method_*: @@ -538,6 +617,7 @@ extern "C" { * - kill: The Kill execution instructions. * - pause: The Pause execution instructions. * - pid_file: The PID file setting. + * - rerun: The Re-run execution after success or failure. * - reload: The Reload execution instructions. * - restart: The Restart execution instructions. * - resume: The Resume execution instructions. @@ -571,6 +651,7 @@ extern "C" { controller_rule_action_type_pause, controller_rule_action_type_pid_file, controller_rule_action_type_reload, + controller_rule_action_type_rerun, controller_rule_action_type_restart, controller_rule_action_type_resume, controller_rule_action_type_start, @@ -583,6 +664,21 @@ extern "C" { controller_rule_action_type__enum_size, }; + enum { + controller_rule_action_type_execute_freeze = 0, + controller_rule_action_type_execute_kill, + controller_rule_action_type_execute_pause, + controller_rule_action_type_execute_reload, + controller_rule_action_type_execute_restart, + controller_rule_action_type_execute_resume, + controller_rule_action_type_execute_start, + controller_rule_action_type_execute_stop, + controller_rule_action_type_execute_thaw, + + // designate the largest value in the enum, the '__' is intended. + controller_rule_action_type_execute__enum_size, + }; + typedef struct { uint8_t type; f_array_length_t line; @@ -632,7 +728,9 @@ extern "C" { * - utility: A Utility to execute. * * type: The type of the Rule Item. + * with: A bitwise number representing execute "with" options. * line: The line number where the Rule Item begins. + * reruns: An array designating rerun settings for each execution type available. * actions: The actions associated with the Rule Item. */ #ifndef _di_controller_rule_item_t_ @@ -646,8 +744,11 @@ extern "C" { typedef struct { uint8_t type; + uint8_t with; f_array_length_t line; + f_string_dynamic_t pid_file; + controller_rule_rerun_t reruns[controller_rule_action_type_execute__enum_size]; controller_rule_actions_t actions; } controller_rule_item_t; @@ -655,6 +756,19 @@ extern "C" { { \ 0, \ 0, \ + 0, \ + f_string_dynamic_t_initialize, \ + { \ + controller_rule_rerun_t_initialize, \ + controller_rule_rerun_t_initialize, \ + controller_rule_rerun_t_initialize, \ + controller_rule_rerun_t_initialize, \ + controller_rule_rerun_t_initialize, \ + controller_rule_rerun_t_initialize, \ + controller_rule_rerun_t_initialize, \ + controller_rule_rerun_t_initialize, \ + controller_rule_rerun_t_initialize, \ + }, \ controller_rule_actions_t_initialize, \ } #endif // _di_controller_rule_item_t_ @@ -864,6 +978,7 @@ extern "C" { F_known_not, \ F_known_not, \ F_known_not, \ + F_known_not, \ }, \ 0, \ 0, \ diff --git a/level_3/controller/c/private-rule.c b/level_3/controller/c/private-rule.c index 2055267..e55ec4c 100644 --- a/level_3/controller/c/private-rule.c +++ b/level_3/controller/c/private-rule.c @@ -160,6 +160,11 @@ extern "C" { buffer.used = controller_string_pid_file_length; break; + case controller_rule_action_type_rerun: + buffer.string = controller_string_rerun_s; + buffer.used = controller_string_rerun_length; + break; + case controller_rule_action_type_reload: buffer.string = controller_string_reload_s; buffer.used = controller_string_reload_length; @@ -382,6 +387,173 @@ extern "C" { if (F_status_is_error(status)) { controller_error_print(global.main->error, F_status_set_fine(status), "fl_fss_apply_delimit", F_true, global.thread); } + else if (type == controller_rule_action_type_pid_file) { + item->pid_file.used = 0; + + status = fl_string_dynamic_rip(cache->buffer_item, cache->content_action.array[0], &item->pid_file); + + if (F_status_is_error(status)) { + controller_error_print(global.main->error, F_status_set_fine(status), "fl_string_dynamic_rip", F_true, global.thread); + } + else { + status = f_string_dynamic_terminate_after(&item->pid_file); + + if (F_status_is_error(status)) { + controller_error_print(global.main->error, F_status_set_fine(status), "f_string_dynamic_terminate_after", F_true, global.thread); + } + } + } + else if (type == controller_rule_action_type_rerun) { + uint8_t type = 0; + + if (cache->content_action.used) { + if (fl_string_dynamic_partial_compare_string(controller_string_freeze_s, cache->buffer_item, controller_string_freeze_length, cache->content_action.array[0]) == F_equal_to) { + type = controller_rule_action_type_execute_freeze; + } + if (fl_string_dynamic_partial_compare_string(controller_string_kill_s, cache->buffer_item, controller_string_kill_length, cache->content_action.array[0]) == F_equal_to) { + type = controller_rule_action_type_execute_kill; + } + else if (fl_string_dynamic_partial_compare_string(controller_string_pause_s, cache->buffer_item, controller_string_pause_length, cache->content_action.array[0]) == F_equal_to) { + type = controller_rule_action_type_execute_pause; + } + else if (fl_string_dynamic_partial_compare_string(controller_string_reload_s, cache->buffer_item, controller_string_reload_length, cache->content_action.array[0]) == F_equal_to) { + type = controller_rule_action_type_execute_reload; + } + else if (fl_string_dynamic_partial_compare_string(controller_string_restart_s, cache->buffer_item, controller_string_restart_length, cache->content_action.array[0]) == F_equal_to) { + type = controller_rule_action_type_execute_restart; + } + else if (fl_string_dynamic_partial_compare_string(controller_string_resume_s, cache->buffer_item, controller_string_resume_length, cache->content_action.array[0]) == F_equal_to) { + type = controller_rule_action_type_execute_resume; + } + else if (fl_string_dynamic_partial_compare_string(controller_string_start_s, cache->buffer_item, controller_string_start_length, cache->content_action.array[0]) == F_equal_to) { + type = controller_rule_action_type_execute_start; + } + else if (fl_string_dynamic_partial_compare_string(controller_string_stop_s, cache->buffer_item, controller_string_stop_length, cache->content_action.array[0]) == F_equal_to) { + type = controller_rule_action_type_execute_stop; + } + else if (fl_string_dynamic_partial_compare_string(controller_string_thaw_s, cache->buffer_item, controller_string_thaw_length, cache->content_action.array[0]) == F_equal_to) { + type = controller_rule_action_type_execute_thaw; + } + } + + if (!type) { + if (global.main->error.verbosity != f_console_verbosity_quiet) { + controller_print_lock(global.main->error.to, global.thread); + + fl_print_format("%c%[%SRule item action '%]", global.main->error.to.stream, f_string_eol_s[0], global.main->error.context, global.main->error.prefix, global.main->error.context); + fl_print_format("%[%s%]", global.main->error.to.stream, global.main->error.notable, controller_string_rerun_s, global.main->error.notable); + fl_print_format("%[' has '%]", global.main->error.to.stream, global.main->error.context, global.main->error.context); + fl_print_format("%[%/Q%]", global.main->error.to.stream, global.main->error.notable, cache->buffer_item, cache->content_action.array[0], global.main->error.notable); + fl_print_format("%[' as the first value, only the following are allowed: '%]", global.main->error.to.stream, global.main->error.context, global.main->error.context); + fl_print_format("%[%s%]%[', '%]", global.main->error.to.stream, global.main->error.notable, controller_string_freeze_s, global.main->error.notable, global.main->error.context, global.main->error.context); + fl_print_format("%[%s%]%[', '%]", global.main->error.to.stream, global.main->error.notable, controller_string_kill_s, global.main->error.notable, global.main->error.context, global.main->error.context); + fl_print_format("%[%s%]%[', '%]", global.main->error.to.stream, global.main->error.notable, controller_string_pause_s, global.main->error.notable, global.main->error.context, global.main->error.context); + fl_print_format("%[%s%]%[', '%]", global.main->error.to.stream, global.main->error.notable, controller_string_reload_s, global.main->error.notable, global.main->error.context, global.main->error.context); + fl_print_format("%[%s%]%[', '%]", global.main->error.to.stream, global.main->error.notable, controller_string_restart_s, global.main->error.notable, global.main->error.context, global.main->error.context); + fl_print_format("%[%s%]%[', '%]", global.main->error.to.stream, global.main->error.notable, controller_string_resume_s, global.main->error.notable, global.main->error.context, global.main->error.context); + fl_print_format("%[%s%]%[', '%]", global.main->error.to.stream, global.main->error.notable, controller_string_start_s, global.main->error.notable, global.main->error.context, global.main->error.context); + fl_print_format("%[%s%]%[', or '%]", global.main->error.to.stream, global.main->error.notable, controller_string_stop_s, global.main->error.notable, global.main->error.context, global.main->error.context); + fl_print_format("%[%s%]", global.main->error.to.stream, global.main->error.notable, controller_string_thaw_s, global.main->error.notable, global.main->error.context); + fl_print_format("%['.%]%c", global.main->error.to.stream, global.main->error.context, global.main->error.context, f_string_eol_s[0]); + + controller_rule_error_print_cache(global.main->error, cache->action, F_true); + + controller_print_unlock_flush(global.main->error.to, global.thread); + } + + return F_status_set_error(F_valid_not); + } + + controller_rule_rerun_item_t *rerun_item = 0; + + if (cache->content_action.used > 1) { + if (fl_string_dynamic_partial_compare_string(controller_string_failure_s, cache->buffer_item, controller_string_failure_length, cache->content_action.array[1]) == F_equal_to) { + rerun_item = &item->reruns[type].failure; + item->reruns[type].is |= controller_rule_rerun_is_failure; + } + else if (fl_string_dynamic_partial_compare_string(controller_string_success_s, cache->buffer_item, controller_string_success_length, cache->content_action.array[1]) == F_equal_to) { + rerun_item = &item->reruns[type].success; + item->reruns[type].is |= controller_rule_rerun_is_success; + } + } + else { + if (global.main->error.verbosity != f_console_verbosity_quiet) { + controller_print_lock(global.main->error.to, global.thread); + + fl_print_format("%c%[%SRule item action '%]", global.main->error.to.stream, f_string_eol_s[0], global.main->error.context, global.main->error.prefix, global.main->error.context); + fl_print_format("%[%s%]", global.main->error.to.stream, global.main->error.notable, controller_string_rerun_s, global.main->error.notable); + fl_print_format("%[' has '%]", global.main->error.to.stream, global.main->error.context, global.main->error.context); + fl_print_format("%[%/Q%]", global.main->error.to.stream, global.main->error.notable, cache->buffer_item, cache->content_action.array[1], global.main->error.notable); + fl_print_format("%[' as the second value, only the following are allowed: '%]", global.main->error.to.stream, global.main->error.context, global.main->error.context); + fl_print_format("%[%s%]%[' or '%]", global.main->error.to.stream, global.main->error.notable, controller_string_stop_s, global.main->error.notable, global.main->error.context, global.main->error.context); + fl_print_format("%[%s%]", global.main->error.to.stream, global.main->error.notable, controller_string_thaw_s, global.main->error.notable, global.main->error.context); + fl_print_format("%['.%]%c", global.main->error.to.stream, global.main->error.context, global.main->error.context, f_string_eol_s[0]); + + controller_rule_error_print_cache(global.main->error, cache->action, F_true); + + controller_print_unlock_flush(global.main->error.to, global.thread); + } + + return F_status_set_error(F_valid_not); + } + + for (f_array_length_t i = 2; i < cache->content_action.used; ++i) { + + if (fl_string_dynamic_partial_compare_string(controller_string_delay_s, cache->buffer_item, controller_string_delay_length, cache->content_action.array[i]) == F_equal_to) { + status = controller_rule_action_read_rerun_number(global, controller_string_delay_s, cache, &i, &rerun_item->delay); + } + else if (fl_string_dynamic_partial_compare_string(controller_string_max_s, cache->buffer_item, controller_string_max_length, cache->content_action.array[i]) == F_equal_to) { + status = controller_rule_action_read_rerun_number(global, controller_string_max_s, cache, &i, &rerun_item->max); + } + else if (fl_string_dynamic_partial_compare_string(controller_string_reset_s, cache->buffer_item, controller_string_reset_length, cache->content_action.array[i]) == F_equal_to) { + item->reruns[type].is |= rerun_item == &item->reruns[type].failure ? controller_rule_rerun_is_failure_reset : controller_rule_rerun_is_success_reset; + } + else { + if (global.main->error.verbosity != f_console_verbosity_quiet) { + controller_print_lock(global.main->error.to, global.thread); + + fl_print_format("%c%[%SRule item action '%]", global.main->error.to.stream, f_string_eol_s[0], global.main->error.context, global.main->error.prefix, global.main->error.context); + fl_print_format("%[%s%]", global.main->error.to.stream, global.main->error.notable, controller_string_rerun_s, global.main->error.notable); + fl_print_format("%[' has an unknown value '%]", global.main->error.to.stream, global.main->error.context, global.main->error.context); + fl_print_format("%[%/Q%]", global.main->error.to.stream, global.main->error.notable, cache->buffer_item, cache->content_action.array[i], global.main->error.notable); + fl_print_format("%['.%]%c", global.main->error.to.stream, global.main->error.context, global.main->error.context, f_string_eol_s[0]); + + controller_rule_error_print_cache(global.main->error, cache->action, F_true); + + controller_print_unlock_flush(global.main->error.to, global.thread); + } + + return F_status_set_error(F_valid_not); + } + } // for + } + else if (type == controller_rule_action_type_with) { + item->with = 0; + + for (f_array_length_t i = 0; i < cache->content_action.used; ++i) { + + if (fl_string_dynamic_partial_compare_string(controller_string_full_path_s, cache->buffer_item, controller_string_full_path_length, cache->content_action.array[i]) == F_equal_to) { + item->with |= controller_with_full_path; + } + else { + if (global.main->error.verbosity != f_console_verbosity_quiet) { + controller_print_lock(global.main->error.to, global.thread); + + fl_print_format("%c%[%SUnknown value '%]", global.main->error.to.stream, f_string_eol_s[0], global.main->error.context, global.main->error.prefix, global.main->error.context); + fl_print_format("%[%/Q%]", global.main->error.to.stream, global.main->error.notable, cache->buffer_item, cache->content_action.array[i], global.main->error.notable); + fl_print_format("%[' for rule item action '%]%[%s%]", global.main->error.to.stream, global.main->error.context, global.main->error.context, global.main->error.notable, controller_string_with_s, global.main->error.notable); + fl_print_format("%['.%]%c", global.main->error.to.stream, global.main->error.context, global.main->error.context, f_string_eol_s[0]); + + controller_rule_error_print_cache(global.main->error, cache->action, F_true); + + controller_print_unlock_flush(global.main->error.to, global.thread); + } + + status = F_status_set_error(F_valid_not); + break; + } + } // for + } else if (item->type == controller_rule_item_type_script || item->type == controller_rule_item_type_utility) { status = f_string_dynamics_increase(controller_common_allocation_small, &actions->array[actions->used].parameters); @@ -402,19 +574,20 @@ extern "C" { if (F_status_is_error(status)) break; } // for - if (F_status_is_error_not(status)) { + if (F_status_is_error(status)) { + controller_error_print(global.main->error, F_status_set_fine(status), "f_string_dynamic_partial_mash_nulless", F_true, global.thread); + } + else { status = f_string_dynamic_terminate_after(&actions->array[actions->used].parameters.array[0]); if (F_status_is_error(status)) { controller_error_print(global.main->error, F_status_set_fine(status), "f_string_dynamic_terminate_after", F_true, global.thread); } else { - actions->array[actions->used++].parameters.used = 1; + actions->array[actions->used].parameters.used = 1; } } } - - return status; } else { status = f_fss_count_lines(cache->buffer_item, range->start, &actions->array[actions->used].line); @@ -462,6 +635,74 @@ extern "C" { } #endif // _di_controller_rule_action_read_ +#ifndef _di_controller_rule_action_read_rerun_number_ + f_status_t controller_rule_action_read_rerun_number(const controller_global_t global, const f_string_t name, controller_cache_t *cache, f_array_length_t *index, f_number_unsigned_t *number) { + + f_status_t status = F_none; + f_number_unsigned_t parsed = 0; + + if (*index + 1 == cache->content_action.used) { + status = F_status_set_error(F_valid_not); + } + else { + status = fl_conversion_string_to_number_signed(cache->buffer_item.string, cache->content_action.array[++(*index)], &parsed); + + if (F_status_set_fine(status) == F_number_positive) { + status = fl_conversion_string_to_number_signed(cache->buffer_item.string, controller_range_after_number_sign(cache->buffer_item, cache->content_action.array[*index]), &parsed); + } + + if (status == F_data_not) { + status = F_status_set_error(F_valid_not); + } + } + + if (F_status_is_error(status)) { + if (global.main->error.verbosity != f_console_verbosity_quiet) { + status = F_status_set_fine(status); + + if (status != F_valid_not && status != F_number && status != F_number_decimal && status != F_number_overflow && status != F_number_underflow && status != F_number_negative) { + controller_error_print(global.main->error, F_status_set_fine(status), "f_string_dynamics_increase", F_true, global.thread); + } + else { + controller_print_lock(global.main->error.to, global.thread); + + fl_print_format("%c%[%SRule item action '%]", global.main->error.to.stream, f_string_eol_s[0], global.main->error.context, global.main->error.prefix, global.main->error.context); + fl_print_format("%[%s%]", global.main->error.to.stream, global.main->error.notable, controller_string_rerun_s, global.main->error.notable); + fl_print_format("%[' requires a positive whole number or 0 for the '%]", global.main->error.to.stream, global.main->error.context, global.main->error.context); + fl_print_format("%[%S%]", global.main->error.to.stream, global.main->error.notable, name, global.main->error.notable); + fl_print_format("%[' value", global.main->error.to.stream, global.main->error.context, global.main->error.context); + + if (*index + 1 == cache->content_action.used) { + fl_print_format(", but none were given.%]%c", global.main->error.to.stream, global.main->error.context, f_string_eol_s[0]); + } + else { + fl_print_format(", but '%]%[%/Q%]", global.main->error.to.stream, global.main->error.context, global.main->error.notable, cache->buffer_item, cache->content_action.array[*index], global.main->error.notable); + + if (status == F_number || status == F_number_decimal) { + fl_print_format("%[' was given.%]%c", global.main->error.to.stream, global.main->error.context, global.main->error.context, f_string_eol_s[0]); + } + else if (status == F_number_overflow) { + fl_print_format("%[' is too large.%]%c", global.main->error.to.stream, global.main->error.context, global.main->error.context, f_string_eol_s[0]); + } + else { + fl_print_format("%[' is negative.%]%c", global.main->error.to.stream, global.main->error.context, global.main->error.context, f_string_eol_s[0]); + } + } + + controller_rule_error_print_cache(global.main->error, cache->action, F_true); + + controller_print_unlock_flush(global.main->error.to, global.thread); + } + } + + return status; + } + + *number = parsed; + return F_none; + } +#endif // _di_controller_rule_action_read_rerun_number_ + #ifndef _di_controller_rule_copy_ f_status_t controller_rule_copy(const controller_rule_t source, controller_rule_t *destination) { @@ -632,7 +873,25 @@ extern "C" { } item_destination->type = item_source->type; + item_destination->with = item_source->with; item_destination->line = item_source->line; + item_destination->pid_file.used = 0; + + status = f_string_dynamic_append(item_source->pid_file, &item_destination->pid_file); + if (F_status_is_error(status)) return status; + + status = f_string_dynamic_terminate_after(&item_destination->pid_file); + if (F_status_is_error(status)) return status; + + for (j = 0; j < controller_rule_action_type_execute__enum_size; ++j) { + item_destination->reruns[j].is = item_source->reruns[j].is; + item_destination->reruns[j].failure.count = item_source->reruns[j].failure.count; + item_destination->reruns[j].failure.delay = item_source->reruns[j].failure.delay; + item_destination->reruns[j].failure.max = item_source->reruns[j].failure.max; + item_destination->reruns[j].success.count = item_source->reruns[j].success.count; + item_destination->reruns[j].success.delay = item_source->reruns[j].success.delay; + item_destination->reruns[j].success.max = item_source->reruns[j].success.max; + } // for for (j = 0; j < item_source->actions.used; ++j) { @@ -823,10 +1082,6 @@ extern "C" { f_array_length_t j = 0; f_array_length_t k = 0; - f_string_dynamic_t *pid_file = 0; - - uint8_t with = 0; - // child processes should receive all signals and handle the signals as they see fit. f_signal_how_t signals = f_signal_how_t_initialize; f_signal_set_empty(&signals.block); @@ -897,20 +1152,6 @@ extern "C" { if (process->rule.items.array[i].type == controller_rule_item_type_setting) continue; - with = 0; - - for (j = 0; j < process->rule.items.array[i].actions.used; ++j) { - - if (process->rule.items.array[i].actions.array[j].type == controller_rule_action_type_with) { - for (k = 0; k < process->rule.items.array[i].actions.array[j].parameters.used; ++k) { - - if (fl_string_dynamic_compare_string(controller_string_full_path_s, process->rule.items.array[i].actions.array[j].parameters.array[k], controller_string_full_path_length) == F_equal_to) { - with |= controller_with_full_path; - } - } // for - } - } // for - for (j = 0; j < process->rule.items.array[i].actions.used; ++j) { if (!controller_thread_is_enabled_process(process, global.thread)) { @@ -924,10 +1165,11 @@ extern "C" { execute_set.parameter.data = 0; execute_set.parameter.option = fl_execute_parameter_option_threadsafe | fl_execute_parameter_option_return; - if (with & controller_with_full_path) { + if (process->rule.items.array[i].with & controller_with_full_path) { execute_set.parameter.option |= fl_execute_parameter_option_path; } + // @todo: wrap these executions (foreground and background) in an additional loop to re-execution on the given re-run conditions. if (process->rule.items.array[i].type == controller_rule_item_type_command) { status = controller_rule_execute_foreground(process->rule.items.array[i].type, process->rule.items.array[i].actions.array[j], 0, process->rule.items.array[i].actions.array[j].parameters, options, global, &execute_set, process); @@ -963,23 +1205,8 @@ extern "C" { } } else if (process->rule.items.array[i].type == controller_rule_item_type_service) { - pid_file = 0; - - for (k = 0; k < process->rule.items.array[i].actions.used; ++k) { - - if (process->rule.items.array[i].actions.array[k].type != controller_rule_action_type_pid_file) { - continue; - } - - if (!process->rule.items.array[i].actions.array[k].parameters.used) { - continue; - } - - pid_file = &process->rule.items.array[i].actions.array[k].parameters.array[0]; - } // for - - if (pid_file) { - status = controller_rule_execute_pid_with(*pid_file, process->rule.items.array[i].type, process->rule.items.array[i].actions.array[j], 0, process->rule.items.array[i].actions.array[j].parameters, options, with, global, &execute_set, process); + if (process->rule.items.array[i].pid_file.used) { + status = controller_rule_execute_pid_with(process->rule.items.array[i].pid_file, process->rule.items.array[i].type, process->rule.items.array[i].actions.array[j], 0, process->rule.items.array[i].actions.array[j].parameters, options, process->rule.items.array[i].with, global, &execute_set, process); if (status == F_child || status == F_signal || F_status_set_fine(status) == F_lock) break; @@ -1002,25 +1229,10 @@ extern "C" { } } else if (process->rule.items.array[i].type == controller_rule_item_type_utility) { - pid_file = 0; - - for (k = 0; k < process->rule.items.array[i].actions.used; ++k) { - - if (process->rule.items.array[i].actions.array[k].type != controller_rule_action_type_pid_file) { - continue; - } - - if (!process->rule.items.array[i].actions.array[k].parameters.used) { - continue; - } - - pid_file = &process->rule.items.array[i].actions.array[k].parameters.array[0]; - } // for - - if (pid_file) { + if (process->rule.items.array[i].pid_file.used) { execute_set.parameter.data = &process->rule.items.array[i].actions.array[j].parameters.array[0]; - status = controller_rule_execute_pid_with(*pid_file, process->rule.items.array[i].type, process->rule.items.array[i].actions.array[j], process->rule.script.used ? process->rule.script.string : controller_default_program_script, arguments_none, options, with, global, &execute_set, process); + status = controller_rule_execute_pid_with(process->rule.items.array[i].pid_file, process->rule.items.array[i].type, process->rule.items.array[i].actions.array[j], process->rule.script.used ? process->rule.script.string : controller_default_program_script, arguments_none, options, process->rule.items.array[i].with, global, &execute_set, process); if (status == F_child || status == F_signal || F_status_set_fine(status) == F_lock) break; @@ -1692,7 +1904,10 @@ extern "C" { break; } - if (fl_string_dynamic_compare_string(controller_string_group_s, cache->action.name_action, controller_string_group_length) == F_equal_to) { + if (fl_string_dynamic_compare_string(controller_string_freeze_s, cache->action.name_action, controller_string_freeze_length) == F_equal_to) { + type = controller_rule_action_type_freeze; + } + else if (fl_string_dynamic_compare_string(controller_string_group_s, cache->action.name_action, controller_string_group_length) == F_equal_to) { type = controller_rule_action_type_group; } else if (fl_string_dynamic_compare_string(controller_string_kill_s, cache->action.name_action, controller_string_kill_length) == F_equal_to) { @@ -1704,21 +1919,27 @@ extern "C" { else if (fl_string_dynamic_compare_string(controller_string_pid_file_s, cache->action.name_action, controller_string_pid_file_length) == F_equal_to) { type = controller_rule_action_type_pid_file; } + else if (fl_string_dynamic_compare_string(controller_string_reload_s, cache->action.name_action, controller_string_reload_length) == F_equal_to) { + type = controller_rule_action_type_reload; + } + else if (fl_string_dynamic_compare_string(controller_string_rerun_s, cache->action.name_action, controller_string_rerun_length) == F_equal_to) { + type = controller_rule_action_type_rerun; + } else if (fl_string_dynamic_compare_string(controller_string_restart_s, cache->action.name_action, controller_string_restart_length) == F_equal_to) { type = controller_rule_action_type_restart; } else if (fl_string_dynamic_compare_string(controller_string_resume_s, cache->action.name_action, controller_string_resume_length) == F_equal_to) { type = controller_rule_action_type_resume; } - else if (fl_string_dynamic_compare_string(controller_string_reload_s, cache->action.name_action, controller_string_reload_length) == F_equal_to) { - type = controller_rule_action_type_reload; - } else if (fl_string_dynamic_compare_string(controller_string_start_s, cache->action.name_action, controller_string_start_length) == F_equal_to) { type = controller_rule_action_type_start; } else if (fl_string_dynamic_compare_string(controller_string_stop_s, cache->action.name_action, controller_string_stop_length) == F_equal_to) { type = controller_rule_action_type_stop; } + else if (fl_string_dynamic_compare_string(controller_string_thaw_s, cache->action.name_action, controller_string_thaw_length) == F_equal_to) { + type = controller_rule_action_type_thaw; + } else if (fl_string_dynamic_compare_string(controller_string_user_s, cache->action.name_action, controller_string_user_length) == F_equal_to) { type = controller_rule_action_type_user; } @@ -5480,6 +5701,7 @@ extern "C" { if (rule.items.used) { controller_rule_action_t *action = 0; controller_rule_item_t *item = 0; + controller_rule_rerun_item_t *rerun_item = 0; f_string_dynamic_t *parameter = 0; f_array_length_t j = 0; @@ -5492,6 +5714,87 @@ extern "C" { fl_print_format(" %[%s%] {%c", main->output.stream, main->context.set.important, controller_string_item_s, main->context.set.important, f_string_eol_s[0]); fl_print_format(" %[%s%] %Q%c", main->output.stream, main->context.set.important, controller_string_type_s, main->context.set.important, controller_rule_item_type_name(item->type), f_string_eol_s[0]); + fl_print_format(" %[%s%] {%c", main->output.stream, main->context.set.important, controller_string_rerun_s, main->context.set.important, f_string_eol_s[0]); + for (j = 0; j < controller_rule_action_type_execute__enum_size; ++j) { + + for (k = 0; k < 2; ++k) { + if (!k && (item->reruns[j].is & controller_rule_rerun_is_failure)) { + rerun_item = &item->reruns[j].failure; + } + else if (k && (item->reruns[j].is & controller_rule_rerun_is_success)) { + rerun_item = &item->reruns[j].success; + } + else { + rerun_item = 0; + continue; + } + + fl_print_format(" %[", main->output.stream, main->context.set.important); + switch (j) { + case controller_rule_action_type_execute_freeze: + f_print_terminated(controller_string_freeze_s, main->output.stream); + break; + + case controller_rule_action_type_execute_kill: + f_print_terminated(controller_string_kill_s, main->output.stream); + break; + + case controller_rule_action_type_execute_pause: + f_print_terminated(controller_string_pause_s, main->output.stream); + break; + + case controller_rule_action_type_execute_reload: + f_print_terminated(controller_string_reload_s, main->output.stream); + break; + + case controller_rule_action_type_execute_restart: + f_print_terminated(controller_string_restart_s, main->output.stream); + break; + + case controller_rule_action_type_execute_resume: + f_print_terminated(controller_string_resume_s, main->output.stream); + break; + + case controller_rule_action_type_execute_start: + f_print_terminated(controller_string_start_s, main->output.stream); + break; + + case controller_rule_action_type_execute_stop: + f_print_terminated(controller_string_stop_s, main->output.stream); + break; + + case controller_rule_action_type_execute_thaw: + f_print_terminated(controller_string_thaw_s, main->output.stream); + break; + + default: + break; + } + + fl_print_format("%] %s", main->output.stream, main->context.set.important, k ? controller_string_success_s : controller_string_failure_s); + fl_print_format(" %s %ul %s %ul", main->output.stream, controller_string_delay_s, rerun_item->delay, controller_string_max_s, rerun_item->max); + + if (!k && (item->reruns[j].is & controller_rule_rerun_is_failure_reset) || k && (item->reruns[j].is & controller_rule_rerun_is_success_reset)) { + fl_print_format(" %s", main->output.stream, controller_string_reset_s); + } + + f_print_terminated(f_string_eol_s, main->output.stream); + } // for + } // for + fl_print_format(" }%c", main->output.stream, f_string_eol_s[0]); + + fl_print_format(" %[%s%]", main->output.stream, main->context.set.important, controller_string_pid_file_s, main->context.set.important); + if (item->pid_file.used) { + fl_print_format(" %Q", main->output.stream, item->pid_file); + } + f_print_terminated(f_string_eol_s, main->output.stream); + + fl_print_format(" %[%s%]", main->output.stream, main->context.set.important, controller_string_with_s, main->context.set.important); + if (item->with & controller_with_full_path) { + fl_print_format(" %s", main->output.stream, controller_string_full_path_s); + } + f_print_terminated(f_string_eol_s, main->output.stream); + for (j = 0; j < item->actions.used; ++j) { action = &item->actions.array[j]; diff --git a/level_3/controller/c/private-rule.h b/level_3/controller/c/private-rule.h index 0f8e793..64a0f76 100644 --- a/level_3/controller/c/private-rule.h +++ b/level_3/controller/c/private-rule.h @@ -560,6 +560,7 @@ extern "C" { * * @return * F_none on success. + * F_valid_not (with error bit) on invalid data. * * Errors (with error bit) from: f_fss_count_lines(). * Errors (with error bit) from: f_string_dynamic_partial_append_nulless(). @@ -776,6 +777,37 @@ extern "C" { #endif // _di_controller_rule_read_ /** + * Process a number from a rule file, incrementing index as necessary. + * + * This prints error messages as necessary. + * + * This is intended to be called by controller_rule_action_read(). + * + * @param global + * The global data. + * @param name + * The name representing the value whose number is being processed. + * @param cache + * A structure for containing and caching relevant data. + * @param index + * The position within the content action array for some rule to process. + * @param number + * The processed number will be saved here. + * + * @return + * F_none on success. + * F_valid_not (with error bit) on failure due to invalid value. + * + * Errors (with error bit) from: fl_conversion_string_to_number_signed(). + * + * @see controller_rule_action_read() + * @see fl_conversion_string_to_number_signed() + */ +#ifndef _di_controller_rule_action_read_rerun_number_ + extern f_status_t controller_rule_action_read_rerun_number(const controller_global_t global, const f_string_t name, controller_cache_t *cache, f_array_length_t *index, f_number_unsigned_t *number) f_attribute_visibility_internal; +#endif // _di_controller_rule_action_read_rerun_number_ + +/** * Read the content within the buffer, extracting all valid settings. * * This will perform additional FSS read functions as appropriate. diff --git a/level_3/controller/data/settings/rules/terminal/four.rule b/level_3/controller/data/settings/rules/terminal/four.rule index ae72e92..3748807 100644 --- a/level_3/controller/data/settings/rules/terminal/four.rule +++ b/level_3/controller/data/settings/rules/terminal/four.rule @@ -11,3 +11,6 @@ setting: command: start agetty -8 tty4 linux + + rerun start success delay 1000 reset + rerun start failure delay 5000 max 100 diff --git a/level_3/controller/data/settings/rules/terminal/one.rule b/level_3/controller/data/settings/rules/terminal/one.rule index 7310ff6..faa1e09 100644 --- a/level_3/controller/data/settings/rules/terminal/one.rule +++ b/level_3/controller/data/settings/rules/terminal/one.rule @@ -11,3 +11,6 @@ setting: command: start agetty -8 -i -J - linux + + rerun start success delay 1000 reset + rerun start failure delay 5000 diff --git a/level_3/controller/data/settings/rules/terminal/three.rule b/level_3/controller/data/settings/rules/terminal/three.rule index a203b39..f73ad24 100644 --- a/level_3/controller/data/settings/rules/terminal/three.rule +++ b/level_3/controller/data/settings/rules/terminal/three.rule @@ -11,3 +11,6 @@ setting: command: start agetty -8 tty3 linux + + rerun start success delay 1000 reset + rerun start failure delay 5000 max 100 diff --git a/level_3/controller/data/settings/rules/terminal/two.rule b/level_3/controller/data/settings/rules/terminal/two.rule index 98aef1a..d0ab2cc 100644 --- a/level_3/controller/data/settings/rules/terminal/two.rule +++ b/level_3/controller/data/settings/rules/terminal/two.rule @@ -11,3 +11,6 @@ setting: command: start agetty -8 tty2 linux + + rerun start success delay 1000 reset + rerun start failure delay 5000 max 100 diff --git a/level_3/controller/documents/rule.txt b/level_3/controller/documents/rule.txt index a12869d..fc0edd5 100644 --- a/level_3/controller/documents/rule.txt +++ b/level_3/controller/documents/rule.txt @@ -36,7 +36,7 @@ Rule Documentation: The first argument is either "existing" or "new", where for "existing" the process is run inside the existing control used by the parent and when "new" the process is executed within a new control group namespace entirely. In the case of "group" and "user"\: - Only users and groups that the user the controller program is being run as may be used. + Only users and groups that the user the controller program is being run as is allowed to use may be used. In the case of "limit"\: The first parameter must be one of: "as", "core", "cpu", "data", "fsize", "locks", "memlock", "msgqueue", "nice", "nofile", "nproc", "rss", "rtprio", "rttime", "sigpending", or "stack". @@ -100,15 +100,25 @@ Rule Documentation: The "utility" Rule Type provides a "script" accompanied with a PID file (Process Identifier file). - There are nine Rule Actions used to execute ("freeze", "kill", "pause", "restart", "resume", "reload", "start", "stop", and "thaw")\: + There are nine Rule Actions used to execute ("freeze", "kill", "pause", "reload", "restart", "resume", "start", "stop", and "thaw")\: When "restart" Object's Content is not provided, then "start" and "stop" is called when the rule is executed using the restart Action, if both "start" and "stop" are provided. When "reload", "start", or "stop" Object's Content are not provided, then no respective Action is performed. Commands are conditionally available depending on the presence of these, such as if "stop" is not provided then "stop" (and "restart") will not be available for the "control" program(s) to use. - Thee are additional Rule Actions not used to execute ("pid_file" and "with")\: + Thee are additional Rule Actions not used to execute ("pid_file", "rerun", and "with")\: The "pid_file" Object's Content designates the path to the PID file created by the called program. + The "rerun" Object's Content designates how to re-run a given execution Rule type. + The first Content represents the execution type, which may be one of: "freeze", "kill", "pause", "reload", "restart", "resume", "start", "stop", and "thaw". + The second Content represents when to run this re-run is triggered, which is either "success" (return code of 0) or "failure" (return code is not 0). + The third Content and more represent additional options for fine tuning how the re-run is perforrmed\: + When "delay", followed by a number of MegaTime (MT) (equivalent to milliseconds) in which to wait before attempting the re-run. + When "max", followed by a positive number or the number 0 designating the maximum number of re-runs to perform. + When "reset", the "max" re-run counter is reset for the opposite re-run when this re-run is triggered, such as\: + A "rerun start success reset" and a "rerun failure max 10", the failure counter would reset to 0 when the "success" re-run is performed and not when the "failure" re-run is performed. + A "max" of 0 designates that the re-run will happen infinitely. + The "with" Object's Content designates special flags designating very specific behavior to be applied to any single Rule Type. The following flags are supported: "full_path": Used only by Rule Types that execute something, wherein the entire full path is used for execution and is assigned as argument[0] (such as "/bin/bash"). diff --git a/level_3/controller/specifications/rule.txt b/level_3/controller/specifications/rule.txt index e3a8245..2ab539c 100644 --- a/level_3/controller/specifications/rule.txt +++ b/level_3/controller/specifications/rule.txt @@ -50,6 +50,7 @@ Rule Specification: "kill": One or more Content representing a program being executed and its arguments. "pause": One or more Content representing a program being executed and its arguments. "reload": One or more Content representing a program being executed and its arguments. + "rerun": Two or more Content representing a Rule type that executes and its properties. "restart": One or more Content representing a program being executed and its arguments. "resume": One or more Content representing a program being executed and its arguments. "start": One or more Content representing a program being executed and its arguments. @@ -59,6 +60,7 @@ Rule Specification: The "service" and "utility" Rule Types allow the following the FSS-0001 (Extended)\: "pid_file": One Content representing the path to a PID file. + "rerun": Two or more Content representing a Rule type that executes and its properties. "with": One or more Content representing special options for the Rule Type. The "command" and "service" Rule Types allow the following the FSS-0003 (Extended List)\: @@ -82,3 +84,9 @@ Rule Specification: "start": A list repesenting the contents of a script, such as a GNU Bash shell. "stop": A list repesenting the contents of a script, such as a GNU Bash shell. "thaw": A list repesenting the contents of a script, such as a GNU Bash shell. + + The "rerun" Rule Type Content has the following structure\: + The first Content represents one of: "freeze", "kill", "pause", "reload", "restart", "resume", "start", "stop", or "thaw". + The second Content represents one of: "success" or "failure". + The third and more Content represents one of: "delay", "max", or "reset". + Where "delay" and "max" must be followed by a positive number or the number 0. -- 1.8.3.1