]> Kevux Git Server - fll/commitdiff
Update: Implement "rerun" and properly get failed execute status codes.
authorKevin Day <thekevinday@gmail.com>
Wed, 13 Oct 2021 23:21:44 +0000 (18:21 -0500)
committerKevin Day <thekevinday@gmail.com>
Wed, 13 Oct 2021 23:37:25 +0000 (18:37 -0500)
Provide "rerun" support feature.

I discovered some problems with the execute functions after testing the "rerun" feature.
Specifically, when a child exits, the exit code is not properly propogating to the caller.
This makes it impossible to detect a failed execution.

It turns out that I need to call exit() with the appropriate failed code (which is only 8-bits).
The pthread_exit() is documented as always exit() with a value of 0.
This makes it impossible to communicate the failed state to the parent via an exit return code.
I am forced to call exit() here.
To do this, several significant changes are required.

Implement F_execute_codes enum and related functions to handle the 8-bit large status codes.
The limited set of codes are focused on possible failure states from the execute functions.
Functions to convert to and from regular status codes and these special limited execute status codes are now provided.

A union called f_execute_result_t is now provided as a way for the execute functions to return a pid_t for the parent process and an int for the child process.
The int in this case is intended to hold the special execute status codes.
An int is used rather than a more appropriate uint8_t because the standard POSIX functions use int.

Additional normal status codes F_too_large and F_too_small are now provided as generic too large and too small statuses.

Exit calls now directly use the execute status codes when calling exit().

The controller program child process now returns the exit status code either at the end of the appropraite threads or at the end of the main().

A new micro time conversion function is provided so that the deprecated usleep() can be avoided.
I may end up rewriting this to perform the sleep as well rather than just return a timespec.

Yet another htop rule is provided for testing "rerun".

See the previous commit for additional details (5b09409e3c7b5eafc164405c5d487bdfd083be11).

27 files changed:
build/level_0/settings
build/monolithic/settings
level_0/f_execute/c/execute-common.h
level_0/f_execute/c/execute.c [new file with mode: 0644]
level_0/f_execute/c/execute.h
level_0/f_execute/data/build/settings
level_0/f_status/c/status.h
level_1/fl_execute/data/build/settings
level_1/fl_status/c/status.c
level_1/fl_status/c/status.h
level_2/fll_execute/c/execute.c
level_2/fll_execute/c/execute.h
level_2/fll_execute/c/private-execute.c
level_2/fll_execute/c/private-execute.h
level_2/fll_execute/data/build/settings
level_2/fll_status/c/status.c
level_3/controller/c/private-common.c
level_3/controller/c/private-common.h
level_3/controller/c/private-controller.c
level_3/controller/c/private-rule.c
level_3/controller/c/private-rule.h
level_3/controller/c/private-thread.c
level_3/controller/data/build/settings
level_3/controller/data/settings/example/entries/htop-command.entry [new file with mode: 0644]
level_3/controller/data/settings/example/rules/command/htop.rule [new file with mode: 0644]
level_3/fake/data/build/settings
level_3/firewall/data/build/settings

index 23b3614db9f8029c36a37c74396bc3b27bdec42a..2ad4bd18a863fd553569b4d0a9b9484e34969fee 100644 (file)
@@ -22,7 +22,7 @@ build_language c
 build_libraries -lc -lcap
 build_libraries-level
 build_libraries-level_threadless
-build_sources_library account.c private-account.c capability.c color.c color-common.c console.c console-common.c control_group.c control_group-common.c conversion.c conversion-common.c private-conversion.c directory.c private-directory.c environment.c private-environment.c file.c file-common.c private-file.c fss.c private-fss.c fss-common.c fss_named.c fss_nest.c fss_set.c iki.c iki-common.c private-iki.c limit.c memory.c memory_structure.c private-memory.c path.c path-common.c private-path.c pipe.c print.c print-common.c private-print.c serialize.c serialize-common.c private-serialize.c signal.c socket.c string.c string-common.c private-string.c string_dynamic.c string_map.c string_quantity.c string_range.c string_triple.c type_array.c private-type_array.c utf.c utf-common.c private-utf.c utf_dynamic.c utf_map.c utf_triple.c
+build_sources_library account.c private-account.c capability.c color.c color-common.c console.c console-common.c control_group.c control_group-common.c conversion.c conversion-common.c private-conversion.c directory.c private-directory.c environment.c private-environment.c execute.c file.c file-common.c private-file.c fss.c private-fss.c fss-common.c fss_named.c fss_nest.c fss_set.c iki.c iki-common.c private-iki.c limit.c memory.c memory_structure.c private-memory.c path.c path-common.c private-path.c pipe.c print.c print-common.c private-print.c serialize.c serialize-common.c private-serialize.c signal.c socket.c string.c string-common.c private-string.c string_dynamic.c string_map.c string_quantity.c string_range.c string_triple.c type_array.c private-type_array.c utf.c utf-common.c private-utf.c utf_dynamic.c utf_map.c utf_triple.c
 build_sources_library-level thread.c private-thread.c
 build_sources_program
 build_sources_headers account.h account-common.h capability.h capability-common.h color.h color-common.h console.h console-common.h control_group.h control_group-common.h conversion.h conversion-common.h directory.h directory_type.h directory-common.h environment.h environment-common.h execute.h execute-common.h file.h file-common.h fss.h fss-common.h fss_comment.h fss_delimit.h fss_named.h fss_nest.h fss_quote.h fss_set.h iki.h iki-common.h limit.h limit-common.h memory.h memory_structure.h memory-common.h path.h path-common.h pipe.h print.h print-common.h serialize.h serialize-common.h signal.h signal-common.h socket.h socket-common.h status.h string.h string-common.h string_dynamic.h string_map.h string_quantity.h string_range.h string_triple.h type.h type_array.h type_array-common.h utf.h utf-common.h utf_dynamic.h utf_map.h utf_triple.h
index 4a0410437082d9ab3abbbcc71a82b68fa493a41a..7576bb0db3acfeb4fc873922a70079fdaf5598d6 100644 (file)
@@ -22,7 +22,7 @@ build_language c
 build_libraries -lc -lcap
 build_libraries-monolithic
 build_libraries-monolithic_threadless
