From: Kevin Day Date: Mon, 24 Jan 2022 01:40:38 +0000 (-0600) Subject: Progress: Continue working on implementing control and controller programs. X-Git-Tag: 0.5.8~91 X-Git-Url: https://git.kevux.org/?a=commitdiff_plain;h=73e77ddac265b3806580693c1eb553b3d2361e1a;p=fll Progress: Continue working on implementing control and controller programs. The control program and the controller program will communicate using datagram named sockets. --- diff --git a/level_3/control/c/control.c b/level_3/control/c/control.c index d8e4a8d..ce8b57f 100644 --- a/level_3/control/c/control.c +++ b/level_3/control/c/control.c @@ -1,31 +1,65 @@ #include "control.h" #include "private-common.h" #include "private-control.h" +#include "private-print.h" #ifdef __cplusplus extern "C" { #endif +#ifndef _di_control_program_version_ + const f_string_static_t control_program_version_s = macro_f_string_static_t_initialize2(CONTROL_program_version_s, 0, CONTROL_program_version_s_length); +#endif // _di_control_program_version_ + +#ifndef _di_control_program_name_ + const f_string_static_t control_program_name_s = macro_f_string_static_t_initialize2(CONTROL_program_name_s, 0, CONTROL_program_name_s_length); + const f_string_static_t control_program_name_long_s = macro_f_string_static_t_initialize2(CONTROL_program_name_long_s, 0, CONTROL_program_name_long_s_length); +#endif // _di_control_program_name_ + +#ifndef _di_control_defines_ + const f_string_static_t control_short_name_s = macro_f_string_static_t_initialize2(CONTROL_short_name_s, 0, CONTROL_short_name_s_length); + const f_string_static_t control_short_settings_s = macro_f_string_static_t_initialize2(CONTROL_short_settings_s, 0, CONTROL_short_settings_s_length); + const f_string_static_t control_short_socket_s = macro_f_string_static_t_initialize2(CONTROL_short_socket_s, 0, CONTROL_short_socket_s_length); + + const f_string_static_t control_long_name_s = macro_f_string_static_t_initialize2(CONTROL_long_name_s, 0, CONTROL_long_name_s_length); + const f_string_static_t control_long_settings_s = macro_f_string_static_t_initialize2(CONTROL_long_settings_s, 0, CONTROL_long_settings_s_length); + const f_string_static_t control_long_socket_s = macro_f_string_static_t_initialize2(CONTROL_long_socket_s, 0, CONTROL_long_socket_s_length); +#endif // _di_control_defines_ + #ifndef _di_control_print_help_ - f_status_t control_print_help(const f_file_t file, const f_color_context_t context) { + f_status_t control_print_help(control_main_t * const main) { + + flockfile(main->output.to.stream); + + fll_program_print_help_header(main->output.to, main->context, control_program_name_long_s.string, control_program_version_s.string); - flockfile(file.stream); + fll_program_print_help_option(main->output.to, main->context, f_console_standard_short_help_s, f_console_standard_long_help_s, f_console_symbol_short_enable_s, f_console_symbol_long_enable_s, " Print this help message."); + fll_program_print_help_option(main->output.to, main->context, f_console_standard_short_dark_s, f_console_standard_long_dark_s, f_console_symbol_short_disable_s, f_console_symbol_long_disable_s, " Output using colors that show up better on dark backgrounds."); + fll_program_print_help_option(main->output.to, main->context, f_console_standard_short_light_s, f_console_standard_long_light_s, f_console_symbol_short_disable_s, f_console_symbol_long_disable_s, " Output using colors that show up better on light backgrounds."); + fll_program_print_help_option(main->output.to, main->context, f_console_standard_short_no_color_s, f_console_standard_long_no_color_s, f_console_symbol_short_disable_s, f_console_symbol_long_disable_s, "Do not main->output.to in color."); + fll_program_print_help_option(main->output.to, main->context, f_console_standard_short_quiet_s, f_console_standard_long_quiet_s, f_console_symbol_short_disable_s, f_console_symbol_long_disable_s, " Decrease verbosity, silencing most output."); + fll_program_print_help_option(main->output.to, main->context, f_console_standard_short_normal_s, f_console_standard_long_normal_s, f_console_symbol_short_disable_s, f_console_symbol_long_disable_s, " Set verbosity to normal main->output.to."); + fll_program_print_help_option(main->output.to, main->context, f_console_standard_short_verbose_s, f_console_standard_long_verbose_s, f_console_symbol_short_disable_s, f_console_symbol_long_disable_s, " Increase verbosity beyond normal output."); + fll_program_print_help_option(main->output.to, main->context, f_console_standard_short_debug_s, f_console_standard_long_debug_s, f_console_symbol_short_disable_s, f_console_symbol_long_disable_s, " Enable debugging, significantly increasing verbosity beyond normal output."); + fll_program_print_help_option(main->output.to, main->context, f_console_standard_short_version_s, f_console_standard_long_version_s, f_console_symbol_short_disable_s, f_console_symbol_long_disable_s, " Print only the version number."); - fll_program_print_help_header(file, context, control_program_name_long_s, control_program_version_s); + f_print_character(f_string_eol_s[0], main->output.to.stream); - fll_program_print_help_option(file, context, f_console_standard_short_help_s, f_console_standard_long_help_s, f_console_symbol_short_enable_s, f_console_symbol_long_enable_s, " Print this help message."); - fll_program_print_help_option(file, context, f_console_standard_short_dark_s, f_console_standard_long_dark_s, f_console_symbol_short_disable_s, f_console_symbol_long_disable_s, " Output using colors that show up better on dark backgrounds."); - fll_program_print_help_option(file, context, f_console_standard_short_light_s, f_console_standard_long_light_s, f_console_symbol_short_disable_s, f_console_symbol_long_disable_s, " Output using colors that show up better on light backgrounds."); - fll_program_print_help_option(file, context, f_console_standard_short_no_color_s, f_console_standard_long_no_color_s, f_console_symbol_short_disable_s, f_console_symbol_long_disable_s, "Do not file in color."); - fll_program_print_help_option(file, context, f_console_standard_short_quiet_s, f_console_standard_long_quiet_s, f_console_symbol_short_disable_s, f_console_symbol_long_disable_s, " Decrease verbosity, silencing most output."); - fll_program_print_help_option(file, context, f_console_standard_short_normal_s, f_console_standard_long_normal_s, f_console_symbol_short_disable_s, f_console_symbol_long_disable_s, " Set verbosity to normal file."); - fll_program_print_help_option(file, context, f_console_standard_short_verbose_s, f_console_standard_long_verbose_s, f_console_symbol_short_disable_s, f_console_symbol_long_disable_s, " Increase verbosity beyond normal output."); - fll_program_print_help_option(file, context, f_console_standard_short_debug_s, f_console_standard_long_debug_s, f_console_symbol_short_disable_s, f_console_symbol_long_disable_s, " Enable debugging, significantly increasing verbosity beyond normal output."); - fll_program_print_help_option(file, context, f_console_standard_short_version_s, f_console_standard_long_version_s, f_console_symbol_short_disable_s, f_console_symbol_long_disable_s, " Print only the version number."); + fll_program_print_help_option(main->output.to, main->context, control_short_name_s.string, control_long_name_s.string, f_console_symbol_short_enable_s, f_console_symbol_long_enable_s, " Specify the name of the controller socket file."); + fll_program_print_help_option(main->output.to, main->context, control_short_settings_s.string, control_long_settings_s.string, f_console_symbol_short_enable_s, f_console_symbol_long_enable_s, "Specify a directory path or a full path to the control settings file."); + fll_program_print_help_option(main->output.to, main->context, control_short_socket_s.string, control_long_socket_s.string, f_console_symbol_short_enable_s, f_console_symbol_long_enable_s, " Specify a directory path or a full path to the controller socket file."); - fll_program_print_help_usage(file, context, control_program_name_s, f_string_empty_s); + fll_program_print_help_usage(main->output.to, main->context, control_program_name_s.string, control_command_s.string); - funlockfile(file.stream); + fl_print_format(" When the %[%s%s%] parameter represents a directory path then the file name is generated from either the", main->output.to.stream, main->context.set.notable, f_console_symbol_long_enable_s, control_long_socket_s.string, main->context.set.notable); + fl_print_format(" %[%s%s%] parameter or from the control settings file.%c%c", main->output.to.stream, main->context.set.notable, f_console_symbol_long_enable_s, control_long_name_s.string, main->context.set.notable, f_string_eol_s[0], f_string_eol_s[0]); + + fl_print_format(" A rule action allows for either the full rule path, such as '%[boot/root%]'", main->output.to.stream, main->context.set.notable, main->context.set.notable); + fl_print_format(" as a single parameter or two parameters with the first representing the rule directory path '%[boot%]'", main->output.to.stream, main->context.set.notable, main->context.set.notable); + fl_print_format(" and the second representing the rule base name '%[root%]'.%c%c", main->output.to.stream, main->context.set.notable, main->context.set.notable, f_string_eol_s[0], f_string_eol_s[0]); + + fflush(main->output.to.stream); + funlockfile(main->output.to.stream); return F_none; } @@ -117,7 +151,7 @@ extern "C" { } if (main->parameters[control_parameter_help_e].result == f_console_result_found_e) { - control_print_help(main->output.to, main->context); + control_print_help(main); control_main_delete(main); @@ -125,14 +159,95 @@ extern "C" { } if (main->parameters[control_parameter_version_e].result == f_console_result_found_e) { - fll_program_print_version(main->output.to, control_program_version_s); + fll_program_print_version(main->output.to, control_program_version_s.string); control_main_delete(main); return F_none; } - // @todo + { + uint8_t ids[] = { + control_parameter_name_e, + control_parameter_settings_e, + control_parameter_socket_e + }; + + f_string_static_t names[] = { + control_long_name_s, + control_long_settings_s, + control_long_socket_s + }; + + f_array_length_t location = f_array_length_t_initialize; + + for (uint8_t i = 0; i < 3; ++i) { + + if (main->parameters[ids[i]].result == f_console_result_found_e) { + control_print_error_parameter_value_not(main, names[i]); + + status = F_status_set_error(F_parameter); + } + else if (main->parameters[ids[i]].result == f_console_result_additional_e) { + location = main->parameters[ids[i]].values.array[main->parameters[ids[i]].values.used - 1]; + + if (!strnlen(arguments->argv[location], f_console_parameter_size)) { + control_print_error_parameter_value_empty(main, names[i]); + + status = F_status_set_error(F_parameter); + } + } + } // for + } + + if (F_status_is_error_not(status)) { + if (main->process_pipe) { + control_print_error_pipe_supported_not(main); + + status = F_status_set_error(F_supported_not); + } + else if (main->remaining.used) { + control_data_t data = control_data_t_initialize; + + // Verify commands before attempting to connect to the socket. + if (control_command_identify(main, &data, arguments->argv[0]) == F_found) { + status = control_command_verify(main, &data, arguments); + } + else { + control_print_error_parameter_command_not(main, arguments->argv[0]); + + status = F_status_set_error(F_parameter); + } + + if (F_status_is_error_not(status)) { + struct sockaddr_un socket_address; + + memset(&socket_address, 0, sizeof(struct sockaddr_un)); + + data.socket.address = (struct sockaddr *) &socket_address; + data.socket.domain = f_socket_domain_file_d; + data.socket.type = f_socket_type_datagram_d; + data.socket.length = sizeof(struct sockaddr_un); + + status = control_settings_load(main, &data, arguments); + + if (F_status_is_error_not(status)) { + // @todo construct the packet, send the packet to the controller, and process the response. + } + + if (data.socket.id != -1) { + f_socket_disconnect(&data.socket, f_socket_close_fast_e); + } + } + + control_data_delete(&data); + } + else { + control_print_error_commands_none(main); + + status = F_status_set_error(F_data_not); + } + } // Ensure a newline is always put at the end of the program execution, unless in quiet mode. if (main->output.verbosity != f_console_verbosity_quiet_e) { @@ -156,12 +271,12 @@ extern "C" { for (f_array_length_t i = 0; i < control_total_parameters_d; ++i) { - macro_f_array_lengths_t_delete_simple(main->parameters[i].locations); - macro_f_array_lengths_t_delete_simple(main->parameters[i].locations_sub); - macro_f_array_lengths_t_delete_simple(main->parameters[i].values); + f_type_array_lengths_resize(0, &main->parameters[i].locations); + f_type_array_lengths_resize(0, &main->parameters[i].locations_sub); + f_type_array_lengths_resize(0, &main->parameters[i].values); } // for - macro_f_array_lengths_t_delete_simple(main->remaining); + f_type_array_lengths_resize(0, &main->remaining); macro_f_color_context_t_delete_simple(main->context); diff --git a/level_3/control/c/control.h b/level_3/control/c/control.h index 9ed13c4..19a2784 100644 --- a/level_3/control/c/control.h +++ b/level_3/control/c/control.h @@ -25,17 +25,21 @@ #include #include #include +#include #include #include #include +#include // fll-1 includes #include +#include #include #include // fll-2 includes #include +#include #include #include @@ -44,30 +48,71 @@ extern "C" { #endif #ifndef _di_control_program_version_ - #define control_program_version_major_s F_string_ascii_0_s - #define control_program_version_minor_s F_string_ascii_5_s - #define control_program_version_micro_s F_string_ascii_8_s + #define CONTROL_program_version_major_s F_string_ascii_0_s + #define CONTROL_program_version_minor_s F_string_ascii_5_s + #define CONTROL_program_version_micro_s F_string_ascii_8_s - #ifndef control_program_version_nano_prefix_s - #define control_program_version_nano_prefix_s + #define CONTROL_program_version_major_s_length 1 + #define CONTROL_program_version_minor_s_length 1 + #define CONTROL_program_version_micro_s_length 1 + + #ifndef CONTROL_program_version_nano_prefix_s + #define CONTROL_program_version_nano_prefix_s + + #define CONTROL_program_version_nano_prefix_s_length 0 #endif - #ifndef control_program_version_nano_s - #define control_program_version_nano_s + #ifndef CONTROL_program_version_nano_s + #define CONTROL_program_version_nano_s + + #define CONTROL_program_version_nano_s_length 0 #endif - #define control_program_version_s control_program_version_major_s F_string_ascii_period_s control_program_version_minor_s F_string_ascii_period_s control_program_version_micro_s control_program_version_nano_prefix_s control_program_version_nano_s + #define CONTROL_program_version_s CONTROL_program_version_major_s F_string_ascii_period_s CONTROL_program_version_minor_s F_string_ascii_period_s CONTROL_program_version_micro_s CONTROL_program_version_nano_prefix_s CONTROL_program_version_nano_s + + #define CONTROL_program_version_s_length CONTROL_program_version_major_s_length + F_string_ascii_period_s_length + CONTROL_program_version_minor_s_length + F_string_ascii_period_s_length + CONTROL_program_version_nano_prefix_s_length + CONTROL_program_version_nano_s_length + + extern const f_string_static_t control_program_version_s; #endif // _di_control_program_version_ #ifndef _di_control_program_name_ - #define control_program_name_s "control" - #define control_program_name_long_s "Control Program" + #define CONTROL_program_name_s "control" + #define CONTROL_program_name_long_s "Control Program" + + #define CONTROL_program_name_s_length 7 + #define CONTROL_program_name_long_s_length 15 + + extern const f_string_static_t control_program_name_s; + extern const f_string_static_t control_program_name_long_s; #endif // _di_control_program_name_ #ifndef _di_control_defines_ + #define CONTROL_short_name_s "n" + #define CONTROL_short_settings_s "s" + #define CONTROL_short_socket_s "S" + + #define CONTROL_long_name_s "name" + #define CONTROL_long_settings_s "settings" + #define CONTROL_long_socket_s "socket" + + #define CONTROL_short_name_s_length 1 + #define CONTROL_short_settings_s_length 1 + #define CONTROL_short_socket_s_length 1 + + #define CONTROL_long_name_s_length 4 + #define CONTROL_long_settings_s_length 8 + #define CONTROL_long_socket_s_length 6 + + extern const f_string_static_t control_short_name_s; + extern const f_string_static_t control_short_settings_s; + extern const f_string_static_t control_short_socket_s; + + extern const f_string_static_t control_long_name_s; + extern const f_string_static_t control_long_settings_s; + extern const f_string_static_t control_long_socket_s; enum { - control_parameter_help_e, + control_parameter_help_e = 0, control_parameter_light_e, control_parameter_dark_e, control_parameter_no_color_e, @@ -76,6 +121,10 @@ extern "C" { control_parameter_verbosity_verbose_e, control_parameter_verbosity_debug_e, control_parameter_version_e, + + control_parameter_name_e, + control_parameter_settings_e, + control_parameter_socket_e, }; #define control_console_parameter_t_initialize \ @@ -89,15 +138,20 @@ extern "C" { macro_f_console_parameter_t_initialize(f_console_standard_short_verbose_s, f_console_standard_long_verbose_s, 0, 0, f_console_type_inverse_e), \ macro_f_console_parameter_t_initialize(f_console_standard_short_debug_s, f_console_standard_long_debug_s, 0, 0, f_console_type_inverse_e), \ macro_f_console_parameter_t_initialize(f_console_standard_short_version_s, f_console_standard_long_version_s, 0, 0, f_console_type_inverse_e), \ + macro_f_console_parameter_t_initialize(control_short_name_s.string, control_long_name_s.string, 0, 1, f_console_type_normal_e), \ + macro_f_console_parameter_t_initialize(control_short_settings_s.string, control_long_settings_s.string, 0, 1, f_console_type_normal_e), \ + macro_f_console_parameter_t_initialize(control_short_socket_s.string, control_long_socket_s.string, 0, 1, f_console_type_normal_e), \ } - #define control_total_parameters_d 9 + #define control_total_parameters_d 12 #endif // _di_control_defines_ -#ifndef _di_control_data_t_ +#ifndef _di_control_main_t_ typedef struct { f_console_parameter_t parameters[control_total_parameters_d]; + uint16_t signal_check; + f_array_lengths_t remaining; bool process_pipe; @@ -110,9 +164,10 @@ extern "C" { f_color_context_t context; } control_main_t; - #define control_data_initialize \ + #define control_main_initialize \ { \ control_console_parameter_t_initialize, \ + 0, \ f_array_lengths_t_initialize, \ F_false, \ fl_print_t_initialize, \ @@ -121,21 +176,19 @@ extern "C" { f_signal_t_initialize, \ f_color_context_t_initialize, \ } -#endif // _di_control_data_t_ +#endif // _di_control_main_t_ /** * Print help. * - * @param file - * The file to print to. - * @param context - * The color context settings. + * @param main + * The main program data. * * @return * F_none on success. */ #ifndef _di_control_print_help_ - extern f_status_t control_print_help(const f_file_t file, const f_color_context_t context); + extern f_status_t control_print_help(control_main_t * const main); #endif // _di_control_print_help_ /** diff --git a/level_3/control/c/main.c b/level_3/control/c/main.c index 4d2c962..18da0ea 100644 --- a/level_3/control/c/main.c +++ b/level_3/control/c/main.c @@ -3,7 +3,7 @@ int main(const int argc, const f_string_t *argv) { const f_console_arguments_t arguments = { argc, argv }; - control_main_t data = control_data_initialize; + control_main_t data = control_main_initialize; if (f_pipe_input_exists()) { data.process_pipe = F_true; diff --git a/level_3/control/c/private-common.c b/level_3/control/c/private-common.c index 4275a00..70ab9c6 100644 --- a/level_3/control/c/private-common.c +++ b/level_3/control/c/private-common.c @@ -1,27 +1,50 @@ #include "control.h" #include "private-common.h" +#include "private-print.h" #ifdef __cplusplus extern "C" { #endif -#ifndef _di_control_print_signal_received_ - void control_print_signal_received(control_main_t * const main, const f_status_t signal) { +#ifndef _di_controller_strings_ + const f_string_static_t controller_name_socket_s = macro_f_string_static_t_initialize2(CONTROLLER_name_socket_s, 0, CONTROLLER_name_socket_s_length); + const f_string_static_t controller_path_socket_s = macro_f_string_static_t_initialize2(CONTROLLER_path_socket_s, 0, CONTROLLER_path_socket_s_length); + const f_string_static_t controller_path_socket_prefix_s = macro_f_string_static_t_initialize2(CONTROLLER_path_socket_prefix_s, 0, CONTROLLER_path_socket_prefix_s_length); + const f_string_static_t controller_path_socket_suffix_s = macro_f_string_static_t_initialize2(CONTROLLER_path_socket_suffix_s, 0, CONTROLLER_path_socket_suffix_s_length); +#endif // _di_controller_strings_ - if (main->warning.verbosity != f_console_verbosity_verbose_e) return; +#ifndef _di_control_strings_s_ + const f_string_static_t control_path_settings_s = macro_f_string_static_t_initialize2(CONTROL_path_settings_s, 0, CONTROL_path_settings_s_length); - // Must flush and reset color because the interrupt may have interrupted the middle of a print function. - fflush(main->warning.to.stream); + const f_string_static_t control_command_s = macro_f_string_static_t_initialize2(CONTROL_command_s, 0, CONTROL_command_s_length); + const f_string_static_t control_default_s = macro_f_string_static_t_initialize2(CONTROL_default_s, 0, CONTROL_default_s_length); + const f_string_static_t control_name_socket_s = macro_f_string_static_t_initialize2(CONTROL_name_socket_s, 0, CONTROL_name_socket_s_length); + const f_string_static_t control_path_socket_s = macro_f_string_static_t_initialize2(CONTROL_path_socket_s, 0, CONTROL_path_socket_s_length); + const f_string_static_t control_path_socket_prefix_s = macro_f_string_static_t_initialize2(CONTROL_path_socket_prefix_s, 0, CONTROL_path_socket_prefix_s_length); + const f_string_static_t control_path_socket_suffix_s = macro_f_string_static_t_initialize2(CONTROL_path_socket_suffix_s, 0, CONTROL_path_socket_suffix_s_length); - flockfile(main->warning.to.stream); + const f_string_static_t control_error_s_length = macro_f_string_static_t_initialize2(CONTROL_error_s, 0, CONTROL_error_s_length); + const f_string_static_t control_freeze_s_length = macro_f_string_static_t_initialize2(CONTROL_freeze_s, 0, CONTROL_freeze_s_length); + const f_string_static_t control_kill_s_length = macro_f_string_static_t_initialize2(CONTROL_kill_s, 0, CONTROL_kill_s_length); + const f_string_static_t control_pause_s_length = macro_f_string_static_t_initialize2(CONTROL_pause_s, 0, CONTROL_pause_s_length); + const f_string_static_t control_reboot_s_length = macro_f_string_static_t_initialize2(CONTROL_reboot_s, 0, CONTROL_reboot_s_length); + const f_string_static_t control_reload_s_length = macro_f_string_static_t_initialize2(CONTROL_reload_s, 0, CONTROL_reload_s_length); + const f_string_static_t control_rerun_s_length = macro_f_string_static_t_initialize2(CONTROL_rerun_s, 0, CONTROL_rerun_s_length); + const f_string_static_t control_restart_s_length = macro_f_string_static_t_initialize2(CONTROL_restart_s, 0, CONTROL_restart_s_length); + const f_string_static_t control_resume_s_length = macro_f_string_static_t_initialize2(CONTROL_resume_s, 0, CONTROL_resume_s_length); + const f_string_static_t control_shutdown_s_length = macro_f_string_static_t_initialize2(CONTROL_shutdown_s, 0, CONTROL_shutdown_s_length); + const f_string_static_t control_start_s_length = macro_f_string_static_t_initialize2(CONTROL_start_s, 0, CONTROL_start_s_length); + const f_string_static_t control_stop_s_length = macro_f_string_static_t_initialize2(CONTROL_stop_s, 0, CONTROL_stop_s_length); + const f_string_static_t control_thaw_s_length = macro_f_string_static_t_initialize2(CONTROL_thaw_s, 0, CONTROL_thaw_s_length); +#endif // _di_control_strings_s_ - fl_print_format("%]%c%c%[Received signal code %]", main->warning.to.stream, main->context.set.reset, f_string_eol_s[0], f_string_eol_s[0], main->context.set.warning, main->context.set.warning); - fl_print_format("%[%i%]", main->warning.to.stream, main->context.set.notable, signal, main->context.set.notable); - fl_print_format("%[.%]%c", main->warning.to.stream, main->context.set.warning, main->context.set.warning, f_string_eol_s[0]); +#ifndef _di_control_data_delete_ + void control_data_delete(control_data_t * const data) { - funlockfile(main->warning.to.stream); + f_string_dynamic_resize(0, &data->cache.buffer_large); + f_string_dynamic_resize(0, &data->cache.buffer_small); } -#endif // _di_control_print_signal_received_ +#endif // _di_control_data_delete_ #ifndef _di_control_signal_received_ f_status_t control_signal_received(control_main_t * const main) { @@ -52,6 +75,33 @@ extern "C" { } #endif // _di_control_signal_received_ +#ifndef _di_control_signal_state_interrupt_fss_ + f_status_t control_signal_state_interrupt_fss(void *state, void *internal) { + + if (!state) { + return F_interrupt_not; + } + + f_state_t * const state_ptr = (f_state_t *) state; + + if (!state_ptr->custom) { + return F_interrupt_not; + } + + control_main_t * const main = (control_main_t *) state_ptr->custom; + + if (!((++main->signal_check) % control_signal_check_d)) { + if (control_signal_received(main)) { + return F_status_set_error(F_interrupt); + } + + main->signal_check = 0; + } + + return F_interrupt_not; + } +#endif // _di_control_signal_state_interrupt_fss_ + #ifdef __cplusplus } // extern "C" #endif diff --git a/level_3/control/c/private-common.h b/level_3/control/c/private-common.h index 7e0f7d4..197cbe8 100644 --- a/level_3/control/c/private-common.h +++ b/level_3/control/c/private-common.h @@ -13,16 +13,259 @@ extern "C" { #endif /** - * Print a message about a process signal being recieved, such as an interrupt signal. + * General defines used throughout the program. * - * @param main - * The main program data. - * @param signal - * The signal received. + * control_default_*: + * - buffer_limit_soft_large: The preferred maximum size of buffers intended for large data sets such that sizes exceeding this will be shrunk when operations are complete (aka: a soft limit). + * - buffer_limit_soft_small: The preferred maximum size of buffers intended for small data sets such that sizes exceeding this will be shrunk when operations are complete (aka: a soft limit). + * + * control_signal_*: + * - check: The interval in which callbacks checking signal should actually perform the signal check (significantly improves perfomance). + * + * control_allocation_*: + * - large: Default allocation buffer size for buffers expected to work with large data sets. + * - small: Default allocation buffer size for buffers expected to work with small data sets. + */ +#ifndef _di_control_defines_s_ + #define control_default_buffer_limit_soft_large_d 2048 + #define control_default_buffer_limit_soft_small_d 64 + + #define control_signal_check_d 10000 + + #define control_allocation_large_d 256 + #define control_allocation_small_d 16 +#endif // _di_control_defines_s_ + +/** + * Controller defines that the control program utilizes. + * + * These are intended to exactly match the relevant controller string defines. + */ +#ifndef _di_controller_strings_ + + // The name_socket is a system-specific path and should match the path compiled into the controller program. + #if defined(_override_controller_name_socket_) && defined(_override_controller_name_socket_length_) + #define CONTROLLER_name_socket_s _override_controller_name_socket_ + + #define CONTROLLER_name_socket_s_length _override_controller_name_socket_length_ + #else + #define CONTROLLER_name_socket_s "default" + + #define CONTROLLER_name_socket_s_length 7 + #endif // defined(_override_controller_name_socket_) && defined(_override_controller_name_socket_length_) + + // The path_socket is a system-specific path and should match the path compiled into the controller program. + #if defined(_override_controller_path_socket_) && defined(_override_controller_path_socket_length_) + #define CONTROLLER_path_socket_s _override_controller_path_socket_ + + #define CONTROLLER_path_socket_s_length _override_controller_path_socket_length_ + #elif defined(_controller_as_init_) + #define CONTROLLER_path_socket_s "/var/run/init" + + #define CONTROLLER_path_socket_s_length 13 + #else + #define CONTROLLER_path_socket_s "/var/run/controller" + + #define CONTROLLER_path_socket_s_length 19 + #endif // defined(_override_controller_path_socket_) && defined(_override_controller_path_socket_length_) + + // The name_socket_prefix is a system-specific path and should match the path compiled into the controller program. + #if defined(_override_controller_path_socket_prefix_) && defined(_override_controller_path_socket_prefix_length_) + #define CONTROLLER_path_socket_prefix_s _override_controller_path_socket_prefix_ + + #define CONTROLLER_path_socket_prefix_s_length _override_controller_path_socket_prefix_length_ + #elif defined(_controller_as_init_) + #define CONTROLLER_path_socket_prefix_s "init-" + + #define CONTROLLER_path_socket_prefix_s_length 5 + #else + #define CONTROLLER_path_socket_prefix_s "" + + #define CONTROLLER_path_socket_prefix_s_length 0 + #endif // defined(_override_controller_name_socket_prefix_) && defined(_override_controller_name_socket_prefix_length_) + + // The name_socket_suffix is a system-specific path and should match the path compiled into the controller program. + #if defined(_override_controller_path_socket_suffix_) && defined(_override_controller_path_socket_suffix_length_) + #define CONTROLLER_path_socket_suffix_s _override_controller_path_socket_suffix_ + + #define CONTROLLER_path_socket_suffix_s_length _override_controller_path_socket_suffix_length_ + #else + #define CONTROLLER_path_socket_suffix_s ".socket" + + #define CONTROLLER_path_socket_suffix_s_length 7 + #endif // defined(_override_controller_name_socket_suffix_) && defined(_override_controller_name_socket_suffix_length_) + + extern const f_string_static_t controller_name_socket_s; + extern const f_string_static_t controller_path_socket_s; + extern const f_string_static_t controller_path_socket_prefix_s; + extern const f_string_static_t controller_path_socket_suffix_s; +#endif // _di_controller_strings_ + +/** + * All special strings used within this program. + */ +#ifndef _di_control_strings_s_ + #if defined(_override_control_path_settings_) && defined(_override_control_path_settings_length_) + #define CONTROL_path_settings_s _override_control_path_settings_ + + #define CONTROL_path_settings_s_length _override_control_path_settings_length_ + #else + #define CONTROL_path_settings_s "/etc/control/settings" + + #define CONTROL_path_settings_s_length 21 + #endif // defined(_override_control_path_settings_) && defined(_override_control_path_settings_length_) + + #define CONTROL_command_s "command" + #define CONTROL_default_s "default" + #define CONTROL_name_socket_s "name_socket" + #define CONTROL_path_socket_s "path_socket" + #define CONTROL_path_socket_prefix_s "path_socket_prefix" + #define CONTROL_path_socket_suffix_s "path_socket_suffix" + + #define CONTROL_error_s "error" + #define CONTROL_freeze_s "freeze" + #define CONTROL_kill_s "kill" + #define CONTROL_pause_s "pause" + #define CONTROL_reboot_s "reboot" + #define CONTROL_reload_s "reload" + #define CONTROL_rerun_s "rerun" + #define CONTROL_restart_s "restart" + #define CONTROL_resume_s "resume" + #define CONTROL_shutdown_s "shutdown" + #define CONTROL_start_s "start" + #define CONTROL_stop_s "stop" + #define CONTROL_thaw_s "thaw" + + #define CONTROL_command_s_length 7 + #define CONTROL_default_s_length 7 + #define CONTROL_name_socket_s_length 11 + #define CONTROL_path_socket_s_length 11 + #define CONTROL_path_socket_prefix_s_length 18 + #define CONTROL_path_socket_suffix_s_length 18 + + #define CONTROL_error_s_length 5 + #define CONTROL_freeze_s_length 6 + #define CONTROL_kill_s_length 4 + #define CONTROL_pause_s_length 5 + #define CONTROL_reboot_s_length 6 + #define CONTROL_reload_s_length 6 + #define CONTROL_rerun_s_length 5 + #define CONTROL_restart_s_length 7 + #define CONTROL_resume_s_length 6 + #define CONTROL_shutdown_s_length 8 + #define CONTROL_start_s_length 5 + #define CONTROL_stop_s_length 4 + #define CONTROL_thaw_s_length 4 + + extern const f_string_static_t control_path_settings_s; + + extern const f_string_static_t control_command_s; + extern const f_string_static_t control_default_s; + extern const f_string_static_t control_name_socket_s; + extern const f_string_static_t control_path_socket_s; + extern const f_string_static_t control_path_socket_prefix_s; + extern const f_string_static_t control_path_socket_suffix_s; + + extern const f_string_static_t control_error_s_length; + extern const f_string_static_t control_freeze_s_length; + extern const f_string_static_t control_kill_s_length; + extern const f_string_static_t control_pause_s_length; + extern const f_string_static_t control_reboot_s_length; + extern const f_string_static_t control_reload_s_length; + extern const f_string_static_t control_rerun_s_length; + extern const f_string_static_t control_restart_s_length; + extern const f_string_static_t control_resume_s_length; + extern const f_string_static_t control_shutdown_s_length; + extern const f_string_static_t control_start_s_length; + extern const f_string_static_t control_stop_s_length; + extern const f_string_static_t control_thaw_s_length; +#endif // _di_control_strings_s_ + +/** + * Codes representing supported commands. + * + * freeze: Perform the freeze controller operation. + * kill: Perform the kill controller operation. + * pause: Perform the pause controller operation. + * reboot: Perform the reboot controller operation (only for init mode). + * reload: Perform the reload controller operation. + * rerun: Perform the rerun controller operation. + * restart: Perform the restart controller operation. + * resume: Perform the resume controller operation. + * shutdown: Perform the shutdown controller operation (only for init mode). + * start: Perform the start controller operation. + * stop: Perform the stop controller operation. + * thaw: Perform the thaw controller operation. + */ +#ifndef _di_control_command_types_ + enum { + control_command_type_freeze_e = 1, + control_command_type_kill_e, + control_command_type_pause_e, + control_command_type_reboot_e, + control_command_type_reload_e, + control_command_type_rerun_e, + control_command_type_restart_e, + control_command_type_resume_e, + control_command_type_shutdown_e, + control_command_type_start_e, + control_command_type_stop_e, + control_command_type_thaw_e, + }; +#endif // _di_control_command_types_ + +/** + * The control cache. + * + * buffer_large: A buffer for storing large sets of data. + * buffer_small: A buffer for storing small sets of data. + */ +#ifndef _di_control_cache_t_ + typedef struct { + f_string_dynamic_t buffer_large; + f_string_dynamic_t buffer_small; + } control_cache_t; + + #define control_cache_initialize \ + { \ + f_string_dynamic_t_initialize, \ + f_string_dynamic_t_initialize, \ + } +#endif // _di_control_cache_t_ + +/** + * The control data. + * + * command: The command type code. + * cache: A cache. + * socket: A socket used to connect to the controller. + */ +#ifndef _di_control_data_t_ + typedef struct { + uint8_t command; + + control_cache_t cache; + + f_socket_t socket; + } control_data_t; + + #define control_data_t_initialize \ + { \ + 0, \ + f_string_dynamic_t_initialize, \ + f_socket_t_initialize, \ + } +#endif // _di_control_data_t_ + +/** + * Deallocate the control data. + * + * @param data + * The control data. */ -#ifndef _di_control_print_signal_received_ - extern void control_print_signal_received(control_main_t * const main, const f_status_t signal) F_attribute_visibility_internal_d; -#endif // _di_control_print_signal_received_ +#ifndef _di_control_data_delete_ + extern void control_data_delete(control_data_t * const data) F_attribute_visibility_internal_d; +#endif // _di_control_data_delete_ /** * Check to see if a process signal is received. @@ -42,6 +285,23 @@ extern "C" { extern f_status_t control_signal_received(control_main_t * const main) F_attribute_visibility_internal_d; #endif // _di_control_signal_received_ +/** + * Callback passed to FSS functions for checking for interrupts. + * + * @param state + * The f_state_t data. + * @param internal + * Not used. + * + * @return + * F_interrupt_not if not interrupted. + * + * F_interrupt (with error bit) on receiving a terminate process signal, such as an interrupt signal. + */ +#ifndef _di_control_signal_state_interrupt_fss_ + extern f_status_t control_signal_state_interrupt_fss(void *state, void *internal) F_attribute_visibility_internal_d; +#endif // _di_control_signal_state_interrupt_fss_ + #ifdef __cplusplus } // extern "C" #endif diff --git a/level_3/control/c/private-control.c b/level_3/control/c/private-control.c index de582a8..bb21571 100644 --- a/level_3/control/c/private-control.c +++ b/level_3/control/c/private-control.c @@ -1,11 +1,449 @@ #include "control.h" #include "private-common.h" #include "private-control.h" +#include "private-print.h" #ifdef __cplusplus extern "C" { #endif +#ifndef _di_control_command_identify_ + f_status_t control_command_identify(control_main_t * const main, control_data_t * const data, const f_string_t command) { + + const f_array_length_t length = strnlen(command, f_console_parameter_size); + + if (fl_string_dynamic_compare_string(command, control_freeze_s_length, length) == F_equal_to) { + data->command = control_command_type_freeze_e; + + return F_found; + } + + if (fl_string_dynamic_compare_string(command, control_kill_s_length, length) == F_equal_to) { + data->command = control_command_type_kill_e; + + return F_found; + } + + if (fl_string_dynamic_compare_string(command, control_pause_s_length, length) == F_equal_to) { + data->command = control_command_type_pause_e; + + return F_found; + } + + if (fl_string_dynamic_compare_string(command, control_reboot_s_length, length) == F_equal_to) { + data->command = control_command_type_reboot_e; + + return F_found; + } + + if (fl_string_dynamic_compare_string(command, control_reload_s_length, length) == F_equal_to) { + data->command = control_command_type_reload_e; + + return F_found; + } + + if (fl_string_dynamic_compare_string(command, control_rerun_s_length, length) == F_equal_to) { + data->command = control_command_type_rerun_e; + + return F_found; + } + + if (fl_string_dynamic_compare_string(command, control_restart_s_length, length) == F_equal_to) { + data->command = control_command_type_restart_e; + + return F_found; + } + + if (fl_string_dynamic_compare_string(command, control_resume_s_length, length) == F_equal_to) { + data->command = control_command_type_resume_e; + + return F_found; + } + + if (fl_string_dynamic_compare_string(command, control_shutdown_s_length, length) == F_equal_to) { + data->command = control_command_type_shutdown_e; + + return F_found; + } + + if (fl_string_dynamic_compare_string(command, control_start_s_length, length) == F_equal_to) { + data->command = control_command_type_start_e; + + return F_found; + } + + if (fl_string_dynamic_compare_string(command, control_stop_s_length, length) == F_equal_to) { + data->command = control_command_type_stop_e; + + return F_found; + } + + if (fl_string_dynamic_compare_string(command, control_thaw_s_length, length) == F_equal_to) { + data->command = control_command_type_thaw_e; + + return F_found; + } + + return F_found_not; + } +#endif // _di_control_command_identify_ + +#ifndef _di_control_command_verify_ + f_status_t control_command_verify(control_main_t * const main, control_data_t * const data, const f_console_arguments_t *arguments) { + + switch (data->command) { + case control_command_type_freeze_e: + case control_command_type_kill_e: + case control_command_type_pause_e: + case control_command_type_reload_e: + case control_command_type_rerun_e: + case control_command_type_restart_e: + case control_command_type_resume_e: + case control_command_type_start_e: + case control_command_type_stop_e: + case control_command_type_thaw_e: + if (main->remaining.used < 2) { + control_print_error_parameter_command_rule_not(main, arguments->argv[0]); + + return F_status_set_error(F_parameter); + } + else if (main->remaining.used > 3) { + control_print_error_parameter_command_rule_too_many(main, arguments->argv[0]); + + return F_status_set_error(F_parameter); + } + + if (!strnlen(arguments->argv[main->remaining.array[1]], f_console_parameter_size)) { + if (main->remaining.used == 2) { + control_print_error_parameter_command_rule_empty(main, arguments->argv[0]); + } + else { + control_print_error_parameter_command_rule_directory_empty(main, arguments->argv[0]); + } + + return F_status_set_error(F_parameter); + } + + if (main->remaining.used == 3) { + if (!strnlen(arguments->argv[main->remaining.array[2]], f_console_parameter_size)) { + control_print_error_parameter_command_rule_basename_empty(main, arguments->argv[0]); + + return F_status_set_error(F_parameter); + } + } + + return F_none; + } + + if (data->command == control_command_type_reboot_e) { + // @todo + } + + if (data->command == control_command_type_shutdown_e) { + // @todo + } + + return F_none; + } +#endif // _di_control_command_verify_ + +#ifndef _di_control_settings_load_ + f_status_t control_settings_load(control_main_t * const main, control_data_t * const data, const f_console_arguments_t *arguments) { + + f_status_t status = F_none; + + data->cache.buffer_small.used = 0; + + if (main->parameters[control_parameter_socket_e].result == f_console_result_additional_e) { + const f_array_length_t location = main->parameters[control_parameter_settings_e].values.array[main->parameters[control_parameter_settings_e].values.used - 1]; + + status = f_string_append(arguments->argv[location], strnlen(arguments->argv[location], f_console_parameter_size), &data->cache.buffer_small); + } + else { + status = f_string_dynamic_append_nulless(control_path_settings_s, &data->cache.buffer_small); + } + + if (F_status_is_error(status)) { + if (main->parameters[control_parameter_socket_e].result == f_console_result_additional_e) { + fll_error_print(main->error, F_status_set_fine(status), "f_string_append", F_true); + } + else { + fll_error_print(main->error, F_status_set_fine(status), "f_string_dynamic_append_nulless", F_true); + } + + return status; + } + + { + f_file_t file = f_file_t_initialize; + + status = f_file_stream_open(data->cache.buffer_small.string, f_file_open_mode_read_s, &file); + + if (F_status_is_error(status)) { + fll_error_file_print(main->error, F_status_set_fine(status), "f_file_stream_open", F_true, data->cache.buffer_small.string, "open", fll_error_file_type_file_e); + + return status; + } + + status = f_file_stream_read(file, &data->cache.buffer_large); + + f_file_stream_close(F_true, &file); + + if (F_status_is_error(status)) { + fll_error_file_print(main->error, F_status_set_fine(status), "f_file_stream_read", F_true, data->cache.buffer_small.string, "read", fll_error_file_type_file_e); + + return status; + } + } + + f_state_t state = f_state_t_initialize; + f_string_range_t range = f_string_range_t_initialize; + f_fss_objects_t objects = f_fss_objects_t_initialize; + f_fss_contents_t contents = f_fss_contents_t_initialize; + f_fss_delimits_t delimits = f_fss_delimits_t_initialize; + + status = fll_fss_extended_read(data->cache.buffer_large, state, &range, &objects, &contents, 0, 0, &delimits, 0); + + if (F_status_is_error(status)) { + fll_error_file_print(main->error, F_status_set_fine(status), "fll_fss_extended_read", F_true, data->cache.buffer_small.string, "process", fll_error_file_type_file_e); + } + else { + status = fl_fss_apply_delimit(delimits, &data->cache.buffer_large); + + if (F_status_is_error(status)) { + fll_error_file_print(main->error, F_status_set_fine(status), "fl_fss_apply_delimit", F_true, data->cache.buffer_small.string, "process", fll_error_file_type_file_e); + } + } + + if (F_status_is_error_not(status)) { + uint8_t parameter_hass[] = { 0, 0, 0, 0 }; + + f_array_length_t parameter_ats[] = { 0, 0, 0, 0 }; + + { + const f_string_static_t parameter_names[] = { + control_name_socket_s, + control_path_socket_s, + control_path_socket_prefix_s, + control_path_socket_suffix_s, + }; + + f_array_length_t i = 0; + uint8_t j = 0; + f_string_range_t range = f_string_range_t_initialize; + + for (; i < objects.used; ++i) { + + for (j = 0; j < 4; ++j) { + + range.stop = parameter_names[j].used - 1; + + if (fl_string_dynamic_partial_compare(parameter_names[j], data->cache.buffer_large, range, objects.array[i]) == F_equal_to) { + parameter_hass[j] = F_true; + parameter_ats[j] = i; + + break; + } + } // for + } // for + } + + data->cache.buffer_small.used = 0; + + if (main->parameters[control_parameter_socket_e].result == f_console_result_additional_e) { + const f_array_length_t location = main->parameters[control_parameter_socket_e].values.array[main->parameters[control_parameter_socket_e].values.used - 1]; + + status = f_string_append(arguments->argv[location], strnlen(arguments->argv[location], f_console_parameter_size), &data->cache.buffer_small); + } + else if (parameter_hass[1]) { + status = f_string_dynamic_partial_append_nulless(data->cache.buffer_large, objects.array[parameter_ats[1]], &data->cache.buffer_small); + } + else { + status = f_string_dynamic_append_nulless(controller_path_socket_s, &data->cache.buffer_small); + } + + if (F_status_is_error(status)) { + if (main->parameters[control_parameter_socket_e].result == f_console_result_additional_e) { + fll_error_print(main->error, F_status_set_fine(status), "f_string_append", F_true); + } + else if (parameter_hass[1]) { + fll_error_print(main->error, F_status_set_fine(status), "f_string_dynamic_partial_append_nulless", F_true); + } + else { + fll_error_print(main->error, F_status_set_fine(status), "f_string_dynamic_append_nulless", F_true); + } + } + else { + status = f_string_dynamic_terminate_after(&data->cache.buffer_small); + + if (F_status_is_error(status)) { + fll_error_print(main->error, F_status_set_fine(status), "f_string_dynamic_terminate_after", F_true); + } + } + + status = f_file_exists(data->cache.buffer_small.string); + + if (F_status_is_error(status) || status == F_false) { + if (F_status_is_error(status)) { + fll_error_file_print(main->error, F_status_set_fine(status), "f_file_exists", F_true, data->cache.buffer_small.string, "find", fll_error_file_type_directory_e); + + if (main->error.verbosity != f_console_verbosity_quiet_e) { + fll_print_terminated(f_string_eol_s, main->error.to.stream); + } + } + + control_print_error_socket_file_missing(main, data->cache.buffer_small); + + status = F_status_set_error(F_socket_not); + } + + // Construct the file name when the socket path is a directory. + else if (f_file_is(data->cache.buffer_small.string, F_file_type_directory_d, F_true) == F_true) { + status = f_string_append_assure(f_path_separator_s, F_path_separator_s_length, &data->cache.buffer_small); + + if (F_status_is_error(status)) { + fll_error_print(main->error, F_status_set_fine(status), "f_string_append_assure", F_true); + } + else { + uint8_t append_ids[] = { + 0, + control_parameter_name_e, + 0, + }; + + uint8_t append_hass[] = { + parameter_hass[2], + parameter_hass[0], + parameter_hass[3], + }; + + const f_string_static_t append_defaults[] = { + controller_path_socket_prefix_s, + controller_name_socket_s, + controller_path_socket_suffix_s, + }; + + for (uint8_t i = 0; i < 3; ++i) { + + if (append_ids[i] && main->parameters[append_ids[i]].result == f_console_result_additional_e) { + const f_array_length_t location = main->parameters[append_ids[i]].values.array[main->parameters[append_ids[i]].values.used - 1]; + + status = f_string_append(arguments->argv[location], strnlen(arguments->argv[location], f_console_parameter_size), &data->cache.buffer_small); + } + else if (append_hass[i]) { + status = f_string_dynamic_partial_append_nulless(data->cache.buffer_large, objects.array[append_hass[i]], &data->cache.buffer_small); + } + else { + status = f_string_dynamic_append_nulless(append_defaults[i], &data->cache.buffer_small); + } + + if (F_status_is_error(status)) { + if (append_ids[i] && main->parameters[append_ids[i]].result == f_console_result_additional_e) { + fll_error_print(main->error, F_status_set_fine(status), "f_string_append", F_true); + } + else if (append_hass[i]) { + fll_error_print(main->error, F_status_set_fine(status), "f_string_dynamic_partial_append_nulless", F_true); + } + else { + fll_error_print(main->error, F_status_set_fine(status), "f_string_dynamic_append_nulless", F_true); + } + + break; + } + } // for + + if (F_status_is_error_not(status)) { + status = f_string_dynamic_terminate_after(&data->cache.buffer_small); + + if (F_status_is_error(status)) { + fll_error_print(main->error, F_status_set_fine(status), "f_string_dynamic_terminate_after", F_true); + } + } + + if (F_status_is_error_not(status)) { + status = f_file_exists(data->cache.buffer_small.string); + + if (F_status_is_error(status) || status == F_false) { + if (F_status_is_error(status)) { + fll_error_file_print(main->error, F_status_set_fine(status), "f_file_exists", F_true, data->cache.buffer_small.string, "find", fll_error_file_type_directory_e); + + if (main->error.verbosity != f_console_verbosity_quiet_e) { + fll_print_terminated(f_string_eol_s, main->error.to.stream); + } + } + + control_print_error_socket_file_missing(main, data->cache.buffer_small); + + status = F_status_set_error(F_socket_not); + } + } + + if (F_status_is_error_not(status)) { + if (f_file_is(data->cache.buffer_small.string, F_file_type_socket_d, F_true) == F_false) { + control_print_error_socket_file_not(main, data->cache.buffer_small); + + status = F_status_set_error(F_socket_not); + } + } + + if (F_status_is_error_not(status)) { + status = f_socket_create(&data->socket); + + if (F_status_is_error(status)) { + fll_error_print(main->error, F_status_set_fine(status), "f_socket_create", F_true); + + if (main->error.verbosity != f_console_verbosity_quiet_e) { + fll_print_terminated(f_string_eol_s, main->error.to.stream); + } + + control_print_error_socket_file_failed(main, data->cache.buffer_small); + } + } + + if (F_status_is_error_not(status)) { + status = f_socket_connect(data->socket); + + if (F_status_is_error(status)) { + fll_error_print(main->error, F_status_set_fine(status), "f_socket_connect", F_true); + + if (main->error.verbosity != f_console_verbosity_quiet_e) { + fll_print_terminated(f_string_eol_s, main->error.to.stream); + } + + control_print_error_socket_file_failed(main, data->cache.buffer_small); + } + } + } + } + } + + f_string_ranges_resize(0, &objects); + f_string_rangess_resize(0, &contents); + f_type_array_lengths_resize(0, &delimits); + + data->cache.buffer_large.used = 0; + data->cache.buffer_small.used = 0; + + if (F_status_is_error_not(status)) { + if (data->cache.buffer_large.size > control_default_buffer_limit_soft_large_d) { + status = f_string_dynamic_resize(control_default_buffer_limit_soft_large_d, &data->cache.buffer_large); + } + + if (F_status_is_error_not(status)) { + if (data->cache.buffer_small.size > control_default_buffer_limit_soft_small_d) { + status = f_string_dynamic_resize(control_default_buffer_limit_soft_small_d, &data->cache.buffer_small); + } + } + } + + if (F_status_is_error(status)) { + return status; + } + + return F_none; + } +#endif // _di_control_settings_load_ + #ifdef __cplusplus } // extern "C" #endif diff --git a/level_3/control/c/private-control.h b/level_3/control/c/private-control.h index 241760d..0398212 100644 --- a/level_3/control/c/private-control.h +++ b/level_3/control/c/private-control.h @@ -12,6 +12,88 @@ extern "C" { #endif + +/** + * Identify the command code the given name represents. + * + * @param main + * The main program data. + * @param data + * The control data. + * @param command + * The parameter representing a command. + * + * @return + * F_found on success. + * F_found_not if name is unknown. + */ +#ifndef _di_control_command_identify_ + extern f_status_t control_command_identify(control_main_t * const main, control_data_t * const data, const f_string_t command) F_attribute_visibility_internal_d; +#endif // _di_control_command_identify_ + +/** + * Verify that the additional parameters are reasonably correct for the identified command. + * + * @param main + * The main program data. + * @param data + * The control data. + * @param arguments + * The main program arguments. + */ +#ifndef _di_control_command_verify_ + extern f_status_t control_command_verify(control_main_t * const main, control_data_t * const data, const f_console_arguments_t *arguments) F_attribute_visibility_internal_d; +#endif // _di_control_command_verify_ +/** + * Load and process the control settings file. + * + * This identifies and attempts to connect to the socket. + * + * @param main + * The main program data. + * @param data + * The control data. + * @param arguments + * The main program arguments. + * + * @return + * F_none on success. + * + * F_interrupt (with error bit) on receiving a terminate process signal, such as an interrupt signal. + * F_socket_not (with error bit) on socket related error preventing the socket from being created or connected to. + * + * Errors (with error bit) from: f_file_exists(). + * Errors (with error bit) from: f_file_open(). + * Errors (with error bit) from: f_file_stream_read(). + * Errors (with error bit) from: f_socket_connect(). + * Errors (with error bit) from: f_socket_create(). + * Errors (with error bit) from: f_string_append(). + * Errors (with error bit) from: f_string_append_assure(). + * Errors (with error bit) from: f_string_dynamic_append_nulless(). + * Errors (with error bit) from: f_string_dynamic_partial_append_nulless(). + * Errors (with error bit) from: f_string_dynamic_terminate_after(). + * Errors (with error bit) from: f_string_dynamics_resize(). + * Errors (with error bit) from: fl_fss_apply_delimit(). + * Errors (with error bit) from: fll_fss_extended_read(). + * + * @see f_file_exists() + * @see f_file_open() + * @see f_file_stream_read() + * @see f_socket_connect() + * @see f_socket_create() + * @see f_string_append() + * @see f_string_append_assure() + * @see f_string_dynamic_append_nulless() + * @see f_string_dynamic_partial_append_nulless() + * @see f_string_dynamic_terminate_after() + * @see f_string_dynamics_resize() + * @see fl_fss_apply_delimit() + * @see fll_fss_extended_read() + */ +#ifndef _di_control_settings_load_ + extern f_status_t control_settings_load(control_main_t * const main, control_data_t * const data, const f_console_arguments_t *arguments) F_attribute_visibility_internal_d; +#endif // _di_control_settings_load_ + #ifdef __cplusplus } // extern "C" #endif diff --git a/level_3/control/c/private-print.c b/level_3/control/c/private-print.c new file mode 100644 index 0000000..ab75ed7 --- /dev/null +++ b/level_3/control/c/private-print.c @@ -0,0 +1,212 @@ +#include "control.h" +#include "private-common.h" +#include "private-print.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_control_print_error_parameter_command_not_ + void control_print_error_parameter_command_not(control_main_t * const main, const f_string_t command) { + + if (main->error.verbosity == f_console_verbosity_quiet_e) return; + + flockfile(main->error.to.stream); + + fl_print_format("%[%SThe parameter '%]", main->error.to.stream, main->context.set.error, main->error.prefix, main->context.set.error); + fl_print_format("%[%S%]", main->error.to.stream, main->context.set.notable, command, main->context.set.notable); + fl_print_format("%[' is not a known controller command.%]%c", main->error.to.stream, main->context.set.error, main->context.set.error, f_string_eol_s[0]); + + funlockfile(main->error.to.stream); + } +#endif // _di_control_print_error_parameter_command_not_ + +#ifndef _di_control_print_error_parameter_command_rule_basename_empty_ + void control_print_error_parameter_command_rule_basename_empty(control_main_t * const main, const f_string_t command) { + + if (main->error.verbosity == f_console_verbosity_quiet_e) return; + + flockfile(main->error.to.stream); + + fl_print_format("%[%SThe command parameter '%]", main->error.to.stream, main->context.set.error, main->error.prefix, main->context.set.error); + fl_print_format("%[%S%]", main->error.to.stream, main->context.set.notable, command, main->context.set.notable); + fl_print_format("%[' a rule base name cannot be an empty string.%]%c", main->error.to.stream, main->context.set.error, main->context.set.error, f_string_eol_s[0]); + + funlockfile(main->error.to.stream); + } +#endif // _di_control_print_error_parameter_command_rule_basename_empty_ + +#ifndef _di_control_print_error_parameter_command_rule_directory_empty_ + void control_print_error_parameter_command_rule_directory_empty(control_main_t * const main, const f_string_t command) { + + if (main->error.verbosity == f_console_verbosity_quiet_e) return; + + flockfile(main->error.to.stream); + + fl_print_format("%[%SThe command parameter '%]", main->error.to.stream, main->context.set.error, main->error.prefix, main->context.set.error); + fl_print_format("%[%S%]", main->error.to.stream, main->context.set.notable, command, main->context.set.notable); + fl_print_format("%[' a rule directory path cannot be an empty string.%]%c", main->error.to.stream, main->context.set.error, main->context.set.error, f_string_eol_s[0]); + + funlockfile(main->error.to.stream); + } +#endif // _di_control_print_error_parameter_command_rule_directory_empty_ + +#ifndef _di_control_print_error_parameter_command_rule_empty_ + void control_print_error_parameter_command_rule_empty(control_main_t * const main, const f_string_t command) { + + if (main->error.verbosity == f_console_verbosity_quiet_e) return; + + flockfile(main->error.to.stream); + + fl_print_format("%[%SThe command parameter '%]", main->error.to.stream, main->context.set.error, main->error.prefix, main->context.set.error); + fl_print_format("%[%S%]", main->error.to.stream, main->context.set.notable, command, main->context.set.notable); + fl_print_format("%[' a rule name cannot be an empty string.%]%c", main->error.to.stream, main->context.set.error, main->context.set.error, f_string_eol_s[0]); + + funlockfile(main->error.to.stream); + } +#endif // _di_control_print_error_parameter_command_rule_empty_ + +#ifndef _di_control_print_error_parameter_command_rule_not_ + void control_print_error_parameter_command_rule_not(control_main_t * const main, const f_string_t command) { + + if (main->error.verbosity == f_console_verbosity_quiet_e) return; + + flockfile(main->error.to.stream); + + fl_print_format("%[%SThe command parameter '%]", main->error.to.stream, main->context.set.error, main->error.prefix, main->context.set.error); + fl_print_format("%[%S%]", main->error.to.stream, main->context.set.notable, command, main->context.set.notable); + fl_print_format("%[' requires either a full rule name or a rule directory path along with the rule base name.%]%c", main->error.to.stream, main->context.set.error, main->context.set.error, f_string_eol_s[0]); + + funlockfile(main->error.to.stream); + } +#endif // _di_control_print_error_parameter_command_rule_not_ + +#ifndef _di_control_print_error_parameter_command_rule_too_many_ + void control_print_error_parameter_command_rule_too_many(control_main_t * const main, const f_string_t command) { + + if (main->error.verbosity == f_console_verbosity_quiet_e) return; + + flockfile(main->error.to.stream); + + fl_print_format("%[%SThe command parameter '%]", main->error.to.stream, main->context.set.error, main->error.prefix, main->context.set.error); + fl_print_format("%[%S%]", main->error.to.stream, main->context.set.notable, command, main->context.set.notable); + fl_print_format("%[' has too many arguments.%]%c", main->error.to.stream, main->context.set.error, main->context.set.error, f_string_eol_s[0]); + + funlockfile(main->error.to.stream); + } +#endif // _di_control_print_error_parameter_command_rule_too_many_ + +#ifndef _di_control_print_error_commands_none_ + void control_print_error_commands_none(control_main_t * const main) { + + if (main->error.verbosity == f_console_verbosity_quiet_e) return; + + fll_print_format("%[%SNo commands are provided.%]%c", main->error.to.stream, main->context.set.error, main->error.prefix, main->context.set.error, f_string_eol_s[0]); + } +#endif // _di_control_print_error_commands_none_ + +#ifndef _di_control_print_error_parameter_value_empty_ + void control_print_error_parameter_value_empty(control_main_t * const main, const f_string_static_t parameter) { + + if (main->error.verbosity == f_console_verbosity_quiet_e) return; + + flockfile(main->error.to.stream); + + fl_print_format("%[%SThe value for the parameter '%]", main->error.to.stream, main->context.set.error, main->error.prefix, main->context.set.error); + fl_print_format("%[%s%q%]", main->error.to.stream, main->context.set.notable, f_console_symbol_long_enable_s, parameter, main->context.set.notable); + fl_print_format("%[' must not be an empty string.%]%c", main->error.to.stream, main->context.set.error, main->context.set.error, f_string_eol_s[0]); + + funlockfile(main->error.to.stream); + } +#endif // _di_control_print_error_parameter_value_empty_ + +#ifndef _di_control_print_error_parameter_value_not_ + void control_print_error_parameter_value_not(control_main_t * const main, const f_string_static_t parameter) { + + if (main->error.verbosity == f_console_verbosity_quiet_e) return; + + flockfile(main->error.to.stream); + + fl_print_format("%[%SThe parameter '%]", main->error.to.stream, main->context.set.error, main->error.prefix, main->context.set.error); + fl_print_format("%[%s%q%]", main->error.to.stream, main->context.set.notable, f_console_symbol_long_enable_s, parameter, main->context.set.notable); + fl_print_format("%[' is specified, but no value is given.%]%c", main->error.to.stream, main->context.set.error, main->context.set.error, f_string_eol_s[0]); + + funlockfile(main->error.to.stream); + } +#endif // _di_control_print_error_parameter_value_not_ + +#ifndef _di_control_print_error_pipe_supported_not_ + void control_print_error_pipe_supported_not(control_main_t * const main) { + + if (main->error.verbosity == f_console_verbosity_quiet_e) return; + + fll_print_format("%[%SPipe input is not supported by this program.%]%c", main->error.to.stream, main->context.set.error, main->error.prefix, main->context.set.error, f_string_eol_s[0]); + } +#endif // _di_control_print_error_pipe_supported_not_ + +#ifndef _di_control_print_error_socket_file_failed_ + void control_print_error_socket_file_failed(control_main_t * const main, const f_string_static_t path_socket) { + + if (main->error.verbosity == f_console_verbosity_quiet_e) return; + + flockfile(main->error.to.stream); + + fl_print_format("%[%SFailed to connect to the socket file '%]", main->error.to.stream, main->context.set.error, main->error.prefix, main->context.set.error); + fl_print_format("%[%Q%]", main->error.to.stream, main->context.set.notable, path_socket, main->context.set.notable); + fl_print_format("%['.%]%c", main->error.to.stream, main->context.set.error, main->context.set.error, f_string_eol_s[0]); + + funlockfile(main->error.to.stream); + } +#endif // _di_control_print_error_socket_file_failed_ + +#ifndef _di_control_print_error_socket_file_missing_ + void control_print_error_socket_file_missing(control_main_t * const main, const f_string_static_t path_socket) { + + if (main->error.verbosity == f_console_verbosity_quiet_e) return; + + flockfile(main->error.to.stream); + + fl_print_format("%[%SThe controller socket file '%]", main->error.to.stream, main->context.set.error, main->error.prefix, main->context.set.error); + fl_print_format("%[%Q%]", main->error.to.stream, main->context.set.notable, path_socket, main->context.set.notable); + fl_print_format("%[' could not be found and is required.%]%c", main->error.to.stream, main->context.set.error, main->context.set.error, f_string_eol_s[0]); + + funlockfile(main->error.to.stream); + } +#endif // _di_control_print_error_socket_file_missing_ + +#ifndef _di_control_print_error_socket_file_not_ + void control_print_error_socket_file_not(control_main_t * const main, const f_string_static_t path_socket) { + + if (main->error.verbosity == f_console_verbosity_quiet_e) return; + + flockfile(main->error.to.stream); + + fl_print_format("%[%SThe controller socket file '%]", main->error.to.stream, main->context.set.error, main->error.prefix, main->context.set.error); + fl_print_format("%[%Q%]", main->error.to.stream, main->context.set.notable, path_socket, main->context.set.notable); + fl_print_format("%[' is not a socket file.%]%c", main->error.to.stream, main->context.set.error, main->context.set.error, f_string_eol_s[0]); + + funlockfile(main->error.to.stream); + } +#endif // _di_control_print_error_socket_file_not_ + +#ifndef _di_control_print_signal_received_ + void control_print_signal_received(control_main_t * const main, const f_status_t signal) { + + if (main->warning.verbosity != f_console_verbosity_verbose_e) return; + + // Must flush and reset color because the interrupt may have interrupted the middle of a print function. + fflush(main->warning.to.stream); + + flockfile(main->warning.to.stream); + + fl_print_format("%]%c%c%[Received signal code %]", main->warning.to.stream, main->context.set.reset, f_string_eol_s[0], f_string_eol_s[0], main->context.set.warning, main->context.set.warning); + fl_print_format("%[%i%]", main->warning.to.stream, main->context.set.notable, signal, main->context.set.notable); + fl_print_format("%[.%]%c", main->warning.to.stream, main->context.set.warning, main->context.set.warning, f_string_eol_s[0]); + + funlockfile(main->warning.to.stream); + } +#endif // _di_control_print_signal_received_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/level_3/control/c/private-print.h b/level_3/control/c/private-print.h new file mode 100644 index 0000000..a74ec61 --- /dev/null +++ b/level_3/control/c/private-print.h @@ -0,0 +1,183 @@ +/** + * FLL - Level 3 + * + * Project: Control + * API Version: 0.5 + * Licenses: lgpl-2.1-or-later + */ +#ifndef _PRIVATE_control_print_h +#define _PRIVATE_control_print_h + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Print an error message about the given parameter not matching the known set of controller commands. + * + * @param main + * The main program data. + * @param command + * The parameter representing a command. + */ +#ifndef _di_control_print_error_parameter_command_not_ + extern void control_print_error_parameter_command_not(control_main_t * const main, const f_string_t command) F_attribute_visibility_internal_d; +#endif // _di_control_print_error_parameter_command_not_ + +/** + * Print an error message about the given parameter being a rule command having an empty rule basename. + * + * @param main + * The main program data. + * @param command + * The parameter representing a command. + */ +#ifndef _di_control_print_error_parameter_command_rule_basename_empty_ + extern void control_print_error_parameter_command_rule_basename_empty(control_main_t * const main, const f_string_t command) F_attribute_visibility_internal_d; +#endif // _di_control_print_error_parameter_command_rule_basename_empty_ + +/** + * Print an error message about the given parameter being a rule command having an empty rule directory path. + * + * @param main + * The main program data. + * @param command + * The parameter representing a command. + */ +#ifndef _di_control_print_error_parameter_command_rule_directory_empty_ + extern void control_print_error_parameter_command_rule_directory_empty(control_main_t * const main, const f_string_t command) F_attribute_visibility_internal_d; +#endif // _di_control_print_error_parameter_command_rule_directory_empty_ + +/** + * Print an error message about the given parameter being a rule command having an empty rule name. + * + * @param main + * The main program data. + * @param command + * The parameter representing a command. + */ +#ifndef _di_control_print_error_parameter_command_rule_empty_ + extern void control_print_error_parameter_command_rule_empty(control_main_t * const main, const f_string_t command) F_attribute_visibility_internal_d; +#endif // _di_control_print_error_parameter_command_rule_empty_ + +/** + * Print an error message about the given parameter being a rule command but no rule name is specified. + * + * @param main + * The main program data. + * @param command + * The parameter representing a command. + */ +#ifndef _di_control_print_error_parameter_command_rule_not_ + extern void control_print_error_parameter_command_rule_not(control_main_t * const main, const f_string_t command) F_attribute_visibility_internal_d; +#endif // _di_control_print_error_parameter_command_rule_not_ + +/** + * Print an error message about the given parameter being a rule command having too many arguments passed. + * + * @param main + * The main program data. + * @param command + * The parameter representing a command. + */ +#ifndef _di_control_print_error_parameter_command_rule_too_many_ + extern void control_print_error_parameter_command_rule_too_many(control_main_t * const main, const f_string_t command) F_attribute_visibility_internal_d; +#endif // _di_control_print_error_parameter_command_rule_too_many_ + +/** + * Print an error message about no commands being provided. + * + * @param main + * The main program data. + */ +#ifndef _di_control_print_error_commands_none_ + extern void control_print_error_commands_none(control_main_t * const main) F_attribute_visibility_internal_d; +#endif // _di_control_print_error_commands_none_ + +/** + * Print an error message about the parameter's associated value being an empty string. + * + * @param main + * The main program data. + * @param parameter + * The parameter name. + */ +#ifndef _di_control_print_error_parameter_value_empty_ + extern void control_print_error_parameter_value_empty(control_main_t * const main, const f_string_static_t parameter) F_attribute_visibility_internal_d; +#endif // _di_control_print_error_parameter_value_empty_ + +/** + * Print an error message about the parameter missings its associated value. + * + * @param main + * The main program data. + * @param parameter + * The parameter name. + */ +#ifndef _di_control_print_error_parameter_value_not_ + extern void control_print_error_parameter_value_not(control_main_t * const main, const f_string_static_t parameter) F_attribute_visibility_internal_d; +#endif // _di_control_print_error_parameter_value_not_ + +/** + * Print an error message about a pipe input being unsupported. + * + * @param main + * The main program data. + */ +#ifndef _di_control_print_error_pipe_supported_not_ + extern void control_print_error_pipe_supported_not(control_main_t * const main) F_attribute_visibility_internal_d; +#endif // _di_control_print_error_pipe_supported_not_ + +/** + * Print an error message about failure to connect to the socket file. + * + * @param main + * The main program data. + * @param path_socket + * The socket file path. + */ +#ifndef _di_control_print_error_socket_file_failed_ + extern void control_print_error_socket_file_failed(control_main_t * const main, const f_string_static_t path_socket) F_attribute_visibility_internal_d; +#endif // _di_control_print_error_socket_file_failed_ + +/** + * Print an error message about the socket file not being found. + * + * @param main + * The main program data. + * @param path_socket + * The socket file path. + */ +#ifndef _di_control_print_error_socket_file_missing_ + extern void control_print_error_socket_file_missing(control_main_t * const main, const f_string_static_t path_socket) F_attribute_visibility_internal_d; +#endif // _di_control_print_error_socket_file_missing_ + +/** + * Print an error message about the socket file not actually being a socket file. + * + * @param main + * The main program data. + * @param path_socket + * The socket file path. + */ +#ifndef _di_control_print_error_socket_file_not_ + extern void control_print_error_socket_file_not(control_main_t * const main, const f_string_static_t path_socket) F_attribute_visibility_internal_d; +#endif // _di_control_print_error_socket_file_not_ + +/** + * Print a message about a process signal being recieved, such as an interrupt signal. + * + * @param main + * The main program data. + * @param signal + * The signal received. + */ +#ifndef _di_control_print_signal_received_ + extern void control_print_signal_received(control_main_t * const main, const f_status_t signal) F_attribute_visibility_internal_d; +#endif // _di_control_print_signal_received_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _PRIVATE_control_print_h diff --git a/level_3/control/data/build/defines b/level_3/control/data/build/defines index 0aedddb..d44a0de 100644 --- a/level_3/control/data/build/defines +++ b/level_3/control/data/build/defines @@ -1,4 +1,14 @@ # fss-0000 -_di_libcap_ Disable libcap support, allow for compiling and linking without libcap (-lcap). -_libcap_legacy_only_ Disable functionality provided by later versions of libcap (2.43 and later). +_controller_as_init_ The controller program is compiled as an init replacement and this control program should treat it as such. +_override_controller_name_socket_ Use this as the default custom file name representing the controller program socket. +_override_controller_name_socket_length_ The number of bytes representing the string in _override_controller_name_socket_ (not including the terminating NULL). +_override_controller_path_socket_ Use this as the default custom directory path representing the location of the controller program socket. +_override_controller_path_socket_length_ The number of bytes representing the string in _override_controller_path_socket_ (not including the terminating NULL). +_override_controller_path_socket_prefix_ Use this as the default custom prefix prepended to the file name of the file representing the controller program socket. +_override_controller_path_socket_prefix_length_ The number of bytes representing the string in _override_controller_path_socket_prefix_ (not including the terminating NULL). +_override_controller_path_socket_suffix_ Use this as the default custom prefix prepended to the file name of the file representing the controller program socket. +_override_controller_path_socket_suffix_length_ The number of bytes representing the string in _override_controller_path_socket_suffix_ (not including the terminating NULL). +_override_control_path_settings_ Use this as the default full path to the controlsettings. +_override_control_path_settings_length_ The number of bytes representing the string in _override_controller_path_settings_length_ (not including the terminating NULL). +_pthread_sigqueue_unsupported_ Disable GNU specific sigqueue(). diff --git a/level_3/control/data/build/dependencies b/level_3/control/data/build/dependencies index 7eeec9a..dca69a2 100644 --- a/level_3/control/data/build/dependencies +++ b/level_3/control/data/build/dependencies @@ -8,12 +8,16 @@ f_utf f_color f_console f_file +f_fss f_pipe f_print f_signal +f_socket fl_console +fl_fss fl_print fl_string fll_error +fll_fss fll_print fll_program diff --git a/level_3/control/data/build/settings b/level_3/control/data/build/settings index a22ce79..b0a31c6 100644 --- a/level_3/control/data/build/settings +++ b/level_3/control/data/build/settings @@ -21,12 +21,12 @@ build_indexer ar build_indexer_arguments rcs build_language c build_libraries -lc -build_libraries-individual -lfll_error -lfll_print -lfll_program -lfl_console -lfl_print -lfl_string -lf_color -lf_console -lf_conversion -lf_file -lf_memory -lf_path -lf_pipe -lf_print -lf_signal -lf_string -lf_type_array -lf_utf +build_libraries-individual -lfll_error -lfll_fss -lfll_print -lfll_program -lfl_console -lfl_conversion -lfl_fss -lfl_print -lfl_string -lf_color -lf_console -lf_conversion -lf_file -lf_fss -lf_memory -lf_path -lf_pipe -lf_print -lf_signal -lf_socket -lf_status_string -lf_string -lf_type_array -lf_utf build_libraries-level -lfll_2 -lfll_1 -lfll_0 build_libraries-monolithic -lfll build_libraries_shared build_libraries_static -build_sources_library control.c private-common.c private-control.c +build_sources_library control.c private-common.c private-control.c private-print.c build_sources_library_shared build_sources_library_static build_sources_program main.c diff --git a/level_3/control/data/settings/settings b/level_3/control/data/settings/settings new file mode 100644 index 0000000..c2697e8 --- /dev/null +++ b/level_3/control/data/settings/settings @@ -0,0 +1,6 @@ +# fss-0001 + +name_socket default +path_socket /var/run/controller +path_socket_prefix controller- +path_socket_suffix .socket diff --git a/level_3/control/documents/settings.txt b/level_3/control/documents/settings.txt new file mode 100644 index 0000000..6a745b2 --- /dev/null +++ b/level_3/control/documents/settings.txt @@ -0,0 +1,61 @@ +# fss-0002 + +Settings Documentation: + This describes intent and purposes of the control settings file. + + The settings file provides default or system-wide settings. + The system-wide settings file is loaded by default but a custom settings file may be alternatively specified. + Using this avoids the need to add additional paramters to the command line when calling the control program. + + When this file is not specified any hardcoded defaults compiled into the program are used. + + The location of the settings file is compile time specific and should be changed depending on the particular design of the system. + The default path for the control settings file is something like "/etc/control/settings". + + - name_socket\: + This represents the file name used to construct the full socket path. + The file name represents the name of the file but any file extensions, such as ".suffix", should likely use "path_socket_suffix" to specify the file extension. + + When not defined the compiled in default is used. + The default socket path directory is generally "default" but this could be changed during compile time. + + This is required to not be empty so when the Object "path_socket" is defined without any Content, then an error is expected to be thrown. + + This is used along with the "path_socket", "path_socket_prefix", and the "path_socket_suffix" to construct the socket file. + + - path_socket\: + This represents the directory path to the socket file provided by the controller or init service. + This directory path is separate from the file name part so that the name can be more dynamically constructed without having to specify a full directory path each time. + + When not defined the compiled in default is used. + The default socket path directory is generally "/var/run/controller" but this could be changed during compile time. + + When the Object "path_socket" is defined without any Content, then no path is added (resulting in the socket relative to the callers current working directory). + + This is used along with the "path_socket_prefix", the "path_socket_suffix", and the "name_socket" to construct the socket file. + A full socket path might look something like "/var/run/controller/controller-default.socket". + + It is common for the controller program to be compiled as an init program. + In this case it may be common for the full socket path to instead be something more like "/var/run/init/init-default.socket". + + - path_socket_prefix\: + This represents a prefix used to construct the full socket path. + This prefix is prepended to the socket file name. + + When not defined the compiled in default is used. + The default path prefix is generally "controller-" but this could be changed during compile time. + + When the Object "path_socket_prefix" is defined without any Content, then no prefix is prepended. + + This is used along with the "path_socket", the "path_socket_suffix", and the "name_socket" to construct the socket file. + + - path_socket_suffix\: + This represents a suffix used to construct the full socket path. + This suffix is appended to the socket file name. + + When not defined the compiled in default is used. + The default path suffix is generally ".socket" but this could be changed during compile time. + + When the Object "path_socket_suffix" is defined without any Content, then no suffix is appended. + + This is used along with the "path_socket", the "path_socket_prefix", and the "name_socket" to construct the socket file. diff --git a/level_3/control/specifications/settings.txt b/level_3/control/specifications/settings.txt new file mode 100644 index 0000000..3f9f63b --- /dev/null +++ b/level_3/control/specifications/settings.txt @@ -0,0 +1,16 @@ +# fss-0002 + +Settings Specification: + The control settings "settings" file follows the FSS-0001 (Extended) format. + + Each Object represents a settings property name. + There is only a distinct set of setting property names (see below). + + Each Content represents the values associated with that property. + Additional restrictions are applied to each Content depending on each specific Object name (see below). + + Object Names and their respective Content purpose/restrictions\: + - name_socket: Must only be a single valid filename, without the directory. + - path_socket: Must only be a single valid directory. + - path_socket_prefix: Zero or one string representing a file name. + - path_socket_suffix: Zero or one string representing a file name. diff --git a/level_3/controller/c/common/private-control.h b/level_3/controller/c/common/private-control.h index e08883e..009b8fa 100644 --- a/level_3/controller/c/common/private-control.h +++ b/level_3/controller/c/common/private-control.h @@ -59,7 +59,15 @@ extern "C" { f_string_dynamic_t output; } controller_control_t; - #define controller_control_t_initialize { 0, 0, f_string_dynamic_t_initialize, f_string_dynamic_t_initialize, f_string_dynamic_t_initialize, f_string_dynamic_t_initialize, f_string_dynamic_t_initialize } + #define controller_control_t_initialize { \ + 0, \ + 0, \ + f_string_dynamic_t_initialize, \ + f_string_dynamic_t_initialize, \ + f_string_dynamic_t_initialize, \ + f_string_dynamic_t_initialize, \ + f_string_dynamic_t_initialize, \ + } #define macro_controller_control_t_initialize(server, client) { \ 0, \ @@ -85,30 +93,6 @@ extern "C" { #endif // _di_controller_control_packet_flag_ /** - * A 34-bit long little-endian structure representing the packet header. - * - * This represents the packet header which is different from the header inside the packet. - * - * Generally, the string-based packet format is FSS-000E (Payload). - * This format is stored within packet and has it's own header and payload parts. - * Example pseudo-structure: - * [0][0][4294967296][# fss-000e - * header: - * type message - * length 4294965248 - * payload: - * ... - * ] - * - * This means that string format is "technical" binary because of the header, but after the header it is entirely a string. - * Unlike other strings, this string is not NULL terminated and is instead end of tranmsission or end of file terminated (as appropriate). - * - * type: A boolean that when TRUE designates this as a binary and when FALSE designates this as a string packet. - * endian: A boolean designating that when TRUE thath the length digit is big endian and when FALSE designates that the length is little endian. - * length: A size representing how large the entire packet is (including the header that is 34 bits). - */ - -/** * Fully deallocate all memory for the given control data without caring about return status. * * @param control diff --git a/level_3/controller/c/control/private-control.h b/level_3/controller/c/control/private-control.h index 5d38cd7..aaa0b53 100644 --- a/level_3/controller/c/control/private-control.h +++ b/level_3/controller/c/control/private-control.h @@ -108,6 +108,17 @@ extern "C" { * * Connectons are processed and actions are performed. * + * The response packet (string based) packet format is FSS-000E (Payload). + * This format is stored within packet and has it's own header and payload parts. + * Example pseudo-structure: + * [0][0][4294967296][# fss-000e + * header: + * type message + * length 4294965248 + * payload: + * ... + * ] + * * @param global * The global data. * @param server diff --git a/level_3/controller/c/controller/controller.c b/level_3/controller/c/controller/controller.c index a03d3ee..72b759e 100644 --- a/level_3/controller/c/controller/controller.c +++ b/level_3/controller/c/controller/controller.c @@ -35,7 +35,7 @@ extern "C" { fll_program_print_help_option(main->output.to, main->context, controller_short_daemon_s, controller_long_daemon_s, f_console_symbol_short_enable_s, f_console_symbol_long_enable_s, " Run in daemon only mode (do not process the entry)."); fll_program_print_help_option(main->output.to, main->context, controller_short_init_s, controller_long_init_s, f_console_symbol_short_enable_s, f_console_symbol_long_enable_s, " The program will run as an init replacement."); fll_program_print_help_option(main->output.to, main->context, controller_short_interruptible_s, controller_long_interruptible_s, f_console_symbol_short_enable_s, f_console_symbol_long_enable_s, " Designate that this program can be interrupted by a signal."); - fll_program_print_help_option(main->output.to, main->context, controller_short_pid_s, controller_long_pid_s, f_console_symbol_short_enable_s, f_console_symbol_long_enable_s, " Specify a custom pid file path, such as '" controller_path_pid_s CONTROLLER_default_s controller_path_suffix_s "'."); + fll_program_print_help_option(main->output.to, main->context, controller_short_pid_s, controller_long_pid_s, f_console_symbol_short_enable_s, f_console_symbol_long_enable_s, " Specify a custom pid file path, such as '" controller_path_pid_s CONTROLLER_default_s controller_path_pid_suffix_s "'."); fll_program_print_help_option(main->output.to, main->context, controller_short_settings_s, controller_long_settings_s, f_console_symbol_short_enable_s, f_console_symbol_long_enable_s, " Specify a custom settings path, such as '" controller_path_settings_s "'."); fll_program_print_help_option(main->output.to, main->context, controller_short_simulate_s, controller_long_simulate_s, f_console_symbol_short_enable_s, f_console_symbol_long_enable_s, " Run as a simulation."); fll_program_print_help_option(main->output.to, main->context, controller_short_uninterruptible_s, controller_long_uninterruptible_s, f_console_symbol_short_enable_s, f_console_symbol_long_enable_s, "Designate that this program cannot be interrupted by a signal."); @@ -166,7 +166,7 @@ extern "C" { struct sockaddr_un address; setting.control_socket.address = (struct sockaddr *) &address; setting.control_socket.domain = f_socket_domain_file_d; - setting.control_socket.type = f_socket_type_stream_d; + setting.control_socket.type = f_socket_type_datagram_d; setting.control_socket.length = sizeof(struct sockaddr_un); memset(&address, 0, setting.control_socket.length); @@ -285,7 +285,7 @@ extern "C" { } if (F_status_is_error_not(status)) { - status = f_string_append(controller_path_suffix_s, controller_path_suffix_s_length, &setting.path_pid); + status = f_string_append(controller_path_pid_suffix_s, controller_path_pid_suffix_s_length, &setting.path_pid); } if (F_status_is_error(status)) { diff --git a/level_3/controller/c/controller/controller.h b/level_3/controller/c/controller/controller.h index dc9f58e..9ff5e89 100644 --- a/level_3/controller/c/controller/controller.h +++ b/level_3/controller/c/controller/controller.h @@ -122,7 +122,7 @@ extern "C" { #else #define controller_path_pid_init_s "/var/run/controller/controller-" #define controller_path_pid_init_s_length 31 - #endif /* defined(_override_controller_path_pid_init_) && defined(_override_controller_path_pid_init_length_) */ + #endif // defined(_override_controller_path_pid_init_) && defined(_override_controller_path_pid_init_length_) // The settings path is a system-specific path and needs to be more easily contolled at compile time. #if defined(_override_controller_path_settings_init_) && defined(_override_controller_path_settings_init_length_) @@ -134,7 +134,7 @@ extern "C" { #else #define controller_path_settings_init_s "/etc/controller" #define controller_path_settings_init_s_length 15 - #endif /* defined(_override_controller_path_settings_init_) && defined(_override_controller_path_settings_init_length_) */ + #endif // defined(_override_controller_path_settings_init_) && defined(_override_controller_path_settings_init_length_) #ifdef _override_controller_default_program_script_ #define controller_default_program_script_s _override_controller_default_program_script_ @@ -142,13 +142,13 @@ extern "C" { #define controller_default_program_script_s "bash" #endif // _override_controller_default_program_script_ - #define controller_path_pid_s "controller/run/controller-" - #define controller_path_settings_s "controller" - #define controller_path_suffix_s ".pid" + #define controller_path_pid_s "controller/run/controller-" + #define controller_path_pid_suffix_s ".pid" + #define controller_path_settings_s "controller" - #define controller_path_pid_s_length 26 - #define controller_path_settings_s_length 10 - #define controller_path_suffix_s_length 4 + #define controller_path_pid_s_length 26 + #define controller_path_pid_suffix_s_length 4 + #define controller_path_settings_s_length 10 #define controller_short_cgroup_s "c" #define controller_short_daemon_s "d" @@ -194,24 +194,24 @@ extern "C" { #define controller_console_parameter_t_initialize \ { \ - f_console_parameter_t_initialize(f_console_standard_short_help_s, f_console_standard_long_help_s, 0, 0, f_console_type_normal_e), \ - f_console_parameter_t_initialize(f_console_standard_short_light_s, f_console_standard_long_light_s, 0, 0, f_console_type_inverse_e), \ - f_console_parameter_t_initialize(f_console_standard_short_dark_s, f_console_standard_long_dark_s, 0, 0, f_console_type_inverse_e), \ - f_console_parameter_t_initialize(f_console_standard_short_no_color_s, f_console_standard_long_no_color_s, 0, 0, f_console_type_inverse_e), \ - f_console_parameter_t_initialize(f_console_standard_short_quiet_s, f_console_standard_long_quiet_s, 0, 0, f_console_type_inverse_e), \ - f_console_parameter_t_initialize(f_console_standard_short_normal_s, f_console_standard_long_normal_s, 0, 0, f_console_type_inverse_e), \ - f_console_parameter_t_initialize(f_console_standard_short_verbose_s, f_console_standard_long_verbose_s, 0, 0, f_console_type_inverse_e), \ - f_console_parameter_t_initialize(f_console_standard_short_debug_s, f_console_standard_long_debug_s, 0, 0, f_console_type_inverse_e), \ - f_console_parameter_t_initialize(f_console_standard_short_version_s, f_console_standard_long_version_s, 0, 0, f_console_type_inverse_e), \ - f_console_parameter_t_initialize(controller_short_cgroup_s, controller_long_cgroup_s, 0, 1, f_console_type_normal_e), \ - f_console_parameter_t_initialize(controller_short_daemon_s, controller_long_daemon_s, 0, 0, f_console_type_normal_e), \ - f_console_parameter_t_initialize(controller_short_init_s, controller_long_init_s, 0, 0, f_console_type_normal_e), \ - f_console_parameter_t_initialize(controller_short_interruptible_s, controller_long_interruptible_s, 0, 0, f_console_type_normal_e), \ - f_console_parameter_t_initialize(controller_short_pid_s, controller_long_pid_s, 0, 1, f_console_type_normal_e), \ - f_console_parameter_t_initialize(controller_short_settings_s, controller_long_settings_s, 0, 1, f_console_type_normal_e), \ - f_console_parameter_t_initialize(controller_short_simulate_s, controller_long_simulate_s, 0, 0, f_console_type_normal_e), \ - f_console_parameter_t_initialize(controller_short_uninterruptible_s, controller_long_uninterruptible_s, 0, 0, f_console_type_normal_e), \ - f_console_parameter_t_initialize(controller_short_validate_s, controller_long_validate_s, 0, 0, f_console_type_normal_e), \ + macro_f_console_parameter_t_initialize(f_console_standard_short_help_s, f_console_standard_long_help_s, 0, 0, f_console_type_normal_e), \ + macro_f_console_parameter_t_initialize(f_console_standard_short_light_s, f_console_standard_long_light_s, 0, 0, f_console_type_inverse_e), \ + macro_f_console_parameter_t_initialize(f_console_standard_short_dark_s, f_console_standard_long_dark_s, 0, 0, f_console_type_inverse_e), \ + macro_f_console_parameter_t_initialize(f_console_standard_short_no_color_s, f_console_standard_long_no_color_s, 0, 0, f_console_type_inverse_e), \ + macro_f_console_parameter_t_initialize(f_console_standard_short_quiet_s, f_console_standard_long_quiet_s, 0, 0, f_console_type_inverse_e), \ + macro_f_console_parameter_t_initialize(f_console_standard_short_normal_s, f_console_standard_long_normal_s, 0, 0, f_console_type_inverse_e), \ + macro_f_console_parameter_t_initialize(f_console_standard_short_verbose_s, f_console_standard_long_verbose_s, 0, 0, f_console_type_inverse_e), \ + macro_f_console_parameter_t_initialize(f_console_standard_short_debug_s, f_console_standard_long_debug_s, 0, 0, f_console_type_inverse_e), \ + macro_f_console_parameter_t_initialize(f_console_standard_short_version_s, f_console_standard_long_version_s, 0, 0, f_console_type_inverse_e), \ + macro_f_console_parameter_t_initialize(controller_short_cgroup_s, controller_long_cgroup_s, 0, 1, f_console_type_normal_e), \ + macro_f_console_parameter_t_initialize(controller_short_daemon_s, controller_long_daemon_s, 0, 0, f_console_type_normal_e), \ + macro_f_console_parameter_t_initialize(controller_short_init_s, controller_long_init_s, 0, 0, f_console_type_normal_e), \ + macro_f_console_parameter_t_initialize(controller_short_interruptible_s, controller_long_interruptible_s, 0, 0, f_console_type_normal_e), \ + macro_f_console_parameter_t_initialize(controller_short_pid_s, controller_long_pid_s, 0, 1, f_console_type_normal_e), \ + macro_f_console_parameter_t_initialize(controller_short_settings_s, controller_long_settings_s, 0, 1, f_console_type_normal_e), \ + macro_f_console_parameter_t_initialize(controller_short_simulate_s, controller_long_simulate_s, 0, 0, f_console_type_normal_e), \ + macro_f_console_parameter_t_initialize(controller_short_uninterruptible_s, controller_long_uninterruptible_s, 0, 0, f_console_type_normal_e), \ + macro_f_console_parameter_t_initialize(controller_short_validate_s, controller_long_validate_s, 0, 0, f_console_type_normal_e), \ } #define controller_total_parameters_d 18 diff --git a/level_3/controller/data/settings/entries/default.entry b/level_3/controller/data/settings/entries/default.entry index 7e22cd1..8d043a8 100644 --- a/level_3/controller/data/settings/entries/default.entry +++ b/level_3/controller/data/settings/entries/default.entry @@ -33,7 +33,7 @@ boot: start boot root require start boot proc asynchronous require start boot devices asynchronous require - start boot file system asynchronous + start boot file_system asynchronous start boot modules wait start service logger diff --git a/level_3/controller/documents/packet.txt b/level_3/controller/documents/packet.txt index bf4fa8e..1fcb0d6 100644 --- a/level_3/controller/documents/packet.txt +++ b/level_3/controller/documents/packet.txt @@ -1,4 +1,29 @@ # fss-0002 Packet Documentation: - Todo write this. + Describes how a packet is designed and intended to be used. + + The "packet" is the general category in which multiple types of packets belong. + This describes the different packets based on their "type". + + Every packet contains a "header", a "type" within the header, a "length" within the header, and a "payload". + + The "controller" packet type\: + Commands being sent to the controller and their respective responses utilize a "controller" packet. + These are pre-defined commands to rules or the controller program itself. + Commands such as starting or stopping some rule, for example. + + When operating in "init" mode, additional commands are available: "reboot" and "shutdown". + The "reboot" is for rebooting the machine and will eventually support "kexec" mode. + The "shutdown" is for shutting down the machine. + These two commands are configurable to fire off based on conditions, namely "time". + Two conditions may be met "on or after a specific date and time" and/or after so many milliseconds (second, minutes, hours, days, etc..) have passed. + + The normal "controller" packet commands are any valid Rule Action that performs some action. + This does not include Actions that provide some setting or configuration (such as "with_pid"). + Some of the supported commands are: "freeze", "kill", "pause", "reload", "rerun", "restart", "resume", "start", "stop", or "thaw". + + The "error" packet type\: + The error packet is intended to communicate some sort of failure. + The "status" from the "header" designates the status code (based on the FSS status codes and FLL status codes). + The "payload" will contain a NULL terminated string representin the message used to describe the error. diff --git a/level_3/controller/specifications/packet.txt b/level_3/controller/specifications/packet.txt index b3501ff..64e2288 100644 --- a/level_3/controller/specifications/packet.txt +++ b/level_3/controller/specifications/packet.txt @@ -1,4 +1,34 @@ # fss-0002 Entry Specification: - todo write this. + The controller program communicates use the FSS-000E Packet format. + + The "header" Object contains the following FSS-0001 Extended Objects (depending on "type")\: + - action: A valid action type: "freeze", "kill", "pause", "reboot", "reload", "rerun", "restart", "resume", "shutdown", "start", "stop", or "thaw". + - length: A positive whole number inclusively between 0 and 4294965248 representing the length of the "payload". + - status: The string name representing an FSS status code, such as F_none or F_failure. + - type: The packet type that is one of "error" and "controller". + + When there are multiple Objects of the same name inside the "header"\: + - action: The order represents the order in which the actions are performed. + - length: There may only be one length Object, all others after the first are ignored. + - status: The first represents the status and all other represent additional statuses. + - type: The first represent the type and all others represents a sub-type. + + There are different headers and payload properties based on the "type". + + The "error" type\: + Supports the following headers: "length", "status", and "type". + + Currently only a single "status" is supported. + + The "payload" is a NULL terminated string whose length is defined by the "length" "header" Content. + + The "controller" type\: + Supports the following headers: "action", "length", "status", and "type". + + Currently only a single "action" is supported. + Currently only a single "status" is supported. + + The "payload" is dependent on the "action". + @todo describe the different actions.