The control program and the controller program will communicate using datagram named sockets.
#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;
}
}
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);
}
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) {
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);
#include <fll/level_0/console.h>
#include <fll/level_0/directory.h>
#include <fll/level_0/file.h>
+#include <fll/level_0/fss.h>
#include <fll/level_0/pipe.h>
#include <fll/level_0/print.h>
#include <fll/level_0/signal.h>
+#include <fll/level_0/socket.h>
// fll-1 includes
#include <fll/level_1/console.h>
+#include <fll/level_1/fss.h>
#include <fll/level_1/print.h>
#include <fll/level_1/string.h>
// fll-2 includes
#include <fll/level_2/error.h>
+#include <fll/level_2/fss_extended.h>
#include <fll/level_2/print.h>
#include <fll/level_2/program.h>
#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,
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 \
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;
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, \
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_
/**
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;
#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) {
}
#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
#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.
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
#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
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
--- /dev/null
+#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
--- /dev/null
+/**
+ * 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
# 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().
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
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
--- /dev/null
+# fss-0001
+
+name_socket default
+path_socket /var/run/controller
+path_socket_prefix controller-
+path_socket_suffix .socket
--- /dev/null
+# 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.
--- /dev/null
+# 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.
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, \
#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
*
* 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
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.");
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);
}
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)) {
#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_)
#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_
#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"
#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
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
# 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.
# 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.