-build_sources_library level_0/account.c level_0/private-account.c level_0/capability.c level_0/color.c level_0/color-common.c level_0/console.c level_0/console-common.c level_0/control_group.c level_0/control_group-common.c level_0/conversion.c level_0/conversion-common.c level_0/private-conversion.c level_0/directory.c level_0/private-directory.c level_0/environment.c level_0/private-environment.c level_0/file.c level_0/file-common.c level_0/private-file.c level_0/fss.c level_0/private-fss.c level_0/fss-common.c level_0/fss_named.c level_0/fss_nest.c level_0/fss_set.c level_0/iki.c level_0/iki-common.c level_0/private-iki.c level_0/limit.c level_0/memory.c level_0/memory_structure.c level_0/private-memory.c level_0/path.c level_0/path-common.c level_0/private-path.c level_0/pipe.c level_0/print.c level_0/print-common.c level_0/private-print.c level_0/serialize.c level_0/serialize-common.c level_0/private-serialize.c level_0/signal.c level_0/socket.c level_0/string.c level_0/string-common.c level_0/private-string.c level_0/string_dynamic.c level_0/string_map.c level_0/string_quantity.c level_0/string_range.c level_0/string_triple.c level_0/type_array.c level_0/private-type_array.c level_0/utf.c level_0/utf-common.c level_0/private-utf.c level_0/utf_dynamic.c level_0/utf_map.c level_0/utf_triple.c level_1/console.c level_1/control_group.c level_1/conversion.c level_1/private-conversion.c level_1/directory.c level_1/private-directory.c level_1/environment.c level_1/private-fss.c level_1/fss_basic.c level_1/fss_basic_list.c level_1/fss_embedded_list.c level_1/fss_extended.c level_1/fss_extended_list.c level_1/iki.c level_1/print.c level_1/private-print.c level_1/signal.c level_1/status.c level_1/string.c level_1/private-string.c level_1/utf.c level_1/private-utf.c level_1/utf_file.c level_1/private-utf_file.c level_2/control_group.c level_2/error.c level_2/error-common.c level_2/private-error.c level_2/execute.c level_2/private-execute.c level_2/file.c level_2/private-file.c level_2/fss.c level_2/private-fss.c level_2/fss_basic.c level_2/fss_basic_list.c level_2/fss_embedded_list.c level_2/fss_extended.c level_2/fss_extended_list.c level_2/fss_status.c level_2/iki.c level_2/private-iki.c level_2/path.c level_2/print.c level_2/program.c level_2/status.c
+build_sources_library level_0/account.c level_0/private-account.c level_0/capability.c level_0/color.c level_0/color-common.c level_0/console.c level_0/console-common.c level_0/control_group.c level_0/control_group-common.c level_0/conversion.c level_0/conversion-common.c level_0/private-conversion.c level_0/directory.c level_0/private-directory.c level_0/environment.c level_0/private-environment.c level_0/execute.c level_0/file.c level_0/file-common.c level_0/private-file.c level_0/fss.c level_0/private-fss.c level_0/fss-common.c level_0/fss_named.c level_0/fss_nest.c level_0/fss_set.c level_0/iki.c level_0/iki-common.c level_0/private-iki.c level_0/limit.c level_0/memory.c level_0/memory_structure.c level_0/private-memory.c level_0/path.c level_0/path-common.c level_0/private-path.c level_0/pipe.c level_0/print.c level_0/print-common.c level_0/private-print.c level_0/serialize.c level_0/serialize-common.c level_0/private-serialize.c level_0/signal.c level_0/socket.c level_0/string.c level_0/string-common.c level_0/private-string.c level_0/string_dynamic.c level_0/string_map.c level_0/string_quantity.c level_0/string_range.c level_0/string_triple.c level_0/type_array.c level_0/private-type_array.c level_0/utf.c level_0/utf-common.c level_0/private-utf.c level_0/utf_dynamic.c level_0/utf_map.c level_0/utf_triple.c level_1/console.c level_1/control_group.c level_1/conversion.c level_1/private-conversion.c level_1/directory.c level_1/private-directory.c level_1/environment.c level_1/private-fss.c level_1/fss_basic.c level_1/fss_basic_list.c level_1/fss_embedded_list.c level_1/fss_extended.c level_1/fss_extended_list.c level_1/iki.c level_1/print.c level_1/private-print.c level_1/signal.c level_1/status.c level_1/string.c level_1/private-string.c level_1/utf.c level_1/private-utf.c level_1/utf_file.c level_1/private-utf_file.c level_2/control_group.c level_2/error.c level_2/error-common.c level_2/private-error.c level_2/execute.c level_2/private-execute.c level_2/file.c level_2/private-file.c level_2/fss.c level_2/private-fss.c level_2/fss_basic.c level_2/fss_basic_list.c level_2/fss_embedded_list.c level_2/fss_extended.c level_2/fss_extended_list.c level_2/fss_status.c level_2/iki.c level_2/private-iki.c level_2/path.c level_2/print.c level_2/program.c level_2/status.c
 build_sources_library-monolithic level_0/thread.c level_0/private-thread.c
 build_sources_program
 build_sources_headers level_0/account.h level_0/account-common.h level_0/capability.h level_0/capability-common.h level_0/color.h level_0/color-common.h level_0/console.h level_0/console-common.h level_0/control_group.h level_0/control_group-common.h level_0/conversion.h level_0/conversion-common.h level_0/directory.h level_0/directory_type.h level_0/directory-common.h level_0/environment.h level_0/environment-common.h level_0/execute.h level_0/execute-common.h level_0/file.h level_0/file-common.h level_0/fss.h level_0/fss-common.h level_0/fss_comment.h level_0/fss_delimit.h level_0/fss_named.h level_0/fss_nest.h level_0/fss_quote.h level_0/fss_set.h level_0/iki.h level_0/iki-common.h level_0/limit.h level_0/limit-common.h level_0/memory.h level_0/memory_structure.h level_0/memory-common.h level_0/path.h level_0/path-common.h level_0/pipe.h level_0/print.h level_0/print-common.h level_0/serialize.h level_0/serialize-common.h level_0/signal.h level_0/signal-common.h level_0/socket.h level_0/socket-common.h level_0/status.h level_0/string.h level_0/string-common.h level_0/string_dynamic.h level_0/string_map.h level_0/string_quantity.h level_0/string_range.h level_0/string_triple.h level_0/type.h level_0/type_array.h level_0/type_array-common.h level_0/utf.h level_0/utf-common.h level_0/utf_dynamic.h level_0/utf_map.h level_0/utf_triple.h level_1/console.h level_1/control_group.h level_1/conversion.h level_1/directory.h level_1/environment.h level_1/execute.h level_1/execute-common.h level_1/fss.h level_1/fss_basic.h level_1/fss_basic_list.h level_1/fss_embedded_list.h level_1/fss_extended.h level_1/fss_extended_list.h level_1/fss_status.h level_1/iki.h level_1/print.h level_1/signal.h level_1/signal-common.h level_1/status.h level_1/string.h level_1/utf.h level_1/utf_file.h level_2/control_group.h level_2/error.h level_2/error-common.h level_2/execute.h level_2/file.h level_2/fss.h level_2/fss_basic.h level_2/fss_basic_list.h level_2/fss_embedded_list.h level_2/fss_extended.h level_2/fss_extended_list.h level_2/fss_status.h level_2/iki.h level_2/path.h level_2/print.h level_2/program.h level_2/status.h
index c1bb1f47f0a03e43ee3b0af71a753946564b370d..3dc01f33ec69bfba98f136f09e2b4e47576db37a 100644 (file)
@@ -17,6 +17,56 @@ extern "C" {
 #endif
 
 /**
+ * All special case execute codes.
+ *
+ * Only the lower 8-bits are available for return codes and so this is a special small set of status codes to be returned by a child process for a parent process to get.
+ * A waitpid() call can be used within the parent to get these codes if the child returns with these codes.
+ *
+ * All codes, except 0, represent an error.
+ *
+ * F_execute_code_last, this is intended to designate the last code provided by level_0 execute project.
+ * All code sets started by another project must start at this number + 1 with a code start map.
+ *
+ * Warning: F_execute and F_execute_not are F_status_t status codes and are not F_execute_codes.
+ * The F_execute_off is the execute code equivalent of F_execute_not.
+ */
+#ifndef _di_F_execute_codes_
+  enum {
+    F_execute_none = 0,
+    F_execute_access,
+    F_execute_buffer,
+    F_execute_busy,
+    F_execute_capability,
+    F_execute_control_group,
+    F_execute_child,
+    F_execute_directory_not,
+    F_execute_failure,
+    F_execute_file_found_not,
+    F_execute_file_type_directory,
+    F_execute_group,
+    F_execute_input_output,
+    F_execute_limit,
+    F_execute_loop,
+    F_execute_memory_not,
+    F_execute_name_not,
+    F_execute_nice,
+    F_execute_off,
+    F_execute_parameter,
+    F_execute_pipe,
+    F_execute_processor,
+    F_execute_prohibited,
+    F_execute_resource_not,
+    F_execute_schedule,
+    F_execute_too_large,
+    F_execute_user,
+    F_execute_valid_not,
+
+    // Required.
+    F_execute_code_last,
+  }; // enum
+#endif // _di_F_execute_codes_
+
+/**
  * A structure representing a scheduler and its parameters for execution.
  *
  * @todo move this into a f_scheduler project.
@@ -39,6 +89,28 @@ extern "C" {
     scheduler.priority = 0;
 #endif // _di_f_execute_scheduler_t_
 
+/**
+ * A structure representing either a pid_t or an f_status_t.
+ *
+ * This is intended to be used for the execute functions that may store a pid_t in a parent process but a f_status_t in a child process.
+ * These would use the same variable, but it may be stored differently.
+ *
+ * status: The status code, generally used by the child process.
+ * pid:    The process id (PID) of the child process, generally used by the parent process;
+ */
+#ifndef _di_f_execute_result_t_
+  typedef union {
+    int status;
+    pid_t pid;
+  } f_execute_result_t;
+
+  #define f_execute_result_t_initialize { 0 }
+
+  #define f_execute_result_t_clear(execute_result) \
+    execute_result.status = 0; \
+    execute_result.pid = 0;
+#endif // _di_f_execute_result_t_
+
 #ifdef __cplusplus
 } // extern "C"
 #endif
