From 1486663abeff2a32f95c422c5c8c463fbfcd35ef Mon Sep 17 00:00:00 2001 From: Kevin Day Date: Sun, 29 Nov 2020 21:45:02 -0600 Subject: [PATCH] Progress: controller program. --- level_3/control/c/control.c | 20 +- level_3/controller/c/controller.c | 121 ++++++++- level_3/controller/c/private-controller.c | 15 +- level_3/controller/c/private-controller.h | 171 +++++++------ level_3/controller/c/private-entry.c | 62 ++++- level_3/controller/c/private-rule.c | 399 +++++++++++++++++++---------- level_3/controller/c/private-rule.h | 4 + level_3/controller/data/build/dependencies | 2 + level_3/controller/documents/rule.txt | 19 +- level_3/controller/specifications/rule.txt | 16 +- specifications/fss-000D.txt | 13 +- 11 files changed, 599 insertions(+), 243 deletions(-) diff --git a/level_3/control/c/control.c b/level_3/control/c/control.c index 1ece906..ee12ecf 100644 --- a/level_3/control/c/control.c +++ b/level_3/control/c/control.c @@ -39,8 +39,24 @@ extern "C" { status = fll_program_parameter_process(arguments, parameters, choices, F_true, &data->remaining, &data->context); - data->error.context = data->context.set.error; - data->error.notable = data->context.set.notable; + if (data->context.set.error.before) { + data->error.context = data->context.set.error; + data->error.notable = data->context.set.notable; + + data->warning.context = data->context.set.warning; + data->warning.notable = data->context.set.notable; + } + else { + data->error.context.before = &fll_error_string_null_s; + data->error.context.after = &fll_error_string_null_s; + data->error.notable.before = &fll_error_string_null_s; + data->error.notable.after = &fll_error_string_null_s; + + data->warning.context.before = &fll_error_string_null_s; + data->warning.context.after = &fll_error_string_null_s; + data->warning.notable.before = &fll_error_string_null_s; + data->warning.notable.after = &fll_error_string_null_s; + } if (F_status_is_error(status)) { if (data->error.verbosity != f_console_verbosity_quiet) { diff --git a/level_3/controller/c/controller.c b/level_3/controller/c/controller.c index b97923f..a26ab05 100644 --- a/level_3/controller/c/controller.c +++ b/level_3/controller/c/controller.c @@ -41,8 +41,6 @@ extern "C" { f_return_status controller_main(const f_console_arguments_t arguments, controller_data_t *data) { f_status_t status = F_none; - // @todo somewhere in here, check to see if the standard pid file exists before attempting to start (when in normal operation mode). - { const f_console_parameters_t parameters = f_macro_console_parameters_t_initialize(data->parameters, controller_total_parameters); @@ -52,11 +50,24 @@ extern "C" { status = fll_program_parameter_process(arguments, parameters, choices, F_true, &data->remaining, &data->context); - data->error.context = data->context.set.error; - data->error.notable = data->context.set.notable; + if (data->context.set.error.before) { + data->error.context = data->context.set.error; + data->error.notable = data->context.set.notable; - data->warning.context = data->context.set.warning; - data->warning.notable = data->context.set.notable; + data->warning.context = data->context.set.warning; + data->warning.notable = data->context.set.notable; + } + else { + data->error.context.before = &fll_error_string_null_s; + data->error.context.after = &fll_error_string_null_s; + data->error.notable.before = &fll_error_string_null_s; + data->error.notable.after = &fll_error_string_null_s; + + data->warning.context.before = &fll_error_string_null_s; + data->warning.context.after = &fll_error_string_null_s; + data->warning.notable.before = &fll_error_string_null_s; + data->warning.notable.after = &fll_error_string_null_s; + } if (F_status_is_error(status)) { if (data->error.verbosity != f_console_verbosity_quiet) { @@ -135,14 +146,102 @@ extern "C" { entry_name.size = entry_name.used; } - status = controller_entry_read(*data, setting, entry_name, &cache_entry, &setting.entry); + if (data->parameters[controller_parameter_settings].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", data->error.context.after->string, data->error.notable.before->string, f_console_symbol_long_enable, controller_long_settings, data->error.notable.after->string); + fprintf(data->error.to.stream, "%s' was specified, but no value was given.%s%c", data->error.context.before->string, data->error.context.after->string, f_string_eol[0]); + } + + status = F_status_set_error(F_parameter); + } + else if (data->parameters[controller_parameter_settings].locations.used) { + const f_array_length_t location = data->parameters[controller_parameter_settings].values.array[data->parameters[controller_parameter_settings].values.used - 1]; + + status = fll_path_canonical(arguments.argv[location], &setting.path_setting); + + if (F_status_is_error(status)) { + if (data->error.verbosity != f_console_verbosity_quiet) { + fll_error_print(data->error, F_status_set_fine(status), "fll_path_canonical", F_true); + } + } + } + else { + status = fl_string_append(controller_path_settings, controller_path_settings_length, &setting.path_setting); + + if (F_status_is_error(status)) { + if (data->error.verbosity != f_console_verbosity_quiet) { + fll_error_print(data->error, F_status_set_fine(status), "fl_string_append", F_true); + } + } + } + + if (data->parameters[controller_parameter_pid].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_pid, data->error.notable.after->string); + fprintf(data->error.to.stream, "%s' was specified, but no value was given.%s%c", data->error.context.before->string, data->error.context.after->string, f_string_eol[0]); + } - // @fixme this is temporary for testing. - if (F_status_is_error(setting.entry.status)) { - status = setting.entry.status; + status = F_status_set_error(F_parameter); } + else if (data->parameters[controller_parameter_pid].locations.used) { + const f_array_length_t location = data->parameters[controller_parameter_pid].values.array[data->parameters[controller_parameter_pid].values.used - 1]; + + if (strnlen(arguments.argv[location], f_console_length_size)) { + status = fll_path_canonical(arguments.argv[location], &setting.path_pid); - // @todo + if (F_status_is_error(status)) { + if (data->error.verbosity != f_console_verbosity_quiet) { + fll_error_print(data->error, F_status_set_fine(status), "fll_path_canonical", F_true); + } + } + } + else { + if (data->warning.verbosity == f_console_verbosity_debug) { + fprintf(data->warning.to.stream, "%c", f_string_eol[0]); + fprintf(data->warning.to.stream, "%s%sThe parameter '", data->warning.context.before->string, data->warning.prefix ? data->warning.prefix : ""); + fprintf(data->warning.to.stream, "%s%s%s%s%s", data->warning.context.after->string, data->warning.notable.before->string, f_console_symbol_long_enable, controller_long_pid, data->warning.notable.after->string); + fprintf(data->warning.to.stream, "%s' must be a file path but instead is an empty string, falling back to the default.%s%c", data->warning.context.before->string, data->warning.context.after->string, f_string_eol[0]); + } + } + } + + // the pid file 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(status)) { + if (data->error.verbosity != f_console_verbosity_quiet) { + fll_error_print(data->error, F_status_set_fine(status), "fl_string_append", F_true); + } + } + } + + if (F_status_is_error_not(status)) { + status = controller_entry_read(*data, setting, entry_name, &cache_entry, &setting.entry); + + // @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 (F_status_is_error_not(status)) { + 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 (data->parameters[controller_parameter_test].result == f_console_result_found) { + // @todo after validation succeeds, perform test run. + } + } + else { + // @todo check to see if the standard pid file exists before attempting to start (when in normal operation mode). + // @todo real execution. + } + } // 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) { diff --git a/level_3/controller/c/private-controller.c b/level_3/controller/c/private-controller.c index 27f9751..61c30fa 100644 --- a/level_3/controller/c/private-controller.c +++ b/level_3/controller/c/private-controller.c @@ -49,25 +49,28 @@ extern "C" { return status; } - const f_string_length_t path_length = setting.path_setting.used + f_path_separator_length + path_file->used; + const f_string_length_t path_length = setting.path_setting.used ? setting.path_setting.used + f_path_separator_length + path_file->used : path_file->used; char path[path_length + 1]; - memcpy(path, setting.path_setting.string, setting.path_setting.used); - memcpy(path + setting.path_setting.used + f_path_separator_length, path_file->string, path_file->used); + if (setting.path_setting.used) { + memcpy(path, setting.path_setting.string, setting.path_setting.used); + memcpy(path + setting.path_setting.used + f_path_separator_length, path_file->string, path_file->used); + + path[setting.path_setting.used] = f_path_separator[0]; + } - path[setting.path_setting.used] = f_path_separator[0]; path[path_length] = 0; status = f_file_stream_open(path, 0, &file); if (F_status_is_error(status)) { - fll_error_file_print(data.error, F_status_set_fine(status), "f_file_stream_open", F_true, path_file->string, "open", fll_error_file_type_file); + fll_error_file_print(data.error, F_status_set_fine(status), "f_file_stream_open", F_true, path, "open", fll_error_file_type_file); } else { status = f_file_stream_read(file, 1, buffer); if (F_status_is_error(status)) { - fll_error_file_print(data.error, F_status_set_fine(status), "f_file_stream_read", F_true, path_file->string, "read", fll_error_file_type_file); + fll_error_file_print(data.error, F_status_set_fine(status), "f_file_stream_read", F_true, path, "read", fll_error_file_type_file); } } diff --git a/level_3/controller/c/private-controller.h b/level_3/controller/c/private-controller.h index 34aeb74..5374ad2 100644 --- a/level_3/controller/c/private-controller.h +++ b/level_3/controller/c/private-controller.h @@ -13,77 +13,81 @@ extern "C" { #endif #ifndef _di_controller_string_ - #define controller_string_asynchronous "asynchronous" - #define controller_string_create "create" - #define controller_string_command "command" - #define controller_string_consider "consider" - #define controller_string_default "default" - #define controller_string_define "define" - #define controller_string_entry "entry" - #define controller_string_entries "entries" - #define controller_string_environment "environment" - #define controller_string_failsafe "failsafe" - #define controller_string_group "group" - #define controller_string_item "item" - #define controller_string_kill "kill" - #define controller_string_main "main" - #define controller_string_name "name" - #define controller_string_need "need" - #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_restart "restart" - #define controller_string_rule "rule" - #define controller_string_rules "rules" - #define controller_string_script "script" - #define controller_string_service "service" - #define controller_string_settings "settings" - #define controller_string_start "start" - #define controller_string_stop "stop" - #define controller_string_timeout "timeout" - #define controller_string_use "use" - #define controller_string_user "user" - #define controller_string_wait "wait" - #define controller_string_want "want" - #define controller_string_wish "wish" - - #define controller_string_asynchronous_length 12 - #define controller_string_create_length 6 - #define controller_string_command_length 7 - #define controller_string_consider_length 8 - #define controller_string_define_length 6 - #define controller_string_default_length 7 - #define controller_string_entry_length 5 - #define controller_string_entries_length 7 - #define controller_string_environment_length 11 - #define controller_string_failsafe_length 8 - #define controller_string_group_length 5 - #define controller_string_item_length 4 - #define controller_string_kill_length 4 - #define controller_string_main_length 4 - #define controller_string_name_length 4 - #define controller_string_need_length 4 - #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_restart_length 7 - #define controller_string_rule_length 4 - #define controller_string_rules_length 5 - #define controller_string_script_length 6 - #define controller_string_service_length 7 - #define controller_string_settings_length 8 - #define controller_string_start_length 5 - #define controller_string_stop_length 4 - #define controller_string_timeout_length 7 - #define controller_string_use_length 3 - #define controller_string_user_length 4 - #define controller_string_wait_length 4 - #define controller_string_want_length 4 - #define controller_string_wish_length 4 + #define controller_string_asynchronous "asynchronous" + #define controller_string_create "create" + #define controller_string_command "command" + #define controller_string_consider "consider" + #define controller_string_control_group "control_group" + #define controller_string_default "default" + #define controller_string_define "define" + #define controller_string_entry "entry" + #define controller_string_entries "entries" + #define controller_string_environment "environment" + #define controller_string_failsafe "failsafe" + #define controller_string_group "group" + #define controller_string_item "item" + #define controller_string_kill "kill" + #define controller_string_main "main" + #define controller_string_name "name" + #define controller_string_need "need" + #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_restart "restart" + #define controller_string_rule "rule" + #define controller_string_rules "rules" + #define controller_string_script "script" + #define controller_string_service "service" + #define controller_string_settings "settings" + #define controller_string_start "start" + #define controller_string_stop "stop" + #define controller_string_timeout "timeout" + #define controller_string_use "use" + #define controller_string_user "user" + #define controller_string_wait "wait" + #define controller_string_want "want" + #define controller_string_wish "wish" + + #define controller_string_asynchronous_length 12 + #define controller_string_create_length 6 + #define controller_string_command_length 7 + #define controller_string_consider_length 8 + #define controller_string_control_group_length 13 + #define controller_string_define_length 6 + #define controller_string_default_length 7 + #define controller_string_entry_length 5 + #define controller_string_entries_length 7 + #define controller_string_environment_length 11 + #define controller_string_failsafe_length 8 + #define controller_string_group_length 5 + #define controller_string_item_length 4 + #define controller_string_kill_length 4 + #define controller_string_main_length 4 + #define controller_string_name_length 4 + #define controller_string_need_length 4 + #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_restart_length 7 + #define controller_string_rule_length 4 + #define controller_string_rules_length 5 + #define controller_string_script_length 6 + #define controller_string_service_length 7 + #define controller_string_settings_length 8 + #define controller_string_start_length 5 + #define controller_string_stop_length 4 + #define controller_string_timeout_length 7 + #define controller_string_use_length 3 + #define controller_string_user_length 4 + #define controller_string_wait_length 4 + #define controller_string_want_length 4 + #define controller_string_wish_length 4 #endif // _di_controller_string_ #ifndef _di_controller_rule_action_t_ @@ -211,6 +215,18 @@ extern "C" { #endif // _di_controller_rule_items_t_ #ifndef _di_controller_rule_t_ + enum { + controller_rule_setting_type_control_group = 1, + controller_rule_setting_type_define, + controller_rule_setting_type_environment, + controller_rule_setting_type_name, + controller_rule_setting_type_need, + controller_rule_setting_type_parameter, + controller_rule_setting_type_path, + controller_rule_setting_type_want, + controller_rule_setting_type_wish, + }; + typedef struct { f_status_t status; @@ -218,9 +234,9 @@ extern "C" { f_string_dynamic_t name; f_string_dynamic_t control_group; f_string_dynamic_t path; - f_string_dynamic_t pid; - f_string_maps_t defines; + f_string_maps_t define; + f_string_maps_t parameter; f_string_dynamics_t environment; f_string_dynamics_t need; @@ -237,7 +253,7 @@ extern "C" { f_string_dynamic_t_initialize, \ f_string_dynamic_t_initialize, \ f_string_dynamic_t_initialize, \ - f_string_dynamic_t_initialize, \ + f_string_maps_t_initialize, \ f_string_maps_t_initialize, \ f_string_dynamics_t_initialize, \ f_string_dynamics_t_initialize, \ @@ -251,8 +267,8 @@ extern "C" { f_macro_string_dynamic_t_delete_simple(rule.name) \ f_macro_string_dynamic_t_delete_simple(rule.control_group) \ f_macro_string_dynamic_t_delete_simple(rule.path) \ - f_macro_string_dynamic_t_delete_simple(rule.pid) \ - f_macro_string_maps_t_delete_simple(rule.defines) \ + f_macro_string_maps_t_delete_simple(rule.define) \ + f_macro_string_maps_t_delete_simple(rule.parameter) \ f_macro_string_dynamics_t_delete_simple(rule.environment) \ f_macro_string_dynamics_t_delete_simple(rule.need) \ f_macro_string_dynamics_t_delete_simple(rule.want) \ @@ -429,6 +445,7 @@ extern "C" { bool interruptable; bool ready; + f_string_dynamic_t path_pid; f_string_dynamic_t path_setting; controller_entry_t entry; @@ -440,11 +457,13 @@ extern "C" { F_false, \ F_false, \ f_string_dynamic_t_initialize, \ + f_string_dynamic_t_initialize, \ controller_entry_t_initialize, \ controller_rules_t_initialize, \ } #define macro_controller_setting_t_delete_simple(setting) \ + f_macro_string_dynamic_t_delete_simple(setting.path_pid) \ f_macro_string_dynamic_t_delete_simple(setting.path_setting) \ macro_controller_entry_t_delete_simple(setting.entry) \ macro_controller_rules_t_delete_simple(setting.rules) diff --git a/level_3/controller/c/private-entry.c b/level_3/controller/c/private-entry.c index 3211646..2c3468e 100644 --- a/level_3/controller/c/private-entry.c +++ b/level_3/controller/c/private-entry.c @@ -207,6 +207,8 @@ extern "C" { if (F_status_is_error(status)) { fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamics_increase_by", F_true); + action->status = status; + if (F_status_is_error_not(status_action)) { status_action = status; } @@ -223,6 +225,8 @@ extern "C" { if (F_status_is_error(status)) { fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_partial_append_nulless", F_true); + action->status = status; + if (F_status_is_error_not(status_action)) { status_action = status; } @@ -243,6 +247,8 @@ extern "C" { if (F_status_is_error(status)) { fll_error_print(data.error, F_status_set_fine(status), "fll_path_canonical", F_true); + action->status = status; + 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) { status_action = status; break; @@ -267,6 +273,59 @@ extern "C" { } if (action->parameters.array[1].used) { + cache->buffer_path.used = 0; + + status = f_file_name_base(action->parameters.array[1].string, action->parameters.array[1].used, &cache->buffer_path); + + if (F_status_is_error(status)) { + fll_error_print(data.error, F_status_set_fine(status), "f_file_name_base", F_true); + + 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) { + status_action = status; + break; + } + + action->status = status; + + if (F_status_is_error_not(status_action)) { + status_action = status; + } + } + else { + if (fl_string_dynamic_compare(action->parameters.array[1], cache->buffer_path) == F_equal_to_not) { + + if (data.error.verbosity != f_console_verbosity_quiet) { + status = fl_string_dynamic_terminate_after(&cache->buffer_path); + + if (F_status_is_error(status)) { + fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_terminate_after", F_true); + + action->status = status; + + 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) { + status_action = status; + } + + break; + } + + fprintf(data.error.to.stream, "%c", f_string_eol[0]); + fprintf(data.error.to.stream, "%s%sThe entry item action second parameter '", data.error.context.before->string, data.error.prefix ? data.error.prefix : ""); + fprintf(data.error.to.stream, "%s%s%s%s", data.error.context.after->string, data.error.notable.before->string, action->parameters.array[1].string, data.error.notable.after->string); + fprintf(data.error.to.stream, "%s' must be a base path name, such as '", data.error.context.before->string); + fprintf(data.error.to.stream, "%s%s%s%s", data.error.context.after->string, data.error.notable.before->string, cache->buffer_path.string, 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]); + } + + action->status = F_status_set_error(F_parameter); + + if (F_status_is_error_not(status_action)) { + status_action = action->status; + } + } + } + } + else { action->status = F_status_set_error(F_parameter); if (F_status_is_error_not(status_action)) { @@ -388,6 +447,7 @@ extern "C" { void controller_entry_error_print(const fll_error_print_t output, const controller_entry_cache_t cache) { if (output.verbosity != f_console_verbosity_quiet) { + fprintf(output.to.stream, "%c", f_string_eol[0]); fprintf(output.to.stream, "%s%sWhile processing ", output.context.before->string, output.prefix ? output.prefix : ""); if (cache.name_action.used) { @@ -637,7 +697,7 @@ extern "C" { if (code & 0x1) { if (data.error.verbosity != f_console_verbosity_quiet) { fprintf(data.error.to.stream, "%c", f_string_eol[0]); - fprintf(data.error.to.stream, "The required entry item '"); + fprintf(data.error.to.stream, "%s%sThe required entry item '", data.error.context.before->string, data.error.prefix ? data.error.prefix : ""); fprintf(data.error.to.stream, "%s%s%s%s", data.error.context.after->string, data.error.notable.before->string, controller_string_main, data.error.notable.after->string); fprintf(data.error.to.stream, "%s' was not found.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol[0]); } diff --git a/level_3/controller/c/private-rule.c b/level_3/controller/c/private-rule.c index 12edb9c..349eea0 100644 --- a/level_3/controller/c/private-rule.c +++ b/level_3/controller/c/private-rule.c @@ -239,6 +239,7 @@ extern "C" { void controller_rule_error_print(const fll_error_print_t output, const controller_rule_cache_t cache, const bool item) { if (output.verbosity != f_console_verbosity_quiet) { + fprintf(output.to.stream, "%c", f_string_eol[0]); fprintf(output.to.stream, "%s%sWhile processing ", output.context.before->string, output.prefix ? output.prefix : ""); if (cache.name_action.used) { @@ -447,9 +448,9 @@ extern "C" { rule->id.used = 0; rule->name.used = 0; - rule->pid.used = 0; - rule->defines.used = 0; + rule->define.used = 0; + rule->parameter.used = 0; rule->environment.used = 0; rule->need.used = 0; @@ -469,6 +470,7 @@ extern "C" { cache->buffer_file.used = 0; cache->buffer_item.used = 0; + cache->buffer_path.used = 0; cache->content_items.used = 0; @@ -528,6 +530,7 @@ extern "C" { cache->object_actions.used = 0; cache->buffer_item.used = 0; + cache->buffer_path.used = 0; cache->name_action.used = 0; cache->name_item.used = 0; @@ -640,6 +643,7 @@ extern "C" { f_string_length_t path_original_length = 0; f_string_dynamic_t *setting_value = 0; f_string_dynamics_t *setting_values = 0; + f_string_maps_t *setting_maps = 0; f_array_length_t i = 0; f_array_length_t j = 0; @@ -666,29 +670,32 @@ extern "C" { continue; } - if (fl_string_dynamic_compare_string(controller_string_define, cache->name_item, controller_string_define_length) == F_equal_to) { - type = 1; + if (fl_string_dynamic_compare_string(controller_string_control_group, cache->name_item, controller_string_control_group_length) == F_equal_to) { + type = controller_rule_setting_type_control_group; + } + else if (fl_string_dynamic_compare_string(controller_string_define, cache->name_item, controller_string_define_length) == F_equal_to) { + type = controller_rule_setting_type_define; } else if (fl_string_dynamic_compare_string(controller_string_environment, cache->name_item, controller_string_environment_length) == F_equal_to) { - type = 2; + type = controller_rule_setting_type_environment; } else if (fl_string_dynamic_compare_string(controller_string_name, cache->name_item, controller_string_name_length) == F_equal_to) { - type = 3; + type = controller_rule_setting_type_name; } else if (fl_string_dynamic_compare_string(controller_string_need, cache->name_item, controller_string_need_length) == F_equal_to) { - type = 4; + type = controller_rule_setting_type_need; } - else if (fl_string_dynamic_compare_string(controller_string_path, cache->name_item, controller_string_path_length) == F_equal_to) { - type = 5; + else if (fl_string_dynamic_compare_string(controller_string_parameter, cache->name_item, controller_string_parameter_length) == F_equal_to) { + type = controller_rule_setting_type_parameter; } - else if (fl_string_dynamic_compare_string(controller_string_pid, cache->name_item, controller_string_pid_length) == F_equal_to) { - type = 6; + else if (fl_string_dynamic_compare_string(controller_string_path, cache->name_item, controller_string_path_length) == F_equal_to) { + type = controller_rule_setting_type_path; } else if (fl_string_dynamic_compare_string(controller_string_want, cache->name_item, controller_string_want_length) == F_equal_to) { - type = 7; + type = controller_rule_setting_type_want; } else if (fl_string_dynamic_compare_string(controller_string_wish, cache->name_item, controller_string_wish_length) == F_equal_to) { - type = 8; + type = controller_rule_setting_type_wish; } else { if (data.warning.verbosity == f_console_verbosity_debug) { @@ -736,7 +743,8 @@ extern "C" { continue; } - if (type == 1) { + if (type == controller_rule_setting_type_define || type == controller_rule_setting_type_parameter) { + if (cache->content_actions.array[i].used != 2) { fprintf(data.error.to.stream, "%c", f_string_eol[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 : "", data.error.context.after->string, f_string_eol[0]); @@ -750,10 +758,17 @@ extern "C" { continue; } - rule->defines.array[rule->defines.used].name.used = 0; - rule->defines.array[rule->defines.used].value.used = 0; + if (type == controller_rule_setting_type_define) { + setting_maps = &rule->define; + } + else if (type == controller_rule_setting_type_parameter) { + setting_maps = &rule->parameter; + } - status = fl_string_maps_increase(&rule->defines); + setting_maps->array[setting_maps->used].name.used = 0; + setting_maps->array[setting_maps->used].value.used = 0; + + status = fl_string_maps_increase(setting_maps); if (F_status_is_error(status)) { fll_error_print(data.error, F_status_set_fine(status), "fl_string_maps_increase", F_true); @@ -770,7 +785,7 @@ extern "C" { continue; } - status = fl_string_dynamic_partial_append_nulless(cache->buffer_item, cache->content_actions.array[i].array[0], &rule->defines.array[rule->defines.used].name); + status = fl_string_dynamic_partial_append_nulless(cache->buffer_item, cache->content_actions.array[i].array[0], &setting_maps->array[setting_maps->used].name); if (F_status_is_error(status)) { fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_partial_append_nulless", F_true); @@ -787,7 +802,7 @@ extern "C" { continue; } - status = fl_string_dynamic_partial_append_nulless(cache->buffer_item, cache->content_actions.array[i].array[1], &rule->defines.array[rule->defines.used].value); + status = fl_string_dynamic_partial_append_nulless(cache->buffer_item, cache->content_actions.array[i].array[1], &setting_maps->array[setting_maps->used].value); if (F_status_is_error(status)) { fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_partial_append_nulless", F_true); @@ -804,80 +819,64 @@ extern "C" { continue; } - rule->defines.used++; + setting_maps->used++; + continue; } - if (type == 3 || type == 5 || type == 6) { - if (type == 3) { + if (type == controller_rule_setting_type_control_group || type == controller_rule_setting_type_name || type == controller_rule_setting_type_path) { + if (type == controller_rule_setting_type_control_group) { + setting_value = &rule->control_group; + } + else if (type == controller_rule_setting_type_name) { setting_value = &rule->name; } - else if (type == 5) { + else if (type == controller_rule_setting_type_path) { setting_value = &rule->path; } - else { - setting_value = &rule->pid; - } - - if (type == 6) { - if (setting_value->used || cache->content_actions.array[i].used != 1) { - fprintf(data.error.to.stream, "%c", f_string_eol[0]); - fprintf(data.error.to.stream, "%s%sRule setting requires exactly one Content.%s%c", data.error.context.before->string, data.error.prefix ? data.error.prefix : "", data.error.context.after->string, f_string_eol[0]); - controller_rule_error_print(data.error, *cache, F_false); + if (setting_value->used || cache->content_actions.array[i].used != 1) { + fprintf(data.error.to.stream, "%c", f_string_eol[0]); + fprintf(data.error.to.stream, "%s%sRule setting requires exactly one Content.%s%c", data.error.context.before->string, data.error.prefix ? data.error.prefix : "", data.error.context.after->string, f_string_eol[0]); - if (F_status_is_error_not(status_return)) { - status_return = F_status_set_error(F_invalid); - } + controller_rule_error_print(data.error, *cache, F_false); - continue; + if (F_status_is_error_not(status_return)) { + status_return = F_status_set_error(F_invalid); } - } - else { - if (setting_value->used || cache->content_actions.array[i].used > 1) { - fprintf(data.error.to.stream, "%c", f_string_eol[0]); - fprintf(data.error.to.stream, "%s%sRule setting requires no Content or exactly one Content.%s%c", data.error.context.before->string, data.error.prefix ? data.error.prefix : "", data.error.context.after->string, f_string_eol[0]); - controller_rule_error_print(data.error, *cache, F_false); + continue; + } - if (F_status_is_error_not(status_return)) { - status_return = F_status_set_error(F_invalid); - } + setting_value->used = 0; - continue; - } + if (type == controller_rule_setting_type_control_group || type == controller_rule_setting_type_name) { + status = fl_string_dynamic_rip_nulless(cache->buffer_item, cache->content_actions.array[i].array[0], setting_value); - if (!cache->content_actions.array[i].used) { + if (F_status_is_error(status)) { setting_value->used = 0; - continue; - } - } - status = fl_string_dynamic_partial_append_nulless(cache->buffer_item, cache->content_actions.array[i].array[0], setting_value); + fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_rip_nulless", F_true); - if (F_status_is_error(status)) { - fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_partial_append_nulless", F_true); + 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; + } - 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; - } + if (F_status_is_error_not(status_return)) { + status_return = status; + } - if (F_status_is_error_not(status_return)) { - status_return = status; + controller_rule_error_print(data.error, *cache, F_false); + continue; } - controller_rule_error_print(data.error, *cache, F_false); - continue; - } - - if (type == 3) { - status = controller_validate_has_graph(setting_values->array[setting_values->used]); + status = controller_validate_has_graph(*setting_value); if (status == F_false || F_status_set_fine(status) == F_incomplete_utf) { if (status == F_false) { fprintf(data.error.to.stream, "%c", f_string_eol[0]); fprintf(data.error.to.stream, "%s%sRule setting has an invalid name '", data.error.context.before->string, data.error.prefix ? data.error.prefix : ""); - fprintf(data.error.to.stream, "%s%s%s%s", data.error.context.after->string, data.error.notable.before->string, setting_values->array[setting_values->used].string, 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]); + fprintf(data.error.to.stream, "%s%s%s%s", data.error.context.after->string, data.error.notable.before->string, setting_value->string, data.error.notable.after->string); + fprintf(data.error.to.stream, "%s', there must be at least 1 graph character.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol[0]); controller_rule_error_print(data.error, *cache, F_false); @@ -895,37 +894,17 @@ extern "C" { } } - setting_values->array[setting_values->used].used = 0; + setting_value->used = 0; controller_rule_error_print(data.error, *cache, F_false); continue; } } - else if (type == 6) { - path_original_length = setting_value->used; - - // guarantee that path begins at the root. - if (!setting_value->used || setting_value->string[0] != f_path_separator[0]) { - path_original_length++; - } - - char path_original[path_original_length + 1]; - - if (path_original_length == setting_value->used) { - memcpy(path_original, setting_value->string, setting_value->used); - } - else { - memcpy(path_original + 1, setting_value->string, setting_value->used - 1); - path_original[0] = f_path_separator[0]; - } - - path_original[path_original_length] = 0; - - // force the path to be canonical (removing all '../' parts). - status = fll_path_canonical(path_original, setting_value); + else if (type == controller_rule_setting_type_path) { + status = fl_string_dynamic_partial_append_nulless(cache->buffer_item, cache->content_actions.array[i].array[0], setting_value); if (F_status_is_error(status)) { - fll_error_print(data.error, F_status_set_fine(status), "fll_path_canonical", F_true); + fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_partial_append_nulless", F_true); 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; @@ -935,6 +914,8 @@ extern "C" { status_return = status; } + setting_value->used = 0; + controller_rule_error_print(data.error, *cache, F_false); continue; } @@ -943,58 +924,49 @@ extern "C" { continue; } - if (type == 2) { + if (type == controller_rule_setting_type_environment) { setting_values = &rule->environment; - } - else if (type == 4) { - setting_values = &rule->need; - } - else if (type == 7) { - setting_values = &rule->want; - } - else { - setting_values = &rule->wish; - } - for (j = 0; j < cache->content_actions.array[i].used; ++j) { + for (j = 0; j < cache->content_actions.array[i].used; ++j) { - status = fl_string_dynamics_increase(setting_values); + status = fl_string_dynamics_increase(setting_values); - if (F_status_is_error(status)) { - fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamics_increase", F_true); + if (F_status_is_error(status)) { + fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamics_increase", F_true); - 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; - } + 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; + } - if (F_status_is_error_not(status_return)) { - status_return = status; + if (F_status_is_error_not(status_return)) { + status_return = status; + } + + controller_rule_error_print(data.error, *cache, F_false); + continue; } - controller_rule_error_print(data.error, *cache, F_false); - continue; - } + setting_values->array[setting_values->used].used = 0; - setting_values->array[setting_values->used].used = 0; + status = fl_string_dynamic_partial_append_nulless(cache->buffer_item, cache->content_actions.array[i].array[j], &setting_values->array[setting_values->used]); - status = fl_string_dynamic_partial_append_nulless(cache->buffer_item, cache->content_actions.array[i].array[j], &setting_values->array[setting_values->used]); + if (F_status_is_error(status)) { + setting_values->array[setting_values->used].used = 0; - if (F_status_is_error(status)) { - fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_partial_append_nulless", F_true); + fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_partial_append_nulless", F_true); - 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; - } + 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; + } - if (F_status_is_error_not(status_return)) { - status_return = status; - } + if (F_status_is_error_not(status_return)) { + status_return = status; + } - controller_rule_error_print(data.error, *cache, F_false); - continue; - } + controller_rule_error_print(data.error, *cache, F_false); + continue; + } - if (type == 2) { status = controller_validate_environment_name(setting_values->array[setting_values->used]); if (status == F_false || F_status_set_fine(status) == F_incomplete_utf) { @@ -1025,10 +997,177 @@ extern "C" { controller_rule_error_print(data.error, *cache, F_false); continue; } + + setting_values->used++; + } // for + + continue; + } + + if (cache->content_actions.array[i].used != 2) { + fprintf(data.error.to.stream, "%c", f_string_eol[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 : "", data.error.context.after->string, f_string_eol[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_invalid); } - setting_values->used++; - } // for + continue; + } + + if (type == controller_rule_setting_type_need) { + setting_values = &rule->need; + } + else if (type == controller_rule_setting_type_want) { + setting_values = &rule->want; + } + else if (type == controller_rule_setting_type_wish) { + setting_values = &rule->wish; + } + + status = fl_string_dynamics_increase_by(2, setting_values); + + if (F_status_is_error(status)) { + fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamics_increase_by", F_true); + + 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; + } + + if (F_status_is_error_not(status_return)) { + status_return = status; + } + + controller_rule_error_print(data.error, *cache, F_false); + continue; + } + + setting_values->array[setting_values->used].used = 0; + setting_values->array[setting_values->used + 1].used = 0; + + status = fl_string_dynamic_partial_append_nulless(cache->buffer_item, cache->content_actions.array[i].array[0], &setting_values->array[setting_values->used]); + + if (F_status_is_error(status)) { + setting_values->array[setting_values->used].used = 0; + + fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_partial_append_nulless", F_true); + + 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; + } + + if (F_status_is_error_not(status_return)) { + status_return = status; + } + + controller_rule_error_print(data.error, *cache, F_false); + continue; + } + + status = fl_string_dynamic_partial_append_nulless(cache->buffer_item, cache->content_actions.array[i].array[1], &setting_values->array[setting_values->used + 1]); + + if (F_status_is_error(status)) { + setting_values->array[setting_values->used].used = 0; + setting_values->array[setting_values->used + 1].used = 0; + + fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_partial_append_nulless", F_true); + + 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; + } + + if (F_status_is_error_not(status_return)) { + status_return = status; + } + + controller_rule_error_print(data.error, *cache, F_false); + continue; + } + + // force the path to be canonical (removing all '../' parts). + status = fll_path_canonical(setting_values->array[setting_values->used].string, &setting_values->array[setting_values->used]); + + if (F_status_is_error(status)) { + setting_values->array[setting_values->used].used = 0; + setting_values->array[setting_values->used + 1].used = 0; + + fll_error_print(data.error, F_status_set_fine(status), "fll_path_canonical", F_true); + + 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) { + status_return = status; + break; + } + + if (F_status_is_error_not(status_return)) { + status_return = status; + } + + continue; + } + + cache->buffer_path.used = 0; + + status = f_file_name_base(setting_values->array[setting_values->used + 1].string, setting_values->array[setting_values->used + 1].used, &cache->buffer_path); + + if (F_status_is_error(status)) { + setting_values->array[setting_values->used].used = 0; + setting_values->array[setting_values->used + 1].used = 0; + + fll_error_print(data.error, F_status_set_fine(status), "f_file_name_base", F_true); + + 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) { + status_return = status; + break; + } + + if (F_status_is_error_not(status_return)) { + status_return = status; + } + + continue; + } + else { + if (fl_string_dynamic_compare(setting_values->array[setting_values->used + 1], cache->buffer_path) == F_equal_to_not) { + + if (data.error.verbosity != f_console_verbosity_quiet) { + status = fl_string_dynamic_terminate_after(&cache->buffer_item); + + if (F_status_is_error(status)) { + setting_values->array[setting_values->used].used = 0; + setting_values->array[setting_values->used + 1].used = 0; + + fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_terminate_after", F_true); + + 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; + } + + if (F_status_is_error_not(status_return)) { + status_return = status; + } + + controller_rule_error_print(data.error, *cache, F_false); + continue; + } + + fprintf(data.error.to.stream, "%c", f_string_eol[0]); + fprintf(data.error.to.stream, "%s%sThe rule item action second parameter '", data.error.context.before->string, data.error.prefix ? data.error.prefix : ""); + fprintf(data.error.to.stream, "%s%s%s%s", data.error.context.after->string, data.error.notable.before->string, setting_values->array[setting_values->used + 1].string, data.error.notable.after->string); + fprintf(data.error.to.stream, "%s' must be a base path name, such as '", data.error.context.before->string); + fprintf(data.error.to.stream, "%s%s%s%s", data.error.context.after->string, data.error.notable.before->string, cache->buffer_path.string, 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]); + } + + setting_values->array[setting_values->used].used = 0; + setting_values->array[setting_values->used + 1].used = 0; + + continue; + } + } + + setting_values->used += 2; } // for return status_return; diff --git a/level_3/controller/c/private-rule.h b/level_3/controller/c/private-rule.h index 8e776a5..8007bb4 100644 --- a/level_3/controller/c/private-rule.h +++ b/level_3/controller/c/private-rule.h @@ -32,6 +32,7 @@ extern "C" { f_string_dynamic_t buffer_file; f_string_dynamic_t buffer_item; + f_string_dynamic_t buffer_path; f_string_dynamic_t name_action; f_string_dynamic_t name_file; @@ -55,6 +56,7 @@ extern "C" { f_string_dynamic_t_initialize, \ f_string_dynamic_t_initialize, \ f_string_dynamic_t_initialize, \ + f_string_dynamic_t_initialize, \ } #define macro_controller_rule_cache_t_delete_simple(cache) \ @@ -284,12 +286,14 @@ extern "C" { * F_invalid (with error bit) on success but there were one or more invalid settings encountered. * * Errors (with error bit) from: fl_string_dynamic_partial_append_nulless(). + * Errors (with error bit) from: fl_string_dynamic_rip_nulless(). * Errors (with error bit) from: fl_string_dynamics_increase(). * Errors (with error bit) from: fl_string_maps_increase(). * Errors (with error bit) from: fll_fss_extended_read(). * Errors (with error bit) from: fll_path_canonical(). * * @see fl_string_dynamic_partial_append_nulless() + * @see fl_string_dynamic_rip_nulless() * @see fl_string_dynamics_increase() * @see fl_string_maps_increase() * @see fll_fss_extended_read() diff --git a/level_3/controller/data/build/dependencies b/level_3/controller/data/build/dependencies index 8b4a9f5..3dba6bd 100644 --- a/level_3/controller/data/build/dependencies +++ b/level_3/controller/data/build/dependencies @@ -10,6 +10,7 @@ f_console f_conversion f_file f_fss +f_iki f_path f_pipe f_print @@ -17,6 +18,7 @@ fl_color fl_console fl_conversion fl_fss +fl_iki fl_string fll_error fll_fss diff --git a/level_3/controller/documents/rule.txt b/level_3/controller/documents/rule.txt index c63d1fe..c1defe0 100644 --- a/level_3/controller/documents/rule.txt +++ b/level_3/controller/documents/rule.txt @@ -12,17 +12,23 @@ Rule Documentation: "control_group": Define a control group (cgroup) in which everything within this rule executes under. "define": Define a custom environment variable with a given variable, and automatically expose it to processes executed within this rule. "environment": A set of environment variables to expose to the processes executed within this rule (PATH is always exposed). - "name": A name used to represent this rule, which is printing to the user, screen, logs, etc... - "need": A list of relative rule path names that represent any given rule required to be executed (must exist and must succeed) before this rule starts. + "name": A name used to represent this rule, which is printed to the user, screen, logs, etc... + "need": A single rule required to be executed (must exist and must succeed) before this rule starts. + "parameter": A statically defined IKI name and its associated value for use in this rule file. "path": A single Content used to set a custom PATH environment variable value. - "pid": A path to a directory where the PID file is expected to be stored in. - "want": A list of relative rule path names that represent any given rule desired to be executed (may exist and must succeed) before this rule starts. - "wish": A list of relative rule path names that represent any given rule desired to be executed (may exist and not required to succeed) before this rule starts. + "want": A single rule desired to be executed (may exist and must succeed) before this rule starts. + "wish": A single rule desired to be executed (may exist and is not required to succeed) before this rule starts. In the case of "want" and "wish", if the desired rule is either not found or is otherwise disabled, then this will not fail or otherwise block the wanting or wishing rule. In the case of "path", when specified, the PATH environment variable is automatically added to the "environment" setting. + In the case of "parameter", IKI variables are expanded in a pre-process manner and will be removed prior to any execution. + Any IKI variables referencing an undefined parameter will be fully removed. + These parameters are only exposed in the specific rule file in which they are defined and cannot be shared between rules. + A "parameter" variable and an "environment" variable are mutually exclusive but an environment variable, in theory, can have an IKI variable assigned to it inside of a "script". + These IKI variables are only substituted within a Rule Item's Content (and not within a Rule Setting nor within a Rule Item's Object). + The "command" outer most part provides a simple command to run under the different circumstances: "start", "stop", "restart", and "reload". A "command" always operates in the foreground. @@ -33,6 +39,8 @@ Rule Documentation: This "script" operates in the foreground, but individual things done within the script may operate in foreground or background. The last return state is treated as an error, so be sure to finish the script with a return code of 0 to designate no error and any other whole number, such a 1, to designate an error. Therefore passing "exit 1" would return as an error and passing "exit 0" would return as a success. + A "script" is assumed to be in GNU Bash, which is the default expected behavior, but the specification does not explicitly require this. + Another scripting language can be used but changing this incurs the responsibility to ensure all rules are updated to the appropriate scripting language. There are five primary inner Content to perform: "kill", "restart", "reload", "start", and "stop". @@ -44,6 +52,7 @@ Rule Documentation: When "restart" Content is not provided, then "start" and "stop" is called when the rule is executed using the restart action, if both "start" and "stop" are provided. When "reload", "start", or "stop" Content are not provided, then no respective action is performed. + Commands are conditionally available depending on the presence of these, such as if "stop" is not provided then "stop" (and "restart") will not be available for the "control" program(s) to use. The "group" inner Content, an associated "command", "service", or "script" are executed with that group ID or group name. The "user" inner Content, an associated "command", "service", or "script" are executed with that user ID or user name. diff --git a/level_3/controller/specifications/rule.txt b/level_3/controller/specifications/rule.txt index 5914018..769c706 100644 --- a/level_3/controller/specifications/rule.txt +++ b/level_3/controller/specifications/rule.txt @@ -1,7 +1,7 @@ # fss-0002 Rule Specification: - The Rule files follow the FSS-000D (Basic Rule) format. + The Rule files follow the FSS-000D (Basic Rule) format with IKI-0000 (Unrestricted IKI). A Rule file name is expected to have the file extension ".rule". @@ -28,15 +28,15 @@ Rule Specification: The other Rule Types are processed top-down. The "settings" Rule Type has the following FSS-0001 (Extended)\: - "control_group": Zero or One Content representing a valid control group (cgroup) name. + "control_group": One Content representing a valid control group (cgroup) name, must have at least 1 graph character (non-whitespace printing character) (leading and trailing whitespace are trimmed off). "define": Two Content, the first Content must be a case-sensitive valid environment variable name (alpha-numeric or underscore, but no leading digits). "environment": Zero or more Content, each must be a case-sensitive valid environment variable name (alpha-numeric or underscore, but no leading digits). - "name": Zero or One Content, must have at least 1 graph character (non-whitespace printing character). - "need": Zero or more Content, each being a partial path and the rule file name without extension (such as "boot/modules"). - "path": Zero or One Content representing a valid PATH environment string (such as "/bin:/sbin:/usr/bin"). - "pid": One Content representing the full path to a PID file directory (such as "/var/run/service/ssh.pid"). - "want": Zero or more Content, each being a partial path and the rule file name without extension (such as "boot/modules"). - "wish": Zero or more Content, each being a partial path and the rule file name without extension (such as "boot/modules"). + "name": One Content, must have at least 1 graph character (non-whitespace printing character) (leading and trailing whitespace are trimmed off). + "need": Two Content, the first being a partial path and the second being a rule file name without extension (such as "boot" "modules"). + "parameter": Two Content, the first Content must be a case-sensitive valid IKI name and the second being an IKI value. + "path": One Content representing a valid PATH environment string (such as "/bin:/sbin:/usr/bin"). + "want": Two Content, the first being a partial path and the second being a rule file name without extension (such as "boot" "modules"). + "wish": Two Content, the first being a partial path and the second being a rule file name without extension (such as "boot" "modules"). The "service" Rule Type allows the following the FSS-0001 (Extended)\: "create": One Content representing the path to a PID file. diff --git a/specifications/fss-000D.txt b/specifications/fss-000D.txt index 63f7190..4fa6d99 100644 --- a/specifications/fss-000D.txt +++ b/specifications/fss-000D.txt @@ -11,6 +11,11 @@ Featureless Settings Specification: 000D - Basic Rule: The FSS Basic and FSS Extended Objects have the same format for Object names but the FSS Extended List Object is slightly different. Anything that would match an FSS Extended List Object must therefore be an FSS Extended List Object. + This supports the use of IKI-0000 (Unrestricted) but only within the Content of the outermost Basic List. + Furthermore, should there be a Basic List that defines IKI names and values, then that Basic List must not support IKI substitution. + Additional restrictions on the use of IKI syntax is allowed if explicitly defined in the implementing specification. + This additional restriction may also include using a more restrictive IKI syntax, such as "IKI-0001 (Basic IKI)". + Anything implementing this specification may impose its own restrictions on when to determine if the Inner Content is what FSS format, based on Object names. See the appropriate specifications for the Key/Structure/Example documentation for the respective FSS-0000 (Basic), FSS-0001 (Extended), and FSS-0003 (Extended List). @@ -18,7 +23,7 @@ Featureless Settings Specification: 000D - Basic Rule: Example\: main: - name boot-devices + name "Boot Devices" script: start { @@ -40,7 +45,7 @@ Featureless Settings Specification: 000D - Basic Rule: 3) command Outer List Contents would be\: - 1.1) name boot-devices + 1.1) name "Boot Devices" 2.1) start { ip addr add 127.0.0.1/8 label lo dev lo; @@ -61,8 +66,8 @@ Featureless Settings Specification: 000D - Basic Rule: 3.1.1) begin 3.1.2) end - Inner Content Contents would be\: - 1.1.1) boot-devices + Inner Content Contents would be (without breaking Content into its individual parts)\: + 1.1.1) Boot Devices 2.1.1) ip addr add 127.0.0.1/8 label lo dev lo; ip link set lo up; 2.1.2) ip link set lo down; -- 1.8.3.1