]> Kevux Git Server - fll/commitdiff
Progress: Continue working on implementing control and controller programs.
authorKevin Day <thekevinday@gmail.com>
Mon, 24 Jan 2022 01:40:38 +0000 (19:40 -0600)
committerKevin Day <thekevinday@gmail.com>
Mon, 24 Jan 2022 01:46:07 +0000 (19:46 -0600)
The control program and the controller program will communicate using datagram named sockets.

22 files changed:
level_3/control/c/control.c
level_3/control/c/control.h
level_3/control/c/main.c
level_3/control/c/private-common.c
level_3/control/c/private-common.h
level_3/control/c/private-control.c
level_3/control/c/private-control.h
level_3/control/c/private-print.c [new file with mode: 0644]
level_3/control/c/private-print.h [new file with mode: 0644]
level_3/control/data/build/defines
level_3/control/data/build/dependencies
level_3/control/data/build/settings
level_3/control/data/settings/settings [new file with mode: 0644]
level_3/control/documents/settings.txt [new file with mode: 0644]
level_3/control/specifications/settings.txt [new file with mode: 0644]
level_3/controller/c/common/private-control.h
level_3/controller/c/control/private-control.h
level_3/controller/c/controller/controller.c
level_3/controller/c/controller/controller.h
level_3/controller/data/settings/entries/default.entry
level_3/controller/documents/packet.txt
level_3/controller/specifications/packet.txt

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