Add the daemon mode where controller does not act like an init program.
fprintf(output.stream, "%c", f_string_eol[0]);
+ fll_program_print_help_option(output, context, controller_short_daemon, controller_long_daemon, f_console_symbol_short_enable, f_console_symbol_long_enable, " Run in daemon only mode (do not process the entry).");
fll_program_print_help_option(output, context, controller_short_interruptable, controller_long_interruptable, f_console_symbol_short_enable, f_console_symbol_long_enable, "Designate that this program can be interrupted.");
fll_program_print_help_option(output, context, controller_short_pid, controller_long_pid, f_console_symbol_short_enable, f_console_symbol_long_enable, " Specify a custom pid file path, such as '" controller_path_pid "'.");
fll_program_print_help_option(output, context, controller_short_settings, controller_long_settings, f_console_symbol_short_enable, f_console_symbol_long_enable, " Specify a custom settings path, such as '" controller_path_settings "'.");
fll_program_print_help_option(output, context, controller_short_test, controller_long_test, f_console_symbol_short_enable, f_console_symbol_long_enable, " Run in test mode, where nothing is actually run (a simulation).");
- fll_program_print_help_option(output, context, controller_short_validate, controller_long_validate, f_console_symbol_short_enable, f_console_symbol_long_enable, " Validate the settings (entry and rules).");
+ fll_program_print_help_option(output, context, controller_short_validate, controller_long_validate, f_console_symbol_short_enable, f_console_symbol_long_enable, " Validate the settings (entry and rules) without running (or simulating).");
fll_program_print_help_usage(output, context, controller_name, "entry");
}
}
- // the pid file is required.
+ // a pid file path is required.
if (!setting.path_pid.used) {
status = fl_string_append(controller_path_pid, controller_path_pid_length, &setting.path_pid);
}
}
- if (F_status_is_error_not(status)) {
- status = controller_entry_read(*data, setting, entry_name, &cache, &setting.entry);
+ if (data->parameters[controller_parameter_daemon].result == f_console_result_found) {
- // @fixme this is temporary and may or may not be used when finished codestorming.
- if (F_status_is_error(setting.entry.status)) {
- status = setting.entry.status;
- }
- }
+ if (data->parameters[controller_parameter_validate].result == f_console_result_found) {
+ if (data->error.verbosity != f_console_verbosity_quiet) {
+ fprintf(data->error.to.stream, "%c", f_string_eol[0]);
+ fprintf(data->error.to.stream, "%s%sThe parameter '", data->error.context.before->string, data->error.prefix ? data->error.prefix : "");
+ fprintf(data->error.to.stream, "%s%s%s%s%s", data->error.context.after->string, data->error.notable.before->string, f_console_symbol_long_enable, controller_long_validate, data->error.notable.after->string);
+ fprintf(data->error.to.stream, "%s' must not be specified with the parameter '", data->error.context.before->string);
+ fprintf(data->error.to.stream, "%s%s%s%s%s", data->error.context.after->string, data->error.notable.before->string, f_console_symbol_long_enable, controller_long_daemon, data->error.notable.after->string);
+ fprintf(data->error.to.stream, "%s'.%s%c", data->error.context.before->string, data->error.context.after->string, f_string_eol[0]);
+ }
- if (F_status_is_error_not(status)) {
- status = controller_preprocess_items(*data, &setting, &cache);
- }
+ status = F_status_set_error(F_parameter);
+ }
- if (F_status_is_error_not(status)) {
+ if (F_status_is_error_not(status)) {
+ setting.ready = controller_setting_ready_done;
- if (data->parameters[controller_parameter_test].result == f_console_result_found || data->parameters[controller_parameter_validate].result == f_console_result_found) {
- // @todo validate happens first, report and handle validation problems or success.
+ if (f_file_exists(setting.path_pid.string) == F_true) {
+ if (data->error.verbosity != f_console_verbosity_quiet) {
+ fprintf(data->error.to.stream, "%c", f_string_eol[0]);
+ fprintf(data->error.to.stream, "%s%sThe pid file must not already exist.%s%c", data->error.context.before->string, data->error.prefix ? data->error.prefix : "", data->error.context.after->string, f_string_eol[0]);
+ }
- if (data->parameters[controller_parameter_test].result == f_console_result_found) {
- // @todo after validation succeeds, perform test run.
+ status = F_status_set_error(F_available_not);
+ setting.ready = controller_setting_ready_abort;
}
+
+ // @todo wait here until told to quit, listening for "control" commands (and listening for signals).
+ // @todo clear cache periodically while waiting.
+ // controller_macro_cache_t_delete_simple(cache);
+ }
+ }
+ else {
+
+ if (F_status_is_error_not(status)) {
+ status = controller_entry_read(*data, setting, entry_name, &cache, &setting.entry);
+ }
+
+ if (F_status_is_error(status)) {
+ setting.ready = controller_setting_ready_fail;
}
else {
- // @todo check to see if the standard pid file exists before attempting to start (when in normal operation mode).
- // @todo real execution.
+ status = controller_preprocess_entry(*data, &setting, &cache);
- // @todo create pid file but not until "ready", so be sure to add this after pre-processing the entry file.
- if (setting.ready) {
- controller_file_pid_create(*data, setting.path_pid);
- }
+ if (data->parameters[controller_parameter_validate].result == f_console_result_none) {
- // @todo when everything is ready, wait here until told to quit.
- // @todo clear cache periodically while waiting and no commands.
- // controller_macro_cache_t_delete_simple(cache);
+ if (f_file_exists(setting.path_pid.string) == F_true) {
+ if (data->error.verbosity != f_console_verbosity_quiet) {
+ fprintf(data->error.to.stream, "%c", f_string_eol[0]);
+ fprintf(data->error.to.stream, "%s%sThe pid file must not already exist.%s%c", data->error.context.before->string, data->error.prefix ? data->error.prefix : "", data->error.context.after->string, f_string_eol[0]);
+ }
+
+ status = F_status_set_error(F_available_not);
+ setting.ready = controller_setting_ready_abort;
+ }
- // @todo on failures that prevent normal execution: trigger failsafe/fallback execution, if defined
- // @todo otherwise, set ready to controller_setting_ready_done.
+ if (F_status_is_error_not(status)) {
+ status = controller_process_entry(*data, &setting, &cache);
+ }
+
+ if (F_status_is_error(status)) {
+ setting.ready = controller_setting_ready_fail;
+ }
+ else {
+ setting.ready = controller_setting_ready_done;
+
+ // @todo wait here until told to quit, listening for "control" commands (and listening for signals).
+ // @todo clear cache periodically while waiting.
+ // controller_macro_cache_t_delete_simple(cache);
+ }
+ }
}
}
controller_delete_data(data);
+ if (setting.ready == controller_setting_ready_fail) {
+ // @todo trigger failsafe/fallback execution, if defined.
+ }
+
return status;
}
#endif // _di_controller_main_
#define controller_path_pid_length 34
#define controller_path_settings_length 15
+ #define controller_short_daemon "d"
#define controller_short_interruptable "i"
#define controller_short_pid "p"
#define controller_short_settings "s"
#define controller_short_test "t"
#define controller_short_validate "V"
+ #define controller_long_daemon "daemon"
#define controller_long_interruptable "interruptable"
#define controller_long_pid "pid"
#define controller_long_settings "settings"
controller_parameter_verbosity_debug,
controller_parameter_version,
+ controller_parameter_daemon,
controller_parameter_interruptable,
controller_parameter_pid,
controller_parameter_settings,
f_console_parameter_t_initialize(f_console_standard_short_verbose, f_console_standard_long_verbose, 0, 0, f_console_type_inverse), \
f_console_parameter_t_initialize(f_console_standard_short_debug, f_console_standard_long_debug, 0, 0, f_console_type_inverse), \
f_console_parameter_t_initialize(f_console_standard_short_version, f_console_standard_long_version, 0, 0, f_console_type_inverse), \
+ f_console_parameter_t_initialize(controller_short_daemon, controller_long_daemon, 0, 0, f_console_type_normal), \
f_console_parameter_t_initialize(controller_short_interruptable, controller_long_interruptable, 0, 0, f_console_type_normal), \
f_console_parameter_t_initialize(controller_short_pid, controller_long_pid, 0, 1, f_console_type_normal), \
f_console_parameter_t_initialize(controller_short_settings, controller_long_settings, 0, 1, f_console_type_normal), \
f_console_parameter_t_initialize(controller_short_validate, controller_long_validate, 0, 0, f_console_type_normal), \
}
- #define controller_total_parameters 14
+ #define controller_total_parameters 15
#endif // _di_controller_defines_
#ifndef _di_controller_data_t_
controller_setting_ready_wait,
controller_setting_ready_yes,
controller_setting_ready_done,
+ controller_setting_ready_fail,
+ controller_setting_ready_abort,
};
typedef struct {
}
#endif // _di_controller_entry_action_type_name_
+#ifndef _di_controller_string_dynamic_append_terminated_
+ f_return_status controller_string_dynamic_append_terminated(const f_string_static_t source, f_string_dynamic_t *destination) {
+
+ f_status_t status = fl_string_dynamic_append(source, destination);
+
+ if (F_status_is_error(status)) return status;
+
+ status = fl_string_dynamic_terminate_after(destination);
+
+ return status;
+ }
+#endif // _di_controller_string_dynamic_append_terminated_
+
+#ifndef _di_controller_string_dynamic_partial_append_terminated_
+ f_return_status controller_string_dynamic_partial_append_terminated(const f_string_static_t source, const f_string_range_t range, f_string_dynamic_t *destination) {
+
+ f_status_t status = fl_string_dynamic_partial_append(source, range, destination);
+
+ if (F_status_is_error(status)) return status;
+
+ status = fl_string_dynamic_terminate_after(destination);
+
+ return status;
+ }
+#endif // _di_controller_string_dynamic_partial_append_terminated_
+
#ifndef _di_controller_file_load_
f_return_status controller_file_load(const controller_data_t data, const controller_setting_t setting, const f_string_t path_prefix, const f_string_static_t path_name, const f_string_t path_suffix, const f_string_length_t path_prefix_length, const f_string_length_t path_suffix_length, f_string_dynamic_t *path_file, f_string_dynamic_t *buffer) {
f_status_t status = F_none;
status = fl_conversion_string_to_decimal_unsigned(pid_buffer.string, &number, range);
if (F_status_is_error_not(status) && number == data.pid) {
- f_file_remove(path_pid.string);
+ status = f_file_remove(path_pid.string);
+
+ if (F_status_is_error(status) && data.warning.verbosity == f_console_verbosity_debug) {
+ fll_error_file_print(data.warning, F_status_set_fine(status), "f_file_remove", F_true, path_pid.string, "delete", fll_error_file_type_file);
+ }
}
}
}
#endif // _di_controller_file_pid_delete_
-#ifndef _di_controller_preprocess_items_
- f_return_status controller_preprocess_items(const controller_data_t data, controller_setting_t *setting, controller_cache_t *cache) {
+#ifndef _di_controller_perform_ready_
+ f_return_status controller_perform_ready(const controller_data_t data, controller_setting_t *setting, controller_cache_t *cache) {
+ f_status_t status = F_none;
+
+ // only create pid file when not in validate mode.
+ if (data.parameters[controller_parameter_validate].result == f_console_result_none) {
+
+ status = controller_file_pid_create(data, setting->path_pid);
+
+ // report pid file error but because this could be an "init" program, consider the pid file as optional and continue on.
+ if (F_status_is_error(status)) {
+ fll_error_file_print(data.error, F_status_set_fine(status), "controller_file_pid_create", F_true, setting->path_pid.string, "create", fll_error_file_type_file);
+
+ controller_entry_error_print(data.error, *cache);
+
+ // always return immediately on memory errors.
+ if (F_status_set_fine(status) == F_memory_not || F_status_set_fine(status) == F_memory_allocation || F_status_set_fine(status) == F_memory_reallocation) {
+ return status;
+ }
+
+ status = F_none;
+ }
+ }
+
+ return status;
+ }
+#endif // _di_controller_perform_ready_
+
+#ifndef _di_controller_preprocess_entry_
+ f_return_status controller_preprocess_entry(const controller_data_t data, controller_setting_t *setting, controller_cache_t *cache) {
f_status_t status = F_none;
f_status_t status2 = F_none;
setting->ready = controller_setting_ready_no;
cache->ats.used = 0;
+ cache->line_action = 0;
+ cache->line_item = 0;
+ cache->name_action.used = 0;
+ cache->name_item.used = 0;
status = fl_type_array_lengths_increase_by(controller_default_allocation_step, &cache->ats);
cache->line_item = setting->entry.items.array[0].line;
cache->name_item.used = 0;
- status = fl_string_dynamic_append(setting->entry.items.array[0].name, &cache->name_item);
+ status = controller_string_dynamic_append_terminated(setting->entry.items.array[0].name, &cache->name_item);
if (F_status_is_error(status)) {
- fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_append", F_true);
- controller_entry_error_print(data.error, *cache);
-
- return status;
- }
-
- status = fl_string_dynamic_terminate_after(&cache->name_item);
-
- if (F_status_is_error(status)) {
- fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_terminate_after", F_true);
+ fll_error_print(data.error, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true);
controller_entry_error_print(data.error, *cache);
return status;
cache->line_action = actions->array[cache->ats.array[at_j]].line;
cache->name_action.used = 0;
- status2 = fl_string_dynamic_append(controller_entry_action_type_name(actions->array[cache->ats.array[at_j]].type), &cache->name_action);
+ status2 = controller_string_dynamic_append_terminated(controller_entry_action_type_name(actions->array[cache->ats.array[at_j]].type), &cache->name_action);
if (F_status_is_error(status2)) {
- fll_error_print(data.error, F_status_set_fine(status2), "fl_string_dynamic_append", F_true);
- controller_entry_error_print(data.error, *cache);
-
- return status2;
- }
-
- status2 = fl_string_dynamic_terminate_after(&cache->name_action);
-
- if (F_status_is_error(status2)) {
- fll_error_print(data.error, F_status_set_fine(status2), "fl_string_dynamic_terminate_after", F_true);
+ fll_error_print(data.error, F_status_set_fine(status2), "controller_string_dynamic_append_terminated", F_true);
controller_entry_error_print(data.error, *cache);
return status2;
cache->name_item.used = 0;
cache->line_item = setting->entry.items.array[i].line;
- status2 = fl_string_dynamic_append(setting->entry.items.array[i].name, &cache->name_item);
+ status2 = controller_string_dynamic_append_terminated(setting->entry.items.array[i].name, &cache->name_item);
if (F_status_is_error(status2)) {
- fll_error_print(data.error, F_status_set_fine(status2), "fl_string_dynamic_append", F_true);
- controller_entry_error_print(data.error, *cache);
-
- return status2;
- }
-
- status2 = fl_string_dynamic_terminate_after(&cache->name_item);
-
- if (F_status_is_error(status2)) {
- fll_error_print(data.error, F_status_set_fine(status2), "fl_string_dynamic_terminate_after", F_true);
+ fll_error_print(data.error, F_status_set_fine(status2), "controller_string_dynamic_append_terminated", F_true);
controller_entry_error_print(data.error, *cache);
return status2;
cache->line_item = setting->entry.items.array[cache->ats.array[at_i]].line;
cache->name_item.used = 0;
- status2 = fl_string_dynamic_append(setting->entry.items.array[cache->ats.array[at_i]].name, &cache->name_item);
+ status2 = controller_string_dynamic_append_terminated(setting->entry.items.array[cache->ats.array[at_i]].name, &cache->name_item);
if (F_status_is_error(status2)) {
- fll_error_print(data.error, F_status_set_fine(status2), "fl_string_dynamic_append", F_true);
- controller_entry_error_print(data.error, *cache);
-
- return status2;
- }
-
- status2 = fl_string_dynamic_terminate_after(&cache->name_item);
-
- if (F_status_is_error(status2)) {
- fll_error_print(data.error, F_status_set_fine(status2), "fl_string_dynamic_terminate_after", F_true);
+ fll_error_print(data.error, F_status_set_fine(status2), "controller_string_dynamic_append_terminated", F_true);
controller_entry_error_print(data.error, *cache);
return status2;
setting->ready = controller_setting_ready_yes;
}
+ return status;
+ }
+#endif // _di_controller_preprocess_entry_
+
+#ifndef _di_controller_process_entry_
+ f_return_status controller_process_entry(const controller_data_t data, controller_setting_t *setting, controller_cache_t *cache) {
+ f_status_t status = F_none;
+
+ f_array_length_t i = 0;
+ f_array_length_t j = 0;
+
+ f_array_length_t at_i = 0;
+ f_array_length_t at_j = 1;
+
+ controller_entry_actions_t *actions = 0;
+
+ const bool simulate = data.parameters[controller_parameter_test].result == f_console_result_found;
+
cache->ats.used = 0;
cache->line_action = 0;
cache->line_item = 0;
cache->name_action.used = 0;
cache->name_item.used = 0;
+ if (setting->ready == controller_setting_ready_yes) {
+ status = controller_perform_ready(data, setting, cache);
+ if (F_status_is_error(status)) return status;
+ }
+
+ status = fl_type_array_lengths_increase_by(controller_default_allocation_step, &cache->ats);
+
+ if (F_status_is_error(status)) {
+ fll_error_print(data.error, F_status_set_fine(status), "fl_type_array_lengths_increase_by", F_true);
+ controller_entry_error_print(data.error, *cache);
+
+ return status;
+ }
+
+ cache->ats.array[0] = 0;
+ cache->ats.array[1] = 0;
+ cache->ats.used = 2;
+
+ cache->line_item = setting->entry.items.array[0].line;
+ cache->name_item.used = 0;
+
+ status = controller_string_dynamic_append_terminated(setting->entry.items.array[0].name, &cache->name_item);
+
+ if (F_status_is_error(status)) {
+ fll_error_print(data.error, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true);
+ controller_entry_error_print(data.error, *cache);
+
+ return status;
+ }
+
+ for (;;) {
+
+ actions = &setting->entry.items.array[cache->ats.array[at_i]].actions;
+
+ for (; cache->ats.array[at_j] < actions->used; ++cache->ats.array[at_j]) {
+
+ cache->line_action = actions->array[cache->ats.array[at_j]].line;
+ cache->name_action.used = 0;
+
+ status = controller_string_dynamic_append_terminated(controller_entry_action_type_name(actions->array[cache->ats.array[at_j]].type), &cache->name_action);
+
+ if (F_status_is_error(status)) {
+ fll_error_print(data.error, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true);
+ controller_entry_error_print(data.error, *cache);
+
+ return status;
+ }
+
+ if (actions->array[cache->ats.array[at_j]].type == controller_entry_action_type_ready) {
+
+ if (setting->ready == controller_setting_ready_wait) {
+ setting->ready = controller_setting_ready_yes;
+
+ controller_perform_ready(data, setting, cache);
+ if (F_status_is_error(status)) return status;
+ }
+ }
+ else if (actions->array[cache->ats.array[at_j]].type == controller_entry_action_type_item) {
+
+ if (actions->array[cache->ats.array[at_j]].number == 0 || actions->array[cache->ats.array[at_j]].number >= setting->entry.items.used) {
+
+ // This should not happen if the pre-process is working as designed, but in case it doesn't, return a critical error to prevent infinite recursion and similar errors.
+ if (data.error.verbosity != f_console_verbosity_quiet) {
+ fprintf(data.error.to.stream, "%c", f_string_eol[0]);
+ fprintf(data.error.to.stream, "%s%sInvalid entry item index ", data.error.context.before->string, data.error.prefix ? data.error.prefix : "");
+ fprintf(data.error.to.stream, "%s%s%llu%s", data.error.context.after->string, data.error.notable.before->string, actions->array[cache->ats.array[at_j]].number, data.error.notable.after->string);
+ fprintf(data.error.to.stream, "%s detected.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol[0]);
+ }
+
+ controller_entry_error_print(data.error, *cache);
+
+ return F_status_is_error(F_critical);
+ }
+
+ status = fl_type_array_lengths_increase_by(controller_default_allocation_step, &cache->ats);
+
+ if (F_status_is_error(status)) {
+ fll_error_print(data.error, F_status_set_fine(status), "fl_type_array_lengths_increase_by", F_true);
+ controller_entry_error_print(data.error, *cache);
+
+ return status;
+ }
+
+ // continue into the requested item.
+ at_i = cache->ats.used;
+ at_j = cache->ats.used + 1;
+
+ cache->ats.array[at_i] = actions->array[cache->ats.array[at_j]].number;
+ cache->ats.array[at_j] = 0;
+ cache->ats.used += 2;
+
+ cache->name_action.used = 0;
+ cache->line_action = 0;
+
+ cache->name_item.used = 0;
+ cache->line_item = setting->entry.items.array[actions->array[cache->ats.array[at_j]].number].line;
+
+ status = controller_string_dynamic_append_terminated(setting->entry.items.array[actions->array[cache->ats.array[at_j]].number].name, &cache->name_item);
+
+ if (F_status_is_error(status)) {
+ fll_error_print(data.error, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true);
+ controller_entry_error_print(data.error, *cache);
+
+ return status;
+ }
+
+ break;
+ }
+ else if (actions->array[cache->ats.array[at_j]].type == controller_entry_action_type_consider || actions->array[cache->ats.array[at_j]].type == controller_entry_action_type_rule) {
+
+ // rule execution will re-use the existing cache, so save the current cache.
+ const f_array_length_t cache_line_action = cache->line_action;
+ const f_array_length_t cache_line_item = cache->line_item;
+
+ const f_string_length_t cache_name_action_used = cache->name_action.used;
+ const f_string_length_t cache_name_item_used = cache->name_item.used;
+
+ char cache_name_item[cache_name_action_used];
+ char cache_name_action[cache_name_item_used];
+
+ memcpy(cache_name_item, cache->name_item.string, cache->name_item.used);
+ memcpy(cache_name_action, cache->name_action.string, cache->name_action.used);
+
+ const f_string_length_t rule_id_length = actions->array[cache->ats.array[at_j]].parameters.array[0].used + actions->array[cache->ats.array[at_j]].parameters.array[1].used + 1;
+ char rule_id_name[rule_id_length + 1];
+ const f_string_static_t rule_id = f_macro_string_static_t_initialize(rule_id_name, rule_id_length);
+
+ memcpy(rule_id_name, actions->array[cache->ats.array[at_j]].parameters.array[0].string, actions->array[cache->ats.array[at_j]].parameters.array[0].used);
+ memcpy(rule_id_name + actions->array[cache->ats.array[at_j]].parameters.array[0].used + 1, actions->array[cache->ats.array[at_j]].parameters.array[1].string, actions->array[cache->ats.array[at_j]].parameters.array[1].used);
+
+ rule_id_name[actions->array[cache->ats.array[at_j]].parameters.array[0].used] = f_path_separator[0];
+ rule_id_name[rule_id_length] = 0;
+
+ // @todo check if the rule is already loaded by using the "rule_id", if not then load it.
+
+ //status = controller_rule_read(data, *setting, rule_id, cache, &setting->rules.array[setting->rules.used]);
+
+ // @todo execute rule.
+ if (F_status_is_error_not(status) && actions->array[cache->ats.array[at_j]].type == controller_entry_action_type_rule) {
+ //setting->rules.used++;
+ //status = controller_rule_process();
+ }
+
+ // restore cache.
+ memcpy(cache->name_action.string, cache_name_action, cache_name_action_used);
+ memcpy(cache->name_item.string, cache_name_item, cache_name_item_used);
+
+ cache->name_action.string[cache_name_action_used] = 0;
+ cache->name_item.string[cache_name_item_used] = 0;
+
+ cache->name_action.used = cache_name_action_used;
+ cache->name_item.used = cache_name_item_used;
+
+ cache->line_action = cache_line_action;
+ cache->line_item = cache_line_item;
+
+ if (F_status_is_error(status)) {
+ controller_entry_error_print(data.error, *cache);
+
+ if (!simulate) break;
+ }
+ }
+ else if (actions->array[cache->ats.array[at_j]].type == controller_entry_action_type_timeout) {
+ // @todo
+ }
+ else if (actions->array[cache->ats.array[at_j]].type == controller_entry_action_type_failsafe) {
+ // @todo
+ }
+
+ } // for
+
+ cache->line_action = 0;
+ cache->name_action.used = 0;
+
+ // end of actions found, so drop to previous loop in stack.
+ if (cache->ats.array[at_j] == actions->used) {
+
+ // all actions for "main" are processed so there is nothing left to do.
+ if (at_i == 0) break;
+
+ at_i -= 2;
+ at_j -= 2;
+
+ cache->ats.used -= 2;
+ cache->ats.array[at_j]++;
+
+ cache->line_item = setting->entry.items.array[cache->ats.array[at_i]].line;
+ cache->name_item.used = 0;
+
+ status = controller_string_dynamic_append_terminated(setting->entry.items.array[cache->ats.array[at_i]].name, &cache->name_item);
+
+ if (F_status_is_error(status)) {
+ fll_error_print(data.error, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true);
+ controller_entry_error_print(data.error, *cache);
+
+ return status;
+ }
+ }
+ } // for
+
return status;
}
-#endif // _di_controller_preprocess_items_
+#endif // _di_controller_process_entry_
#ifndef _di_controller_status_simplify_
f_return_status controller_status_simplify(const f_status_t status) {
return F_status_set_error(F_number);
}
- if (status == F_parameter || status == F_found_not || status == F_interrupt || status == F_supported_not) {
+ if (status == F_parameter || status == F_found_not || status == F_interrupt || status == F_supported_not || status == F_critical) {
return F_status_set_error(status);
}
#ifdef __cplusplus
extern "C" {
#endif
+
/**
* Get a string representing the entry action type.
*
#endif // _di_controller_entry_action_type_name_
/**
+ * Append a string and then add a NULL after the end of the string.
+ *
+ * @param source
+ * The string to copy from.
+ * @param destination
+ * The string to copy to.
+ *
+ * @return
+ * F_none on success.
+ *
+ * Errors (with error bit) from: fl_string_dynamic_append().
+ * Errors (with error bit) from: fl_string_dynamic_terminate_after().
+ *
+ * @see fl_string_dynamic_append()
+ * @see fl_string_dynamic_terminate_after()
+ */
+#ifndef _di_controller_string_dynamic_append_terminated_
+ extern f_return_status controller_string_dynamic_append_terminated(const f_string_static_t from, f_string_dynamic_t *destination) f_gcc_attribute_visibility_internal;
+#endif // _di_controller_string_dynamic_append_terminated_
+
+/**
+ * Append given range from within a string and then add a NULL after the end of the string.
+ *
+ * @param from
+ * The string to copy from.
+ * @param range
+ * The range within the from string to copy.
+ * @param destination
+ * The string to copy to.
+ *
+ * @return
+ * F_none on success.
+ *
+ * Errors (with error bit) from: fl_string_dynamic_append().
+ * Errors (with error bit) from: fl_string_dynamic_terminate_after().
+ *
+ * @see fl_string_dynamic_append()
+ * @see fl_string_dynamic_terminate_after()
+ */
+#ifndef _di_controller_string_dynamic_partial_append_terminated_
+ extern f_return_status controller_string_dynamic_partial_append_terminated(const f_string_static_t from, const f_string_range_t range, f_string_dynamic_t *destination) f_gcc_attribute_visibility_internal;
+#endif // _di_controller_string_dynamic_partial_append_terminated_
+
+/**
* Load a file from the controller settings directory.
*
* @param data
#endif // _di_controller_file_pid_delete_
/**
- * Load relevant rules into memory and performing other pre-process tasks.
+ * Perform all activities requiring the state to be "ready".
+ *
+ * This prints messages on errors.
*
* @param data
* The program data.
*
* @return
* F_none on success.
+ *
+ * Errors from controller_file_pid_create() are not returned, unless it is a memory error.
+ *
+ * @see controller_file_pid_create()
+ */
+#ifndef _di_controller_perform_ready_
+ extern f_return_status controller_perform_ready(const controller_data_t data, controller_setting_t *setting, controller_cache_t *cache) f_gcc_attribute_visibility_internal;
+#endif // _di_controller_perform_ready_
+
+/**
+ * Pre-process all items for the loaded entry.
+ *
+ * @param data
+ * The program data.
+ * @param setting
+ * The controller settings data.
+ * @param cache
+ * The cache.
+ *
+ * @return
+ * F_none on success.
+ * F_recurse (with error bit) on a recursion error.
+ * F_valid_not (with error bit) on invalid entry item, entry item action, or entry item action value.
+ *
+ * Errors (with error bit) from: fl_string_dynamic_append().
+ * Errors (with error bit) from: fl_string_dynamic_terminate_after().
+ * Errors (with error bit) from: fl_type_array_lengths_increase_by().
+ *
+ * This will detect and report all errors, but only the first error is returned.
+ * Memory related errors return immediately.
+ *
+ * @see fl_string_dynamic_append()
+ * @see fl_string_dynamic_terminate_after()
+ * @see fl_type_array_lengths_increase_by()
+ */
+#ifndef _di_controller_preprocess_entry_
+ extern f_return_status controller_preprocess_entry(const controller_data_t data, controller_setting_t *setting, controller_cache_t *cache) f_gcc_attribute_visibility_internal;
+#endif // _di_controller_preprocess_entry_
+
+/**
+ * Process (execute) all items for the loaded entry.
+ *
+ * @param data
+ * The program data.
+ * @param setting
+ * The controller settings data.
+ * @param cache
+ * The cache.
+ *
+ * @return
+ * F_none on success.
+ * F_critical (with error bit) on any critical error.
+ *
+ * Errors (with error bit) from: controller_perform_ready().
+ * Errors (with error bit) from: controller_string_dynamic_append_terminated().
+ * Errors (with error bit) from: fl_type_array_lengths_increase_by().
+ *
+ * @see controller_perform_ready()
+ * @see controller_string_dynamic_append_terminated()
+ * @see fl_type_array_lengths_increase_by()
*/
-#ifndef _di_controller_preprocess_items_
- extern f_return_status controller_preprocess_items(const controller_data_t data, controller_setting_t *setting, controller_cache_t *cache) f_gcc_attribute_visibility_internal;
-#endif // _di_controller_preprocess_items_
+#ifndef _di_controller_process_entry_
+ extern f_return_status controller_process_entry(const controller_data_t data, controller_setting_t *setting, controller_cache_t *cache) f_gcc_attribute_visibility_internal;
+#endif // _di_controller_process_entry_
/**
* Given a wide range of status codes, simplify them down to a small subset.
break;
}
- status = fl_string_dynamic_partial_append_nulless(cache->buffer_file, cache->object_items.array[i], &cache->name_item);
+ status = controller_string_dynamic_partial_append_terminated(cache->buffer_file, cache->object_items.array[i], &cache->name_item);
if (F_status_is_error(status)) {
- fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_partial_append_nulless", F_true);
- break;
- }
-
- status = fl_string_dynamic_terminate_after(&cache->name_item);
-
- if (F_status_is_error(status)) {
- fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_terminate_after", F_true);
+ fll_error_print(data.error, F_status_set_fine(status), "controller_string_dynamic_partial_append_terminated", F_true);
break;
}
entry->items.array[at].line = cache->line_item;
- status = fl_string_dynamic_append(cache->name_item, &entry->items.array[at].name);
+ status = controller_string_dynamic_append_terminated(cache->name_item, &entry->items.array[at].name);
if (F_status_is_error(status)) {
- fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_append", F_true);
- break;
- }
-
- status = fl_string_dynamic_terminate_after(&entry->items.array[at].name);
-
- if (F_status_is_error(status)) {
- fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_terminate_after", F_true);
+ fll_error_print(data.error, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true);
break;
}
cache->line_action = action->line;
cache->line_item = entry->items.array[i].line;
- status = fl_string_dynamic_append(entry->items.array[i].name, &cache->name_item);
+ status = controller_string_dynamic_append_terminated(entry->items.array[i].name, &cache->name_item);
if (F_status_is_error(status)) {
- fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_append", F_true);
- break;
- }
-
- status = fl_string_dynamic_terminate_after(&cache->name_item);
-
- if (F_status_is_error(status)) {
- fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_terminate_after", F_true);
- break;
- }
-
- status = fl_string_dynamic_append(entry->items.array[i].name, &cache->name_item);
-
- if (F_status_is_error(status)) {
- fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_append", F_true);
- break;
- }
-
- status = fl_string_dynamic_terminate_after(&cache->name_item);
-
- if (F_status_is_error(status)) {
- fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_terminate_after", F_true);
+ fll_error_print(data.error, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true);
break;
}
// the error is already fully printed and the entry status is already assigned, so immediately exit.
if (missing & 0x2) {
- return F_false;
+ return entry->status;
}
}
}
controller_entry_error_print(data.error, *cache);
entry->status = controller_status_simplify(F_status_set_fine(status));
- return F_false;
+ }
+ else {
+ entry->status = F_none;
}
- entry->status = F_none;
- return F_true;
+ return entry->status;
}
#endif // _di_controller_entry_read_
* The processed entry.
*
* @return
- * F_true on success.
- * F_false on failure.
+ * F_none on success.
+ *
+ * Errors (with error bit) from: controller_entry_actions_read().
+ * Errors (with error bit) from: controller_entry_items_increase_by().
+ * Errors (with error bit) from: controller_file_load().
+ * Errors (with error bit) from: controller_status_simplify().
+ * Errors (with error bit) from: controller_string_dynamic_append_terminated().
+ * Errors (with error bit) from: controller_string_dynamic_partial_append_terminated().
+ * Errors (with error bit) from: f_fss_count_lines().
+ * Errors (with error bit) from: fl_fss_apply_delimit().
+ * Errors (with error bit) from: fl_string_dynamic_append().
+ * Errors (with error bit) from: fl_string_dynamic_partial_append_nulless().
+ * Errors (with error bit) from: fl_string_dynamic_terminate().
+ * Errors (with error bit) from: fll_fss_basic_list_read().
*
* @see controller_entry_actions_read()
* @see controller_entry_items_increase_by()
* @see controller_file_load()
* @see controller_status_simplify()
+ * @see controller_string_dynamic_append_terminated()
+ * @see controller_string_dynamic_partial_append_terminated()
* @see f_fss_count_lines()
* @see fl_fss_apply_delimit()
* @see fl_string_dynamic_append()
timeout stop 7
timeout kill 3
+ failsafe maintenance
+
item boot
item net
item time
item keyboard
item console
- failsafe maintenance
-
boot:
rule boot filesystem require
rule boot modules require