I am going to be using controller program to codestorm how I want the execute functions to handle forking with child.
I may simplify the "pipe" arguments to only accept an input pipe and then write a execute fork functions that perform the fork and return to the caller so that the caller fully handles everything.
This would allow for the "non-fork" (as in "fork" is not in the function names) functions to only focus on simple executions.
This could then make way for the asynchronous behavior that is planned.
#endif
/**
- * A set containing the three standard descriptors for use in pipes.
+ * A set containing the standard descriptors for use in pipes during the execution process.
*
* Future versions may suppot stdwarn and stddebug if there ever is such a thing.
*
if (f_file_exists(setting.path_pid.string) == F_true) {
if (data->error.verbosity != f_console_verbosity_quiet) {
fprintf(data->error.to.stream, "%c", f_string_eol_s[0]);
- fprintf(data->error.to.stream, "%s%sThe pid file must not already exist.%s%c", data->error.context.before->string, data->error.prefix ? data->error.prefix : f_string_empty_s, data->error.context.after->string, f_string_eol_s[0]);
+ fprintf(data->error.to.stream, "%s%sThe pid file '", data->error.context.before->string, data->error.prefix ? data->error.prefix : f_string_empty_s);
+ fprintf(data->error.to.stream, "%s%s%s%s", data->error.context.after->string, data->error.notable.before->string, setting.path_pid.string, data->error.notable.after->string);
+ fprintf(data->error.to.stream, "%s' must not already exist.%s%c", data->error.context.before->string, data->error.context.after->string, f_string_eol_s[0]);
}
status = F_status_set_error(F_available_not);
if (f_file_exists(setting.path_pid.string) == F_true) {
if (data->error.verbosity != f_console_verbosity_quiet) {
fprintf(data->error.to.stream, "%c", f_string_eol_s[0]);
- fprintf(data->error.to.stream, "%s%sThe pid file must not already exist.%s%c", data->error.context.before->string, data->error.prefix ? data->error.prefix : f_string_empty_s, data->error.context.after->string, f_string_eol_s[0]);
+ fprintf(data->error.to.stream, "%s%sThe pid file '", data->error.context.before->string, data->error.prefix ? data->error.prefix : f_string_empty_s);
+ fprintf(data->error.to.stream, "%s%s%s%s", data->error.context.after->string, data->error.notable.before->string, setting.path_pid.string, data->error.notable.after->string);
+ fprintf(data->error.to.stream, "%s' must not already exist.%s%c", data->error.context.before->string, data->error.context.after->string, f_string_eol_s[0]);
}
status = F_status_set_error(F_available_not);
}
if (F_status_is_error_not(status)) {
- status = controller_process_entry(*data, &setting, &cache);
+ status = controller_process_entry(data, &setting, &cache);
}
- if (F_status_is_error(status)) {
- setting.ready = controller_setting_ready_fail;
- }
- else {
- setting.ready = controller_setting_ready_done;
+ if (!(status == F_child || status == F_signal)) {
+ if (F_status_is_error(status)) {
+ setting.ready = controller_setting_ready_fail;
+ }
+ else {
+ setting.ready = controller_setting_ready_done;
- // @todo wait here until told to quit, listening for "control" commands (and listening for signals).
- // @todo clear cache periodically while waiting.
- // controller_macro_cache_t_delete_simple(cache);
+ // @todo wait here until told to quit, listening for "control" commands (and listening for signals).
+ // @todo clear cache periodically while waiting.
+ // controller_macro_cache_t_delete_simple(cache);
+ }
}
}
}
}
// ensure a newline is always put at the end of the program execution, unless in quiet mode.
- if (data->error.verbosity != f_console_verbosity_quiet) {
+ if (!(status == F_child || status == F_signal) && data->error.verbosity != f_console_verbosity_quiet) {
if (F_status_is_error(status)) {
fprintf(data->error.to.stream, "%c", f_string_eol_s[0]);
}
controller_delete_data(data);
+ if (status == F_child || status == F_signal) {
+ return status;
+ }
+
if (setting.ready == controller_setting_ready_fail) {
// @todo trigger failsafe/fallback execution, if defined.
}
*
* @todo research containers and build in container support into this, providing "container" appropriate verbiage for individual rules.
* @todo research namespaces and user_namespaces, they may be important to support.
+ *
+ * @todo Implement "exit" files that are the opposite of "entry" files whereas rules specified within are all called via the "stop" action type.
+ * This would then allow for switching modes.
*/
#ifndef _controller_h
#include <level_0/color.h>
#include <level_0/console.h>
#include <level_0/directory.h>
+#include <level_0/execute.h>
#include <level_0/file.h>
#include <level_0/fss.h>
#include <level_0/path.h>
#include <level_0/pipe.h>
#include <level_0/print.h>
+#include <level_0/signal.h>
// fll-1 includes
#include <level_1/color.h>
f_string_lengths_t remaining;
bool process_pipe;
- pid_t pid;
f_file_t output;
fll_error_print_t error;
fll_error_print_t warning;
+ pid_t pid;
+ mode_t umask;
+ int child;
+ f_signal_t signal;
+
f_color_context_t context;
} controller_data_t;
controller_console_parameter_t_initialize, \
f_string_lengths_t_initialize, \
F_false, \
- 0, \
f_macro_file_t_initialize(f_type_output, f_type_descriptor_output, f_file_flag_write_only), \
fll_error_print_t_initialize, \
fll_macro_error_print_t_initialize_warning(), \
+ 0, \
+ 0, \
+ 0, \
+ f_signal_t_initialize, \
f_color_context_t_initialize, \
}
#endif // _di_controller_data_t_
int main(const unsigned long argc, const f_string_t *argv) {
const f_console_arguments_t arguments = { argc, argv };
controller_data_t data = controller_data_t_initialize;
+ f_status_t status = F_none;
if (f_pipe_input_exists()) {
data.process_pipe = F_true;
data.pid = getpid();
- const f_status_t status = controller_main(arguments, &data);
+ f_signal_set_empty(&data.signal.set);
+ f_signal_set_add(F_signal_abort, &data.signal.set);
+ f_signal_set_add(F_signal_hangup, &data.signal.set);
+ f_signal_set_add(F_signal_interrupt, &data.signal.set);
+ f_signal_set_add(F_signal_quit, &data.signal.set);
+ f_signal_set_add(F_signal_termination, &data.signal.set);
+ f_signal_set_handle(SIG_BLOCK, &data.signal.set);
+
+ status = f_signal_open(&data.signal);
+
+ // if there is an error opening a signal descriptor, then do not handle signals.
+ if (F_status_is_error(status)) {
+ f_signal_set_handle(SIG_UNBLOCK, &data.signal.set);
+ f_signal_close(&data.signal);
+ }
+
+ // @fixme: bad design in POSIX where there is no get umask without setting it.
+ data.umask = umask(0);
+
+ // restore umask.
+ umask(data.umask);
+
+ status = controller_main(arguments, &data);
// flush output pipes before closing.
fflush(f_type_output);
close(f_type_descriptor_input);
close(f_type_descriptor_error);
+ f_signal_close(&data.signal);
+
+ if (status == F_child) {
+ exit(data.child);
+ }
+
if (F_status_is_error(status)) {
return 1;
}
#define controller_string_entry "entry"
#define controller_string_entries "entries"
#define controller_string_environment "environment"
+ #define controller_string_fail "fail"
#define controller_string_failsafe "failsafe"
#define controller_string_group "group"
#define controller_string_how "how"
#define controller_string_name "name"
#define controller_string_need "need"
#define controller_string_no "no"
+ #define controller_string_optional "optional"
#define controller_string_parameter "parameter"
#define controller_string_path "path"
#define controller_string_pid "pid"
#define controller_string_ready "ready"
#define controller_string_reload "reload"
#define controller_string_require "require"
+ #define controller_string_required "required"
#define controller_string_restart "restart"
#define controller_string_rule "rule"
#define controller_string_rules "rules"
#define controller_string_setting "setting"
#define controller_string_start "start"
#define controller_string_stop "stop"
+ #define controller_string_succeed "succeed"
#define controller_string_synchronous "synchronous"
#define controller_string_timeout "timeout"
#define controller_string_type "type"
#define controller_string_entry_length 5
#define controller_string_entries_length 7
#define controller_string_environment_length 11
+ #define controller_string_fail_length 4
#define controller_string_failsafe_length 8
#define controller_string_group_length 5
#define controller_string_how_length 3
#define controller_string_name_length 4
#define controller_string_need_length 4
#define controller_string_no_length 2
+ #define controller_string_optional_length 8
#define controller_string_parameter_length 9
#define controller_string_path_length 4
#define controller_string_pid_length 3
#define controller_string_ready_length 5
#define controller_string_reload_length 6
#define controller_string_require_length 7
+ #define controller_string_required_length 8
#define controller_string_restart_length 7
#define controller_string_rule_length 4
#define controller_string_rules_length 5
#define controller_string_setting_length 7
#define controller_string_start_length 5
#define controller_string_stop_length 4
+ #define controller_string_succeed_length 7
#define controller_string_synchronous_length 11
#define controller_string_timeout_length 7
#define controller_string_type_length 4
controller_rule_setting_type_wish,
};
- #define controller_rule_option_simulate 0x1
- #define controller_rule_option_asynchronous 0x2
- #define controller_rule_option_wait 0x4
+ #define controller_rule_option_asynchronous 0x1
+ #define controller_rule_option_require 0x2
+ #define controller_rule_option_simulate 0x4
+ #define controller_rule_option_wait 0x8
typedef struct {
f_status_t status;
status = f_file_stream_open(path_pid.string, f_macro_file_open_mode_truncate, &file);
if (F_status_is_error(status)) return status;
- fprintf(file.stream, "%llu\n", data.pid);
+ fprintf(file.stream, "%llu%c", data.pid, f_string_eol_s[0]);
f_file_stream_close(F_true, &file);
#ifndef _di_controller_file_pid_delete_
void controller_file_pid_delete(const controller_data_t data, const f_string_static_t path_pid) {
+ // only delete if the file exists and there is no error while checking.
if (f_file_exists(path_pid.string) != F_true) {
return;
}
#endif // _di_controller_preprocess_entry_
#ifndef _di_controller_process_entry_
- f_return_status controller_process_entry(const controller_data_t data, controller_setting_t *setting, controller_cache_t *cache) {
+ f_return_status controller_process_entry(controller_data_t *data, controller_setting_t *setting, controller_cache_t *cache) {
f_status_t status = F_none;
f_array_length_t i = 0;
controller_entry_actions_t *actions = 0;
- const bool simulate = data.parameters[controller_parameter_test].result == f_console_result_found;
+ const bool simulate = data->parameters[controller_parameter_test].result == f_console_result_found;
cache->ats.used = 0;
cache->line_action = 0;
cache->stack.used = 0;
if (setting->ready == controller_setting_ready_yes) {
- status = controller_perform_ready(data, setting, cache);
+ status = controller_perform_ready(*data, setting, cache);
if (F_status_is_error(status)) return status;
}
status = fl_type_array_lengths_increase_by(controller_default_allocation_step, &cache->ats);
if (F_status_is_error(status)) {
- fll_error_print(data.error, F_status_set_fine(status), "fl_type_array_lengths_increase_by", F_true);
- controller_entry_error_print(data.error, *cache);
+ fll_error_print(data->error, F_status_set_fine(status), "fl_type_array_lengths_increase_by", F_true);
+ controller_entry_error_print(data->error, *cache);
return status;
}
status = controller_string_dynamic_append_terminated(setting->entry.items.array[0].name, &cache->name_item);
if (F_status_is_error(status)) {
- fll_error_print(data.error, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true);
- controller_entry_error_print(data.error, *cache);
+ fll_error_print(data->error, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true);
+ controller_entry_error_print(data->error, *cache);
return status;
}
if (simulate) {
- fprintf(data.output.stream, "%c", f_string_eol_s[0]);
- fprintf(data.output.stream, "Processing entry item rule '");
- fprintf(data.output.stream, "%s%s%s", data.context.set.title.before->string, controller_string_main, data.context.set.title.after->string);
- fprintf(data.output.stream, "'.%c", f_string_eol_s[0]);
+ fprintf(data->output.stream, "%c", f_string_eol_s[0]);
+ fprintf(data->output.stream, "Processing entry item rule '");
+ fprintf(data->output.stream, "%s%s%s", data->context.set.title.before->string, controller_string_main, data->context.set.title.after->string);
+ fprintf(data->output.stream, "'.%c", f_string_eol_s[0]);
}
for (;;) {
status = controller_string_dynamic_append_terminated(controller_entry_action_type_name(actions->array[cache->ats.array[at_j]].type), &cache->name_action);
if (F_status_is_error(status)) {
- fll_error_print(data.error, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true);
- controller_entry_error_print(data.error, *cache);
+ fll_error_print(data->error, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true);
+ controller_entry_error_print(data->error, *cache);
return status;
}
if (actions->array[cache->ats.array[at_j]].type == controller_entry_action_type_rule) {
if (simulate) {
- fprintf(data.output.stream, "%c", f_string_eol_s[0]);
- fprintf(data.output.stream, "The entry item action '");
- fprintf(data.output.stream, "%s%s%s", data.context.set.title.before->string, cache->name_action.string, data.context.set.title.after->string);
+ fprintf(data->output.stream, "%c", f_string_eol_s[0]);
+ fprintf(data->output.stream, "The entry item action '");
+ fprintf(data->output.stream, "%s%s%s", data->context.set.title.before->string, cache->name_action.string, data->context.set.title.after->string);
if (actions->array[cache->ats.array[at_j]].parameters.used) {
- fprintf(data.output.stream, " ");
- fprintf(data.output.stream, "%s", data.context.set.notable.before->string);
- controller_entry_action_parameters_print(data.output.stream, actions->array[cache->ats.array[at_j]]);
- fprintf(data.output.stream, "%s", data.context.set.notable.after->string);
+ fprintf(data->output.stream, " ");
+ fprintf(data->output.stream, "%s", data->context.set.notable.before->string);
+ controller_entry_action_parameters_print(data->output.stream, actions->array[cache->ats.array[at_j]]);
+ fprintf(data->output.stream, "%s", data->context.set.notable.after->string);
}
- fprintf(data.output.stream, "' is %s and is in a %sfailed%s state, skipping execution.%c", actions->array[cache->ats.array[at_j]].code & controller_entry_rule_code_require ? "required" : "optional", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]);
+ fprintf(data->output.stream, "' is %s and is in a %sfailed%s state, skipping execution.%c", actions->array[cache->ats.array[at_j]].code & controller_entry_rule_code_require ? "required" : "optional", data->error.context.before->string, data->error.context.after->string, f_string_eol_s[0]);
}
else if (actions->array[cache->ats.array[at_j]].code & controller_entry_rule_code_require) {
- if (data.error.verbosity != f_console_verbosity_quiet) {
- fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
- fprintf(data.error.to.stream, "%s%sThe entry item action '", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s);
- fprintf(data.error.to.stream, "%s%s%s", data.error.context.after->string, data.error.notable.before->string, cache->name_action.string);
+ if (data->error.verbosity != f_console_verbosity_quiet) {
+ fprintf(data->error.to.stream, "%c", f_string_eol_s[0]);
+ fprintf(data->error.to.stream, "%s%sThe entry item action '", data->error.context.before->string, data->error.prefix ? data->error.prefix : f_string_empty_s);
+ fprintf(data->error.to.stream, "%s%s%s", data->error.context.after->string, data->error.notable.before->string, cache->name_action.string);
if (actions->array[cache->ats.array[at_j]].parameters.used) {
- fprintf(data.error.to.stream, " ");
- controller_entry_action_parameters_print(data.error.to.stream, actions->array[cache->ats.array[at_j]]);
+ fprintf(data->error.to.stream, " ");
+ controller_entry_action_parameters_print(data->error.to.stream, actions->array[cache->ats.array[at_j]]);
}
- fprintf(data.error.to.stream, "%s%s' is ", data.error.notable.after->string, data.error.context.before->string);
- fprintf(data.error.to.stream, "%s%srequired%s", data.error.context.after->string, data.error.notable.before->string, data.error.notable.after->string);
- fprintf(data.error.to.stream, "%s and is in a ", data.error.context.before->string);
- fprintf(data.error.to.stream, "%s%sfailed%s", data.error.context.after->string, data.error.notable.before->string, data.error.notable.after->string);
- fprintf(data.error.to.stream, "%s state, skipping execution.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]);
+ fprintf(data->error.to.stream, "%s%s' is ", data->error.notable.after->string, data->error.context.before->string);
+ fprintf(data->error.to.stream, "%s%srequired%s", data->error.context.after->string, data->error.notable.before->string, data->error.notable.after->string);
+ fprintf(data->error.to.stream, "%s and is in a ", data->error.context.before->string);
+ fprintf(data->error.to.stream, "%s%sfailed%s", data->error.context.after->string, data->error.notable.before->string, data->error.notable.after->string);
+ fprintf(data->error.to.stream, "%s state, skipping execution.%s%c", data->error.context.before->string, data->error.context.after->string, f_string_eol_s[0]);
}
- controller_entry_error_print(data.error, *cache);
+ controller_entry_error_print(data->error, *cache);
return F_status_is_error(F_require);
}
- else if (data.warning.verbosity == f_console_verbosity_debug) {
- fprintf(data.warning.to.stream, "%c", f_string_eol_s[0]);
- fprintf(data.warning.to.stream, "%s%sThe entry item action '", data.warning.context.before->string, data.warning.prefix ? data.warning.prefix : f_string_empty_s);
- fprintf(data.warning.to.stream, "%s%s%s", data.warning.context.after->string, data.warning.notable.before->string, cache->name_action.string);
+ else if (data->warning.verbosity == f_console_verbosity_debug) {
+ fprintf(data->warning.to.stream, "%c", f_string_eol_s[0]);
+ fprintf(data->warning.to.stream, "%s%sThe entry item action '", data->warning.context.before->string, data->warning.prefix ? data->warning.prefix : f_string_empty_s);
+ fprintf(data->warning.to.stream, "%s%s%s", data->warning.context.after->string, data->warning.notable.before->string, cache->name_action.string);
if (actions->array[cache->ats.array[at_j]].parameters.used) {
- fprintf(data.warning.to.stream, " ");
- controller_entry_action_parameters_print(data.warning.to.stream, actions->array[cache->ats.array[at_j]]);
+ fprintf(data->warning.to.stream, " ");
+ controller_entry_action_parameters_print(data->warning.to.stream, actions->array[cache->ats.array[at_j]]);
}
- fprintf(data.warning.to.stream, "%s%s' is ", data.warning.notable.after->string, data.warning.context.before->string);
- fprintf(data.warning.to.stream, "%s%srequired%s", data.warning.context.after->string, data.warning.notable.before->string, data.warning.notable.after->string);
- fprintf(data.warning.to.stream, "%s and is in a ", data.warning.context.before->string);
- fprintf(data.warning.to.stream, "%s%sfailed%s", data.warning.context.after->string, data.warning.notable.before->string, data.warning.notable.after->string);
- fprintf(data.warning.to.stream, "%s state, skipping execution.%s%c", data.warning.context.before->string, data.warning.context.after->string, f_string_eol_s[0]);
+ fprintf(data->warning.to.stream, "%s%s' is ", data->warning.notable.after->string, data->warning.context.before->string);
+ fprintf(data->warning.to.stream, "%s%srequired%s", data->warning.context.after->string, data->warning.notable.before->string, data->warning.notable.after->string);
+ fprintf(data->warning.to.stream, "%s and is in a ", data->warning.context.before->string);
+ fprintf(data->warning.to.stream, "%s%sfailed%s", data->warning.context.after->string, data->warning.notable.before->string, data->warning.notable.after->string);
+ fprintf(data->warning.to.stream, "%s state, skipping execution.%s%c", data->warning.context.before->string, data->warning.context.after->string, f_string_eol_s[0]);
- controller_entry_error_print(data.warning, *cache);
+ controller_entry_error_print(data->warning, *cache);
}
}
else {
if (simulate) {
- fprintf(data.output.stream, "%c", f_string_eol_s[0]);
- fprintf(data.output.stream, "The entry item action '");
- fprintf(data.output.stream, "%s%s%s", data.context.set.title.before->string, cache->name_action.string, data.context.set.title.after->string);
+ fprintf(data->output.stream, "%c", f_string_eol_s[0]);
+ fprintf(data->output.stream, "The entry item action '");
+ fprintf(data->output.stream, "%s%s%s", data->context.set.title.before->string, cache->name_action.string, data->context.set.title.after->string);
if (actions->array[cache->ats.array[at_j]].parameters.used) {
- fprintf(data.output.stream, " ");
- fprintf(data.output.stream, "%s", data.context.set.notable.before->string);
- controller_entry_action_parameters_print(data.output.stream, actions->array[cache->ats.array[at_j]]);
- fprintf(data.output.stream, "%s", data.context.set.notable.after->string);
+ fprintf(data->output.stream, " ");
+ fprintf(data->output.stream, "%s", data->context.set.notable.before->string);
+ controller_entry_action_parameters_print(data->output.stream, actions->array[cache->ats.array[at_j]]);
+ fprintf(data->output.stream, "%s", data->context.set.notable.after->string);
}
- fprintf(data.output.stream, "' is in a %sfailed%s state, skipping.%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]);
+ fprintf(data->output.stream, "' is in a %sfailed%s state, skipping.%c", data->error.context.before->string, data->error.context.after->string, f_string_eol_s[0]);
}
- else if (data.warning.verbosity == f_console_verbosity_debug) {
- fprintf(data.warning.to.stream, "%c", f_string_eol_s[0]);
- fprintf(data.warning.to.stream, "%s%sThe entry item action '", data.warning.context.before->string, data.warning.prefix ? data.warning.prefix : f_string_empty_s);
- fprintf(data.warning.to.stream, "%s%s", data.warning.notable.before->string, cache->name_action.string);
+ else if (data->warning.verbosity == f_console_verbosity_debug) {
+ fprintf(data->warning.to.stream, "%c", f_string_eol_s[0]);
+ fprintf(data->warning.to.stream, "%s%sThe entry item action '", data->warning.context.before->string, data->warning.prefix ? data->warning.prefix : f_string_empty_s);
+ fprintf(data->warning.to.stream, "%s%s", data->warning.notable.before->string, cache->name_action.string);
if (actions->array[cache->ats.array[at_j]].parameters.used) {
- fprintf(data.warning.to.stream, " ");
- controller_entry_action_parameters_print(data.warning.to.stream, actions->array[cache->ats.array[at_j]]);
+ fprintf(data->warning.to.stream, " ");
+ controller_entry_action_parameters_print(data->warning.to.stream, actions->array[cache->ats.array[at_j]]);
}
- fprintf(data.warning.to.stream, "%s' is in a ", data.warning.notable.after->string);
- fprintf(data.warning.to.stream, "%s%sfailed%s", data.warning.context.after->string, data.warning.notable.before->string, data.warning.notable.after->string);
- fprintf(data.warning.to.stream, "%s state, skipping.%s%c", data.warning.context.before->string, data.warning.context.after->string, f_string_eol_s[0]);
+ fprintf(data->warning.to.stream, "%s' is in a ", data->warning.notable.after->string);
+ fprintf(data->warning.to.stream, "%s%sfailed%s", data->warning.context.after->string, data->warning.notable.before->string, data->warning.notable.after->string);
+ fprintf(data->warning.to.stream, "%s state, skipping.%s%c", data->warning.context.before->string, data->warning.context.after->string, f_string_eol_s[0]);
- controller_entry_error_print(data.warning, *cache);
+ controller_entry_error_print(data->warning, *cache);
}
}
if (setting->ready == controller_setting_ready_wait) {
if (simulate) {
- fprintf(data.output.stream, "%c", f_string_eol_s[0]);
- fprintf(data.output.stream, "Processing entry item action '");
- fprintf(data.output.stream, "%s%s%s", data.context.set.title.before->string, controller_string_ready, data.context.set.title.after->string);
- fprintf(data.output.stream, "'.%c", f_string_eol_s[0]);
+ fprintf(data->output.stream, "%c", f_string_eol_s[0]);
+ fprintf(data->output.stream, "Processing entry item action '");
+ fprintf(data->output.stream, "%s%s%s", data->context.set.title.before->string, controller_string_ready, data->context.set.title.after->string);
+ fprintf(data->output.stream, "'.%c", f_string_eol_s[0]);
}
else {
- controller_perform_ready(data, setting, cache);
+ controller_perform_ready(*data, setting, cache);
if (F_status_is_error(status)) return status;
}
setting->ready = controller_setting_ready_yes;
}
else if (simulate) {
- fprintf(data.output.stream, "%c", f_string_eol_s[0]);
- fprintf(data.output.stream, "Ignoring entry item action '");
- fprintf(data.output.stream, "%s%s%s", data.context.set.title.before->string, controller_string_ready, data.context.set.title.after->string);
- fprintf(data.output.stream, "', state already is ready.%c", f_string_eol_s[0]);
+ fprintf(data->output.stream, "%c", f_string_eol_s[0]);
+ fprintf(data->output.stream, "Ignoring entry item action '");
+ fprintf(data->output.stream, "%s%s%s", data->context.set.title.before->string, controller_string_ready, data->context.set.title.after->string);
+ fprintf(data->output.stream, "', state already is ready.%c", f_string_eol_s[0]);
}
}
else if (actions->array[cache->ats.array[at_j]].type == controller_entry_action_type_item) {
if (actions->array[cache->ats.array[at_j]].number == 0 || actions->array[cache->ats.array[at_j]].number >= setting->entry.items.used) {
// This should not happen if the pre-process is working as designed, but in case it doesn't, return a critical error to prevent infinite recursion and similar errors.
- if (data.error.verbosity != f_console_verbosity_quiet) {
- fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
- fprintf(data.error.to.stream, "%s%sInvalid entry item index ", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s);
- fprintf(data.error.to.stream, "%s%s%llu%s", data.error.context.after->string, data.error.notable.before->string, actions->array[cache->ats.array[at_j]].number, data.error.notable.after->string);
- fprintf(data.error.to.stream, "%s detected.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]);
+ if (data->error.verbosity != f_console_verbosity_quiet) {
+ fprintf(data->error.to.stream, "%c", f_string_eol_s[0]);
+ fprintf(data->error.to.stream, "%s%sInvalid entry item index ", data->error.context.before->string, data->error.prefix ? data->error.prefix : f_string_empty_s);
+ fprintf(data->error.to.stream, "%s%s%llu%s", data->error.context.after->string, data->error.notable.before->string, actions->array[cache->ats.array[at_j]].number, data->error.notable.after->string);
+ fprintf(data->error.to.stream, "%s detected.%s%c", data->error.context.before->string, data->error.context.after->string, f_string_eol_s[0]);
}
- controller_entry_error_print(data.error, *cache);
+ controller_entry_error_print(data->error, *cache);
return F_status_is_error(F_critical);
}
status = fl_type_array_lengths_increase_by(controller_default_allocation_step, &cache->ats);
if (F_status_is_error(status)) {
- fll_error_print(data.error, F_status_set_fine(status), "fl_type_array_lengths_increase_by", F_true);
- controller_entry_error_print(data.error, *cache);
+ fll_error_print(data->error, F_status_set_fine(status), "fl_type_array_lengths_increase_by", F_true);
+ controller_entry_error_print(data->error, *cache);
return status;
}
status = controller_string_dynamic_append_terminated(setting->entry.items.array[cache->ats.array[at_i]].name, &cache->name_item);
if (F_status_is_error(status)) {
- fll_error_print(data.error, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true);
- controller_entry_error_print(data.error, *cache);
+ fll_error_print(data->error, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true);
+ controller_entry_error_print(data->error, *cache);
return status;
}
if (simulate) {
- fprintf(data.output.stream, "%c", f_string_eol_s[0]);
- fprintf(data.output.stream, "Processing entry item '");
- fprintf(data.output.stream, "%s%s%s", data.context.set.title.before->string, cache->name_item.string, data.context.set.title.after->string);
- fprintf(data.output.stream, "'.%c", f_string_eol_s[0]);
+ fprintf(data->output.stream, "%c", f_string_eol_s[0]);
+ fprintf(data->output.stream, "Processing entry item '");
+ fprintf(data->output.stream, "%s%s%s", data->context.set.title.before->string, cache->name_item.string, data->context.set.title.after->string);
+ fprintf(data->output.stream, "'.%c", f_string_eol_s[0]);
}
// exit inner loop to force restarting and start processing the requested item.
status = controller_rules_increase(&setting->rules);
if (F_status_is_error(status)) {
- fll_error_print(data.error, F_status_set_fine(status), "controller_rules_increase", F_true);
- controller_entry_error_print(data.error, *cache);
+ fll_error_print(data->error, F_status_set_fine(status), "controller_rules_increase", F_true);
+ controller_entry_error_print(data->error, *cache);
return status;
}
rule_id_name[actions->array[cache->ats.array[at_j]].parameters.array[0].used] = f_path_separator_s[0];
rule_id_name[rule_id_length] = 0;
- at = controller_rule_find_loaded(data, *setting, rule_id);
+ at = controller_rule_find_loaded(*data, *setting, rule_id);
if (simulate) {
- fprintf(data.output.stream, "%c", f_string_eol_s[0]);
- fprintf(data.output.stream, "%s entry item rule '", actions->array[cache->ats.array[at_j]].type == controller_entry_action_type_rule ? "Processing" : "Considering");
- fprintf(data.output.stream, "%s%s%s", data.context.set.title.before->string, rule_id.string, data.context.set.title.after->string);
- fprintf(data.output.stream, "'.%c", f_string_eol_s[0]);
+ fprintf(data->output.stream, "%c", f_string_eol_s[0]);
+ fprintf(data->output.stream, "%s entry item rule '", actions->array[cache->ats.array[at_j]].type == controller_entry_action_type_rule ? "Processing" : "Considering");
+ fprintf(data->output.stream, "%s%s%s", data->context.set.title.before->string, rule_id.string, data->context.set.title.after->string);
+ fprintf(data->output.stream, "'.%c", f_string_eol_s[0]);
}
// the rule is not yet loaded, ensure that it is loaded.
memcpy(cache_name_item, cache->name_item.string, cache->name_item.used);
memcpy(cache_name_file, cache->name_file.string, cache->name_file.used);
- status = controller_rule_read(data, *setting, rule_id, cache, &setting->rules.array[setting->rules.used]);
+ status = controller_rule_read(*data, *setting, rule_id, cache, &setting->rules.array[setting->rules.used]);
// restore cache.
memcpy(cache->name_action.string, cache_name_action, cache_name_action_used);
cache->line_item = cache_line_item;
if (F_status_is_error(status)) {
- controller_entry_error_print(data.error, *cache);
+ controller_entry_error_print(data->error, *cache);
if (!simulate) break;
}
rule_options |= controller_rule_option_asynchronous;
}
+ if (actions->array[cache->ats.array[at_j]].code & controller_entry_rule_code_require) {
+ rule_options |= controller_rule_option_require;
+ }
+
if (actions->array[cache->ats.array[at_j]].code & controller_entry_rule_code_wait) {
rule_options |= controller_rule_option_wait;
}
// @todo: this will also need to support the asynchronous/wait behavior.
- status = controller_rule_process(data, at, rule_options, setting, cache);
+ status = controller_rule_process(at, controller_rule_action_type_start, rule_options, data, setting, cache);
+
+ if (status == F_child || status == F_signal) break;
}
// restore cache.
}
if (F_status_is_error(status)) {
- controller_entry_error_print(data.error, *cache);
+ controller_entry_error_print(data->error, *cache);
if (!simulate || F_status_set_fine(status) == F_memory_not || F_status_set_fine(status) == F_memory_allocation || F_status_set_fine(status) == F_memory_reallocation) {
break;
code = controller_string_stop;
}
- fprintf(data.output.stream, "%c", f_string_eol_s[0]);
- fprintf(data.output.stream, "Processing entry item action '");
- fprintf(data.output.stream, "%s%s%s", data.context.set.title.before->string, controller_string_timeout, data.context.set.title.after->string);
- fprintf(data.output.stream, "' setting '");
- fprintf(data.output.stream, "%s%s%s", data.context.set.important.before->string, code, data.context.set.important.after->string);
- fprintf(data.output.stream, "' to '");
- fprintf(data.output.stream, "%s%llu%s", data.context.set.important.before->string, actions->array[cache->ats.array[at_j]].number, data.context.set.important.after->string);
- fprintf(data.output.stream, "' MegaTime (milliseconds).%c", f_string_eol_s[0]);
+ fprintf(data->output.stream, "%c", f_string_eol_s[0]);
+ fprintf(data->output.stream, "Processing entry item action '");
+ fprintf(data->output.stream, "%s%s%s", data->context.set.title.before->string, controller_string_timeout, data->context.set.title.after->string);
+ fprintf(data->output.stream, "' setting '");
+ fprintf(data->output.stream, "%s%s%s", data->context.set.important.before->string, code, data->context.set.important.after->string);
+ fprintf(data->output.stream, "' to '");
+ fprintf(data->output.stream, "%s%llu%s", data->context.set.important.before->string, actions->array[cache->ats.array[at_j]].number, data->context.set.important.after->string);
+ fprintf(data->output.stream, "' MegaTime (milliseconds).%c", f_string_eol_s[0]);
}
if (actions->array[cache->ats.array[at_j]].code == controller_entry_timeout_code_kill) {
if (actions->array[cache->ats.array[at_j]].number == 0 || actions->array[cache->ats.array[at_j]].number >= setting->entry.items.used) {
// This should not happen if the pre-process is working as designed, but in case it doesn't, return a critical error to prevent infinite recursion and similar errors.
- if (data.error.verbosity != f_console_verbosity_quiet) {
- fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
- fprintf(data.error.to.stream, "%s%sInvalid entry item index ", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s);
- fprintf(data.error.to.stream, "%s%s%llu%s", data.error.context.after->string, data.error.notable.before->string, actions->array[cache->ats.array[at_j]].number, data.error.notable.after->string);
- fprintf(data.error.to.stream, "%s detected.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]);
+ if (data->error.verbosity != f_console_verbosity_quiet) {
+ fprintf(data->error.to.stream, "%c", f_string_eol_s[0]);
+ fprintf(data->error.to.stream, "%s%sInvalid entry item index ", data->error.context.before->string, data->error.prefix ? data->error.prefix : f_string_empty_s);
+ fprintf(data->error.to.stream, "%s%s%llu%s", data->error.context.after->string, data->error.notable.before->string, actions->array[cache->ats.array[at_j]].number, data->error.notable.after->string);
+ fprintf(data->error.to.stream, "%s detected.%s%c", data->error.context.before->string, data->error.context.after->string, f_string_eol_s[0]);
}
- controller_entry_error_print(data.error, *cache);
+ controller_entry_error_print(data->error, *cache);
return F_status_is_error(F_critical);
}
setting->failsafe_rule_id = actions->array[cache->ats.array[at_j]].number;
if (simulate) {
- fprintf(data.output.stream, "%c", f_string_eol_s[0]);
- fprintf(data.output.stream, "Processing entry item action '");
- fprintf(data.output.stream, "%s%s%s", data.context.set.title.before->string, controller_string_failsafe, data.context.set.title.after->string);
- fprintf(data.output.stream, "' setting value to '");
- fprintf(data.output.stream, "%s%s%s", data.context.set.important.before->string, setting->entry.items.array[setting->failsafe_rule_id].name.string, data.context.set.important.after->string);
- fprintf(data.output.stream, "'.%c", f_string_eol_s[0]);
+ fprintf(data->output.stream, "%c", f_string_eol_s[0]);
+ fprintf(data->output.stream, "Processing entry item action '");
+ fprintf(data->output.stream, "%s%s%s", data->context.set.title.before->string, controller_string_failsafe, data->context.set.title.after->string);
+ fprintf(data->output.stream, "' setting value to '");
+ fprintf(data->output.stream, "%s%s%s", data->context.set.important.before->string, setting->entry.items.array[setting->failsafe_rule_id].name.string, data->context.set.important.after->string);
+ fprintf(data->output.stream, "'.%c", f_string_eol_s[0]);
}
}
}
} // for
+ if (status == F_child || status == F_signal) break;
+
cache->line_action = 0;
cache->name_action.used = 0;
status = controller_string_dynamic_append_terminated(setting->entry.items.array[cache->ats.array[at_i]].name, &cache->name_item);
if (F_status_is_error(status)) {
- fll_error_print(data.error, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true);
- controller_entry_error_print(data.error, *cache);
+ fll_error_print(data->error, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true);
+ controller_entry_error_print(data->error, *cache);
break;
}
}
} // for
+ if (status == F_child || status == F_signal) {
+ return status;
+ }
+
if (F_status_is_error_not(status) && simulate) {
- fprintf(data.output.stream, "%c", f_string_eol_s[0]);
+ fprintf(data->output.stream, "%c", f_string_eol_s[0]);
}
return status;
* @see fl_type_array_lengths_increase_by()
*/
#ifndef _di_controller_process_entry_
- extern f_return_status controller_process_entry(const controller_data_t data, controller_setting_t *setting, controller_cache_t *cache) f_gcc_attribute_visibility_internal;
+ extern f_return_status controller_process_entry(controller_data_t *data, controller_setting_t *setting, controller_cache_t *cache) f_gcc_attribute_visibility_internal;
#endif // _di_controller_process_entry_
/**
}
fprintf(data.error.to.stream, "exactly ", data.error.context.before->string);
- fprintf(data.error.to.stream, "%s%s%u%s", data.error.context.after->string, parameters, data.error.notable.after->string);
+ fprintf(data.error.to.stream, "%s%s%u%s", data.error.context.after->string, data.error.notable.before->string, parameters, data.error.notable.after->string);
fprintf(data.error.to.stream, "%s parameters.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]);
}
}
#endif // _di_controller_rule_error_need_want_wish_print_
#ifndef _di_controller_rule_execute_
- f_return_status controller_rule_execute(const controller_data_t data, const controller_cache_t cache, const f_array_length_t index, controller_setting_t *setting) {
- // @todo this needs the "action" in which to perform, such as "start", "stop", "restart", etc..
- // @todo
+ f_return_status controller_rule_execute(const controller_cache_t cache, const f_array_length_t index, const uint8_t action, controller_data_t *data, controller_setting_t *setting) {
+
+ f_array_length_t i = 0;
+ f_array_length_t j = 0;
+ f_array_length_t k = 0;
+
+ controller_rule_item_t *rule_item = 0;
+ controller_rule_action_t *rule_action = 0;
+
+ for (i = 0; i < setting->rules.array[index].items.used; ++i) {
+
+ if (setting->rules.array[index].items.array[i].type == controller_rule_item_type_setting) continue;
+
+ rule_item = &setting->rules.array[index].items.array[i];
+
+ for (j = 0; j < rule_item->actions.used; ++j) {
+
+ if (rule_item->actions.array[j].type != action) continue;
+
+ rule_action = &rule_item->actions.array[j];
+
+ if (rule_item->type == controller_rule_item_type_command) {
+ if (rule_action->method == controller_rule_action_method_extended) {
+ // @todo
+ }
+ else {
+ // @todo extended list execution.
+ }
+ }
+ else if (rule_item->type == controller_rule_item_type_script) {
+ if (rule_action->method == controller_rule_action_method_extended) {
+ // @todo
+ }
+ else {
+ // @todo extended list execution.
+ }
+ }
+ else if (rule_item->type == controller_rule_item_type_service) {
+ if (rule_action->method == controller_rule_action_method_extended) {
+ // @todo
+ }
+ else {
+ // @todo extended list execution.
+ }
+ }
+ else {
+ // unknown, just ignore for now. (@todo print a warning when in debug mode.)
+ continue;
+ }
+ } // for
+ } // for
+
+ return F_none;
}
#endif // _di_controller_rule_execute_
+#ifndef _di_controller_rule_execute_script_
+ f_return_status controller_rule_execute_script(const controller_rule_action_t action, controller_data_t *data) {
+
+ // child processes should receive all signals, without blocking.
+ f_signal_how_t signals = f_signal_how_t_initialize;
+ f_signal_set_empty(&signals.block);
+ f_signal_set_fill(&signals.block_not);
+
+ f_execute_pipe_t pipe = f_execute_pipe_t_initialize;
+
+ f_status_t status = F_none;
+ //f_status_t status = fll_execute_program_environment(program.string, arguments, environment.names, environment.values, &signals, &pipe, &data->child);
+
+ if (status == F_child) {
+ // @todo wait for parent pipe.
+ // @todo how do I get status code? there will likely need to be more changes to fll_execute_program_environment()...
+ return F_child;
+ }
+
+ // parent process should print to the pipe.
+
+ // @todo handle errors, print messages, etc..
+ if (data->child != 0) {
+ status = F_status_set_error(F_failure);
+ }
+ else if (F_status_is_error(status)) {
+ }
+
+ data->child = 0;
+
+ return status;
+ }
+#endif // _di_controller_rule_execute_script_
+
#ifndef _di_controller_rule_find_loaded_
f_array_length_t controller_rule_find_loaded(const controller_data_t data, const controller_setting_t setting, const f_string_static_t rule_id) {
f_array_length_t i = 0;
for (; i < setting.rules.used; ++i) {
- if (fl_string_dynamic_compare(rule_id, setting.rules.array[i].id) == F_equal_to) {
- return i;
- }
+ if (fl_string_dynamic_compare(rule_id, setting.rules.array[i].id) == F_equal_to) break;
} // for
return i;
#endif // _di_controller_rule_path_
#ifndef _di_controller_rule_process_
- f_return_status controller_rule_process(const controller_data_t data, const f_array_length_t index, const uint8_t options, controller_setting_t *setting, controller_cache_t *cache) {
+ f_return_status controller_rule_process(const f_array_length_t index, const uint8_t action, const uint8_t options, controller_data_t *data, controller_setting_t *setting, controller_cache_t *cache) {
+
+ switch (action) {
+ case controller_rule_action_type_kill:
+ case controller_rule_action_type_reload:
+ case controller_rule_action_type_restart:
+ case controller_rule_action_type_start:
+ case controller_rule_action_type_stop:
+ break;
+
+ default:
+
+ if (data->error.verbosity != f_console_verbosity_quiet) {
+ fprintf(data->error.to.stream, "%c", f_string_eol_s[0]);
+ fprintf(data->error.to.stream, "%s%sUnsupported action type '", data->error.context.before->string, data->error.prefix ? data->error.prefix : f_string_empty_s);
+ fprintf(data->error.to.stream, "%s%s%s%s", data->error.context.after->string, data->error.notable.before->string, controller_rule_action_type_name(action), data->error.notable.after->string);
+ fprintf(data->error.to.stream, "%s' while attempting to execute rule.%s%c", data->error.context.before->string, data->error.context.after->string, f_string_eol_s[0]);
+
+ controller_rule_error_print(data->error, *cache, F_true);
+ }
+
+ return F_status_set_error(F_parameter);
+ }
if (index >= setting->rules.used) {
- fll_error_print(data.error, F_parameter, "controller_rule_process", F_true);
- controller_rule_error_print(data.error, *cache, F_true);
+ fll_error_print(data->error, F_parameter, "controller_rule_process", F_true);
+ controller_rule_error_print(data->error, *cache, F_true);
return F_status_set_error(F_parameter);
}
f_status_t status = fl_type_array_lengths_increase_by(controller_default_allocation_step, &cache->stack);
if (F_status_is_error(status)) {
- fll_error_print(data.error, F_status_set_fine(status), "fl_type_array_lengths_increase_by", F_true);
- controller_rule_error_print(data.error, *cache, F_true);
+ fll_error_print(data->error, F_status_set_fine(status), "fl_type_array_lengths_increase_by", F_true);
+ controller_rule_error_print(data->error, *cache, F_true);
return status;
}
for (; i < cache->stack.used; ++i) {
if (cache->stack.array[i] == index) {
- if (data.error.verbosity != f_console_verbosity_quiet) {
- fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
- fprintf(data.error.to.stream, "%s%sThe rule '", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s);
- fprintf(data.error.to.stream, "%s%s%s%s", data.error.context.after->string, data.error.notable.before->string, setting->rules.array[i].name.string, data.error.notable.after->string);
- fprintf(data.error.to.stream, "%s' is already on the execution stack, this recursion is prohibited.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]);
+ if (data->error.verbosity != f_console_verbosity_quiet) {
+ fprintf(data->error.to.stream, "%c", f_string_eol_s[0]);
+ fprintf(data->error.to.stream, "%s%sThe rule '", data->error.context.before->string, data->error.prefix ? data->error.prefix : f_string_empty_s);
+ fprintf(data->error.to.stream, "%s%s%s%s", data->error.context.after->string, data->error.notable.before->string, setting->rules.array[i].name.string, data->error.notable.after->string);
+ fprintf(data->error.to.stream, "%s' is already on the execution stack, this recursion is prohibited.%s%c", data->error.context.before->string, data->error.context.after->string, f_string_eol_s[0]);
- controller_rule_error_print(data.error, *cache, F_true);
+ controller_rule_error_print(data->error, *cache, F_true);
}
// never continue on recursion errors even in simulate mode.
}
if (F_status_is_error(status)) {
- fll_error_print(data.error, F_status_set_fine(status), "fl_string_append", F_true);
- controller_rule_error_print(data.error, *cache, F_true);
+ fll_error_print(data->error, F_status_set_fine(status), "fl_string_append", F_true);
+ controller_rule_error_print(data->error, *cache, F_true);
return status;
}
status = fl_string_dynamic_append(setting->rules.array[index].id, &cache->name_file);
if (F_status_is_error(status)) {
- fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_append", F_true);
- controller_rule_error_print(data.error, *cache, F_true);
+ fll_error_print(data->error, F_status_set_fine(status), "fl_string_dynamic_append", F_true);
+ controller_rule_error_print(data->error, *cache, F_true);
return status;
}
}
if (F_status_is_error(status)) {
- fll_error_print(data.error, F_status_set_fine(status), "fl_string_append", F_true);
- controller_rule_error_print(data.error, *cache, F_true);
+ fll_error_print(data->error, F_status_set_fine(status), "fl_string_append", F_true);
+ controller_rule_error_print(data->error, *cache, F_true);
return status;
}
status = fl_string_dynamic_terminate_after(&cache->name_file);
if (F_status_is_error(status)) {
- fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_terminate_after", F_true);
- controller_rule_error_print(data.error, *cache, F_true);
+ fll_error_print(data->error, F_status_set_fine(status), "fl_string_dynamic_terminate_after", F_true);
+ controller_rule_error_print(data->error, *cache, F_true);
return status;
}
controller_rule_t *rule = &setting->rules.array[index];
- if ((options & controller_rule_option_simulate) && data.parameters[controller_parameter_validate].result == f_console_result_found) {
- controller_rule_simulate(data, *cache, index, options, setting);
+ if ((options & controller_rule_option_simulate) && data->parameters[controller_parameter_validate].result == f_console_result_found) {
+ controller_rule_simulate(*data, *cache, index, controller_rule_action_type_start, options, setting);
}
{
for (i = 0; i < 3; ++i) {
for (j = 0; j < dynamics[i]->used; ++j) {
- at = controller_rule_find_loaded(data, *setting, dynamics[i]->array[j]);
+ at = controller_rule_find_loaded(*data, *setting, dynamics[i]->array[j]);
if (at == setting->rules.used) {
if (i == 0) {
- controller_rule_error_need_want_wish_print(data.error, strings[i], dynamics[i]->array[j].string, "was not found");
+ controller_rule_error_need_want_wish_print(data->error, strings[i], dynamics[i]->array[j].string, "was not found");
status = F_status_set_error(F_found_not);
- controller_rule_error_print(data.error, *cache, F_true);
+ controller_rule_error_print(data->error, *cache, F_true);
if (!(options & controller_rule_option_simulate)) break;
}
else {
- if (data.warning.verbosity == f_console_verbosity_debug) {
- controller_rule_error_need_want_wish_print(data.warning, strings[i], dynamics[i]->array[j].string, "was not found");
- controller_rule_error_print(data.warning, *cache, F_true);
+ if (data->warning.verbosity == f_console_verbosity_debug) {
+ controller_rule_error_need_want_wish_print(data->warning, strings[i], dynamics[i]->array[j].string, "was not found");
+ controller_rule_error_print(data->warning, *cache, F_true);
}
}
}
status = fl_type_array_lengths_increase_by(controller_default_allocation_step, &cache->stack);
if (F_status_is_error(status)) {
- fll_error_print(data.error, F_status_set_fine(status), "fl_type_array_lengths_increase_by", F_true);
- controller_rule_error_print(data.error, *cache, F_true);
+ fll_error_print(data->error, F_status_set_fine(status), "fl_type_array_lengths_increase_by", F_true);
+ controller_rule_error_print(data->error, *cache, F_true);
// always exit on memory errors, even in simulate mode.
break;
memcpy(cache_name_file, cache->name_file.string, cache->name_file.used);
// @todo: this should pass or use the asynchronous state.
- status = controller_rule_process(data, at, options, setting, cache);
+ status = controller_rule_process(at, controller_rule_action_type_start, options, data, setting, cache);
+
+ if (status == F_child || status == F_signal) break;
// restore cache.
memcpy(cache->name_action.string, cache_name_action, cache_name_action_used);
if (F_status_is_error(status)) {
if (i == 0 || i == 1 || F_status_set_fine(status) == F_memory_not || F_status_set_fine(status) == F_memory_allocation || F_status_set_fine(status) == F_memory_reallocation) {
- controller_rule_error_need_want_wish_print(data.error, strings[i], dynamics[i]->array[j].string, "failed during execution");
- controller_rule_error_print(data.error, *cache, F_true);
+ controller_rule_error_need_want_wish_print(data->error, strings[i], dynamics[i]->array[j].string, "failed during execution");
+ controller_rule_error_print(data->error, *cache, F_true);
if (!(options & controller_rule_option_simulate) || F_status_set_fine(status) == F_memory_not || F_status_set_fine(status) == F_memory_allocation || F_status_set_fine(status) == F_memory_reallocation) {
break;
}
}
else {
- if (data.warning.verbosity == f_console_verbosity_debug) {
- controller_rule_error_need_want_wish_print(data.warning, strings[i], dynamics[i]->array[j].string, "failed during execution");
- controller_rule_error_print(data.warning, *cache, F_true);
+ if (data->warning.verbosity == f_console_verbosity_debug) {
+ controller_rule_error_need_want_wish_print(data->warning, strings[i], dynamics[i]->array[j].string, "failed during execution");
+ controller_rule_error_print(data->warning, *cache, F_true);
}
}
}
else if (F_status_is_error(setting->rules.array[at].status)) {
if (i == 0 || i == 1) {
- controller_rule_error_need_want_wish_print(data.error, strings[i], dynamics[i]->array[j].string, "is in a failed state");
+ controller_rule_error_need_want_wish_print(data->error, strings[i], dynamics[i]->array[j].string, "is in a failed state");
status = F_status_set_error(F_found_not);
- controller_rule_error_print(data.error, *cache, F_true);
+ controller_rule_error_print(data->error, *cache, F_true);
if (!(options & controller_rule_option_simulate)) break;
}
else {
- if (data.warning.verbosity == f_console_verbosity_debug) {
- controller_rule_error_need_want_wish_print(data.warning, strings[i], dynamics[i]->array[j].string, "is in a failed state");
- controller_rule_error_print(data.warning, *cache, F_true);
+ if (data->warning.verbosity == f_console_verbosity_debug) {
+ controller_rule_error_need_want_wish_print(data->warning, strings[i], dynamics[i]->array[j].string, "is in a failed state");
+ controller_rule_error_print(data->warning, *cache, F_true);
}
}
}
}
} // for
+ if (status == F_child || status == F_signal) break;
+
if (F_status_is_error(status) && !(options & controller_rule_option_simulate)) break;
} // for
}
if (!(options & controller_rule_option_simulate) && F_status_is_error_not(status)) {
- status = controller_rule_execute(data, *cache, index, setting);
- if (F_status_is_error(status)) {
- fll_error_print(data.error, F_status_set_fine(status), "controller_rule_execute", F_true);
+ // find at least one of the requested action when the rule is required.
+ if (options & controller_rule_option_require) {
+ bool missing = F_true;
+
+ f_array_length_t j = 0;
+
+ for (i = 0; i < rule->items.used; ++i) {
+
+ for (j = 0; j < rule->items.array[i].actions.used; ++j) {
+
+ if (rule->items.array[i].actions.array[j].type == action) {
+ missing = F_false;
+ break;
+ }
+ } // for
+ } // for
+
+ if (missing) {
+
+ if (data->error.verbosity != f_console_verbosity_quiet) {
+ fprintf(data->error.to.stream, "%c", f_string_eol_s[0]);
+ fprintf(data->error.to.stream, "%s%sThe rule '", data->error.context.before->string, data->error.prefix ? data->error.prefix : f_string_empty_s);
+ fprintf(data->error.to.stream, "%s%s%s%s", data->error.context.after->string, data->error.notable.before->string, rule->name.used ? rule->name.string : f_string_empty_s, data->error.notable.after->string);
+ fprintf(data->error.to.stream, "%s' has no '", data->error.context.before->string);
+ fprintf(data->error.to.stream, "%s%s%s%s", data->error.context.after->string, data->error.notable.before->string, controller_rule_action_type_name(action).string, data->error.notable.after->string);
+ fprintf(data->error.to.stream, "%s' action to execute.%s%c", data->error.context.before->string, data->error.context.after->string, f_string_eol_s[0]);
+
+ controller_rule_error_print(data->error, *cache, F_true);
+ }
+
+ status = F_status_set_error(F_parameter);
+ }
+ }
+
+ if (F_status_is_error_not(status)) {
+ status = controller_rule_execute(*cache, index, action, data, setting);
+
+ if (F_status_is_error(status)) {
+ fll_error_print(data->error, F_status_set_fine(status), "controller_rule_execute", F_true);
+ }
+
+ if (status == F_child) {
+ return F_child;
+ }
}
}
}
if (cache->content_actions.array[i].used != 2) {
- fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
- fprintf(data.error.to.stream, "%s%sRule setting requires exactly two Content.%s%c", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s, data.error.context.after->string, f_string_eol_s[0]);
- controller_rule_error_print(data.error, *cache, F_false);
+ if (data.error.verbosity != f_console_verbosity_quiet) {
+ fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
+ fprintf(data.error.to.stream, "%s%sRule setting requires exactly two Content.%s%c", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s, data.error.context.after->string, f_string_eol_s[0]);
+
+ controller_rule_error_print(data.error, *cache, F_false);
+ }
if (F_status_is_error_not(status_return)) {
status_return = F_status_set_error(F_valid_not);
#endif // _di_controller_rule_setting_read_
#ifndef _di_controller_rule_simulate_
- void controller_rule_simulate(const controller_data_t data, const controller_cache_t cache, const f_array_length_t index, const uint8_t options, controller_setting_t *setting) {
+ void controller_rule_simulate(const controller_data_t data, const controller_cache_t cache, const f_array_length_t index, const uint8_t action, const uint8_t options, controller_setting_t *setting) {
+
+ switch (action) {
+ case controller_rule_action_type_kill:
+ case controller_rule_action_type_reload:
+ case controller_rule_action_type_restart:
+ case controller_rule_action_type_start:
+ case controller_rule_action_type_stop:
+ break;
+
+ default:
+
+ if (data.error.verbosity != f_console_verbosity_quiet) {
+ fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
+ fprintf(data.error.to.stream, "%s%sUnsupported action type '", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s);
+ fprintf(data.error.to.stream, "%s%s%s%s", data.error.context.after->string, data.error.notable.before->string, controller_rule_action_type_name(action).string, data.error.notable.after->string);
+ fprintf(data.error.to.stream, "%s' while attempting to simulate rule execution.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]);
+
+ controller_rule_error_print(data.error, cache, F_true);
+ }
- // @todo this needs the "action" in which to perform, such as "start", "stop", "restart", etc..
+ return;
+ }
controller_rule_t * const rule = &setting->rules.array[index];
+ f_array_length_t i = 0;
+ f_array_length_t j = 0;
+
+ // find at least one of the requested action.
+ {
+ bool missing = F_true;
+
+ for (; i < rule->items.used; ++i) {
+
+ for (j = 0; j < rule->items.array[i].actions.used; ++j) {
+
+ if (rule->items.array[i].actions.array[j].type == action) {
+ missing = F_false;
+ break;
+ }
+ } // for
+ } // for
+
+ if (missing) {
+ fprintf(data.output.stream, "%c", f_string_eol_s[0]);
+ fprintf(data.output.stream, "Rule '");
+ fprintf(data.output.stream, "%s%s%s", data.context.set.title.before->string, rule->name.used ? rule->name.string : f_string_empty_s, data.context.set.title.after->string);
+ fprintf(data.output.stream, "' has no '");
+ fprintf(data.output.stream, "%s%s%s", data.context.set.important.before->string, controller_rule_action_type_name(action).string, data.context.set.important.after->string);
+ fprintf(data.output.stream, "' action to execute and would '");
+ fprintf(data.output.stream, "%s%s%s", data.context.set.important.before->string, options & controller_rule_option_require ? controller_string_fail : controller_string_succeed, data.context.set.important.after->string);
+ fprintf(data.output.stream, "' because it is '");
+ fprintf(data.output.stream, "%s%s%s", data.context.set.important.before->string, options & controller_rule_option_require ? controller_string_required : controller_string_optional, data.context.set.important.after->string);
+ fprintf(data.output.stream, "'.%c", f_string_eol_s[0]);
+ }
+ }
+
fprintf(data.output.stream, "%c", f_string_eol_s[0]);
fprintf(data.output.stream, "Rule %s%s%s {%c", data.context.set.title.before->string, rule->id.used ? rule->id.string : f_string_empty_s, data.context.set.title.after->string, f_string_eol_s[0]);
fprintf(data.output.stream, " %s%s%s %s%c", data.context.set.important.before->string, controller_string_name, data.context.set.important.after->string, rule->name.used ? rule->name.string : f_string_empty_s, f_string_eol_s[0]);
- fprintf(data.output.stream, " %s%s%s %s%c", data.context.set.important.before->string, controller_string_control_group, data.context.set.important.after->string, rule->control_group.used ? rule->control_group.string : f_string_empty_s, f_string_eol_s[0]);
fprintf(data.output.stream, " %s%s%s %s%c", data.context.set.important.before->string, controller_string_how, data.context.set.important.after->string, options & controller_rule_option_asynchronous ? controller_string_asynchronous : controller_string_synchronous, f_string_eol_s[0]);
fprintf(data.output.stream, " %s%s%s %s%c", data.context.set.important.before->string, controller_string_wait, data.context.set.important.after->string, options & controller_rule_option_wait ? controller_string_yes : controller_string_no, f_string_eol_s[0]);
-
- f_array_length_t i = 0;
+ fprintf(data.output.stream, " %s%s%s %s%c", data.context.set.important.before->string, controller_string_control_group, data.context.set.important.after->string, rule->control_group.used ? rule->control_group.string : f_string_empty_s, f_string_eol_s[0]);
fprintf(data.output.stream, " %s%s%s {%c", data.context.set.important.before->string, controller_string_define, data.context.set.important.after->string, f_string_eol_s[0]);
if (rule->define.used) {
- for (; i < rule->define.used; ++i) {
+ for (i = 0; i < rule->define.used; ++i) {
if (rule->define.array[i].name.used && rule->define.array[i].value.used) {
fprintf(data.output.stream, " %s %s=%s %s%c", rule->define.array[i].name.string, data.context.set.important.before->string, data.context.set.important.after->string, rule->define.array[i].value.string, f_string_eol_s[0]);
/**
* Perform an execution of the given rule.
*
- * @param data
- * The program data.
* @param cache
* A structure for containing and caching relevant data.
* @param index
* The position in the setting.rules array representing the rule to simulate.
+ * @param action
+ * The action to perform based on the action type codes.
+ *
+ * Only subset of the action type codes are supported:
+ * - controller_rule_action_type_kill
+ * - controller_rule_action_type_reload
+ * - controller_rule_action_type_restart
+ * - controller_rule_action_type_start
+ * - controller_rule_action_type_stop
+ * @param data
+ * The program data.
* @param setting
* The controller settings data.
*
* @return
* F_none on success.
+ * F_child on child process exiting.
+ * F_signal on (exit) signal received.
*
* On success and the rule is run synchronously, then the individual status for the rule is set to F_complete.
* On success and the rule is run asynchronously, then the individual status for the rule is set to F_busy.
* On failure, the individual status for the rule is set to an appropriate error status.
*/
#ifndef _di_controller_rule_execute_
- extern f_return_status controller_rule_execute(const controller_data_t data, const controller_cache_t cache, const f_array_length_t index, controller_setting_t *setting) f_gcc_attribute_visibility_internal;
+ extern f_return_status controller_rule_execute(const controller_cache_t cache, const f_array_length_t index, const uint8_t action, controller_data_t *data, controller_setting_t *setting) f_gcc_attribute_visibility_internal;
#endif // _di_controller_rule_execute_
/**
*
* This function is recursively called for each "need", "want", and "wish", and has a max recursion length of the max size of the f_array_lengths_t array.
*
- * @todo add asynchronous boolean? (will also need a wait boolean, so this should probably be a uint8_t with using bitwise states).
- *
- * @param data
- * The program data.
* @param index
* Position in the rules array representing the rule to execute
+ * @param action
+ * The action to perform based on the action type codes.
+ *
+ * Only subset of the action type codes are supported:
+ * - controller_rule_action_type_kill
+ * - controller_rule_action_type_reload
+ * - controller_rule_action_type_restart
+ * - controller_rule_action_type_start
+ * - controller_rule_action_type_stop
* @param options
* A number using bits to represent specific boolean options.
* If no bits set, then operate normally in a synchronous manner.
* If bit controller_rule_option_simulate, then the rule execution is in simulation mode (printing a message that the rule would be executed but does not execute the rule).
* If bit controller_rule_option_asynchronous, then run asynchronously.
+ * @param data
+ * The program data.
* @param setting
* The controller settings data.
* @param cache
* This utilizes line_action, line_item, name_action, and name_item from cache, but they are backed up before starting and then restored after finishing.
*
* @return
- * F_none on success.
+ * F_none on success.
+ * F_child on child process exiting.
+ * F_signal on (exit) signal received.
*/
#ifndef _di_controller_rule_process_
- extern f_return_status controller_rule_process(const controller_data_t data, const f_array_length_t index, const uint8_t options, controller_setting_t *setting, controller_cache_t *cache) f_gcc_attribute_visibility_internal;
+ extern f_return_status controller_rule_process(const f_array_length_t index, const uint8_t action, const uint8_t options, controller_data_t *data, controller_setting_t *setting, controller_cache_t *cache) f_gcc_attribute_visibility_internal;
#endif // _di_controller_rule_process_
/**
* A structure for containing and caching relevant data.
* @param index
* The position in the setting.rules array representing the rule to simulate.
+ * @param action
+ * The action to perform based on the action type codes.
+ *
+ * Only subset of the action type codes are supported:
+ * - controller_rule_action_type_kill
+ * - controller_rule_action_type_reload
+ * - controller_rule_action_type_restart
+ * - controller_rule_action_type_start
+ * - controller_rule_action_type_stop
* @param options
* A number using bits to represent specific boolean options.
* If no bits set, then operate normally in a synchronous manner.
* The controller settings data.
*/
#ifndef _di_controller_rule_simulate_
- extern void controller_rule_simulate(const controller_data_t data, const controller_cache_t cache, const f_array_length_t index, const uint8_t options, controller_setting_t *setting) f_gcc_attribute_visibility_internal;
+ extern void controller_rule_simulate(const controller_data_t data, const controller_cache_t cache, const f_array_length_t index, const uint8_t action, const uint8_t options, controller_setting_t *setting) f_gcc_attribute_visibility_internal;
#endif // _di_controller_rule_simulate_
/**
f_console
f_conversion
f_directory
+f_execute
f_file
f_fss
f_iki
f_path
f_pipe
f_print
+f_signal
fl_color
fl_console
fl_conversion
build_indexer ar
build_language c
build_libraries -lc
-build_libraries-individual -lfll_error -lfll_fss -lfll_path -lfll_program -lfll_status -lfl_color -lfl_console -lfl_conversion -lfl_fss -lfl_iki -lfl_status -lfl_string -lfl_type -lf_console -lf_conversion -lf_directory -lf_file -lf_fss -lf_iki -lf_memory -lf_path -lf_pipe -lf_print -lf_utf
+build_libraries-individual -lfll_error -lfll_fss -lfll_path -lfll_program -lfll_status -lfl_color -lfl_console -lfl_conversion -lfl_fss -lfl_iki -lfl_status -lfl_string -lfl_type -lf_console -lf_conversion -lf_directory -lf_file -lf_fss -lf_iki -lf_memory -lf_path -lf_pipe -lf_print -lf_signal -lf_utf
build_libraries-level -lfll_2 -lfll_1 -lfll_0
build_libraries-monolithic -lfll
build_sources_library controller.c private-control.c private-controller.c private-entry.c private-rule.c
Until that execution succeeds and the daemon goes into the background the representing rule will block.
After the daemon goes into the background, then the representing rule will be fully executed.
+ Any "rule" specified in this entry file is always executed using the "start" rule action type.
+
The "timeout" Action provides default global settings for each of the three special situations: "start", "stop", and "kill".
Each of these may only have a single one exist at a time (one "start", one "stop", and one "kill").
Each successive "timeout" Action, specific to each Action Name (such as "start"), specified replaces the previously defined "timeout" Action (in a top-down manner).
// fll-0 includes
#include <level_0/type.h>
-#include <level_0/status.h>
#include <level_0/type_array.h>
+#include <level_0/status.h>
#include <level_0/memory.h>
-#include <level_0/signal.h>
#include <level_0/string.h>
#include <level_0/utf.h>
#include <level_0/account.h>
#include <level_0/file.h>
#include <level_0/iki.h>
#include <level_0/path.h>
+#include <level_0/signal.h>
// fll-1 includes
#include <level_1/color.h>
status = fake_main(arguments, &data);
- f_signal_close(&data.signal);
-
// flush output pipes before closing.
fflush(f_type_output);
fflush(f_type_error);
close(f_type_descriptor_input);
close(f_type_descriptor_error);
- if (F_status_is_error(status)) {
- return 1;
- }
+ f_signal_close(&data.signal);
if (status == F_child) {
exit(data.child);
}
+ if (F_status_is_error(status)) {
+ return 1;
+ }
+
return 0;
}