#define controller_string_environment "environment"
#define controller_string_failsafe "failsafe"
#define controller_string_group "group"
+ #define controller_string_how "how"
#define controller_string_item "item"
#define controller_string_kill "kill"
#define controller_string_main "main"
#define controller_string_method "method"
#define controller_string_name "name"
#define controller_string_need "need"
+ #define controller_string_no "no"
#define controller_string_parameter "parameter"
#define controller_string_path "path"
#define controller_string_pid "pid"
#define controller_string_setting "setting"
#define controller_string_start "start"
#define controller_string_stop "stop"
+ #define controller_string_synchronous "synchronous"
#define controller_string_timeout "timeout"
#define controller_string_type "type"
#define controller_string_use "use"
#define controller_string_wait "wait"
#define controller_string_want "want"
#define controller_string_wish "wish"
+ #define controller_string_yes "yes"
#define controller_string_action_length 6
#define controller_string_actions_length 7
#define controller_string_environment_length 11
#define controller_string_failsafe_length 8
#define controller_string_group_length 5
+ #define controller_string_how_length 3
#define controller_string_item_length 4
#define controller_string_kill_length 4
#define controller_string_main_length 4
#define controller_string_method_length 6
#define controller_string_name_length 4
#define controller_string_need_length 4
+ #define controller_string_no_length 2
#define controller_string_parameter_length 9
#define controller_string_path_length 4
#define controller_string_pid_length 3
#define controller_string_setting_length 7
#define controller_string_start_length 5
#define controller_string_stop_length 4
+ #define controller_string_synchronous_length 11
#define controller_string_timeout_length 7
#define controller_string_type_length 4
#define controller_string_use_length 3
#define controller_string_wait_length 4
#define controller_string_want_length 4
#define controller_string_wish_length 4
+ #define controller_string_yes_length 3
#endif // _di_controller_string_
#ifndef _di_controller_rule_action_t_
controller_rule_setting_type_wish,
};
+ #define controller_rule_option_simulate 0x1
+ #define controller_rule_option_asynchronous 0x2
+ #define controller_rule_option_wait 0x4
+
typedef struct {
f_status_t status;
f_number_signed_t process; // @todo: for background/threaded support (ideally should hold the process id, but remove if this ends up not being the strategy) (this can also be used by the parent/main process to check to see if the child no longer a child of this process).
// report pid file error but because this could be an "init" program, consider the pid file as optional and continue on.
if (F_status_is_error(status)) {
- fll_error_file_print(data.error, F_status_set_fine(status), "controller_file_pid_create", F_true, setting->path_pid.string, "create", fll_error_file_type_file);
-
- controller_entry_error_print(data.error, *cache);
// always return immediately on memory errors.
if (F_status_set_fine(status) == F_memory_not || F_status_set_fine(status) == F_memory_allocation || F_status_set_fine(status) == F_memory_reallocation) {
+ fll_error_file_print(data.error, F_status_set_fine(status), "controller_file_pid_create", F_true, setting->path_pid.string, "create", fll_error_file_type_file);
+
+ controller_entry_error_print(data.error, *cache);
+
return status;
}
+ fll_error_file_print(data.warning, F_status_set_fine(status), "controller_file_pid_create", F_true, setting->path_pid.string, "create", fll_error_file_type_file);
+
+ controller_entry_error_print(data.warning, *cache);
+
status = F_none;
}
}
f_array_length_t at_i = 0;
f_array_length_t at_j = 1;
+ uint8_t rule_options = 0;
+
controller_entry_actions_t *actions = 0;
const bool simulate = data.parameters[controller_parameter_test].result == f_console_result_found;
}
if (F_status_is_error(actions->array[cache->ats.array[at_j]].status)) {
- if (simulate) {
- fprintf(data.output.stream, "%c", f_string_eol_s[0]);
- fprintf(data.output.stream, "The entry item action '");
- fprintf(data.output.stream, "%s%s%s", data.context.set.title.before->string, cache->name_action.string, data.context.set.title.after->string);
- fprintf(data.output.stream, "' is in a %sfailed%s state, skipping execution.%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]);
+
+ if (actions->array[cache->ats.array[at_j]].type == controller_entry_action_type_rule) {
+
+ if (simulate) {
+ fprintf(data.output.stream, "%c", f_string_eol_s[0]);
+ fprintf(data.output.stream, "The entry item action '");
+ fprintf(data.output.stream, "%s%s%s", data.context.set.title.before->string, cache->name_action.string, data.context.set.title.after->string);
+
+ if (actions->array[cache->ats.array[at_j]].parameters.used) {
+ fprintf(data.output.stream, " ");
+ fprintf(data.output.stream, "%s", data.context.set.notable.before->string);
+ controller_entry_action_parameters_print(data.output.stream, actions->array[cache->ats.array[at_j]]);
+ fprintf(data.output.stream, "%s", data.context.set.notable.after->string);
+ }
+
+ fprintf(data.output.stream, "' is %s and is in a %sfailed%s state, skipping execution.%c", actions->array[cache->ats.array[at_j]].code & controller_entry_rule_code_require ? "required" : "optional", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]);
+ }
+ else if (actions->array[cache->ats.array[at_j]].code & controller_entry_rule_code_require) {
+
+ if (data.error.verbosity != f_console_verbosity_quiet) {
+ fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
+ fprintf(data.error.to.stream, "%s%sThe entry item action '", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s);
+ fprintf(data.error.to.stream, "%s%s%s", data.error.context.after->string, data.error.notable.before->string, cache->name_action.string);
+
+ if (actions->array[cache->ats.array[at_j]].parameters.used) {
+ fprintf(data.error.to.stream, " ");
+ controller_entry_action_parameters_print(data.error.to.stream, actions->array[cache->ats.array[at_j]]);
+ }
+
+ fprintf(data.error.to.stream, "%s%s' is ", data.error.notable.after->string, data.error.context.before->string);
+ fprintf(data.error.to.stream, "%s%srequired%s", data.error.context.after->string, data.error.notable.before->string, data.error.notable.after->string);
+ fprintf(data.error.to.stream, "%s and is in a ", data.error.context.before->string);
+ fprintf(data.error.to.stream, "%s%sfailed%s", data.error.context.after->string, data.error.notable.before->string, data.error.notable.after->string);
+ fprintf(data.error.to.stream, "%s state, skipping execution.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]);
+ }
+
+ controller_entry_error_print(data.error, *cache);
+
+ return F_status_is_error(F_require);
+ }
+ else if (data.warning.verbosity == f_console_verbosity_debug) {
+ fprintf(data.warning.to.stream, "%c", f_string_eol_s[0]);
+ fprintf(data.warning.to.stream, "%s%sThe entry item action '", data.warning.context.before->string, data.warning.prefix ? data.warning.prefix : f_string_empty_s);
+ fprintf(data.warning.to.stream, "%s%s%s", data.warning.context.after->string, data.warning.notable.before->string, cache->name_action.string);
+
+ if (actions->array[cache->ats.array[at_j]].parameters.used) {
+ fprintf(data.warning.to.stream, " ");
+ controller_entry_action_parameters_print(data.warning.to.stream, actions->array[cache->ats.array[at_j]]);
+ }
+
+ fprintf(data.warning.to.stream, "%s%s' is ", data.warning.notable.after->string, data.warning.context.before->string);
+ fprintf(data.warning.to.stream, "%s%srequired%s", data.warning.context.after->string, data.warning.notable.before->string, data.warning.notable.after->string);
+ fprintf(data.warning.to.stream, "%s and is in a ", data.warning.context.before->string);
+ fprintf(data.warning.to.stream, "%s%sfailed%s", data.warning.context.after->string, data.warning.notable.before->string, data.warning.notable.after->string);
+ fprintf(data.warning.to.stream, "%s state, skipping execution.%s%c", data.warning.context.before->string, data.warning.context.after->string, f_string_eol_s[0]);
+
+ controller_entry_error_print(data.warning, *cache);
+ }
}
else {
- // @todo check to see if this rule is "required" and if so immediately fail, otherwise report a failure as a warning (normal verbosity, not debug verbosity).
+ if (simulate) {
+ fprintf(data.output.stream, "%c", f_string_eol_s[0]);
+ fprintf(data.output.stream, "The entry item action '");
+ fprintf(data.output.stream, "%s%s%s", data.context.set.title.before->string, cache->name_action.string, data.context.set.title.after->string);
+
+ if (actions->array[cache->ats.array[at_j]].parameters.used) {
+ fprintf(data.output.stream, " ");
+ fprintf(data.output.stream, "%s", data.context.set.notable.before->string);
+ controller_entry_action_parameters_print(data.output.stream, actions->array[cache->ats.array[at_j]]);
+ fprintf(data.output.stream, "%s", data.context.set.notable.after->string);
+ }
+
+ fprintf(data.output.stream, "' is in a %sfailed%s state, skipping.%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]);
+ }
+ else if (data.warning.verbosity == f_console_verbosity_debug) {
+ fprintf(data.warning.to.stream, "%c", f_string_eol_s[0]);
+ fprintf(data.warning.to.stream, "%s%sThe entry item action '", data.warning.context.before->string, data.warning.prefix ? data.warning.prefix : f_string_empty_s);
+ fprintf(data.warning.to.stream, "%s%s", data.warning.notable.before->string, cache->name_action.string);
+
+ if (actions->array[cache->ats.array[at_j]].parameters.used) {
+ fprintf(data.warning.to.stream, " ");
+ controller_entry_action_parameters_print(data.warning.to.stream, actions->array[cache->ats.array[at_j]]);
+ }
+
+ fprintf(data.warning.to.stream, "%s' is in a ", data.warning.notable.after->string);
+ fprintf(data.warning.to.stream, "%s%sfailed%s", data.warning.context.after->string, data.warning.notable.before->string, data.warning.notable.after->string);
+ fprintf(data.warning.to.stream, "%s state, skipping.%s%c", data.warning.context.before->string, data.warning.context.after->string, f_string_eol_s[0]);
+
+ controller_entry_error_print(data.warning, *cache);
+ }
}
continue;
fprintf(data.output.stream, "%c", f_string_eol_s[0]);
fprintf(data.output.stream, "Ignoring entry item action '");
fprintf(data.output.stream, "%s%s%s", data.context.set.title.before->string, controller_string_ready, data.context.set.title.after->string);
- fprintf(data.output.stream, "', state is already ready.%c", f_string_eol_s[0]);
+ fprintf(data.output.stream, "', state already is ready.%c", f_string_eol_s[0]);
}
}
else if (actions->array[cache->ats.array[at_j]].type == controller_entry_action_type_item) {
fprintf(data.output.stream, "'.%c", f_string_eol_s[0]);
}
+ // the rule is not yet loaded, ensure that it is loaded.
if (at == setting->rules.used) {
+
+ // rule execution will re-use the existing cache, so save the current cache.
+ const f_array_length_t cache_line_action = cache->line_action;
+ const f_array_length_t cache_line_item = cache->line_item;
+
+ const f_string_length_t cache_name_action_used = cache->name_action.used;
+ const f_string_length_t cache_name_item_used = cache->name_item.used;
+ const f_string_length_t cache_name_file_used = cache->name_file.used;
+
+ char cache_name_action[cache_name_action_used];
+ char cache_name_item[cache_name_item_used];
+ char cache_name_file[cache_name_file_used];
+
+ memcpy(cache_name_action, cache->name_action.string, cache->name_action.used);
+ memcpy(cache_name_item, cache->name_item.string, cache->name_item.used);
+ memcpy(cache_name_file, cache->name_file.string, cache->name_file.used);
+
status = controller_rule_read(data, *setting, rule_id, cache, &setting->rules.array[setting->rules.used]);
+ // restore cache.
+ memcpy(cache->name_action.string, cache_name_action, cache_name_action_used);
+ memcpy(cache->name_item.string, cache_name_item, cache_name_item_used);
+ memcpy(cache->name_file.string, cache_name_file, cache_name_file_used);
+
+ cache->name_action.string[cache_name_action_used] = 0;
+ cache->name_item.string[cache_name_item_used] = 0;
+ cache->name_file.string[cache_name_file_used] = 0;
+
+ cache->name_action.used = cache_name_action_used;
+ cache->name_item.used = cache_name_item_used;
+ cache->name_file.used = cache_name_file_used;
+
+ cache->line_action = cache_line_action;
+ cache->line_item = cache_line_item;
+
if (F_status_is_error(status)) {
controller_entry_error_print(data.error, *cache);
memcpy(cache_name_file, cache->name_file.string, cache->name_file.used);
if (actions->array[cache->ats.array[at_j]].type == controller_entry_action_type_rule) {
+ rule_options = 0;
+
+ if (simulate) {
+ rule_options |= controller_rule_option_simulate;
+ }
+
+ if (actions->array[cache->ats.array[at_j]].code & controller_entry_rule_code_asynchronous) {
+ rule_options |= controller_rule_option_asynchronous;
+ }
+
+ if (actions->array[cache->ats.array[at_j]].code & controller_entry_rule_code_wait) {
+ rule_options |= controller_rule_option_wait;
+ }
+
// @todo: this will also need to support the asynchronous/wait behavior.
- status = controller_rule_process(data, at, simulate, setting, cache);
+ status = controller_rule_process(data, at, rule_options, setting, cache);
}
// restore cache.
}
}
}
-
} // for
cache->line_action = 0;
#endif // _di_controller_rule_path_
#ifndef _di_controller_rule_process_
- f_return_status controller_rule_process(const controller_data_t data, const f_array_length_t index, const bool simulate, controller_setting_t *setting, controller_cache_t *cache) {
+ f_return_status controller_rule_process(const controller_data_t data, const f_array_length_t index, const uint8_t options, controller_setting_t *setting, controller_cache_t *cache) {
if (index >= setting->rules.used) {
fll_error_print(data.error, F_parameter, "controller_rule_process", F_true);
controller_rule_t *rule = &setting->rules.array[index];
- if (simulate && data.parameters[controller_parameter_validate].result == f_console_result_found) {
- controller_rule_simulate(data, *cache, index, setting);
+ if ((options & controller_rule_option_simulate) && data.parameters[controller_parameter_validate].result == f_console_result_found) {
+ controller_rule_simulate(data, *cache, index, options, setting);
}
{
status = F_status_set_error(F_found_not);
controller_rule_error_print(data.error, *cache, F_true);
- if (!simulate) break;
+ if (!(options & controller_rule_option_simulate)) break;
}
else {
if (data.warning.verbosity == f_console_verbosity_debug) {
memcpy(cache_name_file, cache->name_file.string, cache->name_file.used);
// @todo: this should pass or use the asynchronous state.
- status = controller_rule_process(data, at, simulate, setting, cache);
+ status = controller_rule_process(data, at, options, setting, cache);
// restore cache.
memcpy(cache->name_action.string, cache_name_action, cache_name_action_used);
controller_rule_error_need_want_wish_print(data.error, strings[i], dynamics[i]->array[j].string, "failed during execution");
controller_rule_error_print(data.error, *cache, F_true);
- if (!simulate || F_status_set_fine(status) == F_memory_not || F_status_set_fine(status) == F_memory_allocation || F_status_set_fine(status) == F_memory_reallocation) {
+ if (!(options & controller_rule_option_simulate) || F_status_set_fine(status) == F_memory_not || F_status_set_fine(status) == F_memory_allocation || F_status_set_fine(status) == F_memory_reallocation) {
break;
}
}
status = F_status_set_error(F_found_not);
controller_rule_error_print(data.error, *cache, F_true);
- if (!simulate) break;
+ if (!(options & controller_rule_option_simulate)) break;
}
else {
if (data.warning.verbosity == f_console_verbosity_debug) {
}
} // for
- if (F_status_is_error(status) && !simulate) break;
+ if (F_status_is_error(status) && !(options & controller_rule_option_simulate)) break;
} // for
}
- if (!simulate && F_status_is_error_not(status)) {
+ if (!(options & controller_rule_option_simulate) && F_status_is_error_not(status)) {
status = controller_rule_execute(data, *cache, index, setting);
if (F_status_is_error(status)) {
#endif // _di_controller_rule_setting_read_
#ifndef _di_controller_rule_simulate_
- void controller_rule_simulate(const controller_data_t data, const controller_cache_t cache, const f_array_length_t index, controller_setting_t *setting) {
+ void controller_rule_simulate(const controller_data_t data, const controller_cache_t cache, const f_array_length_t index, const uint8_t options, controller_setting_t *setting) {
// @todo this needs the "action" in which to perform, such as "start", "stop", "restart", etc..
fprintf(data.output.stream, "Rule %s%s%s {%c", data.context.set.title.before->string, rule->id.used ? rule->id.string : f_string_empty_s, data.context.set.title.after->string, f_string_eol_s[0]);
fprintf(data.output.stream, " %s%s%s %s%c", data.context.set.important.before->string, controller_string_name, data.context.set.important.after->string, rule->name.used ? rule->name.string : f_string_empty_s, f_string_eol_s[0]);
fprintf(data.output.stream, " %s%s%s %s%c", data.context.set.important.before->string, controller_string_control_group, data.context.set.important.after->string, rule->control_group.used ? rule->control_group.string : f_string_empty_s, f_string_eol_s[0]);
+ fprintf(data.output.stream, " %s%s%s %s%c", data.context.set.important.before->string, controller_string_how, data.context.set.important.after->string, options & controller_rule_option_asynchronous ? controller_string_asynchronous : controller_string_synchronous, f_string_eol_s[0]);
+ fprintf(data.output.stream, " %s%s%s %s%c", data.context.set.important.before->string, controller_string_wait, data.context.set.important.after->string, options & controller_rule_option_wait ? controller_string_yes : controller_string_no, f_string_eol_s[0]);
f_array_length_t i = 0;