diff --git a/level_0/f_execute/c/execute.c b/level_0/f_execute/c/execute.c
new file mode 100644 (file)
index 0000000..050e940
--- /dev/null
@@ -0,0 +1,247 @@
+#include "execute.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _di_f_execute_status_from_status_
+  uint8_t f_execute_status_from_status(f_status_t status) {
+
+    if (F_status_set_fine(status) == F_none) {
+      return F_execute_none;
+    }
+
+    if (F_status_set_fine(status) == F_access) {
+      return F_execute_access;
+    }
+
+    if (F_status_set_fine(status) == F_buffer) {
+      return F_execute_buffer;
+    }
+
+    if (F_status_set_fine(status) == F_busy) {
+      return F_execute_busy;
+    }
+
+    if (F_status_set_fine(status) == F_capability) {
+      return F_execute_capability;
+    }
+
+    if (F_status_set_fine(status) == F_control_group) {
+      return F_execute_control_group;
+    }
+
+    if (F_status_set_fine(status) == F_child) {
+      return F_execute_child;
+    }
+
+    if (F_status_set_fine(status) == F_directory_not) {
+      return F_execute_directory_not;
+    }
+
+    if (F_status_set_fine(status) == F_execute_not) {
+      return F_execute_off;
+    }
+
+    if (F_status_set_fine(status) == F_failure) {
+      return F_execute_failure;
+    }
+
+    if (F_status_set_fine(status) == F_file_found_not) {
+      return F_execute_file_found_not;
+    }
+
+    if (F_status_set_fine(status) == F_file_type_directory) {
+      return F_execute_file_type_directory;
+    }
+
+    if (F_status_set_fine(status) == F_group) {
+      return F_execute_group;
+    }
+
+    if (F_status_set_fine(status) == F_input_output) {
+      return F_execute_input_output;
+    }
+
+    if (F_status_set_fine(status) == F_limit) {
+      return F_execute_limit;
+    }
+
+    if (F_status_set_fine(status) == F_loop) {
+      return F_execute_loop;
+    }
+
+    if (F_status_set_fine(status) == F_memory_not) {
+      return F_execute_memory_not;
+    }
+
+    if (F_status_set_fine(status) == F_name_not) {
+      return F_execute_name_not;
+    }
+
+    if (F_status_set_fine(status) == F_nice) {
+      return F_execute_nice;
+    }
+
+    if (F_status_set_fine(status) == F_parameter) {
+      return F_execute_parameter;
+    }
+
+    if (F_status_set_fine(status) == F_pipe) {
+      return F_execute_pipe;
+    }
+
+    if (F_status_set_fine(status) == F_processor) {
+      return F_execute_processor;
+    }
+
+    if (F_status_set_fine(status) == F_prohibited) {
+      return F_execute_prohibited;
+    }
+
+    if (F_status_set_fine(status) == F_resource_not) {
+      return F_execute_resource_not;
+    }
+
+    if (F_status_set_fine(status) == F_schedule) {
+      return F_execute_schedule;
+    }
+
+    if (F_status_set_fine(status) == F_too_large) {
+      return F_execute_too_large;
+    }
+
+    if (F_status_set_fine(status) == F_user) {
+      return F_execute_user;
+    }
+
+    if (F_status_set_fine(status) == F_valid_not) {
+      return F_execute_valid_not;
+    }
+
+    return F_execute_code_last;
+  }
+#endif // _di_f_execute_status_from_status_
+
+#ifndef _di_f_execute_status_to_status_
+  f_status_t f_execute_status_to_status(uint8_t status) {
+
+    if (status == F_execute_none) {
+      return F_none;
+    }
+
+    if (status == F_execute_access) {
+      return F_access;
+    }
+
+    if (status == F_execute_buffer) {
+      return F_buffer;
+    }
+
+    if (status == F_execute_busy) {
+      return F_busy;
+    }
+
+    if (status == F_execute_capability) {
+      return F_capability;
+    }
+
+    if (status == F_execute_control_group) {
+      return F_control_group;
+    }
+
+    if (status == F_execute_child) {
+      return F_child;
+    }
+
+    if (status == F_execute_directory_not) {
+      return F_directory_not;
+    }
+
+    if (status == F_execute_failure) {
+      return F_failure;
+    }
+
+    if (status == F_execute_file_found_not) {
+      return F_file_found_not;
+    }
+
+    if (status == F_execute_file_type_directory) {
+      return F_file_type_directory;
+    }
+
+    if (status == F_execute_group) {
+      return F_group;
+    }
+
+    if (status == F_execute_input_output) {
+      return F_input_output;
+    }
+
+    if (status == F_execute_limit) {
+      return F_limit;
+    }
+
+    if (status == F_execute_loop) {
+      return F_loop;
+    }
+
+    if (status == F_execute_memory_not) {
+      return F_memory_not;
+    }
+
+    if (status == F_execute_name_not) {
+      return F_name_not;
+    }
+
+    if (status == F_execute_nice) {
+      return F_nice;
+    }
+
+    if (status == F_execute_off) {
+      return F_execute_not;
+    }
+
+    if (status == F_execute_parameter) {
+      return F_parameter;
+    }
+
+    if (status == F_execute_pipe) {
+      return F_pipe;
+    }
+
+    if (status == F_execute_processor) {
+      return F_processor;
+    }
+
+    if (status == F_execute_prohibited) {
+      return F_prohibited;
+    }
+
+    if (status == F_execute_resource_not) {
+      return F_resource_not;
+    }
+
+    if (status == F_execute_schedule) {
+      return F_schedule;
+    }
+
+    if (status == F_execute_too_large) {
+      return F_too_large;
+    }
+
+    if (status == F_execute_user) {
+      return F_user;
+    }
+
+    if (status == F_execute_valid_not) {
+      return F_valid_not;
+    }
+
+    return F_status_set_error(F_known_not);
+  }
+#endif // _di_f_execute_status_to_status_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
index 7b87119475b5ed78ee538cb53f512ff65580eddc..0b721463a916436e7ccc362a294be6ccca19cd4d 100644 (file)
 extern "C" {
 #endif
 
+/**
+ * Convert from F_status_t to execute status.
+ *
+ * @param status
+ *   The status to convert from.
+ *   The execute status does not support flags and so flags on this are ignored.
+ *
+ * @return
+ *   The appropriate execute status code is returned on match.
+ *
+ *   F_execute_code_last is returned when there are no matching execute states.
+ */
+#ifndef _di_f_execute_status_from_status_
+  extern uint8_t f_execute_status_from_status(f_status_t status);
+#endif // _di_f_execute_status_from_status_
+
+/**
+ * Convert execute status to F_status_t.
+ *
+ * @param status
+ *   An execute status number to convert.
+ *   The execute status has no flags and is only 8-bits wide.
+ *
+ * @return
+ *   The appropriate status code is returned on match (no bits, error or otherwise are set).
+ *
+ *   F_known_not (with error bit) if the given number has no known execute state to convert.
+ */
+#ifndef _di_f_execute_status_to_status_
+  extern f_status_t f_execute_status_to_status(uint8_t status);
+#endif // _di_f_execute_status_to_status_
+
 #ifdef __cplusplus
 } // extern "C"
 #endif
index 6320b8328371a0767376d6972b59bc578db80358..91e42ab6628aa0db7dfff16ccdd1d6b35673b4e2 100644 (file)
@@ -21,7 +21,7 @@ build_indexer ar
 build_language c
 build_libraries -lc
 build_libraries-individual -lf_memory -lf_string
-build_sources_library
+build_sources_library execute.c
 build_sources_program
 build_sources_headers execute.h execute-common.h
 build_sources_script
index 1ed658574d3838dd9e64e547a21d3ed164d80817..ad51a533ad63d71481abe13f198a254f442e532c 100644 (file)
@@ -305,6 +305,8 @@ extern "C" {
       F_thread_not,
       F_time,
       F_time_not,
+      F_too_large,
+      F_too_small,
       F_user,
       F_user_not,
       F_utf,
@@ -548,7 +550,7 @@ extern "C" {
     #endif // _di_F_status_access_
 
     // Required.
-    F_status_code_last
+    F_status_code_last,
   }; // enum
 #endif // _di_F_status_codes_
 
index 909a46128dce155094dc6447ef002e392e0e2b12..16a249801c7586433ac829d124694d8d806bb099 100644 (file)
@@ -20,7 +20,7 @@ build_compiler gcc
 build_indexer ar
 build_language c
 build_libraries -lc -lcap
-build_libraries-individual -lf_capability -lf_limit -lf_memory -lf_signal -lf_string -lf_type_array
+build_libraries-individual -lf_capability -lf_execute -lf_limit -lf_memory -lf_signal -lf_string -lf_type_array
 build_sources_library
 build_sources_program
 build_sources_headers execute.h execute-common.h
index dd97bdc66db318409a579be9cb2133b60a1b97ea..eb53745b120faf878b048fd90e7507e1162a092c 100644 (file)
@@ -681,6 +681,12 @@ extern "C" {
         case F_time_not:
           *string = FL_status_string_time_not;
           break;
+        case F_too_large:
+          *string = FL_status_string_too_large;
+          break;
+        case F_too_small:
+          *string = FL_status_string_too_small;
+          break;
         case F_known:
           *string = FL_status_string_known;
           break;
index 6823fcfadcb2f8d1f7b45a9eaa2f4cdeda7264eb..293d9b52b7b3f53134426535881368b646111d5c 100644 (file)
@@ -321,6 +321,8 @@ extern "C" {
     #define FL_status_string_thread_not        "F_thread_not"
     #define FL_status_string_time              "F_time"
     #define FL_status_string_time_not          "F_time_not"
+    #define FL_status_string_too_large         "F_too_large"
+    #define FL_status_string_too_small         "F_too_small"
     #define FL_status_string_success           "F_success"
     #define FL_status_string_success_not       "F_success_not"
     #define FL_status_string_supported         "F_supported"
@@ -504,6 +506,8 @@ extern "C" {
     #define FL_status_string_thread_not_length        12
     #define FL_status_string_time_length              6
     #define FL_status_string_time_not_length          10
+    #define FL_status_string_too_large_length         11
+    #define FL_status_string_too_small_length         11
     #define FL_status_string_user_length              6
     #define FL_status_string_user_not_length          10
     #define FL_status_string_utf_length               5
index cea1d161789536b84d6a01fa4973739b90c1da60..c4ea744be55abcd44cfe20653ef66b00fb4b18fd 100644 (file)
@@ -271,8 +271,35 @@ extern "C" {
     }
 
     // generally this does not return, but in some cases (such as with scripts) this does return so handle the results.
+    if (code < 0) {
+      if (errno == EACCES) code = F_execute_access;
+      else if (errno == E2BIG) code = F_execute_too_large;
+      else if (errno == EAGAIN) code = F_execute_resource_not;
+      else if (errno == EFAULT) code = F_execute_buffer;
+      else if (errno == EINVAL) code = F_execute_parameter;
+      else if (errno == EIO) code = F_execute_input_output;
+      else if (errno == EISDIR) code = F_execute_file_type_directory;
+      else if (errno == EIO) code = F_execute_input_output;
+      else if (errno == ELIBBAD) code = F_execute_valid_not;
+      else if (errno == ELOOP) code = F_execute_loop;
+      else if (errno == EMFILE) code = F_execute_resource_not;
+      else if (errno == ENAMETOOLONG) code = F_execute_name_not;
+      else if (errno == ENFILE) code = F_execute_resource_not;
+      else if (errno == ENOENT) code = F_execute_file_found_not;
+      else if (errno == ENOEXEC) code = F_execute_off;
+      else if (errno == ENOMEM) code = F_execute_memory_not;
+      else if (errno == ENOTDIR) code = F_execute_directory_not;
+      else if (errno == EPERM) code = F_execute_prohibited;
+      else if (errno == ETXTBSY) code = F_execute_busy;
+      else code = F_execute_failure;
+    }
+    else {
+      code = 0;
+    }
+
     if (result) {
-      *result = code;
+      int *r = (int *) result;
+      *r = code;
     }
 
     if (option & fl_execute_parameter_option_exit) {
index 8e2a43eea6119b30d9ac4483d14ccd35698bf7a2..f177426c31818338db2298527c50a1b44c9057a8 100644 (file)
@@ -433,7 +433,7 @@ extern "C" {
  * @param as
  *   (optional) This and most of its fields are optional and are disabled when set to NULL.
  * @param result
- *   (optional) The code returned after finishing execution of program.
+ *   (optional) The execute status code returned after finishing or attempting to finish execution of program.
  *   When fl_execute_parameter_option_return is passed via parameter.option, then this instead stores the child process id (PID).
  *   This is should be of (int *) except when fl_execute_parameter_option_return this should instead be (pid_t *).
  *   Set to NULL to not use.
index 1ca0ce799f43b0b57f674a6c614eaa9cdb2d7167..0d7562c07ca682b0262214cac855cffd5d9f23d7 100644 (file)
@@ -122,12 +122,11 @@ extern "C" {
       errno = 0;
 
       if (nice(*as.nice) == -1 && errno == -1) {
-        *result = -1;
-
         if (parameter && parameter->option & fl_execute_parameter_option_exit) {
-          exit(*result);
+          exit(F_execute_nice);
         }
 
+        *result = F_execute_nice;
         return F_status_set_error(F_nice);
       }
     }
@@ -136,48 +135,45 @@ extern "C" {
       const f_status_t status = f_capability_process_set(as.capability);
 
       if (F_status_is_error(status) && F_status_set_fine(status) != F_supported_not) {
-        *result = -1;
-
         if (parameter && parameter->option & fl_execute_parameter_option_exit) {
-          exit(*result);
+          exit(F_execute_capability);
         }
 
+        *result = F_execute_capability;
         return F_status_set_error(F_capability);
       }
     }
 
     if (as.id_groups) {
       if (setgroups(as.id_groups->used, (const gid_t *) as.id_groups->array) == -1) {
-        *result = -1;
 
         if (parameter && parameter->option & fl_execute_parameter_option_exit) {
-          exit(*result);
+          exit(F_execute_group);
         }
 
+        *result = F_execute_group;
         return F_status_set_error(F_group);
       }
     }
 
     if (as.id_group) {
       if (setgid(*as.id_group) == -1) {
-        *result = -1;
-
         if (parameter && parameter->option & fl_execute_parameter_option_exit) {
-          exit(*result);
+          exit(F_execute_group);
         }
 
+        *result = F_execute_group;
         return F_status_set_error(F_group);
       }
     }
 
     if (as.id_user) {
       if (setuid(*as.id_user) == -1) {
-        *result = -1;
-
         if (parameter && parameter->option & fl_execute_parameter_option_exit) {
-          exit(*result);
+          exit(F_execute_user);
         }
 
+        *result = F_execute_user;
         return F_status_set_error(F_user);
       }
     }
@@ -355,11 +351,11 @@ extern "C" {
 
         if (result) {
           int *r = (int *) result;
-          *r = -1;
+          *r = F_execute_failure;
         }
 
         if (parameter && parameter->option & fl_execute_parameter_option_exit) {
-          exit(-1);
+          exit(F_execute_failure);
         }
 
         return F_child;
@@ -403,7 +399,33 @@ extern "C" {
       if (F_status_is_error(status)) return status;
     }
 
-    const int code = direct ? execv(program, fixed_arguments) : execvp(program, fixed_arguments);
+    int code = direct ? execv(program, fixed_arguments) : execvp(program, fixed_arguments);
+
+    if (code < 0) {
+      if (errno == EACCES) code = F_execute_access;
+      else if (errno == E2BIG) code = F_execute_too_large;
+      else if (errno == EAGAIN) code = F_execute_resource_not;
+      else if (errno == EFAULT) code = F_execute_buffer;
+      else if (errno == EINVAL) code = F_execute_parameter;
+      else if (errno == EIO) code = F_execute_input_output;
+      else if (errno == EISDIR) code = F_execute_file_type_directory;
+      else if (errno == EIO) code = F_execute_input_output;
+      else if (errno == ELIBBAD) code = F_execute_valid_not;
+      else if (errno == ELOOP) code = F_execute_loop;
+      else if (errno == EMFILE) code = F_execute_resource_not;
+      else if (errno == ENAMETOOLONG) code = F_execute_name_not;
+      else if (errno == ENFILE) code = F_execute_resource_not;
+      else if (errno == ENOENT) code = F_execute_file_found_not;
+      else if (errno == ENOEXEC) code = F_execute_off;
+      else if (errno == ENOMEM) code = F_execute_memory_not;
+      else if (errno == ENOTDIR) code = F_execute_directory_not;
+      else if (errno == EPERM) code = F_execute_prohibited;
+      else if (errno == ETXTBSY) code = F_execute_busy;
+      else code = F_execute_failure;
+    }
+    else {
+      code = 0;
+    }
 
     if (result) {
       int *r = (int *) result;
@@ -523,8 +545,8 @@ extern "C" {
         close(descriptors[0]);
 
         if (result) {
-          int *r = (int *) result;
-          *r = -1;
+          f_status_t *r = (f_status_t *) result;
+          *r = F_status_set_error(F_failure);
         }
 
         if (parameter && parameter->option & fl_execute_parameter_option_exit) {
@@ -570,11 +592,42 @@ extern "C" {
       if (F_status_is_error(status)) return status;
     }
 
-    const int code = direct ? execv(program, fixed_arguments) : execvp(program, fixed_arguments);
+    int code = direct ? execv(program, fixed_arguments) : execvp(program, fixed_arguments);
 
     // close the write pipe for the child when done.
     close(descriptors[0]);
 
+    if (code < 0) {
+      if (errno == EACCES) code = F_execute_access;
+      else if (errno == E2BIG) code = F_execute_too_large;
+      else if (errno == EAGAIN) code = F_execute_resource_not;
+      else if (errno == EFAULT) code = F_execute_buffer;
+      else if (errno == EINVAL) code = F_execute_parameter;
+      else if (errno == EIO) code = F_execute_input_output;
+      else if (errno == EISDIR) code = F_execute_file_type_directory;
+      else if (errno == EIO) code = F_execute_input_output;
+      else if (errno == ELIBBAD) code = F_execute_valid_not;
+      else if (errno == ELOOP) code = F_execute_loop;
+      else if (errno == EMFILE) code = F_execute_resource_not;
+      else if (errno == ENAMETOOLONG) code = F_execute_name_not;
+      else if (errno == ENFILE) code = F_execute_resource_not;
+      else if (errno == ENOENT) code = F_execute_file_found_not;
+      else if (errno == ENOEXEC) code = F_execute_off;
+      else if (errno == ENOMEM) code = F_execute_memory_not;
+      else if (errno == ENOTDIR) code = F_execute_directory_not;
+      else if (errno == EPERM) code = F_execute_prohibited;
+      else if (errno == ETXTBSY) code = F_execute_busy;
+      else code = F_execute_failure;
+    }
+    else {
+      code = 0;
+    }
+
+    if (result) {
+      int *r = (int *) result;
+      *r = code;
+    }
+
     if (result) {
       int *r = (int *) result;
       *r = code;
index 8e7930180bee1620e48bf8a44f2423be8fc108ee..f0bf921517e88668e00c49b40d2a7c1243b87ce3 100644 (file)
@@ -203,7 +203,7 @@ extern "C" {
  * @param as
  *   (optional) This and most of its fields are optional and are disabled when set to NULL.
  * @param result
- *   (optional) The code returned after finishing execution of program.
+ *   (optional) The execute status code returned after finishing or attempting to finish execution of program.
  *   When fl_execute_parameter_option_return is passed via parameter.option, then this instead stores the child process id (PID).
  *   This is should be of (int *) except when fl_execute_parameter_option_return this should instead be (pid_t *).
  *   Set to NULL to not use.
@@ -279,7 +279,7 @@ extern "C" {
  * @param as
  *   (optional) This and most of its fields are optional and are disabled when set to NULL.
  * @param result
- *   (optional) The code returned after finishing execution of program.
+ *   (optional) The execute status code returned after finishing or attempting to finish execution of program.
  *   When fl_execute_parameter_option_return is passed via parameter.option, then this instead stores the child process id (PID).
  *   This is should be of (int *) except when fl_execute_parameter_option_return this should instead be (pid_t *).
  *   Set to NULL to not use.
index 18994db13e7dc0abbedb4d2fc070ac60a828bee8..d895a100a162b78582c5a70a8b97c34f1c2f3348 100644 (file)
@@ -20,8 +20,8 @@ build_compiler gcc
 build_indexer ar
 build_language c
 build_libraries -lc -lcap
-build_libraries-individual -lfl_control_group -lfl_environment -lf_account -lf_capability -lf_control_group -lf_environment -lf_file -lf_limit -lf_memory -lf_path -lf_signal -lf_string -lf_thread -lf_type_array -lf_utf
-build_libraries-individual_threadless -lfl_control_group -lfl_environment -lf_account -lf_capability -lf_control_group -lf_environment -lf_file -lf_limit -lf_memory -lf_path -lf_signal -lf_string -lf_type_array -lf_utf
+build_libraries-individual -lfl_control_group -lfl_environment -lf_account -lf_capability -lf_control_group -lf_environment -lf_execute -lf_file -lf_limit -lf_memory -lf_path -lf_signal -lf_string -lf_thread -lf_type_array -lf_utf
+build_libraries-individual_threadless -lfl_control_group -lfl_environment -lf_account -lf_capability -lf_control_group -lf_environment -lf_execute -lf_file -lf_limit -lf_memory -lf_path -lf_signal -lf_string -lf_type_array -lf_utf
 build_sources_library execute.c private-execute.c
 build_sources_program
 build_sources_headers execute.h
index 0a1e1b591ce91657359ca61972953be77d15457f..cc2f46fece4a0c948e5b4913a96af257d3eb791f 100644 (file)
@@ -1393,6 +1393,18 @@ extern "C" {
         return F_none;
       }
 
+      if (fl_string_compare(string, FL_status_string_too_large, length, FL_status_string_too_large_length) == F_equal_to) {
+        *code = F_too_large;
+
+        return F_none;
+      }
+
+      if (fl_string_compare(string, FL_status_string_too_small, length, FL_status_string_too_small_length) == F_equal_to) {
+        *code = F_too_small;
+
+        return F_none;
+      }
+
       if (fl_string_compare(string, FL_status_string_user, length, FL_status_string_user_length) == F_equal_to) {
         *code = F_user;
 
index bd6e14258210adbc2c1adfe8b506a3d57db41b45..fe1c530984dc5e3c9c85c8560a6167238b07461e 100644 (file)
@@ -919,6 +919,17 @@ extern "C" {
   }
 #endif // _di_controller_time_
 
+#ifndef _di_controller_time_micro_
+  struct timespec controller_time_micro(const f_number_unsigned_t microseconds) {
+
+    struct timespec time;
+    time.tv_sec = microseconds / 1000;
+    time.tv_nsec = (time.tv_sec ? microseconds - time.tv_sec : microseconds) * 1000;
+
+    return time;
+  }
+#endif // _di_controller_time_micro_
+
 #ifdef __cplusplus
 } // extern "C"
 #endif
index 7855177d09511a8b53a042a1a69a3ee0166efbe9..f727163607e33f12cac9c749fb3bda385f181dc8 100644 (file)
@@ -1077,6 +1077,7 @@ extern "C" {
  * - control: The process is started from a control operation.
  *
  * id:           The ID of this process relative to the processes array.
+ * result:       The last return code from an execution of a process.
  * status:       The last execution status of the process.
  * state:        The state of the process.
  * action:       The action being performed.
@@ -1122,6 +1123,8 @@ extern "C" {
     uint8_t options;
     uint8_t type;
 
+    int result;
+
     f_thread_id_t id_thread;
     f_thread_lock_t lock;
     f_thread_lock_t active;
@@ -1147,6 +1150,7 @@ extern "C" {
     0, \
     0, \
     0, \
+    0, \
     f_thread_id_t_initialize, \
     f_thread_lock_t_initialize, \
     f_thread_lock_t_initialize, \
@@ -2437,6 +2441,19 @@ extern "C" {
   void controller_time(const time_t seconds, const long nanoseconds, struct timespec *time) f_attribute_visibility_internal;
 #endif // _di_controller_time_
 
+/**
+ * Convert microseconds to nanoseconds.
+ *
+ * @param microseconds
+ *   The number of microseconds.
+ *
+ * @return
+ *   A time structure suitable for passing to nanosleep() and similar functions.
+ */
+#ifndef _di_controller_time_micro_
+  extern struct timespec controller_time_micro(const f_number_unsigned_t microseconds) f_attribute_visibility_internal;
+#endif // _di_controller_time_micro_
+
 #ifdef __cplusplus
 } // extern "C"
 #endif
index 24a8ab64fbee9bfb05a5303cf5ff5aeee1e1212a..a84419ddcff6d15c36c4a4898d1d2d5089775bee 100644 (file)
@@ -1195,7 +1195,7 @@ extern "C" {
 
           int result = 0;
 
-          status = fll_execute_into(0, entry_action->parameters, fl_execute_parameter_option_path, 0, &result);
+          status = fll_execute_into(0, entry_action->parameters, fl_execute_parameter_option_path, 0, (void *) &result);
 
           if (F_status_is_error(status)) {
             if (F_status_set_fine(status) == F_file_found_not) {
index e55ec4c0ba9cafb5d0efeb9f4b7bd7ae22ec9524..fa16b8ede0dd2b787cd7e6daf5467288b6fa343a 100644 (file)
@@ -129,6 +129,49 @@ extern "C" {
   }
 #endif // _di_controller_rule_parameters_read_
 
+#ifndef _di_controller_rule_action_type_to_action_execute_type_
+  uint8_t controller_rule_action_type_to_action_execute_type(const uint8_t type) {
+
+    if (type == controller_rule_action_type_freeze) {
+      return controller_rule_action_type_execute_freeze;
+    }
+
+    if (type == controller_rule_action_type_kill) {
+      return controller_rule_action_type_execute_kill;
+    }
+
+    if (type == controller_rule_action_type_pause) {
+      return controller_rule_action_type_execute_pause;
+    }
+
+    if (type == controller_rule_action_type_reload) {
+      return controller_rule_action_type_execute_reload;
+    }
+
+    if (type == controller_rule_action_type_restart) {
+      return controller_rule_action_type_execute_restart;
+    }
+
+    if (type == controller_rule_action_type_resume) {
+      return controller_rule_action_type_execute_resume;
+    }
+
+    if (type == controller_rule_action_type_start) {
+      return controller_rule_action_type_execute_start;
+    }
+
+    if (type == controller_rule_action_type_stop) {
+      return controller_rule_action_type_execute_stop;
+    }
+
+    if (type == controller_rule_action_type_thaw) {
+      return controller_rule_action_type_execute_thaw;
+    }
+
+    return controller_rule_action_type_execute__enum_size;
+  }
+#endif // _di_controller_rule_action_type_to_action_execute_type_
+
 #ifndef _di_controller_rule_action_type_name_
   f_string_static_t controller_rule_action_type_name(const uint8_t type) {
 
@@ -212,6 +255,64 @@ extern "C" {
   }
 #endif // _di_controller_rule_action_type_name_
 
+#ifndef _di_controller_rule_action_type_execute_name_
+  f_string_static_t controller_rule_action_type_execute_name(const uint8_t type) {
+
+    f_string_static_t buffer = f_string_static_t_initialize;
+
+    switch (type) {
+      case controller_rule_action_type_execute_freeze:
+        buffer.string = controller_string_freeze_s;
+        buffer.used = controller_string_freeze_length;
+        break;
+
+      case controller_rule_action_type_execute_kill:
+        buffer.string = controller_string_kill_s;
+        buffer.used = controller_string_kill_length;
+        break;
+
+      case controller_rule_action_type_execute_pause:
+        buffer.string = controller_string_pause_s;
+        buffer.used = controller_string_pause_length;
+        break;
+
+      case controller_rule_action_type_execute_reload:
+        buffer.string = controller_string_reload_s;
+        buffer.used = controller_string_reload_length;
+        break;
+
+      case controller_rule_action_type_execute_restart:
+        buffer.string = controller_string_restart_s;
+        buffer.used = controller_string_restart_length;
+        break;
+
+      case controller_rule_action_type_execute_resume:
+        buffer.string = controller_string_resume_s;
+        buffer.used = controller_string_resume_length;
+        break;
+
+      case controller_rule_action_type_execute_start:
+        buffer.string = controller_string_start_s;
+        buffer.used = controller_string_start_length;
+        break;
+
+      case controller_rule_action_type_execute_stop:
+        buffer.string = controller_string_stop_s;
+        buffer.used = controller_string_stop_length;
+        break;
+
+      case controller_rule_action_type_execute_thaw:
+        buffer.string = controller_string_thaw_s;
+        buffer.used = controller_string_thaw_length;
+        break;
+    }
+
+    buffer.size = buffer.used;
+
+    return buffer;
+  }
+#endif // _di_controller_rule_action_type_execute_name_
+
 #ifndef _di_controller_rule_actions_increase_by_
   f_status_t controller_rule_actions_increase_by(const f_array_length_t amount, controller_rule_actions_t *actions) {
 
@@ -1015,9 +1116,15 @@ extern "C" {
         fl_print_format("%['.%]%c", print.to.stream, print.context, print.context, f_string_eol_s[0]);
       }
       else if (code) {
-        fl_print_format("%[' failed with the exit code %]", print.to.stream, print.context, print.context);
-        fl_print_format("%[%i%]", print.to.stream, print.notable, code, print.notable);
-        fl_print_format("%[.%]%c", print.to.stream, print.context, print.context, f_string_eol_s[0]);
+        if (code == F_execute_file_found_not) {
+          fl_print_format("%[' could not be executed because it was not found.%]%c", print.to.stream, print.context, print.context, f_string_eol_s[0]);
+        }
+        else {
+          // @todo improve reporting of all known status codes.
+          fl_print_format("%[' failed with the exit code %]", print.to.stream, print.context, print.context);
+          fl_print_format("%[%i%]", print.to.stream, print.notable, code, print.notable);
+          fl_print_format("%[.%]%c", print.to.stream, print.context, print.context, f_string_eol_s[0]);
+        }
       }
       else {
         fl_print_format("%[' failed.%]%c", print.to.stream, print.context, print.context, f_string_eol_s[0]);
@@ -1028,17 +1135,6 @@ extern "C" {
   }
 #endif // _di_controller_rule_item_error_print_execute_
 
-#ifndef _di_controller_rule_item_error_print_execute_not_found_
-  void controller_rule_item_error_print_execute_not_found(const fll_error_print_t print, const bool script_is, const f_string_t name) {
-
-    if (print.verbosity == f_console_verbosity_quiet) return;
-
-    fl_print_format("%c%[%SThe %s '%]", print.to.stream, f_string_eol_s[0], print.context, print.prefix, script_is ? controller_string_script_s : controller_string_program_s, print.context);
-    fl_print_format("%[%S%]", print.to.stream, print.notable, name, print.notable);
-    fl_print_format("%[' could not be executed because it was not found.%]%c", print.to.stream, print.context, print.context, f_string_eol_s[0]);
-  }
-#endif // _di_controller_rule_item_error_print_execute_not_found_
-
 #ifndef _di_controller_rule_item_error_print_need_want_wish_
   void controller_rule_item_error_print_need_want_wish(const fll_error_print_t print, const f_string_t need_want_wish, const f_string_t value, const f_string_t why) {
 
@@ -1169,9 +1265,20 @@ extern "C" {
           execute_set.parameter.option |= fl_execute_parameter_option_path;
         }
 
-        // @todo: wrap these executions (foreground and background) in an additional loop to re-execution on the given re-run conditions.
         if (process->rule.items.array[i].type == controller_rule_item_type_command) {
-          status = controller_rule_execute_foreground(process->rule.items.array[i].type, process->rule.items.array[i].actions.array[j], 0, process->rule.items.array[i].actions.array[j].parameters, options, global, &execute_set, process);
+          for (;;) {
+
+            status = controller_rule_execute_foreground(process->rule.items.array[i].type, process->rule.items.array[i].actions.array[j], 0, process->rule.items.array[i].actions.array[j].parameters, options, global, &execute_set, process);
+
+            if (status == F_child || status == F_signal || F_status_set_fine(status) == F_lock) break;
+            if (F_status_is_error(status) && F_status_set_fine(status) != F_failure) break;
+
+            if (controller_rule_execute_rerun(global, controller_rule_action_type_to_action_execute_type(action), process, &process->rule.items.array[i]) > 0) {
+              continue;
+            }
+
+            break;
+          } // for
 
           if (status == F_child || status == F_signal || F_status_set_fine(status) == F_lock) break;
 
@@ -1189,7 +1296,19 @@ extern "C" {
         else if (process->rule.items.array[i].type == controller_rule_item_type_script) {
           execute_set.parameter.data = &process->rule.items.array[i].actions.array[j].parameters.array[0];
 
-          status = controller_rule_execute_foreground(process->rule.items.array[i].type, process->rule.items.array[i].actions.array[j], process->rule.script.used ? process->rule.script.string : controller_default_program_script, arguments_none, options, global, &execute_set, process);
+          for (;;) {
+
+            status = controller_rule_execute_foreground(process->rule.items.array[i].type, process->rule.items.array[i].actions.array[j], process->rule.script.used ? process->rule.script.string : controller_default_program_script, arguments_none, options, global, &execute_set, process);
+
+            if (status == F_child || status == F_signal || F_status_set_fine(status) == F_lock) break;
+            if (F_status_is_error(status) && F_status_set_fine(status) != F_failure) break;
+
+            if (controller_rule_execute_rerun(global, controller_rule_action_type_to_action_execute_type(action), process, &process->rule.items.array[i]) > 0) {
+              continue;
+            }
+
+            break;
+          } // for
 
           if (status == F_child || status == F_signal || F_status_set_fine(status) == F_lock) break;
 
@@ -1206,7 +1325,19 @@ extern "C" {
         }
         else if (process->rule.items.array[i].type == controller_rule_item_type_service) {
           if (process->rule.items.array[i].pid_file.used) {
-            status = controller_rule_execute_pid_with(process->rule.items.array[i].pid_file, process->rule.items.array[i].type, process->rule.items.array[i].actions.array[j], 0, process->rule.items.array[i].actions.array[j].parameters, options, process->rule.items.array[i].with, global, &execute_set, process);
+            for (;;) {
+
+              status = controller_rule_execute_pid_with(process->rule.items.array[i].pid_file, process->rule.items.array[i].type, process->rule.items.array[i].actions.array[j], 0, process->rule.items.array[i].actions.array[j].parameters, options, process->rule.items.array[i].with, global, &execute_set, process);
+
+              if (status == F_child || status == F_signal || F_status_set_fine(status) == F_lock) break;
+              if (F_status_is_error(status) && F_status_set_fine(status) != F_failure) break;
+
+              if (controller_rule_execute_rerun(global, controller_rule_action_type_to_action_execute_type(action), process, &process->rule.items.array[i]) > 0) {
+                continue;
+              }
+
+              break;
+            } // for
 
             if (status == F_child || status == F_signal || F_status_set_fine(status) == F_lock) break;
 
@@ -1232,7 +1363,19 @@ extern "C" {
           if (process->rule.items.array[i].pid_file.used) {
             execute_set.parameter.data = &process->rule.items.array[i].actions.array[j].parameters.array[0];
 
-            status = controller_rule_execute_pid_with(process->rule.items.array[i].pid_file, process->rule.items.array[i].type, process->rule.items.array[i].actions.array[j], process->rule.script.used ? process->rule.script.string : controller_default_program_script, arguments_none, options, process->rule.items.array[i].with, global, &execute_set, process);
+            for (;;) {
+
+              status = controller_rule_execute_pid_with(process->rule.items.array[i].pid_file, process->rule.items.array[i].type, process->rule.items.array[i].actions.array[j], process->rule.script.used ? process->rule.script.string : controller_default_program_script, arguments_none, options, process->rule.items.array[i].with, global, &execute_set, process);
+
+              if (status == F_child || status == F_signal || F_status_set_fine(status) == F_lock) break;
+              if (F_status_is_error(status) && F_status_set_fine(status) != F_failure) break;
+
+              if (controller_rule_execute_rerun(global, controller_rule_action_type_to_action_execute_type(action), process, &process->rule.items.array[i]) > 0) {
+                continue;
+              }
+
+              break;
+            } // for
 
             if (status == F_child || status == F_signal || F_status_set_fine(status) == F_lock) break;
 
@@ -1317,8 +1460,7 @@ extern "C" {
     f_status_t status = F_none;
     f_status_t status_lock = F_none;
 
-    int result = 0;
-    pid_t id_child = 0;
+    f_execute_result_t result = f_execute_result_t_initialize;
 
     status = controller_pids_increase(&process->childs);
 
@@ -1376,20 +1518,24 @@ extern "C" {
       }
 
       // sleep for less than a second to better show simulation of synchronous vs asynchronous.
-      usleep(controller_thread_simulation_timeout);
+      {
+        struct timespec delay = controller_time_micro(controller_thread_simulation_timeout);
+        nanosleep(&delay, 0);
+      }
 
       const f_string_static_t simulated_program = macro_f_string_static_t_initialize(f_string_empty_s, 0);
       const f_string_statics_t simulated_arguments = f_string_statics_t_initialize;
       fl_execute_parameter_t simulated_parameter = macro_fl_execute_parameter_t_initialize(execute_set->parameter.option, execute_set->parameter.wait, process->rule.has & controller_rule_has_environment ? execute_set->parameter.environment : 0, execute_set->parameter.signals, &simulated_program);
 
-      status = fll_execute_program(controller_default_program_script, simulated_arguments, &simulated_parameter, &execute_set->as, simulated_parameter.option & fl_execute_parameter_option_return ? (void *) &id_child : (void *) &result);
+      status = fll_execute_program(controller_default_program_script, simulated_arguments, &simulated_parameter, &execute_set->as, (void *) &result);
     }
     else {
-      status = fll_execute_program(program, arguments, &execute_set->parameter, &execute_set->as, execute_set->parameter.option & fl_execute_parameter_option_return ? (void *) &id_child : (void *) &result);
+      status = fll_execute_program(program, arguments, &execute_set->parameter, &execute_set->as, (void *) &result);
     }
 
     if (status == F_parent) {
-      result = 0;
+      const pid_t id_child = result.pid;
+      result.status = 0;
 
       f_thread_unlock(&process->lock);
 
@@ -1423,7 +1569,7 @@ extern "C" {
       if (status_lock != F_signal) {
 
         // have the parent wait for the child process to finish.
-        waitpid(id_child, &result, 0);
+        waitpid(id_child, &result.status, 0);
       }
 
       if (status_lock == F_signal || !controller_thread_is_enabled_process(process, global.thread)) {
@@ -1454,6 +1600,8 @@ extern "C" {
         return F_status_set_error(F_lock);
       }
 
+      process->result = result.status;
+
       // remove the pid now that waidpid() has returned.
       *child = 0;
 
@@ -1467,8 +1615,7 @@ extern "C" {
         return F_status_set_error(F_lock);
       }
 
-      // this must explicitly check for 0 (as opposed to checking (!result)).
-      if (!WIFEXITED(result)) {
+      if (WIFEXITED(result.status) ? WEXITSTATUS(result.status) : 0) {
         status = F_status_set_error(F_failure);
       }
       else {
@@ -1476,6 +1623,8 @@ extern "C" {
       }
     }
     else {
+      global.main->child = result.status;
+
       if (!controller_thread_is_enabled_process(process, global.thread)) {
         return F_signal;
       }
@@ -1496,22 +1645,11 @@ extern "C" {
       return status;
     }
 
-    if (result != 0) {
-      status = F_status_set_error(F_failure);
-    }
-
     if (F_status_is_error(status)) {
       status = F_status_set_fine(status);
 
-      if (status == F_control_group || status == F_failure || status == F_limit || status == F_processor || status == F_schedule) {
-        controller_rule_item_error_print_execute(global.main->error, type == controller_rule_item_type_script, program ? program : arguments.used ? arguments.array[0].string : f_string_empty_s, result, status, global.thread);
-      }
-      else if (status == F_file_found_not) {
-        controller_print_lock(global.main->error.to, global.thread);
-
-        controller_rule_item_error_print_execute_not_found(global.main->error, F_false, program);
-
-        controller_print_unlock_flush(global.main->error.to, global.thread);
+      if ((WIFEXITED(process->result) && WEXITSTATUS(process->result)) || status == F_control_group || status == F_failure || status == F_limit || status == F_processor || status == F_schedule) {
+        controller_rule_item_error_print_execute(global.main->error, type == controller_rule_item_type_script, program ? program : arguments.used ? arguments.array[0].string : f_string_empty_s, WIFEXITED(process->result) ? WEXITSTATUS(process->result) : 0, status, global.thread);
       }
       else {
         controller_error_print(global.main->error, F_status_set_fine(status), "fll_execute_program", F_true, global.thread);
@@ -1530,8 +1668,7 @@ extern "C" {
     f_status_t status = F_none;
     f_status_t status_lock = F_none;
 
-    int result = 0;
-    pid_t id_child = 0;
+    f_execute_result_t result = f_execute_result_t_initialize;
 
     status = controller_pids_increase(&process->childs);
 
@@ -1629,20 +1766,24 @@ extern "C" {
       }
 
       // sleep for less than a second to better show simulation of synchronous vs asynchronous.
-      usleep(controller_thread_simulation_timeout);
+      {
+        struct timespec delay = controller_time_micro(controller_thread_simulation_timeout);
+        nanosleep(&delay, 0);
+      }
 
       const f_string_static_t simulated_program = macro_f_string_static_t_initialize(f_string_empty_s, 0);
       const f_string_statics_t simulated_arguments = f_string_statics_t_initialize;
       fl_execute_parameter_t simulated_parameter = macro_fl_execute_parameter_t_initialize(execute_set->parameter.option, execute_set->parameter.wait, process->rule.has & controller_rule_has_environment ? execute_set->parameter.environment : 0, execute_set->parameter.signals, &simulated_program);
 
-      status = fll_execute_program(controller_default_program_script, simulated_arguments, &simulated_parameter, &execute_set->as, simulated_parameter.option & fl_execute_parameter_option_return ? (void *) &id_child : (void *) &result);
+      status = fll_execute_program(controller_default_program_script, simulated_arguments, &simulated_parameter, &execute_set->as, (void *) &result);
     }
     else {
-      status = fll_execute_program(program, arguments, &execute_set->parameter, &execute_set->as, execute_set->parameter.option & fl_execute_parameter_option_return ? (void *) &id_child : (void *) &result);
+      status = fll_execute_program(program, arguments, &execute_set->parameter, &execute_set->as, (void *) &result);
     }
 
     if (status == F_parent) {
-      result = 0;
+      const pid_t id_child = result.pid;
+      result.status = 0;
 
       f_thread_unlock(&process->lock);
 
@@ -1676,7 +1817,7 @@ extern "C" {
       if (status_lock != F_signal) {
 
         // the child process should perform the change into background, therefore it is safe to wait for the child to exit (another process is spawned).
-        waitpid(id_child, &result, 0);
+        waitpid(id_child, &result.status, 0);
       }
 
       if (!controller_thread_is_enabled_process(process, global.thread)) {
@@ -1707,6 +1848,8 @@ extern "C" {
         return F_status_set_error(F_lock);
       }
 
+      process->result = result.status;
+
       // remove the pid now that waidpid() has returned.
       *child = 0;
 
@@ -1720,9 +1863,7 @@ extern "C" {
         return F_status_set_error(F_lock);
       }
 
-      // this must explicitly check for 0 (as opposed to checking (!result)).
-      // @todo expand this to provide user more control over what is or is not an error to designate as a failure.
-      if (!WIFEXITED(result)) {
+      if (WIFEXITED(result.status) ? WEXITSTATUS(result.status) : 0) {
         status = F_status_set_error(F_failure);
       }
       else {
@@ -1730,6 +1871,8 @@ extern "C" {
       }
     }
     else {
+      global.main->child = result.status;
+
       if (!controller_thread_is_enabled_process(process, global.thread)) {
         return F_signal;
       }
@@ -1750,22 +1893,11 @@ extern "C" {
       return status;
     }
 
-    if (result != 0) {
-      status = F_status_set_error(F_failure);
-    }
-
     if (F_status_is_error(status)) {
       status = F_status_set_fine(status);
 
-      if (status == F_control_group || status == F_failure || status == F_limit || status == F_processor || status == F_schedule) {
-        controller_rule_item_error_print_execute(global.main->error, type == controller_rule_item_type_utility, program ? program : arguments.used ? arguments.array[0].string : f_string_empty_s, result, status, global.thread);
-      }
-      else if (status == F_file_found_not) {
-        controller_print_lock(global.main->error.to, global.thread);
-
-        controller_rule_item_error_print_execute_not_found(global.main->error, F_false, program);
-
-        controller_print_unlock_flush(global.main->error.to, global.thread);
+      if ((WIFEXITED(process->result) && WEXITSTATUS(process->result)) || status == F_control_group || status == F_failure || status == F_limit || status == F_processor || status == F_schedule) {
+        controller_rule_item_error_print_execute(global.main->error, type == controller_rule_item_type_utility, program ? program : arguments.used ? arguments.array[0].string : f_string_empty_s, WIFEXITED(process->result) ? WEXITSTATUS(process->result) : 0, status, global.thread);
       }
       else {
         controller_error_print(global.main->error, F_status_set_fine(status), "fll_execute_program", F_true, global.thread);
@@ -1778,6 +1910,75 @@ extern "C" {
   }
 #endif // _di_controller_rule_execute_pid_with_
 
+#ifndef _di_controller_rule_execute_rerun_
+  int8_t controller_rule_execute_rerun(const controller_global_t global, const uint8_t action, controller_process_t *process, controller_rule_item_t *item) {
+
+    const int result = WIFEXITED(process->result) ? WEXITSTATUS(process->result) : 0;
+
+    if (item->reruns[action].is & (result ? controller_rule_rerun_is_failure : controller_rule_rerun_is_success)) {
+      controller_rule_rerun_item_t *rerun_item = result ? &item->reruns[action].failure : &item->reruns[action].success;
+
+      if (!controller_thread_is_enabled_process(process, global.thread)) return -2;
+
+      if (!rerun_item->max || rerun_item->count < rerun_item->max) {
+        if (global.main->error.verbosity == f_console_verbosity_debug) {
+          controller_print_lock(global.main->output, global.thread);
+
+          fl_print_format("%cRe-running '", global.main->output.stream, f_string_eol_s[0]);
+          fl_print_format("%[%q%]", global.main->output.stream, global.main->context.set.title, process->rule.alias, global.main->context.set.title);
+          f_print_terminated("' '", global.main->output.stream);
+          fl_print_format("%[%q%]", global.main->output.stream, global.main->context.set.notable, controller_rule_action_type_execute_name(action), global.main->context.set.notable);
+          f_print_terminated("' with a ", global.main->output.stream);
+          fl_print_format("%[%s%]", global.main->output.stream, global.main->context.set.notable, controller_string_delay_s, global.main->context.set.notable);
+          f_print_terminated(" of ", global.main->output.stream);
+          fl_print_format("%[%ul%] MegaTime", global.main->output.stream, global.main->context.set.notable, rerun_item->delay, global.main->context.set.notable);
+
+          if (rerun_item->max) {
+            f_print_terminated(" for ", global.main->output.stream);
+            fl_print_format("%[%ul%]", global.main->output.stream, global.main->context.set.notable, rerun_item->count, global.main->context.set.notable);
+            f_print_terminated(" of ", global.main->output.stream);
+            fl_print_format("%[%s%] ", global.main->output.stream, global.main->context.set.notable, controller_string_max_s, global.main->context.set.notable);
+            fl_print_format("%[%ul%]", global.main->output.stream, global.main->context.set.notable, rerun_item->max, global.main->context.set.notable);
+            fl_print_format(".%c", global.main->output.stream, f_string_eol_s[0]);
+          }
+          else {
+            fl_print_format(" with no %[%s%].%c", global.main->output.stream, global.main->context.set.notable, controller_string_max_s, global.main->context.set.notable, f_string_eol_s[0]);
+          }
+
+          controller_print_unlock_flush(global.main->output, global.thread);
+        }
+
+        if (rerun_item->delay) {
+          struct timespec time = controller_time_micro(rerun_item->delay);
+
+          if (nanosleep(&time, 0) < 0) {
+            return -1;
+          }
+
+          if (!controller_thread_is_enabled_process(process, global.thread)) return -2;
+        }
+
+        if (item->reruns[action].is & (result ? controller_rule_rerun_is_failure_reset : controller_rule_rerun_is_success_reset)) {
+          if (result) {
+            item->reruns[action].success.count = 0;
+          }
+          else {
+            item->reruns[action].failure.count = 0;
+          }
+        }
+
+        if (rerun_item->max) {
+          ++rerun_item->count;
+        }
+
+        return F_true;
+      }
+    }
+
+    return F_false;
+  }
+#endif // _di_controller_rule_execute_rerun_
+
 #ifndef _di_controller_rule_id_construct_
   f_status_t controller_rule_id_construct(const controller_global_t global, const f_string_static_t source, const f_string_range_t directory, const f_string_range_t basename, f_string_dynamic_t *alias) {
 
@@ -2604,7 +2805,7 @@ extern "C" {
             if (process->rule.items.used) {
               fl_print_format("%c%[%SThe rule '%]", global.main->error.to.stream, f_string_eol_s[0], global.main->error.context, global.main->error.prefix, global.main->error.context);
               fl_print_format("%[%Q%]", global.main->error.to.stream, global.main->error.notable, process->rule.name, global.main->error.notable);
-              fl_print_format("%[' has no '%]", global.main->error.to.stream, global.main->error.context, process->rule.name, global.main->error.context);
+              fl_print_format("%[' has no '%]", global.main->error.to.stream, global.main->error.context, global.main->error.context);
               fl_print_format("%[%q%]", global.main->error.to.stream, global.main->error.notable, controller_rule_action_type_name(process->action), global.main->error.notable);
               fl_print_format("%[' action to execute.%]%c", global.main->error.to.stream, global.main->error.context, global.main->error.context, f_string_eol_s[0]);
             }
index 64a0f76240e9964d88feee0df6c822e432d6bc55..45594e31cc3ac546b14934bb85081579d382021b 100644 (file)
@@ -80,6 +80,22 @@ extern "C" {
 #endif // _di_controller_rule_parameters_read_
 
 /**
+ * Convert the action type to an action execute type.
+ *
+ * @param type
+ *   The action type to convert from.
+ *
+ * @return
+ *   The converted action type, converted into an action execute type.
+ *
+ *   The code controller_rule_action_type_execute__enum_size is returned for unknown types.
+ *
+ */
+#ifndef _di_controller_rule_action_type_to_action_execute_type_
+  extern uint8_t controller_rule_action_type_to_action_execute_type(const uint8_t type) f_attribute_visibility_internal;
+#endif // _di_controller_rule_action_type_to_action_execute_type_
+
+/**
  * Get a string representing the rule action type.
  *
  * @param type
@@ -94,6 +110,20 @@ extern "C" {
 #endif // _di_controller_rule_action_type_name_
 
 /**
+ * Get a string representing the rule action execute type.
+ *
+ * @param type
+ *   The rule action type execute code.
+ *
+ * @return
+ *   The string with used > 0 on success.
+ *   The string with used == 0 if no match was found.
+ */
+#ifndef _di_controller_rule_action_type_execute_name_
+  extern f_string_static_t controller_rule_action_type_execute_name(const uint8_t type) f_attribute_visibility_internal;
+#endif // _di_controller_rule_action_type_execute_name_
+
+/**
  * Increase the size of the rule actions array by the specified amount, but only if necessary.
  *
  * This only increases size if the current used plus amount is greater than the currently allocated size.
@@ -285,21 +315,6 @@ extern "C" {
 #endif // _di_controller_rule_item_error_print_execute_
 
 /**
- * Print an error or warning message related to the failed execution of some program or script for when the program or script is not found.
- *
- * @param print
- *   The error or warning print structure.
- * @param script_is
- *   If TRUE, then this represents a script.
- *   If FALSE, then this represents a program.
- * @param code
- *   The code returned by the executed program or script.
- */
-#ifndef _di_controller_rule_item_error_print_execute_not_found_
-  extern void controller_rule_item_error_print_execute_not_found(const fll_error_print_t print, const bool script_is, const f_string_t name) f_attribute_visibility_internal;
-#endif // _di_controller_rule_item_error_print_execute_not_found_
-
-/**
  * Print an error or warning message related to need/want/wish settings of some rule.
  *
  * @param print
@@ -480,6 +495,31 @@ extern "C" {
 #endif // _di_controller_rule_execute_pid_with_
 
 /**
+ * Determine whether or not an execute rule should be re-run, applying a delay as requested.
+ *
+ * @param global
+ *   The global data.
+ * @param action
+ *   The action type.
+ * @param process
+ *   The process data for processing this rule.
+ * @param item
+ *   The rule item being executed.
+ *
+ * @return
+ *   A positive number to designate re-run.
+ *   0 to designate do not re-run.
+ *   -1 to designate an error from nanosleep(), with errno set to values like:
+ *     - EFAULT: Designates that there was a problem copying information from user space.
+ *     - EINTR:  Consider this having returned F_signal.
+ *     - EINVAL: Consider this having returned F_status_set_error(F_parameter);
+ *   -2 to designate exit due to signal/disabled thread.
+ */
+#ifndef _di_controller_rule_execute_rerun_
+  extern int8_t controller_rule_execute_rerun(const controller_global_t global, const uint8_t action, controller_process_t *process, controller_rule_item_t *item) f_attribute_visibility_internal;
+#endif // _di_controller_rule_execute_rerun_
+
+/**
  * Construct an id from two distinct strings found within a single given source.
  *
  * @param global
index 49e2f911e9f6cc05d646551354bce31f1d0cc5c9..24e08ed32ae08cfae439fc2b3f43cb473ec6c07d 100644 (file)
@@ -361,6 +361,9 @@ extern "C" {
       controller_thread_delete_simple(thread);
       controller_setting_delete_simple(setting);
       controller_main_delete(main);
+
+      // According to the manpages, pthread_exit() calls exit(0), which is not good because a non-zero exit code may be returned.
+      exit(main->child);
     }
   }
 #endif // _di_controller_thread_process_
@@ -800,6 +803,11 @@ extern "C" {
       controller_setting_delete_simple(entry->global->setting);
       controller_main_delete(entry->global->main);
 
+      const int code = main->child;
+
+      // According to the manpages, pthread_exit() calls exit(0), which is not good because a non-zero exit code may be returned.
+      exit(main->child);
+
       return 0;
     }
 
index 3486eaf3c3c466f03b9472fe7b55ca33b449174d..3715a1a9486f7ecd5bfc68585b795b4ffba20785 100644 (file)
@@ -20,7 +20,7 @@ build_compiler gcc
 build_indexer ar
 build_language c
 build_libraries -lc -lcap
-build_libraries-individual -lfll_control_group -lfll_error -lfll_execute -lfll_fss -lfll_path -lfll_print -lfll_program -lfl_console -lfl_control_group -lfl_conversion -lfl_directory -lfl_environment -lfl_fss -lfl_iki -lfl_print -lfl_status -lfl_string -lf_account -lf_capability -lf_color -lf_console -lf_control_group -lf_conversion -lf_directory -lf_environment -lf_file -lf_fss -lf_iki -lf_limit -lf_memory -lf_path -lf_pipe -lf_print -lf_signal -lf_string -lf_thread -lf_type_array -lf_utf
+build_libraries-individual -lfll_control_group -lfll_error -lfll_execute -lfll_fss -lfll_path -lfll_print -lfll_program -lfl_console -lfl_control_group -lfl_conversion -lfl_directory -lfl_environment -lfl_fss -lfl_iki -lfl_print -lfl_status -lfl_string -lf_account -lf_capability -lf_color -lf_console -lf_control_group -lf_conversion -lf_directory -lf_environment -lf_execute -lf_file -lf_fss -lf_iki -lf_limit -lf_memory -lf_path -lf_pipe -lf_print -lf_signal -lf_string -lf_thread -lf_type_array -lf_utf
 build_libraries-level -lfll_2 -lfll_1 -lfll_0
 build_libraries-monolithic -lfll
 build_sources_library controller.c private-common.c private-control.c private-controller.c private-entry.c private-rule.c private-thread.c
diff --git a/level_3/controller/data/settings/example/entries/htop-command.entry b/level_3/controller/data/settings/example/entries/htop-command.entry
new file mode 100644 (file)
index 0000000..9a15e99
--- /dev/null
@@ -0,0 +1,7 @@
+# fss-0005
+
+setting:
+  mode program
+
+main:
+  start command htop
diff --git a/level_3/controller/data/settings/example/rules/command/htop.rule b/level_3/controller/data/settings/example/rules/command/htop.rule
new file mode 100644 (file)
index 0000000..af43951
--- /dev/null
@@ -0,0 +1,9 @@
+# fss-000d
+
+setting:
+  name "Run htop"
+
+command:
+  start htop
+
+  rerun start success delay 3000 max 3
index 97f80759d72b1bc32183dccd2d871f6b5ba15373..8c3bc2dfe385008c75251a912947451972bd1094 100644 (file)
@@ -20,7 +20,7 @@ build_compiler gcc
 build_indexer ar
 build_language c
 build_libraries -lc -lcap
-build_libraries-individual -lfll_error -lfll_execute -lfll_file -lfll_fss -lfll_path -lfll_print -lfll_program -lfl_console -lfl_control_group -lfl_conversion -lfl_directory -lfl_environment -lfl_fss -lfl_iki -lfl_print -lfl_status -lfl_string -lf_account -lf_capability -lf_color -lf_console -lf_control_group -lf_conversion -lf_directory -lf_environment -lf_file -lf_fss -lf_iki -lf_limit -lf_memory -lf_path -lf_print -lf_signal -lf_string -lf_thread -lf_type_array -lf_utf
+build_libraries-individual -lfll_error -lfll_execute -lfll_file -lfll_fss -lfll_path -lfll_print -lfll_program -lfl_console -lfl_control_group -lfl_conversion -lfl_directory -lfl_environment -lfl_fss -lfl_iki -lfl_print -lfl_status -lfl_string -lf_account -lf_capability -lf_color -lf_console -lf_control_group -lf_conversion -lf_directory -lf_environment -lf_execute -lf_file -lf_fss -lf_iki -lf_limit -lf_memory -lf_path -lf_print -lf_signal -lf_string -lf_thread -lf_type_array -lf_utf
 build_libraries-level -lfll_2 -lfll_1 -lfll_0
 build_libraries-monolithic -lfll
 build_sources_library fake.c private-common.c private-fake.c private-clean.c private-build.c private-make.c private-print.c private-skeleton.c
index beeecd10062199cbbe06c48d3398a85ede65bd73..db7b5e05e33b00418ca0319a1684600cdcc6a750 100644 (file)
@@ -20,7 +20,7 @@ build_compiler gcc
 build_indexer ar
 build_language c
 build_libraries -lc -lcap
-build_libraries-individual -lfll_error -lfll_execute -lfll_fss -lfll_print -lfll_program -lfl_console -lfl_control_group -lfl_conversion -lfl_environment -lfl_fss -lfl_print -lfl_status -lfl_string -lf_account -lf_capability -lf_color -lf_console -lf_control_group -lf_conversion -lf_directory -lf_environment -lf_file -lf_fss -lf_limit -lf_memory -lf_path -lf_pipe -lf_print -lf_signal -lf_string -lf_thread -lf_type_array -lf_utf
+build_libraries-individual -lfll_error -lfll_execute -lfll_fss -lfll_print -lfll_program -lfl_console -lfl_control_group -lfl_conversion -lfl_environment -lfl_fss -lfl_print -lfl_status -lfl_string -lf_account -lf_capability -lf_color -lf_console -lf_control_group -lf_conversion -lf_directory -lf_environment -lf_execute -lf_file -lf_fss -lf_limit -lf_memory -lf_path -lf_pipe -lf_print -lf_signal -lf_string -lf_thread -lf_type_array -lf_utf
 build_libraries-level -lfll_2 -lfll_1 -lfll_0
 build_libraries-monolithic -lfll
 build_sources_library firewall.c private-common.c private-firewall.c